summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--Documentation/ABI/testing/sysfs-kernel-slab109
-rw-r--r--Documentation/RCU/trace.txt254
-rw-r--r--Documentation/RCU/whatisRCU.txt2
-rw-r--r--Documentation/blockdev/drbd/DRBD-8.3-data-packets.svg588
-rw-r--r--Documentation/blockdev/drbd/DRBD-data-packets.svg459
-rw-r--r--Documentation/blockdev/drbd/README.txt16
-rw-r--r--Documentation/blockdev/drbd/conn-states-8.dot18
-rw-r--r--Documentation/blockdev/drbd/disk-states-8.dot16
-rw-r--r--Documentation/blockdev/drbd/drbd-connection-state-overview.dot85
-rw-r--r--Documentation/blockdev/drbd/node-states-8.dot14
-rw-r--r--Documentation/dontdiff5
-rw-r--r--Documentation/edac.txt153
-rw-r--r--Documentation/feature-removal-schedule.txt17
-rw-r--r--Documentation/filesystems/00-INDEX12
-rw-r--r--Documentation/filesystems/ceph.txt139
-rw-r--r--Documentation/filesystems/exofs.txt23
-rw-r--r--Documentation/filesystems/nfs/00-INDEX12
-rw-r--r--Documentation/filesystems/nfs/Exporting (renamed from Documentation/filesystems/Exporting)0
-rw-r--r--Documentation/filesystems/nfs/nfs-rdma.txt (renamed from Documentation/filesystems/nfs-rdma.txt)0
-rw-r--r--Documentation/filesystems/nfs/nfs.txt (renamed from Documentation/filesystems/nfs.txt)0
-rw-r--r--Documentation/filesystems/nfs/nfs41-server.txt (renamed from Documentation/filesystems/nfs41-server.txt)9
-rw-r--r--Documentation/filesystems/nfs/nfsroot.txt (renamed from Documentation/filesystems/nfsroot.txt)0
-rw-r--r--Documentation/filesystems/porting2
-rw-r--r--Documentation/filesystems/proc.txt3
-rw-r--r--Documentation/filesystems/vfs.txt2
-rw-r--r--Documentation/hwlat_detector.txt64
-rw-r--r--Documentation/hwmon/it871
-rw-r--r--Documentation/hwmon/mc13783-adc50
-rw-r--r--Documentation/hwmon/w83627hf29
-rw-r--r--Documentation/i2c/busses/i2c-piix42
-rw-r--r--Documentation/i2c/busses/i2c-voodoo362
-rw-r--r--Documentation/i2c/old-module-parameters44
-rw-r--r--Documentation/ioctl/ioctl-number.txt1
-rw-r--r--Documentation/isdn/README.gigaset34
-rw-r--r--Documentation/kbuild/kconfig.txt3
-rw-r--r--Documentation/kernel-parameters.txt35
-rw-r--r--Documentation/laptops/thinkpad-acpi.txt51
-rw-r--r--Documentation/lguest/lguest.c1
-rw-r--r--Documentation/networking/bonding.txt42
-rw-r--r--Documentation/networking/ip-sysctl.txt18
-rw-r--r--Documentation/oops-tracing.txt2
-rw-r--r--Documentation/pcmcia/driver-changes.txt7
-rw-r--r--Documentation/scsi/ChangeLog.megaraid_sas62
-rw-r--r--Documentation/sound/alsa/ALSA-Configuration.txt9
-rw-r--r--Documentation/sysctl/kernel.txt6
-rw-r--r--Documentation/timers/hpet.txt2
-rw-r--r--Documentation/trace/ftrace-design.txt13
-rw-r--r--Documentation/trace/ftrace.txt2
-rw-r--r--Documentation/trace/kprobetrace.txt151
-rw-r--r--Documentation/vm/slqbinfo.c1047
-rw-r--r--Kbuild4
-rw-r--r--MAINTAINERS60
-rw-r--r--Makefile80
-rw-r--r--arch/Kconfig10
-rw-r--r--arch/alpha/boot/bootp.c2
-rw-r--r--arch/alpha/boot/bootpz.c2
-rw-r--r--arch/alpha/boot/main.c2
-rw-r--r--arch/alpha/include/asm/asm-offsets.h1
-rw-r--r--arch/alpha/include/asm/fcntl.h19
-rw-r--r--arch/alpha/include/asm/socket.h2
-rw-r--r--arch/alpha/kernel/systbls.S1
-rw-r--r--arch/arm/Makefile14
-rw-r--r--arch/arm/configs/cm_t35_defconfig (renamed from arch/arm/configs/da830_omapl137_defconfig)1077
-rw-r--r--arch/arm/configs/da8xx_omapl_defconfig (renamed from arch/arm/configs/da850_omapl138_defconfig)245
-rw-r--r--arch/arm/configs/davinci_all_defconfig125
-rw-r--r--arch/arm/configs/u300_defconfig94
-rw-r--r--arch/arm/include/asm/asm-offsets.h1
-rw-r--r--arch/arm/include/asm/elf.h3
-rw-r--r--arch/arm/include/asm/mach-types.h1
-rw-r--r--arch/arm/include/asm/memory.h2
-rw-r--r--arch/arm/include/asm/socket.h2
-rw-r--r--arch/arm/include/asm/swab.h19
-rw-r--r--arch/arm/include/asm/tlbflush.h3
-rw-r--r--arch/arm/kernel/calls.S1
-rw-r--r--arch/arm/kernel/entry-armv.S28
-rw-r--r--arch/arm/kernel/entry-header.S15
-rw-r--r--arch/arm/kernel/process.c9
-rw-r--r--arch/arm/mach-at91/at91sam9g45_devices.c58
-rw-r--r--arch/arm/mach-at91/board-sam9m10g45ek.c1
-rw-r--r--arch/arm/mach-at91/include/mach/board.h1
-rw-r--r--arch/arm/mach-bcmring/arch.c10
-rw-r--r--arch/arm/mach-bcmring/include/mach/reg_nand.h66
-rw-r--r--arch/arm/mach-bcmring/include/mach/reg_umi.h237
-rw-r--r--arch/arm/mach-davinci/Kconfig54
-rw-r--r--arch/arm/mach-davinci/Makefile3
-rw-r--r--arch/arm/mach-davinci/board-da830-evm.c245
-rw-r--r--arch/arm/mach-davinci/board-da850-evm.c366
-rw-r--r--arch/arm/mach-davinci/board-dm355-evm.c12
-rw-r--r--arch/arm/mach-davinci/board-dm355-leopard.c9
-rw-r--r--arch/arm/mach-davinci/board-dm365-evm.c56
-rw-r--r--arch/arm/mach-davinci/board-dm644x-evm.c12
-rw-r--r--arch/arm/mach-davinci/board-dm646x-evm.c84
-rw-r--r--arch/arm/mach-davinci/board-sffsdr.c12
-rw-r--r--arch/arm/mach-davinci/clock.c231
-rw-r--r--arch/arm/mach-davinci/clock.h17
-rw-r--r--arch/arm/mach-davinci/common.c4
-rw-r--r--arch/arm/mach-davinci/cp_intc.c3
-rw-r--r--arch/arm/mach-davinci/cpufreq.c219
-rw-r--r--arch/arm/mach-davinci/da830.c75
-rw-r--r--arch/arm/mach-davinci/da850.c300
-rw-r--r--arch/arm/mach-davinci/devices-da8xx.c76
-rw-r--r--arch/arm/mach-davinci/devices.c6
-rw-r--r--arch/arm/mach-davinci/dm355.c2
-rw-r--r--arch/arm/mach-davinci/dm365.c81
-rw-r--r--arch/arm/mach-davinci/dm644x.c2
-rw-r--r--arch/arm/mach-davinci/dm646x.c11
-rw-r--r--arch/arm/mach-davinci/dma.c105
-rw-r--r--arch/arm/mach-davinci/gpio.c9
-rw-r--r--arch/arm/mach-davinci/include/mach/asp.h3
-rw-r--r--arch/arm/mach-davinci/include/mach/cpufreq.h25
-rw-r--r--arch/arm/mach-davinci/include/mach/da8xx.h23
-rw-r--r--arch/arm/mach-davinci/include/mach/dm365.h7
-rw-r--r--arch/arm/mach-davinci/include/mach/dm644x.h1
-rw-r--r--arch/arm/mach-davinci/include/mach/keyscan.h41
-rw-r--r--arch/arm/mach-davinci/include/mach/mux.h15
-rw-r--r--arch/arm/mach-davinci/include/mach/system.h3
-rw-r--r--arch/arm/mach-davinci/include/mach/usb.h57
-rw-r--r--arch/arm/mach-davinci/mux.c1
-rw-r--r--arch/arm/mach-davinci/psc.c3
-rw-r--r--arch/arm/mach-davinci/serial.c6
-rw-r--r--arch/arm/mach-davinci/sram.c3
-rw-r--r--arch/arm/mach-davinci/time.c6
-rw-r--r--arch/arm/mach-davinci/usb.c41
-rw-r--r--arch/arm/mach-ep93xx/core.c1
-rw-r--r--arch/arm/mach-ep93xx/edb93xx.c2
-rw-r--r--arch/arm/mach-ep93xx/include/mach/platform.h1
-rw-r--r--arch/arm/mach-mmp/aspenite.c42
-rw-r--r--arch/arm/mach-mmp/clock.c15
-rw-r--r--arch/arm/mach-mmp/clock.h1
-rw-r--r--arch/arm/mach-mmp/include/mach/irqs.h4
-rw-r--r--arch/arm/mach-mmp/include/mach/pxa168.h7
-rw-r--r--arch/arm/mach-mmp/include/mach/pxa910.h7
-rw-r--r--arch/arm/mach-mmp/pxa168.c1
-rw-r--r--arch/arm/mach-mmp/pxa910.c1
-rw-r--r--arch/arm/mach-mmp/ttc_dkb.c87
-rw-r--r--arch/arm/mach-mx2/clock_imx27.c8
-rw-r--r--arch/arm/mach-mx2/pcm038.c96
-rw-r--r--arch/arm/mach-mx2/pcm970-baseboard.c2
-rw-r--r--arch/arm/mach-mx25/devices.c19
-rw-r--r--arch/arm/mach-mx25/mx25pdk.c25
-rw-r--r--arch/arm/mach-mx3/clock-imx35.c2
-rw-r--r--arch/arm/mach-mx3/clock.c2
-rw-r--r--arch/arm/mach-mx3/devices.c24
-rw-r--r--arch/arm/mach-mx3/devices.h6
-rw-r--r--arch/arm/mach-mx3/mm.c2
-rw-r--r--arch/arm/mach-nomadik/board-nhk8815.c11
-rw-r--r--arch/arm/mach-omap1/board-ams-delta.c12
-rw-r--r--arch/arm/mach-omap1/board-fsample.c32
-rw-r--r--arch/arm/mach-omap1/board-generic.c8
-rw-r--r--arch/arm/mach-omap1/board-h2-mmc.c2
-rw-r--r--arch/arm/mach-omap1/board-h2.c16
-rw-r--r--arch/arm/mach-omap1/board-h3-mmc.c2
-rw-r--r--arch/arm/mach-omap1/board-h3.c14
-rw-r--r--arch/arm/mach-omap1/board-innovator.c14
-rw-r--r--arch/arm/mach-omap1/board-nokia770.c22
-rw-r--r--arch/arm/mach-omap1/board-osk.c10
-rw-r--r--arch/arm/mach-omap1/board-palmte.c16
-rw-r--r--arch/arm/mach-omap1/board-palmtt.c18
-rw-r--r--arch/arm/mach-omap1/board-palmz71.c18
-rw-r--r--arch/arm/mach-omap1/board-perseus2.c32
-rw-r--r--arch/arm/mach-omap1/board-sx1-mmc.c4
-rw-r--r--arch/arm/mach-omap1/board-sx1.c18
-rw-r--r--arch/arm/mach-omap1/board-voiceblue.c8
-rw-r--r--arch/arm/mach-omap1/clock.c32
-rw-r--r--arch/arm/mach-omap1/devices.c8
-rw-r--r--arch/arm/mach-omap1/fpga.c2
-rw-r--r--arch/arm/mach-omap1/id.c2
-rw-r--r--arch/arm/mach-omap1/include/mach/clkdev.h5
-rw-r--r--arch/arm/mach-omap1/include/mach/debug-macro.S45
-rw-r--r--arch/arm/mach-omap1/include/mach/entry-macro.S58
-rw-r--r--arch/arm/mach-omap1/include/mach/gpio.h5
-rw-r--r--arch/arm/mach-omap1/include/mach/hardware.h5
-rw-r--r--arch/arm/mach-omap1/include/mach/io.h5
-rw-r--r--arch/arm/mach-omap1/include/mach/irqs.h5
-rw-r--r--arch/arm/mach-omap1/include/mach/memory.h5
-rw-r--r--arch/arm/mach-omap1/include/mach/mtd-xip.h (renamed from arch/arm/plat-omap/include/mach/mtd-xip.h)0
-rw-r--r--arch/arm/mach-omap1/include/mach/smp.h5
-rw-r--r--arch/arm/mach-omap1/include/mach/system.h5
-rw-r--r--arch/arm/mach-omap1/include/mach/timex.h5
-rw-r--r--arch/arm/mach-omap1/include/mach/uncompress.h5
-rw-r--r--arch/arm/mach-omap1/include/mach/vmalloc.h20
-rw-r--r--arch/arm/mach-omap1/io.c49
-rw-r--r--arch/arm/mach-omap1/irq.c34
-rw-r--r--arch/arm/mach-omap1/leds-h2p2-debug.c2
-rw-r--r--arch/arm/mach-omap1/leds.c2
-rw-r--r--arch/arm/mach-omap1/mailbox.c2
-rw-r--r--arch/arm/mach-omap1/mcbsp.c42
-rw-r--r--arch/arm/mach-omap1/mux.c72
-rw-r--r--arch/arm/mach-omap1/pm.c114
-rw-r--r--arch/arm/mach-omap1/pm.h53
-rw-r--r--arch/arm/mach-omap1/serial.c32
-rw-r--r--arch/arm/mach-omap1/sleep.S22
-rw-r--r--arch/arm/mach-omap1/timer32k.c2
-rw-r--r--arch/arm/mach-omap2/Kconfig4
-rw-r--r--arch/arm/mach-omap2/Makefile2
-rw-r--r--arch/arm/mach-omap2/board-2430sdp.c14
-rw-r--r--arch/arm/mach-omap2/board-3430sdp.c24
-rw-r--r--arch/arm/mach-omap2/board-4430sdp.c23
-rw-r--r--arch/arm/mach-omap2/board-apollon.c16
-rw-r--r--arch/arm/mach-omap2/board-cm-t35.c459
-rw-r--r--arch/arm/mach-omap2/board-generic.c10
-rw-r--r--arch/arm/mach-omap2/board-h4.c20
-rw-r--r--arch/arm/mach-omap2/board-ldp.c16
-rw-r--r--arch/arm/mach-omap2/board-n8x0.c16
-rw-r--r--arch/arm/mach-omap2/board-omap3beagle.c16
-rw-r--r--arch/arm/mach-omap2/board-omap3evm.c60
-rw-r--r--arch/arm/mach-omap2/board-omap3pandora.c14
-rw-r--r--arch/arm/mach-omap2/board-overo.c16
-rw-r--r--arch/arm/mach-omap2/board-rx51-peripherals.c136
-rw-r--r--arch/arm/mach-omap2/board-rx51.c18
-rw-r--r--arch/arm/mach-omap2/board-zoom-debugboard.c2
-rw-r--r--arch/arm/mach-omap2/board-zoom2.c8
-rw-r--r--arch/arm/mach-omap2/clock.c10
-rw-r--r--arch/arm/mach-omap2/clock.h2
-rw-r--r--arch/arm/mach-omap2/clock24xx.c8
-rw-r--r--arch/arm/mach-omap2/clock34xx.c8
-rw-r--r--arch/arm/mach-omap2/clock34xx.h2
-rw-r--r--arch/arm/mach-omap2/clockdomain.c6
-rw-r--r--arch/arm/mach-omap2/clockdomains.h2
-rw-r--r--arch/arm/mach-omap2/cm.h6
-rw-r--r--arch/arm/mach-omap2/control.c4
-rw-r--r--arch/arm/mach-omap2/devices.c12
-rw-r--r--arch/arm/mach-omap2/gpmc-onenand.c6
-rw-r--r--arch/arm/mach-omap2/gpmc-smc91x.c6
-rw-r--r--arch/arm/mach-omap2/gpmc.c4
-rw-r--r--arch/arm/mach-omap2/id.c141
-rw-r--r--arch/arm/mach-omap2/include/mach/clkdev.h5
-rw-r--r--arch/arm/mach-omap2/include/mach/debug-macro.S (renamed from arch/arm/plat-omap/include/mach/debug-macro.S)19
-rw-r--r--arch/arm/mach-omap2/include/mach/entry-macro.S (renamed from arch/arm/plat-omap/include/mach/entry-macro.S)62
-rw-r--r--arch/arm/mach-omap2/include/mach/gpio.h5
-rw-r--r--arch/arm/mach-omap2/include/mach/hardware.h5
-rw-r--r--arch/arm/mach-omap2/include/mach/io.h5
-rw-r--r--arch/arm/mach-omap2/include/mach/irqs.h5
-rw-r--r--arch/arm/mach-omap2/include/mach/memory.h5
-rw-r--r--arch/arm/mach-omap2/include/mach/smp.h5
-rw-r--r--arch/arm/mach-omap2/include/mach/system.h5
-rw-r--r--arch/arm/mach-omap2/include/mach/timex.h5
-rw-r--r--arch/arm/mach-omap2/include/mach/uncompress.h5
-rw-r--r--arch/arm/mach-omap2/include/mach/vmalloc.h (renamed from arch/arm/plat-omap/include/mach/vmalloc.h)3
-rw-r--r--arch/arm/mach-omap2/io.c38
-rw-r--r--arch/arm/mach-omap2/iommu2.c2
-rw-r--r--arch/arm/mach-omap2/irq.c12
-rw-r--r--arch/arm/mach-omap2/mailbox.c2
-rw-r--r--arch/arm/mach-omap2/mcbsp.c8
-rw-r--r--arch/arm/mach-omap2/mmc-twl4030.c6
-rw-r--r--arch/arm/mach-omap2/mux.c4
-rw-r--r--arch/arm/mach-omap2/omap-smp.c29
-rw-r--r--arch/arm/mach-omap2/omap3-iommu.c2
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c28
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_2420.h6
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_2430.h6
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_34xx.h6
-rw-r--r--arch/arm/mach-omap2/pm-debug.c11
-rw-r--r--arch/arm/mach-omap2/pm.h2
-rw-r--r--arch/arm/mach-omap2/pm24xx.c16
-rw-r--r--arch/arm/mach-omap2/pm34xx.c10
-rw-r--r--arch/arm/mach-omap2/powerdomain.c6
-rw-r--r--arch/arm/mach-omap2/powerdomains.h2
-rw-r--r--arch/arm/mach-omap2/powerdomains24xx.h2
-rw-r--r--arch/arm/mach-omap2/powerdomains34xx.h2
-rw-r--r--arch/arm/mach-omap2/prcm.c4
-rw-r--r--arch/arm/mach-omap2/prm.h6
-rw-r--r--arch/arm/mach-omap2/sdram-micron-mt46h32m32lf-6.h2
-rw-r--r--arch/arm/mach-omap2/sdram-qimonda-hyb18m512160af-6.h2
-rw-r--r--arch/arm/mach-omap2/sdrc.c8
-rw-r--r--arch/arm/mach-omap2/sdrc.h11
-rw-r--r--arch/arm/mach-omap2/sdrc2xxx.c8
-rw-r--r--arch/arm/mach-omap2/serial.c28
-rw-r--r--arch/arm/mach-omap2/sleep24xx.S2
-rw-r--r--arch/arm/mach-omap2/sleep34xx.S2
-rw-r--r--arch/arm/mach-omap2/sram242x.S4
-rw-r--r--arch/arm/mach-omap2/sram243x.S4
-rw-r--r--arch/arm/mach-omap2/timer-gp.c5
-rw-r--r--arch/arm/mach-omap2/usb-musb.c4
-rw-r--r--arch/arm/mach-omap2/usb-tusb6010.c4
-rw-r--r--arch/arm/mach-pxa/Kconfig572
-rw-r--r--arch/arm/mach-pxa/Makefile93
-rw-r--r--arch/arm/mach-pxa/cm-x300.c40
-rw-r--r--arch/arm/mach-pxa/colibri-pxa3xx.c2
-rw-r--r--arch/arm/mach-pxa/devices.c4
-rw-r--r--arch/arm/mach-pxa/include/mach/palmtreo.h67
-rw-r--r--arch/arm/mach-pxa/include/mach/treo680.h49
-rw-r--r--arch/arm/mach-pxa/littleton.c4
-rw-r--r--arch/arm/mach-pxa/palmtreo.c (renamed from arch/arm/mach-pxa/treo680.c)361
-rw-r--r--arch/arm/mach-pxa/saar.c96
-rw-r--r--arch/arm/mach-pxa/spitz.c39
-rw-r--r--arch/arm/mach-pxa/zylonite.c2
-rw-r--r--arch/arm/mach-realview/Kconfig8
-rw-r--r--arch/arm/mach-realview/core.c42
-rw-r--r--arch/arm/mach-realview/core.h5
-rw-r--r--arch/arm/mach-realview/include/mach/memory.h49
-rw-r--r--arch/arm/mach-realview/platsmp.c5
-rw-r--r--arch/arm/mach-realview/realview_eb.c1
-rw-r--r--arch/arm/mach-realview/realview_pb1176.c13
-rw-r--r--arch/arm/mach-realview/realview_pb11mp.c1
-rw-r--r--arch/arm/mach-realview/realview_pba8.c1
-rw-r--r--arch/arm/mach-realview/realview_pbx.c21
-rw-r--r--arch/arm/mach-s3c2400/Kconfig6
-rw-r--r--arch/arm/mach-s3c2410/Kconfig2
-rw-r--r--arch/arm/mach-s3c2412/Kconfig4
-rw-r--r--arch/arm/mach-s3c2440/Kconfig3
-rw-r--r--arch/arm/mach-s3c2442/Kconfig4
-rw-r--r--arch/arm/mach-s3c2443/Kconfig2
-rw-r--r--arch/arm/mach-s3c6400/Kconfig2
-rw-r--r--arch/arm/mach-s3c6410/Kconfig2
-rw-r--r--arch/arm/mach-s5pc100/Kconfig2
-rw-r--r--arch/arm/mach-u300/Makefile1
-rw-r--r--arch/arm/mach-u300/i2c.c248
-rw-r--r--arch/arm/mach-u300/mmc.c64
-rw-r--r--arch/arm/mach-u300/regulator.c88
-rw-r--r--arch/arm/mm/Kconfig5
-rw-r--r--arch/arm/mm/mmu.c2
-rw-r--r--arch/arm/oprofile/op_model_v6.c3
-rw-r--r--arch/arm/plat-omap/clock.c2
-rw-r--r--arch/arm/plat-omap/common.c59
-rw-r--r--arch/arm/plat-omap/cpu-omap.c2
-rw-r--r--arch/arm/plat-omap/debug-devices.c2
-rw-r--r--arch/arm/plat-omap/debug-leds.c2
-rw-r--r--arch/arm/plat-omap/devices.c38
-rw-r--r--arch/arm/plat-omap/dma.c38
-rw-r--r--arch/arm/plat-omap/dmtimer.c18
-rw-r--r--arch/arm/plat-omap/fb.c6
-rw-r--r--arch/arm/plat-omap/gpio.c425
-rw-r--r--arch/arm/plat-omap/i2c.c2
-rw-r--r--arch/arm/plat-omap/include/plat/blizzard.h (renamed from arch/arm/plat-omap/include/mach/blizzard.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/board-ams-delta.h (renamed from arch/arm/plat-omap/include/mach/board-ams-delta.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/board-sx1.h (renamed from arch/arm/plat-omap/include/mach/board-sx1.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/board-voiceblue.h (renamed from arch/arm/plat-omap/include/mach/board-voiceblue.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/board.h (renamed from arch/arm/plat-omap/include/mach/board.h)2
-rw-r--r--arch/arm/plat-omap/include/plat/clkdev.h (renamed from arch/arm/plat-omap/include/mach/clkdev.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/clock.h (renamed from arch/arm/plat-omap/include/mach/clock.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/clockdomain.h (renamed from arch/arm/plat-omap/include/mach/clockdomain.h)6
-rw-r--r--arch/arm/plat-omap/include/plat/common.h (renamed from arch/arm/plat-omap/include/mach/common.h)3
-rw-r--r--arch/arm/plat-omap/include/plat/control.h (renamed from arch/arm/plat-omap/include/mach/control.h)49
-rw-r--r--arch/arm/plat-omap/include/plat/cpu.h (renamed from arch/arm/plat-omap/include/mach/cpu.h)72
-rw-r--r--arch/arm/plat-omap/include/plat/dma.h (renamed from arch/arm/plat-omap/include/mach/dma.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/dmtimer.h (renamed from arch/arm/plat-omap/include/mach/dmtimer.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/dsp_common.h (renamed from arch/arm/plat-omap/include/mach/dsp_common.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/fpga.h (renamed from arch/arm/plat-omap/include/mach/fpga.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/gpio-switch.h (renamed from arch/arm/plat-omap/include/mach/gpio-switch.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/gpio.h (renamed from arch/arm/plat-omap/include/mach/gpio.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/gpmc-smc91x.h (renamed from arch/arm/plat-omap/include/mach/gpmc-smc91x.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/gpmc.h (renamed from arch/arm/plat-omap/include/mach/gpmc.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/hardware.h (renamed from arch/arm/plat-omap/include/mach/hardware.h)16
-rw-r--r--arch/arm/plat-omap/include/plat/hwa742.h (renamed from arch/arm/plat-omap/include/mach/hwa742.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/io.h (renamed from arch/arm/plat-omap/include/mach/io.h)124
-rw-r--r--arch/arm/plat-omap/include/plat/iommu.h (renamed from arch/arm/plat-omap/include/mach/iommu.h)2
-rw-r--r--arch/arm/plat-omap/include/plat/iommu2.h (renamed from arch/arm/plat-omap/include/mach/iommu2.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/iovmm.h (renamed from arch/arm/plat-omap/include/mach/iovmm.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/irda.h (renamed from arch/arm/plat-omap/include/mach/irda.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/irqs.h (renamed from arch/arm/plat-omap/include/mach/irqs.h)229
-rw-r--r--arch/arm/plat-omap/include/plat/keypad.h (renamed from arch/arm/plat-omap/include/mach/keypad.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/lcd_mipid.h (renamed from arch/arm/plat-omap/include/mach/lcd_mipid.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/led.h (renamed from arch/arm/plat-omap/include/mach/led.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/mailbox.h (renamed from arch/arm/plat-omap/include/mach/mailbox.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/mcbsp.h (renamed from arch/arm/plat-omap/include/mach/mcbsp.h)8
-rw-r--r--arch/arm/plat-omap/include/plat/mcspi.h (renamed from arch/arm/plat-omap/include/mach/mcspi.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/memory.h (renamed from arch/arm/plat-omap/include/mach/memory.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/menelaus.h (renamed from arch/arm/plat-omap/include/mach/menelaus.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/mmc.h (renamed from arch/arm/plat-omap/include/mach/mmc.h)2
-rw-r--r--arch/arm/plat-omap/include/plat/mux.h (renamed from arch/arm/plat-omap/include/mach/mux.h)100
-rw-r--r--arch/arm/plat-omap/include/plat/nand.h (renamed from arch/arm/plat-omap/include/mach/nand.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/omap-alsa.h (renamed from arch/arm/plat-omap/include/mach/omap-alsa.h)4
-rw-r--r--arch/arm/plat-omap/include/plat/omap-pm.h (renamed from arch/arm/plat-omap/include/mach/omap-pm.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/omap1510.h (renamed from arch/arm/plat-omap/include/mach/omap1510.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/omap16xx.h (renamed from arch/arm/plat-omap/include/mach/omap16xx.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/omap24xx.h (renamed from arch/arm/plat-omap/include/mach/omap24xx.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/omap34xx.h (renamed from arch/arm/plat-omap/include/mach/omap34xx.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/omap44xx.h (renamed from arch/arm/plat-omap/include/mach/omap44xx.h)8
-rw-r--r--arch/arm/plat-omap/include/plat/omap730.h (renamed from arch/arm/plat-omap/include/mach/omap730.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/omap7xx.h104
-rw-r--r--arch/arm/plat-omap/include/plat/omap850.h (renamed from arch/arm/plat-omap/include/mach/omap850.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/omap_device.h (renamed from arch/arm/plat-omap/include/mach/omap_device.h)2
-rw-r--r--arch/arm/plat-omap/include/plat/omap_hwmod.h (renamed from arch/arm/plat-omap/include/mach/omap_hwmod.h)2
-rw-r--r--arch/arm/plat-omap/include/plat/omapfb.h (renamed from arch/arm/plat-omap/include/mach/omapfb.h)2
-rw-r--r--arch/arm/plat-omap/include/plat/onenand.h (renamed from arch/arm/plat-omap/include/mach/onenand.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/param.h (renamed from arch/arm/plat-omap/include/mach/param.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/powerdomain.h (renamed from arch/arm/plat-omap/include/mach/powerdomain.h)2
-rw-r--r--arch/arm/plat-omap/include/plat/prcm.h (renamed from arch/arm/plat-omap/include/mach/prcm.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/sdrc.h (renamed from arch/arm/plat-omap/include/mach/sdrc.h)6
-rw-r--r--arch/arm/plat-omap/include/plat/serial.h (renamed from arch/arm/plat-omap/include/mach/serial.h)4
-rw-r--r--arch/arm/plat-omap/include/plat/smp.h (renamed from arch/arm/plat-omap/include/mach/smp.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/sram.h (renamed from arch/arm/plat-omap/include/mach/sram.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/system.h (renamed from arch/arm/plat-omap/include/mach/system.h)2
-rw-r--r--arch/arm/plat-omap/include/plat/tc.h (renamed from arch/arm/plat-omap/include/mach/tc.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/timer-gp.h (renamed from arch/arm/plat-omap/include/mach/timer-gp.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/timex.h (renamed from arch/arm/plat-omap/include/mach/timex.h)0
-rw-r--r--arch/arm/plat-omap/include/plat/uncompress.h (renamed from arch/arm/plat-omap/include/mach/uncompress.h)5
-rw-r--r--arch/arm/plat-omap/include/plat/usb.h (renamed from arch/arm/plat-omap/include/mach/usb.h)2
-rw-r--r--arch/arm/plat-omap/io.c44
-rw-r--r--arch/arm/plat-omap/iommu-debug.c4
-rw-r--r--arch/arm/plat-omap/iommu.c2
-rw-r--r--arch/arm/plat-omap/iovmm.c17
-rw-r--r--arch/arm/plat-omap/mailbox.c2
-rw-r--r--arch/arm/plat-omap/mcbsp.c4
-rw-r--r--arch/arm/plat-omap/mux.c2
-rw-r--r--arch/arm/plat-omap/omap-pm-noop.c4
-rw-r--r--arch/arm/plat-omap/omap_device.c54
-rw-r--r--arch/arm/plat-omap/sram.c32
-rw-r--r--arch/arm/plat-omap/usb.c18
-rw-r--r--arch/arm/plat-pxa/include/plat/pxa3xx_nand.h (renamed from arch/arm/mach-pxa/include/mach/pxa3xx_nand.h)0
-rw-r--r--arch/arm/plat-s3c/Kconfig2
-rw-r--r--arch/arm/plat-s3c/include/plat/audio.h45
-rw-r--r--arch/arm/plat-s3c/include/plat/regs-s3c2412-iis.h2
-rw-r--r--arch/arm/plat-s3c24xx/Kconfig2
-rw-r--r--arch/arm/plat-s3c64xx/Kconfig2
-rw-r--r--arch/arm/plat-s5pc1xx/Kconfig2
-rw-r--r--arch/arm/tools/Makefile2
-rw-r--r--arch/arm/tools/gen-mach-types2
-rw-r--r--arch/avr32/boards/atngw100/mrmt.c1
-rw-r--r--arch/avr32/boards/atngw100/setup.c5
-rw-r--r--arch/avr32/include/asm/asm-offsets.h1
-rw-r--r--arch/avr32/include/asm/socket.h2
-rw-r--r--arch/avr32/kernel/syscall_table.S1
-rw-r--r--arch/avr32/kernel/vmlinux.lds.S64
-rw-r--r--arch/avr32/mach-at32ap/at32ap700x.c35
-rw-r--r--arch/avr32/mach-at32ap/include/mach/board.h1
-rw-r--r--arch/avr32/mach-at32ap/include/mach/cpu.h2
-rw-r--r--arch/blackfin/include/asm/asm-offsets.h1
-rw-r--r--arch/blackfin/include/asm/fcntl.h2
-rw-r--r--arch/blackfin/mach-common/entry.S1
-rw-r--r--arch/cris/arch-v10/mm/fault.c3
-rw-r--r--arch/cris/arch-v10/mm/tlb.c22
-rw-r--r--arch/cris/arch-v32/kernel/head.S1
-rw-r--r--arch/cris/include/asm/asm-offsets.h1
-rw-r--r--arch/cris/include/asm/socket.h2
-rw-r--r--arch/cris/kernel/asm-offsets.c1
-rw-r--r--arch/cris/kernel/vmlinux.lds.S1
-rw-r--r--arch/frv/include/asm/asm-offsets.h1
-rw-r--r--arch/frv/include/asm/socket.h2
-rw-r--r--arch/frv/kernel/setup.c2
-rw-r--r--arch/h8300/include/asm/asm-offsets.h1
-rw-r--r--arch/h8300/include/asm/socket.h2
-rw-r--r--arch/ia64/Kconfig3
-rw-r--r--arch/ia64/Makefile2
-rw-r--r--arch/ia64/include/asm/asm-offsets.h1
-rw-r--r--arch/ia64/include/asm/irq.h2
-rw-r--r--arch/ia64/include/asm/kvm.h1
-rw-r--r--arch/ia64/include/asm/kvm_host.h1
-rw-r--r--arch/ia64/include/asm/meminit.h2
-rw-r--r--arch/ia64/include/asm/pgtable.h3
-rw-r--r--arch/ia64/include/asm/sn/arch.h2
-rw-r--r--arch/ia64/include/asm/socket.h2
-rw-r--r--arch/ia64/include/asm/spinlock.h62
-rw-r--r--arch/ia64/include/asm/spinlock_types.h2
-rw-r--r--arch/ia64/include/asm/unistd.h3
-rw-r--r--arch/ia64/kernel/Makefile7
-rw-r--r--arch/ia64/kernel/acpi.c33
-rw-r--r--arch/ia64/kernel/entry.S1
-rw-r--r--arch/ia64/kernel/mca.c104
-rw-r--r--arch/ia64/kernel/setup.c23
-rw-r--r--arch/ia64/kernel/unaligned.c6
-rw-r--r--arch/ia64/kernel/vmlinux.lds.S11
-rw-r--r--arch/ia64/kvm/Makefile2
-rw-r--r--arch/ia64/kvm/asm-offsets.c1
-rw-r--r--arch/ia64/kvm/kvm-ia64.c19
-rw-r--r--arch/ia64/mm/contig.c99
-rw-r--r--arch/ia64/mm/discontig.c124
-rw-r--r--arch/ia64/mm/init.c4
-rw-r--r--arch/ia64/mm/tlb.c24
-rw-r--r--arch/ia64/pci/pci.c39
-rw-r--r--arch/ia64/sn/kernel/io_common.c8
-rw-r--r--arch/ia64/sn/kernel/sn2/sn_hwperf.c7
-rw-r--r--arch/m32r/include/asm/socket.h2
-rw-r--r--arch/m68k/include/asm/asm-offsets.h1
-rw-r--r--arch/m68k/include/asm/processor.h2
-rw-r--r--arch/m68k/include/asm/ptrace.h12
-rw-r--r--arch/m68k/include/asm/socket.h2
-rw-r--r--arch/m68k/kernel/head.S2
-rw-r--r--arch/m68knommu/kernel/ptrace.c18
-rw-r--r--arch/microblaze/include/asm/asm-offsets.h1
-rw-r--r--arch/microblaze/include/asm/prom.h135
-rw-r--r--arch/microblaze/kernel/head.S2
-rw-r--r--arch/microblaze/kernel/prom.c23
-rw-r--r--arch/microblaze/kernel/syscall_table.S1
-rw-r--r--arch/mips/Kconfig14
-rw-r--r--arch/mips/Makefile31
-rw-r--r--arch/mips/alchemy/common/dbdma.c13
-rw-r--r--arch/mips/alchemy/common/irq.c81
-rw-r--r--arch/mips/alchemy/common/platform.c6
-rw-r--r--arch/mips/alchemy/common/setup.c3
-rw-r--r--arch/mips/alchemy/devboards/Makefile2
-rw-r--r--arch/mips/alchemy/devboards/bcsr.c148
-rw-r--r--arch/mips/alchemy/devboards/db1x00/Makefile2
-rw-r--r--arch/mips/alchemy/devboards/db1x00/board_setup.c109
-rw-r--r--arch/mips/alchemy/devboards/db1x00/irqmap.c90
-rw-r--r--arch/mips/alchemy/devboards/db1x00/platform.c84
-rw-r--r--arch/mips/alchemy/devboards/pb1000/board_setup.c17
-rw-r--r--arch/mips/alchemy/devboards/pb1100/Makefile3
-rw-r--r--arch/mips/alchemy/devboards/pb1100/board_setup.c32
-rw-r--r--arch/mips/alchemy/devboards/pb1100/platform.c43
-rw-r--r--arch/mips/alchemy/devboards/pb1200/Makefile2
-rw-r--r--arch/mips/alchemy/devboards/pb1200/board_setup.c91
-rw-r--r--arch/mips/alchemy/devboards/pb1200/irqmap.c134
-rw-r--r--arch/mips/alchemy/devboards/pb1200/platform.c80
-rw-r--r--arch/mips/alchemy/devboards/pb1500/Makefile3
-rw-r--r--arch/mips/alchemy/devboards/pb1500/board_setup.c36
-rw-r--r--arch/mips/alchemy/devboards/pb1500/platform.c42
-rw-r--r--arch/mips/alchemy/devboards/pb1550/Makefile3
-rw-r--r--arch/mips/alchemy/devboards/pb1550/board_setup.c38
-rw-r--r--arch/mips/alchemy/devboards/pb1550/platform.c63
-rw-r--r--arch/mips/alchemy/devboards/platform.c89
-rw-r--r--arch/mips/alchemy/devboards/platform.h18
-rw-r--r--arch/mips/alchemy/mtx-1/Makefile2
-rw-r--r--arch/mips/alchemy/mtx-1/board_setup.c24
-rw-r--r--arch/mips/alchemy/mtx-1/irqmap.c56
-rw-r--r--arch/mips/alchemy/xxs1500/Makefile2
-rw-r--r--arch/mips/alchemy/xxs1500/board_setup.c37
-rw-r--r--arch/mips/alchemy/xxs1500/irqmap.c52
-rw-r--r--arch/mips/alchemy/xxs1500/platform.c63
-rw-r--r--arch/mips/bcm47xx/prom.c10
-rw-r--r--arch/mips/boot/compressed/Makefile97
-rw-r--r--arch/mips/boot/compressed/dbg.c37
-rw-r--r--arch/mips/boot/compressed/decompress.c126
-rw-r--r--arch/mips/boot/compressed/dummy.c4
-rw-r--r--arch/mips/boot/compressed/head.S55
-rw-r--r--arch/mips/boot/compressed/ld.script150
-rw-r--r--arch/mips/boot/compressed/uart-16550.c43
-rw-r--r--arch/mips/fw/arc/cmdline.c5
-rw-r--r--arch/mips/include/asm/asm-offsets.h1
-rw-r--r--arch/mips/include/asm/bootinfo.h4
-rw-r--r--arch/mips/include/asm/fcntl.h17
-rw-r--r--arch/mips/include/asm/mach-au1x00/au1000.h59
-rw-r--r--arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h23
-rw-r--r--arch/mips/include/asm/mach-db1x00/bcsr.h238
-rw-r--r--arch/mips/include/asm/mach-db1x00/db1200.h123
-rw-r--r--arch/mips/include/asm/mach-db1x00/db1x00.h100
-rw-r--r--arch/mips/include/asm/mach-pb1x00/pb1100.h85
-rw-r--r--arch/mips/include/asm/mach-pb1x00/pb1200.h122
-rw-r--r--arch/mips/include/asm/mach-pb1x00/pb1500.h49
-rw-r--r--arch/mips/include/asm/mach-pb1x00/pb1550.h96
-rw-r--r--arch/mips/include/asm/sgialib.h3
-rw-r--r--arch/mips/include/asm/socket.h2
-rw-r--r--arch/mips/include/asm/stackframe.h20
-rw-r--r--arch/mips/kernel/kspd.c1
-rw-r--r--arch/mips/kernel/scall32-o32.S1
-rw-r--r--arch/mips/kernel/scall64-64.S1
-rw-r--r--arch/mips/kernel/scall64-n32.S1
-rw-r--r--arch/mips/kernel/scall64-o32.S1
-rw-r--r--arch/mips/kernel/setup.c4
-rw-r--r--arch/mips/lasat/prom.c4
-rw-r--r--arch/mips/loongson/common/mem.c2
-rw-r--r--arch/mips/mm/cache.c2
-rw-r--r--arch/mips/mti-malta/malta-memory.c2
-rw-r--r--arch/mips/rb532/prom.c4
-rw-r--r--arch/mips/sibyte/common/cfe.c4
-rw-r--r--arch/mips/txx9/generic/setup.c4
-rw-r--r--arch/mn10300/include/asm/asm-offsets.h1
-rw-r--r--arch/mn10300/include/asm/socket.h2
-rw-r--r--arch/parisc/include/asm/asm-offsets.h1
-rw-r--r--arch/parisc/include/asm/fcntl.h5
-rw-r--r--arch/parisc/include/asm/socket.h2
-rw-r--r--arch/parisc/kernel/perf.c2
-rw-r--r--arch/powerpc/boot/dts/cm5200.dts1
-rw-r--r--arch/powerpc/boot/dts/digsy_mtc.dts1
-rw-r--r--arch/powerpc/boot/dts/lite5200.dts2
-rw-r--r--arch/powerpc/boot/dts/lite5200b.dts2
-rw-r--r--arch/powerpc/boot/dts/media5200.dts2
-rw-r--r--arch/powerpc/boot/dts/motionpro.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc5121ads.dts3
-rw-r--r--arch/powerpc/boot/dts/mucmc52.dts332
-rw-r--r--arch/powerpc/boot/dts/pcm030.dts2
-rw-r--r--arch/powerpc/boot/dts/pcm032.dts2
-rw-r--r--arch/powerpc/boot/dts/tqm5200.dts1
-rw-r--r--arch/powerpc/boot/dts/uc101.dts284
-rw-r--r--arch/powerpc/configs/52xx/cm5200_defconfig136
-rw-r--r--arch/powerpc/configs/52xx/lite5200b_defconfig153
-rw-r--r--arch/powerpc/configs/52xx/motionpro_defconfig146
-rw-r--r--arch/powerpc/configs/52xx/pcm030_defconfig142
-rw-r--r--arch/powerpc/configs/52xx/tqm5200_defconfig148
-rw-r--r--arch/powerpc/configs/mpc5200_defconfig192
-rw-r--r--arch/powerpc/configs/ppc64e_defconfig2199
-rw-r--r--arch/powerpc/include/asm/asm-offsets.h1
-rw-r--r--arch/powerpc/include/asm/prom.h147
-rw-r--r--arch/powerpc/include/asm/socket.h2
-rw-r--r--arch/powerpc/kernel/entry_64.S41
-rw-r--r--arch/powerpc/kernel/pci_64.c2
-rw-r--r--arch/powerpc/kernel/perf_event.c17
-rw-r--r--arch/powerpc/kernel/process.c2
-rw-r--r--arch/powerpc/kernel/prom.c23
-rw-r--r--arch/powerpc/kernel/setup_64.c1
-rw-r--r--arch/powerpc/kernel/vdso.c13
-rw-r--r--arch/powerpc/kernel/vdso32/vdso32.lds.S4
-rw-r--r--arch/powerpc/kvm/powerpc.c5
-rw-r--r--arch/powerpc/kvm/timing.h2
-rw-r--r--arch/powerpc/oprofile/op_model_cell.c2
-rw-r--r--arch/powerpc/platforms/52xx/efika.c2
-rw-r--r--arch/powerpc/platforms/52xx/mpc5200_simple.c2
-rw-r--r--arch/powerpc/platforms/amigaone/setup.c2
-rw-r--r--arch/powerpc/platforms/cell/spufs/Makefile6
-rw-r--r--arch/powerpc/platforms/chrp/setup.c2
-rw-r--r--arch/powerpc/platforms/iseries/Makefile11
-rw-r--r--arch/powerpc/platforms/iseries/dt.c56
-rw-r--r--arch/powerpc/platforms/powermac/bootx_init.c2
-rw-r--r--arch/powerpc/xmon/xmon.c20
-rw-r--r--arch/s390/Kconfig15
-rw-r--r--arch/s390/defconfig1
-rw-r--r--arch/s390/hypfs/hypfs.h4
-rw-r--r--arch/s390/hypfs/hypfs_diag.c123
-rw-r--r--arch/s390/hypfs/hypfs_vm.c83
-rw-r--r--arch/s390/hypfs/inode.c18
-rw-r--r--arch/s390/include/asm/asm-offsets.h1
-rw-r--r--arch/s390/include/asm/atomic.h8
-rw-r--r--arch/s390/include/asm/cputime.h6
-rw-r--r--arch/s390/include/asm/mmu_context.h4
-rw-r--r--arch/s390/include/asm/pgalloc.h3
-rw-r--r--arch/s390/include/asm/setup.h17
-rw-r--r--arch/s390/include/asm/smp.h54
-rw-r--r--arch/s390/include/asm/socket.h2
-rw-r--r--arch/s390/include/asm/sockios.h21
-rw-r--r--arch/s390/include/asm/termbits.h206
-rw-r--r--arch/s390/include/asm/timex.h13
-rw-r--r--arch/s390/include/asm/todclk.h23
-rw-r--r--arch/s390/include/asm/uaccess.h2
-rw-r--r--arch/s390/kernel/ftrace.c67
-rw-r--r--arch/s390/kernel/ipl.c7
-rw-r--r--arch/s390/kernel/setup.c36
-rw-r--r--arch/s390/kernel/smp.c7
-rw-r--r--arch/s390/kernel/swsusp_asm64.S1
-rw-r--r--arch/s390/kernel/vdso.c9
-rw-r--r--arch/s390/kvm/Kconfig1
-rw-r--r--arch/s390/kvm/kvm-s390.c5
-rw-r--r--arch/s390/lib/uaccess_mvcos.c4
-rw-r--r--arch/s390/lib/uaccess_pt.c147
-rw-r--r--arch/s390/mm/cmm.c61
-rw-r--r--arch/s390/mm/fault.c380
-rw-r--r--arch/s390/mm/pgtable.c2
-rw-r--r--arch/sh/Kconfig35
-rw-r--r--arch/sh/Makefile13
-rw-r--r--arch/sh/boards/board-ap325rxa.c52
-rw-r--r--arch/sh/boards/mach-ecovec24/setup.c115
-rw-r--r--arch/sh/boards/mach-kfr2r09/setup.c172
-rw-r--r--arch/sh/boards/mach-landisk/gio.c10
-rw-r--r--arch/sh/boards/mach-migor/setup.c52
-rw-r--r--arch/sh/boards/mach-rsk/devices-rsk7203.c4
-rw-r--r--arch/sh/boards/mach-rsk/setup.c23
-rw-r--r--arch/sh/boards/mach-se/7724/setup.c82
-rw-r--r--arch/sh/boot/Makefile6
-rw-r--r--arch/sh/boot/compressed/misc.c2
-rw-r--r--arch/sh/drivers/pci/Kconfig19
-rw-r--r--arch/sh/drivers/pci/fixups-rts7751r2d.c2
-rw-r--r--arch/sh/include/asm/.gitignore1
-rw-r--r--arch/sh/include/asm/addrspace.h9
-rw-r--r--arch/sh/include/asm/asm-offsets.h1
-rw-r--r--arch/sh/include/asm/atomic.h9
-rw-r--r--arch/sh/include/asm/bitops.h4
-rw-r--r--arch/sh/include/asm/bugs.h4
-rw-r--r--arch/sh/include/asm/dma-mapping.h233
-rw-r--r--arch/sh/include/asm/dwarf.h28
-rw-r--r--arch/sh/include/asm/fixmap.h6
-rw-r--r--arch/sh/include/asm/ftrace.h17
-rw-r--r--arch/sh/include/asm/hardirq.h13
-rw-r--r--arch/sh/include/asm/io.h4
-rw-r--r--arch/sh/include/asm/irqflags.h31
-rw-r--r--arch/sh/include/asm/irqflags_32.h99
-rw-r--r--arch/sh/include/asm/irqflags_64.h85
-rw-r--r--arch/sh/include/asm/machvec.h2
-rw-r--r--arch/sh/include/asm/mmu.h13
-rw-r--r--arch/sh/include/asm/pci.h30
-rw-r--r--arch/sh/include/asm/pgtable.h26
-rw-r--r--arch/sh/include/asm/pgtable_32.h2
-rw-r--r--arch/sh/include/asm/scatterlist.h2
-rw-r--r--arch/sh/include/asm/sh_eth.h1
-rw-r--r--arch/sh/include/asm/system_32.h29
-rw-r--r--arch/sh/include/asm/system_64.h26
-rw-r--r--arch/sh/include/asm/thread_info.h26
-rw-r--r--arch/sh/include/asm/topology.h8
-rw-r--r--arch/sh/include/asm/ubc.h11
-rw-r--r--arch/sh/include/asm/watchdog.h59
-rw-r--r--arch/sh/include/cpu-sh4/cpu/watchdog.h13
-rw-r--r--arch/sh/kernel/Makefile8
-rw-r--r--arch/sh/kernel/cpu/Makefile1
-rw-r--r--arch/sh/kernel/cpu/init.c11
-rw-r--r--arch/sh/kernel/cpu/sh3/entry.S33
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-shx3.c45
-rw-r--r--arch/sh/kernel/cpu/sh4a/smp-shx3.c37
-rw-r--r--arch/sh/kernel/cpu/sh5/entry.S2
-rw-r--r--arch/sh/kernel/cpu/ubc.S59
-rw-r--r--arch/sh/kernel/dma-nommu.c82
-rw-r--r--arch/sh/kernel/dwarf.c244
-rw-r--r--arch/sh/kernel/entry-common.S2
-rw-r--r--arch/sh/kernel/ftrace.c146
-rw-r--r--arch/sh/kernel/head_32.S2
-rw-r--r--arch/sh/kernel/idle.c78
-rw-r--r--arch/sh/kernel/irq.c11
-rw-r--r--arch/sh/kernel/irq_32.c57
-rw-r--r--arch/sh/kernel/irq_64.c51
-rw-r--r--arch/sh/kernel/machine_kexec.c6
-rw-r--r--arch/sh/kernel/module.c9
-rw-r--r--arch/sh/kernel/process_32.c2
-rw-r--r--arch/sh/kernel/process_64.c2
-rw-r--r--arch/sh/kernel/return_address.c54
-rw-r--r--arch/sh/kernel/setup.c4
-rw-r--r--arch/sh/kernel/sh_ksyms_32.c81
-rw-r--r--arch/sh/kernel/sh_ksyms_64.c10
-rw-r--r--arch/sh/kernel/signal_32.c24
-rw-r--r--arch/sh/kernel/signal_64.c13
-rw-r--r--arch/sh/kernel/smp.c4
-rw-r--r--arch/sh/kernel/syscalls_64.S1
-rw-r--r--arch/sh/kernel/topology.c26
-rw-r--r--arch/sh/kernel/traps.c2
-rw-r--r--arch/sh/kernel/traps_32.c5
-rw-r--r--arch/sh/mm/Kconfig13
-rw-r--r--arch/sh/mm/Makefile3
-rw-r--r--arch/sh/mm/cache-sh4.c516
-rw-r--r--arch/sh/mm/cache-sh7705.c2
-rw-r--r--arch/sh/mm/cache.c22
-rw-r--r--arch/sh/mm/consistent.c28
-rw-r--r--arch/sh/mm/init.c19
-rw-r--r--arch/sh/mm/kmap.c4
-rw-r--r--arch/sh/mm/pmb-fixed.c45
-rw-r--r--arch/sh/mm/pmb.c268
-rw-r--r--arch/sh/tools/Makefile4
-rw-r--r--arch/sh/tools/gen-mach-types2
-rw-r--r--arch/sparc/include/asm/asm-offsets.h1
-rw-r--r--arch/sparc/include/asm/fcntl.h19
-rw-r--r--arch/sparc/include/asm/pci_64.h2
-rw-r--r--arch/sparc/include/asm/prom.h55
-rw-r--r--arch/sparc/include/asm/socket.h2
-rw-r--r--arch/sparc/include/asm/unistd.h3
-rw-r--r--arch/sparc/kernel/nmi.c8
-rw-r--r--arch/sparc/kernel/pci.c7
-rw-r--r--arch/sparc/kernel/systbls_32.S2
-rw-r--r--arch/sparc/kernel/systbls_64.S4
-rw-r--r--arch/um/Makefile2
-rw-r--r--arch/um/include/asm/asm-offsets.h1
-rw-r--r--arch/x86/Kconfig19
-rw-r--r--arch/x86/Kconfig.cpu4
-rw-r--r--arch/x86/Kconfig.debug23
-rw-r--r--arch/x86/Makefile4
-rw-r--r--arch/x86/Makefile_32.cpu2
-rw-r--r--arch/x86/boot/compressed/head_64.S3
-rw-r--r--arch/x86/boot/header.S2
-rw-r--r--arch/x86/boot/setup.ld3
-rw-r--r--arch/x86/boot/version.c4
-rw-r--r--arch/x86/crypto/Makefile3
-rw-r--r--arch/x86/crypto/aesni-intel_glue.c10
-rw-r--r--arch/x86/crypto/ghash-clmulni-intel_asm.S157
-rw-r--r--arch/x86/crypto/ghash-clmulni-intel_glue.c333
-rw-r--r--arch/x86/ia32/ia32entry.S6
-rw-r--r--arch/x86/include/asm/acpi.h1
-rw-r--r--arch/x86/include/asm/apic.h2
-rw-r--r--arch/x86/include/asm/asm-offsets.h1
-rw-r--r--arch/x86/include/asm/cmpxchg_32.h218
-rw-r--r--arch/x86/include/asm/cmpxchg_64.h234
-rw-r--r--arch/x86/include/asm/cpufeature.h1
-rw-r--r--arch/x86/include/asm/elf.h20
-rw-r--r--arch/x86/include/asm/entry_arch.h2
-rw-r--r--arch/x86/include/asm/hardirq.h2
-rw-r--r--arch/x86/include/asm/hpet.h7
-rw-r--r--arch/x86/include/asm/hw_irq.h35
-rw-r--r--arch/x86/include/asm/inat.h188
-rw-r--r--arch/x86/include/asm/inat_types.h29
-rw-r--r--arch/x86/include/asm/insn.h143
-rw-r--r--arch/x86/include/asm/irq.h2
-rw-r--r--arch/x86/include/asm/irq_vectors.h2
-rw-r--r--arch/x86/include/asm/k8.h4
-rw-r--r--arch/x86/include/asm/kvm.h1
-rw-r--r--arch/x86/include/asm/kvm_host.h21
-rw-r--r--arch/x86/include/asm/mce.h7
-rw-r--r--arch/x86/include/asm/msr.h4
-rw-r--r--arch/x86/include/asm/page_types.h3
-rw-r--r--arch/x86/include/asm/pci_x86.h2
-rw-r--r--arch/x86/include/asm/percpu.h78
-rw-r--r--arch/x86/include/asm/perf_event.h13
-rw-r--r--arch/x86/include/asm/ptrace.h62
-rw-r--r--arch/x86/include/asm/sections.h6
-rw-r--r--arch/x86/include/asm/string_32.h9
-rw-r--r--arch/x86/include/asm/syscalls.h8
-rw-r--r--arch/x86/include/asm/thread_info.h7
-rw-r--r--arch/x86/include/asm/topology.h1
-rw-r--r--arch/x86/include/asm/uaccess.h1
-rw-r--r--arch/x86/include/asm/uaccess_32.h27
-rw-r--r--arch/x86/include/asm/uaccess_64.h19
-rw-r--r--arch/x86/include/asm/unistd_32.h3
-rw-r--r--arch/x86/include/asm/unistd_64.h2
-rw-r--r--arch/x86/include/asm/uv/uv_hub.h23
-rw-r--r--arch/x86/include/asm/uv/uv_irq.h14
-rw-r--r--arch/x86/include/asm/xen/hypervisor.h27
-rw-r--r--arch/x86/kernel/acpi/boot.c1
-rw-r--r--arch/x86/kernel/acpi/realmode/wakeup.lds.S3
-rw-r--r--arch/x86/kernel/apic/Makefile2
-rw-r--r--arch/x86/kernel/apic/apic.c25
-rw-r--r--arch/x86/kernel/apic/apic_noop.c205
-rw-r--r--arch/x86/kernel/apic/io_apic.c195
-rw-r--r--arch/x86/kernel/apic/nmi.c8
-rw-r--r--arch/x86/kernel/apic/x2apic_uv_x.c8
-rw-r--r--arch/x86/kernel/apm_32.c14
-rw-r--r--arch/x86/kernel/cpu/common.c2
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c106
-rw-r--r--arch/x86/kernel/cpu/perf_event.c185
-rw-r--r--arch/x86/kernel/cpuid.c17
-rw-r--r--arch/x86/kernel/crash_dump_32.c19
-rw-r--r--arch/x86/kernel/dumpstack.c7
-rw-r--r--arch/x86/kernel/efi.c2
-rw-r--r--arch/x86/kernel/entry_32.S31
-rw-r--r--arch/x86/kernel/entry_64.S29
-rw-r--r--arch/x86/kernel/ftrace.c84
-rw-r--r--arch/x86/kernel/head_64.S3
-rw-r--r--arch/x86/kernel/hpet.c60
-rw-r--r--arch/x86/kernel/ioport.c11
-rw-r--r--arch/x86/kernel/irq.c20
-rw-r--r--arch/x86/kernel/irqinit.c4
-rw-r--r--arch/x86/kernel/kgdb.c14
-rw-r--r--arch/x86/kernel/kprobes.c248
-rw-r--r--arch/x86/kernel/microcode_core.c2
-rw-r--r--arch/x86/kernel/msr.c16
-rw-r--r--arch/x86/kernel/process.c2
-rw-r--r--arch/x86/kernel/process_32.c2
-rw-r--r--arch/x86/kernel/process_64.c32
-rw-r--r--arch/x86/kernel/ptrace.c112
-rw-r--r--arch/x86/kernel/reboot.c2
-rw-r--r--arch/x86/kernel/setup.c13
-rw-r--r--arch/x86/kernel/signal.c3
-rw-r--r--arch/x86/kernel/syscall_table_32.S1
-rw-r--r--arch/x86/kernel/tlb_uv.c9
-rw-r--r--arch/x86/kernel/tsc.c8
-rw-r--r--arch/x86/kernel/uv_irq.c239
-rw-r--r--arch/x86/kernel/uv_time.c77
-rw-r--r--arch/x86/kernel/vmlinux.lds.S31
-rw-r--r--arch/x86/kernel/x8664_ksyms_64.c2
-rw-r--r--arch/x86/kvm/Makefile3
-rw-r--r--arch/x86/kvm/emulate.c154
-rw-r--r--arch/x86/kvm/i8254.c4
-rw-r--r--arch/x86/kvm/i8259.c44
-rw-r--r--arch/x86/kvm/irq.h1
-rw-r--r--arch/x86/kvm/lapic.c10
-rw-r--r--arch/x86/kvm/mmu.c18
-rw-r--r--arch/x86/kvm/svm.c166
-rw-r--r--arch/x86/kvm/vmx.c188
-rw-r--r--arch/x86/kvm/x86.c205
-rw-r--r--arch/x86/lib/Makefile13
-rw-r--r--arch/x86/lib/copy_user_64.S4
-rw-r--r--arch/x86/lib/inat.c78
-rw-r--r--arch/x86/lib/insn.c464
-rw-r--r--arch/x86/lib/msr.c46
-rw-r--r--arch/x86/lib/usercopy_32.c10
-rw-r--r--arch/x86/lib/x86-opcode-map.txt841
-rw-r--r--arch/x86/mm/extable.c31
-rw-r--r--arch/x86/mm/fault.c11
-rw-r--r--arch/x86/mm/init_32.c8
-rw-r--r--arch/x86/mm/init_64.c21
-rw-r--r--arch/x86/mm/k8topology_64.c89
-rw-r--r--arch/x86/mm/numa_32.c4
-rw-r--r--arch/x86/mm/numa_64.c221
-rw-r--r--arch/x86/mm/pageattr.c14
-rw-r--r--arch/x86/mm/pat.c3
-rw-r--r--arch/x86/mm/srat_64.c29
-rw-r--r--arch/x86/mm/testmmiotrace.c29
-rw-r--r--arch/x86/pci/Makefile5
-rw-r--r--arch/x86/pci/acpi.c14
-rw-r--r--arch/x86/pci/amd_bus.c45
-rw-r--r--arch/x86/pci/bus_numa.h26
-rw-r--r--arch/x86/pci/common.c20
-rw-r--r--arch/x86/pci/i386.c21
-rw-r--r--arch/x86/pci/intel_bus.c90
-rw-r--r--arch/x86/pci/legacy.c43
-rw-r--r--arch/x86/pci/mmconfig-shared.c31
-rw-r--r--arch/x86/tools/Makefile15
-rw-r--r--arch/x86/tools/distill.awk42
-rw-r--r--arch/x86/tools/gen-insn-attr-x86.awk334
-rw-r--r--arch/x86/tools/test_get_len.c108
-rw-r--r--arch/x86/xen/enlighten.c1
-rw-r--r--arch/xtensa/include/asm/asm-offsets.h1
-rw-r--r--arch/xtensa/include/asm/socket.h2
-rw-r--r--arch/xtensa/include/asm/unistd.h4
-rw-r--r--block/Kconfig.iosched26
-rw-r--r--block/Makefile1
-rw-r--r--block/as-iosched.c1520
-rw-r--r--block/elevator.c10
-rw-r--r--crypto/Kconfig9
-rw-r--r--crypto/ansi_cprng.c82
-rw-r--r--crypto/async_tx/async_pq.c60
-rw-r--r--crypto/async_tx/async_raid6_recov.c100
-rw-r--r--crypto/async_tx/async_xor.c18
-rw-r--r--crypto/cryptd.c9
-rw-r--r--crypto/digest.c240
-rw-r--r--crypto/hash.c183
-rw-r--r--crypto/proc.c7
-rw-r--r--crypto/testmgr.c2
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/accessibility/braille/braille_console.c1
-rw-r--r--drivers/acpi/acpica/dswload.c50
-rw-r--r--drivers/acpi/acpica/evregion.c64
-rw-r--r--drivers/acpi/acpica/nsrepair.c110
-rw-r--r--drivers/acpi/glue.c3
-rw-r--r--drivers/acpi/numa.c10
-rw-r--r--drivers/acpi/scan.c1
-rw-r--r--drivers/acpi/video_detect.c10
-rw-r--r--drivers/ata/ahci.c3
-rw-r--r--drivers/ata/libata-core.c12
-rw-r--r--drivers/ata/libata-eh.c6
-rw-r--r--drivers/ata/pata_atiixp.c2
-rw-r--r--drivers/ata/pata_cs5535.c2
-rw-r--r--drivers/ata/pata_sc1200.c3
-rw-r--r--drivers/ata/pata_via.c2
-rw-r--r--drivers/ata/sata_mv.c29
-rw-r--r--drivers/ata/sata_nv.c18
-rw-r--r--drivers/base/core.c4
-rw-r--r--drivers/base/power/Makefile2
-rw-r--r--drivers/base/power/common.c283
-rw-r--r--drivers/base/power/main.c677
-rw-r--r--drivers/base/power/power.h42
-rw-r--r--drivers/base/power/runtime.c4
-rw-r--r--drivers/base/power/sysfs.c47
-rw-r--r--drivers/block/Kconfig2
-rw-r--r--drivers/block/Makefile1
-rw-r--r--drivers/block/aoe/aoecmd.c8
-rw-r--r--drivers/block/ataflop.c3
-rw-r--r--drivers/block/drbd/Kconfig71
-rw-r--r--drivers/block/drbd/Makefile5
-rw-r--r--drivers/block/drbd/drbd_actlog.c1424
-rw-r--r--drivers/block/drbd/drbd_bitmap.c1327
-rw-r--r--drivers/block/drbd/drbd_int.h2252
-rw-r--r--drivers/block/drbd/drbd_main.c3700
-rw-r--r--drivers/block/drbd/drbd_nl.c2360
-rw-r--r--drivers/block/drbd/drbd_proc.c265
-rw-r--r--drivers/block/drbd/drbd_receiver.c4427
-rw-r--r--drivers/block/drbd/drbd_req.c1120
-rw-r--r--drivers/block/drbd/drbd_req.h326
-rw-r--r--drivers/block/drbd/drbd_strings.c113
-rw-r--r--drivers/block/drbd/drbd_tracing.c752
-rw-r--r--drivers/block/drbd/drbd_tracing.h87
-rw-r--r--drivers/block/drbd/drbd_vli.h351
-rw-r--r--drivers/block/drbd/drbd_worker.c1512
-rw-r--r--drivers/block/drbd/drbd_wrappers.h91
-rw-r--r--drivers/block/virtio_blk.c39
-rw-r--r--drivers/block/xen-blkfront.c1
-rw-r--r--drivers/cdrom/gdrom.c10
-rw-r--r--drivers/char/hvc_xen.c2
-rw-r--r--drivers/char/hw_random/virtio-rng.c3
-rw-r--r--drivers/char/mem.c6
-rw-r--r--drivers/char/pcmcia/ipwireless/main.c270
-rw-r--r--drivers/char/pcmcia/synclink_cs.c64
-rw-r--r--drivers/char/tpm/tpm.c2
-rw-r--r--drivers/char/tty_ioctl.c2
-rw-r--r--drivers/char/virtio_console.c1
-rw-r--r--drivers/cpuidle/governor.c4
-rw-r--r--drivers/crypto/padlock-sha.c14
-rw-r--r--drivers/dma/Kconfig2
-rw-r--r--drivers/dma/dmaengine.c36
-rw-r--r--drivers/edac/Kconfig13
-rw-r--r--drivers/edac/Makefile2
-rw-r--r--drivers/edac/amd64_edac.c8
-rw-r--r--drivers/edac/edac_core.h23
-rw-r--r--drivers/edac/edac_mc_sysfs.c175
-rw-r--r--drivers/edac/edac_mce.c61
-rw-r--r--drivers/edac/edac_mce_amd.c21
-rw-r--r--drivers/edac/i7core_edac.c1974
-rw-r--r--drivers/firewire/core-card.c75
-rw-r--r--drivers/firewire/core-cdev.c95
-rw-r--r--drivers/firewire/core-topology.c17
-rw-r--r--drivers/firewire/core-transaction.c9
-rw-r--r--drivers/firewire/core.h9
-rw-r--r--drivers/firewire/ohci.c30
-rw-r--r--drivers/firewire/sbp2.c9
-rw-r--r--drivers/gpio/adp5520-gpio.c36
-rw-r--r--drivers/gpio/wm831x-gpio.c4
-rw-r--r--drivers/gpu/drm/drm_edid.c15
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c42
-rw-r--r--drivers/gpu/drm/drm_fops.c98
-rw-r--r--drivers/gpu/drm/drm_irq.c95
-rw-r--r--drivers/gpu/drm/drm_stub.c2
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c1
-rw-r--r--drivers/gpu/drm/radeon/atombios.h2
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c348
-rw-r--r--drivers/gpu/drm/radeon/r100.c30
-rw-r--r--drivers/gpu/drm/radeon/r300.c2
-rw-r--r--drivers/gpu/drm/radeon/r500_reg.h9
-rw-r--r--drivers/gpu/drm/radeon/r600.c39
-rw-r--r--drivers/gpu/drm/radeon/r600_blit.c58
-rw-r--r--drivers/gpu/drm/radeon/r600_blit_kms.c3
-rw-r--r--drivers/gpu/drm/radeon/r600d.h4
-rw-r--r--drivers/gpu/drm/radeon/radeon.h3
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c175
-rw-r--r--drivers/gpu/drm/radeon/radeon_benchmark.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_combios.c123
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c143
-rw-r--r--drivers/gpu/drm/radeon/radeon_cp.c45
-rw-r--r--drivers/gpu/drm/radeon/radeon_cursor.c10
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c28
-rw-r--r--drivers/gpu/drm/radeon/radeon_encoders.c106
-rw-r--r--drivers/gpu/drm/radeon/radeon_gart.c20
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq_kms.c9
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_crtc.c40
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_encoders.c27
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h32
-rw-r--r--drivers/gpu/drm/radeon/radeon_reg.h6
-rw-r--r--drivers/gpu/drm/radeon/radeon_test.c6
-rw-r--r--drivers/gpu/drm/radeon/rs600.c18
-rw-r--r--drivers/gpu/drm/radeon/rv770.c30
-rw-r--r--drivers/gpu/drm/radeon/rv770d.h5
-rw-r--r--drivers/hid/hid-core.c6
-rw-r--r--drivers/hid/hid-ids.h1
-rw-r--r--drivers/hid/hid-lg.h2
-rw-r--r--drivers/hid/usbhid/hid-core.c9
-rw-r--r--drivers/hid/usbhid/hid-quirks.c1
-rw-r--r--drivers/hwmon/Kconfig17
-rw-r--r--drivers/hwmon/Makefile2
-rw-r--r--drivers/hwmon/adm1021.c76
-rw-r--r--drivers/hwmon/adm1025.c73
-rw-r--r--drivers/hwmon/adm1026.c47
-rw-r--r--drivers/hwmon/adm1029.c55
-rw-r--r--drivers/hwmon/adm1031.c26
-rw-r--r--drivers/hwmon/adm9240.c61
-rw-r--r--drivers/hwmon/ads7828.c22
-rw-r--r--drivers/hwmon/adt7462.c25
-rw-r--r--drivers/hwmon/adt7470.c25
-rw-r--r--drivers/hwmon/adt7473.c25
-rw-r--r--drivers/hwmon/adt7475.c14
-rw-r--r--drivers/hwmon/asb100.c55
-rw-r--r--drivers/hwmon/dme1737.c61
-rw-r--r--drivers/hwmon/ds1621.c22
-rw-r--r--drivers/hwmon/f75375s.c31
-rw-r--r--drivers/hwmon/fschmd.c55
-rw-r--r--drivers/hwmon/gl518sm.c29
-rw-r--r--drivers/hwmon/gl520sm.c12
-rw-r--r--drivers/hwmon/it87.c48
-rw-r--r--drivers/hwmon/lm63.c54
-rw-r--r--drivers/hwmon/lm73.c205
-rw-r--r--drivers/hwmon/lm75.c56
-rw-r--r--drivers/hwmon/lm77.c80
-rw-r--r--drivers/hwmon/lm78.c58
-rw-r--r--drivers/hwmon/lm83.c81
-rw-r--r--drivers/hwmon/lm85.c157
-rw-r--r--drivers/hwmon/lm87.c41
-rw-r--r--drivers/hwmon/lm90.c228
-rw-r--r--drivers/hwmon/lm92.c31
-rw-r--r--drivers/hwmon/lm93.c32
-rw-r--r--drivers/hwmon/lm95241.c48
-rw-r--r--drivers/hwmon/max1619.c64
-rw-r--r--drivers/hwmon/max6650.c20
-rw-r--r--drivers/hwmon/mc13783-adc.c224
-rw-r--r--drivers/hwmon/smsc47m192.c28
-rw-r--r--drivers/hwmon/thmc50.c37
-rw-r--r--drivers/hwmon/tmp401.c55
-rw-r--r--drivers/hwmon/tmp421.c45
-rw-r--r--drivers/hwmon/w83627hf.c96
-rw-r--r--drivers/hwmon/w83781d.c131
-rw-r--r--drivers/hwmon/w83791d.c60
-rw-r--r--drivers/hwmon/w83792d.c61
-rw-r--r--drivers/hwmon/w83793.c53
-rw-r--r--drivers/hwmon/w83l785ts.c70
-rw-r--r--drivers/hwmon/w83l786ng.c56
-rw-r--r--drivers/i2c/Kconfig1
-rw-r--r--drivers/i2c/busses/Kconfig18
-rw-r--r--drivers/i2c/busses/Makefile3
-rw-r--r--drivers/i2c/busses/i2c-ali1535.c2
-rw-r--r--drivers/i2c/busses/i2c-ali15x3.c2
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c6
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c3
-rw-r--r--drivers/i2c/busses/i2c-piix4.c8
-rw-r--r--drivers/i2c/busses/i2c-powermac.c115
-rw-r--r--drivers/i2c/busses/i2c-scmi.c33
-rw-r--r--drivers/i2c/busses/i2c-sis5595.c2
-rw-r--r--drivers/i2c/busses/i2c-sis630.c2
-rw-r--r--drivers/i2c/busses/i2c-voodoo3.c248
-rw-r--r--drivers/i2c/chips/Kconfig10
-rw-r--r--drivers/i2c/chips/Makefile1
-rw-r--r--drivers/i2c/i2c-core.c99
-rw-r--r--drivers/i2c/i2c-dev.c22
-rw-r--r--drivers/ide/atiixp.c2
-rw-r--r--drivers/ide/au1xxx-ide.c21
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.c3
-rw-r--r--drivers/infiniband/hw/nes/nes_nic.c12
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c2
-rw-r--r--drivers/input/input-polldev.c7
-rw-r--r--drivers/input/input.c65
-rw-r--r--drivers/input/keyboard/Kconfig20
-rw-r--r--drivers/input/keyboard/Makefile2
-rw-r--r--drivers/input/keyboard/adp5520-keys.c220
-rw-r--r--drivers/input/keyboard/atkbd.c132
-rw-r--r--drivers/input/keyboard/davinci_keyscan.c337
-rw-r--r--drivers/input/keyboard/lkkbd.c496
-rw-r--r--drivers/input/keyboard/omap-keypad.c6
-rw-r--r--drivers/input/misc/hp_sdc_rtc.c2
-rw-r--r--drivers/input/misc/pcf50633-input.c7
-rw-r--r--drivers/input/misc/wistron_btns.c2
-rw-r--r--drivers/input/mouse/logips2pp.c2
-rw-r--r--drivers/input/mouse/synaptics.c10
-rw-r--r--drivers/input/mouse/vsxxxaa.c374
-rw-r--r--drivers/input/serio/Kconfig8
-rw-r--r--drivers/input/serio/Makefile1
-rw-r--r--drivers/input/serio/altera_ps2.c200
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h13
-rw-r--r--drivers/input/touchscreen/Kconfig12
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/dynapro.c206
-rw-r--r--drivers/input/xen-kbdfront.c3
-rw-r--r--drivers/isdn/act2000/Kconfig4
-rw-r--r--drivers/isdn/capi/Kconfig4
-rw-r--r--drivers/isdn/gigaset/Kconfig25
-rw-r--r--drivers/isdn/gigaset/Makefile5
-rw-r--r--drivers/isdn/gigaset/asyncdata.c124
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c4
-rw-r--r--drivers/isdn/gigaset/capi.c2273
-rw-r--r--drivers/isdn/gigaset/common.c76
-rw-r--r--drivers/isdn/gigaset/dummyll.c68
-rw-r--r--drivers/isdn/gigaset/ev-layer.c90
-rw-r--r--drivers/isdn/gigaset/gigaset.h97
-rw-r--r--drivers/isdn/gigaset/i4l.c506
-rw-r--r--drivers/isdn/gigaset/isocdata.c79
-rw-r--r--drivers/isdn/hysdn/Kconfig4
-rw-r--r--drivers/isdn/i4l/isdn_net.c2
-rw-r--r--drivers/isdn/i4l/isdn_net.h6
-rw-r--r--drivers/isdn/icn/Kconfig4
-rw-r--r--drivers/isdn/mISDN/socket.c3
-rw-r--r--drivers/isdn/pcbit/Kconfig4
-rw-r--r--drivers/isdn/sc/Kconfig4
-rw-r--r--drivers/leds/Kconfig9
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-alix2.c115
-rw-r--r--drivers/leds/leds-ams-delta.c2
-rw-r--r--drivers/leds/leds-ss4200.c552
-rw-r--r--drivers/md/Makefile22
-rw-r--r--drivers/md/bitmap.c9
-rw-r--r--drivers/md/dm-crypt.c2
-rw-r--r--drivers/md/dm-exception-store.c67
-rw-r--r--drivers/md/dm-exception-store.h42
-rw-r--r--drivers/md/dm-ioctl.c4
-rw-r--r--drivers/md/dm-log-userspace-base.c2
-rw-r--r--drivers/md/dm-snap-persistent.c99
-rw-r--r--drivers/md/dm-snap-transient.c24
-rw-r--r--drivers/md/dm-snap.c255
-rw-r--r--drivers/md/dm.c75
-rw-r--r--drivers/md/md.c2
-rw-r--r--drivers/md/raid1.c6
-rw-r--r--drivers/md/raid10.c5
-rw-r--r--drivers/md/raid5.c182
-rw-r--r--drivers/md/raid5.h14
-rw-r--r--drivers/md/raid6altivec.uc2
-rw-r--r--drivers/md/raid6int.uc2
-rw-r--r--drivers/md/raid6test/Makefile42
-rw-r--r--drivers/md/unroll.awk20
-rw-r--r--drivers/md/unroll.pl24
-rw-r--r--drivers/media/common/tuners/tuner-xc2028.c20
-rw-r--r--drivers/media/common/tuners/tuner-xc2028.h2
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c2
-rw-r--r--drivers/media/dvb/frontends/drx397xD.c2
-rw-r--r--drivers/media/video/cx18/cx18-driver.c4
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c4
-rw-r--r--drivers/media/video/davinci/dm355_ccdc.c4
-rw-r--r--drivers/media/video/davinci/dm644x_ccdc.c4
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c4
-rw-r--r--drivers/media/video/ov772x.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c4
-rw-r--r--drivers/media/video/saa7164/saa7164-core.c4
-rw-r--r--drivers/message/fusion/mptbase.h4
-rw-r--r--drivers/message/fusion/mptctl.c5
-rw-r--r--drivers/message/fusion/mptscsih.c86
-rw-r--r--drivers/mfd/88pm8607.c302
-rw-r--r--drivers/mfd/Kconfig44
-rw-r--r--drivers/mfd/Makefile11
-rw-r--r--drivers/mfd/ab3100-core.c3
-rw-r--r--drivers/mfd/ab4500-core.c208
-rw-r--r--drivers/mfd/adp5520.c379
-rw-r--r--drivers/mfd/asic3.c45
-rw-r--r--drivers/mfd/menelaus.c2
-rw-r--r--drivers/mfd/pcf50633-adc.c5
-rw-r--r--drivers/mfd/pcf50633-core.c76
-rw-r--r--drivers/mfd/sh_mobile_sdhi.c145
-rw-r--r--drivers/mfd/t7l66xb.c31
-rw-r--r--drivers/mfd/tc6387xb.c97
-rw-r--r--drivers/mfd/tc6393xb.c56
-rw-r--r--drivers/mfd/tmio_core.c62
-rw-r--r--drivers/mfd/twl4030-core.c15
-rw-r--r--drivers/mfd/twl4030-power.c70
-rw-r--r--drivers/mfd/wm831x-core.c216
-rw-r--r--drivers/mfd/wm831x-irq.c3
-rw-r--r--drivers/mfd/wm8350-core.c769
-rw-r--r--drivers/mfd/wm8350-irq.c525
-rw-r--r--drivers/misc/Kconfig40
-rw-r--r--drivers/misc/Makefile3
-rw-r--r--drivers/misc/ds1682.c (renamed from drivers/i2c/chips/ds1682.c)0
-rw-r--r--drivers/misc/hwlat_detector.c1208
-rw-r--r--drivers/misc/ics932s401.c37
-rw-r--r--drivers/misc/iwmc3200top/Kconfig20
-rw-r--r--drivers/misc/iwmc3200top/Makefile29
-rw-r--r--drivers/misc/iwmc3200top/debugfs.c133
-rw-r--r--drivers/misc/iwmc3200top/debugfs.h58
-rw-r--r--drivers/misc/iwmc3200top/fw-download.c359
-rw-r--r--drivers/misc/iwmc3200top/fw-msg.h113
-rw-r--r--drivers/misc/iwmc3200top/iwmc3200top.h206
-rw-r--r--drivers/misc/iwmc3200top/log.c347
-rw-r--r--drivers/misc/iwmc3200top/log.h158
-rw-r--r--drivers/misc/iwmc3200top/main.c699
-rw-r--r--drivers/misc/sgi-xp/xpc_uv.c5
-rw-r--r--drivers/mmc/card/sdio_uart.c40
-rw-r--r--drivers/mmc/core/core.c4
-rw-r--r--drivers/mmc/core/core.h10
-rw-r--r--drivers/mmc/host/Kconfig2
-rw-r--r--drivers/mmc/host/at91_mci.c1
-rw-r--r--drivers/mmc/host/au1xmmc.c8
-rw-r--r--drivers/mmc/host/omap.c10
-rw-r--r--drivers/mmc/host/omap_hsmmc.c8
-rw-r--r--drivers/mmc/host/tmio_mmc.c78
-rw-r--r--drivers/mmc/host/tmio_mmc.h46
-rw-r--r--drivers/mtd/chips/Kconfig3
-rw-r--r--drivers/mtd/devices/Kconfig3
-rw-r--r--drivers/mtd/devices/m25p80.c7
-rw-r--r--drivers/mtd/devices/mtd_dataflash.c19
-rw-r--r--drivers/mtd/lpddr/Kconfig3
-rw-r--r--drivers/mtd/maps/Kconfig9
-rw-r--r--drivers/mtd/maps/Makefile1
-rw-r--r--drivers/mtd/maps/gpio-addr-flash.c5
-rw-r--r--drivers/mtd/maps/ipaq-flash.c460
-rw-r--r--drivers/mtd/maps/omap_nor.c2
-rw-r--r--drivers/mtd/maps/pcmciamtd.c175
-rw-r--r--drivers/mtd/maps/physmap.c19
-rw-r--r--drivers/mtd/maps/sa1100-flash.c6
-rw-r--r--drivers/mtd/mtd_blkdevs.c2
-rw-r--r--drivers/mtd/nand/Kconfig20
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/ams-delta.c2
-rw-r--r--drivers/mtd/nand/atmel_nand.c1
-rw-r--r--drivers/mtd/nand/au1550nd.c4
-rw-r--r--drivers/mtd/nand/bcm_umi_bch.c213
-rw-r--r--drivers/mtd/nand/bcm_umi_nand.c581
-rw-r--r--drivers/mtd/nand/davinci_nand.c2
-rw-r--r--drivers/mtd/nand/mxc_nand.c18
-rw-r--r--drivers/mtd/nand/nand_base.c6
-rw-r--r--drivers/mtd/nand/nand_bcm_umi.c149
-rw-r--r--drivers/mtd/nand/nand_bcm_umi.h358
-rw-r--r--drivers/mtd/nand/omap2.c6
-rw-r--r--drivers/mtd/nand/plat_nand.c50
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c82
-rw-r--r--drivers/mtd/onenand/Kconfig4
-rw-r--r--drivers/mtd/onenand/omap2.c8
-rw-r--r--drivers/mtd/onenand/onenand_base.c176
-rw-r--r--drivers/mtd/tests/mtd_oobtest.c18
-rw-r--r--drivers/mtd/ubi/Kconfig2
-rw-r--r--drivers/mtd/ubi/build.c3
-rw-r--r--drivers/mtd/ubi/kapi.c40
-rw-r--r--drivers/mtd/ubi/scan.c7
-rw-r--r--drivers/mtd/ubi/scan.h2
-rw-r--r--drivers/net/3c59x.c3
-rw-r--r--drivers/net/8139cp.c8
-rw-r--r--drivers/net/8139too.c3
-rw-r--r--drivers/net/Kconfig16
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/atl1e/atl1e_main.c4
-rw-r--r--drivers/net/atlx/atl1.c11
-rw-r--r--drivers/net/atlx/atl2.c3
-rw-r--r--drivers/net/au1000_eth.c1
-rw-r--r--drivers/net/bcm63xx_enet.c5
-rw-r--r--drivers/net/benet/be.h16
-rw-r--r--drivers/net/benet/be_cmds.c92
-rw-r--r--drivers/net/benet/be_cmds.h42
-rw-r--r--drivers/net/benet/be_ethtool.c43
-rw-r--r--drivers/net/benet/be_main.c37
-rw-r--r--drivers/net/bnx2x.h72
-rw-r--r--drivers/net/bnx2x_hsi.h20
-rw-r--r--drivers/net/bnx2x_main.c1012
-rw-r--r--drivers/net/bonding/bond_3ad.c11
-rw-r--r--drivers/net/bonding/bond_alb.c2
-rw-r--r--drivers/net/bonding/bond_main.c96
-rw-r--r--drivers/net/bonding/bond_sysfs.c53
-rw-r--r--drivers/net/bonding/bonding.h14
-rw-r--r--drivers/net/can/Kconfig7
-rw-r--r--drivers/net/can/Makefile1
-rw-r--r--drivers/net/can/at91_can.c34
-rw-r--r--drivers/net/can/dev.c74
-rw-r--r--drivers/net/can/sja1000/sja1000.c17
-rw-r--r--drivers/net/can/sja1000/sja1000.h2
-rw-r--r--drivers/net/can/ti_hecc.c993
-rw-r--r--drivers/net/can/usb/ems_usb.c20
-rw-r--r--drivers/net/chelsio/sge.c5
-rw-r--r--drivers/net/cnic.c1812
-rw-r--r--drivers/net/cnic.h64
-rw-r--r--drivers/net/cnic_defs.h1917
-rw-r--r--drivers/net/cnic_if.h14
-rw-r--r--drivers/net/cpmac.c6
-rw-r--r--drivers/net/cxgb3/adapter.h16
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c22
-rw-r--r--drivers/net/cxgb3/sge.c31
-rw-r--r--drivers/net/davinci_emac.c26
-rw-r--r--drivers/net/dl2k.c18
-rw-r--r--drivers/net/dm9000.h2
-rw-r--r--drivers/net/e100.c5
-rw-r--r--drivers/net/e1000/e1000.h1
-rw-r--r--drivers/net/e1000/e1000_ethtool.c35
-rw-r--r--drivers/net/e1000/e1000_main.c70
-rw-r--r--drivers/net/e1000e/e1000.h13
-rw-r--r--drivers/net/e1000e/ethtool.c41
-rw-r--r--drivers/net/e1000e/hw.h2
-rw-r--r--drivers/net/e1000e/ich8lan.c150
-rw-r--r--drivers/net/e1000e/netdev.c80
-rw-r--r--drivers/net/e1000e/phy.c469
-rw-r--r--drivers/net/ehea/ehea_main.c9
-rw-r--r--drivers/net/enic/enic_main.c15
-rw-r--r--drivers/net/ethoc.c25
-rw-r--r--drivers/net/fec.c2
-rw-r--r--drivers/net/gianfar.c591
-rw-r--r--drivers/net/gianfar.h1
-rw-r--r--drivers/net/hamachi.c12
-rw-r--r--drivers/net/hamradio/baycom_epp.c6
-rw-r--r--drivers/net/ibm_newemac/core.c10
-rw-r--r--drivers/net/ifb.c3
-rw-r--r--drivers/net/igb/e1000_82575.c306
-rw-r--r--drivers/net/igb/e1000_82575.h1
-rw-r--r--drivers/net/igb/e1000_hw.h8
-rw-r--r--drivers/net/igb/e1000_mac.c100
-rw-r--r--drivers/net/igb/e1000_mbx.c82
-rw-r--r--drivers/net/igb/e1000_nvm.c36
-rw-r--r--drivers/net/igb/e1000_phy.c207
-rw-r--r--drivers/net/igb/e1000_phy.h4
-rw-r--r--drivers/net/igb/e1000_regs.h1
-rw-r--r--drivers/net/igb/igb.h1
-rw-r--r--drivers/net/igb/igb_ethtool.c78
-rw-r--r--drivers/net/igb/igb_main.c312
-rw-r--r--drivers/net/igbvf/ethtool.c55
-rw-r--r--drivers/net/igbvf/netdev.c8
-rw-r--r--drivers/net/ipg.c7
-rw-r--r--drivers/net/irda/au1k_ir.c14
-rw-r--r--drivers/net/irda/irda-usb.c9
-rw-r--r--drivers/net/irda/smsc-ircc2.c2
-rw-r--r--drivers/net/ixgb/ixgb.h1
-rw-r--r--drivers/net/ixgb/ixgb_ethtool.c69
-rw-r--r--drivers/net/ixgb/ixgb_main.c56
-rw-r--r--drivers/net/ixgbe/ixgbe.h3
-rw-r--r--drivers/net/ixgbe/ixgbe_82599.c128
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_nl.c2
-rw-r--r--drivers/net/ixgbe/ixgbe_ethtool.c85
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c40
-rw-r--r--drivers/net/ixgbe/ixgbe_type.h11
-rw-r--r--drivers/net/ixp2000/ixpdev.c3
-rw-r--r--drivers/net/korina.c5
-rw-r--r--drivers/net/ks8842.c5
-rw-r--r--drivers/net/ks8851.c42
-rw-r--r--drivers/net/ks8851.h1
-rw-r--r--drivers/net/lib82596.c11
-rw-r--r--drivers/net/loopback.c2
-rw-r--r--drivers/net/mdio.c12
-rw-r--r--drivers/net/mlx4/main.c1
-rw-r--r--drivers/net/myri10ge/myri10ge.c22
-rw-r--r--drivers/net/netxen/netxen_nic.h36
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c2
-rw-r--r--drivers/net/netxen/netxen_nic_hdr.h77
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c871
-rw-r--r--drivers/net/netxen/netxen_nic_init.c74
-rw-r--r--drivers/net/netxen/netxen_nic_main.c278
-rw-r--r--drivers/net/niu.c9
-rw-r--r--drivers/net/pasemi_mac_ethtool.c14
-rw-r--r--drivers/net/pcmcia/3c574_cs.c18
-rw-r--r--drivers/net/pcmcia/3c589_cs.c21
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c69
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c19
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c241
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c130
-rw-r--r--drivers/net/ppp_async.c5
-rw-r--r--drivers/net/ppp_synctty.c5
-rw-r--r--drivers/net/pppoe.c129
-rw-r--r--drivers/net/pppol2tp.c22
-rw-r--r--drivers/net/pppox.c2
-rw-r--r--drivers/net/ps3_gelic_wireless.h2
-rw-r--r--drivers/net/qla3xxx.c2
-rw-r--r--drivers/net/qlge/qlge.h201
-rw-r--r--drivers/net/qlge/qlge_dbg.c180
-rw-r--r--drivers/net/qlge/qlge_ethtool.c178
-rw-r--r--drivers/net/qlge/qlge_main.c392
-rw-r--r--drivers/net/qlge/qlge_mpi.c154
-rw-r--r--drivers/net/r8169.c16
-rw-r--r--drivers/net/sb1250-mac.c1
-rw-r--r--drivers/net/sc92031.c4
-rw-r--r--drivers/net/sfc/Makefile4
-rw-r--r--drivers/net/sfc/bitfield.h13
-rw-r--r--drivers/net/sfc/boards.c328
-rw-r--r--drivers/net/sfc/boards.h28
-rw-r--r--drivers/net/sfc/efx.c89
-rw-r--r--drivers/net/sfc/efx.h11
-rw-r--r--drivers/net/sfc/ethtool.c8
-rw-r--r--drivers/net/sfc/falcon.c1122
-rw-r--r--drivers/net/sfc/falcon.h4
-rw-r--r--drivers/net/sfc/falcon_boards.c (renamed from drivers/net/sfc/sfe4001.c)371
-rw-r--r--drivers/net/sfc/falcon_gmac.c95
-rw-r--r--drivers/net/sfc/falcon_hwdefs.h1333
-rw-r--r--drivers/net/sfc/falcon_io.h258
-rw-r--r--drivers/net/sfc/falcon_xmac.c178
-rw-r--r--drivers/net/sfc/gmii.h60
-rw-r--r--drivers/net/sfc/io.h256
-rw-r--r--drivers/net/sfc/mdio_10g.c121
-rw-r--r--drivers/net/sfc/mdio_10g.h1
-rw-r--r--drivers/net/sfc/net_driver.h56
-rw-r--r--drivers/net/sfc/phy.h6
-rw-r--r--drivers/net/sfc/qt202x_phy.c (renamed from drivers/net/sfc/xfp_phy.c)80
-rw-r--r--drivers/net/sfc/regs.h3180
-rw-r--r--drivers/net/sfc/rx.c16
-rw-r--r--drivers/net/sfc/selftest.c5
-rw-r--r--drivers/net/sfc/tenxpress.c14
-rw-r--r--drivers/net/sfc/tx.c83
-rw-r--r--drivers/net/sfc/workarounds.h2
-rw-r--r--drivers/net/sgiseeq.c7
-rw-r--r--drivers/net/sh_eth.c55
-rw-r--r--drivers/net/sh_eth.h1
-rw-r--r--drivers/net/sis190.c3
-rw-r--r--drivers/net/skge.c7
-rw-r--r--drivers/net/sky2.c3
-rw-r--r--drivers/net/smsc911x.c3
-rw-r--r--drivers/net/tehuti.c27
-rw-r--r--drivers/net/tlan.c7
-rw-r--r--drivers/net/tokenring/ibmtr.c2
-rw-r--r--drivers/net/tsi108_eth.c10
-rw-r--r--drivers/net/tun.c5
-rw-r--r--drivers/net/usb/cdc_ether.c20
-rw-r--r--drivers/net/usb/usbnet.c17
-rw-r--r--drivers/net/vbus-enet.c1553
-rw-r--r--drivers/net/veth.c7
-rw-r--r--drivers/net/via-rhine.c8
-rw-r--r--drivers/net/via-velocity.c3
-rw-r--r--drivers/net/virtio_net.c24
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c27
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h2
-rw-r--r--drivers/net/vxge/vxge-config.c300
-rw-r--r--drivers/net/vxge/vxge-config.h2
-rw-r--r--drivers/net/vxge/vxge-main.c104
-rw-r--r--drivers/net/vxge/vxge-main.h1
-rw-r--r--drivers/net/vxge/vxge-reg.h4
-rw-r--r--drivers/net/vxge/vxge-traffic.c4
-rw-r--r--drivers/net/vxge/vxge-traffic.h2
-rw-r--r--drivers/net/vxge/vxge-version.h4
-rw-r--r--drivers/net/wan/cosa.c20
-rw-r--r--drivers/net/wimax/i2400m/Kconfig8
-rw-r--r--drivers/net/wireless/Kconfig78
-rw-r--r--drivers/net/wireless/airo.c8
-rw-r--r--drivers/net/wireless/at76c50x-usb.c10
-rw-r--r--drivers/net/wireless/ath/Kconfig8
-rw-r--r--drivers/net/wireless/ath/Makefile9
-rw-r--r--drivers/net/wireless/ath/ar9170/ar9170.h6
-rw-r--r--drivers/net/wireless/ath/ar9170/cmd.c3
-rw-r--r--drivers/net/wireless/ath/ar9170/cmd.h1
-rw-r--r--drivers/net/wireless/ath/ar9170/hw.h6
-rw-r--r--drivers/net/wireless/ath/ar9170/mac.c15
-rw-r--r--drivers/net/wireless/ath/ar9170/main.c41
-rw-r--r--drivers/net/wireless/ath/ar9170/phy.c99
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.c12
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.h2
-rw-r--r--drivers/net/wireless/ath/ath.h41
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h53
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c33
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c116
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h14
-rw-r--r--drivers/net/wireless/ath/ath5k/initvals.c4
-rw-r--r--drivers/net/wireless/ath/ath5k/pcu.c193
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c185
-rw-r--r--drivers/net/wireless/ath/ath5k/reg.h19
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c33
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig8
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile27
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c19
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.c141
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h73
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c112
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.c383
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.h64
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c419
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c55
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h36
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.h9
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_4k.c90
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_9287.c97
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_def.c183
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c595
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h63
-rw-r--r--drivers/net/wireless/ath/ath9k/initvals.h72
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c162
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h11
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c841
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c37
-rw-r--r--drivers/net/wireless/ath/ath9k/phy.c50
-rw-r--r--drivers/net/wireless/ath/ath9k/phy.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c33
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c62
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h5
-rw-r--r--drivers/net/wireless/ath/ath9k/virtual.c22
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c115
-rw-r--r--drivers/net/wireless/ath/debug.c32
-rw-r--r--drivers/net/wireless/ath/debug.h77
-rw-r--r--drivers/net/wireless/ath/hw.c126
-rw-r--r--drivers/net/wireless/ath/reg.h27
-rw-r--r--drivers/net/wireless/ath/regd.h8
-rw-r--r--drivers/net/wireless/ath/regd_common.h32
-rw-r--r--drivers/net/wireless/b43/b43.h16
-rw-r--r--drivers/net/wireless/b43/leds.h1
-rw-r--r--drivers/net/wireless/b43/main.c7
-rw-r--r--drivers/net/wireless/b43/pcmcia.c20
-rw-r--r--drivers/net/wireless/b43/phy_lp.c6
-rw-r--r--drivers/net/wireless/b43/pio.c79
-rw-r--r--drivers/net/wireless/b43/rfkill.c3
-rw-r--r--drivers/net/wireless/b43/xmit.c7
-rw-r--r--drivers/net/wireless/b43legacy/main.c6
-rw-r--r--drivers/net/wireless/hostap/Kconfig2
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c21
-rw-r--r--drivers/net/wireless/ipw2x00/Kconfig7
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c1
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig28
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c50
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-hw.h12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.c371
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.h22
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c286
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-hw.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c233
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c336
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c369
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-led.c85
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-led.h32
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c570
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.h101
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c278
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-calib.c75
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h91
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c469
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h55
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h18
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c693
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h113
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace.c13
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace.h178
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c53
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.h20
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-hcmd.c23
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.h16
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.c323
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.h46
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c232
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c177
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c21
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-spectrum.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c62
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c71
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c294
-rw-r--r--drivers/net/wireless/iwmc3200wifi/Kconfig1
-rw-r--r--drivers/net/wireless/iwmc3200wifi/cfg80211.c47
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.c31
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.h70
-rw-r--r--drivers/net/wireless/iwmc3200wifi/fw.c9
-rw-r--r--drivers/net/wireless/iwmc3200wifi/iwm.h6
-rw-r--r--drivers/net/wireless/iwmc3200wifi/lmac.h8
-rw-r--r--drivers/net/wireless/iwmc3200wifi/main.c48
-rw-r--r--drivers/net/wireless/iwmc3200wifi/netdev.c1
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c84
-rw-r--r--drivers/net/wireless/iwmc3200wifi/sdio.c10
-rw-r--r--drivers/net/wireless/iwmc3200wifi/umac.h5
-rw-r--r--drivers/net/wireless/libertas/11d.c696
-rw-r--r--drivers/net/wireless/libertas/11d.h105
-rw-r--r--drivers/net/wireless/libertas/Kconfig39
-rw-r--r--drivers/net/wireless/libertas/Makefile14
-rw-r--r--drivers/net/wireless/libertas/README26
-rw-r--r--drivers/net/wireless/libertas/assoc.c445
-rw-r--r--drivers/net/wireless/libertas/assoc.h141
-rw-r--r--drivers/net/wireless/libertas/cfg.c198
-rw-r--r--drivers/net/wireless/libertas/cfg.h16
-rw-r--r--drivers/net/wireless/libertas/cmd.c537
-rw-r--r--drivers/net/wireless/libertas/cmd.h127
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c116
-rw-r--r--drivers/net/wireless/libertas/debugfs.c27
-rw-r--r--drivers/net/wireless/libertas/decl.h59
-rw-r--r--drivers/net/wireless/libertas/defs.h3
-rw-r--r--drivers/net/wireless/libertas/dev.h419
-rw-r--r--drivers/net/wireless/libertas/host.h959
-rw-r--r--drivers/net/wireless/libertas/hostcmd.h800
-rw-r--r--drivers/net/wireless/libertas/if_cs.c70
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c56
-rw-r--r--drivers/net/wireless/libertas/if_sdio.h3
-rw-r--r--drivers/net/wireless/libertas/if_spi.c13
-rw-r--r--drivers/net/wireless/libertas/if_usb.c3
-rw-r--r--drivers/net/wireless/libertas/main.c373
-rw-r--r--drivers/net/wireless/libertas/persistcfg.c8
-rw-r--r--drivers/net/wireless/libertas/rx.c2
-rw-r--r--drivers/net/wireless/libertas/scan.c250
-rw-r--r--drivers/net/wireless/libertas/scan.h30
-rw-r--r--drivers/net/wireless/libertas/tx.c2
-rw-r--r--drivers/net/wireless/libertas/types.h4
-rw-r--r--drivers/net/wireless/libertas/wext.c196
-rw-r--r--drivers/net/wireless/libertas/wext.h8
-rw-r--r--drivers/net/wireless/orinoco/Kconfig4
-rw-r--r--drivers/net/wireless/orinoco/hermes_dld.c4
-rw-r--r--drivers/net/wireless/orinoco/hw.c33
-rw-r--r--drivers/net/wireless/orinoco/hw.h3
-rw-r--r--drivers/net/wireless/orinoco/main.c34
-rw-r--r--drivers/net/wireless/orinoco/orinoco.h1
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig30
-rw-r--r--drivers/net/wireless/rt2x00/Makefile2
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c3323
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.h1960
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h7
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00soc.c159
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00soc.h52
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c36
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_main.c7
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_rx.c2
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_spi.c2
-rw-r--r--drivers/net/wireless/wl12xx/wl1271.h92
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_acx.c369
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_acx.h586
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_boot.c215
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_boot.h22
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.c329
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.h115
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_conf.h911
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_event.c64
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_event.h30
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_init.c155
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_init.h53
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_main.c963
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_ps.c68
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_ps.h2
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_reg.h47
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_rx.c86
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_rx.h4
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_spi.c311
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_spi.h65
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.c76
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.h18
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx_80211.h4
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c4
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h18
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c202
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.h25
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c4
-rw-r--r--drivers/net/xen-netfront.c1
-rw-r--r--drivers/of/base.c26
-rw-r--r--drivers/of/of_mdio.c13
-rw-r--r--drivers/pci/dmar.c43
-rw-r--r--drivers/pci/hotplug/Makefile12
-rw-r--r--drivers/pci/hotplug/pci_hotplug_core.c22
-rw-r--r--drivers/pci/intel-iommu.c27
-rw-r--r--drivers/pci/intr_remapping.c92
-rw-r--r--drivers/pci/intr_remapping.h7
-rw-r--r--drivers/pci/pci.c97
-rw-r--r--drivers/pci/pci.h2
-rw-r--r--drivers/pci/pcie/portdrv_core.c1
-rw-r--r--drivers/pci/probe.c32
-rw-r--r--drivers/pci/quirks.c34
-rw-r--r--drivers/pci/setup-bus.c22
-rw-r--r--drivers/pci/setup-res.c28
-rw-r--r--drivers/pcmcia/Kconfig21
-rw-r--r--drivers/pcmcia/Makefile12
-rw-r--r--drivers/pcmcia/au1000_db1x00.c305
-rw-r--r--drivers/pcmcia/au1000_generic.h12
-rw-r--r--drivers/pcmcia/au1000_pb1x00.c119
-rw-r--r--drivers/pcmcia/au1000_xxs1500.c188
-rw-r--r--drivers/pcmcia/cardbus.c23
-rw-r--r--drivers/pcmcia/cirrus.h10
-rw-r--r--drivers/pcmcia/cistpl.c81
-rw-r--r--drivers/pcmcia/cs_internal.h19
-rw-r--r--drivers/pcmcia/db1xxx_ss.c630
-rw-r--r--drivers/pcmcia/ds.c8
-rw-r--r--drivers/pcmcia/i82365.c4
-rw-r--r--drivers/pcmcia/m32r_cfc.c10
-rw-r--r--drivers/pcmcia/m32r_pcc.c10
-rw-r--r--drivers/pcmcia/m8xx_pcmcia.c15
-rw-r--r--drivers/pcmcia/o2micro.h22
-rw-r--r--drivers/pcmcia/omap_cf.c4
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c2
-rw-r--r--drivers/pcmcia/pcmcia_resource.c217
-rw-r--r--drivers/pcmcia/pd6729.c6
-rw-r--r--drivers/pcmcia/rsrc_mgr.c1
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c3
-rw-r--r--drivers/pcmcia/soc_common.c5
-rw-r--r--drivers/pcmcia/socket_sysfs.c2
-rw-r--r--drivers/pcmcia/tcic.c4
-rw-r--r--drivers/pcmcia/xxs1500_ss.c357
-rw-r--r--drivers/platform/Kconfig2
-rw-r--r--drivers/platform/x86/compal-laptop.c1
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c24
-rw-r--r--drivers/pnp/quirks.c12
-rw-r--r--drivers/pnp/resource.c10
-rw-r--r--drivers/pnp/support.c43
-rw-r--r--drivers/pnp/system.c14
-rw-r--r--drivers/power/pcf50633-charger.c3
-rw-r--r--drivers/regulator/88pm8607.c685
-rw-r--r--drivers/regulator/Kconfig13
-rw-r--r--drivers/regulator/Makefile2
-rw-r--r--drivers/regulator/ab3100.c10
-rw-r--r--drivers/regulator/core.c235
-rw-r--r--drivers/regulator/da903x.c2
-rw-r--r--drivers/regulator/max8660.c510
-rw-r--r--drivers/regulator/pcf50633-regulator.c5
-rw-r--r--drivers/regulator/wm831x-dcdc.c207
-rw-r--r--drivers/regulator/wm831x-ldo.c6
-rw-r--r--drivers/rtc/Kconfig19
-rw-r--r--drivers/rtc/Makefile2
-rw-r--r--drivers/rtc/rtc-ds1511.c4
-rw-r--r--drivers/rtc/rtc-msm6242.c268
-rw-r--r--drivers/rtc/rtc-pcf50633.c5
-rw-r--r--drivers/rtc/rtc-rp5c01.c222
-rw-r--r--drivers/rtc/rtc-stk17ta8.c2
-rw-r--r--drivers/s390/block/dasd.c1
-rw-r--r--drivers/s390/block/dasd_3990_erp.c1
-rw-r--r--drivers/s390/block/dasd_diag.c20
-rw-r--r--drivers/s390/block/dasd_eckd.c1
-rw-r--r--drivers/s390/block/dasd_fba.c1
-rw-r--r--drivers/s390/char/sclp_async.c47
-rw-r--r--drivers/s390/net/ctcm_main.c59
-rw-r--r--drivers/s390/net/lcs.c14
-rw-r--r--drivers/s390/net/qeth_core.h2
-rw-r--r--drivers/s390/net/qeth_core_main.c11
-rw-r--r--drivers/s390/net/qeth_l2_main.c4
-rw-r--r--drivers/s390/net/qeth_l3_main.c2
-rw-r--r--drivers/s390/net/smsgiucv.c7
-rw-r--r--drivers/s390/scsi/zfcp_aux.c11
-rw-r--r--drivers/s390/scsi/zfcp_erp.c22
-rw-r--r--drivers/s390/scsi/zfcp_ext.h1
-rw-r--r--drivers/s390/scsi/zfcp_fc.c11
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c13
-rw-r--r--drivers/s390/scsi/zfcp_sysfs.c1
-rw-r--r--drivers/scsi/3w-9xxx.c2
-rw-r--r--drivers/scsi/3w-xxxx.c4
-rw-r--r--drivers/scsi/aic7xxx/aic79xx.seq2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.seq2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c2
-rw-r--r--drivers/scsi/bfa/bfa_cb_ioim_macros.h10
-rw-r--r--drivers/scsi/bfa/bfa_cee.c2
-rw-r--r--drivers/scsi/bfa/bfa_csdebug.c4
-rw-r--r--drivers/scsi/bfa/bfa_fcpim.c4
-rw-r--r--drivers/scsi/bfa/bfa_fcpim_priv.h4
-rw-r--r--drivers/scsi/bfa/bfa_fcport.c59
-rw-r--r--drivers/scsi/bfa/bfa_fcs_lport.c11
-rw-r--r--drivers/scsi/bfa/bfa_fcxp.c8
-rw-r--r--drivers/scsi/bfa/bfa_intr.c2
-rw-r--r--drivers/scsi/bfa/bfa_intr_priv.h18
-rw-r--r--drivers/scsi/bfa/bfa_ioc.c10
-rw-r--r--drivers/scsi/bfa/bfa_ioc.h12
-rw-r--r--drivers/scsi/bfa/bfa_iocfc.c8
-rw-r--r--drivers/scsi/bfa/bfa_iocfc.h8
-rw-r--r--drivers/scsi/bfa/bfa_ioim.c4
-rw-r--r--drivers/scsi/bfa/bfa_itnim.c6
-rw-r--r--drivers/scsi/bfa/bfa_log.c4
-rw-r--r--drivers/scsi/bfa/bfa_port_priv.h4
-rw-r--r--drivers/scsi/bfa/bfa_rport.c6
-rw-r--r--drivers/scsi/bfa/bfa_tskim.c9
-rw-r--r--drivers/scsi/bfa/bfa_uf.c2
-rw-r--r--drivers/scsi/bfa/bfad.c6
-rw-r--r--drivers/scsi/bfa/bfad_fwimg.c8
-rw-r--r--drivers/scsi/bfa/bfad_im.c2
-rw-r--r--drivers/scsi/bfa/bfad_im_compat.h2
-rw-r--r--drivers/scsi/bfa/bfad_intr.c3
-rw-r--r--drivers/scsi/bfa/fabric.c18
-rw-r--r--drivers/scsi/bfa/fcbuild.c190
-rw-r--r--drivers/scsi/bfa/fcbuild.h6
-rw-r--r--drivers/scsi/bfa/fcpim.c7
-rw-r--r--drivers/scsi/bfa/fcs.h2
-rw-r--r--drivers/scsi/bfa/fdmi.c8
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen.h2
-rw-r--r--drivers/scsi/bfa/include/bfa.h10
-rw-r--r--drivers/scsi/bfa/include/bfa_svc.h8
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi.h12
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_ioc.h2
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_lps.h4
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_rport.h8
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_checksum.h6
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_sm.h6
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_trc.h2
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h2
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h17
-rw-r--r--drivers/scsi/bfa/include/protocol/ct.h10
-rw-r--r--drivers/scsi/bfa/include/protocol/fc.h22
-rw-r--r--drivers/scsi/bfa/loop.c233
-rw-r--r--drivers/scsi/bfa/lport_api.c15
-rw-r--r--drivers/scsi/bfa/ns.c5
-rw-r--r--drivers/scsi/bfa/plog.c2
-rw-r--r--drivers/scsi/bfa/rport_ftrs.c28
-rw-r--r--drivers/scsi/bfa/vfapi.c2
-rw-r--r--drivers/scsi/bfa/vport.c20
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c2
-rw-r--r--drivers/scsi/dc395x.c2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c738
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h149
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2.h5
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h274
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_ioc.h18
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_raid.h14
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_tool.h16
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c152
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h37
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.c197
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.h4
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c809
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_transport.c86
-rw-r--r--drivers/scsi/nsp32.c2
-rw-r--r--drivers/scsi/osd/osd_initiator.c26
-rw-r--r--drivers/scsi/osd/osd_uld.c232
-rw-r--r--drivers/scsi/scsi_lib.c2
-rw-r--r--drivers/scsi/scsi_scan.c6
-rw-r--r--drivers/scsi/scsi_sysfs.c7
-rw-r--r--drivers/scsi/scsi_transport_fc.c70
-rw-r--r--drivers/scsi/stex.c282
-rw-r--r--drivers/serial/mpc52xx_uart.c2
-rw-r--r--drivers/serial/serial_cs.c87
-rw-r--r--drivers/sh/intc.c14
-rw-r--r--drivers/sh/maple/maple.c4
-rw-r--r--drivers/spi/au1550_spi.c6
-rw-r--r--drivers/spi/omap2_mcspi.c4
-rw-r--r--drivers/spi/omap_uwire.c10
-rw-r--r--drivers/spi/spidev.c2
-rw-r--r--drivers/ssb/driver_pcicore.c4
-rw-r--r--drivers/ssb/pcmcia.c232
-rw-r--r--drivers/staging/iio/ring_sw.h1
-rw-r--r--drivers/staging/netwave/Kconfig1
-rw-r--r--drivers/staging/panel/panel.c2
-rw-r--r--drivers/staging/rtl8187se/Kconfig3
-rw-r--r--drivers/staging/rtl8187se/r8180.h2
-rw-r--r--drivers/staging/rtl8192e/Kconfig3
-rw-r--r--drivers/staging/tm6000/Kconfig32
-rw-r--r--drivers/staging/tm6000/Makefile15
-rw-r--r--drivers/staging/tm6000/README11
-rw-r--r--drivers/staging/tm6000/hack.c252
-rw-r--r--drivers/staging/tm6000/hack.h45
-rw-r--r--drivers/staging/tm6000/tm6000-alsa.c413
-rw-r--r--drivers/staging/tm6000/tm6000-cards.c630
-rw-r--r--drivers/staging/tm6000/tm6000-core.c511
-rw-r--r--drivers/staging/tm6000/tm6000-dvb.c322
-rw-r--r--drivers/staging/tm6000/tm6000-i2c.c245
-rw-r--r--drivers/staging/tm6000/tm6000-regs.h86
-rw-r--r--drivers/staging/tm6000/tm6000-stds.c873
-rw-r--r--drivers/staging/tm6000/tm6000-usb-isoc.h53
-rw-r--r--drivers/staging/tm6000/tm6000-video.c1573
-rw-r--r--drivers/staging/tm6000/tm6000.h279
-rw-r--r--drivers/staging/vt6655/Kconfig4
-rw-r--r--drivers/staging/vt6656/Kconfig4
-rw-r--r--drivers/staging/wavelan/Kconfig4
-rw-r--r--drivers/usb/gadget/Kconfig1
-rw-r--r--drivers/usb/gadget/file_storage.c2
-rw-r--r--drivers/usb/gadget/omap_udc.c6
-rw-r--r--drivers/usb/host/ehci-hcd.c2
-rw-r--r--drivers/usb/host/ohci-omap.c6
-rw-r--r--drivers/usb/musb/omap2430.c2
-rw-r--r--drivers/usb/musb/omap2430.h2
-rw-r--r--drivers/usb/musb/tusb6010_omap.c4
-rw-r--r--drivers/usb/otg/isp1301_omap.c4
-rw-r--r--drivers/uwb/neh.c2
-rw-r--r--drivers/vbus/Kconfig25
-rw-r--r--drivers/vbus/Makefile6
-rw-r--r--drivers/vbus/bus-proxy.c216
-rw-r--r--drivers/vbus/pci-bridge.c1028
-rw-r--r--drivers/video/atmel_lcdfb.c2
-rw-r--r--drivers/video/backlight/adp5520_bl.c123
-rw-r--r--drivers/video/backlight/lcd.c2
-rw-r--r--drivers/video/backlight/omap1_bl.c4
-rw-r--r--drivers/video/fb_defio.c2
-rw-r--r--drivers/video/omap/blizzard.c6
-rw-r--r--drivers/video/omap/dispc.c26
-rw-r--r--drivers/video/omap/hwa742.c6
-rw-r--r--drivers/video/omap/lcd_2430sdp.c4
-rw-r--r--drivers/video/omap/lcd_ams_delta.c8
-rw-r--r--drivers/video/omap/lcd_apollon.c4
-rw-r--r--drivers/video/omap/lcd_h3.c2
-rw-r--r--drivers/video/omap/lcd_h4.c2
-rw-r--r--drivers/video/omap/lcd_inn1510.c4
-rw-r--r--drivers/video/omap/lcd_inn1610.c2
-rw-r--r--drivers/video/omap/lcd_ldp.c4
-rw-r--r--drivers/video/omap/lcd_mipid.c8
-rw-r--r--drivers/video/omap/lcd_omap2evm.c4
-rw-r--r--drivers/video/omap/lcd_omap3beagle.c4
-rw-r--r--drivers/video/omap/lcd_omap3evm.c4
-rw-r--r--drivers/video/omap/lcd_osk.c4
-rw-r--r--drivers/video/omap/lcd_overo.c4
-rw-r--r--drivers/video/omap/lcd_palmte.c4
-rw-r--r--drivers/video/omap/lcd_palmtt.c2
-rw-r--r--drivers/video/omap/lcd_palmz71.c2
-rw-r--r--drivers/video/omap/lcdc.c4
-rw-r--r--drivers/video/omap/omapfb_main.c4
-rw-r--r--drivers/video/omap/rfbi.c2
-rw-r--r--drivers/video/omap/sossi.c4
-rw-r--r--drivers/video/xen-fbfront.c3
-rw-r--r--drivers/virtio/virtio_balloon.c3
-rw-r--r--drivers/virtio/virtio_pci.c27
-rw-r--r--drivers/virtio/virtio_ring.c3
-rw-r--r--drivers/watchdog/omap_wdt.c2
-rw-r--r--drivers/watchdog/sb_wdog.c4
-rw-r--r--drivers/xen/balloon.c2
-rw-r--r--drivers/xen/cpu_hotplug.c1
-rw-r--r--drivers/xen/evtchn.c2
-rw-r--r--drivers/xen/grant-table.c1
-rw-r--r--drivers/xen/sys-hypervisor.c1
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c2
-rw-r--r--drivers/xen/xenfs/super.c2
-rw-r--r--firmware/Makefile2
-rw-r--r--firmware/WHENCE4
-rw-r--r--firmware/bnx2x-e1-5.0.21.0.fw.ihex10184
-rw-r--r--firmware/bnx2x-e1-5.2.7.0.fw.ihex10178
-rw-r--r--firmware/bnx2x-e1h-5.0.21.0.fw.ihex12855
-rw-r--r--firmware/bnx2x-e1h-5.2.7.0.fw.ihex12847
-rw-r--r--fs/Kconfig3
-rw-r--r--fs/Makefile1
-rw-r--r--fs/afs/write.c8
-rw-r--r--fs/btrfs/file.c4
-rw-r--r--fs/ceph/Kconfig26
-rw-r--r--fs/ceph/Makefile36
-rw-r--r--fs/ceph/README17
-rw-r--r--fs/ceph/addr.c1115
-rw-r--r--fs/ceph/buffer.c34
-rw-r--r--fs/ceph/buffer.h55
-rw-r--r--fs/ceph/caps.c2863
-rw-r--r--fs/ceph/ceph_debug.h37
-rw-r--r--fs/ceph/ceph_frag.c21
-rw-r--r--fs/ceph/ceph_frag.h109
-rw-r--r--fs/ceph/ceph_fs.c104
-rw-r--r--fs/ceph/ceph_fs.h639
-rw-r--r--fs/ceph/ceph_strings.c163
-rw-r--r--fs/ceph/crush/crush.c140
-rw-r--r--fs/ceph/crush/crush.h188
-rw-r--r--fs/ceph/crush/hash.h90
-rw-r--r--fs/ceph/crush/mapper.c594
-rw-r--r--fs/ceph/crush/mapper.h20
-rw-r--r--fs/ceph/debugfs.c425
-rw-r--r--fs/ceph/decode.h141
-rw-r--r--fs/ceph/dir.c1212
-rw-r--r--fs/ceph/export.c223
-rw-r--r--fs/ceph/file.c904
-rw-r--r--fs/ceph/inode.c1622
-rw-r--r--fs/ceph/ioctl.c157
-rw-r--r--fs/ceph/ioctl.h39
-rw-r--r--fs/ceph/mds_client.c2912
-rw-r--r--fs/ceph/mds_client.h321
-rw-r--r--fs/ceph/mdsmap.c166
-rw-r--r--fs/ceph/mdsmap.h53
-rw-r--r--fs/ceph/messenger.c2019
-rw-r--r--fs/ceph/messenger.h243
-rw-r--r--fs/ceph/mon_client.c699
-rw-r--r--fs/ceph/mon_client.h109
-rw-r--r--fs/ceph/msgpool.c181
-rw-r--r--fs/ceph/msgpool.h27
-rw-r--r--fs/ceph/msgr.h158
-rw-r--r--fs/ceph/osd_client.c1308
-rw-r--r--fs/ceph/osd_client.h144
-rw-r--r--fs/ceph/osdmap.c882
-rw-r--r--fs/ceph/osdmap.h123
-rw-r--r--fs/ceph/rados.h372
-rw-r--r--fs/ceph/snap.c897
-rw-r--r--fs/ceph/super.c947
-rw-r--r--fs/ceph/super.h888
-rw-r--r--fs/ceph/types.h28
-rw-r--r--fs/ceph/xattr.c840
-rw-r--r--fs/cifs/connect.c3
-rw-r--r--fs/cifs/dir.c3
-rw-r--r--fs/cifs/export.c2
-rw-r--r--fs/cifs/file.c6
-rw-r--r--fs/compat.c5
-rw-r--r--fs/ecryptfs/inode.c97
-rw-r--r--fs/exec.c8
-rw-r--r--fs/exofs/inode.c13
-rw-r--r--fs/exofs/super.c11
-rw-r--r--fs/exportfs/expfs.c2
-rw-r--r--fs/ext3/inode.c4
-rw-r--r--fs/ext4/balloc.c2
-rw-r--r--fs/ext4/mballoc.c2
-rw-r--r--fs/file_table.c2
-rw-r--r--fs/gfs2/Kconfig2
-rw-r--r--fs/gfs2/acl.c357
-rw-r--r--fs/gfs2/acl.h24
-rw-r--r--fs/gfs2/bmap.c2
-rw-r--r--fs/gfs2/glock.c13
-rw-r--r--fs/gfs2/glock.h9
-rw-r--r--fs/gfs2/glops.c5
-rw-r--r--fs/gfs2/incore.h4
-rw-r--r--fs/gfs2/inode.c2
-rw-r--r--fs/gfs2/log.c2
-rw-r--r--fs/gfs2/lops.c2
-rw-r--r--fs/gfs2/ops_fstype.c154
-rw-r--r--fs/gfs2/quota.c393
-rw-r--r--fs/gfs2/quota.h5
-rw-r--r--fs/gfs2/rgrp.c2
-rw-r--r--fs/gfs2/super.c93
-rw-r--r--fs/gfs2/super.h4
-rw-r--r--fs/gfs2/sys.c14
-rw-r--r--fs/gfs2/xattr.c74
-rw-r--r--fs/gfs2/xattr.h8
-rw-r--r--fs/inode.c10
-rw-r--r--fs/isofs/compress.c533
-rw-r--r--fs/isofs/export.c2
-rw-r--r--fs/isofs/rock.c3
-rw-r--r--fs/jbd2/commit.c2
-rw-r--r--fs/namei.c9
-rw-r--r--fs/namespace.c20
-rw-r--r--fs/nfs/Kconfig2
-rw-r--r--fs/nfs/dir.c2
-rw-r--r--fs/nfs/direct.c1
-rw-r--r--fs/nfs/file.c4
-rw-r--r--fs/nfs/iostat.h24
-rw-r--r--fs/nfs/nfs4proc.c15
-rw-r--r--fs/nfs/nfs4xdr.c1
-rw-r--r--fs/nfs/super.c1
-rw-r--r--fs/nfs/write.c2
-rw-r--r--fs/nfsd/export.c22
-rw-r--r--fs/nfsd/nfs4acl.c2
-rw-r--r--fs/nfsd/nfs4state.c18
-rw-r--r--fs/nfsd/nfsproc.c1
-rw-r--r--fs/nfsd/vfs.c66
-rw-r--r--fs/notify/dnotify/dnotify.c15
-rw-r--r--fs/notify/fsnotify.c103
-rw-r--r--fs/notify/fsnotify.h16
-rw-r--r--fs/notify/group.c132
-rw-r--r--fs/notify/inode_mark.c64
-rw-r--r--fs/notify/inotify/inotify_fsnotify.c62
-rw-r--r--fs/notify/inotify/inotify_user.c219
-rw-r--r--fs/notify/notification.c161
-rw-r--r--fs/ocfs2/cluster/netdebug.c8
-rw-r--r--fs/ocfs2/file.c2
-rw-r--r--fs/open.c29
-rw-r--r--fs/pipe.c41
-rw-r--r--fs/proc/array.c11
-rw-r--r--fs/proc/base.c78
-rw-r--r--fs/proc/stat.c19
-rw-r--r--fs/qnx4/bitmap.c2
-rw-r--r--fs/qnx4/dir.c6
-rw-r--r--fs/qnx4/inode.c26
-rw-r--r--fs/qnx4/namei.c6
-rw-r--r--fs/quota/Kconfig2
-rw-r--r--fs/quota/dquot.c93
-rw-r--r--fs/quota/quota.c93
-rw-r--r--fs/read_write.c8
-rw-r--r--fs/reiserfs/Makefile2
-rw-r--r--fs/reiserfs/bitmap.c4
-rw-r--r--fs/reiserfs/dir.c10
-rw-r--r--fs/reiserfs/do_balan.c17
-rw-r--r--fs/reiserfs/file.c2
-rw-r--r--fs/reiserfs/fix_node.c19
-rw-r--r--fs/reiserfs/inode.c95
-rw-r--r--fs/reiserfs/ioctl.c77
-rw-r--r--fs/reiserfs/journal.c130
-rw-r--r--fs/reiserfs/lock.c88
-rw-r--r--fs/reiserfs/namei.c20
-rw-r--r--fs/reiserfs/prints.c4
-rw-r--r--fs/reiserfs/resize.c2
-rw-r--r--fs/reiserfs/stree.c53
-rw-r--r--fs/reiserfs/super.c52
-rw-r--r--fs/reiserfs/xattr.c6
-rw-r--r--fs/sync.c13
-rw-r--r--fs/ubifs/file.c13
-rw-r--r--fs/xattr_acl.c2
-rw-r--r--fs/xfs/linux-2.6/xfs_lrw.c2
-rw-r--r--fs/xfs/quota/xfs_qm_syscalls.c1
-rw-r--r--fs/xfs/xfs_mount.c12
-rw-r--r--include/acpi/acpixf.h2
-rw-r--r--include/asm-generic/fcntl.h25
-rw-r--r--include/asm-generic/percpu.h5
-rw-r--r--include/asm-generic/socket.h1
-rw-r--r--include/crypto/algapi.h1
-rw-r--r--include/crypto/cryptd.h1
-rw-r--r--include/drm/drm.h33
-rw-r--r--include/drm/drmP.h26
-rw-r--r--include/linux/Kbuild5
-rw-r--r--include/linux/can/dev.h20
-rw-r--r--include/linux/can/platform/ti_hecc.h40
-rw-r--r--include/linux/clocksource.h1
-rw-r--r--include/linux/compiler-gcc4.h6
-rw-r--r--include/linux/compiler.h11
-rw-r--r--include/linux/crypto.h27
-rw-r--r--include/linux/device.h11
-rw-r--r--include/linux/dm-log-userspace.h2
-rw-r--r--include/linux/dmar.h10
-rw-r--r--include/linux/drbd.h350
-rw-r--r--include/linux/drbd_limits.h137
-rw-r--r--include/linux/drbd_nl.h137
-rw-r--r--include/linux/drbd_tag_magic.h83
-rw-r--r--include/linux/edac_mce.h31
-rw-r--r--include/linux/ethtool.h36
-rw-r--r--include/linux/exportfs.h2
-rw-r--r--include/linux/filter.h4
-rw-r--r--include/linux/firewire.h16
-rw-r--r--include/linux/fs.h2
-rw-r--r--include/linux/fsnotify.h44
-rw-r--r--include/linux/fsnotify_backend.h75
-rw-r--r--include/linux/ftrace_event.h34
-rw-r--r--include/linux/hardirq.h24
-rw-r--r--include/linux/hpet.h2
-rw-r--r--include/linux/i2c.h94
-rw-r--r--include/linux/i2c/twl4030.h9
-rw-r--r--include/linux/if_tunnel.h12
-rw-r--r--include/linux/if_vlan.h14
-rw-r--r--include/linux/input-polldev.h11
-rw-r--r--include/linux/intel-iommu.h1
-rw-r--r--include/linux/ioq.h415
-rw-r--r--include/linux/ipv6.h4
-rw-r--r--include/linux/irqflags.h2
-rw-r--r--include/linux/kernel.h5
-rw-r--r--include/linux/kernel_stat.h1
-rw-r--r--include/linux/kmemleak.h6
-rw-r--r--include/linux/kprobes.h2
-rw-r--r--include/linux/kvm_host.h52
-rw-r--r--include/linux/lru_cache.h294
-rw-r--r--include/linux/mfd/88pm8607.h217
-rw-r--r--include/linux/mfd/ab4500.h262
-rw-r--r--include/linux/mfd/adp5520.h299
-rw-r--r--include/linux/mfd/pcf50633/core.h10
-rw-r--r--include/linux/mfd/tmio.h40
-rw-r--r--include/linux/mfd/wm831x/core.h3
-rw-r--r--include/linux/mfd/wm831x/pdata.h17
-rw-r--r--include/linux/mfd/wm8350/core.h6
-rw-r--r--include/linux/mfd/wm8350/gpio.h18
-rw-r--r--include/linux/mmdebug.h2
-rw-r--r--include/linux/mmzone.h2
-rw-r--r--include/linux/moduleparam.h1
-rw-r--r--include/linux/mroute.h13
-rw-r--r--include/linux/mtd/bbm.h35
-rw-r--r--include/linux/mtd/flashchip.h7
-rw-r--r--include/linux/mtd/nand.h93
-rw-r--r--include/linux/mtd/onenand.h19
-rw-r--r--include/linux/mtd/ubi.h2
-rw-r--r--include/linux/net.h2
-rw-r--r--include/linux/netdevice.h2
-rw-r--r--include/linux/nl80211.h2
-rw-r--r--include/linux/notifier.h1
-rw-r--r--include/linux/of.h103
-rw-r--r--include/linux/of_fdt.h86
-rw-r--r--include/linux/page-flags.h2
-rw-r--r--include/linux/pci.h4
-rw-r--r--include/linux/pci_ids.h29
-rw-r--r--include/linux/pci_regs.h13
-rw-r--r--include/linux/percpu.h424
-rw-r--r--include/linux/perf_counter.h1
-rw-r--r--include/linux/perf_event.h10
-rw-r--r--include/linux/pm.h13
-rw-r--r--include/linux/pm_link.h30
-rw-r--r--include/linux/poison.h16
-rw-r--r--include/linux/posix-timers.h2
-rw-r--r--include/linux/posix_acl.h14
-rw-r--r--include/linux/quota.h11
-rw-r--r--include/linux/ratelimit.h33
-rw-r--r--include/linux/rcu_types.h18
-rw-r--r--include/linux/rcupdate.h17
-rw-r--r--include/linux/rcutiny.h95
-rw-r--r--include/linux/rcutree.h6
-rw-r--r--include/linux/regulator/machine.h6
-rw-r--r--include/linux/regulator/max8660.h57
-rw-r--r--include/linux/reiserfs_fs.h71
-rw-r--r--include/linux/reiserfs_fs_sb.h20
-rw-r--r--include/linux/resource.h2
-rw-r--r--include/linux/resume-trace.h7
-rw-r--r--include/linux/sched.h4
-rw-r--r--include/linux/security.h50
-rw-r--r--include/linux/serio.h1
-rw-r--r--include/linux/sh_intc.h4
-rw-r--r--include/linux/shm_signal.h189
-rw-r--r--include/linux/skbuff.h16
-rw-r--r--include/linux/slab.h10
-rw-r--r--include/linux/slqb_def.h301
-rw-r--r--include/linux/smp_lock.h21
-rw-r--r--include/linux/smsc911x.h1
-rw-r--r--include/linux/socket.h10
-rw-r--r--include/linux/spi/spi_bitbang.h2
-rw-r--r--include/linux/srcu.h1
-rw-r--r--include/linux/ssb/ssb.h20
-rw-r--r--include/linux/syscalls.h16
-rw-r--r--include/linux/tc_act/tc_skbedit.h2
-rw-r--r--include/linux/timex.h9
-rw-r--r--include/linux/topology.h4
-rw-r--r--include/linux/tpm.h7
-rw-r--r--include/linux/trace_seq.h2
-rw-r--r--include/linux/udp.h6
-rw-r--r--include/linux/usb/usbnet.h1
-rw-r--r--include/linux/user-return-notifier.h42
-rw-r--r--include/linux/vbus_driver.h81
-rw-r--r--include/linux/vbus_pci.h145
-rw-r--r--include/linux/venet.h133
-rw-r--r--include/linux/vermagic.h2
-rw-r--r--include/linux/videodev2.h1
-rw-r--r--include/linux/virtio_9p.h1
-rw-r--r--include/linux/virtio_balloon.h1
-rw-r--r--include/linux/virtio_blk.h5
-rw-r--r--include/linux/virtio_console.h1
-rw-r--r--include/linux/virtio_net.h1
-rw-r--r--include/linux/virtio_rng.h1
-rw-r--r--include/linux/vmstat.h10
-rw-r--r--include/net/ah.h30
-rw-r--r--include/net/bluetooth/bluetooth.h2
-rw-r--r--include/net/cfg80211.h40
-rw-r--r--include/net/compat.h14
-rw-r--r--include/net/dst.h12
-rw-r--r--include/net/gen_stats.h1
-rw-r--r--include/net/inet6_hashtables.h4
-rw-r--r--include/net/inet_hashtables.h16
-rw-r--r--include/net/inet_sock.h36
-rw-r--r--include/net/inet_timewait_sock.h10
-rw-r--r--include/net/ip.h12
-rw-r--r--include/net/ip_fib.h25
-rw-r--r--include/net/ipip.h20
-rw-r--r--include/net/iw_handler.h14
-rw-r--r--include/net/mac80211.h32
-rw-r--r--include/net/neighbour.h7
-rw-r--r--include/net/net_namespace.h6
-rw-r--r--include/net/netfilter/nf_conntrack.h4
-rw-r--r--include/net/phonet/phonet.h1
-rw-r--r--include/net/phonet/pn_dev.h6
-rw-r--r--include/net/snmp.h50
-rw-r--r--include/net/sock.h32
-rw-r--r--include/net/tc_act/tc_skbedit.h2
-rw-r--r--include/net/udp.h13
-rw-r--r--include/net/wext.h49
-rw-r--r--include/net/xfrm.h3
-rw-r--r--include/pcmcia/ds.h42
-rw-r--r--include/scsi/osd_initiator.h55
-rw-r--r--include/scsi/osd_sense.h3
-rw-r--r--include/sound/Kbuild1
-rw-r--r--include/sound/ac97_codec.h2
-rw-r--r--include/sound/ak4113.h321
-rw-r--r--include/sound/ak4114.h12
-rw-r--r--include/sound/ak4xxx-adda.h5
-rw-r--r--include/sound/soc-dai.h14
-rw-r--r--include/sound/soc-dapm.h17
-rw-r--r--include/sound/soc.h6
-rw-r--r--include/sound/sscape_ioctl.h21
-rw-r--r--include/sound/tlv320dac33-plat.h20
-rw-r--r--include/sound/tpa6130a2-plat.h (renamed from drivers/net/wireless/wl12xx/wl1251_netlink.h)18
-rw-r--r--include/trace/events/bkl.h61
-rw-r--r--include/trace/events/gfs2.h (renamed from fs/gfs2/trace_gfs2.h)7
-rw-r--r--include/trace/events/irq.h8
-rw-r--r--include/trace/events/mce.h69
-rw-r--r--include/trace/events/power.h2
-rw-r--r--include/trace/events/sched.h44
-rw-r--r--include/trace/events/timer.h79
-rw-r--r--include/trace/ftrace.h35
-rw-r--r--include/trace/syscall.h13
-rw-r--r--include/xen/xen.h32
-rw-r--r--init/Kconfig28
-rw-r--r--init/Makefile8
-rw-r--r--init/version.c4
-rw-r--r--ipc/msg.c2
-rw-r--r--kernel/Makefile7
-rw-r--r--kernel/audit.c1
-rw-r--r--kernel/audit.h26
-rw-r--r--kernel/audit_tree.c224
-rw-r--r--kernel/audit_watch.c300
-rw-r--r--kernel/auditfilter.c39
-rw-r--r--kernel/auditsc.c9
-rw-r--r--kernel/bounds.c2
-rw-r--r--kernel/capability.c9
-rw-r--r--kernel/cpuset.c8
-rw-r--r--kernel/futex.c24
-rw-r--r--kernel/irq/manage.c2
-rw-r--r--kernel/kexec.c2
-rw-r--r--kernel/kgdb.c31
-rw-r--r--kernel/kprobes.c68
-rw-r--r--kernel/module.c163
-rw-r--r--kernel/notifier.c2
-rw-r--r--kernel/params.c17
-rw-r--r--kernel/perf_event.c148
-rw-r--r--kernel/posix-cpu-timers.c10
-rw-r--r--kernel/power/Kconfig14
-rw-r--r--kernel/power/Makefile2
-rw-r--r--kernel/power/hibernate.c37
-rw-r--r--kernel/power/main.c31
-rw-r--r--kernel/power/process.c14
-rw-r--r--kernel/power/suspend_test.c5
-rw-r--r--kernel/power/swap.c109
-rw-r--r--kernel/power/swsusp.c188
-rw-r--r--kernel/printk.c7
-rw-r--r--kernel/rcupdate.c4
-rw-r--r--kernel/rcutiny.c291
-rw-r--r--kernel/rcutorture.c39
-rw-r--r--kernel/rcutree.c51
-rw-r--r--kernel/rcutree.h10
-rw-r--r--kernel/rcutree_plugin.h46
-rw-r--r--kernel/rcutree_trace.c8
-rw-r--r--kernel/sched.c15
-rw-r--r--kernel/sched_fair.c74
-rw-r--r--kernel/smp.c11
-rw-r--r--kernel/softlockup.c16
-rw-r--r--kernel/srcu.c74
-rw-r--r--kernel/sys.c68
-rw-r--r--kernel/sys_ni.c2
-rw-r--r--kernel/sysctl.c3
-rw-r--r--kernel/time.c1
-rw-r--r--kernel/time/clocksource.c2
-rw-r--r--kernel/time/timekeeping.c108
-rw-r--r--kernel/trace/Kconfig12
-rw-r--r--kernel/trace/Makefile1
-rw-r--r--kernel/trace/ftrace.c372
-rw-r--r--kernel/trace/ring_buffer.c27
-rw-r--r--kernel/trace/trace.c22
-rw-r--r--kernel/trace/trace.h73
-rw-r--r--kernel/trace/trace_event_profile.c4
-rw-r--r--kernel/trace/trace_events.c191
-rw-r--r--kernel/trace/trace_events_filter.c423
-rw-r--r--kernel/trace/trace_export.c39
-rw-r--r--kernel/trace/trace_functions_graph.c4
-rw-r--r--kernel/trace/trace_kprobe.c1479
-rw-r--r--kernel/trace/trace_output.c5
-rw-r--r--kernel/trace/trace_syscalls.c122
-rw-r--r--kernel/user-return-notifier.c46
-rw-r--r--lib/Kconfig24
-rw-r--r--lib/Kconfig.debug22
-rw-r--r--lib/Makefile4
-rw-r--r--lib/checksum.c14
-rw-r--r--lib/idr.c4
-rw-r--r--lib/ioq.c296
-rw-r--r--lib/kernel_lock.c20
-rw-r--r--lib/lru_cache.c560
-rw-r--r--lib/ratelimit.c45
-rw-r--r--lib/shm_signal.c192
-rw-r--r--lib/vsprintf.c80
-rw-r--r--mm/Kconfig2
-rw-r--r--mm/Makefile5
-rw-r--r--mm/allocpercpu.c177
-rw-r--r--mm/filemap.c49
-rw-r--r--mm/kmemleak.c53
-rw-r--r--mm/memcontrol.c2
-rw-r--r--mm/mmap.c4
-rw-r--r--mm/percpu.c2
-rw-r--r--mm/slab.c10
-rw-r--r--mm/slqb.c3791
-rw-r--r--mm/slub.c18
-rw-r--r--mm/truncate.c2
-rw-r--r--net/8021q/vlan.h2
-rw-r--r--net/8021q/vlan_dev.c2
-rw-r--r--net/9p/trans_virtio.c1
-rw-r--r--net/appletalk/ddp.c2
-rw-r--r--net/atm/common.c2
-rw-r--r--net/atm/pvc.c2
-rw-r--r--net/atm/svc.c2
-rw-r--r--net/ax25/af_ax25.c2
-rw-r--r--net/bluetooth/af_bluetooth.c6
-rw-r--r--net/bluetooth/bnep/core.c4
-rw-r--r--net/bluetooth/bnep/sock.c2
-rw-r--r--net/bluetooth/cmtp/sock.c2
-rw-r--r--net/bluetooth/hci_sock.c2
-rw-r--r--net/bluetooth/hci_sysfs.c4
-rw-r--r--net/bluetooth/hidp/sock.c2
-rw-r--r--net/bluetooth/l2cap.c11
-rw-r--r--net/bluetooth/rfcomm/sock.c4
-rw-r--r--net/bluetooth/sco.c2
-rw-r--r--net/bridge/br_device.c1
-rw-r--r--net/can/af_can.c2
-rw-r--r--net/can/bcm.c2
-rw-r--r--net/can/raw.c2
-rw-r--r--net/compat.c33
-rw-r--r--net/core/datagram.c1
-rw-r--r--net/core/dev.c54
-rw-r--r--net/core/ethtool.c81
-rw-r--r--net/core/filter.c6
-rw-r--r--net/core/gen_stats.c8
-rw-r--r--net/core/net-sysfs.c46
-rw-r--r--net/core/pktgen.c26
-rw-r--r--net/core/rtnetlink.c75
-rw-r--r--net/core/sock.c43
-rw-r--r--net/core/sysctl_net_core.c2
-rw-r--r--net/core/utils.c2
-rw-r--r--net/dccp/ccids/ccid2.c327
-rw-r--r--net/dccp/ccids/ccid2.h46
-rw-r--r--net/dccp/ccids/ccid3.c400
-rw-r--r--net/dccp/ccids/ccid3.h120
-rw-r--r--net/dccp/ipv4.c40
-rw-r--r--net/dccp/ipv6.c31
-rw-r--r--net/dccp/output.c4
-rw-r--r--net/dccp/probe.c31
-rw-r--r--net/dccp/proto.c17
-rw-r--r--net/dccp/timer.c4
-rw-r--r--net/decnet/af_decnet.c4
-rw-r--r--net/econet/af_econet.c10
-rw-r--r--net/ieee802154/af_ieee802154.c2
-rw-r--r--net/ieee802154/dgram.c3
-rw-r--r--net/ieee802154/raw.c3
-rw-r--r--net/ipv4/Kconfig6
-rw-r--r--net/ipv4/af_inet.c64
-rw-r--r--net/ipv4/ah4.c295
-rw-r--r--net/ipv4/cipso_ipv4.c2
-rw-r--r--net/ipv4/datagram.c18
-rw-r--r--net/ipv4/fib_frontend.c26
-rw-r--r--net/ipv4/fib_hash.c25
-rw-r--r--net/ipv4/fib_rules.c2
-rw-r--r--net/ipv4/fib_trie.c26
-rw-r--r--net/ipv4/icmp.c4
-rw-r--r--net/ipv4/inet_connection_sock.c55
-rw-r--r--net/ipv4/inet_diag.c28
-rw-r--r--net/ipv4/inet_hashtables.c36
-rw-r--r--net/ipv4/inet_timewait_sock.c14
-rw-r--r--net/ipv4/ip_gre.c45
-rw-r--r--net/ipv4/ip_input.c2
-rw-r--r--net/ipv4/ip_output.c15
-rw-r--r--net/ipv4/ip_sockglue.c17
-rw-r--r--net/ipv4/ipconfig.c2
-rw-r--r--net/ipv4/ipip.c54
-rw-r--r--net/ipv4/ipmr.c14
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c8
-rw-r--r--net/ipv4/raw.c33
-rw-r--r--net/ipv4/route.c3
-rw-r--r--net/ipv4/syncookies.c3
-rw-r--r--net/ipv4/tcp.c74
-rw-r--r--net/ipv4/tcp_ipv4.c76
-rw-r--r--net/ipv4/tcp_minisocks.c5
-rw-r--r--net/ipv4/tcp_output.c4
-rw-r--r--net/ipv4/tcp_probe.c11
-rw-r--r--net/ipv4/tcp_timer.c12
-rw-r--r--net/ipv4/udp.c165
-rw-r--r--net/ipv4/udplite.c4
-rw-r--r--net/ipv6/Kconfig19
-rw-r--r--net/ipv6/addrconf.c9
-rw-r--r--net/ipv6/af_inet6.c31
-rw-r--r--net/ipv6/ah6.c352
-rw-r--r--net/ipv6/datagram.c34
-rw-r--r--net/ipv6/inet6_connection_sock.c10
-rw-r--r--net/ipv6/inet6_hashtables.c14
-rw-r--r--net/ipv6/ip6_tunnel.c44
-rw-r--r--net/ipv6/ip6mr.c2
-rw-r--r--net/ipv6/ipv6_sockglue.c15
-rw-r--r--net/ipv6/ndisc.c1
-rw-r--r--net/ipv6/raw.c36
-rw-r--r--net/ipv6/route.c3
-rw-r--r--net/ipv6/sit.c252
-rw-r--r--net/ipv6/syncookies.c3
-rw-r--r--net/ipv6/tcp_ipv6.c40
-rw-r--r--net/ipv6/udp.c48
-rw-r--r--net/ipv6/xfrm6_tunnel.c47
-rw-r--r--net/ipx/af_ipx.c2
-rw-r--r--net/irda/af_irda.c2
-rw-r--r--net/iucv/af_iucv.c7
-rw-r--r--net/key/af_key.c4
-rw-r--r--net/llc/af_llc.c2
-rw-r--r--net/mac80211/ibss.c6
-rw-r--r--net/mac80211/iface.c14
-rw-r--r--net/mac80211/mesh.c4
-rw-r--r--net/mac80211/mesh_hwmp.c2
-rw-r--r--net/mac80211/mlme.c25
-rw-r--r--net/mac80211/rx.c21
-rw-r--r--net/mac80211/scan.c10
-rw-r--r--net/mac80211/tx.c2
-rw-r--r--net/netfilter/xt_socket.c2
-rw-r--r--net/netlink/af_netlink.c2
-rw-r--r--net/netlink/genetlink.c32
-rw-r--r--net/netrom/af_netrom.c2
-rw-r--r--net/packet/af_packet.c31
-rw-r--r--net/phonet/af_phonet.c57
-rw-r--r--net/phonet/datagram.c6
-rw-r--r--net/phonet/pep.c2
-rw-r--r--net/phonet/pn_dev.c131
-rw-r--r--net/phonet/pn_netlink.c130
-rw-r--r--net/phonet/socket.c23
-rw-r--r--net/rds/af_rds.c2
-rw-r--r--net/rds/tcp_listen.c8
-rw-r--r--net/rose/af_rose.c2
-rw-r--r--net/rxrpc/af_rxrpc.c2
-rw-r--r--net/rxrpc/ar-recvmsg.c2
-rw-r--r--net/sched/act_api.c5
-rw-r--r--net/sched/act_skbedit.c17
-rw-r--r--net/sched/sch_api.c2
-rw-r--r--net/sched/sch_cbq.c2
-rw-r--r--net/sched/sch_drr.c2
-rw-r--r--net/sched/sch_hfsc.c2
-rw-r--r--net/sched/sch_htb.c2
-rw-r--r--net/sctp/protocol.c8
-rw-r--r--net/sctp/sm_statefuns.c2
-rw-r--r--net/sctp/socket.c32
-rw-r--r--net/socket.c247
-rw-r--r--net/sunrpc/svcauth_unix.c56
-rw-r--r--net/sunrpc/svcsock.c8
-rw-r--r--net/unix/af_unix.c4
-rw-r--r--net/wireless/Kconfig50
-rw-r--r--net/wireless/Makefile10
-rw-r--r--net/wireless/core.c24
-rw-r--r--net/wireless/core.h1
-rw-r--r--net/wireless/ethtool.c45
-rw-r--r--net/wireless/ethtool.h6
-rw-r--r--net/wireless/ibss.c10
-rw-r--r--net/wireless/mlme.c56
-rw-r--r--net/wireless/nl80211.c6
-rw-r--r--net/wireless/scan.c6
-rw-r--r--net/wireless/sme.c33
-rw-r--r--net/wireless/wext-core.c (renamed from net/wireless/wext.c)1456
-rw-r--r--net/wireless/wext-priv.c248
-rw-r--r--net/wireless/wext-proc.c155
-rw-r--r--net/wireless/wext-spy.c231
-rw-r--r--net/x25/af_x25.c4
-rw-r--r--net/xfrm/xfrm_algo.c78
-rw-r--r--samples/Kconfig3
-rw-r--r--scripts/.gitignore1
-rw-r--r--scripts/Makefile.lib2
-rw-r--r--scripts/basic/fixdep.c10
-rw-r--r--scripts/binoffset.c163
-rwxr-xr-xscripts/extract-ikconfig127
-rwxr-xr-xscripts/headers.sh2
-rw-r--r--scripts/kconfig/confdata.c2
-rwxr-xr-xscripts/mkcompile_h2
-rwxr-xr-xscripts/recordmcount.pl1
-rw-r--r--scripts/selinux/Makefile4
-rw-r--r--scripts/selinux/genheaders/.gitignore1
-rw-r--r--scripts/selinux/genheaders/Makefile5
-rw-r--r--scripts/selinux/genheaders/genheaders.c118
-rw-r--r--scripts/selinux/mdp/mdp.c151
-rw-r--r--security/Kconfig13
-rw-r--r--security/Makefile1
-rw-r--r--security/capability.c22
-rw-r--r--security/commoncap.c2
-rw-r--r--security/integrity/ima/Kconfig1
-rw-r--r--security/lsm_audit.c12
-rw-r--r--security/root_plug.c90
-rw-r--r--security/security.c53
-rw-r--r--security/selinux/.gitignore2
-rw-r--r--security/selinux/Makefile10
-rw-r--r--security/selinux/avc.c76
-rw-r--r--security/selinux/hooks.c22
-rw-r--r--security/selinux/include/av_inherit.h34
-rw-r--r--security/selinux/include/av_perm_to_string.h183
-rw-r--r--security/selinux/include/av_permissions.h870
-rw-r--r--security/selinux/include/avc_ss.h21
-rw-r--r--security/selinux/include/class_to_string.h80
-rw-r--r--security/selinux/include/classmap.h150
-rw-r--r--security/selinux/include/common_perm_to_string.h58
-rw-r--r--security/selinux/include/flask.h91
-rw-r--r--security/selinux/include/security.h13
-rw-r--r--security/selinux/selinuxfs.c4
-rw-r--r--security/selinux/ss/Makefile2
-rw-r--r--security/selinux/ss/mls.c2
-rw-r--r--security/selinux/ss/policydb.c47
-rw-r--r--security/selinux/ss/policydb.h7
-rw-r--r--security/selinux/ss/services.c555
-rw-r--r--sound/Kconfig4
-rw-r--r--sound/core/isadma.c10
-rw-r--r--sound/core/rawmidi.c2
-rw-r--r--sound/i2c/other/Makefile3
-rw-r--r--sound/i2c/other/ak4113.c639
-rw-r--r--sound/i2c/other/ak4xxx-adda.c136
-rw-r--r--sound/isa/Kconfig12
-rw-r--r--sound/isa/sscape.c727
-rw-r--r--sound/isa/wss/wss_lib.c98
-rw-r--r--sound/oss/Kconfig2
-rw-r--r--sound/oss/au1550_ac97.c16
-rw-r--r--sound/pci/Kconfig1
-rw-r--r--sound/pci/hda/hda_intel.c16
-rw-r--r--sound/pci/hda/patch_cirrus.c2
-rw-r--r--sound/pci/hda/patch_realtek.c139
-rw-r--r--sound/pci/hda/patch_via.c3501
-rw-r--r--sound/pci/ice1712/Makefile2
-rw-r--r--sound/pci/ice1712/ice1712.c12
-rw-r--r--sound/pci/ice1712/ice1712.h14
-rw-r--r--sound/pci/ice1712/ice1724.c103
-rw-r--r--sound/pci/ice1712/juli.c26
-rw-r--r--sound/pci/ice1712/quartet.c1130
-rw-r--r--sound/pci/ice1712/quartet.h10
-rw-r--r--sound/pci/oxygen/Makefile3
-rw-r--r--sound/pci/oxygen/cs2000.h83
-rw-r--r--sound/pci/oxygen/hifier.c61
-rw-r--r--sound/pci/oxygen/oxygen.c248
-rw-r--r--sound/pci/oxygen/oxygen.h5
-rw-r--r--sound/pci/oxygen/oxygen_lib.c29
-rw-r--r--sound/pci/oxygen/oxygen_mixer.c52
-rw-r--r--sound/pci/oxygen/oxygen_pcm.c19
-rw-r--r--sound/pci/oxygen/virtuoso.c1105
-rw-r--r--sound/pci/oxygen/xonar.h50
-rw-r--r--sound/pci/oxygen/xonar_cs43xx.c434
-rw-r--r--sound/pci/oxygen/xonar_hdmi.c128
-rw-r--r--sound/pci/oxygen/xonar_lib.c132
-rw-r--r--sound/pci/oxygen/xonar_pcm179x.c1115
-rw-r--r--sound/ppc/Kconfig2
-rw-r--r--sound/soc/atmel/playpaq_wm8510.c2
-rw-r--r--sound/soc/atmel/sam9g20_wm8731.c2
-rw-r--r--sound/soc/au1x/dbdma2.c14
-rw-r--r--sound/soc/blackfin/bf5xx-ad1836.c7
-rw-r--r--sound/soc/blackfin/bf5xx-ad1938.c9
-rw-r--r--sound/soc/blackfin/bf5xx-i2s.c15
-rw-r--r--sound/soc/blackfin/bf5xx-tdm-pcm.c9
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.c45
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.h11
-rw-r--r--sound/soc/codecs/Kconfig16
-rw-r--r--sound/soc/codecs/Makefile8
-rw-r--r--sound/soc/codecs/ak4671.c825
-rw-r--r--sound/soc/codecs/ak4671.h156
-rw-r--r--sound/soc/codecs/cs4270.c20
-rw-r--r--sound/soc/codecs/tlv320dac33.c1237
-rw-r--r--sound/soc/codecs/tlv320dac33.h267
-rw-r--r--sound/soc/codecs/tpa6130a2.c463
-rw-r--r--sound/soc/codecs/tpa6130a2.h61
-rw-r--r--sound/soc/codecs/wm8350.c19
-rw-r--r--sound/soc/codecs/wm8400.c20
-rw-r--r--sound/soc/codecs/wm8510.c4
-rw-r--r--sound/soc/codecs/wm8523.c17
-rw-r--r--sound/soc/codecs/wm8580.c21
-rw-r--r--sound/soc/codecs/wm8711.c642
-rw-r--r--sound/soc/codecs/wm8711.h42
-rw-r--r--sound/soc/codecs/wm8731.c34
-rw-r--r--sound/soc/codecs/wm8753.c39
-rw-r--r--sound/soc/codecs/wm8776.c34
-rw-r--r--sound/soc/codecs/wm8900.c21
-rw-r--r--sound/soc/codecs/wm8903.c17
-rw-r--r--sound/soc/codecs/wm8940.c21
-rw-r--r--sound/soc/codecs/wm8960.c21
-rw-r--r--sound/soc/codecs/wm8961.c17
-rw-r--r--sound/soc/codecs/wm8974.c27
-rw-r--r--sound/soc/codecs/wm8988.c34
-rw-r--r--sound/soc/codecs/wm8990.c4
-rw-r--r--sound/soc/codecs/wm8993.c38
-rw-r--r--sound/soc/codecs/wm9081.c17
-rw-r--r--sound/soc/codecs/wm9713.c4
-rw-r--r--sound/soc/codecs/wm_hubs.c35
-rw-r--r--sound/soc/codecs/wm_hubs.h5
-rw-r--r--sound/soc/davinci/Kconfig4
-rw-r--r--sound/soc/davinci/davinci-evm.c7
-rw-r--r--sound/soc/davinci/davinci-i2s.c2
-rw-r--r--sound/soc/davinci/davinci-mcasp.c17
-rw-r--r--sound/soc/davinci/davinci-pcm.c21
-rw-r--r--sound/soc/davinci/davinci-pcm.h1
-rw-r--r--sound/soc/imx/mx27vis_wm8974.c2
-rw-r--r--sound/soc/omap/ams-delta.c4
-rw-r--r--sound/soc/omap/n810.c2
-rw-r--r--sound/soc/omap/omap-mcbsp.c6
-rw-r--r--sound/soc/omap/omap-pcm.c2
-rw-r--r--sound/soc/omap/omap2evm.c2
-rw-r--r--sound/soc/omap/omap3beagle.c2
-rw-r--r--sound/soc/omap/omap3evm.c2
-rw-r--r--sound/soc/omap/osk5912.c2
-rw-r--r--sound/soc/omap/overo.c2
-rw-r--r--sound/soc/omap/sdp3430.c2
-rw-r--r--sound/soc/omap/zoom2.c2
-rw-r--r--sound/soc/pxa/Kconfig3
-rw-r--r--sound/soc/pxa/magician.c2
-rw-r--r--sound/soc/pxa/pxa-ssp.c20
-rw-r--r--sound/soc/pxa/zylonite.c5
-rw-r--r--sound/soc/s3c24xx/Kconfig9
-rw-r--r--sound/soc/s3c24xx/Makefile2
-rw-r--r--sound/soc/s3c24xx/neo1973_gta02_wm8753.c8
-rw-r--r--sound/soc/s3c24xx/neo1973_wm8753.c9
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.c31
-rw-r--r--sound/soc/s3c24xx/s3c2412-i2s.c1
-rw-r--r--sound/soc/s3c24xx/s3c2443-ac97.c1
-rw-r--r--sound/soc/s3c24xx/s3c24xx-i2s.c2
-rw-r--r--sound/soc/s3c24xx/s3c24xx-pcm.c1
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s.c20
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s.h1
-rw-r--r--sound/soc/s3c24xx/smdk64xx_wm8580.c273
-rw-r--r--sound/soc/soc-cache.c46
-rw-r--r--sound/soc/soc-core.c101
-rw-r--r--sound/soc/soc-dapm.c137
-rw-r--r--sound/usb/usx2y/us122l.c75
-rw-r--r--tools/perf/Documentation/perf-probe.txt48
-rw-r--r--tools/perf/Documentation/perf-timechart.txt5
-rw-r--r--tools/perf/Makefile79
-rw-r--r--tools/perf/builtin-annotate.c645
-rw-r--r--tools/perf/builtin-probe.c372
-rw-r--r--tools/perf/builtin-record.c270
-rw-r--r--tools/perf/builtin-report.c961
-rw-r--r--tools/perf/builtin-sched.c310
-rw-r--r--tools/perf/builtin-stat.c31
-rw-r--r--tools/perf/builtin-timechart.c146
-rw-r--r--tools/perf/builtin-top.c308
-rw-r--r--tools/perf/builtin-trace.c174
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/command-list.txt1
-rw-r--r--tools/perf/perf.c17
-rw-r--r--tools/perf/perf.h6
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN2
-rw-r--r--tools/perf/util/cache.h11
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/callchain.h2
-rw-r--r--tools/perf/util/color.h6
-rw-r--r--tools/perf/util/data_map.c222
-rw-r--r--tools/perf/util/data_map.h31
-rw-r--r--tools/perf/util/debug.c4
-rw-r--r--tools/perf/util/debug.h7
-rw-r--r--tools/perf/util/event.c177
-rw-r--r--tools/perf/util/event.h33
-rw-r--r--tools/perf/util/exec_cmd.h6
-rw-r--r--tools/perf/util/header.c74
-rw-r--r--tools/perf/util/header.h29
-rw-r--r--tools/perf/util/help.h6
-rw-r--r--tools/perf/util/hist.c210
-rw-r--r--tools/perf/util/hist.h50
-rw-r--r--tools/perf/util/include/asm/asm-offsets.h1
-rw-r--r--tools/perf/util/include/asm/bitops.h18
-rw-r--r--tools/perf/util/include/asm/byteorder.h2
-rw-r--r--tools/perf/util/include/asm/swab.h1
-rw-r--r--tools/perf/util/include/asm/uaccess.h14
-rw-r--r--tools/perf/util/include/linux/bitmap.h2
-rw-r--r--tools/perf/util/include/linux/bitops.h27
-rw-r--r--tools/perf/util/include/linux/compiler.h10
-rw-r--r--tools/perf/util/include/linux/ctype.h1
-rw-r--r--tools/perf/util/include/linux/kernel.h76
-rw-r--r--tools/perf/util/include/linux/string.h1
-rw-r--r--tools/perf/util/include/linux/types.h9
-rw-r--r--tools/perf/util/levenshtein.h6
-rw-r--r--tools/perf/util/map.c26
-rw-r--r--tools/perf/util/module.c545
-rw-r--r--tools/perf/util/module.h53
-rw-r--r--tools/perf/util/parse-events.c48
-rw-r--r--tools/perf/util/parse-events.h8
-rw-r--r--tools/perf/util/parse-options.h6
-rw-r--r--tools/perf/util/probe-finder.c677
-rw-r--r--tools/perf/util/probe-finder.h53
-rw-r--r--tools/perf/util/quote.h6
-rw-r--r--tools/perf/util/run-command.h6
-rw-r--r--tools/perf/util/sigchain.h6
-rw-r--r--tools/perf/util/sort.c290
-rw-r--r--tools/perf/util/sort.h99
-rw-r--r--tools/perf/util/strbuf.h6
-rw-r--r--tools/perf/util/string.c11
-rw-r--r--tools/perf/util/string.h7
-rw-r--r--tools/perf/util/strlist.h6
-rw-r--r--tools/perf/util/svghelper.c2
-rw-r--r--tools/perf/util/svghelper.h6
-rw-r--r--tools/perf/util/symbol.c791
-rw-r--r--tools/perf/util/symbol.h44
-rw-r--r--tools/perf/util/thread.c167
-rw-r--r--tools/perf/util/thread.h31
-rw-r--r--tools/perf/util/trace-event-info.c6
-rw-r--r--tools/perf/util/trace-event-parse.c537
-rw-r--r--tools/perf/util/trace-event-read.c7
-rw-r--r--tools/perf/util/trace-event.h41
-rw-r--r--tools/perf/util/types.h6
-rw-r--r--tools/perf/util/util.h9
-rw-r--r--tools/perf/util/values.h6
-rw-r--r--virt/kvm/assigned-dev.c818
-rw-r--r--virt/kvm/eventfd.c2
-rw-r--r--virt/kvm/ioapic.c80
-rw-r--r--virt/kvm/ioapic.h5
-rw-r--r--virt/kvm/irq_comm.c221
-rw-r--r--virt/kvm/kvm_main.c901
2717 files changed, 201414 insertions, 75164 deletions
diff --git a/.gitignore b/.gitignore
index b93fb7eff942..4980606ab798 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,14 +44,8 @@ Module.symvers
#
# Generated include files
#
-include/asm
-include/asm-*/asm-offsets.h
include/config
-include/linux/autoconf.h
-include/linux/compile.h
include/linux/version.h
-include/linux/utsrelease.h
-include/linux/bounds.h
include/generated
# stgit generated dirs
diff --git a/Documentation/ABI/testing/sysfs-kernel-slab b/Documentation/ABI/testing/sysfs-kernel-slab
index 6dcf75e594fb..8b093f8222d3 100644
--- a/Documentation/ABI/testing/sysfs-kernel-slab
+++ b/Documentation/ABI/testing/sysfs-kernel-slab
@@ -45,8 +45,9 @@ KernelVersion: 2.6.25
Contact: Pekka Enberg <penberg@cs.helsinki.fi>,
Christoph Lameter <cl@linux-foundation.org>
Description:
- The alloc_fastpath file is read-only and specifies how many
- objects have been allocated using the fast path.
+ The alloc_fastpath file shows how many objects have been
+ allocated using the fast path. It can be written to clear the
+ current count.
Available when CONFIG_SLUB_STATS is enabled.
What: /sys/kernel/slab/cache/alloc_from_partial
@@ -55,9 +56,10 @@ KernelVersion: 2.6.25
Contact: Pekka Enberg <penberg@cs.helsinki.fi>,
Christoph Lameter <cl@linux-foundation.org>
Description:
- The alloc_from_partial file is read-only and specifies how
- many times a cpu slab has been full and it has been refilled
- by using a slab from the list of partially used slabs.
+ The alloc_from_partial file shows how many times a cpu slab has
+ been full and it has been refilled by using a slab from the list
+ of partially used slabs. It can be written to clear the current
+ count.
Available when CONFIG_SLUB_STATS is enabled.
What: /sys/kernel/slab/cache/alloc_refill
@@ -66,9 +68,9 @@ KernelVersion: 2.6.25
Contact: Pekka Enberg <penberg@cs.helsinki.fi>,
Christoph Lameter <cl@linux-foundation.org>
Description:
- The alloc_refill file is read-only and specifies how many
- times the per-cpu freelist was empty but there were objects
- available as the result of remote cpu frees.
+ The alloc_refill file shows how many times the per-cpu freelist
+ was empty but there were objects available as the result of
+ remote cpu frees. It can be written to clear the current count.
Available when CONFIG_SLUB_STATS is enabled.
What: /sys/kernel/slab/cache/alloc_slab
@@ -77,8 +79,9 @@ KernelVersion: 2.6.25
Contact: Pekka Enberg <penberg@cs.helsinki.fi>,
Christoph Lameter <cl@linux-foundation.org>
Description:
- The alloc_slab file is read-only and specifies how many times
- a new slab had to be allocated from the page allocator.
+ The alloc_slab file is shows how many times a new slab had to
+ be allocated from the page allocator. It can be written to
+ clear the current count.
Available when CONFIG_SLUB_STATS is enabled.
What: /sys/kernel/slab/cache/alloc_slowpath
@@ -87,9 +90,10 @@ KernelVersion: 2.6.25
Contact: Pekka Enberg <penberg@cs.helsinki.fi>,
Christoph Lameter <cl@linux-foundation.org>
Description:
- The alloc_slowpath file is read-only and specifies how many
- objects have been allocated using the slow path because of a
- refill or allocation from a partial or new slab.
+ The alloc_slowpath file shows how many objects have been
+ allocated using the slow path because of a refill or
+ allocation from a partial or new slab. It can be written to
+ clear the current count.
Available when CONFIG_SLUB_STATS is enabled.
What: /sys/kernel/slab/cache/cache_dma
@@ -117,10 +121,11 @@ KernelVersion: 2.6.31
Contact: Pekka Enberg <penberg@cs.helsinki.fi>,
Christoph Lameter <cl@linux-foundation.org>
Description:
- The file cpuslab_flush is read-only and specifies how many
- times a cache's cpu slabs have been flushed as the result of
- destroying or shrinking a cache, a cpu going offline, or as
- the result of forcing an allocation from a certain node.
+ The file cpuslab_flush shows how many times a cache's cpu slabs
+ have been flushed as the result of destroying or shrinking a
+ cache, a cpu going offline, or as the result of forcing an
+ allocation from a certain node. It can be written to clear the
+ current count.
Available when CONFIG_SLUB_STATS is enabled.
What: /sys/kernel/slab/cache/ctor
@@ -139,8 +144,8 @@ KernelVersion: 2.6.25
Contact: Pekka Enberg <penberg@cs.helsinki.fi>,
Christoph Lameter <cl@linux-foundation.org>
Description:
- The file deactivate_empty is read-only and specifies how many
- times an empty cpu slab was deactivated.
+ The deactivate_empty file shows how many times an empty cpu slab
+ was deactivated. It can be written to clear the current count.
Available when CONFIG_SLUB_STATS is enabled.
What: /sys/kernel/slab/cache/deactivate_full
@@ -149,8 +154,8 @@ KernelVersion: 2.6.25
Contact: Pekka Enberg <penberg@cs.helsinki.fi>,
Christoph Lameter <cl@linux-foundation.org>
Description:
- The file deactivate_full is read-only and specifies how many
- times a full cpu slab was deactivated.
+ The deactivate_full file shows how many times a full cpu slab
+ was deactivated. It can be written to clear the current count.
Available when CONFIG_SLUB_STATS is enabled.
What: /sys/kernel/slab/cache/deactivate_remote_frees
@@ -159,9 +164,9 @@ KernelVersion: 2.6.25
Contact: Pekka Enberg <penberg@cs.helsinki.fi>,
Christoph Lameter <cl@linux-foundation.org>
Description:
- The file deactivate_remote_frees is read-only and specifies how
- many times a cpu slab has been deactivated and contained free
- objects that were freed remotely.
+ The deactivate_remote_frees file shows how many times a cpu slab
+ has been deactivated and contained free objects that were freed
+ remotely. It can be written to clear the current count.
Available when CONFIG_SLUB_STATS is enabled.
What: /sys/kernel/slab/cache/deactivate_to_head
@@ -170,9 +175,9 @@ KernelVersion: 2.6.25
Contact: Pekka Enberg <penberg@cs.helsinki.fi>,
Christoph Lameter <cl@linux-foundation.org>
Description:
- The file deactivate_to_head is read-only and specifies how
- many times a partial cpu slab was deactivated and added to the
- head of its node's partial list.
+ The deactivate_to_head file shows how many times a partial cpu
+ slab was deactivated and added to the head of its node's partial
+ list. It can be written to clear the current count.
Available when CONFIG_SLUB_STATS is enabled.
What: /sys/kernel/slab/cache/deactivate_to_tail
@@ -181,9 +186,9 @@ KernelVersion: 2.6.25
Contact: Pekka Enberg <penberg@cs.helsinki.fi>,
Christoph Lameter <cl@linux-foundation.org>
Description:
- The file deactivate_to_tail is read-only and specifies how
- many times a partial cpu slab was deactivated and added to the
- tail of its node's partial list.
+ The deactivate_to_tail file shows how many times a partial cpu
+ slab was deactivated and added to the tail of its node's partial
+ list. It can be written to clear the current count.
Available when CONFIG_SLUB_STATS is enabled.
What: /sys/kernel/slab/cache/destroy_by_rcu
@@ -201,9 +206,9 @@ KernelVersion: 2.6.25
Contact: Pekka Enberg <penberg@cs.helsinki.fi>,
Christoph Lameter <cl@linux-foundation.org>
Description:
- The file free_add_partial is read-only and specifies how many
- times an object has been freed in a full slab so that it had to
- added to its node's partial list.
+ The free_add_partial file shows how many times an object has
+ been freed in a full slab so that it had to added to its node's
+ partial list. It can be written to clear the current count.
Available when CONFIG_SLUB_STATS is enabled.
What: /sys/kernel/slab/cache/free_calls
@@ -222,9 +227,9 @@ KernelVersion: 2.6.25
Contact: Pekka Enberg <penberg@cs.helsinki.fi>,
Christoph Lameter <cl@linux-foundation.org>
Description:
- The free_fastpath file is read-only and specifies how many
- objects have been freed using the fast path because it was an
- object from the cpu slab.
+ The free_fastpath file shows how many objects have been freed
+ using the fast path because it was an object from the cpu slab.
+ It can be written to clear the current count.
Available when CONFIG_SLUB_STATS is enabled.
What: /sys/kernel/slab/cache/free_frozen
@@ -233,9 +238,9 @@ KernelVersion: 2.6.25
Contact: Pekka Enberg <penberg@cs.helsinki.fi>,
Christoph Lameter <cl@linux-foundation.org>
Description:
- The free_frozen file is read-only and specifies how many
- objects have been freed to a frozen slab (i.e. a remote cpu
- slab).
+ The free_frozen file shows how many objects have been freed to
+ a frozen slab (i.e. a remote cpu slab). It can be written to
+ clear the current count.
Available when CONFIG_SLUB_STATS is enabled.
What: /sys/kernel/slab/cache/free_remove_partial
@@ -244,9 +249,10 @@ KernelVersion: 2.6.25
Contact: Pekka Enberg <penberg@cs.helsinki.fi>,
Christoph Lameter <cl@linux-foundation.org>
Description:
- The file free_remove_partial is read-only and specifies how
- many times an object has been freed to a now-empty slab so
- that it had to be removed from its node's partial list.
+ The free_remove_partial file shows how many times an object has
+ been freed to a now-empty slab so that it had to be removed from
+ its node's partial list. It can be written to clear the current
+ count.
Available when CONFIG_SLUB_STATS is enabled.
What: /sys/kernel/slab/cache/free_slab
@@ -255,8 +261,9 @@ KernelVersion: 2.6.25
Contact: Pekka Enberg <penberg@cs.helsinki.fi>,
Christoph Lameter <cl@linux-foundation.org>
Description:
- The free_slab file is read-only and specifies how many times an
- empty slab has been freed back to the page allocator.
+ The free_slab file shows how many times an empty slab has been
+ freed back to the page allocator. It can be written to clear
+ the current count.
Available when CONFIG_SLUB_STATS is enabled.
What: /sys/kernel/slab/cache/free_slowpath
@@ -265,9 +272,9 @@ KernelVersion: 2.6.25
Contact: Pekka Enberg <penberg@cs.helsinki.fi>,
Christoph Lameter <cl@linux-foundation.org>
Description:
- The free_slowpath file is read-only and specifies how many
- objects have been freed using the slow path (i.e. to a full or
- partial slab).
+ The free_slowpath file shows how many objects have been freed
+ using the slow path (i.e. to a full or partial slab). It can
+ be written to clear the current count.
Available when CONFIG_SLUB_STATS is enabled.
What: /sys/kernel/slab/cache/hwcache_align
@@ -346,10 +353,10 @@ KernelVersion: 2.6.26
Contact: Pekka Enberg <penberg@cs.helsinki.fi>,
Christoph Lameter <cl@linux-foundation.org>
Description:
- The file order_fallback is read-only and specifies how many
- times an allocation of a new slab has not been possible at the
- cache's order and instead fallen back to its minimum possible
- order.
+ The order_fallback file shows how many times an allocation of a
+ new slab has not been possible at the cache's order and instead
+ fallen back to its minimum possible order. It can be written to
+ clear the current count.
Available when CONFIG_SLUB_STATS is enabled.
What: /sys/kernel/slab/cache/partial
diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt
index 187bbf10c923..8608fd85e921 100644
--- a/Documentation/RCU/trace.txt
+++ b/Documentation/RCU/trace.txt
@@ -1,185 +1,10 @@
CONFIG_RCU_TRACE debugfs Files and Formats
-The rcupreempt and rcutree implementations of RCU provide debugfs trace
-output that summarizes counters and state. This information is useful for
-debugging RCU itself, and can sometimes also help to debug abuses of RCU.
-Note that the rcuclassic implementation of RCU does not provide debugfs
-trace output.
-
-The following sections describe the debugfs files and formats for
-preemptable RCU (rcupreempt) and hierarchical RCU (rcutree).
-
-
-Preemptable RCU debugfs Files and Formats
-
-This implementation of RCU provides three debugfs files under the
-top-level directory RCU: rcu/rcuctrs (which displays the per-CPU
-counters used by preemptable RCU) rcu/rcugp (which displays grace-period
-counters), and rcu/rcustats (which internal counters for debugging RCU).
-
-The output of "cat rcu/rcuctrs" looks as follows:
-
-CPU last cur F M
- 0 5 -5 0 0
- 1 -1 0 0 0
- 2 0 1 0 0
- 3 0 1 0 0
- 4 0 1 0 0
- 5 0 1 0 0
- 6 0 2 0 0
- 7 0 -1 0 0
- 8 0 1 0 0
-ggp = 26226, state = waitzero
-
-The per-CPU fields are as follows:
-
-o "CPU" gives the CPU number. Offline CPUs are not displayed.
-
-o "last" gives the value of the counter that is being decremented
- for the current grace period phase. In the example above,
- the counters sum to 4, indicating that there are still four
- RCU read-side critical sections still running that started
- before the last counter flip.
-
-o "cur" gives the value of the counter that is currently being
- both incremented (by rcu_read_lock()) and decremented (by
- rcu_read_unlock()). In the example above, the counters sum to
- 1, indicating that there is only one RCU read-side critical section
- still running that started after the last counter flip.
-
-o "F" indicates whether RCU is waiting for this CPU to acknowledge
- a counter flip. In the above example, RCU is not waiting on any,
- which is consistent with the state being "waitzero" rather than
- "waitack".
-
-o "M" indicates whether RCU is waiting for this CPU to execute a
- memory barrier. In the above example, RCU is not waiting on any,
- which is consistent with the state being "waitzero" rather than
- "waitmb".
-
-o "ggp" is the global grace-period counter.
-
-o "state" is the RCU state, which can be one of the following:
-
- o "idle": there is no grace period in progress.
-
- o "waitack": RCU just incremented the global grace-period
- counter, which has the effect of reversing the roles of
- the "last" and "cur" counters above, and is waiting for
- all the CPUs to acknowledge the flip. Once the flip has
- been acknowledged, CPUs will no longer be incrementing
- what are now the "last" counters, so that their sum will
- decrease monotonically down to zero.
-
- o "waitzero": RCU is waiting for the sum of the "last" counters
- to decrease to zero.
-
- o "waitmb": RCU is waiting for each CPU to execute a memory
- barrier, which ensures that instructions from a given CPU's
- last RCU read-side critical section cannot be reordered
- with instructions following the memory-barrier instruction.
-
-The output of "cat rcu/rcugp" looks as follows:
-
-oldggp=48870 newggp=48873
-
-Note that reading from this file provokes a synchronize_rcu(). The
-"oldggp" value is that of "ggp" from rcu/rcuctrs above, taken before
-executing the synchronize_rcu(), and the "newggp" value is also the
-"ggp" value, but taken after the synchronize_rcu() command returns.
-
-
-The output of "cat rcu/rcugp" looks as follows:
-
-na=1337955 nl=40 wa=1337915 wl=44 da=1337871 dl=0 dr=1337871 di=1337871
-1=50989 e1=6138 i1=49722 ie1=82 g1=49640 a1=315203 ae1=265563 a2=49640
-z1=1401244 ze1=1351605 z2=49639 m1=5661253 me1=5611614 m2=49639
-
-These are counters tracking internal preemptable-RCU events, however,
-some of them may be useful for debugging algorithms using RCU. In
-particular, the "nl", "wl", and "dl" values track the number of RCU
-callbacks in various states. The fields are as follows:
-
-o "na" is the total number of RCU callbacks that have been enqueued
- since boot.
-
-o "nl" is the number of RCU callbacks waiting for the previous
- grace period to end so that they can start waiting on the next
- grace period.
-
-o "wa" is the total number of RCU callbacks that have started waiting
- for a grace period since boot. "na" should be roughly equal to
- "nl" plus "wa".
-
-o "wl" is the number of RCU callbacks currently waiting for their
- grace period to end.
-
-o "da" is the total number of RCU callbacks whose grace periods
- have completed since boot. "wa" should be roughly equal to
- "wl" plus "da".
-
-o "dr" is the total number of RCU callbacks that have been removed
- from the list of callbacks ready to invoke. "dr" should be roughly
- equal to "da".
-
-o "di" is the total number of RCU callbacks that have been invoked
- since boot. "di" should be roughly equal to "da", though some
- early versions of preemptable RCU had a bug so that only the
- last CPU's count of invocations was displayed, rather than the
- sum of all CPU's counts.
-
-o "1" is the number of calls to rcu_try_flip(). This should be
- roughly equal to the sum of "e1", "i1", "a1", "z1", and "m1"
- described below. In other words, the number of times that
- the state machine is visited should be equal to the sum of the
- number of times that each state is visited plus the number of
- times that the state-machine lock acquisition failed.
-
-o "e1" is the number of times that rcu_try_flip() was unable to
- acquire the fliplock.
-
-o "i1" is the number of calls to rcu_try_flip_idle().
-
-o "ie1" is the number of times rcu_try_flip_idle() exited early
- due to the calling CPU having no work for RCU.
-
-o "g1" is the number of times that rcu_try_flip_idle() decided
- to start a new grace period. "i1" should be roughly equal to
- "ie1" plus "g1".
-
-o "a1" is the number of calls to rcu_try_flip_waitack().
-
-o "ae1" is the number of times that rcu_try_flip_waitack() found
- that at least one CPU had not yet acknowledge the new grace period
- (AKA "counter flip").
-
-o "a2" is the number of time rcu_try_flip_waitack() found that
- all CPUs had acknowledged. "a1" should be roughly equal to
- "ae1" plus "a2". (This particular output was collected on
- a 128-CPU machine, hence the smaller-than-usual fraction of
- calls to rcu_try_flip_waitack() finding all CPUs having already
- acknowledged.)
-
-o "z1" is the number of calls to rcu_try_flip_waitzero().
-
-o "ze1" is the number of times that rcu_try_flip_waitzero() found
- that not all of the old RCU read-side critical sections had
- completed.
-
-o "z2" is the number of times that rcu_try_flip_waitzero() finds
- the sum of the counters equal to zero, in other words, that
- all of the old RCU read-side critical sections had completed.
- The value of "z1" should be roughly equal to "ze1" plus
- "z2".
-
-o "m1" is the number of calls to rcu_try_flip_waitmb().
-
-o "me1" is the number of times that rcu_try_flip_waitmb() finds
- that at least one CPU has not yet executed a memory barrier.
-
-o "m2" is the number of times that rcu_try_flip_waitmb() finds that
- all CPUs have executed a memory barrier.
+The rcutree implementation of RCU provides debugfs trace output that
+summarizes counters and state. This information is useful for debugging
+RCU itself, and can sometimes also help to debug abuses of RCU.
+The following sections describe the debugfs files and formats.
Hierarchical RCU debugfs Files and Formats
@@ -210,9 +35,10 @@ rcu_bh:
6 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=859/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
7 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3761/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
-The first section lists the rcu_data structures for rcu, the second for
-rcu_bh. Each section has one line per CPU, or eight for this 8-CPU system.
-The fields are as follows:
+The first section lists the rcu_data structures for rcu_sched, the second
+for rcu_bh. Note that CONFIG_TREE_PREEMPT_RCU kernels will have an
+additional section for rcu_preempt. Each section has one line per CPU,
+or eight for this 8-CPU system. The fields are as follows:
o The number at the beginning of each line is the CPU number.
CPUs numbers followed by an exclamation mark are offline,
@@ -223,9 +49,9 @@ o The number at the beginning of each line is the CPU number.
o "c" is the count of grace periods that this CPU believes have
completed. CPUs in dynticks idle mode may lag quite a ways
- behind, for example, CPU 4 under "rcu" above, which has slept
- through the past 25 RCU grace periods. It is not unusual to
- see CPUs lagging by thousands of grace periods.
+ behind, for example, CPU 4 under "rcu_sched" above, which has
+ slept through the past 25 RCU grace periods. It is not unusual
+ to see CPUs lagging by thousands of grace periods.
o "g" is the count of grace periods that this CPU believes have
started. Again, CPUs in dynticks idle mode may lag behind.
@@ -308,8 +134,10 @@ The output of "cat rcu/rcugp" looks as follows:
rcu_sched: completed=33062 gpnum=33063
rcu_bh: completed=464 gpnum=464
-Again, this output is for both "rcu" and "rcu_bh". The fields are
-taken from the rcu_state structure, and are as follows:
+Again, this output is for both "rcu_sched" and "rcu_bh". Note that
+kernels built with CONFIG_TREE_PREEMPT_RCU will have an additional
+"rcu_preempt" line. The fields are taken from the rcu_state structure,
+and are as follows:
o "completed" is the number of grace periods that have completed.
It is comparable to the "c" field from rcu/rcudata in that a
@@ -324,23 +152,24 @@ o "gpnum" is the number of grace periods that have started. It is
If these two fields are equal (as they are for "rcu_bh" above),
then there is no grace period in progress, in other words, RCU
is idle. On the other hand, if the two fields differ (as they
- do for "rcu" above), then an RCU grace period is in progress.
+ do for "rcu_sched" above), then an RCU grace period is in progress.
The output of "cat rcu/rcuhier" looks as follows, with very long lines:
-c=6902 g=6903 s=2 jfq=3 j=72c7 nfqs=13142/nfqsng=0(13142) fqlh=6
-1/1 0:127 ^0
-3/3 0:35 ^0 0/0 36:71 ^1 0/0 72:107 ^2 0/0 108:127 ^3
-3/3f 0:5 ^0 2/3 6:11 ^1 0/0 12:17 ^2 0/0 18:23 ^3 0/0 24:29 ^4 0/0 30:35 ^5 0/0 36:41 ^0 0/0 42:47 ^1 0/0 48:53 ^2 0/0 54:59 ^3 0/0 60:65 ^4 0/0 66:71 ^5 0/0 72:77 ^0 0/0 78:83 ^1 0/0 84:89 ^2 0/0 90:95 ^3 0/0 96:101 ^4 0/0 102:107 ^5 0/0 108:113 ^0 0/0 114:119 ^1 0/0 120:125 ^2 0/0 126:127 ^3
+c=6902 g=6903 s=2 jfq=3 j=72c7 nfqs=13142/nfqsng=0(13142) fqlh=6 oqlen=0
+1/1 .>. 0:127 ^0
+3/3 .>. 0:35 ^0 0/0 .>. 36:71 ^1 0/0 .>. 72:107 ^2 0/0 .>. 108:127 ^3
+3/3f .>. 0:5 ^0 2/3 .>. 6:11 ^1 0/0 .>. 12:17 ^2 0/0 .>. 18:23 ^3 0/0 .>. 24:29 ^4 0/0 .>. 30:35 ^5 0/0 .>. 36:41 ^0 0/0 .>. 42:47 ^1 0/0 .>. 48:53 ^2 0/0 .>. 54:59 ^3 0/0 .>. 60:65 ^4 0/0 .>. 66:71 ^5 0/0 .>. 72:77 ^0 0/0 .>. 78:83 ^1 0/0 .>. 84:89 ^2 0/0 .>. 90:95 ^3 0/0 .>. 96:101 ^4 0/0 .>. 102:107 ^5 0/0 .>. 108:113 ^0 0/0 .>. 114:119 ^1 0/0 .>. 120:125 ^2 0/0 .>. 126:127 ^3
rcu_bh:
-c=-226 g=-226 s=1 jfq=-5701 j=72c7 nfqs=88/nfqsng=0(88) fqlh=0
-0/1 0:127 ^0
-0/3 0:35 ^0 0/0 36:71 ^1 0/0 72:107 ^2 0/0 108:127 ^3
-0/3f 0:5 ^0 0/3 6:11 ^1 0/0 12:17 ^2 0/0 18:23 ^3 0/0 24:29 ^4 0/0 30:35 ^5 0/0 36:41 ^0 0/0 42:47 ^1 0/0 48:53 ^2 0/0 54:59 ^3 0/0 60:65 ^4 0/0 66:71 ^5 0/0 72:77 ^0 0/0 78:83 ^1 0/0 84:89 ^2 0/0 90:95 ^3 0/0 96:101 ^4 0/0 102:107 ^5 0/0 108:113 ^0 0/0 114:119 ^1 0/0 120:125 ^2 0/0 126:127 ^3
+c=-226 g=-226 s=1 jfq=-5701 j=72c7 nfqs=88/nfqsng=0(88) fqlh=0 oqlen=0
+0/1 .>. 0:127 ^0
+0/3 .>. 0:35 ^0 0/0 .>. 36:71 ^1 0/0 .>. 72:107 ^2 0/0 .>. 108:127 ^3
+0/3f .>. 0:5 ^0 0/3 .>. 6:11 ^1 0/0 .>. 12:17 ^2 0/0 .>. 18:23 ^3 0/0 .>. 24:29 ^4 0/0 .>. 30:35 ^5 0/0 .>. 36:41 ^0 0/0 .>. 42:47 ^1 0/0 .>. 48:53 ^2 0/0 .>. 54:59 ^3 0/0 .>. 60:65 ^4 0/0 .>. 66:71 ^5 0/0 .>. 72:77 ^0 0/0 .>. 78:83 ^1 0/0 .>. 84:89 ^2 0/0 .>. 90:95 ^3 0/0 .>. 96:101 ^4 0/0 .>. 102:107 ^5 0/0 .>. 108:113 ^0 0/0 .>. 114:119 ^1 0/0 .>. 120:125 ^2 0/0 .>. 126:127 ^3
-This is once again split into "rcu" and "rcu_bh" portions. The fields are
-as follows:
+This is once again split into "rcu_sched" and "rcu_bh" portions,
+and CONFIG_TREE_PREEMPT_RCU kernels will again have an additional
+"rcu_preempt" section. The fields are as follows:
o "c" is exactly the same as "completed" under rcu/rcugp.
@@ -372,6 +201,11 @@ o "fqlh" is the number of calls to force_quiescent_state() that
exited immediately (without even being counted in nfqs above)
due to contention on ->fqslock.
+o "oqlen" is the number of callbacks on the "orphan" callback
+ list. RCU callbacks are placed on this list by CPUs going
+ offline, and are "adopted" either by the CPU helping the outgoing
+ CPU or by the next rcu_barrier*() call, whichever comes first.
+
o Each element of the form "1/1 0:127 ^0" represents one struct
rcu_node. Each line represents one level of the hierarchy, from
root to leaves. It is best to think of the rcu_data structures
@@ -379,7 +213,7 @@ o Each element of the form "1/1 0:127 ^0" represents one struct
might be either one, two, or three levels of rcu_node structures,
depending on the relationship between CONFIG_RCU_FANOUT and
CONFIG_NR_CPUS.
-
+
o The numbers separated by the "/" are the qsmask followed
by the qsmaskinit. The qsmask will have one bit
set for each entity in the next lower level that
@@ -389,10 +223,19 @@ o Each element of the form "1/1 0:127 ^0" represents one struct
The value of qsmaskinit is assigned to that of qsmask
at the beginning of each grace period.
- For example, for "rcu", the qsmask of the first entry
- of the lowest level is 0x14, meaning that we are still
- waiting for CPUs 2 and 4 to check in for the current
- grace period.
+ For example, for "rcu_sched", the qsmask of the first
+ entry of the lowest level is 0x14, meaning that we
+ are still waiting for CPUs 2 and 4 to check in for the
+ current grace period.
+
+ o The characters separated by the ">" indicate the state
+ of the blocked-tasks lists. A "T" preceding the ">"
+ indicates that at least one task blocked in an RCU
+ read-side critical section blocks the current grace
+ period, while a "." preceding the ">" indicates otherwise.
+ The character following the ">" indicates similarly for
+ the next grace period. A "T" should appear in this
+ field only for rcu-preempt.
o The numbers separated by the ":" are the range of CPUs
served by this struct rcu_node. This can be helpful
@@ -431,8 +274,9 @@ rcu_bh:
6 np=120834 qsp=9902 cbr=0 cng=0 gpc=6 gps=3 nf=2 nn=110921
7 np=144888 qsp=26336 cbr=0 cng=0 gpc=8 gps=2 nf=0 nn=118542
-As always, this is once again split into "rcu" and "rcu_bh" portions.
-The fields are as follows:
+As always, this is once again split into "rcu_sched" and "rcu_bh"
+portions, with CONFIG_TREE_PREEMPT_RCU kernels having an additional
+"rcu_preempt" section. The fields are as follows:
o "np" is the number of times that __rcu_pending() has been invoked
for the corresponding flavor of RCU.
diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt
index e41a7fecf0d3..d542ca243b80 100644
--- a/Documentation/RCU/whatisRCU.txt
+++ b/Documentation/RCU/whatisRCU.txt
@@ -830,7 +830,7 @@ sched: Critical sections Grace period Barrier
SRCU: Critical sections Grace period Barrier
srcu_read_lock synchronize_srcu N/A
- srcu_read_unlock
+ srcu_read_unlock synchronize_srcu_expedited
SRCU: Initialization/cleanup
init_srcu_struct
diff --git a/Documentation/blockdev/drbd/DRBD-8.3-data-packets.svg b/Documentation/blockdev/drbd/DRBD-8.3-data-packets.svg
new file mode 100644
index 000000000000..f87cfa0dc2fb
--- /dev/null
+++ b/Documentation/blockdev/drbd/DRBD-8.3-data-packets.svg
@@ -0,0 +1,588 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.0"
+ width="210mm"
+ height="297mm"
+ viewBox="0 0 21000 29700"
+ id="svg2"
+ style="fill-rule:evenodd">
+ <defs
+ id="defs4" />
+ <g
+ id="Default"
+ style="visibility:visible">
+ <desc
+ id="desc180">Master slide</desc>
+ </g>
+ <path
+ d="M 11999,8601 L 11899,8301 L 12099,8301 L 11999,8601 z"
+ id="path193"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 11999,7801 L 11999,8361"
+ id="path197"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <path
+ d="M 7999,10401 L 7899,10101 L 8099,10101 L 7999,10401 z"
+ id="path209"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 7999,9601 L 7999,10161"
+ id="path213"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <path
+ d="M 11999,7801 L 11685,7840 L 11724,7644 L 11999,7801 z"
+ id="path225"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 7999,7001 L 11764,7754"
+ id="path229"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <g
+ transform="matrix(0.9895258,-0.1443562,0.1443562,0.9895258,-1244.4792,1416.5139)"
+ id="g245"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <text
+ id="text247">
+ <tspan
+ x="9139 9368 9579 9808 9986 10075 10252 10481 10659 10837 10909"
+ y="9284"
+ id="tspan249">RSDataReply</tspan>
+ </text>
+ </g>
+ <path
+ d="M 7999,9601 L 8281,9458 L 8311,9655 L 7999,9601 z"
+ id="path259"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 11999,9001 L 8236,9565"
+ id="path263"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <g
+ transform="matrix(0.9788674,0.2044961,-0.2044961,0.9788674,1620.9382,-1639.4947)"
+ id="g279"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <text
+ id="text281">
+ <tspan
+ x="8743 8972 9132 9310 9573 9801 10013 10242 10419 10597 10775 10953 11114"
+ y="7023"
+ id="tspan283">CsumRSRequest</tspan>
+ </text>
+ </g>
+ <text
+ id="text297"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="4034 4263 4440 4703 4881 5042 5219 5397 5503 5681 5842 6003 6180 6341 6519 6625 6803 6980 7158 7336 7497 7586 7692"
+ y="5707"
+ id="tspan299">w_make_resync_request()</tspan>
+ </text>
+ <text
+ id="text313"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12199 12305 12483 12644 12821 12893 13054 13232 13410 13638 13816 13905 14083 14311 14489 14667 14845 15023 15184 15272 15378"
+ y="7806"
+ id="tspan315">receive_DataRequest()</tspan>
+ </text>
+ <text
+ id="text329"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12199 12377 12483 12660 12838 13016 13194 13372 13549 13621 13799 13977 14083 14261 14438 14616 14794 14955 15133 15294 15399"
+ y="8606"
+ id="tspan331">drbd_endio_read_sec()</tspan>
+ </text>
+ <text
+ id="text345"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12191 12420 12597 12775 12953 13131 13309 13486 13664 13825 13986 14164 14426 14604 14710 14871 15049 15154 15332 15510 15616"
+ y="9007"
+ id="tspan347">w_e_end_csum_rs_req()</tspan>
+ </text>
+ <text
+ id="text361"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="4444 4550 4728 4889 5066 5138 5299 5477 5655 5883 6095 6324 6501 6590 6768 6997 7175 7352 7424 7585 7691"
+ y="9507"
+ id="tspan363">receive_RSDataReply()</tspan>
+ </text>
+ <text
+ id="text377"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="4457 4635 4741 4918 5096 5274 5452 5630 5807 5879 6057 6235 6464 6569 6641 6730 6908 7086 7247 7425 7585 7691"
+ y="10407"
+ id="tspan379">drbd_endio_write_sec()</tspan>
+ </text>
+ <text
+ id="text393"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="4647 4825 5003 5180 5358 5536 5714 5820 5997 6158 6319 6497 6658 6836 7013 7085 7263 7424 7585 7691"
+ y="10907"
+ id="tspan395">e_end_resync_block()</tspan>
+ </text>
+ <path
+ d="M 11999,11601 L 11685,11640 L 11724,11444 L 11999,11601 z"
+ id="path405"
+ style="fill:#000080;visibility:visible" />
+ <path
+ d="M 7999,10801 L 11764,11554"
+ id="path409"
+ style="fill:none;stroke:#000080;visibility:visible" />
+ <g
+ transform="matrix(0.9788674,0.2044961,-0.2044961,0.9788674,2434.7562,-1674.649)"
+ id="g425"
+ style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+ <text
+ id="text427">
+ <tspan
+ x="9320 9621 9726 9798 9887 10065 10277 10438"
+ y="10943"
+ id="tspan429">WriteAck</tspan>
+ </text>
+ </g>
+ <text
+ id="text443"
+ style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12199 12377 12555 12644 12821 13033 13105 13283 13444 13604 13816 13977 14138 14244"
+ y="11559"
+ id="tspan445">got_BlockAck()</tspan>
+ </text>
+ <text
+ id="text459"
+ style="font-size:423px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="7999 8304 8541 8778 8990 9201 9413 9650 10001 10120 10357 10594 10806 11043 11280 11398 11703 11940 12152 12364 12601 12812 12931 13049 13261 13498 13710 13947 14065 14302 14540 14658 14777 14870 15107 15225 15437 15649 15886"
+ y="4877"
+ id="tspan461">Checksum based Resync, case not in sync</tspan>
+ </text>
+ <text
+ id="text475"
+ style="font-size:423px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="6961 7266 7571 7854 8159 8299 8536 8654 8891 9010 9247 9484 9603 9840 9958 10077 10170 10407"
+ y="2806"
+ id="tspan477">DRBD-8.3 data flow</tspan>
+ </text>
+ <text
+ id="text491"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="5190 5419 5596 5774 5952 6113 6291 6468 6646 6824 6985 7146 7324 7586 7692"
+ y="7005"
+ id="tspan493">w_e_send_csum()</tspan>
+ </text>
+ <path
+ d="M 11999,17601 L 11899,17301 L 12099,17301 L 11999,17601 z"
+ id="path503"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 11999,16801 L 11999,17361"
+ id="path507"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <path
+ d="M 11999,16801 L 11685,16840 L 11724,16644 L 11999,16801 z"
+ id="path519"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 7999,16001 L 11764,16754"
+ id="path523"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <g
+ transform="matrix(0.9895258,-0.1443562,0.1443562,0.9895258,-2539.5806,1529.3491)"
+ id="g539"
+ style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+ <text
+ id="text541">
+ <tspan
+ x="9269 9498 9709 9798 9959 10048 10226 10437 10598 10776"
+ y="18265"
+ id="tspan543">RSIsInSync</tspan>
+ </text>
+ </g>
+ <path
+ d="M 7999,18601 L 8281,18458 L 8311,18655 L 7999,18601 z"
+ id="path553"
+ style="fill:#000080;visibility:visible" />
+ <path
+ d="M 11999,18001 L 8236,18565"
+ id="path557"
+ style="fill:none;stroke:#000080;visibility:visible" />
+ <g
+ transform="matrix(0.9788674,0.2044961,-0.2044961,0.9788674,3461.4027,-1449.3012)"
+ id="g573"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <text
+ id="text575">
+ <tspan
+ x="8743 8972 9132 9310 9573 9801 10013 10242 10419 10597 10775 10953 11114"
+ y="16023"
+ id="tspan577">CsumRSRequest</tspan>
+ </text>
+ </g>
+ <text
+ id="text591"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12199 12305 12483 12644 12821 12893 13054 13232 13410 13638 13816 13905 14083 14311 14489 14667 14845 15023 15184 15272 15378"
+ y="16806"
+ id="tspan593">receive_DataRequest()</tspan>
+ </text>
+ <text
+ id="text607"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12199 12377 12483 12660 12838 13016 13194 13372 13549 13621 13799 13977 14083 14261 14438 14616 14794 14955 15133 15294 15399"
+ y="17606"
+ id="tspan609">drbd_endio_read_sec()</tspan>
+ </text>
+ <text
+ id="text623"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12191 12420 12597 12775 12953 13131 13309 13486 13664 13825 13986 14164 14426 14604 14710 14871 15049 15154 15332 15510 15616"
+ y="18007"
+ id="tspan625">w_e_end_csum_rs_req()</tspan>
+ </text>
+ <text
+ id="text639"
+ style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="5735 5913 6091 6180 6357 6446 6607 6696 6874 7085 7246 7424 7585 7691"
+ y="18507"
+ id="tspan641">got_IsInSync()</tspan>
+ </text>
+ <text
+ id="text655"
+ style="font-size:423px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="7999 8304 8541 8778 8990 9201 9413 9650 10001 10120 10357 10594 10806 11043 11280 11398 11703 11940 12152 12364 12601 12812 12931 13049 13261 13498 13710 13947 14065 14159 14396 14514 14726 14937 15175"
+ y="13877"
+ id="tspan657">Checksum based Resync, case in sync</tspan>
+ </text>
+ <path
+ d="M 12000,24601 L 11900,24301 L 12100,24301 L 12000,24601 z"
+ id="path667"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 12000,23801 L 12000,24361"
+ id="path671"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <path
+ d="M 8000,26401 L 7900,26101 L 8100,26101 L 8000,26401 z"
+ id="path683"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 8000,25601 L 8000,26161"
+ id="path687"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <path
+ d="M 12000,23801 L 11686,23840 L 11725,23644 L 12000,23801 z"
+ id="path699"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 8000,23001 L 11765,23754"
+ id="path703"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <g
+ transform="matrix(0.9895258,-0.1443562,0.1443562,0.9895258,-3543.8452,1630.5143)"
+ id="g719"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <text
+ id="text721">
+ <tspan
+ x="9464 9710 9921 10150 10328 10505 10577"
+ y="25236"
+ id="tspan723">OVReply</tspan>
+ </text>
+ </g>
+ <path
+ d="M 8000,25601 L 8282,25458 L 8312,25655 L 8000,25601 z"
+ id="path733"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 12000,25001 L 8237,25565"
+ id="path737"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <g
+ transform="matrix(0.9788674,0.2044961,-0.2044961,0.9788674,4918.2801,-1381.2128)"
+ id="g753"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <text
+ id="text755">
+ <tspan
+ x="9142 9388 9599 9828 10006 10183 10361 10539 10700"
+ y="23106"
+ id="tspan757">OVRequest</tspan>
+ </text>
+ </g>
+ <text
+ id="text771"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12200 12306 12484 12645 12822 12894 13055 13233 13411 13656 13868 14097 14274 14452 14630 14808 14969 15058 15163"
+ y="23806"
+ id="tspan773">receive_OVRequest()</tspan>
+ </text>
+ <text
+ id="text787"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12200 12378 12484 12661 12839 13017 13195 13373 13550 13622 13800 13978 14084 14262 14439 14617 14795 14956 15134 15295 15400"
+ y="24606"
+ id="tspan789">drbd_endio_read_sec()</tspan>
+ </text>
+ <text
+ id="text803"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12192 12421 12598 12776 12954 13132 13310 13487 13665 13843 14004 14182 14288 14465 14643 14749"
+ y="25007"
+ id="tspan805">w_e_end_ov_req()</tspan>
+ </text>
+ <text
+ id="text819"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="5101 5207 5385 5546 5723 5795 5956 6134 6312 6557 6769 6998 7175 7353 7425 7586 7692"
+ y="25507"
+ id="tspan821">receive_OVReply()</tspan>
+ </text>
+ <text
+ id="text835"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="4492 4670 4776 4953 5131 5309 5487 5665 5842 5914 6092 6270 6376 6554 6731 6909 7087 7248 7426 7587 7692"
+ y="26407"
+ id="tspan837">drbd_endio_read_sec()</tspan>
+ </text>
+ <text
+ id="text851"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="4902 5131 5308 5486 5664 5842 6020 6197 6375 6553 6714 6892 6998 7175 7353 7425 7586 7692"
+ y="26907"
+ id="tspan853">w_e_end_ov_reply()</tspan>
+ </text>
+ <path
+ d="M 12000,27601 L 11686,27640 L 11725,27444 L 12000,27601 z"
+ id="path863"
+ style="fill:#000080;visibility:visible" />
+ <path
+ d="M 8000,26801 L 11765,27554"
+ id="path867"
+ style="fill:none;stroke:#000080;visibility:visible" />
+ <g
+ transform="matrix(0.9788674,0.2044961,-0.2044961,0.9788674,5704.1907,-1328.312)"
+ id="g883"
+ style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+ <text
+ id="text885">
+ <tspan
+ x="9279 9525 9736 9965 10143 10303 10481 10553"
+ y="26935"
+ id="tspan887">OVResult</tspan>
+ </text>
+ </g>
+ <text
+ id="text901"
+ style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12200 12378 12556 12645 12822 13068 13280 13508 13686 13847 14025 14097 14185 14291"
+ y="27559"
+ id="tspan903">got_OVResult()</tspan>
+ </text>
+ <text
+ id="text917"
+ style="font-size:423px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="8000 8330 8567 8660 8754 8991 9228 9346 9558 9795 9935 10028 10146"
+ y="21877"
+ id="tspan919">Online verify</tspan>
+ </text>
+ <text
+ id="text933"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="4641 4870 5047 5310 5488 5649 5826 6004 6182 6343 6521 6626 6804 6982 7160 7338 7499 7587 7693"
+ y="23005"
+ id="tspan935">w_make_ov_request()</tspan>
+ </text>
+ <path
+ d="M 8000,6500 L 7900,6200 L 8100,6200 L 8000,6500 z"
+ id="path945"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 8000,5700 L 8000,6260"
+ id="path949"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <path
+ d="M 3900,5500 L 3700,5500 L 3700,11000 L 3900,11000"
+ id="path961"
+ style="fill:none;stroke:#000000;visibility:visible" />
+ <path
+ d="M 3900,14500 L 3700,14500 L 3700,18600 L 3900,18600"
+ id="path973"
+ style="fill:none;stroke:#000000;visibility:visible" />
+ <path
+ d="M 3900,22800 L 3700,22800 L 3700,26900 L 3900,26900"
+ id="path985"
+ style="fill:none;stroke:#000000;visibility:visible" />
+ <text
+ id="text1001"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="4492 4670 4776 4953 5131 5309 5487 5665 5842 5914 6092 6270 6376 6554 6731 6909 7087 7248 7426 7587 7692"
+ y="6506"
+ id="tspan1003">drbd_endio_read_sec()</tspan>
+ </text>
+ <text
+ id="text1017"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="4034 4263 4440 4703 4881 5042 5219 5397 5503 5681 5842 6003 6180 6341 6519 6625 6803 6980 7158 7336 7497 7586 7692"
+ y="14708"
+ id="tspan1019">w_make_resync_request()</tspan>
+ </text>
+ <text
+ id="text1033"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="5190 5419 5596 5774 5952 6113 6291 6468 6646 6824 6985 7146 7324 7586 7692"
+ y="16006"
+ id="tspan1035">w_e_send_csum()</tspan>
+ </text>
+ <path
+ d="M 8000,15501 L 7900,15201 L 8100,15201 L 8000,15501 z"
+ id="path1045"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 8000,14701 L 8000,15261"
+ id="path1049"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <text
+ id="text1065"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="4492 4670 4776 4953 5131 5309 5487 5665 5842 5914 6092 6270 6376 6554 6731 6909 7087 7248 7426 7587 7692"
+ y="15507"
+ id="tspan1067">drbd_endio_read_sec()</tspan>
+ </text>
+ <path
+ d="M 16100,9000 L 16300,9000 L 16300,7500 L 16100,7500"
+ id="path1077"
+ style="fill:none;stroke:#000000;visibility:visible" />
+ <path
+ d="M 16100,18000 L 16300,18000 L 16300,16500 L 16100,16500"
+ id="path1089"
+ style="fill:none;stroke:#000000;visibility:visible" />
+ <path
+ d="M 16100,25000 L 16300,25000 L 16300,23500 L 16100,23500"
+ id="path1101"
+ style="fill:none;stroke:#000000;visibility:visible" />
+ <text
+ id="text1117"
+ style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="2026 2132 2293 2471 2648 2826 3004 3076 3254 3431 3503 3681 3787"
+ y="5402"
+ id="tspan1119">rs_begin_io()</tspan>
+ </text>
+ <text
+ id="text1133"
+ style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="2027 2133 2294 2472 2649 2827 3005 3077 3255 3432 3504 3682 3788"
+ y="14402"
+ id="tspan1135">rs_begin_io()</tspan>
+ </text>
+ <text
+ id="text1149"
+ style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="2026 2132 2293 2471 2648 2826 3004 3076 3254 3431 3503 3681 3787"
+ y="22602"
+ id="tspan1151">rs_begin_io()</tspan>
+ </text>
+ <text
+ id="text1165"
+ style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="1426 1532 1693 1871 2031 2209 2472 2649 2721 2899 2988 3166 3344 3416 3593 3699"
+ y="11302"
+ id="tspan1167">rs_complete_io()</tspan>
+ </text>
+ <text
+ id="text1181"
+ style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="1526 1632 1793 1971 2131 2309 2572 2749 2821 2999 3088 3266 3444 3516 3693 3799"
+ y="18931"
+ id="tspan1183">rs_complete_io()</tspan>
+ </text>
+ <text
+ id="text1197"
+ style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="1526 1632 1793 1971 2131 2309 2572 2749 2821 2999 3088 3266 3444 3516 3693 3799"
+ y="27231"
+ id="tspan1199">rs_complete_io()</tspan>
+ </text>
+ <text
+ id="text1213"
+ style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="16126 16232 16393 16571 16748 16926 17104 17176 17354 17531 17603 17781 17887"
+ y="7402"
+ id="tspan1215">rs_begin_io()</tspan>
+ </text>
+ <text
+ id="text1229"
+ style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="16127 16233 16394 16572 16749 16927 17105 17177 17355 17532 17604 17782 17888"
+ y="16331"
+ id="tspan1231">rs_begin_io()</tspan>
+ </text>
+ <text
+ id="text1245"
+ style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="16127 16233 16394 16572 16749 16927 17105 17177 17355 17532 17604 17782 17888"
+ y="23302"
+ id="tspan1247">rs_begin_io()</tspan>
+ </text>
+ <text
+ id="text1261"
+ style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="16115 16221 16382 16560 16720 16898 17161 17338 17410 17588 17677 17855 18033 18105 18282 18388"
+ y="9302"
+ id="tspan1263">rs_complete_io()</tspan>
+ </text>
+ <text
+ id="text1277"
+ style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="16115 16221 16382 16560 16720 16898 17161 17338 17410 17588 17677 17855 18033 18105 18282 18388"
+ y="18331"
+ id="tspan1279">rs_complete_io()</tspan>
+ </text>
+ <text
+ id="text1293"
+ style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="16126 16232 16393 16571 16731 16909 17172 17349 17421 17599 17688 17866 18044 18116 18293 18399"
+ y="25302"
+ id="tspan1295">rs_complete_io()</tspan>
+ </text>
+</svg>
diff --git a/Documentation/blockdev/drbd/DRBD-data-packets.svg b/Documentation/blockdev/drbd/DRBD-data-packets.svg
new file mode 100644
index 000000000000..48a1e2165fec
--- /dev/null
+++ b/Documentation/blockdev/drbd/DRBD-data-packets.svg
@@ -0,0 +1,459 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.0"
+ width="210mm"
+ height="297mm"
+ viewBox="0 0 21000 29700"
+ id="svg2"
+ style="fill-rule:evenodd">
+ <defs
+ id="defs4" />
+ <g
+ id="Default"
+ style="visibility:visible">
+ <desc
+ id="desc176">Master slide</desc>
+ </g>
+ <path
+ d="M 11999,19601 L 11899,19301 L 12099,19301 L 11999,19601 z"
+ id="path189"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 11999,18801 L 11999,19361"
+ id="path193"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <path
+ d="M 7999,21401 L 7899,21101 L 8099,21101 L 7999,21401 z"
+ id="path205"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 7999,20601 L 7999,21161"
+ id="path209"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <path
+ d="M 11999,18801 L 11685,18840 L 11724,18644 L 11999,18801 z"
+ id="path221"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 7999,18001 L 11764,18754"
+ id="path225"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <text
+ x="-3023.845"
+ y="1106.8124"
+ transform="matrix(0.9895258,-0.1443562,0.1443562,0.9895258,0,0)"
+ id="text243"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="6115.1553 6344.1553 6555.1553 6784.1553 6962.1553 7051.1553 7228.1553 7457.1553 7635.1553 7813.1553 7885.1553"
+ y="21390.812"
+ id="tspan245">RSDataReply</tspan>
+ </text>
+ <path
+ d="M 7999,20601 L 8281,20458 L 8311,20655 L 7999,20601 z"
+ id="path255"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 11999,20001 L 8236,20565"
+ id="path259"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <text
+ x="3502.5356"
+ y="-2184.6621"
+ transform="matrix(0.9788674,0.2044961,-0.2044961,0.9788674,0,0)"
+ id="text277"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12321.536 12550.536 12761.536 12990.536 13168.536 13257.536 13434.536 13663.536 13841.536 14019.536 14196.536 14374.536 14535.536"
+ y="15854.338"
+ id="tspan279">RSDataRequest</tspan>
+ </text>
+ <text
+ id="text293"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="4034 4263 4440 4703 4881 5042 5219 5397 5503 5681 5842 6003 6180 6341 6519 6625 6803 6980 7158 7336 7497 7586 7692"
+ y="17807"
+ id="tspan295">w_make_resync_request()</tspan>
+ </text>
+ <text
+ id="text309"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12199 12305 12483 12644 12821 12893 13054 13232 13410 13638 13816 13905 14083 14311 14489 14667 14845 15023 15184 15272 15378"
+ y="18806"
+ id="tspan311">receive_DataRequest()</tspan>
+ </text>
+ <text
+ id="text325"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12199 12377 12483 12660 12838 13016 13194 13372 13549 13621 13799 13977 14083 14261 14438 14616 14794 14955 15133 15294 15399"
+ y="19606"
+ id="tspan327">drbd_endio_read_sec()</tspan>
+ </text>
+ <text
+ id="text341"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12191 12420 12597 12775 12953 13131 13309 13486 13664 13770 13931 14109 14287 14375 14553 14731 14837 15015 15192 15298"
+ y="20007"
+ id="tspan343">w_e_end_rsdata_req()</tspan>
+ </text>
+ <text
+ id="text357"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="4444 4550 4728 4889 5066 5138 5299 5477 5655 5883 6095 6324 6501 6590 6768 6997 7175 7352 7424 7585 7691"
+ y="20507"
+ id="tspan359">receive_RSDataReply()</tspan>
+ </text>
+ <text
+ id="text373"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="4457 4635 4741 4918 5096 5274 5452 5630 5807 5879 6057 6235 6464 6569 6641 6730 6908 7086 7247 7425 7585 7691"
+ y="21407"
+ id="tspan375">drbd_endio_write_sec()</tspan>
+ </text>
+ <text
+ id="text389"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="4647 4825 5003 5180 5358 5536 5714 5820 5997 6158 6319 6497 6658 6836 7013 7085 7263 7424 7585 7691"
+ y="21907"
+ id="tspan391">e_end_resync_block()</tspan>
+ </text>
+ <path
+ d="M 11999,22601 L 11685,22640 L 11724,22444 L 11999,22601 z"
+ id="path401"
+ style="fill:#000080;visibility:visible" />
+ <path
+ d="M 7999,21801 L 11764,22554"
+ id="path405"
+ style="fill:none;stroke:#000080;visibility:visible" />
+ <text
+ x="4290.3008"
+ y="-2369.6162"
+ transform="matrix(0.9788674,0.2044961,-0.2044961,0.9788674,0,0)"
+ id="text423"
+ style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="13610.301 13911.301 14016.301 14088.301 14177.301 14355.301 14567.301 14728.301"
+ y="19573.385"
+ id="tspan425">WriteAck</tspan>
+ </text>
+ <text
+ id="text439"
+ style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12199 12377 12555 12644 12821 13033 13105 13283 13444 13604 13816 13977 14138 14244"
+ y="22559"
+ id="tspan441">got_BlockAck()</tspan>
+ </text>
+ <text
+ id="text455"
+ style="font-size:423px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="7999 8304 8541 8753 8964 9201 9413 9531 9769 9862 10099 10310 10522 10734 10852 10971 11208 11348 11585 11822"
+ y="16877"
+ id="tspan457">Resync blocks, 4-32K</tspan>
+ </text>
+ <path
+ d="M 12000,7601 L 11900,7301 L 12100,7301 L 12000,7601 z"
+ id="path467"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 12000,6801 L 12000,7361"
+ id="path471"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <path
+ d="M 12000,6801 L 11686,6840 L 11725,6644 L 12000,6801 z"
+ id="path483"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 8000,6001 L 11765,6754"
+ id="path487"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <text
+ x="-1288.1796"
+ y="1279.7666"
+ transform="matrix(0.9895258,-0.1443562,0.1443562,0.9895258,0,0)"
+ id="text505"
+ style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="8174.8208 8475.8203 8580.8203 8652.8203 8741.8203 8919.8203 9131.8203 9292.8203"
+ y="9516.7666"
+ id="tspan507">WriteAck</tspan>
+ </text>
+ <path
+ d="M 8000,8601 L 8282,8458 L 8312,8655 L 8000,8601 z"
+ id="path517"
+ style="fill:#000080;visibility:visible" />
+ <path
+ d="M 12000,8001 L 8237,8565"
+ id="path521"
+ style="fill:none;stroke:#000080;visibility:visible" />
+ <text
+ x="1065.6655"
+ y="-2097.7664"
+ transform="matrix(0.9788674,0.2044961,-0.2044961,0.9788674,0,0)"
+ id="text539"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="10682.666 10911.666 11088.666 11177.666"
+ y="4107.2339"
+ id="tspan541">Data</tspan>
+ </text>
+ <text
+ id="text555"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="4746 4924 5030 5207 5385 5563 5826 6003 6164 6342 6520 6626 6803 6981 7159 7337 7498 7587 7692"
+ y="5505"
+ id="tspan557">drbd_make_request()</tspan>
+ </text>
+ <text
+ id="text571"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12200 12306 12484 12645 12822 12894 13055 13233 13411 13639 13817 13906 14084 14190"
+ y="6806"
+ id="tspan573">receive_Data()</tspan>
+ </text>
+ <text
+ id="text587"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12200 12378 12484 12661 12839 13017 13195 13373 13550 13622 13800 13978 14207 14312 14384 14473 14651 14829 14990 15168 15328 15434"
+ y="7606"
+ id="tspan589">drbd_endio_write_sec()</tspan>
+ </text>
+ <text
+ id="text603"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12192 12370 12548 12725 12903 13081 13259 13437 13509 13686 13847 14008 14114"
+ y="8007"
+ id="tspan605">e_end_block()</tspan>
+ </text>
+ <text
+ id="text619"
+ style="font-size:318px;font-weight:400;fill:#000080;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="5647 5825 6003 6092 6269 6481 6553 6731 6892 7052 7264 7425 7586 7692"
+ y="8606"
+ id="tspan621">got_BlockAck()</tspan>
+ </text>
+ <text
+ id="text635"
+ style="font-size:423px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="8000 8305 8542 8779 9016 9109 9346 9486 9604 9956 10049 10189 10328 10565 10705 10942 11179 11298 11603 11742 11835 11954 12191 12310 12428 12665 12902 13139 13279 13516 13753"
+ y="4877"
+ id="tspan637">Regular mirrored write, 512-32K</tspan>
+ </text>
+ <text
+ id="text651"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="5381 5610 5787 5948 6126 6304 6482 6659 6837 7015 7087 7265 7426 7587 7692"
+ y="6003"
+ id="tspan653">w_send_dblock()</tspan>
+ </text>
+ <path
+ d="M 8000,6800 L 7900,6500 L 8100,6500 L 8000,6800 z"
+ id="path663"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 8000,6000 L 8000,6560"
+ id="path667"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <text
+ id="text683"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="4602 4780 4886 5063 5241 5419 5597 5775 5952 6024 6202 6380 6609 6714 6786 6875 7053 7231 7409 7515 7587 7692"
+ y="6905"
+ id="tspan685">drbd_endio_write_pri()</tspan>
+ </text>
+ <path
+ d="M 12000,13602 L 11900,13302 L 12100,13302 L 12000,13602 z"
+ id="path695"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 12000,12802 L 12000,13362"
+ id="path699"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <path
+ d="M 12000,12802 L 11686,12841 L 11725,12645 L 12000,12802 z"
+ id="path711"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 8000,12002 L 11765,12755"
+ id="path715"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <text
+ x="-2155.5266"
+ y="1201.5964"
+ transform="matrix(0.9895258,-0.1443562,0.1443562,0.9895258,0,0)"
+ id="text733"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="7202.4736 7431.4736 7608.4736 7697.4736 7875.4736 8104.4736 8282.4736 8459.4736 8531.4736"
+ y="15454.597"
+ id="tspan735">DataReply</tspan>
+ </text>
+ <path
+ d="M 8000,14602 L 8282,14459 L 8312,14656 L 8000,14602 z"
+ id="path745"
+ style="fill:#008000;visibility:visible" />
+ <path
+ d="M 12000,14002 L 8237,14566"
+ id="path749"
+ style="fill:none;stroke:#008000;visibility:visible" />
+ <text
+ x="2280.3804"
+ y="-2103.2141"
+ transform="matrix(0.9788674,0.2044961,-0.2044961,0.9788674,0,0)"
+ id="text767"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="11316.381 11545.381 11722.381 11811.381 11989.381 12218.381 12396.381 12573.381 12751.381 12929.381 13090.381"
+ y="9981.7861"
+ id="tspan769">DataRequest</tspan>
+ </text>
+ <text
+ id="text783"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="4746 4924 5030 5207 5385 5563 5826 6003 6164 6342 6520 6626 6803 6981 7159 7337 7498 7587 7692"
+ y="11506"
+ id="tspan785">drbd_make_request()</tspan>
+ </text>
+ <text
+ id="text799"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12200 12306 12484 12645 12822 12894 13055 13233 13411 13639 13817 13906 14084 14312 14490 14668 14846 15024 15185 15273 15379"
+ y="12807"
+ id="tspan801">receive_DataRequest()</tspan>
+ </text>
+ <text
+ id="text815"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12200 12378 12484 12661 12839 13017 13195 13373 13550 13622 13800 13978 14084 14262 14439 14617 14795 14956 15134 15295 15400"
+ y="13607"
+ id="tspan817">drbd_endio_read_sec()</tspan>
+ </text>
+ <text
+ id="text831"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="12192 12421 12598 12776 12954 13132 13310 13487 13665 13843 14021 14110 14288 14465 14571 14749 14927 15033"
+ y="14008"
+ id="tspan833">w_e_end_data_req()</tspan>
+ </text>
+ <g
+ id="g835"
+ style="visibility:visible">
+ <desc
+ id="desc837">Drawing</desc>
+ <text
+ id="text847"
+ style="font-size:318px;font-weight:400;fill:#008000;font-family:Helvetica embedded">
+ <tspan
+ x="4885 4991 5169 5330 5507 5579 5740 5918 6096 6324 6502 6591 6769 6997 7175 7353 7425 7586 7692"
+ y="14607"
+ id="tspan849">receive_DataReply()</tspan>
+ </text>
+ </g>
+ <text
+ id="text863"
+ style="font-size:423px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="8000 8305 8398 8610 8821 8914 9151 9363 9575 9693 9833 10070 10307 10544 10663 10781 11018 11255 11493 11632 11869 12106"
+ y="10878"
+ id="tspan865">Diskless read, 512-32K</tspan>
+ </text>
+ <text
+ id="text879"
+ style="font-size:318px;font-weight:400;fill:#008000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="5029 5258 5435 5596 5774 5952 6130 6307 6413 6591 6769 6947 7125 7230 7408 7586 7692"
+ y="12004"
+ id="tspan881">w_send_read_req()</tspan>
+ </text>
+ <text
+ id="text895"
+ style="font-size:423px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="6961 7266 7571 7854 8159 8278 8515 8633 8870 9107 9226 9463 9581 9700 9793 10030"
+ y="2806"
+ id="tspan897">DRBD 8 data flow</tspan>
+ </text>
+ <path
+ d="M 3900,5300 L 3700,5300 L 3700,7000 L 3900,7000"
+ id="path907"
+ style="fill:none;stroke:#000000;visibility:visible" />
+ <path
+ d="M 3900,17600 L 3700,17600 L 3700,22000 L 3900,22000"
+ id="path919"
+ style="fill:none;stroke:#000000;visibility:visible" />
+ <path
+ d="M 16100,20000 L 16300,20000 L 16300,18500 L 16100,18500"
+ id="path931"
+ style="fill:none;stroke:#000000;visibility:visible" />
+ <text
+ id="text947"
+ style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="2126 2304 2376 2554 2731 2909 3087 3159 3337 3515 3587 3764 3870"
+ y="5202"
+ id="tspan949">al_begin_io()</tspan>
+ </text>
+ <text
+ id="text963"
+ style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="1632 1810 1882 2060 2220 2398 2661 2839 2910 3088 3177 3355 3533 3605 3783 3888"
+ y="7331"
+ id="tspan965">al_complete_io()</tspan>
+ </text>
+ <text
+ id="text979"
+ style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="2126 2232 2393 2571 2748 2926 3104 3176 3354 3531 3603 3781 3887"
+ y="17431"
+ id="tspan981">rs_begin_io()</tspan>
+ </text>
+ <text
+ id="text995"
+ style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="1626 1732 1893 2071 2231 2409 2672 2849 2921 3099 3188 3366 3544 3616 3793 3899"
+ y="22331"
+ id="tspan997">rs_complete_io()</tspan>
+ </text>
+ <text
+ id="text1011"
+ style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="16027 16133 16294 16472 16649 16827 17005 17077 17255 17432 17504 17682 17788"
+ y="18402"
+ id="tspan1013">rs_begin_io()</tspan>
+ </text>
+ <text
+ id="text1027"
+ style="font-size:318px;font-weight:400;fill:#000000;visibility:visible;font-family:Helvetica embedded">
+ <tspan
+ x="16115 16221 16382 16560 16720 16898 17161 17338 17410 17588 17677 17855 18033 18105 18282 18388"
+ y="20331"
+ id="tspan1029">rs_complete_io()</tspan>
+ </text>
+</svg>
diff --git a/Documentation/blockdev/drbd/README.txt b/Documentation/blockdev/drbd/README.txt
new file mode 100644
index 000000000000..627b0a1bf35e
--- /dev/null
+++ b/Documentation/blockdev/drbd/README.txt
@@ -0,0 +1,16 @@
+Description
+
+ DRBD is a shared-nothing, synchronously replicated block device. It
+ is designed to serve as a building block for high availability
+ clusters and in this context, is a "drop-in" replacement for shared
+ storage. Simplistically, you could see it as a network RAID 1.
+
+ Please visit http://www.drbd.org to find out more.
+
+The here included files are intended to help understand the implementation
+
+DRBD-8.3-data-packets.svg, DRBD-data-packets.svg
+ relates some functions, and write packets.
+
+conn-states-8.dot, disk-states-8.dot, node-states-8.dot
+ The sub graphs of DRBD's state transitions
diff --git a/Documentation/blockdev/drbd/conn-states-8.dot b/Documentation/blockdev/drbd/conn-states-8.dot
new file mode 100644
index 000000000000..025e8cf5e64a
--- /dev/null
+++ b/Documentation/blockdev/drbd/conn-states-8.dot
@@ -0,0 +1,18 @@
+digraph conn_states {
+ StandAllone -> WFConnection [ label = "ioctl_set_net()" ]
+ WFConnection -> Unconnected [ label = "unable to bind()" ]
+ WFConnection -> WFReportParams [ label = "in connect() after accept" ]
+ WFReportParams -> StandAllone [ label = "checks in receive_param()" ]
+ WFReportParams -> Connected [ label = "in receive_param()" ]
+ WFReportParams -> WFBitMapS [ label = "sync_handshake()" ]
+ WFReportParams -> WFBitMapT [ label = "sync_handshake()" ]
+ WFBitMapS -> SyncSource [ label = "receive_bitmap()" ]
+ WFBitMapT -> SyncTarget [ label = "receive_bitmap()" ]
+ SyncSource -> Connected
+ SyncTarget -> Connected
+ SyncSource -> PausedSyncS
+ SyncTarget -> PausedSyncT
+ PausedSyncS -> SyncSource
+ PausedSyncT -> SyncTarget
+ Connected -> WFConnection [ label = "* on network error" ]
+}
diff --git a/Documentation/blockdev/drbd/disk-states-8.dot b/Documentation/blockdev/drbd/disk-states-8.dot
new file mode 100644
index 000000000000..d06cfb46fb98
--- /dev/null
+++ b/Documentation/blockdev/drbd/disk-states-8.dot
@@ -0,0 +1,16 @@
+digraph disk_states {
+ Diskless -> Inconsistent [ label = "ioctl_set_disk()" ]
+ Diskless -> Consistent [ label = "ioctl_set_disk()" ]
+ Diskless -> Outdated [ label = "ioctl_set_disk()" ]
+ Consistent -> Outdated [ label = "receive_param()" ]
+ Consistent -> UpToDate [ label = "receive_param()" ]
+ Consistent -> Inconsistent [ label = "start resync" ]
+ Outdated -> Inconsistent [ label = "start resync" ]
+ UpToDate -> Inconsistent [ label = "ioctl_replicate" ]
+ Inconsistent -> UpToDate [ label = "resync completed" ]
+ Consistent -> Failed [ label = "io completion error" ]
+ Outdated -> Failed [ label = "io completion error" ]
+ UpToDate -> Failed [ label = "io completion error" ]
+ Inconsistent -> Failed [ label = "io completion error" ]
+ Failed -> Diskless [ label = "sending notify to peer" ]
+}
diff --git a/Documentation/blockdev/drbd/drbd-connection-state-overview.dot b/Documentation/blockdev/drbd/drbd-connection-state-overview.dot
new file mode 100644
index 000000000000..6d9cf0a7b11d
--- /dev/null
+++ b/Documentation/blockdev/drbd/drbd-connection-state-overview.dot
@@ -0,0 +1,85 @@
+// vim: set sw=2 sts=2 :
+digraph {
+ rankdir=BT
+ bgcolor=white
+
+ node [shape=plaintext]
+ node [fontcolor=black]
+
+ StandAlone [ style=filled,fillcolor=gray,label=StandAlone ]
+
+ node [fontcolor=lightgray]
+
+ Unconnected [ label=Unconnected ]
+
+ CommTrouble [ shape=record,
+ label="{communication loss|{Timeout|BrokenPipe|NetworkFailure}}" ]
+
+ node [fontcolor=gray]
+
+ subgraph cluster_try_connect {
+ label="try to connect, handshake"
+ rank=max
+ WFConnection [ label=WFConnection ]
+ WFReportParams [ label=WFReportParams ]
+ }
+
+ TearDown [ label=TearDown ]
+
+ Connected [ label=Connected,style=filled,fillcolor=green,fontcolor=black ]
+
+ node [fontcolor=lightblue]
+
+ StartingSyncS [ label=StartingSyncS ]
+ StartingSyncT [ label=StartingSyncT ]
+
+ subgraph cluster_bitmap_exchange {
+ node [fontcolor=red]
+ fontcolor=red
+ label="new application (WRITE?) requests blocked\lwhile bitmap is exchanged"
+
+ WFBitMapT [ label=WFBitMapT ]
+ WFSyncUUID [ label=WFSyncUUID ]
+ WFBitMapS [ label=WFBitMapS ]
+ }
+
+ node [fontcolor=blue]
+
+ cluster_resync [ shape=record,label="{<any>resynchronisation process running\l'concurrent' application requests allowed|{{<T>PausedSyncT\nSyncTarget}|{<S>PausedSyncS\nSyncSource}}}" ]
+
+ node [shape=box,fontcolor=black]
+
+ // drbdadm [label="drbdadm connect"]
+ // handshake [label="drbd_connect()\ndrbd_do_handshake\ndrbd_sync_handshake() etc."]
+ // comm_error [label="communication trouble"]
+
+ //
+ // edges
+ // --------------------------------------
+
+ StandAlone -> Unconnected [ label="drbdadm connect" ]
+ Unconnected -> StandAlone [ label="drbdadm disconnect\lor serious communication trouble" ]
+ Unconnected -> WFConnection [ label="receiver thread is started" ]
+ WFConnection -> WFReportParams [ headlabel="accept()\land/or \lconnect()\l" ]
+
+ WFReportParams -> StandAlone [ label="during handshake\lpeers do not agree\labout something essential" ]
+ WFReportParams -> Connected [ label="data identical\lno sync needed",color=green,fontcolor=green ]
+
+ WFReportParams -> WFBitMapS
+ WFReportParams -> WFBitMapT
+ WFBitMapT -> WFSyncUUID [minlen=0.1,constraint=false]
+
+ WFBitMapS -> cluster_resync:S
+ WFSyncUUID -> cluster_resync:T
+
+ edge [color=green]
+ cluster_resync:any -> Connected [ label="resnyc done",fontcolor=green ]
+
+ edge [color=red]
+ WFReportParams -> CommTrouble
+ Connected -> CommTrouble
+ cluster_resync:any -> CommTrouble
+ edge [color=black]
+ CommTrouble -> Unconnected [label="receiver thread is stopped" ]
+
+}
diff --git a/Documentation/blockdev/drbd/node-states-8.dot b/Documentation/blockdev/drbd/node-states-8.dot
new file mode 100644
index 000000000000..4a2b00c23547
--- /dev/null
+++ b/Documentation/blockdev/drbd/node-states-8.dot
@@ -0,0 +1,14 @@
+digraph node_states {
+ Secondary -> Primary [ label = "ioctl_set_state()" ]
+ Primary -> Secondary [ label = "ioctl_set_state()" ]
+}
+
+digraph peer_states {
+ Secondary -> Primary [ label = "recv state packet" ]
+ Primary -> Secondary [ label = "recv state packet" ]
+ Primary -> Unknown [ label = "connection lost" ]
+ Secondary -> Unknown [ label = "connection lost" ]
+ Unknown -> Primary [ label = "connected" ]
+ Unknown -> Secondary [ label = "connected" ]
+}
+
diff --git a/Documentation/dontdiff b/Documentation/dontdiff
index e1efc400bed6..d9bcffd59433 100644
--- a/Documentation/dontdiff
+++ b/Documentation/dontdiff
@@ -65,10 +65,10 @@ aicdb.h*
asm-offsets.h
asm_offsets.h
autoconf.h*
+av_permissions.h
bbootsect
bin2c
binkernel.spec
-binoffset
bootsect
bounds.h
bsetup
@@ -95,12 +95,15 @@ docproc
elf2ecoff
elfconfig.h*
fixdep
+flask.h
fore200e_mkfirm
fore200e_pca_fw.c*
gconf
gen-devlist
gen_crc32table
gen_init_cpio
+generated
+genheaders
genksyms
*_gray256.c
ihex2fw
diff --git a/Documentation/edac.txt b/Documentation/edac.txt
index 06f8f46692dc..4ee546fd2f1a 100644
--- a/Documentation/edac.txt
+++ b/Documentation/edac.txt
@@ -6,6 +6,8 @@ Written by Doug Thompson <dougthompson@xmission.com>
7 Dec 2005
17 Jul 2007 Updated
+(c) Mauro Carvalho Chehab <mchehab@redhat.com>
+05 Aug 2009 Nehalem interface
EDAC is maintained and written by:
@@ -718,3 +720,154 @@ unique drivers for their hardware systems.
The 'test_device_edac' sample driver is located at the
bluesmoke.sourceforge.net project site for EDAC.
+=======================================================================
+NEHALEM USAGE OF EDAC APIs
+
+This chapter documents some EXPERIMENTAL mappings for EDAC API to handle
+Nehalem EDAC driver. They will likely be changed on future versions
+of the driver.
+
+Due to the way Nehalem exports Memory Controller data, some adjustments
+were done at i7core_edac driver. This chapter will cover those differences
+
+1) On Nehalem, there are one Memory Controller per Quick Patch Interconnect
+ (QPI). At the driver, the term "socket" means one QPI. This is
+ associated with a physical CPU socket.
+
+ Each MC have 3 physical read channels, 3 physical write channels and
+ 3 logic channels. The driver currenty sees it as just 3 channels.
+ Each channel can have up to 3 DIMMs.
+
+ The minimum known unity is DIMMs. There are no information about csrows.
+ As EDAC API maps the minimum unity is csrows, the driver sequencially
+ maps channel/dimm into different csrows.
+
+ For example, suposing the following layout:
+ Ch0 phy rd0, wr0 (0x063f4031): 2 ranks, UDIMMs
+ dimm 0 1024 Mb offset: 0, bank: 8, rank: 1, row: 0x4000, col: 0x400
+ dimm 1 1024 Mb offset: 4, bank: 8, rank: 1, row: 0x4000, col: 0x400
+ Ch1 phy rd1, wr1 (0x063f4031): 2 ranks, UDIMMs
+ dimm 0 1024 Mb offset: 0, bank: 8, rank: 1, row: 0x4000, col: 0x400
+ Ch2 phy rd3, wr3 (0x063f4031): 2 ranks, UDIMMs
+ dimm 0 1024 Mb offset: 0, bank: 8, rank: 1, row: 0x4000, col: 0x400
+ The driver will map it as:
+ csrow0: channel 0, dimm0
+ csrow1: channel 0, dimm1
+ csrow2: channel 1, dimm0
+ csrow3: channel 2, dimm0
+
+exports one
+ DIMM per csrow.
+
+ Each QPI is exported as a different memory controller.
+
+2) Nehalem MC has the hability to generate errors. The driver implements this
+ functionality via some error injection nodes:
+
+ For injecting a memory error, there are some sysfs nodes, under
+ /sys/devices/system/edac/mc/mc?/:
+
+ inject_addrmatch/*:
+ Controls the error injection mask register. It is possible to specify
+ several characteristics of the address to match an error code:
+ dimm = the affected dimm. Numbers are relative to a channel;
+ rank = the memory rank;
+ channel = the channel that will generate an error;
+ bank = the affected bank;
+ page = the page address;
+ column (or col) = the address column.
+ each of the above values can be set to "any" to match any valid value.
+
+ At driver init, all values are set to any.
+
+ For example, to generate an error at rank 1 of dimm 2, for any channel,
+ any bank, any page, any column:
+ echo 2 >/sys/devices/system/edac/mc/mc0/inject_addrmatch/dimm
+ echo 1 >/sys/devices/system/edac/mc/mc0/inject_addrmatch/rank
+
+ To return to the default behaviour of matching any, you can do:
+ echo any >/sys/devices/system/edac/mc/mc0/inject_addrmatch/dimm
+ echo any >/sys/devices/system/edac/mc/mc0/inject_addrmatch/rank
+
+ inject_eccmask:
+ specifies what bits will have troubles,
+
+ inject_section:
+ specifies what ECC cache section will get the error:
+ 3 for both
+ 2 for the highest
+ 1 for the lowest
+
+ inject_type:
+ specifies the type of error, being a combination of the following bits:
+ bit 0 - repeat
+ bit 1 - ecc
+ bit 2 - parity
+
+ inject_enable starts the error generation when something different
+ than 0 is written.
+
+ All inject vars can be read. root permission is needed for write.
+
+ Datasheet states that the error will only be generated after a write on an
+ address that matches inject_addrmatch. It seems, however, that reading will
+ also produce an error.
+
+ For example, the following code will generate an error for any write access
+ at socket 0, on any DIMM/address on channel 2:
+
+ echo 2 >/sys/devices/system/edac/mc/mc0/inject_addrmatch/channel
+ echo 2 >/sys/devices/system/edac/mc/mc0/inject_type
+ echo 64 >/sys/devices/system/edac/mc/mc0/inject_eccmask
+ echo 3 >/sys/devices/system/edac/mc/mc0/inject_section
+ echo 1 >/sys/devices/system/edac/mc/mc0/inject_enable
+ dd if=/dev/mem of=/dev/null seek=16k bs=4k count=1 >& /dev/null
+
+ For socket 1, it is needed to replace "mc0" by "mc1" at the above
+ commands.
+
+ The generated error message will look like:
+
+ EDAC MC0: UE row 0, channel-a= 0 channel-b= 0 labels "-": NON_FATAL (addr = 0x0075b980, socket=0, Dimm=0, Channel=2, syndrome=0x00000040, count=1, Err=8c0000400001009f:4000080482 (read error: read ECC error))
+
+3) Nehalem specific Corrected Error memory counters
+
+ Nehalem have some registers to count memory errors. The driver uses those
+ registers to report Corrected Errors on devices with Registered Dimms.
+
+ However, those counters don't work with Unregistered Dimms. As the chipset
+ offers some counters that also work with UDIMMS (but with a worse level of
+ granularity than the default ones), the driver exposes those registers for
+ UDIMM memories.
+
+ They can be read by looking at the contents of all_channel_counts/
+
+ $ for i in /sys/devices/system/edac/mc/mc0/all_channel_counts/*; do echo $i; cat $i; done
+ /sys/devices/system/edac/mc/mc0/all_channel_counts/udimm0
+ 0
+ /sys/devices/system/edac/mc/mc0/all_channel_counts/udimm1
+ 0
+ /sys/devices/system/edac/mc/mc0/all_channel_counts/udimm2
+ 0
+
+ What happens here is that errors on different csrows, but at the same
+ dimm number will increment the same counter.
+ So, in this memory mapping:
+ csrow0: channel 0, dimm0
+ csrow1: channel 0, dimm1
+ csrow2: channel 1, dimm0
+ csrow3: channel 2, dimm0
+ The hardware will increment udimm0 for an error at the first dimm at either
+ csrow0, csrow2 or csrow3;
+ The hardware will increment udimm1 for an error at the second dimm at either
+ csrow0, csrow2 or csrow3;
+ The hardware will increment udimm2 for an error at the third dimm at either
+ csrow0, csrow2 or csrow3;
+
+4) Standard error counters
+
+ The standard error counters are generated when an mcelog error is received
+ by the driver. Since, with udimm, this is counted by software, it is
+ possible that some errors could be lost. With rdimm's, they displays the
+ contents of the registers
+
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 04e6c819b28a..4b8cff176382 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -404,20 +404,19 @@ Who: Alex Chiang <achiang@hp.com>
---------------------------
-What: i2c-voodoo3 driver
-When: October 2009
-Why: Superseded by tdfxfb. I2C/DDC support used to live in a separate
- driver but this caused driver conflicts.
-Who: Jean Delvare <khali@linux-fr.org>
- Krzysztof Helt <krzysztof.h1@wp.pl>
-
----------------------------
-
What: CONFIG_RFKILL_INPUT
When: 2.6.33
Why: Should be implemented in userspace, policy daemon.
Who: Johannes Berg <johannes@sipsolutions.net>
+---------------------------
+
+What: CONFIG_INOTIFY
+When: 2.6.33
+Why: last user (audit) will be converted to the newer more generic
+ and more easily maintained fsnotify subsystem
+Who: Eric Paris <eparis@redhat.com>
+
----------------------------
What: lock_policy_rwsem_* and unlock_policy_rwsem_* will not be
diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX
index f15621ee5599..3023a0a07355 100644
--- a/Documentation/filesystems/00-INDEX
+++ b/Documentation/filesystems/00-INDEX
@@ -1,7 +1,5 @@
00-INDEX
- this file (info on some of the filesystems supported by linux).
-Exporting
- - explanation of how to make filesystems exportable.
Locking
- info on locking rules as they pertain to Linux VFS.
9p.txt
@@ -36,6 +34,8 @@ dnotify.txt
- info about directory notification in Linux.
ecryptfs.txt
- docs on eCryptfs: stacked cryptographic filesystem for Linux.
+exofs.txt
+ - info, usage, mount options, design about EXOFS.
ext2.txt
- info, mount options and specifications for the Ext2 filesystem.
ext3.txt
@@ -66,12 +66,8 @@ mandatory-locking.txt
- info on the Linux implementation of Sys V mandatory file locking.
ncpfs.txt
- info on Novell Netware(tm) filesystem using NCP protocol.
-nfs41-server.txt
- - info on the Linux server implementation of NFSv4 minor version 1.
-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.
+nfs/
+ - nfs-related documentation.
nilfs2.txt
- info and mount options for the NILFS2 filesystem.
ntfs.txt
diff --git a/Documentation/filesystems/ceph.txt b/Documentation/filesystems/ceph.txt
new file mode 100644
index 000000000000..6e03917316bd
--- /dev/null
+++ b/Documentation/filesystems/ceph.txt
@@ -0,0 +1,139 @@
+Ceph Distributed File System
+============================
+
+Ceph is a distributed network file system designed to provide good
+performance, reliability, and scalability.
+
+Basic features include:
+
+ * POSIX semantics
+ * Seamless scaling from 1 to many thousands of nodes
+ * High availability and reliability. No single points of failure.
+ * N-way replication of data across storage nodes
+ * Fast recovery from node failures
+ * Automatic rebalancing of data on node addition/removal
+ * Easy deployment: most FS components are userspace daemons
+
+Also,
+ * Flexible snapshots (on any directory)
+ * Recursive accounting (nested files, directories, bytes)
+
+In contrast to cluster filesystems like GFS, OCFS2, and GPFS that rely
+on symmetric access by all clients to shared block devices, Ceph
+separates data and metadata management into independent server
+clusters, similar to Lustre. Unlike Lustre, however, metadata and
+storage nodes run entirely as user space daemons. Storage nodes
+utilize btrfs to store data objects, leveraging its advanced features
+(checksumming, metadata replication, etc.). File data is striped
+across storage nodes in large chunks to distribute workload and
+facilitate high throughputs. When storage nodes fail, data is
+re-replicated in a distributed fashion by the storage nodes themselves
+(with some minimal coordination from a cluster monitor), making the
+system extremely efficient and scalable.
+
+Metadata servers effectively form a large, consistent, distributed
+in-memory cache above the file namespace that is extremely scalable,
+dynamically redistributes metadata in response to workload changes,
+and can tolerate arbitrary (well, non-Byzantine) node failures. The
+metadata server takes a somewhat unconventional approach to metadata
+storage to significantly improve performance for common workloads. In
+particular, inodes with only a single link are embedded in
+directories, allowing entire directories of dentries and inodes to be
+loaded into its cache with a single I/O operation. The contents of
+extremely large directories can be fragmented and managed by
+independent metadata servers, allowing scalable concurrent access.
+
+The system offers automatic data rebalancing/migration when scaling
+from a small cluster of just a few nodes to many hundreds, without
+requiring an administrator carve the data set into static volumes or
+go through the tedious process of migrating data between servers.
+When the file system approaches full, new nodes can be easily added
+and things will "just work."
+
+Ceph includes flexible snapshot mechanism that allows a user to create
+a snapshot on any subdirectory (and its nested contents) in the
+system. Snapshot creation and deletion are as simple as 'mkdir
+.snap/foo' and 'rmdir .snap/foo'.
+
+Ceph also provides some recursive accounting on directories for nested
+files and bytes. That is, a 'getfattr -d foo' on any directory in the
+system will reveal the total number of nested regular files and
+subdirectories, and a summation of all nested file sizes. This makes
+the identification of large disk space consumers relatively quick, as
+no 'du' or similar recursive scan of the file system is required.
+
+
+Mount Syntax
+============
+
+The basic mount syntax is:
+
+ # mount -t ceph monip[:port][,monip2[:port]...]:/[subdir] mnt
+
+You only need to specify a single monitor, as the client will get the
+full list when it connects. (However, if the monitor you specify
+happens to be down, the mount won't succeed.) The port can be left
+off if the monitor is using the default. So if the monitor is at
+1.2.3.4,
+
+ # mount -t ceph 1.2.3.4:/ /mnt/ceph
+
+is sufficient. If /sbin/mount.ceph is installed, a hostname can be
+used instead of an IP address.
+
+
+
+Mount Options
+=============
+
+ ip=A.B.C.D[:N]
+ Specify the IP and/or port the client should bind to locally.
+ There is normally not much reason to do this. If the IP is not
+ specified, the client's IP address is determined by looking at the
+ address it's connection to the monitor originates from.
+
+ wsize=X
+ Specify the maximum write size in bytes. By default there is no
+ maximu. Ceph will normally size writes based on the file stripe
+ size.
+
+ rsize=X
+ Specify the maximum readahead.
+
+ mount_timeout=X
+ Specify the timeout value for mount (in seconds), in the case
+ of a non-responsive Ceph file system. The default is 30
+ seconds.
+
+ rbytes
+ When stat() is called on a directory, set st_size to 'rbytes',
+ the summation of file sizes over all files nested beneath that
+ directory. This is the default.
+
+ norbytes
+ When stat() is called on a directory, set st_size to the
+ number of entries in that directory.
+
+ nocrc
+ Disable CRC32C calculation for data writes. If set, the OSD
+ must rely on TCP's error correction to detect data corruption
+ in the data payload.
+
+ noasyncreaddir
+ Disable client's use its local cache to satisfy readdir
+ requests. (This does not change correctness; the client uses
+ cached metadata only when a lease or capability ensures it is
+ valid.)
+
+
+More Information
+================
+
+For more information on Ceph, see the home page at
+ http://ceph.newdream.net/
+
+The Linux kernel client source tree is available at
+ git://ceph.newdream.net/linux-ceph-client.git
+
+and the source for the full system is at
+ git://ceph.newdream.net/ceph.git
diff --git a/Documentation/filesystems/exofs.txt b/Documentation/filesystems/exofs.txt
index 0ced74c2f73c..abd2a9b5b787 100644
--- a/Documentation/filesystems/exofs.txt
+++ b/Documentation/filesystems/exofs.txt
@@ -60,13 +60,13 @@ USAGE
mkfs.exofs --pid=65536 --format /dev/osd0
- The --format is optional if not specified no OSD_FORMAT will be
- preformed and a clean file system will be created in the specified pid,
+ The --format is optional. If not specified, no OSD_FORMAT will be
+ performed and a clean file system will be created in the specified pid,
in the available space of the target. (Use --format=size_in_meg to limit
the total LUN space available)
- If pid already exist it will be deleted and a new one will be created in it's
- place. Be careful.
+ If pid already exists, it will be deleted and a new one will be created in
+ its place. Be careful.
An exofs lives inside a single OSD partition. You can create multiple exofs
filesystems on the same device using multiple pids.
@@ -81,7 +81,7 @@ USAGE
7. For reference (See do-exofs example script):
do-exofs start - an example of how to perform the above steps.
- do-exofs stop - an example of how to unmount the file system.
+ do-exofs stop - an example of how to unmount the file system.
do-exofs format - an example of how to format and mkfs a new exofs.
8. Extra compilation flags (uncomment in fs/exofs/Kbuild):
@@ -104,8 +104,8 @@ Where:
exofs specific options: Options are separated by commas (,)
pid=<integer> - The partition number to mount/create as
container of the filesystem.
- This option is mandatory
- to=<integer> - Timeout in ticks for a single command
+ This option is mandatory.
+ to=<integer> - Timeout in ticks for a single command.
default is (60 * HZ) [for debugging only]
===============================================================================
@@ -116,7 +116,7 @@ DESIGN
with a special ID (defined in common.h).
Information included in the file system control block is used to fill the
in-memory superblock structure at mount time. This object is created before
- the file system is used by mkexofs.c It contains information such as:
+ the file system is used by mkexofs.c. It contains information such as:
- The file system's magic number
- The next inode number to be allocated
@@ -134,8 +134,8 @@ DESIGN
attributes. This applies to both regular files and other types (directories,
device files, symlinks, etc.).
-* Credentials are generated per object (inode and superblock) when they is
- created in memory (read off disk or created). The credential works for all
+* Credentials are generated per object (inode and superblock) when they are
+ created in memory (read from disk or created). The credential works for all
operations and is used as long as the object remains in memory.
* Async OSD operations are used whenever possible, but the target may execute
@@ -145,7 +145,8 @@ DESIGN
from executing in reverse order:
- The following are handled with the OBJ_CREATED and OBJ_2BCREATED
flags. OBJ_CREATED is set when we know the object exists on the OSD -
- in create's callback function, and when we successfully do a read_inode.
+ in create's callback function, and when we successfully do a
+ read_inode.
OBJ_2BCREATED is set in the beginning of the create function, so we
know that we should wait.
- create/delete: delete should wait until the object is created
diff --git a/Documentation/filesystems/nfs/00-INDEX b/Documentation/filesystems/nfs/00-INDEX
new file mode 100644
index 000000000000..6ff3d212027b
--- /dev/null
+++ b/Documentation/filesystems/nfs/00-INDEX
@@ -0,0 +1,12 @@
+00-INDEX
+ - this file (nfs-related documentation).
+Exporting
+ - explanation of how to make filesystems exportable.
+nfs.txt
+ - nfs client, and DNS resolution for fs_locations.
+nfs41-server.txt
+ - info on the Linux server implementation of NFSv4 minor version 1.
+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.
diff --git a/Documentation/filesystems/Exporting b/Documentation/filesystems/nfs/Exporting
index 87019d2b5981..87019d2b5981 100644
--- a/Documentation/filesystems/Exporting
+++ b/Documentation/filesystems/nfs/Exporting
diff --git a/Documentation/filesystems/nfs-rdma.txt b/Documentation/filesystems/nfs/nfs-rdma.txt
index e386f7e4bcee..e386f7e4bcee 100644
--- a/Documentation/filesystems/nfs-rdma.txt
+++ b/Documentation/filesystems/nfs/nfs-rdma.txt
diff --git a/Documentation/filesystems/nfs.txt b/Documentation/filesystems/nfs/nfs.txt
index f50f26ce6cd0..f50f26ce6cd0 100644
--- a/Documentation/filesystems/nfs.txt
+++ b/Documentation/filesystems/nfs/nfs.txt
diff --git a/Documentation/filesystems/nfs41-server.txt b/Documentation/filesystems/nfs/nfs41-server.txt
index 5920fe26e6ff..1bd0d0c05171 100644
--- a/Documentation/filesystems/nfs41-server.txt
+++ b/Documentation/filesystems/nfs/nfs41-server.txt
@@ -41,7 +41,7 @@ interoperability problems with future clients. Known issues:
conformant with the spec (for example, we don't use kerberos
on the backchannel correctly).
- no trunking support: no clients currently take advantage of
- trunking, but this is a mandatory failure, and its use is
+ trunking, but this is a mandatory feature, and its use is
recommended to clients in a number of places. (E.g. to ensure
timely renewal in case an existing connection's retry timeouts
have gotten too long; see section 8.3 of the draft.)
@@ -213,3 +213,10 @@ The following cases aren't supported yet:
DESTROY_CLIENTID, DESTROY_SESSION, EXCHANGE_ID.
* DESTROY_SESSION MUST be the final operation in the COMPOUND request.
+Nonstandard compound limitations:
+* No support for a sessions fore channel RPC compound that requires both a
+ ca_maxrequestsize request and a ca_maxresponsesize reply, so we may
+ fail to live up to the promise we made in CREATE_SESSION fore channel
+ negotiation.
+* No more than one IO operation (read, write, readdir) allowed per
+ compound.
diff --git a/Documentation/filesystems/nfsroot.txt b/Documentation/filesystems/nfs/nfsroot.txt
index 3ba0b945aaf8..3ba0b945aaf8 100644
--- a/Documentation/filesystems/nfsroot.txt
+++ b/Documentation/filesystems/nfs/nfsroot.txt
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index 92b888d540a6..a7e9746ee7ea 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -140,7 +140,7 @@ Callers of notify_change() need ->i_mutex now.
New super_block field "struct export_operations *s_export_op" for
explicit support for exporting, e.g. via NFS. The structure is fully
documented at its declaration in include/linux/fs.h, and in
-Documentation/filesystems/Exporting.
+Documentation/filesystems/nfs/Exporting.
Briefly it allows for the definition of decode_fh and encode_fh operations
to encode and decode filehandles, and allows the filesystem to use
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 2c48f945546b..4af0018533f2 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -1072,7 +1072,8 @@ second). The meanings of the columns are as follows, from left to right:
- irq: servicing interrupts
- softirq: servicing softirqs
- steal: involuntary wait
-- guest: running a guest
+- guest: running a normal guest
+- guest_nice: running a niced guest
The "intr" line gives counts of interrupts serviced since boot time, for each
of the possible system interrupts. The first column is the total of all
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 623f094c9d8d..3de2f32edd90 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -472,7 +472,7 @@ __sync_single_inode) to check if ->writepages has been successful in
writing out the whole address_space.
The Writeback tag is used by filemap*wait* and sync_page* functions,
-via wait_on_page_writeback_range, to wait for all writeback to
+via filemap_fdatawait_range, to wait for all writeback to
complete. While waiting ->sync_page (if defined) will be called on
each page that is found to require writeback.
diff --git a/Documentation/hwlat_detector.txt b/Documentation/hwlat_detector.txt
new file mode 100644
index 000000000000..cb61516483d3
--- /dev/null
+++ b/Documentation/hwlat_detector.txt
@@ -0,0 +1,64 @@
+Introduction:
+-------------
+
+The module hwlat_detector is a special purpose kernel module that is used to
+detect large system latencies induced by the behavior of certain underlying
+hardware or firmware, independent of Linux itself. The code was developed
+originally to detect SMIs (System Management Interrupts) on x86 systems,
+however there is nothing x86 specific about this patchset. It was
+originally written for use by the "RT" patch since the Real Time
+kernel is highly latency sensitive.
+
+SMIs are usually not serviced by the Linux kernel, which typically does not
+even know that they are occuring. SMIs are instead are set up by BIOS code
+and are serviced by BIOS code, usually for "critical" events such as
+management of thermal sensors and fans. Sometimes though, SMIs are used for
+other tasks and those tasks can spend an inordinate amount of time in the
+handler (sometimes measured in milliseconds). Obviously this is a problem if
+you are trying to keep event service latencies down in the microsecond range.
+
+The hardware latency detector works by hogging all of the cpus for configurable
+amounts of time (by calling stop_machine()), polling the CPU Time Stamp Counter
+for some period, then looking for gaps in the TSC data. Any gap indicates a
+time when the polling was interrupted and since the machine is stopped and
+interrupts turned off the only thing that could do that would be an SMI.
+
+Note that the SMI detector should *NEVER* be used in a production environment.
+It is intended to be run manually to determine if the hardware platform has a
+problem with long system firmware service routines.
+
+Usage:
+------
+
+Loading the module hwlat_detector passing the parameter "enabled=1" (or by
+setting the "enable" entry in "hwlat_detector" debugfs toggled on) is the only
+step required to start the hwlat_detector. It is possible to redefine the
+threshold in microseconds (us) above which latency spikes will be taken
+into account (parameter "threshold=").
+
+Example:
+
+ # modprobe hwlat_detector enabled=1 threshold=100
+
+After the module is loaded, it creates a directory named "hwlat_detector" under
+the debugfs mountpoint, "/debug/hwlat_detector" for this text. It is necessary
+to have debugfs mounted, which might be on /sys/debug on your system.
+
+The /debug/hwlat_detector interface contains the following files:
+
+count - number of latency spikes observed since last reset
+enable - a global enable/disable toggle (0/1), resets count
+max - maximum hardware latency actually observed (usecs)
+sample - a pipe from which to read current raw sample data
+ in the format <timestamp> <latency observed usecs>
+ (can be opened O_NONBLOCK for a single sample)
+threshold - minimum latency value to be considered (usecs)
+width - time period to sample with CPUs held (usecs)
+ must be less than the total window size (enforced)
+window - total period of sampling, width being inside (usecs)
+
+By default we will set width to 500,000 and window to 1,000,000, meaning that
+we will sample every 1,000,000 usecs (1s) for 500,000 usecs (0.5s). If we
+observe any latencies that exceed the threshold (initially 100 usecs),
+then we write to a global sample ring buffer of 8K samples, which is
+consumed by reading from the "sample" (pipe) debugfs file interface.
diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87
index 659315d98e00..f9ba96c0ac4a 100644
--- a/Documentation/hwmon/it87
+++ b/Documentation/hwmon/it87
@@ -86,7 +86,6 @@ The IT8712F and IT8716F additionally feature VID inputs, used to report
the Vcore voltage of the processor. The early IT8712F have 5 VID pins,
the IT8716F and late IT8712F have 6. They are shared with other functions
though, so the functionality may not be available on a given system.
-The driver dumbly assume it is there.
The IT8718F and IT8720F also features VID inputs (up to 8 pins) but the value
is stored in the Super-I/O configuration space. Due to technical limitations,
diff --git a/Documentation/hwmon/mc13783-adc b/Documentation/hwmon/mc13783-adc
new file mode 100644
index 000000000000..044531a86405
--- /dev/null
+++ b/Documentation/hwmon/mc13783-adc
@@ -0,0 +1,50 @@
+Kernel driver mc13783-adc
+=========================
+
+Supported chips:
+ * Freescale Atlas MC13783
+ Prefix: 'mc13783_adc'
+ Datasheet: http://www.freescale.com/files/rf_if/doc/data_sheet/MC13783.pdf?fsrch=1
+
+Authors:
+ Sascha Hauer <s.hauer@pengutronix.de>
+ Luotao Fu <l.fu@pengutronix.de>
+
+Description
+-----------
+
+The Freescale MC13783 is a Power Management and Audio Circuit. Among
+other things it contains a 10-bit A/D converter. The converter has 16
+channels which can be used in different modes.
+The A/D converter has a resolution of 2.25mV. Channels 0-4 have
+a dedicated meaning with chip internal scaling applied. Channels 5-7
+can be used as general purpose inputs or alternatively in a dedicated
+mode. Channels 12-15 are occupied by the touchscreen if it's active.
+
+Currently the driver only supports channels 2 and 5-15 with no alternative
+modes for channels 5-7.
+
+See this table for the meaning of the different channels and their chip
+internal scaling:
+
+Channel Signal Input Range Scaling
+-------------------------------------------------------------------------------
+0 Battery Voltage (BATT) 2.50 - 4.65V -2.40V
+1 Battery Current (BATT - BATTISNS) -50 - 50 mV x20
+2 Application Supply (BP) 2.50 - 4.65V -2.40V
+3 Charger Voltage (CHRGRAW) 0 - 10V / /5
+ 0 - 20V /10
+4 Charger Current (CHRGISNSP-CHRGISNSN) -0.25V - 0.25V x4
+5 General Purpose ADIN5 / Battery Pack Thermistor 0 - 2.30V No
+6 General Purpose ADIN6 / Backup Voltage (LICELL) 0 - 2.30V / No /
+ 1.50 - 3.50V -1.20V
+7 General Purpose ADIN7 / UID / Die Temperature 0 - 2.30V / No /
+ 0 - 2.55V / x0.9 / No
+8 General Purpose ADIN8 0 - 2.30V No
+9 General Purpose ADIN9 0 - 2.30V No
+10 General Purpose ADIN10 0 - 2.30V No
+11 General Purpose ADIN11 0 - 2.30V No
+12 General Purpose TSX1 / Touchscreen X-plate 1 0 - 2.30V No
+13 General Purpose TSX2 / Touchscreen X-plate 2 0 - 2.30V No
+14 General Purpose TSY1 / Touchscreen Y-plate 1 0 - 2.30V No
+15 General Purpose TSY2 / Touchscreen Y-plate 2 0 - 2.30V No
diff --git a/Documentation/hwmon/w83627hf b/Documentation/hwmon/w83627hf
index 6ee36dbafd64..44dd2bcc72bd 100644
--- a/Documentation/hwmon/w83627hf
+++ b/Documentation/hwmon/w83627hf
@@ -32,8 +32,6 @@ Authors:
Module Parameters
-----------------
-* force_addr: int
- Initialize the ISA address of the sensors
* force_i2c: int
Initialize the I2C address of the sensors
* init: int
@@ -70,3 +68,30 @@ doesn't help, you may just ignore the bogus VID reading with no harm done.
For further information on this driver see the w83781d driver documentation.
[1] http://www.lm-sensors.org/browser/lm-sensors/trunk/doc/vid
+
+Forcing the address
+-------------------
+
+The driver used to have a module parameter named force_addr, which could
+be used to force the base I/O address of the hardware monitoring block.
+This was meant as a workaround for mainboards with a broken BIOS. This
+module parameter is gone for technical reasons. If you need this feature,
+you can obtain the same result by using the isaset tool (part of
+lm-sensors) before loading the driver:
+
+# Enter the Super I/O config space
+isaset -y -f 0x2e 0x87
+isaset -y -f 0x2e 0x87
+
+# Select the hwmon logical device
+isaset -y 0x2e 0x2f 0x07 0x0b
+
+# Set the base I/O address (to 0x290 in this example)
+isaset -y 0x2e 0x2f 0x60 0x02
+isaset -y 0x2e 0x2f 0x61 0x90
+
+# Exit the Super-I/O config space
+isaset -y -f 0x2e 0xaa
+
+The above sequence assumes a Super-I/O config space at 0x2e/0x2f, but
+0x4e/0x4f is also possible.
diff --git a/Documentation/i2c/busses/i2c-piix4 b/Documentation/i2c/busses/i2c-piix4
index c5b37c570554..ac540c71c7eb 100644
--- a/Documentation/i2c/busses/i2c-piix4
+++ b/Documentation/i2c/busses/i2c-piix4
@@ -8,7 +8,7 @@ Supported adapters:
Datasheet: Only available via NDA from ServerWorks
* ATI IXP200, IXP300, IXP400, SB600, SB700 and SB800 southbridges
Datasheet: Not publicly available
- * AMD SB900
+ * AMD Hudson-2
Datasheet: Not publicly available
* Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge
Datasheet: Publicly available at the SMSC website http://www.smsc.com
diff --git a/Documentation/i2c/busses/i2c-voodoo3 b/Documentation/i2c/busses/i2c-voodoo3
deleted file mode 100644
index 62d90a454d39..000000000000
--- a/Documentation/i2c/busses/i2c-voodoo3
+++ /dev/null
@@ -1,62 +0,0 @@
-Kernel driver i2c-voodoo3
-
-Supported adapters:
- * 3dfx Voodoo3 based cards
- * Voodoo Banshee based cards
-
-Authors:
- Frodo Looijaard <frodol@dds.nl>,
- Philip Edelbrock <phil@netroedge.com>,
- Ralph Metzler <rjkm@thp.uni-koeln.de>,
- Mark D. Studebaker <mdsxyz123@yahoo.com>
-
-Main contact: Philip Edelbrock <phil@netroedge.com>
-
-The code is based upon Ralph's test code (he did the hard stuff ;')
-
-Description
------------
-
-The 3dfx Voodoo3 chip contains two I2C interfaces (aka a I2C 'master' or
-'host').
-
-The first interface is used for DDC (Data Display Channel) which is a
-serial channel through the VGA monitor connector to a DDC-compliant
-monitor. This interface is defined by the Video Electronics Standards
-Association (VESA). The standards are available for purchase at
-http://www.vesa.org .
-
-The second interface is a general-purpose I2C bus. The intent by 3dfx was
-to allow manufacturers to add extra chips to the video card such as a
-TV-out chip such as the BT869 or possibly even I2C based temperature
-sensors like the ADM1021 or LM75.
-
-Stability
----------
-
-Seems to be stable on the test machine, but needs more testing on other
-machines. Simultaneous accesses of the DDC and I2C busses may cause errors.
-
-Supported Devices
------------------
-
-Specifically, this driver was written and tested on the '3dfx Voodoo3 AGP
-3000' which has a tv-out feature (s-video or composite). According to the
-docs and discussions, this code should work for any Voodoo3 based cards as
-well as Voodoo Banshee based cards. The DDC interface has been tested on a
-Voodoo Banshee card.
-
-Issues
-------
-
-Probably many, but it seems to work OK on my system. :')
-
-
-External Device Connection
---------------------------
-
-The digital video input jumpers give availability to the I2C bus.
-Specifically, pins 13 and 25 (bottom row middle, and bottom right-end) are
-the I2C clock and I2C data lines, respectively. +5V and GND are probably
-also easily available making the addition of extra I2C/SMBus devices easy
-to implement.
diff --git a/Documentation/i2c/old-module-parameters b/Documentation/i2c/old-module-parameters
new file mode 100644
index 000000000000..8e2b629d533c
--- /dev/null
+++ b/Documentation/i2c/old-module-parameters
@@ -0,0 +1,44 @@
+I2C device driver binding control from user-space
+=================================================
+
+Up to kernel 2.6.32, many i2c drivers used helper macros provided by
+<linux/i2c.h> which created standard module parameters to let the user
+control how the driver would probe i2c buses and attach to devices. These
+parameters were known as "probe" (to let the driver probe for an extra
+address), "force" (to forcibly attach the driver to a given device) and
+"ignore" (to prevent a driver from probing a given address).
+
+With the conversion of the i2c subsystem to the standard device driver
+binding model, it became clear that these per-module parameters were no
+longer needed, and that a centralized implementation was possible. The new,
+sysfs-based interface is described in the documentation file
+"instantiating-devices", section "Method 4: Instantiate from user-space".
+
+Below is a mapping from the old module parameters to the new interface.
+
+Attaching a driver to an I2C device
+-----------------------------------
+
+Old method (module parameters):
+# modprobe <driver> probe=1,0x2d
+# modprobe <driver> force=1,0x2d
+# modprobe <driver> force_<device>=1,0x2d
+
+New method (sysfs interface):
+# echo <device> 0x2d > /sys/bus/i2c/devices/i2c-1/new_device
+
+Preventing a driver from attaching to an I2C device
+---------------------------------------------------
+
+Old method (module parameters):
+# modprobe <driver> ignore=1,0x2f
+
+New method (sysfs interface):
+# echo dummy 0x2f > /sys/bus/i2c/devices/i2c-1/new_device
+# modprobe <driver>
+
+Of course, it is important to instantiate the "dummy" device before loading
+the driver. The dummy device will be handled by i2c-core itself, preventing
+other drivers from binding to it later on. If there is a real device at the
+problematic address, and you want another driver to bind to it, then simply
+pass the name of the device in question instead of "dummy".
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 947374977ca5..91cfdd76131e 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -182,6 +182,7 @@ Code Seq# Include File Comments
<http://www.proximity.com.au/~brian/winradio/>
0x90 00 drivers/cdrom/sbpcd.h
0x93 60-7F linux/auto_fs.h
+0x97 00-7F fs/ceph/ioctl.h Ceph file system
0x99 00-0F 537-Addinboard driver
<mailto:buk@buks.ipn.de>
0xA0 all linux/sdp/sdp.h Industrial Device Project
diff --git a/Documentation/isdn/README.gigaset b/Documentation/isdn/README.gigaset
index f9963103ae3d..0fc9831d7ecb 100644
--- a/Documentation/isdn/README.gigaset
+++ b/Documentation/isdn/README.gigaset
@@ -5,7 +5,7 @@ GigaSet 307x Device Driver
------------
1.1. Hardware
--------
- This release supports the connection of the Gigaset 307x/417x family of
+ This driver supports the connection of the Gigaset 307x/417x family of
ISDN DECT bases via Gigaset M101 Data, Gigaset M105 Data or direct USB
connection. The following devices are reported to be compatible:
@@ -33,7 +33,7 @@ GigaSet 307x Device Driver
http://gigaset307x.sourceforge.net/
We had also reports from users of Gigaset M105 who could use the drivers
- with SX 100 and CX 100 ISDN bases (only in unimodem mode, see section 2.4.)
+ with SX 100 and CX 100 ISDN bases (only in unimodem mode, see section 2.5.)
If you have another device that works with our driver, please let us know.
Chances of getting an USB device to work are good if the output of
@@ -49,7 +49,7 @@ GigaSet 307x Device Driver
--------
The driver works with ISDN4linux and so can be used with any software
which is able to use ISDN4linux for ISDN connections (voice or data).
- CAPI4Linux support is planned but not yet available.
+ Experimental Kernel CAPI support is available as a compilation option.
There are some user space tools available at
http://sourceforge.net/projects/gigaset307x/
@@ -102,20 +102,28 @@ GigaSet 307x Device Driver
2.3. ISDN4linux
----------
This is the "normal" mode of operation. After loading the module you can
- set up the ISDN system just as you'd do with any ISDN card.
- Your distribution should provide some configuration utility.
- If not, you can use some HOWTOs like
+ set up the ISDN system just as you'd do with any ISDN card supported by
+ the ISDN4Linux subsystem. Most distributions provide some configuration
+ utility. If not, you can use some HOWTOs like
http://www.linuxhaven.de/dlhp/HOWTO/DE-ISDN-HOWTO-5.html
- If this doesn't work, because you have some recent device like SX100 where
+ If this doesn't work, because you have some device like SX100 where
debug output (see section 3.2.) shows something like this when dialing
CMD Received: ERROR
Available Params: 0
Connection State: 0, Response: -1
gigaset_process_response: resp_code -1 in ConState 0 !
Timeout occurred
- you might need to use unimodem mode:
+ you might need to use unimodem mode. (see section 2.5.)
-2.4. Unimodem mode
+2.4. CAPI
+ ----
+ If the driver is compiled with CAPI support (kernel configuration option
+ GIGASET_CAPI, experimental) it can also be used with CAPI 2.0 kernel and
+ user space applications. ISDN4Linux is supported in this configuration
+ via the capidrv compatibility driver. The kernel module capidrv.ko must
+ be loaded explicitly ("modprobe capidrv") if needed.
+
+2.5. Unimodem mode
-------------
This is needed for some devices [e.g. SX100] as they have problems with
the "normal" commands.
@@ -160,7 +168,7 @@ GigaSet 307x Device Driver
configuration file like /etc/modprobe.conf.local,
using that should be preferred.
-2.5. Call-ID (CID) mode
+2.6. Call-ID (CID) mode
------------------
Call-IDs are numbers used to tag commands to, and responses from, the
Gigaset base in order to support the simultaneous handling of multiple
@@ -188,7 +196,7 @@ GigaSet 307x Device Driver
You can also use /sys/class/tty/ttyGxy/cidmode for changing the CID mode
setting (ttyGxy is ttyGU0 or ttyGB0).
-2.6. Unregistered Wireless Devices (M101/M105)
+2.7. Unregistered Wireless Devices (M101/M105)
-----------------------------------------
The main purpose of the ser_gigaset and usb_gigaset drivers is to allow
the M101 and M105 wireless devices to be used as ISDN devices for ISDN
@@ -228,7 +236,7 @@ GigaSet 307x Device Driver
You have two or more DECT data adapters (M101/M105) and only the
first one you turn on works.
Solution:
- Select Unimodem mode for all DECT data adapters. (see section 2.4.)
+ Select Unimodem mode for all DECT data adapters. (see section 2.5.)
Problem:
Messages like this:
@@ -236,7 +244,7 @@ GigaSet 307x Device Driver
appear in your syslog.
Solution:
Check whether your M10x wireless device is correctly registered to the
- Gigaset base. (see section 2.6.)
+ Gigaset base. (see section 2.7.)
3.2. Telling the driver to provide more information
----------------------------------------------
diff --git a/Documentation/kbuild/kconfig.txt b/Documentation/kbuild/kconfig.txt
index 849b5e56d06f..ab8dc3538988 100644
--- a/Documentation/kbuild/kconfig.txt
+++ b/Documentation/kbuild/kconfig.txt
@@ -106,7 +106,8 @@ This environment variable can be set to specify the path & name of the
KCONFIG_AUTOHEADER
--------------------------------------------------
This environment variable can be set to specify the path & name of the
-"autoconf.h" (header) file. Its default value is "include/linux/autoconf.h".
+"autoconf.h" (header) file.
+Its default value is "include/generated/autoconf.h".
======================================================================
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 9107b387e91f..c6284f44cabf 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -85,7 +85,6 @@ parameter is applicable:
PPT Parallel port support is enabled.
PS2 Appropriate PS/2 support is enabled.
RAM RAM disk support is enabled.
- ROOTPLUG The example Root Plug LSM is enabled.
S390 S390 architecture is enabled.
SCSI Appropriate SCSI support is enabled.
A lot of drivers has their options described inside of
@@ -345,6 +344,15 @@ and is between 256 and 4096 characters. It is defined in the file
Change the amount of debugging information output
when initialising the APIC and IO-APIC components.
+ show_lapic= [APIC,X86] Advanced Programmable Interrupt Controller
+ Limit apic dumping. The parameter defines the maximal
+ number of local apics being dumped. Also it is possible
+ to set it to "all" by meaning -- no limit here.
+ Format: { 1 (default) | 2 | ... | all }.
+ The parameter valid if only apic=debug or
+ apic=verbose is specified.
+ Example: apic=debug show_lapic=all
+
apm= [APM] Advanced Power Management
See header of arch/x86/kernel/apm_32.c.
@@ -779,6 +787,13 @@ and is between 256 and 4096 characters. It is defined in the file
by the set_ftrace_notrace file in the debugfs
tracing directory.
+ ftrace_graph_filter=[function-list]
+ [FTRACE] Limit the top level callers functions traced
+ by the function graph tracer at boot up.
+ function-list is a comma separated list of functions
+ that can be changed at run time by the
+ set_graph_function file in the debugfs tracing directory.
+
gamecon.map[2|3]=
[HW,JOY] Multisystem joystick and NES/SNES/PSX pad
support via parallel port (up to 5 devices per port)
@@ -1017,7 +1032,7 @@ and is between 256 and 4096 characters. It is defined in the file
No delay
ip= [IP_PNP]
- See Documentation/filesystems/nfsroot.txt.
+ See Documentation/filesystems/nfs/nfsroot.txt.
ip2= [HW] Set IO/IRQ pairs for up to 4 IntelliPort boards
See comment before ip2_setup() in
@@ -1538,10 +1553,10 @@ and is between 256 and 4096 characters. It is defined in the file
going to be removed in 2.6.29.
nfsaddrs= [NFS]
- See Documentation/filesystems/nfsroot.txt.
+ See Documentation/filesystems/nfs/nfsroot.txt.
nfsroot= [NFS] nfs root filesystem for disk-less boxes.
- See Documentation/filesystems/nfsroot.txt.
+ See Documentation/filesystems/nfs/nfsroot.txt.
nfs.callback_tcpport=
[NFS] set the TCP port on which the NFSv4 callback
@@ -2164,15 +2179,6 @@ and is between 256 and 4096 characters. It is defined in the file
Useful for devices that are detected asynchronously
(e.g. USB and MMC devices).
- root_plug.vendor_id=
- [ROOTPLUG] Override the default vendor ID
-
- root_plug.product_id=
- [ROOTPLUG] Override the default product ID
-
- root_plug.debug=
- [ROOTPLUG] Enable debugging output
-
rw [KNL] Mount root device read-write on boot
S [KNL] Run init in single mode
@@ -2590,6 +2596,9 @@ and is between 256 and 4096 characters. It is defined in the file
uart6850= [HW,OSS]
Format: <io>,<irq>
+ uhash_entries= [KNL,NET]
+ Set number of hash buckets for UDP/UDP-Lite connections
+
uhci-hcd.ignore_oc=
[USB] Ignore overcurrent events (default N).
Some badly-designed motherboards generate lots of
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
index aafcaa634191..f5056c7fb5be 100644
--- a/Documentation/laptops/thinkpad-acpi.txt
+++ b/Documentation/laptops/thinkpad-acpi.txt
@@ -460,6 +460,8 @@ event code Key Notes
For Lenovo ThinkPads with a new
BIOS, it has to be handled either
by the ACPI OSI, or by userspace.
+ The driver does the right thing,
+ never mess with this.
0x1011 0x10 FN+END Brightness down. See brightness
up for details.
@@ -582,46 +584,15 @@ with hotkey_report_mode.
Brightness hotkey notes:
-These are the current sane choices for brightness key mapping in
-thinkpad-acpi:
+Don't mess with the brightness hotkeys in a Thinkpad. If you want
+notifications for OSD, use the sysfs backlight class event support.
-For IBM and Lenovo models *without* ACPI backlight control (the ones on
-which thinkpad-acpi will autoload its backlight interface by default,
-and on which ACPI video does not export a backlight interface):
-
-1. Don't enable or map the brightness hotkeys in thinkpad-acpi, as
- these older firmware versions unfortunately won't respect the hotkey
- mask for brightness keys anyway, and always reacts to them. This
- usually work fine, unless X.org drivers are doing something to block
- the BIOS. In that case, use (3) below. This is the default mode of
- operation.
-
-2. Enable the hotkeys, but map them to something else that is NOT
- KEY_BRIGHTNESS_UP/DOWN or any other keycode that would cause
- userspace to try to change the backlight level, and use that as an
- on-screen-display hint.
-
-3. IF AND ONLY IF X.org drivers find a way to block the firmware from
- automatically changing the brightness, enable the hotkeys and map
- them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN, and feed that to
- something that calls xbacklight. thinkpad-acpi will not be able to
- change brightness in that case either, so you should disable its
- backlight interface.
-
-For Lenovo models *with* ACPI backlight control:
-
-1. Load up ACPI video and use that. ACPI video will report ACPI
- events for brightness change keys. Do not mess with thinkpad-acpi
- defaults in this case. thinkpad-acpi should not have anything to do
- with backlight events in a scenario where ACPI video is loaded:
- brightness hotkeys must be disabled, and the backlight interface is
- to be kept disabled as well. This is the default mode of operation.
-
-2. Do *NOT* load up ACPI video, enable the hotkeys in thinkpad-acpi,
- and map them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN. Process
- these keys on userspace somehow (e.g. by calling xbacklight).
- The driver will do this automatically if it detects that ACPI video
- has been disabled.
+The driver will issue KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN events
+automatically for the cases were userspace has to do something to
+implement brightness changes. When you override these events, you will
+either fail to handle properly the ThinkPads that require explicit
+action to change backlight brightness, or the ThinkPads that require
+that no action be taken to work properly.
Bluetooth
@@ -1465,3 +1436,5 @@ Sysfs interface changelog:
and it is always able to disable hot keys. Very old
thinkpads are properly supported. hotkey_bios_mask
is deprecated and marked for removal.
+
+0x020600: Marker for backlight change event support.
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c
index ba9373f82ab5..098de5bce00a 100644
--- a/Documentation/lguest/lguest.c
+++ b/Documentation/lguest/lguest.c
@@ -42,7 +42,6 @@
#include <signal.h>
#include "linux/lguest_launcher.h"
#include "linux/virtio_config.h"
-#include <linux/virtio_ids.h>
#include "linux/virtio_net.h"
#include "linux/virtio_blk.h"
#include "linux/virtio_console.h"
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index d5181ce9ff62..61f516b135b4 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -1,7 +1,7 @@
Linux Ethernet Bonding Driver HOWTO
- Latest update: 12 November 2007
+ Latest update: 23 September 2009
Initial release : Thomas Davis <tadavis at lbl.gov>
Corrections, HA extensions : 2000/10/03-15 :
@@ -614,6 +614,46 @@ primary
The primary option is only valid for active-backup mode.
+primary_reselect
+
+ Specifies the reselection policy for the primary slave. This
+ affects how the primary slave is chosen to become the active slave
+ when failure of the active slave or recovery of the primary slave
+ occurs. This option is designed to prevent flip-flopping between
+ the primary slave and other slaves. Possible values are:
+
+ always or 0 (default)
+
+ The primary slave becomes the active slave whenever it
+ comes back up.
+
+ better or 1
+
+ The primary slave becomes the active slave when it comes
+ back up, if the speed and duplex of the primary slave is
+ better than the speed and duplex of the current active
+ slave.
+
+ failure or 2
+
+ The primary slave becomes the active slave only if the
+ current active slave fails and the primary slave is up.
+
+ The primary_reselect setting is ignored in two cases:
+
+ If no slaves are active, the first slave to recover is
+ made the active slave.
+
+ When initially enslaved, the primary slave is always made
+ the active slave.
+
+ Changing the primary_reselect policy via sysfs will cause an
+ immediate selection of the best active slave according to the new
+ policy. This may or may not result in a change of the active
+ slave, depending upon the circumstances.
+
+ This option was added for bonding version 3.6.0.
+
updelay
Specifies the time, in milliseconds, to wait before enabling a
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index fbe427a6580c..a0e134dd2523 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -1086,6 +1086,24 @@ accept_dad - INTEGER
2: Enable DAD, and disable IPv6 operation if MAC-based duplicate
link-local address has been found.
+force_tllao - BOOLEAN
+ Enable sending the target link-layer address option even when
+ responding to a unicast neighbor solicitation.
+ Default: FALSE
+
+ Quoting from RFC 2461, section 4.4, Target link-layer address:
+
+ "The option MUST be included for multicast solicitations in order to
+ avoid infinite Neighbor Solicitation "recursion" when the peer node
+ does not have a cache entry to return a Neighbor Advertisements
+ message. When responding to unicast solicitations, the option can be
+ omitted since the sender of the solicitation has the correct link-
+ layer address; otherwise it would not have be able to send the unicast
+ solicitation in the first place. However, including the link-layer
+ address in this case adds little overhead and eliminates a potential
+ race condition where the sender deletes the cached link-layer address
+ prior to receiving a response to a previous solicitation."
+
icmp/*:
ratelimit - INTEGER
Limit the maximal rates for sending ICMPv6 packets.
diff --git a/Documentation/oops-tracing.txt b/Documentation/oops-tracing.txt
index b152e81da592..c10c022b911c 100644
--- a/Documentation/oops-tracing.txt
+++ b/Documentation/oops-tracing.txt
@@ -257,6 +257,8 @@ characters, each representing a particular tainted value.
10: 'W' if a warning has previously been issued by the kernel.
+ 11: 'C' if a staging driver has been loaded.
+
The primary reason for the 'Tainted: ' string is to tell kernel
debuggers if this is a clean kernel or if anything unusual has
occurred. Tainting is permanent: even if an offending module is
diff --git a/Documentation/pcmcia/driver-changes.txt b/Documentation/pcmcia/driver-changes.txt
index 059934363caf..adfb83e58675 100644
--- a/Documentation/pcmcia/driver-changes.txt
+++ b/Documentation/pcmcia/driver-changes.txt
@@ -1,5 +1,12 @@
This file details changes in 2.6 which affect PCMCIA card driver authors:
+* New CIS tuple access (as of 2.6.33)
+ Instead of pcmcia_get_{first,next}_tuple(), pcmcia_get_tuple_data() and
+ pcmcia_parse_tuple(), a driver shall use "pcmcia_get_tuple()" if it is
+ only interested in one (raw) tuple, or "pcmcia_loop_tuple()" if it is
+ interested in all tuples of one type. To decode the MAC from CISTPL_FUNCE,
+ a new helper "pcmcia_get_mac_from_cis()" was added.
+
* New configuration loop helper (as of 2.6.28)
By calling pcmcia_loop_config(), a driver can iterate over all available
configuration options. During a driver's probe() phase, one doesn't need
diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas
index c851ef497795..151a7b718b8c 100644
--- a/Documentation/scsi/ChangeLog.megaraid_sas
+++ b/Documentation/scsi/ChangeLog.megaraid_sas
@@ -1,3 +1,65 @@
+1 Release Date : Tues. July 28, 2009 10:12:45 PST 2009 -
+ (emaild-id:megaraidlinux@lsi.com)
+ Bo Yang
+
+2 Current Version : 00.00.04.12
+3 Older Version : 00.00.04.10
+
+1. Change the AEN sys PD update from scsi_scan to
+ scsi_add_device and scsi_remove_device.
+2. Takeoff the debug print-out in aen_polling routine.
+
+1 Release Date : Thur. July 02, 2009 10:12:45 PST 2009 -
+ (emaild-id:megaraidlinux@lsi.com)
+ Bo Yang
+
+2 Current Version : 00.00.04.10
+3 Older Version : 00.00.04.08
+
+1. Add the 3 mins timeout during the controller initialize.
+2. Add the fix for 64bit sense date errors.
+
+1 Release Date : Tues. May 05, 2009 10:12:45 PST 2009 -
+ (emaild-id:megaraidlinux@lsi.com)
+ Bo Yang
+
+2 Current Version : 00.00.04.08
+3 Older Version : 00.00.04.06
+
+1. Add the fix of pending in FW after deleted the logic drives.
+2. Add the fix of deallocating memory after get pdlist.
+
+1 Release Date : Tues. March 26, 2009 10:12:45 PST 2009 -
+ (emaild-id:megaraidlinux@lsi.com)
+ Bo Yang
+
+2 Current Version : 00.00.04.06
+3 Older Version : 00.00.04.04
+
+1. Add the fix of the driver cmd empty fix of the driver cmd empty.
+2. Add the fix of the driver MSM AEN CMD cause the system slow.
+
+1 Release Date : Tues. March 03, 2009 10:12:45 PST 2009 -
+ (emaild-id:megaraidlinux@lsi.com)
+ Bo Yang
+
+2 Current Version : 00.00.04.04
+3 Older Version : 00.00.04.01
+
+1. Add the Tape drive fix to the driver: If the command is for
+ the tape device, set the pthru timeout to the os layer timeout value.
+
+2. Add Poll_wait mechanism to Gen-2 Linux driv.
+ In the aen handler, driver needs to wakeup poll handler similar to
+ the way it raises SIGIO.
+
+3. Add new controller new SAS2 support to the driver.
+
+4. Report the unconfigured PD (system PD) to OS.
+
+5. Add the IEEE SGL support to the driver
+
+6. Reasign the Application cmds to SAS2 controller
1 Release Date : Thur.July. 24 11:41:51 PST 2008 -
(emaild-id:megaraidlinux@lsi.com)
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 1c8eb4518ce0..6de56d134abb 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -1631,7 +1631,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
Module snd-sscape
-----------------
- Module for ENSONIQ SoundScape PnP cards.
+ Module for ENSONIQ SoundScape cards.
port - Port # (PnP setup)
wss_port - WSS Port # (PnP setup)
@@ -1639,10 +1639,11 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
mpu_irq - MPU-401 IRQ # (PnP setup)
dma - DMA # (PnP setup)
dma2 - 2nd DMA # (PnP setup, -1 to disable)
+ joystick - Enable gameport - 0 = disable (default), 1 = enable
+
+ This module supports multiple cards.
- This module supports multiple cards. ISA PnP must be enabled.
- You need sscape_ctl tool in alsa-tools package for loading
- the microcode.
+ The driver requires the firmware loader support on kernel.
Module snd-sun-amd7930 (on sparc only)
--------------------------------------
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index a028b92001ed..8f7a0e73ef44 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -139,9 +139,9 @@ core_pattern is used to specify a core dumpfile pattern name.
core_pipe_limit:
This sysctl is only applicable when core_pattern is configured to pipe core
-files to user space helper a (when the first character of core_pattern is a '|',
+files to a user space helper (when the first character of core_pattern is a '|',
see above). When collecting cores via a pipe to an application, it is
-occasionally usefull for the collecting application to gather data about the
+occasionally useful for the collecting application to gather data about the
crashing process from its /proc/pid directory. In order to do this safely, the
kernel must wait for the collecting process to exit, so as not to remove the
crashing processes proc files prematurely. This in turn creates the possibility
@@ -152,7 +152,7 @@ applications in parallel. If this value is exceeded, then those crashing
processes above that value are noted via the kernel log and their cores are
skipped. 0 is a special value, indicating that unlimited processes may be
captured in parallel, but that no waiting will take place (i.e. the collecting
-process is not guaranteed access to /proc/<crahing pid>/). This value defaults
+process is not guaranteed access to /proc/<crashing pid>/). This value defaults
to 0.
==============================================================
diff --git a/Documentation/timers/hpet.txt b/Documentation/timers/hpet.txt
index 04763a325520..16d25e6b5a00 100644
--- a/Documentation/timers/hpet.txt
+++ b/Documentation/timers/hpet.txt
@@ -3,7 +3,7 @@
The High Precision Event Timer (HPET) hardware follows a specification
by Intel and Microsoft which can be found at
- http://www.intel.com/technology/architecture/hpetspec.htm
+ http://www.intel.com/hardwaredesign/hpetspec_1.pdf
Each HPET has one fixed-rate counter (at 10+ MHz, hence "High Precision")
and up to 32 comparators. Normally three or more comparators are provided,
diff --git a/Documentation/trace/ftrace-design.txt b/Documentation/trace/ftrace-design.txt
index 7003e10f10f5..641a1ef2a7ff 100644
--- a/Documentation/trace/ftrace-design.txt
+++ b/Documentation/trace/ftrace-design.txt
@@ -213,10 +213,19 @@ If you can't trace NMI functions, then skip this option.
<details to be filled>
-HAVE_FTRACE_SYSCALLS
+HAVE_SYSCALL_TRACEPOINTS
---------------------
-<details to be filled>
+You need very few things to get the syscalls tracing in an arch.
+
+- Have a NR_syscalls variable in <asm/unistd.h> that provides the number
+ of syscalls supported by the arch.
+- Implement arch_syscall_addr() that resolves a syscall address from a
+ syscall number.
+- Support the TIF_SYSCALL_TRACEPOINT thread flags
+- Put the trace_sys_enter() and trace_sys_exit() tracepoints calls from ptrace
+ in the ptrace syscalls tracing path.
+- Tag this arch as HAVE_SYSCALL_TRACEPOINTS.
HAVE_FTRACE_MCOUNT_RECORD
diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt
index 957b22fde2df..8179692fbb90 100644
--- a/Documentation/trace/ftrace.txt
+++ b/Documentation/trace/ftrace.txt
@@ -1231,6 +1231,7 @@ something like this simple program:
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
+#include <string.h>
#define _STR(x) #x
#define STR(x) _STR(x)
@@ -1265,6 +1266,7 @@ const char *find_debugfs(void)
return NULL;
}
+ strcat(debugfs, "/tracing/");
debugfs_found = 1;
return debugfs;
diff --git a/Documentation/trace/kprobetrace.txt b/Documentation/trace/kprobetrace.txt
new file mode 100644
index 000000000000..15415243a9a3
--- /dev/null
+++ b/Documentation/trace/kprobetrace.txt
@@ -0,0 +1,151 @@
+ Kprobe-based Event Tracer
+ =========================
+
+ Documentation is written by Masami Hiramatsu
+
+
+Overview
+--------
+This tracer is similar to the events tracer which is based on Tracepoint
+infrastructure. Instead of Tracepoint, this tracer is based on kprobes(kprobe
+and kretprobe). It probes anywhere where kprobes can probe(this means, all
+functions body except for __kprobes functions).
+
+Unlike the function tracer, this tracer can probe instructions inside of
+kernel functions. It allows you to check which instruction has been executed.
+
+Unlike the Tracepoint based events tracer, this tracer can add and remove
+probe points on the fly.
+
+Similar to the events tracer, this tracer doesn't need to be activated via
+current_tracer, instead of that, just set probe points via
+/sys/kernel/debug/tracing/kprobe_events. And you can set filters on each
+probe events via /sys/kernel/debug/tracing/events/kprobes/<EVENT>/filter.
+
+
+Synopsis of kprobe_events
+-------------------------
+ p[:[GRP/]EVENT] SYMBOL[+offs]|MEMADDR [FETCHARGS] : Set a probe
+ r[:[GRP/]EVENT] SYMBOL[+0] [FETCHARGS] : Set a return probe
+
+ GRP : Group name. If omitted, use "kprobes" for it.
+ EVENT : Event name. If omitted, the event name is generated
+ based on SYMBOL+offs or MEMADDR.
+ SYMBOL[+offs] : Symbol+offset where the probe is inserted.
+ MEMADDR : Address where the probe is inserted.
+
+ FETCHARGS : Arguments. Each probe can have up to 128 args.
+ %REG : Fetch register REG
+ @ADDR : Fetch memory at ADDR (ADDR should be in kernel)
+ @SYM[+|-offs] : Fetch memory at SYM +|- offs (SYM should be a data symbol)
+ $stackN : Fetch Nth entry of stack (N >= 0)
+ $stack : Fetch stack address.
+ $argN : Fetch function argument. (N >= 0)(*)
+ $retval : Fetch return value.(**)
+ +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(***)
+ NAME=FETCHARG: Set NAME as the argument name of FETCHARG.
+
+ (*) aN may not correct on asmlinkaged functions and at the middle of
+ function body.
+ (**) only for return probe.
+ (***) this is useful for fetching a field of data structures.
+
+
+Per-Probe Event Filtering
+-------------------------
+ Per-probe event filtering feature allows you to set different filter on each
+probe and gives you what arguments will be shown in trace buffer. If an event
+name is specified right after 'p:' or 'r:' in kprobe_events, the tracer adds
+an event under tracing/events/kprobes/<EVENT>, at the directory you can see
+'id', 'enabled', 'format' and 'filter'.
+
+enabled:
+ You can enable/disable the probe by writing 1 or 0 on it.
+
+format:
+ This shows the format of this probe event.
+
+filter:
+ You can write filtering rules of this event.
+
+id:
+ This shows the id of this probe event.
+
+Event Profiling
+---------------
+ You can check the total number of probe hits and probe miss-hits via
+/sys/kernel/debug/tracing/kprobe_profile.
+ The first column is event name, the second is the number of probe hits,
+the third is the number of probe miss-hits.
+
+
+Usage examples
+--------------
+To add a probe as a new event, write a new definition to kprobe_events
+as below.
+
+ echo p:myprobe do_sys_open dfd=$arg0 filename=$arg1 flags=$arg2 mode=$arg3 > /sys/kernel/debug/tracing/kprobe_events
+
+ This sets a kprobe on the top of do_sys_open() function with recording
+1st to 4th arguments as "myprobe" event. As this example shows, users can
+choose more familiar names for each arguments.
+
+ echo r:myretprobe do_sys_open $retval >> /sys/kernel/debug/tracing/kprobe_events
+
+ This sets a kretprobe on the return point of do_sys_open() function with
+recording return value as "myretprobe" event.
+ You can see the format of these events via
+/sys/kernel/debug/tracing/events/kprobes/<EVENT>/format.
+
+ cat /sys/kernel/debug/tracing/events/kprobes/myprobe/format
+name: myprobe
+ID: 75
+format:
+ field:unsigned short common_type; offset:0; size:2;
+ field:unsigned char common_flags; offset:2; size:1;
+ field:unsigned char common_preempt_count; offset:3; size:1;
+ field:int common_pid; offset:4; size:4;
+ field:int common_tgid; offset:8; size:4;
+
+ field: unsigned long ip; offset:16;tsize:8;
+ field: int nargs; offset:24;tsize:4;
+ field: unsigned long dfd; offset:32;tsize:8;
+ field: unsigned long filename; offset:40;tsize:8;
+ field: unsigned long flags; offset:48;tsize:8;
+ field: unsigned long mode; offset:56;tsize:8;
+
+print fmt: "(%lx) dfd=%lx filename=%lx flags=%lx mode=%lx", REC->ip, REC->dfd, REC->filename, REC->flags, REC->mode
+
+
+ You can see that the event has 4 arguments as in the expressions you specified.
+
+ echo > /sys/kernel/debug/tracing/kprobe_events
+
+ This clears all probe points.
+
+ Right after definition, each event is disabled by default. For tracing these
+events, you need to enable it.
+
+ echo 1 > /sys/kernel/debug/tracing/events/kprobes/myprobe/enable
+ echo 1 > /sys/kernel/debug/tracing/events/kprobes/myretprobe/enable
+
+ And you can see the traced information via /sys/kernel/debug/tracing/trace.
+
+ cat /sys/kernel/debug/tracing/trace
+# tracer: nop
+#
+# TASK-PID CPU# TIMESTAMP FUNCTION
+# | | | | |
+ <...>-1447 [001] 1038282.286875: myprobe: (do_sys_open+0x0/0xd6) dfd=3 filename=7fffd1ec4440 flags=8000 mode=0
+ <...>-1447 [001] 1038282.286878: myretprobe: (sys_openat+0xc/0xe <- do_sys_open) $retval=fffffffffffffffe
+ <...>-1447 [001] 1038282.286885: myprobe: (do_sys_open+0x0/0xd6) dfd=ffffff9c filename=40413c flags=8000 mode=1b6
+ <...>-1447 [001] 1038282.286915: myretprobe: (sys_open+0x1b/0x1d <- do_sys_open) $retval=3
+ <...>-1447 [001] 1038282.286969: myprobe: (do_sys_open+0x0/0xd6) dfd=ffffff9c filename=4041c6 flags=98800 mode=10
+ <...>-1447 [001] 1038282.286976: myretprobe: (sys_open+0x1b/0x1d <- do_sys_open) $retval=3
+
+
+ Each line shows when the kernel hits an event, and <- SYMBOL means kernel
+returns from SYMBOL(e.g. "sys_open+0x1b/0x1d <- do_sys_open" means kernel
+returns from do_sys_open to sys_open+0x1b).
+
+
diff --git a/Documentation/vm/slqbinfo.c b/Documentation/vm/slqbinfo.c
new file mode 100644
index 000000000000..3146d3d7c856
--- /dev/null
+++ b/Documentation/vm/slqbinfo.c
@@ -0,0 +1,1047 @@
+/*
+ * Slabinfo: Tool to get reports about slabs
+ *
+ * (C) 2007 sgi, Christoph Lameter
+ *
+ * Reworked by Lin Ming <ming.m.lin@intel.com> for SLQB
+ *
+ * Compile by:
+ *
+ * gcc -o slabinfo slabinfo.c
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <strings.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <getopt.h>
+#include <regex.h>
+#include <errno.h>
+
+#define MAX_SLABS 500
+#define MAX_ALIASES 500
+#define MAX_NODES 1024
+
+struct slabinfo {
+ char *name;
+ int align, cache_dma, destroy_by_rcu;
+ int hwcache_align, object_size, objs_per_slab;
+ int slab_size, store_user;
+ int order, poison, reclaim_account, red_zone;
+ int batch;
+ unsigned long objects, slabs, total_objects;
+ unsigned long alloc, alloc_slab_fill, alloc_slab_new;
+ unsigned long free, free_remote;
+ unsigned long claim_remote_list, claim_remote_list_objects;
+ unsigned long flush_free_list, flush_free_list_objects, flush_free_list_remote;
+ unsigned long flush_rfree_list, flush_rfree_list_objects;
+ unsigned long flush_slab_free, flush_slab_partial;
+ int numa[MAX_NODES];
+ int numa_partial[MAX_NODES];
+} slabinfo[MAX_SLABS];
+
+int slabs = 0;
+int actual_slabs = 0;
+int highest_node = 0;
+
+char buffer[4096];
+
+int show_empty = 0;
+int show_report = 0;
+int show_slab = 0;
+int skip_zero = 1;
+int show_numa = 0;
+int show_track = 0;
+int validate = 0;
+int shrink = 0;
+int show_inverted = 0;
+int show_totals = 0;
+int sort_size = 0;
+int sort_active = 0;
+int set_debug = 0;
+int show_ops = 0;
+int show_activity = 0;
+
+/* Debug options */
+int sanity = 0;
+int redzone = 0;
+int poison = 0;
+int tracking = 0;
+int tracing = 0;
+
+int page_size;
+
+regex_t pattern;
+
+void fatal(const char *x, ...)
+{
+ va_list ap;
+
+ va_start(ap, x);
+ vfprintf(stderr, x, ap);
+ va_end(ap);
+ exit(EXIT_FAILURE);
+}
+
+void usage(void)
+{
+ printf("slabinfo 5/7/2007. (c) 2007 sgi.\n\n"
+ "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
+ "-A|--activity Most active slabs first\n"
+ "-d<options>|--debug=<options> Set/Clear Debug options\n"
+ "-D|--display-active Switch line format to activity\n"
+ "-e|--empty Show empty slabs\n"
+ "-h|--help Show usage information\n"
+ "-i|--inverted Inverted list\n"
+ "-l|--slabs Show slabs\n"
+ "-n|--numa Show NUMA information\n"
+ "-o|--ops Show kmem_cache_ops\n"
+ "-s|--shrink Shrink slabs\n"
+ "-r|--report Detailed report on single slabs\n"
+ "-S|--Size Sort by size\n"
+ "-t|--tracking Show alloc/free information\n"
+ "-T|--Totals Show summary information\n"
+ "-v|--validate Validate slabs\n"
+ "-z|--zero Include empty slabs\n"
+ "\nValid debug options (FZPUT may be combined)\n"
+ "a / A Switch on all debug options (=FZUP)\n"
+ "- Switch off all debug options\n"
+ "f / F Sanity Checks (SLAB_DEBUG_FREE)\n"
+ "z / Z Redzoning\n"
+ "p / P Poisoning\n"
+ "u / U Tracking\n"
+ "t / T Tracing\n"
+ );
+}
+
+unsigned long read_obj(const char *name)
+{
+ FILE *f = fopen(name, "r");
+
+ if (!f)
+ buffer[0] = 0;
+ else {
+ if (!fgets(buffer, sizeof(buffer), f))
+ buffer[0] = 0;
+ fclose(f);
+ if (buffer[strlen(buffer)] == '\n')
+ buffer[strlen(buffer)] = 0;
+ }
+ return strlen(buffer);
+}
+
+
+/*
+ * Get the contents of an attribute
+ */
+unsigned long get_obj(const char *name)
+{
+ if (!read_obj(name))
+ return 0;
+
+ return atol(buffer);
+}
+
+unsigned long get_obj_and_str(const char *name, char **x)
+{
+ unsigned long result = 0;
+ char *p;
+
+ *x = NULL;
+
+ if (!read_obj(name)) {
+ x = NULL;
+ return 0;
+ }
+ result = strtoul(buffer, &p, 10);
+ while (*p == ' ')
+ p++;
+ if (*p)
+ *x = strdup(p);
+ return result;
+}
+
+void set_obj(struct slabinfo *s, const char *name, int n)
+{
+ char x[100];
+ FILE *f;
+
+ snprintf(x, 100, "%s/%s", s->name, name);
+ f = fopen(x, "w");
+ if (!f)
+ fatal("Cannot write to %s\n", x);
+
+ fprintf(f, "%d\n", n);
+ fclose(f);
+}
+
+unsigned long read_slab_obj(struct slabinfo *s, const char *name)
+{
+ char x[100];
+ FILE *f;
+ size_t l;
+
+ snprintf(x, 100, "%s/%s", s->name, name);
+ f = fopen(x, "r");
+ if (!f) {
+ buffer[0] = 0;
+ l = 0;
+ } else {
+ l = fread(buffer, 1, sizeof(buffer), f);
+ buffer[l] = 0;
+ fclose(f);
+ }
+ return l;
+}
+
+
+/*
+ * Put a size string together
+ */
+int store_size(char *buffer, unsigned long value)
+{
+ unsigned long divisor = 1;
+ char trailer = 0;
+ int n;
+
+ if (value > 1000000000UL) {
+ divisor = 100000000UL;
+ trailer = 'G';
+ } else if (value > 1000000UL) {
+ divisor = 100000UL;
+ trailer = 'M';
+ } else if (value > 1000UL) {
+ divisor = 100;
+ trailer = 'K';
+ }
+
+ value /= divisor;
+ n = sprintf(buffer, "%ld",value);
+ if (trailer) {
+ buffer[n] = trailer;
+ n++;
+ buffer[n] = 0;
+ }
+ if (divisor != 1) {
+ memmove(buffer + n - 2, buffer + n - 3, 4);
+ buffer[n-2] = '.';
+ n++;
+ }
+ return n;
+}
+
+void decode_numa_list(int *numa, char *t)
+{
+ int node;
+ int nr;
+
+ memset(numa, 0, MAX_NODES * sizeof(int));
+
+ if (!t)
+ return;
+
+ while (*t == 'N') {
+ t++;
+ node = strtoul(t, &t, 10);
+ if (*t == '=') {
+ t++;
+ nr = strtoul(t, &t, 10);
+ numa[node] = nr;
+ if (node > highest_node)
+ highest_node = node;
+ }
+ while (*t == ' ')
+ t++;
+ }
+}
+
+void slab_validate(struct slabinfo *s)
+{
+ if (strcmp(s->name, "*") == 0)
+ return;
+
+ set_obj(s, "validate", 1);
+}
+
+void slab_shrink(struct slabinfo *s)
+{
+ if (strcmp(s->name, "*") == 0)
+ return;
+
+ set_obj(s, "shrink", 1);
+}
+
+int line = 0;
+
+void first_line(void)
+{
+ if (show_activity)
+ printf("Name Objects Alloc Free %%Fill %%New "
+ "FlushR %%FlushR FlushR_Objs O\n");
+ else
+ printf("Name Objects Objsize Space "
+ " O/S O %%Ef Batch Flg\n");
+}
+
+unsigned long slab_size(struct slabinfo *s)
+{
+ return s->slabs * (page_size << s->order);
+}
+
+unsigned long slab_activity(struct slabinfo *s)
+{
+ return s->alloc + s->free;
+}
+
+void slab_numa(struct slabinfo *s, int mode)
+{
+ int node;
+
+ if (strcmp(s->name, "*") == 0)
+ return;
+
+ if (!highest_node) {
+ printf("\n%s: No NUMA information available.\n", s->name);
+ return;
+ }
+
+ if (skip_zero && !s->slabs)
+ return;
+
+ if (!line) {
+ printf("\n%-21s:", mode ? "NUMA nodes" : "Slab");
+ for(node = 0; node <= highest_node; node++)
+ printf(" %4d", node);
+ printf("\n----------------------");
+ for(node = 0; node <= highest_node; node++)
+ printf("-----");
+ printf("\n");
+ }
+ printf("%-21s ", mode ? "All slabs" : s->name);
+ for(node = 0; node <= highest_node; node++) {
+ char b[20];
+
+ store_size(b, s->numa[node]);
+ printf(" %4s", b);
+ }
+ printf("\n");
+ if (mode) {
+ printf("%-21s ", "Partial slabs");
+ for(node = 0; node <= highest_node; node++) {
+ char b[20];
+
+ store_size(b, s->numa_partial[node]);
+ printf(" %4s", b);
+ }
+ printf("\n");
+ }
+ line++;
+}
+
+void show_tracking(struct slabinfo *s)
+{
+ printf("\n%s: Kernel object allocation\n", s->name);
+ printf("-----------------------------------------------------------------------\n");
+ if (read_slab_obj(s, "alloc_calls"))
+ printf(buffer);
+ else
+ printf("No Data\n");
+
+ printf("\n%s: Kernel object freeing\n", s->name);
+ printf("------------------------------------------------------------------------\n");
+ if (read_slab_obj(s, "free_calls"))
+ printf(buffer);
+ else
+ printf("No Data\n");
+
+}
+
+void ops(struct slabinfo *s)
+{
+ if (strcmp(s->name, "*") == 0)
+ return;
+
+ if (read_slab_obj(s, "ops")) {
+ printf("\n%s: kmem_cache operations\n", s->name);
+ printf("--------------------------------------------\n");
+ printf(buffer);
+ } else
+ printf("\n%s has no kmem_cache operations\n", s->name);
+}
+
+const char *onoff(int x)
+{
+ if (x)
+ return "On ";
+ return "Off";
+}
+
+void slab_stats(struct slabinfo *s)
+{
+ unsigned long total_alloc;
+ unsigned long total_free;
+
+ total_alloc = s->alloc;
+ total_free = s->free;
+
+ if (!total_alloc)
+ return;
+
+ printf("\n");
+ printf("Slab Perf Counter\n");
+ printf("------------------------------------------------------------------------\n");
+ printf("Alloc: %8lu, partial %8lu, page allocator %8lu\n",
+ total_alloc,
+ s->alloc_slab_fill, s->alloc_slab_new);
+ printf("Free: %8lu, partial %8lu, page allocator %8lu, remote %5lu\n",
+ total_free,
+ s->flush_slab_partial,
+ s->flush_slab_free,
+ s->free_remote);
+ printf("Claim: %8lu, objects %8lu\n",
+ s->claim_remote_list,
+ s->claim_remote_list_objects);
+ printf("Flush: %8lu, objects %8lu, remote: %8lu\n",
+ s->flush_free_list,
+ s->flush_free_list_objects,
+ s->flush_free_list_remote);
+ printf("FlushR:%8lu, objects %8lu\n",
+ s->flush_rfree_list,
+ s->flush_rfree_list_objects);
+}
+
+void report(struct slabinfo *s)
+{
+ if (strcmp(s->name, "*") == 0)
+ return;
+
+ printf("\nSlabcache: %-20s Order : %2d Objects: %lu\n",
+ s->name, s->order, s->objects);
+ if (s->hwcache_align)
+ printf("** Hardware cacheline aligned\n");
+ if (s->cache_dma)
+ printf("** Memory is allocated in a special DMA zone\n");
+ if (s->destroy_by_rcu)
+ printf("** Slabs are destroyed via RCU\n");
+ if (s->reclaim_account)
+ printf("** Reclaim accounting active\n");
+
+ printf("\nSizes (bytes) Slabs Debug Memory\n");
+ printf("------------------------------------------------------------------------\n");
+ printf("Object : %7d Total : %7ld Sanity Checks : %s Total: %7ld\n",
+ s->object_size, s->slabs, "N/A",
+ s->slabs * (page_size << s->order));
+ printf("SlabObj: %7d Full : %7s Redzoning : %s Used : %7ld\n",
+ s->slab_size, "N/A",
+ onoff(s->red_zone), s->objects * s->object_size);
+ printf("SlabSiz: %7d Partial: %7s Poisoning : %s Loss : %7ld\n",
+ page_size << s->order, "N/A", onoff(s->poison),
+ s->slabs * (page_size << s->order) - s->objects * s->object_size);
+ printf("Loss : %7d CpuSlab: %7s Tracking : %s Lalig: %7ld\n",
+ s->slab_size - s->object_size, "N/A", onoff(s->store_user),
+ (s->slab_size - s->object_size) * s->objects);
+ printf("Align : %7d Objects: %7d Tracing : %s Lpadd: %7ld\n",
+ s->align, s->objs_per_slab, "N/A",
+ ((page_size << s->order) - s->objs_per_slab * s->slab_size) *
+ s->slabs);
+
+ ops(s);
+ show_tracking(s);
+ slab_numa(s, 1);
+ slab_stats(s);
+}
+
+void slabcache(struct slabinfo *s)
+{
+ char size_str[20];
+ char flags[20];
+ char *p = flags;
+
+ if (strcmp(s->name, "*") == 0)
+ return;
+
+ if (actual_slabs == 1) {
+ report(s);
+ return;
+ }
+
+ if (skip_zero && !show_empty && !s->slabs)
+ return;
+
+ if (show_empty && s->slabs)
+ return;
+
+ store_size(size_str, slab_size(s));
+
+ if (!line++)
+ first_line();
+
+ if (s->cache_dma)
+ *p++ = 'd';
+ if (s->hwcache_align)
+ *p++ = 'A';
+ if (s->poison)
+ *p++ = 'P';
+ if (s->reclaim_account)
+ *p++ = 'a';
+ if (s->red_zone)
+ *p++ = 'Z';
+ if (s->store_user)
+ *p++ = 'U';
+
+ *p = 0;
+ if (show_activity) {
+ unsigned long total_alloc;
+ unsigned long total_free;
+
+ total_alloc = s->alloc;
+ total_free = s->free;
+
+ printf("%-21s %8ld %10ld %10ld %5ld %5ld %7ld %5ld %7ld %8d\n",
+ s->name, s->objects,
+ total_alloc, total_free,
+ total_alloc ? (s->alloc_slab_fill * 100 / total_alloc) : 0,
+ total_alloc ? (s->alloc_slab_new * 100 / total_alloc) : 0,
+ s->flush_rfree_list,
+ s->flush_rfree_list * 100 / (total_alloc + total_free),
+ s->flush_rfree_list_objects,
+ s->order);
+ }
+ else
+ printf("%-21s %8ld %7d %8s %4d %1d %3ld %4d %s\n",
+ s->name, s->objects, s->object_size, size_str,
+ s->objs_per_slab, s->order,
+ s->slabs ? (s->objects * s->object_size * 100) /
+ (s->slabs * (page_size << s->order)) : 100,
+ s->batch, flags);
+}
+
+/*
+ * Analyze debug options. Return false if something is amiss.
+ */
+int debug_opt_scan(char *opt)
+{
+ if (!opt || !opt[0] || strcmp(opt, "-") == 0)
+ return 1;
+
+ if (strcasecmp(opt, "a") == 0) {
+ sanity = 1;
+ poison = 1;
+ redzone = 1;
+ tracking = 1;
+ return 1;
+ }
+
+ for ( ; *opt; opt++)
+ switch (*opt) {
+ case 'F' : case 'f':
+ if (sanity)
+ return 0;
+ sanity = 1;
+ break;
+ case 'P' : case 'p':
+ if (poison)
+ return 0;
+ poison = 1;
+ break;
+
+ case 'Z' : case 'z':
+ if (redzone)
+ return 0;
+ redzone = 1;
+ break;
+
+ case 'U' : case 'u':
+ if (tracking)
+ return 0;
+ tracking = 1;
+ break;
+
+ case 'T' : case 't':
+ if (tracing)
+ return 0;
+ tracing = 1;
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+int slab_empty(struct slabinfo *s)
+{
+ if (s->objects > 0)
+ return 0;
+
+ /*
+ * We may still have slabs even if there are no objects. Shrinking will
+ * remove them.
+ */
+ if (s->slabs != 0)
+ set_obj(s, "shrink", 1);
+
+ return 1;
+}
+
+void slab_debug(struct slabinfo *s)
+{
+ if (strcmp(s->name, "*") == 0)
+ return;
+
+ if (redzone && !s->red_zone) {
+ if (slab_empty(s))
+ set_obj(s, "red_zone", 1);
+ else
+ fprintf(stderr, "%s not empty cannot enable redzoning\n", s->name);
+ }
+ if (!redzone && s->red_zone) {
+ if (slab_empty(s))
+ set_obj(s, "red_zone", 0);
+ else
+ fprintf(stderr, "%s not empty cannot disable redzoning\n", s->name);
+ }
+ if (poison && !s->poison) {
+ if (slab_empty(s))
+ set_obj(s, "poison", 1);
+ else
+ fprintf(stderr, "%s not empty cannot enable poisoning\n", s->name);
+ }
+ if (!poison && s->poison) {
+ if (slab_empty(s))
+ set_obj(s, "poison", 0);
+ else
+ fprintf(stderr, "%s not empty cannot disable poisoning\n", s->name);
+ }
+ if (tracking && !s->store_user) {
+ if (slab_empty(s))
+ set_obj(s, "store_user", 1);
+ else
+ fprintf(stderr, "%s not empty cannot enable tracking\n", s->name);
+ }
+ if (!tracking && s->store_user) {
+ if (slab_empty(s))
+ set_obj(s, "store_user", 0);
+ else
+ fprintf(stderr, "%s not empty cannot disable tracking\n", s->name);
+ }
+}
+
+void totals(void)
+{
+ struct slabinfo *s;
+
+ int used_slabs = 0;
+ char b1[20], b2[20], b3[20], b4[20];
+ unsigned long long max = 1ULL << 63;
+
+ /* Object size */
+ unsigned long long min_objsize = max, max_objsize = 0, avg_objsize;
+
+ /* Number of slabs in a slab cache */
+ unsigned long long min_slabs = max, max_slabs = 0,
+ avg_slabs, total_slabs = 0;
+
+ /* Size of the whole slab */
+ unsigned long long min_size = max, max_size = 0,
+ avg_size, total_size = 0;
+
+ /* Bytes used for object storage in a slab */
+ unsigned long long min_used = max, max_used = 0,
+ avg_used, total_used = 0;
+
+ /* Waste: Bytes used for alignment and padding */
+ unsigned long long min_waste = max, max_waste = 0,
+ avg_waste, total_waste = 0;
+ /* Number of objects in a slab */
+ unsigned long long min_objects = max, max_objects = 0,
+ avg_objects, total_objects = 0;
+ /* Waste per object */
+ unsigned long long min_objwaste = max,
+ max_objwaste = 0, avg_objwaste,
+ total_objwaste = 0;
+
+ /* Memory per object */
+ unsigned long long min_memobj = max,
+ max_memobj = 0, avg_memobj,
+ total_objsize = 0;
+
+ for (s = slabinfo; s < slabinfo + slabs; s++) {
+ unsigned long long size;
+ unsigned long used;
+ unsigned long long wasted;
+ unsigned long long objwaste;
+
+ if (!s->slabs || !s->objects)
+ continue;
+
+ used_slabs++;
+
+ size = slab_size(s);
+ used = s->objects * s->object_size;
+ wasted = size - used;
+ objwaste = s->slab_size - s->object_size;
+
+ if (s->object_size < min_objsize)
+ min_objsize = s->object_size;
+ if (s->slabs < min_slabs)
+ min_slabs = s->slabs;
+ if (size < min_size)
+ min_size = size;
+ if (wasted < min_waste)
+ min_waste = wasted;
+ if (objwaste < min_objwaste)
+ min_objwaste = objwaste;
+ if (s->objects < min_objects)
+ min_objects = s->objects;
+ if (used < min_used)
+ min_used = used;
+ if (s->slab_size < min_memobj)
+ min_memobj = s->slab_size;
+
+ if (s->object_size > max_objsize)
+ max_objsize = s->object_size;
+ if (s->slabs > max_slabs)
+ max_slabs = s->slabs;
+ if (size > max_size)
+ max_size = size;
+ if (wasted > max_waste)
+ max_waste = wasted;
+ if (objwaste > max_objwaste)
+ max_objwaste = objwaste;
+ if (s->objects > max_objects)
+ max_objects = s->objects;
+ if (used > max_used)
+ max_used = used;
+ if (s->slab_size > max_memobj)
+ max_memobj = s->slab_size;
+
+ total_slabs += s->slabs;
+ total_size += size;
+ total_waste += wasted;
+
+ total_objects += s->objects;
+ total_used += used;
+
+ total_objwaste += s->objects * objwaste;
+ total_objsize += s->objects * s->slab_size;
+ }
+
+ if (!total_objects) {
+ printf("No objects\n");
+ return;
+ }
+ if (!used_slabs) {
+ printf("No slabs\n");
+ return;
+ }
+
+ /* Per slab averages */
+ avg_slabs = total_slabs / used_slabs;
+ avg_size = total_size / used_slabs;
+ avg_waste = total_waste / used_slabs;
+
+ avg_objects = total_objects / used_slabs;
+ avg_used = total_used / used_slabs;
+
+ /* Per object object sizes */
+ avg_objsize = total_used / total_objects;
+ avg_objwaste = total_objwaste / total_objects;
+ avg_memobj = total_objsize / total_objects;
+
+ printf("Slabcache Totals\n");
+ printf("----------------\n");
+ printf("Slabcaches : %3d Active: %3d\n",
+ slabs, used_slabs);
+
+ store_size(b1, total_size);store_size(b2, total_waste);
+ store_size(b3, total_waste * 100 / total_used);
+ printf("Memory used: %6s # Loss : %6s MRatio:%6s%%\n", b1, b2, b3);
+
+ store_size(b1, total_objects);
+ printf("# Objects : %6s\n", b1);
+
+ printf("\n");
+ printf("Per Cache Average Min Max Total\n");
+ printf("---------------------------------------------------------\n");
+
+ store_size(b1, avg_objects);store_size(b2, min_objects);
+ store_size(b3, max_objects);store_size(b4, total_objects);
+ printf("#Objects %10s %10s %10s %10s\n",
+ b1, b2, b3, b4);
+
+ store_size(b1, avg_slabs);store_size(b2, min_slabs);
+ store_size(b3, max_slabs);store_size(b4, total_slabs);
+ printf("#Slabs %10s %10s %10s %10s\n",
+ b1, b2, b3, b4);
+
+ store_size(b1, avg_size);store_size(b2, min_size);
+ store_size(b3, max_size);store_size(b4, total_size);
+ printf("Memory %10s %10s %10s %10s\n",
+ b1, b2, b3, b4);
+
+ store_size(b1, avg_used);store_size(b2, min_used);
+ store_size(b3, max_used);store_size(b4, total_used);
+ printf("Used %10s %10s %10s %10s\n",
+ b1, b2, b3, b4);
+
+ store_size(b1, avg_waste);store_size(b2, min_waste);
+ store_size(b3, max_waste);store_size(b4, total_waste);
+ printf("Loss %10s %10s %10s %10s\n",
+ b1, b2, b3, b4);
+
+ printf("\n");
+ printf("Per Object Average Min Max\n");
+ printf("---------------------------------------------\n");
+
+ store_size(b1, avg_memobj);store_size(b2, min_memobj);
+ store_size(b3, max_memobj);
+ printf("Memory %10s %10s %10s\n",
+ b1, b2, b3);
+ store_size(b1, avg_objsize);store_size(b2, min_objsize);
+ store_size(b3, max_objsize);
+ printf("User %10s %10s %10s\n",
+ b1, b2, b3);
+
+ store_size(b1, avg_objwaste);store_size(b2, min_objwaste);
+ store_size(b3, max_objwaste);
+ printf("Loss %10s %10s %10s\n",
+ b1, b2, b3);
+}
+
+void sort_slabs(void)
+{
+ struct slabinfo *s1,*s2;
+
+ for (s1 = slabinfo; s1 < slabinfo + slabs; s1++) {
+ for (s2 = s1 + 1; s2 < slabinfo + slabs; s2++) {
+ int result;
+
+ if (sort_size)
+ result = slab_size(s1) < slab_size(s2);
+ else if (sort_active)
+ result = slab_activity(s1) < slab_activity(s2);
+ else
+ result = strcasecmp(s1->name, s2->name);
+
+ if (show_inverted)
+ result = -result;
+
+ if (result > 0) {
+ struct slabinfo t;
+
+ memcpy(&t, s1, sizeof(struct slabinfo));
+ memcpy(s1, s2, sizeof(struct slabinfo));
+ memcpy(s2, &t, sizeof(struct slabinfo));
+ }
+ }
+ }
+}
+
+int slab_mismatch(char *slab)
+{
+ return regexec(&pattern, slab, 0, NULL, 0);
+}
+
+void read_slab_dir(void)
+{
+ DIR *dir;
+ struct dirent *de;
+ struct slabinfo *slab = slabinfo;
+ char *t;
+
+ if (chdir("/sys/kernel/slab") && chdir("/sys/slab"))
+ fatal("SYSFS support for SLUB not active\n");
+
+ dir = opendir(".");
+ while ((de = readdir(dir))) {
+ if (de->d_name[0] == '.' ||
+ (de->d_name[0] != ':' && slab_mismatch(de->d_name)))
+ continue;
+ switch (de->d_type) {
+ case DT_DIR:
+ if (chdir(de->d_name))
+ fatal("Unable to access slab %s\n", slab->name);
+ slab->name = strdup(de->d_name);
+ slab->align = get_obj("align");
+ slab->cache_dma = get_obj("cache_dma");
+ slab->destroy_by_rcu = get_obj("destroy_by_rcu");
+ slab->hwcache_align = get_obj("hwcache_align");
+ slab->object_size = get_obj("object_size");
+ slab->objects = get_obj("objects");
+ slab->total_objects = get_obj("total_objects");
+ slab->objs_per_slab = get_obj("objs_per_slab");
+ slab->order = get_obj("order");
+ slab->poison = get_obj("poison");
+ slab->reclaim_account = get_obj("reclaim_account");
+ slab->red_zone = get_obj("red_zone");
+ slab->slab_size = get_obj("slab_size");
+ slab->slabs = get_obj_and_str("slabs", &t);
+ decode_numa_list(slab->numa, t);
+ free(t);
+ slab->store_user = get_obj("store_user");
+ slab->batch = get_obj("batch");
+ slab->alloc = get_obj("alloc");
+ slab->alloc_slab_fill = get_obj("alloc_slab_fill");
+ slab->alloc_slab_new = get_obj("alloc_slab_new");
+ slab->free = get_obj("free");
+ slab->free_remote = get_obj("free_remote");
+ slab->claim_remote_list = get_obj("claim_remote_list");
+ slab->claim_remote_list_objects = get_obj("claim_remote_list_objects");
+ slab->flush_free_list = get_obj("flush_free_list");
+ slab->flush_free_list_objects = get_obj("flush_free_list_objects");
+ slab->flush_free_list_remote = get_obj("flush_free_list_remote");
+ slab->flush_rfree_list = get_obj("flush_rfree_list");
+ slab->flush_rfree_list_objects = get_obj("flush_rfree_list_objects");
+ slab->flush_slab_free = get_obj("flush_slab_free");
+ slab->flush_slab_partial = get_obj("flush_slab_partial");
+
+ chdir("..");
+ slab++;
+ break;
+ default :
+ fatal("Unknown file type %lx\n", de->d_type);
+ }
+ }
+ closedir(dir);
+ slabs = slab - slabinfo;
+ actual_slabs = slabs;
+ if (slabs > MAX_SLABS)
+ fatal("Too many slabs\n");
+}
+
+void output_slabs(void)
+{
+ struct slabinfo *slab;
+
+ for (slab = slabinfo; slab < slabinfo + slabs; slab++) {
+
+ if (show_numa)
+ slab_numa(slab, 0);
+ else if (show_track)
+ show_tracking(slab);
+ else if (validate)
+ slab_validate(slab);
+ else if (shrink)
+ slab_shrink(slab);
+ else if (set_debug)
+ slab_debug(slab);
+ else if (show_ops)
+ ops(slab);
+ else if (show_slab)
+ slabcache(slab);
+ else if (show_report)
+ report(slab);
+ }
+}
+
+struct option opts[] = {
+ { "activity", 0, NULL, 'A' },
+ { "debug", 2, NULL, 'd' },
+ { "display-activity", 0, NULL, 'D' },
+ { "empty", 0, NULL, 'e' },
+ { "help", 0, NULL, 'h' },
+ { "inverted", 0, NULL, 'i'},
+ { "numa", 0, NULL, 'n' },
+ { "ops", 0, NULL, 'o' },
+ { "report", 0, NULL, 'r' },
+ { "shrink", 0, NULL, 's' },
+ { "slabs", 0, NULL, 'l' },
+ { "track", 0, NULL, 't'},
+ { "validate", 0, NULL, 'v' },
+ { "zero", 0, NULL, 'z' },
+ { "1ref", 0, NULL, '1'},
+ { NULL, 0, NULL, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ int c;
+ int err;
+ char *pattern_source;
+
+ page_size = getpagesize();
+
+ while ((c = getopt_long(argc, argv, "Ad::Dehil1noprstvzTS",
+ opts, NULL)) != -1)
+ switch (c) {
+ case 'A':
+ sort_active = 1;
+ break;
+ case 'd':
+ set_debug = 1;
+ if (!debug_opt_scan(optarg))
+ fatal("Invalid debug option '%s'\n", optarg);
+ break;
+ case 'D':
+ show_activity = 1;
+ break;
+ case 'e':
+ show_empty = 1;
+ break;
+ case 'h':
+ usage();
+ return 0;
+ case 'i':
+ show_inverted = 1;
+ break;
+ case 'n':
+ show_numa = 1;
+ break;
+ case 'o':
+ show_ops = 1;
+ break;
+ case 'r':
+ show_report = 1;
+ break;
+ case 's':
+ shrink = 1;
+ break;
+ case 'l':
+ show_slab = 1;
+ break;
+ case 't':
+ show_track = 1;
+ break;
+ case 'v':
+ validate = 1;
+ break;
+ case 'z':
+ skip_zero = 0;
+ break;
+ case 'T':
+ show_totals = 1;
+ break;
+ case 'S':
+ sort_size = 1;
+ break;
+
+ default:
+ fatal("%s: Invalid option '%c'\n", argv[0], optopt);
+
+ }
+
+ if (!show_slab && !show_track && !show_report
+ && !validate && !shrink && !set_debug && !show_ops)
+ show_slab = 1;
+
+ if (argc > optind)
+ pattern_source = argv[optind];
+ else
+ pattern_source = ".*";
+
+ err = regcomp(&pattern, pattern_source, REG_ICASE|REG_NOSUB);
+ if (err)
+ fatal("%s: Invalid pattern '%s' code %d\n",
+ argv[0], pattern_source, err);
+ read_slab_dir();
+ if (show_totals)
+ totals();
+ else {
+ sort_slabs();
+ output_slabs();
+ }
+ return 0;
+}
diff --git a/Kbuild b/Kbuild
index f056b4feee51..e3737ad72b5a 100644
--- a/Kbuild
+++ b/Kbuild
@@ -8,7 +8,7 @@
#####
# 1) Generate bounds.h
-bounds-file := include/linux/bounds.h
+bounds-file := include/generated/bounds.h
always := $(bounds-file)
targets := $(bounds-file) kernel/bounds.s
@@ -43,7 +43,7 @@ $(obj)/$(bounds-file): kernel/bounds.s Kbuild
# 2) Generate asm-offsets.h
#
-offsets-file := include/asm/asm-offsets.h
+offsets-file := include/generated/asm-offsets.h
always += $(offsets-file)
targets += $(offsets-file)
diff --git a/MAINTAINERS b/MAINTAINERS
index 88241154f4ce..61c75ff1ef71 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1091,7 +1091,6 @@ F: include/net/ax25.h
F: net/ax25/
B43 WIRELESS DRIVER
-M: Michael Buesch <mb@bu3sch.de>
M: Stefano Brivio <stefano.brivio@polimi.it>
L: linux-wireless@vger.kernel.org
W: http://linuxwireless.org/en/users/Drivers/b43
@@ -1326,6 +1325,15 @@ F: arch/powerpc/include/asm/spu*.h
F: arch/powerpc/oprofile/*cell*
F: arch/powerpc/platforms/cell/
+CEPH DISTRIBUTED FILE SYSTEM CLIENT
+M: Sage Weil <sage@newdream.net>
+L: ceph-devel@lists.sourceforge.net
+W: http://ceph.newdream.net/
+T: git git://ceph.newdream.net/linux-ceph-client.git
+S: Supported
+F: Documentation/filesystems/ceph.txt
+F: fs/ceph
+
CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM:
M: David Vrabel <david.vrabel@csr.com>
L: linux-usb@vger.kernel.org
@@ -1480,6 +1488,7 @@ F: mm/*cgroup*
CORETEMP HARDWARE MONITORING DRIVER
M: Rudolf Marek <r.marek@assembler.cz>
+M: Huaxu Wan <huaxu.wan@intel.com>
L: lm-sensors@lm-sensors.org
S: Maintained
F: Documentation/hwmon/coretemp
@@ -1790,6 +1799,19 @@ S: Maintained
F: drivers/scsi/dpt*
F: drivers/scsi/dpt/
+DRBD DRIVER
+P: Philipp Reisner
+P: Lars Ellenberg
+M: drbd-dev@lists.linbit.com
+L: drbd-user@lists.linbit.com
+W: http://www.drbd.org
+T: git git://git.drbd.org/linux-2.6-drbd.git drbd
+T: git git://git.drbd.org/drbd-8.3.git
+S: Supported
+F: drivers/block/drbd/
+F: lib/lru_cache.c
+F: Documentation/blockdev/drbd/
+
DRIVER CORE, KOBJECTS, AND SYSFS
M: Greg Kroah-Hartman <gregkh@suse.de>
T: quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
@@ -2306,6 +2328,15 @@ W: http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/
S: Maintained
F: drivers/hwmon/hdaps.c
+HARDWARE LATENCY DETECTOR
+P: Jon Masters
+M: jcm@jonmasters.org
+W: http://www.kernel.org/pub/linux/kernel/people/jcm/hwlat_detector/
+S: Supported
+L: linux-kernel@vger.kernel.org
+F: Documentation/hwlat_detector.txt
+F: drivers/misc/hwlat_detector.c
+
HYPERVISOR VIRTUAL CONSOLE DRIVER
L: linuxppc-dev@ozlabs.org
S: Odd Fixes
@@ -2807,6 +2838,12 @@ L: linux-mips@linux-mips.org
S: Maintained
F: drivers/serial/ioc3_serial.c
+IOQ LIBRARY
+M: Gregory Haskins <ghaskins@novell.com>
+S: Maintained
+F: include/linux/ioq.h
+F: lib/ioq.c
+
IP MASQUERADING
M: Juanjo Ciarlante <jjciarla@raiz.uncu.edu.ar>
S: Maintained
@@ -4325,7 +4362,7 @@ F: drivers/video/aty/aty128fb.c
RALINK RT2X00 WIRELESS LAN DRIVER
P: rt2x00 project
L: linux-wireless@vger.kernel.org
-L: users@rt2x00.serialmonkey.com
+L: users@rt2x00.serialmonkey.com (moderated for non-subscribers)
W: http://rt2x00.serialmonkey.com/
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/ivd/rt2x00.git
@@ -4727,6 +4764,12 @@ F: drivers/serial/serial_lh7a40x.c
F: drivers/usb/gadget/lh7a40*
F: drivers/usb/host/ohci-lh7a40*
+SHM-SIGNAL LIBRARY
+M: Gregory Haskins <ghaskins@novell.com>
+S: Maintained
+F: include/linux/shm_signal.h
+F: lib/shm_signal.c
+
SIMPLE FIRMWARE INTERFACE (SFI)
P: Len Brown
M: lenb@kernel.org
@@ -5613,6 +5656,19 @@ S: Maintained
F: Documentation/fb/uvesafb.txt
F: drivers/video/uvesafb.*
+VBUS
+M: Gregory Haskins <ghaskins@novell.com>
+S: Maintained
+F: include/linux/vbus*
+F: drivers/vbus/*
+
+VBUS ETHERNET DRIVER
+M: Gregory Haskins <ghaskins@novell.com>
+S: Maintained
+W: http://developer.novell.com/wiki/index.php/AlacrityVM
+F: include/linux/venet.h
+F: drivers/net/vbus-enet.c
+
VFAT/FAT/MSDOS FILESYSTEM
M: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
S: Maintained
diff --git a/Makefile b/Makefile
index 9425d1de54c7..3ee1c81606ce 100644
--- a/Makefile
+++ b/Makefile
@@ -334,10 +334,9 @@ CFLAGS_GCOV = -fprofile-arcs -ftest-coverage
# Use LINUXINCLUDE when you must reference the include/ directory.
# Needed to be compatible with the O= option
-LINUXINCLUDE := -Iinclude \
- $(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) \
- -I$(srctree)/arch/$(hdr-arch)/include \
- -include include/linux/autoconf.h
+LINUXINCLUDE := -I$(srctree)/arch/$(hdr-arch)/include -Iinclude \
+ $(if $(KBUILD_SRC), -I$(srctree)/include) \
+ -include include/generated/autoconf.h
KBUILD_CPPFLAGS := -D__KERNEL__
@@ -492,17 +491,18 @@ $(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;
# if auto.conf.cmd is missing then we are probably in a cleaned tree so
# we execute the config step to be sure to catch updated Kconfig files
include/config/auto.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
+ $(Q)mkdir -p include/generated
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
else
-# external modules needs include/linux/autoconf.h and include/config/auto.conf
+# external modules needs include/generated/autoconf.h and include/config/auto.conf
# but do not care if they are up-to-date. Use auto.conf to trigger the test
PHONY += include/config/auto.conf
include/config/auto.conf:
- $(Q)test -e include/linux/autoconf.h -a -e $@ || ( \
+ $(Q)test -e include/generated/autoconf.h -a -e $@ || ( \
echo; \
echo " ERROR: Kernel configuration is invalid."; \
- echo " include/linux/autoconf.h or $@ are missing."; \
+ echo " include/generated/autoconf.h or $@ are missing.";\
echo " Run 'make oldconfig && make prepare' on kernel src to fix it."; \
echo; \
/bin/false)
@@ -954,7 +954,6 @@ PHONY += prepare archprepare prepare0 prepare1 prepare2 prepare3
# prepare3 is used to check if we are building in a separate output directory,
# and if so do:
# 1) Check that make has not been executed in the kernel src $(srctree)
-# 2) Create the include2 directory, used for the second asm symlink
prepare3: include/config/kernel.release
ifneq ($(KBUILD_SRC),)
@$(kecho) ' Using $(srctree) as source for kernel'
@@ -963,17 +962,13 @@ ifneq ($(KBUILD_SRC),)
echo " in the '$(srctree)' directory.";\
/bin/false; \
fi;
- $(Q)if [ ! -d include2 ]; then \
- mkdir -p include2; \
- ln -fsn $(srctree)/include/asm-$(SRCARCH) include2/asm; \
- fi
endif
# prepare2 creates a makefile if using a separate output directory
prepare2: prepare3 outputmakefile
-prepare1: prepare2 include/linux/version.h include/linux/utsrelease.h \
- include/asm include/config/auto.conf
+prepare1: prepare2 include/linux/version.h include/generated/utsrelease.h \
+ include/config/auto.conf
$(cmd_crmodverdir)
archprepare: prepare1 scripts_basic
@@ -985,42 +980,6 @@ prepare0: archprepare FORCE
# All the preparing..
prepare: prepare0
-# The asm symlink changes when $(ARCH) changes.
-# Detect this and ask user to run make mrproper
-# If asm is a stale symlink (point to dir that does not exist) remove it
-define check-symlink
- set -e; \
- if [ -L include/asm ]; then \
- asmlink=`readlink include/asm | cut -d '-' -f 2`; \
- if [ "$$asmlink" != "$(SRCARCH)" ]; then \
- echo "ERROR: the symlink $@ points to asm-$$asmlink but asm-$(SRCARCH) was expected"; \
- echo " set ARCH or save .config and run 'make mrproper' to fix it"; \
- exit 1; \
- fi; \
- test -e $$asmlink || rm include/asm; \
- elif [ -d include/asm ]; then \
- echo "ERROR: $@ is a directory but a symlink was expected";\
- exit 1; \
- fi
-endef
-
-# We create the target directory of the symlink if it does
-# not exist so the test in check-symlink works and we have a
-# directory for generated filesas used by some architectures.
-define create-symlink
- if [ ! -L include/asm ]; then \
- $(kecho) ' SYMLINK $@ -> include/asm-$(SRCARCH)'; \
- if [ ! -d include/asm-$(SRCARCH) ]; then \
- mkdir -p include/asm-$(SRCARCH); \
- fi; \
- ln -fsn asm-$(SRCARCH) $@; \
- fi
-endef
-
-include/asm: FORCE
- $(Q)$(check-symlink)
- $(Q)$(create-symlink)
-
# Generate some files
# ---------------------------------------------------------------------------
@@ -1045,7 +1004,7 @@ endef
include/linux/version.h: $(srctree)/Makefile FORCE
$(call filechk,version.h)
-include/linux/utsrelease.h: include/config/kernel.release FORCE
+include/generated/utsrelease.h: include/config/kernel.release FORCE
$(call filechk,utsrelease.h)
PHONY += headerdep
@@ -1075,11 +1034,6 @@ firmware_install: FORCE
export INSTALL_HDR_PATH = $(objtree)/usr
hdr-inst := -rR -f $(srctree)/scripts/Makefile.headersinst obj
-# Find out where the Kbuild file is located to support
-# arch/$(ARCH)/include/asm
-hdr-dir = $(strip \
- $(if $(wildcard $(srctree)/arch/$(hdr-arch)/include/asm/Kbuild), \
- arch/$(hdr-arch)/include/asm, include/asm-$(hdr-arch)))
# If we do an all arch process set dst to asm-$(hdr-arch)
hdr-dst = $(if $(KBUILD_HEADERS), dst=include/asm-$(hdr-arch), dst=include/asm)
@@ -1094,10 +1048,10 @@ headers_install_all:
PHONY += headers_install
headers_install: __headers
- $(if $(wildcard $(srctree)/$(hdr-dir)/Kbuild),, \
+ $(if $(wildcard $(srctree)/arch/$(hdr-arch)/include/asm/Kbuild),, \
$(error Headers not exportable for the $(SRCARCH) architecture))
$(Q)$(MAKE) $(hdr-inst)=include
- $(Q)$(MAKE) $(hdr-inst)=$(hdr-dir) $(hdr-dst)
+ $(Q)$(MAKE) $(hdr-inst)=arch/$(hdr-arch)/include/asm $(hdr-dst)
PHONY += headers_check_all
headers_check_all: headers_install_all
@@ -1106,7 +1060,7 @@ headers_check_all: headers_install_all
PHONY += headers_check
headers_check: headers_install
$(Q)$(MAKE) $(hdr-inst)=include HDRCHECK=1
- $(Q)$(MAKE) $(hdr-inst)=$(hdr-dir) $(hdr-dst) HDRCHECK=1
+ $(Q)$(MAKE) $(hdr-inst)=arch/$(hdr-arch)/include/asm $(hdr-dst) HDRCHECK=1
# ---------------------------------------------------------------------------
# Modules
@@ -1193,11 +1147,9 @@ CLEAN_FILES += vmlinux System.map \
.tmp_kallsyms* .tmp_version .tmp_vmlinux* .tmp_System.map
# Directories & files removed with 'make mrproper'
-MRPROPER_DIRS += include/config include2 usr/include include/generated
-MRPROPER_FILES += .config .config.old include/asm .version .old_version \
- include/linux/autoconf.h include/linux/version.h \
- include/linux/utsrelease.h \
- include/linux/bounds.h include/asm*/asm-offsets.h \
+MRPROPER_DIRS += include/config usr/include include/generated
+MRPROPER_FILES += .config .config.old .version .old_version \
+ include/linux/version.h \
Module.symvers Module.markers tags TAGS cscope*
# clean - Delete most, but leave enough to build external modules
diff --git a/arch/Kconfig b/arch/Kconfig
index 7f418bbc261a..4e312fffbfd7 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -83,6 +83,13 @@ config KRETPROBES
def_bool y
depends on KPROBES && HAVE_KRETPROBES
+config USER_RETURN_NOTIFIER
+ bool
+ depends on HAVE_USER_RETURN_NOTIFIER
+ help
+ Provide a kernel-internal notification when a cpu is about to
+ switch to user mode.
+
config HAVE_IOREMAP_PROT
bool
@@ -126,4 +133,7 @@ config HAVE_DMA_API_DEBUG
config HAVE_DEFAULT_NO_SPIN_MUTEXES
bool
+config HAVE_USER_RETURN_NOTIFIER
+ bool
+
source "kernel/gcov/Kconfig"
diff --git a/arch/alpha/boot/bootp.c b/arch/alpha/boot/bootp.c
index 3af21c789339..3c8d1b25c661 100644
--- a/arch/alpha/boot/bootp.c
+++ b/arch/alpha/boot/bootp.c
@@ -9,7 +9,7 @@
*/
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
#include <linux/mm.h>
#include <asm/system.h>
diff --git a/arch/alpha/boot/bootpz.c b/arch/alpha/boot/bootpz.c
index 1036b515e20c..ade3f129dc27 100644
--- a/arch/alpha/boot/bootpz.c
+++ b/arch/alpha/boot/bootpz.c
@@ -11,7 +11,7 @@
*/
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
#include <linux/mm.h>
#include <asm/system.h>
diff --git a/arch/alpha/boot/main.c b/arch/alpha/boot/main.c
index 89f3be071ae5..644b7db55438 100644
--- a/arch/alpha/boot/main.c
+++ b/arch/alpha/boot/main.c
@@ -7,7 +7,7 @@
*/
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
#include <linux/mm.h>
#include <asm/system.h>
diff --git a/arch/alpha/include/asm/asm-offsets.h b/arch/alpha/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/alpha/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/alpha/include/asm/fcntl.h b/arch/alpha/include/asm/fcntl.h
index e42823e954aa..863d143852fd 100644
--- a/arch/alpha/include/asm/fcntl.h
+++ b/arch/alpha/include/asm/fcntl.h
@@ -1,8 +1,6 @@
#ifndef _ALPHA_FCNTL_H
#define _ALPHA_FCNTL_H
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
#define O_CREAT 01000 /* not fcntl */
#define O_TRUNC 02000 /* not fcntl */
#define O_EXCL 04000 /* not fcntl */
@@ -10,13 +8,28 @@
#define O_NONBLOCK 00004
#define O_APPEND 00010
-#define O_SYNC 040000
+#define O_DSYNC 040000 /* used to be O_SYNC, see below */
#define O_DIRECTORY 0100000 /* must be a directory */
#define O_NOFOLLOW 0200000 /* don't follow links */
#define O_LARGEFILE 0400000 /* will be set by the kernel on every open */
#define O_DIRECT 02000000 /* direct disk access - should check with OSF/1 */
#define O_NOATIME 04000000
#define O_CLOEXEC 010000000 /* set close_on_exec */
+/*
+ * Before Linux 2.6.32 only O_DSYNC semantics were implemented, but using
+ * the O_SYNC flag. We continue to use the existing numerical value
+ * for O_DSYNC semantics now, but using the correct symbolic name for it.
+ * This new value is used to request true Posix O_SYNC semantics. It is
+ * defined in this strange way to make sure applications compiled against
+ * new headers get at least O_DSYNC semantics on older kernels.
+ *
+ * This has the nice side-effect that we can simply test for O_DSYNC
+ * wherever we do not care if O_DSYNC or O_SYNC is used.
+ *
+ * Note: __O_SYNC must never be used directly.
+ */
+#define __O_SYNC 020000000
+#define O_SYNC (__O_SYNC|O_DSYNC)
#define F_GETLK 7
#define F_SETLK 8
diff --git a/arch/alpha/include/asm/socket.h b/arch/alpha/include/asm/socket.h
index 26773e3246e2..06edfefc3373 100644
--- a/arch/alpha/include/asm/socket.h
+++ b/arch/alpha/include/asm/socket.h
@@ -67,6 +67,8 @@
#define SO_TIMESTAMPING 37
#define SCM_TIMESTAMPING SO_TIMESTAMPING
+#define SO_RXQ_OVFL 40
+
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here.
*/
diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S
index 95c9aef1c106..cda6b8b3d573 100644
--- a/arch/alpha/kernel/systbls.S
+++ b/arch/alpha/kernel/systbls.S
@@ -497,6 +497,7 @@ sys_call_table:
.quad sys_signalfd
.quad sys_ni_syscall
.quad sys_eventfd
+ .quad sys_recvmmsg
.size sys_call_table, . - sys_call_table
.type sys_call_table, @object
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index a73caaf66763..90b97045d2ab 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -239,15 +239,8 @@ all: $(KBUILD_IMAGE)
boot := arch/arm/boot
-# Update machine arch and proc symlinks if something which affects
-# them changed. We use .arch to indicate when they were updated
-# last, otherwise make uses the target directory mtime.
-
-archprepare: maketools
-
-PHONY += maketools FORCE
-maketools: include/linux/version.h FORCE
- $(Q)$(MAKE) $(build)=arch/arm/tools include/asm-arm/mach-types.h
+archprepare:
+ $(Q)$(MAKE) $(build)=arch/arm/tools include/generated/mach-types.h
# Convert bzImage to zImage
bzImage: zImage
@@ -258,9 +251,6 @@ zImage Image xipImage bootpImage uImage: vmlinux
zinstall install: vmlinux
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
-CLEAN_FILES += include/asm-arm/mach-types.h \
- include/asm-arm/arch include/asm-arm/.arch
-
# We use MRPROPER_FILES and CLEAN_FILES now
archclean:
$(Q)$(MAKE) $(clean)=$(boot)
diff --git a/arch/arm/configs/da830_omapl137_defconfig b/arch/arm/configs/cm_t35_defconfig
index 7c8e38f5c5ab..e42c5c873eb2 100644
--- a/arch/arm/configs/da830_omapl137_defconfig
+++ b/arch/arm/configs/cm_t35_defconfig
@@ -1,15 +1,13 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc2-davinci1
-# Wed May 13 15:33:29 2009
+# Linux kernel version: 2.6.32-rc4
+# Tue Oct 13 17:10:40 2009
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_MMU=y
-# CONFIG_NO_IOPORT is not set
CONFIG_GENERIC_HARDIRQS=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
@@ -18,44 +16,43 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_HAS_CPUFREQ=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_ZONE_DMA=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
-CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
-# CONFIG_SWAP is not set
+CONFIG_SWAP=y
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_POSIX_MQUEUE_SYSCTL=y
-# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
# CONFIG_TASKSTATS is not set
# CONFIG_AUDIT is not set
#
# RCU Subsystem
#
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=14
+CONFIG_LOG_BUF_SHIFT=17
CONFIG_GROUP_SCHED=y
CONFIG_FAIR_GROUP_SCHED=y
# CONFIG_RT_GROUP_SCHED is not set
@@ -76,11 +73,10 @@ CONFIG_SYSCTL=y
CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -93,19 +89,26 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLUB_DEBUG=y
CONFIG_COMPAT_BRK=y
-# CONFIG_SLAB is not set
-CONFIG_SLUB=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
# CONFIG_SLOB is not set
# CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
CONFIG_HAVE_OPROFILE=y
# CONFIG_KPROBES is not set
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
# CONFIG_SLOW_WORK is not set
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_SLABINFO=y
@@ -114,11 +117,11 @@ CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
# CONFIG_MODULE_FORCE_LOAD is not set
CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
CONFIG_MODVERSIONS=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -127,31 +130,34 @@ CONFIG_BLOCK=y
#
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
CONFIG_DEFAULT_AS=y
# CONFIG_DEFAULT_DEADLINE is not set
# CONFIG_DEFAULT_CFQ is not set
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="anticipatory"
-# CONFIG_FREEZER is not set
+CONFIG_FREEZER=y
#
# System Type
#
+CONFIG_MMU=y
# CONFIG_ARCH_AAEC2000 is not set
# CONFIG_ARCH_INTEGRATOR is not set
# CONFIG_ARCH_REALVIEW is not set
# CONFIG_ARCH_VERSATILE is not set
# CONFIG_ARCH_AT91 is not set
# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
# CONFIG_ARCH_EBSA110 is not set
# CONFIG_ARCH_EP93XX is not set
-# CONFIG_ARCH_GEMINI is not set
# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
# CONFIG_ARCH_NETX is not set
# CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_NOMADIK is not set
# CONFIG_ARCH_IOP13XX is not set
# CONFIG_ARCH_IOP32X is not set
# CONFIG_ARCH_IOP33X is not set
@@ -160,59 +166,87 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# CONFIG_ARCH_IXP4XX is not set
# CONFIG_ARCH_L7200 is not set
# CONFIG_ARCH_KIRKWOOD is not set
-# CONFIG_ARCH_KS8695 is not set
-# CONFIG_ARCH_NS9XXX is not set
# CONFIG_ARCH_LOKI is not set
# CONFIG_ARCH_MV78XX0 is not set
-# CONFIG_ARCH_MXC is not set
# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
# CONFIG_ARCH_PNX4008 is not set
# CONFIG_ARCH_PXA is not set
-# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_MSM is not set
# CONFIG_ARCH_RPC is not set
# CONFIG_ARCH_SA1100 is not set
# CONFIG_ARCH_S3C2410 is not set
# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
# CONFIG_ARCH_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
-CONFIG_ARCH_DAVINCI=y
-# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_MSM is not set
-# CONFIG_ARCH_W90X900 is not set
-CONFIG_CP_INTC=y
-
-#
-# TI DaVinci Implementations
-#
-
-#
-# DaVinci Core Type
-#
-# CONFIG_ARCH_DAVINCI_DM644x is not set
-# CONFIG_ARCH_DAVINCI_DM646x is not set
-# CONFIG_ARCH_DAVINCI_DM355 is not set
-CONFIG_ARCH_DAVINCI_DA830=y
-
-#
-# DaVinci Board Type
-#
-CONFIG_MACH_DAVINCI_DA830_EVM=y
-CONFIG_DAVINCI_MUX=y
-# CONFIG_DAVINCI_MUX_DEBUG is not set
-# CONFIG_DAVINCI_MUX_WARNINGS is not set
-CONFIG_DAVINCI_RESET_CLOCKS=y
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_BCMRING is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+# CONFIG_ARCH_OMAP4 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+CONFIG_OMAP_RESET_CLOCKS=y
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+# CONFIG_OMAP_PM_NONE is not set
+CONFIG_OMAP_PM_NOOP=y
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP3_BEAGLE is not set
+# CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OVERO is not set
+# CONFIG_MACH_OMAP3EVM is not set
+# CONFIG_MACH_OMAP3_PANDORA is not set
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_NOKIA_RX51 is not set
+# CONFIG_MACH_OMAP_ZOOM2 is not set
+CONFIG_MACH_CM_T35=y
#
# Processor Type
#
CONFIG_CPU_32=y
-CONFIG_CPU_ARM926T=y
-CONFIG_CPU_32v5=y
-CONFIG_CPU_ABRT_EV5TJ=y
-CONFIG_CPU_PABRT_NOIFAR=y
-CONFIG_CPU_CACHE_VIVT=y
-CONFIG_CPU_COPY_V4WB=y
-CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
CONFIG_CPU_CP15=y
CONFIG_CPU_CP15_MMU=y
@@ -220,11 +254,15 @@ CONFIG_CPU_CP15_MMU=y
# Processor Features
#
CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
# CONFIG_CPU_ICACHE_DISABLE is not set
# CONFIG_CPU_DCACHE_DISABLE is not set
-CONFIG_CPU_DCACHE_WRITETHROUGH=y
-# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
-# CONFIG_OUTER_CACHE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
CONFIG_COMMON_CLKDEV=y
#
@@ -245,11 +283,13 @@ CONFIG_VMSPLIT_3G=y
# CONFIG_VMSPLIT_2G is not set
# CONFIG_VMSPLIT_1G is not set
CONFIG_PAGE_OFFSET=0xC0000000
-CONFIG_PREEMPT=y
-CONFIG_HZ=100
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+# CONFIG_THUMB2_KERNEL is not set
CONFIG_AEABI=y
-# CONFIG_OABI_COMPAT is not set
-CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+CONFIG_OABI_COMPAT=y
# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
# CONFIG_HIGHMEM is not set
@@ -260,17 +300,17 @@ CONFIG_FLATMEM_MANUAL=y
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_PAGEFLAGS_EXTENDED=y
-CONFIG_SPLIT_PTLOCK_CPUS=4096
+CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_PHYS_ADDR_T_64BIT is not set
-CONFIG_ZONE_DMA_FLAG=1
-CONFIG_BOUNCE=y
+CONFIG_ZONE_DMA_FLAG=0
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
-CONFIG_LEDS=y
-# CONFIG_LEDS_CPU is not set
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_LEDS is not set
CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
#
# Boot options
@@ -284,6 +324,7 @@ CONFIG_CMDLINE=""
#
# CPU Power Management
#
+# CONFIG_CPU_FREQ is not set
# CONFIG_CPU_IDLE is not set
#
@@ -293,7 +334,12 @@ CONFIG_CMDLINE=""
#
# At least one emulation must be selected
#
-# CONFIG_VFP is not set
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
#
# Userspace binary formats
@@ -302,12 +348,18 @@ CONFIG_BINFMT_ELF=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_HAVE_AOUT=y
# CONFIG_BINFMT_AOUT is not set
-# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_MISC=y
#
# Power management options
#
-# CONFIG_PM is not set
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+# CONFIG_PM_RUNTIME is not set
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_NET=y
@@ -322,15 +374,16 @@ CONFIG_XFRM=y
# CONFIG_XFRM_SUB_POLICY is not set
# CONFIG_XFRM_MIGRATE is not set
# CONFIG_XFRM_STATISTICS is not set
-# CONFIG_NET_KEY is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_FIB_HASH=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_ARPD is not set
@@ -339,7 +392,7 @@ CONFIG_IP_PNP_DHCP=y
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_XFRM_TUNNEL is not set
-CONFIG_INET_TUNNEL=m
+# CONFIG_INET_TUNNEL is not set
CONFIG_INET_XFRM_MODE_TRANSPORT=y
CONFIG_INET_XFRM_MODE_TUNNEL=y
CONFIG_INET_XFRM_MODE_BEET=y
@@ -350,54 +403,12 @@ CONFIG_INET_TCP_DIAG=y
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_TCP_MD5SIG is not set
-CONFIG_IPV6=m
-# CONFIG_IPV6_PRIVACY is not set
-# CONFIG_IPV6_ROUTER_PREF is not set
-# CONFIG_IPV6_OPTIMISTIC_DAD is not set
-# CONFIG_INET6_AH is not set
-# CONFIG_INET6_ESP is not set
-# CONFIG_INET6_IPCOMP is not set
-# CONFIG_IPV6_MIP6 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
-CONFIG_INET6_XFRM_MODE_TRANSPORT=m
-CONFIG_INET6_XFRM_MODE_TUNNEL=m
-CONFIG_INET6_XFRM_MODE_BEET=m
-# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
-CONFIG_IPV6_SIT=m
-CONFIG_IPV6_NDISC_NODETYPE=y
-# CONFIG_IPV6_TUNNEL is not set
-# CONFIG_IPV6_MULTIPLE_TABLES is not set
-# CONFIG_IPV6_MROUTE is not set
+# CONFIG_IPV6 is not set
# CONFIG_NETWORK_SECMARK is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-CONFIG_NETFILTER_ADVANCED=y
-
-#
-# Core Netfilter Configuration
-#
-# CONFIG_NETFILTER_NETLINK_QUEUE is not set
-# CONFIG_NETFILTER_NETLINK_LOG is not set
-# CONFIG_NF_CONNTRACK is not set
-# CONFIG_NETFILTER_XTABLES is not set
-# CONFIG_IP_VS is not set
-
-#
-# IP: Netfilter Configuration
-#
-# CONFIG_NF_DEFRAG_IPV4 is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_ARPTABLES is not set
-
-#
-# IPv6: Netfilter Configuration
-#
-# CONFIG_IP6_NF_QUEUE is not set
-# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
@@ -412,6 +423,7 @@ CONFIG_NETFILTER_ADVANCED=y
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -424,7 +436,18 @@ CONFIG_NETFILTER_ADVANCED=y
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set
-# CONFIG_WIRELESS is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+CONFIG_CFG80211_DEFAULT_PS_VALUE=0
+# CONFIG_WIRELESS_OLD_REGULATORY is not set
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_LIB80211=m
+# CONFIG_LIB80211_DEBUG is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -437,26 +460,128 @@ CONFIG_NETFILTER_ADVANCED=y
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=m
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
# CONFIG_CONNECTOR is not set
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_OMAP_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_OMAP2=y
+CONFIG_MTD_NAND_OMAP_PREFETCH=y
+# CONFIG_MTD_NAND_OMAP_PREFETCH_DMA is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=1
-CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
# CONFIG_BLK_DEV_XIP is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
CONFIG_MISC_DEVICES=y
# CONFIG_ICS932S401 is not set
# CONFIG_ENCLOSURE_SERVICES is not set
@@ -466,8 +591,10 @@ CONFIG_MISC_DEVICES=y
#
# EEPROM support
#
-CONFIG_EEPROM_AT24=y
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -476,7 +603,7 @@ CONFIG_HAVE_IDE=y
# SCSI device support
#
# CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=m
+CONFIG_SCSI=y
CONFIG_SCSI_DMA=y
# CONFIG_SCSI_TGT is not set
# CONFIG_SCSI_NETLINK is not set
@@ -485,16 +612,12 @@ CONFIG_SCSI_PROC_FS=y
#
# SCSI support type (disk, tape, CD-ROM)
#
-CONFIG_BLK_DEV_SD=m
+CONFIG_BLK_DEV_SD=y
# CONFIG_CHR_DEV_ST is not set
# CONFIG_CHR_DEV_OSST is not set
# CONFIG_BLK_DEV_SR is not set
# CONFIG_CHR_DEV_SG is not set
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -519,12 +642,11 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ATA is not set
# CONFIG_MD is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
-CONFIG_TUN=m
+# CONFIG_TUN is not set
# CONFIG_VETH is not set
CONFIG_PHYLIB=y
@@ -534,7 +656,7 @@ CONFIG_PHYLIB=y
# CONFIG_MARVELL_PHY is not set
# CONFIG_DAVICOM_PHY is not set
# CONFIG_QSEMI_PHY is not set
-CONFIG_LXT_PHY=y
+# CONFIG_LXT_PHY is not set
# CONFIG_CICADA_PHY is not set
# CONFIG_VITESSE_PHY is not set
# CONFIG_SMSC_PHY is not set
@@ -543,18 +665,18 @@ CONFIG_LXT_PHY=y
# CONFIG_REALTEK_PHY is not set
# CONFIG_NATIONAL_PHY is not set
# CONFIG_STE10XP is not set
-CONFIG_LSI_ET1011C_PHY=y
+# CONFIG_LSI_ET1011C_PHY is not set
# CONFIG_FIXED_PHY is not set
# CONFIG_MDIO_BITBANG is not set
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_AX88796 is not set
# CONFIG_SMC91X is not set
-CONFIG_TI_DAVINCI_EMAC=y
# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
# CONFIG_ETHOC is not set
# CONFIG_SMC911X is not set
-# CONFIG_SMSC911X is not set
+CONFIG_SMSC911X=y
# CONFIG_DNET is not set
# CONFIG_IBM_NEW_EMAC_ZMII is not set
# CONFIG_IBM_NEW_EMAC_RGMII is not set
@@ -564,27 +686,42 @@ CONFIG_TI_DAVINCI_EMAC=y
# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
+CONFIG_WLAN=y
+# CONFIG_WLAN_PRE80211 is not set
+CONFIG_WLAN_80211=y
+CONFIG_LIBERTAS=m
+# CONFIG_LIBERTAS_USB is not set
+CONFIG_LIBERTAS_SDIO=m
+# CONFIG_LIBERTAS_SPI is not set
+# CONFIG_LIBERTAS_DEBUG is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_HOSTAP is not set
#
-# Wireless LAN
+# Enable WiMAX (Networking options) to see the WiMAX drivers
#
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
#
-# Enable WiMAX (Networking options) to see the WiMAX drivers
+# USB Network Adapters
#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
# CONFIG_WAN is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
-CONFIG_NETCONSOLE=y
-# CONFIG_NETCONSOLE_DYNAMIC is not set
-CONFIG_NETPOLL=y
-CONFIG_NETPOLL_TRAP=y
-CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
#
# Input device support
@@ -596,43 +733,57 @@ CONFIG_INPUT=y
#
# Userland interfaces
#
-CONFIG_INPUT_MOUSEDEV=m
+CONFIG_INPUT_MOUSEDEV=y
CONFIG_INPUT_MOUSEDEV_PSAUX=y
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
# CONFIG_INPUT_JOYDEV is not set
-CONFIG_INPUT_EVDEV=m
-CONFIG_INPUT_EVBUG=m
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
#
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=m
-# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_ADP5588 is not set
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_QT2160 is not set
# CONFIG_KEYBOARD_LKKBD is not set
-CONFIG_KEYBOARD_XTKBD=m
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
-CONFIG_KEYBOARD_GPIO=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_KEYBOARD_TWL4030=m
+# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TABLET is not set
CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=m
+# CONFIG_TOUCHSCREEN_AD7877 is not set
# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
# CONFIG_TOUCHSCREEN_FUJITSU is not set
# CONFIG_TOUCHSCREEN_GUNZE is not set
# CONFIG_TOUCHSCREEN_ELO is not set
# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
# CONFIG_TOUCHSCREEN_MTOUCH is not set
# CONFIG_TOUCHSCREEN_INEXIO is not set
# CONFIG_TOUCHSCREEN_MK712 is not set
# CONFIG_TOUCHSCREEN_PENMOUNT is not set
# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
# CONFIG_INPUT_MISC is not set
#
@@ -649,7 +800,7 @@ CONFIG_SERIO_LIBPS2=y
#
CONFIG_VT=y
CONFIG_CONSOLE_TRANSLATIONS=y
-# CONFIG_VT_CONSOLE is not set
+CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
# CONFIG_VT_HW_CONSOLE_BINDING is not set
CONFIG_DEVKMEM=y
@@ -660,27 +811,32 @@ CONFIG_DEVKMEM=y
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=3
-CONFIG_SERIAL_8250_RUNTIME_UARTS=3
-# CONFIG_SERIAL_8250_EXTENDED is not set
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+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
#
# Non-8250 serial port support
#
+# CONFIG_SERIAL_MAX3100 is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_LEGACY_PTYS is not set
# CONFIG_IPMI_HANDLER is not set
-CONFIG_HW_RANDOM=m
+CONFIG_HW_RANDOM=y
# CONFIG_HW_RANDOM_TIMERIOMEM is not set
# CONFIG_R3964 is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_HELPER_AUTO=y
@@ -691,9 +847,10 @@ CONFIG_I2C_HELPER_AUTO=y
#
# I2C system bus drivers (mostly embedded / system-on-chip)
#
-CONFIG_I2C_DAVINCI=y
+# CONFIG_I2C_DESIGNWARE is not set
# CONFIG_I2C_GPIO is not set
# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
# CONFIG_I2C_SIMTEC is not set
#
@@ -701,6 +858,7 @@ CONFIG_I2C_DAVINCI=y
#
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
#
# Other I2C/SMBus bus drivers
@@ -712,18 +870,36 @@ CONFIG_I2C_DAVINCI=y
# Miscellaneous I2C Chip support
#
# CONFIG_DS1682 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
-# CONFIG_SPI is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
# CONFIG_DEBUG_GPIO is not set
-# CONFIG_GPIO_SYSFS is not set
+CONFIG_GPIO_SYSFS=y
#
# Memory mapped GPIO expanders:
@@ -734,7 +910,8 @@ CONFIG_GPIOLIB=y
#
# CONFIG_GPIO_MAX732X is not set
# CONFIG_GPIO_PCA953X is not set
-CONFIG_GPIO_PCF857X=m
+# CONFIG_GPIO_PCF857X is not set
+CONFIG_GPIO_TWL4030=y
#
# PCI GPIO expanders:
@@ -743,19 +920,31 @@ CONFIG_GPIO_PCF857X=m
#
# SPI GPIO expanders:
#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
+CONFIG_WATCHDOG_NOWAYOUT=y
#
# Watchdog Device Drivers
#
# CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_DAVINCI_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+# CONFIG_TWL4030_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
CONFIG_SSB_POSSIBLE=y
#
@@ -772,31 +961,32 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_HTC_EGPIO is not set
# CONFIG_HTC_PASIC3 is not set
# CONFIG_TPS65010 is not set
-# CONFIG_TWL4030_CORE is not set
+CONFIG_TWL4030_CORE=y
+# CONFIG_TWL4030_POWER is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_MFD_T7L66XB is not set
# CONFIG_MFD_TC6387XB is not set
# CONFIG_MFD_TC6393XB is not set
# CONFIG_PMIC_DA903X is not set
# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+CONFIG_REGULATOR_TWL4030=y
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -816,75 +1006,340 @@ CONFIG_SSB_POSSIBLE=y
#
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
-CONFIG_SOUND=m
-# CONFIG_SOUND_OSS_CORE is not set
-CONFIG_SND=m
-CONFIG_SND_TIMER=m
-CONFIG_SND_PCM=m
-CONFIG_SND_JACK=y
-# CONFIG_SND_SEQUENCER is not set
-# CONFIG_SND_MIXER_OSS is not set
-# CONFIG_SND_PCM_OSS is not set
-# CONFIG_SND_HRTIMER is not set
-# CONFIG_SND_DYNAMIC_MINORS is not set
-CONFIG_SND_SUPPORT_OLD_API=y
-CONFIG_SND_VERBOSE_PROCFS=y
-# CONFIG_SND_VERBOSE_PRINTK is not set
-# CONFIG_SND_DEBUG is not set
-CONFIG_SND_DRIVERS=y
-# CONFIG_SND_DUMMY is not set
-# CONFIG_SND_MTPAV is not set
-# CONFIG_SND_SERIAL_U16550 is not set
-# CONFIG_SND_MPU401 is not set
-CONFIG_SND_ARM=y
-CONFIG_SND_SOC=m
-CONFIG_SND_DAVINCI_SOC=m
-CONFIG_SND_SOC_I2C_AND_SPI=m
-# CONFIG_SND_SOC_ALL_CODECS is not set
-# CONFIG_SOUND_PRIME is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# OMAP 343x high speed USB support
+#
# CONFIG_USB_MUSB_HOST is not set
# CONFIG_USB_MUSB_PERIPHERAL is not set
-# CONFIG_USB_MUSB_OTG is not set
-# CONFIG_USB_GADGET_MUSB_HDRC is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+# CONFIG_USB_MUSB_DEBUG is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+CONFIG_USB_TEST=y
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
# CONFIG_USB_GADGET_AT91 is not set
# CONFIG_USB_GADGET_ATMEL_USBA is not set
# CONFIG_USB_GADGET_FSL_USB2 is not set
# CONFIG_USB_GADGET_LH7A40X is not set
# CONFIG_USB_GADGET_OMAP is not set
# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
# CONFIG_USB_GADGET_PXA27X is not set
-# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
# CONFIG_USB_GADGET_M66592 is not set
# CONFIG_USB_GADGET_AMD5536UDC is not set
# CONFIG_USB_GADGET_FSL_QE is not set
# CONFIG_USB_GADGET_CI13XXX is not set
# CONFIG_USB_GADGET_NET2280 is not set
# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
# CONFIG_USB_ZERO is not set
-# CONFIG_USB_ETH is not set
+# CONFIG_USB_AUDIO is not set
+CONFIG_USB_ETH=y
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_ETH_EEM is not set
# CONFIG_USB_GADGETFS is not set
# CONFIG_USB_FILE_STORAGE is not set
# CONFIG_USB_G_SERIAL is not set
# CONFIG_USB_MIDI_GADGET is not set
# CONFIG_USB_G_PRINTER is not set
# CONFIG_USB_CDC_COMPOSITE is not set
-# CONFIG_MMC is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_ISP1301_OMAP is not set
+CONFIG_TWL4030_USB=y
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_OMAP is not set
+CONFIG_MMC_OMAP_HS=y
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
+# CONFIG_MMC_SPI is not set
# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_BD2802 is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
# CONFIG_ACCESSIBILITY is not set
-# CONFIG_NEW_LEDS is not set
CONFIG_RTC_LIB=y
-# CONFIG_RTC_CLASS is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+CONFIG_RTC_DRV_TWL4030=y
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
-# CONFIG_REGULATOR is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -892,30 +1347,32 @@ CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT3_FS_XATTR is not set
# CONFIG_EXT4_FS is not set
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
-CONFIG_XFS_FS=m
-# CONFIG_XFS_QUOTA is not set
-# CONFIG_XFS_POSIX_ACL is not set
-# CONFIG_XFS_RT is not set
-# CONFIG_XFS_DEBUG is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
-# CONFIG_QUOTA is not set
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+CONFIG_QUOTA_TREE=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
# CONFIG_AUTOFS_FS is not set
-CONFIG_AUTOFS4_FS=m
+# CONFIG_AUTOFS4_FS is not set
# CONFIG_FUSE_FS is not set
#
@@ -937,7 +1394,9 @@ CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_FAT_DEFAULT_CODEPAGE=437
CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
-# CONFIG_NTFS_FS is not set
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_RW is not set
#
# Pseudo filesystems
@@ -958,36 +1417,47 @@ CONFIG_MISC_FILESYSTEMS=y
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
-CONFIG_CRAMFS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_CRAMFS is not set
# CONFIG_SQUASHFS is not set
# CONFIG_VXFS_FS is not set
-CONFIG_MINIX_FS=m
+# CONFIG_MINIX_FS is not set
# CONFIG_OMFS_FS is not set
# CONFIG_HPFS_FS is not set
# CONFIG_QNX4FS_FS is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
-# CONFIG_NFS_V4 is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
-CONFIG_NFSD=m
-CONFIG_NFSD_V3=y
-# CONFIG_NFSD_V3_ACL is not set
-# CONFIG_NFSD_V4 is not set
+# CONFIG_NFSD is not set
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=m
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
# CONFIG_RPCSEC_GSS_SPKM3 is not set
-CONFIG_SMB_FS=m
-# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
@@ -1039,7 +1509,7 @@ CONFIG_NLS_CODEPAGE_437=y
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_CODEPAGE_1250 is not set
# CONFIG_NLS_CODEPAGE_1251 is not set
-CONFIG_NLS_ASCII=m
+# CONFIG_NLS_ASCII is not set
CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_ISO8859_2 is not set
# CONFIG_NLS_ISO8859_3 is not set
@@ -1063,7 +1533,8 @@ CONFIG_NLS_UTF8=m
CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=1024
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_FS=y
# CONFIG_HEADERS_CHECK is not set
@@ -1075,15 +1546,13 @@ CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
CONFIG_DETECT_HUNG_TASK=y
# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
-CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHED_DEBUG is not set
# CONFIG_SCHEDSTATS is not set
-CONFIG_TIMER_STATS=y
+# CONFIG_TIMER_STATS is not set
# CONFIG_DEBUG_OBJECTS is not set
-# CONFIG_SLUB_DEBUG_ON is not set
-# CONFIG_SLUB_STATS is not set
-CONFIG_DEBUG_PREEMPT=y
-CONFIG_DEBUG_RT_MUTEXES=y
-CONFIG_DEBUG_PI_LIST=y
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
CONFIG_DEBUG_MUTEXES=y
@@ -1093,37 +1562,35 @@ CONFIG_DEBUG_MUTEXES=y
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
-CONFIG_DEBUG_BUGVERBOSE=y
-# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_VM is not set
# CONFIG_DEBUG_WRITECOUNT is not set
# CONFIG_DEBUG_MEMORY_INIT is not set
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
-# CONFIG_SYSCTL_SYSCALL_CHECK is not set
# CONFIG_PAGE_POISONING is not set
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
# CONFIG_IRQSOFF_TRACER is not set
-# CONFIG_PREEMPT_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -1133,10 +1600,11 @@ CONFIG_TRACING_SUPPORT=y
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
CONFIG_ARM_UNWIND=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
# CONFIG_DEBUG_STACK_USAGE is not set
-# CONFIG_DEBUG_LL is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
#
# Security options
@@ -1150,11 +1618,20 @@ CONFIG_CRYPTO=y
#
# Crypto core or helper
#
-# CONFIG_CRYPTO_FIPS is not set
-# CONFIG_CRYPTO_MANAGER is not set
-# CONFIG_CRYPTO_MANAGER2 is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
# CONFIG_CRYPTO_GF128MUL is not set
# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
# CONFIG_CRYPTO_CRYPTD is not set
# CONFIG_CRYPTO_AUTHENC is not set
# CONFIG_CRYPTO_TEST is not set
@@ -1169,12 +1646,12 @@ CONFIG_CRYPTO=y
#
# Block modes
#
-# CONFIG_CRYPTO_CBC is not set
+CONFIG_CRYPTO_CBC=y
# CONFIG_CRYPTO_CTR is not set
# CONFIG_CRYPTO_CTS is not set
-# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_ECB=m
# CONFIG_CRYPTO_LRW is not set
-# CONFIG_CRYPTO_PCBC is not set
+CONFIG_CRYPTO_PCBC=m
# CONFIG_CRYPTO_XTS is not set
#
@@ -1182,13 +1659,15 @@ CONFIG_CRYPTO=y
#
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
#
# Digest
#
-# CONFIG_CRYPTO_CRC32C is not set
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_GHASH is not set
# CONFIG_CRYPTO_MD4 is not set
-# CONFIG_CRYPTO_MD5 is not set
+CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_MICHAEL_MIC is not set
# CONFIG_CRYPTO_RMD128 is not set
# CONFIG_CRYPTO_RMD160 is not set
@@ -1210,7 +1689,7 @@ CONFIG_CRYPTO=y
# CONFIG_CRYPTO_CAMELLIA is not set
# CONFIG_CRYPTO_CAST5 is not set
# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_DES is not set
+CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_KHAZAD is not set
# CONFIG_CRYPTO_SALSA20 is not set
@@ -1230,7 +1709,7 @@ CONFIG_CRYPTO=y
# Random Number Generation
#
# CONFIG_CRYPTO_ANSI_CPRNG is not set
-# CONFIG_CRYPTO_HW is not set
+CONFIG_CRYPTO_HW=y
# CONFIG_BINARY_PRINTF is not set
#
@@ -1238,16 +1717,16 @@ CONFIG_CRYPTO=y
#
CONFIG_BITREVERSE=y
CONFIG_GENERIC_FIND_LAST_BIT=y
-CONFIG_CRC_CCITT=m
+CONFIG_CRC_CCITT=y
# CONFIG_CRC16 is not set
-CONFIG_CRC_T10DIF=m
+# CONFIG_CRC_T10DIF is not set
# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
# CONFIG_CRC7 is not set
-# CONFIG_LIBCRC32C is not set
+CONFIG_LIBCRC32C=y
CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
CONFIG_DECOMPRESS_GZIP=y
-CONFIG_GENERIC_ALLOCATOR=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/da850_omapl138_defconfig b/arch/arm/configs/da8xx_omapl_defconfig
index 842a70b079bf..d7e7ad4b5c98 100644
--- a/arch/arm/configs/da850_omapl138_defconfig
+++ b/arch/arm/configs/da8xx_omapl_defconfig
@@ -1,15 +1,13 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-davinci1
-# Mon Jun 29 07:54:15 2009
+# Linux kernel version: 2.6.32-rc4
+# Fri Oct 16 10:08:33 2009
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_MMU=y
-# CONFIG_NO_IOPORT is not set
CONFIG_GENERIC_HARDIRQS=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
@@ -18,14 +16,14 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_HAS_CPUFREQ=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_ZONE_DMA=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -48,11 +46,12 @@ CONFIG_POSIX_MQUEUE_SYSCTL=y
#
# RCU Subsystem
#
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
@@ -62,8 +61,8 @@ CONFIG_FAIR_GROUP_SCHED=y
CONFIG_USER_SCHED=y
# CONFIG_CGROUP_SCHED is not set
# CONFIG_CGROUPS is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
# CONFIG_RELAY is not set
# CONFIG_NAMESPACES is not set
CONFIG_BLK_DEV_INITRD=y
@@ -80,7 +79,6 @@ CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -93,6 +91,10 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_SLUB_DEBUG=y
CONFIG_COMPAT_BRK=y
@@ -100,12 +102,16 @@ CONFIG_COMPAT_BRK=y
CONFIG_SLUB=y
# CONFIG_SLOB is not set
# CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
CONFIG_HAVE_OPROFILE=y
# CONFIG_KPROBES is not set
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
# CONFIG_SLOW_WORK is not set
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_SLABINFO=y
@@ -118,7 +124,7 @@ CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_MODVERSIONS=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -139,19 +145,22 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
#
# System Type
#
+CONFIG_MMU=y
# CONFIG_ARCH_AAEC2000 is not set
# CONFIG_ARCH_INTEGRATOR is not set
# CONFIG_ARCH_REALVIEW is not set
# CONFIG_ARCH_VERSATILE is not set
# CONFIG_ARCH_AT91 is not set
# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
# CONFIG_ARCH_EBSA110 is not set
# CONFIG_ARCH_EP93XX is not set
-# CONFIG_ARCH_GEMINI is not set
# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
# CONFIG_ARCH_NETX is not set
# CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_NOMADIK is not set
# CONFIG_ARCH_IOP13XX is not set
# CONFIG_ARCH_IOP32X is not set
# CONFIG_ARCH_IOP33X is not set
@@ -160,25 +169,27 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# CONFIG_ARCH_IXP4XX is not set
# CONFIG_ARCH_L7200 is not set
# CONFIG_ARCH_KIRKWOOD is not set
-# CONFIG_ARCH_KS8695 is not set
-# CONFIG_ARCH_NS9XXX is not set
# CONFIG_ARCH_LOKI is not set
# CONFIG_ARCH_MV78XX0 is not set
-# CONFIG_ARCH_MXC is not set
# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
# CONFIG_ARCH_PNX4008 is not set
# CONFIG_ARCH_PXA is not set
-# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_MSM is not set
# CONFIG_ARCH_RPC is not set
# CONFIG_ARCH_SA1100 is not set
# CONFIG_ARCH_S3C2410 is not set
# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
# CONFIG_ARCH_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
CONFIG_ARCH_DAVINCI=y
# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_MSM is not set
-# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_BCMRING is not set
CONFIG_CP_INTC=y
#
@@ -191,7 +202,7 @@ CONFIG_CP_INTC=y
# CONFIG_ARCH_DAVINCI_DM644x is not set
# CONFIG_ARCH_DAVINCI_DM355 is not set
# CONFIG_ARCH_DAVINCI_DM646x is not set
-# CONFIG_ARCH_DAVINCI_DA830 is not set
+CONFIG_ARCH_DAVINCI_DA830=y
CONFIG_ARCH_DAVINCI_DA850=y
CONFIG_ARCH_DAVINCI_DA8XX=y
# CONFIG_ARCH_DAVINCI_DM365 is not set
@@ -199,7 +210,14 @@ CONFIG_ARCH_DAVINCI_DA8XX=y
#
# DaVinci Board Type
#
+CONFIG_MACH_DAVINCI_DA830_EVM=y
+CONFIG_DA830_UI=y
+CONFIG_DA830_UI_LCD=y
+# CONFIG_DA830_UI_NAND is not set
CONFIG_MACH_DAVINCI_DA850_EVM=y
+CONFIG_DA850_UI_EXP=y
+CONFIG_DA850_UI_NONE=y
+# CONFIG_DA850_UI_RMII is not set
CONFIG_DAVINCI_MUX=y
# CONFIG_DAVINCI_MUX_DEBUG is not set
# CONFIG_DAVINCI_MUX_WARNINGS is not set
@@ -212,7 +230,7 @@ CONFIG_CPU_32=y
CONFIG_CPU_ARM926T=y
CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5TJ=y
-CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_PABRT_LEGACY=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_COPY_V4WB=y
CONFIG_CPU_TLB_V4WBI=y
@@ -225,9 +243,9 @@ CONFIG_CPU_CP15_MMU=y
CONFIG_ARM_THUMB=y
# CONFIG_CPU_ICACHE_DISABLE is not set
# CONFIG_CPU_DCACHE_DISABLE is not set
-# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+CONFIG_CPU_DCACHE_WRITETHROUGH=y
# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
-# CONFIG_OUTER_CACHE is not set
+CONFIG_ARM_L1_CACHE_SHIFT=5
CONFIG_COMMON_CLKDEV=y
#
@@ -248,11 +266,12 @@ CONFIG_VMSPLIT_3G=y
# CONFIG_VMSPLIT_2G is not set
# CONFIG_VMSPLIT_1G is not set
CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
CONFIG_PREEMPT=y
CONFIG_HZ=100
CONFIG_AEABI=y
# CONFIG_OABI_COMPAT is not set
-# CONFIG_ARCH_HAS_HOLES_MEMORYMODEL is not set
# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
# CONFIG_HIGHMEM is not set
@@ -268,12 +287,14 @@ CONFIG_SPLIT_PTLOCK_CPUS=4096
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_LEDS=y
# CONFIG_LEDS_CPU is not set
CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
#
# Boot options
@@ -287,6 +308,21 @@ CONFIG_CMDLINE=""
#
# CPU Power Management
#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=m
+CONFIG_CPU_FREQ_GOV_POWERSAVE=m
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=m
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
# CONFIG_CPU_IDLE is not set
#
@@ -401,6 +437,7 @@ CONFIG_NETFILTER_ADVANCED=y
# CONFIG_IP6_NF_IPTABLES is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
@@ -415,6 +452,7 @@ CONFIG_NETFILTER_ADVANCED=y
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -440,6 +478,7 @@ CONFIG_NETFILTER_ADVANCED=y
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
@@ -460,6 +499,7 @@ CONFIG_BLK_DEV_RAM_SIZE=32768
# CONFIG_BLK_DEV_XIP is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
CONFIG_MISC_DEVICES=y
# CONFIG_ICS932S401 is not set
# CONFIG_ENCLOSURE_SERVICES is not set
@@ -471,6 +511,7 @@ CONFIG_MISC_DEVICES=y
#
CONFIG_EEPROM_AT24=y
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -494,10 +535,6 @@ CONFIG_BLK_DEV_SD=m
# CONFIG_BLK_DEV_SR is not set
# CONFIG_CHR_DEV_SG is not set
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -522,7 +559,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ATA is not set
# CONFIG_MD is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -553,7 +589,7 @@ CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_AX88796 is not set
# CONFIG_SMC91X is not set
-# CONFIG_TI_DAVINCI_EMAC is not set
+CONFIG_TI_DAVINCI_EMAC=y
# CONFIG_DM9000 is not set
# CONFIG_ETHOC is not set
# CONFIG_SMC911X is not set
@@ -567,12 +603,11 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
-
-#
-# Wireless LAN
-#
+CONFIG_WLAN=y
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set
@@ -588,6 +623,7 @@ CONFIG_NETPOLL=y
CONFIG_NETPOLL_TRAP=y
CONFIG_NET_POLL_CONTROLLER=y
# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
#
# Input device support
@@ -611,23 +647,30 @@ CONFIG_INPUT_EVBUG=m
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
CONFIG_KEYBOARD_ATKBD=m
-# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_QT2160 is not set
# CONFIG_KEYBOARD_LKKBD is not set
-CONFIG_KEYBOARD_XTKBD=m
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
-CONFIG_KEYBOARD_GPIO=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_KEYBOARD_XTKBD=m
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TABLET is not set
CONFIG_INPUT_TOUCHSCREEN=y
# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
# CONFIG_TOUCHSCREEN_FUJITSU is not set
# CONFIG_TOUCHSCREEN_GUNZE is not set
# CONFIG_TOUCHSCREEN_ELO is not set
# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
# CONFIG_TOUCHSCREEN_MTOUCH is not set
# CONFIG_TOUCHSCREEN_INEXIO is not set
# CONFIG_TOUCHSCREEN_MK712 is not set
@@ -636,6 +679,7 @@ CONFIG_INPUT_TOUCHSCREEN=y
# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
# CONFIG_INPUT_MISC is not set
#
@@ -684,6 +728,7 @@ CONFIG_HW_RANDOM=m
# CONFIG_TCG_TPM is not set
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_HELPER_AUTO=y
@@ -695,6 +740,7 @@ CONFIG_I2C_HELPER_AUTO=y
# I2C system bus drivers (mostly embedded / system-on-chip)
#
CONFIG_I2C_DAVINCI=y
+# CONFIG_I2C_DESIGNWARE is not set
# CONFIG_I2C_GPIO is not set
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_SIMTEC is not set
@@ -715,14 +761,17 @@ CONFIG_I2C_DAVINCI=y
# Miscellaneous I2C Chip support
#
# CONFIG_DS1682 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
# CONFIG_DEBUG_GPIO is not set
@@ -736,8 +785,8 @@ CONFIG_GPIOLIB=y
# I2C GPIO expanders:
#
# CONFIG_GPIO_MAX732X is not set
-# CONFIG_GPIO_PCA953X is not set
-CONFIG_GPIO_PCF857X=m
+CONFIG_GPIO_PCA953X=y
+CONFIG_GPIO_PCF857X=y
#
# PCI GPIO expanders:
@@ -746,11 +795,14 @@ CONFIG_GPIO_PCF857X=m
#
# SPI GPIO expanders:
#
+
+#
+# AC97 GPIO expanders:
+#
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
CONFIG_WATCHDOG=y
# CONFIG_WATCHDOG_NOWAYOUT is not set
@@ -782,31 +834,47 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_TC6393XB is not set
# CONFIG_PMIC_DA903X is not set
# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
#
# CONFIG_VGASTATE is not set
# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_DAVINCI is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_DA8XX=y
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
@@ -819,6 +887,16 @@ CONFIG_SSB_POSSIBLE=y
#
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
CONFIG_SOUND=m
# CONFIG_SOUND_OSS_CORE is not set
CONFIG_SND=m
@@ -834,6 +912,11 @@ CONFIG_SND_SUPPORT_OLD_API=y
CONFIG_SND_VERBOSE_PROCFS=y
# CONFIG_SND_VERBOSE_PRINTK is not set
# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
CONFIG_SND_DRIVERS=y
# CONFIG_SND_DUMMY is not set
# CONFIG_SND_MTPAV is not set
@@ -842,6 +925,8 @@ CONFIG_SND_DRIVERS=y
CONFIG_SND_ARM=y
CONFIG_SND_SOC=m
CONFIG_SND_DAVINCI_SOC=m
+# CONFIG_SND_DA830_SOC_EVM is not set
+# CONFIG_SND_DA850_SOC_EVM is not set
CONFIG_SND_SOC_I2C_AND_SPI=m
# CONFIG_SND_SOC_ALL_CODECS is not set
# CONFIG_SOUND_PRIME is not set
@@ -849,14 +934,17 @@ CONFIG_SND_SOC_I2C_AND_SPI=m
# CONFIG_USB_SUPPORT is not set
# CONFIG_MMC is not set
# CONFIG_MEMSTICK is not set
-# CONFIG_ACCESSIBILITY is not set
# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
CONFIG_RTC_LIB=y
# CONFIG_RTC_CLASS is not set
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
-# CONFIG_REGULATOR is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -877,14 +965,17 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
CONFIG_XFS_FS=m
# CONFIG_XFS_QUOTA is not set
# CONFIG_XFS_POSIX_ACL is not set
# CONFIG_XFS_RT is not set
# CONFIG_XFS_DEBUG is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -943,7 +1034,6 @@ CONFIG_MINIX_FS=m
# CONFIG_ROMFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
@@ -1039,6 +1129,7 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=1024
# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_FS=y
# CONFIG_HEADERS_CHECK is not set
@@ -1056,6 +1147,7 @@ CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_OBJECTS is not set
# CONFIG_SLUB_DEBUG_ON is not set
# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
CONFIG_DEBUG_PREEMPT=y
CONFIG_DEBUG_RT_MUTEXES=y
CONFIG_DEBUG_PI_LIST=y
@@ -1076,29 +1168,29 @@ CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
# CONFIG_SYSCTL_SYSCALL_CHECK is not set
# CONFIG_PAGE_POISONING is not set
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_PREEMPT_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
@@ -1125,7 +1217,6 @@ CONFIG_CRYPTO=y
#
# Crypto core or helper
#
-# CONFIG_CRYPTO_FIPS is not set
# CONFIG_CRYPTO_MANAGER is not set
# CONFIG_CRYPTO_MANAGER2 is not set
# CONFIG_CRYPTO_GF128MUL is not set
@@ -1157,11 +1248,13 @@ CONFIG_CRYPTO=y
#
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
#
# Digest
#
# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
# CONFIG_CRYPTO_MD4 is not set
# CONFIG_CRYPTO_MD5 is not set
# CONFIG_CRYPTO_MICHAEL_MIC is not set
diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig
index ddffe39d9f87..22077803e9a6 100644
--- a/arch/arm/configs/davinci_all_defconfig
+++ b/arch/arm/configs/davinci_all_defconfig
@@ -1,14 +1,13 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.31-rc3-davinci1
-# Fri Jul 17 08:26:52 2009
+# Linux kernel version: 2.6.32-rc4
+# Mon Oct 12 14:13:12 2009
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
@@ -46,11 +45,12 @@ CONFIG_POSIX_MQUEUE_SYSCTL=y
#
# RCU Subsystem
#
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
@@ -91,17 +91,15 @@ CONFIG_SHMEM=y
CONFIG_AIO=y
#
-# Performance Counters
+# Kernel Performance Events And Counters
#
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_SLUB_DEBUG=y
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
# CONFIG_SLOB is not set
# CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
CONFIG_HAVE_OPROFILE=y
# CONFIG_KPROBES is not set
CONFIG_HAVE_KPROBES=y
@@ -145,6 +143,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
#
# System Type
#
+CONFIG_MMU=y
# CONFIG_ARCH_AAEC2000 is not set
# CONFIG_ARCH_INTEGRATOR is not set
# CONFIG_ARCH_REALVIEW is not set
@@ -159,6 +158,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# CONFIG_ARCH_STMP3XXX is not set
# CONFIG_ARCH_NETX is not set
# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
# CONFIG_ARCH_IOP13XX is not set
# CONFIG_ARCH_IOP32X is not set
# CONFIG_ARCH_IOP33X is not set
@@ -181,11 +181,13 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# CONFIG_ARCH_SA1100 is not set
# CONFIG_ARCH_S3C2410 is not set
# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
# CONFIG_ARCH_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
# CONFIG_ARCH_U300 is not set
CONFIG_ARCH_DAVINCI=y
# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_BCMRING is not set
CONFIG_AINTC=y
CONFIG_ARCH_DAVINCI_DMx=y
@@ -224,7 +226,7 @@ CONFIG_CPU_32=y
CONFIG_CPU_ARM926T=y
CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5TJ=y
-CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_PABRT_LEGACY=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_COPY_V4WB=y
CONFIG_CPU_TLB_V4WBI=y
@@ -239,6 +241,7 @@ CONFIG_ARM_THUMB=y
# CONFIG_CPU_DCACHE_DISABLE is not set
# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+CONFIG_ARM_L1_CACHE_SHIFT=5
CONFIG_COMMON_CLKDEV=y
#
@@ -259,6 +262,8 @@ CONFIG_VMSPLIT_3G=y
# CONFIG_VMSPLIT_2G is not set
# CONFIG_VMSPLIT_1G is not set
CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
CONFIG_PREEMPT=y
CONFIG_HZ=100
CONFIG_AEABI=y
@@ -280,6 +285,7 @@ CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_LEDS=y
# CONFIG_LEDS_CPU is not set
@@ -412,6 +418,7 @@ CONFIG_NETFILTER_ADVANCED=y
# CONFIG_IP6_NF_IPTABLES is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
@@ -452,6 +459,7 @@ CONFIG_NETFILTER_ADVANCED=y
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
@@ -461,9 +469,9 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_CONNECTOR is not set
CONFIG_MTD=m
# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
# CONFIG_MTD_CONCAT is not set
CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_TESTS is not set
# CONFIG_MTD_REDBOOT_PARTS is not set
# CONFIG_MTD_AFS_PARTS is not set
# CONFIG_MTD_AR7_PARTS is not set
@@ -499,7 +507,7 @@ CONFIG_MTD_CFI_I1=y
CONFIG_MTD_CFI_I2=y
# CONFIG_MTD_CFI_I4 is not set
# CONFIG_MTD_CFI_I8 is not set
-# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_INTELEXT=m
CONFIG_MTD_CFI_AMDSTD=m
# CONFIG_MTD_CFI_STAA is not set
CONFIG_MTD_CFI_UTIL=m
@@ -694,12 +702,10 @@ CONFIG_DM9000_DEBUGLEVEL=4
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_B44 is not set
# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
-
-#
-# Wireless LAN
-#
+CONFIG_WLAN=y
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set
@@ -734,6 +740,7 @@ CONFIG_NETPOLL=y
CONFIG_NETPOLL_TRAP=y
CONFIG_NET_POLL_CONTROLLER=y
# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
#
# Input device support
@@ -745,10 +752,7 @@ CONFIG_INPUT=y
#
# Userland interfaces
#
-CONFIG_INPUT_MOUSEDEV=m
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_JOYDEV is not set
CONFIG_INPUT_EVDEV=m
CONFIG_INPUT_EVBUG=m
@@ -757,12 +761,16 @@ CONFIG_INPUT_EVBUG=m
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
CONFIG_KEYBOARD_ATKBD=m
+# CONFIG_QT2160 is not set
# CONFIG_KEYBOARD_LKKBD is not set
CONFIG_KEYBOARD_GPIO=y
# CONFIG_KEYBOARD_MATRIX is not set
# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
# CONFIG_KEYBOARD_SUNKBD is not set
CONFIG_KEYBOARD_XTKBD=m
@@ -777,6 +785,7 @@ CONFIG_INPUT_TOUCHSCREEN=y
# CONFIG_TOUCHSCREEN_GUNZE is not set
# CONFIG_TOUCHSCREEN_ELO is not set
# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
# CONFIG_TOUCHSCREEN_MTOUCH is not set
# CONFIG_TOUCHSCREEN_INEXIO is not set
# CONFIG_TOUCHSCREEN_MK712 is not set
@@ -787,7 +796,17 @@ CONFIG_INPUT_TOUCHSCREEN=y
# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
# CONFIG_TOUCHSCREEN_TSC2007 is not set
# CONFIG_TOUCHSCREEN_W90X900 is not set
-# CONFIG_INPUT_MISC is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+CONFIG_INPUT_DM355EVM=m
+CONFIG_INPUT_DM365EVM=m
#
# Hardware I/O ports
@@ -828,13 +847,13 @@ CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_IPMI_HANDLER is not set
-CONFIG_HW_RANDOM=m
-# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_HW_RANDOM is not set
# CONFIG_R3964 is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_HELPER_AUTO=y
@@ -868,13 +887,17 @@ CONFIG_I2C_DAVINCI=y
# Miscellaneous I2C Chip support
#
# CONFIG_DS1682 is not set
-# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
# CONFIG_DEBUG_GPIO is not set
@@ -889,7 +912,7 @@ CONFIG_GPIOLIB=y
#
# CONFIG_GPIO_MAX732X is not set
# CONFIG_GPIO_PCA953X is not set
-CONFIG_GPIO_PCF857X=m
+CONFIG_GPIO_PCF857X=y
#
# PCI GPIO expanders:
@@ -898,10 +921,19 @@ CONFIG_GPIO_PCF857X=m
#
# SPI GPIO expanders:
#
+
+#
+# AC97 GPIO expanders:
+#
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
# CONFIG_SENSORS_AD7414 is not set
# CONFIG_SENSORS_AD7418 is not set
# CONFIG_SENSORS_ADM1021 is not set
@@ -950,6 +982,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
@@ -959,9 +992,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_W83L786NG is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
CONFIG_WATCHDOG=y
# CONFIG_WATCHDOG_NOWAYOUT is not set
@@ -988,7 +1019,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_CORE is not set
# CONFIG_MFD_SM501 is not set
# CONFIG_MFD_ASIC3 is not set
-# CONFIG_MFD_DM355EVM_MSP is not set
+CONFIG_MFD_DM355EVM_MSP=y
# CONFIG_HTC_EGPIO is not set
# CONFIG_HTC_PASIC3 is not set
# CONFIG_TPS65010 is not set
@@ -999,9 +1030,11 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_TC6393XB is not set
# CONFIG_PMIC_DA903X is not set
# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
# CONFIG_AB3100_CORE is not set
+# CONFIG_REGULATOR is not set
# CONFIG_MEDIA_SUPPORT is not set
#
@@ -1013,9 +1046,9 @@ CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
# CONFIG_FB_DDC is not set
# CONFIG_FB_BOOT_VESA_SUPPORT is not set
-# CONFIG_FB_CFB_FILLRECT is not set
-# CONFIG_FB_CFB_COPYAREA is not set
-# CONFIG_FB_CFB_IMAGEBLIT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
# CONFIG_FB_SYS_FILLRECT is not set
# CONFIG_FB_SYS_COPYAREA is not set
@@ -1032,6 +1065,7 @@ CONFIG_FIRMWARE_EDID=y
# Frame buffer hardware drivers
#
# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_DAVINCI=y
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FB_METRONOME is not set
# CONFIG_FB_MB862XX is not set
@@ -1101,7 +1135,6 @@ CONFIG_SND_SOC_TLV320AIC3X=m
# CONFIG_SOUND_PRIME is not set
CONFIG_HID_SUPPORT=y
CONFIG_HID=m
-# CONFIG_HID_DEBUG is not set
# CONFIG_HIDRAW is not set
#
@@ -1130,6 +1163,7 @@ CONFIG_HID_CYPRESS=m
CONFIG_HID_EZKEY=m
# CONFIG_HID_KYE is not set
CONFIG_HID_GYRATION=m
+# CONFIG_HID_TWINHAN is not set
# CONFIG_HID_KENSINGTON is not set
CONFIG_HID_LOGITECH=m
# CONFIG_LOGITECH_FF is not set
@@ -1176,6 +1210,7 @@ CONFIG_USB_MON=m
# CONFIG_USB_OXU210HP_HCD is not set
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
# CONFIG_USB_SL811_HCD is not set
# CONFIG_USB_R8A66597_HCD is not set
# CONFIG_USB_HWA_HCD is not set
@@ -1269,6 +1304,7 @@ CONFIG_USB_GADGET_SELECTED=y
# CONFIG_USB_GADGET_LH7A40X is not set
# CONFIG_USB_GADGET_OMAP is not set
# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
# CONFIG_USB_GADGET_PXA27X is not set
# CONFIG_USB_GADGET_S3C_HSOTG is not set
# CONFIG_USB_GADGET_IMX is not set
@@ -1286,6 +1322,7 @@ CONFIG_USB_ZERO=m
# CONFIG_USB_AUDIO is not set
CONFIG_USB_ETH=m
CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_ETH_EEM is not set
CONFIG_USB_GADGETFS=m
CONFIG_USB_FILE_STORAGE=m
# CONFIG_USB_FILE_STORAGE_TEST is not set
@@ -1316,8 +1353,10 @@ CONFIG_MMC_BLOCK=m
# MMC/SD/SDIO Host Controller Drivers
#
# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
+CONFIG_MMC_DAVINCI=m
# CONFIG_MEMSTICK is not set
-# CONFIG_ACCESSIBILITY is not set
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=m
@@ -1345,6 +1384,7 @@ CONFIG_LEDS_TRIGGER_HEARTBEAT=m
#
# iptables trigger is under Netfilter config (LED target)
#
+# CONFIG_ACCESSIBILITY is not set
CONFIG_RTC_LIB=y
CONFIG_RTC_CLASS=m
@@ -1370,6 +1410,7 @@ CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_DRV_PCF8563 is not set
# CONFIG_RTC_DRV_PCF8583 is not set
# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_DM355EVM is not set
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
@@ -1399,8 +1440,11 @@ CONFIG_RTC_INTF_DEV=y
#
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
-# CONFIG_REGULATOR is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1429,6 +1473,7 @@ CONFIG_XFS_FS=m
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
CONFIG_FILE_LOCKING=y
CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
@@ -1500,7 +1545,6 @@ CONFIG_MINIX_FS=m
# CONFIG_ROMFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
@@ -1596,6 +1640,7 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=1024
# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_FS=y
# CONFIG_HEADERS_CHECK is not set
@@ -1634,11 +1679,14 @@ CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+CONFIG_FRAME_POINTER=y
# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
# CONFIG_SYSCTL_SYSCALL_CHECK is not set
@@ -1663,7 +1711,7 @@ CONFIG_BRANCH_PROFILE_NONE=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
-CONFIG_ARM_UNWIND=y
+# CONFIG_ARM_UNWIND is not set
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_ERRORS=y
# CONFIG_DEBUG_STACK_USAGE is not set
@@ -1681,7 +1729,6 @@ CONFIG_CRYPTO=y
#
# Crypto core or helper
#
-# CONFIG_CRYPTO_FIPS is not set
# CONFIG_CRYPTO_MANAGER is not set
# CONFIG_CRYPTO_MANAGER2 is not set
# CONFIG_CRYPTO_GF128MUL is not set
@@ -1713,11 +1760,13 @@ CONFIG_CRYPTO=y
#
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
#
# Digest
#
# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
# CONFIG_CRYPTO_MD4 is not set
# CONFIG_CRYPTO_MD5 is not set
# CONFIG_CRYPTO_MICHAEL_MIC is not set
diff --git a/arch/arm/configs/u300_defconfig b/arch/arm/configs/u300_defconfig
index 7d61ae6e75da..953ba0297fc4 100644
--- a/arch/arm/configs/u300_defconfig
+++ b/arch/arm/configs/u300_defconfig
@@ -1,14 +1,14 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.31-rc3
-# Thu Jul 16 23:36:10 2009
+# Linux kernel version: 2.6.32-rc5
+# Sat Oct 17 23:32:24 2009
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_MMU=y
+CONFIG_HAVE_TCM=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
@@ -44,11 +44,12 @@ CONFIG_SYSVIPC_SYSCTL=y
#
# RCU Subsystem
#
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_GROUP_SCHED is not set
@@ -80,17 +81,15 @@ CONFIG_SHMEM=y
# CONFIG_AIO is not set
#
-# Performance Counters
+# Kernel Performance Events And Counters
#
# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_SLUB_DEBUG=y
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_COMPAT_BRK=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
# CONFIG_SLOB is not set
# CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
CONFIG_HAVE_OPROFILE=y
# CONFIG_KPROBES is not set
CONFIG_HAVE_KPROBES=y
@@ -133,6 +132,7 @@ CONFIG_DEFAULT_IOSCHED="deadline"
#
# System Type
#
+CONFIG_MMU=y
# CONFIG_ARCH_AAEC2000 is not set
# CONFIG_ARCH_INTEGRATOR is not set
# CONFIG_ARCH_REALVIEW is not set
@@ -147,6 +147,7 @@ CONFIG_DEFAULT_IOSCHED="deadline"
# CONFIG_ARCH_STMP3XXX is not set
# CONFIG_ARCH_NETX is not set
# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
# CONFIG_ARCH_IOP13XX is not set
# CONFIG_ARCH_IOP32X is not set
# CONFIG_ARCH_IOP33X is not set
@@ -169,11 +170,13 @@ CONFIG_DEFAULT_IOSCHED="deadline"
# CONFIG_ARCH_SA1100 is not set
# CONFIG_ARCH_S3C2410 is not set
# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
# CONFIG_ARCH_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
CONFIG_ARCH_U300=y
# CONFIG_ARCH_DAVINCI is not set
# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_BCMRING is not set
#
# ST-Ericsson AB U300/U330/U335/U365 Platform
@@ -195,6 +198,7 @@ CONFIG_MACH_U300_BS335=y
CONFIG_MACH_U300_DUAL_RAM=y
CONFIG_U300_DEBUG=y
# CONFIG_MACH_U300_SEMI_IS_SHARED is not set
+CONFIG_MACH_U300_SPIDUMMY=y
#
# All the settings below must match the bootloader's settings
@@ -207,7 +211,7 @@ CONFIG_CPU_32=y
CONFIG_CPU_ARM926T=y
CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5TJ=y
-CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_PABRT_LEGACY=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_COPY_V4WB=y
CONFIG_CPU_TLB_V4WBI=y
@@ -222,6 +226,7 @@ CONFIG_ARM_THUMB=y
# CONFIG_CPU_DCACHE_DISABLE is not set
# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+CONFIG_ARM_L1_CACHE_SHIFT=5
CONFIG_ARM_VIC=y
CONFIG_ARM_VIC_NR=2
CONFIG_COMMON_CLKDEV=y
@@ -245,6 +250,8 @@ CONFIG_VMSPLIT_3G=y
# CONFIG_VMSPLIT_2G is not set
# CONFIG_VMSPLIT_1G is not set
CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
CONFIG_PREEMPT=y
CONFIG_HZ=100
CONFIG_AEABI=y
@@ -265,6 +272,7 @@ CONFIG_ZONE_DMA_FLAG=0
CONFIG_VIRT_TO_BUS=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_ALIGNMENT_TRAP=y
# CONFIG_UACCESS_WITH_MEMCPY is not set
@@ -313,6 +321,7 @@ CONFIG_PM=y
# CONFIG_PM_DEBUG is not set
# CONFIG_SUSPEND is not set
# CONFIG_APM_EMULATION is not set
+# CONFIG_PM_RUNTIME is not set
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_NET=y
@@ -351,6 +360,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
@@ -391,6 +401,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
CONFIG_STANDALONE=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
CONFIG_FW_LOADER=y
@@ -402,9 +413,9 @@ CONFIG_EXTRA_FIRMWARE=""
# CONFIG_CONNECTOR is not set
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
# CONFIG_MTD_CONCAT is not set
CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_TESTS is not set
# CONFIG_MTD_REDBOOT_PARTS is not set
CONFIG_MTD_CMDLINE_PARTS=y
# CONFIG_MTD_AFS_PARTS is not set
@@ -453,6 +464,7 @@ CONFIG_MTD_CFI_I2=y
#
# CONFIG_MTD_DATAFLASH is not set
# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
@@ -520,6 +532,7 @@ CONFIG_HAVE_IDE=y
# CONFIG_MD is not set
# CONFIG_NETDEVICES is not set
# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
#
# Input device support
@@ -540,12 +553,16 @@ CONFIG_INPUT_EVDEV=y
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_QT2160 is not set
# CONFIG_KEYBOARD_LKKBD is not set
# CONFIG_KEYBOARD_GPIO is not set
# CONFIG_KEYBOARD_MATRIX is not set
# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
# CONFIG_KEYBOARD_SUNKBD is not set
# CONFIG_KEYBOARD_XTKBD is not set
@@ -597,6 +614,7 @@ CONFIG_LEGACY_PTY_COUNT=16
# CONFIG_TCG_TPM is not set
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
# CONFIG_I2C_CHARDEV is not set
CONFIG_I2C_HELPER_AUTO=y
@@ -629,9 +647,6 @@ CONFIG_I2C_STU300=y
# Miscellaneous I2C Chip support
#
# CONFIG_DS1682 is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
@@ -653,16 +668,21 @@ CONFIG_SPI_PL022=y
#
# CONFIG_SPI_SPIDEV is not set
# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
# CONFIG_W1 is not set
CONFIG_POWER_SUPPLY=y
# CONFIG_POWER_SUPPLY_DEBUG is not set
# CONFIG_PDA_POWER is not set
# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_DS2782 is not set
# CONFIG_BATTERY_BQ27x00 is not set
# CONFIG_BATTERY_MAX17040 is not set
# CONFIG_HWMON is not set
# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
CONFIG_WATCHDOG=y
# CONFIG_WATCHDOG_NOWAYOUT is not set
@@ -690,10 +710,24 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_TC6387XB is not set
# CONFIG_PMIC_DA903X is not set
# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
CONFIG_AB3100_CORE=y
+CONFIG_AB3100_OTP=y
# CONFIG_EZX_PCAP is not set
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_LP3971 is not set
+CONFIG_REGULATOR_AB3100=y
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
# CONFIG_MEDIA_SUPPORT is not set
#
@@ -792,9 +826,10 @@ CONFIG_MMC_BLOCK_BOUNCE=y
#
CONFIG_MMC_ARMMMCI=y
# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
# CONFIG_MMC_SPI is not set
# CONFIG_MEMSTICK is not set
-# CONFIG_ACCESSIBILITY is not set
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
@@ -820,10 +855,10 @@ CONFIG_LEDS_TRIGGER_BACKLIGHT=y
#
# iptables trigger is under Netfilter config (LED target)
#
+# CONFIG_ACCESSIBILITY is not set
CONFIG_RTC_LIB=y
CONFIG_RTC_CLASS=y
-CONFIG_RTC_HCTOSYS=y
-CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_HCTOSYS is not set
# CONFIG_RTC_DEBUG is not set
#
@@ -863,6 +898,7 @@ CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_DRV_R9701 is not set
# CONFIG_RTC_DRV_RS5C348 is not set
# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
#
# Platform RTC drivers
@@ -878,27 +914,25 @@ CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_DRV_M48T59 is not set
# CONFIG_RTC_DRV_BQ4802 is not set
# CONFIG_RTC_DRV_V3020 is not set
+CONFIG_RTC_DRV_AB3100=y
#
# on-CPU RTC drivers
#
# CONFIG_RTC_DRV_PL030 is not set
# CONFIG_RTC_DRV_PL031 is not set
+CONFIG_RTC_DRV_COH901331=y
CONFIG_DMADEVICES=y
#
# DMA Devices
#
# CONFIG_AUXDISPLAY is not set
-CONFIG_REGULATOR=y
-# CONFIG_REGULATOR_DEBUG is not set
-# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
-# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
-# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
-# CONFIG_REGULATOR_BQ24022 is not set
-# CONFIG_REGULATOR_MAX1586 is not set
-# CONFIG_REGULATOR_LP3971 is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -913,6 +947,7 @@ CONFIG_REGULATOR=y
# CONFIG_XFS_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
CONFIG_FILE_LOCKING=y
CONFIG_FSNOTIFY=y
# CONFIG_DNOTIFY is not set
@@ -975,7 +1010,6 @@ CONFIG_MISC_FILESYSTEMS=y
# CONFIG_ROMFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
# CONFIG_NETWORK_FILESYSTEMS is not set
#
@@ -1033,6 +1067,7 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=1024
# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
@@ -1066,11 +1101,13 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
# CONFIG_SYSCTL_SYSCALL_CHECK is not set
@@ -1121,6 +1158,7 @@ CONFIG_GENERIC_FIND_LAST_BIT=y
# CONFIG_CRC32 is not set
# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
+CONFIG_GENERIC_ALLOCATOR=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
diff --git a/arch/arm/include/asm/asm-offsets.h b/arch/arm/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/arm/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index c3b911ee9151..6aac3f5bb2f3 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -98,6 +98,9 @@ extern int elf_check_arch(const struct elf32_hdr *);
extern int arm_elf_read_implies_exec(const struct elf32_hdr *, int);
#define elf_read_implies_exec(ex,stk) arm_elf_read_implies_exec(&(ex), stk)
+int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs);
+#define ELF_CORE_COPY_TASK_REGS dump_task_regs
+
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
diff --git a/arch/arm/include/asm/mach-types.h b/arch/arm/include/asm/mach-types.h
new file mode 100644
index 000000000000..948178cc6ba8
--- /dev/null
+++ b/arch/arm/include/asm/mach-types.h
@@ -0,0 +1 @@
+#include <generated/mach-types.h>
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index cefedf062138..bc2ff8b28133 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -125,8 +125,10 @@
* private definitions which should NOT be used outside memory.h
* files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
*/
+#ifndef __virt_to_phys
#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET)
#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)
+#endif
/*
* Convert a physical address to a Page Frame Number and back
diff --git a/arch/arm/include/asm/socket.h b/arch/arm/include/asm/socket.h
index 92ac61d294fd..90ffd04b8e74 100644
--- a/arch/arm/include/asm/socket.h
+++ b/arch/arm/include/asm/socket.h
@@ -60,4 +60,6 @@
#define SO_PROTOCOL 38
#define SO_DOMAIN 39
+#define SO_RXQ_OVFL 40
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/arm/include/asm/swab.h b/arch/arm/include/asm/swab.h
index ca2bf2f6d6ea..9997ad20eff1 100644
--- a/arch/arm/include/asm/swab.h
+++ b/arch/arm/include/asm/swab.h
@@ -22,6 +22,24 @@
# define __SWAB_64_THRU_32__
#endif
+#if defined(__KERNEL__) && __LINUX_ARM_ARCH__ >= 6
+
+static inline __attribute_const__ __u16 __arch_swab16(__u16 x)
+{
+ __asm__ ("rev16 %0, %1" : "=r" (x) : "r" (x));
+ return x;
+}
+#define __arch_swab16 __arch_swab16
+
+static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
+{
+ __asm__ ("rev %0, %1" : "=r" (x) : "r" (x));
+ return x;
+}
+#define __arch_swab32 __arch_swab32
+
+#else
+
static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
{
__u32 t;
@@ -48,3 +66,4 @@ static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
#endif
+#endif
diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h
index a45ab5dd8255..c2f1605de359 100644
--- a/arch/arm/include/asm/tlbflush.h
+++ b/arch/arm/include/asm/tlbflush.h
@@ -350,7 +350,7 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm)
if (tlb_flag(TLB_WB))
dsb();
- if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm))) {
+ if (cpumask_test_cpu(get_cpu(), mm_cpumask(mm))) {
if (tlb_flag(TLB_V3_FULL))
asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V4_U_FULL))
@@ -360,6 +360,7 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm)
if (tlb_flag(TLB_V4_I_FULL))
asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
}
+ put_cpu();
if (tlb_flag(TLB_V6_U_ASID))
asm("mcr p15, 0, %0, c8, c7, 2" : : "r" (asid) : "cc");
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index fafce1b5c69f..f58c1156e779 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -374,6 +374,7 @@
CALL(sys_pwritev)
CALL(sys_rt_tgsigqueueinfo)
CALL(sys_perf_event_open)
+/* 365 */ CALL(sys_recvmmsg)
#ifndef syscalls_counted
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
#define syscalls_counted
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 322410be573c..0022b4d57f8b 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -608,33 +608,33 @@ call_fpe:
THUMB( add pc, r8 )
nop
- W(mov) pc, lr @ CP#0
+ movw_pc lr @ CP#0
W(b) do_fpe @ CP#1 (FPE)
W(b) do_fpe @ CP#2 (FPE)
- W(mov) pc, lr @ CP#3
+ movw_pc lr @ CP#3
#ifdef CONFIG_CRUNCH
b crunch_task_enable @ CP#4 (MaverickCrunch)
b crunch_task_enable @ CP#5 (MaverickCrunch)
b crunch_task_enable @ CP#6 (MaverickCrunch)
#else
- W(mov) pc, lr @ CP#4
- W(mov) pc, lr @ CP#5
- W(mov) pc, lr @ CP#6
+ movw_pc lr @ CP#4
+ movw_pc lr @ CP#5
+ movw_pc lr @ CP#6
#endif
- W(mov) pc, lr @ CP#7
- W(mov) pc, lr @ CP#8
- W(mov) pc, lr @ CP#9
+ movw_pc lr @ CP#7
+ movw_pc lr @ CP#8
+ movw_pc lr @ CP#9
#ifdef CONFIG_VFP
W(b) do_vfp @ CP#10 (VFP)
W(b) do_vfp @ CP#11 (VFP)
#else
- W(mov) pc, lr @ CP#10 (VFP)
- W(mov) pc, lr @ CP#11 (VFP)
+ movw_pc lr @ CP#10 (VFP)
+ movw_pc lr @ CP#11 (VFP)
#endif
- W(mov) pc, lr @ CP#12
- W(mov) pc, lr @ CP#13
- W(mov) pc, lr @ CP#14 (Debug)
- W(mov) pc, lr @ CP#15 (Control)
+ movw_pc lr @ CP#12
+ movw_pc lr @ CP#13
+ movw_pc lr @ CP#14 (Debug)
+ movw_pc lr @ CP#15 (Control)
#ifdef CONFIG_NEON
.align 6
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index ac34c0d9384b..7e9ed1eea40a 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -110,6 +110,13 @@
mov \rd, sp, lsr #13
mov \rd, \rd, lsl #13
.endm
+
+ @
+ @ 32-bit wide "mov pc, reg"
+ @
+ .macro movw_pc, reg
+ mov pc, \reg
+ .endm
#else /* CONFIG_THUMB2_KERNEL */
.macro svc_exit, rpsr
clrex @ clear the exclusive monitor
@@ -146,6 +153,14 @@
lsr \rd, \rd, #13
mov \rd, \rd, lsl #13
.endm
+
+ @
+ @ 32-bit wide "mov pc, reg"
+ @
+ .macro movw_pc, reg
+ mov pc, \reg
+ nop
+ .endm
#endif /* !CONFIG_THUMB2_KERNEL */
/*
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 790fbee92ec5..0d96d0171c05 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -328,6 +328,15 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start,
}
/*
+ * Fill in the task's elfregs structure for a core dump.
+ */
+int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs)
+{
+ elf_core_copy_regs(elfregs, task_pt_regs(t));
+ return 1;
+}
+
+/*
* fill in the fpe structure for a core dump...
*/
int dump_fpu (struct pt_regs *regs, struct user_fp *fp)
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index d581cff80c4c..a57af3e99c7c 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -131,6 +131,62 @@ void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data) {}
/* --------------------------------------------------------------------
+ * USB Host HS (EHCI)
+ * Needs an OHCI host for low and full speed management
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE)
+static u64 ehci_dmamask = DMA_BIT_MASK(32);
+static struct at91_usbh_data usbh_ehci_data;
+
+static struct resource usbh_ehci_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_EHCI_BASE,
+ .end = AT91SAM9G45_EHCI_BASE + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_UHPHS,
+ .end = AT91SAM9G45_ID_UHPHS,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91_usbh_ehci_device = {
+ .name = "atmel-ehci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &ehci_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &usbh_ehci_data,
+ },
+ .resource = usbh_ehci_resources,
+ .num_resources = ARRAY_SIZE(usbh_ehci_resources),
+};
+
+void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data)
+{
+ int i;
+
+ if (!data)
+ return;
+
+ /* Enable VBus control for UHP ports */
+ for (i = 0; i < data->ports; i++) {
+ if (data->vbus_pin[i])
+ at91_set_gpio_output(data->vbus_pin[i], 0);
+ }
+
+ usbh_ehci_data = *data;
+ at91_clock_associate("uhphs_clk", &at91_usbh_ehci_device.dev, "ehci_clk");
+ platform_device_register(&at91_usbh_ehci_device);
+}
+#else
+void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
* USB HS Device (Gadget)
* -------------------------------------------------------------------- */
@@ -838,7 +894,7 @@ static void __init at91_add_device_rtt(void)
* Watchdog
* -------------------------------------------------------------------- */
-#if defined(CONFIG_AT91SAM9_WATCHDOG) || defined(CONFIG_AT91SAM9_WATCHDOG_MODULE)
+#if defined(CONFIG_AT91SAM9X_WATCHDOG) || defined(CONFIG_AT91SAM9X_WATCHDOG_MODULE)
static struct platform_device at91sam9g45_wdt_device = {
.name = "at91_wdt",
.id = -1,
diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
index 64c3843f323d..1cf4d8681078 100644
--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
+++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
@@ -366,6 +366,7 @@ static void __init ek_board_init(void)
at91_add_device_serial();
/* USB HS Host */
at91_add_device_usbh_ohci(&ek_usbh_hs_data);
+ at91_add_device_usbh_ehci(&ek_usbh_hs_data);
/* USB HS Device */
at91_add_device_usba(&ek_usba_udc_data);
/* SPI */
diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
index 2f4fcedc02ba..2295d80dd893 100644
--- a/arch/arm/mach-at91/include/mach/board.h
+++ b/arch/arm/mach-at91/include/mach/board.h
@@ -98,6 +98,7 @@ struct at91_usbh_data {
};
extern void __init at91_add_device_usbh(struct at91_usbh_data *data);
extern void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data);
+extern void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data);
/* NAND / SmartMedia */
struct atmel_nand_data {
diff --git a/arch/arm/mach-bcmring/arch.c b/arch/arm/mach-bcmring/arch.c
index 0da693b0f7e1..074dad6b1c18 100644
--- a/arch/arm/mach-bcmring/arch.c
+++ b/arch/arm/mach-bcmring/arch.c
@@ -76,9 +76,19 @@ static struct ctl_table bcmring_sysctl_reboot[] = {
{}
};
+static struct resource nand_resource[] = {
+ [0] = {
+ .start = MM_ADDR_IO_NAND,
+ .end = MM_ADDR_IO_NAND + 0x1000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
static struct platform_device nand_device = {
.name = "bcm-nand",
.id = -1,
+ .resource = nand_resource,
+ .num_resources = ARRAY_SIZE(nand_resource),
};
static struct platform_device *devices[] __initdata = {
diff --git a/arch/arm/mach-bcmring/include/mach/reg_nand.h b/arch/arm/mach-bcmring/include/mach/reg_nand.h
new file mode 100644
index 000000000000..387376ffb56b
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/reg_nand.h
@@ -0,0 +1,66 @@
+/*****************************************************************************
+* Copyright 2001 - 2008 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+/*
+*
+*****************************************************************************
+*
+* REG_NAND.h
+*
+* PURPOSE:
+*
+* This file contains definitions for the nand registers:
+*
+* NOTES:
+*
+*****************************************************************************/
+
+#if !defined(__ASM_ARCH_REG_NAND_H)
+#define __ASM_ARCH_REG_NAND_H
+
+/* ---- Include Files ---------------------------------------------------- */
+#include <csp/reg.h>
+#include <mach/reg_umi.h>
+
+/* ---- Constants and Types ---------------------------------------------- */
+
+#define HW_NAND_BASE MM_IO_BASE_NAND /* NAND Flash */
+
+/* DMA accesses by the bootstrap need hard nonvirtual addresses */
+#define REG_NAND_CMD __REG16(HW_NAND_BASE + 0)
+#define REG_NAND_ADDR __REG16(HW_NAND_BASE + 4)
+
+#define REG_NAND_PHYS_DATA16 (HW_NAND_BASE + 8)
+#define REG_NAND_PHYS_DATA8 (HW_NAND_BASE + 8)
+#define REG_NAND_DATA16 __REG16(REG_NAND_PHYS_DATA16)
+#define REG_NAND_DATA8 __REG8(REG_NAND_PHYS_DATA8)
+
+/* use appropriate offset to make sure it start at the 1K boundary */
+#define REG_NAND_PHYS_DATA_DMA (HW_NAND_BASE + 0x400)
+#define REG_NAND_DATA_DMA __REG32(REG_NAND_PHYS_DATA_DMA)
+
+/* Linux DMA requires physical address of the data register */
+#define REG_NAND_DATA16_PADDR HW_IO_VIRT_TO_PHYS(REG_NAND_PHYS_DATA16)
+#define REG_NAND_DATA8_PADDR HW_IO_VIRT_TO_PHYS(REG_NAND_PHYS_DATA8)
+#define REG_NAND_DATA_PADDR HW_IO_VIRT_TO_PHYS(REG_NAND_PHYS_DATA_DMA)
+
+#define NAND_BUS_16BIT() (0)
+#define NAND_BUS_8BIT() (!NAND_BUS_16BIT())
+
+/* Register offsets */
+#define REG_NAND_CMD_OFFSET (0)
+#define REG_NAND_ADDR_OFFSET (4)
+#define REG_NAND_DATA8_OFFSET (8)
+
+#endif
diff --git a/arch/arm/mach-bcmring/include/mach/reg_umi.h b/arch/arm/mach-bcmring/include/mach/reg_umi.h
new file mode 100644
index 000000000000..06a355481ea6
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/reg_umi.h
@@ -0,0 +1,237 @@
+/*****************************************************************************
+* Copyright 2005 - 2008 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+/*
+*
+*****************************************************************************
+*
+* REG_UMI.h
+*
+* PURPOSE:
+*
+* This file contains definitions for the nand registers:
+*
+* NOTES:
+*
+*****************************************************************************/
+
+#if !defined(__ASM_ARCH_REG_UMI_H)
+#define __ASM_ARCH_REG_UMI_H
+
+/* ---- Include Files ---------------------------------------------------- */
+#include <csp/reg.h>
+#include <mach/csp/mm_io.h>
+
+/* ---- Constants and Types ---------------------------------------------- */
+
+/* Unified Memory Interface Ctrl Register */
+#define HW_UMI_BASE MM_IO_BASE_UMI
+
+/* Flash bank 0 timing and control register */
+#define REG_UMI_FLASH0_TCR __REG32(HW_UMI_BASE + 0x00)
+/* Flash bank 1 timing and control register */
+#define REG_UMI_FLASH1_TCR __REG32(HW_UMI_BASE + 0x04)
+/* Flash bank 2 timing and control register */
+#define REG_UMI_FLASH2_TCR __REG32(HW_UMI_BASE + 0x08)
+/* MMD interface and control register */
+#define REG_UMI_MMD_ICR __REG32(HW_UMI_BASE + 0x0c)
+/* NAND timing and control register */
+#define REG_UMI_NAND_TCR __REG32(HW_UMI_BASE + 0x18)
+/* NAND ready/chip select register */
+#define REG_UMI_NAND_RCSR __REG32(HW_UMI_BASE + 0x1c)
+/* NAND ECC control & status register */
+#define REG_UMI_NAND_ECC_CSR __REG32(HW_UMI_BASE + 0x20)
+/* NAND ECC data register XXB2B1B0 */
+#define REG_UMI_NAND_ECC_DATA __REG32(HW_UMI_BASE + 0x24)
+/* BCH ECC Parameter N */
+#define REG_UMI_BCH_N __REG32(HW_UMI_BASE + 0x40)
+/* BCH ECC Parameter T */
+#define REG_UMI_BCH_K __REG32(HW_UMI_BASE + 0x44)
+/* BCH ECC Parameter K */
+#define REG_UMI_BCH_T __REG32(HW_UMI_BASE + 0x48)
+/* BCH ECC Contro Status */
+#define REG_UMI_BCH_CTRL_STATUS __REG32(HW_UMI_BASE + 0x4C)
+/* BCH WR ECC 31:0 */
+#define REG_UMI_BCH_WR_ECC_0 __REG32(HW_UMI_BASE + 0x50)
+/* BCH WR ECC 63:32 */
+#define REG_UMI_BCH_WR_ECC_1 __REG32(HW_UMI_BASE + 0x54)
+/* BCH WR ECC 95:64 */
+#define REG_UMI_BCH_WR_ECC_2 __REG32(HW_UMI_BASE + 0x58)
+/* BCH WR ECC 127:96 */
+#define REG_UMI_BCH_WR_ECC_3 __REG32(HW_UMI_BASE + 0x5c)
+/* BCH WR ECC 155:128 */
+#define REG_UMI_BCH_WR_ECC_4 __REG32(HW_UMI_BASE + 0x60)
+/* BCH Read Error Location 1,0 */
+#define REG_UMI_BCH_RD_ERR_LOC_1_0 __REG32(HW_UMI_BASE + 0x64)
+/* BCH Read Error Location 3,2 */
+#define REG_UMI_BCH_RD_ERR_LOC_3_2 __REG32(HW_UMI_BASE + 0x68)
+/* BCH Read Error Location 5,4 */
+#define REG_UMI_BCH_RD_ERR_LOC_5_4 __REG32(HW_UMI_BASE + 0x6c)
+/* BCH Read Error Location 7,6 */
+#define REG_UMI_BCH_RD_ERR_LOC_7_6 __REG32(HW_UMI_BASE + 0x70)
+/* BCH Read Error Location 9,8 */
+#define REG_UMI_BCH_RD_ERR_LOC_9_8 __REG32(HW_UMI_BASE + 0x74)
+/* BCH Read Error Location 11,10 */
+#define REG_UMI_BCH_RD_ERR_LOC_B_A __REG32(HW_UMI_BASE + 0x78)
+
+/* REG_UMI_FLASH0/1/2_TCR, REG_UMI_SRAM0/1_TCR bits */
+/* Enable wait pin during burst write or read */
+#define REG_UMI_TCR_WAITEN 0x80000000
+/* Enable mem ctrlr to work iwth ext mem of lower freq than AHB clk */
+#define REG_UMI_TCR_LOWFREQ 0x40000000
+/* 1=synch write, 0=async write */
+#define REG_UMI_TCR_MEMTYPE_SYNCWRITE 0x20000000
+/* 1=synch read, 0=async read */
+#define REG_UMI_TCR_MEMTYPE_SYNCREAD 0x10000000
+/* 1=page mode read, 0=normal mode read */
+#define REG_UMI_TCR_MEMTYPE_PAGEREAD 0x08000000
+/* page size/burst size (wrap only) */
+#define REG_UMI_TCR_MEMTYPE_PGSZ_MASK 0x07000000
+/* 4 word */
+#define REG_UMI_TCR_MEMTYPE_PGSZ_4 0x00000000
+/* 8 word */
+#define REG_UMI_TCR_MEMTYPE_PGSZ_8 0x01000000
+/* 16 word */
+#define REG_UMI_TCR_MEMTYPE_PGSZ_16 0x02000000
+/* 32 word */
+#define REG_UMI_TCR_MEMTYPE_PGSZ_32 0x03000000
+/* 64 word */
+#define REG_UMI_TCR_MEMTYPE_PGSZ_64 0x04000000
+/* 128 word */
+#define REG_UMI_TCR_MEMTYPE_PGSZ_128 0x05000000
+/* 256 word */
+#define REG_UMI_TCR_MEMTYPE_PGSZ_256 0x06000000
+/* 512 word */
+#define REG_UMI_TCR_MEMTYPE_PGSZ_512 0x07000000
+/* Page read access cycle / Burst write latency (n+2 / n+1) */
+#define REG_UMI_TCR_TPRC_TWLC_MASK 0x00f80000
+/* Bus turnaround cycle (n) */
+#define REG_UMI_TCR_TBTA_MASK 0x00070000
+/* Write pulse width cycle (n+1) */
+#define REG_UMI_TCR_TWP_MASK 0x0000f800
+/* Write recovery cycle (n+1) */
+#define REG_UMI_TCR_TWR_MASK 0x00000600
+/* Write address setup cycle (n+1) */
+#define REG_UMI_TCR_TAS_MASK 0x00000180
+/* Output enable delay cycle (n) */
+#define REG_UMI_TCR_TOE_MASK 0x00000060
+/* Read access cycle / Burst read latency (n+2 / n+1) */
+#define REG_UMI_TCR_TRC_TLC_MASK 0x0000001f
+
+/* REG_UMI_MMD_ICR bits */
+/* Flash write protection pin control */
+#define REG_UMI_MMD_ICR_FLASH_WP 0x8000
+/* Extend hold time for sram0, sram1 csn (39 MHz operation) */
+#define REG_UMI_MMD_ICR_XHCS 0x4000
+/* Enable SDRAM 2 interface control */
+#define REG_UMI_MMD_ICR_SDRAM2EN 0x2000
+/* Enable merge of flash banks 0/1 to 512 MBit bank */
+#define REG_UMI_MMD_ICR_INST512 0x1000
+/* Enable merge of flash banks 1/2 to 512 MBit bank */
+#define REG_UMI_MMD_ICR_DATA512 0x0800
+/* Enable SDRAM interface control */
+#define REG_UMI_MMD_ICR_SDRAMEN 0x0400
+/* Polarity of busy state of Burst Wait Signal */
+#define REG_UMI_MMD_ICR_WAITPOL 0x0200
+/* Enable burst clock stopped when not accessing external burst flash/sram */
+#define REG_UMI_MMD_ICR_BCLKSTOP 0x0100
+/* Enable the peri1_csn to replace flash1_csn in 512 Mb flash mode */
+#define REG_UMI_MMD_ICR_PERI1EN 0x0080
+/* Enable the peri2_csn to replace sdram_csn */
+#define REG_UMI_MMD_ICR_PERI2EN 0x0040
+/* Enable the peri3_csn to replace sdram2_csn */
+#define REG_UMI_MMD_ICR_PERI3EN 0x0020
+/* Enable sram bank1 for H/W controlled MRS */
+#define REG_UMI_MMD_ICR_MRSB1 0x0010
+/* Enable sram bank0 for H/W controlled MRS */
+#define REG_UMI_MMD_ICR_MRSB0 0x0008
+/* Polarity for assert3ed state of H/W controlled MRS */
+#define REG_UMI_MMD_ICR_MRSPOL 0x0004
+/* 0: S/W controllable ZZ/MRS/CRE/P-Mode pin */
+/* 1: H/W controlled ZZ/MRS/CRE/P-Mode, same timing as CS */
+#define REG_UMI_MMD_ICR_MRSMODE 0x0002
+/* MRS state for S/W controlled mode */
+#define REG_UMI_MMD_ICR_MRSSTATE 0x0001
+
+/* REG_UMI_NAND_TCR bits */
+/* Enable software to control CS */
+#define REG_UMI_NAND_TCR_CS_SWCTRL 0x80000000
+/* 16-bit nand wordsize if set */
+#define REG_UMI_NAND_TCR_WORD16 0x40000000
+/* Bus turnaround cycle (n) */
+#define REG_UMI_NAND_TCR_TBTA_MASK 0x00070000
+/* Write pulse width cycle (n+1) */
+#define REG_UMI_NAND_TCR_TWP_MASK 0x0000f800
+/* Write recovery cycle (n+1) */
+#define REG_UMI_NAND_TCR_TWR_MASK 0x00000600
+/* Write address setup cycle (n+1) */
+#define REG_UMI_NAND_TCR_TAS_MASK 0x00000180
+/* Output enable delay cycle (n) */
+#define REG_UMI_NAND_TCR_TOE_MASK 0x00000060
+/* Read access cycle (n+2) */
+#define REG_UMI_NAND_TCR_TRC_TLC_MASK 0x0000001f
+
+/* REG_UMI_NAND_RCSR bits */
+/* Status: Ready=1, Busy=0 */
+#define REG_UMI_NAND_RCSR_RDY 0x02
+/* Keep CS asserted during operation */
+#define REG_UMI_NAND_RCSR_CS_ASSERTED 0x01
+
+/* REG_UMI_NAND_ECC_CSR bits */
+/* Interrupt status - read-only */
+#define REG_UMI_NAND_ECC_CSR_NANDINT 0x80000000
+/* Read: Status of ECC done, Write: clear ECC interrupt */
+#define REG_UMI_NAND_ECC_CSR_ECCINT_RAW 0x00800000
+/* Read: Status of R/B, Write: clear R/B interrupt */
+#define REG_UMI_NAND_ECC_CSR_RBINT_RAW 0x00400000
+/* 1 = Enable ECC Interrupt */
+#define REG_UMI_NAND_ECC_CSR_ECCINT_ENABLE 0x00008000
+/* 1 = Assert interrupt at rising edge of R/B_ */
+#define REG_UMI_NAND_ECC_CSR_RBINT_ENABLE 0x00004000
+/* Calculate ECC by 0=512 bytes, 1=256 bytes */
+#define REG_UMI_NAND_ECC_CSR_256BYTE 0x00000080
+/* Enable ECC in hardware */
+#define REG_UMI_NAND_ECC_CSR_ECC_ENABLE 0x00000001
+
+/* REG_UMI_BCH_CTRL_STATUS bits */
+/* Shift to Indicate Number of correctable errors detected */
+#define REG_UMI_BCH_CTRL_STATUS_NB_CORR_ERROR_SHIFT 20
+/* Indicate Number of correctable errors detected */
+#define REG_UMI_BCH_CTRL_STATUS_NB_CORR_ERROR 0x00F00000
+/* Indicate Errors detected during read but uncorrectable */
+#define REG_UMI_BCH_CTRL_STATUS_UNCORR_ERR 0x00080000
+/* Indicate Errors detected during read and are correctable */
+#define REG_UMI_BCH_CTRL_STATUS_CORR_ERR 0x00040000
+/* Flag indicates BCH's ECC status of read process are valid */
+#define REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID 0x00020000
+/* Flag indicates BCH's ECC status of write process are valid */
+#define REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID 0x00010000
+/* Pause ECC calculation */
+#define REG_UMI_BCH_CTRL_STATUS_PAUSE_ECC_DEC 0x00000010
+/* Enable Interrupt */
+#define REG_UMI_BCH_CTRL_STATUS_INT_EN 0x00000004
+/* Enable ECC during read */
+#define REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN 0x00000002
+/* Enable ECC during write */
+#define REG_UMI_BCH_CTRL_STATUS_ECC_WR_EN 0x00000001
+/* Mask for location */
+#define REG_UMI_BCH_ERR_LOC_MASK 0x00001FFF
+/* location within a byte */
+#define REG_UMI_BCH_ERR_LOC_BYTE 0x00000007
+/* location within a word */
+#define REG_UMI_BCH_ERR_LOC_WORD 0x00000018
+/* location within a page (512 byte) */
+#define REG_UMI_BCH_ERR_LOC_PAGE 0x00001FE0
+#define REG_UMI_BCH_ERR_LOC_ADDR(index) (__REG32(HW_UMI_BASE + 0x64 + (index / 2)*4) >> ((index % 2) * 16))
+#endif
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig
index 40866c643f13..3a3447a67928 100644
--- a/arch/arm/mach-davinci/Kconfig
+++ b/arch/arm/mach-davinci/Kconfig
@@ -32,6 +32,8 @@ config ARCH_DAVINCI_DA830
bool "DA830/OMAP-L137 based system"
select CP_INTC
select ARCH_DAVINCI_DA8XX
+ select ARCH_HAS_CPUFREQ
+ select CPU_DCACHE_WRITETHROUGH # needed on silicon revs 1.0, 1.1
config ARCH_DAVINCI_DA850
bool "DA850/OMAP-L138 based system"
@@ -101,6 +103,27 @@ config MACH_DAVINCI_DA830_EVM
help
Say Y here to select the TI DA830/OMAP-L137 Evaluation Module.
+config DA830_UI
+ bool "DA830/OMAP-L137 UI (User Interface) board support"
+ depends on MACH_DAVINCI_DA830_EVM
+ help
+ Say Y here if you have the DA830/OMAP-L137 UI
+ (User Interface) board installed and you want to
+ enable the peripherals located on User Interface
+ board.
+
+choice
+ prompt "Select DA830/OMAP-L137 UI board peripheral"
+ depends on DA830_UI
+
+config DA830_UI_LCD
+ bool "LCD"
+ help
+ Say Y here to use the LCD as a framebuffer or simple character
+ display.
+
+endchoice
+
config MACH_DAVINCI_DA850_EVM
bool "TI DA850/OMAP-L138 Reference Platform"
default ARCH_DAVINCI_DA850
@@ -108,6 +131,37 @@ config MACH_DAVINCI_DA850_EVM
help
Say Y here to select the TI DA850/OMAP-L138 Evaluation Module.
+config DA850_UI_EXP
+ bool "DA850/OMAP-L138 UI (User Interface) board expander configuration"
+ depends on MACH_DAVINCI_DA850_EVM
+ select GPIO_PCA953X
+ help
+ Say Y here if you have the DA850/OMAP-L138 UI
+ (User Interface) board installed and you want to
+ enable the peripherals located on User Interface
+ board contorlled by TCA6416 expander.
+
+choice
+ prompt "Select peripherals connected to expander on UI board"
+ depends on DA850_UI_EXP
+
+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
+
+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
+ the EVM.
+ NOTE: Please take care while choosing this option, MII PHY will
+ not be functional if RMII mode is selected.
+
+endchoice
+
config DAVINCI_MUX
bool "DAVINCI multiplexing support"
depends on ARCH_DAVINCI
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
index 2e11e847313b..be629c54e212 100644
--- a/arch/arm/mach-davinci/Makefile
+++ b/arch/arm/mach-davinci/Makefile
@@ -29,3 +29,6 @@ obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM) += board-dm646x-evm.o
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
+
+# Power Management
+obj-$(CONFIG_CPU_FREQ) += cpufreq.o
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index bfbb63936f33..bfa790297f79 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -10,20 +10,21 @@
* or implied.
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/console.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
#include <linux/i2c.h>
+#include <linux/i2c/pcf857x.h>
#include <linux/i2c/at24.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/common.h>
-#include <mach/irqs.h>
#include <mach/cp_intc.h>
+#include <mach/mux.h>
#include <mach/da8xx.h>
-#include <mach/asp.h>
+#include <mach/usb.h>
#define DA830_EVM_PHY_MASK 0x0
#define DA830_EVM_MDIO_FREQUENCY 2200000 /* PHY bus frequency */
@@ -36,6 +37,31 @@ static struct at24_platform_data da830_evm_i2c_eeprom_info = {
.context = (void *)0x7f00,
};
+static int da830_evm_ui_expander_setup(struct i2c_client *client, int gpio,
+ unsigned ngpio, void *context)
+{
+ gpio_request(gpio + 6, "MUX_MODE");
+#ifdef CONFIG_DA830_UI_LCD
+ gpio_direction_output(gpio + 6, 0);
+#else /* Must be NAND or NOR */
+ gpio_direction_output(gpio + 6, 1);
+#endif
+ return 0;
+}
+
+static int da830_evm_ui_expander_teardown(struct i2c_client *client, int gpio,
+ unsigned ngpio, void *context)
+{
+ gpio_free(gpio + 6);
+ return 0;
+}
+
+static struct pcf857x_platform_data da830_evm_ui_expander_info = {
+ .gpio_base = DAVINCI_N_GPIO,
+ .setup = da830_evm_ui_expander_setup,
+ .teardown = da830_evm_ui_expander_teardown,
+};
+
static struct i2c_board_info __initdata da830_evm_i2c_devices[] = {
{
I2C_BOARD_INFO("24c256", 0x50),
@@ -43,7 +69,11 @@ static struct i2c_board_info __initdata da830_evm_i2c_devices[] = {
},
{
I2C_BOARD_INFO("tlv320aic3x", 0x18),
- }
+ },
+ {
+ I2C_BOARD_INFO("pcf8574", 0x3f),
+ .platform_data = &da830_evm_ui_expander_info,
+ },
};
static struct davinci_i2c_platform_data da830_evm_i2c_0_pdata = {
@@ -51,10 +81,139 @@ static struct davinci_i2c_platform_data da830_evm_i2c_0_pdata = {
.bus_delay = 0, /* usec */
};
+/*
+ * USB1 VBUS is controlled by GPIO1[15], over-current is reported on GPIO2[4].
+ */
+#define ON_BD_USB_DRV GPIO_TO_PIN(1, 15)
+#define ON_BD_USB_OVC GPIO_TO_PIN(2, 4)
+
+static const short da830_evm_usb11_pins[] = {
+ DA830_GPIO1_15, DA830_GPIO2_4,
+ -1
+};
+
+static da8xx_ocic_handler_t da830_evm_usb_ocic_handler;
+
+static int da830_evm_usb_set_power(unsigned port, int on)
+{
+ gpio_set_value(ON_BD_USB_DRV, on);
+ return 0;
+}
+
+static int da830_evm_usb_get_power(unsigned port)
+{
+ return gpio_get_value(ON_BD_USB_DRV);
+}
+
+static int da830_evm_usb_get_oci(unsigned port)
+{
+ return !gpio_get_value(ON_BD_USB_OVC);
+}
+
+static irqreturn_t da830_evm_usb_ocic_irq(int, void *);
+
+static int da830_evm_usb_ocic_notify(da8xx_ocic_handler_t handler)
+{
+ int irq = gpio_to_irq(ON_BD_USB_OVC);
+ int error = 0;
+
+ if (handler != NULL) {
+ da830_evm_usb_ocic_handler = handler;
+
+ error = request_irq(irq, da830_evm_usb_ocic_irq, IRQF_DISABLED |
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "OHCI over-current indicator", NULL);
+ if (error)
+ printk(KERN_ERR "%s: could not request IRQ to watch "
+ "over-current indicator changes\n", __func__);
+ } else
+ free_irq(irq, NULL);
+
+ return error;
+}
+
+static struct da8xx_ohci_root_hub da830_evm_usb11_pdata = {
+ .set_power = da830_evm_usb_set_power,
+ .get_power = da830_evm_usb_get_power,
+ .get_oci = da830_evm_usb_get_oci,
+ .ocic_notify = da830_evm_usb_ocic_notify,
+
+ /* TPS2065 switch @ 5V */
+ .potpgt = (3 + 1) / 2, /* 3 ms max */
+};
+
+static irqreturn_t da830_evm_usb_ocic_irq(int irq, void *dev_id)
+{
+ da830_evm_usb_ocic_handler(&da830_evm_usb11_pdata, 1);
+ return IRQ_HANDLED;
+}
+
+static __init void da830_evm_usb_init(void)
+{
+ u32 cfgchip2;
+ int ret;
+
+ /*
+ * Set up USB clock/mode in the CFGCHIP2 register.
+ * FYI: CFGCHIP2 is 0x0000ef00 initially.
+ */
+ cfgchip2 = __raw_readl(DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP2_REG));
+
+ /* USB2.0 PHY reference clock is 24 MHz */
+ cfgchip2 &= ~CFGCHIP2_REFFREQ;
+ cfgchip2 |= CFGCHIP2_REFFREQ_24MHZ;
+
+ /*
+ * Select internal reference clock for USB 2.0 PHY
+ * and use it as a clock source for USB 1.1 PHY
+ * (this is the default setting anyway).
+ */
+ cfgchip2 &= ~CFGCHIP2_USB1PHYCLKMUX;
+ cfgchip2 |= CFGCHIP2_USB2PHYCLKMUX;
+
+ __raw_writel(cfgchip2, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP2_REG));
+
+ ret = da8xx_pinmux_setup(da830_evm_usb11_pins);
+ if (ret) {
+ pr_warning("%s: USB 1.1 PinMux setup failed: %d\n",
+ __func__, ret);
+ return;
+ }
+
+ ret = gpio_request(ON_BD_USB_DRV, "ON_BD_USB_DRV");
+ if (ret) {
+ printk(KERN_ERR "%s: failed to request GPIO for USB 1.1 port "
+ "power control: %d\n", __func__, ret);
+ return;
+ }
+ gpio_direction_output(ON_BD_USB_DRV, 0);
+
+ ret = gpio_request(ON_BD_USB_OVC, "ON_BD_USB_OVC");
+ if (ret) {
+ printk(KERN_ERR "%s: failed to request GPIO for USB 1.1 port "
+ "over-current indicator: %d\n", __func__, ret);
+ return;
+ }
+ gpio_direction_input(ON_BD_USB_OVC);
+
+ ret = da8xx_register_usb11(&da830_evm_usb11_pdata);
+ if (ret)
+ pr_warning("%s: USB 1.1 registration failed: %d\n",
+ __func__, ret);
+}
+
static struct davinci_uart_config da830_evm_uart_config __initdata = {
.enabled_uarts = 0x7,
};
+static const short da830_evm_mcasp1_pins[] = {
+ DA830_AHCLKX1, DA830_ACLKX1, DA830_AFSX1, DA830_AHCLKR1, DA830_AFSR1,
+ DA830_AMUTE1, DA830_AXR1_0, DA830_AXR1_1, DA830_AXR1_2, DA830_AXR1_5,
+ DA830_ACLKR1, DA830_AXR1_6, DA830_AXR1_7, DA830_AXR1_8, DA830_AXR1_10,
+ DA830_AXR1_11,
+ -1
+};
+
static u8 da830_iis_serializer_direction[] = {
RX_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
INACTIVE_MODE, TX_MODE, INACTIVE_MODE, INACTIVE_MODE,
@@ -74,6 +233,57 @@ static struct snd_platform_data da830_evm_snd_data = {
.rxnumevt = 1,
};
+/*
+ * GPIO2[1] is used as MMC_SD_WP and GPIO2[2] as MMC_SD_INS.
+ */
+static const short da830_evm_mmc_sd_pins[] = {
+ DA830_MMCSD_DAT_0, DA830_MMCSD_DAT_1, DA830_MMCSD_DAT_2,
+ DA830_MMCSD_DAT_3, DA830_MMCSD_DAT_4, DA830_MMCSD_DAT_5,
+ DA830_MMCSD_DAT_6, DA830_MMCSD_DAT_7, DA830_MMCSD_CLK,
+ DA830_MMCSD_CMD, DA830_GPIO2_1, DA830_GPIO2_2,
+ -1
+};
+
+#define DA830_MMCSD_WP_PIN GPIO_TO_PIN(2, 1)
+
+static int da830_evm_mmc_get_ro(int index)
+{
+ return gpio_get_value(DA830_MMCSD_WP_PIN);
+}
+
+static struct davinci_mmc_config da830_evm_mmc_config = {
+ .get_ro = da830_evm_mmc_get_ro,
+ .wires = 4,
+ .version = MMC_CTLR_VERSION_2,
+};
+
+static inline void da830_evm_init_mmc(void)
+{
+ int ret;
+
+ ret = da8xx_pinmux_setup(da830_evm_mmc_sd_pins);
+ if (ret) {
+ pr_warning("da830_evm_init: mmc/sd mux setup failed: %d\n",
+ ret);
+ return;
+ }
+
+ ret = gpio_request(DA830_MMCSD_WP_PIN, "MMC WP");
+ if (ret) {
+ pr_warning("da830_evm_init: can not open GPIO %d\n",
+ DA830_MMCSD_WP_PIN);
+ return;
+ }
+ gpio_direction_input(DA830_MMCSD_WP_PIN);
+
+ ret = da8xx_register_mmcsd0(&da830_evm_mmc_config);
+ if (ret) {
+ pr_warning("da830_evm_init: mmc/sd registration failed: %d\n",
+ ret);
+ gpio_free(DA830_MMCSD_WP_PIN);
+ }
+}
+
static __init void da830_evm_init(void)
{
struct davinci_soc_info *soc_info = &davinci_soc_info;
@@ -94,6 +304,8 @@ static __init void da830_evm_init(void)
pr_warning("da830_evm_init: i2c0 registration failed: %d\n",
ret);
+ 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;
@@ -117,12 +329,29 @@ static __init void da830_evm_init(void)
i2c_register_board_info(1, da830_evm_i2c_devices,
ARRAY_SIZE(da830_evm_i2c_devices));
- ret = da8xx_pinmux_setup(da830_mcasp1_pins);
+ ret = da8xx_pinmux_setup(da830_evm_mcasp1_pins);
if (ret)
pr_warning("da830_evm_init: mcasp1 mux setup failed: %d\n",
ret);
- da8xx_init_mcasp(1, &da830_evm_snd_data);
+ da8xx_register_mcasp(1, &da830_evm_snd_data);
+
+ da830_evm_init_mmc();
+
+#ifdef CONFIG_DA830_UI_LCD
+ ret = da8xx_pinmux_setup(da830_lcdcntl_pins);
+ if (ret)
+ pr_warning("da830_evm_init: lcdcntl mux setup failed: %d\n",
+ ret);
+
+ ret = da8xx_register_lcdc(&sharp_lcd035q3dg01_pdata);
+ if (ret)
+ pr_warning("da830_evm_init: lcd setup failed: %d\n", ret);
+#endif
+
+ ret = da8xx_register_rtc();
+ if (ret)
+ pr_warning("da830_evm_init: rtc setup failed: %d\n", ret);
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
@@ -146,7 +375,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 EVM")
.phys_io = IO_PHYS,
.io_pg_offst = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
.boot_params = (DA8XX_DDR_BASE + 0x100),
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index c759d72494e0..23e2024c3d9b 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -12,36 +12,38 @@
* or implied.
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/i2c.h>
#include <linux/i2c/at24.h>
+#include <linux/i2c/pca953x.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
+#include <linux/regulator/machine.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/common.h>
-#include <mach/irqs.h>
#include <mach/cp_intc.h>
#include <mach/da8xx.h>
#include <mach/nand.h>
+#include <mach/mux.h>
#define DA850_EVM_PHY_MASK 0x1
#define DA850_EVM_MDIO_FREQUENCY 2200000 /* PHY bus frequency */
+#define DA850_LCD_PWR_PIN GPIO_TO_PIN(2, 8)
#define DA850_LCD_BL_PIN GPIO_TO_PIN(2, 15)
-#define DA850_LCD_PWR_PIN GPIO_TO_PIN(8, 10)
#define DA850_MMCSD_CD_PIN GPIO_TO_PIN(4, 0)
#define DA850_MMCSD_WP_PIN GPIO_TO_PIN(4, 1)
+#define DA850_MII_MDIO_CLKEN_PIN GPIO_TO_PIN(2, 6)
+
static struct mtd_partition da850_evm_norflash_partition[] = {
{
.name = "NOR filesystem",
@@ -143,10 +145,90 @@ static struct platform_device da850_evm_nandflash_device = {
.resource = da850_evm_nandflash_resource,
};
+static u32 ui_card_detected;
+static void da850_evm_setup_nor_nand(void);
+
+static int da850_evm_ui_expander_setup(struct i2c_client *client, unsigned gpio,
+ unsigned ngpio, void *c)
+{
+ struct davinci_soc_info *soc_info = &davinci_soc_info;
+ int sel_a, sel_b, sel_c, ret;
+
+ sel_a = gpio + 7;
+ sel_b = gpio + 6;
+ sel_c = gpio + 5;
+
+ ret = gpio_request(sel_a, "sel_a");
+ if (ret) {
+ pr_warning("Cannot open UI expander pin %d\n", sel_a);
+ goto exp_setup_sela_fail;
+ }
+
+ ret = gpio_request(sel_b, "sel_b");
+ if (ret) {
+ pr_warning("Cannot open UI expander pin %d\n", sel_b);
+ goto exp_setup_selb_fail;
+ }
+
+ ret = gpio_request(sel_c, "sel_c");
+ if (ret) {
+ pr_warning("Cannot open UI expander pin %d\n", sel_c);
+ goto exp_setup_selc_fail;
+ }
+
+ /* deselect all functionalities */
+ gpio_direction_output(sel_a, 1);
+ gpio_direction_output(sel_b, 1);
+ gpio_direction_output(sel_c, 1);
+
+ ui_card_detected = 1;
+ pr_info("DA850/OMAP-L138 EVM UI card detected\n");
+
+ da850_evm_setup_nor_nand();
+
+ if (soc_info->emac_pdata->rmii_en)
+ /* enable RMII */
+ gpio_set_value(sel_a, 0);
+
+ return 0;
+
+exp_setup_selc_fail:
+ gpio_free(sel_b);
+exp_setup_selb_fail:
+ gpio_free(sel_a);
+exp_setup_sela_fail:
+ return ret;
+}
+
+static int da850_evm_ui_expander_teardown(struct i2c_client *client,
+ unsigned gpio, unsigned ngpio, void *c)
+{
+ /* deselect all functionalities */
+ gpio_set_value(gpio + 5, 1);
+ gpio_set_value(gpio + 6, 1);
+ gpio_set_value(gpio + 7, 1);
+
+ gpio_free(gpio + 5);
+ gpio_free(gpio + 6);
+ gpio_free(gpio + 7);
+
+ return 0;
+}
+
+static struct pca953x_platform_data da850_evm_ui_expander_info = {
+ .gpio_base = DAVINCI_N_GPIO,
+ .setup = da850_evm_ui_expander_setup,
+ .teardown = da850_evm_ui_expander_teardown,
+};
+
static struct i2c_board_info __initdata da850_evm_i2c_devices[] = {
{
I2C_BOARD_INFO("tlv320aic3x", 0x18),
- }
+ },
+ {
+ I2C_BOARD_INFO("tca6416", 0x20),
+ .platform_data = &da850_evm_ui_expander_info,
+ },
};
static struct davinci_i2c_platform_data da850_evm_i2c_0_pdata = {
@@ -250,12 +332,152 @@ static void __init da850_evm_init_nor(void)
iounmap(aemif_addr);
}
-#if defined(CONFIG_MTD_PHYSMAP) || \
- defined(CONFIG_MTD_PHYSMAP_MODULE)
-#define HAS_NOR 1
-#else
-#define HAS_NOR 0
-#endif
+/* TPS65070 voltage regulator support */
+
+/* 3.3V */
+struct regulator_consumer_supply tps65070_dcdc1_consumers[] = {
+ {
+ .supply = "usb0_vdda33",
+ },
+ {
+ .supply = "usb1_vdda33",
+ },
+};
+
+/* 3.3V or 1.8V */
+struct regulator_consumer_supply tps65070_dcdc2_consumers[] = {
+ {
+ .supply = "dvdd3318_a",
+ },
+ {
+ .supply = "dvdd3318_b",
+ },
+ {
+ .supply = "dvdd3318_c",
+ },
+};
+
+/* 1.2V */
+struct regulator_consumer_supply tps65070_dcdc3_consumers[] = {
+ {
+ .supply = "cvdd",
+ },
+};
+
+/* 1.8V LDO */
+struct regulator_consumer_supply tps65070_ldo1_consumers[] = {
+ {
+ .supply = "sata_vddr",
+ },
+ {
+ .supply = "usb0_vdda18",
+ },
+ {
+ .supply = "usb1_vdda18",
+ },
+ {
+ .supply = "ddr_dvdd18",
+ },
+};
+
+/* 1.2V LDO */
+struct regulator_consumer_supply tps65070_ldo2_consumers[] = {
+ {
+ .supply = "sata_vdd",
+ },
+ {
+ .supply = "pll0_vdda",
+ },
+ {
+ .supply = "pll1_vdda",
+ },
+ {
+ .supply = "usbs_cvdd",
+ },
+ {
+ .supply = "vddarnwa1",
+ },
+};
+
+struct regulator_init_data tps65070_regulator_data[] = {
+ /* dcdc1 */
+ {
+ .constraints = {
+ .min_uV = 3150000,
+ .max_uV = 3450000,
+ .valid_ops_mask = (REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS),
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(tps65070_dcdc1_consumers),
+ .consumer_supplies = tps65070_dcdc1_consumers,
+ },
+
+ /* dcdc2 */
+ {
+ .constraints = {
+ .min_uV = 1710000,
+ .max_uV = 3450000,
+ .valid_ops_mask = (REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS),
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(tps65070_dcdc2_consumers),
+ .consumer_supplies = tps65070_dcdc2_consumers,
+ },
+
+ /* dcdc3 */
+ {
+ .constraints = {
+ .min_uV = 950000,
+ .max_uV = 1320000,
+ .valid_ops_mask = (REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS),
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(tps65070_dcdc3_consumers),
+ .consumer_supplies = tps65070_dcdc3_consumers,
+ },
+
+ /* ldo1 */
+ {
+ .constraints = {
+ .min_uV = 1710000,
+ .max_uV = 1890000,
+ .valid_ops_mask = (REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS),
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(tps65070_ldo1_consumers),
+ .consumer_supplies = tps65070_ldo1_consumers,
+ },
+
+ /* ldo2 */
+ {
+ .constraints = {
+ .min_uV = 1140000,
+ .max_uV = 1320000,
+ .valid_ops_mask = (REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS),
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(tps65070_ldo2_consumers),
+ .consumer_supplies = tps65070_ldo2_consumers,
+ },
+};
+
+static struct i2c_board_info __initdata da850evm_tps65070_info[] = {
+ {
+ I2C_BOARD_INFO("tps6507x", 0x48),
+ .platform_data = &tps65070_regulator_data[0],
+ },
+};
+
+static int __init pmic_tps65070_init(void)
+{
+ return i2c_register_board_info(1, da850evm_tps65070_info,
+ ARRAY_SIZE(da850evm_tps65070_info));
+}
#if defined(CONFIG_MMC_DAVINCI) || \
defined(CONFIG_MMC_DAVINCI_MODULE)
@@ -264,25 +486,94 @@ static void __init da850_evm_init_nor(void)
#define HAS_MMC 0
#endif
-static __init void da850_evm_init(void)
+static void da850_evm_setup_nor_nand(void)
{
- struct davinci_soc_info *soc_info = &davinci_soc_info;
+ int ret = 0;
+
+ if (ui_card_detected & !HAS_MMC) {
+ ret = da8xx_pinmux_setup(da850_nand_pins);
+ if (ret)
+ pr_warning("da850_evm_init: nand mux setup failed: "
+ "%d\n", ret);
+
+ ret = da8xx_pinmux_setup(da850_nor_pins);
+ if (ret)
+ pr_warning("da850_evm_init: nor mux setup failed: %d\n",
+ ret);
+
+ da850_evm_init_nor();
+
+ platform_add_devices(da850_evm_devices,
+ ARRAY_SIZE(da850_evm_devices));
+ }
+}
+
+static const short da850_evm_lcdc_pins[] = {
+ DA850_GPIO2_8, DA850_GPIO2_15,
+ -1
+};
+
+static int __init da850_evm_config_emac(u8 rmii_en)
+{
+ void __iomem *cfg_chip3_base;
int ret;
+ u32 val;
+
+ cfg_chip3_base = DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG);
+
+ /* configure the CFGCHIP3 register for RMII or MII */
+ val = __raw_readl(cfg_chip3_base);
+ if (rmii_en)
+ val |= BIT(8);
+ else
+ val &= ~BIT(8);
- ret = da8xx_pinmux_setup(da850_nand_pins);
+ __raw_writel(val, cfg_chip3_base);
+
+ if (!rmii_en)
+ ret = da8xx_pinmux_setup(da850_cpgmac_pins);
+ else
+ ret = da8xx_pinmux_setup(da850_rmii_pins);
if (ret)
- pr_warning("da850_evm_init: nand mux setup failed: %d\n",
+ pr_warning("da850_evm_init: cpgmac/rmii mux setup failed: %d\n",
ret);
- ret = da8xx_pinmux_setup(da850_nor_pins);
+ ret = davinci_cfg_reg(DA850_GPIO2_6);
if (ret)
- pr_warning("da850_evm_init: nor mux setup failed: %d\n",
- ret);
+ pr_warning("da850_evm_init:GPIO(2,6) mux setup "
+ "failed\n");
+
+ ret = gpio_request(DA850_MII_MDIO_CLKEN_PIN, "mdio_clk_en");
+ if (ret) {
+ pr_warning("Cannot open GPIO %d\n",
+ DA850_MII_MDIO_CLKEN_PIN);
+ return ret;
+ }
+
+ if (rmii_en) {
+ /* Disable MII MDIO clock */
+ gpio_direction_output(DA850_MII_MDIO_CLKEN_PIN, 1);
+ pr_info("EMAC: RMII PHY configured, MII PHY will not be"
+ " functional\n");
+ } else {
+ /* Enable MII MDIO clock */
+ gpio_direction_output(DA850_MII_MDIO_CLKEN_PIN, 0);
+ pr_info("EMAC: MII PHY configured, RMII PHY will not be"
+ " functional\n");
+ }
+
+ return 0;
+}
- da850_evm_init_nor();
+static __init void da850_evm_init(void)
+{
+ struct davinci_soc_info *soc_info = &davinci_soc_info;
+ int ret;
- platform_add_devices(da850_evm_devices,
- ARRAY_SIZE(da850_evm_devices));
+ ret = pmic_tps65070_init();
+ if (ret)
+ pr_warning("da850_evm_init: TPS65070 PMIC init failed: %d\n",
+ ret);
ret = da8xx_register_edma();
if (ret)
@@ -301,12 +592,15 @@ static __init void da850_evm_init(void)
soc_info->emac_pdata->phy_mask = DA850_EVM_PHY_MASK;
soc_info->emac_pdata->mdio_max_freq = DA850_EVM_MDIO_FREQUENCY;
+#ifdef CONFIG_DA850_UI_RMII
+ soc_info->emac_pdata->rmii_en = 1;
+#else
soc_info->emac_pdata->rmii_en = 0;
+#endif
- ret = da8xx_pinmux_setup(da850_cpgmac_pins);
+ ret = da850_evm_config_emac(soc_info->emac_pdata->rmii_en);
if (ret)
- pr_warning("da850_evm_init: cpgmac mux setup failed: %d\n",
- ret);
+ pr_warning("da850_evm_init: emac setup failed: %d\n", ret);
ret = da8xx_register_emac();
if (ret)
@@ -319,11 +613,6 @@ static __init void da850_evm_init(void)
ret);
if (HAS_MMC) {
- if (HAS_NOR)
- pr_warning("WARNING: both NOR Flash and MMC/SD are "
- "enabled, but they share AEMIF pins.\n"
- "\tDisable one of them.\n");
-
ret = da8xx_pinmux_setup(da850_mmcsd0_pins);
if (ret)
pr_warning("da850_evm_init: mmcsd0 mux setup failed:"
@@ -365,22 +654,37 @@ static __init void da850_evm_init(void)
pr_warning("da850_evm_init: mcasp mux setup failed: %d\n",
ret);
- da8xx_init_mcasp(0, &da850_evm_snd_data);
+ da8xx_register_mcasp(0, &da850_evm_snd_data);
ret = da8xx_pinmux_setup(da850_lcdcntl_pins);
if (ret)
pr_warning("da850_evm_init: lcdcntl mux setup failed: %d\n",
ret);
+ /* Handle board specific muxing for LCD here */
+ ret = da8xx_pinmux_setup(da850_evm_lcdc_pins);
+ if (ret)
+ pr_warning("da850_evm_init: evm specific lcd mux setup "
+ "failed: %d\n", ret);
+
ret = da850_lcd_hw_init();
if (ret)
pr_warning("da850_evm_init: lcd initialization failed: %d\n",
ret);
- ret = da8xx_register_lcdc();
+ ret = da8xx_register_lcdc(&sharp_lk043t1dg01_pdata);
if (ret)
pr_warning("da850_evm_init: lcdc registration failed: %d\n",
ret);
+
+ ret = da8xx_register_rtc();
+ if (ret)
+ pr_warning("da850_evm_init: rtc setup failed: %d\n", ret);
+
+ ret = da850_register_cpufreq();
+ if (ret)
+ pr_warning("da850_evm_init: cpufreq registration failed: %d\n",
+ ret);
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c
index 77e806798822..42b24a7d46cd 100644
--- a/arch/arm/mach-davinci/board-dm355-evm.c
+++ b/arch/arm/mach-davinci/board-dm355-evm.c
@@ -9,15 +9,13 @@
* or implied.
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
-#include <linux/dma-mapping.h>
+#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
#include <linux/i2c.h>
-#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/clk.h>
#include <linux/videodev2.h>
@@ -25,15 +23,10 @@
#include <linux/spi/spi.h>
#include <linux/spi/eeprom.h>
-#include <asm/setup.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/flash.h>
-#include <mach/hardware.h>
#include <mach/dm355.h>
-#include <mach/psc.h>
#include <mach/common.h>
#include <mach/i2c.h>
#include <mach/serial.h>
@@ -86,8 +79,9 @@ static struct davinci_nand_pdata davinci_nand_data = {
.mask_chipsel = BIT(14),
.parts = davinci_nand_partitions,
.nr_parts = ARRAY_SIZE(davinci_nand_partitions),
- .ecc_mode = NAND_ECC_HW_SYNDROME,
+ .ecc_mode = NAND_ECC_HW,
.options = NAND_USE_FLASH_BBT,
+ .ecc_bits = 4,
};
static struct resource davinci_nand_resources[] = {
diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c
index 84ad5d161a87..d9dcc2f3f7de 100644
--- a/arch/arm/mach-davinci/board-dm355-leopard.c
+++ b/arch/arm/mach-davinci/board-dm355-leopard.c
@@ -8,29 +8,22 @@
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
-#include <linux/dma-mapping.h>
+#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
#include <linux/i2c.h>
-#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/clk.h>
#include <linux/spi/spi.h>
#include <linux/spi/eeprom.h>
-#include <asm/setup.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/flash.h>
-#include <mach/hardware.h>
#include <mach/dm355.h>
-#include <mach/psc.h>
#include <mach/common.h>
#include <mach/i2c.h>
#include <mach/serial.h>
diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c
index 52dd8046b305..19678dc91b09 100644
--- a/arch/arm/mach-davinci/board-dm365-evm.c
+++ b/arch/arm/mach-davinci/board-dm365-evm.c
@@ -13,9 +13,8 @@
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
-#include <linux/dma-mapping.h>
+#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/clk.h>
@@ -24,20 +23,19 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
-#include <asm/setup.h>
+#include <linux/input.h>
+
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
+
#include <mach/mux.h>
-#include <mach/hardware.h>
#include <mach/dm365.h>
-#include <mach/psc.h>
#include <mach/common.h>
#include <mach/i2c.h>
#include <mach/serial.h>
#include <mach/mmc.h>
#include <mach/nand.h>
-
+#include <mach/keyscan.h>
static inline int have_imager(void)
{
@@ -144,6 +142,7 @@ static struct davinci_nand_pdata davinci_nand_data = {
.nr_parts = ARRAY_SIZE(davinci_nand_partitions),
.ecc_mode = NAND_ECC_HW,
.options = NAND_USE_FLASH_BBT,
+ .ecc_bits = 4,
};
static struct resource davinci_nand_resources[] = {
@@ -176,11 +175,16 @@ static struct at24_platform_data eeprom_info = {
.context = (void *)0x7f00,
};
+static struct snd_platform_data dm365_evm_snd_data;
+
static struct i2c_board_info i2c_info[] = {
{
I2C_BOARD_INFO("24c256", 0x50),
.platform_data = &eeprom_info,
},
+ {
+ I2C_BOARD_INFO("tlv320aic3x", 0x18),
+ },
};
static struct davinci_i2c_platform_data i2c_pdata = {
@@ -188,6 +192,38 @@ static struct davinci_i2c_platform_data i2c_pdata = {
.bus_delay = 0 /* usec */,
};
+#ifdef CONFIG_KEYBOARD_DAVINCI
+static unsigned short dm365evm_keymap[] = {
+ KEY_KP2,
+ KEY_LEFT,
+ KEY_EXIT,
+ KEY_DOWN,
+ KEY_ENTER,
+ KEY_UP,
+ KEY_KP1,
+ KEY_RIGHT,
+ KEY_MENU,
+ KEY_RECORD,
+ KEY_REWIND,
+ KEY_KPMINUS,
+ KEY_STOP,
+ KEY_FASTFORWARD,
+ KEY_KPPLUS,
+ KEY_PLAYPAUSE,
+ 0
+};
+
+static struct davinci_ks_platform_data dm365evm_ks_data = {
+ .keymap = dm365evm_keymap,
+ .keymapsize = ARRAY_SIZE(dm365evm_keymap),
+ .rep = 1,
+ /* Scan period = strobe + interval */
+ .strobe = 0x5,
+ .interval = 0x2,
+ .matrix_type = DAVINCI_KEYSCAN_MATRIX_4X4,
+};
+#endif
+
static int cpld_mmc_get_cd(int module)
{
if (!cpld)
@@ -472,6 +508,12 @@ static __init void dm365_evm_init(void)
/* maybe setup mmc1/etc ... _after_ mmc0 */
evm_init_cpld();
+
+ dm365_init_asp(&dm365_evm_snd_data);
+
+#ifdef CONFIG_KEYBOARD_DAVINCI
+ dm365_init_ks(&dm365evm_ks_data);
+#endif
}
static __init void dm365_evm_irq_init(void)
diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c
index 1213a0087ad4..00a80467b491 100644
--- a/arch/arm/mach-davinci/board-dm644x-evm.c
+++ b/arch/arm/mach-davinci/board-dm644x-evm.c
@@ -9,45 +9,33 @@
* or implied.
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
-#include <linux/leds.h>
-#include <linux/memory.h>
-
#include <linux/i2c.h>
#include <linux/i2c/pcf857x.h>
#include <linux/i2c/at24.h>
-#include <linux/etherdevice.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
-#include <linux/io.h>
#include <linux/phy.h>
#include <linux/clk.h>
#include <linux/videodev2.h>
#include <media/tvp514x.h>
-#include <asm/setup.h>
#include <asm/mach-types.h>
-
#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/flash.h>
#include <mach/dm644x.h>
#include <mach/common.h>
#include <mach/i2c.h>
#include <mach/serial.h>
#include <mach/mux.h>
-#include <mach/psc.h>
#include <mach/nand.h>
#include <mach/mmc.h>
-#include <mach/emac.h>
#define DM644X_EVM_PHY_MASK (0x2)
#define DM644X_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */
diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c
index 24e0e13b1492..75b2b6fb8594 100644
--- a/arch/arm/mach-davinci/board-dm646x-evm.c
+++ b/arch/arm/mach-davinci/board-dm646x-evm.c
@@ -17,38 +17,28 @@
**************************************************************************/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/major.h>
-#include <linux/root_dev.h>
-#include <linux/dma-mapping.h>
-#include <linux/serial.h>
-#include <linux/serial_8250.h>
#include <linux/leds.h>
#include <linux/gpio.h>
-#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/i2c/at24.h>
#include <linux/i2c/pcf857x.h>
-#include <linux/etherdevice.h>
#include <media/tvp514x.h>
-#include <asm/setup.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/flash.h>
#include <mach/dm646x.h>
#include <mach/common.h>
-#include <mach/psc.h>
#include <mach/serial.h>
#include <mach/i2c.h>
-#include <mach/mmc.h>
-#include <mach/emac.h>
+#include <mach/nand.h>
#if defined(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \
defined(CONFIG_BLK_DEV_PALMCHIP_BK3710_MODULE)
@@ -57,6 +47,11 @@
#define HAS_ATA 0
#endif
+#define DAVINCI_ASYNC_EMIF_CONTROL_BASE 0x20008000
+#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE 0x42000000
+
+#define NAND_BLOCK_SIZE SZ_128K
+
/* CPLD Register 0 bits to control ATA */
#define DM646X_EVM_ATA_RST BIT(0)
#define DM646X_EVM_ATA_PWD BIT(1)
@@ -92,6 +87,63 @@ static struct davinci_uart_config uart_config __initdata = {
.enabled_uarts = (1 << 0),
};
+/* Note: We are setting first partition as 'bootloader' constituting UBL, U-Boot
+ * and U-Boot environment this avoids dependency on any particular combination
+ * of UBL, U-Boot or flashing tools etc.
+ */
+static struct mtd_partition davinci_nand_partitions[] = {
+ {
+ /* UBL, U-Boot with environment */
+ .name = "bootloader",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 16 * NAND_BLOCK_SIZE,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ }, {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_4M,
+ .mask_flags = 0,
+ }, {
+ .name = "filesystem",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ .mask_flags = 0,
+ }
+};
+
+static struct davinci_nand_pdata davinci_nand_data = {
+ .mask_cle = 0x80000,
+ .mask_ale = 0x40000,
+ .parts = davinci_nand_partitions,
+ .nr_parts = ARRAY_SIZE(davinci_nand_partitions),
+ .ecc_mode = NAND_ECC_HW,
+ .options = 0,
+};
+
+static struct resource davinci_nand_resources[] = {
+ {
+ .start = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE,
+ .end = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE + SZ_32M - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = DAVINCI_ASYNC_EMIF_CONTROL_BASE,
+ .end = DAVINCI_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device davinci_nand_device = {
+ .name = "davinci_nand",
+ .id = 0,
+
+ .num_resources = ARRAY_SIZE(davinci_nand_resources),
+ .resource = davinci_nand_resources,
+
+ .dev = {
+ .platform_data = &davinci_nand_data,
+ },
+};
+
/* CPLD Register 0 Client: used for I/O Control */
static int cpld_reg0_probe(struct i2c_client *client,
const struct i2c_device_id *id)
@@ -647,6 +699,8 @@ static __init void evm_init(void)
dm646x_init_mcasp0(&dm646x_evm_snd_data[0]);
dm646x_init_mcasp1(&dm646x_evm_snd_data[1]);
+ platform_device_register(&davinci_nand_device);
+
if (HAS_ATA)
dm646x_init_ide();
diff --git a/arch/arm/mach-davinci/board-sffsdr.c b/arch/arm/mach-davinci/board-sffsdr.c
index 7acdfd8ac071..e6654877b9cf 100644
--- a/arch/arm/mach-davinci/board-sffsdr.c
+++ b/arch/arm/mach-davinci/board-sffsdr.c
@@ -23,34 +23,22 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
-#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
-#include <linux/gpio.h>
-
#include <linux/i2c.h>
#include <linux/i2c/at24.h>
-#include <linux/etherdevice.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
-#include <linux/io.h>
-#include <asm/setup.h>
#include <asm/mach-types.h>
-
#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
#include <asm/mach/flash.h>
#include <mach/dm644x.h>
#include <mach/common.h>
#include <mach/i2c.h>
#include <mach/serial.h>
-#include <mach/psc.h>
#include <mach/mux.h>
#define SFFSDR_PHY_MASK (0x2)
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
index 83d54d50b5ea..baece65cb9c0 100644
--- a/arch/arm/mach-davinci/clock.c
+++ b/arch/arm/mach-davinci/clock.c
@@ -17,8 +17,8 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/mutex.h>
-#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/delay.h>
#include <mach/hardware.h>
@@ -42,8 +42,7 @@ static void __clk_enable(struct clk *clk)
if (clk->parent)
__clk_enable(clk->parent);
if (clk->usecount++ == 0 && (clk->flags & CLK_PSC))
- davinci_psc_config(psc_domain(clk), clk->psc_ctlr,
- clk->lpsc, 1);
+ davinci_psc_config(psc_domain(clk), clk->gpsc, clk->lpsc, 1);
}
static void __clk_disable(struct clk *clk)
@@ -51,8 +50,7 @@ static void __clk_disable(struct clk *clk)
if (WARN_ON(clk->usecount == 0))
return;
if (--clk->usecount == 0 && !(clk->flags & CLK_PLL))
- davinci_psc_config(psc_domain(clk), clk->psc_ctlr,
- clk->lpsc, 0);
+ davinci_psc_config(psc_domain(clk), clk->gpsc, clk->lpsc, 0);
if (clk->parent)
__clk_disable(clk->parent);
}
@@ -99,20 +97,74 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
if (clk == NULL || IS_ERR(clk))
return -EINVAL;
+ if (clk->round_rate)
+ return clk->round_rate(clk, rate);
+
return clk->rate;
}
EXPORT_SYMBOL(clk_round_rate);
+/* Propagate rate to children */
+static void propagate_rate(struct clk *root)
+{
+ struct clk *clk;
+
+ list_for_each_entry(clk, &root->children, childnode) {
+ if (clk->recalc)
+ clk->rate = clk->recalc(clk);
+ propagate_rate(clk);
+ }
+}
+
int clk_set_rate(struct clk *clk, unsigned long rate)
{
+ unsigned long flags;
+ int ret = -EINVAL;
+
if (clk == NULL || IS_ERR(clk))
- return -EINVAL;
+ return ret;
- /* changing the clk rate is not supported */
- return -EINVAL;
+ spin_lock_irqsave(&clockfw_lock, flags);
+ if (clk->set_rate)
+ ret = clk->set_rate(clk, rate);
+ if (ret == 0) {
+ if (clk->recalc)
+ clk->rate = clk->recalc(clk);
+ propagate_rate(clk);
+ }
+ spin_unlock_irqrestore(&clockfw_lock, flags);
+
+ return ret;
}
EXPORT_SYMBOL(clk_set_rate);
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ unsigned long flags;
+
+ if (clk == NULL || IS_ERR(clk))
+ return -EINVAL;
+
+ /* Cannot change parent on enabled clock */
+ if (WARN_ON(clk->usecount))
+ return -EINVAL;
+
+ mutex_lock(&clocks_mutex);
+ clk->parent = parent;
+ list_del_init(&clk->childnode);
+ list_add(&clk->childnode, &clk->parent->children);
+ mutex_unlock(&clocks_mutex);
+
+ spin_lock_irqsave(&clockfw_lock, flags);
+ if (clk->recalc)
+ clk->rate = clk->recalc(clk);
+ propagate_rate(clk);
+ spin_unlock_irqrestore(&clockfw_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
int clk_register(struct clk *clk)
{
if (clk == NULL || IS_ERR(clk))
@@ -123,16 +175,24 @@ int clk_register(struct clk *clk)
clk->name, clk->parent->name))
return -EINVAL;
+ INIT_LIST_HEAD(&clk->children);
+
mutex_lock(&clocks_mutex);
list_add_tail(&clk->node, &clocks);
+ if (clk->parent)
+ list_add_tail(&clk->childnode, &clk->parent->children);
mutex_unlock(&clocks_mutex);
/* If rate is already set, use it */
if (clk->rate)
return 0;
+ /* Else, see if there is a way to calculate it */
+ if (clk->recalc)
+ clk->rate = clk->recalc(clk);
+
/* Otherwise, default to parent rate */
- if (clk->parent)
+ else if (clk->parent)
clk->rate = clk->parent->rate;
return 0;
@@ -146,6 +206,7 @@ void clk_unregister(struct clk *clk)
mutex_lock(&clocks_mutex);
list_del(&clk->node);
+ list_del(&clk->childnode);
mutex_unlock(&clocks_mutex);
}
EXPORT_SYMBOL(clk_unregister);
@@ -166,11 +227,11 @@ static int __init clk_disable_unused(void)
continue;
/* ignore if in Disabled or SwRstDisable states */
- if (!davinci_psc_is_clk_active(ck->psc_ctlr, ck->lpsc))
+ if (!davinci_psc_is_clk_active(ck->gpsc, ck->lpsc))
continue;
pr_info("Clocks: disable unused %s\n", ck->name);
- davinci_psc_config(psc_domain(ck), ck->psc_ctlr, ck->lpsc, 0);
+ davinci_psc_config(psc_domain(ck), ck->gpsc, ck->lpsc, 0);
}
spin_unlock_irq(&clockfw_lock);
@@ -179,50 +240,62 @@ static int __init clk_disable_unused(void)
late_initcall(clk_disable_unused);
#endif
-static void clk_sysclk_recalc(struct clk *clk)
+static unsigned long clk_sysclk_recalc(struct clk *clk)
{
u32 v, plldiv;
struct pll_data *pll;
+ unsigned long rate = clk->rate;
/* If this is the PLL base clock, no more calculations needed */
if (clk->pll_data)
- return;
+ return rate;
if (WARN_ON(!clk->parent))
- return;
+ return rate;
- clk->rate = clk->parent->rate;
+ rate = clk->parent->rate;
/* Otherwise, the parent must be a PLL */
if (WARN_ON(!clk->parent->pll_data))
- return;
+ return rate;
pll = clk->parent->pll_data;
/* If pre-PLL, source clock is before the multiplier and divider(s) */
if (clk->flags & PRE_PLL)
- clk->rate = pll->input_rate;
+ rate = pll->input_rate;
if (!clk->div_reg)
- return;
+ return rate;
v = __raw_readl(pll->base + clk->div_reg);
if (v & PLLDIV_EN) {
plldiv = (v & PLLDIV_RATIO_MASK) + 1;
if (plldiv)
- clk->rate /= plldiv;
+ rate /= plldiv;
}
+
+ return rate;
+}
+
+static unsigned long clk_leafclk_recalc(struct clk *clk)
+{
+ if (WARN_ON(!clk->parent))
+ return clk->rate;
+
+ return clk->parent->rate;
}
-static void __init clk_pll_init(struct clk *clk)
+static unsigned long clk_pllclk_recalc(struct clk *clk)
{
u32 ctrl, mult = 1, prediv = 1, postdiv = 1;
u8 bypass;
struct pll_data *pll = clk->pll_data;
+ unsigned long rate = clk->rate;
pll->base = IO_ADDRESS(pll->phys_base);
ctrl = __raw_readl(pll->base + PLLCTL);
- clk->rate = pll->input_rate = clk->parent->rate;
+ rate = pll->input_rate = clk->parent->rate;
if (ctrl & PLLCTL_PLLEN) {
bypass = 0;
@@ -255,9 +328,9 @@ static void __init clk_pll_init(struct clk *clk)
}
if (!bypass) {
- clk->rate /= prediv;
- clk->rate *= mult;
- clk->rate /= postdiv;
+ rate /= prediv;
+ rate *= mult;
+ rate /= postdiv;
}
pr_debug("PLL%d: input = %lu MHz [ ",
@@ -270,8 +343,90 @@ static void __init clk_pll_init(struct clk *clk)
pr_debug("* %d ", mult);
if (postdiv > 1)
pr_debug("/ %d ", postdiv);
- pr_debug("] --> %lu MHz output.\n", clk->rate / 1000000);
+ pr_debug("] --> %lu MHz output.\n", rate / 1000000);
+
+ return rate;
+}
+
+/**
+ * davinci_set_pllrate - set the output rate of a given PLL.
+ *
+ * Note: Currently tested to work with OMAP-L138 only.
+ *
+ * @pll: pll whose rate needs to be changed.
+ * @prediv: The pre divider value. Passing 0 disables the pre-divider.
+ * @pllm: The multiplier value. Passing 0 leads to multiply-by-one.
+ * @postdiv: The post divider value. Passing 0 disables the post-divider.
+ */
+int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv,
+ unsigned int mult, unsigned int postdiv)
+{
+ u32 ctrl;
+ unsigned int locktime;
+
+ if (pll->base == NULL)
+ return -EINVAL;
+
+ /*
+ * PLL lock time required per OMAP-L138 datasheet is
+ * (2000 * prediv)/sqrt(pllm) OSCIN cycles. We approximate sqrt(pllm)
+ * as 4 and OSCIN cycle as 25 MHz.
+ */
+ if (prediv) {
+ locktime = ((2000 * prediv) / 100);
+ prediv = (prediv - 1) | PLLDIV_EN;
+ } else {
+ locktime = 20;
+ }
+ if (postdiv)
+ postdiv = (postdiv - 1) | PLLDIV_EN;
+ if (mult)
+ mult = mult - 1;
+
+ ctrl = __raw_readl(pll->base + PLLCTL);
+
+ /* Switch the PLL to bypass mode */
+ ctrl &= ~(PLLCTL_PLLENSRC | PLLCTL_PLLEN);
+ __raw_writel(ctrl, pll->base + PLLCTL);
+
+ /*
+ * Wait for 4 OSCIN/CLKIN cycles to ensure that the PLLC has switched
+ * to bypass mode. Delay of 1us ensures we are good for all > 4MHz
+ * OSCIN/CLKIN inputs. Typically the input is ~25MHz.
+ */
+ udelay(1);
+
+ /* Reset and enable PLL */
+ ctrl &= ~(PLLCTL_PLLRST | PLLCTL_PLLDIS);
+ __raw_writel(ctrl, pll->base + PLLCTL);
+
+ if (pll->flags & PLL_HAS_PREDIV)
+ __raw_writel(prediv, pll->base + PREDIV);
+
+ __raw_writel(mult, pll->base + PLLM);
+
+ if (pll->flags & PLL_HAS_POSTDIV)
+ __raw_writel(postdiv, pll->base + POSTDIV);
+
+ /*
+ * Wait for PLL to reset properly, OMAP-L138 datasheet says
+ * 'min' time = 125ns
+ */
+ udelay(1);
+
+ /* Bring PLL out of reset */
+ ctrl |= PLLCTL_PLLRST;
+ __raw_writel(ctrl, pll->base + PLLCTL);
+
+ udelay(locktime);
+
+ /* Remove PLL from bypass mode */
+ ctrl |= PLLCTL_PLLEN;
+ __raw_writel(ctrl, pll->base + PLLCTL);
+
+ return 0;
}
+EXPORT_SYMBOL(davinci_set_pllrate);
int __init davinci_clk_init(struct davinci_clk *clocks)
{
@@ -281,12 +436,23 @@ int __init davinci_clk_init(struct davinci_clk *clocks)
for (c = clocks; c->lk.clk; c++) {
clk = c->lk.clk;
- if (clk->pll_data)
- clk_pll_init(clk);
+ if (!clk->recalc) {
+
+ /* Check if clock is a PLL */
+ if (clk->pll_data)
+ clk->recalc = clk_pllclk_recalc;
+
+ /* Else, if it is a PLL-derived clock */
+ else if (clk->flags & CLK_PLL)
+ clk->recalc = clk_sysclk_recalc;
+
+ /* Otherwise, it is a leaf clock (PSC clock) */
+ else if (clk->parent)
+ clk->recalc = clk_leafclk_recalc;
+ }
- /* Calculate rates for PLL-derived clocks */
- else if (clk->flags & CLK_PLL)
- clk_sysclk_recalc(clk);
+ if (clk->recalc)
+ clk->rate = clk->recalc(clk);
if (clk->lpsc)
clk->flags |= CLK_PSC;
@@ -352,9 +518,8 @@ dump_clock(struct seq_file *s, unsigned nest, struct clk *parent)
/* REVISIT show device associations too */
/* cost is now small, but not linear... */
- list_for_each_entry(clk, &clocks, node) {
- if (clk->parent == parent)
- dump_clock(s, nest + NEST_DELTA, clk);
+ list_for_each_entry(clk, &parent->children, childnode) {
+ dump_clock(s, nest + NEST_DELTA, clk);
}
}
diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h
index 27233cb4a2fb..c92d77a3008d 100644
--- a/arch/arm/mach-davinci/clock.h
+++ b/arch/arm/mach-davinci/clock.h
@@ -22,6 +22,10 @@
/* PLL/Reset register offsets */
#define PLLCTL 0x100
#define PLLCTL_PLLEN BIT(0)
+#define PLLCTL_PLLPWRDN BIT(1)
+#define PLLCTL_PLLRST BIT(3)
+#define PLLCTL_PLLDIS BIT(4)
+#define PLLCTL_PLLENSRC BIT(5)
#define PLLCTL_CLKMODE BIT(8)
#define PLLM 0x110
@@ -65,15 +69,20 @@ struct clk {
const char *name;
unsigned long rate;
u8 usecount;
- u8 flags;
u8 lpsc;
- u8 psc_ctlr;
+ u8 gpsc;
+ u32 flags;
struct clk *parent;
+ struct list_head children; /* list of children */
+ struct list_head childnode; /* parent's child list node */
struct pll_data *pll_data;
u32 div_reg;
+ unsigned long (*recalc) (struct clk *);
+ int (*set_rate) (struct clk *clk, unsigned long rate);
+ int (*round_rate) (struct clk *clk, unsigned long rate);
};
-/* Clock flags */
+/* Clock flags: SoC-specific flags start at BIT(16) */
#define ALWAYS_ENABLED BIT(1)
#define CLK_PSC BIT(2)
#define PSC_DSP BIT(3) /* PSC uses DSP domain, not ARM */
@@ -94,6 +103,8 @@ struct davinci_clk {
}
int davinci_clk_init(struct davinci_clk *clocks);
+int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv,
+ unsigned int mult, unsigned int postdiv);
extern struct platform_device davinci_wdt_device;
diff --git a/arch/arm/mach-davinci/common.c b/arch/arm/mach-davinci/common.c
index 61ede19c6b54..c2de94cde56a 100644
--- a/arch/arm/mach-davinci/common.c
+++ b/arch/arm/mach-davinci/common.c
@@ -86,6 +86,8 @@ void __init davinci_common_init(struct davinci_soc_info *soc_info)
dip = davinci_get_id(davinci_soc_info.jtag_id);
if (!dip) {
ret = -EINVAL;
+ pr_err("Unknown DaVinci JTAG ID 0x%x\n",
+ davinci_soc_info.jtag_id);
goto err;
}
@@ -104,5 +106,5 @@ void __init davinci_common_init(struct davinci_soc_info *soc_info)
return;
err:
- pr_err("davinci_common_init: SoC Initialization failed\n");
+ panic("davinci_common_init: SoC Initialization failed\n");
}
diff --git a/arch/arm/mach-davinci/cp_intc.c b/arch/arm/mach-davinci/cp_intc.c
index 96c8e97a7deb..52b287cf3a42 100644
--- a/arch/arm/mach-davinci/cp_intc.c
+++ b/arch/arm/mach-davinci/cp_intc.c
@@ -10,9 +10,6 @@
*/
#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/io.h>
diff --git a/arch/arm/mach-davinci/cpufreq.c b/arch/arm/mach-davinci/cpufreq.c
new file mode 100644
index 000000000000..8c8c07b12d87
--- /dev/null
+++ b/arch/arm/mach-davinci/cpufreq.c
@@ -0,0 +1,219 @@
+/*
+ * CPU frequency scaling for DaVinci
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * Based on linux/arch/arm/plat-omap/cpu-omap.c. Original Copyright follows:
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Written by Tony Lindgren <tony@atomide.com>
+ *
+ * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King
+ *
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Updated to support OMAP3
+ * Rajendra Nayak <rnayak@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/types.h>
+#include <linux/cpufreq.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <mach/hardware.h>
+#include <mach/cpufreq.h>
+#include <mach/common.h>
+
+#include "clock.h"
+
+struct davinci_cpufreq {
+ struct device *dev;
+ struct clk *armclk;
+};
+static struct davinci_cpufreq cpufreq;
+
+static int davinci_verify_speed(struct cpufreq_policy *policy)
+{
+ struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data;
+ struct cpufreq_frequency_table *freq_table = pdata->freq_table;
+ struct clk *armclk = cpufreq.armclk;
+
+ if (freq_table)
+ return cpufreq_frequency_table_verify(policy, freq_table);
+
+ if (policy->cpu)
+ return -EINVAL;
+
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+
+ policy->min = clk_round_rate(armclk, policy->min * 1000) / 1000;
+ policy->max = clk_round_rate(armclk, policy->max * 1000) / 1000;
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+ return 0;
+}
+
+static unsigned int davinci_getspeed(unsigned int cpu)
+{
+ if (cpu)
+ return 0;
+
+ return clk_get_rate(cpufreq.armclk) / 1000;
+}
+
+static int davinci_target(struct cpufreq_policy *policy,
+ unsigned int target_freq, unsigned int relation)
+{
+ int ret = 0;
+ unsigned int idx;
+ struct cpufreq_freqs freqs;
+ struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data;
+ struct clk *armclk = cpufreq.armclk;
+
+ /*
+ * Ensure desired rate is within allowed range. Some govenors
+ * (ondemand) will just pass target_freq=0 to get the minimum.
+ */
+ if (target_freq < policy->cpuinfo.min_freq)
+ target_freq = policy->cpuinfo.min_freq;
+ if (target_freq > policy->cpuinfo.max_freq)
+ target_freq = policy->cpuinfo.max_freq;
+
+ freqs.old = davinci_getspeed(0);
+ freqs.new = clk_round_rate(armclk, target_freq * 1000) / 1000;
+ freqs.cpu = 0;
+
+ if (freqs.old == freqs.new)
+ return ret;
+
+ cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER,
+ dev_driver_string(cpufreq.dev),
+ "transition: %u --> %u\n", freqs.old, freqs.new);
+
+ ret = cpufreq_frequency_table_target(policy, pdata->freq_table,
+ freqs.new, relation, &idx);
+ if (ret)
+ return -EINVAL;
+
+ 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);
+
+ ret = clk_set_rate(armclk, idx);
+
+ /* if moving to lower freq, lower the voltage after lowering freq */
+ if (pdata->set_voltage && freqs.new < freqs.old)
+ pdata->set_voltage(idx);
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ return ret;
+}
+
+static int __init davinci_cpu_init(struct cpufreq_policy *policy)
+{
+ int result = 0;
+ struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data;
+ struct cpufreq_frequency_table *freq_table = pdata->freq_table;
+
+ if (policy->cpu != 0)
+ return -EINVAL;
+
+ policy->cur = policy->min = policy->max = davinci_getspeed(0);
+
+ if (freq_table) {
+ result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ if (!result)
+ cpufreq_frequency_table_get_attr(freq_table,
+ policy->cpu);
+ } else {
+ policy->cpuinfo.min_freq = policy->min;
+ policy->cpuinfo.max_freq = policy->max;
+ }
+
+ policy->min = policy->cpuinfo.min_freq;
+ policy->max = policy->cpuinfo.max_freq;
+ policy->cur = davinci_getspeed(0);
+
+ /*
+ * Time measurement across the target() function yields ~1500-1800us
+ * time taken with no drivers on notification list.
+ * Setting the latency to 2000 us to accomodate addition of drivers
+ * to pre/post change notification list.
+ */
+ policy->cpuinfo.transition_latency = 2000 * 1000;
+ return 0;
+}
+
+static int davinci_cpu_exit(struct cpufreq_policy *policy)
+{
+ cpufreq_frequency_table_put_attr(policy->cpu);
+ return 0;
+}
+
+static struct freq_attr *davinci_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static struct cpufreq_driver davinci_driver = {
+ .flags = CPUFREQ_STICKY,
+ .verify = davinci_verify_speed,
+ .target = davinci_target,
+ .get = davinci_getspeed,
+ .init = davinci_cpu_init,
+ .exit = davinci_cpu_exit,
+ .name = "davinci",
+ .attr = davinci_cpufreq_attr,
+};
+
+static int __init davinci_cpufreq_probe(struct platform_device *pdev)
+{
+ struct davinci_cpufreq_config *pdata = pdev->dev.platform_data;
+
+ if (!pdata)
+ return -EINVAL;
+ if (!pdata->freq_table)
+ return -EINVAL;
+
+ cpufreq.dev = &pdev->dev;
+
+ cpufreq.armclk = clk_get(NULL, "arm");
+ if (IS_ERR(cpufreq.armclk)) {
+ dev_err(cpufreq.dev, "Unable to get ARM clock\n");
+ return PTR_ERR(cpufreq.armclk);
+ }
+
+ return cpufreq_register_driver(&davinci_driver);
+}
+
+static int __exit davinci_cpufreq_remove(struct platform_device *pdev)
+{
+ clk_put(cpufreq.armclk);
+
+ return cpufreq_unregister_driver(&davinci_driver);
+}
+
+static struct platform_driver davinci_cpufreq_driver = {
+ .driver = {
+ .name = "cpufreq-davinci",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(davinci_cpufreq_remove),
+};
+
+static int __init davinci_cpufreq_init(void)
+{
+ return platform_driver_probe(&davinci_cpufreq_driver,
+ davinci_cpufreq_probe);
+}
+late_initcall(davinci_cpufreq_init);
+
diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c
index 19b2748357fc..b22b5cf04250 100644
--- a/arch/arm/mach-davinci/da830.c
+++ b/arch/arm/mach-davinci/da830.c
@@ -8,22 +8,17 @@
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
-#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/clk.h>
-#include <linux/platform_device.h>
#include <asm/mach/map.h>
-#include <mach/clock.h>
#include <mach/psc.h>
-#include <mach/mux.h>
#include <mach/irqs.h>
#include <mach/cputype.h>
#include <mach/common.h>
#include <mach/time.h>
#include <mach/da8xx.h>
-#include <mach/asp.h>
#include "clock.h"
#include "mux.h"
@@ -193,14 +188,14 @@ static struct clk uart1_clk = {
.name = "uart1",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_UART1,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk uart2_clk = {
.name = "uart2",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_UART2,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk spi0_clk = {
@@ -213,98 +208,98 @@ static struct clk spi1_clk = {
.name = "spi1",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_SPI1,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk ecap0_clk = {
.name = "ecap0",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_ECAP,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk ecap1_clk = {
.name = "ecap1",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_ECAP,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk ecap2_clk = {
.name = "ecap2",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_ECAP,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk pwm0_clk = {
.name = "pwm0",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_PWM,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk pwm1_clk = {
.name = "pwm1",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_PWM,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk pwm2_clk = {
.name = "pwm2",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_PWM,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk eqep0_clk = {
.name = "eqep0",
.parent = &pll0_sysclk2,
.lpsc = DA830_LPSC1_EQEP,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk eqep1_clk = {
.name = "eqep1",
.parent = &pll0_sysclk2,
.lpsc = DA830_LPSC1_EQEP,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk lcdc_clk = {
.name = "lcdc",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_LCDC,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk mcasp0_clk = {
.name = "mcasp0",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_McASP0,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk mcasp1_clk = {
.name = "mcasp1",
.parent = &pll0_sysclk2,
.lpsc = DA830_LPSC1_McASP1,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk mcasp2_clk = {
.name = "mcasp2",
.parent = &pll0_sysclk2,
.lpsc = DA830_LPSC1_McASP2,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk usb20_clk = {
.name = "usb20",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_USB20,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk aemif_clk = {
@@ -332,36 +327,36 @@ static struct clk emac_clk = {
.name = "emac",
.parent = &pll0_sysclk4,
.lpsc = DA8XX_LPSC1_CPGMAC,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk gpio_clk = {
.name = "gpio",
.parent = &pll0_sysclk4,
.lpsc = DA8XX_LPSC1_GPIO,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk i2c1_clk = {
.name = "i2c1",
.parent = &pll0_sysclk4,
.lpsc = DA8XX_LPSC1_I2C,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk usb11_clk = {
.name = "usb11",
.parent = &pll0_sysclk4,
.lpsc = DA8XX_LPSC1_USB11,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk emif3_clk = {
.name = "emif3",
.parent = &pll0_sysclk5,
.lpsc = DA8XX_LPSC1_EMIF3C,
+ .gpsc = 1,
.flags = ALWAYS_ENABLED,
- .psc_ctlr = 1,
};
static struct clk arm_clk = {
@@ -411,7 +406,7 @@ static struct davinci_clk da830_clks[] = {
CLK(NULL, "pwm2", &pwm2_clk),
CLK("eqep.0", NULL, &eqep0_clk),
CLK("eqep.1", NULL, &eqep1_clk),
- CLK("da830_lcdc", NULL, &lcdc_clk),
+ CLK("da8xx_lcdc.0", NULL, &lcdc_clk),
CLK("davinci-mcasp.0", NULL, &mcasp0_clk),
CLK("davinci-mcasp.1", NULL, &mcasp1_clk),
CLK("davinci-mcasp.2", NULL, &mcasp2_clk),
@@ -1143,7 +1138,21 @@ static struct davinci_id da830_ids[] = {
.part_no = 0xb7df,
.manufacturer = 0x017, /* 0x02f >> 1 */
.cpu_id = DAVINCI_CPU_ID_DA830,
- .name = "da830/omap l137",
+ .name = "da830/omap-l137 rev1.0",
+ },
+ {
+ .variant = 0x8,
+ .part_no = 0xb7df,
+ .manufacturer = 0x017,
+ .cpu_id = DAVINCI_CPU_ID_DA830,
+ .name = "da830/omap-l137 rev1.1",
+ },
+ {
+ .variant = 0x9,
+ .part_no = 0xb7df,
+ .manufacturer = 0x017,
+ .cpu_id = DAVINCI_CPU_ID_DA830,
+ .name = "da830/omap-l137 rev2.0",
},
};
@@ -1178,13 +1187,11 @@ static struct davinci_timer_info da830_timer_info = {
static struct davinci_soc_info davinci_soc_info_da830 = {
.io_desc = da830_io_desc,
.io_desc_num = ARRAY_SIZE(da830_io_desc),
- .jtag_id_base = IO_ADDRESS(DA8XX_JTAG_ID_REG),
.ids = da830_ids,
.ids_num = ARRAY_SIZE(da830_ids),
.cpu_clks = da830_clks,
.psc_bases = da830_psc_bases,
.psc_bases_num = ARRAY_SIZE(da830_psc_bases),
- .pinmux_base = IO_ADDRESS(DA8XX_BOOT_CFG_BASE + 0x120),
.pinmux_pins = da830_pins,
.pinmux_pins_num = ARRAY_SIZE(da830_pins),
.intc_base = (void __iomem *)DA8XX_CP_INTC_VIRT,
@@ -1201,5 +1208,13 @@ static struct davinci_soc_info davinci_soc_info_da830 = {
void __init da830_init(void)
{
+ da8xx_syscfg_base = ioremap(DA8XX_SYSCFG_BASE, SZ_4K);
+ if (WARN(!da8xx_syscfg_base, "Unable to map syscfg module"))
+ return;
+
+ davinci_soc_info_da830.jtag_id_base =
+ DA8XX_SYSCFG_VIRT(DA8XX_JTAG_ID_REG);
+ davinci_soc_info_da830.pinmux_base = DA8XX_SYSCFG_VIRT(0x120);
+
davinci_common_init(&davinci_soc_info_da830);
}
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 192d719a47df..0f27c93545bf 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -11,31 +11,41 @@
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
-#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/cpufreq.h>
+#include <linux/regulator/consumer.h>
#include <asm/mach/map.h>
-#include <mach/clock.h>
#include <mach/psc.h>
-#include <mach/mux.h>
#include <mach/irqs.h>
#include <mach/cputype.h>
#include <mach/common.h>
#include <mach/time.h>
#include <mach/da8xx.h>
+#include <mach/cpufreq.h>
#include "clock.h"
#include "mux.h"
+/* SoC specific clock flags */
+#define DA850_CLK_ASYNC3 BIT(16)
+
#define DA850_PLL1_BASE 0x01e1a000
#define DA850_TIMER64P2_BASE 0x01f0c000
#define DA850_TIMER64P3_BASE 0x01f0d000
#define DA850_REF_FREQ 24000000
+#define CFGCHIP3_ASYNC3_CLKSRC BIT(4)
+#define CFGCHIP0_PLL_MASTER_LOCK BIT(4)
+
+static int da850_set_armrate(struct clk *clk, unsigned long rate);
+static int da850_round_armrate(struct clk *clk, unsigned long rate);
+static int da850_set_pll0rate(struct clk *clk, unsigned long armrate);
+
static struct pll_data pll0_data = {
.num = 1,
.phys_base = DA8XX_PLL0_BASE,
@@ -52,6 +62,7 @@ static struct clk pll0_clk = {
.parent = &ref_clk,
.pll_data = &pll0_data,
.flags = CLK_PLL,
+ .set_rate = da850_set_pll0rate,
};
static struct clk pll0_aux_clk = {
@@ -210,16 +221,16 @@ static struct clk tpcc1_clk = {
.name = "tpcc1",
.parent = &pll0_sysclk2,
.lpsc = DA850_LPSC1_TPCC1,
+ .gpsc = 1,
.flags = CLK_PSC | ALWAYS_ENABLED,
- .psc_ctlr = 1,
};
static struct clk tptc2_clk = {
.name = "tptc2",
.parent = &pll0_sysclk2,
.lpsc = DA850_LPSC1_TPTC2,
+ .gpsc = 1,
.flags = ALWAYS_ENABLED,
- .psc_ctlr = 1,
};
static struct clk uart0_clk = {
@@ -232,14 +243,16 @@ static struct clk uart1_clk = {
.name = "uart1",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_UART1,
- .psc_ctlr = 1,
+ .gpsc = 1,
+ .flags = DA850_CLK_ASYNC3,
};
static struct clk uart2_clk = {
.name = "uart2",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_UART2,
- .psc_ctlr = 1,
+ .gpsc = 1,
+ .flags = DA850_CLK_ASYNC3,
};
static struct clk aintc_clk = {
@@ -253,22 +266,22 @@ static struct clk gpio_clk = {
.name = "gpio",
.parent = &pll0_sysclk4,
.lpsc = DA8XX_LPSC1_GPIO,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk i2c1_clk = {
.name = "i2c1",
.parent = &pll0_sysclk4,
.lpsc = DA8XX_LPSC1_I2C,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk emif3_clk = {
.name = "emif3",
.parent = &pll0_sysclk5,
.lpsc = DA8XX_LPSC1_EMIF3C,
+ .gpsc = 1,
.flags = ALWAYS_ENABLED,
- .psc_ctlr = 1,
};
static struct clk arm_clk = {
@@ -276,6 +289,8 @@ static struct clk arm_clk = {
.parent = &pll0_sysclk6,
.lpsc = DA8XX_LPSC0_ARM,
.flags = ALWAYS_ENABLED,
+ .set_rate = da850_set_armrate,
+ .round_rate = da850_round_armrate,
};
static struct clk rmii_clk = {
@@ -287,21 +302,22 @@ static struct clk emac_clk = {
.name = "emac",
.parent = &pll0_sysclk4,
.lpsc = DA8XX_LPSC1_CPGMAC,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk mcasp_clk = {
.name = "mcasp",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_McASP0,
- .psc_ctlr = 1,
+ .gpsc = 1,
+ .flags = DA850_CLK_ASYNC3,
};
static struct clk lcdc_clk = {
.name = "lcdc",
.parent = &pll0_sysclk2,
.lpsc = DA8XX_LPSC1_LCDC,
- .psc_ctlr = 1,
+ .gpsc = 1,
};
static struct clk mmcsd_clk = {
@@ -404,6 +420,14 @@ static const struct mux_config da850_pins[] = {
MUX_CFG(DA850, MII_RXD_0, 3, 28, 15, 8, false)
MUX_CFG(DA850, MDIO_CLK, 4, 0, 15, 8, false)
MUX_CFG(DA850, MDIO_D, 4, 4, 15, 8, false)
+ MUX_CFG(DA850, RMII_TXD_0, 14, 12, 15, 8, false)
+ MUX_CFG(DA850, RMII_TXD_1, 14, 8, 15, 8, false)
+ MUX_CFG(DA850, RMII_TXEN, 14, 16, 15, 8, false)
+ MUX_CFG(DA850, RMII_CRS_DV, 15, 4, 15, 8, false)
+ MUX_CFG(DA850, RMII_RXD_0, 14, 24, 15, 8, false)
+ MUX_CFG(DA850, RMII_RXD_1, 14, 20, 15, 8, false)
+ MUX_CFG(DA850, RMII_RXER, 14, 28, 15, 8, false)
+ MUX_CFG(DA850, RMII_MHZ_50_CLK, 15, 0, 15, 0, false)
/* McASP function */
MUX_CFG(DA850, ACLKR, 0, 0, 15, 1, false)
MUX_CFG(DA850, ACLKX, 0, 4, 15, 1, false)
@@ -506,8 +530,9 @@ static const struct mux_config da850_pins[] = {
MUX_CFG(DA850, EMA_WAIT_1, 6, 24, 15, 1, false)
MUX_CFG(DA850, NEMA_CS_2, 7, 0, 15, 1, false)
/* GPIO function */
+ MUX_CFG(DA850, GPIO2_6, 6, 4, 15, 8, false)
+ MUX_CFG(DA850, GPIO2_8, 5, 28, 15, 8, false)
MUX_CFG(DA850, GPIO2_15, 5, 0, 15, 8, false)
- MUX_CFG(DA850, GPIO8_10, 18, 28, 15, 8, false)
MUX_CFG(DA850, GPIO4_0, 10, 28, 15, 8, false)
MUX_CFG(DA850, GPIO4_1, 10, 24, 15, 8, false)
#endif
@@ -547,6 +572,14 @@ const short da850_cpgmac_pins[] __initdata = {
-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,
+ -1
+};
+
const short da850_mcasp_pins[] __initdata = {
DA850_AHCLKX, DA850_ACLKX, DA850_AFSX,
DA850_AHCLKR, DA850_ACLKR, DA850_AFSR, DA850_AMUTE,
@@ -555,12 +588,11 @@ const short da850_mcasp_pins[] __initdata = {
};
const short da850_lcdcntl_pins[] __initdata = {
- DA850_LCD_D_1, DA850_LCD_D_2, DA850_LCD_D_3, DA850_LCD_D_4,
- DA850_LCD_D_5, DA850_LCD_D_6, DA850_LCD_D_7, DA850_LCD_D_8,
- DA850_LCD_D_9, DA850_LCD_D_10, DA850_LCD_D_11, DA850_LCD_D_12,
- DA850_LCD_D_13, DA850_LCD_D_14, DA850_LCD_D_15, DA850_LCD_PCLK,
- DA850_LCD_HSYNC, DA850_LCD_VSYNC, DA850_NLCD_AC_ENB_CS, DA850_GPIO2_15,
- DA850_GPIO8_10,
+ DA850_LCD_D_0, DA850_LCD_D_1, DA850_LCD_D_2, DA850_LCD_D_3,
+ DA850_LCD_D_4, DA850_LCD_D_5, DA850_LCD_D_6, DA850_LCD_D_7,
+ DA850_LCD_D_8, DA850_LCD_D_9, DA850_LCD_D_10, DA850_LCD_D_11,
+ DA850_LCD_D_12, DA850_LCD_D_13, DA850_LCD_D_14, DA850_LCD_D_15,
+ DA850_LCD_PCLK, DA850_LCD_HSYNC, DA850_LCD_VSYNC, DA850_NLCD_AC_ENB_CS,
-1
};
@@ -790,16 +822,223 @@ static struct davinci_timer_info da850_timer_info = {
.clocksource_id = T0_TOP,
};
+static void da850_set_async3_src(int pllnum)
+{
+ struct clk *clk, *newparent = pllnum ? &pll1_sysclk2 : &pll0_sysclk2;
+ struct davinci_clk *c;
+ unsigned int v;
+ int ret;
+
+ for (c = da850_clks; c->lk.clk; c++) {
+ clk = c->lk.clk;
+ if (clk->flags & DA850_CLK_ASYNC3) {
+ ret = clk_set_parent(clk, newparent);
+ WARN(ret, "DA850: unable to re-parent clock %s",
+ clk->name);
+ }
+ }
+
+ v = __raw_readl(DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG));
+ if (pllnum)
+ v |= CFGCHIP3_ASYNC3_CLKSRC;
+ else
+ v &= ~CFGCHIP3_ASYNC3_CLKSRC;
+ __raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG));
+}
+
+#ifdef CONFIG_CPU_FREQ
+/*
+ * Notes:
+ * According to the TRM, minimum PLLM results in maximum power savings.
+ * The OPP definitions below should keep the PLLM as low as possible.
+ *
+ * The output of the PLLM must be between 400 to 600 MHz.
+ * This rules out prediv of anything but divide-by-one for 24Mhz OSC input.
+ */
+struct da850_opp {
+ unsigned int freq; /* in KHz */
+ unsigned int prediv;
+ unsigned int mult;
+ unsigned int postdiv;
+ unsigned int cvdd_min; /* in uV */
+ unsigned int cvdd_max; /* in uV */
+};
+
+static const struct da850_opp da850_opp_300 = {
+ .freq = 300000,
+ .prediv = 1,
+ .mult = 25,
+ .postdiv = 2,
+ .cvdd_min = 1140000,
+ .cvdd_max = 1320000,
+};
+
+static const struct da850_opp da850_opp_200 = {
+ .freq = 200000,
+ .prediv = 1,
+ .mult = 25,
+ .postdiv = 3,
+ .cvdd_min = 1050000,
+ .cvdd_max = 1160000,
+};
+
+static const struct da850_opp da850_opp_96 = {
+ .freq = 96000,
+ .prediv = 1,
+ .mult = 20,
+ .postdiv = 5,
+ .cvdd_min = 950000,
+ .cvdd_max = 1050000,
+};
+
+#define OPP(freq) \
+ { \
+ .index = (unsigned int) &da850_opp_##freq, \
+ .frequency = freq * 1000, \
+ }
+
+static struct cpufreq_frequency_table da850_freq_table[] = {
+ OPP(300),
+ OPP(200),
+ OPP(96),
+ {
+ .index = 0,
+ .frequency = CPUFREQ_TABLE_END,
+ },
+};
+
+static struct davinci_cpufreq_config cpufreq_info = {
+ .freq_table = &da850_freq_table[0],
+};
+
+static struct platform_device da850_cpufreq_device = {
+ .name = "cpufreq-davinci",
+ .dev = {
+ .platform_data = &cpufreq_info,
+ },
+};
+
+int __init da850_register_cpufreq(void)
+{
+ return platform_device_register(&da850_cpufreq_device);
+}
+
+static int da850_round_armrate(struct clk *clk, unsigned long rate)
+{
+ int i, ret = 0, diff;
+ unsigned int best = (unsigned int) -1;
+
+ rate /= 1000; /* convert to kHz */
+
+ for (i = 0; da850_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+ diff = da850_freq_table[i].frequency - rate;
+ if (diff < 0)
+ diff = -diff;
+
+ if (diff < best) {
+ best = diff;
+ ret = da850_freq_table[i].frequency;
+ }
+ }
+
+ return ret * 1000;
+}
+
+static int da850_set_armrate(struct clk *clk, unsigned long index)
+{
+ struct clk *pllclk = &pll0_clk;
+
+ return clk_set_rate(pllclk, index);
+}
+
+static int da850_set_pll0rate(struct clk *clk, unsigned long index)
+{
+ unsigned int prediv, mult, postdiv;
+ struct da850_opp *opp;
+ struct pll_data *pll = clk->pll_data;
+ unsigned int v;
+ int ret;
+
+ opp = (struct da850_opp *) da850_freq_table[index].index;
+ prediv = opp->prediv;
+ mult = opp->mult;
+ postdiv = opp->postdiv;
+
+ /* Unlock writing to PLL registers */
+ v = __raw_readl(DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP0_REG));
+ v &= ~CFGCHIP0_PLL_MASTER_LOCK;
+ __raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP0_REG));
+
+ ret = davinci_set_pllrate(pll, prediv, mult, postdiv);
+ if (WARN_ON(ret))
+ return ret;
+
+ return 0;
+}
+#else
+int __init da850_register_cpufreq(void)
+{
+ return 0;
+}
+
+static int da850_set_armrate(struct clk *clk, unsigned long rate)
+{
+ return -EINVAL;
+}
+
+static int da850_set_pll0rate(struct clk *clk, unsigned long armrate)
+{
+ return -EINVAL;
+}
+
+static int da850_round_armrate(struct clk *clk, unsigned long rate)
+{
+ return clk->rate;
+}
+#endif
+
+#ifdef CONFIG_REGULATOR
+static struct regulator *cvdd;
+
+static int da850_set_voltage(unsigned int index)
+{
+ struct da850_opp *opp;
+
+ if (!cvdd)
+ return -ENODEV;
+
+ opp = (struct da850_opp *) da850_freq_table[index].index;
+
+ return regulator_set_voltage(cvdd, opp->cvdd_min, opp->cvdd_max);
+}
+
+static int __init da850_regulator_init(void)
+{
+ int ret = 0;
+
+ cvdd = regulator_get(NULL, "cvdd");
+ if (WARN(IS_ERR(cvdd), "Unable to obtain voltage regulator for CVDD;"
+ " voltage scaling unsupported\n")) {
+ ret = PTR_ERR(cvdd);
+ goto out;
+ }
+
+ cpufreq_info.set_voltage = da850_set_voltage;
+
+out:
+ return ret;
+}
+device_initcall(da850_regulator_init);
+#endif
+
static struct davinci_soc_info davinci_soc_info_da850 = {
.io_desc = da850_io_desc,
.io_desc_num = ARRAY_SIZE(da850_io_desc),
- .jtag_id_base = IO_ADDRESS(DA8XX_JTAG_ID_REG),
.ids = da850_ids,
.ids_num = ARRAY_SIZE(da850_ids),
.cpu_clks = da850_clks,
.psc_bases = da850_psc_bases,
.psc_bases_num = ARRAY_SIZE(da850_psc_bases),
- .pinmux_base = IO_ADDRESS(DA8XX_BOOT_CFG_BASE + 0x120),
.pinmux_pins = da850_pins,
.pinmux_pins_num = ARRAY_SIZE(da850_pins),
.intc_base = (void __iomem *)DA8XX_CP_INTC_VIRT,
@@ -816,5 +1055,22 @@ static struct davinci_soc_info davinci_soc_info_da850 = {
void __init da850_init(void)
{
+ da8xx_syscfg_base = ioremap(DA8XX_SYSCFG_BASE, SZ_4K);
+ if (WARN(!da8xx_syscfg_base, "Unable to map syscfg module"))
+ return;
+
+ davinci_soc_info_da850.jtag_id_base =
+ DA8XX_SYSCFG_VIRT(DA8XX_JTAG_ID_REG);
+ davinci_soc_info_da850.pinmux_base = DA8XX_SYSCFG_VIRT(0x120);
+
davinci_common_init(&davinci_soc_info_da850);
+
+ /*
+ * Move the clock source of Async3 domain to PLL1 SYSCLK2.
+ * This helps keeping the peripherals on this domain insulated
+ * from CPU frequency changes caused by DVFS. The firmware sets
+ * both PLL0 and PLL1 to the same frequency so, there should not
+ * be any noticible change even in non-DVFS use cases.
+ */
+ da850_set_async3_src(1);
}
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 58ad5b66fd60..fda83f82a5fe 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -10,8 +10,6 @@
* 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/init.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
@@ -21,7 +19,6 @@
#include <mach/common.h>
#include <mach/time.h>
#include <mach/da8xx.h>
-#include <video/da8xx-fb.h>
#include "clock.h"
@@ -30,6 +27,7 @@
#define DA8XX_TPTC1_BASE 0x01c08400
#define DA8XX_WDOG_BASE 0x01c21000 /* DA8XX_TIMER64P1_BASE */
#define DA8XX_I2C0_BASE 0x01c22000
+#define DA8XX_RTC_BASE 0x01C23000
#define DA8XX_EMAC_CPPI_PORT_BASE 0x01e20000
#define DA8XX_EMAC_CPGMACSS_BASE 0x01e22000
#define DA8XX_EMAC_CPGMAC_BASE 0x01e23000
@@ -43,6 +41,8 @@
#define DA8XX_MDIO_REG_OFFSET 0x4000
#define DA8XX_EMAC_CTRL_RAM_SIZE SZ_8K
+void __iomem *da8xx_syscfg_base;
+
static struct plat_serial8250_port da8xx_serial_pdata[] = {
{
.mapbase = DA8XX_UART0_BASE,
@@ -282,6 +282,11 @@ static struct platform_device da8xx_emac_device = {
.resource = da8xx_emac_resources,
};
+int __init da8xx_register_emac(void)
+{
+ return platform_device_register(&da8xx_emac_device);
+}
+
static struct resource da830_mcasp1_resources[] = {
{
.name = "mcasp1",
@@ -338,12 +343,7 @@ static struct platform_device da850_mcasp_device = {
.resource = da850_mcasp_resources,
};
-int __init da8xx_register_emac(void)
-{
- return platform_device_register(&da8xx_emac_device);
-}
-
-void __init da8xx_init_mcasp(int id, struct snd_platform_data *pdata)
+void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata)
{
/* DA830/OMAP-L137 has 3 instances of McASP */
if (cpu_is_davinci_da830() && id == 1) {
@@ -379,10 +379,16 @@ static struct lcd_ctrl_config lcd_cfg = {
.raster_order = 0,
};
-static struct da8xx_lcdc_platform_data da850_evm_lcdc_pdata = {
- .manu_name = "sharp",
- .controller_data = &lcd_cfg,
- .type = "Sharp_LK043T1DG01",
+struct da8xx_lcdc_platform_data sharp_lcd035q3dg01_pdata = {
+ .manu_name = "sharp",
+ .controller_data = &lcd_cfg,
+ .type = "Sharp_LCD035Q3DG01",
+};
+
+struct da8xx_lcdc_platform_data sharp_lk043t1dg01_pdata = {
+ .manu_name = "sharp",
+ .controller_data = &lcd_cfg,
+ .type = "Sharp_LK043T1DG01",
};
static struct resource da8xx_lcdc_resources[] = {
@@ -398,19 +404,17 @@ static struct resource da8xx_lcdc_resources[] = {
},
};
-static struct platform_device da850_lcdc_device = {
+static struct platform_device da8xx_lcdc_device = {
.name = "da8xx_lcdc",
.id = 0,
.num_resources = ARRAY_SIZE(da8xx_lcdc_resources),
.resource = da8xx_lcdc_resources,
- .dev = {
- .platform_data = &da850_evm_lcdc_pdata,
- }
};
-int __init da8xx_register_lcdc(void)
+int __init da8xx_register_lcdc(struct da8xx_lcdc_platform_data *pdata)
{
- return platform_device_register(&da850_lcdc_device);
+ da8xx_lcdc_device.dev.platform_data = pdata;
+ return platform_device_register(&da8xx_lcdc_device);
}
static struct resource da8xx_mmcsd0_resources[] = {
@@ -448,3 +452,37 @@ int __init da8xx_register_mmcsd0(struct davinci_mmc_config *config)
da8xx_mmcsd0_device.dev.platform_data = config;
return platform_device_register(&da8xx_mmcsd0_device);
}
+
+static struct resource da8xx_rtc_resources[] = {
+ {
+ .start = DA8XX_RTC_BASE,
+ .end = DA8XX_RTC_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ { /* timer irq */
+ .start = IRQ_DA8XX_RTC,
+ .end = IRQ_DA8XX_RTC,
+ .flags = IORESOURCE_IRQ,
+ },
+ { /* alarm irq */
+ .start = IRQ_DA8XX_RTC,
+ .end = IRQ_DA8XX_RTC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device da8xx_rtc_device = {
+ .name = "omap_rtc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(da8xx_rtc_resources),
+ .resource = da8xx_rtc_resources,
+};
+
+int da8xx_register_rtc(void)
+{
+ /* Unlock the rtc's registers */
+ __raw_writel(0x83e70b13, IO_ADDRESS(DA8XX_RTC_BASE + 0x6c));
+ __raw_writel(0x95a4f1e0, IO_ADDRESS(DA8XX_RTC_BASE + 0x70));
+
+ return platform_device_register(&da8xx_rtc_device);
+}
diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c
index a55b650db71e..147949650c25 100644
--- a/arch/arm/mach-davinci/devices.c
+++ b/arch/arm/mach-davinci/devices.c
@@ -9,15 +9,11 @@
* (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/dma-mapping.h>
#include <linux/io.h>
-#include <asm/mach/map.h>
-
#include <mach/hardware.h>
#include <mach/i2c.h>
#include <mach/irqs.h>
@@ -177,7 +173,7 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config)
mmcsd1_resources[0].start = DM365_MMCSD1_BASE;
mmcsd1_resources[0].end = DM365_MMCSD1_BASE +
SZ_4K - 1;
- mmcsd0_resources[2].start = IRQ_DM365_SDIOINT1;
+ mmcsd1_resources[2].start = IRQ_DM365_SDIOINT1;
} else
break;
diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
index 059670018aff..dedf4d4f3a27 100644
--- a/arch/arm/mach-davinci/dm355.c
+++ b/arch/arm/mach-davinci/dm355.c
@@ -8,7 +8,6 @@
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
-#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/serial_8250.h>
@@ -21,7 +20,6 @@
#include <asm/mach/map.h>
#include <mach/dm355.h>
-#include <mach/clock.h>
#include <mach/cputype.h>
#include <mach/edma.h>
#include <mach/psc.h>
diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
index e81517434703..c12bb005b90d 100644
--- a/arch/arm/mach-davinci/dm365.c
+++ b/arch/arm/mach-davinci/dm365.c
@@ -12,7 +12,6 @@
* 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/clk.h>
#include <linux/serial_8250.h>
@@ -23,7 +22,6 @@
#include <asm/mach/map.h>
#include <mach/dm365.h>
-#include <mach/clock.h>
#include <mach/cputype.h>
#include <mach/edma.h>
#include <mach/psc.h>
@@ -32,6 +30,8 @@
#include <mach/time.h>
#include <mach/serial.h>
#include <mach/common.h>
+#include <mach/asp.h>
+#include <mach/keyscan.h>
#include "clock.h"
#include "mux.h"
@@ -369,7 +369,7 @@ static struct clk timer3_clk = {
static struct clk usb_clk = {
.name = "usb",
- .parent = &pll2_sysclk1,
+ .parent = &pll1_aux_clk,
.lpsc = DAVINCI_LPSC_USB,
};
@@ -456,7 +456,7 @@ static struct davinci_clk dm365_clks[] = {
CLK(NULL, "usb", &usb_clk),
CLK("davinci_emac.1", NULL, &emac_clk),
CLK("voice_codec", NULL, &voicecodec_clk),
- CLK("soc-audio.0", NULL, &asp0_clk),
+ CLK("davinci-asp.0", NULL, &asp0_clk),
CLK(NULL, "rto", &rto_clk),
CLK(NULL, "mjcp", &mjcp_clk),
CLK(NULL, NULL, NULL),
@@ -531,7 +531,7 @@ MUX_CFG(DM365, EMAC_CRS, 3, 2, 1, 1, false)
MUX_CFG(DM365, EMAC_MDIO, 3, 1, 1, 1, false)
MUX_CFG(DM365, EMAC_MDCLK, 3, 0, 1, 1, false)
-MUX_CFG(DM365, KEYPAD, 2, 0, 0x3f, 0x3f, false)
+MUX_CFG(DM365, KEYSCAN, 2, 0, 0x3f, 0x3f, false)
MUX_CFG(DM365, PWM0, 1, 0, 3, 2, false)
MUX_CFG(DM365, PWM0_G23, 3, 26, 3, 3, false)
@@ -603,6 +603,9 @@ INT_CFG(DM365, INT_IMX1_ENABLE, 24, 1, 1, false)
INT_CFG(DM365, INT_IMX1_DISABLE, 24, 1, 0, false)
INT_CFG(DM365, INT_NSF_ENABLE, 25, 1, 1, false)
INT_CFG(DM365, INT_NSF_DISABLE, 25, 1, 0, false)
+
+EVT_CFG(DM365, EVT2_ASP_TX, 0, 1, 0, false)
+EVT_CFG(DM365, EVT3_ASP_RX, 1, 1, 0, false)
#endif
};
@@ -806,6 +809,31 @@ static struct platform_device dm365_edma_device = {
.resource = edma_resources,
};
+static struct resource dm365_asp_resources[] = {
+ {
+ .start = DAVINCI_DM365_ASP0_BASE,
+ .end = DAVINCI_DM365_ASP0_BASE + SZ_8K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = DAVINCI_DMA_ASP0_TX,
+ .end = DAVINCI_DMA_ASP0_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .start = DAVINCI_DMA_ASP0_RX,
+ .end = DAVINCI_DMA_ASP0_RX,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static struct platform_device dm365_asp_device = {
+ .name = "davinci-asp",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(dm365_asp_resources),
+ .resource = dm365_asp_resources,
+};
+
static struct map_desc dm365_io_desc[] = {
{
.virtual = IO_VIRT,
@@ -822,6 +850,28 @@ static struct map_desc dm365_io_desc[] = {
},
};
+static struct resource dm365_ks_resources[] = {
+ {
+ /* registers */
+ .start = DM365_KEYSCAN_BASE,
+ .end = DM365_KEYSCAN_BASE + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* interrupt */
+ .start = IRQ_DM365_KEYINT,
+ .end = IRQ_DM365_KEYINT,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device dm365_ks_device = {
+ .name = "davinci_keyscan",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(dm365_ks_resources),
+ .resource = dm365_ks_resources,
+};
+
/* Contents of JTAG ID register used to identify exact cpu type */
static struct davinci_id dm365_ids[] = {
{
@@ -907,6 +957,27 @@ static struct davinci_soc_info davinci_soc_info_dm365 = {
.sram_len = SZ_32K,
};
+void __init dm365_init_asp(struct snd_platform_data *pdata)
+{
+ davinci_cfg_reg(DM365_MCBSP0_BDX);
+ davinci_cfg_reg(DM365_MCBSP0_X);
+ davinci_cfg_reg(DM365_MCBSP0_BFSX);
+ davinci_cfg_reg(DM365_MCBSP0_BDR);
+ davinci_cfg_reg(DM365_MCBSP0_R);
+ davinci_cfg_reg(DM365_MCBSP0_BFSR);
+ davinci_cfg_reg(DM365_EVT2_ASP_TX);
+ davinci_cfg_reg(DM365_EVT3_ASP_RX);
+ dm365_asp_device.dev.platform_data = pdata;
+ platform_device_register(&dm365_asp_device);
+}
+
+void __init dm365_init_ks(struct davinci_ks_platform_data *pdata)
+{
+ davinci_cfg_reg(DM365_KEYSCAN);
+ dm365_ks_device.dev.platform_data = pdata;
+ platform_device_register(&dm365_ks_device);
+}
+
void __init dm365_init(void)
{
davinci_common_init(&davinci_soc_info_dm365);
diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c
index d6e0fa5a8d8a..84d3d26831c7 100644
--- a/arch/arm/mach-davinci/dm644x.c
+++ b/arch/arm/mach-davinci/dm644x.c
@@ -8,7 +8,6 @@
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
-#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/serial_8250.h>
@@ -18,7 +17,6 @@
#include <asm/mach/map.h>
#include <mach/dm644x.h>
-#include <mach/clock.h>
#include <mach/cputype.h>
#include <mach/edma.h>
#include <mach/irqs.h>
diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c
index 0976049c7b3b..829a44bcf799 100644
--- a/arch/arm/mach-davinci/dm646x.c
+++ b/arch/arm/mach-davinci/dm646x.c
@@ -8,7 +8,6 @@
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
-#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/serial_8250.h>
@@ -18,7 +17,6 @@
#include <asm/mach/map.h>
#include <mach/dm646x.h>
-#include <mach/clock.h>
#include <mach/cputype.h>
#include <mach/edma.h>
#include <mach/irqs.h>
@@ -789,7 +787,14 @@ static struct davinci_id dm646x_ids[] = {
.part_no = 0xb770,
.manufacturer = 0x017,
.cpu_id = DAVINCI_CPU_ID_DM6467,
- .name = "dm6467",
+ .name = "dm6467_rev1.x",
+ },
+ {
+ .variant = 0x1,
+ .part_no = 0xb770,
+ .manufacturer = 0x017,
+ .cpu_id = DAVINCI_CPU_ID_DM6467,
+ .name = "dm6467_rev3.x",
},
};
diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c
index f2e57d272958..648fbb760ae1 100644
--- a/arch/arm/mach-davinci/dma.c
+++ b/arch/arm/mach-davinci/dma.c
@@ -18,22 +18,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/compiler.h>
#include <linux/io.h>
-#include <mach/cputype.h>
-#include <mach/memory.h>
-#include <mach/hardware.h>
-#include <mach/irqs.h>
#include <mach/edma.h>
-#include <mach/mux.h>
-
/* Offsets matching "struct edmacc_param" */
#define PARM_OPT 0x00
@@ -509,43 +500,59 @@ static irqreturn_t dma_tc1err_handler(int irq, void *data)
return IRQ_HANDLED;
}
-static int reserve_contiguous_params(int ctlr, unsigned int id,
- unsigned int num_params,
- unsigned int start_param)
+static int reserve_contiguous_slots(int ctlr, unsigned int id,
+ unsigned int num_slots,
+ unsigned int start_slot)
{
int i, j;
- unsigned int count = num_params;
+ unsigned int count = num_slots;
+ int stop_slot = start_slot;
+ DECLARE_BITMAP(tmp_inuse, EDMA_MAX_PARAMENTRY);
- for (i = start_param; i < edma_info[ctlr]->num_slots; ++i) {
+ for (i = start_slot; i < edma_info[ctlr]->num_slots; ++i) {
j = EDMA_CHAN_SLOT(i);
- if (!test_and_set_bit(j, edma_info[ctlr]->edma_inuse))
+ if (!test_and_set_bit(j, edma_info[ctlr]->edma_inuse)) {
+ /* Record our current beginning slot */
+ if (count == num_slots)
+ stop_slot = i;
+
count--;
+ set_bit(j, tmp_inuse);
+
if (count == 0)
break;
- else if (id == EDMA_CONT_PARAMS_FIXED_EXACT)
- break;
- else
- count = num_params;
+ } else {
+ clear_bit(j, tmp_inuse);
+
+ if (id == EDMA_CONT_PARAMS_FIXED_EXACT) {
+ stop_slot = i;
+ break;
+ } else
+ count = num_slots;
+ }
}
/*
* We have to clear any bits that we set
- * if we run out parameter RAMs, i.e we do find a set
- * of contiguous parameter RAMs but do not find the exact number
- * requested as we may reach the total number of parameter RAMs
+ * if we run out parameter RAM slots, i.e we do find a set
+ * of contiguous parameter RAM slots but do not find the exact number
+ * requested as we may reach the total number of parameter RAM slots
*/
- if (count) {
- for (j = i - num_params + count + 1; j <= i ; ++j)
+ if (i == edma_info[ctlr]->num_slots)
+ stop_slot = i;
+
+ for (j = start_slot; j < stop_slot; j++)
+ if (test_bit(j, tmp_inuse))
clear_bit(j, edma_info[ctlr]->edma_inuse);
+ if (count)
return -EBUSY;
- }
- for (j = i - num_params + 1; j <= i; ++j)
+ for (j = i - num_slots + 1; j <= i; ++j)
memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(j),
&dummy_paramset, PARM_SIZE);
- return EDMA_CTLR_CHAN(ctlr, i - num_params + 1);
+ return EDMA_CTLR_CHAN(ctlr, i - num_slots + 1);
}
/*-----------------------------------------------------------------------*/
@@ -743,26 +750,27 @@ EXPORT_SYMBOL(edma_free_slot);
/**
* edma_alloc_cont_slots- alloc contiguous parameter RAM slots
* The API will return the starting point of a set of
- * contiguous PARAM's that have been requested
+ * contiguous parameter RAM slots that have been requested
*
* @id: can only be EDMA_CONT_PARAMS_ANY or EDMA_CONT_PARAMS_FIXED_EXACT
* or EDMA_CONT_PARAMS_FIXED_NOT_EXACT
- * @count: number of contiguous Paramter RAM's
- * @param - the start value of Parameter RAM that should be passed if id
+ * @count: number of contiguous Paramter RAM slots
+ * @slot - the start value of Parameter RAM slot that should be passed if id
* is EDMA_CONT_PARAMS_FIXED_EXACT or EDMA_CONT_PARAMS_FIXED_NOT_EXACT
*
* If id is EDMA_CONT_PARAMS_ANY then the API starts looking for a set of
- * contiguous Parameter RAMs from parameter RAM 64 in the case of DaVinci SOCs
- * and 32 in the case of Primus
+ * contiguous Parameter RAM slots from parameter RAM 64 in the case of
+ * DaVinci SOCs and 32 in the case of DA8xx SOCs.
*
* If id is EDMA_CONT_PARAMS_FIXED_EXACT then the API starts looking for a
- * set of contiguous parameter RAMs from the "param" that is passed as an
+ * set of contiguous parameter RAM slots from the "slot" that is passed as an
* argument to the API.
*
* If id is EDMA_CONT_PARAMS_FIXED_NOT_EXACT then the API initially tries
- * starts looking for a set of contiguous parameter RAMs from the "param"
+ * starts looking for a set of contiguous parameter RAMs from the "slot"
* that is passed as an argument to the API. On failure the API will try to
- * find a set of contiguous Parameter RAMs in the remaining Parameter RAMs
+ * find a set of contiguous Parameter RAM slots from the remaining Parameter
+ * RAM slots
*/
int edma_alloc_cont_slots(unsigned ctlr, unsigned int id, int slot, int count)
{
@@ -771,12 +779,13 @@ int edma_alloc_cont_slots(unsigned ctlr, unsigned int id, int slot, int count)
* the number of channels and lesser than the total number
* of slots
*/
- if (slot < edma_info[ctlr]->num_channels ||
- slot >= edma_info[ctlr]->num_slots)
+ if ((id != EDMA_CONT_PARAMS_ANY) &&
+ (slot < edma_info[ctlr]->num_channels ||
+ slot >= edma_info[ctlr]->num_slots))
return -EINVAL;
/*
- * The number of parameter RAMs requested cannot be less than 1
+ * The number of parameter RAM slots requested cannot be less than 1
* and cannot be more than the number of slots minus the number of
* channels
*/
@@ -786,11 +795,11 @@ int edma_alloc_cont_slots(unsigned ctlr, unsigned int id, int slot, int count)
switch (id) {
case EDMA_CONT_PARAMS_ANY:
- return reserve_contiguous_params(ctlr, id, count,
+ return reserve_contiguous_slots(ctlr, id, count,
edma_info[ctlr]->num_channels);
case EDMA_CONT_PARAMS_FIXED_EXACT:
case EDMA_CONT_PARAMS_FIXED_NOT_EXACT:
- return reserve_contiguous_params(ctlr, id, count, slot);
+ return reserve_contiguous_slots(ctlr, id, count, slot);
default:
return -EINVAL;
}
@@ -799,21 +808,21 @@ int edma_alloc_cont_slots(unsigned ctlr, unsigned int id, int slot, int count)
EXPORT_SYMBOL(edma_alloc_cont_slots);
/**
- * edma_free_cont_slots - deallocate DMA parameter RAMs
- * @slot: first parameter RAM of a set of parameter RAMs to be freed
- * @count: the number of contiguous parameter RAMs to be freed
+ * edma_free_cont_slots - deallocate DMA parameter RAM slots
+ * @slot: first parameter RAM of a set of parameter RAM slots to be freed
+ * @count: the number of contiguous parameter RAM slots to be freed
*
* This deallocates the parameter RAM slots allocated by
* edma_alloc_cont_slots.
* Callers/applications need to keep track of sets of contiguous
- * parameter RAMs that have been allocated using the edma_alloc_cont_slots
+ * parameter RAM slots that have been allocated using the edma_alloc_cont_slots
* API.
* Callers are responsible for ensuring the slots are inactive, and will
* not be activated.
*/
int edma_free_cont_slots(unsigned slot, int count)
{
- unsigned ctlr;
+ unsigned ctlr, slot_to_free;
int i;
ctlr = EDMA_CTLR(slot);
@@ -826,11 +835,11 @@ int edma_free_cont_slots(unsigned slot, int count)
for (i = slot; i < slot + count; ++i) {
ctlr = EDMA_CTLR(i);
- slot = EDMA_CHAN_SLOT(i);
+ slot_to_free = EDMA_CHAN_SLOT(i);
- memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(slot),
+ memcpy_toio(edmacc_regs_base[ctlr] + PARM_OFFSET(slot_to_free),
&dummy_paramset, PARM_SIZE);
- clear_bit(slot, edma_info[ctlr]->edma_inuse);
+ clear_bit(slot_to_free, edma_info[ctlr]->edma_inuse);
}
return 0;
diff --git a/arch/arm/mach-davinci/gpio.c b/arch/arm/mach-davinci/gpio.c
index f6ea9db11f41..744755b53236 100644
--- a/arch/arm/mach-davinci/gpio.c
+++ b/arch/arm/mach-davinci/gpio.c
@@ -12,23 +12,14 @@
#include <linux/errno.h>
#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/module.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/bitops.h>
-#include <mach/cputype.h>
-#include <mach/irqs.h>
-#include <mach/hardware.h>
-#include <mach/common.h>
#include <mach/gpio.h>
#include <asm/mach/irq.h>
-
static DEFINE_SPINLOCK(gpio_lock);
struct davinci_gpio {
diff --git a/arch/arm/mach-davinci/include/mach/asp.h b/arch/arm/mach-davinci/include/mach/asp.h
index 18e4ce34ece6..fef12b919c69 100644
--- a/arch/arm/mach-davinci/include/mach/asp.h
+++ b/arch/arm/mach-davinci/include/mach/asp.h
@@ -11,6 +11,9 @@
#define DAVINCI_ASP0_BASE 0x01E02000
#define DAVINCI_ASP1_BASE 0x01E04000
+/* Bases of dm365 register banks */
+#define DAVINCI_DM365_ASP0_BASE 0x01D02000
+
/* Bases of dm646x register banks */
#define DAVINCI_DM646X_MCASP0_REG_BASE 0x01D01000
#define DAVINCI_DM646X_MCASP1_REG_BASE 0x01D01800
diff --git a/arch/arm/mach-davinci/include/mach/cpufreq.h b/arch/arm/mach-davinci/include/mach/cpufreq.h
new file mode 100644
index 000000000000..442bdea44632
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/cpufreq.h
@@ -0,0 +1,25 @@
+/*
+ * TI DaVinci CPUFreq platform support.
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc. 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 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 _MACH_DAVINCI_CPUFREQ_H
+#define _MACH_DAVINCI_CPUFREQ_H
+
+#include <linux/cpufreq.h>
+
+struct davinci_cpufreq_config {
+ struct cpufreq_frequency_table *freq_table;
+ int (*set_voltage) (unsigned int index);
+};
+
+#endif
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index d4095d0572c6..b4cf8b146e8e 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -11,12 +11,17 @@
#ifndef __ASM_ARCH_DAVINCI_DA8XX_H
#define __ASM_ARCH_DAVINCI_DA8XX_H
+#include <video/da8xx-fb.h>
+
#include <mach/serial.h>
#include <mach/edma.h>
#include <mach/i2c.h>
#include <mach/emac.h>
#include <mach/asp.h>
#include <mach/mmc.h>
+#include <mach/usb.h>
+
+extern void __iomem *da8xx_syscfg_base;
/*
* The cp_intc interrupt controller for the da8xx isn't in the same
@@ -29,11 +34,15 @@
#define DA8XX_CP_INTC_SIZE SZ_8K
#define DA8XX_CP_INTC_VIRT (IO_VIRT - DA8XX_CP_INTC_SIZE - SZ_4K)
-#define DA8XX_BOOT_CFG_BASE (IO_PHYS + 0x14000)
+#define DA8XX_SYSCFG_BASE (IO_PHYS + 0x14000)
+#define DA8XX_SYSCFG_VIRT(x) (da8xx_syscfg_base + (x))
+#define DA8XX_JTAG_ID_REG 0x18
+#define DA8XX_CFGCHIP0_REG 0x17c
+#define DA8XX_CFGCHIP2_REG 0x184
+#define DA8XX_CFGCHIP3_REG 0x188
#define DA8XX_PSC0_BASE 0x01c10000
#define DA8XX_PLL0_BASE 0x01c11000
-#define DA8XX_JTAG_ID_REG 0x01c14018
#define DA8XX_TIMER64P0_BASE 0x01c20000
#define DA8XX_TIMER64P1_BASE 0x01c21000
#define DA8XX_GPIO_BASE 0x01e26000
@@ -71,13 +80,18 @@ void __init da850_init(void);
int da8xx_register_edma(void);
int da8xx_register_i2c(int instance, struct davinci_i2c_platform_data *pdata);
int da8xx_register_watchdog(void);
+int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata);
int da8xx_register_emac(void);
-int da8xx_register_lcdc(void);
+int da8xx_register_lcdc(struct da8xx_lcdc_platform_data *pdata);
int da8xx_register_mmcsd0(struct davinci_mmc_config *config);
-void __init da8xx_init_mcasp(int id, struct snd_platform_data *pdata);
+void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata);
+int da8xx_register_rtc(void);
+int da850_register_cpufreq(void);
extern struct platform_device da8xx_serial_device;
extern struct emac_platform_data da8xx_emac_pdata;
+extern struct da8xx_lcdc_platform_data sharp_lcd035q3dg01_pdata;
+extern struct da8xx_lcdc_platform_data sharp_lk043t1dg01_pdata;
extern const short da830_emif25_pins[];
extern const short da830_spi0_pins[];
@@ -110,6 +124,7 @@ 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[];
diff --git a/arch/arm/mach-davinci/include/mach/dm365.h b/arch/arm/mach-davinci/include/mach/dm365.h
index 09db4343bb4c..d8d988a0b58b 100644
--- a/arch/arm/mach-davinci/include/mach/dm365.h
+++ b/arch/arm/mach-davinci/include/mach/dm365.h
@@ -16,6 +16,8 @@
#include <linux/platform_device.h>
#include <mach/hardware.h>
#include <mach/emac.h>
+#include <mach/asp.h>
+#include <mach/keyscan.h>
#define DM365_EMAC_BASE (0x01D07000)
#define DM365_EMAC_CNTRL_OFFSET (0x0000)
@@ -24,6 +26,11 @@
#define DM365_EMAC_MDIO_OFFSET (0x4000)
#define DM365_EMAC_CNTRL_RAM_SIZE (0x2000)
+/* Base of key scan register bank */
+#define DM365_KEYSCAN_BASE (0x01C69400)
+
void __init dm365_init(void);
+void __init dm365_init_asp(struct snd_platform_data *pdata);
+void __init dm365_init_ks(struct davinci_ks_platform_data *pdata);
#endif /* __ASM_ARCH_DM365_H */
diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h
index 0efb73852c2c..44e8f0fae9ea 100644
--- a/arch/arm/mach-davinci/include/mach/dm644x.h
+++ b/arch/arm/mach-davinci/include/mach/dm644x.h
@@ -22,7 +22,6 @@
#ifndef __ASM_ARCH_DM644X_H
#define __ASM_ARCH_DM644X_H
-#include <linux/platform_device.h>
#include <mach/hardware.h>
#include <mach/emac.h>
#include <mach/asp.h>
diff --git a/arch/arm/mach-davinci/include/mach/keyscan.h b/arch/arm/mach-davinci/include/mach/keyscan.h
new file mode 100644
index 000000000000..b4e21a2976d1
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/keyscan.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2009 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 DAVINCI_KEYSCAN_H
+#define DAVINCI_KEYSCAN_H
+
+#include <linux/io.h>
+
+enum davinci_matrix_types {
+ DAVINCI_KEYSCAN_MATRIX_4X4,
+ DAVINCI_KEYSCAN_MATRIX_5X3,
+};
+
+struct davinci_ks_platform_data {
+ unsigned short *keymap;
+ u32 keymapsize;
+ u8 rep:1;
+ u8 strobe;
+ u8 interval;
+ u8 matrix_type;
+};
+
+#endif
+
diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h
index bb84893a4e83..d41ad16966b7 100644
--- a/arch/arm/mach-davinci/include/mach/mux.h
+++ b/arch/arm/mach-davinci/include/mach/mux.h
@@ -237,8 +237,8 @@ enum davinci_dm365_index {
DM365_EMAC_MDIO,
DM365_EMAC_MDCLK,
- /* Keypad */
- DM365_KEYPAD,
+ /* Key Scan */
+ DM365_KEYSCAN,
/* PWM */
DM365_PWM0,
@@ -774,6 +774,14 @@ enum davinci_da850_index {
DA850_MII_RXD_0,
DA850_MDIO_CLK,
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,
/* McASP function */
DA850_ACLKR,
@@ -881,8 +889,9 @@ enum davinci_da850_index {
DA850_NEMA_CS_2,
/* GPIO function */
+ DA850_GPIO2_6,
+ DA850_GPIO2_8,
DA850_GPIO2_15,
- DA850_GPIO8_10,
DA850_GPIO4_0,
DA850_GPIO4_1,
};
diff --git a/arch/arm/mach-davinci/include/mach/system.h b/arch/arm/mach-davinci/include/mach/system.h
index 8e4f10fe1263..5a7d7581b8ce 100644
--- a/arch/arm/mach-davinci/include/mach/system.h
+++ b/arch/arm/mach-davinci/include/mach/system.h
@@ -11,9 +11,6 @@
#ifndef __ASM_ARCH_SYSTEM_H
#define __ASM_ARCH_SYSTEM_H
-#include <linux/io.h>
-#include <mach/hardware.h>
-
extern void davinci_watchdog_reset(void);
static inline void arch_idle(void)
diff --git a/arch/arm/mach-davinci/include/mach/usb.h b/arch/arm/mach-davinci/include/mach/usb.h
new file mode 100644
index 000000000000..435f2284238a
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/usb.h
@@ -0,0 +1,57 @@
+/*
+ * USB related definitions
+ *
+ * Copyright (C) 2009 MontaVista Software, Inc. <source@mvista.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 __ASM_ARCH_USB_H
+#define __ASM_ARCH_USB_H
+
+/* DA8xx CFGCHIP2 (USB 2.0 PHY Control) register bits */
+#define CFGCHIP2_PHYCLKGD (1 << 17)
+#define CFGCHIP2_VBUSSENSE (1 << 16)
+#define CFGCHIP2_RESET (1 << 15)
+#define CFGCHIP2_OTGMODE (3 << 13)
+#define CFGCHIP2_NO_OVERRIDE (0 << 13)
+#define CFGCHIP2_FORCE_HOST (1 << 13)
+#define CFGCHIP2_FORCE_DEVICE (2 << 13)
+#define CFGCHIP2_FORCE_HOST_VBUS_LOW (3 << 13)
+#define CFGCHIP2_USB1PHYCLKMUX (1 << 12)
+#define CFGCHIP2_USB2PHYCLKMUX (1 << 11)
+#define CFGCHIP2_PHYPWRDN (1 << 10)
+#define CFGCHIP2_OTGPWRDN (1 << 9)
+#define CFGCHIP2_DATPOL (1 << 8)
+#define CFGCHIP2_USB1SUSPENDM (1 << 7)
+#define CFGCHIP2_PHY_PLLON (1 << 6) /* override PLL suspend */
+#define CFGCHIP2_SESENDEN (1 << 5) /* Vsess_end comparator */
+#define CFGCHIP2_VBDTCTEN (1 << 4) /* Vbus comparator */
+#define CFGCHIP2_REFFREQ (0xf << 0)
+#define CFGCHIP2_REFFREQ_12MHZ (1 << 0)
+#define CFGCHIP2_REFFREQ_24MHZ (2 << 0)
+#define CFGCHIP2_REFFREQ_48MHZ (3 << 0)
+
+struct da8xx_ohci_root_hub;
+
+typedef void (*da8xx_ocic_handler_t)(struct da8xx_ohci_root_hub *hub,
+ unsigned port);
+
+/* Passed as the platform data to the OHCI driver */
+struct da8xx_ohci_root_hub {
+ /* Switch the port power on/off */
+ int (*set_power)(unsigned port, int on);
+ /* Read the port power status */
+ int (*get_power)(unsigned port);
+ /* Read the port over-current indicator */
+ int (*get_oci)(unsigned port);
+ /* Over-current indicator change notification (pass NULL to disable) */
+ int (*ocic_notify)(da8xx_ocic_handler_t handler);
+
+ /* Time from power on to power good (in 2 ms units) */
+ u8 potpgt;
+};
+
+#endif /* ifndef __ASM_ARCH_USB_H */
diff --git a/arch/arm/mach-davinci/mux.c b/arch/arm/mach-davinci/mux.c
index 898905e48946..f757e83415f3 100644
--- a/arch/arm/mach-davinci/mux.c
+++ b/arch/arm/mach-davinci/mux.c
@@ -19,7 +19,6 @@
#include <linux/module.h>
#include <linux/spinlock.h>
-#include <mach/hardware.h>
#include <mach/mux.h>
#include <mach/common.h>
diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c
index a78b657e916e..04a3cb72c5ab 100644
--- a/arch/arm/mach-davinci/psc.c
+++ b/arch/arm/mach-davinci/psc.c
@@ -19,14 +19,11 @@
*
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
#include <mach/cputype.h>
-#include <mach/hardware.h>
#include <mach/psc.h>
-#include <mach/mux.h>
/* PSC register offsets */
#define EPCPR 0x070
diff --git a/arch/arm/mach-davinci/serial.c b/arch/arm/mach-davinci/serial.c
index c530c7333d0a..7ce5ba086575 100644
--- a/arch/arm/mach-davinci/serial.c
+++ b/arch/arm/mach-davinci/serial.c
@@ -28,14 +28,8 @@
#include <linux/clk.h>
#include <linux/io.h>
-#include <asm/irq.h>
-#include <mach/hardware.h>
#include <mach/serial.h>
-#include <mach/irqs.h>
#include <mach/cputype.h>
-#include <mach/common.h>
-
-#include "clock.h"
static inline unsigned int serial_read_reg(struct plat_serial8250_port *up,
int offset)
diff --git a/arch/arm/mach-davinci/sram.c b/arch/arm/mach-davinci/sram.c
index 4f1fc9b318b3..db0f7787faf1 100644
--- a/arch/arm/mach-davinci/sram.c
+++ b/arch/arm/mach-davinci/sram.c
@@ -9,15 +9,12 @@
* (at your option) any later version.
*/
#include <linux/module.h>
-#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/genalloc.h>
#include <mach/common.h>
-#include <mach/memory.h>
#include <mach/sram.h>
-
static struct gen_pool *sram_pool;
void *sram_alloc(size_t len, dma_addr_t *dma)
diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c
index 0d1b6d407b46..42d985beece5 100644
--- a/arch/arm/mach-davinci/time.c
+++ b/arch/arm/mach-davinci/time.c
@@ -14,20 +14,14 @@
#include <linux/interrupt.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
-#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/err.h>
-#include <linux/device.h>
#include <linux/platform_device.h>
#include <mach/hardware.h>
-#include <asm/system.h>
-#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
-#include <asm/errno.h>
-#include <mach/io.h>
#include <mach/cputype.h>
#include <mach/time.h>
#include "clock.h"
diff --git a/arch/arm/mach-davinci/usb.c b/arch/arm/mach-davinci/usb.c
index 06f55931620c..31eec87dc78f 100644
--- a/arch/arm/mach-davinci/usb.c
+++ b/arch/arm/mach-davinci/usb.c
@@ -1,21 +1,19 @@
/*
* USB
*/
-#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/usb/musb.h>
-#include <linux/usb/otg.h>
#include <mach/common.h>
-#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/cputype.h>
+#include <mach/usb.h>
-#define DAVINCI_USB_OTG_BASE 0x01C64000
+#define DAVINCI_USB_OTG_BASE 0x01c64000
+#define DA8XX_USB1_BASE 0x01e25000
#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
static struct musb_hdrc_eps_bits musb_eps[] = {
@@ -108,3 +106,36 @@ void __init setup_usb(unsigned mA, unsigned potpgt_msec)
#endif /* CONFIG_USB_MUSB_HDRC */
+#ifdef CONFIG_ARCH_DAVINCI_DA8XX
+static struct resource da8xx_usb11_resources[] = {
+ [0] = {
+ .start = DA8XX_USB1_BASE,
+ .end = DA8XX_USB1_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_DA8XX_IRQN,
+ .end = IRQ_DA8XX_IRQN,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 da8xx_usb11_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device da8xx_usb11_device = {
+ .name = "ohci",
+ .id = 0,
+ .dev = {
+ .dma_mask = &da8xx_usb11_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .num_resources = ARRAY_SIZE(da8xx_usb11_resources),
+ .resource = da8xx_usb11_resources,
+};
+
+int __init da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata)
+{
+ da8xx_usb11_device.dev.platform_data = pdata;
+ return platform_device_register(&da8xx_usb11_device);
+}
+#endif /* CONFIG_DAVINCI_DA8XX */
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index f95dc160c34b..b4357c388d2e 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -206,7 +206,6 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc)
for (i = 0; i < 8; i++) {
if (status & (1 << i)) {
int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i;
- desc = irq_desc + gpio_irq;
generic_handle_irq(gpio_irq);
}
}
diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c
index ca71cf1a72a0..a4a7be308000 100644
--- a/arch/arm/mach-ep93xx/edb93xx.c
+++ b/arch/arm/mach-ep93xx/edb93xx.c
@@ -112,7 +112,7 @@ static void __init edb93xx_register_i2c(void)
ARRAY_SIZE(edb93xxa_i2c_board_info));
} else if (machine_is_edb9307() || machine_is_edb9312() ||
machine_is_edb9315()) {
- ep93xx_register_i2c(&edb93xx_i2c_gpio_data
+ ep93xx_register_i2c(&edb93xx_i2c_gpio_data,
edb93xx_i2c_board_info,
ARRAY_SIZE(edb93xx_i2c_board_info));
}
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index a3ec33fd79d4..469fd968d517 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -17,7 +17,6 @@ struct ep93xx_eth_data
void ep93xx_map_io(void);
void ep93xx_init_irq(void);
-void ep93xx_init_time(unsigned long);
/* EP93xx System Controller software locked register write */
void ep93xx_syscon_swlocked_write(unsigned int val, void __iomem *reg);
diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c
index 4562452d4074..7cb3bd9352ae 100644
--- a/arch/arm/mach-mmp/aspenite.c
+++ b/arch/arm/mach-mmp/aspenite.c
@@ -13,6 +13,9 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/smc91x.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -20,6 +23,7 @@
#include <mach/mfp-pxa168.h>
#include <mach/pxa168.h>
#include <mach/gpio.h>
+#include <plat/pxa3xx_nand.h>
#include "common.h"
@@ -85,12 +89,50 @@ static struct platform_device smc91x_device = {
.resource = smc91x_resources,
};
+#if defined(CONFIG_MTD_NAND) || defined(CONFIG_MTD_NAND_MODULE)
+static struct mtd_partition aspenite_nand_partitions[] = {
+ {
+ .name = "bootloader",
+ .offset = 0,
+ .size = SZ_1M,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "reserved",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_128K,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "reserved",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_8M,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = (SZ_2M + SZ_1M),
+ .mask_flags = 0,
+ }, {
+ .name = "filesystem",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_48M,
+ .mask_flags = 0,
+ }
+};
+
+static struct pxa3xx_nand_platform_data aspenite_nand_info = {
+ .enable_arbiter = 1,
+ .parts = aspenite_nand_partitions,
+ .nr_parts = ARRAY_SIZE(aspenite_nand_partitions),
+};
+#endif
+
static void __init common_init(void)
{
mfp_config(ARRAY_AND_SIZE(common_pin_config));
/* on-chip devices */
pxa168_add_uart(1);
+ pxa168_add_nand(&aspenite_nand_info);
/* off-chip devices */
platform_device_register(&smc91x_device);
diff --git a/arch/arm/mach-mmp/clock.c b/arch/arm/mach-mmp/clock.c
index 2d9cc5a7122f..2a46ed5cc2a2 100644
--- a/arch/arm/mach-mmp/clock.c
+++ b/arch/arm/mach-mmp/clock.c
@@ -34,6 +34,21 @@ struct clkops apbc_clk_ops = {
.disable = apbc_clk_disable,
};
+static void apmu_clk_enable(struct clk *clk)
+{
+ __raw_writel(clk->enable_val, clk->clk_rst);
+}
+
+static void apmu_clk_disable(struct clk *clk)
+{
+ __raw_writel(0, clk->clk_rst);
+}
+
+struct clkops apmu_clk_ops = {
+ .enable = apmu_clk_enable,
+ .disable = apmu_clk_disable,
+};
+
static DEFINE_SPINLOCK(clocks_lock);
int clk_enable(struct clk *clk)
diff --git a/arch/arm/mach-mmp/clock.h b/arch/arm/mach-mmp/clock.h
index ed967e78e6a8..eefffbe683b0 100644
--- a/arch/arm/mach-mmp/clock.h
+++ b/arch/arm/mach-mmp/clock.h
@@ -25,6 +25,7 @@ struct clk {
};
extern struct clkops apbc_clk_ops;
+extern struct clkops apmu_clk_ops;
#define APBC_CLK(_name, _reg, _fnclksel, _rate) \
struct clk clk_##_name = { \
diff --git a/arch/arm/mach-mmp/include/mach/irqs.h b/arch/arm/mach-mmp/include/mach/irqs.h
index 16295cfd5e29..d68871b0f28c 100644
--- a/arch/arm/mach-mmp/include/mach/irqs.h
+++ b/arch/arm/mach-mmp/include/mach/irqs.h
@@ -31,7 +31,9 @@
#define IRQ_PXA168_DDR_INT 26
#define IRQ_PXA168_UART1 27
#define IRQ_PXA168_UART2 28
+#define IRQ_PXA168_UART3 29
#define IRQ_PXA168_WDT 35
+#define IRQ_PXA168_MAIN_PMU 36
#define IRQ_PXA168_FRQ_CHANGE 38
#define IRQ_PXA168_SDH1 39
#define IRQ_PXA168_SDH2 40
@@ -46,7 +48,7 @@
#define IRQ_PXA168_USB2 51
#define IRQ_PXA168_AC97 57
#define IRQ_PXA168_TWSI1 58
-#define IRQ_PXA168_PMU 60
+#define IRQ_PXA168_AP_PMU 60
#define IRQ_PXA168_SM_INT 63
/*
diff --git a/arch/arm/mach-mmp/include/mach/pxa168.h b/arch/arm/mach-mmp/include/mach/pxa168.h
index 6bf1f0eefcd1..3ad612cbdf09 100644
--- a/arch/arm/mach-mmp/include/mach/pxa168.h
+++ b/arch/arm/mach-mmp/include/mach/pxa168.h
@@ -4,6 +4,7 @@
#include <linux/i2c.h>
#include <mach/devices.h>
#include <plat/i2c.h>
+#include <plat/pxa3xx_nand.h>
extern struct pxa_device_desc pxa168_device_uart1;
extern struct pxa_device_desc pxa168_device_uart2;
@@ -13,6 +14,7 @@ extern struct pxa_device_desc pxa168_device_pwm1;
extern struct pxa_device_desc pxa168_device_pwm2;
extern struct pxa_device_desc pxa168_device_pwm3;
extern struct pxa_device_desc pxa168_device_pwm4;
+extern struct pxa_device_desc pxa168_device_nand;
static inline int pxa168_add_uart(int id)
{
@@ -64,4 +66,9 @@ static inline int pxa168_add_pwm(int id)
return pxa_register_device(d, NULL, 0);
}
+
+static inline int pxa168_add_nand(struct pxa3xx_nand_platform_data *info)
+{
+ return pxa_register_device(&pxa168_device_nand, info, sizeof(*info));
+}
#endif /* __ASM_MACH_PXA168_H */
diff --git a/arch/arm/mach-mmp/include/mach/pxa910.h b/arch/arm/mach-mmp/include/mach/pxa910.h
index 6ae1ed7a0a9f..4f0b4ec6f5d0 100644
--- a/arch/arm/mach-mmp/include/mach/pxa910.h
+++ b/arch/arm/mach-mmp/include/mach/pxa910.h
@@ -4,6 +4,7 @@
#include <linux/i2c.h>
#include <mach/devices.h>
#include <plat/i2c.h>
+#include <plat/pxa3xx_nand.h>
extern struct pxa_device_desc pxa910_device_uart1;
extern struct pxa_device_desc pxa910_device_uart2;
@@ -13,6 +14,7 @@ extern struct pxa_device_desc pxa910_device_pwm1;
extern struct pxa_device_desc pxa910_device_pwm2;
extern struct pxa_device_desc pxa910_device_pwm3;
extern struct pxa_device_desc pxa910_device_pwm4;
+extern struct pxa_device_desc pxa910_device_nand;
static inline int pxa910_add_uart(int id)
{
@@ -64,4 +66,9 @@ static inline int pxa910_add_pwm(int id)
return pxa_register_device(d, NULL, 0);
}
+
+static inline int pxa910_add_nand(struct pxa3xx_nand_platform_data *info)
+{
+ return pxa_register_device(&pxa910_device_nand, info, sizeof(*info));
+}
#endif /* __ASM_MACH_PXA910_H */
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index 71b1ae338753..f3e5840d9441 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -127,3 +127,4 @@ PXA168_DEVICE(pwm1, "pxa168-pwm", 0, NONE, 0xd401a000, 0x10);
PXA168_DEVICE(pwm2, "pxa168-pwm", 1, NONE, 0xd401a400, 0x10);
PXA168_DEVICE(pwm3, "pxa168-pwm", 2, NONE, 0xd401a800, 0x10);
PXA168_DEVICE(pwm4, "pxa168-pwm", 3, NONE, 0xd401ac00, 0x10);
+PXA168_DEVICE(nand, "pxa3xx-nand", -1, NAND, 0xd4283000, 0x80, 97, 99);
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index 5882ca6b49fb..28028919cddf 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -174,3 +174,4 @@ PXA910_DEVICE(pwm1, "pxa910-pwm", 0, NONE, 0xd401a000, 0x10);
PXA910_DEVICE(pwm2, "pxa910-pwm", 1, NONE, 0xd401a400, 0x10);
PXA910_DEVICE(pwm3, "pxa910-pwm", 2, NONE, 0xd401a800, 0x10);
PXA910_DEVICE(pwm4, "pxa910-pwm", 3, NONE, 0xd401ac00, 0x10);
+PXA910_DEVICE(nand, "pxa3xx-nand", -1, NAND, 0xd4283000, 0x80, 97, 99);
diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c
index 08cfef6c92a2..10e8401a8304 100644
--- a/arch/arm/mach-mmp/ttc_dkb.c
+++ b/arch/arm/mach-mmp/ttc_dkb.c
@@ -11,9 +11,13 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/onenand.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
#include <mach/addr-map.h>
#include <mach/mfp-pxa910.h>
#include <mach/pxa910.h>
@@ -26,6 +30,86 @@ static unsigned long ttc_dkb_pin_config[] __initdata = {
/* UART2 */
GPIO47_UART2_RXD,
GPIO48_UART2_TXD,
+
+ /* DFI */
+ DF_IO0_ND_IO0,
+ DF_IO1_ND_IO1,
+ DF_IO2_ND_IO2,
+ DF_IO3_ND_IO3,
+ DF_IO4_ND_IO4,
+ DF_IO5_ND_IO5,
+ DF_IO6_ND_IO6,
+ DF_IO7_ND_IO7,
+ DF_IO8_ND_IO8,
+ DF_IO9_ND_IO9,
+ DF_IO10_ND_IO10,
+ DF_IO11_ND_IO11,
+ DF_IO12_ND_IO12,
+ DF_IO13_ND_IO13,
+ DF_IO14_ND_IO14,
+ DF_IO15_ND_IO15,
+ DF_nCS0_SM_nCS2_nCS0,
+ DF_ALE_SM_WEn_ND_ALE,
+ DF_CLE_SM_OEn_ND_CLE,
+ DF_WEn_DF_WEn,
+ DF_REn_DF_REn,
+ DF_RDY0_DF_RDY0,
+};
+
+static struct mtd_partition ttc_dkb_onenand_partitions[] = {
+ {
+ .name = "bootloader",
+ .offset = 0,
+ .size = SZ_1M,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "reserved",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_128K,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "reserved",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_8M,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = (SZ_2M + SZ_1M),
+ .mask_flags = 0,
+ }, {
+ .name = "filesystem",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_48M,
+ .mask_flags = 0,
+ }
+};
+
+static struct flash_platform_data ttc_dkb_onenand_info = {
+ .parts = ttc_dkb_onenand_partitions,
+ .nr_parts = ARRAY_SIZE(ttc_dkb_onenand_partitions),
+};
+
+static struct resource ttc_dkb_resource_onenand[] = {
+ [0] = {
+ .start = SMC_CS0_PHYS_BASE,
+ .end = 256 * SZ_1M,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device ttc_dkb_device_onenand = {
+ .name = "onenand",
+ .id = -1,
+ .resource = ttc_dkb_resource_onenand,
+ .num_resources = ARRAY_SIZE(ttc_dkb_resource_onenand),
+ .dev = {
+ .platform_data = &ttc_dkb_onenand_info,
+ },
+};
+
+static struct platform_device *ttc_dkb_devices[] = {
+ &ttc_dkb_device_onenand,
};
static void __init ttc_dkb_init(void)
@@ -34,6 +118,9 @@ static void __init ttc_dkb_init(void)
/* on-chip devices */
pxa910_add_uart(1);
+
+ /* off-chip devices */
+ platform_add_devices(ARRAY_AND_SIZE(ttc_dkb_devices));
}
MACHINE_START(TTC_DKB, "PXA910-based TTC_DKB Development Platform")
diff --git a/arch/arm/mach-mx2/clock_imx27.c b/arch/arm/mach-mx2/clock_imx27.c
index 4089951acb47..ff5e33298914 100644
--- a/arch/arm/mach-mx2/clock_imx27.c
+++ b/arch/arm/mach-mx2/clock_imx27.c
@@ -638,9 +638,9 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK("mxc-mmc.0", NULL, sdhc1_clk)
_REGISTER_CLOCK("mxc-mmc.1", NULL, sdhc2_clk)
_REGISTER_CLOCK("mxc-mmc.2", NULL, sdhc3_clk)
- _REGISTER_CLOCK(NULL, "cspi1", cspi1_clk)
- _REGISTER_CLOCK(NULL, "cspi2", cspi2_clk)
- _REGISTER_CLOCK(NULL, "cspi3", cspi3_clk)
+ _REGISTER_CLOCK("spi_imx.0", NULL, cspi1_clk)
+ _REGISTER_CLOCK("spi_imx.1", NULL, cspi2_clk)
+ _REGISTER_CLOCK("spi_imx.2", NULL, cspi3_clk)
_REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk)
_REGISTER_CLOCK(NULL, "csi", csi_clk)
_REGISTER_CLOCK("fsl-usb2-udc", "usb", usb_clk)
@@ -665,7 +665,7 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK(NULL, "sahara2", sahara2_clk)
_REGISTER_CLOCK(NULL, "ata", ata_clk)
_REGISTER_CLOCK(NULL, "mstick", mstick_clk)
- _REGISTER_CLOCK(NULL, "wdog", wdog_clk)
+ _REGISTER_CLOCK("imx-wdt.0", NULL, wdog_clk)
_REGISTER_CLOCK(NULL, "gpio", gpio_clk)
_REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk)
_REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk)
diff --git a/arch/arm/mach-mx2/pcm038.c b/arch/arm/mach-mx2/pcm038.c
index ee65dda584cf..906d59b0a7aa 100644
--- a/arch/arm/mach-mx2/pcm038.c
+++ b/arch/arm/mach-mx2/pcm038.c
@@ -23,6 +23,10 @@
#include <linux/mtd/plat-ram.h>
#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/mc13783.h>
+#include <linux/spi/spi.h>
+#include <linux/irq.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -35,6 +39,7 @@
#include <mach/iomux.h>
#include <mach/imx-uart.h>
#include <mach/mxc_nand.h>
+#include <mach/spi.h>
#include "devices.h"
@@ -78,8 +83,6 @@ static int pcm038_pins[] = {
PC6_PF_I2C2_SCL,
/* SPI1 */
PD25_PF_CSPI1_RDY,
- PD27_PF_CSPI1_SS1,
- PD28_PF_CSPI1_SS0,
PD29_PF_CSPI1_SCLK,
PD30_PF_CSPI1_MISO,
PD31_PF_CSPI1_MOSI,
@@ -196,6 +199,86 @@ static struct i2c_board_info pcm038_i2c_devices[] = {
}
};
+static int pcm038_spi_cs[] = {GPIO_PORTD + 28};
+
+static struct spi_imx_master pcm038_spi_0_data = {
+ .chipselect = pcm038_spi_cs,
+ .num_chipselect = ARRAY_SIZE(pcm038_spi_cs),
+};
+
+static struct regulator_consumer_supply sdhc1_consumers[] = {
+ {
+ .dev = &mxc_sdhc_device1.dev,
+ .supply = "sdhc_vcc",
+ },
+};
+
+static struct regulator_init_data sdhc1_data = {
+ .constraints = {
+ .min_uV = 3000000,
+ .max_uV = 3400000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_FAST,
+ .always_on = 0,
+ .boot_on = 0,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(sdhc1_consumers),
+ .consumer_supplies = sdhc1_consumers,
+};
+
+static struct regulator_consumer_supply cam_consumers[] = {
+ {
+ .dev = NULL,
+ .supply = "imx_cam_vcc",
+ },
+};
+
+static struct regulator_init_data cam_data = {
+ .constraints = {
+ .min_uV = 3000000,
+ .max_uV = 3400000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_FAST,
+ .always_on = 0,
+ .boot_on = 0,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(cam_consumers),
+ .consumer_supplies = cam_consumers,
+};
+
+struct mc13783_regulator_init_data pcm038_regulators[] = {
+ {
+ .id = MC13783_REGU_VCAM,
+ .init_data = &cam_data,
+ }, {
+ .id = MC13783_REGU_VMMC1,
+ .init_data = &sdhc1_data,
+ },
+};
+
+static struct mc13783_platform_data pcm038_pmic = {
+ .regulators = pcm038_regulators,
+ .num_regulators = ARRAY_SIZE(pcm038_regulators),
+ .flags = MC13783_USE_ADC | MC13783_USE_REGULATOR |
+ MC13783_USE_TOUCHSCREEN,
+};
+
+static struct spi_board_info pcm038_spi_board_info[] __initdata = {
+ {
+ .modalias = "mc13783",
+ .irq = IRQ_GPIOB(23),
+ .max_speed_hz = 300000,
+ .bus_num = 0,
+ .chip_select = 0,
+ .platform_data = &pcm038_pmic,
+ .mode = SPI_CS_HIGH,
+ }
+};
+
static void __init pcm038_init(void)
{
mxc_gpio_setup_multiple_pins(pcm038_pins, ARRAY_SIZE(pcm038_pins),
@@ -219,6 +302,15 @@ static void __init pcm038_init(void)
/* PE18 for user-LED D40 */
mxc_gpio_mode(GPIO_PORTE | 18 | GPIO_GPIO | GPIO_OUT);
+ mxc_gpio_mode(GPIO_PORTD | 28 | GPIO_GPIO | GPIO_OUT);
+
+ /* MC13783 IRQ */
+ mxc_gpio_mode(GPIO_PORTB | 23 | GPIO_GPIO | GPIO_IN);
+
+ mxc_register_device(&mxc_spi_device0, &pcm038_spi_0_data);
+ spi_register_board_info(pcm038_spi_board_info,
+ ARRAY_SIZE(pcm038_spi_board_info));
+
platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
#ifdef CONFIG_MACH_PCM970_BASEBOARD
diff --git a/arch/arm/mach-mx2/pcm970-baseboard.c b/arch/arm/mach-mx2/pcm970-baseboard.c
index c261f59b0b4c..3cb7f457e5d0 100644
--- a/arch/arm/mach-mx2/pcm970-baseboard.c
+++ b/arch/arm/mach-mx2/pcm970-baseboard.c
@@ -39,7 +39,6 @@ static int pcm970_pins[] = {
PB7_PF_SD2_D3,
PB8_PF_SD2_CMD,
PB9_PF_SD2_CLK,
- GPIO_PORTC | 28 | GPIO_GPIO | GPIO_IN, /* card detect */
/* display */
PA5_PF_LSCLK,
PA6_PF_LD0,
@@ -228,6 +227,7 @@ void __init pcm970_baseboard_init(void)
"PCM970");
mxc_register_device(&mxc_fb_device, &pcm038_fb_data);
+ mxc_gpio_mode(GPIO_PORTC | 28 | GPIO_GPIO | GPIO_IN);
mxc_register_device(&mxc_sdhc_device1, &sdhc_pdata);
platform_device_register(&pcm970_sja1000);
}
diff --git a/arch/arm/mach-mx25/devices.c b/arch/arm/mach-mx25/devices.c
index eb12de1da42d..63511de3a559 100644
--- a/arch/arm/mach-mx25/devices.c
+++ b/arch/arm/mach-mx25/devices.c
@@ -1,4 +1,23 @@
+/*
+ * Copyright 2009 Sascha Hauer, <kernel@pengutronix.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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
#include <linux/gpio.h>
#include <mach/mx25.h>
#include <mach/irqs.h>
diff --git a/arch/arm/mach-mx25/mx25pdk.c b/arch/arm/mach-mx25/mx25pdk.c
index 92aa4fd19d99..d23ae571c03f 100644
--- a/arch/arm/mach-mx25/mx25pdk.c
+++ b/arch/arm/mach-mx25/mx25pdk.c
@@ -1,3 +1,21 @@
+/*
+ * Copyright 2009 Sascha Hauer, <kernel@pengutronix.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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
#include <linux/types.h>
#include <linux/init.h>
#include <linux/clk.h>
@@ -23,19 +41,12 @@ static struct imxuart_platform_data uart_pdata = {
.flags = IMXUART_HAVE_RTSCTS,
};
-static struct mxc_nand_platform_data nand_board_info = {
- .width = 1,
- .hw_ecc = 1,
-};
-
static void __init mx25pdk_init(void)
{
mxc_register_device(&mxc_uart_device0, &uart_pdata);
mxc_register_device(&mxc_usbh2, NULL);
- mxc_register_device(&mxc_nand_device, &nand_board_info);
}
-
static void __init mx25pdk_timer_init(void)
{
mx25_clocks_init(26000000);
diff --git a/arch/arm/mach-mx3/clock-imx35.c b/arch/arm/mach-mx3/clock-imx35.c
index fe5c4217322e..c595260ec1f9 100644
--- a/arch/arm/mach-mx3/clock-imx35.c
+++ b/arch/arm/mach-mx3/clock-imx35.c
@@ -443,7 +443,7 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK("mxc-ehci.1", "usb", usbotg_clk)
_REGISTER_CLOCK("mxc-ehci.2", "usb", usbotg_clk)
_REGISTER_CLOCK("fsl-usb2-udc", "usb", usbotg_clk)
- _REGISTER_CLOCK("mxc_wdt.0", NULL, wdog_clk)
+ _REGISTER_CLOCK("imx-wdt.0", NULL, wdog_clk)
_REGISTER_CLOCK(NULL, "max", max_clk)
_REGISTER_CLOCK(NULL, "admux", admux_clk)
_REGISTER_CLOCK(NULL, "csi", csi_clk)
diff --git a/arch/arm/mach-mx3/clock.c b/arch/arm/mach-mx3/clock.c
index 06bd6180bfc3..b2a3bcf8266e 100644
--- a/arch/arm/mach-mx3/clock.c
+++ b/arch/arm/mach-mx3/clock.c
@@ -530,7 +530,7 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK("spi_imx.2", NULL, cspi3_clk)
_REGISTER_CLOCK(NULL, "gpt", gpt_clk)
_REGISTER_CLOCK(NULL, "pwm", pwm_clk)
- _REGISTER_CLOCK(NULL, "wdog", wdog_clk)
+ _REGISTER_CLOCK("imx-wdt.0", NULL, wdog_clk)
_REGISTER_CLOCK(NULL, "rtc", rtc_clk)
_REGISTER_CLOCK(NULL, "epit", epit1_clk)
_REGISTER_CLOCK(NULL, "epit", epit2_clk)
diff --git a/arch/arm/mach-mx3/devices.c b/arch/arm/mach-mx3/devices.c
index 8a577f367250..e6abe181b967 100644
--- a/arch/arm/mach-mx3/devices.c
+++ b/arch/arm/mach-mx3/devices.c
@@ -459,7 +459,7 @@ struct platform_device mxc_usbh2 = {
* SPI master controller
* 3 channels
*/
-static struct resource imx_spi_0_resources[] = {
+static struct resource mxc_spi_0_resources[] = {
{
.start = CSPI1_BASE_ADDR,
.end = CSPI1_BASE_ADDR + SZ_4K - 1,
@@ -471,7 +471,7 @@ static struct resource imx_spi_0_resources[] = {
},
};
-static struct resource imx_spi_1_resources[] = {
+static struct resource mxc_spi_1_resources[] = {
{
.start = CSPI2_BASE_ADDR,
.end = CSPI2_BASE_ADDR + SZ_4K - 1,
@@ -483,7 +483,7 @@ static struct resource imx_spi_1_resources[] = {
},
};
-static struct resource imx_spi_2_resources[] = {
+static struct resource mxc_spi_2_resources[] = {
{
.start = CSPI3_BASE_ADDR,
.end = CSPI3_BASE_ADDR + SZ_4K - 1,
@@ -495,25 +495,25 @@ static struct resource imx_spi_2_resources[] = {
},
};
-struct platform_device imx_spi_device0 = {
+struct platform_device mxc_spi_device0 = {
.name = "spi_imx",
.id = 0,
- .num_resources = ARRAY_SIZE(imx_spi_0_resources),
- .resource = imx_spi_0_resources,
+ .num_resources = ARRAY_SIZE(mxc_spi_0_resources),
+ .resource = mxc_spi_0_resources,
};
-struct platform_device imx_spi_device1 = {
+struct platform_device mxc_spi_device1 = {
.name = "spi_imx",
.id = 1,
- .num_resources = ARRAY_SIZE(imx_spi_1_resources),
- .resource = imx_spi_1_resources,
+ .num_resources = ARRAY_SIZE(mxc_spi_1_resources),
+ .resource = mxc_spi_1_resources,
};
-struct platform_device imx_spi_device2 = {
+struct platform_device mxc_spi_device2 = {
.name = "spi_imx",
.id = 2,
- .num_resources = ARRAY_SIZE(imx_spi_2_resources),
- .resource = imx_spi_2_resources,
+ .num_resources = ARRAY_SIZE(mxc_spi_2_resources),
+ .resource = mxc_spi_2_resources,
};
#ifdef CONFIG_ARCH_MX35
diff --git a/arch/arm/mach-mx3/devices.h b/arch/arm/mach-mx3/devices.h
index 79f2be45d139..ab87419dc9a0 100644
--- a/arch/arm/mach-mx3/devices.h
+++ b/arch/arm/mach-mx3/devices.h
@@ -20,7 +20,7 @@ extern struct platform_device mxc_otg_host;
extern struct platform_device mxc_usbh1;
extern struct platform_device mxc_usbh2;
extern struct platform_device mxc_rnga_device;
-extern struct platform_device imx_spi_device0;
-extern struct platform_device imx_spi_device1;
-extern struct platform_device imx_spi_device2;
+extern struct platform_device mxc_spi_device0;
+extern struct platform_device mxc_spi_device1;
+extern struct platform_device mxc_spi_device2;
diff --git a/arch/arm/mach-mx3/mm.c b/arch/arm/mach-mx3/mm.c
index ad5a1122d765..bedf5b8d976a 100644
--- a/arch/arm/mach-mx3/mm.c
+++ b/arch/arm/mach-mx3/mm.c
@@ -81,6 +81,7 @@ void __init mx31_map_io(void)
iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc));
}
+#ifdef CONFIG_ARCH_MX35
void __init mx35_map_io(void)
{
mxc_set_cpu_type(MXC_CPU_MX35);
@@ -89,6 +90,7 @@ void __init mx35_map_io(void)
iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc));
}
+#endif
void __init mx31_init_irq(void)
{
diff --git a/arch/arm/mach-nomadik/board-nhk8815.c b/arch/arm/mach-nomadik/board-nhk8815.c
index 6bfd537d5afb..781b915819c8 100644
--- a/arch/arm/mach-nomadik/board-nhk8815.c
+++ b/arch/arm/mach-nomadik/board-nhk8815.c
@@ -18,6 +18,7 @@
#include <linux/gpio.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
+#include <linux/mtd/onenand.h>
#include <linux/mtd/partitions.h>
#include <linux/io.h>
#include <asm/sizes.h>
@@ -142,7 +143,7 @@ static struct mtd_partition nhk8815_onenand_partitions[] = {
}
};
-static struct flash_platform_data nhk8815_onenand_data = {
+static struct onenand_platform_data nhk8815_onenand_data = {
.parts = nhk8815_onenand_partitions,
.nr_parts = ARRAY_SIZE(nhk8815_onenand_partitions),
};
@@ -156,7 +157,7 @@ static struct resource nhk8815_onenand_resource[] = {
};
static struct platform_device nhk8815_onenand_device = {
- .name = "onenand",
+ .name = "onenand-flash",
.id = -1,
.dev = {
.platform_data = &nhk8815_onenand_data,
@@ -167,10 +168,10 @@ static struct platform_device nhk8815_onenand_device = {
static void __init nhk8815_onenand_init(void)
{
-#ifdef CONFIG_ONENAND
+#ifdef CONFIG_MTD_ONENAND
/* Set up SMCS0 for OneNand */
- writel(0x000030db, FSMC_BCR0);
- writel(0x02100551, FSMC_BTR0);
+ writel(0x000030db, FSMC_BCR(0));
+ writel(0x02100551, FSMC_BTR(0));
#endif
}
diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c
index 42920f9c1a11..7214ff40c16a 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -25,13 +25,13 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/board-ams-delta.h>
+#include <plat/board-ams-delta.h>
#include <mach/gpio.h>
-#include <mach/keypad.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/board.h>
-#include <mach/common.h>
+#include <plat/keypad.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/board.h>
+#include <plat/common.h>
static u8 ams_delta_latch1_reg;
static u16 ams_delta_latch2_reg;
diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c
index a7ead1b93226..f4b72c1654f5 100644
--- a/arch/arm/mach-omap1/board-fsample.c
+++ b/arch/arm/mach-omap1/board-fsample.c
@@ -26,14 +26,14 @@
#include <asm/mach/flash.h>
#include <asm/mach/map.h>
-#include <mach/tc.h>
+#include <plat/tc.h>
#include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/fpga.h>
-#include <mach/nand.h>
-#include <mach/keypad.h>
-#include <mach/common.h>
-#include <mach/board.h>
+#include <plat/mux.h>
+#include <plat/fpga.h>
+#include <plat/nand.h>
+#include <plat/keypad.h>
+#include <plat/common.h>
+#include <plat/board.h>
/* fsample is pretty close to p2-sample */
@@ -107,7 +107,7 @@ static struct resource smc91x_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = INT_730_MPU_EXT_NIRQ,
+ .start = INT_7XX_MPU_EXT_NIRQ,
.end = 0,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
},
@@ -196,8 +196,8 @@ static struct platform_device smc91x_device = {
static struct resource kp_resources[] = {
[0] = {
- .start = INT_730_MPUIO_KEYPAD,
- .end = INT_730_MPUIO_KEYPAD,
+ .start = INT_7XX_MPUIO_KEYPAD,
+ .end = INT_7XX_MPUIO_KEYPAD,
.flags = IORESOURCE_IRQ,
},
};
@@ -309,7 +309,7 @@ static void __init omap_fsample_map_io(void)
/*
* Hold GSM Reset until needed
*/
- omap_writew(omap_readw(OMAP730_DSP_M_CTL) & ~1, OMAP730_DSP_M_CTL);
+ omap_writew(omap_readw(OMAP7XX_DSP_M_CTL) & ~1, OMAP7XX_DSP_M_CTL);
/*
* UARTs -> done automagically by 8250 driver
@@ -320,21 +320,21 @@ static void __init omap_fsample_map_io(void)
*/
/* Flash: CS0 timings setup */
- omap_writel(0x0000fff3, OMAP730_FLASH_CFG_0);
- omap_writel(0x00000088, OMAP730_FLASH_ACFG_0);
+ omap_writel(0x0000fff3, OMAP7XX_FLASH_CFG_0);
+ omap_writel(0x00000088, OMAP7XX_FLASH_ACFG_0);
/*
* Ethernet support through the debug board
* CS1 timings setup
*/
- omap_writel(0x0000fff3, OMAP730_FLASH_CFG_1);
- omap_writel(0x00000000, OMAP730_FLASH_ACFG_1);
+ omap_writel(0x0000fff3, OMAP7XX_FLASH_CFG_1);
+ omap_writel(0x00000000, OMAP7XX_FLASH_ACFG_1);
/*
* Configure MPU_EXT_NIRQ IO in IO_CONF9 register,
* It is used as the Ethernet controller interrupt
*/
- omap_writel(omap_readl(OMAP730_IO_CONF_9) & 0x1FFFFFFF, OMAP730_IO_CONF_9);
+ omap_writel(omap_readl(OMAP7XX_IO_CONF_9) & 0x1FFFFFFF, OMAP7XX_IO_CONF_9);
}
MACHINE_START(OMAP_FSAMPLE, "OMAP730 F-Sample")
diff --git a/arch/arm/mach-omap1/board-generic.c b/arch/arm/mach-omap1/board-generic.c
index fb47239da72f..aaea01823eb2 100644
--- a/arch/arm/mach-omap1/board-generic.c
+++ b/arch/arm/mach-omap1/board-generic.c
@@ -23,10 +23,10 @@
#include <asm/mach/map.h>
#include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/board.h>
-#include <mach/common.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/board.h>
+#include <plat/common.h>
static void __init omap_generic_init_irq(void)
{
diff --git a/arch/arm/mach-omap1/board-h2-mmc.c b/arch/arm/mach-omap1/board-h2-mmc.c
index 46098f546824..b30c4990744d 100644
--- a/arch/arm/mach-omap1/board-h2-mmc.c
+++ b/arch/arm/mach-omap1/board-h2-mmc.c
@@ -16,7 +16,7 @@
#include <linux/i2c/tps65010.h>
-#include <mach/mmc.h>
+#include <plat/mmc.h>
#include <mach/gpio.h>
#include "board-h2.h"
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index aab860307dca..89ba8ec4bbf4 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -37,14 +37,14 @@
#include <asm/mach/flash.h>
#include <asm/mach/map.h>
-#include <mach/mux.h>
-#include <mach/dma.h>
-#include <mach/tc.h>
-#include <mach/nand.h>
-#include <mach/irda.h>
-#include <mach/usb.h>
-#include <mach/keypad.h>
-#include <mach/common.h>
+#include <plat/mux.h>
+#include <plat/dma.h>
+#include <plat/tc.h>
+#include <plat/nand.h>
+#include <plat/irda.h>
+#include <plat/usb.h>
+#include <plat/keypad.h>
+#include <plat/common.h>
#include "board-h2.h"
diff --git a/arch/arm/mach-omap1/board-h3-mmc.c b/arch/arm/mach-omap1/board-h3-mmc.c
index 5e8877ce35e0..54b0f063e263 100644
--- a/arch/arm/mach-omap1/board-h3-mmc.c
+++ b/arch/arm/mach-omap1/board-h3-mmc.c
@@ -16,7 +16,7 @@
#include <linux/i2c/tps65010.h>
-#include <mach/mmc.h>
+#include <plat/mmc.h>
#include <mach/gpio.h>
#include "board-h3.h"
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 89586b80b8d5..f5cc0a730524 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -40,13 +40,13 @@
#include <asm/mach/map.h>
#include <mach/irqs.h>
-#include <mach/mux.h>
-#include <mach/tc.h>
-#include <mach/nand.h>
-#include <mach/usb.h>
-#include <mach/keypad.h>
-#include <mach/dma.h>
-#include <mach/common.h>
+#include <plat/mux.h>
+#include <plat/tc.h>
+#include <plat/nand.h>
+#include <plat/usb.h>
+#include <plat/keypad.h>
+#include <plat/dma.h>
+#include <plat/common.h>
#include "board-h3.h"
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
index cc2abbb2d0f4..68462c505e3d 100644
--- a/arch/arm/mach-omap1/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -30,14 +30,14 @@
#include <asm/mach/flash.h>
#include <asm/mach/map.h>
-#include <mach/mux.h>
-#include <mach/fpga.h>
+#include <plat/mux.h>
+#include <plat/fpga.h>
#include <mach/gpio.h>
-#include <mach/tc.h>
-#include <mach/usb.h>
-#include <mach/keypad.h>
-#include <mach/common.h>
-#include <mach/mmc.h>
+#include <plat/tc.h>
+#include <plat/usb.h>
+#include <plat/keypad.h>
+#include <plat/common.h>
+#include <plat/mmc.h>
/* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */
#define INNOVATOR1610_ETHR_START 0x04000300
diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
index ed2a48a9ce74..5a275bab2dfe 100644
--- a/arch/arm/mach-omap1/board-nokia770.c
+++ b/arch/arm/mach-omap1/board-nokia770.c
@@ -26,17 +26,17 @@
#include <asm/mach/map.h>
#include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/board.h>
-#include <mach/keypad.h>
-#include <mach/common.h>
-#include <mach/dsp_common.h>
-#include <mach/omapfb.h>
-#include <mach/hwa742.h>
-#include <mach/lcd_mipid.h>
-#include <mach/mmc.h>
-#include <mach/clock.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/board.h>
+#include <plat/keypad.h>
+#include <plat/common.h>
+#include <plat/dsp_common.h>
+#include <plat/omapfb.h>
+#include <plat/hwa742.h>
+#include <plat/lcd_mipid.h>
+#include <plat/mmc.h>
+#include <plat/clock.h>
#define ADS7846_PENDOWN_GPIO 15
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index ed891b8a6b15..50c92c13e48a 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -47,10 +47,10 @@
#include <asm/mach/map.h>
#include <asm/mach/flash.h>
-#include <mach/usb.h>
-#include <mach/mux.h>
-#include <mach/tc.h>
-#include <mach/common.h>
+#include <plat/usb.h>
+#include <plat/mux.h>
+#include <plat/tc.h>
+#include <plat/common.h>
/* At OMAP5912 OSK the Ethernet is directly connected to CS1 */
#define OMAP_OSK_ETHR_START 0x04800300
@@ -312,7 +312,7 @@ static struct omap_board_config_kernel osk_config[] __initdata = {
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
-#include <mach/keypad.h>
+#include <plat/keypad.h>
static struct at24_platform_data at24c04 = {
.byte_len = SZ_4K / 8,
diff --git a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c
index 90dd0431b0dc..73d115e288a1 100644
--- a/arch/arm/mach-omap1/board-palmte.c
+++ b/arch/arm/mach-omap1/board-palmte.c
@@ -34,14 +34,14 @@
#include <asm/mach/flash.h>
#include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/tc.h>
-#include <mach/dma.h>
-#include <mach/board.h>
-#include <mach/irda.h>
-#include <mach/keypad.h>
-#include <mach/common.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/tc.h>
+#include <plat/dma.h>
+#include <plat/board.h>
+#include <plat/irda.h>
+#include <plat/keypad.h>
+#include <plat/common.h>
#define PALMTE_USBDETECT_GPIO 0
#define PALMTE_USB_OR_DC_GPIO 1
diff --git a/arch/arm/mach-omap1/board-palmtt.c b/arch/arm/mach-omap1/board-palmtt.c
index 8256139891ff..81dd74dbbd33 100644
--- a/arch/arm/mach-omap1/board-palmtt.c
+++ b/arch/arm/mach-omap1/board-palmtt.c
@@ -29,16 +29,16 @@
#include <asm/mach/map.h>
#include <asm/mach/flash.h>
-#include <mach/led.h>
+#include <plat/led.h>
#include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/dma.h>
-#include <mach/tc.h>
-#include <mach/board.h>
-#include <mach/irda.h>
-#include <mach/keypad.h>
-#include <mach/common.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/dma.h>
+#include <plat/tc.h>
+#include <plat/board.h>
+#include <plat/irda.h>
+#include <plat/keypad.h>
+#include <plat/common.h>
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
diff --git a/arch/arm/mach-omap1/board-palmz71.c b/arch/arm/mach-omap1/board-palmz71.c
index 81b6bde1c5a3..427ad3a6591f 100644
--- a/arch/arm/mach-omap1/board-palmz71.c
+++ b/arch/arm/mach-omap1/board-palmz71.c
@@ -33,15 +33,15 @@
#include <asm/mach/flash.h>
#include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/dma.h>
-#include <mach/tc.h>
-#include <mach/board.h>
-#include <mach/irda.h>
-#include <mach/keypad.h>
-#include <mach/common.h>
-#include <mach/omap-alsa.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/dma.h>
+#include <plat/tc.h>
+#include <plat/board.h>
+#include <plat/irda.h>
+#include <plat/keypad.h>
+#include <plat/common.h>
+#include <plat/omap-alsa.h>
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index 83406699f310..ca7df1e93efc 100644
--- a/arch/arm/mach-omap1/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -26,14 +26,14 @@
#include <asm/mach/flash.h>
#include <asm/mach/map.h>
-#include <mach/tc.h>
+#include <plat/tc.h>
#include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/fpga.h>
-#include <mach/nand.h>
-#include <mach/keypad.h>
-#include <mach/common.h>
-#include <mach/board.h>
+#include <plat/mux.h>
+#include <plat/fpga.h>
+#include <plat/nand.h>
+#include <plat/keypad.h>
+#include <plat/common.h>
+#include <plat/board.h>
static int p2_keymap[] = {
KEY(0,0,KEY_UP),
@@ -74,7 +74,7 @@ static struct resource smc91x_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = INT_730_MPU_EXT_NIRQ,
+ .start = INT_7XX_MPU_EXT_NIRQ,
.end = 0,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
},
@@ -163,8 +163,8 @@ static struct platform_device smc91x_device = {
static struct resource kp_resources[] = {
[0] = {
- .start = INT_730_MPUIO_KEYPAD,
- .end = INT_730_MPUIO_KEYPAD,
+ .start = INT_7XX_MPUIO_KEYPAD,
+ .end = INT_7XX_MPUIO_KEYPAD,
.flags = IORESOURCE_IRQ,
},
};
@@ -270,7 +270,7 @@ static void __init omap_perseus2_map_io(void)
/*
* Hold GSM Reset until needed
*/
- omap_writew(omap_readw(OMAP730_DSP_M_CTL) & ~1, OMAP730_DSP_M_CTL);
+ omap_writew(omap_readw(OMAP7XX_DSP_M_CTL) & ~1, OMAP7XX_DSP_M_CTL);
/*
* UARTs -> done automagically by 8250 driver
@@ -281,21 +281,21 @@ static void __init omap_perseus2_map_io(void)
*/
/* Flash: CS0 timings setup */
- omap_writel(0x0000fff3, OMAP730_FLASH_CFG_0);
- omap_writel(0x00000088, OMAP730_FLASH_ACFG_0);
+ omap_writel(0x0000fff3, OMAP7XX_FLASH_CFG_0);
+ omap_writel(0x00000088, OMAP7XX_FLASH_ACFG_0);
/*
* Ethernet support through the debug board
* CS1 timings setup
*/
- omap_writel(0x0000fff3, OMAP730_FLASH_CFG_1);
- omap_writel(0x00000000, OMAP730_FLASH_ACFG_1);
+ omap_writel(0x0000fff3, OMAP7XX_FLASH_CFG_1);
+ omap_writel(0x00000000, OMAP7XX_FLASH_ACFG_1);
/*
* Configure MPU_EXT_NIRQ IO in IO_CONF9 register,
* It is used as the Ethernet controller interrupt
*/
- omap_writel(omap_readl(OMAP730_IO_CONF_9) & 0x1FFFFFFF, OMAP730_IO_CONF_9);
+ omap_writel(omap_readl(OMAP7XX_IO_CONF_9) & 0x1FFFFFFF, OMAP7XX_IO_CONF_9);
}
MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2")
diff --git a/arch/arm/mach-omap1/board-sx1-mmc.c b/arch/arm/mach-omap1/board-sx1-mmc.c
index 58a46e4e45c3..5b33ae8141bc 100644
--- a/arch/arm/mach-omap1/board-sx1-mmc.c
+++ b/arch/arm/mach-omap1/board-sx1-mmc.c
@@ -15,9 +15,9 @@
#include <linux/platform_device.h>
#include <mach/hardware.h>
-#include <mach/mmc.h>
+#include <plat/mmc.h>
#include <mach/gpio.h>
-#include <mach/board-sx1.h>
+#include <plat/board-sx1.h>
#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
diff --git a/arch/arm/mach-omap1/board-sx1.c b/arch/arm/mach-omap1/board-sx1.c
index 02c85ca2e1df..b3bb01bbaa0d 100644
--- a/arch/arm/mach-omap1/board-sx1.c
+++ b/arch/arm/mach-omap1/board-sx1.c
@@ -33,15 +33,15 @@
#include <asm/mach/map.h>
#include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/dma.h>
-#include <mach/irda.h>
-#include <mach/usb.h>
-#include <mach/tc.h>
-#include <mach/board.h>
-#include <mach/common.h>
-#include <mach/keypad.h>
-#include <mach/board-sx1.h>
+#include <plat/mux.h>
+#include <plat/dma.h>
+#include <plat/irda.h>
+#include <plat/usb.h>
+#include <plat/tc.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/keypad.h>
+#include <plat/board-sx1.h>
/* Write to I2C device */
int sx1_i2c_write_byte(u8 devaddr, u8 regoffset, u8 value)
diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c
index c06e7a553472..ba9db2144b2b 100644
--- a/arch/arm/mach-omap1/board-voiceblue.c
+++ b/arch/arm/mach-omap1/board-voiceblue.c
@@ -29,11 +29,11 @@
#include <asm/mach/flash.h>
#include <asm/mach/map.h>
-#include <mach/common.h>
+#include <plat/common.h>
#include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/tc.h>
-#include <mach/usb.h>
+#include <plat/mux.h>
+#include <plat/tc.h>
+#include <plat/usb.h>
static struct plat_serial8250_port voiceblue_ports[] = {
{
diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c
index 436eed22801b..b4fec9a6e89e 100644
--- a/arch/arm/mach-omap1/clock.c
+++ b/arch/arm/mach-omap1/clock.c
@@ -22,10 +22,10 @@
#include <asm/mach-types.h>
#include <asm/clkdev.h>
-#include <mach/cpu.h>
-#include <mach/usb.h>
-#include <mach/clock.h>
-#include <mach/sram.h>
+#include <plat/cpu.h>
+#include <plat/usb.h>
+#include <plat/clock.h>
+#include <plat/sram.h>
static const struct clkops clkops_generic;
static const struct clkops clkops_uart;
@@ -69,13 +69,13 @@ struct omap_clk {
}
#define CK_310 (1 << 0)
-#define CK_730 (1 << 1)
+#define CK_7XX (1 << 1)
#define CK_1510 (1 << 2)
#define CK_16XX (1 << 3)
static struct omap_clk omap_clks[] = {
/* non-ULPD clocks */
- CLK(NULL, "ck_ref", &ck_ref, CK_16XX | CK_1510 | CK_310),
+ CLK(NULL, "ck_ref", &ck_ref, CK_16XX | CK_1510 | CK_310 | CK_7XX),
CLK(NULL, "ck_dpll1", &ck_dpll1, CK_16XX | CK_1510 | CK_310),
/* CK_GEN1 clocks */
CLK(NULL, "ck_dpll1out", &ck_dpll1out.clk, CK_16XX),
@@ -83,7 +83,7 @@ static struct omap_clk omap_clks[] = {
CLK(NULL, "arm_ck", &arm_ck, CK_16XX | CK_1510 | CK_310),
CLK(NULL, "armper_ck", &armper_ck.clk, CK_16XX | CK_1510 | CK_310),
CLK(NULL, "arm_gpio_ck", &arm_gpio_ck, CK_1510 | CK_310),
- CLK(NULL, "armxor_ck", &armxor_ck.clk, CK_16XX | CK_1510 | CK_310),
+ CLK(NULL, "armxor_ck", &armxor_ck.clk, CK_16XX | CK_1510 | CK_310 | CK_7XX),
CLK(NULL, "armtim_ck", &armtim_ck.clk, CK_16XX | CK_1510 | CK_310),
CLK("omap_wdt", "fck", &armwdt_ck.clk, CK_16XX | CK_1510 | CK_310),
CLK("omap_wdt", "ick", &armper_ck.clk, CK_16XX),
@@ -97,7 +97,7 @@ static struct omap_clk omap_clks[] = {
CLK(NULL, "dspxor_ck", &dspxor_ck, CK_16XX | CK_1510 | CK_310),
CLK(NULL, "dsptim_ck", &dsptim_ck, CK_16XX | CK_1510 | CK_310),
/* CK_GEN3 clocks */
- CLK(NULL, "tc_ck", &tc_ck.clk, CK_16XX | CK_1510 | CK_310 | CK_730),
+ CLK(NULL, "tc_ck", &tc_ck.clk, CK_16XX | CK_1510 | CK_310 | CK_7XX),
CLK(NULL, "tipb_ck", &tipb_ck, CK_1510 | CK_310),
CLK(NULL, "l3_ocpi_ck", &l3_ocpi_ck, CK_16XX),
CLK(NULL, "tc1_ck", &tc1_ck, CK_16XX),
@@ -108,7 +108,7 @@ static struct omap_clk omap_clks[] = {
CLK(NULL, "lb_ck", &lb_ck.clk, CK_1510 | CK_310),
CLK(NULL, "rhea1_ck", &rhea1_ck, CK_16XX),
CLK(NULL, "rhea2_ck", &rhea2_ck, CK_16XX),
- CLK(NULL, "lcd_ck", &lcd_ck_16xx, CK_16XX | CK_730),
+ CLK(NULL, "lcd_ck", &lcd_ck_16xx, CK_16XX | CK_7XX),
CLK(NULL, "lcd_ck", &lcd_ck_1510.clk, CK_1510 | CK_310),
/* ULPD clocks */
CLK(NULL, "uart1_ck", &uart1_1510, CK_1510 | CK_310),
@@ -398,7 +398,7 @@ static int omap1_select_table_rate(struct clk * clk, unsigned long rate)
* Reprogramming the DPLL is tricky, it must be done from SRAM.
* (on 730, bit 13 must always be 1)
*/
- if (cpu_is_omap730())
+ if (cpu_is_omap7xx())
omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val | 0x2000);
else
omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val);
@@ -783,8 +783,8 @@ int __init omap1_clk_init(void)
cpu_mask |= CK_16XX;
if (cpu_is_omap1510())
cpu_mask |= CK_1510;
- if (cpu_is_omap730())
- cpu_mask |= CK_730;
+ if (cpu_is_omap7xx())
+ cpu_mask |= CK_7XX;
if (cpu_is_omap310())
cpu_mask |= CK_310;
@@ -800,7 +800,7 @@ int __init omap1_clk_init(void)
crystal_type = info->system_clock_type;
}
-#if defined(CONFIG_ARCH_OMAP730)
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
ck_ref.rate = 13000000;
#elif defined(CONFIG_ARCH_OMAP16XX)
if (crystal_type == 2)
@@ -847,7 +847,7 @@ int __init omap1_clk_init(void)
printk(KERN_ERR "System frequencies not set. Check your config.\n");
/* Guess sane values (60MHz) */
omap_writew(0x2290, DPLL_CTL);
- omap_writew(cpu_is_omap730() ? 0x3005 : 0x1005, ARM_CKCTL);
+ omap_writew(cpu_is_omap7xx() ? 0x3005 : 0x1005, ARM_CKCTL);
ck_dpll1.rate = 60000000;
}
#endif
@@ -862,7 +862,7 @@ int __init omap1_clk_init(void)
#if defined(CONFIG_MACH_OMAP_PERSEUS2) || defined(CONFIG_MACH_OMAP_FSAMPLE)
/* Select slicer output as OMAP input clock */
- omap_writew(omap_readw(OMAP730_PCC_UPLD_CTRL) & ~0x1, OMAP730_PCC_UPLD_CTRL);
+ omap_writew(omap_readw(OMAP7XX_PCC_UPLD_CTRL) & ~0x1, OMAP7XX_PCC_UPLD_CTRL);
#endif
/* Amstrad Delta wants BCLK high when inactive */
@@ -873,7 +873,7 @@ int __init omap1_clk_init(void)
/* Turn off DSP and ARM_TIMXO. Make sure ARM_INTHCK is not divided */
/* (on 730, bit 13 must not be cleared) */
- if (cpu_is_omap730())
+ if (cpu_is_omap7xx())
omap_writew(omap_readw(ARM_CKCTL) & 0x2fff, ARM_CKCTL);
else
omap_writew(omap_readw(ARM_CKCTL) & 0x0fff, ARM_CKCTL);
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
index 06808434ea04..6d2f72dcbb04 100644
--- a/arch/arm/mach-omap1/devices.c
+++ b/arch/arm/mach-omap1/devices.c
@@ -18,11 +18,11 @@
#include <mach/hardware.h>
#include <asm/mach/map.h>
-#include <mach/tc.h>
-#include <mach/board.h>
-#include <mach/mux.h>
+#include <plat/tc.h>
+#include <plat/board.h>
+#include <plat/mux.h>
#include <mach/gpio.h>
-#include <mach/mmc.h>
+#include <plat/mmc.h>
/*-------------------------------------------------------------------------*/
diff --git a/arch/arm/mach-omap1/fpga.c b/arch/arm/mach-omap1/fpga.c
index 4f2b8a7adb19..5cfce1636da0 100644
--- a/arch/arm/mach-omap1/fpga.c
+++ b/arch/arm/mach-omap1/fpga.c
@@ -27,7 +27,7 @@
#include <asm/irq.h>
#include <asm/mach/irq.h>
-#include <mach/fpga.h>
+#include <plat/fpga.h>
#include <mach/gpio.h>
static void fpga_mask_irq(unsigned int irq)
diff --git a/arch/arm/mach-omap1/id.c b/arch/arm/mach-omap1/id.c
index e5dcdf764c91..a0e3560b39db 100644
--- a/arch/arm/mach-omap1/id.c
+++ b/arch/arm/mach-omap1/id.c
@@ -15,7 +15,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
-#include <mach/cpu.h>
+#include <plat/cpu.h>
#define OMAP_DIE_ID_0 0xfffe1800
#define OMAP_DIE_ID_1 0xfffe1804
diff --git a/arch/arm/mach-omap1/include/mach/clkdev.h b/arch/arm/mach-omap1/include/mach/clkdev.h
new file mode 100644
index 000000000000..ea8640e4603e
--- /dev/null
+++ b/arch/arm/mach-omap1/include/mach/clkdev.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/clkdev.h
+ */
+
+#include <plat/clkdev.h>
diff --git a/arch/arm/mach-omap1/include/mach/debug-macro.S b/arch/arm/mach-omap1/include/mach/debug-macro.S
new file mode 100644
index 000000000000..aedb746fc33c
--- /dev/null
+++ b/arch/arm/mach-omap1/include/mach/debug-macro.S
@@ -0,0 +1,45 @@
+/* arch/arm/mach-omap1/include/mach/debug-macro.S
+ *
+ * Debugging macro include header
+ *
+ * Copyright (C) 1994-1999 Russell King
+ * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
+ *
+ * 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.
+ *
+*/
+
+ .macro addruart,rx
+ mrc p15, 0, \rx, c1, c0
+ tst \rx, #1 @ MMU enabled?
+ moveq \rx, #0xff000000 @ physical base address
+ movne \rx, #0xfe000000 @ virtual base
+ orr \rx, \rx, #0x00fb0000
+#ifdef CONFIG_OMAP_LL_DEBUG_UART3
+ orr \rx, \rx, #0x00009000 @ UART 3
+#endif
+#if defined(CONFIG_OMAP_LL_DEBUG_UART2) || defined(CONFIG_OMAP_LL_DEBUG_UART3)
+ orr \rx, \rx, #0x00000800 @ UART 2 & 3
+#endif
+ .endm
+
+ .macro senduart,rd,rx
+ strb \rd, [\rx]
+ .endm
+
+ .macro busyuart,rd,rx
+1001: ldrb \rd, [\rx, #(0x5 << 2)] @ OMAP-1510 and friends
+ and \rd, \rd, #0x60
+ teq \rd, #0x60
+ beq 1002f
+ ldrb \rd, [\rx, #(0x5 << 0)] @ OMAP-730 only
+ and \rd, \rd, #0x60
+ teq \rd, #0x60
+ bne 1001b
+1002:
+ .endm
+
+ .macro waituart,rd,rx
+ .endm
diff --git a/arch/arm/mach-omap1/include/mach/entry-macro.S b/arch/arm/mach-omap1/include/mach/entry-macro.S
new file mode 100644
index 000000000000..df9060edda28
--- /dev/null
+++ b/arch/arm/mach-omap1/include/mach/entry-macro.S
@@ -0,0 +1,58 @@
+/*
+ * arch/arm/mach-omap1/include/mach/entry-macro.S
+ *
+ * Low-level IRQ helper macros for OMAP-based platforms
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * 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 <mach/hardware.h>
+#include <mach/io.h>
+#include <mach/irqs.h>
+#include <asm/hardware/gic.h>
+
+#if (defined(CONFIG_ARCH_OMAP730)||defined(CONFIG_ARCH_OMAP850)) && \
+ (defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX))
+#error "FIXME: OMAP7XX doesn't support multiple-OMAP"
+#elif defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+#define INT_IH2_IRQ INT_7XX_IH2_IRQ
+#elif defined(CONFIG_ARCH_OMAP15XX)
+#define INT_IH2_IRQ INT_1510_IH2_IRQ
+#elif defined(CONFIG_ARCH_OMAP16XX)
+#define INT_IH2_IRQ INT_1610_IH2_IRQ
+#else
+#warning "IH2 IRQ defaulted"
+#define INT_IH2_IRQ INT_1510_IH2_IRQ
+#endif
+
+ .macro disable_fiq
+ .endm
+
+ .macro get_irqnr_preamble, base, tmp
+ .endm
+
+ .macro arch_ret_to_user, tmp1, tmp2
+ .endm
+
+ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
+ ldr \base, =OMAP1_IO_ADDRESS(OMAP_IH1_BASE)
+ ldr \irqnr, [\base, #IRQ_ITR_REG_OFFSET]
+ ldr \tmp, [\base, #IRQ_MIR_REG_OFFSET]
+ mov \irqstat, #0xffffffff
+ bic \tmp, \irqstat, \tmp
+ tst \irqnr, \tmp
+ beq 1510f
+
+ ldr \irqnr, [\base, #IRQ_SIR_FIQ_REG_OFFSET]
+ cmp \irqnr, #0
+ ldreq \irqnr, [\base, #IRQ_SIR_IRQ_REG_OFFSET]
+ cmpeq \irqnr, #INT_IH2_IRQ
+ ldreq \base, =OMAP1_IO_ADDRESS(OMAP_IH2_BASE)
+ ldreq \irqnr, [\base, #IRQ_SIR_IRQ_REG_OFFSET]
+ addeqs \irqnr, \irqnr, #32
+1510:
+ .endm
+
diff --git a/arch/arm/mach-omap1/include/mach/gpio.h b/arch/arm/mach-omap1/include/mach/gpio.h
new file mode 100644
index 000000000000..e737706a8fe1
--- /dev/null
+++ b/arch/arm/mach-omap1/include/mach/gpio.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/gpio.h
+ */
+
+#include <plat/gpio.h>
diff --git a/arch/arm/mach-omap1/include/mach/hardware.h b/arch/arm/mach-omap1/include/mach/hardware.h
new file mode 100644
index 000000000000..a3f6287b2007
--- /dev/null
+++ b/arch/arm/mach-omap1/include/mach/hardware.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/hardware.h
+ */
+
+#include <plat/hardware.h>
diff --git a/arch/arm/mach-omap1/include/mach/io.h b/arch/arm/mach-omap1/include/mach/io.h
new file mode 100644
index 000000000000..57bdf74a3e64
--- /dev/null
+++ b/arch/arm/mach-omap1/include/mach/io.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/io.h
+ */
+
+#include <plat/io.h>
diff --git a/arch/arm/mach-omap1/include/mach/irqs.h b/arch/arm/mach-omap1/include/mach/irqs.h
new file mode 100644
index 000000000000..9292fdc1cb0b
--- /dev/null
+++ b/arch/arm/mach-omap1/include/mach/irqs.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/irqs.h
+ */
+
+#include <plat/irqs.h>
diff --git a/arch/arm/mach-omap1/include/mach/memory.h b/arch/arm/mach-omap1/include/mach/memory.h
new file mode 100644
index 000000000000..e9b600c113ef
--- /dev/null
+++ b/arch/arm/mach-omap1/include/mach/memory.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/memory.h
+ */
+
+#include <plat/memory.h>
diff --git a/arch/arm/plat-omap/include/mach/mtd-xip.h b/arch/arm/mach-omap1/include/mach/mtd-xip.h
index f82a8dcaad94..f82a8dcaad94 100644
--- a/arch/arm/plat-omap/include/mach/mtd-xip.h
+++ b/arch/arm/mach-omap1/include/mach/mtd-xip.h
diff --git a/arch/arm/mach-omap1/include/mach/smp.h b/arch/arm/mach-omap1/include/mach/smp.h
new file mode 100644
index 000000000000..80a371c06e59
--- /dev/null
+++ b/arch/arm/mach-omap1/include/mach/smp.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/smp.h
+ */
+
+#include <plat/smp.h>
diff --git a/arch/arm/mach-omap1/include/mach/system.h b/arch/arm/mach-omap1/include/mach/system.h
new file mode 100644
index 000000000000..a6c1b3a16dfc
--- /dev/null
+++ b/arch/arm/mach-omap1/include/mach/system.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/system.h
+ */
+
+#include <plat/system.h>
diff --git a/arch/arm/mach-omap1/include/mach/timex.h b/arch/arm/mach-omap1/include/mach/timex.h
new file mode 100644
index 000000000000..4793790d53cc
--- /dev/null
+++ b/arch/arm/mach-omap1/include/mach/timex.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/timex.h
+ */
+
+#include <plat/timex.h>
diff --git a/arch/arm/mach-omap1/include/mach/uncompress.h b/arch/arm/mach-omap1/include/mach/uncompress.h
new file mode 100644
index 000000000000..0ff22dc075c7
--- /dev/null
+++ b/arch/arm/mach-omap1/include/mach/uncompress.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap1/include/mach/uncompress.h
+ */
+
+#include <plat/uncompress.h>
diff --git a/arch/arm/mach-omap1/include/mach/vmalloc.h b/arch/arm/mach-omap1/include/mach/vmalloc.h
new file mode 100644
index 000000000000..1b2af14df151
--- /dev/null
+++ b/arch/arm/mach-omap1/include/mach/vmalloc.h
@@ -0,0 +1,20 @@
+/*
+ * arch/arm/mach-omap1/include/mach/vmalloc.h
+ *
+ * Copyright (C) 2000 Russell King.
+ *
+ * This 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
+ */
+#define VMALLOC_END (PAGE_OFFSET + 0x18000000)
diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c
index 7030f9281ea1..2a6d68aa3489 100644
--- a/arch/arm/mach-omap1/io.c
+++ b/arch/arm/mach-omap1/io.c
@@ -15,8 +15,8 @@
#include <asm/tlb.h>
#include <asm/mach/map.h>
-#include <mach/mux.h>
-#include <mach/tc.h>
+#include <plat/mux.h>
+#include <plat/tc.h>
extern int omap1_clk_init(void);
extern void omap_check_revision(void);
@@ -36,33 +36,17 @@ static struct map_desc omap_io_desc[] __initdata = {
}
};
-#ifdef CONFIG_ARCH_OMAP730
-static struct map_desc omap730_io_desc[] __initdata = {
+#if defined (CONFIG_ARCH_OMAP730) || defined (CONFIG_ARCH_OMAP850)
+static struct map_desc omap7xx_io_desc[] __initdata = {
{
- .virtual = OMAP730_DSP_BASE,
- .pfn = __phys_to_pfn(OMAP730_DSP_START),
- .length = OMAP730_DSP_SIZE,
+ .virtual = OMAP7XX_DSP_BASE,
+ .pfn = __phys_to_pfn(OMAP7XX_DSP_START),
+ .length = OMAP7XX_DSP_SIZE,
.type = MT_DEVICE
}, {
- .virtual = OMAP730_DSPREG_BASE,
- .pfn = __phys_to_pfn(OMAP730_DSPREG_START),
- .length = OMAP730_DSPREG_SIZE,
- .type = MT_DEVICE
- }
-};
-#endif
-
-#ifdef CONFIG_ARCH_OMAP850
-static struct map_desc omap850_io_desc[] __initdata = {
- {
- .virtual = OMAP850_DSP_BASE,
- .pfn = __phys_to_pfn(OMAP850_DSP_START),
- .length = OMAP850_DSP_SIZE,
- .type = MT_DEVICE
- }, {
- .virtual = OMAP850_DSPREG_BASE,
- .pfn = __phys_to_pfn(OMAP850_DSPREG_START),
- .length = OMAP850_DSPREG_SIZE,
+ .virtual = OMAP7XX_DSPREG_BASE,
+ .pfn = __phys_to_pfn(OMAP7XX_DSPREG_START),
+ .length = OMAP7XX_DSPREG_SIZE,
.type = MT_DEVICE
}
};
@@ -120,18 +104,11 @@ void __init omap1_map_common_io(void)
*/
omap_check_revision();
-#ifdef CONFIG_ARCH_OMAP730
- if (cpu_is_omap730()) {
- iotable_init(omap730_io_desc, ARRAY_SIZE(omap730_io_desc));
- }
-#endif
-
-#ifdef CONFIG_ARCH_OMAP850
- if (cpu_is_omap850()) {
- iotable_init(omap850_io_desc, ARRAY_SIZE(omap850_io_desc));
+#if defined (CONFIG_ARCH_OMAP730) || defined (CONFIG_ARCH_OMAP850)
+ if (cpu_is_omap7xx()) {
+ iotable_init(omap7xx_io_desc, ARRAY_SIZE(omap7xx_io_desc));
}
#endif
-
#ifdef CONFIG_ARCH_OMAP15XX
if (cpu_is_omap15xx()) {
iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc));
diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c
index de03c8448994..db913c34d1fe 100644
--- a/arch/arm/mach-omap1/irq.c
+++ b/arch/arm/mach-omap1/irq.c
@@ -46,7 +46,7 @@
#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <mach/gpio.h>
-#include <mach/cpu.h>
+#include <plat/cpu.h>
#define IRQ_BANK(irq) ((irq) >> 5)
#define IRQ_BIT(irq) ((irq) & 0x1f)
@@ -137,16 +137,8 @@ static void omap_irq_set_cfg(int irq, int fiq, int priority, int trigger)
irq_bank_writel(val, bank, offset);
}
-#ifdef CONFIG_ARCH_OMAP730
-static struct omap_irq_bank omap730_irq_banks[] = {
- { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3f8e22f },
- { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb9c1f2 },
- { .base_reg = OMAP_IH2_BASE + 0x100, .trigger_map = 0x800040f3 },
-};
-#endif
-
-#ifdef CONFIG_ARCH_OMAP850
-static struct omap_irq_bank omap850_irq_banks[] = {
+#if defined (CONFIG_ARCH_OMAP730) || defined (CONFIG_ARCH_OMAP850)
+static struct omap_irq_bank omap7xx_irq_banks[] = {
{ .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3f8e22f },
{ .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb9c1f2 },
{ .base_reg = OMAP_IH2_BASE + 0x100, .trigger_map = 0x800040f3 },
@@ -186,16 +178,10 @@ void __init omap_init_irq(void)
{
int i, j;
-#ifdef CONFIG_ARCH_OMAP730
- if (cpu_is_omap730()) {
- irq_banks = omap730_irq_banks;
- irq_bank_count = ARRAY_SIZE(omap730_irq_banks);
- }
-#endif
-#ifdef CONFIG_ARCH_OMAP850
- if (cpu_is_omap850()) {
- irq_banks = omap850_irq_banks;
- irq_bank_count = ARRAY_SIZE(omap850_irq_banks);
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+ if (cpu_is_omap7xx()) {
+ irq_banks = omap7xx_irq_banks;
+ irq_bank_count = ARRAY_SIZE(omap7xx_irq_banks);
}
#endif
#ifdef CONFIG_ARCH_OMAP15XX
@@ -247,10 +233,8 @@ void __init omap_init_irq(void)
/* Unmask level 2 handler */
- if (cpu_is_omap730())
- omap_unmask_irq(INT_730_IH2_IRQ);
- else if (cpu_is_omap850())
- omap_unmask_irq(INT_850_IH2_IRQ);
+ if (cpu_is_omap7xx())
+ omap_unmask_irq(INT_7XX_IH2_IRQ);
else if (cpu_is_omap15xx())
omap_unmask_irq(INT_1510_IH2_IRQ);
else if (cpu_is_omap16xx())
diff --git a/arch/arm/mach-omap1/leds-h2p2-debug.c b/arch/arm/mach-omap1/leds-h2p2-debug.c
index 17c9d0e04216..b4f9be52e1e8 100644
--- a/arch/arm/mach-omap1/leds-h2p2-debug.c
+++ b/arch/arm/mach-omap1/leds-h2p2-debug.c
@@ -19,7 +19,7 @@
#include <asm/system.h>
#include <asm/mach-types.h>
-#include <mach/fpga.h>
+#include <plat/fpga.h>
#include <mach/gpio.h>
#include "leds.h"
diff --git a/arch/arm/mach-omap1/leds.c b/arch/arm/mach-omap1/leds.c
index 8cbf2562dcaa..277f356d4cd0 100644
--- a/arch/arm/mach-omap1/leds.c
+++ b/arch/arm/mach-omap1/leds.c
@@ -10,7 +10,7 @@
#include <asm/mach-types.h>
#include <mach/gpio.h>
-#include <mach/mux.h>
+#include <plat/mux.h>
#include "leds.h"
diff --git a/arch/arm/mach-omap1/mailbox.c b/arch/arm/mach-omap1/mailbox.c
index 6810b4aeb02c..caf889aaa248 100644
--- a/arch/arm/mach-omap1/mailbox.c
+++ b/arch/arm/mach-omap1/mailbox.c
@@ -14,7 +14,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
-#include <mach/mailbox.h>
+#include <plat/mailbox.h>
#include <mach/irqs.h>
#define MAILBOX_ARM2DSP1 0x00
diff --git a/arch/arm/mach-omap1/mcbsp.c b/arch/arm/mach-omap1/mcbsp.c
index 505d98cfe508..6bddce104ee9 100644
--- a/arch/arm/mach-omap1/mcbsp.c
+++ b/arch/arm/mach-omap1/mcbsp.c
@@ -18,11 +18,11 @@
#include <linux/platform_device.h>
#include <mach/irqs.h>
-#include <mach/dma.h>
-#include <mach/mux.h>
-#include <mach/cpu.h>
-#include <mach/mcbsp.h>
-#include <mach/dsp_common.h>
+#include <plat/dma.h>
+#include <plat/mux.h>
+#include <plat/cpu.h>
+#include <plat/mcbsp.h>
+#include <plat/dsp_common.h>
#define DPS_RSTCT2_PER_EN (1 << 0)
#define DSP_RSTCT2_WD_PER_EN (1 << 1)
@@ -79,29 +79,29 @@ static struct omap_mcbsp_ops omap1_mcbsp_ops = {
.free = omap1_mcbsp_free,
};
-#ifdef CONFIG_ARCH_OMAP730
-static struct omap_mcbsp_platform_data omap730_mcbsp_pdata[] = {
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+static struct omap_mcbsp_platform_data omap7xx_mcbsp_pdata[] = {
{
- .phys_base = OMAP730_MCBSP1_BASE,
+ .phys_base = OMAP7XX_MCBSP1_BASE,
.dma_rx_sync = OMAP_DMA_MCBSP1_RX,
.dma_tx_sync = OMAP_DMA_MCBSP1_TX,
- .rx_irq = INT_730_McBSP1RX,
- .tx_irq = INT_730_McBSP1TX,
+ .rx_irq = INT_7XX_McBSP1RX,
+ .tx_irq = INT_7XX_McBSP1TX,
.ops = &omap1_mcbsp_ops,
},
{
- .phys_base = OMAP730_MCBSP2_BASE,
+ .phys_base = OMAP7XX_MCBSP2_BASE,
.dma_rx_sync = OMAP_DMA_MCBSP3_RX,
.dma_tx_sync = OMAP_DMA_MCBSP3_TX,
- .rx_irq = INT_730_McBSP2RX,
- .tx_irq = INT_730_McBSP2TX,
+ .rx_irq = INT_7XX_McBSP2RX,
+ .tx_irq = INT_7XX_McBSP2TX,
.ops = &omap1_mcbsp_ops,
},
};
-#define OMAP730_MCBSP_PDATA_SZ ARRAY_SIZE(omap730_mcbsp_pdata)
+#define OMAP7XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap7xx_mcbsp_pdata)
#else
-#define omap730_mcbsp_pdata NULL
-#define OMAP730_MCBSP_PDATA_SZ 0
+#define omap7xx_mcbsp_pdata NULL
+#define OMAP7XX_MCBSP_PDATA_SZ 0
#endif
#ifdef CONFIG_ARCH_OMAP15XX
@@ -172,8 +172,8 @@ static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = {
int __init omap1_mcbsp_init(void)
{
- if (cpu_is_omap730())
- omap_mcbsp_count = OMAP730_MCBSP_PDATA_SZ;
+ if (cpu_is_omap7xx())
+ omap_mcbsp_count = OMAP7XX_MCBSP_PDATA_SZ;
if (cpu_is_omap15xx())
omap_mcbsp_count = OMAP15XX_MCBSP_PDATA_SZ;
if (cpu_is_omap16xx())
@@ -184,9 +184,9 @@ int __init omap1_mcbsp_init(void)
if (!mcbsp_ptr)
return -ENOMEM;
- if (cpu_is_omap730())
- omap_mcbsp_register_board_cfg(omap730_mcbsp_pdata,
- OMAP730_MCBSP_PDATA_SZ);
+ if (cpu_is_omap7xx())
+ omap_mcbsp_register_board_cfg(omap7xx_mcbsp_pdata,
+ OMAP7XX_MCBSP_PDATA_SZ);
if (cpu_is_omap15xx())
omap_mcbsp_register_board_cfg(omap15xx_mcbsp_pdata,
diff --git a/arch/arm/mach-omap1/mux.c b/arch/arm/mach-omap1/mux.c
index 721e0d9d8b1d..1e6145c9ee93 100644
--- a/arch/arm/mach-omap1/mux.c
+++ b/arch/arm/mach-omap1/mux.c
@@ -29,53 +29,34 @@
#include <asm/system.h>
-#include <mach/mux.h>
+#include <plat/mux.h>
#ifdef CONFIG_OMAP_MUX
static struct omap_mux_cfg arch_mux_cfg;
-#ifdef CONFIG_ARCH_OMAP730
-static struct pin_config __initdata_or_module omap730_pins[] = {
-MUX_CFG_730("E2_730_KBR0", 12, 21, 0, 20, 1, 0)
-MUX_CFG_730("J7_730_KBR1", 12, 25, 0, 24, 1, 0)
-MUX_CFG_730("E1_730_KBR2", 12, 29, 0, 28, 1, 0)
-MUX_CFG_730("F3_730_KBR3", 13, 1, 0, 0, 1, 0)
-MUX_CFG_730("D2_730_KBR4", 13, 5, 0, 4, 1, 0)
-MUX_CFG_730("C2_730_KBC0", 13, 9, 0, 8, 1, 0)
-MUX_CFG_730("D3_730_KBC1", 13, 13, 0, 12, 1, 0)
-MUX_CFG_730("E4_730_KBC2", 13, 17, 0, 16, 1, 0)
-MUX_CFG_730("F4_730_KBC3", 13, 21, 0, 20, 1, 0)
-MUX_CFG_730("E3_730_KBC4", 13, 25, 0, 24, 1, 0)
-
-MUX_CFG_730("AA17_730_USB_DM", 2, 21, 0, 20, 0, 0)
-MUX_CFG_730("W16_730_USB_PU_EN", 2, 25, 0, 24, 0, 0)
-MUX_CFG_730("W17_730_USB_VBUSI", 2, 29, 0, 28, 0, 0)
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+static struct pin_config __initdata_or_module omap7xx_pins[] = {
+MUX_CFG_7XX("E2_7XX_KBR0", 12, 21, 0, 20, 1, 0)
+MUX_CFG_7XX("J7_7XX_KBR1", 12, 25, 0, 24, 1, 0)
+MUX_CFG_7XX("E1_7XX_KBR2", 12, 29, 0, 28, 1, 0)
+MUX_CFG_7XX("F3_7XX_KBR3", 13, 1, 0, 0, 1, 0)
+MUX_CFG_7XX("D2_7XX_KBR4", 13, 5, 0, 4, 1, 0)
+MUX_CFG_7XX("C2_7XX_KBC0", 13, 9, 0, 8, 1, 0)
+MUX_CFG_7XX("D3_7XX_KBC1", 13, 13, 0, 12, 1, 0)
+MUX_CFG_7XX("E4_7XX_KBC2", 13, 17, 0, 16, 1, 0)
+MUX_CFG_7XX("F4_7XX_KBC3", 13, 21, 0, 20, 1, 0)
+MUX_CFG_7XX("E3_7XX_KBC4", 13, 25, 0, 24, 1, 0)
+
+MUX_CFG_7XX("AA17_7XX_USB_DM", 2, 21, 0, 20, 0, 0)
+MUX_CFG_7XX("W16_7XX_USB_PU_EN", 2, 25, 0, 24, 0, 0)
+MUX_CFG_7XX("W17_7XX_USB_VBUSI", 2, 29, 0, 28, 0, 0)
};
-#define OMAP730_PINS_SZ ARRAY_SIZE(omap730_pins)
+#define OMAP7XX_PINS_SZ ARRAY_SIZE(omap7xx_pins)
#else
-#define omap730_pins NULL
-#define OMAP730_PINS_SZ 0
-#endif /* CONFIG_ARCH_OMAP730 */
-
-#ifdef CONFIG_ARCH_OMAP850
-struct pin_config __initdata_or_module omap850_pins[] = {
-MUX_CFG_850("E2_850_KBR0", 12, 21, 0, 20, 1, 0)
-MUX_CFG_850("J7_850_KBR1", 12, 25, 0, 24, 1, 0)
-MUX_CFG_850("E1_850_KBR2", 12, 29, 0, 28, 1, 0)
-MUX_CFG_850("F3_850_KBR3", 13, 1, 0, 0, 1, 0)
-MUX_CFG_850("D2_850_KBR4", 13, 5, 0, 4, 1, 0)
-MUX_CFG_850("C2_850_KBC0", 13, 9, 0, 8, 1, 0)
-MUX_CFG_850("D3_850_KBC1", 13, 13, 0, 12, 1, 0)
-MUX_CFG_850("E4_850_KBC2", 13, 17, 0, 16, 1, 0)
-MUX_CFG_850("F4_850_KBC3", 13, 21, 0, 20, 1, 0)
-MUX_CFG_850("E3_850_KBC4", 13, 25, 0, 24, 1, 0)
-
-MUX_CFG_850("AA17_850_USB_DM", 2, 21, 0, 20, 0, 0)
-MUX_CFG_850("W16_850_USB_PU_EN", 2, 25, 0, 24, 0, 0)
-MUX_CFG_850("W17_850_USB_VBUSI", 2, 29, 0, 28, 0, 0)
-};
-#endif
+#define omap7xx_pins NULL
+#define OMAP7XX_PINS_SZ 0
+#endif /* CONFIG_ARCH_OMAP730 || CONFIG_ARCH_OMAP850 */
#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
static struct pin_config __initdata_or_module omap1xxx_pins[] = {
@@ -438,11 +419,6 @@ int __init_or_module omap1_cfg_reg(const struct pin_config *cfg)
printk(" %s (0x%08x) = 0x%08x -> 0x%08x\n",
cfg->pull_name, cfg->pull_reg, pull_orig, pull);
}
-
-#ifdef CONFIG_ARCH_OMAP850
- omap_mux_register(omap850_pins, ARRAY_SIZE(omap850_pins));
-#endif
-
#endif
#ifdef CONFIG_OMAP_MUX_ERRORS
@@ -454,9 +430,9 @@ int __init_or_module omap1_cfg_reg(const struct pin_config *cfg)
int __init omap1_mux_init(void)
{
- if (cpu_is_omap730()) {
- arch_mux_cfg.pins = omap730_pins;
- arch_mux_cfg.size = OMAP730_PINS_SZ;
+ if (cpu_is_omap7xx()) {
+ arch_mux_cfg.pins = omap7xx_pins;
+ arch_mux_cfg.size = OMAP7XX_PINS_SZ;
arch_mux_cfg.cfg_reg = omap1_cfg_reg;
}
diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c
index 5218943c91c0..b1d3f9fade23 100644
--- a/arch/arm/mach-omap1/pm.c
+++ b/arch/arm/mach-omap1/pm.c
@@ -48,21 +48,21 @@
#include <asm/mach/time.h>
#include <asm/mach/irq.h>
-#include <mach/cpu.h>
+#include <plat/cpu.h>
#include <mach/irqs.h>
-#include <mach/clock.h>
-#include <mach/sram.h>
-#include <mach/tc.h>
-#include <mach/mux.h>
-#include <mach/dma.h>
-#include <mach/dmtimer.h>
+#include <plat/clock.h>
+#include <plat/sram.h>
+#include <plat/tc.h>
+#include <plat/mux.h>
+#include <plat/dma.h>
+#include <plat/dmtimer.h>
#include "pm.h"
static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
static unsigned short dsp_sleep_save[DSP_SLEEP_SAVE_SIZE];
static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE];
-static unsigned int mpui730_sleep_save[MPUI730_SLEEP_SAVE_SIZE];
+static unsigned int mpui7xx_sleep_save[MPUI7XX_SLEEP_SAVE_SIZE];
static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE];
static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
@@ -183,9 +183,9 @@ static void omap_pm_wakeup_setup(void)
* drivers must still separately call omap_set_gpio_wakeup() to
* wake up to a GPIO interrupt.
*/
- if (cpu_is_omap730())
- level1_wake = OMAP_IRQ_BIT(INT_730_GPIO_BANK1) |
- OMAP_IRQ_BIT(INT_730_IH2_IRQ);
+ if (cpu_is_omap7xx())
+ level1_wake = OMAP_IRQ_BIT(INT_7XX_GPIO_BANK1) |
+ OMAP_IRQ_BIT(INT_7XX_IH2_IRQ);
else if (cpu_is_omap15xx())
level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
OMAP_IRQ_BIT(INT_1510_IH2_IRQ);
@@ -195,10 +195,10 @@ static void omap_pm_wakeup_setup(void)
omap_writel(~level1_wake, OMAP_IH1_MIR);
- if (cpu_is_omap730()) {
+ if (cpu_is_omap7xx()) {
omap_writel(~level2_wake, OMAP_IH2_0_MIR);
- omap_writel(~(OMAP_IRQ_BIT(INT_730_WAKE_UP_REQ) |
- OMAP_IRQ_BIT(INT_730_MPUIO_KEYPAD)),
+ omap_writel(~(OMAP_IRQ_BIT(INT_7XX_WAKE_UP_REQ) |
+ OMAP_IRQ_BIT(INT_7XX_MPUIO_KEYPAD)),
OMAP_IH2_1_MIR);
} else if (cpu_is_omap15xx()) {
level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
@@ -253,15 +253,15 @@ void omap1_pm_suspend(void)
* Save interrupt, MPUI, ARM and UPLD control registers.
*/
- if (cpu_is_omap730()) {
- MPUI730_SAVE(OMAP_IH1_MIR);
- MPUI730_SAVE(OMAP_IH2_0_MIR);
- MPUI730_SAVE(OMAP_IH2_1_MIR);
- MPUI730_SAVE(MPUI_CTRL);
- MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG);
- MPUI730_SAVE(MPUI_DSP_API_CONFIG);
- MPUI730_SAVE(EMIFS_CONFIG);
- MPUI730_SAVE(EMIFF_SDRAM_CONFIG);
+ if (cpu_is_omap7xx()) {
+ MPUI7XX_SAVE(OMAP_IH1_MIR);
+ MPUI7XX_SAVE(OMAP_IH2_0_MIR);
+ MPUI7XX_SAVE(OMAP_IH2_1_MIR);
+ MPUI7XX_SAVE(MPUI_CTRL);
+ MPUI7XX_SAVE(MPUI_DSP_BOOT_CONFIG);
+ MPUI7XX_SAVE(MPUI_DSP_API_CONFIG);
+ MPUI7XX_SAVE(EMIFS_CONFIG);
+ MPUI7XX_SAVE(EMIFF_SDRAM_CONFIG);
} else if (cpu_is_omap15xx()) {
MPUI1510_SAVE(OMAP_IH1_MIR);
@@ -306,7 +306,7 @@ void omap1_pm_suspend(void)
omap_writew(omap_readw(ARM_RSTCT1) & ~(1 << DSP_EN), ARM_RSTCT1);
/* shut down dsp_ck */
- if (!cpu_is_omap730())
+ if (!cpu_is_omap7xx())
omap_writew(omap_readw(ARM_CKCTL) & ~(1 << EN_DSPCK), ARM_CKCTL);
/* temporarily enabling api_ck to access DSP registers */
@@ -383,12 +383,12 @@ void omap1_pm_suspend(void)
ULPD_RESTORE(ULPD_CLOCK_CTRL);
ULPD_RESTORE(ULPD_STATUS_REQ);
- if (cpu_is_omap730()) {
- MPUI730_RESTORE(EMIFS_CONFIG);
- MPUI730_RESTORE(EMIFF_SDRAM_CONFIG);
- MPUI730_RESTORE(OMAP_IH1_MIR);
- MPUI730_RESTORE(OMAP_IH2_0_MIR);
- MPUI730_RESTORE(OMAP_IH2_1_MIR);
+ if (cpu_is_omap7xx()) {
+ MPUI7XX_RESTORE(EMIFS_CONFIG);
+ MPUI7XX_RESTORE(EMIFF_SDRAM_CONFIG);
+ MPUI7XX_RESTORE(OMAP_IH1_MIR);
+ MPUI7XX_RESTORE(OMAP_IH2_0_MIR);
+ MPUI7XX_RESTORE(OMAP_IH2_1_MIR);
} else if (cpu_is_omap15xx()) {
MPUI1510_RESTORE(MPUI_CTRL);
MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG);
@@ -461,13 +461,13 @@ static int omap_pm_read_proc(
ULPD_SAVE(ULPD_DPLL_CTRL);
ULPD_SAVE(ULPD_POWER_CTRL);
- if (cpu_is_omap730()) {
- MPUI730_SAVE(MPUI_CTRL);
- MPUI730_SAVE(MPUI_DSP_STATUS);
- MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG);
- MPUI730_SAVE(MPUI_DSP_API_CONFIG);
- MPUI730_SAVE(EMIFF_SDRAM_CONFIG);
- MPUI730_SAVE(EMIFS_CONFIG);
+ if (cpu_is_omap7xx()) {
+ MPUI7XX_SAVE(MPUI_CTRL);
+ MPUI7XX_SAVE(MPUI_DSP_STATUS);
+ MPUI7XX_SAVE(MPUI_DSP_BOOT_CONFIG);
+ MPUI7XX_SAVE(MPUI_DSP_API_CONFIG);
+ MPUI7XX_SAVE(EMIFF_SDRAM_CONFIG);
+ MPUI7XX_SAVE(EMIFS_CONFIG);
} else if (cpu_is_omap15xx()) {
MPUI1510_SAVE(MPUI_CTRL);
MPUI1510_SAVE(MPUI_DSP_STATUS);
@@ -517,20 +517,20 @@ static int omap_pm_read_proc(
ULPD_SHOW(ULPD_STATUS_REQ),
ULPD_SHOW(ULPD_POWER_CTRL));
- if (cpu_is_omap730()) {
+ if (cpu_is_omap7xx()) {
my_buffer_offset += sprintf(my_base + my_buffer_offset,
- "MPUI730_CTRL_REG 0x%-8x \n"
- "MPUI730_DSP_STATUS_REG: 0x%-8x \n"
- "MPUI730_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
- "MPUI730_DSP_API_CONFIG_REG: 0x%-8x \n"
- "MPUI730_SDRAM_CONFIG_REG: 0x%-8x \n"
- "MPUI730_EMIFS_CONFIG_REG: 0x%-8x \n",
- MPUI730_SHOW(MPUI_CTRL),
- MPUI730_SHOW(MPUI_DSP_STATUS),
- MPUI730_SHOW(MPUI_DSP_BOOT_CONFIG),
- MPUI730_SHOW(MPUI_DSP_API_CONFIG),
- MPUI730_SHOW(EMIFF_SDRAM_CONFIG),
- MPUI730_SHOW(EMIFS_CONFIG));
+ "MPUI7XX_CTRL_REG 0x%-8x \n"
+ "MPUI7XX_DSP_STATUS_REG: 0x%-8x \n"
+ "MPUI7XX_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
+ "MPUI7XX_DSP_API_CONFIG_REG: 0x%-8x \n"
+ "MPUI7XX_SDRAM_CONFIG_REG: 0x%-8x \n"
+ "MPUI7XX_EMIFS_CONFIG_REG: 0x%-8x \n",
+ MPUI7XX_SHOW(MPUI_CTRL),
+ MPUI7XX_SHOW(MPUI_DSP_STATUS),
+ MPUI7XX_SHOW(MPUI_DSP_BOOT_CONFIG),
+ MPUI7XX_SHOW(MPUI_DSP_API_CONFIG),
+ MPUI7XX_SHOW(EMIFF_SDRAM_CONFIG),
+ MPUI7XX_SHOW(EMIFS_CONFIG));
} else if (cpu_is_omap15xx()) {
my_buffer_offset += sprintf(my_base + my_buffer_offset,
"MPUI1510_CTRL_REG 0x%-8x \n"
@@ -668,9 +668,9 @@ static int __init omap_pm_init(void)
* These routines need to be in SRAM as that's the only
* memory the MPU can see when it wakes up.
*/
- if (cpu_is_omap730()) {
- omap_sram_suspend = omap_sram_push(omap730_cpu_suspend,
- omap730_cpu_suspend_sz);
+ if (cpu_is_omap7xx()) {
+ omap_sram_suspend = omap_sram_push(omap7xx_cpu_suspend,
+ omap7xx_cpu_suspend_sz);
} else if (cpu_is_omap15xx()) {
omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend,
omap1510_cpu_suspend_sz);
@@ -686,8 +686,8 @@ static int __init omap_pm_init(void)
pm_idle = omap1_pm_idle;
- if (cpu_is_omap730())
- setup_irq(INT_730_WAKE_UP_REQ, &omap_wakeup_irq);
+ if (cpu_is_omap7xx())
+ setup_irq(INT_7XX_WAKE_UP_REQ, &omap_wakeup_irq);
else if (cpu_is_omap16xx())
setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq);
@@ -700,8 +700,8 @@ static int __init omap_pm_init(void)
omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL);
/* Configure IDLECT3 */
- if (cpu_is_omap730())
- omap_writel(OMAP730_IDLECT3_VAL, OMAP730_IDLECT3);
+ if (cpu_is_omap7xx())
+ omap_writel(OMAP7XX_IDLECT3_VAL, OMAP7XX_IDLECT3);
else if (cpu_is_omap16xx())
omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3);
diff --git a/arch/arm/mach-omap1/pm.h b/arch/arm/mach-omap1/pm.h
index c4f05bdcf8a6..56a647986ae9 100644
--- a/arch/arm/mach-omap1/pm.h
+++ b/arch/arm/mach-omap1/pm.h
@@ -98,13 +98,14 @@
#define OMAP1610_IDLECT3 0xfffece24
#define OMAP1610_IDLE_LOOP_REQUEST 0x0400
-#define OMAP730_IDLECT1_SLEEP_VAL 0x16c7
-#define OMAP730_IDLECT2_SLEEP_VAL 0x09c7
-#define OMAP730_IDLECT3_VAL 0x3f
-#define OMAP730_IDLECT3 0xfffece24
-#define OMAP730_IDLE_LOOP_REQUEST 0x0C00
+#define OMAP7XX_IDLECT1_SLEEP_VAL 0x16c7
+#define OMAP7XX_IDLECT2_SLEEP_VAL 0x09c7
+#define OMAP7XX_IDLECT3_VAL 0x3f
+#define OMAP7XX_IDLECT3 0xfffece24
+#define OMAP7XX_IDLE_LOOP_REQUEST 0x0C00
#if !defined(CONFIG_ARCH_OMAP730) && \
+ !defined(CONFIG_ARCH_OMAP850) && \
!defined(CONFIG_ARCH_OMAP15XX) && \
!defined(CONFIG_ARCH_OMAP16XX)
#warning "Power management for this processor not implemented yet"
@@ -122,17 +123,17 @@ extern void allow_idle_sleep(void);
extern void omap1_pm_idle(void);
extern void omap1_pm_suspend(void);
-extern void omap730_cpu_suspend(unsigned short, unsigned short);
+extern void omap7xx_cpu_suspend(unsigned short, unsigned short);
extern void omap1510_cpu_suspend(unsigned short, unsigned short);
extern void omap1610_cpu_suspend(unsigned short, unsigned short);
-extern void omap730_idle_loop_suspend(void);
+extern void omap7xx_idle_loop_suspend(void);
extern void omap1510_idle_loop_suspend(void);
extern void omap1610_idle_loop_suspend(void);
-extern unsigned int omap730_cpu_suspend_sz;
+extern unsigned int omap7xx_cpu_suspend_sz;
extern unsigned int omap1510_cpu_suspend_sz;
extern unsigned int omap1610_cpu_suspend_sz;
-extern unsigned int omap730_idle_loop_suspend_sz;
+extern unsigned int omap7xx_idle_loop_suspend_sz;
extern unsigned int omap1510_idle_loop_suspend_sz;
extern unsigned int omap1610_idle_loop_suspend_sz;
@@ -155,9 +156,9 @@ extern void omap_serial_wake_trigger(int enable);
#define ULPD_RESTORE(x) omap_writew((ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]), (x))
#define ULPD_SHOW(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]
-#define MPUI730_SAVE(x) mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x] = omap_readl(x)
-#define MPUI730_RESTORE(x) omap_writel((mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x]), (x))
-#define MPUI730_SHOW(x) mpui730_sleep_save[MPUI730_SLEEP_SAVE_##x]
+#define MPUI7XX_SAVE(x) mpui7xx_sleep_save[MPUI7XX_SLEEP_SAVE_##x] = omap_readl(x)
+#define MPUI7XX_RESTORE(x) omap_writel((mpui7xx_sleep_save[MPUI7XX_SLEEP_SAVE_##x]), (x))
+#define MPUI7XX_SHOW(x) mpui7xx_sleep_save[MPUI7XX_SLEEP_SAVE_##x]
#define MPUI1510_SAVE(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x] = omap_readl(x)
#define MPUI1510_RESTORE(x) omap_writel((mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x]), (x))
@@ -232,24 +233,24 @@ enum mpui1510_save_state {
#endif
};
-enum mpui730_save_state {
- MPUI730_SLEEP_SAVE_START = 0,
+enum mpui7xx_save_state {
+ MPUI7XX_SLEEP_SAVE_START = 0,
/*
* MPUI registers 32 bits
*/
- MPUI730_SLEEP_SAVE_MPUI_CTRL,
- MPUI730_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
- MPUI730_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
- MPUI730_SLEEP_SAVE_MPUI_DSP_STATUS,
- MPUI730_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
- MPUI730_SLEEP_SAVE_EMIFS_CONFIG,
- MPUI730_SLEEP_SAVE_OMAP_IH1_MIR,
- MPUI730_SLEEP_SAVE_OMAP_IH2_0_MIR,
- MPUI730_SLEEP_SAVE_OMAP_IH2_1_MIR,
-#if defined(CONFIG_ARCH_OMAP730)
- MPUI730_SLEEP_SAVE_SIZE
+ MPUI7XX_SLEEP_SAVE_MPUI_CTRL,
+ MPUI7XX_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
+ MPUI7XX_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
+ MPUI7XX_SLEEP_SAVE_MPUI_DSP_STATUS,
+ MPUI7XX_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
+ MPUI7XX_SLEEP_SAVE_EMIFS_CONFIG,
+ MPUI7XX_SLEEP_SAVE_OMAP_IH1_MIR,
+ MPUI7XX_SLEEP_SAVE_OMAP_IH2_0_MIR,
+ MPUI7XX_SLEEP_SAVE_OMAP_IH2_1_MIR,
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+ MPUI7XX_SLEEP_SAVE_SIZE
#else
- MPUI730_SLEEP_SAVE_SIZE = 0
+ MPUI7XX_SLEEP_SAVE_SIZE = 0
#endif
};
diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c
index d496e50fec40..f82f66e5a36f 100644
--- a/arch/arm/mach-omap1/serial.c
+++ b/arch/arm/mach-omap1/serial.c
@@ -22,10 +22,10 @@
#include <asm/mach-types.h>
-#include <mach/board.h>
-#include <mach/mux.h>
+#include <plat/board.h>
+#include <plat/mux.h>
#include <mach/gpio.h>
-#include <mach/fpga.h>
+#include <plat/fpga.h>
static struct clk * uart1_ck;
static struct clk * uart2_ck;
@@ -64,7 +64,6 @@ static void __init omap_serial_reset(struct plat_serial8250_port *p)
static struct plat_serial8250_port serial_platform_data[] = {
{
- .membase = OMAP1_IO_ADDRESS(OMAP_UART1_BASE),
.mapbase = OMAP_UART1_BASE,
.irq = INT_UART1,
.flags = UPF_BOOT_AUTOCONF,
@@ -73,7 +72,6 @@ static struct plat_serial8250_port serial_platform_data[] = {
.uartclk = OMAP16XX_BASE_BAUD * 16,
},
{
- .membase = OMAP1_IO_ADDRESS(OMAP_UART2_BASE),
.mapbase = OMAP_UART2_BASE,
.irq = INT_UART2,
.flags = UPF_BOOT_AUTOCONF,
@@ -82,7 +80,6 @@ static struct plat_serial8250_port serial_platform_data[] = {
.uartclk = OMAP16XX_BASE_BAUD * 16,
},
{
- .membase = OMAP1_IO_ADDRESS(OMAP_UART3_BASE),
.mapbase = OMAP_UART3_BASE,
.irq = INT_UART3,
.flags = UPF_BOOT_AUTOCONF,
@@ -110,18 +107,11 @@ void __init omap_serial_init(void)
{
int i;
- if (cpu_is_omap730()) {
+ if (cpu_is_omap7xx()) {
serial_platform_data[0].regshift = 0;
serial_platform_data[1].regshift = 0;
- serial_platform_data[0].irq = INT_730_UART_MODEM_1;
- serial_platform_data[1].irq = INT_730_UART_MODEM_IRDA_2;
- }
-
- if (cpu_is_omap850()) {
- serial_platform_data[0].regshift = 0;
- serial_platform_data[1].regshift = 0;
- serial_platform_data[0].irq = INT_850_UART_MODEM_1;
- serial_platform_data[1].irq = INT_850_UART_MODEM_IRDA_2;
+ serial_platform_data[0].irq = INT_7XX_UART_MODEM_1;
+ serial_platform_data[1].irq = INT_7XX_UART_MODEM_IRDA_2;
}
if (cpu_is_omap15xx()) {
@@ -130,9 +120,17 @@ void __init omap_serial_init(void)
serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16;
}
- for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
+ for (i = 0; i < ARRAY_SIZE(serial_platform_data) - 1; i++) {
unsigned char reg;
+ /* Static mapping, never released */
+ serial_platform_data[i].membase =
+ ioremap(serial_platform_data[i].mapbase, SZ_2K);
+ if (!serial_platform_data[i].membase) {
+ printk(KERN_ERR "Could not ioremap uart%i\n", i);
+ continue;
+ }
+
switch (i) {
case 0:
uart1_ck = clk_get(NULL, "uart1_ck");
diff --git a/arch/arm/mach-omap1/sleep.S b/arch/arm/mach-omap1/sleep.S
index 22e8568339b0..ef771ce8b030 100644
--- a/arch/arm/mach-omap1/sleep.S
+++ b/arch/arm/mach-omap1/sleep.S
@@ -1,7 +1,7 @@
/*
* linux/arch/arm/mach-omap1/sleep.S
*
- * Low-level OMAP730/1510/1610 sleep/wakeUp support
+ * Low-level OMAP7XX/1510/1610 sleep/wakeUp support
*
* Initial SA1110 code:
* Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
@@ -57,8 +57,8 @@
*
*/
-#if defined(CONFIG_ARCH_OMAP730)
-ENTRY(omap730_cpu_suspend)
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+ENTRY(omap7xx_cpu_suspend)
@ save registers on stack
stmfd sp!, {r0 - r12, lr}
@@ -91,13 +91,13 @@ ENTRY(omap730_cpu_suspend)
@ turn off clock domains
@ do not disable PERCK (0x04)
- mov r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff
- orr r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00
+ mov r5, #OMAP7XX_IDLECT2_SLEEP_VAL & 0xff
+ orr r5, r5, #OMAP7XX_IDLECT2_SLEEP_VAL & 0xff00
strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
@ request ARM idle
- mov r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff
- orr r3, r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff00
+ mov r3, #OMAP7XX_IDLECT1_SLEEP_VAL & 0xff
+ orr r3, r3, #OMAP7XX_IDLECT1_SLEEP_VAL & 0xff00
strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
@ disable instruction cache
@@ -113,7 +113,7 @@ ENTRY(omap730_cpu_suspend)
mov r2, #0
mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt
/*
- * omap730_cpu_suspend()'s resume point.
+ * omap7xx_cpu_suspend()'s resume point.
*
* It will just start executing here, so we'll restore stuff from the
* stack.
@@ -132,9 +132,9 @@ ENTRY(omap730_cpu_suspend)
@ restore regs and return
ldmfd sp!, {r0 - r12, pc}
-ENTRY(omap730_cpu_suspend_sz)
- .word . - omap730_cpu_suspend
-#endif /* CONFIG_ARCH_OMAP730 */
+ENTRY(omap7xx_cpu_suspend_sz)
+ .word . - omap7xx_cpu_suspend
+#endif /* CONFIG_ARCH_OMAP730 || CONFIG_ARCH_OMAP850 */
#ifdef CONFIG_ARCH_OMAP15XX
ENTRY(omap1510_cpu_suspend)
diff --git a/arch/arm/mach-omap1/timer32k.c b/arch/arm/mach-omap1/timer32k.c
index fd3f7396e162..9ad118563f7d 100644
--- a/arch/arm/mach-omap1/timer32k.c
+++ b/arch/arm/mach-omap1/timer32k.c
@@ -52,7 +52,7 @@
#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
-#include <mach/dmtimer.h>
+#include <plat/dmtimer.h>
struct sys_timer omap_timer;
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 75b1c7efae7e..f80439eff6d7 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -85,6 +85,10 @@ config MACH_OMAP_ZOOM2
bool "OMAP3 Zoom2 board"
depends on ARCH_OMAP3 && ARCH_OMAP34XX
+config MACH_CM_T35
+ bool "CompuLab CM-T35 module"
+ depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
config MACH_OMAP_4430SDP
bool "OMAP 4430 SDP board"
depends on ARCH_OMAP4
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 8cb16777661a..7468505c4d23 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -74,6 +74,8 @@ obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51.o \
obj-$(CONFIG_MACH_OMAP_ZOOM2) += board-zoom2.o \
mmc-twl4030.o \
board-zoom-debugboard.o
+obj-$(CONFIG_MACH_CM_T35) += board-cm-t35.o \
+ mmc-twl4030.o
obj-$(CONFIG_MACH_OMAP_4430SDP) += board-4430sdp.o
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index 42217b32f835..db9374bc528b 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -31,12 +31,12 @@
#include <asm/mach/flash.h>
#include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/board.h>
-#include <mach/common.h>
-#include <mach/gpmc.h>
-#include <mach/usb.h>
-#include <mach/gpmc-smc91x.h>
+#include <plat/mux.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/gpmc.h>
+#include <plat/usb.h>
+#include <plat/gpmc-smc91x.h>
#include "mmc-twl4030.h"
@@ -221,7 +221,7 @@ static void __init omap_2430sdp_map_io(void)
MACHINE_START(OMAP_2430SDP, "OMAP2430 sdp2430 board")
/* Maintainer: Syed Khasim - Texas Instruments Inc */
.phys_io = 0x48000000,
- .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .io_pg_offst = ((0xfa000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = omap_2430sdp_map_io,
.init_irq = omap_2430sdp_init_irq,
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index efaf053eba85..607845b7207f 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -29,17 +29,17 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/mcspi.h>
-#include <mach/mux.h>
-#include <mach/board.h>
-#include <mach/usb.h>
-#include <mach/common.h>
-#include <mach/dma.h>
-#include <mach/gpmc.h>
-
-#include <mach/control.h>
-#include <mach/keypad.h>
-#include <mach/gpmc-smc91x.h>
+#include <plat/mcspi.h>
+#include <plat/mux.h>
+#include <plat/board.h>
+#include <plat/usb.h>
+#include <plat/common.h>
+#include <plat/dma.h>
+#include <plat/gpmc.h>
+
+#include <plat/control.h>
+#include <plat/keypad.h>
+#include <plat/gpmc-smc91x.h>
#include "sdram-qimonda-hyb18m512160af-6.h"
#include "mmc-twl4030.h"
@@ -511,7 +511,7 @@ static void __init omap_3430sdp_map_io(void)
MACHINE_START(OMAP_3430SDP, "OMAP3430 3430SDP board")
/* Maintainer: Syed Khasim - Texas Instruments Inc */
.phys_io = 0x48000000,
- .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .io_pg_offst = ((0xfa000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = omap_3430sdp_map_io,
.init_irq = omap_3430sdp_init_irq,
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index eb37c40ea83a..242bba30b5be 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -23,10 +23,10 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/board.h>
-#include <mach/common.h>
-#include <mach/control.h>
-#include <mach/timer-gp.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/control.h>
+#include <plat/timer-gp.h>
#include <asm/hardware/gic.h>
static struct platform_device sdp4430_lcd_device = {
@@ -52,8 +52,17 @@ static struct omap_board_config_kernel sdp4430_config[] __initdata = {
static void __init gic_init_irq(void)
{
- gic_dist_init(0, OMAP2_IO_ADDRESS(OMAP44XX_GIC_DIST_BASE), 29);
- gic_cpu_init(0, OMAP2_IO_ADDRESS(OMAP44XX_GIC_CPU_BASE));
+ void __iomem *base;
+
+ /* Static mapping, never released */
+ base = ioremap(OMAP44XX_GIC_DIST_BASE, SZ_4K);
+ BUG_ON(!base);
+ gic_dist_init(0, base, 29);
+
+ /* Static mapping, never released */
+ gic_cpu_base_addr = ioremap(OMAP44XX_GIC_CPU_BASE, SZ_512);
+ BUG_ON(!gic_cpu_base_addr);
+ gic_cpu_init(0, gic_cpu_base_addr);
}
static void __init omap_4430sdp_init_irq(void)
@@ -84,7 +93,7 @@ static void __init omap_4430sdp_map_io(void)
MACHINE_START(OMAP_4430SDP, "OMAP4430 4430SDP board")
/* Maintainer: Santosh Shilimkar - Texas Instruments Inc */
.phys_io = 0x48000000,
- .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .io_pg_offst = ((0xfa000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = omap_4430sdp_map_io,
.init_irq = omap_4430sdp_init_irq,
diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c
index a1132288c701..8a2ce77a02ec 100644
--- a/arch/arm/mach-omap2/board-apollon.c
+++ b/arch/arm/mach-omap2/board-apollon.c
@@ -33,13 +33,13 @@
#include <asm/mach/flash.h>
#include <mach/gpio.h>
-#include <mach/led.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/board.h>
-#include <mach/common.h>
-#include <mach/gpmc.h>
-#include <mach/control.h>
+#include <plat/led.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/gpmc.h>
+#include <plat/control.h>
/* LED & Switch macros */
#define LED0_GPIO13 13
@@ -333,7 +333,7 @@ static void __init omap_apollon_map_io(void)
MACHINE_START(OMAP_APOLLON, "OMAP24xx Apollon")
/* Maintainer: Kyungmin Park <kyungmin.park@samsung.com> */
.phys_io = 0x48000000,
- .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .io_pg_offst = ((0xfa000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = omap_apollon_map_io,
.init_irq = omap_apollon_init_irq,
diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
new file mode 100644
index 000000000000..e7a29e4772d1
--- /dev/null
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -0,0 +1,459 @@
+/*
+ * board-cm-t35.c (CompuLab CM-T35 module)
+ *
+ * Copyright (C) 2009 CompuLab, Ltd.
+ * Author: Mike Rapoport <mike@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/input.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <linux/i2c/at24.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/regulator/machine.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/mux.h>
+#include <plat/nand.h>
+#include <plat/keypad.h>
+#include <plat/gpmc.h>
+#include <plat/usb.h>
+
+#include <mach/hardware.h>
+
+#include "sdram-micron-mt46h32m32lf-6.h"
+#include "mmc-twl4030.h"
+
+#define CM_T35_GPIO_PENDOWN 57
+
+#define CM_T35_SMSC911X_CS 5
+#define CM_T35_SMSC911X_GPIO 163
+
+#define NAND_BLOCK_SIZE SZ_128K
+#define GPMC_CS0_BASE 0x60
+#define GPMC_CS0_BASE_ADDR (OMAP34XX_GPMC_VIRT + GPMC_CS0_BASE)
+
+#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
+#include <linux/smsc911x.h>
+
+static struct resource cm_t35_smsc911x_resources[] = {
+ {
+ .name = "smsc911x-memory",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = OMAP_GPIO_IRQ(CM_T35_SMSC911X_GPIO),
+ .end = OMAP_GPIO_IRQ(CM_T35_SMSC911X_GPIO),
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+ },
+};
+
+static struct smsc911x_platform_config cm_t35_smsc911x_config = {
+ .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+ .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+ .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
+ .phy_interface = PHY_INTERFACE_MODE_MII,
+};
+
+static struct platform_device cm_t35_smsc911x_device = {
+ .name = "smsc911x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(cm_t35_smsc911x_resources),
+ .resource = cm_t35_smsc911x_resources,
+ .dev = {
+ .platform_data = &cm_t35_smsc911x_config,
+ },
+};
+
+static void __init cm_t35_init_smsc911x(void)
+{
+ unsigned long cs_mem_base;
+
+ if (gpmc_cs_request(CM_T35_SMSC911X_CS, SZ_16M, &cs_mem_base) < 0) {
+ pr_err("CM-T35: Failed request for GPMC mem for smsc911x\n");
+ return;
+ }
+
+ cm_t35_smsc911x_resources[0].start = cs_mem_base + 0x0;
+ cm_t35_smsc911x_resources[0].end = cs_mem_base + 0xff;
+
+ if ((gpio_request(CM_T35_SMSC911X_GPIO, "CM ETH IRQ") == 0) &&
+ (gpio_direction_input(CM_T35_SMSC911X_GPIO) == 0)) {
+ gpio_export(CM_T35_SMSC911X_GPIO, 0);
+ } else {
+ pr_err("CM-T35: could not obtain gpio for SMSC911X IRQ\n");
+ return;
+ }
+
+ platform_device_register(&cm_t35_smsc911x_device);
+}
+#else
+static inline void __init cm_t35_init_smsc911x(void) { return; }
+#endif
+
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+#include <linux/leds.h>
+
+static struct gpio_led cm_t35_leds[] = {
+ [0] = {
+ .gpio = 186,
+ .name = "cm-t35:green",
+ .default_trigger = "heartbeat",
+ .active_low = 1,
+ },
+};
+
+static struct gpio_led_platform_data cm_t35_led_pdata = {
+ .num_leds = ARRAY_SIZE(cm_t35_leds),
+ .leds = cm_t35_leds,
+};
+
+static struct platform_device cm_t35_led_device = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &cm_t35_led_pdata,
+ },
+};
+
+static void __init cm_t35_init_led(void)
+{
+ platform_device_register(&cm_t35_led_device);
+}
+#else
+static inline void cm_t35_init_led(void) {}
+#endif
+
+#if defined(CONFIG_MTD_NAND_OMAP2) || defined(CONFIG_MTD_NAND_OMAP2_MODULE)
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+static struct mtd_partition cm_t35_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_t35_nand_data = {
+ .parts = cm_t35_nand_partitions,
+ .nr_parts = ARRAY_SIZE(cm_t35_nand_partitions),
+ .dma_channel = -1, /* disable DMA in OMAP NAND driver */
+ .cs = 0,
+ .gpmc_cs_baseaddr = (void __iomem *)GPMC_CS0_BASE_ADDR,
+ .gpmc_baseaddr = (void __iomem *)OMAP34XX_GPMC_VIRT,
+
+};
+
+static struct resource cm_t35_nand_resource = {
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device cm_t35_nand_device = {
+ .name = "omap2-nand",
+ .id = -1,
+ .num_resources = 1,
+ .resource = &cm_t35_nand_resource,
+ .dev = {
+ .platform_data = &cm_t35_nand_data,
+ },
+};
+
+static void __init cm_t35_init_nand(void)
+{
+ if (platform_device_register(&cm_t35_nand_device) < 0)
+ pr_err("CM-T35: Unable to register NAND device\n");
+}
+#else
+static inline void cm_t35_init_nand(void) {}
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
+ defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+#include <linux/spi/spi.h>
+#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 */
+};
+
+static int ads7846_get_pendown_state(void)
+{
+ return !gpio_get_value(CM_T35_GPIO_PENDOWN);
+}
+
+static struct ads7846_platform_data ads7846_config = {
+ .x_max = 0x0fff,
+ .y_max = 0x0fff,
+ .x_plate_ohms = 180,
+ .pressure_max = 255,
+ .debounce_max = 10,
+ .debounce_tol = 3,
+ .debounce_rep = 1,
+ .get_pendown_state = ads7846_get_pendown_state,
+ .keep_vref_on = 1,
+};
+
+static struct spi_board_info cm_t35_spi_board_info[] __initdata = {
+ {
+ .modalias = "ads7846",
+ .bus_num = 1,
+ .chip_select = 0,
+ .max_speed_hz = 1500000,
+ .controller_data = &ads7846_mcspi_config,
+ .irq = OMAP_GPIO_IRQ(CM_T35_GPIO_PENDOWN),
+ .platform_data = &ads7846_config,
+ },
+};
+
+static void __init cm_t35_init_ads7846(void)
+{
+ if ((gpio_request(CM_T35_GPIO_PENDOWN, "ADS7846_PENDOWN") == 0) &&
+ (gpio_direction_input(CM_T35_GPIO_PENDOWN) == 0)) {
+ gpio_export(CM_T35_GPIO_PENDOWN, 0);
+ } else {
+ pr_err("CM-T35: could not obtain gpio for ADS7846_PENDOWN\n");
+ return;
+ }
+
+ spi_register_board_info(cm_t35_spi_board_info,
+ ARRAY_SIZE(cm_t35_spi_board_info));
+}
+#else
+static inline void cm_t35_init_ads7846(void) {}
+#endif
+
+static struct regulator_consumer_supply cm_t35_vmmc1_supply = {
+ .supply = "vmmc",
+};
+
+static struct regulator_consumer_supply cm_t35_vsim_supply = {
+ .supply = "vmmc_aux",
+};
+
+/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
+static struct regulator_init_data cm_t35_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 = &cm_t35_vmmc1_supply,
+};
+
+/* VSIM for MMC1 pins DAT4..DAT7 (2 mA, plus card == max 50 mA) */
+static struct regulator_init_data cm_t35_vsim = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 3000000,
+ .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 = &cm_t35_vsim_supply,
+};
+
+static struct twl4030_usb_data cm_t35_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
+static int 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),
+};
+
+static struct matrix_keymap_data cm_t35_keymap_data = {
+ .keymap = cm_t35_keymap,
+ .keymap_size = ARRAY_SIZE(cm_t35_keymap),
+};
+
+static struct twl4030_keypad_data cm_t35_kp_data = {
+ .keymap_data = &cm_t35_keymap_data,
+ .rows = 3,
+ .cols = 3,
+ .rep = 1,
+};
+
+static struct twl4030_hsmmc_info mmc[] = {
+ {
+ .mmc = 1,
+ .wires = 4,
+ .gpio_cd = -EINVAL,
+ .gpio_wp = -EINVAL,
+
+ },
+ {
+ .mmc = 2,
+ .wires = 4,
+ .transceiver = 1,
+ .gpio_cd = -EINVAL,
+ .gpio_wp = -EINVAL,
+ .ocr_mask = 0x00100000, /* 3.3V */
+ },
+ {} /* Terminator */
+};
+
+static int cm_t35_twl_gpio_setup(struct device *dev, unsigned gpio,
+ unsigned ngpio)
+{
+ int wlan_rst = gpio + 2;
+
+ if ((gpio_request(wlan_rst, "WLAN RST") == 0) &&
+ (gpio_direction_output(wlan_rst, 1) == 0)) {
+ gpio_export(wlan_rst, 0);
+
+ udelay(10);
+ gpio_set_value(wlan_rst, 0);
+ udelay(10);
+ gpio_set_value(wlan_rst, 1);
+ } else {
+ pr_err("CM-T35: could not obtain gpio for WiFi reset\n");
+ }
+
+ /* gpio + 0 is "mmc0_cd" (input/IRQ) */
+ mmc[0].gpio_cd = gpio + 0;
+ twl4030_mmc_init(mmc);
+
+ /* link regulators to MMC adapters */
+ cm_t35_vmmc1_supply.dev = mmc[0].dev;
+ cm_t35_vsim_supply.dev = mmc[0].dev;
+
+ return 0;
+}
+
+static struct twl4030_gpio_platform_data cm_t35_gpio_data = {
+ .gpio_base = OMAP_MAX_GPIO_LINES,
+ .irq_base = TWL4030_GPIO_IRQ_BASE,
+ .irq_end = TWL4030_GPIO_IRQ_END,
+ .setup = cm_t35_twl_gpio_setup,
+};
+
+static struct twl4030_platform_data cm_t35_twldata = {
+ .irq_base = TWL4030_IRQ_BASE,
+ .irq_end = TWL4030_IRQ_END,
+
+ /* platform_data for children goes here */
+ .keypad = &cm_t35_kp_data,
+ .usb = &cm_t35_usb_data,
+ .gpio = &cm_t35_gpio_data,
+ .vmmc1 = &cm_t35_vmmc1,
+ .vsim = &cm_t35_vsim,
+};
+
+static struct i2c_board_info __initdata cm_t35_i2c_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("tps65930", 0x48),
+ .flags = I2C_CLIENT_WAKE,
+ .irq = INT_34XX_SYS_NIRQ,
+ .platform_data = &cm_t35_twldata,
+ },
+};
+
+static void __init cm_t35_init_i2c(void)
+{
+ omap_register_i2c_bus(1, 2600, cm_t35_i2c_boardinfo,
+ ARRAY_SIZE(cm_t35_i2c_boardinfo));
+}
+
+static struct omap_board_config_kernel cm_t35_config[] __initdata = {
+};
+
+static void __init cm_t35_init_irq(void)
+{
+ omap_board_config = cm_t35_config;
+ omap_board_config_size = ARRAY_SIZE(cm_t35_config);
+
+ omap2_init_common_hw(mt46h32m32lf6_sdrc_params,
+ mt46h32m32lf6_sdrc_params);
+ omap_init_irq();
+ omap_gpio_init();
+}
+
+static void __init cm_t35_map_io(void)
+{
+ omap2_set_globals_343x();
+ omap2_map_common_io();
+}
+
+static void __init cm_t35_init(void)
+{
+ omap_serial_init();
+ cm_t35_init_i2c();
+ cm_t35_init_nand();
+ cm_t35_init_ads7846();
+ cm_t35_init_smsc911x();
+ cm_t35_init_led();
+
+ usb_musb_init();
+
+ omap_cfg_reg(AF26_34XX_SYS_NIRQ);
+}
+
+MACHINE_START(CM_T35, "Compulab CM-T35")
+ .phys_io = 0x48000000,
+ .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .boot_params = 0x80000100,
+ .map_io = cm_t35_map_io,
+ .init_irq = cm_t35_init_irq,
+ .init_machine = cm_t35_init,
+ .timer = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c
index 2e09a1c444cb..7e6e6ca88be5 100644
--- a/arch/arm/mach-omap2/board-generic.c
+++ b/arch/arm/mach-omap2/board-generic.c
@@ -26,10 +26,10 @@
#include <asm/mach/map.h>
#include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/board.h>
-#include <mach/common.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/board.h>
+#include <plat/common.h>
static struct omap_board_config_kernel generic_config[] = {
};
@@ -56,7 +56,7 @@ static void __init omap_generic_map_io(void)
MACHINE_START(OMAP_GENERIC, "Generic OMAP24xx")
/* Maintainer: Paul Mundt <paul.mundt@nokia.com> */
.phys_io = 0x48000000,
- .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .io_pg_offst = ((0xfa000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = omap_generic_map_io,
.init_irq = omap_generic_init_irq,
diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c
index eaa02d012c5c..cfb7f1257d20 100644
--- a/arch/arm/mach-omap2/board-h4.c
+++ b/arch/arm/mach-omap2/board-h4.c
@@ -31,16 +31,16 @@
#include <asm/mach/map.h>
#include <asm/mach/flash.h>
-#include <mach/control.h>
+#include <plat/control.h>
#include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/board.h>
-#include <mach/common.h>
-#include <mach/keypad.h>
-#include <mach/menelaus.h>
-#include <mach/dma.h>
-#include <mach/gpmc.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/keypad.h>
+#include <plat/menelaus.h>
+#include <plat/dma.h>
+#include <plat/gpmc.h>
#define H4_FLASH_CS 0
#define H4_SMC91X_CS 1
@@ -376,7 +376,7 @@ static void __init omap_h4_map_io(void)
MACHINE_START(OMAP_H4, "OMAP2420 H4 board")
/* Maintainer: Paul Mundt <paul.mundt@nokia.com> */
.phys_io = 0x48000000,
- .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .io_pg_offst = ((0xfa000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = omap_h4_map_io,
.init_irq = omap_h4_init_irq,
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
index d110a7fdfbd8..5c825607543e 100644
--- a/arch/arm/mach-omap2/board-ldp.c
+++ b/arch/arm/mach-omap2/board-ldp.c
@@ -32,16 +32,16 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/mcspi.h>
+#include <plat/mcspi.h>
#include <mach/gpio.h>
-#include <mach/board.h>
-#include <mach/common.h>
-#include <mach/gpmc.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/gpmc.h>
#include <asm/delay.h>
-#include <mach/control.h>
-#include <mach/usb.h>
-#include <mach/keypad.h>
+#include <plat/control.h>
+#include <plat/usb.h>
+#include <plat/keypad.h>
#include "mmc-twl4030.h"
@@ -399,7 +399,7 @@ static void __init omap_ldp_map_io(void)
MACHINE_START(OMAP_LDP, "OMAP LDP board")
.phys_io = 0x48000000,
- .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .io_pg_offst = ((0xfa000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = omap_ldp_map_io,
.init_irq = omap_ldp_init_irq,
diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c
index 8341632d260b..764ab1ed576d 100644
--- a/arch/arm/mach-omap2/board-n8x0.c
+++ b/arch/arm/mach-omap2/board-n8x0.c
@@ -23,12 +23,12 @@
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
-#include <mach/board.h>
-#include <mach/common.h>
+#include <plat/board.h>
+#include <plat/common.h>
#include <mach/irqs.h>
-#include <mach/mcspi.h>
-#include <mach/onenand.h>
-#include <mach/serial.h>
+#include <plat/mcspi.h>
+#include <plat/onenand.h>
+#include <plat/serial.h>
static struct omap2_mcspi_device_config p54spi_mcspi_config = {
.turbo_mode = 0,
@@ -121,7 +121,7 @@ static void __init n8x0_init_machine(void)
MACHINE_START(NOKIA_N800, "Nokia N800")
.phys_io = 0x48000000,
- .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .io_pg_offst = ((0xfa000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = n8x0_map_io,
.init_irq = n8x0_init_irq,
@@ -131,7 +131,7 @@ MACHINE_END
MACHINE_START(NOKIA_N810, "Nokia N810")
.phys_io = 0x48000000,
- .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .io_pg_offst = ((0xfa000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = n8x0_map_io,
.init_irq = n8x0_init_irq,
@@ -141,7 +141,7 @@ MACHINE_END
MACHINE_START(NOKIA_N810_WIMAX, "Nokia N810 WiMAX")
.phys_io = 0x48000000,
- .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .io_pg_offst = ((0xfa000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = n8x0_map_io,
.init_irq = n8x0_init_irq,
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 70df6b4dbcd4..71a3528b40ce 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -37,13 +37,13 @@
#include <asm/mach/map.h>
#include <asm/mach/flash.h>
-#include <mach/board.h>
-#include <mach/common.h>
-#include <mach/gpmc.h>
-#include <mach/nand.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/timer-gp.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/gpmc.h>
+#include <plat/nand.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/timer-gp.h>
#include "mmc-twl4030.h"
@@ -429,7 +429,7 @@ static void __init omap3_beagle_map_io(void)
MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
/* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */
.phys_io = 0x48000000,
- .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .io_pg_offst = ((0xfa000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = omap3_beagle_map_io,
.init_irq = omap3_beagle_init_irq,
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index e4ec0c591216..5d2310e43dbd 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -27,17 +27,19 @@
#include <linux/i2c/twl4030.h>
#include <linux/usb/otg.h>
+#include <linux/regulator/machine.h>
+
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/board.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/common.h>
-#include <mach/mcspi.h>
-#include <mach/keypad.h>
+#include <plat/board.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/common.h>
+#include <plat/mcspi.h>
+#include <plat/keypad.h>
#include "sdram-micron-mt46h32m32lf-6.h"
#include "mmc-twl4030.h"
@@ -92,6 +94,44 @@ static inline void __init omap3evm_init_smc911x(void)
gpio_direction_input(OMAP3EVM_ETHR_GPIO_IRQ);
}
+static struct regulator_consumer_supply omap3evm_vmmc1_supply = {
+ .supply = "vmmc",
+};
+
+static struct regulator_consumer_supply omap3evm_vsim_supply = {
+ .supply = "vmmc_aux",
+};
+
+/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
+static struct regulator_init_data omap3evm_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 = &omap3evm_vmmc1_supply,
+};
+
+/* VSIM for MMC1 pins DAT4..DAT7 (2 mA, plus card == max 50 mA) */
+static struct regulator_init_data omap3evm_vsim = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 3000000,
+ .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 = &omap3evm_vsim_supply,
+};
+
static struct twl4030_hsmmc_info mmc[] = {
{
.mmc = 1,
@@ -134,6 +174,10 @@ static int omap3evm_twl_gpio_setup(struct device *dev,
mmc[0].gpio_cd = gpio + 0;
twl4030_mmc_init(mmc);
+ /* link regulators to MMC adapters */
+ omap3evm_vmmc1_supply.dev = mmc[0].dev;
+ omap3evm_vsim_supply.dev = mmc[0].dev;
+
/*
* Most GPIOs are for USB OTG. Some are mostly sent to
* the P2 connector; notably LEDA for the LCD backlight.
@@ -203,6 +247,8 @@ static struct twl4030_platform_data omap3evm_twldata = {
.madc = &omap3evm_madc_data,
.usb = &omap3evm_usb_data,
.gpio = &omap3evm_gpio_data,
+ .vmmc1 = &omap3evm_vmmc1,
+ .vsim = &omap3evm_vsim,
};
static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
@@ -324,7 +370,7 @@ static void __init omap3_evm_map_io(void)
MACHINE_START(OMAP3EVM, "OMAP3 EVM")
/* Maintainer: Syed Mohammed Khasim - Texas Instruments */
.phys_io = 0x48000000,
- .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .io_pg_offst = ((0xfa000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = omap3_evm_map_io,
.init_irq = omap3_evm_init_irq,
diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c
index 7f6bf8772af7..d6bcfaab94ca 100644
--- a/arch/arm/mach-omap2/board-omap3pandora.c
+++ b/arch/arm/mach-omap2/board-omap3pandora.c
@@ -33,14 +33,14 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/board.h>
-#include <mach/common.h>
+#include <plat/board.h>
+#include <plat/common.h>
#include <mach/gpio.h>
#include <mach/hardware.h>
-#include <mach/mcspi.h>
-#include <mach/usb.h>
-#include <mach/keypad.h>
-#include <mach/mux.h>
+#include <plat/mcspi.h>
+#include <plat/usb.h>
+#include <plat/keypad.h>
+#include <plat/mux.h>
#include "sdram-micron-mt46h32m32lf-6.h"
#include "mmc-twl4030.h"
@@ -412,7 +412,7 @@ static void __init omap3pandora_map_io(void)
MACHINE_START(OMAP3_PANDORA, "Pandora Handheld Console")
.phys_io = 0x48000000,
- .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .io_pg_offst = ((0xfa000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = omap3pandora_map_io,
.init_irq = omap3pandora_init_irq,
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 9917d2fddc2f..461522c1bced 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -38,14 +38,14 @@
#include <asm/mach/flash.h>
#include <asm/mach/map.h>
-#include <mach/board.h>
-#include <mach/common.h>
+#include <plat/board.h>
+#include <plat/common.h>
#include <mach/gpio.h>
-#include <mach/gpmc.h>
+#include <plat/gpmc.h>
#include <mach/hardware.h>
-#include <mach/nand.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
+#include <plat/nand.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
#include "sdram-micron-mt46h32m32lf-6.h"
#include "mmc-twl4030.h"
@@ -67,7 +67,7 @@
#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
-#include <mach/mcspi.h>
+#include <plat/mcspi.h>
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
@@ -451,7 +451,7 @@ static void __init overo_map_io(void)
MACHINE_START(OVERO, "Gumstix Overo")
.phys_io = 0x48000000,
- .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .io_pg_offst = ((0xfa000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = overo_map_io,
.init_irq = overo_init_irq,
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index 2b0eb1ba5d7f..7a42b9b61f34 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -21,15 +21,15 @@
#include <linux/gpio.h>
#include <linux/mmc/host.h>
-#include <mach/mcspi.h>
-#include <mach/mux.h>
-#include <mach/board.h>
-#include <mach/common.h>
-#include <mach/dma.h>
-#include <mach/gpmc.h>
-#include <mach/keypad.h>
-#include <mach/onenand.h>
-#include <mach/gpmc-smc91x.h>
+#include <plat/mcspi.h>
+#include <plat/mux.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/dma.h>
+#include <plat/gpmc.h>
+#include <plat/keypad.h>
+#include <plat/onenand.h>
+#include <plat/gpmc-smc91x.h>
#include "mmc-twl4030.h"
@@ -292,15 +292,9 @@ static struct twl4030_usb_data rx51_usb_data = {
static struct twl4030_ins sleep_on_seq[] __initdata = {
/*
- * Turn off VDD1 and VDD2.
+ * Turn off everything
*/
- {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_OFF), 4},
- {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_OFF), 2},
-/*
- * And also turn off the OMAP3 PLLs and the sysclk output.
- */
- {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_OFF), 3},
- {MSG_SINGULAR(DEV_GRP_P1, 0x17, RES_STATE_OFF), 3},
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 1, 0, RES_STATE_SLEEP), 2},
};
static struct twl4030_script sleep_on_script __initdata = {
@@ -311,14 +305,9 @@ static struct twl4030_script sleep_on_script __initdata = {
static struct twl4030_ins wakeup_seq[] __initdata = {
/*
- * Reenable the OMAP3 PLLs.
- * Wakeup VDD1 and VDD2.
- * Reenable sysclk output.
+ * Reenable everything
*/
- {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_ACTIVE), 0x30},
- {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_ACTIVE), 0x30},
- {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_ACTIVE), 0x37},
- {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 3},
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 1, 0, RES_STATE_ACTIVE), 2},
};
static struct twl4030_script wakeup_script __initdata = {
@@ -329,10 +318,9 @@ static struct twl4030_script wakeup_script __initdata = {
static struct twl4030_ins wakeup_p3_seq[] __initdata = {
/*
- * Wakeup VDD1 (dummy to be able to insert a delay)
- * Enable CLKEN
+ * Reenable everything
*/
- {MSG_SINGULAR(DEV_GRP_P1, 0x17, RES_STATE_ACTIVE), 3},
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 1, 0, RES_STATE_ACTIVE), 2},
};
static struct twl4030_script wakeup_p3_script __initdata = {
@@ -353,12 +341,11 @@ static struct twl4030_ins wrst_seq[] __initdata = {
{MSG_SINGULAR(DEV_GRP_NULL, RES_RESET, RES_STATE_OFF), 2},
{MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 0, 1, RES_STATE_ACTIVE),
0x13},
- {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_PP, 0, 2, RES_STATE_WRST), 0x13},
{MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_PP, 0, 3, RES_STATE_OFF), 0x13},
{MSG_SINGULAR(DEV_GRP_NULL, RES_VDD1, RES_STATE_WRST), 0x13},
{MSG_SINGULAR(DEV_GRP_NULL, RES_VDD2, RES_STATE_WRST), 0x13},
{MSG_SINGULAR(DEV_GRP_NULL, RES_VPLL1, RES_STATE_WRST), 0x35},
- {MSG_SINGULAR(DEV_GRP_P1, RES_HFCLKOUT, RES_STATE_ACTIVE), 2},
+ {MSG_SINGULAR(DEV_GRP_P3, RES_HFCLKOUT, RES_STATE_ACTIVE), 2},
{MSG_SINGULAR(DEV_GRP_NULL, RES_RESET, RES_STATE_ACTIVE), 2},
};
@@ -380,22 +367,81 @@ static struct twl4030_script *twl4030_scripts[] __initdata = {
};
static struct twl4030_resconfig twl4030_rconfig[] __initdata = {
- { .resource = RES_VINTANA1, .devgroup = -1, .type = -1, .type2 = 1 },
- { .resource = RES_VINTANA2, .devgroup = -1, .type = -1, .type2 = 1 },
- { .resource = RES_VINTDIG, .devgroup = -1, .type = -1, .type2 = 1 },
- { .resource = RES_VMMC1, .devgroup = -1, .type = -1, .type2 = 3},
- { .resource = RES_VMMC2, .devgroup = DEV_GRP_NULL, .type = -1,
- .type2 = 3},
- { .resource = RES_VAUX1, .devgroup = -1, .type = -1, .type2 = 3},
- { .resource = RES_VAUX2, .devgroup = -1, .type = -1, .type2 = 3},
- { .resource = RES_VAUX3, .devgroup = -1, .type = -1, .type2 = 3},
- { .resource = RES_VAUX4, .devgroup = -1, .type = -1, .type2 = 3},
- { .resource = RES_VPLL2, .devgroup = -1, .type = -1, .type2 = 3},
- { .resource = RES_VDAC, .devgroup = -1, .type = -1, .type2 = 3},
- { .resource = RES_VSIM, .devgroup = DEV_GRP_NULL, .type = -1,
- .type2 = 3},
- { .resource = RES_CLKEN, .devgroup = DEV_GRP_P3, .type = -1,
- .type2 = 1 },
+ { .resource = RES_VDD1, .devgroup = -1,
+ .type = 1, .type2 = -1, .remap_off = RES_STATE_OFF,
+ .remap_sleep = RES_STATE_OFF
+ },
+ { .resource = RES_VDD2, .devgroup = -1,
+ .type = 1, .type2 = -1, .remap_off = RES_STATE_OFF,
+ .remap_sleep = RES_STATE_OFF
+ },
+ { .resource = RES_VPLL1, .devgroup = -1,
+ .type = 1, .type2 = -1, .remap_off = RES_STATE_OFF,
+ .remap_sleep = RES_STATE_OFF
+ },
+ { .resource = RES_VPLL2, .devgroup = -1,
+ .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_VAUX1, .devgroup = -1,
+ .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_VAUX2, .devgroup = -1,
+ .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_VAUX3, .devgroup = -1,
+ .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_VAUX4, .devgroup = -1,
+ .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_VMMC1, .devgroup = -1,
+ .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_VMMC2, .devgroup = -1,
+ .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_VDAC, .devgroup = -1,
+ .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_VSIM, .devgroup = -1,
+ .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_VINTANA1, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
+ .type = -1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_VINTANA2, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
+ .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_VINTDIG, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
+ .type = -1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_VIO, .devgroup = DEV_GRP_P3,
+ .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_CLKEN, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
+ .type = 1, .type2 = -1 , .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_REGEN, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
+ .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_NRES_PWRON, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
+ .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_SYSEN, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
+ .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_HFCLKOUT, .devgroup = DEV_GRP_P3,
+ .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_32KCLKOUT, .devgroup = -1,
+ .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_RESET, .devgroup = -1,
+ .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+ },
+ { .resource = RES_Main_Ref, .devgroup = -1,
+ .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+ },
{ 0, 0},
};
diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c
index f9196c3b1a7b..060245e14740 100644
--- a/arch/arm/mach-omap2/board-rx51.c
+++ b/arch/arm/mach-omap2/board-rx51.c
@@ -22,14 +22,14 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <mach/mcspi.h>
-#include <mach/mux.h>
-#include <mach/board.h>
-#include <mach/common.h>
-#include <mach/keypad.h>
-#include <mach/dma.h>
-#include <mach/gpmc.h>
-#include <mach/usb.h>
+#include <plat/mcspi.h>
+#include <plat/mux.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/keypad.h>
+#include <plat/dma.h>
+#include <plat/gpmc.h>
+#include <plat/usb.h>
static struct omap_lcd_config rx51_lcd_config = {
.ctrl_name = "internal",
@@ -85,7 +85,7 @@ static void __init rx51_map_io(void)
MACHINE_START(NOKIA_RX51, "Nokia RX-51 board")
/* Maintainer: Lauri Leukkunen <lauri.leukkunen@nokia.com> */
.phys_io = 0x48000000,
- .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .io_pg_offst = ((0xfa000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = rx51_map_io,
.init_irq = rx51_init_irq,
diff --git a/arch/arm/mach-omap2/board-zoom-debugboard.c b/arch/arm/mach-omap2/board-zoom-debugboard.c
index 1f13e2a1f322..91ecddc9057a 100644
--- a/arch/arm/mach-omap2/board-zoom-debugboard.c
+++ b/arch/arm/mach-omap2/board-zoom-debugboard.c
@@ -14,7 +14,7 @@
#include <linux/smsc911x.h>
#include <linux/interrupt.h>
-#include <mach/gpmc.h>
+#include <plat/gpmc.h>
#define ZOOM2_SMSC911X_CS 7
#define ZOOM2_SMSC911X_GPIO 158
diff --git a/arch/arm/mach-omap2/board-zoom2.c b/arch/arm/mach-omap2/board-zoom2.c
index fd3369d5e5cb..56f9d8436323 100644
--- a/arch/arm/mach-omap2/board-zoom2.c
+++ b/arch/arm/mach-omap2/board-zoom2.c
@@ -20,9 +20,9 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <mach/common.h>
-#include <mach/usb.h>
-#include <mach/keypad.h>
+#include <plat/common.h>
+#include <plat/usb.h>
+#include <plat/keypad.h>
#include "mmc-twl4030.h"
#include "sdram-micron-mt46h32m32lf-6.h"
@@ -283,7 +283,7 @@ static void __init omap_zoom2_map_io(void)
MACHINE_START(OMAP_ZOOM2, "OMAP Zoom2 board")
.phys_io = 0x48000000,
- .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,
+ .io_pg_offst = ((0xfa000000) >> 18) & 0xfffc,
.boot_params = 0x80000100,
.map_io = omap_zoom2_map_io,
.init_irq = omap_zoom2_init_irq,
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index f2a92d614f0f..4716206547ac 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -24,13 +24,13 @@
#include <linux/io.h>
#include <linux/bitops.h>
-#include <mach/clock.h>
-#include <mach/clockdomain.h>
-#include <mach/cpu.h>
-#include <mach/prcm.h>
+#include <plat/clock.h>
+#include <plat/clockdomain.h>
+#include <plat/cpu.h>
+#include <plat/prcm.h>
#include <asm/div64.h>
-#include <mach/sdrc.h>
+#include <plat/sdrc.h>
#include "sdrc.h"
#include "clock.h"
#include "prm.h"
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
index 9ae7540f8af2..43b6bedaafd6 100644
--- a/arch/arm/mach-omap2/clock.h
+++ b/arch/arm/mach-omap2/clock.h
@@ -16,7 +16,7 @@
#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK_H
#define __ARCH_ARM_MACH_OMAP2_CLOCK_H
-#include <mach/clock.h>
+#include <plat/clock.h>
/* The maximum error between a target DPLL rate and the rounded rate in Hz */
#define DEFAULT_DPLL_RATE_TOLERANCE 50000
diff --git a/arch/arm/mach-omap2/clock24xx.c b/arch/arm/mach-omap2/clock24xx.c
index e2dbedd581e8..e70e7e000eaa 100644
--- a/arch/arm/mach-omap2/clock24xx.c
+++ b/arch/arm/mach-omap2/clock24xx.c
@@ -28,13 +28,13 @@
#include <linux/cpufreq.h>
#include <linux/bitops.h>
-#include <mach/clock.h>
-#include <mach/sram.h>
-#include <mach/prcm.h>
+#include <plat/clock.h>
+#include <plat/sram.h>
+#include <plat/prcm.h>
#include <asm/div64.h>
#include <asm/clkdev.h>
-#include <mach/sdrc.h>
+#include <plat/sdrc.h>
#include "clock.h"
#include "prm.h"
#include "prm-regbits-24xx.h"
diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c
index 489556eecbd1..c258f87e78b9 100644
--- a/arch/arm/mach-omap2/clock34xx.c
+++ b/arch/arm/mach-omap2/clock34xx.c
@@ -27,13 +27,13 @@
#include <linux/limits.h>
#include <linux/bitops.h>
-#include <mach/cpu.h>
-#include <mach/clock.h>
-#include <mach/sram.h>
+#include <plat/cpu.h>
+#include <plat/clock.h>
+#include <plat/sram.h>
#include <asm/div64.h>
#include <asm/clkdev.h>
-#include <mach/sdrc.h>
+#include <plat/sdrc.h>
#include "clock.h"
#include "prm.h"
#include "prm-regbits-34xx.h"
diff --git a/arch/arm/mach-omap2/clock34xx.h b/arch/arm/mach-omap2/clock34xx.h
index c8119781e00a..a1b3de7e2bd7 100644
--- a/arch/arm/mach-omap2/clock34xx.h
+++ b/arch/arm/mach-omap2/clock34xx.h
@@ -19,7 +19,7 @@
#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK34XX_H
#define __ARCH_ARM_MACH_OMAP2_CLOCK34XX_H
-#include <mach/control.h>
+#include <plat/control.h>
#include "clock.h"
#include "cm.h"
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index 58aff8485df9..fcd82320a6a3 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -28,14 +28,14 @@
#include <linux/bitops.h>
-#include <mach/clock.h>
+#include <plat/clock.h>
#include "prm.h"
#include "prm-regbits-24xx.h"
#include "cm.h"
-#include <mach/powerdomain.h>
-#include <mach/clockdomain.h>
+#include <plat/powerdomain.h>
+#include <plat/clockdomain.h>
/* clkdm_list contains all registered struct clockdomains */
static LIST_HEAD(clkdm_list);
diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h
index fe319ae4ca0a..c4ee0761d908 100644
--- a/arch/arm/mach-omap2/clockdomains.h
+++ b/arch/arm/mach-omap2/clockdomains.h
@@ -10,7 +10,7 @@
#ifndef __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS_H
#define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS_H
-#include <mach/clockdomain.h>
+#include <plat/clockdomain.h>
/*
* OMAP2/3-common clockdomains
diff --git a/arch/arm/mach-omap2/cm.h b/arch/arm/mach-omap2/cm.h
index cfd0b726ba44..a2fcfcc253cc 100644
--- a/arch/arm/mach-omap2/cm.h
+++ b/arch/arm/mach-omap2/cm.h
@@ -17,11 +17,11 @@
#include "prcm-common.h"
#define OMAP2420_CM_REGADDR(module, reg) \
- OMAP2_IO_ADDRESS(OMAP2420_CM_BASE + (module) + (reg))
+ OMAP2_L4_IO_ADDRESS(OMAP2420_CM_BASE + (module) + (reg))
#define OMAP2430_CM_REGADDR(module, reg) \
- OMAP2_IO_ADDRESS(OMAP2430_CM_BASE + (module) + (reg))
+ OMAP2_L4_IO_ADDRESS(OMAP2430_CM_BASE + (module) + (reg))
#define OMAP34XX_CM_REGADDR(module, reg) \
- OMAP2_IO_ADDRESS(OMAP3430_CM_BASE + (module) + (reg))
+ OMAP2_L4_IO_ADDRESS(OMAP3430_CM_BASE + (module) + (reg))
/*
* Architecture-specific global CM registers
diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
index 5f3aad977842..6adb360c6d45 100644
--- a/arch/arm/mach-omap2/control.c
+++ b/arch/arm/mach-omap2/control.c
@@ -15,8 +15,8 @@
#include <linux/kernel.h>
#include <linux/io.h>
-#include <mach/common.h>
-#include <mach/control.h>
+#include <plat/common.h>
+#include <plat/control.h>
static void __iomem *omap2_ctrl_base;
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index faf7a1e0c525..7d4513b619f2 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -20,12 +20,12 @@
#include <asm/mach-types.h>
#include <asm/mach/map.h>
-#include <mach/control.h>
-#include <mach/tc.h>
-#include <mach/board.h>
-#include <mach/mux.h>
+#include <plat/control.h>
+#include <plat/tc.h>
+#include <plat/board.h>
+#include <plat/mux.h>
#include <mach/gpio.h>
-#include <mach/mmc.h>
+#include <plat/mmc.h>
#if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
@@ -250,7 +250,7 @@ static inline void omap_init_sti(void) {}
#if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
-#include <mach/mcspi.h>
+#include <plat/mcspi.h>
#define OMAP2_MCSPI1_BASE 0x48098000
#define OMAP2_MCSPI2_BASE 0x4809a000
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index 54fec53a48e7..7bb69220adfa 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -17,9 +17,9 @@
#include <asm/mach/flash.h>
-#include <mach/onenand.h>
-#include <mach/board.h>
-#include <mach/gpmc.h>
+#include <plat/onenand.h>
+#include <plat/board.h>
+#include <plat/gpmc.h>
static struct omap_onenand_platform_data *gpmc_onenand_data;
diff --git a/arch/arm/mach-omap2/gpmc-smc91x.c b/arch/arm/mach-omap2/gpmc-smc91x.c
index df99d31d8b64..6083e21b3be6 100644
--- a/arch/arm/mach-omap2/gpmc-smc91x.c
+++ b/arch/arm/mach-omap2/gpmc-smc91x.c
@@ -17,9 +17,9 @@
#include <linux/io.h>
#include <linux/smc91x.h>
-#include <mach/board.h>
-#include <mach/gpmc.h>
-#include <mach/gpmc-smc91x.h>
+#include <plat/board.h>
+#include <plat/gpmc.h>
+#include <plat/gpmc-smc91x.h>
static struct omap_smc91x_platform_data *gpmc_cfg;
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 15876828db23..004da696ace7 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -24,9 +24,9 @@
#include <linux/module.h>
#include <asm/mach-types.h>
-#include <mach/gpmc.h>
+#include <plat/gpmc.h>
-#include <mach/sdrc.h>
+#include <plat/sdrc.h>
/* GPMC register offsets */
#define GPMC_REVISION 0x00
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index a98201cc265c..1c1511220890 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -21,13 +21,14 @@
#include <asm/cputype.h>
-#include <mach/common.h>
-#include <mach/control.h>
-#include <mach/cpu.h>
+#include <plat/common.h>
+#include <plat/control.h>
+#include <plat/cpu.h>
static struct omap_chip_id omap_chip;
static unsigned int omap_revision;
+u32 omap3_features;
unsigned int omap_rev(void)
{
@@ -155,12 +156,37 @@ void __init omap24xx_check_revision(void)
pr_info("\n");
}
-void __init omap34xx_check_revision(void)
+#define OMAP3_CHECK_FEATURE(status,feat) \
+ if (((status & OMAP3_ ##feat## _MASK) \
+ >> OMAP3_ ##feat## _SHIFT) != FEAT_ ##feat## _NONE) { \
+ omap3_features |= OMAP3_HAS_ ##feat; \
+ }
+
+void __init omap3_check_features(void)
+{
+ u32 status;
+
+ omap3_features = 0;
+
+ status = omap_ctrl_readl(OMAP3_CONTROL_OMAP_STATUS);
+
+ OMAP3_CHECK_FEATURE(status, L2CACHE);
+ OMAP3_CHECK_FEATURE(status, IVA);
+ OMAP3_CHECK_FEATURE(status, SGX);
+ OMAP3_CHECK_FEATURE(status, NEON);
+ OMAP3_CHECK_FEATURE(status, ISP);
+
+ /*
+ * TODO: Get additional info (where applicable)
+ * e.g. Size of L2 cache.
+ */
+}
+
+void __init omap3_check_revision(void)
{
u32 cpuid, idcode;
u16 hawkeye;
u8 rev;
- char *rev_name = "ES1.0";
/*
* We cannot access revision registers on ES1.0.
@@ -170,7 +196,7 @@ void __init omap34xx_check_revision(void)
cpuid = read_cpuid(CPUID_ID);
if ((((cpuid >> 4) & 0xfff) == 0xc08) && ((cpuid & 0xf) == 0x0)) {
omap_revision = OMAP3430_REV_ES1_0;
- goto out;
+ return;
}
/*
@@ -183,33 +209,111 @@ void __init omap34xx_check_revision(void)
hawkeye = (idcode >> 12) & 0xffff;
rev = (idcode >> 28) & 0xff;
- if (hawkeye == 0xb7ae) {
+ switch (hawkeye) {
+ case 0xb7ae:
+ /* Handle 34xx/35xx devices */
switch (rev) {
- case 0:
+ case 0: /* Take care of early samples */
+ case 1:
omap_revision = OMAP3430_REV_ES2_0;
- rev_name = "ES2.0";
break;
case 2:
omap_revision = OMAP3430_REV_ES2_1;
- rev_name = "ES2.1";
break;
case 3:
omap_revision = OMAP3430_REV_ES3_0;
- rev_name = "ES3.0";
break;
case 4:
omap_revision = OMAP3430_REV_ES3_1;
- rev_name = "ES3.1";
break;
default:
/* Use the latest known revision as default */
omap_revision = OMAP3430_REV_ES3_1;
- rev_name = "Unknown revision\n";
}
+ break;
+ case 0xb891:
+ /* Handle 36xx devices */
+ switch (rev) {
+ case 0:
+ omap_revision = OMAP3630_REV_ES1_0;
+ break;
+ default:
+ /* Use the latest known revision as default */
+ omap_revision = OMAP3630_REV_ES1_0;
+ }
+ break;
+ default:
+ /* Unknown default to latest silicon rev as default*/
+ omap_revision = OMAP3630_REV_ES1_0;
}
+}
-out:
- pr_info("OMAP%04x %s\n", omap_rev() >> 16, rev_name);
+#define OMAP3_SHOW_FEATURE(feat) \
+ if (omap3_has_ ##feat()) { \
+ pr_info (" - "#feat" : Y"); \
+ } else { \
+ pr_info (" - "#feat" : N"); \
+ }
+
+void __init omap3_cpuinfo(void)
+{
+ u8 rev = GET_OMAP_REVISION();
+ char cpu_name[16], cpu_rev[16];
+
+ /* OMAP3430 and OMAP3530 are assumed to be same.
+ *
+ * OMAP3525, OMAP3515 and OMAP3503 can be detected only based
+ * on available features. Upon detection, update the CPU id
+ * and CPU class bits.
+ */
+ if (cpu_is_omap3630())
+ strcpy(cpu_name, "3630");
+ else if (omap3_has_iva() && omap3_has_sgx())
+ strcpy(cpu_name, "3430/3530");
+ else if (omap3_has_sgx()) {
+ omap_revision = OMAP3525_REV(rev);
+ strcpy(cpu_name, "3525");
+ }
+ else if (omap3_has_iva()) {
+ omap_revision = OMAP3515_REV(rev);
+ strcpy(cpu_name, "3515");
+ }
+ else {
+ omap_revision = OMAP3503_REV(rev);
+ strcpy(cpu_name, "3503");
+ }
+
+ switch (rev) {
+ case OMAP_REVBITS_00:
+ strcpy(cpu_rev, "1.0");
+ 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:
+ strcpy(cpu_rev, "3.1");
+ break;
+ default:
+ /* Use the latest known revision as default */
+ strcpy(cpu_rev, "3.1");
+ }
+
+ /*
+ * Print verbose information
+ */
+ pr_info("OMAP%s ES%s\n", cpu_name, cpu_rev);
+
+ OMAP3_SHOW_FEATURE(l2cache);
+ OMAP3_SHOW_FEATURE(iva);
+ OMAP3_SHOW_FEATURE(sgx);
+ OMAP3_SHOW_FEATURE(neon);
+ OMAP3_SHOW_FEATURE(isp);
}
/*
@@ -223,8 +327,11 @@ void __init omap2_check_revision(void)
*/
if (cpu_is_omap24xx())
omap24xx_check_revision();
- else if (cpu_is_omap34xx())
- omap34xx_check_revision();
+ else if (cpu_is_omap34xx()) {
+ omap3_check_features();
+ omap3_check_revision();
+ omap3_cpuinfo();
+ }
else if (cpu_is_omap44xx()) {
printk(KERN_INFO "FIXME: CPU revision = OMAP4430\n");
return;
diff --git a/arch/arm/mach-omap2/include/mach/clkdev.h b/arch/arm/mach-omap2/include/mach/clkdev.h
new file mode 100644
index 000000000000..53b027441c56
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/clkdev.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/clkdev.h
+ */
+
+#include <plat/clkdev.h>
diff --git a/arch/arm/plat-omap/include/mach/debug-macro.S b/arch/arm/mach-omap2/include/mach/debug-macro.S
index ac24050e3416..e9f255df9163 100644
--- a/arch/arm/plat-omap/include/mach/debug-macro.S
+++ b/arch/arm/mach-omap2/include/mach/debug-macro.S
@@ -1,4 +1,4 @@
-/* arch/arm/plat-omap/include/mach/debug-macro.S
+/* arch/arm/mach-omap2/include/mach/debug-macro.S
*
* Debugging macro include header
*
@@ -14,20 +14,9 @@
.macro addruart,rx
mrc p15, 0, \rx, c1, c0
tst \rx, #1 @ MMU enabled?
-#ifdef CONFIG_ARCH_OMAP1
- moveq \rx, #0xff000000 @ physical base address
- movne \rx, #0xfe000000 @ virtual base
- orr \rx, \rx, #0x00fb0000
-#ifdef CONFIG_OMAP_LL_DEBUG_UART3
- orr \rx, \rx, #0x00009000 @ UART 3
-#endif
-#if defined(CONFIG_OMAP_LL_DEBUG_UART2) || defined(CONFIG_OMAP_LL_DEBUG_UART3)
- orr \rx, \rx, #0x00000800 @ UART 2 & 3
-#endif
-
-#elif CONFIG_ARCH_OMAP2
+#ifdef CONFIG_ARCH_OMAP2
moveq \rx, #0x48000000 @ physical base address
- movne \rx, #0xd8000000 @ virtual base
+ movne \rx, #0xfa000000 @ virtual base
orr \rx, \rx, #0x0006a000
#ifdef CONFIG_OMAP_LL_DEBUG_UART2
add \rx, \rx, #0x00002000 @ UART 2
@@ -38,7 +27,7 @@
#elif defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
moveq \rx, #0x48000000 @ physical base address
- movne \rx, #0xd8000000 @ virtual base
+ movne \rx, #0xfa000000 @ virtual base
orr \rx, \rx, #0x0006a000
#ifdef CONFIG_OMAP_LL_DEBUG_UART2
add \rx, \rx, #0x00002000 @ UART 2
diff --git a/arch/arm/plat-omap/include/mach/entry-macro.S b/arch/arm/mach-omap2/include/mach/entry-macro.S
index a5592991634d..c7f1720bf282 100644
--- a/arch/arm/plat-omap/include/mach/entry-macro.S
+++ b/arch/arm/mach-omap2/include/mach/entry-macro.S
@@ -15,65 +15,17 @@
#include <mach/irqs.h>
#include <asm/hardware/gic.h>
-#if defined(CONFIG_ARCH_OMAP1)
-
-#if defined(CONFIG_ARCH_OMAP730) && \
- (defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX))
-#error "FIXME: OMAP730 doesn't support multiple-OMAP"
-#elif defined(CONFIG_ARCH_OMAP730)
-#define INT_IH2_IRQ INT_730_IH2_IRQ
-#elif defined(CONFIG_ARCH_OMAP15XX)
-#define INT_IH2_IRQ INT_1510_IH2_IRQ
-#elif defined(CONFIG_ARCH_OMAP16XX)
-#define INT_IH2_IRQ INT_1610_IH2_IRQ
-#else
-#warning "IH2 IRQ defaulted"
-#define INT_IH2_IRQ INT_1510_IH2_IRQ
-#endif
-
- .macro disable_fiq
- .endm
-
- .macro get_irqnr_preamble, base, tmp
- .endm
-
- .macro arch_ret_to_user, tmp1, tmp2
- .endm
-
- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
- ldr \base, =OMAP1_IO_ADDRESS(OMAP_IH1_BASE)
- ldr \irqnr, [\base, #IRQ_ITR_REG_OFFSET]
- ldr \tmp, [\base, #IRQ_MIR_REG_OFFSET]
- mov \irqstat, #0xffffffff
- bic \tmp, \irqstat, \tmp
- tst \irqnr, \tmp
- beq 1510f
-
- ldr \irqnr, [\base, #IRQ_SIR_FIQ_REG_OFFSET]
- cmp \irqnr, #0
- ldreq \irqnr, [\base, #IRQ_SIR_IRQ_REG_OFFSET]
- cmpeq \irqnr, #INT_IH2_IRQ
- ldreq \base, =OMAP1_IO_ADDRESS(OMAP_IH2_BASE)
- ldreq \irqnr, [\base, #IRQ_SIR_IRQ_REG_OFFSET]
- addeqs \irqnr, \irqnr, #32
-1510:
- .endm
-
-#endif
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
- defined(CONFIG_ARCH_OMAP4)
-
-#include <mach/omap24xx.h>
-#include <mach/omap34xx.h>
+#include <plat/omap24xx.h>
+#include <plat/omap34xx.h>
/* REVISIT: This should be set dynamically if CONFIG_MULTI_OMAP2 is selected */
#if defined(CONFIG_ARCH_OMAP2420) || defined(CONFIG_ARCH_OMAP2430)
-#define OMAP2_VA_IC_BASE OMAP2_IO_ADDRESS(OMAP24XX_IC_BASE)
+#define OMAP2_VA_IC_BASE OMAP2_L4_IO_ADDRESS(OMAP24XX_IC_BASE)
#elif defined(CONFIG_ARCH_OMAP34XX)
-#define OMAP2_VA_IC_BASE OMAP2_IO_ADDRESS(OMAP34XX_IC_BASE)
+#define OMAP2_VA_IC_BASE OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE)
#endif
#if defined(CONFIG_ARCH_OMAP4)
-#include <mach/omap44xx.h>
+#include <plat/omap44xx.h>
#endif
#define INTCPS_SIR_IRQ_OFFSET 0x0040 /* Active interrupt offset */
#define ACTIVEIRQ_MASK 0x7f /* Active interrupt bits */
@@ -104,6 +56,8 @@
.endm
#else
+#define OMAP44XX_VA_GIC_CPU_BASE OMAP2_L4_IO_ADDRESS(OMAP44XX_GIC_CPU_BASE)
+
/*
* The interrupt numbering scheme is defined in the
* interrupt controller spec. To wit:
@@ -168,5 +122,3 @@
.macro irq_prio_table
.endm
-
-#endif
diff --git a/arch/arm/mach-omap2/include/mach/gpio.h b/arch/arm/mach-omap2/include/mach/gpio.h
new file mode 100644
index 000000000000..be4d290d57ee
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/gpio.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/gpio.h
+ */
+
+#include <plat/gpio.h>
diff --git a/arch/arm/mach-omap2/include/mach/hardware.h b/arch/arm/mach-omap2/include/mach/hardware.h
new file mode 100644
index 000000000000..78edf9d33f71
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/hardware.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/hardware.h
+ */
+
+#include <plat/hardware.h>
diff --git a/arch/arm/mach-omap2/include/mach/io.h b/arch/arm/mach-omap2/include/mach/io.h
new file mode 100644
index 000000000000..fd78f31aa1ad
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/io.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/io.h
+ */
+
+#include <plat/io.h>
diff --git a/arch/arm/mach-omap2/include/mach/irqs.h b/arch/arm/mach-omap2/include/mach/irqs.h
new file mode 100644
index 000000000000..44dab7725696
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/irqs.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/irqs.h
+ */
+
+#include <plat/irqs.h>
diff --git a/arch/arm/mach-omap2/include/mach/memory.h b/arch/arm/mach-omap2/include/mach/memory.h
new file mode 100644
index 000000000000..ca6d32a917dd
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/memory.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/memory.h
+ */
+
+#include <plat/memory.h>
diff --git a/arch/arm/mach-omap2/include/mach/smp.h b/arch/arm/mach-omap2/include/mach/smp.h
new file mode 100644
index 000000000000..323675f21b69
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/smp.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/smp.h
+ */
+
+#include <plat/smp.h>
diff --git a/arch/arm/mach-omap2/include/mach/system.h b/arch/arm/mach-omap2/include/mach/system.h
new file mode 100644
index 000000000000..d488721ab90b
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/system.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/system.h
+ */
+
+#include <plat/system.h>
diff --git a/arch/arm/mach-omap2/include/mach/timex.h b/arch/arm/mach-omap2/include/mach/timex.h
new file mode 100644
index 000000000000..de9f8fc40e7c
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/timex.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/timex.h
+ */
+
+#include <plat/timex.h>
diff --git a/arch/arm/mach-omap2/include/mach/uncompress.h b/arch/arm/mach-omap2/include/mach/uncompress.h
new file mode 100644
index 000000000000..78e0557bfd4e
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/uncompress.h
@@ -0,0 +1,5 @@
+/*
+ * arch/arm/mach-omap2/include/mach/uncompress.h
+ */
+
+#include <plat/uncompress.h>
diff --git a/arch/arm/plat-omap/include/mach/vmalloc.h b/arch/arm/mach-omap2/include/mach/vmalloc.h
index b97dfafeebda..9ce9b6e8ad23 100644
--- a/arch/arm/plat-omap/include/mach/vmalloc.h
+++ b/arch/arm/mach-omap2/include/mach/vmalloc.h
@@ -17,5 +17,4 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#define VMALLOC_END (PAGE_OFFSET + 0x18000000)
-
+#define VMALLOC_END (PAGE_OFFSET + 0x38000000)
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index e3a3bad1d84f..3c33f24208a3 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -27,24 +27,24 @@
#include <asm/mach/map.h>
-#include <mach/mux.h>
-#include <mach/omapfb.h>
-#include <mach/sram.h>
-#include <mach/sdrc.h>
-#include <mach/gpmc.h>
-#include <mach/serial.h>
+#include <plat/mux.h>
+#include <plat/omapfb.h>
+#include <plat/sram.h>
+#include <plat/sdrc.h>
+#include <plat/gpmc.h>
+#include <plat/serial.h>
#ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once clkdev is ready */
#include "clock.h"
-#include <mach/omap-pm.h>
-#include <mach/powerdomain.h>
+#include <plat/omap-pm.h>
+#include <plat/powerdomain.h>
#include "powerdomains.h"
-#include <mach/clockdomain.h>
+#include <plat/clockdomain.h>
#include "clockdomains.h"
#endif
-#include <mach/omap_hwmod.h>
+#include <plat/omap_hwmod.h>
#include "omap_hwmod_2420.h"
#include "omap_hwmod_2430.h"
#include "omap_hwmod_34xx.h"
@@ -203,6 +203,24 @@ static struct map_desc omap44xx_io_desc[] __initdata = {
.type = MT_DEVICE,
},
{
+ .virtual = OMAP44XX_EMIF1_VIRT,
+ .pfn = __phys_to_pfn(OMAP44XX_EMIF1_PHYS),
+ .length = OMAP44XX_EMIF1_SIZE,
+ .type = MT_DEVICE,
+ },
+ {
+ .virtual = OMAP44XX_EMIF2_VIRT,
+ .pfn = __phys_to_pfn(OMAP44XX_EMIF2_PHYS),
+ .length = OMAP44XX_EMIF2_SIZE,
+ .type = MT_DEVICE,
+ },
+ {
+ .virtual = OMAP44XX_DMM_VIRT,
+ .pfn = __phys_to_pfn(OMAP44XX_DMM_PHYS),
+ .length = OMAP44XX_DMM_SIZE,
+ .type = MT_DEVICE,
+ },
+ {
.virtual = L4_PER_44XX_VIRT,
.pfn = __phys_to_pfn(L4_PER_44XX_PHYS),
.length = L4_PER_44XX_SIZE,
diff --git a/arch/arm/mach-omap2/iommu2.c b/arch/arm/mach-omap2/iommu2.c
index 4a0e1cd5c1f4..6f4b7cc8f4d1 100644
--- a/arch/arm/mach-omap2/iommu2.c
+++ b/arch/arm/mach-omap2/iommu2.c
@@ -17,7 +17,7 @@
#include <linux/module.h>
#include <linux/stringify.h>
-#include <mach/iommu.h>
+#include <plat/iommu.h>
/*
* omap2 architecture specific register bit definitions
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index b82863887f10..1db121f437d2 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -178,12 +178,20 @@ void __init omap_init_irq(void)
int i;
for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
+ unsigned long base;
struct omap_irq_bank *bank = irq_banks + i;
if (cpu_is_omap24xx())
- bank->base_reg = OMAP2_IO_ADDRESS(OMAP24XX_IC_BASE);
+ base = OMAP24XX_IC_BASE;
else if (cpu_is_omap34xx())
- bank->base_reg = OMAP2_IO_ADDRESS(OMAP34XX_IC_BASE);
+ base = OMAP34XX_IC_BASE;
+
+ /* Static mapping, never released */
+ bank->base_reg = ioremap(base, SZ_4K);
+ if (!bank->base_reg) {
+ printk(KERN_ERR "Could not ioremap irq bank%i\n", i);
+ continue;
+ }
omap_irq_bank_init_one(bank);
diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c
index c035ad3426d0..46e1f2ebcdca 100644
--- a/arch/arm/mach-omap2/mailbox.c
+++ b/arch/arm/mach-omap2/mailbox.c
@@ -15,7 +15,7 @@
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/io.h>
-#include <mach/mailbox.h>
+#include <plat/mailbox.h>
#include <mach/irqs.h>
#define MAILBOX_REVISION 0x000
diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c
index a846aa1ebb4d..baa451733850 100644
--- a/arch/arm/mach-omap2/mcbsp.c
+++ b/arch/arm/mach-omap2/mcbsp.c
@@ -18,10 +18,10 @@
#include <linux/platform_device.h>
#include <mach/irqs.h>
-#include <mach/dma.h>
-#include <mach/mux.h>
-#include <mach/cpu.h>
-#include <mach/mcbsp.h>
+#include <plat/dma.h>
+#include <plat/mux.h>
+#include <plat/cpu.h>
+#include <plat/mcbsp.h>
static void omap2_mcbsp2_mux_setup(void)
{
diff --git a/arch/arm/mach-omap2/mmc-twl4030.c b/arch/arm/mach-omap2/mmc-twl4030.c
index c9c59a2db4e2..340391468909 100644
--- a/arch/arm/mach-omap2/mmc-twl4030.c
+++ b/arch/arm/mach-omap2/mmc-twl4030.c
@@ -20,9 +20,9 @@
#include <linux/regulator/consumer.h>
#include <mach/hardware.h>
-#include <mach/control.h>
-#include <mach/mmc.h>
-#include <mach/board.h>
+#include <plat/control.h>
+#include <plat/mmc.h>
+#include <plat/board.h>
#include "mmc-twl4030.h"
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index b5fac32aae70..32c953e608db 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -30,8 +30,8 @@
#include <asm/system.h>
-#include <mach/control.h>
-#include <mach/mux.h>
+#include <plat/control.h>
+#include <plat/mux.h>
#ifdef CONFIG_OMAP_MUX
diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
index 48ee295db275..4890bcf4dadd 100644
--- a/arch/arm/mach-omap2/omap-smp.c
+++ b/arch/arm/mach-omap2/omap-smp.c
@@ -24,13 +24,14 @@
#include <asm/localtimer.h>
#include <asm/smp_scu.h>
#include <mach/hardware.h>
+#include <plat/common.h>
/* Registers used for communicating startup information */
-#define OMAP4_AUXCOREBOOT_REG0 (OMAP44XX_VA_WKUPGEN_BASE + 0x800)
-#define OMAP4_AUXCOREBOOT_REG1 (OMAP44XX_VA_WKUPGEN_BASE + 0x804)
+static void __iomem *omap4_auxcoreboot_reg0;
+static void __iomem *omap4_auxcoreboot_reg1;
/* SCU base address */
-static void __iomem *scu_base = OMAP44XX_VA_SCU_BASE;
+static void __iomem *scu_base;
/*
* Use SCU config register to count number of cores
@@ -53,8 +54,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
* core (e.g. timer irq), then they will not have been enabled
* for us: do so
*/
-
- gic_cpu_init(0, OMAP2_IO_ADDRESS(OMAP44XX_GIC_CPU_BASE));
+ gic_cpu_init(0, gic_cpu_base_addr);
/*
* Synchronise with the boot thread.
@@ -79,7 +79,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
* the AuxCoreBoot1 register is updated with cpu state
* A barrier is added to ensure that write buffer is drained
*/
- __raw_writel(cpu, OMAP4_AUXCOREBOOT_REG1);
+ __raw_writel(cpu, omap4_auxcoreboot_reg1);
smp_wmb();
timeout = jiffies + (1 * HZ);
@@ -104,7 +104,7 @@ static void __init wakeup_secondary(void)
* A barrier is added to ensure that write buffer is drained
*/
__raw_writel(virt_to_phys(omap_secondary_startup), \
- OMAP4_AUXCOREBOOT_REG0);
+ omap4_auxcoreboot_reg0);
smp_wmb();
/*
@@ -120,7 +120,13 @@ static void __init wakeup_secondary(void)
*/
void __init smp_init_cpus(void)
{
- unsigned int i, ncores = get_core_count();
+ unsigned int i, ncores;
+
+ /* Never released */
+ scu_base = ioremap(OMAP44XX_SCU_BASE, SZ_256);
+ BUG_ON(!scu_base);
+
+ ncores = get_core_count();
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
@@ -130,6 +136,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
{
unsigned int ncores = get_core_count();
unsigned int cpu = smp_processor_id();
+ void __iomem *omap4_wkupgen_base;
int i;
/* sanity check */
@@ -161,6 +168,12 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
for (i = 0; i < max_cpus; i++)
set_cpu_present(i, true);
+ /* Never released */
+ omap4_wkupgen_base = ioremap(OMAP44XX_WKUPGEN_BASE, SZ_4K);
+ BUG_ON(!omap4_wkupgen_base);
+ omap4_auxcoreboot_reg0 = omap4_wkupgen_base + 0x800;
+ omap4_auxcoreboot_reg1 = omap4_wkupgen_base + 0x804;
+
if (max_cpus > 1) {
/*
* Enable the local timer or broadcast device for the
diff --git a/arch/arm/mach-omap2/omap3-iommu.c b/arch/arm/mach-omap2/omap3-iommu.c
index 194189c746c2..6a9bf4f59d8a 100644
--- a/arch/arm/mach-omap2/omap3-iommu.c
+++ b/arch/arm/mach-omap2/omap3-iommu.c
@@ -12,7 +12,7 @@
#include <linux/platform_device.h>
-#include <mach/iommu.h>
+#include <plat/iommu.h>
#define OMAP3_MMU1_BASE 0x480bd400
#define OMAP3_MMU2_BASE 0x5d000000
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index d2e0f1c95961..633b216a8b26 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -45,11 +45,11 @@
#include <linux/mutex.h>
#include <linux/bootmem.h>
-#include <mach/cpu.h>
-#include <mach/clockdomain.h>
-#include <mach/powerdomain.h>
-#include <mach/clock.h>
-#include <mach/omap_hwmod.h>
+#include <plat/cpu.h>
+#include <plat/clockdomain.h>
+#include <plat/powerdomain.h>
+#include <plat/clock.h>
+#include <plat/omap_hwmod.h>
#include "cm.h"
@@ -496,6 +496,7 @@ static void __iomem *_find_mpu_rt_base(struct omap_hwmod *oh, u8 index)
struct omap_hwmod_addr_space *mem;
int i;
int found = 0;
+ void __iomem *va_start;
if (!oh || oh->slaves_cnt == 0)
return NULL;
@@ -509,16 +510,20 @@ static void __iomem *_find_mpu_rt_base(struct omap_hwmod *oh, u8 index)
}
}
- /* XXX use ioremap() instead? */
-
- if (found)
+ if (found) {
+ va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start);
+ if (!va_start) {
+ pr_err("omap_hwmod: %s: Could not ioremap\n", oh->name);
+ return NULL;
+ }
pr_debug("omap_hwmod: %s: MPU register target at va %p\n",
- oh->name, OMAP2_IO_ADDRESS(mem->pa_start));
- else
+ oh->name, va_start);
+ } else {
pr_debug("omap_hwmod: %s: no MPU register target found\n",
oh->name);
+ }
- return (found) ? OMAP2_IO_ADDRESS(mem->pa_start) : NULL;
+ return (found) ? va_start : NULL;
}
/**
@@ -1148,6 +1153,7 @@ int omap_hwmod_unregister(struct omap_hwmod *oh)
pr_debug("omap_hwmod: %s: unregistering\n", oh->name);
mutex_lock(&omap_hwmod_mutex);
+ iounmap(oh->_rt_va);
list_del(&oh->node);
mutex_unlock(&omap_hwmod_mutex);
diff --git a/arch/arm/mach-omap2/omap_hwmod_2420.h b/arch/arm/mach-omap2/omap_hwmod_2420.h
index 767e4965ac4e..a9ca1b99a301 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2420.h
+++ b/arch/arm/mach-omap2/omap_hwmod_2420.h
@@ -16,10 +16,10 @@
#ifdef CONFIG_ARCH_OMAP2420
-#include <mach/omap_hwmod.h>
+#include <plat/omap_hwmod.h>
#include <mach/irqs.h>
-#include <mach/cpu.h>
-#include <mach/dma.h>
+#include <plat/cpu.h>
+#include <plat/dma.h>
#include "prm-regbits-24xx.h"
diff --git a/arch/arm/mach-omap2/omap_hwmod_2430.h b/arch/arm/mach-omap2/omap_hwmod_2430.h
index a412be6420ec..59a208bea6c2 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2430.h
+++ b/arch/arm/mach-omap2/omap_hwmod_2430.h
@@ -16,10 +16,10 @@
#ifdef CONFIG_ARCH_OMAP2430
-#include <mach/omap_hwmod.h>
+#include <plat/omap_hwmod.h>
#include <mach/irqs.h>
-#include <mach/cpu.h>
-#include <mach/dma.h>
+#include <plat/cpu.h>
+#include <plat/dma.h>
#include "prm-regbits-24xx.h"
diff --git a/arch/arm/mach-omap2/omap_hwmod_34xx.h b/arch/arm/mach-omap2/omap_hwmod_34xx.h
index 1e069f831575..b6076b9c364e 100644
--- a/arch/arm/mach-omap2/omap_hwmod_34xx.h
+++ b/arch/arm/mach-omap2/omap_hwmod_34xx.h
@@ -14,10 +14,10 @@
#ifdef CONFIG_ARCH_OMAP34XX
-#include <mach/omap_hwmod.h>
+#include <plat/omap_hwmod.h>
#include <mach/irqs.h>
-#include <mach/cpu.h>
-#include <mach/dma.h>
+#include <plat/cpu.h>
+#include <plat/dma.h>
#include "prm-regbits-34xx.h"
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
index 2fc4d6abbd0a..7eb2c12c8b7c 100644
--- a/arch/arm/mach-omap2/pm-debug.c
+++ b/arch/arm/mach-omap2/pm-debug.c
@@ -26,10 +26,10 @@
#include <linux/io.h>
#include <linux/module.h>
-#include <mach/clock.h>
-#include <mach/board.h>
-#include <mach/powerdomain.h>
-#include <mach/clockdomain.h>
+#include <plat/clock.h>
+#include <plat/board.h>
+#include <plat/powerdomain.h>
+#include <plat/clockdomain.h>
#include "prm.h"
#include "cm.h"
@@ -51,7 +51,8 @@ int omap2_pm_debug;
regs[reg_count++].val = __raw_readl(reg)
#define DUMP_INTC_REG(reg, off) \
regs[reg_count].name = #reg; \
- regs[reg_count++].val = __raw_readl(OMAP2_IO_ADDRESS(0x480fe000 + (off)))
+ regs[reg_count++].val = \
+ __raw_readl(OMAP2_L4_IO_ADDRESS(0x480fe000 + (off)))
static int __init pm_dbg_init(void);
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 8400f5768923..85b6face5392 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -11,7 +11,7 @@
#ifndef __ARCH_ARM_MACH_OMAP2_PM_H
#define __ARCH_ARM_MACH_OMAP2_PM_H
-#include <mach/powerdomain.h>
+#include <plat/powerdomain.h>
extern int omap3_pm_get_suspend_state(struct powerdomain *pwrdm);
extern int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state);
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index bff5c4e89742..cba05b9f041f 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -36,12 +36,12 @@
#include <asm/mach-types.h>
#include <mach/irqs.h>
-#include <mach/clock.h>
-#include <mach/sram.h>
-#include <mach/control.h>
-#include <mach/mux.h>
-#include <mach/dma.h>
-#include <mach/board.h>
+#include <plat/clock.h>
+#include <plat/sram.h>
+#include <plat/control.h>
+#include <plat/mux.h>
+#include <plat/dma.h>
+#include <plat/board.h>
#include "prm.h"
#include "prm-regbits-24xx.h"
@@ -50,8 +50,8 @@
#include "sdrc.h"
#include "pm.h"
-#include <mach/powerdomain.h>
-#include <mach/clockdomain.h>
+#include <plat/powerdomain.h>
+#include <plat/clockdomain.h>
static void (*omap2_sram_idle)(void);
static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl,
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 378c2f618358..10aa923ea484 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -23,11 +23,11 @@
#include <linux/err.h>
#include <linux/gpio.h>
-#include <mach/sram.h>
-#include <mach/clockdomain.h>
-#include <mach/powerdomain.h>
-#include <mach/control.h>
-#include <mach/serial.h>
+#include <plat/sram.h>
+#include <plat/clockdomain.h>
+#include <plat/powerdomain.h>
+#include <plat/control.h>
+#include <plat/serial.h>
#include "cm.h"
#include "cm-regbits-34xx.h"
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index f00289abd30f..b6990e377783 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -31,9 +31,9 @@
#include "prm.h"
#include "prm-regbits-34xx.h"
-#include <mach/cpu.h>
-#include <mach/powerdomain.h>
-#include <mach/clockdomain.h>
+#include <plat/cpu.h>
+#include <plat/powerdomain.h>
+#include <plat/clockdomain.h>
#include "pm.h"
diff --git a/arch/arm/mach-omap2/powerdomains.h b/arch/arm/mach-omap2/powerdomains.h
index 691470ea4c6a..057b2e3e2c35 100644
--- a/arch/arm/mach-omap2/powerdomains.h
+++ b/arch/arm/mach-omap2/powerdomains.h
@@ -63,7 +63,7 @@
* XXX encode hardware fixed wakeup dependencies -- esp. for 3430 CORE
*/
-#include <mach/powerdomain.h>
+#include <plat/powerdomain.h>
#include "prcm-common.h"
#include "prm.h"
diff --git a/arch/arm/mach-omap2/powerdomains24xx.h b/arch/arm/mach-omap2/powerdomains24xx.h
index 9f08dc3f7fd2..bd249a495aa9 100644
--- a/arch/arm/mach-omap2/powerdomains24xx.h
+++ b/arch/arm/mach-omap2/powerdomains24xx.h
@@ -20,7 +20,7 @@
* the array in mach-omap2/powerdomains.h.
*/
-#include <mach/powerdomain.h>
+#include <plat/powerdomain.h>
#include "prcm-common.h"
#include "prm.h"
diff --git a/arch/arm/mach-omap2/powerdomains34xx.h b/arch/arm/mach-omap2/powerdomains34xx.h
index 4dcf94b800ab..f70eb2da17e7 100644
--- a/arch/arm/mach-omap2/powerdomains34xx.h
+++ b/arch/arm/mach-omap2/powerdomains34xx.h
@@ -20,7 +20,7 @@
* the array in mach-omap2/powerdomains.h.
*/
-#include <mach/powerdomain.h>
+#include <plat/powerdomain.h>
#include "prcm-common.h"
#include "prm.h"
diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c
index ced555a4cd1a..b0d3ad05be2e 100644
--- a/arch/arm/mach-omap2/prcm.c
+++ b/arch/arm/mach-omap2/prcm.c
@@ -19,8 +19,8 @@
#include <linux/io.h>
#include <linux/delay.h>
-#include <mach/common.h>
-#include <mach/prcm.h>
+#include <plat/common.h>
+#include <plat/prcm.h>
#include "clock.h"
#include "prm.h"
diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h
index 03c467c35f54..a117f853ea39 100644
--- a/arch/arm/mach-omap2/prm.h
+++ b/arch/arm/mach-omap2/prm.h
@@ -17,11 +17,11 @@
#include "prcm-common.h"
#define OMAP2420_PRM_REGADDR(module, reg) \
- OMAP2_IO_ADDRESS(OMAP2420_PRM_BASE + (module) + (reg))
+ OMAP2_L4_IO_ADDRESS(OMAP2420_PRM_BASE + (module) + (reg))
#define OMAP2430_PRM_REGADDR(module, reg) \
- OMAP2_IO_ADDRESS(OMAP2430_PRM_BASE + (module) + (reg))
+ OMAP2_L4_IO_ADDRESS(OMAP2430_PRM_BASE + (module) + (reg))
#define OMAP34XX_PRM_REGADDR(module, reg) \
- OMAP2_IO_ADDRESS(OMAP3430_PRM_BASE + (module) + (reg))
+ OMAP2_L4_IO_ADDRESS(OMAP3430_PRM_BASE + (module) + (reg))
/*
* Architecture-specific global PRM registers
diff --git a/arch/arm/mach-omap2/sdram-micron-mt46h32m32lf-6.h b/arch/arm/mach-omap2/sdram-micron-mt46h32m32lf-6.h
index 02e1c2d4705f..a391b4939f74 100644
--- a/arch/arm/mach-omap2/sdram-micron-mt46h32m32lf-6.h
+++ b/arch/arm/mach-omap2/sdram-micron-mt46h32m32lf-6.h
@@ -14,7 +14,7 @@
#ifndef ARCH_ARM_MACH_OMAP2_SDRAM_MICRON_MT46H32M32LF
#define ARCH_ARM_MACH_OMAP2_SDRAM_MICRON_MT46H32M32LF
-#include <mach/sdrc.h>
+#include <plat/sdrc.h>
/* Micron MT46H32M32LF-6 */
/* XXX Using ARE = 0x1 (no autorefresh burst) -- can this be changed? */
diff --git a/arch/arm/mach-omap2/sdram-qimonda-hyb18m512160af-6.h b/arch/arm/mach-omap2/sdram-qimonda-hyb18m512160af-6.h
index 3751d293cb1f..0e518a72831f 100644
--- a/arch/arm/mach-omap2/sdram-qimonda-hyb18m512160af-6.h
+++ b/arch/arm/mach-omap2/sdram-qimonda-hyb18m512160af-6.h
@@ -14,7 +14,7 @@
#ifndef ARCH_ARM_MACH_OMAP2_SDRAM_QIMONDA_HYB18M512160AF6
#define ARCH_ARM_MACH_OMAP2_SDRAM_QIMONDA_HYB18M512160AF6
-#include <mach/sdrc.h>
+#include <plat/sdrc.h>
/* Qimonda HYB18M512160AF-6 */
static struct omap_sdrc_params hyb18m512160af6_sdrc_params[] = {
diff --git a/arch/arm/mach-omap2/sdrc.c b/arch/arm/mach-omap2/sdrc.c
index 9e3bd4fa7810..07000de48f34 100644
--- a/arch/arm/mach-omap2/sdrc.c
+++ b/arch/arm/mach-omap2/sdrc.c
@@ -23,13 +23,13 @@
#include <linux/clk.h>
#include <linux/io.h>
-#include <mach/common.h>
-#include <mach/clock.h>
-#include <mach/sram.h>
+#include <plat/common.h>
+#include <plat/clock.h>
+#include <plat/sram.h>
#include "prm.h"
-#include <mach/sdrc.h>
+#include <plat/sdrc.h>
#include "sdrc.h"
static struct omap_sdrc_params *sdrc_init_params_cs0, *sdrc_init_params_cs1;
diff --git a/arch/arm/mach-omap2/sdrc.h b/arch/arm/mach-omap2/sdrc.h
index 0837eda5f2b6..48207b018989 100644
--- a/arch/arm/mach-omap2/sdrc.h
+++ b/arch/arm/mach-omap2/sdrc.h
@@ -15,7 +15,7 @@
*/
#undef DEBUG
-#include <mach/sdrc.h>
+#include <plat/sdrc.h>
#ifndef __ASSEMBLER__
extern void __iomem *omap2_sdrc_base;
@@ -48,9 +48,12 @@ static inline u32 sms_read_reg(u16 reg)
return __raw_readl(OMAP_SMS_REGADDR(reg));
}
#else
-#define OMAP242X_SDRC_REGADDR(reg) OMAP2_IO_ADDRESS(OMAP2420_SDRC_BASE + (reg))
-#define OMAP243X_SDRC_REGADDR(reg) OMAP2_IO_ADDRESS(OMAP243X_SDRC_BASE + (reg))
-#define OMAP34XX_SDRC_REGADDR(reg) OMAP2_IO_ADDRESS(OMAP343X_SDRC_BASE + (reg))
+#define OMAP242X_SDRC_REGADDR(reg) \
+ OMAP2_L3_IO_ADDRESS(OMAP2420_SDRC_BASE + (reg))
+#define OMAP243X_SDRC_REGADDR(reg) \
+ OMAP2_L3_IO_ADDRESS(OMAP243X_SDRC_BASE + (reg))
+#define OMAP34XX_SDRC_REGADDR(reg) \
+ OMAP2_L3_IO_ADDRESS(OMAP343X_SDRC_BASE + (reg))
#endif /* __ASSEMBLER__ */
#endif
diff --git a/arch/arm/mach-omap2/sdrc2xxx.c b/arch/arm/mach-omap2/sdrc2xxx.c
index feaec7eaf6bd..0f4d27aef44d 100644
--- a/arch/arm/mach-omap2/sdrc2xxx.c
+++ b/arch/arm/mach-omap2/sdrc2xxx.c
@@ -24,13 +24,13 @@
#include <linux/clk.h>
#include <linux/io.h>
-#include <mach/common.h>
-#include <mach/clock.h>
-#include <mach/sram.h>
+#include <plat/common.h>
+#include <plat/clock.h>
+#include <plat/sram.h>
#include "prm.h"
#include "clock.h"
-#include <mach/sdrc.h>
+#include <plat/sdrc.h>
#include "sdrc.h"
/* Memory timing, DLL mode flags */
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index ae2186892c85..5c39d7a5c8ec 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -24,10 +24,10 @@
#include <linux/clk.h>
#include <linux/io.h>
-#include <mach/common.h>
-#include <mach/board.h>
-#include <mach/clock.h>
-#include <mach/control.h>
+#include <plat/common.h>
+#include <plat/board.h>
+#include <plat/clock.h>
+#include <plat/control.h>
#include "prm.h"
#include "pm.h"
@@ -73,7 +73,6 @@ static LIST_HEAD(uart_list);
static struct plat_serial8250_port serial_platform_data0[] = {
{
- .membase = OMAP2_IO_ADDRESS(OMAP_UART1_BASE),
.mapbase = OMAP_UART1_BASE,
.irq = 72,
.flags = UPF_BOOT_AUTOCONF,
@@ -87,7 +86,6 @@ static struct plat_serial8250_port serial_platform_data0[] = {
static struct plat_serial8250_port serial_platform_data1[] = {
{
- .membase = OMAP2_IO_ADDRESS(OMAP_UART2_BASE),
.mapbase = OMAP_UART2_BASE,
.irq = 73,
.flags = UPF_BOOT_AUTOCONF,
@@ -101,7 +99,6 @@ static struct plat_serial8250_port serial_platform_data1[] = {
static struct plat_serial8250_port serial_platform_data2[] = {
{
- .membase = OMAP2_IO_ADDRESS(OMAP_UART3_BASE),
.mapbase = OMAP_UART3_BASE,
.irq = 74,
.flags = UPF_BOOT_AUTOCONF,
@@ -126,7 +123,6 @@ static struct plat_serial8250_port serial_platform_data2[] = {
#ifdef CONFIG_ARCH_OMAP4
static struct plat_serial8250_port serial_platform_data3[] = {
{
- .membase = OMAP2_IO_ADDRESS(OMAP_UART4_BASE),
.mapbase = OMAP_UART4_BASE,
.irq = 70,
.flags = UPF_BOOT_AUTOCONF,
@@ -549,7 +545,7 @@ static inline void omap_uart_idle_init(struct omap_uart_state *uart) {}
#define DEV_CREATE_FILE(dev, attr)
#endif /* CONFIG_PM */
-static struct omap_uart_state omap_uart[OMAP_MAX_NR_PORTS] = {
+static struct omap_uart_state omap_uart[] = {
{
.pdev = {
.name = "serial8250",
@@ -599,12 +595,22 @@ void __init omap_serial_early_init(void)
* if not needed.
*/
- for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
+ for (i = 0; i < ARRAY_SIZE(omap_uart); 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;
+ /*
+ * Module 4KB + L4 interconnect 4KB
+ * Static mapping, never released
+ */
+ p->membase = ioremap(p->mapbase, SZ_8K);
+ if (!p->membase) {
+ printk(KERN_ERR "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)) {
@@ -641,7 +647,7 @@ void __init omap_serial_init(void)
{
int i;
- for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
+ for (i = 0; i < ARRAY_SIZE(omap_uart); i++) {
struct omap_uart_state *uart = &omap_uart[i];
struct platform_device *pdev = &uart->pdev;
struct device *dev = &pdev->dev;
diff --git a/arch/arm/mach-omap2/sleep24xx.S b/arch/arm/mach-omap2/sleep24xx.S
index 130aadbfa083..c7780cc8d919 100644
--- a/arch/arm/mach-omap2/sleep24xx.S
+++ b/arch/arm/mach-omap2/sleep24xx.S
@@ -29,7 +29,7 @@
#include <asm/assembler.h>
#include <mach/io.h>
-#include <mach/omap24xx.h>
+#include <plat/omap24xx.h>
#include "sdrc.h"
diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S
index e5e2553e79a6..6a749f2fea63 100644
--- a/arch/arm/mach-omap2/sleep34xx.S
+++ b/arch/arm/mach-omap2/sleep34xx.S
@@ -27,7 +27,7 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <mach/io.h>
-#include <mach/control.h>
+#include <plat/control.h>
#include "prm.h"
#include "sdrc.h"
diff --git a/arch/arm/mach-omap2/sram242x.S b/arch/arm/mach-omap2/sram242x.S
index 9b62208658bc..92e6e1a12af8 100644
--- a/arch/arm/mach-omap2/sram242x.S
+++ b/arch/arm/mach-omap2/sram242x.S
@@ -128,7 +128,7 @@ omap242x_sdi_prcm_voltctrl:
prcm_mask_val:
.word 0xFFFF3FFC
omap242x_sdi_timer_32ksynct_cr:
- .word OMAP2_IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010)
+ .word OMAP2_L4_IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010)
ENTRY(omap242x_sram_ddr_init_sz)
.word . - omap242x_sram_ddr_init
@@ -224,7 +224,7 @@ omap242x_srs_prcm_voltctrl:
ddr_prcm_mask_val:
.word 0xFFFF3FFC
omap242x_srs_timer_32ksynct:
- .word OMAP2_IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010)
+ .word OMAP2_L4_IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010)
ENTRY(omap242x_sram_reprogram_sdrc_sz)
.word . - omap242x_sram_reprogram_sdrc
diff --git a/arch/arm/mach-omap2/sram243x.S b/arch/arm/mach-omap2/sram243x.S
index df2cd9277c00..ab4973695c71 100644
--- a/arch/arm/mach-omap2/sram243x.S
+++ b/arch/arm/mach-omap2/sram243x.S
@@ -128,7 +128,7 @@ omap243x_sdi_prcm_voltctrl:
prcm_mask_val:
.word 0xFFFF3FFC
omap243x_sdi_timer_32ksynct_cr:
- .word OMAP2_IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010)
+ .word OMAP2_L4_IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010)
ENTRY(omap243x_sram_ddr_init_sz)
.word . - omap243x_sram_ddr_init
@@ -224,7 +224,7 @@ omap243x_srs_prcm_voltctrl:
ddr_prcm_mask_val:
.word 0xFFFF3FFC
omap243x_srs_timer_32ksynct:
- .word OMAP2_IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010)
+ .word OMAP2_L4_IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010)
ENTRY(omap243x_sram_reprogram_sdrc_sz)
.word . - omap243x_sram_reprogram_sdrc
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c
index e2338c0aebcf..df2b7094de98 100644
--- a/arch/arm/mach-omap2/timer-gp.c
+++ b/arch/arm/mach-omap2/timer-gp.c
@@ -37,7 +37,7 @@
#include <linux/clockchips.h>
#include <asm/mach/time.h>
-#include <mach/dmtimer.h>
+#include <plat/dmtimer.h>
#include <asm/localtimer.h>
/* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
@@ -231,7 +231,8 @@ static void __init omap2_gp_clocksource_init(void)
static void __init omap2_gp_timer_init(void)
{
#ifdef CONFIG_LOCAL_TIMERS
- twd_base = OMAP2_IO_ADDRESS(OMAP44XX_LOCAL_TWD_BASE);
+ twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_256);
+ BUG_ON(!twd_base);
#endif
omap_dm_timer_init();
diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c
index 1145a2562b0f..a80441dd19b8 100644
--- a/arch/arm/mach-omap2/usb-musb.c
+++ b/arch/arm/mach-omap2/usb-musb.c
@@ -28,8 +28,8 @@
#include <mach/hardware.h>
#include <mach/irqs.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
#ifdef CONFIG_USB_MUSB_SOC
diff --git a/arch/arm/mach-omap2/usb-tusb6010.c b/arch/arm/mach-omap2/usb-tusb6010.c
index 8622c24cd270..10a2013c1104 100644
--- a/arch/arm/mach-omap2/usb-tusb6010.c
+++ b/arch/arm/mach-omap2/usb-tusb6010.c
@@ -16,8 +16,8 @@
#include <linux/usb/musb.h>
-#include <mach/gpmc.h>
-#include <mach/mux.h>
+#include <plat/gpmc.h>
+#include <plat/mux.h>
static u8 async_cs, sync_cs;
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index a6f8eab14ba5..e62572dc2d71 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -31,216 +31,144 @@ endmenu
endif
-config ARCH_GUMSTIX
- bool "Gumstix XScale 255 boards"
- select PXA25x
- help
- Say Y here if you intend to run this kernel on
- Basix, Connex, ws-200ax, ws-400ax systems
-
-choice
- prompt "Gumstix Carrier/Expansion Board"
- depends on ARCH_GUMSTIX
-
-config GUMSTIX_AM200EPD
- bool "Enable AM200EPD board support"
-
-config GUMSTIX_AM300EPD
- bool "Enable AM300EPD board support"
-
-endchoice
-
-config MACH_INTELMOTE2
- bool "Intel Mote 2 Platform"
- select PXA27x
- select IWMMXT
- select PXA_HAVE_BOARD_IRQS
-
-config MACH_STARGATE2
- bool "Intel Stargate 2 Platform"
- select PXA27x
- select IWMMXT
- select PXA_HAVE_BOARD_IRQS
+comment "Intel/Marvell Dev Platforms (sorted by hardware release time)"
config ARCH_LUBBOCK
- bool "Intel DBPXA250 Development Platform"
+ bool "Intel DBPXA250 Development Platform (aka Lubbock)"
select PXA25x
select SA1111
select PXA_HAVE_BOARD_IRQS
-config MACH_LOGICPD_PXA270
- bool "LogicPD PXA270 Card Engine Development Platform"
+config MACH_MAINSTONE
+ bool "Intel HCDDBBVA0 Development Platform (aka Mainstone)"
select PXA27x
select HAVE_PWM
select PXA_HAVE_BOARD_IRQS
-config MACH_MAINSTONE
- bool "Intel HCDDBBVA0 Development Platform"
- select PXA27x
+config MACH_ZYLONITE
+ bool "PXA3xx Development Platform (aka Zylonite)"
+ select PXA3xx
+ select PXA_SSP
select HAVE_PWM
select PXA_HAVE_BOARD_IRQS
-config MACH_MP900C
- bool "Nec Mobilepro 900/c"
+config MACH_LITTLETON
+ bool "PXA3xx Form Factor Platform (aka Littleton)"
+ select PXA3xx
+ select PXA_SSP
+
+config MACH_TAVOREVB
+ bool "PXA930 Evaluation Board (aka TavorEVB)"
+ select PXA3xx
+ select CPU_PXA930
+
+config MACH_SAAR
+ bool "PXA930 Handheld Platform (aka SAAR)"
+ select PXA3xx
+ select CPU_PXA930
+
+comment "Third Party Dev Platforms (sorted by vendor name)"
+
+config ARCH_PXA_IDP
+ bool "Accelent Xscale IDP"
select PXA25x
+config ARCH_VIPER
+ bool "Arcom/Eurotech VIPER SBC"
+ select PXA25x
+ select ISA
+ select I2C_GPIO
+ select HAVE_PWM
+ select PXA_HAVE_BOARD_IRQS
+ select PXA_HAVE_ISA_IRQS
+
config MACH_BALLOON3
bool "Balloon 3 board"
select PXA27x
select IWMMXT
select PXA_HAVE_BOARD_IRQS
-config ARCH_PXA_IDP
- bool "Accelent Xscale IDP"
- select PXA25x
-
-config PXA_SHARPSL
- bool "SHARP Zaurus SL-5600, SL-C7xx and SL-Cxx00 Models"
- select SHARP_SCOOP
- select SHARP_PARAM
+config MACH_CSB726
+ bool "Enable Cogent CSB726 System On a Module"
+ select PXA27x
+ select IWMMXT
help
- Say Y here if you intend to run this kernel on a
- Sharp Zaurus SL-5600 (Poodle), SL-C700 (Corgi),
- SL-C750 (Shepherd), SL-C760 (Husky), SL-C1000 (Akita),
- SL-C3000 (Spitz), SL-C3100 (Borzoi) or SL-C6000x (Tosa)
- handheld computer.
-
-config SHARPSL_PM
- bool
- select APM_EMULATION
+ Say Y here if you intend to run this kernel on a Cogent
+ CSB726 System On Module.
-config CORGI_SSP_DEPRECATED
- bool
- select PXA_SSP
- help
- This option will include corgi_ssp.c and corgi_lcd.c
- that corgi_ts.c and other legacy drivers (corgi_bl.c
- and sharpsl_pm.c) may depend on.
+config CSB726_CSB701
+ bool "Enable support for CSB701 baseboard"
+ depends on MACH_CSB726
-config MACH_POODLE
- bool "Enable Sharp SL-5600 (Poodle) Support"
- depends on PXA_SHARPSL
+config MACH_ARMCORE
+ bool "CompuLab CM-X255/CM-X270 modules"
+ select PXA27x
+ select IWMMXT
select PXA25x
- select SHARP_LOCOMO
select PXA_SSP
-config MACH_CORGI
- bool "Enable Sharp SL-C700 (Corgi) Support"
- depends on PXA_SHARPSL
- select PXA25x
- select PXA_SHARP_C7xx
-
-config MACH_SHEPHERD
- bool "Enable Sharp SL-C750 (Shepherd) Support"
- depends on PXA_SHARPSL
- select PXA25x
- select PXA_SHARP_C7xx
-
-config MACH_HUSKY
- bool "Enable Sharp SL-C760 (Husky) Support"
- depends on PXA_SHARPSL
- select PXA25x
- select PXA_SHARP_C7xx
-
-config MACH_AKITA
- bool "Enable Sharp SL-1000 (Akita) Support"
- depends on PXA_SHARPSL
+config MACH_EM_X270
+ bool "CompuLab EM-x270 platform"
select PXA27x
- select PXA_SHARP_Cxx00
- select MACH_SPITZ
- select I2C
- select I2C_PXA
-config MACH_SPITZ
- bool "Enable Sharp Zaurus SL-3000 (Spitz) Support"
- depends on PXA_SHARPSL
- select PXA27x
- select PXA_SHARP_Cxx00
-
-config MACH_BORZOI
- bool "Enable Sharp Zaurus SL-3100 (Borzoi) Support"
- depends on PXA_SHARPSL
+config MACH_EXEDA
+ bool "CompuLab eXeda platform"
select PXA27x
- select PXA_SHARP_Cxx00
-config MACH_TOSA
- bool "Enable Sharp SL-6000x (Tosa) Support"
- depends on PXA_SHARPSL
- select PXA25x
- select PXA_HAVE_BOARD_IRQS
+config MACH_CM_X300
+ bool "CompuLab CM-X300 modules"
+ select PXA3xx
+ select CPU_PXA300
-config ARCH_VIPER
- bool "Arcom/Eurotech VIPER SBC"
+config ARCH_GUMSTIX
+ bool "Gumstix XScale 255 boards"
select PXA25x
- select ISA
- select I2C_GPIO
- select HAVE_PWM
- select PXA_HAVE_BOARD_IRQS
- select PXA_HAVE_ISA_IRQS
+ help
+ Say Y here if you intend to run this kernel on
+ Basix, Connex, ws-200ax, ws-400ax systems
-config ARCH_PXA_ESERIES
- bool "PXA based Toshiba e-series PDAs"
- select PXA25x
- select PXA_HAVE_BOARD_IRQS
+choice
+ prompt "Gumstix Carrier/Expansion Board"
+ depends on ARCH_GUMSTIX
-config MACH_E330
- bool "Toshiba e330"
- default y
- depends on ARCH_PXA_ESERIES
- help
- Say Y here if you intend to run this kernel on a Toshiba
- e330 family PDA.
+config GUMSTIX_AM200EPD
+ bool "Enable AM200EPD board support"
-config MACH_E350
- bool "Toshiba e350"
- default y
- depends on ARCH_PXA_ESERIES
- help
- Say Y here if you intend to run this kernel on a Toshiba
- e350 family PDA.
+config GUMSTIX_AM300EPD
+ bool "Enable AM300EPD board support"
-config MACH_E740
- bool "Toshiba e740"
- default y
- depends on ARCH_PXA_ESERIES
- select FB_W100
- help
- Say Y here if you intend to run this kernel on a Toshiba
- e740 family PDA.
+endchoice
-config MACH_E750
- bool "Toshiba e750"
- default y
- depends on ARCH_PXA_ESERIES
- select FB_W100
- help
- Say Y here if you intend to run this kernel on a Toshiba
- e750 family PDA.
+config MACH_INTELMOTE2
+ bool "Intel Mote 2 Platform"
+ select PXA27x
+ select IWMMXT
+ select PXA_HAVE_BOARD_IRQS
-config MACH_E400
- bool "Toshiba e400"
- default y
- depends on ARCH_PXA_ESERIES
- help
- Say Y here if you intend to run this kernel on a Toshiba
- e400 family PDA.
+config MACH_STARGATE2
+ bool "Intel Stargate 2 Platform"
+ select PXA27x
+ select IWMMXT
+ select PXA_HAVE_BOARD_IRQS
-config MACH_E800
- bool "Toshiba e800"
- default y
- depends on ARCH_PXA_ESERIES
- select FB_W100
+config MACH_XCEP
+ bool "Iskratel Electronics XCEP"
+ select PXA25x
+ select MTD
+ select MTD_PARTITIONS
+ select MTD_PHYSMAP
+ select MTD_CFI_INTELEXT
+ select MTD_CFI
+ select MTD_CHAR
+ select SMC91X
+ select PXA_SSP
help
- Say Y here if you intend to run this kernel on a Toshiba
- e800 family PDA.
+ PXA255 based Single Board Computer with SMC 91C111 ethernet chip and 64 MB of flash.
+ Tuned for usage in Libera instruments for particle accelerators.
config TRIZEPS_PXA
bool "PXA based Keith und Koep Trizeps DIMM-Modules"
-config MACH_H5000
- bool "HP iPAQ h5000"
- select PXA25x
-
config MACH_TRIZEPS4
bool "Keith und Koep Trizeps4 DIMM-Module"
depends on TRIZEPS_PXA
@@ -274,13 +202,38 @@ config TRIZEPS_PCMCIA
help
Enable PCMCIA support for Trizeps modules
-config MACH_EM_X270
- bool "CompuLab EM-x270 platform"
+config MACH_LOGICPD_PXA270
+ bool "LogicPD PXA270 Card Engine Development Platform"
select PXA27x
+ select HAVE_PWM
+ select PXA_HAVE_BOARD_IRQS
-config MACH_EXEDA
- bool "CompuLab eXeda platform"
+config MACH_PCM027
+ bool "Phytec phyCORE-PXA270 CPU module (PCM-027)"
select PXA27x
+ select IWMMXT
+ select PXA_SSP
+ select PXA_HAVE_BOARD_IRQS
+
+config MACH_PCM990_BASEBOARD
+ bool "PHYTEC PCM-990 development board"
+ select HAVE_PWM
+ depends on MACH_PCM027
+
+choice
+ prompt "display on pcm990"
+ depends on MACH_PCM990_BASEBOARD
+
+config PCM990_DISPLAY_SHARP
+ bool "sharp lq084v1dg21 stn display"
+
+config PCM990_DISPLAY_NEC
+ bool "nec nl6448bc20_18d tft display"
+
+config PCM990_DISPLAY_NONE
+ bool "no display"
+
+endchoice
config MACH_COLIBRI
bool "Toradex Colibri PXA270"
@@ -296,39 +249,7 @@ config MACH_COLIBRI320
select PXA3xx
select CPU_PXA320
-config MACH_ZYLONITE
- bool "PXA3xx Development Platform (aka Zylonite)"
- select PXA3xx
- select PXA_SSP
- select HAVE_PWM
- select PXA_HAVE_BOARD_IRQS
-
-config MACH_LITTLETON
- bool "PXA3xx Form Factor Platform (aka Littleton)"
- select PXA3xx
- select PXA_SSP
-
-config MACH_TAVOREVB
- bool "PXA930 Evaluation Board (aka TavorEVB)"
- select PXA3xx
- select CPU_PXA930
-
-config MACH_SAAR
- bool "PXA930 Handheld Platform (aka SAAR)"
- select PXA3xx
- select CPU_PXA930
-
-config MACH_ARMCORE
- bool "CompuLab CM-X255/CM-X270 modules"
- select PXA27x
- select IWMMXT
- select PXA25x
- select PXA_SSP
-
-config MACH_CM_X300
- bool "CompuLab CM-X300 modules"
- select PXA3xx
- select CPU_PXA300
+comment "End-user Products (sorted by vendor name)"
config MACH_H4700
bool "HP iPAQ hx4700"
@@ -338,6 +259,15 @@ config MACH_H4700
select HAVE_PWM
select PXA_HAVE_BOARD_IRQS
+config MACH_H5000
+ bool "HP iPAQ h5000"
+ select PXA25x
+
+config MACH_HIMALAYA
+ bool "HTC Himalaya Support"
+ select CPU_PXA26x
+ select FB_W100
+
config MACH_MAGICIAN
bool "Enable HTC Magician Support"
select PXA27x
@@ -346,11 +276,6 @@ config MACH_MAGICIAN
select HAVE_PWM
select PXA_HAVE_BOARD_IRQS
-config MACH_HIMALAYA
- bool "HTC Himalaya Support"
- select CPU_PXA26x
- select FB_W100
-
config MACH_MIOA701
bool "Mitac Mio A701 Support"
select PXA27x
@@ -362,13 +287,47 @@ config MACH_MIOA701
MIO A701. Currently there is only basic support
for this PDA.
-config MACH_PCM027
- bool "Phytec phyCORE-PXA270 CPU module (PCM-027)"
+config PXA_EZX
+ bool "Motorola EZX Platform"
select PXA27x
select IWMMXT
- select PXA_SSP
+ select HAVE_PWM
select PXA_HAVE_BOARD_IRQS
+config MACH_EZX_A780
+ bool "Motorola EZX A780"
+ default y
+ depends on PXA_EZX
+
+config MACH_EZX_E680
+ bool "Motorola EZX E680"
+ default y
+ depends on PXA_EZX
+
+config MACH_EZX_A1200
+ bool "Motorola EZX A1200"
+ default y
+ depends on PXA_EZX
+
+config MACH_EZX_A910
+ bool "Motorola EZX A910"
+ default y
+ depends on PXA_EZX
+
+config MACH_EZX_E6
+ bool "Motorola EZX E6"
+ default y
+ depends on PXA_EZX
+
+config MACH_EZX_E2
+ bool "Motorola EZX E2"
+ default y
+ depends on PXA_EZX
+
+config MACH_MP900C
+ bool "Nec Mobilepro 900/c"
+ select PXA25x
+
config ARCH_PXA_PALM
bool "PXA based Palm PDAs"
select HAVE_PWM
@@ -421,109 +380,172 @@ config MACH_PALMZ72
Say Y here if you intend to run this kernel on Palm Zire 72
handheld computer.
-config MACH_TREO680
- bool "Palm Treo 680"
+config MACH_PALMLD
+ bool "Palm LifeDrive"
default y
depends on ARCH_PXA_PALM
select PXA27x
select IWMMXT
help
- Say Y here if you intend to run this kernel on Palm Treo 680
+ Say Y here if you intend to run this kernel on a Palm LifeDrive
+ handheld computer.
+
+config PALM_TREO
+ bool
+ depends on ARCH_PXA_PALM
+
+config MACH_CENTRO
+ bool "Palm Centro 685 (GSM)"
+ default y
+ depends on ARCH_PXA_PALM
+ select PXA27x
+ select IWMMXT
+ select PALM_TREO
+ help
+ Say Y here if you intend to run this kernel on Palm Centro 685 (GSM)
smartphone.
-config MACH_PALMLD
- bool "Palm LifeDrive"
+config MACH_TREO680
+ bool "Palm Treo 680"
default y
depends on ARCH_PXA_PALM
select PXA27x
select IWMMXT
+ select PALM_TREO
help
- Say Y here if you intend to run this kernel on a Palm LifeDrive
+ Say Y here if you intend to run this kernel on Palm Treo 680
+ smartphone.
+
+config PXA_SHARPSL
+ bool "SHARP Zaurus SL-5600, SL-C7xx and SL-Cxx00 Models"
+ select SHARP_SCOOP
+ select SHARP_PARAM
+ help
+ Say Y here if you intend to run this kernel on a
+ Sharp Zaurus SL-5600 (Poodle), SL-C700 (Corgi),
+ SL-C750 (Shepherd), SL-C760 (Husky), SL-C1000 (Akita),
+ SL-C3000 (Spitz), SL-C3100 (Borzoi) or SL-C6000x (Tosa)
handheld computer.
-config MACH_PCM990_BASEBOARD
- bool "PHYTEC PCM-990 development board"
- select HAVE_PWM
- depends on MACH_PCM027
+config SHARPSL_PM
+ bool
+ select APM_EMULATION
-choice
- prompt "display on pcm990"
- depends on MACH_PCM990_BASEBOARD
+config CORGI_SSP_DEPRECATED
+ bool
+ select PXA_SSP
+ help
+ This option will include corgi_ssp.c and corgi_lcd.c
+ that corgi_ts.c and other legacy drivers (corgi_bl.c
+ and sharpsl_pm.c) may depend on.
-config PCM990_DISPLAY_SHARP
- bool "sharp lq084v1dg21 stn display"
+config MACH_POODLE
+ bool "Enable Sharp SL-5600 (Poodle) Support"
+ depends on PXA_SHARPSL
+ select PXA25x
+ select SHARP_LOCOMO
+ select PXA_SSP
-config PCM990_DISPLAY_NEC
- bool "nec nl6448bc20_18d tft display"
+config MACH_CORGI
+ bool "Enable Sharp SL-C700 (Corgi) Support"
+ depends on PXA_SHARPSL
+ select PXA25x
+ select PXA_SHARP_C7xx
-config PCM990_DISPLAY_NONE
- bool "no display"
+config MACH_SHEPHERD
+ bool "Enable Sharp SL-C750 (Shepherd) Support"
+ depends on PXA_SHARPSL
+ select PXA25x
+ select PXA_SHARP_C7xx
-endchoice
+config MACH_HUSKY
+ bool "Enable Sharp SL-C760 (Husky) Support"
+ depends on PXA_SHARPSL
+ select PXA25x
+ select PXA_SHARP_C7xx
-config MACH_CSB726
- bool "Enable Cogent CSB726 System On a Module"
+config MACH_AKITA
+ bool "Enable Sharp SL-1000 (Akita) Support"
+ depends on PXA_SHARPSL
select PXA27x
- select IWMMXT
- help
- Say Y here if you intend to run this kernel on a Cogent
- CSB726 System On Module.
+ select PXA_SHARP_Cxx00
+ select MACH_SPITZ
+ select I2C
+ select I2C_PXA
-config CSB726_CSB701
- bool "Enable supprot for CSB701 baseboard"
- depends on MACH_CSB726
+config MACH_SPITZ
+ bool "Enable Sharp Zaurus SL-3000 (Spitz) Support"
+ depends on PXA_SHARPSL
+ select PXA27x
+ select PXA_SHARP_Cxx00
-config PXA_EZX
- bool "Motorola EZX Platform"
+config MACH_BORZOI
+ bool "Enable Sharp Zaurus SL-3100 (Borzoi) Support"
+ depends on PXA_SHARPSL
select PXA27x
- select IWMMXT
- select HAVE_PWM
+ select PXA_SHARP_Cxx00
+
+config MACH_TOSA
+ bool "Enable Sharp SL-6000x (Tosa) Support"
+ depends on PXA_SHARPSL
+ select PXA25x
select PXA_HAVE_BOARD_IRQS
-config MACH_EZX_A780
- bool "Motorola EZX A780"
- default y
- depends on PXA_EZX
+config ARCH_PXA_ESERIES
+ bool "PXA based Toshiba e-series PDAs"
+ select PXA25x
+ select PXA_HAVE_BOARD_IRQS
-config MACH_EZX_E680
- bool "Motorola EZX E680"
+config MACH_E330
+ bool "Toshiba e330"
default y
- depends on PXA_EZX
+ depends on ARCH_PXA_ESERIES
+ help
+ Say Y here if you intend to run this kernel on a Toshiba
+ e330 family PDA.
-config MACH_EZX_A1200
- bool "Motorola EZX A1200"
+config MACH_E350
+ bool "Toshiba e350"
default y
- depends on PXA_EZX
+ depends on ARCH_PXA_ESERIES
+ help
+ Say Y here if you intend to run this kernel on a Toshiba
+ e350 family PDA.
-config MACH_EZX_A910
- bool "Motorola EZX A910"
+config MACH_E740
+ bool "Toshiba e740"
default y
- depends on PXA_EZX
+ depends on ARCH_PXA_ESERIES
+ select FB_W100
+ help
+ Say Y here if you intend to run this kernel on a Toshiba
+ e740 family PDA.
-config MACH_EZX_E6
- bool "Motorola EZX E6"
+config MACH_E750
+ bool "Toshiba e750"
default y
- depends on PXA_EZX
+ depends on ARCH_PXA_ESERIES
+ select FB_W100
+ help
+ Say Y here if you intend to run this kernel on a Toshiba
+ e750 family PDA.
-config MACH_EZX_E2
- bool "Motorola EZX E2"
+config MACH_E400
+ bool "Toshiba e400"
default y
- depends on PXA_EZX
+ depends on ARCH_PXA_ESERIES
+ help
+ Say Y here if you intend to run this kernel on a Toshiba
+ e400 family PDA.
-config MACH_XCEP
- bool "Iskratel Electronics XCEP"
- select PXA25x
- select MTD
- select MTD_PARTITIONS
- select MTD_PHYSMAP
- select MTD_CFI_INTELEXT
- select MTD_CFI
- select MTD_CHAR
- select SMC91X
- select PXA_SSP
+config MACH_E800
+ bool "Toshiba e800"
+ default y
+ depends on ARCH_PXA_ESERIES
+ select FB_W100
help
- PXA255 based Single Board Computer with SMC 91C111 ethernet chip and 64 MB of flash.
- Tuned for usage in Libera instruments for particle accelerators.
+ Say Y here if you intend to run this kernel on a Toshiba
+ e800 family PDA.
endmenu
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index f10e152bfc27..cdaf88831c27 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -24,33 +24,66 @@ obj-$(CONFIG_CPU_PXA300) += pxa300.o
obj-$(CONFIG_CPU_PXA320) += pxa320.o
obj-$(CONFIG_CPU_PXA930) += pxa930.o
-# Specific board support
-obj-$(CONFIG_ARCH_GUMSTIX) += gumstix.o
-obj-$(CONFIG_GUMSTIX_AM200EPD) += am200epd.o
-obj-$(CONFIG_GUMSTIX_AM300EPD) += am300epd.o
+# NOTE: keep the order of boards in accordance to their order in Kconfig
+
+# Intel/Marvell Dev Platforms
obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
-obj-$(CONFIG_MACH_LOGICPD_PXA270) += lpd270.o
obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o
-obj-$(CONFIG_MACH_BALLOON3) += balloon3.o
-obj-$(CONFIG_MACH_MP900C) += mp900.o
+ifeq ($(CONFIG_MACH_ZYLONITE),y)
+ obj-y += zylonite.o
+ obj-$(CONFIG_CPU_PXA300) += zylonite_pxa300.o
+ obj-$(CONFIG_CPU_PXA320) += zylonite_pxa320.o
+endif
+obj-$(CONFIG_MACH_LITTLETON) += littleton.o
+obj-$(CONFIG_MACH_TAVOREVB) += tavorevb.o
+obj-$(CONFIG_MACH_SAAR) += saar.o
+
+# 3rd Party Dev Platforms
obj-$(CONFIG_ARCH_PXA_IDP) += idp.o
+obj-$(CONFIG_ARCH_VIPER) += viper.o
+obj-$(CONFIG_MACH_BALLOON3) += balloon3.o
+obj-$(CONFIG_MACH_CSB726) += csb726.o
+obj-$(CONFIG_CSB726_CSB701) += csb701.o
+obj-$(CONFIG_MACH_ARMCORE) += cm-x2xx.o cm-x255.o cm-x270.o
+ifeq ($(CONFIG_PCI),y)
+obj-$(CONFIG_MACH_ARMCORE) += cm-x2xx-pci.o
+endif
+obj-$(CONFIG_MACH_EM_X270) += em-x270.o
+obj-$(CONFIG_MACH_CM_X300) += cm-x300.o
+obj-$(CONFIG_ARCH_GUMSTIX) += gumstix.o
+obj-$(CONFIG_GUMSTIX_AM200EPD) += am200epd.o
+obj-$(CONFIG_GUMSTIX_AM300EPD) += am300epd.o
+obj-$(CONFIG_MACH_INTELMOTE2) += imote2.o
+obj-$(CONFIG_MACH_STARGATE2) += stargate2.o
+obj-$(CONFIG_MACH_XCEP) += xcep.o
obj-$(CONFIG_MACH_TRIZEPS4) += trizeps4.o
+obj-$(CONFIG_MACH_LOGICPD_PXA270) += lpd270.o
+obj-$(CONFIG_MACH_PCM027) += pcm027.o
+obj-$(CONFIG_MACH_PCM990_BASEBOARD) += pcm990-baseboard.o
obj-$(CONFIG_MACH_COLIBRI) += colibri-pxa270.o
obj-$(CONFIG_MACH_COLIBRI300) += colibri-pxa3xx.o colibri-pxa300.o
obj-$(CONFIG_MACH_COLIBRI320) += colibri-pxa3xx.o colibri-pxa320.o
+
+# End-user Products
+obj-$(CONFIG_MACH_H4700) += hx4700.o
obj-$(CONFIG_MACH_H5000) += h5000.o
+obj-$(CONFIG_MACH_HIMALAYA) += himalaya.o
+obj-$(CONFIG_MACH_MAGICIAN) += magician.o
+obj-$(CONFIG_MACH_MIOA701) += mioa701.o mioa701_bootresume.o
+obj-$(CONFIG_PXA_EZX) += ezx.o
+obj-$(CONFIG_MACH_MP900C) += mp900.o
+obj-$(CONFIG_MACH_PALMTE2) += palmte2.o
+obj-$(CONFIG_MACH_PALMTC) += palmtc.o
+obj-$(CONFIG_MACH_PALMT5) += palmt5.o
+obj-$(CONFIG_MACH_PALMTX) += palmtx.o
+obj-$(CONFIG_MACH_PALMZ72) += palmz72.o
+obj-$(CONFIG_MACH_PALMLD) += palmld.o
+obj-$(CONFIG_PALM_TREO) += palmtreo.o
obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o sharpsl_pm.o corgi_pm.o
obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o sharpsl_pm.o spitz_pm.o
obj-$(CONFIG_CORGI_SSP_DEPRECATED) += corgi_ssp.o corgi_lcd.o
obj-$(CONFIG_MACH_POODLE) += poodle.o
-obj-$(CONFIG_MACH_PCM027) += pcm027.o
-obj-$(CONFIG_MACH_PCM990_BASEBOARD) += pcm990-baseboard.o
obj-$(CONFIG_MACH_TOSA) += tosa.o
-obj-$(CONFIG_MACH_EM_X270) += em-x270.o
-obj-$(CONFIG_MACH_H4700) += hx4700.o
-obj-$(CONFIG_MACH_MAGICIAN) += magician.o
-obj-$(CONFIG_MACH_HIMALAYA) += himalaya.o
-obj-$(CONFIG_MACH_MIOA701) += mioa701.o mioa701_bootresume.o
obj-$(CONFIG_ARCH_PXA_ESERIES) += eseries.o
obj-$(CONFIG_MACH_E330) += e330.o
obj-$(CONFIG_MACH_E350) += e350.o
@@ -58,34 +91,6 @@ obj-$(CONFIG_MACH_E740) += e740.o
obj-$(CONFIG_MACH_E750) += e750.o
obj-$(CONFIG_MACH_E400) += e400.o
obj-$(CONFIG_MACH_E800) += e800.o
-obj-$(CONFIG_MACH_PALMTE2) += palmte2.o
-obj-$(CONFIG_MACH_PALMTC) += palmtc.o
-obj-$(CONFIG_MACH_PALMT5) += palmt5.o
-obj-$(CONFIG_MACH_PALMTX) += palmtx.o
-obj-$(CONFIG_MACH_PALMLD) += palmld.o
-obj-$(CONFIG_MACH_PALMZ72) += palmz72.o
-obj-$(CONFIG_MACH_TREO680) += treo680.o
-obj-$(CONFIG_ARCH_VIPER) += viper.o
-
-ifeq ($(CONFIG_MACH_ZYLONITE),y)
- obj-y += zylonite.o
- obj-$(CONFIG_CPU_PXA300) += zylonite_pxa300.o
- obj-$(CONFIG_CPU_PXA320) += zylonite_pxa320.o
-endif
-obj-$(CONFIG_MACH_LITTLETON) += littleton.o
-obj-$(CONFIG_MACH_TAVOREVB) += tavorevb.o
-obj-$(CONFIG_MACH_SAAR) += saar.o
-
-obj-$(CONFIG_MACH_ARMCORE) += cm-x2xx.o cm-x255.o cm-x270.o
-obj-$(CONFIG_MACH_CM_X300) += cm-x300.o
-obj-$(CONFIG_PXA_EZX) += ezx.o
-
-obj-$(CONFIG_MACH_XCEP) += xcep.o
-
-obj-$(CONFIG_MACH_INTELMOTE2) += imote2.o
-obj-$(CONFIG_MACH_STARGATE2) += stargate2.o
-obj-$(CONFIG_MACH_CSB726) += csb726.o
-obj-$(CONFIG_CSB726_CSB701) += csb701.o
# Support for blinky lights
led-y := leds.o
@@ -95,8 +100,4 @@ led-$(CONFIG_ARCH_PXA_IDP) += leds-idp.o
obj-$(CONFIG_LEDS) += $(led-y)
-ifeq ($(CONFIG_PCI),y)
-obj-$(CONFIG_MACH_ARMCORE) += cm-x2xx-pci.o
-endif
-
obj-$(CONFIG_TOSA_BT) += tosa-bt.o
diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
index aac2cda60e09..06552ca91814 100644
--- a/arch/arm/mach-pxa/cm-x300.c
+++ b/arch/arm/mach-pxa/cm-x300.c
@@ -35,7 +35,7 @@
#include <mach/mmc.h>
#include <mach/ohci.h>
#include <plat/i2c.h>
-#include <mach/pxa3xx_nand.h>
+#include <plat/pxa3xx_nand.h>
#include <asm/mach/map.h>
@@ -43,10 +43,10 @@
#define CM_X300_ETH_PHYS 0x08000010
-#define GPIO82_MMC2_IRQ (82)
-#define GPIO85_MMC2_WP (85)
+#define GPIO82_MMC_IRQ (82)
+#define GPIO85_MMC_WP (85)
-#define CM_X300_MMC2_IRQ IRQ_GPIO(GPIO82_MMC2_IRQ)
+#define CM_X300_MMC_IRQ IRQ_GPIO(GPIO82_MMC_IRQ)
#define GPIO95_RTC_CS (95)
#define GPIO96_RTC_WR (96)
@@ -292,37 +292,37 @@ static inline void cm_x300_init_nand(void) {}
#endif
#if defined(CONFIG_MMC) || defined(CONFIG_MMC_MODULE)
-/* The first MMC slot of CM-X300 is hardwired to Libertas card and has
+static struct pxamci_platform_data cm_x300_mci_platform_data = {
+ .detect_delay = 20,
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .gpio_card_detect = GPIO82_MMC_IRQ,
+ .gpio_card_ro = GPIO85_MMC_WP,
+ .gpio_power = -1,
+};
+
+/* The second MMC slot of CM-X300 is hardwired to Libertas card and has
no detection/ro pins */
-static int cm_x300_mci_init(struct device *dev,
- irq_handler_t cm_x300_detect_int,
- void *data)
+static int cm_x300_mci2_init(struct device *dev,
+ irq_handler_t cm_x300_detect_int,
+ void *data)
{
return 0;
}
-static void cm_x300_mci_exit(struct device *dev, void *data)
+static void cm_x300_mci2_exit(struct device *dev, void *data)
{
}
-static struct pxamci_platform_data cm_x300_mci_platform_data = {
+static struct pxamci_platform_data cm_x300_mci2_platform_data = {
.detect_delay = 20,
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .init = cm_x300_mci_init,
- .exit = cm_x300_mci_exit,
+ .init = cm_x300_mci2_init,
+ .exit = cm_x300_mci2_exit,
.gpio_card_detect = -1,
.gpio_card_ro = -1,
.gpio_power = -1,
};
-static struct pxamci_platform_data cm_x300_mci2_platform_data = {
- .detect_delay = 20,
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .gpio_card_detect = GPIO82_MMC2_IRQ,
- .gpio_card_ro = GPIO85_MMC2_WP,
- .gpio_power = -1,
-};
-
static void __init cm_x300_init_mmc(void)
{
pxa_set_mci_info(&cm_x300_mci_platform_data);
diff --git a/arch/arm/mach-pxa/colibri-pxa3xx.c b/arch/arm/mach-pxa/colibri-pxa3xx.c
index efebaf4d734d..e6c0a2287eb8 100644
--- a/arch/arm/mach-pxa/colibri-pxa3xx.c
+++ b/arch/arm/mach-pxa/colibri-pxa3xx.c
@@ -25,7 +25,7 @@
#include <mach/colibri.h>
#include <mach/mmc.h>
#include <mach/pxafb.h>
-#include <mach/pxa3xx_nand.h>
+#include <plat/pxa3xx_nand.h>
#include "generic.h"
#include "devices.h"
diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c
index 46fabe1cca11..e2b427fa55e5 100644
--- a/arch/arm/mach-pxa/devices.c
+++ b/arch/arm/mach-pxa/devices.c
@@ -8,13 +8,13 @@
#include <mach/pxafb.h>
#include <mach/mmc.h>
#include <mach/irda.h>
-#include <plat/i2c.h>
#include <mach/ohci.h>
#include <mach/pxa27x_keypad.h>
#include <mach/pxa2xx_spi.h>
#include <mach/camera.h>
#include <mach/audio.h>
-#include <mach/pxa3xx_nand.h>
+#include <plat/i2c.h>
+#include <plat/pxa3xx_nand.h>
#include "devices.h"
#include "generic.h"
diff --git a/arch/arm/mach-pxa/include/mach/palmtreo.h b/arch/arm/mach-pxa/include/mach/palmtreo.h
new file mode 100644
index 000000000000..2d3f14e3be29
--- /dev/null
+++ b/arch/arm/mach-pxa/include/mach/palmtreo.h
@@ -0,0 +1,67 @@
+/*
+ * GPIOs and interrupts for Palm Treo smartphones
+ *
+ * currently supported:
+ * Palm Treo 680 (GSM)
+ * Palm Centro 685 (GSM)
+ *
+ * Author: Tomas Cech <sleep_walker@suse.cz>
+ *
+ * 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.
+ *
+ * find more info at www.hackndev.com
+ *
+ */
+
+#ifndef _INCLUDE_TREO_H_
+#define _INCLUDE_TREO_H_
+
+/* GPIOs */
+#define GPIO_NR_TREO_POWER_DETECT 0
+#define GPIO_NR_TREO_AMP_EN 27
+#define GPIO_NR_TREO_GREEN_LED 20
+#define GPIO_NR_TREO_RED_LED 79
+#define GPIO_NR_TREO_SD_DETECT_N 113
+#define GPIO_NR_TREO_EP_DETECT_N 116
+#define GPIO_NR_TREO_USB_DETECT 1
+#define GPIO_NR_TREO_USB_PULLUP 114
+#define GPIO_NR_TREO_GSM_POWER 40
+#define GPIO_NR_TREO_GSM_RESET 87
+#define GPIO_NR_TREO_GSM_WAKE 57
+#define GPIO_NR_TREO_GSM_HOST_WAKE 14
+#define GPIO_NR_TREO_GSM_TRIGGER 10
+#define GPIO_NR_TREO_IR_EN 115
+#define GPIO_NR_TREO_IR_TXD 47
+#define GPIO_NR_TREO_BL_POWER 38
+#define GPIO_NR_TREO_LCD_POWER 25
+
+/* Treo680 specific GPIOs */
+#ifdef CONFIG_MACH_TREO680
+#define GPIO_NR_TREO680_SD_READONLY 33
+#define GPIO_NR_TREO680_SD_POWER 42
+#define GPIO_NR_TREO680_VIBRATE_EN 44
+#define GPIO_NR_TREO680_KEYB_BL 24
+#define GPIO_NR_TREO680_BT_EN 43
+#endif /* CONFIG_MACH_TREO680 */
+
+/* Centro685 specific GPIOs */
+#define GPIO_NR_CENTRO_SD_POWER 21
+#define GPIO_NR_CENTRO_VIBRATE_EN 22
+#define GPIO_NR_CENTRO_KEYB_BL 33
+#define GPIO_NR_CENTRO_BT_EN 80
+
+/* Various addresses */
+#define TREO_PHYS_RAM_START 0xa0000000
+#define TREO_PHYS_IO_START 0x40000000
+#define TREO_STR_BASE 0xa2000000
+
+/* BACKLIGHT */
+#define TREO_MAX_INTENSITY 254
+#define TREO_DEFAULT_INTENSITY 160
+#define TREO_LIMIT_MASK 0x7F
+#define TREO_PRESCALER 63
+#define TREO_PERIOD_NS 3500
+
+#endif
diff --git a/arch/arm/mach-pxa/include/mach/treo680.h b/arch/arm/mach-pxa/include/mach/treo680.h
deleted file mode 100644
index af443b24d99a..000000000000
--- a/arch/arm/mach-pxa/include/mach/treo680.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * GPIOs and interrupts for Palm Treo 680 smartphone
- *
- * 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 _INCLUDE_TREO680_H_
-#define _INCLUDE_TREO680_H_
-
-/* GPIOs */
-#define GPIO_NR_TREO680_POWER_DETECT 0
-#define GPIO_NR_TREO680_AMP_EN 27
-#define GPIO_NR_TREO680_KEYB_BL 24
-#define GPIO_NR_TREO680_VIBRATE_EN 44
-#define GPIO_NR_TREO680_GREEN_LED 20
-#define GPIO_NR_TREO680_RED_LED 79
-#define GPIO_NR_TREO680_SD_DETECT_N 113
-#define GPIO_NR_TREO680_SD_READONLY 33
-#define GPIO_NR_TREO680_EP_DETECT_N 116
-#define GPIO_NR_TREO680_SD_POWER 42
-#define GPIO_NR_TREO680_USB_DETECT 1
-#define GPIO_NR_TREO680_USB_PULLUP 114
-#define GPIO_NR_TREO680_GSM_POWER 40
-#define GPIO_NR_TREO680_GSM_RESET 87
-#define GPIO_NR_TREO680_GSM_WAKE 57
-#define GPIO_NR_TREO680_GSM_HOST_WAKE 14
-#define GPIO_NR_TREO680_GSM_TRIGGER 10
-#define GPIO_NR_TREO680_BT_EN 43
-#define GPIO_NR_TREO680_IR_EN 115
-#define GPIO_NR_TREO680_IR_TXD 47
-#define GPIO_NR_TREO680_BL_POWER 38
-#define GPIO_NR_TREO680_LCD_POWER 25
-
-/* Various addresses */
-#define TREO680_PHYS_RAM_START 0xa0000000
-#define TREO680_PHYS_IO_START 0x40000000
-#define TREO680_STR_BASE 0xa2000000
-
-/* BACKLIGHT */
-#define TREO680_MAX_INTENSITY 254
-#define TREO680_DEFAULT_INTENSITY 160
-#define TREO680_LIMIT_MASK 0x7F
-#define TREO680_PRESCALER 63
-#define TREO680_PERIOD_NS 3500
-
-#endif
diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c
index 13848955d133..ce5e6175a050 100644
--- a/arch/arm/mach-pxa/littleton.c
+++ b/arch/arm/mach-pxa/littleton.c
@@ -44,10 +44,10 @@
#include <mach/ssp.h>
#include <mach/mmc.h>
#include <mach/pxa2xx_spi.h>
-#include <plat/i2c.h>
#include <mach/pxa27x_keypad.h>
-#include <mach/pxa3xx_nand.h>
#include <mach/littleton.h>
+#include <plat/i2c.h>
+#include <plat/pxa3xx_nand.h>
#include "generic.h"
diff --git a/arch/arm/mach-pxa/treo680.c b/arch/arm/mach-pxa/palmtreo.c
index fe085076fbf2..c071b60ebed8 100644
--- a/arch/arm/mach-pxa/treo680.c
+++ b/arch/arm/mach-pxa/palmtreo.c
@@ -1,5 +1,9 @@
/*
- * Hardware definitions for Palm Treo 680
+ * Hardware definitions for Palm Treo smartphones
+ *
+ * currently supported:
+ * Palm Treo 680 (GSM)
+ * Palm Centro 685 (GSM)
*
* Author: Tomas Cech <sleep_walker@suse.cz>
*
@@ -31,7 +35,7 @@
#include <mach/pxa27x.h>
#include <mach/pxa27x-udc.h>
#include <mach/audio.h>
-#include <mach/treo680.h>
+#include <mach/palmtreo.h>
#include <mach/mmc.h>
#include <mach/pxafb.h>
#include <mach/irda.h>
@@ -50,7 +54,7 @@
/******************************************************************************
* Pin configuration
******************************************************************************/
-static unsigned long treo680_pin_config[] __initdata = {
+static unsigned long treo_pin_config[] __initdata = {
/* MMC */
GPIO32_MMC_CLK,
GPIO92_MMC_DAT_0,
@@ -58,7 +62,6 @@ static unsigned long treo680_pin_config[] __initdata = {
GPIO110_MMC_DAT_2,
GPIO111_MMC_DAT_3,
GPIO112_MMC_CMD,
- GPIO33_GPIO, /* SD read only */
GPIO113_GPIO, /* SD detect */
/* AC97 */
@@ -80,12 +83,10 @@ static unsigned long treo680_pin_config[] __initdata = {
GPIO1_GPIO | WAKEUP_ON_EDGE_BOTH, /* usb detect */
/* MATRIX KEYPAD */
- GPIO100_KP_MKIN_0 | WAKEUP_ON_LEVEL_HIGH,
GPIO101_KP_MKIN_1,
GPIO102_KP_MKIN_2,
GPIO97_KP_MKIN_3,
GPIO98_KP_MKIN_4,
- GPIO99_KP_MKIN_5,
GPIO91_KP_MKIN_6,
GPIO13_KP_MKIN_7,
GPIO103_KP_MKOUT_0 | MFP_LPM_DRIVE_HIGH,
@@ -150,19 +151,57 @@ static unsigned long treo680_pin_config[] __initdata = {
GPIO11_GPIO | WAKEUP_ON_EDGE_BOTH, /* bluetooth host wake up */
};
+#ifdef CONFIG_MACH_TREO680
+static unsigned long treo680_pin_config[] __initdata = {
+ GPIO33_GPIO, /* SD read only */
+
+ /* MATRIX KEYPAD - different wake up source */
+ GPIO100_KP_MKIN_0 | WAKEUP_ON_LEVEL_HIGH,
+ GPIO99_KP_MKIN_5,
+};
+#endif /* CONFIG_MACH_TREO680 */
+
+#ifdef CONFIG_MACH_CENTRO
+static unsigned long centro685_pin_config[] __initdata = {
+ /* Bluetooth attached to BT UART*/
+ MFP_CFG_OUT(GPIO80, AF0, DRIVE_LOW), /* power: LOW = off */
+ GPIO42_BTUART_RXD,
+ GPIO43_BTUART_TXD,
+ GPIO44_BTUART_CTS,
+ GPIO45_BTUART_RTS,
+
+ /* MATRIX KEYPAD - different wake up source */
+ GPIO100_KP_MKIN_0,
+ GPIO99_KP_MKIN_5 | WAKEUP_ON_LEVEL_HIGH,
+};
+#endif /* CONFIG_MACH_CENTRO */
+
/******************************************************************************
* SD/MMC card controller
******************************************************************************/
+#ifdef CONFIG_MACH_TREO680
static struct pxamci_platform_data treo680_mci_platform_data = {
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
- .gpio_card_detect = GPIO_NR_TREO680_SD_DETECT_N,
+ .gpio_card_detect = GPIO_NR_TREO_SD_DETECT_N,
.gpio_card_ro = GPIO_NR_TREO680_SD_READONLY,
.gpio_power = GPIO_NR_TREO680_SD_POWER,
};
+#endif /* CONFIG_MACH_TREO680 */
+
+#ifdef CONFIG_MACH_CENTRO
+static struct pxamci_platform_data centro_mci_platform_data = {
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .gpio_card_detect = GPIO_NR_TREO_SD_DETECT_N,
+ .gpio_card_ro = -1,
+ .gpio_power = GPIO_NR_CENTRO_SD_POWER,
+ .gpio_power_invert = 1,
+};
+#endif /* CONFIG_MACH_CENTRO */
/******************************************************************************
* GPIO keyboard
******************************************************************************/
+#ifdef CONFIG_MACH_TREO680
static unsigned int treo680_matrix_keys[] = {
KEY(0, 0, KEY_F8), /* Red/Off/Power */
KEY(0, 1, KEY_LEFT),
@@ -232,92 +271,167 @@ static struct pxa27x_keypad_platform_data treo680_keypad_platform_data = {
.debounce_interval = 30,
};
+#endif /* CONFIG_MACH_TREO680 */
+
+#ifdef CONFIG_MACH_CENTRO
+static unsigned int centro_matrix_keys[] = {
+ KEY(0, 0, KEY_F9), /* Home */
+ KEY(0, 1, KEY_LEFT),
+ KEY(0, 2, KEY_LEFTCTRL), /* Alternate */
+ KEY(0, 3, KEY_L),
+ KEY(0, 4, KEY_A),
+ KEY(0, 5, KEY_Q),
+ KEY(0, 6, KEY_P),
+
+ KEY(1, 0, KEY_RIGHTCTRL), /* Menu */
+ KEY(1, 1, KEY_RIGHT),
+ KEY(1, 2, KEY_LEFTSHIFT), /* Left shift */
+ KEY(1, 3, KEY_Z),
+ KEY(1, 4, KEY_S),
+ KEY(1, 5, KEY_W),
+
+ KEY(2, 0, KEY_F1), /* Phone */
+ KEY(2, 1, KEY_UP),
+ KEY(2, 2, KEY_0),
+ KEY(2, 3, KEY_X),
+ KEY(2, 4, KEY_D),
+ KEY(2, 5, KEY_E),
+
+ KEY(3, 0, KEY_F10), /* Calendar */
+ KEY(3, 1, KEY_DOWN),
+ KEY(3, 2, KEY_SPACE),
+ KEY(3, 3, KEY_C),
+ KEY(3, 4, KEY_F),
+ KEY(3, 5, KEY_R),
+
+ KEY(4, 0, KEY_F12), /* Mail */
+ KEY(4, 1, KEY_KPENTER),
+ KEY(4, 2, KEY_RIGHTALT), /* Alt */
+ KEY(4, 3, KEY_V),
+ KEY(4, 4, KEY_G),
+ KEY(4, 5, KEY_T),
+
+ KEY(5, 0, KEY_F8), /* Red/Off/Power */
+ KEY(5, 1, KEY_PAGEUP), /* Side up */
+ KEY(5, 2, KEY_DOT),
+ KEY(5, 3, KEY_B),
+ KEY(5, 4, KEY_H),
+ KEY(5, 5, KEY_Y),
+
+ KEY(6, 0, KEY_TAB), /* Side Activate */
+ KEY(6, 1, KEY_PAGEDOWN), /* Side down */
+ KEY(6, 2, KEY_ENTER),
+ KEY(6, 3, KEY_N),
+ KEY(6, 4, KEY_J),
+ KEY(6, 5, KEY_U),
+
+ KEY(7, 0, KEY_F6), /* Green/Call */
+ KEY(7, 1, KEY_O),
+ KEY(7, 2, KEY_BACKSPACE),
+ KEY(7, 3, KEY_M),
+ KEY(7, 4, KEY_K),
+ KEY(7, 5, KEY_I),
+};
+
+static struct pxa27x_keypad_platform_data centro_keypad_platform_data = {
+ .matrix_key_rows = 8,
+ .matrix_key_cols = 7,
+ .matrix_key_map = centro_matrix_keys,
+ .matrix_key_map_size = ARRAY_SIZE(centro_matrix_keys),
+ .direct_key_map = { KEY_CONNECT },
+ .direct_key_num = 1,
+
+ .debounce_interval = 30,
+};
+#endif /* CONFIG_MACH_CENTRO */
/******************************************************************************
* aSoC audio
******************************************************************************/
-static pxa2xx_audio_ops_t treo680_ac97_pdata = {
+static pxa2xx_audio_ops_t treo_ac97_pdata = {
.reset_gpio = 95,
};
/******************************************************************************
* Backlight
******************************************************************************/
-static int treo680_backlight_init(struct device *dev)
+static int treo_backlight_init(struct device *dev)
{
int ret;
- ret = gpio_request(GPIO_NR_TREO680_BL_POWER, "BL POWER");
+ ret = gpio_request(GPIO_NR_TREO_BL_POWER, "BL POWER");
if (ret)
goto err;
- ret = gpio_direction_output(GPIO_NR_TREO680_BL_POWER, 0);
+ ret = gpio_direction_output(GPIO_NR_TREO_BL_POWER, 0);
if (ret)
goto err2;
return 0;
err2:
- gpio_free(GPIO_NR_TREO680_BL_POWER);
+ gpio_free(GPIO_NR_TREO_BL_POWER);
err:
return ret;
}
-static int treo680_backlight_notify(int brightness)
+static int treo_backlight_notify(int brightness)
{
- gpio_set_value(GPIO_NR_TREO680_BL_POWER, brightness);
- return TREO680_MAX_INTENSITY - brightness;
+ gpio_set_value(GPIO_NR_TREO_BL_POWER, brightness);
+ return TREO_MAX_INTENSITY - brightness;
};
-static void treo680_backlight_exit(struct device *dev)
+static void treo_backlight_exit(struct device *dev)
{
- gpio_free(GPIO_NR_TREO680_BL_POWER);
+ gpio_free(GPIO_NR_TREO_BL_POWER);
}
-static struct platform_pwm_backlight_data treo680_backlight_data = {
+static struct platform_pwm_backlight_data treo_backlight_data = {
.pwm_id = 0,
- .max_brightness = TREO680_MAX_INTENSITY,
- .dft_brightness = TREO680_DEFAULT_INTENSITY,
- .pwm_period_ns = TREO680_PERIOD_NS,
- .init = treo680_backlight_init,
- .notify = treo680_backlight_notify,
- .exit = treo680_backlight_exit,
+ .max_brightness = TREO_MAX_INTENSITY,
+ .dft_brightness = TREO_DEFAULT_INTENSITY,
+ .pwm_period_ns = TREO_PERIOD_NS,
+ .init = treo_backlight_init,
+ .notify = treo_backlight_notify,
+ .exit = treo_backlight_exit,
};
-static struct platform_device treo680_backlight = {
+static struct platform_device treo_backlight = {
.name = "pwm-backlight",
.dev = {
.parent = &pxa27x_device_pwm0.dev,
- .platform_data = &treo680_backlight_data,
+ .platform_data = &treo_backlight_data,
},
};
/******************************************************************************
* IrDA
******************************************************************************/
-static struct pxaficp_platform_data treo680_ficp_info = {
- .gpio_pwdown = GPIO_NR_TREO680_IR_EN,
+static struct pxaficp_platform_data treo_ficp_info = {
+ .gpio_pwdown = GPIO_NR_TREO_IR_EN,
.transceiver_cap = IR_SIRMODE | IR_OFF,
};
/******************************************************************************
* UDC
******************************************************************************/
-static struct pxa2xx_udc_mach_info treo680_udc_info __initdata = {
- .gpio_vbus = GPIO_NR_TREO680_USB_DETECT,
+static struct pxa2xx_udc_mach_info treo_udc_info __initdata = {
+ .gpio_vbus = GPIO_NR_TREO_USB_DETECT,
.gpio_vbus_inverted = 1,
- .gpio_pullup = GPIO_NR_TREO680_USB_PULLUP,
+ .gpio_pullup = GPIO_NR_TREO_USB_PULLUP,
};
/******************************************************************************
* USB host
******************************************************************************/
+#ifdef CONFIG_MACH_TREO680
static struct pxaohci_platform_data treo680_ohci_info = {
.port_mode = PMM_PERPORT_MODE,
.flags = ENABLE_PORT1 | ENABLE_PORT3,
.power_budget = 0,
};
+#endif /* CONFIG_MACH_TREO680 */
/******************************************************************************
* Power supply
@@ -326,41 +440,41 @@ static int power_supply_init(struct device *dev)
{
int ret;
- ret = gpio_request(GPIO_NR_TREO680_POWER_DETECT, "CABLE_STATE_AC");
+ ret = gpio_request(GPIO_NR_TREO_POWER_DETECT, "CABLE_STATE_AC");
if (ret)
goto err1;
- ret = gpio_direction_input(GPIO_NR_TREO680_POWER_DETECT);
+ ret = gpio_direction_input(GPIO_NR_TREO_POWER_DETECT);
if (ret)
goto err2;
return 0;
err2:
- gpio_free(GPIO_NR_TREO680_POWER_DETECT);
+ gpio_free(GPIO_NR_TREO_POWER_DETECT);
err1:
return ret;
}
-static int treo680_is_ac_online(void)
+static int treo_is_ac_online(void)
{
- return gpio_get_value(GPIO_NR_TREO680_POWER_DETECT);
+ return gpio_get_value(GPIO_NR_TREO_POWER_DETECT);
}
static void power_supply_exit(struct device *dev)
{
- gpio_free(GPIO_NR_TREO680_POWER_DETECT);
+ gpio_free(GPIO_NR_TREO_POWER_DETECT);
}
-static char *treo680_supplicants[] = {
+static char *treo_supplicants[] = {
"main-battery",
};
static struct pda_power_pdata power_supply_info = {
.init = power_supply_init,
- .is_ac_online = treo680_is_ac_online,
+ .is_ac_online = treo_is_ac_online,
.exit = power_supply_exit,
- .supplied_to = treo680_supplicants,
- .num_supplicants = ARRAY_SIZE(treo680_supplicants),
+ .supplied_to = treo_supplicants,
+ .num_supplicants = ARRAY_SIZE(treo_supplicants),
};
static struct platform_device power_supply = {
@@ -374,7 +488,8 @@ static struct platform_device power_supply = {
/******************************************************************************
* Vibra and LEDs
******************************************************************************/
-static struct gpio_led gpio_leds[] = {
+#ifdef CONFIG_MACH_TREO680
+static struct gpio_led treo680_gpio_leds[] = {
{
.name = "treo680:vibra:vibra",
.default_trigger = "none",
@@ -383,34 +498,68 @@ static struct gpio_led gpio_leds[] = {
{
.name = "treo680:green:led",
.default_trigger = "mmc0",
- .gpio = GPIO_NR_TREO680_GREEN_LED,
+ .gpio = GPIO_NR_TREO_GREEN_LED,
},
{
- .name = "treo680:keybbl:keybbl",
+ .name = "treo680:white:keybbl",
.default_trigger = "none",
.gpio = GPIO_NR_TREO680_KEYB_BL,
},
};
-static struct gpio_led_platform_data gpio_led_info = {
- .leds = gpio_leds,
- .num_leds = ARRAY_SIZE(gpio_leds),
+static struct gpio_led_platform_data treo680_gpio_led_info = {
+ .leds = treo680_gpio_leds,
+ .num_leds = ARRAY_SIZE(treo680_gpio_leds),
};
static struct platform_device treo680_leds = {
.name = "leds-gpio",
.id = -1,
.dev = {
- .platform_data = &gpio_led_info,
+ .platform_data = &treo680_gpio_led_info,
}
};
+#endif /* CONFIG_MACH_TREO680 */
+#ifdef CONFIG_MACH_CENTRO
+static struct gpio_led centro_gpio_leds[] = {
+ {
+ .name = "centro:vibra:vibra",
+ .default_trigger = "none",
+ .gpio = GPIO_NR_CENTRO_VIBRATE_EN,
+ },
+ {
+ .name = "centro:green:led",
+ .default_trigger = "mmc0",
+ .gpio = GPIO_NR_TREO_GREEN_LED,
+ },
+ {
+ .name = "centro:white:keybbl",
+ .default_trigger = "none",
+ .active_low = 1,
+ .gpio = GPIO_NR_CENTRO_KEYB_BL,
+ },
+};
+
+static struct gpio_led_platform_data centro_gpio_led_info = {
+ .leds = centro_gpio_leds,
+ .num_leds = ARRAY_SIZE(centro_gpio_leds),
+};
+
+static struct platform_device centro_leds = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &centro_gpio_led_info,
+ }
+};
+#endif /* CONFIG_MACH_CENTRO */
/******************************************************************************
* Framebuffer
******************************************************************************/
/* TODO: add support for 324x324 */
-static struct pxafb_mode_info treo680_lcd_modes[] = {
+static struct pxafb_mode_info treo_lcd_modes[] = {
{
.pixclock = 86538,
.xres = 320,
@@ -427,21 +576,21 @@ static struct pxafb_mode_info treo680_lcd_modes[] = {
},
};
-static void treo680_lcd_power(int on, struct fb_var_screeninfo *info)
+static void treo_lcd_power(int on, struct fb_var_screeninfo *info)
{
- gpio_set_value(GPIO_NR_TREO680_BL_POWER, on);
+ gpio_set_value(GPIO_NR_TREO_BL_POWER, on);
}
-static struct pxafb_mach_info treo680_lcd_screen = {
- .modes = treo680_lcd_modes,
- .num_modes = ARRAY_SIZE(treo680_lcd_modes),
+static struct pxafb_mach_info treo_lcd_screen = {
+ .modes = treo_lcd_modes,
+ .num_modes = ARRAY_SIZE(treo_lcd_modes),
.lcd_conn = LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL,
};
/******************************************************************************
* Power management - standby
******************************************************************************/
-static void __init treo680_pm_init(void)
+static void __init treo_pm_init(void)
{
static u32 resume[] = {
0xe3a00101, /* mov r0, #0x40000000 */
@@ -450,70 +599,114 @@ static void __init treo680_pm_init(void)
};
/* this is where the bootloader jumps */
- memcpy(phys_to_virt(TREO680_STR_BASE), resume, sizeof(resume));
+ memcpy(phys_to_virt(TREO_STR_BASE), resume, sizeof(resume));
}
/******************************************************************************
* Machine init
******************************************************************************/
-static struct platform_device *devices[] __initdata = {
- &treo680_backlight,
- &treo680_leds,
+static struct platform_device *treo_devices[] __initdata = {
+ &treo_backlight,
&power_supply,
};
+#ifdef CONFIG_MACH_TREO680
+static struct platform_device *treo680_devices[] __initdata = {
+ &treo680_leds,
+};
+#endif /* CONFIG_MACH_TREO680 */
+
+#ifdef CONFIG_MACH_CENTRO
+static struct platform_device *centro_devices[] __initdata = {
+ &centro_leds,
+};
+#endif /* CONFIG_MACH_CENTRO */
+
/* setup udc GPIOs initial state */
-static void __init treo680_udc_init(void)
+static void __init treo_udc_init(void)
{
- if (!gpio_request(GPIO_NR_TREO680_USB_PULLUP, "UDC Vbus")) {
- gpio_direction_output(GPIO_NR_TREO680_USB_PULLUP, 1);
- gpio_free(GPIO_NR_TREO680_USB_PULLUP);
+ if (!gpio_request(GPIO_NR_TREO_USB_PULLUP, "UDC Vbus")) {
+ gpio_direction_output(GPIO_NR_TREO_USB_PULLUP, 1);
+ gpio_free(GPIO_NR_TREO_USB_PULLUP);
}
}
-static void __init treo680_lcd_power_init(void)
+static void __init treo_lcd_power_init(void)
{
int ret;
- ret = gpio_request(GPIO_NR_TREO680_LCD_POWER, "LCD POWER");
+ ret = gpio_request(GPIO_NR_TREO_LCD_POWER, "LCD POWER");
if (ret) {
pr_err("Treo680: LCD power GPIO request failed!\n");
return;
}
- ret = gpio_direction_output(GPIO_NR_TREO680_LCD_POWER, 0);
+ ret = gpio_direction_output(GPIO_NR_TREO_LCD_POWER, 0);
if (ret) {
pr_err("Treo680: setting LCD power GPIO direction failed!\n");
- gpio_free(GPIO_NR_TREO680_LCD_POWER);
+ gpio_free(GPIO_NR_TREO_LCD_POWER);
return;
}
- treo680_lcd_screen.pxafb_lcd_power = treo680_lcd_power;
+ treo_lcd_screen.pxafb_lcd_power = treo_lcd_power;
}
+static void __init treo_init(void)
+{
+ treo_pm_init();
+ pxa2xx_mfp_config(ARRAY_AND_SIZE(treo_pin_config));
+ treo_lcd_power_init();
+ set_pxa_fb_info(&treo_lcd_screen);
+ treo_udc_init();
+ pxa_set_udc_info(&treo_udc_info);
+ pxa_set_ac97_info(&treo_ac97_pdata);
+ pxa_set_ficp_info(&treo_ficp_info);
+
+ platform_add_devices(ARRAY_AND_SIZE(treo_devices));
+}
+
+#ifdef CONFIG_MACH_TREO680
static void __init treo680_init(void)
{
- treo680_pm_init();
+ treo_init();
pxa2xx_mfp_config(ARRAY_AND_SIZE(treo680_pin_config));
- pxa_set_keypad_info(&treo680_keypad_platform_data);
- treo680_lcd_power_init();
- set_pxa_fb_info(&treo680_lcd_screen);
pxa_set_mci_info(&treo680_mci_platform_data);
- treo680_udc_init();
- pxa_set_udc_info(&treo680_udc_info);
- pxa_set_ac97_info(&treo680_ac97_pdata);
- pxa_set_ficp_info(&treo680_ficp_info);
+ pxa_set_keypad_info(&treo680_keypad_platform_data);
pxa_set_ohci_info(&treo680_ohci_info);
- platform_add_devices(devices, ARRAY_SIZE(devices));
+ platform_add_devices(ARRAY_AND_SIZE(treo680_devices));
}
MACHINE_START(TREO680, "Palm Treo 680")
- .phys_io = TREO680_PHYS_IO_START,
- .io_pg_offst = io_p2v(0x40000000),
- .boot_params = 0xa0000100,
- .map_io = pxa_map_io,
- .init_irq = pxa27x_init_irq,
- .timer = &pxa_timer,
- .init_machine = treo680_init,
+ .phys_io = TREO_PHYS_IO_START,
+ .io_pg_offst = io_p2v(0x40000000),
+ .boot_params = 0xa0000100,
+ .map_io = pxa_map_io,
+ .init_irq = pxa27x_init_irq,
+ .timer = &pxa_timer,
+ .init_machine = treo680_init,
+MACHINE_END
+#endif /* CONFIG_MACH_TREO680 */
+
+#ifdef CONFIG_MACH_CENTRO
+static void __init centro_init(void)
+{
+ treo_init();
+ pxa2xx_mfp_config(ARRAY_AND_SIZE(centro685_pin_config));
+ pxa_set_mci_info(&centro_mci_platform_data);
+
+ pxa_set_keypad_info(&centro_keypad_platform_data);
+
+ platform_add_devices(ARRAY_AND_SIZE(centro_devices));
+}
+
+MACHINE_START(CENTRO, "Palm Centro 685")
+ .phys_io = TREO_PHYS_IO_START,
+ .io_pg_offst = io_p2v(0x40000000),
+ .boot_params = 0xa0000100,
+ .map_io = pxa_map_io,
+ .init_irq = pxa27x_init_irq,
+ .timer = &pxa_timer,
+ .init_machine = centro_init,
MACHINE_END
+#endif /* CONFIG_MACH_CENTRO */
diff --git a/arch/arm/mach-pxa/saar.c b/arch/arm/mach-pxa/saar.c
index 8241a63ea589..8b7ea09574c2 100644
--- a/arch/arm/mach-pxa/saar.c
+++ b/arch/arm/mach-pxa/saar.c
@@ -22,9 +22,13 @@
#include <linux/i2c.h>
#include <linux/smc91x.h>
#include <linux/mfd/da903x.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/onenand.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
#include <mach/pxa930.h>
#include <plat/i2c.h>
@@ -33,7 +37,7 @@
#include "devices.h"
#include "generic.h"
-#define GPIO_LCD_RESET (16)
+#define GPIO_LCD_RESET (16)
/* SAAR MFP configurations */
static mfp_cfg_t saar_mfp_cfg[] __initdata = {
@@ -56,6 +60,31 @@ static mfp_cfg_t saar_mfp_cfg[] __initdata = {
/* Ethernet */
DF_nCS1_nCS3,
GPIO97_GPIO,
+
+ /* DFI */
+ DF_INT_RnB_ND_INT_RnB,
+ DF_nRE_nOE_ND_nRE,
+ DF_nWE_ND_nWE,
+ DF_CLE_nOE_ND_CLE,
+ DF_nADV1_ALE_ND_ALE,
+ DF_nADV2_ALE_nCS3,
+ DF_nCS0_ND_nCS0,
+ DF_IO0_ND_IO0,
+ DF_IO1_ND_IO1,
+ DF_IO2_ND_IO2,
+ DF_IO3_ND_IO3,
+ DF_IO4_ND_IO4,
+ DF_IO5_ND_IO5,
+ DF_IO6_ND_IO6,
+ DF_IO7_ND_IO7,
+ DF_IO8_ND_IO8,
+ DF_IO9_ND_IO9,
+ DF_IO10_ND_IO10,
+ DF_IO11_ND_IO11,
+ DF_IO12_ND_IO12,
+ DF_IO13_ND_IO13,
+ DF_IO14_ND_IO14,
+ DF_IO15_ND_IO15,
};
#define SAAR_ETH_PHYS (0x14000000)
@@ -480,12 +509,77 @@ static void __init saar_init_i2c(void)
#else
static inline void saar_init_i2c(void) {}
#endif
+
+#if defined(CONFIG_MTD_ONENAND) || defined(CONFIG_MTD_ONENAND_MODULE)
+static struct mtd_partition saar_onenand_partitions[] = {
+ {
+ .name = "bootloader",
+ .offset = 0,
+ .size = SZ_1M,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "reserved",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_128K,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "reserved",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_8M,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = (SZ_2M + SZ_1M),
+ .mask_flags = 0,
+ }, {
+ .name = "filesystem",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_48M,
+ .mask_flags = 0,
+ }
+};
+
+static struct flash_platform_data saar_onenand_info = {
+ .parts = saar_onenand_partitions,
+ .nr_parts = ARRAY_SIZE(saar_onenand_partitions),
+};
+
+#define SMC_CS0_PHYS_BASE (0x10000000)
+
+static struct resource saar_resource_onenand[] = {
+ [0] = {
+ .start = SMC_CS0_PHYS_BASE,
+ .end = SMC_CS0_PHYS_BASE + SZ_1M,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device saar_device_onenand = {
+ .name = "onenand",
+ .id = -1,
+ .dev = {
+ .platform_data = &saar_onenand_info,
+ },
+ .resource = saar_resource_onenand,
+ .num_resources = ARRAY_SIZE(saar_resource_onenand),
+};
+
+static void __init saar_init_onenand(void)
+{
+ platform_device_register(&saar_device_onenand);
+}
+#else
+static void __init saar_init_onenand(void) {}
+#endif
+
static void __init saar_init(void)
{
/* initialize MFP configurations */
pxa3xx_mfp_config(ARRAY_AND_SIZE(saar_mfp_cfg));
platform_device_register(&smc91x_device);
+ saar_init_onenand();
saar_init_i2c();
saar_init_lcd();
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index ee8d6038ce82..82ff5733e4dc 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
+#include <linux/gpio_keys.h>
#include <linux/gpio.h>
#include <linux/leds.h>
#include <linux/mtd/physmap.h>
@@ -375,6 +376,43 @@ static struct platform_device spitzkbd_device = {
};
+static struct gpio_keys_button spitz_gpio_keys[] = {
+ {
+ .type = EV_PWR,
+ .code = KEY_SUSPEND,
+ .gpio = SPITZ_GPIO_ON_KEY,
+ .desc = "On/Off",
+ .wakeup = 1,
+ },
+ /* Two buttons detecting the lid state */
+ {
+ .type = EV_SW,
+ .code = 0,
+ .gpio = SPITZ_GPIO_SWA,
+ .desc = "Display Down",
+ },
+ {
+ .type = EV_SW,
+ .code = 1,
+ .gpio = SPITZ_GPIO_SWB,
+ .desc = "Lid Closed",
+ },
+};
+
+static struct gpio_keys_platform_data spitz_gpio_keys_platform_data = {
+ .buttons = spitz_gpio_keys,
+ .nbuttons = ARRAY_SIZE(spitz_gpio_keys),
+};
+
+static struct platform_device spitz_gpio_keys_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &spitz_gpio_keys_platform_data,
+ },
+};
+
+
/*
* Spitz LEDs
*/
@@ -689,6 +727,7 @@ static struct platform_device sharpsl_rom_device = {
static struct platform_device *devices[] __initdata = {
&spitzscoop_device,
&spitzkbd_device,
+ &spitz_gpio_keys_device,
&spitzled_device,
&sharpsl_nand_device,
&sharpsl_rom_device,
diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
index 09784d3954e4..8fcb69411cf7 100644
--- a/arch/arm/mach-pxa/zylonite.c
+++ b/arch/arm/mach-pxa/zylonite.c
@@ -31,7 +31,7 @@
#include <mach/mmc.h>
#include <mach/ohci.h>
#include <mach/pxa27x_keypad.h>
-#include <mach/pxa3xx_nand.h>
+#include <plat/pxa3xx_nand.h>
#include "devices.h"
#include "generic.h"
diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig
index dfc9b0bc6eb2..ba548ab12171 100644
--- a/arch/arm/mach-realview/Kconfig
+++ b/arch/arm/mach-realview/Kconfig
@@ -70,12 +70,14 @@ config MACH_REALVIEW_PBX
bool "Support RealView/PBX platform"
select ARM_GIC
select HAVE_PATA_PLATFORM
+ select ARCH_SPARSEMEM_ENABLE if CPU_V7
+ select ZONE_DMA if SPARSEMEM
help
Include support for the ARM(R) RealView PBX platform.
config REALVIEW_HIGH_PHYS_OFFSET
bool "High physical base address for the RealView platform"
- depends on MMU && !MACH_REALVIEW_PB1176
+ depends on MMU && !MACH_REALVIEW_PB1176 && !SPARSEMEM
default y
help
RealView boards other than PB1176 have the RAM available at
@@ -84,4 +86,8 @@ config REALVIEW_HIGH_PHYS_OFFSET
memory to be accessed contiguously at the high physical
offset.
+config ARCH_FLATMEM_ENABLE
+ bool
+ default y if ARCH_SPARSEMEM_ENABLE
+
endmenu
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index a2083b60e3fb..9f293438e020 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -59,6 +59,25 @@
/* used by entry-macro.S and platsmp.c */
void __iomem *gic_cpu_base_addr;
+#ifdef CONFIG_ZONE_DMA
+/*
+ * Adjust the zones if there are restrictions for DMA access.
+ */
+void __init realview_adjust_zones(int node, unsigned long *size,
+ unsigned long *hole)
+{
+ unsigned long dma_size = SZ_256M >> PAGE_SHIFT;
+
+ if (!machine_is_realview_pbx() || node || (size[0] <= dma_size))
+ return;
+
+ size[ZONE_NORMAL] = size[0] - dma_size;
+ size[ZONE_DMA] = dma_size;
+ hole[ZONE_NORMAL] = hole[0];
+ hole[ZONE_DMA] = 0;
+}
+#endif
+
/*
* This is the RealView sched_clock implementation. This has
* a resolution of 41.7ns, and a maximum value of about 179s.
@@ -543,7 +562,7 @@ static int realview_clcd_setup(struct clcd_fb *fb)
fb->panel = realview_clcd_panel();
fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize,
- &dma, GFP_KERNEL);
+ &dma, GFP_KERNEL | GFP_DMA);
if (!fb->fb.screen_base) {
printk(KERN_ERR "CLCD: unable to map framebuffer\n");
return -ENOMEM;
@@ -788,3 +807,24 @@ void __init realview_timer_init(unsigned int timer_irq)
realview_clocksource_init();
realview_clockevents_init(timer_irq);
}
+
+/*
+ * Setup the memory banks.
+ */
+void realview_fixup(struct machine_desc *mdesc, struct tag *tags, char **from,
+ struct meminfo *meminfo)
+{
+ /*
+ * Most RealView platforms have 512MB contiguous RAM at 0x70000000.
+ * Half of this is mirrored at 0.
+ */
+#ifdef CONFIG_REALVIEW_HIGH_PHYS_OFFSET
+ meminfo->bank[0].start = 0x70000000;
+ meminfo->bank[0].size = SZ_512M;
+ meminfo->nr_banks = 1;
+#else
+ meminfo->bank[0].start = 0;
+ meminfo->bank[0].size = SZ_256M;
+ meminfo->nr_banks = 1;
+#endif
+}
diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h
index 46cd6acb4d40..1398854de157 100644
--- a/arch/arm/mach-realview/core.h
+++ b/arch/arm/mach-realview/core.h
@@ -25,6 +25,7 @@
#include <linux/amba/bus.h>
#include <linux/io.h>
+#include <asm/setup.h>
#include <asm/leds.h>
#define AMBA_DEVICE(name,busid,base,plat) \
@@ -44,6 +45,8 @@ static struct amba_device name##_device = { \
/* .dma = base##_DMA,*/ \
}
+struct machine_desc;
+
extern struct platform_device realview_flash_device;
extern struct platform_device realview_cf_device;
extern struct platform_device realview_i2c_device;
@@ -61,5 +64,7 @@ extern void realview_timer_init(unsigned int timer_irq);
extern int realview_flash_register(struct resource *res, u32 num);
extern int realview_eth_register(const char *name, struct resource *res);
extern int realview_usb_register(struct resource *res);
+extern void realview_fixup(struct machine_desc *mdesc, struct tag *tags,
+ char **from, struct meminfo *meminfo);
#endif
diff --git a/arch/arm/mach-realview/include/mach/memory.h b/arch/arm/mach-realview/include/mach/memory.h
index 293c30025e7e..2417bbcf97fd 100644
--- a/arch/arm/mach-realview/include/mach/memory.h
+++ b/arch/arm/mach-realview/include/mach/memory.h
@@ -29,4 +29,53 @@
#define PHYS_OFFSET UL(0x00000000)
#endif
+#if !defined(__ASSEMBLY__) && defined(CONFIG_ZONE_DMA)
+extern void realview_adjust_zones(int node, unsigned long *size,
+ unsigned long *hole);
+#define arch_adjust_zones(node, size, hole) \
+ realview_adjust_zones(node, size, hole)
+
+#define ISA_DMA_THRESHOLD (PHYS_OFFSET + SZ_256M - 1)
+#define MAX_DMA_ADDRESS (PAGE_OFFSET + SZ_256M)
+#endif
+
+#ifdef CONFIG_SPARSEMEM
+
+/*
+ * Sparsemem definitions for RealView PBX.
+ *
+ * The RealView PBX board has another block of 512MB of RAM at 0x20000000,
+ * however only the block at 0x70000000 (or the 256MB mirror at 0x00000000)
+ * may be used for DMA.
+ *
+ * The macros below define a section size of 256MB and a non-linear virtual to
+ * physical mapping:
+ *
+ * 256MB @ 0x00000000 -> PAGE_OFFSET
+ * 512MB @ 0x20000000 -> PAGE_OFFSET + 0x10000000
+ * 256MB @ 0x80000000 -> PAGE_OFFSET + 0x30000000
+ */
+#ifdef CONFIG_REALVIEW_HIGH_PHYS_OFFSET
+#error "SPARSEMEM not available with REALVIEW_HIGH_PHYS_OFFSET"
+#endif
+
+#define MAX_PHYSMEM_BITS 32
+#define SECTION_SIZE_BITS 28
+
+/* bank page offsets */
+#define PAGE_OFFSET1 (PAGE_OFFSET + 0x10000000)
+#define PAGE_OFFSET2 (PAGE_OFFSET + 0x30000000)
+
+#define __phys_to_virt(phys) \
+ ((phys) >= 0x80000000 ? (phys) - 0x80000000 + PAGE_OFFSET2 : \
+ (phys) >= 0x20000000 ? (phys) - 0x20000000 + PAGE_OFFSET1 : \
+ (phys) + PAGE_OFFSET)
+
+#define __virt_to_phys(virt) \
+ ((virt) >= PAGE_OFFSET2 ? (virt) - PAGE_OFFSET2 + 0x80000000 : \
+ (virt) >= PAGE_OFFSET1 ? (virt) - PAGE_OFFSET1 + 0x20000000 : \
+ (virt) - PAGE_OFFSET)
+
+#endif /* CONFIG_SPARSEMEM */
+
#endif
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index a88458b4799d..009265818d55 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -146,11 +146,8 @@ static void __init poke_milo(void)
* register. The BootMonitor waits for this register to become
* non-zero.
*/
-#define REALVIEW_SYS_FLAGSS_OFFSET 0x30
-#define REALVIEW_SYS_FLAGSC_OFFSET 0x34
__raw_writel(BSYM(virt_to_phys(realview_secondary_startup)),
- __io_address(REALVIEW_SYS_BASE) +
- REALVIEW_SYS_FLAGSS_OFFSET);
+ __io_address(REALVIEW_SYS_FLAGSSET));
mb();
}
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index 1d65e64ae571..917f8ca3abff 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -415,6 +415,7 @@ MACHINE_START(REALVIEW_EB, "ARM-RealView EB")
.phys_io = REALVIEW_EB_UART0_BASE,
.io_pg_offst = (IO_ADDRESS(REALVIEW_EB_UART0_BASE) >> 18) & 0xfffc,
.boot_params = PHYS_OFFSET + 0x00000100,
+ .fixup = realview_fixup,
.map_io = realview_eb_map_io,
.init_irq = gic_init_irq,
.timer = &realview_eb_timer,
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
index 2817fe099319..b1cdd371a049 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -290,6 +290,18 @@ static struct sys_timer realview_pb1176_timer = {
.init = realview_pb1176_timer_init,
};
+static void realview_pb1176_fixup(struct machine_desc *mdesc,
+ struct tag *tags, char **from,
+ struct meminfo *meminfo)
+{
+ /*
+ * RealView PB1176 only has 128MB of RAM mapped at 0.
+ */
+ meminfo->bank[0].start = 0;
+ meminfo->bank[0].size = SZ_128M;
+ meminfo->nr_banks = 1;
+}
+
static void __init realview_pb1176_init(void)
{
int i;
@@ -320,6 +332,7 @@ MACHINE_START(REALVIEW_PB1176, "ARM-RealView PB1176")
.phys_io = REALVIEW_PB1176_UART0_BASE,
.io_pg_offst = (IO_ADDRESS(REALVIEW_PB1176_UART0_BASE) >> 18) & 0xfffc,
.boot_params = PHYS_OFFSET + 0x00000100,
+ .fixup = realview_pb1176_fixup,
.map_io = realview_pb1176_map_io,
.init_irq = gic_init_irq,
.timer = &realview_pb1176_timer,
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index 94680fcf726d..22726b59d4c4 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -331,6 +331,7 @@ MACHINE_START(REALVIEW_PB11MP, "ARM-RealView PB11MPCore")
.phys_io = REALVIEW_PB11MP_UART0_BASE,
.io_pg_offst = (IO_ADDRESS(REALVIEW_PB11MP_UART0_BASE) >> 18) & 0xfffc,
.boot_params = PHYS_OFFSET + 0x00000100,
+ .fixup = realview_fixup,
.map_io = realview_pb11mp_map_io,
.init_irq = gic_init_irq,
.timer = &realview_pb11mp_timer,
diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c
index 941beb2b9709..fe861e96c566 100644
--- a/arch/arm/mach-realview/realview_pba8.c
+++ b/arch/arm/mach-realview/realview_pba8.c
@@ -298,6 +298,7 @@ MACHINE_START(REALVIEW_PBA8, "ARM-RealView PB-A8")
.phys_io = REALVIEW_PBA8_UART0_BASE,
.io_pg_offst = (IO_ADDRESS(REALVIEW_PBA8_UART0_BASE) >> 18) & 0xfffc,
.boot_params = PHYS_OFFSET + 0x00000100,
+ .fixup = realview_fixup,
.map_io = realview_pba8_map_io,
.init_irq = gic_init_irq,
.timer = &realview_pba8_timer,
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
index 7e4bc6cdca52..ec39488e2b42 100644
--- a/arch/arm/mach-realview/realview_pbx.c
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -304,6 +304,26 @@ static struct sys_timer realview_pbx_timer = {
.init = realview_pbx_timer_init,
};
+static void realview_pbx_fixup(struct machine_desc *mdesc, struct tag *tags,
+ char **from, struct meminfo *meminfo)
+{
+#ifdef CONFIG_SPARSEMEM
+ /*
+ * Memory configuration with SPARSEMEM enabled on RealView PBX (see
+ * asm/mach/memory.h for more information).
+ */
+ meminfo->bank[0].start = 0;
+ meminfo->bank[0].size = SZ_256M;
+ meminfo->bank[1].start = 0x20000000;
+ meminfo->bank[1].size = SZ_512M;
+ meminfo->bank[2].start = 0x80000000;
+ meminfo->bank[2].size = SZ_256M;
+ meminfo->nr_banks = 3;
+#else
+ realview_fixup(mdesc, tags, from, meminfo);
+#endif
+}
+
static void __init realview_pbx_init(void)
{
int i;
@@ -345,6 +365,7 @@ MACHINE_START(REALVIEW_PBX, "ARM-RealView PBX")
.phys_io = REALVIEW_PBX_UART0_BASE,
.io_pg_offst = (IO_ADDRESS(REALVIEW_PBX_UART0_BASE) >> 18) & 0xfffc,
.boot_params = PHYS_OFFSET + 0x00000100,
+ .fixup = realview_pbx_fixup,
.map_io = realview_pbx_map_io,
.init_irq = gic_init_irq,
.timer = &realview_pbx_timer,
diff --git a/arch/arm/mach-s3c2400/Kconfig b/arch/arm/mach-s3c2400/Kconfig
index deab0722836e..fdd8f5e96faf 100644
--- a/arch/arm/mach-s3c2400/Kconfig
+++ b/arch/arm/mach-s3c2400/Kconfig
@@ -1,13 +1,7 @@
-# arch/arm/mach-s3c2400/Kconfig
-#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
-
-
menu "S3C2400 Machines"
-
endmenu
-
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index 3d4e9da3fa52..7fcbdb923d79 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/mach-s3c2410/Kconfig
-#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
diff --git a/arch/arm/mach-s3c2412/Kconfig b/arch/arm/mach-s3c2412/Kconfig
index c2bdc4635d12..9a8c0657ae50 100644
--- a/arch/arm/mach-s3c2412/Kconfig
+++ b/arch/arm/mach-s3c2412/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/mach-s3c2412/Kconfig
-#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
@@ -90,6 +88,4 @@ config MACH_VSTMS
help
Say Y here if you are using an VSTMS board
-
endmenu
-
diff --git a/arch/arm/mach-s3c2440/Kconfig b/arch/arm/mach-s3c2440/Kconfig
index d7bba919a77e..16f523860cb8 100644
--- a/arch/arm/mach-s3c2440/Kconfig
+++ b/arch/arm/mach-s3c2440/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/mach-s3c2440/Kconfig
-#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
@@ -108,4 +106,3 @@ config MACH_MINI2440
available via various sources. It can come with a 3.5" or 7" touch LCD.
endmenu
-
diff --git a/arch/arm/mach-s3c2442/Kconfig b/arch/arm/mach-s3c2442/Kconfig
index 103e913f2258..8d3811852fc7 100644
--- a/arch/arm/mach-s3c2442/Kconfig
+++ b/arch/arm/mach-s3c2442/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/mach-s3c2442/Kconfig
-#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
@@ -36,6 +34,4 @@ config MACH_NEO1973_GTA02
help
Say Y here if you are using the Openmoko GTA02 / Freerunner GSM Phone
-
endmenu
-
diff --git a/arch/arm/mach-s3c2443/Kconfig b/arch/arm/mach-s3c2443/Kconfig
index 212141baebec..4314c4424909 100644
--- a/arch/arm/mach-s3c2443/Kconfig
+++ b/arch/arm/mach-s3c2443/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/mach-s3c2443/Kconfig
-#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
diff --git a/arch/arm/mach-s3c6400/Kconfig b/arch/arm/mach-s3c6400/Kconfig
index 770b72067e3d..a250bf68709f 100644
--- a/arch/arm/mach-s3c6400/Kconfig
+++ b/arch/arm/mach-s3c6400/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/mach-s3c6400/Kconfig
-#
# Copyright 2008 Openmoko, Inc.
# Simtec Electronics, Ben Dooks <ben@simtec.co.uk>
#
diff --git a/arch/arm/mach-s3c6410/Kconfig b/arch/arm/mach-s3c6410/Kconfig
index 53fc3ff657f7..b8c03322d842 100644
--- a/arch/arm/mach-s3c6410/Kconfig
+++ b/arch/arm/mach-s3c6410/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/mach-s3c6410/Kconfig
-#
# Copyright 2008 Openmoko, Inc.
# Copyright 2008 Simtec Electronics
#
diff --git a/arch/arm/mach-s5pc100/Kconfig b/arch/arm/mach-s5pc100/Kconfig
index b1a4ba504416..0793b9bb1c36 100644
--- a/arch/arm/mach-s5pc100/Kconfig
+++ b/arch/arm/mach-s5pc100/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/mach-s5pc100/Kconfig
-#
# Copyright 2009 Samsung Electronics Co.
# Byungho Min <bhmin@samsung.com>
#
diff --git a/arch/arm/mach-u300/Makefile b/arch/arm/mach-u300/Makefile
index 885b5c027c1e..fab46fe9a71f 100644
--- a/arch/arm/mach-u300/Makefile
+++ b/arch/arm/mach-u300/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_MMC) += mmc.o
obj-$(CONFIG_SPI_PL022) += spi.o
obj-$(CONFIG_MACH_U300_SPIDUMMY) += dummyspichip.o
obj-$(CONFIG_I2C_STU300) += i2c.o
+obj-$(CONFIG_REGULATOR_AB3100) += regulator.o
diff --git a/arch/arm/mach-u300/i2c.c b/arch/arm/mach-u300/i2c.c
index 10be1f888b27..7bc2503f6442 100644
--- a/arch/arm/mach-u300/i2c.c
+++ b/arch/arm/mach-u300/i2c.c
@@ -9,13 +9,256 @@
*/
#include <linux/kernel.h>
#include <linux/i2c.h>
+#include <linux/mfd/ab3100.h>
+#include <linux/regulator/machine.h>
+#include <linux/amba/bus.h>
#include <mach/irqs.h>
+/*
+ * Initial settings of ab3100 registers.
+ * Common for below LDO regulator settings are that
+ * bit 7-5 controls voltage. Bit 4 turns regulator ON(1) or OFF(0).
+ * Bit 3-2 controls sleep enable and bit 1-0 controls sleep mode.
+ */
+
+/* LDO_A 0x16: 2.75V, ON, SLEEP_A, SLEEP OFF GND */
+#define LDO_A_SETTING 0x16
+/* LDO_C 0x10: 2.65V, ON, SLEEP_A or B, SLEEP full power */
+#define LDO_C_SETTING 0x10
+/* LDO_D 0x10: 2.65V, ON, sleep mode not used */
+#define LDO_D_SETTING 0x10
+/* LDO_E 0x10: 1.8V, ON, SLEEP_A or B, SLEEP full power */
+#define LDO_E_SETTING 0x10
+/* LDO_E SLEEP 0x00: 1.8V, not used, SLEEP_A or B, not used */
+#define LDO_E_SLEEP_SETTING 0x00
+/* LDO_F 0xD0: 2.5V, ON, SLEEP_A or B, SLEEP full power */
+#define LDO_F_SETTING 0xD0
+/* LDO_G 0x00: 2.85V, OFF, SLEEP_A or B, SLEEP full power */
+#define LDO_G_SETTING 0x00
+/* LDO_H 0x18: 2.75V, ON, SLEEP_B, SLEEP full power */
+#define LDO_H_SETTING 0x18
+/* LDO_K 0x00: 2.75V, OFF, SLEEP_A or B, SLEEP full power */
+#define LDO_K_SETTING 0x00
+/* LDO_EXT 0x00: Voltage not set, OFF, not used, not used */
+#define LDO_EXT_SETTING 0x00
+/* BUCK 0x7D: 1.2V, ON, SLEEP_A and B, SLEEP low power */
+#define BUCK_SETTING 0x7D
+/* BUCK SLEEP 0xAC: 1.05V, Not used, SLEEP_A and B, Not used */
+#define BUCK_SLEEP_SETTING 0xAC
+
+static struct regulator_consumer_supply supply_ldo_c[] = {
+ {
+ .dev_name = "ab3100-codec",
+ .supply = "vaudio", /* Powers the codec */
+ },
+};
+
+/*
+ * This one needs to be a supply so we can turn it off
+ * in order to shut down the system.
+ */
+static struct regulator_consumer_supply supply_ldo_d[] = {
+ {
+ .dev = NULL,
+ .supply = "vana15", /* Powers the SoC (CPU etc) */
+ },
+};
+
+static struct regulator_consumer_supply supply_ldo_g[] = {
+ {
+ .dev_name = "mmci",
+ .supply = "vmmc", /* Powers MMC/SD card */
+ },
+};
+
+static struct regulator_consumer_supply supply_ldo_h[] = {
+ {
+ .dev_name = "xgam_pdi",
+ .supply = "vdisp", /* Powers camera, display etc */
+ },
+};
+
+static struct regulator_consumer_supply supply_ldo_k[] = {
+ {
+ .dev_name = "irda",
+ .supply = "vir", /* Power IrDA */
+ },
+};
+
+/*
+ * This is a placeholder for whoever wish to use the
+ * external power.
+ */
+static struct regulator_consumer_supply supply_ldo_ext[] = {
+ {
+ .dev = NULL,
+ .supply = "vext", /* External power */
+ },
+};
+
+/* Preset (hardware defined) voltages for these regulators */
+#define LDO_A_VOLTAGE 2750000
+#define LDO_C_VOLTAGE 2650000
+#define LDO_D_VOLTAGE 2650000
+
+static struct ab3100_platform_data ab3100_plf_data = {
+ .reg_constraints = {
+ /* LDO A routing and constraints */
+ {
+ .constraints = {
+ .name = "vrad",
+ .min_uV = LDO_A_VOLTAGE,
+ .max_uV = LDO_A_VOLTAGE,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .always_on = 1,
+ .boot_on = 1,
+ },
+ },
+ /* LDO C routing and constraints */
+ {
+ .constraints = {
+ .min_uV = LDO_C_VOLTAGE,
+ .max_uV = LDO_C_VOLTAGE,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(supply_ldo_c),
+ .consumer_supplies = supply_ldo_c,
+ },
+ /* LDO D routing and constraints */
+ {
+ .constraints = {
+ .min_uV = LDO_D_VOLTAGE,
+ .max_uV = LDO_D_VOLTAGE,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ /*
+ * Actually this is boot_on but we need
+ * to reference count it externally to
+ * be able to shut down the system.
+ */
+ },
+ .num_consumer_supplies = ARRAY_SIZE(supply_ldo_d),
+ .consumer_supplies = supply_ldo_d,
+ },
+ /* LDO E routing and constraints */
+ {
+ .constraints = {
+ .name = "vio",
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask =
+ REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ .always_on = 1,
+ .boot_on = 1,
+ },
+ },
+ /* LDO F routing and constraints */
+ {
+ .constraints = {
+ .name = "vana25",
+ .min_uV = 2500000,
+ .max_uV = 2500000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask =
+ REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ .always_on = 1,
+ .boot_on = 1,
+ },
+ },
+ /* LDO G routing and constraints */
+ {
+ .constraints = {
+ .min_uV = 1500000,
+ .max_uV = 2850000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask =
+ REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(supply_ldo_g),
+ .consumer_supplies = supply_ldo_g,
+ },
+ /* LDO H routing and constraints */
+ {
+ .constraints = {
+ .min_uV = 1200000,
+ .max_uV = 2750000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask =
+ REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(supply_ldo_h),
+ .consumer_supplies = supply_ldo_h,
+ },
+ /* LDO K routing and constraints */
+ {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 2750000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask =
+ REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(supply_ldo_k),
+ .consumer_supplies = supply_ldo_k,
+ },
+ /* External regulator interface. No fixed voltage specified.
+ * If we knew the voltage of the external regulator and it
+ * was connected on the board, we could add the (fixed)
+ * voltage for it here.
+ */
+ {
+ .constraints = {
+ .min_uV = 0,
+ .max_uV = 0,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask =
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(supply_ldo_ext),
+ .consumer_supplies = supply_ldo_ext,
+ },
+ /* Buck converter routing and constraints */
+ {
+ .constraints = {
+ .name = "vcore",
+ .min_uV = 1200000,
+ .max_uV = 1800000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask =
+ REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ .always_on = 1,
+ .boot_on = 1,
+ },
+ },
+ },
+ .reg_initvals = {
+ LDO_A_SETTING,
+ LDO_C_SETTING,
+ LDO_E_SETTING,
+ LDO_E_SLEEP_SETTING,
+ LDO_F_SETTING,
+ LDO_G_SETTING,
+ LDO_H_SETTING,
+ LDO_K_SETTING,
+ LDO_EXT_SETTING,
+ BUCK_SETTING,
+ BUCK_SLEEP_SETTING,
+ LDO_D_SETTING,
+ },
+};
+
static struct i2c_board_info __initdata bus0_i2c_board_info[] = {
{
.type = "ab3100",
.addr = 0x48,
.irq = IRQ_U300_IRQ0_EXT,
+ .platform_data = &ab3100_plf_data,
},
};
@@ -38,6 +281,11 @@ void __init u300_i2c_register_board_devices(void)
{
i2c_register_board_info(0, bus0_i2c_board_info,
ARRAY_SIZE(bus0_i2c_board_info));
+ /*
+ * This makes the core shut down all unused regulators
+ * after all the initcalls have completed.
+ */
+ regulator_has_full_constraints();
i2c_register_board_info(1, bus1_i2c_board_info,
ARRAY_SIZE(bus1_i2c_board_info));
}
diff --git a/arch/arm/mach-u300/mmc.c b/arch/arm/mach-u300/mmc.c
index 7b6b016786bb..109f5a6e71c7 100644
--- a/arch/arm/mach-u300/mmc.c
+++ b/arch/arm/mach-u300/mmc.c
@@ -40,64 +40,6 @@ static unsigned int mmc_status(struct device *dev)
return mmci_card->mmc_inserted;
}
-/*
- * Here follows a large chunk of code which will only be enabled if you
- * have both the AB3100 chip mounted and the MMC subsystem activated.
- */
-
-static u32 mmc_translate_vdd(struct device *dev, unsigned int voltage)
-{
- int v;
-
- /*
- * MMC Spec:
- * bit 7: 1.70 - 1.95V
- * bit 8 - 14: 2.0 - 2.6V
- * bit 15 - 23: 2.7 - 3.6V
- *
- * ab3100 voltages:
- * 000 - 2.85V
- * 001 - 2.75V
- * 010 - 1.8V
- * 011 - 1.5V
- */
- switch (voltage) {
- case 8:
- v = 3;
- break;
- case 9:
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 15:
- v = 1;
- break;
- case 16:
- v = 1;
- break;
- case 17:
- case 18:
- case 19:
- case 20:
- case 21:
- case 22:
- case 23:
- case 24:
- v = 0;
- break;
- default:
- v = 0;
- break;
- }
-
- /* PL180 voltage register bits */
- return v << 2;
-}
-
-
-
static int mmci_callback(void *data)
{
struct mmci_card_event *mmci_card = data;
@@ -154,9 +96,11 @@ int __devinit mmc_init(struct amba_device *adev)
if (!mmci_card)
return -ENOMEM;
+ /*
+ * Do not set ocr_mask or voltage translation function,
+ * we have a regulator we can control instead.
+ */
/* Nominally 2.85V on our platform */
- mmci_card->mmc0_plat_data.ocr_mask = MMC_VDD_28_29;
- mmci_card->mmc0_plat_data.translate_vdd = mmc_translate_vdd;
mmci_card->mmc0_plat_data.status = mmc_status;
mmci_card->mmc0_plat_data.gpio_wp = -1;
mmci_card->mmc0_plat_data.gpio_cd = -1;
diff --git a/arch/arm/mach-u300/regulator.c b/arch/arm/mach-u300/regulator.c
new file mode 100644
index 000000000000..9c53f01c62eb
--- /dev/null
+++ b/arch/arm/mach-u300/regulator.c
@@ -0,0 +1,88 @@
+/*
+ * arch/arm/mach-u300/regulator.c
+ *
+ * Copyright (C) 2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Handle board-bound regulators and board power not related
+ * to any devices.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+#include <linux/device.h>
+#include <linux/signal.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+/* Those are just for writing in syscon */
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include <mach/syscon.h>
+
+/*
+ * Regulators that power the board and chip and which are
+ * not copuled to specific drivers are hogged in these
+ * instances.
+ */
+static struct regulator *main_power_15;
+
+/*
+ * This function is used from pm.h to shut down the system by
+ * resetting all regulators in turn and then disable regulator
+ * LDO D (main power).
+ */
+void u300_pm_poweroff(void)
+{
+ sigset_t old, all;
+
+ sigfillset(&all);
+ if (!sigprocmask(SIG_BLOCK, &all, &old)) {
+ /* Disable LDO D to shut down the system */
+ if (main_power_15)
+ regulator_disable(main_power_15);
+ else
+ pr_err("regulator not available to shut down system\n");
+ (void) sigprocmask(SIG_SETMASK, &old, NULL);
+ }
+ return;
+}
+
+/*
+ * Hog the regulators needed to power up the board.
+ */
+static int __init u300_init_boardpower(void)
+{
+ int err;
+ u32 val;
+
+ pr_info("U300: setting up board power\n");
+ main_power_15 = regulator_get(NULL, "vana15");
+ if (IS_ERR(main_power_15)) {
+ pr_err("could not get vana15");
+ return PTR_ERR(main_power_15);
+ }
+ err = regulator_enable(main_power_15);
+ if (err) {
+ pr_err("could not enable vana15\n");
+ return err;
+ }
+
+ /*
+ * On U300 a special system controller register pulls up the DC
+ * until the vana15 (LDO D) regulator comes up. At this point, all
+ * regulators are set and we do not need power control via
+ * DC ON anymore. This function will likely be moved whenever
+ * the rest of the U300 power management is implemented.
+ */
+ pr_info("U300: disable system controller pull-up\n");
+ val = readw(U300_SYSCON_VBASE + U300_SYSCON_PMCR);
+ val &= ~U300_SYSCON_PMCR_DCON_ENABLE;
+ writew(val, U300_SYSCON_VBASE + U300_SYSCON_PMCR);
+
+ /* Register globally exported PM poweroff hook */
+ pm_power_off = u300_pm_poweroff;
+
+ return 0;
+}
+
+/*
+ * So at module init time we hog the regulator!
+ */
+module_init(u300_init_boardpower);
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index e993140edd88..9264d814cd7a 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -122,10 +122,7 @@ config CPU_ARM920T
select CPU_TLB_V4WBI if MMU
help
The ARM920T is licensed to be produced by numerous vendors,
- and is used in the Maverick EP9312 and the Samsung S3C2410.
-
- More information on the Maverick EP9312 at
- <http://linuxdevices.com/products/PD2382866068.html>.
+ and is used in the Cirrus EP93xx and the Samsung S3C2410.
Say Y if you want support for the ARM920T processor.
Otherwise, say N.
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 02243eeccf50..fa449bb25d6e 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -874,7 +874,7 @@ void __init reserve_node_zero(pg_data_t *pgdat)
BOOTMEM_EXCLUSIVE);
}
- if (machine_is_treo680()) {
+ if (machine_is_treo680() || machine_is_centro()) {
reserve_bootmem_node(pgdat, 0xa0000000, 0x1000,
BOOTMEM_EXCLUSIVE);
reserve_bootmem_node(pgdat, 0xa2000000, 0x1000,
diff --git a/arch/arm/oprofile/op_model_v6.c b/arch/arm/oprofile/op_model_v6.c
index fe581383d3e2..f7d2ec5ee9a1 100644
--- a/arch/arm/oprofile/op_model_v6.c
+++ b/arch/arm/oprofile/op_model_v6.c
@@ -33,6 +33,9 @@ static int irqs[] = {
#ifdef CONFIG_ARCH_OMAP2
3,
#endif
+#ifdef CONFIG_ARCH_BCMRING
+ IRQ_PMUIRQ, /* for BCMRING, ARM PMU interrupt is 43 */
+#endif
};
static void armv6_pmu_stop(void)
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index bf880e966d3b..681bfc37ebb2 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -24,7 +24,7 @@
#include <linux/debugfs.h>
#include <linux/io.h>
-#include <mach/clock.h>
+#include <plat/clock.h>
static LIST_HEAD(clocks);
static DEFINE_MUTEX(clocks_mutex);
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
index 3a4768d55895..cc050b3313bd 100644
--- a/arch/arm/plat-omap/common.c
+++ b/arch/arm/plat-omap/common.c
@@ -29,13 +29,13 @@
#include <asm/mach/map.h>
#include <asm/setup.h>
-#include <mach/common.h>
-#include <mach/board.h>
-#include <mach/control.h>
-#include <mach/mux.h>
-#include <mach/fpga.h>
+#include <plat/common.h>
+#include <plat/board.h>
+#include <plat/control.h>
+#include <plat/mux.h>
+#include <plat/fpga.h>
-#include <mach/clock.h>
+#include <plat/clock.h>
#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
# include "../mach-omap2/sdrc.h"
@@ -49,6 +49,9 @@ int omap_bootloader_tag_len;
struct omap_board_config_kernel *omap_board_config;
int omap_board_config_size;
+/* used by omap-smp.c and board-4430sdp.c */
+void __iomem *gic_cpu_base_addr;
+
static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
{
struct omap_board_config_kernel *kinfo = NULL;
@@ -224,12 +227,12 @@ static void __init __omap2_set_globals(struct omap_globals *omap2_globals)
static struct omap_globals omap242x_globals = {
.class = OMAP242X_CLASS,
- .tap = OMAP2_IO_ADDRESS(0x48014000),
- .sdrc = OMAP2_IO_ADDRESS(OMAP2420_SDRC_BASE),
- .sms = OMAP2_IO_ADDRESS(OMAP2420_SMS_BASE),
- .ctrl = OMAP2_IO_ADDRESS(OMAP2420_CTRL_BASE),
- .prm = OMAP2_IO_ADDRESS(OMAP2420_PRM_BASE),
- .cm = OMAP2_IO_ADDRESS(OMAP2420_CM_BASE),
+ .tap = OMAP2_L4_IO_ADDRESS(0x48014000),
+ .sdrc = OMAP2_L3_IO_ADDRESS(OMAP2420_SDRC_BASE),
+ .sms = OMAP2_L3_IO_ADDRESS(OMAP2420_SMS_BASE),
+ .ctrl = OMAP2_L4_IO_ADDRESS(OMAP2420_CTRL_BASE),
+ .prm = OMAP2_L4_IO_ADDRESS(OMAP2420_PRM_BASE),
+ .cm = OMAP2_L4_IO_ADDRESS(OMAP2420_CM_BASE),
};
void __init omap2_set_globals_242x(void)
@@ -242,12 +245,12 @@ void __init omap2_set_globals_242x(void)
static struct omap_globals omap243x_globals = {
.class = OMAP243X_CLASS,
- .tap = OMAP2_IO_ADDRESS(0x4900a000),
- .sdrc = OMAP2_IO_ADDRESS(OMAP243X_SDRC_BASE),
- .sms = OMAP2_IO_ADDRESS(OMAP243X_SMS_BASE),
- .ctrl = OMAP2_IO_ADDRESS(OMAP243X_CTRL_BASE),
- .prm = OMAP2_IO_ADDRESS(OMAP2430_PRM_BASE),
- .cm = OMAP2_IO_ADDRESS(OMAP2430_CM_BASE),
+ .tap = OMAP2_L4_IO_ADDRESS(0x4900a000),
+ .sdrc = OMAP2_L3_IO_ADDRESS(OMAP243X_SDRC_BASE),
+ .sms = OMAP2_L3_IO_ADDRESS(OMAP243X_SMS_BASE),
+ .ctrl = OMAP2_L4_IO_ADDRESS(OMAP243X_CTRL_BASE),
+ .prm = OMAP2_L4_IO_ADDRESS(OMAP2430_PRM_BASE),
+ .cm = OMAP2_L4_IO_ADDRESS(OMAP2430_CM_BASE),
};
void __init omap2_set_globals_243x(void)
@@ -260,12 +263,12 @@ void __init omap2_set_globals_243x(void)
static struct omap_globals omap343x_globals = {
.class = OMAP343X_CLASS,
- .tap = OMAP2_IO_ADDRESS(0x4830A000),
- .sdrc = OMAP2_IO_ADDRESS(OMAP343X_SDRC_BASE),
- .sms = OMAP2_IO_ADDRESS(OMAP343X_SMS_BASE),
- .ctrl = OMAP2_IO_ADDRESS(OMAP343X_CTRL_BASE),
- .prm = OMAP2_IO_ADDRESS(OMAP3430_PRM_BASE),
- .cm = OMAP2_IO_ADDRESS(OMAP3430_CM_BASE),
+ .tap = OMAP2_L4_IO_ADDRESS(0x4830A000),
+ .sdrc = OMAP2_L3_IO_ADDRESS(OMAP343X_SDRC_BASE),
+ .sms = OMAP2_L3_IO_ADDRESS(OMAP343X_SMS_BASE),
+ .ctrl = OMAP2_L4_IO_ADDRESS(OMAP343X_CTRL_BASE),
+ .prm = OMAP2_L4_IO_ADDRESS(OMAP3430_PRM_BASE),
+ .cm = OMAP2_L4_IO_ADDRESS(OMAP3430_CM_BASE),
};
void __init omap2_set_globals_343x(void)
@@ -277,10 +280,10 @@ void __init omap2_set_globals_343x(void)
#if defined(CONFIG_ARCH_OMAP4)
static struct omap_globals omap4_globals = {
.class = OMAP443X_CLASS,
- .tap = OMAP2_IO_ADDRESS(0x4830a000),
- .ctrl = OMAP2_IO_ADDRESS(OMAP443X_CTRL_BASE),
- .prm = OMAP2_IO_ADDRESS(OMAP4430_PRM_BASE),
- .cm = OMAP2_IO_ADDRESS(OMAP4430_CM_BASE),
+ .tap = OMAP2_L4_IO_ADDRESS(0x4830a000),
+ .ctrl = OMAP2_L4_IO_ADDRESS(OMAP443X_CTRL_BASE),
+ .prm = OMAP2_L4_IO_ADDRESS(OMAP4430_PRM_BASE),
+ .cm = OMAP2_L4_IO_ADDRESS(OMAP4430_CM_BASE),
};
void __init omap2_set_globals_443x(void)
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
index 1868c0d8f9b5..4e85389c861a 100644
--- a/arch/arm/plat-omap/cpu-omap.c
+++ b/arch/arm/plat-omap/cpu-omap.c
@@ -23,7 +23,7 @@
#include <linux/io.h>
#include <mach/hardware.h>
-#include <mach/clock.h>
+#include <plat/clock.h>
#include <asm/system.h>
#define VERY_HI_RATE 900000000
diff --git a/arch/arm/plat-omap/debug-devices.c b/arch/arm/plat-omap/debug-devices.c
index f6684832ca8f..09c1107637f6 100644
--- a/arch/arm/plat-omap/debug-devices.c
+++ b/arch/arm/plat-omap/debug-devices.c
@@ -16,7 +16,7 @@
#include <mach/hardware.h>
-#include <mach/board.h>
+#include <plat/board.h>
#include <mach/gpio.h>
diff --git a/arch/arm/plat-omap/debug-leds.c b/arch/arm/plat-omap/debug-leds.c
index 9395898dd49a..6c768b71ad64 100644
--- a/arch/arm/plat-omap/debug-leds.c
+++ b/arch/arm/plat-omap/debug-leds.c
@@ -18,7 +18,7 @@
#include <asm/system.h>
#include <asm/mach-types.h>
-#include <mach/fpga.h>
+#include <plat/fpga.h>
#include <mach/gpio.h>
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
index a64b692a1bfe..f86617869b38 100644
--- a/arch/arm/plat-omap/devices.c
+++ b/arch/arm/plat-omap/devices.c
@@ -19,15 +19,15 @@
#include <asm/mach-types.h>
#include <asm/mach/map.h>
-#include <mach/tc.h>
-#include <mach/control.h>
-#include <mach/board.h>
-#include <mach/mmc.h>
-#include <mach/mux.h>
+#include <plat/tc.h>
+#include <plat/control.h>
+#include <plat/board.h>
+#include <plat/mmc.h>
+#include <plat/mux.h>
#include <mach/gpio.h>
-#include <mach/menelaus.h>
-#include <mach/mcbsp.h>
-#include <mach/dsp_common.h>
+#include <plat/menelaus.h>
+#include <plat/mcbsp.h>
+#include <plat/dsp_common.h>
#if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
@@ -113,17 +113,17 @@ static void omap_init_kp(void)
omap_cfg_reg(E19_1610_KBR4);
omap_cfg_reg(N19_1610_KBR5);
} else if (machine_is_omap_perseus2() || machine_is_omap_fsample()) {
- omap_cfg_reg(E2_730_KBR0);
- omap_cfg_reg(J7_730_KBR1);
- omap_cfg_reg(E1_730_KBR2);
- omap_cfg_reg(F3_730_KBR3);
- omap_cfg_reg(D2_730_KBR4);
-
- omap_cfg_reg(C2_730_KBC0);
- omap_cfg_reg(D3_730_KBC1);
- omap_cfg_reg(E4_730_KBC2);
- omap_cfg_reg(F4_730_KBC3);
- omap_cfg_reg(E3_730_KBC4);
+ omap_cfg_reg(E2_7XX_KBR0);
+ omap_cfg_reg(J7_7XX_KBR1);
+ omap_cfg_reg(E1_7XX_KBR2);
+ omap_cfg_reg(F3_7XX_KBR3);
+ omap_cfg_reg(D2_7XX_KBR4);
+
+ omap_cfg_reg(C2_7XX_KBC0);
+ omap_cfg_reg(D3_7XX_KBC1);
+ omap_cfg_reg(E4_7XX_KBC2);
+ omap_cfg_reg(F4_7XX_KBC3);
+ omap_cfg_reg(E3_7XX_KBC4);
} else if (machine_is_omap_h4()) {
omap_cfg_reg(T19_24XX_KBR0);
omap_cfg_reg(R19_24XX_KBR1);
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index 0eb676d7e807..9e11cddf3f72 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -32,9 +32,9 @@
#include <asm/system.h>
#include <mach/hardware.h>
-#include <mach/dma.h>
+#include <plat/dma.h>
-#include <mach/tc.h>
+#include <plat/tc.h>
#undef DEBUG
@@ -2347,40 +2347,46 @@ EXPORT_SYMBOL(omap_stop_lcd_dma);
static int __init omap_init_dma(void)
{
+ unsigned long base;
int ch, r;
if (cpu_class_is_omap1()) {
- omap_dma_base = OMAP1_IO_ADDRESS(OMAP1_DMA_BASE);
+ base = OMAP1_DMA_BASE;
dma_lch_count = OMAP1_LOGICAL_DMA_CH_COUNT;
} else if (cpu_is_omap24xx()) {
- omap_dma_base = OMAP2_IO_ADDRESS(OMAP24XX_DMA4_BASE);
+ base = OMAP24XX_DMA4_BASE;
dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT;
} else if (cpu_is_omap34xx()) {
- omap_dma_base = OMAP2_IO_ADDRESS(OMAP34XX_DMA4_BASE);
+ base = OMAP34XX_DMA4_BASE;
dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT;
} else if (cpu_is_omap44xx()) {
- omap_dma_base = OMAP2_IO_ADDRESS(OMAP44XX_DMA4_BASE);
+ base = OMAP44XX_DMA4_BASE;
dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT;
} else {
pr_err("DMA init failed for unsupported omap\n");
return -ENODEV;
}
+ omap_dma_base = ioremap(base, SZ_4K);
+ BUG_ON(!omap_dma_base);
+
if (cpu_class_is_omap2() && omap_dma_reserve_channels
&& (omap_dma_reserve_channels <= dma_lch_count))
dma_lch_count = omap_dma_reserve_channels;
dma_chan = kzalloc(sizeof(struct omap_dma_lch) * dma_lch_count,
GFP_KERNEL);
- if (!dma_chan)
- return -ENOMEM;
+ if (!dma_chan) {
+ r = -ENOMEM;
+ goto out_unmap;
+ }
if (cpu_class_is_omap2()) {
dma_linked_lch = kzalloc(sizeof(struct dma_link_info) *
dma_lch_count, GFP_KERNEL);
if (!dma_linked_lch) {
- kfree(dma_chan);
- return -ENOMEM;
+ r = -ENOMEM;
+ goto out_free;
}
}
@@ -2454,7 +2460,7 @@ static int __init omap_init_dma(void)
for (i = 0; i < ch; i++)
free_irq(omap1_dma_irq[i],
(void *) (i + 1));
- return r;
+ goto out_free;
}
}
}
@@ -2496,11 +2502,19 @@ static int __init omap_init_dma(void)
"(error %d)\n", r);
for (i = 0; i < dma_chan_count; i++)
free_irq(omap1_dma_irq[i], (void *) (i + 1));
- return r;
+ goto out_free;
}
}
return 0;
+
+out_free:
+ kfree(dma_chan);
+
+out_unmap:
+ iounmap(omap_dma_base);
+
+ return r;
}
arch_initcall(omap_init_dma);
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index d325b54daeb5..64f407ee0f4e 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -38,7 +38,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <mach/hardware.h>
-#include <mach/dmtimer.h>
+#include <plat/dmtimer.h>
#include <mach/irqs.h>
/* register offsets */
@@ -742,16 +742,17 @@ EXPORT_SYMBOL_GPL(omap_dm_timers_active);
int __init omap_dm_timer_init(void)
{
struct omap_dm_timer *timer;
- int i;
+ int i, map_size = SZ_8K; /* Module 4KB + L4 4KB except on omap1 */
if (!(cpu_is_omap16xx() || cpu_class_is_omap2()))
return -ENODEV;
spin_lock_init(&dm_timer_lock);
- if (cpu_class_is_omap1())
+ if (cpu_class_is_omap1()) {
dm_timers = omap1_dm_timers;
- else if (cpu_is_omap24xx()) {
+ map_size = SZ_2K;
+ } else if (cpu_is_omap24xx()) {
dm_timers = omap2_dm_timers;
dm_source_names = omap2_dm_source_names;
dm_source_clocks = omap2_dm_source_clocks;
@@ -774,10 +775,11 @@ int __init omap_dm_timer_init(void)
for (i = 0; i < dm_timer_count; i++) {
timer = &dm_timers[i];
- if (cpu_class_is_omap1())
- timer->io_base = OMAP1_IO_ADDRESS(timer->phys_base);
- else
- timer->io_base = OMAP2_IO_ADDRESS(timer->phys_base);
+
+ /* Static mapping, never released */
+ timer->io_base = ioremap(timer->phys_base, map_size);
+ BUG_ON(!timer->io_base);
+
#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
defined(CONFIG_ARCH_OMAP4)
if (cpu_class_is_omap2()) {
diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c
index 3746222bed10..78a4ce538dbd 100644
--- a/arch/arm/plat-omap/fb.c
+++ b/arch/arm/plat-omap/fb.c
@@ -32,9 +32,9 @@
#include <mach/hardware.h>
#include <asm/mach/map.h>
-#include <mach/board.h>
-#include <mach/sram.h>
-#include <mach/omapfb.h>
+#include <plat/board.h>
+#include <plat/sram.h>
+#include <plat/omapfb.h>
#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index 71ebd7fcfea1..35a59ce5a2b4 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -31,7 +31,7 @@
/*
* OMAP1510 GPIO registers
*/
-#define OMAP1510_GPIO_BASE OMAP1_IO_ADDRESS(0xfffce000)
+#define OMAP1510_GPIO_BASE 0xfffce000
#define OMAP1510_GPIO_DATA_INPUT 0x00
#define OMAP1510_GPIO_DATA_OUTPUT 0x04
#define OMAP1510_GPIO_DIR_CONTROL 0x08
@@ -45,10 +45,10 @@
/*
* OMAP1610 specific GPIO registers
*/
-#define OMAP1610_GPIO1_BASE OMAP1_IO_ADDRESS(0xfffbe400)
-#define OMAP1610_GPIO2_BASE OMAP1_IO_ADDRESS(0xfffbec00)
-#define OMAP1610_GPIO3_BASE OMAP1_IO_ADDRESS(0xfffbb400)
-#define OMAP1610_GPIO4_BASE OMAP1_IO_ADDRESS(0xfffbbc00)
+#define OMAP1610_GPIO1_BASE 0xfffbe400
+#define OMAP1610_GPIO2_BASE 0xfffbec00
+#define OMAP1610_GPIO3_BASE 0xfffbb400
+#define OMAP1610_GPIO4_BASE 0xfffbbc00
#define OMAP1610_GPIO_REVISION 0x0000
#define OMAP1610_GPIO_SYSCONFIG 0x0010
#define OMAP1610_GPIO_SYSSTATUS 0x0014
@@ -68,52 +68,36 @@
#define OMAP1610_GPIO_SET_DATAOUT 0x00f0
/*
- * OMAP730 specific GPIO registers
+ * OMAP7XX specific GPIO registers
*/
-#define OMAP730_GPIO1_BASE OMAP1_IO_ADDRESS(0xfffbc000)
-#define OMAP730_GPIO2_BASE OMAP1_IO_ADDRESS(0xfffbc800)
-#define OMAP730_GPIO3_BASE OMAP1_IO_ADDRESS(0xfffbd000)
-#define OMAP730_GPIO4_BASE OMAP1_IO_ADDRESS(0xfffbd800)
-#define OMAP730_GPIO5_BASE OMAP1_IO_ADDRESS(0xfffbe000)
-#define OMAP730_GPIO6_BASE OMAP1_IO_ADDRESS(0xfffbe800)
-#define OMAP730_GPIO_DATA_INPUT 0x00
-#define OMAP730_GPIO_DATA_OUTPUT 0x04
-#define OMAP730_GPIO_DIR_CONTROL 0x08
-#define OMAP730_GPIO_INT_CONTROL 0x0c
-#define OMAP730_GPIO_INT_MASK 0x10
-#define OMAP730_GPIO_INT_STATUS 0x14
-
-/*
- * OMAP850 specific GPIO registers
- */
-#define OMAP850_GPIO1_BASE OMAP1_IO_ADDRESS(0xfffbc000)
-#define OMAP850_GPIO2_BASE OMAP1_IO_ADDRESS(0xfffbc800)
-#define OMAP850_GPIO3_BASE OMAP1_IO_ADDRESS(0xfffbd000)
-#define OMAP850_GPIO4_BASE OMAP1_IO_ADDRESS(0xfffbd800)
-#define OMAP850_GPIO5_BASE OMAP1_IO_ADDRESS(0xfffbe000)
-#define OMAP850_GPIO6_BASE OMAP1_IO_ADDRESS(0xfffbe800)
-#define OMAP850_GPIO_DATA_INPUT 0x00
-#define OMAP850_GPIO_DATA_OUTPUT 0x04
-#define OMAP850_GPIO_DIR_CONTROL 0x08
-#define OMAP850_GPIO_INT_CONTROL 0x0c
-#define OMAP850_GPIO_INT_MASK 0x10
-#define OMAP850_GPIO_INT_STATUS 0x14
-
-#define OMAP1_MPUIO_VBASE OMAP1_IO_ADDRESS(OMAP1_MPUIO_BASE)
+#define OMAP7XX_GPIO1_BASE 0xfffbc000
+#define OMAP7XX_GPIO2_BASE 0xfffbc800
+#define OMAP7XX_GPIO3_BASE 0xfffbd000
+#define OMAP7XX_GPIO4_BASE 0xfffbd800
+#define OMAP7XX_GPIO5_BASE 0xfffbe000
+#define OMAP7XX_GPIO6_BASE 0xfffbe800
+#define OMAP7XX_GPIO_DATA_INPUT 0x00
+#define OMAP7XX_GPIO_DATA_OUTPUT 0x04
+#define OMAP7XX_GPIO_DIR_CONTROL 0x08
+#define OMAP7XX_GPIO_INT_CONTROL 0x0c
+#define OMAP7XX_GPIO_INT_MASK 0x10
+#define OMAP7XX_GPIO_INT_STATUS 0x14
+
+#define OMAP1_MPUIO_VBASE OMAP1_MPUIO_BASE
/*
* omap24xx specific GPIO registers
*/
-#define OMAP242X_GPIO1_BASE OMAP2_IO_ADDRESS(0x48018000)
-#define OMAP242X_GPIO2_BASE OMAP2_IO_ADDRESS(0x4801a000)
-#define OMAP242X_GPIO3_BASE OMAP2_IO_ADDRESS(0x4801c000)
-#define OMAP242X_GPIO4_BASE OMAP2_IO_ADDRESS(0x4801e000)
+#define OMAP242X_GPIO1_BASE 0x48018000
+#define OMAP242X_GPIO2_BASE 0x4801a000
+#define OMAP242X_GPIO3_BASE 0x4801c000
+#define OMAP242X_GPIO4_BASE 0x4801e000
-#define OMAP243X_GPIO1_BASE OMAP2_IO_ADDRESS(0x4900C000)
-#define OMAP243X_GPIO2_BASE OMAP2_IO_ADDRESS(0x4900E000)
-#define OMAP243X_GPIO3_BASE OMAP2_IO_ADDRESS(0x49010000)
-#define OMAP243X_GPIO4_BASE OMAP2_IO_ADDRESS(0x49012000)
-#define OMAP243X_GPIO5_BASE OMAP2_IO_ADDRESS(0x480B6000)
+#define OMAP243X_GPIO1_BASE 0x4900C000
+#define OMAP243X_GPIO2_BASE 0x4900E000
+#define OMAP243X_GPIO3_BASE 0x49010000
+#define OMAP243X_GPIO4_BASE 0x49012000
+#define OMAP243X_GPIO5_BASE 0x480B6000
#define OMAP24XX_GPIO_REVISION 0x0000
#define OMAP24XX_GPIO_SYSCONFIG 0x0010
@@ -170,24 +154,25 @@
* omap34xx specific GPIO registers
*/
-#define OMAP34XX_GPIO1_BASE OMAP2_IO_ADDRESS(0x48310000)
-#define OMAP34XX_GPIO2_BASE OMAP2_IO_ADDRESS(0x49050000)
-#define OMAP34XX_GPIO3_BASE OMAP2_IO_ADDRESS(0x49052000)
-#define OMAP34XX_GPIO4_BASE OMAP2_IO_ADDRESS(0x49054000)
-#define OMAP34XX_GPIO5_BASE OMAP2_IO_ADDRESS(0x49056000)
-#define OMAP34XX_GPIO6_BASE OMAP2_IO_ADDRESS(0x49058000)
+#define OMAP34XX_GPIO1_BASE 0x48310000
+#define OMAP34XX_GPIO2_BASE 0x49050000
+#define OMAP34XX_GPIO3_BASE 0x49052000
+#define OMAP34XX_GPIO4_BASE 0x49054000
+#define OMAP34XX_GPIO5_BASE 0x49056000
+#define OMAP34XX_GPIO6_BASE 0x49058000
/*
* OMAP44XX specific GPIO registers
*/
-#define OMAP44XX_GPIO1_BASE OMAP2_IO_ADDRESS(0x4a310000)
-#define OMAP44XX_GPIO2_BASE OMAP2_IO_ADDRESS(0x48055000)
-#define OMAP44XX_GPIO3_BASE OMAP2_IO_ADDRESS(0x48057000)
-#define OMAP44XX_GPIO4_BASE OMAP2_IO_ADDRESS(0x48059000)
-#define OMAP44XX_GPIO5_BASE OMAP2_IO_ADDRESS(0x4805B000)
-#define OMAP44XX_GPIO6_BASE OMAP2_IO_ADDRESS(0x4805D000)
+#define OMAP44XX_GPIO1_BASE 0x4a310000
+#define OMAP44XX_GPIO2_BASE 0x48055000
+#define OMAP44XX_GPIO3_BASE 0x48057000
+#define OMAP44XX_GPIO4_BASE 0x48059000
+#define OMAP44XX_GPIO5_BASE 0x4805B000
+#define OMAP44XX_GPIO6_BASE 0x4805D000
struct gpio_bank {
+ unsigned long pbase;
void __iomem *base;
u16 irq;
u16 virtual_irq_start;
@@ -215,96 +200,111 @@ struct gpio_bank {
#define METHOD_MPUIO 0
#define METHOD_GPIO_1510 1
#define METHOD_GPIO_1610 2
-#define METHOD_GPIO_730 3
-#define METHOD_GPIO_850 4
+#define METHOD_GPIO_7XX 3
#define METHOD_GPIO_24XX 5
#ifdef CONFIG_ARCH_OMAP16XX
static struct gpio_bank gpio_bank_1610[5] = {
- { OMAP1_MPUIO_VBASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO},
- { OMAP1610_GPIO1_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_1610 },
- { OMAP1610_GPIO2_BASE, INT_1610_GPIO_BANK2, IH_GPIO_BASE + 16, METHOD_GPIO_1610 },
- { OMAP1610_GPIO3_BASE, INT_1610_GPIO_BANK3, IH_GPIO_BASE + 32, METHOD_GPIO_1610 },
- { OMAP1610_GPIO4_BASE, INT_1610_GPIO_BANK4, IH_GPIO_BASE + 48, METHOD_GPIO_1610 },
+ { OMAP1_MPUIO_VBASE, NULL, INT_MPUIO, IH_MPUIO_BASE,
+ METHOD_MPUIO },
+ { OMAP1610_GPIO1_BASE, NULL, INT_GPIO_BANK1, IH_GPIO_BASE,
+ METHOD_GPIO_1610 },
+ { OMAP1610_GPIO2_BASE, NULL, INT_1610_GPIO_BANK2, IH_GPIO_BASE + 16,
+ METHOD_GPIO_1610 },
+ { OMAP1610_GPIO3_BASE, NULL, INT_1610_GPIO_BANK3, IH_GPIO_BASE + 32,
+ METHOD_GPIO_1610 },
+ { OMAP1610_GPIO4_BASE, NULL, INT_1610_GPIO_BANK4, IH_GPIO_BASE + 48,
+ METHOD_GPIO_1610 },
};
#endif
#ifdef CONFIG_ARCH_OMAP15XX
static struct gpio_bank gpio_bank_1510[2] = {
- { OMAP1_MPUIO_VBASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO },
- { OMAP1510_GPIO_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_1510 }
-};
-#endif
-
-#ifdef CONFIG_ARCH_OMAP730
-static struct gpio_bank gpio_bank_730[7] = {
- { OMAP1_MPUIO_VBASE, INT_730_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO },
- { OMAP730_GPIO1_BASE, INT_730_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_730 },
- { OMAP730_GPIO2_BASE, INT_730_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_730 },
- { OMAP730_GPIO3_BASE, INT_730_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_730 },
- { OMAP730_GPIO4_BASE, INT_730_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_730 },
- { OMAP730_GPIO5_BASE, INT_730_GPIO_BANK5, IH_GPIO_BASE + 128, METHOD_GPIO_730 },
- { OMAP730_GPIO6_BASE, INT_730_GPIO_BANK6, IH_GPIO_BASE + 160, METHOD_GPIO_730 },
+ { OMAP1_MPUIO_VBASE, NULL, INT_MPUIO, IH_MPUIO_BASE,
+ METHOD_MPUIO },
+ { OMAP1510_GPIO_BASE, NULL, INT_GPIO_BANK1, IH_GPIO_BASE,
+ METHOD_GPIO_1510 }
};
#endif
-#ifdef CONFIG_ARCH_OMAP850
-static struct gpio_bank gpio_bank_850[7] = {
- { OMAP1_MPUIO_VBASE, INT_850_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO },
- { OMAP850_GPIO1_BASE, INT_850_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_850 },
- { OMAP850_GPIO2_BASE, INT_850_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_850 },
- { OMAP850_GPIO3_BASE, INT_850_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_850 },
- { OMAP850_GPIO4_BASE, INT_850_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_850 },
- { OMAP850_GPIO5_BASE, INT_850_GPIO_BANK5, IH_GPIO_BASE + 128, METHOD_GPIO_850 },
- { OMAP850_GPIO6_BASE, INT_850_GPIO_BANK6, IH_GPIO_BASE + 160, METHOD_GPIO_850 },
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+static struct gpio_bank gpio_bank_7xx[7] = {
+ { OMAP1_MPUIO_VBASE, NULL, INT_7XX_MPUIO, IH_MPUIO_BASE,
+ METHOD_MPUIO },
+ { OMAP7XX_GPIO1_BASE, NULL, INT_7XX_GPIO_BANK1, IH_GPIO_BASE,
+ METHOD_GPIO_7XX },
+ { OMAP7XX_GPIO2_BASE, NULL, INT_7XX_GPIO_BANK2, IH_GPIO_BASE + 32,
+ METHOD_GPIO_7XX },
+ { OMAP7XX_GPIO3_BASE, NULL, INT_7XX_GPIO_BANK3, IH_GPIO_BASE + 64,
+ METHOD_GPIO_7XX },
+ { OMAP7XX_GPIO4_BASE, NULL, INT_7XX_GPIO_BANK4, IH_GPIO_BASE + 96,
+ METHOD_GPIO_7XX },
+ { OMAP7XX_GPIO5_BASE, NULL, INT_7XX_GPIO_BANK5, IH_GPIO_BASE + 128,
+ METHOD_GPIO_7XX },
+ { OMAP7XX_GPIO6_BASE, NULL, INT_7XX_GPIO_BANK6, IH_GPIO_BASE + 160,
+ METHOD_GPIO_7XX },
};
#endif
-
#ifdef CONFIG_ARCH_OMAP24XX
static struct gpio_bank gpio_bank_242x[4] = {
- { OMAP242X_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_24XX },
- { OMAP242X_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_24XX },
- { OMAP242X_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_24XX },
- { OMAP242X_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_24XX },
+ { OMAP242X_GPIO1_BASE, NULL, INT_24XX_GPIO_BANK1, IH_GPIO_BASE,
+ METHOD_GPIO_24XX },
+ { OMAP242X_GPIO2_BASE, NULL, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32,
+ METHOD_GPIO_24XX },
+ { OMAP242X_GPIO3_BASE, NULL, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64,
+ METHOD_GPIO_24XX },
+ { OMAP242X_GPIO4_BASE, NULL, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96,
+ METHOD_GPIO_24XX },
};
static struct gpio_bank gpio_bank_243x[5] = {
- { OMAP243X_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_24XX },
- { OMAP243X_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_24XX },
- { OMAP243X_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_24XX },
- { OMAP243X_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_24XX },
- { OMAP243X_GPIO5_BASE, INT_24XX_GPIO_BANK5, IH_GPIO_BASE + 128, METHOD_GPIO_24XX },
+ { OMAP243X_GPIO1_BASE, NULL, INT_24XX_GPIO_BANK1, IH_GPIO_BASE,
+ METHOD_GPIO_24XX },
+ { OMAP243X_GPIO2_BASE, NULL, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32,
+ METHOD_GPIO_24XX },
+ { OMAP243X_GPIO3_BASE, NULL, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64,
+ METHOD_GPIO_24XX },
+ { OMAP243X_GPIO4_BASE, NULL, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96,
+ METHOD_GPIO_24XX },
+ { OMAP243X_GPIO5_BASE, NULL, INT_24XX_GPIO_BANK5, IH_GPIO_BASE + 128,
+ METHOD_GPIO_24XX },
};
#endif
#ifdef CONFIG_ARCH_OMAP34XX
static struct gpio_bank gpio_bank_34xx[6] = {
- { OMAP34XX_GPIO1_BASE, INT_34XX_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_24XX },
- { OMAP34XX_GPIO2_BASE, INT_34XX_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_24XX },
- { OMAP34XX_GPIO3_BASE, INT_34XX_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_24XX },
- { OMAP34XX_GPIO4_BASE, INT_34XX_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_24XX },
- { OMAP34XX_GPIO5_BASE, INT_34XX_GPIO_BANK5, IH_GPIO_BASE + 128, METHOD_GPIO_24XX },
- { OMAP34XX_GPIO6_BASE, INT_34XX_GPIO_BANK6, IH_GPIO_BASE + 160, METHOD_GPIO_24XX },
+ { OMAP34XX_GPIO1_BASE, NULL, INT_34XX_GPIO_BANK1, IH_GPIO_BASE,
+ METHOD_GPIO_24XX },
+ { OMAP34XX_GPIO2_BASE, NULL, INT_34XX_GPIO_BANK2, IH_GPIO_BASE + 32,
+ METHOD_GPIO_24XX },
+ { OMAP34XX_GPIO3_BASE, NULL, INT_34XX_GPIO_BANK3, IH_GPIO_BASE + 64,
+ METHOD_GPIO_24XX },
+ { OMAP34XX_GPIO4_BASE, NULL, INT_34XX_GPIO_BANK4, IH_GPIO_BASE + 96,
+ METHOD_GPIO_24XX },
+ { OMAP34XX_GPIO5_BASE, NULL, INT_34XX_GPIO_BANK5, IH_GPIO_BASE + 128,
+ METHOD_GPIO_24XX },
+ { OMAP34XX_GPIO6_BASE, NULL, INT_34XX_GPIO_BANK6, IH_GPIO_BASE + 160,
+ METHOD_GPIO_24XX },
};
#endif
#ifdef CONFIG_ARCH_OMAP4
static struct gpio_bank gpio_bank_44xx[6] = {
- { OMAP44XX_GPIO1_BASE, INT_44XX_GPIO_BANK1, IH_GPIO_BASE, \
+ { OMAP44XX_GPIO1_BASE, NULL, INT_44XX_GPIO_BANK1, IH_GPIO_BASE,
METHOD_GPIO_24XX },
- { OMAP44XX_GPIO2_BASE, INT_44XX_GPIO_BANK2, IH_GPIO_BASE + 32, \
+ { OMAP44XX_GPIO2_BASE, NULL, INT_44XX_GPIO_BANK2, IH_GPIO_BASE + 32,
METHOD_GPIO_24XX },
- { OMAP44XX_GPIO3_BASE, INT_44XX_GPIO_BANK3, IH_GPIO_BASE + 64, \
+ { OMAP44XX_GPIO3_BASE, NULL, INT_44XX_GPIO_BANK3, IH_GPIO_BASE + 64,
METHOD_GPIO_24XX },
- { OMAP44XX_GPIO4_BASE, INT_44XX_GPIO_BANK4, IH_GPIO_BASE + 96, \
+ { OMAP44XX_GPIO4_BASE, NULL, INT_44XX_GPIO_BANK4, IH_GPIO_BASE + 96,
METHOD_GPIO_24XX },
- { OMAP44XX_GPIO5_BASE, INT_44XX_GPIO_BANK5, IH_GPIO_BASE + 128, \
+ { OMAP44XX_GPIO5_BASE, NULL, INT_44XX_GPIO_BANK5, IH_GPIO_BASE + 128,
METHOD_GPIO_24XX },
- { OMAP44XX_GPIO6_BASE, INT_44XX_GPIO_BANK6, IH_GPIO_BASE + 160, \
+ { OMAP44XX_GPIO6_BASE, NULL, INT_44XX_GPIO_BANK6, IH_GPIO_BASE + 160,
METHOD_GPIO_24XX },
};
@@ -402,14 +402,9 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
reg += OMAP1610_GPIO_DIRECTION;
break;
#endif
-#ifdef CONFIG_ARCH_OMAP730
- case METHOD_GPIO_730:
- reg += OMAP730_GPIO_DIR_CONTROL;
- break;
-#endif
-#ifdef CONFIG_ARCH_OMAP850
- case METHOD_GPIO_850:
- reg += OMAP850_GPIO_DIR_CONTROL;
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+ case METHOD_GPIO_7XX:
+ reg += OMAP7XX_GPIO_DIR_CONTROL;
break;
#endif
#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
@@ -469,19 +464,9 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
l = 1 << gpio;
break;
#endif
-#ifdef CONFIG_ARCH_OMAP730
- case METHOD_GPIO_730:
- reg += OMAP730_GPIO_DATA_OUTPUT;
- l = __raw_readl(reg);
- if (enable)
- l |= 1 << gpio;
- else
- l &= ~(1 << gpio);
- break;
-#endif
-#ifdef CONFIG_ARCH_OMAP850
- case METHOD_GPIO_850:
- reg += OMAP850_GPIO_DATA_OUTPUT;
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+ case METHOD_GPIO_7XX:
+ reg += OMAP7XX_GPIO_DATA_OUTPUT;
l = __raw_readl(reg);
if (enable)
l |= 1 << gpio;
@@ -537,14 +522,9 @@ static int _get_gpio_datain(struct gpio_bank *bank, int gpio)
reg += OMAP1610_GPIO_DATAIN;
break;
#endif
-#ifdef CONFIG_ARCH_OMAP730
- case METHOD_GPIO_730:
- reg += OMAP730_GPIO_DATA_INPUT;
- break;
-#endif
-#ifdef CONFIG_ARCH_OMAP850
- case METHOD_GPIO_850:
- reg += OMAP850_GPIO_DATA_INPUT;
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+ case METHOD_GPIO_7XX:
+ reg += OMAP7XX_GPIO_DATA_INPUT;
break;
#endif
#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
@@ -588,14 +568,9 @@ static int _get_gpio_dataout(struct gpio_bank *bank, int gpio)
reg += OMAP1610_GPIO_DATAOUT;
break;
#endif
-#ifdef CONFIG_ARCH_OMAP730
- case METHOD_GPIO_730:
- reg += OMAP730_GPIO_DATA_OUTPUT;
- break;
-#endif
-#ifdef CONFIG_ARCH_OMAP850
- case METHOD_GPIO_850:
- reg += OMAP850_GPIO_DATA_OUTPUT;
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+ case METHOD_GPIO_7XX:
+ reg += OMAP7XX_GPIO_DATA_OUTPUT;
break;
#endif
#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
@@ -797,21 +772,9 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
__raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA);
break;
#endif
-#ifdef CONFIG_ARCH_OMAP730
- case METHOD_GPIO_730:
- reg += OMAP730_GPIO_INT_CONTROL;
- l = __raw_readl(reg);
- if (trigger & IRQ_TYPE_EDGE_RISING)
- l |= 1 << gpio;
- else if (trigger & IRQ_TYPE_EDGE_FALLING)
- l &= ~(1 << gpio);
- else
- goto bad;
- break;
-#endif
-#ifdef CONFIG_ARCH_OMAP850
- case METHOD_GPIO_850:
- reg += OMAP850_GPIO_INT_CONTROL;
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+ case METHOD_GPIO_7XX:
+ reg += OMAP7XX_GPIO_INT_CONTROL;
l = __raw_readl(reg);
if (trigger & IRQ_TYPE_EDGE_RISING)
l |= 1 << gpio;
@@ -897,14 +860,9 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
reg += OMAP1610_GPIO_IRQSTATUS1;
break;
#endif
-#ifdef CONFIG_ARCH_OMAP730
- case METHOD_GPIO_730:
- reg += OMAP730_GPIO_INT_STATUS;
- break;
-#endif
-#ifdef CONFIG_ARCH_OMAP850
- case METHOD_GPIO_850:
- reg += OMAP850_GPIO_INT_STATUS;
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+ case METHOD_GPIO_7XX:
+ reg += OMAP7XX_GPIO_INT_STATUS;
break;
#endif
#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
@@ -971,16 +929,9 @@ static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank)
mask = 0xffff;
break;
#endif
-#ifdef CONFIG_ARCH_OMAP730
- case METHOD_GPIO_730:
- reg += OMAP730_GPIO_INT_MASK;
- mask = 0xffffffff;
- inv = 1;
- break;
-#endif
-#ifdef CONFIG_ARCH_OMAP850
- case METHOD_GPIO_850:
- reg += OMAP850_GPIO_INT_MASK;
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+ case METHOD_GPIO_7XX:
+ reg += OMAP7XX_GPIO_INT_MASK;
mask = 0xffffffff;
inv = 1;
break;
@@ -1044,19 +995,9 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab
l = gpio_mask;
break;
#endif
-#ifdef CONFIG_ARCH_OMAP730
- case METHOD_GPIO_730:
- reg += OMAP730_GPIO_INT_MASK;
- l = __raw_readl(reg);
- if (enable)
- l &= ~(gpio_mask);
- else
- l |= gpio_mask;
- break;
-#endif
-#ifdef CONFIG_ARCH_OMAP850
- case METHOD_GPIO_850:
- reg += OMAP850_GPIO_INT_MASK;
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+ case METHOD_GPIO_7XX:
+ reg += OMAP7XX_GPIO_INT_MASK;
l = __raw_readl(reg);
if (enable)
l &= ~(gpio_mask);
@@ -1249,13 +1190,9 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
if (bank->method == METHOD_GPIO_1610)
isr_reg = bank->base + OMAP1610_GPIO_IRQSTATUS1;
#endif
-#ifdef CONFIG_ARCH_OMAP730
- if (bank->method == METHOD_GPIO_730)
- isr_reg = bank->base + OMAP730_GPIO_INT_STATUS;
-#endif
-#ifdef CONFIG_ARCH_OMAP850
- if (bank->method == METHOD_GPIO_850)
- isr_reg = bank->base + OMAP850_GPIO_INT_STATUS;
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+ if (bank->method == METHOD_GPIO_7XX)
+ isr_reg = bank->base + OMAP7XX_GPIO_INT_STATUS;
#endif
#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
if (bank->method == METHOD_GPIO_24XX)
@@ -1524,11 +1461,8 @@ static int gpio_is_input(struct gpio_bank *bank, int mask)
case METHOD_GPIO_1610:
reg += OMAP1610_GPIO_DIRECTION;
break;
- case METHOD_GPIO_730:
- reg += OMAP730_GPIO_DIR_CONTROL;
- break;
- case METHOD_GPIO_850:
- reg += OMAP850_GPIO_DIR_CONTROL;
+ case METHOD_GPIO_7XX:
+ reg += OMAP7XX_GPIO_DIR_CONTROL;
break;
case METHOD_GPIO_24XX:
reg += OMAP24XX_GPIO_OE;
@@ -1607,6 +1541,23 @@ static struct clk * gpio5_fck;
static struct clk *gpio_iclks[OMAP34XX_NR_GPIOS];
#endif
+static void __init omap_gpio_show_rev(void)
+{
+ u32 rev;
+
+ if (cpu_is_omap16xx())
+ rev = __raw_readw(gpio_bank[1].base + OMAP1610_GPIO_REVISION);
+ else if (cpu_is_omap24xx() || cpu_is_omap34xx())
+ rev = __raw_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
+ else if (cpu_is_omap44xx())
+ rev = __raw_readl(gpio_bank[0].base + OMAP4_GPIO_REVISION);
+ else
+ return;
+
+ printk(KERN_INFO "OMAP GPIO hardware version %d.%d\n",
+ (rev >> 4) & 0x0f, rev & 0x0f);
+}
+
/* This lock class tells lockdep that GPIO irqs are in a different
* category than their parents, so it won't report false recursion.
*/
@@ -1617,6 +1568,7 @@ static int __init _omap_gpio_init(void)
int i;
int gpio = 0;
struct gpio_bank *bank;
+ int bank_size = SZ_8K; /* Module 4KB + L4 4KB except on omap1 */
char clk_name[11];
initialized = 1;
@@ -1679,77 +1631,45 @@ static int __init _omap_gpio_init(void)
#ifdef CONFIG_ARCH_OMAP15XX
if (cpu_is_omap15xx()) {
- printk(KERN_INFO "OMAP1510 GPIO hardware\n");
gpio_bank_count = 2;
gpio_bank = gpio_bank_1510;
+ bank_size = SZ_2K;
}
#endif
#if defined(CONFIG_ARCH_OMAP16XX)
if (cpu_is_omap16xx()) {
- u32 rev;
-
gpio_bank_count = 5;
gpio_bank = gpio_bank_1610;
- rev = __raw_readw(gpio_bank[1].base + OMAP1610_GPIO_REVISION);
- printk(KERN_INFO "OMAP GPIO hardware version %d.%d\n",
- (rev >> 4) & 0x0f, rev & 0x0f);
+ bank_size = SZ_2K;
}
#endif
-#ifdef CONFIG_ARCH_OMAP730
- if (cpu_is_omap730()) {
- printk(KERN_INFO "OMAP730 GPIO hardware\n");
- gpio_bank_count = 7;
- gpio_bank = gpio_bank_730;
- }
-#endif
-#ifdef CONFIG_ARCH_OMAP850
- if (cpu_is_omap850()) {
- printk(KERN_INFO "OMAP850 GPIO hardware\n");
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+ if (cpu_is_omap7xx()) {
gpio_bank_count = 7;
- gpio_bank = gpio_bank_850;
+ gpio_bank = gpio_bank_7xx;
+ bank_size = SZ_2K;
}
#endif
-
#ifdef CONFIG_ARCH_OMAP24XX
if (cpu_is_omap242x()) {
- int rev;
-
gpio_bank_count = 4;
gpio_bank = gpio_bank_242x;
- rev = __raw_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
- printk(KERN_INFO "OMAP242x GPIO hardware version %d.%d\n",
- (rev >> 4) & 0x0f, rev & 0x0f);
}
if (cpu_is_omap243x()) {
- int rev;
-
gpio_bank_count = 5;
gpio_bank = gpio_bank_243x;
- rev = __raw_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
- printk(KERN_INFO "OMAP243x GPIO hardware version %d.%d\n",
- (rev >> 4) & 0x0f, rev & 0x0f);
}
#endif
#ifdef CONFIG_ARCH_OMAP34XX
if (cpu_is_omap34xx()) {
- int rev;
-
gpio_bank_count = OMAP34XX_NR_GPIOS;
gpio_bank = gpio_bank_34xx;
- rev = __raw_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
- printk(KERN_INFO "OMAP34xx GPIO hardware version %d.%d\n",
- (rev >> 4) & 0x0f, rev & 0x0f);
}
#endif
#ifdef CONFIG_ARCH_OMAP4
if (cpu_is_omap44xx()) {
- int rev;
-
gpio_bank_count = OMAP34XX_NR_GPIOS;
gpio_bank = gpio_bank_44xx;
- rev = __raw_readl(gpio_bank[0].base + OMAP4_GPIO_REVISION);
- printk(KERN_INFO "OMAP44xx GPIO hardware version %d.%d\n",
- (rev >> 4) & 0x0f, rev & 0x0f);
}
#endif
for (i = 0; i < gpio_bank_count; i++) {
@@ -1757,6 +1677,14 @@ static int __init _omap_gpio_init(void)
bank = &gpio_bank[i];
spin_lock_init(&bank->lock);
+
+ /* Static mapping, never released */
+ bank->base = ioremap(bank->pbase, bank_size);
+ if (!bank->base) {
+ printk(KERN_ERR "Could not ioremap gpio bank%i\n", i);
+ continue;
+ }
+
if (bank_is_mpuio(bank))
__raw_writew(0xffff, bank->base + OMAP_MPUIO_GPIO_MASKIT);
if (cpu_is_omap15xx() && bank->method == METHOD_GPIO_1510) {
@@ -1768,11 +1696,11 @@ static int __init _omap_gpio_init(void)
__raw_writew(0xffff, bank->base + OMAP1610_GPIO_IRQSTATUS1);
__raw_writew(0x0014, bank->base + OMAP1610_GPIO_SYSCONFIG);
}
- if (cpu_is_omap7xx() && bank->method == METHOD_GPIO_730) {
- __raw_writel(0xffffffff, bank->base + OMAP730_GPIO_INT_MASK);
- __raw_writel(0x00000000, bank->base + OMAP730_GPIO_INT_STATUS);
+ if (cpu_is_omap7xx() && bank->method == METHOD_GPIO_7XX) {
+ __raw_writel(0xffffffff, bank->base + OMAP7XX_GPIO_INT_MASK);
+ __raw_writel(0x00000000, bank->base + OMAP7XX_GPIO_INT_STATUS);
- gpio_count = 32; /* 730 has 32-bit GPIOs */
+ gpio_count = 32; /* 7xx has 32-bit GPIOs */
}
#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
@@ -1862,6 +1790,8 @@ static int __init _omap_gpio_init(void)
if (cpu_is_omap34xx())
omap_writel(1 << 0, 0x48306814);
+ omap_gpio_show_rev();
+
return 0;
}
@@ -2160,8 +2090,7 @@ static int dbg_gpio_show(struct seq_file *s, void *unused)
if (bank_is_mpuio(bank))
gpio = OMAP_MPUIO(0);
- else if (cpu_class_is_omap2() || cpu_is_omap730() ||
- cpu_is_omap850())
+ else if (cpu_class_is_omap2() || cpu_is_omap7xx())
bankwidth = 32;
for (j = 0; j < bankwidth; j++, gpio++, mask <<= 1) {
diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c
index 8b848391f0c8..c08362dbb8ed 100644
--- a/arch/arm/plat-omap/i2c.c
+++ b/arch/arm/plat-omap/i2c.c
@@ -27,7 +27,7 @@
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <mach/irqs.h>
-#include <mach/mux.h>
+#include <plat/mux.h>
#define OMAP_I2C_SIZE 0x3f
#define OMAP1_I2C_BASE 0xfffb3800
diff --git a/arch/arm/plat-omap/include/mach/blizzard.h b/arch/arm/plat-omap/include/plat/blizzard.h
index 8d160f171372..8d160f171372 100644
--- a/arch/arm/plat-omap/include/mach/blizzard.h
+++ b/arch/arm/plat-omap/include/plat/blizzard.h
diff --git a/arch/arm/plat-omap/include/mach/board-ams-delta.h b/arch/arm/plat-omap/include/plat/board-ams-delta.h
index 51b102dc906b..51b102dc906b 100644
--- a/arch/arm/plat-omap/include/mach/board-ams-delta.h
+++ b/arch/arm/plat-omap/include/plat/board-ams-delta.h
diff --git a/arch/arm/plat-omap/include/mach/board-sx1.h b/arch/arm/plat-omap/include/plat/board-sx1.h
index 355adbdaae33..355adbdaae33 100644
--- a/arch/arm/plat-omap/include/mach/board-sx1.h
+++ b/arch/arm/plat-omap/include/plat/board-sx1.h
diff --git a/arch/arm/plat-omap/include/mach/board-voiceblue.h b/arch/arm/plat-omap/include/plat/board-voiceblue.h
index 27916b210f57..27916b210f57 100644
--- a/arch/arm/plat-omap/include/mach/board-voiceblue.h
+++ b/arch/arm/plat-omap/include/plat/board-voiceblue.h
diff --git a/arch/arm/plat-omap/include/mach/board.h b/arch/arm/plat-omap/include/plat/board.h
index 8e913c322810..c4fc69f09796 100644
--- a/arch/arm/plat-omap/include/mach/board.h
+++ b/arch/arm/plat-omap/include/plat/board.h
@@ -12,7 +12,7 @@
#include <linux/types.h>
-#include <mach/gpio-switch.h>
+#include <plat/gpio-switch.h>
/* Different peripheral ids */
#define OMAP_TAG_CLOCK 0x4f01
diff --git a/arch/arm/plat-omap/include/mach/clkdev.h b/arch/arm/plat-omap/include/plat/clkdev.h
index 730c49d1ebd8..730c49d1ebd8 100644
--- a/arch/arm/plat-omap/include/mach/clkdev.h
+++ b/arch/arm/plat-omap/include/plat/clkdev.h
diff --git a/arch/arm/plat-omap/include/mach/clock.h b/arch/arm/plat-omap/include/plat/clock.h
index 4b8b0d65cbf2..4b8b0d65cbf2 100644
--- a/arch/arm/plat-omap/include/mach/clock.h
+++ b/arch/arm/plat-omap/include/plat/clock.h
diff --git a/arch/arm/plat-omap/include/mach/clockdomain.h b/arch/arm/plat-omap/include/plat/clockdomain.h
index 99ebd886f134..eb734826e64e 100644
--- a/arch/arm/plat-omap/include/mach/clockdomain.h
+++ b/arch/arm/plat-omap/include/plat/clockdomain.h
@@ -16,9 +16,9 @@
#ifndef __ASM_ARM_ARCH_OMAP_CLOCKDOMAIN_H
#define __ASM_ARM_ARCH_OMAP_CLOCKDOMAIN_H
-#include <mach/powerdomain.h>
-#include <mach/clock.h>
-#include <mach/cpu.h>
+#include <plat/powerdomain.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
/* Clockdomain capability flags */
#define CLKDM_CAN_FORCE_SLEEP (1 << 0)
diff --git a/arch/arm/plat-omap/include/mach/common.h b/arch/arm/plat-omap/include/plat/common.h
index fdeab421b4dc..064f1730f43b 100644
--- a/arch/arm/plat-omap/include/mach/common.h
+++ b/arch/arm/plat-omap/include/plat/common.h
@@ -31,6 +31,9 @@
struct sys_timer;
+/* used by omap-smp.c and board-4430sdp.c */
+extern void __iomem *gic_cpu_base_addr;
+
extern void omap_map_common_io(void);
extern struct sys_timer omap_timer;
#if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
diff --git a/arch/arm/plat-omap/include/mach/control.h b/arch/arm/plat-omap/include/plat/control.h
index 826d317cdbec..fdb6300974fd 100644
--- a/arch/arm/plat-omap/include/mach/control.h
+++ b/arch/arm/plat-omap/include/plat/control.h
@@ -20,15 +20,18 @@
#ifndef __ASSEMBLY__
#define OMAP242X_CTRL_REGADDR(reg) \
- OMAP2_IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
+ OMAP2_L4_IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
#define OMAP243X_CTRL_REGADDR(reg) \
- OMAP2_IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
+ OMAP2_L4_IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
#define OMAP343X_CTRL_REGADDR(reg) \
- OMAP2_IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
+ OMAP2_L4_IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
#else
-#define OMAP242X_CTRL_REGADDR(reg) OMAP2_IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
-#define OMAP243X_CTRL_REGADDR(reg) OMAP2_IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
-#define OMAP343X_CTRL_REGADDR(reg) OMAP2_IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
+#define OMAP242X_CTRL_REGADDR(reg) \
+ OMAP2_L4_IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
+#define OMAP243X_CTRL_REGADDR(reg) \
+ OMAP2_L4_IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
+#define OMAP343X_CTRL_REGADDR(reg) \
+ OMAP2_L4_IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
#endif /* __ASSEMBLY__ */
/*
@@ -202,6 +205,40 @@
#define OMAP3_PADCONF_WAKEUPEVENT0 (1 << 15)
#define OMAP3_PADCONF_WAKEUPENABLE0 (1 << 14)
+/*
+ * CONTROL OMAP STATUS register to identify OMAP3 features
+ */
+#define OMAP3_CONTROL_OMAP_STATUS 0x044c
+
+#define OMAP3_SGX_SHIFT 13
+#define OMAP3_SGX_MASK (3 << OMAP3_SGX_SHIFT)
+#define FEAT_SGX_FULL 0
+#define FEAT_SGX_HALF 1
+#define FEAT_SGX_NONE 2
+
+#define OMAP3_IVA_SHIFT 12
+#define OMAP3_IVA_MASK (1 << OMAP3_SGX_SHIFT)
+#define FEAT_IVA 0
+#define FEAT_IVA_NONE 1
+
+#define OMAP3_L2CACHE_SHIFT 10
+#define OMAP3_L2CACHE_MASK (3 << OMAP3_L2CACHE_SHIFT)
+#define FEAT_L2CACHE_NONE 0
+#define FEAT_L2CACHE_64KB 1
+#define FEAT_L2CACHE_128KB 2
+#define FEAT_L2CACHE_256KB 3
+
+#define OMAP3_ISP_SHIFT 5
+#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 FEAT_NEON 0
+#define FEAT_NEON_NONE 1
+
+
#ifndef __ASSEMBLY__
#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \
defined(CONFIG_ARCH_OMAP4)
diff --git a/arch/arm/plat-omap/include/mach/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h
index f129efb3075e..7cb05568b446 100644
--- a/arch/arm/plat-omap/include/mach/cpu.h
+++ b/arch/arm/plat-omap/include/plat/cpu.h
@@ -30,6 +30,8 @@
#ifndef __ASM_ARCH_OMAP_CPU_H
#define __ASM_ARCH_OMAP_CPU_H
+#include <linux/bitops.h>
+
/*
* Omap device type i.e. EMU/HS/TST/GP/BAD
*/
@@ -57,6 +59,23 @@ struct omap_chip_id {
unsigned int omap_rev(void);
/*
+ * Define CPU revision bits
+ *
+ * Verbose meaning of the revision bits may be different for a silicon
+ * family. This difference can be handled separately.
+ */
+#define OMAP_REVBITS_00 0x00
+#define OMAP_REVBITS_10 0x10
+#define OMAP_REVBITS_20 0x20
+#define OMAP_REVBITS_30 0x30
+#define OMAP_REVBITS_40 0x40
+
+/*
+ * Get the CPU revision for OMAP devices
+ */
+#define GET_OMAP_REVISION() ((omap_rev() >> 8) & 0xff)
+
+/*
* Test if multicore OMAP support is needed
*/
#undef MULTI_OMAP1
@@ -161,6 +180,7 @@ IS_OMAP_CLASS(34xx, 0x34)
IS_OMAP_SUBCLASS(242x, 0x242)
IS_OMAP_SUBCLASS(243x, 0x243)
IS_OMAP_SUBCLASS(343x, 0x343)
+IS_OMAP_SUBCLASS(363x, 0x363)
#define cpu_is_omap7xx() 0
#define cpu_is_omap15xx() 0
@@ -301,7 +321,12 @@ IS_OMAP_TYPE(3430, 0x3430)
#define cpu_is_omap2422() 0
#define cpu_is_omap2423() 0
#define cpu_is_omap2430() 0
+#define cpu_is_omap3503() 0
+#define cpu_is_omap3515() 0
+#define cpu_is_omap3525() 0
+#define cpu_is_omap3530() 0
#define cpu_is_omap3430() 0
+#define cpu_is_omap3630() 0
/*
* Whether we have MULTI_OMAP1 or not, we still need to distinguish
@@ -351,7 +376,23 @@ IS_OMAP_TYPE(3430, 0x3430)
#if defined(CONFIG_ARCH_OMAP34XX)
# undef cpu_is_omap3430
+# undef cpu_is_omap3503
+# undef cpu_is_omap3515
+# undef cpu_is_omap3525
+# undef cpu_is_omap3530
# define cpu_is_omap3430() is_omap3430()
+# define cpu_is_omap3503 (cpu_is_omap3430() && \
+ (!omap3_has_iva()) && \
+ (!omap3_has_sgx()))
+# define cpu_is_omap3515 (cpu_is_omap3430() && \
+ (omap3_has_iva()) && \
+ (!omap3_has_sgx()))
+# define cpu_is_omap3525 (cpu_is_omap3430() && \
+ (omap3_has_sgx()) && \
+ (!omap3_has_iva()))
+# define cpu_is_omap3530 (cpu_is_omap3430())
+# undef cpu_is_omap3630
+# define cpu_is_omap3630() is_omap363x()
#endif
# if defined(CONFIG_ARCH_OMAP4)
@@ -382,6 +423,14 @@ IS_OMAP_TYPE(3430, 0x3430)
#define OMAP3430_REV_ES3_0 0x34303034
#define OMAP3430_REV_ES3_1 0x34304034
+#define OMAP3630_REV_ES1_0 0x36300034
+
+#define OMAP35XX_CLASS 0x35000034
+#define OMAP3503_REV(v) (OMAP35XX_CLASS | (0x3503 << 16) | (v << 12))
+#define OMAP3515_REV(v) (OMAP35XX_CLASS | (0x3515 << 16) | (v << 12))
+#define OMAP3525_REV(v) (OMAP35XX_CLASS | (0x3525 << 16) | (v << 12))
+#define OMAP3530_REV(v) (OMAP35XX_CLASS | (0x3530 << 16) | (v << 12))
+
#define OMAP443X_CLASS 0x44300034
/*
@@ -423,4 +472,27 @@ IS_OMAP_TYPE(3430, 0x3430)
int omap_chip_is(struct omap_chip_id oci);
void omap2_check_revision(void);
+/*
+ * Runtime detection of OMAP3 features
+ */
+extern u32 omap3_features;
+
+#define OMAP3_HAS_L2CACHE BIT(0)
+#define OMAP3_HAS_IVA BIT(1)
+#define OMAP3_HAS_SGX BIT(2)
+#define OMAP3_HAS_NEON BIT(3)
+#define OMAP3_HAS_ISP BIT(4)
+
+#define OMAP3_HAS_FEATURE(feat,flag) \
+static inline unsigned int omap3_has_ ##feat(void) \
+{ \
+ return (omap3_features & OMAP3_HAS_ ##flag); \
+} \
+
+OMAP3_HAS_FEATURE(l2cache, L2CACHE)
+OMAP3_HAS_FEATURE(sgx, SGX)
+OMAP3_HAS_FEATURE(iva, IVA)
+OMAP3_HAS_FEATURE(neon, NEON)
+OMAP3_HAS_FEATURE(isp, ISP)
+
#endif
diff --git a/arch/arm/plat-omap/include/mach/dma.h b/arch/arm/plat-omap/include/plat/dma.h
index 72f680b7180d..72f680b7180d 100644
--- a/arch/arm/plat-omap/include/mach/dma.h
+++ b/arch/arm/plat-omap/include/plat/dma.h
diff --git a/arch/arm/plat-omap/include/mach/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 20f1054c0a80..20f1054c0a80 100644
--- a/arch/arm/plat-omap/include/mach/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
diff --git a/arch/arm/plat-omap/include/mach/dsp_common.h b/arch/arm/plat-omap/include/plat/dsp_common.h
index da97736f3efa..da97736f3efa 100644
--- a/arch/arm/plat-omap/include/mach/dsp_common.h
+++ b/arch/arm/plat-omap/include/plat/dsp_common.h
diff --git a/arch/arm/plat-omap/include/mach/fpga.h b/arch/arm/plat-omap/include/plat/fpga.h
index f1864a652f7a..f1864a652f7a 100644
--- a/arch/arm/plat-omap/include/mach/fpga.h
+++ b/arch/arm/plat-omap/include/plat/fpga.h
diff --git a/arch/arm/plat-omap/include/mach/gpio-switch.h b/arch/arm/plat-omap/include/plat/gpio-switch.h
index 10da0e07c0cf..10da0e07c0cf 100644
--- a/arch/arm/plat-omap/include/mach/gpio-switch.h
+++ b/arch/arm/plat-omap/include/plat/gpio-switch.h
diff --git a/arch/arm/plat-omap/include/mach/gpio.h b/arch/arm/plat-omap/include/plat/gpio.h
index 633ff688b928..633ff688b928 100644
--- a/arch/arm/plat-omap/include/mach/gpio.h
+++ b/arch/arm/plat-omap/include/plat/gpio.h
diff --git a/arch/arm/plat-omap/include/mach/gpmc-smc91x.h b/arch/arm/plat-omap/include/plat/gpmc-smc91x.h
index b64fbee4d567..b64fbee4d567 100644
--- a/arch/arm/plat-omap/include/mach/gpmc-smc91x.h
+++ b/arch/arm/plat-omap/include/plat/gpmc-smc91x.h
diff --git a/arch/arm/plat-omap/include/mach/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 9c99cda77ba6..9c99cda77ba6 100644
--- a/arch/arm/plat-omap/include/mach/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
diff --git a/arch/arm/plat-omap/include/mach/hardware.h b/arch/arm/plat-omap/include/plat/hardware.h
index 26c1fbff08aa..d5b26adfb890 100644
--- a/arch/arm/plat-omap/include/mach/hardware.h
+++ b/arch/arm/plat-omap/include/plat/hardware.h
@@ -39,9 +39,9 @@
#include <asm/sizes.h>
#ifndef __ASSEMBLER__
#include <asm/types.h>
-#include <mach/cpu.h>
+#include <plat/cpu.h>
#endif
-#include <mach/serial.h>
+#include <plat/serial.h>
/*
* ---------------------------------------------------------------------------
@@ -280,11 +280,11 @@
* ---------------------------------------------------------------------------
*/
-#include "omap730.h"
-#include "omap1510.h"
-#include "omap16xx.h"
-#include "omap24xx.h"
-#include "omap34xx.h"
-#include "omap44xx.h"
+#include <plat/omap7xx.h>
+#include <plat/omap1510.h>
+#include <plat/omap16xx.h>
+#include <plat/omap24xx.h>
+#include <plat/omap34xx.h>
+#include <plat/omap44xx.h>
#endif /* __ASM_ARCH_OMAP_HARDWARE_H */
diff --git a/arch/arm/plat-omap/include/mach/hwa742.h b/arch/arm/plat-omap/include/plat/hwa742.h
index 886248d32b49..886248d32b49 100644
--- a/arch/arm/plat-omap/include/mach/hwa742.h
+++ b/arch/arm/plat-omap/include/plat/hwa742.h
diff --git a/arch/arm/plat-omap/include/mach/io.h b/arch/arm/plat-omap/include/plat/io.h
index 8d32df32b0b1..7e5319f907d1 100644
--- a/arch/arm/plat-omap/include/mach/io.h
+++ b/arch/arm/plat-omap/include/plat/io.h
@@ -63,8 +63,24 @@
#define OMAP1_IO_OFFSET 0x01000000 /* Virtual IO = 0xfefb0000 */
#define OMAP1_IO_ADDRESS(pa) IOMEM((pa) - OMAP1_IO_OFFSET)
-#define OMAP2_IO_OFFSET 0x90000000
-#define OMAP2_IO_ADDRESS(pa) IOMEM((pa) + OMAP2_IO_OFFSET) /* L3 and L4 */
+#define OMAP2_L3_IO_OFFSET 0x90000000
+#define OMAP2_L3_IO_ADDRESS(pa) IOMEM((pa) + OMAP2_L3_IO_OFFSET) /* L3 */
+
+
+#define OMAP2_L4_IO_OFFSET 0xb2000000
+#define OMAP2_L4_IO_ADDRESS(pa) IOMEM((pa) + OMAP2_L4_IO_OFFSET) /* L4 */
+
+#define OMAP4_L3_IO_OFFSET 0xb4000000
+#define OMAP4_L3_IO_ADDRESS(pa) IOMEM((pa) + OMAP4_L3_IO_OFFSET) /* L3 */
+
+#define OMAP4_L3_PER_IO_OFFSET 0xb1100000
+#define OMAP4_L3_PER_IO_ADDRESS(pa) IOMEM((pa) + OMAP4_L3_PER_IO_OFFSET)
+
+#define OMAP4_GPMC_IO_OFFSET 0xa9000000
+#define OMAP4_GPMC_IO_ADDRESS(pa) IOMEM((pa) + OMAP4_GPMC_IO_OFFSET)
+
+#define OMAP2_EMU_IO_OFFSET 0xaa800000 /* Emulation */
+#define OMAP2_EMU_IO_ADDRESS(pa) IOMEM((pa) + OMAP2_EMU_IO_OFFSET)
/*
* ----------------------------------------------------------------------------
@@ -83,24 +99,27 @@
*/
/* We map both L3 and L4 on OMAP2 */
-#define L3_24XX_PHYS L3_24XX_BASE /* 0x68000000 */
-#define L3_24XX_VIRT 0xf8000000
+#define L3_24XX_PHYS L3_24XX_BASE /* 0x68000000 --> 0xf8000000*/
+#define L3_24XX_VIRT (L3_24XX_PHYS + OMAP2_L3_IO_OFFSET)
#define L3_24XX_SIZE SZ_1M /* 44kB of 128MB used, want 1MB sect */
-#define L4_24XX_PHYS L4_24XX_BASE /* 0x48000000 */
-#define L4_24XX_VIRT 0xd8000000
+#define L4_24XX_PHYS L4_24XX_BASE /* 0x48000000 --> 0xfa000000 */
+#define L4_24XX_VIRT (L4_24XX_PHYS + OMAP2_L4_IO_OFFSET)
#define L4_24XX_SIZE SZ_1M /* 1MB of 128MB used, want 1MB sect */
-#define L4_WK_243X_PHYS L4_WK_243X_BASE /* 0x49000000 */
-#define L4_WK_243X_VIRT 0xd9000000
+#define L4_WK_243X_PHYS L4_WK_243X_BASE /* 0x49000000 --> 0xfb000000 */
+#define L4_WK_243X_VIRT (L4_WK_243X_PHYS + OMAP2_L4_IO_OFFSET)
#define L4_WK_243X_SIZE SZ_1M
-#define OMAP243X_GPMC_PHYS OMAP243X_GPMC_BASE /* 0x49000000 */
-#define OMAP243X_GPMC_VIRT 0xFE000000
+#define OMAP243X_GPMC_PHYS OMAP243X_GPMC_BASE
+#define OMAP243X_GPMC_VIRT (OMAP243X_GPMC_PHYS + OMAP2_L3_IO_OFFSET)
+ /* 0x6e000000 --> 0xfe000000 */
#define OMAP243X_GPMC_SIZE SZ_1M
#define OMAP243X_SDRC_PHYS OMAP243X_SDRC_BASE
-#define OMAP243X_SDRC_VIRT 0xFD000000
+ /* 0x6D000000 --> 0xfd000000 */
+#define OMAP243X_SDRC_VIRT (OMAP243X_SDRC_PHYS + OMAP2_L3_IO_OFFSET)
#define OMAP243X_SDRC_SIZE SZ_1M
#define OMAP243X_SMS_PHYS OMAP243X_SMS_BASE
-#define OMAP243X_SMS_VIRT 0xFC000000
+ /* 0x6c000000 --> 0xfc000000 */
+#define OMAP243X_SMS_VIRT (OMAP243X_SMS_PHYS + OMAP2_L3_IO_OFFSET)
#define OMAP243X_SMS_SIZE SZ_1M
/* DSP */
@@ -121,12 +140,12 @@
*/
/* We map both L3 and L4 on OMAP3 */
-#define L3_34XX_PHYS L3_34XX_BASE /* 0x68000000 */
-#define L3_34XX_VIRT 0xf8000000
+#define L3_34XX_PHYS L3_34XX_BASE /* 0x68000000 --> 0xf8000000 */
+#define L3_34XX_VIRT (L3_34XX_PHYS + OMAP2_L3_IO_OFFSET)
#define L3_34XX_SIZE SZ_1M /* 44kB of 128MB used, want 1MB sect */
-#define L4_34XX_PHYS L4_34XX_BASE /* 0x48000000 */
-#define L4_34XX_VIRT 0xd8000000
+#define L4_34XX_PHYS L4_34XX_BASE /* 0x48000000 --> 0xfa000000 */
+#define L4_34XX_VIRT (L4_34XX_PHYS + OMAP2_L4_IO_OFFSET)
#define L4_34XX_SIZE SZ_4M /* 1MB of 128MB used, want 1MB sect */
/*
@@ -134,28 +153,33 @@
* VPOM3430 was not working for Int controller
*/
-#define L4_WK_34XX_PHYS L4_WK_34XX_BASE /* 0x48300000 */
-#define L4_WK_34XX_VIRT 0xd8300000
+#define L4_WK_34XX_PHYS L4_WK_34XX_BASE /* 0x48300000 --> 0xfa300000 */
+#define L4_WK_34XX_VIRT (L4_WK_34XX_PHYS + OMAP2_L4_IO_OFFSET)
#define L4_WK_34XX_SIZE SZ_1M
-#define L4_PER_34XX_PHYS L4_PER_34XX_BASE /* 0x49000000 */
-#define L4_PER_34XX_VIRT 0xd9000000
+#define L4_PER_34XX_PHYS L4_PER_34XX_BASE
+ /* 0x49000000 --> 0xfb000000 */
+#define L4_PER_34XX_VIRT (L4_PER_34XX_PHYS + OMAP2_L4_IO_OFFSET)
#define L4_PER_34XX_SIZE SZ_1M
-#define L4_EMU_34XX_PHYS L4_EMU_34XX_BASE /* 0x54000000 */
-#define L4_EMU_34XX_VIRT 0xe4000000
-#define L4_EMU_34XX_SIZE SZ_64M
+#define L4_EMU_34XX_PHYS L4_EMU_34XX_BASE
+ /* 0x54000000 --> 0xfe800000 */
+#define L4_EMU_34XX_VIRT (L4_EMU_34XX_PHYS + OMAP2_EMU_IO_OFFSET)
+#define L4_EMU_34XX_SIZE SZ_8M
-#define OMAP34XX_GPMC_PHYS OMAP34XX_GPMC_BASE /* 0x6E000000 */
-#define OMAP34XX_GPMC_VIRT 0xFE000000
+#define OMAP34XX_GPMC_PHYS OMAP34XX_GPMC_BASE
+ /* 0x6e000000 --> 0xfe000000 */
+#define OMAP34XX_GPMC_VIRT (OMAP34XX_GPMC_PHYS + OMAP2_L3_IO_OFFSET)
#define OMAP34XX_GPMC_SIZE SZ_1M
-#define OMAP343X_SMS_PHYS OMAP343X_SMS_BASE /* 0x6C000000 */
-#define OMAP343X_SMS_VIRT 0xFC000000
+#define OMAP343X_SMS_PHYS OMAP343X_SMS_BASE
+ /* 0x6c000000 --> 0xfc000000 */
+#define OMAP343X_SMS_VIRT (OMAP343X_SMS_PHYS + OMAP2_L3_IO_OFFSET)
#define OMAP343X_SMS_SIZE SZ_1M
-#define OMAP343X_SDRC_PHYS OMAP343X_SDRC_BASE /* 0x6D000000 */
-#define OMAP343X_SDRC_VIRT 0xFD000000
+#define OMAP343X_SDRC_PHYS OMAP343X_SDRC_BASE
+ /* 0x6D000000 --> 0xfd000000 */
+#define OMAP343X_SDRC_VIRT (OMAP343X_SDRC_PHYS + OMAP2_L3_IO_OFFSET)
#define OMAP343X_SDRC_SIZE SZ_1M
/* DSP */
@@ -176,32 +200,54 @@
*/
/* We map both L3 and L4 on OMAP4 */
-#define L3_44XX_PHYS L3_44XX_BASE
-#define L3_44XX_VIRT 0xd4000000
+#define L3_44XX_PHYS L3_44XX_BASE /* 0x44000000 --> 0xf8000000 */
+#define L3_44XX_VIRT (L3_44XX_PHYS + OMAP4_L3_IO_OFFSET)
#define L3_44XX_SIZE SZ_1M
-#define L4_44XX_PHYS L4_44XX_BASE
-#define L4_44XX_VIRT 0xda000000
+#define L4_44XX_PHYS L4_44XX_BASE /* 0x4a000000 --> 0xfc000000 */
+#define L4_44XX_VIRT (L4_44XX_PHYS + OMAP2_L4_IO_OFFSET)
#define L4_44XX_SIZE SZ_4M
-#define L4_WK_44XX_PHYS L4_WK_44XX_BASE
-#define L4_WK_44XX_VIRT 0xda300000
+#define L4_WK_44XX_PHYS L4_WK_44XX_BASE /* 0x4a300000 --> 0xfc300000 */
+#define L4_WK_44XX_VIRT (L4_WK_44XX_PHYS + OMAP2_L4_IO_OFFSET)
#define L4_WK_44XX_SIZE SZ_1M
#define L4_PER_44XX_PHYS L4_PER_44XX_BASE
-#define L4_PER_44XX_VIRT 0xd8000000
+ /* 0x48000000 --> 0xfa000000 */
+#define L4_PER_44XX_VIRT (L4_PER_44XX_PHYS + OMAP2_L4_IO_OFFSET)
#define L4_PER_44XX_SIZE SZ_4M
+#define L4_ABE_44XX_PHYS L4_ABE_44XX_BASE
+ /* 0x49000000 --> 0xfb000000 */
+#define L4_ABE_44XX_VIRT (L4_ABE_44XX_PHYS + OMAP2_L4_IO_OFFSET)
+#define L4_ABE_44XX_SIZE SZ_1M
+
#define L4_EMU_44XX_PHYS L4_EMU_44XX_BASE
-#define L4_EMU_44XX_VIRT 0xe4000000
-#define L4_EMU_44XX_SIZE SZ_64M
+ /* 0x54000000 --> 0xfe800000 */
+#define L4_EMU_44XX_VIRT (L4_EMU_44XX_PHYS + OMAP2_EMU_IO_OFFSET)
+#define L4_EMU_44XX_SIZE SZ_8M
#define OMAP44XX_GPMC_PHYS OMAP44XX_GPMC_BASE
-#define OMAP44XX_GPMC_VIRT 0xe0000000
+ /* 0x50000000 --> 0xf9000000 */
+#define OMAP44XX_GPMC_VIRT (OMAP44XX_GPMC_PHYS + OMAP4_GPMC_IO_OFFSET)
#define OMAP44XX_GPMC_SIZE SZ_1M
+#define OMAP44XX_EMIF1_PHYS OMAP44XX_EMIF1_BASE
+ /* 0x4c000000 --> 0xfd100000 */
+#define OMAP44XX_EMIF1_VIRT (OMAP44XX_EMIF1_PHYS + OMAP4_L3_PER_IO_OFFSET)
+#define OMAP44XX_EMIF1_SIZE SZ_1M
+
+#define OMAP44XX_EMIF2_PHYS OMAP44XX_EMIF2_BASE
+ /* 0x4d000000 --> 0xfd200000 */
+#define OMAP44XX_EMIF2_VIRT (OMAP44XX_EMIF2_PHYS + OMAP4_L3_PER_IO_OFFSET)
+#define OMAP44XX_EMIF2_SIZE SZ_1M
+
+#define OMAP44XX_DMM_PHYS OMAP44XX_DMM_BASE
+ /* 0x4e000000 --> 0xfd300000 */
+#define OMAP44XX_DMM_VIRT (OMAP44XX_DMM_PHYS + OMAP4_L3_PER_IO_OFFSET)
+#define OMAP44XX_DMM_SIZE SZ_1M
/*
* ----------------------------------------------------------------------------
* Omap specific register access
diff --git a/arch/arm/plat-omap/include/mach/iommu.h b/arch/arm/plat-omap/include/plat/iommu.h
index 46d41ac83dbf..0752af9d099e 100644
--- a/arch/arm/plat-omap/include/mach/iommu.h
+++ b/arch/arm/plat-omap/include/plat/iommu.h
@@ -107,7 +107,7 @@ struct iommu_platform_data {
#if defined(CONFIG_ARCH_OMAP1)
#error "iommu for this processor not implemented yet"
#else
-#include <mach/iommu2.h>
+#include <plat/iommu2.h>
#endif
/*
diff --git a/arch/arm/plat-omap/include/mach/iommu2.h b/arch/arm/plat-omap/include/plat/iommu2.h
index 10ad05f410e9..10ad05f410e9 100644
--- a/arch/arm/plat-omap/include/mach/iommu2.h
+++ b/arch/arm/plat-omap/include/plat/iommu2.h
diff --git a/arch/arm/plat-omap/include/mach/iovmm.h b/arch/arm/plat-omap/include/plat/iovmm.h
index bdc7ce5d7a4a..bdc7ce5d7a4a 100644
--- a/arch/arm/plat-omap/include/mach/iovmm.h
+++ b/arch/arm/plat-omap/include/plat/iovmm.h
diff --git a/arch/arm/plat-omap/include/mach/irda.h b/arch/arm/plat-omap/include/plat/irda.h
index 40f60339d1c6..40f60339d1c6 100644
--- a/arch/arm/plat-omap/include/mach/irda.h
+++ b/arch/arm/plat-omap/include/plat/irda.h
diff --git a/arch/arm/plat-omap/include/mach/irqs.h b/arch/arm/plat-omap/include/plat/irqs.h
index 28a165058b61..6a6d0281e1d5 100644
--- a/arch/arm/plat-omap/include/mach/irqs.h
+++ b/arch/arm/plat-omap/include/plat/irqs.h
@@ -86,49 +86,26 @@
#define INT_1610_SSR_FIFO_0 29
/*
- * OMAP-730 specific IRQ numbers for interrupt handler 1
+ * OMAP-7xx specific IRQ numbers for interrupt handler 1
*/
-#define INT_730_IH2_FIQ 0
-#define INT_730_IH2_IRQ 1
-#define INT_730_USB_NON_ISO 2
-#define INT_730_USB_ISO 3
-#define INT_730_ICR 4
-#define INT_730_EAC 5
-#define INT_730_GPIO_BANK1 6
-#define INT_730_GPIO_BANK2 7
-#define INT_730_GPIO_BANK3 8
-#define INT_730_McBSP2TX 10
-#define INT_730_McBSP2RX 11
-#define INT_730_McBSP2RX_OVF 12
-#define INT_730_LCD_LINE 14
-#define INT_730_GSM_PROTECT 15
-#define INT_730_TIMER3 16
-#define INT_730_GPIO_BANK5 17
-#define INT_730_GPIO_BANK6 18
-#define INT_730_SPGIO_WR 29
-
-/*
- * OMAP-850 specific IRQ numbers for interrupt handler 1
- */
-#define INT_850_IH2_FIQ 0
-#define INT_850_IH2_IRQ 1
-#define INT_850_USB_NON_ISO 2
-#define INT_850_USB_ISO 3
-#define INT_850_ICR 4
-#define INT_850_EAC 5
-#define INT_850_GPIO_BANK1 6
-#define INT_850_GPIO_BANK2 7
-#define INT_850_GPIO_BANK3 8
-#define INT_850_McBSP2TX 10
-#define INT_850_McBSP2RX 11
-#define INT_850_McBSP2RX_OVF 12
-#define INT_850_LCD_LINE 14
-#define INT_850_GSM_PROTECT 15
-#define INT_850_TIMER3 16
-#define INT_850_GPIO_BANK5 17
-#define INT_850_GPIO_BANK6 18
-#define INT_850_SPGIO_WR 29
-
+#define INT_7XX_IH2_FIQ 0
+#define INT_7XX_IH2_IRQ 1
+#define INT_7XX_USB_NON_ISO 2
+#define INT_7XX_USB_ISO 3
+#define INT_7XX_ICR 4
+#define INT_7XX_EAC 5
+#define INT_7XX_GPIO_BANK1 6
+#define INT_7XX_GPIO_BANK2 7
+#define INT_7XX_GPIO_BANK3 8
+#define INT_7XX_McBSP2TX 10
+#define INT_7XX_McBSP2RX 11
+#define INT_7XX_McBSP2RX_OVF 12
+#define INT_7XX_LCD_LINE 14
+#define INT_7XX_GSM_PROTECT 15
+#define INT_7XX_TIMER3 16
+#define INT_7XX_GPIO_BANK5 17
+#define INT_7XX_GPIO_BANK6 18
+#define INT_7XX_SPGIO_WR 29
/*
* IRQ numbers for interrupt handler 2
@@ -206,120 +183,62 @@
#define INT_1610_SHA1MD5 (91 + IH2_BASE)
/*
- * OMAP-730 specific IRQ numbers for interrupt handler 2
- */
-#define INT_730_HW_ERRORS (0 + IH2_BASE)
-#define INT_730_NFIQ_PWR_FAIL (1 + IH2_BASE)
-#define INT_730_CFCD (2 + IH2_BASE)
-#define INT_730_CFIREQ (3 + IH2_BASE)
-#define INT_730_I2C (4 + IH2_BASE)
-#define INT_730_PCC (5 + IH2_BASE)
-#define INT_730_MPU_EXT_NIRQ (6 + IH2_BASE)
-#define INT_730_SPI_100K_1 (7 + IH2_BASE)
-#define INT_730_SYREN_SPI (8 + IH2_BASE)
-#define INT_730_VLYNQ (9 + IH2_BASE)
-#define INT_730_GPIO_BANK4 (10 + IH2_BASE)
-#define INT_730_McBSP1TX (11 + IH2_BASE)
-#define INT_730_McBSP1RX (12 + IH2_BASE)
-#define INT_730_McBSP1RX_OF (13 + IH2_BASE)
-#define INT_730_UART_MODEM_IRDA_2 (14 + IH2_BASE)
-#define INT_730_UART_MODEM_1 (15 + IH2_BASE)
-#define INT_730_MCSI (16 + IH2_BASE)
-#define INT_730_uWireTX (17 + IH2_BASE)
-#define INT_730_uWireRX (18 + IH2_BASE)
-#define INT_730_SMC_CD (19 + IH2_BASE)
-#define INT_730_SMC_IREQ (20 + IH2_BASE)
-#define INT_730_HDQ_1WIRE (21 + IH2_BASE)
-#define INT_730_TIMER32K (22 + IH2_BASE)
-#define INT_730_MMC_SDIO (23 + IH2_BASE)
-#define INT_730_UPLD (24 + IH2_BASE)
-#define INT_730_USB_HHC_1 (27 + IH2_BASE)
-#define INT_730_USB_HHC_2 (28 + IH2_BASE)
-#define INT_730_USB_GENI (29 + IH2_BASE)
-#define INT_730_USB_OTG (30 + IH2_BASE)
-#define INT_730_CAMERA_IF (31 + IH2_BASE)
-#define INT_730_RNG (32 + IH2_BASE)
-#define INT_730_DUAL_MODE_TIMER (33 + IH2_BASE)
-#define INT_730_DBB_RF_EN (34 + IH2_BASE)
-#define INT_730_MPUIO_KEYPAD (35 + IH2_BASE)
-#define INT_730_SHA1_MD5 (36 + IH2_BASE)
-#define INT_730_SPI_100K_2 (37 + IH2_BASE)
-#define INT_730_RNG_IDLE (38 + IH2_BASE)
-#define INT_730_MPUIO (39 + IH2_BASE)
-#define INT_730_LLPC_LCD_CTRL_CAN_BE_OFF (40 + IH2_BASE)
-#define INT_730_LLPC_OE_FALLING (41 + IH2_BASE)
-#define INT_730_LLPC_OE_RISING (42 + IH2_BASE)
-#define INT_730_LLPC_VSYNC (43 + IH2_BASE)
-#define INT_730_WAKE_UP_REQ (46 + IH2_BASE)
-#define INT_730_DMA_CH6 (53 + IH2_BASE)
-#define INT_730_DMA_CH7 (54 + IH2_BASE)
-#define INT_730_DMA_CH8 (55 + IH2_BASE)
-#define INT_730_DMA_CH9 (56 + IH2_BASE)
-#define INT_730_DMA_CH10 (57 + IH2_BASE)
-#define INT_730_DMA_CH11 (58 + IH2_BASE)
-#define INT_730_DMA_CH12 (59 + IH2_BASE)
-#define INT_730_DMA_CH13 (60 + IH2_BASE)
-#define INT_730_DMA_CH14 (61 + IH2_BASE)
-#define INT_730_DMA_CH15 (62 + IH2_BASE)
-#define INT_730_NAND (63 + IH2_BASE)
-
-/*
- * OMAP-850 specific IRQ numbers for interrupt handler 2
+ * OMAP-7xx specific IRQ numbers for interrupt handler 2
*/
-#define INT_850_HW_ERRORS (0 + IH2_BASE)
-#define INT_850_NFIQ_PWR_FAIL (1 + IH2_BASE)
-#define INT_850_CFCD (2 + IH2_BASE)
-#define INT_850_CFIREQ (3 + IH2_BASE)
-#define INT_850_I2C (4 + IH2_BASE)
-#define INT_850_PCC (5 + IH2_BASE)
-#define INT_850_MPU_EXT_NIRQ (6 + IH2_BASE)
-#define INT_850_SPI_100K_1 (7 + IH2_BASE)
-#define INT_850_SYREN_SPI (8 + IH2_BASE)
-#define INT_850_VLYNQ (9 + IH2_BASE)
-#define INT_850_GPIO_BANK4 (10 + IH2_BASE)
-#define INT_850_McBSP1TX (11 + IH2_BASE)
-#define INT_850_McBSP1RX (12 + IH2_BASE)
-#define INT_850_McBSP1RX_OF (13 + IH2_BASE)
-#define INT_850_UART_MODEM_IRDA_2 (14 + IH2_BASE)
-#define INT_850_UART_MODEM_1 (15 + IH2_BASE)
-#define INT_850_MCSI (16 + IH2_BASE)
-#define INT_850_uWireTX (17 + IH2_BASE)
-#define INT_850_uWireRX (18 + IH2_BASE)
-#define INT_850_SMC_CD (19 + IH2_BASE)
-#define INT_850_SMC_IREQ (20 + IH2_BASE)
-#define INT_850_HDQ_1WIRE (21 + IH2_BASE)
-#define INT_850_TIMER32K (22 + IH2_BASE)
-#define INT_850_MMC_SDIO (23 + IH2_BASE)
-#define INT_850_UPLD (24 + IH2_BASE)
-#define INT_850_USB_HHC_1 (27 + IH2_BASE)
-#define INT_850_USB_HHC_2 (28 + IH2_BASE)
-#define INT_850_USB_GENI (29 + IH2_BASE)
-#define INT_850_USB_OTG (30 + IH2_BASE)
-#define INT_850_CAMERA_IF (31 + IH2_BASE)
-#define INT_850_RNG (32 + IH2_BASE)
-#define INT_850_DUAL_MODE_TIMER (33 + IH2_BASE)
-#define INT_850_DBB_RF_EN (34 + IH2_BASE)
-#define INT_850_MPUIO_KEYPAD (35 + IH2_BASE)
-#define INT_850_SHA1_MD5 (36 + IH2_BASE)
-#define INT_850_SPI_100K_2 (37 + IH2_BASE)
-#define INT_850_RNG_IDLE (38 + IH2_BASE)
-#define INT_850_MPUIO (39 + IH2_BASE)
-#define INT_850_LLPC_LCD_CTRL_CAN_BE_OFF (40 + IH2_BASE)
-#define INT_850_LLPC_OE_FALLING (41 + IH2_BASE)
-#define INT_850_LLPC_OE_RISING (42 + IH2_BASE)
-#define INT_850_LLPC_VSYNC (43 + IH2_BASE)
-#define INT_850_WAKE_UP_REQ (46 + IH2_BASE)
-#define INT_850_DMA_CH6 (53 + IH2_BASE)
-#define INT_850_DMA_CH7 (54 + IH2_BASE)
-#define INT_850_DMA_CH8 (55 + IH2_BASE)
-#define INT_850_DMA_CH9 (56 + IH2_BASE)
-#define INT_850_DMA_CH10 (57 + IH2_BASE)
-#define INT_850_DMA_CH11 (58 + IH2_BASE)
-#define INT_850_DMA_CH12 (59 + IH2_BASE)
-#define INT_850_DMA_CH13 (60 + IH2_BASE)
-#define INT_850_DMA_CH14 (61 + IH2_BASE)
-#define INT_850_DMA_CH15 (62 + IH2_BASE)
-#define INT_850_NAND (63 + IH2_BASE)
+#define INT_7XX_HW_ERRORS (0 + IH2_BASE)
+#define INT_7XX_NFIQ_PWR_FAIL (1 + IH2_BASE)
+#define INT_7XX_CFCD (2 + IH2_BASE)
+#define INT_7XX_CFIREQ (3 + IH2_BASE)
+#define INT_7XX_I2C (4 + IH2_BASE)
+#define INT_7XX_PCC (5 + IH2_BASE)
+#define INT_7XX_MPU_EXT_NIRQ (6 + IH2_BASE)
+#define INT_7XX_SPI_100K_1 (7 + IH2_BASE)
+#define INT_7XX_SYREN_SPI (8 + IH2_BASE)
+#define INT_7XX_VLYNQ (9 + IH2_BASE)
+#define INT_7XX_GPIO_BANK4 (10 + IH2_BASE)
+#define INT_7XX_McBSP1TX (11 + IH2_BASE)
+#define INT_7XX_McBSP1RX (12 + IH2_BASE)
+#define INT_7XX_McBSP1RX_OF (13 + IH2_BASE)
+#define INT_7XX_UART_MODEM_IRDA_2 (14 + IH2_BASE)
+#define INT_7XX_UART_MODEM_1 (15 + IH2_BASE)
+#define INT_7XX_MCSI (16 + IH2_BASE)
+#define INT_7XX_uWireTX (17 + IH2_BASE)
+#define INT_7XX_uWireRX (18 + IH2_BASE)
+#define INT_7XX_SMC_CD (19 + IH2_BASE)
+#define INT_7XX_SMC_IREQ (20 + IH2_BASE)
+#define INT_7XX_HDQ_1WIRE (21 + IH2_BASE)
+#define INT_7XX_TIMER32K (22 + IH2_BASE)
+#define INT_7XX_MMC_SDIO (23 + IH2_BASE)
+#define INT_7XX_UPLD (24 + IH2_BASE)
+#define INT_7XX_USB_HHC_1 (27 + IH2_BASE)
+#define INT_7XX_USB_HHC_2 (28 + IH2_BASE)
+#define INT_7XX_USB_GENI (29 + IH2_BASE)
+#define INT_7XX_USB_OTG (30 + IH2_BASE)
+#define INT_7XX_CAMERA_IF (31 + IH2_BASE)
+#define INT_7XX_RNG (32 + IH2_BASE)
+#define INT_7XX_DUAL_MODE_TIMER (33 + IH2_BASE)
+#define INT_7XX_DBB_RF_EN (34 + IH2_BASE)
+#define INT_7XX_MPUIO_KEYPAD (35 + IH2_BASE)
+#define INT_7XX_SHA1_MD5 (36 + IH2_BASE)
+#define INT_7XX_SPI_100K_2 (37 + IH2_BASE)
+#define INT_7XX_RNG_IDLE (38 + IH2_BASE)
+#define INT_7XX_MPUIO (39 + IH2_BASE)
+#define INT_7XX_LLPC_LCD_CTRL_CAN_BE_OFF (40 + IH2_BASE)
+#define INT_7XX_LLPC_OE_FALLING (41 + IH2_BASE)
+#define INT_7XX_LLPC_OE_RISING (42 + IH2_BASE)
+#define INT_7XX_LLPC_VSYNC (43 + IH2_BASE)
+#define INT_7XX_WAKE_UP_REQ (46 + IH2_BASE)
+#define INT_7XX_DMA_CH6 (53 + IH2_BASE)
+#define INT_7XX_DMA_CH7 (54 + IH2_BASE)
+#define INT_7XX_DMA_CH8 (55 + IH2_BASE)
+#define INT_7XX_DMA_CH9 (56 + IH2_BASE)
+#define INT_7XX_DMA_CH10 (57 + IH2_BASE)
+#define INT_7XX_DMA_CH11 (58 + IH2_BASE)
+#define INT_7XX_DMA_CH12 (59 + IH2_BASE)
+#define INT_7XX_DMA_CH13 (60 + IH2_BASE)
+#define INT_7XX_DMA_CH14 (61 + IH2_BASE)
+#define INT_7XX_DMA_CH15 (62 + IH2_BASE)
+#define INT_7XX_NAND (63 + IH2_BASE)
#define INT_24XX_SYS_NIRQ 7
#define INT_24XX_SDMA_IRQ0 12
diff --git a/arch/arm/plat-omap/include/mach/keypad.h b/arch/arm/plat-omap/include/plat/keypad.h
index d91b9be334ff..d91b9be334ff 100644
--- a/arch/arm/plat-omap/include/mach/keypad.h
+++ b/arch/arm/plat-omap/include/plat/keypad.h
diff --git a/arch/arm/plat-omap/include/mach/lcd_mipid.h b/arch/arm/plat-omap/include/plat/lcd_mipid.h
index 8e52c6572281..8e52c6572281 100644
--- a/arch/arm/plat-omap/include/mach/lcd_mipid.h
+++ b/arch/arm/plat-omap/include/plat/lcd_mipid.h
diff --git a/arch/arm/plat-omap/include/mach/led.h b/arch/arm/plat-omap/include/plat/led.h
index 25e451e7e2fd..25e451e7e2fd 100644
--- a/arch/arm/plat-omap/include/mach/led.h
+++ b/arch/arm/plat-omap/include/plat/led.h
diff --git a/arch/arm/plat-omap/include/mach/mailbox.h b/arch/arm/plat-omap/include/plat/mailbox.h
index b7a6991814ec..b7a6991814ec 100644
--- a/arch/arm/plat-omap/include/mach/mailbox.h
+++ b/arch/arm/plat-omap/include/plat/mailbox.h
diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/plat/mcbsp.h
index e0d6eca222cc..4f22e5bb7ff7 100644
--- a/arch/arm/plat-omap/include/mach/mcbsp.h
+++ b/arch/arm/plat-omap/include/plat/mcbsp.h
@@ -28,10 +28,10 @@
#include <linux/spinlock.h>
#include <mach/hardware.h>
-#include <mach/clock.h>
+#include <plat/clock.h>
-#define OMAP730_MCBSP1_BASE 0xfffb1000
-#define OMAP730_MCBSP2_BASE 0xfffb1800
+#define OMAP7XX_MCBSP1_BASE 0xfffb1000
+#define OMAP7XX_MCBSP2_BASE 0xfffb1800
#define OMAP1510_MCBSP1_BASE 0xe1011800
#define OMAP1510_MCBSP2_BASE 0xfffb1000
@@ -58,7 +58,7 @@
#define OMAP44XX_MCBSP3_BASE 0x49026000
#define OMAP44XX_MCBSP4_BASE 0x48074000
-#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP730)
+#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
#define OMAP_MCBSP_REG_DRR2 0x00
#define OMAP_MCBSP_REG_DRR1 0x02
diff --git a/arch/arm/plat-omap/include/mach/mcspi.h b/arch/arm/plat-omap/include/plat/mcspi.h
index 1254e4945b6f..1254e4945b6f 100644
--- a/arch/arm/plat-omap/include/mach/mcspi.h
+++ b/arch/arm/plat-omap/include/plat/mcspi.h
diff --git a/arch/arm/plat-omap/include/mach/memory.h b/arch/arm/plat-omap/include/plat/memory.h
index 9ad41dc484c1..9ad41dc484c1 100644
--- a/arch/arm/plat-omap/include/mach/memory.h
+++ b/arch/arm/plat-omap/include/plat/memory.h
diff --git a/arch/arm/plat-omap/include/mach/menelaus.h b/arch/arm/plat-omap/include/plat/menelaus.h
index 3122bf68c7ce..3122bf68c7ce 100644
--- a/arch/arm/plat-omap/include/mach/menelaus.h
+++ b/arch/arm/plat-omap/include/plat/menelaus.h
diff --git a/arch/arm/plat-omap/include/mach/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h
index 7229b9593301..29937137bf3e 100644
--- a/arch/arm/plat-omap/include/mach/mmc.h
+++ b/arch/arm/plat-omap/include/plat/mmc.h
@@ -15,7 +15,7 @@
#include <linux/device.h>
#include <linux/mmc/host.h>
-#include <mach/board.h>
+#include <plat/board.h>
#define OMAP15XX_NR_MMC 1
#define OMAP16XX_NR_MMC 2
diff --git a/arch/arm/plat-omap/include/mach/mux.h b/arch/arm/plat-omap/include/plat/mux.h
index 0f49d2d563d9..f3c1d8a90456 100644
--- a/arch/arm/plat-omap/include/mach/mux.h
+++ b/arch/arm/plat-omap/include/plat/mux.h
@@ -51,23 +51,13 @@
.pu_pd_reg = PU_PD_SEL_##reg, \
.pu_pd_val = status,
-#define MUX_REG_730(reg, mode_offset, mode) .mux_reg_name = "OMAP730_IO_CONF_"#reg, \
- .mux_reg = OMAP730_IO_CONF_##reg, \
+#define MUX_REG_7XX(reg, mode_offset, mode) .mux_reg_name = "OMAP7XX_IO_CONF_"#reg, \
+ .mux_reg = OMAP7XX_IO_CONF_##reg, \
.mask_offset = mode_offset, \
.mask = mode,
-#define PULL_REG_730(reg, bit, status) .pull_name = "OMAP730_IO_CONF_"#reg, \
- .pull_reg = OMAP730_IO_CONF_##reg, \
- .pull_bit = bit, \
- .pull_val = status,
-
-#define MUX_REG_850(reg, mode_offset, mode) .mux_reg_name = "OMAP850_IO_CONF_"#reg, \
- .mux_reg = OMAP850_IO_CONF_##reg, \
- .mask_offset = mode_offset, \
- .mask = mode,
-
-#define PULL_REG_850(reg, bit, status) .pull_name = "OMAP850_IO_CONF_"#reg, \
- .pull_reg = OMAP850_IO_CONF_##reg, \
+#define PULL_REG_7XX(reg, bit, status) .pull_name = "OMAP7XX_IO_CONF_"#reg, \
+ .pull_reg = OMAP7XX_IO_CONF_##reg, \
.pull_bit = bit, \
.pull_val = status,
@@ -84,21 +74,12 @@
#define PU_PD_REG(reg, status) .pu_pd_reg = PU_PD_SEL_##reg, \
.pu_pd_val = status,
-#define MUX_REG_730(reg, mode_offset, mode) \
- .mux_reg = OMAP730_IO_CONF_##reg, \
+#define MUX_REG_7XX(reg, mode_offset, mode) \
+ .mux_reg = OMAP7XX_IO_CONF_##reg, \
.mask_offset = mode_offset, \
.mask = mode,
-#define PULL_REG_730(reg, bit, status) .pull_reg = OMAP730_IO_CONF_##reg, \
- .pull_bit = bit, \
- .pull_val = status,
-
-#define MUX_REG_850(reg, mode_offset, mode) \
- .mux_reg = OMAP850_IO_CONF_##reg, \
- .mask_offset = mode_offset, \
- .mask = mode,
-
-#define PULL_REG_850(reg, bit, status) .pull_reg = OMAP850_IO_CONF_##reg, \
+#define PULL_REG_7XX(reg, bit, status) .pull_reg = OMAP7XX_IO_CONF_##reg, \
.pull_bit = bit, \
.pull_val = status,
@@ -118,32 +99,21 @@
/*
* OMAP730/850 has a slightly different config for the pin mux.
- * - config regs are the OMAP730_IO_CONF_x regs (see omap730.h) regs and
+ * - config regs are the OMAP7XX_IO_CONF_x regs (see omap730.h) regs and
* not the FUNC_MUX_CTRL_x regs from hardware.h
* - for pull-up/down, only has one enable bit which is is in the same register
* as mux config
*/
-#define MUX_CFG_730(desc, mux_reg, mode_offset, mode, \
+#define MUX_CFG_7XX(desc, mux_reg, mode_offset, mode, \
pull_bit, pull_status, debug_status)\
{ \
.name = desc, \
.debug = debug_status, \
- MUX_REG_730(mux_reg, mode_offset, mode) \
- PULL_REG_730(mux_reg, pull_bit, pull_status) \
+ MUX_REG_7XX(mux_reg, mode_offset, mode) \
+ PULL_REG_7XX(mux_reg, pull_bit, pull_status) \
PU_PD_REG(NA, 0) \
},
-#define MUX_CFG_850(desc, mux_reg, mode_offset, mode, \
- pull_bit, pull_status, debug_status)\
-{ \
- .name = desc, \
- .debug = debug_status, \
- MUX_REG_850(mux_reg, mode_offset, mode) \
- PULL_REG_850(mux_reg, pull_bit, pull_status) \
- PU_PD_REG(NA, 0) \
-},
-
-
#define MUX_CFG_24XX(desc, reg_offset, mode, \
pull_en, pull_mode, dbg) \
{ \
@@ -232,45 +202,25 @@ struct pin_config {
};
-enum omap730_index {
+enum omap7xx_index {
/* OMAP 730 keyboard */
- E2_730_KBR0,
- J7_730_KBR1,
- E1_730_KBR2,
- F3_730_KBR3,
- D2_730_KBR4,
- C2_730_KBC0,
- D3_730_KBC1,
- E4_730_KBC2,
- F4_730_KBC3,
- E3_730_KBC4,
-
- /* USB */
- AA17_730_USB_DM,
- W16_730_USB_PU_EN,
- W17_730_USB_VBUSI,
-};
-
-enum omap850_index {
- /* OMAP 850 keyboard */
- E2_850_KBR0,
- J7_850_KBR1,
- E1_850_KBR2,
- F3_850_KBR3,
- D2_850_KBR4,
- C2_850_KBC0,
- D3_850_KBC1,
- E4_850_KBC2,
- F4_850_KBC3,
- E3_850_KBC4,
+ E2_7XX_KBR0,
+ J7_7XX_KBR1,
+ E1_7XX_KBR2,
+ F3_7XX_KBR3,
+ D2_7XX_KBR4,
+ C2_7XX_KBC0,
+ D3_7XX_KBC1,
+ E4_7XX_KBC2,
+ F4_7XX_KBC3,
+ E3_7XX_KBC4,
/* USB */
- AA17_850_USB_DM,
- W16_850_USB_PU_EN,
- W17_850_USB_VBUSI,
+ AA17_7XX_USB_DM,
+ W16_7XX_USB_PU_EN,
+ W17_7XX_USB_VBUSI,
};
-
enum omap1xxx_index {
/* UART1 (BT_UART_GATING)*/
UART1_TX = 0,
diff --git a/arch/arm/plat-omap/include/mach/nand.h b/arch/arm/plat-omap/include/plat/nand.h
index 631a7bed1eef..631a7bed1eef 100644
--- a/arch/arm/plat-omap/include/mach/nand.h
+++ b/arch/arm/plat-omap/include/plat/nand.h
diff --git a/arch/arm/plat-omap/include/mach/omap-alsa.h b/arch/arm/plat-omap/include/plat/omap-alsa.h
index bdf30a0f87f2..b53055b390d0 100644
--- a/arch/arm/plat-omap/include/mach/omap-alsa.h
+++ b/arch/arm/plat-omap/include/plat/omap-alsa.h
@@ -40,10 +40,10 @@
#ifndef __OMAP_ALSA_H
#define __OMAP_ALSA_H
-#include <mach/dma.h>
+#include <plat/dma.h>
#include <sound/core.h>
#include <sound/pcm.h>
-#include <mach/mcbsp.h>
+#include <plat/mcbsp.h>
#include <linux/platform_device.h>
#define DMA_BUF_SIZE (1024 * 8)
diff --git a/arch/arm/plat-omap/include/mach/omap-pm.h b/arch/arm/plat-omap/include/plat/omap-pm.h
index 3ee41d711492..3ee41d711492 100644
--- a/arch/arm/plat-omap/include/mach/omap-pm.h
+++ b/arch/arm/plat-omap/include/plat/omap-pm.h
diff --git a/arch/arm/plat-omap/include/mach/omap1510.h b/arch/arm/plat-omap/include/plat/omap1510.h
index d24004668138..d24004668138 100644
--- a/arch/arm/plat-omap/include/mach/omap1510.h
+++ b/arch/arm/plat-omap/include/plat/omap1510.h
diff --git a/arch/arm/plat-omap/include/mach/omap16xx.h b/arch/arm/plat-omap/include/plat/omap16xx.h
index 0e69b504c25f..0e69b504c25f 100644
--- a/arch/arm/plat-omap/include/mach/omap16xx.h
+++ b/arch/arm/plat-omap/include/plat/omap16xx.h
diff --git a/arch/arm/plat-omap/include/mach/omap24xx.h b/arch/arm/plat-omap/include/plat/omap24xx.h
index 696edfc145a6..696edfc145a6 100644
--- a/arch/arm/plat-omap/include/mach/omap24xx.h
+++ b/arch/arm/plat-omap/include/plat/omap24xx.h
diff --git a/arch/arm/plat-omap/include/mach/omap34xx.h b/arch/arm/plat-omap/include/plat/omap34xx.h
index f8d186a73712..f8d186a73712 100644
--- a/arch/arm/plat-omap/include/mach/omap34xx.h
+++ b/arch/arm/plat-omap/include/plat/omap34xx.h
diff --git a/arch/arm/plat-omap/include/mach/omap44xx.h b/arch/arm/plat-omap/include/plat/omap44xx.h
index b3ba5ac7b4a4..336189753671 100644
--- a/arch/arm/plat-omap/include/mach/omap44xx.h
+++ b/arch/arm/plat-omap/include/plat/omap44xx.h
@@ -22,6 +22,9 @@
#define L4_PER_44XX_BASE 0x48000000
#define L4_EMU_44XX_BASE 0x54000000
#define L3_44XX_BASE 0x44000000
+#define OMAP44XX_EMIF1_BASE 0x4c000000
+#define OMAP44XX_EMIF2_BASE 0x4d000000
+#define OMAP44XX_DMM_BASE 0x4e000000
#define OMAP4430_32KSYNCT_BASE 0x4a304000
#define OMAP4430_CM_BASE 0x4a004000
#define OMAP4430_PRM_BASE 0x48306000
@@ -33,14 +36,9 @@
#define IRQ_SIR_IRQ 0x0040
#define OMAP44XX_GIC_DIST_BASE 0x48241000
#define OMAP44XX_GIC_CPU_BASE 0x48240100
-#define OMAP44XX_VA_GIC_CPU_BASE OMAP2_IO_ADDRESS(OMAP44XX_GIC_CPU_BASE)
#define OMAP44XX_SCU_BASE 0x48240000
-#define OMAP44XX_VA_SCU_BASE OMAP2_IO_ADDRESS(OMAP44XX_SCU_BASE)
#define OMAP44XX_LOCAL_TWD_BASE 0x48240600
-#define OMAP44XX_VA_LOCAL_TWD_BASE OMAP2_IO_ADDRESS(OMAP44XX_LOCAL_TWD_BASE)
-#define OMAP44XX_LOCAL_TWD_SIZE 0x00000100
#define OMAP44XX_WKUPGEN_BASE 0x48281000
-#define OMAP44XX_VA_WKUPGEN_BASE OMAP2_IO_ADDRESS(OMAP44XX_WKUPGEN_BASE)
#endif /* __ASM_ARCH_OMAP44XX_H */
diff --git a/arch/arm/plat-omap/include/mach/omap730.h b/arch/arm/plat-omap/include/plat/omap730.h
index 14272bc1a6fd..14272bc1a6fd 100644
--- a/arch/arm/plat-omap/include/mach/omap730.h
+++ b/arch/arm/plat-omap/include/plat/omap730.h
diff --git a/arch/arm/plat-omap/include/plat/omap7xx.h b/arch/arm/plat-omap/include/plat/omap7xx.h
new file mode 100644
index 000000000000..53f52414b0e9
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/omap7xx.h
@@ -0,0 +1,104 @@
+/* arch/arm/plat-omap/include/mach/omap7xx.h
+ *
+ * Hardware definitions for TI OMAP7XX processor.
+ *
+ * Cleanup for Linux-2.6 by Dirk Behme <dirk.behme@de.bosch.com>
+ * Adapted for omap850 by Zebediah C. McClure <zmc@lurian.net>
+ * Adapted for omap7xx by Alistair Buxton <a.j.buxton@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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_ARCH_OMAP7XX_H
+#define __ASM_ARCH_OMAP7XX_H
+
+/*
+ * ----------------------------------------------------------------------------
+ * Base addresses
+ * ----------------------------------------------------------------------------
+ */
+
+/* Syntax: XX_BASE = Virtual base address, XX_START = Physical base address */
+
+#define OMAP7XX_DSP_BASE 0xE0000000
+#define OMAP7XX_DSP_SIZE 0x50000
+#define OMAP7XX_DSP_START 0xE0000000
+
+#define OMAP7XX_DSPREG_BASE 0xE1000000
+#define OMAP7XX_DSPREG_SIZE SZ_128K
+#define OMAP7XX_DSPREG_START 0xE1000000
+
+/*
+ * ----------------------------------------------------------------------------
+ * OMAP7XX specific configuration registers
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP7XX_CONFIG_BASE 0xfffe1000
+#define OMAP7XX_IO_CONF_0 0xfffe1070
+#define OMAP7XX_IO_CONF_1 0xfffe1074
+#define OMAP7XX_IO_CONF_2 0xfffe1078
+#define OMAP7XX_IO_CONF_3 0xfffe107c
+#define OMAP7XX_IO_CONF_4 0xfffe1080
+#define OMAP7XX_IO_CONF_5 0xfffe1084
+#define OMAP7XX_IO_CONF_6 0xfffe1088
+#define OMAP7XX_IO_CONF_7 0xfffe108c
+#define OMAP7XX_IO_CONF_8 0xfffe1090
+#define OMAP7XX_IO_CONF_9 0xfffe1094
+#define OMAP7XX_IO_CONF_10 0xfffe1098
+#define OMAP7XX_IO_CONF_11 0xfffe109c
+#define OMAP7XX_IO_CONF_12 0xfffe10a0
+#define OMAP7XX_IO_CONF_13 0xfffe10a4
+
+#define OMAP7XX_MODE_1 0xfffe1010
+#define OMAP7XX_MODE_2 0xfffe1014
+
+/* CSMI specials: in terms of base + offset */
+#define OMAP7XX_MODE2_OFFSET 0x14
+
+/*
+ * ----------------------------------------------------------------------------
+ * OMAP7XX traffic controller configuration registers
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP7XX_FLASH_CFG_0 0xfffecc10
+#define OMAP7XX_FLASH_ACFG_0 0xfffecc50
+#define OMAP7XX_FLASH_CFG_1 0xfffecc14
+#define OMAP7XX_FLASH_ACFG_1 0xfffecc54
+
+/*
+ * ----------------------------------------------------------------------------
+ * OMAP7XX DSP control registers
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP7XX_ICR_BASE 0xfffbb800
+#define OMAP7XX_DSP_M_CTL 0xfffbb804
+#define OMAP7XX_DSP_MMU_BASE 0xfffed200
+
+/*
+ * ----------------------------------------------------------------------------
+ * OMAP7XX PCC_UPLD configuration registers
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP7XX_PCC_UPLD_CTRL_BASE (0xfffe0900)
+#define OMAP7XX_PCC_UPLD_CTRL (OMAP7XX_PCC_UPLD_CTRL_BASE + 0x00)
+
+#endif /* __ASM_ARCH_OMAP7XX_H */
+
diff --git a/arch/arm/plat-omap/include/mach/omap850.h b/arch/arm/plat-omap/include/plat/omap850.h
index c33f67981712..c33f67981712 100644
--- a/arch/arm/plat-omap/include/mach/omap850.h
+++ b/arch/arm/plat-omap/include/plat/omap850.h
diff --git a/arch/arm/plat-omap/include/mach/omap_device.h b/arch/arm/plat-omap/include/plat/omap_device.h
index bd0e136db337..11a9773a4e7f 100644
--- a/arch/arm/plat-omap/include/mach/omap_device.h
+++ b/arch/arm/plat-omap/include/plat/omap_device.h
@@ -34,7 +34,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
-#include <mach/omap_hwmod.h>
+#include <plat/omap_hwmod.h>
/* omap_device._state values */
#define OMAP_DEVICE_STATE_UNKNOWN 0
diff --git a/arch/arm/plat-omap/include/mach/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 1f79c20e2929..dbdd123eca16 100644
--- a/arch/arm/plat-omap/include/mach/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -35,7 +35,7 @@
#include <linux/kernel.h>
#include <linux/ioport.h>
-#include <mach/cpu.h>
+#include <plat/cpu.h>
struct omap_device;
diff --git a/arch/arm/plat-omap/include/mach/omapfb.h b/arch/arm/plat-omap/include/plat/omapfb.h
index b226bdf45739..bfef7ab95f17 100644
--- a/arch/arm/plat-omap/include/mach/omapfb.h
+++ b/arch/arm/plat-omap/include/plat/omapfb.h
@@ -168,7 +168,7 @@ enum omapfb_update_mode {
#include <linux/fb.h>
#include <linux/mutex.h>
-#include <mach/board.h>
+#include <plat/board.h>
#define OMAP_LCDC_INV_VSYNC 0x0001
#define OMAP_LCDC_INV_HSYNC 0x0002
diff --git a/arch/arm/plat-omap/include/mach/onenand.h b/arch/arm/plat-omap/include/plat/onenand.h
index 72f433d7d827..72f433d7d827 100644
--- a/arch/arm/plat-omap/include/mach/onenand.h
+++ b/arch/arm/plat-omap/include/plat/onenand.h
diff --git a/arch/arm/plat-omap/include/mach/param.h b/arch/arm/plat-omap/include/plat/param.h
index 1eb4dc326979..1eb4dc326979 100644
--- a/arch/arm/plat-omap/include/mach/param.h
+++ b/arch/arm/plat-omap/include/plat/param.h
diff --git a/arch/arm/plat-omap/include/mach/powerdomain.h b/arch/arm/plat-omap/include/plat/powerdomain.h
index fa6461423bd0..3d45ee1d3cf4 100644
--- a/arch/arm/plat-omap/include/mach/powerdomain.h
+++ b/arch/arm/plat-omap/include/plat/powerdomain.h
@@ -19,7 +19,7 @@
#include <asm/atomic.h>
-#include <mach/cpu.h>
+#include <plat/cpu.h>
/* Powerdomain basic power states */
diff --git a/arch/arm/plat-omap/include/mach/prcm.h b/arch/arm/plat-omap/include/plat/prcm.h
index cda2a70397b4..cda2a70397b4 100644
--- a/arch/arm/plat-omap/include/mach/prcm.h
+++ b/arch/arm/plat-omap/include/plat/prcm.h
diff --git a/arch/arm/plat-omap/include/mach/sdrc.h b/arch/arm/plat-omap/include/plat/sdrc.h
index 1c09c78a48f2..7b58a5f78ce4 100644
--- a/arch/arm/plat-omap/include/mach/sdrc.h
+++ b/arch/arm/plat-omap/include/plat/sdrc.h
@@ -80,11 +80,11 @@
*/
#define OMAP242X_SMS_REGADDR(reg) \
- (void __iomem *)OMAP2_IO_ADDRESS(OMAP2420_SMS_BASE + reg)
+ (void __iomem *)OMAP2_L3_IO_ADDRESS(OMAP2420_SMS_BASE + reg)
#define OMAP243X_SMS_REGADDR(reg) \
- (void __iomem *)OMAP2_IO_ADDRESS(OMAP243X_SMS_BASE + reg)
+ (void __iomem *)OMAP2_L3_IO_ADDRESS(OMAP243X_SMS_BASE + reg)
#define OMAP343X_SMS_REGADDR(reg) \
- (void __iomem *)OMAP2_IO_ADDRESS(OMAP343X_SMS_BASE + reg)
+ (void __iomem *)OMAP2_L3_IO_ADDRESS(OMAP343X_SMS_BASE + reg)
/* SMS register offsets - read/write with sms_{read,write}_reg() */
diff --git a/arch/arm/plat-omap/include/mach/serial.h b/arch/arm/plat-omap/include/plat/serial.h
index e249186d26e2..9951345a25d6 100644
--- a/arch/arm/plat-omap/include/mach/serial.h
+++ b/arch/arm/plat-omap/include/plat/serial.h
@@ -20,26 +20,22 @@
#define OMAP_UART1_BASE 0xfffb0000
#define OMAP_UART2_BASE 0xfffb0800
#define OMAP_UART3_BASE 0xfffb9800
-#define OMAP_MAX_NR_PORTS 3
#elif defined(CONFIG_ARCH_OMAP2)
/* OMAP2 serial ports */
#define OMAP_UART1_BASE 0x4806a000
#define OMAP_UART2_BASE 0x4806c000
#define OMAP_UART3_BASE 0x4806e000
-#define OMAP_MAX_NR_PORTS 3
#elif defined(CONFIG_ARCH_OMAP3)
/* OMAP3 serial ports */
#define OMAP_UART1_BASE 0x4806a000
#define OMAP_UART2_BASE 0x4806c000
#define OMAP_UART3_BASE 0x49020000
-#define OMAP_MAX_NR_PORTS 3
#elif defined(CONFIG_ARCH_OMAP4)
/* OMAP4 serial ports */
#define OMAP_UART1_BASE 0x4806a000
#define OMAP_UART2_BASE 0x4806c000
#define OMAP_UART3_BASE 0x48020000
#define OMAP_UART4_BASE 0x4806e000
-#define OMAP_MAX_NR_PORTS 4
#endif
#define OMAP1510_BASE_BAUD (12000000/16)
diff --git a/arch/arm/plat-omap/include/mach/smp.h b/arch/arm/plat-omap/include/plat/smp.h
index dcaa8fde7063..dcaa8fde7063 100644
--- a/arch/arm/plat-omap/include/mach/smp.h
+++ b/arch/arm/plat-omap/include/plat/smp.h
diff --git a/arch/arm/plat-omap/include/mach/sram.h b/arch/arm/plat-omap/include/plat/sram.h
index 8974e3fc2691..8974e3fc2691 100644
--- a/arch/arm/plat-omap/include/mach/sram.h
+++ b/arch/arm/plat-omap/include/plat/sram.h
diff --git a/arch/arm/plat-omap/include/mach/system.h b/arch/arm/plat-omap/include/plat/system.h
index ed8ec7477261..c58a4ef42a45 100644
--- a/arch/arm/plat-omap/include/mach/system.h
+++ b/arch/arm/plat-omap/include/plat/system.h
@@ -9,7 +9,7 @@
#include <asm/mach-types.h>
#include <mach/hardware.h>
-#include <mach/prcm.h>
+#include <plat/prcm.h>
#ifndef CONFIG_MACH_VOICEBLUE
#define voiceblue_reset() do {} while (0)
diff --git a/arch/arm/plat-omap/include/mach/tc.h b/arch/arm/plat-omap/include/plat/tc.h
index d2fcd789bb9a..d2fcd789bb9a 100644
--- a/arch/arm/plat-omap/include/mach/tc.h
+++ b/arch/arm/plat-omap/include/plat/tc.h
diff --git a/arch/arm/plat-omap/include/mach/timer-gp.h b/arch/arm/plat-omap/include/plat/timer-gp.h
index c88d346b59d9..c88d346b59d9 100644
--- a/arch/arm/plat-omap/include/mach/timer-gp.h
+++ b/arch/arm/plat-omap/include/plat/timer-gp.h
diff --git a/arch/arm/plat-omap/include/mach/timex.h b/arch/arm/plat-omap/include/plat/timex.h
index 6d35767bc48f..6d35767bc48f 100644
--- a/arch/arm/plat-omap/include/mach/timex.h
+++ b/arch/arm/plat-omap/include/plat/timex.h
diff --git a/arch/arm/plat-omap/include/mach/uncompress.h b/arch/arm/plat-omap/include/plat/uncompress.h
index 0814c5f210c3..e22f57564b59 100644
--- a/arch/arm/plat-omap/include/mach/uncompress.h
+++ b/arch/arm/plat-omap/include/plat/uncompress.h
@@ -19,12 +19,13 @@
#include <linux/types.h>
#include <linux/serial_reg.h>
-#include <mach/serial.h>
+#include <plat/serial.h>
unsigned int system_rev;
#define UART_OMAP_MDR1 0x08 /* mode definition register */
#define OMAP_ID_730 0x355F
+#define OMAP_ID_850 0x362C
#define ID_MASK 0x7fff
#define check_port(base, shift) ((base[UART_OMAP_MDR1 << shift] & 7) == 0)
#define omap_get_id() ((*(volatile unsigned int *)(0xfffed404)) >> 12) & ID_MASK
@@ -53,7 +54,7 @@ static void putc(int c)
/* MMU is not on, so cpu_is_omapXXXX() won't work here */
unsigned int omap_id = omap_get_id();
- if (omap_id == OMAP_ID_730)
+ if (omap_id == OMAP_ID_730 || omap_id == OMAP_ID_850)
shift = 0;
if (check_port(uart, shift))
diff --git a/arch/arm/plat-omap/include/mach/usb.h b/arch/arm/plat-omap/include/plat/usb.h
index f337e1761e2c..33e72ca125d7 100644
--- a/arch/arm/plat-omap/include/mach/usb.h
+++ b/arch/arm/plat-omap/include/plat/usb.h
@@ -3,7 +3,7 @@
#ifndef __ASM_ARCH_OMAP_USB_H
#define __ASM_ARCH_OMAP_USB_H
-#include <mach/board.h>
+#include <plat/board.h>
/*-------------------------------------------------------------------------*/
diff --git a/arch/arm/plat-omap/io.c b/arch/arm/plat-omap/io.c
index b6defa23e77e..11f5d7961c73 100644
--- a/arch/arm/plat-omap/io.c
+++ b/arch/arm/plat-omap/io.c
@@ -13,12 +13,12 @@
#include <linux/io.h>
#include <linux/mm.h>
-#include <mach/omap730.h>
-#include <mach/omap1510.h>
-#include <mach/omap16xx.h>
-#include <mach/omap24xx.h>
-#include <mach/omap34xx.h>
-#include <mach/omap44xx.h>
+#include <plat/omap7xx.h>
+#include <plat/omap1510.h>
+#include <plat/omap16xx.h>
+#include <plat/omap24xx.h>
+#include <plat/omap34xx.h>
+#include <plat/omap44xx.h>
#define BETWEEN(p,st,sz) ((p) >= (st) && (p) < ((st) + (sz)))
#define XLATE(p,pst,vst) ((void __iomem *)((p) - (pst) + (vst)))
@@ -33,13 +33,13 @@ void __iomem *omap_ioremap(unsigned long p, size_t size, unsigned int type)
if (BETWEEN(p, OMAP1_IO_PHYS, OMAP1_IO_SIZE))
return XLATE(p, OMAP1_IO_PHYS, OMAP1_IO_VIRT);
}
- if (cpu_is_omap730()) {
- if (BETWEEN(p, OMAP730_DSP_BASE, OMAP730_DSP_SIZE))
- return XLATE(p, OMAP730_DSP_BASE, OMAP730_DSP_START);
+ if (cpu_is_omap7xx()) {
+ if (BETWEEN(p, OMAP7XX_DSP_BASE, OMAP7XX_DSP_SIZE))
+ return XLATE(p, OMAP7XX_DSP_BASE, OMAP7XX_DSP_START);
- if (BETWEEN(p, OMAP730_DSPREG_BASE, OMAP730_DSPREG_SIZE))
- return XLATE(p, OMAP730_DSPREG_BASE,
- OMAP730_DSPREG_START);
+ if (BETWEEN(p, OMAP7XX_DSPREG_BASE, OMAP7XX_DSPREG_SIZE))
+ return XLATE(p, OMAP7XX_DSPREG_BASE,
+ OMAP7XX_DSPREG_START);
}
if (cpu_is_omap15xx()) {
if (BETWEEN(p, OMAP1510_DSP_BASE, OMAP1510_DSP_SIZE))
@@ -114,6 +114,14 @@ void __iomem *omap_ioremap(unsigned long p, size_t size, unsigned int type)
return XLATE(p, L4_WK_44XX_PHYS, L4_WK_44XX_VIRT);
if (BETWEEN(p, OMAP44XX_GPMC_PHYS, OMAP44XX_GPMC_SIZE))
return XLATE(p, OMAP44XX_GPMC_PHYS, OMAP44XX_GPMC_VIRT);
+ if (BETWEEN(p, OMAP44XX_EMIF1_PHYS, OMAP44XX_EMIF1_SIZE))
+ return XLATE(p, OMAP44XX_EMIF1_PHYS, \
+ OMAP44XX_EMIF1_VIRT);
+ if (BETWEEN(p, OMAP44XX_EMIF2_PHYS, OMAP44XX_EMIF2_SIZE))
+ return XLATE(p, OMAP44XX_EMIF2_PHYS, \
+ OMAP44XX_EMIF2_VIRT);
+ if (BETWEEN(p, OMAP44XX_DMM_PHYS, OMAP44XX_DMM_SIZE))
+ return XLATE(p, OMAP44XX_DMM_PHYS, OMAP44XX_DMM_VIRT);
if (BETWEEN(p, L4_PER_44XX_PHYS, L4_PER_44XX_SIZE))
return XLATE(p, L4_PER_44XX_PHYS, L4_PER_44XX_VIRT);
if (BETWEEN(p, L4_EMU_44XX_PHYS, L4_EMU_44XX_SIZE))
@@ -142,7 +150,7 @@ u8 omap_readb(u32 pa)
if (cpu_class_is_omap1())
return __raw_readb(OMAP1_IO_ADDRESS(pa));
else
- return __raw_readb(OMAP2_IO_ADDRESS(pa));
+ return __raw_readb(OMAP2_L4_IO_ADDRESS(pa));
}
EXPORT_SYMBOL(omap_readb);
@@ -151,7 +159,7 @@ u16 omap_readw(u32 pa)
if (cpu_class_is_omap1())
return __raw_readw(OMAP1_IO_ADDRESS(pa));
else
- return __raw_readw(OMAP2_IO_ADDRESS(pa));
+ return __raw_readw(OMAP2_L4_IO_ADDRESS(pa));
}
EXPORT_SYMBOL(omap_readw);
@@ -160,7 +168,7 @@ u32 omap_readl(u32 pa)
if (cpu_class_is_omap1())
return __raw_readl(OMAP1_IO_ADDRESS(pa));
else
- return __raw_readl(OMAP2_IO_ADDRESS(pa));
+ return __raw_readl(OMAP2_L4_IO_ADDRESS(pa));
}
EXPORT_SYMBOL(omap_readl);
@@ -169,7 +177,7 @@ void omap_writeb(u8 v, u32 pa)
if (cpu_class_is_omap1())
__raw_writeb(v, OMAP1_IO_ADDRESS(pa));
else
- __raw_writeb(v, OMAP2_IO_ADDRESS(pa));
+ __raw_writeb(v, OMAP2_L4_IO_ADDRESS(pa));
}
EXPORT_SYMBOL(omap_writeb);
@@ -178,7 +186,7 @@ void omap_writew(u16 v, u32 pa)
if (cpu_class_is_omap1())
__raw_writew(v, OMAP1_IO_ADDRESS(pa));
else
- __raw_writew(v, OMAP2_IO_ADDRESS(pa));
+ __raw_writew(v, OMAP2_L4_IO_ADDRESS(pa));
}
EXPORT_SYMBOL(omap_writew);
@@ -187,6 +195,6 @@ void omap_writel(u32 v, u32 pa)
if (cpu_class_is_omap1())
__raw_writel(v, OMAP1_IO_ADDRESS(pa));
else
- __raw_writel(v, OMAP2_IO_ADDRESS(pa));
+ __raw_writel(v, OMAP2_L4_IO_ADDRESS(pa));
}
EXPORT_SYMBOL(omap_writel);
diff --git a/arch/arm/plat-omap/iommu-debug.c b/arch/arm/plat-omap/iommu-debug.c
index c799b3b0d709..afd1c27cff7c 100644
--- a/arch/arm/plat-omap/iommu-debug.c
+++ b/arch/arm/plat-omap/iommu-debug.c
@@ -17,8 +17,8 @@
#include <linux/platform_device.h>
#include <linux/debugfs.h>
-#include <mach/iommu.h>
-#include <mach/iovmm.h>
+#include <plat/iommu.h>
+#include <plat/iovmm.h>
#include "iopgtable.h"
diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c
index 4b6012707307..aa84729a0dff 100644
--- a/arch/arm/plat-omap/iommu.c
+++ b/arch/arm/plat-omap/iommu.c
@@ -20,7 +20,7 @@
#include <asm/cacheflush.h>
-#include <mach/iommu.h>
+#include <plat/iommu.h>
#include "iopgtable.h"
diff --git a/arch/arm/plat-omap/iovmm.c b/arch/arm/plat-omap/iovmm.c
index dc3fac3dd0ea..544772ede470 100644
--- a/arch/arm/plat-omap/iovmm.c
+++ b/arch/arm/plat-omap/iovmm.c
@@ -18,8 +18,8 @@
#include <asm/cacheflush.h>
#include <asm/mach/map.h>
-#include <mach/iommu.h>
-#include <mach/iovmm.h>
+#include <plat/iommu.h>
+#include <plat/iovmm.h>
#include "iopgtable.h"
@@ -392,7 +392,6 @@ static void sgtable_fill_vmalloc(struct sg_table *sgt, void *_va)
}
va_end = _va + PAGE_SIZE * i;
- flush_cache_vmap((unsigned long)_va, (unsigned long)va_end);
}
static inline void sgtable_drain_vmalloc(struct sg_table *sgt)
@@ -427,8 +426,6 @@ static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, size_t len)
len -= bytes;
}
BUG_ON(len);
-
- clean_dcache_area(va, len);
}
static inline void sgtable_drain_kmalloc(struct sg_table *sgt)
@@ -617,7 +614,7 @@ u32 iommu_vmap(struct iommu *obj, u32 da, const struct sg_table *sgt,
u32 flags)
{
size_t bytes;
- void *va;
+ void *va = NULL;
if (!obj || !obj->dev || !sgt)
return -EINVAL;
@@ -627,9 +624,11 @@ u32 iommu_vmap(struct iommu *obj, u32 da, const struct sg_table *sgt,
return -EINVAL;
bytes = PAGE_ALIGN(bytes);
- va = vmap_sg(sgt);
- if (IS_ERR(va))
- return PTR_ERR(va);
+ if (flags & IOVMF_MMIO) {
+ va = vmap_sg(sgt);
+ if (IS_ERR(va))
+ return PTR_ERR(va);
+ }
flags &= IOVMF_HW_MASK;
flags |= IOVMF_DISCONT;
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c
index 40424edae939..734bff332c82 100644
--- a/arch/arm/plat-omap/mailbox.c
+++ b/arch/arm/plat-omap/mailbox.c
@@ -26,7 +26,7 @@
#include <linux/device.h>
#include <linux/delay.h>
-#include <mach/mailbox.h>
+#include <plat/mailbox.h>
static int enable_seq_bit;
module_param(enable_seq_bit, bool, 0);
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index e664b912d7bb..92770334d728 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -24,8 +24,8 @@
#include <linux/delay.h>
#include <linux/io.h>
-#include <mach/dma.h>
-#include <mach/mcbsp.h>
+#include <plat/dma.h>
+#include <plat/mcbsp.h>
struct omap_mcbsp **mcbsp_ptr;
int omap_mcbsp_count;
diff --git a/arch/arm/plat-omap/mux.c b/arch/arm/plat-omap/mux.c
index 8d329fb20740..05aebcad215b 100644
--- a/arch/arm/plat-omap/mux.c
+++ b/arch/arm/plat-omap/mux.c
@@ -28,7 +28,7 @@
#include <linux/io.h>
#include <asm/system.h>
#include <linux/spinlock.h>
-#include <mach/mux.h>
+#include <plat/mux.h>
#ifdef CONFIG_OMAP_MUX
diff --git a/arch/arm/plat-omap/omap-pm-noop.c b/arch/arm/plat-omap/omap-pm-noop.c
index e98f0a2a6c26..186bca82cfab 100644
--- a/arch/arm/plat-omap/omap-pm-noop.c
+++ b/arch/arm/plat-omap/omap-pm-noop.c
@@ -22,9 +22,9 @@
#include <linux/device.h>
/* Interface documentation is in mach/omap-pm.h */
-#include <mach/omap-pm.h>
+#include <plat/omap-pm.h>
-#include <mach/powerdomain.h>
+#include <plat/powerdomain.h>
struct omap_opp *dsp_opps;
struct omap_opp *mpu_opps;
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index 2c409fc6dd21..bb16e624a557 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -82,8 +82,8 @@
#include <linux/err.h>
#include <linux/io.h>
-#include <mach/omap_device.h>
-#include <mach/omap_hwmod.h>
+#include <plat/omap_device.h>
+#include <plat/omap_hwmod.h>
/* These parameters are passed to _omap_device_{de,}activate() */
#define USE_WAKEUP_LAT 0
@@ -103,21 +103,6 @@
/* Private functions */
/**
- * _read_32ksynct - read the OMAP 32K sync timer
- *
- * Returns the current value of the 32KiHz synchronization counter.
- * XXX this should be generalized to simply read the system clocksource.
- * XXX this should be moved to a separate synctimer32k.c file
- */
-static u32 _read_32ksynct(void)
-{
- if (!cpu_class_is_omap2())
- BUG();
-
- return __raw_readl(OMAP2_IO_ADDRESS(OMAP_32KSYNCT_BASE + 0x010));
-}
-
-/**
* _omap_device_activate - increase device readiness
* @od: struct omap_device *
* @ignore_lat: increase to latency target (0) or full readiness (1)?
@@ -133,13 +118,13 @@ static u32 _read_32ksynct(void)
*/
static int _omap_device_activate(struct omap_device *od, u8 ignore_lat)
{
- u32 a, b;
+ struct timespec a, b, c;
pr_debug("omap_device: %s: activating\n", od->pdev.name);
while (od->pm_lat_level > 0) {
struct omap_device_pm_latency *odpl;
- int act_lat = 0;
+ unsigned long long act_lat = 0;
od->pm_lat_level--;
@@ -149,20 +134,22 @@ static int _omap_device_activate(struct omap_device *od, u8 ignore_lat)
(od->dev_wakeup_lat <= od->_dev_wakeup_lat_limit))
break;
- a = _read_32ksynct();
+ getnstimeofday(&a);
/* XXX check return code */
odpl->activate_func(od);
- b = _read_32ksynct();
+ getnstimeofday(&b);
- act_lat = (b - a) >> 15; /* 32KiHz cycles to microseconds */
+ c = timespec_sub(b, a);
+ act_lat = timespec_to_ns(&c) * NSEC_PER_USEC;
pr_debug("omap_device: %s: pm_lat %d: activate: elapsed time "
- "%d usec\n", od->pdev.name, od->pm_lat_level, act_lat);
+ "%llu usec\n", od->pdev.name, od->pm_lat_level,
+ act_lat);
WARN(act_lat > odpl->activate_lat, "omap_device: %s.%d: "
- "activate step %d took longer than expected (%d > %d)\n",
+ "activate step %d took longer than expected (%llu > %d)\n",
od->pdev.name, od->pdev.id, od->pm_lat_level,
act_lat, odpl->activate_lat);
@@ -188,13 +175,13 @@ static int _omap_device_activate(struct omap_device *od, u8 ignore_lat)
*/
static int _omap_device_deactivate(struct omap_device *od, u8 ignore_lat)
{
- u32 a, b;
+ struct timespec a, b, c;
pr_debug("omap_device: %s: deactivating\n", od->pdev.name);
while (od->pm_lat_level < od->pm_lats_cnt) {
struct omap_device_pm_latency *odpl;
- int deact_lat = 0;
+ unsigned long long deact_lat = 0;
odpl = od->pm_lats + od->pm_lat_level;
@@ -203,23 +190,24 @@ static int _omap_device_deactivate(struct omap_device *od, u8 ignore_lat)
od->_dev_wakeup_lat_limit))
break;
- a = _read_32ksynct();
+ getnstimeofday(&a);
/* XXX check return code */
odpl->deactivate_func(od);
- b = _read_32ksynct();
+ getnstimeofday(&b);
- deact_lat = (b - a) >> 15; /* 32KiHz cycles to microseconds */
+ c = timespec_sub(b, a);
+ deact_lat = timespec_to_ns(&c) * NSEC_PER_USEC;
pr_debug("omap_device: %s: pm_lat %d: deactivate: elapsed time "
- "%d usec\n", od->pdev.name, od->pm_lat_level,
+ "%llu usec\n", od->pdev.name, od->pm_lat_level,
deact_lat);
WARN(deact_lat > odpl->deactivate_lat, "omap_device: %s.%d: "
- "deactivate step %d took longer than expected (%d > %d)\n",
- od->pdev.name, od->pdev.id, od->pm_lat_level,
- deact_lat, odpl->deactivate_lat);
+ "deactivate step %d took longer than expected "
+ "(%llu > %d)\n", od->pdev.name, od->pdev.id,
+ od->pm_lat_level, deact_lat, odpl->deactivate_lat);
od->dev_wakeup_lat += odpl->activate_lat;
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index 75d1f26e5b17..a53aa8541730 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -25,11 +25,11 @@
#include <asm/mach/map.h>
-#include <mach/sram.h>
-#include <mach/board.h>
-#include <mach/cpu.h>
+#include <plat/sram.h>
+#include <plat/board.h>
+#include <plat/cpu.h>
-#include <mach/control.h>
+#include <plat/control.h>
#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
# include "../mach-omap2/prm.h"
@@ -41,14 +41,14 @@
#define OMAP1_SRAM_VA VMALLOC_END
#define OMAP2_SRAM_PA 0x40200000
#define OMAP2_SRAM_PUB_PA 0x4020f800
-#define OMAP2_SRAM_VA 0xe3000000
+#define OMAP2_SRAM_VA 0xfe400000
#define OMAP2_SRAM_PUB_VA (OMAP2_SRAM_VA + 0x800)
#define OMAP3_SRAM_PA 0x40200000
-#define OMAP3_SRAM_VA 0xe3000000
+#define OMAP3_SRAM_VA 0xfe400000
#define OMAP3_SRAM_PUB_PA 0x40208000
#define OMAP3_SRAM_PUB_VA (OMAP3_SRAM_VA + 0x8000)
#define OMAP4_SRAM_PA 0x40200000 /*0x402f0000*/
-#define OMAP4_SRAM_VA 0xd7000000 /*0xd70f0000*/
+#define OMAP4_SRAM_VA 0xfe400000 /*0xfe4f0000*/
#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
#define SRAM_BOOTLOADER_SZ 0x00
@@ -56,16 +56,16 @@
#define SRAM_BOOTLOADER_SZ 0x80
#endif
-#define OMAP24XX_VA_REQINFOPERM0 OMAP2_IO_ADDRESS(0x68005048)
-#define OMAP24XX_VA_READPERM0 OMAP2_IO_ADDRESS(0x68005050)
-#define OMAP24XX_VA_WRITEPERM0 OMAP2_IO_ADDRESS(0x68005058)
+#define OMAP24XX_VA_REQINFOPERM0 OMAP2_L3_IO_ADDRESS(0x68005048)
+#define OMAP24XX_VA_READPERM0 OMAP2_L3_IO_ADDRESS(0x68005050)
+#define OMAP24XX_VA_WRITEPERM0 OMAP2_L3_IO_ADDRESS(0x68005058)
-#define OMAP34XX_VA_REQINFOPERM0 OMAP2_IO_ADDRESS(0x68012848)
-#define OMAP34XX_VA_READPERM0 OMAP2_IO_ADDRESS(0x68012850)
-#define OMAP34XX_VA_WRITEPERM0 OMAP2_IO_ADDRESS(0x68012858)
-#define OMAP34XX_VA_ADDR_MATCH2 OMAP2_IO_ADDRESS(0x68012880)
-#define OMAP34XX_VA_SMS_RG_ATT0 OMAP2_IO_ADDRESS(0x6C000048)
-#define OMAP34XX_VA_CONTROL_STAT OMAP2_IO_ADDRESS(0x480022F0)
+#define OMAP34XX_VA_REQINFOPERM0 OMAP2_L3_IO_ADDRESS(0x68012848)
+#define OMAP34XX_VA_READPERM0 OMAP2_L3_IO_ADDRESS(0x68012850)
+#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
diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c
index 509f2ed99e21..0ea1e0beb455 100644
--- a/arch/arm/plat-omap/usb.c
+++ b/arch/arm/plat-omap/usb.c
@@ -33,10 +33,10 @@
#include <asm/system.h>
#include <mach/hardware.h>
-#include <mach/control.h>
-#include <mach/mux.h>
-#include <mach/usb.h>
-#include <mach/board.h>
+#include <plat/control.h>
+#include <plat/mux.h>
+#include <plat/usb.h>
+#include <plat/board.h>
#ifdef CONFIG_ARCH_OMAP1
@@ -614,8 +614,8 @@ omap_otg_init(struct omap_usb_config *config)
if (config->otg || config->register_host) {
syscon &= ~HST_IDLE_EN;
ohci_device.dev.platform_data = config;
- if (cpu_is_omap730())
- ohci_resources[1].start = INT_730_USB_HHC_1;
+ if (cpu_is_omap7xx())
+ ohci_resources[1].start = INT_7XX_USB_HHC_1;
status = platform_device_register(&ohci_device);
if (status)
pr_debug("can't register OHCI device, %d\n", status);
@@ -626,8 +626,8 @@ omap_otg_init(struct omap_usb_config *config)
if (config->otg) {
syscon &= ~OTG_IDLE_EN;
otg_device.dev.platform_data = config;
- if (cpu_is_omap730())
- otg_resources[1].start = INT_730_USB_OTG;
+ if (cpu_is_omap7xx())
+ otg_resources[1].start = INT_7XX_USB_OTG;
status = platform_device_register(&otg_device);
if (status)
pr_debug("can't register OTG device, %d\n", status);
@@ -731,7 +731,7 @@ static inline void omap_1510_usb_init(struct omap_usb_config *config) {}
void __init omap_usb_init(struct omap_usb_config *pdata)
{
- if (cpu_is_omap730() || cpu_is_omap16xx() || cpu_is_omap24xx())
+ if (cpu_is_omap7xx() || cpu_is_omap16xx() || cpu_is_omap24xx())
omap_otg_init(pdata);
else if (cpu_is_omap15xx())
omap_1510_usb_init(pdata);
diff --git a/arch/arm/mach-pxa/include/mach/pxa3xx_nand.h b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h
index 3478eae32d8a..3478eae32d8a 100644
--- a/arch/arm/mach-pxa/include/mach/pxa3xx_nand.h
+++ b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h
diff --git a/arch/arm/plat-s3c/Kconfig b/arch/arm/plat-s3c/Kconfig
index 8931c5f0e46b..ed2096681450 100644
--- a/arch/arm/plat-s3c/Kconfig
+++ b/arch/arm/plat-s3c/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/plat-s3c/Kconfig
-#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
diff --git a/arch/arm/plat-s3c/include/plat/audio.h b/arch/arm/plat-s3c/include/plat/audio.h
deleted file mode 100644
index de0e8da48bc3..000000000000
--- a/arch/arm/plat-s3c/include/plat/audio.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/audio.h
- *
- * Copyright (c) 2004-2005 Simtec Electronics
- * http://www.simtec.co.uk/products/SWLINUX/
- * Ben Dooks <ben@simtec.co.uk>
- *
- * S3C24XX - Audio platfrom_device info
- *
- * 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_AUDIO_H
-#define __ASM_ARCH_AUDIO_H __FILE__
-
-/* struct s3c24xx_iis_ops
- *
- * called from the s3c24xx audio core to deal with the architecture
- * or the codec's setup and control.
- *
- * the pointer to itself is passed through in case the caller wants to
- * embed this in an larger structure for easy reference to it's context.
-*/
-
-struct s3c24xx_iis_ops {
- struct module *owner;
-
- int (*startup)(struct s3c24xx_iis_ops *me);
- void (*shutdown)(struct s3c24xx_iis_ops *me);
- int (*suspend)(struct s3c24xx_iis_ops *me);
- int (*resume)(struct s3c24xx_iis_ops *me);
-
- int (*open)(struct s3c24xx_iis_ops *me, struct snd_pcm_substream *strm);
- int (*close)(struct s3c24xx_iis_ops *me, struct snd_pcm_substream *strm);
- int (*prepare)(struct s3c24xx_iis_ops *me, struct snd_pcm_substream *strm, struct snd_pcm_runtime *rt);
-};
-
-struct s3c24xx_platdata_iis {
- const char *codec_clk;
- struct s3c24xx_iis_ops *ops;
- int (*match_dev)(struct device *dev);
-};
-
-#endif /* __ASM_ARCH_AUDIO_H */
diff --git a/arch/arm/plat-s3c/include/plat/regs-s3c2412-iis.h b/arch/arm/plat-s3c/include/plat/regs-s3c2412-iis.h
index 07659dad1748..abf2fbc2eb2f 100644
--- a/arch/arm/plat-s3c/include/plat/regs-s3c2412-iis.h
+++ b/arch/arm/plat-s3c/include/plat/regs-s3c2412-iis.h
@@ -67,6 +67,8 @@
#define S3C2412_IISMOD_BCLK_MASK (3 << 1)
#define S3C2412_IISMOD_8BIT (1 << 0)
+#define S3C64XX_IISMOD_CDCLKCON (1 << 12)
+
#define S3C2412_IISPSR_PSREN (1 << 15)
#define S3C2412_IISFIC_TXFLUSH (1 << 15)
diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig
index 9c7aca489643..c057e2df3afd 100644
--- a/arch/arm/plat-s3c24xx/Kconfig
+++ b/arch/arm/plat-s3c24xx/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/plat-s3c24xx/Kconfig
-#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
diff --git a/arch/arm/plat-s3c64xx/Kconfig b/arch/arm/plat-s3c64xx/Kconfig
index bcfa778614d8..e6da87a5885c 100644
--- a/arch/arm/plat-s3c64xx/Kconfig
+++ b/arch/arm/plat-s3c64xx/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/plat-s3c64xx/Kconfig
-#
# Copyright 2008 Openmoko, Inc.
# Copyright 2008 Simtec Electronics
# Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/plat-s5pc1xx/Kconfig b/arch/arm/plat-s5pc1xx/Kconfig
index a8a711c3c064..b15f2d25a68f 100644
--- a/arch/arm/plat-s5pc1xx/Kconfig
+++ b/arch/arm/plat-s5pc1xx/Kconfig
@@ -1,5 +1,3 @@
-# arch/arm/plat-s5pc1xx/Kconfig
-#
# Copyright 2009 Samsung Electronics Co.
# Byungho Min <bhmin@samsung.com>
#
diff --git a/arch/arm/tools/Makefile b/arch/arm/tools/Makefile
index 1dbaa29ac4d7..635cb1865e4d 100644
--- a/arch/arm/tools/Makefile
+++ b/arch/arm/tools/Makefile
@@ -4,7 +4,7 @@
# Copyright (C) 2001 Russell King
#
-include/asm-arm/mach-types.h: $(src)/gen-mach-types $(src)/mach-types
+include/generated/mach-types.h: $(src)/gen-mach-types $(src)/mach-types
@echo ' Generating $@'
@mkdir -p $(dir $@)
$(Q)$(AWK) -f $^ > $@ || { rm -f $@; /bin/false; }
diff --git a/arch/arm/tools/gen-mach-types b/arch/arm/tools/gen-mach-types
index ce319ef64bc1..04fef71d7be9 100644
--- a/arch/arm/tools/gen-mach-types
+++ b/arch/arm/tools/gen-mach-types
@@ -1,6 +1,6 @@
#!/bin/awk
#
-# Awk script to generate include/asm-arm/mach-types.h
+# Awk script to generate include/generated/mach-types.h
#
BEGIN { nr = 0 }
/^#/ { next }
diff --git a/arch/avr32/boards/atngw100/mrmt.c b/arch/avr32/boards/atngw100/mrmt.c
index bf78e516a85f..7919be311f4a 100644
--- a/arch/avr32/boards/atngw100/mrmt.c
+++ b/arch/avr32/boards/atngw100/mrmt.c
@@ -302,6 +302,7 @@ static int __init mrmt1_init(void)
at32_select_periph( GPIO_PIOB_BASE, 1 << (PB_EXTINT_BASE+TS_IRQ),
GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
set_irq_type( AT32_EXTINT(TS_IRQ), IRQ_TYPE_EDGE_FALLING );
+ at32_spi_setup_slaves(0,spi01_board_info,ARRAY_SIZE(spi01_board_info));
spi_register_board_info(spi01_board_info,ARRAY_SIZE(spi01_board_info));
#endif
diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c
index bc299fbbeb4e..5b022aad4bd9 100644
--- a/arch/avr32/boards/atngw100/setup.c
+++ b/arch/avr32/boards/atngw100/setup.c
@@ -56,13 +56,8 @@ static struct spi_board_info spi0_board_info[] __initdata = {
static struct mci_platform_data __initdata mci0_data = {
.slot[0] = {
.bus_width = 4,
-#if defined(CONFIG_BOARD_ATNGW100_EVKLCD10X) || defined(CONFIG_BOARD_ATNGW100_MRMT1)
- .detect_pin = GPIO_PIN_NONE,
- .wp_pin = GPIO_PIN_NONE,
-#else
.detect_pin = GPIO_PIN_PC(25),
.wp_pin = GPIO_PIN_PE(0),
-#endif
},
};
diff --git a/arch/avr32/include/asm/asm-offsets.h b/arch/avr32/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/avr32/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/avr32/include/asm/socket.h b/arch/avr32/include/asm/socket.h
index fe863f9794d5..c8d1fae49476 100644
--- a/arch/avr32/include/asm/socket.h
+++ b/arch/avr32/include/asm/socket.h
@@ -60,4 +60,6 @@
#define SO_PROTOCOL 38
#define SO_DOMAIN 39
+#define SO_RXQ_OVFL 40
+
#endif /* __ASM_AVR32_SOCKET_H */
diff --git a/arch/avr32/kernel/syscall_table.S b/arch/avr32/kernel/syscall_table.S
index 7ee0057613b3..e76bad16b0f0 100644
--- a/arch/avr32/kernel/syscall_table.S
+++ b/arch/avr32/kernel/syscall_table.S
@@ -295,4 +295,5 @@ sys_call_table:
.long sys_signalfd
.long sys_ni_syscall /* 280, was sys_timerfd */
.long sys_eventfd
+ .long sys_recvmmsg
.long sys_ni_syscall /* r8 is saturated at nr_syscalls */
diff --git a/arch/avr32/kernel/vmlinux.lds.S b/arch/avr32/kernel/vmlinux.lds.S
index c4b56654349a..9cd2bd91d64a 100644
--- a/arch/avr32/kernel/vmlinux.lds.S
+++ b/arch/avr32/kernel/vmlinux.lds.S
@@ -39,30 +39,10 @@ SECTIONS
__tagtable_begin = .;
*(.taglist.init)
__tagtable_end = .;
- INIT_DATA
- . = ALIGN(16);
- __setup_start = .;
- *(.init.setup)
- __setup_end = .;
- . = ALIGN(4);
- __initcall_start = .;
- INITCALLS
- __initcall_end = .;
- __con_initcall_start = .;
- *(.con_initcall.init)
- __con_initcall_end = .;
- __security_initcall_start = .;
- *(.security_initcall.init)
- __security_initcall_end = .;
-#ifdef CONFIG_BLK_DEV_INITRD
- . = ALIGN(32);
- __initramfs_start = .;
- *(.init.ramfs)
- __initramfs_end = .;
-#endif
- . = ALIGN(PAGE_SIZE);
- __init_end = .;
}
+ INIT_DATA_SECTION(16)
+ . = ALIGN(PAGE_SIZE);
+ __init_end = .;
.text : AT(ADDR(.text) - LOAD_OFFSET) {
_evba = .;
@@ -78,34 +58,16 @@ SECTIONS
_etext = .;
} = 0xd703d703
- . = ALIGN(4);
- __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
- __start___ex_table = .;
- *(__ex_table)
- __stop___ex_table = .;
- }
-
+ EXCEPTION_TABLE(4)
RODATA
- . = ALIGN(THREAD_SIZE);
-
.data : AT(ADDR(.data) - LOAD_OFFSET) {
_data = .;
_sdata = .;
- /*
- * First, the init task union, aligned to an 8K boundary.
- */
- *(.data.init_task)
- /* Then, the page-aligned data */
- . = ALIGN(PAGE_SIZE);
- *(.data.page_aligned)
-
- /* Then, the cacheline aligned data */
- . = ALIGN(L1_CACHE_BYTES);
- *(.data.cacheline_aligned)
-
- /* And the rest... */
+ INIT_TASK_DATA(THREAD_SIZE)
+ PAGE_ALIGNED_DATA(PAGE_SIZE);
+ CACHELINE_ALIGNED_DATA(L1_CACHE_BYTES)
*(.data.rel*)
DATA_DATA
CONSTRUCTORS
@@ -113,16 +75,8 @@ SECTIONS
_edata = .;
}
-
- . = ALIGN(8);
- .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
- __bss_start = .;
- *(.bss)
- *(COMMON)
- . = ALIGN(8);
- __bss_stop = .;
- _end = .;
- }
+ BSS_SECTION(0, 8, 8)
+ _end = .;
DWARF_DEBUG
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index eb9d4dc2e86d..a47592e2fc32 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -1181,19 +1181,32 @@ static struct resource atmel_spi1_resource[] = {
DEFINE_DEV(atmel_spi, 1);
DEV_CLK(spi_clk, atmel_spi1, pba, 1);
-static void __init
-at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b,
- unsigned int n, const u8 *pins)
+void __init
+at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b, unsigned int n)
{
+ /*
+ * Manage the chipselects as GPIOs, normally using the same pins
+ * the SPI controller expects; but boards can use other pins.
+ */
+ static u8 __initdata spi_pins[][4] = {
+ { GPIO_PIN_PA(3), GPIO_PIN_PA(4),
+ GPIO_PIN_PA(5), GPIO_PIN_PA(20) },
+ { GPIO_PIN_PB(2), GPIO_PIN_PB(3),
+ GPIO_PIN_PB(4), GPIO_PIN_PA(27) },
+ };
unsigned int pin, mode;
+ /* There are only 2 SPI controllers */
+ if (bus_num > 1)
+ return;
+
for (; n; n--, b++) {
b->bus_num = bus_num;
if (b->chip_select >= 4)
continue;
pin = (unsigned)b->controller_data;
if (!pin) {
- pin = pins[b->chip_select];
+ pin = spi_pins[bus_num][b->chip_select];
b->controller_data = (void *)pin;
}
mode = AT32_GPIOF_OUTPUT;
@@ -1206,16 +1219,6 @@ at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b,
struct platform_device *__init
at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
{
- /*
- * Manage the chipselects as GPIOs, normally using the same pins
- * the SPI controller expects; but boards can use other pins.
- */
- static u8 __initdata spi0_pins[] =
- { GPIO_PIN_PA(3), GPIO_PIN_PA(4),
- GPIO_PIN_PA(5), GPIO_PIN_PA(20), };
- static u8 __initdata spi1_pins[] =
- { GPIO_PIN_PB(2), GPIO_PIN_PB(3),
- GPIO_PIN_PB(4), GPIO_PIN_PA(27), };
struct platform_device *pdev;
u32 pin_mask;
@@ -1228,7 +1231,7 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
select_peripheral(PIOA, (1 << 0), PERIPH_A, AT32_GPIOF_PULLUP);
select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
- at32_spi_setup_slaves(0, b, n, spi0_pins);
+ at32_spi_setup_slaves(0, b, n);
break;
case 1:
@@ -1239,7 +1242,7 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
select_peripheral(PIOB, (1 << 0), PERIPH_B, AT32_GPIOF_PULLUP);
select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
- at32_spi_setup_slaves(1, b, n, spi1_pins);
+ at32_spi_setup_slaves(1, b, n);
break;
default:
diff --git a/arch/avr32/mach-at32ap/include/mach/board.h b/arch/avr32/mach-at32ap/include/mach/board.h
index ddedb471f33e..c7f25bb1d068 100644
--- a/arch/avr32/mach-at32ap/include/mach/board.h
+++ b/arch/avr32/mach-at32ap/include/mach/board.h
@@ -49,6 +49,7 @@ at32_add_device_eth(unsigned int id, struct eth_platform_data *data);
struct spi_board_info;
struct platform_device *
at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n);
+void at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b, unsigned int n);
struct atmel_lcdfb_info;
struct platform_device *
diff --git a/arch/avr32/mach-at32ap/include/mach/cpu.h b/arch/avr32/mach-at32ap/include/mach/cpu.h
index 44d0bfa1f409..c253e9bb5616 100644
--- a/arch/avr32/mach-at32ap/include/mach/cpu.h
+++ b/arch/avr32/mach-at32ap/include/mach/cpu.h
@@ -31,5 +31,7 @@
#define cpu_is_at91sam9263() (0)
#define cpu_is_at91sam9rl() (0)
#define cpu_is_at91cap9() (0)
+#define cpu_is_at91sam9g10() (0)
+#define cpu_is_at91sam9g45() (0)
#endif /* __ASM_ARCH_CPU_H */
diff --git a/arch/blackfin/include/asm/asm-offsets.h b/arch/blackfin/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/blackfin/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/blackfin/include/asm/fcntl.h b/arch/blackfin/include/asm/fcntl.h
index 8727b2b382f1..251c911d59c1 100644
--- a/arch/blackfin/include/asm/fcntl.h
+++ b/arch/blackfin/include/asm/fcntl.h
@@ -7,8 +7,6 @@
#ifndef _BFIN_FCNTL_H
#define _BFIN_FCNTL_H
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
#define O_DIRECTORY 040000 /* must be a directory */
#define O_NOFOLLOW 0100000 /* don't follow links */
#define O_DIRECT 0200000 /* direct disk access hint - currently ignored */
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index 94a0375cbdcf..a50637a8b9bd 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -1600,6 +1600,7 @@ ENTRY(_sys_call_table)
.long _sys_pwritev
.long _sys_rt_tgsigqueueinfo
.long _sys_perf_event_open
+ .long _sys_recvmmsg /* 370 */
.rept NR_syscalls-(.-_sys_call_table)/4
.long _sys_ni_syscall
diff --git a/arch/cris/arch-v10/mm/fault.c b/arch/cris/arch-v10/mm/fault.c
index 087a2096f221..ed60588f8467 100644
--- a/arch/cris/arch-v10/mm/fault.c
+++ b/arch/cris/arch-v10/mm/fault.c
@@ -80,8 +80,7 @@ handle_mmu_bus_fault(struct pt_regs *regs)
* do_page_fault may have flushed the TLB so we have to restore
* the MMU registers.
*/
- local_save_flags(flags);
- local_irq_disable();
+ local_irq_save(flags);
pmd = (pmd_t *)(pgd + pgd_index(address));
if (pmd_none(*pmd))
goto exit;
diff --git a/arch/cris/arch-v10/mm/tlb.c b/arch/cris/arch-v10/mm/tlb.c
index 4a496e4ffacc..21d78c599bab 100644
--- a/arch/cris/arch-v10/mm/tlb.c
+++ b/arch/cris/arch-v10/mm/tlb.c
@@ -134,28 +134,6 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
local_irq_restore(flags);
}
-/* dump the entire TLB for debug purposes */
-
-#if 0
-void
-dump_tlb_all(void)
-{
- int i;
- unsigned long flags;
-
- printk("TLB dump. LO is: pfn | reserved | global | valid | kernel | we |\n");
-
- local_save_flags(flags);
- local_irq_disable();
- for(i = 0; i < NUM_TLB_ENTRIES; i++) {
- *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) );
- printk("Entry %d: HI 0x%08lx, LO 0x%08lx\n",
- i, *R_TLB_HI, *R_TLB_LO);
- }
- local_irq_restore(flags);
-}
-#endif
-
/*
* Initialize the context related info for a new mm_struct
* instance.
diff --git a/arch/cris/arch-v32/kernel/head.S b/arch/cris/arch-v32/kernel/head.S
index 3db478eb5155..76266f80a5f1 100644
--- a/arch/cris/arch-v32/kernel/head.S
+++ b/arch/cris/arch-v32/kernel/head.S
@@ -10,7 +10,6 @@
* The macros found in mmu_defs_asm.h uses the ## concatenation operator, so
* -traditional must not be used when assembling this file.
*/
-#include <linux/autoconf.h>
#include <arch/memmap.h>
#include <hwregs/reg_rdwr.h>
#include <hwregs/intr_vect.h>
diff --git a/arch/cris/include/asm/asm-offsets.h b/arch/cris/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/cris/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/cris/include/asm/socket.h b/arch/cris/include/asm/socket.h
index 45ec49bdb7b1..1a4a61909ca8 100644
--- a/arch/cris/include/asm/socket.h
+++ b/arch/cris/include/asm/socket.h
@@ -62,6 +62,8 @@
#define SO_PROTOCOL 38
#define SO_DOMAIN 39
+#define SO_RXQ_OVFL 40
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/cris/kernel/asm-offsets.c b/arch/cris/kernel/asm-offsets.c
index ddd6fbbe75de..dd7b8e983221 100644
--- a/arch/cris/kernel/asm-offsets.c
+++ b/arch/cris/kernel/asm-offsets.c
@@ -1,6 +1,5 @@
#include <linux/sched.h>
#include <asm/thread_info.h>
-#include <linux/autoconf.h>
/*
* Generate definitions needed by assembly language modules.
diff --git a/arch/cris/kernel/vmlinux.lds.S b/arch/cris/kernel/vmlinux.lds.S
index bbfda67d2907..d49d17d2a14f 100644
--- a/arch/cris/kernel/vmlinux.lds.S
+++ b/arch/cris/kernel/vmlinux.lds.S
@@ -8,7 +8,6 @@
* the kernel has booted.
*/
-#include <linux/autoconf.h>
#include <asm-generic/vmlinux.lds.h>
#include <asm/page.h>
diff --git a/arch/frv/include/asm/asm-offsets.h b/arch/frv/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/frv/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/frv/include/asm/socket.h b/arch/frv/include/asm/socket.h
index 2dea726095c2..a6b26880c1ec 100644
--- a/arch/frv/include/asm/socket.h
+++ b/arch/frv/include/asm/socket.h
@@ -60,5 +60,7 @@
#define SO_PROTOCOL 38
#define SO_DOMAIN 39
+#define SO_RXQ_OVFL 40
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/frv/kernel/setup.c b/arch/frv/kernel/setup.c
index 55e4fab7c0bc..75cf7f4b2fa8 100644
--- a/arch/frv/kernel/setup.c
+++ b/arch/frv/kernel/setup.c
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/delay.h>
diff --git a/arch/h8300/include/asm/asm-offsets.h b/arch/h8300/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/h8300/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/h8300/include/asm/socket.h b/arch/h8300/include/asm/socket.h
index 1547f01c8e22..04c0f4596eb5 100644
--- a/arch/h8300/include/asm/socket.h
+++ b/arch/h8300/include/asm/socket.h
@@ -60,4 +60,6 @@
#define SO_PROTOCOL 38
#define SO_DOMAIN 39
+#define SO_RXQ_OVFL 40
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 1ee596cd942f..2d7f56a98e0f 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -87,9 +87,6 @@ config GENERIC_TIME_VSYSCALL
bool
default y
-config HAVE_LEGACY_PER_CPU_AREA
- def_bool y
-
config HAVE_SETUP_PER_CPU_AREA
def_bool y
diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile
index e7cbaa02cd0b..475e2725fbde 100644
--- a/arch/ia64/Makefile
+++ b/arch/ia64/Makefile
@@ -103,4 +103,4 @@ archprepare: make_nr_irqs_h FORCE
PHONY += make_nr_irqs_h FORCE
make_nr_irqs_h: FORCE
- $(Q)$(MAKE) $(build)=arch/ia64/kernel include/asm-ia64/nr-irqs.h
+ $(Q)$(MAKE) $(build)=arch/ia64/kernel include/generated/nr-irqs.h
diff --git a/arch/ia64/include/asm/asm-offsets.h b/arch/ia64/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/ia64/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/ia64/include/asm/irq.h b/arch/ia64/include/asm/irq.h
index 5282546cdf82..91b920fd7d53 100644
--- a/arch/ia64/include/asm/irq.h
+++ b/arch/ia64/include/asm/irq.h
@@ -13,7 +13,7 @@
#include <linux/types.h>
#include <linux/cpumask.h>
-#include <asm-ia64/nr-irqs.h>
+#include <generated/nr-irqs.h>
static __inline__ int
irq_canonicalize (int irq)
diff --git a/arch/ia64/include/asm/kvm.h b/arch/ia64/include/asm/kvm.h
index 18a7e49abbc5..bc90c75adf67 100644
--- a/arch/ia64/include/asm/kvm.h
+++ b/arch/ia64/include/asm/kvm.h
@@ -60,6 +60,7 @@ struct kvm_ioapic_state {
#define KVM_IRQCHIP_PIC_MASTER 0
#define KVM_IRQCHIP_PIC_SLAVE 1
#define KVM_IRQCHIP_IOAPIC 2
+#define KVM_NR_IRQCHIPS 3
#define KVM_CONTEXT_SIZE 8*1024
diff --git a/arch/ia64/include/asm/kvm_host.h b/arch/ia64/include/asm/kvm_host.h
index d9b6325a9328..a362e67e0ca6 100644
--- a/arch/ia64/include/asm/kvm_host.h
+++ b/arch/ia64/include/asm/kvm_host.h
@@ -475,7 +475,6 @@ struct kvm_arch {
struct list_head assigned_dev_head;
struct iommu_domain *iommu_domain;
int iommu_flags;
- struct hlist_head irq_ack_notifier_list;
unsigned long irq_sources_bitmap;
unsigned long irq_states[KVM_IOAPIC_NUM_PINS];
diff --git a/arch/ia64/include/asm/meminit.h b/arch/ia64/include/asm/meminit.h
index 688a812c017d..61c7b1750b16 100644
--- a/arch/ia64/include/asm/meminit.h
+++ b/arch/ia64/include/asm/meminit.h
@@ -61,7 +61,7 @@ extern int register_active_ranges(u64 start, u64 len, int nid);
#ifdef CONFIG_VIRTUAL_MEM_MAP
# define LARGE_GAP 0x40000000 /* Use virtual mem map if hole is > than this */
- extern unsigned long vmalloc_end;
+ extern unsigned long VMALLOC_END;
extern struct page *vmem_map;
extern int find_largest_hole(u64 start, u64 end, void *arg);
extern int create_mem_map_page_table(u64 start, u64 end, void *arg);
diff --git a/arch/ia64/include/asm/pgtable.h b/arch/ia64/include/asm/pgtable.h
index 8840a690d1e7..69bf13857a9f 100644
--- a/arch/ia64/include/asm/pgtable.h
+++ b/arch/ia64/include/asm/pgtable.h
@@ -228,8 +228,7 @@ ia64_phys_addr_valid (unsigned long addr)
#define VMALLOC_START (RGN_BASE(RGN_GATE) + 0x200000000UL)
#ifdef CONFIG_VIRTUAL_MEM_MAP
# define VMALLOC_END_INIT (RGN_BASE(RGN_GATE) + (1UL << (4*PAGE_SHIFT - 9)))
-# define VMALLOC_END vmalloc_end
- extern unsigned long vmalloc_end;
+extern unsigned long VMALLOC_END;
#else
#if defined(CONFIG_SPARSEMEM) && defined(CONFIG_SPARSEMEM_VMEMMAP)
/* SPARSEMEM_VMEMMAP uses half of vmalloc... */
diff --git a/arch/ia64/include/asm/sn/arch.h b/arch/ia64/include/asm/sn/arch.h
index 7caa1f44cd95..f5f493b0c077 100644
--- a/arch/ia64/include/asm/sn/arch.h
+++ b/arch/ia64/include/asm/sn/arch.h
@@ -71,7 +71,7 @@ DECLARE_PER_CPU(struct sn_hub_info_s, __sn_hub_info);
* Compact node ID to nasid mappings kept in the per-cpu data areas of each
* cpu.
*/
-DECLARE_PER_CPU(short, __sn_cnodeid_to_nasid[MAX_COMPACT_NODES]);
+DECLARE_PER_CPU(short [MAX_COMPACT_NODES], __sn_cnodeid_to_nasid);
#define sn_cnodeid_to_nasid (&__get_cpu_var(__sn_cnodeid_to_nasid[0]))
diff --git a/arch/ia64/include/asm/socket.h b/arch/ia64/include/asm/socket.h
index 0b0d5ff062e5..51427eaa51ba 100644
--- a/arch/ia64/include/asm/socket.h
+++ b/arch/ia64/include/asm/socket.h
@@ -69,4 +69,6 @@
#define SO_PROTOCOL 38
#define SO_DOMAIN 39
+#define SO_RXQ_OVFL 40
+
#endif /* _ASM_IA64_SOCKET_H */
diff --git a/arch/ia64/include/asm/spinlock.h b/arch/ia64/include/asm/spinlock.h
index 30bb930e1111..239ecdc9516d 100644
--- a/arch/ia64/include/asm/spinlock.h
+++ b/arch/ia64/include/asm/spinlock.h
@@ -25,61 +25,82 @@
* by atomically noting the tail and incrementing it by one (thus adding
* ourself to the queue and noting our position), then waiting until the head
* becomes equal to the the initial value of the tail.
+ * The pad bits in the middle are used to prevent the next_ticket number
+ * overflowing into the now_serving number.
*
- * 63 32 31 0
+ * 31 17 16 15 14 0
* +----------------------------------------------------+
- * | next_ticket_number | now_serving |
+ * | now_serving | padding | next_ticket |
* +----------------------------------------------------+
*/
-#define TICKET_SHIFT 32
+#define TICKET_SHIFT 17
+#define TICKET_BITS 15
+#define TICKET_MASK ((1 << TICKET_BITS) - 1)
static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
{
- int *p = (int *)&lock->lock, turn, now_serving;
+ int *p = (int *)&lock->lock, ticket, serve;
- now_serving = *p;
- turn = ia64_fetchadd(1, p+1, acq);
+ ticket = ia64_fetchadd(1, p, acq);
- if (turn == now_serving)
+ if (!(((ticket >> TICKET_SHIFT) ^ ticket) & TICKET_MASK))
return;
- do {
+ ia64_invala();
+
+ for (;;) {
+ asm volatile ("ld4.c.nc %0=[%1]" : "=r"(serve) : "r"(p) : "memory");
+
+ if (!(((serve >> TICKET_SHIFT) ^ ticket) & TICKET_MASK))
+ return;
cpu_relax();
- } while (ACCESS_ONCE(*p) != turn);
+ }
}
static __always_inline int __ticket_spin_trylock(raw_spinlock_t *lock)
{
- long tmp = ACCESS_ONCE(lock->lock), try;
-
- if (!(((tmp >> TICKET_SHIFT) ^ tmp) & ((1L << TICKET_SHIFT) - 1))) {
- try = tmp + (1L << TICKET_SHIFT);
+ int tmp = ACCESS_ONCE(lock->lock);
- return ia64_cmpxchg(acq, &lock->lock, tmp, try, sizeof (tmp)) == tmp;
- }
+ if (!(((tmp >> TICKET_SHIFT) ^ tmp) & TICKET_MASK))
+ return ia64_cmpxchg(acq, &lock->lock, tmp, tmp + 1, sizeof (tmp)) == tmp;
return 0;
}
static __always_inline void __ticket_spin_unlock(raw_spinlock_t *lock)
{
- int *p = (int *)&lock->lock;
+ unsigned short *p = (unsigned short *)&lock->lock + 1, tmp;
- (void)ia64_fetchadd(1, p, rel);
+ asm volatile ("ld2.bias %0=[%1]" : "=r"(tmp) : "r"(p));
+ ACCESS_ONCE(*p) = (tmp + 2) & ~1;
+}
+
+static __always_inline void __ticket_spin_unlock_wait(raw_spinlock_t *lock)
+{
+ int *p = (int *)&lock->lock, ticket;
+
+ ia64_invala();
+
+ for (;;) {
+ asm volatile ("ld4.c.nc %0=[%1]" : "=r"(ticket) : "r"(p) : "memory");
+ if (!(((ticket >> TICKET_SHIFT) ^ ticket) & TICKET_MASK))
+ return;
+ cpu_relax();
+ }
}
static inline int __ticket_spin_is_locked(raw_spinlock_t *lock)
{
long tmp = ACCESS_ONCE(lock->lock);
- return !!(((tmp >> TICKET_SHIFT) ^ tmp) & ((1L << TICKET_SHIFT) - 1));
+ return !!(((tmp >> TICKET_SHIFT) ^ tmp) & TICKET_MASK);
}
static inline int __ticket_spin_is_contended(raw_spinlock_t *lock)
{
long tmp = ACCESS_ONCE(lock->lock);
- return (((tmp >> TICKET_SHIFT) - tmp) & ((1L << TICKET_SHIFT) - 1)) > 1;
+ return ((tmp - (tmp >> TICKET_SHIFT)) & TICKET_MASK) > 1;
}
static inline int __raw_spin_is_locked(raw_spinlock_t *lock)
@@ -116,8 +137,7 @@ static __always_inline void __raw_spin_lock_flags(raw_spinlock_t *lock,
static inline void __raw_spin_unlock_wait(raw_spinlock_t *lock)
{
- while (__raw_spin_is_locked(lock))
- cpu_relax();
+ __ticket_spin_unlock_wait(lock);
}
#define __raw_read_can_lock(rw) (*(volatile int *)(rw) >= 0)
diff --git a/arch/ia64/include/asm/spinlock_types.h b/arch/ia64/include/asm/spinlock_types.h
index b61d136d9bc2..474e46f1ab4a 100644
--- a/arch/ia64/include/asm/spinlock_types.h
+++ b/arch/ia64/include/asm/spinlock_types.h
@@ -6,7 +6,7 @@
#endif
typedef struct {
- volatile unsigned long lock;
+ volatile unsigned int lock;
} raw_spinlock_t;
#define __RAW_SPIN_LOCK_UNLOCKED { 0 }
diff --git a/arch/ia64/include/asm/unistd.h b/arch/ia64/include/asm/unistd.h
index 5a5347f5c4e4..9c72e36c5281 100644
--- a/arch/ia64/include/asm/unistd.h
+++ b/arch/ia64/include/asm/unistd.h
@@ -311,11 +311,12 @@
#define __NR_preadv 1319
#define __NR_pwritev 1320
#define __NR_rt_tgsigqueueinfo 1321
+#define __NR_rt_recvmmsg 1322
#ifdef __KERNEL__
-#define NR_syscalls 298 /* length of syscall table */
+#define NR_syscalls 299 /* length of syscall table */
/*
* The following defines stop scripts/checksyscalls.sh from complaining about
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index 6b7edcab0cb5..2a75e937ae8d 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -81,17 +81,14 @@ define cmd_nr_irqs
endef
# We use internal kbuild rules to avoid the "is up to date" message from make
-arch/$(SRCARCH)/kernel/nr-irqs.s: $(srctree)/arch/$(SRCARCH)/kernel/nr-irqs.c \
- $(wildcard $(srctree)/include/asm-ia64/*/irq.h)
+arch/$(SRCARCH)/kernel/nr-irqs.s: arch/$(SRCARCH)/kernel/nr-irqs.c
$(Q)mkdir -p $(dir $@)
$(call if_changed_dep,cc_s_c)
-include/asm-ia64/nr-irqs.h: arch/$(SRCARCH)/kernel/nr-irqs.s
+include/generated/nr-irqs.h: arch/$(SRCARCH)/kernel/nr-irqs.s
$(Q)mkdir -p $(dir $@)
$(call cmd,nr_irqs)
-clean-files += $(objtree)/include/asm-ia64/nr-irqs.h
-
#
# native ivt.S, entry.S and fsys.S
#
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index baec6f00f7f3..40574ae11401 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -702,11 +702,23 @@ int __init early_acpi_boot_init(void)
printk(KERN_ERR PREFIX
"Error parsing MADT - no LAPIC entries\n");
+#ifdef CONFIG_SMP
+ if (available_cpus == 0) {
+ printk(KERN_INFO "ACPI: Found 0 CPUS; assuming 1\n");
+ printk(KERN_INFO "CPU 0 (0x%04x)", hard_smp_processor_id());
+ smp_boot_data.cpu_phys_id[available_cpus] =
+ hard_smp_processor_id();
+ available_cpus = 1; /* We've got at least one of these, no? */
+ }
+ smp_boot_data.cpu_count = available_cpus;
+#endif
+ /* Make boot-up look pretty */
+ printk(KERN_INFO "%d CPUs available, %d CPUs total\n", available_cpus,
+ total_cpus);
+
return 0;
}
-
-
int __init acpi_boot_init(void)
{
@@ -769,18 +781,8 @@ int __init acpi_boot_init(void)
if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt))
printk(KERN_ERR PREFIX "Can't find FADT\n");
+#ifdef CONFIG_ACPI_NUMA
#ifdef CONFIG_SMP
- if (available_cpus == 0) {
- printk(KERN_INFO "ACPI: Found 0 CPUS; assuming 1\n");
- printk(KERN_INFO "CPU 0 (0x%04x)", hard_smp_processor_id());
- smp_boot_data.cpu_phys_id[available_cpus] =
- hard_smp_processor_id();
- available_cpus = 1; /* We've got at least one of these, no? */
- }
- smp_boot_data.cpu_count = available_cpus;
-
- smp_build_cpu_map();
-# ifdef CONFIG_ACPI_NUMA
if (srat_num_cpus == 0) {
int cpu, i = 1;
for (cpu = 0; cpu < smp_boot_data.cpu_count; cpu++)
@@ -789,14 +791,9 @@ int __init acpi_boot_init(void)
node_cpuid[i++].phys_id =
smp_boot_data.cpu_phys_id[cpu];
}
-# endif
#endif
-#ifdef CONFIG_ACPI_NUMA
build_cpu_to_node_map();
#endif
- /* Make boot-up look pretty */
- printk(KERN_INFO "%d CPUs available, %d CPUs total\n", available_cpus,
- total_cpus);
return 0;
}
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index d0e7d37017b4..d75b872ca4dc 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -1806,6 +1806,7 @@ sys_call_table:
data8 sys_preadv
data8 sys_pwritev // 1320
data8 sys_rt_tgsigqueueinfo
+ data8 sys_recvmmsg
.org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls
#endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index d2877a7bfe2e..496ac7a99488 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -887,6 +887,60 @@ ia64_mca_modify_comm(const struct task_struct *previous_current)
memcpy(current->comm, comm, sizeof(current->comm));
}
+static void
+finish_pt_regs(struct pt_regs *regs, const pal_min_state_area_t *ms,
+ unsigned long *nat)
+{
+ const u64 *bank;
+
+ /* If ipsr.ic then use pmsa_{iip,ipsr,ifs}, else use
+ * pmsa_{xip,xpsr,xfs}
+ */
+ if (ia64_psr(regs)->ic) {
+ regs->cr_iip = ms->pmsa_iip;
+ regs->cr_ipsr = ms->pmsa_ipsr;
+ regs->cr_ifs = ms->pmsa_ifs;
+ } else {
+ regs->cr_iip = ms->pmsa_xip;
+ regs->cr_ipsr = ms->pmsa_xpsr;
+ regs->cr_ifs = ms->pmsa_xfs;
+ }
+ regs->pr = ms->pmsa_pr;
+ regs->b0 = ms->pmsa_br0;
+ regs->ar_rsc = ms->pmsa_rsc;
+ copy_reg(&ms->pmsa_gr[1-1], ms->pmsa_nat_bits, &regs->r1, nat);
+ copy_reg(&ms->pmsa_gr[2-1], ms->pmsa_nat_bits, &regs->r2, nat);
+ copy_reg(&ms->pmsa_gr[3-1], ms->pmsa_nat_bits, &regs->r3, nat);
+ copy_reg(&ms->pmsa_gr[8-1], ms->pmsa_nat_bits, &regs->r8, nat);
+ copy_reg(&ms->pmsa_gr[9-1], ms->pmsa_nat_bits, &regs->r9, nat);
+ copy_reg(&ms->pmsa_gr[10-1], ms->pmsa_nat_bits, &regs->r10, nat);
+ copy_reg(&ms->pmsa_gr[11-1], ms->pmsa_nat_bits, &regs->r11, nat);
+ copy_reg(&ms->pmsa_gr[12-1], ms->pmsa_nat_bits, &regs->r12, nat);
+ copy_reg(&ms->pmsa_gr[13-1], ms->pmsa_nat_bits, &regs->r13, nat);
+ copy_reg(&ms->pmsa_gr[14-1], ms->pmsa_nat_bits, &regs->r14, nat);
+ copy_reg(&ms->pmsa_gr[15-1], ms->pmsa_nat_bits, &regs->r15, nat);
+ if (ia64_psr(regs)->bn)
+ bank = ms->pmsa_bank1_gr;
+ else
+ bank = ms->pmsa_bank0_gr;
+ copy_reg(&bank[16-16], ms->pmsa_nat_bits, &regs->r16, nat);
+ copy_reg(&bank[17-16], ms->pmsa_nat_bits, &regs->r17, nat);
+ copy_reg(&bank[18-16], ms->pmsa_nat_bits, &regs->r18, nat);
+ copy_reg(&bank[19-16], ms->pmsa_nat_bits, &regs->r19, nat);
+ copy_reg(&bank[20-16], ms->pmsa_nat_bits, &regs->r20, nat);
+ copy_reg(&bank[21-16], ms->pmsa_nat_bits, &regs->r21, nat);
+ copy_reg(&bank[22-16], ms->pmsa_nat_bits, &regs->r22, nat);
+ copy_reg(&bank[23-16], ms->pmsa_nat_bits, &regs->r23, nat);
+ copy_reg(&bank[24-16], ms->pmsa_nat_bits, &regs->r24, nat);
+ copy_reg(&bank[25-16], ms->pmsa_nat_bits, &regs->r25, nat);
+ copy_reg(&bank[26-16], ms->pmsa_nat_bits, &regs->r26, nat);
+ copy_reg(&bank[27-16], ms->pmsa_nat_bits, &regs->r27, nat);
+ copy_reg(&bank[28-16], ms->pmsa_nat_bits, &regs->r28, nat);
+ copy_reg(&bank[29-16], ms->pmsa_nat_bits, &regs->r29, nat);
+ copy_reg(&bank[30-16], ms->pmsa_nat_bits, &regs->r30, nat);
+ copy_reg(&bank[31-16], ms->pmsa_nat_bits, &regs->r31, nat);
+}
+
/* On entry to this routine, we are running on the per cpu stack, see
* mca_asm.h. The original stack has not been touched by this event. Some of
* the original stack's registers will be in the RBS on this stack. This stack
@@ -921,7 +975,6 @@ ia64_mca_modify_original_stack(struct pt_regs *regs,
u64 r12 = ms->pmsa_gr[12-1], r13 = ms->pmsa_gr[13-1];
u64 ar_bspstore = regs->ar_bspstore;
u64 ar_bsp = regs->ar_bspstore + (loadrs >> 16);
- const u64 *bank;
const char *msg;
int cpu = smp_processor_id();
@@ -1024,54 +1077,9 @@ ia64_mca_modify_original_stack(struct pt_regs *regs,
p = (char *)r12 - sizeof(*regs);
old_regs = (struct pt_regs *)p;
memcpy(old_regs, regs, sizeof(*regs));
- /* If ipsr.ic then use pmsa_{iip,ipsr,ifs}, else use
- * pmsa_{xip,xpsr,xfs}
- */
- if (ia64_psr(regs)->ic) {
- old_regs->cr_iip = ms->pmsa_iip;
- old_regs->cr_ipsr = ms->pmsa_ipsr;
- old_regs->cr_ifs = ms->pmsa_ifs;
- } else {
- old_regs->cr_iip = ms->pmsa_xip;
- old_regs->cr_ipsr = ms->pmsa_xpsr;
- old_regs->cr_ifs = ms->pmsa_xfs;
- }
- old_regs->pr = ms->pmsa_pr;
- old_regs->b0 = ms->pmsa_br0;
old_regs->loadrs = loadrs;
- old_regs->ar_rsc = ms->pmsa_rsc;
old_unat = old_regs->ar_unat;
- copy_reg(&ms->pmsa_gr[1-1], ms->pmsa_nat_bits, &old_regs->r1, &old_unat);
- copy_reg(&ms->pmsa_gr[2-1], ms->pmsa_nat_bits, &old_regs->r2, &old_unat);
- copy_reg(&ms->pmsa_gr[3-1], ms->pmsa_nat_bits, &old_regs->r3, &old_unat);
- copy_reg(&ms->pmsa_gr[8-1], ms->pmsa_nat_bits, &old_regs->r8, &old_unat);
- copy_reg(&ms->pmsa_gr[9-1], ms->pmsa_nat_bits, &old_regs->r9, &old_unat);
- copy_reg(&ms->pmsa_gr[10-1], ms->pmsa_nat_bits, &old_regs->r10, &old_unat);
- copy_reg(&ms->pmsa_gr[11-1], ms->pmsa_nat_bits, &old_regs->r11, &old_unat);
- copy_reg(&ms->pmsa_gr[12-1], ms->pmsa_nat_bits, &old_regs->r12, &old_unat);
- copy_reg(&ms->pmsa_gr[13-1], ms->pmsa_nat_bits, &old_regs->r13, &old_unat);
- copy_reg(&ms->pmsa_gr[14-1], ms->pmsa_nat_bits, &old_regs->r14, &old_unat);
- copy_reg(&ms->pmsa_gr[15-1], ms->pmsa_nat_bits, &old_regs->r15, &old_unat);
- if (ia64_psr(old_regs)->bn)
- bank = ms->pmsa_bank1_gr;
- else
- bank = ms->pmsa_bank0_gr;
- copy_reg(&bank[16-16], ms->pmsa_nat_bits, &old_regs->r16, &old_unat);
- copy_reg(&bank[17-16], ms->pmsa_nat_bits, &old_regs->r17, &old_unat);
- copy_reg(&bank[18-16], ms->pmsa_nat_bits, &old_regs->r18, &old_unat);
- copy_reg(&bank[19-16], ms->pmsa_nat_bits, &old_regs->r19, &old_unat);
- copy_reg(&bank[20-16], ms->pmsa_nat_bits, &old_regs->r20, &old_unat);
- copy_reg(&bank[21-16], ms->pmsa_nat_bits, &old_regs->r21, &old_unat);
- copy_reg(&bank[22-16], ms->pmsa_nat_bits, &old_regs->r22, &old_unat);
- copy_reg(&bank[23-16], ms->pmsa_nat_bits, &old_regs->r23, &old_unat);
- copy_reg(&bank[24-16], ms->pmsa_nat_bits, &old_regs->r24, &old_unat);
- copy_reg(&bank[25-16], ms->pmsa_nat_bits, &old_regs->r25, &old_unat);
- copy_reg(&bank[26-16], ms->pmsa_nat_bits, &old_regs->r26, &old_unat);
- copy_reg(&bank[27-16], ms->pmsa_nat_bits, &old_regs->r27, &old_unat);
- copy_reg(&bank[28-16], ms->pmsa_nat_bits, &old_regs->r28, &old_unat);
- copy_reg(&bank[29-16], ms->pmsa_nat_bits, &old_regs->r29, &old_unat);
- copy_reg(&bank[30-16], ms->pmsa_nat_bits, &old_regs->r30, &old_unat);
- copy_reg(&bank[31-16], ms->pmsa_nat_bits, &old_regs->r31, &old_unat);
+ finish_pt_regs(old_regs, ms, &old_unat);
/* Next stack a struct switch_stack. mca_asm.S built a partial
* switch_stack, copy it and fill in the blanks using pt_regs and
@@ -1141,6 +1149,8 @@ ia64_mca_modify_original_stack(struct pt_regs *regs,
no_mod:
mprintk(KERN_INFO "cpu %d, %s %s, original stack not modified\n",
smp_processor_id(), type, msg);
+ old_unat = regs->ar_unat;
+ finish_pt_regs(regs, ms, &old_unat);
return previous_current;
}
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index 1de86c96801d..bc1ef4ae828c 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -566,19 +566,18 @@ setup_arch (char **cmdline_p)
early_acpi_boot_init();
# ifdef CONFIG_ACPI_NUMA
acpi_numa_init();
-#ifdef CONFIG_ACPI_HOTPLUG_CPU
+# ifdef CONFIG_ACPI_HOTPLUG_CPU
prefill_possible_map();
-#endif
+# endif
per_cpu_scan_finalize((cpus_weight(early_cpu_possible_map) == 0 ?
32 : cpus_weight(early_cpu_possible_map)),
additional_cpus > 0 ? additional_cpus : 0);
# endif
-#else
-# ifdef CONFIG_SMP
- smp_build_cpu_map(); /* happens, e.g., with the Ski simulator */
-# endif
#endif /* CONFIG_APCI_BOOT */
+#ifdef CONFIG_SMP
+ smp_build_cpu_map();
+#endif
find_memory();
/* process SAL system table: */
@@ -856,18 +855,6 @@ identify_cpu (struct cpuinfo_ia64 *c)
}
/*
- * In UP configuration, setup_per_cpu_areas() is defined in
- * include/linux/percpu.h
- */
-#ifdef CONFIG_SMP
-void __init
-setup_per_cpu_areas (void)
-{
- /* start_kernel() requires this... */
-}
-#endif
-
-/*
* Do the following calculations:
*
* 1. the max. cache line size.
diff --git a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c
index 6db08599ebbc..776dd40397e2 100644
--- a/arch/ia64/kernel/unaligned.c
+++ b/arch/ia64/kernel/unaligned.c
@@ -60,7 +60,6 @@ dump (const char *str, void *vp, size_t len)
*/
int no_unaligned_warning;
int unaligned_dump_stack;
-static int noprint_warning;
/*
* For M-unit:
@@ -1357,9 +1356,8 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs)
/* watch for command names containing %s */
printk(KERN_WARNING "%s", buf);
} else {
- if (no_unaligned_warning && !noprint_warning) {
- noprint_warning = 1;
- printk(KERN_WARNING "%s(%d) encountered an "
+ if (no_unaligned_warning) {
+ printk_once(KERN_WARNING "%s(%d) encountered an "
"unaligned exception which required\n"
"kernel assistance, which degrades "
"the performance of the application.\n"
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index 0a0c77b2c988..1295ba327f6f 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -166,6 +166,12 @@ SECTIONS
}
#endif
+#ifdef CONFIG_SMP
+ . = ALIGN(PERCPU_PAGE_SIZE);
+ __cpu0_per_cpu = .;
+ . = . + PERCPU_PAGE_SIZE; /* cpu0 per-cpu space */
+#endif
+
. = ALIGN(PAGE_SIZE);
__init_end = .;
@@ -198,11 +204,6 @@ SECTIONS
data : { } :data
.data : AT(ADDR(.data) - LOAD_OFFSET)
{
-#ifdef CONFIG_SMP
- . = ALIGN(PERCPU_PAGE_SIZE);
- __cpu0_per_cpu = .;
- . = . + PERCPU_PAGE_SIZE; /* cpu0 per-cpu space */
-#endif
INIT_TASK_DATA(PAGE_SIZE)
CACHELINE_ALIGNED_DATA(SMP_CACHE_BYTES)
READ_MOSTLY_DATA(SMP_CACHE_BYTES)
diff --git a/arch/ia64/kvm/Makefile b/arch/ia64/kvm/Makefile
index 0bb99b732908..1089b3e918ac 100644
--- a/arch/ia64/kvm/Makefile
+++ b/arch/ia64/kvm/Makefile
@@ -49,7 +49,7 @@ EXTRA_CFLAGS += -Ivirt/kvm -Iarch/ia64/kvm/
EXTRA_AFLAGS += -Ivirt/kvm -Iarch/ia64/kvm/
common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \
- coalesced_mmio.o irq_comm.o)
+ coalesced_mmio.o irq_comm.o assigned-dev.o)
ifeq ($(CONFIG_IOMMU_API),y)
common-objs += $(addprefix ../../../virt/kvm/, iommu.o)
diff --git a/arch/ia64/kvm/asm-offsets.c b/arch/ia64/kvm/asm-offsets.c
index 0c3564a7a033..9324c875caf5 100644
--- a/arch/ia64/kvm/asm-offsets.c
+++ b/arch/ia64/kvm/asm-offsets.c
@@ -22,7 +22,6 @@
*
*/
-#include <linux/autoconf.h>
#include <linux/kvm_host.h>
#include <linux/kbuild.h>
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 0ad09f05efa9..5fdeec5fddcf 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -124,7 +124,7 @@ long ia64_pal_vp_create(u64 *vpd, u64 *host_iva, u64 *opt_handler)
static DEFINE_SPINLOCK(vp_lock);
-void kvm_arch_hardware_enable(void *garbage)
+int kvm_arch_hardware_enable(void *garbage)
{
long status;
long tmp_base;
@@ -137,7 +137,7 @@ void kvm_arch_hardware_enable(void *garbage)
slot = ia64_itr_entry(0x3, KVM_VMM_BASE, pte, KVM_VMM_SHIFT);
local_irq_restore(saved_psr);
if (slot < 0)
- return;
+ return -EINVAL;
spin_lock(&vp_lock);
status = ia64_pal_vp_init_env(kvm_vsa_base ?
@@ -145,7 +145,7 @@ void kvm_arch_hardware_enable(void *garbage)
__pa(kvm_vm_buffer), KVM_VM_BUFFER_BASE, &tmp_base);
if (status != 0) {
printk(KERN_WARNING"kvm: Failed to Enable VT Support!!!!\n");
- return ;
+ return -EINVAL;
}
if (!kvm_vsa_base) {
@@ -154,6 +154,8 @@ void kvm_arch_hardware_enable(void *garbage)
}
spin_unlock(&vp_lock);
ia64_ptr_entry(0x3, slot);
+
+ return 0;
}
void kvm_arch_hardware_disable(void *garbage)
@@ -851,8 +853,7 @@ static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm,
r = 0;
switch (chip->chip_id) {
case KVM_IRQCHIP_IOAPIC:
- memcpy(&chip->chip.ioapic, ioapic_irqchip(kvm),
- sizeof(struct kvm_ioapic_state));
+ r = kvm_get_ioapic(kvm, &chip->chip.ioapic);
break;
default:
r = -EINVAL;
@@ -868,9 +869,7 @@ static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
r = 0;
switch (chip->chip_id) {
case KVM_IRQCHIP_IOAPIC:
- memcpy(ioapic_irqchip(kvm),
- &chip->chip.ioapic,
- sizeof(struct kvm_ioapic_state));
+ r = kvm_set_ioapic(kvm, &chip->chip.ioapic);
break;
default:
r = -EINVAL;
@@ -944,7 +943,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
{
struct kvm *kvm = filp->private_data;
void __user *argp = (void __user *)arg;
- int r = -EINVAL;
+ int r = -ENOTTY;
switch (ioctl) {
case KVM_SET_MEMORY_REGION: {
@@ -985,10 +984,8 @@ long kvm_arch_vm_ioctl(struct file *filp,
goto out;
if (irqchip_in_kernel(kvm)) {
__s32 status;
- mutex_lock(&kvm->irq_lock);
status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
irq_event.irq, irq_event.level);
- mutex_unlock(&kvm->irq_lock);
if (ioctl == KVM_IRQ_LINE_STATUS) {
irq_event.status = status;
if (copy_to_user(argp, &irq_event,
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
index 2f724d2bf299..54bf54059811 100644
--- a/arch/ia64/mm/contig.c
+++ b/arch/ia64/mm/contig.c
@@ -154,38 +154,99 @@ static void *cpu_data;
void * __cpuinit
per_cpu_init (void)
{
- int cpu;
- static int first_time=1;
+ static bool first_time = true;
+ void *cpu0_data = __cpu0_per_cpu;
+ unsigned int cpu;
+
+ if (!first_time)
+ goto skip;
+ first_time = false;
/*
- * get_free_pages() cannot be used before cpu_init() done. BSP
- * allocates "NR_CPUS" pages for all CPUs to avoid that AP calls
- * get_zeroed_page().
+ * get_free_pages() cannot be used before cpu_init() done.
+ * BSP allocates PERCPU_PAGE_SIZE bytes for all possible CPUs
+ * to avoid that AP calls get_zeroed_page().
*/
- if (first_time) {
- void *cpu0_data = __cpu0_per_cpu;
+ for_each_possible_cpu(cpu) {
+ void *src = cpu == 0 ? cpu0_data : __phys_per_cpu_start;
- first_time=0;
+ memcpy(cpu_data, src, __per_cpu_end - __per_cpu_start);
+ __per_cpu_offset[cpu] = (char *)cpu_data - __per_cpu_start;
+ per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu];
- __per_cpu_offset[0] = (char *) cpu0_data - __per_cpu_start;
- per_cpu(local_per_cpu_offset, 0) = __per_cpu_offset[0];
+ /*
+ * percpu area for cpu0 is moved from the __init area
+ * which is setup by head.S and used till this point.
+ * Update ar.k3. This move is ensures that percpu
+ * area for cpu0 is on the correct node and its
+ * virtual address isn't insanely far from other
+ * percpu areas which is important for congruent
+ * percpu allocator.
+ */
+ if (cpu == 0)
+ ia64_set_kr(IA64_KR_PER_CPU_DATA, __pa(cpu_data) -
+ (unsigned long)__per_cpu_start);
- for (cpu = 1; cpu < NR_CPUS; cpu++) {
- memcpy(cpu_data, __phys_per_cpu_start, __per_cpu_end - __per_cpu_start);
- __per_cpu_offset[cpu] = (char *) cpu_data - __per_cpu_start;
- cpu_data += PERCPU_PAGE_SIZE;
- per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu];
- }
+ cpu_data += PERCPU_PAGE_SIZE;
}
+skip:
return __per_cpu_start + __per_cpu_offset[smp_processor_id()];
}
static inline void
alloc_per_cpu_data(void)
{
- cpu_data = __alloc_bootmem(PERCPU_PAGE_SIZE * NR_CPUS-1,
+ cpu_data = __alloc_bootmem(PERCPU_PAGE_SIZE * num_possible_cpus(),
PERCPU_PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
}
+
+/**
+ * setup_per_cpu_areas - setup percpu areas
+ *
+ * Arch code has already allocated and initialized percpu areas. All
+ * this function has to do is to teach the determined layout to the
+ * dynamic percpu allocator, which happens to be more complex than
+ * creating whole new ones using helpers.
+ */
+void __init
+setup_per_cpu_areas(void)
+{
+ struct pcpu_alloc_info *ai;
+ struct pcpu_group_info *gi;
+ unsigned int cpu;
+ ssize_t static_size, reserved_size, dyn_size;
+ int rc;
+
+ ai = pcpu_alloc_alloc_info(1, num_possible_cpus());
+ if (!ai)
+ panic("failed to allocate pcpu_alloc_info");
+ gi = &ai->groups[0];
+
+ /* units are assigned consecutively to possible cpus */
+ for_each_possible_cpu(cpu)
+ gi->cpu_map[gi->nr_units++] = cpu;
+
+ /* set parameters */
+ static_size = __per_cpu_end - __per_cpu_start;
+ reserved_size = PERCPU_MODULE_RESERVE;
+ dyn_size = PERCPU_PAGE_SIZE - static_size - reserved_size;
+ if (dyn_size < 0)
+ panic("percpu area overflow static=%zd reserved=%zd\n",
+ static_size, reserved_size);
+
+ ai->static_size = static_size;
+ ai->reserved_size = reserved_size;
+ ai->dyn_size = dyn_size;
+ ai->unit_size = PERCPU_PAGE_SIZE;
+ ai->atom_size = PAGE_SIZE;
+ ai->alloc_size = PERCPU_PAGE_SIZE;
+
+ rc = pcpu_setup_first_chunk(ai, __per_cpu_start + __per_cpu_offset[0]);
+ if (rc)
+ panic("failed to setup percpu area (err=%d)", rc);
+
+ pcpu_free_alloc_info(ai);
+}
#else
#define alloc_per_cpu_data() do { } while (0)
#endif /* CONFIG_SMP */
@@ -270,8 +331,8 @@ paging_init (void)
map_size = PAGE_ALIGN(ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) *
sizeof(struct page));
- vmalloc_end -= map_size;
- vmem_map = (struct page *) vmalloc_end;
+ VMALLOC_END -= map_size;
+ vmem_map = (struct page *) VMALLOC_END;
efi_memmap_walk(create_mem_map_page_table, NULL);
/*
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index d85ba98d9008..40e4c1fbf76b 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -143,22 +143,120 @@ static void *per_cpu_node_setup(void *cpu_data, int node)
int cpu;
for_each_possible_early_cpu(cpu) {
- if (cpu == 0) {
- void *cpu0_data = __cpu0_per_cpu;
- __per_cpu_offset[cpu] = (char*)cpu0_data -
- __per_cpu_start;
- } else if (node == node_cpuid[cpu].nid) {
- memcpy(__va(cpu_data), __phys_per_cpu_start,
- __per_cpu_end - __per_cpu_start);
- __per_cpu_offset[cpu] = (char*)__va(cpu_data) -
- __per_cpu_start;
- cpu_data += PERCPU_PAGE_SIZE;
- }
+ void *src = cpu == 0 ? __cpu0_per_cpu : __phys_per_cpu_start;
+
+ if (node != node_cpuid[cpu].nid)
+ continue;
+
+ memcpy(__va(cpu_data), src, __per_cpu_end - __per_cpu_start);
+ __per_cpu_offset[cpu] = (char *)__va(cpu_data) -
+ __per_cpu_start;
+
+ /*
+ * percpu area for cpu0 is moved from the __init area
+ * which is setup by head.S and used till this point.
+ * Update ar.k3. This move is ensures that percpu
+ * area for cpu0 is on the correct node and its
+ * virtual address isn't insanely far from other
+ * percpu areas which is important for congruent
+ * percpu allocator.
+ */
+ if (cpu == 0)
+ ia64_set_kr(IA64_KR_PER_CPU_DATA,
+ (unsigned long)cpu_data -
+ (unsigned long)__per_cpu_start);
+
+ cpu_data += PERCPU_PAGE_SIZE;
}
#endif
return cpu_data;
}
+#ifdef CONFIG_SMP
+/**
+ * setup_per_cpu_areas - setup percpu areas
+ *
+ * Arch code has already allocated and initialized percpu areas. All
+ * this function has to do is to teach the determined layout to the
+ * dynamic percpu allocator, which happens to be more complex than
+ * creating whole new ones using helpers.
+ */
+void __init setup_per_cpu_areas(void)
+{
+ struct pcpu_alloc_info *ai;
+ struct pcpu_group_info *uninitialized_var(gi);
+ unsigned int *cpu_map;
+ void *base;
+ unsigned long base_offset;
+ unsigned int cpu;
+ ssize_t static_size, reserved_size, dyn_size;
+ int node, prev_node, unit, nr_units, rc;
+
+ ai = pcpu_alloc_alloc_info(MAX_NUMNODES, nr_cpu_ids);
+ if (!ai)
+ panic("failed to allocate pcpu_alloc_info");
+ cpu_map = ai->groups[0].cpu_map;
+
+ /* determine base */
+ base = (void *)ULONG_MAX;
+ for_each_possible_cpu(cpu)
+ base = min(base,
+ (void *)(__per_cpu_offset[cpu] + __per_cpu_start));
+ base_offset = (void *)__per_cpu_start - base;
+
+ /* build cpu_map, units are grouped by node */
+ unit = 0;
+ for_each_node(node)
+ for_each_possible_cpu(cpu)
+ if (node == node_cpuid[cpu].nid)
+ cpu_map[unit++] = cpu;
+ nr_units = unit;
+
+ /* set basic parameters */
+ static_size = __per_cpu_end - __per_cpu_start;
+ reserved_size = PERCPU_MODULE_RESERVE;
+ dyn_size = PERCPU_PAGE_SIZE - static_size - reserved_size;
+ if (dyn_size < 0)
+ panic("percpu area overflow static=%zd reserved=%zd\n",
+ static_size, reserved_size);
+
+ ai->static_size = static_size;
+ ai->reserved_size = reserved_size;
+ ai->dyn_size = dyn_size;
+ ai->unit_size = PERCPU_PAGE_SIZE;
+ ai->atom_size = PAGE_SIZE;
+ ai->alloc_size = PERCPU_PAGE_SIZE;
+
+ /*
+ * CPUs are put into groups according to node. Walk cpu_map
+ * and create new groups at node boundaries.
+ */
+ prev_node = -1;
+ ai->nr_groups = 0;
+ for (unit = 0; unit < nr_units; unit++) {
+ cpu = cpu_map[unit];
+ node = node_cpuid[cpu].nid;
+
+ if (node == prev_node) {
+ gi->nr_units++;
+ continue;
+ }
+ prev_node = node;
+
+ gi = &ai->groups[ai->nr_groups++];
+ gi->nr_units = 1;
+ gi->base_offset = __per_cpu_offset[cpu] + base_offset;
+ gi->cpu_map = &cpu_map[unit];
+ }
+
+ rc = pcpu_setup_first_chunk(ai, base);
+ if (rc)
+ panic("failed to setup percpu area (err=%d)", rc);
+
+ pcpu_free_alloc_info(ai);
+}
+#endif
+
/**
* fill_pernode - initialize pernode data.
* @node: the node id.
@@ -666,9 +764,9 @@ void __init paging_init(void)
sparse_init();
#ifdef CONFIG_VIRTUAL_MEM_MAP
- vmalloc_end -= PAGE_ALIGN(ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) *
+ VMALLOC_END -= PAGE_ALIGN(ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) *
sizeof(struct page));
- vmem_map = (struct page *) vmalloc_end;
+ vmem_map = (struct page *) VMALLOC_END;
efi_memmap_walk(create_mem_map_page_table, NULL);
printk("Virtual mem_map starts at 0x%p\n", vmem_map);
#endif
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 1857766a63c1..b9609c69343a 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -44,8 +44,8 @@ extern void ia64_tlb_init (void);
unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL;
#ifdef CONFIG_VIRTUAL_MEM_MAP
-unsigned long vmalloc_end = VMALLOC_END_INIT;
-EXPORT_SYMBOL(vmalloc_end);
+unsigned long VMALLOC_END = VMALLOC_END_INIT;
+EXPORT_SYMBOL(VMALLOC_END);
struct page *vmem_map;
EXPORT_SYMBOL(vmem_map);
#endif
diff --git a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c
index f426dc78d959..ee09d261f2e6 100644
--- a/arch/ia64/mm/tlb.c
+++ b/arch/ia64/mm/tlb.c
@@ -100,24 +100,36 @@ wrap_mmu_context (struct mm_struct *mm)
* this primitive it can be moved up to a spinaphore.h header.
*/
struct spinaphore {
- atomic_t cur;
+ unsigned long ticket;
+ unsigned long serve;
};
static inline void spinaphore_init(struct spinaphore *ss, int val)
{
- atomic_set(&ss->cur, val);
+ ss->ticket = 0;
+ ss->serve = val;
}
static inline void down_spin(struct spinaphore *ss)
{
- while (unlikely(!atomic_add_unless(&ss->cur, -1, 0)))
- while (atomic_read(&ss->cur) == 0)
- cpu_relax();
+ unsigned long t = ia64_fetchadd(1, &ss->ticket, acq), serve;
+
+ if (time_before(t, ss->serve))
+ return;
+
+ ia64_invala();
+
+ for (;;) {
+ asm volatile ("ld4.c.nc %0=[%1]" : "=r"(serve) : "r"(&ss->serve) : "memory");
+ if (time_before(t, serve))
+ return;
+ cpu_relax();
+ }
}
static inline void up_spin(struct spinaphore *ss)
{
- atomic_add(1, &ss->cur);
+ ia64_fetchadd(1, &ss->serve, rel);
}
static struct spinaphore ptcg_sem;
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 7de76dd352fe..06413b827e97 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -56,10 +56,13 @@ int raw_pci_read(unsigned int seg, unsigned int bus, unsigned int devfn,
if ((seg | reg) <= 255) {
addr = PCI_SAL_ADDRESS(seg, bus, devfn, reg);
mode = 0;
- } else {
+ } else if (sal_revision >= SAL_VERSION_CODE(3,2)) {
addr = PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg);
mode = 1;
+ } else {
+ return -EINVAL;
}
+
result = ia64_sal_pci_config_read(addr, mode, len, &data);
if (result != 0)
return -EINVAL;
@@ -80,9 +83,11 @@ int raw_pci_write(unsigned int seg, unsigned int bus, unsigned int devfn,
if ((seg | reg) <= 255) {
addr = PCI_SAL_ADDRESS(seg, bus, devfn, reg);
mode = 0;
- } else {
+ } else if (sal_revision >= SAL_VERSION_CODE(3,2)) {
addr = PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg);
mode = 1;
+ } else {
+ return -EINVAL;
}
result = ia64_sal_pci_config_write(addr, mode, len, value);
if (result != 0)
@@ -126,6 +131,7 @@ alloc_pci_controller (int seg)
}
struct pci_root_info {
+ struct acpi_device *bridge;
struct pci_controller *controller;
char *name;
};
@@ -292,9 +298,19 @@ static __devinit acpi_status add_window(struct acpi_resource *res, void *data)
window->offset = offset;
if (insert_resource(root, &window->resource)) {
- printk(KERN_ERR "alloc 0x%llx-0x%llx from %s for %s failed\n",
- window->resource.start, window->resource.end,
- root->name, info->name);
+ dev_err(&info->bridge->dev, "can't allocate %pRt\n",
+ &window->resource);
+ } else {
+ if (offset)
+ dev_info(&info->bridge->dev, "host bridge window: %pRt "
+ "(PCI address [%#llx-%#llx])\n",
+ &window->resource,
+ window->resource.start - offset,
+ window->resource.end - offset);
+ else
+ dev_info(&info->bridge->dev,
+ "host bridge window: %pRt\n",
+ &window->resource);
}
return AE_OK;
@@ -314,8 +330,7 @@ pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl)
(res->end - res->start < 16))
continue;
if (j >= PCI_BUS_NUM_RESOURCES) {
- printk("Ignoring range [%#llx-%#llx] (%lx)\n",
- res->start, res->end, res->flags);
+ dev_warn(&bus->dev, "ignoring %pRf (no space)\n", res);
continue;
}
bus->resource[j++] = res;
@@ -359,6 +374,7 @@ pci_acpi_scan_root(struct acpi_device *device, int domain, int bus)
goto out3;
sprintf(name, "PCI Bus %04x:%02x", domain, bus);
+ info.bridge = device;
info.controller = controller;
info.name = name;
acpi_walk_resources(device->handle, METHOD_NAME__CRS,
@@ -715,9 +731,6 @@ int ia64_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size)
return ret;
}
-/* It's defined in drivers/pci/pci.c */
-extern u8 pci_cache_line_size;
-
/**
* set_pci_cacheline_size - determine cacheline size for PCI devices
*
@@ -726,7 +739,7 @@ extern u8 pci_cache_line_size;
*
* Code mostly taken from arch/ia64/kernel/palinfo.c:cache_info().
*/
-static void __init set_pci_cacheline_size(void)
+static void __init set_pci_dfl_cacheline_size(void)
{
unsigned long levels, unique_caches;
long status;
@@ -746,7 +759,7 @@ static void __init set_pci_cacheline_size(void)
"(status=%ld)\n", __func__, status);
return;
}
- pci_cache_line_size = (1 << cci.pcci_line_size) / 4;
+ pci_dfl_cache_line_size = (1 << cci.pcci_line_size) / 4;
}
u64 ia64_dma_get_required_mask(struct device *dev)
@@ -777,7 +790,7 @@ EXPORT_SYMBOL_GPL(dma_get_required_mask);
static int __init pcibios_init(void)
{
- set_pci_cacheline_size();
+ set_pci_dfl_cacheline_size();
return 0;
}
diff --git a/arch/ia64/sn/kernel/io_common.c b/arch/ia64/sn/kernel/io_common.c
index 25831c47c579..308e6595110e 100644
--- a/arch/ia64/sn/kernel/io_common.c
+++ b/arch/ia64/sn/kernel/io_common.c
@@ -119,7 +119,6 @@ sn_pcidev_info_get(struct pci_dev *dev)
* Additionally note that the struct sn_flush_device_war also has to be
* removed from arch/ia64/sn/include/xtalk/hubdev.h
*/
-static u8 war_implemented = 0;
static s64 sn_device_fixup_war(u64 nasid, u64 widget, int device,
struct sn_flush_device_common *common)
@@ -128,11 +127,8 @@ static s64 sn_device_fixup_war(u64 nasid, u64 widget, int device,
struct sn_flush_device_war *dev_entry;
struct ia64_sal_retval isrv = {0,0,0,0};
- if (!war_implemented) {
- printk(KERN_WARNING "PROM version < 4.50 -- implementing old "
- "PROM flush WAR\n");
- war_implemented = 1;
- }
+ printk_once(KERN_WARNING
+ "PROM version < 4.50 -- implementing old PROM flush WAR\n");
war_list = kzalloc(DEV_PER_WIDGET * sizeof(*war_list), GFP_KERNEL);
BUG_ON(!war_list);
diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
index 4c7e74790958..55ac3c4e11d2 100644
--- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c
+++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
@@ -786,17 +786,18 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, unsigned long arg)
break;
case SN_HWPERF_GET_OBJ_NODE:
- if (a.sz != sizeof(u64) || a.arg < 0) {
+ i = a.arg;
+ if (a.sz != sizeof(u64) || i < 0) {
r = -EINVAL;
goto error;
}
if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) {
- if (a.arg >= nobj) {
+ if (i >= nobj) {
r = -EINVAL;
vfree(objs);
goto error;
}
- if (objs[(i = a.arg)].id != a.arg) {
+ if (objs[i].id != a.arg) {
for (i = 0; i < nobj; i++) {
if (objs[i].id == a.arg)
break;
diff --git a/arch/m32r/include/asm/socket.h b/arch/m32r/include/asm/socket.h
index 3390a864f224..469787c30098 100644
--- a/arch/m32r/include/asm/socket.h
+++ b/arch/m32r/include/asm/socket.h
@@ -60,4 +60,6 @@
#define SO_PROTOCOL 38
#define SO_DOMAIN 39
+#define SO_RXQ_OVFL 40
+
#endif /* _ASM_M32R_SOCKET_H */
diff --git a/arch/m68k/include/asm/asm-offsets.h b/arch/m68k/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/m68k/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h
index 74fd674b15ad..cbd3d4751dd2 100644
--- a/arch/m68k/include/asm/processor.h
+++ b/arch/m68k/include/asm/processor.h
@@ -165,6 +165,8 @@ unsigned long get_wchan(struct task_struct *p);
eip; })
#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp)
+#define task_pt_regs(tsk) ((struct pt_regs *) ((tsk)->thread.esp0))
+
#define cpu_relax() barrier()
#endif
diff --git a/arch/m68k/include/asm/ptrace.h b/arch/m68k/include/asm/ptrace.h
index 8c9194b98548..beb209195871 100644
--- a/arch/m68k/include/asm/ptrace.h
+++ b/arch/m68k/include/asm/ptrace.h
@@ -82,6 +82,18 @@ struct switch_stack {
#define instruction_pointer(regs) ((regs)->pc)
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *);
+
+/*
+ * These are defined as per linux/ptrace.h.
+ */
+struct task_struct;
+
+#ifndef CONFIG_MMU
+#define arch_has_single_step() (1)
+extern void user_enable_single_step(struct task_struct *);
+extern void user_disable_single_step(struct task_struct *);
+#endif
+
#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
#endif /* _M68K_PTRACE_H */
diff --git a/arch/m68k/include/asm/socket.h b/arch/m68k/include/asm/socket.h
index eee01cce921b..9bf49c87d954 100644
--- a/arch/m68k/include/asm/socket.h
+++ b/arch/m68k/include/asm/socket.h
@@ -60,4 +60,6 @@
#define SO_PROTOCOL 38
#define SO_DOMAIN 39
+#define SO_RXQ_OVFL 40
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
index 86edb5fbcfc3..ef54128baa0b 100644
--- a/arch/m68k/kernel/head.S
+++ b/arch/m68k/kernel/head.S
@@ -196,7 +196,7 @@
* for them and trying to understand what they mean.
*
* CONFIG_xxx: These are the obvious machine configuration defines created
- * during configuration. These are defined in include/linux/autoconf.h.
+ * during configuration. These are defined in autoconf.h.
*
* CONSOLE: There is support for head.S console in this file. This
* console can talk to a Mac frame buffer, but could easily be extrapolated
diff --git a/arch/m68knommu/kernel/ptrace.c b/arch/m68knommu/kernel/ptrace.c
index ef70ca070ce2..4d3828959fb0 100644
--- a/arch/m68knommu/kernel/ptrace.c
+++ b/arch/m68knommu/kernel/ptrace.c
@@ -86,6 +86,20 @@ static inline int put_reg(struct task_struct *task, int regno,
return 0;
}
+void user_enable_single_step(struct task_struct *task)
+{
+ unsigned long srflags;
+ srflags = get_reg(task, PT_SR) | (TRACE_BITS << 16);
+ put_reg(task, PT_SR, srflags);
+}
+
+void user_disable_single_step(struct task_struct *task)
+{
+ unsigned long srflags;
+ srflags = get_reg(task, PT_SR) & ~(TRACE_BITS << 16);
+ put_reg(task, PT_SR, srflags);
+}
+
/*
* Called by kernel/ptrace.c when detaching..
*
@@ -93,10 +107,8 @@ static inline int put_reg(struct task_struct *task, int regno,
*/
void ptrace_disable(struct task_struct *child)
{
- unsigned long tmp;
/* make sure the single step bit is not set. */
- tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
- put_reg(child, PT_SR, tmp);
+ user_disable_single_step(child);
}
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
diff --git a/arch/microblaze/include/asm/asm-offsets.h b/arch/microblaze/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/microblaze/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h
index 37e6f305a68e..ef3ec1d6ceb3 100644
--- a/arch/microblaze/include/asm/prom.h
+++ b/arch/microblaze/include/asm/prom.h
@@ -12,23 +12,15 @@
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/of.h> /* linux/of.h gets to determine #include ordering */
+
#ifndef _ASM_MICROBLAZE_PROM_H
#define _ASM_MICROBLAZE_PROM_H
#ifdef __KERNEL__
-
-/* Definitions used by the flattened device tree */
-#define OF_DT_HEADER 0xd00dfeed /* marker */
-#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */
-#define OF_DT_END_NODE 0x2 /* End node */
-#define OF_DT_PROP 0x3 /* Property: name off, size, content */
-#define OF_DT_NOP 0x4 /* nop */
-#define OF_DT_END 0x9
-
-#define OF_DT_VERSION 0x10
-
#ifndef __ASSEMBLY__
#include <linux/types.h>
+#include <linux/of_fdt.h>
#include <linux/proc_fs.h>
#include <linux/platform_device.h>
#include <asm/irq.h>
@@ -41,122 +33,19 @@
#define of_prop_cmp(s1, s2) strcmp((s1), (s2))
#define of_node_cmp(s1, s2) strcasecmp((s1), (s2))
-/*
- * This is what gets passed to the kernel by prom_init or kexec
- *
- * The dt struct contains the device tree structure, full pathes and
- * property contents. The dt strings contain a separate block with just
- * the strings for the property names, and is fully page aligned and
- * self contained in a page, so that it can be kept around by the kernel,
- * each property name appears only once in this page (cheap compression)
- *
- * the mem_rsvmap contains a map of reserved ranges of physical memory,
- * passing it here instead of in the device-tree itself greatly simplifies
- * the job of everybody. It's just a list of u64 pairs (base/size) that
- * ends when size is 0
- */
-struct boot_param_header {
- u32 magic; /* magic word OF_DT_HEADER */
- u32 totalsize; /* total size of DT block */
- u32 off_dt_struct; /* offset to structure */
- u32 off_dt_strings; /* offset to strings */
- u32 off_mem_rsvmap; /* offset to memory reserve map */
- u32 version; /* format version */
- u32 last_comp_version; /* last compatible version */
- /* version 2 fields below */
- u32 boot_cpuid_phys; /* Physical CPU id we're booting on */
- /* version 3 fields below */
- u32 dt_strings_size; /* size of the DT strings block */
- /* version 17 fields below */
- u32 dt_struct_size; /* size of the DT structure block */
-};
-
-typedef u32 phandle;
-typedef u32 ihandle;
-
-struct property {
- char *name;
- int length;
- void *value;
- struct property *next;
-};
-
-struct device_node {
- const char *name;
- const char *type;
- phandle node;
- phandle linux_phandle;
- char *full_name;
-
- struct property *properties;
- struct property *deadprops; /* removed properties */
- struct device_node *parent;
- struct device_node *child;
- struct device_node *sibling;
- struct device_node *next; /* next device of same type */
- struct device_node *allnext; /* next in list of all nodes */
- struct proc_dir_entry *pde; /* this node's proc directory */
- struct kref kref;
- unsigned long _flags;
- void *data;
-};
-
extern struct device_node *of_chosen;
-static inline int of_node_check_flag(struct device_node *n, unsigned long flag)
-{
- return test_bit(flag, &n->_flags);
-}
-
-static inline void of_node_set_flag(struct device_node *n, unsigned long flag)
-{
- set_bit(flag, &n->_flags);
-}
-
#define HAVE_ARCH_DEVTREE_FIXUPS
-static inline void set_node_proc_entry(struct device_node *dn,
- struct proc_dir_entry *de)
-{
- dn->pde = de;
-}
-
extern struct device_node *allnodes; /* temporary while merging */
extern rwlock_t devtree_lock; /* temporary while merging */
-extern struct device_node *of_find_all_nodes(struct device_node *prev);
-extern struct device_node *of_node_get(struct device_node *node);
-extern void of_node_put(struct device_node *node);
-
-/* For scanning the flat device-tree at boot time */
-extern int __init of_scan_flat_dt(int (*it)(unsigned long node,
- const char *uname, int depth,
- void *data),
- void *data);
-extern void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
- unsigned long *size);
-extern int __init
- of_flat_dt_is_compatible(unsigned long node, const char *name);
-extern unsigned long __init of_get_flat_dt_root(void);
-
/* For updating the device tree at runtime */
extern void of_attach_node(struct device_node *);
extern void of_detach_node(struct device_node *);
/* Other Prototypes */
-extern void finish_device_tree(void);
-extern void unflatten_device_tree(void);
extern int early_uartlite_console(void);
-extern void early_init_devtree(void *);
-extern int machine_is_compatible(const char *compat);
-extern void print_properties(struct device_node *node);
-extern int prom_n_intr_cells(struct device_node *np);
-extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
-extern int prom_add_property(struct device_node *np, struct property *prop);
-extern int prom_remove_property(struct device_node *np, struct property *prop);
-extern int prom_update_property(struct device_node *np,
- struct property *newprop,
- struct property *oldprop);
extern struct resource *request_OF_resource(struct device_node *node,
int index, const char *name_postfix);
@@ -166,18 +55,6 @@ extern int release_OF_resource(struct device_node *node, int index);
* OF address retreival & translation
*/
-/* Helper to read a big number; size is in cells (not bytes) */
-static inline u64 of_read_number(const u32 *cell, int size)
-{
- u64 r = 0;
- while (size--)
- r = (r << 32) | *(cell++);
- return r;
-}
-
-/* Like of_read_number, but we want an unsigned long result */
-#define of_read_ulong(cell, size) of_read_number(cell, size)
-
/* Translate an OF address block into a CPU physical address
*/
extern u64 of_translate_address(struct device_node *np, const u32 *addr);
@@ -305,12 +182,6 @@ extern int of_irq_to_resource(struct device_node *dev, int index,
*/
extern void __iomem *of_iomap(struct device_node *device, int index);
-/*
- * NB: This is here while we transition from using asm/prom.h
- * to linux/of.h
- */
-#include <linux/of.h>
-
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* _ASM_MICROBLAZE_PROM_H */
diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S
index 697ce3007f30..30916193fcc7 100644
--- a/arch/microblaze/kernel/head.S
+++ b/arch/microblaze/kernel/head.S
@@ -31,7 +31,7 @@
#include <linux/linkage.h>
#include <asm/thread_info.h>
#include <asm/page.h>
-#include <asm/prom.h> /* for OF_DT_HEADER */
+#include <linux/of_fdt.h> /* for OF_DT_HEADER */
#ifdef CONFIG_MMU
#include <asm/setup.h> /* COMMAND_LINE_SIZE */
diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c
index c005cc6f1aaf..b817df172aa9 100644
--- a/arch/microblaze/kernel/prom.c
+++ b/arch/microblaze/kernel/prom.c
@@ -860,29 +860,6 @@ struct device_node *of_find_node_by_phandle(phandle handle)
EXPORT_SYMBOL(of_find_node_by_phandle);
/**
- * of_find_all_nodes - Get next node in global list
- * @prev: Previous node or NULL to start iteration
- * of_node_put() will be called on it
- *
- * Returns a node pointer with refcount incremented, use
- * of_node_put() on it when done.
- */
-struct device_node *of_find_all_nodes(struct device_node *prev)
-{
- struct device_node *np;
-
- read_lock(&devtree_lock);
- np = prev ? prev->allnext : allnodes;
- for (; np != NULL; np = np->allnext)
- if (of_node_get(np))
- break;
- of_node_put(prev);
- read_unlock(&devtree_lock);
- return np;
-}
-EXPORT_SYMBOL(of_find_all_nodes);
-
-/**
* of_node_get - Increment refcount of a node
* @node: Node to inc refcount, NULL is supported to
* simplify writing of callers
diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S
index ecec19155135..c1ab1dc10898 100644
--- a/arch/microblaze/kernel/syscall_table.S
+++ b/arch/microblaze/kernel/syscall_table.S
@@ -371,3 +371,4 @@ ENTRY(sys_call_table)
.long sys_ni_syscall
.long sys_rt_tgsigqueueinfo /* 365 */
.long sys_perf_event_open
+ .long sys_recvmmsg
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 705a7a9170f3..b41bfdd87a2f 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -21,6 +21,7 @@ choice
config MACH_ALCHEMY
bool "Alchemy processor based machines"
+ select SYS_SUPPORTS_ZBOOT
config AR7
bool "Texas Instruments AR7"
@@ -35,6 +36,7 @@ config AR7
select SYS_HAS_EARLY_PRINTK
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
+ select SYS_SUPPORTS_ZBOOT_UART16550
select GENERIC_GPIO
select GCD
select VLYNQ
@@ -191,6 +193,7 @@ config LASAT
config MACH_LOONGSON
bool "Loongson family of machines"
+ select SYS_SUPPORTS_ZBOOT_UART16550
help
This enables the support of Loongson family of machines.
@@ -232,6 +235,7 @@ config MIPS_MALTA
select SYS_SUPPORTS_MIPS_CMP
select SYS_SUPPORTS_MULTITHREADING
select SYS_SUPPORTS_SMARTMIPS
+ select SYS_SUPPORTS_ZBOOT
help
This enables support for the MIPS Technologies Malta evaluation
board.
@@ -1279,6 +1283,16 @@ config CPU_CAVIUM_OCTEON
endchoice
+config SYS_SUPPORTS_ZBOOT
+ bool
+ select HAVE_KERNEL_GZIP
+ select HAVE_KERNEL_BZIP2
+ select HAVE_KERNEL_LZMA
+
+config SYS_SUPPORTS_ZBOOT_UART16550
+ bool
+ select SYS_SUPPORTS_ZBOOT
+
config CPU_LOONGSON2
bool
select CPU_SUPPORTS_32BIT_KERNEL
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 77f5021218d3..ba04782c4b91 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -69,6 +69,7 @@ endif
all-$(CONFIG_BOOT_ELF32) := $(vmlinux-32)
all-$(CONFIG_BOOT_ELF64) := $(vmlinux-64)
+all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlinuz
#
# GCC uses -G 0 -mabicalls -fpic as default. We don't want PIC in the kernel
@@ -331,7 +332,7 @@ load-$(CONFIG_LEMOTE_FULOONG2E) +=0xffffffff80100000
core-$(CONFIG_MIPS_MALTA) += arch/mips/mti-malta/
cflags-$(CONFIG_MIPS_MALTA) += -I$(srctree)/arch/mips/include/asm/mach-malta
load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000
-all-$(CONFIG_MIPS_MALTA) := vmlinux.bin
+all-$(CONFIG_MIPS_MALTA) := vmlinuz.bin
#
# MIPS SIM
@@ -581,7 +582,7 @@ load-$(CONFIG_SNI_RM) += 0xffffffff80600000
else
load-$(CONFIG_SNI_RM) += 0xffffffff80030000
endif
-all-$(CONFIG_SNI_RM) := vmlinux.ecoff
+all-$(CONFIG_SNI_RM) := vmlinuz.ecoff
#
# Common TXx9
@@ -699,9 +700,23 @@ vmlinux.64: vmlinux
$(OBJCOPY) -O $(64bit-bfd) $(OBJCOPYFLAGS) $< $@
makeboot =$(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) $(1)
+makezboot =$(Q)$(MAKE) $(build)=arch/mips/boot/compressed \
+ VMLINUX_LOAD_ADDRESS=$(load-y) 32bit-bfd=$(32bit-bfd) $(1)
all: $(all-y)
+vmlinuz: vmlinux FORCE
+ +@$(call makezboot,$@)
+
+vmlinuz.bin: vmlinux
+ +@$(call makezboot,$@)
+
+vmlinuz.ecoff: vmlinux
+ +@$(call makezboot,$@)
+
+vmlinuz.srec: vmlinux
+ +@$(call makezboot,$@)
+
vmlinux.bin: $(vmlinux-32)
+@$(call makeboot,$@)
@@ -726,11 +741,13 @@ endif
install:
$(Q)install -D -m 755 vmlinux $(INSTALL_PATH)/vmlinux-$(KERNELRELEASE)
+ $(Q)install -D -m 755 vmlinuz $(INSTALL_PATH)/vmlinuz-$(KERNELRELEASE)
$(Q)install -D -m 644 .config $(INSTALL_PATH)/config-$(KERNELRELEASE)
$(Q)install -D -m 644 System.map $(INSTALL_PATH)/System.map-$(KERNELRELEASE)
archclean:
@$(MAKE) $(clean)=arch/mips/boot
+ @$(MAKE) $(clean)=arch/mips/boot/compressed
@$(MAKE) $(clean)=arch/mips/lasat
define archhelp
@@ -738,10 +755,18 @@ define archhelp
echo ' vmlinux.ecoff - ECOFF boot image'
echo ' vmlinux.bin - Raw binary boot image'
echo ' vmlinux.srec - SREC boot image'
+ echo ' vmlinuz - Compressed boot(zboot) image'
+ echo ' vmlinuz.ecoff - ECOFF zboot image'
+ echo ' vmlinuz.bin - Raw binary zboot image'
+ echo ' vmlinuz.srec - SREC zboot image'
echo
echo ' These will be default as apropriate for a configured platform.'
endef
CLEAN_FILES += vmlinux.32 \
vmlinux.64 \
- vmlinux.ecoff
+ vmlinux.ecoff \
+ vmlinuz \
+ vmlinuz.ecoff \
+ vmlinuz.bin \
+ vmlinuz.srec
diff --git a/arch/mips/alchemy/common/dbdma.c b/arch/mips/alchemy/common/dbdma.c
index 19c1c82849ff..1c43794c8ff7 100644
--- a/arch/mips/alchemy/common/dbdma.c
+++ b/arch/mips/alchemy/common/dbdma.c
@@ -569,7 +569,7 @@ EXPORT_SYMBOL(au1xxx_dbdma_ring_alloc);
* This updates the source pointer and byte count. Normally used
* for memory to fifo transfers.
*/
-u32 _au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes, u32 flags)
+u32 au1xxx_dbdma_put_source(u32 chanid, dma_addr_t buf, int nbytes, u32 flags)
{
chan_tab_t *ctp;
au1x_ddma_desc_t *dp;
@@ -595,7 +595,7 @@ u32 _au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes, u32 flags)
return 0;
/* Load up buffer address and byte count. */
- dp->dscr_source0 = virt_to_phys(buf);
+ dp->dscr_source0 = buf & ~0UL;
dp->dscr_cmd1 = nbytes;
/* Check flags */
if (flags & DDMA_FLAGS_IE)
@@ -622,14 +622,13 @@ u32 _au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes, u32 flags)
/* Return something non-zero. */
return nbytes;
}
-EXPORT_SYMBOL(_au1xxx_dbdma_put_source);
+EXPORT_SYMBOL(au1xxx_dbdma_put_source);
/* Put a destination buffer into the DMA ring.
* This updates the destination pointer and byte count. Normally used
* to place an empty buffer into the ring for fifo to memory transfers.
*/
-u32
-_au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes, u32 flags)
+u32 au1xxx_dbdma_put_dest(u32 chanid, dma_addr_t buf, int nbytes, u32 flags)
{
chan_tab_t *ctp;
au1x_ddma_desc_t *dp;
@@ -659,7 +658,7 @@ _au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes, u32 flags)
if (flags & DDMA_FLAGS_NOIE)
dp->dscr_cmd0 &= ~DSCR_CMD0_IE;
- dp->dscr_dest0 = virt_to_phys(buf);
+ dp->dscr_dest0 = buf & ~0UL;
dp->dscr_cmd1 = nbytes;
#if 0
printk(KERN_DEBUG "cmd0:%x cmd1:%x source0:%x source1:%x dest0:%x dest1:%x\n",
@@ -685,7 +684,7 @@ _au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes, u32 flags)
/* Return something non-zero. */
return nbytes;
}
-EXPORT_SYMBOL(_au1xxx_dbdma_put_dest);
+EXPORT_SYMBOL(au1xxx_dbdma_put_dest);
/*
* Get a destination buffer into the DMA ring.
diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c
index c88c821b4c36..a5daf51314b5 100644
--- a/arch/mips/alchemy/common/irq.c
+++ b/arch/mips/alchemy/common/irq.c
@@ -39,9 +39,19 @@
static int au1x_ic_settype(unsigned int irq, unsigned int flow_type);
-/* per-processor fixed function irqs */
-struct au1xxx_irqmap au1xxx_ic0_map[] __initdata = {
+/* NOTE on interrupt priorities: The original writers of this code said:
+ *
+ * Because of the tight timing of SETUP token to reply transactions,
+ * the USB devices-side packet complete interrupt (USB_DEV_REQ_INT)
+ * needs the highest priority.
+ */
+/* per-processor fixed function irqs */
+struct au1xxx_irqmap {
+ int im_irq;
+ int im_type;
+ int im_request; /* set 1 to get higher priority */
+} au1xxx_ic0_map[] __initdata = {
#if defined(CONFIG_SOC_AU1000)
{ AU1000_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
{ AU1000_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
@@ -60,14 +70,14 @@ struct au1xxx_irqmap au1xxx_ic0_map[] __initdata = {
{ AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
- { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
+ { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
- { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
+ { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
{ AU1000_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
{ AU1000_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
- { AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
+ { AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 },
{ AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 },
{ AU1000_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 0 },
@@ -94,12 +104,12 @@ struct au1xxx_irqmap au1xxx_ic0_map[] __initdata = {
{ AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
- { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
+ { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
- { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
- { AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
+ { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
+ { AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 },
{ AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 },
{ AU1000_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 0 },
@@ -126,14 +136,14 @@ struct au1xxx_irqmap au1xxx_ic0_map[] __initdata = {
{ AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
- { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
+ { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
- { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
+ { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
{ AU1000_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
{ AU1000_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
- { AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
+ { AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 },
{ AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 },
{ AU1000_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 0 },
@@ -160,13 +170,13 @@ struct au1xxx_irqmap au1xxx_ic0_map[] __initdata = {
{ AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
- { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
+ { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
- { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
+ { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
{ AU1550_NAND_INT, IRQ_TYPE_EDGE_RISING, 0 },
- { AU1550_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
+ { AU1550_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 },
{ AU1550_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1550_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 },
{ AU1550_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
@@ -188,11 +198,11 @@ struct au1xxx_irqmap au1xxx_ic0_map[] __initdata = {
{ AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
- { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
+ { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
- { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
+ { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
{ AU1200_NAND_INT, IRQ_TYPE_EDGE_RISING, 0 },
{ AU1200_USB_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
{ AU1200_LCD_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
@@ -486,11 +496,11 @@ static int au1x_ic_settype(unsigned int irq, unsigned int flow_type)
asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_status() & read_c0_cause();
- unsigned long s, off, bit;
+ unsigned long s, off;
if (pending & CAUSEF_IP7) {
- do_IRQ(MIPS_CPU_IRQ_BASE + 7);
- return;
+ off = MIPS_CPU_IRQ_BASE + 7;
+ goto handle;
} else if (pending & CAUSEF_IP2) {
s = IC0_REQ0INT;
off = AU1000_INTC0_INT_BASE;
@@ -506,30 +516,19 @@ asmlinkage void plat_irq_dispatch(void)
} else
goto spurious;
- bit = 0;
s = au_readl(s);
if (unlikely(!s)) {
spurious:
spurious_interrupt();
return;
}
-#ifdef AU1000_USB_DEV_REQ_INT
- /*
- * Because of the tight timing of SETUP token to reply
- * transactions, the USB devices-side packet complete
- * interrupt needs the highest priority.
- */
- bit = 1 << (AU1000_USB_DEV_REQ_INT - AU1000_INTC0_INT_BASE);
- if ((pending & CAUSEF_IP2) && (s & bit)) {
- do_IRQ(AU1000_USB_DEV_REQ_INT);
- return;
- }
-#endif
- do_IRQ(__ffs(s) + off);
+ off += __ffs(s);
+handle:
+ do_IRQ(off);
}
/* setup edge/level and assign request 0/1 */
-void __init au1xxx_setup_irqmap(struct au1xxx_irqmap *map, int count)
+static void __init setup_irqmap(struct au1xxx_irqmap *map, int count)
{
unsigned int bit, irq_nr;
@@ -545,11 +544,11 @@ void __init au1xxx_setup_irqmap(struct au1xxx_irqmap *map, int count)
if (irq_nr >= AU1000_INTC1_INT_BASE) {
bit = irq_nr - AU1000_INTC1_INT_BASE;
if (map[count].im_request)
- au_writel(1 << bit, IC1_ASSIGNCLR);
+ au_writel(1 << bit, IC1_ASSIGNSET);
} else {
bit = irq_nr - AU1000_INTC0_INT_BASE;
if (map[count].im_request)
- au_writel(1 << bit, IC0_ASSIGNCLR);
+ au_writel(1 << bit, IC0_ASSIGNSET);
}
au1x_ic_settype(irq_nr, map[count].im_type);
@@ -567,7 +566,7 @@ void __init arch_init_irq(void)
au_writel(0xffffffff, IC0_CFG1CLR);
au_writel(0xffffffff, IC0_CFG2CLR);
au_writel(0xffffffff, IC0_MASKCLR);
- au_writel(0xffffffff, IC0_ASSIGNSET);
+ au_writel(0xffffffff, IC0_ASSIGNCLR);
au_writel(0xffffffff, IC0_WAKECLR);
au_writel(0xffffffff, IC0_SRCSET);
au_writel(0xffffffff, IC0_FALLINGCLR);
@@ -578,7 +577,7 @@ void __init arch_init_irq(void)
au_writel(0xffffffff, IC1_CFG1CLR);
au_writel(0xffffffff, IC1_CFG2CLR);
au_writel(0xffffffff, IC1_MASKCLR);
- au_writel(0xffffffff, IC1_ASSIGNSET);
+ au_writel(0xffffffff, IC1_ASSIGNCLR);
au_writel(0xffffffff, IC1_WAKECLR);
au_writel(0xffffffff, IC1_SRCSET);
au_writel(0xffffffff, IC1_FALLINGCLR);
@@ -601,11 +600,7 @@ void __init arch_init_irq(void)
/*
* Initialize IC0, which is fixed per processor.
*/
- au1xxx_setup_irqmap(au1xxx_ic0_map, ARRAY_SIZE(au1xxx_ic0_map));
-
- /* Boards can register additional (GPIO-based) IRQs.
- */
- board_init_irq();
+ setup_irqmap(au1xxx_ic0_map, ARRAY_SIZE(au1xxx_ic0_map));
set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3);
}
diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c
index 117f99f70649..2b76a57c4947 100644
--- a/arch/mips/alchemy/common/platform.c
+++ b/arch/mips/alchemy/common/platform.c
@@ -308,11 +308,6 @@ static struct platform_device au1200_mmc1_device = {
#endif /* #ifndef CONFIG_MIPS_DB1200 */
#endif /* #ifdef CONFIG_SOC_AU1200 */
-static struct platform_device au1x00_pcmcia_device = {
- .name = "au1x00-pcmcia",
- .id = 0,
-};
-
/* All Alchemy demoboards with I2C have this #define in their headers */
#ifdef SMBUS_PSC_BASE
static struct resource pbdb_smbus_resources[] = {
@@ -334,7 +329,6 @@ static struct platform_device pbdb_smbus_device = {
static struct platform_device *au1xxx_platform_devices[] __initdata = {
&au1xx0_uart_device,
&au1xxx_usb_ohci_device,
- &au1x00_pcmcia_device,
#ifdef CONFIG_FB_AU1100
&au1100_lcd_device,
#endif
diff --git a/arch/mips/alchemy/common/setup.c b/arch/mips/alchemy/common/setup.c
index 6184baa56786..375984e5c2e6 100644
--- a/arch/mips/alchemy/common/setup.c
+++ b/arch/mips/alchemy/common/setup.c
@@ -107,7 +107,8 @@ phys_t __fixup_bigphys_addr(phys_t phys_addr, phys_t size)
* The pseudo address we use is 0xF400 0000. Any address over
* 0xF400 0000 is a PCMCIA pseudo address.
*/
- if ((phys_addr >= 0xF4000000) && (phys_addr < 0xFFFFFFFF))
+ if ((phys_addr >= PCMCIA_ATTR_PSEUDO_PHYS) &&
+ (phys_addr < PCMCIA_PSEUDO_END))
return (phys_t)(phys_addr << 4);
/* default nop */
diff --git a/arch/mips/alchemy/devboards/Makefile b/arch/mips/alchemy/devboards/Makefile
index 730f9f2b30e8..cfda9721142b 100644
--- a/arch/mips/alchemy/devboards/Makefile
+++ b/arch/mips/alchemy/devboards/Makefile
@@ -2,7 +2,7 @@
# Alchemy Develboards
#
-obj-y += prom.o
+obj-y += prom.o bcsr.o platform.o
obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_MIPS_PB1000) += pb1000/
obj-$(CONFIG_MIPS_PB1100) += pb1100/
diff --git a/arch/mips/alchemy/devboards/bcsr.c b/arch/mips/alchemy/devboards/bcsr.c
new file mode 100644
index 000000000000..3bc4fd2155d7
--- /dev/null
+++ b/arch/mips/alchemy/devboards/bcsr.c
@@ -0,0 +1,148 @@
+/*
+ * bcsr.h -- Db1xxx/Pb1xxx Devboard CPLD registers ("BCSR") abstraction.
+ *
+ * All Alchemy development boards (except, of course, the weird PB1000)
+ * have a few registers in a CPLD with standardised layout; they mostly
+ * only differ in base address.
+ * All registers are 16bits wide with 32bit spacing.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <asm/addrspace.h>
+#include <asm/io.h>
+#include <asm/mach-db1x00/bcsr.h>
+
+static struct bcsr_reg {
+ void __iomem *raddr;
+ spinlock_t lock;
+} bcsr_regs[BCSR_CNT];
+
+static void __iomem *bcsr_virt; /* KSEG1 addr of BCSR base */
+static int bcsr_csc_base; /* linux-irq of first cascaded irq */
+
+void __init bcsr_init(unsigned long bcsr1_phys, unsigned long bcsr2_phys)
+{
+ int i;
+
+ bcsr1_phys = KSEG1ADDR(CPHYSADDR(bcsr1_phys));
+ bcsr2_phys = KSEG1ADDR(CPHYSADDR(bcsr2_phys));
+
+ bcsr_virt = (void __iomem *)bcsr1_phys;
+
+ for (i = 0; i < BCSR_CNT; i++) {
+ if (i >= BCSR_HEXLEDS)
+ bcsr_regs[i].raddr = (void __iomem *)bcsr2_phys +
+ (0x04 * (i - BCSR_HEXLEDS));
+ else
+ bcsr_regs[i].raddr = (void __iomem *)bcsr1_phys +
+ (0x04 * i);
+
+ spin_lock_init(&bcsr_regs[i].lock);
+ }
+}
+
+unsigned short bcsr_read(enum bcsr_id reg)
+{
+ unsigned short r;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bcsr_regs[reg].lock, flags);
+ r = __raw_readw(bcsr_regs[reg].raddr);
+ spin_unlock_irqrestore(&bcsr_regs[reg].lock, flags);
+ return r;
+}
+EXPORT_SYMBOL_GPL(bcsr_read);
+
+void bcsr_write(enum bcsr_id reg, unsigned short val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&bcsr_regs[reg].lock, flags);
+ __raw_writew(val, bcsr_regs[reg].raddr);
+ wmb();
+ spin_unlock_irqrestore(&bcsr_regs[reg].lock, flags);
+}
+EXPORT_SYMBOL_GPL(bcsr_write);
+
+void bcsr_mod(enum bcsr_id reg, unsigned short clr, unsigned short set)
+{
+ unsigned short r;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bcsr_regs[reg].lock, flags);
+ r = __raw_readw(bcsr_regs[reg].raddr);
+ r &= ~clr;
+ r |= set;
+ __raw_writew(r, bcsr_regs[reg].raddr);
+ wmb();
+ spin_unlock_irqrestore(&bcsr_regs[reg].lock, flags);
+}
+EXPORT_SYMBOL_GPL(bcsr_mod);
+
+/*
+ * DB1200/PB1200 CPLD IRQ muxer
+ */
+static void bcsr_csc_handler(unsigned int irq, struct irq_desc *d)
+{
+ unsigned short bisr = __raw_readw(bcsr_virt + BCSR_REG_INTSTAT);
+
+ for ( ; bisr; bisr &= bisr - 1)
+ generic_handle_irq(bcsr_csc_base + __ffs(bisr));
+}
+
+/* NOTE: both the enable and mask bits must be cleared, otherwise the
+ * CPLD generates tons of spurious interrupts (at least on my DB1200).
+ * -- mlau
+ */
+static void bcsr_irq_mask(unsigned int irq_nr)
+{
+ unsigned short v = 1 << (irq_nr - bcsr_csc_base);
+ __raw_writew(v, bcsr_virt + BCSR_REG_INTCLR);
+ __raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR);
+ wmb();
+}
+
+static void bcsr_irq_maskack(unsigned int irq_nr)
+{
+ unsigned short v = 1 << (irq_nr - bcsr_csc_base);
+ __raw_writew(v, bcsr_virt + BCSR_REG_INTCLR);
+ __raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR);
+ __raw_writew(v, bcsr_virt + BCSR_REG_INTSTAT); /* ack */
+ wmb();
+}
+
+static void bcsr_irq_unmask(unsigned int irq_nr)
+{
+ unsigned short v = 1 << (irq_nr - bcsr_csc_base);
+ __raw_writew(v, bcsr_virt + BCSR_REG_INTSET);
+ __raw_writew(v, bcsr_virt + BCSR_REG_MASKSET);
+ wmb();
+}
+
+static struct irq_chip bcsr_irq_type = {
+ .name = "CPLD",
+ .mask = bcsr_irq_mask,
+ .mask_ack = bcsr_irq_maskack,
+ .unmask = bcsr_irq_unmask,
+};
+
+void __init bcsr_init_irq(int csc_start, int csc_end, int hook_irq)
+{
+ unsigned int irq;
+
+ /* mask & disable & ack all */
+ __raw_writew(0xffff, bcsr_virt + BCSR_REG_INTCLR);
+ __raw_writew(0xffff, bcsr_virt + BCSR_REG_MASKCLR);
+ __raw_writew(0xffff, bcsr_virt + BCSR_REG_INTSTAT);
+ wmb();
+
+ bcsr_csc_base = csc_start;
+
+ for (irq = csc_start; irq <= csc_end; irq++)
+ set_irq_chip_and_handler_name(irq, &bcsr_irq_type,
+ handle_level_irq, "level");
+
+ set_irq_chained_handler(hook_irq, bcsr_csc_handler);
+}
diff --git a/arch/mips/alchemy/devboards/db1x00/Makefile b/arch/mips/alchemy/devboards/db1x00/Makefile
index 432241ab8677..ce48d58920d0 100644
--- a/arch/mips/alchemy/devboards/db1x00/Makefile
+++ b/arch/mips/alchemy/devboards/db1x00/Makefile
@@ -5,4 +5,4 @@
# Makefile for the Alchemy Semiconductor DBAu1xx0 boards.
#
-obj-y := board_setup.o irqmap.o
+obj-y := board_setup.o
diff --git a/arch/mips/alchemy/devboards/db1x00/board_setup.c b/arch/mips/alchemy/devboards/db1x00/board_setup.c
index de30d8ea7176..3b228a282b07 100644
--- a/arch/mips/alchemy/devboards/db1x00/board_setup.c
+++ b/arch/mips/alchemy/devboards/db1x00/board_setup.c
@@ -29,14 +29,44 @@
#include <linux/gpio.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-db1x00/db1x00.h>
+#include <asm/mach-db1x00/bcsr.h>
#include <prom.h>
+#ifdef CONFIG_MIPS_DB1500
+char irq_tab_alchemy[][5] __initdata = {
+ [12] = { -1, INTA, INTX, INTX, INTX }, /* IDSEL 12 - HPT371 */
+ [13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot */
+};
+#endif
+
+#ifdef CONFIG_MIPS_BOSPORUS
+char irq_tab_alchemy[][5] __initdata = {
+ [11] = { -1, INTA, INTB, INTX, INTX }, /* IDSEL 11 - miniPCI */
+ [12] = { -1, INTA, INTX, INTX, INTX }, /* IDSEL 12 - SN1741 */
+ [13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot */
+};
+#endif
+
+#ifdef CONFIG_MIPS_MIRAGE
+char irq_tab_alchemy[][5] __initdata = {
+ [11] = { -1, INTD, INTX, INTX, INTX }, /* IDSEL 11 - SMI VGX */
+ [12] = { -1, INTX, INTX, INTC, INTX }, /* IDSEL 12 - PNX1300 */
+ [13] = { -1, INTA, INTB, INTX, INTX }, /* IDSEL 13 - miniPCI */
+};
+#endif
-static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
+#ifdef CONFIG_MIPS_DB1550
+char irq_tab_alchemy[][5] __initdata = {
+ [11] = { -1, INTC, INTX, INTX, INTX }, /* IDSEL 11 - on-board HPT371 */
+ [12] = { -1, INTB, INTC, INTD, INTA }, /* IDSEL 12 - PCI slot 2 (left) */
+ [13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot 1 (right) */
+};
+#endif
const char *get_system_type(void)
{
@@ -49,15 +79,43 @@ const char *get_system_type(void)
void board_reset(void)
{
- /* Hit BCSR.SW_RESET[RESET] */
- bcsr->swreset = 0x0000;
+ bcsr_write(BCSR_SYSTEM, 0);
}
void __init board_setup(void)
{
+ unsigned long bcsr1, bcsr2;
u32 pin_func = 0;
char *argptr;
+ bcsr1 = DB1000_BCSR_PHYS_ADDR;
+ bcsr2 = DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS;
+
+#ifdef CONFIG_MIPS_DB1000
+ printk(KERN_INFO "AMD Alchemy Au1000/Db1000 Board\n");
+#endif
+#ifdef CONFIG_MIPS_DB1500
+ printk(KERN_INFO "AMD Alchemy Au1500/Db1500 Board\n");
+#endif
+#ifdef CONFIG_MIPS_DB1100
+ printk(KERN_INFO "AMD Alchemy Au1100/Db1100 Board\n");
+#endif
+#ifdef CONFIG_MIPS_BOSPORUS
+ printk(KERN_INFO "AMD Alchemy Bosporus Board\n");
+#endif
+#ifdef CONFIG_MIPS_MIRAGE
+ printk(KERN_INFO "AMD Alchemy Mirage Board\n");
+#endif
+#ifdef CONFIG_MIPS_DB1550
+ printk(KERN_INFO "AMD Alchemy Au1550/Db1550 Board\n");
+
+ bcsr1 = DB1550_BCSR_PHYS_ADDR;
+ bcsr2 = DB1550_BCSR_PHYS_ADDR + DB1550_BCSR_HEXLED_OFS;
+#endif
+
+ /* initialize board register space */
+ bcsr_init(bcsr1, bcsr2);
+
argptr = prom_getcmdline();
#ifdef CONFIG_SERIAL_8250_CONSOLE
argptr = strstr(argptr, "console=");
@@ -89,11 +147,10 @@ void __init board_setup(void)
pin_func = au_readl(SYS_PINFUNC) | SYS_PF_IRF;
au_writel(pin_func, SYS_PINFUNC);
/* Power off until the driver is in use */
- bcsr->resets &= ~BCSR_RESETS_IRDA_MODE_MASK;
- bcsr->resets |= BCSR_RESETS_IRDA_MODE_OFF;
- au_sync();
+ bcsr_mod(BCSR_RESETS, BCSR_RESETS_IRDA_MODE_MASK,
+ BCSR_RESETS_IRDA_MODE_OFF);
#endif
- bcsr->pcmcia = 0x0000; /* turn off PCMCIA power */
+ bcsr_write(BCSR_PCMCIA, 0); /* turn off PCMCIA power */
/* Enable GPIO[31:0] inputs */
alchemy_gpio1_input_enable();
@@ -123,23 +180,27 @@ void __init board_setup(void)
#endif
au_sync();
+}
-#ifdef CONFIG_MIPS_DB1000
- printk(KERN_INFO "AMD Alchemy Au1000/Db1000 Board\n");
-#endif
-#ifdef CONFIG_MIPS_DB1500
- printk(KERN_INFO "AMD Alchemy Au1500/Db1500 Board\n");
-#endif
-#ifdef CONFIG_MIPS_DB1100
- printk(KERN_INFO "AMD Alchemy Au1100/Db1100 Board\n");
-#endif
-#ifdef CONFIG_MIPS_BOSPORUS
- printk(KERN_INFO "AMD Alchemy Bosporus Board\n");
-#endif
-#ifdef CONFIG_MIPS_MIRAGE
- printk(KERN_INFO "AMD Alchemy Mirage Board\n");
-#endif
-#ifdef CONFIG_MIPS_DB1550
- printk(KERN_INFO "AMD Alchemy Au1550/Db1550 Board\n");
+static int __init db1x00_init_irq(void)
+{
+#if defined(CONFIG_MIPS_MIRAGE)
+ set_irq_type(AU1000_GPIO_7, IRQF_TRIGGER_RISING); /* TS pendown */
+#elif defined(CONFIG_MIPS_DB1550)
+ set_irq_type(AU1000_GPIO_0, IRQF_TRIGGER_LOW); /* CD0# */
+ set_irq_type(AU1000_GPIO_1, IRQF_TRIGGER_LOW); /* CD1# */
+ set_irq_type(AU1000_GPIO_3, IRQF_TRIGGER_LOW); /* CARD0# */
+ set_irq_type(AU1000_GPIO_5, IRQF_TRIGGER_LOW); /* CARD1# */
+ set_irq_type(AU1000_GPIO_21, IRQF_TRIGGER_LOW); /* STSCHG0# */
+ set_irq_type(AU1000_GPIO_22, IRQF_TRIGGER_LOW); /* STSCHG1# */
+#else
+ set_irq_type(AU1000_GPIO_0, IRQF_TRIGGER_LOW); /* CD0# */
+ set_irq_type(AU1000_GPIO_3, IRQF_TRIGGER_LOW); /* CD1# */
+ set_irq_type(AU1000_GPIO_2, IRQF_TRIGGER_LOW); /* CARD0# */
+ set_irq_type(AU1000_GPIO_5, IRQF_TRIGGER_LOW); /* CARD1# */
+ set_irq_type(AU1000_GPIO_1, IRQF_TRIGGER_LOW); /* STSCHG0# */
+ set_irq_type(AU1000_GPIO_4, IRQF_TRIGGER_LOW); /* STSCHG1# */
#endif
+ return 0;
}
+arch_initcall(db1x00_init_irq);
diff --git a/arch/mips/alchemy/devboards/db1x00/irqmap.c b/arch/mips/alchemy/devboards/db1x00/irqmap.c
deleted file mode 100644
index 0b09025087c6..000000000000
--- a/arch/mips/alchemy/devboards/db1x00/irqmap.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- * Au1xxx irq map table
- *
- * Copyright 2003 Embedded Edge, LLC
- * dan@embeddededge.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/init.h>
-#include <linux/interrupt.h>
-
-#include <asm/mach-au1x00/au1000.h>
-
-#ifdef CONFIG_MIPS_DB1500
-char irq_tab_alchemy[][5] __initdata = {
- [12] = { -1, INTA, INTX, INTX, INTX }, /* IDSEL 12 - HPT371 */
- [13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot */
-};
-#endif
-
-#ifdef CONFIG_MIPS_BOSPORUS
-char irq_tab_alchemy[][5] __initdata = {
- [11] = { -1, INTA, INTB, INTX, INTX }, /* IDSEL 11 - miniPCI */
- [12] = { -1, INTA, INTX, INTX, INTX }, /* IDSEL 12 - SN1741 */
- [13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot */
-};
-#endif
-
-#ifdef CONFIG_MIPS_MIRAGE
-char irq_tab_alchemy[][5] __initdata = {
- [11] = { -1, INTD, INTX, INTX, INTX }, /* IDSEL 11 - SMI VGX */
- [12] = { -1, INTX, INTX, INTC, INTX }, /* IDSEL 12 - PNX1300 */
- [13] = { -1, INTA, INTB, INTX, INTX }, /* IDSEL 13 - miniPCI */
-};
-#endif
-
-#ifdef CONFIG_MIPS_DB1550
-char irq_tab_alchemy[][5] __initdata = {
- [11] = { -1, INTC, INTX, INTX, INTX }, /* IDSEL 11 - on-board HPT371 */
- [12] = { -1, INTB, INTC, INTD, INTA }, /* IDSEL 12 - PCI slot 2 (left) */
- [13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot 1 (right) */
-};
-#endif
-
-
-struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
-
-#ifndef CONFIG_MIPS_MIRAGE
-#ifdef CONFIG_MIPS_DB1550
- { AU1000_GPIO_3, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 0 IRQ# */
- { AU1000_GPIO_5, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 1 IRQ# */
-#else
- { AU1000_GPIO_0, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 0 Fully_Interted# */
- { AU1000_GPIO_1, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 0 STSCHG# */
- { AU1000_GPIO_2, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 0 IRQ# */
-
- { AU1000_GPIO_3, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 1 Fully_Interted# */
- { AU1000_GPIO_4, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 1 STSCHG# */
- { AU1000_GPIO_5, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 1 IRQ# */
-#endif
-#else
- { AU1000_GPIO_7, IRQF_TRIGGER_RISING, 0 }, /* touchscreen pen down */
-#endif
-
-};
-
-void __init board_init_irq(void)
-{
- au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map));
-}
diff --git a/arch/mips/alchemy/devboards/db1x00/platform.c b/arch/mips/alchemy/devboards/db1x00/platform.c
new file mode 100644
index 000000000000..b762b790512a
--- /dev/null
+++ b/arch/mips/alchemy/devboards/db1x00/platform.c
@@ -0,0 +1,84 @@
+/*
+ * DBAu1xxx board platform device registration
+ *
+ * Copyright (C) 2009 Manuel Lauss
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-au1x00/au1xxx.h>
+#include "../platform.h"
+
+#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || \
+ defined(CONFIG_MIPS_DB1500) || defined(CONFIG_MIPS_DB1550)
+#define DB1XXX_HAS_PCMCIA
+#endif
+
+/* DB1xxx PCMCIA interrupt sources:
+ * CD0/1 GPIO0/3
+ * STSCHG0/1 GPIO1/4
+ * CARD0/1 GPIO2/5
+ * Db1550: 0/1, 21/22, 3/5
+ */
+#ifndef CONFIG_MIPS_DB1550
+/* Db1000, Db1100, Db1500 */
+#define DB1XXX_PCMCIA_CD0 AU1000_GPIO_0
+#define DB1XXX_PCMCIA_STSCHG0 AU1000_GPIO_1
+#define DB1XXX_PCMCIA_CARD0 AU1000_GPIO_2
+#define DB1XXX_PCMCIA_CD1 AU1000_GPIO_3
+#define DB1XXX_PCMCIA_STSCHG1 AU1000_GPIO_4
+#define DB1XXX_PCMCIA_CARD1 AU1000_GPIO_5
+#else
+#define DB1XXX_PCMCIA_CD0 AU1000_GPIO_0
+#define DB1XXX_PCMCIA_STSCHG0 AU1500_GPIO_21
+#define DB1XXX_PCMCIA_CARD0 AU1000_GPIO_3
+#define DB1XXX_PCMCIA_CD1 AU1000_GPIO_1
+#define DB1XXX_PCMCIA_STSCHG1 AU1500_GPIO_22
+#define DB1XXX_PCMCIA_CARD1 AU1000_GPIO_5
+#endif
+
+static int __init db1xxx_dev_init(void)
+{
+#ifdef DB1XXX_HAS_PCMCIA
+ db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS,
+ PCMCIA_ATTR_PSEUDO_PHYS + 0x00040000 - 1,
+ PCMCIA_MEM_PSEUDO_PHYS,
+ PCMCIA_MEM_PSEUDO_PHYS + 0x00040000 - 1,
+ PCMCIA_IO_PSEUDO_PHYS,
+ PCMCIA_IO_PSEUDO_PHYS + 0x00001000 - 1,
+ DB1XXX_PCMCIA_CARD0,
+ DB1XXX_PCMCIA_CD0,
+ /*DB1XXX_PCMCIA_STSCHG0*/0,
+ 0,
+ 0);
+
+ db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS + 0x00400000,
+ PCMCIA_ATTR_PSEUDO_PHYS + 0x00440000 - 1,
+ PCMCIA_MEM_PSEUDO_PHYS + 0x00400000,
+ PCMCIA_MEM_PSEUDO_PHYS + 0x00440000 - 1,
+ PCMCIA_IO_PSEUDO_PHYS + 0x00400000,
+ PCMCIA_IO_PSEUDO_PHYS + 0x00401000 - 1,
+ DB1XXX_PCMCIA_CARD1,
+ DB1XXX_PCMCIA_CD1,
+ /*DB1XXX_PCMCIA_STSCHG1*/0,
+ 0,
+ 1);
+#endif
+ return 0;
+}
+device_initcall(db1xxx_dev_init);
diff --git a/arch/mips/alchemy/devboards/pb1000/board_setup.c b/arch/mips/alchemy/devboards/pb1000/board_setup.c
index cd273545e810..f1cafea18655 100644
--- a/arch/mips/alchemy/devboards/pb1000/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1000/board_setup.c
@@ -32,11 +32,6 @@
#include <prom.h>
-struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
- { AU1000_GPIO_15, IRQF_TRIGGER_LOW, 0 },
-};
-
-
const char *get_system_type(void)
{
return "Alchemy Pb1000";
@@ -46,11 +41,6 @@ void board_reset(void)
{
}
-void __init board_init_irq(void)
-{
- au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map));
-}
-
void __init board_setup(void)
{
u32 pin_func, static_cfg0;
@@ -193,3 +183,10 @@ void __init board_setup(void)
break;
}
}
+
+static int __init pb1000_init_irq(void)
+{
+ set_irq_type(AU1000_GPIO_15, IRQF_TRIGGER_LOW);
+ return 0;
+}
+arch_initcall(pb1000_init_irq);
diff --git a/arch/mips/alchemy/devboards/pb1100/Makefile b/arch/mips/alchemy/devboards/pb1100/Makefile
index c586dd7e91dc..60cf5b914730 100644
--- a/arch/mips/alchemy/devboards/pb1100/Makefile
+++ b/arch/mips/alchemy/devboards/pb1100/Makefile
@@ -5,4 +5,5 @@
# Makefile for the Alchemy Semiconductor Pb1100 board.
#
-obj-y := board_setup.o
+obj-y := board_setup.o platform.o
+
diff --git a/arch/mips/alchemy/devboards/pb1100/board_setup.c b/arch/mips/alchemy/devboards/pb1100/board_setup.c
index 61263081ef58..b282d93d1445 100644
--- a/arch/mips/alchemy/devboards/pb1100/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1100/board_setup.c
@@ -29,19 +29,11 @@
#include <linux/interrupt.h>
#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-pb1x00/pb1100.h>
+#include <asm/mach-db1x00/bcsr.h>
#include <prom.h>
-struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
- { AU1000_GPIO_9, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card Fully_Inserted# */
- { AU1000_GPIO_10, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card STSCHG# */
- { AU1000_GPIO_11, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card IRQ# */
- { AU1000_GPIO_13, IRQF_TRIGGER_LOW, 0 }, /* DC_IRQ# */
-};
-
-
const char *get_system_type(void)
{
return "Alchemy Pb1100";
@@ -49,13 +41,7 @@ const char *get_system_type(void)
void board_reset(void)
{
- /* Hit BCSR.RST_VDDI[SOFT_RESET] */
- au_writel(0x00000000, PB1100_RST_VDDI);
-}
-
-void __init board_init_irq(void)
-{
- au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map));
+ bcsr_write(BCSR_SYSTEM, 0);
}
void __init board_setup(void)
@@ -63,6 +49,9 @@ void __init board_setup(void)
volatile void __iomem *base = (volatile void __iomem *)0xac000000UL;
char *argptr;
+ bcsr_init(DB1000_BCSR_PHYS_ADDR,
+ DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS);
+
argptr = prom_getcmdline();
#ifdef CONFIG_SERIAL_8250_CONSOLE
argptr = strstr(argptr, "console=");
@@ -155,3 +144,14 @@ void __init board_setup(void)
au_sync();
}
}
+
+static int __init pb1100_init_irq(void)
+{
+ set_irq_type(AU1000_GPIO_9, IRQF_TRIGGER_LOW); /* PCCD# */
+ set_irq_type(AU1000_GPIO_10, IRQF_TRIGGER_LOW); /* PCSTSCHG# */
+ set_irq_type(AU1000_GPIO_11, IRQF_TRIGGER_LOW); /* PCCard# */
+ set_irq_type(AU1000_GPIO_13, IRQF_TRIGGER_LOW); /* DC_IRQ# */
+
+ return 0;
+}
+arch_initcall(pb1100_init_irq);
diff --git a/arch/mips/alchemy/devboards/pb1100/platform.c b/arch/mips/alchemy/devboards/pb1100/platform.c
new file mode 100644
index 000000000000..8487da55a10c
--- /dev/null
+++ b/arch/mips/alchemy/devboards/pb1100/platform.c
@@ -0,0 +1,43 @@
+/*
+ * Pb1100 board platform device registration
+ *
+ * Copyright (C) 2009 Manuel Lauss
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/init.h>
+
+#include <asm/mach-au1x00/au1000.h>
+
+#include "../platform.h"
+
+static int __init pb1100_dev_init(void)
+{
+ /* PCMCIA. single socket, identical to Pb1500 */
+ db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS,
+ PCMCIA_ATTR_PSEUDO_PHYS + 0x00040000 - 1,
+ PCMCIA_MEM_PSEUDO_PHYS,
+ PCMCIA_MEM_PSEUDO_PHYS + 0x00040000 - 1,
+ PCMCIA_IO_PSEUDO_PHYS,
+ PCMCIA_IO_PSEUDO_PHYS + 0x00001000 - 1,
+ AU1000_GPIO_11, /* card */
+ AU1000_GPIO_9, /* insert */
+ /*AU1000_GPIO_10*/0, /* stschg */
+ 0, /* eject */
+ 0); /* id */
+ return 0;
+}
+device_initcall(pb1100_dev_init);
diff --git a/arch/mips/alchemy/devboards/pb1200/Makefile b/arch/mips/alchemy/devboards/pb1200/Makefile
index c8c3a99fb68a..2ea9b02ef09f 100644
--- a/arch/mips/alchemy/devboards/pb1200/Makefile
+++ b/arch/mips/alchemy/devboards/pb1200/Makefile
@@ -2,6 +2,6 @@
# Makefile for the Alchemy Semiconductor Pb1200/DBAu1200 boards.
#
-obj-y := board_setup.o irqmap.o platform.o
+obj-y := board_setup.o platform.o
EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/alchemy/devboards/pb1200/board_setup.c b/arch/mips/alchemy/devboards/pb1200/board_setup.c
index 94e6b7e7753d..76aa652d80b1 100644
--- a/arch/mips/alchemy/devboards/pb1200/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1200/board_setup.c
@@ -25,11 +25,25 @@
*/
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/sched.h>
-#include <prom.h>
-#include <au1xxx.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-db1x00/bcsr.h>
+
+#ifdef CONFIG_MIPS_PB1200
+#include <asm/mach-pb1x00/pb1200.h>
+#endif
+#ifdef CONFIG_MIPS_DB1200
+#include <asm/mach-db1x00/db1200.h>
+#define PB1200_INT_BEGIN DB1200_INT_BEGIN
+#define PB1200_INT_END DB1200_INT_END
+#endif
+
+#include <asm/mach-db1x00/bcsr.h>
+
+#include <prom.h>
const char *get_system_type(void)
{
@@ -38,14 +52,25 @@ const char *get_system_type(void)
void board_reset(void)
{
- bcsr->resets = 0;
- bcsr->system = 0;
+ bcsr_write(BCSR_RESETS, 0);
+ bcsr_write(BCSR_SYSTEM, 0);
}
void __init board_setup(void)
{
char *argptr;
+#ifdef CONFIG_MIPS_PB1200
+ printk(KERN_INFO "AMD Alchemy Pb1200 Board\n");
+ bcsr_init(PB1200_BCSR_PHYS_ADDR,
+ PB1200_BCSR_PHYS_ADDR + PB1200_BCSR_HEXLED_OFS);
+#endif
+#ifdef CONFIG_MIPS_DB1200
+ printk(KERN_INFO "AMD Alchemy Db1200 Board\n");
+ bcsr_init(DB1200_BCSR_PHYS_ADDR,
+ DB1200_BCSR_PHYS_ADDR + DB1200_BCSR_HEXLED_OFS);
+#endif
+
argptr = prom_getcmdline();
#ifdef CONFIG_SERIAL_8250_CONSOLE
argptr = strstr(argptr, "console=");
@@ -82,7 +107,7 @@ void __init board_setup(void)
u32 pin_func;
/* Select SMBus in CPLD */
- bcsr->resets &= ~BCSR_RESETS_PCS0MUX;
+ bcsr_mod(BCSR_RESETS, BCSR_RESETS_PSC0MUX, 0);
pin_func = au_readl(SYS_PINFUNC);
au_sync();
@@ -116,38 +141,56 @@ void __init board_setup(void)
/*
* The Pb1200 development board uses external MUX for PSC0 to
- * support SMB/SPI. bcsr->resets bit 12: 0=SMB 1=SPI
+ * support SMB/SPI. bcsr_resets bit 12: 0=SMB 1=SPI
*/
#ifdef CONFIG_I2C_AU1550
- bcsr->resets &= ~BCSR_RESETS_PCS0MUX;
+ bcsr_mod(BCSR_RESETS, BCSR_RESETS_PSC0MUX, 0);
#endif
au_sync();
+}
+static int __init pb1200_init_irq(void)
+{
#ifdef CONFIG_MIPS_PB1200
- printk(KERN_INFO "AMD Alchemy Pb1200 Board\n");
-#endif
-#ifdef CONFIG_MIPS_DB1200
- printk(KERN_INFO "AMD Alchemy Db1200 Board\n");
+ /* We have a problem with CPLD rev 3. */
+ if (BCSR_WHOAMI_CPLD(bcsr_read(BCSR_WHOAMI)) <= 3) {
+ printk(KERN_ERR "WARNING!!!\n");
+ printk(KERN_ERR "WARNING!!!\n");
+ printk(KERN_ERR "WARNING!!!\n");
+ printk(KERN_ERR "WARNING!!!\n");
+ printk(KERN_ERR "WARNING!!!\n");
+ printk(KERN_ERR "WARNING!!!\n");
+ printk(KERN_ERR "Pb1200 must be at CPLD rev 4. Please have Pb1200\n");
+ printk(KERN_ERR "updated to latest revision. This software will\n");
+ printk(KERN_ERR "not work on anything less than CPLD rev 4.\n");
+ printk(KERN_ERR "WARNING!!!\n");
+ printk(KERN_ERR "WARNING!!!\n");
+ printk(KERN_ERR "WARNING!!!\n");
+ printk(KERN_ERR "WARNING!!!\n");
+ printk(KERN_ERR "WARNING!!!\n");
+ printk(KERN_ERR "WARNING!!!\n");
+ panic("Game over. Your score is 0.");
+ }
#endif
+
+ set_irq_type(AU1000_GPIO_7, IRQF_TRIGGER_LOW);
+ bcsr_init_irq(PB1200_INT_BEGIN, PB1200_INT_END, AU1000_GPIO_7);
+
+ return 0;
}
+arch_initcall(pb1200_init_irq);
+
int board_au1200fb_panel(void)
{
- BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR;
- int p;
-
- p = bcsr->switches;
- p >>= 8;
- p &= 0x0F;
- return p;
+ return (bcsr_read(BCSR_SWITCHES) >> 8) & 0x0f;
}
int board_au1200fb_panel_init(void)
{
/* Apply power */
- BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR;
-
- bcsr->board |= BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | BCSR_BOARD_LCDBL;
+ bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
+ BCSR_BOARD_LCDBL);
/* printk(KERN_DEBUG "board_au1200fb_panel_init()\n"); */
return 0;
}
@@ -155,10 +198,8 @@ int board_au1200fb_panel_init(void)
int board_au1200fb_panel_shutdown(void)
{
/* Remove power */
- BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR;
-
- bcsr->board &= ~(BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
- BCSR_BOARD_LCDBL);
+ bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
+ BCSR_BOARD_LCDBL, 0);
/* printk(KERN_DEBUG "board_au1200fb_panel_shutdown()\n"); */
return 0;
}
diff --git a/arch/mips/alchemy/devboards/pb1200/irqmap.c b/arch/mips/alchemy/devboards/pb1200/irqmap.c
deleted file mode 100644
index fe47498da280..000000000000
--- a/arch/mips/alchemy/devboards/pb1200/irqmap.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- * Au1xxx irq map table
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/init.h>
-#include <linux/interrupt.h>
-
-#include <asm/mach-au1x00/au1000.h>
-
-#ifdef CONFIG_MIPS_PB1200
-#include <asm/mach-pb1x00/pb1200.h>
-#endif
-
-#ifdef CONFIG_MIPS_DB1200
-#include <asm/mach-db1x00/db1200.h>
-#define PB1200_INT_BEGIN DB1200_INT_BEGIN
-#define PB1200_INT_END DB1200_INT_END
-#endif
-
-struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
- /* This is external interrupt cascade */
- { AU1000_GPIO_7, IRQF_TRIGGER_LOW, 0 },
-};
-
-
-/*
- * Support for External interrupts on the Pb1200 Development platform.
- */
-
-static void pb1200_cascade_handler(unsigned int irq, struct irq_desc *d)
-{
- unsigned short bisr = bcsr->int_status;
-
- for ( ; bisr; bisr &= bisr - 1)
- generic_handle_irq(PB1200_INT_BEGIN + __ffs(bisr));
-}
-
-/* NOTE: both the enable and mask bits must be cleared, otherwise the
- * CPLD generates tons of spurious interrupts (at least on the DB1200).
- */
-static void pb1200_mask_irq(unsigned int irq_nr)
-{
- bcsr->intclr_mask = 1 << (irq_nr - PB1200_INT_BEGIN);
- bcsr->intclr = 1 << (irq_nr - PB1200_INT_BEGIN);
- au_sync();
-}
-
-static void pb1200_maskack_irq(unsigned int irq_nr)
-{
- bcsr->intclr_mask = 1 << (irq_nr - PB1200_INT_BEGIN);
- bcsr->intclr = 1 << (irq_nr - PB1200_INT_BEGIN);
- bcsr->int_status = 1 << (irq_nr - PB1200_INT_BEGIN); /* ack */
- au_sync();
-}
-
-static void pb1200_unmask_irq(unsigned int irq_nr)
-{
- bcsr->intset = 1 << (irq_nr - PB1200_INT_BEGIN);
- bcsr->intset_mask = 1 << (irq_nr - PB1200_INT_BEGIN);
- au_sync();
-}
-
-static struct irq_chip pb1200_cpld_irq_type = {
-#ifdef CONFIG_MIPS_PB1200
- .name = "Pb1200 Ext",
-#endif
-#ifdef CONFIG_MIPS_DB1200
- .name = "Db1200 Ext",
-#endif
- .mask = pb1200_mask_irq,
- .mask_ack = pb1200_maskack_irq,
- .unmask = pb1200_unmask_irq,
-};
-
-void __init board_init_irq(void)
-{
- unsigned int irq;
-
- au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map));
-
-#ifdef CONFIG_MIPS_PB1200
- /* We have a problem with CPLD rev 3. */
- if (((bcsr->whoami & BCSR_WHOAMI_CPLD) >> 4) <= 3) {
- printk(KERN_ERR "WARNING!!!\n");
- printk(KERN_ERR "WARNING!!!\n");
- printk(KERN_ERR "WARNING!!!\n");
- printk(KERN_ERR "WARNING!!!\n");
- printk(KERN_ERR "WARNING!!!\n");
- printk(KERN_ERR "WARNING!!!\n");
- printk(KERN_ERR "Pb1200 must be at CPLD rev 4. Please have Pb1200\n");
- printk(KERN_ERR "updated to latest revision. This software will\n");
- printk(KERN_ERR "not work on anything less than CPLD rev 4.\n");
- printk(KERN_ERR "WARNING!!!\n");
- printk(KERN_ERR "WARNING!!!\n");
- printk(KERN_ERR "WARNING!!!\n");
- printk(KERN_ERR "WARNING!!!\n");
- printk(KERN_ERR "WARNING!!!\n");
- printk(KERN_ERR "WARNING!!!\n");
- panic("Game over. Your score is 0.");
- }
-#endif
- /* mask & disable & ack all */
- bcsr->intclr_mask = 0xffff;
- bcsr->intclr = 0xffff;
- bcsr->int_status = 0xffff;
- au_sync();
-
- for (irq = PB1200_INT_BEGIN; irq <= PB1200_INT_END; irq++)
- set_irq_chip_and_handler_name(irq, &pb1200_cpld_irq_type,
- handle_level_irq, "level");
-
- set_irq_chained_handler(AU1000_GPIO_7, pb1200_cascade_handler);
-}
diff --git a/arch/mips/alchemy/devboards/pb1200/platform.c b/arch/mips/alchemy/devboards/pb1200/platform.c
index b93dff4a6789..c8b7ae3f3253 100644
--- a/arch/mips/alchemy/devboards/pb1200/platform.c
+++ b/arch/mips/alchemy/devboards/pb1200/platform.c
@@ -26,27 +26,30 @@
#include <asm/mach-au1x00/au1xxx.h>
#include <asm/mach-au1x00/au1100_mmc.h>
+#include <asm/mach-db1x00/bcsr.h>
+
+#include "../platform.h"
static int mmc_activity;
static void pb1200mmc0_set_power(void *mmc_host, int state)
{
if (state)
- bcsr->board |= BCSR_BOARD_SD0PWR;
+ bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD0PWR);
else
- bcsr->board &= ~BCSR_BOARD_SD0PWR;
+ bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD0PWR, 0);
- au_sync_delay(1);
+ msleep(1);
}
static int pb1200mmc0_card_readonly(void *mmc_host)
{
- return (bcsr->status & BCSR_STATUS_SD0WP) ? 1 : 0;
+ return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD0WP) ? 1 : 0;
}
static int pb1200mmc0_card_inserted(void *mmc_host)
{
- return (bcsr->sig_status & BCSR_INT_SD0INSERT) ? 1 : 0;
+ return (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD0INSERT) ? 1 : 0;
}
static void pb1200_mmcled_set(struct led_classdev *led,
@@ -54,10 +57,10 @@ static void pb1200_mmcled_set(struct led_classdev *led,
{
if (brightness != LED_OFF) {
if (++mmc_activity == 1)
- bcsr->disk_leds &= ~(1 << 8);
+ bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED0, 0);
} else {
if (--mmc_activity == 0)
- bcsr->disk_leds |= (1 << 8);
+ bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED0);
}
}
@@ -69,21 +72,21 @@ static struct led_classdev pb1200mmc_led = {
static void pb1200mmc1_set_power(void *mmc_host, int state)
{
if (state)
- bcsr->board |= BCSR_BOARD_SD1PWR;
+ bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD1PWR);
else
- bcsr->board &= ~BCSR_BOARD_SD1PWR;
+ bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD1PWR, 0);
- au_sync_delay(1);
+ msleep(1);
}
static int pb1200mmc1_card_readonly(void *mmc_host)
{
- return (bcsr->status & BCSR_STATUS_SD1WP) ? 1 : 0;
+ return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD1WP) ? 1 : 0;
}
static int pb1200mmc1_card_inserted(void *mmc_host)
{
- return (bcsr->sig_status & BCSR_INT_SD1INSERT) ? 1 : 0;
+ return (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD1INSERT) ? 1 : 0;
}
#endif
@@ -169,8 +172,57 @@ static struct platform_device *board_platform_devices[] __initdata = {
static int __init board_register_devices(void)
{
+#ifdef CONFIG_MIPS_PB1200
+ db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS,
+ PCMCIA_ATTR_PSEUDO_PHYS + 0x00040000 - 1,
+ PCMCIA_MEM_PSEUDO_PHYS,
+ PCMCIA_MEM_PSEUDO_PHYS + 0x00040000 - 1,
+ PCMCIA_IO_PSEUDO_PHYS,
+ PCMCIA_IO_PSEUDO_PHYS + 0x00001000 - 1,
+ PB1200_PC0_INT,
+ PB1200_PC0_INSERT_INT,
+ /*PB1200_PC0_STSCHG_INT*/0,
+ PB1200_PC0_EJECT_INT,
+ 0);
+
+ db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS + 0x00800000,
+ PCMCIA_ATTR_PSEUDO_PHYS + 0x00840000 - 1,
+ PCMCIA_MEM_PSEUDO_PHYS + 0x00800000,
+ PCMCIA_MEM_PSEUDO_PHYS + 0x00840000 - 1,
+ PCMCIA_IO_PSEUDO_PHYS + 0x00800000,
+ PCMCIA_IO_PSEUDO_PHYS + 0x00801000 - 1,
+ PB1200_PC1_INT,
+ PB1200_PC1_INSERT_INT,
+ /*PB1200_PC1_STSCHG_INT*/0,
+ PB1200_PC1_EJECT_INT,
+ 1);
+#else
+ db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS,
+ PCMCIA_ATTR_PSEUDO_PHYS + 0x00040000 - 1,
+ PCMCIA_MEM_PSEUDO_PHYS,
+ PCMCIA_MEM_PSEUDO_PHYS + 0x00040000 - 1,
+ PCMCIA_IO_PSEUDO_PHYS,
+ PCMCIA_IO_PSEUDO_PHYS + 0x00001000 - 1,
+ DB1200_PC0_INT,
+ DB1200_PC0_INSERT_INT,
+ /*DB1200_PC0_STSCHG_INT*/0,
+ DB1200_PC0_EJECT_INT,
+ 0);
+
+ db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS + 0x00400000,
+ PCMCIA_ATTR_PSEUDO_PHYS + 0x00440000 - 1,
+ PCMCIA_MEM_PSEUDO_PHYS + 0x00400000,
+ PCMCIA_MEM_PSEUDO_PHYS + 0x00440000 - 1,
+ PCMCIA_IO_PSEUDO_PHYS + 0x00400000,
+ PCMCIA_IO_PSEUDO_PHYS + 0x00401000 - 1,
+ DB1200_PC1_INT,
+ DB1200_PC1_INSERT_INT,
+ /*DB1200_PC1_STSCHG_INT*/0,
+ DB1200_PC1_EJECT_INT,
+ 1);
+#endif
+
return platform_add_devices(board_platform_devices,
ARRAY_SIZE(board_platform_devices));
}
-
-arch_initcall(board_register_devices);
+device_initcall(board_register_devices);
diff --git a/arch/mips/alchemy/devboards/pb1500/Makefile b/arch/mips/alchemy/devboards/pb1500/Makefile
index 173b419a7479..c29545d2c8ba 100644
--- a/arch/mips/alchemy/devboards/pb1500/Makefile
+++ b/arch/mips/alchemy/devboards/pb1500/Makefile
@@ -5,4 +5,5 @@
# Makefile for the Alchemy Semiconductor Pb1500 board.
#
-obj-y := board_setup.o
+obj-y := board_setup.o platform.o
+
diff --git a/arch/mips/alchemy/devboards/pb1500/board_setup.c b/arch/mips/alchemy/devboards/pb1500/board_setup.c
index d7a56569e7ed..a148802fa427 100644
--- a/arch/mips/alchemy/devboards/pb1500/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1500/board_setup.c
@@ -29,7 +29,7 @@
#include <linux/interrupt.h>
#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-pb1x00/pb1500.h>
+#include <asm/mach-db1x00/bcsr.h>
#include <prom.h>
@@ -39,14 +39,6 @@ char irq_tab_alchemy[][5] __initdata = {
[13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot */
};
-struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
- { AU1500_GPIO_204, IRQF_TRIGGER_HIGH, 0 },
- { AU1500_GPIO_201, IRQF_TRIGGER_LOW, 0 },
- { AU1500_GPIO_202, IRQF_TRIGGER_LOW, 0 },
- { AU1500_GPIO_203, IRQF_TRIGGER_LOW, 0 },
- { AU1500_GPIO_205, IRQF_TRIGGER_LOW, 0 },
-};
-
const char *get_system_type(void)
{
@@ -55,13 +47,7 @@ const char *get_system_type(void)
void board_reset(void)
{
- /* Hit BCSR.RST_VDDI[SOFT_RESET] */
- au_writel(0x00000000, PB1500_RST_VDDI);
-}
-
-void __init board_init_irq(void)
-{
- au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map));
+ bcsr_write(BCSR_SYSTEM, 0);
}
void __init board_setup(void)
@@ -70,6 +56,9 @@ void __init board_setup(void)
u32 sys_freqctrl, sys_clksrc;
char *argptr;
+ bcsr_init(DB1000_BCSR_PHYS_ADDR,
+ DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS);
+
argptr = prom_getcmdline();
#ifdef CONFIG_SERIAL_8250_CONSOLE
argptr = strstr(argptr, "console=");
@@ -163,3 +152,18 @@ void __init board_setup(void)
au_sync();
}
}
+
+static int __init pb1500_init_irq(void)
+{
+ set_irq_type(AU1000_GPIO_9, IRQF_TRIGGER_LOW); /* CD0# */
+ set_irq_type(AU1000_GPIO_10, IRQF_TRIGGER_LOW); /* CARD0 */
+ set_irq_type(AU1000_GPIO_11, IRQF_TRIGGER_LOW); /* STSCHG0# */
+ set_irq_type(AU1500_GPIO_204, IRQF_TRIGGER_HIGH);
+ set_irq_type(AU1500_GPIO_201, IRQF_TRIGGER_LOW);
+ set_irq_type(AU1500_GPIO_202, IRQF_TRIGGER_LOW);
+ set_irq_type(AU1500_GPIO_203, IRQF_TRIGGER_LOW);
+ set_irq_type(AU1500_GPIO_205, IRQF_TRIGGER_LOW);
+
+ return 0;
+}
+arch_initcall(pb1500_init_irq);
diff --git a/arch/mips/alchemy/devboards/pb1500/platform.c b/arch/mips/alchemy/devboards/pb1500/platform.c
new file mode 100644
index 000000000000..6c00cbe529a2
--- /dev/null
+++ b/arch/mips/alchemy/devboards/pb1500/platform.c
@@ -0,0 +1,42 @@
+/*
+ * Pb1500 board platform device registration
+ *
+ * Copyright (C) 2009 Manuel Lauss
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/init.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#include "../platform.h"
+
+static int __init pb1500_dev_init(void)
+{
+ /* PCMCIA. single socket, identical to Pb1500 */
+ db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS,
+ PCMCIA_ATTR_PSEUDO_PHYS + 0x00040000 - 1,
+ PCMCIA_MEM_PSEUDO_PHYS,
+ PCMCIA_MEM_PSEUDO_PHYS + 0x00040000 - 1,
+ PCMCIA_IO_PSEUDO_PHYS,
+ PCMCIA_IO_PSEUDO_PHYS + 0x00001000 - 1,
+ AU1000_GPIO_11, /* card */
+ AU1000_GPIO_9, /* insert */
+ /*AU1000_GPIO_10*/0, /* stschg */
+ 0, /* eject */
+ 0); /* id */
+ return 0;
+}
+device_initcall(pb1500_dev_init);
diff --git a/arch/mips/alchemy/devboards/pb1550/Makefile b/arch/mips/alchemy/devboards/pb1550/Makefile
index cff95bcdb2ca..86b410b5d19a 100644
--- a/arch/mips/alchemy/devboards/pb1550/Makefile
+++ b/arch/mips/alchemy/devboards/pb1550/Makefile
@@ -5,4 +5,5 @@
# Makefile for the Alchemy Semiconductor Pb1550 board.
#
-obj-y := board_setup.o
+obj-y := board_setup.o platform.o
+
diff --git a/arch/mips/alchemy/devboards/pb1550/board_setup.c b/arch/mips/alchemy/devboards/pb1550/board_setup.c
index b6e9e7d247a3..64a6fc4f1751 100644
--- a/arch/mips/alchemy/devboards/pb1550/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1550/board_setup.c
@@ -32,6 +32,8 @@
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-pb1x00/pb1550.h>
+#include <asm/mach-db1x00/bcsr.h>
+#include <asm/mach-au1x00/gpio.h>
#include <prom.h>
@@ -41,11 +43,6 @@ char irq_tab_alchemy[][5] __initdata = {
[13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot 1 (right) */
};
-struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
- { AU1000_GPIO_0, IRQF_TRIGGER_LOW, 0 },
- { AU1000_GPIO_1, IRQF_TRIGGER_LOW, 0 },
-};
-
const char *get_system_type(void)
{
return "Alchemy Pb1550";
@@ -53,19 +50,17 @@ const char *get_system_type(void)
void board_reset(void)
{
- /* Hit BCSR.SYSTEM[RESET] */
- au_writew(au_readw(0xAF00001C) & ~BCSR_SYSTEM_RESET, 0xAF00001C);
-}
-
-void __init board_init_irq(void)
-{
- au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map));
+ bcsr_write(BCSR_SYSTEM, 0);
}
void __init board_setup(void)
{
u32 pin_func;
+ bcsr_init(PB1550_BCSR_PHYS_ADDR,
+ PB1550_BCSR_PHYS_ADDR + PB1550_BCSR_HEXLED_OFS);
+
+
#ifdef CONFIG_SERIAL_8250_CONSOLE
char *argptr;
argptr = prom_getcmdline();
@@ -76,6 +71,8 @@ void __init board_setup(void)
}
#endif
+ alchemy_gpio2_enable();
+
/*
* Enable PSC1 SYNC for AC'97. Normaly done in audio driver,
* but it is board specific code, so put it here.
@@ -85,8 +82,21 @@ void __init board_setup(void)
pin_func |= SYS_PF_MUST_BE_SET | SYS_PF_PSC1_S1;
au_writel(pin_func, SYS_PINFUNC);
- au_writel(0, (u32)bcsr | 0x10); /* turn off PCMCIA power */
- au_sync();
+ bcsr_write(BCSR_PCMCIA, 0); /* turn off PCMCIA power */
printk(KERN_INFO "AMD Alchemy Pb1550 Board\n");
}
+
+static int __init pb1550_init_irq(void)
+{
+ set_irq_type(AU1000_GPIO_0, IRQF_TRIGGER_LOW);
+ set_irq_type(AU1000_GPIO_1, IRQF_TRIGGER_LOW);
+ set_irq_type(AU1500_GPIO_201_205, IRQF_TRIGGER_HIGH);
+
+ /* enable both PCMCIA card irqs in the shared line */
+ alchemy_gpio2_enable_int(201);
+ alchemy_gpio2_enable_int(202);
+
+ return 0;
+}
+arch_initcall(pb1550_init_irq);
diff --git a/arch/mips/alchemy/devboards/pb1550/platform.c b/arch/mips/alchemy/devboards/pb1550/platform.c
new file mode 100644
index 000000000000..aa5016c2e868
--- /dev/null
+++ b/arch/mips/alchemy/devboards/pb1550/platform.c
@@ -0,0 +1,63 @@
+/*
+ * Pb1550 board platform device registration
+ *
+ * Copyright (C) 2009 Manuel Lauss
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/init.h>
+
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-pb1x00/pb1550.h>
+
+#include "../platform.h"
+
+static int __init pb1550_dev_init(void)
+{
+ /* Pb1550, like all others, also has statuschange irqs; however they're
+ * wired up on one of the Au1550's shared GPIO201_205 line, which also
+ * services the PCMCIA card interrupts. So we ignore statuschange and
+ * use the GPIO201_205 exclusively for card interrupts, since a) pcmcia
+ * drivers are used to shared irqs and b) statuschange isn't really use-
+ * ful anyway.
+ */
+ db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS,
+ PCMCIA_ATTR_PSEUDO_PHYS + 0x00040000 - 1,
+ PCMCIA_MEM_PSEUDO_PHYS,
+ PCMCIA_MEM_PSEUDO_PHYS + 0x00040000 - 1,
+ PCMCIA_IO_PSEUDO_PHYS,
+ PCMCIA_IO_PSEUDO_PHYS + 0x00001000 - 1,
+ AU1500_GPIO_201_205,
+ AU1000_GPIO_0,
+ 0,
+ 0,
+ 0);
+
+ db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS + 0x00800000,
+ PCMCIA_ATTR_PSEUDO_PHYS + 0x00840000 - 1,
+ PCMCIA_MEM_PSEUDO_PHYS + 0x00800000,
+ PCMCIA_MEM_PSEUDO_PHYS + 0x00840000 - 1,
+ PCMCIA_IO_PSEUDO_PHYS + 0x00800000,
+ PCMCIA_IO_PSEUDO_PHYS + 0x00801000 - 1,
+ AU1500_GPIO_201_205,
+ AU1000_GPIO_1,
+ 0,
+ 0,
+ 1);
+
+ return 0;
+}
+device_initcall(pb1550_dev_init);
diff --git a/arch/mips/alchemy/devboards/platform.c b/arch/mips/alchemy/devboards/platform.c
new file mode 100644
index 000000000000..48c537cc8efb
--- /dev/null
+++ b/arch/mips/alchemy/devboards/platform.c
@@ -0,0 +1,89 @@
+/*
+ * devoard misc stuff.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+/* register a pcmcia socket */
+int __init db1x_register_pcmcia_socket(unsigned long pseudo_attr_start,
+ unsigned long pseudo_attr_end,
+ unsigned long pseudo_mem_start,
+ unsigned long pseudo_mem_end,
+ unsigned long pseudo_io_start,
+ unsigned long pseudo_io_end,
+ int card_irq,
+ int cd_irq,
+ int stschg_irq,
+ int eject_irq,
+ int id)
+{
+ int cnt, i, ret;
+ struct resource *sr;
+ struct platform_device *pd;
+
+ cnt = 5;
+ if (eject_irq)
+ cnt++;
+ if (stschg_irq)
+ cnt++;
+
+ sr = kzalloc(sizeof(struct resource) * cnt, GFP_KERNEL);
+ if (!sr)
+ return -ENOMEM;
+
+ pd = platform_device_alloc("db1xxx_pcmcia", id);
+ if (!pd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ sr[0].name = "pseudo-attr";
+ sr[0].flags = IORESOURCE_MEM;
+ sr[0].start = pseudo_attr_start;
+ sr[0].end = pseudo_attr_end;
+
+ sr[1].name = "pseudo-mem";
+ sr[1].flags = IORESOURCE_MEM;
+ sr[1].start = pseudo_mem_start;
+ sr[1].end = pseudo_mem_end;
+
+ sr[2].name = "pseudo-io";
+ sr[2].flags = IORESOURCE_MEM;
+ sr[2].start = pseudo_io_start;
+ sr[2].end = pseudo_io_end;
+
+ sr[3].name = "insert";
+ sr[3].flags = IORESOURCE_IRQ;
+ sr[3].start = sr[3].end = cd_irq;
+
+ sr[4].name = "card";
+ sr[4].flags = IORESOURCE_IRQ;
+ sr[4].start = sr[4].end = card_irq;
+
+ i = 5;
+ if (stschg_irq) {
+ sr[i].name = "insert";
+ sr[i].flags = IORESOURCE_IRQ;
+ sr[i].start = sr[i].end = cd_irq;
+ i++;
+ }
+ if (eject_irq) {
+ sr[i].name = "eject";
+ sr[i].flags = IORESOURCE_IRQ;
+ sr[i].start = sr[i].end = eject_irq;
+ }
+
+ pd->resource = sr;
+ pd->num_resources = cnt;
+
+ ret = platform_device_add(pd);
+ if (!ret)
+ return 0;
+
+ platform_device_put(pd);
+out:
+ kfree(sr);
+ return ret;
+}
diff --git a/arch/mips/alchemy/devboards/platform.h b/arch/mips/alchemy/devboards/platform.h
new file mode 100644
index 000000000000..55ecf7e9258f
--- /dev/null
+++ b/arch/mips/alchemy/devboards/platform.h
@@ -0,0 +1,18 @@
+#ifndef _DEVBOARD_PLATFORM_H_
+#define _DEVBOARD_PLATFORM_H_
+
+#include <linux/init.h>
+
+int __init db1x_register_pcmcia_socket(unsigned long pseudo_attr_start,
+ unsigned long pseudo_attr_len,
+ unsigned long pseudo_mem_start,
+ unsigned long pseudo_mem_end,
+ unsigned long pseudo_io_start,
+ unsigned long pseudo_io_end,
+ int card_irq,
+ int cd_irq,
+ int stschg_irq,
+ int eject_irq,
+ int id);
+
+#endif
diff --git a/arch/mips/alchemy/mtx-1/Makefile b/arch/mips/alchemy/mtx-1/Makefile
index 7c67b3d33bec..4a53815b3c6c 100644
--- a/arch/mips/alchemy/mtx-1/Makefile
+++ b/arch/mips/alchemy/mtx-1/Makefile
@@ -6,7 +6,7 @@
# Makefile for 4G Systems MTX-1 board.
#
-lib-y := init.o board_setup.o irqmap.o
+lib-y := init.o board_setup.o
obj-y := platform.o
EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/alchemy/mtx-1/board_setup.c b/arch/mips/alchemy/mtx-1/board_setup.c
index cc32c69a74ad..568492ccca0e 100644
--- a/arch/mips/alchemy/mtx-1/board_setup.c
+++ b/arch/mips/alchemy/mtx-1/board_setup.c
@@ -30,11 +30,23 @@
#include <linux/gpio.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <asm/mach-au1x00/au1000.h>
#include <prom.h>
+char irq_tab_alchemy[][5] __initdata = {
+ [0] = { -1, INTA, INTA, INTX, INTX }, /* IDSEL 00 - AdapterA-Slot0 (top) */
+ [1] = { -1, INTB, INTA, INTX, INTX }, /* IDSEL 01 - AdapterA-Slot1 (bottom) */
+ [2] = { -1, INTC, INTD, INTX, INTX }, /* IDSEL 02 - AdapterB-Slot0 (top) */
+ [3] = { -1, INTD, INTC, INTX, INTX }, /* IDSEL 03 - AdapterB-Slot1 (bottom) */
+ [4] = { -1, INTA, INTB, INTX, INTX }, /* IDSEL 04 - AdapterC-Slot0 (top) */
+ [5] = { -1, INTB, INTA, INTX, INTX }, /* IDSEL 05 - AdapterC-Slot1 (bottom) */
+ [6] = { -1, INTC, INTD, INTX, INTX }, /* IDSEL 06 - AdapterD-Slot0 (top) */
+ [7] = { -1, INTD, INTC, INTX, INTX }, /* IDSEL 07 - AdapterD-Slot1 (bottom) */
+};
+
extern int (*board_pci_idsel)(unsigned int devsel, int assert);
int mtx1_pci_idsel(unsigned int devsel, int assert);
@@ -110,3 +122,15 @@ mtx1_pci_idsel(unsigned int devsel, int assert)
au_sync_udelay(1);
return 1;
}
+
+static int __init mtx1_init_irq(void)
+{
+ set_irq_type(AU1500_GPIO_204, IRQF_TRIGGER_HIGH);
+ set_irq_type(AU1500_GPIO_201, IRQF_TRIGGER_LOW);
+ set_irq_type(AU1500_GPIO_202, IRQF_TRIGGER_LOW);
+ set_irq_type(AU1500_GPIO_203, IRQF_TRIGGER_LOW);
+ set_irq_type(AU1500_GPIO_205, IRQF_TRIGGER_LOW);
+
+ return 0;
+}
+arch_initcall(mtx1_init_irq);
diff --git a/arch/mips/alchemy/mtx-1/irqmap.c b/arch/mips/alchemy/mtx-1/irqmap.c
deleted file mode 100644
index f1ab12ab3433..000000000000
--- a/arch/mips/alchemy/mtx-1/irqmap.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- * Au1xxx irq map table
- *
- * Copyright 2003 Embedded Edge, LLC
- * dan@embeddededge.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <asm/mach-au1x00/au1000.h>
-
-char irq_tab_alchemy[][5] __initdata = {
- [0] = { -1, INTA, INTA, INTX, INTX }, /* IDSEL 00 - AdapterA-Slot0 (top) */
- [1] = { -1, INTB, INTA, INTX, INTX }, /* IDSEL 01 - AdapterA-Slot1 (bottom) */
- [2] = { -1, INTC, INTD, INTX, INTX }, /* IDSEL 02 - AdapterB-Slot0 (top) */
- [3] = { -1, INTD, INTC, INTX, INTX }, /* IDSEL 03 - AdapterB-Slot1 (bottom) */
- [4] = { -1, INTA, INTB, INTX, INTX }, /* IDSEL 04 - AdapterC-Slot0 (top) */
- [5] = { -1, INTB, INTA, INTX, INTX }, /* IDSEL 05 - AdapterC-Slot1 (bottom) */
- [6] = { -1, INTC, INTD, INTX, INTX }, /* IDSEL 06 - AdapterD-Slot0 (top) */
- [7] = { -1, INTD, INTC, INTX, INTX }, /* IDSEL 07 - AdapterD-Slot1 (bottom) */
-};
-
-struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
- { AU1500_GPIO_204, IRQF_TRIGGER_HIGH, 0 },
- { AU1500_GPIO_201, IRQF_TRIGGER_LOW, 0 },
- { AU1500_GPIO_202, IRQF_TRIGGER_LOW, 0 },
- { AU1500_GPIO_203, IRQF_TRIGGER_LOW, 0 },
- { AU1500_GPIO_205, IRQF_TRIGGER_LOW, 0 },
-};
-
-
-void __init board_init_irq(void)
-{
- au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map));
-}
diff --git a/arch/mips/alchemy/xxs1500/Makefile b/arch/mips/alchemy/xxs1500/Makefile
index db3c526f64d8..68671c2f372c 100644
--- a/arch/mips/alchemy/xxs1500/Makefile
+++ b/arch/mips/alchemy/xxs1500/Makefile
@@ -5,4 +5,4 @@
# Makefile for MyCable XXS1500 board.
#
-lib-y := init.o board_setup.o irqmap.o
+lib-y := init.o board_setup.o platform.o
diff --git a/arch/mips/alchemy/xxs1500/board_setup.c b/arch/mips/alchemy/xxs1500/board_setup.c
index 4de2d48caed8..eb31350d9772 100644
--- a/arch/mips/alchemy/xxs1500/board_setup.c
+++ b/arch/mips/alchemy/xxs1500/board_setup.c
@@ -25,6 +25,7 @@
#include <linux/gpio.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/delay.h>
#include <asm/mach-au1x00/au1000.h>
@@ -68,22 +69,6 @@ void __init board_setup(void)
/* Enable DTR = USB power up */
au_writel(0x01, UART3_ADDR + UART_MCR); /* UART_MCR_DTR is 0x01??? */
-#ifdef CONFIG_PCMCIA_XXS1500
- /* GPIO 0, 1, and 4 are inputs */
- alchemy_gpio_direction_input(0);
- alchemy_gpio_direction_input(1);
- alchemy_gpio_direction_input(4);
-
- /* GPIO2 208/9/10/11 are inputs */
- alchemy_gpio_direction_input(208);
- alchemy_gpio_direction_input(209);
- alchemy_gpio_direction_input(210);
- alchemy_gpio_direction_input(211);
-
- /* Turn off power */
- alchemy_gpio_direction_output(214, 0);
-#endif
-
#ifdef CONFIG_PCI
#if defined(__MIPSEB__)
au_writel(0xf | (2 << 6) | (1 << 4), Au1500_PCI_CFG);
@@ -92,3 +77,23 @@ void __init board_setup(void)
#endif
#endif
}
+
+static int __init xxs1500_init_irq(void)
+{
+ set_irq_type(AU1500_GPIO_204, IRQF_TRIGGER_HIGH);
+ set_irq_type(AU1500_GPIO_201, IRQF_TRIGGER_LOW);
+ set_irq_type(AU1500_GPIO_202, IRQF_TRIGGER_LOW);
+ set_irq_type(AU1500_GPIO_203, IRQF_TRIGGER_LOW);
+ set_irq_type(AU1500_GPIO_205, IRQF_TRIGGER_LOW);
+ set_irq_type(AU1500_GPIO_207, IRQF_TRIGGER_LOW);
+
+ set_irq_type(AU1000_GPIO_0, IRQF_TRIGGER_LOW);
+ set_irq_type(AU1000_GPIO_1, IRQF_TRIGGER_LOW);
+ set_irq_type(AU1000_GPIO_2, IRQF_TRIGGER_LOW);
+ set_irq_type(AU1000_GPIO_3, IRQF_TRIGGER_LOW);
+ set_irq_type(AU1000_GPIO_4, IRQF_TRIGGER_LOW); /* CF interrupt */
+ set_irq_type(AU1000_GPIO_5, IRQF_TRIGGER_LOW);
+
+ return 0;
+}
+arch_initcall(xxs1500_init_irq);
diff --git a/arch/mips/alchemy/xxs1500/irqmap.c b/arch/mips/alchemy/xxs1500/irqmap.c
deleted file mode 100644
index 0f0f3012e5fd..000000000000
--- a/arch/mips/alchemy/xxs1500/irqmap.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- * Au1xxx irq map table
- *
- * Copyright 2003 Embedded Edge, LLC
- * dan@embeddededge.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <asm/mach-au1x00/au1000.h>
-
-struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
- { AU1500_GPIO_204, IRQF_TRIGGER_HIGH, 0 },
- { AU1500_GPIO_201, IRQF_TRIGGER_LOW, 0 },
- { AU1500_GPIO_202, IRQF_TRIGGER_LOW, 0 },
- { AU1500_GPIO_203, IRQF_TRIGGER_LOW, 0 },
- { AU1500_GPIO_205, IRQF_TRIGGER_LOW, 0 },
- { AU1500_GPIO_207, IRQF_TRIGGER_LOW, 0 },
-
- { AU1000_GPIO_0, IRQF_TRIGGER_LOW, 0 },
- { AU1000_GPIO_1, IRQF_TRIGGER_LOW, 0 },
- { AU1000_GPIO_2, IRQF_TRIGGER_LOW, 0 },
- { AU1000_GPIO_3, IRQF_TRIGGER_LOW, 0 },
- { AU1000_GPIO_4, IRQF_TRIGGER_LOW, 0 }, /* CF interrupt */
- { AU1000_GPIO_5, IRQF_TRIGGER_LOW, 0 },
-};
-
-void __init board_init_irq(void)
-{
- au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map));
-}
diff --git a/arch/mips/alchemy/xxs1500/platform.c b/arch/mips/alchemy/xxs1500/platform.c
new file mode 100644
index 000000000000..c14dcaa95311
--- /dev/null
+++ b/arch/mips/alchemy/xxs1500/platform.c
@@ -0,0 +1,63 @@
+/*
+ * XXS1500 board platform device registration
+ *
+ * Copyright (C) 2009 Manuel Lauss
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-au1x00/au1000.h>
+
+static struct resource xxs1500_pcmcia_res[] = {
+ {
+ .name = "pseudo-io",
+ .flags = IORESOURCE_MEM,
+ .start = PCMCIA_IO_PSEUDO_PHYS,
+ .end = PCMCIA_IO_PSEUDO_PHYS + 0x00040000 - 1,
+ },
+ {
+ .name = "pseudo-attr",
+ .flags = IORESOURCE_MEM,
+ .start = PCMCIA_ATTR_PSEUDO_PHYS,
+ .end = PCMCIA_ATTR_PSEUDO_PHYS + 0x00040000 - 1,
+ },
+ {
+ .name = "pseudo-mem",
+ .flags = IORESOURCE_MEM,
+ .start = PCMCIA_IO_PSEUDO_PHYS,
+ .end = PCMCIA_IO_PSEUDO_PHYS + 0x00040000 - 1,
+ },
+};
+
+static struct platform_device xxs1500_pcmcia_dev = {
+ .name = "xxs1500_pcmcia",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(xxs1500_pcmcia_res),
+ .resource = xxs1500_pcmcia_res,
+};
+
+static struct platform_device *xxs1500_devs[] __initdata = {
+ &xxs1500_pcmcia_dev,
+};
+
+static int __init xxs1500_dev_init(void)
+{
+ return platform_add_devices(xxs1500_devs,
+ ARRAY_SIZE(xxs1500_devs));
+}
+device_initcall(xxs1500_dev_init);
diff --git a/arch/mips/bcm47xx/prom.c b/arch/mips/bcm47xx/prom.c
index 079e33d52783..a06b1a64c1f7 100644
--- a/arch/mips/bcm47xx/prom.c
+++ b/arch/mips/bcm47xx/prom.c
@@ -100,11 +100,11 @@ static __init void prom_init_console(void)
static __init void prom_init_cmdline(void)
{
- char buf[CL_SIZE];
+ char buf[COMMAND_LINE_SIZE];
/* Get the kernel command line from CFE */
- if (cfe_getenv("LINUX_CMDLINE", buf, CL_SIZE) >= 0) {
- buf[CL_SIZE-1] = 0;
+ if (cfe_getenv("LINUX_CMDLINE", buf, COMMAND_LINE_SIZE) >= 0) {
+ buf[COMMAND_LINE_SIZE-1] = 0;
strcpy(arcs_cmdline, buf);
}
@@ -112,13 +112,13 @@ static __init void prom_init_cmdline(void)
* as CFE is not available anymore later in the boot process. */
if ((strstr(arcs_cmdline, "console=")) == NULL) {
/* Try to read the default serial port used by CFE */
- if ((cfe_getenv("BOOT_CONSOLE", buf, CL_SIZE) < 0)
+ if ((cfe_getenv("BOOT_CONSOLE", buf, COMMAND_LINE_SIZE) < 0)
|| (strncmp("uart", buf, 4)))
/* Default to uart0 */
strcpy(buf, "uart0");
/* Compute the new command line */
- snprintf(arcs_cmdline, CL_SIZE, "%s console=ttyS%c,115200",
+ snprintf(arcs_cmdline, COMMAND_LINE_SIZE, "%s console=ttyS%c,115200",
arcs_cmdline, buf[4]);
}
}
diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile
new file mode 100644
index 000000000000..9bc435dbc348
--- /dev/null
+++ b/arch/mips/boot/compressed/Makefile
@@ -0,0 +1,97 @@
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.
+#
+# Adapted for MIPS Pete Popov, Dan Malek
+#
+# Copyright (C) 1994 by Linus Torvalds
+# Adapted for PowerPC by Gary Thomas
+# modified by Cort (cort@cs.nmt.edu)
+#
+# Copyright (C) 2009 Lemote Inc. & DSLab, Lanzhou University
+# Author: Wu Zhangjin <wuzj@lemote.com>
+#
+
+# compressed kernel load addr: VMLINUZ_LOAD_ADDRESS > VMLINUX_LOAD_ADDRESS + VMLINUX_SIZE
+VMLINUX_SIZE := $(shell wc -c $(objtree)/$(KBUILD_IMAGE) 2>/dev/null | cut -d' ' -f1)
+VMLINUX_SIZE := $(shell [ -n "$(VMLINUX_SIZE)" ] && echo $$(($(VMLINUX_SIZE) + (65536 - $(VMLINUX_SIZE) % 65536))))
+VMLINUZ_LOAD_ADDRESS := 0x$(shell [ -n "$(VMLINUX_SIZE)" ] && printf %x $$(($(VMLINUX_LOAD_ADDRESS) + $(VMLINUX_SIZE))))
+
+# set the default size of the mallocing area for decompressing
+BOOT_HEAP_SIZE := 0x400000
+
+KBUILD_CFLAGS := $(LINUXINCLUDE) $(KBUILD_CFLAGS) -D__KERNEL__ \
+ -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) -D"VMLINUX_LOAD_ADDRESS_ULL=$(VMLINUX_LOAD_ADDRESS)ull" \
+
+KBUILD_AFLAGS := $(LINUXINCLUDE) $(KBUILD_AFLAGS) -D__ASSEMBLY__ \
+ -DKERNEL_ENTRY=0x$(shell $(NM) $(objtree)/$(KBUILD_IMAGE) 2>/dev/null | grep " kernel_entry" | cut -f1 -d \ ) \
+ -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE)
+
+obj-y := $(obj)/head.o $(obj)/decompress.o $(obj)/dbg.o
+
+obj-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o
+
+OBJCOPYFLAGS_vmlinux.bin := $(OBJCOPYFLAGS) -O binary -R .comment -S
+$(obj)/vmlinux.bin: $(KBUILD_IMAGE)
+ $(call if_changed,objcopy)
+
+suffix_$(CONFIG_KERNEL_GZIP) = gz
+suffix_$(CONFIG_KERNEL_BZIP2) = bz2
+suffix_$(CONFIG_KERNEL_LZMA) = lzma
+tool_$(CONFIG_KERNEL_GZIP) = gzip
+tool_$(CONFIG_KERNEL_BZIP2) = bzip2
+tool_$(CONFIG_KERNEL_LZMA) = lzma
+$(obj)/vmlinux.$(suffix_y): $(obj)/vmlinux.bin
+ $(call if_changed,$(tool_y))
+
+$(obj)/piggy.o: $(obj)/vmlinux.$(suffix_y) $(obj)/dummy.o
+ $(Q)$(OBJCOPY) $(OBJCOPYFLAGS) \
+ --add-section=.image=$< \
+ --set-section-flags=.image=contents,alloc,load,readonly,data \
+ $(obj)/dummy.o $@
+
+LDFLAGS_vmlinuz := $(LDFLAGS) -Ttext $(VMLINUZ_LOAD_ADDRESS) -T
+vmlinuz: $(src)/ld.script $(obj-y) $(obj)/piggy.o
+ $(call if_changed,ld)
+ $(Q)$(OBJCOPY) $(OBJCOPYFLAGS) -R .comment -R .stab -R .stabstr -R .initrd -R .sysmap $@
+
+#
+# Some DECstations need all possible sections of an ECOFF executable
+#
+ifdef CONFIG_MACH_DECSTATION
+ E2EFLAGS = -a
+else
+ E2EFLAGS =
+endif
+
+# elf2ecoff can only handle 32bit image
+
+ifdef CONFIG_32BIT
+ VMLINUZ = vmlinuz
+else
+ VMLINUZ = vmlinuz.32
+endif
+
+vmlinuz.32: vmlinuz
+ $(Q)$(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@
+
+vmlinuz.ecoff: $(obj)/../elf2ecoff $(VMLINUZ)
+ $(Q)$(obj)/../elf2ecoff $(VMLINUZ) vmlinuz.ecoff $(E2EFLAGS)
+
+$(obj)/../elf2ecoff: $(src)/../elf2ecoff.c
+ $(Q)$(HOSTCC) -o $@ $^
+
+drop-sections = .reginfo .mdebug .comment .note .pdr .options .MIPS.options
+strip-flags = $(addprefix --remove-section=,$(drop-sections))
+
+OBJCOPYFLAGS_vmlinuz.bin := $(OBJCOPYFLAGS) -O binary $(strip-flags)
+vmlinuz.bin: vmlinuz
+ $(call if_changed,objcopy)
+
+OBJCOPYFLAGS_vmlinuz.srec := $(OBJCOPYFLAGS) -S -O srec $(strip-flags)
+vmlinuz.srec: vmlinuz
+ $(call if_changed,objcopy)
+
+clean:
+clean-files += *.o \
+ vmlinu*
diff --git a/arch/mips/boot/compressed/dbg.c b/arch/mips/boot/compressed/dbg.c
new file mode 100644
index 000000000000..ff4dc7a33a9f
--- /dev/null
+++ b/arch/mips/boot/compressed/dbg.c
@@ -0,0 +1,37 @@
+/*
+ * MIPS-specific debug support for pre-boot environment
+ *
+ * NOTE: putc() is board specific, if your board have a 16550 compatible uart,
+ * please select SYS_SUPPORTS_ZBOOT_UART16550 for your machine. othewise, you
+ * need to implement your own putc().
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+
+void __attribute__ ((weak)) putc(char c)
+{
+}
+
+void puts(const char *s)
+{
+ char c;
+ while ((c = *s++) != '\0') {
+ putc(c);
+ if (c == '\n')
+ putc('\r');
+ }
+}
+
+void puthex(unsigned long long val)
+{
+
+ unsigned char buf[10];
+ int i;
+ for (i = 7; i >= 0; i--) {
+ buf[i] = "0123456789ABCDEF"[val & 0x0F];
+ val >>= 4;
+ }
+ buf[8] = '\0';
+ puts(buf);
+}
diff --git a/arch/mips/boot/compressed/decompress.c b/arch/mips/boot/compressed/decompress.c
new file mode 100644
index 000000000000..67330c2f7318
--- /dev/null
+++ b/arch/mips/boot/compressed/decompress.c
@@ -0,0 +1,126 @@
+/*
+ * Misc. bootloader code for many machines.
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: Matt Porter <mporter@mvista.com> Derived from
+ * arch/ppc/boot/prep/misc.c
+ *
+ * Copyright (C) 2009 Lemote, Inc. & Institute of Computing Technology
+ * Author: Wu Zhangjin <wuzj@lemote.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/types.h>
+#include <linux/kernel.h>
+
+#include <asm/addrspace.h>
+
+/* These two variables specify the free mem region
+ * that can be used for temporary malloc area
+ */
+unsigned long free_mem_ptr;
+unsigned long free_mem_end_ptr;
+char *zimage_start;
+
+/* The linker tells us where the image is. */
+extern unsigned char __image_begin, __image_end;
+extern unsigned char __ramdisk_begin, __ramdisk_end;
+unsigned long initrd_size;
+
+/* debug interfaces */
+extern void puts(const char *s);
+extern void puthex(unsigned long long val);
+
+void error(char *x)
+{
+ puts("\n\n");
+ puts(x);
+ puts("\n\n -- System halted");
+
+ while (1)
+ ; /* Halt */
+}
+
+/* activate the code for pre-boot environment */
+#define STATIC static
+
+#ifdef CONFIG_KERNEL_GZIP
+void *memcpy(void *dest, const void *src, size_t n)
+{
+ int i;
+ const char *s = src;
+ char *d = dest;
+
+ for (i = 0; i < n; i++)
+ d[i] = s[i];
+ return dest;
+}
+#include "../../../../lib/decompress_inflate.c"
+#endif
+
+#ifdef CONFIG_KERNEL_BZIP2
+void *memset(void *s, int c, size_t n)
+{
+ int i;
+ char *ss = s;
+
+ for (i = 0; i < n; i++)
+ ss[i] = c;
+ return s;
+}
+#include "../../../../lib/decompress_bunzip2.c"
+#endif
+
+#ifdef CONFIG_KERNEL_LZMA
+#include "../../../../lib/decompress_unlzma.c"
+#endif
+
+void decompress_kernel(unsigned long boot_heap_start)
+{
+ int zimage_size;
+
+ /*
+ * We link ourself to an arbitrary low address. When we run, we
+ * relocate outself to that address. __image_beign points to
+ * the part of the image where the zImage is. -- Tom
+ */
+ zimage_start = (char *)(unsigned long)(&__image_begin);
+ zimage_size = (unsigned long)(&__image_end) -
+ (unsigned long)(&__image_begin);
+
+ /*
+ * The zImage and initrd will be between start and _end, so they've
+ * already been moved once. We're good to go now. -- Tom
+ */
+ puts("zimage at: ");
+ puthex((unsigned long)zimage_start);
+ puts(" ");
+ puthex((unsigned long)(zimage_size + zimage_start));
+ puts("\n");
+
+ if (initrd_size) {
+ puts("initrd at: ");
+ puthex((unsigned long)(&__ramdisk_begin));
+ puts(" ");
+ puthex((unsigned long)(&__ramdisk_end));
+ puts("\n");
+ }
+
+ /* this area are prepared for mallocing when decompressing */
+ free_mem_ptr = boot_heap_start;
+ free_mem_end_ptr = boot_heap_start + BOOT_HEAP_SIZE;
+
+ /* Display standard Linux/MIPS boot prompt for kernel args */
+ puts("Uncompressing Linux at load address ");
+ puthex(VMLINUX_LOAD_ADDRESS_ULL);
+ puts("\n");
+ /* Decompress the kernel with according algorithm */
+ decompress(zimage_start, zimage_size, 0, 0,
+ (void *)VMLINUX_LOAD_ADDRESS_ULL, 0, error);
+ /* FIXME: is there a need to flush cache here? */
+ puts("Now, booting the kernel...\n");
+}
diff --git a/arch/mips/boot/compressed/dummy.c b/arch/mips/boot/compressed/dummy.c
new file mode 100644
index 000000000000..31dbf45bf99c
--- /dev/null
+++ b/arch/mips/boot/compressed/dummy.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/arch/mips/boot/compressed/head.S b/arch/mips/boot/compressed/head.S
new file mode 100644
index 000000000000..e23f25eebac3
--- /dev/null
+++ b/arch/mips/boot/compressed/head.S
@@ -0,0 +1,55 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994, 1995 Waldorf Electronics
+ * Written by Ralf Baechle and Andreas Busse
+ * Copyright (C) 1995 - 1999 Ralf Baechle
+ * Copyright (C) 1996 Paul M. Antoine
+ * Modified for DECStation and hence R3000 support by Paul M. Antoine
+ * Further modifications by David S. Miller and Harald Koerfgen
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ */
+
+#include <asm/asm.h>
+#include <asm/regdef.h>
+
+ .set noreorder
+ .cprestore
+ LEAF(start)
+start:
+ /* Save boot rom start args */
+ move s0, a0
+ move s1, a1
+ move s2, a2
+ move s3, a3
+
+ /* Clear BSS */
+ PTR_LA a0, _edata
+ PTR_LA a2, _end
+1: sw zero, 0(a0)
+ bne a2, a0, 1b
+ addu a0, 4
+
+ PTR_LA a0, (.heap) /* heap address */
+ PTR_LA sp, (.stack + 8192) /* stack address */
+
+ PTR_LA ra, 2f
+ PTR_LA k0, decompress_kernel
+ jr k0
+ nop
+2:
+ move a0, s0
+ move a1, s1
+ move a2, s2
+ move a3, s3
+ PTR_LI k0, KERNEL_ENTRY
+ jr k0
+ nop
+3:
+ b 3b
+ END(start)
+
+ .comm .heap,BOOT_HEAP_SIZE,4
+ .comm .stack,4096*2,4
diff --git a/arch/mips/boot/compressed/ld.script b/arch/mips/boot/compressed/ld.script
new file mode 100644
index 000000000000..29e9f4c0d5d8
--- /dev/null
+++ b/arch/mips/boot/compressed/ld.script
@@ -0,0 +1,150 @@
+OUTPUT_ARCH(mips)
+ENTRY(start)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ .init : { *(.init) } =0
+ .text :
+ {
+ _ftext = . ;
+ *(.text)
+ *(.rodata)
+ *(.rodata1)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ } =0
+ .kstrtab : { *(.kstrtab) }
+
+ . = ALIGN(16); /* Exception table */
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ __start___dbe_table = .; /* Exception table for data bus errors */
+ __dbe_table : { *(__dbe_table) }
+ __stop___dbe_table = .;
+
+ __start___ksymtab = .; /* Kernel symbol table */
+ __ksymtab : { *(__ksymtab) }
+ __stop___ksymtab = .;
+
+ _etext = .;
+
+ . = ALIGN(8192);
+ .data.init_task : { *(.data.init_task) }
+
+ /* Startup code */
+ . = ALIGN(4096);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(16);
+ __setup_start = .;
+ .setup.init : { *(.setup.init) }
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : { *(.initcall.init) }
+ __initcall_end = .;
+ . = ALIGN(4096); /* Align double page for init_task_union */
+ __init_end = .;
+
+ . = ALIGN(4096);
+ .data.page_aligned : { *(.data.idt) }
+
+ . = ALIGN(32);
+ .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+ .fini : { *(.fini) } =0
+ .reginfo : { *(.reginfo) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. It would
+ be more correct to do this:
+ . = .;
+ The current expression does not correctly handle the case of a
+ text segment ending precisely at the end of a page; it causes the
+ data segment to skip a page. The above expression does not have
+ this problem, but it will currently (2/95) cause BFD to allocate
+ a single segment, combining both text and data, for this case.
+ This will prevent the text segment from being shared among
+ multiple executions of the program; I think that is more
+ important than losing a page of the virtual address space (note
+ that no actual memory is lost; the page which is skipped can not
+ be referenced). */
+ . = .;
+ .data :
+ {
+ _fdata = . ;
+ *(.data)
+
+ /* Put the compressed image here, so bss is on the end. */
+ __image_begin = .;
+ *(.image)
+ __image_end = .;
+ /* Align the initial ramdisk image (INITRD) on page boundaries. */
+ . = ALIGN(4096);
+ __ramdisk_begin = .;
+ *(.initrd)
+ __ramdisk_end = .;
+ . = ALIGN(4096);
+
+ CONSTRUCTORS
+ }
+ .data1 : { *(.data1) }
+ _gp = . + 0x8000;
+ .lit8 : { *(.lit8) }
+ .lit4 : { *(.lit4) }
+ .ctors : { *(.ctors) }
+ .dtors : { *(.dtors) }
+ .got : { *(.got.plt) *(.got) }
+ .dynamic : { *(.dynamic) }
+ /* We want the small data sections together, so single-instruction offsets
+ can access them all, and initialized data all before uninitialized, so
+ we can shorten the on-disk segment size. */
+ .sdata : { *(.sdata) }
+ . = ALIGN(4);
+ _edata = .;
+ PROVIDE (edata = .);
+
+ __bss_start = .;
+ _fbss = .;
+ .sbss : { *(.sbss) *(.scommon) }
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ . = ALIGN(4);
+ _end = . ;
+ PROVIDE (end = .);
+ }
+
+ /* Sections to be discarded */
+ /DISCARD/ :
+ {
+ *(.text.exit)
+ *(.data.exit)
+ *(.exitcall.exit)
+ }
+
+ /* This is the MIPS specific mdebug section. */
+ .mdebug : { *(.mdebug) }
+ /* These are needed for ELF backends which have not yet been
+ converted to the new style linker. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ /* DWARF debug sections.
+ Symbols in the .debug DWARF section are relative to the beginning of the
+ section so we begin .debug at 0. It's not clear yet what needs to happen
+ for the others. */
+ .debug 0 : { *(.debug) }
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ .line 0 : { *(.line) }
+ /* These must appear regardless of . */
+ .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
+ .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
+ .comment : { *(.comment) }
+ .note : { *(.note) }
+}
diff --git a/arch/mips/boot/compressed/uart-16550.c b/arch/mips/boot/compressed/uart-16550.c
new file mode 100644
index 000000000000..c9caaf4fbf60
--- /dev/null
+++ b/arch/mips/boot/compressed/uart-16550.c
@@ -0,0 +1,43 @@
+/*
+ * 16550 compatible uart based serial debug support for zboot
+ */
+
+#include <linux/types.h>
+#include <linux/serial_reg.h>
+#include <linux/init.h>
+
+#include <asm/addrspace.h>
+
+#if defined(CONFIG_MACH_LOONGSON) || defined(CONFIG_MIPS_MALTA)
+#define UART_BASE 0x1fd003f8
+#define PORT(offset) (CKSEG1ADDR(UART_BASE) + (offset))
+#endif
+
+#ifdef CONFIG_AR7
+#include <ar7.h>
+#define PORT(offset) (CKSEG1ADDR(AR7_REGS_UART0) + (4 * offset))
+#endif
+
+#ifndef PORT
+#error please define the serial port address for your own machine
+#endif
+
+static inline unsigned int serial_in(int offset)
+{
+ return *((char *)PORT(offset));
+}
+
+static inline void serial_out(int offset, int value)
+{
+ *((char *)PORT(offset)) = value;
+}
+
+void putc(char c)
+{
+ int timeout = 1024;
+
+ while (((serial_in(UART_LSR) & UART_LSR_THRE) == 0) && (timeout-- > 0))
+ ;
+
+ serial_out(UART_TX, c);
+}
diff --git a/arch/mips/fw/arc/cmdline.c b/arch/mips/fw/arc/cmdline.c
index 4ca4eef934a5..5c8603c85f20 100644
--- a/arch/mips/fw/arc/cmdline.c
+++ b/arch/mips/fw/arc/cmdline.c
@@ -16,11 +16,6 @@
#undef DEBUG_CMDLINE
-char * __init prom_getcmdline(void)
-{
- return arcs_cmdline;
-}
-
static char *ignored[] = {
"ConsoleIn=",
"ConsoleOut=",
diff --git a/arch/mips/include/asm/asm-offsets.h b/arch/mips/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/mips/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h
index f5dfaf6a1606..07d41157afb2 100644
--- a/arch/mips/include/asm/bootinfo.h
+++ b/arch/mips/include/asm/bootinfo.h
@@ -69,8 +69,6 @@
#define MACH_DEXXON_GDIUM2F10 5
#define MACH_LOONGSON_END 6
-#define CL_SIZE COMMAND_LINE_SIZE
-
extern char *system_type;
const char *get_system_type(void);
@@ -107,7 +105,7 @@ extern void free_init_pages(const char *what,
/*
* Initial kernel command line, usually setup by prom_init()
*/
-extern char arcs_cmdline[CL_SIZE];
+extern char arcs_cmdline[COMMAND_LINE_SIZE];
/*
* Registers a0, a1, a3 and a4 as passed to the kernel entry by firmware
diff --git a/arch/mips/include/asm/fcntl.h b/arch/mips/include/asm/fcntl.h
index 2a52333a062d..7c6681aa2ab8 100644
--- a/arch/mips/include/asm/fcntl.h
+++ b/arch/mips/include/asm/fcntl.h
@@ -10,7 +10,7 @@
#define O_APPEND 0x0008
-#define O_SYNC 0x0010
+#define O_DSYNC 0x0010 /* used to be O_SYNC, see below */
#define O_NONBLOCK 0x0080
#define O_CREAT 0x0100 /* not fcntl */
#define O_TRUNC 0x0200 /* not fcntl */
@@ -18,6 +18,21 @@
#define O_NOCTTY 0x0800 /* not fcntl */
#define FASYNC 0x1000 /* fcntl, for BSD compatibility */
#define O_LARGEFILE 0x2000 /* allow large file opens */
+/*
+ * Before Linux 2.6.32 only O_DSYNC semantics were implemented, but using
+ * the O_SYNC flag. We continue to use the existing numerical value
+ * for O_DSYNC semantics now, but using the correct symbolic name for it.
+ * This new value is used to request true Posix O_SYNC semantics. It is
+ * defined in this strange way to make sure applications compiled against
+ * new headers get at least O_DSYNC semantics on older kernels.
+ *
+ * This has the nice side-effect that we can simply test for O_DSYNC
+ * wherever we do not care if O_DSYNC or O_SYNC is used.
+ *
+ * Note: __O_SYNC must never be used directly.
+ */
+#define __O_SYNC 0x4000
+#define O_SYNC (__O_SYNC|O_DSYNC)
#define O_DIRECT 0x8000 /* direct disk access hint */
#define F_GETLK 14
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index 854e95f1b07c..9174285884de 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -130,6 +130,36 @@ static inline int au1xxx_cpu_needs_config_od(void)
return 0;
}
+#define ALCHEMY_CPU_UNKNOWN -1
+#define ALCHEMY_CPU_AU1000 0
+#define ALCHEMY_CPU_AU1500 1
+#define ALCHEMY_CPU_AU1100 2
+#define ALCHEMY_CPU_AU1550 3
+#define ALCHEMY_CPU_AU1200 4
+
+static inline int alchemy_get_cputype(void)
+{
+ switch (read_c0_prid() & 0xffff0000) {
+ case 0x00030000:
+ return ALCHEMY_CPU_AU1000;
+ break;
+ case 0x01030000:
+ return ALCHEMY_CPU_AU1500;
+ break;
+ case 0x02030000:
+ return ALCHEMY_CPU_AU1100;
+ break;
+ case 0x03030000:
+ return ALCHEMY_CPU_AU1550;
+ break;
+ case 0x04030000:
+ return ALCHEMY_CPU_AU1200;
+ break;
+ }
+
+ return ALCHEMY_CPU_UNKNOWN;
+}
+
/* arch/mips/au1000/common/clocks.c */
extern void set_au1x00_speed(unsigned int new_freq);
extern unsigned int get_au1x00_speed(void);
@@ -143,21 +173,6 @@ void au_sleep(void);
void save_au1xxx_intctl(void);
void restore_au1xxx_intctl(void);
-/*
- * Every board describes its IRQ mapping with this table.
- */
-struct au1xxx_irqmap {
- int im_irq;
- int im_type;
- int im_request;
-};
-
-/* core calls this function to let boards initialize other IRQ sources */
-void board_init_irq(void);
-
-/* boards call this to register additional (GPIO) interrupts */
-void au1xxx_setup_irqmap(struct au1xxx_irqmap *map, int count);
-
#endif /* !defined (_LANGUAGE_ASSEMBLY) */
/*
@@ -1739,6 +1754,20 @@ enum soc_au1200_ints {
#endif
+/*
+ * All Au1xx0 SOCs have a PCMCIA controller.
+ * We setup our 32-bit pseudo addresses to be equal to the
+ * 36-bit addr >> 4, to make it easier to check the address
+ * and fix it.
+ * The PCMCIA socket 0 physical attribute address is 0xF 4000 0000.
+ * The pseudo address we use is 0xF400 0000. Any address over
+ * 0xF400 0000 is a PCMCIA pseudo address.
+ */
+#define PCMCIA_IO_PSEUDO_PHYS (PCMCIA_IO_PHYS_ADDR >> 4)
+#define PCMCIA_ATTR_PSEUDO_PHYS (PCMCIA_ATTR_PHYS_ADDR >> 4)
+#define PCMCIA_MEM_PSEUDO_PHYS (PCMCIA_MEM_PHYS_ADDR >> 4)
+#define PCMCIA_PSEUDO_END (0xffffffff)
+
#ifndef _LANGUAGE_ASSEMBLY
typedef volatile struct {
/* 0x0000 */ u32 toytrim;
diff --git a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
index 06f68f43800a..c098b45a0360 100644
--- a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
+++ b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
@@ -338,8 +338,8 @@ u32 au1xxx_dbdma_set_devwidth(u32 chanid, int bits);
u32 au1xxx_dbdma_ring_alloc(u32 chanid, int entries);
/* Put buffers on source/destination descriptors. */
-u32 _au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes, u32 flags);
-u32 _au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes, u32 flags);
+u32 au1xxx_dbdma_put_source(u32 chanid, dma_addr_t buf, int nbytes, u32 flags);
+u32 au1xxx_dbdma_put_dest(u32 chanid, dma_addr_t buf, int nbytes, u32 flags);
/* Get a buffer from the destination descriptor. */
u32 au1xxx_dbdma_get_dest(u32 chanid, void **buf, int *nbytes);
@@ -362,25 +362,6 @@ void au1xxx_dbdma_suspend(void);
void au1xxx_dbdma_resume(void);
#endif
-
-/*
- * Some compatibilty macros -- needed to make changes to API
- * without breaking existing drivers.
- */
-#define au1xxx_dbdma_put_source(chanid, buf, nbytes) \
- _au1xxx_dbdma_put_source(chanid, buf, nbytes, DDMA_FLAGS_IE)
-#define au1xxx_dbdma_put_source_flags(chanid, buf, nbytes, flags) \
- _au1xxx_dbdma_put_source(chanid, buf, nbytes, flags)
-#define put_source_flags(chanid, buf, nbytes, flags) \
- au1xxx_dbdma_put_source_flags(chanid, buf, nbytes, flags)
-
-#define au1xxx_dbdma_put_dest(chanid, buf, nbytes) \
- _au1xxx_dbdma_put_dest(chanid, buf, nbytes, DDMA_FLAGS_IE)
-#define au1xxx_dbdma_put_dest_flags(chanid, buf, nbytes, flags) \
- _au1xxx_dbdma_put_dest(chanid, buf, nbytes, flags)
-#define put_dest_flags(chanid, buf, nbytes, flags) \
- au1xxx_dbdma_put_dest_flags(chanid, buf, nbytes, flags)
-
/*
* Flags for the put_source/put_dest functions.
*/
diff --git a/arch/mips/include/asm/mach-db1x00/bcsr.h b/arch/mips/include/asm/mach-db1x00/bcsr.h
new file mode 100644
index 000000000000..618d2de02ed3
--- /dev/null
+++ b/arch/mips/include/asm/mach-db1x00/bcsr.h
@@ -0,0 +1,238 @@
+/*
+ * bcsr.h -- Db1xxx/Pb1xxx Devboard CPLD registers ("BCSR") abstraction.
+ *
+ * All Alchemy development boards (except, of course, the weird PB1000)
+ * have a few registers in a CPLD with standardised layout; they mostly
+ * only differ in base address and bit meanings in the RESETS and BOARD
+ * registers.
+ *
+ * All data taken from the official AMD board documentation sheets.
+ */
+
+#ifndef _DB1XXX_BCSR_H_
+#define _DB1XXX_BCSR_H_
+
+
+/* BCSR base addresses on various boards. BCSR base 2 refers to the
+ * physical address of the first HEXLEDS register, which is usually
+ * a variable offset from the WHOAMI register.
+ */
+
+/* DB1000, DB1100, DB1500, PB1100, PB1500 */
+#define DB1000_BCSR_PHYS_ADDR 0x0E000000
+#define DB1000_BCSR_HEXLED_OFS 0x01000000
+
+#define DB1550_BCSR_PHYS_ADDR 0x0F000000
+#define DB1550_BCSR_HEXLED_OFS 0x00400000
+
+#define PB1550_BCSR_PHYS_ADDR 0x0F000000
+#define PB1550_BCSR_HEXLED_OFS 0x00800000
+
+#define DB1200_BCSR_PHYS_ADDR 0x19800000
+#define DB1200_BCSR_HEXLED_OFS 0x00400000
+
+#define PB1200_BCSR_PHYS_ADDR 0x0D800000
+#define PB1200_BCSR_HEXLED_OFS 0x00400000
+
+
+enum bcsr_id {
+ /* BCSR base 1 */
+ BCSR_WHOAMI = 0,
+ BCSR_STATUS,
+ BCSR_SWITCHES,
+ BCSR_RESETS,
+ BCSR_PCMCIA,
+ BCSR_BOARD,
+ BCSR_LEDS,
+ BCSR_SYSTEM,
+ /* Au1200/1300 based boards */
+ BCSR_INTCLR,
+ BCSR_INTSET,
+ BCSR_MASKCLR,
+ BCSR_MASKSET,
+ BCSR_SIGSTAT,
+ BCSR_INTSTAT,
+
+ /* BCSR base 2 */
+ BCSR_HEXLEDS,
+ BCSR_RSVD1,
+ BCSR_HEXCLEAR,
+
+ BCSR_CNT,
+};
+
+/* register offsets, valid for all Db1xxx/Pb1xxx boards */
+#define BCSR_REG_WHOAMI 0x00
+#define BCSR_REG_STATUS 0x04
+#define BCSR_REG_SWITCHES 0x08
+#define BCSR_REG_RESETS 0x0c
+#define BCSR_REG_PCMCIA 0x10
+#define BCSR_REG_BOARD 0x14
+#define BCSR_REG_LEDS 0x18
+#define BCSR_REG_SYSTEM 0x1c
+/* Au1200/Au1300 based boards: CPLD IRQ muxer */
+#define BCSR_REG_INTCLR 0x20
+#define BCSR_REG_INTSET 0x24
+#define BCSR_REG_MASKCLR 0x28
+#define BCSR_REG_MASKSET 0x2c
+#define BCSR_REG_SIGSTAT 0x30
+#define BCSR_REG_INTSTAT 0x34
+
+/* hexled control, offset from BCSR base 2 */
+#define BCSR_REG_HEXLEDS 0x00
+#define BCSR_REG_HEXCLEAR 0x08
+
+/*
+ * Register Bits and Pieces.
+ */
+#define BCSR_WHOAMI_DCID(x) ((x) & 0xf)
+#define BCSR_WHOAMI_CPLD(x) (((x) >> 4) & 0xf)
+#define BCSR_WHOAMI_BOARD(x) (((x) >> 8) & 0xf)
+
+/* register "WHOAMI" bits 11:8 identify the board */
+enum bcsr_whoami_boards {
+ BCSR_WHOAMI_PB1500 = 1,
+ BCSR_WHOAMI_PB1500R2,
+ BCSR_WHOAMI_PB1100,
+ BCSR_WHOAMI_DB1000,
+ BCSR_WHOAMI_DB1100,
+ BCSR_WHOAMI_DB1500,
+ BCSR_WHOAMI_DB1550,
+ BCSR_WHOAMI_PB1550_DDR,
+ BCSR_WHOAMI_PB1550 = BCSR_WHOAMI_PB1550_DDR,
+ BCSR_WHOAMI_PB1550_SDR,
+ BCSR_WHOAMI_PB1200_DDR1,
+ BCSR_WHOAMI_PB1200 = BCSR_WHOAMI_PB1200_DDR1,
+ BCSR_WHOAMI_PB1200_DDR2,
+ BCSR_WHOAMI_DB1200,
+};
+
+/* STATUS reg. Unless otherwise noted, they're valid on all boards.
+ * PB1200 = DB1200.
+ */
+#define BCSR_STATUS_PC0VS 0x0003
+#define BCSR_STATUS_PC1VS 0x000C
+#define BCSR_STATUS_PC0FI 0x0010
+#define BCSR_STATUS_PC1FI 0x0020
+#define BCSR_STATUS_PB1550_SWAPBOOT 0x0040
+#define BCSR_STATUS_SRAMWIDTH 0x0080
+#define BCSR_STATUS_FLASHBUSY 0x0100
+#define BCSR_STATUS_ROMBUSY 0x0400
+#define BCSR_STATUS_SD0WP 0x0400 /* DB1200 */
+#define BCSR_STATUS_SD1WP 0x0800
+#define BCSR_STATUS_USBOTGID 0x0800 /* PB/DB1550 */
+#define BCSR_STATUS_DB1000_SWAPBOOT 0x2000
+#define BCSR_STATUS_DB1200_SWAPBOOT 0x0040 /* DB1200 */
+#define BCSR_STATUS_IDECBLID 0x0200 /* DB1200 */
+#define BCSR_STATUS_DB1200_U0RXD 0x1000 /* DB1200 */
+#define BCSR_STATUS_DB1200_U1RXD 0x2000 /* DB1200 */
+#define BCSR_STATUS_FLASHDEN 0xC000
+#define BCSR_STATUS_DB1550_U0RXD 0x1000 /* DB1550 */
+#define BCSR_STATUS_DB1550_U3RXD 0x2000 /* DB1550 */
+#define BCSR_STATUS_PB1550_U0RXD 0x1000 /* PB1550 */
+#define BCSR_STATUS_PB1550_U1RXD 0x2000 /* PB1550 */
+#define BCSR_STATUS_PB1550_U3RXD 0x8000 /* PB1550 */
+
+
+/* DB/PB1000,1100,1500,1550 */
+#define BCSR_RESETS_PHY0 0x0001
+#define BCSR_RESETS_PHY1 0x0002
+#define BCSR_RESETS_DC 0x0004
+#define BCSR_RESETS_FIR_SEL 0x2000
+#define BCSR_RESETS_IRDA_MODE_MASK 0xC000
+#define BCSR_RESETS_IRDA_MODE_FULL 0x0000
+#define BCSR_RESETS_PB1550_WSCFSM 0x2000
+#define BCSR_RESETS_IRDA_MODE_OFF 0x4000
+#define BCSR_RESETS_IRDA_MODE_2_3 0x8000
+#define BCSR_RESETS_IRDA_MODE_1_3 0xC000
+#define BCSR_RESETS_DMAREQ 0x8000 /* PB1550 */
+
+#define BCSR_BOARD_PCIM66EN 0x0001
+#define BCSR_BOARD_SD0PWR 0x0040
+#define BCSR_BOARD_SD1PWR 0x0080
+#define BCSR_BOARD_PCIM33 0x0100
+#define BCSR_BOARD_PCIEXTARB 0x0200
+#define BCSR_BOARD_GPIO200RST 0x0400
+#define BCSR_BOARD_PCICLKOUT 0x0800
+#define BCSR_BOARD_PCICFG 0x1000
+#define BCSR_BOARD_SPISEL 0x4000 /* PB/DB1550 */
+#define BCSR_BOARD_SD0WP 0x4000 /* DB1100 */
+#define BCSR_BOARD_SD1WP 0x8000 /* DB1100 */
+
+
+/* DB/PB1200 */
+#define BCSR_RESETS_ETH 0x0001
+#define BCSR_RESETS_CAMERA 0x0002
+#define BCSR_RESETS_DC 0x0004
+#define BCSR_RESETS_IDE 0x0008
+#define BCSR_RESETS_TV 0x0010 /* DB1200 */
+/* Not resets but in the same register */
+#define BCSR_RESETS_PWMR1MUX 0x0800 /* DB1200 */
+#define BCSR_RESETS_PB1200_WSCFSM 0x0800 /* PB1200 */
+#define BCSR_RESETS_PSC0MUX 0x1000
+#define BCSR_RESETS_PSC1MUX 0x2000
+#define BCSR_RESETS_SPISEL 0x4000
+#define BCSR_RESETS_SD1MUX 0x8000 /* PB1200 */
+
+#define BCSR_BOARD_LCDVEE 0x0001
+#define BCSR_BOARD_LCDVDD 0x0002
+#define BCSR_BOARD_LCDBL 0x0004
+#define BCSR_BOARD_CAMSNAP 0x0010
+#define BCSR_BOARD_CAMPWR 0x0020
+#define BCSR_BOARD_SD0PWR 0x0040
+
+
+#define BCSR_SWITCHES_DIP 0x00FF
+#define BCSR_SWITCHES_DIP_1 0x0080
+#define BCSR_SWITCHES_DIP_2 0x0040
+#define BCSR_SWITCHES_DIP_3 0x0020
+#define BCSR_SWITCHES_DIP_4 0x0010
+#define BCSR_SWITCHES_DIP_5 0x0008
+#define BCSR_SWITCHES_DIP_6 0x0004
+#define BCSR_SWITCHES_DIP_7 0x0002
+#define BCSR_SWITCHES_DIP_8 0x0001
+#define BCSR_SWITCHES_ROTARY 0x0F00
+
+
+#define BCSR_PCMCIA_PC0VPP 0x0003
+#define BCSR_PCMCIA_PC0VCC 0x000C
+#define BCSR_PCMCIA_PC0DRVEN 0x0010
+#define BCSR_PCMCIA_PC0RST 0x0080
+#define BCSR_PCMCIA_PC1VPP 0x0300
+#define BCSR_PCMCIA_PC1VCC 0x0C00
+#define BCSR_PCMCIA_PC1DRVEN 0x1000
+#define BCSR_PCMCIA_PC1RST 0x8000
+
+
+#define BCSR_LEDS_DECIMALS 0x0003
+#define BCSR_LEDS_LED0 0x0100
+#define BCSR_LEDS_LED1 0x0200
+#define BCSR_LEDS_LED2 0x0400
+#define BCSR_LEDS_LED3 0x0800
+
+
+#define BCSR_SYSTEM_RESET 0x8000 /* clear to reset */
+#define BCSR_SYSTEM_PWROFF 0x4000 /* set to power off */
+#define BCSR_SYSTEM_VDDI 0x001F /* PB1xxx boards */
+
+
+
+
+/* initialize BCSR for a board. Provide the PHYSICAL addresses of both
+ * BCSR spaces.
+ */
+void __init bcsr_init(unsigned long bcsr1_phys, unsigned long bcsr2_phys);
+
+/* read a board register */
+unsigned short bcsr_read(enum bcsr_id reg);
+
+/* write to a board register */
+void bcsr_write(enum bcsr_id reg, unsigned short val);
+
+/* modify a register. clear bits set in 'clr', set bits set in 'set' */
+void bcsr_mod(enum bcsr_id reg, unsigned short clr, unsigned short set);
+
+/* install CPLD IRQ demuxer (DB1200/PB1200) */
+void __init bcsr_init_irq(int csc_start, int csc_end, int hook_irq);
+
+#endif
diff --git a/arch/mips/include/asm/mach-db1x00/db1200.h b/arch/mips/include/asm/mach-db1x00/db1200.h
index 27f26102b1bb..52b1d84a92c7 100644
--- a/arch/mips/include/asm/mach-db1x00/db1200.h
+++ b/arch/mips/include/asm/mach-db1x00/db1200.h
@@ -25,6 +25,7 @@
#define __ASM_DB1200_H
#include <linux/types.h>
+#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx_psc.h>
#define DBDMA_AC97_TX_CHAN DSCR_CMD0_PSC1_TX
@@ -45,113 +46,6 @@
#define AC97_PSC_BASE PSC1_BASE_ADDR
#define I2S_PSC_BASE PSC1_BASE_ADDR
-#define BCSR_KSEG1_ADDR 0xB9800000
-
-typedef volatile struct
-{
- /*00*/ u16 whoami;
- u16 reserved0;
- /*04*/ u16 status;
- u16 reserved1;
- /*08*/ u16 switches;
- u16 reserved2;
- /*0C*/ u16 resets;
- u16 reserved3;
-
- /*10*/ u16 pcmcia;
- u16 reserved4;
- /*14*/ u16 board;
- u16 reserved5;
- /*18*/ u16 disk_leds;
- u16 reserved6;
- /*1C*/ u16 system;
- u16 reserved7;
-
- /*20*/ u16 intclr;
- u16 reserved8;
- /*24*/ u16 intset;
- u16 reserved9;
- /*28*/ u16 intclr_mask;
- u16 reserved10;
- /*2C*/ u16 intset_mask;
- u16 reserved11;
-
- /*30*/ u16 sig_status;
- u16 reserved12;
- /*34*/ u16 int_status;
- u16 reserved13;
- /*38*/ u16 reserved14;
- u16 reserved15;
- /*3C*/ u16 reserved16;
- u16 reserved17;
-
-} BCSR;
-
-static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
-
-/*
- * Register bit definitions for the BCSRs
- */
-#define BCSR_WHOAMI_DCID 0x000F
-#define BCSR_WHOAMI_CPLD 0x00F0
-#define BCSR_WHOAMI_BOARD 0x0F00
-
-#define BCSR_STATUS_PCMCIA0VS 0x0003
-#define BCSR_STATUS_PCMCIA1VS 0x000C
-#define BCSR_STATUS_SWAPBOOT 0x0040
-#define BCSR_STATUS_FLASHBUSY 0x0100
-#define BCSR_STATUS_IDECBLID 0x0200
-#define BCSR_STATUS_SD0WP 0x0400
-#define BCSR_STATUS_U0RXD 0x1000
-#define BCSR_STATUS_U1RXD 0x2000
-
-#define BCSR_SWITCHES_OCTAL 0x00FF
-#define BCSR_SWITCHES_DIP_1 0x0080
-#define BCSR_SWITCHES_DIP_2 0x0040
-#define BCSR_SWITCHES_DIP_3 0x0020
-#define BCSR_SWITCHES_DIP_4 0x0010
-#define BCSR_SWITCHES_DIP_5 0x0008
-#define BCSR_SWITCHES_DIP_6 0x0004
-#define BCSR_SWITCHES_DIP_7 0x0002
-#define BCSR_SWITCHES_DIP_8 0x0001
-#define BCSR_SWITCHES_ROTARY 0x0F00
-
-#define BCSR_RESETS_ETH 0x0001
-#define BCSR_RESETS_CAMERA 0x0002
-#define BCSR_RESETS_DC 0x0004
-#define BCSR_RESETS_IDE 0x0008
-#define BCSR_RESETS_TV 0x0010
-/* Not resets but in the same register */
-#define BCSR_RESETS_PWMR1MUX 0x0800
-#define BCSR_RESETS_PCS0MUX 0x1000
-#define BCSR_RESETS_PCS1MUX 0x2000
-#define BCSR_RESETS_SPISEL 0x4000
-
-#define BCSR_PCMCIA_PC0VPP 0x0003
-#define BCSR_PCMCIA_PC0VCC 0x000C
-#define BCSR_PCMCIA_PC0DRVEN 0x0010
-#define BCSR_PCMCIA_PC0RST 0x0080
-#define BCSR_PCMCIA_PC1VPP 0x0300
-#define BCSR_PCMCIA_PC1VCC 0x0C00
-#define BCSR_PCMCIA_PC1DRVEN 0x1000
-#define BCSR_PCMCIA_PC1RST 0x8000
-
-#define BCSR_BOARD_LCDVEE 0x0001
-#define BCSR_BOARD_LCDVDD 0x0002
-#define BCSR_BOARD_LCDBL 0x0004
-#define BCSR_BOARD_CAMSNAP 0x0010
-#define BCSR_BOARD_CAMPWR 0x0020
-#define BCSR_BOARD_SD0PWR 0x0040
-
-#define BCSR_LEDS_DECIMALS 0x0003
-#define BCSR_LEDS_LED0 0x0100
-#define BCSR_LEDS_LED1 0x0200
-#define BCSR_LEDS_LED2 0x0400
-#define BCSR_LEDS_LED3 0x0800
-
-#define BCSR_SYSTEM_POWEROFF 0x4000
-#define BCSR_SYSTEM_RESET 0x8000
-
/* Bit positions for the different interrupt sources */
#define BCSR_INT_IDE 0x0001
#define BCSR_INT_ETH 0x0002
@@ -209,21 +103,6 @@ enum external_pb1200_ints {
DB1200_INT_END = DB1200_INT_BEGIN + 15,
};
-
-/*
- * DBAu1200 specific PCMCIA defines for drivers/pcmcia/au1000_db1x00.c
- */
-#define PCMCIA_MAX_SOCK 1
-#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
-
-/* VPP/VCC */
-#define SET_VCC_VPP(VCC, VPP, SLOT) \
- ((((VCC) << 2) | ((VPP) << 0)) << ((SLOT) * 8))
-
-#define BOARD_PC0_INT DB1200_PC0_INT
-#define BOARD_PC1_INT DB1200_PC1_INT
-#define BOARD_CARD_INSERTED(SOCKET) bcsr->sig_status & (1 << (8 + (2 * SOCKET)))
-
/* NAND chip select */
#define NAND_CS 1
diff --git a/arch/mips/include/asm/mach-db1x00/db1x00.h b/arch/mips/include/asm/mach-db1x00/db1x00.h
index 1a515b8c870f..a919dac525a1 100644
--- a/arch/mips/include/asm/mach-db1x00/db1x00.h
+++ b/arch/mips/include/asm/mach-db1x00/db1x00.h
@@ -41,111 +41,11 @@
#define SMBUS_PSC_BASE PSC2_BASE_ADDR
#define I2S_PSC_BASE PSC3_BASE_ADDR
-#define BCSR_KSEG1_ADDR 0xAF000000
#define NAND_PHYS_ADDR 0x20000000
-#else
-#define BCSR_KSEG1_ADDR 0xAE000000
#endif
/*
- * Overlay data structure of the DBAu1x00 board registers.
- * Registers are located at physical 0E0000xx, KSEG1 0xAE0000xx.
- */
-typedef volatile struct
-{
- /*00*/ unsigned short whoami;
- unsigned short reserved0;
- /*04*/ unsigned short status;
- unsigned short reserved1;
- /*08*/ unsigned short switches;
- unsigned short reserved2;
- /*0C*/ unsigned short resets;
- unsigned short reserved3;
- /*10*/ unsigned short pcmcia;
- unsigned short reserved4;
- /*14*/ unsigned short specific;
- unsigned short reserved5;
- /*18*/ unsigned short leds;
- unsigned short reserved6;
- /*1C*/ unsigned short swreset;
- unsigned short reserved7;
-
-} BCSR;
-
-
-/*
- * Register/mask bit definitions for the BCSRs
- */
-#define BCSR_WHOAMI_DCID 0x000F
-#define BCSR_WHOAMI_CPLD 0x00F0
-#define BCSR_WHOAMI_BOARD 0x0F00
-
-#define BCSR_STATUS_PC0VS 0x0003
-#define BCSR_STATUS_PC1VS 0x000C
-#define BCSR_STATUS_PC0FI 0x0010
-#define BCSR_STATUS_PC1FI 0x0020
-#define BCSR_STATUS_FLASHBUSY 0x0100
-#define BCSR_STATUS_ROMBUSY 0x0400
-#define BCSR_STATUS_SWAPBOOT 0x2000
-#define BCSR_STATUS_FLASHDEN 0xC000
-
-#define BCSR_SWITCHES_DIP 0x00FF
-#define BCSR_SWITCHES_DIP_1 0x0080
-#define BCSR_SWITCHES_DIP_2 0x0040
-#define BCSR_SWITCHES_DIP_3 0x0020
-#define BCSR_SWITCHES_DIP_4 0x0010
-#define BCSR_SWITCHES_DIP_5 0x0008
-#define BCSR_SWITCHES_DIP_6 0x0004
-#define BCSR_SWITCHES_DIP_7 0x0002
-#define BCSR_SWITCHES_DIP_8 0x0001
-#define BCSR_SWITCHES_ROTARY 0x0F00
-
-#define BCSR_RESETS_PHY0 0x0001
-#define BCSR_RESETS_PHY1 0x0002
-#define BCSR_RESETS_DC 0x0004
-#define BCSR_RESETS_FIR_SEL 0x2000
-#define BCSR_RESETS_IRDA_MODE_MASK 0xC000
-#define BCSR_RESETS_IRDA_MODE_FULL 0x0000
-#define BCSR_RESETS_IRDA_MODE_OFF 0x4000
-#define BCSR_RESETS_IRDA_MODE_2_3 0x8000
-#define BCSR_RESETS_IRDA_MODE_1_3 0xC000
-
-#define BCSR_PCMCIA_PC0VPP 0x0003
-#define BCSR_PCMCIA_PC0VCC 0x000C
-#define BCSR_PCMCIA_PC0DRVEN 0x0010
-#define BCSR_PCMCIA_PC0RST 0x0080
-#define BCSR_PCMCIA_PC1VPP 0x0300
-#define BCSR_PCMCIA_PC1VCC 0x0C00
-#define BCSR_PCMCIA_PC1DRVEN 0x1000
-#define BCSR_PCMCIA_PC1RST 0x8000
-
-#define BCSR_BOARD_PCIM66EN 0x0001
-#define BCSR_BOARD_SD0_PWR 0x0040
-#define BCSR_BOARD_SD1_PWR 0x0080
-#define BCSR_BOARD_PCIM33 0x0100
-#define BCSR_BOARD_GPIO200RST 0x0400
-#define BCSR_BOARD_PCICFG 0x1000
-#define BCSR_BOARD_SD0_WP 0x4000
-#define BCSR_BOARD_SD1_WP 0x8000
-
-#define BCSR_LEDS_DECIMALS 0x0003
-#define BCSR_LEDS_LED0 0x0100
-#define BCSR_LEDS_LED1 0x0200
-#define BCSR_LEDS_LED2 0x0400
-#define BCSR_LEDS_LED3 0x0800
-
-#define BCSR_SWRESET_RESET 0x0080
-
-/* PCMCIA DBAu1x00 specific defines */
-#define PCMCIA_MAX_SOCK 1
-#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
-
-/* VPP/VCC */
-#define SET_VCC_VPP(VCC, VPP, SLOT)\
- ((((VCC) << 2) | ((VPP) << 0)) << ((SLOT) * 8))
-
-/*
* NAND defines
*
* Timing values as described in databook, * ns value stripped of the
diff --git a/arch/mips/include/asm/mach-pb1x00/pb1100.h b/arch/mips/include/asm/mach-pb1x00/pb1100.h
deleted file mode 100644
index b1a60f1cbd02..000000000000
--- a/arch/mips/include/asm/mach-pb1x00/pb1100.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Alchemy Semi Pb1100 Referrence Board
- *
- * Copyright 2001, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.com>
- *
- * ########################################################################
- *
- * This program is free software; you can distribute it and/or modify it
- * under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * ########################################################################
- *
- *
- */
-#ifndef __ASM_PB1100_H
-#define __ASM_PB1100_H
-
-#define PB1100_IDENT 0xAE000000
-#define BOARD_STATUS_REG 0xAE000004
-# define PB1100_ROM_SEL (1 << 15)
-# define PB1100_ROM_SIZ (1 << 14)
-# define PB1100_SWAP_BOOT (1 << 13)
-# define PB1100_FLASH_WP (1 << 12)
-# define PB1100_ROM_H_STS (1 << 11)
-# define PB1100_ROM_L_STS (1 << 10)
-# define PB1100_FLASH_H_STS (1 << 9)
-# define PB1100_FLASH_L_STS (1 << 8)
-# define PB1100_SRAM_SIZ (1 << 7)
-# define PB1100_TSC_BUSY (1 << 6)
-# define PB1100_PCMCIA_VS_MASK (3 << 4)
-# define PB1100_RS232_CD (1 << 3)
-# define PB1100_RS232_CTS (1 << 2)
-# define PB1100_RS232_DSR (1 << 1)
-# define PB1100_RS232_RI (1 << 0)
-
-#define PB1100_IRDA_RS232 0xAE00000C
-# define PB1100_IRDA_FULL (0 << 14) /* full power */
-# define PB1100_IRDA_SHUTDOWN (1 << 14)
-# define PB1100_IRDA_TT (2 << 14) /* 2/3 power */
-# define PB1100_IRDA_OT (3 << 14) /* 1/3 power */
-# define PB1100_IRDA_FIR (1 << 13)
-
-#define PCMCIA_BOARD_REG 0xAE000010
-# define PB1100_SD_WP1_RO (1 << 15) /* read only */
-# define PB1100_SD_WP0_RO (1 << 14) /* read only */
-# define PB1100_SD_PWR1 (1 << 11) /* applies power to SD1 */
-# define PB1100_SD_PWR0 (1 << 10) /* applies power to SD0 */
-# define PB1100_SEL_SD_CONN1 (1 << 9)
-# define PB1100_SEL_SD_CONN0 (1 << 8)
-# define PC_DEASSERT_RST (1 << 7)
-# define PC_DRV_EN (1 << 4)
-
-#define PB1100_G_CONTROL 0xAE000014 /* graphics control */
-
-#define PB1100_RST_VDDI 0xAE00001C
-# define PB1100_SOFT_RESET (1 << 15) /* clear to reset the board */
-# define PB1100_VDDI_MASK 0x1F
-
-#define PB1100_LEDS 0xAE000018
-
-/*
- * 11:8 is 4 discreet LEDs. Clearing a bit illuminates the LED.
- * 7:0 is the LED Display's decimal points.
- */
-#define PB1100_HEX_LED 0xAE000018
-
-/* PCMCIA Pb1100 specific defines */
-#define PCMCIA_MAX_SOCK 0
-#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
-
-/* VPP/VCC */
-#define SET_VCC_VPP(VCC, VPP) (((VCC) << 2) | ((VPP) << 0))
-
-#endif /* __ASM_PB1100_H */
diff --git a/arch/mips/include/asm/mach-pb1x00/pb1200.h b/arch/mips/include/asm/mach-pb1x00/pb1200.h
index c8618df88cb5..962eb55dc880 100644
--- a/arch/mips/include/asm/mach-pb1x00/pb1200.h
+++ b/arch/mips/include/asm/mach-pb1x00/pb1200.h
@@ -25,6 +25,7 @@
#define __ASM_PB1200_H
#include <linux/types.h>
+#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx_psc.h>
#define DBDMA_AC97_TX_CHAN DSCR_CMD0_PSC1_TX
@@ -43,113 +44,8 @@
* Refer to board documentation.
*/
#define AC97_PSC_BASE PSC1_BASE_ADDR
-#define I2S_PSC_BASE PSC1_BASE_ADDR
+#define I2S_PSC_BASE PSC1_BASE_ADDR
-#define BCSR_KSEG1_ADDR 0xAD800000
-
-typedef volatile struct
-{
- /*00*/ u16 whoami;
- u16 reserved0;
- /*04*/ u16 status;
- u16 reserved1;
- /*08*/ u16 switches;
- u16 reserved2;
- /*0C*/ u16 resets;
- u16 reserved3;
-
- /*10*/ u16 pcmcia;
- u16 reserved4;
- /*14*/ u16 board;
- u16 reserved5;
- /*18*/ u16 disk_leds;
- u16 reserved6;
- /*1C*/ u16 system;
- u16 reserved7;
-
- /*20*/ u16 intclr;
- u16 reserved8;
- /*24*/ u16 intset;
- u16 reserved9;
- /*28*/ u16 intclr_mask;
- u16 reserved10;
- /*2C*/ u16 intset_mask;
- u16 reserved11;
-
- /*30*/ u16 sig_status;
- u16 reserved12;
- /*34*/ u16 int_status;
- u16 reserved13;
- /*38*/ u16 reserved14;
- u16 reserved15;
- /*3C*/ u16 reserved16;
- u16 reserved17;
-
-} BCSR;
-
-static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
-
-/*
- * Register bit definitions for the BCSRs
- */
-#define BCSR_WHOAMI_DCID 0x000F
-#define BCSR_WHOAMI_CPLD 0x00F0
-#define BCSR_WHOAMI_BOARD 0x0F00
-
-#define BCSR_STATUS_PCMCIA0VS 0x0003
-#define BCSR_STATUS_PCMCIA1VS 0x000C
-#define BCSR_STATUS_SWAPBOOT 0x0040
-#define BCSR_STATUS_FLASHBUSY 0x0100
-#define BCSR_STATUS_IDECBLID 0x0200
-#define BCSR_STATUS_SD0WP 0x0400
-#define BCSR_STATUS_SD1WP 0x0800
-#define BCSR_STATUS_U0RXD 0x1000
-#define BCSR_STATUS_U1RXD 0x2000
-
-#define BCSR_SWITCHES_OCTAL 0x00FF
-#define BCSR_SWITCHES_DIP_1 0x0080
-#define BCSR_SWITCHES_DIP_2 0x0040
-#define BCSR_SWITCHES_DIP_3 0x0020
-#define BCSR_SWITCHES_DIP_4 0x0010
-#define BCSR_SWITCHES_DIP_5 0x0008
-#define BCSR_SWITCHES_DIP_6 0x0004
-#define BCSR_SWITCHES_DIP_7 0x0002
-#define BCSR_SWITCHES_DIP_8 0x0001
-#define BCSR_SWITCHES_ROTARY 0x0F00
-
-#define BCSR_RESETS_ETH 0x0001
-#define BCSR_RESETS_CAMERA 0x0002
-#define BCSR_RESETS_DC 0x0004
-#define BCSR_RESETS_IDE 0x0008
-/* not resets but in the same register */
-#define BCSR_RESETS_WSCFSM 0x0800
-#define BCSR_RESETS_PCS0MUX 0x1000
-#define BCSR_RESETS_PCS1MUX 0x2000
-#define BCSR_RESETS_SPISEL 0x4000
-#define BCSR_RESETS_SD1MUX 0x8000
-
-#define BCSR_PCMCIA_PC0VPP 0x0003
-#define BCSR_PCMCIA_PC0VCC 0x000C
-#define BCSR_PCMCIA_PC0DRVEN 0x0010
-#define BCSR_PCMCIA_PC0RST 0x0080
-#define BCSR_PCMCIA_PC1VPP 0x0300
-#define BCSR_PCMCIA_PC1VCC 0x0C00
-#define BCSR_PCMCIA_PC1DRVEN 0x1000
-#define BCSR_PCMCIA_PC1RST 0x8000
-
-#define BCSR_BOARD_LCDVEE 0x0001
-#define BCSR_BOARD_LCDVDD 0x0002
-#define BCSR_BOARD_LCDBL 0x0004
-#define BCSR_BOARD_CAMSNAP 0x0010
-#define BCSR_BOARD_CAMPWR 0x0020
-#define BCSR_BOARD_SD0PWR 0x0040
-#define BCSR_BOARD_SD1PWR 0x0080
-
-#define BCSR_LEDS_DECIMALS 0x00FF
-#define BCSR_LEDS_LED0 0x0100
-#define BCSR_LEDS_LED1 0x0200
-#define BCSR_LEDS_LED2 0x0400
-#define BCSR_LEDS_LED3 0x0800
#define BCSR_SYSTEM_VDDI 0x001F
#define BCSR_SYSTEM_POWEROFF 0x4000
@@ -239,20 +135,6 @@ enum external_pb1200_ints {
PB1200_INT_END = PB1200_INT_BEGIN + 15
};
-/*
- * Pb1200 specific PCMCIA defines for drivers/pcmcia/au1000_db1x00.c
- */
-#define PCMCIA_MAX_SOCK 1
-#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
-
-/* VPP/VCC */
-#define SET_VCC_VPP(VCC, VPP, SLOT) \
- ((((VCC) << 2) | ((VPP) << 0)) << ((SLOT) * 8))
-
-#define BOARD_PC0_INT PB1200_PC0_INT
-#define BOARD_PC1_INT PB1200_PC1_INT
-#define BOARD_CARD_INSERTED(SOCKET) bcsr->sig_status & (1 << (8 + (2 * SOCKET)))
-
/* NAND chip select */
#define NAND_CS 1
diff --git a/arch/mips/include/asm/mach-pb1x00/pb1500.h b/arch/mips/include/asm/mach-pb1x00/pb1500.h
deleted file mode 100644
index da51a2eb7b82..000000000000
--- a/arch/mips/include/asm/mach-pb1x00/pb1500.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Alchemy Semi Pb1500 Referrence Board
- *
- * Copyright 2001, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.com>
- *
- * ########################################################################
- *
- * This program is free software; you can distribute it and/or modify it
- * under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * ########################################################################
- *
- *
- */
-#ifndef __ASM_PB1500_H
-#define __ASM_PB1500_H
-
-#define IDENT_BOARD_REG 0xAE000000
-#define BOARD_STATUS_REG 0xAE000004
-#define PCI_BOARD_REG 0xAE000010
-#define PCMCIA_BOARD_REG 0xAE000010
-# define PC_DEASSERT_RST 0x80
-# define PC_DRV_EN 0x10
-#define PB1500_G_CONTROL 0xAE000014
-#define PB1500_RST_VDDI 0xAE00001C
-#define PB1500_LEDS 0xAE000018
-
-#define PB1500_HEX_LED 0xAF000004
-#define PB1500_HEX_LED_BLANK 0xAF000008
-
-/* PCMCIA Pb1500 specific defines */
-#define PCMCIA_MAX_SOCK 0
-#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
-
-/* VPP/VCC */
-#define SET_VCC_VPP(VCC, VPP) (((VCC) << 2) | ((VPP) << 0))
-
-#endif /* __ASM_PB1500_H */
diff --git a/arch/mips/include/asm/mach-pb1x00/pb1550.h b/arch/mips/include/asm/mach-pb1x00/pb1550.h
index 6704a11497db..58796410bd6e 100644
--- a/arch/mips/include/asm/mach-pb1x00/pb1550.h
+++ b/arch/mips/include/asm/mach-pb1x00/pb1550.h
@@ -40,102 +40,6 @@
#define SMBUS_PSC_BASE PSC2_BASE_ADDR
#define I2S_PSC_BASE PSC3_BASE_ADDR
-#define BCSR_PHYS_ADDR 0xAF000000
-
-typedef volatile struct
-{
- /*00*/ u16 whoami;
- u16 reserved0;
- /*04*/ u16 status;
- u16 reserved1;
- /*08*/ u16 switches;
- u16 reserved2;
- /*0C*/ u16 resets;
- u16 reserved3;
- /*10*/ u16 pcmcia;
- u16 reserved4;
- /*14*/ u16 pci;
- u16 reserved5;
- /*18*/ u16 leds;
- u16 reserved6;
- /*1C*/ u16 system;
- u16 reserved7;
-
-} BCSR;
-
-static BCSR * const bcsr = (BCSR *)BCSR_PHYS_ADDR;
-
-/*
- * Register bit definitions for the BCSRs
- */
-#define BCSR_WHOAMI_DCID 0x000F
-#define BCSR_WHOAMI_CPLD 0x00F0
-#define BCSR_WHOAMI_BOARD 0x0F00
-
-#define BCSR_STATUS_PCMCIA0VS 0x0003
-#define BCSR_STATUS_PCMCIA1VS 0x000C
-#define BCSR_STATUS_PCMCIA0FI 0x0010
-#define BCSR_STATUS_PCMCIA1FI 0x0020
-#define BCSR_STATUS_SWAPBOOT 0x0040
-#define BCSR_STATUS_SRAMWIDTH 0x0080
-#define BCSR_STATUS_FLASHBUSY 0x0100
-#define BCSR_STATUS_ROMBUSY 0x0200
-#define BCSR_STATUS_USBOTGID 0x0800
-#define BCSR_STATUS_U0RXD 0x1000
-#define BCSR_STATUS_U1RXD 0x2000
-#define BCSR_STATUS_U3RXD 0x8000
-
-#define BCSR_SWITCHES_OCTAL 0x00FF
-#define BCSR_SWITCHES_DIP_1 0x0080
-#define BCSR_SWITCHES_DIP_2 0x0040
-#define BCSR_SWITCHES_DIP_3 0x0020
-#define BCSR_SWITCHES_DIP_4 0x0010
-#define BCSR_SWITCHES_DIP_5 0x0008
-#define BCSR_SWITCHES_DIP_6 0x0004
-#define BCSR_SWITCHES_DIP_7 0x0002
-#define BCSR_SWITCHES_DIP_8 0x0001
-#define BCSR_SWITCHES_ROTARY 0x0F00
-
-#define BCSR_RESETS_PHY0 0x0001
-#define BCSR_RESETS_PHY1 0x0002
-#define BCSR_RESETS_DC 0x0004
-#define BCSR_RESETS_WSC 0x2000
-#define BCSR_RESETS_SPISEL 0x4000
-#define BCSR_RESETS_DMAREQ 0x8000
-
-#define BCSR_PCMCIA_PC0VPP 0x0003
-#define BCSR_PCMCIA_PC0VCC 0x000C
-#define BCSR_PCMCIA_PC0DRVEN 0x0010
-#define BCSR_PCMCIA_PC0RST 0x0080
-#define BCSR_PCMCIA_PC1VPP 0x0300
-#define BCSR_PCMCIA_PC1VCC 0x0C00
-#define BCSR_PCMCIA_PC1DRVEN 0x1000
-#define BCSR_PCMCIA_PC1RST 0x8000
-
-#define BCSR_PCI_M66EN 0x0001
-#define BCSR_PCI_M33 0x0100
-#define BCSR_PCI_EXTERNARB 0x0200
-#define BCSR_PCI_GPIO200RST 0x0400
-#define BCSR_PCI_CLKOUT 0x0800
-#define BCSR_PCI_CFGHOST 0x1000
-
-#define BCSR_LEDS_DECIMALS 0x00FF
-#define BCSR_LEDS_LED0 0x0100
-#define BCSR_LEDS_LED1 0x0200
-#define BCSR_LEDS_LED2 0x0400
-#define BCSR_LEDS_LED3 0x0800
-
-#define BCSR_SYSTEM_VDDI 0x001F
-#define BCSR_SYSTEM_POWEROFF 0x4000
-#define BCSR_SYSTEM_RESET 0x8000
-
-#define PCMCIA_MAX_SOCK 1
-#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
-
-/* VPP/VCC */
-#define SET_VCC_VPP(VCC, VPP, SLOT) \
- ((((VCC) << 2) | ((VPP) << 0)) << ((SLOT) * 8))
-
#if defined(CONFIG_MTD_PB1550_BOOT) && defined(CONFIG_MTD_PB1550_USER)
#define PB1550_BOTH_BANKS
#elif defined(CONFIG_MTD_PB1550_BOOT) && !defined(CONFIG_MTD_PB1550_USER)
diff --git a/arch/mips/include/asm/sgialib.h b/arch/mips/include/asm/sgialib.h
index bfce5c786f1c..63741ca1e422 100644
--- a/arch/mips/include/asm/sgialib.h
+++ b/arch/mips/include/asm/sgialib.h
@@ -85,8 +85,7 @@ extern void prom_identify_arch(void);
extern PCHAR ArcGetEnvironmentVariable(PCHAR name);
extern LONG ArcSetEnvironmentVariable(PCHAR name, PCHAR value);
-/* ARCS command line acquisition and parsing. */
-extern char *prom_getcmdline(void);
+/* ARCS command line parsing. */
extern void prom_init_cmdline(void);
/* Acquiring info about the current time, etc. */
diff --git a/arch/mips/include/asm/socket.h b/arch/mips/include/asm/socket.h
index ae05accd9fe4..9de5190f2487 100644
--- a/arch/mips/include/asm/socket.h
+++ b/arch/mips/include/asm/socket.h
@@ -80,6 +80,8 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */
#define SO_TIMESTAMPING 37
#define SCM_TIMESTAMPING SO_TIMESTAMPING
+#define SO_RXQ_OVFL 40
+
#ifdef __KERNEL__
/** sock_type - Socket types
diff --git a/arch/mips/include/asm/stackframe.h b/arch/mips/include/asm/stackframe.h
index db0fa7b5aeaf..dd7e220e087b 100644
--- a/arch/mips/include/asm/stackframe.h
+++ b/arch/mips/include/asm/stackframe.h
@@ -51,9 +51,6 @@
LONG_S v1, PT_ACX(sp)
#else
mfhi v1
- LONG_S v1, PT_HI(sp)
- mflo v1
- LONG_S v1, PT_LO(sp)
#endif
#ifdef CONFIG_32BIT
LONG_S $8, PT_R8(sp)
@@ -62,10 +59,17 @@
LONG_S $10, PT_R10(sp)
LONG_S $11, PT_R11(sp)
LONG_S $12, PT_R12(sp)
+#ifndef CONFIG_CPU_HAS_SMARTMIPS
+ LONG_S v1, PT_HI(sp)
+ mflo v1
+#endif
LONG_S $13, PT_R13(sp)
LONG_S $14, PT_R14(sp)
LONG_S $15, PT_R15(sp)
LONG_S $24, PT_R24(sp)
+#ifndef CONFIG_CPU_HAS_SMARTMIPS
+ LONG_S v1, PT_LO(sp)
+#endif
.endm
.macro SAVE_STATIC
@@ -166,7 +170,6 @@
LONG_S $0, PT_R0(sp)
mfc0 v1, CP0_STATUS
LONG_S $2, PT_R2(sp)
- LONG_S v1, PT_STATUS(sp)
#ifdef CONFIG_MIPS_MT_SMTC
/*
* Ideally, these instructions would be shuffled in
@@ -178,20 +181,21 @@
LONG_S v1, PT_TCSTATUS(sp)
#endif /* CONFIG_MIPS_MT_SMTC */
LONG_S $4, PT_R4(sp)
- mfc0 v1, CP0_CAUSE
LONG_S $5, PT_R5(sp)
- LONG_S v1, PT_CAUSE(sp)
+ LONG_S v1, PT_STATUS(sp)
+ mfc0 v1, CP0_CAUSE
LONG_S $6, PT_R6(sp)
- MFC0 v1, CP0_EPC
LONG_S $7, PT_R7(sp)
+ LONG_S v1, PT_CAUSE(sp)
+ MFC0 v1, CP0_EPC
#ifdef CONFIG_64BIT
LONG_S $8, PT_R8(sp)
LONG_S $9, PT_R9(sp)
#endif
- LONG_S v1, PT_EPC(sp)
LONG_S $25, PT_R25(sp)
LONG_S $28, PT_R28(sp)
LONG_S $31, PT_R31(sp)
+ LONG_S v1, PT_EPC(sp)
ori $28, sp, _THREAD_MASK
xori $28, _THREAD_MASK
#ifdef CONFIG_CPU_CAVIUM_OCTEON
diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c
index ad4e017ed2f3..80e2ba694bab 100644
--- a/arch/mips/kernel/kspd.c
+++ b/arch/mips/kernel/kspd.c
@@ -82,6 +82,7 @@ static int sp_stopping;
#define MTSP_O_SHLOCK 0x0010
#define MTSP_O_EXLOCK 0x0020
#define MTSP_O_ASYNC 0x0040
+/* XXX: check which of these is actually O_SYNC vs O_DSYNC */
#define MTSP_O_FSYNC O_SYNC
#define MTSP_O_NOFOLLOW 0x0100
#define MTSP_O_SYNC 0x0080
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index fd2a9bb620d6..17202bbe843f 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -583,6 +583,7 @@ einval: li v0, -ENOSYS
sys sys_rt_tgsigqueueinfo 4
sys sys_perf_event_open 5
sys sys_accept4 4
+ sys sys_recvmmsg 5
.endm
/* We pre-compute the number of _instruction_ bytes needed to
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index 18bf7f32c5e4..a8a6c596eb04 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -420,4 +420,5 @@ sys_call_table:
PTR sys_rt_tgsigqueueinfo
PTR sys_perf_event_open
PTR sys_accept4
+ PTR sys_recvmmsg
.size sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 6ebc07976694..5154e64f7cfe 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -418,4 +418,5 @@ EXPORT(sysn32_call_table)
PTR compat_sys_rt_tgsigqueueinfo /* 5295 */
PTR sys_perf_event_open
PTR sys_accept4
+ PTR compat_sys_recvmmsg
.size sysn32_call_table,.-sysn32_call_table
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 9bbf9775e0bd..d0eff53d7cb9 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -538,4 +538,5 @@ sys_call_table:
PTR compat_sys_rt_tgsigqueueinfo
PTR sys_perf_event_open
PTR sys_accept4
+ PTR compat_sys_recvmmsg
.size sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 2b290d70083e..fd138c9b33ef 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -58,8 +58,8 @@ EXPORT_SYMBOL(mips_machtype);
struct boot_mem_map boot_mem_map;
-static char command_line[CL_SIZE];
- char arcs_cmdline[CL_SIZE]=CONFIG_CMDLINE;
+static char command_line[COMMAND_LINE_SIZE];
+ char arcs_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE;
/*
* mips_io_port_base is the begin of the address space to which x86 style
diff --git a/arch/mips/lasat/prom.c b/arch/mips/lasat/prom.c
index 6acc6cb85f0a..20fde19a5fbf 100644
--- a/arch/mips/lasat/prom.c
+++ b/arch/mips/lasat/prom.c
@@ -100,8 +100,8 @@ void __init prom_init(void)
/* Get the command line */
if (argc > 0) {
- strncpy(arcs_cmdline, argv[0], CL_SIZE-1);
- arcs_cmdline[CL_SIZE-1] = '\0';
+ strncpy(arcs_cmdline, argv[0], COMMAND_LINE_SIZE-1);
+ arcs_cmdline[COMMAND_LINE_SIZE-1] = '\0';
}
/* Set the I/O base address */
diff --git a/arch/mips/loongson/common/mem.c b/arch/mips/loongson/common/mem.c
index 7c92f79b6480..e94ef158f980 100644
--- a/arch/mips/loongson/common/mem.c
+++ b/arch/mips/loongson/common/mem.c
@@ -26,7 +26,7 @@ void __init prom_init_memory(void)
/* override of arch/mips/mm/cache.c: __uncached_access */
int __uncached_access(struct file *file, unsigned long addr)
{
- if (file->f_flags & O_SYNC)
+ if (file->f_flags & O_DSYNC)
return 1;
return addr >= __pa(high_memory) ||
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
index 694d51f523d1..102b2dfa542a 100644
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -194,7 +194,7 @@ void __devinit cpu_cache_init(void)
int __weak __uncached_access(struct file *file, unsigned long addr)
{
- if (file->f_flags & O_SYNC)
+ if (file->f_flags & O_DSYNC)
return 1;
return addr >= __pa(high_memory);
diff --git a/arch/mips/mti-malta/malta-memory.c b/arch/mips/mti-malta/malta-memory.c
index 61888ff72c87..eafea8714a9e 100644
--- a/arch/mips/mti-malta/malta-memory.c
+++ b/arch/mips/mti-malta/malta-memory.c
@@ -54,7 +54,7 @@ static struct prom_pmemblock * __init prom_getmdesc(void)
{
char *memsize_str;
unsigned int memsize;
- char cmdline[CL_SIZE], *ptr;
+ char cmdline[COMMAND_LINE_SIZE], *ptr;
/* otherwise look in the environment */
memsize_str = prom_getenv("memsize");
diff --git a/arch/mips/rb532/prom.c b/arch/mips/rb532/prom.c
index 46ca24dbcc2d..dd6798f188a1 100644
--- a/arch/mips/rb532/prom.c
+++ b/arch/mips/rb532/prom.c
@@ -69,7 +69,7 @@ static inline unsigned long tag2ul(char *arg, const char *tag)
void __init prom_setup_cmdline(void)
{
- char cmd_line[CL_SIZE];
+ char cmd_line[COMMAND_LINE_SIZE];
char *cp, *board;
int prom_argc;
char **prom_argv, **prom_envp;
@@ -115,7 +115,7 @@ void __init prom_setup_cmdline(void)
strcpy(cp, arcs_cmdline);
cp += strlen(arcs_cmdline);
}
- cmd_line[CL_SIZE-1] = '\0';
+ cmd_line[COMMAND_LINE_SIZE-1] = '\0';
strcpy(arcs_cmdline, cmd_line);
}
diff --git a/arch/mips/sibyte/common/cfe.c b/arch/mips/sibyte/common/cfe.c
index eb5396cf81bb..6343011e9902 100644
--- a/arch/mips/sibyte/common/cfe.c
+++ b/arch/mips/sibyte/common/cfe.c
@@ -287,7 +287,7 @@ void __init prom_init(void)
* boot console
*/
cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
- if (cfe_getenv("LINUX_CMDLINE", arcs_cmdline, CL_SIZE) < 0) {
+ if (cfe_getenv("LINUX_CMDLINE", arcs_cmdline, COMMAND_LINE_SIZE) < 0) {
if (argc >= 0) {
/* The loader should have set the command line */
/* too early for panic to do any good */
@@ -318,7 +318,7 @@ void __init prom_init(void)
#endif /* CONFIG_BLK_DEV_INITRD */
/* Not sure this is needed, but it's the safe way. */
- arcs_cmdline[CL_SIZE-1] = 0;
+ arcs_cmdline[COMMAND_LINE_SIZE-1] = 0;
prom_meminit();
diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c
index c860810722c0..cb8f2b3d9459 100644
--- a/arch/mips/txx9/generic/setup.c
+++ b/arch/mips/txx9/generic/setup.c
@@ -160,7 +160,7 @@ static void __init prom_init_cmdline(void)
int argc;
int *argv32;
int i; /* Always ignore the "-c" at argv[0] */
- char builtin[CL_SIZE];
+ char builtin[COMMAND_LINE_SIZE];
if (fw_arg0 >= CKSEG0 || fw_arg1 < CKSEG0) {
/*
@@ -315,7 +315,7 @@ static inline void txx9_cache_fixup(void)
static void __init preprocess_cmdline(void)
{
- char cmdline[CL_SIZE];
+ char cmdline[COMMAND_LINE_SIZE];
char *s;
strcpy(cmdline, arcs_cmdline);
diff --git a/arch/mn10300/include/asm/asm-offsets.h b/arch/mn10300/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/mn10300/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/mn10300/include/asm/socket.h b/arch/mn10300/include/asm/socket.h
index 4df75af29d76..4e60c4281288 100644
--- a/arch/mn10300/include/asm/socket.h
+++ b/arch/mn10300/include/asm/socket.h
@@ -60,4 +60,6 @@
#define SO_PROTOCOL 38
#define SO_DOMAIN 39
+#define SO_RXQ_OVFL 40
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/parisc/include/asm/asm-offsets.h b/arch/parisc/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/parisc/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/parisc/include/asm/fcntl.h b/arch/parisc/include/asm/fcntl.h
index 5f39d5597ced..fea42a596210 100644
--- a/arch/parisc/include/asm/fcntl.h
+++ b/arch/parisc/include/asm/fcntl.h
@@ -1,14 +1,13 @@
#ifndef _PARISC_FCNTL_H
#define _PARISC_FCNTL_H
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
#define O_APPEND 000000010
#define O_BLKSEEK 000000100 /* HPUX only */
#define O_CREAT 000000400 /* not fcntl */
#define O_EXCL 000002000 /* not fcntl */
#define O_LARGEFILE 000004000
-#define O_SYNC 000100000
+#define __O_SYNC 000100000
+#define O_SYNC (__O_SYNC|O_DSYNC)
#define O_NONBLOCK 000200004 /* HPUX has separate NDELAY & NONBLOCK */
#define O_NOCTTY 000400000 /* not fcntl */
#define O_DSYNC 001000000 /* HPUX only */
diff --git a/arch/parisc/include/asm/socket.h b/arch/parisc/include/asm/socket.h
index 960b1e5d8e16..225b7d6a1a0a 100644
--- a/arch/parisc/include/asm/socket.h
+++ b/arch/parisc/include/asm/socket.h
@@ -59,6 +59,8 @@
#define SO_TIMESTAMPING 0x4020
#define SCM_TIMESTAMPING SO_TIMESTAMPING
+#define SO_RXQ_OVFL 0x4021
+
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here.
*/
diff --git a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c
index 75099efb3bf3..f9f6783e4bdd 100644
--- a/arch/parisc/kernel/perf.c
+++ b/arch/parisc/kernel/perf.c
@@ -24,7 +24,7 @@
*
* This driver programs the PCX-U/PCX-W performance counters
* on the PA-RISC 2.0 chips. The driver keeps all images now
- * internally to the kernel to hopefully eliminate the possiblity
+ * internally to the kernel to hopefully eliminate the possibility
* of a bad image halting the CPU. Also, there are different
* images for the PCX-W and later chips vs the PCX-U chips.
*
diff --git a/arch/powerpc/boot/dts/cm5200.dts b/arch/powerpc/boot/dts/cm5200.dts
index cee8080aa245..dd3860846f15 100644
--- a/arch/powerpc/boot/dts/cm5200.dts
+++ b/arch/powerpc/boot/dts/cm5200.dts
@@ -210,7 +210,6 @@
compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
reg = <0x3d40 0x40>;
interrupts = <2 16 0>;
- fsl5200-clocking;
};
sram@8000 {
diff --git a/arch/powerpc/boot/dts/digsy_mtc.dts b/arch/powerpc/boot/dts/digsy_mtc.dts
index 4c36186ef946..8e9be6bfe23e 100644
--- a/arch/powerpc/boot/dts/digsy_mtc.dts
+++ b/arch/powerpc/boot/dts/digsy_mtc.dts
@@ -199,7 +199,6 @@
compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
reg = <0x3d00 0x40>;
interrupts = <2 15 0>;
- fsl5200-clocking;
rtc@50 {
compatible = "at,24c08";
diff --git a/arch/powerpc/boot/dts/lite5200.dts b/arch/powerpc/boot/dts/lite5200.dts
index de30b3f9eb26..82ff2b13bc37 100644
--- a/arch/powerpc/boot/dts/lite5200.dts
+++ b/arch/powerpc/boot/dts/lite5200.dts
@@ -247,7 +247,6 @@
compatible = "fsl,mpc5200-i2c","fsl-i2c";
reg = <0x3d00 0x40>;
interrupts = <2 15 0>;
- fsl5200-clocking;
};
i2c@3d40 {
@@ -256,7 +255,6 @@
compatible = "fsl,mpc5200-i2c","fsl-i2c";
reg = <0x3d40 0x40>;
interrupts = <2 16 0>;
- fsl5200-clocking;
};
sram@8000 {
compatible = "fsl,mpc5200-sram";
diff --git a/arch/powerpc/boot/dts/lite5200b.dts b/arch/powerpc/boot/dts/lite5200b.dts
index d13cb11ce623..e45a63be3a86 100644
--- a/arch/powerpc/boot/dts/lite5200b.dts
+++ b/arch/powerpc/boot/dts/lite5200b.dts
@@ -251,7 +251,6 @@
compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
reg = <0x3d00 0x40>;
interrupts = <2 15 0>;
- fsl5200-clocking;
};
i2c@3d40 {
@@ -260,7 +259,6 @@
compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
reg = <0x3d40 0x40>;
interrupts = <2 16 0>;
- fsl5200-clocking;
};
sram@8000 {
diff --git a/arch/powerpc/boot/dts/media5200.dts b/arch/powerpc/boot/dts/media5200.dts
index e297d8b41875..0c3902bc5b6a 100644
--- a/arch/powerpc/boot/dts/media5200.dts
+++ b/arch/powerpc/boot/dts/media5200.dts
@@ -223,7 +223,6 @@
compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
reg = <0x3d00 0x40>;
interrupts = <2 15 0>;
- fsl5200-clocking;
};
i2c@3d40 {
@@ -232,7 +231,6 @@
compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
reg = <0x3d40 0x40>;
interrupts = <2 16 0>;
- fsl5200-clocking;
};
sram@8000 {
diff --git a/arch/powerpc/boot/dts/motionpro.dts b/arch/powerpc/boot/dts/motionpro.dts
index 7be8ca038676..6ca4fc144a33 100644
--- a/arch/powerpc/boot/dts/motionpro.dts
+++ b/arch/powerpc/boot/dts/motionpro.dts
@@ -222,7 +222,6 @@
compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
reg = <0x3d40 0x40>;
interrupts = <2 16 0>;
- fsl5200-clocking;
rtc@68 {
compatible = "dallas,ds1339";
diff --git a/arch/powerpc/boot/dts/mpc5121ads.dts b/arch/powerpc/boot/dts/mpc5121ads.dts
index c2b8dbfab79e..c353dac33416 100644
--- a/arch/powerpc/boot/dts/mpc5121ads.dts
+++ b/arch/powerpc/boot/dts/mpc5121ads.dts
@@ -209,7 +209,6 @@
reg = <0x1700 0x20>;
interrupts = <9 0x8>;
interrupt-parent = < &ipic >;
- fsl5200-clocking;
};
i2c@1720 {
@@ -220,7 +219,6 @@
reg = <0x1720 0x20>;
interrupts = <10 0x8>;
interrupt-parent = < &ipic >;
- fsl5200-clocking;
};
i2c@1740 {
@@ -231,7 +229,6 @@
reg = <0x1740 0x20>;
interrupts = <11 0x8>;
interrupt-parent = < &ipic >;
- fsl5200-clocking;
};
i2ccontrol@1760 {
diff --git a/arch/powerpc/boot/dts/mucmc52.dts b/arch/powerpc/boot/dts/mucmc52.dts
new file mode 100644
index 000000000000..b72a7581d798
--- /dev/null
+++ b/arch/powerpc/boot/dts/mucmc52.dts
@@ -0,0 +1,332 @@
+/*
+ * Manroland mucmc52 board Device Tree Source
+ *
+ * Copyright (C) 2009 DENX Software Engineering GmbH
+ * Heiko Schocher <hs@denx.de>
+ * Copyright 2006-2007 Secret Lab 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.
+ */
+
+/dts-v1/;
+
+/ {
+ model = "manroland,mucmc52";
+ compatible = "manroland,mucmc52";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&mpc5200_pic>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,5200@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <32>;
+ i-cache-line-size = <32>;
+ d-cache-size = <0x4000>; // L1, 16K
+ i-cache-size = <0x4000>; // L1, 16K
+ timebase-frequency = <0>; // from bootloader
+ bus-frequency = <0>; // from bootloader
+ clock-frequency = <0>; // from bootloader
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x04000000>; // 64MB
+ };
+
+ soc5200@f0000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,mpc5200b-immr";
+ ranges = <0 0xf0000000 0x0000c000>;
+ reg = <0xf0000000 0x00000100>;
+ bus-frequency = <0>; // from bootloader
+ system-frequency = <0>; // from bootloader
+
+ cdm@200 {
+ compatible = "fsl,mpc5200b-cdm","fsl,mpc5200-cdm";
+ reg = <0x200 0x38>;
+ };
+
+ mpc5200_pic: interrupt-controller@500 {
+ // 5200 interrupts are encoded into two levels;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ compatible = "fsl,mpc5200b-pic","fsl,mpc5200-pic";
+ reg = <0x500 0x80>;
+ };
+
+ gpt0: timer@600 { // GPT 0 in GPIO mode
+ compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ reg = <0x600 0x10>;
+ interrupts = <1 9 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpt1: timer@610 { // General Purpose Timer in GPIO mode
+ compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ reg = <0x610 0x10>;
+ interrupts = <1 10 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpt2: timer@620 { // General Purpose Timer in GPIO mode
+ compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ reg = <0x620 0x10>;
+ interrupts = <1 11 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpt3: timer@630 { // General Purpose Timer in GPIO mode
+ compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ reg = <0x630 0x10>;
+ interrupts = <1 12 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpio_simple: gpio@b00 {
+ compatible = "fsl,mpc5200b-gpio","fsl,mpc5200-gpio";
+ reg = <0xb00 0x40>;
+ interrupts = <1 7 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpio_wkup: gpio@c00 {
+ compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup";
+ reg = <0xc00 0x40>;
+ interrupts = <1 8 0 0 3 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ dma-controller@1200 {
+ compatible = "fsl,mpc5200b-bestcomm","fsl,mpc5200-bestcomm";
+ reg = <0x1200 0x80>;
+ interrupts = <3 0 0 3 1 0 3 2 0 3 3 0
+ 3 4 0 3 5 0 3 6 0 3 7 0
+ 3 8 0 3 9 0 3 10 0 3 11 0
+ 3 12 0 3 13 0 3 14 0 3 15 0>;
+ };
+
+ xlb@1f00 {
+ compatible = "fsl,mpc5200b-xlb","fsl,mpc5200-xlb";
+ reg = <0x1f00 0x100>;
+ };
+
+ serial@2000 { /* PSC1 in UART mode */
+ compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+ reg = <0x2000 0x100>;
+ interrupts = <2 1 0>;
+ };
+
+ serial@2200 { /* PSC2 in UART mode */
+ compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+ reg = <0x2200 0x100>;
+ interrupts = <2 2 0>;
+ };
+
+ serial@2c00 { /* PSC6 in UART mode */
+ compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+ reg = <0x2c00 0x100>;
+ interrupts = <2 4 0>;
+ };
+
+ ethernet@3000 {
+ compatible = "fsl,mpc5200b-fec","fsl,mpc5200-fec";
+ reg = <0x3000 0x400>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <2 5 0>;
+ phy-handle = <&phy0>;
+ };
+
+ mdio@3000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,mpc5200b-mdio","fsl,mpc5200-mdio";
+ reg = <0x3000 0x400>; // fec range, since we need to setup fec interrupts
+ interrupts = <2 5 0>; // these are for "mii command finished", not link changes & co.
+
+ phy0: ethernet-phy@0 {
+ compatible = "intel,lxt971";
+ reg = <0>;
+ };
+ };
+
+ ata@3a00 {
+ compatible = "fsl,mpc5200b-ata","fsl,mpc5200-ata";
+ reg = <0x3a00 0x100>;
+ interrupts = <2 7 0>;
+ };
+
+ i2c@3d40 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
+ reg = <0x3d40 0x40>;
+ interrupts = <2 16 0>;
+ hwmon@2c {
+ compatible = "ad,adm9240";
+ reg = <0x2c>;
+ };
+ rtc@51 {
+ compatible = "nxp,pcf8563";
+ reg = <0x51>;
+ };
+ };
+
+ sram@8000 {
+ compatible = "fsl,mpc5200b-sram","fsl,mpc5200-sram";
+ reg = <0x8000 0x4000>;
+ };
+ };
+
+ pci@f0000d00 {
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ device_type = "pci";
+ compatible = "fsl,mpc5200b-pci","fsl,mpc5200-pci";
+ reg = <0xf0000d00 0x100>;
+ interrupt-map-mask = <0xf800 0 0 7>;
+ interrupt-map = <
+ /* IDSEL 0x10 */
+ 0x8000 0 0 1 &mpc5200_pic 0 3 3
+ 0x8000 0 0 2 &mpc5200_pic 0 3 3
+ 0x8000 0 0 3 &mpc5200_pic 0 2 3
+ 0x8000 0 0 4 &mpc5200_pic 0 1 3
+ >;
+ clock-frequency = <0>; // From boot loader
+ interrupts = <2 8 0 2 9 0 2 10 0>;
+ bus-range = <0 0>;
+ ranges = <0x42000000 0 0x60000000 0x60000000 0 0x10000000
+ 0x02000000 0 0x90000000 0x90000000 0 0x10000000
+ 0x01000000 0 0x00000000 0xa0000000 0 0x01000000>;
+ };
+
+ localbus {
+ compatible = "fsl,mpc5200b-lpb","fsl,mpc5200-lpb","simple-bus";
+
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ ranges = <0 0 0xff800000 0x00800000
+ 1 0 0x80000000 0x00800000
+ 3 0 0x80000000 0x00800000>;
+
+ flash@0,0 {
+ compatible = "cfi-flash";
+ reg = <0 0 0x00800000>;
+ bank-width = <4>;
+ device-width = <2>;
+ #size-cells = <1>;
+ #address-cells = <1>;
+ partition@0 {
+ label = "DTS";
+ reg = <0x0 0x00100000>;
+ };
+ partition@100000 {
+ label = "Kernel";
+ reg = <0x100000 0x00200000>;
+ };
+ partition@300000 {
+ label = "RootFS";
+ reg = <0x00300000 0x00200000>;
+ };
+ partition@500000 {
+ label = "user";
+ reg = <0x00500000 0x00200000>;
+ };
+ partition@700000 {
+ label = "U-Boot";
+ reg = <0x00700000 0x00040000>;
+ };
+ partition@740000 {
+ label = "Env";
+ reg = <0x00740000 0x00020000>;
+ };
+ partition@760000 {
+ label = "red. Env";
+ reg = <0x00760000 0x00020000>;
+ };
+ partition@780000 {
+ label = "reserve";
+ reg = <0x00780000 0x00080000>;
+ };
+ };
+
+ simple100: gpio-controller-100@3,600100 {
+ compatible = "manroland,mucmc52-aux-gpio";
+ reg = <3 0x00600100 0x1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+ simple104: gpio-controller-104@3,600104 {
+ compatible = "manroland,mucmc52-aux-gpio";
+ reg = <3 0x00600104 0x1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+ simple200: gpio-controller-200@3,600200 {
+ compatible = "manroland,mucmc52-aux-gpio";
+ reg = <3 0x00600200 0x1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+ simple201: gpio-controller-201@3,600201 {
+ compatible = "manroland,mucmc52-aux-gpio";
+ reg = <3 0x00600201 0x1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+ simple202: gpio-controller-202@3,600202 {
+ compatible = "manroland,mucmc52-aux-gpio";
+ reg = <3 0x00600202 0x1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+ simple203: gpio-controller-203@3,600203 {
+ compatible = "manroland,mucmc52-aux-gpio";
+ reg = <3 0x00600203 0x1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+ simple204: gpio-controller-204@3,600204 {
+ compatible = "manroland,mucmc52-aux-gpio";
+ reg = <3 0x00600204 0x1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+ simple206: gpio-controller-206@3,600206 {
+ compatible = "manroland,mucmc52-aux-gpio";
+ reg = <3 0x00600206 0x1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+ simple207: gpio-controller-207@3,600207 {
+ compatible = "manroland,mucmc52-aux-gpio";
+ reg = <3 0x00600207 0x1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+ simple20f: gpio-controller-20f@3,60020f {
+ compatible = "manroland,mucmc52-aux-gpio";
+ reg = <3 0x0060020f 0x1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ };
+};
diff --git a/arch/powerpc/boot/dts/pcm030.dts b/arch/powerpc/boot/dts/pcm030.dts
index 30bfdc04c6df..8a4ec30b21ae 100644
--- a/arch/powerpc/boot/dts/pcm030.dts
+++ b/arch/powerpc/boot/dts/pcm030.dts
@@ -244,7 +244,6 @@
compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
reg = <0x3d00 0x40>;
interrupts = <2 15 0>;
- fsl5200-clocking;
};
i2c@3d40 {
@@ -253,7 +252,6 @@
compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
reg = <0x3d40 0x40>;
interrupts = <2 16 0>;
- fsl5200-clocking;
rtc@51 {
compatible = "nxp,pcf8563";
reg = <0x51>;
diff --git a/arch/powerpc/boot/dts/pcm032.dts b/arch/powerpc/boot/dts/pcm032.dts
index 030042678392..85d857a5d46e 100644
--- a/arch/powerpc/boot/dts/pcm032.dts
+++ b/arch/powerpc/boot/dts/pcm032.dts
@@ -244,7 +244,6 @@
compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
reg = <0x3d00 0x40>;
interrupts = <2 15 0>;
- fsl5200-clocking;
};
i2c@3d40 {
@@ -253,7 +252,6 @@
compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
reg = <0x3d40 0x40>;
interrupts = <2 16 0>;
- fsl5200-clocking;
rtc@51 {
compatible = "nxp,pcf8563";
reg = <0x51>;
diff --git a/arch/powerpc/boot/dts/tqm5200.dts b/arch/powerpc/boot/dts/tqm5200.dts
index c9590b58b7b0..1db07f6cf133 100644
--- a/arch/powerpc/boot/dts/tqm5200.dts
+++ b/arch/powerpc/boot/dts/tqm5200.dts
@@ -160,7 +160,6 @@
compatible = "fsl,mpc5200-i2c","fsl-i2c";
reg = <0x3d40 0x40>;
interrupts = <2 16 0>;
- fsl5200-clocking;
rtc@68 {
compatible = "dallas,ds1307";
diff --git a/arch/powerpc/boot/dts/uc101.dts b/arch/powerpc/boot/dts/uc101.dts
new file mode 100644
index 000000000000..019264c62904
--- /dev/null
+++ b/arch/powerpc/boot/dts/uc101.dts
@@ -0,0 +1,284 @@
+/*
+ * Manroland uc101 board Device Tree Source
+ *
+ * Copyright (C) 2009 DENX Software Engineering GmbH
+ * Heiko Schocher <hs@denx.de>
+ * Copyright 2006-2007 Secret Lab 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.
+ */
+
+/dts-v1/;
+
+/ {
+ model = "manroland,uc101";
+ compatible = "manroland,uc101";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&mpc5200_pic>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,5200@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <32>;
+ i-cache-line-size = <32>;
+ d-cache-size = <0x4000>; // L1, 16K
+ i-cache-size = <0x4000>; // L1, 16K
+ timebase-frequency = <0>; // from bootloader
+ bus-frequency = <0>; // from bootloader
+ clock-frequency = <0>; // from bootloader
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x04000000>; // 64MB
+ };
+
+ soc5200@f0000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,mpc5200b-immr";
+ ranges = <0 0xf0000000 0x0000c000>;
+ reg = <0xf0000000 0x00000100>;
+ bus-frequency = <0>; // from bootloader
+ system-frequency = <0>; // from bootloader
+
+ cdm@200 {
+ compatible = "fsl,mpc5200b-cdm","fsl,mpc5200-cdm";
+ reg = <0x200 0x38>;
+ };
+
+ mpc5200_pic: interrupt-controller@500 {
+ // 5200 interrupts are encoded into two levels;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ compatible = "fsl,mpc5200b-pic","fsl,mpc5200-pic";
+ reg = <0x500 0x80>;
+ };
+
+ gpt0: timer@600 { // General Purpose Timer in GPIO mode
+ compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ reg = <0x600 0x10>;
+ interrupts = <1 9 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpt1: timer@610 { // General Purpose Timer in GPIO mode
+ compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ reg = <0x610 0x10>;
+ interrupts = <1 10 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpt2: timer@620 { // General Purpose Timer in GPIO mode
+ compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ reg = <0x620 0x10>;
+ interrupts = <1 11 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpt3: timer@630 { // General Purpose Timer in GPIO mode
+ compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ reg = <0x630 0x10>;
+ interrupts = <1 12 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpt4: timer@640 { // General Purpose Timer in GPIO mode
+ compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ reg = <0x640 0x10>;
+ interrupts = <1 13 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpt5: timer@650 { // General Purpose Timer in GPIO mode
+ compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ reg = <0x650 0x10>;
+ interrupts = <1 14 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpt6: timer@660 { // General Purpose Timer in GPIO mode
+ compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ reg = <0x660 0x10>;
+ interrupts = <1 15 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpt7: timer@670 { // General Purpose Timer in GPIO mode
+ compatible = "fsl,mpc5200b-gpt","fsl,mpc5200-gpt";
+ reg = <0x670 0x10>;
+ interrupts = <1 16 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpio_simple: gpio@b00 {
+ compatible = "fsl,mpc5200b-gpio","fsl,mpc5200-gpio";
+ reg = <0xb00 0x40>;
+ interrupts = <1 7 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpio_wkup: gpio@c00 {
+ compatible = "fsl,mpc5200b-gpio-wkup","fsl,mpc5200-gpio-wkup";
+ reg = <0xc00 0x40>;
+ interrupts = <1 8 0 0 3 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ dma-controller@1200 {
+ compatible = "fsl,mpc5200b-bestcomm","fsl,mpc5200-bestcomm";
+ reg = <0x1200 0x80>;
+ interrupts = <3 0 0 3 1 0 3 2 0 3 3 0
+ 3 4 0 3 5 0 3 6 0 3 7 0
+ 3 8 0 3 9 0 3 10 0 3 11 0
+ 3 12 0 3 13 0 3 14 0 3 15 0>;
+ };
+
+ xlb@1f00 {
+ compatible = "fsl,mpc5200b-xlb","fsl,mpc5200-xlb";
+ reg = <0x1f00 0x100>;
+ };
+
+ serial@2000 { /* PSC1 in UART mode */
+ compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+ reg = <0x2000 0x100>;
+ interrupts = <2 1 0>;
+ };
+
+ serial@2200 { /* PSC2 in UART mode */
+ compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+ reg = <0x2200 0x100>;
+ interrupts = <2 2 0>;
+ };
+
+ serial@2c00 { /* PSC6 in UART mode */
+ compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+ reg = <0x2c00 0x100>;
+ interrupts = <2 4 0>;
+ };
+
+ ethernet@3000 {
+ compatible = "fsl,mpc5200b-fec","fsl,mpc5200-fec";
+ reg = <0x3000 0x400>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <2 5 0>;
+ phy-handle = <&phy0>;
+ };
+
+ mdio@3000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,mpc5200b-mdio","fsl,mpc5200-mdio";
+ reg = <0x3000 0x400>; // fec range, since we need to setup fec interrupts
+ interrupts = <2 5 0>; // these are for "mii command finished", not link changes & co.
+
+ phy0: ethernet-phy@0 {
+ compatible = "intel,lxt971";
+ reg = <0>;
+ };
+ };
+
+ ata@3a00 {
+ compatible = "fsl,mpc5200b-ata","fsl,mpc5200-ata";
+ reg = <0x3a00 0x100>;
+ interrupts = <2 7 0>;
+ };
+
+ i2c@3d40 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
+ reg = <0x3d40 0x40>;
+ interrupts = <2 16 0>;
+ fsl,preserve-clocking;
+ clock-frequency = <400000>;
+
+ hwmon@2c {
+ compatible = "ad,adm9240";
+ reg = <0x2c>;
+ };
+ rtc@51 {
+ compatible = "nxp,pcf8563";
+ reg = <0x51>;
+ };
+ };
+
+ sram@8000 {
+ compatible = "fsl,mpc5200b-sram","fsl,mpc5200-sram";
+ reg = <0x8000 0x4000>;
+ };
+ };
+
+ localbus {
+ compatible = "fsl,mpc5200b-lpb","fsl,mpc5200-lpb","simple-bus";
+
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ ranges = <0 0 0xff800000 0x00800000
+ 1 0 0x80000000 0x00800000
+ 3 0 0x80000000 0x00800000>;
+
+ flash@0,0 {
+ compatible = "cfi-flash";
+ reg = <0 0 0x00800000>;
+ bank-width = <2>;
+ device-width = <2>;
+ #size-cells = <1>;
+ #address-cells = <1>;
+
+ partition@0 {
+ label = "DTS";
+ reg = <0x0 0x00100000>;
+ };
+ partition@100000 {
+ label = "Kernel";
+ reg = <0x100000 0x00200000>;
+ };
+ partition@300000 {
+ label = "RootFS";
+ reg = <0x00300000 0x00200000>;
+ };
+ partition@500000 {
+ label = "user";
+ reg = <0x00500000 0x00200000>;
+ };
+ partition@700000 {
+ label = "U-Boot";
+ reg = <0x00700000 0x00040000>;
+ };
+ partition@740000 {
+ label = "Env";
+ reg = <0x00740000 0x00010000>;
+ };
+ partition@750000 {
+ label = "red. Env";
+ reg = <0x00750000 0x00010000>;
+ };
+ partition@760000 {
+ label = "reserve";
+ reg = <0x00760000 0x000a0000>;
+ };
+ };
+
+ };
+};
diff --git a/arch/powerpc/configs/52xx/cm5200_defconfig b/arch/powerpc/configs/52xx/cm5200_defconfig
index 3838b77b8116..0396ce7bffc6 100644
--- a/arch/powerpc/configs/52xx/cm5200_defconfig
+++ b/arch/powerpc/configs/52xx/cm5200_defconfig
@@ -1,25 +1,27 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc2
-# Sat Apr 18 00:47:44 2009
+# Linux kernel version: 2.6.32-rc4
+# Thu Oct 15 10:33:22 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -30,15 +32,17 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+# CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -52,11 +56,13 @@ CONFIG_OF=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -77,11 +83,12 @@ CONFIG_SYSVIPC_SYSCTL=y
#
# RCU Subsystem
#
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=14
CONFIG_GROUP_SCHED=y
@@ -105,7 +112,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -118,6 +124,13 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_SLUB_DEBUG=y
CONFIG_COMPAT_BRK=y
@@ -125,14 +138,19 @@ CONFIG_COMPAT_BRK=y
CONFIG_SLUB=y
# CONFIG_SLOB is not set
# CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_ATTRS=y
CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -140,7 +158,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -219,11 +237,13 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
# CONFIG_KEXEC is not set
# CONFIG_CRASH_DUMP is not set
+CONFIG_MAX_ACTIVE_REGIONS=32
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
@@ -239,9 +259,10 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -252,6 +273,7 @@ CONFIG_PROC_DEVICETREE=y
CONFIG_EXTRA_TARGETS=""
CONFIG_PM=y
# CONFIG_PM_DEBUG is not set
+# CONFIG_PM_RUNTIME is not set
CONFIG_SECCOMP=y
CONFIG_ISA_DMA_API=y
@@ -328,6 +350,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
@@ -342,6 +365,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -367,6 +391,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
@@ -457,6 +482,7 @@ CONFIG_MTD_PHYSMAP_OF=y
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -495,10 +521,6 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_BLK_DEV_SR is not set
CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -519,7 +541,6 @@ CONFIG_CHR_DEV_SG=y
# CONFIG_MD is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -558,14 +579,14 @@ CONFIG_NET_ETHERNET=y
# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
CONFIG_FEC_MPC52xx=y
CONFIG_FEC_MPC52xx_MDIO=y
+# CONFIG_XILINX_EMACLITE is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
-
-#
-# Wireless LAN
-#
+CONFIG_WLAN=y
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set
@@ -636,6 +657,7 @@ CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_TCG_TPM is not set
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_HELPER_AUTO=y
@@ -646,6 +668,7 @@ CONFIG_I2C_HELPER_AUTO=y
#
# I2C system bus drivers (mostly embedded / system-on-chip)
#
+# CONFIG_I2C_DESIGNWARE is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_SIMTEC is not set
@@ -666,23 +689,23 @@ CONFIG_I2C_MPC=y
# Miscellaneous I2C Chip support
#
# CONFIG_DS1682 is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
CONFIG_WATCHDOG=y
# CONFIG_WATCHDOG_NOWAYOUT is not set
@@ -713,25 +736,12 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_TMIO is not set
# CONFIG_PMIC_DA903X is not set
# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -775,11 +785,12 @@ CONFIG_USB_DEVICEFS=y
# CONFIG_USB_OXU210HP_HCD is not set
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PPC_SOC=y
-CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
+CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
# CONFIG_USB_OHCI_LITTLE_ENDIAN is not set
@@ -866,6 +877,10 @@ CONFIG_USB_STORAGE=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -885,10 +900,13 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -959,12 +977,12 @@ CONFIG_CRAMFS=y
# CONFIG_ROMFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1064,6 +1082,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1073,6 +1092,7 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=1024
# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
@@ -1090,10 +1110,14 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_DEBUG_OBJECTS is not set
# CONFIG_SLUB_DEBUG_ON is not set
# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1105,11 +1129,12 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
# CONFIG_DEBUG_PAGEALLOC is not set
@@ -1118,23 +1143,25 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
@@ -1159,7 +1186,6 @@ CONFIG_CRYPTO=y
#
# Crypto core or helper
#
-# CONFIG_CRYPTO_FIPS is not set
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
CONFIG_CRYPTO_AEAD2=y
@@ -1200,11 +1226,13 @@ CONFIG_CRYPTO_PCBC=y
#
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
#
# Digest
#
# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
# CONFIG_CRYPTO_MD4 is not set
CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_MICHAEL_MIC is not set
diff --git a/arch/powerpc/configs/52xx/lite5200b_defconfig b/arch/powerpc/configs/52xx/lite5200b_defconfig
index 29b0f34488f5..f5c07fd72239 100644
--- a/arch/powerpc/configs/52xx/lite5200b_defconfig
+++ b/arch/powerpc/configs/52xx/lite5200b_defconfig
@@ -1,25 +1,27 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc2
-# Sat Apr 18 00:48:04 2009
+# Linux kernel version: 2.6.32-rc4
+# Thu Oct 15 10:33:24 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -30,15 +32,17 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+# CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -52,12 +56,14 @@ CONFIG_OF=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -78,11 +84,12 @@ CONFIG_SYSVIPC_SYSCTL=y
#
# RCU Subsystem
#
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=14
CONFIG_GROUP_SCHED=y
@@ -106,7 +113,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -119,6 +125,13 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
@@ -127,14 +140,19 @@ CONFIG_COMPAT_BRK=y
CONFIG_SLUB=y
# CONFIG_SLOB is not set
# CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_ATTRS=y
CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -147,7 +165,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -228,11 +246,13 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
# CONFIG_KEXEC is not set
# CONFIG_CRASH_DUMP is not set
+CONFIG_MAX_ACTIVE_REGIONS=32
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
@@ -248,9 +268,10 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -264,6 +285,7 @@ CONFIG_PM=y
CONFIG_PM_SLEEP=y
CONFIG_SUSPEND=y
CONFIG_SUSPEND_FREEZER=y
+# CONFIG_PM_RUNTIME is not set
CONFIG_SECCOMP=y
CONFIG_ISA_DMA_API=y
@@ -348,6 +370,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
@@ -362,6 +385,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -387,6 +411,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
@@ -397,6 +422,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_MTD is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -431,7 +457,9 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -454,10 +482,6 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_BLK_DEV_SR is not set
# CONFIG_CHR_DEV_SG is not set
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -475,6 +499,8 @@ CONFIG_SCSI_WAIT_SCAN=m
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_BE2ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -483,6 +509,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -502,7 +529,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
@@ -514,11 +540,14 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_PMCRAID is not set
# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_BFA_FC is not set
# CONFIG_SCSI_DH is not set
# CONFIG_SCSI_OSD_INITIATOR is not set
CONFIG_ATA=y
# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
CONFIG_SATA_PMP=y
# CONFIG_SATA_AHCI is not set
# CONFIG_SATA_SIL24 is not set
@@ -540,6 +569,7 @@ CONFIG_ATA_SFF=y
# CONFIG_PATA_ALI is not set
# CONFIG_PATA_AMD is not set
# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATP867X is not set
# CONFIG_PATA_ATIIXP is not set
# CONFIG_PATA_CMD640_PCI is not set
# CONFIG_PATA_CMD64X is not set
@@ -568,6 +598,7 @@ CONFIG_PATA_MPC52xx=y
# CONFIG_PATA_OPTIDMA is not set
# CONFIG_PATA_PDC_OLD is not set
# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
# CONFIG_PATA_RZ1000 is not set
# CONFIG_PATA_SC1200 is not set
# CONFIG_PATA_SERVERWORKS is not set
@@ -586,14 +617,17 @@ CONFIG_PATA_MPC52xx=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -640,9 +674,12 @@ CONFIG_NET_ETHERNET=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
CONFIG_FEC_MPC52xx=y
CONFIG_FEC_MPC52xx_MDIO=y
# CONFIG_ATL2 is not set
+# CONFIG_XILINX_EMACLITE is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
# CONFIG_DL2K is not set
@@ -661,6 +698,8 @@ CONFIG_NETDEV_1000=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
+# CONFIG_MV643XX_ETH is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
# CONFIG_ATL1E is not set
@@ -686,10 +725,7 @@ CONFIG_CHELSIO_T3_DEPENDS=y
# CONFIG_SFC is not set
# CONFIG_BE2NET is not set
# CONFIG_TR is not set
-
-#
-# Wireless LAN
-#
+CONFIG_WLAN=y
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set
@@ -759,6 +795,7 @@ CONFIG_GEN_RTC=y
CONFIG_DEVPORT=y
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_HELPER_AUTO=y
@@ -787,6 +824,7 @@ CONFIG_I2C_HELPER_AUTO=y
#
# I2C system bus drivers (mostly embedded / system-on-chip)
#
+# CONFIG_I2C_DESIGNWARE is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_SIMTEC is not set
@@ -812,23 +850,23 @@ CONFIG_I2C_MPC=y
# Miscellaneous I2C Chip support
#
# CONFIG_DS1682 is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
# CONFIG_WATCHDOG is not set
CONFIG_SSB_POSSIBLE=y
@@ -847,30 +885,18 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_TMIO is not set
# CONFIG_PMIC_DA903X is not set
# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
#
# CONFIG_AGP is not set
+CONFIG_VGA_ARB=y
# CONFIG_DRM is not set
# CONFIG_VGASTATE is not set
CONFIG_VIDEO_OUTPUT_CONTROL=m
@@ -913,6 +939,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -932,10 +962,13 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -992,12 +1025,12 @@ CONFIG_MISC_FILESYSTEMS=y
# CONFIG_ROMFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1041,6 +1074,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1050,6 +1084,7 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=1024
# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
@@ -1067,10 +1102,14 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_DEBUG_OBJECTS is not set
# CONFIG_SLUB_DEBUG_ON is not set
# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1082,11 +1121,12 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
# CONFIG_DEBUG_PAGEALLOC is not set
@@ -1095,23 +1135,25 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
@@ -1136,7 +1178,6 @@ CONFIG_CRYPTO=y
#
# Crypto core or helper
#
-# CONFIG_CRYPTO_FIPS is not set
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
CONFIG_CRYPTO_AEAD2=y
@@ -1178,11 +1219,13 @@ CONFIG_CRYPTO_CBC=y
#
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
#
# Digest
#
# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
# CONFIG_CRYPTO_MD4 is not set
CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_MICHAEL_MIC is not set
diff --git a/arch/powerpc/configs/52xx/motionpro_defconfig b/arch/powerpc/configs/52xx/motionpro_defconfig
index 07b6b266ea95..4f77a1bdc8f9 100644
--- a/arch/powerpc/configs/52xx/motionpro_defconfig
+++ b/arch/powerpc/configs/52xx/motionpro_defconfig
@@ -1,25 +1,27 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc2
-# Sat Apr 18 00:48:22 2009
+# Linux kernel version: 2.6.32-rc4
+# Thu Oct 15 10:33:22 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -30,15 +32,17 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+# CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -52,11 +56,13 @@ CONFIG_OF=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -77,11 +83,12 @@ CONFIG_SYSVIPC_SYSCTL=y
#
# RCU Subsystem
#
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=14
CONFIG_GROUP_SCHED=y
@@ -105,7 +112,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -118,6 +124,13 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_SLUB_DEBUG=y
CONFIG_COMPAT_BRK=y
@@ -125,14 +138,19 @@ CONFIG_COMPAT_BRK=y
CONFIG_SLUB=y
# CONFIG_SLOB is not set
# CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_ATTRS=y
CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -140,7 +158,7 @@ CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -220,11 +238,13 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
# CONFIG_KEXEC is not set
# CONFIG_CRASH_DUMP is not set
+CONFIG_MAX_ACTIVE_REGIONS=32
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
@@ -240,9 +260,10 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -253,6 +274,7 @@ CONFIG_PROC_DEVICETREE=y
CONFIG_EXTRA_TARGETS=""
CONFIG_PM=y
# CONFIG_PM_DEBUG is not set
+# CONFIG_PM_RUNTIME is not set
CONFIG_SECCOMP=y
CONFIG_ISA_DMA_API=y
@@ -329,6 +351,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
@@ -343,6 +366,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -368,6 +392,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
@@ -458,6 +483,7 @@ CONFIG_MTD_ROM=y
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -483,6 +509,7 @@ CONFIG_MISC_DEVICES=y
#
# CONFIG_EEPROM_AT24 is not set
CONFIG_EEPROM_LEGACY=y
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -506,10 +533,6 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_BLK_DEV_SR is not set
CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -532,6 +555,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_OSD_INITIATOR is not set
CONFIG_ATA=y
# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
CONFIG_SATA_PMP=y
CONFIG_ATA_SFF=y
# CONFIG_SATA_MV is not set
@@ -540,7 +564,6 @@ CONFIG_PATA_MPC52xx=y
# CONFIG_MD is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -579,14 +602,14 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
CONFIG_FEC_MPC52xx=y
CONFIG_FEC_MPC52xx_MDIO=y
+# CONFIG_XILINX_EMACLITE is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
-
-#
-# Wireless LAN
-#
+CONFIG_WLAN=y
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set
@@ -647,6 +670,7 @@ CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_TCG_TPM is not set
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_HELPER_AUTO=y
@@ -657,6 +681,7 @@ CONFIG_I2C_HELPER_AUTO=y
#
# I2C system bus drivers (mostly embedded / system-on-chip)
#
+# CONFIG_I2C_DESIGNWARE is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_SIMTEC is not set
@@ -676,22 +701,28 @@ CONFIG_I2C_MPC=y
# Miscellaneous I2C Chip support
#
# CONFIG_DS1682 is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
# CONFIG_SENSORS_AD7414 is not set
# CONFIG_SENSORS_AD7418 is not set
# CONFIG_SENSORS_ADM1021 is not set
@@ -738,6 +769,8 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
@@ -747,9 +780,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_W83L786NG is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
CONFIG_WATCHDOG=y
# CONFIG_WATCHDOG_NOWAYOUT is not set
@@ -775,25 +806,12 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_TMIO is not set
# CONFIG_PMIC_DA903X is not set
# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -817,7 +835,7 @@ CONFIG_LEDS_CLASS=y
#
# LED drivers
#
-# CONFIG_LEDS_LP5521 is not set
+# CONFIG_LEDS_LP3944 is not set
# CONFIG_LEDS_PCA955X is not set
# CONFIG_LEDS_BD2802 is not set
@@ -866,6 +884,7 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -893,6 +912,10 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -912,10 +935,13 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -986,12 +1012,12 @@ CONFIG_CRAMFS=y
# CONFIG_ROMFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1091,6 +1117,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1100,6 +1127,7 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=1024
# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
@@ -1117,10 +1145,14 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_DEBUG_OBJECTS is not set
# CONFIG_SLUB_DEBUG_ON is not set
# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1132,11 +1164,12 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
# CONFIG_DEBUG_PAGEALLOC is not set
@@ -1145,23 +1178,25 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
@@ -1186,7 +1221,6 @@ CONFIG_CRYPTO=y
#
# Crypto core or helper
#
-# CONFIG_CRYPTO_FIPS is not set
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
CONFIG_CRYPTO_AEAD2=y
@@ -1227,11 +1261,13 @@ CONFIG_CRYPTO_PCBC=y
#
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
#
# Digest
#
# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
# CONFIG_CRYPTO_MD4 is not set
CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_MICHAEL_MIC is not set
diff --git a/arch/powerpc/configs/52xx/pcm030_defconfig b/arch/powerpc/configs/52xx/pcm030_defconfig
index afb1a3d1ef0a..f9168c1a2fa5 100644
--- a/arch/powerpc/configs/52xx/pcm030_defconfig
+++ b/arch/powerpc/configs/52xx/pcm030_defconfig
@@ -1,25 +1,27 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc2
-# Sat Apr 18 00:48:42 2009
+# Linux kernel version: 2.6.32-rc4
+# Thu Oct 15 10:33:25 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -30,15 +32,17 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+# CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -52,11 +56,13 @@ CONFIG_OF=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -79,11 +85,12 @@ CONFIG_POSIX_MQUEUE_SYSCTL=y
#
# RCU Subsystem
#
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
@@ -105,7 +112,6 @@ CONFIG_EMBEDDED=y
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -118,6 +124,13 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_PCI_QUIRKS=y
CONFIG_COMPAT_BRK=y
@@ -125,7 +138,6 @@ CONFIG_SLAB=y
# CONFIG_SLUB is not set
# CONFIG_SLOB is not set
# CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
CONFIG_HAVE_OPROFILE=y
# CONFIG_KPROBES is not set
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
@@ -133,7 +145,13 @@ CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_ATTRS=y
CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -146,7 +164,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -227,11 +245,13 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
# CONFIG_KEXEC is not set
# CONFIG_CRASH_DUMP is not set
+CONFIG_MAX_ACTIVE_REGIONS=32
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
@@ -247,9 +267,10 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -336,6 +357,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
@@ -350,6 +372,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -375,6 +398,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
@@ -382,9 +406,9 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_CONNECTOR is not set
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
# CONFIG_MTD_CONCAT is not set
CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_TESTS is not set
# CONFIG_MTD_REDBOOT_PARTS is not set
CONFIG_MTD_CMDLINE_PARTS=y
# CONFIG_MTD_OF_PARTS is not set
@@ -467,6 +491,7 @@ CONFIG_MTD_PHYSMAP=y
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
# CONFIG_BLK_DEV is not set
# CONFIG_MISC_DEVICES is not set
@@ -492,10 +517,6 @@ CONFIG_BLK_DEV_SD=m
# CONFIG_BLK_DEV_SR is not set
# CONFIG_CHR_DEV_SG is not set
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -515,6 +536,7 @@ CONFIG_SCSI_WAIT_SCAN=m
# CONFIG_SCSI_OSD_INITIATOR is not set
CONFIG_ATA=m
# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
CONFIG_SATA_PMP=y
# CONFIG_SATA_AHCI is not set
# CONFIG_SATA_SIL24 is not set
@@ -536,6 +558,7 @@ CONFIG_ATA_SFF=y
# CONFIG_PATA_ALI is not set
# CONFIG_PATA_AMD is not set
# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATP867X is not set
# CONFIG_PATA_ATIIXP is not set
# CONFIG_PATA_CMD640_PCI is not set
# CONFIG_PATA_CMD64X is not set
@@ -564,6 +587,7 @@ CONFIG_PATA_MPC52xx=m
# CONFIG_PATA_OPTIDMA is not set
# CONFIG_PATA_PDC_OLD is not set
# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
# CONFIG_PATA_RZ1000 is not set
# CONFIG_PATA_SC1200 is not set
# CONFIG_PATA_SERVERWORKS is not set
@@ -582,14 +606,17 @@ CONFIG_PATA_MPC52xx=m
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -636,16 +663,16 @@ CONFIG_MII=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
CONFIG_FEC_MPC52xx=y
CONFIG_FEC_MPC52xx_MDIO=y
# CONFIG_ATL2 is not set
+# CONFIG_XILINX_EMACLITE is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
# CONFIG_TR is not set
-
-#
-# Wireless LAN
-#
+CONFIG_WLAN=y
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set
@@ -722,6 +749,7 @@ CONFIG_HW_RANDOM=y
CONFIG_DEVPORT=y
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_HELPER_AUTO=y
@@ -750,6 +778,7 @@ CONFIG_I2C_HELPER_AUTO=y
#
# I2C system bus drivers (mostly embedded / system-on-chip)
#
+# CONFIG_I2C_DESIGNWARE is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_SIMTEC is not set
@@ -776,23 +805,23 @@ CONFIG_I2C_MPC=y
# Miscellaneous I2C Chip support
#
# CONFIG_DS1682 is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
# CONFIG_WATCHDOG is not set
CONFIG_SSB_POSSIBLE=y
@@ -811,30 +840,18 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_TMIO is not set
# CONFIG_PMIC_DA903X is not set
# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
#
# CONFIG_AGP is not set
+CONFIG_VGA_ARB=y
# CONFIG_DRM is not set
# CONFIG_VGASTATE is not set
# CONFIG_VIDEO_OUTPUT_CONTROL is not set
@@ -871,15 +888,17 @@ CONFIG_USB_DEVICEFS=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
# CONFIG_USB_EHCI_HCD is not set
# CONFIG_USB_OXU210HP_HCD is not set
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
CONFIG_USB_OHCI_HCD=m
# CONFIG_USB_OHCI_HCD_PPC_SOC is not set
-CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
+CONFIG_USB_OHCI_HCD_PPC_OF=y
# CONFIG_USB_OHCI_HCD_PCI is not set
CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
@@ -995,6 +1014,7 @@ CONFIG_RTC_DRV_PCF8563=m
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1022,6 +1042,10 @@ CONFIG_RTC_DRV_PCF8563=m
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1041,12 +1065,16 @@ CONFIG_FS_MBCACHE=m
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
# CONFIG_DNOTIFY is not set
# CONFIG_INOTIFY is not set
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
@@ -1114,7 +1142,6 @@ CONFIG_JFFS2_RTIME=y
# CONFIG_ROMFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
@@ -1201,6 +1228,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1210,6 +1238,7 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=1024
# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
@@ -1223,23 +1252,12 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_PREEMPT_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
-# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_KMEMTRACE is not set
-# CONFIG_WORKQUEUE_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_FTRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_IRQSTACKS is not set
# CONFIG_BOOTX_TEXT is not set
diff --git a/arch/powerpc/configs/52xx/tqm5200_defconfig b/arch/powerpc/configs/52xx/tqm5200_defconfig
index 8585c7c12861..75c835c2ae66 100644
--- a/arch/powerpc/configs/52xx/tqm5200_defconfig
+++ b/arch/powerpc/configs/52xx/tqm5200_defconfig
@@ -1,25 +1,27 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc2
-# Sat Apr 18 00:48:57 2009
+# Linux kernel version: 2.6.32-rc4
+# Thu Oct 15 10:33:23 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -30,15 +32,17 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+# CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
CONFIG_PPC=y
@@ -52,11 +56,13 @@ CONFIG_OF=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -77,11 +83,12 @@ CONFIG_SYSVIPC_SYSCTL=y
#
# RCU Subsystem
#
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=14
CONFIG_GROUP_SCHED=y
@@ -105,7 +112,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -118,6 +124,13 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_SLUB_DEBUG=y
CONFIG_COMPAT_BRK=y
@@ -125,14 +138,19 @@ CONFIG_COMPAT_BRK=y
CONFIG_SLUB=y
# CONFIG_SLOB is not set
# CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_ATTRS=y
CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -145,7 +163,7 @@ CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -225,11 +243,13 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
# CONFIG_KEXEC is not set
# CONFIG_CRASH_DUMP is not set
+CONFIG_MAX_ACTIVE_REGIONS=32
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
@@ -245,9 +265,10 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -258,6 +279,7 @@ CONFIG_PROC_DEVICETREE=y
CONFIG_EXTRA_TARGETS=""
CONFIG_PM=y
# CONFIG_PM_DEBUG is not set
+# CONFIG_PM_RUNTIME is not set
CONFIG_SECCOMP=y
CONFIG_ISA_DMA_API=y
@@ -334,6 +356,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
@@ -348,6 +371,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -373,6 +397,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
@@ -382,9 +407,9 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_CONNECTOR is not set
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
CONFIG_MTD_CONCAT=y
CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_TESTS is not set
# CONFIG_MTD_REDBOOT_PARTS is not set
CONFIG_MTD_CMDLINE_PARTS=y
# CONFIG_MTD_OF_PARTS is not set
@@ -464,6 +489,7 @@ CONFIG_MTD_PHYSMAP_OF=y
# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -502,10 +528,6 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_BLK_DEV_SR is not set
CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -529,6 +551,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_OSD_INITIATOR is not set
CONFIG_ATA=y
# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
CONFIG_SATA_PMP=y
CONFIG_ATA_SFF=y
# CONFIG_SATA_MV is not set
@@ -538,7 +561,6 @@ CONFIG_PATA_PLATFORM=y
# CONFIG_MD is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -577,14 +599,14 @@ CONFIG_NET_ETHERNET=y
# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
CONFIG_FEC_MPC52xx=y
CONFIG_FEC_MPC52xx_MDIO=y
+# CONFIG_XILINX_EMACLITE is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
-
-#
-# Wireless LAN
-#
+CONFIG_WLAN=y
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set
@@ -654,6 +676,7 @@ CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_TCG_TPM is not set
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_HELPER_AUTO=y
@@ -664,6 +687,7 @@ CONFIG_I2C_HELPER_AUTO=y
#
# I2C system bus drivers (mostly embedded / system-on-chip)
#
+# CONFIG_I2C_DESIGNWARE is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_SIMTEC is not set
@@ -685,22 +709,28 @@ CONFIG_I2C_MPC=y
# Miscellaneous I2C Chip support
#
# CONFIG_DS1682 is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
# CONFIG_GPIOLIB is not set
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
# CONFIG_SENSORS_AD7414 is not set
# CONFIG_SENSORS_AD7418 is not set
# CONFIG_SENSORS_ADM1021 is not set
@@ -747,6 +777,8 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
@@ -756,9 +788,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_W83L786NG is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
CONFIG_WATCHDOG=y
# CONFIG_WATCHDOG_NOWAYOUT is not set
@@ -789,25 +819,12 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_TMIO is not set
# CONFIG_PMIC_DA903X is not set
# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
@@ -851,11 +868,12 @@ CONFIG_USB_MON=y
# CONFIG_USB_OXU210HP_HCD is not set
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PPC_SOC=y
-CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
+CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
# CONFIG_USB_OHCI_LITTLE_ENDIAN is not set
@@ -969,6 +987,7 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -996,6 +1015,10 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1015,10 +1038,13 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1089,12 +1115,12 @@ CONFIG_CRAMFS=y
# CONFIG_ROMFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1194,6 +1220,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1203,6 +1230,7 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=1024
# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
@@ -1220,10 +1248,14 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_DEBUG_OBJECTS is not set
# CONFIG_SLUB_DEBUG_ON is not set
# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1235,11 +1267,12 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
# CONFIG_DEBUG_PAGEALLOC is not set
@@ -1248,23 +1281,25 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
@@ -1289,7 +1324,6 @@ CONFIG_CRYPTO=y
#
# Crypto core or helper
#
-# CONFIG_CRYPTO_FIPS is not set
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
CONFIG_CRYPTO_AEAD2=y
@@ -1331,11 +1365,13 @@ CONFIG_CRYPTO_PCBC=y
#
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
#
# Digest
#
# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
# CONFIG_CRYPTO_MD4 is not set
CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_MICHAEL_MIC is not set
diff --git a/arch/powerpc/configs/mpc5200_defconfig b/arch/powerpc/configs/mpc5200_defconfig
index aaa4416660e9..523d5fe18c0e 100644
--- a/arch/powerpc/configs/mpc5200_defconfig
+++ b/arch/powerpc/configs/mpc5200_defconfig
@@ -1,25 +1,27 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc2
-# Mon Apr 20 11:06:25 2009
+# Linux kernel version: 2.6.32-rc4
+# Thu Oct 15 10:33:21 2009
#
# CONFIG_PPC64 is not set
#
# Processor support
#
-CONFIG_6xx=y
+CONFIG_PPC_BOOK3S_32=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
# CONFIG_E200 is not set
CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
CONFIG_PPC_FPU=y
# CONFIG_ALTIVEC is not set
CONFIG_PPC_STD_MMU=y
CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
# CONFIG_SMP is not set
CONFIG_PPC32=y
CONFIG_WORD_SIZE=32
@@ -30,15 +32,17 @@ CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+# CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK is not set
CONFIG_IRQ_PER_CPU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_ARCH_HAS_ILOG2_U32=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
@@ -53,12 +57,14 @@ CONFIG_OF=y
# CONFIG_GENERIC_TBSYNC is not set
CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
CONFIG_DEFAULT_UIMAGE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_PPC_DCR_NATIVE is not set
# CONFIG_PPC_DCR_MMIO is not set
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
#
# General setup
@@ -79,11 +85,12 @@ CONFIG_SYSVIPC_SYSCTL=y
#
# RCU Subsystem
#
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_GROUP_SCHED is not set
@@ -103,7 +110,6 @@ CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
@@ -116,6 +122,13 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
CONFIG_SLUB_DEBUG=y
@@ -124,14 +137,19 @@ CONFIG_COMPAT_BRK=y
CONFIG_SLUB=y
# CONFIG_SLOB is not set
# CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_ATTRS=y
CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -144,7 +162,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_BLOCK=y
-# CONFIG_LBD is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_BLK_DEV_INTEGRITY is not set
@@ -205,7 +223,7 @@ CONFIG_RTAS_PROC=y
CONFIG_PPC_BESTCOMM=y
CONFIG_PPC_BESTCOMM_ATA=y
CONFIG_PPC_BESTCOMM_FEC=y
-# CONFIG_SIMPLE_GPIO is not set
+CONFIG_SIMPLE_GPIO=y
#
# Kernel options
@@ -229,11 +247,13 @@ CONFIG_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
# CONFIG_BINFMT_MISC is not set
# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_ARCH_HAS_WALK_MEMORY=y
CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
# CONFIG_KEXEC is not set
# CONFIG_CRASH_DUMP is not set
+CONFIG_MAX_ACTIVE_REGIONS=32
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
@@ -249,9 +269,10 @@ CONFIG_MIGRATION=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
CONFIG_HAVE_MLOCK=y
CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_PPC_4K_PAGES=y
# CONFIG_PPC_16K_PAGES is not set
# CONFIG_PPC_64K_PAGES is not set
@@ -265,6 +286,7 @@ CONFIG_PM=y
CONFIG_PM_SLEEP=y
CONFIG_SUSPEND=y
CONFIG_SUSPEND_FREEZER=y
+# CONFIG_PM_RUNTIME is not set
CONFIG_SECCOMP=y
CONFIG_ISA_DMA_API=y
@@ -349,6 +371,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
@@ -363,6 +386,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@@ -388,6 +412,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
@@ -397,9 +422,9 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_CONNECTOR is not set
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
CONFIG_MTD_CONCAT=y
CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_TESTS is not set
# CONFIG_MTD_REDBOOT_PARTS is not set
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
@@ -458,6 +483,7 @@ CONFIG_MTD_PHYSMAP_OF=y
# CONFIG_MTD_PMC551 is not set
# CONFIG_MTD_DATAFLASH is not set
# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
@@ -493,6 +519,7 @@ CONFIG_OF_DEVICE=y
CONFIG_OF_GPIO=y
CONFIG_OF_I2C=y
CONFIG_OF_SPI=y
+CONFIG_OF_MDIO=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
@@ -529,7 +556,9 @@ CONFIG_MISC_DEVICES=y
CONFIG_EEPROM_AT24=y
# CONFIG_EEPROM_AT25 is not set
# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -552,10 +581,6 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_BLK_DEV_SR is not set
CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -572,6 +597,8 @@ CONFIG_SCSI_WAIT_SCAN=m
# CONFIG_SCSI_SRP_ATTRS is not set
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_BE2ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -580,6 +607,7 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
@@ -599,7 +627,6 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
@@ -611,11 +638,14 @@ CONFIG_SCSI_LOWLEVEL=y
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_PMCRAID is not set
# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_BFA_FC is not set
# CONFIG_SCSI_DH is not set
# CONFIG_SCSI_OSD_INITIATOR is not set
CONFIG_ATA=y
# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
CONFIG_SATA_PMP=y
# CONFIG_SATA_AHCI is not set
# CONFIG_SATA_SIL24 is not set
@@ -637,6 +667,7 @@ CONFIG_ATA_SFF=y
# CONFIG_PATA_ALI is not set
# CONFIG_PATA_AMD is not set
# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATP867X is not set
# CONFIG_PATA_ATIIXP is not set
# CONFIG_PATA_CMD640_PCI is not set
# CONFIG_PATA_CMD64X is not set
@@ -665,6 +696,7 @@ CONFIG_PATA_MPC52xx=y
# CONFIG_PATA_OPTIDMA is not set
# CONFIG_PATA_PDC_OLD is not set
# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
# CONFIG_PATA_RZ1000 is not set
# CONFIG_PATA_SC1200 is not set
# CONFIG_PATA_SERVERWORKS is not set
@@ -684,14 +716,17 @@ CONFIG_PATA_PLATFORM=y
#
#
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
@@ -739,16 +774,17 @@ CONFIG_NET_ETHERNET=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
CONFIG_FEC_MPC52xx=y
CONFIG_FEC_MPC52xx_MDIO=y
# CONFIG_ATL2 is not set
+# CONFIG_XILINX_EMACLITE is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
# CONFIG_TR is not set
-
-#
-# Wireless LAN
-#
+CONFIG_WLAN=y
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set
@@ -854,6 +890,7 @@ CONFIG_LEGACY_PTY_COUNT=256
CONFIG_DEVPORT=y
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_HELPER_AUTO=y
CONFIG_I2C_ALGOBIT=y
@@ -883,6 +920,7 @@ CONFIG_I2C_ALGOBIT=y
#
# I2C system bus drivers (mostly embedded / system-on-chip)
#
+# CONFIG_I2C_DESIGNWARE is not set
# CONFIG_I2C_GPIO is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_OCORES is not set
@@ -910,10 +948,6 @@ CONFIG_I2C_MPC=y
# Miscellaneous I2C Chip support
#
# CONFIG_DS1682 is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_PCF8575 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
@@ -935,6 +969,11 @@ CONFIG_SPI_MPC52xx_PSC=m
#
CONFIG_SPI_SPIDEV=m
# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
@@ -957,16 +996,27 @@ CONFIG_GPIOLIB=y
# PCI GPIO expanders:
#
# CONFIG_GPIO_BT8XX is not set
+# CONFIG_GPIO_LANGWELL is not set
#
# SPI GPIO expanders:
#
# CONFIG_GPIO_MAX7301 is not set
# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
# CONFIG_SENSORS_AD7414 is not set
# CONFIG_SENSORS_AD7418 is not set
# CONFIG_SENSORS_ADCXX is not set
@@ -1019,6 +1069,8 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -1031,9 +1083,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
# CONFIG_SENSORS_LIS3_SPI is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
# CONFIG_THERMAL is not set
-# CONFIG_THERMAL_HWMON is not set
CONFIG_WATCHDOG=y
# CONFIG_WATCHDOG_NOWAYOUT is not set
@@ -1073,31 +1123,20 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_TMIO is not set
# CONFIG_PMIC_DA903X is not set
# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
# CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
-# CONFIG_USB_DABUSB is not set
+# CONFIG_MEDIA_SUPPORT is not set
#
# Graphics support
#
# CONFIG_AGP is not set
+CONFIG_VGA_ARB=y
CONFIG_DRM=y
# CONFIG_DRM_TDFX is not set
# CONFIG_DRM_R128 is not set
@@ -1167,6 +1206,7 @@ CONFIG_FB_RADEON_BACKLIGHT=y
# CONFIG_FB_BROADSHEET is not set
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_LCD_CLASS_DEVICE=m
+# CONFIG_LCD_LMS283GF05 is not set
# CONFIG_LCD_LTV350QV is not set
# CONFIG_LCD_ILI9320 is not set
# CONFIG_LCD_TDO24M is not set
@@ -1198,7 +1238,6 @@ CONFIG_LOGO_LINUX_CLUT224=y
# CONFIG_SOUND is not set
CONFIG_HID_SUPPORT=y
CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
# CONFIG_HIDRAW is not set
#
@@ -1217,10 +1256,11 @@ CONFIG_HID_BELKIN=y
CONFIG_HID_CHERRY=y
# CONFIG_HID_CHICONY is not set
CONFIG_HID_CYPRESS=y
-# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_HID_DRAGONRISE is not set
CONFIG_HID_EZKEY=y
# CONFIG_HID_KYE is not set
# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
# CONFIG_HID_KENSINGTON is not set
# CONFIG_HID_LOGITECH is not set
# CONFIG_HID_MICROSOFT is not set
@@ -1231,10 +1271,11 @@ CONFIG_HID_EZKEY=y
# CONFIG_HID_SAMSUNG is not set
# CONFIG_HID_SONY is not set
# CONFIG_HID_SUNPLUS is not set
-# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
# CONFIG_HID_TOPSEED is not set
-# CONFIG_THRUSTMASTER_FF is not set
-# CONFIG_ZEROPLUS_FF is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
@@ -1261,15 +1302,17 @@ CONFIG_USB_MON=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
# CONFIG_USB_EHCI_HCD is not set
# CONFIG_USB_OXU210HP_HCD is not set
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PPC_SOC=y
-CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
+CONFIG_USB_OHCI_HCD_PPC_OF=y
CONFIG_USB_OHCI_HCD_PCI=y
CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
@@ -1400,6 +1443,7 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
#
# SPI RTC drivers
@@ -1411,6 +1455,7 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_RTC_DRV_R9701 is not set
# CONFIG_RTC_DRV_RS5C348 is not set
# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
#
# Platform RTC drivers
@@ -1434,6 +1479,10 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
# CONFIG_STAGING is not set
#
@@ -1453,10 +1502,13 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
@@ -1533,12 +1585,12 @@ CONFIG_CRAMFS=y
# CONFIG_ROMFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-# CONFIG_NILFS2_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_LOCKD=y
@@ -1624,6 +1676,7 @@ CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_HAVE_LMB=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
#
# Kernel hacking
@@ -1633,6 +1686,7 @@ CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=1024
# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
@@ -1650,10 +1704,14 @@ CONFIG_SCHED_DEBUG=y
# CONFIG_DEBUG_OBJECTS is not set
# CONFIG_SLUB_DEBUG_ON is not set
# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1665,11 +1723,12 @@ CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
# CONFIG_DEBUG_PAGEALLOC is not set
@@ -1678,23 +1737,25 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
# CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_KMEMTRACE is not set
# CONFIG_WORKQUEUE_TRACER is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
CONFIG_PRINT_STACK_DEPTH=64
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
@@ -1719,7 +1780,6 @@ CONFIG_CRYPTO=y
#
# Crypto core or helper
#
-# CONFIG_CRYPTO_FIPS is not set
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
CONFIG_CRYPTO_AEAD2=y
@@ -1761,11 +1821,13 @@ CONFIG_CRYPTO_CBC=y
#
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
#
# Digest
#
# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
# CONFIG_CRYPTO_MD4 is not set
CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_MICHAEL_MIC is not set
diff --git a/arch/powerpc/configs/ppc64e_defconfig b/arch/powerpc/configs/ppc64e_defconfig
new file mode 100644
index 000000000000..18af46036258
--- /dev/null
+++ b/arch/powerpc/configs/ppc64e_defconfig
@@ -0,0 +1,2199 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.32-rc5
+# Fri Oct 16 11:37:15 2009
+#
+CONFIG_PPC64=y
+
+#
+# Processor support
+#
+# CONFIG_PPC_BOOK3S_64 is not set
+CONFIG_PPC_BOOK3E_64=y
+CONFIG_PPC_BOOK3E=y
+CONFIG_PPC_FPU=y
+CONFIG_BOOKE=y
+CONFIG_PPC_MMU_NOHASH=y
+CONFIG_PPC_MMU_NOHASH_64=y
+CONFIG_PPC_BOOK3E_MMU=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_VIRT_CPU_ACCOUNTING=y
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
+CONFIG_PPC_PERF_CTRS=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=32
+CONFIG_64BIT=y
+CONFIG_WORD_SIZE=64
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_ARCH_HAS_ILOG2_U64=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_COMPAT=y
+CONFIG_SYSVIPC_COMPAT=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_OF=y
+# CONFIG_PPC_UDBG_16550 is not set
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
+# CONFIG_DEFAULT_UIMAGE is not set
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+# CONFIG_PPC_OF_PLATFORM_PCI is not set
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+# CONFIG_TASK_XACCT is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=64
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_GROUP_SCHED is not set
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CGROUP_NS is not set
+# CONFIG_CGROUP_FREEZER is not set
+# CONFIG_CGROUP_DEVICE is not set
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+# CONFIG_CGROUP_CPUACCT is not set
+# CONFIG_RESOURCE_COUNTERS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+# CONFIG_EMBEDDED is not set
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_PERF_EVENTS=y
+CONFIG_EVENT_PROFILE=y
+# CONFIG_PERF_COUNTERS is not set
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+CONFIG_OPROFILE=y
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_SYSCALL_WRAPPERS=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_SLOW_WORK=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_BLK_DEV_BSG=y
+# CONFIG_BLK_DEV_INTEGRITY is not set
+CONFIG_BLOCK_COMPAT=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+# CONFIG_FREEZER is not set
+
+#
+# Platform support
+#
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PQ2ADS is not set
+CONFIG_PPC_OF_BOOT_TRAMPOLINE=y
+# CONFIG_IPIC is not set
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_U3_DART is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+
+#
+# CPU Frequency drivers
+#
+# CONFIG_FSL_ULI1575 is not set
+# CONFIG_SIMPLE_GPIO is not set
+
+#
+# Kernel options
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_SCHED_HRTICK=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_COMPAT_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+CONFIG_BINFMT_MISC=m
+CONFIG_IOMMU_VMERGE=y
+CONFIG_IOMMU_HELPER=y
+# CONFIG_SWIOTLB is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+# CONFIG_CRASH_DUMP is not set
+CONFIG_IRQ_ALL_CPUS=y
+# CONFIG_NUMA is not set
+CONFIG_MAX_ACTIVE_REGIONS=256
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_SPARSEMEM_EXTREME=y
+CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
+CONFIG_SPARSEMEM_VMEMMAP=y
+# CONFIG_MEMORY_HOTPLUG is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_PPC_HAS_HASH_64K is not set
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_64K_PAGES is not set
+# CONFIG_PPC_256K_PAGES is not set
+CONFIG_FORCE_MAX_ZONEORDER=13
+# CONFIG_SCHED_SMT is not set
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_EXTRA_TARGETS=""
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_PPC_INDIRECT_PCI is not set
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+# CONFIG_PCIEPORTBUS is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+CONFIG_PCI_MSI=y
+# CONFIG_PCI_LEGACY is not set
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=y
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
+CONFIG_CARDBUS=y
+
+#
+# PC-card bridges
+#
+# CONFIG_YENTA is not set
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+CONFIG_HOTPLUG_PCI=m
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+# CONFIG_HAS_RAPIDIO is not set
+# CONFIG_RELOCATABLE is not set
+CONFIG_PAGE_OFFSET=0xc000000000000000
+CONFIG_KERNEL_START=0xc000000000000000
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_NET=y
+CONFIG_COMPAT_NETLINK_MESSAGES=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_XFRM_IPCOMP=m
+CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+CONFIG_NET_IPIP=y
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CT_ACCT=y
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+# CONFIG_NF_CT_PROTO_DCCP is not set
+CONFIG_NF_CT_PROTO_GRE=m
+CONFIG_NF_CT_PROTO_SCTP=m
+# CONFIG_NF_CT_PROTO_UDPLITE is not set
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_PPTP=m
+# CONFIG_NF_CONNTRACK_SANE is not set
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NETFILTER_TPROXY=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_HL=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_RATEEST=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_HL=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+# CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT is not set
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+CONFIG_NETFILTER_XT_MATCH_U32=m
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_NF_NAT=m
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_NF_NAT_SNMP_BASIC=m
+CONFIG_NF_NAT_PROTO_GRE=m
+CONFIG_NF_NAT_PROTO_SCTP=m
+CONFIG_NF_NAT_FTP=m
+CONFIG_NF_NAT_IRC=m
+CONFIG_NF_NAT_TFTP=m
+CONFIG_NF_NAT_AMANDA=m
+CONFIG_NF_NAT_PPTP=m
+CONFIG_NF_NAT_H323=m
+CONFIG_NF_NAT_SIP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_DROP_MONITOR is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+CONFIG_CFG80211_DEFAULT_PS_VALUE=0
+CONFIG_WIRELESS_OLD_REGULATORY=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=65536
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
+CONFIG_HAVE_IDE=y
+CONFIG_IDE=y
+
+#
+# Please see Documentation/ide/ide.txt for help/info on IDE drives
+#
+CONFIG_IDE_XFER_MODE=y
+CONFIG_IDE_TIMINGS=y
+CONFIG_IDE_ATAPI=y
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_IDE_GD=y
+CONFIG_IDE_GD_ATA=y
+# CONFIG_IDE_GD_ATAPI is not set
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_DELKIN is not set
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_PLATFORM is not set
+CONFIG_BLK_DEV_IDEDMA_SFF=y
+
+#
+# PCI IDE chipsets support
+#
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_PCIBUS_ORDER=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+CONFIG_BLK_DEV_AMD74XX=y
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT8172 is not set
+# CONFIG_BLK_DEV_IT8213 is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_TC86C001 is not set
+CONFIG_BLK_DEV_IDEDMA=y
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+CONFIG_SCSI_NETLINK=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=y
+CONFIG_SCSI_FC_ATTRS=y
+CONFIG_SCSI_ISCSI_ATTRS=m
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+CONFIG_SCSI_SRP_ATTRS=y
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_BE2ISCSI is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_MPT2SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_FCOE is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+CONFIG_SCSI_SYM53C8XX_MMIO=y
+CONFIG_SCSI_IPR=y
+CONFIG_SCSI_IPR_TRACE=y
+CONFIG_SCSI_IPR_DUMP=y
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+CONFIG_SCSI_LPFC=m
+# CONFIG_SCSI_LPFC_DEBUG_FS is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+CONFIG_SCSI_DEBUG=m
+# CONFIG_SCSI_PMCRAID is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_BFA_FC is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_SATA_PMP=y
+# CONFIG_SATA_AHCI is not set
+CONFIG_SATA_SIL24=y
+CONFIG_ATA_SFF=y
+CONFIG_SATA_SVW=y
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATP867X is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PCMCIA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_SCH is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_AUTODETECT=y
+CONFIG_MD_LINEAR=y
+CONFIG_MD_RAID0=y
+CONFIG_MD_RAID1=y
+CONFIG_MD_RAID10=y
+CONFIG_MD_RAID456=y
+# CONFIG_MULTICORE_RAID456 is not set
+CONFIG_MD_RAID6_PQ=y
+# CONFIG_ASYNC_RAID6_TEST is not set
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_DEBUG is not set
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+# CONFIG_DM_LOG_USERSPACE is not set
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_QL is not set
+# CONFIG_DM_MULTIPATH_ST is not set
+# CONFIG_DM_DELAY is not set
+# CONFIG_DM_UEVENT is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
+#
+# CONFIG_FIREWIRE is not set
+CONFIG_IEEE1394=y
+CONFIG_IEEE1394_OHCI1394=y
+# CONFIG_IEEE1394_PCILYNX is not set
+CONFIG_IEEE1394_SBP2=m
+CONFIG_IEEE1394_ETH1394_ROM_ENTRY=y
+CONFIG_IEEE1394_ETH1394=m
+CONFIG_IEEE1394_RAWIO=y
+CONFIG_IEEE1394_VIDEO1394=m
+CONFIG_IEEE1394_DV1394=m
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+# CONFIG_I2O is not set
+CONFIG_MACINTOSH_DRIVERS=y
+# CONFIG_MAC_EMUMOUSEBTN is not set
+CONFIG_WINDFARM=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=y
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+CONFIG_BROADCOM_PHY=m
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+CONFIG_SUNGEM=y
+# CONFIG_CASSINI is not set
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_VORTEX=y
+# CONFIG_TYPHOON is not set
+# CONFIG_ETHOC is not set
+# CONFIG_DNET is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=y
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+CONFIG_E100=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_R6040 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SMSC9420 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_SC92031 is not set
+# CONFIG_ATL2 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_ACENIC=y
+CONFIG_ACENIC_OMIT_TIGON_I=y
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+# CONFIG_E1000E is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_VIA_VELOCITY is not set
+CONFIG_TIGON3=y
+# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_JME is not set
+CONFIG_NETDEV_10000=y
+# CONFIG_CHELSIO_T1 is not set
+CONFIG_CHELSIO_T3_DEPENDS=y
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_ENIC is not set
+# CONFIG_IXGBE is not set
+CONFIG_IXGB=m
+# CONFIG_S2IO is not set
+# CONFIG_VXGE is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_NIU is not set
+# CONFIG_MLX4_EN is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_TEHUTI is not set
+# CONFIG_BNX2X is not set
+# CONFIG_QLGE is not set
+# CONFIG_SFC is not set
+# CONFIG_BE2NET is not set
+CONFIG_TR=y
+CONFIG_IBMOL=y
+# CONFIG_3C359 is not set
+# CONFIG_TMS380TR is not set
+CONFIG_WLAN=y
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_NET_PCMCIA is not set
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
+CONFIG_PPPOE=m
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+# CONFIG_NET_FC is not set
+CONFIG_NETCONSOLE=y
+# CONFIG_NETCONSOLE_DYNAMIC is not set
+CONFIG_NETPOLL=y
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=m
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+# CONFIG_INPUT_UINPUT is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_XILINX_XPS_PS2 is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
+# CONFIG_SERIAL_8250_CS is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_OF_PLATFORM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_HVC_UDBG is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_IPWIRELESS is not set
+CONFIG_RAW_DRIVER=y
+CONFIG_MAX_RAW_DEVS=256
+# CONFIG_HANGCHECK_TIMER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+CONFIG_I2C_AMD8111=y
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+CONFIG_VGA_ARB=y
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB_DDC=y
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+CONFIG_FB_MACMODES=y
+CONFIG_FB_BACKLIGHT=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+CONFIG_FB_OF=y
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G=y
+CONFIG_FB_MATROX_I2C=m
+CONFIG_FB_MATROX_MAVEN=m
+CONFIG_FB_RADEON=y
+CONFIG_FB_RADEON_I2C=y
+CONFIG_FB_RADEON_BACKLIGHT=y
+# CONFIG_FB_RADEON_DEBUG is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_VIA is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_CARMINE is not set
+CONFIG_FB_IBM_GXT4500=y
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_PLATFORM is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+
+#
+# Display device support
+#
+CONFIG_DISPLAY_SUPPORT=y
+
+#
+# Display hardware drivers
+#
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=m
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_PCI=y
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AW2 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_OXYGEN is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS5530 is not set
+# CONFIG_SND_CTXFI is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_INDIGOIOX is not set
+# CONFIG_SND_INDIGODJX is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_HIFIER is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_LX6464ES is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRTUOSO is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+CONFIG_SND_PPC=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_USX2Y is not set
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_PCMCIA=y
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_PDAUDIOCF is not set
+# CONFIG_SND_SOC is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+CONFIG_USB_HIDDEV=y
+
+#
+# Special HID drivers
+#
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_DRAGONRISE=y
+# CONFIG_DRAGONRISE_FF is not set
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KYE=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_PANTHERLORD=y
+# CONFIG_PANTHERLORD_FF is not set
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+# CONFIG_GREENASIA_FF is not set
+CONFIG_HID_SMARTJOYPLUS=y
+# CONFIG_SMARTJOYPLUS_FF is not set
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+# CONFIG_THRUSTMASTER_FF is not set
+CONFIG_HID_ZEROPLUS=y
+# CONFIG_ZEROPLUS_FF is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+# CONFIG_USB_EHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+CONFIG_USB_APPLEDISPLAY=m
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_INFINIBAND=m
+# CONFIG_INFINIBAND_USER_MAD is not set
+# CONFIG_INFINIBAND_USER_ACCESS is not set
+CONFIG_INFINIBAND_ADDR_TRANS=y
+CONFIG_INFINIBAND_MTHCA=m
+CONFIG_INFINIBAND_MTHCA_DEBUG=y
+# CONFIG_INFINIBAND_IPATH is not set
+# CONFIG_INFINIBAND_AMSO1100 is not set
+# CONFIG_MLX4_INFINIBAND is not set
+# CONFIG_INFINIBAND_NES is not set
+CONFIG_INFINIBAND_IPOIB=m
+# CONFIG_INFINIBAND_IPOIB_CM is not set
+CONFIG_INFINIBAND_IPOIB_DEBUG=y
+# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set
+# CONFIG_INFINIBAND_SRP is not set
+CONFIG_INFINIBAND_ISER=m
+CONFIG_EDAC=y
+
+#
+# Reporting subsystems
+#
+# CONFIG_EDAC_DEBUG is not set
+CONFIG_EDAC_MM_EDAC=y
+# CONFIG_EDAC_CPC925 is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+CONFIG_RTC_DRV_DS1307=y
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_GENERIC is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT2_FS_XIP=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_XATTR=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_FS_XIP=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_JBD2=y
+# CONFIG_JBD2_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=y
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+CONFIG_JFS_FS=y
+CONFIG_JFS_POSIX_ACL=y
+CONFIG_JFS_SECURITY=y
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_QUOTA is not set
+CONFIG_XFS_POSIX_ACL=y
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_DEBUG is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=m
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_SUNRPC_XPRT_RDMA=m
+CONFIG_RPCSEC_GSS_KRB5=y
+CONFIG_RPCSEC_GSS_SPKM3=m
+# CONFIG_SMB_FS is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+CONFIG_BINARY_PRINTF=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=y
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_LZO_COMPRESS=m
+CONFIG_LZO_DECOMPRESS=m
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+CONFIG_NLATTR=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHEDSTATS=y
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+CONFIG_TRACE_IRQFLAGS=y
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_LATENCYTOP=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACER_MAX_TRACE=y
+CONFIG_RING_BUFFER=y
+CONFIG_EVENT_TRACING=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
+CONFIG_RING_BUFFER_ALLOW_SWAP=y
+CONFIG_TRACING=y
+CONFIG_GENERIC_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+CONFIG_IRQSOFF_TRACER=y
+CONFIG_SCHED_TRACER=y
+# CONFIG_BOOT_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
+CONFIG_PRINT_STACK_DEPTH=64
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_DEBUG_STACK_USAGE=y
+# CONFIG_PPC_EMULATED_STATS is not set
+CONFIG_CODE_PATCHING_SELFTEST=y
+CONFIG_FTR_FIXUP_SELFTEST=y
+CONFIG_MSI_BITMAP_SELFTEST=y
+CONFIG_XMON=y
+# CONFIG_XMON_DEFAULT is not set
+CONFIG_XMON_DISASSEMBLY=y
+CONFIG_DEBUGGER=y
+CONFIG_IRQSTACKS=y
+# CONFIG_VIRQ_DEBUG is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_XOR_BLOCKS=y
+CONFIG_ASYNC_CORE=y
+CONFIG_ASYNC_MEMCPY=y
+CONFIG_ASYNC_XOR=y
+CONFIG_ASYNC_PQ=y
+CONFIG_ASYNC_RAID6_RECOV=y
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_GF128MUL=m
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_SEQIV=m
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CTR=m
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_GHASH=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_BLOWFISH=m
+# CONFIG_CRYPTO_CAMELLIA is not set
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SALSA20=m
+# CONFIG_CRYPTO_SEED is not set
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=m
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/powerpc/include/asm/asm-offsets.h b/arch/powerpc/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/powerpc/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h
index 6ff04185d2aa..2ab9cbd98826 100644
--- a/arch/powerpc/include/asm/prom.h
+++ b/arch/powerpc/include/asm/prom.h
@@ -1,3 +1,4 @@
+#include <linux/of.h> /* linux/of.h gets to determine #include ordering */
#ifndef _POWERPC_PROM_H
#define _POWERPC_PROM_H
#ifdef __KERNEL__
@@ -16,6 +17,7 @@
* 2 of the License, or (at your option) any later version.
*/
#include <linux/types.h>
+#include <linux/of_fdt.h>
#include <linux/proc_fs.h>
#include <linux/platform_device.h>
#include <asm/irq.h>
@@ -28,133 +30,14 @@
#define of_prop_cmp(s1, s2) strcmp((s1), (s2))
#define of_node_cmp(s1, s2) strcasecmp((s1), (s2))
-/* Definitions used by the flattened device tree */
-#define OF_DT_HEADER 0xd00dfeed /* marker */
-#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */
-#define OF_DT_END_NODE 0x2 /* End node */
-#define OF_DT_PROP 0x3 /* Property: name off, size,
- * content */
-#define OF_DT_NOP 0x4 /* nop */
-#define OF_DT_END 0x9
-
-#define OF_DT_VERSION 0x10
-
-/*
- * This is what gets passed to the kernel by prom_init or kexec
- *
- * The dt struct contains the device tree structure, full pathes and
- * property contents. The dt strings contain a separate block with just
- * the strings for the property names, and is fully page aligned and
- * self contained in a page, so that it can be kept around by the kernel,
- * each property name appears only once in this page (cheap compression)
- *
- * the mem_rsvmap contains a map of reserved ranges of physical memory,
- * passing it here instead of in the device-tree itself greatly simplifies
- * the job of everybody. It's just a list of u64 pairs (base/size) that
- * ends when size is 0
- */
-struct boot_param_header
-{
- u32 magic; /* magic word OF_DT_HEADER */
- u32 totalsize; /* total size of DT block */
- u32 off_dt_struct; /* offset to structure */
- u32 off_dt_strings; /* offset to strings */
- u32 off_mem_rsvmap; /* offset to memory reserve map */
- u32 version; /* format version */
- u32 last_comp_version; /* last compatible version */
- /* version 2 fields below */
- u32 boot_cpuid_phys; /* Physical CPU id we're booting on */
- /* version 3 fields below */
- u32 dt_strings_size; /* size of the DT strings block */
- /* version 17 fields below */
- u32 dt_struct_size; /* size of the DT structure block */
-};
-
-
-
-typedef u32 phandle;
-typedef u32 ihandle;
-
-struct property {
- char *name;
- int length;
- void *value;
- struct property *next;
-};
-
-struct device_node {
- const char *name;
- const char *type;
- phandle node;
- phandle linux_phandle;
- char *full_name;
-
- struct property *properties;
- struct property *deadprops; /* removed properties */
- struct device_node *parent;
- struct device_node *child;
- struct device_node *sibling;
- struct device_node *next; /* next device of same type */
- struct device_node *allnext; /* next in list of all nodes */
- struct proc_dir_entry *pde; /* this node's proc directory */
- struct kref kref;
- unsigned long _flags;
- void *data;
-};
-
extern struct device_node *of_chosen;
-static inline int of_node_check_flag(struct device_node *n, unsigned long flag)
-{
- return test_bit(flag, &n->_flags);
-}
-
-static inline void of_node_set_flag(struct device_node *n, unsigned long flag)
-{
- set_bit(flag, &n->_flags);
-}
-
-
#define HAVE_ARCH_DEVTREE_FIXUPS
-static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
-{
- dn->pde = de;
-}
-
-
-extern struct device_node *of_find_all_nodes(struct device_node *prev);
-extern struct device_node *of_node_get(struct device_node *node);
-extern void of_node_put(struct device_node *node);
-
-/* For scanning the flat device-tree at boot time */
-extern int __init of_scan_flat_dt(int (*it)(unsigned long node,
- const char *uname, int depth,
- void *data),
- void *data);
-extern void* __init of_get_flat_dt_prop(unsigned long node, const char *name,
- unsigned long *size);
-extern int __init of_flat_dt_is_compatible(unsigned long node, const char *name);
-extern unsigned long __init of_get_flat_dt_root(void);
-
/* For updating the device tree at runtime */
extern void of_attach_node(struct device_node *);
extern void of_detach_node(struct device_node *);
-/* Other Prototypes */
-extern void finish_device_tree(void);
-extern void unflatten_device_tree(void);
-extern void early_init_devtree(void *);
-extern int machine_is_compatible(const char *compat);
-extern void print_properties(struct device_node *node);
-extern int prom_n_intr_cells(struct device_node* np);
-extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
-extern int prom_add_property(struct device_node* np, struct property* prop);
-extern int prom_remove_property(struct device_node *np, struct property *prop);
-extern int prom_update_property(struct device_node *np,
- struct property *newprop,
- struct property *oldprop);
-
#ifdef CONFIG_PPC32
/*
* PCI <-> OF matching functions
@@ -178,26 +61,6 @@ extern int release_OF_resource(struct device_node* node, int index);
* OF address retreival & translation
*/
-
-/* Helper to read a big number; size is in cells (not bytes) */
-static inline u64 of_read_number(const u32 *cell, int size)
-{
- u64 r = 0;
- while (size--)
- r = (r << 32) | *(cell++);
- return r;
-}
-
-/* Like of_read_number, but we want an unsigned long result */
-#ifdef CONFIG_PPC32
-static inline unsigned long of_read_ulong(const u32 *cell, int size)
-{
- return cell[size-1];
-}
-#else
-#define of_read_ulong(cell, size) of_read_number(cell, size)
-#endif
-
/* Translate an OF address block into a CPU physical address
*/
extern u64 of_translate_address(struct device_node *np, const u32 *addr);
@@ -349,11 +212,5 @@ extern int of_irq_to_resource(struct device_node *dev, int index,
*/
extern void __iomem *of_iomap(struct device_node *device, int index);
-/*
- * NB: This is here while we transition from using asm/prom.h
- * to linux/of.h
- */
-#include <linux/of.h>
-
#endif /* __KERNEL__ */
#endif /* _POWERPC_PROM_H */
diff --git a/arch/powerpc/include/asm/socket.h b/arch/powerpc/include/asm/socket.h
index 3ab8b3e6feb0..866f7606da68 100644
--- a/arch/powerpc/include/asm/socket.h
+++ b/arch/powerpc/include/asm/socket.h
@@ -67,4 +67,6 @@
#define SO_PROTOCOL 38
#define SO_DOMAIN 39
+#define SO_RXQ_OVFL 40
+
#endif /* _ASM_POWERPC_SOCKET_H */
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index f9fd54bfcc84..9763267e38b4 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -658,42 +658,43 @@ do_work:
cmpdi r0,0
crandc eq,cr1*4+eq,eq
bne restore
- /* here we are preempting the current task */
-1:
-#ifdef CONFIG_TRACE_IRQFLAGS
- bl .trace_hardirqs_on
- /* Note: we just clobbered r10 which used to contain the previous
- * MSR before the hard-disabling done by the caller of do_work.
- * We don't have that value anymore, but it doesn't matter as
- * we will hard-enable unconditionally, we can just reload the
- * current MSR into r10
+
+ /* Here we are preempting the current task.
+ *
+ * Ensure interrupts are soft-disabled. We also properly mark
+ * the PACA to reflect the fact that they are hard-disabled
+ * and trace the change
*/
- mfmsr r10
-#endif /* CONFIG_TRACE_IRQFLAGS */
- li r0,1
+ li r0,0
stb r0,PACASOFTIRQEN(r13)
stb r0,PACAHARDIRQEN(r13)
+ TRACE_DISABLE_INTS
+
+ /* Call the scheduler with soft IRQs off */
+1: bl .preempt_schedule_irq
+
+ /* Hard-disable interrupts again (and update PACA) */
#ifdef CONFIG_PPC_BOOK3E
- wrteei 1
- bl .preempt_schedule
wrteei 0
#else
- ori r10,r10,MSR_EE
- mtmsrd r10,1 /* reenable interrupts */
- bl .preempt_schedule
mfmsr r10
- clrrdi r9,r1,THREAD_SHIFT
- rldicl r10,r10,48,1 /* disable interrupts again */
+ rldicl r10,r10,48,1
rotldi r10,r10,16
mtmsrd r10,1
#endif /* CONFIG_PPC_BOOK3E */
+ li r0,0
+ stb r0,PACAHARDIRQEN(r13)
+
+ /* Re-test flags and eventually loop */
+ clrrdi r9,r1,THREAD_SHIFT
ld r4,TI_FLAGS(r9)
andi. r0,r4,_TIF_NEED_RESCHED
bne 1b
b restore
user_work:
-#endif
+#endif /* CONFIG_PREEMPT */
+
/* Enable interrupts */
#ifdef CONFIG_PPC_BOOK3E
wrteei 1
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index ba949a2c93ac..ccf56ac92de5 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -97,7 +97,9 @@ int pcibios_unmap_io_space(struct pci_bus *bus)
* to do an appropriate TLB flush here too
*/
if (bus->self) {
+#ifdef CONFIG_PPC_STD_MMU_64
struct resource *res = bus->resource[0];
+#endif
pr_debug("IO unmapping for PCI-PCI bridge %s\n",
pci_name(bus->self));
diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/kernel/perf_event.c
index bbcbae183e92..87f1663584b0 100644
--- a/arch/powerpc/kernel/perf_event.c
+++ b/arch/powerpc/kernel/perf_event.c
@@ -116,20 +116,23 @@ static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp)
static inline u32 perf_get_misc_flags(struct pt_regs *regs)
{
unsigned long mmcra = regs->dsisr;
+ unsigned long sihv = MMCRA_SIHV;
+ unsigned long sipr = MMCRA_SIPR;
if (TRAP(regs) != 0xf00)
return 0; /* not a PMU interrupt */
if (ppmu->flags & PPMU_ALT_SIPR) {
- if (mmcra & POWER6_MMCRA_SIHV)
- return PERF_RECORD_MISC_HYPERVISOR;
- return (mmcra & POWER6_MMCRA_SIPR) ?
- PERF_RECORD_MISC_USER : PERF_RECORD_MISC_KERNEL;
+ sihv = POWER6_MMCRA_SIHV;
+ sipr = POWER6_MMCRA_SIPR;
}
- if (mmcra & MMCRA_SIHV)
+
+ /* PR has priority over HV, so order below is important */
+ if (mmcra & sipr)
+ return PERF_RECORD_MISC_USER;
+ if ((mmcra & sihv) && (freeze_events_kernel != MMCR0_FCHV))
return PERF_RECORD_MISC_HYPERVISOR;
- return (mmcra & MMCRA_SIPR) ? PERF_RECORD_MISC_USER :
- PERF_RECORD_MISC_KERNEL;
+ return PERF_RECORD_MISC_KERNEL;
}
/*
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 2ec1eaed19ca..c930ac38e59f 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1172,7 +1172,7 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
unsigned long base = mm->brk;
unsigned long ret;
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_PPC_STD_MMU_64
/*
* If we are using 1TB segments and we are allowed to randomise
* the heap, we can put it above 1TB so it is backed by a 1TB
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index d4405b95bfaa..4ec300862466 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -1317,29 +1317,6 @@ struct device_node *of_find_next_cache_node(struct device_node *np)
}
/**
- * of_find_all_nodes - Get next node in global list
- * @prev: Previous node or NULL to start iteration
- * of_node_put() will be called on it
- *
- * Returns a node pointer with refcount incremented, use
- * of_node_put() on it when done.
- */
-struct device_node *of_find_all_nodes(struct device_node *prev)
-{
- struct device_node *np;
-
- read_lock(&devtree_lock);
- np = prev ? prev->allnext : allnodes;
- for (; np != 0; np = np->allnext)
- if (of_node_get(np))
- break;
- of_node_put(prev);
- read_unlock(&devtree_lock);
- return np;
-}
-EXPORT_SYMBOL(of_find_all_nodes);
-
-/**
* of_node_get - Increment refcount of a node
* @node: Node to inc refcount, NULL is supported to
* simplify writing of callers
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 797ea95aae2e..04f638d82fb3 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -57,7 +57,6 @@
#include <asm/cache.h>
#include <asm/page.h>
#include <asm/mmu.h>
-#include <asm/mmu-hash64.h>
#include <asm/firmware.h>
#include <asm/xmon.h>
#include <asm/udbg.h>
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index 94e2df3cae07..d84d19224a95 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -50,6 +50,9 @@
/* Max supported size for symbol names */
#define MAX_SYMNAME 64
+/* The alignment of the vDSO */
+#define VDSO_ALIGNMENT (1 << 16)
+
extern char vdso32_start, vdso32_end;
static void *vdso32_kbase = &vdso32_start;
static unsigned int vdso32_pages;
@@ -231,15 +234,21 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
* pick a base address for the vDSO in process space. We try to put it
* at vdso_base which is the "natural" base for it, but we might fail
* and end up putting it elsewhere.
+ * Add enough to the size so that the result can be aligned.
*/
down_write(&mm->mmap_sem);
vdso_base = get_unmapped_area(NULL, vdso_base,
- vdso_pages << PAGE_SHIFT, 0, 0);
+ (vdso_pages << PAGE_SHIFT) +
+ ((VDSO_ALIGNMENT - 1) & PAGE_MASK),
+ 0, 0);
if (IS_ERR_VALUE(vdso_base)) {
rc = vdso_base;
goto fail_mmapsem;
}
+ /* Add required alignment. */
+ vdso_base = ALIGN(vdso_base, VDSO_ALIGNMENT);
+
/*
* Put vDSO base into mm struct. We need to do this before calling
* install_special_mapping or the perf counter mmap tracking code
@@ -712,7 +721,7 @@ static int __init vdso_init(void)
#ifdef CONFIG_PPC64
/*
- * Fill up the "systemcfg" stuff for backward compatiblity
+ * Fill up the "systemcfg" stuff for backward compatibility
*/
strcpy((char *)vdso_data->eye_catcher, "SYSTEMCFG:PPC64");
vdso_data->version.major = SYSTEMCFG_MAJOR;
diff --git a/arch/powerpc/kernel/vdso32/vdso32.lds.S b/arch/powerpc/kernel/vdso32/vdso32.lds.S
index 904ef1360dd7..0546bcd49cd0 100644
--- a/arch/powerpc/kernel/vdso32/vdso32.lds.S
+++ b/arch/powerpc/kernel/vdso32/vdso32.lds.S
@@ -25,7 +25,7 @@ SECTIONS
. = ALIGN(16);
.text : {
*(.text .stub .text.* .gnu.linkonce.t.* __ftr_alt_*)
- }
+ } :text
PROVIDE(__etext = .);
PROVIDE(_etext = .);
PROVIDE(etext = .);
@@ -56,7 +56,7 @@ SECTIONS
.fixup : { *(.fixup) }
.dynamic : { *(.dynamic) } :text :dynamic
- .got : { *(.got) }
+ .got : { *(.got) } :text
.plt : { *(.plt) }
_end = .;
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 2a4551f78f60..5902bbc2411e 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -78,8 +78,9 @@ int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
return r;
}
-void kvm_arch_hardware_enable(void *garbage)
+int kvm_arch_hardware_enable(void *garbage)
{
+ return 0;
}
void kvm_arch_hardware_disable(void *garbage)
@@ -421,7 +422,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
switch (ioctl) {
default:
- r = -EINVAL;
+ r = -ENOTTY;
}
return r;
diff --git a/arch/powerpc/kvm/timing.h b/arch/powerpc/kvm/timing.h
index bb13b1f3cd5a..4c34099cea9f 100644
--- a/arch/powerpc/kvm/timing.h
+++ b/arch/powerpc/kvm/timing.h
@@ -48,7 +48,7 @@ static inline void kvmppc_set_exit_type(struct kvm_vcpu *vcpu, int type) {}
static inline void kvmppc_account_exit_stat(struct kvm_vcpu *vcpu, int type)
{
/* type has to be known at build time for optimization */
- BUILD_BUG_ON(__builtin_constant_p(type));
+ //BUILD_BUG_ON(__builtin_constant_p(type));
switch (type) {
case EXT_INTR_EXITS:
vcpu->stat.ext_intr_exits++;
diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c
index ae06c6236d9c..52c98edcd703 100644
--- a/arch/powerpc/oprofile/op_model_cell.c
+++ b/arch/powerpc/oprofile/op_model_cell.c
@@ -248,7 +248,7 @@ static int pm_rtas_activate_signals(u32 node, u32 count)
* There is no debug setup required for the cycles event.
* Note that only events in the same group can be used.
* Otherwise, there will be conflicts in correctly routing
- * the signals on the debug bus. It is the responsiblity
+ * the signals on the debug bus. It is the responsibility
* of the OProfile user tool to check the events are in
* the same group.
*/
diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c
index bcc69e1f77c1..45c0cb9b67e6 100644
--- a/arch/powerpc/platforms/52xx/efika.c
+++ b/arch/powerpc/platforms/52xx/efika.c
@@ -10,7 +10,7 @@
*/
#include <linux/init.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
#include <linux/pci.h>
#include <linux/of.h>
#include <asm/prom.h>
diff --git a/arch/powerpc/platforms/52xx/mpc5200_simple.c b/arch/powerpc/platforms/52xx/mpc5200_simple.c
index c31e5b534f0a..d45be5b5ad49 100644
--- a/arch/powerpc/platforms/52xx/mpc5200_simple.c
+++ b/arch/powerpc/platforms/52xx/mpc5200_simple.c
@@ -51,6 +51,8 @@ static void __init mpc5200_simple_setup_arch(void)
/* list of the supported boards */
static char *board[] __initdata = {
"intercontrol,digsy-mtc",
+ "manroland,mucmc52",
+ "manroland,uc101",
"phytec,pcm030",
"phytec,pcm032",
"promess,motionpro",
diff --git a/arch/powerpc/platforms/amigaone/setup.c b/arch/powerpc/platforms/amigaone/setup.c
index 9290a7a442d0..fb4eb0df054c 100644
--- a/arch/powerpc/platforms/amigaone/setup.c
+++ b/arch/powerpc/platforms/amigaone/setup.c
@@ -14,7 +14,7 @@
#include <linux/kernel.h>
#include <linux/seq_file.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
#include <asm/machdep.h>
#include <asm/cputable.h>
diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile
index b93f877ba504..b9d5d678aa44 100644
--- a/arch/powerpc/platforms/cell/spufs/Makefile
+++ b/arch/powerpc/platforms/cell/spufs/Makefile
@@ -13,10 +13,8 @@ SPU_CC := $(SPU_CROSS)gcc
SPU_AS := $(SPU_CROSS)gcc
SPU_LD := $(SPU_CROSS)ld
SPU_OBJCOPY := $(SPU_CROSS)objcopy
-SPU_CFLAGS := -O2 -Wall -I$(srctree)/include \
- -I$(objtree)/include2 -D__KERNEL__
-SPU_AFLAGS := -c -D__ASSEMBLY__ -I$(srctree)/include \
- -I$(objtree)/include2 -D__KERNEL__
+SPU_CFLAGS := -O2 -Wall -I$(srctree)/include -D__KERNEL__
+SPU_AFLAGS := -c -D__ASSEMBLY__ -I$(srctree)/include -D__KERNEL__
SPU_LDFLAGS := -N -Ttext=0x0
$(obj)/switch.o: $(obj)/spu_save_dump.h $(obj)/spu_restore_dump.h
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index cd4ad9aea760..0a6f5ab8aab3 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -23,7 +23,7 @@
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/pci.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
#include <linux/adb.h>
#include <linux/module.h>
#include <linux/delay.h>
diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile
index cc7161ff1666..ce014928d460 100644
--- a/arch/powerpc/platforms/iseries/Makefile
+++ b/arch/powerpc/platforms/iseries/Makefile
@@ -1,18 +1,9 @@
EXTRA_CFLAGS += -mno-minimal-toc
-extra-y += dt.o
-
obj-y += exception.o
-obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt_mod.o mf.o lpevents.o \
+obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt.o mf.o lpevents.o \
hvcall.o proc.o htab.o iommu.o misc.o irq.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_VIOPATH) += viopath.o vio.o
obj-$(CONFIG_MODULES) += ksyms.o
-
-quiet_cmd_dt_strings = DT_STR $@
- cmd_dt_strings = $(OBJCOPY) --rename-section .rodata.str1.8=.dt_strings \
- $< $@
-
-$(obj)/dt_mod.o: $(obj)/dt.o
- $(call if_changed,dt_strings)
diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c
index c5a87a72057b..7f45a51fe793 100644
--- a/arch/powerpc/platforms/iseries/dt.c
+++ b/arch/powerpc/platforms/iseries/dt.c
@@ -51,11 +51,16 @@
/*
* These are created by the linker script at the start and end
- * of the section containing all the strings from this file.
+ * of the section containing all the strings marked with the DS macro.
*/
extern char __dt_strings_start[];
extern char __dt_strings_end[];
+#define DS(s) ({ \
+ static const char __s[] __attribute__((section(".dt_strings"))) = s; \
+ __s; \
+})
+
struct iseries_flat_dt {
struct boot_param_header header;
u64 reserve_map[2];
@@ -64,9 +69,8 @@ struct iseries_flat_dt {
static void * __initdata dt_data;
/*
- * Putting these strings here keeps them out of the section
- * that we rename to .dt_strings using objcopy and capture
- * for the strings blob of the flattened device tree.
+ * Putting these strings here keeps them out of the .dt_strings section
+ * that we capture for the strings blob of the flattened device tree.
*/
static char __initdata device_type_cpu[] = "cpu";
static char __initdata device_type_memory[] = "memory";
@@ -173,7 +177,7 @@ static void __init dt_start_node(struct iseries_flat_dt *dt, const char *name)
#define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE)
-static void __init dt_prop(struct iseries_flat_dt *dt, const char *name,
+static void __init __dt_prop(struct iseries_flat_dt *dt, const char *name,
const void *data, int len)
{
unsigned long offset;
@@ -191,44 +195,32 @@ static void __init dt_prop(struct iseries_flat_dt *dt, const char *name,
/* The actual data. */
dt_push_bytes(dt, data, len);
}
+#define dt_prop(dt, name, data, len) __dt_prop((dt), DS(name), (data), (len))
-static void __init dt_prop_str(struct iseries_flat_dt *dt, const char *name,
- const char *data)
-{
- dt_prop(dt, name, data, strlen(data) + 1); /* + 1 for NULL */
-}
+#define dt_prop_str(dt, name, data) \
+ dt_prop((dt), name, (data), strlen((data)) + 1); /* + 1 for NULL */
-static void __init dt_prop_u32(struct iseries_flat_dt *dt, const char *name,
+static void __init __dt_prop_u32(struct iseries_flat_dt *dt, const char *name,
u32 data)
{
- dt_prop(dt, name, &data, sizeof(u32));
+ __dt_prop(dt, name, &data, sizeof(u32));
}
+#define dt_prop_u32(dt, name, data) __dt_prop_u32((dt), DS(name), (data))
-static void __init __maybe_unused dt_prop_u64(struct iseries_flat_dt *dt,
- const char *name,
- u64 data)
+static void __init __maybe_unused __dt_prop_u64(struct iseries_flat_dt *dt,
+ const char *name, u64 data)
{
- dt_prop(dt, name, &data, sizeof(u64));
+ __dt_prop(dt, name, &data, sizeof(u64));
}
+#define dt_prop_u64(dt, name, data) __dt_prop_u64((dt), DS(name), (data))
-static void __init dt_prop_u64_list(struct iseries_flat_dt *dt,
- const char *name, u64 *data, int n)
-{
- dt_prop(dt, name, data, sizeof(u64) * n);
-}
+#define dt_prop_u64_list(dt, name, data, n) \
+ dt_prop((dt), name, (data), sizeof(u64) * (n))
-static void __init dt_prop_u32_list(struct iseries_flat_dt *dt,
- const char *name, u32 *data, int n)
-{
- dt_prop(dt, name, data, sizeof(u32) * n);
-}
+#define dt_prop_u32_list(dt, name, data, n) \
+ dt_prop((dt), name, (data), sizeof(u32) * (n))
-#ifdef notyet
-static void __init dt_prop_empty(struct iseries_flat_dt *dt, const char *name)
-{
- dt_prop(dt, name, NULL, 0);
-}
-#endif
+#define dt_prop_empty(dt, name) dt_prop((dt), name, NULL, 0)
static void __init dt_cpus(struct iseries_flat_dt *dt)
{
diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c
index cf660916ae0b..9dd789a7370d 100644
--- a/arch/powerpc/platforms/powermac/bootx_init.c
+++ b/arch/powerpc/platforms/powermac/bootx_init.c
@@ -12,7 +12,7 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/init.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
#include <asm/sections.h>
#include <asm/prom.h>
#include <asm/page.h>
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index c6f0a71b405e..bdbe96c8a7e4 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -517,6 +517,15 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
in_xmon = 0;
#endif
+#ifdef CONFIG_BOOKE
+ if (regs->msr & MSR_DE) {
+ bp = at_breakpoint(regs->nip);
+ if (bp != NULL) {
+ regs->nip = (unsigned long) &bp->instr[0];
+ atomic_inc(&bp->ref_count);
+ }
+ }
+#else
if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
bp = at_breakpoint(regs->nip);
if (bp != NULL) {
@@ -530,7 +539,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
}
}
}
-
+#endif
insert_cpu_bpts();
local_irq_restore(flags);
@@ -894,6 +903,14 @@ cmds(struct pt_regs *excp)
}
}
+#ifdef CONFIG_BOOKE
+static int do_step(struct pt_regs *regs)
+{
+ regs->msr |= MSR_DE;
+ mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
+ return 1;
+}
+#else
/*
* Step a single instruction.
* Some instructions we emulate, others we execute with MSR_SE set.
@@ -924,6 +941,7 @@ static int do_step(struct pt_regs *regs)
regs->msr |= MSR_SE;
return 1;
}
+#endif
static void bootcmds(void)
{
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 43c0acad7160..df8eb2aa6123 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -192,23 +192,8 @@ config AUDIT_ARCH
bool
default y
-config S390_SWITCH_AMODE
- bool "Switch kernel/user addressing modes"
- help
- This option allows to switch the addressing modes of kernel and user
- space. The kernel parameter switch_amode=on will enable this feature,
- default is disabled. Enabling this (via kernel parameter) on machines
- earlier than IBM System z9-109 EC/BC will reduce system performance.
-
- Note that this option will also be selected by selecting the execute
- protection option below. Enabling the execute protection via the
- noexec kernel parameter will also switch the addressing modes,
- independent of the switch_amode kernel parameter.
-
-
config S390_EXEC_PROTECT
bool "Data execute protection"
- select S390_SWITCH_AMODE
help
This option allows to enable a buffer overflow protection for user
space programs and it also selects the addressing mode option above.
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index ab4464486b7a..f4e53c6708dc 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -185,7 +185,6 @@ CONFIG_HOTPLUG_CPU=y
CONFIG_COMPAT=y
CONFIG_SYSVIPC_COMPAT=y
CONFIG_AUDIT_ARCH=y
-CONFIG_S390_SWITCH_AMODE=y
CONFIG_S390_EXEC_PROTECT=y
#
diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h
index aea572009d60..fa487d4cc08b 100644
--- a/arch/s390/hypfs/hypfs.h
+++ b/arch/s390/hypfs/hypfs.h
@@ -11,6 +11,7 @@
#include <linux/fs.h>
#include <linux/types.h>
+#include <linux/debugfs.h>
#define REG_FILE_MODE 0440
#define UPDATE_FILE_MODE 0220
@@ -34,6 +35,9 @@ extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root);
/* VM Hypervisor */
extern int hypfs_vm_init(void);
+extern void hypfs_vm_exit(void);
extern int hypfs_vm_create_files(struct super_block *sb, struct dentry *root);
+/* Directory for debugfs files */
+extern struct dentry *hypfs_dbfs_dir;
#endif /* _HYPFS_H_ */
diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c
index 77df726180ba..70afd3c12cfc 100644
--- a/arch/s390/hypfs/hypfs_diag.c
+++ b/arch/s390/hypfs/hypfs_diag.c
@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
+#include <linux/mm.h>
#include <asm/ebcdic.h>
#include "hypfs.h"
@@ -23,6 +24,8 @@
#define CPU_NAME_LEN 16 /* type name len of cpus in diag224 name table */
#define TMP_SIZE 64 /* size of temporary buffers */
+#define DBFS_D204_HDR_VERSION 0
+
/* diag 204 subcodes */
enum diag204_sc {
SUBC_STIB4 = 4,
@@ -48,6 +51,8 @@ static void *diag204_buf; /* 4K aligned buffer for diag204 data */
static void *diag204_buf_vmalloc; /* vmalloc pointer for diag204 data */
static int diag204_buf_pages; /* number of pages for diag204 data */
+static struct dentry *dbfs_d204_file;
+
/*
* DIAG 204 data structures and member access functions.
*
@@ -365,18 +370,21 @@ static void diag204_free_buffer(void)
} else {
free_pages((unsigned long) diag204_buf, 0);
}
- diag204_buf_pages = 0;
diag204_buf = NULL;
}
+static void *page_align_ptr(void *ptr)
+{
+ return (void *) PAGE_ALIGN((unsigned long) ptr);
+}
+
static void *diag204_alloc_vbuf(int pages)
{
/* The buffer has to be page aligned! */
diag204_buf_vmalloc = vmalloc(PAGE_SIZE * (pages + 1));
if (!diag204_buf_vmalloc)
return ERR_PTR(-ENOMEM);
- diag204_buf = (void*)((unsigned long)diag204_buf_vmalloc
- & ~0xfffUL) + 0x1000;
+ diag204_buf = page_align_ptr(diag204_buf_vmalloc);
diag204_buf_pages = pages;
return diag204_buf;
}
@@ -469,17 +477,26 @@ fail_alloc:
return rc;
}
+static int diag204_do_store(void *buf, int pages)
+{
+ int rc;
+
+ rc = diag204((unsigned long) diag204_store_sc |
+ (unsigned long) diag204_info_type, pages, buf);
+ return rc < 0 ? -ENOSYS : 0;
+}
+
static void *diag204_store(void)
{
void *buf;
- int pages;
+ int pages, rc;
buf = diag204_get_buffer(diag204_info_type, &pages);
if (IS_ERR(buf))
goto out;
- if (diag204((unsigned long)diag204_store_sc |
- (unsigned long)diag204_info_type, pages, buf) < 0)
- return ERR_PTR(-ENOSYS);
+ rc = diag204_do_store(buf, pages);
+ if (rc)
+ return ERR_PTR(rc);
out:
return buf;
}
@@ -527,6 +544,92 @@ static int diag224_idx2name(int index, char *name)
return 0;
}
+struct dbfs_d204_hdr {
+ u64 len; /* Length of d204 buffer without header */
+ u16 version; /* Version of header */
+ u8 sc; /* Used subcode */
+ char reserved[53];
+} __attribute__ ((packed));
+
+struct dbfs_d204 {
+ struct dbfs_d204_hdr hdr; /* 64 byte header */
+ char buf[]; /* d204 buffer */
+} __attribute__ ((packed));
+
+struct dbfs_d204_private {
+ struct dbfs_d204 *d204; /* Aligned d204 data with header */
+ void *base; /* Base pointer (needed for vfree) */
+};
+
+static int dbfs_d204_open(struct inode *inode, struct file *file)
+{
+ struct dbfs_d204_private *data;
+ struct dbfs_d204 *d204;
+ int rc, buf_size;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ buf_size = PAGE_SIZE * (diag204_buf_pages + 1) + sizeof(d204->hdr);
+ data->base = vmalloc(buf_size);
+ if (!data->base) {
+ rc = -ENOMEM;
+ goto fail_kfree_data;
+ }
+ memset(data->base, 0, buf_size);
+ d204 = page_align_ptr(data->base + sizeof(d204->hdr))
+ - sizeof(d204->hdr);
+ rc = diag204_do_store(&d204->buf, diag204_buf_pages);
+ if (rc)
+ goto fail_vfree_base;
+ d204->hdr.version = DBFS_D204_HDR_VERSION;
+ d204->hdr.len = PAGE_SIZE * diag204_buf_pages;
+ d204->hdr.sc = diag204_store_sc;
+ data->d204 = d204;
+ file->private_data = data;
+ return 0;
+
+fail_vfree_base:
+ vfree(data->base);
+fail_kfree_data:
+ kfree(data);
+ return rc;
+}
+
+static int dbfs_d204_release(struct inode *inode, struct file *file)
+{
+ struct dbfs_d204_private *data = file->private_data;
+
+ vfree(data->base);
+ kfree(data);
+ return 0;
+}
+
+static ssize_t dbfs_d204_read(struct file *file, char __user *buf,
+ size_t size, loff_t *ppos)
+{
+ struct dbfs_d204_private *data = file->private_data;
+
+ return simple_read_from_buffer(buf, size, ppos, data->d204,
+ data->d204->hdr.len +
+ sizeof(data->d204->hdr));
+}
+
+static const struct file_operations dbfs_d204_ops = {
+ .open = dbfs_d204_open,
+ .read = dbfs_d204_read,
+ .release = dbfs_d204_release,
+};
+
+static int hypfs_dbfs_init(void)
+{
+ dbfs_d204_file = debugfs_create_file("d204_bin", 0400, hypfs_dbfs_dir,
+ NULL, &dbfs_d204_ops);
+ if (IS_ERR(dbfs_d204_file))
+ return PTR_ERR(dbfs_d204_file);
+ return 0;
+}
+
__init int hypfs_diag_init(void)
{
int rc;
@@ -541,11 +644,17 @@ __init int hypfs_diag_init(void)
pr_err("The hardware system does not provide all "
"functions required by hypfs\n");
}
+ if (diag204_info_type == INFO_EXT) {
+ rc = hypfs_dbfs_init();
+ if (rc)
+ diag204_free_buffer();
+ }
return rc;
}
void hypfs_diag_exit(void)
{
+ debugfs_remove(dbfs_d204_file);
diag224_delete_name_table();
diag204_free_buffer();
}
diff --git a/arch/s390/hypfs/hypfs_vm.c b/arch/s390/hypfs/hypfs_vm.c
index d01fc8f799f0..66efef57f225 100644
--- a/arch/s390/hypfs/hypfs_vm.c
+++ b/arch/s390/hypfs/hypfs_vm.c
@@ -10,14 +10,18 @@
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <asm/ebcdic.h>
+#include <asm/timex.h>
#include "hypfs.h"
#define NAME_LEN 8
+#define DBFS_D2FC_HDR_VERSION 0
static char local_guest[] = " ";
static char all_guests[] = "* ";
static char *guest_query;
+static struct dentry *dbfs_d2fc_file;
+
struct diag2fc_data {
__u32 version;
__u32 flags;
@@ -76,23 +80,26 @@ static int diag2fc(int size, char* query, void *addr)
return -residual_cnt;
}
-static struct diag2fc_data *diag2fc_store(char *query, int *count)
+/*
+ * Allocate buffer for "query" and store diag 2fc at "offset"
+ */
+static void *diag2fc_store(char *query, unsigned int *count, int offset)
{
+ void *data;
int size;
- struct diag2fc_data *data;
do {
size = diag2fc(0, query, NULL);
if (size < 0)
return ERR_PTR(-EACCES);
- data = vmalloc(size);
+ data = vmalloc(size + offset);
if (!data)
return ERR_PTR(-ENOMEM);
- if (diag2fc(size, query, data) == 0)
+ if (diag2fc(size, query, data + offset) == 0)
break;
vfree(data);
} while (1);
- *count = (size / sizeof(*data));
+ *count = (size / sizeof(struct diag2fc_data));
return data;
}
@@ -168,9 +175,10 @@ int hypfs_vm_create_files(struct super_block *sb, struct dentry *root)
{
struct dentry *dir, *file;
struct diag2fc_data *data;
- int rc, i, count = 0;
+ unsigned int count = 0;
+ int rc, i;
- data = diag2fc_store(guest_query, &count);
+ data = diag2fc_store(guest_query, &count, 0);
if (IS_ERR(data))
return PTR_ERR(data);
@@ -218,6 +226,57 @@ failed:
return rc;
}
+struct dbfs_d2fc_hdr {
+ u64 len; /* Length of d2fc buffer without header */
+ u16 version; /* Version of header */
+ char tod_ext[16]; /* TOD clock for d2fc */
+ u64 count; /* Number of VM guests in d2fc buffer */
+ char reserved[30];
+} __attribute__ ((packed));
+
+struct dbfs_d2fc {
+ struct dbfs_d2fc_hdr hdr; /* 64 byte header */
+ char buf[]; /* d2fc buffer */
+} __attribute__ ((packed));
+
+static int dbfs_d2fc_open(struct inode *inode, struct file *file)
+{
+ struct dbfs_d2fc *data;
+ unsigned int count;
+
+ data = diag2fc_store(guest_query, &count, sizeof(data->hdr));
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+ get_clock_ext(data->hdr.tod_ext);
+ data->hdr.len = count * sizeof(struct diag2fc_data);
+ data->hdr.version = DBFS_D2FC_HDR_VERSION;
+ data->hdr.count = count;
+ memset(&data->hdr.reserved, 0, sizeof(data->hdr.reserved));
+ file->private_data = data;
+ return 0;
+}
+
+static int dbfs_d2fc_release(struct inode *inode, struct file *file)
+{
+ diag2fc_free(file->private_data);
+ return 0;
+}
+
+static ssize_t dbfs_d2fc_read(struct file *file, char __user *buf,
+ size_t size, loff_t *ppos)
+{
+ struct dbfs_d2fc *data = file->private_data;
+
+ return simple_read_from_buffer(buf, size, ppos, data, data->hdr.len +
+ sizeof(struct dbfs_d2fc_hdr));
+}
+
+static const struct file_operations dbfs_d2fc_ops = {
+ .open = dbfs_d2fc_open,
+ .read = dbfs_d2fc_read,
+ .release = dbfs_d2fc_release,
+};
+
int hypfs_vm_init(void)
{
if (diag2fc(0, all_guests, NULL) > 0)
@@ -227,5 +286,15 @@ int hypfs_vm_init(void)
else
return -EACCES;
+ dbfs_d2fc_file = debugfs_create_file("d2fc_bin", 0400, hypfs_dbfs_dir,
+ NULL, &dbfs_d2fc_ops);
+ if (IS_ERR(dbfs_d2fc_file))
+ return PTR_ERR(dbfs_d2fc_file);
+
return 0;
}
+
+void hypfs_vm_exit(void)
+{
+ debugfs_remove(dbfs_d2fc_file);
+}
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index 341aff2687a5..c052394ab42a 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -46,6 +46,8 @@ static const struct super_operations hypfs_s_ops;
/* start of list of all dentries, which have to be deleted on update */
static struct dentry *hypfs_last_dentry;
+struct dentry *hypfs_dbfs_dir;
+
static void hypfs_update_update(struct super_block *sb)
{
struct hypfs_sb_info *sb_info = sb->s_fs_info;
@@ -484,14 +486,20 @@ static int __init hypfs_init(void)
{
int rc;
+ hypfs_dbfs_dir = debugfs_create_dir("s390_hypfs", NULL);
+ if (IS_ERR(hypfs_dbfs_dir))
+ return PTR_ERR(hypfs_dbfs_dir);
+
if (MACHINE_IS_VM) {
- if (hypfs_vm_init())
+ if (hypfs_vm_init()) {
/* no diag 2fc, just exit */
+ debugfs_remove(hypfs_dbfs_dir);
return -ENODATA;
+ }
} else {
if (hypfs_diag_init()) {
rc = -ENODATA;
- goto fail_diag;
+ goto fail_debugfs_remove;
}
}
s390_kobj = kobject_create_and_add("s390", hypervisor_kobj);
@@ -509,7 +517,9 @@ fail_filesystem:
fail_sysfs:
if (!MACHINE_IS_VM)
hypfs_diag_exit();
-fail_diag:
+fail_debugfs_remove:
+ debugfs_remove(hypfs_dbfs_dir);
+
pr_err("Initialization of hypfs failed with rc=%i\n", rc);
return rc;
}
@@ -518,6 +528,8 @@ static void __exit hypfs_exit(void)
{
if (!MACHINE_IS_VM)
hypfs_diag_exit();
+ else
+ hypfs_vm_exit();
unregister_filesystem(&hypfs_type);
kobject_put(s390_kobj);
}
diff --git a/arch/s390/include/asm/asm-offsets.h b/arch/s390/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/s390/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h
index ae7c8f9f94a5..2a113d6a7dfd 100644
--- a/arch/s390/include/asm/atomic.h
+++ b/arch/s390/include/asm/atomic.h
@@ -21,7 +21,7 @@
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
#define __CS_LOOP(ptr, op_val, op_string) ({ \
- typeof(ptr->counter) old_val, new_val; \
+ int old_val, new_val; \
asm volatile( \
" l %0,%2\n" \
"0: lr %1,%0\n" \
@@ -38,7 +38,7 @@
#else /* __GNUC__ */
#define __CS_LOOP(ptr, op_val, op_string) ({ \
- typeof(ptr->counter) old_val, new_val; \
+ int old_val, new_val; \
asm volatile( \
" l %0,0(%3)\n" \
"0: lr %1,%0\n" \
@@ -143,7 +143,7 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
#define __CSG_LOOP(ptr, op_val, op_string) ({ \
- typeof(ptr->counter) old_val, new_val; \
+ long long old_val, new_val; \
asm volatile( \
" lg %0,%2\n" \
"0: lgr %1,%0\n" \
@@ -160,7 +160,7 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
#else /* __GNUC__ */
#define __CSG_LOOP(ptr, op_val, op_string) ({ \
- typeof(ptr->counter) old_val, new_val; \
+ long long old_val, new_val; \
asm volatile( \
" lg %0,0(%3)\n" \
"0: lgr %1,%0\n" \
diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h
index 24b1244aadb9..f23961ada7fb 100644
--- a/arch/s390/include/asm/cputime.h
+++ b/arch/s390/include/asm/cputime.h
@@ -78,7 +78,7 @@ cputime64_to_jiffies64(cputime64_t cputime)
static inline unsigned int
cputime_to_msecs(const cputime_t cputime)
{
- return __div(cputime, 4096000);
+ return cputime_div(cputime, 4096000);
}
static inline cputime_t
@@ -160,7 +160,7 @@ cputime_to_timeval(const cputime_t cputime, struct timeval *value)
static inline clock_t
cputime_to_clock_t(cputime_t cputime)
{
- return __div(cputime, 4096000000ULL / USER_HZ);
+ return cputime_div(cputime, 4096000000ULL / USER_HZ);
}
static inline cputime_t
@@ -175,7 +175,7 @@ clock_t_to_cputime(unsigned long x)
static inline clock_t
cputime64_to_clock_t(cputime64_t cputime)
{
- return __div(cputime, 4096000000ULL / USER_HZ);
+ return cputime_div(cputime, 4096000000ULL / USER_HZ);
}
struct s390_idle_data {
diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h
index fc7edd6f41b6..976e273988c2 100644
--- a/arch/s390/include/asm/mmu_context.h
+++ b/arch/s390/include/asm/mmu_context.h
@@ -36,7 +36,7 @@ static inline int init_new_context(struct task_struct *tsk,
mm->context.has_pgste = 1;
mm->context.alloc_pgste = 1;
} else {
- mm->context.noexec = s390_noexec;
+ mm->context.noexec = (user_mode == SECONDARY_SPACE_MODE);
mm->context.has_pgste = 0;
mm->context.alloc_pgste = 0;
}
@@ -58,7 +58,7 @@ static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk)
pgd_t *pgd = mm->pgd;
S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd);
- if (switch_amode) {
+ if (user_mode != HOME_SPACE_MODE) {
/* Load primary space page table origin. */
pgd = mm->context.noexec ? get_shadow_table(pgd) : pgd;
S390_lowcore.user_exec_asce = mm->context.asce_bits | __pa(pgd);
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h
index ddad5903341c..68940d0bad91 100644
--- a/arch/s390/include/asm/pgalloc.h
+++ b/arch/s390/include/asm/pgalloc.h
@@ -143,7 +143,8 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
spin_lock_init(&mm->context.list_lock);
INIT_LIST_HEAD(&mm->context.crst_list);
INIT_LIST_HEAD(&mm->context.pgtable_list);
- return (pgd_t *) crst_table_alloc(mm, s390_noexec);
+ return (pgd_t *)
+ crst_table_alloc(mm, user_mode == SECONDARY_SPACE_MODE);
}
#define pgd_free(mm, pgd) crst_table_free(mm, (unsigned long *) pgd)
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h
index e37478e87286..52a779c337e8 100644
--- a/arch/s390/include/asm/setup.h
+++ b/arch/s390/include/asm/setup.h
@@ -49,17 +49,12 @@ extern unsigned long memory_end;
void detect_memory_layout(struct mem_chunk chunk[]);
-#ifdef CONFIG_S390_SWITCH_AMODE
-extern unsigned int switch_amode;
-#else
-#define switch_amode (0)
-#endif
-
-#ifdef CONFIG_S390_EXEC_PROTECT
-extern unsigned int s390_noexec;
-#else
-#define s390_noexec (0)
-#endif
+#define PRIMARY_SPACE_MODE 0
+#define ACCESS_REGISTER_MODE 1
+#define SECONDARY_SPACE_MODE 2
+#define HOME_SPACE_MODE 3
+
+extern unsigned int user_mode;
/*
* Machine features detected in head.S
diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h
index a868b272c257..2ab1141eeb50 100644
--- a/arch/s390/include/asm/smp.h
+++ b/arch/s390/include/asm/smp.h
@@ -1,57 +1,22 @@
/*
- * include/asm-s390/smp.h
- *
- * S390 version
- * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
- * Martin Schwidefsky (schwidefsky@de.ibm.com)
- * Heiko Carstens (heiko.carstens@de.ibm.com)
+ * Copyright IBM Corp. 1999,2009
+ * Author(s): Denis Joseph Barrow,
+ * Martin Schwidefsky <schwidefsky@de.ibm.com>,
+ * Heiko Carstens <heiko.carstens@de.ibm.com>,
*/
#ifndef __ASM_SMP_H
#define __ASM_SMP_H
-#include <linux/threads.h>
-#include <linux/cpumask.h>
-#include <linux/bitops.h>
+#ifdef CONFIG_SMP
-#if defined(__KERNEL__) && defined(CONFIG_SMP) && !defined(__ASSEMBLY__)
-
-#include <asm/lowcore.h>
-#include <asm/sigp.h>
-#include <asm/ptrace.h>
#include <asm/system.h>
-
-/*
- s390 specific smp.c headers
- */
-typedef struct
-{
- int intresting;
- sigp_ccode ccode;
- __u32 status;
- __u16 cpu;
-} sigp_info;
+#include <asm/sigp.h>
extern void machine_restart_smp(char *);
extern void machine_halt_smp(void);
extern void machine_power_off_smp(void);
-#define NO_PROC_ID 0xFF /* No processor magic marker */
-
-/*
- * This magic constant controls our willingness to transfer
- * a process across CPUs. Such a transfer incurs misses on the L1
- * cache, and on a P6 or P5 with multiple L2 caches L2 hits. My
- * gut feeling is this will vary by board in value. For a board
- * with separate L2 cache it probably depends also on the RSS, and
- * for a board with shared L2 cache it ought to decay fast as other
- * processes are run.
- */
-
-#define PROC_CHANGE_PENALTY 20 /* Schedule penalty */
-
#define raw_smp_processor_id() (S390_lowcore.cpu_nr)
-#define cpu_logical_map(cpu) (cpu)
extern int __cpu_disable (void);
extern void __cpu_die (unsigned int cpu);
@@ -64,7 +29,9 @@ extern int smp_cpu_polarization[];
extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
-#endif
+extern union save_area *zfcpdump_save_areas[NR_CPUS + 1];
+
+#endif /* CONFIG_SMP */
#ifdef CONFIG_HOTPLUG_CPU
extern int smp_rescan_cpus(void);
@@ -72,5 +39,4 @@ extern int smp_rescan_cpus(void);
static inline int smp_rescan_cpus(void) { return 0; }
#endif
-extern union save_area *zfcpdump_save_areas[NR_CPUS + 1];
-#endif
+#endif /* __ASM_SMP_H */
diff --git a/arch/s390/include/asm/socket.h b/arch/s390/include/asm/socket.h
index e42df89a0b85..fdff1e995c73 100644
--- a/arch/s390/include/asm/socket.h
+++ b/arch/s390/include/asm/socket.h
@@ -68,4 +68,6 @@
#define SO_PROTOCOL 38
#define SO_DOMAIN 39
+#define SO_RXQ_OVFL 40
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/s390/include/asm/sockios.h b/arch/s390/include/asm/sockios.h
index f4fc16c7da59..6f60eee73242 100644
--- a/arch/s390/include/asm/sockios.h
+++ b/arch/s390/include/asm/sockios.h
@@ -1,21 +1,6 @@
-/*
- * include/asm-s390/sockios.h
- *
- * S390 version
- *
- * Derived from "include/asm-i386/sockios.h"
- */
+#ifndef _ASM_S390_SOCKIOS_H
+#define _ASM_S390_SOCKIOS_H
-#ifndef __ARCH_S390_SOCKIOS__
-#define __ARCH_S390_SOCKIOS__
-
-/* Socket-level I/O control calls. */
-#define FIOSETOWN 0x8901
-#define SIOCSPGRP 0x8902
-#define FIOGETOWN 0x8903
-#define SIOCGPGRP 0x8904
-#define SIOCATMARK 0x8905
-#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */
-#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */
+#include <asm-generic/sockios.h>
#endif
diff --git a/arch/s390/include/asm/termbits.h b/arch/s390/include/asm/termbits.h
index 58731853d529..71bf6ac6a2b9 100644
--- a/arch/s390/include/asm/termbits.h
+++ b/arch/s390/include/asm/termbits.h
@@ -1,206 +1,6 @@
-/*
- * include/asm-s390/termbits.h
- *
- * S390 version
- *
- * Derived from "include/asm-i386/termbits.h"
- */
+#ifndef _ASM_S390_TERMBITS_H
+#define _ASM_S390_TERMBITS_H
-#ifndef __ARCH_S390_TERMBITS_H__
-#define __ARCH_S390_TERMBITS_H__
-
-#include <linux/posix_types.h>
-
-typedef unsigned char cc_t;
-typedef unsigned int speed_t;
-typedef unsigned int tcflag_t;
-
-#define NCCS 19
-struct termios {
- tcflag_t c_iflag; /* input mode flags */
- tcflag_t c_oflag; /* output mode flags */
- tcflag_t c_cflag; /* control mode flags */
- tcflag_t c_lflag; /* local mode flags */
- cc_t c_line; /* line discipline */
- cc_t c_cc[NCCS]; /* control characters */
-};
-
-struct termios2 {
- tcflag_t c_iflag; /* input mode flags */
- tcflag_t c_oflag; /* output mode flags */
- tcflag_t c_cflag; /* control mode flags */
- tcflag_t c_lflag; /* local mode flags */
- cc_t c_line; /* line discipline */
- cc_t c_cc[NCCS]; /* control characters */
- speed_t c_ispeed; /* input speed */
- speed_t c_ospeed; /* output speed */
-};
-
-struct ktermios {
- tcflag_t c_iflag; /* input mode flags */
- tcflag_t c_oflag; /* output mode flags */
- tcflag_t c_cflag; /* control mode flags */
- tcflag_t c_lflag; /* local mode flags */
- cc_t c_line; /* line discipline */
- cc_t c_cc[NCCS]; /* control characters */
- speed_t c_ispeed; /* input speed */
- speed_t c_ospeed; /* output speed */
-};
-
-/* c_cc characters */
-#define VINTR 0
-#define VQUIT 1
-#define VERASE 2
-#define VKILL 3
-#define VEOF 4
-#define VTIME 5
-#define VMIN 6
-#define VSWTC 7
-#define VSTART 8
-#define VSTOP 9
-#define VSUSP 10
-#define VEOL 11
-#define VREPRINT 12
-#define VDISCARD 13
-#define VWERASE 14
-#define VLNEXT 15
-#define VEOL2 16
-
-/* c_iflag bits */
-#define IGNBRK 0000001
-#define BRKINT 0000002
-#define IGNPAR 0000004
-#define PARMRK 0000010
-#define INPCK 0000020
-#define ISTRIP 0000040
-#define INLCR 0000100
-#define IGNCR 0000200
-#define ICRNL 0000400
-#define IUCLC 0001000
-#define IXON 0002000
-#define IXANY 0004000
-#define IXOFF 0010000
-#define IMAXBEL 0020000
-#define IUTF8 0040000
-
-/* c_oflag bits */
-#define OPOST 0000001
-#define OLCUC 0000002
-#define ONLCR 0000004
-#define OCRNL 0000010
-#define ONOCR 0000020
-#define ONLRET 0000040
-#define OFILL 0000100
-#define OFDEL 0000200
-#define NLDLY 0000400
-#define NL0 0000000
-#define NL1 0000400
-#define CRDLY 0003000
-#define CR0 0000000
-#define CR1 0001000
-#define CR2 0002000
-#define CR3 0003000
-#define TABDLY 0014000
-#define TAB0 0000000
-#define TAB1 0004000
-#define TAB2 0010000
-#define TAB3 0014000
-#define XTABS 0014000
-#define BSDLY 0020000
-#define BS0 0000000
-#define BS1 0020000
-#define VTDLY 0040000
-#define VT0 0000000
-#define VT1 0040000
-#define FFDLY 0100000
-#define FF0 0000000
-#define FF1 0100000
-
-/* c_cflag bit meaning */
-#define CBAUD 0010017
-#define B0 0000000 /* hang up */
-#define B50 0000001
-#define B75 0000002
-#define B110 0000003
-#define B134 0000004
-#define B150 0000005
-#define B200 0000006
-#define B300 0000007
-#define B600 0000010
-#define B1200 0000011
-#define B1800 0000012
-#define B2400 0000013
-#define B4800 0000014
-#define B9600 0000015
-#define B19200 0000016
-#define B38400 0000017
-#define EXTA B19200
-#define EXTB B38400
-#define CSIZE 0000060
-#define CS5 0000000
-#define CS6 0000020
-#define CS7 0000040
-#define CS8 0000060
-#define CSTOPB 0000100
-#define CREAD 0000200
-#define PARENB 0000400
-#define PARODD 0001000
-#define HUPCL 0002000
-#define CLOCAL 0004000
-#define CBAUDEX 0010000
-#define BOTHER 0010000
-#define B57600 0010001
-#define B115200 0010002
-#define B230400 0010003
-#define B460800 0010004
-#define B500000 0010005
-#define B576000 0010006
-#define B921600 0010007
-#define B1000000 0010010
-#define B1152000 0010011
-#define B1500000 0010012
-#define B2000000 0010013
-#define B2500000 0010014
-#define B3000000 0010015
-#define B3500000 0010016
-#define B4000000 0010017
-#define CIBAUD 002003600000 /* input baud rate */
-#define CMSPAR 010000000000 /* mark or space (stick) parity */
-#define CRTSCTS 020000000000 /* flow control */
-
-#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
-
-/* c_lflag bits */
-#define ISIG 0000001
-#define ICANON 0000002
-#define XCASE 0000004
-#define ECHO 0000010
-#define ECHOE 0000020
-#define ECHOK 0000040
-#define ECHONL 0000100
-#define NOFLSH 0000200
-#define TOSTOP 0000400
-#define ECHOCTL 0001000
-#define ECHOPRT 0002000
-#define ECHOKE 0004000
-#define FLUSHO 0010000
-#define PENDIN 0040000
-#define IEXTEN 0100000
-
-/* tcflow() and TCXONC use these */
-#define TCOOFF 0
-#define TCOON 1
-#define TCIOFF 2
-#define TCION 3
-
-/* tcflush() and TCFLSH use these */
-#define TCIFLUSH 0
-#define TCOFLUSH 1
-#define TCIOFLUSH 2
-
-/* tcsetattr uses these */
-#define TCSANOW 0
-#define TCSADRAIN 1
-#define TCSAFLUSH 2
+#include <asm-generic/termbits.h>
#endif
diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h
index 68d9fea34b4b..1277caf1a186 100644
--- a/arch/s390/include/asm/timex.h
+++ b/arch/s390/include/asm/timex.h
@@ -65,17 +65,20 @@ static inline unsigned long long get_clock (void)
return clk;
}
-static inline unsigned long long get_clock_xt(void)
+static inline void get_clock_ext(char *clk)
{
- unsigned char clk[16];
-
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
- asm volatile("stcke %0" : "=Q" (clk) : : "cc");
+ asm volatile("stcke %0" : "=Q" (*clk) : : "cc");
#else /* __GNUC__ */
- asm volatile("stcke 0(%1)" : "=m" (clk)
+ asm volatile("stcke 0(%1)" : "=m" (*clk)
: "a" (clk) : "cc");
#endif /* __GNUC__ */
+}
+static inline unsigned long long get_clock_xt(void)
+{
+ unsigned char clk[16];
+ get_clock_ext(clk);
return *((unsigned long long *)&clk[1]);
}
diff --git a/arch/s390/include/asm/todclk.h b/arch/s390/include/asm/todclk.h
deleted file mode 100644
index c7f62055488a..000000000000
--- a/arch/s390/include/asm/todclk.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * File...........: linux/include/asm/todclk.h
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
- *
- * History of changes (starts July 2000)
- */
-
-#ifndef __ASM_TODCLK_H
-#define __ASM_TODCLK_H
-
-#ifdef __KERNEL__
-
-#define TOD_uSEC (0x1000ULL)
-#define TOD_mSEC (1000 * TOD_uSEC)
-#define TOD_SEC (1000 * TOD_mSEC)
-#define TOD_MIN (60 * TOD_SEC)
-#define TOD_HOUR (60 * TOD_MIN)
-
-#endif
-
-#endif
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index 8377e91533d2..cbf0a8745bf4 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -93,6 +93,8 @@ extern struct uaccess_ops uaccess_mvcos;
extern struct uaccess_ops uaccess_mvcos_switch;
extern struct uaccess_ops uaccess_pt;
+extern int __handle_fault(unsigned long, unsigned long, int);
+
static inline int __put_user_fn(size_t size, void __user *ptr, void *x)
{
size = uaccess.copy_to_user_small(size, ptr, x);
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c
index f5fe34dd821b..5a82bc68193e 100644
--- a/arch/s390/kernel/ftrace.c
+++ b/arch/s390/kernel/ftrace.c
@@ -203,73 +203,10 @@ out:
#ifdef CONFIG_FTRACE_SYSCALLS
-extern unsigned long __start_syscalls_metadata[];
-extern unsigned long __stop_syscalls_metadata[];
extern unsigned int sys_call_table[];
-static struct syscall_metadata **syscalls_metadata;
-
-struct syscall_metadata *syscall_nr_to_meta(int nr)
-{
- if (!syscalls_metadata || nr >= NR_syscalls || nr < 0)
- return NULL;
-
- return syscalls_metadata[nr];
-}
-
-int syscall_name_to_nr(char *name)
-{
- int i;
-
- if (!syscalls_metadata)
- return -1;
- for (i = 0; i < NR_syscalls; i++)
- if (syscalls_metadata[i])
- if (!strcmp(syscalls_metadata[i]->name, name))
- return i;
- return -1;
-}
-
-void set_syscall_enter_id(int num, int id)
-{
- syscalls_metadata[num]->enter_id = id;
-}
-
-void set_syscall_exit_id(int num, int id)
+unsigned long __init arch_syscall_addr(int nr)
{
- syscalls_metadata[num]->exit_id = id;
-}
-
-static struct syscall_metadata *find_syscall_meta(unsigned long syscall)
-{
- struct syscall_metadata *start;
- struct syscall_metadata *stop;
- char str[KSYM_SYMBOL_LEN];
-
- start = (struct syscall_metadata *)__start_syscalls_metadata;
- stop = (struct syscall_metadata *)__stop_syscalls_metadata;
- kallsyms_lookup(syscall, NULL, NULL, NULL, str);
-
- for ( ; start < stop; start++) {
- if (start->name && !strcmp(start->name + 3, str + 3))
- return start;
- }
- return NULL;
-}
-
-static int __init arch_init_ftrace_syscalls(void)
-{
- struct syscall_metadata *meta;
- int i;
- syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * NR_syscalls,
- GFP_KERNEL);
- if (!syscalls_metadata)
- return -ENOMEM;
- for (i = 0; i < NR_syscalls; i++) {
- meta = find_syscall_meta((unsigned long)sys_call_table[i]);
- syscalls_metadata[i] = meta;
- }
- return 0;
+ return (unsigned long)sys_call_table[nr];
}
-arch_initcall(arch_init_ftrace_syscalls);
#endif
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index ee57a42e6e93..4890ac6d7faa 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -1595,10 +1595,9 @@ static void stop_run(struct shutdown_trigger *trigger)
{
if (strcmp(trigger->name, ON_PANIC_STR) == 0)
disabled_wait((unsigned long) __builtin_return_address(0));
- else {
- signal_processor(smp_processor_id(), sigp_stop);
- for (;;);
- }
+ while (signal_processor(smp_processor_id(), sigp_stop) == sigp_busy)
+ cpu_relax();
+ for (;;);
}
static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR,
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 061479ff029f..0663287fa1b3 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -305,9 +305,8 @@ static int __init early_parse_mem(char *p)
}
early_param("mem", early_parse_mem);
-#ifdef CONFIG_S390_SWITCH_AMODE
-unsigned int switch_amode = 0;
-EXPORT_SYMBOL_GPL(switch_amode);
+unsigned int user_mode = HOME_SPACE_MODE;
+EXPORT_SYMBOL_GPL(user_mode);
static int set_amode_and_uaccess(unsigned long user_amode,
unsigned long user32_amode)
@@ -340,23 +339,29 @@ static int set_amode_and_uaccess(unsigned long user_amode,
*/
static int __init early_parse_switch_amode(char *p)
{
- switch_amode = 1;
+ if (user_mode != SECONDARY_SPACE_MODE)
+ user_mode = PRIMARY_SPACE_MODE;
return 0;
}
early_param("switch_amode", early_parse_switch_amode);
-#else /* CONFIG_S390_SWITCH_AMODE */
-static inline int set_amode_and_uaccess(unsigned long user_amode,
- unsigned long user32_amode)
+static int __init early_parse_user_mode(char *p)
{
+ if (p && strcmp(p, "primary") == 0)
+ user_mode = PRIMARY_SPACE_MODE;
+#ifdef CONFIG_S390_EXEC_PROTECT
+ else if (p && strcmp(p, "secondary") == 0)
+ user_mode = SECONDARY_SPACE_MODE;
+#endif
+ else if (!p || strcmp(p, "home") == 0)
+ user_mode = HOME_SPACE_MODE;
+ else
+ return 1;
return 0;
}
-#endif /* CONFIG_S390_SWITCH_AMODE */
+early_param("user_mode", early_parse_user_mode);
#ifdef CONFIG_S390_EXEC_PROTECT
-unsigned int s390_noexec = 0;
-EXPORT_SYMBOL_GPL(s390_noexec);
-
/*
* Enable execute protection?
*/
@@ -364,8 +369,7 @@ static int __init early_parse_noexec(char *p)
{
if (!strncmp(p, "off", 3))
return 0;
- switch_amode = 1;
- s390_noexec = 1;
+ user_mode = SECONDARY_SPACE_MODE;
return 0;
}
early_param("noexec", early_parse_noexec);
@@ -373,7 +377,7 @@ early_param("noexec", early_parse_noexec);
static void setup_addressing_mode(void)
{
- if (s390_noexec) {
+ if (user_mode == SECONDARY_SPACE_MODE) {
if (set_amode_and_uaccess(PSW_ASC_SECONDARY,
PSW32_ASC_SECONDARY))
pr_info("Execute protection active, "
@@ -381,7 +385,7 @@ static void setup_addressing_mode(void)
else
pr_info("Execute protection active, "
"mvcos not available\n");
- } else if (switch_amode) {
+ } else if (user_mode == PRIMARY_SPACE_MODE) {
if (set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY))
pr_info("Address spaces switched, "
"mvcos available\n");
@@ -411,7 +415,7 @@ setup_lowcore(void)
lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
lc->restart_psw.addr =
PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
- if (switch_amode)
+ if (user_mode != HOME_SPACE_MODE)
lc->restart_psw.mask |= PSW_ASC_HOME;
lc->external_new_psw.mask = psw_kernel_bits;
lc->external_new_psw.addr =
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index c932caa5e850..93e52039321b 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -76,7 +76,6 @@ static int cpu_stopped(int cpu)
__u32 status;
switch (signal_processor_ps(&status, 0, cpu, sigp_sense)) {
- case sigp_order_code_accepted:
case sigp_status_stored:
/* Check for stopped and check stop state */
if (status & 0x50)
@@ -638,6 +637,8 @@ void __cpu_die(unsigned int cpu)
/* Wait until target cpu is down */
while (!cpu_stopped(cpu))
cpu_relax();
+ while (signal_processor_p(0, cpu, sigp_set_prefix) == sigp_busy)
+ udelay(10);
smp_free_lowcore(cpu);
pr_info("Processor %d stopped\n", cpu);
}
@@ -645,8 +646,8 @@ void __cpu_die(unsigned int cpu)
void cpu_die(void)
{
idle_task_exit();
- signal_processor(smp_processor_id(), sigp_stop);
- BUG();
+ while (signal_processor(smp_processor_id(), sigp_stop) == sigp_busy)
+ cpu_relax();
for (;;);
}
diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S
index 7c8653e27db6..da2c9e2b7455 100644
--- a/arch/s390/kernel/swsusp_asm64.S
+++ b/arch/s390/kernel/swsusp_asm64.S
@@ -206,6 +206,7 @@ restart_suspend:
llgh %r2,0(%r1)
7:
sigp %r9,%r2,__SIGP_SENSE /* Wait for resume CPU */
+ brc 8,7b /* accepted, status 0, still running */
brc 2,7b /* busy, try again */
tmll %r9,0x40 /* Test if resume CPU is stopped */
jz 7b
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c
index adfb32aa6d59..5f99e66c51c3 100644
--- a/arch/s390/kernel/vdso.c
+++ b/arch/s390/kernel/vdso.c
@@ -86,7 +86,8 @@ static void vdso_init_data(struct vdso_data *vd)
unsigned int facility_list;
facility_list = stfl();
- vd->ectg_available = switch_amode && (facility_list & 1);
+ vd->ectg_available =
+ user_mode != HOME_SPACE_MODE && (facility_list & 1);
}
#ifdef CONFIG_64BIT
@@ -114,7 +115,7 @@ int vdso_alloc_per_cpu(int cpu, struct _lowcore *lowcore)
lowcore->vdso_per_cpu_data = __LC_PASTE;
- if (!switch_amode || !vdso_enabled)
+ if (user_mode == HOME_SPACE_MODE || !vdso_enabled)
return 0;
segment_table = __get_free_pages(GFP_KERNEL, SEGMENT_ORDER);
@@ -160,7 +161,7 @@ void vdso_free_per_cpu(int cpu, struct _lowcore *lowcore)
unsigned long segment_table, page_table, page_frame;
u32 *psal, *aste;
- if (!switch_amode || !vdso_enabled)
+ if (user_mode == HOME_SPACE_MODE || !vdso_enabled)
return;
psal = (u32 *)(addr_t) lowcore->paste[4];
@@ -184,7 +185,7 @@ static void __vdso_init_cr5(void *dummy)
static void vdso_init_cr5(void)
{
- if (switch_amode && vdso_enabled)
+ if (user_mode != HOME_SPACE_MODE && vdso_enabled)
on_each_cpu(__vdso_init_cr5, NULL, 1);
}
#endif /* CONFIG_64BIT */
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig
index bf164fc21864..6ee55ae84ce2 100644
--- a/arch/s390/kvm/Kconfig
+++ b/arch/s390/kvm/Kconfig
@@ -20,7 +20,6 @@ config KVM
depends on HAVE_KVM && EXPERIMENTAL
select PREEMPT_NOTIFIERS
select ANON_INODES
- select S390_SWITCH_AMODE
---help---
Support hosting paravirtualized guest machines using the SIE
virtualization capability on the mainframe. This should work
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 07ced89740d7..544505893c9f 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -74,9 +74,10 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
static unsigned long long *facilities;
/* Section: not file related */
-void kvm_arch_hardware_enable(void *garbage)
+int kvm_arch_hardware_enable(void *garbage)
{
/* every s390 is virtualization enabled ;-) */
+ return 0;
}
void kvm_arch_hardware_disable(void *garbage)
@@ -150,7 +151,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
break;
}
default:
- r = -EINVAL;
+ r = -ENOTTY;
}
return r;
diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c
index 58da3f461214..60455f104ea3 100644
--- a/arch/s390/lib/uaccess_mvcos.c
+++ b/arch/s390/lib/uaccess_mvcos.c
@@ -162,7 +162,6 @@ static size_t clear_user_mvcos(size_t size, void __user *to)
return size;
}
-#ifdef CONFIG_S390_SWITCH_AMODE
static size_t strnlen_user_mvcos(size_t count, const char __user *src)
{
char buf[256];
@@ -200,7 +199,6 @@ static size_t strncpy_from_user_mvcos(size_t count, const char __user *src,
} while ((len_str == len) && (done < count));
return done;
}
-#endif /* CONFIG_S390_SWITCH_AMODE */
struct uaccess_ops uaccess_mvcos = {
.copy_from_user = copy_from_user_mvcos_check,
@@ -215,7 +213,6 @@ struct uaccess_ops uaccess_mvcos = {
.futex_atomic_cmpxchg = futex_atomic_cmpxchg_std,
};
-#ifdef CONFIG_S390_SWITCH_AMODE
struct uaccess_ops uaccess_mvcos_switch = {
.copy_from_user = copy_from_user_mvcos,
.copy_from_user_small = copy_from_user_mvcos,
@@ -228,4 +225,3 @@ struct uaccess_ops uaccess_mvcos_switch = {
.futex_atomic_op = futex_atomic_op_pt,
.futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt,
};
-#endif
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index cb5d59eab0ee..404f2de296dc 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -23,86 +23,21 @@ static inline pte_t *follow_table(struct mm_struct *mm, unsigned long addr)
pgd = pgd_offset(mm, addr);
if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
- return NULL;
+ return (pte_t *) 0x3a;
pud = pud_offset(pgd, addr);
if (pud_none(*pud) || unlikely(pud_bad(*pud)))
- return NULL;
+ return (pte_t *) 0x3b;
pmd = pmd_offset(pud, addr);
if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
- return NULL;
+ return (pte_t *) 0x10;
return pte_offset_map(pmd, addr);
}
-static int __handle_fault(struct mm_struct *mm, unsigned long address,
- int write_access)
-{
- struct vm_area_struct *vma;
- int ret = -EFAULT;
- int fault;
-
- if (in_atomic())
- return ret;
- down_read(&mm->mmap_sem);
- vma = find_vma(mm, address);
- if (unlikely(!vma))
- goto out;
- if (unlikely(vma->vm_start > address)) {
- if (!(vma->vm_flags & VM_GROWSDOWN))
- goto out;
- if (expand_stack(vma, address))
- goto out;
- }
-
- if (!write_access) {
- /* page not present, check vm flags */
- if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
- goto out;
- } else {
- if (!(vma->vm_flags & VM_WRITE))
- goto out;
- }
-
-survive:
- fault = handle_mm_fault(mm, vma, address, write_access ? FAULT_FLAG_WRITE : 0);
- if (unlikely(fault & VM_FAULT_ERROR)) {
- if (fault & VM_FAULT_OOM)
- goto out_of_memory;
- else if (fault & VM_FAULT_SIGBUS)
- goto out_sigbus;
- BUG();
- }
- if (fault & VM_FAULT_MAJOR)
- current->maj_flt++;
- else
- current->min_flt++;
- ret = 0;
-out:
- up_read(&mm->mmap_sem);
- return ret;
-
-out_of_memory:
- up_read(&mm->mmap_sem);
- if (is_global_init(current)) {
- yield();
- down_read(&mm->mmap_sem);
- goto survive;
- }
- printk("VM: killing process %s\n", current->comm);
- return ret;
-
-out_sigbus:
- up_read(&mm->mmap_sem);
- current->thread.prot_addr = address;
- current->thread.trap_no = 0x11;
- force_sig(SIGBUS, current);
- return ret;
-}
-
-static size_t __user_copy_pt(unsigned long uaddr, void *kptr,
- size_t n, int write_user)
+static __always_inline size_t __user_copy_pt(unsigned long uaddr, void *kptr,
+ size_t n, int write_user)
{
struct mm_struct *mm = current->mm;
unsigned long offset, pfn, done, size;
@@ -114,12 +49,17 @@ retry:
spin_lock(&mm->page_table_lock);
do {
pte = follow_table(mm, uaddr);
- if (!pte || !pte_present(*pte) ||
- (write_user && !pte_write(*pte)))
+ if ((unsigned long) pte < 0x1000)
goto fault;
+ if (!pte_present(*pte)) {
+ pte = (pte_t *) 0x11;
+ goto fault;
+ } else if (write_user && !pte_write(*pte)) {
+ pte = (pte_t *) 0x04;
+ goto fault;
+ }
pfn = pte_pfn(*pte);
-
offset = uaddr & (PAGE_SIZE - 1);
size = min(n - done, PAGE_SIZE - offset);
if (write_user) {
@@ -137,7 +77,7 @@ retry:
return n - done;
fault:
spin_unlock(&mm->page_table_lock);
- if (__handle_fault(mm, uaddr, write_user))
+ if (__handle_fault(uaddr, (unsigned long) pte, write_user))
return n - done;
goto retry;
}
@@ -146,30 +86,31 @@ fault:
* Do DAT for user address by page table walk, return kernel address.
* This function needs to be called with current->mm->page_table_lock held.
*/
-static unsigned long __dat_user_addr(unsigned long uaddr)
+static __always_inline unsigned long __dat_user_addr(unsigned long uaddr)
{
struct mm_struct *mm = current->mm;
- unsigned long pfn, ret;
+ unsigned long pfn;
pte_t *pte;
int rc;
- ret = 0;
retry:
pte = follow_table(mm, uaddr);
- if (!pte || !pte_present(*pte))
+ if ((unsigned long) pte < 0x1000)
goto fault;
+ if (!pte_present(*pte)) {
+ pte = (pte_t *) 0x11;
+ goto fault;
+ }
pfn = pte_pfn(*pte);
- ret = (pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE - 1));
-out:
- return ret;
+ return (pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE - 1));
fault:
spin_unlock(&mm->page_table_lock);
- rc = __handle_fault(mm, uaddr, 0);
+ rc = __handle_fault(uaddr, (unsigned long) pte, 0);
spin_lock(&mm->page_table_lock);
- if (rc)
- goto out;
- goto retry;
+ if (!rc)
+ goto retry;
+ return 0;
}
size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
@@ -234,8 +175,12 @@ retry:
spin_lock(&mm->page_table_lock);
do {
pte = follow_table(mm, uaddr);
- if (!pte || !pte_present(*pte))
+ if ((unsigned long) pte < 0x1000)
+ goto fault;
+ if (!pte_present(*pte)) {
+ pte = (pte_t *) 0x11;
goto fault;
+ }
pfn = pte_pfn(*pte);
offset = uaddr & (PAGE_SIZE-1);
@@ -249,9 +194,8 @@ retry:
return done + 1;
fault:
spin_unlock(&mm->page_table_lock);
- if (__handle_fault(mm, uaddr, 0)) {
+ if (__handle_fault(uaddr, (unsigned long) pte, 0))
return 0;
- }
goto retry;
}
@@ -284,7 +228,7 @@ static size_t copy_in_user_pt(size_t n, void __user *to,
{
struct mm_struct *mm = current->mm;
unsigned long offset_from, offset_to, offset_max, pfn_from, pfn_to,
- uaddr, done, size;
+ uaddr, done, size, error_code;
unsigned long uaddr_from = (unsigned long) from;
unsigned long uaddr_to = (unsigned long) to;
pte_t *pte_from, *pte_to;
@@ -298,17 +242,28 @@ static size_t copy_in_user_pt(size_t n, void __user *to,
retry:
spin_lock(&mm->page_table_lock);
do {
+ write_user = 0;
+ uaddr = uaddr_from;
pte_from = follow_table(mm, uaddr_from);
- if (!pte_from || !pte_present(*pte_from)) {
- uaddr = uaddr_from;
- write_user = 0;
+ error_code = (unsigned long) pte_from;
+ if (error_code < 0x1000)
+ goto fault;
+ if (!pte_present(*pte_from)) {
+ error_code = 0x11;
goto fault;
}
+ write_user = 1;
+ uaddr = uaddr_to;
pte_to = follow_table(mm, uaddr_to);
- if (!pte_to || !pte_present(*pte_to) || !pte_write(*pte_to)) {
- uaddr = uaddr_to;
- write_user = 1;
+ error_code = (unsigned long) pte_to;
+ if (error_code < 0x1000)
+ goto fault;
+ if (!pte_present(*pte_to)) {
+ error_code = 0x11;
+ goto fault;
+ } else if (!pte_write(*pte_to)) {
+ error_code = 0x04;
goto fault;
}
@@ -329,7 +284,7 @@ retry:
return n - done;
fault:
spin_unlock(&mm->page_table_lock);
- if (__handle_fault(mm, uaddr, write_user))
+ if (__handle_fault(uaddr, error_code, write_user))
return n - done;
goto retry;
}
diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c
index b201135cc18c..5e5f3849660f 100644
--- a/arch/s390/mm/cmm.c
+++ b/arch/s390/mm/cmm.c
@@ -18,6 +18,7 @@
#include <linux/swap.h>
#include <linux/kthread.h>
#include <linux/oom.h>
+#include <linux/suspend.h>
#include <asm/pgalloc.h>
#include <asm/uaccess.h>
@@ -44,6 +45,7 @@ static volatile long cmm_pages_target;
static volatile long cmm_timed_pages_target;
static long cmm_timeout_pages;
static long cmm_timeout_seconds;
+static int cmm_suspended;
static struct cmm_page_array *cmm_page_list;
static struct cmm_page_array *cmm_timed_page_list;
@@ -147,9 +149,9 @@ cmm_thread(void *dummy)
while (1) {
rc = wait_event_interruptible(cmm_thread_wait,
- (cmm_pages != cmm_pages_target ||
- cmm_timed_pages != cmm_timed_pages_target ||
- kthread_should_stop()));
+ (!cmm_suspended && (cmm_pages != cmm_pages_target ||
+ cmm_timed_pages != cmm_timed_pages_target)) ||
+ kthread_should_stop());
if (kthread_should_stop() || rc == -ERESTARTSYS) {
cmm_pages_target = cmm_pages;
cmm_timed_pages_target = cmm_timed_pages;
@@ -411,6 +413,38 @@ cmm_smsg_target(char *from, char *msg)
static struct ctl_table_header *cmm_sysctl_header;
+static int cmm_suspend(void)
+{
+ cmm_suspended = 1;
+ cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
+ cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);
+ return 0;
+}
+
+static int cmm_resume(void)
+{
+ cmm_suspended = 0;
+ cmm_kick_thread();
+ return 0;
+}
+
+static int cmm_power_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ switch (event) {
+ case PM_POST_HIBERNATION:
+ return cmm_resume();
+ case PM_HIBERNATION_PREPARE:
+ return cmm_suspend();
+ default:
+ return NOTIFY_DONE;
+ }
+}
+
+static struct notifier_block cmm_power_notifier = {
+ .notifier_call = cmm_power_event,
+};
+
static int
cmm_init (void)
{
@@ -419,7 +453,7 @@ cmm_init (void)
#ifdef CONFIG_CMM_PROC
cmm_sysctl_header = register_sysctl_table(cmm_dir_table);
if (!cmm_sysctl_header)
- goto out;
+ goto out_sysctl;
#endif
#ifdef CONFIG_CMM_IUCV
rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
@@ -429,17 +463,21 @@ cmm_init (void)
rc = register_oom_notifier(&cmm_oom_nb);
if (rc < 0)
goto out_oom_notify;
+ rc = register_pm_notifier(&cmm_power_notifier);
+ if (rc)
+ goto out_pm;
init_waitqueue_head(&cmm_thread_wait);
init_timer(&cmm_timer);
cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread");
rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0;
- if (!rc)
- goto out;
- /*
- * kthread_create failed. undo all the stuff from above again.
- */
- unregister_oom_notifier(&cmm_oom_nb);
+ if (rc)
+ goto out_kthread;
+ return 0;
+out_kthread:
+ unregister_pm_notifier(&cmm_power_notifier);
+out_pm:
+ unregister_oom_notifier(&cmm_oom_nb);
out_oom_notify:
#ifdef CONFIG_CMM_IUCV
smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target);
@@ -447,8 +485,8 @@ out_smsg:
#endif
#ifdef CONFIG_CMM_PROC
unregister_sysctl_table(cmm_sysctl_header);
+out_sysctl:
#endif
-out:
return rc;
}
@@ -456,6 +494,7 @@ static void
cmm_exit(void)
{
kthread_stop(cmm_thread_ptr);
+ unregister_pm_notifier(&cmm_power_notifier);
unregister_oom_notifier(&cmm_oom_nb);
cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 6d507462967a..4e73e8bc90db 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -34,16 +34,15 @@
#include <asm/pgtable.h>
#include <asm/s390_ext.h>
#include <asm/mmu_context.h>
+#include <asm/compat.h>
#include "../kernel/entry.h"
#ifndef CONFIG_64BIT
#define __FAIL_ADDR_MASK 0x7ffff000
-#define __FIXUP_MASK 0x7fffffff
#define __SUBCODE_MASK 0x0200
#define __PF_RES_FIELD 0ULL
#else /* CONFIG_64BIT */
#define __FAIL_ADDR_MASK -4096L
-#define __FIXUP_MASK ~0L
#define __SUBCODE_MASK 0x0600
#define __PF_RES_FIELD 0x8000000000000000ULL
#endif /* CONFIG_64BIT */
@@ -52,27 +51,25 @@
extern int sysctl_userprocess_debug;
#endif
-#ifdef CONFIG_KPROBES
-static inline int notify_page_fault(struct pt_regs *regs, long err)
+#define VM_FAULT_BADCONTEXT 0x010000
+#define VM_FAULT_BADMAP 0x020000
+#define VM_FAULT_BADACCESS 0x040000
+
+static inline int notify_page_fault(struct pt_regs *regs)
{
int ret = 0;
+#ifdef CONFIG_KPROBES
/* kprobe_running() needs smp_processor_id() */
- if (!user_mode(regs)) {
+ if (!user_mode(regs) && kprobe_running()) {
preempt_disable();
if (kprobe_running() && kprobe_fault_handler(regs, 14))
ret = 1;
preempt_enable();
}
-
+#endif
return ret;
}
-#else
-static inline int notify_page_fault(struct pt_regs *regs, long err)
-{
- return 0;
-}
-#endif
/*
@@ -100,57 +97,50 @@ void bust_spinlocks(int yes)
/*
* Returns the address space associated with the fault.
- * Returns 0 for kernel space, 1 for user space and
- * 2 for code execution in user space with noexec=on.
+ * Returns 0 for kernel space and 1 for user space.
*/
-static inline int check_space(struct task_struct *tsk)
+static inline int user_space_fault(unsigned long trans_exc_code)
{
/*
- * The lowest two bits of S390_lowcore.trans_exc_code
- * indicate which paging table was used.
+ * The lowest two bits of the translation exception
+ * identification indicate which paging table was used.
*/
- int desc = S390_lowcore.trans_exc_code & 3;
-
- if (desc == 3) /* Home Segment Table Descriptor */
- return switch_amode == 0;
- if (desc == 2) /* Secondary Segment Table Descriptor */
- return tsk->thread.mm_segment.ar4;
-#ifdef CONFIG_S390_SWITCH_AMODE
- if (unlikely(desc == 1)) { /* STD determined via access register */
- /* %a0 always indicates primary space. */
- if (S390_lowcore.exc_access_id != 0) {
- save_access_regs(tsk->thread.acrs);
- /*
- * An alet of 0 indicates primary space.
- * An alet of 1 indicates secondary space.
- * Any other alet values generate an
- * alen-translation exception.
- */
- if (tsk->thread.acrs[S390_lowcore.exc_access_id])
- return tsk->thread.mm_segment.ar4;
- }
- }
-#endif
- /* Primary Segment Table Descriptor */
- return switch_amode << s390_noexec;
+ trans_exc_code &= 3;
+ if (trans_exc_code == 2)
+ /* Access via secondary space, set_fs setting decides */
+ return current->thread.mm_segment.ar4;
+ if (user_mode == HOME_SPACE_MODE)
+ /* User space if the access has been done via home space. */
+ return trans_exc_code == 3;
+ /*
+ * If the user space is not the home space the kernel runs in home
+ * space. Access via secondary space has already been covered,
+ * access via primary space or access register is from user space
+ * and access via home space is from the kernel.
+ */
+ return trans_exc_code != 3;
}
/*
* Send SIGSEGV to task. This is an external routine
* to keep the stack usage of do_page_fault small.
*/
-static void do_sigsegv(struct pt_regs *regs, unsigned long error_code,
- int si_code, unsigned long address)
+static noinline void do_sigsegv(struct pt_regs *regs, long int_code,
+ int si_code, unsigned long trans_exc_code)
{
struct siginfo si;
+ unsigned long address;
+ address = trans_exc_code & __FAIL_ADDR_MASK;
+ current->thread.prot_addr = address;
+ current->thread.trap_no = int_code;
#if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG)
#if defined(CONFIG_SYSCTL)
if (sysctl_userprocess_debug)
#endif
{
printk("User process fault: interruption code 0x%lX\n",
- error_code);
+ int_code);
printk("failing address: %lX\n", address);
show_regs(regs);
}
@@ -161,13 +151,14 @@ static void do_sigsegv(struct pt_regs *regs, unsigned long error_code,
force_sig_info(SIGSEGV, &si, current);
}
-static void do_no_context(struct pt_regs *regs, unsigned long error_code,
- unsigned long address)
+static noinline void do_no_context(struct pt_regs *regs, long int_code,
+ unsigned long trans_exc_code)
{
const struct exception_table_entry *fixup;
+ unsigned long address;
/* Are we prepared to handle this kernel fault? */
- fixup = search_exception_tables(regs->psw.addr & __FIXUP_MASK);
+ fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
if (fixup) {
regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE;
return;
@@ -177,129 +168,149 @@ static void do_no_context(struct pt_regs *regs, unsigned long error_code,
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice.
*/
- if (check_space(current) == 0)
+ address = trans_exc_code & __FAIL_ADDR_MASK;
+ if (!user_space_fault(trans_exc_code))
printk(KERN_ALERT "Unable to handle kernel pointer dereference"
" at virtual kernel address %p\n", (void *)address);
else
printk(KERN_ALERT "Unable to handle kernel paging request"
" at virtual user address %p\n", (void *)address);
- die("Oops", regs, error_code);
+ die("Oops", regs, int_code);
do_exit(SIGKILL);
}
-static void do_low_address(struct pt_regs *regs, unsigned long error_code)
+static noinline void do_low_address(struct pt_regs *regs, long int_code,
+ unsigned long trans_exc_code)
{
/* Low-address protection hit in kernel mode means
NULL pointer write access in kernel mode. */
if (regs->psw.mask & PSW_MASK_PSTATE) {
/* Low-address protection hit in user mode 'cannot happen'. */
- die ("Low-address protection", regs, error_code);
+ die ("Low-address protection", regs, int_code);
do_exit(SIGKILL);
}
- do_no_context(regs, error_code, 0);
+ do_no_context(regs, int_code, trans_exc_code);
}
-static void do_sigbus(struct pt_regs *regs, unsigned long error_code,
- unsigned long address)
+static noinline void do_sigbus(struct pt_regs *regs, long int_code,
+ unsigned long trans_exc_code)
{
struct task_struct *tsk = current;
- struct mm_struct *mm = tsk->mm;
- up_read(&mm->mmap_sem);
/*
* Send a sigbus, regardless of whether we were in kernel
* or user mode.
*/
- tsk->thread.prot_addr = address;
- tsk->thread.trap_no = error_code;
+ tsk->thread.prot_addr = trans_exc_code & __FAIL_ADDR_MASK;
+ tsk->thread.trap_no = int_code;
force_sig(SIGBUS, tsk);
-
- /* Kernel mode? Handle exceptions or die */
- if (!(regs->psw.mask & PSW_MASK_PSTATE))
- do_no_context(regs, error_code, address);
}
#ifdef CONFIG_S390_EXEC_PROTECT
-static int signal_return(struct mm_struct *mm, struct pt_regs *regs,
- unsigned long address, unsigned long error_code)
+static noinline int signal_return(struct pt_regs *regs, long int_code,
+ unsigned long trans_exc_code)
{
u16 instruction;
int rc;
-#ifdef CONFIG_COMPAT
- int compat;
-#endif
- pagefault_disable();
rc = __get_user(instruction, (u16 __user *) regs->psw.addr);
- pagefault_enable();
- if (rc)
- return -EFAULT;
- up_read(&mm->mmap_sem);
- clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
-#ifdef CONFIG_COMPAT
- compat = is_compat_task();
- if (compat && instruction == 0x0a77)
- sys32_sigreturn();
- else if (compat && instruction == 0x0aad)
- sys32_rt_sigreturn();
- else
-#endif
- if (instruction == 0x0a77)
- sys_sigreturn();
- else if (instruction == 0x0aad)
- sys_rt_sigreturn();
- else {
- current->thread.prot_addr = address;
- current->thread.trap_no = error_code;
- do_sigsegv(regs, error_code, SEGV_MAPERR, address);
- }
+ if (!rc && instruction == 0x0a77) {
+ clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
+ if (is_compat_task())
+ sys32_sigreturn();
+ else
+ sys_sigreturn();
+ } else if (!rc && instruction == 0x0aad) {
+ clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
+ if (is_compat_task())
+ sys32_rt_sigreturn();
+ else
+ sys_rt_sigreturn();
+ } else
+ do_sigsegv(regs, int_code, SEGV_MAPERR, trans_exc_code);
return 0;
}
#endif /* CONFIG_S390_EXEC_PROTECT */
+static noinline void do_fault_error(struct pt_regs *regs, long int_code,
+ unsigned long trans_exc_code, int fault)
+{
+ int si_code;
+
+ switch (fault) {
+ case VM_FAULT_BADACCESS:
+#ifdef CONFIG_S390_EXEC_PROTECT
+ if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY &&
+ (trans_exc_code & 3) == 0) {
+ signal_return(regs, int_code, trans_exc_code);
+ break;
+ }
+#endif /* CONFIG_S390_EXEC_PROTECT */
+ case VM_FAULT_BADMAP:
+ /* Bad memory access. Check if it is kernel or user space. */
+ if (regs->psw.mask & PSW_MASK_PSTATE) {
+ /* User mode accesses just cause a SIGSEGV */
+ si_code = (fault == VM_FAULT_BADMAP) ?
+ SEGV_MAPERR : SEGV_ACCERR;
+ do_sigsegv(regs, int_code, si_code, trans_exc_code);
+ return;
+ }
+ case VM_FAULT_BADCONTEXT:
+ do_no_context(regs, int_code, trans_exc_code);
+ break;
+ default: /* fault & VM_FAULT_ERROR */
+ 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
+ BUG();
+ break;
+ }
+}
+
/*
* This routine handles page faults. It determines the address,
* and the problem, and then passes it off to one of the appropriate
* routines.
*
- * error_code:
+ * interruption code (int_code):
* 04 Protection -> Write-Protection (suprression)
* 10 Segment translation -> Not present (nullification)
* 11 Page translation -> Not present (nullification)
* 3b Region third trans. -> Not present (nullification)
*/
-static inline void
-do_exception(struct pt_regs *regs, unsigned long error_code, int write)
+static inline int do_exception(struct pt_regs *regs, int access,
+ unsigned long trans_exc_code)
{
struct task_struct *tsk;
struct mm_struct *mm;
struct vm_area_struct *vma;
unsigned long address;
- int space;
- int si_code;
int fault;
- if (notify_page_fault(regs, error_code))
- return;
+ if (notify_page_fault(regs))
+ return 0;
tsk = current;
mm = tsk->mm;
- /* get the failing address and the affected space */
- address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK;
- space = check_space(tsk);
-
/*
* Verify that the fault happened in user space, that
* we are not in an interrupt and that there is a
* user context.
*/
- if (unlikely(space == 0 || in_atomic() || !mm))
- goto no_context;
+ fault = VM_FAULT_BADCONTEXT;
+ if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm))
+ 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
@@ -309,42 +320,26 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int write)
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
down_read(&mm->mmap_sem);
- si_code = SEGV_MAPERR;
+ fault = VM_FAULT_BADMAP;
vma = find_vma(mm, address);
if (!vma)
- goto bad_area;
-
-#ifdef CONFIG_S390_EXEC_PROTECT
- if (unlikely((space == 2) && !(vma->vm_flags & VM_EXEC)))
- if (!signal_return(mm, regs, address, error_code))
- /*
- * signal_return() has done an up_read(&mm->mmap_sem)
- * if it returns 0.
- */
- return;
-#endif
+ goto out_up;
- if (vma->vm_start <= address)
- goto good_area;
- if (!(vma->vm_flags & VM_GROWSDOWN))
- goto bad_area;
- if (expand_stack(vma, address))
- goto bad_area;
-/*
- * Ok, we have a good vm_area for this memory access, so
- * we can handle it..
- */
-good_area:
- si_code = SEGV_ACCERR;
- if (!write) {
- /* page not present, check vm flags */
- if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
- goto bad_area;
- } else {
- if (!(vma->vm_flags & VM_WRITE))
- goto bad_area;
+ if (unlikely(vma->vm_start > address)) {
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto out_up;
+ if (expand_stack(vma, address))
+ goto out_up;
}
+ /*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+ fault = VM_FAULT_BADACCESS;
+ if (unlikely(!(vma->vm_flags & access)))
+ goto out_up;
+
if (is_vm_hugetlb_page(vma))
address &= HPAGE_MASK;
/*
@@ -352,18 +347,11 @@ good_area:
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
- fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0);
- if (unlikely(fault & VM_FAULT_ERROR)) {
- if (fault & VM_FAULT_OOM) {
- up_read(&mm->mmap_sem);
- pagefault_out_of_memory();
- return;
- } else if (fault & VM_FAULT_SIGBUS) {
- do_sigbus(regs, error_code, address);
- return;
- }
- BUG();
- }
+ fault = handle_mm_fault(mm, vma, address,
+ (access == VM_WRITE) ? FAULT_FLAG_WRITE : 0);
+ if (unlikely(fault & VM_FAULT_ERROR))
+ goto out_up;
+
if (fault & VM_FAULT_MAJOR) {
tsk->maj_flt++;
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
@@ -373,74 +361,69 @@ good_area:
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
regs, address);
}
- up_read(&mm->mmap_sem);
/*
* The instruction that caused the program check will
* be repeated. Don't signal single step via SIGTRAP.
*/
clear_tsk_thread_flag(tsk, TIF_SINGLE_STEP);
- return;
-
-/*
- * Something tried to access memory that isn't in our memory map..
- * Fix it, but check if it's kernel or user first..
- */
-bad_area:
+ fault = 0;
+out_up:
up_read(&mm->mmap_sem);
-
- /* User mode accesses just cause a SIGSEGV */
- if (regs->psw.mask & PSW_MASK_PSTATE) {
- tsk->thread.prot_addr = address;
- tsk->thread.trap_no = error_code;
- do_sigsegv(regs, error_code, si_code, address);
- return;
- }
-
-no_context:
- do_no_context(regs, error_code, address);
+out:
+ return fault;
}
-void __kprobes do_protection_exception(struct pt_regs *regs,
- long error_code)
+void __kprobes do_protection_exception(struct pt_regs *regs, long int_code)
{
+ unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
+ int fault;
+
/* Protection exception is supressing, decrement psw address. */
- regs->psw.addr -= (error_code >> 16);
+ regs->psw.addr -= (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(!(S390_lowcore.trans_exc_code & 4))) {
- do_low_address(regs, error_code);
+ if (unlikely(!(trans_exc_code & 4))) {
+ do_low_address(regs, int_code, trans_exc_code);
return;
}
- do_exception(regs, 4, 1);
+ fault = do_exception(regs, VM_WRITE, trans_exc_code);
+ if (unlikely(fault))
+ do_fault_error(regs, 4, trans_exc_code, fault);
}
-void __kprobes do_dat_exception(struct pt_regs *regs, long error_code)
+void __kprobes do_dat_exception(struct pt_regs *regs, long int_code)
{
- do_exception(regs, error_code & 0xff, 0);
+ unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
+ int access, fault;
+
+ access = VM_READ | VM_EXEC | VM_WRITE;
+#ifdef CONFIG_S390_EXEC_PROTECT
+ if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY &&
+ (trans_exc_code & 3) == 0)
+ access = VM_EXEC;
+#endif
+ fault = do_exception(regs, access, trans_exc_code);
+ if (unlikely(fault))
+ do_fault_error(regs, int_code & 255, trans_exc_code, fault);
}
#ifdef CONFIG_64BIT
-void __kprobes do_asce_exception(struct pt_regs *regs, unsigned long error_code)
+void __kprobes do_asce_exception(struct pt_regs *regs, long int_code)
{
- struct mm_struct *mm;
+ unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
+ struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
- unsigned long address;
- int space;
-
- mm = current->mm;
- address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK;
- space = check_space(current);
- if (unlikely(space == 0 || in_atomic() || !mm))
+ 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, address);
+ vma = find_vma(mm, trans_exc_code & __FAIL_ADDR_MASK);
up_read(&mm->mmap_sem);
if (vma) {
@@ -450,17 +433,38 @@ void __kprobes do_asce_exception(struct pt_regs *regs, unsigned long error_code)
/* User mode accesses just cause a SIGSEGV */
if (regs->psw.mask & PSW_MASK_PSTATE) {
- current->thread.prot_addr = address;
- current->thread.trap_no = error_code;
- do_sigsegv(regs, error_code, SEGV_MAPERR, address);
+ do_sigsegv(regs, int_code, SEGV_MAPERR, trans_exc_code);
return;
}
no_context:
- do_no_context(regs, error_code, address);
+ do_no_context(regs, int_code, trans_exc_code);
}
#endif
+int __handle_fault(unsigned long uaddr, unsigned long int_code, int write_user)
+{
+ struct pt_regs regs;
+ int access, fault;
+
+ regs.psw.mask = psw_kernel_bits;
+ if (!irqs_disabled())
+ regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT;
+ 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;
+ 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);
+ }
+ return fault ? -EFAULT : 0;
+}
+
#ifdef CONFIG_PFAULT
/*
* 'pfault' pseudo page faults routines.
@@ -522,7 +526,7 @@ void pfault_fini(void)
: : "a" (&refbk), "m" (refbk) : "cc");
}
-static void pfault_interrupt(__u16 error_code)
+static void pfault_interrupt(__u16 int_code)
{
struct task_struct *tsk;
__u16 subcode;
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index 2757c5616a07..ad621e06ada3 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -269,7 +269,7 @@ int s390_enable_sie(void)
struct mm_struct *mm, *old_mm;
/* Do we have switched amode? If no, we cannot do sie */
- if (!switch_amode)
+ if (user_mode == HOME_SPACE_MODE)
return -EINVAL;
/* Do we have pgstes? if yes, we are done */
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index b940424f8ccc..0031a6979f3a 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -16,7 +16,9 @@ config SUPERH
select HAVE_IOREMAP_PROT if MMU
select HAVE_ARCH_TRACEHOOK
select HAVE_DMA_API_DEBUG
+ select HAVE_DMA_ATTRS
select HAVE_PERF_EVENTS
+ select PERF_USE_VMALLOC
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_LZMA
@@ -37,7 +39,7 @@ config SUPERH32
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_DYNAMIC_FTRACE
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
- select HAVE_FTRACE_SYSCALLS
+ select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_ARCH_KGDB
select ARCH_HIBERNATION_POSSIBLE if MMU
@@ -122,6 +124,9 @@ config SYS_SUPPORTS_APM_EMULATION
bool
select ARCH_SUSPEND_POSSIBLE
+config SYS_SUPPORTS_HUGETLBFS
+ bool
+
config SYS_SUPPORTS_SMP
bool
@@ -168,6 +173,12 @@ config ARCH_HAS_CPU_IDLE_WAIT
config IO_TRAPPED
bool
+config DMA_COHERENT
+ bool
+
+config DMA_NONCOHERENT
+ def_bool !DMA_COHERENT
+
source "init/Kconfig"
source "kernel/Kconfig.freezer"
@@ -196,6 +207,7 @@ config CPU_SH4
select CPU_HAS_SR_RB
select CPU_HAS_FPU if !CPU_SH4AL_DSP
select SYS_SUPPORTS_TMU
+ select SYS_SUPPORTS_HUGETLBFS if MMU
config CPU_SH4A
bool
@@ -210,12 +222,14 @@ config CPU_SH5
bool
select CPU_HAS_FPU
select SYS_SUPPORTS_TMU
+ select SYS_SUPPORTS_HUGETLBFS if MMU
config CPU_SHX2
bool
config CPU_SHX3
bool
+ select DMA_COHERENT
config ARCH_SHMOBILE
bool
@@ -757,17 +771,6 @@ config ENTRY_OFFSET
default "0x00010000" if PAGE_SIZE_64KB
default "0x00000000"
-config UBC_WAKEUP
- bool "Wakeup UBC on startup"
- depends on CPU_SH4 && !CPU_SH4A
- help
- Selecting this option will wakeup the User Break Controller (UBC) on
- startup. Although the UBC is left in an awake state when the processor
- comes up, some boot loaders misbehave by putting the UBC to sleep in a
- power saving state, which causes issues with things like ptrace().
-
- If unsure, say N.
-
choice
prompt "Kernel command line"
optional
@@ -814,7 +817,13 @@ config MAPLE
Dreamcast with a serial line terminal or a remote network
connection.
-source "arch/sh/drivers/pci/Kconfig"
+config PCI
+ bool "PCI support"
+ depends on SYS_SUPPORTS_PCI
+ help
+ Find out whether you have a PCI motherboard. PCI is the name of a
+ bus system, i.e. the way the CPU talks to the other stuff inside
+ your box. If you have PCI, say Y, otherwise N.
source "drivers/pci/pcie/Kconfig"
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index fc51a918b31a..1a9438dc6178 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -199,12 +199,9 @@ endif
libs-$(CONFIG_SUPERH32) := arch/sh/lib/ $(libs-y)
libs-$(CONFIG_SUPERH64) := arch/sh/lib64/ $(libs-y)
-BOOT_TARGETS = uImage uImage.bz2 uImage.gz uImage.lzma uImage.srec \
+BOOT_TARGETS = uImage uImage.bz2 uImage.gz uImage.lzma uImage.srec uImage.bin \
zImage vmlinux.srec romImage
-PHONY += maketools $(BOOT_TARGETS) FORCE
-
-maketools: include/linux/version.h FORCE
- $(Q)$(MAKE) $(build)=arch/sh/tools include/asm-sh/machtypes.h
+PHONY += $(BOOT_TARGETS)
all: $(KBUILD_IMAGE)
@@ -213,7 +210,8 @@ $(BOOT_TARGETS): vmlinux
compressed: zImage
-archprepare: maketools
+archprepare:
+ $(Q)$(MAKE) $(build)=arch/sh/tools include/generated/machtypes.h
archclean:
$(Q)$(MAKE) $(clean)=$(boot)
@@ -225,9 +223,8 @@ define archhelp
@echo ' vmlinux.srec - Create an ELF S-record'
@echo '* uImage - Alias to bootable U-Boot image'
@echo ' uImage.srec - Create an S-record for U-Boot'
+ @echo ' uImage.bin - Kernel-only image for U-Boot (bin)'
@echo '* uImage.gz - Kernel-only image for U-Boot (gzip)'
@echo ' uImage.bz2 - Kernel-only image for U-Boot (bzip2)'
@echo ' uImage.lzma - Kernel-only image for U-Boot (lzma)'
endef
-
-CLEAN_FILES += include/asm-sh/machtypes.h
diff --git a/arch/sh/boards/board-ap325rxa.c b/arch/sh/boards/board-ap325rxa.c
index 2d080732a964..b95deee35e0f 100644
--- a/arch/sh/boards/board-ap325rxa.c
+++ b/arch/sh/boards/board-ap325rxa.c
@@ -20,8 +20,6 @@
#include <linux/i2c.h>
#include <linux/smsc911x.h>
#include <linux/gpio.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/spi_gpio.h>
#include <media/ov772x.h>
#include <media/soc_camera.h>
#include <media/soc_camera_platform.h>
@@ -409,17 +407,25 @@ static struct platform_device ceu_device = {
},
};
-struct spi_gpio_platform_data sdcard_cn3_platform_data = {
- .sck = GPIO_PTD0,
- .mosi = GPIO_PTD1,
- .miso = GPIO_PTD2,
- .num_chipselect = 1,
+static struct resource sdhi0_cn3_resources[] = {
+ [0] = {
+ .name = "SDHI0",
+ .start = 0x04ce0000,
+ .end = 0x04ce01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 101,
+ .flags = IORESOURCE_IRQ,
+ },
};
-static struct platform_device sdcard_cn3_device = {
- .name = "spi_gpio",
- .dev = {
- .platform_data = &sdcard_cn3_platform_data,
+static struct platform_device sdhi0_cn3_device = {
+ .name = "sh_mobile_sdhi",
+ .num_resources = ARRAY_SIZE(sdhi0_cn3_resources),
+ .resource = sdhi0_cn3_resources,
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI0,
},
};
@@ -470,20 +476,11 @@ static struct platform_device *ap325rxa_devices[] __initdata = {
&lcdc_device,
&ceu_device,
&nand_flash_device,
- &sdcard_cn3_device,
+ &sdhi0_cn3_device,
&ap325rxa_camera[0],
&ap325rxa_camera[1],
};
-static struct spi_board_info ap325rxa_spi_devices[] = {
- {
- .modalias = "mmc_spi",
- .max_speed_hz = 5000000,
- .chip_select = 0,
- .controller_data = (void *) GPIO_PTD5,
- },
-};
-
static int __init ap325rxa_devices_setup(void)
{
/* LD3 and LD4 LEDs */
@@ -578,12 +575,19 @@ static int __init ap325rxa_devices_setup(void)
platform_resource_setup_memory(&ceu_device, "ceu", 4 << 20);
+ /* SDHI0 */
+ gpio_request(GPIO_FN_SDHI0CD_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0WP_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0D3_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0D2_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0D1_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0D0_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0CMD_PTD, NULL);
+ gpio_request(GPIO_FN_SDHI0CLK_PTD, NULL);
+
i2c_register_board_info(0, ap325rxa_i2c_devices,
ARRAY_SIZE(ap325rxa_i2c_devices));
- spi_register_board_info(ap325rxa_spi_devices,
- ARRAY_SIZE(ap325rxa_spi_devices));
-
return platform_add_devices(ap325rxa_devices,
ARRAY_SIZE(ap325rxa_devices));
}
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 3b1ceb46fa54..da851a3b714a 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -147,6 +147,9 @@ static struct platform_device sh_eth_device = {
},
.num_resources = ARRAY_SIZE(sh_eth_resources),
.resource = sh_eth_resources,
+ .archdata = {
+ .hwblk_id = HWBLK_ETHER,
+ },
};
/* USB0 host */
@@ -428,6 +431,54 @@ static struct i2c_board_info ts_i2c_clients = {
.irq = IRQ0,
};
+/* SHDI0 */
+static struct resource sdhi0_resources[] = {
+ [0] = {
+ .name = "SDHI0",
+ .start = 0x04ce0000,
+ .end = 0x04ce01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 101,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi0_device = {
+ .name = "sh_mobile_sdhi",
+ .num_resources = ARRAY_SIZE(sdhi0_resources),
+ .resource = sdhi0_resources,
+ .id = 0,
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI0,
+ },
+};
+
+/* SHDI1 */
+static struct resource sdhi1_resources[] = {
+ [0] = {
+ .name = "SDHI1",
+ .start = 0x04cf0000,
+ .end = 0x04cf01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 24,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi1_device = {
+ .name = "sh_mobile_sdhi",
+ .num_resources = ARRAY_SIZE(sdhi1_resources),
+ .resource = sdhi1_resources,
+ .id = 1,
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI1,
+ },
+};
+
static struct platform_device *ecovec_devices[] __initdata = {
&heartbeat_device,
&nor_flash_device,
@@ -438,6 +489,8 @@ static struct platform_device *ecovec_devices[] __initdata = {
&ceu0_device,
&ceu1_device,
&keysc_device,
+ &sdhi0_device,
+ &sdhi1_device,
};
#define EEPROM_ADDR 0x50
@@ -466,12 +519,9 @@ static u8 mac_read(struct i2c_adapter *a, u8 command)
return buf;
}
-#define MAC_LEN 6
-static void __init sh_eth_init(void)
+static void __init sh_eth_init(struct sh_eth_plat_data *pd)
{
struct i2c_adapter *a = i2c_get_adapter(1);
- struct clk *eth_clk;
- u8 mac[MAC_LEN];
int i;
if (!a) {
@@ -479,33 +529,11 @@ static void __init sh_eth_init(void)
return;
}
- eth_clk = clk_get(NULL, "eth0");
- if (!eth_clk) {
- pr_err("can not get eth0 clk\n");
- return;
- }
-
/* read MAC address frome EEPROM */
- for (i = 0; i < MAC_LEN; i++) {
- mac[i] = mac_read(a, 0x10 + i);
+ for (i = 0; i < sizeof(pd->mac_addr); i++) {
+ pd->mac_addr[i] = mac_read(a, 0x10 + i);
msleep(10);
}
-
- /* clock enable */
- clk_enable(eth_clk);
-
- /* reset sh-eth */
- ctrl_outl(0x1, SH_ETH_ADDR + 0x0);
-
- /* set MAC addr */
- ctrl_outl((mac[0] << 24) |
- (mac[1] << 16) |
- (mac[2] << 8) |
- (mac[3] << 0), SH_ETH_MAHR);
- ctrl_outl((mac[4] << 8) |
- (mac[5] << 0), SH_ETH_MALR);
-
- clk_put(eth_clk);
}
#define PORT_HIZA 0xA4050158
@@ -710,6 +738,34 @@ static int __init arch_setup(void)
gpio_direction_input(GPIO_PTR5);
gpio_direction_input(GPIO_PTR6);
+ /* enable SDHI0 */
+ gpio_request(GPIO_FN_SDHI0CD, NULL);
+ gpio_request(GPIO_FN_SDHI0WP, NULL);
+ gpio_request(GPIO_FN_SDHI0CMD, NULL);
+ gpio_request(GPIO_FN_SDHI0CLK, NULL);
+ gpio_request(GPIO_FN_SDHI0D3, NULL);
+ gpio_request(GPIO_FN_SDHI0D2, NULL);
+ gpio_request(GPIO_FN_SDHI0D1, NULL);
+ gpio_request(GPIO_FN_SDHI0D0, NULL);
+
+ /* enable SDHI1 */
+ gpio_request(GPIO_FN_SDHI1CD, NULL);
+ gpio_request(GPIO_FN_SDHI1WP, NULL);
+ gpio_request(GPIO_FN_SDHI1CMD, NULL);
+ gpio_request(GPIO_FN_SDHI1CLK, NULL);
+ gpio_request(GPIO_FN_SDHI1D3, NULL);
+ gpio_request(GPIO_FN_SDHI1D2, NULL);
+ gpio_request(GPIO_FN_SDHI1D1, NULL);
+ gpio_request(GPIO_FN_SDHI1D0, NULL);
+
+ gpio_request(GPIO_PTB6, NULL);
+ gpio_request(GPIO_PTB7, NULL);
+ gpio_direction_output(GPIO_PTB6, 1);
+ gpio_direction_output(GPIO_PTB7, 1);
+
+ /* I/O buffer drive ability is high for SDHI1 */
+ ctrl_outw((ctrl_inw(IODRIVEA) & ~0x3000) | 0x2000 , IODRIVEA);
+
/* enable I2C device */
i2c_register_board_info(1, i2c1_devices,
ARRAY_SIZE(i2c1_devices));
@@ -721,12 +777,11 @@ arch_initcall(arch_setup);
static int __init devices_setup(void)
{
- sh_eth_init();
+ sh_eth_init(&sh_eth_plat);
return 0;
}
device_initcall(devices_setup);
-
static struct sh_machine_vector mv_ecovec __initmv = {
.mv_name = "R0P7724 (EcoVec)",
};
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c
index c08d33fe2104..43d75ee93358 100644
--- a/arch/sh/boards/mach-kfr2r09/setup.c
+++ b/arch/sh/boards/mach-kfr2r09/setup.c
@@ -18,6 +18,8 @@
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/usb/r8a66597.h>
+#include <media/soc_camera.h>
+#include <media/sh_mobile_ceu.h>
#include <video/sh_mobile_lcdc.h>
#include <asm/clock.h>
#include <asm/machvec.h>
@@ -212,11 +214,154 @@ static struct platform_device kfr2r09_usb0_gadget_device = {
.resource = kfr2r09_usb0_gadget_resources,
};
+static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
+ .flags = SH_CEU_FLAG_USE_8BIT_BUS,
+};
+
+static struct resource kfr2r09_ceu_resources[] = {
+ [0] = {
+ .name = "CEU",
+ .start = 0xfe910000,
+ .end = 0xfe91009f,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 52,
+ .end = 52,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ /* place holder for contiguous memory */
+ },
+};
+
+static struct platform_device kfr2r09_ceu_device = {
+ .name = "sh_mobile_ceu",
+ .id = 0, /* "ceu0" clock */
+ .num_resources = ARRAY_SIZE(kfr2r09_ceu_resources),
+ .resource = kfr2r09_ceu_resources,
+ .dev = {
+ .platform_data = &sh_mobile_ceu_info,
+ },
+ .archdata = {
+ .hwblk_id = HWBLK_CEU0,
+ },
+};
+
+static struct i2c_board_info kfr2r09_i2c_camera = {
+ I2C_BOARD_INFO("rj54n1cb0c", 0x50),
+};
+
+static struct clk *camera_clk;
+
+#define DRVCRB 0xA405018C
+static int camera_power(struct device *dev, int mode)
+{
+ int ret;
+
+ if (mode) {
+ long rate;
+
+ camera_clk = clk_get(NULL, "video_clk");
+ if (IS_ERR(camera_clk))
+ return PTR_ERR(camera_clk);
+
+ /* set VIO_CKO clock to 25MHz */
+ rate = clk_round_rate(camera_clk, 25000000);
+ ret = clk_set_rate(camera_clk, rate);
+ if (ret < 0)
+ goto eclkrate;
+
+ /* set DRVCRB
+ *
+ * use 1.8 V for VccQ_VIO
+ * use 2.85V for VccQ_SR
+ */
+ ctrl_outw((ctrl_inw(DRVCRB) & ~0x0003) | 0x0001, DRVCRB);
+
+ /* reset clear */
+ ret = gpio_request(GPIO_PTB4, NULL);
+ if (ret < 0)
+ goto eptb4;
+ ret = gpio_request(GPIO_PTB7, NULL);
+ if (ret < 0)
+ goto eptb7;
+
+ ret = gpio_direction_output(GPIO_PTB4, 1);
+ if (!ret)
+ ret = gpio_direction_output(GPIO_PTB7, 1);
+ if (ret < 0)
+ goto egpioout;
+ msleep(1);
+
+ ret = clk_enable(camera_clk); /* start VIO_CKO */
+ if (ret < 0)
+ goto eclkon;
+
+ return 0;
+ }
+
+ ret = 0;
+
+ clk_disable(camera_clk);
+eclkon:
+ gpio_set_value(GPIO_PTB7, 0);
+egpioout:
+ gpio_set_value(GPIO_PTB4, 0);
+ gpio_free(GPIO_PTB7);
+eptb7:
+ gpio_free(GPIO_PTB4);
+eptb4:
+eclkrate:
+ clk_put(camera_clk);
+ return ret;
+}
+
+static struct soc_camera_link rj54n1_link = {
+ .power = camera_power,
+ .board_info = &kfr2r09_i2c_camera,
+ .i2c_adapter_id = 1,
+ .module_name = "rj54n1cb0c",
+};
+
+static struct platform_device kfr2r09_camera = {
+ .name = "soc-camera-pdrv",
+ .id = 0,
+ .dev = {
+ .platform_data = &rj54n1_link,
+ },
+};
+
+static struct resource kfr2r09_sh_sdhi0_resources[] = {
+ [0] = {
+ .name = "SDHI0",
+ .start = 0x04ce0000,
+ .end = 0x04ce01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 101,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device kfr2r09_sh_sdhi0_device = {
+ .name = "sh_mobile_sdhi",
+ .num_resources = ARRAY_SIZE(kfr2r09_sh_sdhi0_resources),
+ .resource = kfr2r09_sh_sdhi0_resources,
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI0,
+ },
+};
+
static struct platform_device *kfr2r09_devices[] __initdata = {
&kfr2r09_nor_flash_device,
&kfr2r09_nand_flash_device,
&kfr2r09_sh_keysc_device,
&kfr2r09_sh_lcdc_device,
+ &kfr2r09_ceu_device,
+ &kfr2r09_camera,
+ &kfr2r09_sh_sdhi0_device,
};
#define BSC_CS0BCR 0xfec10004
@@ -361,6 +506,33 @@ static int __init kfr2r09_devices_setup(void)
if (kfr2r09_usb0_gadget_setup() == 0)
platform_device_register(&kfr2r09_usb0_gadget_device);
+ /* CEU */
+ gpio_request(GPIO_FN_VIO_CKO, NULL);
+ gpio_request(GPIO_FN_VIO0_CLK, NULL);
+ gpio_request(GPIO_FN_VIO0_VD, NULL);
+ gpio_request(GPIO_FN_VIO0_HD, NULL);
+ gpio_request(GPIO_FN_VIO0_FLD, NULL);
+ gpio_request(GPIO_FN_VIO0_D7, NULL);
+ gpio_request(GPIO_FN_VIO0_D6, NULL);
+ gpio_request(GPIO_FN_VIO0_D5, NULL);
+ gpio_request(GPIO_FN_VIO0_D4, NULL);
+ gpio_request(GPIO_FN_VIO0_D3, NULL);
+ gpio_request(GPIO_FN_VIO0_D2, NULL);
+ gpio_request(GPIO_FN_VIO0_D1, NULL);
+ gpio_request(GPIO_FN_VIO0_D0, NULL);
+
+ platform_resource_setup_memory(&kfr2r09_ceu_device, "ceu", 4 << 20);
+
+ /* SDHI0 connected to yc304 */
+ gpio_request(GPIO_FN_SDHI0CD, NULL);
+ gpio_request(GPIO_FN_SDHI0WP, NULL);
+ gpio_request(GPIO_FN_SDHI0D3, NULL);
+ gpio_request(GPIO_FN_SDHI0D2, NULL);
+ gpio_request(GPIO_FN_SDHI0D1, NULL);
+ gpio_request(GPIO_FN_SDHI0D0, NULL);
+ gpio_request(GPIO_FN_SDHI0CMD, NULL);
+ gpio_request(GPIO_FN_SDHI0CLK, NULL);
+
return platform_add_devices(kfr2r09_devices,
ARRAY_SIZE(kfr2r09_devices));
}
diff --git a/arch/sh/boards/mach-landisk/gio.c b/arch/sh/boards/mach-landisk/gio.c
index 25cdf7358000..528013188196 100644
--- a/arch/sh/boards/mach-landisk/gio.c
+++ b/arch/sh/boards/mach-landisk/gio.c
@@ -14,7 +14,6 @@
*/
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/fs.h>
@@ -35,7 +34,7 @@ static int gio_open(struct inode *inode, struct file *filp)
int minor;
int ret = -ENOENT;
- lock_kernel();
+ preempt_disable();
minor = MINOR(inode->i_rdev);
if (minor < DEVCOUNT) {
if (openCnt > 0) {
@@ -45,7 +44,7 @@ static int gio_open(struct inode *inode, struct file *filp)
ret = 0;
}
}
- unlock_kernel();
+ preempt_enable();
return ret;
}
@@ -60,8 +59,7 @@ static int gio_close(struct inode *inode, struct file *filp)
return 0;
}
-static int gio_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static long gio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
unsigned int data;
static unsigned int addr = 0;
@@ -129,7 +127,7 @@ static const struct file_operations gio_fops = {
.owner = THIS_MODULE,
.open = gio_open, /* open */
.release = gio_close, /* release */
- .ioctl = gio_ioctl, /* ioctl */
+ .unlocked_ioctl = gio_ioctl,
};
static int __init gio_init(void)
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index 6ed1fd32369e..8e911360c91e 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -18,8 +18,6 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/gpio.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/spi_gpio.h>
#include <video/sh_mobile_lcdc.h>
#include <media/sh_mobile_ceu.h>
#include <media/ov772x.h>
@@ -390,17 +388,25 @@ static struct platform_device migor_ceu_device = {
},
};
-struct spi_gpio_platform_data sdcard_cn9_platform_data = {
- .sck = GPIO_PTD0,
- .mosi = GPIO_PTD1,
- .miso = GPIO_PTD2,
- .num_chipselect = 1,
+static struct resource sdhi_cn9_resources[] = {
+ [0] = {
+ .name = "SDHI",
+ .start = 0x04ce0000,
+ .end = 0x04ce01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 101,
+ .flags = IORESOURCE_IRQ,
+ },
};
-static struct platform_device sdcard_cn9_device = {
- .name = "spi_gpio",
- .dev = {
- .platform_data = &sdcard_cn9_platform_data,
+static struct platform_device sdhi_cn9_device = {
+ .name = "sh_mobile_sdhi",
+ .num_resources = ARRAY_SIZE(sdhi_cn9_resources),
+ .resource = sdhi_cn9_resources,
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI,
},
};
@@ -467,20 +473,11 @@ static struct platform_device *migor_devices[] __initdata = {
&migor_ceu_device,
&migor_nor_flash_device,
&migor_nand_flash_device,
- &sdcard_cn9_device,
+ &sdhi_cn9_device,
&migor_camera[0],
&migor_camera[1],
};
-static struct spi_board_info migor_spi_devices[] = {
- {
- .modalias = "mmc_spi",
- .max_speed_hz = 5000000,
- .chip_select = 0,
- .controller_data = (void *) GPIO_PTD5,
- },
-};
-
static int __init migor_devices_setup(void)
{
@@ -525,6 +522,16 @@ static int __init migor_devices_setup(void)
gpio_request(GPIO_PTA1, NULL);
gpio_direction_input(GPIO_PTA1);
+ /* SDHI */
+ gpio_request(GPIO_FN_SDHICD, NULL);
+ gpio_request(GPIO_FN_SDHIWP, NULL);
+ gpio_request(GPIO_FN_SDHID3, NULL);
+ gpio_request(GPIO_FN_SDHID2, NULL);
+ gpio_request(GPIO_FN_SDHID1, NULL);
+ gpio_request(GPIO_FN_SDHID0, NULL);
+ gpio_request(GPIO_FN_SDHICMD, NULL);
+ gpio_request(GPIO_FN_SDHICLK, NULL);
+
/* Touch Panel */
gpio_request(GPIO_FN_IRQ6, NULL);
@@ -612,9 +619,6 @@ static int __init migor_devices_setup(void)
i2c_register_board_info(0, migor_i2c_devices,
ARRAY_SIZE(migor_i2c_devices));
- spi_register_board_info(migor_spi_devices,
- ARRAY_SIZE(migor_spi_devices));
-
return platform_add_devices(migor_devices, ARRAY_SIZE(migor_devices));
}
arch_initcall(migor_devices_setup);
diff --git a/arch/sh/boards/mach-rsk/devices-rsk7203.c b/arch/sh/boards/mach-rsk/devices-rsk7203.c
index 4af3a771c058..c37617e63220 100644
--- a/arch/sh/boards/mach-rsk/devices-rsk7203.c
+++ b/arch/sh/boards/mach-rsk/devices-rsk7203.c
@@ -11,10 +11,6 @@
#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
-#include <linux/mtd/map.h>
#include <linux/smsc911x.h>
#include <linux/gpio.h>
#include <linux/leds.h>
diff --git a/arch/sh/boards/mach-rsk/setup.c b/arch/sh/boards/mach-rsk/setup.c
index af64d030a5c7..a5c0df785bfe 100644
--- a/arch/sh/boards/mach-rsk/setup.c
+++ b/arch/sh/boards/mach-rsk/setup.c
@@ -15,14 +15,12 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
+#ifdef CONFIG_MTD
#include <linux/mtd/map.h>
+#endif
#include <asm/machvec.h>
#include <asm/io.h>
-static const char *probes[] = { "cmdlinepart", NULL };
-
-static struct mtd_partition *parsed_partitions;
-
static struct mtd_partition rsk_partitions[] = {
{
.name = "Bootloader",
@@ -41,6 +39,8 @@ static struct mtd_partition rsk_partitions[] = {
};
static struct physmap_flash_data flash_data = {
+ .parts = rsk_partitions,
+ .nr_parts = ARRAY_SIZE(rsk_partitions),
.width = 2,
};
@@ -60,7 +60,8 @@ static struct platform_device flash_device = {
},
};
-static struct mtd_info *flash_mtd;
+#ifdef CONFIG_MTD
+static const char *probes[] = { "cmdlinepart", NULL };
static struct map_info rsk_flash_map = {
.name = "RSK+ Flash",
@@ -68,6 +69,10 @@ static struct map_info rsk_flash_map = {
.bankwidth = 2,
};
+static struct mtd_info *flash_mtd;
+
+static struct mtd_partition *parsed_partitions;
+
static void __init set_mtd_partitions(void)
{
int nr_parts = 0;
@@ -77,14 +82,14 @@ static void __init set_mtd_partitions(void)
nr_parts = parse_mtd_partitions(flash_mtd, probes,
&parsed_partitions, 0);
/* If there is no partition table, used the hard coded table */
- if (nr_parts <= 0) {
- flash_data.parts = rsk_partitions;
- flash_data.nr_parts = ARRAY_SIZE(rsk_partitions);
- } else {
+ if (nr_parts > 0) {
flash_data.nr_parts = nr_parts;
flash_data.parts = parsed_partitions;
}
}
+#else
+static inline void set_mtd_partitions(void) {}
+#endif
static struct platform_device *rsk_devices[] __initdata = {
&flash_device,
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index e78c3be8ad2f..ffb97f22783c 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -448,6 +448,52 @@ static struct platform_device sh7724_usb1_gadget_device = {
.resource = sh7724_usb1_gadget_resources,
};
+static struct resource sdhi0_cn7_resources[] = {
+ [0] = {
+ .name = "SDHI0",
+ .start = 0x04ce0000,
+ .end = 0x04ce01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 101,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi0_cn7_device = {
+ .name = "sh_mobile_sdhi",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(sdhi0_cn7_resources),
+ .resource = sdhi0_cn7_resources,
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI0,
+ },
+};
+
+static struct resource sdhi1_cn8_resources[] = {
+ [0] = {
+ .name = "SDHI1",
+ .start = 0x04cf0000,
+ .end = 0x04cf01ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 24,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi1_cn8_device = {
+ .name = "sh_mobile_sdhi",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(sdhi1_cn8_resources),
+ .resource = sdhi1_cn8_resources,
+ .archdata = {
+ .hwblk_id = HWBLK_SDHI1,
+ },
+};
+
static struct platform_device *ms7724se_devices[] __initdata = {
&heartbeat_device,
&smc91x_eth_device,
@@ -460,6 +506,8 @@ static struct platform_device *ms7724se_devices[] __initdata = {
&sh7724_usb0_host_device,
&sh7724_usb1_gadget_device,
&fsi_device,
+ &sdhi0_cn7_device,
+ &sdhi1_cn8_device,
};
#define EEPROM_OP 0xBA206000
@@ -484,7 +532,7 @@ static int __init sh_eth_is_eeprom_ready(void)
static void __init sh_eth_init(void)
{
int i;
- u16 mac[3];
+ u16 mac;
/* check EEPROM status */
if (!sh_eth_is_eeprom_ready())
@@ -498,16 +546,10 @@ static void __init sh_eth_init(void)
if (!sh_eth_is_eeprom_ready())
return;
- mac[i] = ctrl_inw(EEPROM_DATA);
- mac[i] = ((mac[i] & 0xFF) << 8) | (mac[i] >> 8); /* swap */
+ mac = ctrl_inw(EEPROM_DATA);
+ sh_eth_plat.mac_addr[i << 1] = mac & 0xff;
+ sh_eth_plat.mac_addr[(i << 1) + 1] = mac >> 8;
}
-
- /* reset sh-eth */
- ctrl_outl(0x1, SH_ETH_ADDR + 0x0);
-
- /* set MAC addr */
- ctrl_outl(((mac[0] << 16) | (mac[1])), SH_ETH_MAHR);
- ctrl_outl((mac[2]), SH_ETH_MALR);
}
#define SW4140 0xBA201000
@@ -698,6 +740,26 @@ static int __init devices_setup(void)
clk_set_rate(&fsimcka_clk, 11000);
clk_put(fsia_clk);
+ /* SDHI0 connected to cn7 */
+ gpio_request(GPIO_FN_SDHI0CD, NULL);
+ gpio_request(GPIO_FN_SDHI0WP, NULL);
+ gpio_request(GPIO_FN_SDHI0D3, NULL);
+ gpio_request(GPIO_FN_SDHI0D2, NULL);
+ gpio_request(GPIO_FN_SDHI0D1, NULL);
+ gpio_request(GPIO_FN_SDHI0D0, NULL);
+ gpio_request(GPIO_FN_SDHI0CMD, NULL);
+ gpio_request(GPIO_FN_SDHI0CLK, NULL);
+
+ /* SDHI1 connected to cn8 */
+ gpio_request(GPIO_FN_SDHI1CD, NULL);
+ gpio_request(GPIO_FN_SDHI1WP, NULL);
+ gpio_request(GPIO_FN_SDHI1D3, NULL);
+ gpio_request(GPIO_FN_SDHI1D2, NULL);
+ gpio_request(GPIO_FN_SDHI1D1, NULL);
+ gpio_request(GPIO_FN_SDHI1D0, NULL);
+ gpio_request(GPIO_FN_SDHI1CMD, NULL);
+ gpio_request(GPIO_FN_SDHI1CLK, NULL);
+
/*
* enable SH-Eth
*
diff --git a/arch/sh/boot/Makefile b/arch/sh/boot/Makefile
index a1316872be6f..cb8cf5572e79 100644
--- a/arch/sh/boot/Makefile
+++ b/arch/sh/boot/Makefile
@@ -20,11 +20,12 @@ CONFIG_BOOT_LINK_OFFSET ?= 0x00800000
CONFIG_ZERO_PAGE_OFFSET ?= 0x00001000
CONFIG_ENTRY_OFFSET ?= 0x00001000
+suffix-y := bin
suffix-$(CONFIG_KERNEL_GZIP) := gz
suffix-$(CONFIG_KERNEL_BZIP2) := bz2
suffix-$(CONFIG_KERNEL_LZMA) := lzma
-targets := zImage vmlinux.srec romImage uImage uImage.srec uImage.gz uImage.bz2 uImage.lzma
+targets := zImage vmlinux.srec romImage uImage uImage.srec uImage.gz uImage.bz2 uImage.lzma uImage.bin
extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma
subdir- := compressed romimage
@@ -88,6 +89,9 @@ $(obj)/uImage.gz: $(obj)/vmlinux.bin.gz
$(obj)/uImage.lzma: $(obj)/vmlinux.bin.lzma
$(call if_changed,uimage,lzma)
+$(obj)/uImage.bin: $(obj)/vmlinux.bin
+ $(call if_changed,uimage,none)
+
OBJCOPYFLAGS_vmlinux.srec := -I binary -O srec
$(obj)/vmlinux.srec: $(obj)/compressed/vmlinux
$(call if_changed,objcopy)
diff --git a/arch/sh/boot/compressed/misc.c b/arch/sh/boot/compressed/misc.c
index fd56a71ca9d9..b51b1fc4baae 100644
--- a/arch/sh/boot/compressed/misc.c
+++ b/arch/sh/boot/compressed/misc.c
@@ -131,7 +131,7 @@ void decompress_kernel(void)
#ifdef CONFIG_SUPERH64
output_addr = (CONFIG_MEMORY_START + 0x2000);
#else
- output_addr = PHYSADDR((unsigned long)&_text+PAGE_SIZE);
+ output_addr = __pa((unsigned long)&_text+PAGE_SIZE);
#ifdef CONFIG_29BIT
output_addr |= P2SEG;
#endif
diff --git a/arch/sh/drivers/pci/Kconfig b/arch/sh/drivers/pci/Kconfig
deleted file mode 100644
index e8db585a6638..000000000000
--- a/arch/sh/drivers/pci/Kconfig
+++ /dev/null
@@ -1,19 +0,0 @@
-config PCI
- bool "PCI support"
- depends on SYS_SUPPORTS_PCI
- help
- Find out whether you have a PCI motherboard. PCI is the name of a
- bus system, i.e. the way the CPU talks to the other stuff inside
- your box. If you have PCI, say Y, otherwise N.
-
-config SH_PCIDMA_NONCOHERENT
- bool "Cache and PCI noncoherent"
- depends on PCI
- default y
- help
- Enable this option if your platform does not have a CPU cache which
- remains coherent with PCI DMA. It is safest to say 'Y', although you
- will see better performance if you can say 'N', because the PCI DMA
- code will not have to flush the CPU's caches. If you have a PCI host
- bridge integrated with your SH CPU, refer carefully to the chip specs
- to see if you can say 'N' here. Otherwise, leave it as 'Y'.
diff --git a/arch/sh/drivers/pci/fixups-rts7751r2d.c b/arch/sh/drivers/pci/fixups-rts7751r2d.c
index 052b354236dc..7898f14d6641 100644
--- a/arch/sh/drivers/pci/fixups-rts7751r2d.c
+++ b/arch/sh/drivers/pci/fixups-rts7751r2d.c
@@ -15,7 +15,7 @@
#include <mach/lboxre2.h>
#include <mach/r2d.h>
#include "pci-sh4.h"
-#include <asm/machtypes.h>
+#include <generated/machtypes.h>
#define PCIMCR_MRSET_OFF 0xBFFFFFFF
#define PCIMCR_RFSH_OFF 0xFFFFFFFB
diff --git a/arch/sh/include/asm/.gitignore b/arch/sh/include/asm/.gitignore
deleted file mode 100644
index 378db779fb6c..000000000000
--- a/arch/sh/include/asm/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-machtypes.h
diff --git a/arch/sh/include/asm/addrspace.h b/arch/sh/include/asm/addrspace.h
index 80d40813e057..99d6b3ecbe22 100644
--- a/arch/sh/include/asm/addrspace.h
+++ b/arch/sh/include/asm/addrspace.h
@@ -28,9 +28,6 @@
/* Returns the privileged segment base of a given address */
#define PXSEG(a) (((unsigned long)(a)) & 0xe0000000)
-/* Returns the physical address of a PnSEG (n=1,2) address */
-#define PHYSADDR(a) (((unsigned long)(a)) & 0x1fffffff)
-
#if defined(CONFIG_29BIT) || defined(CONFIG_PMB_FIXED)
/*
* Map an address to a certain privileged segment
@@ -60,5 +57,11 @@
#define P3_ADDR_MAX P4SEG
#endif
+#ifndef __ASSEMBLY__
+#ifdef CONFIG_PMB
+extern int __in_29bit_mode(void);
+#endif /* CONFIG_PMB */
+#endif /* __ASSEMBLY__ */
+
#endif /* __KERNEL__ */
#endif /* __ASM_SH_ADDRSPACE_H */
diff --git a/arch/sh/include/asm/asm-offsets.h b/arch/sh/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/sh/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/sh/include/asm/atomic.h b/arch/sh/include/asm/atomic.h
index e8e78137c6f5..b16388d71954 100644
--- a/arch/sh/include/asm/atomic.h
+++ b/arch/sh/include/asm/atomic.h
@@ -78,11 +78,10 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
-/* Atomic operations are already serializing on SH */
-#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()
+#define smp_mb__before_atomic_dec() smp_mb()
+#define smp_mb__after_atomic_dec() smp_mb()
+#define smp_mb__before_atomic_inc() smp_mb()
+#define smp_mb__after_atomic_inc() smp_mb()
#include <asm-generic/atomic-long.h>
#include <asm-generic/atomic64.h>
diff --git a/arch/sh/include/asm/bitops.h b/arch/sh/include/asm/bitops.h
index ebe595b7ab1f..98511e4d28cb 100644
--- a/arch/sh/include/asm/bitops.h
+++ b/arch/sh/include/asm/bitops.h
@@ -26,8 +26,8 @@
/*
* clear_bit() doesn't provide any barrier for the compiler.
*/
-#define smp_mb__before_clear_bit() barrier()
-#define smp_mb__after_clear_bit() barrier()
+#define smp_mb__before_clear_bit() smp_mb()
+#define smp_mb__after_clear_bit() smp_mb()
#ifdef CONFIG_SUPERH32
static inline unsigned long ffz(unsigned long word)
diff --git a/arch/sh/include/asm/bugs.h b/arch/sh/include/asm/bugs.h
index 46260fcbdf4b..02a19a1c033a 100644
--- a/arch/sh/include/asm/bugs.h
+++ b/arch/sh/include/asm/bugs.h
@@ -14,11 +14,15 @@
#include <asm/processor.h>
+extern void select_idle_routine(void);
+
static void __init check_bugs(void)
{
extern unsigned long loops_per_jiffy;
char *p = &init_utsname()->machine[2]; /* "sh" */
+ select_idle_routine();
+
current_cpu_data.loops_per_jiffy = loops_per_jiffy;
switch (current_cpu_data.family) {
diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h
index 69d56dd4c968..87ced133a363 100644
--- a/arch/sh/include/asm/dma-mapping.h
+++ b/arch/sh/include/asm/dma-mapping.h
@@ -1,219 +1,108 @@
#ifndef __ASM_SH_DMA_MAPPING_H
#define __ASM_SH_DMA_MAPPING_H
-#include <linux/mm.h>
-#include <linux/scatterlist.h>
-#include <linux/dma-debug.h>
-#include <asm/cacheflush.h>
-#include <asm/io.h>
+extern struct dma_map_ops *dma_ops;
+extern void no_iommu_init(void);
+
+static inline struct dma_map_ops *get_dma_ops(struct device *dev)
+{
+ return dma_ops;
+}
+
#include <asm-generic/dma-coherent.h>
+#include <asm-generic/dma-mapping-common.h>
+
+static inline int dma_supported(struct device *dev, u64 mask)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
-extern struct bus_type pci_bus_type;
+ if (ops->dma_supported)
+ return ops->dma_supported(dev, mask);
-#define dma_supported(dev, mask) (1)
+ return 1;
+}
static inline int dma_set_mask(struct device *dev, u64 mask)
{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+
if (!dev->dma_mask || !dma_supported(dev, mask))
return -EIO;
+ if (ops->set_dma_mask)
+ return ops->set_dma_mask(dev, mask);
*dev->dma_mask = mask;
return 0;
}
-void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag);
-
-void dma_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle);
-
void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
enum dma_data_direction dir);
#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)
-#define dma_is_consistent(d, h) (1)
-
-static inline dma_addr_t dma_map_single(struct device *dev,
- void *ptr, size_t size,
- enum dma_data_direction dir)
-{
- dma_addr_t addr = virt_to_phys(ptr);
-
-#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
- if (dev->bus == &pci_bus_type)
- return addr;
-#endif
- dma_cache_sync(dev, ptr, size, dir);
-
- debug_dma_map_page(dev, virt_to_page(ptr),
- (unsigned long)ptr & ~PAGE_MASK, size,
- dir, addr, true);
-
- return addr;
-}
-
-static inline void dma_unmap_single(struct device *dev, dma_addr_t addr,
- size_t size, enum dma_data_direction dir)
-{
- debug_dma_unmap_page(dev, addr, size, dir, true);
-}
-static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
- int nents, enum dma_data_direction dir)
-{
- int i;
-
- for (i = 0; i < nents; i++) {
-#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
- dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, dir);
+#ifdef CONFIG_DMA_COHERENT
+#define dma_is_consistent(d, h) (1)
+#else
+#define dma_is_consistent(d, h) (0)
#endif
- sg[i].dma_address = sg_phys(&sg[i]);
- sg[i].dma_length = sg[i].length;
- }
- debug_dma_map_sg(dev, sg, nents, i, dir);
-
- return nents;
-}
-
-static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
- int nents, enum dma_data_direction dir)
-{
- debug_dma_unmap_sg(dev, sg, nents, dir);
-}
-
-static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
- unsigned long offset, size_t size,
- enum dma_data_direction dir)
-{
- return dma_map_single(dev, page_address(page) + offset, size, dir);
-}
-
-static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
- size_t size, enum dma_data_direction dir)
-{
- dma_unmap_single(dev, dma_address, size, dir);
-}
-
-static inline void __dma_sync_single(struct device *dev, dma_addr_t dma_handle,
- size_t size, enum dma_data_direction dir)
+static inline int dma_get_cache_alignment(void)
{
-#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
- if (dev->bus == &pci_bus_type)
- return;
-#endif
- dma_cache_sync(dev, phys_to_virt(dma_handle), size, dir);
+ /*
+ * Each processor family will define its own L1_CACHE_SHIFT,
+ * L1_CACHE_BYTES wraps to this, so this is always safe.
+ */
+ return L1_CACHE_BYTES;
}
-static inline void dma_sync_single_range(struct device *dev,
- dma_addr_t dma_handle,
- unsigned long offset, size_t size,
- enum dma_data_direction dir)
+static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
-#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
- if (dev->bus == &pci_bus_type)
- return;
-#endif
- dma_cache_sync(dev, phys_to_virt(dma_handle) + offset, size, dir);
-}
+ struct dma_map_ops *ops = get_dma_ops(dev);
-static inline void __dma_sync_sg(struct device *dev, struct scatterlist *sg,
- int nelems, enum dma_data_direction dir)
-{
- int i;
+ if (ops->mapping_error)
+ return ops->mapping_error(dev, dma_addr);
- for (i = 0; i < nelems; i++) {
-#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
- dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, dir);
-#endif
- sg[i].dma_address = sg_phys(&sg[i]);
- sg[i].dma_length = sg[i].length;
- }
+ return dma_addr == 0;
}
-static inline void dma_sync_single_for_cpu(struct device *dev,
- dma_addr_t dma_handle, size_t size,
- enum dma_data_direction dir)
+static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp)
{
- __dma_sync_single(dev, dma_handle, size, dir);
- debug_dma_sync_single_for_cpu(dev, dma_handle, size, dir);
-}
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ void *memory;
-static inline void dma_sync_single_for_device(struct device *dev,
- dma_addr_t dma_handle,
- size_t size,
- enum dma_data_direction dir)
-{
- __dma_sync_single(dev, dma_handle, size, dir);
- debug_dma_sync_single_for_device(dev, dma_handle, size, dir);
-}
+ if (dma_alloc_from_coherent(dev, size, dma_handle, &memory))
+ return memory;
+ if (!ops->alloc_coherent)
+ return NULL;
-static inline void dma_sync_single_range_for_cpu(struct device *dev,
- dma_addr_t dma_handle,
- unsigned long offset,
- size_t size,
- enum dma_data_direction direction)
-{
- dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction);
- debug_dma_sync_single_range_for_cpu(dev, dma_handle,
- offset, size, direction);
-}
+ memory = ops->alloc_coherent(dev, size, dma_handle, gfp);
+ debug_dma_alloc_coherent(dev, size, *dma_handle, memory);
-static inline void dma_sync_single_range_for_device(struct device *dev,
- dma_addr_t dma_handle,
- unsigned long offset,
- size_t size,
- enum dma_data_direction direction)
-{
- dma_sync_single_for_device(dev, dma_handle+offset, size, direction);
- debug_dma_sync_single_range_for_device(dev, dma_handle,
- offset, size, direction);
+ return memory;
}
-
-static inline void dma_sync_sg_for_cpu(struct device *dev,
- struct scatterlist *sg, int nelems,
- enum dma_data_direction dir)
+static inline void dma_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
{
- __dma_sync_sg(dev, sg, nelems, dir);
- debug_dma_sync_sg_for_cpu(dev, sg, nelems, dir);
-}
+ struct dma_map_ops *ops = get_dma_ops(dev);
-static inline void dma_sync_sg_for_device(struct device *dev,
- struct scatterlist *sg, int nelems,
- enum dma_data_direction dir)
-{
- __dma_sync_sg(dev, sg, nelems, dir);
- debug_dma_sync_sg_for_device(dev, sg, nelems, dir);
-}
+ WARN_ON(irqs_disabled()); /* for portability */
-static inline int dma_get_cache_alignment(void)
-{
- /*
- * Each processor family will define its own L1_CACHE_SHIFT,
- * L1_CACHE_BYTES wraps to this, so this is always safe.
- */
- return L1_CACHE_BYTES;
-}
+ if (dma_release_from_coherent(dev, get_order(size), vaddr))
+ return;
-static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
- return dma_addr == 0;
+ debug_dma_free_coherent(dev, size, vaddr, dma_handle);
+ if (ops->free_coherent)
+ ops->free_coherent(dev, size, vaddr, dma_handle);
}
-#define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
-
-extern int
-dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
- dma_addr_t device_addr, size_t size, int flags);
-
-extern void
-dma_release_declared_memory(struct device *dev);
-
-extern void *
-dma_mark_declared_memory_occupied(struct device *dev,
- dma_addr_t device_addr, size_t size);
+/* arch/sh/mm/consistent.c */
+extern void *dma_generic_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_addr, gfp_t flag);
+extern void dma_generic_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle);
#endif /* __ASM_SH_DMA_MAPPING_H */
diff --git a/arch/sh/include/asm/dwarf.h b/arch/sh/include/asm/dwarf.h
index ced6795891a6..bdccbbfdc0bd 100644
--- a/arch/sh/include/asm/dwarf.h
+++ b/arch/sh/include/asm/dwarf.h
@@ -194,6 +194,12 @@
#define DWARF_ARCH_RA_REG 17
#ifndef __ASSEMBLY__
+
+#include <linux/compiler.h>
+#include <linux/bug.h>
+#include <linux/list.h>
+#include <linux/module.h>
+
/*
* Read either the frame pointer (r14) or the stack pointer (r15).
* NOTE: this MUST be inlined.
@@ -241,6 +247,12 @@ struct dwarf_cie {
unsigned long flags;
#define DWARF_CIE_Z_AUGMENTATION (1 << 0)
+
+ /*
+ * 'mod' will be non-NULL if this CIE came from a module's
+ * .eh_frame section.
+ */
+ struct module *mod;
};
/**
@@ -255,6 +267,12 @@ struct dwarf_fde {
unsigned char *instructions;
unsigned char *end;
struct list_head link;
+
+ /*
+ * 'mod' will be non-NULL if this FDE came from a module's
+ * .eh_frame section.
+ */
+ struct module *mod;
};
/**
@@ -364,6 +382,12 @@ static inline unsigned int DW_CFA_operand(unsigned long insn)
extern struct dwarf_frame *dwarf_unwind_stack(unsigned long,
struct dwarf_frame *);
+extern void dwarf_free_frame(struct dwarf_frame *);
+
+extern int module_dwarf_finalize(const Elf_Ehdr *, const Elf_Shdr *,
+ struct module *);
+extern void module_dwarf_cleanup(struct module *);
+
#endif /* !__ASSEMBLY__ */
#define CFI_STARTPROC .cfi_startproc
@@ -391,6 +415,10 @@ extern struct dwarf_frame *dwarf_unwind_stack(unsigned long,
static inline void dwarf_unwinder_init(void)
{
}
+
+#define module_dwarf_finalize(hdr, sechdrs, me) (0)
+#define module_dwarf_cleanup(mod) do { } while (0)
+
#endif
#endif /* CONFIG_DWARF_UNWINDER */
diff --git a/arch/sh/include/asm/fixmap.h b/arch/sh/include/asm/fixmap.h
index 721fcc4d5e98..76c5a3099cb8 100644
--- a/arch/sh/include/asm/fixmap.h
+++ b/arch/sh/include/asm/fixmap.h
@@ -14,9 +14,9 @@
#define _ASM_FIXMAP_H
#include <linux/kernel.h>
+#include <linux/threads.h>
#include <asm/page.h>
#ifdef CONFIG_HIGHMEM
-#include <linux/threads.h>
#include <asm/kmap_types.h>
#endif
@@ -46,9 +46,9 @@
* fix-mapped?
*/
enum fixed_addresses {
-#define FIX_N_COLOURS 16
+#define FIX_N_COLOURS 8
FIX_CMAP_BEGIN,
- FIX_CMAP_END = FIX_CMAP_BEGIN + FIX_N_COLOURS,
+ FIX_CMAP_END = FIX_CMAP_BEGIN + (FIX_N_COLOURS * NR_CPUS),
FIX_UNCACHED,
#ifdef CONFIG_HIGHMEM
FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
diff --git a/arch/sh/include/asm/ftrace.h b/arch/sh/include/asm/ftrace.h
index 12f3a31f20af..13e9966464c2 100644
--- a/arch/sh/include/asm/ftrace.h
+++ b/arch/sh/include/asm/ftrace.h
@@ -35,4 +35,21 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr)
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_FUNCTION_TRACER */
+#ifndef __ASSEMBLY__
+
+/* arch/sh/kernel/return_address.c */
+extern void *return_address(unsigned int);
+
+#define HAVE_ARCH_CALLER_ADDR
+
+#define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0))
+#define CALLER_ADDR1 ((unsigned long)return_address(1))
+#define CALLER_ADDR2 ((unsigned long)return_address(2))
+#define CALLER_ADDR3 ((unsigned long)return_address(3))
+#define CALLER_ADDR4 ((unsigned long)return_address(4))
+#define CALLER_ADDR5 ((unsigned long)return_address(5))
+#define CALLER_ADDR6 ((unsigned long)return_address(6))
+
+#endif /* __ASSEMBLY__ */
+
#endif /* __ASM_SH_FTRACE_H */
diff --git a/arch/sh/include/asm/hardirq.h b/arch/sh/include/asm/hardirq.h
index a5be4afa790b..48b191313a99 100644
--- a/arch/sh/include/asm/hardirq.h
+++ b/arch/sh/include/asm/hardirq.h
@@ -1,9 +1,16 @@
#ifndef __ASM_SH_HARDIRQ_H
#define __ASM_SH_HARDIRQ_H
-extern void ack_bad_irq(unsigned int irq);
-#define ack_bad_irq ack_bad_irq
+#include <linux/threads.h>
+#include <linux/irq.h>
+
+typedef struct {
+ unsigned int __softirq_pending;
+ unsigned int __nmi_count; /* arch dependent */
+} ____cacheline_aligned irq_cpustat_t;
-#include <asm-generic/hardirq.h>
+#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+
+extern void ack_bad_irq(unsigned int irq);
#endif /* __ASM_SH_HARDIRQ_H */
diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h
index 5be45ea4dfec..0cf2a5708e26 100644
--- a/arch/sh/include/asm/io.h
+++ b/arch/sh/include/asm/io.h
@@ -246,7 +246,7 @@ void __iounmap(void __iomem *addr);
static inline void __iomem *
__ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
{
-#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED)
+#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED) && !defined(CONFIG_PMB)
unsigned long last_addr = offset + size - 1;
#endif
void __iomem *ret;
@@ -255,7 +255,7 @@ __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
if (ret)
return ret;
-#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED)
+#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED) && !defined(CONFIG_PMB)
/*
* For P1 and P2 space this is trivial, as everything is already
* mapped. Uncached access for P1 addresses are done through P2.
diff --git a/arch/sh/include/asm/irqflags.h b/arch/sh/include/asm/irqflags.h
index 46e71da5be6b..a741153b41c2 100644
--- a/arch/sh/include/asm/irqflags.h
+++ b/arch/sh/include/asm/irqflags.h
@@ -1,34 +1,9 @@
#ifndef __ASM_SH_IRQFLAGS_H
#define __ASM_SH_IRQFLAGS_H
-#ifdef CONFIG_SUPERH32
-#include "irqflags_32.h"
-#else
-#include "irqflags_64.h"
-#endif
+#define RAW_IRQ_DISABLED 0xf0
+#define RAW_IRQ_ENABLED 0x00
-#define raw_local_save_flags(flags) \
- do { (flags) = __raw_local_save_flags(); } while (0)
-
-static inline int raw_irqs_disabled_flags(unsigned long flags)
-{
- return (flags != 0);
-}
-
-static inline int raw_irqs_disabled(void)
-{
- unsigned long flags = __raw_local_save_flags();
-
- return raw_irqs_disabled_flags(flags);
-}
-
-#define raw_local_irq_save(flags) \
- do { (flags) = __raw_local_irq_save(); } while (0)
-
-static inline void raw_local_irq_restore(unsigned long flags)
-{
- if ((flags & 0xf0) != 0xf0)
- raw_local_irq_enable();
-}
+#include <asm-generic/irqflags.h>
#endif /* __ASM_SH_IRQFLAGS_H */
diff --git a/arch/sh/include/asm/irqflags_32.h b/arch/sh/include/asm/irqflags_32.h
deleted file mode 100644
index 60218f541340..000000000000
--- a/arch/sh/include/asm/irqflags_32.h
+++ /dev/null
@@ -1,99 +0,0 @@
-#ifndef __ASM_SH_IRQFLAGS_32_H
-#define __ASM_SH_IRQFLAGS_32_H
-
-static inline void raw_local_irq_enable(void)
-{
- unsigned long __dummy0, __dummy1;
-
- __asm__ __volatile__ (
- "stc sr, %0\n\t"
- "and %1, %0\n\t"
-#ifdef CONFIG_CPU_HAS_SR_RB
- "stc r6_bank, %1\n\t"
- "or %1, %0\n\t"
-#endif
- "ldc %0, sr\n\t"
- : "=&r" (__dummy0), "=r" (__dummy1)
- : "1" (~0x000000f0)
- : "memory"
- );
-}
-
-static inline void raw_local_irq_disable(void)
-{
- unsigned long flags;
-
- __asm__ __volatile__ (
- "stc sr, %0\n\t"
- "or #0xf0, %0\n\t"
- "ldc %0, sr\n\t"
- : "=&z" (flags)
- : /* no inputs */
- : "memory"
- );
-}
-
-static inline void set_bl_bit(void)
-{
- unsigned long __dummy0, __dummy1;
-
- __asm__ __volatile__ (
- "stc sr, %0\n\t"
- "or %2, %0\n\t"
- "and %3, %0\n\t"
- "ldc %0, sr\n\t"
- : "=&r" (__dummy0), "=r" (__dummy1)
- : "r" (0x10000000), "r" (0xffffff0f)
- : "memory"
- );
-}
-
-static inline void clear_bl_bit(void)
-{
- unsigned long __dummy0, __dummy1;
-
- __asm__ __volatile__ (
- "stc sr, %0\n\t"
- "and %2, %0\n\t"
- "ldc %0, sr\n\t"
- : "=&r" (__dummy0), "=r" (__dummy1)
- : "1" (~0x10000000)
- : "memory"
- );
-}
-
-static inline unsigned long __raw_local_save_flags(void)
-{
- unsigned long flags;
-
- __asm__ __volatile__ (
- "stc sr, %0\n\t"
- "and #0xf0, %0\n\t"
- : "=&z" (flags)
- : /* no inputs */
- : "memory"
- );
-
- return flags;
-}
-
-static inline unsigned long __raw_local_irq_save(void)
-{
- unsigned long flags, __dummy;
-
- __asm__ __volatile__ (
- "stc sr, %1\n\t"
- "mov %1, %0\n\t"
- "or #0xf0, %0\n\t"
- "ldc %0, sr\n\t"
- "mov %1, %0\n\t"
- "and #0xf0, %0\n\t"
- : "=&z" (flags), "=&r" (__dummy)
- : /* no inputs */
- : "memory"
- );
-
- return flags;
-}
-
-#endif /* __ASM_SH_IRQFLAGS_32_H */
diff --git a/arch/sh/include/asm/irqflags_64.h b/arch/sh/include/asm/irqflags_64.h
deleted file mode 100644
index 88f65222c1d4..000000000000
--- a/arch/sh/include/asm/irqflags_64.h
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef __ASM_SH_IRQFLAGS_64_H
-#define __ASM_SH_IRQFLAGS_64_H
-
-#include <cpu/registers.h>
-
-#define SR_MASK_LL 0x00000000000000f0LL
-#define SR_BL_LL 0x0000000010000000LL
-
-static inline void raw_local_irq_enable(void)
-{
- unsigned long long __dummy0, __dummy1 = ~SR_MASK_LL;
-
- __asm__ __volatile__("getcon " __SR ", %0\n\t"
- "and %0, %1, %0\n\t"
- "putcon %0, " __SR "\n\t"
- : "=&r" (__dummy0)
- : "r" (__dummy1));
-}
-
-static inline void raw_local_irq_disable(void)
-{
- unsigned long long __dummy0, __dummy1 = SR_MASK_LL;
-
- __asm__ __volatile__("getcon " __SR ", %0\n\t"
- "or %0, %1, %0\n\t"
- "putcon %0, " __SR "\n\t"
- : "=&r" (__dummy0)
- : "r" (__dummy1));
-}
-
-static inline void set_bl_bit(void)
-{
- unsigned long long __dummy0, __dummy1 = SR_BL_LL;
-
- __asm__ __volatile__("getcon " __SR ", %0\n\t"
- "or %0, %1, %0\n\t"
- "putcon %0, " __SR "\n\t"
- : "=&r" (__dummy0)
- : "r" (__dummy1));
-
-}
-
-static inline void clear_bl_bit(void)
-{
- unsigned long long __dummy0, __dummy1 = ~SR_BL_LL;
-
- __asm__ __volatile__("getcon " __SR ", %0\n\t"
- "and %0, %1, %0\n\t"
- "putcon %0, " __SR "\n\t"
- : "=&r" (__dummy0)
- : "r" (__dummy1));
-}
-
-static inline unsigned long __raw_local_save_flags(void)
-{
- unsigned long long __dummy = SR_MASK_LL;
- unsigned long flags;
-
- __asm__ __volatile__ (
- "getcon " __SR ", %0\n\t"
- "and %0, %1, %0"
- : "=&r" (flags)
- : "r" (__dummy));
-
- return flags;
-}
-
-static inline unsigned long __raw_local_irq_save(void)
-{
- unsigned long long __dummy0, __dummy1 = SR_MASK_LL;
- unsigned long flags;
-
- __asm__ __volatile__ (
- "getcon " __SR ", %1\n\t"
- "or %1, r63, %0\n\t"
- "or %1, %2, %1\n\t"
- "putcon %1, " __SR "\n\t"
- "and %0, %2, %0"
- : "=&r" (flags), "=&r" (__dummy0)
- : "r" (__dummy1));
-
- return flags;
-}
-
-#endif /* __ASM_SH_IRQFLAGS_64_H */
diff --git a/arch/sh/include/asm/machvec.h b/arch/sh/include/asm/machvec.h
index 84dd37761f56..9c30955630ff 100644
--- a/arch/sh/include/asm/machvec.h
+++ b/arch/sh/include/asm/machvec.h
@@ -12,7 +12,7 @@
#include <linux/types.h>
#include <linux/time.h>
-#include <asm/machtypes.h>
+#include <generated/machtypes.h>
struct sh_machine_vector {
void (*mv_setup)(char **cmdline_p);
diff --git a/arch/sh/include/asm/mmu.h b/arch/sh/include/asm/mmu.h
index f5963037c9d6..c7426ad9926e 100644
--- a/arch/sh/include/asm/mmu.h
+++ b/arch/sh/include/asm/mmu.h
@@ -7,12 +7,16 @@
#define PMB_PASCR 0xff000070
#define PMB_IRMCR 0xff000078
+#define PASCR_SE 0x80000000
+
#define PMB_ADDR 0xf6100000
#define PMB_DATA 0xf7100000
#define PMB_ENTRY_MAX 16
#define PMB_E_MASK 0x0000000f
#define PMB_E_SHIFT 8
+#define PMB_PFN_MASK 0xff000000
+
#define PMB_SZ_16M 0x00000000
#define PMB_SZ_64M 0x00000010
#define PMB_SZ_128M 0x00000080
@@ -62,17 +66,10 @@ struct pmb_entry {
};
/* arch/sh/mm/pmb.c */
-int __set_pmb_entry(unsigned long vpn, unsigned long ppn,
- unsigned long flags, int *entry);
-int set_pmb_entry(struct pmb_entry *pmbe);
-void clear_pmb_entry(struct pmb_entry *pmbe);
-struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn,
- unsigned long flags);
-void pmb_free(struct pmb_entry *pmbe);
long pmb_remap(unsigned long virt, unsigned long phys,
unsigned long size, unsigned long flags);
void pmb_unmap(unsigned long addr);
+int pmb_init(void);
#endif /* __ASSEMBLY__ */
#endif /* __MMU_H */
-
diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h
index 4163950cd1c6..67f3999b544e 100644
--- a/arch/sh/include/asm/pci.h
+++ b/arch/sh/include/asm/pci.h
@@ -3,8 +3,6 @@
#ifdef __KERNEL__
-#include <linux/dma-mapping.h>
-
/* Can be used to override the logic in pci_scan_bus for skipping
already-configured bus numbers - to be used for buggy BIOSes
or architectures with incomplete PCI setup by the loader */
@@ -54,30 +52,18 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
* address space. The networking and block device layers use
* this boolean for bounce buffer decisions.
*/
-#define PCI_DMA_BUS_IS_PHYS (1)
-
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <asm/scatterlist.h>
-#include <linux/string.h>
-#include <asm/io.h>
+#define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys)
/* pci_unmap_{single,page} being a nop depends upon the
* configuration.
*/
-#ifdef CONFIG_SH_PCIDMA_NONCOHERENT
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \
- dma_addr_t ADDR_NAME;
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \
- __u32 LEN_NAME;
-#define pci_unmap_addr(PTR, ADDR_NAME) \
- ((PTR)->ADDR_NAME)
-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \
- (((PTR)->ADDR_NAME) = (VAL))
-#define pci_unmap_len(PTR, LEN_NAME) \
- ((PTR)->LEN_NAME)
-#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \
- (((PTR)->LEN_NAME) = (VAL))
+#ifdef CONFIG_DMA_NONCOHERENT
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) __u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME) ((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) (((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME) ((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL) (((PTR)->LEN_NAME) = (VAL))
#else
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
diff --git a/arch/sh/include/asm/pgtable.h b/arch/sh/include/asm/pgtable.h
index 4f3efa7d5a64..ba3046e4f06f 100644
--- a/arch/sh/include/asm/pgtable.h
+++ b/arch/sh/include/asm/pgtable.h
@@ -75,13 +75,31 @@ static inline unsigned long long neff_sign_extend(unsigned long val)
#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
#define FIRST_USER_ADDRESS 0
-#ifdef CONFIG_32BIT
-#define PHYS_ADDR_MASK 0xffffffff
+#define PHYS_ADDR_MASK29 0x1fffffff
+#define PHYS_ADDR_MASK32 0xffffffff
+
+#ifdef CONFIG_PMB
+static inline unsigned long phys_addr_mask(void)
+{
+ /* Is the MMU in 29bit mode? */
+ if (__in_29bit_mode())
+ return PHYS_ADDR_MASK29;
+
+ return PHYS_ADDR_MASK32;
+}
+#elif defined(CONFIG_32BIT)
+static inline unsigned long phys_addr_mask(void)
+{
+ return PHYS_ADDR_MASK32;
+}
#else
-#define PHYS_ADDR_MASK 0x1fffffff
+static inline unsigned long phys_addr_mask(void)
+{
+ return PHYS_ADDR_MASK29;
+}
#endif
-#define PTE_PHYS_MASK (PHYS_ADDR_MASK & PAGE_MASK)
+#define PTE_PHYS_MASK (phys_addr_mask() & PAGE_MASK)
#define PTE_FLAGS_MASK (~(PTE_PHYS_MASK) << PAGE_SHIFT)
#ifdef CONFIG_SUPERH32
diff --git a/arch/sh/include/asm/pgtable_32.h b/arch/sh/include/asm/pgtable_32.h
index c0d359ce337b..b35435516203 100644
--- a/arch/sh/include/asm/pgtable_32.h
+++ b/arch/sh/include/asm/pgtable_32.h
@@ -108,7 +108,7 @@ static inline unsigned long copy_ptea_attributes(unsigned long x)
#define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED | _PAGE_FILE)
#endif
-#define _PAGE_FLAGS_HARDWARE_MASK (PHYS_ADDR_MASK & ~(_PAGE_CLEAR_FLAGS))
+#define _PAGE_FLAGS_HARDWARE_MASK (phys_addr_mask() & ~(_PAGE_CLEAR_FLAGS))
/* Hardware flags, page size encoding */
#if !defined(CONFIG_MMU)
diff --git a/arch/sh/include/asm/scatterlist.h b/arch/sh/include/asm/scatterlist.h
index 327cc2e4c97b..e38d1d4c7f6f 100644
--- a/arch/sh/include/asm/scatterlist.h
+++ b/arch/sh/include/asm/scatterlist.h
@@ -1,7 +1,7 @@
#ifndef __ASM_SH_SCATTERLIST_H
#define __ASM_SH_SCATTERLIST_H
-#define ISA_DMA_THRESHOLD PHYS_ADDR_MASK
+#define ISA_DMA_THRESHOLD phys_addr_mask()
#include <asm-generic/scatterlist.h>
diff --git a/arch/sh/include/asm/sh_eth.h b/arch/sh/include/asm/sh_eth.h
index acf99700deed..f739061e2ee4 100644
--- a/arch/sh/include/asm/sh_eth.h
+++ b/arch/sh/include/asm/sh_eth.h
@@ -7,6 +7,7 @@ struct sh_eth_plat_data {
int phy;
int edmac_endian;
+ unsigned char mac_addr[6];
unsigned no_ether_link:1;
unsigned ether_link_active_low:1;
};
diff --git a/arch/sh/include/asm/system_32.h b/arch/sh/include/asm/system_32.h
index 607d413f6168..06814f5b59c7 100644
--- a/arch/sh/include/asm/system_32.h
+++ b/arch/sh/include/asm/system_32.h
@@ -232,4 +232,33 @@ asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7,
struct pt_regs __regs);
+static inline void set_bl_bit(void)
+{
+ unsigned long __dummy0, __dummy1;
+
+ __asm__ __volatile__ (
+ "stc sr, %0\n\t"
+ "or %2, %0\n\t"
+ "and %3, %0\n\t"
+ "ldc %0, sr\n\t"
+ : "=&r" (__dummy0), "=r" (__dummy1)
+ : "r" (0x10000000), "r" (0xffffff0f)
+ : "memory"
+ );
+}
+
+static inline void clear_bl_bit(void)
+{
+ unsigned long __dummy0, __dummy1;
+
+ __asm__ __volatile__ (
+ "stc sr, %0\n\t"
+ "and %2, %0\n\t"
+ "ldc %0, sr\n\t"
+ : "=&r" (__dummy0), "=r" (__dummy1)
+ : "1" (~0x10000000)
+ : "memory"
+ );
+}
+
#endif /* __ASM_SH_SYSTEM_32_H */
diff --git a/arch/sh/include/asm/system_64.h b/arch/sh/include/asm/system_64.h
index 8e4a03e7966c..ab1dd917ea87 100644
--- a/arch/sh/include/asm/system_64.h
+++ b/arch/sh/include/asm/system_64.h
@@ -12,6 +12,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
+#include <cpu/registers.h>
#include <asm/processor.h>
/*
@@ -47,4 +48,29 @@ static inline reg_size_t register_align(void *val)
return (unsigned long long)(signed long long)(signed long)val;
}
+#define SR_BL_LL 0x0000000010000000LL
+
+static inline void set_bl_bit(void)
+{
+ unsigned long long __dummy0, __dummy1 = SR_BL_LL;
+
+ __asm__ __volatile__("getcon " __SR ", %0\n\t"
+ "or %0, %1, %0\n\t"
+ "putcon %0, " __SR "\n\t"
+ : "=&r" (__dummy0)
+ : "r" (__dummy1));
+
+}
+
+static inline void clear_bl_bit(void)
+{
+ unsigned long long __dummy0, __dummy1 = ~SR_BL_LL;
+
+ __asm__ __volatile__("getcon " __SR ", %0\n\t"
+ "and %0, %1, %0\n\t"
+ "putcon %0, " __SR "\n\t"
+ : "=&r" (__dummy0)
+ : "r" (__dummy1));
+}
+
#endif /* __ASM_SH_SYSTEM_64_H */
diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h
index bdeb9d46d17d..23eeed89467a 100644
--- a/arch/sh/include/asm/thread_info.h
+++ b/arch/sh/include/asm/thread_info.h
@@ -19,6 +19,7 @@ struct thread_info {
struct task_struct *task; /* main task structure */
struct exec_domain *exec_domain; /* execution domain */
unsigned long flags; /* low level flags */
+ __u32 status; /* thread synchronous flags */
__u32 cpu;
int preempt_count; /* 0 => preemptable, <0 => BUG */
mm_segment_t addr_limit; /* thread address space */
@@ -111,7 +112,6 @@ extern void free_thread_info(struct thread_info *ti);
#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
#define TIF_SIGPENDING 1 /* signal pending */
#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
-#define TIF_RESTORE_SIGMASK 3 /* restore signal mask in do_signal() */
#define TIF_SINGLESTEP 4 /* singlestepping active */
#define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */
#define TIF_SECCOMP 6 /* secure computing */
@@ -125,7 +125,6 @@ extern void free_thread_info(struct thread_info *ti);
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
-#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
@@ -149,13 +148,32 @@ extern void free_thread_info(struct thread_info *ti);
/* work to do on any return to u-space */
#define _TIF_ALLWORK_MASK (_TIF_SYSCALL_TRACE | _TIF_SIGPENDING | \
_TIF_NEED_RESCHED | _TIF_SYSCALL_AUDIT | \
- _TIF_SINGLESTEP | _TIF_RESTORE_SIGMASK | \
- _TIF_NOTIFY_RESUME | _TIF_SYSCALL_TRACEPOINT)
+ _TIF_SINGLESTEP | _TIF_NOTIFY_RESUME | \
+ _TIF_SYSCALL_TRACEPOINT)
/* work to do on interrupt/exception return */
#define _TIF_WORK_MASK (_TIF_ALLWORK_MASK & ~(_TIF_SYSCALL_TRACE | \
_TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP))
+/*
+ * Thread-synchronous status.
+ *
+ * This is different from the flags in that nobody else
+ * ever touches our thread-synchronous status, so we don't
+ * have to worry about atomic accesses.
+ */
+#define TS_RESTORE_SIGMASK 0x0001 /* restore signal mask in do_signal() */
+
+#ifndef __ASSEMBLY__
+#define HAVE_SET_RESTORE_SIGMASK 1
+static inline void set_restore_sigmask(void)
+{
+ struct thread_info *ti = current_thread_info();
+ ti->status |= TS_RESTORE_SIGMASK;
+ set_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags);
+}
+#endif /* !__ASSEMBLY__ */
+
#endif /* __KERNEL__ */
#endif /* __ASM_SH_THREAD_INFO_H */
diff --git a/arch/sh/include/asm/topology.h b/arch/sh/include/asm/topology.h
index 65e7bd2f2240..37cdadd975ac 100644
--- a/arch/sh/include/asm/topology.h
+++ b/arch/sh/include/asm/topology.h
@@ -40,6 +40,14 @@
#endif
+#define mc_capable() (1)
+
+const struct cpumask *cpu_coregroup_mask(unsigned int cpu);
+
+extern cpumask_t cpu_core_map[NR_CPUS];
+
+#define topology_core_cpumask(cpu) (&cpu_core_map[cpu])
+
#include <asm-generic/topology.h>
#endif /* _ASM_SH_TOPOLOGY_H */
diff --git a/arch/sh/include/asm/ubc.h b/arch/sh/include/asm/ubc.h
index 4ca4b7717371..9bf961684431 100644
--- a/arch/sh/include/asm/ubc.h
+++ b/arch/sh/include/asm/ubc.h
@@ -60,16 +60,5 @@
#define BRCR_UBDE (1 << 0)
#endif
-#ifndef __ASSEMBLY__
-/* arch/sh/kernel/cpu/ubc.S */
-extern void ubc_sleep(void);
-
-#ifdef CONFIG_UBC_WAKEUP
-extern void ubc_wakeup(void);
-#else
-#define ubc_wakeup() do { } while (0)
-#endif
-#endif
-
#endif /* __KERNEL__ */
#endif /* __ASM_SH_UBC_H */
diff --git a/arch/sh/include/asm/watchdog.h b/arch/sh/include/asm/watchdog.h
index 2fe7cee9e43a..19dfff5c8511 100644
--- a/arch/sh/include/asm/watchdog.h
+++ b/arch/sh/include/asm/watchdog.h
@@ -2,6 +2,8 @@
* include/asm-sh/watchdog.h
*
* Copyright (C) 2002, 2003 Paul Mundt
+ * Copyright (C) 2009 Siemens AG
+ * Copyright (C) 2009 Valentin Sitdikov
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -61,6 +63,61 @@
#define WTCSR_CKS_2048 0x06
#define WTCSR_CKS_4096 0x07
+#if defined(CONFIG_CPU_SUBTYPE_SH7785) || defined(CONFIG_CPU_SUBTYPE_SH7780)
+/**
+ * sh_wdt_read_cnt - Read from Counter
+ * Reads back the WTCNT value.
+ */
+static inline __u32 sh_wdt_read_cnt(void)
+{
+ return ctrl_inl(WTCNT_R);
+}
+
+/**
+ * sh_wdt_write_cnt - Write to Counter
+ * @val: Value to write
+ *
+ * Writes the given value @val to the lower byte of the timer counter.
+ * The upper byte is set manually on each write.
+ */
+static inline void sh_wdt_write_cnt(__u32 val)
+{
+ ctrl_outl((WTCNT_HIGH << 24) | (__u32)val, WTCNT);
+}
+
+/**
+ * sh_wdt_write_bst - Write to Counter
+ * @val: Value to write
+ *
+ * Writes the given value @val to the lower byte of the timer counter.
+ * The upper byte is set manually on each write.
+ */
+static inline void sh_wdt_write_bst(__u32 val)
+{
+ ctrl_outl((WTBST_HIGH << 24) | (__u32)val, WTBST);
+}
+/**
+ * sh_wdt_read_csr - Read from Control/Status Register
+ *
+ * Reads back the WTCSR value.
+ */
+static inline __u32 sh_wdt_read_csr(void)
+{
+ return ctrl_inl(WTCSR_R);
+}
+
+/**
+ * sh_wdt_write_csr - Write to Control/Status Register
+ * @val: Value to write
+ *
+ * Writes the given value @val to the lower byte of the control/status
+ * register. The upper byte is set manually on each write.
+ */
+static inline void sh_wdt_write_csr(__u32 val)
+{
+ ctrl_outl((WTCSR_HIGH << 24) | (__u32)val, WTCSR);
+}
+#else
/**
* sh_wdt_read_cnt - Read from Counter
* Reads back the WTCNT value.
@@ -103,6 +160,6 @@ static inline void sh_wdt_write_csr(__u8 val)
{
ctrl_outw((WTCSR_HIGH << 8) | (__u16)val, WTCSR);
}
-
+#endif /* CONFIG_CPU_SUBTYPE_SH7785 || CONFIG_CPU_SUBTYPE_SH7780 */
#endif /* __KERNEL__ */
#endif /* __ASM_SH_WATCHDOG_H */
diff --git a/arch/sh/include/cpu-sh4/cpu/watchdog.h b/arch/sh/include/cpu-sh4/cpu/watchdog.h
index 259f6a0ce23d..7672301d0c70 100644
--- a/arch/sh/include/cpu-sh4/cpu/watchdog.h
+++ b/arch/sh/include/cpu-sh4/cpu/watchdog.h
@@ -2,6 +2,8 @@
* include/asm-sh/cpu-sh4/watchdog.h
*
* Copyright (C) 2002, 2003 Paul Mundt
+ * Copyright (C) 2009 Siemens AG
+ * Copyright (C) 2009 Sitdikov Valentin
*
* 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
@@ -10,9 +12,20 @@
#ifndef __ASM_CPU_SH4_WATCHDOG_H
#define __ASM_CPU_SH4_WATCHDOG_H
+#if defined(CONFIG_CPU_SUBTYPE_SH7785) || defined(CONFIG_CPU_SUBTYPE_SH7780)
+/* Prefix definition */
+#define WTBST_HIGH 0x55
+/* Register definitions */
+#define WTCNT_R 0xffcc0010 /*WDTCNT*/
+#define WTCSR 0xffcc0004 /*WDTCSR*/
+#define WTCNT 0xffcc0000 /*WDTST*/
+#define WTST WTCNT
+#define WTBST 0xffcc0008 /*WDTBST*/
+#else
/* Register definitions */
#define WTCNT 0xffc00008
#define WTCSR 0xffc0000c
+#endif
/* Bit definitions */
#define WTCSR_TME 0x80
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index a2d0a40f3848..097ae5ceb0e3 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -9,8 +9,12 @@ ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_ftrace.o = -pg
endif
-obj-y := debugtraps.o dumpstack.o idle.o io.o io_generic.o irq.o \
- machvec.o nmi_debug.o process_$(BITS).o ptrace_$(BITS).o \
+CFLAGS_REMOVE_return_address.o = -pg
+
+obj-y := debugtraps.o dma-nommu.o dumpstack.o \
+ idle.o io.o io_generic.o irq.o \
+ irq_$(BITS).o machvec.o nmi_debug.o process_$(BITS).o \
+ ptrace_$(BITS).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 \
traps_$(BITS).o unwinder.o
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
index 3d6b9312dc47..d97c803719ec 100644
--- a/arch/sh/kernel/cpu/Makefile
+++ b/arch/sh/kernel/cpu/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_ARCH_SHMOBILE) += shmobile/
# Common interfaces.
-obj-$(CONFIG_UBC_WAKEUP) += ubc.o
obj-$(CONFIG_SH_ADC) += adc.o
obj-$(CONFIG_SH_CLK_CPG) += clock-cpg.o
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index e932ebef4738..580d58b94cc5 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -338,17 +338,6 @@ asmlinkage void __init sh_cpu_init(void)
}
#endif
- /*
- * Some brain-damaged loaders decided it would be a good idea to put
- * the UBC to sleep. This causes some issues when it comes to things
- * like PTRACE_SINGLESTEP or doing hardware watchpoints in GDB. So ..
- * we wake it up and hope that all is well.
- */
-#ifdef CONFIG_SUPERH32
- if (raw_smp_processor_id() == 0)
- ubc_wakeup();
-#endif
-
speculative_execution_init();
expmask_init();
}
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index bb407ef0b91e..3f7e2a22c7c2 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -297,41 +297,8 @@ ENTRY(vbr_base)
!
.balign 256,0,256
general_exception:
-#ifndef CONFIG_CPU_SUBTYPE_SHX3
bra handle_exception
sts pr, k3 ! save original pr value in k3
-#else
- mov.l 1f, k4
- mov.l @k4, k4
-
- ! Is EXPEVT larger than 0x800?
- mov #0x8, k0
- shll8 k0
- cmp/hs k0, k4
- bf 0f
-
- ! then add 0x580 (k2 is 0xd80 or 0xda0)
- mov #0x58, k0
- shll2 k0
- shll2 k0
- add k0, k4
-0:
- ! Setup stack and save DSP context (k0 contains original r15 on return)
- bsr prepare_stack
- nop
-
- ! Save registers / Switch to bank 0
- mov k4, k2 ! keep vector in k2
- mov.l 1f, k4 ! SR bits to clear in k4
- bsr save_regs ! needs original pr value in k3
- nop
-
- bra handle_exception_special
- nop
-
- .align 2
-1: .long EXPEVT
-#endif
! prepare_stack()
! - roll back gRB
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
index e848443deeb9..c7ba9166e18a 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
@@ -15,6 +15,15 @@
#include <linux/sh_timer.h>
#include <asm/mmzone.h>
+/*
+ * This intentionally only registers SCIF ports 0, 1, and 3. SCIF 2
+ * INTEVT values overlap with the FPU EXPEVT ones, requiring special
+ * demuxing in the exception dispatch path.
+ *
+ * As this overlap is something that never should have made it in to
+ * silicon in the first place, we just refuse to deal with the port at
+ * all rather than adding infrastructure to hack around it.
+ */
static struct plat_sci_port sci_platform_data[] = {
{
.mapbase = 0xffc30000,
@@ -27,11 +36,6 @@ static struct plat_sci_port sci_platform_data[] = {
.type = PORT_SCIF,
.irqs = { 44, 45, 47, 46 },
}, {
- .mapbase = 0xffc50000,
- .flags = UPF_BOOT_AUTOCONF,
- .type = PORT_SCIF,
- .irqs = { 48, 49, 51, 50 },
- }, {
.mapbase = 0xffc60000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
@@ -268,7 +272,11 @@ enum {
UNUSED = 0,
/* interrupt sources */
- IRL, IRQ0, IRQ1, IRQ2, IRQ3,
+ IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+ IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+ IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+ IRL_HHLL, IRL_HHLH, IRL_HHHL,
+ IRQ0, IRQ1, IRQ2, IRQ3,
HUDII,
TMU0, TMU1, TMU2, TMU3, TMU4, TMU5,
PCII0, PCII1, PCII2, PCII3, PCII4,
@@ -291,7 +299,7 @@ enum {
INTICI4, INTICI5, INTICI6, INTICI7,
/* interrupt groups */
- PCII56789, SCIF0, SCIF1, SCIF2, SCIF3,
+ IRL, PCII56789, SCIF0, SCIF1, SCIF2, SCIF3,
DMAC0, DMAC1,
};
@@ -309,8 +317,6 @@ static struct intc_vect vectors[] __initdata = {
INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760),
INTC_VECT(SCIF1_ERI, 0x780), INTC_VECT(SCIF1_RXI, 0x7a0),
INTC_VECT(SCIF1_BRI, 0x7c0), INTC_VECT(SCIF1_TXI, 0x7e0),
- INTC_VECT(SCIF2_ERI, 0x800), INTC_VECT(SCIF2_RXI, 0x820),
- INTC_VECT(SCIF2_BRI, 0x840), INTC_VECT(SCIF2_TXI, 0x860),
INTC_VECT(SCIF3_ERI, 0x880), INTC_VECT(SCIF3_RXI, 0x8a0),
INTC_VECT(SCIF3_BRI, 0x8c0), INTC_VECT(SCIF3_TXI, 0x8e0),
INTC_VECT(DMAC0_DMINT0, 0x900), INTC_VECT(DMAC0_DMINT1, 0x920),
@@ -344,10 +350,13 @@ static struct intc_vect vectors[] __initdata = {
};
static struct intc_group groups[] __initdata = {
+ INTC_GROUP(IRL, IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+ IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+ IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+ IRL_HHLL, IRL_HHLH, IRL_HHHL),
INTC_GROUP(PCII56789, PCII5, PCII6, PCII7, PCII8, PCII9),
INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
- INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
INTC_GROUP(SCIF3, SCIF3_ERI, SCIF3_RXI, SCIF3_BRI, SCIF3_TXI),
INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE),
@@ -419,14 +428,14 @@ static DECLARE_INTC_DESC(intc_desc_irq, "shx3-irq", vectors_irq, groups,
/* External interrupt pins in IRL mode */
static struct intc_vect vectors_irl[] __initdata = {
- INTC_VECT(IRL, 0x200), INTC_VECT(IRL, 0x220),
- INTC_VECT(IRL, 0x240), INTC_VECT(IRL, 0x260),
- INTC_VECT(IRL, 0x280), INTC_VECT(IRL, 0x2a0),
- INTC_VECT(IRL, 0x2c0), INTC_VECT(IRL, 0x2e0),
- INTC_VECT(IRL, 0x300), INTC_VECT(IRL, 0x320),
- INTC_VECT(IRL, 0x340), INTC_VECT(IRL, 0x360),
- INTC_VECT(IRL, 0x380), INTC_VECT(IRL, 0x3a0),
- INTC_VECT(IRL, 0x3c0),
+ INTC_VECT(IRL_LLLL, 0x200), INTC_VECT(IRL_LLLH, 0x220),
+ INTC_VECT(IRL_LLHL, 0x240), INTC_VECT(IRL_LLHH, 0x260),
+ INTC_VECT(IRL_LHLL, 0x280), INTC_VECT(IRL_LHLH, 0x2a0),
+ INTC_VECT(IRL_LHHL, 0x2c0), INTC_VECT(IRL_LHHH, 0x2e0),
+ INTC_VECT(IRL_HLLL, 0x300), INTC_VECT(IRL_HLLH, 0x320),
+ INTC_VECT(IRL_HLHL, 0x340), INTC_VECT(IRL_HLHH, 0x360),
+ INTC_VECT(IRL_HHLL, 0x380), INTC_VECT(IRL_HHLH, 0x3a0),
+ INTC_VECT(IRL_HHHL, 0x3c0),
};
static DECLARE_INTC_DESC(intc_desc_irl, "shx3-irl", vectors_irl, groups,
diff --git a/arch/sh/kernel/cpu/sh4a/smp-shx3.c b/arch/sh/kernel/cpu/sh4a/smp-shx3.c
index 185ec3976a25..5863e0c4d02f 100644
--- a/arch/sh/kernel/cpu/sh4a/smp-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/smp-shx3.c
@@ -14,6 +14,13 @@
#include <linux/interrupt.h>
#include <linux/io.h>
+#define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12))
+#define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12))
+
+#define STBCR_MSTP 0x00000001
+#define STBCR_RESET 0x00000002
+#define STBCR_LTSLP 0x80000000
+
static irqreturn_t ipi_interrupt_handler(int irq, void *arg)
{
unsigned int message = (unsigned int)(long)arg;
@@ -21,9 +28,9 @@ static irqreturn_t ipi_interrupt_handler(int irq, void *arg)
unsigned int offs = 4 * cpu;
unsigned int x;
- x = ctrl_inl(0xfe410070 + offs); /* C0INITICI..CnINTICI */
+ x = __raw_readl(0xfe410070 + offs); /* C0INITICI..CnINTICI */
x &= (1 << (message << 2));
- ctrl_outl(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */
+ __raw_writel(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */
smp_message_recv(message);
@@ -37,6 +44,9 @@ void __init plat_smp_setup(void)
init_cpu_possible(cpumask_of(cpu));
+ /* Enable light sleep for the boot CPU */
+ __raw_writel(__raw_readl(STBCR_REG(cpu)) | STBCR_LTSLP, STBCR_REG(cpu));
+
__cpu_number_map[0] = 0;
__cpu_logical_map[0] = 0;
@@ -66,32 +76,23 @@ void __init plat_prepare_cpus(unsigned int max_cpus)
"IPI", (void *)(long)i);
}
-#define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12))
-#define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12))
-
-#define STBCR_MSTP 0x00000001
-#define STBCR_RESET 0x00000002
-#define STBCR_LTSLP 0x80000000
-
-#define STBCR_AP_VAL (STBCR_RESET | STBCR_LTSLP)
-
void plat_start_cpu(unsigned int cpu, unsigned long entry_point)
{
- ctrl_outl(entry_point, RESET_REG(cpu));
+ __raw_writel(entry_point, RESET_REG(cpu));
- if (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP))
- ctrl_outl(STBCR_MSTP, STBCR_REG(cpu));
+ if (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP))
+ __raw_writel(STBCR_MSTP, STBCR_REG(cpu));
- while (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP))
+ while (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP))
cpu_relax();
/* Start up secondary processor by sending a reset */
- ctrl_outl(STBCR_AP_VAL, STBCR_REG(cpu));
+ __raw_writel(STBCR_RESET | STBCR_LTSLP, STBCR_REG(cpu));
}
int plat_smp_processor_id(void)
{
- return ctrl_inl(0xff000048); /* CPIDR */
+ return __raw_readl(0xff000048); /* CPIDR */
}
void plat_send_ipi(unsigned int cpu, unsigned int message)
@@ -100,5 +101,5 @@ void plat_send_ipi(unsigned int cpu, unsigned int message)
BUG_ON(cpu >= 4);
- ctrl_outl(1 << (message << 2), addr); /* C0INTICI..CnINTICI */
+ __raw_writel(1 << (message << 2), addr); /* C0INTICI..CnINTICI */
}
diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S
index b0aacf675258..8f13f73cb2cb 100644
--- a/arch/sh/kernel/cpu/sh5/entry.S
+++ b/arch/sh/kernel/cpu/sh5/entry.S
@@ -933,7 +933,7 @@ ret_with_reschedule:
pta restore_all, tr1
- movi (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r8
+ movi _TIF_SIGPENDING, r8
and r8, r7, r8
pta work_notifysig, tr0
bne r8, ZERO, tr0
diff --git a/arch/sh/kernel/cpu/ubc.S b/arch/sh/kernel/cpu/ubc.S
deleted file mode 100644
index 81923079fa12..000000000000
--- a/arch/sh/kernel/cpu/ubc.S
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * arch/sh/kernel/cpu/ubc.S
- *
- * Set of management routines for the User Break Controller (UBC)
- *
- * Copyright (C) 2002 Paul Mundt
- *
- * This 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/ubc.h>
-
-#define STBCR2 0xffc00010
-
-ENTRY(ubc_sleep)
- mov #0, r0
-
- mov.l 1f, r1 ! Zero out UBC_BBRA ..
- mov.w r0, @r1
-
- mov.l 2f, r1 ! .. same for BBRB ..
- mov.w r0, @r1
-
- mov.l 3f, r1 ! .. and again for BRCR.
- mov.w r0, @r1
-
- mov.w @r1, r0 ! Dummy read BRCR
-
- mov.l 4f, r1 ! Set MSTP5 in STBCR2
- mov.b @r1, r0
- or #0x01, r0
- mov.b r0, @r1
-
- mov.b @r1, r0 ! Two dummy reads ..
- mov.b @r1, r0
-
- rts
- nop
-
-ENTRY(ubc_wakeup)
- mov.l 4f, r1 ! Clear MSTP5
- mov.b @r1, r0
- and #0xfe, r0
- mov.b r0, @r1
-
- mov.b @r1, r0 ! Two more dummy reads ..
- mov.b @r1, r0
-
- rts
- nop
-
-1: .long UBC_BBRA
-2: .long UBC_BBRB
-3: .long UBC_BRCR
-4: .long STBCR2
-
diff --git a/arch/sh/kernel/dma-nommu.c b/arch/sh/kernel/dma-nommu.c
new file mode 100644
index 000000000000..3c55b87f8b63
--- /dev/null
+++ b/arch/sh/kernel/dma-nommu.c
@@ -0,0 +1,82 @@
+/*
+ * DMA mapping support for platforms lacking IOMMUs.
+ *
+ * Copyright (C) 2009 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+
+static dma_addr_t nommu_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ dma_addr_t addr = page_to_phys(page) + offset;
+
+ WARN_ON(size == 0);
+ dma_cache_sync(dev, page_address(page) + offset, size, dir);
+
+ return addr;
+}
+
+static int nommu_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct scatterlist *s;
+ int i;
+
+ WARN_ON(nents == 0 || sg[0].length == 0);
+
+ for_each_sg(sg, s, nents, i) {
+ BUG_ON(!sg_page(s));
+
+ dma_cache_sync(dev, sg_virt(s), s->length, dir);
+
+ s->dma_address = sg_phys(s);
+ s->dma_length = s->length;
+ }
+
+ return nents;
+}
+
+#ifdef CONFIG_DMA_NONCOHERENT
+static void nommu_sync_single(struct device *dev, dma_addr_t addr,
+ size_t size, enum dma_data_direction dir)
+{
+ dma_cache_sync(dev, phys_to_virt(addr), size, dir);
+}
+
+static void nommu_sync_sg(struct device *dev, struct scatterlist *sg,
+ int nelems, enum dma_data_direction dir)
+{
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(sg, s, nelems, i)
+ dma_cache_sync(dev, sg_virt(s), s->length, dir);
+}
+#endif
+
+struct dma_map_ops nommu_dma_ops = {
+ .alloc_coherent = dma_generic_alloc_coherent,
+ .free_coherent = dma_generic_free_coherent,
+ .map_page = nommu_map_page,
+ .map_sg = nommu_map_sg,
+#ifdef CONFIG_DMA_NONCOHERENT
+ .sync_single_for_device = nommu_sync_single,
+ .sync_sg_for_device = nommu_sync_sg,
+#endif
+ .is_phys = 1,
+};
+
+void __init no_iommu_init(void)
+{
+ if (dma_ops)
+ return;
+ dma_ops = &nommu_dma_ops;
+}
diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c
index 03b3616c80a5..6c9d0c10f2be 100644
--- a/arch/sh/kernel/dwarf.c
+++ b/arch/sh/kernel/dwarf.c
@@ -20,6 +20,8 @@
#include <linux/list.h>
#include <linux/mempool.h>
#include <linux/mm.h>
+#include <linux/elf.h>
+#include <linux/ftrace.h>
#include <asm/dwarf.h>
#include <asm/unwinder.h>
#include <asm/sections.h>
@@ -529,7 +531,18 @@ static int dwarf_cfa_execute_insns(unsigned char *insn_start,
}
/**
- * dwarf_unwind_stack - recursively unwind the stack
+ * dwarf_free_frame - free the memory allocated for @frame
+ * @frame: the frame to free
+ */
+void dwarf_free_frame(struct dwarf_frame *frame)
+{
+ dwarf_frame_free_regs(frame);
+ mempool_free(frame, dwarf_frame_pool);
+}
+
+/**
+ * dwarf_unwind_stack - unwind the stack
+ *
* @pc: address of the function to unwind
* @prev: struct dwarf_frame of the previous stackframe on the callstack
*
@@ -547,9 +560,9 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
unsigned long addr;
/*
- * If this is the first invocation of this recursive function we
- * need get the contents of a physical register to get the CFA
- * in order to begin the virtual unwinding of the stack.
+ * If we're starting at the top of the stack we need get the
+ * contents of a physical register to get the CFA in order to
+ * begin the virtual unwinding of the stack.
*
* NOTE: the return address is guaranteed to be setup by the
* time this function makes its first function call.
@@ -557,6 +570,27 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
if (!pc && !prev)
pc = (unsigned long)current_text_addr();
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ /*
+ * If our stack has been patched by the function graph tracer
+ * then we might see the address of return_to_handler() where we
+ * expected to find the real return address.
+ */
+ if (pc == (unsigned long)&return_to_handler) {
+ int index = current->curr_ret_stack;
+
+ /*
+ * We currently have no way of tracking how many
+ * return_to_handler()'s we've seen. If there is more
+ * than one patched return address on our stack,
+ * complain loudly.
+ */
+ WARN_ON(index > 0);
+
+ pc = current->ret_stack[index].ret;
+ }
+#endif
+
frame = mempool_alloc(dwarf_frame_pool, GFP_ATOMIC);
if (!frame) {
printk(KERN_ERR "Unable to allocate a dwarf frame\n");
@@ -571,9 +605,8 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
fde = dwarf_lookup_fde(pc);
if (!fde) {
/*
- * This is our normal exit path - the one that stops the
- * recursion. There's two reasons why we might exit
- * here,
+ * This is our normal exit path. There are two reasons
+ * why we might exit here,
*
* a) pc has no asscociated DWARF frame info and so
* we don't know how to unwind this frame. This is
@@ -615,10 +648,10 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
} else {
/*
- * Again, this is the first invocation of this
- * recurisve function. We need to physically
- * read the contents of a register in order to
- * get the Canonical Frame Address for this
+ * Again, we're starting from the top of the
+ * stack. We need to physically read
+ * the contents of a register in order to get
+ * the Canonical Frame Address for this
* function.
*/
frame->cfa = dwarf_read_arch_reg(frame->cfa_register);
@@ -648,13 +681,12 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
return frame;
bail:
- dwarf_frame_free_regs(frame);
- mempool_free(frame, dwarf_frame_pool);
+ dwarf_free_frame(frame);
return NULL;
}
static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
- unsigned char *end)
+ unsigned char *end, struct module *mod)
{
struct dwarf_cie *cie;
unsigned long flags;
@@ -750,6 +782,8 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
cie->initial_instructions = p;
cie->instructions_end = end;
+ cie->mod = mod;
+
/* Add to list */
spin_lock_irqsave(&dwarf_cie_lock, flags);
list_add_tail(&cie->link, &dwarf_cie_list);
@@ -760,7 +794,7 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
static int dwarf_parse_fde(void *entry, u32 entry_type,
void *start, unsigned long len,
- unsigned char *end)
+ unsigned char *end, struct module *mod)
{
struct dwarf_fde *fde;
struct dwarf_cie *cie;
@@ -809,6 +843,8 @@ static int dwarf_parse_fde(void *entry, u32 entry_type,
fde->instructions = p;
fde->end = end;
+ fde->mod = mod;
+
/* Add to list. */
spin_lock_irqsave(&dwarf_fde_lock, flags);
list_add_tail(&fde->link, &dwarf_fde_list);
@@ -832,10 +868,8 @@ static void dwarf_unwinder_dump(struct task_struct *task,
while (1) {
frame = dwarf_unwind_stack(return_addr, _frame);
- if (_frame) {
- dwarf_frame_free_regs(_frame);
- mempool_free(_frame, dwarf_frame_pool);
- }
+ if (_frame)
+ dwarf_free_frame(_frame);
_frame = frame;
@@ -845,6 +879,9 @@ static void dwarf_unwinder_dump(struct task_struct *task,
return_addr = frame->return_addr;
ops->address(data, return_addr, 1);
}
+
+ if (frame)
+ dwarf_free_frame(frame);
}
static struct unwinder dwarf_unwinder = {
@@ -874,48 +911,28 @@ static void dwarf_unwinder_cleanup(void)
}
/**
- * dwarf_unwinder_init - initialise the dwarf unwinder
+ * dwarf_parse_section - parse DWARF section
+ * @eh_frame_start: start address of the .eh_frame section
+ * @eh_frame_end: end address of the .eh_frame section
+ * @mod: the kernel module containing the .eh_frame section
*
- * Build the data structures describing the .dwarf_frame section to
- * make it easier to lookup CIE and FDE entries. Because the
- * .eh_frame section is packed as tightly as possible it is not
- * easy to lookup the FDE for a given PC, so we build a list of FDE
- * and CIE entries that make it easier.
+ * Parse the information in a .eh_frame section.
*/
-static int __init dwarf_unwinder_init(void)
+static int dwarf_parse_section(char *eh_frame_start, char *eh_frame_end,
+ struct module *mod)
{
u32 entry_type;
void *p, *entry;
int count, err = 0;
- unsigned long len;
+ unsigned long len = 0;
unsigned int c_entries, f_entries;
unsigned char *end;
- INIT_LIST_HEAD(&dwarf_cie_list);
- INIT_LIST_HEAD(&dwarf_fde_list);
c_entries = 0;
f_entries = 0;
- entry = &__start_eh_frame;
-
- dwarf_frame_cachep = kmem_cache_create("dwarf_frames",
- sizeof(struct dwarf_frame), 0,
- SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL);
+ entry = eh_frame_start;
- dwarf_reg_cachep = kmem_cache_create("dwarf_regs",
- sizeof(struct dwarf_reg), 0,
- SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL);
-
- dwarf_frame_pool = mempool_create(DWARF_FRAME_MIN_REQ,
- mempool_alloc_slab,
- mempool_free_slab,
- dwarf_frame_cachep);
-
- dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ,
- mempool_alloc_slab,
- mempool_free_slab,
- dwarf_reg_cachep);
-
- while ((char *)entry < __stop_eh_frame) {
+ while ((char *)entry < eh_frame_end) {
p = entry;
count = dwarf_entry_len(p, &len);
@@ -927,6 +944,7 @@ static int __init dwarf_unwinder_init(void)
* entry and move to the next one because 'len'
* tells us where our next entry is.
*/
+ err = -EINVAL;
goto out;
} else
p += count;
@@ -938,13 +956,14 @@ static int __init dwarf_unwinder_init(void)
p += 4;
if (entry_type == DW_EH_FRAME_CIE) {
- err = dwarf_parse_cie(entry, p, len, end);
+ err = dwarf_parse_cie(entry, p, len, end, mod);
if (err < 0)
goto out;
else
c_entries++;
} else {
- err = dwarf_parse_fde(entry, entry_type, p, len, end);
+ err = dwarf_parse_fde(entry, entry_type, p, len,
+ end, mod);
if (err < 0)
goto out;
else
@@ -957,6 +976,129 @@ static int __init dwarf_unwinder_init(void)
printk(KERN_INFO "DWARF unwinder initialised: read %u CIEs, %u FDEs\n",
c_entries, f_entries);
+ return 0;
+
+out:
+ return err;
+}
+
+#ifdef CONFIG_MODULES
+int module_dwarf_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
+ struct module *me)
+{
+ unsigned int i, err;
+ unsigned long start, end;
+ char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+ start = end = 0;
+
+ for (i = 1; i < hdr->e_shnum; i++) {
+ /* Alloc bit cleared means "ignore it." */
+ if ((sechdrs[i].sh_flags & SHF_ALLOC)
+ && !strcmp(secstrings+sechdrs[i].sh_name, ".eh_frame")) {
+ start = sechdrs[i].sh_addr;
+ end = start + sechdrs[i].sh_size;
+ break;
+ }
+ }
+
+ /* Did we find the .eh_frame section? */
+ if (i != hdr->e_shnum) {
+ err = dwarf_parse_section((char *)start, (char *)end, me);
+ if (err) {
+ printk(KERN_WARNING "%s: failed to parse DWARF info\n",
+ me->name);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * module_dwarf_cleanup - remove FDE/CIEs associated with @mod
+ * @mod: the module that is being unloaded
+ *
+ * Remove any FDEs and CIEs from the global lists that came from
+ * @mod's .eh_frame section because @mod is being unloaded.
+ */
+void module_dwarf_cleanup(struct module *mod)
+{
+ struct dwarf_fde *fde;
+ struct dwarf_cie *cie;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dwarf_cie_lock, flags);
+
+again_cie:
+ list_for_each_entry(cie, &dwarf_cie_list, link) {
+ if (cie->mod == mod)
+ break;
+ }
+
+ if (&cie->link != &dwarf_cie_list) {
+ list_del(&cie->link);
+ kfree(cie);
+ goto again_cie;
+ }
+
+ spin_unlock_irqrestore(&dwarf_cie_lock, flags);
+
+ spin_lock_irqsave(&dwarf_fde_lock, flags);
+
+again_fde:
+ list_for_each_entry(fde, &dwarf_fde_list, link) {
+ if (fde->mod == mod)
+ break;
+ }
+
+ if (&fde->link != &dwarf_fde_list) {
+ list_del(&fde->link);
+ kfree(fde);
+ goto again_fde;
+ }
+
+ spin_unlock_irqrestore(&dwarf_fde_lock, flags);
+}
+#endif /* CONFIG_MODULES */
+
+/**
+ * dwarf_unwinder_init - initialise the dwarf unwinder
+ *
+ * Build the data structures describing the .dwarf_frame section to
+ * make it easier to lookup CIE and FDE entries. Because the
+ * .eh_frame section is packed as tightly as possible it is not
+ * easy to lookup the FDE for a given PC, so we build a list of FDE
+ * and CIE entries that make it easier.
+ */
+static int __init dwarf_unwinder_init(void)
+{
+ int err;
+ INIT_LIST_HEAD(&dwarf_cie_list);
+ INIT_LIST_HEAD(&dwarf_fde_list);
+
+ dwarf_frame_cachep = kmem_cache_create("dwarf_frames",
+ sizeof(struct dwarf_frame), 0,
+ SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL);
+
+ dwarf_reg_cachep = kmem_cache_create("dwarf_regs",
+ sizeof(struct dwarf_reg), 0,
+ SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL);
+
+ dwarf_frame_pool = mempool_create(DWARF_FRAME_MIN_REQ,
+ mempool_alloc_slab,
+ mempool_free_slab,
+ dwarf_frame_cachep);
+
+ dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ,
+ mempool_alloc_slab,
+ mempool_free_slab,
+ dwarf_reg_cachep);
+
+ err = dwarf_parse_section(__start_eh_frame, __stop_eh_frame, NULL);
+ if (err)
+ goto out;
+
err = unwinder_register(&dwarf_unwinder);
if (err)
goto out;
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S
index 3eb84931d2aa..f0abd58c3a69 100644
--- a/arch/sh/kernel/entry-common.S
+++ b/arch/sh/kernel/entry-common.S
@@ -133,7 +133,7 @@ work_pending:
! r8: current_thread_info
! t: result of "tst #_TIF_NEED_RESCHED, r0"
bf/s work_resched
- tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0
+ tst #_TIF_SIGPENDING, r0
work_notifysig:
bt/s __restore_all
mov r15, r4
diff --git a/arch/sh/kernel/ftrace.c b/arch/sh/kernel/ftrace.c
index 2c48e267256e..b6f41c109beb 100644
--- a/arch/sh/kernel/ftrace.c
+++ b/arch/sh/kernel/ftrace.c
@@ -62,6 +62,150 @@ static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
return ftrace_replaced_code;
}
+/*
+ * Modifying code must take extra care. On an SMP machine, if
+ * the code being modified is also being executed on another CPU
+ * that CPU will have undefined results and possibly take a GPF.
+ * We use kstop_machine to stop other CPUS from exectuing code.
+ * But this does not stop NMIs from happening. We still need
+ * to protect against that. We separate out the modification of
+ * the code to take care of this.
+ *
+ * Two buffers are added: An IP buffer and a "code" buffer.
+ *
+ * 1) Put the instruction pointer into the IP buffer
+ * and the new code into the "code" buffer.
+ * 2) Wait for any running NMIs to finish and set a flag that says
+ * we are modifying code, it is done in an atomic operation.
+ * 3) Write the code
+ * 4) clear the flag.
+ * 5) Wait for any running NMIs to finish.
+ *
+ * If an NMI is executed, the first thing it does is to call
+ * "ftrace_nmi_enter". This will check if the flag is set to write
+ * and if it is, it will write what is in the IP and "code" buffers.
+ *
+ * The trick is, it does not matter if everyone is writing the same
+ * content to the code location. Also, if a CPU is executing code
+ * it is OK to write to that code location if the contents being written
+ * are the same as what exists.
+ */
+#define MOD_CODE_WRITE_FLAG (1 << 31) /* set when NMI should do the write */
+static atomic_t nmi_running = ATOMIC_INIT(0);
+static int mod_code_status; /* holds return value of text write */
+static void *mod_code_ip; /* holds the IP to write to */
+static void *mod_code_newcode; /* holds the text to write to the IP */
+
+static unsigned nmi_wait_count;
+static atomic_t nmi_update_count = ATOMIC_INIT(0);
+
+int ftrace_arch_read_dyn_info(char *buf, int size)
+{
+ int r;
+
+ r = snprintf(buf, size, "%u %u",
+ nmi_wait_count,
+ atomic_read(&nmi_update_count));
+ return r;
+}
+
+static void clear_mod_flag(void)
+{
+ int old = atomic_read(&nmi_running);
+
+ for (;;) {
+ int new = old & ~MOD_CODE_WRITE_FLAG;
+
+ if (old == new)
+ break;
+
+ old = atomic_cmpxchg(&nmi_running, old, new);
+ }
+}
+
+static void ftrace_mod_code(void)
+{
+ /*
+ * Yes, more than one CPU process can be writing to mod_code_status.
+ * (and the code itself)
+ * But if one were to fail, then they all should, and if one were
+ * to succeed, then they all should.
+ */
+ mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode,
+ MCOUNT_INSN_SIZE);
+
+ /* if we fail, then kill any new writers */
+ if (mod_code_status)
+ clear_mod_flag();
+}
+
+void ftrace_nmi_enter(void)
+{
+ if (atomic_inc_return(&nmi_running) & MOD_CODE_WRITE_FLAG) {
+ smp_rmb();
+ ftrace_mod_code();
+ atomic_inc(&nmi_update_count);
+ }
+ /* Must have previous changes seen before executions */
+ smp_mb();
+}
+
+void ftrace_nmi_exit(void)
+{
+ /* Finish all executions before clearing nmi_running */
+ smp_mb();
+ atomic_dec(&nmi_running);
+}
+
+static void wait_for_nmi_and_set_mod_flag(void)
+{
+ if (!atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG))
+ return;
+
+ do {
+ cpu_relax();
+ } while (atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG));
+
+ nmi_wait_count++;
+}
+
+static void wait_for_nmi(void)
+{
+ if (!atomic_read(&nmi_running))
+ return;
+
+ do {
+ cpu_relax();
+ } while (atomic_read(&nmi_running));
+
+ nmi_wait_count++;
+}
+
+static int
+do_ftrace_mod_code(unsigned long ip, void *new_code)
+{
+ mod_code_ip = (void *)ip;
+ mod_code_newcode = new_code;
+
+ /* The buffers need to be visible before we let NMIs write them */
+ smp_mb();
+
+ wait_for_nmi_and_set_mod_flag();
+
+ /* Make sure all running NMIs have finished before we write the code */
+ smp_mb();
+
+ ftrace_mod_code();
+
+ /* Make sure the write happens before clearing the bit */
+ smp_mb();
+
+ clear_mod_flag();
+ wait_for_nmi();
+
+ return mod_code_status;
+}
+
static int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
unsigned char *new_code)
{
@@ -86,7 +230,7 @@ static int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
return -EINVAL;
/* replace the text with the new text */
- if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE))
+ if (do_ftrace_mod_code(ip, new_code))
return -EPERM;
flush_icache_range(ip, ip + MCOUNT_INSN_SIZE);
diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S
index a78be74b8d3e..1151ecdffa71 100644
--- a/arch/sh/kernel/head_32.S
+++ b/arch/sh/kernel/head_32.S
@@ -33,7 +33,7 @@ ENTRY(empty_zero_page)
.long 1 /* LOADER_TYPE */
.long 0x00000000 /* INITRD_START */
.long 0x00000000 /* INITRD_SIZE */
-#ifdef CONFIG_32BIT
+#if defined(CONFIG_32BIT) && defined(CONFIG_PMB_FIXED)
.long 0x53453f00 + 32 /* "SE?" = 32 bit */
#else
.long 0x53453f00 + 29 /* "SE?" = 29 bit */
diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c
index 27ff2dc093c7..aaff0037fcd7 100644
--- a/arch/sh/kernel/idle.c
+++ b/arch/sh/kernel/idle.c
@@ -21,7 +21,7 @@
#include <asm/atomic.h>
static int hlt_counter;
-void (*pm_idle)(void);
+void (*pm_idle)(void) = NULL;
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
@@ -39,48 +39,92 @@ static int __init hlt_setup(char *__unused)
}
__setup("hlt", hlt_setup);
+static inline int hlt_works(void)
+{
+ return !hlt_counter;
+}
+
+/*
+ * 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 void poll_idle(void)
+{
+ local_irq_enable();
+ while (!need_resched())
+ cpu_relax();
+}
+
void default_idle(void)
{
- if (!hlt_counter) {
+ if (hlt_works()) {
clear_thread_flag(TIF_POLLING_NRFLAG);
smp_mb__after_clear_bit();
- set_bl_bit();
- stop_critical_timings();
- while (!need_resched())
+ if (!need_resched()) {
+ local_irq_enable();
cpu_sleep();
+ } else
+ local_irq_enable();
- start_critical_timings();
- clear_bl_bit();
set_thread_flag(TIF_POLLING_NRFLAG);
} else
- while (!need_resched())
- cpu_relax();
+ poll_idle();
}
+/*
+ * The idle thread. There's no useful work to be done, so just try to conserve
+ * power and have a low exit latency (ie sit in a loop waiting for somebody to
+ * say that they'd like to reschedule)
+ */
void cpu_idle(void)
{
+ unsigned int cpu = smp_processor_id();
+
set_thread_flag(TIF_POLLING_NRFLAG);
/* endless idle loop with no priority at all */
while (1) {
- void (*idle)(void) = pm_idle;
+ tick_nohz_stop_sched_tick(1);
- if (!idle)
- idle = default_idle;
+ while (!need_resched() && cpu_online(cpu)) {
+ check_pgt_cache();
+ rmb();
- tick_nohz_stop_sched_tick(1);
- while (!need_resched())
- idle();
- tick_nohz_restart_sched_tick();
+ local_irq_disable();
+ /* Don't trace irqs off for idle */
+ stop_critical_timings();
+ pm_idle();
+ /*
+ * Sanity check to ensure that pm_idle() returns
+ * with IRQs enabled
+ */
+ WARN_ON(irqs_disabled());
+ start_critical_timings();
+ }
+ tick_nohz_restart_sched_tick();
preempt_enable_no_resched();
schedule();
preempt_disable();
- check_pgt_cache();
}
}
+void __cpuinit select_idle_routine(void)
+{
+ /*
+ * If a platform has set its own idle routine, leave it alone.
+ */
+ if (pm_idle)
+ return;
+
+ if (hlt_works())
+ pm_idle = default_idle;
+ else
+ pm_idle = poll_idle;
+}
+
static void do_nothing(void *unused)
{
}
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index 7cb933ba4957..7aa89fac1f81 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/kernel_stat.h>
#include <linux/seq_file.h>
+#include <linux/ftrace.h>
#include <asm/processor.h>
#include <asm/machvec.h>
#include <asm/uaccess.h>
@@ -36,7 +37,15 @@ void ack_bad_irq(unsigned int irq)
*/
static int show_other_interrupts(struct seq_file *p, int prec)
{
+ int j;
+
+ seq_printf(p, "%*s: ", prec, "NMI");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", irq_stat[j].__nmi_count);
+ seq_printf(p, " Non-maskable interrupts\n");
+
seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count));
+
return 0;
}
@@ -106,7 +115,7 @@ static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly;
static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly;
#endif
-asmlinkage int do_IRQ(unsigned int irq, struct pt_regs *regs)
+asmlinkage __irq_entry int do_IRQ(unsigned int irq, struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
#ifdef CONFIG_IRQSTACKS
diff --git a/arch/sh/kernel/irq_32.c b/arch/sh/kernel/irq_32.c
new file mode 100644
index 000000000000..e33ab15831f9
--- /dev/null
+++ b/arch/sh/kernel/irq_32.c
@@ -0,0 +1,57 @@
+/*
+ * SHcompact irqflags support
+ *
+ * Copyright (C) 2006 - 2009 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/irqflags.h>
+#include <linux/module.h>
+
+void notrace raw_local_irq_restore(unsigned long flags)
+{
+ unsigned long __dummy0, __dummy1;
+
+ if (flags == RAW_IRQ_DISABLED) {
+ __asm__ __volatile__ (
+ "stc sr, %0\n\t"
+ "or #0xf0, %0\n\t"
+ "ldc %0, sr\n\t"
+ : "=&z" (__dummy0)
+ : /* no inputs */
+ : "memory"
+ );
+ } else {
+ __asm__ __volatile__ (
+ "stc sr, %0\n\t"
+ "and %1, %0\n\t"
+#ifdef CONFIG_CPU_HAS_SR_RB
+ "stc r6_bank, %1\n\t"
+ "or %1, %0\n\t"
+#endif
+ "ldc %0, sr\n\t"
+ : "=&r" (__dummy0), "=r" (__dummy1)
+ : "1" (~RAW_IRQ_DISABLED)
+ : "memory"
+ );
+ }
+}
+EXPORT_SYMBOL(raw_local_irq_restore);
+
+unsigned long notrace __raw_local_save_flags(void)
+{
+ unsigned long flags;
+
+ __asm__ __volatile__ (
+ "stc sr, %0\n\t"
+ "and #0xf0, %0\n\t"
+ : "=&z" (flags)
+ : /* no inputs */
+ : "memory"
+ );
+
+ return flags;
+}
+EXPORT_SYMBOL(__raw_local_save_flags);
diff --git a/arch/sh/kernel/irq_64.c b/arch/sh/kernel/irq_64.c
new file mode 100644
index 000000000000..32365ba0e039
--- /dev/null
+++ b/arch/sh/kernel/irq_64.c
@@ -0,0 +1,51 @@
+/*
+ * SHmedia irqflags support
+ *
+ * Copyright (C) 2006 - 2009 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/irqflags.h>
+#include <linux/module.h>
+#include <cpu/registers.h>
+
+void notrace raw_local_irq_restore(unsigned long flags)
+{
+ unsigned long long __dummy;
+
+ if (flags == RAW_IRQ_DISABLED) {
+ __asm__ __volatile__ (
+ "getcon " __SR ", %0\n\t"
+ "or %0, %1, %0\n\t"
+ "putcon %0, " __SR "\n\t"
+ : "=&r" (__dummy)
+ : "r" (RAW_IRQ_DISABLED)
+ );
+ } else {
+ __asm__ __volatile__ (
+ "getcon " __SR ", %0\n\t"
+ "and %0, %1, %0\n\t"
+ "putcon %0, " __SR "\n\t"
+ : "=&r" (__dummy)
+ : "r" (~RAW_IRQ_DISABLED)
+ );
+ }
+}
+EXPORT_SYMBOL(raw_local_irq_restore);
+
+unsigned long notrace __raw_local_save_flags(void)
+{
+ unsigned long flags;
+
+ __asm__ __volatile__ (
+ "getcon " __SR ", %0\n\t"
+ "and %0, %1, %0"
+ : "=&r" (flags)
+ : "r" (RAW_IRQ_DISABLED)
+ );
+
+ return flags;
+}
+EXPORT_SYMBOL(__raw_local_save_flags);
diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c
index 7ea2704ea033..76f280223ebd 100644
--- a/arch/sh/kernel/machine_kexec.c
+++ b/arch/sh/kernel/machine_kexec.c
@@ -46,12 +46,6 @@ void machine_crash_shutdown(struct pt_regs *regs)
*/
int machine_kexec_prepare(struct kimage *image)
{
- /* older versions of kexec-tools are passing
- * the zImage entry point as a virtual address.
- */
- if (image->start != PHYSADDR(image->start))
- return -EINVAL; /* upgrade your kexec-tools */
-
return 0;
}
diff --git a/arch/sh/kernel/module.c b/arch/sh/kernel/module.c
index c2efdcde266f..43adddfe4c04 100644
--- a/arch/sh/kernel/module.c
+++ b/arch/sh/kernel/module.c
@@ -32,6 +32,7 @@
#include <linux/string.h>
#include <linux/kernel.h>
#include <asm/unaligned.h>
+#include <asm/dwarf.h>
void *module_alloc(unsigned long size)
{
@@ -145,10 +146,16 @@ int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs,
struct module *me)
{
- return module_bug_finalize(hdr, sechdrs, me);
+ int ret = 0;
+
+ ret |= module_dwarf_finalize(hdr, sechdrs, me);
+ ret |= module_bug_finalize(hdr, sechdrs, me);
+
+ return ret;
}
void module_arch_cleanup(struct module *mod)
{
module_bug_cleanup(mod);
+ module_dwarf_cleanup(mod);
}
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c
index 0673c4746be3..a40342be32b2 100644
--- a/arch/sh/kernel/process_32.c
+++ b/arch/sh/kernel/process_32.c
@@ -142,6 +142,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
return pid;
}
+EXPORT_SYMBOL(kernel_thread);
/*
* Free current thread data structures etc..
@@ -186,6 +187,7 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
return fpvalid;
}
+EXPORT_SYMBOL(dump_fpu);
asmlinkage void ret_from_fork(void);
diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c
index 1192398ef582..359b8a2f4d2e 100644
--- a/arch/sh/kernel/process_64.c
+++ b/arch/sh/kernel/process_64.c
@@ -335,6 +335,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
&regs, 0, NULL, NULL);
}
+EXPORT_SYMBOL(kernel_thread);
/*
* Free current thread data structures etc..
@@ -417,6 +418,7 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
return 0; /* Task didn't use the fpu at all. */
#endif
}
+EXPORT_SYMBOL(dump_fpu);
asmlinkage void ret_from_fork(void);
diff --git a/arch/sh/kernel/return_address.c b/arch/sh/kernel/return_address.c
new file mode 100644
index 000000000000..df3ab5811074
--- /dev/null
+++ b/arch/sh/kernel/return_address.c
@@ -0,0 +1,54 @@
+/*
+ * arch/sh/kernel/return_address.c
+ *
+ * Copyright (C) 2009 Matt Fleming
+ * Copyright (C) 2009 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <asm/dwarf.h>
+
+#ifdef CONFIG_DWARF_UNWINDER
+
+void *return_address(unsigned int depth)
+{
+ struct dwarf_frame *frame;
+ unsigned long ra;
+ int i;
+
+ for (i = 0, frame = NULL, ra = 0; i <= depth; i++) {
+ struct dwarf_frame *tmp;
+
+ tmp = dwarf_unwind_stack(ra, frame);
+
+ if (frame)
+ dwarf_free_frame(frame);
+
+ frame = tmp;
+
+ if (!frame || !frame->return_addr)
+ break;
+
+ ra = frame->return_addr;
+ }
+
+ /* Failed to unwind the stack to the specified depth. */
+ WARN_ON(i != depth + 1);
+
+ if (frame)
+ dwarf_free_frame(frame);
+
+ return (void *)ra;
+}
+
+#else
+
+void *return_address(unsigned int depth)
+{
+ return NULL;
+}
+
+#endif
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index 99b4fb553bf1..5a947a2567e4 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -453,6 +453,10 @@ void __init setup_arch(char **cmdline_p)
paging_init();
+#ifdef CONFIG_PMB_ENABLE
+ pmb_init();
+#endif
+
#ifdef CONFIG_SMP
plat_smp_setup();
#endif
diff --git a/arch/sh/kernel/sh_ksyms_32.c b/arch/sh/kernel/sh_ksyms_32.c
index 86c270428357..3896f26efa4a 100644
--- a/arch/sh/kernel/sh_ksyms_32.c
+++ b/arch/sh/kernel/sh_ksyms_32.c
@@ -1,37 +1,11 @@
#include <linux/module.h>
-#include <linux/smp.h>
-#include <linux/user.h>
-#include <linux/elfcore.h>
-#include <linux/sched.h>
-#include <linux/in6.h>
-#include <linux/interrupt.h>
-#include <linux/vmalloc.h>
-#include <linux/pci.h>
-#include <linux/irq.h>
-#include <asm/sections.h>
-#include <asm/processor.h>
-#include <asm/uaccess.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
#include <asm/checksum.h>
-#include <asm/io.h>
-#include <asm/delay.h>
-#include <asm/tlbflush.h>
-#include <asm/cacheflush.h>
-#include <asm/ftrace.h>
-
-extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
-
-/* platform dependent support */
-EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(strlen);
-
-/* PCI exports */
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL(pci_alloc_consistent);
-EXPORT_SYMBOL(pci_free_consistent);
-#endif
+#include <asm/sections.h>
-/* mem exports */
EXPORT_SYMBOL(memchr);
EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(memset);
@@ -40,6 +14,13 @@ EXPORT_SYMBOL(__copy_user);
EXPORT_SYMBOL(__udelay);
EXPORT_SYMBOL(__ndelay);
EXPORT_SYMBOL(__const_udelay);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(csum_partial);
+EXPORT_SYMBOL(csum_partial_copy_generic);
+EXPORT_SYMBOL(copy_page);
+EXPORT_SYMBOL(__clear_user);
+EXPORT_SYMBOL(_ebss);
+EXPORT_SYMBOL(empty_zero_page);
#define DECLARE_EXPORT(name) \
extern void name(void);EXPORT_SYMBOL(name)
@@ -85,6 +66,20 @@ DECLARE_EXPORT(__movstr_i4_even);
DECLARE_EXPORT(__movstr_i4_odd);
DECLARE_EXPORT(__movstrSI12_i4);
DECLARE_EXPORT(__movmem);
+DECLARE_EXPORT(__movmemSI8);
+DECLARE_EXPORT(__movmemSI12);
+DECLARE_EXPORT(__movmemSI16);
+DECLARE_EXPORT(__movmemSI20);
+DECLARE_EXPORT(__movmemSI24);
+DECLARE_EXPORT(__movmemSI28);
+DECLARE_EXPORT(__movmemSI32);
+DECLARE_EXPORT(__movmemSI36);
+DECLARE_EXPORT(__movmemSI40);
+DECLARE_EXPORT(__movmemSI44);
+DECLARE_EXPORT(__movmemSI48);
+DECLARE_EXPORT(__movmemSI52);
+DECLARE_EXPORT(__movmemSI56);
+DECLARE_EXPORT(__movmemSI60);
DECLARE_EXPORT(__movmem_i4_even);
DECLARE_EXPORT(__movmem_i4_odd);
DECLARE_EXPORT(__movmemSI12_i4);
@@ -93,30 +88,6 @@ DECLARE_EXPORT(__sdivsi3_i4);
DECLARE_EXPORT(__udivsi3_i4);
DECLARE_EXPORT(__sdivsi3_i4i);
DECLARE_EXPORT(__udivsi3_i4i);
-
-#if !defined(CONFIG_CACHE_OFF) && (defined(CONFIG_CPU_SH4) || \
- defined(CONFIG_SH7705_CACHE_32KB))
-/* needed by some modules */
-EXPORT_SYMBOL(flush_cache_all);
-EXPORT_SYMBOL(flush_cache_range);
-EXPORT_SYMBOL(flush_dcache_page);
-#endif
-
#ifdef CONFIG_MCOUNT
DECLARE_EXPORT(mcount);
#endif
-EXPORT_SYMBOL(csum_partial);
-EXPORT_SYMBOL(csum_partial_copy_generic);
-#ifdef CONFIG_IPV6
-EXPORT_SYMBOL(csum_ipv6_magic);
-#endif
-EXPORT_SYMBOL(copy_page);
-EXPORT_SYMBOL(__clear_user);
-EXPORT_SYMBOL(_ebss);
-EXPORT_SYMBOL(empty_zero_page);
-
-#ifndef CONFIG_CACHE_OFF
-EXPORT_SYMBOL(__flush_purge_region);
-EXPORT_SYMBOL(__flush_wback_region);
-EXPORT_SYMBOL(__flush_invalidate_region);
-#endif
diff --git a/arch/sh/kernel/sh_ksyms_64.c b/arch/sh/kernel/sh_ksyms_64.c
index d008e17eb257..45afa5c51f67 100644
--- a/arch/sh/kernel/sh_ksyms_64.c
+++ b/arch/sh/kernel/sh_ksyms_64.c
@@ -24,16 +24,6 @@
#include <asm/delay.h>
#include <asm/irq.h>
-extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
-
-/* platform dependent support */
-EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(kernel_thread);
-
-#ifdef CONFIG_VT
-EXPORT_SYMBOL(screen_info);
-#endif
-
EXPORT_SYMBOL(__put_user_asm_b);
EXPORT_SYMBOL(__put_user_asm_w);
EXPORT_SYMBOL(__put_user_asm_l);
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c
index 3db37425210d..12815ce01ecd 100644
--- a/arch/sh/kernel/signal_32.c
+++ b/arch/sh/kernel/signal_32.c
@@ -67,7 +67,8 @@ sys_sigsuspend(old_sigset_t mask,
current->state = TASK_INTERRUPTIBLE;
schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
+ set_restore_sigmask();
+
return -ERESTARTNOHAND;
}
@@ -590,7 +591,7 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)
if (try_to_freeze())
goto no_signal;
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK)
oldset = &current->saved_sigmask;
else
oldset = &current->blocked;
@@ -602,12 +603,13 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)
/* Whee! Actually deliver the signal. */
if (handle_signal(signr, &ka, &info, oldset,
regs, save_r0) == 0) {
- /* a signal was successfully delivered; the saved
+ /*
+ * A signal was successfully delivered; the saved
* sigmask will have been stored in the signal frame,
* and will be restored by sigreturn, so we can simply
- * clear the TIF_RESTORE_SIGMASK flag */
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- clear_thread_flag(TIF_RESTORE_SIGMASK);
+ * clear the TS_RESTORE_SIGMASK flag
+ */
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
tracehook_signal_handler(signr, &info, &ka, regs,
test_thread_flag(TIF_SINGLESTEP));
@@ -631,10 +633,12 @@ no_signal:
}
}
- /* if there's no signal to deliver, we just put the saved sigmask
- * back */
- if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
- clear_thread_flag(TIF_RESTORE_SIGMASK);
+ /*
+ * If there's no signal to deliver, we just put the saved sigmask
+ * back.
+ */
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
}
}
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c
index 74793c80a57a..feb3dddd3192 100644
--- a/arch/sh/kernel/signal_64.c
+++ b/arch/sh/kernel/signal_64.c
@@ -101,7 +101,7 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset)
if (try_to_freeze())
goto no_signal;
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK)
oldset = &current->saved_sigmask;
else if (!oldset)
oldset = &current->blocked;
@@ -115,11 +115,9 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset)
/*
* If a signal was successfully delivered, the
* saved sigmask is in its frame, and we can
- * clear the TIF_RESTORE_SIGMASK flag.
+ * clear the TS_RESTORE_SIGMASK flag.
*/
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- clear_thread_flag(TIF_RESTORE_SIGMASK);
-
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
tracehook_signal_handler(signr, &info, &ka, regs, 0);
return 1;
}
@@ -146,8 +144,8 @@ no_signal:
}
/* No signal to deliver -- put the saved sigmask back */
- if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
- clear_thread_flag(TIF_RESTORE_SIGMASK);
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
}
@@ -176,6 +174,7 @@ sys_sigsuspend(old_sigset_t mask,
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
+ set_restore_sigmask();
regs->pc += 4; /* because sys_sigreturn decrements the pc */
if (do_signal(regs, &saveset)) {
/* pc now points at signal handler. Need to decrement
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c
index 160db1003cfb..983e0792d5f3 100644
--- a/arch/sh/kernel/smp.c
+++ b/arch/sh/kernel/smp.c
@@ -122,7 +122,9 @@ int __cpuinit __cpu_up(unsigned int cpu)
stack_start.bss_start = 0; /* don't clear bss for secondary cpus */
stack_start.start_kernel_fn = start_secondary;
- flush_cache_all();
+ flush_icache_range((unsigned long)&stack_start,
+ (unsigned long)&stack_start + sizeof(stack_start));
+ wmb();
plat_start_cpu(cpu, (unsigned long)_stext);
diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S
index 5bfde6c77498..07d2aaea9ae8 100644
--- a/arch/sh/kernel/syscalls_64.S
+++ b/arch/sh/kernel/syscalls_64.S
@@ -391,3 +391,4 @@ sys_call_table:
.long sys_pwritev
.long sys_rt_tgsigqueueinfo
.long sys_perf_event_open
+ .long sys_recvmmsg /* 365 */
diff --git a/arch/sh/kernel/topology.c b/arch/sh/kernel/topology.c
index 0838942b7083..9b0b633b6c92 100644
--- a/arch/sh/kernel/topology.c
+++ b/arch/sh/kernel/topology.c
@@ -16,6 +16,32 @@
static DEFINE_PER_CPU(struct cpu, cpu_devices);
+cpumask_t cpu_core_map[NR_CPUS];
+
+static cpumask_t cpu_coregroup_map(unsigned int cpu)
+{
+ /*
+ * Presently all SH-X3 SMP cores are multi-cores, so just keep it
+ * simple until we have a method for determining topology..
+ */
+ return cpu_possible_map;
+}
+
+const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
+{
+ return &cpu_core_map[cpu];
+}
+
+int arch_update_cpu_topology(void)
+{
+ unsigned int cpu;
+
+ for_each_possible_cpu(cpu)
+ cpu_core_map[cpu] = cpu_coregroup_map(cpu);
+
+ return 0;
+}
+
static int __init topology_init(void)
{
int i, ret;
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index a8396f36bd14..d52695df2702 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -95,9 +95,11 @@ BUILD_TRAP_HANDLER(bug)
BUILD_TRAP_HANDLER(nmi)
{
+ unsigned int cpu = smp_processor_id();
TRAP_HANDLER_DECL;
nmi_enter();
+ nmi_count(cpu)++;
switch (notify_die(DIE_NMI, "NMI", regs, 0, vec & 0xff, SIGINT)) {
case NOTIFY_OK:
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index 7a2ee3a6b8e7..114d21761823 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -945,14 +945,9 @@ void __init trap_init(void)
set_exception_table_evt(0x800, do_reserved_inst);
set_exception_table_evt(0x820, do_illegal_slot_inst);
#elif defined(CONFIG_SH_FPU)
-#ifdef CONFIG_CPU_SUBTYPE_SHX3
- set_exception_table_evt(0xd80, fpu_state_restore_trap_handler);
- set_exception_table_evt(0xda0, fpu_state_restore_trap_handler);
-#else
set_exception_table_evt(0x800, fpu_state_restore_trap_handler);
set_exception_table_evt(0x820, fpu_state_restore_trap_handler);
#endif
-#endif
#ifdef CONFIG_CPU_SH2
set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_trap_handler);
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 64dc1ad59801..a5e0867d8ae9 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -83,7 +83,6 @@ config 32BIT
config PMB_ENABLE
bool "Support 32-bit physical addressing through PMB"
depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7757 || CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785)
- select 32BIT
default y
help
If you say Y here, physical addressing will be extended to
@@ -98,7 +97,6 @@ choice
config PMB
bool "PMB"
depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7757 || CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785)
- select 32BIT
help
If you say Y here, physical addressing will be extended to
32-bits through the SH-4A PMB. If this is not set, legacy
@@ -227,7 +225,7 @@ endchoice
choice
prompt "HugeTLB page size"
- depends on HUGETLB_PAGE && (CPU_SH4 || CPU_SH5) && MMU
+ depends on HUGETLB_PAGE
default HUGETLB_PAGE_SIZE_1MB if PAGE_SIZE_64KB
default HUGETLB_PAGE_SIZE_64K
@@ -258,6 +256,15 @@ endchoice
source "mm/Kconfig"
+config SCHED_MC
+ bool "Multi-core scheduler support"
+ depends on SMP
+ default y
+ help
+ Multi-core scheduler support improves the CPU scheduler's decision
+ making when dealing with multi-core CPU chips at a cost of slightly
+ increased overhead in some places. If unsure say N here.
+
endmenu
menu "Cache configuration"
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
index 3759bf853293..8a70535fa7ce 100644
--- a/arch/sh/mm/Makefile
+++ b/arch/sh/mm/Makefile
@@ -33,8 +33,7 @@ obj-y += $(tlb-y)
endif
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
-obj-$(CONFIG_PMB) += pmb.o
-obj-$(CONFIG_PMB_FIXED) += pmb-fixed.o
+obj-$(CONFIG_PMB_ENABLE) += pmb.o
obj-$(CONFIG_NUMA) += numa.o
# Special flags for fault_64.o. This puts restrictions on the number of
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c
index a98c7d8984fa..4a2fbf2864de 100644
--- a/arch/sh/mm/cache-sh4.c
+++ b/arch/sh/mm/cache-sh4.c
@@ -2,7 +2,7 @@
* arch/sh/mm/cache-sh4.c
*
* Copyright (C) 1999, 2000, 2002 Niibe Yutaka
- * Copyright (C) 2001 - 2007 Paul Mundt
+ * Copyright (C) 2001 - 2009 Paul Mundt
* Copyright (C) 2003 Richard Curnow
* Copyright (c) 2007 STMicroelectronics (R&D) Ltd.
*
@@ -15,6 +15,8 @@
#include <linux/io.h>
#include <linux/mutex.h>
#include <linux/fs.h>
+#include <linux/highmem.h>
+#include <asm/pgtable.h>
#include <asm/mmu_context.h>
#include <asm/cacheflush.h>
@@ -23,21 +25,12 @@
* flushing. Anything exceeding this will simply flush the dcache in its
* entirety.
*/
-#define MAX_DCACHE_PAGES 64 /* XXX: Tune for ways */
#define MAX_ICACHE_PAGES 32
-static void __flush_cache_4096(unsigned long addr, unsigned long phys,
+static void __flush_cache_one(unsigned long addr, unsigned long phys,
unsigned long exec_offset);
/*
- * This is initialised here to ensure that it is not placed in the BSS. If
- * that were to happen, note that cache_init gets called before the BSS is
- * cleared, so this would get nulled out which would be hopeless.
- */
-static void (*__flush_dcache_segment_fn)(unsigned long, unsigned long) =
- (void (*)(unsigned long, unsigned long))0xdeadbeef;
-
-/*
* Write back the range of D-cache, and purge the I-cache.
*
* Called from kernel/module.c:sys_init_module and routine for a.out format,
@@ -89,22 +82,21 @@ static void __uses_jump_to_uncached sh4_flush_icache_range(void *args)
local_irq_restore(flags);
}
-static inline void flush_cache_4096(unsigned long start,
- unsigned long phys)
+static inline void flush_cache_one(unsigned long start, unsigned long phys)
{
unsigned long flags, exec_offset = 0;
/*
- * All types of SH-4 require PC to be in P2 to operate on the I-cache.
- * Some types of SH-4 require PC to be in P2 to operate on the D-cache.
+ * All types of SH-4 require PC to be uncached to operate on the I-cache.
+ * Some types of SH-4 require PC to be uncached to operate on the D-cache.
*/
if ((boot_cpu_data.flags & CPU_HAS_P2_FLUSH_BUG) ||
(start < CACHE_OC_ADDRESS_ARRAY))
- exec_offset = 0x20000000;
+ exec_offset = cached_to_uncached;
local_irq_save(flags);
- __flush_cache_4096(start | SH_CACHE_ASSOC,
- P1SEGADDR(phys), exec_offset);
+ __flush_cache_one(start | SH_CACHE_ASSOC,
+ virt_to_phys(phys), exec_offset);
local_irq_restore(flags);
}
@@ -123,14 +115,14 @@ static void sh4_flush_dcache_page(void *arg)
else
#endif
{
- unsigned long phys = PHYSADDR(page_address(page));
+ unsigned long phys = page_to_phys(page);
unsigned long addr = CACHE_OC_ADDRESS_ARRAY;
int i, n;
/* Loop all the D-cache */
n = boot_cpu_data.dcache.n_aliases;
- for (i = 0; i < n; i++, addr += 4096)
- flush_cache_4096(addr, phys);
+ for (i = 0; i <= n; i++, addr += PAGE_SIZE)
+ flush_cache_one(addr, phys);
}
wmb();
@@ -158,10 +150,27 @@ static void __uses_jump_to_uncached flush_icache_all(void)
local_irq_restore(flags);
}
-static inline void flush_dcache_all(void)
+static void flush_dcache_all(void)
{
- (*__flush_dcache_segment_fn)(0UL, boot_cpu_data.dcache.way_size);
- wmb();
+ unsigned long addr, end_addr, entry_offset;
+
+ end_addr = CACHE_OC_ADDRESS_ARRAY +
+ (current_cpu_data.dcache.sets <<
+ current_cpu_data.dcache.entry_shift) *
+ current_cpu_data.dcache.ways;
+
+ entry_offset = 1 << current_cpu_data.dcache.entry_shift;
+
+ for (addr = CACHE_OC_ADDRESS_ARRAY; addr < end_addr; ) {
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ __raw_writel(0, addr); addr += entry_offset;
+ }
}
static void sh4_flush_cache_all(void *unused)
@@ -170,89 +179,13 @@ static void sh4_flush_cache_all(void *unused)
flush_icache_all();
}
-static void __flush_cache_mm(struct mm_struct *mm, unsigned long start,
- unsigned long end)
-{
- unsigned long d = 0, p = start & PAGE_MASK;
- unsigned long alias_mask = boot_cpu_data.dcache.alias_mask;
- unsigned long n_aliases = boot_cpu_data.dcache.n_aliases;
- unsigned long select_bit;
- unsigned long all_aliases_mask;
- unsigned long addr_offset;
- pgd_t *dir;
- pmd_t *pmd;
- pud_t *pud;
- pte_t *pte;
- int i;
-
- dir = pgd_offset(mm, p);
- pud = pud_offset(dir, p);
- pmd = pmd_offset(pud, p);
- end = PAGE_ALIGN(end);
-
- all_aliases_mask = (1 << n_aliases) - 1;
-
- do {
- if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) {
- p &= PMD_MASK;
- p += PMD_SIZE;
- pmd++;
-
- continue;
- }
-
- pte = pte_offset_kernel(pmd, p);
-
- do {
- unsigned long phys;
- pte_t entry = *pte;
-
- if (!(pte_val(entry) & _PAGE_PRESENT)) {
- pte++;
- p += PAGE_SIZE;
- continue;
- }
-
- phys = pte_val(entry) & PTE_PHYS_MASK;
-
- if ((p ^ phys) & alias_mask) {
- d |= 1 << ((p & alias_mask) >> PAGE_SHIFT);
- d |= 1 << ((phys & alias_mask) >> PAGE_SHIFT);
-
- if (d == all_aliases_mask)
- goto loop_exit;
- }
-
- pte++;
- p += PAGE_SIZE;
- } while (p < end && ((unsigned long)pte & ~PAGE_MASK));
- pmd++;
- } while (p < end);
-
-loop_exit:
- addr_offset = 0;
- select_bit = 1;
-
- for (i = 0; i < n_aliases; i++) {
- if (d & select_bit) {
- (*__flush_dcache_segment_fn)(addr_offset, PAGE_SIZE);
- wmb();
- }
-
- select_bit <<= 1;
- addr_offset += PAGE_SIZE;
- }
-}
-
/*
* Note : (RPC) since the caches are physically tagged, the only point
* of flush_cache_mm for SH-4 is to get rid of aliases from the
* D-cache. The assumption elsewhere, e.g. flush_cache_range, is that
* lines can stay resident so long as the virtual address they were
* accessed with (hence cache set) is in accord with the physical
- * address (i.e. tag). It's no different here. So I reckon we don't
- * need to flush the I-cache, since aliases don't matter for that. We
- * should try that.
+ * address (i.e. tag). It's no different here.
*
* Caller takes mm->mmap_sem.
*/
@@ -263,33 +196,7 @@ static void sh4_flush_cache_mm(void *arg)
if (cpu_context(smp_processor_id(), mm) == NO_CONTEXT)
return;
- /*
- * If cache is only 4k-per-way, there are never any 'aliases'. Since
- * the cache is physically tagged, the data can just be left in there.
- */
- if (boot_cpu_data.dcache.n_aliases == 0)
- return;
-
- /*
- * Don't bother groveling around the dcache for the VMA ranges
- * if there are too many PTEs to make it worthwhile.
- */
- if (mm->nr_ptes >= MAX_DCACHE_PAGES)
- flush_dcache_all();
- else {
- struct vm_area_struct *vma;
-
- /*
- * In this case there are reasonably sized ranges to flush,
- * iterate through the VMA list and take care of any aliases.
- */
- for (vma = mm->mmap; vma; vma = vma->vm_next)
- __flush_cache_mm(mm, vma->vm_start, vma->vm_end);
- }
-
- /* Only touch the icache if one of the VMAs has VM_EXEC set. */
- if (mm->exec_vm)
- flush_icache_all();
+ flush_dcache_all();
}
/*
@@ -302,44 +209,63 @@ static void sh4_flush_cache_page(void *args)
{
struct flusher_data *data = args;
struct vm_area_struct *vma;
+ struct page *page;
unsigned long address, pfn, phys;
- unsigned int alias_mask;
+ int map_coherent = 0;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ void *vaddr;
vma = data->vma;
- address = data->addr1;
+ address = data->addr1 & PAGE_MASK;
pfn = data->addr2;
phys = pfn << PAGE_SHIFT;
+ page = pfn_to_page(pfn);
if (cpu_context(smp_processor_id(), vma->vm_mm) == NO_CONTEXT)
return;
- alias_mask = boot_cpu_data.dcache.alias_mask;
-
- /* We only need to flush D-cache when we have alias */
- if ((address^phys) & alias_mask) {
- /* Loop 4K of the D-cache */
- flush_cache_4096(
- CACHE_OC_ADDRESS_ARRAY | (address & alias_mask),
- phys);
- /* Loop another 4K of the D-cache */
- flush_cache_4096(
- CACHE_OC_ADDRESS_ARRAY | (phys & alias_mask),
- phys);
- }
+ pgd = pgd_offset(vma->vm_mm, address);
+ pud = pud_offset(pgd, address);
+ pmd = pmd_offset(pud, address);
+ pte = pte_offset_kernel(pmd, address);
+
+ /* If the page isn't present, there is nothing to do here. */
+ if (!(pte_val(*pte) & _PAGE_PRESENT))
+ return;
- alias_mask = boot_cpu_data.icache.alias_mask;
- if (vma->vm_flags & VM_EXEC) {
+ if ((vma->vm_mm == current->active_mm))
+ vaddr = NULL;
+ else {
/*
- * Evict entries from the portion of the cache from which code
- * may have been executed at this address (virtual). There's
- * no need to evict from the portion corresponding to the
- * physical address as for the D-cache, because we know the
- * kernel has never executed the code through its identity
- * translation.
+ * Use kmap_coherent or kmap_atomic to do flushes for
+ * another ASID than the current one.
*/
- flush_cache_4096(
- CACHE_IC_ADDRESS_ARRAY | (address & alias_mask),
- phys);
+ map_coherent = (current_cpu_data.dcache.n_aliases &&
+ !test_bit(PG_dcache_dirty, &page->flags) &&
+ page_mapped(page));
+ if (map_coherent)
+ vaddr = kmap_coherent(page, address);
+ else
+ vaddr = kmap_atomic(page, KM_USER0);
+
+ address = (unsigned long)vaddr;
+ }
+
+ if (pages_do_alias(address, phys))
+ flush_cache_one(CACHE_OC_ADDRESS_ARRAY |
+ (address & shm_align_mask), phys);
+
+ if (vma->vm_flags & VM_EXEC)
+ flush_icache_all();
+
+ if (vaddr) {
+ if (map_coherent)
+ kunmap_coherent(vaddr);
+ else
+ kunmap_atomic(vaddr, KM_USER0);
}
}
@@ -372,28 +298,14 @@ static void sh4_flush_cache_range(void *args)
if (boot_cpu_data.dcache.n_aliases == 0)
return;
- /*
- * Don't bother with the lookup and alias check if we have a
- * wide range to cover, just blow away the dcache in its
- * entirety instead. -- PFM.
- */
- if (((end - start) >> PAGE_SHIFT) >= MAX_DCACHE_PAGES)
- flush_dcache_all();
- else
- __flush_cache_mm(vma->vm_mm, start, end);
+ flush_dcache_all();
- if (vma->vm_flags & VM_EXEC) {
- /*
- * TODO: Is this required??? Need to look at how I-cache
- * coherency is assured when new programs are loaded to see if
- * this matters.
- */
+ if (vma->vm_flags & VM_EXEC)
flush_icache_all();
- }
}
/**
- * __flush_cache_4096
+ * __flush_cache_one
*
* @addr: address in memory mapped cache array
* @phys: P1 address to flush (has to match tags if addr has 'A' bit
@@ -406,7 +318,7 @@ static void sh4_flush_cache_range(void *args)
* operation (purge/write-back) is selected by the lower 2 bits of
* 'phys'.
*/
-static void __flush_cache_4096(unsigned long addr, unsigned long phys,
+static void __flush_cache_one(unsigned long addr, unsigned long phys,
unsigned long exec_offset)
{
int way_count;
@@ -463,245 +375,6 @@ static void __flush_cache_4096(unsigned long addr, unsigned long phys,
} while (--way_count != 0);
}
-/*
- * Break the 1, 2 and 4 way variants of this out into separate functions to
- * avoid nearly all the overhead of having the conditional stuff in the function
- * bodies (+ the 1 and 2 way cases avoid saving any registers too).
- *
- * We want to eliminate unnecessary bus transactions, so this code uses
- * a non-obvious technique.
- *
- * Loop over a cache way sized block of, one cache line at a time. For each
- * line, use movca.a to cause the current cache line contents to be written
- * back, but without reading anything from main memory. However this has the
- * side effect that the cache is now caching that memory location. So follow
- * this with a cache invalidate to mark the cache line invalid. And do all
- * this with interrupts disabled, to avoid the cache line being accidently
- * evicted while it is holding garbage.
- *
- * This also breaks in a number of circumstances:
- * - if there are modifications to the region of memory just above
- * empty_zero_page (for example because a breakpoint has been placed
- * there), then these can be lost.
- *
- * This is because the the memory address which the cache temporarily
- * caches in the above description is empty_zero_page. So the
- * movca.l hits the cache (it is assumed that it misses, or at least
- * isn't dirty), modifies the line and then invalidates it, losing the
- * required change.
- *
- * - If caches are disabled or configured in write-through mode, then
- * the movca.l writes garbage directly into memory.
- */
-static void __flush_dcache_segment_writethrough(unsigned long start,
- unsigned long extent_per_way)
-{
- unsigned long addr;
- int i;
-
- addr = CACHE_OC_ADDRESS_ARRAY | (start & cpu_data->dcache.entry_mask);
-
- while (extent_per_way) {
- for (i = 0; i < cpu_data->dcache.ways; i++)
- __raw_writel(0, addr + cpu_data->dcache.way_incr * i);
-
- addr += cpu_data->dcache.linesz;
- extent_per_way -= cpu_data->dcache.linesz;
- }
-}
-
-static void __flush_dcache_segment_1way(unsigned long start,
- unsigned long extent_per_way)
-{
- unsigned long orig_sr, sr_with_bl;
- unsigned long base_addr;
- unsigned long way_incr, linesz, way_size;
- struct cache_info *dcache;
- register unsigned long a0, a0e;
-
- asm volatile("stc sr, %0" : "=r" (orig_sr));
- sr_with_bl = orig_sr | (1<<28);
- base_addr = ((unsigned long)&empty_zero_page[0]);
-
- /*
- * The previous code aligned base_addr to 16k, i.e. the way_size of all
- * existing SH-4 D-caches. Whilst I don't see a need to have this
- * aligned to any better than the cache line size (which it will be
- * anyway by construction), let's align it to at least the way_size of
- * any existing or conceivable SH-4 D-cache. -- RPC
- */
- base_addr = ((base_addr >> 16) << 16);
- base_addr |= start;
-
- dcache = &boot_cpu_data.dcache;
- linesz = dcache->linesz;
- way_incr = dcache->way_incr;
- way_size = dcache->way_size;
-
- a0 = base_addr;
- a0e = base_addr + extent_per_way;
- do {
- asm volatile("ldc %0, sr" : : "r" (sr_with_bl));
- asm volatile("movca.l r0, @%0\n\t"
- "ocbi @%0" : : "r" (a0));
- a0 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "ocbi @%0" : : "r" (a0));
- a0 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "ocbi @%0" : : "r" (a0));
- a0 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "ocbi @%0" : : "r" (a0));
- asm volatile("ldc %0, sr" : : "r" (orig_sr));
- a0 += linesz;
- } while (a0 < a0e);
-}
-
-static void __flush_dcache_segment_2way(unsigned long start,
- unsigned long extent_per_way)
-{
- unsigned long orig_sr, sr_with_bl;
- unsigned long base_addr;
- unsigned long way_incr, linesz, way_size;
- struct cache_info *dcache;
- register unsigned long a0, a1, a0e;
-
- asm volatile("stc sr, %0" : "=r" (orig_sr));
- sr_with_bl = orig_sr | (1<<28);
- base_addr = ((unsigned long)&empty_zero_page[0]);
-
- /* See comment under 1-way above */
- base_addr = ((base_addr >> 16) << 16);
- base_addr |= start;
-
- dcache = &boot_cpu_data.dcache;
- linesz = dcache->linesz;
- way_incr = dcache->way_incr;
- way_size = dcache->way_size;
-
- a0 = base_addr;
- a1 = a0 + way_incr;
- a0e = base_addr + extent_per_way;
- do {
- asm volatile("ldc %0, sr" : : "r" (sr_with_bl));
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1" : :
- "r" (a0), "r" (a1));
- a0 += linesz;
- a1 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1" : :
- "r" (a0), "r" (a1));
- a0 += linesz;
- a1 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1" : :
- "r" (a0), "r" (a1));
- a0 += linesz;
- a1 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1" : :
- "r" (a0), "r" (a1));
- asm volatile("ldc %0, sr" : : "r" (orig_sr));
- a0 += linesz;
- a1 += linesz;
- } while (a0 < a0e);
-}
-
-static void __flush_dcache_segment_4way(unsigned long start,
- unsigned long extent_per_way)
-{
- unsigned long orig_sr, sr_with_bl;
- unsigned long base_addr;
- unsigned long way_incr, linesz, way_size;
- struct cache_info *dcache;
- register unsigned long a0, a1, a2, a3, a0e;
-
- asm volatile("stc sr, %0" : "=r" (orig_sr));
- sr_with_bl = orig_sr | (1<<28);
- base_addr = ((unsigned long)&empty_zero_page[0]);
-
- /* See comment under 1-way above */
- base_addr = ((base_addr >> 16) << 16);
- base_addr |= start;
-
- dcache = &boot_cpu_data.dcache;
- linesz = dcache->linesz;
- way_incr = dcache->way_incr;
- way_size = dcache->way_size;
-
- a0 = base_addr;
- a1 = a0 + way_incr;
- a2 = a1 + way_incr;
- a3 = a2 + way_incr;
- a0e = base_addr + extent_per_way;
- do {
- asm volatile("ldc %0, sr" : : "r" (sr_with_bl));
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "movca.l r0, @%2\n\t"
- "movca.l r0, @%3\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1\n\t"
- "ocbi @%2\n\t"
- "ocbi @%3\n\t" : :
- "r" (a0), "r" (a1), "r" (a2), "r" (a3));
- a0 += linesz;
- a1 += linesz;
- a2 += linesz;
- a3 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "movca.l r0, @%2\n\t"
- "movca.l r0, @%3\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1\n\t"
- "ocbi @%2\n\t"
- "ocbi @%3\n\t" : :
- "r" (a0), "r" (a1), "r" (a2), "r" (a3));
- a0 += linesz;
- a1 += linesz;
- a2 += linesz;
- a3 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "movca.l r0, @%2\n\t"
- "movca.l r0, @%3\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1\n\t"
- "ocbi @%2\n\t"
- "ocbi @%3\n\t" : :
- "r" (a0), "r" (a1), "r" (a2), "r" (a3));
- a0 += linesz;
- a1 += linesz;
- a2 += linesz;
- a3 += linesz;
- asm volatile("movca.l r0, @%0\n\t"
- "movca.l r0, @%1\n\t"
- "movca.l r0, @%2\n\t"
- "movca.l r0, @%3\n\t"
- "ocbi @%0\n\t"
- "ocbi @%1\n\t"
- "ocbi @%2\n\t"
- "ocbi @%3\n\t" : :
- "r" (a0), "r" (a1), "r" (a2), "r" (a3));
- asm volatile("ldc %0, sr" : : "r" (orig_sr));
- a0 += linesz;
- a1 += linesz;
- a2 += linesz;
- a3 += linesz;
- } while (a0 < a0e);
-}
-
extern void __weak sh4__flush_region_init(void);
/*
@@ -709,32 +382,11 @@ extern void __weak sh4__flush_region_init(void);
*/
void __init sh4_cache_init(void)
{
- unsigned int wt_enabled = !!(__raw_readl(CCR) & CCR_CACHE_WT);
-
printk("PVR=%08x CVR=%08x PRR=%08x\n",
ctrl_inl(CCN_PVR),
ctrl_inl(CCN_CVR),
ctrl_inl(CCN_PRR));
- if (wt_enabled)
- __flush_dcache_segment_fn = __flush_dcache_segment_writethrough;
- else {
- switch (boot_cpu_data.dcache.ways) {
- case 1:
- __flush_dcache_segment_fn = __flush_dcache_segment_1way;
- break;
- case 2:
- __flush_dcache_segment_fn = __flush_dcache_segment_2way;
- break;
- case 4:
- __flush_dcache_segment_fn = __flush_dcache_segment_4way;
- break;
- default:
- panic("unknown number of cache ways\n");
- break;
- }
- }
-
local_flush_icache_range = sh4_flush_icache_range;
local_flush_dcache_page = sh4_flush_dcache_page;
local_flush_cache_all = sh4_flush_cache_all;
diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c
index 2601935eb589..f527fb70fce6 100644
--- a/arch/sh/mm/cache-sh7705.c
+++ b/arch/sh/mm/cache-sh7705.c
@@ -141,7 +141,7 @@ static void sh7705_flush_dcache_page(void *arg)
if (mapping && !mapping_mapped(mapping))
set_bit(PG_dcache_dirty, &page->flags);
else
- __flush_dcache_page(PHYSADDR(page_address(page)));
+ __flush_dcache_page(__pa(page_address(page)));
}
static void __uses_jump_to_uncached sh7705_flush_cache_all(void *args)
diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c
index 5e1091be9dc4..63c132998f24 100644
--- a/arch/sh/mm/cache.c
+++ b/arch/sh/mm/cache.c
@@ -27,8 +27,11 @@ void (*local_flush_icache_page)(void *args) = cache_noop;
void (*local_flush_cache_sigtramp)(void *args) = cache_noop;
void (*__flush_wback_region)(void *start, int size);
+EXPORT_SYMBOL(__flush_wback_region);
void (*__flush_purge_region)(void *start, int size);
+EXPORT_SYMBOL(__flush_purge_region);
void (*__flush_invalidate_region)(void *start, int size);
+EXPORT_SYMBOL(__flush_invalidate_region);
static inline void noop__flush_region(void *start, int size)
{
@@ -161,14 +164,21 @@ void flush_cache_all(void)
{
cacheop_on_each_cpu(local_flush_cache_all, NULL, 1);
}
+EXPORT_SYMBOL(flush_cache_all);
void flush_cache_mm(struct mm_struct *mm)
{
+ if (boot_cpu_data.dcache.n_aliases == 0)
+ return;
+
cacheop_on_each_cpu(local_flush_cache_mm, mm, 1);
}
void flush_cache_dup_mm(struct mm_struct *mm)
{
+ if (boot_cpu_data.dcache.n_aliases == 0)
+ return;
+
cacheop_on_each_cpu(local_flush_cache_dup_mm, mm, 1);
}
@@ -195,11 +205,13 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
cacheop_on_each_cpu(local_flush_cache_range, (void *)&data, 1);
}
+EXPORT_SYMBOL(flush_cache_range);
void flush_dcache_page(struct page *page)
{
cacheop_on_each_cpu(local_flush_dcache_page, page, 1);
}
+EXPORT_SYMBOL(flush_dcache_page);
void flush_icache_range(unsigned long start, unsigned long end)
{
@@ -265,6 +277,8 @@ static void __init emit_cache_params(void)
void __init cpu_cache_init(void)
{
+ unsigned int cache_disabled = !(__raw_readl(CCR) & CCR_CACHE_ENABLE);
+
compute_alias(&boot_cpu_data.icache);
compute_alias(&boot_cpu_data.dcache);
compute_alias(&boot_cpu_data.scache);
@@ -273,6 +287,13 @@ void __init cpu_cache_init(void)
__flush_purge_region = noop__flush_region;
__flush_invalidate_region = noop__flush_region;
+ /*
+ * No flushing is necessary in the disabled cache case so we can
+ * just keep the noop functions in local_flush_..() and __flush_..()
+ */
+ if (unlikely(cache_disabled))
+ goto skip;
+
if (boot_cpu_data.family == CPU_FAMILY_SH2) {
extern void __weak sh2_cache_init(void);
@@ -312,5 +333,6 @@ void __init cpu_cache_init(void)
sh5_cache_init();
}
+skip:
emit_cache_params();
}
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
index e098ec158ddb..902967e3f841 100644
--- a/arch/sh/mm/consistent.c
+++ b/arch/sh/mm/consistent.c
@@ -15,11 +15,15 @@
#include <linux/dma-mapping.h>
#include <linux/dma-debug.h>
#include <linux/io.h>
+#include <linux/module.h>
#include <asm/cacheflush.h>
#include <asm/addrspace.h>
#define PREALLOC_DMA_DEBUG_ENTRIES 4096
+struct dma_map_ops *dma_ops;
+EXPORT_SYMBOL(dma_ops);
+
static int __init dma_init(void)
{
dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
@@ -27,15 +31,12 @@ static int __init dma_init(void)
}
fs_initcall(dma_init);
-void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t gfp)
+void *dma_generic_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp)
{
void *ret, *ret_nocache;
int order = get_order(size);
- if (dma_alloc_from_coherent(dev, size, dma_handle, &ret))
- return ret;
-
ret = (void *)__get_free_pages(gfp, order);
if (!ret)
return NULL;
@@ -57,35 +58,26 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
*dma_handle = virt_to_phys(ret);
- debug_dma_alloc_coherent(dev, size, *dma_handle, ret_nocache);
-
return ret_nocache;
}
-EXPORT_SYMBOL(dma_alloc_coherent);
-void dma_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
+void dma_generic_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
{
int order = get_order(size);
unsigned long pfn = dma_handle >> PAGE_SHIFT;
int k;
- WARN_ON(irqs_disabled()); /* for portability */
-
- if (dma_release_from_coherent(dev, order, vaddr))
- return;
-
- debug_dma_free_coherent(dev, size, vaddr, dma_handle);
for (k = 0; k < (1 << order); k++)
__free_pages(pfn_to_page(pfn + k), 0);
+
iounmap(vaddr);
}
-EXPORT_SYMBOL(dma_free_coherent);
void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
enum dma_data_direction direction)
{
-#ifdef CONFIG_CPU_SH5
+#if defined(CONFIG_CPU_SH5) || defined(CONFIG_PMB)
void *p1addr = vaddr;
#else
void *p1addr = (void*) P1SEGADDR((unsigned long)vaddr);
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index 8173e38afd38..432acd07e76a 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -15,6 +15,7 @@
#include <linux/pagemap.h>
#include <linux/percpu.h>
#include <linux/io.h>
+#include <linux/dma-mapping.h>
#include <asm/mmu_context.h>
#include <asm/tlb.h>
#include <asm/cacheflush.h>
@@ -186,11 +187,21 @@ void __init paging_init(void)
set_fixmap_nocache(FIX_UNCACHED, __pa(&__uncached_start));
}
+/*
+ * Early initialization for any I/O MMUs we might have.
+ */
+static void __init iommu_init(void)
+{
+ no_iommu_init();
+}
+
void __init mem_init(void)
{
int codesize, datasize, initsize;
int nid;
+ iommu_init();
+
num_physpages = 0;
high_memory = NULL;
@@ -323,4 +334,12 @@ int memory_add_physaddr_to_nid(u64 addr)
}
EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
#endif
+
#endif /* CONFIG_MEMORY_HOTPLUG */
+
+#ifdef CONFIG_PMB
+int __in_29bit_mode(void)
+{
+ return !(ctrl_inl(PMB_PASCR) & PASCR_SE);
+}
+#endif /* CONFIG_PMB */
diff --git a/arch/sh/mm/kmap.c b/arch/sh/mm/kmap.c
index 16e01b5fed04..15d74ea42094 100644
--- a/arch/sh/mm/kmap.c
+++ b/arch/sh/mm/kmap.c
@@ -39,7 +39,9 @@ void *kmap_coherent(struct page *page, unsigned long addr)
pagefault_disable();
idx = FIX_CMAP_END -
- ((addr & current_cpu_data.dcache.alias_mask) >> PAGE_SHIFT);
+ (((addr >> PAGE_SHIFT) & (FIX_N_COLOURS - 1)) +
+ (FIX_N_COLOURS * smp_processor_id()));
+
vaddr = __fix_to_virt(idx);
BUG_ON(!pte_none(*(kmap_coherent_pte - idx)));
diff --git a/arch/sh/mm/pmb-fixed.c b/arch/sh/mm/pmb-fixed.c
deleted file mode 100644
index 43c8eac4d8a1..000000000000
--- a/arch/sh/mm/pmb-fixed.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * arch/sh/mm/fixed_pmb.c
- *
- * Copyright (C) 2009 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/mm.h>
-#include <linux/io.h>
-#include <asm/mmu.h>
-#include <asm/mmu_context.h>
-
-static int __uses_jump_to_uncached fixed_pmb_init(void)
-{
- int i;
- unsigned long addr, data;
-
- jump_to_uncached();
-
- for (i = 0; i < PMB_ENTRY_MAX; i++) {
- addr = PMB_DATA + (i << PMB_E_SHIFT);
- data = ctrl_inl(addr);
- if (!(data & PMB_V))
- continue;
-
- if (data & PMB_C) {
-#if defined(CONFIG_CACHE_WRITETHROUGH)
- data |= PMB_WT;
-#elif defined(CONFIG_CACHE_WRITEBACK)
- data &= ~PMB_WT;
-#else
- data &= ~(PMB_C | PMB_WT);
-#endif
- }
- ctrl_outl(data, addr);
- }
-
- back_to_cached();
-
- return 0;
-}
-arch_initcall(fixed_pmb_init);
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c
index aade31102112..280f6a166035 100644
--- a/arch/sh/mm/pmb.c
+++ b/arch/sh/mm/pmb.c
@@ -35,29 +35,9 @@
static void __pmb_unmap(struct pmb_entry *);
-static struct kmem_cache *pmb_cache;
+static struct pmb_entry pmb_entry_list[NR_PMB_ENTRIES];
static unsigned long pmb_map;
-static struct pmb_entry pmb_init_map[] = {
- /* vpn ppn flags (ub/sz/c/wt) */
-
- /* P1 Section Mappings */
- { 0x80000000, 0x00000000, PMB_SZ_64M | PMB_C, },
- { 0x84000000, 0x04000000, PMB_SZ_64M | PMB_C, },
- { 0x88000000, 0x08000000, PMB_SZ_128M | PMB_C, },
- { 0x90000000, 0x10000000, PMB_SZ_64M | PMB_C, },
- { 0x94000000, 0x14000000, PMB_SZ_64M | PMB_C, },
- { 0x98000000, 0x18000000, PMB_SZ_64M | PMB_C, },
-
- /* P2 Section Mappings */
- { 0xa0000000, 0x00000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
- { 0xa4000000, 0x04000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
- { 0xa8000000, 0x08000000, PMB_UB | PMB_SZ_128M | PMB_WT, },
- { 0xb0000000, 0x10000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
- { 0xb4000000, 0x14000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
- { 0xb8000000, 0x18000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
-};
-
static inline unsigned long mk_pmb_entry(unsigned int entry)
{
return (entry & PMB_E_MASK) << PMB_E_SHIFT;
@@ -73,81 +53,68 @@ static inline unsigned long mk_pmb_data(unsigned int entry)
return mk_pmb_entry(entry) | PMB_DATA;
}
-static DEFINE_SPINLOCK(pmb_list_lock);
-static struct pmb_entry *pmb_list;
-
-static inline void pmb_list_add(struct pmb_entry *pmbe)
+static int pmb_alloc_entry(void)
{
- struct pmb_entry **p, *tmp;
+ unsigned int pos;
- p = &pmb_list;
- while ((tmp = *p) != NULL)
- p = &tmp->next;
+repeat:
+ pos = find_first_zero_bit(&pmb_map, NR_PMB_ENTRIES);
- pmbe->next = tmp;
- *p = pmbe;
-}
+ if (unlikely(pos > NR_PMB_ENTRIES))
+ return -ENOSPC;
-static inline void pmb_list_del(struct pmb_entry *pmbe)
-{
- struct pmb_entry **p, *tmp;
+ if (test_and_set_bit(pos, &pmb_map))
+ goto repeat;
- for (p = &pmb_list; (tmp = *p); p = &tmp->next)
- if (tmp == pmbe) {
- *p = tmp->next;
- return;
- }
+ return pos;
}
-struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn,
- unsigned long flags)
+static struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn,
+ unsigned long flags, int entry)
{
struct pmb_entry *pmbe;
+ int pos;
+
+ if (entry == PMB_NO_ENTRY) {
+ pos = pmb_alloc_entry();
+ if (pos < 0)
+ return ERR_PTR(pos);
+ } else {
+ if (test_bit(entry, &pmb_map))
+ return ERR_PTR(-ENOSPC);
+ pos = entry;
+ }
- pmbe = kmem_cache_alloc(pmb_cache, GFP_KERNEL);
+ pmbe = &pmb_entry_list[pos];
if (!pmbe)
return ERR_PTR(-ENOMEM);
pmbe->vpn = vpn;
pmbe->ppn = ppn;
pmbe->flags = flags;
-
- spin_lock_irq(&pmb_list_lock);
- pmb_list_add(pmbe);
- spin_unlock_irq(&pmb_list_lock);
+ pmbe->entry = pos;
return pmbe;
}
-void pmb_free(struct pmb_entry *pmbe)
+static void pmb_free(struct pmb_entry *pmbe)
{
- spin_lock_irq(&pmb_list_lock);
- pmb_list_del(pmbe);
- spin_unlock_irq(&pmb_list_lock);
+ int pos = pmbe->entry;
- kmem_cache_free(pmb_cache, pmbe);
+ pmbe->vpn = 0;
+ pmbe->ppn = 0;
+ pmbe->flags = 0;
+ pmbe->entry = 0;
+
+ clear_bit(pos, &pmb_map);
}
/*
* Must be in P2 for __set_pmb_entry()
*/
-int __set_pmb_entry(unsigned long vpn, unsigned long ppn,
- unsigned long flags, int *entry)
+static void __set_pmb_entry(unsigned long vpn, unsigned long ppn,
+ unsigned long flags, int pos)
{
- unsigned int pos = *entry;
-
- if (unlikely(pos == PMB_NO_ENTRY))
- pos = find_first_zero_bit(&pmb_map, NR_PMB_ENTRIES);
-
-repeat:
- if (unlikely(pos > NR_PMB_ENTRIES))
- return -ENOSPC;
-
- if (test_and_set_bit(pos, &pmb_map)) {
- pos = find_first_zero_bit(&pmb_map, NR_PMB_ENTRIES);
- goto repeat;
- }
-
ctrl_outl(vpn | PMB_V, mk_pmb_addr(pos));
#ifdef CONFIG_CACHE_WRITETHROUGH
@@ -161,35 +128,21 @@ repeat:
#endif
ctrl_outl(ppn | flags | PMB_V, mk_pmb_data(pos));
-
- *entry = pos;
-
- return 0;
}
-int __uses_jump_to_uncached set_pmb_entry(struct pmb_entry *pmbe)
+static void __uses_jump_to_uncached set_pmb_entry(struct pmb_entry *pmbe)
{
- int ret;
-
jump_to_uncached();
- ret = __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, &pmbe->entry);
+ __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, pmbe->entry);
back_to_cached();
-
- return ret;
}
-void __uses_jump_to_uncached clear_pmb_entry(struct pmb_entry *pmbe)
+static void __uses_jump_to_uncached clear_pmb_entry(struct pmb_entry *pmbe)
{
unsigned int entry = pmbe->entry;
unsigned long addr;
- /*
- * Don't allow clearing of wired init entries, P1 or P2 access
- * without a corresponding mapping in the PMB will lead to reset
- * by the TLB.
- */
- if (unlikely(entry < ARRAY_SIZE(pmb_init_map) ||
- entry >= NR_PMB_ENTRIES))
+ if (unlikely(entry >= NR_PMB_ENTRIES))
return;
jump_to_uncached();
@@ -202,8 +155,6 @@ void __uses_jump_to_uncached clear_pmb_entry(struct pmb_entry *pmbe)
ctrl_outl(ctrl_inl(addr) & ~PMB_V, addr);
back_to_cached();
-
- clear_bit(entry, &pmb_map);
}
@@ -239,23 +190,17 @@ long pmb_remap(unsigned long vaddr, unsigned long phys,
again:
for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) {
- int ret;
-
if (size < pmb_sizes[i].size)
continue;
- pmbe = pmb_alloc(vaddr, phys, pmb_flags | pmb_sizes[i].flag);
+ pmbe = pmb_alloc(vaddr, phys, pmb_flags | pmb_sizes[i].flag,
+ PMB_NO_ENTRY);
if (IS_ERR(pmbe)) {
err = PTR_ERR(pmbe);
goto out;
}
- ret = set_pmb_entry(pmbe);
- if (ret != 0) {
- pmb_free(pmbe);
- err = -EBUSY;
- goto out;
- }
+ set_pmb_entry(pmbe);
phys += pmb_sizes[i].size;
vaddr += pmb_sizes[i].size;
@@ -292,11 +237,16 @@ out:
void pmb_unmap(unsigned long addr)
{
- struct pmb_entry **p, *pmbe;
+ struct pmb_entry *pmbe = NULL;
+ int i;
- for (p = &pmb_list; (pmbe = *p); p = &pmbe->next)
- if (pmbe->vpn == addr)
- break;
+ for (i = 0; i < ARRAY_SIZE(pmb_entry_list); i++) {
+ if (test_bit(i, &pmb_map)) {
+ pmbe = &pmb_entry_list[i];
+ if (pmbe->vpn == addr)
+ break;
+ }
+ }
if (unlikely(!pmbe))
return;
@@ -306,13 +256,22 @@ void pmb_unmap(unsigned long addr)
static void __pmb_unmap(struct pmb_entry *pmbe)
{
- WARN_ON(!test_bit(pmbe->entry, &pmb_map));
+ BUG_ON(!test_bit(pmbe->entry, &pmb_map));
do {
struct pmb_entry *pmblink = pmbe;
- if (pmbe->entry != PMB_NO_ENTRY)
- clear_pmb_entry(pmbe);
+ /*
+ * We may be called before this pmb_entry has been
+ * entered into the PMB table via set_pmb_entry(), but
+ * that's OK because we've allocated a unique slot for
+ * this entry in pmb_alloc() (even if we haven't filled
+ * it yet).
+ *
+ * Therefore, calling clear_pmb_entry() is safe as no
+ * other mapping can be using that slot.
+ */
+ clear_pmb_entry(pmbe);
pmbe = pmblink->link;
@@ -320,42 +279,34 @@ static void __pmb_unmap(struct pmb_entry *pmbe)
} while (pmbe);
}
-static void pmb_cache_ctor(void *pmb)
+#ifdef CONFIG_PMB
+int __uses_jump_to_uncached pmb_init(void)
{
- struct pmb_entry *pmbe = pmb;
-
- memset(pmb, 0, sizeof(struct pmb_entry));
-
- pmbe->entry = PMB_NO_ENTRY;
-}
-
-static int __uses_jump_to_uncached pmb_init(void)
-{
- unsigned int nr_entries = ARRAY_SIZE(pmb_init_map);
- unsigned int entry, i;
-
- BUG_ON(unlikely(nr_entries >= NR_PMB_ENTRIES));
-
- pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry), 0,
- SLAB_PANIC, pmb_cache_ctor);
+ unsigned int i;
+ long size, ret;
jump_to_uncached();
/*
- * Ordering is important, P2 must be mapped in the PMB before we
- * can set PMB.SE, and P1 must be mapped before we jump back to
- * P1 space.
+ * Insert PMB entries for the P1 and P2 areas so that, after
+ * we've switched the MMU to 32-bit mode, the semantics of P1
+ * and P2 are the same as in 29-bit mode, e.g.
+ *
+ * P1 - provides a cached window onto physical memory
+ * P2 - provides an uncached window onto physical memory
*/
- for (entry = 0; entry < nr_entries; entry++) {
- struct pmb_entry *pmbe = pmb_init_map + entry;
+ size = __MEMORY_START + __MEMORY_SIZE;
- __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, &entry);
- }
+ ret = pmb_remap(P1SEG, 0x00000000, size, PMB_C);
+ BUG_ON(ret != size);
+
+ ret = pmb_remap(P2SEG, 0x00000000, size, PMB_WT | PMB_UB);
+ BUG_ON(ret != size);
ctrl_outl(0, PMB_IRMCR);
/* PMB.SE and UB[7] */
- ctrl_outl((1 << 31) | (1 << 7), PMB_PASCR);
+ ctrl_outl(PASCR_SE | (1 << 7), PMB_PASCR);
/* Flush out the TLB */
i = ctrl_inl(MMUCR);
@@ -366,7 +317,53 @@ static int __uses_jump_to_uncached pmb_init(void)
return 0;
}
-arch_initcall(pmb_init);
+#else
+int __uses_jump_to_uncached pmb_init(void)
+{
+ int i;
+ unsigned long addr, data;
+
+ jump_to_uncached();
+
+ for (i = 0; i < PMB_ENTRY_MAX; i++) {
+ struct pmb_entry *pmbe;
+ unsigned long vpn, ppn, flags;
+
+ addr = PMB_DATA + (i << PMB_E_SHIFT);
+ data = ctrl_inl(addr);
+ if (!(data & PMB_V))
+ continue;
+
+ if (data & PMB_C) {
+#if defined(CONFIG_CACHE_WRITETHROUGH)
+ data |= PMB_WT;
+#elif defined(CONFIG_CACHE_WRITEBACK)
+ data &= ~PMB_WT;
+#else
+ data &= ~(PMB_C | PMB_WT);
+#endif
+ }
+ ctrl_outl(data, addr);
+
+ ppn = data & PMB_PFN_MASK;
+
+ flags = data & (PMB_C | PMB_WT | PMB_UB);
+ flags |= data & PMB_SZ_MASK;
+
+ addr = PMB_ADDR + (i << PMB_E_SHIFT);
+ data = ctrl_inl(addr);
+
+ vpn = data & PMB_PFN_MASK;
+
+ pmbe = pmb_alloc(vpn, ppn, flags, i);
+ WARN_ON(IS_ERR(pmbe));
+ }
+
+ back_to_cached();
+
+ return 0;
+}
+#endif /* CONFIG_PMB */
static int pmb_seq_show(struct seq_file *file, void *iter)
{
@@ -434,15 +431,18 @@ postcore_initcall(pmb_debugfs_init);
static int pmb_sysdev_suspend(struct sys_device *dev, pm_message_t state)
{
static pm_message_t prev_state;
+ int i;
/* Restore the PMB after a resume from hibernation */
if (state.event == PM_EVENT_ON &&
prev_state.event == PM_EVENT_FREEZE) {
struct pmb_entry *pmbe;
- spin_lock_irq(&pmb_list_lock);
- for (pmbe = pmb_list; pmbe; pmbe = pmbe->next)
- set_pmb_entry(pmbe);
- spin_unlock_irq(&pmb_list_lock);
+ for (i = 0; i < ARRAY_SIZE(pmb_entry_list); i++) {
+ if (test_bit(i, &pmb_map)) {
+ pmbe = &pmb_entry_list[i];
+ set_pmb_entry(pmbe);
+ }
+ }
}
prev_state = state;
return 0;
diff --git a/arch/sh/tools/Makefile b/arch/sh/tools/Makefile
index 567516b58acc..558a56bcc7cf 100644
--- a/arch/sh/tools/Makefile
+++ b/arch/sh/tools/Makefile
@@ -10,7 +10,7 @@
# Shamelessly cloned from ARM.
#
-include/asm-sh/machtypes.h: $(src)/gen-mach-types $(src)/mach-types
+include/generated/machtypes.h: $(src)/gen-mach-types $(src)/mach-types
@echo ' Generating $@'
- $(Q)if [ ! -d include/asm-sh ]; then mkdir -p include/asm-sh; fi
+ $(Q)mkdir -p $(dir $@)
$(Q)$(AWK) -f $^ > $@ || { rm -f $@; /bin/false; }
diff --git a/arch/sh/tools/gen-mach-types b/arch/sh/tools/gen-mach-types
index 65161e368353..f5ff7c5d8913 100644
--- a/arch/sh/tools/gen-mach-types
+++ b/arch/sh/tools/gen-mach-types
@@ -1,6 +1,6 @@
#!/bin/awk
#
-# Awk script to generate include/asm-sh/machtypes.h
+# Awk script to generate include/generated/machtypes.h
# Heavily based on arch/arm/tools/gen-mach-types
#
BEGIN { nr = 0 }
diff --git a/arch/sparc/include/asm/asm-offsets.h b/arch/sparc/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/sparc/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/sparc/include/asm/fcntl.h b/arch/sparc/include/asm/fcntl.h
index d4d9c9d852c3..3b9cfb39175e 100644
--- a/arch/sparc/include/asm/fcntl.h
+++ b/arch/sparc/include/asm/fcntl.h
@@ -1,14 +1,12 @@
#ifndef _SPARC_FCNTL_H
#define _SPARC_FCNTL_H
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
#define O_APPEND 0x0008
#define FASYNC 0x0040 /* fcntl, for BSD compatibility */
#define O_CREAT 0x0200 /* not fcntl */
#define O_TRUNC 0x0400 /* not fcntl */
#define O_EXCL 0x0800 /* not fcntl */
-#define O_SYNC 0x2000
+#define O_DSYNC 0x2000 /* used to be O_SYNC, see below */
#define O_NONBLOCK 0x4000
#if defined(__sparc__) && defined(__arch64__)
#define O_NDELAY 0x0004
@@ -20,6 +18,21 @@
#define O_DIRECT 0x100000 /* direct disk access hint */
#define O_NOATIME 0x200000
#define O_CLOEXEC 0x400000
+/*
+ * Before Linux 2.6.32 only O_DSYNC semantics were implemented, but using
+ * the O_SYNC flag. We continue to use the existing numerical value
+ * for O_DSYNC semantics now, but using the correct symbolic name for it.
+ * This new value is used to request true Posix O_SYNC semantics. It is
+ * defined in this strange way to make sure applications compiled against
+ * new headers get at least O_DSYNC semantics on older kernels.
+ *
+ * This has the nice side-effect that we can simply test for O_DSYNC
+ * wherever we do not care if O_DSYNC or O_SYNC is used.
+ *
+ * Note: __O_SYNC must never be used directly.
+ */
+#define __O_SYNC 0x800000
+#define O_SYNC (__O_SYNC|O_DSYNC)
#define F_GETOWN 5 /* for sockets. */
#define F_SETOWN 6 /* for sockets. */
diff --git a/arch/sparc/include/asm/pci_64.h b/arch/sparc/include/asm/pci_64.h
index b63e51c3c3ee..b0576df6ec83 100644
--- a/arch/sparc/include/asm/pci_64.h
+++ b/arch/sparc/include/asm/pci_64.h
@@ -16,8 +16,6 @@
#define PCI_IRQ_NONE 0xffffffff
-#define PCI_CACHE_LINE_BYTES 64
-
static inline void pcibios_set_master(struct pci_dev *dev)
{
/* No special bus mastering setup handling */
diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h
index 82a190d7efc1..f845828ca4c6 100644
--- a/arch/sparc/include/asm/prom.h
+++ b/arch/sparc/include/asm/prom.h
@@ -1,3 +1,4 @@
+#include <linux/of.h> /* linux/of.h gets to determine #include ordering */
#ifndef _SPARC_PROM_H
#define _SPARC_PROM_H
#ifdef __KERNEL__
@@ -28,50 +29,11 @@
#define of_prop_cmp(s1, s2) strcasecmp((s1), (s2))
#define of_node_cmp(s1, s2) strcmp((s1), (s2))
-typedef u32 phandle;
-typedef u32 ihandle;
-
-struct property {
- char *name;
- int length;
- void *value;
- struct property *next;
- unsigned long _flags;
- unsigned int unique_id;
-};
-
-struct of_irq_controller;
-struct device_node {
- const char *name;
- const char *type;
- phandle node;
- char *path_component_name;
- char *full_name;
-
- struct property *properties;
- struct property *deadprops; /* removed properties */
- struct device_node *parent;
- struct device_node *child;
- struct device_node *sibling;
- struct device_node *next; /* next device of same type */
- struct device_node *allnext; /* next in list of all nodes */
- struct proc_dir_entry *pde; /* this node's proc directory */
- struct kref kref;
- unsigned long _flags;
- void *data;
- unsigned int unique_id;
-
- struct of_irq_controller *irq_trans;
-};
-
struct of_irq_controller {
unsigned int (*irq_build)(struct device_node *, unsigned int, void *);
void *data;
};
-#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
-#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
-
extern struct device_node *of_find_node_by_cpuid(int cpuid);
extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
extern struct mutex of_set_property_mutex;
@@ -89,15 +51,6 @@ extern void prom_build_devicetree(void);
extern void of_populate_present_mask(void);
extern void of_fill_in_cpu_data(void);
-/* Dummy ref counting routines - to be implemented later */
-static inline struct device_node *of_node_get(struct device_node *node)
-{
- return node;
-}
-static inline void of_node_put(struct device_node *node)
-{
-}
-
/* These routines are here to provide compatibility with how powerpc
* handles IRQ mapping for OF device nodes. We precompute and permanently
* register them in the of_device objects, whereas powerpc computes them
@@ -108,12 +61,6 @@ static inline void irq_dispose_mapping(unsigned int virq)
{
}
-/*
- * NB: This is here while we transition from using asm/prom.h
- * to linux/of.h
- */
-#include <linux/of.h>
-
extern struct device_node *of_console_device;
extern char *of_console_path;
extern char *of_console_options;
diff --git a/arch/sparc/include/asm/socket.h b/arch/sparc/include/asm/socket.h
index 3a5ae3d12088..9d3fefcff2f5 100644
--- a/arch/sparc/include/asm/socket.h
+++ b/arch/sparc/include/asm/socket.h
@@ -56,6 +56,8 @@
#define SO_TIMESTAMPING 0x0023
#define SCM_TIMESTAMPING SO_TIMESTAMPING
+#define SO_RXQ_OVFL 0x0024
+
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define SO_SECURITY_AUTHENTICATION 0x5001
#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h
index 42f2316c3eaa..d8d25bd97121 100644
--- a/arch/sparc/include/asm/unistd.h
+++ b/arch/sparc/include/asm/unistd.h
@@ -396,8 +396,9 @@
#define __NR_pwritev 325
#define __NR_rt_tgsigqueueinfo 326
#define __NR_perf_event_open 327
+#define __NR_recvmmsg 328
-#define NR_SYSCALLS 328
+#define NR_SYSCALLS 329
#ifdef __32bit_syscall_numbers__
/* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
diff --git a/arch/sparc/kernel/nmi.c b/arch/sparc/kernel/nmi.c
index b129611590a4..f30f4a1ead23 100644
--- a/arch/sparc/kernel/nmi.c
+++ b/arch/sparc/kernel/nmi.c
@@ -47,7 +47,7 @@ static DEFINE_PER_CPU(short, wd_enabled);
static int endflag __initdata;
static DEFINE_PER_CPU(unsigned int, last_irq_sum);
-static DEFINE_PER_CPU(local_t, alert_counter);
+static DEFINE_PER_CPU(long, alert_counter);
static DEFINE_PER_CPU(int, nmi_touch);
void touch_nmi_watchdog(void)
@@ -112,13 +112,13 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs)
touched = 1;
}
if (!touched && __get_cpu_var(last_irq_sum) == sum) {
- local_inc(&__get_cpu_var(alert_counter));
- if (local_read(&__get_cpu_var(alert_counter)) == 30 * nmi_hz)
+ __this_cpu_inc(per_cpu_var(alert_counter));
+ if (__this_cpu_read(per_cpu_var(alert_counter)) == 30 * nmi_hz)
die_nmi("BUG: NMI Watchdog detected LOCKUP",
regs, panic_on_timeout);
} else {
__get_cpu_var(last_irq_sum) = sum;
- local_set(&__get_cpu_var(alert_counter), 0);
+ __this_cpu_write(per_cpu_var(alert_counter), 0);
}
if (__get_cpu_var(wd_enabled)) {
write_pic(picl_value(nmi_hz));
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index c68648662802..b85374f7cf94 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -1081,3 +1081,10 @@ void pci_resource_to_user(const struct pci_dev *pdev, int bar,
*start = rp->start - offset;
*end = rp->end - offset;
}
+
+static int __init pcibios_init(void)
+{
+ pci_dfl_cache_line_size = 64 >> 2;
+ return 0;
+}
+subsys_initcall(pcibios_init);
diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S
index 0f1658d37490..ceb1530f8aa6 100644
--- a/arch/sparc/kernel/systbls_32.S
+++ b/arch/sparc/kernel/systbls_32.S
@@ -82,5 +82,5 @@ sys_call_table:
/*310*/ .long sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate
/*315*/ .long sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1
/*320*/ .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv
-/*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open
+/*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg
diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S
index 009825f6e73c..f37bef747e60 100644
--- a/arch/sparc/kernel/systbls_64.S
+++ b/arch/sparc/kernel/systbls_64.S
@@ -83,7 +83,7 @@ sys_call_table32:
/*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate
.word compat_sys_timerfd_settime, compat_sys_timerfd_gettime, compat_sys_signalfd4, sys_eventfd2, sys_epoll_create1
/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv
- .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open
+ .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg
#endif /* CONFIG_COMPAT */
@@ -158,4 +158,4 @@ sys_call_table:
/*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate
.word sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1
/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv
- .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open
+ .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg
diff --git a/arch/um/Makefile b/arch/um/Makefile
index fc633dbacf84..fab8121d2b32 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -149,6 +149,6 @@ $(SHARED_HEADERS)/user_constants.h: $(ARCH_DIR)/sys-$(SUBARCH)/user-offsets.s
$(SHARED_HEADERS)/kern_constants.h:
$(Q)mkdir -p $(dir $@)
- $(Q)echo '#include "../../../../include/asm/asm-offsets.h"' >$@
+ $(Q)echo '#include "../../../../include/generated/asm-offsets.h"' >$@
export SUBARCH USER_CFLAGS CFLAGS_NO_HARDENING OS HEADER_ARCH DEV_NULL_PATH
diff --git a/arch/um/include/asm/asm-offsets.h b/arch/um/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/um/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 07e01149e3bf..f33d8e101df0 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -50,6 +50,7 @@ config X86
select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_LZMA
select HAVE_ARCH_KMEMCHECK
+ select HAVE_USER_RETURN_NOTIFIER
config OUTPUT_FORMAT
string
@@ -1242,6 +1243,11 @@ config ARCH_MEMORY_PROBE
def_bool X86_64
depends on MEMORY_HOTPLUG
+config ILLEGAL_POINTER_VALUE
+ hex
+ default 0 if X86_32
+ default 0xdead000000000000 if X86_64
+
source "mm/Kconfig"
config HIGHPTE
@@ -1330,7 +1336,9 @@ config MATH_EMULATION
kernel, it won't hurt.
config MTRR
- bool "MTRR (Memory Type Range Register) support"
+ bool
+ default y
+ prompt "MTRR (Memory Type Range Register) support" if EMBEDDED
---help---
On Intel P6 family processors (Pentium Pro, Pentium II and later)
the Memory Type Range Registers (MTRRs) may be used to control
@@ -1396,7 +1404,8 @@ config MTRR_SANITIZER_SPARE_REG_NR_DEFAULT
config X86_PAT
bool
- prompt "x86 PAT support"
+ default y
+ prompt "x86 PAT support" if EMBEDDED
depends on MTRR
---help---
Use PAT attributes to setup page level cache control.
@@ -1443,12 +1452,8 @@ config SECCOMP
If unsure, say Y. Only embedded should say N here.
-config CC_STACKPROTECTOR_ALL
- bool
-
config CC_STACKPROTECTOR
bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)"
- select CC_STACKPROTECTOR_ALL
---help---
This option turns on the -fstack-protector GCC feature. This
feature puts, at the beginning of functions, a canary value on
@@ -2038,6 +2043,8 @@ source "drivers/pcmcia/Kconfig"
source "drivers/pci/hotplug/Kconfig"
+source "drivers/vbus/Kconfig"
+
endmenu
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index f2824fb8c79c..5e99762eb5c2 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -400,13 +400,13 @@ config X86_TSC
config X86_CMPXCHG64
def_bool y
- depends on X86_PAE || X86_64 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MATOM
+ depends on !M386 && !M486
# this should be set for all -march=.. options where the compiler
# generates cmov.
config X86_CMOV
def_bool y
- depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MATOM)
+ depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MATOM || MGEODE_LX)
config X86_MINIMUM_CPU_FAMILY
int
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index d105f29bb6bb..731318e5ac1d 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -186,6 +186,15 @@ config X86_DS_SELFTEST
config HAVE_MMIOTRACE_SUPPORT
def_bool y
+config X86_DECODER_SELFTEST
+ bool "x86 instruction decoder selftest"
+ depends on DEBUG_KERNEL
+ ---help---
+ Perform x86 instruction decoder selftests at build time.
+ This option is useful for checking the sanity of x86 instruction
+ decoder code.
+ If unsure, say "N".
+
#
# IO delay types:
#
@@ -287,4 +296,18 @@ config OPTIMIZE_INLINING
If unsure, say N.
+config DEBUG_STRICT_USER_COPY_CHECKS
+ bool "Strict copy size checks"
+ depends on DEBUG_KERNEL && !TRACE_BRANCH_PROFILING
+ ---help---
+ Enabling this option turns a certain set of sanity checks for user
+ copy operations into compile time failures.
+
+ The copy_from_user() etc checks are there to help test if there
+ are sufficient security checks on the length argument of
+ the copy operation, by having gcc prove that the argument is
+ within bounds.
+
+ If unsure, or if you run an older (pre 4.4) gcc, say N.
+
endmenu
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index a012ee8ef803..78b32be55e9e 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -76,7 +76,6 @@ ifdef CONFIG_CC_STACKPROTECTOR
cc_has_sp := $(srctree)/scripts/gcc-x86_$(BITS)-has-stack-protector.sh
ifeq ($(shell $(CONFIG_SHELL) $(cc_has_sp) $(CC) $(biarch)),y)
stackp-y := -fstack-protector
- stackp-$(CONFIG_CC_STACKPROTECTOR_ALL) += -fstack-protector-all
KBUILD_CFLAGS += $(stackp-y)
else
$(warning stack protector enabled but no compiler support)
@@ -156,6 +155,9 @@ all: bzImage
KBUILD_IMAGE := $(boot)/bzImage
bzImage: vmlinux
+ifeq ($(CONFIG_X86_DECODER_SELFTEST),y)
+ $(Q)$(MAKE) $(build)=arch/x86/tools posttest
+endif
$(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE)
$(Q)mkdir -p $(objtree)/arch/$(UTS_MACHINE)/boot
$(Q)ln -fsn ../../x86/boot/bzImage $(objtree)/arch/$(UTS_MACHINE)/boot/$@
diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu
index 30e9a264f69d..cbf0776dbec1 100644
--- a/arch/x86/Makefile_32.cpu
+++ b/arch/x86/Makefile_32.cpu
@@ -41,7 +41,7 @@ cflags-$(CONFIG_X86_ELAN) += -march=i486
# Geode GX1 support
cflags-$(CONFIG_MGEODEGX1) += -march=pentium-mmx
-
+cflags-$(CONFIG_MGEODE_LX) += $(call cc-option,-march=geode,-march=pentium-mmx)
# add at the end to overwrite eventual tuning options from earlier
# cpu entries
cflags-$(CONFIG_X86_GENERIC) += $(call tune,generic,$(call tune,i686))
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index 077e1b69198e..faff0dc9c06a 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -107,8 +107,7 @@ ENTRY(startup_32)
lgdt gdt(%ebp)
/* Enable PAE mode */
- xorl %eax, %eax
- orl $(X86_CR4_PAE), %eax
+ movl $(X86_CR4_PAE), %eax
movl %eax, %cr4
/*
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index b31cc54b4641..93e689f4bd86 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -16,7 +16,7 @@
*/
#include <asm/segment.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
#include <asm/boot.h>
#include <asm/e820.h>
#include <asm/page_types.h>
diff --git a/arch/x86/boot/setup.ld b/arch/x86/boot/setup.ld
index 0f6ec455a2b1..03c0683636b6 100644
--- a/arch/x86/boot/setup.ld
+++ b/arch/x86/boot/setup.ld
@@ -53,6 +53,9 @@ SECTIONS
/DISCARD/ : { *(.note*) }
+ /*
+ * The ASSERT() sink to . is intentional, for binutils 2.14 compatibility:
+ */
. = ASSERT(_end <= 0x8000, "Setup too big!");
. = ASSERT(hdr == 0x1f1, "The setup header has the wrong offset!");
/* Necessary for the very-old-loader check to work... */
diff --git a/arch/x86/boot/version.c b/arch/x86/boot/version.c
index 2723d9b5ce43..2b15aa488ffb 100644
--- a/arch/x86/boot/version.c
+++ b/arch/x86/boot/version.c
@@ -13,8 +13,8 @@
*/
#include "boot.h"
-#include <linux/utsrelease.h>
-#include <linux/compile.h>
+#include <generated/utsrelease.h>
+#include <generated/compile.h>
const char kernel_version[] =
UTS_RELEASE " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ") "
diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile
index cfb0010fa940..1a58ad89fdf7 100644
--- a/arch/x86/crypto/Makefile
+++ b/arch/x86/crypto/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o
obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
obj-$(CONFIG_CRYPTO_SALSA20_X86_64) += salsa20-x86_64.o
obj-$(CONFIG_CRYPTO_AES_NI_INTEL) += aesni-intel.o
+obj-$(CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL) += ghash-clmulni-intel.o
obj-$(CONFIG_CRYPTO_CRC32C_INTEL) += crc32c-intel.o
@@ -24,3 +25,5 @@ twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o
salsa20-x86_64-y := salsa20-x86_64-asm_64.o salsa20_glue.o
aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o
+
+ghash-clmulni-intel-y := ghash-clmulni-intel_asm.o ghash-clmulni-intel_glue.o
diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c
index 585edebe12cf..49c552c060e9 100644
--- a/arch/x86/crypto/aesni-intel_glue.c
+++ b/arch/x86/crypto/aesni-intel_glue.c
@@ -82,7 +82,7 @@ static int aes_set_key_common(struct crypto_tfm *tfm, void *raw_ctx,
return -EINVAL;
}
- if (irq_fpu_usable())
+ if (!irq_fpu_usable())
err = crypto_aes_expand_key(ctx, in_key, key_len);
else {
kernel_fpu_begin();
@@ -103,7 +103,7 @@ static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm));
- if (irq_fpu_usable())
+ if (!irq_fpu_usable())
crypto_aes_encrypt_x86(ctx, dst, src);
else {
kernel_fpu_begin();
@@ -116,7 +116,7 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm));
- if (irq_fpu_usable())
+ if (!irq_fpu_usable())
crypto_aes_decrypt_x86(ctx, dst, src);
else {
kernel_fpu_begin();
@@ -342,7 +342,7 @@ static int ablk_encrypt(struct ablkcipher_request *req)
struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
struct async_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
- if (irq_fpu_usable()) {
+ if (!irq_fpu_usable()) {
struct ablkcipher_request *cryptd_req =
ablkcipher_request_ctx(req);
memcpy(cryptd_req, req, sizeof(*req));
@@ -363,7 +363,7 @@ static int ablk_decrypt(struct ablkcipher_request *req)
struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
struct async_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
- if (irq_fpu_usable()) {
+ if (!irq_fpu_usable()) {
struct ablkcipher_request *cryptd_req =
ablkcipher_request_ctx(req);
memcpy(cryptd_req, req, sizeof(*req));
diff --git a/arch/x86/crypto/ghash-clmulni-intel_asm.S b/arch/x86/crypto/ghash-clmulni-intel_asm.S
new file mode 100644
index 000000000000..b9e787a511da
--- /dev/null
+++ b/arch/x86/crypto/ghash-clmulni-intel_asm.S
@@ -0,0 +1,157 @@
+/*
+ * Accelerated GHASH implementation with Intel PCLMULQDQ-NI
+ * instructions. This file contains accelerated part of ghash
+ * implementation. More information about PCLMULQDQ can be found at:
+ *
+ * http://software.intel.com/en-us/articles/carry-less-multiplication-and-its-usage-for-computing-the-gcm-mode/
+ *
+ * Copyright (c) 2009 Intel Corp.
+ * Author: Huang Ying <ying.huang@intel.com>
+ * Vinodh Gopal
+ * Erdinc Ozturk
+ * Deniz Karakoyunlu
+ *
+ * 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/linkage.h>
+
+.align 16
+.Lbswap_mask:
+ .octa 0x000102030405060708090a0b0c0d0e0f
+.Lpoly:
+ .octa 0xc2000000000000000000000000000001
+.Ltwo_one:
+ .octa 0x00000001000000000000000000000001
+
+#define DATA %xmm0
+#define SHASH %xmm1
+#define T1 %xmm2
+#define T2 %xmm3
+#define T3 %xmm4
+#define BSWAP %xmm5
+#define IN1 %xmm6
+
+.text
+
+/*
+ * __clmul_gf128mul_ble: internal ABI
+ * input:
+ * DATA: operand1
+ * SHASH: operand2, hash_key << 1 mod poly
+ * output:
+ * DATA: operand1 * operand2 mod poly
+ * changed:
+ * T1
+ * T2
+ * T3
+ */
+__clmul_gf128mul_ble:
+ movaps DATA, T1
+ pshufd $0b01001110, DATA, T2
+ pshufd $0b01001110, SHASH, T3
+ pxor DATA, T2
+ pxor SHASH, T3
+
+ # pclmulqdq $0x00, SHASH, DATA # DATA = a0 * b0
+ .byte 0x66, 0x0f, 0x3a, 0x44, 0xc1, 0x00
+ # pclmulqdq $0x11, SHASH, T1 # T1 = a1 * b1
+ .byte 0x66, 0x0f, 0x3a, 0x44, 0xd1, 0x11
+ # pclmulqdq $0x00, T3, T2 # T2 = (a1 + a0) * (b1 + b0)
+ .byte 0x66, 0x0f, 0x3a, 0x44, 0xdc, 0x00
+ pxor DATA, T2
+ pxor T1, T2 # T2 = a0 * b1 + a1 * b0
+
+ movaps T2, T3
+ pslldq $8, T3
+ psrldq $8, T2
+ pxor T3, DATA
+ pxor T2, T1 # <T1:DATA> is result of
+ # carry-less multiplication
+
+ # first phase of the reduction
+ movaps DATA, T3
+ psllq $1, T3
+ pxor DATA, T3
+ psllq $5, T3
+ pxor DATA, T3
+ psllq $57, T3
+ movaps T3, T2
+ pslldq $8, T2
+ psrldq $8, T3
+ pxor T2, DATA
+ pxor T3, T1
+
+ # second phase of the reduction
+ movaps DATA, T2
+ psrlq $5, T2
+ pxor DATA, T2
+ psrlq $1, T2
+ pxor DATA, T2
+ psrlq $1, T2
+ pxor T2, T1
+ pxor T1, DATA
+ ret
+
+/* void clmul_ghash_mul(char *dst, const be128 *shash) */
+ENTRY(clmul_ghash_mul)
+ movups (%rdi), DATA
+ movups (%rsi), SHASH
+ movaps .Lbswap_mask, BSWAP
+ pshufb BSWAP, DATA
+ call __clmul_gf128mul_ble
+ pshufb BSWAP, DATA
+ movups DATA, (%rdi)
+ ret
+
+/*
+ * void clmul_ghash_update(char *dst, const char *src, unsigned int srclen,
+ * const be128 *shash);
+ */
+ENTRY(clmul_ghash_update)
+ cmp $16, %rdx
+ jb .Lupdate_just_ret # check length
+ movaps .Lbswap_mask, BSWAP
+ movups (%rdi), DATA
+ movups (%rcx), SHASH
+ pshufb BSWAP, DATA
+.align 4
+.Lupdate_loop:
+ movups (%rsi), IN1
+ pshufb BSWAP, IN1
+ pxor IN1, DATA
+ call __clmul_gf128mul_ble
+ sub $16, %rdx
+ add $16, %rsi
+ cmp $16, %rdx
+ jge .Lupdate_loop
+ pshufb BSWAP, DATA
+ movups DATA, (%rdi)
+.Lupdate_just_ret:
+ ret
+
+/*
+ * void clmul_ghash_setkey(be128 *shash, const u8 *key);
+ *
+ * Calculate hash_key << 1 mod poly
+ */
+ENTRY(clmul_ghash_setkey)
+ movaps .Lbswap_mask, BSWAP
+ movups (%rsi), %xmm0
+ pshufb BSWAP, %xmm0
+ movaps %xmm0, %xmm1
+ psllq $1, %xmm0
+ psrlq $63, %xmm1
+ movaps %xmm1, %xmm2
+ pslldq $8, %xmm1
+ psrldq $8, %xmm2
+ por %xmm1, %xmm0
+ # reduction
+ pshufd $0b00100100, %xmm2, %xmm1
+ pcmpeqd .Ltwo_one, %xmm1
+ pand .Lpoly, %xmm1
+ pxor %xmm1, %xmm0
+ movups %xmm0, (%rdi)
+ ret
diff --git a/arch/x86/crypto/ghash-clmulni-intel_glue.c b/arch/x86/crypto/ghash-clmulni-intel_glue.c
new file mode 100644
index 000000000000..65d409644d72
--- /dev/null
+++ b/arch/x86/crypto/ghash-clmulni-intel_glue.c
@@ -0,0 +1,333 @@
+/*
+ * Accelerated GHASH implementation with Intel PCLMULQDQ-NI
+ * instructions. This file contains glue code.
+ *
+ * Copyright (c) 2009 Intel Corp.
+ * Author: Huang Ying <ying.huang@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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/crypto.h>
+#include <crypto/algapi.h>
+#include <crypto/cryptd.h>
+#include <crypto/gf128mul.h>
+#include <crypto/internal/hash.h>
+#include <asm/i387.h>
+
+#define GHASH_BLOCK_SIZE 16
+#define GHASH_DIGEST_SIZE 16
+
+void clmul_ghash_mul(char *dst, const be128 *shash);
+
+void clmul_ghash_update(char *dst, const char *src, unsigned int srclen,
+ const be128 *shash);
+
+void clmul_ghash_setkey(be128 *shash, const u8 *key);
+
+struct ghash_async_ctx {
+ struct cryptd_ahash *cryptd_tfm;
+};
+
+struct ghash_ctx {
+ be128 shash;
+};
+
+struct ghash_desc_ctx {
+ u8 buffer[GHASH_BLOCK_SIZE];
+ u32 bytes;
+};
+
+static int ghash_init(struct shash_desc *desc)
+{
+ struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
+
+ memset(dctx, 0, sizeof(*dctx));
+
+ return 0;
+}
+
+static int ghash_setkey(struct crypto_shash *tfm,
+ const u8 *key, unsigned int keylen)
+{
+ struct ghash_ctx *ctx = crypto_shash_ctx(tfm);
+
+ if (keylen != GHASH_BLOCK_SIZE) {
+ crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ }
+
+ clmul_ghash_setkey(&ctx->shash, key);
+
+ return 0;
+}
+
+static int ghash_update(struct shash_desc *desc,
+ const u8 *src, unsigned int srclen)
+{
+ struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
+ struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
+ u8 *dst = dctx->buffer;
+
+ kernel_fpu_begin();
+ if (dctx->bytes) {
+ int n = min(srclen, dctx->bytes);
+ u8 *pos = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
+
+ dctx->bytes -= n;
+ srclen -= n;
+
+ while (n--)
+ *pos++ ^= *src++;
+
+ if (!dctx->bytes)
+ clmul_ghash_mul(dst, &ctx->shash);
+ }
+
+ clmul_ghash_update(dst, src, srclen, &ctx->shash);
+ kernel_fpu_end();
+
+ if (srclen & 0xf) {
+ src += srclen - (srclen & 0xf);
+ srclen &= 0xf;
+ dctx->bytes = GHASH_BLOCK_SIZE - srclen;
+ while (srclen--)
+ *dst++ ^= *src++;
+ }
+
+ return 0;
+}
+
+static void ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx)
+{
+ u8 *dst = dctx->buffer;
+
+ if (dctx->bytes) {
+ u8 *tmp = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
+
+ while (dctx->bytes--)
+ *tmp++ ^= 0;
+
+ kernel_fpu_begin();
+ clmul_ghash_mul(dst, &ctx->shash);
+ kernel_fpu_end();
+ }
+
+ dctx->bytes = 0;
+}
+
+static int ghash_final(struct shash_desc *desc, u8 *dst)
+{
+ struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
+ struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
+ u8 *buf = dctx->buffer;
+
+ ghash_flush(ctx, dctx);
+ memcpy(dst, buf, GHASH_BLOCK_SIZE);
+
+ return 0;
+}
+
+static struct shash_alg ghash_alg = {
+ .digestsize = GHASH_DIGEST_SIZE,
+ .init = ghash_init,
+ .update = ghash_update,
+ .final = ghash_final,
+ .setkey = ghash_setkey,
+ .descsize = sizeof(struct ghash_desc_ctx),
+ .base = {
+ .cra_name = "__ghash",
+ .cra_driver_name = "__ghash-pclmulqdqni",
+ .cra_priority = 0,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = GHASH_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct ghash_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(ghash_alg.base.cra_list),
+ },
+};
+
+static int ghash_async_init(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct ahash_request *cryptd_req = ahash_request_ctx(req);
+ struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
+
+ if (irq_fpu_usable()) {
+ memcpy(cryptd_req, req, sizeof(*req));
+ ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
+ return crypto_ahash_init(cryptd_req);
+ } else {
+ struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
+ struct crypto_shash *child = cryptd_ahash_child(cryptd_tfm);
+
+ desc->tfm = child;
+ desc->flags = req->base.flags;
+ return crypto_shash_init(desc);
+ }
+}
+
+static int ghash_async_update(struct ahash_request *req)
+{
+ struct ahash_request *cryptd_req = ahash_request_ctx(req);
+
+ if (irq_fpu_usable()) {
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
+
+ memcpy(cryptd_req, req, sizeof(*req));
+ ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
+ return crypto_ahash_update(cryptd_req);
+ } else {
+ struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
+ return shash_ahash_update(req, desc);
+ }
+}
+
+static int ghash_async_final(struct ahash_request *req)
+{
+ struct ahash_request *cryptd_req = ahash_request_ctx(req);
+
+ if (irq_fpu_usable()) {
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
+
+ memcpy(cryptd_req, req, sizeof(*req));
+ ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
+ return crypto_ahash_final(cryptd_req);
+ } else {
+ struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
+ return crypto_shash_final(desc, req->result);
+ }
+}
+
+static int ghash_async_digest(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct ahash_request *cryptd_req = ahash_request_ctx(req);
+ struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
+
+ if (irq_fpu_usable()) {
+ memcpy(cryptd_req, req, sizeof(*req));
+ ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
+ return crypto_ahash_digest(cryptd_req);
+ } else {
+ struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
+ struct crypto_shash *child = cryptd_ahash_child(cryptd_tfm);
+
+ desc->tfm = child;
+ desc->flags = req->base.flags;
+ return shash_ahash_digest(req, desc);
+ }
+}
+
+static int ghash_async_setkey(struct crypto_ahash *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct crypto_ahash *child = &ctx->cryptd_tfm->base;
+ int err;
+
+ crypto_ahash_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+ crypto_ahash_set_flags(child, crypto_ahash_get_flags(tfm)
+ & CRYPTO_TFM_REQ_MASK);
+ err = crypto_ahash_setkey(child, key, keylen);
+ crypto_ahash_set_flags(tfm, crypto_ahash_get_flags(child)
+ & CRYPTO_TFM_RES_MASK);
+
+ return 0;
+}
+
+static int ghash_async_init_tfm(struct crypto_tfm *tfm)
+{
+ struct cryptd_ahash *cryptd_tfm;
+ struct ghash_async_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ cryptd_tfm = cryptd_alloc_ahash("__ghash-pclmulqdqni", 0, 0);
+ if (IS_ERR(cryptd_tfm))
+ return PTR_ERR(cryptd_tfm);
+ ctx->cryptd_tfm = cryptd_tfm;
+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ sizeof(struct ahash_request) +
+ crypto_ahash_reqsize(&cryptd_tfm->base));
+
+ return 0;
+}
+
+static void ghash_async_exit_tfm(struct crypto_tfm *tfm)
+{
+ struct ghash_async_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ cryptd_free_ahash(ctx->cryptd_tfm);
+}
+
+static struct ahash_alg ghash_async_alg = {
+ .init = ghash_async_init,
+ .update = ghash_async_update,
+ .final = ghash_async_final,
+ .setkey = ghash_async_setkey,
+ .digest = ghash_async_digest,
+ .halg = {
+ .digestsize = GHASH_DIGEST_SIZE,
+ .base = {
+ .cra_name = "ghash",
+ .cra_driver_name = "ghash-clmulni",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = GHASH_BLOCK_SIZE,
+ .cra_type = &crypto_ahash_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(ghash_async_alg.halg.base.cra_list),
+ .cra_init = ghash_async_init_tfm,
+ .cra_exit = ghash_async_exit_tfm,
+ },
+ },
+};
+
+static int __init ghash_pclmulqdqni_mod_init(void)
+{
+ int err;
+
+ if (!cpu_has_pclmulqdq) {
+ printk(KERN_INFO "Intel PCLMULQDQ-NI instructions are not"
+ " detected.\n");
+ return -ENODEV;
+ }
+
+ err = crypto_register_shash(&ghash_alg);
+ if (err)
+ goto err_out;
+ err = crypto_register_ahash(&ghash_async_alg);
+ if (err)
+ goto err_shash;
+
+ return 0;
+
+err_shash:
+ crypto_unregister_shash(&ghash_alg);
+err_out:
+ return err;
+}
+
+static void __exit ghash_pclmulqdqni_mod_exit(void)
+{
+ crypto_unregister_ahash(&ghash_async_alg);
+ crypto_unregister_shash(&ghash_alg);
+}
+
+module_init(ghash_pclmulqdqni_mod_init);
+module_exit(ghash_pclmulqdqni_mod_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("GHASH Message Digest Algorithm, "
+ "acclerated by PCLMULQDQ-NI");
+MODULE_ALIAS("ghash");
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index 1733f9f65e82..d23b98782653 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -204,7 +204,7 @@ sysexit_from_sys_call:
movl RDI-ARGOFFSET(%rsp),%r8d /* reload 5th syscall arg */
.endm
- .macro auditsys_exit exit,ebpsave=RBP
+ .macro auditsys_exit exit
testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),TI_flags(%r10)
jnz ia32_ret_from_sys_call
TRACE_IRQS_ON
@@ -217,7 +217,6 @@ sysexit_from_sys_call:
call audit_syscall_exit
GET_THREAD_INFO(%r10)
movl RAX-ARGOFFSET(%rsp),%eax /* reload syscall return value */
- movl \ebpsave-ARGOFFSET(%rsp),%ebp /* reload user register value */
movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),%edi
cli
TRACE_IRQS_OFF
@@ -351,7 +350,7 @@ cstar_auditsys:
jmp cstar_dispatch
sysretl_audit:
- auditsys_exit sysretl_from_sys_call, RCX /* user %ebp in RCX slot */
+ auditsys_exit sysretl_from_sys_call
#endif
cstar_tracesys:
@@ -842,4 +841,5 @@ ia32_sys_call_table:
.quad compat_sys_pwritev
.quad compat_sys_rt_tgsigqueueinfo /* 335 */
.quad sys_perf_event_open
+ .quad compat_sys_recvmmsg
ia32_syscall_end:
diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h
index 4518dc500903..e3d4a0daff57 100644
--- a/arch/x86/include/asm/acpi.h
+++ b/arch/x86/include/asm/acpi.h
@@ -158,6 +158,7 @@ struct bootnode;
#ifdef CONFIG_ACPI_NUMA
extern int acpi_numa;
+extern int acpi_get_nodes(struct bootnode *physnodes);
extern int acpi_scan_nodes(unsigned long start, unsigned long end);
#define NR_NODE_MEMBLKS (MAX_NUMNODES*2)
extern void acpi_fake_nodes(const struct bootnode *fake_nodes,
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 474d80d3e6cc..08a5f420e07b 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -488,6 +488,8 @@ static inline unsigned int read_apic_id(void)
extern void default_setup_apic_routing(void);
+extern struct apic apic_noop;
+
#ifdef CONFIG_X86_32
extern struct apic apic_default;
diff --git a/arch/x86/include/asm/asm-offsets.h b/arch/x86/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/x86/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/x86/include/asm/cmpxchg_32.h b/arch/x86/include/asm/cmpxchg_32.h
index ee1931be6593..ffb9bb6b6c37 100644
--- a/arch/x86/include/asm/cmpxchg_32.h
+++ b/arch/x86/include/asm/cmpxchg_32.h
@@ -8,14 +8,50 @@
* you need to test for the feature in boot_cpu_data.
*/
-#define xchg(ptr, v) \
- ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), sizeof(*(ptr))))
+extern void __xchg_wrong_size(void);
+
+/*
+ * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
+ * Note 2: xchg has side effect, so that attribute volatile is necessary,
+ * but generally the primitive is invalid, *ptr is output argument. --ANK
+ */
struct __xchg_dummy {
unsigned long a[100];
};
#define __xg(x) ((struct __xchg_dummy *)(x))
+#define __xchg(x, ptr, size) \
+({ \
+ __typeof(*(ptr)) __x = (x); \
+ switch (size) { \
+ case 1: \
+ asm volatile("xchgb %b0,%1" \
+ : "=q" (__x) \
+ : "m" (*__xg(ptr)), "0" (__x) \
+ : "memory"); \
+ break; \
+ case 2: \
+ asm volatile("xchgw %w0,%1" \
+ : "=r" (__x) \
+ : "m" (*__xg(ptr)), "0" (__x) \
+ : "memory"); \
+ break; \
+ case 4: \
+ asm volatile("xchgl %0,%1" \
+ : "=r" (__x) \
+ : "m" (*__xg(ptr)), "0" (__x) \
+ : "memory"); \
+ break; \
+ default: \
+ __xchg_wrong_size(); \
+ } \
+ __x; \
+})
+
+#define xchg(ptr, v) \
+ __xchg((v), (ptr), sizeof(*ptr))
+
/*
* The semantics of XCHGCMP8B are a bit strange, this is why
* there is a loop and the loading of %%eax and %%edx has to
@@ -71,57 +107,63 @@ static inline void __set_64bit_var(unsigned long long *ptr,
(unsigned int)((value) >> 32)) \
: __set_64bit(ptr, ll_low((value)), ll_high((value))))
-/*
- * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
- * Note 2: xchg has side effect, so that attribute volatile is necessary,
- * but generally the primitive is invalid, *ptr is output argument. --ANK
- */
-static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
- int size)
-{
- switch (size) {
- case 1:
- asm volatile("xchgb %b0,%1"
- : "=q" (x)
- : "m" (*__xg(ptr)), "0" (x)
- : "memory");
- break;
- case 2:
- asm volatile("xchgw %w0,%1"
- : "=r" (x)
- : "m" (*__xg(ptr)), "0" (x)
- : "memory");
- break;
- case 4:
- asm volatile("xchgl %0,%1"
- : "=r" (x)
- : "m" (*__xg(ptr)), "0" (x)
- : "memory");
- break;
- }
- return x;
-}
+extern void __cmpxchg_wrong_size(void);
/*
* Atomic compare and exchange. Compare OLD with MEM, if identical,
* store NEW in MEM. Return the initial value in MEM. Success is
* indicated by comparing RETURN with OLD.
*/
+#define __raw_cmpxchg(ptr, old, new, size, lock) \
+({ \
+ __typeof__(*(ptr)) __ret; \
+ __typeof__(*(ptr)) __old = (old); \
+ __typeof__(*(ptr)) __new = (new); \
+ switch (size) { \
+ case 1: \
+ asm volatile(lock "cmpxchgb %b1,%2" \
+ : "=a"(__ret) \
+ : "q"(__new), "m"(*__xg(ptr)), "0"(__old) \
+ : "memory"); \
+ break; \
+ case 2: \
+ asm volatile(lock "cmpxchgw %w1,%2" \
+ : "=a"(__ret) \
+ : "r"(__new), "m"(*__xg(ptr)), "0"(__old) \
+ : "memory"); \
+ break; \
+ case 4: \
+ asm volatile(lock "cmpxchgl %1,%2" \
+ : "=a"(__ret) \
+ : "r"(__new), "m"(*__xg(ptr)), "0"(__old) \
+ : "memory"); \
+ break; \
+ default: \
+ __cmpxchg_wrong_size(); \
+ } \
+ __ret; \
+})
+
+#define __cmpxchg(ptr, old, new, size) \
+ __raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)
+
+#define __sync_cmpxchg(ptr, old, new, size) \
+ __raw_cmpxchg((ptr), (old), (new), (size), "lock; ")
+
+#define __cmpxchg_local(ptr, old, new, size) \
+ __raw_cmpxchg((ptr), (old), (new), (size), "")
#ifdef CONFIG_X86_CMPXCHG
#define __HAVE_ARCH_CMPXCHG 1
-#define cmpxchg(ptr, o, n) \
- ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), \
- (unsigned long)(n), \
- sizeof(*(ptr))))
-#define sync_cmpxchg(ptr, o, n) \
- ((__typeof__(*(ptr)))__sync_cmpxchg((ptr), (unsigned long)(o), \
- (unsigned long)(n), \
- sizeof(*(ptr))))
-#define cmpxchg_local(ptr, o, n) \
- ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \
- (unsigned long)(n), \
- sizeof(*(ptr))))
+
+#define cmpxchg(ptr, old, new) \
+ __cmpxchg((ptr), (old), (new), sizeof(*ptr))
+
+#define sync_cmpxchg(ptr, old, new) \
+ __sync_cmpxchg((ptr), (old), (new), sizeof(*ptr))
+
+#define cmpxchg_local(ptr, old, new) \
+ __cmpxchg_local((ptr), (old), (new), sizeof(*ptr))
#endif
#ifdef CONFIG_X86_CMPXCHG64
@@ -133,94 +175,6 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
(unsigned long long)(n)))
#endif
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
- unsigned long new, int size)
-{
- unsigned long prev;
- switch (size) {
- case 1:
- asm volatile(LOCK_PREFIX "cmpxchgb %b1,%2"
- : "=a"(prev)
- : "q"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 2:
- asm volatile(LOCK_PREFIX "cmpxchgw %w1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 4:
- asm volatile(LOCK_PREFIX "cmpxchgl %1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- }
- return old;
-}
-
-/*
- * Always use locked operations when touching memory shared with a
- * hypervisor, since the system may be SMP even if the guest kernel
- * isn't.
- */
-static inline unsigned long __sync_cmpxchg(volatile void *ptr,
- unsigned long old,
- unsigned long new, int size)
-{
- unsigned long prev;
- switch (size) {
- case 1:
- asm volatile("lock; cmpxchgb %b1,%2"
- : "=a"(prev)
- : "q"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 2:
- asm volatile("lock; cmpxchgw %w1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 4:
- asm volatile("lock; cmpxchgl %1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- }
- return old;
-}
-
-static inline unsigned long __cmpxchg_local(volatile void *ptr,
- unsigned long old,
- unsigned long new, int size)
-{
- unsigned long prev;
- switch (size) {
- case 1:
- asm volatile("cmpxchgb %b1,%2"
- : "=a"(prev)
- : "q"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 2:
- asm volatile("cmpxchgw %w1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 4:
- asm volatile("cmpxchgl %1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- }
- return old;
-}
-
static inline unsigned long long __cmpxchg64(volatile void *ptr,
unsigned long long old,
unsigned long long new)
diff --git a/arch/x86/include/asm/cmpxchg_64.h b/arch/x86/include/asm/cmpxchg_64.h
index 52de72e0de8c..485ae415faec 100644
--- a/arch/x86/include/asm/cmpxchg_64.h
+++ b/arch/x86/include/asm/cmpxchg_64.h
@@ -3,9 +3,6 @@
#include <asm/alternative.h> /* Provides LOCK_PREFIX */
-#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), \
- (ptr), sizeof(*(ptr))))
-
#define __xg(x) ((volatile long *)(x))
static inline void set_64bit(volatile unsigned long *ptr, unsigned long val)
@@ -15,167 +12,118 @@ static inline void set_64bit(volatile unsigned long *ptr, unsigned long val)
#define _set_64bit set_64bit
+extern void __xchg_wrong_size(void);
+extern void __cmpxchg_wrong_size(void);
+
/*
* Note: no "lock" prefix even on SMP: xchg always implies lock anyway
* Note 2: xchg has side effect, so that attribute volatile is necessary,
* but generally the primitive is invalid, *ptr is output argument. --ANK
*/
-static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
- int size)
-{
- switch (size) {
- case 1:
- asm volatile("xchgb %b0,%1"
- : "=q" (x)
- : "m" (*__xg(ptr)), "0" (x)
- : "memory");
- break;
- case 2:
- asm volatile("xchgw %w0,%1"
- : "=r" (x)
- : "m" (*__xg(ptr)), "0" (x)
- : "memory");
- break;
- case 4:
- asm volatile("xchgl %k0,%1"
- : "=r" (x)
- : "m" (*__xg(ptr)), "0" (x)
- : "memory");
- break;
- case 8:
- asm volatile("xchgq %0,%1"
- : "=r" (x)
- : "m" (*__xg(ptr)), "0" (x)
- : "memory");
- break;
- }
- return x;
-}
+#define __xchg(x, ptr, size) \
+({ \
+ __typeof(*(ptr)) __x = (x); \
+ switch (size) { \
+ case 1: \
+ asm volatile("xchgb %b0,%1" \
+ : "=q" (__x) \
+ : "m" (*__xg(ptr)), "0" (__x) \
+ : "memory"); \
+ break; \
+ case 2: \
+ asm volatile("xchgw %w0,%1" \
+ : "=r" (__x) \
+ : "m" (*__xg(ptr)), "0" (__x) \
+ : "memory"); \
+ break; \
+ case 4: \
+ asm volatile("xchgl %k0,%1" \
+ : "=r" (__x) \
+ : "m" (*__xg(ptr)), "0" (__x) \
+ : "memory"); \
+ break; \
+ case 8: \
+ asm volatile("xchgq %0,%1" \
+ : "=r" (__x) \
+ : "m" (*__xg(ptr)), "0" (__x) \
+ : "memory"); \
+ break; \
+ default: \
+ __xchg_wrong_size(); \
+ } \
+ __x; \
+})
+
+#define xchg(ptr, v) \
+ __xchg((v), (ptr), sizeof(*ptr))
+
+#define __HAVE_ARCH_CMPXCHG 1
/*
* Atomic compare and exchange. Compare OLD with MEM, if identical,
* store NEW in MEM. Return the initial value in MEM. Success is
* indicated by comparing RETURN with OLD.
*/
+#define __raw_cmpxchg(ptr, old, new, size, lock) \
+({ \
+ __typeof__(*(ptr)) __ret; \
+ __typeof__(*(ptr)) __old = (old); \
+ __typeof__(*(ptr)) __new = (new); \
+ switch (size) { \
+ case 1: \
+ asm volatile(lock "cmpxchgb %b1,%2" \
+ : "=a"(__ret) \
+ : "q"(__new), "m"(*__xg(ptr)), "0"(__old) \
+ : "memory"); \
+ break; \
+ case 2: \
+ asm volatile(lock "cmpxchgw %w1,%2" \
+ : "=a"(__ret) \
+ : "r"(__new), "m"(*__xg(ptr)), "0"(__old) \
+ : "memory"); \
+ break; \
+ case 4: \
+ asm volatile(lock "cmpxchgl %k1,%2" \
+ : "=a"(__ret) \
+ : "r"(__new), "m"(*__xg(ptr)), "0"(__old) \
+ : "memory"); \
+ break; \
+ case 8: \
+ asm volatile(lock "cmpxchgq %1,%2" \
+ : "=a"(__ret) \
+ : "r"(__new), "m"(*__xg(ptr)), "0"(__old) \
+ : "memory"); \
+ break; \
+ default: \
+ __cmpxchg_wrong_size(); \
+ } \
+ __ret; \
+})
-#define __HAVE_ARCH_CMPXCHG 1
+#define __cmpxchg(ptr, old, new, size) \
+ __raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
- unsigned long new, int size)
-{
- unsigned long prev;
- switch (size) {
- case 1:
- asm volatile(LOCK_PREFIX "cmpxchgb %b1,%2"
- : "=a"(prev)
- : "q"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 2:
- asm volatile(LOCK_PREFIX "cmpxchgw %w1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 4:
- asm volatile(LOCK_PREFIX "cmpxchgl %k1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 8:
- asm volatile(LOCK_PREFIX "cmpxchgq %1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- }
- return old;
-}
+#define __sync_cmpxchg(ptr, old, new, size) \
+ __raw_cmpxchg((ptr), (old), (new), (size), "lock; ")
-/*
- * Always use locked operations when touching memory shared with a
- * hypervisor, since the system may be SMP even if the guest kernel
- * isn't.
- */
-static inline unsigned long __sync_cmpxchg(volatile void *ptr,
- unsigned long old,
- unsigned long new, int size)
-{
- unsigned long prev;
- switch (size) {
- case 1:
- asm volatile("lock; cmpxchgb %b1,%2"
- : "=a"(prev)
- : "q"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 2:
- asm volatile("lock; cmpxchgw %w1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 4:
- asm volatile("lock; cmpxchgl %1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- }
- return old;
-}
+#define __cmpxchg_local(ptr, old, new, size) \
+ __raw_cmpxchg((ptr), (old), (new), (size), "")
-static inline unsigned long __cmpxchg_local(volatile void *ptr,
- unsigned long old,
- unsigned long new, int size)
-{
- unsigned long prev;
- switch (size) {
- case 1:
- asm volatile("cmpxchgb %b1,%2"
- : "=a"(prev)
- : "q"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 2:
- asm volatile("cmpxchgw %w1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 4:
- asm volatile("cmpxchgl %k1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 8:
- asm volatile("cmpxchgq %1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- }
- return old;
-}
+#define cmpxchg(ptr, old, new) \
+ __cmpxchg((ptr), (old), (new), sizeof(*ptr))
+
+#define sync_cmpxchg(ptr, old, new) \
+ __sync_cmpxchg((ptr), (old), (new), sizeof(*ptr))
+
+#define cmpxchg_local(ptr, old, new) \
+ __cmpxchg_local((ptr), (old), (new), sizeof(*ptr))
-#define cmpxchg(ptr, o, n) \
- ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), \
- (unsigned long)(n), sizeof(*(ptr))))
#define cmpxchg64(ptr, o, n) \
({ \
BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
cmpxchg((ptr), (o), (n)); \
})
-#define cmpxchg_local(ptr, o, n) \
- ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \
- (unsigned long)(n), \
- sizeof(*(ptr))))
-#define sync_cmpxchg(ptr, o, n) \
- ((__typeof__(*(ptr)))__sync_cmpxchg((ptr), (unsigned long)(o), \
- (unsigned long)(n), \
- sizeof(*(ptr))))
+
#define cmpxchg64_local(ptr, o, n) \
({ \
BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 9cfc88b97742..613700f27a4a 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -248,6 +248,7 @@ extern const char * const x86_power_flags[32];
#define cpu_has_x2apic boot_cpu_has(X86_FEATURE_X2APIC)
#define cpu_has_xsave boot_cpu_has(X86_FEATURE_XSAVE)
#define cpu_has_hypervisor boot_cpu_has(X86_FEATURE_HYPERVISOR)
+#define cpu_has_pclmulqdq boot_cpu_has(X86_FEATURE_PCLMULQDQ)
#if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64)
# define cpu_has_invlpg 1
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index 456a304b8172..8a024babe5e6 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -157,19 +157,6 @@ do { \
#define compat_elf_check_arch(x) elf_check_arch_ia32(x)
-static inline void start_ia32_thread(struct pt_regs *regs, u32 ip, u32 sp)
-{
- loadsegment(fs, 0);
- loadsegment(ds, __USER32_DS);
- loadsegment(es, __USER32_DS);
- load_gs_index(0);
- regs->ip = ip;
- regs->sp = sp;
- regs->flags = X86_EFLAGS_IF;
- regs->cs = __USER32_CS;
- regs->ss = __USER32_DS;
-}
-
static inline void elf_common_init(struct thread_struct *t,
struct pt_regs *regs, const u16 ds)
{
@@ -191,11 +178,8 @@ do { \
#define COMPAT_ELF_PLAT_INIT(regs, load_addr) \
elf_common_init(&current->thread, regs, __USER_DS)
-#define compat_start_thread(regs, ip, sp) \
-do { \
- start_ia32_thread(regs, ip, sp); \
- set_fs(USER_DS); \
-} while (0)
+void start_thread_ia32(struct pt_regs *regs, u32 new_ip, u32 new_sp);
+#define compat_start_thread start_thread_ia32
#define COMPAT_SET_PERSONALITY(ex) \
do { \
diff --git a/arch/x86/include/asm/entry_arch.h b/arch/x86/include/asm/entry_arch.h
index f5693c81a1db..8e8ec663a98f 100644
--- a/arch/x86/include/asm/entry_arch.h
+++ b/arch/x86/include/asm/entry_arch.h
@@ -34,7 +34,7 @@ BUILD_INTERRUPT3(invalidate_interrupt7,INVALIDATE_TLB_VECTOR_START+7,
smp_invalidate_interrupt)
#endif
-BUILD_INTERRUPT(generic_interrupt, GENERIC_INTERRUPT_VECTOR)
+BUILD_INTERRUPT(x86_platform_ipi, X86_PLATFORM_IPI_VECTOR)
/*
* every pentium local APIC has two 'local interrupts', with a
diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h
index 82e3e8f01043..beaabd794a10 100644
--- a/arch/x86/include/asm/hardirq.h
+++ b/arch/x86/include/asm/hardirq.h
@@ -12,7 +12,7 @@ typedef struct {
unsigned int apic_timer_irqs; /* arch dependent */
unsigned int irq_spurious_count;
#endif
- unsigned int generic_irqs; /* arch dependent */
+ unsigned int x86_platform_ipis; /* arch dependent */
unsigned int apic_perf_irqs;
unsigned int apic_pending_irqs;
#ifdef CONFIG_SMP
diff --git a/arch/x86/include/asm/hpet.h b/arch/x86/include/asm/hpet.h
index 1c22cb05ad6a..5d89fd2a3690 100644
--- a/arch/x86/include/asm/hpet.h
+++ b/arch/x86/include/asm/hpet.h
@@ -65,11 +65,12 @@
/* hpet memory map physical address */
extern unsigned long hpet_address;
extern unsigned long force_hpet_address;
+extern u8 hpet_blockid;
extern int hpet_force_user;
extern int is_hpet_enabled(void);
extern int hpet_enable(void);
extern void hpet_disable(void);
-extern unsigned long hpet_readl(unsigned long a);
+extern unsigned int hpet_readl(unsigned int a);
extern void force_hpet_resume(void);
extern void hpet_msi_unmask(unsigned int irq);
@@ -78,9 +79,9 @@ extern void hpet_msi_write(unsigned int irq, struct msi_msg *msg);
extern void hpet_msi_read(unsigned int irq, struct msi_msg *msg);
#ifdef CONFIG_PCI_MSI
-extern int arch_setup_hpet_msi(unsigned int irq);
+extern int arch_setup_hpet_msi(unsigned int irq, unsigned int id);
#else
-static inline int arch_setup_hpet_msi(unsigned int irq)
+static inline int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
{
return -EINVAL;
}
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
index ba180d93b08c..f44e3aa3c574 100644
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -27,7 +27,7 @@
/* Interrupt handlers registered during init_IRQ */
extern void apic_timer_interrupt(void);
-extern void generic_interrupt(void);
+extern void x86_platform_ipi(void);
extern void error_interrupt(void);
extern void perf_pending_interrupt(void);
@@ -79,14 +79,33 @@ static inline void set_io_apic_irq_attr(struct io_apic_irq_attr *irq_attr,
int ioapic, int ioapic_pin,
int trigger, int polarity)
{
- irq_attr->ioapic = ioapic;
- irq_attr->ioapic_pin = ioapic_pin;
- irq_attr->trigger = trigger;
- irq_attr->polarity = polarity;
+ irq_attr->ioapic = ioapic;
+ irq_attr->ioapic_pin = ioapic_pin;
+ irq_attr->trigger = trigger;
+ irq_attr->polarity = polarity;
}
-extern int IO_APIC_get_PCI_irq_vector(int bus, int devfn, int pin,
- struct io_apic_irq_attr *irq_attr);
+/*
+ * This is performance-critical, we want to do it O(1)
+ *
+ * Most irqs are mapped 1:1 with pins.
+ */
+struct irq_cfg {
+ struct irq_pin_list *irq_2_pin;
+ cpumask_var_t domain;
+ cpumask_var_t old_domain;
+ unsigned move_cleanup_count;
+ u8 vector;
+ u8 move_in_progress : 1;
+};
+
+extern struct irq_cfg *irq_cfg(unsigned int);
+extern int assign_irq_vector(int, struct irq_cfg *, const struct cpumask *);
+extern void send_cleanup_vector(struct irq_cfg *);
+
+struct irq_desc;
+extern unsigned int set_desc_affinity(struct irq_desc *, const struct cpumask *);
+extern int IO_APIC_get_PCI_irq_vector(int bus, int devfn, int pin, struct io_apic_irq_attr *irq_attr);
extern void setup_ioapic_dest(void);
extern void enable_IO_APIC(void);
@@ -101,7 +120,7 @@ extern void eisa_set_level_irq(unsigned int irq);
/* SMP */
extern void smp_apic_timer_interrupt(struct pt_regs *);
extern void smp_spurious_interrupt(struct pt_regs *);
-extern void smp_generic_interrupt(struct pt_regs *);
+extern void smp_x86_platform_ipi(struct pt_regs *);
extern void smp_error_interrupt(struct pt_regs *);
#ifdef CONFIG_X86_IO_APIC
extern asmlinkage void smp_irq_move_cleanup_interrupt(void);
diff --git a/arch/x86/include/asm/inat.h b/arch/x86/include/asm/inat.h
new file mode 100644
index 000000000000..2866fddd1848
--- /dev/null
+++ b/arch/x86/include/asm/inat.h
@@ -0,0 +1,188 @@
+#ifndef _ASM_X86_INAT_H
+#define _ASM_X86_INAT_H
+/*
+ * x86 instruction attributes
+ *
+ * Written by Masami Hiramatsu <mhiramat@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 <asm/inat_types.h>
+
+/*
+ * Internal bits. Don't use bitmasks directly, because these bits are
+ * unstable. You should use checking functions.
+ */
+
+#define INAT_OPCODE_TABLE_SIZE 256
+#define INAT_GROUP_TABLE_SIZE 8
+
+/* Legacy instruction prefixes */
+#define INAT_PFX_OPNDSZ 1 /* 0x66 */ /* LPFX1 */
+#define INAT_PFX_REPNE 2 /* 0xF2 */ /* LPFX2 */
+#define INAT_PFX_REPE 3 /* 0xF3 */ /* LPFX3 */
+#define INAT_PFX_LOCK 4 /* 0xF0 */
+#define INAT_PFX_CS 5 /* 0x2E */
+#define INAT_PFX_DS 6 /* 0x3E */
+#define INAT_PFX_ES 7 /* 0x26 */
+#define INAT_PFX_FS 8 /* 0x64 */
+#define INAT_PFX_GS 9 /* 0x65 */
+#define INAT_PFX_SS 10 /* 0x36 */
+#define INAT_PFX_ADDRSZ 11 /* 0x67 */
+
+#define INAT_LPREFIX_MAX 3
+
+/* Immediate size */
+#define INAT_IMM_BYTE 1
+#define INAT_IMM_WORD 2
+#define INAT_IMM_DWORD 3
+#define INAT_IMM_QWORD 4
+#define INAT_IMM_PTR 5
+#define INAT_IMM_VWORD32 6
+#define INAT_IMM_VWORD 7
+
+/* Legacy prefix */
+#define INAT_PFX_OFFS 0
+#define INAT_PFX_BITS 4
+#define INAT_PFX_MAX ((1 << INAT_PFX_BITS) - 1)
+#define INAT_PFX_MASK (INAT_PFX_MAX << INAT_PFX_OFFS)
+/* Escape opcodes */
+#define INAT_ESC_OFFS (INAT_PFX_OFFS + INAT_PFX_BITS)
+#define INAT_ESC_BITS 2
+#define INAT_ESC_MAX ((1 << INAT_ESC_BITS) - 1)
+#define INAT_ESC_MASK (INAT_ESC_MAX << INAT_ESC_OFFS)
+/* Group opcodes (1-16) */
+#define INAT_GRP_OFFS (INAT_ESC_OFFS + INAT_ESC_BITS)
+#define INAT_GRP_BITS 5
+#define INAT_GRP_MAX ((1 << INAT_GRP_BITS) - 1)
+#define INAT_GRP_MASK (INAT_GRP_MAX << INAT_GRP_OFFS)
+/* Immediates */
+#define INAT_IMM_OFFS (INAT_GRP_OFFS + INAT_GRP_BITS)
+#define INAT_IMM_BITS 3
+#define INAT_IMM_MASK (((1 << INAT_IMM_BITS) - 1) << INAT_IMM_OFFS)
+/* Flags */
+#define INAT_FLAG_OFFS (INAT_IMM_OFFS + INAT_IMM_BITS)
+#define INAT_REXPFX (1 << INAT_FLAG_OFFS)
+#define INAT_MODRM (1 << (INAT_FLAG_OFFS + 1))
+#define INAT_FORCE64 (1 << (INAT_FLAG_OFFS + 2))
+#define INAT_SCNDIMM (1 << (INAT_FLAG_OFFS + 3))
+#define INAT_MOFFSET (1 << (INAT_FLAG_OFFS + 4))
+#define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 5))
+/* Attribute making macros for attribute tables */
+#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS)
+#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS)
+#define INAT_MAKE_GROUP(grp) ((grp << INAT_GRP_OFFS) | INAT_MODRM)
+#define INAT_MAKE_IMM(imm) (imm << INAT_IMM_OFFS)
+
+/* Attribute search APIs */
+extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode);
+extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode,
+ insn_byte_t last_pfx,
+ insn_attr_t esc_attr);
+extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm,
+ insn_byte_t last_pfx,
+ insn_attr_t esc_attr);
+
+/* Attribute checking functions */
+static inline int inat_is_prefix(insn_attr_t attr)
+{
+ return attr & INAT_PFX_MASK;
+}
+
+static inline int inat_is_address_size_prefix(insn_attr_t attr)
+{
+ return (attr & INAT_PFX_MASK) == INAT_PFX_ADDRSZ;
+}
+
+static inline int inat_is_operand_size_prefix(insn_attr_t attr)
+{
+ return (attr & INAT_PFX_MASK) == INAT_PFX_OPNDSZ;
+}
+
+static inline int inat_last_prefix_id(insn_attr_t attr)
+{
+ if ((attr & INAT_PFX_MASK) > INAT_LPREFIX_MAX)
+ return 0;
+ else
+ return attr & INAT_PFX_MASK;
+}
+
+static inline int inat_is_escape(insn_attr_t attr)
+{
+ return attr & INAT_ESC_MASK;
+}
+
+static inline int inat_escape_id(insn_attr_t attr)
+{
+ return (attr & INAT_ESC_MASK) >> INAT_ESC_OFFS;
+}
+
+static inline int inat_is_group(insn_attr_t attr)
+{
+ return attr & INAT_GRP_MASK;
+}
+
+static inline int inat_group_id(insn_attr_t attr)
+{
+ return (attr & INAT_GRP_MASK) >> INAT_GRP_OFFS;
+}
+
+static inline int inat_group_common_attribute(insn_attr_t attr)
+{
+ return attr & ~INAT_GRP_MASK;
+}
+
+static inline int inat_has_immediate(insn_attr_t attr)
+{
+ return attr & INAT_IMM_MASK;
+}
+
+static inline int inat_immediate_size(insn_attr_t attr)
+{
+ return (attr & INAT_IMM_MASK) >> INAT_IMM_OFFS;
+}
+
+static inline int inat_is_rex_prefix(insn_attr_t attr)
+{
+ return attr & INAT_REXPFX;
+}
+
+static inline int inat_has_modrm(insn_attr_t attr)
+{
+ return attr & INAT_MODRM;
+}
+
+static inline int inat_is_force64(insn_attr_t attr)
+{
+ return attr & INAT_FORCE64;
+}
+
+static inline int inat_has_second_immediate(insn_attr_t attr)
+{
+ return attr & INAT_SCNDIMM;
+}
+
+static inline int inat_has_moffset(insn_attr_t attr)
+{
+ return attr & INAT_MOFFSET;
+}
+
+static inline int inat_has_variant(insn_attr_t attr)
+{
+ return attr & INAT_VARIANT;
+}
+
+#endif
diff --git a/arch/x86/include/asm/inat_types.h b/arch/x86/include/asm/inat_types.h
new file mode 100644
index 000000000000..cb3c20ce39cf
--- /dev/null
+++ b/arch/x86/include/asm/inat_types.h
@@ -0,0 +1,29 @@
+#ifndef _ASM_X86_INAT_TYPES_H
+#define _ASM_X86_INAT_TYPES_H
+/*
+ * x86 instruction attributes
+ *
+ * Written by Masami Hiramatsu <mhiramat@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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.
+ *
+ */
+
+/* Instruction attributes */
+typedef unsigned int insn_attr_t;
+typedef unsigned char insn_byte_t;
+typedef signed int insn_value_t;
+
+#endif
diff --git a/arch/x86/include/asm/insn.h b/arch/x86/include/asm/insn.h
new file mode 100644
index 000000000000..12b4e3751d3f
--- /dev/null
+++ b/arch/x86/include/asm/insn.h
@@ -0,0 +1,143 @@
+#ifndef _ASM_X86_INSN_H
+#define _ASM_X86_INSN_H
+/*
+ * x86 instruction analysis
+ *
+ * This 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, 2009
+ */
+
+/* insn_attr_t is defined in inat.h */
+#include <asm/inat.h>
+
+struct insn_field {
+ union {
+ insn_value_t value;
+ insn_byte_t bytes[4];
+ };
+ /* !0 if we've run insn_get_xxx() for this field */
+ unsigned char got;
+ unsigned char nbytes;
+};
+
+struct insn {
+ struct insn_field prefixes; /*
+ * Prefixes
+ * prefixes.bytes[3]: last prefix
+ */
+ struct insn_field rex_prefix; /* REX prefix */
+ struct insn_field opcode; /*
+ * opcode.bytes[0]: opcode1
+ * opcode.bytes[1]: opcode2
+ * opcode.bytes[2]: opcode3
+ */
+ struct insn_field modrm;
+ struct insn_field sib;
+ struct insn_field displacement;
+ union {
+ struct insn_field immediate;
+ struct insn_field moffset1; /* for 64bit MOV */
+ struct insn_field immediate1; /* for 64bit imm or off16/32 */
+ };
+ union {
+ struct insn_field moffset2; /* for 64bit MOV */
+ struct insn_field immediate2; /* for 64bit imm or seg16 */
+ };
+
+ insn_attr_t attr;
+ unsigned char opnd_bytes;
+ unsigned char addr_bytes;
+ unsigned char length;
+ unsigned char x86_64;
+
+ const insn_byte_t *kaddr; /* kernel address of insn to analyze */
+ const insn_byte_t *next_byte;
+};
+
+#define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6)
+#define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3)
+#define X86_MODRM_RM(modrm) ((modrm) & 0x07)
+
+#define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6)
+#define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3)
+#define X86_SIB_BASE(sib) ((sib) & 0x07)
+
+#define X86_REX_W(rex) ((rex) & 8)
+#define X86_REX_R(rex) ((rex) & 4)
+#define X86_REX_X(rex) ((rex) & 2)
+#define X86_REX_B(rex) ((rex) & 1)
+
+/* The last prefix is needed for two-byte and three-byte opcodes */
+static inline insn_byte_t insn_last_prefix(struct insn *insn)
+{
+ return insn->prefixes.bytes[3];
+}
+
+extern void insn_init(struct insn *insn, const void *kaddr, int x86_64);
+extern void insn_get_prefixes(struct insn *insn);
+extern void insn_get_opcode(struct insn *insn);
+extern void insn_get_modrm(struct insn *insn);
+extern void insn_get_sib(struct insn *insn);
+extern void insn_get_displacement(struct insn *insn);
+extern void insn_get_immediate(struct insn *insn);
+extern void insn_get_length(struct insn *insn);
+
+/* Attribute will be determined after getting ModRM (for opcode groups) */
+static inline void insn_get_attribute(struct insn *insn)
+{
+ insn_get_modrm(insn);
+}
+
+/* Instruction uses RIP-relative addressing */
+extern int insn_rip_relative(struct insn *insn);
+
+/* Init insn for kernel text */
+static inline void kernel_insn_init(struct insn *insn, const void *kaddr)
+{
+#ifdef CONFIG_X86_64
+ insn_init(insn, kaddr, 1);
+#else /* CONFIG_X86_32 */
+ insn_init(insn, kaddr, 0);
+#endif
+}
+
+/* Offset of each field from kaddr */
+static inline int insn_offset_rex_prefix(struct insn *insn)
+{
+ return insn->prefixes.nbytes;
+}
+static inline int insn_offset_opcode(struct insn *insn)
+{
+ return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes;
+}
+static inline int insn_offset_modrm(struct insn *insn)
+{
+ return insn_offset_opcode(insn) + insn->opcode.nbytes;
+}
+static inline int insn_offset_sib(struct insn *insn)
+{
+ return insn_offset_modrm(insn) + insn->modrm.nbytes;
+}
+static inline int insn_offset_displacement(struct insn *insn)
+{
+ return insn_offset_sib(insn) + insn->sib.nbytes;
+}
+static inline int insn_offset_immediate(struct insn *insn)
+{
+ return insn_offset_displacement(insn) + insn->displacement.nbytes;
+}
+
+#endif /* _ASM_X86_INSN_H */
diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h
index ddda6cbed6f4..fcbc6d144501 100644
--- a/arch/x86/include/asm/irq.h
+++ b/arch/x86/include/asm/irq.h
@@ -36,7 +36,7 @@ static inline int irq_canonicalize(int irq)
extern void fixup_irqs(void);
#endif
-extern void (*generic_interrupt_extension)(void);
+extern void (*x86_platform_ipi_callback)(void);
extern void native_init_IRQ(void);
extern bool handle_irq(unsigned irq, struct pt_regs *regs);
diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h
index 5b21f0ec3df2..6a635bd39867 100644
--- a/arch/x86/include/asm/irq_vectors.h
+++ b/arch/x86/include/asm/irq_vectors.h
@@ -106,7 +106,7 @@
/*
* Generic system vector for platform specific use
*/
-#define GENERIC_INTERRUPT_VECTOR 0xed
+#define X86_PLATFORM_IPI_VECTOR 0xed
/*
* Performance monitoring pending work vector:
diff --git a/arch/x86/include/asm/k8.h b/arch/x86/include/asm/k8.h
index c2d1f3b58e5f..c092f720bd60 100644
--- a/arch/x86/include/asm/k8.h
+++ b/arch/x86/include/asm/k8.h
@@ -10,7 +10,9 @@ extern struct pci_dev **k8_northbridges;
extern int num_k8_northbridges;
extern int cache_k8_northbridges(void);
extern void k8_flush_garts(void);
-extern int k8_scan_nodes(unsigned long start, unsigned long end);
+extern int k8_get_nodes(struct bootnode *nodes);
+extern int k8_numa_init(unsigned long start_pfn, unsigned long end_pfn);
+extern int k8_scan_nodes(void);
#ifdef CONFIG_K8_NB
static inline struct pci_dev *node_to_k8_nb_misc(int node)
diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h
index 4a5fe914dc59..f02e87a5206f 100644
--- a/arch/x86/include/asm/kvm.h
+++ b/arch/x86/include/asm/kvm.h
@@ -79,6 +79,7 @@ struct kvm_ioapic_state {
#define KVM_IRQCHIP_PIC_MASTER 0
#define KVM_IRQCHIP_PIC_SLAVE 1
#define KVM_IRQCHIP_IOAPIC 2
+#define KVM_NR_IRQCHIPS 3
/* for KVM_GET_REGS and KVM_SET_REGS */
struct kvm_regs {
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index d83892226f73..179a919f53a4 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -397,7 +397,6 @@ struct kvm_arch{
struct kvm_pic *vpic;
struct kvm_ioapic *vioapic;
struct kvm_pit *vpit;
- struct hlist_head irq_ack_notifier_list;
int vapics_in_nmi_mode;
unsigned int tss_addr;
@@ -410,7 +409,6 @@ struct kvm_arch{
gpa_t ept_identity_map_addr;
unsigned long irq_sources_bitmap;
- unsigned long irq_states[KVM_IOAPIC_NUM_PINS];
u64 vm_init_tsc;
};
@@ -461,7 +459,7 @@ struct descriptor_table {
struct kvm_x86_ops {
int (*cpu_has_kvm_support)(void); /* __init */
int (*disabled_by_bios)(void); /* __init */
- void (*hardware_enable)(void *dummy); /* __init */
+ int (*hardware_enable)(void *dummy);
void (*hardware_disable)(void *dummy);
void (*check_processor_compatibility)(void *rtn);
int (*hardware_setup)(void); /* __init */
@@ -477,8 +475,8 @@ struct kvm_x86_ops {
void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu);
void (*vcpu_put)(struct kvm_vcpu *vcpu);
- int (*set_guest_debug)(struct kvm_vcpu *vcpu,
- struct kvm_guest_debug *dbg);
+ void (*set_guest_debug)(struct kvm_vcpu *vcpu,
+ struct kvm_guest_debug *dbg);
int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg);
@@ -506,8 +504,8 @@ struct kvm_x86_ops {
void (*tlb_flush)(struct kvm_vcpu *vcpu);
- void (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
- int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
+ void (*run)(struct kvm_vcpu *vcpu);
+ int (*handle_exit)(struct kvm_vcpu *vcpu);
void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
void (*set_interrupt_shadow)(struct kvm_vcpu *vcpu, int mask);
u32 (*get_interrupt_shadow)(struct kvm_vcpu *vcpu, int mask);
@@ -568,7 +566,7 @@ enum emulation_result {
#define EMULTYPE_NO_DECODE (1 << 0)
#define EMULTYPE_TRAP_UD (1 << 1)
#define EMULTYPE_SKIP (1 << 2)
-int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run,
+int emulate_instruction(struct kvm_vcpu *vcpu,
unsigned long cr2, u16 error_code, int emulation_type);
void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context);
void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
@@ -585,9 +583,9 @@ int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
struct x86_emulate_ctxt;
-int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+int kvm_emulate_pio(struct kvm_vcpu *vcpu, int in,
int size, unsigned port);
-int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in,
int size, unsigned long count, int down,
gva_t address, int rep, unsigned port);
void kvm_emulate_cpuid(struct kvm_vcpu *vcpu);
@@ -616,6 +614,9 @@ void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l);
int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data);
+unsigned long kvm_get_rflags(struct kvm_vcpu *vcpu);
+void kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags);
+
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_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long cr2,
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index f1363b72364f..161485da6838 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -108,6 +108,8 @@ struct mce_log {
#define K8_MCE_THRESHOLD_BANK_5 (MCE_THRESHOLD_BASE + 5 * 9)
#define K8_MCE_THRESHOLD_DRAM_ECC (MCE_THRESHOLD_BANK_4 + 0)
+extern struct atomic_notifier_head x86_mce_decoder_chain;
+
#ifdef __KERNEL__
#include <linux/percpu.h>
@@ -118,9 +120,9 @@ extern int mce_disabled;
extern int mce_p5_enabled;
#ifdef CONFIG_X86_MCE
-void mcheck_init(struct cpuinfo_x86 *c);
+void mcheck_cpu_init(struct cpuinfo_x86 *c);
#else
-static inline void mcheck_init(struct cpuinfo_x86 *c) {}
+static inline void mcheck_cpu_init(struct cpuinfo_x86 *c) {}
#endif
#ifdef CONFIG_X86_ANCIENT_MCE
@@ -213,6 +215,5 @@ extern void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu);
void intel_init_thermal(struct cpuinfo_x86 *c);
void mce_log_therm_throt_event(__u64 status);
-
#endif /* __KERNEL__ */
#endif /* _ASM_X86_MCE_H */
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index 7e2b6ba962ff..9a00219b331a 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -247,8 +247,8 @@ do { \
#ifdef CONFIG_SMP
int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
-void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs);
-void wrmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs);
+void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs);
+void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs);
int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]);
diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h
index 6473f5ccff85..642fe34b36a2 100644
--- a/arch/x86/include/asm/page_types.h
+++ b/arch/x86/include/asm/page_types.h
@@ -49,7 +49,8 @@ extern unsigned long max_pfn_mapped;
extern unsigned long init_memory_mapping(unsigned long start,
unsigned long end);
-extern void initmem_init(unsigned long start_pfn, unsigned long end_pfn);
+extern void initmem_init(unsigned long start_pfn, unsigned long end_pfn,
+ int acpi, int k8);
extern void free_initmem(void);
#endif /* !__ASSEMBLY__ */
diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
index b399988eee3a..e61147fa3b8e 100644
--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -52,6 +52,8 @@ extern int pcibios_last_bus;
extern struct pci_bus *pci_root_bus;
extern struct pci_ops pci_root_ops;
+void pcibios_scan_specific_bus(int busn);
+
/* pci-irq.c */
struct irq_info {
diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h
index b65a36defeb7..8b5ec19bdef4 100644
--- a/arch/x86/include/asm/percpu.h
+++ b/arch/x86/include/asm/percpu.h
@@ -153,6 +153,84 @@ do { \
#define percpu_or(var, val) percpu_to_op("or", per_cpu__##var, val)
#define percpu_xor(var, val) percpu_to_op("xor", per_cpu__##var, val)
+#define __this_cpu_read_1(pcp) percpu_from_op("mov", (pcp), "m"(pcp))
+#define __this_cpu_read_2(pcp) percpu_from_op("mov", (pcp), "m"(pcp))
+#define __this_cpu_read_4(pcp) percpu_from_op("mov", (pcp), "m"(pcp))
+
+#define __this_cpu_write_1(pcp, val) percpu_to_op("mov", (pcp), val)
+#define __this_cpu_write_2(pcp, val) percpu_to_op("mov", (pcp), val)
+#define __this_cpu_write_4(pcp, val) percpu_to_op("mov", (pcp), val)
+#define __this_cpu_add_1(pcp, val) percpu_to_op("add", (pcp), val)
+#define __this_cpu_add_2(pcp, val) percpu_to_op("add", (pcp), val)
+#define __this_cpu_add_4(pcp, val) percpu_to_op("add", (pcp), val)
+#define __this_cpu_and_1(pcp, val) percpu_to_op("and", (pcp), val)
+#define __this_cpu_and_2(pcp, val) percpu_to_op("and", (pcp), val)
+#define __this_cpu_and_4(pcp, val) percpu_to_op("and", (pcp), val)
+#define __this_cpu_or_1(pcp, val) percpu_to_op("or", (pcp), val)
+#define __this_cpu_or_2(pcp, val) percpu_to_op("or", (pcp), val)
+#define __this_cpu_or_4(pcp, val) percpu_to_op("or", (pcp), val)
+#define __this_cpu_xor_1(pcp, val) percpu_to_op("xor", (pcp), val)
+#define __this_cpu_xor_2(pcp, val) percpu_to_op("xor", (pcp), val)
+#define __this_cpu_xor_4(pcp, val) percpu_to_op("xor", (pcp), val)
+
+#define this_cpu_read_1(pcp) percpu_from_op("mov", (pcp), "m"(pcp))
+#define this_cpu_read_2(pcp) percpu_from_op("mov", (pcp), "m"(pcp))
+#define this_cpu_read_4(pcp) percpu_from_op("mov", (pcp), "m"(pcp))
+#define this_cpu_write_1(pcp, val) percpu_to_op("mov", (pcp), val)
+#define this_cpu_write_2(pcp, val) percpu_to_op("mov", (pcp), val)
+#define this_cpu_write_4(pcp, val) percpu_to_op("mov", (pcp), val)
+#define this_cpu_add_1(pcp, val) percpu_to_op("add", (pcp), val)
+#define this_cpu_add_2(pcp, val) percpu_to_op("add", (pcp), val)
+#define this_cpu_add_4(pcp, val) percpu_to_op("add", (pcp), val)
+#define this_cpu_and_1(pcp, val) percpu_to_op("and", (pcp), val)
+#define this_cpu_and_2(pcp, val) percpu_to_op("and", (pcp), val)
+#define this_cpu_and_4(pcp, val) percpu_to_op("and", (pcp), val)
+#define this_cpu_or_1(pcp, val) percpu_to_op("or", (pcp), val)
+#define this_cpu_or_2(pcp, val) percpu_to_op("or", (pcp), val)
+#define this_cpu_or_4(pcp, val) percpu_to_op("or", (pcp), val)
+#define this_cpu_xor_1(pcp, val) percpu_to_op("xor", (pcp), val)
+#define this_cpu_xor_2(pcp, val) percpu_to_op("xor", (pcp), val)
+#define this_cpu_xor_4(pcp, val) percpu_to_op("xor", (pcp), val)
+
+#define irqsafe_cpu_add_1(pcp, val) percpu_to_op("add", (pcp), val)
+#define irqsafe_cpu_add_2(pcp, val) percpu_to_op("add", (pcp), val)
+#define irqsafe_cpu_add_4(pcp, val) percpu_to_op("add", (pcp), val)
+#define irqsafe_cpu_and_1(pcp, val) percpu_to_op("and", (pcp), val)
+#define irqsafe_cpu_and_2(pcp, val) percpu_to_op("and", (pcp), val)
+#define irqsafe_cpu_and_4(pcp, val) percpu_to_op("and", (pcp), val)
+#define irqsafe_cpu_or_1(pcp, val) percpu_to_op("or", (pcp), val)
+#define irqsafe_cpu_or_2(pcp, val) percpu_to_op("or", (pcp), val)
+#define irqsafe_cpu_or_4(pcp, val) percpu_to_op("or", (pcp), val)
+#define irqsafe_cpu_xor_1(pcp, val) percpu_to_op("xor", (pcp), val)
+#define irqsafe_cpu_xor_2(pcp, val) percpu_to_op("xor", (pcp), val)
+#define irqsafe_cpu_xor_4(pcp, val) percpu_to_op("xor", (pcp), val)
+
+/*
+ * Per cpu atomic 64 bit operations are only available under 64 bit.
+ * 32 bit must fall back to generic operations.
+ */
+#ifdef CONFIG_X86_64
+#define __this_cpu_read_8(pcp) percpu_from_op("mov", (pcp), "m"(pcp))
+#define __this_cpu_write_8(pcp, val) percpu_to_op("mov", (pcp), val)
+#define __this_cpu_add_8(pcp, val) percpu_to_op("add", (pcp), val)
+#define __this_cpu_and_8(pcp, val) percpu_to_op("and", (pcp), val)
+#define __this_cpu_or_8(pcp, val) percpu_to_op("or", (pcp), val)
+#define __this_cpu_xor_8(pcp, val) percpu_to_op("xor", (pcp), val)
+
+#define this_cpu_read_8(pcp) percpu_from_op("mov", (pcp), "m"(pcp))
+#define this_cpu_write_8(pcp, val) percpu_to_op("mov", (pcp), val)
+#define this_cpu_add_8(pcp, val) percpu_to_op("add", (pcp), val)
+#define this_cpu_and_8(pcp, val) percpu_to_op("and", (pcp), val)
+#define this_cpu_or_8(pcp, val) percpu_to_op("or", (pcp), val)
+#define this_cpu_xor_8(pcp, val) percpu_to_op("xor", (pcp), val)
+
+#define irqsafe_cpu_add_8(pcp, val) percpu_to_op("add", (pcp), val)
+#define irqsafe_cpu_and_8(pcp, val) percpu_to_op("and", (pcp), val)
+#define irqsafe_cpu_or_8(pcp, val) percpu_to_op("or", (pcp), val)
+#define irqsafe_cpu_xor_8(pcp, val) percpu_to_op("xor", (pcp), val)
+
+#endif
+
/* This is not atomic against other CPUs -- CPU preemption needs to be off */
#define x86_test_and_clear_bit_percpu(bit, var) \
({ \
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index ad7ce3fd5065..8d9f8548a870 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -28,9 +28,20 @@
*/
#define ARCH_PERFMON_EVENT_MASK 0xffff
+/*
+ * filter mask to validate fixed counter events.
+ * the following filters disqualify for fixed counters:
+ * - inv
+ * - edge
+ * - cnt-mask
+ * The other filters are supported by fixed counters.
+ * The any-thread option is supported starting with v3.
+ */
+#define ARCH_PERFMON_EVENT_FILTER_MASK 0xff840000
+
#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL 0x3c
#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK (0x00 << 8)
-#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX 0
+#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX 0
#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT \
(1 << (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX))
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h
index 0f0d908349aa..a3d49dd7d26e 100644
--- a/arch/x86/include/asm/ptrace.h
+++ b/arch/x86/include/asm/ptrace.h
@@ -7,6 +7,7 @@
#ifdef __KERNEL__
#include <asm/segment.h>
+#include <asm/page_types.h>
#endif
#ifndef __ASSEMBLY__
@@ -216,6 +217,67 @@ static inline unsigned long user_stack_pointer(struct pt_regs *regs)
return regs->sp;
}
+/* 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);
+#define MAX_REG_OFFSET (offsetof(struct pt_regs, ss))
+
+/**
+ * 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 whose offset from @regs
+ * is @offset. The @offset is the offset of the register in struct pt_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_kenel_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 specifined 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;
+}
+
+/* Get Nth argument at function call */
+extern unsigned long regs_get_argument_nth(struct pt_regs *regs,
+ unsigned int n);
+
/*
* These are defined as per linux/ptrace.h, which see.
*/
diff --git a/arch/x86/include/asm/sections.h b/arch/x86/include/asm/sections.h
index 1b7ee5d673c2..0a5242428659 100644
--- a/arch/x86/include/asm/sections.h
+++ b/arch/x86/include/asm/sections.h
@@ -2,7 +2,13 @@
#define _ASM_X86_SECTIONS_H
#include <asm-generic/sections.h>
+#include <asm/uaccess.h>
extern char __brk_base[], __brk_limit[];
+extern struct exception_table_entry __stop___ex_table[];
+
+#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
+extern char __end_rodata_hpage_align[];
+#endif
#endif /* _ASM_X86_SECTIONS_H */
diff --git a/arch/x86/include/asm/string_32.h b/arch/x86/include/asm/string_32.h
index ae907e617181..3d3e8353ee5c 100644
--- a/arch/x86/include/asm/string_32.h
+++ b/arch/x86/include/asm/string_32.h
@@ -177,10 +177,15 @@ static inline void *__memcpy3d(void *to, const void *from, size_t len)
*/
#ifndef CONFIG_KMEMCHECK
+
+#if (__GNUC__ >= 4)
+#define memcpy(t, f, n) __builtin_memcpy(t, f, n)
+#else
#define memcpy(t, f, n) \
(__builtin_constant_p((n)) \
? __constant_memcpy((t), (f), (n)) \
: __memcpy((t), (f), (n)))
+#endif
#else
/*
* kmemcheck becomes very happy if we use the REP instructions unconditionally,
@@ -316,11 +321,15 @@ void *__constant_c_and_count_memset(void *s, unsigned long pattern,
: __memset_generic((s), (c), (count)))
#define __HAVE_ARCH_MEMSET
+#if (__GNUC__ >= 4)
+#define memset(s, c, count) __builtin_memset(s, c, count)
+#else
#define memset(s, c, count) \
(__builtin_constant_p(c) \
? __constant_c_x_memset((s), (0x01010101UL * (unsigned char)(c)), \
(count)) \
: __memset((s), (c), (count)))
+#endif
/*
* find the first occurrence of byte 'c', or 1 past the area if none
diff --git a/arch/x86/include/asm/syscalls.h b/arch/x86/include/asm/syscalls.h
index 372b76edd63f..5336ce249c99 100644
--- a/arch/x86/include/asm/syscalls.h
+++ b/arch/x86/include/asm/syscalls.h
@@ -33,11 +33,11 @@ long sys_rt_sigreturn(struct pt_regs *);
asmlinkage int sys_set_thread_area(struct user_desc __user *);
asmlinkage int sys_get_thread_area(struct user_desc __user *);
-/* X86_32 only */
-#ifdef CONFIG_X86_32
/* kernel/ioport.c */
-long sys_iopl(struct pt_regs *);
+asmlinkage long sys_iopl(unsigned int);
+/* X86_32 only */
+#ifdef CONFIG_X86_32
/* kernel/process_32.c */
int sys_clone(struct pt_regs *);
int sys_execve(struct pt_regs *);
@@ -70,8 +70,6 @@ int sys_vm86(struct pt_regs *);
#else /* CONFIG_X86_32 */
/* X86_64 only */
-/* kernel/ioport.c */
-asmlinkage long sys_iopl(unsigned int, struct pt_regs *);
/* kernel/process_64.c */
asmlinkage long sys_clone(unsigned long, unsigned long,
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index d27d0a2fec4c..375c917c37d2 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -83,6 +83,7 @@ struct thread_info {
#define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
#define TIF_SECCOMP 8 /* secure computing */
#define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */
+#define TIF_USER_RETURN_NOTIFY 11 /* notify kernel of userspace return */
#define TIF_NOTSC 16 /* TSC is not accessible in userland */
#define TIF_IA32 17 /* 32bit process */
#define TIF_FORK 18 /* ret_from_fork */
@@ -107,6 +108,7 @@ struct thread_info {
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
#define _TIF_MCE_NOTIFY (1 << TIF_MCE_NOTIFY)
+#define _TIF_USER_RETURN_NOTIFY (1 << TIF_USER_RETURN_NOTIFY)
#define _TIF_NOTSC (1 << TIF_NOTSC)
#define _TIF_IA32 (1 << TIF_IA32)
#define _TIF_FORK (1 << TIF_FORK)
@@ -142,13 +144,14 @@ struct thread_info {
/* Only used for 64 bit */
#define _TIF_DO_NOTIFY_MASK \
- (_TIF_SIGPENDING|_TIF_MCE_NOTIFY|_TIF_NOTIFY_RESUME)
+ (_TIF_SIGPENDING | _TIF_MCE_NOTIFY | _TIF_NOTIFY_RESUME | \
+ _TIF_USER_RETURN_NOTIFY)
/* flags to check in __switch_to() */
#define _TIF_WORK_CTXSW \
(_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR|_TIF_DS_AREA_MSR|_TIF_NOTSC)
-#define _TIF_WORK_CTXSW_PREV _TIF_WORK_CTXSW
+#define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW|_TIF_USER_RETURN_NOTIFY)
#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG)
#define PREEMPT_ACTIVE 0x10000000
diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h
index 25a92842dd99..d823c245f63b 100644
--- a/arch/x86/include/asm/topology.h
+++ b/arch/x86/include/asm/topology.h
@@ -143,6 +143,7 @@ extern unsigned long node_remap_size[];
| 1*SD_BALANCE_FORK \
| 0*SD_BALANCE_WAKE \
| 1*SD_WAKE_AFFINE \
+ | 1*SD_PREFER_LOCAL \
| 0*SD_SHARE_CPUPOWER \
| 0*SD_POWERSAVINGS_BALANCE \
| 0*SD_SHARE_PKG_RESOURCES \
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index d2c6c930b491..abd3e0ea762a 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -570,7 +570,6 @@ extern struct movsl_mask {
#ifdef CONFIG_X86_32
# include "uaccess_32.h"
#else
-# define ARCH_HAS_SEARCH_EXTABLE
# include "uaccess_64.h"
#endif
diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h
index 632fb44b4cb5..0c9825e97f36 100644
--- a/arch/x86/include/asm/uaccess_32.h
+++ b/arch/x86/include/asm/uaccess_32.h
@@ -187,9 +187,34 @@ __copy_from_user_inatomic_nocache(void *to, const void __user *from,
unsigned long __must_check copy_to_user(void __user *to,
const void *from, unsigned long n);
-unsigned long __must_check copy_from_user(void *to,
+unsigned long __must_check _copy_from_user(void *to,
const void __user *from,
unsigned long n);
+
+
+extern void copy_from_user_overflow(void)
+#ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS
+ __compiletime_error("copy_from_user() buffer size is not provably correct")
+#else
+ __compiletime_warning("copy_from_user() buffer size is not provably correct")
+#endif
+;
+
+static inline unsigned long __must_check copy_from_user(void *to,
+ const void __user *from,
+ unsigned long n)
+{
+ int sz = __compiletime_object_size(to);
+ int ret = -EFAULT;
+
+ if (likely(sz == -1 || sz >= n))
+ ret = _copy_from_user(to, from, n);
+ else
+ copy_from_user_overflow();
+
+ return ret;
+}
+
long __must_check strncpy_from_user(char *dst, const char __user *src,
long count);
long __must_check __strncpy_from_user(char *dst,
diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h
index db24b215fc50..ce6fec7ce38d 100644
--- a/arch/x86/include/asm/uaccess_64.h
+++ b/arch/x86/include/asm/uaccess_64.h
@@ -21,10 +21,27 @@ copy_user_generic(void *to, const void *from, unsigned len);
__must_check unsigned long
copy_to_user(void __user *to, const void *from, unsigned len);
__must_check unsigned long
-copy_from_user(void *to, const void __user *from, unsigned len);
+_copy_from_user(void *to, const void __user *from, unsigned len);
__must_check unsigned long
copy_in_user(void __user *to, const void __user *from, unsigned len);
+static inline unsigned long __must_check copy_from_user(void *to,
+ const void __user *from,
+ unsigned long n)
+{
+ int sz = __compiletime_object_size(to);
+ int ret = -EFAULT;
+
+ if (likely(sz == -1 || sz >= n))
+ ret = _copy_from_user(to, from, n);
+#ifdef CONFIG_DEBUG_VM
+ else
+ WARN(1, "Buffer overflow detected!\n");
+#endif
+ return ret;
+}
+
+
static __always_inline __must_check
int __copy_from_user(void *dst, const void __user *src, unsigned size)
{
diff --git a/arch/x86/include/asm/unistd_32.h b/arch/x86/include/asm/unistd_32.h
index 6fb3c209a7e3..3baf379fa840 100644
--- a/arch/x86/include/asm/unistd_32.h
+++ b/arch/x86/include/asm/unistd_32.h
@@ -342,10 +342,11 @@
#define __NR_pwritev 334
#define __NR_rt_tgsigqueueinfo 335
#define __NR_perf_event_open 336
+#define __NR_recvmmsg 337
#ifdef __KERNEL__
-#define NR_syscalls 337
+#define NR_syscalls 338
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
diff --git a/arch/x86/include/asm/unistd_64.h b/arch/x86/include/asm/unistd_64.h
index 8d3ad0adbc68..4843f7ba754a 100644
--- a/arch/x86/include/asm/unistd_64.h
+++ b/arch/x86/include/asm/unistd_64.h
@@ -661,6 +661,8 @@ __SYSCALL(__NR_pwritev, sys_pwritev)
__SYSCALL(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo)
#define __NR_perf_event_open 298
__SYSCALL(__NR_perf_event_open, sys_perf_event_open)
+#define __NR_recvmmsg 299
+__SYSCALL(__NR_recvmmsg, sys_recvmmsg)
#ifndef __NO_STUBS
#define __ARCH_WANT_OLD_READDIR
diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h
index 04eb6c958b9d..d1414af98559 100644
--- a/arch/x86/include/asm/uv/uv_hub.h
+++ b/arch/x86/include/asm/uv/uv_hub.h
@@ -19,6 +19,8 @@
#include <asm/types.h>
#include <asm/percpu.h>
#include <asm/uv/uv_mmrs.h>
+#include <asm/irq_vectors.h>
+#include <asm/io_apic.h>
/*
@@ -114,7 +116,7 @@
/*
* The largest possible NASID of a C or M brick (+ 2)
*/
-#define UV_MAX_NASID_VALUE (UV_MAX_NUMALINK_NODES * 2)
+#define UV_MAX_NASID_VALUE (UV_MAX_NUMALINK_BLADES * 2)
struct uv_scir_s {
struct timer_list timer;
@@ -230,6 +232,20 @@ static inline unsigned long uv_gpa(void *v)
return uv_soc_phys_ram_to_gpa(__pa(v));
}
+/* gnode -> pnode */
+static inline unsigned long uv_gpa_to_gnode(unsigned long gpa)
+{
+ return gpa >> uv_hub_info->m_val;
+}
+
+/* gpa -> pnode */
+static inline int uv_gpa_to_pnode(unsigned long gpa)
+{
+ unsigned long n_mask = (1UL << uv_hub_info->n_val) - 1;
+
+ return uv_gpa_to_gnode(gpa) & n_mask;
+}
+
/* pnode, offset --> socket virtual */
static inline void *uv_pnode_offset_to_vaddr(int pnode, unsigned long offset)
{
@@ -421,9 +437,14 @@ static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value)
static inline void uv_hub_send_ipi(int pnode, int apicid, int vector)
{
unsigned long val;
+ unsigned long dmode = dest_Fixed;
+
+ if (vector == NMI_VECTOR)
+ dmode = dest_NMI;
val = (1UL << UVH_IPI_INT_SEND_SHFT) |
((apicid) << UVH_IPI_INT_APIC_ID_SHFT) |
+ (dmode << UVH_IPI_INT_DELIVERY_MODE_SHFT) |
(vector << UVH_IPI_INT_VECTOR_SHFT);
uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
}
diff --git a/arch/x86/include/asm/uv/uv_irq.h b/arch/x86/include/asm/uv/uv_irq.h
index 9613c8c0b647..d6b17c760622 100644
--- a/arch/x86/include/asm/uv/uv_irq.h
+++ b/arch/x86/include/asm/uv/uv_irq.h
@@ -25,12 +25,14 @@ struct uv_IO_APIC_route_entry {
dest : 32;
};
-extern struct irq_chip uv_irq_chip;
-
-extern int arch_enable_uv_irq(char *, unsigned int, int, int, unsigned long);
-extern void arch_disable_uv_irq(int, unsigned long);
+enum {
+ UV_AFFINITY_ALL,
+ UV_AFFINITY_NODE,
+ UV_AFFINITY_CPU
+};
-extern int uv_setup_irq(char *, int, int, unsigned long);
-extern void uv_teardown_irq(unsigned int, int, unsigned long);
+extern int uv_irq_2_mmr_info(int, unsigned long *, int *);
+extern int uv_setup_irq(char *, int, int, unsigned long, int);
+extern void uv_teardown_irq(unsigned int);
#endif /* _ASM_X86_UV_UV_IRQ_H */
diff --git a/arch/x86/include/asm/xen/hypervisor.h b/arch/x86/include/asm/xen/hypervisor.h
index d5b7e90c0edf..396ff4cc8ed4 100644
--- a/arch/x86/include/asm/xen/hypervisor.h
+++ b/arch/x86/include/asm/xen/hypervisor.h
@@ -37,31 +37,4 @@
extern struct shared_info *HYPERVISOR_shared_info;
extern struct start_info *xen_start_info;
-enum xen_domain_type {
- XEN_NATIVE, /* running on bare hardware */
- XEN_PV_DOMAIN, /* running in a PV domain */
- XEN_HVM_DOMAIN, /* running in a Xen hvm domain */
-};
-
-#ifdef CONFIG_XEN
-extern enum xen_domain_type xen_domain_type;
-#else
-#define xen_domain_type XEN_NATIVE
-#endif
-
-#define xen_domain() (xen_domain_type != XEN_NATIVE)
-#define xen_pv_domain() (xen_domain() && \
- xen_domain_type == XEN_PV_DOMAIN)
-#define xen_hvm_domain() (xen_domain() && \
- xen_domain_type == XEN_HVM_DOMAIN)
-
-#ifdef CONFIG_XEN_DOM0
-#include <xen/interface/xen.h>
-
-#define xen_initial_domain() (xen_pv_domain() && \
- xen_start_info->flags & SIF_INITDOMAIN)
-#else /* !CONFIG_XEN_DOM0 */
-#define xen_initial_domain() (0)
-#endif /* CONFIG_XEN_DOM0 */
-
#endif /* _ASM_X86_XEN_HYPERVISOR_H */
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 67e929b89875..87eee07da21f 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -624,6 +624,7 @@ static int __init acpi_parse_hpet(struct acpi_table_header *table)
}
hpet_address = hpet_tbl->address.address;
+ hpet_blockid = hpet_tbl->sequence;
/*
* Some broken BIOSes advertise HPET at 0x0. We really do not
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.lds.S b/arch/x86/kernel/acpi/realmode/wakeup.lds.S
index 7da00b799cda..060fff8f5c5b 100644
--- a/arch/x86/kernel/acpi/realmode/wakeup.lds.S
+++ b/arch/x86/kernel/acpi/realmode/wakeup.lds.S
@@ -57,5 +57,8 @@ SECTIONS
*(.note*)
}
+ /*
+ * The ASSERT() sink to . is intentional, for binutils 2.14 compatibility:
+ */
. = ASSERT(_end <= WAKEUP_SIZE, "Wakeup too big!");
}
diff --git a/arch/x86/kernel/apic/Makefile b/arch/x86/kernel/apic/Makefile
index da7b7b9f8bd8..565c1bfc507d 100644
--- a/arch/x86/kernel/apic/Makefile
+++ b/arch/x86/kernel/apic/Makefile
@@ -2,7 +2,7 @@
# Makefile for local APIC drivers and for the IO-APIC code
#
-obj-$(CONFIG_X86_LOCAL_APIC) += apic.o probe_$(BITS).o ipi.o nmi.o
+obj-$(CONFIG_X86_LOCAL_APIC) += apic.o apic_noop.o probe_$(BITS).o ipi.o nmi.o
obj-$(CONFIG_X86_IO_APIC) += io_apic.o
obj-$(CONFIG_SMP) += ipi.o
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 894aa97f0717..4c689f45b238 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -241,28 +241,13 @@ static int modern_apic(void)
}
/*
- * bare function to substitute write operation
- * and it's _that_ fast :)
- */
-static void native_apic_write_dummy(u32 reg, u32 v)
-{
- WARN_ON_ONCE((cpu_has_apic || !disable_apic));
-}
-
-static u32 native_apic_read_dummy(u32 reg)
-{
- WARN_ON_ONCE((cpu_has_apic && !disable_apic));
- return 0;
-}
-
-/*
- * right after this call apic->write/read doesn't do anything
- * note that there is no restore operation it works one way
+ * right after this call apic become NOOP driven
+ * so apic->write/read doesn't do anything
*/
void apic_disable(void)
{
- apic->read = native_apic_read_dummy;
- apic->write = native_apic_write_dummy;
+ pr_info("APIC: switched to apic NOOP\n");
+ apic = &apic_noop;
}
void native_apic_wait_icr_idle(void)
@@ -459,7 +444,7 @@ static void lapic_timer_setup(enum clock_event_mode mode,
v = apic_read(APIC_LVTT);
v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
apic_write(APIC_LVTT, v);
- apic_write(APIC_TMICT, 0xffffffff);
+ apic_write(APIC_TMICT, 0);
break;
case CLOCK_EVT_MODE_RESUME:
/* Nothing to do here */
diff --git a/arch/x86/kernel/apic/apic_noop.c b/arch/x86/kernel/apic/apic_noop.c
new file mode 100644
index 000000000000..9ab6ffb313ac
--- /dev/null
+++ b/arch/x86/kernel/apic/apic_noop.c
@@ -0,0 +1,205 @@
+/*
+ * NOOP APIC driver.
+ *
+ * Does almost nothing and should be substituted by a real apic driver via
+ * probe routine.
+ *
+ * Though in case if apic is disabled (for some reason) we try
+ * to not uglify the caller's code and allow to call (some) apic routines
+ * like self-ipi, etc...
+ */
+
+#include <linux/threads.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <asm/fixmap.h>
+#include <asm/mpspec.h>
+#include <asm/apicdef.h>
+#include <asm/apic.h>
+#include <asm/setup.h>
+
+#include <linux/smp.h>
+#include <asm/ipi.h>
+
+#include <linux/interrupt.h>
+#include <asm/acpi.h>
+#include <asm/e820.h>
+
+static void noop_init_apic_ldr(void) { }
+static void noop_send_IPI_mask(const struct cpumask *cpumask, int vector) { }
+static void noop_send_IPI_mask_allbutself(const struct cpumask *cpumask, int vector) { }
+static void noop_send_IPI_allbutself(int vector) { }
+static void noop_send_IPI_all(int vector) { }
+static void noop_send_IPI_self(int vector) { }
+static void noop_apic_wait_icr_idle(void) { }
+static void noop_apic_icr_write(u32 low, u32 id) { }
+
+static int noop_wakeup_secondary_cpu(int apicid, unsigned long start_eip)
+{
+ return -1;
+}
+
+static u32 noop_safe_apic_wait_icr_idle(void)
+{
+ return 0;
+}
+
+static u64 noop_apic_icr_read(void)
+{
+ return 0;
+}
+
+static physid_mask_t noop_ioapic_phys_id_map(physid_mask_t phys_map)
+{
+ return phys_map;
+}
+
+static int noop_cpu_to_logical_apicid(int cpu)
+{
+ return 0;
+}
+
+static int noop_phys_pkg_id(int cpuid_apic, int index_msb)
+{
+ return 0;
+}
+
+static unsigned int noop_get_apic_id(unsigned long x)
+{
+ return 0;
+}
+
+static int noop_probe(void)
+{
+ /*
+ * NOOP apic should not ever be
+ * enabled via probe routine
+ */
+ return 0;
+}
+
+static int noop_apic_id_registered(void)
+{
+ /*
+ * if we would be really "pedantic"
+ * we should pass read_apic_id() here
+ * but since NOOP suppose APIC ID = 0
+ * lets save a few cycles
+ */
+ return physid_isset(0, phys_cpu_present_map);
+}
+
+static const struct cpumask *noop_target_cpus(void)
+{
+ /* only BSP here */
+ return cpumask_of(0);
+}
+
+static unsigned long noop_check_apicid_used(physid_mask_t bitmap, int apicid)
+{
+ return physid_isset(apicid, bitmap);
+}
+
+static unsigned long noop_check_apicid_present(int bit)
+{
+ return physid_isset(bit, phys_cpu_present_map);
+}
+
+static void noop_vector_allocation_domain(int cpu, struct cpumask *retmask)
+{
+ if (cpu != 0)
+ pr_warning("APIC: Vector allocated for non-BSP cpu\n");
+ cpumask_clear(retmask);
+ cpumask_set_cpu(cpu, retmask);
+}
+
+int noop_apicid_to_node(int logical_apicid)
+{
+ /* we're always on node 0 */
+ return 0;
+}
+
+static u32 noop_apic_read(u32 reg)
+{
+ WARN_ON_ONCE((cpu_has_apic && !disable_apic));
+ return 0;
+}
+
+static void noop_apic_write(u32 reg, u32 v)
+{
+ WARN_ON_ONCE((cpu_has_apic || !disable_apic));
+}
+
+struct apic apic_noop = {
+ .name = "noop",
+ .probe = noop_probe,
+ .acpi_madt_oem_check = NULL,
+
+ .apic_id_registered = noop_apic_id_registered,
+
+ .irq_delivery_mode = dest_LowestPrio,
+ /* logical delivery broadcast to all CPUs: */
+ .irq_dest_mode = 1,
+
+ .target_cpus = noop_target_cpus,
+ .disable_esr = 0,
+ .dest_logical = APIC_DEST_LOGICAL,
+ .check_apicid_used = noop_check_apicid_used,
+ .check_apicid_present = noop_check_apicid_present,
+
+ .vector_allocation_domain = noop_vector_allocation_domain,
+ .init_apic_ldr = noop_init_apic_ldr,
+
+ .ioapic_phys_id_map = noop_ioapic_phys_id_map,
+ .setup_apic_routing = NULL,
+ .multi_timer_check = NULL,
+ .apicid_to_node = noop_apicid_to_node,
+
+ .cpu_to_logical_apicid = noop_cpu_to_logical_apicid,
+ .cpu_present_to_apicid = default_cpu_present_to_apicid,
+ .apicid_to_cpu_present = default_apicid_to_cpu_present,
+
+ .setup_portio_remap = NULL,
+ .check_phys_apicid_present = default_check_phys_apicid_present,
+ .enable_apic_mode = NULL,
+
+ .phys_pkg_id = noop_phys_pkg_id,
+
+ .mps_oem_check = NULL,
+
+ .get_apic_id = noop_get_apic_id,
+ .set_apic_id = NULL,
+ .apic_id_mask = 0x0F << 24,
+
+ .cpu_mask_to_apicid = default_cpu_mask_to_apicid,
+ .cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and,
+
+ .send_IPI_mask = noop_send_IPI_mask,
+ .send_IPI_mask_allbutself = noop_send_IPI_mask_allbutself,
+ .send_IPI_allbutself = noop_send_IPI_allbutself,
+ .send_IPI_all = noop_send_IPI_all,
+ .send_IPI_self = noop_send_IPI_self,
+
+ .wakeup_secondary_cpu = noop_wakeup_secondary_cpu,
+
+ /* should be safe */
+ .trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW,
+ .trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH,
+
+ .wait_for_init_deassert = NULL,
+
+ .smp_callin_clear_local_apic = NULL,
+ .inquire_remote_apic = NULL,
+
+ .read = noop_apic_read,
+ .write = noop_apic_write,
+ .icr_read = noop_apic_icr_read,
+ .icr_write = noop_apic_icr_write,
+ .wait_icr_idle = noop_apic_wait_icr_idle,
+ .safe_wait_icr_idle = noop_safe_apic_wait_icr_idle,
+};
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index dc69f28489f5..2b3a199179e4 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -60,8 +60,6 @@
#include <asm/irq_remapping.h>
#include <asm/hpet.h>
#include <asm/hw_irq.h>
-#include <asm/uv/uv_hub.h>
-#include <asm/uv/uv_irq.h>
#include <asm/apic.h>
@@ -140,20 +138,6 @@ static struct irq_pin_list *get_one_free_irq_2_pin(int node)
return pin;
}
-/*
- * This is performance-critical, we want to do it O(1)
- *
- * Most irqs are mapped 1:1 with pins.
- */
-struct irq_cfg {
- struct irq_pin_list *irq_2_pin;
- cpumask_var_t domain;
- cpumask_var_t old_domain;
- unsigned move_cleanup_count;
- u8 vector;
- u8 move_in_progress : 1;
-};
-
/* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
#ifdef CONFIG_SPARSE_IRQ
static struct irq_cfg irq_cfgx[] = {
@@ -209,7 +193,7 @@ int __init arch_early_irq_init(void)
}
#ifdef CONFIG_SPARSE_IRQ
-static struct irq_cfg *irq_cfg(unsigned int irq)
+struct irq_cfg *irq_cfg(unsigned int irq)
{
struct irq_cfg *cfg = NULL;
struct irq_desc *desc;
@@ -361,7 +345,7 @@ void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc)
/* end for move_irq_desc */
#else
-static struct irq_cfg *irq_cfg(unsigned int irq)
+struct irq_cfg *irq_cfg(unsigned int irq)
{
return irq < nr_irqs ? irq_cfgx + irq : NULL;
}
@@ -1237,8 +1221,7 @@ next:
return err;
}
-static int
-assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
+int assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
{
int err;
unsigned long flags;
@@ -1599,9 +1582,6 @@ __apicdebuginit(void) print_IO_APIC(void)
struct irq_desc *desc;
unsigned int irq;
- if (apic_verbosity == APIC_QUIET)
- return;
-
printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
for (i = 0; i < nr_ioapics; i++)
printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n",
@@ -1708,9 +1688,6 @@ __apicdebuginit(void) print_APIC_field(int base)
{
int i;
- if (apic_verbosity == APIC_QUIET)
- return;
-
printk(KERN_DEBUG);
for (i = 0; i < 8; i++)
@@ -1724,9 +1701,6 @@ __apicdebuginit(void) print_local_APIC(void *dummy)
unsigned int i, v, ver, maxlvt;
u64 icr;
- if (apic_verbosity == APIC_QUIET)
- return;
-
printk(KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",
smp_processor_id(), hard_smp_processor_id());
v = apic_read(APIC_ID);
@@ -1824,13 +1798,19 @@ __apicdebuginit(void) print_local_APIC(void *dummy)
printk("\n");
}
-__apicdebuginit(void) print_all_local_APICs(void)
+__apicdebuginit(void) print_local_APICs(int maxcpu)
{
int cpu;
+ if (!maxcpu)
+ return;
+
preempt_disable();
- for_each_online_cpu(cpu)
+ for_each_online_cpu(cpu) {
+ if (cpu >= maxcpu)
+ break;
smp_call_function_single(cpu, print_local_APIC, NULL, 1);
+ }
preempt_enable();
}
@@ -1839,7 +1819,7 @@ __apicdebuginit(void) print_PIC(void)
unsigned int v;
unsigned long flags;
- if (apic_verbosity == APIC_QUIET || !nr_legacy_irqs)
+ if (!nr_legacy_irqs)
return;
printk(KERN_DEBUG "\nprinting PIC contents\n");
@@ -1866,21 +1846,41 @@ __apicdebuginit(void) print_PIC(void)
printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
}
-__apicdebuginit(int) print_all_ICs(void)
+static int __initdata show_lapic = 1;
+static __init int setup_show_lapic(char *arg)
{
+ int num = -1;
+
+ if (strcmp(arg, "all") == 0) {
+ show_lapic = CONFIG_NR_CPUS;
+ } else {
+ get_option(&arg, &num);
+ if (num >= 0)
+ show_lapic = num;
+ }
+
+ return 1;
+}
+__setup("show_lapic=", setup_show_lapic);
+
+__apicdebuginit(int) print_ICs(void)
+{
+ if (apic_verbosity == APIC_QUIET)
+ return 0;
+
print_PIC();
/* don't print out if apic is not there */
if (!cpu_has_apic && !apic_from_smp_config())
return 0;
- print_all_local_APICs();
+ print_local_APICs(show_lapic);
print_IO_APIC();
return 0;
}
-fs_initcall(print_all_ICs);
+fs_initcall(print_ICs);
/* Where if anywhere is the i8259 connect in external int mode */
@@ -2228,7 +2228,7 @@ static int ioapic_retrigger_irq(unsigned int irq)
*/
#ifdef CONFIG_SMP
-static void send_cleanup_vector(struct irq_cfg *cfg)
+void send_cleanup_vector(struct irq_cfg *cfg)
{
cpumask_var_t cleanup_mask;
@@ -2272,15 +2272,12 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq
}
}
-static int
-assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask);
-
/*
* Either sets desc->affinity to a valid value, and returns
* ->cpu_mask_to_apicid of that, or returns BAD_APICID and
* leaves desc->affinity untouched.
*/
-static unsigned int
+unsigned int
set_desc_affinity(struct irq_desc *desc, const struct cpumask *mask)
{
struct irq_cfg *cfg;
@@ -3211,7 +3208,8 @@ void destroy_irq(unsigned int irq)
* MSI message composition
*/
#ifdef CONFIG_PCI_MSI
-static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
+static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
+ struct msi_msg *msg, u8 hpet_id)
{
struct irq_cfg *cfg;
int err;
@@ -3245,7 +3243,10 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
irte.dest_id = IRTE_DEST(dest);
/* Set source-id of interrupt request */
- set_msi_sid(&irte, pdev);
+ if (pdev)
+ set_msi_sid(&irte, pdev);
+ else
+ set_hpet_sid(&irte, hpet_id);
modify_irte(irq, &irte);
@@ -3410,7 +3411,7 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
int ret;
struct msi_msg msg;
- ret = msi_compose_msg(dev, irq, &msg);
+ ret = msi_compose_msg(dev, irq, &msg, -1);
if (ret < 0)
return ret;
@@ -3543,7 +3544,7 @@ int arch_setup_dmar_msi(unsigned int irq)
int ret;
struct msi_msg msg;
- ret = msi_compose_msg(NULL, irq, &msg);
+ ret = msi_compose_msg(NULL, irq, &msg, -1);
if (ret < 0)
return ret;
dmar_msi_write(irq, &msg);
@@ -3583,6 +3584,19 @@ static int hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
#endif /* CONFIG_SMP */
+static struct irq_chip ir_hpet_msi_type = {
+ .name = "IR-HPET_MSI",
+ .unmask = hpet_msi_unmask,
+ .mask = hpet_msi_mask,
+#ifdef CONFIG_INTR_REMAP
+ .ack = ir_ack_apic_edge,
+#ifdef CONFIG_SMP
+ .set_affinity = ir_set_msi_irq_affinity,
+#endif
+#endif
+ .retrigger = ioapic_retrigger_irq,
+};
+
static struct irq_chip hpet_msi_type = {
.name = "HPET_MSI",
.unmask = hpet_msi_unmask,
@@ -3594,20 +3608,36 @@ static struct irq_chip hpet_msi_type = {
.retrigger = ioapic_retrigger_irq,
};
-int arch_setup_hpet_msi(unsigned int irq)
+int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
{
int ret;
struct msi_msg msg;
struct irq_desc *desc = irq_to_desc(irq);
- ret = msi_compose_msg(NULL, irq, &msg);
+ if (intr_remapping_enabled) {
+ struct intel_iommu *iommu = map_hpet_to_ir(id);
+ int index;
+
+ if (!iommu)
+ return -1;
+
+ index = alloc_irte(iommu, irq, 1);
+ if (index < 0)
+ return -1;
+ }
+
+ ret = msi_compose_msg(NULL, irq, &msg, id);
if (ret < 0)
return ret;
hpet_msi_write(irq, &msg);
desc->status |= IRQ_MOVE_PCNTXT;
- set_irq_chip_and_handler_name(irq, &hpet_msi_type, handle_edge_irq,
- "edge");
+ if (irq_remapped(irq))
+ set_irq_chip_and_handler_name(irq, &ir_hpet_msi_type,
+ handle_edge_irq, "edge");
+ else
+ set_irq_chip_and_handler_name(irq, &hpet_msi_type,
+ handle_edge_irq, "edge");
return 0;
}
@@ -3708,75 +3738,6 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
}
#endif /* CONFIG_HT_IRQ */
-#ifdef CONFIG_X86_UV
-/*
- * Re-target the irq to the specified CPU and enable the specified MMR located
- * on the specified blade to allow the sending of MSIs to the specified CPU.
- */
-int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
- unsigned long mmr_offset)
-{
- const struct cpumask *eligible_cpu = cpumask_of(cpu);
- struct irq_cfg *cfg;
- int mmr_pnode;
- unsigned long mmr_value;
- struct uv_IO_APIC_route_entry *entry;
- unsigned long flags;
- int err;
-
- BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long));
-
- cfg = irq_cfg(irq);
-
- err = assign_irq_vector(irq, cfg, eligible_cpu);
- if (err != 0)
- return err;
-
- spin_lock_irqsave(&vector_lock, flags);
- set_irq_chip_and_handler_name(irq, &uv_irq_chip, handle_percpu_irq,
- irq_name);
- spin_unlock_irqrestore(&vector_lock, flags);
-
- mmr_value = 0;
- entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
- entry->vector = cfg->vector;
- entry->delivery_mode = apic->irq_delivery_mode;
- entry->dest_mode = apic->irq_dest_mode;
- entry->polarity = 0;
- entry->trigger = 0;
- entry->mask = 0;
- entry->dest = apic->cpu_mask_to_apicid(eligible_cpu);
-
- mmr_pnode = uv_blade_to_pnode(mmr_blade);
- uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
-
- if (cfg->move_in_progress)
- send_cleanup_vector(cfg);
-
- return irq;
-}
-
-/*
- * Disable the specified MMR located on the specified blade so that MSIs are
- * longer allowed to be sent.
- */
-void arch_disable_uv_irq(int mmr_blade, unsigned long mmr_offset)
-{
- unsigned long mmr_value;
- struct uv_IO_APIC_route_entry *entry;
- int mmr_pnode;
-
- BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long));
-
- mmr_value = 0;
- entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
- entry->mask = 1;
-
- mmr_pnode = uv_blade_to_pnode(mmr_blade);
- uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
-}
-#endif /* CONFIG_X86_64 */
-
int __init io_apic_get_redir_entries (int ioapic)
{
union IO_APIC_reg_01 reg_01;
diff --git a/arch/x86/kernel/apic/nmi.c b/arch/x86/kernel/apic/nmi.c
index 7ff61d6a188a..e631cc4416f7 100644
--- a/arch/x86/kernel/apic/nmi.c
+++ b/arch/x86/kernel/apic/nmi.c
@@ -360,7 +360,7 @@ void stop_apic_nmi_watchdog(void *unused)
*/
static DEFINE_PER_CPU(unsigned, last_irq_sum);
-static DEFINE_PER_CPU(local_t, alert_counter);
+static DEFINE_PER_CPU(long, alert_counter);
static DEFINE_PER_CPU(int, nmi_touch);
void touch_nmi_watchdog(void)
@@ -437,8 +437,8 @@ nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)
* Ayiee, looks like this CPU is stuck ...
* wait a few IRQs (5 seconds) before doing the oops ...
*/
- local_inc(&__get_cpu_var(alert_counter));
- if (local_read(&__get_cpu_var(alert_counter)) == 5 * nmi_hz)
+ __this_cpu_inc(per_cpu_var(alert_counter));
+ if (__this_cpu_read(per_cpu_var(alert_counter)) == 5 * nmi_hz)
/*
* die_nmi will return ONLY if NOTIFY_STOP happens..
*/
@@ -446,7 +446,7 @@ nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)
regs, panic_on_timeout);
} else {
__get_cpu_var(last_irq_sum) = sum;
- local_set(&__get_cpu_var(alert_counter), 0);
+ __this_cpu_write(per_cpu_var(alert_counter), 0);
}
/* see if the nmi watchdog went off */
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index f5f5886a6b53..326c25477d3d 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -352,14 +352,14 @@ static __init void get_lowmem_redirect(unsigned long *base, unsigned long *size)
for (i = 0; i < ARRAY_SIZE(redir_addrs); i++) {
alias.v = uv_read_local_mmr(redir_addrs[i].alias);
- if (alias.s.base == 0) {
+ if (alias.s.enable && alias.s.base == 0) {
*size = (1UL << alias.s.m_alias);
redirect.v = uv_read_local_mmr(redir_addrs[i].redirect);
*base = (unsigned long)redirect.s.dest_base << DEST_SHIFT;
return;
}
}
- BUG();
+ *base = *size = 0;
}
enum map_type {map_wb, map_uc};
@@ -619,12 +619,12 @@ void __init uv_system_init(void)
uv_cpu_hub_info(cpu)->lowmem_remap_base = lowmem_redir_base;
uv_cpu_hub_info(cpu)->lowmem_remap_top = lowmem_redir_size;
uv_cpu_hub_info(cpu)->m_val = m_val;
- uv_cpu_hub_info(cpu)->n_val = m_val;
+ uv_cpu_hub_info(cpu)->n_val = n_val;
uv_cpu_hub_info(cpu)->numa_blade_id = blade;
uv_cpu_hub_info(cpu)->blade_processor_id = lcpu;
uv_cpu_hub_info(cpu)->pnode = pnode;
uv_cpu_hub_info(cpu)->pnode_mask = pnode_mask;
- uv_cpu_hub_info(cpu)->gpa_mask = (1 << (m_val + n_val)) - 1;
+ uv_cpu_hub_info(cpu)->gpa_mask = (1UL << (m_val + n_val)) - 1;
uv_cpu_hub_info(cpu)->gnode_upper = gnode_upper;
uv_cpu_hub_info(cpu)->gnode_extra = gnode_extra;
uv_cpu_hub_info(cpu)->global_mmr_base = mmr_base;
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index 151ace69a5aa..b5b6b23bce53 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -204,7 +204,6 @@
#include <linux/module.h>
#include <linux/poll.h>
-#include <linux/smp_lock.h>
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/timer.h>
@@ -403,6 +402,7 @@ static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
static struct apm_user *user_list;
static DEFINE_SPINLOCK(user_list_lock);
+static DEFINE_MUTEX(apm_mutex);
/*
* Set up a segment that references the real mode segment 0x40
@@ -1531,7 +1531,7 @@ static long do_ioctl(struct file *filp, u_int cmd, u_long arg)
return -EPERM;
switch (cmd) {
case APM_IOC_STANDBY:
- lock_kernel();
+ mutex_lock(&apm_mutex);
if (as->standbys_read > 0) {
as->standbys_read--;
as->standbys_pending--;
@@ -1540,10 +1540,10 @@ static long do_ioctl(struct file *filp, u_int cmd, u_long arg)
queue_event(APM_USER_STANDBY, as);
if (standbys_pending <= 0)
standby();
- unlock_kernel();
+ mutex_unlock(&apm_mutex);
break;
case APM_IOC_SUSPEND:
- lock_kernel();
+ mutex_lock(&apm_mutex);
if (as->suspends_read > 0) {
as->suspends_read--;
as->suspends_pending--;
@@ -1552,13 +1552,14 @@ static long do_ioctl(struct file *filp, u_int cmd, u_long arg)
queue_event(APM_USER_SUSPEND, as);
if (suspends_pending <= 0) {
ret = suspend(1);
+ mutex_unlock(&apm_mutex);
} else {
as->suspend_wait = 1;
+ mutex_unlock(&apm_mutex);
wait_event_interruptible(apm_suspend_waitqueue,
as->suspend_wait == 0);
ret = as->suspend_result;
}
- unlock_kernel();
return ret;
default:
return -ENOTTY;
@@ -1608,12 +1609,10 @@ static int do_open(struct inode *inode, struct file *filp)
{
struct apm_user *as;
- lock_kernel();
as = kmalloc(sizeof(*as), GFP_KERNEL);
if (as == NULL) {
printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n",
sizeof(*as));
- unlock_kernel();
return -ENOMEM;
}
as->magic = APM_BIOS_MAGIC;
@@ -1635,7 +1634,6 @@ static int do_open(struct inode *inode, struct file *filp)
user_list = as;
spin_unlock(&user_list_lock);
filp->private_data = as;
- unlock_kernel();
return 0;
}
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index cc25c2b4a567..4df69a38be57 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -839,7 +839,7 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
#ifdef CONFIG_X86_MCE
/* Init Machine Check Exception if available. */
- mcheck_init(c);
+ mcheck_cpu_init(c);
#endif
select_idle_routine(c);
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index b1598a9436d0..d5f7aebcfaee 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -35,6 +35,7 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/debugfs.h>
+#include <linux/edac_mce.h>
#include <asm/processor.h>
#include <asm/hw_irq.h>
@@ -46,6 +47,9 @@
#include "mce-internal.h"
+#define CREATE_TRACE_POINTS
+#include <trace/events/mce.h>
+
int mce_disabled __read_mostly;
#define MISC_MCELOG_MINOR 227
@@ -85,18 +89,26 @@ static DECLARE_WAIT_QUEUE_HEAD(mce_wait);
static DEFINE_PER_CPU(struct mce, mces_seen);
static int cpu_missing;
-static void default_decode_mce(struct mce *m)
+/*
+ * CPU/chipset specific EDAC code can register a notifier call here to print
+ * MCE errors in a human-readable form.
+ */
+ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain);
+EXPORT_SYMBOL_GPL(x86_mce_decoder_chain);
+
+static int default_decode_mce(struct notifier_block *nb, unsigned long val,
+ void *data)
{
pr_emerg("No human readable MCE decoding support on this CPU type.\n");
pr_emerg("Run the message through 'mcelog --ascii' to decode.\n");
+
+ return NOTIFY_STOP;
}
-/*
- * CPU/chipset specific EDAC code can register a callback here to print
- * MCE errors in a human-readable form:
- */
-void (*x86_mce_decode_callback)(struct mce *m) = default_decode_mce;
-EXPORT_SYMBOL(x86_mce_decode_callback);
+static struct notifier_block mce_dec_nb = {
+ .notifier_call = default_decode_mce,
+ .priority = -1,
+};
/* MCA banks polled by the period polling timer for corrected events */
DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
@@ -141,12 +153,24 @@ void mce_log(struct mce *mce)
{
unsigned next, entry;
+ /* Emit the trace record: */
+ trace_mce_record(mce);
+
mce->finished = 0;
wmb();
for (;;) {
entry = rcu_dereference(mcelog.next);
for (;;) {
/*
+ * If edac_mce is enabled, it will check the error type
+ * and will process it, if it is a known error.
+ * Otherwise, the error will be sent through mcelog
+ * interface
+ */
+ if (edac_mce_parse(mce))
+ return;
+
+ /*
* When the buffer fills up discard new entries.
* Assume that the earlier errors are the more
* interesting ones:
@@ -204,9 +228,9 @@ static void print_mce(struct mce *m)
/*
* Print out human-readable details about the MCE error,
- * (if the CPU has an implementation for that):
+ * (if the CPU has an implementation for that)
*/
- x86_mce_decode_callback(m);
+ atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, m);
}
static void print_mce_head(void)
@@ -1122,7 +1146,7 @@ static int check_interval = 5 * 60; /* 5 minutes */
static DEFINE_PER_CPU(int, mce_next_interval); /* in jiffies */
static DEFINE_PER_CPU(struct timer_list, mce_timer);
-static void mcheck_timer(unsigned long data)
+static void mce_start_timer(unsigned long data)
{
struct timer_list *t = &per_cpu(mce_timer, data);
int *n;
@@ -1206,7 +1230,7 @@ static int mce_banks_init(void)
/*
* Initialize Machine Checks for a CPU.
*/
-static int __cpuinit mce_cap_init(void)
+static int __cpuinit __mcheck_cpu_cap_init(void)
{
unsigned b;
u64 cap;
@@ -1214,7 +1238,8 @@ static int __cpuinit mce_cap_init(void)
rdmsrl(MSR_IA32_MCG_CAP, cap);
b = cap & MCG_BANKCNT_MASK;
- printk(KERN_INFO "mce: CPU supports %d MCE banks\n", b);
+ if (!banks)
+ printk(KERN_INFO "mce: CPU supports %d MCE banks\n", b);
if (b > MAX_NR_BANKS) {
printk(KERN_WARNING
@@ -1243,7 +1268,7 @@ static int __cpuinit mce_cap_init(void)
return 0;
}
-static void mce_init(void)
+static void __mcheck_cpu_init_generic(void)
{
mce_banks_t all_banks;
u64 cap;
@@ -1272,7 +1297,7 @@ static void mce_init(void)
}
/* Add per CPU specific workarounds here */
-static int __cpuinit mce_cpu_quirks(struct cpuinfo_x86 *c)
+static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c)
{
if (c->x86_vendor == X86_VENDOR_UNKNOWN) {
pr_info("MCE: unknown CPU type - not enabling MCE support.\n");
@@ -1340,7 +1365,7 @@ static int __cpuinit mce_cpu_quirks(struct cpuinfo_x86 *c)
return 0;
}
-static void __cpuinit mce_ancient_init(struct cpuinfo_x86 *c)
+static void __cpuinit __mcheck_cpu_ancient_init(struct cpuinfo_x86 *c)
{
if (c->x86 != 5)
return;
@@ -1354,7 +1379,7 @@ static void __cpuinit mce_ancient_init(struct cpuinfo_x86 *c)
}
}
-static void mce_cpu_features(struct cpuinfo_x86 *c)
+static void __mcheck_cpu_init_vendor(struct cpuinfo_x86 *c)
{
switch (c->x86_vendor) {
case X86_VENDOR_INTEL:
@@ -1368,7 +1393,7 @@ static void mce_cpu_features(struct cpuinfo_x86 *c)
}
}
-static void mce_init_timer(void)
+static void __mcheck_cpu_init_timer(void)
{
struct timer_list *t = &__get_cpu_var(mce_timer);
int *n = &__get_cpu_var(mce_next_interval);
@@ -1379,7 +1404,7 @@ static void mce_init_timer(void)
*n = check_interval * HZ;
if (!*n)
return;
- setup_timer(t, mcheck_timer, smp_processor_id());
+ setup_timer(t, mce_start_timer, smp_processor_id());
t->expires = round_jiffies(jiffies + *n);
add_timer_on(t, smp_processor_id());
}
@@ -1399,27 +1424,28 @@ void (*machine_check_vector)(struct pt_regs *, long error_code) =
* Called for each booted CPU to set up machine checks.
* Must be called with preempt off:
*/
-void __cpuinit mcheck_init(struct cpuinfo_x86 *c)
+void __cpuinit mcheck_cpu_init(struct cpuinfo_x86 *c)
{
if (mce_disabled)
return;
- mce_ancient_init(c);
+ __mcheck_cpu_ancient_init(c);
if (!mce_available(c))
return;
- if (mce_cap_init() < 0 || mce_cpu_quirks(c) < 0) {
+ if (__mcheck_cpu_cap_init() < 0 || __mcheck_cpu_apply_quirks(c) < 0) {
mce_disabled = 1;
return;
}
machine_check_vector = do_machine_check;
- mce_init();
- mce_cpu_features(c);
- mce_init_timer();
+ __mcheck_cpu_init_generic();
+ __mcheck_cpu_init_vendor(c);
+ __mcheck_cpu_init_timer();
INIT_WORK(&__get_cpu_var(mce_work), mce_process_work);
+
}
/*
@@ -1639,6 +1665,14 @@ static int __init mcheck_enable(char *str)
}
__setup("mce", mcheck_enable);
+static int __init mcheck_init(void)
+{
+ atomic_notifier_chain_register(&x86_mce_decoder_chain, &mce_dec_nb);
+
+ return 0;
+}
+early_initcall(mcheck_init);
+
/*
* Sysfs support
*/
@@ -1647,7 +1681,7 @@ __setup("mce", mcheck_enable);
* Disable machine checks on suspend and shutdown. We can't really handle
* them later.
*/
-static int mce_disable(void)
+static int mce_disable_error_reporting(void)
{
int i;
@@ -1662,12 +1696,12 @@ static int mce_disable(void)
static int mce_suspend(struct sys_device *dev, pm_message_t state)
{
- return mce_disable();
+ return mce_disable_error_reporting();
}
static int mce_shutdown(struct sys_device *dev)
{
- return mce_disable();
+ return mce_disable_error_reporting();
}
/*
@@ -1677,8 +1711,8 @@ static int mce_shutdown(struct sys_device *dev)
*/
static int mce_resume(struct sys_device *dev)
{
- mce_init();
- mce_cpu_features(&current_cpu_data);
+ __mcheck_cpu_init_generic();
+ __mcheck_cpu_init_vendor(&current_cpu_data);
return 0;
}
@@ -1688,8 +1722,8 @@ static void mce_cpu_restart(void *data)
del_timer_sync(&__get_cpu_var(mce_timer));
if (!mce_available(&current_cpu_data))
return;
- mce_init();
- mce_init_timer();
+ __mcheck_cpu_init_generic();
+ __mcheck_cpu_init_timer();
}
/* Reinit MCEs after user configuration changes */
@@ -1715,7 +1749,7 @@ static void mce_enable_ce(void *all)
cmci_reenable();
cmci_recheck();
if (all)
- mce_init_timer();
+ __mcheck_cpu_init_timer();
}
static struct sysdev_class mce_sysclass = {
@@ -2024,7 +2058,7 @@ static __init void mce_init_banks(void)
}
}
-static __init int mce_init_device(void)
+static __init int mcheck_init_device(void)
{
int err;
int i = 0;
@@ -2052,7 +2086,7 @@ static __init int mce_init_device(void)
return err;
}
-device_initcall(mce_init_device);
+device_initcall(mcheck_init_device);
/*
* Old style boot options parsing. Only for compatibility.
@@ -2100,7 +2134,7 @@ static int fake_panic_set(void *data, u64 val)
DEFINE_SIMPLE_ATTRIBUTE(fake_panic_fops, fake_panic_get,
fake_panic_set, "%llu\n");
-static int __init mce_debugfs_init(void)
+static int __init mcheck_debugfs_init(void)
{
struct dentry *dmce, *ffake_panic;
@@ -2114,5 +2148,5 @@ static int __init mce_debugfs_init(void)
return 0;
}
-late_initcall(mce_debugfs_init);
+late_initcall(mcheck_debugfs_init);
#endif
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index b5801c311846..2e20bca3cca1 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -77,6 +77,18 @@ struct cpu_hw_events {
struct debug_store *ds;
};
+struct event_constraint {
+ unsigned long idxmsk[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
+ int code;
+};
+
+#define EVENT_CONSTRAINT(c, m) { .code = (c), .idxmsk[0] = (m) }
+#define EVENT_CONSTRAINT_END { .code = 0, .idxmsk[0] = 0 }
+
+#define for_each_event_constraint(e, c) \
+ for ((e) = (c); (e)->idxmsk[0]; (e)++)
+
+
/*
* struct x86_pmu - generic x86 pmu
*/
@@ -102,6 +114,8 @@ struct x86_pmu {
u64 intel_ctrl;
void (*enable_bts)(u64 config);
void (*disable_bts)(void);
+ int (*get_event_idx)(struct cpu_hw_events *cpuc,
+ struct hw_perf_event *hwc);
};
static struct x86_pmu x86_pmu __read_mostly;
@@ -110,6 +124,8 @@ static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = {
.enabled = 1,
};
+static const struct event_constraint *event_constraints;
+
/*
* Not sure about some of these
*/
@@ -155,6 +171,16 @@ static u64 p6_pmu_raw_event(u64 hw_event)
return hw_event & P6_EVNTSEL_MASK;
}
+static const struct event_constraint intel_p6_event_constraints[] =
+{
+ EVENT_CONSTRAINT(0xc1, 0x1), /* FLOPS */
+ EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */
+ EVENT_CONSTRAINT(0x11, 0x1), /* FP_ASSIST */
+ EVENT_CONSTRAINT(0x12, 0x2), /* MUL */
+ EVENT_CONSTRAINT(0x13, 0x2), /* DIV */
+ EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */
+ EVENT_CONSTRAINT_END
+};
/*
* Intel PerfMon v3. Used on Core2 and later.
@@ -170,6 +196,35 @@ static const u64 intel_perfmon_event_map[] =
[PERF_COUNT_HW_BUS_CYCLES] = 0x013c,
};
+static const struct event_constraint intel_core_event_constraints[] =
+{
+ EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */
+ EVENT_CONSTRAINT(0x11, 0x2), /* FP_ASSIST */
+ EVENT_CONSTRAINT(0x12, 0x2), /* MUL */
+ EVENT_CONSTRAINT(0x13, 0x2), /* DIV */
+ EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */
+ EVENT_CONSTRAINT(0x18, 0x1), /* IDLE_DURING_DIV */
+ EVENT_CONSTRAINT(0x19, 0x2), /* DELAYED_BYPASS */
+ EVENT_CONSTRAINT(0xa1, 0x1), /* RS_UOPS_DISPATCH_CYCLES */
+ EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED */
+ EVENT_CONSTRAINT_END
+};
+
+static const struct event_constraint intel_nehalem_event_constraints[] =
+{
+ EVENT_CONSTRAINT(0x40, 0x3), /* L1D_CACHE_LD */
+ EVENT_CONSTRAINT(0x41, 0x3), /* L1D_CACHE_ST */
+ EVENT_CONSTRAINT(0x42, 0x3), /* L1D_CACHE_LOCK */
+ EVENT_CONSTRAINT(0x43, 0x3), /* L1D_ALL_REF */
+ EVENT_CONSTRAINT(0x4e, 0x3), /* L1D_PREFETCH */
+ EVENT_CONSTRAINT(0x4c, 0x3), /* LOAD_HIT_PRE */
+ EVENT_CONSTRAINT(0x51, 0x3), /* L1D */
+ EVENT_CONSTRAINT(0x52, 0x3), /* L1D_CACHE_PREFETCH_LOCK_FB_HIT */
+ EVENT_CONSTRAINT(0x53, 0x3), /* L1D_CACHE_LOCK_FB_HIT */
+ EVENT_CONSTRAINT(0xc5, 0x3), /* CACHE_LOCK_CYCLES */
+ EVENT_CONSTRAINT_END
+};
+
static u64 intel_pmu_event_map(int hw_event)
{
return intel_perfmon_event_map[hw_event];
@@ -469,7 +524,7 @@ static u64 intel_pmu_raw_event(u64 hw_event)
#define CORE_EVNTSEL_UNIT_MASK 0x0000FF00ULL
#define CORE_EVNTSEL_EDGE_MASK 0x00040000ULL
#define CORE_EVNTSEL_INV_MASK 0x00800000ULL
-#define CORE_EVNTSEL_REG_MASK 0xFF000000ULL
+#define CORE_EVNTSEL_REG_MASK 0xFF000000ULL
#define CORE_EVNTSEL_MASK \
(CORE_EVNTSEL_EVENT_MASK | \
@@ -932,6 +987,8 @@ static int __hw_perf_event_init(struct perf_event *event)
*/
hwc->config = ARCH_PERFMON_EVENTSEL_INT;
+ hwc->idx = -1;
+
/*
* Count user and OS events unless requested not to.
*/
@@ -1334,8 +1391,7 @@ static void amd_pmu_enable_event(struct hw_perf_event *hwc, int idx)
x86_pmu_enable_event(hwc, idx);
}
-static int
-fixed_mode_idx(struct perf_event *event, struct hw_perf_event *hwc)
+static int fixed_mode_idx(struct hw_perf_event *hwc)
{
unsigned int hw_event;
@@ -1349,6 +1405,12 @@ fixed_mode_idx(struct perf_event *event, struct hw_perf_event *hwc)
if (!x86_pmu.num_events_fixed)
return -1;
+ /*
+ * fixed counters do not take all possible filters
+ */
+ if (hwc->config & ARCH_PERFMON_EVENT_FILTER_MASK)
+ return -1;
+
if (unlikely(hw_event == x86_pmu.event_map(PERF_COUNT_HW_INSTRUCTIONS)))
return X86_PMC_IDX_FIXED_INSTRUCTIONS;
if (unlikely(hw_event == x86_pmu.event_map(PERF_COUNT_HW_CPU_CYCLES)))
@@ -1360,22 +1422,57 @@ fixed_mode_idx(struct perf_event *event, struct hw_perf_event *hwc)
}
/*
- * Find a PMC slot for the freshly enabled / scheduled in event:
+ * generic counter allocator: get next free counter
*/
-static int x86_pmu_enable(struct perf_event *event)
+static int
+gen_get_event_idx(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc)
+{
+ int idx;
+
+ idx = find_first_zero_bit(cpuc->used_mask, x86_pmu.num_events);
+ return idx == x86_pmu.num_events ? -1 : idx;
+}
+
+/*
+ * intel-specific counter allocator: check event constraints
+ */
+static int
+intel_get_event_idx(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc)
+{
+ const struct event_constraint *event_constraint;
+ int i, code;
+
+ if (!event_constraints)
+ goto skip;
+
+ code = hwc->config & CORE_EVNTSEL_EVENT_MASK;
+
+ for_each_event_constraint(event_constraint, event_constraints) {
+ if (code == event_constraint->code) {
+ for_each_bit(i, event_constraint->idxmsk, X86_PMC_IDX_MAX) {
+ if (!test_and_set_bit(i, cpuc->used_mask))
+ return i;
+ }
+ return -1;
+ }
+ }
+skip:
+ return gen_get_event_idx(cpuc, hwc);
+}
+
+static int
+x86_schedule_event(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc)
{
- struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
- struct hw_perf_event *hwc = &event->hw;
int idx;
- idx = fixed_mode_idx(event, hwc);
+ idx = fixed_mode_idx(hwc);
if (idx == X86_PMC_IDX_FIXED_BTS) {
/* BTS is already occupied. */
if (test_and_set_bit(idx, cpuc->used_mask))
return -EAGAIN;
hwc->config_base = 0;
- hwc->event_base = 0;
+ hwc->event_base = 0;
hwc->idx = idx;
} else if (idx >= 0) {
/*
@@ -1396,20 +1493,35 @@ static int x86_pmu_enable(struct perf_event *event)
} else {
idx = hwc->idx;
/* Try to get the previous generic event again */
- if (test_and_set_bit(idx, cpuc->used_mask)) {
+ if (idx == -1 || test_and_set_bit(idx, cpuc->used_mask)) {
try_generic:
- idx = find_first_zero_bit(cpuc->used_mask,
- x86_pmu.num_events);
- if (idx == x86_pmu.num_events)
+ idx = x86_pmu.get_event_idx(cpuc, hwc);
+ if (idx == -1)
return -EAGAIN;
set_bit(idx, cpuc->used_mask);
hwc->idx = idx;
}
- hwc->config_base = x86_pmu.eventsel;
- hwc->event_base = x86_pmu.perfctr;
+ hwc->config_base = x86_pmu.eventsel;
+ hwc->event_base = x86_pmu.perfctr;
}
+ return idx;
+}
+
+/*
+ * Find a PMC slot for the freshly enabled / scheduled in event:
+ */
+static int x86_pmu_enable(struct perf_event *event)
+{
+ struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+ struct hw_perf_event *hwc = &event->hw;
+ int idx;
+
+ idx = x86_schedule_event(cpuc, hwc);
+ if (idx < 0)
+ return idx;
+
perf_events_lapic_init();
x86_pmu.disable(hwc, idx);
@@ -1877,6 +1989,7 @@ static struct x86_pmu p6_pmu = {
*/
.event_bits = 32,
.event_mask = (1ULL << 32) - 1,
+ .get_event_idx = intel_get_event_idx,
};
static struct x86_pmu intel_pmu = {
@@ -1900,6 +2013,7 @@ static struct x86_pmu intel_pmu = {
.max_period = (1ULL << 31) - 1,
.enable_bts = intel_pmu_enable_bts,
.disable_bts = intel_pmu_disable_bts,
+ .get_event_idx = intel_get_event_idx,
};
static struct x86_pmu amd_pmu = {
@@ -1920,6 +2034,7 @@ static struct x86_pmu amd_pmu = {
.apic = 1,
/* use highest bit to detect overflow */
.max_period = (1ULL << 47) - 1,
+ .get_event_idx = gen_get_event_idx,
};
static int p6_pmu_init(void)
@@ -1932,10 +2047,12 @@ static int p6_pmu_init(void)
case 7:
case 8:
case 11: /* Pentium III */
+ event_constraints = intel_p6_event_constraints;
break;
case 9:
case 13:
/* Pentium M */
+ event_constraints = intel_p6_event_constraints;
break;
default:
pr_cont("unsupported p6 CPU model %d ",
@@ -2007,12 +2124,14 @@ static int intel_pmu_init(void)
sizeof(hw_cache_event_ids));
pr_cont("Core2 events, ");
+ event_constraints = intel_core_event_constraints;
break;
default:
case 26:
memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids,
sizeof(hw_cache_event_ids));
+ event_constraints = intel_nehalem_event_constraints;
pr_cont("Nehalem/Corei7 events, ");
break;
case 28:
@@ -2105,11 +2224,47 @@ static const struct pmu pmu = {
.unthrottle = x86_pmu_unthrottle,
};
+static int
+validate_event(struct cpu_hw_events *cpuc, struct perf_event *event)
+{
+ struct hw_perf_event fake_event = event->hw;
+
+ if (event->pmu != &pmu)
+ return 0;
+
+ return x86_schedule_event(cpuc, &fake_event);
+}
+
+static int validate_group(struct perf_event *event)
+{
+ struct perf_event *sibling, *leader = event->group_leader;
+ struct cpu_hw_events fake_pmu;
+
+ memset(&fake_pmu, 0, sizeof(fake_pmu));
+
+ if (!validate_event(&fake_pmu, leader))
+ return -ENOSPC;
+
+ list_for_each_entry(sibling, &leader->sibling_list, group_entry) {
+ if (!validate_event(&fake_pmu, sibling))
+ return -ENOSPC;
+ }
+
+ if (!validate_event(&fake_pmu, event))
+ return -ENOSPC;
+
+ return 0;
+}
+
const struct pmu *hw_perf_event_init(struct perf_event *event)
{
int err;
err = __hw_perf_event_init(event);
+ if (!err) {
+ if (event->group_leader != event)
+ err = validate_group(event);
+ }
if (err) {
if (event->destroy)
event->destroy(event);
diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c
index 6a52d4b36a30..7ef24a796992 100644
--- a/arch/x86/kernel/cpuid.c
+++ b/arch/x86/kernel/cpuid.c
@@ -116,21 +116,16 @@ static int cpuid_open(struct inode *inode, struct file *file)
{
unsigned int cpu;
struct cpuinfo_x86 *c;
- int ret = 0;
-
- lock_kernel();
cpu = iminor(file->f_path.dentry->d_inode);
- if (cpu >= nr_cpu_ids || !cpu_online(cpu)) {
- ret = -ENXIO; /* No such CPU */
- goto out;
- }
+ if (cpu >= nr_cpu_ids || !cpu_online(cpu))
+ return -ENXIO; /* No such CPU */
+
c = &cpu_data(cpu);
if (c->cpuid_level < 0)
- ret = -EIO; /* CPUID not supported */
-out:
- unlock_kernel();
- return ret;
+ return -EIO; /* CPUID not supported */
+
+ return 0;
}
/*
diff --git a/arch/x86/kernel/crash_dump_32.c b/arch/x86/kernel/crash_dump_32.c
index f7cdb3b457aa..cd97ce18c29d 100644
--- a/arch/x86/kernel/crash_dump_32.c
+++ b/arch/x86/kernel/crash_dump_32.c
@@ -16,6 +16,22 @@ static void *kdump_buf_page;
/* Stores the physical address of elf header of crash image. */
unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX;
+static inline bool is_crashed_pfn_valid(unsigned long pfn)
+{
+#ifndef CONFIG_X86_PAE
+ /*
+ * non-PAE kdump kernel executed from a PAE one will crop high pte
+ * bits and poke unwanted space counting again from address 0, we
+ * don't want that. pte must fit into unsigned long. In fact the
+ * test checks high 12 bits for being zero (pfn will be shifted left
+ * by PAGE_SHIFT).
+ */
+ return pte_pfn(pfn_pte(pfn, __pgprot(0))) == pfn;
+#else
+ return true;
+#endif
+}
+
/**
* copy_oldmem_page - copy one page from "oldmem"
* @pfn: page frame number to be copied
@@ -41,6 +57,9 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
if (!csize)
return 0;
+ if (!is_crashed_pfn_valid(pfn))
+ return -EFAULT;
+
vaddr = kmap_atomic_pfn(pfn, KM_PTE0);
if (!userbuf) {
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index 2d8a371d4339..b8ce165dde5d 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -268,11 +268,12 @@ int __kprobes __die(const char *str, struct pt_regs *regs, long err)
show_registers(regs);
#ifdef CONFIG_X86_32
- sp = (unsigned long) (&regs->sp);
- savesegment(ss, ss);
- if (user_mode(regs)) {
+ if (user_mode_vm(regs)) {
sp = regs->sp;
ss = regs->ss & 0xffff;
+ } else {
+ sp = kernel_stack_pointer(regs);
+ savesegment(ss, ss);
}
printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
print_symbol("%s", regs->ip);
diff --git a/arch/x86/kernel/efi.c b/arch/x86/kernel/efi.c
index ad5bd988fb79..cdcfb122f256 100644
--- a/arch/x86/kernel/efi.c
+++ b/arch/x86/kernel/efi.c
@@ -454,8 +454,10 @@ void __init efi_init(void)
if (add_efi_memmap)
do_add_efi_memmap();
+#ifdef CONFIG_X86_32
x86_platform.get_wallclock = efi_get_time;
x86_platform.set_wallclock = efi_set_rtc_mmss;
+#endif
/* Setup for EFI runtime service */
reboot_type = BOOT_EFI;
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index c097e7d607c6..50b9c220e121 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -334,6 +334,10 @@ ENTRY(ret_from_fork)
END(ret_from_fork)
/*
+ * Interrupt exit functions should be protected against kprobes
+ */
+ .pushsection .kprobes.text, "ax"
+/*
* Return to user mode is not as complex as all this looks,
* but we want the default path for a system call return to
* go as quickly as possible which is why some of this is
@@ -383,6 +387,10 @@ need_resched:
END(resume_kernel)
#endif
CFI_ENDPROC
+/*
+ * End of kprobes section
+ */
+ .popsection
/* SYSENTER_RETURN points to after the "sysenter" instruction in
the vsyscall page. See vsyscall-sysentry.S, which defines the symbol. */
@@ -513,6 +521,10 @@ sysexit_audit:
PTGS_TO_GS_EX
ENDPROC(ia32_sysenter_target)
+/*
+ * syscall stub including irq exit should be protected against kprobes
+ */
+ .pushsection .kprobes.text, "ax"
# system call handler stub
ENTRY(system_call)
RING0_INT_FRAME # can't unwind into user space anyway
@@ -705,6 +717,10 @@ syscall_badsys:
jmp resume_userspace
END(syscall_badsys)
CFI_ENDPROC
+/*
+ * End of kprobes section
+ */
+ .popsection
/*
* System calls that need a pt_regs pointer.
@@ -814,6 +830,10 @@ common_interrupt:
ENDPROC(common_interrupt)
CFI_ENDPROC
+/*
+ * Irq entries should be protected against kprobes
+ */
+ .pushsection .kprobes.text, "ax"
#define BUILD_INTERRUPT3(name, nr, fn) \
ENTRY(name) \
RING0_INT_FRAME; \
@@ -980,6 +1000,10 @@ ENTRY(spurious_interrupt_bug)
jmp error_code
CFI_ENDPROC
END(spurious_interrupt_bug)
+/*
+ * End of kprobes section
+ */
+ .popsection
ENTRY(kernel_thread_helper)
pushl $0 # fake return address for unwinder
@@ -1185,17 +1209,14 @@ END(ftrace_graph_caller)
.globl return_to_handler
return_to_handler:
- pushl $0
pushl %eax
- pushl %ecx
pushl %edx
movl %ebp, %eax
call ftrace_return_to_handler
- movl %eax, 0xc(%esp)
+ movl %eax, %ecx
popl %edx
- popl %ecx
popl %eax
- ret
+ jmp *%ecx
#endif
.section .rodata,"a"
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index b5c061f8f358..7fdd8d601eff 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -155,11 +155,11 @@ GLOBAL(return_to_handler)
call ftrace_return_to_handler
- movq %rax, 16(%rsp)
+ movq %rax, %rdi
movq 8(%rsp), %rdx
movq (%rsp), %rax
- addq $16, %rsp
- retq
+ addq $24, %rsp
+ jmp *%rdi
#endif
@@ -803,6 +803,10 @@ END(interrupt)
call \func
.endm
+/*
+ * Interrupt entry/exit should be protected against kprobes
+ */
+ .pushsection .kprobes.text, "ax"
/*
* The interrupt stubs push (~vector+0x80) onto the stack and
* then jump to common_interrupt.
@@ -941,6 +945,10 @@ ENTRY(retint_kernel)
CFI_ENDPROC
END(common_interrupt)
+/*
+ * End of kprobes section
+ */
+ .popsection
/*
* APIC interrupts.
@@ -969,8 +977,8 @@ apicinterrupt UV_BAU_MESSAGE \
#endif
apicinterrupt LOCAL_TIMER_VECTOR \
apic_timer_interrupt smp_apic_timer_interrupt
-apicinterrupt GENERIC_INTERRUPT_VECTOR \
- generic_interrupt smp_generic_interrupt
+apicinterrupt X86_PLATFORM_IPI_VECTOR \
+ x86_platform_ipi smp_x86_platform_ipi
#ifdef CONFIG_SMP
apicinterrupt INVALIDATE_TLB_VECTOR_START+0 \
@@ -1491,12 +1499,17 @@ error_kernelspace:
leaq irq_return(%rip),%rcx
cmpq %rcx,RIP+8(%rsp)
je error_swapgs
- movl %ecx,%ecx /* zero extend */
- cmpq %rcx,RIP+8(%rsp)
- je error_swapgs
+ movl %ecx,%eax /* zero extend */
+ cmpq %rax,RIP+8(%rsp)
+ je bstep_iret
cmpq $gs_change,RIP+8(%rsp)
je error_swapgs
jmp error_sti
+
+bstep_iret:
+ /* Fix truncated RIP */
+ movq %rcx,RIP+8(%rsp)
+ je error_swapgs
END(error_entry)
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 9dbb527e1652..5a1b9758fd62 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -9,6 +9,8 @@
* the dangers of modifying code on the run.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/spinlock.h>
#include <linux/hardirq.h>
#include <linux/uaccess.h>
@@ -336,15 +338,15 @@ int __init ftrace_dyn_arch_init(void *data)
switch (faulted) {
case 0:
- pr_info("ftrace: converting mcount calls to 0f 1f 44 00 00\n");
+ pr_info("converting mcount calls to 0f 1f 44 00 00\n");
memcpy(ftrace_nop, ftrace_test_p6nop, MCOUNT_INSN_SIZE);
break;
case 1:
- pr_info("ftrace: converting mcount calls to 66 66 66 66 90\n");
+ pr_info("converting mcount calls to 66 66 66 66 90\n");
memcpy(ftrace_nop, ftrace_test_nop5, MCOUNT_INSN_SIZE);
break;
case 2:
- pr_info("ftrace: converting mcount calls to jmp . + 5\n");
+ pr_info("converting mcount calls to jmp . + 5\n");
memcpy(ftrace_nop, ftrace_test_jmp, MCOUNT_INSN_SIZE);
break;
}
@@ -468,82 +470,10 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
#ifdef CONFIG_FTRACE_SYSCALLS
-extern unsigned long __start_syscalls_metadata[];
-extern unsigned long __stop_syscalls_metadata[];
extern unsigned long *sys_call_table;
-static struct syscall_metadata **syscalls_metadata;
-
-static struct syscall_metadata *find_syscall_meta(unsigned long *syscall)
-{
- struct syscall_metadata *start;
- struct syscall_metadata *stop;
- char str[KSYM_SYMBOL_LEN];
-
-
- start = (struct syscall_metadata *)__start_syscalls_metadata;
- stop = (struct syscall_metadata *)__stop_syscalls_metadata;
- kallsyms_lookup((unsigned long) syscall, NULL, NULL, NULL, str);
-
- for ( ; start < stop; start++) {
- if (start->name && !strcmp(start->name, str))
- return start;
- }
- return NULL;
-}
-
-struct syscall_metadata *syscall_nr_to_meta(int nr)
-{
- if (!syscalls_metadata || nr >= NR_syscalls || nr < 0)
- return NULL;
-
- return syscalls_metadata[nr];
-}
-
-int syscall_name_to_nr(char *name)
+unsigned long __init arch_syscall_addr(int nr)
{
- int i;
-
- if (!syscalls_metadata)
- return -1;
-
- for (i = 0; i < NR_syscalls; i++) {
- if (syscalls_metadata[i]) {
- if (!strcmp(syscalls_metadata[i]->name, name))
- return i;
- }
- }
- return -1;
-}
-
-void set_syscall_enter_id(int num, int id)
-{
- syscalls_metadata[num]->enter_id = id;
-}
-
-void set_syscall_exit_id(int num, int id)
-{
- syscalls_metadata[num]->exit_id = id;
-}
-
-static int __init arch_init_ftrace_syscalls(void)
-{
- int i;
- struct syscall_metadata *meta;
- unsigned long **psys_syscall_table = &sys_call_table;
-
- syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) *
- NR_syscalls, GFP_KERNEL);
- if (!syscalls_metadata) {
- WARN_ON(1);
- return -ENOMEM;
- }
-
- for (i = 0; i < NR_syscalls; i++) {
- meta = find_syscall_meta(psys_syscall_table[i]);
- syscalls_metadata[i] = meta;
- }
- return 0;
+ return (unsigned long)(&sys_call_table)[nr];
}
-arch_initcall(arch_init_ftrace_syscalls);
#endif
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 780cd928fcd5..b55ee4ff509f 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -262,11 +262,11 @@ ENTRY(secondary_startup_64)
.quad x86_64_start_kernel
ENTRY(initial_gs)
.quad INIT_PER_CPU_VAR(irq_stack_union)
- __FINITDATA
ENTRY(stack_start)
.quad init_thread_union+THREAD_SIZE-8
.word 0
+ __FINITDATA
bad_address:
jmp bad_address
@@ -340,6 +340,7 @@ ENTRY(name)
i = i + 1 ; \
.endr
+ .data
/*
* This default setting generates an ident mapping at address 0x100000
* and a mapping for the kernel that precisely maps virtual address
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index dedc2bddf7a5..7f024ff47d1d 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -33,6 +33,7 @@
* HPET address is set in acpi/boot.c, when an ACPI entry exists
*/
unsigned long hpet_address;
+u8 hpet_blockid; /* OS timer block num */
#ifdef CONFIG_PCI_MSI
static unsigned long hpet_num_timers;
#endif
@@ -47,12 +48,12 @@ struct hpet_dev {
char name[10];
};
-unsigned long hpet_readl(unsigned long a)
+inline unsigned int hpet_readl(unsigned int a)
{
return readl(hpet_virt_address + a);
}
-static inline void hpet_writel(unsigned long d, unsigned long a)
+static inline void hpet_writel(unsigned int d, unsigned int a)
{
writel(d, hpet_virt_address + a);
}
@@ -167,7 +168,7 @@ do { \
static void hpet_reserve_msi_timers(struct hpet_data *hd);
-static void hpet_reserve_platform_timers(unsigned long id)
+static void hpet_reserve_platform_timers(unsigned int id)
{
struct hpet __iomem *hpet = hpet_virt_address;
struct hpet_timer __iomem *timer = &hpet->hpet_timers[2];
@@ -205,7 +206,7 @@ static void hpet_reserve_platform_timers(unsigned long id)
}
#else
-static void hpet_reserve_platform_timers(unsigned long id) { }
+static void hpet_reserve_platform_timers(unsigned int id) { }
#endif
/*
@@ -246,7 +247,7 @@ static void hpet_reset_counter(void)
static void hpet_start_counter(void)
{
- unsigned long cfg = hpet_readl(HPET_CFG);
+ unsigned int cfg = hpet_readl(HPET_CFG);
cfg |= HPET_CFG_ENABLE;
hpet_writel(cfg, HPET_CFG);
}
@@ -271,7 +272,7 @@ static void hpet_resume_counter(void)
static void hpet_enable_legacy_int(void)
{
- unsigned long cfg = hpet_readl(HPET_CFG);
+ unsigned int cfg = hpet_readl(HPET_CFG);
cfg |= HPET_CFG_LEGACY;
hpet_writel(cfg, HPET_CFG);
@@ -314,7 +315,7 @@ static int hpet_setup_msi_irq(unsigned int irq);
static void hpet_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt, int timer)
{
- unsigned long cfg, cmp, now;
+ unsigned int cfg, cmp, now;
uint64_t delta;
switch (mode) {
@@ -323,7 +324,7 @@ static void hpet_set_mode(enum clock_event_mode mode,
delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * evt->mult;
delta >>= evt->shift;
now = hpet_readl(HPET_COUNTER);
- cmp = now + (unsigned long) delta;
+ cmp = now + (unsigned int) delta;
cfg = hpet_readl(HPET_Tn_CFG(timer));
/* Make sure we use edge triggered interrupts */
cfg &= ~HPET_TN_LEVEL;
@@ -339,7 +340,7 @@ static void hpet_set_mode(enum clock_event_mode mode,
* (See AMD-8111 HyperTransport I/O Hub Data Sheet,
* Publication # 24674)
*/
- hpet_writel((unsigned long) delta, HPET_Tn_CMP(timer));
+ hpet_writel((unsigned int) delta, HPET_Tn_CMP(timer));
hpet_start_counter();
hpet_print_config();
break;
@@ -387,9 +388,9 @@ static int hpet_next_event(unsigned long delta,
* what we wrote hit the chip before we compare it to the
* counter.
*/
- WARN_ON_ONCE((u32)hpet_readl(HPET_Tn_CMP(timer)) != cnt);
+ WARN_ON_ONCE(hpet_readl(HPET_Tn_CMP(timer)) != cnt);
- return (s32)((u32)hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0;
+ return (s32)(hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0;
}
static void hpet_legacy_set_mode(enum clock_event_mode mode,
@@ -415,7 +416,7 @@ static struct hpet_dev *hpet_devs;
void hpet_msi_unmask(unsigned int irq)
{
struct hpet_dev *hdev = get_irq_data(irq);
- unsigned long cfg;
+ unsigned int cfg;
/* unmask it */
cfg = hpet_readl(HPET_Tn_CFG(hdev->num));
@@ -425,7 +426,7 @@ void hpet_msi_unmask(unsigned int irq)
void hpet_msi_mask(unsigned int irq)
{
- unsigned long cfg;
+ unsigned int cfg;
struct hpet_dev *hdev = get_irq_data(irq);
/* mask it */
@@ -467,7 +468,7 @@ static int hpet_msi_next_event(unsigned long delta,
static int hpet_setup_msi_irq(unsigned int irq)
{
- if (arch_setup_hpet_msi(irq)) {
+ if (arch_setup_hpet_msi(irq, hpet_blockid)) {
destroy_irq(irq);
return -EINVAL;
}
@@ -584,6 +585,8 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)
unsigned int num_timers_used = 0;
int i;
+ if (boot_cpu_has(X86_FEATURE_ARAT))
+ return;
id = hpet_readl(HPET_ID);
num_timers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT);
@@ -598,7 +601,7 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)
for (i = start_timer; i < num_timers - RESERVE_TIMERS; i++) {
struct hpet_dev *hdev = &hpet_devs[num_timers_used];
- unsigned long cfg = hpet_readl(HPET_Tn_CFG(i));
+ unsigned int cfg = hpet_readl(HPET_Tn_CFG(i));
/* Only consider HPET timer with MSI support */
if (!(cfg & HPET_TN_FSB_CAP))
@@ -813,7 +816,7 @@ static int hpet_clocksource_register(void)
*/
int __init hpet_enable(void)
{
- unsigned long id;
+ unsigned int id;
int i;
if (!is_hpet_capable())
@@ -872,10 +875,8 @@ int __init hpet_enable(void)
if (id & HPET_ID_LEGSUP) {
hpet_legacy_clockevent_register();
- hpet_msi_capability_lookup(2);
return 1;
}
- hpet_msi_capability_lookup(0);
return 0;
out_nohpet:
@@ -908,9 +909,17 @@ static __init int hpet_late_init(void)
if (!hpet_virt_address)
return -ENODEV;
+ if (hpet_readl(HPET_ID) & HPET_ID_LEGSUP)
+ hpet_msi_capability_lookup(2);
+ else
+ hpet_msi_capability_lookup(0);
+
hpet_reserve_platform_timers(hpet_readl(HPET_ID));
hpet_print_config();
+ if (boot_cpu_has(X86_FEATURE_ARAT))
+ return 0;
+
for_each_online_cpu(cpu) {
hpet_cpuhp_notify(NULL, CPU_ONLINE, (void *)(long)cpu);
}
@@ -925,7 +934,7 @@ fs_initcall(hpet_late_init);
void hpet_disable(void)
{
if (is_hpet_capable()) {
- unsigned long cfg = hpet_readl(HPET_CFG);
+ unsigned int cfg = hpet_readl(HPET_CFG);
if (hpet_legacy_int_enabled) {
cfg &= ~HPET_CFG_LEGACY;
@@ -965,8 +974,8 @@ static int hpet_prev_update_sec;
static struct rtc_time hpet_alarm_time;
static unsigned long hpet_pie_count;
static u32 hpet_t1_cmp;
-static unsigned long hpet_default_delta;
-static unsigned long hpet_pie_delta;
+static u32 hpet_default_delta;
+static u32 hpet_pie_delta;
static unsigned long hpet_pie_limit;
static rtc_irq_handler irq_handler;
@@ -1017,7 +1026,8 @@ EXPORT_SYMBOL_GPL(hpet_unregister_irq_handler);
*/
int hpet_rtc_timer_init(void)
{
- unsigned long cfg, cnt, delta, flags;
+ unsigned int cfg, cnt, delta;
+ unsigned long flags;
if (!is_hpet_enabled())
return 0;
@@ -1027,7 +1037,7 @@ int hpet_rtc_timer_init(void)
clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC;
clc >>= hpet_clockevent.shift + DEFAULT_RTC_SHIFT;
- hpet_default_delta = (unsigned long) clc;
+ hpet_default_delta = clc;
}
if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit)
@@ -1113,7 +1123,7 @@ int hpet_set_periodic_freq(unsigned long freq)
clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC;
do_div(clc, freq);
clc >>= hpet_clockevent.shift;
- hpet_pie_delta = (unsigned long) clc;
+ hpet_pie_delta = clc;
}
return 1;
}
@@ -1127,7 +1137,7 @@ EXPORT_SYMBOL_GPL(hpet_rtc_dropped_irq);
static void hpet_rtc_timer_reinit(void)
{
- unsigned long cfg, delta;
+ unsigned int cfg, delta;
int lost_ints = -1;
if (unlikely(!hpet_rtc_flags)) {
diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c
index 99c4d308f16b..bad4f22f1146 100644
--- a/arch/x86/kernel/ioport.c
+++ b/arch/x86/kernel/ioport.c
@@ -119,11 +119,10 @@ static int do_iopl(unsigned int level, struct pt_regs *regs)
return 0;
}
-#ifdef CONFIG_X86_32
-long sys_iopl(struct pt_regs *regs)
+asmlinkage long sys_iopl(unsigned int level)
{
- unsigned int level = regs->bx;
struct thread_struct *t = &current->thread;
+ struct pt_regs *regs = task_pt_regs(current);
int rc;
rc = do_iopl(level, regs);
@@ -135,9 +134,3 @@ long sys_iopl(struct pt_regs *regs)
out:
return rc;
}
-#else
-asmlinkage long sys_iopl(unsigned int level, struct pt_regs *regs)
-{
- return do_iopl(level, regs);
-}
-#endif
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index 04bbd5278568..0239994d10c5 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -18,7 +18,7 @@
atomic_t irq_err_count;
/* Function pointer for generic interrupt vector handling */
-void (*generic_interrupt_extension)(void) = NULL;
+void (*x86_platform_ipi_callback)(void) = NULL;
/*
* 'what should we do if we get a hw irq event on an illegal vector'.
@@ -72,10 +72,10 @@ static int show_other_interrupts(struct seq_file *p, int prec)
seq_printf(p, "%10u ", irq_stats(j)->apic_pending_irqs);
seq_printf(p, " Performance pending work\n");
#endif
- if (generic_interrupt_extension) {
+ if (x86_platform_ipi_callback) {
seq_printf(p, "%*s: ", prec, "PLT");
for_each_online_cpu(j)
- seq_printf(p, "%10u ", irq_stats(j)->generic_irqs);
+ seq_printf(p, "%10u ", irq_stats(j)->x86_platform_ipis);
seq_printf(p, " Platform interrupts\n");
}
#ifdef CONFIG_SMP
@@ -187,8 +187,8 @@ u64 arch_irq_stat_cpu(unsigned int cpu)
sum += irq_stats(cpu)->apic_perf_irqs;
sum += irq_stats(cpu)->apic_pending_irqs;
#endif
- if (generic_interrupt_extension)
- sum += irq_stats(cpu)->generic_irqs;
+ if (x86_platform_ipi_callback)
+ sum += irq_stats(cpu)->x86_platform_ipis;
#ifdef CONFIG_SMP
sum += irq_stats(cpu)->irq_resched_count;
sum += irq_stats(cpu)->irq_call_count;
@@ -251,9 +251,9 @@ unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
}
/*
- * Handler for GENERIC_INTERRUPT_VECTOR.
+ * Handler for X86_PLATFORM_IPI_VECTOR.
*/
-void smp_generic_interrupt(struct pt_regs *regs)
+void smp_x86_platform_ipi(struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
@@ -263,10 +263,10 @@ void smp_generic_interrupt(struct pt_regs *regs)
irq_enter();
- inc_irq_stat(generic_irqs);
+ inc_irq_stat(x86_platform_ipis);
- if (generic_interrupt_extension)
- generic_interrupt_extension();
+ if (x86_platform_ipi_callback)
+ x86_platform_ipi_callback();
irq_exit();
diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c
index 40f30773fb29..d5932226614f 100644
--- a/arch/x86/kernel/irqinit.c
+++ b/arch/x86/kernel/irqinit.c
@@ -200,8 +200,8 @@ static void __init apic_intr_init(void)
/* self generated IPI for local APIC timer */
alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
- /* generic IPI for platform specific use */
- alloc_intr_gate(GENERIC_INTERRUPT_VECTOR, generic_interrupt);
+ /* IPI for X86 platform specific use */
+ alloc_intr_gate(X86_PLATFORM_IPI_VECTOR, x86_platform_ipi);
/* IPI vectors for APIC spurious and error interrupts */
alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c
index 8d82a77a3f3b..9fbae2eafaf7 100644
--- a/arch/x86/kernel/kgdb.c
+++ b/arch/x86/kernel/kgdb.c
@@ -85,10 +85,15 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
gdb_regs[GDB_DS] = regs->ds;
gdb_regs[GDB_ES] = regs->es;
gdb_regs[GDB_CS] = regs->cs;
- gdb_regs[GDB_SS] = __KERNEL_DS;
gdb_regs[GDB_FS] = 0xFFFF;
gdb_regs[GDB_GS] = 0xFFFF;
- gdb_regs[GDB_SP] = (int)&regs->sp;
+ if (user_mode_vm(regs)) {
+ gdb_regs[GDB_SS] = regs->ss;
+ gdb_regs[GDB_SP] = regs->sp;
+ } else {
+ gdb_regs[GDB_SS] = __KERNEL_DS;
+ gdb_regs[GDB_SP] = kernel_stack_pointer(regs);
+ }
#else
gdb_regs[GDB_R8] = regs->r8;
gdb_regs[GDB_R9] = regs->r9;
@@ -101,7 +106,7 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
gdb_regs32[GDB_PS] = regs->flags;
gdb_regs32[GDB_CS] = regs->cs;
gdb_regs32[GDB_SS] = regs->ss;
- gdb_regs[GDB_SP] = regs->sp;
+ gdb_regs[GDB_SP] = kernel_stack_pointer(regs);
#endif
}
@@ -220,8 +225,7 @@ static void kgdb_correct_hw_break(void)
dr7 |= ((breakinfo[breakno].len << 2) |
breakinfo[breakno].type) <<
((breakno << 2) + 16);
- if (breakno >= 0 && breakno <= 3)
- set_debugreg(breakinfo[breakno].addr, breakno);
+ set_debugreg(breakinfo[breakno].addr, breakno);
} else {
if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c
index 7b5169d2b000..01b6297b8bca 100644
--- a/arch/x86/kernel/kprobes.c
+++ b/arch/x86/kernel/kprobes.c
@@ -48,31 +48,21 @@
#include <linux/preempt.h>
#include <linux/module.h>
#include <linux/kdebug.h>
+#include <linux/kallsyms.h>
#include <asm/cacheflush.h>
#include <asm/desc.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/alternative.h>
+#include <asm/insn.h>
void jprobe_return_end(void);
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
-#ifdef CONFIG_X86_64
-#define stack_addr(regs) ((unsigned long *)regs->sp)
-#else
-/*
- * "&regs->sp" looks wrong, but it's correct for x86_32. x86_32 CPUs
- * don't save the ss and esp registers if the CPU is already in kernel
- * mode when it traps. So for kprobes, regs->sp and regs->ss are not
- * the [nonexistent] saved stack pointer and ss register, but rather
- * the top 8 bytes of the pre-int3 stack. So &regs->sp happens to
- * point to the top of the pre-int3 stack.
- */
-#define stack_addr(regs) ((unsigned long *)&regs->sp)
-#endif
+#define stack_addr(regs) ((unsigned long *)kernel_stack_pointer(regs))
#define W(row, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf)\
(((b0##UL << 0x0)|(b1##UL << 0x1)|(b2##UL << 0x2)|(b3##UL << 0x3) | \
@@ -106,50 +96,6 @@ static const u32 twobyte_is_boostable[256 / 32] = {
/* ----------------------------------------------- */
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
};
-static const u32 onebyte_has_modrm[256 / 32] = {
- /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
- /* ----------------------------------------------- */
- W(0x00, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 00 */
- W(0x10, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) , /* 10 */
- W(0x20, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 20 */
- W(0x30, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) , /* 30 */
- W(0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* 40 */
- W(0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 50 */
- W(0x60, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0) | /* 60 */
- W(0x70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 70 */
- W(0x80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */
- W(0x90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 90 */
- W(0xa0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* a0 */
- W(0xb0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* b0 */
- W(0xc0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0) | /* c0 */
- W(0xd0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */
- W(0xe0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* e0 */
- W(0xf0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1) /* f0 */
- /* ----------------------------------------------- */
- /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
-};
-static const u32 twobyte_has_modrm[256 / 32] = {
- /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
- /* ----------------------------------------------- */
- W(0x00, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1) | /* 0f */
- W(0x10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0) , /* 1f */
- W(0x20, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1) | /* 2f */
- W(0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 3f */
- W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 4f */
- W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 5f */
- W(0x60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 6f */
- W(0x70, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1) , /* 7f */
- W(0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* 8f */
- W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 9f */
- W(0xa0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1) | /* af */
- W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1) , /* bf */
- W(0xc0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0) | /* cf */
- W(0xd0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* df */
- W(0xe0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* ef */
- W(0xf0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) /* ff */
- /* ----------------------------------------------- */
- /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
-};
#undef W
struct kretprobe_blackpoint kretprobe_blacklist[] = {
@@ -244,6 +190,75 @@ retry:
}
}
+/* Recover the probed instruction at addr for further analysis. */
+static int recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr)
+{
+ struct kprobe *kp;
+ kp = get_kprobe((void *)addr);
+ if (!kp)
+ return -EINVAL;
+
+ /*
+ * Basically, kp->ainsn.insn has an original instruction.
+ * However, RIP-relative instruction can not do single-stepping
+ * at different place, fix_riprel() tweaks the displacement of
+ * that instruction. In that case, we can't recover the instruction
+ * from the kp->ainsn.insn.
+ *
+ * On the other hand, kp->opcode has a copy of the first byte of
+ * the probed instruction, which is overwritten by int3. And
+ * the instruction at kp->addr is not modified by kprobes except
+ * for the first byte, we can recover the original instruction
+ * from it and kp->opcode.
+ */
+ memcpy(buf, kp->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
+ buf[0] = kp->opcode;
+ return 0;
+}
+
+/* Dummy buffers for kallsyms_lookup */
+static char __dummy_buf[KSYM_NAME_LEN];
+
+/* Check if paddr is at an instruction boundary */
+static int __kprobes can_probe(unsigned long paddr)
+{
+ int ret;
+ unsigned long addr, offset = 0;
+ struct insn insn;
+ kprobe_opcode_t buf[MAX_INSN_SIZE];
+
+ if (!kallsyms_lookup(paddr, NULL, &offset, NULL, __dummy_buf))
+ return 0;
+
+ /* Decode instructions */
+ addr = paddr - offset;
+ while (addr < paddr) {
+ kernel_insn_init(&insn, (void *)addr);
+ insn_get_opcode(&insn);
+
+ /*
+ * Check if the instruction has been modified by another
+ * kprobe, in which case we replace the breakpoint by the
+ * original instruction in our buffer.
+ */
+ if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION) {
+ ret = recover_probed_instruction(buf, addr);
+ if (ret)
+ /*
+ * Another debugging subsystem might insert
+ * this breakpoint. In that case, we can't
+ * recover it.
+ */
+ return 0;
+ kernel_insn_init(&insn, buf);
+ }
+ insn_get_length(&insn);
+ addr += insn.length;
+ }
+
+ return (addr == paddr);
+}
+
/*
* Returns non-zero if opcode modifies the interrupt flag.
*/
@@ -277,68 +292,30 @@ static int __kprobes is_IF_modifier(kprobe_opcode_t *insn)
static void __kprobes fix_riprel(struct kprobe *p)
{
#ifdef CONFIG_X86_64
- u8 *insn = p->ainsn.insn;
- s64 disp;
- int need_modrm;
-
- /* Skip legacy instruction prefixes. */
- while (1) {
- switch (*insn) {
- case 0x66:
- case 0x67:
- case 0x2e:
- case 0x3e:
- case 0x26:
- case 0x64:
- case 0x65:
- case 0x36:
- case 0xf0:
- case 0xf3:
- case 0xf2:
- ++insn;
- continue;
- }
- break;
- }
+ struct insn insn;
+ kernel_insn_init(&insn, p->ainsn.insn);
- /* Skip REX instruction prefix. */
- if (is_REX_prefix(insn))
- ++insn;
-
- if (*insn == 0x0f) {
- /* Two-byte opcode. */
- ++insn;
- need_modrm = test_bit(*insn,
- (unsigned long *)twobyte_has_modrm);
- } else
- /* One-byte opcode. */
- need_modrm = test_bit(*insn,
- (unsigned long *)onebyte_has_modrm);
-
- if (need_modrm) {
- u8 modrm = *++insn;
- if ((modrm & 0xc7) == 0x05) {
- /* %rip+disp32 addressing mode */
- /* Displacement follows ModRM byte. */
- ++insn;
- /*
- * The copied instruction uses the %rip-relative
- * addressing mode. Adjust the displacement for the
- * difference between the original location of this
- * instruction and the location of the copy that will
- * actually be run. The tricky bit here is making sure
- * that the sign extension happens correctly in this
- * calculation, since we need a signed 32-bit result to
- * be sign-extended to 64 bits when it's added to the
- * %rip value and yield the same 64-bit result that the
- * sign-extension of the original signed 32-bit
- * displacement would have given.
- */
- disp = (u8 *) p->addr + *((s32 *) insn) -
- (u8 *) p->ainsn.insn;
- BUG_ON((s64) (s32) disp != disp); /* Sanity check. */
- *(s32 *)insn = (s32) disp;
- }
+ if (insn_rip_relative(&insn)) {
+ s64 newdisp;
+ u8 *disp;
+ insn_get_displacement(&insn);
+ /*
+ * The copied instruction uses the %rip-relative addressing
+ * mode. Adjust the displacement for the difference between
+ * the original location of this instruction and the location
+ * of the copy that will actually be run. The tricky bit here
+ * is making sure that the sign extension happens correctly in
+ * this calculation, since we need a signed 32-bit result to
+ * be sign-extended to 64 bits when it's added to the %rip
+ * value and yield the same 64-bit result that the sign-
+ * extension of the original signed 32-bit displacement would
+ * have given.
+ */
+ newdisp = (u8 *) p->addr + (s64) insn.displacement.value -
+ (u8 *) p->ainsn.insn;
+ BUG_ON((s64) (s32) newdisp != newdisp); /* Sanity check. */
+ disp = (u8 *) p->ainsn.insn + insn_offset_displacement(&insn);
+ *(s32 *) disp = (s32) newdisp;
}
#endif
}
@@ -359,6 +336,8 @@ static void __kprobes arch_copy_kprobe(struct kprobe *p)
int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
+ if (!can_probe((unsigned long)p->addr))
+ return -EILSEQ;
/* insn: must be on special executable page on x86. */
p->ainsn.insn = get_insn_slot();
if (!p->ainsn.insn)
@@ -472,17 +451,6 @@ static int __kprobes reenter_kprobe(struct kprobe *p, struct pt_regs *regs,
{
switch (kcb->kprobe_status) {
case KPROBE_HIT_SSDONE:
-#ifdef CONFIG_X86_64
- /* TODO: Provide re-entrancy from post_kprobes_handler() and
- * avoid exception stack corruption while single-stepping on
- * the instruction of the new probe.
- */
- arch_disarm_kprobe(p);
- regs->ip = (unsigned long)p->addr;
- reset_current_kprobe();
- preempt_enable_no_resched();
- break;
-#endif
case KPROBE_HIT_ACTIVE:
save_previous_kprobe(kcb);
set_current_kprobe(p, regs, kcb);
@@ -491,18 +459,16 @@ static int __kprobes reenter_kprobe(struct kprobe *p, struct pt_regs *regs,
kcb->kprobe_status = KPROBE_REENTER;
break;
case KPROBE_HIT_SS:
- if (p == kprobe_running()) {
- regs->flags &= ~X86_EFLAGS_TF;
- regs->flags |= kcb->kprobe_saved_flags;
- return 0;
- } else {
- /* A probe has been hit in the codepath leading up
- * to, or just after, single-stepping of a probed
- * instruction. This entire codepath should strictly
- * reside in .kprobes.text section. Raise a warning
- * to highlight this peculiar case.
- */
- }
+ /* A probe has been hit in the codepath leading up to, or just
+ * after, single-stepping of a probed instruction. This entire
+ * codepath should strictly reside in .kprobes.text section.
+ * Raise a BUG or we'll continue in an endless reentering loop
+ * and eventually a stack overflow.
+ */
+ printk(KERN_WARNING "Unrecoverable kprobe detected at %p.\n",
+ p->addr);
+ dump_kprobe(p);
+ BUG();
default:
/* impossible cases */
WARN_ON(1);
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c
index 378e9a8f1bf8..2bcad3926edb 100644
--- a/arch/x86/kernel/microcode_core.c
+++ b/arch/x86/kernel/microcode_core.c
@@ -73,7 +73,6 @@
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/capability.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
@@ -201,7 +200,6 @@ static int do_microcode_update(const void __user *buf, size_t size)
static int microcode_open(struct inode *unused1, struct file *unused2)
{
- cycle_kernel_lock();
return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
}
diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c
index 6a3cefc7dda1..553449951b84 100644
--- a/arch/x86/kernel/msr.c
+++ b/arch/x86/kernel/msr.c
@@ -174,21 +174,17 @@ static int msr_open(struct inode *inode, struct file *file)
{
unsigned int cpu = iminor(file->f_path.dentry->d_inode);
struct cpuinfo_x86 *c = &cpu_data(cpu);
- int ret = 0;
- lock_kernel();
cpu = iminor(file->f_path.dentry->d_inode);
- if (cpu >= nr_cpu_ids || !cpu_online(cpu)) {
- ret = -ENXIO; /* No such CPU */
- goto out;
- }
+ if (cpu >= nr_cpu_ids || !cpu_online(cpu))
+ return -ENXIO; /* No such CPU */
+
c = &cpu_data(cpu);
if (!cpu_has(c, X86_FEATURE_MSR))
- ret = -EIO; /* MSR not supported */
-out:
- unlock_kernel();
- return ret;
+ return -EIO; /* MSR not supported */
+
+ return 0;
}
/*
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 5284cd2b5776..e51b056fc88f 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -9,6 +9,7 @@
#include <linux/pm.h>
#include <linux/clockchips.h>
#include <linux/random.h>
+#include <linux/user-return-notifier.h>
#include <trace/events/power.h>
#include <asm/system.h>
#include <asm/apic.h>
@@ -224,6 +225,7 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
*/
memset(tss->io_bitmap, 0xff, prev->io_bitmap_max);
}
+ propagate_user_return_notify(prev_p, next_p);
}
int sys_fork(struct pt_regs *regs)
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 4cf79567cdab..35e6fad73e0d 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -134,7 +134,7 @@ void __show_regs(struct pt_regs *regs, int all)
ss = regs->ss & 0xffff;
gs = get_user_gs(regs);
} else {
- sp = (unsigned long) (&regs->sp);
+ sp = kernel_stack_pointer(regs);
savesegment(ss, ss);
savesegment(gs, gs);
}
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index ad535b683170..eb261c582a44 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -344,26 +344,42 @@ out:
return err;
}
-void
-start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
+static void
+start_thread_common(struct pt_regs *regs, unsigned long new_ip,
+ unsigned long new_sp,
+ unsigned int _cs, unsigned int _ss, unsigned int _ds)
{
loadsegment(fs, 0);
- loadsegment(es, 0);
- loadsegment(ds, 0);
+ loadsegment(es, _ds);
+ loadsegment(ds, _ds);
load_gs_index(0);
regs->ip = new_ip;
regs->sp = new_sp;
percpu_write(old_rsp, new_sp);
- regs->cs = __USER_CS;
- regs->ss = __USER_DS;
- regs->flags = 0x200;
+ regs->cs = _cs;
+ regs->ss = _ss;
+ regs->flags = X86_EFLAGS_IF;
set_fs(USER_DS);
/*
* Free the old FP and other extended state
*/
free_thread_xstate(current);
}
-EXPORT_SYMBOL_GPL(start_thread);
+
+void
+start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
+{
+ start_thread_common(regs, new_ip, new_sp,
+ __USER_CS, __USER_DS, 0);
+}
+
+#ifdef CONFIG_IA32_EMULATION
+void start_thread_ia32(struct pt_regs *regs, u32 new_ip, u32 new_sp)
+{
+ start_thread_common(regs, new_ip, new_sp,
+ __USER32_CS, __USER32_DS, __USER32_DS);
+}
+#endif
/*
* switch_to(x,y) should switch tasks from x to y.
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 7b058a2dc66a..c4f76d275ee4 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -49,6 +49,118 @@ enum x86_regset {
REGSET_IOPERM32,
};
+struct pt_regs_offset {
+ const char *name;
+ int offset;
+};
+
+#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
+#define REG_OFFSET_END {.name = NULL, .offset = 0}
+
+static const struct pt_regs_offset regoffset_table[] = {
+#ifdef CONFIG_X86_64
+ REG_OFFSET_NAME(r15),
+ REG_OFFSET_NAME(r14),
+ REG_OFFSET_NAME(r13),
+ REG_OFFSET_NAME(r12),
+ REG_OFFSET_NAME(r11),
+ REG_OFFSET_NAME(r10),
+ REG_OFFSET_NAME(r9),
+ REG_OFFSET_NAME(r8),
+#endif
+ REG_OFFSET_NAME(bx),
+ REG_OFFSET_NAME(cx),
+ REG_OFFSET_NAME(dx),
+ REG_OFFSET_NAME(si),
+ REG_OFFSET_NAME(di),
+ REG_OFFSET_NAME(bp),
+ REG_OFFSET_NAME(ax),
+#ifdef CONFIG_X86_32
+ REG_OFFSET_NAME(ds),
+ REG_OFFSET_NAME(es),
+ REG_OFFSET_NAME(fs),
+ REG_OFFSET_NAME(gs),
+#endif
+ REG_OFFSET_NAME(orig_ax),
+ REG_OFFSET_NAME(ip),
+ REG_OFFSET_NAME(cs),
+ REG_OFFSET_NAME(flags),
+ REG_OFFSET_NAME(sp),
+ REG_OFFSET_NAME(ss),
+ REG_OFFSET_END,
+};
+
+/**
+ * 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;
+}
+
+static const int arg_offs_table[] = {
+#ifdef CONFIG_X86_32
+ [0] = offsetof(struct pt_regs, ax),
+ [1] = offsetof(struct pt_regs, dx),
+ [2] = offsetof(struct pt_regs, cx)
+#else /* CONFIG_X86_64 */
+ [0] = offsetof(struct pt_regs, di),
+ [1] = offsetof(struct pt_regs, si),
+ [2] = offsetof(struct pt_regs, dx),
+ [3] = offsetof(struct pt_regs, cx),
+ [4] = offsetof(struct pt_regs, r8),
+ [5] = offsetof(struct pt_regs, r9)
+#endif
+};
+
+/**
+ * regs_get_argument_nth() - get Nth argument at function call
+ * @regs: pt_regs which contains registers at function entry.
+ * @n: argument number.
+ *
+ * regs_get_argument_nth() returns @n th argument of a function call.
+ * Since usually the kernel stack will be changed right after function entry,
+ * you must use this at function entry. If the @n th entry is NOT in the
+ * kernel stack or pt_regs, this returns 0.
+ */
+unsigned long regs_get_argument_nth(struct pt_regs *regs, unsigned int n)
+{
+ if (n < ARRAY_SIZE(arg_offs_table))
+ return *(unsigned long *)((char *)regs + arg_offs_table[n]);
+ else {
+ /*
+ * The typical case: arg n is on the stack.
+ * (Note: stack[0] = return address, so skip it)
+ */
+ n -= ARRAY_SIZE(arg_offs_table);
+ return regs_get_kernel_stack_nth(regs, 1 + n);
+ }
+}
+
/*
* does not yet catch signals sent when the child dies.
* in exit.c or in signal.c.
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index a1a3cdda06e1..d9d8d91741a1 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -34,7 +34,7 @@ EXPORT_SYMBOL(pm_power_off);
static const struct desc_ptr no_idt = {};
static int reboot_mode;
-enum reboot_type reboot_type = BOOT_KBD;
+enum reboot_type reboot_type = BOOT_ACPI;
int reboot_force;
#if defined(CONFIG_X86_32) && defined(CONFIG_SMP)
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index e09f0e2c14b5..f89141982702 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -106,6 +106,7 @@
#include <asm/percpu.h>
#include <asm/topology.h>
#include <asm/apicdef.h>
+#include <asm/k8.h>
#ifdef CONFIG_X86_64
#include <asm/numa_64.h>
#endif
@@ -691,6 +692,9 @@ static struct dmi_system_id __initdata bad_bios_dmi_table[] = {
void __init setup_arch(char **cmdline_p)
{
+ int acpi = 0;
+ int k8 = 0;
+
#ifdef CONFIG_X86_32
memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
visws_early_detect();
@@ -934,10 +938,15 @@ void __init setup_arch(char **cmdline_p)
/*
* Parse SRAT to discover nodes.
*/
- acpi_numa_init();
+ acpi = acpi_numa_init();
+#endif
+
+#ifdef CONFIG_K8_NUMA
+ if (!acpi)
+ k8 = !k8_numa_init(0, max_pfn);
#endif
- initmem_init(0, max_pfn);
+ initmem_init(0, max_pfn, acpi, k8);
#ifdef CONFIG_ACPI_SLEEP
/*
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 6a44a76055ad..c49f90f7957a 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -19,6 +19,7 @@
#include <linux/stddef.h>
#include <linux/personality.h>
#include <linux/uaccess.h>
+#include <linux/user-return-notifier.h>
#include <asm/processor.h>
#include <asm/ucontext.h>
@@ -872,6 +873,8 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
if (current->replacement_session_keyring)
key_replace_session_keyring();
}
+ if (thread_info_flags & _TIF_USER_RETURN_NOTIFY)
+ fire_user_return_notifiers();
#ifdef CONFIG_X86_32
clear_thread_flag(TIF_IRET);
diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S
index 0157cd26d7cc..70c2125d55b9 100644
--- a/arch/x86/kernel/syscall_table_32.S
+++ b/arch/x86/kernel/syscall_table_32.S
@@ -336,3 +336,4 @@ ENTRY(sys_call_table)
.long sys_pwritev
.long sys_rt_tgsigqueueinfo /* 335 */
.long sys_perf_event_open
+ .long sys_recvmmsg
diff --git a/arch/x86/kernel/tlb_uv.c b/arch/x86/kernel/tlb_uv.c
index 503c1f2e8835..1740c85e24bb 100644
--- a/arch/x86/kernel/tlb_uv.c
+++ b/arch/x86/kernel/tlb_uv.c
@@ -23,8 +23,6 @@
static struct bau_control **uv_bau_table_bases __read_mostly;
static int uv_bau_retry_limit __read_mostly;
-/* position of pnode (which is nasid>>1): */
-static int uv_nshift __read_mostly;
/* base pnode in this partition */
static int uv_partition_base_pnode __read_mostly;
@@ -723,7 +721,7 @@ uv_activation_descriptor_init(int node, int pnode)
BUG_ON(!adp);
pa = uv_gpa(adp); /* need the real nasid*/
- n = pa >> uv_nshift;
+ n = uv_gpa_to_pnode(pa);
m = pa & uv_mmask;
uv_write_global_mmr64(pnode, UVH_LB_BAU_SB_DESCRIPTOR_BASE,
@@ -778,7 +776,7 @@ uv_payload_queue_init(int node, int pnode, struct bau_control *bau_tablesp)
* need the pnode of where the memory was really allocated
*/
pa = uv_gpa(pqp);
- pn = pa >> uv_nshift;
+ pn = uv_gpa_to_pnode(pa);
uv_write_global_mmr64(pnode,
UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST,
((unsigned long)pn << UV_PAYLOADQ_PNODE_SHIFT) |
@@ -843,8 +841,7 @@ static int __init uv_bau_init(void)
GFP_KERNEL, cpu_to_node(cur_cpu));
uv_bau_retry_limit = 1;
- uv_nshift = uv_hub_info->n_val;
- uv_mmask = (1UL << uv_hub_info->n_val) - 1;
+ uv_mmask = (1UL << uv_hub_info->m_val) - 1;
nblades = uv_num_possible_blades();
uv_bau_table_bases = (struct bau_control **)
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index cd982f48e23e..f67bfaa1adc2 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -763,14 +763,12 @@ void mark_tsc_unstable(char *reason)
{
if (!tsc_unstable) {
tsc_unstable = 1;
- printk(KERN_INFO "Marking TSC unstable due to %s\n", reason);
+ printk("Marking TSC unstable due to %s\n", reason);
/* Change only the rating, when not registered */
if (clocksource_tsc.mult)
- clocksource_mark_unstable(&clocksource_tsc);
- else {
- clocksource_tsc.flags |= CLOCK_SOURCE_UNSTABLE;
+ clocksource_change_rating(&clocksource_tsc, 0);
+ else
clocksource_tsc.rating = 0;
- }
}
}
diff --git a/arch/x86/kernel/uv_irq.c b/arch/x86/kernel/uv_irq.c
index aeef529917e4..61d805df4c91 100644
--- a/arch/x86/kernel/uv_irq.c
+++ b/arch/x86/kernel/uv_irq.c
@@ -9,10 +9,25 @@
*/
#include <linux/module.h>
+#include <linux/rbtree.h>
#include <linux/irq.h>
#include <asm/apic.h>
#include <asm/uv/uv_irq.h>
+#include <asm/uv/uv_hub.h>
+
+/* MMR offset and pnode of hub sourcing interrupts for a given irq */
+struct uv_irq_2_mmr_pnode{
+ struct rb_node list;
+ unsigned long offset;
+ int pnode;
+ int irq;
+};
+
+static spinlock_t uv_irq_lock;
+static struct rb_root uv_irq_root;
+
+static int uv_set_irq_affinity(unsigned int, const struct cpumask *);
static void uv_noop(unsigned int irq)
{
@@ -39,25 +54,214 @@ struct irq_chip uv_irq_chip = {
.unmask = uv_noop,
.eoi = uv_ack_apic,
.end = uv_noop,
+ .set_affinity = uv_set_irq_affinity,
};
/*
+ * Add offset and pnode information of the hub sourcing interrupts to the
+ * rb tree for a specific irq.
+ */
+static int uv_set_irq_2_mmr_info(int irq, unsigned long offset, unsigned blade)
+{
+ struct rb_node **link = &uv_irq_root.rb_node;
+ struct rb_node *parent = NULL;
+ struct uv_irq_2_mmr_pnode *n;
+ struct uv_irq_2_mmr_pnode *e;
+ unsigned long irqflags;
+
+ n = kmalloc_node(sizeof(struct uv_irq_2_mmr_pnode), GFP_KERNEL,
+ uv_blade_to_memory_nid(blade));
+ if (!n)
+ return -ENOMEM;
+
+ n->irq = irq;
+ n->offset = offset;
+ n->pnode = uv_blade_to_pnode(blade);
+ spin_lock_irqsave(&uv_irq_lock, irqflags);
+ /* Find the right place in the rbtree: */
+ while (*link) {
+ parent = *link;
+ e = rb_entry(parent, struct uv_irq_2_mmr_pnode, list);
+
+ if (unlikely(irq == e->irq)) {
+ /* irq entry exists */
+ e->pnode = uv_blade_to_pnode(blade);
+ e->offset = offset;
+ spin_unlock_irqrestore(&uv_irq_lock, irqflags);
+ kfree(n);
+ return 0;
+ }
+
+ if (irq < e->irq)
+ link = &(*link)->rb_left;
+ else
+ link = &(*link)->rb_right;
+ }
+
+ /* Insert the node into the rbtree. */
+ rb_link_node(&n->list, parent, link);
+ rb_insert_color(&n->list, &uv_irq_root);
+
+ spin_unlock_irqrestore(&uv_irq_lock, irqflags);
+ return 0;
+}
+
+/* Retrieve offset and pnode information from the rb tree for a specific irq */
+int uv_irq_2_mmr_info(int irq, unsigned long *offset, int *pnode)
+{
+ struct uv_irq_2_mmr_pnode *e;
+ struct rb_node *n;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&uv_irq_lock, irqflags);
+ n = uv_irq_root.rb_node;
+ while (n) {
+ e = rb_entry(n, struct uv_irq_2_mmr_pnode, list);
+
+ if (e->irq == irq) {
+ *offset = e->offset;
+ *pnode = e->pnode;
+ spin_unlock_irqrestore(&uv_irq_lock, irqflags);
+ return 0;
+ }
+
+ if (irq < e->irq)
+ n = n->rb_left;
+ else
+ n = n->rb_right;
+ }
+ spin_unlock_irqrestore(&uv_irq_lock, irqflags);
+ return -1;
+}
+
+/*
+ * Re-target the irq to the specified CPU and enable the specified MMR located
+ * on the specified blade to allow the sending of MSIs to the specified CPU.
+ */
+static int
+arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
+ unsigned long mmr_offset, int restrict)
+{
+ const struct cpumask *eligible_cpu = cpumask_of(cpu);
+ struct irq_desc *desc = irq_to_desc(irq);
+ struct irq_cfg *cfg;
+ int mmr_pnode;
+ unsigned long mmr_value;
+ struct uv_IO_APIC_route_entry *entry;
+ int err;
+
+ BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) !=
+ sizeof(unsigned long));
+
+ cfg = irq_cfg(irq);
+
+ err = assign_irq_vector(irq, cfg, eligible_cpu);
+ if (err != 0)
+ return err;
+
+ if (restrict == UV_AFFINITY_CPU)
+ desc->status |= IRQ_NO_BALANCING;
+ else
+ desc->status |= IRQ_MOVE_PCNTXT;
+
+ set_irq_chip_and_handler_name(irq, &uv_irq_chip, handle_percpu_irq,
+ irq_name);
+
+ mmr_value = 0;
+ entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
+ entry->vector = cfg->vector;
+ entry->delivery_mode = apic->irq_delivery_mode;
+ entry->dest_mode = apic->irq_dest_mode;
+ entry->polarity = 0;
+ entry->trigger = 0;
+ entry->mask = 0;
+ entry->dest = apic->cpu_mask_to_apicid(eligible_cpu);
+
+ mmr_pnode = uv_blade_to_pnode(mmr_blade);
+ uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
+
+ if (cfg->move_in_progress)
+ send_cleanup_vector(cfg);
+
+ return irq;
+}
+
+/*
+ * Disable the specified MMR located on the specified blade so that MSIs are
+ * longer allowed to be sent.
+ */
+static void arch_disable_uv_irq(int mmr_pnode, unsigned long mmr_offset)
+{
+ unsigned long mmr_value;
+ struct uv_IO_APIC_route_entry *entry;
+
+ BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) !=
+ sizeof(unsigned long));
+
+ mmr_value = 0;
+ entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
+ entry->mask = 1;
+
+ uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
+}
+
+static int uv_set_irq_affinity(unsigned int irq, const struct cpumask *mask)
+{
+ struct irq_desc *desc = irq_to_desc(irq);
+ struct irq_cfg *cfg = desc->chip_data;
+ unsigned int dest;
+ unsigned long mmr_value;
+ struct uv_IO_APIC_route_entry *entry;
+ unsigned long mmr_offset;
+ unsigned mmr_pnode;
+
+ dest = set_desc_affinity(desc, mask);
+ if (dest == BAD_APICID)
+ return -1;
+
+ mmr_value = 0;
+ entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
+
+ entry->vector = cfg->vector;
+ entry->delivery_mode = apic->irq_delivery_mode;
+ entry->dest_mode = apic->irq_dest_mode;
+ entry->polarity = 0;
+ entry->trigger = 0;
+ entry->mask = 0;
+ entry->dest = dest;
+
+ /* Get previously stored MMR and pnode of hub sourcing interrupts */
+ if (uv_irq_2_mmr_info(irq, &mmr_offset, &mmr_pnode))
+ return -1;
+
+ uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
+
+ if (cfg->move_in_progress)
+ send_cleanup_vector(cfg);
+
+ return 0;
+}
+
+/*
* Set up a mapping of an available irq and vector, and enable the specified
* MMR that defines the MSI that is to be sent to the specified CPU when an
* interrupt is raised.
*/
int uv_setup_irq(char *irq_name, int cpu, int mmr_blade,
- unsigned long mmr_offset)
+ unsigned long mmr_offset, int restrict)
{
- int irq;
- int ret;
+ int irq, ret;
+
+ irq = create_irq_nr(NR_IRQS_LEGACY, uv_blade_to_memory_nid(mmr_blade));
- irq = create_irq();
if (irq <= 0)
return -EBUSY;
- ret = arch_enable_uv_irq(irq_name, irq, cpu, mmr_blade, mmr_offset);
- if (ret != irq)
+ ret = arch_enable_uv_irq(irq_name, irq, cpu, mmr_blade, mmr_offset,
+ restrict);
+ if (ret == irq)
+ uv_set_irq_2_mmr_info(irq, mmr_offset, mmr_blade);
+ else
destroy_irq(irq);
return ret;
@@ -71,9 +275,28 @@ EXPORT_SYMBOL_GPL(uv_setup_irq);
*
* Set mmr_blade and mmr_offset to what was passed in on uv_setup_irq().
*/
-void uv_teardown_irq(unsigned int irq, int mmr_blade, unsigned long mmr_offset)
+void uv_teardown_irq(unsigned int irq)
{
- arch_disable_uv_irq(mmr_blade, mmr_offset);
+ struct uv_irq_2_mmr_pnode *e;
+ struct rb_node *n;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&uv_irq_lock, irqflags);
+ n = uv_irq_root.rb_node;
+ while (n) {
+ e = rb_entry(n, struct uv_irq_2_mmr_pnode, list);
+ if (e->irq == irq) {
+ arch_disable_uv_irq(e->pnode, e->offset);
+ rb_erase(n, &uv_irq_root);
+ kfree(e);
+ break;
+ }
+ if (irq < e->irq)
+ n = n->rb_left;
+ else
+ n = n->rb_right;
+ }
+ spin_unlock_irqrestore(&uv_irq_lock, irqflags);
destroy_irq(irq);
}
EXPORT_SYMBOL_GPL(uv_teardown_irq);
diff --git a/arch/x86/kernel/uv_time.c b/arch/x86/kernel/uv_time.c
index 583f11d5c480..3da7b1d8bfd3 100644
--- a/arch/x86/kernel/uv_time.c
+++ b/arch/x86/kernel/uv_time.c
@@ -75,6 +75,7 @@ struct uv_rtc_timer_head {
static struct uv_rtc_timer_head **blade_info __read_mostly;
static int uv_rtc_enable;
+static int uv_rtc_evt_enable;
/*
* Hardware interface routines
@@ -90,7 +91,7 @@ static void uv_rtc_send_IPI(int cpu)
pnode = uv_apicid_to_pnode(apicid);
val = (1UL << UVH_IPI_INT_SEND_SHFT) |
(apicid << UVH_IPI_INT_APIC_ID_SHFT) |
- (GENERIC_INTERRUPT_VECTOR << UVH_IPI_INT_VECTOR_SHFT);
+ (X86_PLATFORM_IPI_VECTOR << UVH_IPI_INT_VECTOR_SHFT);
uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
}
@@ -115,7 +116,7 @@ static int uv_setup_intr(int cpu, u64 expires)
uv_write_global_mmr64(pnode, UVH_EVENT_OCCURRED0_ALIAS,
UVH_EVENT_OCCURRED0_RTC1_MASK);
- val = (GENERIC_INTERRUPT_VECTOR << UVH_RTC1_INT_CONFIG_VECTOR_SHFT) |
+ val = (X86_PLATFORM_IPI_VECTOR << UVH_RTC1_INT_CONFIG_VECTOR_SHFT) |
((u64)cpu_physical_id(cpu) << UVH_RTC1_INT_CONFIG_APIC_ID_SHFT);
/* Set configuration */
@@ -123,7 +124,10 @@ static int uv_setup_intr(int cpu, u64 expires)
/* Initialize comparator value */
uv_write_global_mmr64(pnode, UVH_INT_CMPB, expires);
- return (expires < uv_read_rtc(NULL) && !uv_intr_pending(pnode));
+ if (uv_read_rtc(NULL) <= expires)
+ return 0;
+
+ return !uv_intr_pending(pnode);
}
/*
@@ -223,6 +227,7 @@ static int uv_rtc_set_timer(int cpu, u64 expires)
next_cpu = head->next_cpu;
*t = expires;
+
/* Will this one be next to go off? */
if (next_cpu < 0 || bcpu == next_cpu ||
expires < head->cpu[next_cpu].expires) {
@@ -231,7 +236,7 @@ static int uv_rtc_set_timer(int cpu, u64 expires)
*t = ULLONG_MAX;
uv_rtc_find_next_timer(head, pnode);
spin_unlock_irqrestore(&head->lock, flags);
- return 1;
+ return -ETIME;
}
}
@@ -244,7 +249,7 @@ static int uv_rtc_set_timer(int cpu, u64 expires)
*
* Returns 1 if this timer was pending.
*/
-static int uv_rtc_unset_timer(int cpu)
+static int uv_rtc_unset_timer(int cpu, int force)
{
int pnode = uv_cpu_to_pnode(cpu);
int bid = uv_cpu_to_blade_id(cpu);
@@ -256,14 +261,15 @@ static int uv_rtc_unset_timer(int cpu)
spin_lock_irqsave(&head->lock, flags);
- if (head->next_cpu == bcpu && uv_read_rtc(NULL) >= *t)
+ if ((head->next_cpu == bcpu && uv_read_rtc(NULL) >= *t) || force)
rc = 1;
- *t = ULLONG_MAX;
-
- /* Was the hardware setup for this timer? */
- if (head->next_cpu == bcpu)
- uv_rtc_find_next_timer(head, pnode);
+ if (rc) {
+ *t = ULLONG_MAX;
+ /* Was the hardware setup for this timer? */
+ if (head->next_cpu == bcpu)
+ uv_rtc_find_next_timer(head, pnode);
+ }
spin_unlock_irqrestore(&head->lock, flags);
@@ -310,20 +316,20 @@ static void uv_rtc_timer_setup(enum clock_event_mode mode,
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
- uv_rtc_unset_timer(ced_cpu);
+ uv_rtc_unset_timer(ced_cpu, 1);
break;
}
}
static void uv_rtc_interrupt(void)
{
- struct clock_event_device *ced = &__get_cpu_var(cpu_ced);
int cpu = smp_processor_id();
+ struct clock_event_device *ced = &per_cpu(cpu_ced, cpu);
if (!ced || !ced->event_handler)
return;
- if (uv_rtc_unset_timer(cpu) != 1)
+ if (uv_rtc_unset_timer(cpu, 0) != 1)
return;
ced->event_handler(ced);
@@ -337,6 +343,14 @@ static int __init uv_enable_rtc(char *str)
}
__setup("uvrtc", uv_enable_rtc);
+static int __init uv_enable_evt_rtc(char *str)
+{
+ uv_rtc_evt_enable = 1;
+
+ return 1;
+}
+__setup("uvrtcevt", uv_enable_evt_rtc);
+
static __init void uv_rtc_register_clockevents(struct work_struct *dummy)
{
struct clock_event_device *ced = &__get_cpu_var(cpu_ced);
@@ -350,27 +364,28 @@ static __init int uv_rtc_setup_clock(void)
{
int rc;
- if (!uv_rtc_enable || !is_uv_system() || generic_interrupt_extension)
+ if (!uv_rtc_enable || !is_uv_system() || x86_platform_ipi_callback)
return -ENODEV;
- generic_interrupt_extension = uv_rtc_interrupt;
-
clocksource_uv.mult = clocksource_hz2mult(sn_rtc_cycles_per_second,
clocksource_uv.shift);
rc = clocksource_register(&clocksource_uv);
- if (rc) {
- generic_interrupt_extension = NULL;
+ if (rc)
+ printk(KERN_INFO "UV RTC clocksource failed rc %d\n", rc);
+ else
+ printk(KERN_INFO "UV RTC clocksource registered freq %lu MHz\n",
+ sn_rtc_cycles_per_second/(unsigned long)1E6);
+
+ if (rc || !uv_rtc_evt_enable)
return rc;
- }
/* Setup and register clockevents */
rc = uv_rtc_allocate_timers();
- if (rc) {
- clocksource_unregister(&clocksource_uv);
- generic_interrupt_extension = NULL;
- return rc;
- }
+ if (rc)
+ goto error;
+
+ x86_platform_ipi_callback = uv_rtc_interrupt;
clock_event_device_uv.mult = div_sc(sn_rtc_cycles_per_second,
NSEC_PER_SEC, clock_event_device_uv.shift);
@@ -383,11 +398,19 @@ static __init int uv_rtc_setup_clock(void)
rc = schedule_on_each_cpu(uv_rtc_register_clockevents);
if (rc) {
- clocksource_unregister(&clocksource_uv);
- generic_interrupt_extension = NULL;
+ x86_platform_ipi_callback = NULL;
uv_rtc_deallocate_timers();
+ goto error;
}
+ printk(KERN_INFO "UV RTC clockevents registered\n");
+
+ return 0;
+
+error:
+ clocksource_unregister(&clocksource_uv);
+ printk(KERN_INFO "UV RTC clockevents failed rc %d\n", rc);
+
return rc;
}
arch_initcall(uv_rtc_setup_clock);
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 92929fb3f9fa..ff54ce742505 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -41,6 +41,32 @@ ENTRY(phys_startup_64)
jiffies_64 = jiffies;
#endif
+#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
+/*
+ * On 64-bit, align RODATA to 2MB so that even with CONFIG_DEBUG_RODATA
+ * we retain large page mappings for boundaries spanning kernel text, rodata
+ * and data sections.
+ *
+ * However, kernel identity mappings will have different RWX permissions
+ * to the pages mapping to text and to the pages padding (which are freed) the
+ * text section. Hence kernel identity mappings will be broken to smaller
+ * pages. For 64-bit, kernel text and kernel identity mappings are different,
+ * so we can enable protection checks that come with CONFIG_DEBUG_RODATA,
+ * as well as retain 2MB large page mappings for kernel text.
+ */
+#define X64_ALIGN_DEBUG_RODATA_BEGIN . = ALIGN(HPAGE_SIZE);
+
+#define X64_ALIGN_DEBUG_RODATA_END \
+ . = ALIGN(HPAGE_SIZE); \
+ __end_rodata_hpage_align = .;
+
+#else
+
+#define X64_ALIGN_DEBUG_RODATA_BEGIN
+#define X64_ALIGN_DEBUG_RODATA_END
+
+#endif
+
PHDRS {
text PT_LOAD FLAGS(5); /* R_E */
data PT_LOAD FLAGS(7); /* RWE */
@@ -90,7 +116,9 @@ SECTIONS
EXCEPTION_TABLE(16) :text = 0x9090
+ X64_ALIGN_DEBUG_RODATA_BEGIN
RO_DATA(PAGE_SIZE)
+ X64_ALIGN_DEBUG_RODATA_END
/* Data */
.data : AT(ADDR(.data) - LOAD_OFFSET) {
@@ -305,6 +333,9 @@ SECTIONS
#ifdef CONFIG_X86_32
+/*
+ * The ASSERT() sink to . is intentional, for binutils 2.14 compatibility:
+ */
. = ASSERT((_end - LOAD_OFFSET <= KERNEL_IMAGE_SIZE),
"kernel image bigger than KERNEL_IMAGE_SIZE");
#else
diff --git a/arch/x86/kernel/x8664_ksyms_64.c b/arch/x86/kernel/x8664_ksyms_64.c
index 3909e3ba5ce3..a0cdd8cc1d67 100644
--- a/arch/x86/kernel/x8664_ksyms_64.c
+++ b/arch/x86/kernel/x8664_ksyms_64.c
@@ -30,7 +30,7 @@ EXPORT_SYMBOL(__put_user_8);
EXPORT_SYMBOL(copy_user_generic);
EXPORT_SYMBOL(__copy_user_nocache);
-EXPORT_SYMBOL(copy_from_user);
+EXPORT_SYMBOL(_copy_from_user);
EXPORT_SYMBOL(copy_to_user);
EXPORT_SYMBOL(__copy_from_user_inatomic);
diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
index 0e7fe78d0f74..31a7035c4bd9 100644
--- a/arch/x86/kvm/Makefile
+++ b/arch/x86/kvm/Makefile
@@ -6,7 +6,8 @@ CFLAGS_svm.o := -I.
CFLAGS_vmx.o := -I.
kvm-y += $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \
- coalesced_mmio.o irq_comm.o eventfd.o)
+ coalesced_mmio.o irq_comm.o eventfd.o \
+ assigned-dev.o)
kvm-$(CONFIG_IOMMU_API) += $(addprefix ../../../virt/kvm/, iommu.o)
kvm-y += x86.o mmu.o emulate.o i8259.o irq.o lapic.o \
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 1be5cd640e93..d226dff47d77 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -75,6 +75,8 @@
#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 No64 (1<<28)
/* Source 2 operand type */
#define Src2None (0<<29)
#define Src2CL (1<<29)
@@ -92,19 +94,23 @@ static u32 opcode_table[256] = {
/* 0x00 - 0x07 */
ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
- ByteOp | DstAcc | SrcImm, DstAcc | SrcImm, 0, 0,
+ ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
+ ImplicitOps | Stack | No64, ImplicitOps | Stack | No64,
/* 0x08 - 0x0F */
ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
- 0, 0, 0, 0,
+ ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
+ ImplicitOps | Stack | No64, 0,
/* 0x10 - 0x17 */
ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
- ByteOp | DstAcc | SrcImm, DstAcc | SrcImm, 0, 0,
+ ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
+ ImplicitOps | Stack | No64, ImplicitOps | Stack | No64,
/* 0x18 - 0x1F */
ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
- ByteOp | DstAcc | SrcImm, DstAcc | SrcImm, 0, 0,
+ ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
+ ImplicitOps | Stack | No64, ImplicitOps | Stack | No64,
/* 0x20 - 0x27 */
ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
@@ -133,7 +139,8 @@ static u32 opcode_table[256] = {
DstReg | Stack, DstReg | Stack, DstReg | Stack, DstReg | Stack,
DstReg | Stack, DstReg | Stack, DstReg | Stack, DstReg | Stack,
/* 0x60 - 0x67 */
- 0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ ,
+ 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,
@@ -158,7 +165,7 @@ static u32 opcode_table[256] = {
/* 0x90 - 0x97 */
DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg,
/* 0x98 - 0x9F */
- 0, 0, SrcImm | Src2Imm16, 0,
+ 0, 0, SrcImm | Src2Imm16 | No64, 0,
ImplicitOps | Stack, ImplicitOps | Stack, 0, 0,
/* 0xA0 - 0xA7 */
ByteOp | DstReg | SrcMem | Mov | MemAbs, DstReg | SrcMem | Mov | MemAbs,
@@ -185,7 +192,7 @@ static u32 opcode_table[256] = {
ByteOp | DstMem | SrcImm | ModRM | Mov, DstMem | SrcImm | ModRM | Mov,
/* 0xC8 - 0xCF */
0, 0, 0, ImplicitOps | Stack,
- ImplicitOps, SrcImmByte, ImplicitOps, ImplicitOps,
+ ImplicitOps, SrcImmByte, ImplicitOps | No64, ImplicitOps,
/* 0xD0 - 0xD7 */
ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM,
ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM,
@@ -198,7 +205,7 @@ static u32 opcode_table[256] = {
ByteOp | SrcImmUByte, SrcImmUByte,
/* 0xE8 - 0xEF */
SrcImm | Stack, SrcImm | ImplicitOps,
- SrcImmU | Src2Imm16, SrcImmByte | ImplicitOps,
+ SrcImmU | Src2Imm16 | No64, SrcImmByte | ImplicitOps,
SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps,
SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps,
/* 0xF0 - 0xF7 */
@@ -244,11 +251,13 @@ static u32 twobyte_table[256] = {
/* 0x90 - 0x9F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xA0 - 0xA7 */
- 0, 0, 0, DstMem | SrcReg | ModRM | BitOp,
+ ImplicitOps | Stack, ImplicitOps | Stack,
+ 0, DstMem | SrcReg | ModRM | BitOp,
DstMem | SrcReg | Src2ImmByte | ModRM,
DstMem | SrcReg | Src2CL | ModRM, 0, 0,
/* 0xA8 - 0xAF */
- 0, 0, 0, DstMem | SrcReg | ModRM | BitOp,
+ ImplicitOps | Stack, ImplicitOps | Stack,
+ 0, DstMem | SrcReg | ModRM | BitOp,
DstMem | SrcReg | Src2ImmByte | ModRM,
DstMem | SrcReg | Src2CL | ModRM,
ModRM, 0,
@@ -962,6 +971,11 @@ done_prefixes:
}
}
+ if (mode == X86EMUL_MODE_PROT64 && (c->d & No64)) {
+ kvm_report_emulation_failure(ctxt->vcpu, "invalid x86/64 instruction");;
+ return -1;
+ }
+
if (c->d & Group) {
group = c->d & GroupMask;
c->modrm = insn_fetch(u8, 1, c->eip);
@@ -1186,6 +1200,69 @@ static int emulate_pop(struct x86_emulate_ctxt *ctxt,
return rc;
}
+static void emulate_push_sreg(struct x86_emulate_ctxt *ctxt, int seg)
+{
+ struct decode_cache *c = &ctxt->decode;
+ struct kvm_segment segment;
+
+ kvm_x86_ops->get_segment(ctxt->vcpu, &segment, seg);
+
+ c->src.val = segment.selector;
+ emulate_push(ctxt);
+}
+
+static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops, int seg)
+{
+ struct decode_cache *c = &ctxt->decode;
+ unsigned long selector;
+ int rc;
+
+ rc = emulate_pop(ctxt, ops, &selector, c->op_bytes);
+ if (rc != 0)
+ return rc;
+
+ rc = kvm_load_segment_descriptor(ctxt->vcpu, (u16)selector, 1, seg);
+ return rc;
+}
+
+static void emulate_pusha(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ unsigned long old_esp = c->regs[VCPU_REGS_RSP];
+ int reg = VCPU_REGS_RAX;
+
+ while (reg <= VCPU_REGS_RDI) {
+ (reg == VCPU_REGS_RSP) ?
+ (c->src.val = old_esp) : (c->src.val = c->regs[reg]);
+
+ emulate_push(ctxt);
+ ++reg;
+ }
+}
+
+static int emulate_popa(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops)
+{
+ struct decode_cache *c = &ctxt->decode;
+ int rc = 0;
+ int reg = VCPU_REGS_RDI;
+
+ while (reg >= VCPU_REGS_RAX) {
+ if (reg == VCPU_REGS_RSP) {
+ register_address_increment(c, &c->regs[VCPU_REGS_RSP],
+ c->op_bytes);
+ --reg;
+ }
+
+ rc = emulate_pop(ctxt, ops, &c->regs[reg], c->op_bytes);
+ if (rc != 0)
+ break;
+ --reg;
+ }
+ return rc;
+}
+
static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops)
{
@@ -1707,18 +1784,45 @@ special_insn:
add: /* add */
emulate_2op_SrcV("add", c->src, c->dst, ctxt->eflags);
break;
+ case 0x06: /* push es */
+ emulate_push_sreg(ctxt, VCPU_SREG_ES);
+ break;
+ case 0x07: /* pop es */
+ rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_ES);
+ if (rc != 0)
+ goto done;
+ break;
case 0x08 ... 0x0d:
or: /* or */
emulate_2op_SrcV("or", c->src, c->dst, ctxt->eflags);
break;
+ case 0x0e: /* push cs */
+ emulate_push_sreg(ctxt, VCPU_SREG_CS);
+ break;
case 0x10 ... 0x15:
adc: /* adc */
emulate_2op_SrcV("adc", c->src, c->dst, ctxt->eflags);
break;
+ case 0x16: /* push ss */
+ emulate_push_sreg(ctxt, VCPU_SREG_SS);
+ break;
+ case 0x17: /* pop ss */
+ rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_SS);
+ if (rc != 0)
+ goto done;
+ break;
case 0x18 ... 0x1d:
sbb: /* sbb */
emulate_2op_SrcV("sbb", c->src, c->dst, ctxt->eflags);
break;
+ case 0x1e: /* push ds */
+ emulate_push_sreg(ctxt, VCPU_SREG_DS);
+ break;
+ case 0x1f: /* pop ds */
+ rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_DS);
+ if (rc != 0)
+ goto done;
+ break;
case 0x20 ... 0x25:
and: /* and */
emulate_2op_SrcV("and", c->src, c->dst, ctxt->eflags);
@@ -1750,6 +1854,14 @@ special_insn:
if (rc != 0)
goto done;
break;
+ case 0x60: /* pusha */
+ emulate_pusha(ctxt);
+ break;
+ case 0x61: /* popa */
+ rc = emulate_popa(ctxt, ops);
+ if (rc != 0)
+ goto done;
+ break;
case 0x63: /* movsxd */
if (ctxt->mode != X86EMUL_MODE_PROT64)
goto cannot_emulate;
@@ -1761,7 +1873,7 @@ special_insn:
break;
case 0x6c: /* insb */
case 0x6d: /* insw/insd */
- if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
+ if (kvm_emulate_pio_string(ctxt->vcpu,
1,
(c->d & ByteOp) ? 1 : c->op_bytes,
c->rep_prefix ?
@@ -1777,7 +1889,7 @@ special_insn:
return 0;
case 0x6e: /* outsb */
case 0x6f: /* outsw/outsd */
- if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
+ if (kvm_emulate_pio_string(ctxt->vcpu,
0,
(c->d & ByteOp) ? 1 : c->op_bytes,
c->rep_prefix ?
@@ -2070,7 +2182,7 @@ special_insn:
case 0xef: /* out (e/r)ax,dx */
port = c->regs[VCPU_REGS_RDX];
io_dir_in = 0;
- do_io: if (kvm_emulate_pio(ctxt->vcpu, NULL, io_dir_in,
+ do_io: if (kvm_emulate_pio(ctxt->vcpu, io_dir_in,
(c->d & ByteOp) ? 1 : c->op_bytes,
port) != 0) {
c->eip = saved_eip;
@@ -2297,6 +2409,14 @@ twobyte_insn:
jmp_rel(c, c->src.val);
c->dst.type = OP_NONE;
break;
+ case 0xa0: /* push fs */
+ emulate_push_sreg(ctxt, VCPU_SREG_FS);
+ break;
+ case 0xa1: /* pop fs */
+ rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_FS);
+ if (rc != 0)
+ goto done;
+ break;
case 0xa3:
bt: /* bt */
c->dst.type = OP_NONE;
@@ -2308,6 +2428,14 @@ twobyte_insn:
case 0xa5: /* shld cl, r, r/m */
emulate_2op_cl("shld", c->src2, c->src, c->dst, ctxt->eflags);
break;
+ case 0xa8: /* push gs */
+ emulate_push_sreg(ctxt, VCPU_SREG_GS);
+ break;
+ case 0xa9: /* pop gs */
+ rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_GS);
+ if (rc != 0)
+ goto done;
+ break;
case 0xab:
bts: /* bts */
/* only subword offset */
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index 82ad523b4901..fab7440c9bb2 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -116,7 +116,7 @@ static s64 __kpit_elapsed(struct kvm *kvm)
* itself with the initial count and continues counting
* from there.
*/
- remaining = hrtimer_expires_remaining(&ps->pit_timer.timer);
+ remaining = hrtimer_get_remaining(&ps->pit_timer.timer);
elapsed = ps->pit_timer.period - ktime_to_ns(remaining);
elapsed = mod_64(elapsed, ps->pit_timer.period);
@@ -688,10 +688,8 @@ static void __inject_pit_timer_intr(struct kvm *kvm)
struct kvm_vcpu *vcpu;
int i;
- mutex_lock(&kvm->irq_lock);
kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 1);
kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 0);
- mutex_unlock(&kvm->irq_lock);
/*
* Provides NMI watchdog support via Virtual Wire mode.
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c
index 01f151682802..d057c0cbd245 100644
--- a/arch/x86/kvm/i8259.c
+++ b/arch/x86/kvm/i8259.c
@@ -38,7 +38,15 @@ static void pic_clear_isr(struct kvm_kpic_state *s, int irq)
s->isr_ack |= (1 << irq);
if (s != &s->pics_state->pics[0])
irq += 8;
+ /*
+ * We are dropping lock while calling ack notifiers since ack
+ * notifier callbacks for assigned devices call into PIC recursively.
+ * Other interrupt may be delivered to PIC while lock is dropped but
+ * it should be safe since PIC state is already updated at this stage.
+ */
+ spin_unlock(&s->pics_state->lock);
kvm_notify_acked_irq(s->pics_state->kvm, SELECT_PIC(irq), irq);
+ spin_lock(&s->pics_state->lock);
}
void kvm_pic_clear_isr_ack(struct kvm *kvm)
@@ -176,16 +184,18 @@ int kvm_pic_set_irq(void *opaque, int irq, int level)
static inline void pic_intack(struct kvm_kpic_state *s, int irq)
{
s->isr |= 1 << irq;
- if (s->auto_eoi) {
- if (s->rotate_on_auto_eoi)
- s->priority_add = (irq + 1) & 7;
- pic_clear_isr(s, irq);
- }
/*
* We don't clear a level sensitive interrupt here
*/
if (!(s->elcr & (1 << irq)))
s->irr &= ~(1 << irq);
+
+ if (s->auto_eoi) {
+ if (s->rotate_on_auto_eoi)
+ s->priority_add = (irq + 1) & 7;
+ pic_clear_isr(s, irq);
+ }
+
}
int kvm_pic_read_irq(struct kvm *kvm)
@@ -225,22 +235,11 @@ int kvm_pic_read_irq(struct kvm *kvm)
void kvm_pic_reset(struct kvm_kpic_state *s)
{
- int irq, irqbase, n;
+ int irq;
struct kvm *kvm = s->pics_state->irq_request_opaque;
struct kvm_vcpu *vcpu0 = kvm->bsp_vcpu;
+ u8 irr = s->irr, isr = s->imr;
- if (s == &s->pics_state->pics[0])
- irqbase = 0;
- else
- irqbase = 8;
-
- for (irq = 0; irq < PIC_NUM_PINS/2; irq++) {
- if (vcpu0 && kvm_apic_accept_pic_intr(vcpu0))
- if (s->irr & (1 << irq) || s->isr & (1 << irq)) {
- n = irq + irqbase;
- kvm_notify_acked_irq(kvm, SELECT_PIC(n), n);
- }
- }
s->last_irr = 0;
s->irr = 0;
s->imr = 0;
@@ -256,6 +255,13 @@ void kvm_pic_reset(struct kvm_kpic_state *s)
s->rotate_on_auto_eoi = 0;
s->special_fully_nested_mode = 0;
s->init4 = 0;
+
+ for (irq = 0; irq < PIC_NUM_PINS/2; irq++) {
+ if (vcpu0 && kvm_apic_accept_pic_intr(vcpu0))
+ if (irr & (1 << irq) || isr & (1 << irq)) {
+ pic_clear_isr(s, irq);
+ }
+ }
}
static void pic_ioport_write(void *opaque, u32 addr, u32 val)
@@ -298,9 +304,9 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val)
priority = get_priority(s, s->isr);
if (priority != 8) {
irq = (priority + s->priority_add) & 7;
- pic_clear_isr(s, irq);
if (cmd == 5)
s->priority_add = (irq + 1) & 7;
+ pic_clear_isr(s, irq);
pic_update_irq(s->pics_state);
}
break;
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h
index 7d6058a2fd38..c025a2362aae 100644
--- a/arch/x86/kvm/irq.h
+++ b/arch/x86/kvm/irq.h
@@ -71,6 +71,7 @@ struct kvm_pic {
int output; /* intr from master PIC */
struct kvm_io_device dev;
void (*ack_notifier)(void *opaque, int irq);
+ unsigned long irq_states[16];
};
struct kvm_pic *kvm_create_pic(struct kvm *kvm);
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 7024224f0fc8..cd60c0bd1b32 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -32,7 +32,6 @@
#include <asm/current.h>
#include <asm/apicdef.h>
#include <asm/atomic.h>
-#include <asm/apicdef.h>
#include "kvm_cache_regs.h"
#include "irq.h"
#include "trace.h"
@@ -471,11 +470,8 @@ static void apic_set_eoi(struct kvm_lapic *apic)
trigger_mode = IOAPIC_LEVEL_TRIG;
else
trigger_mode = IOAPIC_EDGE_TRIG;
- if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)) {
- mutex_lock(&apic->vcpu->kvm->irq_lock);
+ if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI))
kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode);
- mutex_unlock(&apic->vcpu->kvm->irq_lock);
- }
}
static void apic_send_ipi(struct kvm_lapic *apic)
@@ -504,9 +500,7 @@ static void apic_send_ipi(struct kvm_lapic *apic)
irq.trig_mode, irq.level, irq.dest_mode, irq.delivery_mode,
irq.vector);
- mutex_lock(&apic->vcpu->kvm->irq_lock);
kvm_irq_delivery_to_apic(apic->vcpu->kvm, apic, &irq);
- mutex_unlock(&apic->vcpu->kvm->irq_lock);
}
static u32 apic_get_tmcct(struct kvm_lapic *apic)
@@ -521,7 +515,7 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic)
if (apic_get_reg(apic, APIC_TMICT) == 0)
return 0;
- remaining = hrtimer_expires_remaining(&apic->lapic_timer.timer);
+ remaining = hrtimer_get_remaining(&apic->lapic_timer.timer);
if (ktime_to_ns(remaining) < 0)
remaining = ktime_set(0, 0);
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 685a4ffac8e6..a9024797b21f 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -748,7 +748,8 @@ static int rmap_write_protect(struct kvm *kvm, u64 gfn)
return write_protected;
}
-static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp, u64 data)
+static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
+ unsigned long data)
{
u64 *spte;
int need_tlb_flush = 0;
@@ -763,7 +764,8 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp, u64 data)
return need_tlb_flush;
}
-static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp, u64 data)
+static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp,
+ unsigned long data)
{
int need_flush = 0;
u64 *spte, new_spte;
@@ -799,9 +801,10 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp, u64 data)
return 0;
}
-static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, u64 data,
+static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
+ unsigned long data,
int (*handler)(struct kvm *kvm, unsigned long *rmapp,
- u64 data))
+ unsigned long data))
{
int i, j;
int retval = 0;
@@ -846,10 +849,11 @@ int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
{
- kvm_handle_hva(kvm, hva, (u64)&pte, kvm_set_pte_rmapp);
+ kvm_handle_hva(kvm, hva, (unsigned long)&pte, kvm_set_pte_rmapp);
}
-static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, u64 data)
+static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
+ unsigned long data)
{
u64 *spte;
int young = 0;
@@ -2785,7 +2789,7 @@ int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code)
if (r)
goto out;
- er = emulate_instruction(vcpu, vcpu->run, cr2, error_code, 0);
+ er = emulate_instruction(vcpu, cr2, error_code, 0);
switch (er) {
case EMULATE_DONE:
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index c17404add91f..279a2ae21b4f 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -286,7 +286,7 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
struct vcpu_svm *svm = to_svm(vcpu);
if (!svm->next_rip) {
- if (emulate_instruction(vcpu, vcpu->run, 0, 0, EMULTYPE_SKIP) !=
+ if (emulate_instruction(vcpu, 0, 0, EMULTYPE_SKIP) !=
EMULATE_DONE)
printk(KERN_DEBUG "%s: NOP\n", __func__);
return;
@@ -316,7 +316,7 @@ static void svm_hardware_disable(void *garbage)
cpu_svm_disable();
}
-static void svm_hardware_enable(void *garbage)
+static int svm_hardware_enable(void *garbage)
{
struct svm_cpu_data *svm_data;
@@ -325,16 +325,21 @@ static void svm_hardware_enable(void *garbage)
struct desc_struct *gdt;
int me = raw_smp_processor_id();
+ rdmsrl(MSR_EFER, efer);
+ if (efer & EFER_SVME)
+ return -EBUSY;
+
if (!has_svm()) {
- printk(KERN_ERR "svm_cpu_init: err EOPNOTSUPP on %d\n", me);
- return;
+ printk(KERN_ERR "svm_hardware_enable: err EOPNOTSUPP on %d\n",
+ me);
+ return -EINVAL;
}
svm_data = per_cpu(svm_data, me);
if (!svm_data) {
- printk(KERN_ERR "svm_cpu_init: svm_data is NULL on %d\n",
+ printk(KERN_ERR "svm_hardware_enable: svm_data is NULL on %d\n",
me);
- return;
+ return -EINVAL;
}
svm_data->asid_generation = 1;
@@ -345,11 +350,12 @@ static void svm_hardware_enable(void *garbage)
gdt = (struct desc_struct *)gdt_descr.base;
svm_data->tss_desc = (struct kvm_ldttss_desc *)(gdt + GDT_ENTRY_TSS);
- rdmsrl(MSR_EFER, efer);
wrmsrl(MSR_EFER, efer | EFER_SVME);
wrmsrl(MSR_VM_HSAVE_PA,
page_to_pfn(svm_data->save_area) << PAGE_SHIFT);
+
+ return 0;
}
static void svm_cpu_uninit(int cpu)
@@ -476,7 +482,7 @@ static __init int svm_hardware_setup(void)
kvm_enable_efer_bits(EFER_SVME);
}
- for_each_online_cpu(cpu) {
+ for_each_possible_cpu(cpu) {
r = svm_cpu_init(cpu);
if (r)
goto err;
@@ -510,7 +516,7 @@ static __exit void svm_hardware_unsetup(void)
{
int cpu;
- for_each_online_cpu(cpu)
+ for_each_possible_cpu(cpu)
svm_cpu_uninit(cpu);
__free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER);
@@ -758,14 +764,13 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
int i;
if (unlikely(cpu != vcpu->cpu)) {
- u64 tsc_this, delta;
+ u64 delta;
/*
* Make sure that the guest sees a monotonically
* increasing TSC.
*/
- rdtscll(tsc_this);
- delta = vcpu->arch.host_tsc - tsc_this;
+ 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;
@@ -787,7 +792,7 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
- rdtscll(vcpu->arch.host_tsc);
+ vcpu->arch.host_tsc = native_read_tsc();
}
static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
@@ -1060,26 +1065,16 @@ static void update_db_intercept(struct kvm_vcpu *vcpu)
vcpu->guest_debug = 0;
}
-static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
+static void svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
{
- int old_debug = vcpu->guest_debug;
struct vcpu_svm *svm = to_svm(vcpu);
- vcpu->guest_debug = dbg->control;
-
- update_db_intercept(vcpu);
-
if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
svm->vmcb->save.dr7 = dbg->arch.debugreg[7];
else
svm->vmcb->save.dr7 = vcpu->arch.dr7;
- if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
- svm->vmcb->save.rflags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
- else if (old_debug & KVM_GUESTDBG_SINGLESTEP)
- svm->vmcb->save.rflags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF);
-
- return 0;
+ update_db_intercept(vcpu);
}
static void load_host_msrs(struct kvm_vcpu *vcpu)
@@ -1180,7 +1175,7 @@ static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
}
}
-static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int pf_interception(struct vcpu_svm *svm)
{
u64 fault_address;
u32 error_code;
@@ -1194,8 +1189,10 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
return kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code);
}
-static int db_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int db_interception(struct vcpu_svm *svm)
{
+ struct kvm_run *kvm_run = svm->vcpu.run;
+
if (!(svm->vcpu.guest_debug &
(KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) &&
!svm->vcpu.arch.singlestep) {
@@ -1223,25 +1220,27 @@ static int db_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
return 1;
}
-static int bp_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int bp_interception(struct vcpu_svm *svm)
{
+ struct kvm_run *kvm_run = svm->vcpu.run;
+
kvm_run->exit_reason = KVM_EXIT_DEBUG;
kvm_run->debug.arch.pc = svm->vmcb->save.cs.base + svm->vmcb->save.rip;
kvm_run->debug.arch.exception = BP_VECTOR;
return 0;
}
-static int ud_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int ud_interception(struct vcpu_svm *svm)
{
int er;
- er = emulate_instruction(&svm->vcpu, kvm_run, 0, 0, EMULTYPE_TRAP_UD);
+ er = emulate_instruction(&svm->vcpu, 0, 0, EMULTYPE_TRAP_UD);
if (er != EMULATE_DONE)
kvm_queue_exception(&svm->vcpu, UD_VECTOR);
return 1;
}
-static int nm_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int nm_interception(struct vcpu_svm *svm)
{
svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
if (!(svm->vcpu.arch.cr0 & X86_CR0_TS))
@@ -1251,7 +1250,7 @@ static int nm_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
return 1;
}
-static int mc_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int mc_interception(struct vcpu_svm *svm)
{
/*
* On an #MC intercept the MCE handler is not called automatically in
@@ -1264,8 +1263,10 @@ static int mc_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
return 1;
}
-static int shutdown_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int shutdown_interception(struct vcpu_svm *svm)
{
+ struct kvm_run *kvm_run = svm->vcpu.run;
+
/*
* VMCB is undefined after a SHUTDOWN intercept
* so reinitialize it.
@@ -1277,7 +1278,7 @@ static int shutdown_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
return 0;
}
-static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int io_interception(struct vcpu_svm *svm)
{
u32 io_info = svm->vmcb->control.exit_info_1; /* address size bug? */
int size, in, string;
@@ -1291,7 +1292,7 @@ static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
if (string) {
if (emulate_instruction(&svm->vcpu,
- kvm_run, 0, 0, 0) == EMULATE_DO_MMIO)
+ 0, 0, 0) == EMULATE_DO_MMIO)
return 0;
return 1;
}
@@ -1301,33 +1302,33 @@ static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT;
skip_emulated_instruction(&svm->vcpu);
- return kvm_emulate_pio(&svm->vcpu, kvm_run, in, size, port);
+ return kvm_emulate_pio(&svm->vcpu, in, size, port);
}
-static int nmi_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int nmi_interception(struct vcpu_svm *svm)
{
return 1;
}
-static int intr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int intr_interception(struct vcpu_svm *svm)
{
++svm->vcpu.stat.irq_exits;
return 1;
}
-static int nop_on_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int nop_on_interception(struct vcpu_svm *svm)
{
return 1;
}
-static int halt_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int halt_interception(struct vcpu_svm *svm)
{
svm->next_rip = kvm_rip_read(&svm->vcpu) + 1;
skip_emulated_instruction(&svm->vcpu);
return kvm_emulate_halt(&svm->vcpu);
}
-static int vmmcall_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int vmmcall_interception(struct vcpu_svm *svm)
{
svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
skip_emulated_instruction(&svm->vcpu);
@@ -1390,10 +1391,7 @@ static void *nested_svm_map(struct vcpu_svm *svm, u64 gpa, enum km_type idx)
{
struct page *page;
- down_read(&current->mm->mmap_sem);
page = gfn_to_page(svm->vcpu.kvm, gpa >> PAGE_SHIFT);
- up_read(&current->mm->mmap_sem);
-
if (is_error_page(page))
goto error;
@@ -1789,8 +1787,6 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
svm->nested.intercept = nested_vmcb->control.intercept;
force_new_asid(&svm->vcpu);
- svm->vmcb->control.exit_int_info = nested_vmcb->control.exit_int_info;
- svm->vmcb->control.exit_int_info_err = nested_vmcb->control.exit_int_info_err;
svm->vmcb->control.int_ctl = nested_vmcb->control.int_ctl | V_INTR_MASKING_MASK;
if (nested_vmcb->control.int_ctl & V_IRQ_MASK) {
nsvm_printk("nSVM Injecting Interrupt: 0x%x\n",
@@ -1837,7 +1833,7 @@ static void nested_svm_vmloadsave(struct vmcb *from_vmcb, struct vmcb *to_vmcb)
to_vmcb->save.sysenter_eip = from_vmcb->save.sysenter_eip;
}
-static int vmload_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int vmload_interception(struct vcpu_svm *svm)
{
struct vmcb *nested_vmcb;
@@ -1857,7 +1853,7 @@ static int vmload_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
return 1;
}
-static int vmsave_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int vmsave_interception(struct vcpu_svm *svm)
{
struct vmcb *nested_vmcb;
@@ -1877,7 +1873,7 @@ static int vmsave_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
return 1;
}
-static int vmrun_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int vmrun_interception(struct vcpu_svm *svm)
{
nsvm_printk("VMrun\n");
@@ -1907,7 +1903,7 @@ failed:
return 1;
}
-static int stgi_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int stgi_interception(struct vcpu_svm *svm)
{
if (nested_svm_check_permissions(svm))
return 1;
@@ -1920,7 +1916,7 @@ static int stgi_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
return 1;
}
-static int clgi_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int clgi_interception(struct vcpu_svm *svm)
{
if (nested_svm_check_permissions(svm))
return 1;
@@ -1937,7 +1933,7 @@ static int clgi_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
return 1;
}
-static int invlpga_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int invlpga_interception(struct vcpu_svm *svm)
{
struct kvm_vcpu *vcpu = &svm->vcpu;
nsvm_printk("INVLPGA\n");
@@ -1950,15 +1946,13 @@ static int invlpga_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
return 1;
}
-static int invalid_op_interception(struct vcpu_svm *svm,
- struct kvm_run *kvm_run)
+static int invalid_op_interception(struct vcpu_svm *svm)
{
kvm_queue_exception(&svm->vcpu, UD_VECTOR);
return 1;
}
-static int task_switch_interception(struct vcpu_svm *svm,
- struct kvm_run *kvm_run)
+static int task_switch_interception(struct vcpu_svm *svm)
{
u16 tss_selector;
int reason;
@@ -2008,14 +2002,14 @@ static int task_switch_interception(struct vcpu_svm *svm,
return kvm_task_switch(&svm->vcpu, tss_selector, reason);
}
-static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int cpuid_interception(struct vcpu_svm *svm)
{
svm->next_rip = kvm_rip_read(&svm->vcpu) + 2;
kvm_emulate_cpuid(&svm->vcpu);
return 1;
}
-static int iret_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int iret_interception(struct vcpu_svm *svm)
{
++svm->vcpu.stat.nmi_window_exits;
svm->vmcb->control.intercept &= ~(1UL << INTERCEPT_IRET);
@@ -2023,26 +2017,27 @@ static int iret_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
return 1;
}
-static int invlpg_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int invlpg_interception(struct vcpu_svm *svm)
{
- if (emulate_instruction(&svm->vcpu, kvm_run, 0, 0, 0) != EMULATE_DONE)
+ if (emulate_instruction(&svm->vcpu, 0, 0, 0) != EMULATE_DONE)
pr_unimpl(&svm->vcpu, "%s: failed\n", __func__);
return 1;
}
-static int emulate_on_interception(struct vcpu_svm *svm,
- struct kvm_run *kvm_run)
+static int emulate_on_interception(struct vcpu_svm *svm)
{
- if (emulate_instruction(&svm->vcpu, NULL, 0, 0, 0) != EMULATE_DONE)
+ if (emulate_instruction(&svm->vcpu, 0, 0, 0) != EMULATE_DONE)
pr_unimpl(&svm->vcpu, "%s: failed\n", __func__);
return 1;
}
-static int cr8_write_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int cr8_write_interception(struct vcpu_svm *svm)
{
+ struct kvm_run *kvm_run = svm->vcpu.run;
+
u8 cr8_prev = kvm_get_cr8(&svm->vcpu);
/* instruction emulation calls kvm_set_cr8() */
- emulate_instruction(&svm->vcpu, NULL, 0, 0, 0);
+ emulate_instruction(&svm->vcpu, 0, 0, 0);
if (irqchip_in_kernel(svm->vcpu.kvm)) {
svm->vmcb->control.intercept_cr_write &= ~INTERCEPT_CR8_MASK;
return 1;
@@ -2128,7 +2123,7 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
return 0;
}
-static int rdmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int rdmsr_interception(struct vcpu_svm *svm)
{
u32 ecx = svm->vcpu.arch.regs[VCPU_REGS_RCX];
u64 data;
@@ -2221,7 +2216,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
return 0;
}
-static int wrmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int wrmsr_interception(struct vcpu_svm *svm)
{
u32 ecx = svm->vcpu.arch.regs[VCPU_REGS_RCX];
u64 data = (svm->vcpu.arch.regs[VCPU_REGS_RAX] & -1u)
@@ -2237,17 +2232,18 @@ static int wrmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
return 1;
}
-static int msr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
+static int msr_interception(struct vcpu_svm *svm)
{
if (svm->vmcb->control.exit_info_1)
- return wrmsr_interception(svm, kvm_run);
+ return wrmsr_interception(svm);
else
- return rdmsr_interception(svm, kvm_run);
+ return rdmsr_interception(svm);
}
-static int interrupt_window_interception(struct vcpu_svm *svm,
- struct kvm_run *kvm_run)
+static int interrupt_window_interception(struct vcpu_svm *svm)
{
+ struct kvm_run *kvm_run = svm->vcpu.run;
+
svm_clear_vintr(svm);
svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
/*
@@ -2265,8 +2261,7 @@ static int interrupt_window_interception(struct vcpu_svm *svm,
return 1;
}
-static int (*svm_exit_handlers[])(struct vcpu_svm *svm,
- struct kvm_run *kvm_run) = {
+static int (*svm_exit_handlers[])(struct vcpu_svm *svm) = {
[SVM_EXIT_READ_CR0] = emulate_on_interception,
[SVM_EXIT_READ_CR3] = emulate_on_interception,
[SVM_EXIT_READ_CR4] = emulate_on_interception,
@@ -2321,9 +2316,10 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm,
[SVM_EXIT_NPF] = pf_interception,
};
-static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
+static int handle_exit(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
+ struct kvm_run *kvm_run = vcpu->run;
u32 exit_code = svm->vmcb->control.exit_code;
trace_kvm_exit(exit_code, svm->vmcb->save.rip);
@@ -2383,7 +2379,7 @@ static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
return 0;
}
- return svm_exit_handlers[exit_code](svm, kvm_run);
+ return svm_exit_handlers[exit_code](svm);
}
static void reload_tss(struct kvm_vcpu *vcpu)
@@ -2464,10 +2460,18 @@ static int svm_interrupt_allowed(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
struct vmcb *vmcb = svm->vmcb;
- return (vmcb->save.rflags & X86_EFLAGS_IF) &&
- !(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) &&
- gif_set(svm) &&
- !(is_nested(svm) && (svm->vcpu.arch.hflags & HF_VINTR_MASK));
+ int ret;
+
+ if (!gif_set(svm) ||
+ (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK))
+ return 0;
+
+ ret = !!(vmcb->save.rflags & X86_EFLAGS_IF);
+
+ if (is_nested(svm))
+ return ret && !(svm->vcpu.arch.hflags & HF_VINTR_MASK);
+
+ return ret;
}
static void enable_irq_window(struct kvm_vcpu *vcpu)
@@ -2588,7 +2592,7 @@ static void svm_complete_interrupts(struct vcpu_svm *svm)
#define R "e"
#endif
-static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static void svm_vcpu_run(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
u16 fs_selector;
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index ed53b42caba1..70020e505c22 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -107,7 +107,6 @@ struct vcpu_vmx {
} rmode;
int vpid;
bool emulation_required;
- enum emulation_result invalid_state_emulation_result;
/* Support for vnmi-less CPUs */
int soft_vnmi_blocked;
@@ -1097,30 +1096,14 @@ static void vmx_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg)
}
}
-static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
+static void set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg)
{
- int old_debug = vcpu->guest_debug;
- unsigned long flags;
-
- vcpu->guest_debug = dbg->control;
- if (!(vcpu->guest_debug & KVM_GUESTDBG_ENABLE))
- vcpu->guest_debug = 0;
-
if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
vmcs_writel(GUEST_DR7, dbg->arch.debugreg[7]);
else
vmcs_writel(GUEST_DR7, vcpu->arch.dr7);
- flags = vmcs_readl(GUEST_RFLAGS);
- if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
- flags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
- else if (old_debug & KVM_GUESTDBG_SINGLESTEP)
- flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF);
- vmcs_writel(GUEST_RFLAGS, flags);
-
update_exception_bitmap(vcpu);
-
- return 0;
}
static __init int cpu_has_kvm_support(void)
@@ -1139,12 +1122,15 @@ static __init int vmx_disabled_by_bios(void)
/* locked but not enabled */
}
-static void hardware_enable(void *garbage)
+static int hardware_enable(void *garbage)
{
int cpu = raw_smp_processor_id();
u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
u64 old;
+ if (read_cr4() & X86_CR4_VMXE)
+ return -EBUSY;
+
INIT_LIST_HEAD(&per_cpu(vcpus_on_cpu, cpu));
rdmsrl(MSR_IA32_FEATURE_CONTROL, old);
if ((old & (FEATURE_CONTROL_LOCKED |
@@ -1159,6 +1145,10 @@ static void hardware_enable(void *garbage)
asm volatile (ASM_VMX_VMXON_RAX
: : "a"(&phys_addr), "m"(phys_addr)
: "memory", "cc");
+
+ ept_sync_global();
+
+ return 0;
}
static void vmclear_local_vcpus(void)
@@ -1344,15 +1334,17 @@ static void free_kvm_area(void)
{
int cpu;
- for_each_online_cpu(cpu)
+ for_each_possible_cpu(cpu) {
free_vmcs(per_cpu(vmxarea, cpu));
+ per_cpu(vmxarea, cpu) = NULL;
+ }
}
static __init int alloc_kvm_area(void)
{
int cpu;
- for_each_online_cpu(cpu) {
+ for_each_possible_cpu(cpu) {
struct vmcs *vmcs;
vmcs = alloc_vmcs_cpu(cpu);
@@ -2659,7 +2651,7 @@ static int handle_rmode_exception(struct kvm_vcpu *vcpu,
* Cause the #SS fault with 0 error code in VM86 mode.
*/
if (((vec == GP_VECTOR) || (vec == SS_VECTOR)) && err_code == 0)
- if (emulate_instruction(vcpu, NULL, 0, 0, 0) == EMULATE_DONE)
+ if (emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DONE)
return 1;
/*
* Forward all other exceptions that are valid in real mode.
@@ -2710,15 +2702,16 @@ static void kvm_machine_check(void)
#endif
}
-static int handle_machine_check(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_machine_check(struct kvm_vcpu *vcpu)
{
/* already handled by vcpu_run */
return 1;
}
-static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_exception(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
+ struct kvm_run *kvm_run = vcpu->run;
u32 intr_info, ex_no, error_code;
unsigned long cr2, rip, dr6;
u32 vect_info;
@@ -2728,7 +2721,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
if (is_machine_check(intr_info))
- return handle_machine_check(vcpu, kvm_run);
+ return handle_machine_check(vcpu);
if ((vect_info & VECTORING_INFO_VALID_MASK) &&
!is_page_fault(intr_info))
@@ -2744,7 +2737,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
}
if (is_invalid_opcode(intr_info)) {
- er = emulate_instruction(vcpu, kvm_run, 0, 0, EMULTYPE_TRAP_UD);
+ er = emulate_instruction(vcpu, 0, 0, EMULTYPE_TRAP_UD);
if (er != EMULATE_DONE)
kvm_queue_exception(vcpu, UD_VECTOR);
return 1;
@@ -2803,20 +2796,19 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 0;
}
-static int handle_external_interrupt(struct kvm_vcpu *vcpu,
- struct kvm_run *kvm_run)
+static int handle_external_interrupt(struct kvm_vcpu *vcpu)
{
++vcpu->stat.irq_exits;
return 1;
}
-static int handle_triple_fault(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_triple_fault(struct kvm_vcpu *vcpu)
{
- kvm_run->exit_reason = KVM_EXIT_SHUTDOWN;
+ vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
return 0;
}
-static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_io(struct kvm_vcpu *vcpu)
{
unsigned long exit_qualification;
int size, in, string;
@@ -2827,8 +2819,7 @@ static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
string = (exit_qualification & 16) != 0;
if (string) {
- if (emulate_instruction(vcpu,
- kvm_run, 0, 0, 0) == EMULATE_DO_MMIO)
+ if (emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DO_MMIO)
return 0;
return 1;
}
@@ -2838,7 +2829,7 @@ static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
port = exit_qualification >> 16;
skip_emulated_instruction(vcpu);
- return kvm_emulate_pio(vcpu, kvm_run, in, size, port);
+ return kvm_emulate_pio(vcpu, in, size, port);
}
static void
@@ -2852,7 +2843,7 @@ vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
hypercall[2] = 0xc1;
}
-static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_cr(struct kvm_vcpu *vcpu)
{
unsigned long exit_qualification, val;
int cr;
@@ -2887,7 +2878,7 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
if (cr8_prev <= cr8)
return 1;
- kvm_run->exit_reason = KVM_EXIT_SET_TPR;
+ vcpu->run->exit_reason = KVM_EXIT_SET_TPR;
return 0;
}
};
@@ -2922,13 +2913,13 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
default:
break;
}
- kvm_run->exit_reason = 0;
+ vcpu->run->exit_reason = 0;
pr_unimpl(vcpu, "unhandled control register: op %d cr %d\n",
(int)(exit_qualification >> 4) & 3, cr);
return 0;
}
-static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_dr(struct kvm_vcpu *vcpu)
{
unsigned long exit_qualification;
unsigned long val;
@@ -2944,13 +2935,13 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
* guest debugging itself.
*/
if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) {
- kvm_run->debug.arch.dr6 = vcpu->arch.dr6;
- kvm_run->debug.arch.dr7 = dr;
- kvm_run->debug.arch.pc =
+ vcpu->run->debug.arch.dr6 = vcpu->arch.dr6;
+ vcpu->run->debug.arch.dr7 = dr;
+ vcpu->run->debug.arch.pc =
vmcs_readl(GUEST_CS_BASE) +
vmcs_readl(GUEST_RIP);
- kvm_run->debug.arch.exception = DB_VECTOR;
- kvm_run->exit_reason = KVM_EXIT_DEBUG;
+ vcpu->run->debug.arch.exception = DB_VECTOR;
+ vcpu->run->exit_reason = KVM_EXIT_DEBUG;
return 0;
} else {
vcpu->arch.dr7 &= ~DR7_GD;
@@ -3016,13 +3007,13 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
}
-static int handle_cpuid(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_cpuid(struct kvm_vcpu *vcpu)
{
kvm_emulate_cpuid(vcpu);
return 1;
}
-static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_rdmsr(struct kvm_vcpu *vcpu)
{
u32 ecx = vcpu->arch.regs[VCPU_REGS_RCX];
u64 data;
@@ -3041,7 +3032,7 @@ static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
}
-static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_wrmsr(struct kvm_vcpu *vcpu)
{
u32 ecx = vcpu->arch.regs[VCPU_REGS_RCX];
u64 data = (vcpu->arch.regs[VCPU_REGS_RAX] & -1u)
@@ -3058,14 +3049,12 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
}
-static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu,
- struct kvm_run *kvm_run)
+static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu)
{
return 1;
}
-static int handle_interrupt_window(struct kvm_vcpu *vcpu,
- struct kvm_run *kvm_run)
+static int handle_interrupt_window(struct kvm_vcpu *vcpu)
{
u32 cpu_based_vm_exec_control;
@@ -3081,34 +3070,34 @@ static int handle_interrupt_window(struct kvm_vcpu *vcpu,
* possible
*/
if (!irqchip_in_kernel(vcpu->kvm) &&
- kvm_run->request_interrupt_window &&
+ vcpu->run->request_interrupt_window &&
!kvm_cpu_has_interrupt(vcpu)) {
- kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
+ vcpu->run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
return 0;
}
return 1;
}
-static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_halt(struct kvm_vcpu *vcpu)
{
skip_emulated_instruction(vcpu);
return kvm_emulate_halt(vcpu);
}
-static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_vmcall(struct kvm_vcpu *vcpu)
{
skip_emulated_instruction(vcpu);
kvm_emulate_hypercall(vcpu);
return 1;
}
-static int handle_vmx_insn(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_vmx_insn(struct kvm_vcpu *vcpu)
{
kvm_queue_exception(vcpu, UD_VECTOR);
return 1;
}
-static int handle_invlpg(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_invlpg(struct kvm_vcpu *vcpu)
{
unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
@@ -3117,14 +3106,14 @@ static int handle_invlpg(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
}
-static int handle_wbinvd(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_wbinvd(struct kvm_vcpu *vcpu)
{
skip_emulated_instruction(vcpu);
/* TODO: Add support for VT-d/pass-through device */
return 1;
}
-static int handle_apic_access(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_apic_access(struct kvm_vcpu *vcpu)
{
unsigned long exit_qualification;
enum emulation_result er;
@@ -3133,7 +3122,7 @@ static int handle_apic_access(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
offset = exit_qualification & 0xffful;
- er = emulate_instruction(vcpu, kvm_run, 0, 0, 0);
+ er = emulate_instruction(vcpu, 0, 0, 0);
if (er != EMULATE_DONE) {
printk(KERN_ERR
@@ -3144,7 +3133,7 @@ static int handle_apic_access(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
}
-static int handle_task_switch(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_task_switch(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
unsigned long exit_qualification;
@@ -3198,7 +3187,7 @@ static int handle_task_switch(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
}
-static int handle_ept_violation(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_ept_violation(struct kvm_vcpu *vcpu)
{
unsigned long exit_qualification;
gpa_t gpa;
@@ -3219,8 +3208,8 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
vmcs_readl(GUEST_LINEAR_ADDRESS));
printk(KERN_ERR "EPT: Exit qualification is 0x%lx\n",
(long unsigned int)exit_qualification);
- kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
- kvm_run->hw.hardware_exit_reason = EXIT_REASON_EPT_VIOLATION;
+ vcpu->run->exit_reason = KVM_EXIT_UNKNOWN;
+ vcpu->run->hw.hardware_exit_reason = EXIT_REASON_EPT_VIOLATION;
return 0;
}
@@ -3290,7 +3279,7 @@ static void ept_misconfig_inspect_spte(struct kvm_vcpu *vcpu, u64 spte,
}
}
-static int handle_ept_misconfig(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_ept_misconfig(struct kvm_vcpu *vcpu)
{
u64 sptes[4];
int nr_sptes, i;
@@ -3306,13 +3295,13 @@ static int handle_ept_misconfig(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
for (i = PT64_ROOT_LEVEL; i > PT64_ROOT_LEVEL - nr_sptes; --i)
ept_misconfig_inspect_spte(vcpu, sptes[i-1], i);
- kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
- kvm_run->hw.hardware_exit_reason = EXIT_REASON_EPT_MISCONFIG;
+ vcpu->run->exit_reason = KVM_EXIT_UNKNOWN;
+ vcpu->run->hw.hardware_exit_reason = EXIT_REASON_EPT_MISCONFIG;
return 0;
}
-static int handle_nmi_window(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_nmi_window(struct kvm_vcpu *vcpu)
{
u32 cpu_based_vm_exec_control;
@@ -3325,36 +3314,37 @@ static int handle_nmi_window(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
}
-static void handle_invalid_guest_state(struct kvm_vcpu *vcpu,
- struct kvm_run *kvm_run)
+static int handle_invalid_guest_state(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
enum emulation_result err = EMULATE_DONE;
-
- local_irq_enable();
- preempt_enable();
+ int ret = 1;
while (!guest_state_valid(vcpu)) {
- err = emulate_instruction(vcpu, kvm_run, 0, 0, 0);
+ err = emulate_instruction(vcpu, 0, 0, 0);
- if (err == EMULATE_DO_MMIO)
- break;
+ if (err == EMULATE_DO_MMIO) {
+ ret = 0;
+ goto out;
+ }
if (err != EMULATE_DONE) {
kvm_report_emulation_failure(vcpu, "emulation failure");
- break;
+ vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+ vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
+ ret = 0;
+ goto out;
}
if (signal_pending(current))
- break;
+ goto out;
if (need_resched())
schedule();
}
- preempt_disable();
- local_irq_disable();
-
- vmx->invalid_state_emulation_result = err;
+ vmx->emulation_required = 0;
+out:
+ return ret;
}
/*
@@ -3362,8 +3352,7 @@ static void handle_invalid_guest_state(struct kvm_vcpu *vcpu,
* may resume. Otherwise they set the kvm_run parameter to indicate what needs
* to be done to userspace and return 0.
*/
-static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
- struct kvm_run *kvm_run) = {
+static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = {
[EXIT_REASON_EXCEPTION_NMI] = handle_exception,
[EXIT_REASON_EXTERNAL_INTERRUPT] = handle_external_interrupt,
[EXIT_REASON_TRIPLE_FAULT] = handle_triple_fault,
@@ -3403,7 +3392,7 @@ static const int kvm_vmx_max_exit_handlers =
* The guest has exited. See if we can fix it or if we need userspace
* assistance.
*/
-static int vmx_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
+static int vmx_handle_exit(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
u32 exit_reason = vmx->exit_reason;
@@ -3411,13 +3400,9 @@ static int vmx_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
trace_kvm_exit(exit_reason, kvm_rip_read(vcpu));
- /* If we need to emulate an MMIO from handle_invalid_guest_state
- * we just return 0 */
- if (vmx->emulation_required && emulate_invalid_guest_state) {
- if (guest_state_valid(vcpu))
- vmx->emulation_required = 0;
- return vmx->invalid_state_emulation_result != EMULATE_DO_MMIO;
- }
+ /* If guest state is invalid, start emulating */
+ if (vmx->emulation_required && emulate_invalid_guest_state)
+ return handle_invalid_guest_state(vcpu);
/* Access CR3 don't cause VMExit in paging mode, so we need
* to sync with guest real CR3. */
@@ -3425,8 +3410,8 @@ static int vmx_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
vcpu->arch.cr3 = vmcs_readl(GUEST_CR3);
if (unlikely(vmx->fail)) {
- kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
- kvm_run->fail_entry.hardware_entry_failure_reason
+ vcpu->run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+ vcpu->run->fail_entry.hardware_entry_failure_reason
= vmcs_read32(VM_INSTRUCTION_ERROR);
return 0;
}
@@ -3459,10 +3444,10 @@ static int vmx_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
if (exit_reason < kvm_vmx_max_exit_handlers
&& kvm_vmx_exit_handlers[exit_reason])
- return kvm_vmx_exit_handlers[exit_reason](vcpu, kvm_run);
+ return kvm_vmx_exit_handlers[exit_reason](vcpu);
else {
- kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
- kvm_run->hw.hardware_exit_reason = exit_reason;
+ vcpu->run->exit_reason = KVM_EXIT_UNKNOWN;
+ vcpu->run->hw.hardware_exit_reason = exit_reason;
}
return 0;
}
@@ -3600,7 +3585,7 @@ static void fixup_rmode_irq(struct vcpu_vmx *vmx)
#define Q "l"
#endif
-static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -3612,11 +3597,10 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
if (unlikely(!cpu_has_virtual_nmis() && vmx->soft_vnmi_blocked))
vmx->entry_time = ktime_get();
- /* Handle invalid guest state instead of entering VMX */
- if (vmx->emulation_required && emulate_invalid_guest_state) {
- handle_invalid_guest_state(vcpu, kvm_run);
+ /* Don't enter VMX if guest state is invalid, let the exit handler
+ start emulation until we arrive back to a valid state */
+ if (vmx->emulation_required && emulate_invalid_guest_state)
return;
- }
if (test_bit(VCPU_REGS_RSP, (unsigned long *)&vcpu->arch.regs_dirty))
vmcs_writel(GUEST_RSP, vcpu->arch.regs[VCPU_REGS_RSP]);
@@ -4049,8 +4033,6 @@ static int __init vmx_init(void)
if (bypass_guest_pf)
kvm_mmu_set_nonpresent_ptes(~0xffeull, 0ull);
- ept_sync_global();
-
return 0;
out3:
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 9b9695322f56..11a6f2f440ae 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -235,6 +235,25 @@ bool kvm_require_cpl(struct kvm_vcpu *vcpu, int required_cpl)
}
EXPORT_SYMBOL_GPL(kvm_require_cpl);
+unsigned long kvm_get_rflags(struct kvm_vcpu *vcpu)
+{
+ unsigned long rflags;
+
+ rflags = kvm_x86_ops->get_rflags(vcpu);
+ if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
+ rflags &= ~(unsigned long)(X86_EFLAGS_TF | X86_EFLAGS_RF);
+ return rflags;
+}
+EXPORT_SYMBOL_GPL(kvm_get_rflags);
+
+void kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
+{
+ if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
+ rflags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
+ kvm_x86_ops->set_rflags(vcpu, rflags);
+}
+EXPORT_SYMBOL_GPL(kvm_set_rflags);
+
/*
* Load the pae pdptrs. Return true is they are all valid.
*/
@@ -1238,8 +1257,8 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_NR_MEMSLOTS:
r = KVM_MEMORY_SLOTS;
break;
- case KVM_CAP_PV_MMU:
- r = !tdp_enabled;
+ case KVM_CAP_PV_MMU: /* obsolete */
+ r = 0;
break;
case KVM_CAP_IOMMU:
r = iommu_found();
@@ -1326,6 +1345,8 @@ out:
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))
+ per_cpu(cpu_tsc_khz, cpu) = cpufreq_quick_get(cpu);
kvm_request_guest_time_update(vcpu);
}
@@ -2038,9 +2059,7 @@ static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
sizeof(struct kvm_pic_state));
break;
case KVM_IRQCHIP_IOAPIC:
- memcpy(&chip->chip.ioapic,
- ioapic_irqchip(kvm),
- sizeof(struct kvm_ioapic_state));
+ r = kvm_get_ioapic(kvm, &chip->chip.ioapic);
break;
default:
r = -EINVAL;
@@ -2070,11 +2089,7 @@ static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
spin_unlock(&pic_irqchip(kvm)->lock);
break;
case KVM_IRQCHIP_IOAPIC:
- mutex_lock(&kvm->irq_lock);
- memcpy(ioapic_irqchip(kvm),
- &chip->chip.ioapic,
- sizeof(struct kvm_ioapic_state));
- mutex_unlock(&kvm->irq_lock);
+ r = kvm_set_ioapic(kvm, &chip->chip.ioapic);
break;
default:
r = -EINVAL;
@@ -2182,7 +2197,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
{
struct kvm *kvm = filp->private_data;
void __user *argp = (void __user *)arg;
- int r = -EINVAL;
+ int r = -ENOTTY;
/*
* This union makes it completely explicit to gcc-3.x
* that these two variables' stack usage should be
@@ -2292,10 +2307,8 @@ long kvm_arch_vm_ioctl(struct file *filp,
goto out;
if (irqchip_in_kernel(kvm)) {
__s32 status;
- mutex_lock(&kvm->irq_lock);
status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
irq_event.irq, irq_event.level);
- mutex_unlock(&kvm->irq_lock);
if (ioctl == KVM_IRQ_LINE_STATUS) {
irq_event.status = status;
if (copy_to_user(argp, &irq_event,
@@ -2757,13 +2770,13 @@ static void cache_all_regs(struct kvm_vcpu *vcpu)
}
int emulate_instruction(struct kvm_vcpu *vcpu,
- struct kvm_run *run,
unsigned long cr2,
u16 error_code,
int emulation_type)
{
int r, shadow_mask;
struct decode_cache *c;
+ struct kvm_run *run = vcpu->run;
kvm_clear_exception_queue(vcpu);
vcpu->arch.mmio_fault_cr2 = cr2;
@@ -2783,7 +2796,7 @@ int emulate_instruction(struct kvm_vcpu *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.eflags = kvm_get_rflags(vcpu);
vcpu->arch.emulate_ctxt.mode =
(vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM)
? X86EMUL_MODE_REAL : cs_l
@@ -2861,7 +2874,7 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
return EMULATE_DO_MMIO;
}
- kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
+ kvm_set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
if (vcpu->mmio_is_write) {
vcpu->mmio_needed = 0;
@@ -2969,8 +2982,7 @@ static int pio_string_write(struct kvm_vcpu *vcpu)
return r;
}
-int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
- int size, unsigned port)
+int kvm_emulate_pio(struct kvm_vcpu *vcpu, int in, int size, unsigned port)
{
unsigned long val;
@@ -2999,7 +3011,7 @@ int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
}
EXPORT_SYMBOL_GPL(kvm_emulate_pio);
-int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in,
int size, unsigned long count, int down,
gva_t address, int rep, unsigned port)
{
@@ -3072,9 +3084,6 @@ static void bounce_off(void *info)
/* nothing */
}
-static unsigned int ref_freq;
-static unsigned long tsc_khz_ref;
-
static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
void *data)
{
@@ -3083,14 +3092,11 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long va
struct kvm_vcpu *vcpu;
int i, send_ipi = 0;
- if (!ref_freq)
- ref_freq = freq->old;
-
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) = cpufreq_scale(tsc_khz_ref, ref_freq, freq->new);
+ per_cpu(cpu_tsc_khz, freq->cpu) = freq->new;
spin_lock(&kvm_lock);
list_for_each_entry(kvm, &vm_list, vm_list) {
@@ -3127,9 +3133,24 @@ static struct notifier_block kvmclock_cpufreq_notifier_block = {
.notifier_call = kvmclock_cpufreq_notifier
};
+static void kvm_timer_init(void)
+{
+ int cpu;
+
+ if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) {
+ cpufreq_register_notifier(&kvmclock_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ for_each_online_cpu(cpu)
+ per_cpu(cpu_tsc_khz, cpu) = cpufreq_get(cpu);
+ } else {
+ for_each_possible_cpu(cpu)
+ per_cpu(cpu_tsc_khz, cpu) = tsc_khz;
+ }
+}
+
int kvm_arch_init(void *opaque)
{
- int r, cpu;
+ int r;
struct kvm_x86_ops *ops = (struct kvm_x86_ops *)opaque;
if (kvm_x86_ops) {
@@ -3161,13 +3182,7 @@ int kvm_arch_init(void *opaque)
kvm_mmu_set_mask_ptes(PT_USER_MASK, PT_ACCESSED_MASK,
PT_DIRTY_MASK, PT64_NX_MASK, 0);
- for_each_possible_cpu(cpu)
- per_cpu(cpu_tsc_khz, cpu) = tsc_khz;
- if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) {
- tsc_khz_ref = tsc_khz;
- cpufreq_register_notifier(&kvmclock_cpufreq_notifier_block,
- CPUFREQ_TRANSITION_NOTIFIER);
- }
+ kvm_timer_init();
return 0;
@@ -3295,7 +3310,7 @@ void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
unsigned long *rflags)
{
kvm_lmsw(vcpu, msw);
- *rflags = kvm_x86_ops->get_rflags(vcpu);
+ *rflags = kvm_get_rflags(vcpu);
}
unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
@@ -3333,7 +3348,7 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val,
switch (cr) {
case 0:
kvm_set_cr0(vcpu, mk_cr_64(vcpu->arch.cr0, val));
- *rflags = kvm_x86_ops->get_rflags(vcpu);
+ *rflags = kvm_get_rflags(vcpu);
break;
case 2:
vcpu->arch.cr2 = val;
@@ -3453,18 +3468,18 @@ EXPORT_SYMBOL_GPL(kvm_emulate_cpuid);
*
* No need to exit to userspace if we already have an interrupt queued.
*/
-static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
- struct kvm_run *kvm_run)
+static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu)
{
return (!irqchip_in_kernel(vcpu->kvm) && !kvm_cpu_has_interrupt(vcpu) &&
- kvm_run->request_interrupt_window &&
+ vcpu->run->request_interrupt_window &&
kvm_arch_interrupt_allowed(vcpu));
}
-static void post_kvm_run_save(struct kvm_vcpu *vcpu,
- struct kvm_run *kvm_run)
+static void post_kvm_run_save(struct kvm_vcpu *vcpu)
{
- kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0;
+ struct kvm_run *kvm_run = vcpu->run;
+
+ kvm_run->if_flag = (kvm_get_rflags(vcpu) & X86_EFLAGS_IF) != 0;
kvm_run->cr8 = kvm_get_cr8(vcpu);
kvm_run->apic_base = kvm_get_apic_base(vcpu);
if (irqchip_in_kernel(vcpu->kvm))
@@ -3525,7 +3540,7 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu)
kvm_x86_ops->update_cr8_intercept(vcpu, tpr, max_irr);
}
-static void inject_pending_event(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static void inject_pending_event(struct kvm_vcpu *vcpu)
{
/* try to reinject previous events if any */
if (vcpu->arch.exception.pending) {
@@ -3561,11 +3576,11 @@ static void inject_pending_event(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
}
}
-static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
{
int r;
bool req_int_win = !irqchip_in_kernel(vcpu->kvm) &&
- kvm_run->request_interrupt_window;
+ vcpu->run->request_interrupt_window;
if (vcpu->requests)
if (test_and_clear_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests))
@@ -3586,12 +3601,12 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
kvm_x86_ops->tlb_flush(vcpu);
if (test_and_clear_bit(KVM_REQ_REPORT_TPR_ACCESS,
&vcpu->requests)) {
- kvm_run->exit_reason = KVM_EXIT_TPR_ACCESS;
+ vcpu->run->exit_reason = KVM_EXIT_TPR_ACCESS;
r = 0;
goto out;
}
if (test_and_clear_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests)) {
- kvm_run->exit_reason = KVM_EXIT_SHUTDOWN;
+ vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
r = 0;
goto out;
}
@@ -3615,7 +3630,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
goto out;
}
- inject_pending_event(vcpu, kvm_run);
+ inject_pending_event(vcpu);
/* enable NMI/IRQ window open exits if needed */
if (vcpu->arch.nmi_pending)
@@ -3641,7 +3656,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
}
trace_kvm_entry(vcpu->vcpu_id);
- kvm_x86_ops->run(vcpu, kvm_run);
+ kvm_x86_ops->run(vcpu);
if (unlikely(vcpu->arch.switch_db_regs || test_thread_flag(TIF_DEBUG))) {
set_debugreg(current->thread.debugreg0, 0);
@@ -3682,13 +3697,13 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
kvm_lapic_sync_from_vapic(vcpu);
- r = kvm_x86_ops->handle_exit(kvm_run, vcpu);
+ r = kvm_x86_ops->handle_exit(vcpu);
out:
return r;
}
-static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int __vcpu_run(struct kvm_vcpu *vcpu)
{
int r;
@@ -3708,7 +3723,7 @@ static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
r = 1;
while (r > 0) {
if (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE)
- r = vcpu_enter_guest(vcpu, kvm_run);
+ r = vcpu_enter_guest(vcpu);
else {
up_read(&vcpu->kvm->slots_lock);
kvm_vcpu_block(vcpu);
@@ -3736,14 +3751,14 @@ static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
if (kvm_cpu_has_pending_timer(vcpu))
kvm_inject_pending_timer_irqs(vcpu);
- if (dm_request_for_irq_injection(vcpu, kvm_run)) {
+ if (dm_request_for_irq_injection(vcpu)) {
r = -EINTR;
- kvm_run->exit_reason = KVM_EXIT_INTR;
+ vcpu->run->exit_reason = KVM_EXIT_INTR;
++vcpu->stat.request_irq_exits;
}
if (signal_pending(current)) {
r = -EINTR;
- kvm_run->exit_reason = KVM_EXIT_INTR;
+ vcpu->run->exit_reason = KVM_EXIT_INTR;
++vcpu->stat.signal_exits;
}
if (need_resched()) {
@@ -3754,7 +3769,7 @@ static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
}
up_read(&vcpu->kvm->slots_lock);
- post_kvm_run_save(vcpu, kvm_run);
+ post_kvm_run_save(vcpu);
vapic_exit(vcpu);
@@ -3794,8 +3809,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
vcpu->mmio_needed = 0;
down_read(&vcpu->kvm->slots_lock);
- r = emulate_instruction(vcpu, kvm_run,
- vcpu->arch.mmio_fault_cr2, 0,
+ r = emulate_instruction(vcpu, vcpu->arch.mmio_fault_cr2, 0,
EMULTYPE_NO_DECODE);
up_read(&vcpu->kvm->slots_lock);
if (r == EMULATE_DO_MMIO) {
@@ -3811,7 +3825,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
kvm_register_write(vcpu, VCPU_REGS_RAX,
kvm_run->hypercall.ret);
- r = __vcpu_run(vcpu, kvm_run);
+ r = __vcpu_run(vcpu);
out:
if (vcpu->sigset_active)
@@ -3845,13 +3859,7 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
#endif
regs->rip = kvm_rip_read(vcpu);
- regs->rflags = kvm_x86_ops->get_rflags(vcpu);
-
- /*
- * Don't leak debug flags in case they were set for guest debugging
- */
- if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
- regs->rflags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF);
+ regs->rflags = kvm_get_rflags(vcpu);
vcpu_put(vcpu);
@@ -3879,12 +3887,10 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
kvm_register_write(vcpu, VCPU_REGS_R13, regs->r13);
kvm_register_write(vcpu, VCPU_REGS_R14, regs->r14);
kvm_register_write(vcpu, VCPU_REGS_R15, regs->r15);
-
#endif
kvm_rip_write(vcpu, regs->rip);
- kvm_x86_ops->set_rflags(vcpu, regs->rflags);
-
+ kvm_set_rflags(vcpu, regs->rflags);
vcpu->arch.exception.pending = false;
@@ -4103,7 +4109,7 @@ static int is_vm86_segment(struct kvm_vcpu *vcpu, int seg)
{
return (seg != VCPU_SREG_LDTR) &&
(seg != VCPU_SREG_TR) &&
- (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_VM);
+ (kvm_get_rflags(vcpu) & X86_EFLAGS_VM);
}
int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
@@ -4131,7 +4137,7 @@ static void save_state_to_tss32(struct kvm_vcpu *vcpu,
{
tss->cr3 = vcpu->arch.cr3;
tss->eip = kvm_rip_read(vcpu);
- tss->eflags = kvm_x86_ops->get_rflags(vcpu);
+ tss->eflags = kvm_get_rflags(vcpu);
tss->eax = kvm_register_read(vcpu, VCPU_REGS_RAX);
tss->ecx = kvm_register_read(vcpu, VCPU_REGS_RCX);
tss->edx = kvm_register_read(vcpu, VCPU_REGS_RDX);
@@ -4155,7 +4161,7 @@ static int load_state_from_tss32(struct kvm_vcpu *vcpu,
kvm_set_cr3(vcpu, tss->cr3);
kvm_rip_write(vcpu, tss->eip);
- kvm_x86_ops->set_rflags(vcpu, tss->eflags | 2);
+ kvm_set_rflags(vcpu, tss->eflags | 2);
kvm_register_write(vcpu, VCPU_REGS_RAX, tss->eax);
kvm_register_write(vcpu, VCPU_REGS_RCX, tss->ecx);
@@ -4193,7 +4199,7 @@ static void save_state_to_tss16(struct kvm_vcpu *vcpu,
struct tss_segment_16 *tss)
{
tss->ip = kvm_rip_read(vcpu);
- tss->flag = kvm_x86_ops->get_rflags(vcpu);
+ tss->flag = kvm_get_rflags(vcpu);
tss->ax = kvm_register_read(vcpu, VCPU_REGS_RAX);
tss->cx = kvm_register_read(vcpu, VCPU_REGS_RCX);
tss->dx = kvm_register_read(vcpu, VCPU_REGS_RDX);
@@ -4208,14 +4214,13 @@ static void save_state_to_tss16(struct kvm_vcpu *vcpu,
tss->ss = get_segment_selector(vcpu, VCPU_SREG_SS);
tss->ds = get_segment_selector(vcpu, VCPU_SREG_DS);
tss->ldt = get_segment_selector(vcpu, VCPU_SREG_LDTR);
- tss->prev_task_link = get_segment_selector(vcpu, VCPU_SREG_TR);
}
static int load_state_from_tss16(struct kvm_vcpu *vcpu,
struct tss_segment_16 *tss)
{
kvm_rip_write(vcpu, tss->ip);
- kvm_x86_ops->set_rflags(vcpu, tss->flag | 2);
+ kvm_set_rflags(vcpu, tss->flag | 2);
kvm_register_write(vcpu, VCPU_REGS_RAX, tss->ax);
kvm_register_write(vcpu, VCPU_REGS_RCX, tss->cx);
kvm_register_write(vcpu, VCPU_REGS_RDX, tss->dx);
@@ -4361,8 +4366,8 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
}
if (reason == TASK_SWITCH_IRET) {
- u32 eflags = kvm_x86_ops->get_rflags(vcpu);
- kvm_x86_ops->set_rflags(vcpu, eflags & ~X86_EFLAGS_NT);
+ u32 eflags = kvm_get_rflags(vcpu);
+ kvm_set_rflags(vcpu, eflags & ~X86_EFLAGS_NT);
}
/* set back link to prev task only if NT bit is set in eflags
@@ -4383,8 +4388,8 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
old_tss_base, &nseg_desc);
if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) {
- u32 eflags = kvm_x86_ops->get_rflags(vcpu);
- kvm_x86_ops->set_rflags(vcpu, eflags | X86_EFLAGS_NT);
+ u32 eflags = kvm_get_rflags(vcpu);
+ kvm_set_rflags(vcpu, eflags | X86_EFLAGS_NT);
}
if (reason != TASK_SWITCH_IRET) {
@@ -4478,12 +4483,22 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
struct kvm_guest_debug *dbg)
{
- int i, r;
+ unsigned long rflags;
+ int i;
vcpu_load(vcpu);
- if ((dbg->control & (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP)) ==
- (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP)) {
+ /*
+ * Read rflags as long as potentially injected trace flags are still
+ * filtered out.
+ */
+ rflags = kvm_get_rflags(vcpu);
+
+ vcpu->guest_debug = dbg->control;
+ if (!(vcpu->guest_debug & KVM_GUESTDBG_ENABLE))
+ vcpu->guest_debug = 0;
+
+ if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) {
for (i = 0; i < KVM_NR_DB_REGS; ++i)
vcpu->arch.eff_db[i] = dbg->arch.debugreg[i];
vcpu->arch.switch_db_regs =
@@ -4494,16 +4509,22 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
vcpu->arch.switch_db_regs = (vcpu->arch.dr7 & DR7_BP_EN_MASK);
}
- r = kvm_x86_ops->set_guest_debug(vcpu, dbg);
+ /*
+ * Trigger an rflags update that will inject or remove the trace
+ * flags.
+ */
+ kvm_set_rflags(vcpu, rflags);
+
+ kvm_x86_ops->set_guest_debug(vcpu, dbg);
- if (dbg->control & KVM_GUESTDBG_INJECT_DB)
+ if (vcpu->guest_debug & KVM_GUESTDBG_INJECT_DB)
kvm_queue_exception(vcpu, DB_VECTOR);
- else if (dbg->control & KVM_GUESTDBG_INJECT_BP)
+ else if (vcpu->guest_debug & KVM_GUESTDBG_INJECT_BP)
kvm_queue_exception(vcpu, BP_VECTOR);
vcpu_put(vcpu);
- return r;
+ return 0;
}
/*
@@ -4701,9 +4722,17 @@ int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu)
return kvm_x86_ops->vcpu_reset(vcpu);
}
-void kvm_arch_hardware_enable(void *garbage)
+int kvm_arch_hardware_enable(void *garbage)
{
- kvm_x86_ops->hardware_enable(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;
+ }
+ return kvm_x86_ops->hardware_enable(garbage);
}
void kvm_arch_hardware_disable(void *garbage)
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index 85f5db95c60f..a2d6472895fb 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -2,12 +2,25 @@
# Makefile for x86 specific library files.
#
+inat_tables_script = $(srctree)/arch/x86/tools/gen-insn-attr-x86.awk
+inat_tables_maps = $(srctree)/arch/x86/lib/x86-opcode-map.txt
+quiet_cmd_inat_tables = GEN $@
+ cmd_inat_tables = $(AWK) -f $(inat_tables_script) $(inat_tables_maps) > $@
+
+$(obj)/inat-tables.c: $(inat_tables_script) $(inat_tables_maps)
+ $(call cmd,inat_tables)
+
+$(obj)/inat.o: $(obj)/inat-tables.c
+
+clean-files := inat-tables.c
+
obj-$(CONFIG_SMP) := msr.o
lib-y := delay.o
lib-y += thunk_$(BITS).o
lib-y += usercopy_$(BITS).o getuser.o putuser.o
lib-y += memcpy_$(BITS).o
+lib-y += insn.o inat.o
obj-y += msr-reg.o msr-reg-export.o
diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S
index 6ba0f7bb85ea..4be3c415b3e9 100644
--- a/arch/x86/lib/copy_user_64.S
+++ b/arch/x86/lib/copy_user_64.S
@@ -78,7 +78,7 @@ ENTRY(copy_to_user)
ENDPROC(copy_to_user)
/* Standard copy_from_user with segment limit checking */
-ENTRY(copy_from_user)
+ENTRY(_copy_from_user)
CFI_STARTPROC
GET_THREAD_INFO(%rax)
movq %rsi,%rcx
@@ -88,7 +88,7 @@ ENTRY(copy_from_user)
jae bad_from_user
ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
CFI_ENDPROC
-ENDPROC(copy_from_user)
+ENDPROC(_copy_from_user)
ENTRY(copy_user_generic)
CFI_STARTPROC
diff --git a/arch/x86/lib/inat.c b/arch/x86/lib/inat.c
new file mode 100644
index 000000000000..3fb5998b823e
--- /dev/null
+++ b/arch/x86/lib/inat.c
@@ -0,0 +1,78 @@
+/*
+ * x86 instruction attribute tables
+ *
+ * Written by Masami Hiramatsu <mhiramat@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 <asm/insn.h>
+
+/* Attribute tables are generated from opcode map */
+#include "inat-tables.c"
+
+/* Attribute search APIs */
+insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode)
+{
+ return inat_primary_table[opcode];
+}
+
+insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, insn_byte_t last_pfx,
+ insn_attr_t esc_attr)
+{
+ const insn_attr_t *table;
+ insn_attr_t lpfx_attr;
+ int n, m = 0;
+
+ n = inat_escape_id(esc_attr);
+ if (last_pfx) {
+ lpfx_attr = inat_get_opcode_attribute(last_pfx);
+ m = inat_last_prefix_id(lpfx_attr);
+ }
+ table = inat_escape_tables[n][0];
+ if (!table)
+ return 0;
+ if (inat_has_variant(table[opcode]) && m) {
+ table = inat_escape_tables[n][m];
+ if (!table)
+ return 0;
+ }
+ return table[opcode];
+}
+
+insn_attr_t inat_get_group_attribute(insn_byte_t modrm, insn_byte_t last_pfx,
+ insn_attr_t grp_attr)
+{
+ const insn_attr_t *table;
+ insn_attr_t lpfx_attr;
+ int n, m = 0;
+
+ n = inat_group_id(grp_attr);
+ if (last_pfx) {
+ lpfx_attr = inat_get_opcode_attribute(last_pfx);
+ m = inat_last_prefix_id(lpfx_attr);
+ }
+ table = inat_group_tables[n][0];
+ if (!table)
+ return inat_group_common_attribute(grp_attr);
+ if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && m) {
+ table = inat_group_tables[n][m];
+ if (!table)
+ return inat_group_common_attribute(grp_attr);
+ }
+ return table[X86_MODRM_REG(modrm)] |
+ inat_group_common_attribute(grp_attr);
+}
+
diff --git a/arch/x86/lib/insn.c b/arch/x86/lib/insn.c
new file mode 100644
index 000000000000..dfd56a30053f
--- /dev/null
+++ b/arch/x86/lib/insn.c
@@ -0,0 +1,464 @@
+/*
+ * x86 instruction analysis
+ *
+ * This 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, 2002, 2004, 2009
+ */
+
+#include <linux/string.h>
+#include <asm/inat.h>
+#include <asm/insn.h>
+
+#define get_next(t, insn) \
+ ({t r; r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; })
+
+#define peek_next(t, insn) \
+ ({t r; r = *(t*)insn->next_byte; r; })
+
+/**
+ * insn_init() - initialize struct insn
+ * @insn: &struct insn to be initialized
+ * @kaddr: address (in kernel memory) of instruction (or copy thereof)
+ * @x86_64: !0 for 64-bit kernel or 64-bit app
+ */
+void insn_init(struct insn *insn, const void *kaddr, int x86_64)
+{
+ memset(insn, 0, sizeof(*insn));
+ insn->kaddr = kaddr;
+ insn->next_byte = kaddr;
+ insn->x86_64 = x86_64 ? 1 : 0;
+ insn->opnd_bytes = 4;
+ if (x86_64)
+ insn->addr_bytes = 8;
+ else
+ insn->addr_bytes = 4;
+}
+
+/**
+ * insn_get_prefixes - scan x86 instruction prefix bytes
+ * @insn: &struct insn containing instruction
+ *
+ * Populates the @insn->prefixes bitmap, and updates @insn->next_byte
+ * to point to the (first) opcode. No effect if @insn->prefixes.got
+ * is already set.
+ */
+void insn_get_prefixes(struct insn *insn)
+{
+ struct insn_field *prefixes = &insn->prefixes;
+ insn_attr_t attr;
+ insn_byte_t b, lb;
+ int i, nb;
+
+ if (prefixes->got)
+ return;
+
+ nb = 0;
+ lb = 0;
+ b = peek_next(insn_byte_t, insn);
+ attr = inat_get_opcode_attribute(b);
+ while (inat_is_prefix(attr)) {
+ /* Skip if same prefix */
+ for (i = 0; i < nb; i++)
+ if (prefixes->bytes[i] == b)
+ goto found;
+ if (nb == 4)
+ /* Invalid instruction */
+ break;
+ prefixes->bytes[nb++] = b;
+ if (inat_is_address_size_prefix(attr)) {
+ /* address size switches 2/4 or 4/8 */
+ if (insn->x86_64)
+ insn->addr_bytes ^= 12;
+ else
+ insn->addr_bytes ^= 6;
+ } else if (inat_is_operand_size_prefix(attr)) {
+ /* oprand size switches 2/4 */
+ insn->opnd_bytes ^= 6;
+ }
+found:
+ prefixes->nbytes++;
+ insn->next_byte++;
+ lb = b;
+ b = peek_next(insn_byte_t, insn);
+ attr = inat_get_opcode_attribute(b);
+ }
+ /* Set the last prefix */
+ if (lb && lb != insn->prefixes.bytes[3]) {
+ if (unlikely(insn->prefixes.bytes[3])) {
+ /* Swap the last prefix */
+ b = insn->prefixes.bytes[3];
+ for (i = 0; i < nb; i++)
+ if (prefixes->bytes[i] == lb)
+ prefixes->bytes[i] = b;
+ }
+ insn->prefixes.bytes[3] = lb;
+ }
+
+ if (insn->x86_64) {
+ b = peek_next(insn_byte_t, insn);
+ attr = inat_get_opcode_attribute(b);
+ if (inat_is_rex_prefix(attr)) {
+ insn->rex_prefix.value = b;
+ insn->rex_prefix.nbytes = 1;
+ insn->next_byte++;
+ if (X86_REX_W(b))
+ /* REX.W overrides opnd_size */
+ insn->opnd_bytes = 8;
+ }
+ }
+ insn->rex_prefix.got = 1;
+ prefixes->got = 1;
+ return;
+}
+
+/**
+ * insn_get_opcode - collect opcode(s)
+ * @insn: &struct insn containing instruction
+ *
+ * Populates @insn->opcode, updates @insn->next_byte to point past the
+ * opcode byte(s), and set @insn->attr (except for groups).
+ * If necessary, first collects any preceding (prefix) bytes.
+ * Sets @insn->opcode.value = opcode1. No effect if @insn->opcode.got
+ * is already 1.
+ */
+void insn_get_opcode(struct insn *insn)
+{
+ struct insn_field *opcode = &insn->opcode;
+ insn_byte_t op, pfx;
+ if (opcode->got)
+ return;
+ if (!insn->prefixes.got)
+ insn_get_prefixes(insn);
+
+ /* Get first opcode */
+ op = get_next(insn_byte_t, insn);
+ opcode->bytes[0] = op;
+ opcode->nbytes = 1;
+ insn->attr = inat_get_opcode_attribute(op);
+ while (inat_is_escape(insn->attr)) {
+ /* Get escaped opcode */
+ op = get_next(insn_byte_t, insn);
+ opcode->bytes[opcode->nbytes++] = op;
+ pfx = insn_last_prefix(insn);
+ insn->attr = inat_get_escape_attribute(op, pfx, insn->attr);
+ }
+ opcode->got = 1;
+}
+
+/**
+ * insn_get_modrm - collect ModRM byte, if any
+ * @insn: &struct insn containing instruction
+ *
+ * Populates @insn->modrm and updates @insn->next_byte to point past the
+ * ModRM byte, if any. If necessary, first collects the preceding bytes
+ * (prefixes and opcode(s)). No effect if @insn->modrm.got is already 1.
+ */
+void insn_get_modrm(struct insn *insn)
+{
+ struct insn_field *modrm = &insn->modrm;
+ insn_byte_t pfx, mod;
+ if (modrm->got)
+ return;
+ if (!insn->opcode.got)
+ insn_get_opcode(insn);
+
+ if (inat_has_modrm(insn->attr)) {
+ mod = get_next(insn_byte_t, insn);
+ modrm->value = mod;
+ modrm->nbytes = 1;
+ if (inat_is_group(insn->attr)) {
+ pfx = insn_last_prefix(insn);
+ insn->attr = inat_get_group_attribute(mod, pfx,
+ insn->attr);
+ }
+ }
+
+ if (insn->x86_64 && inat_is_force64(insn->attr))
+ insn->opnd_bytes = 8;
+ modrm->got = 1;
+}
+
+
+/**
+ * insn_rip_relative() - Does instruction use RIP-relative addressing mode?
+ * @insn: &struct insn containing instruction
+ *
+ * If necessary, first collects the instruction up to and including the
+ * ModRM byte. No effect if @insn->x86_64 is 0.
+ */
+int insn_rip_relative(struct insn *insn)
+{
+ struct insn_field *modrm = &insn->modrm;
+
+ if (!insn->x86_64)
+ return 0;
+ if (!modrm->got)
+ insn_get_modrm(insn);
+ /*
+ * For rip-relative instructions, the mod field (top 2 bits)
+ * is zero and the r/m field (bottom 3 bits) is 0x5.
+ */
+ return (modrm->nbytes && (modrm->value & 0xc7) == 0x5);
+}
+
+/**
+ * insn_get_sib() - Get the SIB byte of instruction
+ * @insn: &struct insn containing instruction
+ *
+ * If necessary, first collects the instruction up to and including the
+ * ModRM byte.
+ */
+void insn_get_sib(struct insn *insn)
+{
+ insn_byte_t modrm;
+
+ if (insn->sib.got)
+ return;
+ if (!insn->modrm.got)
+ insn_get_modrm(insn);
+ if (insn->modrm.nbytes) {
+ modrm = (insn_byte_t)insn->modrm.value;
+ if (insn->addr_bytes != 2 &&
+ X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) {
+ insn->sib.value = get_next(insn_byte_t, insn);
+ insn->sib.nbytes = 1;
+ }
+ }
+ insn->sib.got = 1;
+}
+
+
+/**
+ * insn_get_displacement() - Get the displacement of instruction
+ * @insn: &struct insn containing instruction
+ *
+ * If necessary, first collects the instruction up to and including the
+ * SIB byte.
+ * Displacement value is sign-expanded.
+ */
+void insn_get_displacement(struct insn *insn)
+{
+ insn_byte_t mod, rm, base;
+
+ if (insn->displacement.got)
+ return;
+ if (!insn->sib.got)
+ insn_get_sib(insn);
+ if (insn->modrm.nbytes) {
+ /*
+ * Interpreting the modrm byte:
+ * mod = 00 - no displacement fields (exceptions below)
+ * mod = 01 - 1-byte displacement field
+ * mod = 10 - displacement field is 4 bytes, or 2 bytes if
+ * address size = 2 (0x67 prefix in 32-bit mode)
+ * mod = 11 - no memory operand
+ *
+ * If address size = 2...
+ * mod = 00, r/m = 110 - displacement field is 2 bytes
+ *
+ * If address size != 2...
+ * mod != 11, r/m = 100 - SIB byte exists
+ * mod = 00, SIB base = 101 - displacement field is 4 bytes
+ * mod = 00, r/m = 101 - rip-relative addressing, displacement
+ * field is 4 bytes
+ */
+ mod = X86_MODRM_MOD(insn->modrm.value);
+ rm = X86_MODRM_RM(insn->modrm.value);
+ base = X86_SIB_BASE(insn->sib.value);
+ if (mod == 3)
+ goto out;
+ if (mod == 1) {
+ insn->displacement.value = get_next(char, insn);
+ insn->displacement.nbytes = 1;
+ } else if (insn->addr_bytes == 2) {
+ if ((mod == 0 && rm == 6) || mod == 2) {
+ insn->displacement.value =
+ get_next(short, insn);
+ insn->displacement.nbytes = 2;
+ }
+ } else {
+ if ((mod == 0 && rm == 5) || mod == 2 ||
+ (mod == 0 && base == 5)) {
+ insn->displacement.value = get_next(int, insn);
+ insn->displacement.nbytes = 4;
+ }
+ }
+ }
+out:
+ insn->displacement.got = 1;
+}
+
+/* Decode moffset16/32/64 */
+static void __get_moffset(struct insn *insn)
+{
+ switch (insn->addr_bytes) {
+ case 2:
+ insn->moffset1.value = get_next(short, insn);
+ insn->moffset1.nbytes = 2;
+ break;
+ case 4:
+ insn->moffset1.value = get_next(int, insn);
+ insn->moffset1.nbytes = 4;
+ break;
+ case 8:
+ insn->moffset1.value = get_next(int, insn);
+ insn->moffset1.nbytes = 4;
+ insn->moffset2.value = get_next(int, insn);
+ insn->moffset2.nbytes = 4;
+ break;
+ }
+ insn->moffset1.got = insn->moffset2.got = 1;
+}
+
+/* Decode imm v32(Iz) */
+static void __get_immv32(struct insn *insn)
+{
+ switch (insn->opnd_bytes) {
+ case 2:
+ insn->immediate.value = get_next(short, insn);
+ insn->immediate.nbytes = 2;
+ break;
+ case 4:
+ case 8:
+ insn->immediate.value = get_next(int, insn);
+ insn->immediate.nbytes = 4;
+ break;
+ }
+}
+
+/* Decode imm v64(Iv/Ov) */
+static void __get_immv(struct insn *insn)
+{
+ switch (insn->opnd_bytes) {
+ case 2:
+ insn->immediate1.value = get_next(short, insn);
+ insn->immediate1.nbytes = 2;
+ break;
+ case 4:
+ insn->immediate1.value = get_next(int, insn);
+ insn->immediate1.nbytes = 4;
+ break;
+ case 8:
+ insn->immediate1.value = get_next(int, insn);
+ insn->immediate1.nbytes = 4;
+ insn->immediate2.value = get_next(int, insn);
+ insn->immediate2.nbytes = 4;
+ break;
+ }
+ insn->immediate1.got = insn->immediate2.got = 1;
+}
+
+/* Decode ptr16:16/32(Ap) */
+static void __get_immptr(struct insn *insn)
+{
+ switch (insn->opnd_bytes) {
+ case 2:
+ insn->immediate1.value = get_next(short, insn);
+ insn->immediate1.nbytes = 2;
+ break;
+ case 4:
+ insn->immediate1.value = get_next(int, insn);
+ insn->immediate1.nbytes = 4;
+ break;
+ case 8:
+ /* ptr16:64 is not exist (no segment) */
+ return;
+ }
+ insn->immediate2.value = get_next(unsigned short, insn);
+ insn->immediate2.nbytes = 2;
+ insn->immediate1.got = insn->immediate2.got = 1;
+}
+
+/**
+ * insn_get_immediate() - Get the immediates of instruction
+ * @insn: &struct insn containing instruction
+ *
+ * If necessary, first collects the instruction up to and including the
+ * displacement bytes.
+ * Basically, most of immediates are sign-expanded. Unsigned-value can be
+ * get by bit masking with ((1 << (nbytes * 8)) - 1)
+ */
+void insn_get_immediate(struct insn *insn)
+{
+ if (insn->immediate.got)
+ return;
+ if (!insn->displacement.got)
+ insn_get_displacement(insn);
+
+ if (inat_has_moffset(insn->attr)) {
+ __get_moffset(insn);
+ goto done;
+ }
+
+ if (!inat_has_immediate(insn->attr))
+ /* no immediates */
+ goto done;
+
+ switch (inat_immediate_size(insn->attr)) {
+ case INAT_IMM_BYTE:
+ insn->immediate.value = get_next(char, insn);
+ insn->immediate.nbytes = 1;
+ break;
+ case INAT_IMM_WORD:
+ insn->immediate.value = get_next(short, insn);
+ insn->immediate.nbytes = 2;
+ break;
+ case INAT_IMM_DWORD:
+ insn->immediate.value = get_next(int, insn);
+ insn->immediate.nbytes = 4;
+ break;
+ case INAT_IMM_QWORD:
+ insn->immediate1.value = get_next(int, insn);
+ insn->immediate1.nbytes = 4;
+ insn->immediate2.value = get_next(int, insn);
+ insn->immediate2.nbytes = 4;
+ break;
+ case INAT_IMM_PTR:
+ __get_immptr(insn);
+ break;
+ case INAT_IMM_VWORD32:
+ __get_immv32(insn);
+ break;
+ case INAT_IMM_VWORD:
+ __get_immv(insn);
+ break;
+ default:
+ break;
+ }
+ if (inat_has_second_immediate(insn->attr)) {
+ insn->immediate2.value = get_next(char, insn);
+ insn->immediate2.nbytes = 1;
+ }
+done:
+ insn->immediate.got = 1;
+}
+
+/**
+ * insn_get_length() - Get the length of instruction
+ * @insn: &struct insn containing instruction
+ *
+ * If necessary, first collects the instruction up to and including the
+ * immediates bytes.
+ */
+void insn_get_length(struct insn *insn)
+{
+ if (insn->length)
+ return;
+ if (!insn->immediate.got)
+ insn_get_immediate(insn);
+ insn->length = (unsigned char)((unsigned long)insn->next_byte
+ - (unsigned long)insn->kaddr);
+}
diff --git a/arch/x86/lib/msr.c b/arch/x86/lib/msr.c
index 33a1e3ca22d8..41628b104b9e 100644
--- a/arch/x86/lib/msr.c
+++ b/arch/x86/lib/msr.c
@@ -71,14 +71,9 @@ int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
}
EXPORT_SYMBOL(wrmsr_on_cpu);
-/* rdmsr on a bunch of CPUs
- *
- * @mask: which CPUs
- * @msr_no: which MSR
- * @msrs: array of MSR values
- *
- */
-void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs)
+static void __rwmsr_on_cpus(const struct cpumask *mask, u32 msr_no,
+ struct msr *msrs,
+ void (*msr_func) (void *info))
{
struct msr_info rv;
int this_cpu;
@@ -92,11 +87,23 @@ void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs)
this_cpu = get_cpu();
if (cpumask_test_cpu(this_cpu, mask))
- __rdmsr_on_cpu(&rv);
+ msr_func(&rv);
- smp_call_function_many(mask, __rdmsr_on_cpu, &rv, 1);
+ smp_call_function_many(mask, msr_func, &rv, 1);
put_cpu();
}
+
+/* rdmsr on a bunch of CPUs
+ *
+ * @mask: which CPUs
+ * @msr_no: which MSR
+ * @msrs: array of MSR values
+ *
+ */
+void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
+{
+ __rwmsr_on_cpus(mask, msr_no, msrs, __rdmsr_on_cpu);
+}
EXPORT_SYMBOL(rdmsr_on_cpus);
/*
@@ -107,24 +114,9 @@ EXPORT_SYMBOL(rdmsr_on_cpus);
* @msrs: array of MSR values
*
*/
-void wrmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs)
+void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs)
{
- struct msr_info rv;
- int this_cpu;
-
- memset(&rv, 0, sizeof(rv));
-
- rv.off = cpumask_first(mask);
- rv.msrs = msrs;
- rv.msr_no = msr_no;
-
- this_cpu = get_cpu();
-
- if (cpumask_test_cpu(this_cpu, mask))
- __wrmsr_on_cpu(&rv);
-
- smp_call_function_many(mask, __wrmsr_on_cpu, &rv, 1);
- put_cpu();
+ __rwmsr_on_cpus(mask, msr_no, msrs, __wrmsr_on_cpu);
}
EXPORT_SYMBOL(wrmsr_on_cpus);
diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c
index 1f118d462acc..e218d5df85ff 100644
--- a/arch/x86/lib/usercopy_32.c
+++ b/arch/x86/lib/usercopy_32.c
@@ -874,7 +874,7 @@ EXPORT_SYMBOL(copy_to_user);
* data to the requested size using zero bytes.
*/
unsigned long
-copy_from_user(void *to, const void __user *from, unsigned long n)
+_copy_from_user(void *to, const void __user *from, unsigned long n)
{
if (access_ok(VERIFY_READ, from, n))
n = __copy_from_user(to, from, n);
@@ -882,4 +882,10 @@ copy_from_user(void *to, const void __user *from, unsigned long n)
memset(to, 0, n);
return n;
}
-EXPORT_SYMBOL(copy_from_user);
+EXPORT_SYMBOL(_copy_from_user);
+
+void copy_from_user_overflow(void)
+{
+ WARN(1, "Buffer overflow detected!\n");
+}
+EXPORT_SYMBOL(copy_from_user_overflow);
diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt
new file mode 100644
index 000000000000..701c4678687b
--- /dev/null
+++ b/arch/x86/lib/x86-opcode-map.txt
@@ -0,0 +1,841 @@
+# x86 Opcode Maps
+#
+#<Opcode maps>
+# Table: table-name
+# Referrer: escaped-name
+# opcode: mnemonic|GrpXXX [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...]
+# (or)
+# opcode: escape # escaped-name
+# EndTable
+#
+#<group maps>
+# GrpTable: GrpXXX
+# reg: mnemonic [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...]
+# EndTable
+#
+
+Table: one byte opcode
+Referrer:
+# 0x00 - 0x0f
+00: ADD Eb,Gb
+01: ADD Ev,Gv
+02: ADD Gb,Eb
+03: ADD Gv,Ev
+04: ADD AL,Ib
+05: ADD rAX,Iz
+06: PUSH ES (i64)
+07: POP ES (i64)
+08: OR Eb,Gb
+09: OR Ev,Gv
+0a: OR Gb,Eb
+0b: OR Gv,Ev
+0c: OR AL,Ib
+0d: OR rAX,Iz
+0e: PUSH CS (i64)
+0f: escape # 2-byte escape
+# 0x10 - 0x1f
+10: ADC Eb,Gb
+11: ADC Ev,Gv
+12: ADC Gb,Eb
+13: ADC Gv,Ev
+14: ADC AL,Ib
+15: ADC rAX,Iz
+16: PUSH SS (i64)
+17: POP SS (i64)
+18: SBB Eb,Gb
+19: SBB Ev,Gv
+1a: SBB Gb,Eb
+1b: SBB Gv,Ev
+1c: SBB AL,Ib
+1d: SBB rAX,Iz
+1e: PUSH DS (i64)
+1f: POP DS (i64)
+# 0x20 - 0x2f
+20: AND Eb,Gb
+21: AND Ev,Gv
+22: AND Gb,Eb
+23: AND Gv,Ev
+24: AND AL,Ib
+25: AND rAx,Iz
+26: SEG=ES (Prefix)
+27: DAA (i64)
+28: SUB Eb,Gb
+29: SUB Ev,Gv
+2a: SUB Gb,Eb
+2b: SUB Gv,Ev
+2c: SUB AL,Ib
+2d: SUB rAX,Iz
+2e: SEG=CS (Prefix)
+2f: DAS (i64)
+# 0x30 - 0x3f
+30: XOR Eb,Gb
+31: XOR Ev,Gv
+32: XOR Gb,Eb
+33: XOR Gv,Ev
+34: XOR AL,Ib
+35: XOR rAX,Iz
+36: SEG=SS (Prefix)
+37: AAA (i64)
+38: CMP Eb,Gb
+39: CMP Ev,Gv
+3a: CMP Gb,Eb
+3b: CMP Gv,Ev
+3c: CMP AL,Ib
+3d: CMP rAX,Iz
+3e: SEG=DS (Prefix)
+3f: AAS (i64)
+# 0x40 - 0x4f
+40: INC eAX (i64) | REX (o64)
+41: INC eCX (i64) | REX.B (o64)
+42: INC eDX (i64) | REX.X (o64)
+43: INC eBX (i64) | REX.XB (o64)
+44: INC eSP (i64) | REX.R (o64)
+45: INC eBP (i64) | REX.RB (o64)
+46: INC eSI (i64) | REX.RX (o64)
+47: INC eDI (i64) | REX.RXB (o64)
+48: DEC eAX (i64) | REX.W (o64)
+49: DEC eCX (i64) | REX.WB (o64)
+4a: DEC eDX (i64) | REX.WX (o64)
+4b: DEC eBX (i64) | REX.WXB (o64)
+4c: DEC eSP (i64) | REX.WR (o64)
+4d: DEC eBP (i64) | REX.WRB (o64)
+4e: DEC eSI (i64) | REX.WRX (o64)
+4f: DEC eDI (i64) | REX.WRXB (o64)
+# 0x50 - 0x5f
+50: PUSH rAX/r8 (d64)
+51: PUSH rCX/r9 (d64)
+52: PUSH rDX/r10 (d64)
+53: PUSH rBX/r11 (d64)
+54: PUSH rSP/r12 (d64)
+55: PUSH rBP/r13 (d64)
+56: PUSH rSI/r14 (d64)
+57: PUSH rDI/r15 (d64)
+58: POP rAX/r8 (d64)
+59: POP rCX/r9 (d64)
+5a: POP rDX/r10 (d64)
+5b: POP rBX/r11 (d64)
+5c: POP rSP/r12 (d64)
+5d: POP rBP/r13 (d64)
+5e: POP rSI/r14 (d64)
+5f: POP rDI/r15 (d64)
+# 0x60 - 0x6f
+60: PUSHA/PUSHAD (i64)
+61: POPA/POPAD (i64)
+62: BOUND Gv,Ma (i64)
+63: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64)
+64: SEG=FS (Prefix)
+65: SEG=GS (Prefix)
+66: Operand-Size (Prefix)
+67: Address-Size (Prefix)
+68: PUSH Iz (d64)
+69: IMUL Gv,Ev,Iz
+6a: PUSH Ib (d64)
+6b: IMUL Gv,Ev,Ib
+6c: INS/INSB Yb,DX
+6d: INS/INSW/INSD Yz,DX
+6e: OUTS/OUTSB DX,Xb
+6f: OUTS/OUTSW/OUTSD DX,Xz
+# 0x70 - 0x7f
+70: JO Jb
+71: JNO Jb
+72: JB/JNAE/JC Jb
+73: JNB/JAE/JNC Jb
+74: JZ/JE Jb
+75: JNZ/JNE Jb
+76: JBE/JNA Jb
+77: JNBE/JA Jb
+78: JS Jb
+79: JNS Jb
+7a: JP/JPE Jb
+7b: JNP/JPO Jb
+7c: JL/JNGE Jb
+7d: JNL/JGE Jb
+7e: JLE/JNG Jb
+7f: JNLE/JG Jb
+# 0x80 - 0x8f
+80: Grp1 Eb,Ib (1A)
+81: Grp1 Ev,Iz (1A)
+82: Grp1 Eb,Ib (1A),(i64)
+83: Grp1 Ev,Ib (1A)
+84: TEST Eb,Gb
+85: TEST Ev,Gv
+86: XCHG Eb,Gb
+87: XCHG Ev,Gv
+88: MOV Eb,Gb
+89: MOV Ev,Gv
+8a: MOV Gb,Eb
+8b: MOV Gv,Ev
+8c: MOV Ev,Sw
+8d: LEA Gv,M
+8e: MOV Sw,Ew
+8f: Grp1A (1A) | POP Ev (d64)
+# 0x90 - 0x9f
+90: NOP | PAUSE (F3) | XCHG r8,rAX
+91: XCHG rCX/r9,rAX
+92: XCHG rDX/r10,rAX
+93: XCHG rBX/r11,rAX
+94: XCHG rSP/r12,rAX
+95: XCHG rBP/r13,rAX
+96: XCHG rSI/r14,rAX
+97: XCHG rDI/r15,rAX
+98: CBW/CWDE/CDQE
+99: CWD/CDQ/CQO
+9a: CALLF Ap (i64)
+9b: FWAIT/WAIT
+9c: PUSHF/D/Q Fv (d64)
+9d: POPF/D/Q Fv (d64)
+9e: SAHF
+9f: LAHF
+# 0xa0 - 0xaf
+a0: MOV AL,Ob
+a1: MOV rAX,Ov
+a2: MOV Ob,AL
+a3: MOV Ov,rAX
+a4: MOVS/B Xb,Yb
+a5: MOVS/W/D/Q Xv,Yv
+a6: CMPS/B Xb,Yb
+a7: CMPS/W/D Xv,Yv
+a8: TEST AL,Ib
+a9: TEST rAX,Iz
+aa: STOS/B Yb,AL
+ab: STOS/W/D/Q Yv,rAX
+ac: LODS/B AL,Xb
+ad: LODS/W/D/Q rAX,Xv
+ae: SCAS/B AL,Yb
+af: SCAS/W/D/Q rAX,Xv
+# 0xb0 - 0xbf
+b0: MOV AL/R8L,Ib
+b1: MOV CL/R9L,Ib
+b2: MOV DL/R10L,Ib
+b3: MOV BL/R11L,Ib
+b4: MOV AH/R12L,Ib
+b5: MOV CH/R13L,Ib
+b6: MOV DH/R14L,Ib
+b7: MOV BH/R15L,Ib
+b8: MOV rAX/r8,Iv
+b9: MOV rCX/r9,Iv
+ba: MOV rDX/r10,Iv
+bb: MOV rBX/r11,Iv
+bc: MOV rSP/r12,Iv
+bd: MOV rBP/r13,Iv
+be: MOV rSI/r14,Iv
+bf: MOV rDI/r15,Iv
+# 0xc0 - 0xcf
+c0: Grp2 Eb,Ib (1A)
+c1: Grp2 Ev,Ib (1A)
+c2: RETN Iw (f64)
+c3: RETN
+c4: LES Gz,Mp (i64)
+c5: LDS Gz,Mp (i64)
+c6: Grp11 Eb,Ib (1A)
+c7: Grp11 Ev,Iz (1A)
+c8: ENTER Iw,Ib
+c9: LEAVE (d64)
+ca: RETF Iw
+cb: RETF
+cc: INT3
+cd: INT Ib
+ce: INTO (i64)
+cf: IRET/D/Q
+# 0xd0 - 0xdf
+d0: Grp2 Eb,1 (1A)
+d1: Grp2 Ev,1 (1A)
+d2: Grp2 Eb,CL (1A)
+d3: Grp2 Ev,CL (1A)
+d4: AAM Ib (i64)
+d5: AAD Ib (i64)
+d6:
+d7: XLAT/XLATB
+d8: ESC
+d9: ESC
+da: ESC
+db: ESC
+dc: ESC
+dd: ESC
+de: ESC
+df: ESC
+# 0xe0 - 0xef
+e0: LOOPNE/LOOPNZ Jb (f64)
+e1: LOOPE/LOOPZ Jb (f64)
+e2: LOOP Jb (f64)
+e3: JrCXZ Jb (f64)
+e4: IN AL,Ib
+e5: IN eAX,Ib
+e6: OUT Ib,AL
+e7: OUT Ib,eAX
+e8: CALL Jz (f64)
+e9: JMP-near Jz (f64)
+ea: JMP-far Ap (i64)
+eb: JMP-short Jb (f64)
+ec: IN AL,DX
+ed: IN eAX,DX
+ee: OUT DX,AL
+ef: OUT DX,eAX
+# 0xf0 - 0xff
+f0: LOCK (Prefix)
+f1:
+f2: REPNE (Prefix)
+f3: REP/REPE (Prefix)
+f4: HLT
+f5: CMC
+f6: Grp3_1 Eb (1A)
+f7: Grp3_2 Ev (1A)
+f8: CLC
+f9: STC
+fa: CLI
+fb: STI
+fc: CLD
+fd: STD
+fe: Grp4 (1A)
+ff: Grp5 (1A)
+EndTable
+
+Table: 2-byte opcode # First Byte is 0x0f
+Referrer: 2-byte escape
+# 0x0f 0x00-0x0f
+00: Grp6 (1A)
+01: Grp7 (1A)
+02: LAR Gv,Ew
+03: LSL Gv,Ew
+04:
+05: SYSCALL (o64)
+06: CLTS
+07: SYSRET (o64)
+08: INVD
+09: WBINVD
+0a:
+0b: UD2 (1B)
+0c:
+0d: NOP Ev | GrpP
+0e: FEMMS
+# 3DNow! uses the last imm byte as opcode extension.
+0f: 3DNow! Pq,Qq,Ib
+# 0x0f 0x10-0x1f
+10: movups Vps,Wps | movss Vss,Wss (F3) | movupd Vpd,Wpd (66) | movsd Vsd,Wsd (F2)
+11: movups Wps,Vps | movss Wss,Vss (F3) | movupd Wpd,Vpd (66) | movsd Wsd,Vsd (F2)
+12: movlps Vq,Mq | movlpd Vq,Mq (66) | movhlps Vq,Uq | movddup Vq,Wq (F2) | movsldup Vq,Wq (F3)
+13: mpvlps Mq,Vq | movlpd Mq,Vq (66)
+14: unpcklps Vps,Wq | unpcklpd Vpd,Wq (66)
+15: unpckhps Vps,Wq | unpckhpd Vpd,Wq (66)
+16: movhps Vq,Mq | movhpd Vq,Mq (66) | movlsps Vq,Uq | movshdup Vq,Wq (F3)
+17: movhps Mq,Vq | movhpd Mq,Vq (66)
+18: Grp16 (1A)
+19:
+1a:
+1b:
+1c:
+1d:
+1e:
+1f: NOP Ev
+# 0x0f 0x20-0x2f
+20: MOV Rd,Cd
+21: MOV Rd,Dd
+22: MOV Cd,Rd
+23: MOV Dd,Rd
+24:
+25:
+26:
+27:
+28: movaps Vps,Wps | movapd Vpd,Wpd (66)
+29: movaps Wps,Vps | movapd Wpd,Vpd (66)
+2a: cvtpi2ps Vps,Qpi | cvtsi2ss Vss,Ed/q (F3) | cvtpi2pd Vpd,Qpi (66) | cvtsi2sd Vsd,Ed/q (F2)
+2b: movntps Mps,Vps | movntpd Mpd,Vpd (66)
+2c: cvttps2pi Ppi,Wps | cvttss2si Gd/q,Wss (F3) | cvttpd2pi Ppi,Wpd (66) | cvttsd2si Gd/q,Wsd (F2)
+2d: cvtps2pi Ppi,Wps | cvtss2si Gd/q,Wss (F3) | cvtpd2pi Qpi,Wpd (66) | cvtsd2si Gd/q,Wsd (F2)
+2e: ucomiss Vss,Wss | ucomisd Vsd,Wsd (66)
+2f: comiss Vss,Wss | comisd Vsd,Wsd (66)
+# 0x0f 0x30-0x3f
+30: WRMSR
+31: RDTSC
+32: RDMSR
+33: RDPMC
+34: SYSENTER
+35: SYSEXIT
+36:
+37: GETSEC
+38: escape # 3-byte escape 1
+39:
+3a: escape # 3-byte escape 2
+3b:
+3c:
+3d:
+3e:
+3f:
+# 0x0f 0x40-0x4f
+40: CMOVO Gv,Ev
+41: CMOVNO Gv,Ev
+42: CMOVB/C/NAE Gv,Ev
+43: CMOVAE/NB/NC Gv,Ev
+44: CMOVE/Z Gv,Ev
+45: CMOVNE/NZ Gv,Ev
+46: CMOVBE/NA Gv,Ev
+47: CMOVA/NBE Gv,Ev
+48: CMOVS Gv,Ev
+49: CMOVNS Gv,Ev
+4a: CMOVP/PE Gv,Ev
+4b: CMOVNP/PO Gv,Ev
+4c: CMOVL/NGE Gv,Ev
+4d: CMOVNL/GE Gv,Ev
+4e: CMOVLE/NG Gv,Ev
+4f: CMOVNLE/G Gv,Ev
+# 0x0f 0x50-0x5f
+50: movmskps Gd/q,Ups | movmskpd Gd/q,Upd (66)
+51: sqrtps Vps,Wps | sqrtss Vss,Wss (F3) | sqrtpd Vpd,Wpd (66) | sqrtsd Vsd,Wsd (F2)
+52: rsqrtps Vps,Wps | rsqrtss Vss,Wss (F3)
+53: rcpps Vps,Wps | rcpss Vss,Wss (F3)
+54: andps Vps,Wps | andpd Vpd,Wpd (66)
+55: andnps Vps,Wps | andnpd Vpd,Wpd (66)
+56: orps Vps,Wps | orpd Vpd,Wpd (66)
+57: xorps Vps,Wps | xorpd Vpd,Wpd (66)
+58: addps Vps,Wps | addss Vss,Wss (F3) | addpd Vpd,Wpd (66) | addsd Vsd,Wsd (F2)
+59: mulps Vps,Wps | mulss Vss,Wss (F3) | mulpd Vpd,Wpd (66) | mulsd Vsd,Wsd (F2)
+5a: cvtps2pd Vpd,Wps | cvtss2sd Vsd,Wss (F3) | cvtpd2ps Vps,Wpd (66) | cvtsd2ss Vsd,Wsd (F2)
+5b: cvtdq2ps Vps,Wdq | cvtps2dq Vdq,Wps (66) | cvttps2dq Vdq,Wps (F3)
+5c: subps Vps,Wps | subss Vss,Wss (F3) | subpd Vpd,Wpd (66) | subsd Vsd,Wsd (F2)
+5d: minps Vps,Wps | minss Vss,Wss (F3) | minpd Vpd,Wpd (66) | minsd Vsd,Wsd (F2)
+5e: divps Vps,Wps | divss Vss,Wss (F3) | divpd Vpd,Wpd (66) | divsd Vsd,Wsd (F2)
+5f: maxps Vps,Wps | maxss Vss,Wss (F3) | maxpd Vpd,Wpd (66) | maxsd Vsd,Wsd (F2)
+# 0x0f 0x60-0x6f
+60: punpcklbw Pq,Qd | punpcklbw Vdq,Wdq (66)
+61: punpcklwd Pq,Qd | punpcklwd Vdq,Wdq (66)
+62: punpckldq Pq,Qd | punpckldq Vdq,Wdq (66)
+63: packsswb Pq,Qq | packsswb Vdq,Wdq (66)
+64: pcmpgtb Pq,Qq | pcmpgtb Vdq,Wdq (66)
+65: pcmpgtw Pq,Qq | pcmpgtw(66) Vdq,Wdq
+66: pcmpgtd Pq,Qq | pcmpgtd Vdq,Wdq (66)
+67: packuswb Pq,Qq | packuswb(66) Vdq,Wdq
+68: punpckhbw Pq,Qd | punpckhbw Vdq,Wdq (66)
+69: punpckhwd Pq,Qd | punpckhwd Vdq,Wdq (66)
+6a: punpckhdq Pq,Qd | punpckhdq Vdq,Wdq (66)
+6b: packssdw Pq,Qd | packssdw Vdq,Wdq (66)
+6c: punpcklqdq Vdq,Wdq (66)
+6d: punpckhqdq Vdq,Wdq (66)
+6e: movd/q/ Pd,Ed/q | movd/q Vdq,Ed/q (66)
+6f: movq Pq,Qq | movdqa Vdq,Wdq (66) | movdqu Vdq,Wdq (F3)
+# 0x0f 0x70-0x7f
+70: pshufw Pq,Qq,Ib | pshufd Vdq,Wdq,Ib (66) | pshufhw Vdq,Wdq,Ib (F3) | pshuflw VdqWdq,Ib (F2)
+71: Grp12 (1A)
+72: Grp13 (1A)
+73: Grp14 (1A)
+74: pcmpeqb Pq,Qq | pcmpeqb Vdq,Wdq (66)
+75: pcmpeqw Pq,Qq | pcmpeqw Vdq,Wdq (66)
+76: pcmpeqd Pq,Qq | pcmpeqd Vdq,Wdq (66)
+77: emms
+78: VMREAD Ed/q,Gd/q
+79: VMWRITE Gd/q,Ed/q
+7a:
+7b:
+7c: haddps(F2) Vps,Wps | haddpd(66) Vpd,Wpd
+7d: hsubps(F2) Vps,Wps | hsubpd(66) Vpd,Wpd
+7e: movd/q Ed/q,Pd | movd/q Ed/q,Vdq (66) | movq Vq,Wq (F3)
+7f: movq Qq,Pq | movdqa Wdq,Vdq (66) | movdqu Wdq,Vdq (F3)
+# 0x0f 0x80-0x8f
+80: JO Jz (f64)
+81: JNO Jz (f64)
+82: JB/JNAE/JC Jz (f64)
+83: JNB/JAE/JNC Jz (f64)
+84: JZ/JE Jz (f64)
+85: JNZ/JNE Jz (f64)
+86: JBE/JNA Jz (f64)
+87: JNBE/JA Jz (f64)
+88: JS Jz (f64)
+89: JNS Jz (f64)
+8a: JP/JPE Jz (f64)
+8b: JNP/JPO Jz (f64)
+8c: JL/JNGE Jz (f64)
+8d: JNL/JGE Jz (f64)
+8e: JLE/JNG Jz (f64)
+8f: JNLE/JG Jz (f64)
+# 0x0f 0x90-0x9f
+90: SETO Eb
+91: SETNO Eb
+92: SETB/C/NAE Eb
+93: SETAE/NB/NC Eb
+94: SETE/Z Eb
+95: SETNE/NZ Eb
+96: SETBE/NA Eb
+97: SETA/NBE Eb
+98: SETS Eb
+99: SETNS Eb
+9a: SETP/PE Eb
+9b: SETNP/PO Eb
+9c: SETL/NGE Eb
+9d: SETNL/GE Eb
+9e: SETLE/NG Eb
+9f: SETNLE/G Eb
+# 0x0f 0xa0-0xaf
+a0: PUSH FS (d64)
+a1: POP FS (d64)
+a2: CPUID
+a3: BT Ev,Gv
+a4: SHLD Ev,Gv,Ib
+a5: SHLD Ev,Gv,CL
+a6: GrpPDLK
+a7: GrpRNG
+a8: PUSH GS (d64)
+a9: POP GS (d64)
+aa: RSM
+ab: BTS Ev,Gv
+ac: SHRD Ev,Gv,Ib
+ad: SHRD Ev,Gv,CL
+ae: Grp15 (1A),(1C)
+af: IMUL Gv,Ev
+# 0x0f 0xb0-0xbf
+b0: CMPXCHG Eb,Gb
+b1: CMPXCHG Ev,Gv
+b2: LSS Gv,Mp
+b3: BTR Ev,Gv
+b4: LFS Gv,Mp
+b5: LGS Gv,Mp
+b6: MOVZX Gv,Eb
+b7: MOVZX Gv,Ew
+b8: JMPE | POPCNT Gv,Ev (F3)
+b9: Grp10 (1A)
+ba: Grp8 Ev,Ib (1A)
+bb: BTC Ev,Gv
+bc: BSF Gv,Ev
+bd: BSR Gv,Ev
+be: MOVSX Gv,Eb
+bf: MOVSX Gv,Ew
+# 0x0f 0xc0-0xcf
+c0: XADD Eb,Gb
+c1: XADD Ev,Gv
+c2: cmpps Vps,Wps,Ib | cmpss Vss,Wss,Ib (F3) | cmppd Vpd,Wpd,Ib (66) | cmpsd Vsd,Wsd,Ib (F2)
+c3: movnti Md/q,Gd/q
+c4: pinsrw Pq,Rd/q/Mw,Ib | pinsrw Vdq,Rd/q/Mw,Ib (66)
+c5: pextrw Gd,Nq,Ib | pextrw Gd,Udq,Ib (66)
+c6: shufps Vps,Wps,Ib | shufpd Vpd,Wpd,Ib (66)
+c7: Grp9 (1A)
+c8: BSWAP RAX/EAX/R8/R8D
+c9: BSWAP RCX/ECX/R9/R9D
+ca: BSWAP RDX/EDX/R10/R10D
+cb: BSWAP RBX/EBX/R11/R11D
+cc: BSWAP RSP/ESP/R12/R12D
+cd: BSWAP RBP/EBP/R13/R13D
+ce: BSWAP RSI/ESI/R14/R14D
+cf: BSWAP RDI/EDI/R15/R15D
+# 0x0f 0xd0-0xdf
+d0: addsubps Vps,Wps (F2) | addsubpd Vpd,Wpd (66)
+d1: psrlw Pq,Qq | psrlw Vdq,Wdq (66)
+d2: psrld Pq,Qq | psrld Vdq,Wdq (66)
+d3: psrlq Pq,Qq | psrlq Vdq,Wdq (66)
+d4: paddq Pq,Qq | paddq Vdq,Wdq (66)
+d5: pmullw Pq,Qq | pmullw Vdq,Wdq (66)
+d6: movq Wq,Vq (66) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2)
+d7: pmovmskb Gd,Nq | pmovmskb Gd,Udq (66)
+d8: psubusb Pq,Qq | psubusb Vdq,Wdq (66)
+d9: psubusw Pq,Qq | psubusw Vdq,Wdq (66)
+da: pminub Pq,Qq | pminub Vdq,Wdq (66)
+db: pand Pq,Qq | pand Vdq,Wdq (66)
+dc: paddusb Pq,Qq | paddusb Vdq,Wdq (66)
+dd: paddusw Pq,Qq | paddusw Vdq,Wdq (66)
+de: pmaxub Pq,Qq | pmaxub Vdq,Wdq (66)
+df: pandn Pq,Qq | pandn Vdq,Wdq (66)
+# 0x0f 0xe0-0xef
+e0: pavgb Pq,Qq | pavgb Vdq,Wdq (66)
+e1: psraw Pq,Qq | psraw Vdq,Wdq (66)
+e2: psrad Pq,Qq | psrad Vdq,Wdq (66)
+e3: pavgw Pq,Qq | pavgw Vdq,Wdq (66)
+e4: pmulhuw Pq,Qq | pmulhuw Vdq,Wdq (66)
+e5: pmulhw Pq,Qq | pmulhw Vdq,Wdq (66)
+e6: cvtpd2dq Vdq,Wpd (F2) | cvttpd2dq Vdq,Wpd (66) | cvtdq2pd Vpd,Wdq (F3)
+e7: movntq Mq,Pq | movntdq Mdq,Vdq (66)
+e8: psubsb Pq,Qq | psubsb Vdq,Wdq (66)
+e9: psubsw Pq,Qq | psubsw Vdq,Wdq (66)
+ea: pminsw Pq,Qq | pminsw Vdq,Wdq (66)
+eb: por Pq,Qq | por Vdq,Wdq (66)
+ec: paddsb Pq,Qq | paddsb Vdq,Wdq (66)
+ed: paddsw Pq,Qq | paddsw Vdq,Wdq (66)
+ee: pmaxsw Pq,Qq | pmaxsw Vdq,Wdq (66)
+ef: pxor Pq,Qq | pxor Vdq,Wdq (66)
+# 0x0f 0xf0-0xff
+f0: lddqu Vdq,Mdq (F2)
+f1: psllw Pq,Qq | psllw Vdq,Wdq (66)
+f2: pslld Pq,Qq | pslld Vdq,Wdq (66)
+f3: psllq Pq,Qq | psllq Vdq,Wdq (66)
+f4: pmuludq Pq,Qq | pmuludq Vdq,Wdq (66)
+f5: pmaddwd Pq,Qq | pmaddwd Vdq,Wdq (66)
+f6: psadbw Pq,Qq | psadbw Vdq,Wdq (66)
+f7: maskmovq Pq,Nq | maskmovdqu Vdq,Udq (66)
+f8: psubb Pq,Qq | psubb Vdq,Wdq (66)
+f9: psubw Pq,Qq | psubw Vdq,Wdq (66)
+fa: psubd Pq,Qq | psubd Vdq,Wdq (66)
+fb: psubq Pq,Qq | psubq Vdq,Wdq (66)
+fc: paddb Pq,Qq | paddb Vdq,Wdq (66)
+fd: paddw Pq,Qq | paddw Vdq,Wdq (66)
+fe: paddd Pq,Qq | paddd Vdq,Wdq (66)
+ff:
+EndTable
+
+Table: 3-byte opcode 1 (0x0f 0x38)
+Referrer: 3-byte escape 1
+# 0x0f 0x38 0x00-0x0f
+00: pshufb Pq,Qq | pshufb Vdq,Wdq (66)
+01: phaddw Pq,Qq | phaddw Vdq,Wdq (66)
+02: phaddd Pq,Qq | phaddd Vdq,Wdq (66)
+03: phaddsw Pq,Qq | phaddsw Vdq,Wdq (66)
+04: pmaddubsw Pq,Qq | pmaddubsw (66)Vdq,Wdq
+05: phsubw Pq,Qq | phsubw Vdq,Wdq (66)
+06: phsubd Pq,Qq | phsubd Vdq,Wdq (66)
+07: phsubsw Pq,Qq | phsubsw Vdq,Wdq (66)
+08: psignb Pq,Qq | psignb Vdq,Wdq (66)
+09: psignw Pq,Qq | psignw Vdq,Wdq (66)
+0a: psignd Pq,Qq | psignd Vdq,Wdq (66)
+0b: pmulhrsw Pq,Qq | pmulhrsw Vdq,Wdq (66)
+0c:
+0d:
+0e:
+0f:
+# 0x0f 0x38 0x10-0x1f
+10: pblendvb Vdq,Wdq (66)
+11:
+12:
+13:
+14: blendvps Vdq,Wdq (66)
+15: blendvpd Vdq,Wdq (66)
+16:
+17: ptest Vdq,Wdq (66)
+18:
+19:
+1a:
+1b:
+1c: pabsb Pq,Qq | pabsb Vdq,Wdq (66)
+1d: pabsw Pq,Qq | pabsw Vdq,Wdq (66)
+1e: pabsd Pq,Qq | pabsd Vdq,Wdq (66)
+1f:
+# 0x0f 0x38 0x20-0x2f
+20: pmovsxbw Vdq,Udq/Mq (66)
+21: pmovsxbd Vdq,Udq/Md (66)
+22: pmovsxbq Vdq,Udq/Mw (66)
+23: pmovsxwd Vdq,Udq/Mq (66)
+24: pmovsxwq Vdq,Udq/Md (66)
+25: pmovsxdq Vdq,Udq/Mq (66)
+26:
+27:
+28: pmuldq Vdq,Wdq (66)
+29: pcmpeqq Vdq,Wdq (66)
+2a: movntdqa Vdq,Mdq (66)
+2b: packusdw Vdq,Wdq (66)
+2c:
+2d:
+2e:
+2f:
+# 0x0f 0x38 0x30-0x3f
+30: pmovzxbw Vdq,Udq/Mq (66)
+31: pmovzxbd Vdq,Udq/Md (66)
+32: pmovzxbq Vdq,Udq/Mw (66)
+33: pmovzxwd Vdq,Udq/Mq (66)
+34: pmovzxwq Vdq,Udq/Md (66)
+35: pmovzxdq Vdq,Udq/Mq (66)
+36:
+37: pcmpgtq Vdq,Wdq (66)
+38: pminsb Vdq,Wdq (66)
+39: pminsd Vdq,Wdq (66)
+3a: pminuw Vdq,Wdq (66)
+3b: pminud Vdq,Wdq (66)
+3c: pmaxsb Vdq,Wdq (66)
+3d: pmaxsd Vdq,Wdq (66)
+3e: pmaxuw Vdq,Wdq (66)
+3f: pmaxud Vdq,Wdq (66)
+# 0x0f 0x38 0x4f-0xff
+40: pmulld Vdq,Wdq (66)
+41: phminposuw Vdq,Wdq (66)
+80: INVEPT Gd/q,Mdq (66)
+81: INVPID Gd/q,Mdq (66)
+db: aesimc Vdq,Wdq (66)
+dc: aesenc Vdq,Wdq (66)
+dd: aesenclast Vdq,Wdq (66)
+de: aesdec Vdq,Wdq (66)
+df: aesdeclast Vdq,Wdq (66)
+f0: MOVBE Gv,Mv | CRC32 Gd,Eb (F2)
+f1: MOVBE Mv,Gv | CRC32 Gd,Ev (F2)
+EndTable
+
+Table: 3-byte opcode 2 (0x0f 0x3a)
+Referrer: 3-byte escape 2
+# 0x0f 0x3a 0x00-0xff
+08: roundps Vdq,Wdq,Ib (66)
+09: roundpd Vdq,Wdq,Ib (66)
+0a: roundss Vss,Wss,Ib (66)
+0b: roundsd Vsd,Wsd,Ib (66)
+0c: blendps Vdq,Wdq,Ib (66)
+0d: blendpd Vdq,Wdq,Ib (66)
+0e: pblendw Vdq,Wdq,Ib (66)
+0f: palignr Pq,Qq,Ib | palignr Vdq,Wdq,Ib (66)
+14: pextrb Rd/Mb,Vdq,Ib (66)
+15: pextrw Rd/Mw,Vdq,Ib (66)
+16: pextrd/pextrq Ed/q,Vdq,Ib (66)
+17: extractps Ed,Vdq,Ib (66)
+20: pinsrb Vdq,Rd/q/Mb,Ib (66)
+21: insertps Vdq,Udq/Md,Ib (66)
+22: pinsrd/pinsrq Vdq,Ed/q,Ib (66)
+40: dpps Vdq,Wdq,Ib (66)
+41: dppd Vdq,Wdq,Ib (66)
+42: mpsadbw Vdq,Wdq,Ib (66)
+60: pcmpestrm Vdq,Wdq,Ib (66)
+61: pcmpestri Vdq,Wdq,Ib (66)
+62: pcmpistrm Vdq,Wdq,Ib (66)
+63: pcmpistri Vdq,Wdq,Ib (66)
+df: aeskeygenassist Vdq,Wdq,Ib (66)
+EndTable
+
+GrpTable: Grp1
+0: ADD
+1: OR
+2: ADC
+3: SBB
+4: AND
+5: SUB
+6: XOR
+7: CMP
+EndTable
+
+GrpTable: Grp1A
+0: POP
+EndTable
+
+GrpTable: Grp2
+0: ROL
+1: ROR
+2: RCL
+3: RCR
+4: SHL/SAL
+5: SHR
+6:
+7: SAR
+EndTable
+
+GrpTable: Grp3_1
+0: TEST Eb,Ib
+1:
+2: NOT Eb
+3: NEG Eb
+4: MUL AL,Eb
+5: IMUL AL,Eb
+6: DIV AL,Eb
+7: IDIV AL,Eb
+EndTable
+
+GrpTable: Grp3_2
+0: TEST Ev,Iz
+1:
+2: NOT Ev
+3: NEG Ev
+4: MUL rAX,Ev
+5: IMUL rAX,Ev
+6: DIV rAX,Ev
+7: IDIV rAX,Ev
+EndTable
+
+GrpTable: Grp4
+0: INC Eb
+1: DEC Eb
+EndTable
+
+GrpTable: Grp5
+0: INC Ev
+1: DEC Ev
+2: CALLN Ev (f64)
+3: CALLF Ep
+4: JMPN Ev (f64)
+5: JMPF Ep
+6: PUSH Ev (d64)
+7:
+EndTable
+
+GrpTable: Grp6
+0: SLDT Rv/Mw
+1: STR Rv/Mw
+2: LLDT Ew
+3: LTR Ew
+4: VERR Ew
+5: VERW Ew
+EndTable
+
+GrpTable: Grp7
+0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B)
+1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001)
+2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B)
+3: LIDT Ms
+4: SMSW Mw/Rv
+5:
+6: LMSW Ew
+7: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B)
+EndTable
+
+GrpTable: Grp8
+4: BT
+5: BTS
+6: BTR
+7: BTC
+EndTable
+
+GrpTable: Grp9
+1: CMPXCHG8B/16B Mq/Mdq
+6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3)
+7: VMPTRST Mq
+EndTable
+
+GrpTable: Grp10
+EndTable
+
+GrpTable: Grp11
+0: MOV
+EndTable
+
+GrpTable: Grp12
+2: psrlw Nq,Ib (11B) | psrlw Udq,Ib (66),(11B)
+4: psraw Nq,Ib (11B) | psraw Udq,Ib (66),(11B)
+6: psllw Nq,Ib (11B) | psllw Udq,Ib (66),(11B)
+EndTable
+
+GrpTable: Grp13
+2: psrld Nq,Ib (11B) | psrld Udq,Ib (66),(11B)
+4: psrad Nq,Ib (11B) | psrad Udq,Ib (66),(11B)
+6: pslld Nq,Ib (11B) | pslld Udq,Ib (66),(11B)
+EndTable
+
+GrpTable: Grp14
+2: psrlq Nq,Ib (11B) | psrlq Udq,Ib (66),(11B)
+3: psrldq Udq,Ib (66),(11B)
+6: psllq Nq,Ib (11B) | psllq Udq,Ib (66),(11B)
+7: pslldq Udq,Ib (66),(11B)
+EndTable
+
+GrpTable: Grp15
+0: fxsave
+1: fxstor
+2: ldmxcsr
+3: stmxcsr
+4: XSAVE
+5: XRSTOR | lfence (11B)
+6: mfence (11B)
+7: clflush | sfence (11B)
+EndTable
+
+GrpTable: Grp16
+0: prefetch NTA
+1: prefetch T0
+2: prefetch T1
+3: prefetch T2
+EndTable
+
+# AMD's Prefetch Group
+GrpTable: GrpP
+0: PREFETCH
+1: PREFETCHW
+EndTable
+
+GrpTable: GrpPDLK
+0: MONTMUL
+1: XSHA1
+2: XSHA2
+EndTable
+
+GrpTable: GrpRNG
+0: xstore-rng
+1: xcrypt-ecb
+2: xcrypt-cbc
+4: xcrypt-cfb
+5: xcrypt-ofb
+EndTable
diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
index 61b41ca3b5a2..d0474ad2a6e5 100644
--- a/arch/x86/mm/extable.c
+++ b/arch/x86/mm/extable.c
@@ -35,34 +35,3 @@ int fixup_exception(struct pt_regs *regs)
return 0;
}
-
-#ifdef CONFIG_X86_64
-/*
- * Need to defined our own search_extable on X86_64 to work around
- * a B stepping K8 bug.
- */
-const struct exception_table_entry *
-search_extable(const struct exception_table_entry *first,
- const struct exception_table_entry *last,
- unsigned long value)
-{
- /* B stepping K8 bug */
- if ((value >> 32) == 0)
- value |= 0xffffffffUL << 32;
-
- while (first <= last) {
- const struct exception_table_entry *mid;
- long diff;
-
- mid = (last - first) / 2 + first;
- diff = mid->insn - value;
- if (diff == 0)
- return mid;
- else if (diff < 0)
- first = mid+1;
- else
- last = mid-1;
- }
- return NULL;
-}
-#endif
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index f4cee9028cf0..8f4e2ac93928 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -38,7 +38,8 @@ enum x86_pf_error_code {
* Returns 0 if mmiotrace is disabled, or if the fault is not
* handled by mmiotrace:
*/
-static inline int kmmio_fault(struct pt_regs *regs, unsigned long addr)
+static inline int __kprobes
+kmmio_fault(struct pt_regs *regs, unsigned long addr)
{
if (unlikely(is_kmmio_active()))
if (kmmio_handler(regs, addr) == 1)
@@ -46,7 +47,7 @@ static inline int kmmio_fault(struct pt_regs *regs, unsigned long addr)
return 0;
}
-static inline int notify_page_fault(struct pt_regs *regs)
+static inline int __kprobes notify_page_fault(struct pt_regs *regs)
{
int ret = 0;
@@ -240,7 +241,7 @@ void vmalloc_sync_all(void)
*
* Handle a fault on the vmalloc or module mapping area
*/
-static noinline int vmalloc_fault(unsigned long address)
+static noinline __kprobes int vmalloc_fault(unsigned long address)
{
unsigned long pgd_paddr;
pmd_t *pmd_k;
@@ -357,7 +358,7 @@ void vmalloc_sync_all(void)
*
* This assumes no large pages in there.
*/
-static noinline int vmalloc_fault(unsigned long address)
+static noinline __kprobes int vmalloc_fault(unsigned long address)
{
pgd_t *pgd, *pgd_ref;
pud_t *pud, *pud_ref;
@@ -860,7 +861,7 @@ static int spurious_fault_check(unsigned long error_code, pte_t *pte)
* There are no security implications to leaving a stale TLB when
* increasing the permissions on a page.
*/
-static noinline int
+static noinline __kprobes int
spurious_fault(unsigned long error_code, unsigned long address)
{
pgd_t *pgd;
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 30938c1d8d5d..f64d0d5e0f89 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -412,7 +412,7 @@ static void __init permanent_kmaps_init(pgd_t *pgd_base)
pkmap_page_table = pte;
}
-static void __init add_one_highpage_init(struct page *page, int pfn)
+static void __init add_one_highpage_init(struct page *page)
{
ClearPageReserved(page);
init_page_count(page);
@@ -445,7 +445,7 @@ static int __init add_highpages_work_fn(unsigned long start_pfn,
if (!pfn_valid(node_pfn))
continue;
page = pfn_to_page(node_pfn);
- add_one_highpage_init(page, node_pfn);
+ add_one_highpage_init(page);
}
return 0;
@@ -703,8 +703,8 @@ void __init find_low_pfn_range(void)
}
#ifndef CONFIG_NEED_MULTIPLE_NODES
-void __init initmem_init(unsigned long start_pfn,
- unsigned long end_pfn)
+void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
+ int acpi, int k8)
{
#ifdef CONFIG_HIGHMEM
highstart_pfn = highend_pfn = max_pfn;
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 5a4398a6006b..0ed09fad6aa1 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -568,7 +568,8 @@ kernel_physical_mapping_init(unsigned long start,
}
#ifndef CONFIG_NUMA
-void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn)
+void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
+ int acpi, int k8)
{
unsigned long bootmap_size, bootmap;
@@ -698,7 +699,7 @@ static int kernel_set_to_readonly;
void set_kernel_text_rw(void)
{
- unsigned long start = PFN_ALIGN(_stext);
+ unsigned long start = PFN_ALIGN(_text);
unsigned long end = PFN_ALIGN(__start_rodata);
if (!kernel_set_to_readonly)
@@ -712,7 +713,7 @@ void set_kernel_text_rw(void)
void set_kernel_text_ro(void)
{
- unsigned long start = PFN_ALIGN(_stext);
+ unsigned long start = PFN_ALIGN(_text);
unsigned long end = PFN_ALIGN(__start_rodata);
if (!kernel_set_to_readonly)
@@ -726,9 +727,13 @@ void set_kernel_text_ro(void)
void mark_rodata_ro(void)
{
- unsigned long start = PFN_ALIGN(_stext), end = PFN_ALIGN(__end_rodata);
+ unsigned long start = PFN_ALIGN(_text);
unsigned long rodata_start =
((unsigned long)__start_rodata + PAGE_SIZE - 1) & PAGE_MASK;
+ unsigned long end = (unsigned long) &__end_rodata_hpage_align;
+ unsigned long text_end = PAGE_ALIGN((unsigned long) &__stop___ex_table);
+ unsigned long rodata_end = PAGE_ALIGN((unsigned long) &__end_rodata);
+ unsigned long data_start = (unsigned long) &_sdata;
printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n",
(end - start) >> 10);
@@ -751,6 +756,14 @@ void mark_rodata_ro(void)
printk(KERN_INFO "Testing CPA: again\n");
set_memory_ro(start, (end-start) >> PAGE_SHIFT);
#endif
+
+ free_init_pages("unused kernel memory",
+ (unsigned long) page_address(virt_to_page(text_end)),
+ (unsigned long)
+ page_address(virt_to_page(rodata_start)));
+ free_init_pages("unused kernel memory",
+ (unsigned long) page_address(virt_to_page(rodata_end)),
+ (unsigned long) page_address(virt_to_page(data_start)));
}
#endif
diff --git a/arch/x86/mm/k8topology_64.c b/arch/x86/mm/k8topology_64.c
index 268f8255280f..b9e2dbfe55c3 100644
--- a/arch/x86/mm/k8topology_64.c
+++ b/arch/x86/mm/k8topology_64.c
@@ -24,6 +24,9 @@
#include <asm/apic.h>
#include <asm/k8.h>
+static struct bootnode __initdata nodes[8];
+static nodemask_t __initdata nodes_parsed = NODE_MASK_NONE;
+
static __init int find_northbridge(void)
{
int num;
@@ -76,12 +79,26 @@ static __init void early_get_boot_cpu_id(void)
early_init_lapic_mapping();
}
-int __init k8_scan_nodes(unsigned long start, unsigned long end)
+int __init k8_get_nodes(struct bootnode *physnodes)
{
- unsigned numnodes, cores, bits, apicid_base;
+ int i;
+ int ret = 0;
+
+ for_each_node_mask(i, nodes_parsed) {
+ physnodes[ret].start = nodes[i].start;
+ physnodes[ret].end = nodes[i].end;
+ ret++;
+ }
+ return ret;
+}
+
+int __init k8_numa_init(unsigned long start_pfn, unsigned long end_pfn)
+{
+ unsigned long start = PFN_PHYS(start_pfn);
+ unsigned long end = PFN_PHYS(end_pfn);
+ unsigned numnodes;
unsigned long prevbase;
- struct bootnode nodes[8];
- int i, j, nb, found = 0;
+ int i, nb, found = 0;
u32 nodeid, reg;
if (!early_pci_allowed())
@@ -91,16 +108,15 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
if (nb < 0)
return nb;
- printk(KERN_INFO "Scanning NUMA topology in Northbridge %d\n", nb);
+ pr_info("Scanning NUMA topology in Northbridge %d\n", nb);
reg = read_pci_config(0, nb, 0, 0x60);
numnodes = ((reg >> 4) & 0xF) + 1;
if (numnodes <= 1)
return -1;
- printk(KERN_INFO "Number of nodes %d\n", numnodes);
+ pr_info("Number of physical nodes %d\n", numnodes);
- memset(&nodes, 0, sizeof(nodes));
prevbase = 0;
for (i = 0; i < 8; i++) {
unsigned long base, limit;
@@ -111,28 +127,28 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
nodeid = limit & 7;
if ((base & 3) == 0) {
if (i < numnodes)
- printk("Skipping disabled node %d\n", i);
+ pr_info("Skipping disabled node %d\n", i);
continue;
}
if (nodeid >= numnodes) {
- printk("Ignoring excess node %d (%lx:%lx)\n", nodeid,
- base, limit);
+ pr_info("Ignoring excess node %d (%lx:%lx)\n", nodeid,
+ base, limit);
continue;
}
if (!limit) {
- printk(KERN_INFO "Skipping node entry %d (base %lx)\n",
- i, base);
+ pr_info("Skipping node entry %d (base %lx)\n",
+ i, base);
continue;
}
if ((base >> 8) & 3 || (limit >> 8) & 3) {
- printk(KERN_ERR "Node %d using interleaving mode %lx/%lx\n",
- nodeid, (base>>8)&3, (limit>>8) & 3);
+ pr_err("Node %d using interleaving mode %lx/%lx\n",
+ nodeid, (base >> 8) & 3, (limit >> 8) & 3);
return -1;
}
- if (node_isset(nodeid, node_possible_map)) {
- printk(KERN_INFO "Node %d already present. Skipping\n",
- nodeid);
+ if (node_isset(nodeid, nodes_parsed)) {
+ pr_info("Node %d already present, skipping\n",
+ nodeid);
continue;
}
@@ -141,8 +157,8 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
limit |= (1<<24)-1;
limit++;
- if (limit > max_pfn << PAGE_SHIFT)
- limit = max_pfn << PAGE_SHIFT;
+ if (limit > end)
+ limit = end;
if (limit <= base)
continue;
@@ -154,24 +170,24 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
if (limit > end)
limit = end;
if (limit == base) {
- printk(KERN_ERR "Empty node %d\n", nodeid);
+ pr_err("Empty node %d\n", nodeid);
continue;
}
if (limit < base) {
- printk(KERN_ERR "Node %d bogus settings %lx-%lx.\n",
+ pr_err("Node %d bogus settings %lx-%lx.\n",
nodeid, base, limit);
continue;
}
/* Could sort here, but pun for now. Should not happen anyroads. */
if (prevbase > base) {
- printk(KERN_ERR "Node map not sorted %lx,%lx\n",
+ pr_err("Node map not sorted %lx,%lx\n",
prevbase, base);
return -1;
}
- printk(KERN_INFO "Node %d MemBase %016lx Limit %016lx\n",
- nodeid, base, limit);
+ pr_info("Node %d MemBase %016lx Limit %016lx\n",
+ nodeid, base, limit);
found++;
@@ -180,18 +196,29 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
prevbase = base;
- node_set(nodeid, node_possible_map);
+ node_set(nodeid, nodes_parsed);
}
if (!found)
return -1;
+ return 0;
+}
+int __init k8_scan_nodes(void)
+{
+ unsigned int bits;
+ unsigned int cores;
+ unsigned int apicid_base;
+ int i;
+
+ BUG_ON(nodes_empty(nodes_parsed));
+ node_possible_map = nodes_parsed;
memnode_shift = compute_hash_shift(nodes, 8, NULL);
if (memnode_shift < 0) {
- printk(KERN_ERR "No NUMA node hash function found. Contact maintainer\n");
+ pr_err("No NUMA node hash function found. Contact maintainer\n");
return -1;
}
- printk(KERN_INFO "Using node hash shift of %d\n", memnode_shift);
+ pr_info("Using node hash shift of %d\n", memnode_shift);
/* use the coreid bits from early_identify_cpu */
bits = boot_cpu_data.x86_coreid_bits;
@@ -200,14 +227,12 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
/* need to get boot_cpu_id early for system with apicid lifting */
early_get_boot_cpu_id();
if (boot_cpu_physical_apicid > 0) {
- printk(KERN_INFO "BSP APIC ID: %02x\n",
- boot_cpu_physical_apicid);
+ pr_info("BSP APIC ID: %02x\n", boot_cpu_physical_apicid);
apicid_base = boot_cpu_physical_apicid;
}
- for (i = 0; i < 8; i++) {
- if (nodes[i].start == nodes[i].end)
- continue;
+ for_each_node_mask(i, node_possible_map) {
+ int j;
e820_register_active_regions(i,
nodes[i].start >> PAGE_SHIFT,
diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c
index d2530062fe00..b20760ca7244 100644
--- a/arch/x86/mm/numa_32.c
+++ b/arch/x86/mm/numa_32.c
@@ -347,8 +347,8 @@ static void init_remap_allocator(int nid)
(ulong) node_remap_end_vaddr[nid]);
}
-void __init initmem_init(unsigned long start_pfn,
- unsigned long end_pfn)
+void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
+ int acpi, int k8)
{
int nid;
long kva_target_pfn;
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c
index 459913beac71..086f98a66d80 100644
--- a/arch/x86/mm/numa_64.c
+++ b/arch/x86/mm/numa_64.c
@@ -306,8 +306,71 @@ void __init numa_init_array(void)
#ifdef CONFIG_NUMA_EMU
/* Numa emulation */
+static struct bootnode nodes[MAX_NUMNODES] __initdata;
+static struct bootnode physnodes[MAX_NUMNODES] __initdata;
static char *cmdline __initdata;
+static int __init setup_physnodes(unsigned long start, unsigned long end,
+ int acpi, int k8)
+{
+ int nr_nodes = 0;
+ int ret = 0;
+ int i;
+
+#ifdef CONFIG_ACPI_NUMA
+ if (acpi)
+ nr_nodes = acpi_get_nodes(physnodes);
+#endif
+#ifdef CONFIG_K8_NUMA
+ if (k8)
+ nr_nodes = k8_get_nodes(physnodes);
+#endif
+ /*
+ * Basic sanity checking on the physical node map: there may be errors
+ * if the SRAT or K8 incorrectly reported the topology or the mem=
+ * kernel parameter is used.
+ */
+ for (i = 0; i < nr_nodes; i++) {
+ if (physnodes[i].start == physnodes[i].end)
+ continue;
+ if (physnodes[i].start > end) {
+ physnodes[i].end = physnodes[i].start;
+ continue;
+ }
+ if (physnodes[i].end < start) {
+ physnodes[i].start = physnodes[i].end;
+ continue;
+ }
+ if (physnodes[i].start < start)
+ physnodes[i].start = start;
+ if (physnodes[i].end > end)
+ physnodes[i].end = end;
+ }
+
+ /*
+ * Remove all nodes that have no memory or were truncated because of the
+ * limited address range.
+ */
+ for (i = 0; i < nr_nodes; i++) {
+ if (physnodes[i].start == physnodes[i].end)
+ continue;
+ physnodes[ret].start = physnodes[i].start;
+ physnodes[ret].end = physnodes[i].end;
+ ret++;
+ }
+
+ /*
+ * If no physical topology was detected, a single node is faked to cover
+ * the entire address space.
+ */
+ if (!ret) {
+ physnodes[ret].start = start;
+ physnodes[ret].end = end;
+ ret = 1;
+ }
+ return ret;
+}
+
/*
* Setups up nid to range from addr to addr + size. If the end
* boundary is greater than max_addr, then max_addr is used instead.
@@ -315,11 +378,9 @@ static char *cmdline __initdata;
* allocation past addr and -1 otherwise. addr is adjusted to be at
* the end of the node.
*/
-static int __init setup_node_range(int nid, struct bootnode *nodes, u64 *addr,
- u64 size, u64 max_addr)
+static int __init setup_node_range(int nid, u64 *addr, u64 size, u64 max_addr)
{
int ret = 0;
-
nodes[nid].start = *addr;
*addr += size;
if (*addr >= max_addr) {
@@ -335,12 +396,111 @@ static int __init setup_node_range(int nid, struct bootnode *nodes, u64 *addr,
}
/*
+ * Sets up nr_nodes fake nodes interleaved over physical nodes ranging from addr
+ * to max_addr. The return value is the number of nodes allocated.
+ */
+static int __init split_nodes_interleave(u64 addr, u64 max_addr,
+ int nr_phys_nodes, int nr_nodes)
+{
+ nodemask_t physnode_mask = NODE_MASK_NONE;
+ u64 size;
+ int big;
+ int ret = 0;
+ int i;
+
+ if (nr_nodes <= 0)
+ return -1;
+ if (nr_nodes > MAX_NUMNODES) {
+ pr_info("numa=fake=%d too large, reducing to %d\n",
+ nr_nodes, MAX_NUMNODES);
+ nr_nodes = MAX_NUMNODES;
+ }
+
+ size = (max_addr - addr - e820_hole_size(addr, max_addr)) / nr_nodes;
+ /*
+ * Calculate the number of big nodes that can be allocated as a result
+ * of consolidating the remainder.
+ */
+ big = ((size & ~FAKE_NODE_MIN_HASH_MASK) & nr_nodes) /
+ FAKE_NODE_MIN_SIZE;
+
+ size &= FAKE_NODE_MIN_HASH_MASK;
+ if (!size) {
+ pr_err("Not enough memory for each node. "
+ "NUMA emulation disabled.\n");
+ return -1;
+ }
+
+ for (i = 0; i < nr_phys_nodes; i++)
+ if (physnodes[i].start != physnodes[i].end)
+ node_set(i, physnode_mask);
+
+ /*
+ * Continue to fill physical nodes with fake nodes until there is no
+ * memory left on any of them.
+ */
+ while (nodes_weight(physnode_mask)) {
+ for_each_node_mask(i, physnode_mask) {
+ u64 end = physnodes[i].start + size;
+ u64 dma32_end = PFN_PHYS(MAX_DMA32_PFN);
+
+ if (ret < big)
+ end += FAKE_NODE_MIN_SIZE;
+
+ /*
+ * Continue to add memory to this fake node if its
+ * non-reserved memory is less than the per-node size.
+ */
+ while (end - physnodes[i].start -
+ e820_hole_size(physnodes[i].start, end) < size) {
+ end += FAKE_NODE_MIN_SIZE;
+ if (end > physnodes[i].end) {
+ end = physnodes[i].end;
+ break;
+ }
+ }
+
+ /*
+ * If there won't be at least FAKE_NODE_MIN_SIZE of
+ * non-reserved memory in ZONE_DMA32 for the next node,
+ * this one must extend to the boundary.
+ */
+ if (end < dma32_end && dma32_end - end -
+ e820_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
+ end = dma32_end;
+
+ /*
+ * If there won't be enough non-reserved memory for the
+ * next node, this one must extend to the end of the
+ * physical node.
+ */
+ if (physnodes[i].end - end -
+ e820_hole_size(end, physnodes[i].end) < size)
+ end = physnodes[i].end;
+
+ /*
+ * Avoid allocating more nodes than requested, which can
+ * happen as a result of rounding down each node's size
+ * to FAKE_NODE_MIN_SIZE.
+ */
+ if (nodes_weight(physnode_mask) + ret >= nr_nodes)
+ end = physnodes[i].end;
+
+ if (setup_node_range(ret++, &physnodes[i].start,
+ end - physnodes[i].start,
+ physnodes[i].end) < 0)
+ node_clear(i, physnode_mask);
+ }
+ }
+ return ret;
+}
+
+/*
* Splits num_nodes nodes up equally starting at node_start. The return value
* is the number of nodes split up and addr is adjusted to be at the end of the
* last node allocated.
*/
-static int __init split_nodes_equally(struct bootnode *nodes, u64 *addr,
- u64 max_addr, int node_start,
+static int __init split_nodes_equally(u64 *addr, u64 max_addr, int node_start,
int num_nodes)
{
unsigned int big;
@@ -388,7 +548,7 @@ static int __init split_nodes_equally(struct bootnode *nodes, u64 *addr,
break;
}
}
- if (setup_node_range(i, nodes, addr, end - *addr, max_addr) < 0)
+ if (setup_node_range(i, addr, end - *addr, max_addr) < 0)
break;
}
return i - node_start + 1;
@@ -399,12 +559,12 @@ static int __init split_nodes_equally(struct bootnode *nodes, u64 *addr,
* always assigned to a final node and can be asymmetric. Returns the number of
* nodes split.
*/
-static int __init split_nodes_by_size(struct bootnode *nodes, u64 *addr,
- u64 max_addr, int node_start, u64 size)
+static int __init split_nodes_by_size(u64 *addr, u64 max_addr, int node_start,
+ u64 size)
{
int i = node_start;
size = (size << 20) & FAKE_NODE_MIN_HASH_MASK;
- while (!setup_node_range(i++, nodes, addr, size, max_addr))
+ while (!setup_node_range(i++, addr, size, max_addr))
;
return i - node_start;
}
@@ -413,15 +573,15 @@ static int __init split_nodes_by_size(struct bootnode *nodes, u64 *addr,
* Sets up the system RAM area from start_pfn to last_pfn according to the
* numa=fake command-line option.
*/
-static struct bootnode nodes[MAX_NUMNODES] __initdata;
-
-static int __init numa_emulation(unsigned long start_pfn, unsigned long last_pfn)
+static int __init numa_emulation(unsigned long start_pfn,
+ unsigned long last_pfn, int acpi, int k8)
{
u64 size, addr = start_pfn << PAGE_SHIFT;
u64 max_addr = last_pfn << PAGE_SHIFT;
int num_nodes = 0, num = 0, coeff_flag, coeff = -1, i;
+ int num_phys_nodes;
- memset(&nodes, 0, sizeof(nodes));
+ num_phys_nodes = setup_physnodes(addr, max_addr, acpi, k8);
/*
* If the numa=fake command-line is just a single number N, split the
* system RAM into N fake nodes.
@@ -429,7 +589,8 @@ static int __init numa_emulation(unsigned long start_pfn, unsigned long last_pfn
if (!strchr(cmdline, '*') && !strchr(cmdline, ',')) {
long n = simple_strtol(cmdline, NULL, 0);
- num_nodes = split_nodes_equally(nodes, &addr, max_addr, 0, n);
+ num_nodes = split_nodes_interleave(addr, max_addr,
+ num_phys_nodes, n);
if (num_nodes < 0)
return num_nodes;
goto out;
@@ -456,8 +617,8 @@ static int __init numa_emulation(unsigned long start_pfn, unsigned long last_pfn
size = ((u64)num << 20) & FAKE_NODE_MIN_HASH_MASK;
if (size)
for (i = 0; i < coeff; i++, num_nodes++)
- if (setup_node_range(num_nodes, nodes,
- &addr, size, max_addr) < 0)
+ if (setup_node_range(num_nodes, &addr,
+ size, max_addr) < 0)
goto done;
if (!*cmdline)
break;
@@ -473,7 +634,7 @@ done:
if (addr < max_addr) {
if (coeff_flag && coeff < 0) {
/* Split remaining nodes into num-sized chunks */
- num_nodes += split_nodes_by_size(nodes, &addr, max_addr,
+ num_nodes += split_nodes_by_size(&addr, max_addr,
num_nodes, num);
goto out;
}
@@ -482,7 +643,7 @@ done:
/* Split remaining nodes into coeff chunks */
if (coeff <= 0)
break;
- num_nodes += split_nodes_equally(nodes, &addr, max_addr,
+ num_nodes += split_nodes_equally(&addr, max_addr,
num_nodes, coeff);
break;
case ',':
@@ -490,8 +651,8 @@ done:
break;
default:
/* Give one final node */
- setup_node_range(num_nodes, nodes, &addr,
- max_addr - addr, max_addr);
+ setup_node_range(num_nodes, &addr, max_addr - addr,
+ max_addr);
num_nodes++;
}
}
@@ -505,14 +666,10 @@ out:
}
/*
- * We need to vacate all active ranges that may have been registered by
- * SRAT and set acpi_numa to -1 so that srat_disabled() always returns
- * true. NUMA emulation has succeeded so we will not scan ACPI nodes.
+ * We need to vacate all active ranges that may have been registered for
+ * the e820 memory map.
*/
remove_all_active_ranges();
-#ifdef CONFIG_ACPI_NUMA
- acpi_numa = -1;
-#endif
for_each_node_mask(i, node_possible_map) {
e820_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
nodes[i].end >> PAGE_SHIFT);
@@ -524,7 +681,8 @@ out:
}
#endif /* CONFIG_NUMA_EMU */
-void __init initmem_init(unsigned long start_pfn, unsigned long last_pfn)
+void __init initmem_init(unsigned long start_pfn, unsigned long last_pfn,
+ int acpi, int k8)
{
int i;
@@ -532,23 +690,22 @@ void __init initmem_init(unsigned long start_pfn, unsigned long last_pfn)
nodes_clear(node_online_map);
#ifdef CONFIG_NUMA_EMU
- if (cmdline && !numa_emulation(start_pfn, last_pfn))
+ if (cmdline && !numa_emulation(start_pfn, last_pfn, acpi, k8))
return;
nodes_clear(node_possible_map);
nodes_clear(node_online_map);
#endif
#ifdef CONFIG_ACPI_NUMA
- if (!numa_off && !acpi_scan_nodes(start_pfn << PAGE_SHIFT,
- last_pfn << PAGE_SHIFT))
+ if (!numa_off && acpi && !acpi_scan_nodes(start_pfn << PAGE_SHIFT,
+ last_pfn << PAGE_SHIFT))
return;
nodes_clear(node_possible_map);
nodes_clear(node_online_map);
#endif
#ifdef CONFIG_K8_NUMA
- if (!numa_off && !k8_scan_nodes(start_pfn<<PAGE_SHIFT,
- last_pfn<<PAGE_SHIFT))
+ if (!numa_off && k8 && !k8_scan_nodes())
return;
nodes_clear(node_possible_map);
nodes_clear(node_online_map);
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index dd38bfbefd1f..b494fc4a986e 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -279,6 +279,20 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
__pa((unsigned long)__end_rodata) >> PAGE_SHIFT))
pgprot_val(forbidden) |= _PAGE_RW;
+#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
+ /*
+ * Kernel text mappings for the large page aligned .rodata section
+ * will be read-only. For the kernel identity mappings covering
+ * the holes caused by this alignment can be anything.
+ *
+ * This will preserve the large page mappings for kernel text/data
+ * at no extra cost.
+ */
+ if (within(address, (unsigned long)_text,
+ (unsigned long)__end_rodata_hpage_align))
+ pgprot_val(forbidden) |= _PAGE_RW;
+#endif
+
prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));
return prot;
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index e78cd0ec2bcf..ea526d89a9bc 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -708,9 +708,8 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
if (!range_is_allowed(pfn, size))
return 0;
- if (file->f_flags & O_SYNC) {
+ if (file->f_flags & O_DSYNC)
flags = _PAGE_CACHE_UC_MINUS;
- }
#ifdef CONFIG_X86_32
/*
diff --git a/arch/x86/mm/srat_64.c b/arch/x86/mm/srat_64.c
index dbb5381f7b3b..34aa438d60b6 100644
--- a/arch/x86/mm/srat_64.c
+++ b/arch/x86/mm/srat_64.c
@@ -290,8 +290,6 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
printk(KERN_INFO "SRAT: Node %u PXM %u %lx-%lx\n", node, pxm,
start, end);
- e820_register_active_regions(node, start >> PAGE_SHIFT,
- end >> PAGE_SHIFT);
if (ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) {
update_nodes_add(node, start, end);
@@ -338,6 +336,19 @@ static int __init nodes_cover_memory(const struct bootnode *nodes)
void __init acpi_numa_arch_fixup(void) {}
+int __init acpi_get_nodes(struct bootnode *physnodes)
+{
+ int i;
+ int ret = 0;
+
+ for_each_node_mask(i, nodes_parsed) {
+ physnodes[ret].start = nodes[i].start;
+ physnodes[ret].end = nodes[i].end;
+ ret++;
+ }
+ return ret;
+}
+
/* Use the information discovered above to actually set up the nodes. */
int __init acpi_scan_nodes(unsigned long start, unsigned long end)
{
@@ -350,11 +361,6 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
for (i = 0; i < MAX_NUMNODES; i++)
cutoff_node(i, start, end);
- if (!nodes_cover_memory(nodes)) {
- bad_srat();
- return -1;
- }
-
memnode_shift = compute_hash_shift(node_memblk_range, num_node_memblks,
memblk_nodeid);
if (memnode_shift < 0) {
@@ -364,6 +370,14 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
return -1;
}
+ for_each_node_mask(i, nodes_parsed)
+ e820_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
+ nodes[i].end >> PAGE_SHIFT);
+ if (!nodes_cover_memory(nodes)) {
+ bad_srat();
+ return -1;
+ }
+
/* Account for nodes with cpus and no memory */
nodes_or(node_possible_map, nodes_parsed, cpu_nodes_parsed);
@@ -454,7 +468,6 @@ void __init acpi_fake_nodes(const struct bootnode *fake_nodes, int num_nodes)
for (i = 0; i < num_nodes; i++)
if (fake_nodes[i].start != fake_nodes[i].end)
node_set(i, nodes_parsed);
- WARN_ON(!nodes_cover_memory(fake_nodes));
}
static int null_slit_node_compare(int a, int b)
diff --git a/arch/x86/mm/testmmiotrace.c b/arch/x86/mm/testmmiotrace.c
index 427fd1b56df5..8565d944f7cf 100644
--- a/arch/x86/mm/testmmiotrace.c
+++ b/arch/x86/mm/testmmiotrace.c
@@ -1,12 +1,13 @@
/*
* Written by Pekka Paalanen, 2008-2009 <pq@iki.fi>
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/io.h>
#include <linux/mmiotrace.h>
-#define MODULE_NAME "testmmiotrace"
-
static unsigned long mmio_address;
module_param(mmio_address, ulong, 0);
MODULE_PARM_DESC(mmio_address, " Start address of the mapping of 16 kB "
@@ -30,7 +31,7 @@ static unsigned v32(unsigned i)
static void do_write_test(void __iomem *p)
{
unsigned int i;
- pr_info(MODULE_NAME ": write test.\n");
+ pr_info("write test.\n");
mmiotrace_printk("Write test.\n");
for (i = 0; i < 256; i++)
@@ -47,7 +48,7 @@ static void do_read_test(void __iomem *p)
{
unsigned int i;
unsigned errs[3] = { 0 };
- pr_info(MODULE_NAME ": read test.\n");
+ pr_info("read test.\n");
mmiotrace_printk("Read test.\n");
for (i = 0; i < 256; i++)
@@ -68,7 +69,7 @@ static void do_read_test(void __iomem *p)
static void do_read_far_test(void __iomem *p)
{
- pr_info(MODULE_NAME ": read far test.\n");
+ pr_info("read far test.\n");
mmiotrace_printk("Read far test.\n");
ioread32(p + read_far);
@@ -78,7 +79,7 @@ static void do_test(unsigned long size)
{
void __iomem *p = ioremap_nocache(mmio_address, size);
if (!p) {
- pr_err(MODULE_NAME ": could not ioremap, aborting.\n");
+ pr_err("could not ioremap, aborting.\n");
return;
}
mmiotrace_printk("ioremap returned %p.\n", p);
@@ -94,24 +95,22 @@ static int __init init(void)
unsigned long size = (read_far) ? (8 << 20) : (16 << 10);
if (mmio_address == 0) {
- pr_err(MODULE_NAME ": you have to use the module argument "
- "mmio_address.\n");
- pr_err(MODULE_NAME ": DO NOT LOAD THIS MODULE UNLESS"
- " YOU REALLY KNOW WHAT YOU ARE DOING!\n");
+ pr_err("you have to use the module argument mmio_address.\n");
+ pr_err("DO NOT LOAD THIS MODULE UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!\n");
return -ENXIO;
}
- pr_warning(MODULE_NAME ": WARNING: mapping %lu kB @ 0x%08lx in PCI "
- "address space, and writing 16 kB of rubbish in there.\n",
- size >> 10, mmio_address);
+ pr_warning("WARNING: mapping %lu kB @ 0x%08lx in PCI address space, "
+ "and writing 16 kB of rubbish in there.\n",
+ size >> 10, mmio_address);
do_test(size);
- pr_info(MODULE_NAME ": All done.\n");
+ pr_info("All done.\n");
return 0;
}
static void __exit cleanup(void)
{
- pr_debug(MODULE_NAME ": unloaded.\n");
+ pr_debug("unloaded.\n");
}
module_init(init);
diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile
index d49202e740ea..d8a0a6279a4d 100644
--- a/arch/x86/pci/Makefile
+++ b/arch/x86/pci/Makefile
@@ -15,3 +15,8 @@ obj-$(CONFIG_X86_NUMAQ) += numaq_32.o
obj-y += common.o early.o
obj-y += amd_bus.o
+obj-$(CONFIG_X86_64) += intel_bus.o
+
+ifeq ($(CONFIG_PCI_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 1014eb4bfc37..9b3daf976732 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -7,6 +7,7 @@
#include <asm/pci_x86.h>
struct pci_root_info {
+ struct acpi_device *bridge;
char *name;
unsigned int res_num;
struct resource *res;
@@ -107,12 +108,18 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
res->child = NULL;
if (insert_resource(root, res)) {
- printk(KERN_ERR "PCI: Failed to allocate 0x%lx-0x%lx "
- "from %s for %s\n", (unsigned long) res->start,
- (unsigned long) res->end, root->name, info->name);
+ dev_err(&info->bridge->dev, "can't allocate %pRt\n", res);
} else {
info->bus->resource[info->res_num] = res;
info->res_num++;
+ if (addr.translation_offset)
+ dev_info(&info->bridge->dev, "host bridge window: %pRt "
+ "(PCI address [%#llx-%#llx])\n",
+ res, res->start - addr.translation_offset,
+ res->end - addr.translation_offset);
+ else
+ dev_info(&info->bridge->dev,
+ "host bridge window: %pRt\n", res);
}
return AE_OK;
}
@@ -124,6 +131,7 @@ get_current_resources(struct acpi_device *device, int busnum,
struct pci_root_info info;
size_t size;
+ info.bridge = device;
info.bus = bus;
info.res_num = 0;
acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource,
diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c
index 572ee9782f2a..995f36096a42 100644
--- a/arch/x86/pci/amd_bus.c
+++ b/arch/x86/pci/amd_bus.c
@@ -10,6 +10,8 @@
#include <linux/cpumask.h>
#endif
+#include "bus_numa.h"
+
/*
* This discovers the pcibus <-> node mapping on AMD K8.
* also get peer root bus resource for io,mmio
@@ -17,25 +19,9 @@
#ifdef CONFIG_X86_64
-/*
- * sub bus (transparent) will use entres from 3 to store extra from root,
- * so need to make sure have enought slot there, increase PCI_BUS_NUM_RESOURCES?
- */
-#define RES_NUM 16
-struct pci_root_info {
- char name[12];
- unsigned int res_num;
- struct resource res[RES_NUM];
- int bus_min;
- int bus_max;
- int node;
- int link;
-};
-
-/* 4 at this time, it may become to 32 */
-#define PCI_ROOT_NR 4
-static int pci_root_num;
-static struct pci_root_info pci_root_info[PCI_ROOT_NR];
+int pci_root_num;
+struct pci_root_info pci_root_info[PCI_ROOT_NR];
+static int found_all_numa_early;
void x86_pci_root_bus_res_quirks(struct pci_bus *b)
{
@@ -48,8 +34,11 @@ void x86_pci_root_bus_res_quirks(struct pci_bus *b)
b->resource[1] != &iomem_resource)
return;
- /* if only one root bus, don't need to anything */
- if (pci_root_num < 2)
+ if (!pci_root_num)
+ return;
+
+ /* for amd, if only one root bus, don't need to do anything */
+ if (pci_root_num < 2 && found_all_numa_early)
return;
for (i = 0; i < pci_root_num; i++) {
@@ -130,12 +119,15 @@ static void __init update_range(struct res_range *range, size_t start,
}
}
-static void __init update_res(struct pci_root_info *info, size_t start,
+void __init update_res(struct pci_root_info *info, size_t start,
size_t end, unsigned long flags, int merge)
{
int i;
struct resource *res;
+ if (start > end)
+ return;
+
if (!merge)
goto addit;
@@ -230,7 +222,6 @@ static int __init early_fill_mp_bus_info(void)
int j;
unsigned bus;
unsigned slot;
- int found;
int node;
int link;
int def_node;
@@ -247,7 +238,7 @@ static int __init early_fill_mp_bus_info(void)
if (!early_pci_allowed())
return -1;
- found = 0;
+ found_all_numa_early = 0;
for (i = 0; i < ARRAY_SIZE(pci_probes); i++) {
u32 id;
u16 device;
@@ -261,12 +252,12 @@ static int __init early_fill_mp_bus_info(void)
device = (id>>16) & 0xffff;
if (pci_probes[i].vendor == vendor &&
pci_probes[i].device == device) {
- found = 1;
+ found_all_numa_early = 1;
break;
}
}
- if (!found)
+ if (!found_all_numa_early)
return 0;
pci_root_num = 0;
@@ -488,7 +479,7 @@ static int __init early_fill_mp_bus_info(void)
info = &pci_root_info[i];
res_num = info->res_num;
busnum = info->bus_min;
- printk(KERN_DEBUG "bus: [%02x,%02x] on node %x link %x\n",
+ printk(KERN_DEBUG "bus: [%02x, %02x] on node %x link %x\n",
info->bus_min, info->bus_max, info->node, info->link);
for (j = 0; j < res_num; j++) {
res = &info->res[j];
diff --git a/arch/x86/pci/bus_numa.h b/arch/x86/pci/bus_numa.h
new file mode 100644
index 000000000000..4ff126a3e887
--- /dev/null
+++ b/arch/x86/pci/bus_numa.h
@@ -0,0 +1,26 @@
+#ifdef CONFIG_X86_64
+
+/*
+ * sub bus (transparent) will use entres from 3 to store extra from
+ * root, so need to make sure we have enought slot there, Should we
+ * increase PCI_BUS_NUM_RESOURCES?
+ */
+#define RES_NUM 16
+struct pci_root_info {
+ char name[12];
+ unsigned int res_num;
+ struct resource res[RES_NUM];
+ int bus_min;
+ int bus_max;
+ int node;
+ int link;
+};
+
+/* 4 at this time, it may become to 32 */
+#define PCI_ROOT_NR 4
+extern int pci_root_num;
+extern struct pci_root_info pci_root_info[PCI_ROOT_NR];
+
+extern void update_res(struct pci_root_info *info, size_t start,
+ size_t end, unsigned long flags, int merge);
+#endif
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 1331fcf26143..d2552c68e94d 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -410,8 +410,6 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum)
return bus;
}
-extern u8 pci_cache_line_size;
-
int __init pcibios_init(void)
{
struct cpuinfo_x86 *c = &boot_cpu_data;
@@ -422,15 +420,19 @@ int __init pcibios_init(void)
}
/*
- * Assume PCI cacheline size of 32 bytes for all x86s except K7/K8
- * and P4. It's also good for 386/486s (which actually have 16)
+ * Set PCI cacheline size to that of the CPU if the CPU has reported it.
+ * (For older CPUs that don't support cpuid, we se it to 32 bytes
+ * It's also good for 386/486s (which actually have 16)
* as quite a few PCI devices do not support smaller values.
*/
- pci_cache_line_size = 32 >> 2;
- if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD)
- pci_cache_line_size = 64 >> 2; /* K7 & K8 */
- else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL)
- pci_cache_line_size = 128 >> 2; /* P4 */
+ if (c->x86_clflush_size > 0) {
+ pci_dfl_cache_line_size = c->x86_clflush_size >> 2;
+ printk(KERN_DEBUG "PCI: pci_cache_line_size set to %d bytes\n",
+ pci_dfl_cache_line_size << 2);
+ } else {
+ pci_dfl_cache_line_size = 32 >> 2;
+ printk(KERN_DEBUG "PCI: Unknown cacheline size. Setting to 32 bytes\n");
+ }
pcibios_resource_survey();
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index b22d13b0c71d..52e656f17781 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -129,7 +129,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
continue;
if (!r->start ||
pci_claim_resource(dev, idx) < 0) {
- dev_info(&dev->dev, "BAR %d: can't allocate resource\n", idx);
+ dev_info(&dev->dev, "BAR %d: can't allocate %pRt\n", idx, r);
/*
* Something is wrong with the region.
* Invalidate the resource to prevent
@@ -164,12 +164,10 @@ static void __init pcibios_allocate_resources(int pass)
else
disabled = !(command & PCI_COMMAND_MEMORY);
if (pass == disabled) {
- dev_dbg(&dev->dev, "resource %#08llx-%#08llx (f=%lx, d=%d, p=%d)\n",
- (unsigned long long) r->start,
- (unsigned long long) r->end,
- r->flags, disabled, pass);
+ dev_dbg(&dev->dev, "%pRf (d=%d, p=%d)\n", r,
+ disabled, pass);
if (pci_claim_resource(dev, idx) < 0) {
- dev_info(&dev->dev, "BAR %d: can't allocate resource\n", idx);
+ dev_info(&dev->dev, "BAR %d: can't allocate %pRt\n", idx, r);
/* We'll assign a new address later */
r->end -= r->start;
r->start = 0;
@@ -182,7 +180,7 @@ static void __init pcibios_allocate_resources(int pass)
/* Turn the ROM off, leave the resource region,
* but keep it unregistered. */
u32 reg;
- dev_dbg(&dev->dev, "disabling ROM\n");
+ dev_dbg(&dev->dev, "disabling ROM %pRt\n", r);
r->flags &= ~IORESOURCE_ROM_ENABLE;
pci_read_config_dword(dev,
dev->rom_base_reg, &reg);
@@ -282,6 +280,15 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
return -EINVAL;
prot = pgprot_val(vma->vm_page_prot);
+
+ /*
+ * Return error if pat is not enabled and write_combine is requested.
+ * Caller can followup with UC MINUS request and add a WC mtrr if there
+ * is a free mtrr slot.
+ */
+ if (!pat_enabled && write_combine)
+ return -EINVAL;
+
if (pat_enabled && write_combine)
prot |= _PAGE_CACHE_WC;
else if (pat_enabled || boot_cpu_data.x86 > 3)
diff --git a/arch/x86/pci/intel_bus.c b/arch/x86/pci/intel_bus.c
new file mode 100644
index 000000000000..b7a55dc55d13
--- /dev/null
+++ b/arch/x86/pci/intel_bus.c
@@ -0,0 +1,90 @@
+/*
+ * to read io range from IOH pci conf, need to do it after mmconfig is there
+ */
+
+#include <linux/delay.h>
+#include <linux/dmi.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <asm/pci_x86.h>
+
+#include "bus_numa.h"
+
+static inline void print_ioh_resources(struct pci_root_info *info)
+{
+ int res_num;
+ int busnum;
+ int i;
+
+ printk(KERN_DEBUG "IOH bus: [%02x, %02x]\n",
+ info->bus_min, info->bus_max);
+ res_num = info->res_num;
+ busnum = info->bus_min;
+ for (i = 0; i < res_num; i++) {
+ struct resource *res;
+
+ res = &info->res[i];
+ printk(KERN_DEBUG "IOH bus: %02x index %x %s: [%llx, %llx]\n",
+ busnum, i,
+ (res->flags & IORESOURCE_IO) ? "io port" :
+ "mmio",
+ res->start, res->end);
+ }
+}
+
+#define IOH_LIO 0x108
+#define IOH_LMMIOL 0x10c
+#define IOH_LMMIOH 0x110
+#define IOH_LMMIOH_BASEU 0x114
+#define IOH_LMMIOH_LIMITU 0x118
+#define IOH_LCFGBUS 0x11c
+
+static void __devinit pci_root_bus_res(struct pci_dev *dev)
+{
+ u16 word;
+ u32 dword;
+ struct pci_root_info *info;
+ u16 io_base, io_end;
+ u32 mmiol_base, mmiol_end;
+ u64 mmioh_base, mmioh_end;
+ int bus_base, bus_end;
+
+ if (pci_root_num >= PCI_ROOT_NR) {
+ printk(KERN_DEBUG "intel_bus.c: PCI_ROOT_NR is too small\n");
+ return;
+ }
+
+ info = &pci_root_info[pci_root_num];
+ pci_root_num++;
+
+ pci_read_config_word(dev, IOH_LCFGBUS, &word);
+ bus_base = (word & 0xff);
+ bus_end = (word & 0xff00) >> 8;
+ sprintf(info->name, "PCI Bus #%02x", bus_base);
+ info->bus_min = bus_base;
+ info->bus_max = bus_end;
+
+ pci_read_config_word(dev, IOH_LIO, &word);
+ io_base = (word & 0xf0) << (12 - 4);
+ io_end = (word & 0xf000) | 0xfff;
+ update_res(info, io_base, io_end, IORESOURCE_IO, 0);
+
+ pci_read_config_dword(dev, IOH_LMMIOL, &dword);
+ mmiol_base = (dword & 0xff00) << (24 - 8);
+ mmiol_end = (dword & 0xff000000) | 0xffffff;
+ update_res(info, mmiol_base, mmiol_end, IORESOURCE_MEM, 0);
+
+ pci_read_config_dword(dev, IOH_LMMIOH, &dword);
+ mmioh_base = ((u64)(dword & 0xfc00)) << (26 - 10);
+ mmioh_end = ((u64)(dword & 0xfc000000) | 0x3ffffff);
+ pci_read_config_dword(dev, IOH_LMMIOH_BASEU, &dword);
+ mmioh_base |= ((u64)(dword & 0x7ffff)) << 32;
+ pci_read_config_dword(dev, IOH_LMMIOH_LIMITU, &dword);
+ mmioh_end |= ((u64)(dword & 0x7ffff)) << 32;
+ update_res(info, mmioh_base, mmioh_end, IORESOURCE_MEM, 0);
+
+ print_ioh_resources(info);
+}
+
+/* intel IOH */
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x342e, pci_root_bus_res);
diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c
index 4061bb0f267d..5e22d837a5db 100644
--- a/arch/x86/pci/legacy.c
+++ b/arch/x86/pci/legacy.c
@@ -11,28 +11,14 @@
*/
static void __devinit pcibios_fixup_peer_bridges(void)
{
- int n, devfn;
- long node;
+ int n;
if (pcibios_last_bus <= 0 || pcibios_last_bus > 0xff)
return;
DBG("PCI: Peer bridge fixup\n");
- for (n=0; n <= pcibios_last_bus; n++) {
- u32 l;
- if (pci_find_bus(0, n))
- continue;
- node = get_mp_bus_to_node(n);
- for (devfn = 0; devfn < 256; devfn += 8) {
- if (!raw_pci_read(0, n, devfn, PCI_VENDOR_ID, 2, &l) &&
- l != 0x0000 && l != 0xffff) {
- DBG("Found device at %02x:%02x [%04x]\n", n, devfn, l);
- printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n);
- pci_scan_bus_on_node(n, &pci_root_ops, node);
- break;
- }
- }
- }
+ for (n=0; n <= pcibios_last_bus; n++)
+ pcibios_scan_specific_bus(n);
}
static int __init pci_legacy_init(void)
@@ -52,6 +38,29 @@ static int __init pci_legacy_init(void)
return 0;
}
+EXPORT_SYMBOL_GPL(pci_legacy_init);
+
+void pcibios_scan_specific_bus(int busn)
+{
+ int devfn;
+ long node;
+ u32 l;
+
+ if (pci_find_bus(0, busn))
+ return;
+
+ node = get_mp_bus_to_node(busn);
+ for (devfn = 0; devfn < 256; devfn += 8) {
+ if (!raw_pci_read(0, busn, devfn, PCI_VENDOR_ID, 2, &l) &&
+ l != 0x0000 && l != 0xffff) {
+ DBG("Found device at %02x:%02x [%04x]\n", busn, devfn, l);
+ printk(KERN_INFO "PCI: Discovered peer bus %02x\n", busn);
+ pci_scan_bus_on_node(busn, &pci_root_ops, node);
+ return;
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(pcibios_scan_specific_bus);
int __init pci_subsys_init(void)
{
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index 602c172d3bd5..02642773c29d 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -15,6 +15,7 @@
#include <linux/acpi.h>
#include <linux/sfi_acpi.h>
#include <linux/bitmap.h>
+#include <linux/dmi.h>
#include <linux/sort.h>
#include <asm/e820.h>
#include <asm/pci_x86.h>
@@ -527,18 +528,31 @@ reject:
static int __initdata known_bridge;
-static int acpi_mcfg_64bit_base_addr __initdata = FALSE;
-
/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */
struct acpi_mcfg_allocation *pci_mmcfg_config;
int pci_mmcfg_config_num;
-static int __init acpi_mcfg_oem_check(struct acpi_table_mcfg *mcfg)
+static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
+ struct acpi_mcfg_allocation *cfg)
{
+ int year;
+
+ if (cfg->address < 0xFFFFFFFF)
+ return 0;
+
if (!strcmp(mcfg->header.oem_id, "SGI"))
- acpi_mcfg_64bit_base_addr = TRUE;
+ return 0;
- return 0;
+ if (mcfg->header.revision >= 1) {
+ if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) &&
+ year >= 2010)
+ return 0;
+ }
+
+ printk(KERN_ERR PREFIX "MCFG region for %04x:%02x-%02x at %#llx "
+ "is above 4GB, ignored\n", cfg->pci_segment,
+ cfg->start_bus_number, cfg->end_bus_number, cfg->address);
+ return -EINVAL;
}
static int __init pci_parse_mcfg(struct acpi_table_header *header)
@@ -574,13 +588,8 @@ static int __init pci_parse_mcfg(struct acpi_table_header *header)
memcpy(pci_mmcfg_config, &mcfg[1], config_size);
- acpi_mcfg_oem_check(mcfg);
-
for (i = 0; i < pci_mmcfg_config_num; ++i) {
- if ((pci_mmcfg_config[i].address > 0xFFFFFFFF) &&
- !acpi_mcfg_64bit_base_addr) {
- printk(KERN_ERR PREFIX
- "MMCONFIG not in low 4GB of memory\n");
+ if (acpi_mcfg_check_entry(mcfg, &pci_mmcfg_config[i])) {
kfree(pci_mmcfg_config);
pci_mmcfg_config_num = 0;
return -ENODEV;
diff --git a/arch/x86/tools/Makefile b/arch/x86/tools/Makefile
new file mode 100644
index 000000000000..5e295d95dc25
--- /dev/null
+++ b/arch/x86/tools/Makefile
@@ -0,0 +1,15 @@
+PHONY += posttest
+quiet_cmd_posttest = TEST $@
+ cmd_posttest = $(OBJDUMP) -d -j .text $(objtree)/vmlinux | awk -f $(srctree)/arch/x86/tools/distill.awk | $(obj)/test_get_len $(CONFIG_64BIT)
+
+posttest: $(obj)/test_get_len vmlinux
+ $(call cmd,posttest)
+
+hostprogs-y := test_get_len
+
+# -I needed for generated C source and C source which in the kernel tree.
+HOSTCFLAGS_test_get_len.o := -Wall -I$(objtree)/arch/x86/lib/ -I$(srctree)/arch/x86/include/ -I$(srctree)/arch/x86/lib/ -I$(srctree)/include/
+
+# Dependencies are also needed.
+$(obj)/test_get_len.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c
+
diff --git a/arch/x86/tools/distill.awk b/arch/x86/tools/distill.awk
new file mode 100644
index 000000000000..d433619bb866
--- /dev/null
+++ b/arch/x86/tools/distill.awk
@@ -0,0 +1,42 @@
+#!/bin/awk -f
+# Usage: objdump -d a.out | awk -f distill.awk | ./test_get_len
+# Distills the disassembly as follows:
+# - Removes all lines except the disassembled instructions.
+# - For instructions that exceed 1 line (7 bytes), crams all the hex bytes
+# into a single line.
+# - Remove bad(or prefix only) instructions
+
+BEGIN {
+ prev_addr = ""
+ prev_hex = ""
+ prev_mnemonic = ""
+ bad_expr = "(\\(bad\\)|^rex|^.byte|^rep(z|nz)$|^lock$|^es$|^cs$|^ss$|^ds$|^fs$|^gs$|^data(16|32)$|^addr(16|32|64))"
+ fwait_expr = "^9b "
+ fwait_str="9b\tfwait"
+}
+
+/^ *[0-9a-f]+:/ {
+ if (split($0, field, "\t") < 3) {
+ # This is a continuation of the same insn.
+ prev_hex = prev_hex field[2]
+ } else {
+ # Skip bad instructions
+ if (match(prev_mnemonic, bad_expr))
+ prev_addr = ""
+ # Split fwait from other f* instructions
+ if (match(prev_hex, fwait_expr) && prev_mnemonic != "fwait") {
+ printf "%s\t%s\n", prev_addr, fwait_str
+ sub(fwait_expr, "", prev_hex)
+ }
+ if (prev_addr != "")
+ printf "%s\t%s\t%s\n", prev_addr, prev_hex, prev_mnemonic
+ prev_addr = field[1]
+ prev_hex = field[2]
+ prev_mnemonic = field[3]
+ }
+}
+
+END {
+ if (prev_addr != "")
+ printf "%s\t%s\t%s\n", prev_addr, prev_hex, prev_mnemonic
+}
diff --git a/arch/x86/tools/gen-insn-attr-x86.awk b/arch/x86/tools/gen-insn-attr-x86.awk
new file mode 100644
index 000000000000..19ba096b7dd1
--- /dev/null
+++ b/arch/x86/tools/gen-insn-attr-x86.awk
@@ -0,0 +1,334 @@
+#!/bin/awk -f
+# gen-insn-attr-x86.awk: Instruction attribute table generator
+# Written by Masami Hiramatsu <mhiramat@redhat.com>
+#
+# Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c
+
+# Awk implementation sanity check
+function check_awk_implement() {
+ if (!match("abc", "[[:lower:]]+"))
+ return "Your awk doesn't support charactor-class."
+ if (sprintf("%x", 0) != "0")
+ return "Your awk has a printf-format problem."
+ return ""
+}
+
+BEGIN {
+ # Implementation error checking
+ awkchecked = check_awk_implement()
+ if (awkchecked != "") {
+ print "Error: " awkchecked > "/dev/stderr"
+ print "Please try to use gawk." > "/dev/stderr"
+ exit 1
+ }
+
+ # Setup generating tables
+ print "/* x86 opcode map generated from x86-opcode-map.txt */"
+ print "/* Do not change this code. */"
+ ggid = 1
+ geid = 1
+
+ opnd_expr = "^[[:alpha:]]"
+ ext_expr = "^\\("
+ sep_expr = "^\\|$"
+ group_expr = "^Grp[[:alnum:]]+"
+
+ imm_expr = "^[IJAO][[:lower:]]"
+ imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
+ imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
+ imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)"
+ imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)"
+ imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)"
+ imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)"
+ imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
+ imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
+ imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)"
+ imm_flag["Ob"] = "INAT_MOFFSET"
+ imm_flag["Ov"] = "INAT_MOFFSET"
+
+ modrm_expr = "^([CDEGMNPQRSUVW][[:lower:]]+|NTA|T[012])"
+ force64_expr = "\\([df]64\\)"
+ rex_expr = "^REX(\\.[XRWB]+)*"
+ fpu_expr = "^ESC" # TODO
+
+ lprefix1_expr = "\\(66\\)"
+ delete lptable1
+ lprefix2_expr = "\\(F2\\)"
+ delete lptable2
+ lprefix3_expr = "\\(F3\\)"
+ delete lptable3
+ max_lprefix = 4
+
+ prefix_expr = "\\(Prefix\\)"
+ prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
+ prefix_num["REPNE"] = "INAT_PFX_REPNE"
+ prefix_num["REP/REPE"] = "INAT_PFX_REPE"
+ prefix_num["LOCK"] = "INAT_PFX_LOCK"
+ prefix_num["SEG=CS"] = "INAT_PFX_CS"
+ prefix_num["SEG=DS"] = "INAT_PFX_DS"
+ prefix_num["SEG=ES"] = "INAT_PFX_ES"
+ prefix_num["SEG=FS"] = "INAT_PFX_FS"
+ prefix_num["SEG=GS"] = "INAT_PFX_GS"
+ prefix_num["SEG=SS"] = "INAT_PFX_SS"
+ prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ"
+
+ delete table
+ delete etable
+ delete gtable
+ eid = -1
+ gid = -1
+}
+
+function semantic_error(msg) {
+ print "Semantic error at " NR ": " msg > "/dev/stderr"
+ exit 1
+}
+
+function debug(msg) {
+ print "DEBUG: " msg
+}
+
+function array_size(arr, i,c) {
+ c = 0
+ for (i in arr)
+ c++
+ return c
+}
+
+/^Table:/ {
+ print "/* " $0 " */"
+}
+
+/^Referrer:/ {
+ if (NF == 1) {
+ # primary opcode table
+ tname = "inat_primary_table"
+ eid = -1
+ } else {
+ # escape opcode table
+ ref = ""
+ for (i = 2; i <= NF; i++)
+ ref = ref $i
+ eid = escape[ref]
+ tname = sprintf("inat_escape_table_%d", eid)
+ }
+}
+
+/^GrpTable:/ {
+ print "/* " $0 " */"
+ if (!($2 in group))
+ semantic_error("No group: " $2 )
+ gid = group[$2]
+ tname = "inat_group_table_" gid
+}
+
+function print_table(tbl,name,fmt,n)
+{
+ print "const insn_attr_t " name " = {"
+ for (i = 0; i < n; i++) {
+ id = sprintf(fmt, i)
+ if (tbl[id])
+ print " [" id "] = " tbl[id] ","
+ }
+ print "};"
+}
+
+/^EndTable/ {
+ if (gid != -1) {
+ # print group tables
+ if (array_size(table) != 0) {
+ print_table(table, tname "[INAT_GROUP_TABLE_SIZE]",
+ "0x%x", 8)
+ gtable[gid,0] = tname
+ }
+ if (array_size(lptable1) != 0) {
+ print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]",
+ "0x%x", 8)
+ gtable[gid,1] = tname "_1"
+ }
+ if (array_size(lptable2) != 0) {
+ print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]",
+ "0x%x", 8)
+ gtable[gid,2] = tname "_2"
+ }
+ if (array_size(lptable3) != 0) {
+ print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]",
+ "0x%x", 8)
+ gtable[gid,3] = tname "_3"
+ }
+ } else {
+ # print primary/escaped tables
+ if (array_size(table) != 0) {
+ print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]",
+ "0x%02x", 256)
+ etable[eid,0] = tname
+ }
+ if (array_size(lptable1) != 0) {
+ print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]",
+ "0x%02x", 256)
+ etable[eid,1] = tname "_1"
+ }
+ if (array_size(lptable2) != 0) {
+ print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]",
+ "0x%02x", 256)
+ etable[eid,2] = tname "_2"
+ }
+ if (array_size(lptable3) != 0) {
+ print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]",
+ "0x%02x", 256)
+ etable[eid,3] = tname "_3"
+ }
+ }
+ print ""
+ delete table
+ delete lptable1
+ delete lptable2
+ delete lptable3
+ gid = -1
+ eid = -1
+}
+
+function add_flags(old,new) {
+ if (old && new)
+ return old " | " new
+ else if (old)
+ return old
+ else
+ return new
+}
+
+# convert operands to flags.
+function convert_operands(opnd, i,imm,mod)
+{
+ imm = null
+ mod = null
+ for (i in opnd) {
+ i = opnd[i]
+ if (match(i, imm_expr) == 1) {
+ if (!imm_flag[i])
+ semantic_error("Unknown imm opnd: " i)
+ if (imm) {
+ if (i != "Ib")
+ semantic_error("Second IMM error")
+ imm = add_flags(imm, "INAT_SCNDIMM")
+ } else
+ imm = imm_flag[i]
+ } else if (match(i, modrm_expr))
+ mod = "INAT_MODRM"
+ }
+ return add_flags(imm, mod)
+}
+
+/^[0-9a-f]+\:/ {
+ if (NR == 1)
+ next
+ # get index
+ idx = "0x" substr($1, 1, index($1,":") - 1)
+ if (idx in table)
+ semantic_error("Redefine " idx " in " tname)
+
+ # check if escaped opcode
+ if ("escape" == $2) {
+ if ($3 != "#")
+ semantic_error("No escaped name")
+ ref = ""
+ for (i = 4; i <= NF; i++)
+ ref = ref $i
+ if (ref in escape)
+ semantic_error("Redefine escape (" ref ")")
+ escape[ref] = geid
+ geid++
+ table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")"
+ next
+ }
+
+ variant = null
+ # converts
+ i = 2
+ while (i <= NF) {
+ opcode = $(i++)
+ delete opnds
+ ext = null
+ flags = null
+ opnd = null
+ # parse one opcode
+ if (match($i, opnd_expr)) {
+ opnd = $i
+ split($(i++), opnds, ",")
+ flags = convert_operands(opnds)
+ }
+ if (match($i, ext_expr))
+ ext = $(i++)
+ if (match($i, sep_expr))
+ i++
+ else if (i < NF)
+ semantic_error($i " is not a separator")
+
+ # check if group opcode
+ if (match(opcode, group_expr)) {
+ if (!(opcode in group)) {
+ group[opcode] = ggid
+ ggid++
+ }
+ flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")")
+ }
+ # check force(or default) 64bit
+ if (match(ext, force64_expr))
+ flags = add_flags(flags, "INAT_FORCE64")
+
+ # check REX prefix
+ if (match(opcode, rex_expr))
+ flags = add_flags(flags, "INAT_REXPFX")
+
+ # check coprocessor escape : TODO
+ if (match(opcode, fpu_expr))
+ flags = add_flags(flags, "INAT_MODRM")
+
+ # check prefixes
+ if (match(ext, prefix_expr)) {
+ if (!prefix_num[opcode])
+ semantic_error("Unknown prefix: " opcode)
+ flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")")
+ }
+ if (length(flags) == 0)
+ continue
+ # check if last prefix
+ if (match(ext, lprefix1_expr)) {
+ lptable1[idx] = add_flags(lptable1[idx],flags)
+ variant = "INAT_VARIANT"
+ } else if (match(ext, lprefix2_expr)) {
+ lptable2[idx] = add_flags(lptable2[idx],flags)
+ variant = "INAT_VARIANT"
+ } else if (match(ext, lprefix3_expr)) {
+ lptable3[idx] = add_flags(lptable3[idx],flags)
+ variant = "INAT_VARIANT"
+ } else {
+ table[idx] = add_flags(table[idx],flags)
+ }
+ }
+ if (variant)
+ table[idx] = add_flags(table[idx],variant)
+}
+
+END {
+ if (awkchecked != "")
+ exit 1
+ # print escape opcode map's array
+ print "/* Escape opcode map array */"
+ print "const insn_attr_t const *inat_escape_tables[INAT_ESC_MAX + 1]" \
+ "[INAT_LPREFIX_MAX + 1] = {"
+ for (i = 0; i < geid; i++)
+ for (j = 0; j < max_lprefix; j++)
+ if (etable[i,j])
+ print " ["i"]["j"] = "etable[i,j]","
+ print "};\n"
+ # print group opcode map's array
+ print "/* Group opcode map array */"
+ print "const insn_attr_t const *inat_group_tables[INAT_GRP_MAX + 1]"\
+ "[INAT_LPREFIX_MAX + 1] = {"
+ for (i = 0; i < ggid; i++)
+ for (j = 0; j < max_lprefix; j++)
+ if (gtable[i,j])
+ print " ["i"]["j"] = "gtable[i,j]","
+ print "};"
+}
diff --git a/arch/x86/tools/test_get_len.c b/arch/x86/tools/test_get_len.c
new file mode 100644
index 000000000000..376d33852191
--- /dev/null
+++ b/arch/x86/tools/test_get_len.c
@@ -0,0 +1,108 @@
+/*
+ * This 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, 2009
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#define unlikely(cond) (cond)
+
+#include <asm/insn.h>
+#include <inat.c>
+#include <insn.c>
+
+/*
+ * Test of instruction analysis in general and insn_get_length() in
+ * particular. See if insn_get_length() and the disassembler agree
+ * on the length of each instruction in an elf disassembly.
+ *
+ * Usage: objdump -d a.out | awk -f distill.awk | ./test_get_len
+ */
+
+const char *prog;
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: objdump -d a.out | awk -f distill.awk |"
+ " %s [y|n](64bit flag)\n", prog);
+ exit(1);
+}
+
+static void malformed_line(const char *line, int line_nr)
+{
+ fprintf(stderr, "%s: malformed line %d:\n%s", prog, line_nr, line);
+ exit(3);
+}
+
+#define BUFSIZE 256
+
+int main(int argc, char **argv)
+{
+ char line[BUFSIZE];
+ unsigned char insn_buf[16];
+ struct insn insn;
+ int insns = 0;
+ int x86_64 = 0;
+
+ prog = argv[0];
+ if (argc > 2)
+ usage();
+
+ if (argc == 2 && argv[1][0] == 'y')
+ x86_64 = 1;
+
+ while (fgets(line, BUFSIZE, stdin)) {
+ char copy[BUFSIZE], *s, *tab1, *tab2;
+ int nb = 0;
+ unsigned int b;
+
+ insns++;
+ memset(insn_buf, 0, 16);
+ strcpy(copy, line);
+ tab1 = strchr(copy, '\t');
+ if (!tab1)
+ malformed_line(line, insns);
+ s = tab1 + 1;
+ s += strspn(s, " ");
+ tab2 = strchr(s, '\t');
+ if (!tab2)
+ malformed_line(line, insns);
+ *tab2 = '\0'; /* Characters beyond tab2 aren't examined */
+ while (s < tab2) {
+ if (sscanf(s, "%x", &b) == 1) {
+ insn_buf[nb++] = (unsigned char) b;
+ s += 3;
+ } else
+ break;
+ }
+ /* Decode an instruction */
+ insn_init(&insn, insn_buf, x86_64);
+ insn_get_length(&insn);
+ if (insn.length != nb) {
+ fprintf(stderr, "Error: %s", line);
+ fprintf(stderr, "Error: objdump says %d bytes, but "
+ "insn_get_length() says %d (attr:%x)\n", nb,
+ insn.length, insn.attr);
+ exit(2);
+ }
+ }
+ fprintf(stderr, "Succeed: decoded and checked %d instructions\n",
+ insns);
+ return 0;
+}
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 3439616d69f1..fbc076d72cdc 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -28,6 +28,7 @@
#include <linux/highmem.h>
#include <linux/console.h>
+#include <xen/xen.h>
#include <xen/interface/xen.h>
#include <xen/interface/version.h>
#include <xen/interface/physdev.h>
diff --git a/arch/xtensa/include/asm/asm-offsets.h b/arch/xtensa/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/xtensa/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/xtensa/include/asm/socket.h b/arch/xtensa/include/asm/socket.h
index beb3a6bdb61d..cbdf2ffaacff 100644
--- a/arch/xtensa/include/asm/socket.h
+++ b/arch/xtensa/include/asm/socket.h
@@ -71,4 +71,6 @@
#define SO_PROTOCOL 38
#define SO_DOMAIN 39
+#define SO_RXQ_OVFL 40
+
#endif /* _XTENSA_SOCKET_H */
diff --git a/arch/xtensa/include/asm/unistd.h b/arch/xtensa/include/asm/unistd.h
index c092c8fbb2cf..4e55dc763021 100644
--- a/arch/xtensa/include/asm/unistd.h
+++ b/arch/xtensa/include/asm/unistd.h
@@ -681,8 +681,10 @@ __SYSCALL(304, sys_signalfd, 3)
__SYSCALL(305, sys_ni_syscall, 0)
#define __NR_eventfd 306
__SYSCALL(306, sys_eventfd, 1)
+#define __NR_recvmmsg 307
+__SYSCALL(307, sys_recvmmsg, 5)
-#define __NR_syscall_count 307
+#define __NR_syscall_count 308
/*
* sysxtensa syscall handler
diff --git a/block/Kconfig.iosched b/block/Kconfig.iosched
index 7e803fc88770..8bd105115a69 100644
--- a/block/Kconfig.iosched
+++ b/block/Kconfig.iosched
@@ -12,24 +12,14 @@ config IOSCHED_NOOP
that do their own scheduling and require only minimal assistance from
the kernel.
-config IOSCHED_AS
- tristate "Anticipatory I/O scheduler"
- default y
- ---help---
- The anticipatory I/O scheduler is generally a good choice for most
- environments, but is quite large and complex when compared to the
- deadline I/O scheduler, it can also be slower in some cases
- especially some database loads.
-
config IOSCHED_DEADLINE
tristate "Deadline I/O scheduler"
default y
---help---
- The deadline I/O scheduler is simple and compact, and is often as
- good as the anticipatory I/O scheduler, and in some database
- workloads, better. In the case of a single process performing I/O to
- a disk at any one time, its behaviour is almost identical to the
- anticipatory I/O scheduler and so is a good choice.
+ The deadline I/O scheduler is simple and compact. It will provide
+ CSCAN service with FIFO expiration of requests, switching to
+ a new point in the service tree and doing a batch of IO from there
+ in case of expiry.
config IOSCHED_CFQ
tristate "CFQ I/O scheduler"
@@ -37,7 +27,9 @@ config IOSCHED_CFQ
---help---
The CFQ I/O scheduler tries to distribute bandwidth equally
among all processes in the system. It should provide a fair
- working environment, suitable for desktop systems.
+ and low latency working environment, suitable for both desktop
+ and server systems.
+
This is the default I/O scheduler.
choice
@@ -47,9 +39,6 @@ choice
Select the I/O scheduler which will be used by default for all
block devices.
- config DEFAULT_AS
- bool "Anticipatory" if IOSCHED_AS=y
-
config DEFAULT_DEADLINE
bool "Deadline" if IOSCHED_DEADLINE=y
@@ -63,7 +52,6 @@ endchoice
config DEFAULT_IOSCHED
string
- default "anticipatory" if DEFAULT_AS
default "deadline" if DEFAULT_DEADLINE
default "cfq" if DEFAULT_CFQ
default "noop" if DEFAULT_NOOP
diff --git a/block/Makefile b/block/Makefile
index ba74ca6bfa14..7914108952f2 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -9,7 +9,6 @@ obj-$(CONFIG_BLOCK) := elevator.o blk-core.o blk-tag.o blk-sysfs.o \
obj-$(CONFIG_BLK_DEV_BSG) += bsg.o
obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o
-obj-$(CONFIG_IOSCHED_AS) += as-iosched.o
obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o
obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o
diff --git a/block/as-iosched.c b/block/as-iosched.c
deleted file mode 100644
index ce8ba57c6557..000000000000
--- a/block/as-iosched.c
+++ /dev/null
@@ -1,1520 +0,0 @@
-/*
- * Anticipatory & deadline i/o scheduler.
- *
- * Copyright (C) 2002 Jens Axboe <axboe@kernel.dk>
- * Nick Piggin <nickpiggin@yahoo.com.au>
- *
- */
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/blkdev.h>
-#include <linux/elevator.h>
-#include <linux/bio.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/compiler.h>
-#include <linux/rbtree.h>
-#include <linux/interrupt.h>
-
-/*
- * See Documentation/block/as-iosched.txt
- */
-
-/*
- * max time before a read is submitted.
- */
-#define default_read_expire (HZ / 8)
-
-/*
- * ditto for writes, these limits are not hard, even
- * if the disk is capable of satisfying them.
- */
-#define default_write_expire (HZ / 4)
-
-/*
- * read_batch_expire describes how long we will allow a stream of reads to
- * persist before looking to see whether it is time to switch over to writes.
- */
-#define default_read_batch_expire (HZ / 2)
-
-/*
- * write_batch_expire describes how long we want a stream of writes to run for.
- * This is not a hard limit, but a target we set for the auto-tuning thingy.
- * See, the problem is: we can send a lot of writes to disk cache / TCQ in
- * a short amount of time...
- */
-#define default_write_batch_expire (HZ / 8)
-
-/*
- * max time we may wait to anticipate a read (default around 6ms)
- */
-#define default_antic_expire ((HZ / 150) ? HZ / 150 : 1)
-
-/*
- * Keep track of up to 20ms thinktimes. We can go as big as we like here,
- * however huge values tend to interfere and not decay fast enough. A program
- * might be in a non-io phase of operation. Waiting on user input for example,
- * or doing a lengthy computation. A small penalty can be justified there, and
- * will still catch out those processes that constantly have large thinktimes.
- */
-#define MAX_THINKTIME (HZ/50UL)
-
-/* Bits in as_io_context.state */
-enum as_io_states {
- AS_TASK_RUNNING=0, /* Process has not exited */
- AS_TASK_IOSTARTED, /* Process has started some IO */
- AS_TASK_IORUNNING, /* Process has completed some IO */
-};
-
-enum anticipation_status {
- ANTIC_OFF=0, /* Not anticipating (normal operation) */
- ANTIC_WAIT_REQ, /* The last read has not yet completed */
- ANTIC_WAIT_NEXT, /* Currently anticipating a request vs
- last read (which has completed) */
- ANTIC_FINISHED, /* Anticipating but have found a candidate
- * or timed out */
-};
-
-struct as_data {
- /*
- * run time data
- */
-
- struct request_queue *q; /* the "owner" queue */
-
- /*
- * requests (as_rq s) are present on both sort_list and fifo_list
- */
- struct rb_root sort_list[2];
- struct list_head fifo_list[2];
-
- struct request *next_rq[2]; /* next in sort order */
- sector_t last_sector[2]; /* last SYNC & ASYNC sectors */
-
- unsigned long exit_prob; /* probability a task will exit while
- being waited on */
- unsigned long exit_no_coop; /* probablility an exited task will
- not be part of a later cooperating
- request */
- unsigned long new_ttime_total; /* mean thinktime on new proc */
- unsigned long new_ttime_mean;
- u64 new_seek_total; /* mean seek on new proc */
- sector_t new_seek_mean;
-
- unsigned long current_batch_expires;
- unsigned long last_check_fifo[2];
- int changed_batch; /* 1: waiting for old batch to end */
- int new_batch; /* 1: waiting on first read complete */
- int batch_data_dir; /* current batch SYNC / ASYNC */
- int write_batch_count; /* max # of reqs in a write batch */
- int current_write_count; /* how many requests left this batch */
- int write_batch_idled; /* has the write batch gone idle? */
-
- enum anticipation_status antic_status;
- unsigned long antic_start; /* jiffies: when it started */
- struct timer_list antic_timer; /* anticipatory scheduling timer */
- struct work_struct antic_work; /* Deferred unplugging */
- struct io_context *io_context; /* Identify the expected process */
- int ioc_finished; /* IO associated with io_context is finished */
- int nr_dispatched;
-
- /*
- * settings that change how the i/o scheduler behaves
- */
- unsigned long fifo_expire[2];
- unsigned long batch_expire[2];
- unsigned long antic_expire;
-};
-
-/*
- * per-request data.
- */
-enum arq_state {
- AS_RQ_NEW=0, /* New - not referenced and not on any lists */
- AS_RQ_QUEUED, /* In the request queue. It belongs to the
- scheduler */
- AS_RQ_DISPATCHED, /* On the dispatch list. It belongs to the
- driver now */
- AS_RQ_PRESCHED, /* Debug poisoning for requests being used */
- AS_RQ_REMOVED,
- AS_RQ_MERGED,
- AS_RQ_POSTSCHED, /* when they shouldn't be */
-};
-
-#define RQ_IOC(rq) ((struct io_context *) (rq)->elevator_private)
-#define RQ_STATE(rq) ((enum arq_state)(rq)->elevator_private2)
-#define RQ_SET_STATE(rq, state) ((rq)->elevator_private2 = (void *) state)
-
-static DEFINE_PER_CPU(unsigned long, as_ioc_count);
-static struct completion *ioc_gone;
-static DEFINE_SPINLOCK(ioc_gone_lock);
-
-static void as_move_to_dispatch(struct as_data *ad, struct request *rq);
-static void as_antic_stop(struct as_data *ad);
-
-/*
- * IO Context helper functions
- */
-
-/* Called to deallocate the as_io_context */
-static void free_as_io_context(struct as_io_context *aic)
-{
- kfree(aic);
- elv_ioc_count_dec(as_ioc_count);
- if (ioc_gone) {
- /*
- * AS scheduler is exiting, grab exit lock and check
- * the pending io context count. If it hits zero,
- * complete ioc_gone and set it back to NULL.
- */
- spin_lock(&ioc_gone_lock);
- if (ioc_gone && !elv_ioc_count_read(as_ioc_count)) {
- complete(ioc_gone);
- ioc_gone = NULL;
- }
- spin_unlock(&ioc_gone_lock);
- }
-}
-
-static void as_trim(struct io_context *ioc)
-{
- spin_lock_irq(&ioc->lock);
- if (ioc->aic)
- free_as_io_context(ioc->aic);
- ioc->aic = NULL;
- spin_unlock_irq(&ioc->lock);
-}
-
-/* Called when the task exits */
-static void exit_as_io_context(struct as_io_context *aic)
-{
- WARN_ON(!test_bit(AS_TASK_RUNNING, &aic->state));
- clear_bit(AS_TASK_RUNNING, &aic->state);
-}
-
-static struct as_io_context *alloc_as_io_context(void)
-{
- struct as_io_context *ret;
-
- ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
- if (ret) {
- ret->dtor = free_as_io_context;
- ret->exit = exit_as_io_context;
- ret->state = 1 << AS_TASK_RUNNING;
- atomic_set(&ret->nr_queued, 0);
- atomic_set(&ret->nr_dispatched, 0);
- spin_lock_init(&ret->lock);
- ret->ttime_total = 0;
- ret->ttime_samples = 0;
- ret->ttime_mean = 0;
- ret->seek_total = 0;
- ret->seek_samples = 0;
- ret->seek_mean = 0;
- elv_ioc_count_inc(as_ioc_count);
- }
-
- return ret;
-}
-
-/*
- * If the current task has no AS IO context then create one and initialise it.
- * Then take a ref on the task's io context and return it.
- */
-static struct io_context *as_get_io_context(int node)
-{
- struct io_context *ioc = get_io_context(GFP_ATOMIC, node);
- if (ioc && !ioc->aic) {
- ioc->aic = alloc_as_io_context();
- if (!ioc->aic) {
- put_io_context(ioc);
- ioc = NULL;
- }
- }
- return ioc;
-}
-
-static void as_put_io_context(struct request *rq)
-{
- struct as_io_context *aic;
-
- if (unlikely(!RQ_IOC(rq)))
- return;
-
- aic = RQ_IOC(rq)->aic;
-
- if (rq_is_sync(rq) && aic) {
- unsigned long flags;
-
- spin_lock_irqsave(&aic->lock, flags);
- set_bit(AS_TASK_IORUNNING, &aic->state);
- aic->last_end_request = jiffies;
- spin_unlock_irqrestore(&aic->lock, flags);
- }
-
- put_io_context(RQ_IOC(rq));
-}
-
-/*
- * rb tree support functions
- */
-#define RQ_RB_ROOT(ad, rq) (&(ad)->sort_list[rq_is_sync((rq))])
-
-static void as_add_rq_rb(struct as_data *ad, struct request *rq)
-{
- struct request *alias;
-
- while ((unlikely(alias = elv_rb_add(RQ_RB_ROOT(ad, rq), rq)))) {
- as_move_to_dispatch(ad, alias);
- as_antic_stop(ad);
- }
-}
-
-static inline void as_del_rq_rb(struct as_data *ad, struct request *rq)
-{
- elv_rb_del(RQ_RB_ROOT(ad, rq), rq);
-}
-
-/*
- * IO Scheduler proper
- */
-
-#define MAXBACK (1024 * 1024) /*
- * Maximum distance the disk will go backward
- * for a request.
- */
-
-#define BACK_PENALTY 2
-
-/*
- * as_choose_req selects the preferred one of two requests of the same data_dir
- * ignoring time - eg. timeouts, which is the job of as_dispatch_request
- */
-static struct request *
-as_choose_req(struct as_data *ad, struct request *rq1, struct request *rq2)
-{
- int data_dir;
- sector_t last, s1, s2, d1, d2;
- int r1_wrap=0, r2_wrap=0; /* requests are behind the disk head */
- const sector_t maxback = MAXBACK;
-
- if (rq1 == NULL || rq1 == rq2)
- return rq2;
- if (rq2 == NULL)
- return rq1;
-
- data_dir = rq_is_sync(rq1);
-
- last = ad->last_sector[data_dir];
- s1 = blk_rq_pos(rq1);
- s2 = blk_rq_pos(rq2);
-
- BUG_ON(data_dir != rq_is_sync(rq2));
-
- /*
- * Strict one way elevator _except_ in the case where we allow
- * short backward seeks which are biased as twice the cost of a
- * similar forward seek.
- */
- if (s1 >= last)
- d1 = s1 - last;
- else if (s1+maxback >= last)
- d1 = (last - s1)*BACK_PENALTY;
- else {
- r1_wrap = 1;
- d1 = 0; /* shut up, gcc */
- }
-
- if (s2 >= last)
- d2 = s2 - last;
- else if (s2+maxback >= last)
- d2 = (last - s2)*BACK_PENALTY;
- else {
- r2_wrap = 1;
- d2 = 0;
- }
-
- /* Found required data */
- if (!r1_wrap && r2_wrap)
- return rq1;
- else if (!r2_wrap && r1_wrap)
- return rq2;
- else if (r1_wrap && r2_wrap) {
- /* both behind the head */
- if (s1 <= s2)
- return rq1;
- else
- return rq2;
- }
-
- /* Both requests in front of the head */
- if (d1 < d2)
- return rq1;
- else if (d2 < d1)
- return rq2;
- else {
- if (s1 >= s2)
- return rq1;
- else
- return rq2;
- }
-}
-
-/*
- * as_find_next_rq finds the next request after @prev in elevator order.
- * this with as_choose_req form the basis for how the scheduler chooses
- * what request to process next. Anticipation works on top of this.
- */
-static struct request *
-as_find_next_rq(struct as_data *ad, struct request *last)
-{
- struct rb_node *rbnext = rb_next(&last->rb_node);
- struct rb_node *rbprev = rb_prev(&last->rb_node);
- struct request *next = NULL, *prev = NULL;
-
- BUG_ON(RB_EMPTY_NODE(&last->rb_node));
-
- if (rbprev)
- prev = rb_entry_rq(rbprev);
-
- if (rbnext)
- next = rb_entry_rq(rbnext);
- else {
- const int data_dir = rq_is_sync(last);
-
- rbnext = rb_first(&ad->sort_list[data_dir]);
- if (rbnext && rbnext != &last->rb_node)
- next = rb_entry_rq(rbnext);
- }
-
- return as_choose_req(ad, next, prev);
-}
-
-/*
- * anticipatory scheduling functions follow
- */
-
-/*
- * as_antic_expired tells us when we have anticipated too long.
- * The funny "absolute difference" math on the elapsed time is to handle
- * jiffy wraps, and disks which have been idle for 0x80000000 jiffies.
- */
-static int as_antic_expired(struct as_data *ad)
-{
- long delta_jif;
-
- delta_jif = jiffies - ad->antic_start;
- if (unlikely(delta_jif < 0))
- delta_jif = -delta_jif;
- if (delta_jif < ad->antic_expire)
- return 0;
-
- return 1;
-}
-
-/*
- * as_antic_waitnext starts anticipating that a nice request will soon be
- * submitted. See also as_antic_waitreq
- */
-static void as_antic_waitnext(struct as_data *ad)
-{
- unsigned long timeout;
-
- BUG_ON(ad->antic_status != ANTIC_OFF
- && ad->antic_status != ANTIC_WAIT_REQ);
-
- timeout = ad->antic_start + ad->antic_expire;
-
- mod_timer(&ad->antic_timer, timeout);
-
- ad->antic_status = ANTIC_WAIT_NEXT;
-}
-
-/*
- * as_antic_waitreq starts anticipating. We don't start timing the anticipation
- * until the request that we're anticipating on has finished. This means we
- * are timing from when the candidate process wakes up hopefully.
- */
-static void as_antic_waitreq(struct as_data *ad)
-{
- BUG_ON(ad->antic_status == ANTIC_FINISHED);
- if (ad->antic_status == ANTIC_OFF) {
- if (!ad->io_context || ad->ioc_finished)
- as_antic_waitnext(ad);
- else
- ad->antic_status = ANTIC_WAIT_REQ;
- }
-}
-
-/*
- * This is called directly by the functions in this file to stop anticipation.
- * We kill the timer and schedule a call to the request_fn asap.
- */
-static void as_antic_stop(struct as_data *ad)
-{
- int status = ad->antic_status;
-
- if (status == ANTIC_WAIT_REQ || status == ANTIC_WAIT_NEXT) {
- if (status == ANTIC_WAIT_NEXT)
- del_timer(&ad->antic_timer);
- ad->antic_status = ANTIC_FINISHED;
- /* see as_work_handler */
- kblockd_schedule_work(ad->q, &ad->antic_work);
- }
-}
-
-/*
- * as_antic_timeout is the timer function set by as_antic_waitnext.
- */
-static void as_antic_timeout(unsigned long data)
-{
- struct request_queue *q = (struct request_queue *)data;
- struct as_data *ad = q->elevator->elevator_data;
- unsigned long flags;
-
- spin_lock_irqsave(q->queue_lock, flags);
- if (ad->antic_status == ANTIC_WAIT_REQ
- || ad->antic_status == ANTIC_WAIT_NEXT) {
- struct as_io_context *aic;
- spin_lock(&ad->io_context->lock);
- aic = ad->io_context->aic;
-
- ad->antic_status = ANTIC_FINISHED;
- kblockd_schedule_work(q, &ad->antic_work);
-
- if (aic->ttime_samples == 0) {
- /* process anticipated on has exited or timed out*/
- ad->exit_prob = (7*ad->exit_prob + 256)/8;
- }
- if (!test_bit(AS_TASK_RUNNING, &aic->state)) {
- /* process not "saved" by a cooperating request */
- ad->exit_no_coop = (7*ad->exit_no_coop + 256)/8;
- }
- spin_unlock(&ad->io_context->lock);
- }
- spin_unlock_irqrestore(q->queue_lock, flags);
-}
-
-static void as_update_thinktime(struct as_data *ad, struct as_io_context *aic,
- unsigned long ttime)
-{
- /* fixed point: 1.0 == 1<<8 */
- if (aic->ttime_samples == 0) {
- ad->new_ttime_total = (7*ad->new_ttime_total + 256*ttime) / 8;
- ad->new_ttime_mean = ad->new_ttime_total / 256;
-
- ad->exit_prob = (7*ad->exit_prob)/8;
- }
- aic->ttime_samples = (7*aic->ttime_samples + 256) / 8;
- aic->ttime_total = (7*aic->ttime_total + 256*ttime) / 8;
- aic->ttime_mean = (aic->ttime_total + 128) / aic->ttime_samples;
-}
-
-static void as_update_seekdist(struct as_data *ad, struct as_io_context *aic,
- sector_t sdist)
-{
- u64 total;
-
- if (aic->seek_samples == 0) {
- ad->new_seek_total = (7*ad->new_seek_total + 256*(u64)sdist)/8;
- ad->new_seek_mean = ad->new_seek_total / 256;
- }
-
- /*
- * Don't allow the seek distance to get too large from the
- * odd fragment, pagein, etc
- */
- if (aic->seek_samples <= 60) /* second&third seek */
- sdist = min(sdist, (aic->seek_mean * 4) + 2*1024*1024);
- else
- sdist = min(sdist, (aic->seek_mean * 4) + 2*1024*64);
-
- aic->seek_samples = (7*aic->seek_samples + 256) / 8;
- aic->seek_total = (7*aic->seek_total + (u64)256*sdist) / 8;
- total = aic->seek_total + (aic->seek_samples/2);
- do_div(total, aic->seek_samples);
- aic->seek_mean = (sector_t)total;
-}
-
-/*
- * as_update_iohist keeps a decaying histogram of IO thinktimes, and
- * updates @aic->ttime_mean based on that. It is called when a new
- * request is queued.
- */
-static void as_update_iohist(struct as_data *ad, struct as_io_context *aic,
- struct request *rq)
-{
- int data_dir = rq_is_sync(rq);
- unsigned long thinktime = 0;
- sector_t seek_dist;
-
- if (aic == NULL)
- return;
-
- if (data_dir == BLK_RW_SYNC) {
- unsigned long in_flight = atomic_read(&aic->nr_queued)
- + atomic_read(&aic->nr_dispatched);
- spin_lock(&aic->lock);
- if (test_bit(AS_TASK_IORUNNING, &aic->state) ||
- test_bit(AS_TASK_IOSTARTED, &aic->state)) {
- /* Calculate read -> read thinktime */
- if (test_bit(AS_TASK_IORUNNING, &aic->state)
- && in_flight == 0) {
- thinktime = jiffies - aic->last_end_request;
- thinktime = min(thinktime, MAX_THINKTIME-1);
- }
- as_update_thinktime(ad, aic, thinktime);
-
- /* Calculate read -> read seek distance */
- if (aic->last_request_pos < blk_rq_pos(rq))
- seek_dist = blk_rq_pos(rq) -
- aic->last_request_pos;
- else
- seek_dist = aic->last_request_pos -
- blk_rq_pos(rq);
- as_update_seekdist(ad, aic, seek_dist);
- }
- aic->last_request_pos = blk_rq_pos(rq) + blk_rq_sectors(rq);
- set_bit(AS_TASK_IOSTARTED, &aic->state);
- spin_unlock(&aic->lock);
- }
-}
-
-/*
- * as_close_req decides if one request is considered "close" to the
- * previous one issued.
- */
-static int as_close_req(struct as_data *ad, struct as_io_context *aic,
- struct request *rq)
-{
- unsigned long delay; /* jiffies */
- sector_t last = ad->last_sector[ad->batch_data_dir];
- sector_t next = blk_rq_pos(rq);
- sector_t delta; /* acceptable close offset (in sectors) */
- sector_t s;
-
- if (ad->antic_status == ANTIC_OFF || !ad->ioc_finished)
- delay = 0;
- else
- delay = jiffies - ad->antic_start;
-
- if (delay == 0)
- delta = 8192;
- else if (delay <= (20 * HZ / 1000) && delay <= ad->antic_expire)
- delta = 8192 << delay;
- else
- return 1;
-
- if ((last <= next + (delta>>1)) && (next <= last + delta))
- return 1;
-
- if (last < next)
- s = next - last;
- else
- s = last - next;
-
- if (aic->seek_samples == 0) {
- /*
- * Process has just started IO. Use past statistics to
- * gauge success possibility
- */
- if (ad->new_seek_mean > s) {
- /* this request is better than what we're expecting */
- return 1;
- }
-
- } else {
- if (aic->seek_mean > s) {
- /* this request is better than what we're expecting */
- return 1;
- }
- }
-
- return 0;
-}
-
-/*
- * as_can_break_anticipation returns true if we have been anticipating this
- * request.
- *
- * It also returns true if the process against which we are anticipating
- * submits a write - that's presumably an fsync, O_SYNC write, etc. We want to
- * dispatch it ASAP, because we know that application will not be submitting
- * any new reads.
- *
- * If the task which has submitted the request has exited, break anticipation.
- *
- * If this task has queued some other IO, do not enter enticipation.
- */
-static int as_can_break_anticipation(struct as_data *ad, struct request *rq)
-{
- struct io_context *ioc;
- struct as_io_context *aic;
-
- ioc = ad->io_context;
- BUG_ON(!ioc);
- spin_lock(&ioc->lock);
-
- if (rq && ioc == RQ_IOC(rq)) {
- /* request from same process */
- spin_unlock(&ioc->lock);
- return 1;
- }
-
- if (ad->ioc_finished && as_antic_expired(ad)) {
- /*
- * In this situation status should really be FINISHED,
- * however the timer hasn't had the chance to run yet.
- */
- spin_unlock(&ioc->lock);
- return 1;
- }
-
- aic = ioc->aic;
- if (!aic) {
- spin_unlock(&ioc->lock);
- return 0;
- }
-
- if (atomic_read(&aic->nr_queued) > 0) {
- /* process has more requests queued */
- spin_unlock(&ioc->lock);
- return 1;
- }
-
- if (atomic_read(&aic->nr_dispatched) > 0) {
- /* process has more requests dispatched */
- spin_unlock(&ioc->lock);
- return 1;
- }
-
- if (rq && rq_is_sync(rq) && as_close_req(ad, aic, rq)) {
- /*
- * Found a close request that is not one of ours.
- *
- * This makes close requests from another process update
- * our IO history. Is generally useful when there are
- * two or more cooperating processes working in the same
- * area.
- */
- if (!test_bit(AS_TASK_RUNNING, &aic->state)) {
- if (aic->ttime_samples == 0)
- ad->exit_prob = (7*ad->exit_prob + 256)/8;
-
- ad->exit_no_coop = (7*ad->exit_no_coop)/8;
- }
-
- as_update_iohist(ad, aic, rq);
- spin_unlock(&ioc->lock);
- return 1;
- }
-
- if (!test_bit(AS_TASK_RUNNING, &aic->state)) {
- /* process anticipated on has exited */
- if (aic->ttime_samples == 0)
- ad->exit_prob = (7*ad->exit_prob + 256)/8;
-
- if (ad->exit_no_coop > 128) {
- spin_unlock(&ioc->lock);
- return 1;
- }
- }
-
- if (aic->ttime_samples == 0) {
- if (ad->new_ttime_mean > ad->antic_expire) {
- spin_unlock(&ioc->lock);
- return 1;
- }
- if (ad->exit_prob * ad->exit_no_coop > 128*256) {
- spin_unlock(&ioc->lock);
- return 1;
- }
- } else if (aic->ttime_mean > ad->antic_expire) {
- /* the process thinks too much between requests */
- spin_unlock(&ioc->lock);
- return 1;
- }
- spin_unlock(&ioc->lock);
- return 0;
-}
-
-/*
- * as_can_anticipate indicates whether we should either run rq
- * or keep anticipating a better request.
- */
-static int as_can_anticipate(struct as_data *ad, struct request *rq)
-{
-#if 0 /* disable for now, we need to check tag level as well */
- /*
- * SSD device without seek penalty, disable idling
- */
- if (blk_queue_nonrot(ad->q)) axman
- return 0;
-#endif
-
- if (!ad->io_context)
- /*
- * Last request submitted was a write
- */
- return 0;
-
- if (ad->antic_status == ANTIC_FINISHED)
- /*
- * Don't restart if we have just finished. Run the next request
- */
- return 0;
-
- if (as_can_break_anticipation(ad, rq))
- /*
- * This request is a good candidate. Don't keep anticipating,
- * run it.
- */
- return 0;
-
- /*
- * OK from here, we haven't finished, and don't have a decent request!
- * Status is either ANTIC_OFF so start waiting,
- * ANTIC_WAIT_REQ so continue waiting for request to finish
- * or ANTIC_WAIT_NEXT so continue waiting for an acceptable request.
- */
-
- return 1;
-}
-
-/*
- * as_update_rq must be called whenever a request (rq) is added to
- * the sort_list. This function keeps caches up to date, and checks if the
- * request might be one we are "anticipating"
- */
-static void as_update_rq(struct as_data *ad, struct request *rq)
-{
- const int data_dir = rq_is_sync(rq);
-
- /* keep the next_rq cache up to date */
- ad->next_rq[data_dir] = as_choose_req(ad, rq, ad->next_rq[data_dir]);
-
- /*
- * have we been anticipating this request?
- * or does it come from the same process as the one we are anticipating
- * for?
- */
- if (ad->antic_status == ANTIC_WAIT_REQ
- || ad->antic_status == ANTIC_WAIT_NEXT) {
- if (as_can_break_anticipation(ad, rq))
- as_antic_stop(ad);
- }
-}
-
-/*
- * Gathers timings and resizes the write batch automatically
- */
-static void update_write_batch(struct as_data *ad)
-{
- unsigned long batch = ad->batch_expire[BLK_RW_ASYNC];
- long write_time;
-
- write_time = (jiffies - ad->current_batch_expires) + batch;
- if (write_time < 0)
- write_time = 0;
-
- if (write_time > batch && !ad->write_batch_idled) {
- if (write_time > batch * 3)
- ad->write_batch_count /= 2;
- else
- ad->write_batch_count--;
- } else if (write_time < batch && ad->current_write_count == 0) {
- if (batch > write_time * 3)
- ad->write_batch_count *= 2;
- else
- ad->write_batch_count++;
- }
-
- if (ad->write_batch_count < 1)
- ad->write_batch_count = 1;
-}
-
-/*
- * as_completed_request is to be called when a request has completed and
- * returned something to the requesting process, be it an error or data.
- */
-static void as_completed_request(struct request_queue *q, struct request *rq)
-{
- struct as_data *ad = q->elevator->elevator_data;
-
- WARN_ON(!list_empty(&rq->queuelist));
-
- if (RQ_STATE(rq) != AS_RQ_REMOVED) {
- WARN(1, "rq->state %d\n", RQ_STATE(rq));
- goto out;
- }
-
- if (ad->changed_batch && ad->nr_dispatched == 1) {
- ad->current_batch_expires = jiffies +
- ad->batch_expire[ad->batch_data_dir];
- kblockd_schedule_work(q, &ad->antic_work);
- ad->changed_batch = 0;
-
- if (ad->batch_data_dir == BLK_RW_SYNC)
- ad->new_batch = 1;
- }
- WARN_ON(ad->nr_dispatched == 0);
- ad->nr_dispatched--;
-
- /*
- * Start counting the batch from when a request of that direction is
- * actually serviced. This should help devices with big TCQ windows
- * and writeback caches
- */
- if (ad->new_batch && ad->batch_data_dir == rq_is_sync(rq)) {
- update_write_batch(ad);
- ad->current_batch_expires = jiffies +
- ad->batch_expire[BLK_RW_SYNC];
- ad->new_batch = 0;
- }
-
- if (ad->io_context == RQ_IOC(rq) && ad->io_context) {
- ad->antic_start = jiffies;
- ad->ioc_finished = 1;
- if (ad->antic_status == ANTIC_WAIT_REQ) {
- /*
- * We were waiting on this request, now anticipate
- * the next one
- */
- as_antic_waitnext(ad);
- }
- }
-
- as_put_io_context(rq);
-out:
- RQ_SET_STATE(rq, AS_RQ_POSTSCHED);
-}
-
-/*
- * as_remove_queued_request removes a request from the pre dispatch queue
- * without updating refcounts. It is expected the caller will drop the
- * reference unless it replaces the request at somepart of the elevator
- * (ie. the dispatch queue)
- */
-static void as_remove_queued_request(struct request_queue *q,
- struct request *rq)
-{
- const int data_dir = rq_is_sync(rq);
- struct as_data *ad = q->elevator->elevator_data;
- struct io_context *ioc;
-
- WARN_ON(RQ_STATE(rq) != AS_RQ_QUEUED);
-
- ioc = RQ_IOC(rq);
- if (ioc && ioc->aic) {
- BUG_ON(!atomic_read(&ioc->aic->nr_queued));
- atomic_dec(&ioc->aic->nr_queued);
- }
-
- /*
- * Update the "next_rq" cache if we are about to remove its
- * entry
- */
- if (ad->next_rq[data_dir] == rq)
- ad->next_rq[data_dir] = as_find_next_rq(ad, rq);
-
- rq_fifo_clear(rq);
- as_del_rq_rb(ad, rq);
-}
-
-/*
- * as_fifo_expired returns 0 if there are no expired requests on the fifo,
- * 1 otherwise. It is ratelimited so that we only perform the check once per
- * `fifo_expire' interval. Otherwise a large number of expired requests
- * would create a hopeless seekstorm.
- *
- * See as_antic_expired comment.
- */
-static int as_fifo_expired(struct as_data *ad, int adir)
-{
- struct request *rq;
- long delta_jif;
-
- delta_jif = jiffies - ad->last_check_fifo[adir];
- if (unlikely(delta_jif < 0))
- delta_jif = -delta_jif;
- if (delta_jif < ad->fifo_expire[adir])
- return 0;
-
- ad->last_check_fifo[adir] = jiffies;
-
- if (list_empty(&ad->fifo_list[adir]))
- return 0;
-
- rq = rq_entry_fifo(ad->fifo_list[adir].next);
-
- return time_after(jiffies, rq_fifo_time(rq));
-}
-
-/*
- * as_batch_expired returns true if the current batch has expired. A batch
- * is a set of reads or a set of writes.
- */
-static inline int as_batch_expired(struct as_data *ad)
-{
- if (ad->changed_batch || ad->new_batch)
- return 0;
-
- if (ad->batch_data_dir == BLK_RW_SYNC)
- /* TODO! add a check so a complete fifo gets written? */
- return time_after(jiffies, ad->current_batch_expires);
-
- return time_after(jiffies, ad->current_batch_expires)
- || ad->current_write_count == 0;
-}
-
-/*
- * move an entry to dispatch queue
- */
-static void as_move_to_dispatch(struct as_data *ad, struct request *rq)
-{
- const int data_dir = rq_is_sync(rq);
-
- BUG_ON(RB_EMPTY_NODE(&rq->rb_node));
-
- as_antic_stop(ad);
- ad->antic_status = ANTIC_OFF;
-
- /*
- * This has to be set in order to be correctly updated by
- * as_find_next_rq
- */
- ad->last_sector[data_dir] = blk_rq_pos(rq) + blk_rq_sectors(rq);
-
- if (data_dir == BLK_RW_SYNC) {
- struct io_context *ioc = RQ_IOC(rq);
- /* In case we have to anticipate after this */
- copy_io_context(&ad->io_context, &ioc);
- } else {
- if (ad->io_context) {
- put_io_context(ad->io_context);
- ad->io_context = NULL;
- }
-
- if (ad->current_write_count != 0)
- ad->current_write_count--;
- }
- ad->ioc_finished = 0;
-
- ad->next_rq[data_dir] = as_find_next_rq(ad, rq);
-
- /*
- * take it off the sort and fifo list, add to dispatch queue
- */
- as_remove_queued_request(ad->q, rq);
- WARN_ON(RQ_STATE(rq) != AS_RQ_QUEUED);
-
- elv_dispatch_sort(ad->q, rq);
-
- RQ_SET_STATE(rq, AS_RQ_DISPATCHED);
- if (RQ_IOC(rq) && RQ_IOC(rq)->aic)
- atomic_inc(&RQ_IOC(rq)->aic->nr_dispatched);
- ad->nr_dispatched++;
-}
-
-/*
- * as_dispatch_request selects the best request according to
- * read/write expire, batch expire, etc, and moves it to the dispatch
- * queue. Returns 1 if a request was found, 0 otherwise.
- */
-static int as_dispatch_request(struct request_queue *q, int force)
-{
- struct as_data *ad = q->elevator->elevator_data;
- const int reads = !list_empty(&ad->fifo_list[BLK_RW_SYNC]);
- const int writes = !list_empty(&ad->fifo_list[BLK_RW_ASYNC]);
- struct request *rq;
-
- if (unlikely(force)) {
- /*
- * Forced dispatch, accounting is useless. Reset
- * accounting states and dump fifo_lists. Note that
- * batch_data_dir is reset to BLK_RW_SYNC to avoid
- * screwing write batch accounting as write batch
- * accounting occurs on W->R transition.
- */
- int dispatched = 0;
-
- ad->batch_data_dir = BLK_RW_SYNC;
- ad->changed_batch = 0;
- ad->new_batch = 0;
-
- while (ad->next_rq[BLK_RW_SYNC]) {
- as_move_to_dispatch(ad, ad->next_rq[BLK_RW_SYNC]);
- dispatched++;
- }
- ad->last_check_fifo[BLK_RW_SYNC] = jiffies;
-
- while (ad->next_rq[BLK_RW_ASYNC]) {
- as_move_to_dispatch(ad, ad->next_rq[BLK_RW_ASYNC]);
- dispatched++;
- }
- ad->last_check_fifo[BLK_RW_ASYNC] = jiffies;
-
- return dispatched;
- }
-
- /* Signal that the write batch was uncontended, so we can't time it */
- if (ad->batch_data_dir == BLK_RW_ASYNC && !reads) {
- if (ad->current_write_count == 0 || !writes)
- ad->write_batch_idled = 1;
- }
-
- if (!(reads || writes)
- || ad->antic_status == ANTIC_WAIT_REQ
- || ad->antic_status == ANTIC_WAIT_NEXT
- || ad->changed_batch)
- return 0;
-
- if (!(reads && writes && as_batch_expired(ad))) {
- /*
- * batch is still running or no reads or no writes
- */
- rq = ad->next_rq[ad->batch_data_dir];
-
- if (ad->batch_data_dir == BLK_RW_SYNC && ad->antic_expire) {
- if (as_fifo_expired(ad, BLK_RW_SYNC))
- goto fifo_expired;
-
- if (as_can_anticipate(ad, rq)) {
- as_antic_waitreq(ad);
- return 0;
- }
- }
-
- if (rq) {
- /* we have a "next request" */
- if (reads && !writes)
- ad->current_batch_expires =
- jiffies + ad->batch_expire[BLK_RW_SYNC];
- goto dispatch_request;
- }
- }
-
- /*
- * at this point we are not running a batch. select the appropriate
- * data direction (read / write)
- */
-
- if (reads) {
- BUG_ON(RB_EMPTY_ROOT(&ad->sort_list[BLK_RW_SYNC]));
-
- if (writes && ad->batch_data_dir == BLK_RW_SYNC)
- /*
- * Last batch was a read, switch to writes
- */
- goto dispatch_writes;
-
- if (ad->batch_data_dir == BLK_RW_ASYNC) {
- WARN_ON(ad->new_batch);
- ad->changed_batch = 1;
- }
- ad->batch_data_dir = BLK_RW_SYNC;
- rq = rq_entry_fifo(ad->fifo_list[BLK_RW_SYNC].next);
- ad->last_check_fifo[ad->batch_data_dir] = jiffies;
- goto dispatch_request;
- }
-
- /*
- * the last batch was a read
- */
-
- if (writes) {
-dispatch_writes:
- BUG_ON(RB_EMPTY_ROOT(&ad->sort_list[BLK_RW_ASYNC]));
-
- if (ad->batch_data_dir == BLK_RW_SYNC) {
- ad->changed_batch = 1;
-
- /*
- * new_batch might be 1 when the queue runs out of
- * reads. A subsequent submission of a write might
- * cause a change of batch before the read is finished.
- */
- ad->new_batch = 0;
- }
- ad->batch_data_dir = BLK_RW_ASYNC;
- ad->current_write_count = ad->write_batch_count;
- ad->write_batch_idled = 0;
- rq = rq_entry_fifo(ad->fifo_list[BLK_RW_ASYNC].next);
- ad->last_check_fifo[BLK_RW_ASYNC] = jiffies;
- goto dispatch_request;
- }
-
- BUG();
- return 0;
-
-dispatch_request:
- /*
- * If a request has expired, service it.
- */
-
- if (as_fifo_expired(ad, ad->batch_data_dir)) {
-fifo_expired:
- rq = rq_entry_fifo(ad->fifo_list[ad->batch_data_dir].next);
- }
-
- if (ad->changed_batch) {
- WARN_ON(ad->new_batch);
-
- if (ad->nr_dispatched)
- return 0;
-
- if (ad->batch_data_dir == BLK_RW_ASYNC)
- ad->current_batch_expires = jiffies +
- ad->batch_expire[BLK_RW_ASYNC];
- else
- ad->new_batch = 1;
-
- ad->changed_batch = 0;
- }
-
- /*
- * rq is the selected appropriate request.
- */
- as_move_to_dispatch(ad, rq);
-
- return 1;
-}
-
-/*
- * add rq to rbtree and fifo
- */
-static void as_add_request(struct request_queue *q, struct request *rq)
-{
- struct as_data *ad = q->elevator->elevator_data;
- int data_dir;
-
- RQ_SET_STATE(rq, AS_RQ_NEW);
-
- data_dir = rq_is_sync(rq);
-
- rq->elevator_private = as_get_io_context(q->node);
-
- if (RQ_IOC(rq)) {
- as_update_iohist(ad, RQ_IOC(rq)->aic, rq);
- atomic_inc(&RQ_IOC(rq)->aic->nr_queued);
- }
-
- as_add_rq_rb(ad, rq);
-
- /*
- * set expire time and add to fifo list
- */
- rq_set_fifo_time(rq, jiffies + ad->fifo_expire[data_dir]);
- list_add_tail(&rq->queuelist, &ad->fifo_list[data_dir]);
-
- as_update_rq(ad, rq); /* keep state machine up to date */
- RQ_SET_STATE(rq, AS_RQ_QUEUED);
-}
-
-static void as_activate_request(struct request_queue *q, struct request *rq)
-{
- WARN_ON(RQ_STATE(rq) != AS_RQ_DISPATCHED);
- RQ_SET_STATE(rq, AS_RQ_REMOVED);
- if (RQ_IOC(rq) && RQ_IOC(rq)->aic)
- atomic_dec(&RQ_IOC(rq)->aic->nr_dispatched);
-}
-
-static void as_deactivate_request(struct request_queue *q, struct request *rq)
-{
- WARN_ON(RQ_STATE(rq) != AS_RQ_REMOVED);
- RQ_SET_STATE(rq, AS_RQ_DISPATCHED);
- if (RQ_IOC(rq) && RQ_IOC(rq)->aic)
- atomic_inc(&RQ_IOC(rq)->aic->nr_dispatched);
-}
-
-/*
- * as_queue_empty tells us if there are requests left in the device. It may
- * not be the case that a driver can get the next request even if the queue
- * is not empty - it is used in the block layer to check for plugging and
- * merging opportunities
- */
-static int as_queue_empty(struct request_queue *q)
-{
- struct as_data *ad = q->elevator->elevator_data;
-
- return list_empty(&ad->fifo_list[BLK_RW_ASYNC])
- && list_empty(&ad->fifo_list[BLK_RW_SYNC]);
-}
-
-static int
-as_merge(struct request_queue *q, struct request **req, struct bio *bio)
-{
- struct as_data *ad = q->elevator->elevator_data;
- sector_t rb_key = bio->bi_sector + bio_sectors(bio);
- struct request *__rq;
-
- /*
- * check for front merge
- */
- __rq = elv_rb_find(&ad->sort_list[bio_data_dir(bio)], rb_key);
- if (__rq && elv_rq_merge_ok(__rq, bio)) {
- *req = __rq;
- return ELEVATOR_FRONT_MERGE;
- }
-
- return ELEVATOR_NO_MERGE;
-}
-
-static void as_merged_request(struct request_queue *q, struct request *req,
- int type)
-{
- struct as_data *ad = q->elevator->elevator_data;
-
- /*
- * if the merge was a front merge, we need to reposition request
- */
- if (type == ELEVATOR_FRONT_MERGE) {
- as_del_rq_rb(ad, req);
- as_add_rq_rb(ad, req);
- /*
- * Note! At this stage of this and the next function, our next
- * request may not be optimal - eg the request may have "grown"
- * behind the disk head. We currently don't bother adjusting.
- */
- }
-}
-
-static void as_merged_requests(struct request_queue *q, struct request *req,
- struct request *next)
-{
- /*
- * if next expires before rq, assign its expire time to arq
- * and move into next position (next will be deleted) in fifo
- */
- if (!list_empty(&req->queuelist) && !list_empty(&next->queuelist)) {
- if (time_before(rq_fifo_time(next), rq_fifo_time(req))) {
- list_move(&req->queuelist, &next->queuelist);
- rq_set_fifo_time(req, rq_fifo_time(next));
- }
- }
-
- /*
- * kill knowledge of next, this one is a goner
- */
- as_remove_queued_request(q, next);
- as_put_io_context(next);
-
- RQ_SET_STATE(next, AS_RQ_MERGED);
-}
-
-/*
- * This is executed in a "deferred" process context, by kblockd. It calls the
- * driver's request_fn so the driver can submit that request.
- *
- * IMPORTANT! This guy will reenter the elevator, so set up all queue global
- * state before calling, and don't rely on any state over calls.
- *
- * FIXME! dispatch queue is not a queue at all!
- */
-static void as_work_handler(struct work_struct *work)
-{
- struct as_data *ad = container_of(work, struct as_data, antic_work);
-
- blk_run_queue(ad->q);
-}
-
-static int as_may_queue(struct request_queue *q, int rw)
-{
- int ret = ELV_MQUEUE_MAY;
- struct as_data *ad = q->elevator->elevator_data;
- struct io_context *ioc;
- if (ad->antic_status == ANTIC_WAIT_REQ ||
- ad->antic_status == ANTIC_WAIT_NEXT) {
- ioc = as_get_io_context(q->node);
- if (ad->io_context == ioc)
- ret = ELV_MQUEUE_MUST;
- put_io_context(ioc);
- }
-
- return ret;
-}
-
-static void as_exit_queue(struct elevator_queue *e)
-{
- struct as_data *ad = e->elevator_data;
-
- del_timer_sync(&ad->antic_timer);
- cancel_work_sync(&ad->antic_work);
-
- BUG_ON(!list_empty(&ad->fifo_list[BLK_RW_SYNC]));
- BUG_ON(!list_empty(&ad->fifo_list[BLK_RW_ASYNC]));
-
- put_io_context(ad->io_context);
- kfree(ad);
-}
-
-/*
- * initialize elevator private data (as_data).
- */
-static void *as_init_queue(struct request_queue *q)
-{
- struct as_data *ad;
-
- ad = kmalloc_node(sizeof(*ad), GFP_KERNEL | __GFP_ZERO, q->node);
- if (!ad)
- return NULL;
-
- ad->q = q; /* Identify what queue the data belongs to */
-
- /* anticipatory scheduling helpers */
- ad->antic_timer.function = as_antic_timeout;
- ad->antic_timer.data = (unsigned long)q;
- init_timer(&ad->antic_timer);
- INIT_WORK(&ad->antic_work, as_work_handler);
-
- INIT_LIST_HEAD(&ad->fifo_list[BLK_RW_SYNC]);
- INIT_LIST_HEAD(&ad->fifo_list[BLK_RW_ASYNC]);
- ad->sort_list[BLK_RW_SYNC] = RB_ROOT;
- ad->sort_list[BLK_RW_ASYNC] = RB_ROOT;
- ad->fifo_expire[BLK_RW_SYNC] = default_read_expire;
- ad->fifo_expire[BLK_RW_ASYNC] = default_write_expire;
- ad->antic_expire = default_antic_expire;
- ad->batch_expire[BLK_RW_SYNC] = default_read_batch_expire;
- ad->batch_expire[BLK_RW_ASYNC] = default_write_batch_expire;
-
- ad->current_batch_expires = jiffies + ad->batch_expire[BLK_RW_SYNC];
- ad->write_batch_count = ad->batch_expire[BLK_RW_ASYNC] / 10;
- if (ad->write_batch_count < 2)
- ad->write_batch_count = 2;
-
- return ad;
-}
-
-/*
- * sysfs parts below
- */
-
-static ssize_t
-as_var_show(unsigned int var, char *page)
-{
- return sprintf(page, "%d\n", var);
-}
-
-static ssize_t
-as_var_store(unsigned long *var, const char *page, size_t count)
-{
- char *p = (char *) page;
-
- *var = simple_strtoul(p, &p, 10);
- return count;
-}
-
-static ssize_t est_time_show(struct elevator_queue *e, char *page)
-{
- struct as_data *ad = e->elevator_data;
- int pos = 0;
-
- pos += sprintf(page+pos, "%lu %% exit probability\n",
- 100*ad->exit_prob/256);
- pos += sprintf(page+pos, "%lu %% probability of exiting without a "
- "cooperating process submitting IO\n",
- 100*ad->exit_no_coop/256);
- pos += sprintf(page+pos, "%lu ms new thinktime\n", ad->new_ttime_mean);
- pos += sprintf(page+pos, "%llu sectors new seek distance\n",
- (unsigned long long)ad->new_seek_mean);
-
- return pos;
-}
-
-#define SHOW_FUNCTION(__FUNC, __VAR) \
-static ssize_t __FUNC(struct elevator_queue *e, char *page) \
-{ \
- struct as_data *ad = e->elevator_data; \
- return as_var_show(jiffies_to_msecs((__VAR)), (page)); \
-}
-SHOW_FUNCTION(as_read_expire_show, ad->fifo_expire[BLK_RW_SYNC]);
-SHOW_FUNCTION(as_write_expire_show, ad->fifo_expire[BLK_RW_ASYNC]);
-SHOW_FUNCTION(as_antic_expire_show, ad->antic_expire);
-SHOW_FUNCTION(as_read_batch_expire_show, ad->batch_expire[BLK_RW_SYNC]);
-SHOW_FUNCTION(as_write_batch_expire_show, ad->batch_expire[BLK_RW_ASYNC]);
-#undef SHOW_FUNCTION
-
-#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX) \
-static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count) \
-{ \
- struct as_data *ad = e->elevator_data; \
- int ret = as_var_store(__PTR, (page), count); \
- if (*(__PTR) < (MIN)) \
- *(__PTR) = (MIN); \
- else if (*(__PTR) > (MAX)) \
- *(__PTR) = (MAX); \
- *(__PTR) = msecs_to_jiffies(*(__PTR)); \
- return ret; \
-}
-STORE_FUNCTION(as_read_expire_store, &ad->fifo_expire[BLK_RW_SYNC], 0, INT_MAX);
-STORE_FUNCTION(as_write_expire_store,
- &ad->fifo_expire[BLK_RW_ASYNC], 0, INT_MAX);
-STORE_FUNCTION(as_antic_expire_store, &ad->antic_expire, 0, INT_MAX);
-STORE_FUNCTION(as_read_batch_expire_store,
- &ad->batch_expire[BLK_RW_SYNC], 0, INT_MAX);
-STORE_FUNCTION(as_write_batch_expire_store,
- &ad->batch_expire[BLK_RW_ASYNC], 0, INT_MAX);
-#undef STORE_FUNCTION
-
-#define AS_ATTR(name) \
- __ATTR(name, S_IRUGO|S_IWUSR, as_##name##_show, as_##name##_store)
-
-static struct elv_fs_entry as_attrs[] = {
- __ATTR_RO(est_time),
- AS_ATTR(read_expire),
- AS_ATTR(write_expire),
- AS_ATTR(antic_expire),
- AS_ATTR(read_batch_expire),
- AS_ATTR(write_batch_expire),
- __ATTR_NULL
-};
-
-static struct elevator_type iosched_as = {
- .ops = {
- .elevator_merge_fn = as_merge,
- .elevator_merged_fn = as_merged_request,
- .elevator_merge_req_fn = as_merged_requests,
- .elevator_dispatch_fn = as_dispatch_request,
- .elevator_add_req_fn = as_add_request,
- .elevator_activate_req_fn = as_activate_request,
- .elevator_deactivate_req_fn = as_deactivate_request,
- .elevator_queue_empty_fn = as_queue_empty,
- .elevator_completed_req_fn = as_completed_request,
- .elevator_former_req_fn = elv_rb_former_request,
- .elevator_latter_req_fn = elv_rb_latter_request,
- .elevator_may_queue_fn = as_may_queue,
- .elevator_init_fn = as_init_queue,
- .elevator_exit_fn = as_exit_queue,
- .trim = as_trim,
- },
-
- .elevator_attrs = as_attrs,
- .elevator_name = "anticipatory",
- .elevator_owner = THIS_MODULE,
-};
-
-static int __init as_init(void)
-{
- elv_register(&iosched_as);
-
- return 0;
-}
-
-static void __exit as_exit(void)
-{
- DECLARE_COMPLETION_ONSTACK(all_gone);
- elv_unregister(&iosched_as);
- ioc_gone = &all_gone;
- /* ioc_gone's update must be visible before reading ioc_count */
- smp_wmb();
- if (elv_ioc_count_read(as_ioc_count))
- wait_for_completion(&all_gone);
- synchronize_rcu();
-}
-
-module_init(as_init);
-module_exit(as_exit);
-
-MODULE_AUTHOR("Nick Piggin");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("anticipatory IO scheduler");
diff --git a/block/elevator.c b/block/elevator.c
index a847046c6e53..9ad5ccc4c5ee 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -154,10 +154,7 @@ static struct elevator_type *elevator_get(const char *name)
spin_unlock(&elv_list_lock);
- if (!strcmp(name, "anticipatory"))
- sprintf(elv, "as-iosched");
- else
- sprintf(elv, "%s-iosched", name);
+ sprintf(elv, "%s-iosched", name);
request_module("%s", elv);
spin_lock(&elv_list_lock);
@@ -193,10 +190,7 @@ static int __init elevator_setup(char *str)
* Be backwards-compatible with previous kernels, so users
* won't get the wrong elevator.
*/
- if (!strcmp(str, "as"))
- strcpy(chosen_elevator, "anticipatory");
- else
- strncpy(chosen_elevator, str, sizeof(chosen_elevator) - 1);
+ strncpy(chosen_elevator, str, sizeof(chosen_elevator) - 1);
return 1;
}
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 26b5dd0cb564..81c185a6971f 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -440,6 +440,15 @@ config CRYPTO_WP512
See also:
<http://planeta.terra.com.br/informatica/paulobarreto/WhirlpoolPage.html>
+config CRYPTO_GHASH_CLMUL_NI_INTEL
+ tristate "GHASH digest algorithm (CLMUL-NI accelerated)"
+ depends on (X86 || UML_X86) && 64BIT
+ select CRYPTO_SHASH
+ select CRYPTO_CRYPTD
+ help
+ GHASH is message digest algorithm for GCM (Galois/Counter Mode).
+ The implementation is accelerated by CLMUL-NI of Intel.
+
comment "Ciphers"
config CRYPTO_AES
diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c
index 3aa6e3834bfe..45bd2182cb36 100644
--- a/crypto/ansi_cprng.c
+++ b/crypto/ansi_cprng.c
@@ -85,7 +85,7 @@ static void xor_vectors(unsigned char *in1, unsigned char *in2,
* Returns DEFAULT_BLK_SZ bytes of random data per call
* returns 0 if generation succeded, <0 if something went wrong
*/
-static int _get_more_prng_bytes(struct prng_context *ctx)
+static int _get_more_prng_bytes(struct prng_context *ctx, int cont_test)
{
int i;
unsigned char tmp[DEFAULT_BLK_SZ];
@@ -132,7 +132,7 @@ static int _get_more_prng_bytes(struct prng_context *ctx)
*/
if (!memcmp(ctx->rand_data, ctx->last_rand_data,
DEFAULT_BLK_SZ)) {
- if (fips_enabled) {
+ if (cont_test) {
panic("cprng %p Failed repetition check!\n",
ctx);
}
@@ -185,16 +185,14 @@ static int _get_more_prng_bytes(struct prng_context *ctx)
}
/* Our exported functions */
-static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx)
+static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx,
+ int do_cont_test)
{
unsigned char *ptr = buf;
unsigned int byte_count = (unsigned int)nbytes;
int err;
- if (nbytes < 0)
- return -EINVAL;
-
spin_lock_bh(&ctx->prng_lock);
err = -EINVAL;
@@ -220,7 +218,7 @@ static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx)
remainder:
if (ctx->rand_data_valid == DEFAULT_BLK_SZ) {
- if (_get_more_prng_bytes(ctx) < 0) {
+ if (_get_more_prng_bytes(ctx, do_cont_test) < 0) {
memset(buf, 0, nbytes);
err = -EINVAL;
goto done;
@@ -247,7 +245,7 @@ empty_rbuf:
*/
for (; byte_count >= DEFAULT_BLK_SZ; byte_count -= DEFAULT_BLK_SZ) {
if (ctx->rand_data_valid == DEFAULT_BLK_SZ) {
- if (_get_more_prng_bytes(ctx) < 0) {
+ if (_get_more_prng_bytes(ctx, do_cont_test) < 0) {
memset(buf, 0, nbytes);
err = -EINVAL;
goto done;
@@ -356,7 +354,15 @@ static int cprng_get_random(struct crypto_rng *tfm, u8 *rdata,
{
struct prng_context *prng = crypto_rng_ctx(tfm);
- return get_prng_bytes(rdata, dlen, prng);
+ return get_prng_bytes(rdata, dlen, prng, 0);
+}
+
+static int fips_cprng_get_random(struct crypto_rng *tfm, u8 *rdata,
+ unsigned int dlen)
+{
+ struct prng_context *prng = crypto_rng_ctx(tfm);
+
+ return get_prng_bytes(rdata, dlen, prng, 1);
}
/*
@@ -384,6 +390,26 @@ static int cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
return 0;
}
+static int fips_cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
+{
+ u8 rdata[DEFAULT_BLK_SZ];
+ int rc;
+
+ struct prng_context *prng = crypto_rng_ctx(tfm);
+
+ rc = cprng_reset(tfm, seed, slen);
+
+ if (!rc)
+ goto out;
+
+ /* this primes our continuity test */
+ rc = get_prng_bytes(rdata, DEFAULT_BLK_SZ, prng, 0);
+ prng->rand_data_valid = DEFAULT_BLK_SZ;
+
+out:
+ return rc;
+}
+
static struct crypto_alg rng_alg = {
.cra_name = "stdrng",
.cra_driver_name = "ansi_cprng",
@@ -404,19 +430,51 @@ static struct crypto_alg rng_alg = {
}
};
+#ifdef CONFIG_CRYPTO_FIPS
+static struct crypto_alg fips_rng_alg = {
+ .cra_name = "fips(ansi_cprng)",
+ .cra_driver_name = "fips_ansi_cprng",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_RNG,
+ .cra_ctxsize = sizeof(struct prng_context),
+ .cra_type = &crypto_rng_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(rng_alg.cra_list),
+ .cra_init = cprng_init,
+ .cra_exit = cprng_exit,
+ .cra_u = {
+ .rng = {
+ .rng_make_random = fips_cprng_get_random,
+ .rng_reset = fips_cprng_reset,
+ .seedsize = DEFAULT_PRNG_KSZ + 2*DEFAULT_BLK_SZ,
+ }
+ }
+};
+#endif
/* Module initalization */
static int __init prng_mod_init(void)
{
- if (fips_enabled)
- rng_alg.cra_priority += 200;
+ int rc = 0;
- return crypto_register_alg(&rng_alg);
+ rc = crypto_register_alg(&rng_alg);
+#ifdef CONFIG_CRYPTO_FIPS
+ if (rc)
+ goto out;
+
+ rc = crypto_register_alg(&fips_rng_alg);
+
+out:
+#endif
+ return rc;
}
static void __exit prng_mod_fini(void)
{
crypto_unregister_alg(&rng_alg);
+#ifdef CONFIG_CRYPTO_FIPS
+ crypto_unregister_alg(&fips_rng_alg);
+#endif
return;
}
diff --git a/crypto/async_tx/async_pq.c b/crypto/async_tx/async_pq.c
index b88db6d1dc65..6b5cc4fba59f 100644
--- a/crypto/async_tx/async_pq.c
+++ b/crypto/async_tx/async_pq.c
@@ -26,14 +26,10 @@
#include <linux/async_tx.h>
/**
- * scribble - space to hold throwaway P buffer for synchronous gen_syndrome
+ * pq_scribble_page - space to hold throwaway P or Q buffer for
+ * synchronous gen_syndrome
*/
-static struct page *scribble;
-
-static bool is_raid6_zero_block(struct page *p)
-{
- return p == (void *) raid6_empty_zero_page;
-}
+static struct page *pq_scribble_page;
/* the struct page *blocks[] parameter passed to async_gen_syndrome()
* and async_syndrome_val() contains the 'P' destination address at
@@ -83,7 +79,7 @@ do_async_gen_syndrome(struct dma_chan *chan, struct page **blocks,
* sources and update the coefficients accordingly
*/
for (i = 0, idx = 0; i < src_cnt; i++) {
- if (is_raid6_zero_block(blocks[i]))
+ if (blocks[i] == NULL)
continue;
dma_src[idx] = dma_map_page(dma->dev, blocks[i], offset, len,
DMA_TO_DEVICE);
@@ -160,9 +156,9 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int offset, int disks,
srcs = (void **) blocks;
for (i = 0; i < disks; i++) {
- if (is_raid6_zero_block(blocks[i])) {
+ if (blocks[i] == NULL) {
BUG_ON(i > disks - 3); /* P or Q can't be zero */
- srcs[i] = blocks[i];
+ srcs[i] = (void*)raid6_empty_zero_page;
} else
srcs[i] = page_address(blocks[i]) + offset;
}
@@ -186,10 +182,14 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int offset, int disks,
* blocks[disks-1] to NULL. When P or Q is omitted 'len' must be <=
* PAGE_SIZE as a temporary buffer of this size is used in the
* synchronous path. 'disks' always accounts for both destination
- * buffers.
+ * buffers. If any source buffers (blocks[i] where i < disks - 2) are
+ * set to NULL those buffers will be replaced with the raid6_zero_page
+ * in the synchronous path and omitted in the hardware-asynchronous
+ * path.
*
* 'blocks' note: if submit->scribble is NULL then the contents of
- * 'blocks' may be overridden
+ * 'blocks' may be overwritten to perform address conversions
+ * (dma_map_page() or page_address()).
*/
struct dma_async_tx_descriptor *
async_gen_syndrome(struct page **blocks, unsigned int offset, int disks,
@@ -227,11 +227,11 @@ async_gen_syndrome(struct page **blocks, unsigned int offset, int disks,
async_tx_quiesce(&submit->depend_tx);
if (!P(blocks, disks)) {
- P(blocks, disks) = scribble;
+ P(blocks, disks) = pq_scribble_page;
BUG_ON(len + offset > PAGE_SIZE);
}
if (!Q(blocks, disks)) {
- Q(blocks, disks) = scribble;
+ Q(blocks, disks) = pq_scribble_page;
BUG_ON(len + offset > PAGE_SIZE);
}
do_sync_gen_syndrome(blocks, offset, disks, len, submit);
@@ -265,8 +265,10 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks,
len);
struct dma_device *device = chan ? chan->device : NULL;
struct dma_async_tx_descriptor *tx;
+ unsigned char coefs[disks-2];
enum dma_ctrl_flags dma_flags = submit->cb_fn ? DMA_PREP_INTERRUPT : 0;
dma_addr_t *dma_src = NULL;
+ int src_cnt = 0;
BUG_ON(disks < 4);
@@ -285,22 +287,32 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks,
__func__, disks, len);
if (!P(blocks, disks))
dma_flags |= DMA_PREP_PQ_DISABLE_P;
+ else
+ pq[0] = dma_map_page(dev, P(blocks, disks),
+ offset, len,
+ DMA_TO_DEVICE);
if (!Q(blocks, disks))
dma_flags |= DMA_PREP_PQ_DISABLE_Q;
+ else
+ pq[1] = dma_map_page(dev, Q(blocks, disks),
+ offset, len,
+ DMA_TO_DEVICE);
+
if (submit->flags & ASYNC_TX_FENCE)
dma_flags |= DMA_PREP_FENCE;
- for (i = 0; i < disks; i++)
+ for (i = 0; i < disks-2; i++)
if (likely(blocks[i])) {
- BUG_ON(is_raid6_zero_block(blocks[i]));
- dma_src[i] = dma_map_page(dev, blocks[i],
- offset, len,
- DMA_TO_DEVICE);
+ dma_src[src_cnt] = dma_map_page(dev, blocks[i],
+ offset, len,
+ DMA_TO_DEVICE);
+ coefs[src_cnt] = raid6_gfexp[i];
+ src_cnt++;
}
for (;;) {
tx = device->device_prep_dma_pq_val(chan, pq, dma_src,
- disks - 2,
- raid6_gfexp,
+ src_cnt,
+ coefs,
len, pqres,
dma_flags);
if (likely(tx))
@@ -373,9 +385,9 @@ EXPORT_SYMBOL_GPL(async_syndrome_val);
static int __init async_pq_init(void)
{
- scribble = alloc_page(GFP_KERNEL);
+ pq_scribble_page = alloc_page(GFP_KERNEL);
- if (scribble)
+ if (pq_scribble_page)
return 0;
pr_err("%s: failed to allocate required spare page\n", __func__);
@@ -385,7 +397,7 @@ static int __init async_pq_init(void)
static void __exit async_pq_exit(void)
{
- put_page(scribble);
+ put_page(pq_scribble_page);
}
module_init(async_pq_init);
diff --git a/crypto/async_tx/async_raid6_recov.c b/crypto/async_tx/async_raid6_recov.c
index 6d73dde4786d..943f2abac9b4 100644
--- a/crypto/async_tx/async_raid6_recov.c
+++ b/crypto/async_tx/async_raid6_recov.c
@@ -131,8 +131,8 @@ async_mult(struct page *dest, struct page *src, u8 coef, size_t len,
}
static struct dma_async_tx_descriptor *
-__2data_recov_4(size_t bytes, int faila, int failb, struct page **blocks,
- struct async_submit_ctl *submit)
+__2data_recov_4(int disks, size_t bytes, int faila, int failb,
+ struct page **blocks, struct async_submit_ctl *submit)
{
struct dma_async_tx_descriptor *tx = NULL;
struct page *p, *q, *a, *b;
@@ -143,8 +143,8 @@ __2data_recov_4(size_t bytes, int faila, int failb, struct page **blocks,
void *cb_param = submit->cb_param;
void *scribble = submit->scribble;
- p = blocks[4-2];
- q = blocks[4-1];
+ p = blocks[disks-2];
+ q = blocks[disks-1];
a = blocks[faila];
b = blocks[failb];
@@ -170,8 +170,8 @@ __2data_recov_4(size_t bytes, int faila, int failb, struct page **blocks,
}
static struct dma_async_tx_descriptor *
-__2data_recov_5(size_t bytes, int faila, int failb, struct page **blocks,
- struct async_submit_ctl *submit)
+__2data_recov_5(int disks, size_t bytes, int faila, int failb,
+ struct page **blocks, struct async_submit_ctl *submit)
{
struct dma_async_tx_descriptor *tx = NULL;
struct page *p, *q, *g, *dp, *dq;
@@ -181,21 +181,22 @@ __2data_recov_5(size_t bytes, int faila, int failb, struct page **blocks,
dma_async_tx_callback cb_fn = submit->cb_fn;
void *cb_param = submit->cb_param;
void *scribble = submit->scribble;
- int uninitialized_var(good);
- int i;
+ int good_srcs, good, i;
- for (i = 0; i < 3; i++) {
+ good_srcs = 0;
+ good = -1;
+ for (i = 0; i < disks-2; i++) {
+ if (blocks[i] == NULL)
+ continue;
if (i == faila || i == failb)
continue;
- else {
- good = i;
- break;
- }
+ good = i;
+ good_srcs++;
}
- BUG_ON(i >= 3);
+ BUG_ON(good_srcs > 1);
- p = blocks[5-2];
- q = blocks[5-1];
+ p = blocks[disks-2];
+ q = blocks[disks-1];
g = blocks[good];
/* Compute syndrome with zero for the missing data pages
@@ -263,10 +264,10 @@ __2data_recov_n(int disks, size_t bytes, int faila, int failb,
* delta p and delta q
*/
dp = blocks[faila];
- blocks[faila] = (void *)raid6_empty_zero_page;
+ blocks[faila] = NULL;
blocks[disks-2] = dp;
dq = blocks[failb];
- blocks[failb] = (void *)raid6_empty_zero_page;
+ blocks[failb] = NULL;
blocks[disks-1] = dq;
init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL, scribble);
@@ -323,6 +324,8 @@ struct dma_async_tx_descriptor *
async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
struct page **blocks, struct async_submit_ctl *submit)
{
+ int non_zero_srcs, i;
+
BUG_ON(faila == failb);
if (failb < faila)
swap(faila, failb);
@@ -334,11 +337,13 @@ async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
*/
if (!submit->scribble) {
void **ptrs = (void **) blocks;
- int i;
async_tx_quiesce(&submit->depend_tx);
for (i = 0; i < disks; i++)
- ptrs[i] = page_address(blocks[i]);
+ if (blocks[i] == NULL)
+ ptrs[i] = (void *) raid6_empty_zero_page;
+ else
+ ptrs[i] = page_address(blocks[i]);
raid6_2data_recov(disks, bytes, faila, failb, ptrs);
@@ -347,19 +352,30 @@ async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
return NULL;
}
- switch (disks) {
- case 4:
+ non_zero_srcs = 0;
+ for (i = 0; i < disks-2 && non_zero_srcs < 4; i++)
+ if (blocks[i])
+ non_zero_srcs++;
+ switch (non_zero_srcs) {
+ case 0:
+ case 1:
+ /* There must be at least 2 sources - the failed devices. */
+ BUG();
+
+ case 2:
/* dma devices do not uniformly understand a zero source pq
* operation (in contrast to the synchronous case), so
- * explicitly handle the 4 disk special case
+ * explicitly handle the special case of a 4 disk array with
+ * both data disks missing.
*/
- return __2data_recov_4(bytes, faila, failb, blocks, submit);
- case 5:
+ return __2data_recov_4(disks, bytes, faila, failb, blocks, submit);
+ case 3:
/* dma devices do not uniformly understand a single
* source pq operation (in contrast to the synchronous
- * case), so explicitly handle the 5 disk special case
+ * case), so explicitly handle the special case of a 5 disk
+ * array with 2 of 3 data disks missing.
*/
- return __2data_recov_5(bytes, faila, failb, blocks, submit);
+ return __2data_recov_5(disks, bytes, faila, failb, blocks, submit);
default:
return __2data_recov_n(disks, bytes, faila, failb, blocks, submit);
}
@@ -385,6 +401,7 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila,
dma_async_tx_callback cb_fn = submit->cb_fn;
void *cb_param = submit->cb_param;
void *scribble = submit->scribble;
+ int good_srcs, good, i;
struct page *srcs[2];
pr_debug("%s: disks: %d len: %zu\n", __func__, disks, bytes);
@@ -394,11 +411,13 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila,
*/
if (!scribble) {
void **ptrs = (void **) blocks;
- int i;
async_tx_quiesce(&submit->depend_tx);
for (i = 0; i < disks; i++)
- ptrs[i] = page_address(blocks[i]);
+ if (blocks[i] == NULL)
+ ptrs[i] = (void*)raid6_empty_zero_page;
+ else
+ ptrs[i] = page_address(blocks[i]);
raid6_datap_recov(disks, bytes, faila, ptrs);
@@ -407,6 +426,20 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila,
return NULL;
}
+ good_srcs = 0;
+ good = -1;
+ for (i = 0; i < disks-2; i++) {
+ if (i == faila)
+ continue;
+ if (blocks[i]) {
+ good = i;
+ good_srcs++;
+ if (good_srcs > 1)
+ break;
+ }
+ }
+ BUG_ON(good_srcs == 0);
+
p = blocks[disks-2];
q = blocks[disks-1];
@@ -414,14 +447,13 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila,
* Use the dead data page as temporary storage for delta q
*/
dq = blocks[faila];
- blocks[faila] = (void *)raid6_empty_zero_page;
+ blocks[faila] = NULL;
blocks[disks-1] = dq;
- /* in the 4 disk case we only need to perform a single source
- * multiplication
+ /* in the 4-disk case we only need to perform a single source
+ * multiplication with the one good data block.
*/
- if (disks == 4) {
- int good = faila == 0 ? 1 : 0;
+ if (good_srcs == 1) {
struct page *g = blocks[good];
init_async_submit(submit, ASYNC_TX_FENCE, tx, NULL, NULL,
diff --git a/crypto/async_tx/async_xor.c b/crypto/async_tx/async_xor.c
index b459a9034aac..79182dcb91b7 100644
--- a/crypto/async_tx/async_xor.c
+++ b/crypto/async_tx/async_xor.c
@@ -44,20 +44,23 @@ do_async_xor(struct dma_chan *chan, struct page *dest, struct page **src_list,
void *cb_param_orig = submit->cb_param;
enum async_tx_flags flags_orig = submit->flags;
enum dma_ctrl_flags dma_flags;
- int xor_src_cnt;
+ int xor_src_cnt = 0;
dma_addr_t dma_dest;
/* map the dest bidrectional in case it is re-used as a source */
dma_dest = dma_map_page(dma->dev, dest, offset, len, DMA_BIDIRECTIONAL);
for (i = 0; i < src_cnt; i++) {
/* only map the dest once */
+ if (!src_list[i])
+ continue;
if (unlikely(src_list[i] == dest)) {
- dma_src[i] = dma_dest;
+ dma_src[xor_src_cnt++] = dma_dest;
continue;
}
- dma_src[i] = dma_map_page(dma->dev, src_list[i], offset,
- len, DMA_TO_DEVICE);
+ dma_src[xor_src_cnt++] = dma_map_page(dma->dev, src_list[i], offset,
+ len, DMA_TO_DEVICE);
}
+ src_cnt = xor_src_cnt;
while (src_cnt) {
submit->flags = flags_orig;
@@ -123,7 +126,7 @@ do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset,
int src_cnt, size_t len, struct async_submit_ctl *submit)
{
int i;
- int xor_src_cnt;
+ int xor_src_cnt = 0;
int src_off = 0;
void *dest_buf;
void **srcs;
@@ -135,8 +138,9 @@ do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset,
/* convert to buffer pointers */
for (i = 0; i < src_cnt; i++)
- srcs[i] = page_address(src_list[i]) + offset;
-
+ if (src_list[i])
+ srcs[xor_src_cnt++] = page_address(src_list[i]) + offset;
+ src_cnt = xor_src_cnt;
/* set destination address */
dest_buf = page_address(dest) + offset;
diff --git a/crypto/cryptd.c b/crypto/cryptd.c
index 35335825a4ef..704c14115323 100644
--- a/crypto/cryptd.c
+++ b/crypto/cryptd.c
@@ -99,7 +99,7 @@ static int cryptd_enqueue_request(struct cryptd_queue *queue,
struct cryptd_cpu_queue *cpu_queue;
cpu = get_cpu();
- cpu_queue = per_cpu_ptr(queue->cpu_queue, cpu);
+ cpu_queue = this_cpu_ptr(queue->cpu_queue);
err = crypto_enqueue_request(&cpu_queue->queue, request);
queue_work_on(cpu, kcrypto_wq, &cpu_queue->work);
put_cpu();
@@ -711,6 +711,13 @@ struct crypto_shash *cryptd_ahash_child(struct cryptd_ahash *tfm)
}
EXPORT_SYMBOL_GPL(cryptd_ahash_child);
+struct shash_desc *cryptd_shash_desc(struct ahash_request *req)
+{
+ struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req);
+ return &rctx->desc;
+}
+EXPORT_SYMBOL_GPL(cryptd_shash_desc);
+
void cryptd_free_ahash(struct cryptd_ahash *tfm)
{
crypto_free_ahash(&tfm->base);
diff --git a/crypto/digest.c b/crypto/digest.c
deleted file mode 100644
index 5d3f1303da98..000000000000
--- a/crypto/digest.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Digest operations.
- *
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.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.
- *
- */
-
-#include <crypto/internal/hash.h>
-#include <crypto/scatterwalk.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/hardirq.h>
-#include <linux/highmem.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/scatterlist.h>
-
-#include "internal.h"
-
-static int init(struct hash_desc *desc)
-{
- struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
-
- tfm->__crt_alg->cra_digest.dia_init(tfm);
- return 0;
-}
-
-static int update2(struct hash_desc *desc,
- struct scatterlist *sg, unsigned int nbytes)
-{
- struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
- unsigned int alignmask = crypto_tfm_alg_alignmask(tfm);
-
- if (!nbytes)
- return 0;
-
- for (;;) {
- struct page *pg = sg_page(sg);
- unsigned int offset = sg->offset;
- unsigned int l = sg->length;
-
- if (unlikely(l > nbytes))
- l = nbytes;
- nbytes -= l;
-
- do {
- unsigned int bytes_from_page = min(l, ((unsigned int)
- (PAGE_SIZE)) -
- offset);
- char *src = crypto_kmap(pg, 0);
- char *p = src + offset;
-
- if (unlikely(offset & alignmask)) {
- unsigned int bytes =
- alignmask + 1 - (offset & alignmask);
- bytes = min(bytes, bytes_from_page);
- tfm->__crt_alg->cra_digest.dia_update(tfm, p,
- bytes);
- p += bytes;
- bytes_from_page -= bytes;
- l -= bytes;
- }
- tfm->__crt_alg->cra_digest.dia_update(tfm, p,
- bytes_from_page);
- crypto_kunmap(src, 0);
- crypto_yield(desc->flags);
- offset = 0;
- pg++;
- l -= bytes_from_page;
- } while (l > 0);
-
- if (!nbytes)
- break;
- sg = scatterwalk_sg_next(sg);
- }
-
- return 0;
-}
-
-static int update(struct hash_desc *desc,
- struct scatterlist *sg, unsigned int nbytes)
-{
- if (WARN_ON_ONCE(in_irq()))
- return -EDEADLK;
- return update2(desc, sg, nbytes);
-}
-
-static int final(struct hash_desc *desc, u8 *out)
-{
- struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
- unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
- struct digest_alg *digest = &tfm->__crt_alg->cra_digest;
-
- if (unlikely((unsigned long)out & alignmask)) {
- unsigned long align = alignmask + 1;
- unsigned long addr = (unsigned long)crypto_tfm_ctx(tfm);
- u8 *dst = (u8 *)ALIGN(addr, align) +
- ALIGN(tfm->__crt_alg->cra_ctxsize, align);
-
- digest->dia_final(tfm, dst);
- memcpy(out, dst, digest->dia_digestsize);
- } else
- digest->dia_final(tfm, out);
-
- return 0;
-}
-
-static int nosetkey(struct crypto_hash *tfm, const u8 *key, unsigned int keylen)
-{
- crypto_hash_clear_flags(tfm, CRYPTO_TFM_RES_MASK);
- return -ENOSYS;
-}
-
-static int setkey(struct crypto_hash *hash, const u8 *key, unsigned int keylen)
-{
- struct crypto_tfm *tfm = crypto_hash_tfm(hash);
-
- crypto_hash_clear_flags(hash, CRYPTO_TFM_RES_MASK);
- return tfm->__crt_alg->cra_digest.dia_setkey(tfm, key, keylen);
-}
-
-static int digest(struct hash_desc *desc,
- struct scatterlist *sg, unsigned int nbytes, u8 *out)
-{
- if (WARN_ON_ONCE(in_irq()))
- return -EDEADLK;
-
- init(desc);
- update2(desc, sg, nbytes);
- return final(desc, out);
-}
-
-int crypto_init_digest_ops(struct crypto_tfm *tfm)
-{
- struct hash_tfm *ops = &tfm->crt_hash;
- struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
-
- if (dalg->dia_digestsize > PAGE_SIZE / 8)
- return -EINVAL;
-
- ops->init = init;
- ops->update = update;
- ops->final = final;
- ops->digest = digest;
- ops->setkey = dalg->dia_setkey ? setkey : nosetkey;
- ops->digestsize = dalg->dia_digestsize;
-
- return 0;
-}
-
-void crypto_exit_digest_ops(struct crypto_tfm *tfm)
-{
-}
-
-static int digest_async_nosetkey(struct crypto_ahash *tfm_async, const u8 *key,
- unsigned int keylen)
-{
- crypto_ahash_clear_flags(tfm_async, CRYPTO_TFM_RES_MASK);
- return -ENOSYS;
-}
-
-static int digest_async_setkey(struct crypto_ahash *tfm_async, const u8 *key,
- unsigned int keylen)
-{
- struct crypto_tfm *tfm = crypto_ahash_tfm(tfm_async);
- struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
-
- crypto_ahash_clear_flags(tfm_async, CRYPTO_TFM_RES_MASK);
- return dalg->dia_setkey(tfm, key, keylen);
-}
-
-static int digest_async_init(struct ahash_request *req)
-{
- struct crypto_tfm *tfm = req->base.tfm;
- struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
-
- dalg->dia_init(tfm);
- return 0;
-}
-
-static int digest_async_update(struct ahash_request *req)
-{
- struct crypto_tfm *tfm = req->base.tfm;
- struct hash_desc desc = {
- .tfm = __crypto_hash_cast(tfm),
- .flags = req->base.flags,
- };
-
- update(&desc, req->src, req->nbytes);
- return 0;
-}
-
-static int digest_async_final(struct ahash_request *req)
-{
- struct crypto_tfm *tfm = req->base.tfm;
- struct hash_desc desc = {
- .tfm = __crypto_hash_cast(tfm),
- .flags = req->base.flags,
- };
-
- final(&desc, req->result);
- return 0;
-}
-
-static int digest_async_digest(struct ahash_request *req)
-{
- struct crypto_tfm *tfm = req->base.tfm;
- struct hash_desc desc = {
- .tfm = __crypto_hash_cast(tfm),
- .flags = req->base.flags,
- };
-
- return digest(&desc, req->src, req->nbytes, req->result);
-}
-
-int crypto_init_digest_ops_async(struct crypto_tfm *tfm)
-{
- struct ahash_tfm *crt = &tfm->crt_ahash;
- struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
-
- if (dalg->dia_digestsize > PAGE_SIZE / 8)
- return -EINVAL;
-
- crt->init = digest_async_init;
- crt->update = digest_async_update;
- crt->final = digest_async_final;
- crt->digest = digest_async_digest;
- crt->setkey = dalg->dia_setkey ? digest_async_setkey :
- digest_async_nosetkey;
- crt->digestsize = dalg->dia_digestsize;
-
- return 0;
-}
diff --git a/crypto/hash.c b/crypto/hash.c
deleted file mode 100644
index cb86b19fd105..000000000000
--- a/crypto/hash.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Cryptographic Hash operations.
- *
- * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.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.
- */
-
-#include <crypto/internal/hash.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/seq_file.h>
-
-#include "internal.h"
-
-static unsigned int crypto_hash_ctxsize(struct crypto_alg *alg, u32 type,
- u32 mask)
-{
- return alg->cra_ctxsize;
-}
-
-static int hash_setkey_unaligned(struct crypto_hash *crt, const u8 *key,
- unsigned int keylen)
-{
- struct crypto_tfm *tfm = crypto_hash_tfm(crt);
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
- unsigned long alignmask = crypto_hash_alignmask(crt);
- int ret;
- u8 *buffer, *alignbuffer;
- unsigned long absize;
-
- absize = keylen + alignmask;
- buffer = kmalloc(absize, GFP_ATOMIC);
- if (!buffer)
- return -ENOMEM;
-
- alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
- memcpy(alignbuffer, key, keylen);
- ret = alg->setkey(crt, alignbuffer, keylen);
- memset(alignbuffer, 0, keylen);
- kfree(buffer);
- return ret;
-}
-
-static int hash_setkey(struct crypto_hash *crt, const u8 *key,
- unsigned int keylen)
-{
- struct crypto_tfm *tfm = crypto_hash_tfm(crt);
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
- unsigned long alignmask = crypto_hash_alignmask(crt);
-
- if ((unsigned long)key & alignmask)
- return hash_setkey_unaligned(crt, key, keylen);
-
- return alg->setkey(crt, key, keylen);
-}
-
-static int hash_async_setkey(struct crypto_ahash *tfm_async, const u8 *key,
- unsigned int keylen)
-{
- struct crypto_tfm *tfm = crypto_ahash_tfm(tfm_async);
- struct crypto_hash *tfm_hash = __crypto_hash_cast(tfm);
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
-
- return alg->setkey(tfm_hash, key, keylen);
-}
-
-static int hash_async_init(struct ahash_request *req)
-{
- struct crypto_tfm *tfm = req->base.tfm;
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
- struct hash_desc desc = {
- .tfm = __crypto_hash_cast(tfm),
- .flags = req->base.flags,
- };
-
- return alg->init(&desc);
-}
-
-static int hash_async_update(struct ahash_request *req)
-{
- struct crypto_tfm *tfm = req->base.tfm;
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
- struct hash_desc desc = {
- .tfm = __crypto_hash_cast(tfm),
- .flags = req->base.flags,
- };
-
- return alg->update(&desc, req->src, req->nbytes);
-}
-
-static int hash_async_final(struct ahash_request *req)
-{
- struct crypto_tfm *tfm = req->base.tfm;
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
- struct hash_desc desc = {
- .tfm = __crypto_hash_cast(tfm),
- .flags = req->base.flags,
- };
-
- return alg->final(&desc, req->result);
-}
-
-static int hash_async_digest(struct ahash_request *req)
-{
- struct crypto_tfm *tfm = req->base.tfm;
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
- struct hash_desc desc = {
- .tfm = __crypto_hash_cast(tfm),
- .flags = req->base.flags,
- };
-
- return alg->digest(&desc, req->src, req->nbytes, req->result);
-}
-
-static int crypto_init_hash_ops_async(struct crypto_tfm *tfm)
-{
- struct ahash_tfm *crt = &tfm->crt_ahash;
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
-
- crt->init = hash_async_init;
- crt->update = hash_async_update;
- crt->final = hash_async_final;
- crt->digest = hash_async_digest;
- crt->setkey = hash_async_setkey;
- crt->digestsize = alg->digestsize;
-
- return 0;
-}
-
-static int crypto_init_hash_ops_sync(struct crypto_tfm *tfm)
-{
- struct hash_tfm *crt = &tfm->crt_hash;
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
-
- crt->init = alg->init;
- crt->update = alg->update;
- crt->final = alg->final;
- crt->digest = alg->digest;
- crt->setkey = hash_setkey;
- crt->digestsize = alg->digestsize;
-
- return 0;
-}
-
-static int crypto_init_hash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
-{
- struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
-
- if (alg->digestsize > PAGE_SIZE / 8)
- return -EINVAL;
-
- if ((mask & CRYPTO_ALG_TYPE_HASH_MASK) != CRYPTO_ALG_TYPE_HASH_MASK)
- return crypto_init_hash_ops_async(tfm);
- else
- return crypto_init_hash_ops_sync(tfm);
-}
-
-static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
- __attribute__ ((unused));
-static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
-{
- seq_printf(m, "type : hash\n");
- seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
- seq_printf(m, "digestsize : %u\n", alg->cra_hash.digestsize);
-}
-
-const struct crypto_type crypto_hash_type = {
- .ctxsize = crypto_hash_ctxsize,
- .init = crypto_init_hash_ops,
-#ifdef CONFIG_PROC_FS
- .show = crypto_hash_show,
-#endif
-};
-EXPORT_SYMBOL_GPL(crypto_hash_type);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic cryptographic hash type");
diff --git a/crypto/proc.c b/crypto/proc.c
index 5dc07e442fca..ff4cb4a357f9 100644
--- a/crypto/proc.c
+++ b/crypto/proc.c
@@ -115,13 +115,6 @@ static int c_show(struct seq_file *m, void *p)
seq_printf(m, "max keysize : %u\n",
alg->cra_cipher.cia_max_keysize);
break;
-
- case CRYPTO_ALG_TYPE_DIGEST:
- seq_printf(m, "type : digest\n");
- seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
- seq_printf(m, "digestsize : %u\n",
- alg->cra_digest.dia_digestsize);
- break;
case CRYPTO_ALG_TYPE_COMPRESS:
seq_printf(m, "type : compression\n");
break;
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 6d5b746637be..1f2357bc6424 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -1201,7 +1201,7 @@ static int test_cprng(struct crypto_rng *tfm, struct cprng_testvec *template,
unsigned int tcount)
{
const char *algo = crypto_tfm_alg_driver_name(crypto_rng_tfm(tfm));
- int err, i, j, seedsize;
+ int err = 0, i, j, seedsize;
u8 *seed;
char result[32];
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 48bbdbe43e69..26e434ad373c 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -1,5 +1,3 @@
-# drivers/Kconfig
-
menu "Device Drivers"
source "drivers/base/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 6ee53c7a57a1..f0d8b97909d3 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -111,3 +111,4 @@ obj-$(CONFIG_VLYNQ) += vlynq/
obj-$(CONFIG_STAGING) += staging/
obj-y += platform/
obj-y += ieee802154/
+obj-y += vbus/
diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c
index d672cfe7ca59..cb423f5aef24 100644
--- a/drivers/accessibility/braille/braille_console.c
+++ b/drivers/accessibility/braille/braille_console.c
@@ -21,7 +21,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/autoconf.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c
index 6de3a99d4cd4..10fc78517843 100644
--- a/drivers/acpi/acpica/dswload.c
+++ b/drivers/acpi/acpica/dswload.c
@@ -639,26 +639,42 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
break;
case AML_SCOPE_OP:
- /*
- * The Path is an object reference to an existing object.
- * Don't enter the name into the namespace, but look it up
- * for use later.
- */
- status =
- acpi_ns_lookup(walk_state->scope_info, buffer_ptr,
- object_type, ACPI_IMODE_EXECUTE,
- ACPI_NS_SEARCH_PARENT, walk_state, &(node));
- if (ACPI_FAILURE(status)) {
-#ifdef ACPI_ASL_COMPILER
- if (status == AE_NOT_FOUND) {
- status = AE_OK;
- } else {
- ACPI_ERROR_NAMESPACE(buffer_ptr, status);
+
+ /* Special case for Scope(\) -> refers to the Root node */
+
+ if (op && (op->named.node == acpi_gbl_root_node)) {
+ node = op->named.node;
+
+ status =
+ acpi_ds_scope_stack_push(node, object_type,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
}
+ } else {
+ /*
+ * The Path is an object reference to an existing object.
+ * Don't enter the name into the namespace, but look it up
+ * for use later.
+ */
+ status =
+ acpi_ns_lookup(walk_state->scope_info, buffer_ptr,
+ object_type, ACPI_IMODE_EXECUTE,
+ ACPI_NS_SEARCH_PARENT, walk_state,
+ &(node));
+ if (ACPI_FAILURE(status)) {
+#ifdef ACPI_ASL_COMPILER
+ if (status == AE_NOT_FOUND) {
+ status = AE_OK;
+ } else {
+ ACPI_ERROR_NAMESPACE(buffer_ptr,
+ status);
+ }
#else
- ACPI_ERROR_NAMESPACE(buffer_ptr, status);
+ ACPI_ERROR_NAMESPACE(buffer_ptr, status);
#endif
- return_ACPI_STATUS(status);
+ return_ACPI_STATUS(status);
+ }
}
/*
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c
index 98c7f9c62653..c9fa040725d4 100644
--- a/drivers/acpi/acpica/evregion.c
+++ b/drivers/acpi/acpica/evregion.c
@@ -51,6 +51,10 @@
ACPI_MODULE_NAME("evregion")
/* Local prototypes */
+static u8
+acpi_ev_has_default_handler(struct acpi_namespace_node *node,
+ acpi_adr_space_type space_id);
+
static acpi_status
acpi_ev_reg_run(acpi_handle obj_handle,
u32 level, void *context, void **return_value);
@@ -142,6 +146,50 @@ acpi_status acpi_ev_install_region_handlers(void)
/*******************************************************************************
*
+ * FUNCTION: acpi_ev_has_default_handler
+ *
+ * PARAMETERS: Node - Namespace node for the device
+ * space_id - The address space ID
+ *
+ * RETURN: TRUE if default handler is installed, FALSE otherwise
+ *
+ * DESCRIPTION: Check if the default handler is installed for the requested
+ * space ID.
+ *
+ ******************************************************************************/
+
+static u8
+acpi_ev_has_default_handler(struct acpi_namespace_node *node,
+ acpi_adr_space_type space_id)
+{
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *handler_obj;
+
+ /* Must have an existing internal object */
+
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (obj_desc) {
+ handler_obj = obj_desc->device.handler;
+
+ /* Walk the linked list of handlers for this object */
+
+ while (handler_obj) {
+ if (handler_obj->address_space.space_id == space_id) {
+ if (handler_obj->address_space.handler_flags &
+ ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) {
+ return (TRUE);
+ }
+ }
+
+ handler_obj = handler_obj->address_space.next;
+ }
+ }
+
+ return (FALSE);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ev_initialize_op_regions
*
* PARAMETERS: None
@@ -169,12 +217,18 @@ acpi_status acpi_ev_initialize_op_regions(void)
for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) {
/*
- * TBD: Make sure handler is the DEFAULT handler, otherwise
- * _REG will have already been run.
+ * Make sure the installed handler is the DEFAULT handler. If not the
+ * default, the _REG methods will have already been run (when the
+ * handler was installed)
*/
- status = acpi_ev_execute_reg_methods(acpi_gbl_root_node,
- acpi_gbl_default_address_spaces
- [i]);
+ if (acpi_ev_has_default_handler(acpi_gbl_root_node,
+ acpi_gbl_default_address_spaces
+ [i])) {
+ status =
+ acpi_ev_execute_reg_methods(acpi_gbl_root_node,
+ acpi_gbl_default_address_spaces
+ [i]);
+ }
}
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c
index db2b2a99c3a8..f2f5269fed6d 100644
--- a/drivers/acpi/acpica/nsrepair.c
+++ b/drivers/acpi/acpica/nsrepair.c
@@ -44,6 +44,7 @@
#include <acpi/acpi.h>
#include "accommon.h"
#include "acnamesp.h"
+#include "acinterp.h"
#include "acpredef.h"
#define _COMPONENT ACPI_NAMESPACE
@@ -76,7 +77,13 @@ acpi_ns_repair_object(struct acpi_predefined_data *data,
union acpi_operand_object *return_object = *return_object_ptr;
union acpi_operand_object *new_object;
acpi_size length;
+ acpi_status status;
+ /*
+ * At this point, we know that the type of the returned object was not
+ * one of the expected types for this predefined name. Attempt to
+ * repair the object. Only a limited number of repairs are possible.
+ */
switch (return_object->common.type) {
case ACPI_TYPE_BUFFER:
@@ -111,43 +118,94 @@ acpi_ns_repair_object(struct acpi_predefined_data *data,
*/
ACPI_MEMCPY(new_object->string.pointer,
return_object->buffer.pointer, length);
+ break;
- /*
- * If the original object is a package element, we need to:
- * 1. Set the reference count of the new object to match the
- * reference count of the old object.
- * 2. Decrement the reference count of the original object.
- */
- if (package_index != ACPI_NOT_PACKAGE_ELEMENT) {
- new_object->common.reference_count =
- return_object->common.reference_count;
+ case ACPI_TYPE_INTEGER:
+
+ /* 1) Does the method/object legally return a buffer? */
+
+ if (expected_btypes & ACPI_RTYPE_BUFFER) {
+ /*
+ * Convert the Integer to a packed-byte buffer. _MAT needs
+ * this sometimes, if a read has been performed on a Field
+ * object that is less than or equal to the global integer
+ * size (32 or 64 bits).
+ */
+ status =
+ acpi_ex_convert_to_buffer(return_object,
+ &new_object);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ }
- if (return_object->common.reference_count > 1) {
- return_object->common.reference_count--;
+ /* 2) Does the method/object legally return a string? */
+
+ else if (expected_btypes & ACPI_RTYPE_STRING) {
+ /*
+ * The only supported Integer-to-String conversion is to convert
+ * an integer of value 0 to a NULL string. The last element of
+ * _BIF and _BIX packages occasionally need this fix.
+ */
+ if (return_object->integer.value != 0) {
+ return (AE_AML_OPERAND_TYPE);
}
- ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
- data->node_flags,
- "Converted Buffer to expected String at index %u",
- package_index));
+ /* Allocate a new NULL string object */
+
+ new_object = acpi_ut_create_string_object(0);
+ if (!new_object) {
+ return (AE_NO_MEMORY);
+ }
} else {
- ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
- data->node_flags,
- "Converted Buffer to expected String"));
+ return (AE_AML_OPERAND_TYPE);
}
+ break;
- /* Delete old object, install the new return object */
+ default:
- acpi_ut_remove_reference(return_object);
- *return_object_ptr = new_object;
- data->flags |= ACPI_OBJECT_REPAIRED;
- return (AE_OK);
+ /* We cannot repair this object */
- default:
- break;
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ /* Object was successfully repaired */
+
+ /*
+ * If the original object is a package element, we need to:
+ * 1. Set the reference count of the new object to match the
+ * reference count of the old object.
+ * 2. Decrement the reference count of the original object.
+ */
+ if (package_index != ACPI_NOT_PACKAGE_ELEMENT) {
+ new_object->common.reference_count =
+ return_object->common.reference_count;
+
+ if (return_object->common.reference_count > 1) {
+ return_object->common.reference_count--;
+ }
+
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Converted %s to expected %s at index %u",
+ acpi_ut_get_object_type_name
+ (return_object),
+ acpi_ut_get_object_type_name(new_object),
+ package_index));
+ } else {
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ "Converted %s to expected %s",
+ acpi_ut_get_object_type_name
+ (return_object),
+ acpi_ut_get_object_type_name
+ (new_object)));
}
- return (AE_AML_OPERAND_TYPE);
+ /* Delete old object, install the new return object */
+
+ acpi_ut_remove_reference(return_object);
+ *return_object_ptr = new_object;
+ data->flags |= ACPI_OBJECT_REPAIRED;
+ return (AE_OK);
}
/*******************************************************************************
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index c6645f26224b..1ff30b24a923 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -11,6 +11,7 @@
#include <linux/device.h>
#include <linux/rwsem.h>
#include <linux/acpi.h>
+#include <linux/pm_link.h>
#include "internal.h"
@@ -170,6 +171,7 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle)
device_set_wakeup_enable(dev,
acpi_dev->wakeup.state.enabled);
}
+ pm_link_add(dev, &acpi_dev->dev);
}
return 0;
@@ -189,6 +191,7 @@ static int acpi_unbind_one(struct device *dev)
&acpi_dev)) {
sysfs_remove_link(&dev->kobj, "firmware_node");
sysfs_remove_link(&acpi_dev->dev.kobj, "physical_node");
+ pm_link_remove(dev, &acpi_dev->dev);
}
acpi_detach_data(dev->archdata.acpi_handle,
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 202dd0c976a3..2be2fb66204e 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -283,22 +283,24 @@ acpi_table_parse_srat(enum acpi_srat_type id,
int __init acpi_numa_init(void)
{
+ int ret = 0;
+
/* SRAT: Static Resource Affinity Table */
if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
acpi_table_parse_srat(ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY,
acpi_parse_x2apic_affinity, NR_CPUS);
acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
acpi_parse_processor_affinity, NR_CPUS);
- acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
- acpi_parse_memory_affinity,
- NR_NODE_MEMBLKS);
+ ret = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
+ acpi_parse_memory_affinity,
+ NR_NODE_MEMBLKS);
}
/* SLIT: System Locality Information Table */
acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit);
acpi_numa_arch_fixup();
- return 0;
+ return ret;
}
int acpi_get_pxm(acpi_handle h)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 14a7481c97d7..c7a0d274fcae 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -503,6 +503,7 @@ static int acpi_device_register(struct acpi_device *device)
dev_name(&device->dev));
device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
+ device_enable_async_suspend(&device->dev, true);
return 0;
end:
mutex_lock(&acpi_device_lock);
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index 575593a8b4e6..27c77729c7ca 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -7,7 +7,7 @@
* video_detect.c:
* Provides acpi_is_video_device() for early scanning of ACPI devices in scan.c
* There a Linux specific (Spec does not provide a HID for video devices) is
- * assinged
+ * assigned
*
* After PCI devices are glued with ACPI devices
* acpi_get_pci_dev() can be called to identify ACPI graphics
@@ -83,16 +83,16 @@ long acpi_is_video_device(struct acpi_device *device)
if (!device)
return 0;
- /* Does this device able to support video switching ? */
+ /* Is this device able to support video switching ? */
if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) ||
ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
- /* Does this device able to retrieve a video ROM ? */
+ /* Is this device able to retrieve a video ROM ? */
if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
- /* Does this device able to configure which video head to be POSTed ? */
+ /* Is this device able to configure which video head to be POSTed ? */
if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) &&
ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) &&
ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy)))
@@ -137,7 +137,7 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
*
* if NULL is passed as argument all ACPI devices are enumerated and
* all graphics capabilities of physically present devices are
- * summerized and returned. This is cached and done only once.
+ * summarized and returned. This is cached and done only once.
*/
long acpi_video_get_capabilities(acpi_handle graphics_handle)
{
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index b1a257746a19..a06f5d6375a8 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -575,7 +575,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */
/* AMD */
- { PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD SB900 */
+ { PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */
/* AMD is using RAID class only for ahci controllers */
{ PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
@@ -605,6 +605,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci_yesncq }, /* MCP67 */
{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_yesncq }, /* MCP67 */
{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_yesncq }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x0580), board_ahci_yesncq }, /* Linux ID */
{ PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_yesncq }, /* MCP73 */
{ PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_yesncq }, /* MCP73 */
{ PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_yesncq }, /* MCP73 */
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index b525a0981348..d7f0f1b1ae3e 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -5028,12 +5028,14 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
qc->flags |= ATA_QCFLAG_FAILED;
if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) {
- if (!ata_tag_internal(qc->tag)) {
- /* always fill result TF for failed qc */
- fill_result_tf(qc);
+ /* always fill result TF for failed qc */
+ fill_result_tf(qc);
+
+ if (!ata_tag_internal(qc->tag))
ata_qc_schedule_eh(qc);
- return;
- }
+ else
+ __ata_qc_complete(qc);
+ return;
}
WARN_ON_ONCE(ap->pflags & ATA_PFLAG_FROZEN);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 0a97822da211..bba2ae5df1c2 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2981,12 +2981,14 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
* device detection messages backwards.
*/
ata_for_each_dev(dev, link, ALL) {
- if (!(new_mask & (1 << dev->devno)) ||
- dev->class == ATA_DEV_PMP)
+ if (!(new_mask & (1 << dev->devno)))
continue;
dev->class = ehc->classes[dev->devno];
+ if (dev->class == ATA_DEV_PMP)
+ continue;
+
ehc->i.flags |= ATA_EHI_PRINTINFO;
rc = ata_dev_configure(dev);
ehc->i.flags &= ~ATA_EHI_PRINTINFO;
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index aa4b3f6ae771..ae4454d4e955 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -246,7 +246,7 @@ static const struct pci_device_id atiixp[] = {
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), },
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), },
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP700_IDE), },
- { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_SB900_IDE), },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_HUDSON2_IDE), },
{ },
};
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
index 403f56165cec..71cef9a962d4 100644
--- a/drivers/ata/pata_cs5535.c
+++ b/drivers/ata/pata_cs5535.c
@@ -4,7 +4,7 @@
* Alan Cox <alan@lxorguk.ukuu.org.uk>
*
* based upon cs5535.c from AMD <Jens.Altmann@amd.com> as cleaned up and
- * made readable and Linux style by Wolfgang Zuleger <wolfgang.zuleger@gmx.de
+ * made readable and Linux style by Wolfgang Zuleger <wolfgang.zuleger@gmx.de>
* and Alexander Kiausch <alex.kiausch@t-online.de>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index f49814d6fd2e..3bbed8322ecf 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -235,8 +235,7 @@ static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
.udma_mask = ATA_UDMA2,
.port_ops = &sc1200_port_ops
};
- /* Can't enable port 2 yet, see top comments */
- const struct ata_port_info *ppi[] = { &info, };
+ const struct ata_port_info *ppi[] = { &info, NULL };
return ata_pci_sff_init_one(dev, ppi, &sc1200_sht, NULL);
}
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index 45657cacec43..88984b803d6d 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -111,7 +111,7 @@ static const struct via_isa_bridge {
{ "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_SATA_PATA },
{ "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES },
- { "vt6415", PCI_DEVICE_ID_VIA_6415, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES },
+ { "vt6415", PCI_DEVICE_ID_VIA_6415, 0x00, 0xff, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES },
{ "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 17f9ff9067a2..6f5093b7c8c5 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -1382,6 +1382,25 @@ static int mv_qc_defer(struct ata_queued_cmd *qc)
*/
if (pp->pp_flags & MV_PP_FLAG_DELAYED_EH)
return ATA_DEFER_PORT;
+
+ /* PIO commands need exclusive link: no other commands [DMA or PIO]
+ * can run concurrently.
+ * set excl_link when we want to send a PIO command in DMA mode
+ * or a non-NCQ command in NCQ mode.
+ * When we receive a command from that link, and there are no
+ * outstanding commands, mark a flag to clear excl_link and let
+ * the command go through.
+ */
+ if (unlikely(ap->excl_link)) {
+ if (link == ap->excl_link) {
+ if (ap->nr_active_links)
+ return ATA_DEFER_PORT;
+ qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+ return 0;
+ } else
+ return ATA_DEFER_PORT;
+ }
+
/*
* If the port is completely idle, then allow the new qc.
*/
@@ -1395,8 +1414,14 @@ static int mv_qc_defer(struct ata_queued_cmd *qc)
* doesn't allow it.
*/
if ((pp->pp_flags & MV_PP_FLAG_EDMA_EN) &&
- (pp->pp_flags & MV_PP_FLAG_NCQ_EN) && ata_is_ncq(qc->tf.protocol))
- return 0;
+ (pp->pp_flags & MV_PP_FLAG_NCQ_EN)) {
+ if (ata_is_ncq(qc->tf.protocol))
+ return 0;
+ else {
+ ap->excl_link = link;
+ return ATA_DEFER_PORT;
+ }
+ }
return ATA_DEFER_PORT;
}
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 86a40582999c..1eb4e020eb5c 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -1594,9 +1594,21 @@ static int nv_hardreset(struct ata_link *link, unsigned int *class,
!ata_dev_enabled(link->device))
sata_link_hardreset(link, sata_deb_timing_hotplug, deadline,
NULL, NULL);
- else if (!(ehc->i.flags & ATA_EHI_QUIET))
- ata_link_printk(link, KERN_INFO,
- "nv: skipping hardreset on occupied port\n");
+ else {
+ const unsigned long *timing = sata_ehc_deb_timing(ehc);
+ int rc;
+
+ if (!(ehc->i.flags & ATA_EHI_QUIET))
+ ata_link_printk(link, KERN_INFO, "nv: skipping "
+ "hardreset on occupied port\n");
+
+ /* make sure the link is online */
+ rc = sata_link_resume(link, timing, deadline);
+ /* whine about phy resume failure but proceed */
+ if (rc && rc != -EOPNOTSUPP)
+ ata_link_printk(link, KERN_WARNING, "failed to resume "
+ "link (errno=%d)\n", rc);
+ }
/* device signature acquisition is unreliable */
return -EAGAIN;
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 6bee6af8d8e1..cb8f3e2acb25 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1268,9 +1268,13 @@ int __init devices_init(void)
sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
if (!sysfs_dev_char_kobj)
goto char_kobj_err;
+ if (pm_link_init())
+ goto pm_link_err;
return 0;
+ pm_link_err:
+ kobject_put(sysfs_dev_char_kobj);
char_kobj_err:
kobject_put(sysfs_dev_block_kobj);
block_kobj_err:
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 3ce3519e8f30..c56687ad0012 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,4 +1,4 @@
-obj-$(CONFIG_PM) += sysfs.o
+obj-$(CONFIG_PM) += sysfs.o common.o
obj-$(CONFIG_PM_SLEEP) += main.o
obj-$(CONFIG_PM_RUNTIME) += runtime.o
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c
new file mode 100644
index 000000000000..23fa9a412260
--- /dev/null
+++ b/drivers/base/power/common.c
@@ -0,0 +1,283 @@
+/*
+ * drivers/base/power/common.c - device PM common functions.
+ *
+ * Copyright (c) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/rculist.h>
+#include <linux/device.h>
+#include <linux/srcu.h>
+#include <linux/pm_link.h>
+
+#include "power.h"
+
+/**
+ * device_pm_init - Initialize the PM part of a device object.
+ * @dev: Device object being initialized.
+ */
+void device_pm_init(struct device *dev)
+{
+ spin_lock_init(&dev->power.lock);
+ init_waitqueue_head(&dev->power.wait_queue);
+ INIT_LIST_HEAD(&dev->power.master_links);
+ INIT_LIST_HEAD(&dev->power.slave_links);
+ dev->power.status = DPM_ON;
+ pm_runtime_init(dev);
+}
+
+/**
+ * device_pm_add - Handle the PM part of a device added to device tree.
+ * @dev: Device object being added to device tree.
+ */
+void device_pm_add(struct device *dev)
+{
+ pr_debug("PM: Adding info for %s:%s\n",
+ dev->bus ? dev->bus->name : "No Bus",
+ kobject_name(&dev->kobj));
+ device_pm_list_add(dev);
+}
+
+/**
+ * device_pm_remove - Handle the PM part of a device removed from device tree.
+ * @dev: Device object being removed from device tree.
+ */
+void device_pm_remove(struct device *dev)
+{
+ pr_debug("PM: Removing info for %s:%s\n",
+ dev->bus ? dev->bus->name : "No Bus",
+ kobject_name(&dev->kobj));
+ device_pm_list_remove(dev);
+ pm_runtime_remove(dev);
+ pm_link_remove_all(dev);
+}
+
+/*
+ * PM links framework.
+ *
+ * There are PM dependencies between devices that are not reflected by the
+ * structure of the device tree. In other words, as far as PM is concerned, a
+ * device may depend on some other devices which are not its children and none
+ * of which is its parent.
+ *
+ * Every such dependency involves two devices, one of which is a "master" and
+ * the other of which is a "slave", meaning that the "slave" have to be
+ * suspended before the "master" and cannot be woken up before it. Thus every
+ * device can be given two lists of "dependency objects", one for the
+ * dependencies where the device is the "master" and the other for the
+ * dependencies where the device is the "slave". Then, each "dependency object"
+ * can be represented as 'struct pm_link' as defined in include/linux/pm_link.h.
+ *
+ * The PM links of a device can help decide when the device should be suspended
+ * or resumed. Namely, In addition to checking the device's parent, the PM core
+ * can walk the list of its "masters" and check their PM status. Similarly, in
+ * addition to walking the list of a device's children, the PM core can walk the
+ * list of its "slaves".
+ */
+
+static struct srcu_struct pm_link_ss;
+static DEFINE_MUTEX(pm_link_mtx);
+
+/**
+ * pm_link_add - Create a PM link object connecting two devices.
+ * @slave: Device to be the slave in this link.
+ * @master: Device to be the master in this link.
+ */
+int pm_link_add(struct device *slave, struct device *master)
+{
+ struct pm_link *link;
+ int error = -ENODEV;
+
+ if (!get_device(master))
+ return error;
+
+ if (!get_device(slave))
+ goto err_slave;
+
+ link = kzalloc(sizeof(*link), GFP_KERNEL);
+ if (!link)
+ goto err_link;
+
+ dev_dbg(slave, "PM: Creating PM link to (master) %s %s\n",
+ dev_driver_string(master), dev_name(master));
+
+ link->master = master;
+ INIT_LIST_HEAD(&link->master_hook);
+ link->slave = slave;
+ INIT_LIST_HEAD(&link->slave_hook);
+
+ spin_lock_irq(&master->power.lock);
+ list_add_tail_rcu(&link->master_hook, &master->power.master_links);
+ spin_unlock_irq(&master->power.lock);
+
+ spin_lock_irq(&slave->power.lock);
+ list_add_tail_rcu(&link->slave_hook, &slave->power.slave_links);
+ spin_unlock_irq(&slave->power.lock);
+
+ return 0;
+
+ err_link:
+ master->power.async_suspend = false;
+ slave->power.async_suspend = false;
+ error = -ENOMEM;
+ put_device(slave);
+
+ err_slave:
+ put_device(master);
+
+ return error;
+}
+EXPORT_SYMBOL_GPL(pm_link_add);
+
+/**
+ * __pm_link_remove - Remove a PM link object.
+ * @link: PM link object to remove
+ */
+static void __pm_link_remove(struct pm_link *link)
+{
+ struct device *master = link->master;
+ struct device *slave = link->slave;
+
+ dev_dbg(slave, "PM: Removing PM link to (master) %s %s\n",
+ dev_driver_string(master), dev_name(master));
+
+ spin_lock_irq(&master->power.lock);
+ list_del_rcu(&link->master_hook);
+ spin_unlock_irq(&master->power.lock);
+
+ spin_lock_irq(&slave->power.lock);
+ list_del_rcu(&link->slave_hook);
+ spin_unlock_irq(&slave->power.lock);
+
+ synchronize_srcu(&pm_link_ss);
+
+ kfree(link);
+
+ put_device(master);
+ put_device(slave);
+}
+
+/**
+ * pm_link_remove_all - Remove all PM link objects for given device.
+ * @dev: Device to handle.
+ */
+void pm_link_remove_all(struct device *dev)
+{
+ struct pm_link *link, *n;
+
+ mutex_lock(&pm_link_mtx);
+
+ list_for_each_entry_safe(link, n, &dev->power.master_links, master_hook)
+ __pm_link_remove(link);
+
+ list_for_each_entry_safe(link, n, &dev->power.slave_links, slave_hook)
+ __pm_link_remove(link);
+
+ mutex_unlock(&pm_link_mtx);
+}
+
+/**
+ * pm_link_remove - Remove a PM link object connecting two devices.
+ * @dev: Slave device of the PM link to remove.
+ * @master: Master device of the PM link to remove.
+ */
+void pm_link_remove(struct device *dev, struct device *master)
+{
+ struct pm_link *link, *n;
+
+ mutex_lock(&pm_link_mtx);
+
+ list_for_each_entry_safe(link, n, &dev->power.slave_links, slave_hook) {
+ if (link->master != master)
+ continue;
+
+ __pm_link_remove(link);
+ break;
+ }
+
+ mutex_unlock(&pm_link_mtx);
+}
+EXPORT_SYMBOL_GPL(pm_link_remove);
+
+/**
+ * device_for_each_master - Execute given function for each master of a device.
+ * @slave: Device whose masters to execute the function for.
+ * @data: Data pointer to pass to the function.
+ * @fn: Function to execute for each master of @slave.
+ *
+ * The function is executed for the parent of the device, if there is one, and
+ * for each device connected to it via a pm_link object where @slave is the
+ * "slave".
+ */
+int device_for_each_master(struct device *slave, void *data,
+ int (*fn)(struct device *dev, void *data))
+{
+ struct pm_link *link;
+ int idx;
+ int error = 0;
+
+ if (slave->parent) {
+ error = fn(slave->parent, data);
+ if (error)
+ return error;
+ }
+
+ idx = srcu_read_lock(&pm_link_ss);
+
+ list_for_each_entry_rcu(link, &slave->power.slave_links, slave_hook) {
+ struct device *master = link->master;
+
+ error = fn(master, data);
+ if (error)
+ break;
+ }
+
+ srcu_read_unlock(&pm_link_ss, idx);
+
+ return error;
+}
+EXPORT_SYMBOL_GPL(device_for_each_master);
+
+/**
+ * device_for_each_slave - Execute given function for each slave of a device.
+ * @master: Device whose slaves to execute the function for.
+ * @data: Data pointer to pass to the function.
+ * @fn: Function to execute for each slave of @master.
+ *
+ * The function is executed for all children of the device, if there are any,
+ * and for each device connected to it via a pm_link object where @master is the
+ * "master".
+ */
+int device_for_each_slave(struct device *master, void *data,
+ int (*fn)(struct device *dev, void *data))
+{
+ struct pm_link *link;
+ int idx;
+ int error;
+
+ error = device_for_each_child(master, data, fn);
+ if (error)
+ return error;
+
+ idx = srcu_read_lock(&pm_link_ss);
+
+ list_for_each_entry_rcu(link, &master->power.master_links,
+ master_hook) {
+ struct device *slave = link->slave;
+
+ error = fn(slave, data);
+ if (error)
+ break;
+ }
+
+ srcu_read_unlock(&pm_link_ss, idx);
+
+ return error;
+}
+EXPORT_SYMBOL_GPL(device_for_each_slave);
+
+int __init pm_link_init(void)
+{
+ return init_srcu_struct(&pm_link_ss);
+}
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index e0dc4071e088..fb1c6486d5cf 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -21,10 +21,15 @@
#include <linux/kallsyms.h>
#include <linux/mutex.h>
#include <linux/pm.h>
+#include <linux/pm_link.h>
#include <linux/pm_runtime.h>
#include <linux/resume-trace.h>
#include <linux/rwsem.h>
#include <linux/interrupt.h>
+#include <linux/async.h>
+#include <linux/completion.h>
+#include <linux/time.h>
+#include <linux/sched.h>
#include "../base.h"
#include "power.h"
@@ -42,6 +47,7 @@
LIST_HEAD(dpm_list);
static DEFINE_MUTEX(dpm_list_mtx);
+static pm_message_t pm_transition;
/*
* Set once the preparation of devices for a PM transition has started, reset
@@ -50,16 +56,6 @@ static DEFINE_MUTEX(dpm_list_mtx);
static bool transition_started;
/**
- * device_pm_init - Initialize the PM-related part of a device object.
- * @dev: Device object being initialized.
- */
-void device_pm_init(struct device *dev)
-{
- dev->power.status = DPM_ON;
- pm_runtime_init(dev);
-}
-
-/**
* device_pm_lock - Lock the list of active devices used by the PM core.
*/
void device_pm_lock(void)
@@ -76,14 +72,11 @@ void device_pm_unlock(void)
}
/**
- * device_pm_add - Add a device to the PM core's list of active devices.
+ * device_pm_list_add - Add a device to the PM core's list of active devices.
* @dev: Device to add to the list.
*/
-void device_pm_add(struct device *dev)
+void device_pm_list_add(struct device *dev)
{
- pr_debug("PM: Adding info for %s:%s\n",
- dev->bus ? dev->bus->name : "No Bus",
- kobject_name(&dev->kobj));
mutex_lock(&dpm_list_mtx);
if (dev->parent) {
if (dev->parent->power.status >= DPM_SUSPENDING)
@@ -97,24 +90,19 @@ void device_pm_add(struct device *dev)
*/
dev_WARN(dev, "Parentless device registered during a PM transaction\n");
}
-
list_add_tail(&dev->power.entry, &dpm_list);
mutex_unlock(&dpm_list_mtx);
}
/**
- * device_pm_remove - Remove a device from the PM core's list of active devices.
+ * device_pm_list_remove - Remove a device from the PM core's list of devices.
* @dev: Device to be removed from the list.
*/
-void device_pm_remove(struct device *dev)
+void device_pm_list_remove(struct device *dev)
{
- pr_debug("PM: Removing info for %s:%s\n",
- dev->bus ? dev->bus->name : "No Bus",
- kobject_name(&dev->kobj));
mutex_lock(&dpm_list_mtx);
list_del_init(&dev->power.entry);
mutex_unlock(&dpm_list_mtx);
- pm_runtime_remove(dev);
}
/**
@@ -162,6 +150,150 @@ void device_pm_move_last(struct device *dev)
}
/**
+ * dpm_reset - Clear power.op_started and power.op_complete for given device.
+ * @dev: Device to handle.
+ */
+static void dpm_reset(struct device *dev)
+{
+ dev->power.op_started = false;
+ dev->power.op_complete = false;
+}
+
+/**
+ * dpm_reset_all - Call dpm_reset() for all devices.
+ */
+static void dpm_reset_all(void)
+{
+ struct device *dev;
+
+ list_for_each_entry(dev, &dpm_list, power.entry)
+ dpm_reset(dev);
+}
+
+/**
+ * dpm_synchronize_noirq - Wait for "late" or "early" PM callbacks to complete.
+ *
+ * Wait for the "late" or "early" suspend/resume callbacks of all devices to
+ * complete and clear power.op_started and power.op_complete for all devices.
+ */
+static void dpm_synchronize_noirq(void)
+{
+ async_synchronize_full();
+ dpm_reset_all();
+}
+
+/**
+ * dpm_synchronize_noirq - Wait for PM callbacks to complete.
+ *
+ * Wait for the "regular" suspend/resume callbacks of all devices to complete
+ * and clear power.op_started and power.op_complete for all devices.
+ */
+static void dpm_synchronize(void)
+{
+ async_synchronize_full();
+ mutex_lock(&dpm_list_mtx);
+ dpm_reset_all();
+ mutex_unlock(&dpm_list_mtx);
+}
+
+/**
+ * device_pm_wait - Wait for a PM operation to complete.
+ * @sub: "Slave" device.
+ * @dev: Device to wait for.
+ *
+ * Wait for a PM operation carried out for @dev to complete, unless both @sub
+ * and @dev have to be handled synchronously (in such a case they are going to
+ * be handled in the right order anyway thanks to the pm_list ordering).
+ */
+static void device_pm_wait(struct device *sub, struct device *dev)
+{
+ if (!dev)
+ return;
+
+ if (!(sub->power.async_suspend || dev->power.async_suspend))
+ return;
+
+ if (!dev->power.op_complete) {
+ dev_dbg(sub, "PM: Waiting for %s %s\n", dev_driver_string(dev),
+ dev_name(dev));
+ wait_event(dev->power.wait_queue, !!dev->power.op_complete);
+ }
+}
+
+/**
+ * device_pm_wait_fn - Wrapper for device_pm_wait().
+ * @dev: Device to wait for.
+ * @data: Pointer to the "slave" device object.
+ */
+static int device_pm_wait_fn(struct device *dev, void *data)
+{
+ device_pm_wait((struct device *)data, dev);
+ return 0;
+}
+
+/**
+ * device_pm_wait_for_masters - Wait for all masters of given device.
+ * @slave: Device to wait for the masters of.
+ */
+static void device_pm_wait_for_masters(struct device *slave)
+{
+ if (pm_async_enabled && !pm_trace_is_enabled())
+ device_for_each_master(slave, slave, device_pm_wait_fn);
+}
+
+/**
+ * device_pm_wait_for_slaves - Wait for all slaves of given device.
+ * @slave: Device to wait for the slaves of.
+ */
+static void device_pm_wait_for_slaves(struct device *master)
+{
+ if (pm_async_enabled)
+ device_for_each_slave(master, master, device_pm_wait_fn);
+}
+
+/**
+ * device_pm_check - Check the power.op_complete flag of given device.
+ * @dev: Device to check.
+ */
+static bool device_pm_check(struct device *dev)
+{
+ int ret = 0;
+
+ if (dev)
+ ret = !dev->power.op_complete;
+
+ return ret;
+}
+
+/**
+ * device_pm_check_fn - Wrapper for device_pm_check().
+ * @dev: Device to check.
+ * @data: Ignored.
+ */
+static int device_pm_check_fn(struct device *dev, void *data)
+{
+ return device_pm_check(dev);
+}
+
+/**
+ * device_pm_check_masters - Check power.op_complete for masters of a device.
+ * @slave: Device to check the masters of.
+ */
+static int device_pm_check_masters(struct device *slave)
+{
+ return device_for_each_master(slave, NULL, device_pm_check_fn);
+}
+
+/**
+ * device_pm_check_slaves - Check power.op_complete for slaves of a device.
+ * @slave: Device to check the slaves of.
+ */
+static int device_pm_check_slaves(struct device *master)
+{
+ return device_for_each_slave(master, NULL, device_pm_check_fn);
+}
+
+/**
* pm_op - Execute the PM operation appropriate for given PM event.
* @dev: Device to handle.
* @ops: PM operations to choose from.
@@ -286,6 +418,38 @@ static int pm_noirq_op(struct device *dev,
return error;
}
+/**
+ * pm_op_started - Mark the beginning of a PM operation for given device.
+ * @dev: Device to handle.
+ */
+static bool pm_op_started(struct device *dev)
+{
+ bool ret = false;
+
+ spin_lock_irq(&dev->power.lock);
+ if (dev->power.op_started)
+ ret = true;
+ else
+ dev->power.op_started = true;
+ spin_unlock_irq(&dev->power.lock);
+
+ return ret;
+}
+
+/**
+ * pm_time_elapsed - Compute time elapsed between two timestamps.
+ * @start: First timestamp.
+ * @stop: Second timestamp.
+ */
+int pm_time_elapsed(struct timeval *start, struct timeval *stop)
+{
+ s64 elapsed_msecs64;
+
+ elapsed_msecs64 = timeval_to_ns(stop) - timeval_to_ns(start);
+ do_div(elapsed_msecs64, NSEC_PER_SEC / MSEC_PER_SEC);
+ return elapsed_msecs64;
+}
+
static char *pm_verb(int event)
{
switch (event) {
@@ -310,6 +474,16 @@ static char *pm_verb(int event)
}
}
+static void dpm_show_time(struct timeval *start, struct timeval *stop,
+ pm_message_t state, const char *info)
+{
+ int centisecs = pm_time_elapsed(start, stop) / 10;
+
+ printk(KERN_INFO "PM: %s%s%s of devices complete in %d.%02d seconds\n",
+ info ? info : "", info ? " " : "", pm_verb(state.event),
+ centisecs / 100, centisecs % 100);
+}
+
static void pm_dev_dbg(struct device *dev, pm_message_t state, char *info)
{
dev_dbg(dev, "%s%s%s\n", info, pm_verb(state.event),
@@ -324,36 +498,135 @@ static void pm_dev_err(struct device *dev, pm_message_t state, char *info,
kobject_name(&dev->kobj), pm_verb(state.event), info, error);
}
+#ifdef DEBUG
+static inline void dbg_get_time(struct timeval *start)
+{
+ do_gettimeofday(start);
+}
+
+static void dbg_show_time(struct timeval *start, struct device *dev,
+ pm_message_t state, char *info)
+{
+ struct timeval stop;
+ int msecs;
+
+ do_gettimeofday(&stop);
+ msecs = pm_time_elapsed(start, &stop);
+ dev_dbg(dev, "PID %d: %s%s%s complete in %d.%03d seconds\n",
+ task_pid_nr(current), info ? info : "", info ? " " : "",
+ pm_verb(state.event), msecs / 1000, msecs % 1000);
+}
+
+#else /* !DEBUG */
+static void dbg_get_time(struct timeval *start) {}
+static void dbg_show_time(struct timeval *start, struct device *dev,
+ pm_message_t state, char *info) {}
+
+#endif /* !DEBUG */
+
/*------------------------- Resume routines -------------------------*/
/**
- * device_resume_noirq - Execute an "early resume" callback for given device.
+ * __device_resume_noirq - Execute an "early resume" callback for given device.
* @dev: Device to handle.
* @state: PM transition of the system being carried out.
*
* The driver of @dev will not receive interrupts while this function is being
* executed.
*/
-static int device_resume_noirq(struct device *dev, pm_message_t state)
+static int __device_resume_noirq(struct device *dev, pm_message_t state)
{
int error = 0;
+ struct timeval start;
+ dbg_get_time(&start);
TRACE_DEVICE(dev);
TRACE_RESUME(0);
- if (!dev->bus)
- goto End;
-
- if (dev->bus->pm) {
+ if (dev->bus && dev->bus->pm) {
pm_dev_dbg(dev, state, "EARLY ");
error = pm_noirq_op(dev, dev->bus->pm, state);
}
- End:
+
+ dev->power.op_complete = true;
+ wake_up_all(&dev->power.wait_queue);
+
TRACE_RESUME(error);
+ dbg_show_time(&start, dev, state, "EARLY");
return error;
}
/**
+ * async_device_resume_noirq - Wrapper of __device_resume_noirq().
+ * @dev: Device to resume.
+ */
+static void async_device_resume_noirq(struct device *dev)
+{
+ int error;
+
+ pm_dev_dbg(dev, pm_transition, "async EARLY ");
+ error = __device_resume_noirq(dev, pm_transition);
+ if (error)
+ pm_dev_err(dev, pm_transition, " async EARLY", error);
+}
+
+/**
+ * async_resume_noirq - Execute "early" resume callbacks asynchronously.
+ * @data: Pointer to the first device to resume.
+ * @cookie: Ignored.
+ *
+ * The execution of this function is scheduled with async_schedule(), so it runs
+ * in its own kernel thread. It first calls the "early" resume callback for the
+ * device passed to it as @data. Next, it walks dpm_list looking for devices
+ * that can be resumed without waiting for their "masters". If such a device is
+ * found, its "early" resume callback is run.
+ */
+static void async_resume_noirq(void *data, async_cookie_t cookie)
+{
+ struct device *dev = (struct device *)data;
+
+ device_pm_wait_for_masters(dev);
+ async_device_resume_noirq(dev);
+
+ list_for_each_entry_continue(dev, &dpm_list, power.entry) {
+ if (!dev->power.async_suspend || dev->power.status <= DPM_OFF)
+ continue;
+
+ if (device_pm_check_masters(dev))
+ continue;
+
+ if (pm_op_started(dev))
+ continue;
+
+ pm_dev_dbg(dev, pm_transition, "out of order EARLY ");
+ async_device_resume_noirq(dev);
+ }
+}
+
+/**
+ * device_resume_noirq - Execute or schedule "early" resume callback.
+ * @dev: Device to resume.
+ *
+ * If @dev can be resumed asynchronously, schedule the execution of
+ * async_resume_noirq() for it. Otherwise, execute its "early" resume callback
+ * directly.
+ */
+static int device_resume_noirq(struct device *dev)
+{
+ if (pm_op_started(dev))
+ return 0;
+
+ if (pm_async_enabled && dev->power.async_suspend
+ && !pm_trace_is_enabled()) {
+ async_schedule(async_resume_noirq, dev);
+ return 0;
+ }
+
+ device_pm_wait_for_masters(dev);
+ return __device_resume_noirq(dev, pm_transition);
+}
+
+/**
* dpm_resume_noirq - Execute "early resume" callbacks for non-sysdev devices.
* @state: PM transition of the system being carried out.
*
@@ -363,32 +636,43 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
void dpm_resume_noirq(pm_message_t state)
{
struct device *dev;
+ struct timeval start, stop;
+
+ do_gettimeofday(&start);
mutex_lock(&dpm_list_mtx);
transition_started = false;
+ pm_transition = state;
list_for_each_entry(dev, &dpm_list, power.entry)
if (dev->power.status > DPM_OFF) {
int error;
dev->power.status = DPM_OFF;
- error = device_resume_noirq(dev, state);
+ error = device_resume_noirq(dev);
if (error)
- pm_dev_err(dev, state, " early", error);
+ pm_dev_err(dev, state, " EARLY", error);
}
+ dpm_synchronize_noirq();
mutex_unlock(&dpm_list_mtx);
+
+ do_gettimeofday(&stop);
+ dpm_show_time(&start, &stop, state, "EARLY");
+
resume_device_irqs();
}
EXPORT_SYMBOL_GPL(dpm_resume_noirq);
/**
- * device_resume - Execute "resume" callbacks for given device.
+ * __device_resume - Execute "resume" callbacks for given device.
* @dev: Device to handle.
* @state: PM transition of the system being carried out.
*/
-static int device_resume(struct device *dev, pm_message_t state)
+static int __device_resume(struct device *dev, pm_message_t state)
{
int error = 0;
+ struct timeval start;
+ dbg_get_time(&start);
TRACE_DEVICE(dev);
TRACE_RESUME(0);
@@ -426,12 +710,94 @@ static int device_resume(struct device *dev, pm_message_t state)
}
End:
up(&dev->sem);
+ dev->power.op_complete = true;
+ wake_up_all(&dev->power.wait_queue);
TRACE_RESUME(error);
+ dbg_show_time(&start, dev, state, NULL);
return error;
}
/**
+ * async_device_resume - Wrapper of __device_resume().
+ * @dev: Device to resume.
+ */
+static void async_device_resume(struct device *dev)
+{
+ int error;
+
+ pm_dev_dbg(dev, pm_transition, "async ");
+ error = __device_resume(dev, pm_transition);
+ if (error)
+ pm_dev_err(dev, pm_transition, " async", error);
+}
+
+/**
+ * async_resume - Execute resume callbacks asynchronously.
+ * @data: Pointer to the first device to resume.
+ * @cookie: Ignored.
+ *
+ * The execution of this function is scheduled with async_schedule(), so it runs
+ * in its own kernel thread. It first calls the resume callbacks for the device
+ * passed to it as @data. Next, it walks dpm_list looking for devices that can
+ * be resumed without waiting for their "masters". If such a device is found,
+ * its resume callbacks are run.
+ */
+static void async_resume(void *data, async_cookie_t cookie)
+{
+ struct device *dev = (struct device *)data;
+
+ device_pm_wait_for_masters(dev);
+
+ repeat:
+ async_device_resume(dev);
+ put_device(dev);
+
+ mutex_lock(&dpm_list_mtx);
+ if (dev->power.status < DPM_OFF)
+ dev = to_device(dpm_list.next);
+ list_for_each_entry_continue(dev, &dpm_list, power.entry) {
+ if (!dev->power.async_suspend || dev->power.status < DPM_OFF)
+ continue;
+
+ if (device_pm_check_masters(dev))
+ continue;
+
+ if (pm_op_started(dev))
+ continue;
+
+ get_device(dev);
+ mutex_unlock(&dpm_list_mtx);
+ pm_dev_dbg(dev, pm_transition, "out of order ");
+ goto repeat;
+ }
+ mutex_unlock(&dpm_list_mtx);
+}
+
+/**
+ * device_resume - Execute or schedule resume callbacks for given device.
+ * @dev: Device to resume.
+ *
+ * If @dev can be resumed asynchronously, schedule the execution of
+ * async_resume() for it. Otherwise, execute its resume callbacks directly.
+ */
+static int device_resume(struct device *dev)
+{
+ if (pm_op_started(dev))
+ return 0;
+
+ if (pm_async_enabled && dev->power.async_suspend
+ && !pm_trace_is_enabled()) {
+ get_device(dev);
+ async_schedule(async_resume, dev);
+ return 0;
+ }
+
+ device_pm_wait_for_masters(dev);
+ return __device_resume(dev, pm_transition);
+}
+
+/**
* dpm_resume - Execute "resume" callbacks for non-sysdev devices.
* @state: PM transition of the system being carried out.
*
@@ -441,9 +807,13 @@ static int device_resume(struct device *dev, pm_message_t state)
static void dpm_resume(pm_message_t state)
{
struct list_head list;
+ struct timeval start, stop;
+
+ do_gettimeofday(&start);
INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx);
+ pm_transition = state;
while (!list_empty(&dpm_list)) {
struct device *dev = to_device(dpm_list.next);
@@ -454,7 +824,7 @@ static void dpm_resume(pm_message_t state)
dev->power.status = DPM_RESUMING;
mutex_unlock(&dpm_list_mtx);
- error = device_resume(dev, state);
+ error = device_resume(dev);
mutex_lock(&dpm_list_mtx);
if (error)
@@ -469,6 +839,10 @@ static void dpm_resume(pm_message_t state)
}
list_splice(&list, &dpm_list);
mutex_unlock(&dpm_list_mtx);
+ dpm_synchronize();
+
+ do_gettimeofday(&stop);
+ dpm_show_time(&start, &stop, state, NULL);
}
/**
@@ -550,6 +924,8 @@ EXPORT_SYMBOL_GPL(dpm_resume_end);
/*------------------------- Suspend routines -------------------------*/
+static atomic_t async_error;
+
/**
* resume_event - Return a "resume" message for given "suspend" sleep state.
* @sleep_state: PM message representing a sleep state.
@@ -579,21 +955,104 @@ static pm_message_t resume_event(pm_message_t sleep_state)
* The driver of @dev will not receive interrupts while this function is being
* executed.
*/
-static int device_suspend_noirq(struct device *dev, pm_message_t state)
+static int __device_suspend_noirq(struct device *dev, pm_message_t state)
{
int error = 0;
+ struct timeval start;
- if (!dev->bus)
- return 0;
+ dbg_get_time(&start);
- if (dev->bus->pm) {
+ if (dev->bus && dev->bus->pm) {
pm_dev_dbg(dev, state, "LATE ");
error = pm_noirq_op(dev, dev->bus->pm, state);
}
+
+ dev->power.op_complete = true;
+ wake_up_all(&dev->power.wait_queue);
+
+ dbg_show_time(&start, dev, state, "LATE");
return error;
}
/**
+ * async_device_suspend_noirq - Wrapper of __device_suspend_noirq().
+ * @dev: Device to suspend.
+ *
+ * Execute __device_suspend_noirq() for given device unless async_error is
+ * set and if that returns error code, copy it to async_error and change the
+ * PM status of @dev to DPM_OFF.
+ */
+static void async_device_suspend_noirq(struct device *dev)
+{
+ int error = atomic_read(&async_error);
+
+ if (error)
+ return;
+ pm_dev_dbg(dev, pm_transition, "async LATE ");
+ error = __device_suspend_noirq(dev, pm_transition);
+ if (!error)
+ return;
+ pm_dev_err(dev, pm_transition, " async LATE", error);
+ dev->power.status = DPM_OFF;
+ atomic_set(&async_error, error);
+}
+
+/**
+ * async_suspend_noirq - Execute "late" suspend callbacks asynchronously.
+ * @data: Pointer to the first device to suspend.
+ * @cookie: Ignored.
+ *
+ * The execution of this function is scheduled with async_schedule(), so it runs
+ * in its own kernel thread. It first calls the "late" suspend callback for the
+ * device passed to it as @data. Next, it walks dpm_list looking for devices
+ * that can be suspended without waiting for their "slaves". If such a device
+ * is found, its "late" suspend callback is run.
+ */
+static void async_suspend_noirq(void *data, async_cookie_t cookie)
+{
+ struct device *dev = (struct device *)data;
+
+ device_pm_wait_for_slaves(dev);
+ async_device_suspend_noirq(dev);
+
+ list_for_each_entry_continue_reverse(dev, &dpm_list, power.entry) {
+ if (!dev->power.async_suspend)
+ continue;
+
+ if (device_pm_check_slaves(dev))
+ continue;
+
+ if (pm_op_started(dev))
+ continue;
+
+ pm_dev_dbg(dev, pm_transition, "out of order LATE ");
+ async_device_suspend_noirq(dev);
+ }
+}
+
+/**
+ * device_suspend_noirq - Execute or schedule "late" suspend callback.
+ * @dev: Device to suspend.
+ *
+ * If @dev can be resumed asynchronously, schedule the execution of
+ * async_suspend_noirq() for it. Otherwise, execute its "late" suspend callback
+ * directly.
+ */
+static int device_suspend_noirq(struct device *dev)
+{
+ if (pm_op_started(dev))
+ return 0;
+
+ if (pm_async_enabled && dev->power.async_suspend) {
+ async_schedule(async_suspend_noirq, dev);
+ return 0;
+ }
+
+ device_pm_wait_for_slaves(dev);
+ return __device_suspend_noirq(dev, pm_transition);
+}
+
+/**
* dpm_suspend_noirq - Execute "late suspend" callbacks for non-sysdev devices.
* @state: PM transition of the system being carried out.
*
@@ -603,21 +1062,34 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
int dpm_suspend_noirq(pm_message_t state)
{
struct device *dev;
+ struct timeval start, stop;
int error = 0;
+ do_gettimeofday(&start);
+
suspend_device_irqs();
mutex_lock(&dpm_list_mtx);
+ pm_transition = state;
list_for_each_entry_reverse(dev, &dpm_list, power.entry) {
- error = device_suspend_noirq(dev, state);
+ dev->power.status = DPM_OFF_IRQ;
+ error = device_suspend_noirq(dev);
if (error) {
- pm_dev_err(dev, state, " late", error);
+ pm_dev_err(dev, state, " LATE", error);
+ dev->power.status = DPM_OFF;
break;
}
- dev->power.status = DPM_OFF_IRQ;
+ error = atomic_read(&async_error);
+ if (error)
+ break;
}
+ dpm_synchronize_noirq();
mutex_unlock(&dpm_list_mtx);
- if (error)
+ if (error) {
dpm_resume_noirq(resume_event(state));
+ } else {
+ do_gettimeofday(&stop);
+ dpm_show_time(&start, &stop, state, "LATE");
+ }
return error;
}
EXPORT_SYMBOL_GPL(dpm_suspend_noirq);
@@ -627,9 +1099,12 @@ EXPORT_SYMBOL_GPL(dpm_suspend_noirq);
* @dev: Device to handle.
* @state: PM transition of the system being carried out.
*/
-static int device_suspend(struct device *dev, pm_message_t state)
+static int __device_suspend(struct device *dev, pm_message_t state)
{
int error = 0;
+ struct timeval start;
+
+ dbg_get_time(&start);
down(&dev->sem);
@@ -667,42 +1142,149 @@ static int device_suspend(struct device *dev, pm_message_t state)
}
End:
up(&dev->sem);
+ dev->power.op_complete = true;
+ wake_up_all(&dev->power.wait_queue);
+ dbg_show_time(&start, dev, state, NULL);
return error;
}
/**
+ * async_device_suspend - Wrapper of __device_suspend().
+ * @dev: Device to suspend.
+ *
+ * Execute __device_suspend() for given device unless async_error is set and if
+ * that returns error code, copy it to async_error and change the PM status of
+ * @dev to DPM_SUSPENDING.
+ */
+static void async_device_suspend(struct device *dev)
+{
+ int error = atomic_read(&async_error);
+
+ if (error)
+ return;
+ pm_dev_dbg(dev, pm_transition, "async ");
+ error = __device_suspend(dev, pm_transition);
+ if (!error)
+ return;
+ pm_dev_err(dev, pm_transition, " async", error);
+ mutex_lock(&dpm_list_mtx);
+ dev->power.status = DPM_SUSPENDING;
+ atomic_set(&async_error, error);
+ mutex_unlock(&dpm_list_mtx);
+}
+
+/**
+ * async_suspend - Execute suspend callbacks asynchronously.
+ * @data: Pointer to the first device to resume.
+ * @cookie: Ignored.
+ *
+ * The execution of this function is scheduled with async_schedule(), so it runs
+ * in its own kernel thread. It first calls the suspend callbacks for the
+ * device passed to it as @data. Next, it walks dpm_list looking for devices
+ * that can be suspended without waiting for their "slaves". If such a device
+ * is found, its suspend callbacks are run.
+ */
+static void async_suspend(void *data, async_cookie_t cookie)
+{
+ struct device *dev = (struct device *)data;
+
+ device_pm_wait_for_slaves(dev);
+
+ repeat:
+ async_device_suspend(dev);
+ put_device(dev);
+
+ mutex_lock(&dpm_list_mtx);
+ if (dev->power.status >= DPM_OFF)
+ dev = to_device(dpm_list.prev);
+ list_for_each_entry_continue_reverse(dev, &dpm_list, power.entry) {
+ if (!dev->power.async_suspend)
+ continue;
+
+ if (device_pm_check_slaves(dev))
+ continue;
+
+ if (pm_op_started(dev))
+ continue;
+
+ get_device(dev);
+ mutex_unlock(&dpm_list_mtx);
+ pm_dev_dbg(dev, pm_transition, "out of order ");
+ goto repeat;
+ }
+ mutex_unlock(&dpm_list_mtx);
+}
+
+/**
+ * device_suspend - Execute or schedule suspend callbacks for given device.
+ * @dev: Device to suspend.
+ *
+ * If @dev can be suspended asynchronously, schedule the execution of
+ * async_suspend() for it. Otherwise, execute its suspend callbacks directly.
+ */
+static int device_suspend(struct device *dev)
+{
+ if (pm_op_started(dev))
+ return 0;
+
+ if (pm_async_enabled && dev->power.async_suspend) {
+ get_device(dev);
+ async_schedule(async_suspend, dev);
+ return 0;
+ }
+
+ device_pm_wait_for_slaves(dev);
+ return __device_suspend(dev, pm_transition);
+}
+
+/**
* dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices.
* @state: PM transition of the system being carried out.
*/
static int dpm_suspend(pm_message_t state)
{
struct list_head list;
+ struct timeval start, stop;
int error = 0;
+ do_gettimeofday(&start);
+
INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx);
+ pm_transition = state;
while (!list_empty(&dpm_list)) {
struct device *dev = to_device(dpm_list.prev);
get_device(dev);
+ dev->power.status = DPM_OFF;
mutex_unlock(&dpm_list_mtx);
- error = device_suspend(dev, state);
+ error = device_suspend(dev);
mutex_lock(&dpm_list_mtx);
if (error) {
pm_dev_err(dev, state, "", error);
+ dev->power.status = DPM_SUSPENDING;
put_device(dev);
break;
}
- dev->power.status = DPM_OFF;
if (!list_empty(&dev->power.entry))
list_move(&dev->power.entry, &list);
put_device(dev);
+ error = atomic_read(&async_error);
+ if (error)
+ break;
}
list_splice(&list, dpm_list.prev);
mutex_unlock(&dpm_list_mtx);
+ dpm_synchronize();
+
+ if (!error) {
+ do_gettimeofday(&stop);
+ dpm_show_time(&start, &stop, state, NULL);
+ }
+
return error;
}
@@ -761,6 +1343,7 @@ static int dpm_prepare(pm_message_t state)
INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx);
transition_started = true;
+ atomic_set(&async_error, 0);
while (!list_empty(&dpm_list)) {
struct device *dev = to_device(dpm_list.next);
@@ -792,8 +1375,10 @@ static int dpm_prepare(pm_message_t state)
break;
}
dev->power.status = DPM_SUSPENDING;
- if (!list_empty(&dev->power.entry))
+ if (!list_empty(&dev->power.entry)) {
list_move_tail(&dev->power.entry, &list);
+ dpm_reset(dev);
+ }
put_device(dev);
}
list_splice(&list, &dpm_list);
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index b8fa1aa5225a..30f985c1a300 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -12,10 +12,10 @@ static inline void pm_runtime_remove(struct device *dev) {}
#ifdef CONFIG_PM_SLEEP
-/*
- * main.c
- */
+/* kernel/power/main.c */
+extern int pm_async_enabled;
+/* drivers/base/power/main.c */
extern struct list_head dpm_list; /* The active device list */
static inline struct device *to_device(struct list_head *entry)
@@ -23,7 +23,8 @@ static inline struct device *to_device(struct list_head *entry)
return container_of(entry, struct device, power.entry);
}
-extern void device_pm_init(struct device *dev);
+extern void device_pm_list_add(struct device *dev);
+extern void device_pm_list_remove(struct device *dev);
extern void device_pm_add(struct device *);
extern void device_pm_remove(struct device *);
extern void device_pm_move_before(struct device *, struct device *);
@@ -32,17 +33,8 @@ extern void device_pm_move_last(struct device *);
#else /* !CONFIG_PM_SLEEP */
-static inline void device_pm_init(struct device *dev)
-{
- pm_runtime_init(dev);
-}
-
-static inline void device_pm_remove(struct device *dev)
-{
- pm_runtime_remove(dev);
-}
-
-static inline void device_pm_add(struct device *dev) {}
+static inline void device_pm_list_add(struct device *dev) {}
+static inline void device_pm_list_remove(struct device *dev) {}
static inline void device_pm_move_before(struct device *deva,
struct device *devb) {}
static inline void device_pm_move_after(struct device *deva,
@@ -53,6 +45,11 @@ static inline void device_pm_move_last(struct device *dev) {}
#ifdef CONFIG_PM
+/* drivers/base/power/common.c */
+extern void device_pm_init(struct device *dev);
+extern void device_pm_add(struct device *dev);
+extern void device_pm_remove(struct device *dev);
+
/*
* sysfs.c
*/
@@ -60,7 +57,15 @@ static inline void device_pm_move_last(struct device *dev) {}
extern int dpm_sysfs_add(struct device *);
extern void dpm_sysfs_remove(struct device *);
-#else /* CONFIG_PM */
+/* drivers/base/power/link.c */
+extern int pm_link_init(void);
+extern void pm_link_remove_all(struct device *dev);
+
+#else /* !CONFIG_PM */
+
+static inline void device_pm_init(struct device *dev) {}
+static inline void device_pm_add(struct device *dev) {}
+static inline void device_pm_remove(struct device *dev) {}
static inline int dpm_sysfs_add(struct device *dev)
{
@@ -71,4 +76,7 @@ static inline void dpm_sysfs_remove(struct device *dev)
{
}
-#endif
+static inline int pm_link_init(void) { return 0; }
+static inline void pm_link_remove_all(struct device *dev) {}
+
+#endif /* !CONFIG_PM */
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 38556f6cc22d..7a6e461584e6 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -972,8 +972,6 @@ EXPORT_SYMBOL_GPL(pm_runtime_enable);
*/
void pm_runtime_init(struct device *dev)
{
- spin_lock_init(&dev->power.lock);
-
dev->power.runtime_status = RPM_SUSPENDED;
dev->power.idle_notification = false;
@@ -993,8 +991,6 @@ void pm_runtime_init(struct device *dev)
dev->power.timer_expires = 0;
setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn,
(unsigned long)dev);
-
- init_waitqueue_head(&dev->power.wait_queue);
}
/**
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 596aeecfdffe..1970449e6290 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -38,6 +38,22 @@
* wakeup events internally (unless they are disabled), keeping
* their hardware in low power modes whenever they're unused. This
* saves runtime power, without requiring system-wide sleep states.
+ *
+ * async - Report/change current async suspend setting for the device
+ *
+ * If set, the PM core will attempt to suspend and resume the device during
+ * system power transitions (e.g. suspend to RAM, hibernation) in parallel
+ * with other devices it doesn't appear to depend on (to the PM core's
+ * knowledge).
+ *
+ * + "enabled\n" to permit the asynchronous suspend/resume of the device
+ * + "disabled\n" to forbid it
+ *
+ * NOTE: It generally is unsafe to permit the asynchronous suspend/resume
+ * of a device unless it is certain that all of the PM dependencies of the
+ * device are known to the PM core. However, for some devices this
+ * attribute is set to "enabled" by the kernel and in that cases it should
+ * be safe to leave the default value.
*/
static const char enabled[] = "enabled";
@@ -77,9 +93,40 @@ wake_store(struct device * dev, struct device_attribute *attr,
static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
+#ifdef CONFIG_PM_SLEEP_ADVANCED_DEBUG
+static ssize_t async_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n",
+ device_async_suspend_enabled(dev) ? enabled : disabled);
+}
+
+static ssize_t async_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+ char *cp;
+ int len = n;
+
+ cp = memchr(buf, '\n', n);
+ if (cp)
+ len = cp - buf;
+ if (len == sizeof enabled - 1 && strncmp(buf, enabled, len) == 0)
+ device_enable_async_suspend(dev, true);
+ else if (len == sizeof disabled - 1 && strncmp(buf, disabled, len) == 0)
+ device_enable_async_suspend(dev, false);
+ else
+ return -EINVAL;
+ return n;
+}
+
+static DEVICE_ATTR(async, 0644, async_show, async_store);
+#endif /* CONFIG_PM_SLEEP_ADVANCED_DEBUG */
static struct attribute * power_attrs[] = {
&dev_attr_wakeup.attr,
+#ifdef CONFIG_PM_SLEEP_ADVANCED_DEBUG
+ &dev_attr_async.attr,
+#endif
NULL,
};
static struct attribute_group pm_attr_group = {
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 1d886e079c58..77bfce52e9ca 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -271,6 +271,8 @@ config BLK_DEV_CRYPTOLOOP
instead, which can be configured to be on-disk compatible with the
cryptoloop device.
+source "drivers/block/drbd/Kconfig"
+
config BLK_DEV_NBD
tristate "Network block device support"
depends on NET
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index cdaa3f8fddf0..aff5ac925c34 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -36,5 +36,6 @@ obj-$(CONFIG_BLK_DEV_UB) += ub.o
obj-$(CONFIG_BLK_DEV_HD) += hd.o
obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o
+obj-$(CONFIG_BLK_DEV_DRBD) += drbd/
swim_mod-objs := swim.o swim_asm.o
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 965ece2c7e4d..437b95b15829 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -982,8 +982,12 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
}
sysminor = SYSMINOR(aoemajor, h->minor);
- if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) {
- printk(KERN_INFO "aoe: e%ld.%d: minor number too large\n",
+ if (h->minor >= NPERSHELF) {
+ printk(KERN_INFO "aoe: e%ld.%d: AoE minor address too large\n",
+ aoemajor, (int) h->minor);
+ return;
+ } else if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) {
+ printk(KERN_INFO "aoe: e%ld.%d: AoE major address too large\n",
aoemajor, (int) h->minor);
return;
}
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 847a9e57570a..a5af1d6dda8b 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -1478,10 +1478,7 @@ void do_fd_request(struct request_queue * q)
stdma_lock(floppy_irq, NULL);
atari_disable_irq( IRQ_MFP_FDC );
- local_save_flags(flags); /* The request function is called with ints
- local_irq_disable(); * disabled... so must save the IPL for later */
redo_fd_request();
- local_irq_restore(flags);
atari_enable_irq( IRQ_MFP_FDC );
}
diff --git a/drivers/block/drbd/Kconfig b/drivers/block/drbd/Kconfig
new file mode 100644
index 000000000000..f4acd04ebeef
--- /dev/null
+++ b/drivers/block/drbd/Kconfig
@@ -0,0 +1,71 @@
+#
+# DRBD device driver configuration
+#
+
+comment "DRBD disabled because PROC_FS, INET or CONNECTOR not selected"
+ depends on !PROC_FS || !INET || !CONNECTOR
+
+config BLK_DEV_DRBD
+ tristate "DRBD Distributed Replicated Block Device support"
+ depends on PROC_FS && INET && CONNECTOR
+ select LRU_CACHE
+ default n
+ help
+
+ NOTE: In order to authenticate connections you have to select
+ CRYPTO_HMAC and a hash function as well.
+
+ DRBD is a shared-nothing, synchronously replicated block device. It
+ is designed to serve as a building block for high availability
+ clusters and in this context, is a "drop-in" replacement for shared
+ storage. Simplistically, you could see it as a network RAID 1.
+
+ Each minor device has a role, which can be 'primary' or 'secondary'.
+ On the node with the primary device the application is supposed to
+ run and to access the device (/dev/drbdX). Every write is sent to
+ the local 'lower level block device' and, across the network, to the
+ node with the device in 'secondary' state. The secondary device
+ simply writes the data to its lower level block device.
+
+ DRBD can also be used in dual-Primary mode (device writable on both
+ nodes), which means it can exhibit shared disk semantics in a
+ shared-nothing cluster. Needless to say, on top of dual-Primary
+ DRBD utilizing a cluster file system is necessary to maintain for
+ cache coherency.
+
+ For automatic failover you need a cluster manager (e.g. heartbeat).
+ See also: http://www.drbd.org/, http://www.linux-ha.org
+
+ If unsure, say N.
+
+config DRBD_FAULT_INJECTION
+ bool "DRBD fault injection"
+ depends on BLK_DEV_DRBD
+ help
+
+ Say Y here if you want to simulate IO errors, in order to test DRBD's
+ behavior.
+
+ The actual simulation of IO errors is done by writing 3 values to
+ /sys/module/drbd/parameters/
+
+ enable_faults: bitmask of...
+ 1 meta data write
+ 2 read
+ 4 resync data write
+ 8 read
+ 16 data write
+ 32 data read
+ 64 read ahead
+ 128 kmalloc of bitmap
+ 256 allocation of EE (epoch_entries)
+
+ fault_devs: bitmask of minor numbers
+ fault_rate: frequency in percent
+
+ Example: Simulate data write errors on /dev/drbd0 with a probability of 5%.
+ echo 16 > /sys/module/drbd/parameters/enable_faults
+ echo 1 > /sys/module/drbd/parameters/fault_devs
+ echo 5 > /sys/module/drbd/parameters/fault_rate
+
+ If unsure, say N.
diff --git a/drivers/block/drbd/Makefile b/drivers/block/drbd/Makefile
new file mode 100644
index 000000000000..0d3f337ff5ff
--- /dev/null
+++ b/drivers/block/drbd/Makefile
@@ -0,0 +1,5 @@
+drbd-y := drbd_bitmap.o drbd_proc.o
+drbd-y += drbd_worker.o drbd_receiver.o drbd_req.o drbd_actlog.o
+drbd-y += drbd_main.o drbd_strings.o drbd_nl.o
+
+obj-$(CONFIG_BLK_DEV_DRBD) += drbd.o
diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c
new file mode 100644
index 000000000000..17956ff6a08d
--- /dev/null
+++ b/drivers/block/drbd/drbd_actlog.c
@@ -0,0 +1,1424 @@
+/*
+ drbd_actlog.c
+
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2003-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 2003-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+ Copyright (C) 2003-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+ drbd 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.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT 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 drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/slab.h>
+#include <linux/drbd.h>
+#include "drbd_int.h"
+#include "drbd_wrappers.h"
+
+/* We maintain a trivial check sum in our on disk activity log.
+ * With that we can ensure correct operation even when the storage
+ * device might do a partial (last) sector write while loosing power.
+ */
+struct __packed al_transaction {
+ u32 magic;
+ u32 tr_number;
+ struct __packed {
+ u32 pos;
+ u32 extent; } updates[1 + AL_EXTENTS_PT];
+ u32 xor_sum;
+};
+
+struct update_odbm_work {
+ struct drbd_work w;
+ unsigned int enr;
+};
+
+struct update_al_work {
+ struct drbd_work w;
+ struct lc_element *al_ext;
+ struct completion event;
+ unsigned int enr;
+ /* if old_enr != LC_FREE, write corresponding bitmap sector, too */
+ unsigned int old_enr;
+};
+
+struct drbd_atodb_wait {
+ atomic_t count;
+ struct completion io_done;
+ struct drbd_conf *mdev;
+ int error;
+};
+
+
+int w_al_write_transaction(struct drbd_conf *, struct drbd_work *, int);
+
+static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
+ struct drbd_backing_dev *bdev,
+ struct page *page, sector_t sector,
+ int rw, int size)
+{
+ struct bio *bio;
+ struct drbd_md_io md_io;
+ int ok;
+
+ md_io.mdev = mdev;
+ init_completion(&md_io.event);
+ md_io.error = 0;
+
+ if ((rw & WRITE) && !test_bit(MD_NO_BARRIER, &mdev->flags))
+ rw |= (1 << BIO_RW_BARRIER);
+ rw |= ((1<<BIO_RW_UNPLUG) | (1<<BIO_RW_SYNCIO));
+
+ retry:
+ bio = bio_alloc(GFP_NOIO, 1);
+ bio->bi_bdev = bdev->md_bdev;
+ bio->bi_sector = sector;
+ ok = (bio_add_page(bio, page, size, 0) == size);
+ if (!ok)
+ goto out;
+ bio->bi_private = &md_io;
+ bio->bi_end_io = drbd_md_io_complete;
+ bio->bi_rw = rw;
+
+ if (FAULT_ACTIVE(mdev, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD))
+ bio_endio(bio, -EIO);
+ else
+ submit_bio(rw, bio);
+ wait_for_completion(&md_io.event);
+ ok = bio_flagged(bio, BIO_UPTODATE) && md_io.error == 0;
+
+ /* check for unsupported barrier op.
+ * would rather check on EOPNOTSUPP, but that is not reliable.
+ * don't try again for ANY return value != 0 */
+ if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER) && !ok)) {
+ /* Try again with no barrier */
+ dev_warn(DEV, "Barriers not supported on meta data device - disabling\n");
+ set_bit(MD_NO_BARRIER, &mdev->flags);
+ rw &= ~(1 << BIO_RW_BARRIER);
+ bio_put(bio);
+ goto retry;
+ }
+ out:
+ bio_put(bio);
+ return ok;
+}
+
+int drbd_md_sync_page_io(struct drbd_conf *mdev, struct drbd_backing_dev *bdev,
+ sector_t sector, int rw)
+{
+ int logical_block_size, mask, ok;
+ int offset = 0;
+ struct page *iop = mdev->md_io_page;
+
+ D_ASSERT(mutex_is_locked(&mdev->md_io_mutex));
+
+ BUG_ON(!bdev->md_bdev);
+
+ logical_block_size = bdev_logical_block_size(bdev->md_bdev);
+ if (logical_block_size == 0)
+ logical_block_size = MD_SECTOR_SIZE;
+
+ /* in case logical_block_size != 512 [ s390 only? ] */
+ if (logical_block_size != MD_SECTOR_SIZE) {
+ mask = (logical_block_size / MD_SECTOR_SIZE) - 1;
+ D_ASSERT(mask == 1 || mask == 3 || mask == 7);
+ D_ASSERT(logical_block_size == (mask+1) * MD_SECTOR_SIZE);
+ offset = sector & mask;
+ sector = sector & ~mask;
+ iop = mdev->md_io_tmpp;
+
+ if (rw & WRITE) {
+ /* these are GFP_KERNEL pages, pre-allocated
+ * on device initialization */
+ void *p = page_address(mdev->md_io_page);
+ void *hp = page_address(mdev->md_io_tmpp);
+
+ ok = _drbd_md_sync_page_io(mdev, bdev, iop, sector,
+ READ, logical_block_size);
+
+ if (unlikely(!ok)) {
+ dev_err(DEV, "drbd_md_sync_page_io(,%llus,"
+ "READ [logical_block_size!=512]) failed!\n",
+ (unsigned long long)sector);
+ return 0;
+ }
+
+ memcpy(hp + offset*MD_SECTOR_SIZE, p, MD_SECTOR_SIZE);
+ }
+ }
+
+ if (sector < drbd_md_first_sector(bdev) ||
+ sector > drbd_md_last_sector(bdev))
+ dev_alert(DEV, "%s [%d]:%s(,%llus,%s) out of range md access!\n",
+ current->comm, current->pid, __func__,
+ (unsigned long long)sector, (rw & WRITE) ? "WRITE" : "READ");
+
+ ok = _drbd_md_sync_page_io(mdev, bdev, iop, sector, rw, logical_block_size);
+ if (unlikely(!ok)) {
+ dev_err(DEV, "drbd_md_sync_page_io(,%llus,%s) failed!\n",
+ (unsigned long long)sector, (rw & WRITE) ? "WRITE" : "READ");
+ return 0;
+ }
+
+ if (logical_block_size != MD_SECTOR_SIZE && !(rw & WRITE)) {
+ void *p = page_address(mdev->md_io_page);
+ void *hp = page_address(mdev->md_io_tmpp);
+
+ memcpy(p, hp + offset*MD_SECTOR_SIZE, MD_SECTOR_SIZE);
+ }
+
+ return ok;
+}
+
+static struct lc_element *_al_get(struct drbd_conf *mdev, unsigned int enr)
+{
+ struct lc_element *al_ext;
+ struct lc_element *tmp;
+ unsigned long al_flags = 0;
+
+ spin_lock_irq(&mdev->al_lock);
+ tmp = lc_find(mdev->resync, enr/AL_EXT_PER_BM_SECT);
+ if (unlikely(tmp != NULL)) {
+ struct bm_extent *bm_ext = lc_entry(tmp, struct bm_extent, lce);
+ if (test_bit(BME_NO_WRITES, &bm_ext->flags)) {
+ spin_unlock_irq(&mdev->al_lock);
+ return NULL;
+ }
+ }
+ al_ext = lc_get(mdev->act_log, enr);
+ al_flags = mdev->act_log->flags;
+ spin_unlock_irq(&mdev->al_lock);
+
+ /*
+ if (!al_ext) {
+ if (al_flags & LC_STARVING)
+ dev_warn(DEV, "Have to wait for LRU element (AL too small?)\n");
+ if (al_flags & LC_DIRTY)
+ dev_warn(DEV, "Ongoing AL update (AL device too slow?)\n");
+ }
+ */
+
+ return al_ext;
+}
+
+void drbd_al_begin_io(struct drbd_conf *mdev, sector_t sector)
+{
+ unsigned int enr = (sector >> (AL_EXTENT_SHIFT-9));
+ struct lc_element *al_ext;
+ struct update_al_work al_work;
+
+ D_ASSERT(atomic_read(&mdev->local_cnt) > 0);
+
+ wait_event(mdev->al_wait, (al_ext = _al_get(mdev, enr)));
+
+ if (al_ext->lc_number != enr) {
+ /* drbd_al_write_transaction(mdev,al_ext,enr);
+ * recurses into generic_make_request(), which
+ * disallows recursion, bios being serialized on the
+ * current->bio_tail list now.
+ * we have to delegate updates to the activity log
+ * to the worker thread. */
+ init_completion(&al_work.event);
+ al_work.al_ext = al_ext;
+ al_work.enr = enr;
+ al_work.old_enr = al_ext->lc_number;
+ al_work.w.cb = w_al_write_transaction;
+ drbd_queue_work_front(&mdev->data.work, &al_work.w);
+ wait_for_completion(&al_work.event);
+
+ mdev->al_writ_cnt++;
+
+ spin_lock_irq(&mdev->al_lock);
+ lc_changed(mdev->act_log, al_ext);
+ spin_unlock_irq(&mdev->al_lock);
+ wake_up(&mdev->al_wait);
+ }
+}
+
+void drbd_al_complete_io(struct drbd_conf *mdev, sector_t sector)
+{
+ unsigned int enr = (sector >> (AL_EXTENT_SHIFT-9));
+ struct lc_element *extent;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdev->al_lock, flags);
+
+ extent = lc_find(mdev->act_log, enr);
+
+ if (!extent) {
+ spin_unlock_irqrestore(&mdev->al_lock, flags);
+ dev_err(DEV, "al_complete_io() called on inactive extent %u\n", enr);
+ return;
+ }
+
+ if (lc_put(mdev->act_log, extent) == 0)
+ wake_up(&mdev->al_wait);
+
+ spin_unlock_irqrestore(&mdev->al_lock, flags);
+}
+
+int
+w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused)
+{
+ struct update_al_work *aw = container_of(w, struct update_al_work, w);
+ struct lc_element *updated = aw->al_ext;
+ const unsigned int new_enr = aw->enr;
+ const unsigned int evicted = aw->old_enr;
+ struct al_transaction *buffer;
+ sector_t sector;
+ int i, n, mx;
+ unsigned int extent_nr;
+ u32 xor_sum = 0;
+
+ if (!get_ldev(mdev)) {
+ dev_err(DEV, "get_ldev() failed in w_al_write_transaction\n");
+ complete(&((struct update_al_work *)w)->event);
+ return 1;
+ }
+ /* do we have to do a bitmap write, first?
+ * TODO reduce maximum latency:
+ * submit both bios, then wait for both,
+ * instead of doing two synchronous sector writes. */
+ if (mdev->state.conn < C_CONNECTED && evicted != LC_FREE)
+ drbd_bm_write_sect(mdev, evicted/AL_EXT_PER_BM_SECT);
+
+ mutex_lock(&mdev->md_io_mutex); /* protects md_io_page, al_tr_cycle, ... */
+ buffer = (struct al_transaction *)page_address(mdev->md_io_page);
+
+ buffer->magic = __constant_cpu_to_be32(DRBD_MAGIC);
+ buffer->tr_number = cpu_to_be32(mdev->al_tr_number);
+
+ n = lc_index_of(mdev->act_log, updated);
+
+ buffer->updates[0].pos = cpu_to_be32(n);
+ buffer->updates[0].extent = cpu_to_be32(new_enr);
+
+ xor_sum ^= new_enr;
+
+ mx = min_t(int, AL_EXTENTS_PT,
+ mdev->act_log->nr_elements - mdev->al_tr_cycle);
+ for (i = 0; i < mx; i++) {
+ unsigned idx = mdev->al_tr_cycle + i;
+ extent_nr = lc_element_by_index(mdev->act_log, idx)->lc_number;
+ buffer->updates[i+1].pos = cpu_to_be32(idx);
+ buffer->updates[i+1].extent = cpu_to_be32(extent_nr);
+ xor_sum ^= extent_nr;
+ }
+ for (; i < AL_EXTENTS_PT; i++) {
+ buffer->updates[i+1].pos = __constant_cpu_to_be32(-1);
+ buffer->updates[i+1].extent = __constant_cpu_to_be32(LC_FREE);
+ xor_sum ^= LC_FREE;
+ }
+ mdev->al_tr_cycle += AL_EXTENTS_PT;
+ if (mdev->al_tr_cycle >= mdev->act_log->nr_elements)
+ mdev->al_tr_cycle = 0;
+
+ buffer->xor_sum = cpu_to_be32(xor_sum);
+
+ sector = mdev->ldev->md.md_offset
+ + mdev->ldev->md.al_offset + mdev->al_tr_pos;
+
+ if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE))
+ drbd_chk_io_error(mdev, 1, TRUE);
+
+ if (++mdev->al_tr_pos >
+ div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT))
+ mdev->al_tr_pos = 0;
+
+ D_ASSERT(mdev->al_tr_pos < MD_AL_MAX_SIZE);
+ mdev->al_tr_number++;
+
+ mutex_unlock(&mdev->md_io_mutex);
+
+ complete(&((struct update_al_work *)w)->event);
+ put_ldev(mdev);
+
+ return 1;
+}
+
+/**
+ * drbd_al_read_tr() - Read a single transaction from the on disk activity log
+ * @mdev: DRBD device.
+ * @bdev: Block device to read form.
+ * @b: pointer to an al_transaction.
+ * @index: On disk slot of the transaction to read.
+ *
+ * Returns -1 on IO error, 0 on checksum error and 1 upon success.
+ */
+static int drbd_al_read_tr(struct drbd_conf *mdev,
+ struct drbd_backing_dev *bdev,
+ struct al_transaction *b,
+ int index)
+{
+ sector_t sector;
+ int rv, i;
+ u32 xor_sum = 0;
+
+ sector = bdev->md.md_offset + bdev->md.al_offset + index;
+
+ /* Dont process error normally,
+ * as this is done before disk is attached! */
+ if (!drbd_md_sync_page_io(mdev, bdev, sector, READ))
+ return -1;
+
+ rv = (be32_to_cpu(b->magic) == DRBD_MAGIC);
+
+ for (i = 0; i < AL_EXTENTS_PT + 1; i++)
+ xor_sum ^= be32_to_cpu(b->updates[i].extent);
+ rv &= (xor_sum == be32_to_cpu(b->xor_sum));
+
+ return rv;
+}
+
+/**
+ * drbd_al_read_log() - Restores the activity log from its on disk representation.
+ * @mdev: DRBD device.
+ * @bdev: Block device to read form.
+ *
+ * Returns 1 on success, returns 0 when reading the log failed due to IO errors.
+ */
+int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
+{
+ struct al_transaction *buffer;
+ int i;
+ int rv;
+ int mx;
+ int active_extents = 0;
+ int transactions = 0;
+ int found_valid = 0;
+ int from = 0;
+ int to = 0;
+ u32 from_tnr = 0;
+ u32 to_tnr = 0;
+ u32 cnr;
+
+ mx = div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT);
+
+ /* lock out all other meta data io for now,
+ * and make sure the page is mapped.
+ */
+ mutex_lock(&mdev->md_io_mutex);
+ buffer = page_address(mdev->md_io_page);
+
+ /* Find the valid transaction in the log */
+ for (i = 0; i <= mx; i++) {
+ rv = drbd_al_read_tr(mdev, bdev, buffer, i);
+ if (rv == 0)
+ continue;
+ if (rv == -1) {
+ mutex_unlock(&mdev->md_io_mutex);
+ return 0;
+ }
+ cnr = be32_to_cpu(buffer->tr_number);
+
+ if (++found_valid == 1) {
+ from = i;
+ to = i;
+ from_tnr = cnr;
+ to_tnr = cnr;
+ continue;
+ }
+ if ((int)cnr - (int)from_tnr < 0) {
+ D_ASSERT(from_tnr - cnr + i - from == mx+1);
+ from = i;
+ from_tnr = cnr;
+ }
+ if ((int)cnr - (int)to_tnr > 0) {
+ D_ASSERT(cnr - to_tnr == i - to);
+ to = i;
+ to_tnr = cnr;
+ }
+ }
+
+ if (!found_valid) {
+ dev_warn(DEV, "No usable activity log found.\n");
+ mutex_unlock(&mdev->md_io_mutex);
+ return 1;
+ }
+
+ /* Read the valid transactions.
+ * dev_info(DEV, "Reading from %d to %d.\n",from,to); */
+ i = from;
+ while (1) {
+ int j, pos;
+ unsigned int extent_nr;
+ unsigned int trn;
+
+ rv = drbd_al_read_tr(mdev, bdev, buffer, i);
+ ERR_IF(rv == 0) goto cancel;
+ if (rv == -1) {
+ mutex_unlock(&mdev->md_io_mutex);
+ return 0;
+ }
+
+ trn = be32_to_cpu(buffer->tr_number);
+
+ spin_lock_irq(&mdev->al_lock);
+
+ /* This loop runs backwards because in the cyclic
+ elements there might be an old version of the
+ updated element (in slot 0). So the element in slot 0
+ can overwrite old versions. */
+ for (j = AL_EXTENTS_PT; j >= 0; j--) {
+ pos = be32_to_cpu(buffer->updates[j].pos);
+ extent_nr = be32_to_cpu(buffer->updates[j].extent);
+
+ if (extent_nr == LC_FREE)
+ continue;
+
+ lc_set(mdev->act_log, extent_nr, pos);
+ active_extents++;
+ }
+ spin_unlock_irq(&mdev->al_lock);
+
+ transactions++;
+
+cancel:
+ if (i == to)
+ break;
+ i++;
+ if (i > mx)
+ i = 0;
+ }
+
+ mdev->al_tr_number = to_tnr+1;
+ mdev->al_tr_pos = to;
+ if (++mdev->al_tr_pos >
+ div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT))
+ mdev->al_tr_pos = 0;
+
+ /* ok, we are done with it */
+ mutex_unlock(&mdev->md_io_mutex);
+
+ dev_info(DEV, "Found %d transactions (%d active extents) in activity log.\n",
+ transactions, active_extents);
+
+ return 1;
+}
+
+static void atodb_endio(struct bio *bio, int error)
+{
+ struct drbd_atodb_wait *wc = bio->bi_private;
+ struct drbd_conf *mdev = wc->mdev;
+ struct page *page;
+ int uptodate = bio_flagged(bio, BIO_UPTODATE);
+
+ /* strange behavior of some lower level drivers...
+ * fail the request by clearing the uptodate flag,
+ * but do not return any error?! */
+ if (!error && !uptodate)
+ error = -EIO;
+
+ drbd_chk_io_error(mdev, error, TRUE);
+ if (error && wc->error == 0)
+ wc->error = error;
+
+ if (atomic_dec_and_test(&wc->count))
+ complete(&wc->io_done);
+
+ page = bio->bi_io_vec[0].bv_page;
+ put_page(page);
+ bio_put(bio);
+ mdev->bm_writ_cnt++;
+ put_ldev(mdev);
+}
+
+#define S2W(s) ((s)<<(BM_EXT_SHIFT-BM_BLOCK_SHIFT-LN2_BPL))
+/* activity log to on disk bitmap -- prepare bio unless that sector
+ * is already covered by previously prepared bios */
+static int atodb_prepare_unless_covered(struct drbd_conf *mdev,
+ struct bio **bios,
+ unsigned int enr,
+ struct drbd_atodb_wait *wc) __must_hold(local)
+{
+ struct bio *bio;
+ struct page *page;
+ sector_t on_disk_sector = enr + mdev->ldev->md.md_offset
+ + mdev->ldev->md.bm_offset;
+ unsigned int page_offset = PAGE_SIZE;
+ int offset;
+ int i = 0;
+ int err = -ENOMEM;
+
+ /* Check if that enr is already covered by an already created bio.
+ * Caution, bios[] is not NULL terminated,
+ * but only initialized to all NULL.
+ * For completely scattered activity log,
+ * the last invocation iterates over all bios,
+ * and finds the last NULL entry.
+ */
+ while ((bio = bios[i])) {
+ if (bio->bi_sector == on_disk_sector)
+ return 0;
+ i++;
+ }
+ /* bios[i] == NULL, the next not yet used slot */
+
+ /* GFP_KERNEL, we are not in the write-out path */
+ bio = bio_alloc(GFP_KERNEL, 1);
+ if (bio == NULL)
+ return -ENOMEM;
+
+ if (i > 0) {
+ const struct bio_vec *prev_bv = bios[i-1]->bi_io_vec;
+ page_offset = prev_bv->bv_offset + prev_bv->bv_len;
+ page = prev_bv->bv_page;
+ }
+ if (page_offset == PAGE_SIZE) {
+ page = alloc_page(__GFP_HIGHMEM);
+ if (page == NULL)
+ goto out_bio_put;
+ page_offset = 0;
+ } else {
+ get_page(page);
+ }
+
+ offset = S2W(enr);
+ drbd_bm_get_lel(mdev, offset,
+ min_t(size_t, S2W(1), drbd_bm_words(mdev) - offset),
+ kmap(page) + page_offset);
+ kunmap(page);
+
+ bio->bi_private = wc;
+ bio->bi_end_io = atodb_endio;
+ bio->bi_bdev = mdev->ldev->md_bdev;
+ bio->bi_sector = on_disk_sector;
+
+ if (bio_add_page(bio, page, MD_SECTOR_SIZE, page_offset) != MD_SECTOR_SIZE)
+ goto out_put_page;
+
+ atomic_inc(&wc->count);
+ /* we already know that we may do this...
+ * get_ldev_if_state(mdev,D_ATTACHING);
+ * just get the extra reference, so that the local_cnt reflects
+ * the number of pending IO requests DRBD at its backing device.
+ */
+ atomic_inc(&mdev->local_cnt);
+
+ bios[i] = bio;
+
+ return 0;
+
+out_put_page:
+ err = -EINVAL;
+ put_page(page);
+out_bio_put:
+ bio_put(bio);
+ return err;
+}
+
+/**
+ * drbd_al_to_on_disk_bm() - * Writes bitmap parts covered by active AL extents
+ * @mdev: DRBD device.
+ *
+ * Called when we detach (unconfigure) local storage,
+ * or when we go from R_PRIMARY to R_SECONDARY role.
+ */
+void drbd_al_to_on_disk_bm(struct drbd_conf *mdev)
+{
+ int i, nr_elements;
+ unsigned int enr;
+ struct bio **bios;
+ struct drbd_atodb_wait wc;
+
+ ERR_IF (!get_ldev_if_state(mdev, D_ATTACHING))
+ return; /* sorry, I don't have any act_log etc... */
+
+ wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
+
+ nr_elements = mdev->act_log->nr_elements;
+
+ /* GFP_KERNEL, we are not in anyone's write-out path */
+ bios = kzalloc(sizeof(struct bio *) * nr_elements, GFP_KERNEL);
+ if (!bios)
+ goto submit_one_by_one;
+
+ atomic_set(&wc.count, 0);
+ init_completion(&wc.io_done);
+ wc.mdev = mdev;
+ wc.error = 0;
+
+ for (i = 0; i < nr_elements; i++) {
+ enr = lc_element_by_index(mdev->act_log, i)->lc_number;
+ if (enr == LC_FREE)
+ continue;
+ /* next statement also does atomic_inc wc.count and local_cnt */
+ if (atodb_prepare_unless_covered(mdev, bios,
+ enr/AL_EXT_PER_BM_SECT,
+ &wc))
+ goto free_bios_submit_one_by_one;
+ }
+
+ /* unnecessary optimization? */
+ lc_unlock(mdev->act_log);
+ wake_up(&mdev->al_wait);
+
+ /* all prepared, submit them */
+ for (i = 0; i < nr_elements; i++) {
+ if (bios[i] == NULL)
+ break;
+ if (FAULT_ACTIVE(mdev, DRBD_FAULT_MD_WR)) {
+ bios[i]->bi_rw = WRITE;
+ bio_endio(bios[i], -EIO);
+ } else {
+ submit_bio(WRITE, bios[i]);
+ }
+ }
+
+ drbd_blk_run_queue(bdev_get_queue(mdev->ldev->md_bdev));
+
+ /* always (try to) flush bitmap to stable storage */
+ drbd_md_flush(mdev);
+
+ /* In case we did not submit a single IO do not wait for
+ * them to complete. ( Because we would wait forever here. )
+ *
+ * In case we had IOs and they are already complete, there
+ * is not point in waiting anyways.
+ * Therefore this if () ... */
+ if (atomic_read(&wc.count))
+ wait_for_completion(&wc.io_done);
+
+ put_ldev(mdev);
+
+ kfree(bios);
+ return;
+
+ free_bios_submit_one_by_one:
+ /* free everything by calling the endio callback directly. */
+ for (i = 0; i < nr_elements && bios[i]; i++)
+ bio_endio(bios[i], 0);
+
+ kfree(bios);
+
+ submit_one_by_one:
+ dev_warn(DEV, "Using the slow drbd_al_to_on_disk_bm()\n");
+
+ for (i = 0; i < mdev->act_log->nr_elements; i++) {
+ enr = lc_element_by_index(mdev->act_log, i)->lc_number;
+ if (enr == LC_FREE)
+ continue;
+ /* Really slow: if we have al-extents 16..19 active,
+ * sector 4 will be written four times! Synchronous! */
+ drbd_bm_write_sect(mdev, enr/AL_EXT_PER_BM_SECT);
+ }
+
+ lc_unlock(mdev->act_log);
+ wake_up(&mdev->al_wait);
+ put_ldev(mdev);
+}
+
+/**
+ * drbd_al_apply_to_bm() - Sets the bitmap to diry(1) where covered ba active AL extents
+ * @mdev: DRBD device.
+ */
+void drbd_al_apply_to_bm(struct drbd_conf *mdev)
+{
+ unsigned int enr;
+ unsigned long add = 0;
+ char ppb[10];
+ int i;
+
+ wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
+
+ for (i = 0; i < mdev->act_log->nr_elements; i++) {
+ enr = lc_element_by_index(mdev->act_log, i)->lc_number;
+ if (enr == LC_FREE)
+ continue;
+ add += drbd_bm_ALe_set_all(mdev, enr);
+ }
+
+ lc_unlock(mdev->act_log);
+ wake_up(&mdev->al_wait);
+
+ dev_info(DEV, "Marked additional %s as out-of-sync based on AL.\n",
+ ppsize(ppb, Bit2KB(add)));
+}
+
+static int _try_lc_del(struct drbd_conf *mdev, struct lc_element *al_ext)
+{
+ int rv;
+
+ spin_lock_irq(&mdev->al_lock);
+ rv = (al_ext->refcnt == 0);
+ if (likely(rv))
+ lc_del(mdev->act_log, al_ext);
+ spin_unlock_irq(&mdev->al_lock);
+
+ return rv;
+}
+
+/**
+ * drbd_al_shrink() - Removes all active extents form the activity log
+ * @mdev: DRBD device.
+ *
+ * Removes all active extents form the activity log, waiting until
+ * the reference count of each entry dropped to 0 first, of course.
+ *
+ * You need to lock mdev->act_log with lc_try_lock() / lc_unlock()
+ */
+void drbd_al_shrink(struct drbd_conf *mdev)
+{
+ struct lc_element *al_ext;
+ int i;
+
+ D_ASSERT(test_bit(__LC_DIRTY, &mdev->act_log->flags));
+
+ for (i = 0; i < mdev->act_log->nr_elements; i++) {
+ al_ext = lc_element_by_index(mdev->act_log, i);
+ if (al_ext->lc_number == LC_FREE)
+ continue;
+ wait_event(mdev->al_wait, _try_lc_del(mdev, al_ext));
+ }
+
+ wake_up(&mdev->al_wait);
+}
+
+static int w_update_odbm(struct drbd_conf *mdev, struct drbd_work *w, int unused)
+{
+ struct update_odbm_work *udw = container_of(w, struct update_odbm_work, w);
+
+ if (!get_ldev(mdev)) {
+ if (__ratelimit(&drbd_ratelimit_state))
+ dev_warn(DEV, "Can not update on disk bitmap, local IO disabled.\n");
+ kfree(udw);
+ return 1;
+ }
+
+ drbd_bm_write_sect(mdev, udw->enr);
+ put_ldev(mdev);
+
+ kfree(udw);
+
+ if (drbd_bm_total_weight(mdev) <= mdev->rs_failed) {
+ switch (mdev->state.conn) {
+ case C_SYNC_SOURCE: case C_SYNC_TARGET:
+ case C_PAUSED_SYNC_S: case C_PAUSED_SYNC_T:
+ drbd_resync_finished(mdev);
+ default:
+ /* nothing to do */
+ break;
+ }
+ }
+ drbd_bcast_sync_progress(mdev);
+
+ return 1;
+}
+
+
+/* ATTENTION. The AL's extents are 4MB each, while the extents in the
+ * resync LRU-cache are 16MB each.
+ * The caller of this function has to hold an get_ldev() reference.
+ *
+ * TODO will be obsoleted once we have a caching lru of the on disk bitmap
+ */
+static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector,
+ int count, int success)
+{
+ struct lc_element *e;
+ struct update_odbm_work *udw;
+
+ unsigned int enr;
+
+ D_ASSERT(atomic_read(&mdev->local_cnt));
+
+ /* I simply assume that a sector/size pair never crosses
+ * a 16 MB extent border. (Currently this is true...) */
+ enr = BM_SECT_TO_EXT(sector);
+
+ e = lc_get(mdev->resync, enr);
+ if (e) {
+ struct bm_extent *ext = lc_entry(e, struct bm_extent, lce);
+ if (ext->lce.lc_number == enr) {
+ if (success)
+ ext->rs_left -= count;
+ else
+ ext->rs_failed += count;
+ if (ext->rs_left < ext->rs_failed) {
+ dev_err(DEV, "BAD! sector=%llus enr=%u rs_left=%d "
+ "rs_failed=%d count=%d\n",
+ (unsigned long long)sector,
+ ext->lce.lc_number, ext->rs_left,
+ ext->rs_failed, count);
+ dump_stack();
+
+ lc_put(mdev->resync, &ext->lce);
+ drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+ return;
+ }
+ } else {
+ /* Normally this element should be in the cache,
+ * since drbd_rs_begin_io() pulled it already in.
+ *
+ * But maybe an application write finished, and we set
+ * something outside the resync lru_cache in sync.
+ */
+ int rs_left = drbd_bm_e_weight(mdev, enr);
+ if (ext->flags != 0) {
+ dev_warn(DEV, "changing resync lce: %d[%u;%02lx]"
+ " -> %d[%u;00]\n",
+ ext->lce.lc_number, ext->rs_left,
+ ext->flags, enr, rs_left);
+ ext->flags = 0;
+ }
+ if (ext->rs_failed) {
+ dev_warn(DEV, "Kicking resync_lru element enr=%u "
+ "out with rs_failed=%d\n",
+ ext->lce.lc_number, ext->rs_failed);
+ set_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags);
+ }
+ ext->rs_left = rs_left;
+ ext->rs_failed = success ? 0 : count;
+ lc_changed(mdev->resync, &ext->lce);
+ }
+ lc_put(mdev->resync, &ext->lce);
+ /* no race, we are within the al_lock! */
+
+ if (ext->rs_left == ext->rs_failed) {
+ ext->rs_failed = 0;
+
+ udw = kmalloc(sizeof(*udw), GFP_ATOMIC);
+ if (udw) {
+ udw->enr = ext->lce.lc_number;
+ udw->w.cb = w_update_odbm;
+ drbd_queue_work_front(&mdev->data.work, &udw->w);
+ } else {
+ dev_warn(DEV, "Could not kmalloc an udw\n");
+ set_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags);
+ }
+ }
+ } else {
+ dev_err(DEV, "lc_get() failed! locked=%d/%d flags=%lu\n",
+ mdev->resync_locked,
+ mdev->resync->nr_elements,
+ mdev->resync->flags);
+ }
+}
+
+/* clear the bit corresponding to the piece of storage in question:
+ * size byte of data starting from sector. Only clear a bits of the affected
+ * one ore more _aligned_ BM_BLOCK_SIZE blocks.
+ *
+ * called by worker on C_SYNC_TARGET and receiver on SyncSource.
+ *
+ */
+void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size,
+ const char *file, const unsigned int line)
+{
+ /* Is called from worker and receiver context _only_ */
+ unsigned long sbnr, ebnr, lbnr;
+ unsigned long count = 0;
+ sector_t esector, nr_sectors;
+ int wake_up = 0;
+ unsigned long flags;
+
+ if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) {
+ dev_err(DEV, "drbd_set_in_sync: sector=%llus size=%d nonsense!\n",
+ (unsigned long long)sector, size);
+ return;
+ }
+ nr_sectors = drbd_get_capacity(mdev->this_bdev);
+ esector = sector + (size >> 9) - 1;
+
+ ERR_IF(sector >= nr_sectors) return;
+ ERR_IF(esector >= nr_sectors) esector = (nr_sectors-1);
+
+ lbnr = BM_SECT_TO_BIT(nr_sectors-1);
+
+ /* we clear it (in sync).
+ * round up start sector, round down end sector. we make sure we only
+ * clear full, aligned, BM_BLOCK_SIZE (4K) blocks */
+ if (unlikely(esector < BM_SECT_PER_BIT-1))
+ return;
+ if (unlikely(esector == (nr_sectors-1)))
+ ebnr = lbnr;
+ else
+ ebnr = BM_SECT_TO_BIT(esector - (BM_SECT_PER_BIT-1));
+ sbnr = BM_SECT_TO_BIT(sector + BM_SECT_PER_BIT-1);
+
+ if (sbnr > ebnr)
+ return;
+
+ /*
+ * ok, (capacity & 7) != 0 sometimes, but who cares...
+ * we count rs_{total,left} in bits, not sectors.
+ */
+ spin_lock_irqsave(&mdev->al_lock, flags);
+ count = drbd_bm_clear_bits(mdev, sbnr, ebnr);
+ if (count) {
+ /* we need the lock for drbd_try_clear_on_disk_bm */
+ if (jiffies - mdev->rs_mark_time > HZ*10) {
+ /* should be rolling marks,
+ * but we estimate only anyways. */
+ if (mdev->rs_mark_left != drbd_bm_total_weight(mdev) &&
+ mdev->state.conn != C_PAUSED_SYNC_T &&
+ mdev->state.conn != C_PAUSED_SYNC_S) {
+ mdev->rs_mark_time = jiffies;
+ mdev->rs_mark_left = drbd_bm_total_weight(mdev);
+ }
+ }
+ if (get_ldev(mdev)) {
+ drbd_try_clear_on_disk_bm(mdev, sector, count, TRUE);
+ put_ldev(mdev);
+ }
+ /* just wake_up unconditional now, various lc_chaged(),
+ * lc_put() in drbd_try_clear_on_disk_bm(). */
+ wake_up = 1;
+ }
+ spin_unlock_irqrestore(&mdev->al_lock, flags);
+ if (wake_up)
+ wake_up(&mdev->al_wait);
+}
+
+/*
+ * this is intended to set one request worth of data out of sync.
+ * affects at least 1 bit,
+ * and at most 1+DRBD_MAX_SEGMENT_SIZE/BM_BLOCK_SIZE bits.
+ *
+ * called by tl_clear and drbd_send_dblock (==drbd_make_request).
+ * so this can be _any_ process.
+ */
+void __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size,
+ const char *file, const unsigned int line)
+{
+ unsigned long sbnr, ebnr, lbnr, flags;
+ sector_t esector, nr_sectors;
+ unsigned int enr, count;
+ struct lc_element *e;
+
+ if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) {
+ dev_err(DEV, "sector: %llus, size: %d\n",
+ (unsigned long long)sector, size);
+ return;
+ }
+
+ if (!get_ldev(mdev))
+ return; /* no disk, no metadata, no bitmap to set bits in */
+
+ nr_sectors = drbd_get_capacity(mdev->this_bdev);
+ esector = sector + (size >> 9) - 1;
+
+ ERR_IF(sector >= nr_sectors)
+ goto out;
+ ERR_IF(esector >= nr_sectors)
+ esector = (nr_sectors-1);
+
+ lbnr = BM_SECT_TO_BIT(nr_sectors-1);
+
+ /* we set it out of sync,
+ * we do not need to round anything here */
+ sbnr = BM_SECT_TO_BIT(sector);
+ ebnr = BM_SECT_TO_BIT(esector);
+
+ /* ok, (capacity & 7) != 0 sometimes, but who cares...
+ * we count rs_{total,left} in bits, not sectors. */
+ spin_lock_irqsave(&mdev->al_lock, flags);
+ count = drbd_bm_set_bits(mdev, sbnr, ebnr);
+
+ enr = BM_SECT_TO_EXT(sector);
+ e = lc_find(mdev->resync, enr);
+ if (e)
+ lc_entry(e, struct bm_extent, lce)->rs_left += count;
+ spin_unlock_irqrestore(&mdev->al_lock, flags);
+
+out:
+ put_ldev(mdev);
+}
+
+static
+struct bm_extent *_bme_get(struct drbd_conf *mdev, unsigned int enr)
+{
+ struct lc_element *e;
+ struct bm_extent *bm_ext;
+ int wakeup = 0;
+ unsigned long rs_flags;
+
+ spin_lock_irq(&mdev->al_lock);
+ if (mdev->resync_locked > mdev->resync->nr_elements/2) {
+ spin_unlock_irq(&mdev->al_lock);
+ return NULL;
+ }
+ e = lc_get(mdev->resync, enr);
+ bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
+ if (bm_ext) {
+ if (bm_ext->lce.lc_number != enr) {
+ bm_ext->rs_left = drbd_bm_e_weight(mdev, enr);
+ bm_ext->rs_failed = 0;
+ lc_changed(mdev->resync, &bm_ext->lce);
+ wakeup = 1;
+ }
+ if (bm_ext->lce.refcnt == 1)
+ mdev->resync_locked++;
+ set_bit(BME_NO_WRITES, &bm_ext->flags);
+ }
+ rs_flags = mdev->resync->flags;
+ spin_unlock_irq(&mdev->al_lock);
+ if (wakeup)
+ wake_up(&mdev->al_wait);
+
+ if (!bm_ext) {
+ if (rs_flags & LC_STARVING)
+ dev_warn(DEV, "Have to wait for element"
+ " (resync LRU too small?)\n");
+ BUG_ON(rs_flags & LC_DIRTY);
+ }
+
+ return bm_ext;
+}
+
+static int _is_in_al(struct drbd_conf *mdev, unsigned int enr)
+{
+ struct lc_element *al_ext;
+ int rv = 0;
+
+ spin_lock_irq(&mdev->al_lock);
+ if (unlikely(enr == mdev->act_log->new_number))
+ rv = 1;
+ else {
+ al_ext = lc_find(mdev->act_log, enr);
+ if (al_ext) {
+ if (al_ext->refcnt)
+ rv = 1;
+ }
+ }
+ spin_unlock_irq(&mdev->al_lock);
+
+ /*
+ if (unlikely(rv)) {
+ dev_info(DEV, "Delaying sync read until app's write is done\n");
+ }
+ */
+ return rv;
+}
+
+/**
+ * drbd_rs_begin_io() - Gets an extent in the resync LRU cache and sets it to BME_LOCKED
+ * @mdev: DRBD device.
+ * @sector: The sector number.
+ *
+ * This functions sleeps on al_wait. Returns 1 on success, 0 if interrupted.
+ */
+int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector)
+{
+ unsigned int enr = BM_SECT_TO_EXT(sector);
+ struct bm_extent *bm_ext;
+ int i, sig;
+
+ sig = wait_event_interruptible(mdev->al_wait,
+ (bm_ext = _bme_get(mdev, enr)));
+ if (sig)
+ return 0;
+
+ if (test_bit(BME_LOCKED, &bm_ext->flags))
+ return 1;
+
+ for (i = 0; i < AL_EXT_PER_BM_SECT; i++) {
+ sig = wait_event_interruptible(mdev->al_wait,
+ !_is_in_al(mdev, enr * AL_EXT_PER_BM_SECT + i));
+ if (sig) {
+ spin_lock_irq(&mdev->al_lock);
+ if (lc_put(mdev->resync, &bm_ext->lce) == 0) {
+ clear_bit(BME_NO_WRITES, &bm_ext->flags);
+ mdev->resync_locked--;
+ wake_up(&mdev->al_wait);
+ }
+ spin_unlock_irq(&mdev->al_lock);
+ return 0;
+ }
+ }
+
+ set_bit(BME_LOCKED, &bm_ext->flags);
+
+ return 1;
+}
+
+/**
+ * drbd_try_rs_begin_io() - Gets an extent in the resync LRU cache, does not sleep
+ * @mdev: DRBD device.
+ * @sector: The sector number.
+ *
+ * Gets an extent in the resync LRU cache, sets it to BME_NO_WRITES, then
+ * tries to set it to BME_LOCKED. Returns 0 upon success, and -EAGAIN
+ * if there is still application IO going on in this area.
+ */
+int drbd_try_rs_begin_io(struct drbd_conf *mdev, sector_t sector)
+{
+ unsigned int enr = BM_SECT_TO_EXT(sector);
+ const unsigned int al_enr = enr*AL_EXT_PER_BM_SECT;
+ struct lc_element *e;
+ struct bm_extent *bm_ext;
+ int i;
+
+ spin_lock_irq(&mdev->al_lock);
+ if (mdev->resync_wenr != LC_FREE && mdev->resync_wenr != enr) {
+ /* in case you have very heavy scattered io, it may
+ * stall the syncer undefined if we give up the ref count
+ * when we try again and requeue.
+ *
+ * if we don't give up the refcount, but the next time
+ * we are scheduled this extent has been "synced" by new
+ * application writes, we'd miss the lc_put on the
+ * extent we keep the refcount on.
+ * so we remembered which extent we had to try again, and
+ * if the next requested one is something else, we do
+ * the lc_put here...
+ * we also have to wake_up
+ */
+ e = lc_find(mdev->resync, mdev->resync_wenr);
+ bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
+ if (bm_ext) {
+ D_ASSERT(!test_bit(BME_LOCKED, &bm_ext->flags));
+ D_ASSERT(test_bit(BME_NO_WRITES, &bm_ext->flags));
+ clear_bit(BME_NO_WRITES, &bm_ext->flags);
+ mdev->resync_wenr = LC_FREE;
+ if (lc_put(mdev->resync, &bm_ext->lce) == 0)
+ mdev->resync_locked--;
+ wake_up(&mdev->al_wait);
+ } else {
+ dev_alert(DEV, "LOGIC BUG\n");
+ }
+ }
+ /* TRY. */
+ e = lc_try_get(mdev->resync, enr);
+ bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
+ if (bm_ext) {
+ if (test_bit(BME_LOCKED, &bm_ext->flags))
+ goto proceed;
+ if (!test_and_set_bit(BME_NO_WRITES, &bm_ext->flags)) {
+ mdev->resync_locked++;
+ } else {
+ /* we did set the BME_NO_WRITES,
+ * but then could not set BME_LOCKED,
+ * so we tried again.
+ * drop the extra reference. */
+ bm_ext->lce.refcnt--;
+ D_ASSERT(bm_ext->lce.refcnt > 0);
+ }
+ goto check_al;
+ } else {
+ /* do we rather want to try later? */
+ if (mdev->resync_locked > mdev->resync->nr_elements-3)
+ goto try_again;
+ /* Do or do not. There is no try. -- Yoda */
+ e = lc_get(mdev->resync, enr);
+ bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
+ if (!bm_ext) {
+ const unsigned long rs_flags = mdev->resync->flags;
+ if (rs_flags & LC_STARVING)
+ dev_warn(DEV, "Have to wait for element"
+ " (resync LRU too small?)\n");
+ BUG_ON(rs_flags & LC_DIRTY);
+ goto try_again;
+ }
+ if (bm_ext->lce.lc_number != enr) {
+ bm_ext->rs_left = drbd_bm_e_weight(mdev, enr);
+ bm_ext->rs_failed = 0;
+ lc_changed(mdev->resync, &bm_ext->lce);
+ wake_up(&mdev->al_wait);
+ D_ASSERT(test_bit(BME_LOCKED, &bm_ext->flags) == 0);
+ }
+ set_bit(BME_NO_WRITES, &bm_ext->flags);
+ D_ASSERT(bm_ext->lce.refcnt == 1);
+ mdev->resync_locked++;
+ goto check_al;
+ }
+check_al:
+ for (i = 0; i < AL_EXT_PER_BM_SECT; i++) {
+ if (unlikely(al_enr+i == mdev->act_log->new_number))
+ goto try_again;
+ if (lc_is_used(mdev->act_log, al_enr+i))
+ goto try_again;
+ }
+ set_bit(BME_LOCKED, &bm_ext->flags);
+proceed:
+ mdev->resync_wenr = LC_FREE;
+ spin_unlock_irq(&mdev->al_lock);
+ return 0;
+
+try_again:
+ if (bm_ext)
+ mdev->resync_wenr = enr;
+ spin_unlock_irq(&mdev->al_lock);
+ return -EAGAIN;
+}
+
+void drbd_rs_complete_io(struct drbd_conf *mdev, sector_t sector)
+{
+ unsigned int enr = BM_SECT_TO_EXT(sector);
+ struct lc_element *e;
+ struct bm_extent *bm_ext;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdev->al_lock, flags);
+ e = lc_find(mdev->resync, enr);
+ bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
+ if (!bm_ext) {
+ spin_unlock_irqrestore(&mdev->al_lock, flags);
+ if (__ratelimit(&drbd_ratelimit_state))
+ dev_err(DEV, "drbd_rs_complete_io() called, but extent not found\n");
+ return;
+ }
+
+ if (bm_ext->lce.refcnt == 0) {
+ spin_unlock_irqrestore(&mdev->al_lock, flags);
+ dev_err(DEV, "drbd_rs_complete_io(,%llu [=%u]) called, "
+ "but refcnt is 0!?\n",
+ (unsigned long long)sector, enr);
+ return;
+ }
+
+ if (lc_put(mdev->resync, &bm_ext->lce) == 0) {
+ clear_bit(BME_LOCKED, &bm_ext->flags);
+ clear_bit(BME_NO_WRITES, &bm_ext->flags);
+ mdev->resync_locked--;
+ wake_up(&mdev->al_wait);
+ }
+
+ spin_unlock_irqrestore(&mdev->al_lock, flags);
+}
+
+/**
+ * drbd_rs_cancel_all() - Removes all extents from the resync LRU (even BME_LOCKED)
+ * @mdev: DRBD device.
+ */
+void drbd_rs_cancel_all(struct drbd_conf *mdev)
+{
+ spin_lock_irq(&mdev->al_lock);
+
+ if (get_ldev_if_state(mdev, D_FAILED)) { /* Makes sure ->resync is there. */
+ lc_reset(mdev->resync);
+ put_ldev(mdev);
+ }
+ mdev->resync_locked = 0;
+ mdev->resync_wenr = LC_FREE;
+ spin_unlock_irq(&mdev->al_lock);
+ wake_up(&mdev->al_wait);
+}
+
+/**
+ * drbd_rs_del_all() - Gracefully remove all extents from the resync LRU
+ * @mdev: DRBD device.
+ *
+ * Returns 0 upon success, -EAGAIN if at least one reference count was
+ * not zero.
+ */
+int drbd_rs_del_all(struct drbd_conf *mdev)
+{
+ struct lc_element *e;
+ struct bm_extent *bm_ext;
+ int i;
+
+ spin_lock_irq(&mdev->al_lock);
+
+ if (get_ldev_if_state(mdev, D_FAILED)) {
+ /* ok, ->resync is there. */
+ for (i = 0; i < mdev->resync->nr_elements; i++) {
+ e = lc_element_by_index(mdev->resync, i);
+ bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
+ if (bm_ext->lce.lc_number == LC_FREE)
+ continue;
+ if (bm_ext->lce.lc_number == mdev->resync_wenr) {
+ dev_info(DEV, "dropping %u in drbd_rs_del_all, apparently"
+ " got 'synced' by application io\n",
+ mdev->resync_wenr);
+ D_ASSERT(!test_bit(BME_LOCKED, &bm_ext->flags));
+ D_ASSERT(test_bit(BME_NO_WRITES, &bm_ext->flags));
+ clear_bit(BME_NO_WRITES, &bm_ext->flags);
+ mdev->resync_wenr = LC_FREE;
+ lc_put(mdev->resync, &bm_ext->lce);
+ }
+ if (bm_ext->lce.refcnt != 0) {
+ dev_info(DEV, "Retrying drbd_rs_del_all() later. "
+ "refcnt=%d\n", bm_ext->lce.refcnt);
+ put_ldev(mdev);
+ spin_unlock_irq(&mdev->al_lock);
+ return -EAGAIN;
+ }
+ D_ASSERT(!test_bit(BME_LOCKED, &bm_ext->flags));
+ D_ASSERT(!test_bit(BME_NO_WRITES, &bm_ext->flags));
+ lc_del(mdev->resync, &bm_ext->lce);
+ }
+ D_ASSERT(mdev->resync->used == 0);
+ put_ldev(mdev);
+ }
+ spin_unlock_irq(&mdev->al_lock);
+
+ return 0;
+}
+
+/**
+ * drbd_rs_failed_io() - Record information on a failure to resync the specified blocks
+ * @mdev: DRBD device.
+ * @sector: The sector number.
+ * @size: Size of failed IO operation, in byte.
+ */
+void drbd_rs_failed_io(struct drbd_conf *mdev, sector_t sector, int size)
+{
+ /* Is called from worker and receiver context _only_ */
+ unsigned long sbnr, ebnr, lbnr;
+ unsigned long count;
+ sector_t esector, nr_sectors;
+ int wake_up = 0;
+
+ if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) {
+ dev_err(DEV, "drbd_rs_failed_io: sector=%llus size=%d nonsense!\n",
+ (unsigned long long)sector, size);
+ return;
+ }
+ nr_sectors = drbd_get_capacity(mdev->this_bdev);
+ esector = sector + (size >> 9) - 1;
+
+ ERR_IF(sector >= nr_sectors) return;
+ ERR_IF(esector >= nr_sectors) esector = (nr_sectors-1);
+
+ lbnr = BM_SECT_TO_BIT(nr_sectors-1);
+
+ /*
+ * round up start sector, round down end sector. we make sure we only
+ * handle full, aligned, BM_BLOCK_SIZE (4K) blocks */
+ if (unlikely(esector < BM_SECT_PER_BIT-1))
+ return;
+ if (unlikely(esector == (nr_sectors-1)))
+ ebnr = lbnr;
+ else
+ ebnr = BM_SECT_TO_BIT(esector - (BM_SECT_PER_BIT-1));
+ sbnr = BM_SECT_TO_BIT(sector + BM_SECT_PER_BIT-1);
+
+ if (sbnr > ebnr)
+ return;
+
+ /*
+ * ok, (capacity & 7) != 0 sometimes, but who cares...
+ * we count rs_{total,left} in bits, not sectors.
+ */
+ spin_lock_irq(&mdev->al_lock);
+ count = drbd_bm_count_bits(mdev, sbnr, ebnr);
+ if (count) {
+ mdev->rs_failed += count;
+
+ if (get_ldev(mdev)) {
+ drbd_try_clear_on_disk_bm(mdev, sector, count, FALSE);
+ put_ldev(mdev);
+ }
+
+ /* just wake_up unconditional now, various lc_chaged(),
+ * lc_put() in drbd_try_clear_on_disk_bm(). */
+ wake_up = 1;
+ }
+ spin_unlock_irq(&mdev->al_lock);
+ if (wake_up)
+ wake_up(&mdev->al_wait);
+}
diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c
new file mode 100644
index 000000000000..b61057e77882
--- /dev/null
+++ b/drivers/block/drbd/drbd_bitmap.c
@@ -0,0 +1,1327 @@
+/*
+ drbd_bitmap.c
+
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2004-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 2004-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+ Copyright (C) 2004-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+ drbd 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.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT 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 drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/bitops.h>
+#include <linux/vmalloc.h>
+#include <linux/string.h>
+#include <linux/drbd.h>
+#include <asm/kmap_types.h>
+#include "drbd_int.h"
+
+/* OPAQUE outside this file!
+ * interface defined in drbd_int.h
+
+ * convention:
+ * function name drbd_bm_... => used elsewhere, "public".
+ * function name bm_... => internal to implementation, "private".
+
+ * Note that since find_first_bit returns int, at the current granularity of
+ * the bitmap (4KB per byte), this implementation "only" supports up to
+ * 1<<(32+12) == 16 TB...
+ */
+
+/*
+ * NOTE
+ * Access to the *bm_pages is protected by bm_lock.
+ * It is safe to read the other members within the lock.
+ *
+ * drbd_bm_set_bits is called from bio_endio callbacks,
+ * We may be called with irq already disabled,
+ * so we need spin_lock_irqsave().
+ * And we need the kmap_atomic.
+ */
+struct drbd_bitmap {
+ struct page **bm_pages;
+ spinlock_t bm_lock;
+ /* WARNING unsigned long bm_*:
+ * 32bit number of bit offset is just enough for 512 MB bitmap.
+ * it will blow up if we make the bitmap bigger...
+ * not that it makes much sense to have a bitmap that large,
+ * rather change the granularity to 16k or 64k or something.
+ * (that implies other problems, however...)
+ */
+ unsigned long bm_set; /* nr of set bits; THINK maybe atomic_t? */
+ unsigned long bm_bits;
+ size_t bm_words;
+ size_t bm_number_of_pages;
+ sector_t bm_dev_capacity;
+ struct semaphore bm_change; /* serializes resize operations */
+
+ atomic_t bm_async_io;
+ wait_queue_head_t bm_io_wait;
+
+ unsigned long bm_flags;
+
+ /* debugging aid, in case we are still racy somewhere */
+ char *bm_why;
+ struct task_struct *bm_task;
+};
+
+/* definition of bits in bm_flags */
+#define BM_LOCKED 0
+#define BM_MD_IO_ERROR 1
+#define BM_P_VMALLOCED 2
+
+static int bm_is_locked(struct drbd_bitmap *b)
+{
+ return test_bit(BM_LOCKED, &b->bm_flags);
+}
+
+#define bm_print_lock_info(m) __bm_print_lock_info(m, __func__)
+static void __bm_print_lock_info(struct drbd_conf *mdev, const char *func)
+{
+ struct drbd_bitmap *b = mdev->bitmap;
+ if (!__ratelimit(&drbd_ratelimit_state))
+ return;
+ dev_err(DEV, "FIXME %s in %s, bitmap locked for '%s' by %s\n",
+ current == mdev->receiver.task ? "receiver" :
+ current == mdev->asender.task ? "asender" :
+ current == mdev->worker.task ? "worker" : current->comm,
+ func, b->bm_why ?: "?",
+ b->bm_task == mdev->receiver.task ? "receiver" :
+ b->bm_task == mdev->asender.task ? "asender" :
+ b->bm_task == mdev->worker.task ? "worker" : "?");
+}
+
+void drbd_bm_lock(struct drbd_conf *mdev, char *why)
+{
+ struct drbd_bitmap *b = mdev->bitmap;
+ int trylock_failed;
+
+ if (!b) {
+ dev_err(DEV, "FIXME no bitmap in drbd_bm_lock!?\n");
+ return;
+ }
+
+ trylock_failed = down_trylock(&b->bm_change);
+
+ if (trylock_failed) {
+ dev_warn(DEV, "%s going to '%s' but bitmap already locked for '%s' by %s\n",
+ current == mdev->receiver.task ? "receiver" :
+ current == mdev->asender.task ? "asender" :
+ current == mdev->worker.task ? "worker" : current->comm,
+ why, b->bm_why ?: "?",
+ b->bm_task == mdev->receiver.task ? "receiver" :
+ b->bm_task == mdev->asender.task ? "asender" :
+ b->bm_task == mdev->worker.task ? "worker" : "?");
+ down(&b->bm_change);
+ }
+ if (__test_and_set_bit(BM_LOCKED, &b->bm_flags))
+ dev_err(DEV, "FIXME bitmap already locked in bm_lock\n");
+
+ b->bm_why = why;
+ b->bm_task = current;
+}
+
+void drbd_bm_unlock(struct drbd_conf *mdev)
+{
+ struct drbd_bitmap *b = mdev->bitmap;
+ if (!b) {
+ dev_err(DEV, "FIXME no bitmap in drbd_bm_unlock!?\n");
+ return;
+ }
+
+ if (!__test_and_clear_bit(BM_LOCKED, &mdev->bitmap->bm_flags))
+ dev_err(DEV, "FIXME bitmap not locked in bm_unlock\n");
+
+ b->bm_why = NULL;
+ b->bm_task = NULL;
+ up(&b->bm_change);
+}
+
+/* word offset to long pointer */
+static unsigned long *__bm_map_paddr(struct drbd_bitmap *b, unsigned long offset, const enum km_type km)
+{
+ struct page *page;
+ unsigned long page_nr;
+
+ /* page_nr = (word*sizeof(long)) >> PAGE_SHIFT; */
+ page_nr = offset >> (PAGE_SHIFT - LN2_BPL + 3);
+ BUG_ON(page_nr >= b->bm_number_of_pages);
+ page = b->bm_pages[page_nr];
+
+ return (unsigned long *) kmap_atomic(page, km);
+}
+
+static unsigned long * bm_map_paddr(struct drbd_bitmap *b, unsigned long offset)
+{
+ return __bm_map_paddr(b, offset, KM_IRQ1);
+}
+
+static void __bm_unmap(unsigned long *p_addr, const enum km_type km)
+{
+ kunmap_atomic(p_addr, km);
+};
+
+static void bm_unmap(unsigned long *p_addr)
+{
+ return __bm_unmap(p_addr, KM_IRQ1);
+}
+
+/* long word offset of _bitmap_ sector */
+#define S2W(s) ((s)<<(BM_EXT_SHIFT-BM_BLOCK_SHIFT-LN2_BPL))
+/* word offset from start of bitmap to word number _in_page_
+ * modulo longs per page
+#define MLPP(X) ((X) % (PAGE_SIZE/sizeof(long))
+ hm, well, Philipp thinks gcc might not optimze the % into & (... - 1)
+ so do it explicitly:
+ */
+#define MLPP(X) ((X) & ((PAGE_SIZE/sizeof(long))-1))
+
+/* Long words per page */
+#define LWPP (PAGE_SIZE/sizeof(long))
+
+/*
+ * actually most functions herein should take a struct drbd_bitmap*, not a
+ * struct drbd_conf*, but for the debug macros I like to have the mdev around
+ * to be able to report device specific.
+ */
+
+static void bm_free_pages(struct page **pages, unsigned long number)
+{
+ unsigned long i;
+ if (!pages)
+ return;
+
+ for (i = 0; i < number; i++) {
+ if (!pages[i]) {
+ printk(KERN_ALERT "drbd: bm_free_pages tried to free "
+ "a NULL pointer; i=%lu n=%lu\n",
+ i, number);
+ continue;
+ }
+ __free_page(pages[i]);
+ pages[i] = NULL;
+ }
+}
+
+static void bm_vk_free(void *ptr, int v)
+{
+ if (v)
+ vfree(ptr);
+ else
+ kfree(ptr);
+}
+
+/*
+ * "have" and "want" are NUMBER OF PAGES.
+ */
+static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want)
+{
+ struct page **old_pages = b->bm_pages;
+ struct page **new_pages, *page;
+ unsigned int i, bytes, vmalloced = 0;
+ unsigned long have = b->bm_number_of_pages;
+
+ BUG_ON(have == 0 && old_pages != NULL);
+ BUG_ON(have != 0 && old_pages == NULL);
+
+ if (have == want)
+ return old_pages;
+
+ /* Trying kmalloc first, falling back to vmalloc.
+ * GFP_KERNEL is ok, as this is done when a lower level disk is
+ * "attached" to the drbd. Context is receiver thread or cqueue
+ * thread. As we have no disk yet, we are not in the IO path,
+ * not even the IO path of the peer. */
+ bytes = sizeof(struct page *)*want;
+ new_pages = kmalloc(bytes, GFP_KERNEL);
+ if (!new_pages) {
+ new_pages = vmalloc(bytes);
+ if (!new_pages)
+ return NULL;
+ vmalloced = 1;
+ }
+
+ memset(new_pages, 0, bytes);
+ if (want >= have) {
+ for (i = 0; i < have; i++)
+ new_pages[i] = old_pages[i];
+ for (; i < want; i++) {
+ page = alloc_page(GFP_HIGHUSER);
+ if (!page) {
+ bm_free_pages(new_pages + have, i - have);
+ bm_vk_free(new_pages, vmalloced);
+ return NULL;
+ }
+ new_pages[i] = page;
+ }
+ } else {
+ for (i = 0; i < want; i++)
+ new_pages[i] = old_pages[i];
+ /* NOT HERE, we are outside the spinlock!
+ bm_free_pages(old_pages + want, have - want);
+ */
+ }
+
+ if (vmalloced)
+ set_bit(BM_P_VMALLOCED, &b->bm_flags);
+ else
+ clear_bit(BM_P_VMALLOCED, &b->bm_flags);
+
+ return new_pages;
+}
+
+/*
+ * called on driver init only. TODO call when a device is created.
+ * allocates the drbd_bitmap, and stores it in mdev->bitmap.
+ */
+int drbd_bm_init(struct drbd_conf *mdev)
+{
+ struct drbd_bitmap *b = mdev->bitmap;
+ WARN_ON(b != NULL);
+ b = kzalloc(sizeof(struct drbd_bitmap), GFP_KERNEL);
+ if (!b)
+ return -ENOMEM;
+ spin_lock_init(&b->bm_lock);
+ init_MUTEX(&b->bm_change);
+ init_waitqueue_head(&b->bm_io_wait);
+
+ mdev->bitmap = b;
+
+ return 0;
+}
+
+sector_t drbd_bm_capacity(struct drbd_conf *mdev)
+{
+ ERR_IF(!mdev->bitmap) return 0;
+ return mdev->bitmap->bm_dev_capacity;
+}
+
+/* called on driver unload. TODO: call when a device is destroyed.
+ */
+void drbd_bm_cleanup(struct drbd_conf *mdev)
+{
+ ERR_IF (!mdev->bitmap) return;
+ bm_free_pages(mdev->bitmap->bm_pages, mdev->bitmap->bm_number_of_pages);
+ bm_vk_free(mdev->bitmap->bm_pages, test_bit(BM_P_VMALLOCED, &mdev->bitmap->bm_flags));
+ kfree(mdev->bitmap);
+ mdev->bitmap = NULL;
+}
+
+/*
+ * since (b->bm_bits % BITS_PER_LONG) != 0,
+ * this masks out the remaining bits.
+ * Returns the number of bits cleared.
+ */
+static int bm_clear_surplus(struct drbd_bitmap *b)
+{
+ const unsigned long mask = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) - 1;
+ size_t w = b->bm_bits >> LN2_BPL;
+ int cleared = 0;
+ unsigned long *p_addr, *bm;
+
+ p_addr = bm_map_paddr(b, w);
+ bm = p_addr + MLPP(w);
+ if (w < b->bm_words) {
+ cleared = hweight_long(*bm & ~mask);
+ *bm &= mask;
+ w++; bm++;
+ }
+
+ if (w < b->bm_words) {
+ cleared += hweight_long(*bm);
+ *bm = 0;
+ }
+ bm_unmap(p_addr);
+ return cleared;
+}
+
+static void bm_set_surplus(struct drbd_bitmap *b)
+{
+ const unsigned long mask = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) - 1;
+ size_t w = b->bm_bits >> LN2_BPL;
+ unsigned long *p_addr, *bm;
+
+ p_addr = bm_map_paddr(b, w);
+ bm = p_addr + MLPP(w);
+ if (w < b->bm_words) {
+ *bm |= ~mask;
+ bm++; w++;
+ }
+
+ if (w < b->bm_words) {
+ *bm = ~(0UL);
+ }
+ bm_unmap(p_addr);
+}
+
+static unsigned long __bm_count_bits(struct drbd_bitmap *b, const int swap_endian)
+{
+ unsigned long *p_addr, *bm, offset = 0;
+ unsigned long bits = 0;
+ unsigned long i, do_now;
+
+ while (offset < b->bm_words) {
+ i = do_now = min_t(size_t, b->bm_words-offset, LWPP);
+ p_addr = __bm_map_paddr(b, offset, KM_USER0);
+ bm = p_addr + MLPP(offset);
+ while (i--) {
+#ifndef __LITTLE_ENDIAN
+ if (swap_endian)
+ *bm = lel_to_cpu(*bm);
+#endif
+ bits += hweight_long(*bm++);
+ }
+ __bm_unmap(p_addr, KM_USER0);
+ offset += do_now;
+ cond_resched();
+ }
+
+ return bits;
+}
+
+static unsigned long bm_count_bits(struct drbd_bitmap *b)
+{
+ return __bm_count_bits(b, 0);
+}
+
+static unsigned long bm_count_bits_swap_endian(struct drbd_bitmap *b)
+{
+ return __bm_count_bits(b, 1);
+}
+
+/* offset and len in long words.*/
+static void bm_memset(struct drbd_bitmap *b, size_t offset, int c, size_t len)
+{
+ unsigned long *p_addr, *bm;
+ size_t do_now, end;
+
+#define BM_SECTORS_PER_BIT (BM_BLOCK_SIZE/512)
+
+ end = offset + len;
+
+ if (end > b->bm_words) {
+ printk(KERN_ALERT "drbd: bm_memset end > bm_words\n");
+ return;
+ }
+
+ while (offset < end) {
+ do_now = min_t(size_t, ALIGN(offset + 1, LWPP), end) - offset;
+ p_addr = bm_map_paddr(b, offset);
+ bm = p_addr + MLPP(offset);
+ if (bm+do_now > p_addr + LWPP) {
+ printk(KERN_ALERT "drbd: BUG BUG BUG! p_addr:%p bm:%p do_now:%d\n",
+ p_addr, bm, (int)do_now);
+ break; /* breaks to after catch_oob_access_end() only! */
+ }
+ memset(bm, c, do_now * sizeof(long));
+ bm_unmap(p_addr);
+ offset += do_now;
+ }
+}
+
+/*
+ * make sure the bitmap has enough room for the attached storage,
+ * if necessary, resize.
+ * called whenever we may have changed the device size.
+ * returns -ENOMEM if we could not allocate enough memory, 0 on success.
+ * In case this is actually a resize, we copy the old bitmap into the new one.
+ * Otherwise, the bitmap is initialized to all bits set.
+ */
+int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity)
+{
+ struct drbd_bitmap *b = mdev->bitmap;
+ unsigned long bits, words, owords, obits, *p_addr, *bm;
+ unsigned long want, have, onpages; /* number of pages */
+ struct page **npages, **opages = NULL;
+ int err = 0, growing;
+ int opages_vmalloced;
+
+ ERR_IF(!b) return -ENOMEM;
+
+ drbd_bm_lock(mdev, "resize");
+
+ dev_info(DEV, "drbd_bm_resize called with capacity == %llu\n",
+ (unsigned long long)capacity);
+
+ if (capacity == b->bm_dev_capacity)
+ goto out;
+
+ opages_vmalloced = test_bit(BM_P_VMALLOCED, &b->bm_flags);
+
+ if (capacity == 0) {
+ spin_lock_irq(&b->bm_lock);
+ opages = b->bm_pages;
+ onpages = b->bm_number_of_pages;
+ owords = b->bm_words;
+ b->bm_pages = NULL;
+ b->bm_number_of_pages =
+ b->bm_set =
+ b->bm_bits =
+ b->bm_words =
+ b->bm_dev_capacity = 0;
+ spin_unlock_irq(&b->bm_lock);
+ bm_free_pages(opages, onpages);
+ bm_vk_free(opages, opages_vmalloced);
+ goto out;
+ }
+ bits = BM_SECT_TO_BIT(ALIGN(capacity, BM_SECT_PER_BIT));
+
+ /* if we would use
+ words = ALIGN(bits,BITS_PER_LONG) >> LN2_BPL;
+ a 32bit host could present the wrong number of words
+ to a 64bit host.
+ */
+ words = ALIGN(bits, 64) >> LN2_BPL;
+
+ if (get_ldev(mdev)) {
+ D_ASSERT((u64)bits <= (((u64)mdev->ldev->md.md_size_sect-MD_BM_OFFSET) << 12));
+ put_ldev(mdev);
+ }
+
+ /* one extra long to catch off by one errors */
+ want = ALIGN((words+1)*sizeof(long), PAGE_SIZE) >> PAGE_SHIFT;
+ have = b->bm_number_of_pages;
+ if (want == have) {
+ D_ASSERT(b->bm_pages != NULL);
+ npages = b->bm_pages;
+ } else {
+ if (FAULT_ACTIVE(mdev, DRBD_FAULT_BM_ALLOC))
+ npages = NULL;
+ else
+ npages = bm_realloc_pages(b, want);
+ }
+
+ if (!npages) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ spin_lock_irq(&b->bm_lock);
+ opages = b->bm_pages;
+ owords = b->bm_words;
+ obits = b->bm_bits;
+
+ growing = bits > obits;
+ if (opages)
+ bm_set_surplus(b);
+
+ b->bm_pages = npages;
+ b->bm_number_of_pages = want;
+ b->bm_bits = bits;
+ b->bm_words = words;
+ b->bm_dev_capacity = capacity;
+
+ if (growing) {
+ bm_memset(b, owords, 0xff, words-owords);
+ b->bm_set += bits - obits;
+ }
+
+ if (want < have) {
+ /* implicit: (opages != NULL) && (opages != npages) */
+ bm_free_pages(opages + want, have - want);
+ }
+
+ p_addr = bm_map_paddr(b, words);
+ bm = p_addr + MLPP(words);
+ *bm = DRBD_MAGIC;
+ bm_unmap(p_addr);
+
+ (void)bm_clear_surplus(b);
+
+ spin_unlock_irq(&b->bm_lock);
+ if (opages != npages)
+ bm_vk_free(opages, opages_vmalloced);
+ if (!growing)
+ b->bm_set = bm_count_bits(b);
+ dev_info(DEV, "resync bitmap: bits=%lu words=%lu\n", bits, words);
+
+ out:
+ drbd_bm_unlock(mdev);
+ return err;
+}
+
+/* inherently racy:
+ * if not protected by other means, return value may be out of date when
+ * leaving this function...
+ * we still need to lock it, since it is important that this returns
+ * bm_set == 0 precisely.
+ *
+ * maybe bm_set should be atomic_t ?
+ */
+static unsigned long _drbd_bm_total_weight(struct drbd_conf *mdev)
+{
+ struct drbd_bitmap *b = mdev->bitmap;
+ unsigned long s;
+ unsigned long flags;
+
+ ERR_IF(!b) return 0;
+ ERR_IF(!b->bm_pages) return 0;
+
+ spin_lock_irqsave(&b->bm_lock, flags);
+ s = b->bm_set;
+ spin_unlock_irqrestore(&b->bm_lock, flags);
+
+ return s;
+}
+
+unsigned long drbd_bm_total_weight(struct drbd_conf *mdev)
+{
+ unsigned long s;
+ /* if I don't have a disk, I don't know about out-of-sync status */
+ if (!get_ldev_if_state(mdev, D_NEGOTIATING))
+ return 0;
+ s = _drbd_bm_total_weight(mdev);
+ put_ldev(mdev);
+ return s;
+}
+
+size_t drbd_bm_words(struct drbd_conf *mdev)
+{
+ struct drbd_bitmap *b = mdev->bitmap;
+ ERR_IF(!b) return 0;
+ ERR_IF(!b->bm_pages) return 0;
+
+ return b->bm_words;
+}
+
+unsigned long drbd_bm_bits(struct drbd_conf *mdev)
+{
+ struct drbd_bitmap *b = mdev->bitmap;
+ ERR_IF(!b) return 0;
+
+ return b->bm_bits;
+}
+
+/* merge number words from buffer into the bitmap starting at offset.
+ * buffer[i] is expected to be little endian unsigned long.
+ * bitmap must be locked by drbd_bm_lock.
+ * currently only used from receive_bitmap.
+ */
+void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset, size_t number,
+ unsigned long *buffer)
+{
+ struct drbd_bitmap *b = mdev->bitmap;
+ unsigned long *p_addr, *bm;
+ unsigned long word, bits;
+ size_t end, do_now;
+
+ end = offset + number;
+
+ ERR_IF(!b) return;
+ ERR_IF(!b->bm_pages) return;
+ if (number == 0)
+ return;
+ WARN_ON(offset >= b->bm_words);
+ WARN_ON(end > b->bm_words);
+
+ spin_lock_irq(&b->bm_lock);
+ while (offset < end) {
+ do_now = min_t(size_t, ALIGN(offset+1, LWPP), end) - offset;
+ p_addr = bm_map_paddr(b, offset);
+ bm = p_addr + MLPP(offset);
+ offset += do_now;
+ while (do_now--) {
+ bits = hweight_long(*bm);
+ word = *bm | lel_to_cpu(*buffer++);
+ *bm++ = word;
+ b->bm_set += hweight_long(word) - bits;
+ }
+ bm_unmap(p_addr);
+ }
+ /* with 32bit <-> 64bit cross-platform connect
+ * this is only correct for current usage,
+ * where we _know_ that we are 64 bit aligned,
+ * and know that this function is used in this way, too...
+ */
+ if (end == b->bm_words)
+ b->bm_set -= bm_clear_surplus(b);
+
+ spin_unlock_irq(&b->bm_lock);
+}
+
+/* copy number words from the bitmap starting at offset into the buffer.
+ * buffer[i] will be little endian unsigned long.
+ */
+void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset, size_t number,
+ unsigned long *buffer)
+{
+ struct drbd_bitmap *b = mdev->bitmap;
+ unsigned long *p_addr, *bm;
+ size_t end, do_now;
+
+ end = offset + number;
+
+ ERR_IF(!b) return;
+ ERR_IF(!b->bm_pages) return;
+
+ spin_lock_irq(&b->bm_lock);
+ if ((offset >= b->bm_words) ||
+ (end > b->bm_words) ||
+ (number <= 0))
+ dev_err(DEV, "offset=%lu number=%lu bm_words=%lu\n",
+ (unsigned long) offset,
+ (unsigned long) number,
+ (unsigned long) b->bm_words);
+ else {
+ while (offset < end) {
+ do_now = min_t(size_t, ALIGN(offset+1, LWPP), end) - offset;
+ p_addr = bm_map_paddr(b, offset);
+ bm = p_addr + MLPP(offset);
+ offset += do_now;
+ while (do_now--)
+ *buffer++ = cpu_to_lel(*bm++);
+ bm_unmap(p_addr);
+ }
+ }
+ spin_unlock_irq(&b->bm_lock);
+}
+
+/* set all bits in the bitmap */
+void drbd_bm_set_all(struct drbd_conf *mdev)
+{
+ struct drbd_bitmap *b = mdev->bitmap;
+ ERR_IF(!b) return;
+ ERR_IF(!b->bm_pages) return;
+
+ spin_lock_irq(&b->bm_lock);
+ bm_memset(b, 0, 0xff, b->bm_words);
+ (void)bm_clear_surplus(b);
+ b->bm_set = b->bm_bits;
+ spin_unlock_irq(&b->bm_lock);
+}
+
+/* clear all bits in the bitmap */
+void drbd_bm_clear_all(struct drbd_conf *mdev)
+{
+ struct drbd_bitmap *b = mdev->bitmap;
+ ERR_IF(!b) return;
+ ERR_IF(!b->bm_pages) return;
+
+ spin_lock_irq(&b->bm_lock);
+ bm_memset(b, 0, 0, b->bm_words);
+ b->bm_set = 0;
+ spin_unlock_irq(&b->bm_lock);
+}
+
+static void bm_async_io_complete(struct bio *bio, int error)
+{
+ struct drbd_bitmap *b = bio->bi_private;
+ int uptodate = bio_flagged(bio, BIO_UPTODATE);
+
+
+ /* strange behavior of some lower level drivers...
+ * fail the request by clearing the uptodate flag,
+ * but do not return any error?!
+ * do we want to WARN() on this? */
+ if (!error && !uptodate)
+ error = -EIO;
+
+ if (error) {
+ /* doh. what now?
+ * for now, set all bits, and flag MD_IO_ERROR */
+ __set_bit(BM_MD_IO_ERROR, &b->bm_flags);
+ }
+ if (atomic_dec_and_test(&b->bm_async_io))
+ wake_up(&b->bm_io_wait);
+
+ bio_put(bio);
+}
+
+static void bm_page_io_async(struct drbd_conf *mdev, struct drbd_bitmap *b, int page_nr, int rw) __must_hold(local)
+{
+ /* we are process context. we always get a bio */
+ struct bio *bio = bio_alloc(GFP_KERNEL, 1);
+ unsigned int len;
+ sector_t on_disk_sector =
+ mdev->ldev->md.md_offset + mdev->ldev->md.bm_offset;
+ on_disk_sector += ((sector_t)page_nr) << (PAGE_SHIFT-9);
+
+ /* this might happen with very small
+ * flexible external meta data device */
+ len = min_t(unsigned int, PAGE_SIZE,
+ (drbd_md_last_sector(mdev->ldev) - on_disk_sector + 1)<<9);
+
+ bio->bi_bdev = mdev->ldev->md_bdev;
+ bio->bi_sector = on_disk_sector;
+ bio_add_page(bio, b->bm_pages[page_nr], len, 0);
+ bio->bi_private = b;
+ bio->bi_end_io = bm_async_io_complete;
+
+ if (FAULT_ACTIVE(mdev, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) {
+ bio->bi_rw |= rw;
+ bio_endio(bio, -EIO);
+ } else {
+ submit_bio(rw, bio);
+ }
+}
+
+# if defined(__LITTLE_ENDIAN)
+ /* nothing to do, on disk == in memory */
+# define bm_cpu_to_lel(x) ((void)0)
+# else
+void bm_cpu_to_lel(struct drbd_bitmap *b)
+{
+ /* need to cpu_to_lel all the pages ...
+ * this may be optimized by using
+ * cpu_to_lel(-1) == -1 and cpu_to_lel(0) == 0;
+ * the following is still not optimal, but better than nothing */
+ unsigned int i;
+ unsigned long *p_addr, *bm;
+ if (b->bm_set == 0) {
+ /* no page at all; avoid swap if all is 0 */
+ i = b->bm_number_of_pages;
+ } else if (b->bm_set == b->bm_bits) {
+ /* only the last page */
+ i = b->bm_number_of_pages - 1;
+ } else {
+ /* all pages */
+ i = 0;
+ }
+ for (; i < b->bm_number_of_pages; i++) {
+ p_addr = kmap_atomic(b->bm_pages[i], KM_USER0);
+ for (bm = p_addr; bm < p_addr + PAGE_SIZE/sizeof(long); bm++)
+ *bm = cpu_to_lel(*bm);
+ kunmap_atomic(p_addr, KM_USER0);
+ }
+}
+# endif
+/* lel_to_cpu == cpu_to_lel */
+# define bm_lel_to_cpu(x) bm_cpu_to_lel(x)
+
+/*
+ * bm_rw: read/write the whole bitmap from/to its on disk location.
+ */
+static int bm_rw(struct drbd_conf *mdev, int rw) __must_hold(local)
+{
+ struct drbd_bitmap *b = mdev->bitmap;
+ /* sector_t sector; */
+ int bm_words, num_pages, i;
+ unsigned long now;
+ char ppb[10];
+ int err = 0;
+
+ WARN_ON(!bm_is_locked(b));
+
+ /* no spinlock here, the drbd_bm_lock should be enough! */
+
+ bm_words = drbd_bm_words(mdev);
+ num_pages = (bm_words*sizeof(long) + PAGE_SIZE-1) >> PAGE_SHIFT;
+
+ /* on disk bitmap is little endian */
+ if (rw == WRITE)
+ bm_cpu_to_lel(b);
+
+ now = jiffies;
+ atomic_set(&b->bm_async_io, num_pages);
+ __clear_bit(BM_MD_IO_ERROR, &b->bm_flags);
+
+ /* let the layers below us try to merge these bios... */
+ for (i = 0; i < num_pages; i++)
+ bm_page_io_async(mdev, b, i, rw);
+
+ drbd_blk_run_queue(bdev_get_queue(mdev->ldev->md_bdev));
+ wait_event(b->bm_io_wait, atomic_read(&b->bm_async_io) == 0);
+
+ if (test_bit(BM_MD_IO_ERROR, &b->bm_flags)) {
+ dev_alert(DEV, "we had at least one MD IO ERROR during bitmap IO\n");
+ drbd_chk_io_error(mdev, 1, TRUE);
+ err = -EIO;
+ }
+
+ now = jiffies;
+ if (rw == WRITE) {
+ /* swap back endianness */
+ bm_lel_to_cpu(b);
+ /* flush bitmap to stable storage */
+ drbd_md_flush(mdev);
+ } else /* rw == READ */ {
+ /* just read, if necessary adjust endianness */
+ b->bm_set = bm_count_bits_swap_endian(b);
+ dev_info(DEV, "recounting of set bits took additional %lu jiffies\n",
+ jiffies - now);
+ }
+ now = b->bm_set;
+
+ dev_info(DEV, "%s (%lu bits) marked out-of-sync by on disk bit-map.\n",
+ ppsize(ppb, now << (BM_BLOCK_SHIFT-10)), now);
+
+ return err;
+}
+
+/**
+ * drbd_bm_read() - Read the whole bitmap from its on disk location.
+ * @mdev: DRBD device.
+ */
+int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local)
+{
+ return bm_rw(mdev, READ);
+}
+
+/**
+ * drbd_bm_write() - Write the whole bitmap to its on disk location.
+ * @mdev: DRBD device.
+ */
+int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local)
+{
+ return bm_rw(mdev, WRITE);
+}
+
+/**
+ * drbd_bm_write_sect: Writes a 512 (MD_SECTOR_SIZE) byte piece of the bitmap
+ * @mdev: DRBD device.
+ * @enr: Extent number in the resync lru (happens to be sector offset)
+ *
+ * The BM_EXT_SIZE is on purpose exactly the amount of the bitmap covered
+ * by a single sector write. Therefore enr == sector offset from the
+ * start of the bitmap.
+ */
+int drbd_bm_write_sect(struct drbd_conf *mdev, unsigned long enr) __must_hold(local)
+{
+ sector_t on_disk_sector = enr + mdev->ldev->md.md_offset
+ + mdev->ldev->md.bm_offset;
+ int bm_words, num_words, offset;
+ int err = 0;
+
+ mutex_lock(&mdev->md_io_mutex);
+ bm_words = drbd_bm_words(mdev);
+ offset = S2W(enr); /* word offset into bitmap */
+ num_words = min(S2W(1), bm_words - offset);
+ if (num_words < S2W(1))
+ memset(page_address(mdev->md_io_page), 0, MD_SECTOR_SIZE);
+ drbd_bm_get_lel(mdev, offset, num_words,
+ page_address(mdev->md_io_page));
+ if (!drbd_md_sync_page_io(mdev, mdev->ldev, on_disk_sector, WRITE)) {
+ int i;
+ err = -EIO;
+ dev_err(DEV, "IO ERROR writing bitmap sector %lu "
+ "(meta-disk sector %llus)\n",
+ enr, (unsigned long long)on_disk_sector);
+ drbd_chk_io_error(mdev, 1, TRUE);
+ for (i = 0; i < AL_EXT_PER_BM_SECT; i++)
+ drbd_bm_ALe_set_all(mdev, enr*AL_EXT_PER_BM_SECT+i);
+ }
+ mdev->bm_writ_cnt++;
+ mutex_unlock(&mdev->md_io_mutex);
+ return err;
+}
+
+/* NOTE
+ * find_first_bit returns int, we return unsigned long.
+ * should not make much difference anyways, but ...
+ *
+ * this returns a bit number, NOT a sector!
+ */
+#define BPP_MASK ((1UL << (PAGE_SHIFT+3)) - 1)
+static unsigned long __bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo,
+ const int find_zero_bit, const enum km_type km)
+{
+ struct drbd_bitmap *b = mdev->bitmap;
+ unsigned long i = -1UL;
+ unsigned long *p_addr;
+ unsigned long bit_offset; /* bit offset of the mapped page. */
+
+ if (bm_fo > b->bm_bits) {
+ dev_err(DEV, "bm_fo=%lu bm_bits=%lu\n", bm_fo, b->bm_bits);
+ } else {
+ while (bm_fo < b->bm_bits) {
+ unsigned long offset;
+ bit_offset = bm_fo & ~BPP_MASK; /* bit offset of the page */
+ offset = bit_offset >> LN2_BPL; /* word offset of the page */
+ p_addr = __bm_map_paddr(b, offset, km);
+
+ if (find_zero_bit)
+ i = find_next_zero_bit(p_addr, PAGE_SIZE*8, bm_fo & BPP_MASK);
+ else
+ i = find_next_bit(p_addr, PAGE_SIZE*8, bm_fo & BPP_MASK);
+
+ __bm_unmap(p_addr, km);
+ if (i < PAGE_SIZE*8) {
+ i = bit_offset + i;
+ if (i >= b->bm_bits)
+ break;
+ goto found;
+ }
+ bm_fo = bit_offset + PAGE_SIZE*8;
+ }
+ i = -1UL;
+ }
+ found:
+ return i;
+}
+
+static unsigned long bm_find_next(struct drbd_conf *mdev,
+ unsigned long bm_fo, const int find_zero_bit)
+{
+ struct drbd_bitmap *b = mdev->bitmap;
+ unsigned long i = -1UL;
+
+ ERR_IF(!b) return i;
+ ERR_IF(!b->bm_pages) return i;
+
+ spin_lock_irq(&b->bm_lock);
+ if (bm_is_locked(b))
+ bm_print_lock_info(mdev);
+
+ i = __bm_find_next(mdev, bm_fo, find_zero_bit, KM_IRQ1);
+
+ spin_unlock_irq(&b->bm_lock);
+ return i;
+}
+
+unsigned long drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo)
+{
+ return bm_find_next(mdev, bm_fo, 0);
+}
+
+#if 0
+/* not yet needed for anything. */
+unsigned long drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo)
+{
+ return bm_find_next(mdev, bm_fo, 1);
+}
+#endif
+
+/* does not spin_lock_irqsave.
+ * you must take drbd_bm_lock() first */
+unsigned long _drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo)
+{
+ /* WARN_ON(!bm_is_locked(mdev)); */
+ return __bm_find_next(mdev, bm_fo, 0, KM_USER1);
+}
+
+unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo)
+{
+ /* WARN_ON(!bm_is_locked(mdev)); */
+ return __bm_find_next(mdev, bm_fo, 1, KM_USER1);
+}
+
+/* returns number of bits actually changed.
+ * for val != 0, we change 0 -> 1, return code positive
+ * for val == 0, we change 1 -> 0, return code negative
+ * wants bitnr, not sector.
+ * expected to be called for only a few bits (e - s about BITS_PER_LONG).
+ * Must hold bitmap lock already. */
+int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
+ unsigned long e, int val, const enum km_type km)
+{
+ struct drbd_bitmap *b = mdev->bitmap;
+ unsigned long *p_addr = NULL;
+ unsigned long bitnr;
+ unsigned long last_page_nr = -1UL;
+ int c = 0;
+
+ if (e >= b->bm_bits) {
+ dev_err(DEV, "ASSERT FAILED: bit_s=%lu bit_e=%lu bm_bits=%lu\n",
+ s, e, b->bm_bits);
+ e = b->bm_bits ? b->bm_bits -1 : 0;
+ }
+ for (bitnr = s; bitnr <= e; bitnr++) {
+ unsigned long offset = bitnr>>LN2_BPL;
+ unsigned long page_nr = offset >> (PAGE_SHIFT - LN2_BPL + 3);
+ if (page_nr != last_page_nr) {
+ if (p_addr)
+ __bm_unmap(p_addr, km);
+ p_addr = __bm_map_paddr(b, offset, km);
+ last_page_nr = page_nr;
+ }
+ if (val)
+ c += (0 == __test_and_set_bit(bitnr & BPP_MASK, p_addr));
+ else
+ c -= (0 != __test_and_clear_bit(bitnr & BPP_MASK, p_addr));
+ }
+ if (p_addr)
+ __bm_unmap(p_addr, km);
+ b->bm_set += c;
+ return c;
+}
+
+/* returns number of bits actually changed.
+ * for val != 0, we change 0 -> 1, return code positive
+ * for val == 0, we change 1 -> 0, return code negative
+ * wants bitnr, not sector */
+int bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
+ const unsigned long e, int val)
+{
+ unsigned long flags;
+ struct drbd_bitmap *b = mdev->bitmap;
+ int c = 0;
+
+ ERR_IF(!b) return 1;
+ ERR_IF(!b->bm_pages) return 0;
+
+ spin_lock_irqsave(&b->bm_lock, flags);
+ if (bm_is_locked(b))
+ bm_print_lock_info(mdev);
+
+ c = __bm_change_bits_to(mdev, s, e, val, KM_IRQ1);
+
+ spin_unlock_irqrestore(&b->bm_lock, flags);
+ return c;
+}
+
+/* returns number of bits changed 0 -> 1 */
+int drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e)
+{
+ return bm_change_bits_to(mdev, s, e, 1);
+}
+
+/* returns number of bits changed 1 -> 0 */
+int drbd_bm_clear_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e)
+{
+ return -bm_change_bits_to(mdev, s, e, 0);
+}
+
+/* sets all bits in full words,
+ * from first_word up to, but not including, last_word */
+static inline void bm_set_full_words_within_one_page(struct drbd_bitmap *b,
+ int page_nr, int first_word, int last_word)
+{
+ int i;
+ int bits;
+ unsigned long *paddr = kmap_atomic(b->bm_pages[page_nr], KM_USER0);
+ for (i = first_word; i < last_word; i++) {
+ bits = hweight_long(paddr[i]);
+ paddr[i] = ~0UL;
+ b->bm_set += BITS_PER_LONG - bits;
+ }
+ kunmap_atomic(paddr, KM_USER0);
+}
+
+/* Same thing as drbd_bm_set_bits, but without taking the spin_lock_irqsave.
+ * You must first drbd_bm_lock().
+ * Can be called to set the whole bitmap in one go.
+ * Sets bits from s to e _inclusive_. */
+void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e)
+{
+ /* First set_bit from the first bit (s)
+ * up to the next long boundary (sl),
+ * then assign full words up to the last long boundary (el),
+ * then set_bit up to and including the last bit (e).
+ *
+ * Do not use memset, because we must account for changes,
+ * so we need to loop over the words with hweight() anyways.
+ */
+ unsigned long sl = ALIGN(s,BITS_PER_LONG);
+ unsigned long el = (e+1) & ~((unsigned long)BITS_PER_LONG-1);
+ int first_page;
+ int last_page;
+ int page_nr;
+ int first_word;
+ int last_word;
+
+ if (e - s <= 3*BITS_PER_LONG) {
+ /* don't bother; el and sl may even be wrong. */
+ __bm_change_bits_to(mdev, s, e, 1, KM_USER0);
+ return;
+ }
+
+ /* difference is large enough that we can trust sl and el */
+
+ /* bits filling the current long */
+ if (sl)
+ __bm_change_bits_to(mdev, s, sl-1, 1, KM_USER0);
+
+ first_page = sl >> (3 + PAGE_SHIFT);
+ last_page = el >> (3 + PAGE_SHIFT);
+
+ /* MLPP: modulo longs per page */
+ /* LWPP: long words per page */
+ first_word = MLPP(sl >> LN2_BPL);
+ last_word = LWPP;
+
+ /* first and full pages, unless first page == last page */
+ for (page_nr = first_page; page_nr < last_page; page_nr++) {
+ bm_set_full_words_within_one_page(mdev->bitmap, page_nr, first_word, last_word);
+ cond_resched();
+ first_word = 0;
+ }
+
+ /* last page (respectively only page, for first page == last page) */
+ last_word = MLPP(el >> LN2_BPL);
+ bm_set_full_words_within_one_page(mdev->bitmap, last_page, first_word, last_word);
+
+ /* possibly trailing bits.
+ * example: (e & 63) == 63, el will be e+1.
+ * if that even was the very last bit,
+ * it would trigger an assert in __bm_change_bits_to()
+ */
+ if (el <= e)
+ __bm_change_bits_to(mdev, el, e, 1, KM_USER0);
+}
+
+/* returns bit state
+ * wants bitnr, NOT sector.
+ * inherently racy... area needs to be locked by means of {al,rs}_lru
+ * 1 ... bit set
+ * 0 ... bit not set
+ * -1 ... first out of bounds access, stop testing for bits!
+ */
+int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr)
+{
+ unsigned long flags;
+ struct drbd_bitmap *b = mdev->bitmap;
+ unsigned long *p_addr;
+ int i;
+
+ ERR_IF(!b) return 0;
+ ERR_IF(!b->bm_pages) return 0;
+
+ spin_lock_irqsave(&b->bm_lock, flags);
+ if (bm_is_locked(b))
+ bm_print_lock_info(mdev);
+ if (bitnr < b->bm_bits) {
+ unsigned long offset = bitnr>>LN2_BPL;
+ p_addr = bm_map_paddr(b, offset);
+ i = test_bit(bitnr & BPP_MASK, p_addr) ? 1 : 0;
+ bm_unmap(p_addr);
+ } else if (bitnr == b->bm_bits) {
+ i = -1;
+ } else { /* (bitnr > b->bm_bits) */
+ dev_err(DEV, "bitnr=%lu > bm_bits=%lu\n", bitnr, b->bm_bits);
+ i = 0;
+ }
+
+ spin_unlock_irqrestore(&b->bm_lock, flags);
+ return i;
+}
+
+/* returns number of bits set in the range [s, e] */
+int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e)
+{
+ unsigned long flags;
+ struct drbd_bitmap *b = mdev->bitmap;
+ unsigned long *p_addr = NULL, page_nr = -1;
+ unsigned long bitnr;
+ int c = 0;
+ size_t w;
+
+ /* If this is called without a bitmap, that is a bug. But just to be
+ * robust in case we screwed up elsewhere, in that case pretend there
+ * was one dirty bit in the requested area, so we won't try to do a
+ * local read there (no bitmap probably implies no disk) */
+ ERR_IF(!b) return 1;
+ ERR_IF(!b->bm_pages) return 1;
+
+ spin_lock_irqsave(&b->bm_lock, flags);
+ if (bm_is_locked(b))
+ bm_print_lock_info(mdev);
+ for (bitnr = s; bitnr <= e; bitnr++) {
+ w = bitnr >> LN2_BPL;
+ if (page_nr != w >> (PAGE_SHIFT - LN2_BPL + 3)) {
+ page_nr = w >> (PAGE_SHIFT - LN2_BPL + 3);
+ if (p_addr)
+ bm_unmap(p_addr);
+ p_addr = bm_map_paddr(b, w);
+ }
+ ERR_IF (bitnr >= b->bm_bits) {
+ dev_err(DEV, "bitnr=%lu bm_bits=%lu\n", bitnr, b->bm_bits);
+ } else {
+ c += (0 != test_bit(bitnr - (page_nr << (PAGE_SHIFT+3)), p_addr));
+ }
+ }
+ if (p_addr)
+ bm_unmap(p_addr);
+ spin_unlock_irqrestore(&b->bm_lock, flags);
+ return c;
+}
+
+
+/* inherently racy...
+ * return value may be already out-of-date when this function returns.
+ * but the general usage is that this is only use during a cstate when bits are
+ * only cleared, not set, and typically only care for the case when the return
+ * value is zero, or we already "locked" this "bitmap extent" by other means.
+ *
+ * enr is bm-extent number, since we chose to name one sector (512 bytes)
+ * worth of the bitmap a "bitmap extent".
+ *
+ * TODO
+ * I think since we use it like a reference count, we should use the real
+ * reference count of some bitmap extent element from some lru instead...
+ *
+ */
+int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr)
+{
+ struct drbd_bitmap *b = mdev->bitmap;
+ int count, s, e;
+ unsigned long flags;
+ unsigned long *p_addr, *bm;
+
+ ERR_IF(!b) return 0;
+ ERR_IF(!b->bm_pages) return 0;
+
+ spin_lock_irqsave(&b->bm_lock, flags);
+ if (bm_is_locked(b))
+ bm_print_lock_info(mdev);
+
+ s = S2W(enr);
+ e = min((size_t)S2W(enr+1), b->bm_words);
+ count = 0;
+ if (s < b->bm_words) {
+ int n = e-s;
+ p_addr = bm_map_paddr(b, s);
+ bm = p_addr + MLPP(s);
+ while (n--)
+ count += hweight_long(*bm++);
+ bm_unmap(p_addr);
+ } else {
+ dev_err(DEV, "start offset (%d) too large in drbd_bm_e_weight\n", s);
+ }
+ spin_unlock_irqrestore(&b->bm_lock, flags);
+ return count;
+}
+
+/* set all bits covered by the AL-extent al_enr */
+unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, unsigned long al_enr)
+{
+ struct drbd_bitmap *b = mdev->bitmap;
+ unsigned long *p_addr, *bm;
+ unsigned long weight;
+ int count, s, e, i, do_now;
+ ERR_IF(!b) return 0;
+ ERR_IF(!b->bm_pages) return 0;
+
+ spin_lock_irq(&b->bm_lock);
+ if (bm_is_locked(b))
+ bm_print_lock_info(mdev);
+ weight = b->bm_set;
+
+ s = al_enr * BM_WORDS_PER_AL_EXT;
+ e = min_t(size_t, s + BM_WORDS_PER_AL_EXT, b->bm_words);
+ /* assert that s and e are on the same page */
+ D_ASSERT((e-1) >> (PAGE_SHIFT - LN2_BPL + 3)
+ == s >> (PAGE_SHIFT - LN2_BPL + 3));
+ count = 0;
+ if (s < b->bm_words) {
+ i = do_now = e-s;
+ p_addr = bm_map_paddr(b, s);
+ bm = p_addr + MLPP(s);
+ while (i--) {
+ count += hweight_long(*bm);
+ *bm = -1UL;
+ bm++;
+ }
+ bm_unmap(p_addr);
+ b->bm_set += do_now*BITS_PER_LONG - count;
+ if (e == b->bm_words)
+ b->bm_set -= bm_clear_surplus(b);
+ } else {
+ dev_err(DEV, "start offset (%d) too large in drbd_bm_ALe_set_all\n", s);
+ }
+ weight = b->bm_set - weight;
+ spin_unlock_irq(&b->bm_lock);
+ return weight;
+}
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
new file mode 100644
index 000000000000..2312d782fe99
--- /dev/null
+++ b/drivers/block/drbd/drbd_int.h
@@ -0,0 +1,2252 @@
+/*
+ drbd_int.h
+
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+ Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+ drbd 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.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT 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 drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef _DRBD_INT_H
+#define _DRBD_INT_H
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/crypto.h>
+#include <linux/ratelimit.h>
+#include <linux/tcp.h>
+#include <linux/mutex.h>
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <linux/genhd.h>
+#include <net/tcp.h>
+#include <linux/lru_cache.h>
+
+#ifdef __CHECKER__
+# define __protected_by(x) __attribute__((require_context(x,1,999,"rdwr")))
+# define __protected_read_by(x) __attribute__((require_context(x,1,999,"read")))
+# define __protected_write_by(x) __attribute__((require_context(x,1,999,"write")))
+# define __must_hold(x) __attribute__((context(x,1,1), require_context(x,1,999,"call")))
+#else
+# define __protected_by(x)
+# define __protected_read_by(x)
+# define __protected_write_by(x)
+# define __must_hold(x)
+#endif
+
+#define __no_warn(lock, stmt) do { __acquire(lock); stmt; __release(lock); } while (0)
+
+/* module parameter, defined in drbd_main.c */
+extern unsigned int minor_count;
+extern int disable_sendpage;
+extern int allow_oos;
+extern unsigned int cn_idx;
+
+#ifdef CONFIG_DRBD_FAULT_INJECTION
+extern int enable_faults;
+extern int fault_rate;
+extern int fault_devs;
+#endif
+
+extern char usermode_helper[];
+
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* I don't remember why XCPU ...
+ * This is used to wake the asender,
+ * and to interrupt sending the sending task
+ * on disconnect.
+ */
+#define DRBD_SIG SIGXCPU
+
+/* This is used to stop/restart our threads.
+ * Cannot use SIGTERM nor SIGKILL, since these
+ * are sent out by init on runlevel changes
+ * I choose SIGHUP for now.
+ */
+#define DRBD_SIGKILL SIGHUP
+
+/* All EEs on the free list should have ID_VACANT (== 0)
+ * freshly allocated EEs get !ID_VACANT (== 1)
+ * so if it says "cannot dereference null pointer at adress 0x00000001",
+ * it is most likely one of these :( */
+
+#define ID_IN_SYNC (4711ULL)
+#define ID_OUT_OF_SYNC (4712ULL)
+
+#define ID_SYNCER (-1ULL)
+#define ID_VACANT 0
+#define is_syncer_block_id(id) ((id) == ID_SYNCER)
+
+struct drbd_conf;
+
+
+/* to shorten dev_warn(DEV, "msg"); and relatives statements */
+#define DEV (disk_to_dev(mdev->vdisk))
+
+#define D_ASSERT(exp) if (!(exp)) \
+ dev_err(DEV, "ASSERT( " #exp " ) in %s:%d\n", __FILE__, __LINE__)
+
+#define ERR_IF(exp) if (({ \
+ int _b = (exp) != 0; \
+ if (_b) dev_err(DEV, "%s: (%s) in %s:%d\n", \
+ __func__, #exp, __FILE__, __LINE__); \
+ _b; \
+ }))
+
+/* Defines to control fault insertion */
+enum {
+ DRBD_FAULT_MD_WR = 0, /* meta data write */
+ DRBD_FAULT_MD_RD = 1, /* read */
+ DRBD_FAULT_RS_WR = 2, /* resync */
+ DRBD_FAULT_RS_RD = 3,
+ DRBD_FAULT_DT_WR = 4, /* data */
+ DRBD_FAULT_DT_RD = 5,
+ DRBD_FAULT_DT_RA = 6, /* data read ahead */
+ DRBD_FAULT_BM_ALLOC = 7, /* bitmap allocation */
+ DRBD_FAULT_AL_EE = 8, /* alloc ee */
+
+ DRBD_FAULT_MAX,
+};
+
+#ifdef CONFIG_DRBD_FAULT_INJECTION
+extern unsigned int
+_drbd_insert_fault(struct drbd_conf *mdev, unsigned int type);
+static inline int
+drbd_insert_fault(struct drbd_conf *mdev, unsigned int type) {
+ return fault_rate &&
+ (enable_faults & (1<<type)) &&
+ _drbd_insert_fault(mdev, type);
+}
+#define FAULT_ACTIVE(_m, _t) (drbd_insert_fault((_m), (_t)))
+
+#else
+#define FAULT_ACTIVE(_m, _t) (0)
+#endif
+
+/* integer division, round _UP_ to the next integer */
+#define div_ceil(A, B) ((A)/(B) + ((A)%(B) ? 1 : 0))
+/* usual integer division */
+#define div_floor(A, B) ((A)/(B))
+
+/* drbd_meta-data.c (still in drbd_main.c) */
+/* 4th incarnation of the disk layout. */
+#define DRBD_MD_MAGIC (DRBD_MAGIC+4)
+
+extern struct drbd_conf **minor_table;
+extern struct ratelimit_state drbd_ratelimit_state;
+
+/* on the wire */
+enum drbd_packets {
+ /* receiver (data socket) */
+ P_DATA = 0x00,
+ P_DATA_REPLY = 0x01, /* Response to P_DATA_REQUEST */
+ P_RS_DATA_REPLY = 0x02, /* Response to P_RS_DATA_REQUEST */
+ P_BARRIER = 0x03,
+ P_BITMAP = 0x04,
+ P_BECOME_SYNC_TARGET = 0x05,
+ P_BECOME_SYNC_SOURCE = 0x06,
+ P_UNPLUG_REMOTE = 0x07, /* Used at various times to hint the peer */
+ P_DATA_REQUEST = 0x08, /* Used to ask for a data block */
+ P_RS_DATA_REQUEST = 0x09, /* Used to ask for a data block for resync */
+ P_SYNC_PARAM = 0x0a,
+ P_PROTOCOL = 0x0b,
+ P_UUIDS = 0x0c,
+ P_SIZES = 0x0d,
+ P_STATE = 0x0e,
+ P_SYNC_UUID = 0x0f,
+ P_AUTH_CHALLENGE = 0x10,
+ P_AUTH_RESPONSE = 0x11,
+ P_STATE_CHG_REQ = 0x12,
+
+ /* asender (meta socket */
+ P_PING = 0x13,
+ P_PING_ACK = 0x14,
+ P_RECV_ACK = 0x15, /* Used in protocol B */
+ P_WRITE_ACK = 0x16, /* Used in protocol C */
+ P_RS_WRITE_ACK = 0x17, /* Is a P_WRITE_ACK, additionally call set_in_sync(). */
+ P_DISCARD_ACK = 0x18, /* Used in proto C, two-primaries conflict detection */
+ P_NEG_ACK = 0x19, /* Sent if local disk is unusable */
+ P_NEG_DREPLY = 0x1a, /* Local disk is broken... */
+ P_NEG_RS_DREPLY = 0x1b, /* Local disk is broken... */
+ P_BARRIER_ACK = 0x1c,
+ P_STATE_CHG_REPLY = 0x1d,
+
+ /* "new" commands, no longer fitting into the ordering scheme above */
+
+ P_OV_REQUEST = 0x1e, /* data socket */
+ P_OV_REPLY = 0x1f,
+ P_OV_RESULT = 0x20, /* meta socket */
+ P_CSUM_RS_REQUEST = 0x21, /* data socket */
+ P_RS_IS_IN_SYNC = 0x22, /* meta socket */
+ P_SYNC_PARAM89 = 0x23, /* data socket, protocol version 89 replacement for P_SYNC_PARAM */
+ P_COMPRESSED_BITMAP = 0x24, /* compressed or otherwise encoded bitmap transfer */
+
+ P_MAX_CMD = 0x25,
+ P_MAY_IGNORE = 0x100, /* Flag to test if (cmd > P_MAY_IGNORE) ... */
+ P_MAX_OPT_CMD = 0x101,
+
+ /* special command ids for handshake */
+
+ P_HAND_SHAKE_M = 0xfff1, /* First Packet on the MetaSock */
+ P_HAND_SHAKE_S = 0xfff2, /* First Packet on the Socket */
+
+ P_HAND_SHAKE = 0xfffe /* FIXED for the next century! */
+};
+
+static inline const char *cmdname(enum drbd_packets cmd)
+{
+ /* THINK may need to become several global tables
+ * when we want to support more than
+ * one PRO_VERSION */
+ static const char *cmdnames[] = {
+ [P_DATA] = "Data",
+ [P_DATA_REPLY] = "DataReply",
+ [P_RS_DATA_REPLY] = "RSDataReply",
+ [P_BARRIER] = "Barrier",
+ [P_BITMAP] = "ReportBitMap",
+ [P_BECOME_SYNC_TARGET] = "BecomeSyncTarget",
+ [P_BECOME_SYNC_SOURCE] = "BecomeSyncSource",
+ [P_UNPLUG_REMOTE] = "UnplugRemote",
+ [P_DATA_REQUEST] = "DataRequest",
+ [P_RS_DATA_REQUEST] = "RSDataRequest",
+ [P_SYNC_PARAM] = "SyncParam",
+ [P_SYNC_PARAM89] = "SyncParam89",
+ [P_PROTOCOL] = "ReportProtocol",
+ [P_UUIDS] = "ReportUUIDs",
+ [P_SIZES] = "ReportSizes",
+ [P_STATE] = "ReportState",
+ [P_SYNC_UUID] = "ReportSyncUUID",
+ [P_AUTH_CHALLENGE] = "AuthChallenge",
+ [P_AUTH_RESPONSE] = "AuthResponse",
+ [P_PING] = "Ping",
+ [P_PING_ACK] = "PingAck",
+ [P_RECV_ACK] = "RecvAck",
+ [P_WRITE_ACK] = "WriteAck",
+ [P_RS_WRITE_ACK] = "RSWriteAck",
+ [P_DISCARD_ACK] = "DiscardAck",
+ [P_NEG_ACK] = "NegAck",
+ [P_NEG_DREPLY] = "NegDReply",
+ [P_NEG_RS_DREPLY] = "NegRSDReply",
+ [P_BARRIER_ACK] = "BarrierAck",
+ [P_STATE_CHG_REQ] = "StateChgRequest",
+ [P_STATE_CHG_REPLY] = "StateChgReply",
+ [P_OV_REQUEST] = "OVRequest",
+ [P_OV_REPLY] = "OVReply",
+ [P_OV_RESULT] = "OVResult",
+ [P_MAX_CMD] = NULL,
+ };
+
+ if (cmd == P_HAND_SHAKE_M)
+ return "HandShakeM";
+ if (cmd == P_HAND_SHAKE_S)
+ return "HandShakeS";
+ if (cmd == P_HAND_SHAKE)
+ return "HandShake";
+ if (cmd >= P_MAX_CMD)
+ return "Unknown";
+ return cmdnames[cmd];
+}
+
+/* for sending/receiving the bitmap,
+ * possibly in some encoding scheme */
+struct bm_xfer_ctx {
+ /* "const"
+ * stores total bits and long words
+ * of the bitmap, so we don't need to
+ * call the accessor functions over and again. */
+ unsigned long bm_bits;
+ unsigned long bm_words;
+ /* during xfer, current position within the bitmap */
+ unsigned long bit_offset;
+ unsigned long word_offset;
+
+ /* statistics; index: (h->command == P_BITMAP) */
+ unsigned packets[2];
+ unsigned bytes[2];
+};
+
+extern void INFO_bm_xfer_stats(struct drbd_conf *mdev,
+ const char *direction, struct bm_xfer_ctx *c);
+
+static inline void bm_xfer_ctx_bit_to_word_offset(struct bm_xfer_ctx *c)
+{
+ /* word_offset counts "native long words" (32 or 64 bit),
+ * aligned at 64 bit.
+ * Encoded packet may end at an unaligned bit offset.
+ * In case a fallback clear text packet is transmitted in
+ * between, we adjust this offset back to the last 64bit
+ * aligned "native long word", which makes coding and decoding
+ * the plain text bitmap much more convenient. */
+#if BITS_PER_LONG == 64
+ c->word_offset = c->bit_offset >> 6;
+#elif BITS_PER_LONG == 32
+ c->word_offset = c->bit_offset >> 5;
+ c->word_offset &= ~(1UL);
+#else
+# error "unsupported BITS_PER_LONG"
+#endif
+}
+
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+
+/* This is the layout for a packet on the wire.
+ * The byteorder is the network byte order.
+ * (except block_id and barrier fields.
+ * these are pointers to local structs
+ * and have no relevance for the partner,
+ * which just echoes them as received.)
+ *
+ * NOTE that the payload starts at a long aligned offset,
+ * regardless of 32 or 64 bit arch!
+ */
+struct p_header {
+ u32 magic;
+ u16 command;
+ u16 length; /* bytes of data after this header */
+ u8 payload[0];
+} __packed;
+/* 8 bytes. packet FIXED for the next century! */
+
+/*
+ * short commands, packets without payload, plain p_header:
+ * P_PING
+ * P_PING_ACK
+ * P_BECOME_SYNC_TARGET
+ * P_BECOME_SYNC_SOURCE
+ * P_UNPLUG_REMOTE
+ */
+
+/*
+ * commands with out-of-struct payload:
+ * P_BITMAP (no additional fields)
+ * P_DATA, P_DATA_REPLY (see p_data)
+ * P_COMPRESSED_BITMAP (see receive_compressed_bitmap)
+ */
+
+/* these defines must not be changed without changing the protocol version */
+#define DP_HARDBARRIER 1
+#define DP_RW_SYNC 2
+#define DP_MAY_SET_IN_SYNC 4
+
+struct p_data {
+ struct p_header head;
+ u64 sector; /* 64 bits sector number */
+ u64 block_id; /* to identify the request in protocol B&C */
+ u32 seq_num;
+ u32 dp_flags;
+} __packed;
+
+/*
+ * commands which share a struct:
+ * p_block_ack:
+ * P_RECV_ACK (proto B), P_WRITE_ACK (proto C),
+ * P_DISCARD_ACK (proto C, two-primaries conflict detection)
+ * p_block_req:
+ * P_DATA_REQUEST, P_RS_DATA_REQUEST
+ */
+struct p_block_ack {
+ struct p_header head;
+ u64 sector;
+ u64 block_id;
+ u32 blksize;
+ u32 seq_num;
+} __packed;
+
+
+struct p_block_req {
+ struct p_header head;
+ u64 sector;
+ u64 block_id;
+ u32 blksize;
+ u32 pad; /* to multiple of 8 Byte */
+} __packed;
+
+/*
+ * commands with their own struct for additional fields:
+ * P_HAND_SHAKE
+ * P_BARRIER
+ * P_BARRIER_ACK
+ * P_SYNC_PARAM
+ * ReportParams
+ */
+
+struct p_handshake {
+ struct p_header head; /* 8 bytes */
+ u32 protocol_min;
+ u32 feature_flags;
+ u32 protocol_max;
+
+ /* should be more than enough for future enhancements
+ * for now, feature_flags and the reserverd array shall be zero.
+ */
+
+ u32 _pad;
+ u64 reserverd[7];
+} __packed;
+/* 80 bytes, FIXED for the next century */
+
+struct p_barrier {
+ struct p_header head;
+ u32 barrier; /* barrier number _handle_ only */
+ u32 pad; /* to multiple of 8 Byte */
+} __packed;
+
+struct p_barrier_ack {
+ struct p_header head;
+ u32 barrier;
+ u32 set_size;
+} __packed;
+
+struct p_rs_param {
+ struct p_header head;
+ u32 rate;
+
+ /* Since protocol version 88 and higher. */
+ char verify_alg[0];
+} __packed;
+
+struct p_rs_param_89 {
+ struct p_header head;
+ u32 rate;
+ /* protocol version 89: */
+ char verify_alg[SHARED_SECRET_MAX];
+ char csums_alg[SHARED_SECRET_MAX];
+} __packed;
+
+struct p_protocol {
+ struct p_header head;
+ u32 protocol;
+ u32 after_sb_0p;
+ u32 after_sb_1p;
+ u32 after_sb_2p;
+ u32 want_lose;
+ u32 two_primaries;
+
+ /* Since protocol version 87 and higher. */
+ char integrity_alg[0];
+
+} __packed;
+
+struct p_uuids {
+ struct p_header head;
+ u64 uuid[UI_EXTENDED_SIZE];
+} __packed;
+
+struct p_rs_uuid {
+ struct p_header head;
+ u64 uuid;
+} __packed;
+
+struct p_sizes {
+ struct p_header head;
+ u64 d_size; /* size of disk */
+ u64 u_size; /* user requested size */
+ u64 c_size; /* current exported size */
+ u32 max_segment_size; /* Maximal size of a BIO */
+ u32 queue_order_type;
+} __packed;
+
+struct p_state {
+ struct p_header head;
+ u32 state;
+} __packed;
+
+struct p_req_state {
+ struct p_header head;
+ u32 mask;
+ u32 val;
+} __packed;
+
+struct p_req_state_reply {
+ struct p_header head;
+ u32 retcode;
+} __packed;
+
+struct p_drbd06_param {
+ u64 size;
+ u32 state;
+ u32 blksize;
+ u32 protocol;
+ u32 version;
+ u32 gen_cnt[5];
+ u32 bit_map_gen[5];
+} __packed;
+
+struct p_discard {
+ struct p_header head;
+ u64 block_id;
+ u32 seq_num;
+ u32 pad;
+} __packed;
+
+/* Valid values for the encoding field.
+ * Bump proto version when changing this. */
+enum drbd_bitmap_code {
+ /* RLE_VLI_Bytes = 0,
+ * and other bit variants had been defined during
+ * algorithm evaluation. */
+ RLE_VLI_Bits = 2,
+};
+
+struct p_compressed_bm {
+ struct p_header head;
+ /* (encoding & 0x0f): actual encoding, see enum drbd_bitmap_code
+ * (encoding & 0x80): polarity (set/unset) of first runlength
+ * ((encoding >> 4) & 0x07): pad_bits, number of trailing zero bits
+ * used to pad up to head.length bytes
+ */
+ u8 encoding;
+
+ u8 code[0];
+} __packed;
+
+/* DCBP: Drbd Compressed Bitmap Packet ... */
+static inline enum drbd_bitmap_code
+DCBP_get_code(struct p_compressed_bm *p)
+{
+ return (enum drbd_bitmap_code)(p->encoding & 0x0f);
+}
+
+static inline void
+DCBP_set_code(struct p_compressed_bm *p, enum drbd_bitmap_code code)
+{
+ BUG_ON(code & ~0xf);
+ p->encoding = (p->encoding & ~0xf) | code;
+}
+
+static inline int
+DCBP_get_start(struct p_compressed_bm *p)
+{
+ return (p->encoding & 0x80) != 0;
+}
+
+static inline void
+DCBP_set_start(struct p_compressed_bm *p, int set)
+{
+ p->encoding = (p->encoding & ~0x80) | (set ? 0x80 : 0);
+}
+
+static inline int
+DCBP_get_pad_bits(struct p_compressed_bm *p)
+{
+ return (p->encoding >> 4) & 0x7;
+}
+
+static inline void
+DCBP_set_pad_bits(struct p_compressed_bm *p, int n)
+{
+ BUG_ON(n & ~0x7);
+ p->encoding = (p->encoding & (~0x7 << 4)) | (n << 4);
+}
+
+/* one bitmap packet, including the p_header,
+ * should fit within one _architecture independend_ page.
+ * so we need to use the fixed size 4KiB page size
+ * most architechtures have used for a long time.
+ */
+#define BM_PACKET_PAYLOAD_BYTES (4096 - sizeof(struct p_header))
+#define BM_PACKET_WORDS (BM_PACKET_PAYLOAD_BYTES/sizeof(long))
+#define BM_PACKET_VLI_BYTES_MAX (4096 - sizeof(struct p_compressed_bm))
+#if (PAGE_SIZE < 4096)
+/* drbd_send_bitmap / receive_bitmap would break horribly */
+#error "PAGE_SIZE too small"
+#endif
+
+union p_polymorph {
+ struct p_header header;
+ struct p_handshake handshake;
+ struct p_data data;
+ struct p_block_ack block_ack;
+ struct p_barrier barrier;
+ struct p_barrier_ack barrier_ack;
+ struct p_rs_param_89 rs_param_89;
+ struct p_protocol protocol;
+ struct p_sizes sizes;
+ struct p_uuids uuids;
+ struct p_state state;
+ struct p_req_state req_state;
+ struct p_req_state_reply req_state_reply;
+ struct p_block_req block_req;
+} __packed;
+
+/**********************************************************************/
+enum drbd_thread_state {
+ None,
+ Running,
+ Exiting,
+ Restarting
+};
+
+struct drbd_thread {
+ spinlock_t t_lock;
+ struct task_struct *task;
+ struct completion stop;
+ enum drbd_thread_state t_state;
+ int (*function) (struct drbd_thread *);
+ struct drbd_conf *mdev;
+ int reset_cpu_mask;
+};
+
+static inline enum drbd_thread_state get_t_state(struct drbd_thread *thi)
+{
+ /* THINK testing the t_state seems to be uncritical in all cases
+ * (but thread_{start,stop}), so we can read it *without* the lock.
+ * --lge */
+
+ smp_rmb();
+ return thi->t_state;
+}
+
+
+/*
+ * Having this as the first member of a struct provides sort of "inheritance".
+ * "derived" structs can be "drbd_queue_work()"ed.
+ * The callback should know and cast back to the descendant struct.
+ * drbd_request and drbd_epoch_entry are descendants of drbd_work.
+ */
+struct drbd_work;
+typedef int (*drbd_work_cb)(struct drbd_conf *, struct drbd_work *, int cancel);
+struct drbd_work {
+ struct list_head list;
+ drbd_work_cb cb;
+};
+
+struct drbd_tl_epoch;
+struct drbd_request {
+ struct drbd_work w;
+ struct drbd_conf *mdev;
+
+ /* if local IO is not allowed, will be NULL.
+ * if local IO _is_ allowed, holds the locally submitted bio clone,
+ * or, after local IO completion, the ERR_PTR(error).
+ * see drbd_endio_pri(). */
+ struct bio *private_bio;
+
+ struct hlist_node colision;
+ sector_t sector;
+ unsigned int size;
+ unsigned int epoch; /* barrier_nr */
+
+ /* barrier_nr: used to check on "completion" whether this req was in
+ * the current epoch, and we therefore have to close it,
+ * starting a new epoch...
+ */
+
+ /* up to here, the struct layout is identical to drbd_epoch_entry;
+ * we might be able to use that to our advantage... */
+
+ struct list_head tl_requests; /* ring list in the transfer log */
+ struct bio *master_bio; /* master bio pointer */
+ unsigned long rq_state; /* see comments above _req_mod() */
+ int seq_num;
+ unsigned long start_time;
+};
+
+struct drbd_tl_epoch {
+ struct drbd_work w;
+ struct list_head requests; /* requests before */
+ struct drbd_tl_epoch *next; /* pointer to the next barrier */
+ unsigned int br_number; /* the barriers identifier. */
+ int n_req; /* number of requests attached before this barrier */
+};
+
+struct drbd_request;
+
+/* These Tl_epoch_entries may be in one of 6 lists:
+ active_ee .. data packet being written
+ sync_ee .. syncer block being written
+ done_ee .. block written, need to send P_WRITE_ACK
+ read_ee .. [RS]P_DATA_REQUEST being read
+*/
+
+struct drbd_epoch {
+ struct list_head list;
+ unsigned int barrier_nr;
+ atomic_t epoch_size; /* increased on every request added. */
+ atomic_t active; /* increased on every req. added, and dec on every finished. */
+ unsigned long flags;
+};
+
+/* drbd_epoch flag bits */
+enum {
+ DE_BARRIER_IN_NEXT_EPOCH_ISSUED,
+ DE_BARRIER_IN_NEXT_EPOCH_DONE,
+ DE_CONTAINS_A_BARRIER,
+ DE_HAVE_BARRIER_NUMBER,
+ DE_IS_FINISHING,
+};
+
+enum epoch_event {
+ EV_PUT,
+ EV_GOT_BARRIER_NR,
+ EV_BARRIER_DONE,
+ EV_BECAME_LAST,
+ EV_CLEANUP = 32, /* used as flag */
+};
+
+struct drbd_epoch_entry {
+ struct drbd_work w;
+ struct drbd_conf *mdev;
+ struct bio *private_bio;
+ struct hlist_node colision;
+ sector_t sector;
+ unsigned int size;
+ struct drbd_epoch *epoch;
+
+ /* up to here, the struct layout is identical to drbd_request;
+ * we might be able to use that to our advantage... */
+
+ unsigned int flags;
+ u64 block_id;
+};
+
+struct drbd_wq_barrier {
+ struct drbd_work w;
+ struct completion done;
+};
+
+struct digest_info {
+ int digest_size;
+ void *digest;
+};
+
+/* ee flag bits */
+enum {
+ __EE_CALL_AL_COMPLETE_IO,
+ __EE_CONFLICT_PENDING,
+ __EE_MAY_SET_IN_SYNC,
+ __EE_IS_BARRIER,
+};
+#define EE_CALL_AL_COMPLETE_IO (1<<__EE_CALL_AL_COMPLETE_IO)
+#define EE_CONFLICT_PENDING (1<<__EE_CONFLICT_PENDING)
+#define EE_MAY_SET_IN_SYNC (1<<__EE_MAY_SET_IN_SYNC)
+#define EE_IS_BARRIER (1<<__EE_IS_BARRIER)
+
+/* global flag bits */
+enum {
+ CREATE_BARRIER, /* next P_DATA is preceeded by a P_BARRIER */
+ SIGNAL_ASENDER, /* whether asender wants to be interrupted */
+ SEND_PING, /* whether asender should send a ping asap */
+
+ STOP_SYNC_TIMER, /* tell timer to cancel itself */
+ UNPLUG_QUEUED, /* only relevant with kernel 2.4 */
+ UNPLUG_REMOTE, /* sending a "UnplugRemote" could help */
+ MD_DIRTY, /* current uuids and flags not yet on disk */
+ DISCARD_CONCURRENT, /* Set on one node, cleared on the peer! */
+ USE_DEGR_WFC_T, /* degr-wfc-timeout instead of wfc-timeout. */
+ CLUSTER_ST_CHANGE, /* Cluster wide state change going on... */
+ CL_ST_CHG_SUCCESS,
+ CL_ST_CHG_FAIL,
+ CRASHED_PRIMARY, /* This node was a crashed primary.
+ * Gets cleared when the state.conn
+ * goes into C_CONNECTED state. */
+ WRITE_BM_AFTER_RESYNC, /* A kmalloc() during resync failed */
+ NO_BARRIER_SUPP, /* underlying block device doesn't implement barriers */
+ CONSIDER_RESYNC,
+
+ MD_NO_BARRIER, /* meta data device does not support barriers,
+ so don't even try */
+ SUSPEND_IO, /* suspend application io */
+ BITMAP_IO, /* suspend application io;
+ once no more io in flight, start bitmap io */
+ BITMAP_IO_QUEUED, /* Started bitmap IO */
+ RESYNC_AFTER_NEG, /* Resync after online grow after the attach&negotiate finished. */
+ NET_CONGESTED, /* The data socket is congested */
+
+ CONFIG_PENDING, /* serialization of (re)configuration requests.
+ * if set, also prevents the device from dying */
+ DEVICE_DYING, /* device became unconfigured,
+ * but worker thread is still handling the cleanup.
+ * reconfiguring (nl_disk_conf, nl_net_conf) is dissalowed,
+ * while this is set. */
+ RESIZE_PENDING, /* Size change detected locally, waiting for the response from
+ * the peer, if it changed there as well. */
+};
+
+struct drbd_bitmap; /* opaque for drbd_conf */
+
+/* TODO sort members for performance
+ * MAYBE group them further */
+
+/* THINK maybe we actually want to use the default "event/%s" worker threads
+ * or similar in linux 2.6, which uses per cpu data and threads.
+ *
+ * To be general, this might need a spin_lock member.
+ * For now, please use the mdev->req_lock to protect list_head,
+ * see drbd_queue_work below.
+ */
+struct drbd_work_queue {
+ struct list_head q;
+ struct semaphore s; /* producers up it, worker down()s it */
+ spinlock_t q_lock; /* to protect the list. */
+};
+
+struct drbd_socket {
+ struct drbd_work_queue work;
+ struct mutex mutex;
+ struct socket *socket;
+ /* this way we get our
+ * send/receive buffers off the stack */
+ union p_polymorph sbuf;
+ union p_polymorph rbuf;
+};
+
+struct drbd_md {
+ u64 md_offset; /* sector offset to 'super' block */
+
+ u64 la_size_sect; /* last agreed size, unit sectors */
+ u64 uuid[UI_SIZE];
+ u64 device_uuid;
+ u32 flags;
+ u32 md_size_sect;
+
+ s32 al_offset; /* signed relative sector offset to al area */
+ s32 bm_offset; /* signed relative sector offset to bitmap */
+
+ /* u32 al_nr_extents; important for restoring the AL
+ * is stored into sync_conf.al_extents, which in turn
+ * gets applied to act_log->nr_elements
+ */
+};
+
+/* for sync_conf and other types... */
+#define NL_PACKET(name, number, fields) struct name { fields };
+#define NL_INTEGER(pn,pr,member) int member;
+#define NL_INT64(pn,pr,member) __u64 member;
+#define NL_BIT(pn,pr,member) unsigned member:1;
+#define NL_STRING(pn,pr,member,len) unsigned char member[len]; int member ## _len;
+#include "linux/drbd_nl.h"
+
+struct drbd_backing_dev {
+ struct block_device *backing_bdev;
+ struct block_device *md_bdev;
+ struct file *lo_file;
+ struct file *md_file;
+ struct drbd_md md;
+ struct disk_conf dc; /* The user provided config... */
+ sector_t known_size; /* last known size of that backing device */
+};
+
+struct drbd_md_io {
+ struct drbd_conf *mdev;
+ struct completion event;
+ int error;
+};
+
+struct bm_io_work {
+ struct drbd_work w;
+ char *why;
+ int (*io_fn)(struct drbd_conf *mdev);
+ void (*done)(struct drbd_conf *mdev, int rv);
+};
+
+enum write_ordering_e {
+ WO_none,
+ WO_drain_io,
+ WO_bdev_flush,
+ WO_bio_barrier
+};
+
+struct drbd_conf {
+ /* things that are stored as / read from meta data on disk */
+ unsigned long flags;
+
+ /* configured by drbdsetup */
+ struct net_conf *net_conf; /* protected by get_net_conf() and put_net_conf() */
+ struct syncer_conf sync_conf;
+ struct drbd_backing_dev *ldev __protected_by(local);
+
+ sector_t p_size; /* partner's disk size */
+ struct request_queue *rq_queue;
+ struct block_device *this_bdev;
+ struct gendisk *vdisk;
+
+ struct drbd_socket data; /* data/barrier/cstate/parameter packets */
+ struct drbd_socket meta; /* ping/ack (metadata) packets */
+ int agreed_pro_version; /* actually used protocol version */
+ unsigned long last_received; /* in jiffies, either socket */
+ unsigned int ko_count;
+ struct drbd_work resync_work,
+ unplug_work,
+ md_sync_work;
+ struct timer_list resync_timer;
+ struct timer_list md_sync_timer;
+
+ /* Used after attach while negotiating new disk state. */
+ union drbd_state new_state_tmp;
+
+ union drbd_state state;
+ wait_queue_head_t misc_wait;
+ wait_queue_head_t state_wait; /* upon each state change. */
+ unsigned int send_cnt;
+ unsigned int recv_cnt;
+ unsigned int read_cnt;
+ unsigned int writ_cnt;
+ unsigned int al_writ_cnt;
+ unsigned int bm_writ_cnt;
+ atomic_t ap_bio_cnt; /* Requests we need to complete */
+ atomic_t ap_pending_cnt; /* AP data packets on the wire, ack expected */
+ atomic_t rs_pending_cnt; /* RS request/data packets on the wire */
+ atomic_t unacked_cnt; /* Need to send replys for */
+ atomic_t local_cnt; /* Waiting for local completion */
+ atomic_t net_cnt; /* Users of net_conf */
+ spinlock_t req_lock;
+ struct drbd_tl_epoch *unused_spare_tle; /* for pre-allocation */
+ struct drbd_tl_epoch *newest_tle;
+ struct drbd_tl_epoch *oldest_tle;
+ struct list_head out_of_sequence_requests;
+ struct hlist_head *tl_hash;
+ unsigned int tl_hash_s;
+
+ /* blocks to sync in this run [unit BM_BLOCK_SIZE] */
+ unsigned long rs_total;
+ /* number of sync IOs that failed in this run */
+ unsigned long rs_failed;
+ /* Syncer's start time [unit jiffies] */
+ unsigned long rs_start;
+ /* cumulated time in PausedSyncX state [unit jiffies] */
+ unsigned long rs_paused;
+ /* block not up-to-date at mark [unit BM_BLOCK_SIZE] */
+ unsigned long rs_mark_left;
+ /* marks's time [unit jiffies] */
+ unsigned long rs_mark_time;
+ /* skipped because csum was equeal [unit BM_BLOCK_SIZE] */
+ unsigned long rs_same_csum;
+
+ /* where does the admin want us to start? (sector) */
+ sector_t ov_start_sector;
+ /* where are we now? (sector) */
+ sector_t ov_position;
+ /* Start sector of out of sync range (to merge printk reporting). */
+ sector_t ov_last_oos_start;
+ /* size of out-of-sync range in sectors. */
+ sector_t ov_last_oos_size;
+ unsigned long ov_left; /* in bits */
+ struct crypto_hash *csums_tfm;
+ struct crypto_hash *verify_tfm;
+
+ struct drbd_thread receiver;
+ struct drbd_thread worker;
+ struct drbd_thread asender;
+ struct drbd_bitmap *bitmap;
+ unsigned long bm_resync_fo; /* bit offset for drbd_bm_find_next */
+
+ /* Used to track operations of resync... */
+ struct lru_cache *resync;
+ /* Number of locked elements in resync LRU */
+ unsigned int resync_locked;
+ /* resync extent number waiting for application requests */
+ unsigned int resync_wenr;
+
+ int open_cnt;
+ u64 *p_uuid;
+ struct drbd_epoch *current_epoch;
+ spinlock_t epoch_lock;
+ unsigned int epochs;
+ enum write_ordering_e write_ordering;
+ struct list_head active_ee; /* IO in progress */
+ struct list_head sync_ee; /* IO in progress */
+ struct list_head done_ee; /* send ack */
+ struct list_head read_ee; /* IO in progress */
+ struct list_head net_ee; /* zero-copy network send in progress */
+ struct hlist_head *ee_hash; /* is proteced by req_lock! */
+ unsigned int ee_hash_s;
+
+ /* this one is protected by ee_lock, single thread */
+ struct drbd_epoch_entry *last_write_w_barrier;
+
+ int next_barrier_nr;
+ struct hlist_head *app_reads_hash; /* is proteced by req_lock */
+ struct list_head resync_reads;
+ atomic_t pp_in_use;
+ wait_queue_head_t ee_wait;
+ struct page *md_io_page; /* one page buffer for md_io */
+ struct page *md_io_tmpp; /* for logical_block_size != 512 */
+ struct mutex md_io_mutex; /* protects the md_io_buffer */
+ spinlock_t al_lock;
+ wait_queue_head_t al_wait;
+ struct lru_cache *act_log; /* activity log */
+ unsigned int al_tr_number;
+ int al_tr_cycle;
+ int al_tr_pos; /* position of the next transaction in the journal */
+ struct crypto_hash *cram_hmac_tfm;
+ struct crypto_hash *integrity_w_tfm; /* to be used by the worker thread */
+ struct crypto_hash *integrity_r_tfm; /* to be used by the receiver thread */
+ void *int_dig_out;
+ void *int_dig_in;
+ void *int_dig_vv;
+ wait_queue_head_t seq_wait;
+ atomic_t packet_seq;
+ unsigned int peer_seq;
+ spinlock_t peer_seq_lock;
+ unsigned int minor;
+ unsigned long comm_bm_set; /* communicated number of set bits. */
+ cpumask_var_t cpu_mask;
+ struct bm_io_work bm_io_work;
+ u64 ed_uuid; /* UUID of the exposed data */
+ struct mutex state_mutex;
+ char congestion_reason; /* Why we where congested... */
+};
+
+static inline struct drbd_conf *minor_to_mdev(unsigned int minor)
+{
+ struct drbd_conf *mdev;
+
+ mdev = minor < minor_count ? minor_table[minor] : NULL;
+
+ return mdev;
+}
+
+static inline unsigned int mdev_to_minor(struct drbd_conf *mdev)
+{
+ return mdev->minor;
+}
+
+/* returns 1 if it was successfull,
+ * returns 0 if there was no data socket.
+ * so wherever you are going to use the data.socket, e.g. do
+ * if (!drbd_get_data_sock(mdev))
+ * return 0;
+ * CODE();
+ * drbd_put_data_sock(mdev);
+ */
+static inline int drbd_get_data_sock(struct drbd_conf *mdev)
+{
+ mutex_lock(&mdev->data.mutex);
+ /* drbd_disconnect() could have called drbd_free_sock()
+ * while we were waiting in down()... */
+ if (unlikely(mdev->data.socket == NULL)) {
+ mutex_unlock(&mdev->data.mutex);
+ return 0;
+ }
+ return 1;
+}
+
+static inline void drbd_put_data_sock(struct drbd_conf *mdev)
+{
+ mutex_unlock(&mdev->data.mutex);
+}
+
+/*
+ * function declarations
+ *************************/
+
+/* drbd_main.c */
+
+enum chg_state_flags {
+ CS_HARD = 1,
+ CS_VERBOSE = 2,
+ CS_WAIT_COMPLETE = 4,
+ CS_SERIALIZE = 8,
+ CS_ORDERED = CS_WAIT_COMPLETE + CS_SERIALIZE,
+};
+
+extern void drbd_init_set_defaults(struct drbd_conf *mdev);
+extern int drbd_change_state(struct drbd_conf *mdev, enum chg_state_flags f,
+ union drbd_state mask, union drbd_state val);
+extern void drbd_force_state(struct drbd_conf *, union drbd_state,
+ union drbd_state);
+extern int _drbd_request_state(struct drbd_conf *, union drbd_state,
+ union drbd_state, enum chg_state_flags);
+extern int __drbd_set_state(struct drbd_conf *, union drbd_state,
+ enum chg_state_flags, struct completion *done);
+extern void print_st_err(struct drbd_conf *, union drbd_state,
+ union drbd_state, int);
+extern int drbd_thread_start(struct drbd_thread *thi);
+extern void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait);
+#ifdef CONFIG_SMP
+extern void drbd_thread_current_set_cpu(struct drbd_conf *mdev);
+extern void drbd_calc_cpu_mask(struct drbd_conf *mdev);
+#else
+#define drbd_thread_current_set_cpu(A) ({})
+#define drbd_calc_cpu_mask(A) ({})
+#endif
+extern void drbd_free_resources(struct drbd_conf *mdev);
+extern void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr,
+ unsigned int set_size);
+extern void tl_clear(struct drbd_conf *mdev);
+extern void _tl_add_barrier(struct drbd_conf *, struct drbd_tl_epoch *);
+extern void drbd_free_sock(struct drbd_conf *mdev);
+extern int drbd_send(struct drbd_conf *mdev, struct socket *sock,
+ void *buf, size_t size, unsigned msg_flags);
+extern int drbd_send_protocol(struct drbd_conf *mdev);
+extern int drbd_send_uuids(struct drbd_conf *mdev);
+extern int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev);
+extern int drbd_send_sync_uuid(struct drbd_conf *mdev, u64 val);
+extern int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply);
+extern int _drbd_send_state(struct drbd_conf *mdev);
+extern int drbd_send_state(struct drbd_conf *mdev);
+extern int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock,
+ enum drbd_packets cmd, struct p_header *h,
+ size_t size, unsigned msg_flags);
+#define USE_DATA_SOCKET 1
+#define USE_META_SOCKET 0
+extern int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket,
+ enum drbd_packets cmd, struct p_header *h,
+ size_t size);
+extern int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packets cmd,
+ char *data, size_t size);
+extern int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc);
+extern int drbd_send_b_ack(struct drbd_conf *mdev, u32 barrier_nr,
+ u32 set_size);
+extern int drbd_send_ack(struct drbd_conf *mdev, enum drbd_packets cmd,
+ struct drbd_epoch_entry *e);
+extern int drbd_send_ack_rp(struct drbd_conf *mdev, enum drbd_packets cmd,
+ struct p_block_req *rp);
+extern int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packets cmd,
+ struct p_data *dp);
+extern int drbd_send_ack_ex(struct drbd_conf *mdev, enum drbd_packets cmd,
+ sector_t sector, int blksize, u64 block_id);
+extern int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd,
+ struct drbd_epoch_entry *e);
+extern int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req);
+extern int _drbd_send_barrier(struct drbd_conf *mdev,
+ struct drbd_tl_epoch *barrier);
+extern int drbd_send_drequest(struct drbd_conf *mdev, int cmd,
+ sector_t sector, int size, u64 block_id);
+extern int drbd_send_drequest_csum(struct drbd_conf *mdev,
+ sector_t sector,int size,
+ void *digest, int digest_size,
+ enum drbd_packets cmd);
+extern int drbd_send_ov_request(struct drbd_conf *mdev,sector_t sector,int size);
+
+extern int drbd_send_bitmap(struct drbd_conf *mdev);
+extern int _drbd_send_bitmap(struct drbd_conf *mdev);
+extern int drbd_send_sr_reply(struct drbd_conf *mdev, int retcode);
+extern void drbd_free_bc(struct drbd_backing_dev *ldev);
+extern void drbd_mdev_cleanup(struct drbd_conf *mdev);
+
+/* drbd_meta-data.c (still in drbd_main.c) */
+extern void drbd_md_sync(struct drbd_conf *mdev);
+extern int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev);
+/* maybe define them below as inline? */
+extern void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local);
+extern void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local);
+extern void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local);
+extern void _drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local);
+extern void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local);
+extern void drbd_md_set_flag(struct drbd_conf *mdev, int flags) __must_hold(local);
+extern void drbd_md_clear_flag(struct drbd_conf *mdev, int flags)__must_hold(local);
+extern int drbd_md_test_flag(struct drbd_backing_dev *, int);
+extern void drbd_md_mark_dirty(struct drbd_conf *mdev);
+extern void drbd_queue_bitmap_io(struct drbd_conf *mdev,
+ int (*io_fn)(struct drbd_conf *),
+ void (*done)(struct drbd_conf *, int),
+ char *why);
+extern int drbd_bmio_set_n_write(struct drbd_conf *mdev);
+extern int drbd_bmio_clear_n_write(struct drbd_conf *mdev);
+extern int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why);
+
+
+/* Meta data layout
+ We reserve a 128MB Block (4k aligned)
+ * either at the end of the backing device
+ * or on a seperate meta data device. */
+
+#define MD_RESERVED_SECT (128LU << 11) /* 128 MB, unit sectors */
+/* The following numbers are sectors */
+#define MD_AL_OFFSET 8 /* 8 Sectors after start of meta area */
+#define MD_AL_MAX_SIZE 64 /* = 32 kb LOG ~ 3776 extents ~ 14 GB Storage */
+/* Allows up to about 3.8TB */
+#define MD_BM_OFFSET (MD_AL_OFFSET + MD_AL_MAX_SIZE)
+
+/* Since the smalles IO unit is usually 512 byte */
+#define MD_SECTOR_SHIFT 9
+#define MD_SECTOR_SIZE (1<<MD_SECTOR_SHIFT)
+
+/* activity log */
+#define AL_EXTENTS_PT ((MD_SECTOR_SIZE-12)/8-1) /* 61 ; Extents per 512B sector */
+#define AL_EXTENT_SHIFT 22 /* One extent represents 4M Storage */
+#define AL_EXTENT_SIZE (1<<AL_EXTENT_SHIFT)
+
+#if BITS_PER_LONG == 32
+#define LN2_BPL 5
+#define cpu_to_lel(A) cpu_to_le32(A)
+#define lel_to_cpu(A) le32_to_cpu(A)
+#elif BITS_PER_LONG == 64
+#define LN2_BPL 6
+#define cpu_to_lel(A) cpu_to_le64(A)
+#define lel_to_cpu(A) le64_to_cpu(A)
+#else
+#error "LN2 of BITS_PER_LONG unknown!"
+#endif
+
+/* resync bitmap */
+/* 16MB sized 'bitmap extent' to track syncer usage */
+struct bm_extent {
+ int rs_left; /* number of bits set (out of sync) in this extent. */
+ int rs_failed; /* number of failed resync requests in this extent. */
+ unsigned long flags;
+ struct lc_element lce;
+};
+
+#define BME_NO_WRITES 0 /* bm_extent.flags: no more requests on this one! */
+#define BME_LOCKED 1 /* bm_extent.flags: syncer active on this one. */
+
+/* drbd_bitmap.c */
+/*
+ * We need to store one bit for a block.
+ * Example: 1GB disk @ 4096 byte blocks ==> we need 32 KB bitmap.
+ * Bit 0 ==> local node thinks this block is binary identical on both nodes
+ * Bit 1 ==> local node thinks this block needs to be synced.
+ */
+
+#define BM_BLOCK_SHIFT 12 /* 4k per bit */
+#define BM_BLOCK_SIZE (1<<BM_BLOCK_SHIFT)
+/* (9+3) : 512 bytes @ 8 bits; representing 16M storage
+ * per sector of on disk bitmap */
+#define BM_EXT_SHIFT (BM_BLOCK_SHIFT + MD_SECTOR_SHIFT + 3) /* = 24 */
+#define BM_EXT_SIZE (1<<BM_EXT_SHIFT)
+
+#if (BM_EXT_SHIFT != 24) || (BM_BLOCK_SHIFT != 12)
+#error "HAVE YOU FIXED drbdmeta AS WELL??"
+#endif
+
+/* thus many _storage_ sectors are described by one bit */
+#define BM_SECT_TO_BIT(x) ((x)>>(BM_BLOCK_SHIFT-9))
+#define BM_BIT_TO_SECT(x) ((sector_t)(x)<<(BM_BLOCK_SHIFT-9))
+#define BM_SECT_PER_BIT BM_BIT_TO_SECT(1)
+
+/* bit to represented kilo byte conversion */
+#define Bit2KB(bits) ((bits)<<(BM_BLOCK_SHIFT-10))
+
+/* in which _bitmap_ extent (resp. sector) the bit for a certain
+ * _storage_ sector is located in */
+#define BM_SECT_TO_EXT(x) ((x)>>(BM_EXT_SHIFT-9))
+
+/* how much _storage_ sectors we have per bitmap sector */
+#define BM_EXT_TO_SECT(x) ((sector_t)(x) << (BM_EXT_SHIFT-9))
+#define BM_SECT_PER_EXT BM_EXT_TO_SECT(1)
+
+/* in one sector of the bitmap, we have this many activity_log extents. */
+#define AL_EXT_PER_BM_SECT (1 << (BM_EXT_SHIFT - AL_EXTENT_SHIFT))
+#define BM_WORDS_PER_AL_EXT (1 << (AL_EXTENT_SHIFT-BM_BLOCK_SHIFT-LN2_BPL))
+
+#define BM_BLOCKS_PER_BM_EXT_B (BM_EXT_SHIFT - BM_BLOCK_SHIFT)
+#define BM_BLOCKS_PER_BM_EXT_MASK ((1<<BM_BLOCKS_PER_BM_EXT_B) - 1)
+
+/* the extent in "PER_EXTENT" below is an activity log extent
+ * we need that many (long words/bytes) to store the bitmap
+ * of one AL_EXTENT_SIZE chunk of storage.
+ * we can store the bitmap for that many AL_EXTENTS within
+ * one sector of the _on_disk_ bitmap:
+ * bit 0 bit 37 bit 38 bit (512*8)-1
+ * ...|........|........|.. // ..|........|
+ * sect. 0 `296 `304 ^(512*8*8)-1
+ *
+#define BM_WORDS_PER_EXT ( (AL_EXT_SIZE/BM_BLOCK_SIZE) / BITS_PER_LONG )
+#define BM_BYTES_PER_EXT ( (AL_EXT_SIZE/BM_BLOCK_SIZE) / 8 ) // 128
+#define BM_EXT_PER_SECT ( 512 / BM_BYTES_PER_EXTENT ) // 4
+ */
+
+#define DRBD_MAX_SECTORS_32 (0xffffffffLU)
+#define DRBD_MAX_SECTORS_BM \
+ ((MD_RESERVED_SECT - MD_BM_OFFSET) * (1LL<<(BM_EXT_SHIFT-9)))
+#if DRBD_MAX_SECTORS_BM < DRBD_MAX_SECTORS_32
+#define DRBD_MAX_SECTORS DRBD_MAX_SECTORS_BM
+#define DRBD_MAX_SECTORS_FLEX DRBD_MAX_SECTORS_BM
+#elif !defined(CONFIG_LBD) && BITS_PER_LONG == 32
+#define DRBD_MAX_SECTORS DRBD_MAX_SECTORS_32
+#define DRBD_MAX_SECTORS_FLEX DRBD_MAX_SECTORS_32
+#else
+#define DRBD_MAX_SECTORS DRBD_MAX_SECTORS_BM
+/* 16 TB in units of sectors */
+#if BITS_PER_LONG == 32
+/* adjust by one page worth of bitmap,
+ * so we won't wrap around in drbd_bm_find_next_bit.
+ * you should use 64bit OS for that much storage, anyways. */
+#define DRBD_MAX_SECTORS_FLEX BM_BIT_TO_SECT(0xffff7fff)
+#else
+#define DRBD_MAX_SECTORS_FLEX BM_BIT_TO_SECT(0x1LU << 32)
+#endif
+#endif
+
+/* Sector shift value for the "hash" functions of tl_hash and ee_hash tables.
+ * With a value of 6 all IO in one 32K block make it to the same slot of the
+ * hash table. */
+#define HT_SHIFT 6
+#define DRBD_MAX_SEGMENT_SIZE (1U<<(9+HT_SHIFT))
+
+/* Number of elements in the app_reads_hash */
+#define APP_R_HSIZE 15
+
+extern int drbd_bm_init(struct drbd_conf *mdev);
+extern int drbd_bm_resize(struct drbd_conf *mdev, sector_t sectors);
+extern void drbd_bm_cleanup(struct drbd_conf *mdev);
+extern void drbd_bm_set_all(struct drbd_conf *mdev);
+extern void drbd_bm_clear_all(struct drbd_conf *mdev);
+extern int drbd_bm_set_bits(
+ struct drbd_conf *mdev, unsigned long s, unsigned long e);
+extern int drbd_bm_clear_bits(
+ struct drbd_conf *mdev, unsigned long s, unsigned long e);
+/* bm_set_bits variant for use while holding drbd_bm_lock */
+extern void _drbd_bm_set_bits(struct drbd_conf *mdev,
+ const unsigned long s, const unsigned long e);
+extern int drbd_bm_test_bit(struct drbd_conf *mdev, unsigned long bitnr);
+extern int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr);
+extern int drbd_bm_write_sect(struct drbd_conf *mdev, unsigned long enr) __must_hold(local);
+extern int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local);
+extern int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local);
+extern unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev,
+ unsigned long al_enr);
+extern size_t drbd_bm_words(struct drbd_conf *mdev);
+extern unsigned long drbd_bm_bits(struct drbd_conf *mdev);
+extern sector_t drbd_bm_capacity(struct drbd_conf *mdev);
+extern unsigned long drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo);
+/* bm_find_next variants for use while you hold drbd_bm_lock() */
+extern unsigned long _drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo);
+extern unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo);
+extern unsigned long drbd_bm_total_weight(struct drbd_conf *mdev);
+extern int drbd_bm_rs_done(struct drbd_conf *mdev);
+/* for receive_bitmap */
+extern void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset,
+ size_t number, unsigned long *buffer);
+/* for _drbd_send_bitmap and drbd_bm_write_sect */
+extern void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset,
+ size_t number, unsigned long *buffer);
+
+extern void drbd_bm_lock(struct drbd_conf *mdev, char *why);
+extern void drbd_bm_unlock(struct drbd_conf *mdev);
+
+extern int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e);
+/* drbd_main.c */
+
+extern struct kmem_cache *drbd_request_cache;
+extern struct kmem_cache *drbd_ee_cache; /* epoch entries */
+extern struct kmem_cache *drbd_bm_ext_cache; /* bitmap extents */
+extern struct kmem_cache *drbd_al_ext_cache; /* activity log extents */
+extern mempool_t *drbd_request_mempool;
+extern mempool_t *drbd_ee_mempool;
+
+extern struct page *drbd_pp_pool; /* drbd's page pool */
+extern spinlock_t drbd_pp_lock;
+extern int drbd_pp_vacant;
+extern wait_queue_head_t drbd_pp_wait;
+
+extern rwlock_t global_state_lock;
+
+extern struct drbd_conf *drbd_new_device(unsigned int minor);
+extern void drbd_free_mdev(struct drbd_conf *mdev);
+
+extern int proc_details;
+
+/* drbd_req */
+extern int drbd_make_request_26(struct request_queue *q, struct bio *bio);
+extern int drbd_read_remote(struct drbd_conf *mdev, struct drbd_request *req);
+extern int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec);
+extern int is_valid_ar_handle(struct drbd_request *, sector_t);
+
+
+/* drbd_nl.c */
+extern void drbd_suspend_io(struct drbd_conf *mdev);
+extern void drbd_resume_io(struct drbd_conf *mdev);
+extern char *ppsize(char *buf, unsigned long long size);
+extern sector_t drbd_new_dev_size(struct drbd_conf *,
+ struct drbd_backing_dev *);
+enum determine_dev_size { dev_size_error = -1, unchanged = 0, shrunk = 1, grew = 2 };
+extern enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *) __must_hold(local);
+extern void resync_after_online_grow(struct drbd_conf *);
+extern void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int) __must_hold(local);
+extern int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role,
+ int force);
+enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev);
+extern int drbd_khelper(struct drbd_conf *mdev, char *cmd);
+
+/* drbd_worker.c */
+extern int drbd_worker(struct drbd_thread *thi);
+extern int drbd_alter_sa(struct drbd_conf *mdev, int na);
+extern void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side);
+extern void resume_next_sg(struct drbd_conf *mdev);
+extern void suspend_other_sg(struct drbd_conf *mdev);
+extern int drbd_resync_finished(struct drbd_conf *mdev);
+/* maybe rather drbd_main.c ? */
+extern int drbd_md_sync_page_io(struct drbd_conf *mdev,
+ struct drbd_backing_dev *bdev, sector_t sector, int rw);
+extern void drbd_ov_oos_found(struct drbd_conf*, sector_t, int);
+
+static inline void ov_oos_print(struct drbd_conf *mdev)
+{
+ if (mdev->ov_last_oos_size) {
+ dev_err(DEV, "Out of sync: start=%llu, size=%lu (sectors)\n",
+ (unsigned long long)mdev->ov_last_oos_start,
+ (unsigned long)mdev->ov_last_oos_size);
+ }
+ mdev->ov_last_oos_size=0;
+}
+
+
+extern void drbd_csum(struct drbd_conf *, struct crypto_hash *, struct bio *, void *);
+/* worker callbacks */
+extern int w_req_cancel_conflict(struct drbd_conf *, struct drbd_work *, int);
+extern int w_read_retry_remote(struct drbd_conf *, struct drbd_work *, int);
+extern int w_e_end_data_req(struct drbd_conf *, struct drbd_work *, int);
+extern int w_e_end_rsdata_req(struct drbd_conf *, struct drbd_work *, int);
+extern int w_e_end_csum_rs_req(struct drbd_conf *, struct drbd_work *, int);
+extern int w_e_end_ov_reply(struct drbd_conf *, struct drbd_work *, int);
+extern int w_e_end_ov_req(struct drbd_conf *, struct drbd_work *, int);
+extern int w_ov_finished(struct drbd_conf *, struct drbd_work *, int);
+extern int w_resync_inactive(struct drbd_conf *, struct drbd_work *, int);
+extern int w_resume_next_sg(struct drbd_conf *, struct drbd_work *, int);
+extern int w_io_error(struct drbd_conf *, struct drbd_work *, int);
+extern int w_send_write_hint(struct drbd_conf *, struct drbd_work *, int);
+extern int w_make_resync_request(struct drbd_conf *, struct drbd_work *, int);
+extern int w_send_dblock(struct drbd_conf *, struct drbd_work *, int);
+extern int w_send_barrier(struct drbd_conf *, struct drbd_work *, int);
+extern int w_send_read_req(struct drbd_conf *, struct drbd_work *, int);
+extern int w_prev_work_done(struct drbd_conf *, struct drbd_work *, int);
+extern int w_e_reissue(struct drbd_conf *, struct drbd_work *, int);
+
+extern void resync_timer_fn(unsigned long data);
+
+/* drbd_receiver.c */
+extern int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list);
+extern struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev,
+ u64 id,
+ sector_t sector,
+ unsigned int data_size,
+ gfp_t gfp_mask) __must_hold(local);
+extern void drbd_free_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e);
+extern void drbd_wait_ee_list_empty(struct drbd_conf *mdev,
+ struct list_head *head);
+extern void _drbd_wait_ee_list_empty(struct drbd_conf *mdev,
+ struct list_head *head);
+extern void drbd_set_recv_tcq(struct drbd_conf *mdev, int tcq_enabled);
+extern void _drbd_clear_done_ee(struct drbd_conf *mdev, struct list_head *to_be_freed);
+extern void drbd_flush_workqueue(struct drbd_conf *mdev);
+
+/* yes, there is kernel_setsockopt, but only since 2.6.18. we don't need to
+ * mess with get_fs/set_fs, we know we are KERNEL_DS always. */
+static inline int drbd_setsockopt(struct socket *sock, int level, int optname,
+ char __user *optval, int optlen)
+{
+ int err;
+ if (level == SOL_SOCKET)
+ err = sock_setsockopt(sock, level, optname, optval, optlen);
+ else
+ err = sock->ops->setsockopt(sock, level, optname, optval,
+ optlen);
+ return err;
+}
+
+static inline void drbd_tcp_cork(struct socket *sock)
+{
+ int __user val = 1;
+ (void) drbd_setsockopt(sock, SOL_TCP, TCP_CORK,
+ (char __user *)&val, sizeof(val));
+}
+
+static inline void drbd_tcp_uncork(struct socket *sock)
+{
+ int __user val = 0;
+ (void) drbd_setsockopt(sock, SOL_TCP, TCP_CORK,
+ (char __user *)&val, sizeof(val));
+}
+
+static inline void drbd_tcp_nodelay(struct socket *sock)
+{
+ int __user val = 1;
+ (void) drbd_setsockopt(sock, SOL_TCP, TCP_NODELAY,
+ (char __user *)&val, sizeof(val));
+}
+
+static inline void drbd_tcp_quickack(struct socket *sock)
+{
+ int __user val = 1;
+ (void) drbd_setsockopt(sock, SOL_TCP, TCP_QUICKACK,
+ (char __user *)&val, sizeof(val));
+}
+
+void drbd_bump_write_ordering(struct drbd_conf *mdev, enum write_ordering_e wo);
+
+/* drbd_proc.c */
+extern struct proc_dir_entry *drbd_proc;
+extern struct file_operations drbd_proc_fops;
+extern const char *drbd_conn_str(enum drbd_conns s);
+extern const char *drbd_role_str(enum drbd_role s);
+
+/* drbd_actlog.c */
+extern void drbd_al_begin_io(struct drbd_conf *mdev, sector_t sector);
+extern void drbd_al_complete_io(struct drbd_conf *mdev, sector_t sector);
+extern void drbd_rs_complete_io(struct drbd_conf *mdev, sector_t sector);
+extern int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector);
+extern int drbd_try_rs_begin_io(struct drbd_conf *mdev, sector_t sector);
+extern void drbd_rs_cancel_all(struct drbd_conf *mdev);
+extern int drbd_rs_del_all(struct drbd_conf *mdev);
+extern void drbd_rs_failed_io(struct drbd_conf *mdev,
+ sector_t sector, int size);
+extern int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *);
+extern void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector,
+ int size, const char *file, const unsigned int line);
+#define drbd_set_in_sync(mdev, sector, size) \
+ __drbd_set_in_sync(mdev, sector, size, __FILE__, __LINE__)
+extern void __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector,
+ int size, const char *file, const unsigned int line);
+#define drbd_set_out_of_sync(mdev, sector, size) \
+ __drbd_set_out_of_sync(mdev, sector, size, __FILE__, __LINE__)
+extern void drbd_al_apply_to_bm(struct drbd_conf *mdev);
+extern void drbd_al_to_on_disk_bm(struct drbd_conf *mdev);
+extern void drbd_al_shrink(struct drbd_conf *mdev);
+
+
+/* drbd_nl.c */
+
+void drbd_nl_cleanup(void);
+int __init drbd_nl_init(void);
+void drbd_bcast_state(struct drbd_conf *mdev, union drbd_state);
+void drbd_bcast_sync_progress(struct drbd_conf *mdev);
+void drbd_bcast_ee(struct drbd_conf *mdev,
+ const char *reason, const int dgs,
+ const char* seen_hash, const char* calc_hash,
+ const struct drbd_epoch_entry* e);
+
+
+/**
+ * DOC: DRBD State macros
+ *
+ * These macros are used to express state changes in easily readable form.
+ *
+ * The NS macros expand to a mask and a value, that can be bit ored onto the
+ * current state as soon as the spinlock (req_lock) was taken.
+ *
+ * The _NS macros are used for state functions that get called with the
+ * spinlock. These macros expand directly to the new state value.
+ *
+ * Besides the basic forms NS() and _NS() additional _?NS[23] are defined
+ * to express state changes that affect more than one aspect of the state.
+ *
+ * E.g. NS2(conn, C_CONNECTED, peer, R_SECONDARY)
+ * Means that the network connection was established and that the peer
+ * is in secondary role.
+ */
+#define role_MASK R_MASK
+#define peer_MASK R_MASK
+#define disk_MASK D_MASK
+#define pdsk_MASK D_MASK
+#define conn_MASK C_MASK
+#define susp_MASK 1
+#define user_isp_MASK 1
+#define aftr_isp_MASK 1
+
+#define NS(T, S) \
+ ({ union drbd_state mask; mask.i = 0; mask.T = T##_MASK; mask; }), \
+ ({ union drbd_state val; val.i = 0; val.T = (S); val; })
+#define NS2(T1, S1, T2, S2) \
+ ({ union drbd_state mask; mask.i = 0; mask.T1 = T1##_MASK; \
+ mask.T2 = T2##_MASK; mask; }), \
+ ({ union drbd_state val; val.i = 0; val.T1 = (S1); \
+ val.T2 = (S2); val; })
+#define NS3(T1, S1, T2, S2, T3, S3) \
+ ({ union drbd_state mask; mask.i = 0; mask.T1 = T1##_MASK; \
+ mask.T2 = T2##_MASK; mask.T3 = T3##_MASK; mask; }), \
+ ({ union drbd_state val; val.i = 0; val.T1 = (S1); \
+ val.T2 = (S2); val.T3 = (S3); val; })
+
+#define _NS(D, T, S) \
+ D, ({ union drbd_state __ns; __ns.i = D->state.i; __ns.T = (S); __ns; })
+#define _NS2(D, T1, S1, T2, S2) \
+ D, ({ union drbd_state __ns; __ns.i = D->state.i; __ns.T1 = (S1); \
+ __ns.T2 = (S2); __ns; })
+#define _NS3(D, T1, S1, T2, S2, T3, S3) \
+ D, ({ union drbd_state __ns; __ns.i = D->state.i; __ns.T1 = (S1); \
+ __ns.T2 = (S2); __ns.T3 = (S3); __ns; })
+
+/*
+ * inline helper functions
+ *************************/
+
+static inline void drbd_state_lock(struct drbd_conf *mdev)
+{
+ wait_event(mdev->misc_wait,
+ !test_and_set_bit(CLUSTER_ST_CHANGE, &mdev->flags));
+}
+
+static inline void drbd_state_unlock(struct drbd_conf *mdev)
+{
+ clear_bit(CLUSTER_ST_CHANGE, &mdev->flags);
+ wake_up(&mdev->misc_wait);
+}
+
+static inline int _drbd_set_state(struct drbd_conf *mdev,
+ union drbd_state ns, enum chg_state_flags flags,
+ struct completion *done)
+{
+ int rv;
+
+ read_lock(&global_state_lock);
+ rv = __drbd_set_state(mdev, ns, flags, done);
+ read_unlock(&global_state_lock);
+
+ return rv;
+}
+
+/**
+ * drbd_request_state() - Reqest a state change
+ * @mdev: DRBD device.
+ * @mask: mask of state bits to change.
+ * @val: value of new state bits.
+ *
+ * This is the most graceful way of requesting a state change. It is verbose
+ * quite verbose in case the state change is not possible, and all those
+ * state changes are globally serialized.
+ */
+static inline int drbd_request_state(struct drbd_conf *mdev,
+ union drbd_state mask,
+ union drbd_state val)
+{
+ return _drbd_request_state(mdev, mask, val, CS_VERBOSE + CS_ORDERED);
+}
+
+#define __drbd_chk_io_error(m,f) __drbd_chk_io_error_(m,f, __func__)
+static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach, const char *where)
+{
+ switch (mdev->ldev->dc.on_io_error) {
+ case EP_PASS_ON:
+ if (!forcedetach) {
+ if (printk_ratelimit())
+ dev_err(DEV, "Local IO failed in %s."
+ "Passing error on...\n", where);
+ break;
+ }
+ /* NOTE fall through to detach case if forcedetach set */
+ case EP_DETACH:
+ case EP_CALL_HELPER:
+ if (mdev->state.disk > D_FAILED) {
+ _drbd_set_state(_NS(mdev, disk, D_FAILED), CS_HARD, NULL);
+ dev_err(DEV, "Local IO failed in %s."
+ "Detaching...\n", where);
+ }
+ break;
+ }
+}
+
+/**
+ * drbd_chk_io_error: Handle the on_io_error setting, should be called from all io completion handlers
+ * @mdev: DRBD device.
+ * @error: Error code passed to the IO completion callback
+ * @forcedetach: Force detach. I.e. the error happened while accessing the meta data
+ *
+ * See also drbd_main.c:after_state_ch() if (os.disk > D_FAILED && ns.disk == D_FAILED)
+ */
+#define drbd_chk_io_error(m,e,f) drbd_chk_io_error_(m,e,f, __func__)
+static inline void drbd_chk_io_error_(struct drbd_conf *mdev,
+ int error, int forcedetach, const char *where)
+{
+ if (error) {
+ unsigned long flags;
+ spin_lock_irqsave(&mdev->req_lock, flags);
+ __drbd_chk_io_error_(mdev, forcedetach, where);
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+ }
+}
+
+
+/**
+ * drbd_md_first_sector() - Returns the first sector number of the meta data area
+ * @bdev: Meta data block device.
+ *
+ * BTW, for internal meta data, this happens to be the maximum capacity
+ * we could agree upon with our peer node.
+ */
+static inline sector_t drbd_md_first_sector(struct drbd_backing_dev *bdev)
+{
+ switch (bdev->dc.meta_dev_idx) {
+ case DRBD_MD_INDEX_INTERNAL:
+ case DRBD_MD_INDEX_FLEX_INT:
+ return bdev->md.md_offset + bdev->md.bm_offset;
+ case DRBD_MD_INDEX_FLEX_EXT:
+ default:
+ return bdev->md.md_offset;
+ }
+}
+
+/**
+ * drbd_md_last_sector() - Return the last sector number of the meta data area
+ * @bdev: Meta data block device.
+ */
+static inline sector_t drbd_md_last_sector(struct drbd_backing_dev *bdev)
+{
+ switch (bdev->dc.meta_dev_idx) {
+ case DRBD_MD_INDEX_INTERNAL:
+ case DRBD_MD_INDEX_FLEX_INT:
+ return bdev->md.md_offset + MD_AL_OFFSET - 1;
+ case DRBD_MD_INDEX_FLEX_EXT:
+ default:
+ return bdev->md.md_offset + bdev->md.md_size_sect;
+ }
+}
+
+/* Returns the number of 512 byte sectors of the device */
+static inline sector_t drbd_get_capacity(struct block_device *bdev)
+{
+ /* return bdev ? get_capacity(bdev->bd_disk) : 0; */
+ return bdev ? bdev->bd_inode->i_size >> 9 : 0;
+}
+
+/**
+ * drbd_get_max_capacity() - Returns the capacity we announce to out peer
+ * @bdev: Meta data block device.
+ *
+ * returns the capacity we announce to out peer. we clip ourselves at the
+ * various MAX_SECTORS, because if we don't, current implementation will
+ * oops sooner or later
+ */
+static inline sector_t drbd_get_max_capacity(struct drbd_backing_dev *bdev)
+{
+ sector_t s;
+ switch (bdev->dc.meta_dev_idx) {
+ case DRBD_MD_INDEX_INTERNAL:
+ case DRBD_MD_INDEX_FLEX_INT:
+ s = drbd_get_capacity(bdev->backing_bdev)
+ ? min_t(sector_t, DRBD_MAX_SECTORS_FLEX,
+ drbd_md_first_sector(bdev))
+ : 0;
+ break;
+ case DRBD_MD_INDEX_FLEX_EXT:
+ s = min_t(sector_t, DRBD_MAX_SECTORS_FLEX,
+ drbd_get_capacity(bdev->backing_bdev));
+ /* clip at maximum size the meta device can support */
+ s = min_t(sector_t, s,
+ BM_EXT_TO_SECT(bdev->md.md_size_sect
+ - bdev->md.bm_offset));
+ break;
+ default:
+ s = min_t(sector_t, DRBD_MAX_SECTORS,
+ drbd_get_capacity(bdev->backing_bdev));
+ }
+ return s;
+}
+
+/**
+ * drbd_md_ss__() - Return the sector number of our meta data super block
+ * @mdev: DRBD device.
+ * @bdev: Meta data block device.
+ */
+static inline sector_t drbd_md_ss__(struct drbd_conf *mdev,
+ struct drbd_backing_dev *bdev)
+{
+ switch (bdev->dc.meta_dev_idx) {
+ default: /* external, some index */
+ return MD_RESERVED_SECT * bdev->dc.meta_dev_idx;
+ case DRBD_MD_INDEX_INTERNAL:
+ /* with drbd08, internal meta data is always "flexible" */
+ case DRBD_MD_INDEX_FLEX_INT:
+ /* sizeof(struct md_on_disk_07) == 4k
+ * position: last 4k aligned block of 4k size */
+ if (!bdev->backing_bdev) {
+ if (__ratelimit(&drbd_ratelimit_state)) {
+ dev_err(DEV, "bdev->backing_bdev==NULL\n");
+ dump_stack();
+ }
+ return 0;
+ }
+ return (drbd_get_capacity(bdev->backing_bdev) & ~7ULL)
+ - MD_AL_OFFSET;
+ case DRBD_MD_INDEX_FLEX_EXT:
+ return 0;
+ }
+}
+
+static inline void
+_drbd_queue_work(struct drbd_work_queue *q, struct drbd_work *w)
+{
+ list_add_tail(&w->list, &q->q);
+ up(&q->s);
+}
+
+static inline void
+drbd_queue_work_front(struct drbd_work_queue *q, struct drbd_work *w)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&q->q_lock, flags);
+ list_add(&w->list, &q->q);
+ up(&q->s); /* within the spinlock,
+ see comment near end of drbd_worker() */
+ spin_unlock_irqrestore(&q->q_lock, flags);
+}
+
+static inline void
+drbd_queue_work(struct drbd_work_queue *q, struct drbd_work *w)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&q->q_lock, flags);
+ list_add_tail(&w->list, &q->q);
+ up(&q->s); /* within the spinlock,
+ see comment near end of drbd_worker() */
+ spin_unlock_irqrestore(&q->q_lock, flags);
+}
+
+static inline void wake_asender(struct drbd_conf *mdev)
+{
+ if (test_bit(SIGNAL_ASENDER, &mdev->flags))
+ force_sig(DRBD_SIG, mdev->asender.task);
+}
+
+static inline void request_ping(struct drbd_conf *mdev)
+{
+ set_bit(SEND_PING, &mdev->flags);
+ wake_asender(mdev);
+}
+
+static inline int drbd_send_short_cmd(struct drbd_conf *mdev,
+ enum drbd_packets cmd)
+{
+ struct p_header h;
+ return drbd_send_cmd(mdev, USE_DATA_SOCKET, cmd, &h, sizeof(h));
+}
+
+static inline int drbd_send_ping(struct drbd_conf *mdev)
+{
+ struct p_header h;
+ return drbd_send_cmd(mdev, USE_META_SOCKET, P_PING, &h, sizeof(h));
+}
+
+static inline int drbd_send_ping_ack(struct drbd_conf *mdev)
+{
+ struct p_header h;
+ return drbd_send_cmd(mdev, USE_META_SOCKET, P_PING_ACK, &h, sizeof(h));
+}
+
+static inline void drbd_thread_stop(struct drbd_thread *thi)
+{
+ _drbd_thread_stop(thi, FALSE, TRUE);
+}
+
+static inline void drbd_thread_stop_nowait(struct drbd_thread *thi)
+{
+ _drbd_thread_stop(thi, FALSE, FALSE);
+}
+
+static inline void drbd_thread_restart_nowait(struct drbd_thread *thi)
+{
+ _drbd_thread_stop(thi, TRUE, FALSE);
+}
+
+/* counts how many answer packets packets we expect from our peer,
+ * for either explicit application requests,
+ * or implicit barrier packets as necessary.
+ * increased:
+ * w_send_barrier
+ * _req_mod(req, queue_for_net_write or queue_for_net_read);
+ * it is much easier and equally valid to count what we queue for the
+ * worker, even before it actually was queued or send.
+ * (drbd_make_request_common; recovery path on read io-error)
+ * decreased:
+ * got_BarrierAck (respective tl_clear, tl_clear_barrier)
+ * _req_mod(req, data_received)
+ * [from receive_DataReply]
+ * _req_mod(req, write_acked_by_peer or recv_acked_by_peer or neg_acked)
+ * [from got_BlockAck (P_WRITE_ACK, P_RECV_ACK)]
+ * for some reason it is NOT decreased in got_NegAck,
+ * but in the resulting cleanup code from report_params.
+ * we should try to remember the reason for that...
+ * _req_mod(req, send_failed or send_canceled)
+ * _req_mod(req, connection_lost_while_pending)
+ * [from tl_clear_barrier]
+ */
+static inline void inc_ap_pending(struct drbd_conf *mdev)
+{
+ atomic_inc(&mdev->ap_pending_cnt);
+}
+
+#define ERR_IF_CNT_IS_NEGATIVE(which) \
+ if (atomic_read(&mdev->which) < 0) \
+ dev_err(DEV, "in %s:%d: " #which " = %d < 0 !\n", \
+ __func__ , __LINE__ , \
+ atomic_read(&mdev->which))
+
+#define dec_ap_pending(mdev) do { \
+ typecheck(struct drbd_conf *, mdev); \
+ if (atomic_dec_and_test(&mdev->ap_pending_cnt)) \
+ wake_up(&mdev->misc_wait); \
+ ERR_IF_CNT_IS_NEGATIVE(ap_pending_cnt); } while (0)
+
+/* counts how many resync-related answers we still expect from the peer
+ * increase decrease
+ * C_SYNC_TARGET sends P_RS_DATA_REQUEST (and expects P_RS_DATA_REPLY)
+ * C_SYNC_SOURCE sends P_RS_DATA_REPLY (and expects P_WRITE_ACK whith ID_SYNCER)
+ * (or P_NEG_ACK with ID_SYNCER)
+ */
+static inline void inc_rs_pending(struct drbd_conf *mdev)
+{
+ atomic_inc(&mdev->rs_pending_cnt);
+}
+
+#define dec_rs_pending(mdev) do { \
+ typecheck(struct drbd_conf *, mdev); \
+ atomic_dec(&mdev->rs_pending_cnt); \
+ ERR_IF_CNT_IS_NEGATIVE(rs_pending_cnt); } while (0)
+
+/* counts how many answers we still need to send to the peer.
+ * increased on
+ * receive_Data unless protocol A;
+ * we need to send a P_RECV_ACK (proto B)
+ * or P_WRITE_ACK (proto C)
+ * receive_RSDataReply (recv_resync_read) we need to send a P_WRITE_ACK
+ * receive_DataRequest (receive_RSDataRequest) we need to send back P_DATA
+ * receive_Barrier_* we need to send a P_BARRIER_ACK
+ */
+static inline void inc_unacked(struct drbd_conf *mdev)
+{
+ atomic_inc(&mdev->unacked_cnt);
+}
+
+#define dec_unacked(mdev) do { \
+ typecheck(struct drbd_conf *, mdev); \
+ atomic_dec(&mdev->unacked_cnt); \
+ ERR_IF_CNT_IS_NEGATIVE(unacked_cnt); } while (0)
+
+#define sub_unacked(mdev, n) do { \
+ typecheck(struct drbd_conf *, mdev); \
+ atomic_sub(n, &mdev->unacked_cnt); \
+ ERR_IF_CNT_IS_NEGATIVE(unacked_cnt); } while (0)
+
+
+static inline void put_net_conf(struct drbd_conf *mdev)
+{
+ if (atomic_dec_and_test(&mdev->net_cnt))
+ wake_up(&mdev->misc_wait);
+}
+
+/**
+ * get_net_conf() - Increase ref count on mdev->net_conf; Returns 0 if nothing there
+ * @mdev: DRBD device.
+ *
+ * You have to call put_net_conf() when finished working with mdev->net_conf.
+ */
+static inline int get_net_conf(struct drbd_conf *mdev)
+{
+ int have_net_conf;
+
+ atomic_inc(&mdev->net_cnt);
+ have_net_conf = mdev->state.conn >= C_UNCONNECTED;
+ if (!have_net_conf)
+ put_net_conf(mdev);
+ return have_net_conf;
+}
+
+/**
+ * get_ldev() - Increase the ref count on mdev->ldev. Returns 0 if there is no ldev
+ * @M: DRBD device.
+ *
+ * You have to call put_ldev() when finished working with mdev->ldev.
+ */
+#define get_ldev(M) __cond_lock(local, _get_ldev_if_state(M,D_INCONSISTENT))
+#define get_ldev_if_state(M,MINS) __cond_lock(local, _get_ldev_if_state(M,MINS))
+
+static inline void put_ldev(struct drbd_conf *mdev)
+{
+ __release(local);
+ if (atomic_dec_and_test(&mdev->local_cnt))
+ wake_up(&mdev->misc_wait);
+ D_ASSERT(atomic_read(&mdev->local_cnt) >= 0);
+}
+
+#ifndef __CHECKER__
+static inline int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins)
+{
+ int io_allowed;
+
+ atomic_inc(&mdev->local_cnt);
+ io_allowed = (mdev->state.disk >= mins);
+ if (!io_allowed)
+ put_ldev(mdev);
+ return io_allowed;
+}
+#else
+extern int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins);
+#endif
+
+/* you must have an "get_ldev" reference */
+static inline void drbd_get_syncer_progress(struct drbd_conf *mdev,
+ unsigned long *bits_left, unsigned int *per_mil_done)
+{
+ /*
+ * this is to break it at compile time when we change that
+ * (we may feel 4TB maximum storage per drbd is not enough)
+ */
+ typecheck(unsigned long, mdev->rs_total);
+
+ /* note: both rs_total and rs_left are in bits, i.e. in
+ * units of BM_BLOCK_SIZE.
+ * for the percentage, we don't care. */
+
+ *bits_left = drbd_bm_total_weight(mdev) - mdev->rs_failed;
+ /* >> 10 to prevent overflow,
+ * +1 to prevent division by zero */
+ if (*bits_left > mdev->rs_total) {
+ /* doh. maybe a logic bug somewhere.
+ * may also be just a race condition
+ * between this and a disconnect during sync.
+ * for now, just prevent in-kernel buffer overflow.
+ */
+ smp_rmb();
+ dev_warn(DEV, "cs:%s rs_left=%lu > rs_total=%lu (rs_failed %lu)\n",
+ drbd_conn_str(mdev->state.conn),
+ *bits_left, mdev->rs_total, mdev->rs_failed);
+ *per_mil_done = 0;
+ } else {
+ /* make sure the calculation happens in long context */
+ unsigned long tmp = 1000UL -
+ (*bits_left >> 10)*1000UL
+ / ((mdev->rs_total >> 10) + 1UL);
+ *per_mil_done = tmp;
+ }
+}
+
+
+/* this throttles on-the-fly application requests
+ * according to max_buffers settings;
+ * maybe re-implement using semaphores? */
+static inline int drbd_get_max_buffers(struct drbd_conf *mdev)
+{
+ int mxb = 1000000; /* arbitrary limit on open requests */
+ if (get_net_conf(mdev)) {
+ mxb = mdev->net_conf->max_buffers;
+ put_net_conf(mdev);
+ }
+ return mxb;
+}
+
+static inline int drbd_state_is_stable(union drbd_state s)
+{
+
+ /* DO NOT add a default clause, we want the compiler to warn us
+ * for any newly introduced state we may have forgotten to add here */
+
+ switch ((enum drbd_conns)s.conn) {
+ /* new io only accepted when there is no connection, ... */
+ case C_STANDALONE:
+ case C_WF_CONNECTION:
+ /* ... or there is a well established connection. */
+ case C_CONNECTED:
+ case C_SYNC_SOURCE:
+ case C_SYNC_TARGET:
+ case C_VERIFY_S:
+ case C_VERIFY_T:
+ case C_PAUSED_SYNC_S:
+ case C_PAUSED_SYNC_T:
+ /* maybe stable, look at the disk state */
+ break;
+
+ /* no new io accepted during tansitional states
+ * like handshake or teardown */
+ case C_DISCONNECTING:
+ case C_UNCONNECTED:
+ case C_TIMEOUT:
+ case C_BROKEN_PIPE:
+ case C_NETWORK_FAILURE:
+ case C_PROTOCOL_ERROR:
+ case C_TEAR_DOWN:
+ case C_WF_REPORT_PARAMS:
+ case C_STARTING_SYNC_S:
+ case C_STARTING_SYNC_T:
+ case C_WF_BITMAP_S:
+ case C_WF_BITMAP_T:
+ case C_WF_SYNC_UUID:
+ case C_MASK:
+ /* not "stable" */
+ return 0;
+ }
+
+ switch ((enum drbd_disk_state)s.disk) {
+ case D_DISKLESS:
+ case D_INCONSISTENT:
+ case D_OUTDATED:
+ case D_CONSISTENT:
+ case D_UP_TO_DATE:
+ /* disk state is stable as well. */
+ break;
+
+ /* no new io accepted during tansitional states */
+ case D_ATTACHING:
+ case D_FAILED:
+ case D_NEGOTIATING:
+ case D_UNKNOWN:
+ case D_MASK:
+ /* not "stable" */
+ return 0;
+ }
+
+ return 1;
+}
+
+static inline int __inc_ap_bio_cond(struct drbd_conf *mdev)
+{
+ int mxb = drbd_get_max_buffers(mdev);
+
+ if (mdev->state.susp)
+ return 0;
+ if (test_bit(SUSPEND_IO, &mdev->flags))
+ return 0;
+
+ /* to avoid potential deadlock or bitmap corruption,
+ * in various places, we only allow new application io
+ * to start during "stable" states. */
+
+ /* no new io accepted when attaching or detaching the disk */
+ if (!drbd_state_is_stable(mdev->state))
+ return 0;
+
+ /* since some older kernels don't have atomic_add_unless,
+ * and we are within the spinlock anyways, we have this workaround. */
+ if (atomic_read(&mdev->ap_bio_cnt) > mxb)
+ return 0;
+ if (test_bit(BITMAP_IO, &mdev->flags))
+ return 0;
+ return 1;
+}
+
+/* I'd like to use wait_event_lock_irq,
+ * but I'm not sure when it got introduced,
+ * and not sure when it has 3 or 4 arguments */
+static inline void inc_ap_bio(struct drbd_conf *mdev, int one_or_two)
+{
+ /* compare with after_state_ch,
+ * os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S */
+ DEFINE_WAIT(wait);
+
+ /* we wait here
+ * as long as the device is suspended
+ * until the bitmap is no longer on the fly during connection
+ * handshake as long as we would exeed the max_buffer limit.
+ *
+ * to avoid races with the reconnect code,
+ * we need to atomic_inc within the spinlock. */
+
+ spin_lock_irq(&mdev->req_lock);
+ while (!__inc_ap_bio_cond(mdev)) {
+ prepare_to_wait(&mdev->misc_wait, &wait, TASK_UNINTERRUPTIBLE);
+ spin_unlock_irq(&mdev->req_lock);
+ schedule();
+ finish_wait(&mdev->misc_wait, &wait);
+ spin_lock_irq(&mdev->req_lock);
+ }
+ atomic_add(one_or_two, &mdev->ap_bio_cnt);
+ spin_unlock_irq(&mdev->req_lock);
+}
+
+static inline void dec_ap_bio(struct drbd_conf *mdev)
+{
+ int mxb = drbd_get_max_buffers(mdev);
+ int ap_bio = atomic_dec_return(&mdev->ap_bio_cnt);
+
+ D_ASSERT(ap_bio >= 0);
+ /* this currently does wake_up for every dec_ap_bio!
+ * maybe rather introduce some type of hysteresis?
+ * e.g. (ap_bio == mxb/2 || ap_bio == 0) ? */
+ if (ap_bio < mxb)
+ wake_up(&mdev->misc_wait);
+ if (ap_bio == 0 && test_bit(BITMAP_IO, &mdev->flags)) {
+ if (!test_and_set_bit(BITMAP_IO_QUEUED, &mdev->flags))
+ drbd_queue_work(&mdev->data.work, &mdev->bm_io_work.w);
+ }
+}
+
+static inline void drbd_set_ed_uuid(struct drbd_conf *mdev, u64 val)
+{
+ mdev->ed_uuid = val;
+}
+
+static inline int seq_cmp(u32 a, u32 b)
+{
+ /* we assume wrap around at 32bit.
+ * for wrap around at 24bit (old atomic_t),
+ * we'd have to
+ * a <<= 8; b <<= 8;
+ */
+ return (s32)(a) - (s32)(b);
+}
+#define seq_lt(a, b) (seq_cmp((a), (b)) < 0)
+#define seq_gt(a, b) (seq_cmp((a), (b)) > 0)
+#define seq_ge(a, b) (seq_cmp((a), (b)) >= 0)
+#define seq_le(a, b) (seq_cmp((a), (b)) <= 0)
+/* CAUTION: please no side effects in arguments! */
+#define seq_max(a, b) ((u32)(seq_gt((a), (b)) ? (a) : (b)))
+
+static inline void update_peer_seq(struct drbd_conf *mdev, unsigned int new_seq)
+{
+ unsigned int m;
+ spin_lock(&mdev->peer_seq_lock);
+ m = seq_max(mdev->peer_seq, new_seq);
+ mdev->peer_seq = m;
+ spin_unlock(&mdev->peer_seq_lock);
+ if (m == new_seq)
+ wake_up(&mdev->seq_wait);
+}
+
+static inline void drbd_update_congested(struct drbd_conf *mdev)
+{
+ struct sock *sk = mdev->data.socket->sk;
+ if (sk->sk_wmem_queued > sk->sk_sndbuf * 4 / 5)
+ set_bit(NET_CONGESTED, &mdev->flags);
+}
+
+static inline int drbd_queue_order_type(struct drbd_conf *mdev)
+{
+ /* sorry, we currently have no working implementation
+ * of distributed TCQ stuff */
+#ifndef QUEUE_ORDERED_NONE
+#define QUEUE_ORDERED_NONE 0
+#endif
+ return QUEUE_ORDERED_NONE;
+}
+
+static inline void drbd_blk_run_queue(struct request_queue *q)
+{
+ if (q && q->unplug_fn)
+ q->unplug_fn(q);
+}
+
+static inline void drbd_kick_lo(struct drbd_conf *mdev)
+{
+ if (get_ldev(mdev)) {
+ drbd_blk_run_queue(bdev_get_queue(mdev->ldev->backing_bdev));
+ put_ldev(mdev);
+ }
+}
+
+static inline void drbd_md_flush(struct drbd_conf *mdev)
+{
+ int r;
+
+ if (test_bit(MD_NO_BARRIER, &mdev->flags))
+ return;
+
+ r = blkdev_issue_flush(mdev->ldev->md_bdev, NULL);
+ if (r) {
+ set_bit(MD_NO_BARRIER, &mdev->flags);
+ dev_err(DEV, "meta data flush failed with status %d, disabling md-flushes\n", r);
+ }
+}
+
+#endif
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
new file mode 100644
index 000000000000..11d8ff6016ac
--- /dev/null
+++ b/drivers/block/drbd/drbd_main.c
@@ -0,0 +1,3700 @@
+/*
+ drbd.c
+
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+ Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+ Thanks to Carter Burden, Bart Grantham and Gennadiy Nerubayev
+ from Logicworks, Inc. for making SDP replication support possible.
+
+ drbd 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.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT 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 drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/drbd.h>
+#include <asm/uaccess.h>
+#include <asm/types.h>
+#include <net/sock.h>
+#include <linux/ctype.h>
+#include <linux/smp_lock.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/memcontrol.h>
+#include <linux/mm_inline.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/reboot.h>
+#include <linux/notifier.h>
+#include <linux/kthread.h>
+
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+#include <linux/vmalloc.h>
+
+#include <linux/drbd_limits.h>
+#include "drbd_int.h"
+#include "drbd_req.h" /* only for _req_mod in tl_release and tl_clear */
+
+#include "drbd_vli.h"
+
+struct after_state_chg_work {
+ struct drbd_work w;
+ union drbd_state os;
+ union drbd_state ns;
+ enum chg_state_flags flags;
+ struct completion *done;
+};
+
+int drbdd_init(struct drbd_thread *);
+int drbd_worker(struct drbd_thread *);
+int drbd_asender(struct drbd_thread *);
+
+int drbd_init(void);
+static int drbd_open(struct block_device *bdev, fmode_t mode);
+static int drbd_release(struct gendisk *gd, fmode_t mode);
+static int w_after_state_ch(struct drbd_conf *mdev, struct drbd_work *w, int unused);
+static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
+ union drbd_state ns, enum chg_state_flags flags);
+static int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused);
+static void md_sync_timer_fn(unsigned long data);
+static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused);
+
+MODULE_AUTHOR("Philipp Reisner <phil@linbit.com>, "
+ "Lars Ellenberg <lars@linbit.com>");
+MODULE_DESCRIPTION("drbd - Distributed Replicated Block Device v" REL_VERSION);
+MODULE_VERSION(REL_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_PARM_DESC(minor_count, "Maximum number of drbd devices (1-255)");
+MODULE_ALIAS_BLOCKDEV_MAJOR(DRBD_MAJOR);
+
+#include <linux/moduleparam.h>
+/* allow_open_on_secondary */
+MODULE_PARM_DESC(allow_oos, "DONT USE!");
+/* thanks to these macros, if compiled into the kernel (not-module),
+ * this becomes the boot parameter drbd.minor_count */
+module_param(minor_count, uint, 0444);
+module_param(disable_sendpage, bool, 0644);
+module_param(allow_oos, bool, 0);
+module_param(cn_idx, uint, 0444);
+module_param(proc_details, int, 0644);
+
+#ifdef CONFIG_DRBD_FAULT_INJECTION
+int enable_faults;
+int fault_rate;
+static int fault_count;
+int fault_devs;
+/* bitmap of enabled faults */
+module_param(enable_faults, int, 0664);
+/* fault rate % value - applies to all enabled faults */
+module_param(fault_rate, int, 0664);
+/* count of faults inserted */
+module_param(fault_count, int, 0664);
+/* bitmap of devices to insert faults on */
+module_param(fault_devs, int, 0644);
+#endif
+
+/* module parameter, defined */
+unsigned int minor_count = 32;
+int disable_sendpage;
+int allow_oos;
+unsigned int cn_idx = CN_IDX_DRBD;
+int proc_details; /* Detail level in proc drbd*/
+
+/* Module parameter for setting the user mode helper program
+ * to run. Default is /sbin/drbdadm */
+char usermode_helper[80] = "/sbin/drbdadm";
+
+module_param_string(usermode_helper, usermode_helper, sizeof(usermode_helper), 0644);
+
+/* in 2.6.x, our device mapping and config info contains our virtual gendisks
+ * as member "struct gendisk *vdisk;"
+ */
+struct drbd_conf **minor_table;
+
+struct kmem_cache *drbd_request_cache;
+struct kmem_cache *drbd_ee_cache; /* epoch entries */
+struct kmem_cache *drbd_bm_ext_cache; /* bitmap extents */
+struct kmem_cache *drbd_al_ext_cache; /* activity log extents */
+mempool_t *drbd_request_mempool;
+mempool_t *drbd_ee_mempool;
+
+/* I do not use a standard mempool, because:
+ 1) I want to hand out the pre-allocated objects first.
+ 2) I want to be able to interrupt sleeping allocation with a signal.
+ Note: This is a single linked list, the next pointer is the private
+ member of struct page.
+ */
+struct page *drbd_pp_pool;
+spinlock_t drbd_pp_lock;
+int drbd_pp_vacant;
+wait_queue_head_t drbd_pp_wait;
+
+DEFINE_RATELIMIT_STATE(drbd_ratelimit_state, 5 * HZ, 5);
+
+static struct block_device_operations drbd_ops = {
+ .owner = THIS_MODULE,
+ .open = drbd_open,
+ .release = drbd_release,
+};
+
+#define ARRY_SIZE(A) (sizeof(A)/sizeof(A[0]))
+
+#ifdef __CHECKER__
+/* When checking with sparse, and this is an inline function, sparse will
+ give tons of false positives. When this is a real functions sparse works.
+ */
+int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins)
+{
+ int io_allowed;
+
+ atomic_inc(&mdev->local_cnt);
+ io_allowed = (mdev->state.disk >= mins);
+ if (!io_allowed) {
+ if (atomic_dec_and_test(&mdev->local_cnt))
+ wake_up(&mdev->misc_wait);
+ }
+ return io_allowed;
+}
+
+#endif
+
+/**
+ * DOC: The transfer log
+ *
+ * The transfer log is a single linked list of &struct drbd_tl_epoch objects.
+ * mdev->newest_tle points to the head, mdev->oldest_tle points to the tail
+ * of the list. There is always at least one &struct drbd_tl_epoch object.
+ *
+ * Each &struct drbd_tl_epoch has a circular double linked list of requests
+ * attached.
+ */
+static int tl_init(struct drbd_conf *mdev)
+{
+ struct drbd_tl_epoch *b;
+
+ /* during device minor initialization, we may well use GFP_KERNEL */
+ b = kmalloc(sizeof(struct drbd_tl_epoch), GFP_KERNEL);
+ if (!b)
+ return 0;
+ INIT_LIST_HEAD(&b->requests);
+ INIT_LIST_HEAD(&b->w.list);
+ b->next = NULL;
+ b->br_number = 4711;
+ b->n_req = 0;
+ b->w.cb = NULL; /* if this is != NULL, we need to dec_ap_pending in tl_clear */
+
+ mdev->oldest_tle = b;
+ mdev->newest_tle = b;
+ INIT_LIST_HEAD(&mdev->out_of_sequence_requests);
+
+ mdev->tl_hash = NULL;
+ mdev->tl_hash_s = 0;
+
+ return 1;
+}
+
+static void tl_cleanup(struct drbd_conf *mdev)
+{
+ D_ASSERT(mdev->oldest_tle == mdev->newest_tle);
+ D_ASSERT(list_empty(&mdev->out_of_sequence_requests));
+ kfree(mdev->oldest_tle);
+ mdev->oldest_tle = NULL;
+ kfree(mdev->unused_spare_tle);
+ mdev->unused_spare_tle = NULL;
+ kfree(mdev->tl_hash);
+ mdev->tl_hash = NULL;
+ mdev->tl_hash_s = 0;
+}
+
+/**
+ * _tl_add_barrier() - Adds a barrier to the transfer log
+ * @mdev: DRBD device.
+ * @new: Barrier to be added before the current head of the TL.
+ *
+ * The caller must hold the req_lock.
+ */
+void _tl_add_barrier(struct drbd_conf *mdev, struct drbd_tl_epoch *new)
+{
+ struct drbd_tl_epoch *newest_before;
+
+ INIT_LIST_HEAD(&new->requests);
+ INIT_LIST_HEAD(&new->w.list);
+ new->w.cb = NULL; /* if this is != NULL, we need to dec_ap_pending in tl_clear */
+ new->next = NULL;
+ new->n_req = 0;
+
+ newest_before = mdev->newest_tle;
+ /* never send a barrier number == 0, because that is special-cased
+ * when using TCQ for our write ordering code */
+ new->br_number = (newest_before->br_number+1) ?: 1;
+ if (mdev->newest_tle != new) {
+ mdev->newest_tle->next = new;
+ mdev->newest_tle = new;
+ }
+}
+
+/**
+ * tl_release() - Free or recycle the oldest &struct drbd_tl_epoch object of the TL
+ * @mdev: DRBD device.
+ * @barrier_nr: Expected identifier of the DRBD write barrier packet.
+ * @set_size: Expected number of requests before that barrier.
+ *
+ * In case the passed barrier_nr or set_size does not match the oldest
+ * &struct drbd_tl_epoch objects this function will cause a termination
+ * of the connection.
+ */
+void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr,
+ unsigned int set_size)
+{
+ struct drbd_tl_epoch *b, *nob; /* next old barrier */
+ struct list_head *le, *tle;
+ struct drbd_request *r;
+
+ spin_lock_irq(&mdev->req_lock);
+
+ b = mdev->oldest_tle;
+
+ /* first some paranoia code */
+ if (b == NULL) {
+ dev_err(DEV, "BAD! BarrierAck #%u received, but no epoch in tl!?\n",
+ barrier_nr);
+ goto bail;
+ }
+ if (b->br_number != barrier_nr) {
+ dev_err(DEV, "BAD! BarrierAck #%u received, expected #%u!\n",
+ barrier_nr, b->br_number);
+ goto bail;
+ }
+ if (b->n_req != set_size) {
+ dev_err(DEV, "BAD! BarrierAck #%u received with n_req=%u, expected n_req=%u!\n",
+ barrier_nr, set_size, b->n_req);
+ goto bail;
+ }
+
+ /* Clean up list of requests processed during current epoch */
+ list_for_each_safe(le, tle, &b->requests) {
+ r = list_entry(le, struct drbd_request, tl_requests);
+ _req_mod(r, barrier_acked);
+ }
+ /* There could be requests on the list waiting for completion
+ of the write to the local disk. To avoid corruptions of
+ slab's data structures we have to remove the lists head.
+
+ Also there could have been a barrier ack out of sequence, overtaking
+ the write acks - which would be a bug and violating write ordering.
+ To not deadlock in case we lose connection while such requests are
+ still pending, we need some way to find them for the
+ _req_mode(connection_lost_while_pending).
+
+ These have been list_move'd to the out_of_sequence_requests list in
+ _req_mod(, barrier_acked) above.
+ */
+ list_del_init(&b->requests);
+
+ nob = b->next;
+ if (test_and_clear_bit(CREATE_BARRIER, &mdev->flags)) {
+ _tl_add_barrier(mdev, b);
+ if (nob)
+ mdev->oldest_tle = nob;
+ /* if nob == NULL b was the only barrier, and becomes the new
+ barrier. Therefore mdev->oldest_tle points already to b */
+ } else {
+ D_ASSERT(nob != NULL);
+ mdev->oldest_tle = nob;
+ kfree(b);
+ }
+
+ spin_unlock_irq(&mdev->req_lock);
+ dec_ap_pending(mdev);
+
+ return;
+
+bail:
+ spin_unlock_irq(&mdev->req_lock);
+ drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR));
+}
+
+
+/**
+ * tl_clear() - Clears all requests and &struct drbd_tl_epoch objects out of the TL
+ * @mdev: DRBD device.
+ *
+ * This is called after the connection to the peer was lost. The storage covered
+ * by the requests on the transfer gets marked as our of sync. Called from the
+ * receiver thread and the worker thread.
+ */
+void tl_clear(struct drbd_conf *mdev)
+{
+ struct drbd_tl_epoch *b, *tmp;
+ struct list_head *le, *tle;
+ struct drbd_request *r;
+ int new_initial_bnr = net_random();
+
+ spin_lock_irq(&mdev->req_lock);
+
+ b = mdev->oldest_tle;
+ while (b) {
+ list_for_each_safe(le, tle, &b->requests) {
+ r = list_entry(le, struct drbd_request, tl_requests);
+ /* It would be nice to complete outside of spinlock.
+ * But this is easier for now. */
+ _req_mod(r, connection_lost_while_pending);
+ }
+ tmp = b->next;
+
+ /* there could still be requests on that ring list,
+ * in case local io is still pending */
+ list_del(&b->requests);
+
+ /* dec_ap_pending corresponding to queue_barrier.
+ * the newest barrier may not have been queued yet,
+ * in which case w.cb is still NULL. */
+ if (b->w.cb != NULL)
+ dec_ap_pending(mdev);
+
+ if (b == mdev->newest_tle) {
+ /* recycle, but reinit! */
+ D_ASSERT(tmp == NULL);
+ INIT_LIST_HEAD(&b->requests);
+ INIT_LIST_HEAD(&b->w.list);
+ b->w.cb = NULL;
+ b->br_number = new_initial_bnr;
+ b->n_req = 0;
+
+ mdev->oldest_tle = b;
+ break;
+ }
+ kfree(b);
+ b = tmp;
+ }
+
+ /* we expect this list to be empty. */
+ D_ASSERT(list_empty(&mdev->out_of_sequence_requests));
+
+ /* but just in case, clean it up anyways! */
+ list_for_each_safe(le, tle, &mdev->out_of_sequence_requests) {
+ r = list_entry(le, struct drbd_request, tl_requests);
+ /* It would be nice to complete outside of spinlock.
+ * But this is easier for now. */
+ _req_mod(r, connection_lost_while_pending);
+ }
+
+ /* ensure bit indicating barrier is required is clear */
+ clear_bit(CREATE_BARRIER, &mdev->flags);
+
+ spin_unlock_irq(&mdev->req_lock);
+}
+
+/**
+ * cl_wide_st_chg() - TRUE if the state change is a cluster wide one
+ * @mdev: DRBD device.
+ * @os: old (current) state.
+ * @ns: new (wanted) state.
+ */
+static int cl_wide_st_chg(struct drbd_conf *mdev,
+ union drbd_state os, union drbd_state ns)
+{
+ return (os.conn >= C_CONNECTED && ns.conn >= C_CONNECTED &&
+ ((os.role != R_PRIMARY && ns.role == R_PRIMARY) ||
+ (os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) ||
+ (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S) ||
+ (os.disk != D_DISKLESS && ns.disk == D_DISKLESS))) ||
+ (os.conn >= C_CONNECTED && ns.conn == C_DISCONNECTING) ||
+ (os.conn == C_CONNECTED && ns.conn == C_VERIFY_S);
+}
+
+int drbd_change_state(struct drbd_conf *mdev, enum chg_state_flags f,
+ union drbd_state mask, union drbd_state val)
+{
+ unsigned long flags;
+ union drbd_state os, ns;
+ int rv;
+
+ spin_lock_irqsave(&mdev->req_lock, flags);
+ os = mdev->state;
+ ns.i = (os.i & ~mask.i) | val.i;
+ rv = _drbd_set_state(mdev, ns, f, NULL);
+ ns = mdev->state;
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+ return rv;
+}
+
+/**
+ * drbd_force_state() - Impose a change which happens outside our control on our state
+ * @mdev: DRBD device.
+ * @mask: mask of state bits to change.
+ * @val: value of new state bits.
+ */
+void drbd_force_state(struct drbd_conf *mdev,
+ union drbd_state mask, union drbd_state val)
+{
+ drbd_change_state(mdev, CS_HARD, mask, val);
+}
+
+static int is_valid_state(struct drbd_conf *mdev, union drbd_state ns);
+static int is_valid_state_transition(struct drbd_conf *,
+ union drbd_state, union drbd_state);
+static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os,
+ union drbd_state ns, int *warn_sync_abort);
+int drbd_send_state_req(struct drbd_conf *,
+ union drbd_state, union drbd_state);
+
+static enum drbd_state_ret_codes _req_st_cond(struct drbd_conf *mdev,
+ union drbd_state mask, union drbd_state val)
+{
+ union drbd_state os, ns;
+ unsigned long flags;
+ int rv;
+
+ if (test_and_clear_bit(CL_ST_CHG_SUCCESS, &mdev->flags))
+ return SS_CW_SUCCESS;
+
+ if (test_and_clear_bit(CL_ST_CHG_FAIL, &mdev->flags))
+ return SS_CW_FAILED_BY_PEER;
+
+ rv = 0;
+ spin_lock_irqsave(&mdev->req_lock, flags);
+ os = mdev->state;
+ ns.i = (os.i & ~mask.i) | val.i;
+ ns = sanitize_state(mdev, os, ns, NULL);
+
+ if (!cl_wide_st_chg(mdev, os, ns))
+ rv = SS_CW_NO_NEED;
+ if (!rv) {
+ rv = is_valid_state(mdev, ns);
+ if (rv == SS_SUCCESS) {
+ rv = is_valid_state_transition(mdev, ns, os);
+ if (rv == SS_SUCCESS)
+ rv = 0; /* cont waiting, otherwise fail. */
+ }
+ }
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+ return rv;
+}
+
+/**
+ * drbd_req_state() - Perform an eventually cluster wide state change
+ * @mdev: DRBD device.
+ * @mask: mask of state bits to change.
+ * @val: value of new state bits.
+ * @f: flags
+ *
+ * Should not be called directly, use drbd_request_state() or
+ * _drbd_request_state().
+ */
+static int drbd_req_state(struct drbd_conf *mdev,
+ union drbd_state mask, union drbd_state val,
+ enum chg_state_flags f)
+{
+ struct completion done;
+ unsigned long flags;
+ union drbd_state os, ns;
+ int rv;
+
+ init_completion(&done);
+
+ if (f & CS_SERIALIZE)
+ mutex_lock(&mdev->state_mutex);
+
+ spin_lock_irqsave(&mdev->req_lock, flags);
+ os = mdev->state;
+ ns.i = (os.i & ~mask.i) | val.i;
+ ns = sanitize_state(mdev, os, ns, NULL);
+
+ if (cl_wide_st_chg(mdev, os, ns)) {
+ rv = is_valid_state(mdev, ns);
+ if (rv == SS_SUCCESS)
+ rv = is_valid_state_transition(mdev, ns, os);
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+ if (rv < SS_SUCCESS) {
+ if (f & CS_VERBOSE)
+ print_st_err(mdev, os, ns, rv);
+ goto abort;
+ }
+
+ drbd_state_lock(mdev);
+ if (!drbd_send_state_req(mdev, mask, val)) {
+ drbd_state_unlock(mdev);
+ rv = SS_CW_FAILED_BY_PEER;
+ if (f & CS_VERBOSE)
+ print_st_err(mdev, os, ns, rv);
+ goto abort;
+ }
+
+ wait_event(mdev->state_wait,
+ (rv = _req_st_cond(mdev, mask, val)));
+
+ if (rv < SS_SUCCESS) {
+ drbd_state_unlock(mdev);
+ if (f & CS_VERBOSE)
+ print_st_err(mdev, os, ns, rv);
+ goto abort;
+ }
+ spin_lock_irqsave(&mdev->req_lock, flags);
+ os = mdev->state;
+ ns.i = (os.i & ~mask.i) | val.i;
+ rv = _drbd_set_state(mdev, ns, f, &done);
+ drbd_state_unlock(mdev);
+ } else {
+ rv = _drbd_set_state(mdev, ns, f, &done);
+ }
+
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+ if (f & CS_WAIT_COMPLETE && rv == SS_SUCCESS) {
+ D_ASSERT(current != mdev->worker.task);
+ wait_for_completion(&done);
+ }
+
+abort:
+ if (f & CS_SERIALIZE)
+ mutex_unlock(&mdev->state_mutex);
+
+ return rv;
+}
+
+/**
+ * _drbd_request_state() - Request a state change (with flags)
+ * @mdev: DRBD device.
+ * @mask: mask of state bits to change.
+ * @val: value of new state bits.
+ * @f: flags
+ *
+ * Cousin of drbd_request_state(), useful with the CS_WAIT_COMPLETE
+ * flag, or when logging of failed state change requests is not desired.
+ */
+int _drbd_request_state(struct drbd_conf *mdev, union drbd_state mask,
+ union drbd_state val, enum chg_state_flags f)
+{
+ int rv;
+
+ wait_event(mdev->state_wait,
+ (rv = drbd_req_state(mdev, mask, val, f)) != SS_IN_TRANSIENT_STATE);
+
+ return rv;
+}
+
+static void print_st(struct drbd_conf *mdev, char *name, union drbd_state ns)
+{
+ dev_err(DEV, " %s = { cs:%s ro:%s/%s ds:%s/%s %c%c%c%c }\n",
+ name,
+ drbd_conn_str(ns.conn),
+ drbd_role_str(ns.role),
+ drbd_role_str(ns.peer),
+ drbd_disk_str(ns.disk),
+ drbd_disk_str(ns.pdsk),
+ ns.susp ? 's' : 'r',
+ ns.aftr_isp ? 'a' : '-',
+ ns.peer_isp ? 'p' : '-',
+ ns.user_isp ? 'u' : '-'
+ );
+}
+
+void print_st_err(struct drbd_conf *mdev,
+ union drbd_state os, union drbd_state ns, int err)
+{
+ if (err == SS_IN_TRANSIENT_STATE)
+ return;
+ dev_err(DEV, "State change failed: %s\n", drbd_set_st_err_str(err));
+ print_st(mdev, " state", os);
+ print_st(mdev, "wanted", ns);
+}
+
+
+#define drbd_peer_str drbd_role_str
+#define drbd_pdsk_str drbd_disk_str
+
+#define drbd_susp_str(A) ((A) ? "1" : "0")
+#define drbd_aftr_isp_str(A) ((A) ? "1" : "0")
+#define drbd_peer_isp_str(A) ((A) ? "1" : "0")
+#define drbd_user_isp_str(A) ((A) ? "1" : "0")
+
+#define PSC(A) \
+ ({ if (ns.A != os.A) { \
+ pbp += sprintf(pbp, #A "( %s -> %s ) ", \
+ drbd_##A##_str(os.A), \
+ drbd_##A##_str(ns.A)); \
+ } })
+
+/**
+ * is_valid_state() - Returns an SS_ error code if ns is not valid
+ * @mdev: DRBD device.
+ * @ns: State to consider.
+ */
+static int is_valid_state(struct drbd_conf *mdev, union drbd_state ns)
+{
+ /* See drbd_state_sw_errors in drbd_strings.c */
+
+ enum drbd_fencing_p fp;
+ int rv = SS_SUCCESS;
+
+ fp = FP_DONT_CARE;
+ if (get_ldev(mdev)) {
+ fp = mdev->ldev->dc.fencing;
+ put_ldev(mdev);
+ }
+
+ if (get_net_conf(mdev)) {
+ if (!mdev->net_conf->two_primaries &&
+ ns.role == R_PRIMARY && ns.peer == R_PRIMARY)
+ rv = SS_TWO_PRIMARIES;
+ put_net_conf(mdev);
+ }
+
+ if (rv <= 0)
+ /* already found a reason to abort */;
+ else if (ns.role == R_SECONDARY && mdev->open_cnt)
+ rv = SS_DEVICE_IN_USE;
+
+ else if (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.disk < D_UP_TO_DATE)
+ rv = SS_NO_UP_TO_DATE_DISK;
+
+ else if (fp >= FP_RESOURCE &&
+ ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk >= D_UNKNOWN)
+ rv = SS_PRIMARY_NOP;
+
+ else if (ns.role == R_PRIMARY && ns.disk <= D_INCONSISTENT && ns.pdsk <= D_INCONSISTENT)
+ rv = SS_NO_UP_TO_DATE_DISK;
+
+ else if (ns.conn > C_CONNECTED && ns.disk < D_INCONSISTENT)
+ rv = SS_NO_LOCAL_DISK;
+
+ else if (ns.conn > C_CONNECTED && ns.pdsk < D_INCONSISTENT)
+ rv = SS_NO_REMOTE_DISK;
+
+ else if ((ns.conn == C_CONNECTED ||
+ ns.conn == C_WF_BITMAP_S ||
+ ns.conn == C_SYNC_SOURCE ||
+ ns.conn == C_PAUSED_SYNC_S) &&
+ ns.disk == D_OUTDATED)
+ rv = SS_CONNECTED_OUTDATES;
+
+ else if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) &&
+ (mdev->sync_conf.verify_alg[0] == 0))
+ rv = SS_NO_VERIFY_ALG;
+
+ else if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) &&
+ mdev->agreed_pro_version < 88)
+ rv = SS_NOT_SUPPORTED;
+
+ return rv;
+}
+
+/**
+ * is_valid_state_transition() - Returns an SS_ error code if the state transition is not possible
+ * @mdev: DRBD device.
+ * @ns: new state.
+ * @os: old state.
+ */
+static int is_valid_state_transition(struct drbd_conf *mdev,
+ union drbd_state ns, union drbd_state os)
+{
+ int rv = SS_SUCCESS;
+
+ if ((ns.conn == C_STARTING_SYNC_T || ns.conn == C_STARTING_SYNC_S) &&
+ os.conn > C_CONNECTED)
+ rv = SS_RESYNC_RUNNING;
+
+ if (ns.conn == C_DISCONNECTING && os.conn == C_STANDALONE)
+ rv = SS_ALREADY_STANDALONE;
+
+ if (ns.disk > D_ATTACHING && os.disk == D_DISKLESS)
+ rv = SS_IS_DISKLESS;
+
+ if (ns.conn == C_WF_CONNECTION && os.conn < C_UNCONNECTED)
+ rv = SS_NO_NET_CONFIG;
+
+ if (ns.disk == D_OUTDATED && os.disk < D_OUTDATED && os.disk != D_ATTACHING)
+ rv = SS_LOWER_THAN_OUTDATED;
+
+ if (ns.conn == C_DISCONNECTING && os.conn == C_UNCONNECTED)
+ rv = SS_IN_TRANSIENT_STATE;
+
+ if (ns.conn == os.conn && ns.conn == C_WF_REPORT_PARAMS)
+ rv = SS_IN_TRANSIENT_STATE;
+
+ if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && os.conn < C_CONNECTED)
+ rv = SS_NEED_CONNECTION;
+
+ if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) &&
+ ns.conn != os.conn && os.conn > C_CONNECTED)
+ rv = SS_RESYNC_RUNNING;
+
+ if ((ns.conn == C_STARTING_SYNC_S || ns.conn == C_STARTING_SYNC_T) &&
+ os.conn < C_CONNECTED)
+ rv = SS_NEED_CONNECTION;
+
+ return rv;
+}
+
+/**
+ * sanitize_state() - Resolves implicitly necessary additional changes to a state transition
+ * @mdev: DRBD device.
+ * @os: old state.
+ * @ns: new state.
+ * @warn_sync_abort:
+ *
+ * When we loose connection, we have to set the state of the peers disk (pdsk)
+ * to D_UNKNOWN. This rule and many more along those lines are in this function.
+ */
+static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os,
+ union drbd_state ns, int *warn_sync_abort)
+{
+ enum drbd_fencing_p fp;
+
+ fp = FP_DONT_CARE;
+ if (get_ldev(mdev)) {
+ fp = mdev->ldev->dc.fencing;
+ put_ldev(mdev);
+ }
+
+ /* Disallow Network errors to configure a device's network part */
+ if ((ns.conn >= C_TIMEOUT && ns.conn <= C_TEAR_DOWN) &&
+ os.conn <= C_DISCONNECTING)
+ ns.conn = os.conn;
+
+ /* After a network error (+C_TEAR_DOWN) only C_UNCONNECTED or C_DISCONNECTING can follow */
+ if (os.conn >= C_TIMEOUT && os.conn <= C_TEAR_DOWN &&
+ ns.conn != C_UNCONNECTED && ns.conn != C_DISCONNECTING)
+ ns.conn = os.conn;
+
+ /* After C_DISCONNECTING only C_STANDALONE may follow */
+ if (os.conn == C_DISCONNECTING && ns.conn != C_STANDALONE)
+ ns.conn = os.conn;
+
+ if (ns.conn < C_CONNECTED) {
+ ns.peer_isp = 0;
+ ns.peer = R_UNKNOWN;
+ if (ns.pdsk > D_UNKNOWN || ns.pdsk < D_INCONSISTENT)
+ ns.pdsk = D_UNKNOWN;
+ }
+
+ /* Clear the aftr_isp when becoming unconfigured */
+ if (ns.conn == C_STANDALONE && ns.disk == D_DISKLESS && ns.role == R_SECONDARY)
+ ns.aftr_isp = 0;
+
+ if (ns.conn <= C_DISCONNECTING && ns.disk == D_DISKLESS)
+ ns.pdsk = D_UNKNOWN;
+
+ /* Abort resync if a disk fails/detaches */
+ if (os.conn > C_CONNECTED && ns.conn > C_CONNECTED &&
+ (ns.disk <= D_FAILED || ns.pdsk <= D_FAILED)) {
+ if (warn_sync_abort)
+ *warn_sync_abort = 1;
+ ns.conn = C_CONNECTED;
+ }
+
+ if (ns.conn >= C_CONNECTED &&
+ ((ns.disk == D_CONSISTENT || ns.disk == D_OUTDATED) ||
+ (ns.disk == D_NEGOTIATING && ns.conn == C_WF_BITMAP_T))) {
+ switch (ns.conn) {
+ case C_WF_BITMAP_T:
+ case C_PAUSED_SYNC_T:
+ ns.disk = D_OUTDATED;
+ break;
+ case C_CONNECTED:
+ case C_WF_BITMAP_S:
+ case C_SYNC_SOURCE:
+ case C_PAUSED_SYNC_S:
+ ns.disk = D_UP_TO_DATE;
+ break;
+ case C_SYNC_TARGET:
+ ns.disk = D_INCONSISTENT;
+ dev_warn(DEV, "Implicitly set disk state Inconsistent!\n");
+ break;
+ }
+ if (os.disk == D_OUTDATED && ns.disk == D_UP_TO_DATE)
+ dev_warn(DEV, "Implicitly set disk from Outdated to UpToDate\n");
+ }
+
+ if (ns.conn >= C_CONNECTED &&
+ (ns.pdsk == D_CONSISTENT || ns.pdsk == D_OUTDATED)) {
+ switch (ns.conn) {
+ case C_CONNECTED:
+ case C_WF_BITMAP_T:
+ case C_PAUSED_SYNC_T:
+ case C_SYNC_TARGET:
+ ns.pdsk = D_UP_TO_DATE;
+ break;
+ case C_WF_BITMAP_S:
+ case C_PAUSED_SYNC_S:
+ ns.pdsk = D_OUTDATED;
+ break;
+ case C_SYNC_SOURCE:
+ ns.pdsk = D_INCONSISTENT;
+ dev_warn(DEV, "Implicitly set pdsk Inconsistent!\n");
+ break;
+ }
+ if (os.pdsk == D_OUTDATED && ns.pdsk == D_UP_TO_DATE)
+ dev_warn(DEV, "Implicitly set pdsk from Outdated to UpToDate\n");
+ }
+
+ /* Connection breaks down before we finished "Negotiating" */
+ if (ns.conn < C_CONNECTED && ns.disk == D_NEGOTIATING &&
+ get_ldev_if_state(mdev, D_NEGOTIATING)) {
+ if (mdev->ed_uuid == mdev->ldev->md.uuid[UI_CURRENT]) {
+ ns.disk = mdev->new_state_tmp.disk;
+ ns.pdsk = mdev->new_state_tmp.pdsk;
+ } else {
+ dev_alert(DEV, "Connection lost while negotiating, no data!\n");
+ ns.disk = D_DISKLESS;
+ ns.pdsk = D_UNKNOWN;
+ }
+ put_ldev(mdev);
+ }
+
+ if (fp == FP_STONITH &&
+ (ns.role == R_PRIMARY &&
+ ns.conn < C_CONNECTED &&
+ ns.pdsk > D_OUTDATED))
+ ns.susp = 1;
+
+ if (ns.aftr_isp || ns.peer_isp || ns.user_isp) {
+ if (ns.conn == C_SYNC_SOURCE)
+ ns.conn = C_PAUSED_SYNC_S;
+ if (ns.conn == C_SYNC_TARGET)
+ ns.conn = C_PAUSED_SYNC_T;
+ } else {
+ if (ns.conn == C_PAUSED_SYNC_S)
+ ns.conn = C_SYNC_SOURCE;
+ if (ns.conn == C_PAUSED_SYNC_T)
+ ns.conn = C_SYNC_TARGET;
+ }
+
+ return ns;
+}
+
+/* helper for __drbd_set_state */
+static void set_ov_position(struct drbd_conf *mdev, enum drbd_conns cs)
+{
+ if (cs == C_VERIFY_T) {
+ /* starting online verify from an arbitrary position
+ * does not fit well into the existing protocol.
+ * on C_VERIFY_T, we initialize ov_left and friends
+ * implicitly in receive_DataRequest once the
+ * first P_OV_REQUEST is received */
+ mdev->ov_start_sector = ~(sector_t)0;
+ } else {
+ unsigned long bit = BM_SECT_TO_BIT(mdev->ov_start_sector);
+ if (bit >= mdev->rs_total)
+ mdev->ov_start_sector =
+ BM_BIT_TO_SECT(mdev->rs_total - 1);
+ mdev->ov_position = mdev->ov_start_sector;
+ }
+}
+
+/**
+ * __drbd_set_state() - Set a new DRBD state
+ * @mdev: DRBD device.
+ * @ns: new state.
+ * @flags: Flags
+ * @done: Optional completion, that will get completed after the after_state_ch() finished
+ *
+ * Caller needs to hold req_lock, and global_state_lock. Do not call directly.
+ */
+int __drbd_set_state(struct drbd_conf *mdev,
+ union drbd_state ns, enum chg_state_flags flags,
+ struct completion *done)
+{
+ union drbd_state os;
+ int rv = SS_SUCCESS;
+ int warn_sync_abort = 0;
+ struct after_state_chg_work *ascw;
+
+ os = mdev->state;
+
+ ns = sanitize_state(mdev, os, ns, &warn_sync_abort);
+
+ if (ns.i == os.i)
+ return SS_NOTHING_TO_DO;
+
+ if (!(flags & CS_HARD)) {
+ /* pre-state-change checks ; only look at ns */
+ /* See drbd_state_sw_errors in drbd_strings.c */
+
+ rv = is_valid_state(mdev, ns);
+ if (rv < SS_SUCCESS) {
+ /* If the old state was illegal as well, then let
+ this happen...*/
+
+ if (is_valid_state(mdev, os) == rv) {
+ dev_err(DEV, "Considering state change from bad state. "
+ "Error would be: '%s'\n",
+ drbd_set_st_err_str(rv));
+ print_st(mdev, "old", os);
+ print_st(mdev, "new", ns);
+ rv = is_valid_state_transition(mdev, ns, os);
+ }
+ } else
+ rv = is_valid_state_transition(mdev, ns, os);
+ }
+
+ if (rv < SS_SUCCESS) {
+ if (flags & CS_VERBOSE)
+ print_st_err(mdev, os, ns, rv);
+ return rv;
+ }
+
+ if (warn_sync_abort)
+ dev_warn(DEV, "Resync aborted.\n");
+
+ {
+ char *pbp, pb[300];
+ pbp = pb;
+ *pbp = 0;
+ PSC(role);
+ PSC(peer);
+ PSC(conn);
+ PSC(disk);
+ PSC(pdsk);
+ PSC(susp);
+ PSC(aftr_isp);
+ PSC(peer_isp);
+ PSC(user_isp);
+ dev_info(DEV, "%s\n", pb);
+ }
+
+ /* solve the race between becoming unconfigured,
+ * worker doing the cleanup, and
+ * admin reconfiguring us:
+ * on (re)configure, first set CONFIG_PENDING,
+ * then wait for a potentially exiting worker,
+ * start the worker, and schedule one no_op.
+ * then proceed with configuration.
+ */
+ if (ns.disk == D_DISKLESS &&
+ ns.conn == C_STANDALONE &&
+ ns.role == R_SECONDARY &&
+ !test_and_set_bit(CONFIG_PENDING, &mdev->flags))
+ set_bit(DEVICE_DYING, &mdev->flags);
+
+ mdev->state.i = ns.i;
+ wake_up(&mdev->misc_wait);
+ wake_up(&mdev->state_wait);
+
+ /* post-state-change actions */
+ if (os.conn >= C_SYNC_SOURCE && ns.conn <= C_CONNECTED) {
+ set_bit(STOP_SYNC_TIMER, &mdev->flags);
+ mod_timer(&mdev->resync_timer, jiffies);
+ }
+
+ /* aborted verify run. log the last position */
+ if ((os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) &&
+ ns.conn < C_CONNECTED) {
+ mdev->ov_start_sector =
+ BM_BIT_TO_SECT(mdev->rs_total - mdev->ov_left);
+ dev_info(DEV, "Online Verify reached sector %llu\n",
+ (unsigned long long)mdev->ov_start_sector);
+ }
+
+ if ((os.conn == C_PAUSED_SYNC_T || os.conn == C_PAUSED_SYNC_S) &&
+ (ns.conn == C_SYNC_TARGET || ns.conn == C_SYNC_SOURCE)) {
+ dev_info(DEV, "Syncer continues.\n");
+ mdev->rs_paused += (long)jiffies-(long)mdev->rs_mark_time;
+ if (ns.conn == C_SYNC_TARGET) {
+ if (!test_and_clear_bit(STOP_SYNC_TIMER, &mdev->flags))
+ mod_timer(&mdev->resync_timer, jiffies);
+ /* This if (!test_bit) is only needed for the case
+ that a device that has ceased to used its timer,
+ i.e. it is already in drbd_resync_finished() gets
+ paused and resumed. */
+ }
+ }
+
+ if ((os.conn == C_SYNC_TARGET || os.conn == C_SYNC_SOURCE) &&
+ (ns.conn == C_PAUSED_SYNC_T || ns.conn == C_PAUSED_SYNC_S)) {
+ dev_info(DEV, "Resync suspended\n");
+ mdev->rs_mark_time = jiffies;
+ if (ns.conn == C_PAUSED_SYNC_T)
+ set_bit(STOP_SYNC_TIMER, &mdev->flags);
+ }
+
+ if (os.conn == C_CONNECTED &&
+ (ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T)) {
+ mdev->ov_position = 0;
+ mdev->rs_total =
+ mdev->rs_mark_left = drbd_bm_bits(mdev);
+ if (mdev->agreed_pro_version >= 90)
+ set_ov_position(mdev, ns.conn);
+ else
+ mdev->ov_start_sector = 0;
+ mdev->ov_left = mdev->rs_total
+ - BM_SECT_TO_BIT(mdev->ov_position);
+ mdev->rs_start =
+ mdev->rs_mark_time = jiffies;
+ mdev->ov_last_oos_size = 0;
+ mdev->ov_last_oos_start = 0;
+
+ if (ns.conn == C_VERIFY_S) {
+ dev_info(DEV, "Starting Online Verify from sector %llu\n",
+ (unsigned long long)mdev->ov_position);
+ mod_timer(&mdev->resync_timer, jiffies);
+ }
+ }
+
+ if (get_ldev(mdev)) {
+ u32 mdf = mdev->ldev->md.flags & ~(MDF_CONSISTENT|MDF_PRIMARY_IND|
+ MDF_CONNECTED_IND|MDF_WAS_UP_TO_DATE|
+ MDF_PEER_OUT_DATED|MDF_CRASHED_PRIMARY);
+
+ if (test_bit(CRASHED_PRIMARY, &mdev->flags))
+ mdf |= MDF_CRASHED_PRIMARY;
+ if (mdev->state.role == R_PRIMARY ||
+ (mdev->state.pdsk < D_INCONSISTENT && mdev->state.peer == R_PRIMARY))
+ mdf |= MDF_PRIMARY_IND;
+ if (mdev->state.conn > C_WF_REPORT_PARAMS)
+ mdf |= MDF_CONNECTED_IND;
+ if (mdev->state.disk > D_INCONSISTENT)
+ mdf |= MDF_CONSISTENT;
+ if (mdev->state.disk > D_OUTDATED)
+ mdf |= MDF_WAS_UP_TO_DATE;
+ if (mdev->state.pdsk <= D_OUTDATED && mdev->state.pdsk >= D_INCONSISTENT)
+ mdf |= MDF_PEER_OUT_DATED;
+ if (mdf != mdev->ldev->md.flags) {
+ mdev->ldev->md.flags = mdf;
+ drbd_md_mark_dirty(mdev);
+ }
+ if (os.disk < D_CONSISTENT && ns.disk >= D_CONSISTENT)
+ drbd_set_ed_uuid(mdev, mdev->ldev->md.uuid[UI_CURRENT]);
+ put_ldev(mdev);
+ }
+
+ /* Peer was forced D_UP_TO_DATE & R_PRIMARY, consider to resync */
+ if (os.disk == D_INCONSISTENT && os.pdsk == D_INCONSISTENT &&
+ os.peer == R_SECONDARY && ns.peer == R_PRIMARY)
+ set_bit(CONSIDER_RESYNC, &mdev->flags);
+
+ /* Receiver should clean up itself */
+ if (os.conn != C_DISCONNECTING && ns.conn == C_DISCONNECTING)
+ drbd_thread_stop_nowait(&mdev->receiver);
+
+ /* Now the receiver finished cleaning up itself, it should die */
+ if (os.conn != C_STANDALONE && ns.conn == C_STANDALONE)
+ drbd_thread_stop_nowait(&mdev->receiver);
+
+ /* Upon network failure, we need to restart the receiver. */
+ if (os.conn > C_TEAR_DOWN &&
+ ns.conn <= C_TEAR_DOWN && ns.conn >= C_TIMEOUT)
+ drbd_thread_restart_nowait(&mdev->receiver);
+
+ ascw = kmalloc(sizeof(*ascw), GFP_ATOMIC);
+ if (ascw) {
+ ascw->os = os;
+ ascw->ns = ns;
+ ascw->flags = flags;
+ ascw->w.cb = w_after_state_ch;
+ ascw->done = done;
+ drbd_queue_work(&mdev->data.work, &ascw->w);
+ } else {
+ dev_warn(DEV, "Could not kmalloc an ascw\n");
+ }
+
+ return rv;
+}
+
+static int w_after_state_ch(struct drbd_conf *mdev, struct drbd_work *w, int unused)
+{
+ struct after_state_chg_work *ascw =
+ container_of(w, struct after_state_chg_work, w);
+ after_state_ch(mdev, ascw->os, ascw->ns, ascw->flags);
+ if (ascw->flags & CS_WAIT_COMPLETE) {
+ D_ASSERT(ascw->done != NULL);
+ complete(ascw->done);
+ }
+ kfree(ascw);
+
+ return 1;
+}
+
+static void abw_start_sync(struct drbd_conf *mdev, int rv)
+{
+ if (rv) {
+ dev_err(DEV, "Writing the bitmap failed not starting resync.\n");
+ _drbd_request_state(mdev, NS(conn, C_CONNECTED), CS_VERBOSE);
+ return;
+ }
+
+ switch (mdev->state.conn) {
+ case C_STARTING_SYNC_T:
+ _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE);
+ break;
+ case C_STARTING_SYNC_S:
+ drbd_start_resync(mdev, C_SYNC_SOURCE);
+ break;
+ }
+}
+
+/**
+ * after_state_ch() - Perform after state change actions that may sleep
+ * @mdev: DRBD device.
+ * @os: old state.
+ * @ns: new state.
+ * @flags: Flags
+ */
+static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
+ union drbd_state ns, enum chg_state_flags flags)
+{
+ enum drbd_fencing_p fp;
+
+ if (os.conn != C_CONNECTED && ns.conn == C_CONNECTED) {
+ clear_bit(CRASHED_PRIMARY, &mdev->flags);
+ if (mdev->p_uuid)
+ mdev->p_uuid[UI_FLAGS] &= ~((u64)2);
+ }
+
+ fp = FP_DONT_CARE;
+ if (get_ldev(mdev)) {
+ fp = mdev->ldev->dc.fencing;
+ put_ldev(mdev);
+ }
+
+ /* Inform userspace about the change... */
+ drbd_bcast_state(mdev, ns);
+
+ if (!(os.role == R_PRIMARY && os.disk < D_UP_TO_DATE && os.pdsk < D_UP_TO_DATE) &&
+ (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE))
+ drbd_khelper(mdev, "pri-on-incon-degr");
+
+ /* Here we have the actions that are performed after a
+ state change. This function might sleep */
+
+ if (fp == FP_STONITH && ns.susp) {
+ /* case1: The outdate peer handler is successful:
+ * case2: The connection was established again: */
+ if ((os.pdsk > D_OUTDATED && ns.pdsk <= D_OUTDATED) ||
+ (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED)) {
+ tl_clear(mdev);
+ spin_lock_irq(&mdev->req_lock);
+ _drbd_set_state(_NS(mdev, susp, 0), CS_VERBOSE, NULL);
+ spin_unlock_irq(&mdev->req_lock);
+ }
+ }
+ /* Do not change the order of the if above and the two below... */
+ if (os.pdsk == D_DISKLESS && ns.pdsk > D_DISKLESS) { /* attach on the peer */
+ drbd_send_uuids(mdev);
+ drbd_send_state(mdev);
+ }
+ if (os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S)
+ drbd_queue_bitmap_io(mdev, &drbd_send_bitmap, NULL, "send_bitmap (WFBitMapS)");
+
+ /* Lost contact to peer's copy of the data */
+ if ((os.pdsk >= D_INCONSISTENT &&
+ os.pdsk != D_UNKNOWN &&
+ os.pdsk != D_OUTDATED)
+ && (ns.pdsk < D_INCONSISTENT ||
+ ns.pdsk == D_UNKNOWN ||
+ ns.pdsk == D_OUTDATED)) {
+ kfree(mdev->p_uuid);
+ mdev->p_uuid = NULL;
+ if (get_ldev(mdev)) {
+ if ((ns.role == R_PRIMARY || ns.peer == R_PRIMARY) &&
+ mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) {
+ drbd_uuid_new_current(mdev);
+ drbd_send_uuids(mdev);
+ }
+ put_ldev(mdev);
+ }
+ }
+
+ if (ns.pdsk < D_INCONSISTENT && get_ldev(mdev)) {
+ if (ns.peer == R_PRIMARY && mdev->ldev->md.uuid[UI_BITMAP] == 0)
+ drbd_uuid_new_current(mdev);
+
+ /* D_DISKLESS Peer becomes secondary */
+ if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY)
+ drbd_al_to_on_disk_bm(mdev);
+ put_ldev(mdev);
+ }
+
+ /* Last part of the attaching process ... */
+ if (ns.conn >= C_CONNECTED &&
+ os.disk == D_ATTACHING && ns.disk == D_NEGOTIATING) {
+ kfree(mdev->p_uuid); /* We expect to receive up-to-date UUIDs soon. */
+ mdev->p_uuid = NULL; /* ...to not use the old ones in the mean time */
+ drbd_send_sizes(mdev, 0); /* to start sync... */
+ drbd_send_uuids(mdev);
+ drbd_send_state(mdev);
+ }
+
+ /* We want to pause/continue resync, tell peer. */
+ if (ns.conn >= C_CONNECTED &&
+ ((os.aftr_isp != ns.aftr_isp) ||
+ (os.user_isp != ns.user_isp)))
+ drbd_send_state(mdev);
+
+ /* In case one of the isp bits got set, suspend other devices. */
+ if ((!os.aftr_isp && !os.peer_isp && !os.user_isp) &&
+ (ns.aftr_isp || ns.peer_isp || ns.user_isp))
+ suspend_other_sg(mdev);
+
+ /* Make sure the peer gets informed about eventual state
+ changes (ISP bits) while we were in WFReportParams. */
+ if (os.conn == C_WF_REPORT_PARAMS && ns.conn >= C_CONNECTED)
+ drbd_send_state(mdev);
+
+ /* We are in the progress to start a full sync... */
+ if ((os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) ||
+ (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S))
+ drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, &abw_start_sync, "set_n_write from StartingSync");
+
+ /* We are invalidating our self... */
+ if (os.conn < C_CONNECTED && ns.conn < C_CONNECTED &&
+ os.disk > D_INCONSISTENT && ns.disk == D_INCONSISTENT)
+ drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, NULL, "set_n_write from invalidate");
+
+ if (os.disk > D_FAILED && ns.disk == D_FAILED) {
+ enum drbd_io_error_p eh;
+
+ eh = EP_PASS_ON;
+ if (get_ldev_if_state(mdev, D_FAILED)) {
+ eh = mdev->ldev->dc.on_io_error;
+ put_ldev(mdev);
+ }
+
+ drbd_rs_cancel_all(mdev);
+ /* since get_ldev() only works as long as disk>=D_INCONSISTENT,
+ and it is D_DISKLESS here, local_cnt can only go down, it can
+ not increase... It will reach zero */
+ wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
+ mdev->rs_total = 0;
+ mdev->rs_failed = 0;
+ atomic_set(&mdev->rs_pending_cnt, 0);
+
+ spin_lock_irq(&mdev->req_lock);
+ _drbd_set_state(_NS(mdev, disk, D_DISKLESS), CS_HARD, NULL);
+ spin_unlock_irq(&mdev->req_lock);
+
+ if (eh == EP_CALL_HELPER)
+ drbd_khelper(mdev, "local-io-error");
+ }
+
+ if (os.disk > D_DISKLESS && ns.disk == D_DISKLESS) {
+
+ if (os.disk == D_FAILED) /* && ns.disk == D_DISKLESS*/ {
+ if (drbd_send_state(mdev))
+ dev_warn(DEV, "Notified peer that my disk is broken.\n");
+ else
+ dev_err(DEV, "Sending state in drbd_io_error() failed\n");
+ }
+
+ lc_destroy(mdev->resync);
+ mdev->resync = NULL;
+ lc_destroy(mdev->act_log);
+ mdev->act_log = NULL;
+ __no_warn(local,
+ drbd_free_bc(mdev->ldev);
+ mdev->ldev = NULL;);
+
+ if (mdev->md_io_tmpp)
+ __free_page(mdev->md_io_tmpp);
+ }
+
+ /* Disks got bigger while they were detached */
+ if (ns.disk > D_NEGOTIATING && ns.pdsk > D_NEGOTIATING &&
+ test_and_clear_bit(RESYNC_AFTER_NEG, &mdev->flags)) {
+ if (ns.conn == C_CONNECTED)
+ resync_after_online_grow(mdev);
+ }
+
+ /* A resync finished or aborted, wake paused devices... */
+ if ((os.conn > C_CONNECTED && ns.conn <= C_CONNECTED) ||
+ (os.peer_isp && !ns.peer_isp) ||
+ (os.user_isp && !ns.user_isp))
+ resume_next_sg(mdev);
+
+ /* Upon network connection, we need to start the receiver */
+ if (os.conn == C_STANDALONE && ns.conn == C_UNCONNECTED)
+ drbd_thread_start(&mdev->receiver);
+
+ /* Terminate worker thread if we are unconfigured - it will be
+ restarted as needed... */
+ if (ns.disk == D_DISKLESS &&
+ ns.conn == C_STANDALONE &&
+ ns.role == R_SECONDARY) {
+ if (os.aftr_isp != ns.aftr_isp)
+ resume_next_sg(mdev);
+ /* set in __drbd_set_state, unless CONFIG_PENDING was set */
+ if (test_bit(DEVICE_DYING, &mdev->flags))
+ drbd_thread_stop_nowait(&mdev->worker);
+ }
+
+ drbd_md_sync(mdev);
+}
+
+
+static int drbd_thread_setup(void *arg)
+{
+ struct drbd_thread *thi = (struct drbd_thread *) arg;
+ struct drbd_conf *mdev = thi->mdev;
+ unsigned long flags;
+ int retval;
+
+restart:
+ retval = thi->function(thi);
+
+ spin_lock_irqsave(&thi->t_lock, flags);
+
+ /* if the receiver has been "Exiting", the last thing it did
+ * was set the conn state to "StandAlone",
+ * if now a re-connect request comes in, conn state goes C_UNCONNECTED,
+ * and receiver thread will be "started".
+ * drbd_thread_start needs to set "Restarting" in that case.
+ * t_state check and assignment needs to be within the same spinlock,
+ * so either thread_start sees Exiting, and can remap to Restarting,
+ * or thread_start see None, and can proceed as normal.
+ */
+
+ if (thi->t_state == Restarting) {
+ dev_info(DEV, "Restarting %s\n", current->comm);
+ thi->t_state = Running;
+ spin_unlock_irqrestore(&thi->t_lock, flags);
+ goto restart;
+ }
+
+ thi->task = NULL;
+ thi->t_state = None;
+ smp_mb();
+ complete(&thi->stop);
+ spin_unlock_irqrestore(&thi->t_lock, flags);
+
+ dev_info(DEV, "Terminating %s\n", current->comm);
+
+ /* Release mod reference taken when thread was started */
+ module_put(THIS_MODULE);
+ return retval;
+}
+
+static void drbd_thread_init(struct drbd_conf *mdev, struct drbd_thread *thi,
+ int (*func) (struct drbd_thread *))
+{
+ spin_lock_init(&thi->t_lock);
+ thi->task = NULL;
+ thi->t_state = None;
+ thi->function = func;
+ thi->mdev = mdev;
+}
+
+int drbd_thread_start(struct drbd_thread *thi)
+{
+ struct drbd_conf *mdev = thi->mdev;
+ struct task_struct *nt;
+ unsigned long flags;
+
+ const char *me =
+ thi == &mdev->receiver ? "receiver" :
+ thi == &mdev->asender ? "asender" :
+ thi == &mdev->worker ? "worker" : "NONSENSE";
+
+ /* is used from state engine doing drbd_thread_stop_nowait,
+ * while holding the req lock irqsave */
+ spin_lock_irqsave(&thi->t_lock, flags);
+
+ switch (thi->t_state) {
+ case None:
+ dev_info(DEV, "Starting %s thread (from %s [%d])\n",
+ me, current->comm, current->pid);
+
+ /* Get ref on module for thread - this is released when thread exits */
+ if (!try_module_get(THIS_MODULE)) {
+ dev_err(DEV, "Failed to get module reference in drbd_thread_start\n");
+ spin_unlock_irqrestore(&thi->t_lock, flags);
+ return FALSE;
+ }
+
+ init_completion(&thi->stop);
+ D_ASSERT(thi->task == NULL);
+ thi->reset_cpu_mask = 1;
+ thi->t_state = Running;
+ spin_unlock_irqrestore(&thi->t_lock, flags);
+ flush_signals(current); /* otherw. may get -ERESTARTNOINTR */
+
+ nt = kthread_create(drbd_thread_setup, (void *) thi,
+ "drbd%d_%s", mdev_to_minor(mdev), me);
+
+ if (IS_ERR(nt)) {
+ dev_err(DEV, "Couldn't start thread\n");
+
+ module_put(THIS_MODULE);
+ return FALSE;
+ }
+ spin_lock_irqsave(&thi->t_lock, flags);
+ thi->task = nt;
+ thi->t_state = Running;
+ spin_unlock_irqrestore(&thi->t_lock, flags);
+ wake_up_process(nt);
+ break;
+ case Exiting:
+ thi->t_state = Restarting;
+ dev_info(DEV, "Restarting %s thread (from %s [%d])\n",
+ me, current->comm, current->pid);
+ /* fall through */
+ case Running:
+ case Restarting:
+ default:
+ spin_unlock_irqrestore(&thi->t_lock, flags);
+ break;
+ }
+
+ return TRUE;
+}
+
+
+void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait)
+{
+ unsigned long flags;
+
+ enum drbd_thread_state ns = restart ? Restarting : Exiting;
+
+ /* may be called from state engine, holding the req lock irqsave */
+ spin_lock_irqsave(&thi->t_lock, flags);
+
+ if (thi->t_state == None) {
+ spin_unlock_irqrestore(&thi->t_lock, flags);
+ if (restart)
+ drbd_thread_start(thi);
+ return;
+ }
+
+ if (thi->t_state != ns) {
+ if (thi->task == NULL) {
+ spin_unlock_irqrestore(&thi->t_lock, flags);
+ return;
+ }
+
+ thi->t_state = ns;
+ smp_mb();
+ init_completion(&thi->stop);
+ if (thi->task != current)
+ force_sig(DRBD_SIGKILL, thi->task);
+
+ }
+
+ spin_unlock_irqrestore(&thi->t_lock, flags);
+
+ if (wait)
+ wait_for_completion(&thi->stop);
+}
+
+#ifdef CONFIG_SMP
+/**
+ * drbd_calc_cpu_mask() - Generate CPU masks, spread over all CPUs
+ * @mdev: DRBD device.
+ *
+ * Forces all threads of a device onto the same CPU. This is beneficial for
+ * DRBD's performance. May be overwritten by user's configuration.
+ */
+void drbd_calc_cpu_mask(struct drbd_conf *mdev)
+{
+ int ord, cpu;
+
+ /* user override. */
+ if (cpumask_weight(mdev->cpu_mask))
+ return;
+
+ ord = mdev_to_minor(mdev) % cpumask_weight(cpu_online_mask);
+ for_each_online_cpu(cpu) {
+ if (ord-- == 0) {
+ cpumask_set_cpu(cpu, mdev->cpu_mask);
+ return;
+ }
+ }
+ /* should not be reached */
+ cpumask_setall(mdev->cpu_mask);
+}
+
+/**
+ * drbd_thread_current_set_cpu() - modifies the cpu mask of the _current_ thread
+ * @mdev: DRBD device.
+ *
+ * call in the "main loop" of _all_ threads, no need for any mutex, current won't die
+ * prematurely.
+ */
+void drbd_thread_current_set_cpu(struct drbd_conf *mdev)
+{
+ struct task_struct *p = current;
+ struct drbd_thread *thi =
+ p == mdev->asender.task ? &mdev->asender :
+ p == mdev->receiver.task ? &mdev->receiver :
+ p == mdev->worker.task ? &mdev->worker :
+ NULL;
+ ERR_IF(thi == NULL)
+ return;
+ if (!thi->reset_cpu_mask)
+ return;
+ thi->reset_cpu_mask = 0;
+ set_cpus_allowed_ptr(p, mdev->cpu_mask);
+}
+#endif
+
+/* the appropriate socket mutex must be held already */
+int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock,
+ enum drbd_packets cmd, struct p_header *h,
+ size_t size, unsigned msg_flags)
+{
+ int sent, ok;
+
+ ERR_IF(!h) return FALSE;
+ ERR_IF(!size) return FALSE;
+
+ h->magic = BE_DRBD_MAGIC;
+ h->command = cpu_to_be16(cmd);
+ h->length = cpu_to_be16(size-sizeof(struct p_header));
+
+ sent = drbd_send(mdev, sock, h, size, msg_flags);
+
+ ok = (sent == size);
+ if (!ok)
+ dev_err(DEV, "short sent %s size=%d sent=%d\n",
+ cmdname(cmd), (int)size, sent);
+ return ok;
+}
+
+/* don't pass the socket. we may only look at it
+ * when we hold the appropriate socket mutex.
+ */
+int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket,
+ enum drbd_packets cmd, struct p_header *h, size_t size)
+{
+ int ok = 0;
+ struct socket *sock;
+
+ if (use_data_socket) {
+ mutex_lock(&mdev->data.mutex);
+ sock = mdev->data.socket;
+ } else {
+ mutex_lock(&mdev->meta.mutex);
+ sock = mdev->meta.socket;
+ }
+
+ /* drbd_disconnect() could have called drbd_free_sock()
+ * while we were waiting in down()... */
+ if (likely(sock != NULL))
+ ok = _drbd_send_cmd(mdev, sock, cmd, h, size, 0);
+
+ if (use_data_socket)
+ mutex_unlock(&mdev->data.mutex);
+ else
+ mutex_unlock(&mdev->meta.mutex);
+ return ok;
+}
+
+int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packets cmd, char *data,
+ size_t size)
+{
+ struct p_header h;
+ int ok;
+
+ h.magic = BE_DRBD_MAGIC;
+ h.command = cpu_to_be16(cmd);
+ h.length = cpu_to_be16(size);
+
+ if (!drbd_get_data_sock(mdev))
+ return 0;
+
+ ok = (sizeof(h) ==
+ drbd_send(mdev, mdev->data.socket, &h, sizeof(h), 0));
+ ok = ok && (size ==
+ drbd_send(mdev, mdev->data.socket, data, size, 0));
+
+ drbd_put_data_sock(mdev);
+
+ return ok;
+}
+
+int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc)
+{
+ struct p_rs_param_89 *p;
+ struct socket *sock;
+ int size, rv;
+ const int apv = mdev->agreed_pro_version;
+
+ size = apv <= 87 ? sizeof(struct p_rs_param)
+ : apv == 88 ? sizeof(struct p_rs_param)
+ + strlen(mdev->sync_conf.verify_alg) + 1
+ : /* 89 */ sizeof(struct p_rs_param_89);
+
+ /* used from admin command context and receiver/worker context.
+ * to avoid kmalloc, grab the socket right here,
+ * then use the pre-allocated sbuf there */
+ mutex_lock(&mdev->data.mutex);
+ sock = mdev->data.socket;
+
+ if (likely(sock != NULL)) {
+ enum drbd_packets cmd = apv >= 89 ? P_SYNC_PARAM89 : P_SYNC_PARAM;
+
+ p = &mdev->data.sbuf.rs_param_89;
+
+ /* initialize verify_alg and csums_alg */
+ memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX);
+
+ p->rate = cpu_to_be32(sc->rate);
+
+ if (apv >= 88)
+ strcpy(p->verify_alg, mdev->sync_conf.verify_alg);
+ if (apv >= 89)
+ strcpy(p->csums_alg, mdev->sync_conf.csums_alg);
+
+ rv = _drbd_send_cmd(mdev, sock, cmd, &p->head, size, 0);
+ } else
+ rv = 0; /* not ok */
+
+ mutex_unlock(&mdev->data.mutex);
+
+ return rv;
+}
+
+int drbd_send_protocol(struct drbd_conf *mdev)
+{
+ struct p_protocol *p;
+ int size, rv;
+
+ size = sizeof(struct p_protocol);
+
+ if (mdev->agreed_pro_version >= 87)
+ size += strlen(mdev->net_conf->integrity_alg) + 1;
+
+ /* we must not recurse into our own queue,
+ * as that is blocked during handshake */
+ p = kmalloc(size, GFP_NOIO);
+ if (p == NULL)
+ return 0;
+
+ p->protocol = cpu_to_be32(mdev->net_conf->wire_protocol);
+ p->after_sb_0p = cpu_to_be32(mdev->net_conf->after_sb_0p);
+ p->after_sb_1p = cpu_to_be32(mdev->net_conf->after_sb_1p);
+ p->after_sb_2p = cpu_to_be32(mdev->net_conf->after_sb_2p);
+ p->want_lose = cpu_to_be32(mdev->net_conf->want_lose);
+ p->two_primaries = cpu_to_be32(mdev->net_conf->two_primaries);
+
+ if (mdev->agreed_pro_version >= 87)
+ strcpy(p->integrity_alg, mdev->net_conf->integrity_alg);
+
+ rv = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_PROTOCOL,
+ (struct p_header *)p, size);
+ kfree(p);
+ return rv;
+}
+
+int _drbd_send_uuids(struct drbd_conf *mdev, u64 uuid_flags)
+{
+ struct p_uuids p;
+ int i;
+
+ if (!get_ldev_if_state(mdev, D_NEGOTIATING))
+ return 1;
+
+ for (i = UI_CURRENT; i < UI_SIZE; i++)
+ p.uuid[i] = mdev->ldev ? cpu_to_be64(mdev->ldev->md.uuid[i]) : 0;
+
+ mdev->comm_bm_set = drbd_bm_total_weight(mdev);
+ p.uuid[UI_SIZE] = cpu_to_be64(mdev->comm_bm_set);
+ uuid_flags |= mdev->net_conf->want_lose ? 1 : 0;
+ uuid_flags |= test_bit(CRASHED_PRIMARY, &mdev->flags) ? 2 : 0;
+ uuid_flags |= mdev->new_state_tmp.disk == D_INCONSISTENT ? 4 : 0;
+ p.uuid[UI_FLAGS] = cpu_to_be64(uuid_flags);
+
+ put_ldev(mdev);
+
+ return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_UUIDS,
+ (struct p_header *)&p, sizeof(p));
+}
+
+int drbd_send_uuids(struct drbd_conf *mdev)
+{
+ return _drbd_send_uuids(mdev, 0);
+}
+
+int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev)
+{
+ return _drbd_send_uuids(mdev, 8);
+}
+
+
+int drbd_send_sync_uuid(struct drbd_conf *mdev, u64 val)
+{
+ struct p_rs_uuid p;
+
+ p.uuid = cpu_to_be64(val);
+
+ return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_SYNC_UUID,
+ (struct p_header *)&p, sizeof(p));
+}
+
+int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply)
+{
+ struct p_sizes p;
+ sector_t d_size, u_size;
+ int q_order_type;
+ int ok;
+
+ if (get_ldev_if_state(mdev, D_NEGOTIATING)) {
+ D_ASSERT(mdev->ldev->backing_bdev);
+ d_size = drbd_get_max_capacity(mdev->ldev);
+ u_size = mdev->ldev->dc.disk_size;
+ q_order_type = drbd_queue_order_type(mdev);
+ p.queue_order_type = cpu_to_be32(drbd_queue_order_type(mdev));
+ put_ldev(mdev);
+ } else {
+ d_size = 0;
+ u_size = 0;
+ q_order_type = QUEUE_ORDERED_NONE;
+ }
+
+ p.d_size = cpu_to_be64(d_size);
+ p.u_size = cpu_to_be64(u_size);
+ p.c_size = cpu_to_be64(trigger_reply ? 0 : drbd_get_capacity(mdev->this_bdev));
+ p.max_segment_size = cpu_to_be32(queue_max_segment_size(mdev->rq_queue));
+ p.queue_order_type = cpu_to_be32(q_order_type);
+
+ ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_SIZES,
+ (struct p_header *)&p, sizeof(p));
+ return ok;
+}
+
+/**
+ * drbd_send_state() - Sends the drbd state to the peer
+ * @mdev: DRBD device.
+ */
+int drbd_send_state(struct drbd_conf *mdev)
+{
+ struct socket *sock;
+ struct p_state p;
+ int ok = 0;
+
+ /* Grab state lock so we wont send state if we're in the middle
+ * of a cluster wide state change on another thread */
+ drbd_state_lock(mdev);
+
+ mutex_lock(&mdev->data.mutex);
+
+ p.state = cpu_to_be32(mdev->state.i); /* Within the send mutex */
+ sock = mdev->data.socket;
+
+ if (likely(sock != NULL)) {
+ ok = _drbd_send_cmd(mdev, sock, P_STATE,
+ (struct p_header *)&p, sizeof(p), 0);
+ }
+
+ mutex_unlock(&mdev->data.mutex);
+
+ drbd_state_unlock(mdev);
+ return ok;
+}
+
+int drbd_send_state_req(struct drbd_conf *mdev,
+ union drbd_state mask, union drbd_state val)
+{
+ struct p_req_state p;
+
+ p.mask = cpu_to_be32(mask.i);
+ p.val = cpu_to_be32(val.i);
+
+ return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_STATE_CHG_REQ,
+ (struct p_header *)&p, sizeof(p));
+}
+
+int drbd_send_sr_reply(struct drbd_conf *mdev, int retcode)
+{
+ struct p_req_state_reply p;
+
+ p.retcode = cpu_to_be32(retcode);
+
+ return drbd_send_cmd(mdev, USE_META_SOCKET, P_STATE_CHG_REPLY,
+ (struct p_header *)&p, sizeof(p));
+}
+
+int fill_bitmap_rle_bits(struct drbd_conf *mdev,
+ struct p_compressed_bm *p,
+ struct bm_xfer_ctx *c)
+{
+ struct bitstream bs;
+ unsigned long plain_bits;
+ unsigned long tmp;
+ unsigned long rl;
+ unsigned len;
+ unsigned toggle;
+ int bits;
+
+ /* may we use this feature? */
+ if ((mdev->sync_conf.use_rle == 0) ||
+ (mdev->agreed_pro_version < 90))
+ return 0;
+
+ if (c->bit_offset >= c->bm_bits)
+ return 0; /* nothing to do. */
+
+ /* use at most thus many bytes */
+ bitstream_init(&bs, p->code, BM_PACKET_VLI_BYTES_MAX, 0);
+ memset(p->code, 0, BM_PACKET_VLI_BYTES_MAX);
+ /* plain bits covered in this code string */
+ plain_bits = 0;
+
+ /* p->encoding & 0x80 stores whether the first run length is set.
+ * bit offset is implicit.
+ * start with toggle == 2 to be able to tell the first iteration */
+ toggle = 2;
+
+ /* see how much plain bits we can stuff into one packet
+ * using RLE and VLI. */
+ do {
+ tmp = (toggle == 0) ? _drbd_bm_find_next_zero(mdev, c->bit_offset)
+ : _drbd_bm_find_next(mdev, c->bit_offset);
+ if (tmp == -1UL)
+ tmp = c->bm_bits;
+ rl = tmp - c->bit_offset;
+
+ if (toggle == 2) { /* first iteration */
+ if (rl == 0) {
+ /* the first checked bit was set,
+ * store start value, */
+ DCBP_set_start(p, 1);
+ /* but skip encoding of zero run length */
+ toggle = !toggle;
+ continue;
+ }
+ DCBP_set_start(p, 0);
+ }
+
+ /* paranoia: catch zero runlength.
+ * can only happen if bitmap is modified while we scan it. */
+ if (rl == 0) {
+ dev_err(DEV, "unexpected zero runlength while encoding bitmap "
+ "t:%u bo:%lu\n", toggle, c->bit_offset);
+ return -1;
+ }
+
+ bits = vli_encode_bits(&bs, rl);
+ if (bits == -ENOBUFS) /* buffer full */
+ break;
+ if (bits <= 0) {
+ dev_err(DEV, "error while encoding bitmap: %d\n", bits);
+ return 0;
+ }
+
+ toggle = !toggle;
+ plain_bits += rl;
+ c->bit_offset = tmp;
+ } while (c->bit_offset < c->bm_bits);
+
+ len = bs.cur.b - p->code + !!bs.cur.bit;
+
+ if (plain_bits < (len << 3)) {
+ /* incompressible with this method.
+ * we need to rewind both word and bit position. */
+ c->bit_offset -= plain_bits;
+ bm_xfer_ctx_bit_to_word_offset(c);
+ c->bit_offset = c->word_offset * BITS_PER_LONG;
+ return 0;
+ }
+
+ /* RLE + VLI was able to compress it just fine.
+ * update c->word_offset. */
+ bm_xfer_ctx_bit_to_word_offset(c);
+
+ /* store pad_bits */
+ DCBP_set_pad_bits(p, (8 - bs.cur.bit) & 0x7);
+
+ return len;
+}
+
+enum { OK, FAILED, DONE }
+send_bitmap_rle_or_plain(struct drbd_conf *mdev,
+ struct p_header *h, struct bm_xfer_ctx *c)
+{
+ struct p_compressed_bm *p = (void*)h;
+ unsigned long num_words;
+ int len;
+ int ok;
+
+ len = fill_bitmap_rle_bits(mdev, p, c);
+
+ if (len < 0)
+ return FAILED;
+
+ if (len) {
+ DCBP_set_code(p, RLE_VLI_Bits);
+ ok = _drbd_send_cmd(mdev, mdev->data.socket, P_COMPRESSED_BITMAP, h,
+ sizeof(*p) + len, 0);
+
+ c->packets[0]++;
+ c->bytes[0] += sizeof(*p) + len;
+
+ if (c->bit_offset >= c->bm_bits)
+ len = 0; /* DONE */
+ } else {
+ /* was not compressible.
+ * send a buffer full of plain text bits instead. */
+ num_words = min_t(size_t, BM_PACKET_WORDS, c->bm_words - c->word_offset);
+ len = num_words * sizeof(long);
+ if (len)
+ drbd_bm_get_lel(mdev, c->word_offset, num_words, (unsigned long*)h->payload);
+ ok = _drbd_send_cmd(mdev, mdev->data.socket, P_BITMAP,
+ h, sizeof(struct p_header) + len, 0);
+ c->word_offset += num_words;
+ c->bit_offset = c->word_offset * BITS_PER_LONG;
+
+ c->packets[1]++;
+ c->bytes[1] += sizeof(struct p_header) + len;
+
+ if (c->bit_offset > c->bm_bits)
+ c->bit_offset = c->bm_bits;
+ }
+ ok = ok ? ((len == 0) ? DONE : OK) : FAILED;
+
+ if (ok == DONE)
+ INFO_bm_xfer_stats(mdev, "send", c);
+ return ok;
+}
+
+/* See the comment at receive_bitmap() */
+int _drbd_send_bitmap(struct drbd_conf *mdev)
+{
+ struct bm_xfer_ctx c;
+ struct p_header *p;
+ int ret;
+
+ ERR_IF(!mdev->bitmap) return FALSE;
+
+ /* maybe we should use some per thread scratch page,
+ * and allocate that during initial device creation? */
+ p = (struct p_header *) __get_free_page(GFP_NOIO);
+ if (!p) {
+ dev_err(DEV, "failed to allocate one page buffer in %s\n", __func__);
+ return FALSE;
+ }
+
+ if (get_ldev(mdev)) {
+ if (drbd_md_test_flag(mdev->ldev, MDF_FULL_SYNC)) {
+ dev_info(DEV, "Writing the whole bitmap, MDF_FullSync was set.\n");
+ drbd_bm_set_all(mdev);
+ if (drbd_bm_write(mdev)) {
+ /* write_bm did fail! Leave full sync flag set in Meta P_DATA
+ * but otherwise process as per normal - need to tell other
+ * side that a full resync is required! */
+ dev_err(DEV, "Failed to write bitmap to disk!\n");
+ } else {
+ drbd_md_clear_flag(mdev, MDF_FULL_SYNC);
+ drbd_md_sync(mdev);
+ }
+ }
+ put_ldev(mdev);
+ }
+
+ c = (struct bm_xfer_ctx) {
+ .bm_bits = drbd_bm_bits(mdev),
+ .bm_words = drbd_bm_words(mdev),
+ };
+
+ do {
+ ret = send_bitmap_rle_or_plain(mdev, p, &c);
+ } while (ret == OK);
+
+ free_page((unsigned long) p);
+ return (ret == DONE);
+}
+
+int drbd_send_bitmap(struct drbd_conf *mdev)
+{
+ int err;
+
+ if (!drbd_get_data_sock(mdev))
+ return -1;
+ err = !_drbd_send_bitmap(mdev);
+ drbd_put_data_sock(mdev);
+ return err;
+}
+
+int drbd_send_b_ack(struct drbd_conf *mdev, u32 barrier_nr, u32 set_size)
+{
+ int ok;
+ struct p_barrier_ack p;
+
+ p.barrier = barrier_nr;
+ p.set_size = cpu_to_be32(set_size);
+
+ if (mdev->state.conn < C_CONNECTED)
+ return FALSE;
+ ok = drbd_send_cmd(mdev, USE_META_SOCKET, P_BARRIER_ACK,
+ (struct p_header *)&p, sizeof(p));
+ return ok;
+}
+
+/**
+ * _drbd_send_ack() - Sends an ack packet
+ * @mdev: DRBD device.
+ * @cmd: Packet command code.
+ * @sector: sector, needs to be in big endian byte order
+ * @blksize: size in byte, needs to be in big endian byte order
+ * @block_id: Id, big endian byte order
+ */
+static int _drbd_send_ack(struct drbd_conf *mdev, enum drbd_packets cmd,
+ u64 sector,
+ u32 blksize,
+ u64 block_id)
+{
+ int ok;
+ struct p_block_ack p;
+
+ p.sector = sector;
+ p.block_id = block_id;
+ p.blksize = blksize;
+ p.seq_num = cpu_to_be32(atomic_add_return(1, &mdev->packet_seq));
+
+ if (!mdev->meta.socket || mdev->state.conn < C_CONNECTED)
+ return FALSE;
+ ok = drbd_send_cmd(mdev, USE_META_SOCKET, cmd,
+ (struct p_header *)&p, sizeof(p));
+ return ok;
+}
+
+int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packets cmd,
+ struct p_data *dp)
+{
+ const int header_size = sizeof(struct p_data)
+ - sizeof(struct p_header);
+ int data_size = ((struct p_header *)dp)->length - header_size;
+
+ return _drbd_send_ack(mdev, cmd, dp->sector, cpu_to_be32(data_size),
+ dp->block_id);
+}
+
+int drbd_send_ack_rp(struct drbd_conf *mdev, enum drbd_packets cmd,
+ struct p_block_req *rp)
+{
+ return _drbd_send_ack(mdev, cmd, rp->sector, rp->blksize, rp->block_id);
+}
+
+/**
+ * drbd_send_ack() - Sends an ack packet
+ * @mdev: DRBD device.
+ * @cmd: Packet command code.
+ * @e: Epoch entry.
+ */
+int drbd_send_ack(struct drbd_conf *mdev,
+ enum drbd_packets cmd, struct drbd_epoch_entry *e)
+{
+ return _drbd_send_ack(mdev, cmd,
+ cpu_to_be64(e->sector),
+ cpu_to_be32(e->size),
+ e->block_id);
+}
+
+/* This function misuses the block_id field to signal if the blocks
+ * are is sync or not. */
+int drbd_send_ack_ex(struct drbd_conf *mdev, enum drbd_packets cmd,
+ sector_t sector, int blksize, u64 block_id)
+{
+ return _drbd_send_ack(mdev, cmd,
+ cpu_to_be64(sector),
+ cpu_to_be32(blksize),
+ cpu_to_be64(block_id));
+}
+
+int drbd_send_drequest(struct drbd_conf *mdev, int cmd,
+ sector_t sector, int size, u64 block_id)
+{
+ int ok;
+ struct p_block_req p;
+
+ p.sector = cpu_to_be64(sector);
+ p.block_id = block_id;
+ p.blksize = cpu_to_be32(size);
+
+ ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, cmd,
+ (struct p_header *)&p, sizeof(p));
+ return ok;
+}
+
+int drbd_send_drequest_csum(struct drbd_conf *mdev,
+ sector_t sector, int size,
+ void *digest, int digest_size,
+ enum drbd_packets cmd)
+{
+ int ok;
+ struct p_block_req p;
+
+ p.sector = cpu_to_be64(sector);
+ p.block_id = BE_DRBD_MAGIC + 0xbeef;
+ p.blksize = cpu_to_be32(size);
+
+ p.head.magic = BE_DRBD_MAGIC;
+ p.head.command = cpu_to_be16(cmd);
+ p.head.length = cpu_to_be16(sizeof(p) - sizeof(struct p_header) + digest_size);
+
+ mutex_lock(&mdev->data.mutex);
+
+ ok = (sizeof(p) == drbd_send(mdev, mdev->data.socket, &p, sizeof(p), 0));
+ ok = ok && (digest_size == drbd_send(mdev, mdev->data.socket, digest, digest_size, 0));
+
+ mutex_unlock(&mdev->data.mutex);
+
+ return ok;
+}
+
+int drbd_send_ov_request(struct drbd_conf *mdev, sector_t sector, int size)
+{
+ int ok;
+ struct p_block_req p;
+
+ p.sector = cpu_to_be64(sector);
+ p.block_id = BE_DRBD_MAGIC + 0xbabe;
+ p.blksize = cpu_to_be32(size);
+
+ ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_OV_REQUEST,
+ (struct p_header *)&p, sizeof(p));
+ return ok;
+}
+
+/* called on sndtimeo
+ * returns FALSE if we should retry,
+ * TRUE if we think connection is dead
+ */
+static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket *sock)
+{
+ int drop_it;
+ /* long elapsed = (long)(jiffies - mdev->last_received); */
+
+ drop_it = mdev->meta.socket == sock
+ || !mdev->asender.task
+ || get_t_state(&mdev->asender) != Running
+ || mdev->state.conn < C_CONNECTED;
+
+ if (drop_it)
+ return TRUE;
+
+ drop_it = !--mdev->ko_count;
+ if (!drop_it) {
+ dev_err(DEV, "[%s/%d] sock_sendmsg time expired, ko = %u\n",
+ current->comm, current->pid, mdev->ko_count);
+ request_ping(mdev);
+ }
+
+ return drop_it; /* && (mdev->state == R_PRIMARY) */;
+}
+
+/* The idea of sendpage seems to be to put some kind of reference
+ * to the page into the skb, and to hand it over to the NIC. In
+ * this process get_page() gets called.
+ *
+ * As soon as the page was really sent over the network put_page()
+ * gets called by some part of the network layer. [ NIC driver? ]
+ *
+ * [ get_page() / put_page() increment/decrement the count. If count
+ * reaches 0 the page will be freed. ]
+ *
+ * This works nicely with pages from FSs.
+ * But this means that in protocol A we might signal IO completion too early!
+ *
+ * In order not to corrupt data during a resync we must make sure
+ * that we do not reuse our own buffer pages (EEs) to early, therefore
+ * we have the net_ee list.
+ *
+ * XFS seems to have problems, still, it submits pages with page_count == 0!
+ * As a workaround, we disable sendpage on pages
+ * with page_count == 0 or PageSlab.
+ */
+static int _drbd_no_send_page(struct drbd_conf *mdev, struct page *page,
+ int offset, size_t size)
+{
+ int sent = drbd_send(mdev, mdev->data.socket, kmap(page) + offset, size, 0);
+ kunmap(page);
+ if (sent == size)
+ mdev->send_cnt += size>>9;
+ return sent == size;
+}
+
+static int _drbd_send_page(struct drbd_conf *mdev, struct page *page,
+ int offset, size_t size)
+{
+ mm_segment_t oldfs = get_fs();
+ int sent, ok;
+ int len = size;
+
+ /* e.g. XFS meta- & log-data is in slab pages, which have a
+ * page_count of 0 and/or have PageSlab() set.
+ * we cannot use send_page for those, as that does get_page();
+ * put_page(); and would cause either a VM_BUG directly, or
+ * __page_cache_release a page that would actually still be referenced
+ * by someone, leading to some obscure delayed Oops somewhere else. */
+ if (disable_sendpage || (page_count(page) < 1) || PageSlab(page))
+ return _drbd_no_send_page(mdev, page, offset, size);
+
+ drbd_update_congested(mdev);
+ set_fs(KERNEL_DS);
+ do {
+ sent = mdev->data.socket->ops->sendpage(mdev->data.socket, page,
+ offset, len,
+ MSG_NOSIGNAL);
+ if (sent == -EAGAIN) {
+ if (we_should_drop_the_connection(mdev,
+ mdev->data.socket))
+ break;
+ else
+ continue;
+ }
+ if (sent <= 0) {
+ dev_warn(DEV, "%s: size=%d len=%d sent=%d\n",
+ __func__, (int)size, len, sent);
+ break;
+ }
+ len -= sent;
+ offset += sent;
+ } while (len > 0 /* THINK && mdev->cstate >= C_CONNECTED*/);
+ set_fs(oldfs);
+ clear_bit(NET_CONGESTED, &mdev->flags);
+
+ ok = (len == 0);
+ if (likely(ok))
+ mdev->send_cnt += size>>9;
+ return ok;
+}
+
+static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio)
+{
+ struct bio_vec *bvec;
+ int i;
+ __bio_for_each_segment(bvec, bio, i, 0) {
+ if (!_drbd_no_send_page(mdev, bvec->bv_page,
+ bvec->bv_offset, bvec->bv_len))
+ return 0;
+ }
+ return 1;
+}
+
+static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio)
+{
+ struct bio_vec *bvec;
+ int i;
+ __bio_for_each_segment(bvec, bio, i, 0) {
+ if (!_drbd_send_page(mdev, bvec->bv_page,
+ bvec->bv_offset, bvec->bv_len))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Used to send write requests
+ * R_PRIMARY -> Peer (P_DATA)
+ */
+int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req)
+{
+ int ok = 1;
+ struct p_data p;
+ unsigned int dp_flags = 0;
+ void *dgb;
+ int dgs;
+
+ if (!drbd_get_data_sock(mdev))
+ return 0;
+
+ dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_w_tfm) ?
+ crypto_hash_digestsize(mdev->integrity_w_tfm) : 0;
+
+ p.head.magic = BE_DRBD_MAGIC;
+ p.head.command = cpu_to_be16(P_DATA);
+ p.head.length =
+ cpu_to_be16(sizeof(p) - sizeof(struct p_header) + dgs + req->size);
+
+ p.sector = cpu_to_be64(req->sector);
+ p.block_id = (unsigned long)req;
+ p.seq_num = cpu_to_be32(req->seq_num =
+ atomic_add_return(1, &mdev->packet_seq));
+ dp_flags = 0;
+
+ /* NOTE: no need to check if barriers supported here as we would
+ * not pass the test in make_request_common in that case
+ */
+ if (bio_rw_flagged(req->master_bio, BIO_RW_BARRIER)) {
+ dev_err(DEV, "ASSERT FAILED would have set DP_HARDBARRIER\n");
+ /* dp_flags |= DP_HARDBARRIER; */
+ }
+ if (bio_rw_flagged(req->master_bio, BIO_RW_SYNCIO))
+ dp_flags |= DP_RW_SYNC;
+ /* for now handle SYNCIO and UNPLUG
+ * as if they still were one and the same flag */
+ if (bio_rw_flagged(req->master_bio, BIO_RW_UNPLUG))
+ dp_flags |= DP_RW_SYNC;
+ if (mdev->state.conn >= C_SYNC_SOURCE &&
+ mdev->state.conn <= C_PAUSED_SYNC_T)
+ dp_flags |= DP_MAY_SET_IN_SYNC;
+
+ p.dp_flags = cpu_to_be32(dp_flags);
+ set_bit(UNPLUG_REMOTE, &mdev->flags);
+ ok = (sizeof(p) ==
+ drbd_send(mdev, mdev->data.socket, &p, sizeof(p), MSG_MORE));
+ if (ok && dgs) {
+ dgb = mdev->int_dig_out;
+ drbd_csum(mdev, mdev->integrity_w_tfm, req->master_bio, dgb);
+ ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, MSG_MORE);
+ }
+ if (ok) {
+ if (mdev->net_conf->wire_protocol == DRBD_PROT_A)
+ ok = _drbd_send_bio(mdev, req->master_bio);
+ else
+ ok = _drbd_send_zc_bio(mdev, req->master_bio);
+ }
+
+ drbd_put_data_sock(mdev);
+ return ok;
+}
+
+/* answer packet, used to send data back for read requests:
+ * Peer -> (diskless) R_PRIMARY (P_DATA_REPLY)
+ * C_SYNC_SOURCE -> C_SYNC_TARGET (P_RS_DATA_REPLY)
+ */
+int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd,
+ struct drbd_epoch_entry *e)
+{
+ int ok;
+ struct p_data p;
+ void *dgb;
+ int dgs;
+
+ dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_w_tfm) ?
+ crypto_hash_digestsize(mdev->integrity_w_tfm) : 0;
+
+ p.head.magic = BE_DRBD_MAGIC;
+ p.head.command = cpu_to_be16(cmd);
+ p.head.length =
+ cpu_to_be16(sizeof(p) - sizeof(struct p_header) + dgs + e->size);
+
+ p.sector = cpu_to_be64(e->sector);
+ p.block_id = e->block_id;
+ /* p.seq_num = 0; No sequence numbers here.. */
+
+ /* Only called by our kernel thread.
+ * This one may be interrupted by DRBD_SIG and/or DRBD_SIGKILL
+ * in response to admin command or module unload.
+ */
+ if (!drbd_get_data_sock(mdev))
+ return 0;
+
+ ok = sizeof(p) == drbd_send(mdev, mdev->data.socket, &p,
+ sizeof(p), MSG_MORE);
+ if (ok && dgs) {
+ dgb = mdev->int_dig_out;
+ drbd_csum(mdev, mdev->integrity_w_tfm, e->private_bio, dgb);
+ ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, MSG_MORE);
+ }
+ if (ok)
+ ok = _drbd_send_zc_bio(mdev, e->private_bio);
+
+ drbd_put_data_sock(mdev);
+ return ok;
+}
+
+/*
+ drbd_send distinguishes two cases:
+
+ Packets sent via the data socket "sock"
+ and packets sent via the meta data socket "msock"
+
+ sock msock
+ -----------------+-------------------------+------------------------------
+ timeout conf.timeout / 2 conf.timeout / 2
+ timeout action send a ping via msock Abort communication
+ and close all sockets
+*/
+
+/*
+ * you must have down()ed the appropriate [m]sock_mutex elsewhere!
+ */
+int drbd_send(struct drbd_conf *mdev, struct socket *sock,
+ void *buf, size_t size, unsigned msg_flags)
+{
+ struct kvec iov;
+ struct msghdr msg;
+ int rv, sent = 0;
+
+ if (!sock)
+ return -1000;
+
+ /* THINK if (signal_pending) return ... ? */
+
+ iov.iov_base = buf;
+ iov.iov_len = size;
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = msg_flags | MSG_NOSIGNAL;
+
+ if (sock == mdev->data.socket) {
+ mdev->ko_count = mdev->net_conf->ko_count;
+ drbd_update_congested(mdev);
+ }
+ do {
+ /* STRANGE
+ * tcp_sendmsg does _not_ use its size parameter at all ?
+ *
+ * -EAGAIN on timeout, -EINTR on signal.
+ */
+/* THINK
+ * do we need to block DRBD_SIG if sock == &meta.socket ??
+ * otherwise wake_asender() might interrupt some send_*Ack !
+ */
+ rv = kernel_sendmsg(sock, &msg, &iov, 1, size);
+ if (rv == -EAGAIN) {
+ if (we_should_drop_the_connection(mdev, sock))
+ break;
+ else
+ continue;
+ }
+ D_ASSERT(rv != 0);
+ if (rv == -EINTR) {
+ flush_signals(current);
+ rv = 0;
+ }
+ if (rv < 0)
+ break;
+ sent += rv;
+ iov.iov_base += rv;
+ iov.iov_len -= rv;
+ } while (sent < size);
+
+ if (sock == mdev->data.socket)
+ clear_bit(NET_CONGESTED, &mdev->flags);
+
+ if (rv <= 0) {
+ if (rv != -EAGAIN) {
+ dev_err(DEV, "%s_sendmsg returned %d\n",
+ sock == mdev->meta.socket ? "msock" : "sock",
+ rv);
+ drbd_force_state(mdev, NS(conn, C_BROKEN_PIPE));
+ } else
+ drbd_force_state(mdev, NS(conn, C_TIMEOUT));
+ }
+
+ return sent;
+}
+
+static int drbd_open(struct block_device *bdev, fmode_t mode)
+{
+ struct drbd_conf *mdev = bdev->bd_disk->private_data;
+ unsigned long flags;
+ int rv = 0;
+
+ spin_lock_irqsave(&mdev->req_lock, flags);
+ /* to have a stable mdev->state.role
+ * and no race with updating open_cnt */
+
+ if (mdev->state.role != R_PRIMARY) {
+ if (mode & FMODE_WRITE)
+ rv = -EROFS;
+ else if (!allow_oos)
+ rv = -EMEDIUMTYPE;
+ }
+
+ if (!rv)
+ mdev->open_cnt++;
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+ return rv;
+}
+
+static int drbd_release(struct gendisk *gd, fmode_t mode)
+{
+ struct drbd_conf *mdev = gd->private_data;
+ mdev->open_cnt--;
+ return 0;
+}
+
+static void drbd_unplug_fn(struct request_queue *q)
+{
+ struct drbd_conf *mdev = q->queuedata;
+
+ /* unplug FIRST */
+ spin_lock_irq(q->queue_lock);
+ blk_remove_plug(q);
+ spin_unlock_irq(q->queue_lock);
+
+ /* only if connected */
+ spin_lock_irq(&mdev->req_lock);
+ if (mdev->state.pdsk >= D_INCONSISTENT && mdev->state.conn >= C_CONNECTED) {
+ D_ASSERT(mdev->state.role == R_PRIMARY);
+ if (test_and_clear_bit(UNPLUG_REMOTE, &mdev->flags)) {
+ /* add to the data.work queue,
+ * unless already queued.
+ * XXX this might be a good addition to drbd_queue_work
+ * anyways, to detect "double queuing" ... */
+ if (list_empty(&mdev->unplug_work.list))
+ drbd_queue_work(&mdev->data.work,
+ &mdev->unplug_work);
+ }
+ }
+ spin_unlock_irq(&mdev->req_lock);
+
+ if (mdev->state.disk >= D_INCONSISTENT)
+ drbd_kick_lo(mdev);
+}
+
+static void drbd_set_defaults(struct drbd_conf *mdev)
+{
+ mdev->sync_conf.after = DRBD_AFTER_DEF;
+ mdev->sync_conf.rate = DRBD_RATE_DEF;
+ mdev->sync_conf.al_extents = DRBD_AL_EXTENTS_DEF;
+ mdev->state = (union drbd_state) {
+ { .role = R_SECONDARY,
+ .peer = R_UNKNOWN,
+ .conn = C_STANDALONE,
+ .disk = D_DISKLESS,
+ .pdsk = D_UNKNOWN,
+ .susp = 0
+ } };
+}
+
+void drbd_init_set_defaults(struct drbd_conf *mdev)
+{
+ /* the memset(,0,) did most of this.
+ * note: only assignments, no allocation in here */
+
+ drbd_set_defaults(mdev);
+
+ /* for now, we do NOT yet support it,
+ * even though we start some framework
+ * to eventually support barriers */
+ set_bit(NO_BARRIER_SUPP, &mdev->flags);
+
+ atomic_set(&mdev->ap_bio_cnt, 0);
+ atomic_set(&mdev->ap_pending_cnt, 0);
+ atomic_set(&mdev->rs_pending_cnt, 0);
+ atomic_set(&mdev->unacked_cnt, 0);
+ atomic_set(&mdev->local_cnt, 0);
+ atomic_set(&mdev->net_cnt, 0);
+ atomic_set(&mdev->packet_seq, 0);
+ atomic_set(&mdev->pp_in_use, 0);
+
+ mutex_init(&mdev->md_io_mutex);
+ mutex_init(&mdev->data.mutex);
+ mutex_init(&mdev->meta.mutex);
+ sema_init(&mdev->data.work.s, 0);
+ sema_init(&mdev->meta.work.s, 0);
+ mutex_init(&mdev->state_mutex);
+
+ spin_lock_init(&mdev->data.work.q_lock);
+ spin_lock_init(&mdev->meta.work.q_lock);
+
+ spin_lock_init(&mdev->al_lock);
+ spin_lock_init(&mdev->req_lock);
+ spin_lock_init(&mdev->peer_seq_lock);
+ spin_lock_init(&mdev->epoch_lock);
+
+ INIT_LIST_HEAD(&mdev->active_ee);
+ INIT_LIST_HEAD(&mdev->sync_ee);
+ INIT_LIST_HEAD(&mdev->done_ee);
+ INIT_LIST_HEAD(&mdev->read_ee);
+ INIT_LIST_HEAD(&mdev->net_ee);
+ INIT_LIST_HEAD(&mdev->resync_reads);
+ INIT_LIST_HEAD(&mdev->data.work.q);
+ INIT_LIST_HEAD(&mdev->meta.work.q);
+ INIT_LIST_HEAD(&mdev->resync_work.list);
+ INIT_LIST_HEAD(&mdev->unplug_work.list);
+ INIT_LIST_HEAD(&mdev->md_sync_work.list);
+ INIT_LIST_HEAD(&mdev->bm_io_work.w.list);
+ mdev->resync_work.cb = w_resync_inactive;
+ mdev->unplug_work.cb = w_send_write_hint;
+ mdev->md_sync_work.cb = w_md_sync;
+ mdev->bm_io_work.w.cb = w_bitmap_io;
+ init_timer(&mdev->resync_timer);
+ init_timer(&mdev->md_sync_timer);
+ mdev->resync_timer.function = resync_timer_fn;
+ mdev->resync_timer.data = (unsigned long) mdev;
+ mdev->md_sync_timer.function = md_sync_timer_fn;
+ mdev->md_sync_timer.data = (unsigned long) mdev;
+
+ init_waitqueue_head(&mdev->misc_wait);
+ init_waitqueue_head(&mdev->state_wait);
+ init_waitqueue_head(&mdev->ee_wait);
+ init_waitqueue_head(&mdev->al_wait);
+ init_waitqueue_head(&mdev->seq_wait);
+
+ drbd_thread_init(mdev, &mdev->receiver, drbdd_init);
+ drbd_thread_init(mdev, &mdev->worker, drbd_worker);
+ drbd_thread_init(mdev, &mdev->asender, drbd_asender);
+
+ mdev->agreed_pro_version = PRO_VERSION_MAX;
+ mdev->write_ordering = WO_bio_barrier;
+ mdev->resync_wenr = LC_FREE;
+}
+
+void drbd_mdev_cleanup(struct drbd_conf *mdev)
+{
+ if (mdev->receiver.t_state != None)
+ dev_err(DEV, "ASSERT FAILED: receiver t_state == %d expected 0.\n",
+ mdev->receiver.t_state);
+
+ /* no need to lock it, I'm the only thread alive */
+ if (atomic_read(&mdev->current_epoch->epoch_size) != 0)
+ dev_err(DEV, "epoch_size:%d\n", atomic_read(&mdev->current_epoch->epoch_size));
+ mdev->al_writ_cnt =
+ mdev->bm_writ_cnt =
+ mdev->read_cnt =
+ mdev->recv_cnt =
+ mdev->send_cnt =
+ mdev->writ_cnt =
+ mdev->p_size =
+ mdev->rs_start =
+ mdev->rs_total =
+ mdev->rs_failed =
+ mdev->rs_mark_left =
+ mdev->rs_mark_time = 0;
+ D_ASSERT(mdev->net_conf == NULL);
+
+ drbd_set_my_capacity(mdev, 0);
+ if (mdev->bitmap) {
+ /* maybe never allocated. */
+ drbd_bm_resize(mdev, 0);
+ drbd_bm_cleanup(mdev);
+ }
+
+ drbd_free_resources(mdev);
+
+ /*
+ * currently we drbd_init_ee only on module load, so
+ * we may do drbd_release_ee only on module unload!
+ */
+ D_ASSERT(list_empty(&mdev->active_ee));
+ D_ASSERT(list_empty(&mdev->sync_ee));
+ D_ASSERT(list_empty(&mdev->done_ee));
+ D_ASSERT(list_empty(&mdev->read_ee));
+ D_ASSERT(list_empty(&mdev->net_ee));
+ D_ASSERT(list_empty(&mdev->resync_reads));
+ D_ASSERT(list_empty(&mdev->data.work.q));
+ D_ASSERT(list_empty(&mdev->meta.work.q));
+ D_ASSERT(list_empty(&mdev->resync_work.list));
+ D_ASSERT(list_empty(&mdev->unplug_work.list));
+
+}
+
+
+static void drbd_destroy_mempools(void)
+{
+ struct page *page;
+
+ while (drbd_pp_pool) {
+ page = drbd_pp_pool;
+ drbd_pp_pool = (struct page *)page_private(page);
+ __free_page(page);
+ drbd_pp_vacant--;
+ }
+
+ /* D_ASSERT(atomic_read(&drbd_pp_vacant)==0); */
+
+ if (drbd_ee_mempool)
+ mempool_destroy(drbd_ee_mempool);
+ if (drbd_request_mempool)
+ mempool_destroy(drbd_request_mempool);
+ if (drbd_ee_cache)
+ kmem_cache_destroy(drbd_ee_cache);
+ if (drbd_request_cache)
+ kmem_cache_destroy(drbd_request_cache);
+ if (drbd_bm_ext_cache)
+ kmem_cache_destroy(drbd_bm_ext_cache);
+ if (drbd_al_ext_cache)
+ kmem_cache_destroy(drbd_al_ext_cache);
+
+ drbd_ee_mempool = NULL;
+ drbd_request_mempool = NULL;
+ drbd_ee_cache = NULL;
+ drbd_request_cache = NULL;
+ drbd_bm_ext_cache = NULL;
+ drbd_al_ext_cache = NULL;
+
+ return;
+}
+
+static int drbd_create_mempools(void)
+{
+ struct page *page;
+ const int number = (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE) * minor_count;
+ int i;
+
+ /* prepare our caches and mempools */
+ drbd_request_mempool = NULL;
+ drbd_ee_cache = NULL;
+ drbd_request_cache = NULL;
+ drbd_bm_ext_cache = NULL;
+ drbd_al_ext_cache = NULL;
+ drbd_pp_pool = NULL;
+
+ /* caches */
+ drbd_request_cache = kmem_cache_create(
+ "drbd_req", sizeof(struct drbd_request), 0, 0, NULL);
+ if (drbd_request_cache == NULL)
+ goto Enomem;
+
+ drbd_ee_cache = kmem_cache_create(
+ "drbd_ee", sizeof(struct drbd_epoch_entry), 0, 0, NULL);
+ if (drbd_ee_cache == NULL)
+ goto Enomem;
+
+ drbd_bm_ext_cache = kmem_cache_create(
+ "drbd_bm", sizeof(struct bm_extent), 0, 0, NULL);
+ if (drbd_bm_ext_cache == NULL)
+ goto Enomem;
+
+ drbd_al_ext_cache = kmem_cache_create(
+ "drbd_al", sizeof(struct lc_element), 0, 0, NULL);
+ if (drbd_al_ext_cache == NULL)
+ goto Enomem;
+
+ /* mempools */
+ drbd_request_mempool = mempool_create(number,
+ mempool_alloc_slab, mempool_free_slab, drbd_request_cache);
+ if (drbd_request_mempool == NULL)
+ goto Enomem;
+
+ drbd_ee_mempool = mempool_create(number,
+ mempool_alloc_slab, mempool_free_slab, drbd_ee_cache);
+ if (drbd_request_mempool == NULL)
+ goto Enomem;
+
+ /* drbd's page pool */
+ spin_lock_init(&drbd_pp_lock);
+
+ for (i = 0; i < number; i++) {
+ page = alloc_page(GFP_HIGHUSER);
+ if (!page)
+ goto Enomem;
+ set_page_private(page, (unsigned long)drbd_pp_pool);
+ drbd_pp_pool = page;
+ }
+ drbd_pp_vacant = number;
+
+ return 0;
+
+Enomem:
+ drbd_destroy_mempools(); /* in case we allocated some */
+ return -ENOMEM;
+}
+
+static int drbd_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ /* just so we have it. you never know what interesting things we
+ * might want to do here some day...
+ */
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block drbd_notifier = {
+ .notifier_call = drbd_notify_sys,
+};
+
+static void drbd_release_ee_lists(struct drbd_conf *mdev)
+{
+ int rr;
+
+ rr = drbd_release_ee(mdev, &mdev->active_ee);
+ if (rr)
+ dev_err(DEV, "%d EEs in active list found!\n", rr);
+
+ rr = drbd_release_ee(mdev, &mdev->sync_ee);
+ if (rr)
+ dev_err(DEV, "%d EEs in sync list found!\n", rr);
+
+ rr = drbd_release_ee(mdev, &mdev->read_ee);
+ if (rr)
+ dev_err(DEV, "%d EEs in read list found!\n", rr);
+
+ rr = drbd_release_ee(mdev, &mdev->done_ee);
+ if (rr)
+ dev_err(DEV, "%d EEs in done list found!\n", rr);
+
+ rr = drbd_release_ee(mdev, &mdev->net_ee);
+ if (rr)
+ dev_err(DEV, "%d EEs in net list found!\n", rr);
+}
+
+/* caution. no locking.
+ * currently only used from module cleanup code. */
+static void drbd_delete_device(unsigned int minor)
+{
+ struct drbd_conf *mdev = minor_to_mdev(minor);
+
+ if (!mdev)
+ return;
+
+ /* paranoia asserts */
+ if (mdev->open_cnt != 0)
+ dev_err(DEV, "open_cnt = %d in %s:%u", mdev->open_cnt,
+ __FILE__ , __LINE__);
+
+ ERR_IF (!list_empty(&mdev->data.work.q)) {
+ struct list_head *lp;
+ list_for_each(lp, &mdev->data.work.q) {
+ dev_err(DEV, "lp = %p\n", lp);
+ }
+ };
+ /* end paranoia asserts */
+
+ del_gendisk(mdev->vdisk);
+
+ /* cleanup stuff that may have been allocated during
+ * device (re-)configuration or state changes */
+
+ if (mdev->this_bdev)
+ bdput(mdev->this_bdev);
+
+ drbd_free_resources(mdev);
+
+ drbd_release_ee_lists(mdev);
+
+ /* should be free'd on disconnect? */
+ kfree(mdev->ee_hash);
+ /*
+ mdev->ee_hash_s = 0;
+ mdev->ee_hash = NULL;
+ */
+
+ lc_destroy(mdev->act_log);
+ lc_destroy(mdev->resync);
+
+ kfree(mdev->p_uuid);
+ /* mdev->p_uuid = NULL; */
+
+ kfree(mdev->int_dig_out);
+ kfree(mdev->int_dig_in);
+ kfree(mdev->int_dig_vv);
+
+ /* cleanup the rest that has been
+ * allocated from drbd_new_device
+ * and actually free the mdev itself */
+ drbd_free_mdev(mdev);
+}
+
+static void drbd_cleanup(void)
+{
+ unsigned int i;
+
+ unregister_reboot_notifier(&drbd_notifier);
+
+ drbd_nl_cleanup();
+
+ if (minor_table) {
+ if (drbd_proc)
+ remove_proc_entry("drbd", NULL);
+ i = minor_count;
+ while (i--)
+ drbd_delete_device(i);
+ drbd_destroy_mempools();
+ }
+
+ kfree(minor_table);
+
+ unregister_blkdev(DRBD_MAJOR, "drbd");
+
+ printk(KERN_INFO "drbd: module cleanup done.\n");
+}
+
+/**
+ * drbd_congested() - Callback for pdflush
+ * @congested_data: User data
+ * @bdi_bits: Bits pdflush is currently interested in
+ *
+ * Returns 1<<BDI_async_congested and/or 1<<BDI_sync_congested if we are congested.
+ */
+static int drbd_congested(void *congested_data, int bdi_bits)
+{
+ struct drbd_conf *mdev = congested_data;
+ struct request_queue *q;
+ char reason = '-';
+ int r = 0;
+
+ if (!__inc_ap_bio_cond(mdev)) {
+ /* DRBD has frozen IO */
+ r = bdi_bits;
+ reason = 'd';
+ goto out;
+ }
+
+ if (get_ldev(mdev)) {
+ q = bdev_get_queue(mdev->ldev->backing_bdev);
+ r = bdi_congested(&q->backing_dev_info, bdi_bits);
+ put_ldev(mdev);
+ if (r)
+ reason = 'b';
+ }
+
+ if (bdi_bits & (1 << BDI_async_congested) && test_bit(NET_CONGESTED, &mdev->flags)) {
+ r |= (1 << BDI_async_congested);
+ reason = reason == 'b' ? 'a' : 'n';
+ }
+
+out:
+ mdev->congestion_reason = reason;
+ return r;
+}
+
+struct drbd_conf *drbd_new_device(unsigned int minor)
+{
+ struct drbd_conf *mdev;
+ struct gendisk *disk;
+ struct request_queue *q;
+
+ /* GFP_KERNEL, we are outside of all write-out paths */
+ mdev = kzalloc(sizeof(struct drbd_conf), GFP_KERNEL);
+ if (!mdev)
+ return NULL;
+ if (!zalloc_cpumask_var(&mdev->cpu_mask, GFP_KERNEL))
+ goto out_no_cpumask;
+
+ mdev->minor = minor;
+
+ drbd_init_set_defaults(mdev);
+
+ q = blk_alloc_queue(GFP_KERNEL);
+ if (!q)
+ goto out_no_q;
+ mdev->rq_queue = q;
+ q->queuedata = mdev;
+ blk_queue_max_segment_size(q, DRBD_MAX_SEGMENT_SIZE);
+
+ disk = alloc_disk(1);
+ if (!disk)
+ goto out_no_disk;
+ mdev->vdisk = disk;
+
+ set_disk_ro(disk, TRUE);
+
+ disk->queue = q;
+ disk->major = DRBD_MAJOR;
+ disk->first_minor = minor;
+ disk->fops = &drbd_ops;
+ sprintf(disk->disk_name, "drbd%d", minor);
+ disk->private_data = mdev;
+
+ mdev->this_bdev = bdget(MKDEV(DRBD_MAJOR, minor));
+ /* we have no partitions. we contain only ourselves. */
+ mdev->this_bdev->bd_contains = mdev->this_bdev;
+
+ q->backing_dev_info.congested_fn = drbd_congested;
+ q->backing_dev_info.congested_data = mdev;
+
+ blk_queue_make_request(q, drbd_make_request_26);
+ blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
+ blk_queue_merge_bvec(q, drbd_merge_bvec);
+ q->queue_lock = &mdev->req_lock; /* needed since we use */
+ /* plugging on a queue, that actually has no requests! */
+ q->unplug_fn = drbd_unplug_fn;
+
+ mdev->md_io_page = alloc_page(GFP_KERNEL);
+ if (!mdev->md_io_page)
+ goto out_no_io_page;
+
+ if (drbd_bm_init(mdev))
+ goto out_no_bitmap;
+ /* no need to lock access, we are still initializing this minor device. */
+ if (!tl_init(mdev))
+ goto out_no_tl;
+
+ mdev->app_reads_hash = kzalloc(APP_R_HSIZE*sizeof(void *), GFP_KERNEL);
+ if (!mdev->app_reads_hash)
+ goto out_no_app_reads;
+
+ mdev->current_epoch = kzalloc(sizeof(struct drbd_epoch), GFP_KERNEL);
+ if (!mdev->current_epoch)
+ goto out_no_epoch;
+
+ INIT_LIST_HEAD(&mdev->current_epoch->list);
+ mdev->epochs = 1;
+
+ return mdev;
+
+/* out_whatever_else:
+ kfree(mdev->current_epoch); */
+out_no_epoch:
+ kfree(mdev->app_reads_hash);
+out_no_app_reads:
+ tl_cleanup(mdev);
+out_no_tl:
+ drbd_bm_cleanup(mdev);
+out_no_bitmap:
+ __free_page(mdev->md_io_page);
+out_no_io_page:
+ put_disk(disk);
+out_no_disk:
+ blk_cleanup_queue(q);
+out_no_q:
+ free_cpumask_var(mdev->cpu_mask);
+out_no_cpumask:
+ kfree(mdev);
+ return NULL;
+}
+
+/* counterpart of drbd_new_device.
+ * last part of drbd_delete_device. */
+void drbd_free_mdev(struct drbd_conf *mdev)
+{
+ kfree(mdev->current_epoch);
+ kfree(mdev->app_reads_hash);
+ tl_cleanup(mdev);
+ if (mdev->bitmap) /* should no longer be there. */
+ drbd_bm_cleanup(mdev);
+ __free_page(mdev->md_io_page);
+ put_disk(mdev->vdisk);
+ blk_cleanup_queue(mdev->rq_queue);
+ free_cpumask_var(mdev->cpu_mask);
+ kfree(mdev);
+}
+
+
+int __init drbd_init(void)
+{
+ int err;
+
+ if (sizeof(struct p_handshake) != 80) {
+ printk(KERN_ERR
+ "drbd: never change the size or layout "
+ "of the HandShake packet.\n");
+ return -EINVAL;
+ }
+
+ if (1 > minor_count || minor_count > 255) {
+ printk(KERN_ERR
+ "drbd: invalid minor_count (%d)\n", minor_count);
+#ifdef MODULE
+ return -EINVAL;
+#else
+ minor_count = 8;
+#endif
+ }
+
+ err = drbd_nl_init();
+ if (err)
+ return err;
+
+ err = register_blkdev(DRBD_MAJOR, "drbd");
+ if (err) {
+ printk(KERN_ERR
+ "drbd: unable to register block device major %d\n",
+ DRBD_MAJOR);
+ return err;
+ }
+
+ register_reboot_notifier(&drbd_notifier);
+
+ /*
+ * allocate all necessary structs
+ */
+ err = -ENOMEM;
+
+ init_waitqueue_head(&drbd_pp_wait);
+
+ drbd_proc = NULL; /* play safe for drbd_cleanup */
+ minor_table = kzalloc(sizeof(struct drbd_conf *)*minor_count,
+ GFP_KERNEL);
+ if (!minor_table)
+ goto Enomem;
+
+ err = drbd_create_mempools();
+ if (err)
+ goto Enomem;
+
+ drbd_proc = proc_create("drbd", S_IFREG | S_IRUGO , NULL, &drbd_proc_fops);
+ if (!drbd_proc) {
+ printk(KERN_ERR "drbd: unable to register proc file\n");
+ goto Enomem;
+ }
+
+ rwlock_init(&global_state_lock);
+
+ printk(KERN_INFO "drbd: initialized. "
+ "Version: " REL_VERSION " (api:%d/proto:%d-%d)\n",
+ API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX);
+ printk(KERN_INFO "drbd: %s\n", drbd_buildtag());
+ printk(KERN_INFO "drbd: registered as block device major %d\n",
+ DRBD_MAJOR);
+ printk(KERN_INFO "drbd: minor_table @ 0x%p\n", minor_table);
+
+ return 0; /* Success! */
+
+Enomem:
+ drbd_cleanup();
+ if (err == -ENOMEM)
+ /* currently always the case */
+ printk(KERN_ERR "drbd: ran out of memory\n");
+ else
+ printk(KERN_ERR "drbd: initialization failure\n");
+ return err;
+}
+
+void drbd_free_bc(struct drbd_backing_dev *ldev)
+{
+ if (ldev == NULL)
+ return;
+
+ bd_release(ldev->backing_bdev);
+ bd_release(ldev->md_bdev);
+
+ fput(ldev->lo_file);
+ fput(ldev->md_file);
+
+ kfree(ldev);
+}
+
+void drbd_free_sock(struct drbd_conf *mdev)
+{
+ if (mdev->data.socket) {
+ kernel_sock_shutdown(mdev->data.socket, SHUT_RDWR);
+ sock_release(mdev->data.socket);
+ mdev->data.socket = NULL;
+ }
+ if (mdev->meta.socket) {
+ kernel_sock_shutdown(mdev->meta.socket, SHUT_RDWR);
+ sock_release(mdev->meta.socket);
+ mdev->meta.socket = NULL;
+ }
+}
+
+
+void drbd_free_resources(struct drbd_conf *mdev)
+{
+ crypto_free_hash(mdev->csums_tfm);
+ mdev->csums_tfm = NULL;
+ crypto_free_hash(mdev->verify_tfm);
+ mdev->verify_tfm = NULL;
+ crypto_free_hash(mdev->cram_hmac_tfm);
+ mdev->cram_hmac_tfm = NULL;
+ crypto_free_hash(mdev->integrity_w_tfm);
+ mdev->integrity_w_tfm = NULL;
+ crypto_free_hash(mdev->integrity_r_tfm);
+ mdev->integrity_r_tfm = NULL;
+
+ drbd_free_sock(mdev);
+
+ __no_warn(local,
+ drbd_free_bc(mdev->ldev);
+ mdev->ldev = NULL;);
+}
+
+/* meta data management */
+
+struct meta_data_on_disk {
+ u64 la_size; /* last agreed size. */
+ u64 uuid[UI_SIZE]; /* UUIDs. */
+ u64 device_uuid;
+ u64 reserved_u64_1;
+ u32 flags; /* MDF */
+ u32 magic;
+ u32 md_size_sect;
+ u32 al_offset; /* offset to this block */
+ u32 al_nr_extents; /* important for restoring the AL */
+ /* `-- act_log->nr_elements <-- sync_conf.al_extents */
+ u32 bm_offset; /* offset to the bitmap, from here */
+ u32 bm_bytes_per_bit; /* BM_BLOCK_SIZE */
+ u32 reserved_u32[4];
+
+} __packed;
+
+/**
+ * drbd_md_sync() - Writes the meta data super block if the MD_DIRTY flag bit is set
+ * @mdev: DRBD device.
+ */
+void drbd_md_sync(struct drbd_conf *mdev)
+{
+ struct meta_data_on_disk *buffer;
+ sector_t sector;
+ int i;
+
+ if (!test_and_clear_bit(MD_DIRTY, &mdev->flags))
+ return;
+ del_timer(&mdev->md_sync_timer);
+
+ /* We use here D_FAILED and not D_ATTACHING because we try to write
+ * metadata even if we detach due to a disk failure! */
+ if (!get_ldev_if_state(mdev, D_FAILED))
+ return;
+
+ mutex_lock(&mdev->md_io_mutex);
+ buffer = (struct meta_data_on_disk *)page_address(mdev->md_io_page);
+ memset(buffer, 0, 512);
+
+ buffer->la_size = cpu_to_be64(drbd_get_capacity(mdev->this_bdev));
+ for (i = UI_CURRENT; i < UI_SIZE; i++)
+ buffer->uuid[i] = cpu_to_be64(mdev->ldev->md.uuid[i]);
+ buffer->flags = cpu_to_be32(mdev->ldev->md.flags);
+ buffer->magic = cpu_to_be32(DRBD_MD_MAGIC);
+
+ buffer->md_size_sect = cpu_to_be32(mdev->ldev->md.md_size_sect);
+ buffer->al_offset = cpu_to_be32(mdev->ldev->md.al_offset);
+ buffer->al_nr_extents = cpu_to_be32(mdev->act_log->nr_elements);
+ buffer->bm_bytes_per_bit = cpu_to_be32(BM_BLOCK_SIZE);
+ buffer->device_uuid = cpu_to_be64(mdev->ldev->md.device_uuid);
+
+ buffer->bm_offset = cpu_to_be32(mdev->ldev->md.bm_offset);
+
+ D_ASSERT(drbd_md_ss__(mdev, mdev->ldev) == mdev->ldev->md.md_offset);
+ sector = mdev->ldev->md.md_offset;
+
+ if (drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) {
+ clear_bit(MD_DIRTY, &mdev->flags);
+ } else {
+ /* this was a try anyways ... */
+ dev_err(DEV, "meta data update failed!\n");
+
+ drbd_chk_io_error(mdev, 1, TRUE);
+ }
+
+ /* Update mdev->ldev->md.la_size_sect,
+ * since we updated it on metadata. */
+ mdev->ldev->md.la_size_sect = drbd_get_capacity(mdev->this_bdev);
+
+ mutex_unlock(&mdev->md_io_mutex);
+ put_ldev(mdev);
+}
+
+/**
+ * drbd_md_read() - Reads in the meta data super block
+ * @mdev: DRBD device.
+ * @bdev: Device from which the meta data should be read in.
+ *
+ * Return 0 (NO_ERROR) on success, and an enum drbd_ret_codes in case
+ * something goes wrong. Currently only: ERR_IO_MD_DISK, ERR_MD_INVALID.
+ */
+int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
+{
+ struct meta_data_on_disk *buffer;
+ int i, rv = NO_ERROR;
+
+ if (!get_ldev_if_state(mdev, D_ATTACHING))
+ return ERR_IO_MD_DISK;
+
+ mutex_lock(&mdev->md_io_mutex);
+ buffer = (struct meta_data_on_disk *)page_address(mdev->md_io_page);
+
+ if (!drbd_md_sync_page_io(mdev, bdev, bdev->md.md_offset, READ)) {
+ /* NOTE: cant do normal error processing here as this is
+ called BEFORE disk is attached */
+ dev_err(DEV, "Error while reading metadata.\n");
+ rv = ERR_IO_MD_DISK;
+ goto err;
+ }
+
+ if (be32_to_cpu(buffer->magic) != DRBD_MD_MAGIC) {
+ dev_err(DEV, "Error while reading metadata, magic not found.\n");
+ rv = ERR_MD_INVALID;
+ goto err;
+ }
+ if (be32_to_cpu(buffer->al_offset) != bdev->md.al_offset) {
+ dev_err(DEV, "unexpected al_offset: %d (expected %d)\n",
+ be32_to_cpu(buffer->al_offset), bdev->md.al_offset);
+ rv = ERR_MD_INVALID;
+ goto err;
+ }
+ if (be32_to_cpu(buffer->bm_offset) != bdev->md.bm_offset) {
+ dev_err(DEV, "unexpected bm_offset: %d (expected %d)\n",
+ be32_to_cpu(buffer->bm_offset), bdev->md.bm_offset);
+ rv = ERR_MD_INVALID;
+ goto err;
+ }
+ if (be32_to_cpu(buffer->md_size_sect) != bdev->md.md_size_sect) {
+ dev_err(DEV, "unexpected md_size: %u (expected %u)\n",
+ be32_to_cpu(buffer->md_size_sect), bdev->md.md_size_sect);
+ rv = ERR_MD_INVALID;
+ goto err;
+ }
+
+ if (be32_to_cpu(buffer->bm_bytes_per_bit) != BM_BLOCK_SIZE) {
+ dev_err(DEV, "unexpected bm_bytes_per_bit: %u (expected %u)\n",
+ be32_to_cpu(buffer->bm_bytes_per_bit), BM_BLOCK_SIZE);
+ rv = ERR_MD_INVALID;
+ goto err;
+ }
+
+ bdev->md.la_size_sect = be64_to_cpu(buffer->la_size);
+ for (i = UI_CURRENT; i < UI_SIZE; i++)
+ bdev->md.uuid[i] = be64_to_cpu(buffer->uuid[i]);
+ bdev->md.flags = be32_to_cpu(buffer->flags);
+ mdev->sync_conf.al_extents = be32_to_cpu(buffer->al_nr_extents);
+ bdev->md.device_uuid = be64_to_cpu(buffer->device_uuid);
+
+ if (mdev->sync_conf.al_extents < 7)
+ mdev->sync_conf.al_extents = 127;
+
+ err:
+ mutex_unlock(&mdev->md_io_mutex);
+ put_ldev(mdev);
+
+ return rv;
+}
+
+/**
+ * drbd_md_mark_dirty() - Mark meta data super block as dirty
+ * @mdev: DRBD device.
+ *
+ * Call this function if you change anything that should be written to
+ * the meta-data super block. This function sets MD_DIRTY, and starts a
+ * timer that ensures that within five seconds you have to call drbd_md_sync().
+ */
+void drbd_md_mark_dirty(struct drbd_conf *mdev)
+{
+ set_bit(MD_DIRTY, &mdev->flags);
+ mod_timer(&mdev->md_sync_timer, jiffies + 5*HZ);
+}
+
+
+static void drbd_uuid_move_history(struct drbd_conf *mdev) __must_hold(local)
+{
+ int i;
+
+ for (i = UI_HISTORY_START; i < UI_HISTORY_END; i++)
+ mdev->ldev->md.uuid[i+1] = mdev->ldev->md.uuid[i];
+}
+
+void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local)
+{
+ if (idx == UI_CURRENT) {
+ if (mdev->state.role == R_PRIMARY)
+ val |= 1;
+ else
+ val &= ~((u64)1);
+
+ drbd_set_ed_uuid(mdev, val);
+ }
+
+ mdev->ldev->md.uuid[idx] = val;
+ drbd_md_mark_dirty(mdev);
+}
+
+
+void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local)
+{
+ if (mdev->ldev->md.uuid[idx]) {
+ drbd_uuid_move_history(mdev);
+ mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[idx];
+ }
+ _drbd_uuid_set(mdev, idx, val);
+}
+
+/**
+ * drbd_uuid_new_current() - Creates a new current UUID
+ * @mdev: DRBD device.
+ *
+ * Creates a new current UUID, and rotates the old current UUID into
+ * the bitmap slot. Causes an incremental resync upon next connect.
+ */
+void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local)
+{
+ u64 val;
+
+ dev_info(DEV, "Creating new current UUID\n");
+ D_ASSERT(mdev->ldev->md.uuid[UI_BITMAP] == 0);
+ mdev->ldev->md.uuid[UI_BITMAP] = mdev->ldev->md.uuid[UI_CURRENT];
+
+ get_random_bytes(&val, sizeof(u64));
+ _drbd_uuid_set(mdev, UI_CURRENT, val);
+}
+
+void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local)
+{
+ if (mdev->ldev->md.uuid[UI_BITMAP] == 0 && val == 0)
+ return;
+
+ if (val == 0) {
+ drbd_uuid_move_history(mdev);
+ mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[UI_BITMAP];
+ mdev->ldev->md.uuid[UI_BITMAP] = 0;
+ } else {
+ if (mdev->ldev->md.uuid[UI_BITMAP])
+ dev_warn(DEV, "bm UUID already set");
+
+ mdev->ldev->md.uuid[UI_BITMAP] = val;
+ mdev->ldev->md.uuid[UI_BITMAP] &= ~((u64)1);
+
+ }
+ drbd_md_mark_dirty(mdev);
+}
+
+/**
+ * drbd_bmio_set_n_write() - io_fn for drbd_queue_bitmap_io() or drbd_bitmap_io()
+ * @mdev: DRBD device.
+ *
+ * Sets all bits in the bitmap and writes the whole bitmap to stable storage.
+ */
+int drbd_bmio_set_n_write(struct drbd_conf *mdev)
+{
+ int rv = -EIO;
+
+ if (get_ldev_if_state(mdev, D_ATTACHING)) {
+ drbd_md_set_flag(mdev, MDF_FULL_SYNC);
+ drbd_md_sync(mdev);
+ drbd_bm_set_all(mdev);
+
+ rv = drbd_bm_write(mdev);
+
+ if (!rv) {
+ drbd_md_clear_flag(mdev, MDF_FULL_SYNC);
+ drbd_md_sync(mdev);
+ }
+
+ put_ldev(mdev);
+ }
+
+ return rv;
+}
+
+/**
+ * drbd_bmio_clear_n_write() - io_fn for drbd_queue_bitmap_io() or drbd_bitmap_io()
+ * @mdev: DRBD device.
+ *
+ * Clears all bits in the bitmap and writes the whole bitmap to stable storage.
+ */
+int drbd_bmio_clear_n_write(struct drbd_conf *mdev)
+{
+ int rv = -EIO;
+
+ if (get_ldev_if_state(mdev, D_ATTACHING)) {
+ drbd_bm_clear_all(mdev);
+ rv = drbd_bm_write(mdev);
+ put_ldev(mdev);
+ }
+
+ return rv;
+}
+
+static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused)
+{
+ struct bm_io_work *work = container_of(w, struct bm_io_work, w);
+ int rv;
+
+ D_ASSERT(atomic_read(&mdev->ap_bio_cnt) == 0);
+
+ drbd_bm_lock(mdev, work->why);
+ rv = work->io_fn(mdev);
+ drbd_bm_unlock(mdev);
+
+ clear_bit(BITMAP_IO, &mdev->flags);
+ wake_up(&mdev->misc_wait);
+
+ if (work->done)
+ work->done(mdev, rv);
+
+ clear_bit(BITMAP_IO_QUEUED, &mdev->flags);
+ work->why = NULL;
+
+ return 1;
+}
+
+/**
+ * drbd_queue_bitmap_io() - Queues an IO operation on the whole bitmap
+ * @mdev: DRBD device.
+ * @io_fn: IO callback to be called when bitmap IO is possible
+ * @done: callback to be called after the bitmap IO was performed
+ * @why: Descriptive text of the reason for doing the IO
+ *
+ * While IO on the bitmap happens we freeze application IO thus we ensure
+ * that drbd_set_out_of_sync() can not be called. This function MAY ONLY be
+ * called from worker context. It MUST NOT be used while a previous such
+ * work is still pending!
+ */
+void drbd_queue_bitmap_io(struct drbd_conf *mdev,
+ int (*io_fn)(struct drbd_conf *),
+ void (*done)(struct drbd_conf *, int),
+ char *why)
+{
+ D_ASSERT(current == mdev->worker.task);
+
+ D_ASSERT(!test_bit(BITMAP_IO_QUEUED, &mdev->flags));
+ D_ASSERT(!test_bit(BITMAP_IO, &mdev->flags));
+ D_ASSERT(list_empty(&mdev->bm_io_work.w.list));
+ if (mdev->bm_io_work.why)
+ dev_err(DEV, "FIXME going to queue '%s' but '%s' still pending?\n",
+ why, mdev->bm_io_work.why);
+
+ mdev->bm_io_work.io_fn = io_fn;
+ mdev->bm_io_work.done = done;
+ mdev->bm_io_work.why = why;
+
+ set_bit(BITMAP_IO, &mdev->flags);
+ if (atomic_read(&mdev->ap_bio_cnt) == 0) {
+ if (list_empty(&mdev->bm_io_work.w.list)) {
+ set_bit(BITMAP_IO_QUEUED, &mdev->flags);
+ drbd_queue_work(&mdev->data.work, &mdev->bm_io_work.w);
+ } else
+ dev_err(DEV, "FIXME avoided double queuing bm_io_work\n");
+ }
+}
+
+/**
+ * drbd_bitmap_io() - Does an IO operation on the whole bitmap
+ * @mdev: DRBD device.
+ * @io_fn: IO callback to be called when bitmap IO is possible
+ * @why: Descriptive text of the reason for doing the IO
+ *
+ * freezes application IO while that the actual IO operations runs. This
+ * functions MAY NOT be called from worker context.
+ */
+int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why)
+{
+ int rv;
+
+ D_ASSERT(current != mdev->worker.task);
+
+ drbd_suspend_io(mdev);
+
+ drbd_bm_lock(mdev, why);
+ rv = io_fn(mdev);
+ drbd_bm_unlock(mdev);
+
+ drbd_resume_io(mdev);
+
+ return rv;
+}
+
+void drbd_md_set_flag(struct drbd_conf *mdev, int flag) __must_hold(local)
+{
+ if ((mdev->ldev->md.flags & flag) != flag) {
+ drbd_md_mark_dirty(mdev);
+ mdev->ldev->md.flags |= flag;
+ }
+}
+
+void drbd_md_clear_flag(struct drbd_conf *mdev, int flag) __must_hold(local)
+{
+ if ((mdev->ldev->md.flags & flag) != 0) {
+ drbd_md_mark_dirty(mdev);
+ mdev->ldev->md.flags &= ~flag;
+ }
+}
+int drbd_md_test_flag(struct drbd_backing_dev *bdev, int flag)
+{
+ return (bdev->md.flags & flag) != 0;
+}
+
+static void md_sync_timer_fn(unsigned long data)
+{
+ struct drbd_conf *mdev = (struct drbd_conf *) data;
+
+ drbd_queue_work_front(&mdev->data.work, &mdev->md_sync_work);
+}
+
+static int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused)
+{
+ dev_warn(DEV, "md_sync_timer expired! Worker calls drbd_md_sync().\n");
+ drbd_md_sync(mdev);
+
+ return 1;
+}
+
+#ifdef CONFIG_DRBD_FAULT_INJECTION
+/* Fault insertion support including random number generator shamelessly
+ * stolen from kernel/rcutorture.c */
+struct fault_random_state {
+ unsigned long state;
+ unsigned long count;
+};
+
+#define FAULT_RANDOM_MULT 39916801 /* prime */
+#define FAULT_RANDOM_ADD 479001701 /* prime */
+#define FAULT_RANDOM_REFRESH 10000
+
+/*
+ * Crude but fast random-number generator. Uses a linear congruential
+ * generator, with occasional help from get_random_bytes().
+ */
+static unsigned long
+_drbd_fault_random(struct fault_random_state *rsp)
+{
+ long refresh;
+
+ if (--rsp->count < 0) {
+ get_random_bytes(&refresh, sizeof(refresh));
+ rsp->state += refresh;
+ rsp->count = FAULT_RANDOM_REFRESH;
+ }
+ rsp->state = rsp->state * FAULT_RANDOM_MULT + FAULT_RANDOM_ADD;
+ return swahw32(rsp->state);
+}
+
+static char *
+_drbd_fault_str(unsigned int type) {
+ static char *_faults[] = {
+ [DRBD_FAULT_MD_WR] = "Meta-data write",
+ [DRBD_FAULT_MD_RD] = "Meta-data read",
+ [DRBD_FAULT_RS_WR] = "Resync write",
+ [DRBD_FAULT_RS_RD] = "Resync read",
+ [DRBD_FAULT_DT_WR] = "Data write",
+ [DRBD_FAULT_DT_RD] = "Data read",
+ [DRBD_FAULT_DT_RA] = "Data read ahead",
+ [DRBD_FAULT_BM_ALLOC] = "BM allocation",
+ [DRBD_FAULT_AL_EE] = "EE allocation"
+ };
+
+ return (type < DRBD_FAULT_MAX) ? _faults[type] : "**Unknown**";
+}
+
+unsigned int
+_drbd_insert_fault(struct drbd_conf *mdev, unsigned int type)
+{
+ static struct fault_random_state rrs = {0, 0};
+
+ unsigned int ret = (
+ (fault_devs == 0 ||
+ ((1 << mdev_to_minor(mdev)) & fault_devs) != 0) &&
+ (((_drbd_fault_random(&rrs) % 100) + 1) <= fault_rate));
+
+ if (ret) {
+ fault_count++;
+
+ if (printk_ratelimit())
+ dev_warn(DEV, "***Simulating %s failure\n",
+ _drbd_fault_str(type));
+ }
+
+ return ret;
+}
+#endif
+
+const char *drbd_buildtag(void)
+{
+ /* DRBD built from external sources has here a reference to the
+ git hash of the source code. */
+
+ static char buildtag[38] = "\0uilt-in";
+
+ if (buildtag[0] == 0) {
+#ifdef CONFIG_MODULES
+ if (THIS_MODULE != NULL)
+ sprintf(buildtag, "srcversion: %-24s", THIS_MODULE->srcversion);
+ else
+#endif
+ buildtag[0] = 'b';
+ }
+
+ return buildtag;
+}
+
+module_init(drbd_init)
+module_exit(drbd_cleanup)
+
+EXPORT_SYMBOL(drbd_conn_str);
+EXPORT_SYMBOL(drbd_role_str);
+EXPORT_SYMBOL(drbd_disk_str);
+EXPORT_SYMBOL(drbd_set_st_err_str);
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
new file mode 100644
index 000000000000..22538d9628f1
--- /dev/null
+++ b/drivers/block/drbd/drbd_nl.c
@@ -0,0 +1,2360 @@
+/*
+ drbd_nl.c
+
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+ Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+ drbd 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.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT 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 drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/module.h>
+#include <linux/drbd.h>
+#include <linux/in.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/connector.h>
+#include <linux/blkpg.h>
+#include <linux/cpumask.h>
+#include "drbd_int.h"
+#include "drbd_wrappers.h"
+#include <asm/unaligned.h>
+#include <linux/drbd_tag_magic.h>
+#include <linux/drbd_limits.h>
+
+static unsigned short *tl_add_blob(unsigned short *, enum drbd_tags, const void *, int);
+static unsigned short *tl_add_str(unsigned short *, enum drbd_tags, const char *);
+static unsigned short *tl_add_int(unsigned short *, enum drbd_tags, const void *);
+
+/* see get_sb_bdev and bd_claim */
+static char *drbd_m_holder = "Hands off! this is DRBD's meta data device.";
+
+/* Generate the tag_list to struct functions */
+#define NL_PACKET(name, number, fields) \
+static int name ## _from_tags(struct drbd_conf *mdev, \
+ unsigned short *tags, struct name *arg) __attribute__ ((unused)); \
+static int name ## _from_tags(struct drbd_conf *mdev, \
+ unsigned short *tags, struct name *arg) \
+{ \
+ int tag; \
+ int dlen; \
+ \
+ while ((tag = get_unaligned(tags++)) != TT_END) { \
+ dlen = get_unaligned(tags++); \
+ switch (tag_number(tag)) { \
+ fields \
+ default: \
+ if (tag & T_MANDATORY) { \
+ dev_err(DEV, "Unknown tag: %d\n", tag_number(tag)); \
+ return 0; \
+ } \
+ } \
+ tags = (unsigned short *)((char *)tags + dlen); \
+ } \
+ return 1; \
+}
+#define NL_INTEGER(pn, pr, member) \
+ case pn: /* D_ASSERT( tag_type(tag) == TT_INTEGER ); */ \
+ arg->member = get_unaligned((int *)(tags)); \
+ break;
+#define NL_INT64(pn, pr, member) \
+ case pn: /* D_ASSERT( tag_type(tag) == TT_INT64 ); */ \
+ arg->member = get_unaligned((u64 *)(tags)); \
+ break;
+#define NL_BIT(pn, pr, member) \
+ case pn: /* D_ASSERT( tag_type(tag) == TT_BIT ); */ \
+ arg->member = *(char *)(tags) ? 1 : 0; \
+ break;
+#define NL_STRING(pn, pr, member, len) \
+ case pn: /* D_ASSERT( tag_type(tag) == TT_STRING ); */ \
+ if (dlen > len) { \
+ dev_err(DEV, "arg too long: %s (%u wanted, max len: %u bytes)\n", \
+ #member, dlen, (unsigned int)len); \
+ return 0; \
+ } \
+ arg->member ## _len = dlen; \
+ memcpy(arg->member, tags, min_t(size_t, dlen, len)); \
+ break;
+#include "linux/drbd_nl.h"
+
+/* Generate the struct to tag_list functions */
+#define NL_PACKET(name, number, fields) \
+static unsigned short* \
+name ## _to_tags(struct drbd_conf *mdev, \
+ struct name *arg, unsigned short *tags) __attribute__ ((unused)); \
+static unsigned short* \
+name ## _to_tags(struct drbd_conf *mdev, \
+ struct name *arg, unsigned short *tags) \
+{ \
+ fields \
+ return tags; \
+}
+
+#define NL_INTEGER(pn, pr, member) \
+ put_unaligned(pn | pr | TT_INTEGER, tags++); \
+ put_unaligned(sizeof(int), tags++); \
+ put_unaligned(arg->member, (int *)tags); \
+ tags = (unsigned short *)((char *)tags+sizeof(int));
+#define NL_INT64(pn, pr, member) \
+ put_unaligned(pn | pr | TT_INT64, tags++); \
+ put_unaligned(sizeof(u64), tags++); \
+ put_unaligned(arg->member, (u64 *)tags); \
+ tags = (unsigned short *)((char *)tags+sizeof(u64));
+#define NL_BIT(pn, pr, member) \
+ put_unaligned(pn | pr | TT_BIT, tags++); \
+ put_unaligned(sizeof(char), tags++); \
+ *(char *)tags = arg->member; \
+ tags = (unsigned short *)((char *)tags+sizeof(char));
+#define NL_STRING(pn, pr, member, len) \
+ put_unaligned(pn | pr | TT_STRING, tags++); \
+ put_unaligned(arg->member ## _len, tags++); \
+ memcpy(tags, arg->member, arg->member ## _len); \
+ tags = (unsigned short *)((char *)tags + arg->member ## _len);
+#include "linux/drbd_nl.h"
+
+void drbd_bcast_ev_helper(struct drbd_conf *mdev, char *helper_name);
+void drbd_nl_send_reply(struct cn_msg *, int);
+
+int drbd_khelper(struct drbd_conf *mdev, char *cmd)
+{
+ char *envp[] = { "HOME=/",
+ "TERM=linux",
+ "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
+ NULL, /* Will be set to address family */
+ NULL, /* Will be set to address */
+ NULL };
+
+ char mb[12], af[20], ad[60], *afs;
+ char *argv[] = {usermode_helper, cmd, mb, NULL };
+ int ret;
+
+ snprintf(mb, 12, "minor-%d", mdev_to_minor(mdev));
+
+ if (get_net_conf(mdev)) {
+ switch (((struct sockaddr *)mdev->net_conf->peer_addr)->sa_family) {
+ case AF_INET6:
+ afs = "ipv6";
+ snprintf(ad, 60, "DRBD_PEER_ADDRESS=%pI6",
+ &((struct sockaddr_in6 *)mdev->net_conf->peer_addr)->sin6_addr);
+ break;
+ case AF_INET:
+ afs = "ipv4";
+ snprintf(ad, 60, "DRBD_PEER_ADDRESS=%pI4",
+ &((struct sockaddr_in *)mdev->net_conf->peer_addr)->sin_addr);
+ break;
+ default:
+ afs = "ssocks";
+ snprintf(ad, 60, "DRBD_PEER_ADDRESS=%pI4",
+ &((struct sockaddr_in *)mdev->net_conf->peer_addr)->sin_addr);
+ }
+ snprintf(af, 20, "DRBD_PEER_AF=%s", afs);
+ envp[3]=af;
+ envp[4]=ad;
+ put_net_conf(mdev);
+ }
+
+ dev_info(DEV, "helper command: %s %s %s\n", usermode_helper, cmd, mb);
+
+ drbd_bcast_ev_helper(mdev, cmd);
+ ret = call_usermodehelper(usermode_helper, argv, envp, 1);
+ if (ret)
+ dev_warn(DEV, "helper command: %s %s %s exit code %u (0x%x)\n",
+ usermode_helper, cmd, mb,
+ (ret >> 8) & 0xff, ret);
+ else
+ dev_info(DEV, "helper command: %s %s %s exit code %u (0x%x)\n",
+ usermode_helper, cmd, mb,
+ (ret >> 8) & 0xff, ret);
+
+ if (ret < 0) /* Ignore any ERRNOs we got. */
+ ret = 0;
+
+ return ret;
+}
+
+enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev)
+{
+ char *ex_to_string;
+ int r;
+ enum drbd_disk_state nps;
+ enum drbd_fencing_p fp;
+
+ D_ASSERT(mdev->state.pdsk == D_UNKNOWN);
+
+ if (get_ldev_if_state(mdev, D_CONSISTENT)) {
+ fp = mdev->ldev->dc.fencing;
+ put_ldev(mdev);
+ } else {
+ dev_warn(DEV, "Not fencing peer, I'm not even Consistent myself.\n");
+ return mdev->state.pdsk;
+ }
+
+ if (fp == FP_STONITH)
+ _drbd_request_state(mdev, NS(susp, 1), CS_WAIT_COMPLETE);
+
+ r = drbd_khelper(mdev, "fence-peer");
+
+ switch ((r>>8) & 0xff) {
+ case 3: /* peer is inconsistent */
+ ex_to_string = "peer is inconsistent or worse";
+ nps = D_INCONSISTENT;
+ break;
+ case 4: /* peer got outdated, or was already outdated */
+ ex_to_string = "peer was fenced";
+ nps = D_OUTDATED;
+ break;
+ case 5: /* peer was down */
+ if (mdev->state.disk == D_UP_TO_DATE) {
+ /* we will(have) create(d) a new UUID anyways... */
+ ex_to_string = "peer is unreachable, assumed to be dead";
+ nps = D_OUTDATED;
+ } else {
+ ex_to_string = "peer unreachable, doing nothing since disk != UpToDate";
+ nps = mdev->state.pdsk;
+ }
+ break;
+ case 6: /* Peer is primary, voluntarily outdate myself.
+ * This is useful when an unconnected R_SECONDARY is asked to
+ * become R_PRIMARY, but finds the other peer being active. */
+ ex_to_string = "peer is active";
+ dev_warn(DEV, "Peer is primary, outdating myself.\n");
+ nps = D_UNKNOWN;
+ _drbd_request_state(mdev, NS(disk, D_OUTDATED), CS_WAIT_COMPLETE);
+ break;
+ case 7:
+ if (fp != FP_STONITH)
+ dev_err(DEV, "fence-peer() = 7 && fencing != Stonith !!!\n");
+ ex_to_string = "peer was stonithed";
+ nps = D_OUTDATED;
+ break;
+ default:
+ /* The script is broken ... */
+ nps = D_UNKNOWN;
+ dev_err(DEV, "fence-peer helper broken, returned %d\n", (r>>8)&0xff);
+ return nps;
+ }
+
+ dev_info(DEV, "fence-peer helper returned %d (%s)\n",
+ (r>>8) & 0xff, ex_to_string);
+ return nps;
+}
+
+
+int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
+{
+ const int max_tries = 4;
+ int r = 0;
+ int try = 0;
+ int forced = 0;
+ union drbd_state mask, val;
+ enum drbd_disk_state nps;
+
+ if (new_role == R_PRIMARY)
+ request_ping(mdev); /* Detect a dead peer ASAP */
+
+ mutex_lock(&mdev->state_mutex);
+
+ mask.i = 0; mask.role = R_MASK;
+ val.i = 0; val.role = new_role;
+
+ while (try++ < max_tries) {
+ r = _drbd_request_state(mdev, mask, val, CS_WAIT_COMPLETE);
+
+ /* in case we first succeeded to outdate,
+ * but now suddenly could establish a connection */
+ if (r == SS_CW_FAILED_BY_PEER && mask.pdsk != 0) {
+ val.pdsk = 0;
+ mask.pdsk = 0;
+ continue;
+ }
+
+ if (r == SS_NO_UP_TO_DATE_DISK && force &&
+ (mdev->state.disk == D_INCONSISTENT ||
+ mdev->state.disk == D_OUTDATED)) {
+ mask.disk = D_MASK;
+ val.disk = D_UP_TO_DATE;
+ forced = 1;
+ continue;
+ }
+
+ if (r == SS_NO_UP_TO_DATE_DISK &&
+ mdev->state.disk == D_CONSISTENT && mask.pdsk == 0) {
+ D_ASSERT(mdev->state.pdsk == D_UNKNOWN);
+ nps = drbd_try_outdate_peer(mdev);
+
+ if (nps == D_OUTDATED || nps == D_INCONSISTENT) {
+ val.disk = D_UP_TO_DATE;
+ mask.disk = D_MASK;
+ }
+
+ val.pdsk = nps;
+ mask.pdsk = D_MASK;
+
+ continue;
+ }
+
+ if (r == SS_NOTHING_TO_DO)
+ goto fail;
+ if (r == SS_PRIMARY_NOP && mask.pdsk == 0) {
+ nps = drbd_try_outdate_peer(mdev);
+
+ if (force && nps > D_OUTDATED) {
+ dev_warn(DEV, "Forced into split brain situation!\n");
+ nps = D_OUTDATED;
+ }
+
+ mask.pdsk = D_MASK;
+ val.pdsk = nps;
+
+ continue;
+ }
+ if (r == SS_TWO_PRIMARIES) {
+ /* Maybe the peer is detected as dead very soon...
+ retry at most once more in this case. */
+ __set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout((mdev->net_conf->ping_timeo+1)*HZ/10);
+ if (try < max_tries)
+ try = max_tries - 1;
+ continue;
+ }
+ if (r < SS_SUCCESS) {
+ r = _drbd_request_state(mdev, mask, val,
+ CS_VERBOSE + CS_WAIT_COMPLETE);
+ if (r < SS_SUCCESS)
+ goto fail;
+ }
+ break;
+ }
+
+ if (r < SS_SUCCESS)
+ goto fail;
+
+ if (forced)
+ dev_warn(DEV, "Forced to consider local data as UpToDate!\n");
+
+ /* Wait until nothing is on the fly :) */
+ wait_event(mdev->misc_wait, atomic_read(&mdev->ap_pending_cnt) == 0);
+
+ if (new_role == R_SECONDARY) {
+ set_disk_ro(mdev->vdisk, TRUE);
+ if (get_ldev(mdev)) {
+ mdev->ldev->md.uuid[UI_CURRENT] &= ~(u64)1;
+ put_ldev(mdev);
+ }
+ } else {
+ if (get_net_conf(mdev)) {
+ mdev->net_conf->want_lose = 0;
+ put_net_conf(mdev);
+ }
+ set_disk_ro(mdev->vdisk, FALSE);
+ if (get_ldev(mdev)) {
+ if (((mdev->state.conn < C_CONNECTED ||
+ mdev->state.pdsk <= D_FAILED)
+ && mdev->ldev->md.uuid[UI_BITMAP] == 0) || forced)
+ drbd_uuid_new_current(mdev);
+
+ mdev->ldev->md.uuid[UI_CURRENT] |= (u64)1;
+ put_ldev(mdev);
+ }
+ }
+
+ if ((new_role == R_SECONDARY) && get_ldev(mdev)) {
+ drbd_al_to_on_disk_bm(mdev);
+ put_ldev(mdev);
+ }
+
+ if (mdev->state.conn >= C_WF_REPORT_PARAMS) {
+ /* if this was forced, we should consider sync */
+ if (forced)
+ drbd_send_uuids(mdev);
+ drbd_send_state(mdev);
+ }
+
+ drbd_md_sync(mdev);
+
+ kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE);
+ fail:
+ mutex_unlock(&mdev->state_mutex);
+ return r;
+}
+
+
+static int drbd_nl_primary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ struct primary primary_args;
+
+ memset(&primary_args, 0, sizeof(struct primary));
+ if (!primary_from_tags(mdev, nlp->tag_list, &primary_args)) {
+ reply->ret_code = ERR_MANDATORY_TAG;
+ return 0;
+ }
+
+ reply->ret_code =
+ drbd_set_role(mdev, R_PRIMARY, primary_args.overwrite_peer);
+
+ return 0;
+}
+
+static int drbd_nl_secondary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ reply->ret_code = drbd_set_role(mdev, R_SECONDARY, 0);
+
+ return 0;
+}
+
+/* initializes the md.*_offset members, so we are able to find
+ * the on disk meta data */
+static void drbd_md_set_sector_offsets(struct drbd_conf *mdev,
+ struct drbd_backing_dev *bdev)
+{
+ sector_t md_size_sect = 0;
+ switch (bdev->dc.meta_dev_idx) {
+ default:
+ /* v07 style fixed size indexed meta data */
+ bdev->md.md_size_sect = MD_RESERVED_SECT;
+ bdev->md.md_offset = drbd_md_ss__(mdev, bdev);
+ bdev->md.al_offset = MD_AL_OFFSET;
+ bdev->md.bm_offset = MD_BM_OFFSET;
+ break;
+ case DRBD_MD_INDEX_FLEX_EXT:
+ /* just occupy the full device; unit: sectors */
+ bdev->md.md_size_sect = drbd_get_capacity(bdev->md_bdev);
+ bdev->md.md_offset = 0;
+ bdev->md.al_offset = MD_AL_OFFSET;
+ bdev->md.bm_offset = MD_BM_OFFSET;
+ break;
+ case DRBD_MD_INDEX_INTERNAL:
+ case DRBD_MD_INDEX_FLEX_INT:
+ bdev->md.md_offset = drbd_md_ss__(mdev, bdev);
+ /* al size is still fixed */
+ bdev->md.al_offset = -MD_AL_MAX_SIZE;
+ /* we need (slightly less than) ~ this much bitmap sectors: */
+ md_size_sect = drbd_get_capacity(bdev->backing_bdev);
+ md_size_sect = ALIGN(md_size_sect, BM_SECT_PER_EXT);
+ md_size_sect = BM_SECT_TO_EXT(md_size_sect);
+ md_size_sect = ALIGN(md_size_sect, 8);
+
+ /* plus the "drbd meta data super block",
+ * and the activity log; */
+ md_size_sect += MD_BM_OFFSET;
+
+ bdev->md.md_size_sect = md_size_sect;
+ /* bitmap offset is adjusted by 'super' block size */
+ bdev->md.bm_offset = -md_size_sect + MD_AL_OFFSET;
+ break;
+ }
+}
+
+char *ppsize(char *buf, unsigned long long size)
+{
+ /* Needs 9 bytes at max. */
+ static char units[] = { 'K', 'M', 'G', 'T', 'P', 'E' };
+ int base = 0;
+ while (size >= 10000) {
+ /* shift + round */
+ size = (size >> 10) + !!(size & (1<<9));
+ base++;
+ }
+ sprintf(buf, "%lu %cB", (long)size, units[base]);
+
+ return buf;
+}
+
+/* there is still a theoretical deadlock when called from receiver
+ * on an D_INCONSISTENT R_PRIMARY:
+ * remote READ does inc_ap_bio, receiver would need to receive answer
+ * packet from remote to dec_ap_bio again.
+ * receiver receive_sizes(), comes here,
+ * waits for ap_bio_cnt == 0. -> deadlock.
+ * but this cannot happen, actually, because:
+ * R_PRIMARY D_INCONSISTENT, and peer's disk is unreachable
+ * (not connected, or bad/no disk on peer):
+ * see drbd_fail_request_early, ap_bio_cnt is zero.
+ * R_PRIMARY D_INCONSISTENT, and C_SYNC_TARGET:
+ * peer may not initiate a resize.
+ */
+void drbd_suspend_io(struct drbd_conf *mdev)
+{
+ set_bit(SUSPEND_IO, &mdev->flags);
+ wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt));
+}
+
+void drbd_resume_io(struct drbd_conf *mdev)
+{
+ clear_bit(SUSPEND_IO, &mdev->flags);
+ wake_up(&mdev->misc_wait);
+}
+
+/**
+ * drbd_determine_dev_size() - Sets the right device size obeying all constraints
+ * @mdev: DRBD device.
+ *
+ * Returns 0 on success, negative return values indicate errors.
+ * You should call drbd_md_sync() after calling this function.
+ */
+enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *mdev) __must_hold(local)
+{
+ sector_t prev_first_sect, prev_size; /* previous meta location */
+ sector_t la_size;
+ sector_t size;
+ char ppb[10];
+
+ int md_moved, la_size_changed;
+ enum determine_dev_size rv = unchanged;
+
+ /* race:
+ * application request passes inc_ap_bio,
+ * but then cannot get an AL-reference.
+ * this function later may wait on ap_bio_cnt == 0. -> deadlock.
+ *
+ * to avoid that:
+ * Suspend IO right here.
+ * still lock the act_log to not trigger ASSERTs there.
+ */
+ drbd_suspend_io(mdev);
+
+ /* no wait necessary anymore, actually we could assert that */
+ wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
+
+ prev_first_sect = drbd_md_first_sector(mdev->ldev);
+ prev_size = mdev->ldev->md.md_size_sect;
+ la_size = mdev->ldev->md.la_size_sect;
+
+ /* TODO: should only be some assert here, not (re)init... */
+ drbd_md_set_sector_offsets(mdev, mdev->ldev);
+
+ size = drbd_new_dev_size(mdev, mdev->ldev);
+
+ if (drbd_get_capacity(mdev->this_bdev) != size ||
+ drbd_bm_capacity(mdev) != size) {
+ int err;
+ err = drbd_bm_resize(mdev, size);
+ if (unlikely(err)) {
+ /* currently there is only one error: ENOMEM! */
+ size = drbd_bm_capacity(mdev)>>1;
+ if (size == 0) {
+ dev_err(DEV, "OUT OF MEMORY! "
+ "Could not allocate bitmap!\n");
+ } else {
+ dev_err(DEV, "BM resizing failed. "
+ "Leaving size unchanged at size = %lu KB\n",
+ (unsigned long)size);
+ }
+ rv = dev_size_error;
+ }
+ /* racy, see comments above. */
+ drbd_set_my_capacity(mdev, size);
+ mdev->ldev->md.la_size_sect = size;
+ dev_info(DEV, "size = %s (%llu KB)\n", ppsize(ppb, size>>1),
+ (unsigned long long)size>>1);
+ }
+ if (rv == dev_size_error)
+ goto out;
+
+ la_size_changed = (la_size != mdev->ldev->md.la_size_sect);
+
+ md_moved = prev_first_sect != drbd_md_first_sector(mdev->ldev)
+ || prev_size != mdev->ldev->md.md_size_sect;
+
+ if (la_size_changed || md_moved) {
+ drbd_al_shrink(mdev); /* All extents inactive. */
+ dev_info(DEV, "Writing the whole bitmap, %s\n",
+ la_size_changed && md_moved ? "size changed and md moved" :
+ la_size_changed ? "size changed" : "md moved");
+ rv = drbd_bitmap_io(mdev, &drbd_bm_write, "size changed"); /* does drbd_resume_io() ! */
+ drbd_md_mark_dirty(mdev);
+ }
+
+ if (size > la_size)
+ rv = grew;
+ if (size < la_size)
+ rv = shrunk;
+out:
+ lc_unlock(mdev->act_log);
+ wake_up(&mdev->al_wait);
+ drbd_resume_io(mdev);
+
+ return rv;
+}
+
+sector_t
+drbd_new_dev_size(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
+{
+ sector_t p_size = mdev->p_size; /* partner's disk size. */
+ sector_t la_size = bdev->md.la_size_sect; /* last agreed size. */
+ sector_t m_size; /* my size */
+ sector_t u_size = bdev->dc.disk_size; /* size requested by user. */
+ sector_t size = 0;
+
+ m_size = drbd_get_max_capacity(bdev);
+
+ if (p_size && m_size) {
+ size = min_t(sector_t, p_size, m_size);
+ } else {
+ if (la_size) {
+ size = la_size;
+ if (m_size && m_size < size)
+ size = m_size;
+ if (p_size && p_size < size)
+ size = p_size;
+ } else {
+ if (m_size)
+ size = m_size;
+ if (p_size)
+ size = p_size;
+ }
+ }
+
+ if (size == 0)
+ dev_err(DEV, "Both nodes diskless!\n");
+
+ if (u_size) {
+ if (u_size > size)
+ dev_err(DEV, "Requested disk size is too big (%lu > %lu)\n",
+ (unsigned long)u_size>>1, (unsigned long)size>>1);
+ else
+ size = u_size;
+ }
+
+ return size;
+}
+
+/**
+ * drbd_check_al_size() - Ensures that the AL is of the right size
+ * @mdev: DRBD device.
+ *
+ * Returns -EBUSY if current al lru is still used, -ENOMEM when allocation
+ * failed, and 0 on success. You should call drbd_md_sync() after you called
+ * this function.
+ */
+static int drbd_check_al_size(struct drbd_conf *mdev)
+{
+ struct lru_cache *n, *t;
+ struct lc_element *e;
+ unsigned int in_use;
+ int i;
+
+ ERR_IF(mdev->sync_conf.al_extents < 7)
+ mdev->sync_conf.al_extents = 127;
+
+ if (mdev->act_log &&
+ mdev->act_log->nr_elements == mdev->sync_conf.al_extents)
+ return 0;
+
+ in_use = 0;
+ t = mdev->act_log;
+ n = lc_create("act_log", drbd_al_ext_cache,
+ mdev->sync_conf.al_extents, sizeof(struct lc_element), 0);
+
+ if (n == NULL) {
+ dev_err(DEV, "Cannot allocate act_log lru!\n");
+ return -ENOMEM;
+ }
+ spin_lock_irq(&mdev->al_lock);
+ if (t) {
+ for (i = 0; i < t->nr_elements; i++) {
+ e = lc_element_by_index(t, i);
+ if (e->refcnt)
+ dev_err(DEV, "refcnt(%d)==%d\n",
+ e->lc_number, e->refcnt);
+ in_use += e->refcnt;
+ }
+ }
+ if (!in_use)
+ mdev->act_log = n;
+ spin_unlock_irq(&mdev->al_lock);
+ if (in_use) {
+ dev_err(DEV, "Activity log still in use!\n");
+ lc_destroy(n);
+ return -EBUSY;
+ } else {
+ if (t)
+ lc_destroy(t);
+ }
+ drbd_md_mark_dirty(mdev); /* we changed mdev->act_log->nr_elemens */
+ return 0;
+}
+
+void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_seg_s) __must_hold(local)
+{
+ struct request_queue * const q = mdev->rq_queue;
+ struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue;
+ int max_segments = mdev->ldev->dc.max_bio_bvecs;
+
+ if (b->merge_bvec_fn && !mdev->ldev->dc.use_bmbv)
+ max_seg_s = PAGE_SIZE;
+
+ max_seg_s = min(queue_max_sectors(b) * queue_logical_block_size(b), max_seg_s);
+
+ blk_queue_max_sectors(q, max_seg_s >> 9);
+ blk_queue_max_phys_segments(q, max_segments ? max_segments : MAX_PHYS_SEGMENTS);
+ blk_queue_max_hw_segments(q, max_segments ? max_segments : MAX_HW_SEGMENTS);
+ blk_queue_max_segment_size(q, max_seg_s);
+ blk_queue_logical_block_size(q, 512);
+ blk_queue_segment_boundary(q, PAGE_SIZE-1);
+ blk_stack_limits(&q->limits, &b->limits, 0);
+
+ if (b->merge_bvec_fn)
+ dev_warn(DEV, "Backing device's merge_bvec_fn() = %p\n",
+ b->merge_bvec_fn);
+ dev_info(DEV, "max_segment_size ( = BIO size ) = %u\n", queue_max_segment_size(q));
+
+ if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) {
+ dev_info(DEV, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n",
+ q->backing_dev_info.ra_pages,
+ b->backing_dev_info.ra_pages);
+ q->backing_dev_info.ra_pages = b->backing_dev_info.ra_pages;
+ }
+}
+
+/* serialize deconfig (worker exiting, doing cleanup)
+ * and reconfig (drbdsetup disk, drbdsetup net)
+ *
+ * wait for a potentially exiting worker, then restart it,
+ * or start a new one.
+ */
+static void drbd_reconfig_start(struct drbd_conf *mdev)
+{
+ wait_event(mdev->state_wait, test_and_set_bit(CONFIG_PENDING, &mdev->flags));
+ wait_event(mdev->state_wait, !test_bit(DEVICE_DYING, &mdev->flags));
+ drbd_thread_start(&mdev->worker);
+}
+
+/* if still unconfigured, stops worker again.
+ * if configured now, clears CONFIG_PENDING.
+ * wakes potential waiters */
+static void drbd_reconfig_done(struct drbd_conf *mdev)
+{
+ spin_lock_irq(&mdev->req_lock);
+ if (mdev->state.disk == D_DISKLESS &&
+ mdev->state.conn == C_STANDALONE &&
+ mdev->state.role == R_SECONDARY) {
+ set_bit(DEVICE_DYING, &mdev->flags);
+ drbd_thread_stop_nowait(&mdev->worker);
+ } else
+ clear_bit(CONFIG_PENDING, &mdev->flags);
+ spin_unlock_irq(&mdev->req_lock);
+ wake_up(&mdev->state_wait);
+}
+
+/* does always return 0;
+ * interesting return code is in reply->ret_code */
+static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ enum drbd_ret_codes retcode;
+ enum determine_dev_size dd;
+ sector_t max_possible_sectors;
+ sector_t min_md_device_sectors;
+ struct drbd_backing_dev *nbc = NULL; /* new_backing_conf */
+ struct inode *inode, *inode2;
+ struct lru_cache *resync_lru = NULL;
+ union drbd_state ns, os;
+ int rv;
+ int cp_discovered = 0;
+ int logical_block_size;
+
+ drbd_reconfig_start(mdev);
+
+ /* if you want to reconfigure, please tear down first */
+ if (mdev->state.disk > D_DISKLESS) {
+ retcode = ERR_DISK_CONFIGURED;
+ goto fail;
+ }
+
+ /* allocation not in the IO path, cqueue thread context */
+ nbc = kzalloc(sizeof(struct drbd_backing_dev), GFP_KERNEL);
+ if (!nbc) {
+ retcode = ERR_NOMEM;
+ goto fail;
+ }
+
+ nbc->dc.disk_size = DRBD_DISK_SIZE_SECT_DEF;
+ nbc->dc.on_io_error = DRBD_ON_IO_ERROR_DEF;
+ nbc->dc.fencing = DRBD_FENCING_DEF;
+ nbc->dc.max_bio_bvecs = DRBD_MAX_BIO_BVECS_DEF;
+
+ if (!disk_conf_from_tags(mdev, nlp->tag_list, &nbc->dc)) {
+ retcode = ERR_MANDATORY_TAG;
+ goto fail;
+ }
+
+ if (nbc->dc.meta_dev_idx < DRBD_MD_INDEX_FLEX_INT) {
+ retcode = ERR_MD_IDX_INVALID;
+ goto fail;
+ }
+
+ nbc->lo_file = filp_open(nbc->dc.backing_dev, O_RDWR, 0);
+ if (IS_ERR(nbc->lo_file)) {
+ dev_err(DEV, "open(\"%s\") failed with %ld\n", nbc->dc.backing_dev,
+ PTR_ERR(nbc->lo_file));
+ nbc->lo_file = NULL;
+ retcode = ERR_OPEN_DISK;
+ goto fail;
+ }
+
+ inode = nbc->lo_file->f_dentry->d_inode;
+
+ if (!S_ISBLK(inode->i_mode)) {
+ retcode = ERR_DISK_NOT_BDEV;
+ goto fail;
+ }
+
+ nbc->md_file = filp_open(nbc->dc.meta_dev, O_RDWR, 0);
+ if (IS_ERR(nbc->md_file)) {
+ dev_err(DEV, "open(\"%s\") failed with %ld\n", nbc->dc.meta_dev,
+ PTR_ERR(nbc->md_file));
+ nbc->md_file = NULL;
+ retcode = ERR_OPEN_MD_DISK;
+ goto fail;
+ }
+
+ inode2 = nbc->md_file->f_dentry->d_inode;
+
+ if (!S_ISBLK(inode2->i_mode)) {
+ retcode = ERR_MD_NOT_BDEV;
+ goto fail;
+ }
+
+ nbc->backing_bdev = inode->i_bdev;
+ if (bd_claim(nbc->backing_bdev, mdev)) {
+ printk(KERN_ERR "drbd: bd_claim(%p,%p); failed [%p;%p;%u]\n",
+ nbc->backing_bdev, mdev,
+ nbc->backing_bdev->bd_holder,
+ nbc->backing_bdev->bd_contains->bd_holder,
+ nbc->backing_bdev->bd_holders);
+ retcode = ERR_BDCLAIM_DISK;
+ goto fail;
+ }
+
+ resync_lru = lc_create("resync", drbd_bm_ext_cache,
+ 61, sizeof(struct bm_extent),
+ offsetof(struct bm_extent, lce));
+ if (!resync_lru) {
+ retcode = ERR_NOMEM;
+ goto release_bdev_fail;
+ }
+
+ /* meta_dev_idx >= 0: external fixed size,
+ * possibly multiple drbd sharing one meta device.
+ * TODO in that case, paranoia check that [md_bdev, meta_dev_idx] is
+ * not yet used by some other drbd minor!
+ * (if you use drbd.conf + drbdadm,
+ * that should check it for you already; but if you don't, or someone
+ * fooled it, we need to double check here) */
+ nbc->md_bdev = inode2->i_bdev;
+ if (bd_claim(nbc->md_bdev, (nbc->dc.meta_dev_idx < 0) ? (void *)mdev
+ : (void *) drbd_m_holder)) {
+ retcode = ERR_BDCLAIM_MD_DISK;
+ goto release_bdev_fail;
+ }
+
+ if ((nbc->backing_bdev == nbc->md_bdev) !=
+ (nbc->dc.meta_dev_idx == DRBD_MD_INDEX_INTERNAL ||
+ nbc->dc.meta_dev_idx == DRBD_MD_INDEX_FLEX_INT)) {
+ retcode = ERR_MD_IDX_INVALID;
+ goto release_bdev2_fail;
+ }
+
+ /* RT - for drbd_get_max_capacity() DRBD_MD_INDEX_FLEX_INT */
+ drbd_md_set_sector_offsets(mdev, nbc);
+
+ if (drbd_get_max_capacity(nbc) < nbc->dc.disk_size) {
+ dev_err(DEV, "max capacity %llu smaller than disk size %llu\n",
+ (unsigned long long) drbd_get_max_capacity(nbc),
+ (unsigned long long) nbc->dc.disk_size);
+ retcode = ERR_DISK_TO_SMALL;
+ goto release_bdev2_fail;
+ }
+
+ if (nbc->dc.meta_dev_idx < 0) {
+ max_possible_sectors = DRBD_MAX_SECTORS_FLEX;
+ /* at least one MB, otherwise it does not make sense */
+ min_md_device_sectors = (2<<10);
+ } else {
+ max_possible_sectors = DRBD_MAX_SECTORS;
+ min_md_device_sectors = MD_RESERVED_SECT * (nbc->dc.meta_dev_idx + 1);
+ }
+
+ if (drbd_get_capacity(nbc->md_bdev) > max_possible_sectors)
+ dev_warn(DEV, "truncating very big lower level device "
+ "to currently maximum possible %llu sectors\n",
+ (unsigned long long) max_possible_sectors);
+
+ if (drbd_get_capacity(nbc->md_bdev) < min_md_device_sectors) {
+ retcode = ERR_MD_DISK_TO_SMALL;
+ dev_warn(DEV, "refusing attach: md-device too small, "
+ "at least %llu sectors needed for this meta-disk type\n",
+ (unsigned long long) min_md_device_sectors);
+ goto release_bdev2_fail;
+ }
+
+ /* Make sure the new disk is big enough
+ * (we may currently be R_PRIMARY with no local disk...) */
+ if (drbd_get_max_capacity(nbc) <
+ drbd_get_capacity(mdev->this_bdev)) {
+ retcode = ERR_DISK_TO_SMALL;
+ goto release_bdev2_fail;
+ }
+
+ nbc->known_size = drbd_get_capacity(nbc->backing_bdev);
+
+ drbd_suspend_io(mdev);
+ /* also wait for the last barrier ack. */
+ wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_pending_cnt));
+ /* and for any other previously queued work */
+ drbd_flush_workqueue(mdev);
+
+ retcode = _drbd_request_state(mdev, NS(disk, D_ATTACHING), CS_VERBOSE);
+ drbd_resume_io(mdev);
+ if (retcode < SS_SUCCESS)
+ goto release_bdev2_fail;
+
+ if (!get_ldev_if_state(mdev, D_ATTACHING))
+ goto force_diskless;
+
+ drbd_md_set_sector_offsets(mdev, nbc);
+
+ if (!mdev->bitmap) {
+ if (drbd_bm_init(mdev)) {
+ retcode = ERR_NOMEM;
+ goto force_diskless_dec;
+ }
+ }
+
+ retcode = drbd_md_read(mdev, nbc);
+ if (retcode != NO_ERROR)
+ goto force_diskless_dec;
+
+ if (mdev->state.conn < C_CONNECTED &&
+ mdev->state.role == R_PRIMARY &&
+ (mdev->ed_uuid & ~((u64)1)) != (nbc->md.uuid[UI_CURRENT] & ~((u64)1))) {
+ dev_err(DEV, "Can only attach to data with current UUID=%016llX\n",
+ (unsigned long long)mdev->ed_uuid);
+ retcode = ERR_DATA_NOT_CURRENT;
+ goto force_diskless_dec;
+ }
+
+ /* Since we are diskless, fix the activity log first... */
+ if (drbd_check_al_size(mdev)) {
+ retcode = ERR_NOMEM;
+ goto force_diskless_dec;
+ }
+
+ /* Prevent shrinking of consistent devices ! */
+ if (drbd_md_test_flag(nbc, MDF_CONSISTENT) &&
+ drbd_new_dev_size(mdev, nbc) < nbc->md.la_size_sect) {
+ dev_warn(DEV, "refusing to truncate a consistent device\n");
+ retcode = ERR_DISK_TO_SMALL;
+ goto force_diskless_dec;
+ }
+
+ if (!drbd_al_read_log(mdev, nbc)) {
+ retcode = ERR_IO_MD_DISK;
+ goto force_diskless_dec;
+ }
+
+ /* allocate a second IO page if logical_block_size != 512 */
+ logical_block_size = bdev_logical_block_size(nbc->md_bdev);
+ if (logical_block_size == 0)
+ logical_block_size = MD_SECTOR_SIZE;
+
+ if (logical_block_size != MD_SECTOR_SIZE) {
+ if (!mdev->md_io_tmpp) {
+ struct page *page = alloc_page(GFP_NOIO);
+ if (!page)
+ goto force_diskless_dec;
+
+ dev_warn(DEV, "Meta data's bdev logical_block_size = %d != %d\n",
+ logical_block_size, MD_SECTOR_SIZE);
+ dev_warn(DEV, "Workaround engaged (has performance impact).\n");
+
+ mdev->md_io_tmpp = page;
+ }
+ }
+
+ /* Reset the "barriers don't work" bits here, then force meta data to
+ * be written, to ensure we determine if barriers are supported. */
+ if (nbc->dc.no_md_flush)
+ set_bit(MD_NO_BARRIER, &mdev->flags);
+ else
+ clear_bit(MD_NO_BARRIER, &mdev->flags);
+
+ /* Point of no return reached.
+ * Devices and memory are no longer released by error cleanup below.
+ * now mdev takes over responsibility, and the state engine should
+ * clean it up somewhere. */
+ D_ASSERT(mdev->ldev == NULL);
+ mdev->ldev = nbc;
+ mdev->resync = resync_lru;
+ nbc = NULL;
+ resync_lru = NULL;
+
+ mdev->write_ordering = WO_bio_barrier;
+ drbd_bump_write_ordering(mdev, WO_bio_barrier);
+
+ if (drbd_md_test_flag(mdev->ldev, MDF_CRASHED_PRIMARY))
+ set_bit(CRASHED_PRIMARY, &mdev->flags);
+ else
+ clear_bit(CRASHED_PRIMARY, &mdev->flags);
+
+ if (drbd_md_test_flag(mdev->ldev, MDF_PRIMARY_IND)) {
+ set_bit(CRASHED_PRIMARY, &mdev->flags);
+ cp_discovered = 1;
+ }
+
+ mdev->send_cnt = 0;
+ mdev->recv_cnt = 0;
+ mdev->read_cnt = 0;
+ mdev->writ_cnt = 0;
+
+ drbd_setup_queue_param(mdev, DRBD_MAX_SEGMENT_SIZE);
+
+ /* If I am currently not R_PRIMARY,
+ * but meta data primary indicator is set,
+ * I just now recover from a hard crash,
+ * and have been R_PRIMARY before that crash.
+ *
+ * Now, if I had no connection before that crash
+ * (have been degraded R_PRIMARY), chances are that
+ * I won't find my peer now either.
+ *
+ * In that case, and _only_ in that case,
+ * we use the degr-wfc-timeout instead of the default,
+ * so we can automatically recover from a crash of a
+ * degraded but active "cluster" after a certain timeout.
+ */
+ clear_bit(USE_DEGR_WFC_T, &mdev->flags);
+ if (mdev->state.role != R_PRIMARY &&
+ drbd_md_test_flag(mdev->ldev, MDF_PRIMARY_IND) &&
+ !drbd_md_test_flag(mdev->ldev, MDF_CONNECTED_IND))
+ set_bit(USE_DEGR_WFC_T, &mdev->flags);
+
+ dd = drbd_determin_dev_size(mdev);
+ if (dd == dev_size_error) {
+ retcode = ERR_NOMEM_BITMAP;
+ goto force_diskless_dec;
+ } else if (dd == grew)
+ set_bit(RESYNC_AFTER_NEG, &mdev->flags);
+
+ if (drbd_md_test_flag(mdev->ldev, MDF_FULL_SYNC)) {
+ dev_info(DEV, "Assuming that all blocks are out of sync "
+ "(aka FullSync)\n");
+ if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write, "set_n_write from attaching")) {
+ retcode = ERR_IO_MD_DISK;
+ goto force_diskless_dec;
+ }
+ } else {
+ if (drbd_bitmap_io(mdev, &drbd_bm_read, "read from attaching") < 0) {
+ retcode = ERR_IO_MD_DISK;
+ goto force_diskless_dec;
+ }
+ }
+
+ if (cp_discovered) {
+ drbd_al_apply_to_bm(mdev);
+ drbd_al_to_on_disk_bm(mdev);
+ }
+
+ spin_lock_irq(&mdev->req_lock);
+ os = mdev->state;
+ ns.i = os.i;
+ /* If MDF_CONSISTENT is not set go into inconsistent state,
+ otherwise investigate MDF_WasUpToDate...
+ If MDF_WAS_UP_TO_DATE is not set go into D_OUTDATED disk state,
+ otherwise into D_CONSISTENT state.
+ */
+ if (drbd_md_test_flag(mdev->ldev, MDF_CONSISTENT)) {
+ if (drbd_md_test_flag(mdev->ldev, MDF_WAS_UP_TO_DATE))
+ ns.disk = D_CONSISTENT;
+ else
+ ns.disk = D_OUTDATED;
+ } else {
+ ns.disk = D_INCONSISTENT;
+ }
+
+ if (drbd_md_test_flag(mdev->ldev, MDF_PEER_OUT_DATED))
+ ns.pdsk = D_OUTDATED;
+
+ if ( ns.disk == D_CONSISTENT &&
+ (ns.pdsk == D_OUTDATED || mdev->ldev->dc.fencing == FP_DONT_CARE))
+ ns.disk = D_UP_TO_DATE;
+
+ /* All tests on MDF_PRIMARY_IND, MDF_CONNECTED_IND,
+ MDF_CONSISTENT and MDF_WAS_UP_TO_DATE must happen before
+ this point, because drbd_request_state() modifies these
+ flags. */
+
+ /* In case we are C_CONNECTED postpone any decision on the new disk
+ state after the negotiation phase. */
+ if (mdev->state.conn == C_CONNECTED) {
+ mdev->new_state_tmp.i = ns.i;
+ ns.i = os.i;
+ ns.disk = D_NEGOTIATING;
+ }
+
+ rv = _drbd_set_state(mdev, ns, CS_VERBOSE, NULL);
+ ns = mdev->state;
+ spin_unlock_irq(&mdev->req_lock);
+
+ if (rv < SS_SUCCESS)
+ goto force_diskless_dec;
+
+ if (mdev->state.role == R_PRIMARY)
+ mdev->ldev->md.uuid[UI_CURRENT] |= (u64)1;
+ else
+ mdev->ldev->md.uuid[UI_CURRENT] &= ~(u64)1;
+
+ drbd_md_mark_dirty(mdev);
+ drbd_md_sync(mdev);
+
+ kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE);
+ put_ldev(mdev);
+ reply->ret_code = retcode;
+ drbd_reconfig_done(mdev);
+ return 0;
+
+ force_diskless_dec:
+ put_ldev(mdev);
+ force_diskless:
+ drbd_force_state(mdev, NS(disk, D_DISKLESS));
+ drbd_md_sync(mdev);
+ release_bdev2_fail:
+ if (nbc)
+ bd_release(nbc->md_bdev);
+ release_bdev_fail:
+ if (nbc)
+ bd_release(nbc->backing_bdev);
+ fail:
+ if (nbc) {
+ if (nbc->lo_file)
+ fput(nbc->lo_file);
+ if (nbc->md_file)
+ fput(nbc->md_file);
+ kfree(nbc);
+ }
+ lc_destroy(resync_lru);
+
+ reply->ret_code = retcode;
+ drbd_reconfig_done(mdev);
+ return 0;
+}
+
+static int drbd_nl_detach(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ reply->ret_code = drbd_request_state(mdev, NS(disk, D_DISKLESS));
+ return 0;
+}
+
+static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ int i, ns;
+ enum drbd_ret_codes retcode;
+ struct net_conf *new_conf = NULL;
+ struct crypto_hash *tfm = NULL;
+ struct crypto_hash *integrity_w_tfm = NULL;
+ struct crypto_hash *integrity_r_tfm = NULL;
+ struct hlist_head *new_tl_hash = NULL;
+ struct hlist_head *new_ee_hash = NULL;
+ struct drbd_conf *odev;
+ char hmac_name[CRYPTO_MAX_ALG_NAME];
+ void *int_dig_out = NULL;
+ void *int_dig_in = NULL;
+ void *int_dig_vv = NULL;
+ struct sockaddr *new_my_addr, *new_peer_addr, *taken_addr;
+
+ drbd_reconfig_start(mdev);
+
+ if (mdev->state.conn > C_STANDALONE) {
+ retcode = ERR_NET_CONFIGURED;
+ goto fail;
+ }
+
+ /* allocation not in the IO path, cqueue thread context */
+ new_conf = kmalloc(sizeof(struct net_conf), GFP_KERNEL);
+ if (!new_conf) {
+ retcode = ERR_NOMEM;
+ goto fail;
+ }
+
+ memset(new_conf, 0, sizeof(struct net_conf));
+ new_conf->timeout = DRBD_TIMEOUT_DEF;
+ new_conf->try_connect_int = DRBD_CONNECT_INT_DEF;
+ new_conf->ping_int = DRBD_PING_INT_DEF;
+ new_conf->max_epoch_size = DRBD_MAX_EPOCH_SIZE_DEF;
+ new_conf->max_buffers = DRBD_MAX_BUFFERS_DEF;
+ new_conf->unplug_watermark = DRBD_UNPLUG_WATERMARK_DEF;
+ new_conf->sndbuf_size = DRBD_SNDBUF_SIZE_DEF;
+ new_conf->rcvbuf_size = DRBD_RCVBUF_SIZE_DEF;
+ new_conf->ko_count = DRBD_KO_COUNT_DEF;
+ new_conf->after_sb_0p = DRBD_AFTER_SB_0P_DEF;
+ new_conf->after_sb_1p = DRBD_AFTER_SB_1P_DEF;
+ new_conf->after_sb_2p = DRBD_AFTER_SB_2P_DEF;
+ new_conf->want_lose = 0;
+ new_conf->two_primaries = 0;
+ new_conf->wire_protocol = DRBD_PROT_C;
+ new_conf->ping_timeo = DRBD_PING_TIMEO_DEF;
+ new_conf->rr_conflict = DRBD_RR_CONFLICT_DEF;
+
+ if (!net_conf_from_tags(mdev, nlp->tag_list, new_conf)) {
+ retcode = ERR_MANDATORY_TAG;
+ goto fail;
+ }
+
+ if (new_conf->two_primaries
+ && (new_conf->wire_protocol != DRBD_PROT_C)) {
+ retcode = ERR_NOT_PROTO_C;
+ goto fail;
+ };
+
+ if (mdev->state.role == R_PRIMARY && new_conf->want_lose) {
+ retcode = ERR_DISCARD;
+ goto fail;
+ }
+
+ retcode = NO_ERROR;
+
+ new_my_addr = (struct sockaddr *)&new_conf->my_addr;
+ new_peer_addr = (struct sockaddr *)&new_conf->peer_addr;
+ for (i = 0; i < minor_count; i++) {
+ odev = minor_to_mdev(i);
+ if (!odev || odev == mdev)
+ continue;
+ if (get_net_conf(odev)) {
+ taken_addr = (struct sockaddr *)&odev->net_conf->my_addr;
+ if (new_conf->my_addr_len == odev->net_conf->my_addr_len &&
+ !memcmp(new_my_addr, taken_addr, new_conf->my_addr_len))
+ retcode = ERR_LOCAL_ADDR;
+
+ taken_addr = (struct sockaddr *)&odev->net_conf->peer_addr;
+ if (new_conf->peer_addr_len == odev->net_conf->peer_addr_len &&
+ !memcmp(new_peer_addr, taken_addr, new_conf->peer_addr_len))
+ retcode = ERR_PEER_ADDR;
+
+ put_net_conf(odev);
+ if (retcode != NO_ERROR)
+ goto fail;
+ }
+ }
+
+ if (new_conf->cram_hmac_alg[0] != 0) {
+ snprintf(hmac_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)",
+ new_conf->cram_hmac_alg);
+ tfm = crypto_alloc_hash(hmac_name, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(tfm)) {
+ tfm = NULL;
+ retcode = ERR_AUTH_ALG;
+ goto fail;
+ }
+
+ if (crypto_tfm_alg_type(crypto_hash_tfm(tfm))
+ != CRYPTO_ALG_TYPE_HASH) {
+ retcode = ERR_AUTH_ALG_ND;
+ goto fail;
+ }
+ }
+
+ if (new_conf->integrity_alg[0]) {
+ integrity_w_tfm = crypto_alloc_hash(new_conf->integrity_alg, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(integrity_w_tfm)) {
+ integrity_w_tfm = NULL;
+ retcode=ERR_INTEGRITY_ALG;
+ goto fail;
+ }
+
+ if (!drbd_crypto_is_hash(crypto_hash_tfm(integrity_w_tfm))) {
+ retcode=ERR_INTEGRITY_ALG_ND;
+ goto fail;
+ }
+
+ integrity_r_tfm = crypto_alloc_hash(new_conf->integrity_alg, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(integrity_r_tfm)) {
+ integrity_r_tfm = NULL;
+ retcode=ERR_INTEGRITY_ALG;
+ goto fail;
+ }
+ }
+
+ ns = new_conf->max_epoch_size/8;
+ if (mdev->tl_hash_s != ns) {
+ new_tl_hash = kzalloc(ns*sizeof(void *), GFP_KERNEL);
+ if (!new_tl_hash) {
+ retcode = ERR_NOMEM;
+ goto fail;
+ }
+ }
+
+ ns = new_conf->max_buffers/8;
+ if (new_conf->two_primaries && (mdev->ee_hash_s != ns)) {
+ new_ee_hash = kzalloc(ns*sizeof(void *), GFP_KERNEL);
+ if (!new_ee_hash) {
+ retcode = ERR_NOMEM;
+ goto fail;
+ }
+ }
+
+ ((char *)new_conf->shared_secret)[SHARED_SECRET_MAX-1] = 0;
+
+ if (integrity_w_tfm) {
+ i = crypto_hash_digestsize(integrity_w_tfm);
+ int_dig_out = kmalloc(i, GFP_KERNEL);
+ if (!int_dig_out) {
+ retcode = ERR_NOMEM;
+ goto fail;
+ }
+ int_dig_in = kmalloc(i, GFP_KERNEL);
+ if (!int_dig_in) {
+ retcode = ERR_NOMEM;
+ goto fail;
+ }
+ int_dig_vv = kmalloc(i, GFP_KERNEL);
+ if (!int_dig_vv) {
+ retcode = ERR_NOMEM;
+ goto fail;
+ }
+ }
+
+ if (!mdev->bitmap) {
+ if(drbd_bm_init(mdev)) {
+ retcode = ERR_NOMEM;
+ goto fail;
+ }
+ }
+
+ spin_lock_irq(&mdev->req_lock);
+ if (mdev->net_conf != NULL) {
+ retcode = ERR_NET_CONFIGURED;
+ spin_unlock_irq(&mdev->req_lock);
+ goto fail;
+ }
+ mdev->net_conf = new_conf;
+
+ mdev->send_cnt = 0;
+ mdev->recv_cnt = 0;
+
+ if (new_tl_hash) {
+ kfree(mdev->tl_hash);
+ mdev->tl_hash_s = mdev->net_conf->max_epoch_size/8;
+ mdev->tl_hash = new_tl_hash;
+ }
+
+ if (new_ee_hash) {
+ kfree(mdev->ee_hash);
+ mdev->ee_hash_s = mdev->net_conf->max_buffers/8;
+ mdev->ee_hash = new_ee_hash;
+ }
+
+ crypto_free_hash(mdev->cram_hmac_tfm);
+ mdev->cram_hmac_tfm = tfm;
+
+ crypto_free_hash(mdev->integrity_w_tfm);
+ mdev->integrity_w_tfm = integrity_w_tfm;
+
+ crypto_free_hash(mdev->integrity_r_tfm);
+ mdev->integrity_r_tfm = integrity_r_tfm;
+
+ kfree(mdev->int_dig_out);
+ kfree(mdev->int_dig_in);
+ kfree(mdev->int_dig_vv);
+ mdev->int_dig_out=int_dig_out;
+ mdev->int_dig_in=int_dig_in;
+ mdev->int_dig_vv=int_dig_vv;
+ spin_unlock_irq(&mdev->req_lock);
+
+ retcode = _drbd_request_state(mdev, NS(conn, C_UNCONNECTED), CS_VERBOSE);
+
+ kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE);
+ reply->ret_code = retcode;
+ drbd_reconfig_done(mdev);
+ return 0;
+
+fail:
+ kfree(int_dig_out);
+ kfree(int_dig_in);
+ kfree(int_dig_vv);
+ crypto_free_hash(tfm);
+ crypto_free_hash(integrity_w_tfm);
+ crypto_free_hash(integrity_r_tfm);
+ kfree(new_tl_hash);
+ kfree(new_ee_hash);
+ kfree(new_conf);
+
+ reply->ret_code = retcode;
+ drbd_reconfig_done(mdev);
+ return 0;
+}
+
+static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ int retcode;
+
+ retcode = _drbd_request_state(mdev, NS(conn, C_DISCONNECTING), CS_ORDERED);
+
+ if (retcode == SS_NOTHING_TO_DO)
+ goto done;
+ else if (retcode == SS_ALREADY_STANDALONE)
+ goto done;
+ else if (retcode == SS_PRIMARY_NOP) {
+ /* Our statche checking code wants to see the peer outdated. */
+ retcode = drbd_request_state(mdev, NS2(conn, C_DISCONNECTING,
+ pdsk, D_OUTDATED));
+ } else if (retcode == SS_CW_FAILED_BY_PEER) {
+ /* The peer probably wants to see us outdated. */
+ retcode = _drbd_request_state(mdev, NS2(conn, C_DISCONNECTING,
+ disk, D_OUTDATED),
+ CS_ORDERED);
+ if (retcode == SS_IS_DISKLESS || retcode == SS_LOWER_THAN_OUTDATED) {
+ drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+ retcode = SS_SUCCESS;
+ }
+ }
+
+ if (retcode < SS_SUCCESS)
+ goto fail;
+
+ if (wait_event_interruptible(mdev->state_wait,
+ mdev->state.conn != C_DISCONNECTING)) {
+ /* Do not test for mdev->state.conn == C_STANDALONE, since
+ someone else might connect us in the mean time! */
+ retcode = ERR_INTR;
+ goto fail;
+ }
+
+ done:
+ retcode = NO_ERROR;
+ fail:
+ drbd_md_sync(mdev);
+ reply->ret_code = retcode;
+ return 0;
+}
+
+void resync_after_online_grow(struct drbd_conf *mdev)
+{
+ int iass; /* I am sync source */
+
+ dev_info(DEV, "Resync of new storage after online grow\n");
+ if (mdev->state.role != mdev->state.peer)
+ iass = (mdev->state.role == R_PRIMARY);
+ else
+ iass = test_bit(DISCARD_CONCURRENT, &mdev->flags);
+
+ if (iass)
+ drbd_start_resync(mdev, C_SYNC_SOURCE);
+ else
+ _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE + CS_SERIALIZE);
+}
+
+static int drbd_nl_resize(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ struct resize rs;
+ int retcode = NO_ERROR;
+ int ldsc = 0; /* local disk size changed */
+ enum determine_dev_size dd;
+
+ memset(&rs, 0, sizeof(struct resize));
+ if (!resize_from_tags(mdev, nlp->tag_list, &rs)) {
+ retcode = ERR_MANDATORY_TAG;
+ goto fail;
+ }
+
+ if (mdev->state.conn > C_CONNECTED) {
+ retcode = ERR_RESIZE_RESYNC;
+ goto fail;
+ }
+
+ if (mdev->state.role == R_SECONDARY &&
+ mdev->state.peer == R_SECONDARY) {
+ retcode = ERR_NO_PRIMARY;
+ goto fail;
+ }
+
+ if (!get_ldev(mdev)) {
+ retcode = ERR_NO_DISK;
+ goto fail;
+ }
+
+ if (mdev->ldev->known_size != drbd_get_capacity(mdev->ldev->backing_bdev)) {
+ mdev->ldev->known_size = drbd_get_capacity(mdev->ldev->backing_bdev);
+ ldsc = 1;
+ }
+
+ mdev->ldev->dc.disk_size = (sector_t)rs.resize_size;
+ dd = drbd_determin_dev_size(mdev);
+ drbd_md_sync(mdev);
+ put_ldev(mdev);
+ if (dd == dev_size_error) {
+ retcode = ERR_NOMEM_BITMAP;
+ goto fail;
+ }
+
+ if (mdev->state.conn == C_CONNECTED && (dd != unchanged || ldsc)) {
+ if (dd == grew)
+ set_bit(RESIZE_PENDING, &mdev->flags);
+
+ drbd_send_uuids(mdev);
+ drbd_send_sizes(mdev, 1);
+ }
+
+ fail:
+ reply->ret_code = retcode;
+ return 0;
+}
+
+static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ int retcode = NO_ERROR;
+ int err;
+ int ovr; /* online verify running */
+ int rsr; /* re-sync running */
+ struct crypto_hash *verify_tfm = NULL;
+ struct crypto_hash *csums_tfm = NULL;
+ struct syncer_conf sc;
+ cpumask_var_t new_cpu_mask;
+
+ if (!zalloc_cpumask_var(&new_cpu_mask, GFP_KERNEL)) {
+ retcode = ERR_NOMEM;
+ goto fail;
+ }
+
+ if (nlp->flags & DRBD_NL_SET_DEFAULTS) {
+ memset(&sc, 0, sizeof(struct syncer_conf));
+ sc.rate = DRBD_RATE_DEF;
+ sc.after = DRBD_AFTER_DEF;
+ sc.al_extents = DRBD_AL_EXTENTS_DEF;
+ } else
+ memcpy(&sc, &mdev->sync_conf, sizeof(struct syncer_conf));
+
+ if (!syncer_conf_from_tags(mdev, nlp->tag_list, &sc)) {
+ retcode = ERR_MANDATORY_TAG;
+ goto fail;
+ }
+
+ /* re-sync running */
+ rsr = ( mdev->state.conn == C_SYNC_SOURCE ||
+ mdev->state.conn == C_SYNC_TARGET ||
+ mdev->state.conn == C_PAUSED_SYNC_S ||
+ mdev->state.conn == C_PAUSED_SYNC_T );
+
+ if (rsr && strcmp(sc.csums_alg, mdev->sync_conf.csums_alg)) {
+ retcode = ERR_CSUMS_RESYNC_RUNNING;
+ goto fail;
+ }
+
+ if (!rsr && sc.csums_alg[0]) {
+ csums_tfm = crypto_alloc_hash(sc.csums_alg, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(csums_tfm)) {
+ csums_tfm = NULL;
+ retcode = ERR_CSUMS_ALG;
+ goto fail;
+ }
+
+ if (!drbd_crypto_is_hash(crypto_hash_tfm(csums_tfm))) {
+ retcode = ERR_CSUMS_ALG_ND;
+ goto fail;
+ }
+ }
+
+ /* online verify running */
+ ovr = (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T);
+
+ if (ovr) {
+ if (strcmp(sc.verify_alg, mdev->sync_conf.verify_alg)) {
+ retcode = ERR_VERIFY_RUNNING;
+ goto fail;
+ }
+ }
+
+ if (!ovr && sc.verify_alg[0]) {
+ verify_tfm = crypto_alloc_hash(sc.verify_alg, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(verify_tfm)) {
+ verify_tfm = NULL;
+ retcode = ERR_VERIFY_ALG;
+ goto fail;
+ }
+
+ if (!drbd_crypto_is_hash(crypto_hash_tfm(verify_tfm))) {
+ retcode = ERR_VERIFY_ALG_ND;
+ goto fail;
+ }
+ }
+
+ /* silently ignore cpu mask on UP kernel */
+ if (nr_cpu_ids > 1 && sc.cpu_mask[0] != 0) {
+ err = __bitmap_parse(sc.cpu_mask, 32, 0,
+ cpumask_bits(new_cpu_mask), nr_cpu_ids);
+ if (err) {
+ dev_warn(DEV, "__bitmap_parse() failed with %d\n", err);
+ retcode = ERR_CPU_MASK_PARSE;
+ goto fail;
+ }
+ }
+
+ ERR_IF (sc.rate < 1) sc.rate = 1;
+ ERR_IF (sc.al_extents < 7) sc.al_extents = 127; /* arbitrary minimum */
+#define AL_MAX ((MD_AL_MAX_SIZE-1) * AL_EXTENTS_PT)
+ if (sc.al_extents > AL_MAX) {
+ dev_err(DEV, "sc.al_extents > %d\n", AL_MAX);
+ sc.al_extents = AL_MAX;
+ }
+#undef AL_MAX
+
+ /* most sanity checks done, try to assign the new sync-after
+ * dependency. need to hold the global lock in there,
+ * to avoid a race in the dependency loop check. */
+ retcode = drbd_alter_sa(mdev, sc.after);
+ if (retcode != NO_ERROR)
+ goto fail;
+
+ /* ok, assign the rest of it as well.
+ * lock against receive_SyncParam() */
+ spin_lock(&mdev->peer_seq_lock);
+ mdev->sync_conf = sc;
+
+ if (!rsr) {
+ crypto_free_hash(mdev->csums_tfm);
+ mdev->csums_tfm = csums_tfm;
+ csums_tfm = NULL;
+ }
+
+ if (!ovr) {
+ crypto_free_hash(mdev->verify_tfm);
+ mdev->verify_tfm = verify_tfm;
+ verify_tfm = NULL;
+ }
+ spin_unlock(&mdev->peer_seq_lock);
+
+ if (get_ldev(mdev)) {
+ wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
+ drbd_al_shrink(mdev);
+ err = drbd_check_al_size(mdev);
+ lc_unlock(mdev->act_log);
+ wake_up(&mdev->al_wait);
+
+ put_ldev(mdev);
+ drbd_md_sync(mdev);
+
+ if (err) {
+ retcode = ERR_NOMEM;
+ goto fail;
+ }
+ }
+
+ if (mdev->state.conn >= C_CONNECTED)
+ drbd_send_sync_param(mdev, &sc);
+
+ if (!cpumask_equal(mdev->cpu_mask, new_cpu_mask)) {
+ cpumask_copy(mdev->cpu_mask, new_cpu_mask);
+ drbd_calc_cpu_mask(mdev);
+ mdev->receiver.reset_cpu_mask = 1;
+ mdev->asender.reset_cpu_mask = 1;
+ mdev->worker.reset_cpu_mask = 1;
+ }
+
+ kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE);
+fail:
+ free_cpumask_var(new_cpu_mask);
+ crypto_free_hash(csums_tfm);
+ crypto_free_hash(verify_tfm);
+ reply->ret_code = retcode;
+ return 0;
+}
+
+static int drbd_nl_invalidate(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ int retcode;
+
+ retcode = _drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_T), CS_ORDERED);
+
+ if (retcode < SS_SUCCESS && retcode != SS_NEED_CONNECTION)
+ retcode = drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_T));
+
+ while (retcode == SS_NEED_CONNECTION) {
+ spin_lock_irq(&mdev->req_lock);
+ if (mdev->state.conn < C_CONNECTED)
+ retcode = _drbd_set_state(_NS(mdev, disk, D_INCONSISTENT), CS_VERBOSE, NULL);
+ spin_unlock_irq(&mdev->req_lock);
+
+ if (retcode != SS_NEED_CONNECTION)
+ break;
+
+ retcode = drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_T));
+ }
+
+ reply->ret_code = retcode;
+ return 0;
+}
+
+static int drbd_nl_invalidate_peer(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+
+ reply->ret_code = drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_S));
+
+ return 0;
+}
+
+static int drbd_nl_pause_sync(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ int retcode = NO_ERROR;
+
+ if (drbd_request_state(mdev, NS(user_isp, 1)) == SS_NOTHING_TO_DO)
+ retcode = ERR_PAUSE_IS_SET;
+
+ reply->ret_code = retcode;
+ return 0;
+}
+
+static int drbd_nl_resume_sync(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ int retcode = NO_ERROR;
+
+ if (drbd_request_state(mdev, NS(user_isp, 0)) == SS_NOTHING_TO_DO)
+ retcode = ERR_PAUSE_IS_CLEAR;
+
+ reply->ret_code = retcode;
+ return 0;
+}
+
+static int drbd_nl_suspend_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ reply->ret_code = drbd_request_state(mdev, NS(susp, 1));
+
+ return 0;
+}
+
+static int drbd_nl_resume_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ reply->ret_code = drbd_request_state(mdev, NS(susp, 0));
+ return 0;
+}
+
+static int drbd_nl_outdate(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ reply->ret_code = drbd_request_state(mdev, NS(disk, D_OUTDATED));
+ return 0;
+}
+
+static int drbd_nl_get_config(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ unsigned short *tl;
+
+ tl = reply->tag_list;
+
+ if (get_ldev(mdev)) {
+ tl = disk_conf_to_tags(mdev, &mdev->ldev->dc, tl);
+ put_ldev(mdev);
+ }
+
+ if (get_net_conf(mdev)) {
+ tl = net_conf_to_tags(mdev, mdev->net_conf, tl);
+ put_net_conf(mdev);
+ }
+ tl = syncer_conf_to_tags(mdev, &mdev->sync_conf, tl);
+
+ put_unaligned(TT_END, tl++); /* Close the tag list */
+
+ return (int)((char *)tl - (char *)reply->tag_list);
+}
+
+static int drbd_nl_get_state(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ unsigned short *tl = reply->tag_list;
+ union drbd_state s = mdev->state;
+ unsigned long rs_left;
+ unsigned int res;
+
+ tl = get_state_to_tags(mdev, (struct get_state *)&s, tl);
+
+ /* no local ref, no bitmap, no syncer progress. */
+ if (s.conn >= C_SYNC_SOURCE && s.conn <= C_PAUSED_SYNC_T) {
+ if (get_ldev(mdev)) {
+ drbd_get_syncer_progress(mdev, &rs_left, &res);
+ tl = tl_add_int(tl, T_sync_progress, &res);
+ put_ldev(mdev);
+ }
+ }
+ put_unaligned(TT_END, tl++); /* Close the tag list */
+
+ return (int)((char *)tl - (char *)reply->tag_list);
+}
+
+static int drbd_nl_get_uuids(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ unsigned short *tl;
+
+ tl = reply->tag_list;
+
+ if (get_ldev(mdev)) {
+ tl = tl_add_blob(tl, T_uuids, mdev->ldev->md.uuid, UI_SIZE*sizeof(u64));
+ tl = tl_add_int(tl, T_uuids_flags, &mdev->ldev->md.flags);
+ put_ldev(mdev);
+ }
+ put_unaligned(TT_END, tl++); /* Close the tag list */
+
+ return (int)((char *)tl - (char *)reply->tag_list);
+}
+
+/**
+ * drbd_nl_get_timeout_flag() - Used by drbdsetup to find out which timeout value to use
+ * @mdev: DRBD device.
+ * @nlp: Netlink/connector packet from drbdsetup
+ * @reply: Reply packet for drbdsetup
+ */
+static int drbd_nl_get_timeout_flag(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ unsigned short *tl;
+ char rv;
+
+ tl = reply->tag_list;
+
+ rv = mdev->state.pdsk == D_OUTDATED ? UT_PEER_OUTDATED :
+ test_bit(USE_DEGR_WFC_T, &mdev->flags) ? UT_DEGRADED : UT_DEFAULT;
+
+ tl = tl_add_blob(tl, T_use_degraded, &rv, sizeof(rv));
+ put_unaligned(TT_END, tl++); /* Close the tag list */
+
+ return (int)((char *)tl - (char *)reply->tag_list);
+}
+
+static int drbd_nl_start_ov(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ /* default to resume from last known position, if possible */
+ struct start_ov args =
+ { .start_sector = mdev->ov_start_sector };
+
+ if (!start_ov_from_tags(mdev, nlp->tag_list, &args)) {
+ reply->ret_code = ERR_MANDATORY_TAG;
+ return 0;
+ }
+ /* w_make_ov_request expects position to be aligned */
+ mdev->ov_start_sector = args.start_sector & ~BM_SECT_PER_BIT;
+ reply->ret_code = drbd_request_state(mdev,NS(conn,C_VERIFY_S));
+ return 0;
+}
+
+
+static int drbd_nl_new_c_uuid(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
+ struct drbd_nl_cfg_reply *reply)
+{
+ int retcode = NO_ERROR;
+ int skip_initial_sync = 0;
+ int err;
+
+ struct new_c_uuid args;
+
+ memset(&args, 0, sizeof(struct new_c_uuid));
+ if (!new_c_uuid_from_tags(mdev, nlp->tag_list, &args)) {
+ reply->ret_code = ERR_MANDATORY_TAG;
+ return 0;
+ }
+
+ mutex_lock(&mdev->state_mutex); /* Protects us against serialized state changes. */
+
+ if (!get_ldev(mdev)) {
+ retcode = ERR_NO_DISK;
+ goto out;
+ }
+
+ /* this is "skip initial sync", assume to be clean */
+ if (mdev->state.conn == C_CONNECTED && mdev->agreed_pro_version >= 90 &&
+ mdev->ldev->md.uuid[UI_CURRENT] == UUID_JUST_CREATED && args.clear_bm) {
+ dev_info(DEV, "Preparing to skip initial sync\n");
+ skip_initial_sync = 1;
+ } else if (mdev->state.conn != C_STANDALONE) {
+ retcode = ERR_CONNECTED;
+ goto out_dec;
+ }
+
+ drbd_uuid_set(mdev, UI_BITMAP, 0); /* Rotate UI_BITMAP to History 1, etc... */
+ drbd_uuid_new_current(mdev); /* New current, previous to UI_BITMAP */
+
+ if (args.clear_bm) {
+ err = drbd_bitmap_io(mdev, &drbd_bmio_clear_n_write, "clear_n_write from new_c_uuid");
+ if (err) {
+ dev_err(DEV, "Writing bitmap failed with %d\n",err);
+ retcode = ERR_IO_MD_DISK;
+ }
+ if (skip_initial_sync) {
+ drbd_send_uuids_skip_initial_sync(mdev);
+ _drbd_uuid_set(mdev, UI_BITMAP, 0);
+ spin_lock_irq(&mdev->req_lock);
+ _drbd_set_state(_NS2(mdev, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE),
+ CS_VERBOSE, NULL);
+ spin_unlock_irq(&mdev->req_lock);
+ }
+ }
+
+ drbd_md_sync(mdev);
+out_dec:
+ put_ldev(mdev);
+out:
+ mutex_unlock(&mdev->state_mutex);
+
+ reply->ret_code = retcode;
+ return 0;
+}
+
+static struct drbd_conf *ensure_mdev(struct drbd_nl_cfg_req *nlp)
+{
+ struct drbd_conf *mdev;
+
+ if (nlp->drbd_minor >= minor_count)
+ return NULL;
+
+ mdev = minor_to_mdev(nlp->drbd_minor);
+
+ if (!mdev && (nlp->flags & DRBD_NL_CREATE_DEVICE)) {
+ struct gendisk *disk = NULL;
+ mdev = drbd_new_device(nlp->drbd_minor);
+
+ spin_lock_irq(&drbd_pp_lock);
+ if (minor_table[nlp->drbd_minor] == NULL) {
+ minor_table[nlp->drbd_minor] = mdev;
+ disk = mdev->vdisk;
+ mdev = NULL;
+ } /* else: we lost the race */
+ spin_unlock_irq(&drbd_pp_lock);
+
+ if (disk) /* we won the race above */
+ /* in case we ever add a drbd_delete_device(),
+ * don't forget the del_gendisk! */
+ add_disk(disk);
+ else /* we lost the race above */
+ drbd_free_mdev(mdev);
+
+ mdev = minor_to_mdev(nlp->drbd_minor);
+ }
+
+ return mdev;
+}
+
+struct cn_handler_struct {
+ int (*function)(struct drbd_conf *,
+ struct drbd_nl_cfg_req *,
+ struct drbd_nl_cfg_reply *);
+ int reply_body_size;
+};
+
+static struct cn_handler_struct cnd_table[] = {
+ [ P_primary ] = { &drbd_nl_primary, 0 },
+ [ P_secondary ] = { &drbd_nl_secondary, 0 },
+ [ P_disk_conf ] = { &drbd_nl_disk_conf, 0 },
+ [ P_detach ] = { &drbd_nl_detach, 0 },
+ [ P_net_conf ] = { &drbd_nl_net_conf, 0 },
+ [ P_disconnect ] = { &drbd_nl_disconnect, 0 },
+ [ P_resize ] = { &drbd_nl_resize, 0 },
+ [ P_syncer_conf ] = { &drbd_nl_syncer_conf, 0 },
+ [ P_invalidate ] = { &drbd_nl_invalidate, 0 },
+ [ P_invalidate_peer ] = { &drbd_nl_invalidate_peer, 0 },
+ [ P_pause_sync ] = { &drbd_nl_pause_sync, 0 },
+ [ P_resume_sync ] = { &drbd_nl_resume_sync, 0 },
+ [ P_suspend_io ] = { &drbd_nl_suspend_io, 0 },
+ [ P_resume_io ] = { &drbd_nl_resume_io, 0 },
+ [ P_outdate ] = { &drbd_nl_outdate, 0 },
+ [ P_get_config ] = { &drbd_nl_get_config,
+ sizeof(struct syncer_conf_tag_len_struct) +
+ sizeof(struct disk_conf_tag_len_struct) +
+ sizeof(struct net_conf_tag_len_struct) },
+ [ P_get_state ] = { &drbd_nl_get_state,
+ sizeof(struct get_state_tag_len_struct) +
+ sizeof(struct sync_progress_tag_len_struct) },
+ [ P_get_uuids ] = { &drbd_nl_get_uuids,
+ sizeof(struct get_uuids_tag_len_struct) },
+ [ P_get_timeout_flag ] = { &drbd_nl_get_timeout_flag,
+ sizeof(struct get_timeout_flag_tag_len_struct)},
+ [ P_start_ov ] = { &drbd_nl_start_ov, 0 },
+ [ P_new_c_uuid ] = { &drbd_nl_new_c_uuid, 0 },
+};
+
+static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms *nsp)
+{
+ struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req *)req->data;
+ struct cn_handler_struct *cm;
+ struct cn_msg *cn_reply;
+ struct drbd_nl_cfg_reply *reply;
+ struct drbd_conf *mdev;
+ int retcode, rr;
+ int reply_size = sizeof(struct cn_msg)
+ + sizeof(struct drbd_nl_cfg_reply)
+ + sizeof(short int);
+
+ if (!try_module_get(THIS_MODULE)) {
+ printk(KERN_ERR "drbd: try_module_get() failed!\n");
+ return;
+ }
+
+ if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN)) {
+ retcode = ERR_PERM;
+ goto fail;
+ }
+
+ mdev = ensure_mdev(nlp);
+ if (!mdev) {
+ retcode = ERR_MINOR_INVALID;
+ goto fail;
+ }
+
+ if (nlp->packet_type >= P_nl_after_last_packet) {
+ retcode = ERR_PACKET_NR;
+ goto fail;
+ }
+
+ cm = cnd_table + nlp->packet_type;
+
+ /* This may happen if packet number is 0: */
+ if (cm->function == NULL) {
+ retcode = ERR_PACKET_NR;
+ goto fail;
+ }
+
+ reply_size += cm->reply_body_size;
+
+ /* allocation not in the IO path, cqueue thread context */
+ cn_reply = kmalloc(reply_size, GFP_KERNEL);
+ if (!cn_reply) {
+ retcode = ERR_NOMEM;
+ goto fail;
+ }
+ reply = (struct drbd_nl_cfg_reply *) cn_reply->data;
+
+ reply->packet_type =
+ cm->reply_body_size ? nlp->packet_type : P_nl_after_last_packet;
+ reply->minor = nlp->drbd_minor;
+ reply->ret_code = NO_ERROR; /* Might by modified by cm->function. */
+ /* reply->tag_list; might be modified by cm->function. */
+
+ rr = cm->function(mdev, nlp, reply);
+
+ cn_reply->id = req->id;
+ cn_reply->seq = req->seq;
+ cn_reply->ack = req->ack + 1;
+ cn_reply->len = sizeof(struct drbd_nl_cfg_reply) + rr;
+ cn_reply->flags = 0;
+
+ rr = cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_KERNEL);
+ if (rr && rr != -ESRCH)
+ printk(KERN_INFO "drbd: cn_netlink_send()=%d\n", rr);
+
+ kfree(cn_reply);
+ module_put(THIS_MODULE);
+ return;
+ fail:
+ drbd_nl_send_reply(req, retcode);
+ module_put(THIS_MODULE);
+}
+
+static atomic_t drbd_nl_seq = ATOMIC_INIT(2); /* two. */
+
+static unsigned short *
+__tl_add_blob(unsigned short *tl, enum drbd_tags tag, const void *data,
+ unsigned short len, int nul_terminated)
+{
+ unsigned short l = tag_descriptions[tag_number(tag)].max_len;
+ len = (len < l) ? len : l;
+ put_unaligned(tag, tl++);
+ put_unaligned(len, tl++);
+ memcpy(tl, data, len);
+ tl = (unsigned short*)((char*)tl + len);
+ if (nul_terminated)
+ *((char*)tl - 1) = 0;
+ return tl;
+}
+
+static unsigned short *
+tl_add_blob(unsigned short *tl, enum drbd_tags tag, const void *data, int len)
+{
+ return __tl_add_blob(tl, tag, data, len, 0);
+}
+
+static unsigned short *
+tl_add_str(unsigned short *tl, enum drbd_tags tag, const char *str)
+{
+ return __tl_add_blob(tl, tag, str, strlen(str)+1, 0);
+}
+
+static unsigned short *
+tl_add_int(unsigned short *tl, enum drbd_tags tag, const void *val)
+{
+ put_unaligned(tag, tl++);
+ switch(tag_type(tag)) {
+ case TT_INTEGER:
+ put_unaligned(sizeof(int), tl++);
+ put_unaligned(*(int *)val, (int *)tl);
+ tl = (unsigned short*)((char*)tl+sizeof(int));
+ break;
+ case TT_INT64:
+ put_unaligned(sizeof(u64), tl++);
+ put_unaligned(*(u64 *)val, (u64 *)tl);
+ tl = (unsigned short*)((char*)tl+sizeof(u64));
+ break;
+ default:
+ /* someone did something stupid. */
+ ;
+ }
+ return tl;
+}
+
+void drbd_bcast_state(struct drbd_conf *mdev, union drbd_state state)
+{
+ char buffer[sizeof(struct cn_msg)+
+ sizeof(struct drbd_nl_cfg_reply)+
+ sizeof(struct get_state_tag_len_struct)+
+ sizeof(short int)];
+ struct cn_msg *cn_reply = (struct cn_msg *) buffer;
+ struct drbd_nl_cfg_reply *reply =
+ (struct drbd_nl_cfg_reply *)cn_reply->data;
+ unsigned short *tl = reply->tag_list;
+
+ /* dev_warn(DEV, "drbd_bcast_state() got called\n"); */
+
+ tl = get_state_to_tags(mdev, (struct get_state *)&state, tl);
+
+ put_unaligned(TT_END, tl++); /* Close the tag list */
+
+ cn_reply->id.idx = CN_IDX_DRBD;
+ cn_reply->id.val = CN_VAL_DRBD;
+
+ cn_reply->seq = atomic_add_return(1, &drbd_nl_seq);
+ cn_reply->ack = 0; /* not used here. */
+ cn_reply->len = sizeof(struct drbd_nl_cfg_reply) +
+ (int)((char *)tl - (char *)reply->tag_list);
+ cn_reply->flags = 0;
+
+ reply->packet_type = P_get_state;
+ reply->minor = mdev_to_minor(mdev);
+ reply->ret_code = NO_ERROR;
+
+ cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_NOIO);
+}
+
+void drbd_bcast_ev_helper(struct drbd_conf *mdev, char *helper_name)
+{
+ char buffer[sizeof(struct cn_msg)+
+ sizeof(struct drbd_nl_cfg_reply)+
+ sizeof(struct call_helper_tag_len_struct)+
+ sizeof(short int)];
+ struct cn_msg *cn_reply = (struct cn_msg *) buffer;
+ struct drbd_nl_cfg_reply *reply =
+ (struct drbd_nl_cfg_reply *)cn_reply->data;
+ unsigned short *tl = reply->tag_list;
+
+ /* dev_warn(DEV, "drbd_bcast_state() got called\n"); */
+
+ tl = tl_add_str(tl, T_helper, helper_name);
+ put_unaligned(TT_END, tl++); /* Close the tag list */
+
+ cn_reply->id.idx = CN_IDX_DRBD;
+ cn_reply->id.val = CN_VAL_DRBD;
+
+ cn_reply->seq = atomic_add_return(1, &drbd_nl_seq);
+ cn_reply->ack = 0; /* not used here. */
+ cn_reply->len = sizeof(struct drbd_nl_cfg_reply) +
+ (int)((char *)tl - (char *)reply->tag_list);
+ cn_reply->flags = 0;
+
+ reply->packet_type = P_call_helper;
+ reply->minor = mdev_to_minor(mdev);
+ reply->ret_code = NO_ERROR;
+
+ cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_NOIO);
+}
+
+void drbd_bcast_ee(struct drbd_conf *mdev,
+ const char *reason, const int dgs,
+ const char* seen_hash, const char* calc_hash,
+ const struct drbd_epoch_entry* e)
+{
+ struct cn_msg *cn_reply;
+ struct drbd_nl_cfg_reply *reply;
+ struct bio_vec *bvec;
+ unsigned short *tl;
+ int i;
+
+ if (!e)
+ return;
+ if (!reason || !reason[0])
+ return;
+
+ /* apparently we have to memcpy twice, first to prepare the data for the
+ * struct cn_msg, then within cn_netlink_send from the cn_msg to the
+ * netlink skb. */
+ /* receiver thread context, which is not in the writeout path (of this node),
+ * but may be in the writeout path of the _other_ node.
+ * GFP_NOIO to avoid potential "distributed deadlock". */
+ cn_reply = kmalloc(
+ sizeof(struct cn_msg)+
+ sizeof(struct drbd_nl_cfg_reply)+
+ sizeof(struct dump_ee_tag_len_struct)+
+ sizeof(short int),
+ GFP_NOIO);
+
+ if (!cn_reply) {
+ dev_err(DEV, "could not kmalloc buffer for drbd_bcast_ee, sector %llu, size %u\n",
+ (unsigned long long)e->sector, e->size);
+ return;
+ }
+
+ reply = (struct drbd_nl_cfg_reply*)cn_reply->data;
+ tl = reply->tag_list;
+
+ tl = tl_add_str(tl, T_dump_ee_reason, reason);
+ tl = tl_add_blob(tl, T_seen_digest, seen_hash, dgs);
+ tl = tl_add_blob(tl, T_calc_digest, calc_hash, dgs);
+ tl = tl_add_int(tl, T_ee_sector, &e->sector);
+ tl = tl_add_int(tl, T_ee_block_id, &e->block_id);
+
+ put_unaligned(T_ee_data, tl++);
+ put_unaligned(e->size, tl++);
+
+ __bio_for_each_segment(bvec, e->private_bio, i, 0) {
+ void *d = kmap(bvec->bv_page);
+ memcpy(tl, d + bvec->bv_offset, bvec->bv_len);
+ kunmap(bvec->bv_page);
+ tl=(unsigned short*)((char*)tl + bvec->bv_len);
+ }
+ put_unaligned(TT_END, tl++); /* Close the tag list */
+
+ cn_reply->id.idx = CN_IDX_DRBD;
+ cn_reply->id.val = CN_VAL_DRBD;
+
+ cn_reply->seq = atomic_add_return(1,&drbd_nl_seq);
+ cn_reply->ack = 0; // not used here.
+ cn_reply->len = sizeof(struct drbd_nl_cfg_reply) +
+ (int)((char*)tl - (char*)reply->tag_list);
+ cn_reply->flags = 0;
+
+ reply->packet_type = P_dump_ee;
+ reply->minor = mdev_to_minor(mdev);
+ reply->ret_code = NO_ERROR;
+
+ cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_NOIO);
+ kfree(cn_reply);
+}
+
+void drbd_bcast_sync_progress(struct drbd_conf *mdev)
+{
+ char buffer[sizeof(struct cn_msg)+
+ sizeof(struct drbd_nl_cfg_reply)+
+ sizeof(struct sync_progress_tag_len_struct)+
+ sizeof(short int)];
+ struct cn_msg *cn_reply = (struct cn_msg *) buffer;
+ struct drbd_nl_cfg_reply *reply =
+ (struct drbd_nl_cfg_reply *)cn_reply->data;
+ unsigned short *tl = reply->tag_list;
+ unsigned long rs_left;
+ unsigned int res;
+
+ /* no local ref, no bitmap, no syncer progress, no broadcast. */
+ if (!get_ldev(mdev))
+ return;
+ drbd_get_syncer_progress(mdev, &rs_left, &res);
+ put_ldev(mdev);
+
+ tl = tl_add_int(tl, T_sync_progress, &res);
+ put_unaligned(TT_END, tl++); /* Close the tag list */
+
+ cn_reply->id.idx = CN_IDX_DRBD;
+ cn_reply->id.val = CN_VAL_DRBD;
+
+ cn_reply->seq = atomic_add_return(1, &drbd_nl_seq);
+ cn_reply->ack = 0; /* not used here. */
+ cn_reply->len = sizeof(struct drbd_nl_cfg_reply) +
+ (int)((char *)tl - (char *)reply->tag_list);
+ cn_reply->flags = 0;
+
+ reply->packet_type = P_sync_progress;
+ reply->minor = mdev_to_minor(mdev);
+ reply->ret_code = NO_ERROR;
+
+ cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_NOIO);
+}
+
+int __init drbd_nl_init(void)
+{
+ static struct cb_id cn_id_drbd;
+ int err, try=10;
+
+ cn_id_drbd.val = CN_VAL_DRBD;
+ do {
+ cn_id_drbd.idx = cn_idx;
+ err = cn_add_callback(&cn_id_drbd, "cn_drbd", &drbd_connector_callback);
+ if (!err)
+ break;
+ cn_idx = (cn_idx + CN_IDX_STEP);
+ } while (try--);
+
+ if (err) {
+ printk(KERN_ERR "drbd: cn_drbd failed to register\n");
+ return err;
+ }
+
+ return 0;
+}
+
+void drbd_nl_cleanup(void)
+{
+ static struct cb_id cn_id_drbd;
+
+ cn_id_drbd.idx = cn_idx;
+ cn_id_drbd.val = CN_VAL_DRBD;
+
+ cn_del_callback(&cn_id_drbd);
+}
+
+void drbd_nl_send_reply(struct cn_msg *req, int ret_code)
+{
+ char buffer[sizeof(struct cn_msg)+sizeof(struct drbd_nl_cfg_reply)];
+ struct cn_msg *cn_reply = (struct cn_msg *) buffer;
+ struct drbd_nl_cfg_reply *reply =
+ (struct drbd_nl_cfg_reply *)cn_reply->data;
+ int rr;
+
+ cn_reply->id = req->id;
+
+ cn_reply->seq = req->seq;
+ cn_reply->ack = req->ack + 1;
+ cn_reply->len = sizeof(struct drbd_nl_cfg_reply);
+ cn_reply->flags = 0;
+
+ reply->minor = ((struct drbd_nl_cfg_req *)req->data)->drbd_minor;
+ reply->ret_code = ret_code;
+
+ rr = cn_netlink_send(cn_reply, CN_IDX_DRBD, GFP_NOIO);
+ if (rr && rr != -ESRCH)
+ printk(KERN_INFO "drbd: cn_netlink_send()=%d\n", rr);
+}
+
diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c
new file mode 100644
index 000000000000..bdd0b4943b10
--- /dev/null
+++ b/drivers/block/drbd/drbd_proc.c
@@ -0,0 +1,265 @@
+/*
+ drbd_proc.c
+
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+ Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+ drbd 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.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT 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 drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/module.h>
+
+#include <asm/uaccess.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/drbd.h>
+#include "drbd_int.h"
+
+static int drbd_proc_open(struct inode *inode, struct file *file);
+
+
+struct proc_dir_entry *drbd_proc;
+struct file_operations drbd_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = drbd_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+
+/*lge
+ * progress bars shamelessly adapted from driver/md/md.c
+ * output looks like
+ * [=====>..............] 33.5% (23456/123456)
+ * finish: 2:20:20 speed: 6,345 (6,456) K/sec
+ */
+static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq)
+{
+ unsigned long db, dt, dbdt, rt, rs_left;
+ unsigned int res;
+ int i, x, y;
+
+ drbd_get_syncer_progress(mdev, &rs_left, &res);
+
+ x = res/50;
+ y = 20-x;
+ seq_printf(seq, "\t[");
+ for (i = 1; i < x; i++)
+ seq_printf(seq, "=");
+ seq_printf(seq, ">");
+ for (i = 0; i < y; i++)
+ seq_printf(seq, ".");
+ seq_printf(seq, "] ");
+
+ seq_printf(seq, "sync'ed:%3u.%u%% ", res / 10, res % 10);
+ /* if more than 1 GB display in MB */
+ if (mdev->rs_total > 0x100000L)
+ seq_printf(seq, "(%lu/%lu)M\n\t",
+ (unsigned long) Bit2KB(rs_left >> 10),
+ (unsigned long) Bit2KB(mdev->rs_total >> 10));
+ else
+ seq_printf(seq, "(%lu/%lu)K\n\t",
+ (unsigned long) Bit2KB(rs_left),
+ (unsigned long) Bit2KB(mdev->rs_total));
+
+ /* see drivers/md/md.c
+ * We do not want to overflow, so the order of operands and
+ * the * 100 / 100 trick are important. We do a +1 to be
+ * safe against division by zero. We only estimate anyway.
+ *
+ * dt: time from mark until now
+ * db: blocks written from mark until now
+ * rt: remaining time
+ */
+ dt = (jiffies - mdev->rs_mark_time) / HZ;
+
+ if (dt > 20) {
+ /* if we made no update to rs_mark_time for too long,
+ * we are stalled. show that. */
+ seq_printf(seq, "stalled\n");
+ return;
+ }
+
+ if (!dt)
+ dt++;
+ db = mdev->rs_mark_left - rs_left;
+ rt = (dt * (rs_left / (db/100+1)))/100; /* seconds */
+
+ seq_printf(seq, "finish: %lu:%02lu:%02lu",
+ rt / 3600, (rt % 3600) / 60, rt % 60);
+
+ /* current speed average over (SYNC_MARKS * SYNC_MARK_STEP) jiffies */
+ dbdt = Bit2KB(db/dt);
+ if (dbdt > 1000)
+ seq_printf(seq, " speed: %ld,%03ld",
+ dbdt/1000, dbdt % 1000);
+ else
+ seq_printf(seq, " speed: %ld", dbdt);
+
+ /* mean speed since syncer started
+ * we do account for PausedSync periods */
+ dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ;
+ if (dt <= 0)
+ dt = 1;
+ db = mdev->rs_total - rs_left;
+ dbdt = Bit2KB(db/dt);
+ if (dbdt > 1000)
+ seq_printf(seq, " (%ld,%03ld)",
+ dbdt/1000, dbdt % 1000);
+ else
+ seq_printf(seq, " (%ld)", dbdt);
+
+ seq_printf(seq, " K/sec\n");
+}
+
+static void resync_dump_detail(struct seq_file *seq, struct lc_element *e)
+{
+ struct bm_extent *bme = lc_entry(e, struct bm_extent, lce);
+
+ seq_printf(seq, "%5d %s %s\n", bme->rs_left,
+ bme->flags & BME_NO_WRITES ? "NO_WRITES" : "---------",
+ bme->flags & BME_LOCKED ? "LOCKED" : "------"
+ );
+}
+
+static int drbd_seq_show(struct seq_file *seq, void *v)
+{
+ int i, hole = 0;
+ const char *sn;
+ struct drbd_conf *mdev;
+
+ static char write_ordering_chars[] = {
+ [WO_none] = 'n',
+ [WO_drain_io] = 'd',
+ [WO_bdev_flush] = 'f',
+ [WO_bio_barrier] = 'b',
+ };
+
+ seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n",
+ API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX, drbd_buildtag());
+
+ /*
+ cs .. connection state
+ ro .. node role (local/remote)
+ ds .. disk state (local/remote)
+ protocol
+ various flags
+ ns .. network send
+ nr .. network receive
+ dw .. disk write
+ dr .. disk read
+ al .. activity log write count
+ bm .. bitmap update write count
+ pe .. pending (waiting for ack or data reply)
+ ua .. unack'd (still need to send ack or data reply)
+ ap .. application requests accepted, but not yet completed
+ ep .. number of epochs currently "on the fly", P_BARRIER_ACK pending
+ wo .. write ordering mode currently in use
+ oos .. known out-of-sync kB
+ */
+
+ for (i = 0; i < minor_count; i++) {
+ mdev = minor_to_mdev(i);
+ if (!mdev) {
+ hole = 1;
+ continue;
+ }
+ if (hole) {
+ hole = 0;
+ seq_printf(seq, "\n");
+ }
+
+ sn = drbd_conn_str(mdev->state.conn);
+
+ if (mdev->state.conn == C_STANDALONE &&
+ mdev->state.disk == D_DISKLESS &&
+ mdev->state.role == R_SECONDARY) {
+ seq_printf(seq, "%2d: cs:Unconfigured\n", i);
+ } else {
+ seq_printf(seq,
+ "%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c\n"
+ " ns:%u nr:%u dw:%u dr:%u al:%u bm:%u "
+ "lo:%d pe:%d ua:%d ap:%d ep:%d wo:%c",
+ i, sn,
+ drbd_role_str(mdev->state.role),
+ drbd_role_str(mdev->state.peer),
+ drbd_disk_str(mdev->state.disk),
+ drbd_disk_str(mdev->state.pdsk),
+ (mdev->net_conf == NULL ? ' ' :
+ (mdev->net_conf->wire_protocol - DRBD_PROT_A+'A')),
+ mdev->state.susp ? 's' : 'r',
+ mdev->state.aftr_isp ? 'a' : '-',
+ mdev->state.peer_isp ? 'p' : '-',
+ mdev->state.user_isp ? 'u' : '-',
+ mdev->congestion_reason ?: '-',
+ mdev->send_cnt/2,
+ mdev->recv_cnt/2,
+ mdev->writ_cnt/2,
+ mdev->read_cnt/2,
+ mdev->al_writ_cnt,
+ mdev->bm_writ_cnt,
+ atomic_read(&mdev->local_cnt),
+ atomic_read(&mdev->ap_pending_cnt) +
+ atomic_read(&mdev->rs_pending_cnt),
+ atomic_read(&mdev->unacked_cnt),
+ atomic_read(&mdev->ap_bio_cnt),
+ mdev->epochs,
+ write_ordering_chars[mdev->write_ordering]
+ );
+ seq_printf(seq, " oos:%lu\n",
+ Bit2KB(drbd_bm_total_weight(mdev)));
+ }
+ if (mdev->state.conn == C_SYNC_SOURCE ||
+ mdev->state.conn == C_SYNC_TARGET)
+ drbd_syncer_progress(mdev, seq);
+
+ if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T)
+ seq_printf(seq, "\t%3d%% %lu/%lu\n",
+ (int)((mdev->rs_total-mdev->ov_left) /
+ (mdev->rs_total/100+1)),
+ mdev->rs_total - mdev->ov_left,
+ mdev->rs_total);
+
+ if (proc_details >= 1 && get_ldev_if_state(mdev, D_FAILED)) {
+ lc_seq_printf_stats(seq, mdev->resync);
+ lc_seq_printf_stats(seq, mdev->act_log);
+ put_ldev(mdev);
+ }
+
+ if (proc_details >= 2) {
+ if (mdev->resync) {
+ lc_seq_dump_details(seq, mdev->resync, "rs_left",
+ resync_dump_detail);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int drbd_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, drbd_seq_show, PDE(inode)->data);
+}
+
+/* PROC FS stuff end */
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
new file mode 100644
index 000000000000..360baf60f574
--- /dev/null
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -0,0 +1,4427 @@
+/*
+ drbd_receiver.c
+
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+ Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+ drbd 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.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT 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 drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+
+#include <asm/uaccess.h>
+#include <net/sock.h>
+
+#include <linux/version.h>
+#include <linux/drbd.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/in.h>
+#include <linux/mm.h>
+#include <linux/memcontrol.h>
+#include <linux/mm_inline.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/pkt_sched.h>
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+#include <linux/vmalloc.h>
+#include <linux/random.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/scatterlist.h>
+#include "drbd_int.h"
+#include "drbd_req.h"
+
+#include "drbd_vli.h"
+
+struct flush_work {
+ struct drbd_work w;
+ struct drbd_epoch *epoch;
+};
+
+enum finish_epoch {
+ FE_STILL_LIVE,
+ FE_DESTROYED,
+ FE_RECYCLED,
+};
+
+static int drbd_do_handshake(struct drbd_conf *mdev);
+static int drbd_do_auth(struct drbd_conf *mdev);
+
+static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *, struct drbd_epoch *, enum epoch_event);
+static int e_end_block(struct drbd_conf *, struct drbd_work *, int);
+
+static struct drbd_epoch *previous_epoch(struct drbd_conf *mdev, struct drbd_epoch *epoch)
+{
+ struct drbd_epoch *prev;
+ spin_lock(&mdev->epoch_lock);
+ prev = list_entry(epoch->list.prev, struct drbd_epoch, list);
+ if (prev == epoch || prev == mdev->current_epoch)
+ prev = NULL;
+ spin_unlock(&mdev->epoch_lock);
+ return prev;
+}
+
+#define GFP_TRY (__GFP_HIGHMEM | __GFP_NOWARN)
+
+static struct page *drbd_pp_first_page_or_try_alloc(struct drbd_conf *mdev)
+{
+ struct page *page = NULL;
+
+ /* Yes, testing drbd_pp_vacant outside the lock is racy.
+ * So what. It saves a spin_lock. */
+ if (drbd_pp_vacant > 0) {
+ spin_lock(&drbd_pp_lock);
+ page = drbd_pp_pool;
+ if (page) {
+ drbd_pp_pool = (struct page *)page_private(page);
+ set_page_private(page, 0); /* just to be polite */
+ drbd_pp_vacant--;
+ }
+ spin_unlock(&drbd_pp_lock);
+ }
+ /* GFP_TRY, because we must not cause arbitrary write-out: in a DRBD
+ * "criss-cross" setup, that might cause write-out on some other DRBD,
+ * which in turn might block on the other node at this very place. */
+ if (!page)
+ page = alloc_page(GFP_TRY);
+ if (page)
+ atomic_inc(&mdev->pp_in_use);
+ return page;
+}
+
+/* kick lower level device, if we have more than (arbitrary number)
+ * reference counts on it, which typically are locally submitted io
+ * requests. don't use unacked_cnt, so we speed up proto A and B, too. */
+static void maybe_kick_lo(struct drbd_conf *mdev)
+{
+ if (atomic_read(&mdev->local_cnt) >= mdev->net_conf->unplug_watermark)
+ drbd_kick_lo(mdev);
+}
+
+static void reclaim_net_ee(struct drbd_conf *mdev, struct list_head *to_be_freed)
+{
+ struct drbd_epoch_entry *e;
+ struct list_head *le, *tle;
+
+ /* The EEs are always appended to the end of the list. Since
+ they are sent in order over the wire, they have to finish
+ in order. As soon as we see the first not finished we can
+ stop to examine the list... */
+
+ list_for_each_safe(le, tle, &mdev->net_ee) {
+ e = list_entry(le, struct drbd_epoch_entry, w.list);
+ if (drbd_bio_has_active_page(e->private_bio))
+ break;
+ list_move(le, to_be_freed);
+ }
+}
+
+static void drbd_kick_lo_and_reclaim_net(struct drbd_conf *mdev)
+{
+ LIST_HEAD(reclaimed);
+ struct drbd_epoch_entry *e, *t;
+
+ maybe_kick_lo(mdev);
+ spin_lock_irq(&mdev->req_lock);
+ reclaim_net_ee(mdev, &reclaimed);
+ spin_unlock_irq(&mdev->req_lock);
+
+ list_for_each_entry_safe(e, t, &reclaimed, w.list)
+ drbd_free_ee(mdev, e);
+}
+
+/**
+ * drbd_pp_alloc() - Returns a page, fails only if a signal comes in
+ * @mdev: DRBD device.
+ * @retry: whether or not to retry allocation forever (or until signalled)
+ *
+ * Tries to allocate a page, first from our own page pool, then from the
+ * kernel, unless this allocation would exceed the max_buffers setting.
+ * If @retry is non-zero, retry until DRBD frees a page somewhere else.
+ */
+static struct page *drbd_pp_alloc(struct drbd_conf *mdev, int retry)
+{
+ struct page *page = NULL;
+ DEFINE_WAIT(wait);
+
+ if (atomic_read(&mdev->pp_in_use) < mdev->net_conf->max_buffers) {
+ page = drbd_pp_first_page_or_try_alloc(mdev);
+ if (page)
+ return page;
+ }
+
+ for (;;) {
+ prepare_to_wait(&drbd_pp_wait, &wait, TASK_INTERRUPTIBLE);
+
+ drbd_kick_lo_and_reclaim_net(mdev);
+
+ if (atomic_read(&mdev->pp_in_use) < mdev->net_conf->max_buffers) {
+ page = drbd_pp_first_page_or_try_alloc(mdev);
+ if (page)
+ break;
+ }
+
+ if (!retry)
+ break;
+
+ if (signal_pending(current)) {
+ dev_warn(DEV, "drbd_pp_alloc interrupted!\n");
+ break;
+ }
+
+ schedule();
+ }
+ finish_wait(&drbd_pp_wait, &wait);
+
+ return page;
+}
+
+/* Must not be used from irq, as that may deadlock: see drbd_pp_alloc.
+ * Is also used from inside an other spin_lock_irq(&mdev->req_lock) */
+static void drbd_pp_free(struct drbd_conf *mdev, struct page *page)
+{
+ int free_it;
+
+ spin_lock(&drbd_pp_lock);
+ if (drbd_pp_vacant > (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE)*minor_count) {
+ free_it = 1;
+ } else {
+ set_page_private(page, (unsigned long)drbd_pp_pool);
+ drbd_pp_pool = page;
+ drbd_pp_vacant++;
+ free_it = 0;
+ }
+ spin_unlock(&drbd_pp_lock);
+
+ atomic_dec(&mdev->pp_in_use);
+
+ if (free_it)
+ __free_page(page);
+
+ wake_up(&drbd_pp_wait);
+}
+
+static void drbd_pp_free_bio_pages(struct drbd_conf *mdev, struct bio *bio)
+{
+ struct page *p_to_be_freed = NULL;
+ struct page *page;
+ struct bio_vec *bvec;
+ int i;
+
+ spin_lock(&drbd_pp_lock);
+ __bio_for_each_segment(bvec, bio, i, 0) {
+ if (drbd_pp_vacant > (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE)*minor_count) {
+ set_page_private(bvec->bv_page, (unsigned long)p_to_be_freed);
+ p_to_be_freed = bvec->bv_page;
+ } else {
+ set_page_private(bvec->bv_page, (unsigned long)drbd_pp_pool);
+ drbd_pp_pool = bvec->bv_page;
+ drbd_pp_vacant++;
+ }
+ }
+ spin_unlock(&drbd_pp_lock);
+ atomic_sub(bio->bi_vcnt, &mdev->pp_in_use);
+
+ while (p_to_be_freed) {
+ page = p_to_be_freed;
+ p_to_be_freed = (struct page *)page_private(page);
+ set_page_private(page, 0); /* just to be polite */
+ put_page(page);
+ }
+
+ wake_up(&drbd_pp_wait);
+}
+
+/*
+You need to hold the req_lock:
+ _drbd_wait_ee_list_empty()
+
+You must not have the req_lock:
+ drbd_free_ee()
+ drbd_alloc_ee()
+ drbd_init_ee()
+ drbd_release_ee()
+ drbd_ee_fix_bhs()
+ drbd_process_done_ee()
+ drbd_clear_done_ee()
+ drbd_wait_ee_list_empty()
+*/
+
+struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev,
+ u64 id,
+ sector_t sector,
+ unsigned int data_size,
+ gfp_t gfp_mask) __must_hold(local)
+{
+ struct request_queue *q;
+ struct drbd_epoch_entry *e;
+ struct page *page;
+ struct bio *bio;
+ unsigned int ds;
+
+ if (FAULT_ACTIVE(mdev, DRBD_FAULT_AL_EE))
+ return NULL;
+
+ e = mempool_alloc(drbd_ee_mempool, gfp_mask & ~__GFP_HIGHMEM);
+ if (!e) {
+ if (!(gfp_mask & __GFP_NOWARN))
+ dev_err(DEV, "alloc_ee: Allocation of an EE failed\n");
+ return NULL;
+ }
+
+ bio = bio_alloc(gfp_mask & ~__GFP_HIGHMEM, div_ceil(data_size, PAGE_SIZE));
+ if (!bio) {
+ if (!(gfp_mask & __GFP_NOWARN))
+ dev_err(DEV, "alloc_ee: Allocation of a bio failed\n");
+ goto fail1;
+ }
+
+ bio->bi_bdev = mdev->ldev->backing_bdev;
+ bio->bi_sector = sector;
+
+ ds = data_size;
+ while (ds) {
+ page = drbd_pp_alloc(mdev, (gfp_mask & __GFP_WAIT));
+ if (!page) {
+ if (!(gfp_mask & __GFP_NOWARN))
+ dev_err(DEV, "alloc_ee: Allocation of a page failed\n");
+ goto fail2;
+ }
+ if (!bio_add_page(bio, page, min_t(int, ds, PAGE_SIZE), 0)) {
+ drbd_pp_free(mdev, page);
+ dev_err(DEV, "alloc_ee: bio_add_page(s=%llu,"
+ "data_size=%u,ds=%u) failed\n",
+ (unsigned long long)sector, data_size, ds);
+
+ q = bdev_get_queue(bio->bi_bdev);
+ if (q->merge_bvec_fn) {
+ struct bvec_merge_data bvm = {
+ .bi_bdev = bio->bi_bdev,
+ .bi_sector = bio->bi_sector,
+ .bi_size = bio->bi_size,
+ .bi_rw = bio->bi_rw,
+ };
+ int l = q->merge_bvec_fn(q, &bvm,
+ &bio->bi_io_vec[bio->bi_vcnt]);
+ dev_err(DEV, "merge_bvec_fn() = %d\n", l);
+ }
+
+ /* dump more of the bio. */
+ dev_err(DEV, "bio->bi_max_vecs = %d\n", bio->bi_max_vecs);
+ dev_err(DEV, "bio->bi_vcnt = %d\n", bio->bi_vcnt);
+ dev_err(DEV, "bio->bi_size = %d\n", bio->bi_size);
+ dev_err(DEV, "bio->bi_phys_segments = %d\n", bio->bi_phys_segments);
+
+ goto fail2;
+ break;
+ }
+ ds -= min_t(int, ds, PAGE_SIZE);
+ }
+
+ D_ASSERT(data_size == bio->bi_size);
+
+ bio->bi_private = e;
+ e->mdev = mdev;
+ e->sector = sector;
+ e->size = bio->bi_size;
+
+ e->private_bio = bio;
+ e->block_id = id;
+ INIT_HLIST_NODE(&e->colision);
+ e->epoch = NULL;
+ e->flags = 0;
+
+ return e;
+
+ fail2:
+ drbd_pp_free_bio_pages(mdev, bio);
+ bio_put(bio);
+ fail1:
+ mempool_free(e, drbd_ee_mempool);
+
+ return NULL;
+}
+
+void drbd_free_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e)
+{
+ struct bio *bio = e->private_bio;
+ drbd_pp_free_bio_pages(mdev, bio);
+ bio_put(bio);
+ D_ASSERT(hlist_unhashed(&e->colision));
+ mempool_free(e, drbd_ee_mempool);
+}
+
+int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list)
+{
+ LIST_HEAD(work_list);
+ struct drbd_epoch_entry *e, *t;
+ int count = 0;
+
+ spin_lock_irq(&mdev->req_lock);
+ list_splice_init(list, &work_list);
+ spin_unlock_irq(&mdev->req_lock);
+
+ list_for_each_entry_safe(e, t, &work_list, w.list) {
+ drbd_free_ee(mdev, e);
+ count++;
+ }
+ return count;
+}
+
+
+/*
+ * This function is called from _asender only_
+ * but see also comments in _req_mod(,barrier_acked)
+ * and receive_Barrier.
+ *
+ * Move entries from net_ee to done_ee, if ready.
+ * Grab done_ee, call all callbacks, free the entries.
+ * The callbacks typically send out ACKs.
+ */
+static int drbd_process_done_ee(struct drbd_conf *mdev)
+{
+ LIST_HEAD(work_list);
+ LIST_HEAD(reclaimed);
+ struct drbd_epoch_entry *e, *t;
+ int ok = (mdev->state.conn >= C_WF_REPORT_PARAMS);
+
+ spin_lock_irq(&mdev->req_lock);
+ reclaim_net_ee(mdev, &reclaimed);
+ list_splice_init(&mdev->done_ee, &work_list);
+ spin_unlock_irq(&mdev->req_lock);
+
+ list_for_each_entry_safe(e, t, &reclaimed, w.list)
+ drbd_free_ee(mdev, e);
+
+ /* possible callbacks here:
+ * e_end_block, and e_end_resync_block, e_send_discard_ack.
+ * all ignore the last argument.
+ */
+ list_for_each_entry_safe(e, t, &work_list, w.list) {
+ /* list_del not necessary, next/prev members not touched */
+ ok = e->w.cb(mdev, &e->w, !ok) && ok;
+ drbd_free_ee(mdev, e);
+ }
+ wake_up(&mdev->ee_wait);
+
+ return ok;
+}
+
+void _drbd_wait_ee_list_empty(struct drbd_conf *mdev, struct list_head *head)
+{
+ DEFINE_WAIT(wait);
+
+ /* avoids spin_lock/unlock
+ * and calling prepare_to_wait in the fast path */
+ while (!list_empty(head)) {
+ prepare_to_wait(&mdev->ee_wait, &wait, TASK_UNINTERRUPTIBLE);
+ spin_unlock_irq(&mdev->req_lock);
+ drbd_kick_lo(mdev);
+ schedule();
+ finish_wait(&mdev->ee_wait, &wait);
+ spin_lock_irq(&mdev->req_lock);
+ }
+}
+
+void drbd_wait_ee_list_empty(struct drbd_conf *mdev, struct list_head *head)
+{
+ spin_lock_irq(&mdev->req_lock);
+ _drbd_wait_ee_list_empty(mdev, head);
+ spin_unlock_irq(&mdev->req_lock);
+}
+
+/* see also kernel_accept; which is only present since 2.6.18.
+ * also we want to log which part of it failed, exactly */
+static int drbd_accept(struct drbd_conf *mdev, const char **what,
+ struct socket *sock, struct socket **newsock)
+{
+ struct sock *sk = sock->sk;
+ int err = 0;
+
+ *what = "listen";
+ err = sock->ops->listen(sock, 5);
+ if (err < 0)
+ goto out;
+
+ *what = "sock_create_lite";
+ err = sock_create_lite(sk->sk_family, sk->sk_type, sk->sk_protocol,
+ newsock);
+ if (err < 0)
+ goto out;
+
+ *what = "accept";
+ err = sock->ops->accept(sock, *newsock, 0);
+ if (err < 0) {
+ sock_release(*newsock);
+ *newsock = NULL;
+ goto out;
+ }
+ (*newsock)->ops = sock->ops;
+
+out:
+ return err;
+}
+
+static int drbd_recv_short(struct drbd_conf *mdev, struct socket *sock,
+ void *buf, size_t size, int flags)
+{
+ mm_segment_t oldfs;
+ struct kvec iov = {
+ .iov_base = buf,
+ .iov_len = size,
+ };
+ struct msghdr msg = {
+ .msg_iovlen = 1,
+ .msg_iov = (struct iovec *)&iov,
+ .msg_flags = (flags ? flags : MSG_WAITALL | MSG_NOSIGNAL)
+ };
+ int rv;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ rv = sock_recvmsg(sock, &msg, size, msg.msg_flags);
+ set_fs(oldfs);
+
+ return rv;
+}
+
+static int drbd_recv(struct drbd_conf *mdev, void *buf, size_t size)
+{
+ mm_segment_t oldfs;
+ struct kvec iov = {
+ .iov_base = buf,
+ .iov_len = size,
+ };
+ struct msghdr msg = {
+ .msg_iovlen = 1,
+ .msg_iov = (struct iovec *)&iov,
+ .msg_flags = MSG_WAITALL | MSG_NOSIGNAL
+ };
+ int rv;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ for (;;) {
+ rv = sock_recvmsg(mdev->data.socket, &msg, size, msg.msg_flags);
+ if (rv == size)
+ break;
+
+ /* Note:
+ * ECONNRESET other side closed the connection
+ * ERESTARTSYS (on sock) we got a signal
+ */
+
+ if (rv < 0) {
+ if (rv == -ECONNRESET)
+ dev_info(DEV, "sock was reset by peer\n");
+ else if (rv != -ERESTARTSYS)
+ dev_err(DEV, "sock_recvmsg returned %d\n", rv);
+ break;
+ } else if (rv == 0) {
+ dev_info(DEV, "sock was shut down by peer\n");
+ break;
+ } else {
+ /* signal came in, or peer/link went down,
+ * after we read a partial message
+ */
+ /* D_ASSERT(signal_pending(current)); */
+ break;
+ }
+ };
+
+ set_fs(oldfs);
+
+ if (rv != size)
+ drbd_force_state(mdev, NS(conn, C_BROKEN_PIPE));
+
+ return rv;
+}
+
+static struct socket *drbd_try_connect(struct drbd_conf *mdev)
+{
+ const char *what;
+ struct socket *sock;
+ struct sockaddr_in6 src_in6;
+ int err;
+ int disconnect_on_error = 1;
+
+ if (!get_net_conf(mdev))
+ return NULL;
+
+ what = "sock_create_kern";
+ err = sock_create_kern(((struct sockaddr *)mdev->net_conf->my_addr)->sa_family,
+ SOCK_STREAM, IPPROTO_TCP, &sock);
+ if (err < 0) {
+ sock = NULL;
+ goto out;
+ }
+
+ sock->sk->sk_rcvtimeo =
+ sock->sk->sk_sndtimeo = mdev->net_conf->try_connect_int*HZ;
+
+ /* explicitly bind to the configured IP as source IP
+ * for the outgoing connections.
+ * This is needed for multihomed hosts and to be
+ * able to use lo: interfaces for drbd.
+ * Make sure to use 0 as port number, so linux selects
+ * a free one dynamically.
+ */
+ memcpy(&src_in6, mdev->net_conf->my_addr,
+ min_t(int, mdev->net_conf->my_addr_len, sizeof(src_in6)));
+ if (((struct sockaddr *)mdev->net_conf->my_addr)->sa_family == AF_INET6)
+ src_in6.sin6_port = 0;
+ else
+ ((struct sockaddr_in *)&src_in6)->sin_port = 0; /* AF_INET & AF_SCI */
+
+ what = "bind before connect";
+ err = sock->ops->bind(sock,
+ (struct sockaddr *) &src_in6,
+ mdev->net_conf->my_addr_len);
+ if (err < 0)
+ goto out;
+
+ /* connect may fail, peer not yet available.
+ * stay C_WF_CONNECTION, don't go Disconnecting! */
+ disconnect_on_error = 0;
+ what = "connect";
+ err = sock->ops->connect(sock,
+ (struct sockaddr *)mdev->net_conf->peer_addr,
+ mdev->net_conf->peer_addr_len, 0);
+
+out:
+ if (err < 0) {
+ if (sock) {
+ sock_release(sock);
+ sock = NULL;
+ }
+ switch (-err) {
+ /* timeout, busy, signal pending */
+ case ETIMEDOUT: case EAGAIN: case EINPROGRESS:
+ case EINTR: case ERESTARTSYS:
+ /* peer not (yet) available, network problem */
+ case ECONNREFUSED: case ENETUNREACH:
+ case EHOSTDOWN: case EHOSTUNREACH:
+ disconnect_on_error = 0;
+ break;
+ default:
+ dev_err(DEV, "%s failed, err = %d\n", what, err);
+ }
+ if (disconnect_on_error)
+ drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+ }
+ put_net_conf(mdev);
+ return sock;
+}
+
+static struct socket *drbd_wait_for_connect(struct drbd_conf *mdev)
+{
+ int timeo, err;
+ struct socket *s_estab = NULL, *s_listen;
+ const char *what;
+
+ if (!get_net_conf(mdev))
+ return NULL;
+
+ what = "sock_create_kern";
+ err = sock_create_kern(((struct sockaddr *)mdev->net_conf->my_addr)->sa_family,
+ SOCK_STREAM, IPPROTO_TCP, &s_listen);
+ if (err) {
+ s_listen = NULL;
+ goto out;
+ }
+
+ timeo = mdev->net_conf->try_connect_int * HZ;
+ timeo += (random32() & 1) ? timeo / 7 : -timeo / 7; /* 28.5% random jitter */
+
+ s_listen->sk->sk_reuse = 1; /* SO_REUSEADDR */
+ s_listen->sk->sk_rcvtimeo = timeo;
+ s_listen->sk->sk_sndtimeo = timeo;
+
+ what = "bind before listen";
+ err = s_listen->ops->bind(s_listen,
+ (struct sockaddr *) mdev->net_conf->my_addr,
+ mdev->net_conf->my_addr_len);
+ if (err < 0)
+ goto out;
+
+ err = drbd_accept(mdev, &what, s_listen, &s_estab);
+
+out:
+ if (s_listen)
+ sock_release(s_listen);
+ if (err < 0) {
+ if (err != -EAGAIN && err != -EINTR && err != -ERESTARTSYS) {
+ dev_err(DEV, "%s failed, err = %d\n", what, err);
+ drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+ }
+ }
+ put_net_conf(mdev);
+
+ return s_estab;
+}
+
+static int drbd_send_fp(struct drbd_conf *mdev,
+ struct socket *sock, enum drbd_packets cmd)
+{
+ struct p_header *h = (struct p_header *) &mdev->data.sbuf.header;
+
+ return _drbd_send_cmd(mdev, sock, cmd, h, sizeof(*h), 0);
+}
+
+static enum drbd_packets drbd_recv_fp(struct drbd_conf *mdev, struct socket *sock)
+{
+ struct p_header *h = (struct p_header *) &mdev->data.sbuf.header;
+ int rr;
+
+ rr = drbd_recv_short(mdev, sock, h, sizeof(*h), 0);
+
+ if (rr == sizeof(*h) && h->magic == BE_DRBD_MAGIC)
+ return be16_to_cpu(h->command);
+
+ return 0xffff;
+}
+
+/**
+ * drbd_socket_okay() - Free the socket if its connection is not okay
+ * @mdev: DRBD device.
+ * @sock: pointer to the pointer to the socket.
+ */
+static int drbd_socket_okay(struct drbd_conf *mdev, struct socket **sock)
+{
+ int rr;
+ char tb[4];
+
+ if (!*sock)
+ return FALSE;
+
+ rr = drbd_recv_short(mdev, *sock, tb, 4, MSG_DONTWAIT | MSG_PEEK);
+
+ if (rr > 0 || rr == -EAGAIN) {
+ return TRUE;
+ } else {
+ sock_release(*sock);
+ *sock = NULL;
+ return FALSE;
+ }
+}
+
+/*
+ * return values:
+ * 1 yes, we have a valid connection
+ * 0 oops, did not work out, please try again
+ * -1 peer talks different language,
+ * no point in trying again, please go standalone.
+ * -2 We do not have a network config...
+ */
+static int drbd_connect(struct drbd_conf *mdev)
+{
+ struct socket *s, *sock, *msock;
+ int try, h, ok;
+
+ D_ASSERT(!mdev->data.socket);
+
+ if (test_and_clear_bit(CREATE_BARRIER, &mdev->flags))
+ dev_err(DEV, "CREATE_BARRIER flag was set in drbd_connect - now cleared!\n");
+
+ if (drbd_request_state(mdev, NS(conn, C_WF_CONNECTION)) < SS_SUCCESS)
+ return -2;
+
+ clear_bit(DISCARD_CONCURRENT, &mdev->flags);
+
+ sock = NULL;
+ msock = NULL;
+
+ do {
+ for (try = 0;;) {
+ /* 3 tries, this should take less than a second! */
+ s = drbd_try_connect(mdev);
+ if (s || ++try >= 3)
+ break;
+ /* give the other side time to call bind() & listen() */
+ __set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ / 10);
+ }
+
+ if (s) {
+ if (!sock) {
+ drbd_send_fp(mdev, s, P_HAND_SHAKE_S);
+ sock = s;
+ s = NULL;
+ } else if (!msock) {
+ drbd_send_fp(mdev, s, P_HAND_SHAKE_M);
+ msock = s;
+ s = NULL;
+ } else {
+ dev_err(DEV, "Logic error in drbd_connect()\n");
+ goto out_release_sockets;
+ }
+ }
+
+ if (sock && msock) {
+ __set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ / 10);
+ ok = drbd_socket_okay(mdev, &sock);
+ ok = drbd_socket_okay(mdev, &msock) && ok;
+ if (ok)
+ break;
+ }
+
+retry:
+ s = drbd_wait_for_connect(mdev);
+ if (s) {
+ try = drbd_recv_fp(mdev, s);
+ drbd_socket_okay(mdev, &sock);
+ drbd_socket_okay(mdev, &msock);
+ switch (try) {
+ case P_HAND_SHAKE_S:
+ if (sock) {
+ dev_warn(DEV, "initial packet S crossed\n");
+ sock_release(sock);
+ }
+ sock = s;
+ break;
+ case P_HAND_SHAKE_M:
+ if (msock) {
+ dev_warn(DEV, "initial packet M crossed\n");
+ sock_release(msock);
+ }
+ msock = s;
+ set_bit(DISCARD_CONCURRENT, &mdev->flags);
+ break;
+ default:
+ dev_warn(DEV, "Error receiving initial packet\n");
+ sock_release(s);
+ if (random32() & 1)
+ goto retry;
+ }
+ }
+
+ if (mdev->state.conn <= C_DISCONNECTING)
+ goto out_release_sockets;
+ if (signal_pending(current)) {
+ flush_signals(current);
+ smp_rmb();
+ if (get_t_state(&mdev->receiver) == Exiting)
+ goto out_release_sockets;
+ }
+
+ if (sock && msock) {
+ ok = drbd_socket_okay(mdev, &sock);
+ ok = drbd_socket_okay(mdev, &msock) && ok;
+ if (ok)
+ break;
+ }
+ } while (1);
+
+ msock->sk->sk_reuse = 1; /* SO_REUSEADDR */
+ sock->sk->sk_reuse = 1; /* SO_REUSEADDR */
+
+ sock->sk->sk_allocation = GFP_NOIO;
+ msock->sk->sk_allocation = GFP_NOIO;
+
+ sock->sk->sk_priority = TC_PRIO_INTERACTIVE_BULK;
+ msock->sk->sk_priority = TC_PRIO_INTERACTIVE;
+
+ if (mdev->net_conf->sndbuf_size) {
+ sock->sk->sk_sndbuf = mdev->net_conf->sndbuf_size;
+ sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
+ }
+
+ if (mdev->net_conf->rcvbuf_size) {
+ sock->sk->sk_rcvbuf = mdev->net_conf->rcvbuf_size;
+ sock->sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
+ }
+
+ /* NOT YET ...
+ * sock->sk->sk_sndtimeo = mdev->net_conf->timeout*HZ/10;
+ * sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT;
+ * first set it to the P_HAND_SHAKE timeout,
+ * which we set to 4x the configured ping_timeout. */
+ sock->sk->sk_sndtimeo =
+ sock->sk->sk_rcvtimeo = mdev->net_conf->ping_timeo*4*HZ/10;
+
+ msock->sk->sk_sndtimeo = mdev->net_conf->timeout*HZ/10;
+ msock->sk->sk_rcvtimeo = mdev->net_conf->ping_int*HZ;
+
+ /* we don't want delays.
+ * we use TCP_CORK where apropriate, though */
+ drbd_tcp_nodelay(sock);
+ drbd_tcp_nodelay(msock);
+
+ mdev->data.socket = sock;
+ mdev->meta.socket = msock;
+ mdev->last_received = jiffies;
+
+ D_ASSERT(mdev->asender.task == NULL);
+
+ h = drbd_do_handshake(mdev);
+ if (h <= 0)
+ return h;
+
+ if (mdev->cram_hmac_tfm) {
+ /* drbd_request_state(mdev, NS(conn, WFAuth)); */
+ if (!drbd_do_auth(mdev)) {
+ dev_err(DEV, "Authentication of peer failed\n");
+ return -1;
+ }
+ }
+
+ if (drbd_request_state(mdev, NS(conn, C_WF_REPORT_PARAMS)) < SS_SUCCESS)
+ return 0;
+
+ sock->sk->sk_sndtimeo = mdev->net_conf->timeout*HZ/10;
+ sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT;
+
+ atomic_set(&mdev->packet_seq, 0);
+ mdev->peer_seq = 0;
+
+ drbd_thread_start(&mdev->asender);
+
+ drbd_send_protocol(mdev);
+ drbd_send_sync_param(mdev, &mdev->sync_conf);
+ drbd_send_sizes(mdev, 0);
+ drbd_send_uuids(mdev);
+ drbd_send_state(mdev);
+ clear_bit(USE_DEGR_WFC_T, &mdev->flags);
+ clear_bit(RESIZE_PENDING, &mdev->flags);
+
+ return 1;
+
+out_release_sockets:
+ if (sock)
+ sock_release(sock);
+ if (msock)
+ sock_release(msock);
+ return -1;
+}
+
+static int drbd_recv_header(struct drbd_conf *mdev, struct p_header *h)
+{
+ int r;
+
+ r = drbd_recv(mdev, h, sizeof(*h));
+
+ if (unlikely(r != sizeof(*h))) {
+ dev_err(DEV, "short read expecting header on sock: r=%d\n", r);
+ return FALSE;
+ };
+ h->command = be16_to_cpu(h->command);
+ h->length = be16_to_cpu(h->length);
+ if (unlikely(h->magic != BE_DRBD_MAGIC)) {
+ dev_err(DEV, "magic?? on data m: 0x%lx c: %d l: %d\n",
+ (long)be32_to_cpu(h->magic),
+ h->command, h->length);
+ return FALSE;
+ }
+ mdev->last_received = jiffies;
+
+ return TRUE;
+}
+
+static enum finish_epoch drbd_flush_after_epoch(struct drbd_conf *mdev, struct drbd_epoch *epoch)
+{
+ int rv;
+
+ if (mdev->write_ordering >= WO_bdev_flush && get_ldev(mdev)) {
+ rv = blkdev_issue_flush(mdev->ldev->backing_bdev, NULL);
+ if (rv) {
+ dev_err(DEV, "local disk flush failed with status %d\n", rv);
+ /* would rather check on EOPNOTSUPP, but that is not reliable.
+ * don't try again for ANY return value != 0
+ * if (rv == -EOPNOTSUPP) */
+ drbd_bump_write_ordering(mdev, WO_drain_io);
+ }
+ put_ldev(mdev);
+ }
+
+ return drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE);
+}
+
+static int w_flush(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ struct flush_work *fw = (struct flush_work *)w;
+ struct drbd_epoch *epoch = fw->epoch;
+
+ kfree(w);
+
+ if (!test_and_set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags))
+ drbd_flush_after_epoch(mdev, epoch);
+
+ drbd_may_finish_epoch(mdev, epoch, EV_PUT |
+ (mdev->state.conn < C_CONNECTED ? EV_CLEANUP : 0));
+
+ return 1;
+}
+
+/**
+ * drbd_may_finish_epoch() - Applies an epoch_event to the epoch's state, eventually finishes it.
+ * @mdev: DRBD device.
+ * @epoch: Epoch object.
+ * @ev: Epoch event.
+ */
+static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev,
+ struct drbd_epoch *epoch,
+ enum epoch_event ev)
+{
+ int finish, epoch_size;
+ struct drbd_epoch *next_epoch;
+ int schedule_flush = 0;
+ enum finish_epoch rv = FE_STILL_LIVE;
+
+ spin_lock(&mdev->epoch_lock);
+ do {
+ next_epoch = NULL;
+ finish = 0;
+
+ epoch_size = atomic_read(&epoch->epoch_size);
+
+ switch (ev & ~EV_CLEANUP) {
+ case EV_PUT:
+ atomic_dec(&epoch->active);
+ break;
+ case EV_GOT_BARRIER_NR:
+ set_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags);
+
+ /* Special case: If we just switched from WO_bio_barrier to
+ WO_bdev_flush we should not finish the current epoch */
+ if (test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags) && epoch_size == 1 &&
+ mdev->write_ordering != WO_bio_barrier &&
+ epoch == mdev->current_epoch)
+ clear_bit(DE_CONTAINS_A_BARRIER, &epoch->flags);
+ break;
+ case EV_BARRIER_DONE:
+ set_bit(DE_BARRIER_IN_NEXT_EPOCH_DONE, &epoch->flags);
+ break;
+ case EV_BECAME_LAST:
+ /* nothing to do*/
+ break;
+ }
+
+ if (epoch_size != 0 &&
+ atomic_read(&epoch->active) == 0 &&
+ test_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags) &&
+ epoch->list.prev == &mdev->current_epoch->list &&
+ !test_bit(DE_IS_FINISHING, &epoch->flags)) {
+ /* Nearly all conditions are met to finish that epoch... */
+ if (test_bit(DE_BARRIER_IN_NEXT_EPOCH_DONE, &epoch->flags) ||
+ mdev->write_ordering == WO_none ||
+ (epoch_size == 1 && test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags)) ||
+ ev & EV_CLEANUP) {
+ finish = 1;
+ set_bit(DE_IS_FINISHING, &epoch->flags);
+ } else if (!test_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags) &&
+ mdev->write_ordering == WO_bio_barrier) {
+ atomic_inc(&epoch->active);
+ schedule_flush = 1;
+ }
+ }
+ if (finish) {
+ if (!(ev & EV_CLEANUP)) {
+ spin_unlock(&mdev->epoch_lock);
+ drbd_send_b_ack(mdev, epoch->barrier_nr, epoch_size);
+ spin_lock(&mdev->epoch_lock);
+ }
+ dec_unacked(mdev);
+
+ if (mdev->current_epoch != epoch) {
+ next_epoch = list_entry(epoch->list.next, struct drbd_epoch, list);
+ list_del(&epoch->list);
+ ev = EV_BECAME_LAST | (ev & EV_CLEANUP);
+ mdev->epochs--;
+ kfree(epoch);
+
+ if (rv == FE_STILL_LIVE)
+ rv = FE_DESTROYED;
+ } else {
+ epoch->flags = 0;
+ atomic_set(&epoch->epoch_size, 0);
+ /* atomic_set(&epoch->active, 0); is alrady zero */
+ if (rv == FE_STILL_LIVE)
+ rv = FE_RECYCLED;
+ }
+ }
+
+ if (!next_epoch)
+ break;
+
+ epoch = next_epoch;
+ } while (1);
+
+ spin_unlock(&mdev->epoch_lock);
+
+ if (schedule_flush) {
+ struct flush_work *fw;
+ fw = kmalloc(sizeof(*fw), GFP_ATOMIC);
+ if (fw) {
+ fw->w.cb = w_flush;
+ fw->epoch = epoch;
+ drbd_queue_work(&mdev->data.work, &fw->w);
+ } else {
+ dev_warn(DEV, "Could not kmalloc a flush_work obj\n");
+ set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags);
+ /* That is not a recursion, only one level */
+ drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE);
+ drbd_may_finish_epoch(mdev, epoch, EV_PUT);
+ }
+ }
+
+ return rv;
+}
+
+/**
+ * drbd_bump_write_ordering() - Fall back to an other write ordering method
+ * @mdev: DRBD device.
+ * @wo: Write ordering method to try.
+ */
+void drbd_bump_write_ordering(struct drbd_conf *mdev, enum write_ordering_e wo) __must_hold(local)
+{
+ enum write_ordering_e pwo;
+ static char *write_ordering_str[] = {
+ [WO_none] = "none",
+ [WO_drain_io] = "drain",
+ [WO_bdev_flush] = "flush",
+ [WO_bio_barrier] = "barrier",
+ };
+
+ pwo = mdev->write_ordering;
+ wo = min(pwo, wo);
+ if (wo == WO_bio_barrier && mdev->ldev->dc.no_disk_barrier)
+ wo = WO_bdev_flush;
+ if (wo == WO_bdev_flush && mdev->ldev->dc.no_disk_flush)
+ wo = WO_drain_io;
+ if (wo == WO_drain_io && mdev->ldev->dc.no_disk_drain)
+ wo = WO_none;
+ mdev->write_ordering = wo;
+ if (pwo != mdev->write_ordering || wo == WO_bio_barrier)
+ dev_info(DEV, "Method to ensure write ordering: %s\n", write_ordering_str[mdev->write_ordering]);
+}
+
+/**
+ * w_e_reissue() - Worker callback; Resubmit a bio, without BIO_RW_BARRIER set
+ * @mdev: DRBD device.
+ * @w: work object.
+ * @cancel: The connection will be closed anyways (unused in this callback)
+ */
+int w_e_reissue(struct drbd_conf *mdev, struct drbd_work *w, int cancel) __releases(local)
+{
+ struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w;
+ struct bio *bio = e->private_bio;
+
+ /* We leave DE_CONTAINS_A_BARRIER and EE_IS_BARRIER in place,
+ (and DE_BARRIER_IN_NEXT_EPOCH_ISSUED in the previous Epoch)
+ so that we can finish that epoch in drbd_may_finish_epoch().
+ That is necessary if we already have a long chain of Epochs, before
+ we realize that BIO_RW_BARRIER is actually not supported */
+
+ /* As long as the -ENOTSUPP on the barrier is reported immediately
+ that will never trigger. If it is reported late, we will just
+ print that warning and continue correctly for all future requests
+ with WO_bdev_flush */
+ if (previous_epoch(mdev, e->epoch))
+ dev_warn(DEV, "Write ordering was not enforced (one time event)\n");
+
+ /* prepare bio for re-submit,
+ * re-init volatile members */
+ /* we still have a local reference,
+ * get_ldev was done in receive_Data. */
+ bio->bi_bdev = mdev->ldev->backing_bdev;
+ bio->bi_sector = e->sector;
+ bio->bi_size = e->size;
+ bio->bi_idx = 0;
+
+ bio->bi_flags &= ~(BIO_POOL_MASK - 1);
+ bio->bi_flags |= 1 << BIO_UPTODATE;
+
+ /* don't know whether this is necessary: */
+ bio->bi_phys_segments = 0;
+ bio->bi_next = NULL;
+
+ /* these should be unchanged: */
+ /* bio->bi_end_io = drbd_endio_write_sec; */
+ /* bio->bi_vcnt = whatever; */
+
+ e->w.cb = e_end_block;
+
+ /* This is no longer a barrier request. */
+ bio->bi_rw &= ~(1UL << BIO_RW_BARRIER);
+
+ drbd_generic_make_request(mdev, DRBD_FAULT_DT_WR, bio);
+
+ return 1;
+}
+
+static int receive_Barrier(struct drbd_conf *mdev, struct p_header *h)
+{
+ int rv, issue_flush;
+ struct p_barrier *p = (struct p_barrier *)h;
+ struct drbd_epoch *epoch;
+
+ ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
+
+ rv = drbd_recv(mdev, h->payload, h->length);
+ ERR_IF(rv != h->length) return FALSE;
+
+ inc_unacked(mdev);
+
+ if (mdev->net_conf->wire_protocol != DRBD_PROT_C)
+ drbd_kick_lo(mdev);
+
+ mdev->current_epoch->barrier_nr = p->barrier;
+ rv = drbd_may_finish_epoch(mdev, mdev->current_epoch, EV_GOT_BARRIER_NR);
+
+ /* P_BARRIER_ACK may imply that the corresponding extent is dropped from
+ * the activity log, which means it would not be resynced in case the
+ * R_PRIMARY crashes now.
+ * Therefore we must send the barrier_ack after the barrier request was
+ * completed. */
+ switch (mdev->write_ordering) {
+ case WO_bio_barrier:
+ case WO_none:
+ if (rv == FE_RECYCLED)
+ return TRUE;
+ break;
+
+ case WO_bdev_flush:
+ case WO_drain_io:
+ D_ASSERT(rv == FE_STILL_LIVE);
+ set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &mdev->current_epoch->flags);
+ drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
+ rv = drbd_flush_after_epoch(mdev, mdev->current_epoch);
+ if (rv == FE_RECYCLED)
+ return TRUE;
+
+ /* The asender will send all the ACKs and barrier ACKs out, since
+ all EEs moved from the active_ee to the done_ee. We need to
+ provide a new epoch object for the EEs that come in soon */
+ break;
+ }
+
+ /* receiver context, in the writeout path of the other node.
+ * avoid potential distributed deadlock */
+ epoch = kmalloc(sizeof(struct drbd_epoch), GFP_NOIO);
+ if (!epoch) {
+ dev_warn(DEV, "Allocation of an epoch failed, slowing down\n");
+ issue_flush = !test_and_set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags);
+ drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
+ if (issue_flush) {
+ rv = drbd_flush_after_epoch(mdev, mdev->current_epoch);
+ if (rv == FE_RECYCLED)
+ return TRUE;
+ }
+
+ drbd_wait_ee_list_empty(mdev, &mdev->done_ee);
+
+ return TRUE;
+ }
+
+ epoch->flags = 0;
+ atomic_set(&epoch->epoch_size, 0);
+ atomic_set(&epoch->active, 0);
+
+ spin_lock(&mdev->epoch_lock);
+ if (atomic_read(&mdev->current_epoch->epoch_size)) {
+ list_add(&epoch->list, &mdev->current_epoch->list);
+ mdev->current_epoch = epoch;
+ mdev->epochs++;
+ } else {
+ /* The current_epoch got recycled while we allocated this one... */
+ kfree(epoch);
+ }
+ spin_unlock(&mdev->epoch_lock);
+
+ return TRUE;
+}
+
+/* used from receive_RSDataReply (recv_resync_read)
+ * and from receive_Data */
+static struct drbd_epoch_entry *
+read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __must_hold(local)
+{
+ struct drbd_epoch_entry *e;
+ struct bio_vec *bvec;
+ struct page *page;
+ struct bio *bio;
+ int dgs, ds, i, rr;
+ void *dig_in = mdev->int_dig_in;
+ void *dig_vv = mdev->int_dig_vv;
+
+ dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_r_tfm) ?
+ crypto_hash_digestsize(mdev->integrity_r_tfm) : 0;
+
+ if (dgs) {
+ rr = drbd_recv(mdev, dig_in, dgs);
+ if (rr != dgs) {
+ dev_warn(DEV, "short read receiving data digest: read %d expected %d\n",
+ rr, dgs);
+ return NULL;
+ }
+ }
+
+ data_size -= dgs;
+
+ ERR_IF(data_size & 0x1ff) return NULL;
+ ERR_IF(data_size > DRBD_MAX_SEGMENT_SIZE) return NULL;
+
+ /* GFP_NOIO, because we must not cause arbitrary write-out: in a DRBD
+ * "criss-cross" setup, that might cause write-out on some other DRBD,
+ * which in turn might block on the other node at this very place. */
+ e = drbd_alloc_ee(mdev, id, sector, data_size, GFP_NOIO);
+ if (!e)
+ return NULL;
+ bio = e->private_bio;
+ ds = data_size;
+ bio_for_each_segment(bvec, bio, i) {
+ page = bvec->bv_page;
+ rr = drbd_recv(mdev, kmap(page), min_t(int, ds, PAGE_SIZE));
+ kunmap(page);
+ if (rr != min_t(int, ds, PAGE_SIZE)) {
+ drbd_free_ee(mdev, e);
+ dev_warn(DEV, "short read receiving data: read %d expected %d\n",
+ rr, min_t(int, ds, PAGE_SIZE));
+ return NULL;
+ }
+ ds -= rr;
+ }
+
+ if (dgs) {
+ drbd_csum(mdev, mdev->integrity_r_tfm, bio, dig_vv);
+ if (memcmp(dig_in, dig_vv, dgs)) {
+ dev_err(DEV, "Digest integrity check FAILED.\n");
+ drbd_bcast_ee(mdev, "digest failed",
+ dgs, dig_in, dig_vv, e);
+ drbd_free_ee(mdev, e);
+ return NULL;
+ }
+ }
+ mdev->recv_cnt += data_size>>9;
+ return e;
+}
+
+/* drbd_drain_block() just takes a data block
+ * out of the socket input buffer, and discards it.
+ */
+static int drbd_drain_block(struct drbd_conf *mdev, int data_size)
+{
+ struct page *page;
+ int rr, rv = 1;
+ void *data;
+
+ page = drbd_pp_alloc(mdev, 1);
+
+ data = kmap(page);
+ while (data_size) {
+ rr = drbd_recv(mdev, data, min_t(int, data_size, PAGE_SIZE));
+ if (rr != min_t(int, data_size, PAGE_SIZE)) {
+ rv = 0;
+ dev_warn(DEV, "short read receiving data: read %d expected %d\n",
+ rr, min_t(int, data_size, PAGE_SIZE));
+ break;
+ }
+ data_size -= rr;
+ }
+ kunmap(page);
+ drbd_pp_free(mdev, page);
+ return rv;
+}
+
+static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req,
+ sector_t sector, int data_size)
+{
+ struct bio_vec *bvec;
+ struct bio *bio;
+ int dgs, rr, i, expect;
+ void *dig_in = mdev->int_dig_in;
+ void *dig_vv = mdev->int_dig_vv;
+
+ dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_r_tfm) ?
+ crypto_hash_digestsize(mdev->integrity_r_tfm) : 0;
+
+ if (dgs) {
+ rr = drbd_recv(mdev, dig_in, dgs);
+ if (rr != dgs) {
+ dev_warn(DEV, "short read receiving data reply digest: read %d expected %d\n",
+ rr, dgs);
+ return 0;
+ }
+ }
+
+ data_size -= dgs;
+
+ /* optimistically update recv_cnt. if receiving fails below,
+ * we disconnect anyways, and counters will be reset. */
+ mdev->recv_cnt += data_size>>9;
+
+ bio = req->master_bio;
+ D_ASSERT(sector == bio->bi_sector);
+
+ bio_for_each_segment(bvec, bio, i) {
+ expect = min_t(int, data_size, bvec->bv_len);
+ rr = drbd_recv(mdev,
+ kmap(bvec->bv_page)+bvec->bv_offset,
+ expect);
+ kunmap(bvec->bv_page);
+ if (rr != expect) {
+ dev_warn(DEV, "short read receiving data reply: "
+ "read %d expected %d\n",
+ rr, expect);
+ return 0;
+ }
+ data_size -= rr;
+ }
+
+ if (dgs) {
+ drbd_csum(mdev, mdev->integrity_r_tfm, bio, dig_vv);
+ if (memcmp(dig_in, dig_vv, dgs)) {
+ dev_err(DEV, "Digest integrity check FAILED. Broken NICs?\n");
+ return 0;
+ }
+ }
+
+ D_ASSERT(data_size == 0);
+ return 1;
+}
+
+/* e_end_resync_block() is called via
+ * drbd_process_done_ee() by asender only */
+static int e_end_resync_block(struct drbd_conf *mdev, struct drbd_work *w, int unused)
+{
+ struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w;
+ sector_t sector = e->sector;
+ int ok;
+
+ D_ASSERT(hlist_unhashed(&e->colision));
+
+ if (likely(drbd_bio_uptodate(e->private_bio))) {
+ drbd_set_in_sync(mdev, sector, e->size);
+ ok = drbd_send_ack(mdev, P_RS_WRITE_ACK, e);
+ } else {
+ /* Record failure to sync */
+ drbd_rs_failed_io(mdev, sector, e->size);
+
+ ok = drbd_send_ack(mdev, P_NEG_ACK, e);
+ }
+ dec_unacked(mdev);
+
+ return ok;
+}
+
+static int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_size) __releases(local)
+{
+ struct drbd_epoch_entry *e;
+
+ e = read_in_block(mdev, ID_SYNCER, sector, data_size);
+ if (!e) {
+ put_ldev(mdev);
+ return FALSE;
+ }
+
+ dec_rs_pending(mdev);
+
+ e->private_bio->bi_end_io = drbd_endio_write_sec;
+ e->private_bio->bi_rw = WRITE;
+ e->w.cb = e_end_resync_block;
+
+ inc_unacked(mdev);
+ /* corresponding dec_unacked() in e_end_resync_block()
+ * respective _drbd_clear_done_ee */
+
+ spin_lock_irq(&mdev->req_lock);
+ list_add(&e->w.list, &mdev->sync_ee);
+ spin_unlock_irq(&mdev->req_lock);
+
+ drbd_generic_make_request(mdev, DRBD_FAULT_RS_WR, e->private_bio);
+ /* accounting done in endio */
+
+ maybe_kick_lo(mdev);
+ return TRUE;
+}
+
+static int receive_DataReply(struct drbd_conf *mdev, struct p_header *h)
+{
+ struct drbd_request *req;
+ sector_t sector;
+ unsigned int header_size, data_size;
+ int ok;
+ struct p_data *p = (struct p_data *)h;
+
+ header_size = sizeof(*p) - sizeof(*h);
+ data_size = h->length - header_size;
+
+ ERR_IF(data_size == 0) return FALSE;
+
+ if (drbd_recv(mdev, h->payload, header_size) != header_size)
+ return FALSE;
+
+ sector = be64_to_cpu(p->sector);
+
+ spin_lock_irq(&mdev->req_lock);
+ req = _ar_id_to_req(mdev, p->block_id, sector);
+ spin_unlock_irq(&mdev->req_lock);
+ if (unlikely(!req)) {
+ dev_err(DEV, "Got a corrupt block_id/sector pair(1).\n");
+ return FALSE;
+ }
+
+ /* hlist_del(&req->colision) is done in _req_may_be_done, to avoid
+ * special casing it there for the various failure cases.
+ * still no race with drbd_fail_pending_reads */
+ ok = recv_dless_read(mdev, req, sector, data_size);
+
+ if (ok)
+ req_mod(req, data_received);
+ /* else: nothing. handled from drbd_disconnect...
+ * I don't think we may complete this just yet
+ * in case we are "on-disconnect: freeze" */
+
+ return ok;
+}
+
+static int receive_RSDataReply(struct drbd_conf *mdev, struct p_header *h)
+{
+ sector_t sector;
+ unsigned int header_size, data_size;
+ int ok;
+ struct p_data *p = (struct p_data *)h;
+
+ header_size = sizeof(*p) - sizeof(*h);
+ data_size = h->length - header_size;
+
+ ERR_IF(data_size == 0) return FALSE;
+
+ if (drbd_recv(mdev, h->payload, header_size) != header_size)
+ return FALSE;
+
+ sector = be64_to_cpu(p->sector);
+ D_ASSERT(p->block_id == ID_SYNCER);
+
+ if (get_ldev(mdev)) {
+ /* data is submitted to disk within recv_resync_read.
+ * corresponding put_ldev done below on error,
+ * or in drbd_endio_write_sec. */
+ ok = recv_resync_read(mdev, sector, data_size);
+ } else {
+ if (__ratelimit(&drbd_ratelimit_state))
+ dev_err(DEV, "Can not write resync data to local disk.\n");
+
+ ok = drbd_drain_block(mdev, data_size);
+
+ drbd_send_ack_dp(mdev, P_NEG_ACK, p);
+ }
+
+ return ok;
+}
+
+/* e_end_block() is called via drbd_process_done_ee().
+ * this means this function only runs in the asender thread
+ */
+static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w;
+ sector_t sector = e->sector;
+ struct drbd_epoch *epoch;
+ int ok = 1, pcmd;
+
+ if (e->flags & EE_IS_BARRIER) {
+ epoch = previous_epoch(mdev, e->epoch);
+ if (epoch)
+ drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE + (cancel ? EV_CLEANUP : 0));
+ }
+
+ if (mdev->net_conf->wire_protocol == DRBD_PROT_C) {
+ if (likely(drbd_bio_uptodate(e->private_bio))) {
+ pcmd = (mdev->state.conn >= C_SYNC_SOURCE &&
+ mdev->state.conn <= C_PAUSED_SYNC_T &&
+ e->flags & EE_MAY_SET_IN_SYNC) ?
+ P_RS_WRITE_ACK : P_WRITE_ACK;
+ ok &= drbd_send_ack(mdev, pcmd, e);
+ if (pcmd == P_RS_WRITE_ACK)
+ drbd_set_in_sync(mdev, sector, e->size);
+ } else {
+ ok = drbd_send_ack(mdev, P_NEG_ACK, e);
+ /* we expect it to be marked out of sync anyways...
+ * maybe assert this? */
+ }
+ dec_unacked(mdev);
+ }
+ /* we delete from the conflict detection hash _after_ we sent out the
+ * P_WRITE_ACK / P_NEG_ACK, to get the sequence number right. */
+ if (mdev->net_conf->two_primaries) {
+ spin_lock_irq(&mdev->req_lock);
+ D_ASSERT(!hlist_unhashed(&e->colision));
+ hlist_del_init(&e->colision);
+ spin_unlock_irq(&mdev->req_lock);
+ } else {
+ D_ASSERT(hlist_unhashed(&e->colision));
+ }
+
+ drbd_may_finish_epoch(mdev, e->epoch, EV_PUT + (cancel ? EV_CLEANUP : 0));
+
+ return ok;
+}
+
+static int e_send_discard_ack(struct drbd_conf *mdev, struct drbd_work *w, int unused)
+{
+ struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w;
+ int ok = 1;
+
+ D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C);
+ ok = drbd_send_ack(mdev, P_DISCARD_ACK, e);
+
+ spin_lock_irq(&mdev->req_lock);
+ D_ASSERT(!hlist_unhashed(&e->colision));
+ hlist_del_init(&e->colision);
+ spin_unlock_irq(&mdev->req_lock);
+
+ dec_unacked(mdev);
+
+ return ok;
+}
+
+/* Called from receive_Data.
+ * Synchronize packets on sock with packets on msock.
+ *
+ * This is here so even when a P_DATA packet traveling via sock overtook an Ack
+ * packet traveling on msock, they are still processed in the order they have
+ * been sent.
+ *
+ * Note: we don't care for Ack packets overtaking P_DATA packets.
+ *
+ * In case packet_seq is larger than mdev->peer_seq number, there are
+ * outstanding packets on the msock. We wait for them to arrive.
+ * In case we are the logically next packet, we update mdev->peer_seq
+ * ourselves. Correctly handles 32bit wrap around.
+ *
+ * Assume we have a 10 GBit connection, that is about 1<<30 byte per second,
+ * about 1<<21 sectors per second. So "worst" case, we have 1<<3 == 8 seconds
+ * for the 24bit wrap (historical atomic_t guarantee on some archs), and we have
+ * 1<<9 == 512 seconds aka ages for the 32bit wrap around...
+ *
+ * returns 0 if we may process the packet,
+ * -ERESTARTSYS if we were interrupted (by disconnect signal). */
+static int drbd_wait_peer_seq(struct drbd_conf *mdev, const u32 packet_seq)
+{
+ DEFINE_WAIT(wait);
+ unsigned int p_seq;
+ long timeout;
+ int ret = 0;
+ spin_lock(&mdev->peer_seq_lock);
+ for (;;) {
+ prepare_to_wait(&mdev->seq_wait, &wait, TASK_INTERRUPTIBLE);
+ if (seq_le(packet_seq, mdev->peer_seq+1))
+ break;
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ p_seq = mdev->peer_seq;
+ spin_unlock(&mdev->peer_seq_lock);
+ timeout = schedule_timeout(30*HZ);
+ spin_lock(&mdev->peer_seq_lock);
+ if (timeout == 0 && p_seq == mdev->peer_seq) {
+ ret = -ETIMEDOUT;
+ dev_err(DEV, "ASSERT FAILED waited 30 seconds for sequence update, forcing reconnect\n");
+ break;
+ }
+ }
+ finish_wait(&mdev->seq_wait, &wait);
+ if (mdev->peer_seq+1 == packet_seq)
+ mdev->peer_seq++;
+ spin_unlock(&mdev->peer_seq_lock);
+ return ret;
+}
+
+/* mirrored write */
+static int receive_Data(struct drbd_conf *mdev, struct p_header *h)
+{
+ sector_t sector;
+ struct drbd_epoch_entry *e;
+ struct p_data *p = (struct p_data *)h;
+ int header_size, data_size;
+ int rw = WRITE;
+ u32 dp_flags;
+
+ header_size = sizeof(*p) - sizeof(*h);
+ data_size = h->length - header_size;
+
+ ERR_IF(data_size == 0) return FALSE;
+
+ if (drbd_recv(mdev, h->payload, header_size) != header_size)
+ return FALSE;
+
+ if (!get_ldev(mdev)) {
+ if (__ratelimit(&drbd_ratelimit_state))
+ dev_err(DEV, "Can not write mirrored data block "
+ "to local disk.\n");
+ spin_lock(&mdev->peer_seq_lock);
+ if (mdev->peer_seq+1 == be32_to_cpu(p->seq_num))
+ mdev->peer_seq++;
+ spin_unlock(&mdev->peer_seq_lock);
+
+ drbd_send_ack_dp(mdev, P_NEG_ACK, p);
+ atomic_inc(&mdev->current_epoch->epoch_size);
+ return drbd_drain_block(mdev, data_size);
+ }
+
+ /* get_ldev(mdev) successful.
+ * Corresponding put_ldev done either below (on various errors),
+ * or in drbd_endio_write_sec, if we successfully submit the data at
+ * the end of this function. */
+
+ sector = be64_to_cpu(p->sector);
+ e = read_in_block(mdev, p->block_id, sector, data_size);
+ if (!e) {
+ put_ldev(mdev);
+ return FALSE;
+ }
+
+ e->private_bio->bi_end_io = drbd_endio_write_sec;
+ e->w.cb = e_end_block;
+
+ spin_lock(&mdev->epoch_lock);
+ e->epoch = mdev->current_epoch;
+ atomic_inc(&e->epoch->epoch_size);
+ atomic_inc(&e->epoch->active);
+
+ if (mdev->write_ordering == WO_bio_barrier && atomic_read(&e->epoch->epoch_size) == 1) {
+ struct drbd_epoch *epoch;
+ /* Issue a barrier if we start a new epoch, and the previous epoch
+ was not a epoch containing a single request which already was
+ a Barrier. */
+ epoch = list_entry(e->epoch->list.prev, struct drbd_epoch, list);
+ if (epoch == e->epoch) {
+ set_bit(DE_CONTAINS_A_BARRIER, &e->epoch->flags);
+ rw |= (1<<BIO_RW_BARRIER);
+ e->flags |= EE_IS_BARRIER;
+ } else {
+ if (atomic_read(&epoch->epoch_size) > 1 ||
+ !test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags)) {
+ set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags);
+ set_bit(DE_CONTAINS_A_BARRIER, &e->epoch->flags);
+ rw |= (1<<BIO_RW_BARRIER);
+ e->flags |= EE_IS_BARRIER;
+ }
+ }
+ }
+ spin_unlock(&mdev->epoch_lock);
+
+ dp_flags = be32_to_cpu(p->dp_flags);
+ if (dp_flags & DP_HARDBARRIER) {
+ dev_err(DEV, "ASSERT FAILED would have submitted barrier request\n");
+ /* rw |= (1<<BIO_RW_BARRIER); */
+ }
+ if (dp_flags & DP_RW_SYNC)
+ rw |= (1<<BIO_RW_SYNCIO) | (1<<BIO_RW_UNPLUG);
+ if (dp_flags & DP_MAY_SET_IN_SYNC)
+ e->flags |= EE_MAY_SET_IN_SYNC;
+
+ /* I'm the receiver, I do hold a net_cnt reference. */
+ if (!mdev->net_conf->two_primaries) {
+ spin_lock_irq(&mdev->req_lock);
+ } else {
+ /* don't get the req_lock yet,
+ * we may sleep in drbd_wait_peer_seq */
+ const int size = e->size;
+ const int discard = test_bit(DISCARD_CONCURRENT, &mdev->flags);
+ DEFINE_WAIT(wait);
+ struct drbd_request *i;
+ struct hlist_node *n;
+ struct hlist_head *slot;
+ int first;
+
+ D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C);
+ BUG_ON(mdev->ee_hash == NULL);
+ BUG_ON(mdev->tl_hash == NULL);
+
+ /* conflict detection and handling:
+ * 1. wait on the sequence number,
+ * in case this data packet overtook ACK packets.
+ * 2. check our hash tables for conflicting requests.
+ * we only need to walk the tl_hash, since an ee can not
+ * have a conflict with an other ee: on the submitting
+ * node, the corresponding req had already been conflicting,
+ * and a conflicting req is never sent.
+ *
+ * Note: for two_primaries, we are protocol C,
+ * so there cannot be any request that is DONE
+ * but still on the transfer log.
+ *
+ * unconditionally add to the ee_hash.
+ *
+ * if no conflicting request is found:
+ * submit.
+ *
+ * if any conflicting request is found
+ * that has not yet been acked,
+ * AND I have the "discard concurrent writes" flag:
+ * queue (via done_ee) the P_DISCARD_ACK; OUT.
+ *
+ * if any conflicting request is found:
+ * block the receiver, waiting on misc_wait
+ * until no more conflicting requests are there,
+ * or we get interrupted (disconnect).
+ *
+ * we do not just write after local io completion of those
+ * requests, but only after req is done completely, i.e.
+ * we wait for the P_DISCARD_ACK to arrive!
+ *
+ * then proceed normally, i.e. submit.
+ */
+ if (drbd_wait_peer_seq(mdev, be32_to_cpu(p->seq_num)))
+ goto out_interrupted;
+
+ spin_lock_irq(&mdev->req_lock);
+
+ hlist_add_head(&e->colision, ee_hash_slot(mdev, sector));
+
+#define OVERLAPS overlaps(i->sector, i->size, sector, size)
+ slot = tl_hash_slot(mdev, sector);
+ first = 1;
+ for (;;) {
+ int have_unacked = 0;
+ int have_conflict = 0;
+ prepare_to_wait(&mdev->misc_wait, &wait,
+ TASK_INTERRUPTIBLE);
+ hlist_for_each_entry(i, n, slot, colision) {
+ if (OVERLAPS) {
+ /* only ALERT on first iteration,
+ * we may be woken up early... */
+ if (first)
+ dev_alert(DEV, "%s[%u] Concurrent local write detected!"
+ " new: %llus +%u; pending: %llus +%u\n",
+ current->comm, current->pid,
+ (unsigned long long)sector, size,
+ (unsigned long long)i->sector, i->size);
+ if (i->rq_state & RQ_NET_PENDING)
+ ++have_unacked;
+ ++have_conflict;
+ }
+ }
+#undef OVERLAPS
+ if (!have_conflict)
+ break;
+
+ /* Discard Ack only for the _first_ iteration */
+ if (first && discard && have_unacked) {
+ dev_alert(DEV, "Concurrent write! [DISCARD BY FLAG] sec=%llus\n",
+ (unsigned long long)sector);
+ inc_unacked(mdev);
+ e->w.cb = e_send_discard_ack;
+ list_add_tail(&e->w.list, &mdev->done_ee);
+
+ spin_unlock_irq(&mdev->req_lock);
+
+ /* we could probably send that P_DISCARD_ACK ourselves,
+ * but I don't like the receiver using the msock */
+
+ put_ldev(mdev);
+ wake_asender(mdev);
+ finish_wait(&mdev->misc_wait, &wait);
+ return TRUE;
+ }
+
+ if (signal_pending(current)) {
+ hlist_del_init(&e->colision);
+
+ spin_unlock_irq(&mdev->req_lock);
+
+ finish_wait(&mdev->misc_wait, &wait);
+ goto out_interrupted;
+ }
+
+ spin_unlock_irq(&mdev->req_lock);
+ if (first) {
+ first = 0;
+ dev_alert(DEV, "Concurrent write! [W AFTERWARDS] "
+ "sec=%llus\n", (unsigned long long)sector);
+ } else if (discard) {
+ /* we had none on the first iteration.
+ * there must be none now. */
+ D_ASSERT(have_unacked == 0);
+ }
+ schedule();
+ spin_lock_irq(&mdev->req_lock);
+ }
+ finish_wait(&mdev->misc_wait, &wait);
+ }
+
+ list_add(&e->w.list, &mdev->active_ee);
+ spin_unlock_irq(&mdev->req_lock);
+
+ switch (mdev->net_conf->wire_protocol) {
+ case DRBD_PROT_C:
+ inc_unacked(mdev);
+ /* corresponding dec_unacked() in e_end_block()
+ * respective _drbd_clear_done_ee */
+ break;
+ case DRBD_PROT_B:
+ /* I really don't like it that the receiver thread
+ * sends on the msock, but anyways */
+ drbd_send_ack(mdev, P_RECV_ACK, e);
+ break;
+ case DRBD_PROT_A:
+ /* nothing to do */
+ break;
+ }
+
+ if (mdev->state.pdsk == D_DISKLESS) {
+ /* In case we have the only disk of the cluster, */
+ drbd_set_out_of_sync(mdev, e->sector, e->size);
+ e->flags |= EE_CALL_AL_COMPLETE_IO;
+ drbd_al_begin_io(mdev, e->sector);
+ }
+
+ e->private_bio->bi_rw = rw;
+ drbd_generic_make_request(mdev, DRBD_FAULT_DT_WR, e->private_bio);
+ /* accounting done in endio */
+
+ maybe_kick_lo(mdev);
+ return TRUE;
+
+out_interrupted:
+ /* yes, the epoch_size now is imbalanced.
+ * but we drop the connection anyways, so we don't have a chance to
+ * receive a barrier... atomic_inc(&mdev->epoch_size); */
+ put_ldev(mdev);
+ drbd_free_ee(mdev, e);
+ return FALSE;
+}
+
+static int receive_DataRequest(struct drbd_conf *mdev, struct p_header *h)
+{
+ sector_t sector;
+ const sector_t capacity = drbd_get_capacity(mdev->this_bdev);
+ struct drbd_epoch_entry *e;
+ struct digest_info *di = NULL;
+ int size, digest_size;
+ unsigned int fault_type;
+ struct p_block_req *p =
+ (struct p_block_req *)h;
+ const int brps = sizeof(*p)-sizeof(*h);
+
+ if (drbd_recv(mdev, h->payload, brps) != brps)
+ return FALSE;
+
+ sector = be64_to_cpu(p->sector);
+ size = be32_to_cpu(p->blksize);
+
+ if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) {
+ dev_err(DEV, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__,
+ (unsigned long long)sector, size);
+ return FALSE;
+ }
+ if (sector + (size>>9) > capacity) {
+ dev_err(DEV, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__,
+ (unsigned long long)sector, size);
+ return FALSE;
+ }
+
+ if (!get_ldev_if_state(mdev, D_UP_TO_DATE)) {
+ if (__ratelimit(&drbd_ratelimit_state))
+ dev_err(DEV, "Can not satisfy peer's read request, "
+ "no local data.\n");
+ drbd_send_ack_rp(mdev, h->command == P_DATA_REQUEST ? P_NEG_DREPLY :
+ P_NEG_RS_DREPLY , p);
+ return TRUE;
+ }
+
+ /* GFP_NOIO, because we must not cause arbitrary write-out: in a DRBD
+ * "criss-cross" setup, that might cause write-out on some other DRBD,
+ * which in turn might block on the other node at this very place. */
+ e = drbd_alloc_ee(mdev, p->block_id, sector, size, GFP_NOIO);
+ if (!e) {
+ put_ldev(mdev);
+ return FALSE;
+ }
+
+ e->private_bio->bi_rw = READ;
+ e->private_bio->bi_end_io = drbd_endio_read_sec;
+
+ switch (h->command) {
+ case P_DATA_REQUEST:
+ e->w.cb = w_e_end_data_req;
+ fault_type = DRBD_FAULT_DT_RD;
+ break;
+ case P_RS_DATA_REQUEST:
+ e->w.cb = w_e_end_rsdata_req;
+ fault_type = DRBD_FAULT_RS_RD;
+ /* Eventually this should become asynchronously. Currently it
+ * blocks the whole receiver just to delay the reading of a
+ * resync data block.
+ * the drbd_work_queue mechanism is made for this...
+ */
+ if (!drbd_rs_begin_io(mdev, sector)) {
+ /* we have been interrupted,
+ * probably connection lost! */
+ D_ASSERT(signal_pending(current));
+ goto out_free_e;
+ }
+ break;
+
+ case P_OV_REPLY:
+ case P_CSUM_RS_REQUEST:
+ fault_type = DRBD_FAULT_RS_RD;
+ digest_size = h->length - brps ;
+ di = kmalloc(sizeof(*di) + digest_size, GFP_NOIO);
+ if (!di)
+ goto out_free_e;
+
+ di->digest_size = digest_size;
+ di->digest = (((char *)di)+sizeof(struct digest_info));
+
+ if (drbd_recv(mdev, di->digest, digest_size) != digest_size)
+ goto out_free_e;
+
+ e->block_id = (u64)(unsigned long)di;
+ if (h->command == P_CSUM_RS_REQUEST) {
+ D_ASSERT(mdev->agreed_pro_version >= 89);
+ e->w.cb = w_e_end_csum_rs_req;
+ } else if (h->command == P_OV_REPLY) {
+ e->w.cb = w_e_end_ov_reply;
+ dec_rs_pending(mdev);
+ break;
+ }
+
+ if (!drbd_rs_begin_io(mdev, sector)) {
+ /* we have been interrupted, probably connection lost! */
+ D_ASSERT(signal_pending(current));
+ goto out_free_e;
+ }
+ break;
+
+ case P_OV_REQUEST:
+ if (mdev->state.conn >= C_CONNECTED &&
+ mdev->state.conn != C_VERIFY_T)
+ dev_warn(DEV, "ASSERT FAILED: got P_OV_REQUEST while being %s\n",
+ drbd_conn_str(mdev->state.conn));
+ if (mdev->ov_start_sector == ~(sector_t)0 &&
+ mdev->agreed_pro_version >= 90) {
+ mdev->ov_start_sector = sector;
+ mdev->ov_position = sector;
+ mdev->ov_left = mdev->rs_total - BM_SECT_TO_BIT(sector);
+ dev_info(DEV, "Online Verify start sector: %llu\n",
+ (unsigned long long)sector);
+ }
+ e->w.cb = w_e_end_ov_req;
+ fault_type = DRBD_FAULT_RS_RD;
+ /* Eventually this should become asynchronous. Currently it
+ * blocks the whole receiver just to delay the reading of a
+ * resync data block.
+ * the drbd_work_queue mechanism is made for this...
+ */
+ if (!drbd_rs_begin_io(mdev, sector)) {
+ /* we have been interrupted,
+ * probably connection lost! */
+ D_ASSERT(signal_pending(current));
+ goto out_free_e;
+ }
+ break;
+
+
+ default:
+ dev_err(DEV, "unexpected command (%s) in receive_DataRequest\n",
+ cmdname(h->command));
+ fault_type = DRBD_FAULT_MAX;
+ }
+
+ spin_lock_irq(&mdev->req_lock);
+ list_add(&e->w.list, &mdev->read_ee);
+ spin_unlock_irq(&mdev->req_lock);
+
+ inc_unacked(mdev);
+
+ drbd_generic_make_request(mdev, fault_type, e->private_bio);
+ maybe_kick_lo(mdev);
+
+ return TRUE;
+
+out_free_e:
+ kfree(di);
+ put_ldev(mdev);
+ drbd_free_ee(mdev, e);
+ return FALSE;
+}
+
+static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local)
+{
+ int self, peer, rv = -100;
+ unsigned long ch_self, ch_peer;
+
+ self = mdev->ldev->md.uuid[UI_BITMAP] & 1;
+ peer = mdev->p_uuid[UI_BITMAP] & 1;
+
+ ch_peer = mdev->p_uuid[UI_SIZE];
+ ch_self = mdev->comm_bm_set;
+
+ switch (mdev->net_conf->after_sb_0p) {
+ case ASB_CONSENSUS:
+ case ASB_DISCARD_SECONDARY:
+ case ASB_CALL_HELPER:
+ dev_err(DEV, "Configuration error.\n");
+ break;
+ case ASB_DISCONNECT:
+ break;
+ case ASB_DISCARD_YOUNGER_PRI:
+ if (self == 0 && peer == 1) {
+ rv = -1;
+ break;
+ }
+ if (self == 1 && peer == 0) {
+ rv = 1;
+ break;
+ }
+ /* Else fall through to one of the other strategies... */
+ case ASB_DISCARD_OLDER_PRI:
+ if (self == 0 && peer == 1) {
+ rv = 1;
+ break;
+ }
+ if (self == 1 && peer == 0) {
+ rv = -1;
+ break;
+ }
+ /* Else fall through to one of the other strategies... */
+ dev_warn(DEV, "Discard younger/older primary did not found a decision\n"
+ "Using discard-least-changes instead\n");
+ case ASB_DISCARD_ZERO_CHG:
+ if (ch_peer == 0 && ch_self == 0) {
+ rv = test_bit(DISCARD_CONCURRENT, &mdev->flags)
+ ? -1 : 1;
+ break;
+ } else {
+ if (ch_peer == 0) { rv = 1; break; }
+ if (ch_self == 0) { rv = -1; break; }
+ }
+ if (mdev->net_conf->after_sb_0p == ASB_DISCARD_ZERO_CHG)
+ break;
+ case ASB_DISCARD_LEAST_CHG:
+ if (ch_self < ch_peer)
+ rv = -1;
+ else if (ch_self > ch_peer)
+ rv = 1;
+ else /* ( ch_self == ch_peer ) */
+ /* Well, then use something else. */
+ rv = test_bit(DISCARD_CONCURRENT, &mdev->flags)
+ ? -1 : 1;
+ break;
+ case ASB_DISCARD_LOCAL:
+ rv = -1;
+ break;
+ case ASB_DISCARD_REMOTE:
+ rv = 1;
+ }
+
+ return rv;
+}
+
+static int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local)
+{
+ int self, peer, hg, rv = -100;
+
+ self = mdev->ldev->md.uuid[UI_BITMAP] & 1;
+ peer = mdev->p_uuid[UI_BITMAP] & 1;
+
+ switch (mdev->net_conf->after_sb_1p) {
+ case ASB_DISCARD_YOUNGER_PRI:
+ case ASB_DISCARD_OLDER_PRI:
+ case ASB_DISCARD_LEAST_CHG:
+ case ASB_DISCARD_LOCAL:
+ case ASB_DISCARD_REMOTE:
+ dev_err(DEV, "Configuration error.\n");
+ break;
+ case ASB_DISCONNECT:
+ break;
+ case ASB_CONSENSUS:
+ hg = drbd_asb_recover_0p(mdev);
+ if (hg == -1 && mdev->state.role == R_SECONDARY)
+ rv = hg;
+ if (hg == 1 && mdev->state.role == R_PRIMARY)
+ rv = hg;
+ break;
+ case ASB_VIOLENTLY:
+ rv = drbd_asb_recover_0p(mdev);
+ break;
+ case ASB_DISCARD_SECONDARY:
+ return mdev->state.role == R_PRIMARY ? 1 : -1;
+ case ASB_CALL_HELPER:
+ hg = drbd_asb_recover_0p(mdev);
+ if (hg == -1 && mdev->state.role == R_PRIMARY) {
+ self = drbd_set_role(mdev, R_SECONDARY, 0);
+ /* drbd_change_state() does not sleep while in SS_IN_TRANSIENT_STATE,
+ * we might be here in C_WF_REPORT_PARAMS which is transient.
+ * we do not need to wait for the after state change work either. */
+ self = drbd_change_state(mdev, CS_VERBOSE, NS(role, R_SECONDARY));
+ if (self != SS_SUCCESS) {
+ drbd_khelper(mdev, "pri-lost-after-sb");
+ } else {
+ dev_warn(DEV, "Successfully gave up primary role.\n");
+ rv = hg;
+ }
+ } else
+ rv = hg;
+ }
+
+ return rv;
+}
+
+static int drbd_asb_recover_2p(struct drbd_conf *mdev) __must_hold(local)
+{
+ int self, peer, hg, rv = -100;
+
+ self = mdev->ldev->md.uuid[UI_BITMAP] & 1;
+ peer = mdev->p_uuid[UI_BITMAP] & 1;
+
+ switch (mdev->net_conf->after_sb_2p) {
+ case ASB_DISCARD_YOUNGER_PRI:
+ case ASB_DISCARD_OLDER_PRI:
+ case ASB_DISCARD_LEAST_CHG:
+ case ASB_DISCARD_LOCAL:
+ case ASB_DISCARD_REMOTE:
+ case ASB_CONSENSUS:
+ case ASB_DISCARD_SECONDARY:
+ dev_err(DEV, "Configuration error.\n");
+ break;
+ case ASB_VIOLENTLY:
+ rv = drbd_asb_recover_0p(mdev);
+ break;
+ case ASB_DISCONNECT:
+ break;
+ case ASB_CALL_HELPER:
+ hg = drbd_asb_recover_0p(mdev);
+ if (hg == -1) {
+ /* drbd_change_state() does not sleep while in SS_IN_TRANSIENT_STATE,
+ * we might be here in C_WF_REPORT_PARAMS which is transient.
+ * we do not need to wait for the after state change work either. */
+ self = drbd_change_state(mdev, CS_VERBOSE, NS(role, R_SECONDARY));
+ if (self != SS_SUCCESS) {
+ drbd_khelper(mdev, "pri-lost-after-sb");
+ } else {
+ dev_warn(DEV, "Successfully gave up primary role.\n");
+ rv = hg;
+ }
+ } else
+ rv = hg;
+ }
+
+ return rv;
+}
+
+static void drbd_uuid_dump(struct drbd_conf *mdev, char *text, u64 *uuid,
+ u64 bits, u64 flags)
+{
+ if (!uuid) {
+ dev_info(DEV, "%s uuid info vanished while I was looking!\n", text);
+ return;
+ }
+ dev_info(DEV, "%s %016llX:%016llX:%016llX:%016llX bits:%llu flags:%llX\n",
+ text,
+ (unsigned long long)uuid[UI_CURRENT],
+ (unsigned long long)uuid[UI_BITMAP],
+ (unsigned long long)uuid[UI_HISTORY_START],
+ (unsigned long long)uuid[UI_HISTORY_END],
+ (unsigned long long)bits,
+ (unsigned long long)flags);
+}
+
+/*
+ 100 after split brain try auto recover
+ 2 C_SYNC_SOURCE set BitMap
+ 1 C_SYNC_SOURCE use BitMap
+ 0 no Sync
+ -1 C_SYNC_TARGET use BitMap
+ -2 C_SYNC_TARGET set BitMap
+ -100 after split brain, disconnect
+-1000 unrelated data
+ */
+static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(local)
+{
+ u64 self, peer;
+ int i, j;
+
+ self = mdev->ldev->md.uuid[UI_CURRENT] & ~((u64)1);
+ peer = mdev->p_uuid[UI_CURRENT] & ~((u64)1);
+
+ *rule_nr = 10;
+ if (self == UUID_JUST_CREATED && peer == UUID_JUST_CREATED)
+ return 0;
+
+ *rule_nr = 20;
+ if ((self == UUID_JUST_CREATED || self == (u64)0) &&
+ peer != UUID_JUST_CREATED)
+ return -2;
+
+ *rule_nr = 30;
+ if (self != UUID_JUST_CREATED &&
+ (peer == UUID_JUST_CREATED || peer == (u64)0))
+ return 2;
+
+ if (self == peer) {
+ int rct, dc; /* roles at crash time */
+
+ if (mdev->p_uuid[UI_BITMAP] == (u64)0 && mdev->ldev->md.uuid[UI_BITMAP] != (u64)0) {
+
+ if (mdev->agreed_pro_version < 91)
+ return -1001;
+
+ if ((mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1)) &&
+ (mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START + 1] & ~((u64)1))) {
+ dev_info(DEV, "was SyncSource, missed the resync finished event, corrected myself:\n");
+ drbd_uuid_set_bm(mdev, 0UL);
+
+ drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid,
+ mdev->state.disk >= D_NEGOTIATING ? drbd_bm_total_weight(mdev) : 0, 0);
+ *rule_nr = 34;
+ } else {
+ dev_info(DEV, "was SyncSource (peer failed to write sync_uuid)\n");
+ *rule_nr = 36;
+ }
+
+ return 1;
+ }
+
+ if (mdev->ldev->md.uuid[UI_BITMAP] == (u64)0 && mdev->p_uuid[UI_BITMAP] != (u64)0) {
+
+ if (mdev->agreed_pro_version < 91)
+ return -1001;
+
+ if ((mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (mdev->p_uuid[UI_BITMAP] & ~((u64)1)) &&
+ (mdev->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1))) {
+ dev_info(DEV, "was SyncTarget, peer missed the resync finished event, corrected peer:\n");
+
+ mdev->p_uuid[UI_HISTORY_START + 1] = mdev->p_uuid[UI_HISTORY_START];
+ mdev->p_uuid[UI_HISTORY_START] = mdev->p_uuid[UI_BITMAP];
+ mdev->p_uuid[UI_BITMAP] = 0UL;
+
+ drbd_uuid_dump(mdev, "peer", mdev->p_uuid, mdev->p_uuid[UI_SIZE], mdev->p_uuid[UI_FLAGS]);
+ *rule_nr = 35;
+ } else {
+ dev_info(DEV, "was SyncTarget (failed to write sync_uuid)\n");
+ *rule_nr = 37;
+ }
+
+ return -1;
+ }
+
+ /* Common power [off|failure] */
+ rct = (test_bit(CRASHED_PRIMARY, &mdev->flags) ? 1 : 0) +
+ (mdev->p_uuid[UI_FLAGS] & 2);
+ /* lowest bit is set when we were primary,
+ * next bit (weight 2) is set when peer was primary */
+ *rule_nr = 40;
+
+ switch (rct) {
+ case 0: /* !self_pri && !peer_pri */ return 0;
+ case 1: /* self_pri && !peer_pri */ return 1;
+ case 2: /* !self_pri && peer_pri */ return -1;
+ case 3: /* self_pri && peer_pri */
+ dc = test_bit(DISCARD_CONCURRENT, &mdev->flags);
+ return dc ? -1 : 1;
+ }
+ }
+
+ *rule_nr = 50;
+ peer = mdev->p_uuid[UI_BITMAP] & ~((u64)1);
+ if (self == peer)
+ return -1;
+
+ *rule_nr = 51;
+ peer = mdev->p_uuid[UI_HISTORY_START] & ~((u64)1);
+ if (self == peer) {
+ self = mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1);
+ peer = mdev->p_uuid[UI_HISTORY_START + 1] & ~((u64)1);
+ if (self == peer) {
+ /* The last P_SYNC_UUID did not get though. Undo the last start of
+ resync as sync source modifications of the peer's UUIDs. */
+
+ if (mdev->agreed_pro_version < 91)
+ return -1001;
+
+ mdev->p_uuid[UI_BITMAP] = mdev->p_uuid[UI_HISTORY_START];
+ mdev->p_uuid[UI_HISTORY_START] = mdev->p_uuid[UI_HISTORY_START + 1];
+ return -1;
+ }
+ }
+
+ *rule_nr = 60;
+ self = mdev->ldev->md.uuid[UI_CURRENT] & ~((u64)1);
+ for (i = UI_HISTORY_START; i <= UI_HISTORY_END; i++) {
+ peer = mdev->p_uuid[i] & ~((u64)1);
+ if (self == peer)
+ return -2;
+ }
+
+ *rule_nr = 70;
+ self = mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1);
+ peer = mdev->p_uuid[UI_CURRENT] & ~((u64)1);
+ if (self == peer)
+ return 1;
+
+ *rule_nr = 71;
+ self = mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1);
+ if (self == peer) {
+ self = mdev->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1);
+ peer = mdev->p_uuid[UI_HISTORY_START] & ~((u64)1);
+ if (self == peer) {
+ /* The last P_SYNC_UUID did not get though. Undo the last start of
+ resync as sync source modifications of our UUIDs. */
+
+ if (mdev->agreed_pro_version < 91)
+ return -1001;
+
+ _drbd_uuid_set(mdev, UI_BITMAP, mdev->ldev->md.uuid[UI_HISTORY_START]);
+ _drbd_uuid_set(mdev, UI_HISTORY_START, mdev->ldev->md.uuid[UI_HISTORY_START + 1]);
+
+ dev_info(DEV, "Undid last start of resync:\n");
+
+ drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid,
+ mdev->state.disk >= D_NEGOTIATING ? drbd_bm_total_weight(mdev) : 0, 0);
+
+ return 1;
+ }
+ }
+
+
+ *rule_nr = 80;
+ for (i = UI_HISTORY_START; i <= UI_HISTORY_END; i++) {
+ self = mdev->ldev->md.uuid[i] & ~((u64)1);
+ if (self == peer)
+ return 2;
+ }
+
+ *rule_nr = 90;
+ self = mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1);
+ peer = mdev->p_uuid[UI_BITMAP] & ~((u64)1);
+ if (self == peer && self != ((u64)0))
+ return 100;
+
+ *rule_nr = 100;
+ for (i = UI_HISTORY_START; i <= UI_HISTORY_END; i++) {
+ self = mdev->ldev->md.uuid[i] & ~((u64)1);
+ for (j = UI_HISTORY_START; j <= UI_HISTORY_END; j++) {
+ peer = mdev->p_uuid[j] & ~((u64)1);
+ if (self == peer)
+ return -100;
+ }
+ }
+
+ return -1000;
+}
+
+/* drbd_sync_handshake() returns the new conn state on success, or
+ CONN_MASK (-1) on failure.
+ */
+static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_role peer_role,
+ enum drbd_disk_state peer_disk) __must_hold(local)
+{
+ int hg, rule_nr;
+ enum drbd_conns rv = C_MASK;
+ enum drbd_disk_state mydisk;
+
+ mydisk = mdev->state.disk;
+ if (mydisk == D_NEGOTIATING)
+ mydisk = mdev->new_state_tmp.disk;
+
+ dev_info(DEV, "drbd_sync_handshake:\n");
+ drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid, mdev->comm_bm_set, 0);
+ drbd_uuid_dump(mdev, "peer", mdev->p_uuid,
+ mdev->p_uuid[UI_SIZE], mdev->p_uuid[UI_FLAGS]);
+
+ hg = drbd_uuid_compare(mdev, &rule_nr);
+
+ dev_info(DEV, "uuid_compare()=%d by rule %d\n", hg, rule_nr);
+
+ if (hg == -1000) {
+ dev_alert(DEV, "Unrelated data, aborting!\n");
+ return C_MASK;
+ }
+ if (hg == -1001) {
+ dev_alert(DEV, "To resolve this both sides have to support at least protocol\n");
+ return C_MASK;
+ }
+
+ if ((mydisk == D_INCONSISTENT && peer_disk > D_INCONSISTENT) ||
+ (peer_disk == D_INCONSISTENT && mydisk > D_INCONSISTENT)) {
+ int f = (hg == -100) || abs(hg) == 2;
+ hg = mydisk > D_INCONSISTENT ? 1 : -1;
+ if (f)
+ hg = hg*2;
+ dev_info(DEV, "Becoming sync %s due to disk states.\n",
+ hg > 0 ? "source" : "target");
+ }
+
+ if (hg == 100 || (hg == -100 && mdev->net_conf->always_asbp)) {
+ int pcount = (mdev->state.role == R_PRIMARY)
+ + (peer_role == R_PRIMARY);
+ int forced = (hg == -100);
+
+ switch (pcount) {
+ case 0:
+ hg = drbd_asb_recover_0p(mdev);
+ break;
+ case 1:
+ hg = drbd_asb_recover_1p(mdev);
+ break;
+ case 2:
+ hg = drbd_asb_recover_2p(mdev);
+ break;
+ }
+ if (abs(hg) < 100) {
+ dev_warn(DEV, "Split-Brain detected, %d primaries, "
+ "automatically solved. Sync from %s node\n",
+ pcount, (hg < 0) ? "peer" : "this");
+ if (forced) {
+ dev_warn(DEV, "Doing a full sync, since"
+ " UUIDs where ambiguous.\n");
+ hg = hg*2;
+ }
+ }
+ }
+
+ if (hg == -100) {
+ if (mdev->net_conf->want_lose && !(mdev->p_uuid[UI_FLAGS]&1))
+ hg = -1;
+ if (!mdev->net_conf->want_lose && (mdev->p_uuid[UI_FLAGS]&1))
+ hg = 1;
+
+ if (abs(hg) < 100)
+ dev_warn(DEV, "Split-Brain detected, manually solved. "
+ "Sync from %s node\n",
+ (hg < 0) ? "peer" : "this");
+ }
+
+ if (hg == -100) {
+ dev_alert(DEV, "Split-Brain detected, dropping connection!\n");
+ drbd_khelper(mdev, "split-brain");
+ return C_MASK;
+ }
+
+ if (hg > 0 && mydisk <= D_INCONSISTENT) {
+ dev_err(DEV, "I shall become SyncSource, but I am inconsistent!\n");
+ return C_MASK;
+ }
+
+ if (hg < 0 && /* by intention we do not use mydisk here. */
+ mdev->state.role == R_PRIMARY && mdev->state.disk >= D_CONSISTENT) {
+ switch (mdev->net_conf->rr_conflict) {
+ case ASB_CALL_HELPER:
+ drbd_khelper(mdev, "pri-lost");
+ /* fall through */
+ case ASB_DISCONNECT:
+ dev_err(DEV, "I shall become SyncTarget, but I am primary!\n");
+ return C_MASK;
+ case ASB_VIOLENTLY:
+ dev_warn(DEV, "Becoming SyncTarget, violating the stable-data"
+ "assumption\n");
+ }
+ }
+
+ if (abs(hg) >= 2) {
+ dev_info(DEV, "Writing the whole bitmap, full sync required after drbd_sync_handshake.\n");
+ if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write, "set_n_write from sync_handshake"))
+ return C_MASK;
+ }
+
+ if (hg > 0) { /* become sync source. */
+ rv = C_WF_BITMAP_S;
+ } else if (hg < 0) { /* become sync target */
+ rv = C_WF_BITMAP_T;
+ } else {
+ rv = C_CONNECTED;
+ if (drbd_bm_total_weight(mdev)) {
+ dev_info(DEV, "No resync, but %lu bits in bitmap!\n",
+ drbd_bm_total_weight(mdev));
+ }
+ }
+
+ return rv;
+}
+
+/* returns 1 if invalid */
+static int cmp_after_sb(enum drbd_after_sb_p peer, enum drbd_after_sb_p self)
+{
+ /* ASB_DISCARD_REMOTE - ASB_DISCARD_LOCAL is valid */
+ if ((peer == ASB_DISCARD_REMOTE && self == ASB_DISCARD_LOCAL) ||
+ (self == ASB_DISCARD_REMOTE && peer == ASB_DISCARD_LOCAL))
+ return 0;
+
+ /* any other things with ASB_DISCARD_REMOTE or ASB_DISCARD_LOCAL are invalid */
+ if (peer == ASB_DISCARD_REMOTE || peer == ASB_DISCARD_LOCAL ||
+ self == ASB_DISCARD_REMOTE || self == ASB_DISCARD_LOCAL)
+ return 1;
+
+ /* everything else is valid if they are equal on both sides. */
+ if (peer == self)
+ return 0;
+
+ /* everything es is invalid. */
+ return 1;
+}
+
+static int receive_protocol(struct drbd_conf *mdev, struct p_header *h)
+{
+ struct p_protocol *p = (struct p_protocol *)h;
+ int header_size, data_size;
+ int p_proto, p_after_sb_0p, p_after_sb_1p, p_after_sb_2p;
+ int p_want_lose, p_two_primaries;
+ char p_integrity_alg[SHARED_SECRET_MAX] = "";
+
+ header_size = sizeof(*p) - sizeof(*h);
+ data_size = h->length - header_size;
+
+ if (drbd_recv(mdev, h->payload, header_size) != header_size)
+ return FALSE;
+
+ p_proto = be32_to_cpu(p->protocol);
+ p_after_sb_0p = be32_to_cpu(p->after_sb_0p);
+ p_after_sb_1p = be32_to_cpu(p->after_sb_1p);
+ p_after_sb_2p = be32_to_cpu(p->after_sb_2p);
+ p_want_lose = be32_to_cpu(p->want_lose);
+ p_two_primaries = be32_to_cpu(p->two_primaries);
+
+ if (p_proto != mdev->net_conf->wire_protocol) {
+ dev_err(DEV, "incompatible communication protocols\n");
+ goto disconnect;
+ }
+
+ if (cmp_after_sb(p_after_sb_0p, mdev->net_conf->after_sb_0p)) {
+ dev_err(DEV, "incompatible after-sb-0pri settings\n");
+ goto disconnect;
+ }
+
+ if (cmp_after_sb(p_after_sb_1p, mdev->net_conf->after_sb_1p)) {
+ dev_err(DEV, "incompatible after-sb-1pri settings\n");
+ goto disconnect;
+ }
+
+ if (cmp_after_sb(p_after_sb_2p, mdev->net_conf->after_sb_2p)) {
+ dev_err(DEV, "incompatible after-sb-2pri settings\n");
+ goto disconnect;
+ }
+
+ if (p_want_lose && mdev->net_conf->want_lose) {
+ dev_err(DEV, "both sides have the 'want_lose' flag set\n");
+ goto disconnect;
+ }
+
+ if (p_two_primaries != mdev->net_conf->two_primaries) {
+ dev_err(DEV, "incompatible setting of the two-primaries options\n");
+ goto disconnect;
+ }
+
+ if (mdev->agreed_pro_version >= 87) {
+ unsigned char *my_alg = mdev->net_conf->integrity_alg;
+
+ if (drbd_recv(mdev, p_integrity_alg, data_size) != data_size)
+ return FALSE;
+
+ p_integrity_alg[SHARED_SECRET_MAX-1] = 0;
+ if (strcmp(p_integrity_alg, my_alg)) {
+ dev_err(DEV, "incompatible setting of the data-integrity-alg\n");
+ goto disconnect;
+ }
+ dev_info(DEV, "data-integrity-alg: %s\n",
+ my_alg[0] ? my_alg : (unsigned char *)"<not-used>");
+ }
+
+ return TRUE;
+
+disconnect:
+ drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+ return FALSE;
+}
+
+/* helper function
+ * input: alg name, feature name
+ * return: NULL (alg name was "")
+ * ERR_PTR(error) if something goes wrong
+ * or the crypto hash ptr, if it worked out ok. */
+struct crypto_hash *drbd_crypto_alloc_digest_safe(const struct drbd_conf *mdev,
+ const char *alg, const char *name)
+{
+ struct crypto_hash *tfm;
+
+ if (!alg[0])
+ return NULL;
+
+ tfm = crypto_alloc_hash(alg, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(tfm)) {
+ dev_err(DEV, "Can not allocate \"%s\" as %s (reason: %ld)\n",
+ alg, name, PTR_ERR(tfm));
+ return tfm;
+ }
+ if (!drbd_crypto_is_hash(crypto_hash_tfm(tfm))) {
+ crypto_free_hash(tfm);
+ dev_err(DEV, "\"%s\" is not a digest (%s)\n", alg, name);
+ return ERR_PTR(-EINVAL);
+ }
+ return tfm;
+}
+
+static int receive_SyncParam(struct drbd_conf *mdev, struct p_header *h)
+{
+ int ok = TRUE;
+ struct p_rs_param_89 *p = (struct p_rs_param_89 *)h;
+ unsigned int header_size, data_size, exp_max_sz;
+ struct crypto_hash *verify_tfm = NULL;
+ struct crypto_hash *csums_tfm = NULL;
+ const int apv = mdev->agreed_pro_version;
+
+ exp_max_sz = apv <= 87 ? sizeof(struct p_rs_param)
+ : apv == 88 ? sizeof(struct p_rs_param)
+ + SHARED_SECRET_MAX
+ : /* 89 */ sizeof(struct p_rs_param_89);
+
+ if (h->length > exp_max_sz) {
+ dev_err(DEV, "SyncParam packet too long: received %u, expected <= %u bytes\n",
+ h->length, exp_max_sz);
+ return FALSE;
+ }
+
+ if (apv <= 88) {
+ header_size = sizeof(struct p_rs_param) - sizeof(*h);
+ data_size = h->length - header_size;
+ } else /* apv >= 89 */ {
+ header_size = sizeof(struct p_rs_param_89) - sizeof(*h);
+ data_size = h->length - header_size;
+ D_ASSERT(data_size == 0);
+ }
+
+ /* initialize verify_alg and csums_alg */
+ memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX);
+
+ if (drbd_recv(mdev, h->payload, header_size) != header_size)
+ return FALSE;
+
+ mdev->sync_conf.rate = be32_to_cpu(p->rate);
+
+ if (apv >= 88) {
+ if (apv == 88) {
+ if (data_size > SHARED_SECRET_MAX) {
+ dev_err(DEV, "verify-alg too long, "
+ "peer wants %u, accepting only %u byte\n",
+ data_size, SHARED_SECRET_MAX);
+ return FALSE;
+ }
+
+ if (drbd_recv(mdev, p->verify_alg, data_size) != data_size)
+ return FALSE;
+
+ /* we expect NUL terminated string */
+ /* but just in case someone tries to be evil */
+ D_ASSERT(p->verify_alg[data_size-1] == 0);
+ p->verify_alg[data_size-1] = 0;
+
+ } else /* apv >= 89 */ {
+ /* we still expect NUL terminated strings */
+ /* but just in case someone tries to be evil */
+ D_ASSERT(p->verify_alg[SHARED_SECRET_MAX-1] == 0);
+ D_ASSERT(p->csums_alg[SHARED_SECRET_MAX-1] == 0);
+ p->verify_alg[SHARED_SECRET_MAX-1] = 0;
+ p->csums_alg[SHARED_SECRET_MAX-1] = 0;
+ }
+
+ if (strcmp(mdev->sync_conf.verify_alg, p->verify_alg)) {
+ if (mdev->state.conn == C_WF_REPORT_PARAMS) {
+ dev_err(DEV, "Different verify-alg settings. me=\"%s\" peer=\"%s\"\n",
+ mdev->sync_conf.verify_alg, p->verify_alg);
+ goto disconnect;
+ }
+ verify_tfm = drbd_crypto_alloc_digest_safe(mdev,
+ p->verify_alg, "verify-alg");
+ if (IS_ERR(verify_tfm)) {
+ verify_tfm = NULL;
+ goto disconnect;
+ }
+ }
+
+ if (apv >= 89 && strcmp(mdev->sync_conf.csums_alg, p->csums_alg)) {
+ if (mdev->state.conn == C_WF_REPORT_PARAMS) {
+ dev_err(DEV, "Different csums-alg settings. me=\"%s\" peer=\"%s\"\n",
+ mdev->sync_conf.csums_alg, p->csums_alg);
+ goto disconnect;
+ }
+ csums_tfm = drbd_crypto_alloc_digest_safe(mdev,
+ p->csums_alg, "csums-alg");
+ if (IS_ERR(csums_tfm)) {
+ csums_tfm = NULL;
+ goto disconnect;
+ }
+ }
+
+
+ spin_lock(&mdev->peer_seq_lock);
+ /* lock against drbd_nl_syncer_conf() */
+ if (verify_tfm) {
+ strcpy(mdev->sync_conf.verify_alg, p->verify_alg);
+ mdev->sync_conf.verify_alg_len = strlen(p->verify_alg) + 1;
+ crypto_free_hash(mdev->verify_tfm);
+ mdev->verify_tfm = verify_tfm;
+ dev_info(DEV, "using verify-alg: \"%s\"\n", p->verify_alg);
+ }
+ if (csums_tfm) {
+ strcpy(mdev->sync_conf.csums_alg, p->csums_alg);
+ mdev->sync_conf.csums_alg_len = strlen(p->csums_alg) + 1;
+ crypto_free_hash(mdev->csums_tfm);
+ mdev->csums_tfm = csums_tfm;
+ dev_info(DEV, "using csums-alg: \"%s\"\n", p->csums_alg);
+ }
+ spin_unlock(&mdev->peer_seq_lock);
+ }
+
+ return ok;
+disconnect:
+ /* just for completeness: actually not needed,
+ * as this is not reached if csums_tfm was ok. */
+ crypto_free_hash(csums_tfm);
+ /* but free the verify_tfm again, if csums_tfm did not work out */
+ crypto_free_hash(verify_tfm);
+ drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+ return FALSE;
+}
+
+static void drbd_setup_order_type(struct drbd_conf *mdev, int peer)
+{
+ /* sorry, we currently have no working implementation
+ * of distributed TCQ */
+}
+
+/* warn if the arguments differ by more than 12.5% */
+static void warn_if_differ_considerably(struct drbd_conf *mdev,
+ const char *s, sector_t a, sector_t b)
+{
+ sector_t d;
+ if (a == 0 || b == 0)
+ return;
+ d = (a > b) ? (a - b) : (b - a);
+ if (d > (a>>3) || d > (b>>3))
+ dev_warn(DEV, "Considerable difference in %s: %llus vs. %llus\n", s,
+ (unsigned long long)a, (unsigned long long)b);
+}
+
+static int receive_sizes(struct drbd_conf *mdev, struct p_header *h)
+{
+ struct p_sizes *p = (struct p_sizes *)h;
+ enum determine_dev_size dd = unchanged;
+ unsigned int max_seg_s;
+ sector_t p_size, p_usize, my_usize;
+ int ldsc = 0; /* local disk size changed */
+ enum drbd_conns nconn;
+
+ ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
+ if (drbd_recv(mdev, h->payload, h->length) != h->length)
+ return FALSE;
+
+ p_size = be64_to_cpu(p->d_size);
+ p_usize = be64_to_cpu(p->u_size);
+
+ if (p_size == 0 && mdev->state.disk == D_DISKLESS) {
+ dev_err(DEV, "some backing storage is needed\n");
+ drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+ return FALSE;
+ }
+
+ /* just store the peer's disk size for now.
+ * we still need to figure out whether we accept that. */
+ mdev->p_size = p_size;
+
+#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r))
+ if (get_ldev(mdev)) {
+ warn_if_differ_considerably(mdev, "lower level device sizes",
+ p_size, drbd_get_max_capacity(mdev->ldev));
+ warn_if_differ_considerably(mdev, "user requested size",
+ p_usize, mdev->ldev->dc.disk_size);
+
+ /* if this is the first connect, or an otherwise expected
+ * param exchange, choose the minimum */
+ if (mdev->state.conn == C_WF_REPORT_PARAMS)
+ p_usize = min_not_zero((sector_t)mdev->ldev->dc.disk_size,
+ p_usize);
+
+ my_usize = mdev->ldev->dc.disk_size;
+
+ if (mdev->ldev->dc.disk_size != p_usize) {
+ mdev->ldev->dc.disk_size = p_usize;
+ dev_info(DEV, "Peer sets u_size to %lu sectors\n",
+ (unsigned long)mdev->ldev->dc.disk_size);
+ }
+
+ /* Never shrink a device with usable data during connect.
+ But allow online shrinking if we are connected. */
+ if (drbd_new_dev_size(mdev, mdev->ldev) <
+ drbd_get_capacity(mdev->this_bdev) &&
+ mdev->state.disk >= D_OUTDATED &&
+ mdev->state.conn < C_CONNECTED) {
+ dev_err(DEV, "The peer's disk size is too small!\n");
+ drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+ mdev->ldev->dc.disk_size = my_usize;
+ put_ldev(mdev);
+ return FALSE;
+ }
+ put_ldev(mdev);
+ }
+#undef min_not_zero
+
+ if (get_ldev(mdev)) {
+ dd = drbd_determin_dev_size(mdev);
+ put_ldev(mdev);
+ if (dd == dev_size_error)
+ return FALSE;
+ drbd_md_sync(mdev);
+ } else {
+ /* I am diskless, need to accept the peer's size. */
+ drbd_set_my_capacity(mdev, p_size);
+ }
+
+ if (mdev->p_uuid && mdev->state.conn <= C_CONNECTED && get_ldev(mdev)) {
+ nconn = drbd_sync_handshake(mdev,
+ mdev->state.peer, mdev->state.pdsk);
+ put_ldev(mdev);
+
+ if (nconn == C_MASK) {
+ drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+ return FALSE;
+ }
+
+ if (drbd_request_state(mdev, NS(conn, nconn)) < SS_SUCCESS) {
+ drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+ return FALSE;
+ }
+ }
+
+ if (get_ldev(mdev)) {
+ if (mdev->ldev->known_size != drbd_get_capacity(mdev->ldev->backing_bdev)) {
+ mdev->ldev->known_size = drbd_get_capacity(mdev->ldev->backing_bdev);
+ ldsc = 1;
+ }
+
+ max_seg_s = be32_to_cpu(p->max_segment_size);
+ if (max_seg_s != queue_max_segment_size(mdev->rq_queue))
+ drbd_setup_queue_param(mdev, max_seg_s);
+
+ drbd_setup_order_type(mdev, be32_to_cpu(p->queue_order_type));
+ put_ldev(mdev);
+ }
+
+ if (mdev->state.conn > C_WF_REPORT_PARAMS) {
+ if (be64_to_cpu(p->c_size) !=
+ drbd_get_capacity(mdev->this_bdev) || ldsc) {
+ /* we have different sizes, probably peer
+ * needs to know my new size... */
+ drbd_send_sizes(mdev, 0);
+ }
+ if (test_and_clear_bit(RESIZE_PENDING, &mdev->flags) ||
+ (dd == grew && mdev->state.conn == C_CONNECTED)) {
+ if (mdev->state.pdsk >= D_INCONSISTENT &&
+ mdev->state.disk >= D_INCONSISTENT)
+ resync_after_online_grow(mdev);
+ else
+ set_bit(RESYNC_AFTER_NEG, &mdev->flags);
+ }
+ }
+
+ return TRUE;
+}
+
+static int receive_uuids(struct drbd_conf *mdev, struct p_header *h)
+{
+ struct p_uuids *p = (struct p_uuids *)h;
+ u64 *p_uuid;
+ int i;
+
+ ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
+ if (drbd_recv(mdev, h->payload, h->length) != h->length)
+ return FALSE;
+
+ p_uuid = kmalloc(sizeof(u64)*UI_EXTENDED_SIZE, GFP_NOIO);
+
+ for (i = UI_CURRENT; i < UI_EXTENDED_SIZE; i++)
+ p_uuid[i] = be64_to_cpu(p->uuid[i]);
+
+ kfree(mdev->p_uuid);
+ mdev->p_uuid = p_uuid;
+
+ if (mdev->state.conn < C_CONNECTED &&
+ mdev->state.disk < D_INCONSISTENT &&
+ mdev->state.role == R_PRIMARY &&
+ (mdev->ed_uuid & ~((u64)1)) != (p_uuid[UI_CURRENT] & ~((u64)1))) {
+ dev_err(DEV, "Can only connect to data with current UUID=%016llX\n",
+ (unsigned long long)mdev->ed_uuid);
+ drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+ return FALSE;
+ }
+
+ if (get_ldev(mdev)) {
+ int skip_initial_sync =
+ mdev->state.conn == C_CONNECTED &&
+ mdev->agreed_pro_version >= 90 &&
+ mdev->ldev->md.uuid[UI_CURRENT] == UUID_JUST_CREATED &&
+ (p_uuid[UI_FLAGS] & 8);
+ if (skip_initial_sync) {
+ dev_info(DEV, "Accepted new current UUID, preparing to skip initial sync\n");
+ drbd_bitmap_io(mdev, &drbd_bmio_clear_n_write,
+ "clear_n_write from receive_uuids");
+ _drbd_uuid_set(mdev, UI_CURRENT, p_uuid[UI_CURRENT]);
+ _drbd_uuid_set(mdev, UI_BITMAP, 0);
+ _drbd_set_state(_NS2(mdev, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE),
+ CS_VERBOSE, NULL);
+ drbd_md_sync(mdev);
+ }
+ put_ldev(mdev);
+ }
+
+ /* Before we test for the disk state, we should wait until an eventually
+ ongoing cluster wide state change is finished. That is important if
+ we are primary and are detaching from our disk. We need to see the
+ new disk state... */
+ wait_event(mdev->misc_wait, !test_bit(CLUSTER_ST_CHANGE, &mdev->flags));
+ if (mdev->state.conn >= C_CONNECTED && mdev->state.disk < D_INCONSISTENT)
+ drbd_set_ed_uuid(mdev, p_uuid[UI_CURRENT]);
+
+ return TRUE;
+}
+
+/**
+ * convert_state() - Converts the peer's view of the cluster state to our point of view
+ * @ps: The state as seen by the peer.
+ */
+static union drbd_state convert_state(union drbd_state ps)
+{
+ union drbd_state ms;
+
+ static enum drbd_conns c_tab[] = {
+ [C_CONNECTED] = C_CONNECTED,
+
+ [C_STARTING_SYNC_S] = C_STARTING_SYNC_T,
+ [C_STARTING_SYNC_T] = C_STARTING_SYNC_S,
+ [C_DISCONNECTING] = C_TEAR_DOWN, /* C_NETWORK_FAILURE, */
+ [C_VERIFY_S] = C_VERIFY_T,
+ [C_MASK] = C_MASK,
+ };
+
+ ms.i = ps.i;
+
+ ms.conn = c_tab[ps.conn];
+ ms.peer = ps.role;
+ ms.role = ps.peer;
+ ms.pdsk = ps.disk;
+ ms.disk = ps.pdsk;
+ ms.peer_isp = (ps.aftr_isp | ps.user_isp);
+
+ return ms;
+}
+
+static int receive_req_state(struct drbd_conf *mdev, struct p_header *h)
+{
+ struct p_req_state *p = (struct p_req_state *)h;
+ union drbd_state mask, val;
+ int rv;
+
+ ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
+ if (drbd_recv(mdev, h->payload, h->length) != h->length)
+ return FALSE;
+
+ mask.i = be32_to_cpu(p->mask);
+ val.i = be32_to_cpu(p->val);
+
+ if (test_bit(DISCARD_CONCURRENT, &mdev->flags) &&
+ test_bit(CLUSTER_ST_CHANGE, &mdev->flags)) {
+ drbd_send_sr_reply(mdev, SS_CONCURRENT_ST_CHG);
+ return TRUE;
+ }
+
+ mask = convert_state(mask);
+ val = convert_state(val);
+
+ rv = drbd_change_state(mdev, CS_VERBOSE, mask, val);
+
+ drbd_send_sr_reply(mdev, rv);
+ drbd_md_sync(mdev);
+
+ return TRUE;
+}
+
+static int receive_state(struct drbd_conf *mdev, struct p_header *h)
+{
+ struct p_state *p = (struct p_state *)h;
+ enum drbd_conns nconn, oconn;
+ union drbd_state ns, peer_state;
+ enum drbd_disk_state real_peer_disk;
+ int rv;
+
+ ERR_IF(h->length != (sizeof(*p)-sizeof(*h)))
+ return FALSE;
+
+ if (drbd_recv(mdev, h->payload, h->length) != h->length)
+ return FALSE;
+
+ peer_state.i = be32_to_cpu(p->state);
+
+ real_peer_disk = peer_state.disk;
+ if (peer_state.disk == D_NEGOTIATING) {
+ real_peer_disk = mdev->p_uuid[UI_FLAGS] & 4 ? D_INCONSISTENT : D_CONSISTENT;
+ dev_info(DEV, "real peer disk state = %s\n", drbd_disk_str(real_peer_disk));
+ }
+
+ spin_lock_irq(&mdev->req_lock);
+ retry:
+ oconn = nconn = mdev->state.conn;
+ spin_unlock_irq(&mdev->req_lock);
+
+ if (nconn == C_WF_REPORT_PARAMS)
+ nconn = C_CONNECTED;
+
+ if (mdev->p_uuid && peer_state.disk >= D_NEGOTIATING &&
+ get_ldev_if_state(mdev, D_NEGOTIATING)) {
+ int cr; /* consider resync */
+
+ /* if we established a new connection */
+ cr = (oconn < C_CONNECTED);
+ /* if we had an established connection
+ * and one of the nodes newly attaches a disk */
+ cr |= (oconn == C_CONNECTED &&
+ (peer_state.disk == D_NEGOTIATING ||
+ mdev->state.disk == D_NEGOTIATING));
+ /* if we have both been inconsistent, and the peer has been
+ * forced to be UpToDate with --overwrite-data */
+ cr |= test_bit(CONSIDER_RESYNC, &mdev->flags);
+ /* if we had been plain connected, and the admin requested to
+ * start a sync by "invalidate" or "invalidate-remote" */
+ cr |= (oconn == C_CONNECTED &&
+ (peer_state.conn >= C_STARTING_SYNC_S &&
+ peer_state.conn <= C_WF_BITMAP_T));
+
+ if (cr)
+ nconn = drbd_sync_handshake(mdev, peer_state.role, real_peer_disk);
+
+ put_ldev(mdev);
+ if (nconn == C_MASK) {
+ if (mdev->state.disk == D_NEGOTIATING) {
+ drbd_force_state(mdev, NS(disk, D_DISKLESS));
+ nconn = C_CONNECTED;
+ } else if (peer_state.disk == D_NEGOTIATING) {
+ dev_err(DEV, "Disk attach process on the peer node was aborted.\n");
+ peer_state.disk = D_DISKLESS;
+ } else {
+ D_ASSERT(oconn == C_WF_REPORT_PARAMS);
+ drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+ return FALSE;
+ }
+ }
+ }
+
+ spin_lock_irq(&mdev->req_lock);
+ if (mdev->state.conn != oconn)
+ goto retry;
+ clear_bit(CONSIDER_RESYNC, &mdev->flags);
+ ns.i = mdev->state.i;
+ ns.conn = nconn;
+ ns.peer = peer_state.role;
+ ns.pdsk = real_peer_disk;
+ ns.peer_isp = (peer_state.aftr_isp | peer_state.user_isp);
+ if ((nconn == C_CONNECTED || nconn == C_WF_BITMAP_S) && ns.disk == D_NEGOTIATING)
+ ns.disk = mdev->new_state_tmp.disk;
+
+ rv = _drbd_set_state(mdev, ns, CS_VERBOSE | CS_HARD, NULL);
+ ns = mdev->state;
+ spin_unlock_irq(&mdev->req_lock);
+
+ if (rv < SS_SUCCESS) {
+ drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+ return FALSE;
+ }
+
+ if (oconn > C_WF_REPORT_PARAMS) {
+ if (nconn > C_CONNECTED && peer_state.conn <= C_CONNECTED &&
+ peer_state.disk != D_NEGOTIATING ) {
+ /* we want resync, peer has not yet decided to sync... */
+ /* Nowadays only used when forcing a node into primary role and
+ setting its disk to UpToDate with that */
+ drbd_send_uuids(mdev);
+ drbd_send_state(mdev);
+ }
+ }
+
+ mdev->net_conf->want_lose = 0;
+
+ drbd_md_sync(mdev); /* update connected indicator, la_size, ... */
+
+ return TRUE;
+}
+
+static int receive_sync_uuid(struct drbd_conf *mdev, struct p_header *h)
+{
+ struct p_rs_uuid *p = (struct p_rs_uuid *)h;
+
+ wait_event(mdev->misc_wait,
+ mdev->state.conn == C_WF_SYNC_UUID ||
+ mdev->state.conn < C_CONNECTED ||
+ mdev->state.disk < D_NEGOTIATING);
+
+ /* D_ASSERT( mdev->state.conn == C_WF_SYNC_UUID ); */
+
+ ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
+ if (drbd_recv(mdev, h->payload, h->length) != h->length)
+ return FALSE;
+
+ /* Here the _drbd_uuid_ functions are right, current should
+ _not_ be rotated into the history */
+ if (get_ldev_if_state(mdev, D_NEGOTIATING)) {
+ _drbd_uuid_set(mdev, UI_CURRENT, be64_to_cpu(p->uuid));
+ _drbd_uuid_set(mdev, UI_BITMAP, 0UL);
+
+ drbd_start_resync(mdev, C_SYNC_TARGET);
+
+ put_ldev(mdev);
+ } else
+ dev_err(DEV, "Ignoring SyncUUID packet!\n");
+
+ return TRUE;
+}
+
+enum receive_bitmap_ret { OK, DONE, FAILED };
+
+static enum receive_bitmap_ret
+receive_bitmap_plain(struct drbd_conf *mdev, struct p_header *h,
+ unsigned long *buffer, struct bm_xfer_ctx *c)
+{
+ unsigned num_words = min_t(size_t, BM_PACKET_WORDS, c->bm_words - c->word_offset);
+ unsigned want = num_words * sizeof(long);
+
+ if (want != h->length) {
+ dev_err(DEV, "%s:want (%u) != h->length (%u)\n", __func__, want, h->length);
+ return FAILED;
+ }
+ if (want == 0)
+ return DONE;
+ if (drbd_recv(mdev, buffer, want) != want)
+ return FAILED;
+
+ drbd_bm_merge_lel(mdev, c->word_offset, num_words, buffer);
+
+ c->word_offset += num_words;
+ c->bit_offset = c->word_offset * BITS_PER_LONG;
+ if (c->bit_offset > c->bm_bits)
+ c->bit_offset = c->bm_bits;
+
+ return OK;
+}
+
+static enum receive_bitmap_ret
+recv_bm_rle_bits(struct drbd_conf *mdev,
+ struct p_compressed_bm *p,
+ struct bm_xfer_ctx *c)
+{
+ struct bitstream bs;
+ u64 look_ahead;
+ u64 rl;
+ u64 tmp;
+ unsigned long s = c->bit_offset;
+ unsigned long e;
+ int len = p->head.length - (sizeof(*p) - sizeof(p->head));
+ int toggle = DCBP_get_start(p);
+ int have;
+ int bits;
+
+ bitstream_init(&bs, p->code, len, DCBP_get_pad_bits(p));
+
+ bits = bitstream_get_bits(&bs, &look_ahead, 64);
+ if (bits < 0)
+ return FAILED;
+
+ for (have = bits; have > 0; s += rl, toggle = !toggle) {
+ bits = vli_decode_bits(&rl, look_ahead);
+ if (bits <= 0)
+ return FAILED;
+
+ if (toggle) {
+ e = s + rl -1;
+ if (e >= c->bm_bits) {
+ dev_err(DEV, "bitmap overflow (e:%lu) while decoding bm RLE packet\n", e);
+ return FAILED;
+ }
+ _drbd_bm_set_bits(mdev, s, e);
+ }
+
+ if (have < bits) {
+ dev_err(DEV, "bitmap decoding error: h:%d b:%d la:0x%08llx l:%u/%u\n",
+ have, bits, look_ahead,
+ (unsigned int)(bs.cur.b - p->code),
+ (unsigned int)bs.buf_len);
+ return FAILED;
+ }
+ look_ahead >>= bits;
+ have -= bits;
+
+ bits = bitstream_get_bits(&bs, &tmp, 64 - have);
+ if (bits < 0)
+ return FAILED;
+ look_ahead |= tmp << have;
+ have += bits;
+ }
+
+ c->bit_offset = s;
+ bm_xfer_ctx_bit_to_word_offset(c);
+
+ return (s == c->bm_bits) ? DONE : OK;
+}
+
+static enum receive_bitmap_ret
+decode_bitmap_c(struct drbd_conf *mdev,
+ struct p_compressed_bm *p,
+ struct bm_xfer_ctx *c)
+{
+ if (DCBP_get_code(p) == RLE_VLI_Bits)
+ return recv_bm_rle_bits(mdev, p, c);
+
+ /* other variants had been implemented for evaluation,
+ * but have been dropped as this one turned out to be "best"
+ * during all our tests. */
+
+ dev_err(DEV, "receive_bitmap_c: unknown encoding %u\n", p->encoding);
+ drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR));
+ return FAILED;
+}
+
+void INFO_bm_xfer_stats(struct drbd_conf *mdev,
+ const char *direction, struct bm_xfer_ctx *c)
+{
+ /* what would it take to transfer it "plaintext" */
+ unsigned plain = sizeof(struct p_header) *
+ ((c->bm_words+BM_PACKET_WORDS-1)/BM_PACKET_WORDS+1)
+ + c->bm_words * sizeof(long);
+ unsigned total = c->bytes[0] + c->bytes[1];
+ unsigned r;
+
+ /* total can not be zero. but just in case: */
+ if (total == 0)
+ return;
+
+ /* don't report if not compressed */
+ if (total >= plain)
+ return;
+
+ /* total < plain. check for overflow, still */
+ r = (total > UINT_MAX/1000) ? (total / (plain/1000))
+ : (1000 * total / plain);
+
+ if (r > 1000)
+ r = 1000;
+
+ r = 1000 - r;
+ dev_info(DEV, "%s bitmap stats [Bytes(packets)]: plain %u(%u), RLE %u(%u), "
+ "total %u; compression: %u.%u%%\n",
+ direction,
+ c->bytes[1], c->packets[1],
+ c->bytes[0], c->packets[0],
+ total, r/10, r % 10);
+}
+
+/* Since we are processing the bitfield from lower addresses to higher,
+ it does not matter if the process it in 32 bit chunks or 64 bit
+ chunks as long as it is little endian. (Understand it as byte stream,
+ beginning with the lowest byte...) If we would use big endian
+ we would need to process it from the highest address to the lowest,
+ in order to be agnostic to the 32 vs 64 bits issue.
+
+ returns 0 on failure, 1 if we successfully received it. */
+static int receive_bitmap(struct drbd_conf *mdev, struct p_header *h)
+{
+ struct bm_xfer_ctx c;
+ void *buffer;
+ enum receive_bitmap_ret ret;
+ int ok = FALSE;
+
+ wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt));
+
+ drbd_bm_lock(mdev, "receive bitmap");
+
+ /* maybe we should use some per thread scratch page,
+ * and allocate that during initial device creation? */
+ buffer = (unsigned long *) __get_free_page(GFP_NOIO);
+ if (!buffer) {
+ dev_err(DEV, "failed to allocate one page buffer in %s\n", __func__);
+ goto out;
+ }
+
+ c = (struct bm_xfer_ctx) {
+ .bm_bits = drbd_bm_bits(mdev),
+ .bm_words = drbd_bm_words(mdev),
+ };
+
+ do {
+ if (h->command == P_BITMAP) {
+ ret = receive_bitmap_plain(mdev, h, buffer, &c);
+ } else if (h->command == P_COMPRESSED_BITMAP) {
+ /* MAYBE: sanity check that we speak proto >= 90,
+ * and the feature is enabled! */
+ struct p_compressed_bm *p;
+
+ if (h->length > BM_PACKET_PAYLOAD_BYTES) {
+ dev_err(DEV, "ReportCBitmap packet too large\n");
+ goto out;
+ }
+ /* use the page buff */
+ p = buffer;
+ memcpy(p, h, sizeof(*h));
+ if (drbd_recv(mdev, p->head.payload, h->length) != h->length)
+ goto out;
+ if (p->head.length <= (sizeof(*p) - sizeof(p->head))) {
+ dev_err(DEV, "ReportCBitmap packet too small (l:%u)\n", p->head.length);
+ return FAILED;
+ }
+ ret = decode_bitmap_c(mdev, p, &c);
+ } else {
+ dev_warn(DEV, "receive_bitmap: h->command neither ReportBitMap nor ReportCBitMap (is 0x%x)", h->command);
+ goto out;
+ }
+
+ c.packets[h->command == P_BITMAP]++;
+ c.bytes[h->command == P_BITMAP] += sizeof(struct p_header) + h->length;
+
+ if (ret != OK)
+ break;
+
+ if (!drbd_recv_header(mdev, h))
+ goto out;
+ } while (ret == OK);
+ if (ret == FAILED)
+ goto out;
+
+ INFO_bm_xfer_stats(mdev, "receive", &c);
+
+ if (mdev->state.conn == C_WF_BITMAP_T) {
+ ok = !drbd_send_bitmap(mdev);
+ if (!ok)
+ goto out;
+ /* Omit CS_ORDERED with this state transition to avoid deadlocks. */
+ ok = _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE);
+ D_ASSERT(ok == SS_SUCCESS);
+ } else if (mdev->state.conn != C_WF_BITMAP_S) {
+ /* admin may have requested C_DISCONNECTING,
+ * other threads may have noticed network errors */
+ dev_info(DEV, "unexpected cstate (%s) in receive_bitmap\n",
+ drbd_conn_str(mdev->state.conn));
+ }
+
+ ok = TRUE;
+ out:
+ drbd_bm_unlock(mdev);
+ if (ok && mdev->state.conn == C_WF_BITMAP_S)
+ drbd_start_resync(mdev, C_SYNC_SOURCE);
+ free_page((unsigned long) buffer);
+ return ok;
+}
+
+static int receive_skip(struct drbd_conf *mdev, struct p_header *h)
+{
+ /* TODO zero copy sink :) */
+ static char sink[128];
+ int size, want, r;
+
+ dev_warn(DEV, "skipping unknown optional packet type %d, l: %d!\n",
+ h->command, h->length);
+
+ size = h->length;
+ while (size > 0) {
+ want = min_t(int, size, sizeof(sink));
+ r = drbd_recv(mdev, sink, want);
+ ERR_IF(r <= 0) break;
+ size -= r;
+ }
+ return size == 0;
+}
+
+static int receive_UnplugRemote(struct drbd_conf *mdev, struct p_header *h)
+{
+ if (mdev->state.disk >= D_INCONSISTENT)
+ drbd_kick_lo(mdev);
+
+ /* Make sure we've acked all the TCP data associated
+ * with the data requests being unplugged */
+ drbd_tcp_quickack(mdev->data.socket);
+
+ return TRUE;
+}
+
+typedef int (*drbd_cmd_handler_f)(struct drbd_conf *, struct p_header *);
+
+static drbd_cmd_handler_f drbd_default_handler[] = {
+ [P_DATA] = receive_Data,
+ [P_DATA_REPLY] = receive_DataReply,
+ [P_RS_DATA_REPLY] = receive_RSDataReply,
+ [P_BARRIER] = receive_Barrier,
+ [P_BITMAP] = receive_bitmap,
+ [P_COMPRESSED_BITMAP] = receive_bitmap,
+ [P_UNPLUG_REMOTE] = receive_UnplugRemote,
+ [P_DATA_REQUEST] = receive_DataRequest,
+ [P_RS_DATA_REQUEST] = receive_DataRequest,
+ [P_SYNC_PARAM] = receive_SyncParam,
+ [P_SYNC_PARAM89] = receive_SyncParam,
+ [P_PROTOCOL] = receive_protocol,
+ [P_UUIDS] = receive_uuids,
+ [P_SIZES] = receive_sizes,
+ [P_STATE] = receive_state,
+ [P_STATE_CHG_REQ] = receive_req_state,
+ [P_SYNC_UUID] = receive_sync_uuid,
+ [P_OV_REQUEST] = receive_DataRequest,
+ [P_OV_REPLY] = receive_DataRequest,
+ [P_CSUM_RS_REQUEST] = receive_DataRequest,
+ /* anything missing from this table is in
+ * the asender_tbl, see get_asender_cmd */
+ [P_MAX_CMD] = NULL,
+};
+
+static drbd_cmd_handler_f *drbd_cmd_handler = drbd_default_handler;
+static drbd_cmd_handler_f *drbd_opt_cmd_handler;
+
+static void drbdd(struct drbd_conf *mdev)
+{
+ drbd_cmd_handler_f handler;
+ struct p_header *header = &mdev->data.rbuf.header;
+
+ while (get_t_state(&mdev->receiver) == Running) {
+ drbd_thread_current_set_cpu(mdev);
+ if (!drbd_recv_header(mdev, header))
+ break;
+
+ if (header->command < P_MAX_CMD)
+ handler = drbd_cmd_handler[header->command];
+ else if (P_MAY_IGNORE < header->command
+ && header->command < P_MAX_OPT_CMD)
+ handler = drbd_opt_cmd_handler[header->command-P_MAY_IGNORE];
+ else if (header->command > P_MAX_OPT_CMD)
+ handler = receive_skip;
+ else
+ handler = NULL;
+
+ if (unlikely(!handler)) {
+ dev_err(DEV, "unknown packet type %d, l: %d!\n",
+ header->command, header->length);
+ drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR));
+ break;
+ }
+ if (unlikely(!handler(mdev, header))) {
+ dev_err(DEV, "error receiving %s, l: %d!\n",
+ cmdname(header->command), header->length);
+ drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR));
+ break;
+ }
+ }
+}
+
+static void drbd_fail_pending_reads(struct drbd_conf *mdev)
+{
+ struct hlist_head *slot;
+ struct hlist_node *pos;
+ struct hlist_node *tmp;
+ struct drbd_request *req;
+ int i;
+
+ /*
+ * Application READ requests
+ */
+ spin_lock_irq(&mdev->req_lock);
+ for (i = 0; i < APP_R_HSIZE; i++) {
+ slot = mdev->app_reads_hash+i;
+ hlist_for_each_entry_safe(req, pos, tmp, slot, colision) {
+ /* it may (but should not any longer!)
+ * be on the work queue; if that assert triggers,
+ * we need to also grab the
+ * spin_lock_irq(&mdev->data.work.q_lock);
+ * and list_del_init here. */
+ D_ASSERT(list_empty(&req->w.list));
+ /* It would be nice to complete outside of spinlock.
+ * But this is easier for now. */
+ _req_mod(req, connection_lost_while_pending);
+ }
+ }
+ for (i = 0; i < APP_R_HSIZE; i++)
+ if (!hlist_empty(mdev->app_reads_hash+i))
+ dev_warn(DEV, "ASSERT FAILED: app_reads_hash[%d].first: "
+ "%p, should be NULL\n", i, mdev->app_reads_hash[i].first);
+
+ memset(mdev->app_reads_hash, 0, APP_R_HSIZE*sizeof(void *));
+ spin_unlock_irq(&mdev->req_lock);
+}
+
+void drbd_flush_workqueue(struct drbd_conf *mdev)
+{
+ struct drbd_wq_barrier barr;
+
+ barr.w.cb = w_prev_work_done;
+ init_completion(&barr.done);
+ drbd_queue_work(&mdev->data.work, &barr.w);
+ wait_for_completion(&barr.done);
+}
+
+static void drbd_disconnect(struct drbd_conf *mdev)
+{
+ enum drbd_fencing_p fp;
+ union drbd_state os, ns;
+ int rv = SS_UNKNOWN_ERROR;
+ unsigned int i;
+
+ if (mdev->state.conn == C_STANDALONE)
+ return;
+ if (mdev->state.conn >= C_WF_CONNECTION)
+ dev_err(DEV, "ASSERT FAILED cstate = %s, expected < WFConnection\n",
+ drbd_conn_str(mdev->state.conn));
+
+ /* asender does not clean up anything. it must not interfere, either */
+ drbd_thread_stop(&mdev->asender);
+
+ mutex_lock(&mdev->data.mutex);
+ drbd_free_sock(mdev);
+ mutex_unlock(&mdev->data.mutex);
+
+ spin_lock_irq(&mdev->req_lock);
+ _drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
+ _drbd_wait_ee_list_empty(mdev, &mdev->sync_ee);
+ _drbd_wait_ee_list_empty(mdev, &mdev->read_ee);
+ spin_unlock_irq(&mdev->req_lock);
+
+ /* We do not have data structures that would allow us to
+ * get the rs_pending_cnt down to 0 again.
+ * * On C_SYNC_TARGET we do not have any data structures describing
+ * the pending RSDataRequest's we have sent.
+ * * On C_SYNC_SOURCE there is no data structure that tracks
+ * the P_RS_DATA_REPLY blocks that we sent to the SyncTarget.
+ * And no, it is not the sum of the reference counts in the
+ * resync_LRU. The resync_LRU tracks the whole operation including
+ * the disk-IO, while the rs_pending_cnt only tracks the blocks
+ * on the fly. */
+ drbd_rs_cancel_all(mdev);
+ mdev->rs_total = 0;
+ mdev->rs_failed = 0;
+ atomic_set(&mdev->rs_pending_cnt, 0);
+ wake_up(&mdev->misc_wait);
+
+ /* make sure syncer is stopped and w_resume_next_sg queued */
+ del_timer_sync(&mdev->resync_timer);
+ set_bit(STOP_SYNC_TIMER, &mdev->flags);
+ resync_timer_fn((unsigned long)mdev);
+
+ /* so we can be sure that all remote or resync reads
+ * made it at least to net_ee */
+ wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
+
+ /* wait for all w_e_end_data_req, w_e_end_rsdata_req, w_send_barrier,
+ * w_make_resync_request etc. which may still be on the worker queue
+ * to be "canceled" */
+ drbd_flush_workqueue(mdev);
+
+ /* This also does reclaim_net_ee(). If we do this too early, we might
+ * miss some resync ee and pages.*/
+ drbd_process_done_ee(mdev);
+
+ kfree(mdev->p_uuid);
+ mdev->p_uuid = NULL;
+
+ if (!mdev->state.susp)
+ tl_clear(mdev);
+
+ drbd_fail_pending_reads(mdev);
+
+ dev_info(DEV, "Connection closed\n");
+
+ drbd_md_sync(mdev);
+
+ fp = FP_DONT_CARE;
+ if (get_ldev(mdev)) {
+ fp = mdev->ldev->dc.fencing;
+ put_ldev(mdev);
+ }
+
+ if (mdev->state.role == R_PRIMARY) {
+ if (fp >= FP_RESOURCE && mdev->state.pdsk >= D_UNKNOWN) {
+ enum drbd_disk_state nps = drbd_try_outdate_peer(mdev);
+ drbd_request_state(mdev, NS(pdsk, nps));
+ }
+ }
+
+ spin_lock_irq(&mdev->req_lock);
+ os = mdev->state;
+ if (os.conn >= C_UNCONNECTED) {
+ /* Do not restart in case we are C_DISCONNECTING */
+ ns = os;
+ ns.conn = C_UNCONNECTED;
+ rv = _drbd_set_state(mdev, ns, CS_VERBOSE, NULL);
+ }
+ spin_unlock_irq(&mdev->req_lock);
+
+ if (os.conn == C_DISCONNECTING) {
+ struct hlist_head *h;
+ wait_event(mdev->misc_wait, atomic_read(&mdev->net_cnt) == 0);
+
+ /* we must not free the tl_hash
+ * while application io is still on the fly */
+ wait_event(mdev->misc_wait, atomic_read(&mdev->ap_bio_cnt) == 0);
+
+ spin_lock_irq(&mdev->req_lock);
+ /* paranoia code */
+ for (h = mdev->ee_hash; h < mdev->ee_hash + mdev->ee_hash_s; h++)
+ if (h->first)
+ dev_err(DEV, "ASSERT FAILED ee_hash[%u].first == %p, expected NULL\n",
+ (int)(h - mdev->ee_hash), h->first);
+ kfree(mdev->ee_hash);
+ mdev->ee_hash = NULL;
+ mdev->ee_hash_s = 0;
+
+ /* paranoia code */
+ for (h = mdev->tl_hash; h < mdev->tl_hash + mdev->tl_hash_s; h++)
+ if (h->first)
+ dev_err(DEV, "ASSERT FAILED tl_hash[%u] == %p, expected NULL\n",
+ (int)(h - mdev->tl_hash), h->first);
+ kfree(mdev->tl_hash);
+ mdev->tl_hash = NULL;
+ mdev->tl_hash_s = 0;
+ spin_unlock_irq(&mdev->req_lock);
+
+ crypto_free_hash(mdev->cram_hmac_tfm);
+ mdev->cram_hmac_tfm = NULL;
+
+ kfree(mdev->net_conf);
+ mdev->net_conf = NULL;
+ drbd_request_state(mdev, NS(conn, C_STANDALONE));
+ }
+
+ /* tcp_close and release of sendpage pages can be deferred. I don't
+ * want to use SO_LINGER, because apparently it can be deferred for
+ * more than 20 seconds (longest time I checked).
+ *
+ * Actually we don't care for exactly when the network stack does its
+ * put_page(), but release our reference on these pages right here.
+ */
+ i = drbd_release_ee(mdev, &mdev->net_ee);
+ if (i)
+ dev_info(DEV, "net_ee not empty, killed %u entries\n", i);
+ i = atomic_read(&mdev->pp_in_use);
+ if (i)
+ dev_info(DEV, "pp_in_use = %u, expected 0\n", i);
+
+ D_ASSERT(list_empty(&mdev->read_ee));
+ D_ASSERT(list_empty(&mdev->active_ee));
+ D_ASSERT(list_empty(&mdev->sync_ee));
+ D_ASSERT(list_empty(&mdev->done_ee));
+
+ /* ok, no more ee's on the fly, it is safe to reset the epoch_size */
+ atomic_set(&mdev->current_epoch->epoch_size, 0);
+ D_ASSERT(list_empty(&mdev->current_epoch->list));
+}
+
+/*
+ * We support PRO_VERSION_MIN to PRO_VERSION_MAX. The protocol version
+ * we can agree on is stored in agreed_pro_version.
+ *
+ * feature flags and the reserved array should be enough room for future
+ * enhancements of the handshake protocol, and possible plugins...
+ *
+ * for now, they are expected to be zero, but ignored.
+ */
+static int drbd_send_handshake(struct drbd_conf *mdev)
+{
+ /* ASSERT current == mdev->receiver ... */
+ struct p_handshake *p = &mdev->data.sbuf.handshake;
+ int ok;
+
+ if (mutex_lock_interruptible(&mdev->data.mutex)) {
+ dev_err(DEV, "interrupted during initial handshake\n");
+ return 0; /* interrupted. not ok. */
+ }
+
+ if (mdev->data.socket == NULL) {
+ mutex_unlock(&mdev->data.mutex);
+ return 0;
+ }
+
+ memset(p, 0, sizeof(*p));
+ p->protocol_min = cpu_to_be32(PRO_VERSION_MIN);
+ p->protocol_max = cpu_to_be32(PRO_VERSION_MAX);
+ ok = _drbd_send_cmd( mdev, mdev->data.socket, P_HAND_SHAKE,
+ (struct p_header *)p, sizeof(*p), 0 );
+ mutex_unlock(&mdev->data.mutex);
+ return ok;
+}
+
+/*
+ * return values:
+ * 1 yes, we have a valid connection
+ * 0 oops, did not work out, please try again
+ * -1 peer talks different language,
+ * no point in trying again, please go standalone.
+ */
+static int drbd_do_handshake(struct drbd_conf *mdev)
+{
+ /* ASSERT current == mdev->receiver ... */
+ struct p_handshake *p = &mdev->data.rbuf.handshake;
+ const int expect = sizeof(struct p_handshake)
+ -sizeof(struct p_header);
+ int rv;
+
+ rv = drbd_send_handshake(mdev);
+ if (!rv)
+ return 0;
+
+ rv = drbd_recv_header(mdev, &p->head);
+ if (!rv)
+ return 0;
+
+ if (p->head.command != P_HAND_SHAKE) {
+ dev_err(DEV, "expected HandShake packet, received: %s (0x%04x)\n",
+ cmdname(p->head.command), p->head.command);
+ return -1;
+ }
+
+ if (p->head.length != expect) {
+ dev_err(DEV, "expected HandShake length: %u, received: %u\n",
+ expect, p->head.length);
+ return -1;
+ }
+
+ rv = drbd_recv(mdev, &p->head.payload, expect);
+
+ if (rv != expect) {
+ dev_err(DEV, "short read receiving handshake packet: l=%u\n", rv);
+ return 0;
+ }
+
+ p->protocol_min = be32_to_cpu(p->protocol_min);
+ p->protocol_max = be32_to_cpu(p->protocol_max);
+ if (p->protocol_max == 0)
+ p->protocol_max = p->protocol_min;
+
+ if (PRO_VERSION_MAX < p->protocol_min ||
+ PRO_VERSION_MIN > p->protocol_max)
+ goto incompat;
+
+ mdev->agreed_pro_version = min_t(int, PRO_VERSION_MAX, p->protocol_max);
+
+ dev_info(DEV, "Handshake successful: "
+ "Agreed network protocol version %d\n", mdev->agreed_pro_version);
+
+ return 1;
+
+ incompat:
+ dev_err(DEV, "incompatible DRBD dialects: "
+ "I support %d-%d, peer supports %d-%d\n",
+ PRO_VERSION_MIN, PRO_VERSION_MAX,
+ p->protocol_min, p->protocol_max);
+ return -1;
+}
+
+#if !defined(CONFIG_CRYPTO_HMAC) && !defined(CONFIG_CRYPTO_HMAC_MODULE)
+static int drbd_do_auth(struct drbd_conf *mdev)
+{
+ dev_err(DEV, "This kernel was build without CONFIG_CRYPTO_HMAC.\n");
+ dev_err(DEV, "You need to disable 'cram-hmac-alg' in drbd.conf.\n");
+ return 0;
+}
+#else
+#define CHALLENGE_LEN 64
+static int drbd_do_auth(struct drbd_conf *mdev)
+{
+ char my_challenge[CHALLENGE_LEN]; /* 64 Bytes... */
+ struct scatterlist sg;
+ char *response = NULL;
+ char *right_response = NULL;
+ char *peers_ch = NULL;
+ struct p_header p;
+ unsigned int key_len = strlen(mdev->net_conf->shared_secret);
+ unsigned int resp_size;
+ struct hash_desc desc;
+ int rv;
+
+ desc.tfm = mdev->cram_hmac_tfm;
+ desc.flags = 0;
+
+ rv = crypto_hash_setkey(mdev->cram_hmac_tfm,
+ (u8 *)mdev->net_conf->shared_secret, key_len);
+ if (rv) {
+ dev_err(DEV, "crypto_hash_setkey() failed with %d\n", rv);
+ rv = 0;
+ goto fail;
+ }
+
+ get_random_bytes(my_challenge, CHALLENGE_LEN);
+
+ rv = drbd_send_cmd2(mdev, P_AUTH_CHALLENGE, my_challenge, CHALLENGE_LEN);
+ if (!rv)
+ goto fail;
+
+ rv = drbd_recv_header(mdev, &p);
+ if (!rv)
+ goto fail;
+
+ if (p.command != P_AUTH_CHALLENGE) {
+ dev_err(DEV, "expected AuthChallenge packet, received: %s (0x%04x)\n",
+ cmdname(p.command), p.command);
+ rv = 0;
+ goto fail;
+ }
+
+ if (p.length > CHALLENGE_LEN*2) {
+ dev_err(DEV, "expected AuthChallenge payload too big.\n");
+ rv = 0;
+ goto fail;
+ }
+
+ peers_ch = kmalloc(p.length, GFP_NOIO);
+ if (peers_ch == NULL) {
+ dev_err(DEV, "kmalloc of peers_ch failed\n");
+ rv = 0;
+ goto fail;
+ }
+
+ rv = drbd_recv(mdev, peers_ch, p.length);
+
+ if (rv != p.length) {
+ dev_err(DEV, "short read AuthChallenge: l=%u\n", rv);
+ rv = 0;
+ goto fail;
+ }
+
+ resp_size = crypto_hash_digestsize(mdev->cram_hmac_tfm);
+ response = kmalloc(resp_size, GFP_NOIO);
+ if (response == NULL) {
+ dev_err(DEV, "kmalloc of response failed\n");
+ rv = 0;
+ goto fail;
+ }
+
+ sg_init_table(&sg, 1);
+ sg_set_buf(&sg, peers_ch, p.length);
+
+ rv = crypto_hash_digest(&desc, &sg, sg.length, response);
+ if (rv) {
+ dev_err(DEV, "crypto_hash_digest() failed with %d\n", rv);
+ rv = 0;
+ goto fail;
+ }
+
+ rv = drbd_send_cmd2(mdev, P_AUTH_RESPONSE, response, resp_size);
+ if (!rv)
+ goto fail;
+
+ rv = drbd_recv_header(mdev, &p);
+ if (!rv)
+ goto fail;
+
+ if (p.command != P_AUTH_RESPONSE) {
+ dev_err(DEV, "expected AuthResponse packet, received: %s (0x%04x)\n",
+ cmdname(p.command), p.command);
+ rv = 0;
+ goto fail;
+ }
+
+ if (p.length != resp_size) {
+ dev_err(DEV, "expected AuthResponse payload of wrong size\n");
+ rv = 0;
+ goto fail;
+ }
+
+ rv = drbd_recv(mdev, response , resp_size);
+
+ if (rv != resp_size) {
+ dev_err(DEV, "short read receiving AuthResponse: l=%u\n", rv);
+ rv = 0;
+ goto fail;
+ }
+
+ right_response = kmalloc(resp_size, GFP_NOIO);
+ if (response == NULL) {
+ dev_err(DEV, "kmalloc of right_response failed\n");
+ rv = 0;
+ goto fail;
+ }
+
+ sg_set_buf(&sg, my_challenge, CHALLENGE_LEN);
+
+ rv = crypto_hash_digest(&desc, &sg, sg.length, right_response);
+ if (rv) {
+ dev_err(DEV, "crypto_hash_digest() failed with %d\n", rv);
+ rv = 0;
+ goto fail;
+ }
+
+ rv = !memcmp(response, right_response, resp_size);
+
+ if (rv)
+ dev_info(DEV, "Peer authenticated using %d bytes of '%s' HMAC\n",
+ resp_size, mdev->net_conf->cram_hmac_alg);
+
+ fail:
+ kfree(peers_ch);
+ kfree(response);
+ kfree(right_response);
+
+ return rv;
+}
+#endif
+
+int drbdd_init(struct drbd_thread *thi)
+{
+ struct drbd_conf *mdev = thi->mdev;
+ unsigned int minor = mdev_to_minor(mdev);
+ int h;
+
+ sprintf(current->comm, "drbd%d_receiver", minor);
+
+ dev_info(DEV, "receiver (re)started\n");
+
+ do {
+ h = drbd_connect(mdev);
+ if (h == 0) {
+ drbd_disconnect(mdev);
+ __set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ);
+ }
+ if (h == -1) {
+ dev_warn(DEV, "Discarding network configuration.\n");
+ drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+ }
+ } while (h == 0);
+
+ if (h > 0) {
+ if (get_net_conf(mdev)) {
+ drbdd(mdev);
+ put_net_conf(mdev);
+ }
+ }
+
+ drbd_disconnect(mdev);
+
+ dev_info(DEV, "receiver terminated\n");
+ return 0;
+}
+
+/* ********* acknowledge sender ******** */
+
+static int got_RqSReply(struct drbd_conf *mdev, struct p_header *h)
+{
+ struct p_req_state_reply *p = (struct p_req_state_reply *)h;
+
+ int retcode = be32_to_cpu(p->retcode);
+
+ if (retcode >= SS_SUCCESS) {
+ set_bit(CL_ST_CHG_SUCCESS, &mdev->flags);
+ } else {
+ set_bit(CL_ST_CHG_FAIL, &mdev->flags);
+ dev_err(DEV, "Requested state change failed by peer: %s (%d)\n",
+ drbd_set_st_err_str(retcode), retcode);
+ }
+ wake_up(&mdev->state_wait);
+
+ return TRUE;
+}
+
+static int got_Ping(struct drbd_conf *mdev, struct p_header *h)
+{
+ return drbd_send_ping_ack(mdev);
+
+}
+
+static int got_PingAck(struct drbd_conf *mdev, struct p_header *h)
+{
+ /* restore idle timeout */
+ mdev->meta.socket->sk->sk_rcvtimeo = mdev->net_conf->ping_int*HZ;
+
+ return TRUE;
+}
+
+static int got_IsInSync(struct drbd_conf *mdev, struct p_header *h)
+{
+ struct p_block_ack *p = (struct p_block_ack *)h;
+ sector_t sector = be64_to_cpu(p->sector);
+ int blksize = be32_to_cpu(p->blksize);
+
+ D_ASSERT(mdev->agreed_pro_version >= 89);
+
+ update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+
+ drbd_rs_complete_io(mdev, sector);
+ drbd_set_in_sync(mdev, sector, blksize);
+ /* rs_same_csums is supposed to count in units of BM_BLOCK_SIZE */
+ mdev->rs_same_csum += (blksize >> BM_BLOCK_SHIFT);
+ dec_rs_pending(mdev);
+
+ return TRUE;
+}
+
+/* when we receive the ACK for a write request,
+ * verify that we actually know about it */
+static struct drbd_request *_ack_id_to_req(struct drbd_conf *mdev,
+ u64 id, sector_t sector)
+{
+ struct hlist_head *slot = tl_hash_slot(mdev, sector);
+ struct hlist_node *n;
+ struct drbd_request *req;
+
+ hlist_for_each_entry(req, n, slot, colision) {
+ if ((unsigned long)req == (unsigned long)id) {
+ if (req->sector != sector) {
+ dev_err(DEV, "_ack_id_to_req: found req %p but it has "
+ "wrong sector (%llus versus %llus)\n", req,
+ (unsigned long long)req->sector,
+ (unsigned long long)sector);
+ break;
+ }
+ return req;
+ }
+ }
+ dev_err(DEV, "_ack_id_to_req: failed to find req %p, sector %llus in list\n",
+ (void *)(unsigned long)id, (unsigned long long)sector);
+ return NULL;
+}
+
+typedef struct drbd_request *(req_validator_fn)
+ (struct drbd_conf *mdev, u64 id, sector_t sector);
+
+static int validate_req_change_req_state(struct drbd_conf *mdev,
+ u64 id, sector_t sector, req_validator_fn validator,
+ const char *func, enum drbd_req_event what)
+{
+ struct drbd_request *req;
+ struct bio_and_error m;
+
+ spin_lock_irq(&mdev->req_lock);
+ req = validator(mdev, id, sector);
+ if (unlikely(!req)) {
+ spin_unlock_irq(&mdev->req_lock);
+ dev_err(DEV, "%s: got a corrupt block_id/sector pair\n", func);
+ return FALSE;
+ }
+ __req_mod(req, what, &m);
+ spin_unlock_irq(&mdev->req_lock);
+
+ if (m.bio)
+ complete_master_bio(mdev, &m);
+ return TRUE;
+}
+
+static int got_BlockAck(struct drbd_conf *mdev, struct p_header *h)
+{
+ struct p_block_ack *p = (struct p_block_ack *)h;
+ sector_t sector = be64_to_cpu(p->sector);
+ int blksize = be32_to_cpu(p->blksize);
+ enum drbd_req_event what;
+
+ update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+
+ if (is_syncer_block_id(p->block_id)) {
+ drbd_set_in_sync(mdev, sector, blksize);
+ dec_rs_pending(mdev);
+ return TRUE;
+ }
+ switch (be16_to_cpu(h->command)) {
+ case P_RS_WRITE_ACK:
+ D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C);
+ what = write_acked_by_peer_and_sis;
+ break;
+ case P_WRITE_ACK:
+ D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C);
+ what = write_acked_by_peer;
+ break;
+ case P_RECV_ACK:
+ D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_B);
+ what = recv_acked_by_peer;
+ break;
+ case P_DISCARD_ACK:
+ D_ASSERT(mdev->net_conf->wire_protocol == DRBD_PROT_C);
+ what = conflict_discarded_by_peer;
+ break;
+ default:
+ D_ASSERT(0);
+ return FALSE;
+ }
+
+ return validate_req_change_req_state(mdev, p->block_id, sector,
+ _ack_id_to_req, __func__ , what);
+}
+
+static int got_NegAck(struct drbd_conf *mdev, struct p_header *h)
+{
+ struct p_block_ack *p = (struct p_block_ack *)h;
+ sector_t sector = be64_to_cpu(p->sector);
+
+ if (__ratelimit(&drbd_ratelimit_state))
+ dev_warn(DEV, "Got NegAck packet. Peer is in troubles?\n");
+
+ update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+
+ if (is_syncer_block_id(p->block_id)) {
+ int size = be32_to_cpu(p->blksize);
+ dec_rs_pending(mdev);
+ drbd_rs_failed_io(mdev, sector, size);
+ return TRUE;
+ }
+ return validate_req_change_req_state(mdev, p->block_id, sector,
+ _ack_id_to_req, __func__ , neg_acked);
+}
+
+static int got_NegDReply(struct drbd_conf *mdev, struct p_header *h)
+{
+ struct p_block_ack *p = (struct p_block_ack *)h;
+ sector_t sector = be64_to_cpu(p->sector);
+
+ update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+ dev_err(DEV, "Got NegDReply; Sector %llus, len %u; Fail original request.\n",
+ (unsigned long long)sector, be32_to_cpu(p->blksize));
+
+ return validate_req_change_req_state(mdev, p->block_id, sector,
+ _ar_id_to_req, __func__ , neg_acked);
+}
+
+static int got_NegRSDReply(struct drbd_conf *mdev, struct p_header *h)
+{
+ sector_t sector;
+ int size;
+ struct p_block_ack *p = (struct p_block_ack *)h;
+
+ sector = be64_to_cpu(p->sector);
+ size = be32_to_cpu(p->blksize);
+ D_ASSERT(p->block_id == ID_SYNCER);
+
+ update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+
+ dec_rs_pending(mdev);
+
+ if (get_ldev_if_state(mdev, D_FAILED)) {
+ drbd_rs_complete_io(mdev, sector);
+ drbd_rs_failed_io(mdev, sector, size);
+ put_ldev(mdev);
+ }
+
+ return TRUE;
+}
+
+static int got_BarrierAck(struct drbd_conf *mdev, struct p_header *h)
+{
+ struct p_barrier_ack *p = (struct p_barrier_ack *)h;
+
+ tl_release(mdev, p->barrier, be32_to_cpu(p->set_size));
+
+ return TRUE;
+}
+
+static int got_OVResult(struct drbd_conf *mdev, struct p_header *h)
+{
+ struct p_block_ack *p = (struct p_block_ack *)h;
+ struct drbd_work *w;
+ sector_t sector;
+ int size;
+
+ sector = be64_to_cpu(p->sector);
+ size = be32_to_cpu(p->blksize);
+
+ update_peer_seq(mdev, be32_to_cpu(p->seq_num));
+
+ if (be64_to_cpu(p->block_id) == ID_OUT_OF_SYNC)
+ drbd_ov_oos_found(mdev, sector, size);
+ else
+ ov_oos_print(mdev);
+
+ drbd_rs_complete_io(mdev, sector);
+ dec_rs_pending(mdev);
+
+ if (--mdev->ov_left == 0) {
+ w = kmalloc(sizeof(*w), GFP_NOIO);
+ if (w) {
+ w->cb = w_ov_finished;
+ drbd_queue_work_front(&mdev->data.work, w);
+ } else {
+ dev_err(DEV, "kmalloc(w) failed.");
+ ov_oos_print(mdev);
+ drbd_resync_finished(mdev);
+ }
+ }
+ return TRUE;
+}
+
+struct asender_cmd {
+ size_t pkt_size;
+ int (*process)(struct drbd_conf *mdev, struct p_header *h);
+};
+
+static struct asender_cmd *get_asender_cmd(int cmd)
+{
+ static struct asender_cmd asender_tbl[] = {
+ /* anything missing from this table is in
+ * the drbd_cmd_handler (drbd_default_handler) table,
+ * see the beginning of drbdd() */
+ [P_PING] = { sizeof(struct p_header), got_Ping },
+ [P_PING_ACK] = { sizeof(struct p_header), got_PingAck },
+ [P_RECV_ACK] = { sizeof(struct p_block_ack), got_BlockAck },
+ [P_WRITE_ACK] = { sizeof(struct p_block_ack), got_BlockAck },
+ [P_RS_WRITE_ACK] = { sizeof(struct p_block_ack), got_BlockAck },
+ [P_DISCARD_ACK] = { sizeof(struct p_block_ack), got_BlockAck },
+ [P_NEG_ACK] = { sizeof(struct p_block_ack), got_NegAck },
+ [P_NEG_DREPLY] = { sizeof(struct p_block_ack), got_NegDReply },
+ [P_NEG_RS_DREPLY] = { sizeof(struct p_block_ack), got_NegRSDReply},
+ [P_OV_RESULT] = { sizeof(struct p_block_ack), got_OVResult },
+ [P_BARRIER_ACK] = { sizeof(struct p_barrier_ack), got_BarrierAck },
+ [P_STATE_CHG_REPLY] = { sizeof(struct p_req_state_reply), got_RqSReply },
+ [P_RS_IS_IN_SYNC] = { sizeof(struct p_block_ack), got_IsInSync },
+ [P_MAX_CMD] = { 0, NULL },
+ };
+ if (cmd > P_MAX_CMD || asender_tbl[cmd].process == NULL)
+ return NULL;
+ return &asender_tbl[cmd];
+}
+
+int drbd_asender(struct drbd_thread *thi)
+{
+ struct drbd_conf *mdev = thi->mdev;
+ struct p_header *h = &mdev->meta.rbuf.header;
+ struct asender_cmd *cmd = NULL;
+
+ int rv, len;
+ void *buf = h;
+ int received = 0;
+ int expect = sizeof(struct p_header);
+ int empty;
+
+ sprintf(current->comm, "drbd%d_asender", mdev_to_minor(mdev));
+
+ current->policy = SCHED_RR; /* Make this a realtime task! */
+ current->rt_priority = 2; /* more important than all other tasks */
+
+ while (get_t_state(thi) == Running) {
+ drbd_thread_current_set_cpu(mdev);
+ if (test_and_clear_bit(SEND_PING, &mdev->flags)) {
+ ERR_IF(!drbd_send_ping(mdev)) goto reconnect;
+ mdev->meta.socket->sk->sk_rcvtimeo =
+ mdev->net_conf->ping_timeo*HZ/10;
+ }
+
+ /* conditionally cork;
+ * it may hurt latency if we cork without much to send */
+ if (!mdev->net_conf->no_cork &&
+ 3 < atomic_read(&mdev->unacked_cnt))
+ drbd_tcp_cork(mdev->meta.socket);
+ while (1) {
+ clear_bit(SIGNAL_ASENDER, &mdev->flags);
+ flush_signals(current);
+ if (!drbd_process_done_ee(mdev)) {
+ dev_err(DEV, "process_done_ee() = NOT_OK\n");
+ goto reconnect;
+ }
+ /* to avoid race with newly queued ACKs */
+ set_bit(SIGNAL_ASENDER, &mdev->flags);
+ spin_lock_irq(&mdev->req_lock);
+ empty = list_empty(&mdev->done_ee);
+ spin_unlock_irq(&mdev->req_lock);
+ /* new ack may have been queued right here,
+ * but then there is also a signal pending,
+ * and we start over... */
+ if (empty)
+ break;
+ }
+ /* but unconditionally uncork unless disabled */
+ if (!mdev->net_conf->no_cork)
+ drbd_tcp_uncork(mdev->meta.socket);
+
+ /* short circuit, recv_msg would return EINTR anyways. */
+ if (signal_pending(current))
+ continue;
+
+ rv = drbd_recv_short(mdev, mdev->meta.socket,
+ buf, expect-received, 0);
+ clear_bit(SIGNAL_ASENDER, &mdev->flags);
+
+ flush_signals(current);
+
+ /* Note:
+ * -EINTR (on meta) we got a signal
+ * -EAGAIN (on meta) rcvtimeo expired
+ * -ECONNRESET other side closed the connection
+ * -ERESTARTSYS (on data) we got a signal
+ * rv < 0 other than above: unexpected error!
+ * rv == expected: full header or command
+ * rv < expected: "woken" by signal during receive
+ * rv == 0 : "connection shut down by peer"
+ */
+ if (likely(rv > 0)) {
+ received += rv;
+ buf += rv;
+ } else if (rv == 0) {
+ dev_err(DEV, "meta connection shut down by peer.\n");
+ goto reconnect;
+ } else if (rv == -EAGAIN) {
+ if (mdev->meta.socket->sk->sk_rcvtimeo ==
+ mdev->net_conf->ping_timeo*HZ/10) {
+ dev_err(DEV, "PingAck did not arrive in time.\n");
+ goto reconnect;
+ }
+ set_bit(SEND_PING, &mdev->flags);
+ continue;
+ } else if (rv == -EINTR) {
+ continue;
+ } else {
+ dev_err(DEV, "sock_recvmsg returned %d\n", rv);
+ goto reconnect;
+ }
+
+ if (received == expect && cmd == NULL) {
+ if (unlikely(h->magic != BE_DRBD_MAGIC)) {
+ dev_err(DEV, "magic?? on meta m: 0x%lx c: %d l: %d\n",
+ (long)be32_to_cpu(h->magic),
+ h->command, h->length);
+ goto reconnect;
+ }
+ cmd = get_asender_cmd(be16_to_cpu(h->command));
+ len = be16_to_cpu(h->length);
+ if (unlikely(cmd == NULL)) {
+ dev_err(DEV, "unknown command?? on meta m: 0x%lx c: %d l: %d\n",
+ (long)be32_to_cpu(h->magic),
+ h->command, h->length);
+ goto disconnect;
+ }
+ expect = cmd->pkt_size;
+ ERR_IF(len != expect-sizeof(struct p_header))
+ goto reconnect;
+ }
+ if (received == expect) {
+ D_ASSERT(cmd != NULL);
+ if (!cmd->process(mdev, h))
+ goto reconnect;
+
+ buf = h;
+ received = 0;
+ expect = sizeof(struct p_header);
+ cmd = NULL;
+ }
+ }
+
+ if (0) {
+reconnect:
+ drbd_force_state(mdev, NS(conn, C_NETWORK_FAILURE));
+ }
+ if (0) {
+disconnect:
+ drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+ }
+ clear_bit(SIGNAL_ASENDER, &mdev->flags);
+
+ D_ASSERT(mdev->state.conn < C_CONNECTED);
+ dev_info(DEV, "asender terminated\n");
+
+ return 0;
+}
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
new file mode 100644
index 000000000000..3678d3d66c6c
--- /dev/null
+++ b/drivers/block/drbd/drbd_req.c
@@ -0,0 +1,1120 @@
+/*
+ drbd_req.c
+
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+ Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+ drbd 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.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT 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 drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/module.h>
+
+#include <linux/slab.h>
+#include <linux/drbd.h>
+#include "drbd_int.h"
+#include "drbd_req.h"
+
+
+/* Update disk stats at start of I/O request */
+static void _drbd_start_io_acct(struct drbd_conf *mdev, struct drbd_request *req, struct bio *bio)
+{
+ const int rw = bio_data_dir(bio);
+ int cpu;
+ cpu = part_stat_lock();
+ part_stat_inc(cpu, &mdev->vdisk->part0, ios[rw]);
+ part_stat_add(cpu, &mdev->vdisk->part0, sectors[rw], bio_sectors(bio));
+ part_stat_unlock();
+ mdev->vdisk->part0.in_flight[rw]++;
+}
+
+/* Update disk stats when completing request upwards */
+static void _drbd_end_io_acct(struct drbd_conf *mdev, struct drbd_request *req)
+{
+ int rw = bio_data_dir(req->master_bio);
+ unsigned long duration = jiffies - req->start_time;
+ int cpu;
+ cpu = part_stat_lock();
+ part_stat_add(cpu, &mdev->vdisk->part0, ticks[rw], duration);
+ part_round_stats(cpu, &mdev->vdisk->part0);
+ part_stat_unlock();
+ mdev->vdisk->part0.in_flight[rw]--;
+}
+
+static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const int rw)
+{
+ const unsigned long s = req->rq_state;
+ /* if it was a write, we may have to set the corresponding
+ * bit(s) out-of-sync first. If it had a local part, we need to
+ * release the reference to the activity log. */
+ if (rw == WRITE) {
+ /* remove it from the transfer log.
+ * well, only if it had been there in the first
+ * place... if it had not (local only or conflicting
+ * and never sent), it should still be "empty" as
+ * initialized in drbd_req_new(), so we can list_del() it
+ * here unconditionally */
+ list_del(&req->tl_requests);
+ /* Set out-of-sync unless both OK flags are set
+ * (local only or remote failed).
+ * Other places where we set out-of-sync:
+ * READ with local io-error */
+ if (!(s & RQ_NET_OK) || !(s & RQ_LOCAL_OK))
+ drbd_set_out_of_sync(mdev, req->sector, req->size);
+
+ if ((s & RQ_NET_OK) && (s & RQ_LOCAL_OK) && (s & RQ_NET_SIS))
+ drbd_set_in_sync(mdev, req->sector, req->size);
+
+ /* one might be tempted to move the drbd_al_complete_io
+ * to the local io completion callback drbd_endio_pri.
+ * but, if this was a mirror write, we may only
+ * drbd_al_complete_io after this is RQ_NET_DONE,
+ * otherwise the extent could be dropped from the al
+ * before it has actually been written on the peer.
+ * if we crash before our peer knows about the request,
+ * but after the extent has been dropped from the al,
+ * we would forget to resync the corresponding extent.
+ */
+ if (s & RQ_LOCAL_MASK) {
+ if (get_ldev_if_state(mdev, D_FAILED)) {
+ drbd_al_complete_io(mdev, req->sector);
+ put_ldev(mdev);
+ } else if (__ratelimit(&drbd_ratelimit_state)) {
+ dev_warn(DEV, "Should have called drbd_al_complete_io(, %llu), "
+ "but my Disk seems to have failed :(\n",
+ (unsigned long long) req->sector);
+ }
+ }
+ }
+
+ /* if it was a local io error, we want to notify our
+ * peer about that, and see if we need to
+ * detach the disk and stuff.
+ * to avoid allocating some special work
+ * struct, reuse the request. */
+
+ /* THINK
+ * why do we do this not when we detect the error,
+ * but delay it until it is "done", i.e. possibly
+ * until the next barrier ack? */
+
+ if (rw == WRITE &&
+ ((s & RQ_LOCAL_MASK) && !(s & RQ_LOCAL_OK))) {
+ if (!(req->w.list.next == LIST_POISON1 ||
+ list_empty(&req->w.list))) {
+ /* DEBUG ASSERT only; if this triggers, we
+ * probably corrupt the worker list here */
+ dev_err(DEV, "req->w.list.next = %p\n", req->w.list.next);
+ dev_err(DEV, "req->w.list.prev = %p\n", req->w.list.prev);
+ }
+ req->w.cb = w_io_error;
+ drbd_queue_work(&mdev->data.work, &req->w);
+ /* drbd_req_free() is done in w_io_error */
+ } else {
+ drbd_req_free(req);
+ }
+}
+
+static void queue_barrier(struct drbd_conf *mdev)
+{
+ struct drbd_tl_epoch *b;
+
+ /* We are within the req_lock. Once we queued the barrier for sending,
+ * we set the CREATE_BARRIER bit. It is cleared as soon as a new
+ * barrier/epoch object is added. This is the only place this bit is
+ * set. It indicates that the barrier for this epoch is already queued,
+ * and no new epoch has been created yet. */
+ if (test_bit(CREATE_BARRIER, &mdev->flags))
+ return;
+
+ b = mdev->newest_tle;
+ b->w.cb = w_send_barrier;
+ /* inc_ap_pending done here, so we won't
+ * get imbalanced on connection loss.
+ * dec_ap_pending will be done in got_BarrierAck
+ * or (on connection loss) in tl_clear. */
+ inc_ap_pending(mdev);
+ drbd_queue_work(&mdev->data.work, &b->w);
+ set_bit(CREATE_BARRIER, &mdev->flags);
+}
+
+static void _about_to_complete_local_write(struct drbd_conf *mdev,
+ struct drbd_request *req)
+{
+ const unsigned long s = req->rq_state;
+ struct drbd_request *i;
+ struct drbd_epoch_entry *e;
+ struct hlist_node *n;
+ struct hlist_head *slot;
+
+ /* before we can signal completion to the upper layers,
+ * we may need to close the current epoch */
+ if (mdev->state.conn >= C_CONNECTED &&
+ req->epoch == mdev->newest_tle->br_number)
+ queue_barrier(mdev);
+
+ /* we need to do the conflict detection stuff,
+ * if we have the ee_hash (two_primaries) and
+ * this has been on the network */
+ if ((s & RQ_NET_DONE) && mdev->ee_hash != NULL) {
+ const sector_t sector = req->sector;
+ const int size = req->size;
+
+ /* ASSERT:
+ * there must be no conflicting requests, since
+ * they must have been failed on the spot */
+#define OVERLAPS overlaps(sector, size, i->sector, i->size)
+ slot = tl_hash_slot(mdev, sector);
+ hlist_for_each_entry(i, n, slot, colision) {
+ if (OVERLAPS) {
+ dev_alert(DEV, "LOGIC BUG: completed: %p %llus +%u; "
+ "other: %p %llus +%u\n",
+ req, (unsigned long long)sector, size,
+ i, (unsigned long long)i->sector, i->size);
+ }
+ }
+
+ /* maybe "wake" those conflicting epoch entries
+ * that wait for this request to finish.
+ *
+ * currently, there can be only _one_ such ee
+ * (well, or some more, which would be pending
+ * P_DISCARD_ACK not yet sent by the asender...),
+ * since we block the receiver thread upon the
+ * first conflict detection, which will wait on
+ * misc_wait. maybe we want to assert that?
+ *
+ * anyways, if we found one,
+ * we just have to do a wake_up. */
+#undef OVERLAPS
+#define OVERLAPS overlaps(sector, size, e->sector, e->size)
+ slot = ee_hash_slot(mdev, req->sector);
+ hlist_for_each_entry(e, n, slot, colision) {
+ if (OVERLAPS) {
+ wake_up(&mdev->misc_wait);
+ break;
+ }
+ }
+ }
+#undef OVERLAPS
+}
+
+void complete_master_bio(struct drbd_conf *mdev,
+ struct bio_and_error *m)
+{
+ bio_endio(m->bio, m->error);
+ dec_ap_bio(mdev);
+}
+
+/* Helper for __req_mod().
+ * Set m->bio to the master bio, if it is fit to be completed,
+ * or leave it alone (it is initialized to NULL in __req_mod),
+ * if it has already been completed, or cannot be completed yet.
+ * If m->bio is set, the error status to be returned is placed in m->error.
+ */
+void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m)
+{
+ const unsigned long s = req->rq_state;
+ struct drbd_conf *mdev = req->mdev;
+ /* only WRITES may end up here without a master bio (on barrier ack) */
+ int rw = req->master_bio ? bio_data_dir(req->master_bio) : WRITE;
+
+ /* we must not complete the master bio, while it is
+ * still being processed by _drbd_send_zc_bio (drbd_send_dblock)
+ * not yet acknowledged by the peer
+ * not yet completed by the local io subsystem
+ * these flags may get cleared in any order by
+ * the worker,
+ * the receiver,
+ * the bio_endio completion callbacks.
+ */
+ if (s & RQ_NET_QUEUED)
+ return;
+ if (s & RQ_NET_PENDING)
+ return;
+ if (s & RQ_LOCAL_PENDING)
+ return;
+
+ if (req->master_bio) {
+ /* this is data_received (remote read)
+ * or protocol C P_WRITE_ACK
+ * or protocol B P_RECV_ACK
+ * or protocol A "handed_over_to_network" (SendAck)
+ * or canceled or failed,
+ * or killed from the transfer log due to connection loss.
+ */
+
+ /*
+ * figure out whether to report success or failure.
+ *
+ * report success when at least one of the operations succeeded.
+ * or, to put the other way,
+ * only report failure, when both operations failed.
+ *
+ * what to do about the failures is handled elsewhere.
+ * what we need to do here is just: complete the master_bio.
+ *
+ * local completion error, if any, has been stored as ERR_PTR
+ * in private_bio within drbd_endio_pri.
+ */
+ int ok = (s & RQ_LOCAL_OK) || (s & RQ_NET_OK);
+ int error = PTR_ERR(req->private_bio);
+
+ /* remove the request from the conflict detection
+ * respective block_id verification hash */
+ if (!hlist_unhashed(&req->colision))
+ hlist_del(&req->colision);
+ else
+ D_ASSERT((s & RQ_NET_MASK) == 0);
+
+ /* for writes we need to do some extra housekeeping */
+ if (rw == WRITE)
+ _about_to_complete_local_write(mdev, req);
+
+ /* Update disk stats */
+ _drbd_end_io_acct(mdev, req);
+
+ m->error = ok ? 0 : (error ?: -EIO);
+ m->bio = req->master_bio;
+ req->master_bio = NULL;
+ }
+
+ if ((s & RQ_NET_MASK) == 0 || (s & RQ_NET_DONE)) {
+ /* this is disconnected (local only) operation,
+ * or protocol C P_WRITE_ACK,
+ * or protocol A or B P_BARRIER_ACK,
+ * or killed from the transfer log due to connection loss. */
+ _req_is_done(mdev, req, rw);
+ }
+ /* else: network part and not DONE yet. that is
+ * protocol A or B, barrier ack still pending... */
+}
+
+/*
+ * checks whether there was an overlapping request
+ * or ee already registered.
+ *
+ * if so, return 1, in which case this request is completed on the spot,
+ * without ever being submitted or send.
+ *
+ * return 0 if it is ok to submit this request.
+ *
+ * NOTE:
+ * paranoia: assume something above us is broken, and issues different write
+ * requests for the same block simultaneously...
+ *
+ * To ensure these won't be reordered differently on both nodes, resulting in
+ * diverging data sets, we discard the later one(s). Not that this is supposed
+ * to happen, but this is the rationale why we also have to check for
+ * conflicting requests with local origin, and why we have to do so regardless
+ * of whether we allowed multiple primaries.
+ *
+ * BTW, in case we only have one primary, the ee_hash is empty anyways, and the
+ * second hlist_for_each_entry becomes a noop. This is even simpler than to
+ * grab a reference on the net_conf, and check for the two_primaries flag...
+ */
+static int _req_conflicts(struct drbd_request *req)
+{
+ struct drbd_conf *mdev = req->mdev;
+ const sector_t sector = req->sector;
+ const int size = req->size;
+ struct drbd_request *i;
+ struct drbd_epoch_entry *e;
+ struct hlist_node *n;
+ struct hlist_head *slot;
+
+ D_ASSERT(hlist_unhashed(&req->colision));
+
+ if (!get_net_conf(mdev))
+ return 0;
+
+ /* BUG_ON */
+ ERR_IF (mdev->tl_hash_s == 0)
+ goto out_no_conflict;
+ BUG_ON(mdev->tl_hash == NULL);
+
+#define OVERLAPS overlaps(i->sector, i->size, sector, size)
+ slot = tl_hash_slot(mdev, sector);
+ hlist_for_each_entry(i, n, slot, colision) {
+ if (OVERLAPS) {
+ dev_alert(DEV, "%s[%u] Concurrent local write detected! "
+ "[DISCARD L] new: %llus +%u; "
+ "pending: %llus +%u\n",
+ current->comm, current->pid,
+ (unsigned long long)sector, size,
+ (unsigned long long)i->sector, i->size);
+ goto out_conflict;
+ }
+ }
+
+ if (mdev->ee_hash_s) {
+ /* now, check for overlapping requests with remote origin */
+ BUG_ON(mdev->ee_hash == NULL);
+#undef OVERLAPS
+#define OVERLAPS overlaps(e->sector, e->size, sector, size)
+ slot = ee_hash_slot(mdev, sector);
+ hlist_for_each_entry(e, n, slot, colision) {
+ if (OVERLAPS) {
+ dev_alert(DEV, "%s[%u] Concurrent remote write detected!"
+ " [DISCARD L] new: %llus +%u; "
+ "pending: %llus +%u\n",
+ current->comm, current->pid,
+ (unsigned long long)sector, size,
+ (unsigned long long)e->sector, e->size);
+ goto out_conflict;
+ }
+ }
+ }
+#undef OVERLAPS
+
+out_no_conflict:
+ /* this is like it should be, and what we expected.
+ * our users do behave after all... */
+ put_net_conf(mdev);
+ return 0;
+
+out_conflict:
+ put_net_conf(mdev);
+ return 1;
+}
+
+/* obviously this could be coded as many single functions
+ * instead of one huge switch,
+ * or by putting the code directly in the respective locations
+ * (as it has been before).
+ *
+ * but having it this way
+ * enforces that it is all in this one place, where it is easier to audit,
+ * it makes it obvious that whatever "event" "happens" to a request should
+ * happen "atomically" within the req_lock,
+ * and it enforces that we have to think in a very structured manner
+ * about the "events" that may happen to a request during its life time ...
+ */
+void __req_mod(struct drbd_request *req, enum drbd_req_event what,
+ struct bio_and_error *m)
+{
+ struct drbd_conf *mdev = req->mdev;
+ m->bio = NULL;
+
+ switch (what) {
+ default:
+ dev_err(DEV, "LOGIC BUG in %s:%u\n", __FILE__ , __LINE__);
+ break;
+
+ /* does not happen...
+ * initialization done in drbd_req_new
+ case created:
+ break;
+ */
+
+ case to_be_send: /* via network */
+ /* reached via drbd_make_request_common
+ * and from w_read_retry_remote */
+ D_ASSERT(!(req->rq_state & RQ_NET_MASK));
+ req->rq_state |= RQ_NET_PENDING;
+ inc_ap_pending(mdev);
+ break;
+
+ case to_be_submitted: /* locally */
+ /* reached via drbd_make_request_common */
+ D_ASSERT(!(req->rq_state & RQ_LOCAL_MASK));
+ req->rq_state |= RQ_LOCAL_PENDING;
+ break;
+
+ case completed_ok:
+ if (bio_data_dir(req->master_bio) == WRITE)
+ mdev->writ_cnt += req->size>>9;
+ else
+ mdev->read_cnt += req->size>>9;
+
+ req->rq_state |= (RQ_LOCAL_COMPLETED|RQ_LOCAL_OK);
+ req->rq_state &= ~RQ_LOCAL_PENDING;
+
+ _req_may_be_done(req, m);
+ put_ldev(mdev);
+ break;
+
+ case write_completed_with_error:
+ req->rq_state |= RQ_LOCAL_COMPLETED;
+ req->rq_state &= ~RQ_LOCAL_PENDING;
+
+ dev_alert(DEV, "Local WRITE failed sec=%llus size=%u\n",
+ (unsigned long long)req->sector, req->size);
+ /* and now: check how to handle local io error. */
+ __drbd_chk_io_error(mdev, FALSE);
+ _req_may_be_done(req, m);
+ put_ldev(mdev);
+ break;
+
+ case read_ahead_completed_with_error:
+ /* it is legal to fail READA */
+ req->rq_state |= RQ_LOCAL_COMPLETED;
+ req->rq_state &= ~RQ_LOCAL_PENDING;
+ _req_may_be_done(req, m);
+ put_ldev(mdev);
+ break;
+
+ case read_completed_with_error:
+ drbd_set_out_of_sync(mdev, req->sector, req->size);
+
+ req->rq_state |= RQ_LOCAL_COMPLETED;
+ req->rq_state &= ~RQ_LOCAL_PENDING;
+
+ dev_alert(DEV, "Local READ failed sec=%llus size=%u\n",
+ (unsigned long long)req->sector, req->size);
+ /* _req_mod(req,to_be_send); oops, recursion... */
+ D_ASSERT(!(req->rq_state & RQ_NET_MASK));
+ req->rq_state |= RQ_NET_PENDING;
+ inc_ap_pending(mdev);
+
+ __drbd_chk_io_error(mdev, FALSE);
+ put_ldev(mdev);
+ /* NOTE: if we have no connection,
+ * or know the peer has no good data either,
+ * then we don't actually need to "queue_for_net_read",
+ * but we do so anyways, since the drbd_io_error()
+ * and the potential state change to "Diskless"
+ * needs to be done from process context */
+
+ /* fall through: _req_mod(req,queue_for_net_read); */
+
+ case queue_for_net_read:
+ /* READ or READA, and
+ * no local disk,
+ * or target area marked as invalid,
+ * or just got an io-error. */
+ /* from drbd_make_request_common
+ * or from bio_endio during read io-error recovery */
+
+ /* so we can verify the handle in the answer packet
+ * corresponding hlist_del is in _req_may_be_done() */
+ hlist_add_head(&req->colision, ar_hash_slot(mdev, req->sector));
+
+ set_bit(UNPLUG_REMOTE, &mdev->flags); /* why? */
+
+ D_ASSERT(req->rq_state & RQ_NET_PENDING);
+ req->rq_state |= RQ_NET_QUEUED;
+ req->w.cb = (req->rq_state & RQ_LOCAL_MASK)
+ ? w_read_retry_remote
+ : w_send_read_req;
+ drbd_queue_work(&mdev->data.work, &req->w);
+ break;
+
+ case queue_for_net_write:
+ /* assert something? */
+ /* from drbd_make_request_common only */
+
+ hlist_add_head(&req->colision, tl_hash_slot(mdev, req->sector));
+ /* corresponding hlist_del is in _req_may_be_done() */
+
+ /* NOTE
+ * In case the req ended up on the transfer log before being
+ * queued on the worker, it could lead to this request being
+ * missed during cleanup after connection loss.
+ * So we have to do both operations here,
+ * within the same lock that protects the transfer log.
+ *
+ * _req_add_to_epoch(req); this has to be after the
+ * _maybe_start_new_epoch(req); which happened in
+ * drbd_make_request_common, because we now may set the bit
+ * again ourselves to close the current epoch.
+ *
+ * Add req to the (now) current epoch (barrier). */
+
+ /* see drbd_make_request_common,
+ * just after it grabs the req_lock */
+ D_ASSERT(test_bit(CREATE_BARRIER, &mdev->flags) == 0);
+
+ req->epoch = mdev->newest_tle->br_number;
+ list_add_tail(&req->tl_requests,
+ &mdev->newest_tle->requests);
+
+ /* increment size of current epoch */
+ mdev->newest_tle->n_req++;
+
+ /* queue work item to send data */
+ D_ASSERT(req->rq_state & RQ_NET_PENDING);
+ req->rq_state |= RQ_NET_QUEUED;
+ req->w.cb = w_send_dblock;
+ drbd_queue_work(&mdev->data.work, &req->w);
+
+ /* close the epoch, in case it outgrew the limit */
+ if (mdev->newest_tle->n_req >= mdev->net_conf->max_epoch_size)
+ queue_barrier(mdev);
+
+ break;
+
+ case send_canceled:
+ /* treat it the same */
+ case send_failed:
+ /* real cleanup will be done from tl_clear. just update flags
+ * so it is no longer marked as on the worker queue */
+ req->rq_state &= ~RQ_NET_QUEUED;
+ /* if we did it right, tl_clear should be scheduled only after
+ * this, so this should not be necessary! */
+ _req_may_be_done(req, m);
+ break;
+
+ case handed_over_to_network:
+ /* assert something? */
+ if (bio_data_dir(req->master_bio) == WRITE &&
+ mdev->net_conf->wire_protocol == DRBD_PROT_A) {
+ /* this is what is dangerous about protocol A:
+ * pretend it was successfully written on the peer. */
+ if (req->rq_state & RQ_NET_PENDING) {
+ dec_ap_pending(mdev);
+ req->rq_state &= ~RQ_NET_PENDING;
+ req->rq_state |= RQ_NET_OK;
+ } /* else: neg-ack was faster... */
+ /* it is still not yet RQ_NET_DONE until the
+ * corresponding epoch barrier got acked as well,
+ * so we know what to dirty on connection loss */
+ }
+ req->rq_state &= ~RQ_NET_QUEUED;
+ req->rq_state |= RQ_NET_SENT;
+ /* because _drbd_send_zc_bio could sleep, and may want to
+ * dereference the bio even after the "write_acked_by_peer" and
+ * "completed_ok" events came in, once we return from
+ * _drbd_send_zc_bio (drbd_send_dblock), we have to check
+ * whether it is done already, and end it. */
+ _req_may_be_done(req, m);
+ break;
+
+ case connection_lost_while_pending:
+ /* transfer log cleanup after connection loss */
+ /* assert something? */
+ if (req->rq_state & RQ_NET_PENDING)
+ dec_ap_pending(mdev);
+ req->rq_state &= ~(RQ_NET_OK|RQ_NET_PENDING);
+ req->rq_state |= RQ_NET_DONE;
+ /* if it is still queued, we may not complete it here.
+ * it will be canceled soon. */
+ if (!(req->rq_state & RQ_NET_QUEUED))
+ _req_may_be_done(req, m);
+ break;
+
+ case write_acked_by_peer_and_sis:
+ req->rq_state |= RQ_NET_SIS;
+ case conflict_discarded_by_peer:
+ /* for discarded conflicting writes of multiple primaries,
+ * there is no need to keep anything in the tl, potential
+ * node crashes are covered by the activity log. */
+ if (what == conflict_discarded_by_peer)
+ dev_alert(DEV, "Got DiscardAck packet %llus +%u!"
+ " DRBD is not a random data generator!\n",
+ (unsigned long long)req->sector, req->size);
+ req->rq_state |= RQ_NET_DONE;
+ /* fall through */
+ case write_acked_by_peer:
+ /* protocol C; successfully written on peer.
+ * Nothing to do here.
+ * We want to keep the tl in place for all protocols, to cater
+ * for volatile write-back caches on lower level devices.
+ *
+ * A barrier request is expected to have forced all prior
+ * requests onto stable storage, so completion of a barrier
+ * request could set NET_DONE right here, and not wait for the
+ * P_BARRIER_ACK, but that is an unnecessary optimization. */
+
+ /* this makes it effectively the same as for: */
+ case recv_acked_by_peer:
+ /* protocol B; pretends to be successfully written on peer.
+ * see also notes above in handed_over_to_network about
+ * protocol != C */
+ req->rq_state |= RQ_NET_OK;
+ D_ASSERT(req->rq_state & RQ_NET_PENDING);
+ dec_ap_pending(mdev);
+ req->rq_state &= ~RQ_NET_PENDING;
+ _req_may_be_done(req, m);
+ break;
+
+ case neg_acked:
+ /* assert something? */
+ if (req->rq_state & RQ_NET_PENDING)
+ dec_ap_pending(mdev);
+ req->rq_state &= ~(RQ_NET_OK|RQ_NET_PENDING);
+
+ req->rq_state |= RQ_NET_DONE;
+ _req_may_be_done(req, m);
+ /* else: done by handed_over_to_network */
+ break;
+
+ case barrier_acked:
+ if (req->rq_state & RQ_NET_PENDING) {
+ /* barrier came in before all requests have been acked.
+ * this is bad, because if the connection is lost now,
+ * we won't be able to clean them up... */
+ dev_err(DEV, "FIXME (barrier_acked but pending)\n");
+ list_move(&req->tl_requests, &mdev->out_of_sequence_requests);
+ }
+ D_ASSERT(req->rq_state & RQ_NET_SENT);
+ req->rq_state |= RQ_NET_DONE;
+ _req_may_be_done(req, m);
+ break;
+
+ case data_received:
+ D_ASSERT(req->rq_state & RQ_NET_PENDING);
+ dec_ap_pending(mdev);
+ req->rq_state &= ~RQ_NET_PENDING;
+ req->rq_state |= (RQ_NET_OK|RQ_NET_DONE);
+ _req_may_be_done(req, m);
+ break;
+ };
+}
+
+/* we may do a local read if:
+ * - we are consistent (of course),
+ * - or we are generally inconsistent,
+ * BUT we are still/already IN SYNC for this area.
+ * since size may be bigger than BM_BLOCK_SIZE,
+ * we may need to check several bits.
+ */
+static int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int size)
+{
+ unsigned long sbnr, ebnr;
+ sector_t esector, nr_sectors;
+
+ if (mdev->state.disk == D_UP_TO_DATE)
+ return 1;
+ if (mdev->state.disk >= D_OUTDATED)
+ return 0;
+ if (mdev->state.disk < D_INCONSISTENT)
+ return 0;
+ /* state.disk == D_INCONSISTENT We will have a look at the BitMap */
+ nr_sectors = drbd_get_capacity(mdev->this_bdev);
+ esector = sector + (size >> 9) - 1;
+
+ D_ASSERT(sector < nr_sectors);
+ D_ASSERT(esector < nr_sectors);
+
+ sbnr = BM_SECT_TO_BIT(sector);
+ ebnr = BM_SECT_TO_BIT(esector);
+
+ return 0 == drbd_bm_count_bits(mdev, sbnr, ebnr);
+}
+
+static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio)
+{
+ const int rw = bio_rw(bio);
+ const int size = bio->bi_size;
+ const sector_t sector = bio->bi_sector;
+ struct drbd_tl_epoch *b = NULL;
+ struct drbd_request *req;
+ int local, remote;
+ int err = -EIO;
+
+ /* allocate outside of all locks; */
+ req = drbd_req_new(mdev, bio);
+ if (!req) {
+ dec_ap_bio(mdev);
+ /* only pass the error to the upper layers.
+ * if user cannot handle io errors, that's not our business. */
+ dev_err(DEV, "could not kmalloc() req\n");
+ bio_endio(bio, -ENOMEM);
+ return 0;
+ }
+
+ local = get_ldev(mdev);
+ if (!local) {
+ bio_put(req->private_bio); /* or we get a bio leak */
+ req->private_bio = NULL;
+ }
+ if (rw == WRITE) {
+ remote = 1;
+ } else {
+ /* READ || READA */
+ if (local) {
+ if (!drbd_may_do_local_read(mdev, sector, size)) {
+ /* we could kick the syncer to
+ * sync this extent asap, wait for
+ * it, then continue locally.
+ * Or just issue the request remotely.
+ */
+ local = 0;
+ bio_put(req->private_bio);
+ req->private_bio = NULL;
+ put_ldev(mdev);
+ }
+ }
+ remote = !local && mdev->state.pdsk >= D_UP_TO_DATE;
+ }
+
+ /* If we have a disk, but a READA request is mapped to remote,
+ * we are R_PRIMARY, D_INCONSISTENT, SyncTarget.
+ * Just fail that READA request right here.
+ *
+ * THINK: maybe fail all READA when not local?
+ * or make this configurable...
+ * if network is slow, READA won't do any good.
+ */
+ if (rw == READA && mdev->state.disk >= D_INCONSISTENT && !local) {
+ err = -EWOULDBLOCK;
+ goto fail_and_free_req;
+ }
+
+ /* For WRITES going to the local disk, grab a reference on the target
+ * extent. This waits for any resync activity in the corresponding
+ * resync extent to finish, and, if necessary, pulls in the target
+ * extent into the activity log, which involves further disk io because
+ * of transactional on-disk meta data updates. */
+ if (rw == WRITE && local)
+ drbd_al_begin_io(mdev, sector);
+
+ remote = remote && (mdev->state.pdsk == D_UP_TO_DATE ||
+ (mdev->state.pdsk == D_INCONSISTENT &&
+ mdev->state.conn >= C_CONNECTED));
+
+ if (!(local || remote)) {
+ dev_err(DEV, "IO ERROR: neither local nor remote disk\n");
+ goto fail_free_complete;
+ }
+
+ /* For WRITE request, we have to make sure that we have an
+ * unused_spare_tle, in case we need to start a new epoch.
+ * I try to be smart and avoid to pre-allocate always "just in case",
+ * but there is a race between testing the bit and pointer outside the
+ * spinlock, and grabbing the spinlock.
+ * if we lost that race, we retry. */
+ if (rw == WRITE && remote &&
+ mdev->unused_spare_tle == NULL &&
+ test_bit(CREATE_BARRIER, &mdev->flags)) {
+allocate_barrier:
+ b = kmalloc(sizeof(struct drbd_tl_epoch), GFP_NOIO);
+ if (!b) {
+ dev_err(DEV, "Failed to alloc barrier.\n");
+ err = -ENOMEM;
+ goto fail_free_complete;
+ }
+ }
+
+ /* GOOD, everything prepared, grab the spin_lock */
+ spin_lock_irq(&mdev->req_lock);
+
+ if (remote) {
+ remote = (mdev->state.pdsk == D_UP_TO_DATE ||
+ (mdev->state.pdsk == D_INCONSISTENT &&
+ mdev->state.conn >= C_CONNECTED));
+ if (!remote)
+ dev_warn(DEV, "lost connection while grabbing the req_lock!\n");
+ if (!(local || remote)) {
+ dev_err(DEV, "IO ERROR: neither local nor remote disk\n");
+ spin_unlock_irq(&mdev->req_lock);
+ goto fail_free_complete;
+ }
+ }
+
+ if (b && mdev->unused_spare_tle == NULL) {
+ mdev->unused_spare_tle = b;
+ b = NULL;
+ }
+ if (rw == WRITE && remote &&
+ mdev->unused_spare_tle == NULL &&
+ test_bit(CREATE_BARRIER, &mdev->flags)) {
+ /* someone closed the current epoch
+ * while we were grabbing the spinlock */
+ spin_unlock_irq(&mdev->req_lock);
+ goto allocate_barrier;
+ }
+
+
+ /* Update disk stats */
+ _drbd_start_io_acct(mdev, req, bio);
+
+ /* _maybe_start_new_epoch(mdev);
+ * If we need to generate a write barrier packet, we have to add the
+ * new epoch (barrier) object, and queue the barrier packet for sending,
+ * and queue the req's data after it _within the same lock_, otherwise
+ * we have race conditions were the reorder domains could be mixed up.
+ *
+ * Even read requests may start a new epoch and queue the corresponding
+ * barrier packet. To get the write ordering right, we only have to
+ * make sure that, if this is a write request and it triggered a
+ * barrier packet, this request is queued within the same spinlock. */
+ if (remote && mdev->unused_spare_tle &&
+ test_and_clear_bit(CREATE_BARRIER, &mdev->flags)) {
+ _tl_add_barrier(mdev, mdev->unused_spare_tle);
+ mdev->unused_spare_tle = NULL;
+ } else {
+ D_ASSERT(!(remote && rw == WRITE &&
+ test_bit(CREATE_BARRIER, &mdev->flags)));
+ }
+
+ /* NOTE
+ * Actually, 'local' may be wrong here already, since we may have failed
+ * to write to the meta data, and may become wrong anytime because of
+ * local io-error for some other request, which would lead to us
+ * "detaching" the local disk.
+ *
+ * 'remote' may become wrong any time because the network could fail.
+ *
+ * This is a harmless race condition, though, since it is handled
+ * correctly at the appropriate places; so it just defers the failure
+ * of the respective operation.
+ */
+
+ /* mark them early for readability.
+ * this just sets some state flags. */
+ if (remote)
+ _req_mod(req, to_be_send);
+ if (local)
+ _req_mod(req, to_be_submitted);
+
+ /* check this request on the collision detection hash tables.
+ * if we have a conflict, just complete it here.
+ * THINK do we want to check reads, too? (I don't think so...) */
+ if (rw == WRITE && _req_conflicts(req)) {
+ /* this is a conflicting request.
+ * even though it may have been only _partially_
+ * overlapping with one of the currently pending requests,
+ * without even submitting or sending it, we will
+ * pretend that it was successfully served right now.
+ */
+ if (local) {
+ bio_put(req->private_bio);
+ req->private_bio = NULL;
+ drbd_al_complete_io(mdev, req->sector);
+ put_ldev(mdev);
+ local = 0;
+ }
+ if (remote)
+ dec_ap_pending(mdev);
+ _drbd_end_io_acct(mdev, req);
+ /* THINK: do we want to fail it (-EIO), or pretend success? */
+ bio_endio(req->master_bio, 0);
+ req->master_bio = NULL;
+ dec_ap_bio(mdev);
+ drbd_req_free(req);
+ remote = 0;
+ }
+
+ /* NOTE remote first: to get the concurrent write detection right,
+ * we must register the request before start of local IO. */
+ if (remote) {
+ /* either WRITE and C_CONNECTED,
+ * or READ, and no local disk,
+ * or READ, but not in sync.
+ */
+ _req_mod(req, (rw == WRITE)
+ ? queue_for_net_write
+ : queue_for_net_read);
+ }
+ spin_unlock_irq(&mdev->req_lock);
+ kfree(b); /* if someone else has beaten us to it... */
+
+ if (local) {
+ req->private_bio->bi_bdev = mdev->ldev->backing_bdev;
+
+ if (FAULT_ACTIVE(mdev, rw == WRITE ? DRBD_FAULT_DT_WR
+ : rw == READ ? DRBD_FAULT_DT_RD
+ : DRBD_FAULT_DT_RA))
+ bio_endio(req->private_bio, -EIO);
+ else
+ generic_make_request(req->private_bio);
+ }
+
+ /* we need to plug ALWAYS since we possibly need to kick lo_dev.
+ * we plug after submit, so we won't miss an unplug event */
+ drbd_plug_device(mdev);
+
+ return 0;
+
+fail_free_complete:
+ if (rw == WRITE && local)
+ drbd_al_complete_io(mdev, sector);
+fail_and_free_req:
+ if (local) {
+ bio_put(req->private_bio);
+ req->private_bio = NULL;
+ put_ldev(mdev);
+ }
+ bio_endio(bio, err);
+ drbd_req_free(req);
+ dec_ap_bio(mdev);
+ kfree(b);
+
+ return 0;
+}
+
+/* helper function for drbd_make_request
+ * if we can determine just by the mdev (state) that this request will fail,
+ * return 1
+ * otherwise return 0
+ */
+static int drbd_fail_request_early(struct drbd_conf *mdev, int is_write)
+{
+ /* Unconfigured */
+ if (mdev->state.conn == C_DISCONNECTING &&
+ mdev->state.disk == D_DISKLESS)
+ return 1;
+
+ if (mdev->state.role != R_PRIMARY &&
+ (!allow_oos || is_write)) {
+ if (__ratelimit(&drbd_ratelimit_state)) {
+ dev_err(DEV, "Process %s[%u] tried to %s; "
+ "since we are not in Primary state, "
+ "we cannot allow this\n",
+ current->comm, current->pid,
+ is_write ? "WRITE" : "READ");
+ }
+ return 1;
+ }
+
+ /*
+ * Paranoia: we might have been primary, but sync target, or
+ * even diskless, then lost the connection.
+ * This should have been handled (panic? suspend?) somewhere
+ * else. But maybe it was not, so check again here.
+ * Caution: as long as we do not have a read/write lock on mdev,
+ * to serialize state changes, this is racy, since we may lose
+ * the connection *after* we test for the cstate.
+ */
+ if (mdev->state.disk < D_UP_TO_DATE && mdev->state.pdsk < D_UP_TO_DATE) {
+ if (__ratelimit(&drbd_ratelimit_state))
+ dev_err(DEV, "Sorry, I have no access to good data anymore.\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+int drbd_make_request_26(struct request_queue *q, struct bio *bio)
+{
+ unsigned int s_enr, e_enr;
+ struct drbd_conf *mdev = (struct drbd_conf *) q->queuedata;
+
+ if (drbd_fail_request_early(mdev, bio_data_dir(bio) & WRITE)) {
+ bio_endio(bio, -EPERM);
+ return 0;
+ }
+
+ /* Reject barrier requests if we know the underlying device does
+ * not support them.
+ * XXX: Need to get this info from peer as well some how so we
+ * XXX: reject if EITHER side/data/metadata area does not support them.
+ *
+ * because of those XXX, this is not yet enabled,
+ * i.e. in drbd_init_set_defaults we set the NO_BARRIER_SUPP bit.
+ */
+ if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER) && test_bit(NO_BARRIER_SUPP, &mdev->flags))) {
+ /* dev_warn(DEV, "Rejecting barrier request as underlying device does not support\n"); */
+ bio_endio(bio, -EOPNOTSUPP);
+ return 0;
+ }
+
+ /*
+ * what we "blindly" assume:
+ */
+ D_ASSERT(bio->bi_size > 0);
+ D_ASSERT((bio->bi_size & 0x1ff) == 0);
+ D_ASSERT(bio->bi_idx == 0);
+
+ /* to make some things easier, force alignment of requests within the
+ * granularity of our hash tables */
+ s_enr = bio->bi_sector >> HT_SHIFT;
+ e_enr = (bio->bi_sector+(bio->bi_size>>9)-1) >> HT_SHIFT;
+
+ if (likely(s_enr == e_enr)) {
+ inc_ap_bio(mdev, 1);
+ return drbd_make_request_common(mdev, bio);
+ }
+
+ /* can this bio be split generically?
+ * Maybe add our own split-arbitrary-bios function. */
+ if (bio->bi_vcnt != 1 || bio->bi_idx != 0 || bio->bi_size > DRBD_MAX_SEGMENT_SIZE) {
+ /* rather error out here than BUG in bio_split */
+ dev_err(DEV, "bio would need to, but cannot, be split: "
+ "(vcnt=%u,idx=%u,size=%u,sector=%llu)\n",
+ bio->bi_vcnt, bio->bi_idx, bio->bi_size,
+ (unsigned long long)bio->bi_sector);
+ bio_endio(bio, -EINVAL);
+ } else {
+ /* This bio crosses some boundary, so we have to split it. */
+ struct bio_pair *bp;
+ /* works for the "do not cross hash slot boundaries" case
+ * e.g. sector 262269, size 4096
+ * s_enr = 262269 >> 6 = 4097
+ * e_enr = (262269+8-1) >> 6 = 4098
+ * HT_SHIFT = 6
+ * sps = 64, mask = 63
+ * first_sectors = 64 - (262269 & 63) = 3
+ */
+ const sector_t sect = bio->bi_sector;
+ const int sps = 1 << HT_SHIFT; /* sectors per slot */
+ const int mask = sps - 1;
+ const sector_t first_sectors = sps - (sect & mask);
+ bp = bio_split(bio,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+ bio_split_pool,
+#endif
+ first_sectors);
+
+ /* we need to get a "reference count" (ap_bio_cnt)
+ * to avoid races with the disconnect/reconnect/suspend code.
+ * In case we need to split the bio here, we need to get two references
+ * atomically, otherwise we might deadlock when trying to submit the
+ * second one! */
+ inc_ap_bio(mdev, 2);
+
+ D_ASSERT(e_enr == s_enr + 1);
+
+ drbd_make_request_common(mdev, &bp->bio1);
+ drbd_make_request_common(mdev, &bp->bio2);
+ bio_pair_release(bp);
+ }
+ return 0;
+}
+
+/* This is called by bio_add_page(). With this function we reduce
+ * the number of BIOs that span over multiple DRBD_MAX_SEGMENT_SIZEs
+ * units (was AL_EXTENTs).
+ *
+ * we do the calculation within the lower 32bit of the byte offsets,
+ * since we don't care for actual offset, but only check whether it
+ * would cross "activity log extent" boundaries.
+ *
+ * As long as the BIO is empty we have to allow at least one bvec,
+ * regardless of size and offset. so the resulting bio may still
+ * cross extent boundaries. those are dealt with (bio_split) in
+ * drbd_make_request_26.
+ */
+int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec)
+{
+ struct drbd_conf *mdev = (struct drbd_conf *) q->queuedata;
+ unsigned int bio_offset =
+ (unsigned int)bvm->bi_sector << 9; /* 32 bit */
+ unsigned int bio_size = bvm->bi_size;
+ int limit, backing_limit;
+
+ limit = DRBD_MAX_SEGMENT_SIZE
+ - ((bio_offset & (DRBD_MAX_SEGMENT_SIZE-1)) + bio_size);
+ if (limit < 0)
+ limit = 0;
+ if (bio_size == 0) {
+ if (limit <= bvec->bv_len)
+ limit = bvec->bv_len;
+ } else if (limit && get_ldev(mdev)) {
+ struct request_queue * const b =
+ mdev->ldev->backing_bdev->bd_disk->queue;
+ if (b->merge_bvec_fn && mdev->ldev->dc.use_bmbv) {
+ backing_limit = b->merge_bvec_fn(b, bvm, bvec);
+ limit = min(limit, backing_limit);
+ }
+ put_ldev(mdev);
+ }
+ return limit;
+}
diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h
new file mode 100644
index 000000000000..f22c1bc8ec7e
--- /dev/null
+++ b/drivers/block/drbd/drbd_req.h
@@ -0,0 +1,326 @@
+/*
+ drbd_req.h
+
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2006-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 2006-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+ Copyright (C) 2006-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+
+ DRBD 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.
+
+ DRBD is distributed in the hope that it will be useful,
+ but WITHOUT 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 drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _DRBD_REQ_H
+#define _DRBD_REQ_H
+
+#include <linux/module.h>
+
+#include <linux/slab.h>
+#include <linux/drbd.h>
+#include "drbd_int.h"
+#include "drbd_wrappers.h"
+
+/* The request callbacks will be called in irq context by the IDE drivers,
+ and in Softirqs/Tasklets/BH context by the SCSI drivers,
+ and by the receiver and worker in kernel-thread context.
+ Try to get the locking right :) */
+
+/*
+ * Objects of type struct drbd_request do only exist on a R_PRIMARY node, and are
+ * associated with IO requests originating from the block layer above us.
+ *
+ * There are quite a few things that may happen to a drbd request
+ * during its lifetime.
+ *
+ * It will be created.
+ * It will be marked with the intention to be
+ * submitted to local disk and/or
+ * send via the network.
+ *
+ * It has to be placed on the transfer log and other housekeeping lists,
+ * In case we have a network connection.
+ *
+ * It may be identified as a concurrent (write) request
+ * and be handled accordingly.
+ *
+ * It may me handed over to the local disk subsystem.
+ * It may be completed by the local disk subsystem,
+ * either sucessfully or with io-error.
+ * In case it is a READ request, and it failed locally,
+ * it may be retried remotely.
+ *
+ * It may be queued for sending.
+ * It may be handed over to the network stack,
+ * which may fail.
+ * It may be acknowledged by the "peer" according to the wire_protocol in use.
+ * this may be a negative ack.
+ * It may receive a faked ack when the network connection is lost and the
+ * transfer log is cleaned up.
+ * Sending may be canceled due to network connection loss.
+ * When it finally has outlived its time,
+ * corresponding dirty bits in the resync-bitmap may be cleared or set,
+ * it will be destroyed,
+ * and completion will be signalled to the originator,
+ * with or without "success".
+ */
+
+enum drbd_req_event {
+ created,
+ to_be_send,
+ to_be_submitted,
+
+ /* XXX yes, now I am inconsistent...
+ * these two are not "events" but "actions"
+ * oh, well... */
+ queue_for_net_write,
+ queue_for_net_read,
+
+ send_canceled,
+ send_failed,
+ handed_over_to_network,
+ connection_lost_while_pending,
+ recv_acked_by_peer,
+ write_acked_by_peer,
+ write_acked_by_peer_and_sis, /* and set_in_sync */
+ conflict_discarded_by_peer,
+ neg_acked,
+ barrier_acked, /* in protocol A and B */
+ data_received, /* (remote read) */
+
+ read_completed_with_error,
+ read_ahead_completed_with_error,
+ write_completed_with_error,
+ completed_ok,
+ nothing, /* for tracing only */
+};
+
+/* encoding of request states for now. we don't actually need that many bits.
+ * we don't need to do atomic bit operations either, since most of the time we
+ * need to look at the connection state and/or manipulate some lists at the
+ * same time, so we should hold the request lock anyways.
+ */
+enum drbd_req_state_bits {
+ /* 210
+ * 000: no local possible
+ * 001: to be submitted
+ * UNUSED, we could map: 011: submitted, completion still pending
+ * 110: completed ok
+ * 010: completed with error
+ */
+ __RQ_LOCAL_PENDING,
+ __RQ_LOCAL_COMPLETED,
+ __RQ_LOCAL_OK,
+
+ /* 76543
+ * 00000: no network possible
+ * 00001: to be send
+ * 00011: to be send, on worker queue
+ * 00101: sent, expecting recv_ack (B) or write_ack (C)
+ * 11101: sent,
+ * recv_ack (B) or implicit "ack" (A),
+ * still waiting for the barrier ack.
+ * master_bio may already be completed and invalidated.
+ * 11100: write_acked (C),
+ * data_received (for remote read, any protocol)
+ * or finally the barrier ack has arrived (B,A)...
+ * request can be freed
+ * 01100: neg-acked (write, protocol C)
+ * or neg-d-acked (read, any protocol)
+ * or killed from the transfer log
+ * during cleanup after connection loss
+ * request can be freed
+ * 01000: canceled or send failed...
+ * request can be freed
+ */
+
+ /* if "SENT" is not set, yet, this can still fail or be canceled.
+ * if "SENT" is set already, we still wait for an Ack packet.
+ * when cleared, the master_bio may be completed.
+ * in (B,A) the request object may still linger on the transaction log
+ * until the corresponding barrier ack comes in */
+ __RQ_NET_PENDING,
+
+ /* If it is QUEUED, and it is a WRITE, it is also registered in the
+ * transfer log. Currently we need this flag to avoid conflicts between
+ * worker canceling the request and tl_clear_barrier killing it from
+ * transfer log. We should restructure the code so this conflict does
+ * no longer occur. */
+ __RQ_NET_QUEUED,
+
+ /* well, actually only "handed over to the network stack".
+ *
+ * TODO can potentially be dropped because of the similar meaning
+ * of RQ_NET_SENT and ~RQ_NET_QUEUED.
+ * however it is not exactly the same. before we drop it
+ * we must ensure that we can tell a request with network part
+ * from a request without, regardless of what happens to it. */
+ __RQ_NET_SENT,
+
+ /* when set, the request may be freed (if RQ_NET_QUEUED is clear).
+ * basically this means the corresponding P_BARRIER_ACK was received */
+ __RQ_NET_DONE,
+
+ /* whether or not we know (C) or pretend (B,A) that the write
+ * was successfully written on the peer.
+ */
+ __RQ_NET_OK,
+
+ /* peer called drbd_set_in_sync() for this write */
+ __RQ_NET_SIS,
+
+ /* keep this last, its for the RQ_NET_MASK */
+ __RQ_NET_MAX,
+};
+
+#define RQ_LOCAL_PENDING (1UL << __RQ_LOCAL_PENDING)
+#define RQ_LOCAL_COMPLETED (1UL << __RQ_LOCAL_COMPLETED)
+#define RQ_LOCAL_OK (1UL << __RQ_LOCAL_OK)
+
+#define RQ_LOCAL_MASK ((RQ_LOCAL_OK << 1)-1) /* 0x07 */
+
+#define RQ_NET_PENDING (1UL << __RQ_NET_PENDING)
+#define RQ_NET_QUEUED (1UL << __RQ_NET_QUEUED)
+#define RQ_NET_SENT (1UL << __RQ_NET_SENT)
+#define RQ_NET_DONE (1UL << __RQ_NET_DONE)
+#define RQ_NET_OK (1UL << __RQ_NET_OK)
+#define RQ_NET_SIS (1UL << __RQ_NET_SIS)
+
+/* 0x1f8 */
+#define RQ_NET_MASK (((1UL << __RQ_NET_MAX)-1) & ~RQ_LOCAL_MASK)
+
+/* epoch entries */
+static inline
+struct hlist_head *ee_hash_slot(struct drbd_conf *mdev, sector_t sector)
+{
+ BUG_ON(mdev->ee_hash_s == 0);
+ return mdev->ee_hash +
+ ((unsigned int)(sector>>HT_SHIFT) % mdev->ee_hash_s);
+}
+
+/* transfer log (drbd_request objects) */
+static inline
+struct hlist_head *tl_hash_slot(struct drbd_conf *mdev, sector_t sector)
+{
+ BUG_ON(mdev->tl_hash_s == 0);
+ return mdev->tl_hash +
+ ((unsigned int)(sector>>HT_SHIFT) % mdev->tl_hash_s);
+}
+
+/* application reads (drbd_request objects) */
+static struct hlist_head *ar_hash_slot(struct drbd_conf *mdev, sector_t sector)
+{
+ return mdev->app_reads_hash
+ + ((unsigned int)(sector) % APP_R_HSIZE);
+}
+
+/* when we receive the answer for a read request,
+ * verify that we actually know about it */
+static inline struct drbd_request *_ar_id_to_req(struct drbd_conf *mdev,
+ u64 id, sector_t sector)
+{
+ struct hlist_head *slot = ar_hash_slot(mdev, sector);
+ struct hlist_node *n;
+ struct drbd_request *req;
+
+ hlist_for_each_entry(req, n, slot, colision) {
+ if ((unsigned long)req == (unsigned long)id) {
+ D_ASSERT(req->sector == sector);
+ return req;
+ }
+ }
+ return NULL;
+}
+
+static inline struct drbd_request *drbd_req_new(struct drbd_conf *mdev,
+ struct bio *bio_src)
+{
+ struct bio *bio;
+ struct drbd_request *req =
+ mempool_alloc(drbd_request_mempool, GFP_NOIO);
+ if (likely(req)) {
+ bio = bio_clone(bio_src, GFP_NOIO); /* XXX cannot fail?? */
+
+ req->rq_state = 0;
+ req->mdev = mdev;
+ req->master_bio = bio_src;
+ req->private_bio = bio;
+ req->epoch = 0;
+ req->sector = bio->bi_sector;
+ req->size = bio->bi_size;
+ req->start_time = jiffies;
+ INIT_HLIST_NODE(&req->colision);
+ INIT_LIST_HEAD(&req->tl_requests);
+ INIT_LIST_HEAD(&req->w.list);
+
+ bio->bi_private = req;
+ bio->bi_end_io = drbd_endio_pri;
+ bio->bi_next = NULL;
+ }
+ return req;
+}
+
+static inline void drbd_req_free(struct drbd_request *req)
+{
+ mempool_free(req, drbd_request_mempool);
+}
+
+static inline int overlaps(sector_t s1, int l1, sector_t s2, int l2)
+{
+ return !((s1 + (l1>>9) <= s2) || (s1 >= s2 + (l2>>9)));
+}
+
+/* Short lived temporary struct on the stack.
+ * We could squirrel the error to be returned into
+ * bio->bi_size, or similar. But that would be too ugly. */
+struct bio_and_error {
+ struct bio *bio;
+ int error;
+};
+
+extern void _req_may_be_done(struct drbd_request *req,
+ struct bio_and_error *m);
+extern void __req_mod(struct drbd_request *req, enum drbd_req_event what,
+ struct bio_and_error *m);
+extern void complete_master_bio(struct drbd_conf *mdev,
+ struct bio_and_error *m);
+
+/* use this if you don't want to deal with calling complete_master_bio()
+ * outside the spinlock, e.g. when walking some list on cleanup. */
+static inline void _req_mod(struct drbd_request *req, enum drbd_req_event what)
+{
+ struct drbd_conf *mdev = req->mdev;
+ struct bio_and_error m;
+
+ /* __req_mod possibly frees req, do not touch req after that! */
+ __req_mod(req, what, &m);
+ if (m.bio)
+ complete_master_bio(mdev, &m);
+}
+
+/* completion of master bio is outside of spinlock.
+ * If you need it irqsave, do it your self! */
+static inline void req_mod(struct drbd_request *req,
+ enum drbd_req_event what)
+{
+ struct drbd_conf *mdev = req->mdev;
+ struct bio_and_error m;
+ spin_lock_irq(&mdev->req_lock);
+ __req_mod(req, what, &m);
+ spin_unlock_irq(&mdev->req_lock);
+
+ if (m.bio)
+ complete_master_bio(mdev, &m);
+}
+#endif
diff --git a/drivers/block/drbd/drbd_strings.c b/drivers/block/drbd/drbd_strings.c
new file mode 100644
index 000000000000..76863e3f05be
--- /dev/null
+++ b/drivers/block/drbd/drbd_strings.c
@@ -0,0 +1,113 @@
+/*
+ drbd.h
+
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2003-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 2003-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+ Copyright (C) 2003-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+ drbd 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.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT 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 drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/drbd.h>
+
+static const char *drbd_conn_s_names[] = {
+ [C_STANDALONE] = "StandAlone",
+ [C_DISCONNECTING] = "Disconnecting",
+ [C_UNCONNECTED] = "Unconnected",
+ [C_TIMEOUT] = "Timeout",
+ [C_BROKEN_PIPE] = "BrokenPipe",
+ [C_NETWORK_FAILURE] = "NetworkFailure",
+ [C_PROTOCOL_ERROR] = "ProtocolError",
+ [C_WF_CONNECTION] = "WFConnection",
+ [C_WF_REPORT_PARAMS] = "WFReportParams",
+ [C_TEAR_DOWN] = "TearDown",
+ [C_CONNECTED] = "Connected",
+ [C_STARTING_SYNC_S] = "StartingSyncS",
+ [C_STARTING_SYNC_T] = "StartingSyncT",
+ [C_WF_BITMAP_S] = "WFBitMapS",
+ [C_WF_BITMAP_T] = "WFBitMapT",
+ [C_WF_SYNC_UUID] = "WFSyncUUID",
+ [C_SYNC_SOURCE] = "SyncSource",
+ [C_SYNC_TARGET] = "SyncTarget",
+ [C_PAUSED_SYNC_S] = "PausedSyncS",
+ [C_PAUSED_SYNC_T] = "PausedSyncT",
+ [C_VERIFY_S] = "VerifyS",
+ [C_VERIFY_T] = "VerifyT",
+};
+
+static const char *drbd_role_s_names[] = {
+ [R_PRIMARY] = "Primary",
+ [R_SECONDARY] = "Secondary",
+ [R_UNKNOWN] = "Unknown"
+};
+
+static const char *drbd_disk_s_names[] = {
+ [D_DISKLESS] = "Diskless",
+ [D_ATTACHING] = "Attaching",
+ [D_FAILED] = "Failed",
+ [D_NEGOTIATING] = "Negotiating",
+ [D_INCONSISTENT] = "Inconsistent",
+ [D_OUTDATED] = "Outdated",
+ [D_UNKNOWN] = "DUnknown",
+ [D_CONSISTENT] = "Consistent",
+ [D_UP_TO_DATE] = "UpToDate",
+};
+
+static const char *drbd_state_sw_errors[] = {
+ [-SS_TWO_PRIMARIES] = "Multiple primaries not allowed by config",
+ [-SS_NO_UP_TO_DATE_DISK] = "Refusing to be Primary without at least one UpToDate disk",
+ [-SS_NO_LOCAL_DISK] = "Can not resync without local disk",
+ [-SS_NO_REMOTE_DISK] = "Can not resync without remote disk",
+ [-SS_CONNECTED_OUTDATES] = "Refusing to be Outdated while Connected",
+ [-SS_PRIMARY_NOP] = "Refusing to be Primary while peer is not outdated",
+ [-SS_RESYNC_RUNNING] = "Can not start OV/resync since it is already active",
+ [-SS_ALREADY_STANDALONE] = "Can not disconnect a StandAlone device",
+ [-SS_CW_FAILED_BY_PEER] = "State change was refused by peer node",
+ [-SS_IS_DISKLESS] = "Device is diskless, the requested operation requires a disk",
+ [-SS_DEVICE_IN_USE] = "Device is held open by someone",
+ [-SS_NO_NET_CONFIG] = "Have no net/connection configuration",
+ [-SS_NO_VERIFY_ALG] = "Need a verify algorithm to start online verify",
+ [-SS_NEED_CONNECTION] = "Need a connection to start verify or resync",
+ [-SS_NOT_SUPPORTED] = "Peer does not support protocol",
+ [-SS_LOWER_THAN_OUTDATED] = "Disk state is lower than outdated",
+ [-SS_IN_TRANSIENT_STATE] = "In transient state, retry after next state change",
+ [-SS_CONCURRENT_ST_CHG] = "Concurrent state changes detected and aborted",
+};
+
+const char *drbd_conn_str(enum drbd_conns s)
+{
+ /* enums are unsigned... */
+ return s > C_PAUSED_SYNC_T ? "TOO_LARGE" : drbd_conn_s_names[s];
+}
+
+const char *drbd_role_str(enum drbd_role s)
+{
+ return s > R_SECONDARY ? "TOO_LARGE" : drbd_role_s_names[s];
+}
+
+const char *drbd_disk_str(enum drbd_disk_state s)
+{
+ return s > D_UP_TO_DATE ? "TOO_LARGE" : drbd_disk_s_names[s];
+}
+
+const char *drbd_set_st_err_str(enum drbd_state_ret_codes err)
+{
+ return err <= SS_AFTER_LAST_ERROR ? "TOO_SMALL" :
+ err > SS_TWO_PRIMARIES ? "TOO_LARGE"
+ : drbd_state_sw_errors[-err];
+}
diff --git a/drivers/block/drbd/drbd_tracing.c b/drivers/block/drbd/drbd_tracing.c
new file mode 100644
index 000000000000..d18d4f7b4bef
--- /dev/null
+++ b/drivers/block/drbd/drbd_tracing.c
@@ -0,0 +1,752 @@
+/*
+ drbd_tracing.c
+
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2003-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 2003-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+ Copyright (C) 2003-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+ drbd 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.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT 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 drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/module.h>
+#include <linux/drbd.h>
+#include <linux/ctype.h>
+#include "drbd_int.h"
+#include "drbd_tracing.h"
+#include <linux/drbd_tag_magic.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Philipp Reisner, Lars Ellenberg");
+MODULE_DESCRIPTION("DRBD tracepoint probes");
+MODULE_PARM_DESC(trace_mask, "Bitmap of events to trace see drbd_tracing.c");
+MODULE_PARM_DESC(trace_level, "Current tracing level (changeable in /sys)");
+MODULE_PARM_DESC(trace_devs, "Bitmap of devices to trace (changeable in /sys)");
+
+unsigned int trace_mask = 0; /* Bitmap of events to trace */
+int trace_level; /* Current trace level */
+int trace_devs; /* Bitmap of devices to trace */
+
+module_param(trace_mask, uint, 0444);
+module_param(trace_level, int, 0644);
+module_param(trace_devs, int, 0644);
+
+enum {
+ TRACE_PACKET = 0x0001,
+ TRACE_RQ = 0x0002,
+ TRACE_UUID = 0x0004,
+ TRACE_RESYNC = 0x0008,
+ TRACE_EE = 0x0010,
+ TRACE_UNPLUG = 0x0020,
+ TRACE_NL = 0x0040,
+ TRACE_AL_EXT = 0x0080,
+ TRACE_INT_RQ = 0x0100,
+ TRACE_MD_IO = 0x0200,
+ TRACE_EPOCH = 0x0400,
+};
+
+/* Buffer printing support
+ * dbg_print_flags: used for Flags arg to drbd_print_buffer
+ * - DBGPRINT_BUFFADDR; if set, each line starts with the
+ * virtual address of the line being output. If clear,
+ * each line starts with the offset from the beginning
+ * of the buffer. */
+enum dbg_print_flags {
+ DBGPRINT_BUFFADDR = 0x0001,
+};
+
+/* Macro stuff */
+static char *nl_packet_name(int packet_type)
+{
+/* Generate packet type strings */
+#define NL_PACKET(name, number, fields) \
+ [P_ ## name] = # name,
+#define NL_INTEGER Argh!
+#define NL_BIT Argh!
+#define NL_INT64 Argh!
+#define NL_STRING Argh!
+
+ static char *nl_tag_name[P_nl_after_last_packet] = {
+#include "linux/drbd_nl.h"
+ };
+
+ return (packet_type < sizeof(nl_tag_name)/sizeof(nl_tag_name[0])) ?
+ nl_tag_name[packet_type] : "*Unknown*";
+}
+/* /Macro stuff */
+
+static inline int is_mdev_trace(struct drbd_conf *mdev, unsigned int level)
+{
+ return trace_level >= level && ((1 << mdev_to_minor(mdev)) & trace_devs);
+}
+
+static void probe_drbd_unplug(struct drbd_conf *mdev, char *msg)
+{
+ if (!is_mdev_trace(mdev, TRACE_LVL_ALWAYS))
+ return;
+
+ dev_info(DEV, "%s, ap_bio_count=%d\n", msg, atomic_read(&mdev->ap_bio_cnt));
+}
+
+static void probe_drbd_uuid(struct drbd_conf *mdev, enum drbd_uuid_index index)
+{
+ static char *uuid_str[UI_EXTENDED_SIZE] = {
+ [UI_CURRENT] = "CURRENT",
+ [UI_BITMAP] = "BITMAP",
+ [UI_HISTORY_START] = "HISTORY_START",
+ [UI_HISTORY_END] = "HISTORY_END",
+ [UI_SIZE] = "SIZE",
+ [UI_FLAGS] = "FLAGS",
+ };
+
+ if (!is_mdev_trace(mdev, TRACE_LVL_ALWAYS))
+ return;
+
+ if (index >= UI_EXTENDED_SIZE) {
+ dev_warn(DEV, " uuid_index >= EXTENDED_SIZE\n");
+ return;
+ }
+
+ dev_info(DEV, " uuid[%s] now %016llX\n",
+ uuid_str[index],
+ (unsigned long long)mdev->ldev->md.uuid[index]);
+}
+
+static void probe_drbd_md_io(struct drbd_conf *mdev, int rw,
+ struct drbd_backing_dev *bdev)
+{
+ if (!is_mdev_trace(mdev, TRACE_LVL_ALWAYS))
+ return;
+
+ dev_info(DEV, " %s metadata superblock now\n",
+ rw == READ ? "Reading" : "Writing");
+}
+
+static void probe_drbd_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, char* msg)
+{
+ if (!is_mdev_trace(mdev, TRACE_LVL_ALWAYS))
+ return;
+
+ dev_info(DEV, "EE %s sec=%llus size=%u e=%p\n",
+ msg, (unsigned long long)e->sector, e->size, e);
+}
+
+static void probe_drbd_epoch(struct drbd_conf *mdev, struct drbd_epoch *epoch,
+ enum epoch_event ev)
+{
+ static char *epoch_event_str[] = {
+ [EV_PUT] = "put",
+ [EV_GOT_BARRIER_NR] = "got_barrier_nr",
+ [EV_BARRIER_DONE] = "barrier_done",
+ [EV_BECAME_LAST] = "became_last",
+ [EV_TRACE_FLUSH] = "issuing_flush",
+ [EV_TRACE_ADD_BARRIER] = "added_barrier",
+ [EV_TRACE_SETTING_BI] = "just set barrier_in_next_epoch",
+ };
+
+ if (!is_mdev_trace(mdev, TRACE_LVL_ALWAYS))
+ return;
+
+ ev &= ~EV_CLEANUP;
+
+ switch (ev) {
+ case EV_TRACE_ALLOC:
+ dev_info(DEV, "Allocate epoch %p/xxxx { } nr_epochs=%d\n", epoch, mdev->epochs);
+ break;
+ case EV_TRACE_FREE:
+ dev_info(DEV, "Freeing epoch %p/%d { size=%d } nr_epochs=%d\n",
+ epoch, epoch->barrier_nr, atomic_read(&epoch->epoch_size),
+ mdev->epochs);
+ break;
+ default:
+ dev_info(DEV, "Update epoch %p/%d { size=%d active=%d %c%c n%c%c } ev=%s\n",
+ epoch, epoch->barrier_nr, atomic_read(&epoch->epoch_size),
+ atomic_read(&epoch->active),
+ test_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags) ? 'n' : '-',
+ test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags) ? 'b' : '-',
+ test_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags) ? 'i' : '-',
+ test_bit(DE_BARRIER_IN_NEXT_EPOCH_DONE, &epoch->flags) ? 'd' : '-',
+ epoch_event_str[ev]);
+ }
+}
+
+static void probe_drbd_netlink(void *data, int is_req)
+{
+ struct cn_msg *msg = data;
+
+ if (is_req) {
+ struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req *)msg->data;
+
+ printk(KERN_INFO "drbd%d: "
+ "Netlink: << %s (%d) - seq: %x, ack: %x, len: %x\n",
+ nlp->drbd_minor,
+ nl_packet_name(nlp->packet_type),
+ nlp->packet_type,
+ msg->seq, msg->ack, msg->len);
+ } else {
+ struct drbd_nl_cfg_reply *nlp = (struct drbd_nl_cfg_reply *)msg->data;
+
+ printk(KERN_INFO "drbd%d: "
+ "Netlink: >> %s (%d) - seq: %x, ack: %x, len: %x\n",
+ nlp->minor,
+ nlp->packet_type == P_nl_after_last_packet ?
+ "Empty-Reply" : nl_packet_name(nlp->packet_type),
+ nlp->packet_type,
+ msg->seq, msg->ack, msg->len);
+ }
+}
+
+static void probe_drbd_actlog(struct drbd_conf *mdev, sector_t sector, char* msg)
+{
+ unsigned int enr = (sector >> (AL_EXTENT_SHIFT-9));
+
+ if (!is_mdev_trace(mdev, TRACE_LVL_ALWAYS))
+ return;
+
+ dev_info(DEV, "%s (sec=%llus, al_enr=%u, rs_enr=%d)\n",
+ msg, (unsigned long long) sector, enr,
+ (int)BM_SECT_TO_EXT(sector));
+}
+
+/**
+ * drbd_print_buffer() - Hexdump arbitrary binary data into a buffer
+ * @prefix: String is output at the beginning of each line output.
+ * @flags: Currently only defined flag: DBGPRINT_BUFFADDR; if set, each
+ * line starts with the virtual address of the line being
+ * output. If clear, each line starts with the offset from the
+ * beginning of the buffer.
+ * @size: Indicates the size of each entry in the buffer. Supported
+ * values are sizeof(char), sizeof(short) and sizeof(int)
+ * @buffer: Start address of buffer
+ * @buffer_va: Virtual address of start of buffer (normally the same
+ * as Buffer, but having it separate allows it to hold
+ * file address for example)
+ * @length: length of buffer
+ */
+static void drbd_print_buffer(const char *prefix, unsigned int flags, int size,
+ const void *buffer, const void *buffer_va,
+ unsigned int length)
+
+#define LINE_SIZE 16
+#define LINE_ENTRIES (int)(LINE_SIZE/size)
+{
+ const unsigned char *pstart;
+ const unsigned char *pstart_va;
+ const unsigned char *pend;
+ char bytes_str[LINE_SIZE*3+8], ascii_str[LINE_SIZE+8];
+ char *pbytes = bytes_str, *pascii = ascii_str;
+ int offset = 0;
+ long sizemask;
+ int field_width;
+ int index;
+ const unsigned char *pend_str;
+ const unsigned char *p;
+ int count;
+
+ /* verify size parameter */
+ if (size != sizeof(char) &&
+ size != sizeof(short) &&
+ size != sizeof(int)) {
+ printk(KERN_DEBUG "drbd_print_buffer: "
+ "ERROR invalid size %d\n", size);
+ return;
+ }
+
+ sizemask = size-1;
+ field_width = size*2;
+
+ /* Adjust start/end to be on appropriate boundary for size */
+ buffer = (const char *)((long)buffer & ~sizemask);
+ pend = (const unsigned char *)
+ (((long)buffer + length + sizemask) & ~sizemask);
+
+ if (flags & DBGPRINT_BUFFADDR) {
+ /* Move start back to nearest multiple of line size,
+ * if printing address. This results in nicely formatted output
+ * with addresses being on line size (16) byte boundaries */
+ pstart = (const unsigned char *)((long)buffer & ~(LINE_SIZE-1));
+ } else {
+ pstart = (const unsigned char *)buffer;
+ }
+
+ /* Set value of start VA to print if addresses asked for */
+ pstart_va = (const unsigned char *)buffer_va
+ - ((const unsigned char *)buffer-pstart);
+
+ /* Calculate end position to nicely align right hand side */
+ pend_str = pstart + (((pend-pstart) + LINE_SIZE-1) & ~(LINE_SIZE-1));
+
+ /* Init strings */
+ *pbytes = *pascii = '\0';
+
+ /* Start at beginning of first line */
+ p = pstart;
+ count = 0;
+
+ while (p < pend_str) {
+ if (p < (const unsigned char *)buffer || p >= pend) {
+ /* Before start of buffer or after end- print spaces */
+ pbytes += sprintf(pbytes, "%*c ", field_width, ' ');
+ pascii += sprintf(pascii, "%*c", size, ' ');
+ p += size;
+ } else {
+ /* Add hex and ascii to strings */
+ int val;
+ switch (size) {
+ default:
+ case 1:
+ val = *(unsigned char *)p;
+ break;
+ case 2:
+ val = *(unsigned short *)p;
+ break;
+ case 4:
+ val = *(unsigned int *)p;
+ break;
+ }
+
+ pbytes += sprintf(pbytes, "%0*x ", field_width, val);
+
+ for (index = size; index; index--) {
+ *pascii++ = isprint(*p) ? *p : '.';
+ p++;
+ }
+ }
+
+ count++;
+
+ if (count == LINE_ENTRIES || p >= pend_str) {
+ /* Null terminate and print record */
+ *pascii = '\0';
+ printk(KERN_DEBUG "%s%8.8lx: %*s|%*s|\n",
+ prefix,
+ (flags & DBGPRINT_BUFFADDR)
+ ? (long)pstart_va:(long)offset,
+ LINE_ENTRIES*(field_width+1), bytes_str,
+ LINE_SIZE, ascii_str);
+
+ /* Move onto next line */
+ pstart_va += (p-pstart);
+ pstart = p;
+ count = 0;
+ offset += LINE_SIZE;
+
+ /* Re-init strings */
+ pbytes = bytes_str;
+ pascii = ascii_str;
+ *pbytes = *pascii = '\0';
+ }
+ }
+}
+
+static void probe_drbd_resync(struct drbd_conf *mdev, int level, const char *fmt, va_list args)
+{
+ char str[256];
+
+ if (!is_mdev_trace(mdev, level))
+ return;
+
+ if (vsnprintf(str, 256, fmt, args) >= 256)
+ str[255] = 0;
+
+ printk(KERN_INFO "%s %s: %s", dev_driver_string(disk_to_dev(mdev->vdisk)),
+ dev_name(disk_to_dev(mdev->vdisk)), str);
+}
+
+static void probe_drbd_bio(struct drbd_conf *mdev, const char *pfx, struct bio *bio, int complete,
+ struct drbd_request *r)
+{
+#if defined(CONFIG_LBDAF) || defined(CONFIG_LBD)
+#define SECTOR_FORMAT "%Lx"
+#else
+#define SECTOR_FORMAT "%lx"
+#endif
+#define SECTOR_SHIFT 9
+
+ unsigned long lowaddr = (unsigned long)(bio->bi_sector << SECTOR_SHIFT);
+ char *faddr = (char *)(lowaddr);
+ char rb[sizeof(void *)*2+6] = { 0, };
+ struct bio_vec *bvec;
+ int segno;
+
+ const int rw = bio->bi_rw;
+ const int biorw = (rw & (RW_MASK|RWA_MASK));
+ const int biobarrier = (rw & (1<<BIO_RW_BARRIER));
+ const int biosync = (rw & ((1<<BIO_RW_UNPLUG) | (1<<BIO_RW_SYNCIO)));
+
+ if (!is_mdev_trace(mdev, TRACE_LVL_ALWAYS))
+ return;
+
+ if (r)
+ sprintf(rb, "Req:%p ", r);
+
+ dev_info(DEV, "%s %s:%s%s%s Bio:%p %s- %soffset " SECTOR_FORMAT ", size %x\n",
+ complete ? "<<<" : ">>>",
+ pfx,
+ biorw == WRITE ? "Write" : "Read",
+ biobarrier ? " : B" : "",
+ biosync ? " : S" : "",
+ bio,
+ rb,
+ complete ? (bio_flagged(bio, BIO_UPTODATE) ? "Success, " : "Failed, ") : "",
+ bio->bi_sector << SECTOR_SHIFT,
+ bio->bi_size);
+
+ if (trace_level >= TRACE_LVL_METRICS &&
+ ((biorw == WRITE) ^ complete)) {
+ printk(KERN_DEBUG " ind page offset length\n");
+ __bio_for_each_segment(bvec, bio, segno, 0) {
+ printk(KERN_DEBUG " [%d] %p %8.8x %8.8x\n", segno,
+ bvec->bv_page, bvec->bv_offset, bvec->bv_len);
+
+ if (trace_level >= TRACE_LVL_ALL) {
+ char *bvec_buf;
+ unsigned long flags;
+
+ bvec_buf = bvec_kmap_irq(bvec, &flags);
+
+ drbd_print_buffer(" ", DBGPRINT_BUFFADDR, 1,
+ bvec_buf,
+ faddr,
+ (bvec->bv_len <= 0x80)
+ ? bvec->bv_len : 0x80);
+
+ bvec_kunmap_irq(bvec_buf, &flags);
+
+ if (bvec->bv_len > 0x40)
+ printk(KERN_DEBUG " ....\n");
+
+ faddr += bvec->bv_len;
+ }
+ }
+ }
+}
+
+static void probe_drbd_req(struct drbd_request *req, enum drbd_req_event what, char *msg)
+{
+ static const char *rq_event_names[] = {
+ [created] = "created",
+ [to_be_send] = "to_be_send",
+ [to_be_submitted] = "to_be_submitted",
+ [queue_for_net_write] = "queue_for_net_write",
+ [queue_for_net_read] = "queue_for_net_read",
+ [send_canceled] = "send_canceled",
+ [send_failed] = "send_failed",
+ [handed_over_to_network] = "handed_over_to_network",
+ [connection_lost_while_pending] =
+ "connection_lost_while_pending",
+ [recv_acked_by_peer] = "recv_acked_by_peer",
+ [write_acked_by_peer] = "write_acked_by_peer",
+ [neg_acked] = "neg_acked",
+ [conflict_discarded_by_peer] = "conflict_discarded_by_peer",
+ [barrier_acked] = "barrier_acked",
+ [data_received] = "data_received",
+ [read_completed_with_error] = "read_completed_with_error",
+ [read_ahead_completed_with_error] = "reada_completed_with_error",
+ [write_completed_with_error] = "write_completed_with_error",
+ [completed_ok] = "completed_ok",
+ };
+
+ struct drbd_conf *mdev = req->mdev;
+
+ const int rw = (req->master_bio == NULL ||
+ bio_data_dir(req->master_bio) == WRITE) ?
+ 'W' : 'R';
+ const unsigned long s = req->rq_state;
+
+ if (what != nothing) {
+ dev_info(DEV, "__req_mod(%p %c ,%s)\n", req, rw, rq_event_names[what]);
+ } else {
+ dev_info(DEV, "%s %p %c L%c%c%cN%c%c%c%c%c %u (%llus +%u) %s\n",
+ msg, req, rw,
+ s & RQ_LOCAL_PENDING ? 'p' : '-',
+ s & RQ_LOCAL_COMPLETED ? 'c' : '-',
+ s & RQ_LOCAL_OK ? 'o' : '-',
+ s & RQ_NET_PENDING ? 'p' : '-',
+ s & RQ_NET_QUEUED ? 'q' : '-',
+ s & RQ_NET_SENT ? 's' : '-',
+ s & RQ_NET_DONE ? 'd' : '-',
+ s & RQ_NET_OK ? 'o' : '-',
+ req->epoch,
+ (unsigned long long)req->sector,
+ req->size,
+ drbd_conn_str(mdev->state.conn));
+ }
+}
+
+
+#define drbd_peer_str drbd_role_str
+#define drbd_pdsk_str drbd_disk_str
+
+#define PSM(A) \
+do { \
+ if (mask.A) { \
+ int i = snprintf(p, len, " " #A "( %s )", \
+ drbd_##A##_str(val.A)); \
+ if (i >= len) \
+ return op; \
+ p += i; \
+ len -= i; \
+ } \
+} while (0)
+
+static char *dump_st(char *p, int len, union drbd_state mask, union drbd_state val)
+{
+ char *op = p;
+ *p = '\0';
+ PSM(role);
+ PSM(peer);
+ PSM(conn);
+ PSM(disk);
+ PSM(pdsk);
+
+ return op;
+}
+
+#define INFOP(fmt, args...) \
+do { \
+ if (trace_level >= TRACE_LVL_ALL) { \
+ dev_info(DEV, "%s:%d: %s [%d] %s %s " fmt , \
+ file, line, current->comm, current->pid, \
+ sockname, recv ? "<<<" : ">>>" , \
+ ## args); \
+ } else { \
+ dev_info(DEV, "%s %s " fmt, sockname, \
+ recv ? "<<<" : ">>>" , \
+ ## args); \
+ } \
+} while (0)
+
+static char *_dump_block_id(u64 block_id, char *buff)
+{
+ if (is_syncer_block_id(block_id))
+ strcpy(buff, "SyncerId");
+ else
+ sprintf(buff, "%llx", (unsigned long long)block_id);
+
+ return buff;
+}
+
+static void probe_drbd_packet(struct drbd_conf *mdev, struct socket *sock,
+ int recv, union p_polymorph *p, char *file, int line)
+{
+ char *sockname = sock == mdev->meta.socket ? "meta" : "data";
+ int cmd = (recv == 2) ? p->header.command : be16_to_cpu(p->header.command);
+ char tmp[300];
+ union drbd_state m, v;
+
+ switch (cmd) {
+ case P_HAND_SHAKE:
+ INFOP("%s (protocol %u-%u)\n", cmdname(cmd),
+ be32_to_cpu(p->handshake.protocol_min),
+ be32_to_cpu(p->handshake.protocol_max));
+ break;
+
+ case P_BITMAP: /* don't report this */
+ case P_COMPRESSED_BITMAP: /* don't report this */
+ break;
+
+ case P_DATA:
+ INFOP("%s (sector %llus, id %s, seq %u, f %x)\n", cmdname(cmd),
+ (unsigned long long)be64_to_cpu(p->data.sector),
+ _dump_block_id(p->data.block_id, tmp),
+ be32_to_cpu(p->data.seq_num),
+ be32_to_cpu(p->data.dp_flags)
+ );
+ break;
+
+ case P_DATA_REPLY:
+ case P_RS_DATA_REPLY:
+ INFOP("%s (sector %llus, id %s)\n", cmdname(cmd),
+ (unsigned long long)be64_to_cpu(p->data.sector),
+ _dump_block_id(p->data.block_id, tmp)
+ );
+ break;
+
+ case P_RECV_ACK:
+ case P_WRITE_ACK:
+ case P_RS_WRITE_ACK:
+ case P_DISCARD_ACK:
+ case P_NEG_ACK:
+ case P_NEG_RS_DREPLY:
+ INFOP("%s (sector %llus, size %u, id %s, seq %u)\n",
+ cmdname(cmd),
+ (long long)be64_to_cpu(p->block_ack.sector),
+ be32_to_cpu(p->block_ack.blksize),
+ _dump_block_id(p->block_ack.block_id, tmp),
+ be32_to_cpu(p->block_ack.seq_num)
+ );
+ break;
+
+ case P_DATA_REQUEST:
+ case P_RS_DATA_REQUEST:
+ INFOP("%s (sector %llus, size %u, id %s)\n", cmdname(cmd),
+ (long long)be64_to_cpu(p->block_req.sector),
+ be32_to_cpu(p->block_req.blksize),
+ _dump_block_id(p->block_req.block_id, tmp)
+ );
+ break;
+
+ case P_BARRIER:
+ case P_BARRIER_ACK:
+ INFOP("%s (barrier %u)\n", cmdname(cmd), p->barrier.barrier);
+ break;
+
+ case P_SYNC_PARAM:
+ case P_SYNC_PARAM89:
+ INFOP("%s (rate %u, verify-alg \"%.64s\", csums-alg \"%.64s\")\n",
+ cmdname(cmd), be32_to_cpu(p->rs_param_89.rate),
+ p->rs_param_89.verify_alg, p->rs_param_89.csums_alg);
+ break;
+
+ case P_UUIDS:
+ INFOP("%s Curr:%016llX, Bitmap:%016llX, "
+ "HisSt:%016llX, HisEnd:%016llX\n",
+ cmdname(cmd),
+ (unsigned long long)be64_to_cpu(p->uuids.uuid[UI_CURRENT]),
+ (unsigned long long)be64_to_cpu(p->uuids.uuid[UI_BITMAP]),
+ (unsigned long long)be64_to_cpu(p->uuids.uuid[UI_HISTORY_START]),
+ (unsigned long long)be64_to_cpu(p->uuids.uuid[UI_HISTORY_END]));
+ break;
+
+ case P_SIZES:
+ INFOP("%s (d %lluMiB, u %lluMiB, c %lldMiB, "
+ "max bio %x, q order %x)\n",
+ cmdname(cmd),
+ (long long)(be64_to_cpu(p->sizes.d_size)>>(20-9)),
+ (long long)(be64_to_cpu(p->sizes.u_size)>>(20-9)),
+ (long long)(be64_to_cpu(p->sizes.c_size)>>(20-9)),
+ be32_to_cpu(p->sizes.max_segment_size),
+ be32_to_cpu(p->sizes.queue_order_type));
+ break;
+
+ case P_STATE:
+ v.i = be32_to_cpu(p->state.state);
+ m.i = 0xffffffff;
+ dump_st(tmp, sizeof(tmp), m, v);
+ INFOP("%s (s %x {%s})\n", cmdname(cmd), v.i, tmp);
+ break;
+
+ case P_STATE_CHG_REQ:
+ m.i = be32_to_cpu(p->req_state.mask);
+ v.i = be32_to_cpu(p->req_state.val);
+ dump_st(tmp, sizeof(tmp), m, v);
+ INFOP("%s (m %x v %x {%s})\n", cmdname(cmd), m.i, v.i, tmp);
+ break;
+
+ case P_STATE_CHG_REPLY:
+ INFOP("%s (ret %x)\n", cmdname(cmd),
+ be32_to_cpu(p->req_state_reply.retcode));
+ break;
+
+ case P_PING:
+ case P_PING_ACK:
+ /*
+ * Dont trace pings at summary level
+ */
+ if (trace_level < TRACE_LVL_ALL)
+ break;
+ /* fall through... */
+ default:
+ INFOP("%s (%u)\n", cmdname(cmd), cmd);
+ break;
+ }
+}
+
+
+static int __init drbd_trace_init(void)
+{
+ int ret;
+
+ if (trace_mask & TRACE_UNPLUG) {
+ ret = register_trace_drbd_unplug(probe_drbd_unplug);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_UUID) {
+ ret = register_trace_drbd_uuid(probe_drbd_uuid);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_EE) {
+ ret = register_trace_drbd_ee(probe_drbd_ee);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_PACKET) {
+ ret = register_trace_drbd_packet(probe_drbd_packet);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_MD_IO) {
+ ret = register_trace_drbd_md_io(probe_drbd_md_io);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_EPOCH) {
+ ret = register_trace_drbd_epoch(probe_drbd_epoch);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_NL) {
+ ret = register_trace_drbd_netlink(probe_drbd_netlink);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_AL_EXT) {
+ ret = register_trace_drbd_actlog(probe_drbd_actlog);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_RQ) {
+ ret = register_trace_drbd_bio(probe_drbd_bio);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_INT_RQ) {
+ ret = register_trace_drbd_req(probe_drbd_req);
+ WARN_ON(ret);
+ }
+ if (trace_mask & TRACE_RESYNC) {
+ ret = register_trace__drbd_resync(probe_drbd_resync);
+ WARN_ON(ret);
+ }
+ return 0;
+}
+
+module_init(drbd_trace_init);
+
+static void __exit drbd_trace_exit(void)
+{
+ if (trace_mask & TRACE_UNPLUG)
+ unregister_trace_drbd_unplug(probe_drbd_unplug);
+ if (trace_mask & TRACE_UUID)
+ unregister_trace_drbd_uuid(probe_drbd_uuid);
+ if (trace_mask & TRACE_EE)
+ unregister_trace_drbd_ee(probe_drbd_ee);
+ if (trace_mask & TRACE_PACKET)
+ unregister_trace_drbd_packet(probe_drbd_packet);
+ if (trace_mask & TRACE_MD_IO)
+ unregister_trace_drbd_md_io(probe_drbd_md_io);
+ if (trace_mask & TRACE_EPOCH)
+ unregister_trace_drbd_epoch(probe_drbd_epoch);
+ if (trace_mask & TRACE_NL)
+ unregister_trace_drbd_netlink(probe_drbd_netlink);
+ if (trace_mask & TRACE_AL_EXT)
+ unregister_trace_drbd_actlog(probe_drbd_actlog);
+ if (trace_mask & TRACE_RQ)
+ unregister_trace_drbd_bio(probe_drbd_bio);
+ if (trace_mask & TRACE_INT_RQ)
+ unregister_trace_drbd_req(probe_drbd_req);
+ if (trace_mask & TRACE_RESYNC)
+ unregister_trace__drbd_resync(probe_drbd_resync);
+
+ tracepoint_synchronize_unregister();
+}
+
+module_exit(drbd_trace_exit);
diff --git a/drivers/block/drbd/drbd_tracing.h b/drivers/block/drbd/drbd_tracing.h
new file mode 100644
index 000000000000..c4531a137f65
--- /dev/null
+++ b/drivers/block/drbd/drbd_tracing.h
@@ -0,0 +1,87 @@
+/*
+ drbd_tracing.h
+
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2003-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 2003-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+ Copyright (C) 2003-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+ drbd 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.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT 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 drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#ifndef DRBD_TRACING_H
+#define DRBD_TRACING_H
+
+#include <linux/tracepoint.h>
+#include "drbd_int.h"
+#include "drbd_req.h"
+
+enum {
+ TRACE_LVL_ALWAYS = 0,
+ TRACE_LVL_SUMMARY,
+ TRACE_LVL_METRICS,
+ TRACE_LVL_ALL,
+ TRACE_LVL_MAX
+};
+
+DECLARE_TRACE(drbd_unplug,
+ TP_PROTO(struct drbd_conf *mdev, char* msg),
+ TP_ARGS(mdev, msg));
+
+DECLARE_TRACE(drbd_uuid,
+ TP_PROTO(struct drbd_conf *mdev, enum drbd_uuid_index index),
+ TP_ARGS(mdev, index));
+
+DECLARE_TRACE(drbd_ee,
+ TP_PROTO(struct drbd_conf *mdev, struct drbd_epoch_entry *e, char* msg),
+ TP_ARGS(mdev, e, msg));
+
+DECLARE_TRACE(drbd_md_io,
+ TP_PROTO(struct drbd_conf *mdev, int rw, struct drbd_backing_dev *bdev),
+ TP_ARGS(mdev, rw, bdev));
+
+DECLARE_TRACE(drbd_epoch,
+ TP_PROTO(struct drbd_conf *mdev, struct drbd_epoch *epoch, enum epoch_event ev),
+ TP_ARGS(mdev, epoch, ev));
+
+DECLARE_TRACE(drbd_netlink,
+ TP_PROTO(void *data, int is_req),
+ TP_ARGS(data, is_req));
+
+DECLARE_TRACE(drbd_actlog,
+ TP_PROTO(struct drbd_conf *mdev, sector_t sector, char* msg),
+ TP_ARGS(mdev, sector, msg));
+
+DECLARE_TRACE(drbd_bio,
+ TP_PROTO(struct drbd_conf *mdev, const char *pfx, struct bio *bio, int complete,
+ struct drbd_request *r),
+ TP_ARGS(mdev, pfx, bio, complete, r));
+
+DECLARE_TRACE(drbd_req,
+ TP_PROTO(struct drbd_request *req, enum drbd_req_event what, char *msg),
+ TP_ARGS(req, what, msg));
+
+DECLARE_TRACE(drbd_packet,
+ TP_PROTO(struct drbd_conf *mdev, struct socket *sock,
+ int recv, union p_polymorph *p, char *file, int line),
+ TP_ARGS(mdev, sock, recv, p, file, line));
+
+DECLARE_TRACE(_drbd_resync,
+ TP_PROTO(struct drbd_conf *mdev, int level, const char *fmt, va_list args),
+ TP_ARGS(mdev, level, fmt, args));
+
+#endif
diff --git a/drivers/block/drbd/drbd_vli.h b/drivers/block/drbd/drbd_vli.h
new file mode 100644
index 000000000000..fc824006e721
--- /dev/null
+++ b/drivers/block/drbd/drbd_vli.h
@@ -0,0 +1,351 @@
+/*
+-*- linux-c -*-
+ drbd_receiver.c
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+ Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+ drbd 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.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT 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 drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _DRBD_VLI_H
+#define _DRBD_VLI_H
+
+/*
+ * At a granularity of 4KiB storage represented per bit,
+ * and stroage sizes of several TiB,
+ * and possibly small-bandwidth replication,
+ * the bitmap transfer time can take much too long,
+ * if transmitted in plain text.
+ *
+ * We try to reduce the transfered bitmap information
+ * by encoding runlengths of bit polarity.
+ *
+ * We never actually need to encode a "zero" (runlengths are positive).
+ * But then we have to store the value of the first bit.
+ * The first bit of information thus shall encode if the first runlength
+ * gives the number of set or unset bits.
+ *
+ * We assume that large areas are either completely set or unset,
+ * which gives good compression with any runlength method,
+ * even when encoding the runlength as fixed size 32bit/64bit integers.
+ *
+ * Still, there may be areas where the polarity flips every few bits,
+ * and encoding the runlength sequence of those areas with fix size
+ * integers would be much worse than plaintext.
+ *
+ * We want to encode small runlength values with minimum code length,
+ * while still being able to encode a Huge run of all zeros.
+ *
+ * Thus we need a Variable Length Integer encoding, VLI.
+ *
+ * For some cases, we produce more code bits than plaintext input.
+ * We need to send incompressible chunks as plaintext, skip over them
+ * and then see if the next chunk compresses better.
+ *
+ * We don't care too much about "excellent" compression ratio for large
+ * runlengths (all set/all clear): whether we achieve a factor of 100
+ * or 1000 is not that much of an issue.
+ * We do not want to waste too much on short runlengths in the "noisy"
+ * parts of the bitmap, though.
+ *
+ * There are endless variants of VLI, we experimented with:
+ * * simple byte-based
+ * * various bit based with different code word length.
+ *
+ * To avoid yet an other configuration parameter (choice of bitmap compression
+ * algorithm) which was difficult to explain and tune, we just chose the one
+ * variant that turned out best in all test cases.
+ * Based on real world usage patterns, with device sizes ranging from a few GiB
+ * to several TiB, file server/mailserver/webserver/mysql/postgress,
+ * mostly idle to really busy, the all time winner (though sometimes only
+ * marginally better) is:
+ */
+
+/*
+ * encoding is "visualised" as
+ * __little endian__ bitstream, least significant bit first (left most)
+ *
+ * this particular encoding is chosen so that the prefix code
+ * starts as unary encoding the level, then modified so that
+ * 10 levels can be described in 8bit, with minimal overhead
+ * for the smaller levels.
+ *
+ * Number of data bits follow fibonacci sequence, with the exception of the
+ * last level (+1 data bit, so it makes 64bit total). The only worse code when
+ * encoding bit polarity runlength is 1 plain bits => 2 code bits.
+prefix data bits max val Nº data bits
+0 x 0x2 1
+10 x 0x4 1
+110 xx 0x8 2
+1110 xxx 0x10 3
+11110 xxx xx 0x30 5
+111110 xx xxxxxx 0x130 8
+11111100 xxxxxxxx xxxxx 0x2130 13
+11111110 xxxxxxxx xxxxxxxx xxxxx 0x202130 21
+11111101 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xx 0x400202130 34
+11111111 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx 56
+ * maximum encodable value: 0x100000400202130 == 2**56 + some */
+
+/* compression "table":
+ transmitted x 0.29
+ as plaintext x ........................
+ x ........................
+ x ........................
+ x 0.59 0.21........................
+ x ........................................................
+ x .. c ...................................................
+ x 0.44.. o ...................................................
+ x .......... d ...................................................
+ x .......... e ...................................................
+ X............. ...................................................
+ x.............. b ...................................................
+2.0x............... i ...................................................
+ #X................ t ...................................................
+ #................. s ........................... plain bits ..........
+-+-----------------------------------------------------------------------
+ 1 16 32 64
+*/
+
+/* LEVEL: (total bits, prefix bits, prefix value),
+ * sorted ascending by number of total bits.
+ * The rest of the code table is calculated at compiletime from this. */
+
+/* fibonacci data 1, 1, ... */
+#define VLI_L_1_1() do { \
+ LEVEL( 2, 1, 0x00); \
+ LEVEL( 3, 2, 0x01); \
+ LEVEL( 5, 3, 0x03); \
+ LEVEL( 7, 4, 0x07); \
+ LEVEL(10, 5, 0x0f); \
+ LEVEL(14, 6, 0x1f); \
+ LEVEL(21, 8, 0x3f); \
+ LEVEL(29, 8, 0x7f); \
+ LEVEL(42, 8, 0xbf); \
+ LEVEL(64, 8, 0xff); \
+ } while (0)
+
+/* finds a suitable level to decode the least significant part of in.
+ * returns number of bits consumed.
+ *
+ * BUG() for bad input, as that would mean a buggy code table. */
+static inline int vli_decode_bits(u64 *out, const u64 in)
+{
+ u64 adj = 1;
+
+#define LEVEL(t,b,v) \
+ do { \
+ if ((in & ((1 << b) -1)) == v) { \
+ *out = ((in & ((~0ULL) >> (64-t))) >> b) + adj; \
+ return t; \
+ } \
+ adj += 1ULL << (t - b); \
+ } while (0)
+
+ VLI_L_1_1();
+
+ /* NOT REACHED, if VLI_LEVELS code table is defined properly */
+ BUG();
+#undef LEVEL
+}
+
+/* return number of code bits needed,
+ * or negative error number */
+static inline int __vli_encode_bits(u64 *out, const u64 in)
+{
+ u64 max = 0;
+ u64 adj = 1;
+
+ if (in == 0)
+ return -EINVAL;
+
+#define LEVEL(t,b,v) do { \
+ max += 1ULL << (t - b); \
+ if (in <= max) { \
+ if (out) \
+ *out = ((in - adj) << b) | v; \
+ return t; \
+ } \
+ adj = max + 1; \
+ } while (0)
+
+ VLI_L_1_1();
+
+ return -EOVERFLOW;
+#undef LEVEL
+}
+
+#undef VLI_L_1_1
+
+/* code from here down is independend of actually used bit code */
+
+/*
+ * Code length is determined by some unique (e.g. unary) prefix.
+ * This encodes arbitrary bit length, not whole bytes: we have a bit-stream,
+ * not a byte stream.
+ */
+
+/* for the bitstream, we need a cursor */
+struct bitstream_cursor {
+ /* the current byte */
+ u8 *b;
+ /* the current bit within *b, nomalized: 0..7 */
+ unsigned int bit;
+};
+
+/* initialize cursor to point to first bit of stream */
+static inline void bitstream_cursor_reset(struct bitstream_cursor *cur, void *s)
+{
+ cur->b = s;
+ cur->bit = 0;
+}
+
+/* advance cursor by that many bits; maximum expected input value: 64,
+ * but depending on VLI implementation, it may be more. */
+static inline void bitstream_cursor_advance(struct bitstream_cursor *cur, unsigned int bits)
+{
+ bits += cur->bit;
+ cur->b = cur->b + (bits >> 3);
+ cur->bit = bits & 7;
+}
+
+/* the bitstream itself knows its length */
+struct bitstream {
+ struct bitstream_cursor cur;
+ unsigned char *buf;
+ size_t buf_len; /* in bytes */
+
+ /* for input stream:
+ * number of trailing 0 bits for padding
+ * total number of valid bits in stream: buf_len * 8 - pad_bits */
+ unsigned int pad_bits;
+};
+
+static inline void bitstream_init(struct bitstream *bs, void *s, size_t len, unsigned int pad_bits)
+{
+ bs->buf = s;
+ bs->buf_len = len;
+ bs->pad_bits = pad_bits;
+ bitstream_cursor_reset(&bs->cur, bs->buf);
+}
+
+static inline void bitstream_rewind(struct bitstream *bs)
+{
+ bitstream_cursor_reset(&bs->cur, bs->buf);
+ memset(bs->buf, 0, bs->buf_len);
+}
+
+/* Put (at most 64) least significant bits of val into bitstream, and advance cursor.
+ * Ignores "pad_bits".
+ * Returns zero if bits == 0 (nothing to do).
+ * Returns number of bits used if successful.
+ *
+ * If there is not enough room left in bitstream,
+ * leaves bitstream unchanged and returns -ENOBUFS.
+ */
+static inline int bitstream_put_bits(struct bitstream *bs, u64 val, const unsigned int bits)
+{
+ unsigned char *b = bs->cur.b;
+ unsigned int tmp;
+
+ if (bits == 0)
+ return 0;
+
+ if ((bs->cur.b + ((bs->cur.bit + bits -1) >> 3)) - bs->buf >= bs->buf_len)
+ return -ENOBUFS;
+
+ /* paranoia: strip off hi bits; they should not be set anyways. */
+ if (bits < 64)
+ val &= ~0ULL >> (64 - bits);
+
+ *b++ |= (val & 0xff) << bs->cur.bit;
+
+ for (tmp = 8 - bs->cur.bit; tmp < bits; tmp += 8)
+ *b++ |= (val >> tmp) & 0xff;
+
+ bitstream_cursor_advance(&bs->cur, bits);
+ return bits;
+}
+
+/* Fetch (at most 64) bits from bitstream into *out, and advance cursor.
+ *
+ * If more than 64 bits are requested, returns -EINVAL and leave *out unchanged.
+ *
+ * If there are less than the requested number of valid bits left in the
+ * bitstream, still fetches all available bits.
+ *
+ * Returns number of actually fetched bits.
+ */
+static inline int bitstream_get_bits(struct bitstream *bs, u64 *out, int bits)
+{
+ u64 val;
+ unsigned int n;
+
+ if (bits > 64)
+ return -EINVAL;
+
+ if (bs->cur.b + ((bs->cur.bit + bs->pad_bits + bits -1) >> 3) - bs->buf >= bs->buf_len)
+ bits = ((bs->buf_len - (bs->cur.b - bs->buf)) << 3)
+ - bs->cur.bit - bs->pad_bits;
+
+ if (bits == 0) {
+ *out = 0;
+ return 0;
+ }
+
+ /* get the high bits */
+ val = 0;
+ n = (bs->cur.bit + bits + 7) >> 3;
+ /* n may be at most 9, if cur.bit + bits > 64 */
+ /* which means this copies at most 8 byte */
+ if (n) {
+ memcpy(&val, bs->cur.b+1, n - 1);
+ val = le64_to_cpu(val) << (8 - bs->cur.bit);
+ }
+
+ /* we still need the low bits */
+ val |= bs->cur.b[0] >> bs->cur.bit;
+
+ /* and mask out bits we don't want */
+ val &= ~0ULL >> (64 - bits);
+
+ bitstream_cursor_advance(&bs->cur, bits);
+ *out = val;
+
+ return bits;
+}
+
+/* encodes @in as vli into @bs;
+
+ * return values
+ * > 0: number of bits successfully stored in bitstream
+ * -ENOBUFS @bs is full
+ * -EINVAL input zero (invalid)
+ * -EOVERFLOW input too large for this vli code (invalid)
+ */
+static inline int vli_encode_bits(struct bitstream *bs, u64 in)
+{
+ u64 code = code;
+ int bits = __vli_encode_bits(&code, in);
+
+ if (bits <= 0)
+ return bits;
+
+ return bitstream_put_bits(bs, code, bits);
+}
+
+#endif
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
new file mode 100644
index 000000000000..ed8796f1112d
--- /dev/null
+++ b/drivers/block/drbd/drbd_worker.c
@@ -0,0 +1,1512 @@
+/*
+ drbd_worker.c
+
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+ Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+ drbd 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.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT 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 drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/drbd.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/wait.h>
+#include <linux/mm.h>
+#include <linux/memcontrol.h>
+#include <linux/mm_inline.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/scatterlist.h>
+
+#include "drbd_int.h"
+#include "drbd_req.h"
+
+#define SLEEP_TIME (HZ/10)
+
+static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int cancel);
+
+
+
+/* defined here:
+ drbd_md_io_complete
+ drbd_endio_write_sec
+ drbd_endio_read_sec
+ drbd_endio_pri
+
+ * more endio handlers:
+ atodb_endio in drbd_actlog.c
+ drbd_bm_async_io_complete in drbd_bitmap.c
+
+ * For all these callbacks, note the following:
+ * The callbacks will be called in irq context by the IDE drivers,
+ * and in Softirqs/Tasklets/BH context by the SCSI drivers.
+ * Try to get the locking right :)
+ *
+ */
+
+
+/* About the global_state_lock
+ Each state transition on an device holds a read lock. In case we have
+ to evaluate the sync after dependencies, we grab a write lock, because
+ we need stable states on all devices for that. */
+rwlock_t global_state_lock;
+
+/* used for synchronous meta data and bitmap IO
+ * submitted by drbd_md_sync_page_io()
+ */
+void drbd_md_io_complete(struct bio *bio, int error)
+{
+ struct drbd_md_io *md_io;
+
+ md_io = (struct drbd_md_io *)bio->bi_private;
+ md_io->error = error;
+
+ complete(&md_io->event);
+}
+
+/* reads on behalf of the partner,
+ * "submitted" by the receiver
+ */
+void drbd_endio_read_sec(struct bio *bio, int error) __releases(local)
+{
+ unsigned long flags = 0;
+ struct drbd_epoch_entry *e = NULL;
+ struct drbd_conf *mdev;
+ int uptodate = bio_flagged(bio, BIO_UPTODATE);
+
+ e = bio->bi_private;
+ mdev = e->mdev;
+
+ if (error)
+ dev_warn(DEV, "read: error=%d s=%llus\n", error,
+ (unsigned long long)e->sector);
+ if (!error && !uptodate) {
+ dev_warn(DEV, "read: setting error to -EIO s=%llus\n",
+ (unsigned long long)e->sector);
+ /* strange behavior of some lower level drivers...
+ * fail the request by clearing the uptodate flag,
+ * but do not return any error?! */
+ error = -EIO;
+ }
+
+ D_ASSERT(e->block_id != ID_VACANT);
+
+ spin_lock_irqsave(&mdev->req_lock, flags);
+ mdev->read_cnt += e->size >> 9;
+ list_del(&e->w.list);
+ if (list_empty(&mdev->read_ee))
+ wake_up(&mdev->ee_wait);
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+ drbd_chk_io_error(mdev, error, FALSE);
+ drbd_queue_work(&mdev->data.work, &e->w);
+ put_ldev(mdev);
+}
+
+/* writes on behalf of the partner, or resync writes,
+ * "submitted" by the receiver.
+ */
+void drbd_endio_write_sec(struct bio *bio, int error) __releases(local)
+{
+ unsigned long flags = 0;
+ struct drbd_epoch_entry *e = NULL;
+ struct drbd_conf *mdev;
+ sector_t e_sector;
+ int do_wake;
+ int is_syncer_req;
+ int do_al_complete_io;
+ int uptodate = bio_flagged(bio, BIO_UPTODATE);
+ int is_barrier = bio_rw_flagged(bio, BIO_RW_BARRIER);
+
+ e = bio->bi_private;
+ mdev = e->mdev;
+
+ if (error)
+ dev_warn(DEV, "write: error=%d s=%llus\n", error,
+ (unsigned long long)e->sector);
+ if (!error && !uptodate) {
+ dev_warn(DEV, "write: setting error to -EIO s=%llus\n",
+ (unsigned long long)e->sector);
+ /* strange behavior of some lower level drivers...
+ * fail the request by clearing the uptodate flag,
+ * but do not return any error?! */
+ error = -EIO;
+ }
+
+ /* error == -ENOTSUPP would be a better test,
+ * alas it is not reliable */
+ if (error && is_barrier && e->flags & EE_IS_BARRIER) {
+ drbd_bump_write_ordering(mdev, WO_bdev_flush);
+ spin_lock_irqsave(&mdev->req_lock, flags);
+ list_del(&e->w.list);
+ e->w.cb = w_e_reissue;
+ /* put_ldev actually happens below, once we come here again. */
+ __release(local);
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+ drbd_queue_work(&mdev->data.work, &e->w);
+ return;
+ }
+
+ D_ASSERT(e->block_id != ID_VACANT);
+
+ spin_lock_irqsave(&mdev->req_lock, flags);
+ mdev->writ_cnt += e->size >> 9;
+ is_syncer_req = is_syncer_block_id(e->block_id);
+
+ /* after we moved e to done_ee,
+ * we may no longer access it,
+ * it may be freed/reused already!
+ * (as soon as we release the req_lock) */
+ e_sector = e->sector;
+ do_al_complete_io = e->flags & EE_CALL_AL_COMPLETE_IO;
+
+ list_del(&e->w.list); /* has been on active_ee or sync_ee */
+ list_add_tail(&e->w.list, &mdev->done_ee);
+
+ /* No hlist_del_init(&e->colision) here, we did not send the Ack yet,
+ * neither did we wake possibly waiting conflicting requests.
+ * done from "drbd_process_done_ee" within the appropriate w.cb
+ * (e_end_block/e_end_resync_block) or from _drbd_clear_done_ee */
+
+ do_wake = is_syncer_req
+ ? list_empty(&mdev->sync_ee)
+ : list_empty(&mdev->active_ee);
+
+ if (error)
+ __drbd_chk_io_error(mdev, FALSE);
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+ if (is_syncer_req)
+ drbd_rs_complete_io(mdev, e_sector);
+
+ if (do_wake)
+ wake_up(&mdev->ee_wait);
+
+ if (do_al_complete_io)
+ drbd_al_complete_io(mdev, e_sector);
+
+ wake_asender(mdev);
+ put_ldev(mdev);
+
+}
+
+/* read, readA or write requests on R_PRIMARY coming from drbd_make_request
+ */
+void drbd_endio_pri(struct bio *bio, int error)
+{
+ unsigned long flags;
+ struct drbd_request *req = bio->bi_private;
+ struct drbd_conf *mdev = req->mdev;
+ struct bio_and_error m;
+ enum drbd_req_event what;
+ int uptodate = bio_flagged(bio, BIO_UPTODATE);
+
+ if (error)
+ dev_warn(DEV, "p %s: error=%d\n",
+ bio_data_dir(bio) == WRITE ? "write" : "read", error);
+ if (!error && !uptodate) {
+ dev_warn(DEV, "p %s: setting error to -EIO\n",
+ bio_data_dir(bio) == WRITE ? "write" : "read");
+ /* strange behavior of some lower level drivers...
+ * fail the request by clearing the uptodate flag,
+ * but do not return any error?! */
+ error = -EIO;
+ }
+
+ /* to avoid recursion in __req_mod */
+ if (unlikely(error)) {
+ what = (bio_data_dir(bio) == WRITE)
+ ? write_completed_with_error
+ : (bio_rw(bio) == READA)
+ ? read_completed_with_error
+ : read_ahead_completed_with_error;
+ } else
+ what = completed_ok;
+
+ bio_put(req->private_bio);
+ req->private_bio = ERR_PTR(error);
+
+ spin_lock_irqsave(&mdev->req_lock, flags);
+ __req_mod(req, what, &m);
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+ if (m.bio)
+ complete_master_bio(mdev, &m);
+}
+
+int w_io_error(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ struct drbd_request *req = container_of(w, struct drbd_request, w);
+
+ /* NOTE: mdev->ldev can be NULL by the time we get here! */
+ /* D_ASSERT(mdev->ldev->dc.on_io_error != EP_PASS_ON); */
+
+ /* the only way this callback is scheduled is from _req_may_be_done,
+ * when it is done and had a local write error, see comments there */
+ drbd_req_free(req);
+
+ return TRUE;
+}
+
+int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ struct drbd_request *req = container_of(w, struct drbd_request, w);
+
+ /* We should not detach for read io-error,
+ * but try to WRITE the P_DATA_REPLY to the failed location,
+ * to give the disk the chance to relocate that block */
+
+ spin_lock_irq(&mdev->req_lock);
+ if (cancel ||
+ mdev->state.conn < C_CONNECTED ||
+ mdev->state.pdsk <= D_INCONSISTENT) {
+ _req_mod(req, send_canceled);
+ spin_unlock_irq(&mdev->req_lock);
+ dev_alert(DEV, "WE ARE LOST. Local IO failure, no peer.\n");
+ return 1;
+ }
+ spin_unlock_irq(&mdev->req_lock);
+
+ return w_send_read_req(mdev, w, 0);
+}
+
+int w_resync_inactive(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ ERR_IF(cancel) return 1;
+ dev_err(DEV, "resync inactive, but callback triggered??\n");
+ return 1; /* Simply ignore this! */
+}
+
+void drbd_csum(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio *bio, void *digest)
+{
+ struct hash_desc desc;
+ struct scatterlist sg;
+ struct bio_vec *bvec;
+ int i;
+
+ desc.tfm = tfm;
+ desc.flags = 0;
+
+ sg_init_table(&sg, 1);
+ crypto_hash_init(&desc);
+
+ __bio_for_each_segment(bvec, bio, i, 0) {
+ sg_set_page(&sg, bvec->bv_page, bvec->bv_len, bvec->bv_offset);
+ crypto_hash_update(&desc, &sg, sg.length);
+ }
+ crypto_hash_final(&desc, digest);
+}
+
+static int w_e_send_csum(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
+ int digest_size;
+ void *digest;
+ int ok;
+
+ D_ASSERT(e->block_id == DRBD_MAGIC + 0xbeef);
+
+ if (unlikely(cancel)) {
+ drbd_free_ee(mdev, e);
+ return 1;
+ }
+
+ if (likely(drbd_bio_uptodate(e->private_bio))) {
+ digest_size = crypto_hash_digestsize(mdev->csums_tfm);
+ digest = kmalloc(digest_size, GFP_NOIO);
+ if (digest) {
+ drbd_csum(mdev, mdev->csums_tfm, e->private_bio, digest);
+
+ inc_rs_pending(mdev);
+ ok = drbd_send_drequest_csum(mdev,
+ e->sector,
+ e->size,
+ digest,
+ digest_size,
+ P_CSUM_RS_REQUEST);
+ kfree(digest);
+ } else {
+ dev_err(DEV, "kmalloc() of digest failed.\n");
+ ok = 0;
+ }
+ } else
+ ok = 1;
+
+ drbd_free_ee(mdev, e);
+
+ if (unlikely(!ok))
+ dev_err(DEV, "drbd_send_drequest(..., csum) failed\n");
+ return ok;
+}
+
+#define GFP_TRY (__GFP_HIGHMEM | __GFP_NOWARN)
+
+static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size)
+{
+ struct drbd_epoch_entry *e;
+
+ if (!get_ldev(mdev))
+ return 0;
+
+ /* GFP_TRY, because if there is no memory available right now, this may
+ * be rescheduled for later. It is "only" background resync, after all. */
+ e = drbd_alloc_ee(mdev, DRBD_MAGIC+0xbeef, sector, size, GFP_TRY);
+ if (!e) {
+ put_ldev(mdev);
+ return 2;
+ }
+
+ spin_lock_irq(&mdev->req_lock);
+ list_add(&e->w.list, &mdev->read_ee);
+ spin_unlock_irq(&mdev->req_lock);
+
+ e->private_bio->bi_end_io = drbd_endio_read_sec;
+ e->private_bio->bi_rw = READ;
+ e->w.cb = w_e_send_csum;
+
+ mdev->read_cnt += size >> 9;
+ drbd_generic_make_request(mdev, DRBD_FAULT_RS_RD, e->private_bio);
+
+ return 1;
+}
+
+void resync_timer_fn(unsigned long data)
+{
+ unsigned long flags;
+ struct drbd_conf *mdev = (struct drbd_conf *) data;
+ int queue;
+
+ spin_lock_irqsave(&mdev->req_lock, flags);
+
+ if (likely(!test_and_clear_bit(STOP_SYNC_TIMER, &mdev->flags))) {
+ queue = 1;
+ if (mdev->state.conn == C_VERIFY_S)
+ mdev->resync_work.cb = w_make_ov_request;
+ else
+ mdev->resync_work.cb = w_make_resync_request;
+ } else {
+ queue = 0;
+ mdev->resync_work.cb = w_resync_inactive;
+ }
+
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+ /* harmless race: list_empty outside data.work.q_lock */
+ if (list_empty(&mdev->resync_work.list) && queue)
+ drbd_queue_work(&mdev->data.work, &mdev->resync_work);
+}
+
+int w_make_resync_request(struct drbd_conf *mdev,
+ struct drbd_work *w, int cancel)
+{
+ unsigned long bit;
+ sector_t sector;
+ const sector_t capacity = drbd_get_capacity(mdev->this_bdev);
+ int max_segment_size = queue_max_segment_size(mdev->rq_queue);
+ int number, i, size, pe, mx;
+ int align, queued, sndbuf;
+
+ if (unlikely(cancel))
+ return 1;
+
+ if (unlikely(mdev->state.conn < C_CONNECTED)) {
+ dev_err(DEV, "Confused in w_make_resync_request()! cstate < Connected");
+ return 0;
+ }
+
+ if (mdev->state.conn != C_SYNC_TARGET)
+ dev_err(DEV, "%s in w_make_resync_request\n",
+ drbd_conn_str(mdev->state.conn));
+
+ if (!get_ldev(mdev)) {
+ /* Since we only need to access mdev->rsync a
+ get_ldev_if_state(mdev,D_FAILED) would be sufficient, but
+ to continue resync with a broken disk makes no sense at
+ all */
+ dev_err(DEV, "Disk broke down during resync!\n");
+ mdev->resync_work.cb = w_resync_inactive;
+ return 1;
+ }
+
+ number = SLEEP_TIME * mdev->sync_conf.rate / ((BM_BLOCK_SIZE/1024)*HZ);
+ pe = atomic_read(&mdev->rs_pending_cnt);
+
+ mutex_lock(&mdev->data.mutex);
+ if (mdev->data.socket)
+ mx = mdev->data.socket->sk->sk_rcvbuf / sizeof(struct p_block_req);
+ else
+ mx = 1;
+ mutex_unlock(&mdev->data.mutex);
+
+ /* For resync rates >160MB/sec, allow more pending RS requests */
+ if (number > mx)
+ mx = number;
+
+ /* Limit the number of pending RS requests to no more than the peer's receive buffer */
+ if ((pe + number) > mx) {
+ number = mx - pe;
+ }
+
+ for (i = 0; i < number; i++) {
+ /* Stop generating RS requests, when half of the send buffer is filled */
+ mutex_lock(&mdev->data.mutex);
+ if (mdev->data.socket) {
+ queued = mdev->data.socket->sk->sk_wmem_queued;
+ sndbuf = mdev->data.socket->sk->sk_sndbuf;
+ } else {
+ queued = 1;
+ sndbuf = 0;
+ }
+ mutex_unlock(&mdev->data.mutex);
+ if (queued > sndbuf / 2)
+ goto requeue;
+
+next_sector:
+ size = BM_BLOCK_SIZE;
+ bit = drbd_bm_find_next(mdev, mdev->bm_resync_fo);
+
+ if (bit == -1UL) {
+ mdev->bm_resync_fo = drbd_bm_bits(mdev);
+ mdev->resync_work.cb = w_resync_inactive;
+ put_ldev(mdev);
+ return 1;
+ }
+
+ sector = BM_BIT_TO_SECT(bit);
+
+ if (drbd_try_rs_begin_io(mdev, sector)) {
+ mdev->bm_resync_fo = bit;
+ goto requeue;
+ }
+ mdev->bm_resync_fo = bit + 1;
+
+ if (unlikely(drbd_bm_test_bit(mdev, bit) == 0)) {
+ drbd_rs_complete_io(mdev, sector);
+ goto next_sector;
+ }
+
+#if DRBD_MAX_SEGMENT_SIZE > BM_BLOCK_SIZE
+ /* try to find some adjacent bits.
+ * we stop if we have already the maximum req size.
+ *
+ * Additionally always align bigger requests, in order to
+ * be prepared for all stripe sizes of software RAIDs.
+ *
+ * we _do_ care about the agreed-upon q->max_segment_size
+ * here, as splitting up the requests on the other side is more
+ * difficult. the consequence is, that on lvm and md and other
+ * "indirect" devices, this is dead code, since
+ * q->max_segment_size will be PAGE_SIZE.
+ */
+ align = 1;
+ for (;;) {
+ if (size + BM_BLOCK_SIZE > max_segment_size)
+ break;
+
+ /* Be always aligned */
+ if (sector & ((1<<(align+3))-1))
+ break;
+
+ /* do not cross extent boundaries */
+ if (((bit+1) & BM_BLOCKS_PER_BM_EXT_MASK) == 0)
+ break;
+ /* now, is it actually dirty, after all?
+ * caution, drbd_bm_test_bit is tri-state for some
+ * obscure reason; ( b == 0 ) would get the out-of-band
+ * only accidentally right because of the "oddly sized"
+ * adjustment below */
+ if (drbd_bm_test_bit(mdev, bit+1) != 1)
+ break;
+ bit++;
+ size += BM_BLOCK_SIZE;
+ if ((BM_BLOCK_SIZE << align) <= size)
+ align++;
+ i++;
+ }
+ /* if we merged some,
+ * reset the offset to start the next drbd_bm_find_next from */
+ if (size > BM_BLOCK_SIZE)
+ mdev->bm_resync_fo = bit + 1;
+#endif
+
+ /* adjust very last sectors, in case we are oddly sized */
+ if (sector + (size>>9) > capacity)
+ size = (capacity-sector)<<9;
+ if (mdev->agreed_pro_version >= 89 && mdev->csums_tfm) {
+ switch (read_for_csum(mdev, sector, size)) {
+ case 0: /* Disk failure*/
+ put_ldev(mdev);
+ return 0;
+ case 2: /* Allocation failed */
+ drbd_rs_complete_io(mdev, sector);
+ mdev->bm_resync_fo = BM_SECT_TO_BIT(sector);
+ goto requeue;
+ /* case 1: everything ok */
+ }
+ } else {
+ inc_rs_pending(mdev);
+ if (!drbd_send_drequest(mdev, P_RS_DATA_REQUEST,
+ sector, size, ID_SYNCER)) {
+ dev_err(DEV, "drbd_send_drequest() failed, aborting...\n");
+ dec_rs_pending(mdev);
+ put_ldev(mdev);
+ return 0;
+ }
+ }
+ }
+
+ if (mdev->bm_resync_fo >= drbd_bm_bits(mdev)) {
+ /* last syncer _request_ was sent,
+ * but the P_RS_DATA_REPLY not yet received. sync will end (and
+ * next sync group will resume), as soon as we receive the last
+ * resync data block, and the last bit is cleared.
+ * until then resync "work" is "inactive" ...
+ */
+ mdev->resync_work.cb = w_resync_inactive;
+ put_ldev(mdev);
+ return 1;
+ }
+
+ requeue:
+ mod_timer(&mdev->resync_timer, jiffies + SLEEP_TIME);
+ put_ldev(mdev);
+ return 1;
+}
+
+static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ int number, i, size;
+ sector_t sector;
+ const sector_t capacity = drbd_get_capacity(mdev->this_bdev);
+
+ if (unlikely(cancel))
+ return 1;
+
+ if (unlikely(mdev->state.conn < C_CONNECTED)) {
+ dev_err(DEV, "Confused in w_make_ov_request()! cstate < Connected");
+ return 0;
+ }
+
+ number = SLEEP_TIME*mdev->sync_conf.rate / ((BM_BLOCK_SIZE/1024)*HZ);
+ if (atomic_read(&mdev->rs_pending_cnt) > number)
+ goto requeue;
+
+ number -= atomic_read(&mdev->rs_pending_cnt);
+
+ sector = mdev->ov_position;
+ for (i = 0; i < number; i++) {
+ if (sector >= capacity) {
+ mdev->resync_work.cb = w_resync_inactive;
+ return 1;
+ }
+
+ size = BM_BLOCK_SIZE;
+
+ if (drbd_try_rs_begin_io(mdev, sector)) {
+ mdev->ov_position = sector;
+ goto requeue;
+ }
+
+ if (sector + (size>>9) > capacity)
+ size = (capacity-sector)<<9;
+
+ inc_rs_pending(mdev);
+ if (!drbd_send_ov_request(mdev, sector, size)) {
+ dec_rs_pending(mdev);
+ return 0;
+ }
+ sector += BM_SECT_PER_BIT;
+ }
+ mdev->ov_position = sector;
+
+ requeue:
+ mod_timer(&mdev->resync_timer, jiffies + SLEEP_TIME);
+ return 1;
+}
+
+
+int w_ov_finished(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ kfree(w);
+ ov_oos_print(mdev);
+ drbd_resync_finished(mdev);
+
+ return 1;
+}
+
+static int w_resync_finished(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ kfree(w);
+
+ drbd_resync_finished(mdev);
+
+ return 1;
+}
+
+int drbd_resync_finished(struct drbd_conf *mdev)
+{
+ unsigned long db, dt, dbdt;
+ unsigned long n_oos;
+ union drbd_state os, ns;
+ struct drbd_work *w;
+ char *khelper_cmd = NULL;
+
+ /* Remove all elements from the resync LRU. Since future actions
+ * might set bits in the (main) bitmap, then the entries in the
+ * resync LRU would be wrong. */
+ if (drbd_rs_del_all(mdev)) {
+ /* In case this is not possible now, most probably because
+ * there are P_RS_DATA_REPLY Packets lingering on the worker's
+ * queue (or even the read operations for those packets
+ * is not finished by now). Retry in 100ms. */
+
+ drbd_kick_lo(mdev);
+ __set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ / 10);
+ w = kmalloc(sizeof(struct drbd_work), GFP_ATOMIC);
+ if (w) {
+ w->cb = w_resync_finished;
+ drbd_queue_work(&mdev->data.work, w);
+ return 1;
+ }
+ dev_err(DEV, "Warn failed to drbd_rs_del_all() and to kmalloc(w).\n");
+ }
+
+ dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ;
+ if (dt <= 0)
+ dt = 1;
+ db = mdev->rs_total;
+ dbdt = Bit2KB(db/dt);
+ mdev->rs_paused /= HZ;
+
+ if (!get_ldev(mdev))
+ goto out;
+
+ spin_lock_irq(&mdev->req_lock);
+ os = mdev->state;
+
+ /* This protects us against multiple calls (that can happen in the presence
+ of application IO), and against connectivity loss just before we arrive here. */
+ if (os.conn <= C_CONNECTED)
+ goto out_unlock;
+
+ ns = os;
+ ns.conn = C_CONNECTED;
+
+ dev_info(DEV, "%s done (total %lu sec; paused %lu sec; %lu K/sec)\n",
+ (os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) ?
+ "Online verify " : "Resync",
+ dt + mdev->rs_paused, mdev->rs_paused, dbdt);
+
+ n_oos = drbd_bm_total_weight(mdev);
+
+ if (os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) {
+ if (n_oos) {
+ dev_alert(DEV, "Online verify found %lu %dk block out of sync!\n",
+ n_oos, Bit2KB(1));
+ khelper_cmd = "out-of-sync";
+ }
+ } else {
+ D_ASSERT((n_oos - mdev->rs_failed) == 0);
+
+ if (os.conn == C_SYNC_TARGET || os.conn == C_PAUSED_SYNC_T)
+ khelper_cmd = "after-resync-target";
+
+ if (mdev->csums_tfm && mdev->rs_total) {
+ const unsigned long s = mdev->rs_same_csum;
+ const unsigned long t = mdev->rs_total;
+ const int ratio =
+ (t == 0) ? 0 :
+ (t < 100000) ? ((s*100)/t) : (s/(t/100));
+ dev_info(DEV, "%u %% had equal check sums, eliminated: %luK; "
+ "transferred %luK total %luK\n",
+ ratio,
+ Bit2KB(mdev->rs_same_csum),
+ Bit2KB(mdev->rs_total - mdev->rs_same_csum),
+ Bit2KB(mdev->rs_total));
+ }
+ }
+
+ if (mdev->rs_failed) {
+ dev_info(DEV, " %lu failed blocks\n", mdev->rs_failed);
+
+ if (os.conn == C_SYNC_TARGET || os.conn == C_PAUSED_SYNC_T) {
+ ns.disk = D_INCONSISTENT;
+ ns.pdsk = D_UP_TO_DATE;
+ } else {
+ ns.disk = D_UP_TO_DATE;
+ ns.pdsk = D_INCONSISTENT;
+ }
+ } else {
+ ns.disk = D_UP_TO_DATE;
+ ns.pdsk = D_UP_TO_DATE;
+
+ if (os.conn == C_SYNC_TARGET || os.conn == C_PAUSED_SYNC_T) {
+ if (mdev->p_uuid) {
+ int i;
+ for (i = UI_BITMAP ; i <= UI_HISTORY_END ; i++)
+ _drbd_uuid_set(mdev, i, mdev->p_uuid[i]);
+ drbd_uuid_set(mdev, UI_BITMAP, mdev->ldev->md.uuid[UI_CURRENT]);
+ _drbd_uuid_set(mdev, UI_CURRENT, mdev->p_uuid[UI_CURRENT]);
+ } else {
+ dev_err(DEV, "mdev->p_uuid is NULL! BUG\n");
+ }
+ }
+
+ drbd_uuid_set_bm(mdev, 0UL);
+
+ if (mdev->p_uuid) {
+ /* Now the two UUID sets are equal, update what we
+ * know of the peer. */
+ int i;
+ for (i = UI_CURRENT ; i <= UI_HISTORY_END ; i++)
+ mdev->p_uuid[i] = mdev->ldev->md.uuid[i];
+ }
+ }
+
+ _drbd_set_state(mdev, ns, CS_VERBOSE, NULL);
+out_unlock:
+ spin_unlock_irq(&mdev->req_lock);
+ put_ldev(mdev);
+out:
+ mdev->rs_total = 0;
+ mdev->rs_failed = 0;
+ mdev->rs_paused = 0;
+ mdev->ov_start_sector = 0;
+
+ if (test_and_clear_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags)) {
+ dev_warn(DEV, "Writing the whole bitmap, due to failed kmalloc\n");
+ drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, "write from resync_finished");
+ }
+
+ if (khelper_cmd)
+ drbd_khelper(mdev, khelper_cmd);
+
+ return 1;
+}
+
+/* helper */
+static void move_to_net_ee_or_free(struct drbd_conf *mdev, struct drbd_epoch_entry *e)
+{
+ if (drbd_bio_has_active_page(e->private_bio)) {
+ /* This might happen if sendpage() has not finished */
+ spin_lock_irq(&mdev->req_lock);
+ list_add_tail(&e->w.list, &mdev->net_ee);
+ spin_unlock_irq(&mdev->req_lock);
+ } else
+ drbd_free_ee(mdev, e);
+}
+
+/**
+ * w_e_end_data_req() - Worker callback, to send a P_DATA_REPLY packet in response to a P_DATA_REQUEST
+ * @mdev: DRBD device.
+ * @w: work object.
+ * @cancel: The connection will be closed anyways
+ */
+int w_e_end_data_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
+ int ok;
+
+ if (unlikely(cancel)) {
+ drbd_free_ee(mdev, e);
+ dec_unacked(mdev);
+ return 1;
+ }
+
+ if (likely(drbd_bio_uptodate(e->private_bio))) {
+ ok = drbd_send_block(mdev, P_DATA_REPLY, e);
+ } else {
+ if (__ratelimit(&drbd_ratelimit_state))
+ dev_err(DEV, "Sending NegDReply. sector=%llus.\n",
+ (unsigned long long)e->sector);
+
+ ok = drbd_send_ack(mdev, P_NEG_DREPLY, e);
+ }
+
+ dec_unacked(mdev);
+
+ move_to_net_ee_or_free(mdev, e);
+
+ if (unlikely(!ok))
+ dev_err(DEV, "drbd_send_block() failed\n");
+ return ok;
+}
+
+/**
+ * w_e_end_rsdata_req() - Worker callback to send a P_RS_DATA_REPLY packet in response to a P_RS_DATA_REQUESTRS
+ * @mdev: DRBD device.
+ * @w: work object.
+ * @cancel: The connection will be closed anyways
+ */
+int w_e_end_rsdata_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
+ int ok;
+
+ if (unlikely(cancel)) {
+ drbd_free_ee(mdev, e);
+ dec_unacked(mdev);
+ return 1;
+ }
+
+ if (get_ldev_if_state(mdev, D_FAILED)) {
+ drbd_rs_complete_io(mdev, e->sector);
+ put_ldev(mdev);
+ }
+
+ if (likely(drbd_bio_uptodate(e->private_bio))) {
+ if (likely(mdev->state.pdsk >= D_INCONSISTENT)) {
+ inc_rs_pending(mdev);
+ ok = drbd_send_block(mdev, P_RS_DATA_REPLY, e);
+ } else {
+ if (__ratelimit(&drbd_ratelimit_state))
+ dev_err(DEV, "Not sending RSDataReply, "
+ "partner DISKLESS!\n");
+ ok = 1;
+ }
+ } else {
+ if (__ratelimit(&drbd_ratelimit_state))
+ dev_err(DEV, "Sending NegRSDReply. sector %llus.\n",
+ (unsigned long long)e->sector);
+
+ ok = drbd_send_ack(mdev, P_NEG_RS_DREPLY, e);
+
+ /* update resync data with failure */
+ drbd_rs_failed_io(mdev, e->sector, e->size);
+ }
+
+ dec_unacked(mdev);
+
+ move_to_net_ee_or_free(mdev, e);
+
+ if (unlikely(!ok))
+ dev_err(DEV, "drbd_send_block() failed\n");
+ return ok;
+}
+
+int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
+ struct digest_info *di;
+ int digest_size;
+ void *digest = NULL;
+ int ok, eq = 0;
+
+ if (unlikely(cancel)) {
+ drbd_free_ee(mdev, e);
+ dec_unacked(mdev);
+ return 1;
+ }
+
+ drbd_rs_complete_io(mdev, e->sector);
+
+ di = (struct digest_info *)(unsigned long)e->block_id;
+
+ if (likely(drbd_bio_uptodate(e->private_bio))) {
+ /* quick hack to try to avoid a race against reconfiguration.
+ * a real fix would be much more involved,
+ * introducing more locking mechanisms */
+ if (mdev->csums_tfm) {
+ digest_size = crypto_hash_digestsize(mdev->csums_tfm);
+ D_ASSERT(digest_size == di->digest_size);
+ digest = kmalloc(digest_size, GFP_NOIO);
+ }
+ if (digest) {
+ drbd_csum(mdev, mdev->csums_tfm, e->private_bio, digest);
+ eq = !memcmp(digest, di->digest, digest_size);
+ kfree(digest);
+ }
+
+ if (eq) {
+ drbd_set_in_sync(mdev, e->sector, e->size);
+ mdev->rs_same_csum++;
+ ok = drbd_send_ack(mdev, P_RS_IS_IN_SYNC, e);
+ } else {
+ inc_rs_pending(mdev);
+ e->block_id = ID_SYNCER;
+ ok = drbd_send_block(mdev, P_RS_DATA_REPLY, e);
+ }
+ } else {
+ ok = drbd_send_ack(mdev, P_NEG_RS_DREPLY, e);
+ if (__ratelimit(&drbd_ratelimit_state))
+ dev_err(DEV, "Sending NegDReply. I guess it gets messy.\n");
+ }
+
+ dec_unacked(mdev);
+
+ kfree(di);
+
+ move_to_net_ee_or_free(mdev, e);
+
+ if (unlikely(!ok))
+ dev_err(DEV, "drbd_send_block/ack() failed\n");
+ return ok;
+}
+
+int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
+ int digest_size;
+ void *digest;
+ int ok = 1;
+
+ if (unlikely(cancel))
+ goto out;
+
+ if (unlikely(!drbd_bio_uptodate(e->private_bio)))
+ goto out;
+
+ digest_size = crypto_hash_digestsize(mdev->verify_tfm);
+ /* FIXME if this allocation fails, online verify will not terminate! */
+ digest = kmalloc(digest_size, GFP_NOIO);
+ if (digest) {
+ drbd_csum(mdev, mdev->verify_tfm, e->private_bio, digest);
+ inc_rs_pending(mdev);
+ ok = drbd_send_drequest_csum(mdev, e->sector, e->size,
+ digest, digest_size, P_OV_REPLY);
+ if (!ok)
+ dec_rs_pending(mdev);
+ kfree(digest);
+ }
+
+out:
+ drbd_free_ee(mdev, e);
+
+ dec_unacked(mdev);
+
+ return ok;
+}
+
+void drbd_ov_oos_found(struct drbd_conf *mdev, sector_t sector, int size)
+{
+ if (mdev->ov_last_oos_start + mdev->ov_last_oos_size == sector) {
+ mdev->ov_last_oos_size += size>>9;
+ } else {
+ mdev->ov_last_oos_start = sector;
+ mdev->ov_last_oos_size = size>>9;
+ }
+ drbd_set_out_of_sync(mdev, sector, size);
+ set_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags);
+}
+
+int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
+ struct digest_info *di;
+ int digest_size;
+ void *digest;
+ int ok, eq = 0;
+
+ if (unlikely(cancel)) {
+ drbd_free_ee(mdev, e);
+ dec_unacked(mdev);
+ return 1;
+ }
+
+ /* after "cancel", because after drbd_disconnect/drbd_rs_cancel_all
+ * the resync lru has been cleaned up already */
+ drbd_rs_complete_io(mdev, e->sector);
+
+ di = (struct digest_info *)(unsigned long)e->block_id;
+
+ if (likely(drbd_bio_uptodate(e->private_bio))) {
+ digest_size = crypto_hash_digestsize(mdev->verify_tfm);
+ digest = kmalloc(digest_size, GFP_NOIO);
+ if (digest) {
+ drbd_csum(mdev, mdev->verify_tfm, e->private_bio, digest);
+
+ D_ASSERT(digest_size == di->digest_size);
+ eq = !memcmp(digest, di->digest, digest_size);
+ kfree(digest);
+ }
+ } else {
+ ok = drbd_send_ack(mdev, P_NEG_RS_DREPLY, e);
+ if (__ratelimit(&drbd_ratelimit_state))
+ dev_err(DEV, "Sending NegDReply. I guess it gets messy.\n");
+ }
+
+ dec_unacked(mdev);
+
+ kfree(di);
+
+ if (!eq)
+ drbd_ov_oos_found(mdev, e->sector, e->size);
+ else
+ ov_oos_print(mdev);
+
+ ok = drbd_send_ack_ex(mdev, P_OV_RESULT, e->sector, e->size,
+ eq ? ID_IN_SYNC : ID_OUT_OF_SYNC);
+
+ drbd_free_ee(mdev, e);
+
+ if (--mdev->ov_left == 0) {
+ ov_oos_print(mdev);
+ drbd_resync_finished(mdev);
+ }
+
+ return ok;
+}
+
+int w_prev_work_done(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ struct drbd_wq_barrier *b = container_of(w, struct drbd_wq_barrier, w);
+ complete(&b->done);
+ return 1;
+}
+
+int w_send_barrier(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ struct drbd_tl_epoch *b = container_of(w, struct drbd_tl_epoch, w);
+ struct p_barrier *p = &mdev->data.sbuf.barrier;
+ int ok = 1;
+
+ /* really avoid racing with tl_clear. w.cb may have been referenced
+ * just before it was reassigned and re-queued, so double check that.
+ * actually, this race was harmless, since we only try to send the
+ * barrier packet here, and otherwise do nothing with the object.
+ * but compare with the head of w_clear_epoch */
+ spin_lock_irq(&mdev->req_lock);
+ if (w->cb != w_send_barrier || mdev->state.conn < C_CONNECTED)
+ cancel = 1;
+ spin_unlock_irq(&mdev->req_lock);
+ if (cancel)
+ return 1;
+
+ if (!drbd_get_data_sock(mdev))
+ return 0;
+ p->barrier = b->br_number;
+ /* inc_ap_pending was done where this was queued.
+ * dec_ap_pending will be done in got_BarrierAck
+ * or (on connection loss) in w_clear_epoch. */
+ ok = _drbd_send_cmd(mdev, mdev->data.socket, P_BARRIER,
+ (struct p_header *)p, sizeof(*p), 0);
+ drbd_put_data_sock(mdev);
+
+ return ok;
+}
+
+int w_send_write_hint(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ if (cancel)
+ return 1;
+ return drbd_send_short_cmd(mdev, P_UNPLUG_REMOTE);
+}
+
+/**
+ * w_send_dblock() - Worker callback to send a P_DATA packet in order to mirror a write request
+ * @mdev: DRBD device.
+ * @w: work object.
+ * @cancel: The connection will be closed anyways
+ */
+int w_send_dblock(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ struct drbd_request *req = container_of(w, struct drbd_request, w);
+ int ok;
+
+ if (unlikely(cancel)) {
+ req_mod(req, send_canceled);
+ return 1;
+ }
+
+ ok = drbd_send_dblock(mdev, req);
+ req_mod(req, ok ? handed_over_to_network : send_failed);
+
+ return ok;
+}
+
+/**
+ * w_send_read_req() - Worker callback to send a read request (P_DATA_REQUEST) packet
+ * @mdev: DRBD device.
+ * @w: work object.
+ * @cancel: The connection will be closed anyways
+ */
+int w_send_read_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+ struct drbd_request *req = container_of(w, struct drbd_request, w);
+ int ok;
+
+ if (unlikely(cancel)) {
+ req_mod(req, send_canceled);
+ return 1;
+ }
+
+ ok = drbd_send_drequest(mdev, P_DATA_REQUEST, req->sector, req->size,
+ (unsigned long)req);
+
+ if (!ok) {
+ /* ?? we set C_TIMEOUT or C_BROKEN_PIPE in drbd_send();
+ * so this is probably redundant */
+ if (mdev->state.conn >= C_CONNECTED)
+ drbd_force_state(mdev, NS(conn, C_NETWORK_FAILURE));
+ }
+ req_mod(req, ok ? handed_over_to_network : send_failed);
+
+ return ok;
+}
+
+static int _drbd_may_sync_now(struct drbd_conf *mdev)
+{
+ struct drbd_conf *odev = mdev;
+
+ while (1) {
+ if (odev->sync_conf.after == -1)
+ return 1;
+ odev = minor_to_mdev(odev->sync_conf.after);
+ ERR_IF(!odev) return 1;
+ if ((odev->state.conn >= C_SYNC_SOURCE &&
+ odev->state.conn <= C_PAUSED_SYNC_T) ||
+ odev->state.aftr_isp || odev->state.peer_isp ||
+ odev->state.user_isp)
+ return 0;
+ }
+}
+
+/**
+ * _drbd_pause_after() - Pause resync on all devices that may not resync now
+ * @mdev: DRBD device.
+ *
+ * Called from process context only (admin command and after_state_ch).
+ */
+static int _drbd_pause_after(struct drbd_conf *mdev)
+{
+ struct drbd_conf *odev;
+ int i, rv = 0;
+
+ for (i = 0; i < minor_count; i++) {
+ odev = minor_to_mdev(i);
+ if (!odev)
+ continue;
+ if (odev->state.conn == C_STANDALONE && odev->state.disk == D_DISKLESS)
+ continue;
+ if (!_drbd_may_sync_now(odev))
+ rv |= (__drbd_set_state(_NS(odev, aftr_isp, 1), CS_HARD, NULL)
+ != SS_NOTHING_TO_DO);
+ }
+
+ return rv;
+}
+
+/**
+ * _drbd_resume_next() - Resume resync on all devices that may resync now
+ * @mdev: DRBD device.
+ *
+ * Called from process context only (admin command and worker).
+ */
+static int _drbd_resume_next(struct drbd_conf *mdev)
+{
+ struct drbd_conf *odev;
+ int i, rv = 0;
+
+ for (i = 0; i < minor_count; i++) {
+ odev = minor_to_mdev(i);
+ if (!odev)
+ continue;
+ if (odev->state.conn == C_STANDALONE && odev->state.disk == D_DISKLESS)
+ continue;
+ if (odev->state.aftr_isp) {
+ if (_drbd_may_sync_now(odev))
+ rv |= (__drbd_set_state(_NS(odev, aftr_isp, 0),
+ CS_HARD, NULL)
+ != SS_NOTHING_TO_DO) ;
+ }
+ }
+ return rv;
+}
+
+void resume_next_sg(struct drbd_conf *mdev)
+{
+ write_lock_irq(&global_state_lock);
+ _drbd_resume_next(mdev);
+ write_unlock_irq(&global_state_lock);
+}
+
+void suspend_other_sg(struct drbd_conf *mdev)
+{
+ write_lock_irq(&global_state_lock);
+ _drbd_pause_after(mdev);
+ write_unlock_irq(&global_state_lock);
+}
+
+static int sync_after_error(struct drbd_conf *mdev, int o_minor)
+{
+ struct drbd_conf *odev;
+
+ if (o_minor == -1)
+ return NO_ERROR;
+ if (o_minor < -1 || minor_to_mdev(o_minor) == NULL)
+ return ERR_SYNC_AFTER;
+
+ /* check for loops */
+ odev = minor_to_mdev(o_minor);
+ while (1) {
+ if (odev == mdev)
+ return ERR_SYNC_AFTER_CYCLE;
+
+ /* dependency chain ends here, no cycles. */
+ if (odev->sync_conf.after == -1)
+ return NO_ERROR;
+
+ /* follow the dependency chain */
+ odev = minor_to_mdev(odev->sync_conf.after);
+ }
+}
+
+int drbd_alter_sa(struct drbd_conf *mdev, int na)
+{
+ int changes;
+ int retcode;
+
+ write_lock_irq(&global_state_lock);
+ retcode = sync_after_error(mdev, na);
+ if (retcode == NO_ERROR) {
+ mdev->sync_conf.after = na;
+ do {
+ changes = _drbd_pause_after(mdev);
+ changes |= _drbd_resume_next(mdev);
+ } while (changes);
+ }
+ write_unlock_irq(&global_state_lock);
+ return retcode;
+}
+
+/**
+ * drbd_start_resync() - Start the resync process
+ * @mdev: DRBD device.
+ * @side: Either C_SYNC_SOURCE or C_SYNC_TARGET
+ *
+ * This function might bring you directly into one of the
+ * C_PAUSED_SYNC_* states.
+ */
+void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side)
+{
+ union drbd_state ns;
+ int r;
+
+ if (mdev->state.conn >= C_SYNC_SOURCE) {
+ dev_err(DEV, "Resync already running!\n");
+ return;
+ }
+
+ /* In case a previous resync run was aborted by an IO error/detach on the peer. */
+ drbd_rs_cancel_all(mdev);
+
+ if (side == C_SYNC_TARGET) {
+ /* Since application IO was locked out during C_WF_BITMAP_T and
+ C_WF_SYNC_UUID we are still unmodified. Before going to C_SYNC_TARGET
+ we check that we might make the data inconsistent. */
+ r = drbd_khelper(mdev, "before-resync-target");
+ r = (r >> 8) & 0xff;
+ if (r > 0) {
+ dev_info(DEV, "before-resync-target handler returned %d, "
+ "dropping connection.\n", r);
+ drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+ return;
+ }
+ }
+
+ drbd_state_lock(mdev);
+
+ if (!get_ldev_if_state(mdev, D_NEGOTIATING)) {
+ drbd_state_unlock(mdev);
+ return;
+ }
+
+ if (side == C_SYNC_TARGET) {
+ mdev->bm_resync_fo = 0;
+ } else /* side == C_SYNC_SOURCE */ {
+ u64 uuid;
+
+ get_random_bytes(&uuid, sizeof(u64));
+ drbd_uuid_set(mdev, UI_BITMAP, uuid);
+ drbd_send_sync_uuid(mdev, uuid);
+
+ D_ASSERT(mdev->state.disk == D_UP_TO_DATE);
+ }
+
+ write_lock_irq(&global_state_lock);
+ ns = mdev->state;
+
+ ns.aftr_isp = !_drbd_may_sync_now(mdev);
+
+ ns.conn = side;
+
+ if (side == C_SYNC_TARGET)
+ ns.disk = D_INCONSISTENT;
+ else /* side == C_SYNC_SOURCE */
+ ns.pdsk = D_INCONSISTENT;
+
+ r = __drbd_set_state(mdev, ns, CS_VERBOSE, NULL);
+ ns = mdev->state;
+
+ if (ns.conn < C_CONNECTED)
+ r = SS_UNKNOWN_ERROR;
+
+ if (r == SS_SUCCESS) {
+ mdev->rs_total =
+ mdev->rs_mark_left = drbd_bm_total_weight(mdev);
+ mdev->rs_failed = 0;
+ mdev->rs_paused = 0;
+ mdev->rs_start =
+ mdev->rs_mark_time = jiffies;
+ mdev->rs_same_csum = 0;
+ _drbd_pause_after(mdev);
+ }
+ write_unlock_irq(&global_state_lock);
+ drbd_state_unlock(mdev);
+ put_ldev(mdev);
+
+ if (r == SS_SUCCESS) {
+ dev_info(DEV, "Began resync as %s (will sync %lu KB [%lu bits set]).\n",
+ drbd_conn_str(ns.conn),
+ (unsigned long) mdev->rs_total << (BM_BLOCK_SHIFT-10),
+ (unsigned long) mdev->rs_total);
+
+ if (mdev->rs_total == 0) {
+ /* Peer still reachable? Beware of failing before-resync-target handlers! */
+ request_ping(mdev);
+ __set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(mdev->net_conf->ping_timeo*HZ/9); /* 9 instead 10 */
+ drbd_resync_finished(mdev);
+ return;
+ }
+
+ /* ns.conn may already be != mdev->state.conn,
+ * we may have been paused in between, or become paused until
+ * the timer triggers.
+ * No matter, that is handled in resync_timer_fn() */
+ if (ns.conn == C_SYNC_TARGET)
+ mod_timer(&mdev->resync_timer, jiffies);
+
+ drbd_md_sync(mdev);
+ }
+}
+
+int drbd_worker(struct drbd_thread *thi)
+{
+ struct drbd_conf *mdev = thi->mdev;
+ struct drbd_work *w = NULL;
+ LIST_HEAD(work_list);
+ int intr = 0, i;
+
+ sprintf(current->comm, "drbd%d_worker", mdev_to_minor(mdev));
+
+ while (get_t_state(thi) == Running) {
+ drbd_thread_current_set_cpu(mdev);
+
+ if (down_trylock(&mdev->data.work.s)) {
+ mutex_lock(&mdev->data.mutex);
+ if (mdev->data.socket && !mdev->net_conf->no_cork)
+ drbd_tcp_uncork(mdev->data.socket);
+ mutex_unlock(&mdev->data.mutex);
+
+ intr = down_interruptible(&mdev->data.work.s);
+
+ mutex_lock(&mdev->data.mutex);
+ if (mdev->data.socket && !mdev->net_conf->no_cork)
+ drbd_tcp_cork(mdev->data.socket);
+ mutex_unlock(&mdev->data.mutex);
+ }
+
+ if (intr) {
+ D_ASSERT(intr == -EINTR);
+ flush_signals(current);
+ ERR_IF (get_t_state(thi) == Running)
+ continue;
+ break;
+ }
+
+ if (get_t_state(thi) != Running)
+ break;
+ /* With this break, we have done a down() but not consumed
+ the entry from the list. The cleanup code takes care of
+ this... */
+
+ w = NULL;
+ spin_lock_irq(&mdev->data.work.q_lock);
+ ERR_IF(list_empty(&mdev->data.work.q)) {
+ /* something terribly wrong in our logic.
+ * we were able to down() the semaphore,
+ * but the list is empty... doh.
+ *
+ * what is the best thing to do now?
+ * try again from scratch, restarting the receiver,
+ * asender, whatnot? could break even more ugly,
+ * e.g. when we are primary, but no good local data.
+ *
+ * I'll try to get away just starting over this loop.
+ */
+ spin_unlock_irq(&mdev->data.work.q_lock);
+ continue;
+ }
+ w = list_entry(mdev->data.work.q.next, struct drbd_work, list);
+ list_del_init(&w->list);
+ spin_unlock_irq(&mdev->data.work.q_lock);
+
+ if (!w->cb(mdev, w, mdev->state.conn < C_CONNECTED)) {
+ /* dev_warn(DEV, "worker: a callback failed! \n"); */
+ if (mdev->state.conn >= C_CONNECTED)
+ drbd_force_state(mdev,
+ NS(conn, C_NETWORK_FAILURE));
+ }
+ }
+ D_ASSERT(test_bit(DEVICE_DYING, &mdev->flags));
+ D_ASSERT(test_bit(CONFIG_PENDING, &mdev->flags));
+
+ spin_lock_irq(&mdev->data.work.q_lock);
+ i = 0;
+ while (!list_empty(&mdev->data.work.q)) {
+ list_splice_init(&mdev->data.work.q, &work_list);
+ spin_unlock_irq(&mdev->data.work.q_lock);
+
+ while (!list_empty(&work_list)) {
+ w = list_entry(work_list.next, struct drbd_work, list);
+ list_del_init(&w->list);
+ w->cb(mdev, w, 1);
+ i++; /* dead debugging code */
+ }
+
+ spin_lock_irq(&mdev->data.work.q_lock);
+ }
+ sema_init(&mdev->data.work.s, 0);
+ /* DANGEROUS race: if someone did queue his work within the spinlock,
+ * but up() ed outside the spinlock, we could get an up() on the
+ * semaphore without corresponding list entry.
+ * So don't do that.
+ */
+ spin_unlock_irq(&mdev->data.work.q_lock);
+
+ D_ASSERT(mdev->state.disk == D_DISKLESS && mdev->state.conn == C_STANDALONE);
+ /* _drbd_set_state only uses stop_nowait.
+ * wait here for the Exiting receiver. */
+ drbd_thread_stop(&mdev->receiver);
+ drbd_mdev_cleanup(mdev);
+
+ dev_info(DEV, "worker terminated\n");
+
+ clear_bit(DEVICE_DYING, &mdev->flags);
+ clear_bit(CONFIG_PENDING, &mdev->flags);
+ wake_up(&mdev->state_wait);
+
+ return 0;
+}
diff --git a/drivers/block/drbd/drbd_wrappers.h b/drivers/block/drbd/drbd_wrappers.h
new file mode 100644
index 000000000000..f93fa111ce50
--- /dev/null
+++ b/drivers/block/drbd/drbd_wrappers.h
@@ -0,0 +1,91 @@
+#ifndef _DRBD_WRAPPERS_H
+#define _DRBD_WRAPPERS_H
+
+#include <linux/ctype.h>
+#include <linux/mm.h>
+
+/* see get_sb_bdev and bd_claim */
+extern char *drbd_sec_holder;
+
+/* sets the number of 512 byte sectors of our virtual device */
+static inline void drbd_set_my_capacity(struct drbd_conf *mdev,
+ sector_t size)
+{
+ /* set_capacity(mdev->this_bdev->bd_disk, size); */
+ set_capacity(mdev->vdisk, size);
+ mdev->this_bdev->bd_inode->i_size = (loff_t)size << 9;
+}
+
+#define drbd_bio_uptodate(bio) bio_flagged(bio, BIO_UPTODATE)
+
+static inline int drbd_bio_has_active_page(struct bio *bio)
+{
+ struct bio_vec *bvec;
+ int i;
+
+ __bio_for_each_segment(bvec, bio, i, 0) {
+ if (page_count(bvec->bv_page) > 1)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* bi_end_io handlers */
+extern void drbd_md_io_complete(struct bio *bio, int error);
+extern void drbd_endio_read_sec(struct bio *bio, int error);
+extern void drbd_endio_write_sec(struct bio *bio, int error);
+extern void drbd_endio_pri(struct bio *bio, int error);
+
+/*
+ * used to submit our private bio
+ */
+static inline void drbd_generic_make_request(struct drbd_conf *mdev,
+ int fault_type, struct bio *bio)
+{
+ __release(local);
+ if (!bio->bi_bdev) {
+ printk(KERN_ERR "drbd%d: drbd_generic_make_request: "
+ "bio->bi_bdev == NULL\n",
+ mdev_to_minor(mdev));
+ dump_stack();
+ bio_endio(bio, -ENODEV);
+ return;
+ }
+
+ if (FAULT_ACTIVE(mdev, fault_type))
+ bio_endio(bio, -EIO);
+ else
+ generic_make_request(bio);
+}
+
+static inline void drbd_plug_device(struct drbd_conf *mdev)
+{
+ struct request_queue *q;
+ q = bdev_get_queue(mdev->this_bdev);
+
+ spin_lock_irq(q->queue_lock);
+
+/* XXX the check on !blk_queue_plugged is redundant,
+ * implicitly checked in blk_plug_device */
+
+ if (!blk_queue_plugged(q)) {
+ blk_plug_device(q);
+ del_timer(&q->unplug_timer);
+ /* unplugging should not happen automatically... */
+ }
+ spin_unlock_irq(q->queue_lock);
+}
+
+static inline int drbd_crypto_is_hash(struct crypto_tfm *tfm)
+{
+ return (crypto_tfm_alg_type(tfm) & CRYPTO_ALG_TYPE_HASH_MASK)
+ == CRYPTO_ALG_TYPE_HASH;
+}
+
+#ifndef __CHECKER__
+# undef __cond_lock
+# define __cond_lock(x,c) (c)
+#endif
+
+#endif
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 43f19389647a..51042f0ba7e1 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -3,7 +3,6 @@
#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/virtio.h>
-#include <linux/virtio_ids.h>
#include <linux/virtio_blk.h>
#include <linux/scatterlist.h>
@@ -183,34 +182,6 @@ static void do_virtblk_request(struct request_queue *q)
vblk->vq->vq_ops->kick(vblk->vq);
}
-/* return ATA identify data
- */
-static int virtblk_identify(struct gendisk *disk, void *argp)
-{
- struct virtio_blk *vblk = disk->private_data;
- void *opaque;
- int err = -ENOMEM;
-
- opaque = kmalloc(VIRTIO_BLK_ID_BYTES, GFP_KERNEL);
- if (!opaque)
- goto out;
-
- err = virtio_config_buf(vblk->vdev, VIRTIO_BLK_F_IDENTIFY,
- offsetof(struct virtio_blk_config, identify), opaque,
- VIRTIO_BLK_ID_BYTES);
-
- if (err)
- goto out_kfree;
-
- if (copy_to_user(argp, opaque, VIRTIO_BLK_ID_BYTES))
- err = -EFAULT;
-
-out_kfree:
- kfree(opaque);
-out:
- return err;
-}
-
static void virtblk_prepare_flush(struct request_queue *q, struct request *req)
{
req->cmd_type = REQ_TYPE_LINUX_BLOCK;
@@ -222,10 +193,6 @@ static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
{
struct gendisk *disk = bdev->bd_disk;
struct virtio_blk *vblk = disk->private_data;
- void __user *argp = (void __user *)data;
-
- if (cmd == HDIO_GET_IDENTITY)
- return virtblk_identify(disk, argp);
/*
* Only allow the generic SCSI ioctls if the host can support it.
@@ -233,7 +200,8 @@ static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI))
return -ENOTTY;
- return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp);
+ return scsi_cmd_ioctl(disk->queue, disk, mode, cmd,
+ (void __user *)data);
}
/* We provide getgeo only to please some old bootloader/partitioning tools */
@@ -332,7 +300,6 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
}
vblk->disk->queue->queuedata = vblk;
- queue_flag_set_unlocked(QUEUE_FLAG_VIRT, vblk->disk->queue);
if (index < 26) {
sprintf(vblk->disk->disk_name, "vd%c", 'a' + index % 26);
@@ -445,7 +412,7 @@ static struct virtio_device_id id_table[] = {
static unsigned int features[] = {
VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
- VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_IDENTIFY, VIRTIO_BLK_F_FLUSH
+ VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_FLUSH
};
/*
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index b8578bb3f4c9..05a31e55d278 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -42,6 +42,7 @@
#include <linux/module.h>
#include <linux/scatterlist.h>
+#include <xen/xen.h>
#include <xen/xenbus.h>
#include <xen/grant_table.h>
#include <xen/events.h>
diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c
index a762283d2a21..e789e6c9a422 100644
--- a/drivers/cdrom/gdrom.c
+++ b/drivers/cdrom/gdrom.c
@@ -214,7 +214,7 @@ static void gdrom_spicommand(void *spi_string, int buflen)
gdrom_getsense(NULL);
return;
}
- outsw(PHYSADDR(GDROM_DATA_REG), cmd, 6);
+ outsw(GDROM_DATA_REG, cmd, 6);
}
@@ -298,7 +298,7 @@ static int gdrom_readtoc_cmd(struct gdromtoc *toc, int session)
err = -EINVAL;
goto cleanup_readtoc;
}
- insw(PHYSADDR(GDROM_DATA_REG), toc, tocsize/2);
+ insw(GDROM_DATA_REG, toc, tocsize/2);
if (gd.status & 0x01)
err = -EINVAL;
@@ -449,7 +449,7 @@ static int gdrom_getsense(short *bufstring)
GDROM_DEFAULT_TIMEOUT);
if (gd.pending)
goto cleanup_sense;
- insw(PHYSADDR(GDROM_DATA_REG), &sense, sense_command->buflen/2);
+ insw(GDROM_DATA_REG, &sense, sense_command->buflen/2);
if (sense[1] & 40) {
printk(KERN_INFO "GDROM: Drive not ready - command aborted\n");
goto cleanup_sense;
@@ -586,7 +586,7 @@ static void gdrom_readdisk_dma(struct work_struct *work)
spin_unlock(&gdrom_lock);
block = blk_rq_pos(req)/GD_TO_BLK + GD_SESSION_OFFSET;
block_cnt = blk_rq_sectors(req)/GD_TO_BLK;
- ctrl_outl(PHYSADDR(req->buffer), GDROM_DMA_STARTADDR_REG);
+ ctrl_outl(virt_to_phys(req->buffer), GDROM_DMA_STARTADDR_REG);
ctrl_outl(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG);
ctrl_outl(1, GDROM_DMA_DIRECTION_REG);
ctrl_outl(1, GDROM_DMA_ENABLE_REG);
@@ -615,7 +615,7 @@ static void gdrom_readdisk_dma(struct work_struct *work)
cpu_relax();
gd.pending = 1;
gd.transfer = 1;
- outsw(PHYSADDR(GDROM_DATA_REG), &read_command->cmd, 6);
+ outsw(GDROM_DATA_REG, &read_command->cmd, 6);
timeout = jiffies + HZ / 2;
/* Wait for any pending DMA to finish */
while (ctrl_inb(GDROM_DMA_STATUS_REG) &&
diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c
index eba999f8598d..93d33816c9d9 100644
--- a/drivers/char/hvc_xen.c
+++ b/drivers/char/hvc_xen.c
@@ -25,6 +25,8 @@
#include <linux/types.h>
#include <asm/xen/hypervisor.h>
+
+#include <xen/xen.h>
#include <xen/page.h>
#include <xen/events.h>
#include <xen/interface/io/console.h>
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
index 962968f05b94..915157fcff98 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -21,7 +21,6 @@
#include <linux/scatterlist.h>
#include <linux/spinlock.h>
#include <linux/virtio.h>
-#include <linux/virtio_ids.h>
#include <linux/virtio_rng.h>
/* The host will fill any buffer we give it with sweet, sweet randomness. We
@@ -117,7 +116,7 @@ static int virtrng_probe(struct virtio_device *vdev)
return 0;
}
-static void virtrng_remove(struct virtio_device *vdev)
+static void __devexit virtrng_remove(struct virtio_device *vdev)
{
vdev->config->reset(vdev);
hwrng_unregister(&virtio_hwrng);
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index a074fceb67d3..ac1795f5982b 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -44,7 +44,7 @@ static inline int uncached_access(struct file *file, unsigned long addr)
{
#if defined(CONFIG_IA64)
/*
- * On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases.
+ * On ia64, we ignore O_DSYNC because we cannot tolerate memory attribute aliases.
*/
return !(efi_mem_attributes(addr) & EFI_MEMORY_WB);
#elif defined(CONFIG_MIPS)
@@ -57,9 +57,9 @@ static inline int uncached_access(struct file *file, unsigned long addr)
#else
/*
* Accessing memory above the top the kernel knows about or through a file pointer
- * that was marked O_SYNC will be done non-cached.
+ * that was marked O_DSYNC will be done non-cached.
*/
- if (file->f_flags & O_SYNC)
+ if (file->f_flags & O_DSYNC)
return 1;
return addr >= __pa(high_memory);
#endif
diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c
index 5216fce0c62d..0f4674959917 100644
--- a/drivers/char/pcmcia/ipwireless/main.c
+++ b/drivers/char/pcmcia/ipwireless/main.c
@@ -79,208 +79,140 @@ static void signalled_reboot_callback(void *callback_data)
schedule_work(&ipw->work_reboot);
}
-static int config_ipwireless(struct ipw_dev *ipw)
+static int ipwireless_probe(struct pcmcia_device *p_dev,
+ cistpl_cftable_entry_t *cfg,
+ cistpl_cftable_entry_t *dflt,
+ unsigned int vcc,
+ void *priv_data)
{
- struct pcmcia_device *link = ipw->link;
- int ret;
- tuple_t tuple;
- unsigned short buf[64];
- cisparse_t parse;
- unsigned short cor_value;
+ struct ipw_dev *ipw = priv_data;
+ struct resource *io_resource;
memreq_t memreq_attr_memory;
memreq_t memreq_common_memory;
+ int ret;
- ipw->is_v2_card = 0;
-
- tuple.Attributes = 0;
- tuple.TupleData = (cisdata_t *) buf;
- tuple.TupleDataMax = sizeof(buf);
- tuple.TupleOffset = 0;
-
- tuple.DesiredTuple = RETURN_FIRST_TUPLE;
-
- ret = pcmcia_get_first_tuple(link, &tuple);
-
- while (ret == 0) {
- ret = pcmcia_get_tuple_data(link, &tuple);
-
- if (ret != 0) {
- cs_error(link, GetTupleData, ret);
- goto exit0;
- }
- ret = pcmcia_get_next_tuple(link, &tuple);
- }
-
- tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-
- ret = pcmcia_get_first_tuple(link, &tuple);
-
- if (ret != 0) {
- cs_error(link, GetFirstTuple, ret);
- goto exit0;
- }
-
- ret = pcmcia_get_tuple_data(link, &tuple);
-
- if (ret != 0) {
- cs_error(link, GetTupleData, ret);
- goto exit0;
- }
-
- ret = pcmcia_parse_tuple(&tuple, &parse);
-
- if (ret != 0) {
- cs_error(link, ParseTuple, ret);
- goto exit0;
- }
-
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
- link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
- link->io.IOAddrLines = 16;
+ p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ p_dev->io.BasePort1 = cfg->io.win[0].base;
+ p_dev->io.NumPorts1 = cfg->io.win[0].len;
+ p_dev->io.IOAddrLines = 16;
- link->irq.IRQInfo1 = parse.cftable_entry.irq.IRQInfo1;
+ p_dev->irq.IRQInfo1 = cfg->irq.IRQInfo1;
/* 0x40 causes it to generate level mode interrupts. */
/* 0x04 enables IREQ pin. */
- cor_value = parse.cftable_entry.index | 0x44;
- link->conf.ConfigIndex = cor_value;
+ p_dev->conf.ConfigIndex = cfg->index | 0x44;
+ ret = pcmcia_request_io(p_dev, &p_dev->io);
+ if (ret)
+ return ret;
- /* IRQ and I/O settings */
- tuple.DesiredTuple = CISTPL_CONFIG;
+ io_resource = request_region(p_dev->io.BasePort1, p_dev->io.NumPorts1,
+ IPWIRELESS_PCCARD_NAME);
- ret = pcmcia_get_first_tuple(link, &tuple);
+ if (cfg->mem.nwin == 0)
+ return 0;
- if (ret != 0) {
- cs_error(link, GetFirstTuple, ret);
- goto exit0;
- }
+ ipw->request_common_memory.Attributes =
+ WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE;
+ ipw->request_common_memory.Base = cfg->mem.win[0].host_addr;
+ ipw->request_common_memory.Size = cfg->mem.win[0].len;
+ if (ipw->request_common_memory.Size < 0x1000)
+ ipw->request_common_memory.Size = 0x1000;
+ ipw->request_common_memory.AccessSpeed = 0;
- ret = pcmcia_get_tuple_data(link, &tuple);
+ ret = pcmcia_request_window(&p_dev, &ipw->request_common_memory,
+ &ipw->handle_common_memory);
if (ret != 0) {
- cs_error(link, GetTupleData, ret);
- goto exit0;
+ cs_error(p_dev, RequestWindow, ret);
+ goto exit1;
}
- ret = pcmcia_parse_tuple(&tuple, &parse);
+ memreq_common_memory.CardOffset = cfg->mem.win[0].card_addr;
+ memreq_common_memory.Page = 0;
- if (ret != 0) {
- cs_error(link, GetTupleData, ret);
- goto exit0;
- }
- link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.ConfigBase = parse.config.base;
- link->conf.Present = parse.config.rmask[0];
- link->conf.IntType = INT_MEMORY_AND_IO;
-
- link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
- link->irq.Handler = ipwireless_interrupt;
- link->irq.Instance = ipw->hardware;
-
- ret = pcmcia_request_io(link, &link->io);
+ ret = pcmcia_map_mem_page(ipw->handle_common_memory,
+ &memreq_common_memory);
if (ret != 0) {
- cs_error(link, RequestIO, ret);
- goto exit0;
+ cs_error(p_dev, MapMemPage, ret);
+ goto exit2;
}
- request_region(link->io.BasePort1, link->io.NumPorts1,
- IPWIRELESS_PCCARD_NAME);
+ ipw->is_v2_card = cfg->mem.win[0].len == 0x100;
- /* memory settings */
+ ipw->common_memory = ioremap(ipw->request_common_memory.Base,
+ ipw->request_common_memory.Size);
+ request_mem_region(ipw->request_common_memory.Base,
+ ipw->request_common_memory.Size,
+ IPWIRELESS_PCCARD_NAME);
- tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ ipw->request_attr_memory.Attributes =
+ WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | WIN_ENABLE;
+ ipw->request_attr_memory.Base = 0;
+ ipw->request_attr_memory.Size = 0; /* this used to be 0x1000 */
+ ipw->request_attr_memory.AccessSpeed = 0;
- ret = pcmcia_get_first_tuple(link, &tuple);
+ ret = pcmcia_request_window(&p_dev, &ipw->request_attr_memory,
+ &ipw->handle_attr_memory);
if (ret != 0) {
- cs_error(link, GetFirstTuple, ret);
- goto exit1;
+ cs_error(p_dev, RequestWindow, ret);
+ goto exit2;
}
- ret = pcmcia_get_tuple_data(link, &tuple);
+ memreq_attr_memory.CardOffset = 0;
+ memreq_attr_memory.Page = 0;
- if (ret != 0) {
- cs_error(link, GetTupleData, ret);
- goto exit1;
- }
-
- ret = pcmcia_parse_tuple(&tuple, &parse);
+ ret = pcmcia_map_mem_page(ipw->handle_attr_memory,
+ &memreq_attr_memory);
if (ret != 0) {
- cs_error(link, ParseTuple, ret);
- goto exit1;
+ cs_error(p_dev, MapMemPage, ret);
+ goto exit3;
}
- if (parse.cftable_entry.mem.nwin > 0) {
- ipw->request_common_memory.Attributes =
- WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE;
- ipw->request_common_memory.Base =
- parse.cftable_entry.mem.win[0].host_addr;
- ipw->request_common_memory.Size = parse.cftable_entry.mem.win[0].len;
- if (ipw->request_common_memory.Size < 0x1000)
- ipw->request_common_memory.Size = 0x1000;
- ipw->request_common_memory.AccessSpeed = 0;
-
- ret = pcmcia_request_window(&link, &ipw->request_common_memory,
- &ipw->handle_common_memory);
-
- if (ret != 0) {
- cs_error(link, RequestWindow, ret);
- goto exit1;
- }
-
- memreq_common_memory.CardOffset =
- parse.cftable_entry.mem.win[0].card_addr;
- memreq_common_memory.Page = 0;
-
- ret = pcmcia_map_mem_page(ipw->handle_common_memory,
- &memreq_common_memory);
-
- if (ret != 0) {
- cs_error(link, MapMemPage, ret);
- goto exit1;
- }
+ ipw->attr_memory = ioremap(ipw->request_attr_memory.Base,
+ ipw->request_attr_memory.Size);
+ request_mem_region(ipw->request_attr_memory.Base,
+ ipw->request_attr_memory.Size, IPWIRELESS_PCCARD_NAME);
- ipw->is_v2_card =
- parse.cftable_entry.mem.win[0].len == 0x100;
+ return 0;
- ipw->common_memory = ioremap(ipw->request_common_memory.Base,
+exit3:
+ pcmcia_release_window(ipw->handle_attr_memory);
+exit2:
+ if (ipw->common_memory) {
+ release_mem_region(ipw->request_common_memory.Base,
ipw->request_common_memory.Size);
- request_mem_region(ipw->request_common_memory.Base,
- ipw->request_common_memory.Size, IPWIRELESS_PCCARD_NAME);
-
- ipw->request_attr_memory.Attributes =
- WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | WIN_ENABLE;
- ipw->request_attr_memory.Base = 0;
- ipw->request_attr_memory.Size = 0; /* this used to be 0x1000 */
- ipw->request_attr_memory.AccessSpeed = 0;
-
- ret = pcmcia_request_window(&link, &ipw->request_attr_memory,
- &ipw->handle_attr_memory);
+ iounmap(ipw->common_memory);
+ pcmcia_release_window(ipw->handle_common_memory);
+ } else
+ pcmcia_release_window(ipw->handle_common_memory);
+exit1:
+ release_resource(io_resource);
+ pcmcia_disable_device(p_dev);
+ return -1;
+}
- if (ret != 0) {
- cs_error(link, RequestWindow, ret);
- goto exit2;
- }
+static int config_ipwireless(struct ipw_dev *ipw)
+{
+ struct pcmcia_device *link = ipw->link;
+ int ret = 0;
- memreq_attr_memory.CardOffset = 0;
- memreq_attr_memory.Page = 0;
+ ipw->is_v2_card = 0;
- ret = pcmcia_map_mem_page(ipw->handle_attr_memory,
- &memreq_attr_memory);
+ ret = pcmcia_loop_config(link, ipwireless_probe, ipw);
+ if (ret != 0) {
+ cs_error(link, RequestIO, ret);
+ return ret;
+ }
- if (ret != 0) {
- cs_error(link, MapMemPage, ret);
- goto exit2;
- }
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.IntType = INT_MEMORY_AND_IO;
- ipw->attr_memory = ioremap(ipw->request_attr_memory.Base,
- ipw->request_attr_memory.Size);
- request_mem_region(ipw->request_attr_memory.Base, ipw->request_attr_memory.Size,
- IPWIRELESS_PCCARD_NAME);
- }
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
+ link->irq.Handler = ipwireless_interrupt;
+ link->irq.Instance = ipw->hardware;
INIT_WORK(&ipw->work_reboot, signalled_reboot_work);
@@ -293,7 +225,7 @@ static int config_ipwireless(struct ipw_dev *ipw)
if (ret != 0) {
cs_error(link, RequestIRQ, ret);
- goto exit3;
+ goto exit;
}
printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n",
@@ -316,12 +248,12 @@ static int config_ipwireless(struct ipw_dev *ipw)
ipw->network = ipwireless_network_create(ipw->hardware);
if (!ipw->network)
- goto exit3;
+ goto exit;
ipw->tty = ipwireless_tty_create(ipw->hardware, ipw->network,
ipw->nodes);
if (!ipw->tty)
- goto exit3;
+ goto exit;
ipwireless_init_hardware_v2_v3(ipw->hardware);
@@ -333,33 +265,27 @@ static int config_ipwireless(struct ipw_dev *ipw)
if (ret != 0) {
cs_error(link, RequestConfiguration, ret);
- goto exit4;
+ goto exit;
}
link->dev_node = &ipw->nodes[0];
return 0;
-exit4:
- pcmcia_disable_device(link);
-exit3:
+exit:
if (ipw->attr_memory) {
release_mem_region(ipw->request_attr_memory.Base,
ipw->request_attr_memory.Size);
iounmap(ipw->attr_memory);
pcmcia_release_window(ipw->handle_attr_memory);
- pcmcia_disable_device(link);
}
-exit2:
if (ipw->common_memory) {
release_mem_region(ipw->request_common_memory.Base,
ipw->request_common_memory.Size);
iounmap(ipw->common_memory);
pcmcia_release_window(ipw->handle_common_memory);
}
-exit1:
pcmcia_disable_device(link);
-exit0:
return -1;
}
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index caf6e4d19469..429b7313119b 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -575,55 +575,39 @@ static int mgslpc_probe(struct pcmcia_device *link)
#define CS_CHECK(fn, ret) \
do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+static int mgslpc_ioprobe(struct pcmcia_device *p_dev,
+ cistpl_cftable_entry_t *cfg,
+ cistpl_cftable_entry_t *dflt,
+ unsigned int vcc,
+ void *priv_data)
+{
+ if (cfg->io.nwin > 0) {
+ p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ if (!(cfg->io.flags & CISTPL_IO_8BIT))
+ p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+ if (!(cfg->io.flags & CISTPL_IO_16BIT))
+ p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK;
+ p_dev->io.BasePort1 = cfg->io.win[0].base;
+ p_dev->io.NumPorts1 = cfg->io.win[0].len;
+ return pcmcia_request_io(p_dev, &p_dev->io);
+ }
+ return -ENODEV;
+}
+
static int mgslpc_config(struct pcmcia_device *link)
{
MGSLPC_INFO *info = link->priv;
- tuple_t tuple;
- cisparse_t parse;
- int last_fn, last_ret;
- u_char buf[64];
- cistpl_cftable_entry_t dflt = { 0 };
- cistpl_cftable_entry_t *cfg;
+ int last_fn = RequestIO;
+ int last_ret;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("mgslpc_config(0x%p)\n", link);
- tuple.Attributes = 0;
- tuple.TupleData = buf;
- tuple.TupleDataMax = sizeof(buf);
- tuple.TupleOffset = 0;
-
- /* get CIS configuration entry */
-
- tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
- CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
-
- cfg = &(parse.cftable_entry);
- CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
- CS_CHECK(ParseTuple, pcmcia_parse_tuple(&tuple, &parse));
-
- if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
- if (cfg->index == 0)
+ last_ret = pcmcia_loop_config(link, mgslpc_ioprobe, NULL);
+ if (last_ret != 0)
goto cs_failed;
- link->conf.ConfigIndex = cfg->index;
- link->conf.Attributes |= CONF_ENABLE_IRQ;
-
- /* IO window settings */
- link->io.NumPorts1 = 0;
- if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
- cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- if (!(io->flags & CISTPL_IO_8BIT))
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- if (!(io->flags & CISTPL_IO_16BIT))
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
- link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
- link->io.BasePort1 = io->win[0].base;
- link->io.NumPorts1 = io->win[0].len;
- CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io));
- }
-
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 8;
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 47c2d2763456..f06bb37defb1 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -31,7 +31,7 @@
enum tpm_const {
TPM_MINOR = 224, /* officially assigned */
- TPM_BUFSIZE = 2048,
+ TPM_BUFSIZE = 4096,
TPM_NUM_DEVICES = 256,
};
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 8e67d5c642a4..6bd5f8866c74 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -315,7 +315,7 @@ EXPORT_SYMBOL(tty_termios_input_baud_rate);
* For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
* we need to carefully set the bits when the user does not get the
* desired speed. We allow small margins and preserve as much of possible
- * of the input intent to keep compatiblity.
+ * of the input intent to keep compatibility.
*
* Locking: Caller should hold termios lock. This is already held
* when calling this function from the driver termios handler.
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 0d328b59568d..a035ae39a359 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -31,7 +31,6 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/virtio.h>
-#include <linux/virtio_ids.h>
#include <linux/virtio_console.h>
#include "hvc_console.h"
diff --git a/drivers/cpuidle/governor.c b/drivers/cpuidle/governor.c
index 70b59642a708..724c164d31c9 100644
--- a/drivers/cpuidle/governor.c
+++ b/drivers/cpuidle/governor.c
@@ -21,7 +21,7 @@ struct cpuidle_governor *cpuidle_curr_governor;
* __cpuidle_find_governor - finds a governor of the specified name
* @str: the name
*
- * Must be called with cpuidle_lock aquired.
+ * Must be called with cpuidle_lock acquired.
*/
static struct cpuidle_governor * __cpuidle_find_governor(const char *str)
{
@@ -39,7 +39,7 @@ static struct cpuidle_governor * __cpuidle_find_governor(const char *str)
* @gov: the new target governor
*
* NOTE: "gov" can be NULL to specify disabled
- * Must be called with cpuidle_lock aquired.
+ * Must be called with cpuidle_lock acquired.
*/
int cpuidle_switch_governor(struct cpuidle_governor *gov)
{
diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c
index 76cb6b345e7b..0af80577dc7b 100644
--- a/drivers/crypto/padlock-sha.c
+++ b/drivers/crypto/padlock-sha.c
@@ -24,6 +24,12 @@
#include <asm/i387.h>
#include "padlock.h"
+#ifdef CONFIG_64BIT
+#define STACK_ALIGN 16
+#else
+#define STACK_ALIGN 4
+#endif
+
struct padlock_sha_desc {
struct shash_desc fallback;
};
@@ -64,7 +70,9 @@ static int padlock_sha1_finup(struct shash_desc *desc, const u8 *in,
/* We can't store directly to *out as it may be unaligned. */
/* BTW Don't reduce the buffer size below 128 Bytes!
* PadLock microcode needs it that big. */
- char result[128] __attribute__ ((aligned(PADLOCK_ALIGNMENT)));
+ char buf[128 + PADLOCK_ALIGNMENT - STACK_ALIGN] __attribute__
+ ((aligned(STACK_ALIGN)));
+ char *result = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT);
struct padlock_sha_desc *dctx = shash_desc_ctx(desc);
struct sha1_state state;
unsigned int space;
@@ -128,7 +136,9 @@ static int padlock_sha256_finup(struct shash_desc *desc, const u8 *in,
/* We can't store directly to *out as it may be unaligned. */
/* BTW Don't reduce the buffer size below 128 Bytes!
* PadLock microcode needs it that big. */
- char result[128] __attribute__ ((aligned(PADLOCK_ALIGNMENT)));
+ char buf[128 + PADLOCK_ALIGNMENT - STACK_ALIGN] __attribute__
+ ((aligned(STACK_ALIGN)));
+ char *result = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT);
struct padlock_sha_desc *dctx = shash_desc_ctx(desc);
struct sha256_state state;
unsigned int space;
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 5903a88351bf..668151977b8a 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -52,7 +52,7 @@ config DW_DMAC
config AT_HDMAC
tristate "Atmel AHB DMA support"
- depends on ARCH_AT91SAM9RL
+ depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
select DMA_ENGINE
help
Support the Atmel AHB DMA controller. This can be integrated in
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index bd0b248de2cf..51d7480d3a92 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -326,14 +326,7 @@ arch_initcall(dma_channel_table_init);
*/
struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type)
{
- struct dma_chan *chan;
- int cpu;
-
- cpu = get_cpu();
- chan = per_cpu_ptr(channel_table[tx_type], cpu)->chan;
- put_cpu();
-
- return chan;
+ return this_cpu_read(channel_table[tx_type]->chan);
}
EXPORT_SYMBOL(dma_find_channel);
@@ -847,7 +840,6 @@ dma_async_memcpy_buf_to_buf(struct dma_chan *chan, void *dest,
struct dma_async_tx_descriptor *tx;
dma_addr_t dma_dest, dma_src;
dma_cookie_t cookie;
- int cpu;
unsigned long flags;
dma_src = dma_map_single(dev->dev, src, len, DMA_TO_DEVICE);
@@ -866,10 +858,10 @@ dma_async_memcpy_buf_to_buf(struct dma_chan *chan, void *dest,
tx->callback = NULL;
cookie = tx->tx_submit(tx);
- cpu = get_cpu();
- per_cpu_ptr(chan->local, cpu)->bytes_transferred += len;
- per_cpu_ptr(chan->local, cpu)->memcpy_count++;
- put_cpu();
+ preempt_disable();
+ __this_cpu_add(chan->local->bytes_transferred, len);
+ __this_cpu_inc(chan->local->memcpy_count);
+ preempt_enable();
return cookie;
}
@@ -896,7 +888,6 @@ dma_async_memcpy_buf_to_pg(struct dma_chan *chan, struct page *page,
struct dma_async_tx_descriptor *tx;
dma_addr_t dma_dest, dma_src;
dma_cookie_t cookie;
- int cpu;
unsigned long flags;
dma_src = dma_map_single(dev->dev, kdata, len, DMA_TO_DEVICE);
@@ -913,10 +904,10 @@ dma_async_memcpy_buf_to_pg(struct dma_chan *chan, struct page *page,
tx->callback = NULL;
cookie = tx->tx_submit(tx);
- cpu = get_cpu();
- per_cpu_ptr(chan->local, cpu)->bytes_transferred += len;
- per_cpu_ptr(chan->local, cpu)->memcpy_count++;
- put_cpu();
+ preempt_disable();
+ __this_cpu_add(chan->local->bytes_transferred, len);
+ __this_cpu_inc(chan->local->memcpy_count);
+ preempt_enable();
return cookie;
}
@@ -945,7 +936,6 @@ dma_async_memcpy_pg_to_pg(struct dma_chan *chan, struct page *dest_pg,
struct dma_async_tx_descriptor *tx;
dma_addr_t dma_dest, dma_src;
dma_cookie_t cookie;
- int cpu;
unsigned long flags;
dma_src = dma_map_page(dev->dev, src_pg, src_off, len, DMA_TO_DEVICE);
@@ -963,10 +953,10 @@ dma_async_memcpy_pg_to_pg(struct dma_chan *chan, struct page *dest_pg,
tx->callback = NULL;
cookie = tx->tx_submit(tx);
- cpu = get_cpu();
- per_cpu_ptr(chan->local, cpu)->bytes_transferred += len;
- per_cpu_ptr(chan->local, cpu)->memcpy_count++;
- put_cpu();
+ preempt_disable();
+ __this_cpu_add(chan->local->bytes_transferred, len);
+ __this_cpu_inc(chan->local->memcpy_count);
+ preempt_enable();
return cookie;
}
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 55c9c59b3f71..aedef7941b22 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -69,6 +69,9 @@ config EDAC_MM_EDAC
occurred so that a particular failing memory module can be
replaced. If unsure, select 'Y'.
+config EDAC_MCE
+ bool
+
config EDAC_AMD64
tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h"
depends on EDAC_MM_EDAC && K8_NB && X86_64 && PCI && EDAC_DECODE_MCE
@@ -166,6 +169,16 @@ config EDAC_I5400
Support for error detection and correction the Intel
i5400 MCH chipset (Seaburg).
+config EDAC_I7CORE
+ tristate "Intel i7 Core (Nehalem) processors"
+ depends on EDAC_MM_EDAC && PCI && X86
+ select EDAC_MCE
+ help
+ Support for error detection and correction the Intel
+ i7 Core (Nehalem) Integrated Memory Controller that exists on
+ newer processors like i7 Core, i7 Core Extreme, Xeon 35xx
+ and Xeon 55xx processors.
+
config EDAC_I82860
tristate "Intel 82860"
depends on EDAC_MM_EDAC && PCI && X86_32
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index bc5dc232a0fb..ca6b1bb24ccc 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -8,6 +8,7 @@
obj-$(CONFIG_EDAC) := edac_stub.o
obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o
+obj-$(CONFIG_EDAC_MCE) += edac_mce.o
edac_core-objs := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o
edac_core-objs += edac_module.o edac_device_sysfs.o
@@ -23,6 +24,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_I7CORE) += i7core_edac.o
obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o
obj-$(CONFIG_EDAC_E752X) += e752x_edac.o
obj-$(CONFIG_EDAC_I82443BXGX) += i82443bxgx_edac.o
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 4f4ac82382f7..d4560d9d5a83 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -1122,7 +1122,7 @@ static void k8_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
debugf0("Reading K8_DRAM_BASE_LOW failed\n");
/* Extract parts into separate data entries */
- pvt->dram_base[dram] = ((u64) low & 0xFFFF0000) << 24;
+ pvt->dram_base[dram] = ((u64) low & 0xFFFF0000) << 8;
pvt->dram_IntlvEn[dram] = (low >> 8) & 0x7;
pvt->dram_rw_en[dram] = (low & 0x3);
@@ -1135,7 +1135,7 @@ static void k8_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
* Extract parts into separate data entries. Limit is the HIGHEST memory
* location of the region, so lower 24 bits need to be all ones
*/
- pvt->dram_limit[dram] = (((u64) low & 0xFFFF0000) << 24) | 0x00FFFFFF;
+ pvt->dram_limit[dram] = (((u64) low & 0xFFFF0000) << 8) | 0x00FFFFFF;
pvt->dram_IntlvSel[dram] = (low >> 8) & 0x7;
pvt->dram_DstNode[dram] = (low & 0x7);
}
@@ -1369,7 +1369,7 @@ static void f10_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
pvt->dram_IntlvEn[dram] = (low_base >> 8) & 0x7;
pvt->dram_base[dram] = (((u64)high_base & 0x000000FF) << 40) |
- (((u64)low_base & 0xFFFF0000) << 24);
+ (((u64)low_base & 0xFFFF0000) << 8);
low_offset = K8_DRAM_LIMIT_LOW + (dram << 3);
high_offset = F10_DRAM_LIMIT_HIGH + (dram << 3);
@@ -1391,7 +1391,7 @@ static void f10_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
* memory location of the region, so low 24 bits need to be all ones.
*/
pvt->dram_limit[dram] = (((u64)high_limit & 0x000000FF) << 40) |
- (((u64) low_limit & 0xFFFF0000) << 24) |
+ (((u64) low_limit & 0xFFFF0000) << 8) |
0x00FFFFFF;
}
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index 12f355cafdbe..f84da6ee2115 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -340,12 +340,30 @@ struct csrow_info {
struct channel_info *channels;
};
+struct mcidev_sysfs_group {
+ const char *name; /* group name */
+ struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */
+};
+
+struct mcidev_sysfs_group_kobj {
+ struct list_head list; /* list for all instances within a mc */
+
+ struct kobject kobj; /* kobj for the group */
+
+ struct mcidev_sysfs_group *grp; /* group description table */
+ struct mem_ctl_info *mci; /* the parent */
+};
+
/* mcidev_sysfs_attribute structure
* used for driver sysfs attributes and in mem_ctl_info
* sysfs top level entries
*/
struct mcidev_sysfs_attribute {
- struct attribute attr;
+ /* It should use either attr or grp */
+ struct attribute attr;
+ 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 *);
ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
};
@@ -423,6 +441,9 @@ struct mem_ctl_info {
/* edac sysfs device control */
struct kobject edac_mci_kobj;
+ /* list for all grp instances within a mc */
+ struct list_head grp_kobj_list;
+
/* Additional top controller level attributes, but specified
* by the low level driver.
*
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index e1d4ce083481..299547c04e51 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -556,6 +556,8 @@ static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
+ debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
+
if (mcidev_attr->show)
return mcidev_attr->show(mem_ctl_info, buffer);
@@ -568,6 +570,8 @@ static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
+ debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
+
if (mcidev_attr->store)
return mcidev_attr->store(mem_ctl_info, buffer, count);
@@ -725,28 +729,118 @@ void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
#define EDAC_DEVICE_SYMLINK "device"
+#define grp_to_mci(k) (container_of(k, struct mcidev_sysfs_group_kobj, kobj)->mci)
+
+/* MCI show/store functions for top most object */
+static ssize_t inst_grp_show(struct kobject *kobj, struct attribute *attr,
+ char *buffer)
+{
+ struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj);
+ struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
+
+ debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
+
+ if (mcidev_attr->show)
+ return mcidev_attr->show(mem_ctl_info, buffer);
+
+ return -EIO;
+}
+
+static ssize_t inst_grp_store(struct kobject *kobj, struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj);
+ struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
+
+ debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
+
+ if (mcidev_attr->store)
+ return mcidev_attr->store(mem_ctl_info, buffer, count);
+
+ return -EIO;
+}
+
+/* No memory to release for this kobj */
+static void edac_inst_grp_release(struct kobject *kobj)
+{
+ struct mcidev_sysfs_group_kobj *grp;
+ struct mem_ctl_info *mci;
+
+ debugf1("%s()\n", __func__);
+
+ grp = container_of(kobj, struct mcidev_sysfs_group_kobj, kobj);
+ mci = grp->mci;
+
+ kobject_put(&mci->edac_mci_kobj);
+}
+
+/* Intermediate show/store table */
+static struct sysfs_ops inst_grp_ops = {
+ .show = inst_grp_show,
+ .store = inst_grp_store
+};
+
+/* the kobj_type instance for a instance group */
+static struct kobj_type ktype_inst_grp = {
+ .release = edac_inst_grp_release,
+ .sysfs_ops = &inst_grp_ops,
+};
+
+
/*
* edac_create_mci_instance_attributes
- * create MC driver specific attributes at the topmost level
- * directory of this mci instance.
+ * create MC driver specific attributes bellow an specified kobj
+ * This routine calls itself recursively, in order to create an entire
+ * object tree.
*/
-static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci)
+static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
+ struct mcidev_sysfs_attribute *sysfs_attrib,
+ struct kobject *kobj)
{
int err;
- struct mcidev_sysfs_attribute *sysfs_attrib;
- /* point to the start of the array and iterate over it
- * adding each attribute listed to this mci instance's kobject
- */
- sysfs_attrib = mci->mc_driver_sysfs_attributes;
+ debugf1("%s()\n", __func__);
+
+ while (sysfs_attrib) {
+ if (sysfs_attrib->grp) {
+ struct mcidev_sysfs_group_kobj *grp_kobj;
+
+ grp_kobj = kzalloc(sizeof(*grp_kobj), GFP_KERNEL);
+ 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;
+
+ debugf0("%s() grp %s, mci %p\n", __func__,
+ sysfs_attrib->grp->name, mci);
+
+ err = kobject_init_and_add(&grp_kobj->kobj,
+ &ktype_inst_grp,
+ &mci->edac_mci_kobj,
+ sysfs_attrib->grp->name);
+ if (err)
+ return err;
+
+ err = edac_create_mci_instance_attributes(mci,
+ grp_kobj->grp->mcidev_attr,
+ &grp_kobj->kobj);
+
+ if (err)
+ 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);
+ } else
+ break;
- while (sysfs_attrib && sysfs_attrib->attr.name) {
- err = sysfs_create_file(&mci->edac_mci_kobj,
- (struct attribute*) sysfs_attrib);
if (err) {
return err;
}
-
sysfs_attrib++;
}
@@ -758,21 +852,44 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci)
* remove MC driver specific attributes at the topmost level
* directory of this mci instance.
*/
-static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci)
+static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
+ struct mcidev_sysfs_attribute *sysfs_attrib,
+ struct kobject *kobj, int count)
{
- struct mcidev_sysfs_attribute *sysfs_attrib;
+ struct mcidev_sysfs_group_kobj *grp_kobj, *tmp;
- /* point to the start of the array and iterate over it
- * adding each attribute listed to this mci instance's kobject
- */
- sysfs_attrib = mci->mc_driver_sysfs_attributes;
+ debugf1("%s()\n", __func__);
- /* loop if there are attributes and until we hit a NULL entry */
- while (sysfs_attrib && sysfs_attrib->attr.name) {
- sysfs_remove_file(&mci->edac_mci_kobj,
- (struct attribute *) sysfs_attrib);
+ /*
+ * loop if there are attributes and until we hit a NULL entry
+ * Remove first all the atributes
+ */
+ while (sysfs_attrib) {
+ if (sysfs_attrib->grp) {
+ list_for_each_entry(grp_kobj, &mci->grp_kobj_list,
+ list)
+ if (grp_kobj->grp == sysfs_attrib->grp)
+ edac_remove_mci_instance_attributes(mci,
+ grp_kobj->grp->mcidev_attr,
+ &grp_kobj->kobj, count + 1);
+ } else if (sysfs_attrib->attr.name) {
+ debugf0("%s() file %s\n", __func__,
+ sysfs_attrib->attr.name);
+ sysfs_remove_file(kobj, &sysfs_attrib->attr);
+ } else
+ break;
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);
+ }
}
@@ -793,6 +910,8 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
+ INIT_LIST_HEAD(&mci->grp_kobj_list);
+
/* create a symlink for the device */
err = sysfs_create_link(kobj_mci, &mci->dev->kobj,
EDAC_DEVICE_SYMLINK);
@@ -805,7 +924,9 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
* then create them now for the driver.
*/
if (mci->mc_driver_sysfs_attributes) {
- err = edac_create_mci_instance_attributes(mci);
+ err = edac_create_mci_instance_attributes(mci,
+ mci->mc_driver_sysfs_attributes,
+ &mci->edac_mci_kobj);
if (err) {
debugf1("%s() failure to create mci attributes\n",
__func__);
@@ -840,7 +961,8 @@ fail1:
}
/* remove the mci instance's attributes, if any */
- edac_remove_mci_instance_attributes(mci);
+ edac_remove_mci_instance_attributes(mci,
+ mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj, 0);
/* remove the symlink */
sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK);
@@ -874,8 +996,9 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
debugf0("%s() remove_mci_instance\n", __func__);
/* remove this mci instance's attribtes */
- edac_remove_mci_instance_attributes(mci);
-
+ 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 */
diff --git a/drivers/edac/edac_mce.c b/drivers/edac/edac_mce.c
new file mode 100644
index 000000000000..9ccdc5b140e7
--- /dev/null
+++ b/drivers/edac/edac_mce.c
@@ -0,0 +1,61 @@
+/* Provides edac interface to mcelog events
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License version 2.
+ *
+ * Copyright (c) 2009 by:
+ * Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Red Hat Inc. http://www.redhat.com
+ */
+
+#include <linux/module.h>
+#include <linux/edac_mce.h>
+#include <asm/mce.h>
+
+int edac_mce_enabled;
+EXPORT_SYMBOL_GPL(edac_mce_enabled);
+
+
+/*
+ * Extension interface
+ */
+
+static LIST_HEAD(edac_mce_list);
+static DEFINE_MUTEX(edac_mce_lock);
+
+int edac_mce_register(struct edac_mce *edac_mce)
+{
+ mutex_lock(&edac_mce_lock);
+ list_add_tail(&edac_mce->list, &edac_mce_list);
+ mutex_unlock(&edac_mce_lock);
+ return 0;
+}
+EXPORT_SYMBOL(edac_mce_register);
+
+void edac_mce_unregister(struct edac_mce *edac_mce)
+{
+ mutex_lock(&edac_mce_lock);
+ list_del(&edac_mce->list);
+ mutex_unlock(&edac_mce_lock);
+}
+EXPORT_SYMBOL(edac_mce_unregister);
+
+int edac_mce_parse(struct mce *mce)
+{
+ struct edac_mce *edac_mce;
+
+ list_for_each_entry(edac_mce, &edac_mce_list, list) {
+ if (edac_mce->check_error(edac_mce->priv, mce))
+ return 1;
+ }
+
+ /* Nobody queued the error */
+ return 0;
+}
+EXPORT_SYMBOL_GPL(edac_mce_parse);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_DESCRIPTION("EDAC Driver for mcelog captured errors");
diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c
index 713ed7d37247..689cc6a6214d 100644
--- a/drivers/edac/edac_mce_amd.c
+++ b/drivers/edac/edac_mce_amd.c
@@ -3,7 +3,6 @@
static bool report_gart_errors;
static void (*nb_bus_decoder)(int node_id, struct err_regs *regs);
-static void (*orig_mce_callback)(struct mce *m);
void amd_report_gart_errors(bool v)
{
@@ -363,8 +362,10 @@ static inline void amd_decode_err_code(unsigned int ec)
pr_warning("Huh? Unknown MCE error 0x%x\n", ec);
}
-static void amd_decode_mce(struct mce *m)
+static int amd_decode_mce(struct notifier_block *nb, unsigned long val,
+ void *data)
{
+ struct mce *m = (struct mce *)data;
struct err_regs regs;
int node, ecc;
@@ -420,20 +421,22 @@ static void amd_decode_mce(struct mce *m)
}
amd_decode_err_code(m->status & 0xffff);
+
+ return NOTIFY_STOP;
}
+static struct notifier_block amd_mce_dec_nb = {
+ .notifier_call = amd_decode_mce,
+};
+
static int __init mce_amd_init(void)
{
/*
* We can decode MCEs for Opteron and later CPUs:
*/
if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
- (boot_cpu_data.x86 >= 0xf)) {
- /* safe the default decode mce callback */
- orig_mce_callback = x86_mce_decode_callback;
-
- x86_mce_decode_callback = amd_decode_mce;
- }
+ (boot_cpu_data.x86 >= 0xf))
+ atomic_notifier_chain_register(&x86_mce_decoder_chain, &amd_mce_dec_nb);
return 0;
}
@@ -442,7 +445,7 @@ early_initcall(mce_amd_init);
#ifdef MODULE
static void __exit mce_amd_exit(void)
{
- x86_mce_decode_callback = orig_mce_callback;
+ atomic_notifier_chain_unregister(&x86_mce_decoder_chain, &amd_mce_dec_nb);
}
MODULE_DESCRIPTION("AMD MCE decoder");
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
new file mode 100644
index 000000000000..b6fce2e38e3d
--- /dev/null
+++ b/drivers/edac/i7core_edac.c
@@ -0,0 +1,1974 @@
+/* Intel 7 core Memory Controller kernel module (Nehalem)
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License version 2 only.
+ *
+ * Copyright (c) 2009 by:
+ * Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Red Hat Inc. http://www.redhat.com
+ *
+ * Forked and adapted from the i5400_edac driver
+ *
+ * Based on the following public Intel datasheets:
+ * Intel Core i7 Processor Extreme Edition and Intel Core i7 Processor
+ * Datasheet, Volume 2:
+ * http://download.intel.com/design/processor/datashts/320835.pdf
+ * Intel Xeon Processor 5500 Series Datasheet Volume 2
+ * http://www.intel.com/Assets/PDF/datasheet/321322.pdf
+ * also available at:
+ * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
+ */
+
+#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 <linux/edac_mce.h>
+#include <linux/smp.h>
+#include <asm/processor.h>
+
+#include "edac_core.h"
+
+/*
+ * 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.
+ * We currently find devices with only 2 sockets. In order to support more QPI
+ * Quick Path Interconnect, just increment this number.
+ */
+#define MAX_SOCKET_BUSES 2
+
+
+/*
+ * Alter this version for the module when modifications are made
+ */
+#define I7CORE_REVISION " Ver: 1.0.0 " __DATE__
+#define EDAC_MOD_STR "i7core_edac"
+
+/*
+ * Debug macros
+ */
+#define i7core_printk(level, fmt, arg...) \
+ edac_printk(level, "i7core", fmt, ##arg)
+
+#define i7core_mc_printk(mci, level, fmt, arg...) \
+ edac_mc_chipset_printk(mci, level, "i7core", fmt, ##arg)
+
+/*
+ * i7core Memory Controller Registers
+ */
+
+ /* OFFSETS for Device 0 Function 0 */
+
+#define MC_CFG_CONTROL 0x90
+
+ /* OFFSETS for Device 3 Function 0 */
+
+#define MC_CONTROL 0x48
+#define MC_STATUS 0x4c
+#define MC_MAX_DOD 0x64
+
+/*
+ * OFFSETS for Device 3 Function 4, as inicated on Xeon 5500 datasheet:
+ * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
+ */
+
+#define MC_TEST_ERR_RCV1 0x60
+ #define DIMM2_COR_ERR(r) ((r) & 0x7fff)
+
+#define MC_TEST_ERR_RCV0 0x64
+ #define DIMM1_COR_ERR(r) (((r) >> 16) & 0x7fff)
+ #define DIMM0_COR_ERR(r) ((r) & 0x7fff)
+
+/* OFFSETS for Device 3 Function 2, as inicated on Xeon 5500 datasheet */
+#define MC_COR_ECC_CNT_0 0x80
+#define MC_COR_ECC_CNT_1 0x84
+#define MC_COR_ECC_CNT_2 0x88
+#define MC_COR_ECC_CNT_3 0x8c
+#define MC_COR_ECC_CNT_4 0x90
+#define MC_COR_ECC_CNT_5 0x94
+
+#define DIMM_TOP_COR_ERR(r) (((r) >> 16) & 0x7fff)
+#define DIMM_BOT_COR_ERR(r) ((r) & 0x7fff)
+
+
+ /* OFFSETS for Devices 4,5 and 6 Function 0 */
+
+#define MC_CHANNEL_DIMM_INIT_PARAMS 0x58
+ #define THREE_DIMMS_PRESENT (1 << 24)
+ #define SINGLE_QUAD_RANK_PRESENT (1 << 23)
+ #define QUAD_RANK_PRESENT (1 << 22)
+ #define REGISTERED_DIMM (1 << 15)
+
+#define MC_CHANNEL_MAPPER 0x60
+ #define RDLCH(r, ch) ((((r) >> (3 + (ch * 6))) & 0x07) - 1)
+ #define WRLCH(r, ch) ((((r) >> (ch * 6)) & 0x07) - 1)
+
+#define MC_CHANNEL_RANK_PRESENT 0x7c
+ #define RANK_PRESENT_MASK 0xffff
+
+#define MC_CHANNEL_ADDR_MATCH 0xf0
+#define MC_CHANNEL_ERROR_MASK 0xf8
+#define MC_CHANNEL_ERROR_INJECT 0xfc
+ #define INJECT_ADDR_PARITY 0x10
+ #define INJECT_ECC 0x08
+ #define MASK_CACHELINE 0x06
+ #define MASK_FULL_CACHELINE 0x06
+ #define MASK_MSB32_CACHELINE 0x04
+ #define MASK_LSB32_CACHELINE 0x02
+ #define NO_MASK_CACHELINE 0x00
+ #define REPEAT_EN 0x01
+
+ /* OFFSETS for Devices 4,5 and 6 Function 1 */
+
+#define MC_DOD_CH_DIMM0 0x48
+#define MC_DOD_CH_DIMM1 0x4c
+#define MC_DOD_CH_DIMM2 0x50
+ #define RANKOFFSET_MASK ((1 << 12) | (1 << 11) | (1 << 10))
+ #define RANKOFFSET(x) ((x & RANKOFFSET_MASK) >> 10)
+ #define DIMM_PRESENT_MASK (1 << 9)
+ #define DIMM_PRESENT(x) (((x) & DIMM_PRESENT_MASK) >> 9)
+ #define MC_DOD_NUMBANK_MASK ((1 << 8) | (1 << 7))
+ #define MC_DOD_NUMBANK(x) (((x) & MC_DOD_NUMBANK_MASK) >> 7)
+ #define MC_DOD_NUMRANK_MASK ((1 << 6) | (1 << 5))
+ #define MC_DOD_NUMRANK(x) (((x) & MC_DOD_NUMRANK_MASK) >> 5)
+ #define MC_DOD_NUMROW_MASK ((1 << 4) | (1 << 3) | (1 << 2))
+ #define MC_DOD_NUMROW(x) (((x) & MC_DOD_NUMROW_MASK) >> 2)
+ #define MC_DOD_NUMCOL_MASK 3
+ #define MC_DOD_NUMCOL(x) ((x) & MC_DOD_NUMCOL_MASK)
+
+#define MC_RANK_PRESENT 0x7c
+
+#define MC_SAG_CH_0 0x80
+#define MC_SAG_CH_1 0x84
+#define MC_SAG_CH_2 0x88
+#define MC_SAG_CH_3 0x8c
+#define MC_SAG_CH_4 0x90
+#define MC_SAG_CH_5 0x94
+#define MC_SAG_CH_6 0x98
+#define MC_SAG_CH_7 0x9c
+
+#define MC_RIR_LIMIT_CH_0 0x40
+#define MC_RIR_LIMIT_CH_1 0x44
+#define MC_RIR_LIMIT_CH_2 0x48
+#define MC_RIR_LIMIT_CH_3 0x4C
+#define MC_RIR_LIMIT_CH_4 0x50
+#define MC_RIR_LIMIT_CH_5 0x54
+#define MC_RIR_LIMIT_CH_6 0x58
+#define MC_RIR_LIMIT_CH_7 0x5C
+#define MC_RIR_LIMIT_MASK ((1 << 10) - 1)
+
+#define MC_RIR_WAY_CH 0x80
+ #define MC_RIR_WAY_OFFSET_MASK (((1 << 14) - 1) & ~0x7)
+ #define MC_RIR_WAY_RANK_MASK 0x7
+
+/*
+ * i7core structs
+ */
+
+#define NUM_CHANS 3
+#define MAX_DIMMS 3 /* Max DIMMS per channel */
+#define MAX_MCR_FUNC 4
+#define MAX_CHAN_FUNC 3
+
+struct i7core_info {
+ u32 mc_control;
+ u32 mc_status;
+ u32 max_dod;
+ u32 ch_map;
+};
+
+
+struct i7core_inject {
+ int enable;
+
+ u32 section;
+ u32 type;
+ u32 eccmask;
+
+ /* Error address mask */
+ int channel, dimm, rank, bank, page, col;
+};
+
+struct i7core_channel {
+ u32 ranks;
+ u32 dimms;
+};
+
+struct pci_id_descr {
+ int dev;
+ int func;
+ int dev_id;
+ int optional;
+};
+
+struct i7core_dev {
+ struct list_head list;
+ u8 socket;
+ struct pci_dev **pdev;
+ int n_devs;
+ struct mem_ctl_info *mci;
+};
+
+struct i7core_pvt {
+ struct pci_dev *pci_noncore;
+ struct pci_dev *pci_mcr[MAX_MCR_FUNC + 1];
+ struct pci_dev *pci_ch[NUM_CHANS][MAX_CHAN_FUNC + 1];
+
+ struct i7core_dev *i7core_dev;
+
+ struct i7core_info info;
+ 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];
+
+ /* ECC corrected errors counts per udimm */
+ unsigned long udimm_ce_count[MAX_DIMMS];
+ int udimm_last_ce_count[MAX_DIMMS];
+ /* ECC corrected errors counts per rdimm */
+ unsigned long rdimm_ce_count[NUM_CHANS][MAX_DIMMS];
+ int rdimm_last_ce_count[NUM_CHANS][MAX_DIMMS];
+
+ unsigned int is_registered;
+
+ /* mcelog glue */
+ struct edac_mce edac_mce;
+
+ /* Fifo double buffers */
+ struct mce mce_entry[MCE_LOG_LEN];
+ struct mce mce_outentry[MCE_LOG_LEN];
+
+ /* Fifo in/out counters */
+ unsigned mce_in, mce_out;
+
+ /* Count indicator to show errors not got */
+ unsigned mce_overrun;
+};
+
+/* Static vars */
+static LIST_HEAD(i7core_edac_list);
+static DEFINE_MUTEX(i7core_edac_lock);
+
+#define PCI_DESCR(device, function, device_id) \
+ .dev = (device), \
+ .func = (function), \
+ .dev_id = (device_id)
+
+struct pci_id_descr pci_dev_descr_i7core[] = {
+ /* 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 */
+ { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS), .optional = 1 },
+ { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) },
+
+ /* Channel 0 */
+ { PCI_DESCR(4, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL) },
+ { PCI_DESCR(4, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH0_ADDR) },
+ { PCI_DESCR(4, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH0_RANK) },
+ { PCI_DESCR(4, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH0_TC) },
+
+ /* Channel 1 */
+ { PCI_DESCR(5, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL) },
+ { PCI_DESCR(5, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH1_ADDR) },
+ { PCI_DESCR(5, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH1_RANK) },
+ { PCI_DESCR(5, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH1_TC) },
+
+ /* Channel 2 */
+ { PCI_DESCR(6, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL) },
+ { 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) },
+
+};
+
+/*
+ * pci_device_id table for which devices we are looking for
+ */
+static const struct pci_device_id i7core_pci_tbl[] __devinitdata = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)},
+ {0,} /* 0 terminated list. */
+};
+
+static struct edac_pci_ctl_info *i7core_pci;
+
+/****************************************************************************
+ Anciliary status routines
+ ****************************************************************************/
+
+ /* MC_CONTROL bits */
+#define CH_ACTIVE(pvt, ch) ((pvt)->info.mc_control & (1 << (8 + ch)))
+#define ECCx8(pvt) ((pvt)->info.mc_control & (1 << 1))
+
+ /* MC_STATUS bits */
+#define ECC_ENABLED(pvt) ((pvt)->info.mc_status & (1 << 4))
+#define CH_DISABLED(pvt, ch) ((pvt)->info.mc_status & (1 << ch))
+
+ /* MC_MAX_DOD read functions */
+static inline int numdimms(u32 dimms)
+{
+ return (dimms & 0x3) + 1;
+}
+
+static inline int numrank(u32 rank)
+{
+ static int ranks[4] = { 1, 2, 4, -EINVAL };
+
+ return ranks[rank & 0x3];
+}
+
+static inline int numbank(u32 bank)
+{
+ static int banks[4] = { 4, 8, 16, -EINVAL };
+
+ return banks[bank & 0x3];
+}
+
+static inline int numrow(u32 row)
+{
+ static int rows[8] = {
+ 1 << 12, 1 << 13, 1 << 14, 1 << 15,
+ 1 << 16, -EINVAL, -EINVAL, -EINVAL,
+ };
+
+ return rows[row & 0x7];
+}
+
+static inline int numcol(u32 col)
+{
+ static int cols[8] = {
+ 1 << 10, 1 << 11, 1 << 12, -EINVAL,
+ };
+ return cols[col & 0x3];
+}
+
+static struct i7core_dev *get_i7core_dev(u8 socket)
+{
+ struct i7core_dev *i7core_dev;
+
+ list_for_each_entry(i7core_dev, &i7core_edac_list, list) {
+ if (i7core_dev->socket == socket)
+ return i7core_dev;
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Memory check routines
+ ****************************************************************************/
+static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot,
+ unsigned func)
+{
+ struct i7core_dev *i7core_dev = get_i7core_dev(socket);
+ int i;
+
+ if (!i7core_dev)
+ return NULL;
+
+ for (i = 0; i < i7core_dev->n_devs; i++) {
+ if (!i7core_dev->pdev[i])
+ continue;
+
+ if (PCI_SLOT(i7core_dev->pdev[i]->devfn) == slot &&
+ PCI_FUNC(i7core_dev->pdev[i]->devfn) == func) {
+ return i7core_dev->pdev[i];
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * i7core_get_active_channels() - gets the number of channels and csrows
+ * @socket: Quick Path Interconnect socket
+ * @channels: Number of channels that will be returned
+ * @csrows: Number of csrows found
+ *
+ * Since EDAC core needs to know in advance the number of available channels
+ * and csrows, in order to allocate memory for csrows/channels, it is needed
+ * to run two similar steps. At the first step, implemented on this function,
+ * it checks the number of csrows/channels present at one socket.
+ * this is used in order to properly allocate the size of mci components.
+ *
+ * It should be noticed that none of the current available datasheets explain
+ * or even mention how csrows are seen by the memory controller. So, we need
+ * 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,
+ unsigned *csrows)
+{
+ struct pci_dev *pdev = NULL;
+ int i, j;
+ u32 status, control;
+
+ *channels = 0;
+ *csrows = 0;
+
+ pdev = get_pdev_slot_func(socket, 3, 0);
+ if (!pdev) {
+ i7core_printk(KERN_ERR, "Couldn't find socket %d fn 3.0!!!\n",
+ socket);
+ return -ENODEV;
+ }
+
+ /* Device 3 function 0 reads */
+ pci_read_config_dword(pdev, MC_STATUS, &status);
+ pci_read_config_dword(pdev, MC_CONTROL, &control);
+
+ for (i = 0; i < NUM_CHANS; i++) {
+ u32 dimm_dod[3];
+ /* Check if the channel is active */
+ if (!(control & (1 << (8 + i))))
+ continue;
+
+ /* Check if the channel is disabled */
+ if (status & (1 << i))
+ continue;
+
+ pdev = get_pdev_slot_func(socket, i + 4, 1);
+ if (!pdev) {
+ i7core_printk(KERN_ERR, "Couldn't find socket %d "
+ "fn %d.%d!!!\n",
+ socket, i + 4, 1);
+ return -ENODEV;
+ }
+ /* Devices 4-6 function 1 */
+ pci_read_config_dword(pdev,
+ MC_DOD_CH_DIMM0, &dimm_dod[0]);
+ pci_read_config_dword(pdev,
+ MC_DOD_CH_DIMM1, &dimm_dod[1]);
+ pci_read_config_dword(pdev,
+ MC_DOD_CH_DIMM2, &dimm_dod[2]);
+
+ (*channels)++;
+
+ for (j = 0; j < 3; j++) {
+ if (!DIMM_PRESENT(dimm_dod[j]))
+ continue;
+ (*csrows)++;
+ }
+ }
+
+ debugf0("Number of active channels on socket %d: %d\n",
+ socket, *channels);
+
+ return 0;
+}
+
+static int get_dimm_config(struct mem_ctl_info *mci, int *csrow)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ struct csrow_info *csr;
+ struct pci_dev *pdev;
+ int i, j;
+ unsigned long last_page = 0;
+ enum edac_type mode;
+ enum mem_type mtype;
+
+ /* Get data from the MC register, function 0 */
+ pdev = pvt->pci_mcr[0];
+ if (!pdev)
+ return -ENODEV;
+
+ /* Device 3 function 0 reads */
+ pci_read_config_dword(pdev, MC_CONTROL, &pvt->info.mc_control);
+ pci_read_config_dword(pdev, MC_STATUS, &pvt->info.mc_status);
+ pci_read_config_dword(pdev, MC_MAX_DOD, &pvt->info.max_dod);
+ pci_read_config_dword(pdev, MC_CHANNEL_MAPPER, &pvt->info.ch_map);
+
+ debugf0("QPI %d control=0x%08x status=0x%08x dod=0x%08x map=0x%08x\n",
+ pvt->i7core_dev->socket, pvt->info.mc_control, pvt->info.mc_status,
+ pvt->info.max_dod, pvt->info.ch_map);
+
+ if (ECC_ENABLED(pvt)) {
+ debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt) ? 8 : 4);
+ if (ECCx8(pvt))
+ mode = EDAC_S8ECD8ED;
+ else
+ mode = EDAC_S4ECD4ED;
+ } else {
+ debugf0("ECC disabled\n");
+ mode = EDAC_NONE;
+ }
+
+ /* FIXME: need to handle the error codes */
+ debugf0("DOD Max limits: DIMMS: %d, %d-ranked, %d-banked "
+ "x%x x 0x%x\n",
+ numdimms(pvt->info.max_dod),
+ numrank(pvt->info.max_dod >> 2),
+ numbank(pvt->info.max_dod >> 4),
+ numrow(pvt->info.max_dod >> 6),
+ numcol(pvt->info.max_dod >> 9));
+
+ for (i = 0; i < NUM_CHANS; i++) {
+ u32 data, dimm_dod[3], value[8];
+
+ if (!CH_ACTIVE(pvt, i)) {
+ debugf0("Channel %i is not active\n", i);
+ continue;
+ }
+ if (CH_DISABLED(pvt, i)) {
+ debugf0("Channel %i is disabled\n", i);
+ continue;
+ }
+
+ /* Devices 4-6 function 0 */
+ pci_read_config_dword(pvt->pci_ch[i][0],
+ MC_CHANNEL_DIMM_INIT_PARAMS, &data);
+
+ pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT) ?
+ 4 : 2;
+
+ if (data & REGISTERED_DIMM)
+ mtype = MEM_RDDR3;
+ else
+ mtype = MEM_DDR3;
+#if 0
+ if (data & THREE_DIMMS_PRESENT)
+ pvt->channel[i].dimms = 3;
+ else if (data & SINGLE_QUAD_RANK_PRESENT)
+ pvt->channel[i].dimms = 1;
+ else
+ pvt->channel[i].dimms = 2;
+#endif
+
+ /* Devices 4-6 function 1 */
+ pci_read_config_dword(pvt->pci_ch[i][1],
+ MC_DOD_CH_DIMM0, &dimm_dod[0]);
+ pci_read_config_dword(pvt->pci_ch[i][1],
+ MC_DOD_CH_DIMM1, &dimm_dod[1]);
+ pci_read_config_dword(pvt->pci_ch[i][1],
+ MC_DOD_CH_DIMM2, &dimm_dod[2]);
+
+ debugf0("Ch%d phy rd%d, wr%d (0x%08x): "
+ "%d ranks, %cDIMMs\n",
+ i,
+ RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i),
+ data,
+ pvt->channel[i].ranks,
+ (data & REGISTERED_DIMM) ? 'R' : 'U');
+
+ for (j = 0; j < 3; j++) {
+ u32 banks, ranks, rows, cols;
+ u32 size, npages;
+
+ if (!DIMM_PRESENT(dimm_dod[j]))
+ continue;
+
+ banks = numbank(MC_DOD_NUMBANK(dimm_dod[j]));
+ ranks = numrank(MC_DOD_NUMRANK(dimm_dod[j]));
+ rows = numrow(MC_DOD_NUMROW(dimm_dod[j]));
+ cols = numcol(MC_DOD_NUMCOL(dimm_dod[j]));
+
+ /* DDR3 has 8 I/O banks */
+ size = (rows * cols * banks * ranks) >> (20 - 3);
+
+ pvt->channel[i].dimms++;
+
+ debugf0("\tdimm %d %d Mb offset: %x, "
+ "bank: %d, rank: %d, row: %#x, col: %#x\n",
+ j, size,
+ RANKOFFSET(dimm_dod[j]),
+ banks, ranks, rows, cols);
+
+#if PAGE_SHIFT > 20
+ npages = size >> (PAGE_SHIFT - 20);
+#else
+ npages = size << (20 - PAGE_SHIFT);
+#endif
+
+ csr = &mci->csrows[*csrow];
+ csr->first_page = last_page + 1;
+ last_page += npages;
+ csr->last_page = last_page;
+ csr->nr_pages = npages;
+
+ csr->page_mask = 0;
+ csr->grain = 8;
+ 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;
+
+ switch (banks) {
+ case 4:
+ csr->dtype = DEV_X4;
+ break;
+ case 8:
+ csr->dtype = DEV_X8;
+ break;
+ case 16:
+ csr->dtype = DEV_X16;
+ break;
+ default:
+ csr->dtype = DEV_UNKNOWN;
+ }
+
+ csr->edac_mode = mode;
+ csr->mtype = mtype;
+
+ (*csrow)++;
+ }
+
+ pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]);
+ pci_read_config_dword(pdev, MC_SAG_CH_1, &value[1]);
+ pci_read_config_dword(pdev, MC_SAG_CH_2, &value[2]);
+ pci_read_config_dword(pdev, MC_SAG_CH_3, &value[3]);
+ pci_read_config_dword(pdev, MC_SAG_CH_4, &value[4]);
+ pci_read_config_dword(pdev, MC_SAG_CH_5, &value[5]);
+ pci_read_config_dword(pdev, MC_SAG_CH_6, &value[6]);
+ pci_read_config_dword(pdev, MC_SAG_CH_7, &value[7]);
+ debugf1("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i);
+ for (j = 0; j < 8; j++)
+ debugf1("\t\t%#x\t%#x\t%#x\n",
+ (value[j] >> 27) & 0x1,
+ (value[j] >> 24) & 0x7,
+ (value[j] && ((1 << 24) - 1)));
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ Error insertion routines
+ ****************************************************************************/
+
+/* The i7core has independent error injection features per channel.
+ However, to have a simpler code, we don't allow enabling error injection
+ on more than one channel.
+ Also, since a change at an inject parameter will be applied only at enable,
+ 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)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+
+ pvt->inject.enable = 0;
+
+ if (!pvt->pci_ch[pvt->inject.channel][0])
+ return -ENODEV;
+
+ pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0],
+ MC_CHANNEL_ERROR_INJECT, 0);
+
+ return 0;
+}
+
+/*
+ * i7core inject inject.section
+ *
+ * accept and store error injection inject.section value
+ * bit 0 - refers to the lower 32-byte half cacheline
+ * bit 1 - refers to the upper 32-byte half cacheline
+ */
+static ssize_t i7core_inject_section_store(struct mem_ctl_info *mci,
+ const char *data, size_t count)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ unsigned long value;
+ int rc;
+
+ if (pvt->inject.enable)
+ disable_inject(mci);
+
+ rc = strict_strtoul(data, 10, &value);
+ if ((rc < 0) || (value > 3))
+ return -EIO;
+
+ pvt->inject.section = (u32) value;
+ return count;
+}
+
+static ssize_t i7core_inject_section_show(struct mem_ctl_info *mci,
+ char *data)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ return sprintf(data, "0x%08x\n", pvt->inject.section);
+}
+
+/*
+ * i7core inject.type
+ *
+ * accept and store error injection inject.section value
+ * bit 0 - repeat enable - Enable error repetition
+ * bit 1 - inject ECC error
+ * bit 2 - inject parity error
+ */
+static ssize_t i7core_inject_type_store(struct mem_ctl_info *mci,
+ const char *data, size_t count)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ unsigned long value;
+ int rc;
+
+ if (pvt->inject.enable)
+ disable_inject(mci);
+
+ rc = strict_strtoul(data, 10, &value);
+ if ((rc < 0) || (value > 7))
+ return -EIO;
+
+ pvt->inject.type = (u32) value;
+ return count;
+}
+
+static ssize_t i7core_inject_type_show(struct mem_ctl_info *mci,
+ char *data)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ return sprintf(data, "0x%08x\n", pvt->inject.type);
+}
+
+/*
+ * i7core_inject_inject.eccmask_store
+ *
+ * The type of error (UE/CE) will depend on the inject.eccmask value:
+ * Any bits set to a 1 will flip the corresponding ECC bit
+ * Correctable errors can be injected by flipping 1 bit or the bits within
+ * a symbol pair (2 consecutive aligned 8-bit pairs - i.e. 7:0 and 15:8 or
+ * 23:16 and 31:24). Flipping bits in two symbol pairs will cause an
+ * uncorrectable error to be injected.
+ */
+static ssize_t i7core_inject_eccmask_store(struct mem_ctl_info *mci,
+ const char *data, size_t count)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ unsigned long value;
+ int rc;
+
+ if (pvt->inject.enable)
+ disable_inject(mci);
+
+ rc = strict_strtoul(data, 10, &value);
+ if (rc < 0)
+ return -EIO;
+
+ pvt->inject.eccmask = (u32) value;
+ return count;
+}
+
+static ssize_t i7core_inject_eccmask_show(struct mem_ctl_info *mci,
+ char *data)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ return sprintf(data, "0x%08x\n", pvt->inject.eccmask);
+}
+
+/*
+ * i7core_addrmatch
+ *
+ * The type of error (UE/CE) will depend on the inject.eccmask value:
+ * Any bits set to a 1 will flip the corresponding ECC bit
+ * Correctable errors can be injected by flipping 1 bit or the bits within
+ * a symbol pair (2 consecutive aligned 8-bit pairs - i.e. 7:0 and 15:8 or
+ * 23:16 and 31:24). Flipping bits in two symbol pairs will cause an
+ * uncorrectable error to be injected.
+ */
+
+#define DECLARE_ADDR_MATCH(param, limit) \
+static ssize_t i7core_inject_store_##param( \
+ struct mem_ctl_info *mci, \
+ const char *data, size_t count) \
+{ \
+ struct i7core_pvt *pvt; \
+ long value; \
+ int rc; \
+ \
+ debugf1("%s()\n", __func__); \
+ pvt = mci->pvt_info; \
+ \
+ if (pvt->inject.enable) \
+ disable_inject(mci); \
+ \
+ if (!strcasecmp(data, "any") || !strcasecmp(data, "any\n"))\
+ value = -1; \
+ else { \
+ rc = strict_strtoul(data, 10, &value); \
+ if ((rc < 0) || (value >= limit)) \
+ return -EIO; \
+ } \
+ \
+ pvt->inject.param = value; \
+ \
+ return count; \
+} \
+ \
+static ssize_t i7core_inject_show_##param( \
+ struct mem_ctl_info *mci, \
+ char *data) \
+{ \
+ struct i7core_pvt *pvt; \
+ \
+ pvt = mci->pvt_info; \
+ debugf1("%s() pvt=%p\n", __func__, pvt); \
+ if (pvt->inject.param < 0) \
+ return sprintf(data, "any\n"); \
+ else \
+ return sprintf(data, "%d\n", pvt->inject.param);\
+}
+
+#define ATTR_ADDR_MATCH(param) \
+ { \
+ .attr = { \
+ .name = #param, \
+ .mode = (S_IRUGO | S_IWUSR) \
+ }, \
+ .show = i7core_inject_show_##param, \
+ .store = i7core_inject_store_##param, \
+ }
+
+DECLARE_ADDR_MATCH(channel, 3);
+DECLARE_ADDR_MATCH(dimm, 3);
+DECLARE_ADDR_MATCH(rank, 4);
+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)
+{
+ u32 read;
+ int count;
+
+ debugf0("setting pci %02x:%02x.%x reg=%02x value=%08x\n",
+ dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+ where, val);
+
+ for (count = 0; count < 10; count++) {
+ if (count)
+ msleep(100);
+ pci_write_config_dword(dev, where, val);
+ pci_read_config_dword(dev, where, &read);
+
+ if (read == val)
+ return 0;
+ }
+
+ i7core_printk(KERN_ERR, "Error during set pci %02x:%02x.%x reg=%02x "
+ "write=%08x. Read=%08x\n",
+ dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+ where, val, read);
+
+ return -EINVAL;
+}
+
+/*
+ * This routine prepares the Memory Controller for error injection.
+ * The error will be injected when some process tries to write to the
+ * memory that matches the given criteria.
+ * The criteria can be set in terms of a mask where dimm, rank, bank, page
+ * and col can be specified.
+ * A -1 value for any of the mask items will make the MCU to ignore
+ * that matching criteria for error injection.
+ *
+ * It should be noticed that the error will only happen after a write operation
+ * on a memory that matches the condition. if REPEAT_EN is not enabled at
+ * inject mask, then it will produce just one error. Otherwise, it will repeat
+ * until the injectmask would be cleaned.
+ *
+ * FIXME: This routine assumes that MAXNUMDIMMS value of MC_MAX_DOD
+ * is reliable enough to check if the MC is using the
+ * three channels. However, this is not clear at the datasheet.
+ */
+static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci,
+ const char *data, size_t count)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ u32 injectmask;
+ u64 mask = 0;
+ int rc;
+ long enable;
+
+ if (!pvt->pci_ch[pvt->inject.channel][0])
+ return 0;
+
+ rc = strict_strtoul(data, 10, &enable);
+ if ((rc < 0))
+ return 0;
+
+ if (enable) {
+ pvt->inject.enable = 1;
+ } else {
+ disable_inject(mci);
+ return count;
+ }
+
+ /* Sets pvt->inject.dimm mask */
+ if (pvt->inject.dimm < 0)
+ mask |= 1L << 41;
+ else {
+ if (pvt->channel[pvt->inject.channel].dimms > 2)
+ mask |= (pvt->inject.dimm & 0x3L) << 35;
+ else
+ mask |= (pvt->inject.dimm & 0x1L) << 36;
+ }
+
+ /* Sets pvt->inject.rank mask */
+ if (pvt->inject.rank < 0)
+ mask |= 1L << 40;
+ else {
+ if (pvt->channel[pvt->inject.channel].dimms > 2)
+ mask |= (pvt->inject.rank & 0x1L) << 34;
+ else
+ mask |= (pvt->inject.rank & 0x3L) << 34;
+ }
+
+ /* Sets pvt->inject.bank mask */
+ if (pvt->inject.bank < 0)
+ mask |= 1L << 39;
+ else
+ mask |= (pvt->inject.bank & 0x15L) << 30;
+
+ /* Sets pvt->inject.page mask */
+ if (pvt->inject.page < 0)
+ mask |= 1L << 38;
+ else
+ mask |= (pvt->inject.page & 0xffffL) << 14;
+
+ /* Sets pvt->inject.column mask */
+ if (pvt->inject.col < 0)
+ mask |= 1L << 37;
+ else
+ mask |= (pvt->inject.col & 0x3fffL);
+
+ /*
+ * bit 0: REPEAT_EN
+ * bits 1-2: MASK_HALF_CACHELINE
+ * bit 3: INJECT_ECC
+ * bit 4: INJECT_ADDR_PARITY
+ */
+
+ injectmask = (pvt->inject.type & 1) |
+ (pvt->inject.section & 0x3) << 1 |
+ (pvt->inject.type & 0x6) << (3 - 1);
+
+ /* Unlock writes to registers - this register is write only */
+ pci_write_config_dword(pvt->pci_noncore,
+ MC_CFG_CONTROL, 0x2);
+
+ write_and_test(pvt->pci_ch[pvt->inject.channel][0],
+ MC_CHANNEL_ADDR_MATCH, mask);
+ write_and_test(pvt->pci_ch[pvt->inject.channel][0],
+ MC_CHANNEL_ADDR_MATCH + 4, mask >> 32L);
+
+ write_and_test(pvt->pci_ch[pvt->inject.channel][0],
+ MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask);
+
+ write_and_test(pvt->pci_ch[pvt->inject.channel][0],
+ MC_CHANNEL_ERROR_INJECT, injectmask);
+
+ /*
+ * This is something undocumented, based on my tests
+ * Without writing 8 to this register, errors aren't injected. Not sure
+ * why.
+ */
+ pci_write_config_dword(pvt->pci_noncore,
+ MC_CFG_CONTROL, 8);
+
+ debugf0("Error inject addr match 0x%016llx, ecc 0x%08x,"
+ " inject 0x%08x\n",
+ mask, pvt->inject.eccmask, injectmask);
+
+
+ return count;
+}
+
+static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci,
+ char *data)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ u32 injectmask;
+
+ pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0],
+ MC_CHANNEL_ERROR_INJECT, &injectmask);
+
+ debugf0("Inject error read: 0x%018x\n", injectmask);
+
+ if (injectmask & 0x0c)
+ pvt->inject.enable = 1;
+
+ return sprintf(data, "%d\n", pvt->inject.enable);
+}
+
+#define DECLARE_COUNTER(param) \
+static ssize_t i7core_show_counter_##param( \
+ struct mem_ctl_info *mci, \
+ char *data) \
+{ \
+ struct i7core_pvt *pvt = mci->pvt_info; \
+ \
+ debugf1("%s() \n", __func__); \
+ if (!pvt->ce_count_available || (pvt->is_registered)) \
+ return sprintf(data, "data unavailable\n"); \
+ return sprintf(data, "%lu\n", \
+ pvt->udimm_ce_count[param]); \
+}
+
+#define ATTR_COUNTER(param) \
+ { \
+ .attr = { \
+ .name = __stringify(udimm##param), \
+ .mode = (S_IRUGO | S_IWUSR) \
+ }, \
+ .show = i7core_show_counter_##param \
+ }
+
+DECLARE_COUNTER(0);
+DECLARE_COUNTER(1);
+DECLARE_COUNTER(2);
+
+/*
+ * Sysfs struct
+ */
+
+
+static 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 } }
+};
+
+static struct mcidev_sysfs_group i7core_inject_addrmatch = {
+ .name = "inject_addrmatch",
+ .mcidev_attr = i7core_addrmatch_attrs,
+};
+
+static struct mcidev_sysfs_attribute i7core_udimm_counters_attrs[] = {
+ ATTR_COUNTER(0),
+ ATTR_COUNTER(1),
+ ATTR_COUNTER(2),
+};
+
+static 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[] = {
+ {
+ .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,
+ },
+ { .attr = { .name = NULL } }, /* Reserved for udimm counters */
+ { .attr = { .name = NULL } }
+};
+
+/****************************************************************************
+ Device initialization routines: put/get, init/exit
+ ****************************************************************************/
+
+/*
+ * i7core_put_devices 'put' all the devices that we have
+ * reserved via 'get'
+ */
+static void i7core_put_devices(struct i7core_dev *i7core_dev)
+{
+ int i;
+
+ debugf0(__FILE__ ": %s()\n", __func__);
+ for (i = 0; i < i7core_dev->n_devs; i++) {
+ struct pci_dev *pdev = i7core_dev->pdev[i];
+ if (!pdev)
+ continue;
+ debugf0("Removing dev %02x:%02x.%d\n",
+ pdev->bus->number,
+ 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)
+ i7core_put_devices(i7core_dev);
+}
+
+static void i7core_xeon_pci_fixup(int dev_id)
+{
+ 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
+ * to detect them
+ */
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL, dev_id, NULL);
+ if (unlikely(!pdev)) {
+ for (i = 0; i < MAX_SOCKET_BUSES; i++)
+ pcibios_scan_specific_bus(255-i);
+ }
+}
+
+/*
+ * i7core_get_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)
+{
+ struct i7core_dev *i7core_dev;
+
+ struct pci_dev *pdev = NULL;
+ u8 bus = 0;
+ u8 socket = 0;
+
+ 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 (!pdev) {
+ if (*prev) {
+ *prev = pdev;
+ return 0;
+ }
+
+ if (dev_descr->optional)
+ return 0;
+
+ i7core_printk(KERN_ERR,
+ "Device not found: dev %02x.%d PCI ID %04x:%04x\n",
+ dev_descr->dev, dev_descr->func,
+ PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
+
+ /* End of list, leave */
+ return -ENODEV;
+ }
+ bus = pdev->bus->number;
+
+ if (bus == 0x3f)
+ socket = 0;
+ else
+ socket = 255 - bus;
+
+ 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)
+ 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]) {
+ i7core_printk(KERN_ERR,
+ "Duplicated device for "
+ "dev %02x:%02x.%d PCI ID %04x:%04x\n",
+ bus, dev_descr->dev, dev_descr->func,
+ PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
+ pci_dev_put(pdev);
+ return -ENODEV;
+ }
+
+ i7core_dev->pdev[devno] = pdev;
+
+ /* Sanity check */
+ if (unlikely(PCI_SLOT(pdev->devfn) != dev_descr->dev ||
+ PCI_FUNC(pdev->devfn) != dev_descr->func)) {
+ i7core_printk(KERN_ERR,
+ "Device PCI ID %04x:%04x "
+ "has dev %02x:%02x.%d instead of dev %02x:%02x.%d\n",
+ PCI_VENDOR_ID_INTEL, dev_descr->dev_id,
+ bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+ bus, dev_descr->dev, dev_descr->func);
+ return -ENODEV;
+ }
+
+ /* Be sure that the device is enabled */
+ if (unlikely(pci_enable_device(pdev) < 0)) {
+ i7core_printk(KERN_ERR,
+ "Couldn't enable "
+ "dev %02x:%02x.%d PCI ID %04x:%04x\n",
+ bus, dev_descr->dev, dev_descr->func,
+ PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
+ return -ENODEV;
+ }
+
+ debugf0("Detected socket %d dev %02x:%02x.%d PCI ID %04x:%04x\n",
+ socket, bus, dev_descr->dev,
+ dev_descr->func,
+ PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
+
+ *prev = pdev;
+
+ return 0;
+}
+
+static int i7core_get_devices(struct pci_id_descr dev_descr[], unsigned n_devs)
+{
+ int i, rc;
+ struct pci_dev *pdev = NULL;
+
+ for (i = 0; i < n_devs; i++) {
+ pdev = NULL;
+ do {
+ rc = i7core_get_onedevice(&pdev, i, &dev_descr[i],
+ n_devs);
+ if (rc < 0) {
+ i7core_put_all_devices();
+ return -ENODEV;
+ }
+ } while (pdev);
+ }
+
+ return 0;
+}
+
+static int mci_bind_devs(struct mem_ctl_info *mci,
+ struct i7core_dev *i7core_dev)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ 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];
+ if (!pdev)
+ continue;
+
+ func = PCI_FUNC(pdev->devfn);
+ slot = PCI_SLOT(pdev->devfn);
+ if (slot == 3) {
+ if (unlikely(func > MAX_MCR_FUNC))
+ goto error;
+ pvt->pci_mcr[func] = pdev;
+ } else if (likely(slot >= 4 && slot < 4 + NUM_CHANS)) {
+ if (unlikely(func > MAX_CHAN_FUNC))
+ goto error;
+ pvt->pci_ch[slot - 4][func] = pdev;
+ } else if (!slot && !func)
+ pvt->pci_noncore = pdev;
+ else
+ goto error;
+
+ debugf0("Associated fn %d.%d, dev = %p, socket %d\n",
+ PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+ pdev, i7core_dev->socket);
+
+ if (PCI_SLOT(pdev->devfn) == 3 &&
+ PCI_FUNC(pdev->devfn) == 2)
+ 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:
+ i7core_printk(KERN_ERR, "Device %d, function %d "
+ "is out of the expected range\n",
+ slot, func);
+ return -EINVAL;
+}
+
+/****************************************************************************
+ Error check routines
+ ****************************************************************************/
+static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci,
+ int chan, int dimm, int add)
+{
+ char *msg;
+ struct i7core_pvt *pvt = mci->pvt_info;
+ int row = pvt->csrow_map[chan][dimm], i;
+
+ for (i = 0; i < add; i++) {
+ msg = kasprintf(GFP_KERNEL, "Corrected error "
+ "(Socket=%d channel=%d dimm=%d)",
+ pvt->i7core_dev->socket, chan, dimm);
+
+ edac_mc_handle_fbd_ce(mci, row, 0, msg);
+ kfree (msg);
+ }
+}
+
+static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci,
+ int chan, int new0, int new1, int new2)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ int add0 = 0, add1 = 0, add2 = 0;
+ /* Updates CE counters if it is not the first time here */
+ if (pvt->ce_count_available) {
+ /* Updates CE counters */
+
+ add2 = new2 - pvt->rdimm_last_ce_count[chan][2];
+ add1 = new1 - pvt->rdimm_last_ce_count[chan][1];
+ add0 = new0 - pvt->rdimm_last_ce_count[chan][0];
+
+ if (add2 < 0)
+ add2 += 0x7fff;
+ pvt->rdimm_ce_count[chan][2] += add2;
+
+ if (add1 < 0)
+ add1 += 0x7fff;
+ pvt->rdimm_ce_count[chan][1] += add1;
+
+ if (add0 < 0)
+ add0 += 0x7fff;
+ pvt->rdimm_ce_count[chan][0] += add0;
+ } else
+ pvt->ce_count_available = 1;
+
+ /* Store the new values */
+ pvt->rdimm_last_ce_count[chan][2] = new2;
+ pvt->rdimm_last_ce_count[chan][1] = new1;
+ pvt->rdimm_last_ce_count[chan][0] = new0;
+
+ /*updated the edac core */
+ if (add0 != 0)
+ i7core_rdimm_update_csrow(mci, chan, 0, add0);
+ if (add1 != 0)
+ i7core_rdimm_update_csrow(mci, chan, 1, add1);
+ if (add2 != 0)
+ i7core_rdimm_update_csrow(mci, chan, 2, add2);
+
+}
+
+static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ u32 rcv[3][2];
+ int i, new0, new1, new2;
+
+ /*Read DEV 3: FUN 2: MC_COR_ECC_CNT regs directly*/
+ pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_0,
+ &rcv[0][0]);
+ pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_1,
+ &rcv[0][1]);
+ pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_2,
+ &rcv[1][0]);
+ pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_3,
+ &rcv[1][1]);
+ pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_4,
+ &rcv[2][0]);
+ pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_5,
+ &rcv[2][1]);
+ for (i = 0 ; i < 3; i++) {
+ debugf3("MC_COR_ECC_CNT%d = 0x%x; MC_COR_ECC_CNT%d = 0x%x\n",
+ (i * 2), rcv[i][0], (i * 2) + 1, rcv[i][1]);
+ /*if the channel has 3 dimms*/
+ if (pvt->channel[i].dimms > 2) {
+ new0 = DIMM_BOT_COR_ERR(rcv[i][0]);
+ new1 = DIMM_TOP_COR_ERR(rcv[i][0]);
+ new2 = DIMM_BOT_COR_ERR(rcv[i][1]);
+ } else {
+ new0 = DIMM_TOP_COR_ERR(rcv[i][0]) +
+ DIMM_BOT_COR_ERR(rcv[i][0]);
+ new1 = DIMM_TOP_COR_ERR(rcv[i][1]) +
+ DIMM_BOT_COR_ERR(rcv[i][1]);
+ new2 = 0;
+ }
+
+ i7core_rdimm_update_ce_count(mci, i, new0, new1, new2);
+ }
+}
+
+/* This function is based on the device 3 function 4 registers as described on:
+ * Intel Xeon Processor 5500 Series Datasheet Volume 2
+ * http://www.intel.com/Assets/PDF/datasheet/321322.pdf
+ * also available at:
+ * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
+ */
+static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ u32 rcv1, rcv0;
+ int new0, new1, new2;
+
+ if (!pvt->pci_mcr[4]) {
+ debugf0("%s MCR registers not found\n", __func__);
+ return;
+ }
+
+ /* Corrected test errors */
+ pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV1, &rcv1);
+ pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV0, &rcv0);
+
+ /* Store the new values */
+ new2 = DIMM2_COR_ERR(rcv1);
+ new1 = DIMM1_COR_ERR(rcv0);
+ new0 = DIMM0_COR_ERR(rcv0);
+
+ /* Updates CE counters if it is not the first time here */
+ if (pvt->ce_count_available) {
+ /* Updates CE counters */
+ int add0, add1, add2;
+
+ add2 = new2 - pvt->udimm_last_ce_count[2];
+ add1 = new1 - pvt->udimm_last_ce_count[1];
+ add0 = new0 - pvt->udimm_last_ce_count[0];
+
+ if (add2 < 0)
+ add2 += 0x7fff;
+ pvt->udimm_ce_count[2] += add2;
+
+ if (add1 < 0)
+ add1 += 0x7fff;
+ pvt->udimm_ce_count[1] += add1;
+
+ if (add0 < 0)
+ add0 += 0x7fff;
+ pvt->udimm_ce_count[0] += add0;
+
+ if (add0 | add1 | add2)
+ i7core_printk(KERN_ERR, "New Corrected error(s): "
+ "dimm0: +%d, dimm1: +%d, dimm2 +%d\n",
+ add0, add1, add2);
+ } else
+ pvt->ce_count_available = 1;
+
+ /* Store the new values */
+ pvt->udimm_last_ce_count[2] = new2;
+ pvt->udimm_last_ce_count[1] = new1;
+ pvt->udimm_last_ce_count[0] = new0;
+}
+
+/*
+ * According with tables E-11 and E-12 of chapter E.3.3 of Intel 64 and IA-32
+ * Architectures Software Developer’s Manual Volume 3B.
+ * Nehalem are defined as family 0x06, model 0x1a
+ *
+ * The MCA registers used here are the following ones:
+ * struct mce field MCA Register
+ * m->status MSR_IA32_MC8_STATUS
+ * m->addr MSR_IA32_MC8_ADDR
+ * m->misc MSR_IA32_MC8_MISC
+ * In the case of Nehalem, the error information is masked at .status and .misc
+ * fields
+ */
+static void i7core_mce_output_error(struct mem_ctl_info *mci,
+ struct mce *m)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ char *type, *optype, *err, *msg;
+ unsigned long error = m->status & 0x1ff0000l;
+ u32 optypenum = (m->status >> 4) & 0x07;
+ u32 core_err_cnt = (m->status >> 38) && 0x7fff;
+ u32 dimm = (m->misc >> 16) & 0x3;
+ u32 channel = (m->misc >> 18) & 0x3;
+ u32 syndrome = m->misc >> 32;
+ u32 errnum = find_first_bit(&error, 32);
+ int csrow;
+
+ if (m->mcgstatus & 1)
+ type = "FATAL";
+ else
+ type = "NON_FATAL";
+
+ switch (optypenum) {
+ case 0:
+ optype = "generic undef request";
+ break;
+ case 1:
+ optype = "read error";
+ break;
+ case 2:
+ optype = "write error";
+ break;
+ case 3:
+ optype = "addr/cmd error";
+ break;
+ case 4:
+ optype = "scrubbing error";
+ break;
+ default:
+ optype = "reserved";
+ break;
+ }
+
+ switch (errnum) {
+ case 16:
+ err = "read ECC error";
+ break;
+ case 17:
+ err = "RAS ECC error";
+ break;
+ case 18:
+ err = "write parity error";
+ break;
+ case 19:
+ err = "redundacy loss";
+ break;
+ case 20:
+ err = "reserved";
+ break;
+ case 21:
+ err = "memory range error";
+ break;
+ case 22:
+ err = "RTID out of range";
+ break;
+ case 23:
+ err = "address parity error";
+ break;
+ case 24:
+ err = "byte enable parity error";
+ break;
+ default:
+ err = "unknown";
+ }
+
+ /* FIXME: should convert addr into bank and rank information */
+ msg = kasprintf(GFP_ATOMIC,
+ "%s (addr = 0x%08llx, cpu=%d, Dimm=%d, Channel=%d, "
+ "syndrome=0x%08x, count=%d, Err=%08llx:%08llx (%s: %s))\n",
+ type, (long long) m->addr, m->cpu, dimm, channel,
+ syndrome, core_err_cnt, (long long)m->status,
+ (long long)m->misc, optype, err);
+
+ debugf0("%s", msg);
+
+ csrow = pvt->csrow_map[channel][dimm];
+
+ /* Call the helper to output message */
+ if (m->mcgstatus & 1)
+ edac_mc_handle_fbd_ue(mci, csrow, 0,
+ 0 /* FIXME: should be channel here */, msg);
+ else if (!pvt->is_registered)
+ edac_mc_handle_fbd_ce(mci, csrow,
+ 0 /* FIXME: should be channel here */, msg);
+
+ kfree(msg);
+}
+
+/*
+ * i7core_check_error Retrieve and process errors reported by the
+ * hardware. Called by the Core module.
+ */
+static void i7core_check_error(struct mem_ctl_info *mci)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ int i;
+ unsigned count = 0;
+ struct mce *m;
+
+ /*
+ * MCE first step: Copy all mce errors into a temporary buffer
+ * We use a double buffering here, to reduce the risk of
+ * loosing an error.
+ */
+ smp_rmb();
+ count = (pvt->mce_out + MCE_LOG_LEN - pvt->mce_in)
+ % MCE_LOG_LEN;
+ if (!count)
+ return;
+
+ m = pvt->mce_outentry;
+ if (pvt->mce_in + count > MCE_LOG_LEN) {
+ unsigned l = MCE_LOG_LEN - pvt->mce_in;
+
+ memcpy(m, &pvt->mce_entry[pvt->mce_in], sizeof(*m) * l);
+ smp_wmb();
+ pvt->mce_in = 0;
+ count -= l;
+ m += l;
+ }
+ memcpy(m, &pvt->mce_entry[pvt->mce_in], sizeof(*m) * count);
+ smp_wmb();
+ pvt->mce_in += count;
+
+ smp_rmb();
+ if (pvt->mce_overrun) {
+ i7core_printk(KERN_ERR, "Lost %d memory errors\n",
+ pvt->mce_overrun);
+ smp_wmb();
+ pvt->mce_overrun = 0;
+ }
+
+ /*
+ * MCE second step: parse errors and display
+ */
+ for (i = 0; i < count; i++)
+ i7core_mce_output_error(mci, &pvt->mce_outentry[i]);
+
+ /*
+ * Now, let's increment CE error counts
+ */
+ if (!pvt->is_registered)
+ i7core_udimm_check_mc_ecc_err(mci);
+ else
+ i7core_rdimm_check_mc_ecc_err(mci);
+}
+
+/*
+ * i7core_mce_check_error Replicates mcelog routine to get errors
+ * This routine simply queues mcelog errors, and
+ * return. The error itself should be handled later
+ * by i7core_check_error.
+ * WARNING: As this routine should be called at NMI time, extra care should
+ * be taken to avoid deadlocks, and to be as fast as possible.
+ */
+static int i7core_mce_check_error(void *priv, struct mce *mce)
+{
+ struct mem_ctl_info *mci = priv;
+ struct i7core_pvt *pvt = mci->pvt_info;
+
+ /*
+ * Just let mcelog handle it if the error is
+ * outside the memory controller
+ */
+ if (((mce->status & 0xffff) >> 7) != 1)
+ return 0;
+
+ /* Bank 8 registers are the only ones that we know how to handle */
+ if (mce->bank != 8)
+ return 0;
+
+ /* Only handle if it is the right mc controller */
+ if (cpu_data(mce->cpu).phys_proc_id != pvt->i7core_dev->socket)
+ return 0;
+
+ smp_rmb();
+ if ((pvt->mce_out + 1) % MCE_LOG_LEN == pvt->mce_in) {
+ smp_wmb();
+ pvt->mce_overrun++;
+ return 0;
+ }
+
+ /* Copy memory error at the ringbuffer */
+ memcpy(&pvt->mce_entry[pvt->mce_out], mce, sizeof(*mce));
+ smp_wmb();
+ pvt->mce_out = (pvt->mce_out + 1) % MCE_LOG_LEN;
+
+ /* Handle fatal errors immediately */
+ if (mce->mcgstatus & 1)
+ i7core_check_error(mci);
+
+ /* Advice mcelog that the error were handled */
+ return 1;
+}
+
+static int i7core_register_mci(struct i7core_dev *i7core_dev,
+ int num_channels, int num_csrows)
+{
+ struct mem_ctl_info *mci;
+ struct i7core_pvt *pvt;
+ int csrow = 0;
+ int rc;
+
+ /* allocate a new MC control structure */
+ mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_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;
+
+ pvt = mci->pvt_info;
+ memset(pvt, 0, sizeof(*pvt));
+
+ /*
+ * FIXME: how to handle RDDR3 at MCI level? It is possible to have
+ * Mixed RDDR3/UDDR3 with Nehalem, provided that they are on different
+ * memory channels
+ */
+ mci->mtype_cap = MEM_FLAG_DDR3;
+ mci->edac_ctl_cap = EDAC_FLAG_NONE;
+ mci->edac_cap = EDAC_FLAG_NONE;
+ mci->mod_name = "i7core_edac.c";
+ mci->mod_ver = I7CORE_REVISION;
+ mci->ctl_name = kasprintf(GFP_KERNEL, "i7 core #%d",
+ 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;
+
+ /* Get dimm basic config */
+ get_dimm_config(mci, &csrow);
+
+ /* add this new MC control structure to EDAC's list of MCs */
+ if (unlikely(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
+ */
+
+ 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__);
+ }
+
+ /* Default error mask is any memory */
+ pvt->inject.channel = 0;
+ pvt->inject.dimm = -1;
+ pvt->inject.rank = -1;
+ pvt->inject.bank = -1;
+ pvt->inject.page = -1;
+ pvt->inject.col = -1;
+
+ /* 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__);
+ }
+
+fail:
+ edac_mc_free(mci);
+ return rc;
+}
+
+/*
+ * i7core_probe Probe for ONE instance of device to see if it is
+ * present.
+ * return:
+ * 0 for FOUND a device
+ * < 0 for error code
+ */
+static int __devinit i7core_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int dev_idx = id->driver_data;
+ int rc;
+ struct i7core_dev *i7core_dev;
+
+ /*
+ * All memory controllers are allocated at the first pass.
+ */
+ if (unlikely(dev_idx >= 1))
+ return -EINVAL;
+
+ /* get the pci devices we want to reserve for our use */
+ mutex_lock(&i7core_edac_lock);
+
+ rc = i7core_get_devices(pci_dev_descr_i7core,
+ ARRAY_SIZE(pci_dev_descr_i7core));
+ 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);
+ if (unlikely(rc < 0))
+ goto fail1;
+ }
+
+ i7core_printk(KERN_INFO, "Driver loaded.\n");
+
+ mutex_unlock(&i7core_edac_lock);
+ return 0;
+
+fail1:
+ i7core_put_all_devices();
+fail0:
+ mutex_unlock(&i7core_edac_lock);
+ return rc;
+}
+
+/*
+ * i7core_remove destructor for one instance of device
+ *
+ */
+static void __devexit i7core_remove(struct pci_dev *pdev)
+{
+ struct mem_ctl_info *mci;
+ struct i7core_dev *i7core_dev, *tmp;
+
+ 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
+ * is a Nehalem or upper design. However, due to the way several PCI
+ * devices are grouped together to provide MC functionality, we need
+ * to use a different method for releasing the devices
+ */
+
+ 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);
+ }
+ }
+ mutex_unlock(&i7core_edac_lock);
+}
+
+MODULE_DEVICE_TABLE(pci, i7core_pci_tbl);
+
+/*
+ * i7core_driver pci_driver structure for this module
+ *
+ */
+static struct pci_driver i7core_driver = {
+ .name = "i7core_edac",
+ .probe = i7core_probe,
+ .remove = __devexit_p(i7core_remove),
+ .id_table = i7core_pci_tbl,
+};
+
+/*
+ * i7core_init Module entry function
+ * Try to initialize this module for its devices
+ */
+static int __init i7core_init(void)
+{
+ int pci_rc;
+
+ debugf2("MC: " __FILE__ ": %s()\n", __func__);
+
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
+ i7core_xeon_pci_fixup(pci_dev_descr_i7core[0].dev_id);
+
+ pci_rc = pci_register_driver(&i7core_driver);
+
+ if (pci_rc >= 0)
+ return 0;
+
+ i7core_printk(KERN_ERR, "Failed to register device with error %d.\n",
+ pci_rc);
+
+ return pci_rc;
+}
+
+/*
+ * i7core_exit() Module exit function
+ * Unregister the driver
+ */
+static void __exit i7core_exit(void)
+{
+ debugf2("MC: " __FILE__ ": %s()\n", __func__);
+ pci_unregister_driver(&i7core_driver);
+}
+
+module_init(i7core_init);
+module_exit(i7core_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 i7 Core memory controllers - "
+ I7CORE_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/firewire/core-card.c b/drivers/firewire/core-card.c
index e4864e894e4f..7083bcc1b9c7 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -38,15 +38,14 @@
#include "core.h"
-int fw_compute_block_crc(u32 *block)
+int fw_compute_block_crc(__be32 *block)
{
- __be32 be32_block[256];
- int i, length;
+ int length;
+ u16 crc;
- length = (*block >> 16) & 0xff;
- for (i = 0; i < length; i++)
- be32_block[i] = cpu_to_be32(block[i + 1]);
- *block |= crc_itu_t(0, (u8 *) be32_block, length * 4);
+ length = (be32_to_cpu(block[0]) >> 16) & 0xff;
+ crc = crc_itu_t(0, (u8 *)&block[1], length * 4);
+ *block |= cpu_to_be32(crc);
return length;
}
@@ -57,6 +56,8 @@ static LIST_HEAD(card_list);
static LIST_HEAD(descriptor_list);
static int descriptor_count;
+static __be32 tmp_config_rom[256];
+
#define BIB_CRC(v) ((v) << 0)
#define BIB_CRC_LENGTH(v) ((v) << 16)
#define BIB_INFO_LENGTH(v) ((v) << 24)
@@ -72,11 +73,10 @@ static int descriptor_count;
#define BIB_CMC ((1) << 30)
#define BIB_IMC ((1) << 31)
-static u32 *generate_config_rom(struct fw_card *card, size_t *config_rom_length)
+static size_t generate_config_rom(struct fw_card *card, __be32 *config_rom)
{
struct fw_descriptor *desc;
- static u32 config_rom[256];
- int i, j, length;
+ int i, j, k, length;
/*
* Initialize contents of config rom buffer. On the OHCI
@@ -87,40 +87,39 @@ static u32 *generate_config_rom(struct fw_card *card, size_t *config_rom_length)
* the version stored in the OHCI registers.
*/
- memset(config_rom, 0, sizeof(config_rom));
- config_rom[0] = BIB_CRC_LENGTH(4) | BIB_INFO_LENGTH(4) | BIB_CRC(0);
- config_rom[1] = 0x31333934;
-
- config_rom[2] =
+ config_rom[0] = cpu_to_be32(
+ BIB_CRC_LENGTH(4) | BIB_INFO_LENGTH(4) | BIB_CRC(0));
+ config_rom[1] = cpu_to_be32(0x31333934);
+ config_rom[2] = cpu_to_be32(
BIB_LINK_SPEED(card->link_speed) |
BIB_GENERATION(card->config_rom_generation++ % 14 + 2) |
BIB_MAX_ROM(2) |
BIB_MAX_RECEIVE(card->max_receive) |
- BIB_BMC | BIB_ISC | BIB_CMC | BIB_IMC;
- config_rom[3] = card->guid >> 32;
- config_rom[4] = card->guid;
+ BIB_BMC | BIB_ISC | BIB_CMC | BIB_IMC);
+ config_rom[3] = cpu_to_be32(card->guid >> 32);
+ config_rom[4] = cpu_to_be32(card->guid);
/* Generate root directory. */
- i = 5;
- config_rom[i++] = 0;
- config_rom[i++] = 0x0c0083c0; /* node capabilities */
- j = i + descriptor_count;
+ config_rom[6] = cpu_to_be32(0x0c0083c0); /* node capabilities */
+ i = 7;
+ j = 7 + descriptor_count;
/* Generate root directory entries for descriptors. */
list_for_each_entry (desc, &descriptor_list, link) {
if (desc->immediate > 0)
- config_rom[i++] = desc->immediate;
- config_rom[i] = desc->key | (j - i);
+ config_rom[i++] = cpu_to_be32(desc->immediate);
+ config_rom[i] = cpu_to_be32(desc->key | (j - i));
i++;
j += desc->length;
}
/* Update root directory length. */
- config_rom[5] = (i - 5 - 1) << 16;
+ config_rom[5] = cpu_to_be32((i - 5 - 1) << 16);
/* End of root directory, now copy in descriptors. */
list_for_each_entry (desc, &descriptor_list, link) {
- memcpy(&config_rom[i], desc->data, desc->length * 4);
+ for (k = 0; k < desc->length; k++)
+ config_rom[i + k] = cpu_to_be32(desc->data[k]);
i += desc->length;
}
@@ -131,20 +130,17 @@ static u32 *generate_config_rom(struct fw_card *card, size_t *config_rom_length)
for (i = 0; i < j; i += length + 1)
length = fw_compute_block_crc(config_rom + i);
- *config_rom_length = j;
-
- return config_rom;
+ return j;
}
static void update_config_roms(void)
{
struct fw_card *card;
- u32 *config_rom;
size_t length;
list_for_each_entry (card, &card_list, link) {
- config_rom = generate_config_rom(card, &length);
- card->driver->set_config_rom(card, config_rom, length);
+ length = generate_config_rom(card, tmp_config_rom);
+ card->driver->set_config_rom(card, tmp_config_rom, length);
}
}
@@ -211,11 +207,8 @@ static const char gap_count_table[] = {
void fw_schedule_bm_work(struct fw_card *card, unsigned long delay)
{
- int scheduled;
-
fw_card_get(card);
- scheduled = schedule_delayed_work(&card->work, delay);
- if (!scheduled)
+ if (!schedule_delayed_work(&card->work, delay))
fw_card_put(card);
}
@@ -435,7 +428,6 @@ EXPORT_SYMBOL(fw_card_initialize);
int fw_card_add(struct fw_card *card,
u32 max_receive, u32 link_speed, u64 guid)
{
- u32 *config_rom;
size_t length;
int ret;
@@ -445,8 +437,8 @@ int fw_card_add(struct fw_card *card,
mutex_lock(&card_mutex);
- config_rom = generate_config_rom(card, &length);
- ret = card->driver->enable(card, config_rom, length);
+ length = generate_config_rom(card, tmp_config_rom);
+ ret = card->driver->enable(card, tmp_config_rom, length);
if (ret == 0)
list_add_tail(&card->link, &card_list);
@@ -465,7 +457,8 @@ EXPORT_SYMBOL(fw_card_add);
* shutdown still need to be provided by the card driver.
*/
-static int dummy_enable(struct fw_card *card, u32 *config_rom, size_t length)
+static int dummy_enable(struct fw_card *card,
+ const __be32 *config_rom, size_t length)
{
BUG();
return -1;
@@ -478,7 +471,7 @@ static int dummy_update_phy_reg(struct fw_card *card, int address,
}
static int dummy_set_config_rom(struct fw_card *card,
- u32 *config_rom, size_t length)
+ const __be32 *config_rom, size_t length)
{
/*
* We take the card out of card_list before setting the dummy
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 5089331544ed..20b7cc30383f 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -130,9 +130,22 @@ struct iso_resource {
struct iso_resource_event *e_alloc, *e_dealloc;
};
-static void schedule_iso_resource(struct iso_resource *);
static void release_iso_resource(struct client *, struct client_resource *);
+static void schedule_iso_resource(struct iso_resource *r, unsigned long delay)
+{
+ client_get(r->client);
+ if (!schedule_delayed_work(&r->work, delay))
+ client_put(r->client);
+}
+
+static void schedule_if_iso_resource(struct client_resource *resource)
+{
+ if (resource->release == release_iso_resource)
+ schedule_iso_resource(container_of(resource,
+ struct iso_resource, resource), 0);
+}
+
/*
* dequeue_event() just kfree()'s the event, so the event has to be
* the first field in a struct XYZ_event.
@@ -166,7 +179,7 @@ struct iso_interrupt_event {
struct iso_resource_event {
struct event event;
- struct fw_cdev_event_iso_resource resource;
+ struct fw_cdev_event_iso_resource iso_resource;
};
static inline void __user *u64_to_uptr(__u64 value)
@@ -314,11 +327,8 @@ static void for_each_client(struct fw_device *device,
static int schedule_reallocations(int id, void *p, void *data)
{
- struct client_resource *r = p;
+ schedule_if_iso_resource(p);
- if (r->release == release_iso_resource)
- schedule_iso_resource(container_of(r,
- struct iso_resource, resource));
return 0;
}
@@ -414,9 +424,7 @@ static int add_client_resource(struct client *client,
&resource->handle);
if (ret >= 0) {
client_get(client);
- if (resource->release == release_iso_resource)
- schedule_iso_resource(container_of(resource,
- struct iso_resource, resource));
+ schedule_if_iso_resource(resource);
}
spin_unlock_irqrestore(&client->lock, flags);
@@ -428,26 +436,26 @@ static int add_client_resource(struct client *client,
static int release_client_resource(struct client *client, u32 handle,
client_resource_release_fn_t release,
- struct client_resource **resource)
+ struct client_resource **return_resource)
{
- struct client_resource *r;
+ struct client_resource *resource;
spin_lock_irq(&client->lock);
if (client->in_shutdown)
- r = NULL;
+ resource = NULL;
else
- r = idr_find(&client->resource_idr, handle);
- if (r && r->release == release)
+ resource = idr_find(&client->resource_idr, handle);
+ if (resource && resource->release == release)
idr_remove(&client->resource_idr, handle);
spin_unlock_irq(&client->lock);
- if (!(r && r->release == release))
+ if (!(resource && resource->release == release))
return -EINVAL;
- if (resource)
- *resource = r;
+ if (return_resource)
+ *return_resource = resource;
else
- r->release(client, r);
+ resource->release(client, resource);
client_put(client);
@@ -699,6 +707,7 @@ static int ioctl_send_response(struct client *client, void *buffer)
struct fw_cdev_send_response *request = buffer;
struct client_resource *resource;
struct inbound_transaction_resource *r;
+ int ret = 0;
if (release_client_resource(client, request->handle,
release_request, &resource) < 0)
@@ -708,13 +717,17 @@ static int ioctl_send_response(struct client *client, void *buffer)
resource);
if (request->length < r->length)
r->length = request->length;
- if (copy_from_user(r->data, u64_to_uptr(request->data), r->length))
- return -EFAULT;
+
+ if (copy_from_user(r->data, u64_to_uptr(request->data), r->length)) {
+ ret = -EFAULT;
+ goto out;
+ }
fw_send_response(client->device->card, r->request, request->rcode);
+ out:
kfree(r);
- return 0;
+ return ret;
}
static int ioctl_initiate_bus_reset(struct client *client, void *buffer)
@@ -1028,8 +1041,7 @@ static void iso_resource_work(struct work_struct *work)
/* Allow 1000ms grace period for other reallocations. */
if (todo == ISO_RES_ALLOC &&
time_is_after_jiffies(client->device->card->reset_jiffies + HZ)) {
- if (schedule_delayed_work(&r->work, DIV_ROUND_UP(HZ, 3)))
- client_get(client);
+ schedule_iso_resource(r, DIV_ROUND_UP(HZ, 3));
skip = true;
} else {
/* We could be called twice within the same generation. */
@@ -1097,12 +1109,12 @@ static void iso_resource_work(struct work_struct *work)
e = r->e_dealloc;
r->e_dealloc = NULL;
}
- e->resource.handle = r->resource.handle;
- e->resource.channel = channel;
- e->resource.bandwidth = bandwidth;
+ e->iso_resource.handle = r->resource.handle;
+ e->iso_resource.channel = channel;
+ e->iso_resource.bandwidth = bandwidth;
queue_event(client, &e->event,
- &e->resource, sizeof(e->resource), NULL, 0);
+ &e->iso_resource, sizeof(e->iso_resource), NULL, 0);
if (free) {
cancel_delayed_work(&r->work);
@@ -1114,13 +1126,6 @@ static void iso_resource_work(struct work_struct *work)
client_put(client);
}
-static void schedule_iso_resource(struct iso_resource *r)
-{
- client_get(r->client);
- if (!schedule_delayed_work(&r->work, 0))
- client_put(r->client);
-}
-
static void release_iso_resource(struct client *client,
struct client_resource *resource)
{
@@ -1129,7 +1134,7 @@ static void release_iso_resource(struct client *client,
spin_lock_irq(&client->lock);
r->todo = ISO_RES_DEALLOC;
- schedule_iso_resource(r);
+ schedule_iso_resource(r, 0);
spin_unlock_irq(&client->lock);
}
@@ -1162,10 +1167,10 @@ static int init_iso_resource(struct client *client,
r->e_alloc = e1;
r->e_dealloc = e2;
- e1->resource.closure = request->closure;
- e1->resource.type = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED;
- e2->resource.closure = request->closure;
- e2->resource.type = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
+ e1->iso_resource.closure = request->closure;
+ e1->iso_resource.type = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED;
+ e2->iso_resource.closure = request->closure;
+ e2->iso_resource.type = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
if (todo == ISO_RES_ALLOC) {
r->resource.release = release_iso_resource;
@@ -1175,7 +1180,7 @@ static int init_iso_resource(struct client *client,
} else {
r->resource.release = NULL;
r->resource.handle = -1;
- schedule_iso_resource(r);
+ schedule_iso_resource(r, 0);
}
request->handle = r->resource.handle;
@@ -1390,10 +1395,10 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
static int shutdown_resource(int id, void *p, void *data)
{
- struct client_resource *r = p;
+ struct client_resource *resource = p;
struct client *client = data;
- r->release(client, r);
+ resource->release(client, resource);
client_put(client);
return 0;
@@ -1402,7 +1407,7 @@ static int shutdown_resource(int id, void *p, void *data)
static int fw_device_op_release(struct inode *inode, struct file *file)
{
struct client *client = file->private_data;
- struct event *e, *next_e;
+ struct event *event, *next_event;
mutex_lock(&client->device->client_list_mutex);
list_del(&client->link);
@@ -1423,8 +1428,8 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
idr_remove_all(&client->resource_idr);
idr_destroy(&client->resource_idr);
- list_for_each_entry_safe(e, next_e, &client->event_list, link)
- kfree(e);
+ list_for_each_entry_safe(event, next_event, &client->event_list, link)
+ kfree(event);
client_put(client);
diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c
index fddf2b358936..9a5f38c80b0e 100644
--- a/drivers/firewire/core-topology.c
+++ b/drivers/firewire/core-topology.c
@@ -28,9 +28,9 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include <linux/string.h>
#include <asm/atomic.h>
+#include <asm/byteorder.h>
#include <asm/system.h>
#include "core.h"
@@ -510,13 +510,16 @@ static void update_tree(struct fw_card *card, struct fw_node *root)
static void update_topology_map(struct fw_card *card,
u32 *self_ids, int self_id_count)
{
- int node_count;
+ int node_count = (card->root_node->node_id & 0x3f) + 1;
+ __be32 *map = card->topology_map;
+
+ *map++ = cpu_to_be32((self_id_count + 2) << 16);
+ *map++ = cpu_to_be32(be32_to_cpu(card->topology_map[1]) + 1);
+ *map++ = cpu_to_be32((node_count << 16) | self_id_count);
+
+ while (self_id_count--)
+ *map++ = cpu_to_be32p(self_ids++);
- card->topology_map[1]++;
- node_count = (card->root_node->node_id & 0x3f) + 1;
- card->topology_map[2] = (node_count << 16) | self_id_count;
- card->topology_map[0] = (self_id_count + 2) << 16;
- memcpy(&card->topology_map[3], self_ids, self_id_count * 4);
fw_compute_block_crc(card->topology_map);
}
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index da628c72a462..203e6428bada 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -810,8 +810,7 @@ static void handle_topology_map(struct fw_card *card, struct fw_request *request
int speed, unsigned long long offset,
void *payload, size_t length, void *callback_data)
{
- int i, start, end;
- __be32 *map;
+ int start;
if (!TCODE_IS_READ_REQUEST(tcode)) {
fw_send_response(card, request, RCODE_TYPE_ERROR);
@@ -824,11 +823,7 @@ static void handle_topology_map(struct fw_card *card, struct fw_request *request
}
start = (offset - topology_map_region.start) / 4;
- end = start + length / 4;
- map = payload;
-
- for (i = 0; i < length / 4; i++)
- map[i] = cpu_to_be32(card->topology_map[start + i]);
+ memcpy(payload, &card->topology_map[start], length);
fw_send_response(card, request, RCODE_COMPLETE);
}
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index 7ff6e7585152..ed3b1a765c00 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -40,7 +40,8 @@ struct fw_card_driver {
* enable the PHY or set the link_on bit and initiate a bus
* reset.
*/
- int (*enable)(struct fw_card *card, u32 *config_rom, size_t length);
+ int (*enable)(struct fw_card *card,
+ const __be32 *config_rom, size_t length);
int (*update_phy_reg)(struct fw_card *card, int address,
int clear_bits, int set_bits);
@@ -48,10 +49,10 @@ struct fw_card_driver {
/*
* Update the config rom for an enabled card. This function
* should change the config rom that is presented on the bus
- * an initiate a bus reset.
+ * and initiate a bus reset.
*/
int (*set_config_rom)(struct fw_card *card,
- u32 *config_rom, size_t length);
+ const __be32 *config_rom, size_t length);
void (*send_request)(struct fw_card *card, struct fw_packet *packet);
void (*send_response)(struct fw_card *card, struct fw_packet *packet);
@@ -93,7 +94,7 @@ int fw_card_add(struct fw_card *card,
u32 max_receive, u32 link_speed, u64 guid);
void fw_core_remove_card(struct fw_card *card);
int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset);
-int fw_compute_block_crc(u32 *block);
+int fw_compute_block_crc(__be32 *block);
void fw_schedule_bm_work(struct fw_card *card, unsigned long delay);
static inline struct fw_card *fw_card_get(struct fw_card *card)
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 5d524254499e..418415564791 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -205,7 +205,7 @@ struct fw_ohci {
dma_addr_t config_rom_bus;
__be32 *next_config_rom;
dma_addr_t next_config_rom_bus;
- u32 next_header;
+ __be32 next_header;
struct ar_context ar_request_ctx;
struct ar_context ar_response_ctx;
@@ -1355,8 +1355,9 @@ static void bus_reset_tasklet(unsigned long data)
*/
reg_write(ohci, OHCI1394_BusOptions,
be32_to_cpu(ohci->config_rom[2]));
- ohci->config_rom[0] = cpu_to_be32(ohci->next_header);
- reg_write(ohci, OHCI1394_ConfigROMhdr, ohci->next_header);
+ ohci->config_rom[0] = ohci->next_header;
+ reg_write(ohci, OHCI1394_ConfigROMhdr,
+ be32_to_cpu(ohci->next_header));
}
#ifdef CONFIG_FIREWIRE_OHCI_REMOTE_DMA
@@ -1464,7 +1465,17 @@ static int software_reset(struct fw_ohci *ohci)
return -EBUSY;
}
-static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)
+static void copy_config_rom(__be32 *dest, const __be32 *src, size_t length)
+{
+ size_t size = length * 4;
+
+ memcpy(dest, src, size);
+ if (size < CONFIG_ROM_SIZE)
+ memset(&dest[length], 0, CONFIG_ROM_SIZE - size);
+}
+
+static int ohci_enable(struct fw_card *card,
+ const __be32 *config_rom, size_t length)
{
struct fw_ohci *ohci = fw_ohci(card);
struct pci_dev *dev = to_pci_dev(card->device);
@@ -1565,8 +1576,7 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)
if (ohci->next_config_rom == NULL)
return -ENOMEM;
- memset(ohci->next_config_rom, 0, CONFIG_ROM_SIZE);
- fw_memcpy_to_be32(ohci->next_config_rom, config_rom, length * 4);
+ copy_config_rom(ohci->next_config_rom, config_rom, length);
} else {
/*
* In the suspend case, config_rom is NULL, which
@@ -1576,7 +1586,7 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)
ohci->next_config_rom_bus = ohci->config_rom_bus;
}
- ohci->next_header = be32_to_cpu(ohci->next_config_rom[0]);
+ ohci->next_header = ohci->next_config_rom[0];
ohci->next_config_rom[0] = 0;
reg_write(ohci, OHCI1394_ConfigROMhdr, 0);
reg_write(ohci, OHCI1394_BusOptions,
@@ -1610,7 +1620,7 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)
}
static int ohci_set_config_rom(struct fw_card *card,
- u32 *config_rom, size_t length)
+ const __be32 *config_rom, size_t length)
{
struct fw_ohci *ohci;
unsigned long flags;
@@ -1659,9 +1669,7 @@ static int ohci_set_config_rom(struct fw_card *card,
ohci->next_config_rom = next_config_rom;
ohci->next_config_rom_bus = next_config_rom_bus;
- memset(ohci->next_config_rom, 0, CONFIG_ROM_SIZE);
- fw_memcpy_to_be32(ohci->next_config_rom, config_rom,
- length * 4);
+ copy_config_rom(ohci->next_config_rom, config_rom, length);
ohci->next_header = config_rom[0];
ohci->next_config_rom[0] = 0;
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index 98dbbda3ad41..d485cdd8cbac 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -820,20 +820,25 @@ static void sbp2_release_target(struct kref *kref)
fw_device_put(device);
}
-static struct workqueue_struct *sbp2_wq;
+static void sbp2_target_get(struct sbp2_target *tgt)
+{
+ kref_get(&tgt->kref);
+}
static void sbp2_target_put(struct sbp2_target *tgt)
{
kref_put(&tgt->kref, sbp2_release_target);
}
+static struct workqueue_struct *sbp2_wq;
+
/*
* Always get the target's kref when scheduling work on one its units.
* Each workqueue job is responsible to call sbp2_target_put() upon return.
*/
static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay)
{
- kref_get(&lu->tgt->kref);
+ sbp2_target_get(lu->tgt);
if (!queue_delayed_work(sbp2_wq, &lu->work, delay))
sbp2_target_put(lu->tgt);
}
diff --git a/drivers/gpio/adp5520-gpio.c b/drivers/gpio/adp5520-gpio.c
index ad05bbc7ffd5..0f93105873cd 100644
--- a/drivers/gpio/adp5520-gpio.c
+++ b/drivers/gpio/adp5520-gpio.c
@@ -34,9 +34,9 @@ static int adp5520_gpio_get_value(struct gpio_chip *chip, unsigned off)
*/
if (test_bit(off, &dev->output))
- adp5520_read(dev->master, GPIO_OUT, &reg_val);
+ adp5520_read(dev->master, ADP5520_GPIO_OUT, &reg_val);
else
- adp5520_read(dev->master, GPIO_IN, &reg_val);
+ adp5520_read(dev->master, ADP5520_GPIO_IN, &reg_val);
return !!(reg_val & dev->lut[off]);
}
@@ -48,9 +48,9 @@ static void adp5520_gpio_set_value(struct gpio_chip *chip,
dev = container_of(chip, struct adp5520_gpio, gpio_chip);
if (val)
- adp5520_set_bits(dev->master, GPIO_OUT, dev->lut[off]);
+ adp5520_set_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]);
else
- adp5520_clr_bits(dev->master, GPIO_OUT, dev->lut[off]);
+ adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]);
}
static int adp5520_gpio_direction_input(struct gpio_chip *chip, unsigned off)
@@ -60,7 +60,8 @@ static int adp5520_gpio_direction_input(struct gpio_chip *chip, unsigned off)
clear_bit(off, &dev->output);
- return adp5520_clr_bits(dev->master, GPIO_CFG_2, dev->lut[off]);
+ return adp5520_clr_bits(dev->master, ADP5520_GPIO_CFG_2,
+ dev->lut[off]);
}
static int adp5520_gpio_direction_output(struct gpio_chip *chip,
@@ -73,18 +74,21 @@ static int adp5520_gpio_direction_output(struct gpio_chip *chip,
set_bit(off, &dev->output);
if (val)
- ret |= adp5520_set_bits(dev->master, GPIO_OUT, dev->lut[off]);
+ ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_OUT,
+ dev->lut[off]);
else
- ret |= adp5520_clr_bits(dev->master, GPIO_OUT, dev->lut[off]);
+ ret |= adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT,
+ dev->lut[off]);
- ret |= adp5520_set_bits(dev->master, GPIO_CFG_2, dev->lut[off]);
+ ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_CFG_2,
+ dev->lut[off]);
return ret;
}
static int __devinit adp5520_gpio_probe(struct platform_device *pdev)
{
- struct adp5520_gpio_platfrom_data *pdata = pdev->dev.platform_data;
+ struct adp5520_gpio_platform_data *pdata = pdev->dev.platform_data;
struct adp5520_gpio *dev;
struct gpio_chip *gc;
int ret, i, gpios;
@@ -129,20 +133,20 @@ static int __devinit adp5520_gpio_probe(struct platform_device *pdev)
gc->label = pdev->name;
gc->owner = THIS_MODULE;
- ret = adp5520_clr_bits(dev->master, GPIO_CFG_1,
+ ret = adp5520_clr_bits(dev->master, ADP5520_GPIO_CFG_1,
pdata->gpio_en_mask);
- if (pdata->gpio_en_mask & GPIO_C3)
- ctl_mask |= C3_MODE;
+ if (pdata->gpio_en_mask & ADP5520_GPIO_C3)
+ ctl_mask |= ADP5520_C3_MODE;
- if (pdata->gpio_en_mask & GPIO_R3)
- ctl_mask |= R3_MODE;
+ if (pdata->gpio_en_mask & ADP5520_GPIO_R3)
+ ctl_mask |= ADP5520_R3_MODE;
if (ctl_mask)
- ret = adp5520_set_bits(dev->master, LED_CONTROL,
+ ret = adp5520_set_bits(dev->master, ADP5520_LED_CONTROL,
ctl_mask);
- ret |= adp5520_set_bits(dev->master, GPIO_PULLUP,
+ ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_PULLUP,
pdata->gpio_pullup_mask);
if (ret) {
diff --git a/drivers/gpio/wm831x-gpio.c b/drivers/gpio/wm831x-gpio.c
index f9c09a54ec7f..f5e4934f1da1 100644
--- a/drivers/gpio/wm831x-gpio.c
+++ b/drivers/gpio/wm831x-gpio.c
@@ -23,8 +23,6 @@
#include <linux/mfd/wm831x/pdata.h>
#include <linux/mfd/wm831x/gpio.h>
-#define WM831X_GPIO_MAX 16
-
struct wm831x_gpio {
struct wm831x *wm831x;
struct gpio_chip gpio_chip;
@@ -192,7 +190,7 @@ static int __devinit wm831x_gpio_probe(struct platform_device *pdev)
wm831x_gpio->wm831x = wm831x;
wm831x_gpio->gpio_chip = template_chip;
- wm831x_gpio->gpio_chip.ngpio = WM831X_GPIO_MAX;
+ wm831x_gpio->gpio_chip.ngpio = wm831x->num_gpio;
wm831x_gpio->gpio_chip.dev = &pdev->dev;
if (pdata && pdata->gpio_base)
wm831x_gpio->gpio_chip.base = pdata->gpio_base;
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 3c0d2b3aed76..cea665d86dd3 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -626,6 +626,12 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
return NULL;
}
+ /* it is incorrect if hsync/vsync width is zero */
+ if (!hsync_pulse_width || !vsync_pulse_width) {
+ DRM_DEBUG_KMS("Incorrect Detailed timing. "
+ "Wrong Hsync/Vsync pulse width\n");
+ return NULL;
+ }
mode = drm_mode_create(dev);
if (!mode)
return NULL;
@@ -647,6 +653,15 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
mode->vsync_end = mode->vsync_start + vsync_pulse_width;
mode->vtotal = mode->vdisplay + vblank;
+ /* perform the basic check for the detailed timing */
+ if (mode->hsync_end > mode->htotal ||
+ mode->vsync_end > mode->vtotal) {
+ drm_mode_destroy(dev, mode);
+ DRM_DEBUG_KMS("Incorrect detailed timing. "
+ "Sync is beyond the blank.\n");
+ return NULL;
+ }
+
drm_mode_set_name(mode);
if (pt->misc & DRM_EDID_PT_INTERLACED)
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 23dc9c115fd9..9c924614c418 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -454,22 +454,39 @@ out_free:
}
EXPORT_SYMBOL(drm_fb_helper_init_crtc_count);
-static void setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
+static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, u16 regno, struct fb_info *info)
{
struct drm_fb_helper *fb_helper = info->par;
struct drm_framebuffer *fb = fb_helper->fb;
int pindex;
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+ u32 *palette;
+ u32 value;
+ /* place color in psuedopalette */
+ if (regno > 16)
+ return -EINVAL;
+ palette = (u32 *)info->pseudo_palette;
+ red >>= (16 - info->var.red.length);
+ green >>= (16 - info->var.green.length);
+ blue >>= (16 - info->var.blue.length);
+ value = (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset);
+ palette[regno] = value;
+ return 0;
+ }
+
pindex = regno;
if (fb->bits_per_pixel == 16) {
pindex = regno << 3;
if (fb->depth == 16 && regno > 63)
- return;
+ return -EINVAL;
if (fb->depth == 15 && regno > 31)
- return;
+ return -EINVAL;
if (fb->depth == 16) {
u16 r, g, b;
@@ -493,13 +510,7 @@ static void setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
if (fb->depth != 16)
fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex);
-
- if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
- ((u32 *) fb->pseudo_palette)[regno] =
- (regno << info->var.red.offset) |
- (regno << info->var.green.offset) |
- (regno << info->var.blue.offset);
- }
+ return 0;
}
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
@@ -536,7 +547,9 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
if (transp)
htransp = *transp++;
- setcolreg(crtc, hred, hgreen, hblue, start++, info);
+ rc = setcolreg(crtc, hred, hgreen, hblue, start++, info);
+ if (rc)
+ return rc;
}
crtc_funcs->load_lut(crtc);
}
@@ -555,6 +568,7 @@ int drm_fb_helper_setcolreg(unsigned regno,
struct drm_device *dev = fb_helper->dev;
struct drm_crtc *crtc;
int i;
+ int ret;
if (regno > 255)
return 1;
@@ -568,8 +582,10 @@ int drm_fb_helper_setcolreg(unsigned regno,
if (i == fb_helper->crtc_count)
continue;
+ ret = setcolreg(crtc, red, green, blue, regno, info);
+ if (ret)
+ return ret;
- setcolreg(crtc, red, green, blue, regno, info);
crtc_funcs->load_lut(crtc);
}
return 0;
@@ -928,7 +944,7 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
{
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
- FB_VISUAL_DIRECTCOLOR;
+ FB_VISUAL_TRUECOLOR;
info->fix.type_aux = 0;
info->fix.xpanstep = 1; /* doing it in hw */
info->fix.ypanstep = 1; /* doing it in hw */
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 251bc0e3b5ec..8ac7fbf6b2b7 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -257,6 +257,9 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
INIT_LIST_HEAD(&priv->lhead);
INIT_LIST_HEAD(&priv->fbs);
+ INIT_LIST_HEAD(&priv->event_list);
+ init_waitqueue_head(&priv->event_wait);
+ priv->event_space = 4096; /* set aside 4k for event buffer */
if (dev->driver->driver_features & DRIVER_GEM)
drm_gem_open(dev, priv);
@@ -413,6 +416,30 @@ static void drm_master_release(struct drm_device *dev, struct file *filp)
}
}
+static void drm_events_release(struct drm_file *file_priv)
+{
+ struct drm_device *dev = file_priv->minor->dev;
+ struct drm_pending_event *e, *et;
+ struct drm_pending_vblank_event *v, *vt;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+
+ /* Remove pending flips */
+ list_for_each_entry_safe(v, vt, &dev->vblank_event_list, base.link)
+ if (v->base.file_priv == file_priv) {
+ list_del(&v->base.link);
+ drm_vblank_put(dev, v->pipe);
+ v->base.destroy(&v->base);
+ }
+
+ /* Remove unconsumed events */
+ list_for_each_entry_safe(e, et, &file_priv->event_list, link)
+ e->destroy(e);
+
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
/**
* Release file.
*
@@ -451,6 +478,8 @@ int drm_release(struct inode *inode, struct file *filp)
if (file_priv->minor->master)
drm_master_release(dev, filp);
+ drm_events_release(file_priv);
+
if (dev->driver->driver_features & DRIVER_GEM)
drm_gem_release(dev, file_priv);
@@ -544,9 +573,74 @@ int drm_release(struct inode *inode, struct file *filp)
}
EXPORT_SYMBOL(drm_release);
-/** No-op. */
+static bool
+drm_dequeue_event(struct drm_file *file_priv,
+ size_t total, size_t max, struct drm_pending_event **out)
+{
+ struct drm_device *dev = file_priv->minor->dev;
+ struct drm_pending_event *e;
+ unsigned long flags;
+ bool ret = false;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+
+ *out = NULL;
+ if (list_empty(&file_priv->event_list))
+ goto out;
+ e = list_first_entry(&file_priv->event_list,
+ struct drm_pending_event, link);
+ if (e->event->length + total > max)
+ goto out;
+
+ file_priv->event_space += e->event->length;
+ list_del(&e->link);
+ *out = e;
+ ret = true;
+
+out:
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ return ret;
+}
+
+ssize_t drm_read(struct file *filp, char __user *buffer,
+ size_t count, loff_t *offset)
+{
+ struct drm_file *file_priv = filp->private_data;
+ struct drm_pending_event *e;
+ size_t total;
+ ssize_t ret;
+
+ ret = wait_event_interruptible(file_priv->event_wait,
+ !list_empty(&file_priv->event_list));
+ if (ret < 0)
+ return ret;
+
+ total = 0;
+ while (drm_dequeue_event(file_priv, total, count, &e)) {
+ if (copy_to_user(buffer + total,
+ e->event, e->event->length)) {
+ total = -EFAULT;
+ break;
+ }
+
+ total += e->event->length;
+ e->destroy(e);
+ }
+
+ return total;
+}
+EXPORT_SYMBOL(drm_read);
+
unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait)
{
- return 0;
+ struct drm_file *file_priv = filp->private_data;
+ unsigned int mask = 0;
+
+ poll_wait(filp, &file_priv->event_wait, wait);
+
+ if (!list_empty(&file_priv->event_list))
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
}
EXPORT_SYMBOL(drm_poll);
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 0a6f0b3bdc78..72754aca7abf 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -550,6 +550,62 @@ out:
return ret;
}
+static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
+ union drm_wait_vblank *vblwait,
+ struct drm_file *file_priv)
+{
+ struct drm_pending_vblank_event *e;
+ struct timeval now;
+ unsigned long flags;
+ unsigned int seq;
+
+ e = kzalloc(sizeof *e, GFP_KERNEL);
+ if (e == NULL)
+ return -ENOMEM;
+
+ e->pipe = pipe;
+ e->event.base.type = DRM_EVENT_VBLANK;
+ e->event.base.length = sizeof e->event;
+ e->event.user_data = vblwait->request.signal;
+ e->base.event = &e->event.base;
+ e->base.file_priv = file_priv;
+ e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
+
+ do_gettimeofday(&now);
+ spin_lock_irqsave(&dev->event_lock, flags);
+
+ if (file_priv->event_space < sizeof e->event) {
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ kfree(e);
+ return -ENOMEM;
+ }
+
+ file_priv->event_space -= sizeof e->event;
+ seq = drm_vblank_count(dev, pipe);
+ if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) &&
+ (seq - vblwait->request.sequence) <= (1 << 23)) {
+ vblwait->request.sequence = seq + 1;
+ }
+
+ DRM_DEBUG("event on vblank count %d, current %d, crtc %d\n",
+ vblwait->request.sequence, seq, pipe);
+
+ e->event.sequence = vblwait->request.sequence;
+ if ((seq - vblwait->request.sequence) <= (1 << 23)) {
+ e->event.tv_sec = now.tv_sec;
+ e->event.tv_usec = now.tv_usec;
+ drm_vblank_put(dev, e->pipe);
+ list_add_tail(&e->base.link, &e->base.file_priv->event_list);
+ wake_up_interruptible(&e->base.file_priv->event_wait);
+ } else {
+ list_add_tail(&e->base.link, &dev->vblank_event_list);
+ }
+
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ return 0;
+}
+
/**
* Wait for VBLANK.
*
@@ -609,6 +665,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
goto done;
}
+ if (flags & _DRM_VBLANK_EVENT)
+ return drm_queue_vblank_event(dev, crtc, vblwait, file_priv);
+
if ((flags & _DRM_VBLANK_NEXTONMISS) &&
(seq - vblwait->request.sequence) <= (1<<23)) {
vblwait->request.sequence = seq + 1;
@@ -641,6 +700,38 @@ done:
return ret;
}
+void drm_handle_vblank_events(struct drm_device *dev, int crtc)
+{
+ struct drm_pending_vblank_event *e, *t;
+ struct timeval now;
+ unsigned long flags;
+ unsigned int seq;
+
+ do_gettimeofday(&now);
+ seq = drm_vblank_count(dev, crtc);
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+
+ list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
+ if (e->pipe != crtc)
+ continue;
+ if ((seq - e->event.sequence) > (1<<23))
+ continue;
+
+ DRM_DEBUG("vblank event on %d, current %d\n",
+ e->event.sequence, seq);
+
+ e->event.sequence = seq;
+ e->event.tv_sec = now.tv_sec;
+ e->event.tv_usec = now.tv_usec;
+ drm_vblank_put(dev, e->pipe);
+ list_move_tail(&e->base.link, &e->base.file_priv->event_list);
+ wake_up_interruptible(&e->base.file_priv->event_wait);
+ }
+
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
/**
* drm_handle_vblank - handle a vblank event
* @dev: DRM device
@@ -651,7 +742,11 @@ done:
*/
void drm_handle_vblank(struct drm_device *dev, int crtc)
{
+ if (!dev->num_crtcs)
+ return;
+
atomic_inc(&dev->_vblank_count[crtc]);
DRM_WAKEUP(&dev->vbl_queue[crtc]);
+ drm_handle_vblank_events(dev, crtc);
}
EXPORT_SYMBOL(drm_handle_vblank);
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index 55bb8a82d612..adb864dfef3e 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -220,9 +220,11 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
INIT_LIST_HEAD(&dev->ctxlist);
INIT_LIST_HEAD(&dev->vmalist);
INIT_LIST_HEAD(&dev->maplist);
+ 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);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index b93814c0d3e2..40c87caab426 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -332,6 +332,7 @@ static struct drm_driver driver = {
.mmap = drm_gem_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
+ .read = drm_read,
#ifdef CONFIG_COMPAT
.compat_ioctl = i915_compat_ioctl,
#endif
diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h
index 5d402086bc47..c11ddddfb3b6 100644
--- a/drivers/gpu/drm/radeon/atombios.h
+++ b/drivers/gpu/drm/radeon/atombios.h
@@ -2314,7 +2314,7 @@ typedef struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT {
UCHAR ucSS_Step;
UCHAR ucSS_Delay;
UCHAR ucSS_Id;
- UCHAR ucRecommandedRef_Div;
+ UCHAR ucRecommendedRef_Div;
UCHAR ucSS_Range; /* it was reserved for V11 */
} ATOM_SPREAD_SPECTRUM_ASSIGNMENT;
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 14fa9701aeb3..e5a3c301b7a9 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -31,10 +31,6 @@
#include "atom.h"
#include "atom-bits.h"
-/* evil but including atombios.h is much worse */
-bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
- SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION *crtc_timing,
- int32_t *pixel_clock);
static void atombios_overscan_setup(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -248,18 +244,18 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
switch (mode) {
case DRM_MODE_DPMS_ON:
+ atombios_enable_crtc(crtc, 1);
if (ASIC_IS_DCE3(rdev))
atombios_enable_crtc_memreq(crtc, 1);
- atombios_enable_crtc(crtc, 1);
atombios_blank_crtc(crtc, 0);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
atombios_blank_crtc(crtc, 1);
- atombios_enable_crtc(crtc, 0);
if (ASIC_IS_DCE3(rdev))
atombios_enable_crtc_memreq(crtc, 0);
+ atombios_enable_crtc(crtc, 0);
break;
}
@@ -270,59 +266,144 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
static void
atombios_set_crtc_dtd_timing(struct drm_crtc *crtc,
- SET_CRTC_USING_DTD_TIMING_PARAMETERS * crtc_param)
+ struct drm_display_mode *mode)
{
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
- SET_CRTC_USING_DTD_TIMING_PARAMETERS conv_param;
+ SET_CRTC_USING_DTD_TIMING_PARAMETERS args;
int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming);
+ u16 misc = 0;
- conv_param.usH_Size = cpu_to_le16(crtc_param->usH_Size);
- conv_param.usH_Blanking_Time =
- cpu_to_le16(crtc_param->usH_Blanking_Time);
- conv_param.usV_Size = cpu_to_le16(crtc_param->usV_Size);
- conv_param.usV_Blanking_Time =
- cpu_to_le16(crtc_param->usV_Blanking_Time);
- conv_param.usH_SyncOffset = cpu_to_le16(crtc_param->usH_SyncOffset);
- conv_param.usH_SyncWidth = cpu_to_le16(crtc_param->usH_SyncWidth);
- conv_param.usV_SyncOffset = cpu_to_le16(crtc_param->usV_SyncOffset);
- conv_param.usV_SyncWidth = cpu_to_le16(crtc_param->usV_SyncWidth);
- conv_param.susModeMiscInfo.usAccess =
- cpu_to_le16(crtc_param->susModeMiscInfo.usAccess);
- conv_param.ucCRTC = crtc_param->ucCRTC;
+ memset(&args, 0, sizeof(args));
+ args.usH_Size = cpu_to_le16(mode->crtc_hdisplay);
+ args.usH_Blanking_Time =
+ cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay);
+ args.usV_Size = cpu_to_le16(mode->crtc_vdisplay);
+ args.usV_Blanking_Time =
+ cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay);
+ args.usH_SyncOffset =
+ cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay);
+ args.usH_SyncWidth =
+ cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
+ args.usV_SyncOffset =
+ cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay);
+ args.usV_SyncWidth =
+ cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
+ /*args.ucH_Border = mode->hborder;*/
+ /*args.ucV_Border = mode->vborder;*/
+
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ misc |= ATOM_VSYNC_POLARITY;
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ misc |= ATOM_HSYNC_POLARITY;
+ if (mode->flags & DRM_MODE_FLAG_CSYNC)
+ misc |= ATOM_COMPOSITESYNC;
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ misc |= ATOM_INTERLACE;
+ if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+ misc |= ATOM_DOUBLE_CLOCK_MODE;
+
+ args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
+ args.ucCRTC = radeon_crtc->crtc_id;
printk("executing set crtc dtd timing\n");
- atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&conv_param);
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
-void atombios_crtc_set_timing(struct drm_crtc *crtc,
- SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION *
- crtc_param)
+static void atombios_crtc_set_timing(struct drm_crtc *crtc,
+ struct drm_display_mode *mode)
{
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
- SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION conv_param;
+ SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args;
int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing);
+ u16 misc = 0;
- conv_param.usH_Total = cpu_to_le16(crtc_param->usH_Total);
- conv_param.usH_Disp = cpu_to_le16(crtc_param->usH_Disp);
- conv_param.usH_SyncStart = cpu_to_le16(crtc_param->usH_SyncStart);
- conv_param.usH_SyncWidth = cpu_to_le16(crtc_param->usH_SyncWidth);
- conv_param.usV_Total = cpu_to_le16(crtc_param->usV_Total);
- conv_param.usV_Disp = cpu_to_le16(crtc_param->usV_Disp);
- conv_param.usV_SyncStart = cpu_to_le16(crtc_param->usV_SyncStart);
- conv_param.usV_SyncWidth = cpu_to_le16(crtc_param->usV_SyncWidth);
- conv_param.susModeMiscInfo.usAccess =
- cpu_to_le16(crtc_param->susModeMiscInfo.usAccess);
- conv_param.ucCRTC = crtc_param->ucCRTC;
- conv_param.ucOverscanRight = crtc_param->ucOverscanRight;
- conv_param.ucOverscanLeft = crtc_param->ucOverscanLeft;
- conv_param.ucOverscanBottom = crtc_param->ucOverscanBottom;
- conv_param.ucOverscanTop = crtc_param->ucOverscanTop;
- conv_param.ucReserved = crtc_param->ucReserved;
+ memset(&args, 0, sizeof(args));
+ args.usH_Total = cpu_to_le16(mode->crtc_htotal);
+ args.usH_Disp = cpu_to_le16(mode->crtc_hdisplay);
+ args.usH_SyncStart = cpu_to_le16(mode->crtc_hsync_start);
+ args.usH_SyncWidth =
+ cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
+ args.usV_Total = cpu_to_le16(mode->crtc_vtotal);
+ args.usV_Disp = cpu_to_le16(mode->crtc_vdisplay);
+ args.usV_SyncStart = cpu_to_le16(mode->crtc_vsync_start);
+ args.usV_SyncWidth =
+ cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
+
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ misc |= ATOM_VSYNC_POLARITY;
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ misc |= ATOM_HSYNC_POLARITY;
+ if (mode->flags & DRM_MODE_FLAG_CSYNC)
+ misc |= ATOM_COMPOSITESYNC;
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ misc |= ATOM_INTERLACE;
+ if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+ misc |= ATOM_DOUBLE_CLOCK_MODE;
+
+ args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
+ args.ucCRTC = radeon_crtc->crtc_id;
printk("executing set crtc timing\n");
- atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&conv_param);
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+static void atombios_set_ss(struct drm_crtc *crtc, int enable)
+{
+ 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);
+ ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION args;
+ ENABLE_LVDS_SS_PARAMETERS legacy_args;
+ uint16_t percentage = 0;
+ uint8_t type = 0, step = 0, delay = 0, range = 0;
+
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ if (encoder->crtc == crtc) {
+ radeon_encoder = to_radeon_encoder(encoder);
+ dig = radeon_encoder->enc_priv;
+ /* only enable spread spectrum on LVDS */
+ 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 if (enable)
+ return;
+ break;
+ }
+ }
+
+ if (!radeon_encoder)
+ return;
+
+ if (ASIC_IS_AVIVO(rdev)) {
+ memset(&args, 0, sizeof(args));
+ args.usSpreadSpectrumPercentage = percentage;
+ args.ucSpreadSpectrumType = type;
+ args.ucSpreadSpectrumStep = step;
+ args.ucSpreadSpectrumDelay = delay;
+ args.ucSpreadSpectrumRange = range;
+ args.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
+ args.ucEnable = enable;
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+ } else {
+ memset(&legacy_args, 0, sizeof(legacy_args));
+ legacy_args.usSpreadSpectrumPercentage = percentage;
+ legacy_args.ucSpreadSpectrumType = type;
+ legacy_args.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2;
+ legacy_args.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4;
+ legacy_args.ucEnable = enable;
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&legacy_args);
+ }
}
void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
@@ -333,12 +414,13 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
struct drm_encoder *encoder = NULL;
struct radeon_encoder *radeon_encoder = NULL;
uint8_t frev, crev;
- int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
+ int index;
SET_PIXEL_CLOCK_PS_ALLOCATION args;
PIXEL_CLOCK_PARAMETERS *spc1_ptr;
PIXEL_CLOCK_PARAMETERS_V2 *spc2_ptr;
PIXEL_CLOCK_PARAMETERS_V3 *spc3_ptr;
- uint32_t sclock = mode->clock;
+ uint32_t pll_clock = mode->clock;
+ uint32_t adjusted_clock;
uint32_t ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
struct radeon_pll *pll;
int pll_flags = 0;
@@ -346,8 +428,6 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
memset(&args, 0, sizeof(args));
if (ASIC_IS_AVIVO(rdev)) {
- uint32_t ss_cntl;
-
if ((rdev->family == CHIP_RS600) ||
(rdev->family == CHIP_RS690) ||
(rdev->family == CHIP_RS740))
@@ -358,15 +438,6 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
else
pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
-
- /* disable spread spectrum clocking for now -- thanks Hedy Lamarr */
- if (radeon_crtc->crtc_id == 0) {
- ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL);
- WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl & ~1);
- } else {
- ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL);
- WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl & ~1);
- }
} else {
pll_flags |= RADEON_PLL_LEGACY;
@@ -393,14 +464,37 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
}
}
+ /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock
+ * accordingly based on the encoder/transmitter to work around
+ * special hw requirements.
+ */
+ if (ASIC_IS_DCE3(rdev)) {
+ ADJUST_DISPLAY_PLL_PS_ALLOCATION adjust_pll_args;
+
+ if (!encoder)
+ return;
+
+ memset(&adjust_pll_args, 0, sizeof(adjust_pll_args));
+ adjust_pll_args.usPixelClock = cpu_to_le16(mode->clock / 10);
+ adjust_pll_args.ucTransmitterID = radeon_encoder->encoder_id;
+ adjust_pll_args.ucEncodeMode = atombios_get_encoder_mode(encoder);
+
+ index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll);
+ atom_execute_table(rdev->mode_info.atom_context,
+ index, (uint32_t *)&adjust_pll_args);
+ adjusted_clock = le16_to_cpu(adjust_pll_args.usPixelClock) * 10;
+ } else
+ adjusted_clock = mode->clock;
+
if (radeon_crtc->crtc_id == 0)
pll = &rdev->clock.p1pll;
else
pll = &rdev->clock.p2pll;
- radeon_compute_pll(pll, mode->clock, &sclock, &fb_div, &frac_fb_div,
+ radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
&ref_div, &post_div, pll_flags);
+ index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
&crev);
@@ -409,7 +503,7 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
switch (crev) {
case 1:
spc1_ptr = (PIXEL_CLOCK_PARAMETERS *) & args.sPCLKInput;
- spc1_ptr->usPixelClock = cpu_to_le16(sclock);
+ spc1_ptr->usPixelClock = cpu_to_le16(mode->clock / 10);
spc1_ptr->usRefDiv = cpu_to_le16(ref_div);
spc1_ptr->usFbDiv = cpu_to_le16(fb_div);
spc1_ptr->ucFracFbDiv = frac_fb_div;
@@ -422,7 +516,7 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
case 2:
spc2_ptr =
(PIXEL_CLOCK_PARAMETERS_V2 *) & args.sPCLKInput;
- spc2_ptr->usPixelClock = cpu_to_le16(sclock);
+ spc2_ptr->usPixelClock = cpu_to_le16(mode->clock / 10);
spc2_ptr->usRefDiv = cpu_to_le16(ref_div);
spc2_ptr->usFbDiv = cpu_to_le16(fb_div);
spc2_ptr->ucFracFbDiv = frac_fb_div;
@@ -437,7 +531,7 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
return;
spc3_ptr =
(PIXEL_CLOCK_PARAMETERS_V3 *) & args.sPCLKInput;
- spc3_ptr->usPixelClock = cpu_to_le16(sclock);
+ spc3_ptr->usPixelClock = cpu_to_le16(mode->clock / 10);
spc3_ptr->usRefDiv = cpu_to_le16(ref_div);
spc3_ptr->usFbDiv = cpu_to_le16(fb_div);
spc3_ptr->ucFracFbDiv = frac_fb_div;
@@ -527,6 +621,16 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
WREG32(AVIVO_D1VGA_CONTROL, 0);
else
WREG32(AVIVO_D2VGA_CONTROL, 0);
+
+ if (rdev->family >= CHIP_RV770) {
+ if (radeon_crtc->crtc_id) {
+ WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0);
+ WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0);
+ } else {
+ WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0);
+ WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0);
+ }
+ }
WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
(u32) fb_location);
WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS +
@@ -563,6 +667,10 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
radeon_fb = to_radeon_framebuffer(old_fb);
radeon_gem_object_unpin(radeon_fb->obj);
}
+
+ /* Bytes per pixel may have changed */
+ radeon_bandwidth_update(rdev);
+
return 0;
}
@@ -574,134 +682,24 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,
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;
- SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION crtc_timing;
- int need_tv_timings = 0;
- bool ret;
/* TODO color tiling */
- memset(&crtc_timing, 0, sizeof(crtc_timing));
-
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- /* find tv std */
- if (encoder->crtc == crtc) {
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-
- if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) {
- struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv;
- if (tv_dac) {
- if (tv_dac->tv_std == TV_STD_NTSC ||
- tv_dac->tv_std == TV_STD_NTSC_J ||
- tv_dac->tv_std == TV_STD_PAL_M)
- need_tv_timings = 1;
- else
- need_tv_timings = 2;
- break;
- }
- }
- }
- }
-
- crtc_timing.ucCRTC = radeon_crtc->crtc_id;
- if (need_tv_timings) {
- ret = radeon_atom_get_tv_timings(rdev, need_tv_timings - 1,
- &crtc_timing, &adjusted_mode->clock);
- if (ret == false)
- need_tv_timings = 0;
- }
-
- if (!need_tv_timings) {
- crtc_timing.usH_Total = adjusted_mode->crtc_htotal;
- crtc_timing.usH_Disp = adjusted_mode->crtc_hdisplay;
- crtc_timing.usH_SyncStart = adjusted_mode->crtc_hsync_start;
- crtc_timing.usH_SyncWidth =
- adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
-
- crtc_timing.usV_Total = adjusted_mode->crtc_vtotal;
- crtc_timing.usV_Disp = adjusted_mode->crtc_vdisplay;
- crtc_timing.usV_SyncStart = adjusted_mode->crtc_vsync_start;
- crtc_timing.usV_SyncWidth =
- adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
-
- if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
- crtc_timing.susModeMiscInfo.usAccess |= ATOM_VSYNC_POLARITY;
-
- if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
- crtc_timing.susModeMiscInfo.usAccess |= ATOM_HSYNC_POLARITY;
-
- if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC)
- crtc_timing.susModeMiscInfo.usAccess |= ATOM_COMPOSITESYNC;
-
- if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
- crtc_timing.susModeMiscInfo.usAccess |= ATOM_INTERLACE;
-
- if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
- crtc_timing.susModeMiscInfo.usAccess |= ATOM_DOUBLE_CLOCK_MODE;
- }
+ atombios_set_ss(crtc, 0);
atombios_crtc_set_pll(crtc, adjusted_mode);
- atombios_crtc_set_timing(crtc, &crtc_timing);
+ atombios_set_ss(crtc, 1);
+ atombios_crtc_set_timing(crtc, adjusted_mode);
if (ASIC_IS_AVIVO(rdev))
atombios_crtc_set_base(crtc, x, y, old_fb);
else {
- if (radeon_crtc->crtc_id == 0) {
- SET_CRTC_USING_DTD_TIMING_PARAMETERS crtc_dtd_timing;
- memset(&crtc_dtd_timing, 0, sizeof(crtc_dtd_timing));
-
- /* setup FP shadow regs on R4xx */
- crtc_dtd_timing.ucCRTC = radeon_crtc->crtc_id;
- crtc_dtd_timing.usH_Size = adjusted_mode->crtc_hdisplay;
- crtc_dtd_timing.usV_Size = adjusted_mode->crtc_vdisplay;
- crtc_dtd_timing.usH_Blanking_Time =
- adjusted_mode->crtc_hblank_end -
- adjusted_mode->crtc_hdisplay;
- crtc_dtd_timing.usV_Blanking_Time =
- adjusted_mode->crtc_vblank_end -
- adjusted_mode->crtc_vdisplay;
- crtc_dtd_timing.usH_SyncOffset =
- adjusted_mode->crtc_hsync_start -
- adjusted_mode->crtc_hdisplay;
- crtc_dtd_timing.usV_SyncOffset =
- adjusted_mode->crtc_vsync_start -
- adjusted_mode->crtc_vdisplay;
- crtc_dtd_timing.usH_SyncWidth =
- adjusted_mode->crtc_hsync_end -
- adjusted_mode->crtc_hsync_start;
- crtc_dtd_timing.usV_SyncWidth =
- adjusted_mode->crtc_vsync_end -
- adjusted_mode->crtc_vsync_start;
- /* crtc_dtd_timing.ucH_Border = adjusted_mode->crtc_hborder; */
- /* crtc_dtd_timing.ucV_Border = adjusted_mode->crtc_vborder; */
-
- if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
- crtc_dtd_timing.susModeMiscInfo.usAccess |=
- ATOM_VSYNC_POLARITY;
-
- if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
- crtc_dtd_timing.susModeMiscInfo.usAccess |=
- ATOM_HSYNC_POLARITY;
-
- if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC)
- crtc_dtd_timing.susModeMiscInfo.usAccess |=
- ATOM_COMPOSITESYNC;
-
- if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
- crtc_dtd_timing.susModeMiscInfo.usAccess |=
- ATOM_INTERLACE;
-
- if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
- crtc_dtd_timing.susModeMiscInfo.usAccess |=
- ATOM_DOUBLE_CLOCK_MODE;
-
- atombios_set_crtc_dtd_timing(crtc, &crtc_dtd_timing);
- }
+ if (radeon_crtc->crtc_id == 0)
+ atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
radeon_crtc_set_base(crtc, x, y, old_fb);
radeon_legacy_atom_set_surface(crtc);
}
atombios_overscan_setup(crtc, mode, adjusted_mode);
atombios_scaler_setup(crtc);
- radeon_bandwidth_update(rdev);
return 0;
}
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 161094c07d94..28779edbaaba 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -186,7 +186,7 @@ static inline uint32_t r100_irq_ack(struct radeon_device *rdev)
int r100_irq_process(struct radeon_device *rdev)
{
- uint32_t status;
+ uint32_t status, msi_rearm;
status = r100_irq_ack(rdev);
if (!status) {
@@ -209,6 +209,21 @@ int r100_irq_process(struct radeon_device *rdev)
}
status = r100_irq_ack(rdev);
}
+ if (rdev->msi_enabled) {
+ switch (rdev->family) {
+ case CHIP_RS400:
+ case CHIP_RS480:
+ msi_rearm = RREG32(RADEON_AIC_CNTL) & ~RS400_MSI_REARM;
+ WREG32(RADEON_AIC_CNTL, msi_rearm);
+ WREG32(RADEON_AIC_CNTL, msi_rearm | RS400_MSI_REARM);
+ break;
+ default:
+ msi_rearm = RREG32(RADEON_MSI_REARM_EN) & ~RV370_MSI_REARM_EN;
+ WREG32(RADEON_MSI_REARM_EN, msi_rearm);
+ WREG32(RADEON_MSI_REARM_EN, msi_rearm | RV370_MSI_REARM_EN);
+ break;
+ }
+ }
return IRQ_HANDLED;
}
@@ -240,7 +255,7 @@ int r100_wb_init(struct radeon_device *rdev)
int r;
if (rdev->wb.wb_obj == NULL) {
- r = radeon_object_create(rdev, NULL, 4096,
+ r = radeon_object_create(rdev, NULL, RADEON_GPU_PAGE_SIZE,
true,
RADEON_GEM_DOMAIN_GTT,
false, &rdev->wb.wb_obj);
@@ -2364,7 +2379,7 @@ void r100_bandwidth_update(struct radeon_device *rdev)
/*
Find the total latency for the display data.
*/
- disp_latency_overhead.full = rfixed_const(80);
+ disp_latency_overhead.full = rfixed_const(8);
disp_latency_overhead.full = rfixed_div(disp_latency_overhead, sclk_ff);
mc_latency_mclk.full += disp_latency_overhead.full + cur_latency_mclk.full;
mc_latency_sclk.full += disp_latency_overhead.full + cur_latency_sclk.full;
@@ -2562,8 +2577,11 @@ void r100_bandwidth_update(struct radeon_device *rdev)
static inline void r100_cs_track_texture_print(struct r100_cs_track_texture *t)
{
DRM_ERROR("pitch %d\n", t->pitch);
+ DRM_ERROR("use_pitch %d\n", t->use_pitch);
DRM_ERROR("width %d\n", t->width);
+ DRM_ERROR("width_11 %d\n", t->width_11);
DRM_ERROR("height %d\n", t->height);
+ DRM_ERROR("height_11 %d\n", t->height_11);
DRM_ERROR("num levels %d\n", t->num_levels);
DRM_ERROR("depth %d\n", t->txdepth);
DRM_ERROR("bpp %d\n", t->cpp);
@@ -2623,15 +2641,17 @@ static int r100_cs_track_texture_check(struct radeon_device *rdev,
else
w = track->textures[u].pitch / (1 << i);
} else {
- w = track->textures[u].width / (1 << i);
+ w = track->textures[u].width;
if (rdev->family >= CHIP_RV515)
w |= track->textures[u].width_11;
+ w = w / (1 << i);
if (track->textures[u].roundup_w)
w = roundup_pow_of_two(w);
}
- h = track->textures[u].height / (1 << i);
+ h = track->textures[u].height;
if (rdev->family >= CHIP_RV515)
h |= track->textures[u].height_11;
+ h = h / (1 << i);
if (track->textures[u].roundup_h)
h = roundup_pow_of_two(h);
size += w * h;
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index e08c4a8974ca..2f43ee8e4048 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -113,7 +113,7 @@ int rv370_pcie_gart_enable(struct radeon_device *rdev)
tmp = RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD;
WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp);
WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, rdev->mc.gtt_location);
- tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 4096;
+ tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - RADEON_GPU_PAGE_SIZE;
WREG32_PCIE(RADEON_PCIE_TX_GART_END_LO, tmp);
WREG32_PCIE(RADEON_PCIE_TX_GART_START_HI, 0);
WREG32_PCIE(RADEON_PCIE_TX_GART_END_HI, 0);
diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h
index 868add6e166d..7baa73955563 100644
--- a/drivers/gpu/drm/radeon/r500_reg.h
+++ b/drivers/gpu/drm/radeon/r500_reg.h
@@ -384,9 +384,16 @@
# define AVIVO_D1GRPH_TILED (1 << 20)
# define AVIVO_D1GRPH_MACRO_ADDRESS_MODE (1 << 21)
+/* The R7xx *_HIGH surface regs are backwards; the D1 regs are in the D2
+ * block and vice versa. This applies to GRPH, CUR, etc.
+ */
#define AVIVO_D1GRPH_LUT_SEL 0x6108
#define AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS 0x6110
+#define R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6914
+#define R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6114
#define AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS 0x6118
+#define R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x691c
+#define R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x611c
#define AVIVO_D1GRPH_PITCH 0x6120
#define AVIVO_D1GRPH_SURFACE_OFFSET_X 0x6124
#define AVIVO_D1GRPH_SURFACE_OFFSET_Y 0x6128
@@ -404,6 +411,8 @@
# define AVIVO_D1CURSOR_MODE_MASK (3 << 8)
# define AVIVO_D1CURSOR_MODE_24BPP 2
#define AVIVO_D1CUR_SURFACE_ADDRESS 0x6408
+#define R700_D1CUR_SURFACE_ADDRESS_HIGH 0x6c0c
+#define R700_D2CUR_SURFACE_ADDRESS_HIGH 0x640c
#define AVIVO_D1CUR_SIZE 0x6410
#define AVIVO_D1CUR_POSITION 0x6414
#define AVIVO_D1CUR_HOT_SPOT 0x6418
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 609719490ec2..136ce622b028 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -339,11 +339,10 @@ int r600_mc_init(struct radeon_device *rdev)
{
fixed20_12 a;
u32 tmp;
- int chansize;
+ int chansize, numchan;
int r;
/* Get VRAM informations */
- rdev->mc.vram_width = 128;
rdev->mc.vram_is_ddr = true;
tmp = RREG32(RAMCFG);
if (tmp & CHANSIZE_OVERRIDE) {
@@ -353,17 +352,23 @@ int r600_mc_init(struct radeon_device *rdev)
} else {
chansize = 32;
}
- if (rdev->family == CHIP_R600) {
- rdev->mc.vram_width = 8 * chansize;
- } else if (rdev->family == CHIP_RV670) {
- rdev->mc.vram_width = 4 * chansize;
- } else if ((rdev->family == CHIP_RV610) ||
- (rdev->family == CHIP_RV620)) {
- rdev->mc.vram_width = chansize;
- } else if ((rdev->family == CHIP_RV630) ||
- (rdev->family == CHIP_RV635)) {
- rdev->mc.vram_width = 2 * chansize;
+ tmp = RREG32(CHMAP);
+ switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
+ case 0:
+ default:
+ numchan = 1;
+ break;
+ case 1:
+ numchan = 2;
+ break;
+ case 2:
+ numchan = 4;
+ break;
+ case 3:
+ numchan = 8;
+ break;
}
+ rdev->mc.vram_width = numchan * chansize;
/* Could aper size report 0 ? */
rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
@@ -1269,9 +1274,9 @@ int r600_cp_resume(struct radeon_device *rdev)
rb_bufsz = drm_order(rdev->cp.ring_size / 8);
#ifdef __BIG_ENDIAN
WREG32(CP_RB_CNTL, BUF_SWAP_32BIT | RB_NO_UPDATE |
- (drm_order(4096/8) << 8) | rb_bufsz);
+ (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz);
#else
- WREG32(CP_RB_CNTL, RB_NO_UPDATE | (drm_order(4096/8) << 8) | rb_bufsz);
+ WREG32(CP_RB_CNTL, RB_NO_UPDATE | (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz);
#endif
WREG32(CP_SEM_WAIT_TIMER, 0x4);
@@ -1400,7 +1405,7 @@ int r600_wb_enable(struct radeon_device *rdev)
int r;
if (rdev->wb.wb_obj == NULL) {
- r = radeon_object_create(rdev, NULL, 4096, true,
+ r = radeon_object_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, true,
RADEON_GEM_DOMAIN_GTT, false, &rdev->wb.wb_obj);
if (r) {
dev_warn(rdev->dev, "failed to create WB buffer (%d).\n", r);
@@ -1450,8 +1455,8 @@ int r600_copy_blit(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_pages, struct radeon_fence *fence)
{
- r600_blit_prepare_copy(rdev, num_pages * 4096);
- r600_kms_blit_copy(rdev, src_offset, dst_offset, num_pages * 4096);
+ r600_blit_prepare_copy(rdev, num_pages * RADEON_GPU_PAGE_SIZE);
+ r600_kms_blit_copy(rdev, src_offset, dst_offset, num_pages * RADEON_GPU_PAGE_SIZE);
r600_blit_done_copy(rdev, fence);
return 0;
}
diff --git a/drivers/gpu/drm/radeon/r600_blit.c b/drivers/gpu/drm/radeon/r600_blit.c
index dec501081608..5ea432347589 100644
--- a/drivers/gpu/drm/radeon/r600_blit.c
+++ b/drivers/gpu/drm/radeon/r600_blit.c
@@ -582,6 +582,8 @@ r600_blit_copy(struct drm_device *dev,
u64 vb_addr;
u32 *vb;
+ vb = r600_nomm_get_vb_ptr(dev);
+
if ((size_bytes & 3) || (src_gpu_addr & 3) || (dst_gpu_addr & 3)) {
max_bytes = 8192;
@@ -617,8 +619,8 @@ r600_blit_copy(struct drm_device *dev,
if (!dev_priv->blit_vb)
return;
set_shaders(dev);
+ vb = r600_nomm_get_vb_ptr(dev);
}
- vb = r600_nomm_get_vb_ptr(dev);
vb[0] = i2f(dst_x);
vb[1] = 0;
@@ -706,8 +708,8 @@ r600_blit_copy(struct drm_device *dev,
return;
set_shaders(dev);
+ vb = r600_nomm_get_vb_ptr(dev);
}
- vb = r600_nomm_get_vb_ptr(dev);
vb[0] = i2f(dst_x / 4);
vb[1] = 0;
@@ -772,6 +774,7 @@ r600_blit_swap(struct drm_device *dev,
{
drm_radeon_private_t *dev_priv = dev->dev_private;
int cb_format, tex_format;
+ int sx2, sy2, dx2, dy2;
u64 vb_addr;
u32 *vb;
@@ -786,16 +789,10 @@ r600_blit_swap(struct drm_device *dev,
}
vb = r600_nomm_get_vb_ptr(dev);
- if (cpp == 4) {
- cb_format = COLOR_8_8_8_8;
- tex_format = FMT_8_8_8_8;
- } else if (cpp == 2) {
- cb_format = COLOR_5_6_5;
- tex_format = FMT_5_6_5;
- } else {
- cb_format = COLOR_8;
- tex_format = FMT_8;
- }
+ sx2 = sx + w;
+ sy2 = sy + h;
+ dx2 = dx + w;
+ dy2 = dy + h;
vb[0] = i2f(dx);
vb[1] = i2f(dy);
@@ -803,31 +800,46 @@ r600_blit_swap(struct drm_device *dev,
vb[3] = i2f(sy);
vb[4] = i2f(dx);
- vb[5] = i2f(dy + h);
+ vb[5] = i2f(dy2);
vb[6] = i2f(sx);
- vb[7] = i2f(sy + h);
+ vb[7] = i2f(sy2);
+
+ vb[8] = i2f(dx2);
+ vb[9] = i2f(dy2);
+ vb[10] = i2f(sx2);
+ vb[11] = i2f(sy2);
- vb[8] = i2f(dx + w);
- vb[9] = i2f(dy + h);
- vb[10] = i2f(sx + w);
- vb[11] = i2f(sy + h);
+ switch(cpp) {
+ case 4:
+ cb_format = COLOR_8_8_8_8;
+ tex_format = FMT_8_8_8_8;
+ break;
+ case 2:
+ cb_format = COLOR_5_6_5;
+ tex_format = FMT_5_6_5;
+ break;
+ default:
+ cb_format = COLOR_8;
+ tex_format = FMT_8;
+ break;
+ }
/* src */
set_tex_resource(dev_priv, tex_format,
src_pitch / cpp,
- sy + h, src_pitch / cpp,
+ sy2, src_pitch / cpp,
src_gpu_addr);
cp_set_surface_sync(dev_priv,
- R600_TC_ACTION_ENA, (src_pitch * (sy + h)), src_gpu_addr);
+ R600_TC_ACTION_ENA, src_pitch * sy2, src_gpu_addr);
/* dst */
set_render_target(dev_priv, cb_format,
- dst_pitch / cpp, dy + h,
+ dst_pitch / cpp, dy2,
dst_gpu_addr);
/* scissors */
- set_scissors(dev_priv, dx, dy, dx + w, dy + h);
+ set_scissors(dev_priv, dx, dy, dx2, dy2);
/* Vertex buffer setup */
vb_addr = dev_priv->gart_buffers_offset +
@@ -840,7 +852,7 @@ r600_blit_swap(struct drm_device *dev,
cp_set_surface_sync(dev_priv,
R600_CB_ACTION_ENA | R600_CB0_DEST_BASE_ENA,
- dst_pitch * (dy + h), dst_gpu_addr);
+ dst_pitch * dy2, dst_gpu_addr);
dev_priv->blit_vb->used += 12 * 4;
}
diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c
index 93108bb31d1d..acae33e2ad51 100644
--- a/drivers/gpu/drm/radeon/r600_blit_kms.c
+++ b/drivers/gpu/drm/radeon/r600_blit_kms.c
@@ -610,6 +610,7 @@ void r600_kms_blit_copy(struct radeon_device *rdev,
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;
@@ -652,7 +653,6 @@ void r600_kms_blit_copy(struct radeon_device *rdev,
vb = r600_nomm_get_vb_ptr(dev);
#endif
}
- vb = (u32 *)(rdev->r600_blit.vb_ib->ptr + rdev->r600_blit.vb_used);
vb[0] = i2f(dst_x);
vb[1] = 0;
@@ -747,7 +747,6 @@ void r600_kms_blit_copy(struct radeon_device *rdev,
vb = r600_nomm_get_vb_ptr(dev);
}
#endif
- vb = (u32 *)(rdev->r600_blit.vb_ib->ptr + rdev->r600_blit.vb_used);
vb[0] = i2f(dst_x / 4);
vb[1] = 0;
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index 9b64d47f1f82..00d9642198a3 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -271,6 +271,10 @@
#define PCIE_PORT_INDEX 0x0038
#define PCIE_PORT_DATA 0x003C
+#define CHMAP 0x2004
+#define NOOFCHAN_SHIFT 12
+#define NOOFCHAN_MASK 0x00003000
+
#define RAMCFG 0x2408
#define NOOFBANK_SHIFT 0
#define NOOFBANK_MASK 0x00000001
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 5ab35b81c86b..620a7c8ca016 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -276,6 +276,8 @@ union radeon_gart_table {
struct radeon_gart_table_vram vram;
};
+#define RADEON_GPU_PAGE_SIZE 4096
+
struct radeon_gart {
dma_addr_t table_addr;
unsigned num_gpu_pages;
@@ -783,6 +785,7 @@ struct radeon_device {
const struct firmware *me_fw; /* all family ME firmware */
const struct firmware *pfp_fw; /* r6/700 PFP firmware */
struct r600_blit r600_blit;
+ int msi_enabled; /* msi enabled */
};
int radeon_device_init(struct radeon_device *rdev,
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 5b6c08cee40e..18729259c2fc 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -641,8 +641,12 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
le16_to_cpu(firmware_info->info.usReferenceClock);
p1pll->reference_div = 0;
- p1pll->pll_out_min =
- le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output);
+ if (crev < 2)
+ p1pll->pll_out_min =
+ le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output);
+ else
+ p1pll->pll_out_min =
+ le32_to_cpu(firmware_info->info_12.ulMinPixelClockPLL_Output);
p1pll->pll_out_max =
le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output);
@@ -767,6 +771,46 @@ 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)
+{
+ 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;
+ struct _ATOM_SPREAD_SPECTRUM_INFO *ss_info;
+ uint8_t frev, crev;
+ struct radeon_atom_ss *ss = NULL;
+
+ if (id > ATOM_MAX_SS_ENTRY)
+ return NULL;
+
+ atom_parse_data_header(mode_info->atom_context, index, NULL, &frev,
+ &crev, &data_offset);
+
+ ss_info =
+ (struct _ATOM_SPREAD_SPECTRUM_INFO *)(mode_info->atom_context->bios + data_offset);
+
+ if (ss_info) {
+ ss =
+ kzalloc(sizeof(struct radeon_atom_ss), GFP_KERNEL);
+
+ if (!ss)
+ return NULL;
+
+ ss->percentage = le16_to_cpu(ss_info->asSS_Info[id].usSpreadSpectrumPercentage);
+ ss->type = ss_info->asSS_Info[id].ucSpreadSpectrumType;
+ ss->step = ss_info->asSS_Info[id].ucSS_Step;
+ ss->delay = ss_info->asSS_Info[id].ucSS_Delay;
+ ss->range = ss_info->asSS_Info[id].ucSS_Range;
+ ss->refdiv = ss_info->asSS_Info[id].ucRecommendedRef_Div;
+ }
+ return ss;
+}
+
union lvds_info {
struct _ATOM_LVDS_INFO info;
struct _ATOM_LVDS_INFO_V12 info_12;
@@ -798,27 +842,31 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
if (!lvds)
return NULL;
- lvds->native_mode.dotclock =
+ lvds->native_mode.clock =
le16_to_cpu(lvds_info->info.sLCDTiming.usPixClk) * 10;
- lvds->native_mode.panel_xres =
+ lvds->native_mode.hdisplay =
le16_to_cpu(lvds_info->info.sLCDTiming.usHActive);
- lvds->native_mode.panel_yres =
+ lvds->native_mode.vdisplay =
le16_to_cpu(lvds_info->info.sLCDTiming.usVActive);
- lvds->native_mode.hblank =
- le16_to_cpu(lvds_info->info.sLCDTiming.usHBlanking_Time);
- lvds->native_mode.hoverplus =
- le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncOffset);
- lvds->native_mode.hsync_width =
- le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncWidth);
- lvds->native_mode.vblank =
- le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time);
- lvds->native_mode.voverplus =
- le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset);
- lvds->native_mode.vsync_width =
- le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth);
+ lvds->native_mode.htotal = lvds->native_mode.hdisplay +
+ le16_to_cpu(lvds_info->info.sLCDTiming.usHBlanking_Time);
+ lvds->native_mode.hsync_start = lvds->native_mode.hdisplay +
+ le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncOffset);
+ lvds->native_mode.hsync_end = lvds->native_mode.hsync_start +
+ le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncWidth);
+ lvds->native_mode.vtotal = lvds->native_mode.vdisplay +
+ le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time);
+ lvds->native_mode.vsync_start = lvds->native_mode.vdisplay +
+ le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth);
+ lvds->native_mode.vsync_end = lvds->native_mode.vsync_start +
+ 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;
+ /* 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);
encoder->native_mode = lvds->native_mode;
}
@@ -857,8 +905,7 @@ radeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder)
}
bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
- SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION *crtc_timing,
- int32_t *pixel_clock)
+ struct drm_display_mode *mode)
{
struct radeon_mode_info *mode_info = &rdev->mode_info;
ATOM_ANALOG_TV_INFO *tv_info;
@@ -866,7 +913,7 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
ATOM_DTD_FORMAT *dtd_timings;
int data_index = GetIndexIntoMasterTable(DATA, AnalogTV_Info);
u8 frev, crev;
- uint16_t data_offset;
+ u16 data_offset, misc;
atom_parse_data_header(mode_info->atom_context, data_index, NULL, &frev, &crev, &data_offset);
@@ -876,28 +923,37 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
if (index > MAX_SUPPORTED_TV_TIMING)
return false;
- crtc_timing->usH_Total = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Total);
- crtc_timing->usH_Disp = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Disp);
- crtc_timing->usH_SyncStart = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart);
- crtc_timing->usH_SyncWidth = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncWidth);
-
- crtc_timing->usV_Total = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Total);
- crtc_timing->usV_Disp = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Disp);
- crtc_timing->usV_SyncStart = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart);
- crtc_timing->usV_SyncWidth = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncWidth);
-
- crtc_timing->susModeMiscInfo = tv_info->aModeTimings[index].susModeMiscInfo;
-
- crtc_timing->ucOverscanRight = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_OverscanRight);
- crtc_timing->ucOverscanLeft = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_OverscanLeft);
- crtc_timing->ucOverscanBottom = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_OverscanBottom);
- crtc_timing->ucOverscanTop = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_OverscanTop);
- *pixel_clock = le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10;
+ mode->crtc_htotal = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Total);
+ mode->crtc_hdisplay = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Disp);
+ mode->crtc_hsync_start = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart);
+ mode->crtc_hsync_end = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart) +
+ le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncWidth);
+
+ mode->crtc_vtotal = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Total);
+ mode->crtc_vdisplay = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Disp);
+ mode->crtc_vsync_start = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart);
+ mode->crtc_vsync_end = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart) +
+ le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncWidth);
+
+ mode->flags = 0;
+ misc = le16_to_cpu(tv_info->aModeTimings[index].susModeMiscInfo.usAccess);
+ if (misc & ATOM_VSYNC_POLARITY)
+ mode->flags |= DRM_MODE_FLAG_NVSYNC;
+ if (misc & ATOM_HSYNC_POLARITY)
+ mode->flags |= DRM_MODE_FLAG_NHSYNC;
+ if (misc & ATOM_COMPOSITESYNC)
+ mode->flags |= DRM_MODE_FLAG_CSYNC;
+ if (misc & ATOM_INTERLACE)
+ mode->flags |= DRM_MODE_FLAG_INTERLACE;
+ if (misc & ATOM_DOUBLE_CLOCK_MODE)
+ mode->flags |= DRM_MODE_FLAG_DBLSCAN;
+
+ mode->clock = le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10;
if (index == 1) {
/* PAL timings appear to have wrong values for totals */
- crtc_timing->usH_Total -= 1;
- crtc_timing->usV_Total -= 1;
+ mode->crtc_htotal -= 1;
+ mode->crtc_vtotal -= 1;
}
break;
case 2:
@@ -906,17 +962,36 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
return false;
dtd_timings = &tv_info_v1_2->aModeTimings[index];
- crtc_timing->usH_Total = le16_to_cpu(dtd_timings->usHActive) + le16_to_cpu(dtd_timings->usHBlanking_Time);
- crtc_timing->usH_Disp = le16_to_cpu(dtd_timings->usHActive);
- crtc_timing->usH_SyncStart = le16_to_cpu(dtd_timings->usHActive) + le16_to_cpu(dtd_timings->usHSyncOffset);
- crtc_timing->usH_SyncWidth = le16_to_cpu(dtd_timings->usHSyncWidth);
- crtc_timing->usV_Total = le16_to_cpu(dtd_timings->usVActive) + le16_to_cpu(dtd_timings->usVBlanking_Time);
- crtc_timing->usV_Disp = le16_to_cpu(dtd_timings->usVActive);
- crtc_timing->usV_SyncStart = le16_to_cpu(dtd_timings->usVActive) + le16_to_cpu(dtd_timings->usVSyncOffset);
- crtc_timing->usV_SyncWidth = le16_to_cpu(dtd_timings->usVSyncWidth);
-
- crtc_timing->susModeMiscInfo.usAccess = le16_to_cpu(dtd_timings->susModeMiscInfo.usAccess);
- *pixel_clock = le16_to_cpu(dtd_timings->usPixClk) * 10;
+ mode->crtc_htotal = le16_to_cpu(dtd_timings->usHActive) +
+ le16_to_cpu(dtd_timings->usHBlanking_Time);
+ mode->crtc_hdisplay = le16_to_cpu(dtd_timings->usHActive);
+ mode->crtc_hsync_start = le16_to_cpu(dtd_timings->usHActive) +
+ le16_to_cpu(dtd_timings->usHSyncOffset);
+ mode->crtc_hsync_end = mode->crtc_hsync_start +
+ le16_to_cpu(dtd_timings->usHSyncWidth);
+
+ mode->crtc_vtotal = le16_to_cpu(dtd_timings->usVActive) +
+ le16_to_cpu(dtd_timings->usVBlanking_Time);
+ mode->crtc_vdisplay = le16_to_cpu(dtd_timings->usVActive);
+ mode->crtc_vsync_start = le16_to_cpu(dtd_timings->usVActive) +
+ le16_to_cpu(dtd_timings->usVSyncOffset);
+ mode->crtc_vsync_end = mode->crtc_vsync_start +
+ le16_to_cpu(dtd_timings->usVSyncWidth);
+
+ mode->flags = 0;
+ misc = le16_to_cpu(dtd_timings->susModeMiscInfo.usAccess);
+ if (misc & ATOM_VSYNC_POLARITY)
+ mode->flags |= DRM_MODE_FLAG_NVSYNC;
+ if (misc & ATOM_HSYNC_POLARITY)
+ mode->flags |= DRM_MODE_FLAG_NHSYNC;
+ if (misc & ATOM_COMPOSITESYNC)
+ mode->flags |= DRM_MODE_FLAG_CSYNC;
+ if (misc & ATOM_INTERLACE)
+ mode->flags |= DRM_MODE_FLAG_INTERLACE;
+ if (misc & ATOM_DOUBLE_CLOCK_MODE)
+ mode->flags |= DRM_MODE_FLAG_DBLSCAN;
+
+ mode->clock = le16_to_cpu(dtd_timings->usPixClk) * 10;
break;
}
return true;
diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c
index 2e938f7496fb..10bd50a7db87 100644
--- a/drivers/gpu/drm/radeon/radeon_benchmark.c
+++ b/drivers/gpu/drm/radeon/radeon_benchmark.c
@@ -63,7 +63,7 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize,
if (r) {
goto out_cleanup;
}
- r = radeon_copy_dma(rdev, saddr, daddr, size / 4096, fence);
+ r = radeon_copy_dma(rdev, saddr, daddr, size / RADEON_GPU_PAGE_SIZE, fence);
if (r) {
goto out_cleanup;
}
@@ -88,7 +88,7 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize,
if (r) {
goto out_cleanup;
}
- r = radeon_copy_blit(rdev, saddr, daddr, size / 4096, fence);
+ r = radeon_copy_blit(rdev, saddr, daddr, size / RADEON_GPU_PAGE_SIZE, fence);
if (r) {
goto out_cleanup;
}
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index 748265a105b3..fcb9371bf057 100644
--- a/drivers/gpu/drm/radeon/radeon_combios.c
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
@@ -808,25 +808,25 @@ static struct radeon_encoder_lvds *radeon_legacy_get_lvds_info_from_regs(struct
lvds->panel_blon_delay = (lvds_ss_gen_cntl >> RADEON_LVDS_PWRSEQ_DELAY2_SHIFT) & 0xf;
if (fp_vert_stretch & RADEON_VERT_STRETCH_ENABLE)
- lvds->native_mode.panel_yres =
+ lvds->native_mode.vdisplay =
((fp_vert_stretch & RADEON_VERT_PANEL_SIZE) >>
RADEON_VERT_PANEL_SHIFT) + 1;
else
- lvds->native_mode.panel_yres =
+ lvds->native_mode.vdisplay =
(RREG32(RADEON_CRTC_V_TOTAL_DISP) >> 16) + 1;
if (fp_horz_stretch & RADEON_HORZ_STRETCH_ENABLE)
- lvds->native_mode.panel_xres =
+ lvds->native_mode.hdisplay =
(((fp_horz_stretch & RADEON_HORZ_PANEL_SIZE) >>
RADEON_HORZ_PANEL_SHIFT) + 1) * 8;
else
- lvds->native_mode.panel_xres =
+ lvds->native_mode.hdisplay =
((RREG32(RADEON_CRTC_H_TOTAL_DISP) >> 16) + 1) * 8;
- if ((lvds->native_mode.panel_xres < 640) ||
- (lvds->native_mode.panel_yres < 480)) {
- lvds->native_mode.panel_xres = 640;
- lvds->native_mode.panel_yres = 480;
+ if ((lvds->native_mode.hdisplay < 640) ||
+ (lvds->native_mode.vdisplay < 480)) {
+ lvds->native_mode.hdisplay = 640;
+ lvds->native_mode.vdisplay = 480;
}
ppll_div_sel = RREG8(RADEON_CLOCK_CNTL_INDEX + 1) & 0x3;
@@ -846,8 +846,8 @@ static struct radeon_encoder_lvds *radeon_legacy_get_lvds_info_from_regs(struct
lvds->panel_vcc_delay = 200;
DRM_INFO("Panel info derived from registers\n");
- DRM_INFO("Panel Size %dx%d\n", lvds->native_mode.panel_xres,
- lvds->native_mode.panel_yres);
+ DRM_INFO("Panel Size %dx%d\n", lvds->native_mode.hdisplay,
+ lvds->native_mode.vdisplay);
return lvds;
}
@@ -882,11 +882,11 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder
DRM_INFO("Panel ID String: %s\n", stmp);
- lvds->native_mode.panel_xres = RBIOS16(lcd_info + 0x19);
- lvds->native_mode.panel_yres = RBIOS16(lcd_info + 0x1b);
+ lvds->native_mode.hdisplay = RBIOS16(lcd_info + 0x19);
+ lvds->native_mode.vdisplay = RBIOS16(lcd_info + 0x1b);
- DRM_INFO("Panel Size %dx%d\n", lvds->native_mode.panel_xres,
- lvds->native_mode.panel_yres);
+ DRM_INFO("Panel Size %dx%d\n", lvds->native_mode.hdisplay,
+ lvds->native_mode.vdisplay);
lvds->panel_vcc_delay = RBIOS16(lcd_info + 0x2c);
if (lvds->panel_vcc_delay > 2000 || lvds->panel_vcc_delay < 0)
@@ -944,27 +944,25 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder
if (tmp == 0)
break;
- if ((RBIOS16(tmp) == lvds->native_mode.panel_xres) &&
+ if ((RBIOS16(tmp) == lvds->native_mode.hdisplay) &&
(RBIOS16(tmp + 2) ==
- lvds->native_mode.panel_yres)) {
- lvds->native_mode.hblank =
- (RBIOS16(tmp + 17) - RBIOS16(tmp + 19)) * 8;
- lvds->native_mode.hoverplus =
- (RBIOS16(tmp + 21) - RBIOS16(tmp + 19) -
- 1) * 8;
- lvds->native_mode.hsync_width =
- RBIOS8(tmp + 23) * 8;
-
- lvds->native_mode.vblank = (RBIOS16(tmp + 24) -
- RBIOS16(tmp + 26));
- lvds->native_mode.voverplus =
- ((RBIOS16(tmp + 28) & 0x7ff) -
- RBIOS16(tmp + 26));
- lvds->native_mode.vsync_width =
- ((RBIOS16(tmp + 28) & 0xf800) >> 11);
- lvds->native_mode.dotclock =
- RBIOS16(tmp + 9) * 10;
+ lvds->native_mode.vdisplay)) {
+ lvds->native_mode.htotal = RBIOS16(tmp + 17) * 8;
+ lvds->native_mode.hsync_start = RBIOS16(tmp + 21) * 8;
+ lvds->native_mode.hsync_end = (RBIOS8(tmp + 23) +
+ RBIOS16(tmp + 21)) * 8;
+
+ lvds->native_mode.vtotal = RBIOS16(tmp + 24);
+ lvds->native_mode.vsync_start = RBIOS16(tmp + 28) & 0x7ff;
+ lvds->native_mode.vsync_end =
+ ((RBIOS16(tmp + 28) & 0xf800) >> 11) +
+ (RBIOS16(tmp + 28) & 0x7ff);
+
+ lvds->native_mode.clock = RBIOS16(tmp + 9) * 10;
lvds->native_mode.flags = 0;
+ /* set crtc values */
+ drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V);
+
}
}
} else {
@@ -1581,6 +1579,17 @@ static bool radeon_apply_legacy_quirks(struct drm_device *dev,
return true;
}
+static bool radeon_apply_legacy_tv_quirks(struct drm_device *dev)
+{
+ /* Acer 5102 has non-existent TV port */
+ if (dev->pdev->device == 0x5975 &&
+ dev->pdev->subsystem_vendor == 0x1025 &&
+ dev->pdev->subsystem_device == 0x009f)
+ return false;
+
+ return true;
+}
+
bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
{
struct radeon_device *rdev = dev->dev_private;
@@ -1628,8 +1637,9 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
break;
}
- radeon_apply_legacy_quirks(dev, i, &connector,
- &ddc_i2c);
+ if (!radeon_apply_legacy_quirks(dev, i, &connector,
+ &ddc_i2c))
+ continue;
switch (connector) {
case CONNECTOR_PROPRIETARY_LEGACY:
@@ -1774,8 +1784,25 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
DRM_MODE_CONNECTOR_DVII,
&ddc_i2c);
} else {
- DRM_DEBUG("No connector info found\n");
- return false;
+ uint16_t crt_info =
+ combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE);
+ DRM_DEBUG("Found CRT table, assuming VGA connector\n");
+ if (crt_info) {
+ radeon_add_legacy_encoder(dev,
+ radeon_get_encoder_id(dev,
+ ATOM_DEVICE_CRT1_SUPPORT,
+ 1),
+ ATOM_DEVICE_CRT1_SUPPORT);
+ ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
+ radeon_add_legacy_connector(dev,
+ 0,
+ ATOM_DEVICE_CRT1_SUPPORT,
+ DRM_MODE_CONNECTOR_VGA,
+ &ddc_i2c);
+ } else {
+ DRM_DEBUG("No connector info found\n");
+ return false;
+ }
}
}
@@ -1880,16 +1907,18 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE);
if (tv_info) {
if (RBIOS8(tv_info + 6) == 'T') {
- radeon_add_legacy_encoder(dev,
- radeon_get_encoder_id
- (dev,
- ATOM_DEVICE_TV1_SUPPORT,
- 2),
- ATOM_DEVICE_TV1_SUPPORT);
- radeon_add_legacy_connector(dev, 6,
- ATOM_DEVICE_TV1_SUPPORT,
- DRM_MODE_CONNECTOR_SVIDEO,
- &ddc_i2c);
+ if (radeon_apply_legacy_tv_quirks(dev)) {
+ radeon_add_legacy_encoder(dev,
+ radeon_get_encoder_id
+ (dev,
+ ATOM_DEVICE_TV1_SUPPORT,
+ 2),
+ ATOM_DEVICE_TV1_SUPPORT);
+ radeon_add_legacy_connector(dev, 6,
+ ATOM_DEVICE_TV1_SUPPORT,
+ DRM_MODE_CONNECTOR_SVIDEO,
+ &ddc_i2c);
+ }
}
}
}
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index e376be47a4a0..ce3a785a633b 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -178,25 +178,12 @@ static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encode
struct drm_device *dev = encoder->dev;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct drm_display_mode *mode = NULL;
- struct radeon_native_mode *native_mode = &radeon_encoder->native_mode;
-
- if (native_mode->panel_xres != 0 &&
- native_mode->panel_yres != 0 &&
- native_mode->dotclock != 0) {
- mode = drm_mode_create(dev);
-
- mode->hdisplay = native_mode->panel_xres;
- mode->vdisplay = native_mode->panel_yres;
-
- mode->htotal = mode->hdisplay + native_mode->hblank;
- mode->hsync_start = mode->hdisplay + native_mode->hoverplus;
- mode->hsync_end = mode->hsync_start + native_mode->hsync_width;
- mode->vtotal = mode->vdisplay + native_mode->vblank;
- mode->vsync_start = mode->vdisplay + native_mode->voverplus;
- mode->vsync_end = mode->vsync_start + native_mode->vsync_width;
- mode->clock = native_mode->dotclock;
- mode->flags = 0;
+ struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
+ if (native_mode->hdisplay != 0 &&
+ native_mode->vdisplay != 0 &&
+ native_mode->clock != 0) {
+ mode = drm_mode_duplicate(dev, native_mode);
mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
drm_mode_set_name(mode);
@@ -210,7 +197,7 @@ static void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_conn
struct drm_device *dev = encoder->dev;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct drm_display_mode *mode = NULL;
- struct radeon_native_mode *native_mode = &radeon_encoder->native_mode;
+ struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
int i;
struct mode_size {
int w;
@@ -236,11 +223,16 @@ static void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_conn
};
for (i = 0; i < 17; i++) {
+ if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) {
+ if (common_modes[i].w > 1024 ||
+ common_modes[i].h > 768)
+ continue;
+ }
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
- if (common_modes[i].w > native_mode->panel_xres ||
- common_modes[i].h > native_mode->panel_yres ||
- (common_modes[i].w == native_mode->panel_xres &&
- common_modes[i].h == native_mode->panel_yres))
+ if (common_modes[i].w > native_mode->hdisplay ||
+ common_modes[i].h > native_mode->vdisplay ||
+ (common_modes[i].w == native_mode->hdisplay &&
+ common_modes[i].h == native_mode->vdisplay))
continue;
}
if (common_modes[i].w < 320 || common_modes[i].h < 200)
@@ -344,28 +336,23 @@ static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder,
struct drm_connector *connector)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- struct radeon_native_mode *native_mode = &radeon_encoder->native_mode;
+ struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
/* Try to get native mode details from EDID if necessary */
- if (!native_mode->dotclock) {
+ if (!native_mode->clock) {
struct drm_display_mode *t, *mode;
list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
- if (mode->hdisplay == native_mode->panel_xres &&
- mode->vdisplay == native_mode->panel_yres) {
- native_mode->hblank = mode->htotal - mode->hdisplay;
- native_mode->hoverplus = mode->hsync_start - mode->hdisplay;
- native_mode->hsync_width = mode->hsync_end - mode->hsync_start;
- native_mode->vblank = mode->vtotal - mode->vdisplay;
- native_mode->voverplus = mode->vsync_start - mode->vdisplay;
- native_mode->vsync_width = mode->vsync_end - mode->vsync_start;
- native_mode->dotclock = mode->clock;
+ if (mode->hdisplay == native_mode->hdisplay &&
+ mode->vdisplay == native_mode->vdisplay) {
+ *native_mode = *mode;
+ drm_mode_set_crtcinfo(native_mode, CRTC_INTERLACE_HALVE_V);
DRM_INFO("Determined LVDS native mode details from EDID\n");
break;
}
}
}
- if (!native_mode->dotclock) {
+ if (!native_mode->clock) {
DRM_INFO("No LVDS native mode details, disabling RMX\n");
radeon_encoder->rmx_type = RMX_OFF;
}
@@ -415,8 +402,35 @@ static int radeon_lvds_mode_valid(struct drm_connector *connector,
static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connector)
{
- enum drm_connector_status ret = connector_status_connected;
+ struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+ struct drm_encoder *encoder = radeon_best_single_encoder(connector);
+ enum drm_connector_status ret = connector_status_disconnected;
+
+ if (encoder) {
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
+
+ /* check if panel is valid */
+ if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
+ ret = connector_status_connected;
+
+ }
+
+ /* check for edid as well */
+ if (radeon_connector->edid)
+ ret = connector_status_connected;
+ else {
+ if (radeon_connector->ddc_bus) {
+ radeon_i2c_do_lock(radeon_connector, 1);
+ radeon_connector->edid = drm_get_edid(&radeon_connector->base,
+ &radeon_connector->ddc_bus->adapter);
+ radeon_i2c_do_lock(radeon_connector, 0);
+ if (radeon_connector->edid)
+ ret = connector_status_connected;
+ }
+ }
/* check acpi lid status ??? */
+
radeon_connector_update_scratch_regs(connector, ret);
return ret;
}
@@ -427,6 +441,8 @@ static void radeon_connector_destroy(struct drm_connector *connector)
if (radeon_connector->ddc_bus)
radeon_i2c_destroy(radeon_connector->ddc_bus);
+ if (radeon_connector->edid)
+ kfree(radeon_connector->edid);
kfree(radeon_connector->con_priv);
drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector);
@@ -514,9 +530,32 @@ static enum drm_connector_status radeon_vga_detect(struct drm_connector *connect
radeon_i2c_do_lock(radeon_connector, 1);
dret = radeon_ddc_probe(radeon_connector);
radeon_i2c_do_lock(radeon_connector, 0);
- if (dret)
- ret = connector_status_connected;
- else {
+ if (dret) {
+ if (radeon_connector->edid) {
+ kfree(radeon_connector->edid);
+ radeon_connector->edid = NULL;
+ }
+ radeon_i2c_do_lock(radeon_connector, 1);
+ radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
+ radeon_i2c_do_lock(radeon_connector, 0);
+
+ if (!radeon_connector->edid) {
+ DRM_ERROR("DDC responded but not EDID found for %s\n",
+ drm_get_connector_name(connector));
+ } else {
+ radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
+
+ /* some oems have boards with separate digital and analog connectors
+ * with a shared ddc line (often vga + hdmi)
+ */
+ if (radeon_connector->use_digital && radeon_connector->shared_ddc) {
+ kfree(radeon_connector->edid);
+ radeon_connector->edid = NULL;
+ ret = connector_status_disconnected;
+ } else
+ ret = connector_status_connected;
+ }
+ } else {
if (radeon_connector->dac_load_detect) {
encoder_funcs = encoder->helper_private;
ret = encoder_funcs->detect(encoder, connector);
@@ -644,6 +683,10 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect
dret = radeon_ddc_probe(radeon_connector);
radeon_i2c_do_lock(radeon_connector, 0);
if (dret) {
+ if (radeon_connector->edid) {
+ kfree(radeon_connector->edid);
+ radeon_connector->edid = NULL;
+ }
radeon_i2c_do_lock(radeon_connector, 1);
radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
radeon_i2c_do_lock(radeon_connector, 0);
@@ -654,10 +697,15 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect
} else {
radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
- /* if this isn't a digital monitor
- then we need to make sure we don't have any
- TV conflicts */
- ret = connector_status_connected;
+ /* some oems have boards with separate digital and analog connectors
+ * with a shared ddc line (often vga + hdmi)
+ */
+ if ((!radeon_connector->use_digital) && radeon_connector->shared_ddc) {
+ kfree(radeon_connector->edid);
+ radeon_connector->edid = NULL;
+ ret = connector_status_disconnected;
+ } else
+ ret = connector_status_connected;
}
}
@@ -782,6 +830,7 @@ radeon_add_atom_connector(struct drm_device *dev,
struct radeon_connector *radeon_connector;
struct radeon_connector_atom_dig *radeon_dig_connector;
uint32_t subpixel_order = SubPixelNone;
+ bool shared_ddc = false;
int ret;
/* fixme - tv/cv/din */
@@ -795,6 +844,13 @@ radeon_add_atom_connector(struct drm_device *dev,
radeon_connector->devices |= supported_device;
return;
}
+ if (radeon_connector->ddc_bus && i2c_bus->valid) {
+ if (memcmp(&radeon_connector->ddc_bus->rec, i2c_bus,
+ sizeof(struct radeon_i2c_bus_rec)) == 0) {
+ radeon_connector->shared_ddc = true;
+ shared_ddc = true;
+ }
+ }
}
radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL);
@@ -805,6 +861,7 @@ radeon_add_atom_connector(struct drm_device *dev,
radeon_connector->connector_id = connector_id;
radeon_connector->devices = supported_device;
+ radeon_connector->shared_ddc = shared_ddc;
switch (connector_type) {
case DRM_MODE_CONNECTOR_VGA:
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c
index 4f7afc79dd82..0b2f9c2ad2c1 100644
--- a/drivers/gpu/drm/radeon/radeon_cp.c
+++ b/drivers/gpu/drm/radeon/radeon_cp.c
@@ -1941,8 +1941,8 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev)
for (t = 0; t < dev_priv->usec_timeout; t++) {
u32 done_age = GET_SCRATCH(dev_priv, 1);
DRM_DEBUG("done_age = %d\n", done_age);
- for (i = start; i < dma->buf_count; i++) {
- buf = dma->buflist[i];
+ for (i = 0; i < dma->buf_count; i++) {
+ buf = dma->buflist[start];
buf_priv = buf->dev_private;
if (buf->file_priv == NULL || (buf->pending &&
buf_priv->age <=
@@ -1951,7 +1951,8 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev)
buf->pending = 0;
return buf;
}
- start = 0;
+ if (++start >= dma->buf_count)
+ start = 0;
}
if (t) {
@@ -1960,47 +1961,9 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev)
}
}
- DRM_DEBUG("returning NULL!\n");
return NULL;
}
-#if 0
-struct drm_buf *radeon_freelist_get(struct drm_device * dev)
-{
- struct drm_device_dma *dma = dev->dma;
- drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_buf_priv_t *buf_priv;
- struct drm_buf *buf;
- int i, t;
- int start;
- u32 done_age;
-
- done_age = radeon_read_ring_rptr(dev_priv, RADEON_SCRATCHOFF(1));
- if (++dev_priv->last_buf >= dma->buf_count)
- dev_priv->last_buf = 0;
-
- start = dev_priv->last_buf;
- dev_priv->stats.freelist_loops++;
-
- for (t = 0; t < 2; t++) {
- for (i = start; i < dma->buf_count; i++) {
- buf = dma->buflist[i];
- buf_priv = buf->dev_private;
- if (buf->file_priv == 0 || (buf->pending &&
- buf_priv->age <=
- done_age)) {
- dev_priv->stats.requested_bufs++;
- buf->pending = 0;
- return buf;
- }
- }
- start = 0;
- }
-
- return NULL;
-}
-#endif
-
void radeon_freelist_reset(struct drm_device * dev)
{
struct drm_device_dma *dma = dev->dma;
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c
index b13c79e38bc0..28772a37009c 100644
--- a/drivers/gpu/drm/radeon/radeon_cursor.c
+++ b/drivers/gpu/drm/radeon/radeon_cursor.c
@@ -109,9 +109,15 @@ static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj,
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct radeon_device *rdev = crtc->dev->dev_private;
- if (ASIC_IS_AVIVO(rdev))
+ if (ASIC_IS_AVIVO(rdev)) {
+ if (rdev->family >= CHIP_RV770) {
+ if (radeon_crtc->crtc_id)
+ WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, 0);
+ else
+ WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, 0);
+ }
WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, gpu_addr);
- else {
+ } else {
radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr;
/* offset is from DISP(2)_BASE_ADDRESS */
WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, radeon_crtc->legacy_cursor_offset);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 3655d91993a6..c85df4afcb7a 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -137,9 +137,6 @@ static void radeon_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
if (size != 256) {
return;
}
- if (crtc->fb == NULL) {
- return;
- }
/* userspace palettes are always correct as is */
for (i = 0; i < 256; i++) {
@@ -147,7 +144,6 @@ static void radeon_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
radeon_crtc->lut_g[i] = green[i] >> 6;
radeon_crtc->lut_b[i] = blue[i] >> 6;
}
-
radeon_crtc_load_lut(crtc);
}
@@ -338,27 +334,19 @@ static bool radeon_setup_enc_conn(struct drm_device *dev)
int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
{
- struct edid *edid;
int ret = 0;
if (!radeon_connector->ddc_bus)
return -1;
if (!radeon_connector->edid) {
radeon_i2c_do_lock(radeon_connector, 1);
- edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
+ radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
radeon_i2c_do_lock(radeon_connector, 0);
- } else
- edid = radeon_connector->edid;
+ }
- if (edid) {
- /* update digital bits here */
- if (edid->input & DRM_EDID_INPUT_DIGITAL)
- radeon_connector->use_digital = 1;
- else
- radeon_connector->use_digital = 0;
- drm_mode_connector_update_edid_property(&radeon_connector->base, edid);
- ret = drm_add_edid_modes(&radeon_connector->base, edid);
- kfree(edid);
+ if (radeon_connector->edid) {
+ drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid);
+ ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid);
return ret;
}
drm_mode_connector_update_edid_property(&radeon_connector->base, NULL);
@@ -765,7 +753,7 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
radeon_crtc->rmx_type = radeon_encoder->rmx_type;
memcpy(&radeon_crtc->native_mode,
&radeon_encoder->native_mode,
- sizeof(struct radeon_native_mode));
+ sizeof(struct drm_display_mode));
first = false;
} else {
if (radeon_crtc->rmx_type != radeon_encoder->rmx_type) {
@@ -783,10 +771,10 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
if (radeon_crtc->rmx_type != RMX_OFF) {
fixed20_12 a, b;
a.full = rfixed_const(crtc->mode.vdisplay);
- b.full = rfixed_const(radeon_crtc->native_mode.panel_xres);
+ b.full = rfixed_const(radeon_crtc->native_mode.hdisplay);
radeon_crtc->vsc.full = rfixed_div(a, b);
a.full = rfixed_const(crtc->mode.hdisplay);
- b.full = rfixed_const(radeon_crtc->native_mode.panel_yres);
+ b.full = rfixed_const(radeon_crtc->native_mode.vdisplay);
radeon_crtc->hsc.full = rfixed_div(a, b);
} else {
radeon_crtc->vsc.full = rfixed_const(1);
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c
index a65ab1a0dad2..2aa5994a29d5 100644
--- a/drivers/gpu/drm/radeon/radeon_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_encoders.c
@@ -31,6 +31,10 @@
extern int atom_debug;
+/* evil but including atombios.h is much worse */
+bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
+ struct drm_display_mode *mode);
+
uint32_t
radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, uint8_t dac)
{
@@ -167,49 +171,17 @@ void radeon_rmx_mode_fixup(struct drm_encoder *encoder,
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
- struct radeon_native_mode *native_mode = &radeon_encoder->native_mode;
-
- if (mode->hdisplay < native_mode->panel_xres ||
- mode->vdisplay < native_mode->panel_yres) {
- if (ASIC_IS_AVIVO(rdev)) {
- adjusted_mode->hdisplay = native_mode->panel_xres;
- adjusted_mode->vdisplay = native_mode->panel_yres;
- adjusted_mode->htotal = native_mode->panel_xres + native_mode->hblank;
- adjusted_mode->hsync_start = native_mode->panel_xres + native_mode->hoverplus;
- adjusted_mode->hsync_end = adjusted_mode->hsync_start + native_mode->hsync_width;
- adjusted_mode->vtotal = native_mode->panel_yres + native_mode->vblank;
- adjusted_mode->vsync_start = native_mode->panel_yres + native_mode->voverplus;
- adjusted_mode->vsync_end = adjusted_mode->vsync_start + native_mode->vsync_width;
- /* update crtc values */
- drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
- /* adjust crtc values */
- adjusted_mode->crtc_hdisplay = native_mode->panel_xres;
- adjusted_mode->crtc_vdisplay = native_mode->panel_yres;
- adjusted_mode->crtc_htotal = adjusted_mode->crtc_hdisplay + native_mode->hblank;
- adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hdisplay + native_mode->hoverplus;
- adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + native_mode->hsync_width;
- adjusted_mode->crtc_vtotal = adjusted_mode->crtc_vdisplay + native_mode->vblank;
- adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + native_mode->voverplus;
- adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + native_mode->vsync_width;
- } else {
- adjusted_mode->htotal = native_mode->panel_xres + native_mode->hblank;
- adjusted_mode->hsync_start = native_mode->panel_xres + native_mode->hoverplus;
- adjusted_mode->hsync_end = adjusted_mode->hsync_start + native_mode->hsync_width;
- adjusted_mode->vtotal = native_mode->panel_yres + native_mode->vblank;
- adjusted_mode->vsync_start = native_mode->panel_yres + native_mode->voverplus;
- adjusted_mode->vsync_end = adjusted_mode->vsync_start + native_mode->vsync_width;
- /* update crtc values */
- drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
- /* adjust crtc values */
- adjusted_mode->crtc_htotal = adjusted_mode->crtc_hdisplay + native_mode->hblank;
- adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hdisplay + native_mode->hoverplus;
- adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + native_mode->hsync_width;
- adjusted_mode->crtc_vtotal = adjusted_mode->crtc_vdisplay + native_mode->vblank;
- adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + native_mode->voverplus;
- adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + native_mode->vsync_width;
+ struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
+
+ if (mode->hdisplay < native_mode->hdisplay ||
+ mode->vdisplay < native_mode->vdisplay) {
+ int mode_id = adjusted_mode->base.id;
+ *adjusted_mode = *native_mode;
+ if (!ASIC_IS_AVIVO(rdev)) {
+ adjusted_mode->hdisplay = mode->hdisplay;
+ adjusted_mode->vdisplay = mode->vdisplay;
}
- adjusted_mode->flags = native_mode->flags;
- adjusted_mode->clock = native_mode->dotclock;
+ adjusted_mode->base.id = mode_id;
}
}
@@ -219,7 +191,11 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *adjusted_mode)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ /* set the active encoder to connector routing */
+ radeon_encoder_set_active_device(encoder);
drm_mode_set_crtcinfo(adjusted_mode, 0);
if (radeon_encoder->rmx_type != RMX_OFF)
@@ -230,6 +206,18 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder,
&& (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2)))
adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2;
+ if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
+ struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv;
+ if (tv_dac) {
+ if (tv_dac->tv_std == TV_STD_NTSC ||
+ tv_dac->tv_std == TV_STD_NTSC_J ||
+ tv_dac->tv_std == TV_STD_PAL_M)
+ radeon_atom_get_tv_timings(rdev, 0, adjusted_mode);
+ else
+ radeon_atom_get_tv_timings(rdev, 1, adjusted_mode);
+ }
+ }
+
return true;
}
@@ -461,7 +449,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
case 1:
args.v1.ucMisc = 0;
args.v1.ucAction = action;
- if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr))
+ if (drm_detect_hdmi_monitor(radeon_connector->edid))
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)) {
@@ -486,7 +474,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
if (dig->coherent_mode)
args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT;
}
- if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr))
+ if (drm_detect_hdmi_monitor(radeon_connector->edid))
args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
args.v2.ucTruncate = 0;
@@ -544,7 +532,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
switch (connector->connector_type) {
case DRM_MODE_CONNECTOR_DVII:
case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */
- if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr))
+ if (drm_detect_hdmi_monitor(radeon_connector->edid))
return ATOM_ENCODER_MODE_HDMI;
else if (radeon_connector->use_digital)
return ATOM_ENCODER_MODE_DVI;
@@ -554,7 +542,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
case DRM_MODE_CONNECTOR_DVID:
case DRM_MODE_CONNECTOR_HDMIA:
default:
- if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr))
+ if (drm_detect_hdmi_monitor(radeon_connector->edid))
return ATOM_ENCODER_MODE_HDMI;
else
return ATOM_ENCODER_MODE_DVI;
@@ -566,7 +554,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
/*if (radeon_output->MonType == MT_DP)
return ATOM_ENCODER_MODE_DP;
else*/
- if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr))
+ if (drm_detect_hdmi_monitor(radeon_connector->edid))
return ATOM_ENCODER_MODE_HDMI;
else
return ATOM_ENCODER_MODE_DVI;
@@ -874,16 +862,9 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args;
int index = 0;
bool is_dig = false;
- int devices;
memset(&args, 0, sizeof(args));
- /* on DPMS off we have no idea if active device is meaningful */
- if (mode != DRM_MODE_DPMS_ON && !radeon_encoder->active_device)
- devices = radeon_encoder->devices;
- else
- devices = radeon_encoder->active_device;
-
DRM_DEBUG("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n",
radeon_encoder->encoder_id, mode, radeon_encoder->devices,
radeon_encoder->active_device);
@@ -914,18 +895,18 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
break;
case ENCODER_OBJECT_ID_INTERNAL_DAC1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
- if (devices & (ATOM_DEVICE_TV_SUPPORT))
+ if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
- else if (devices & (ATOM_DEVICE_CV_SUPPORT))
+ else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
else
index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
break;
case ENCODER_OBJECT_ID_INTERNAL_DAC2:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
- if (devices & (ATOM_DEVICE_TV_SUPPORT))
+ if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
- else if (devices & (ATOM_DEVICE_CV_SUPPORT))
+ else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
else
index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl);
@@ -1104,8 +1085,11 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder,
}
/* set scaler clears this on some chips */
- if (ASIC_IS_AVIVO(rdev) && (mode->flags & DRM_MODE_FLAG_INTERLACE))
- WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, AVIVO_D1MODE_INTERLEAVE_EN);
+ if (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))) {
+ if (ASIC_IS_AVIVO(rdev) && (mode->flags & DRM_MODE_FLAG_INTERLACE))
+ WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset,
+ AVIVO_D1MODE_INTERLEAVE_EN);
+ }
}
static void
@@ -1268,8 +1252,6 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
{
radeon_atom_output_lock(encoder, true);
radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
-
- radeon_encoder_set_active_device(encoder);
}
static void radeon_atom_encoder_commit(struct drm_encoder *encoder)
diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c
index a931af065dd4..a68d7566178c 100644
--- a/drivers/gpu/drm/radeon/radeon_gart.c
+++ b/drivers/gpu/drm/radeon/radeon_gart.c
@@ -140,15 +140,15 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
WARN(1, "trying to unbind memory to unitialized GART !\n");
return;
}
- t = offset / 4096;
- p = t / (PAGE_SIZE / 4096);
+ t = offset / RADEON_GPU_PAGE_SIZE;
+ p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
for (i = 0; i < pages; i++, p++) {
if (rdev->gart.pages[p]) {
pci_unmap_page(rdev->pdev, rdev->gart.pages_addr[p],
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
rdev->gart.pages[p] = NULL;
rdev->gart.pages_addr[p] = 0;
- for (j = 0; j < (PAGE_SIZE / 4096); j++, t++) {
+ for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
radeon_gart_set_page(rdev, t, 0);
}
}
@@ -169,8 +169,8 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
DRM_ERROR("trying to bind memory to unitialized GART !\n");
return -EINVAL;
}
- t = offset / 4096;
- p = t / (PAGE_SIZE / 4096);
+ t = offset / RADEON_GPU_PAGE_SIZE;
+ p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
for (i = 0; i < pages; i++, p++) {
/* we need to support large memory configurations */
@@ -185,9 +185,9 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
}
rdev->gart.pages[p] = pagelist[i];
page_base = rdev->gart.pages_addr[p];
- for (j = 0; j < (PAGE_SIZE / 4096); j++, t++) {
+ for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
radeon_gart_set_page(rdev, t, page_base);
- page_base += 4096;
+ page_base += RADEON_GPU_PAGE_SIZE;
}
}
mb();
@@ -200,14 +200,14 @@ int radeon_gart_init(struct radeon_device *rdev)
if (rdev->gart.pages) {
return 0;
}
- /* We need PAGE_SIZE >= 4096 */
- if (PAGE_SIZE < 4096) {
+ /* We need PAGE_SIZE >= RADEON_GPU_PAGE_SIZE */
+ if (PAGE_SIZE < RADEON_GPU_PAGE_SIZE) {
DRM_ERROR("Page size is smaller than GPU page size!\n");
return -EINVAL;
}
/* Compute table size */
rdev->gart.num_cpu_pages = rdev->mc.gtt_size / PAGE_SIZE;
- rdev->gart.num_gpu_pages = rdev->mc.gtt_size / 4096;
+ rdev->gart.num_gpu_pages = rdev->mc.gtt_size / RADEON_GPU_PAGE_SIZE;
DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n",
rdev->gart.num_cpu_pages, rdev->gart.num_gpu_pages);
/* Allocate pages table */
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index 8e0a8759e428..a0fe6232dcb6 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -92,6 +92,13 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
if (r) {
return r;
}
+ /* enable msi */
+ rdev->msi_enabled = 0;
+ if (rdev->family >= CHIP_RV380) {
+ int ret = pci_enable_msi(rdev->pdev);
+ if (!ret)
+ rdev->msi_enabled = 1;
+ }
drm_irq_install(rdev->ddev);
rdev->irq.installed = true;
DRM_INFO("radeon: irq initialized.\n");
@@ -103,5 +110,7 @@ void radeon_irq_kms_fini(struct radeon_device *rdev)
if (rdev->irq.installed) {
rdev->irq.installed = false;
drm_irq_uninstall(rdev->ddev);
+ if (rdev->msi_enabled)
+ pci_disable_msi(rdev->pdev);
}
}
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
index 36410f85d705..8d0b7aa87fa4 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
@@ -48,7 +48,7 @@ static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc,
u32 fp_horz_stretch, fp_vert_stretch, fp_horz_vert_active;
u32 fp_h_sync_strt_wid, fp_crtc_h_total_disp;
u32 fp_v_sync_strt_wid, fp_crtc_v_total_disp;
- struct radeon_native_mode *native_mode = &radeon_crtc->native_mode;
+ struct drm_display_mode *native_mode = &radeon_crtc->native_mode;
fp_vert_stretch = RREG32(RADEON_FP_VERT_STRETCH) &
(RADEON_VERT_STRETCH_RESERVED |
@@ -95,19 +95,19 @@ static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc,
fp_horz_vert_active = 0;
- if (native_mode->panel_xres == 0 ||
- native_mode->panel_yres == 0) {
+ if (native_mode->hdisplay == 0 ||
+ native_mode->vdisplay == 0) {
hscale = false;
vscale = false;
} else {
- if (xres > native_mode->panel_xres)
- xres = native_mode->panel_xres;
- if (yres > native_mode->panel_yres)
- yres = native_mode->panel_yres;
+ if (xres > native_mode->hdisplay)
+ xres = native_mode->hdisplay;
+ if (yres > native_mode->vdisplay)
+ yres = native_mode->vdisplay;
- if (xres == native_mode->panel_xres)
+ if (xres == native_mode->hdisplay)
hscale = false;
- if (yres == native_mode->panel_yres)
+ if (yres == native_mode->vdisplay)
vscale = false;
}
@@ -119,11 +119,11 @@ static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc,
else {
inc = (fp_horz_stretch & RADEON_HORZ_AUTO_RATIO_INC) ? 1 : 0;
scale = ((xres + inc) * RADEON_HORZ_STRETCH_RATIO_MAX)
- / native_mode->panel_xres + 1;
+ / native_mode->hdisplay + 1;
fp_horz_stretch |= (((scale) & RADEON_HORZ_STRETCH_RATIO_MASK) |
RADEON_HORZ_STRETCH_BLEND |
RADEON_HORZ_STRETCH_ENABLE |
- ((native_mode->panel_xres/8-1) << 16));
+ ((native_mode->hdisplay/8-1) << 16));
}
if (!vscale)
@@ -131,11 +131,11 @@ static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc,
else {
inc = (fp_vert_stretch & RADEON_VERT_AUTO_RATIO_INC) ? 1 : 0;
scale = ((yres + inc) * RADEON_VERT_STRETCH_RATIO_MAX)
- / native_mode->panel_yres + 1;
+ / native_mode->vdisplay + 1;
fp_vert_stretch |= (((scale) & RADEON_VERT_STRETCH_RATIO_MASK) |
RADEON_VERT_STRETCH_ENABLE |
RADEON_VERT_STRETCH_BLEND |
- ((native_mode->panel_yres-1) << 12));
+ ((native_mode->vdisplay-1) << 12));
}
break;
case RMX_CENTER:
@@ -175,8 +175,8 @@ static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc,
? RADEON_CRTC_V_SYNC_POL
: 0)));
- fp_horz_vert_active = (((native_mode->panel_yres) & 0xfff) |
- (((native_mode->panel_xres / 8) & 0x1ff) << 16));
+ fp_horz_vert_active = (((native_mode->vdisplay) & 0xfff) |
+ (((native_mode->hdisplay / 8) & 0x1ff) << 16));
break;
case RMX_OFF:
default:
@@ -532,6 +532,10 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
radeon_fb = to_radeon_framebuffer(old_fb);
radeon_gem_object_unpin(radeon_fb->obj);
}
+
+ /* Bytes per pixel may have changed */
+ radeon_bandwidth_update(rdev);
+
return 0;
}
@@ -664,6 +668,9 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod
WREG32(RADEON_DISP2_MERGE_CNTL, disp2_merge_cntl);
WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
+
+ WREG32(RADEON_FP_H2_SYNC_STRT_WID, crtc_h_sync_strt_wid);
+ WREG32(RADEON_FP_V2_SYNC_STRT_WID, crtc_v_sync_strt_wid);
} else {
uint32_t crtc_gen_cntl;
uint32_t crtc_ext_cntl;
@@ -1015,14 +1022,11 @@ static int radeon_crtc_mode_set(struct drm_crtc *crtc,
int x, int y, struct drm_framebuffer *old_fb)
{
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
- struct drm_device *dev = crtc->dev;
- struct radeon_device *rdev = dev->dev_private;
/* TODO TV */
radeon_crtc_set_base(crtc, x, y, old_fb);
radeon_set_crtc_timing(crtc, adjusted_mode);
radeon_set_pll(crtc, adjusted_mode);
- radeon_bandwidth_update(rdev);
if (radeon_crtc->crtc_id == 0) {
radeon_legacy_rmx_mode_set(crtc, mode, adjusted_mode);
} else {
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
index 6ceb958fd194..00382122869b 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
@@ -107,8 +107,6 @@ static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder)
else
radeon_combios_output_lock(encoder, true);
radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_OFF);
-
- radeon_encoder_set_active_device(encoder);
}
static void radeon_legacy_lvds_commit(struct drm_encoder *encoder)
@@ -192,6 +190,8 @@ static bool radeon_legacy_lvds_mode_fixup(struct drm_encoder *encoder,
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ /* set the active encoder to connector routing */
+ radeon_encoder_set_active_device(encoder);
drm_mode_set_crtcinfo(adjusted_mode, 0);
if (radeon_encoder->rmx_type != RMX_OFF)
@@ -218,7 +218,8 @@ static bool radeon_legacy_primary_dac_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
-
+ /* set the active encoder to connector routing */
+ radeon_encoder_set_active_device(encoder);
drm_mode_set_crtcinfo(adjusted_mode, 0);
return true;
@@ -272,7 +273,6 @@ static void radeon_legacy_primary_dac_prepare(struct drm_encoder *encoder)
else
radeon_combios_output_lock(encoder, true);
radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_OFF);
- radeon_encoder_set_active_device(encoder);
}
static void radeon_legacy_primary_dac_commit(struct drm_encoder *encoder)
@@ -468,7 +468,6 @@ static void radeon_legacy_tmds_int_prepare(struct drm_encoder *encoder)
else
radeon_combios_output_lock(encoder, true);
radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_OFF);
- radeon_encoder_set_active_device(encoder);
}
static void radeon_legacy_tmds_int_commit(struct drm_encoder *encoder)
@@ -543,6 +542,14 @@ static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder,
fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN);
+ fp_gen_cntl &= ~(RADEON_FP_RMX_HVSYNC_CONTROL_EN |
+ RADEON_FP_DFP_SYNC_SEL |
+ RADEON_FP_CRT_SYNC_SEL |
+ RADEON_FP_CRTC_LOCK_8DOT |
+ RADEON_FP_USE_SHADOW_EN |
+ RADEON_FP_CRTC_USE_SHADOW_VEND |
+ RADEON_FP_CRT_SYNC_ALT);
+
if (1) /* FIXME rgbBits == 8 */
fp_gen_cntl |= RADEON_FP_PANEL_FORMAT; /* 24 bit format */
else
@@ -556,7 +563,7 @@ static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder,
else
fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1;
} else
- fp_gen_cntl |= RADEON_FP_SEL_CRTC1;
+ fp_gen_cntl &= ~RADEON_FP_SEL_CRTC2;
} else {
if (ASIC_IS_R300(rdev) || rdev->family == CHIP_R200) {
fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK;
@@ -593,7 +600,8 @@ static bool radeon_legacy_tmds_ext_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
-
+ /* set the active encoder to connector routing */
+ radeon_encoder_set_active_device(encoder);
drm_mode_set_crtcinfo(adjusted_mode, 0);
return true;
@@ -636,7 +644,6 @@ static void radeon_legacy_tmds_ext_prepare(struct drm_encoder *encoder)
else
radeon_combios_output_lock(encoder, true);
radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_OFF);
- radeon_encoder_set_active_device(encoder);
}
static void radeon_legacy_tmds_ext_commit(struct drm_encoder *encoder)
@@ -735,7 +742,8 @@ static bool radeon_legacy_tv_dac_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
-
+ /* set the active encoder to connector routing */
+ radeon_encoder_set_active_device(encoder);
drm_mode_set_crtcinfo(adjusted_mode, 0);
return true;
@@ -839,7 +847,6 @@ static void radeon_legacy_tv_dac_prepare(struct drm_encoder *encoder)
else
radeon_combios_output_lock(encoder, true);
radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_OFF);
- radeon_encoder_set_active_device(encoder);
}
static void radeon_legacy_tv_dac_commit(struct drm_encoder *encoder)
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index e61226817ccf..2ea5707c018c 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -186,17 +186,6 @@ struct radeon_mode_info {
};
-struct radeon_native_mode {
- /* preferred mode */
- uint32_t panel_xres, panel_yres;
- uint32_t hoverplus, hsync_width;
- uint32_t hblank;
- uint32_t voverplus, vsync_width;
- uint32_t vblank;
- uint32_t dotclock;
- uint32_t flags;
-};
-
#define MAX_H_CODE_TIMING_LEN 32
#define MAX_V_CODE_TIMING_LEN 32
@@ -228,7 +217,7 @@ struct radeon_crtc {
enum radeon_rmx_type rmx_type;
fixed20_12 vsc;
fixed20_12 hsc;
- struct radeon_native_mode native_mode;
+ struct drm_display_mode native_mode;
};
struct radeon_encoder_primary_dac {
@@ -248,7 +237,7 @@ struct radeon_encoder_lvds {
bool use_bios_dividers;
uint32_t lvds_gen_cntl;
/* panel mode */
- struct radeon_native_mode native_mode;
+ struct drm_display_mode native_mode;
};
struct radeon_encoder_tv_dac {
@@ -271,6 +260,16 @@ struct radeon_encoder_int_tmds {
struct radeon_tmds_pll tmds_pll[4];
};
+/* spread spectrum */
+struct radeon_atom_ss {
+ uint16_t percentage;
+ uint8_t type;
+ uint8_t step;
+ uint8_t delay;
+ uint8_t range;
+ uint8_t refdiv;
+};
+
struct radeon_encoder_atom_dig {
/* atom dig */
bool coherent_mode;
@@ -278,8 +277,9 @@ struct radeon_encoder_atom_dig {
/* atom lvds */
uint32_t lvds_misc;
uint16_t panel_pwr_delay;
+ struct radeon_atom_ss *ss;
/* panel mode */
- struct radeon_native_mode native_mode;
+ struct drm_display_mode native_mode;
};
struct radeon_encoder_atom_dac {
@@ -294,7 +294,7 @@ struct radeon_encoder {
uint32_t flags;
uint32_t pixel_clock;
enum radeon_rmx_type rmx_type;
- struct radeon_native_mode native_mode;
+ struct drm_display_mode native_mode;
void *enc_priv;
};
@@ -308,6 +308,8 @@ struct radeon_connector {
uint32_t connector_id;
uint32_t devices;
struct radeon_i2c_chan *ddc_bus;
+ /* some systems have a an hdmi and vga port with a shared ddc line */
+ bool shared_ddc;
bool use_digital;
/* we need to mind the EDID between detect
and get modes due to analog/digital/tvencoder */
diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h
index bfa1ab9c93e1..29ab75903ec1 100644
--- a/drivers/gpu/drm/radeon/radeon_reg.h
+++ b/drivers/gpu/drm/radeon/radeon_reg.h
@@ -290,6 +290,8 @@
#define RADEON_BUS_CNTL 0x0030
# define RADEON_BUS_MASTER_DIS (1 << 6)
# define RADEON_BUS_BIOS_DIS_ROM (1 << 12)
+# define RS600_BUS_MASTER_DIS (1 << 14)
+# define RS600_MSI_REARM (1 << 20) /* rs600/rs690/rs740 */
# define RADEON_BUS_RD_DISCARD_EN (1 << 24)
# define RADEON_BUS_RD_ABORT_EN (1 << 25)
# define RADEON_BUS_MSTR_DISCONNECT_EN (1 << 28)
@@ -297,6 +299,9 @@
# define RADEON_BUS_READ_BURST (1 << 30)
#define RADEON_BUS_CNTL1 0x0034
# define RADEON_BUS_WAIT_ON_LOCK_EN (1 << 4)
+/* rv370/rv380, rv410, r423/r430/r480, r5xx */
+#define RADEON_MSI_REARM_EN 0x0160
+# define RV370_MSI_REARM_EN (1 << 0)
/* #define RADEON_PCIE_INDEX 0x0030 */
/* #define RADEON_PCIE_DATA 0x0034 */
@@ -3311,6 +3316,7 @@
#define RADEON_AIC_CNTL 0x01d0
# define RADEON_PCIGART_TRANSLATE_EN (1 << 0)
# define RADEON_DIS_OUT_OF_PCI_GART_ACCESS (1 << 1)
+# define RS400_MSI_REARM (1 << 3) /* rs400/rs480 */
#define RADEON_AIC_LO_ADDR 0x01dc
#define RADEON_AIC_PT_BASE 0x01d8
#define RADEON_AIC_HI_ADDR 0x01e0
diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c
index 03c33cf4e14c..f8a465d9a1cf 100644
--- a/drivers/gpu/drm/radeon/radeon_test.c
+++ b/drivers/gpu/drm/radeon/radeon_test.c
@@ -42,7 +42,7 @@ void radeon_test_moves(struct radeon_device *rdev)
/* Number of tests =
* (Total GTT - IB pool - writeback page - ring buffer) / test size
*/
- n = (rdev->mc.gtt_size - RADEON_IB_POOL_SIZE*64*1024 - 4096 -
+ n = (rdev->mc.gtt_size - RADEON_IB_POOL_SIZE*64*1024 - RADEON_GPU_PAGE_SIZE -
rdev->cp.ring_size) / size;
gtt_obj = kzalloc(n * sizeof(*gtt_obj), GFP_KERNEL);
@@ -102,7 +102,7 @@ void radeon_test_moves(struct radeon_device *rdev)
goto out_cleanup;
}
- r = radeon_copy(rdev, gtt_addr, vram_addr, size / 4096, fence);
+ r = radeon_copy(rdev, gtt_addr, vram_addr, size / RADEON_GPU_PAGE_SIZE, fence);
if (r) {
DRM_ERROR("Failed GTT->VRAM copy %d\n", i);
goto out_cleanup;
@@ -145,7 +145,7 @@ void radeon_test_moves(struct radeon_device *rdev)
goto out_cleanup;
}
- r = radeon_copy(rdev, vram_addr, gtt_addr, size / 4096, fence);
+ r = radeon_copy(rdev, vram_addr, gtt_addr, size / RADEON_GPU_PAGE_SIZE, fence);
if (r) {
DRM_ERROR("Failed VRAM->GTT copy %d\n", i);
goto out_cleanup;
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 10dfa78762da..942754c39be9 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -242,7 +242,7 @@ void rs600_irq_disable(struct radeon_device *rdev)
int rs600_irq_process(struct radeon_device *rdev)
{
- uint32_t status;
+ uint32_t status, msi_rearm;
uint32_t r500_disp_int;
status = rs600_irq_ack(rdev, &r500_disp_int);
@@ -260,6 +260,22 @@ int rs600_irq_process(struct radeon_device *rdev)
drm_handle_vblank(rdev->ddev, 1);
status = rs600_irq_ack(rdev, &r500_disp_int);
}
+ if (rdev->msi_enabled) {
+ switch (rdev->family) {
+ case CHIP_RS600:
+ case CHIP_RS690:
+ case CHIP_RS740:
+ msi_rearm = RREG32(RADEON_BUS_CNTL) & ~RS600_MSI_REARM;
+ WREG32(RADEON_BUS_CNTL, msi_rearm);
+ WREG32(RADEON_BUS_CNTL, msi_rearm | RS600_MSI_REARM);
+ break;
+ default:
+ msi_rearm = RREG32(RADEON_MSI_REARM_EN) & ~RV370_MSI_REARM_EN;
+ WREG32(RADEON_MSI_REARM_EN, msi_rearm);
+ WREG32(RADEON_MSI_REARM_EN, msi_rearm | RV370_MSI_REARM_EN);
+ break;
+ }
+ }
return IRQ_HANDLED;
}
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 595ac638039d..40553913b928 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -774,14 +774,36 @@ int rv770_mc_init(struct radeon_device *rdev)
{
fixed20_12 a;
u32 tmp;
+ int chansize, numchan;
int r;
/* Get VRAM informations */
- /* FIXME: Don't know how to determine vram width, need to check
- * vram_width usage
- */
- rdev->mc.vram_width = 128;
rdev->mc.vram_is_ddr = true;
+ tmp = RREG32(MC_ARB_RAMCFG);
+ if (tmp & CHANSIZE_OVERRIDE) {
+ chansize = 16;
+ } else if (tmp & CHANSIZE_MASK) {
+ chansize = 64;
+ } else {
+ chansize = 32;
+ }
+ tmp = RREG32(MC_SHARED_CHMAP);
+ switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
+ case 0:
+ default:
+ numchan = 1;
+ break;
+ case 1:
+ numchan = 2;
+ break;
+ case 2:
+ numchan = 4;
+ break;
+ case 3:
+ numchan = 8;
+ break;
+ }
+ rdev->mc.vram_width = numchan * chansize;
/* Could aper size report 0 ? */
rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h
index 4b9c3d6396ff..a1367ab6f261 100644
--- a/drivers/gpu/drm/radeon/rv770d.h
+++ b/drivers/gpu/drm/radeon/rv770d.h
@@ -129,6 +129,10 @@
#define HDP_REG_COHERENCY_FLUSH_CNTL 0x54A0
#define HDP_TILING_CONFIG 0x2F3C
+#define MC_SHARED_CHMAP 0x2004
+#define NOOFCHAN_SHIFT 12
+#define NOOFCHAN_MASK 0x00003000
+
#define MC_ARB_RAMCFG 0x2760
#define NOOFBANK_SHIFT 0
#define NOOFBANK_MASK 0x00000003
@@ -142,6 +146,7 @@
#define CHANSIZE_MASK 0x00000100
#define BURSTLENGTH_SHIFT 9
#define BURSTLENGTH_MASK 0x00000200
+#define CHANSIZE_OVERRIDE (1 << 11)
#define MC_VM_AGP_TOP 0x2028
#define MC_VM_AGP_BOT 0x202C
#define MC_VM_AGP_BASE 0x2030
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 7d05c4bb201e..6d5c84573b3a 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -39,8 +39,6 @@
* Version Information
*/
-#define DRIVER_VERSION "v2.6"
-#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik, Jiri Kosina"
#define DRIVER_DESC "HID core driver"
#define DRIVER_LICENSE "GPL"
@@ -1620,6 +1618,7 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KWORLD, USB_DEVICE_ID_KWORLD_RADIO_FM700) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_KYE, 0x0058) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY) },
@@ -1918,5 +1917,8 @@ static void __exit hid_exit(void)
module_init(hid_init);
module_exit(hid_exit);
+MODULE_AUTHOR("Andreas Gal");
+MODULE_AUTHOR("Vojtech Pavlik");
+MODULE_AUTHOR("Jiri Kosina");
MODULE_LICENSE(DRIVER_LICENSE);
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index adbef5d069c4..1d99c81ad171 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -117,6 +117,7 @@
#define USB_DEVICE_ID_CH_PRO_PEDALS 0x00f2
#define USB_DEVICE_ID_CH_COMBATSTICK 0x00f4
#define USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE 0x00ff
+#define USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK 0x00d3
#define USB_VENDOR_ID_CHERRY 0x046a
#define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023
diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h
index 27ae750ca878..bf31592eaf79 100644
--- a/drivers/hid/hid-lg.h
+++ b/drivers/hid/hid-lg.h
@@ -1,8 +1,6 @@
#ifndef __HID_LG_H
#define __HID_LG_H
-#include <linux/autoconf.h>
-
#ifdef CONFIG_LOGITECH_FF
int lgff_init(struct hid_device *hdev);
#else
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 03bd703255a3..3f56e9c02e65 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -41,8 +41,6 @@
* Version Information
*/
-#define DRIVER_VERSION "v2.6"
-#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik, Jiri Kosina"
#define DRIVER_DESC "USB HID core driver"
#define DRIVER_LICENSE "GPL"
@@ -1395,8 +1393,7 @@ static int __init hid_init(void)
retval = usb_register(&hid_driver);
if (retval)
goto usb_register_fail;
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
return 0;
usb_register_fail:
@@ -1423,6 +1420,8 @@ static void __exit hid_exit(void)
module_init(hid_init);
module_exit(hid_exit);
-MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_AUTHOR("Andreas Gal");
+MODULE_AUTHOR("Vojtech Pavlik");
+MODULE_AUTHOR("Jiri Kosina");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 0d9045aa2c4b..2d445b270215 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -53,6 +53,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_COMBATSTICK, HID_QUIRK_NOGET },
{ 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_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 700e93adeb33..dd6939370f75 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -442,6 +442,15 @@ config SENSORS_LM70
This driver can also be built as a module. If so, the module
will be called lm70.
+config SENSORS_LM73
+ tristate "National Semiconductor LM73"
+ depends on I2C
+ help
+ If you say yes here you get support for National Semiconductor LM73
+ sensor chips.
+ This driver can also be built as a module. If so, the module
+ will be called lm73.
+
config SENSORS_LM75
tristate "National Semiconductor LM75 and compatibles"
depends on I2C
@@ -841,7 +850,7 @@ config SENSORS_W83781D
config SENSORS_W83791D
tristate "Winbond W83791D"
- depends on I2C && EXPERIMENTAL
+ depends on I2C
select HWMON_VID
help
If you say yes here you get support for the Winbond W83791D chip.
@@ -1008,6 +1017,12 @@ config SENSORS_APPLESMC
Say Y here if you have an applicable laptop and want to experience
the awesome power of applesmc.
+config SENSORS_MC13783_ADC
+ tristate "Freescale MC13783 ADC"
+ depends on MFD_MC13783
+ help
+ Support for the A/D converter on MC13783 PMIC.
+
if ACPI
comment "ACPI drivers"
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 9f46cb019cc6..33c2ee105284 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -57,6 +57,7 @@ obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o hp_accel.o
obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d.o lis3lv02d_spi.o
obj-$(CONFIG_SENSORS_LM63) += lm63.o
obj-$(CONFIG_SENSORS_LM70) += lm70.o
+obj-$(CONFIG_SENSORS_LM73) += lm73.o
obj-$(CONFIG_SENSORS_LM75) += lm75.o
obj-$(CONFIG_SENSORS_LM77) += lm77.o
obj-$(CONFIG_SENSORS_LM78) += lm78.o
@@ -73,6 +74,7 @@ obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o
obj-$(CONFIG_SENSORS_MAX1111) += max1111.o
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
+obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c
index afc594318125..33acf29531af 100644
--- a/drivers/hwmon/adm1021.c
+++ b/drivers/hwmon/adm1021.c
@@ -288,9 +288,8 @@ static int adm1021_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
- int i;
- const char *type_name = "";
- int conv_rate, status, config;
+ const char *type_name;
+ int conv_rate, status, config, man_id, dev_id;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
pr_debug("adm1021: detect failed, "
@@ -303,62 +302,37 @@ static int adm1021_detect(struct i2c_client *client, int kind,
ADM1021_REG_CONV_RATE_R);
config = i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R);
- /* Now, we do the remaining detection. */
- if (kind < 0) {
- if ((status & 0x03) != 0x00 || (config & 0x3F) != 0x00
- || (conv_rate & 0xF8) != 0x00) {
- pr_debug("adm1021: detect failed, "
- "chip not detected!\n");
- return -ENODEV;
- }
+ /* Check unused bits */
+ if ((status & 0x03) || (config & 0x3F) || (conv_rate & 0xF8)) {
+ pr_debug("adm1021: detect failed, chip not detected!\n");
+ return -ENODEV;
}
/* Determine the chip type. */
- if (kind <= 0) {
- i = i2c_smbus_read_byte_data(client, ADM1021_REG_MAN_ID);
- if (i == 0x41)
- if ((i2c_smbus_read_byte_data(client,
- ADM1021_REG_DEV_ID) & 0xF0) == 0x30)
- kind = adm1023;
- else
- kind = adm1021;
- else if (i == 0x49)
- kind = thmc10;
- else if (i == 0x23)
- kind = gl523sm;
- else if ((i == 0x4d) &&
- (i2c_smbus_read_byte_data(client,
- ADM1021_REG_DEV_ID) == 0x01))
- kind = max1617a;
- else if (i == 0x54)
- kind = mc1066;
- /* LM84 Mfr ID in a different place, and it has more unused bits */
- else if (conv_rate == 0x00
- && (kind == 0 /* skip extra detection */
- || ((config & 0x7F) == 0x00
- && (status & 0xAB) == 0x00)))
- kind = lm84;
- else
- kind = max1617;
- }
+ man_id = i2c_smbus_read_byte_data(client, ADM1021_REG_MAN_ID);
+ dev_id = i2c_smbus_read_byte_data(client, ADM1021_REG_DEV_ID);
- if (kind == max1617) {
- type_name = "max1617";
- } else if (kind == max1617a) {
+ if (man_id == 0x4d && dev_id == 0x01)
type_name = "max1617a";
- } else if (kind == adm1021) {
- type_name = "adm1021";
- } else if (kind == adm1023) {
- type_name = "adm1023";
- } else if (kind == thmc10) {
+ else if (man_id == 0x41) {
+ if ((dev_id & 0xF0) == 0x30)
+ type_name = "adm1023";
+ else
+ type_name = "adm1021";
+ } else if (man_id == 0x49)
type_name = "thmc10";
- } else if (kind == lm84) {
- type_name = "lm84";
- } else if (kind == gl523sm) {
+ else if (man_id == 0x23)
type_name = "gl523sm";
- } else if (kind == mc1066) {
+ else if (man_id == 0x54)
type_name = "mc1066";
- }
+ /* LM84 Mfr ID in a different place, and it has more unused bits */
+ else if (conv_rate == 0x00
+ && (config & 0x7F) == 0x00
+ && (status & 0xAB) == 0x00)
+ type_name = "lm84";
+ else
+ type_name = "max1617";
+
pr_debug("adm1021: Detected chip %s at adapter %d, address 0x%02x.\n",
type_name, i2c_adapter_id(adapter), client->addr);
strlcpy(info->type, type_name, I2C_NAME_SIZE);
diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c
index 4db04d603ec9..db6ac2b04f6f 100644
--- a/drivers/hwmon/adm1025.c
+++ b/drivers/hwmon/adm1025.c
@@ -2,7 +2,7 @@
* adm1025.c
*
* Copyright (C) 2000 Chen-Yuan Wu <gwu@esoft.com>
- * Copyright (C) 2003-2008 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2003-2009 Jean Delvare <khali@linux-fr.org>
*
* The ADM1025 is a sensor chip made by Analog Devices. It reports up to 6
* voltages (including its own power source) and up to two temperatures
@@ -413,67 +413,34 @@ static int adm1025_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
- const char *name = "";
- u8 config;
+ const char *name;
+ u8 man_id, chip_id;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- /*
- * Now we do the remaining detection. A negative kind means that
- * the driver was loaded with no force parameter (default), so we
- * must both detect and identify the chip. A zero kind means that
- * the driver was loaded with the force parameter, the detection
- * step shall be skipped. A positive kind means that the driver
- * was loaded with the force parameter and a given kind of chip is
- * requested, so both the detection and the identification steps
- * are skipped.
- */
- config = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG);
- if (kind < 0) { /* detection */
- if ((config & 0x80) != 0x00
- || (i2c_smbus_read_byte_data(client,
- ADM1025_REG_STATUS1) & 0xC0) != 0x00
- || (i2c_smbus_read_byte_data(client,
- ADM1025_REG_STATUS2) & 0xBC) != 0x00) {
- dev_dbg(&adapter->dev,
- "ADM1025 detection failed at 0x%02x.\n",
- client->addr);
- return -ENODEV;
- }
+ /* Check for unused bits */
+ if ((i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG) & 0x80)
+ || (i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS1) & 0xC0)
+ || (i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS2) & 0xBC)) {
+ dev_dbg(&adapter->dev, "ADM1025 detection failed at 0x%02x\n",
+ client->addr);
+ return -ENODEV;
}
- if (kind <= 0) { /* identification */
- u8 man_id, chip_id;
-
- man_id = i2c_smbus_read_byte_data(client, ADM1025_REG_MAN_ID);
- chip_id = i2c_smbus_read_byte_data(client, ADM1025_REG_CHIP_ID);
-
- if (man_id == 0x41) { /* Analog Devices */
- if ((chip_id & 0xF0) == 0x20) { /* ADM1025/ADM1025A */
- kind = adm1025;
- }
- } else
- if (man_id == 0xA1) { /* Philips */
- if (client->addr != 0x2E
- && (chip_id & 0xF0) == 0x20) { /* NE1619 */
- kind = ne1619;
- }
- }
-
- if (kind <= 0) { /* identification failed */
- dev_info(&adapter->dev,
- "Unsupported chip (man_id=0x%02X, "
- "chip_id=0x%02X).\n", man_id, chip_id);
- return -ENODEV;
- }
- }
+ /* Identification */
+ chip_id = i2c_smbus_read_byte_data(client, ADM1025_REG_CHIP_ID);
+ if ((chip_id & 0xF0) != 0x20)
+ return -ENODEV;
- if (kind == adm1025) {
+ man_id = i2c_smbus_read_byte_data(client, ADM1025_REG_MAN_ID);
+ if (man_id == 0x41)
name = "adm1025";
- } else if (kind == ne1619) {
+ else if (man_id == 0xA1 && client->addr != 0x2E)
name = "ne1619";
- }
+ else
+ return -ENODEV;
+
strlcpy(info->type, name, I2C_NAME_SIZE);
return 0;
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
index ff7de40b6e35..fb5363985e21 100644
--- a/drivers/hwmon/adm1026.c
+++ b/drivers/hwmon/adm1026.c
@@ -1672,35 +1672,26 @@ static int adm1026_detect(struct i2c_client *client, int kind,
i2c_adapter_id(client->adapter), client->addr,
company, verstep);
- /* If auto-detecting, Determine the chip type. */
- if (kind <= 0) {
- dev_dbg(&adapter->dev, "Autodetecting device at %d,0x%02x "
- "...\n", i2c_adapter_id(adapter), address);
- if (company == ADM1026_COMPANY_ANALOG_DEV
- && verstep == ADM1026_VERSTEP_ADM1026) {
- kind = adm1026;
- } else if (company == ADM1026_COMPANY_ANALOG_DEV
- && (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
- dev_err(&adapter->dev, "Unrecognized stepping "
- "0x%02x. Defaulting to ADM1026.\n", verstep);
- kind = adm1026;
- } else if ((verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
- dev_err(&adapter->dev, "Found version/stepping "
- "0x%02x. Assuming generic ADM1026.\n",
- verstep);
- kind = any_chip;
- } else {
- dev_dbg(&adapter->dev, "Autodetection failed\n");
- /* Not an ADM1026 ... */
- if (kind == 0) { /* User used force=x,y */
- dev_err(&adapter->dev, "Generic ADM1026 not "
- "found at %d,0x%02x. Try "
- "force_adm1026.\n",
- i2c_adapter_id(adapter), address);
- }
- return -ENODEV;
- }
+ /* Determine the chip type. */
+ dev_dbg(&adapter->dev, "Autodetecting device at %d,0x%02x...\n",
+ i2c_adapter_id(adapter), address);
+ if (company == ADM1026_COMPANY_ANALOG_DEV
+ && verstep == ADM1026_VERSTEP_ADM1026) {
+ /* Analog Devices ADM1026 */
+ } else if (company == ADM1026_COMPANY_ANALOG_DEV
+ && (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
+ dev_err(&adapter->dev, "Unrecognized stepping "
+ "0x%02x. Defaulting to ADM1026.\n", verstep);
+ } else if ((verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
+ dev_err(&adapter->dev, "Found version/stepping "
+ "0x%02x. Assuming generic ADM1026.\n",
+ verstep);
+ } else {
+ dev_dbg(&adapter->dev, "Autodetection failed\n");
+ /* Not an ADM1026... */
+ return -ENODEV;
}
+
strlcpy(info->type, "adm1026", I2C_NAME_SIZE);
return 0;
diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c
index 36718150b475..4d7d8433c2f3 100644
--- a/drivers/hwmon/adm1029.c
+++ b/drivers/hwmon/adm1029.c
@@ -301,59 +301,36 @@ static int adm1029_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
+ u8 man_id, chip_id, temp_devices_installed, nb_fan_support;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- /* Now we do the detection and identification. A negative kind
- * means that the driver was loaded with no force parameter
- * (default), so we must both detect and identify the chip
- * (actually there is only one possible kind of chip for now, adm1029).
- * A zero kind means that the driver was loaded with the force
- * parameter, the detection step shall be skipped. A positive kind
- * means that the driver was loaded with the force parameter and a
- * given kind of chip is requested, so both the detection and the
- * identification steps are skipped. */
-
- /* Default to an adm1029 if forced */
- if (kind == 0)
- kind = adm1029;
-
/* ADM1029 doesn't have CHIP ID, check just MAN ID
* For better detection we check also ADM1029_TEMP_DEVICES_INSTALLED,
* ADM1029_REG_NB_FAN_SUPPORT and compare it with possible values
* documented
*/
- if (kind <= 0) { /* identification */
- u8 man_id, chip_id, temp_devices_installed, nb_fan_support;
-
- man_id = i2c_smbus_read_byte_data(client, ADM1029_REG_MAN_ID);
- chip_id = i2c_smbus_read_byte_data(client, ADM1029_REG_CHIP_ID);
- temp_devices_installed = i2c_smbus_read_byte_data(client,
+ man_id = i2c_smbus_read_byte_data(client, ADM1029_REG_MAN_ID);
+ chip_id = i2c_smbus_read_byte_data(client, ADM1029_REG_CHIP_ID);
+ temp_devices_installed = i2c_smbus_read_byte_data(client,
ADM1029_REG_TEMP_DEVICES_INSTALLED);
- nb_fan_support = i2c_smbus_read_byte_data(client,
+ nb_fan_support = i2c_smbus_read_byte_data(client,
ADM1029_REG_NB_FAN_SUPPORT);
- /* 0x41 is Analog Devices */
- if (man_id == 0x41 && (temp_devices_installed & 0xf9) == 0x01
- && nb_fan_support == 0x03) {
- if ((chip_id & 0xF0) == 0x00) {
- kind = adm1029;
- } else {
- /* There are no "official" CHIP ID, so actually
- * we use Major/Minor revision for that */
- printk(KERN_INFO
- "adm1029: Unknown major revision %x, "
- "please let us know\n", chip_id);
- }
- }
+ /* 0x41 is Analog Devices */
+ if (man_id != 0x41 || (temp_devices_installed & 0xf9) != 0x01
+ || nb_fan_support != 0x03)
+ return -ENODEV;
- if (kind <= 0) { /* identification failed */
- pr_debug("adm1029: Unsupported chip (man_id=0x%02X, "
- "chip_id=0x%02X)\n", man_id, chip_id);
- return -ENODEV;
- }
+ if ((chip_id & 0xF0) != 0x00) {
+ /* There are no "official" CHIP ID, so actually
+ * we use Major/Minor revision for that */
+ pr_info("adm1029: Unknown major revision %x, "
+ "please let us know\n", chip_id);
+ return -ENODEV;
}
+
strlcpy(info->type, "adm1029", I2C_NAME_SIZE);
return 0;
diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c
index 56905955352c..0e722175aae0 100644
--- a/drivers/hwmon/adm1031.c
+++ b/drivers/hwmon/adm1031.c
@@ -817,31 +817,19 @@ static int adm1031_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
- const char *name = "";
+ const char *name;
+ int id, co;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- if (kind < 0) {
- int id, co;
- id = i2c_smbus_read_byte_data(client, 0x3d);
- co = i2c_smbus_read_byte_data(client, 0x3e);
+ id = i2c_smbus_read_byte_data(client, 0x3d);
+ co = i2c_smbus_read_byte_data(client, 0x3e);
- if (!((id == 0x31 || id == 0x30) && co == 0x41))
- return -ENODEV;
- kind = (id == 0x30) ? adm1030 : adm1031;
- }
-
- if (kind <= 0)
- kind = adm1031;
+ if (!((id == 0x31 || id == 0x30) && co == 0x41))
+ return -ENODEV;
+ name = (id == 0x30) ? "adm1030" : "adm1031";
- /* Given the detected chip type, set the chip name and the
- * auto fan control helper table. */
- if (kind == adm1030) {
- name = "adm1030";
- } else if (kind == adm1031) {
- name = "adm1031";
- }
strlcpy(info->type, name, I2C_NAME_SIZE);
return 0;
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
index 2444b15f2e9d..20e0481cc206 100644
--- a/drivers/hwmon/adm9240.c
+++ b/drivers/hwmon/adm9240.c
@@ -556,51 +556,34 @@ static int adm9240_detect(struct i2c_client *new_client, int kind,
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- if (kind == 0) {
- kind = adm9240;
- }
-
- if (kind < 0) {
-
- /* verify chip: reg address should match i2c address */
- if (i2c_smbus_read_byte_data(new_client, ADM9240_REG_I2C_ADDR)
- != address) {
- dev_err(&adapter->dev, "detect fail: address match, "
- "0x%02x\n", address);
- return -ENODEV;
- }
-
- /* check known chip manufacturer */
- man_id = i2c_smbus_read_byte_data(new_client,
- ADM9240_REG_MAN_ID);
- if (man_id == 0x23) {
- kind = adm9240;
- } else if (man_id == 0xda) {
- kind = ds1780;
- } else if (man_id == 0x01) {
- kind = lm81;
- } else {
- dev_err(&adapter->dev, "detect fail: unknown manuf, "
- "0x%02x\n", man_id);
- return -ENODEV;
- }
-
- /* successful detect, print chip info */
- die_rev = i2c_smbus_read_byte_data(new_client,
- ADM9240_REG_DIE_REV);
- dev_info(&adapter->dev, "found %s revision %u\n",
- man_id == 0x23 ? "ADM9240" :
- man_id == 0xda ? "DS1780" : "LM81", die_rev);
+ /* verify chip: reg address should match i2c address */
+ if (i2c_smbus_read_byte_data(new_client, ADM9240_REG_I2C_ADDR)
+ != address) {
+ dev_err(&adapter->dev, "detect fail: address match, 0x%02x\n",
+ address);
+ return -ENODEV;
}
- /* either forced or detected chip kind */
- if (kind == adm9240) {
+ /* check known chip manufacturer */
+ man_id = i2c_smbus_read_byte_data(new_client, ADM9240_REG_MAN_ID);
+ if (man_id == 0x23) {
name = "adm9240";
- } else if (kind == ds1780) {
+ } else if (man_id == 0xda) {
name = "ds1780";
- } else if (kind == lm81) {
+ } else if (man_id == 0x01) {
name = "lm81";
+ } else {
+ dev_err(&adapter->dev, "detect fail: unknown manuf, 0x%02x\n",
+ man_id);
+ return -ENODEV;
}
+
+ /* successful detect, print chip info */
+ die_rev = i2c_smbus_read_byte_data(new_client, ADM9240_REG_DIE_REV);
+ dev_info(&adapter->dev, "found %s revision %u\n",
+ man_id == 0x23 ? "ADM9240" :
+ man_id == 0xda ? "DS1780" : "LM81", die_rev);
+
strlcpy(info->type, name, I2C_NAME_SIZE);
return 0;
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
index 5c39b4af1b23..451977bca7d6 100644
--- a/drivers/hwmon/ads7828.c
+++ b/drivers/hwmon/ads7828.c
@@ -191,6 +191,7 @@ static int ads7828_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
+ int ch;
/* Check we have a valid client */
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA))
@@ -202,20 +203,17 @@ static int ads7828_detect(struct i2c_client *client, int kind,
- Read from the 8 channel addresses
- Check the top 4 bits of each result are not set (12 data bits)
*/
- if (kind < 0) {
- int ch;
- for (ch = 0; ch < ADS7828_NCH; ch++) {
- u16 in_data;
- u8 cmd = channel_cmd_byte(ch);
- in_data = ads7828_read_value(client, cmd);
- if (in_data & 0xF000) {
- printk(KERN_DEBUG
- "%s : Doesn't look like an ads7828 device\n",
- __func__);
- return -ENODEV;
- }
+ for (ch = 0; ch < ADS7828_NCH; ch++) {
+ u16 in_data;
+ u8 cmd = channel_cmd_byte(ch);
+ in_data = ads7828_read_value(client, cmd);
+ if (in_data & 0xF000) {
+ pr_debug("%s : Doesn't look like an ads7828 device\n",
+ __func__);
+ return -ENODEV;
}
}
+
strlcpy(info->type, "ads7828", I2C_NAME_SIZE);
return 0;
diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c
index 1852f27bac51..f9c9562b6a94 100644
--- a/drivers/hwmon/adt7462.c
+++ b/drivers/hwmon/adt7462.c
@@ -1906,27 +1906,22 @@ static int adt7462_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
+ int vendor, device, revision;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- if (kind <= 0) {
- int vendor, device, revision;
-
- vendor = i2c_smbus_read_byte_data(client, ADT7462_REG_VENDOR);
- if (vendor != ADT7462_VENDOR)
- return -ENODEV;
+ vendor = i2c_smbus_read_byte_data(client, ADT7462_REG_VENDOR);
+ if (vendor != ADT7462_VENDOR)
+ return -ENODEV;
- device = i2c_smbus_read_byte_data(client, ADT7462_REG_DEVICE);
- if (device != ADT7462_DEVICE)
- return -ENODEV;
+ device = i2c_smbus_read_byte_data(client, ADT7462_REG_DEVICE);
+ if (device != ADT7462_DEVICE)
+ return -ENODEV;
- revision = i2c_smbus_read_byte_data(client,
- ADT7462_REG_REVISION);
- if (revision != ADT7462_REVISION)
- return -ENODEV;
- } else
- dev_dbg(&adapter->dev, "detection forced\n");
+ revision = i2c_smbus_read_byte_data(client, ADT7462_REG_REVISION);
+ if (revision != ADT7462_REVISION)
+ return -ENODEV;
strlcpy(info->type, "adt7462", I2C_NAME_SIZE);
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
index 633e1a1e9d79..32b1750a6890 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -1229,27 +1229,22 @@ static int adt7470_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
+ int vendor, device, revision;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- if (kind <= 0) {
- int vendor, device, revision;
-
- vendor = i2c_smbus_read_byte_data(client, ADT7470_REG_VENDOR);
- if (vendor != ADT7470_VENDOR)
- return -ENODEV;
+ vendor = i2c_smbus_read_byte_data(client, ADT7470_REG_VENDOR);
+ if (vendor != ADT7470_VENDOR)
+ return -ENODEV;
- device = i2c_smbus_read_byte_data(client, ADT7470_REG_DEVICE);
- if (device != ADT7470_DEVICE)
- return -ENODEV;
+ device = i2c_smbus_read_byte_data(client, ADT7470_REG_DEVICE);
+ if (device != ADT7470_DEVICE)
+ return -ENODEV;
- revision = i2c_smbus_read_byte_data(client,
- ADT7470_REG_REVISION);
- if (revision != ADT7470_REVISION)
- return -ENODEV;
- } else
- dev_dbg(&adapter->dev, "detection forced\n");
+ revision = i2c_smbus_read_byte_data(client, ADT7470_REG_REVISION);
+ if (revision != ADT7470_REVISION)
+ return -ENODEV;
strlcpy(info->type, "adt7470", I2C_NAME_SIZE);
diff --git a/drivers/hwmon/adt7473.c b/drivers/hwmon/adt7473.c
index 0a6ce2367b42..97ef50833f64 100644
--- a/drivers/hwmon/adt7473.c
+++ b/drivers/hwmon/adt7473.c
@@ -1090,27 +1090,22 @@ static int adt7473_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
+ int vendor, device, revision;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- if (kind <= 0) {
- int vendor, device, revision;
-
- vendor = i2c_smbus_read_byte_data(client, ADT7473_REG_VENDOR);
- if (vendor != ADT7473_VENDOR)
- return -ENODEV;
+ vendor = i2c_smbus_read_byte_data(client, ADT7473_REG_VENDOR);
+ if (vendor != ADT7473_VENDOR)
+ return -ENODEV;
- device = i2c_smbus_read_byte_data(client, ADT7473_REG_DEVICE);
- if (device != ADT7473_DEVICE)
- return -ENODEV;
+ device = i2c_smbus_read_byte_data(client, ADT7473_REG_DEVICE);
+ if (device != ADT7473_DEVICE)
+ return -ENODEV;
- revision = i2c_smbus_read_byte_data(client,
- ADT7473_REG_REVISION);
- if (revision != ADT7473_REV_68 && revision != ADT7473_REV_69)
- return -ENODEV;
- } else
- dev_dbg(&adapter->dev, "detection forced\n");
+ revision = i2c_smbus_read_byte_data(client, ADT7473_REG_REVISION);
+ if (revision != ADT7473_REV_68 && revision != ADT7473_REV_69)
+ return -ENODEV;
strlcpy(info->type, "adt7473", I2C_NAME_SIZE);
diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c
index d39877a7da63..90f381ff6ec2 100644
--- a/drivers/hwmon/adt7475.c
+++ b/drivers/hwmon/adt7475.c
@@ -975,14 +975,12 @@ static int adt7475_detect(struct i2c_client *client, int kind,
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- if (kind <= 0) {
- if (adt7475_read(REG_VENDID) != 0x41 ||
- adt7475_read(REG_DEVID) != 0x75) {
- dev_err(&adapter->dev,
- "Couldn't detect a adt7475 part at 0x%02x\n",
- (unsigned int)client->addr);
- return -ENODEV;
- }
+ if (adt7475_read(REG_VENDID) != 0x41 ||
+ adt7475_read(REG_DEVID) != 0x75) {
+ dev_err(&adapter->dev,
+ "Couldn't detect a adt7475 part at 0x%02x\n",
+ (unsigned int)client->addr);
+ return -ENODEV;
}
strlcpy(info->type, adt7475_id[0].name, I2C_NAME_SIZE);
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index 8acf82977e7b..480f80ea1fa0 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -701,6 +701,7 @@ static int asb100_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
+ int val1, val2;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
pr_debug("asb100.o: detect failed, "
@@ -708,50 +709,30 @@ static int asb100_detect(struct i2c_client *client, int kind,
return -ENODEV;
}
- /* The chip may be stuck in some other bank than bank 0. This may
- make reading other information impossible. Specify a force=... or
- force_*=... parameter, and the chip will be reset to the right
- bank. */
- if (kind < 0) {
-
- int val1 = i2c_smbus_read_byte_data(client, ASB100_REG_BANK);
- int val2 = i2c_smbus_read_byte_data(client, ASB100_REG_CHIPMAN);
-
- /* If we're in bank 0 */
- if ((!(val1 & 0x07)) &&
- /* Check for ASB100 ID (low byte) */
- (((!(val1 & 0x80)) && (val2 != 0x94)) ||
- /* Check for ASB100 ID (high byte ) */
- ((val1 & 0x80) && (val2 != 0x06)))) {
- pr_debug("asb100.o: detect failed, "
- "bad chip id 0x%02x!\n", val2);
- return -ENODEV;
- }
+ val1 = i2c_smbus_read_byte_data(client, ASB100_REG_BANK);
+ val2 = i2c_smbus_read_byte_data(client, ASB100_REG_CHIPMAN);
- } /* kind < 0 */
+ /* If we're in bank 0 */
+ if ((!(val1 & 0x07)) &&
+ /* Check for ASB100 ID (low byte) */
+ (((!(val1 & 0x80)) && (val2 != 0x94)) ||
+ /* Check for ASB100 ID (high byte ) */
+ ((val1 & 0x80) && (val2 != 0x06)))) {
+ pr_debug("asb100: detect failed, bad chip id 0x%02x!\n", val2);
+ return -ENODEV;
+ }
- /* We have either had a force parameter, or we have already detected
- Winbond. Put it now into bank 0 and Vendor ID High Byte */
+ /* Put it now into bank 0 and Vendor ID High Byte */
i2c_smbus_write_byte_data(client, ASB100_REG_BANK,
(i2c_smbus_read_byte_data(client, ASB100_REG_BANK) & 0x78)
| 0x80);
/* Determine the chip type. */
- if (kind <= 0) {
- int val1 = i2c_smbus_read_byte_data(client, ASB100_REG_WCHIPID);
- int val2 = i2c_smbus_read_byte_data(client, ASB100_REG_CHIPMAN);
-
- if ((val1 == 0x31) && (val2 == 0x06))
- kind = asb100;
- else {
- if (kind == 0)
- dev_warn(&adapter->dev, "ignoring "
- "'force' parameter for unknown chip "
- "at adapter %d, address 0x%02x.\n",
- i2c_adapter_id(adapter), client->addr);
- return -ENODEV;
- }
- }
+ val1 = i2c_smbus_read_byte_data(client, ASB100_REG_WCHIPID);
+ val2 = i2c_smbus_read_byte_data(client, ASB100_REG_CHIPMAN);
+
+ if (val1 != 0x31 || val2 != 0x06)
+ return -ENODEV;
strlcpy(info->type, "asb100", I2C_NAME_SIZE);
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
index 2c2cb1ec94c5..4377bb0cc526 100644
--- a/drivers/hwmon/dme1737.c
+++ b/drivers/hwmon/dme1737.c
@@ -572,7 +572,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
/* Sample register contents every 1 sec */
if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
- if (data->type != sch5027) {
+ if (data->type == dme1737) {
data->vid = dme1737_read(data, DME1737_REG_VID) &
0x3f;
}
@@ -1621,9 +1621,6 @@ static struct attribute *dme1737_misc_attr[] = {
&sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr,
&sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr,
&sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr,
- /* Misc */
- &dev_attr_vrm.attr,
- &dev_attr_cpu0_vid.attr,
NULL
};
@@ -1631,6 +1628,18 @@ static const struct attribute_group dme1737_misc_group = {
.attrs = dme1737_misc_attr,
};
+/* The following struct holds VID-related attributes. Their creation
+ depends on the chip type which is determined during module load. */
+static struct attribute *dme1737_vid_attr[] = {
+ &dev_attr_vrm.attr,
+ &dev_attr_cpu0_vid.attr,
+ NULL
+};
+
+static const struct attribute_group dme1737_vid_group = {
+ .attrs = dme1737_vid_attr,
+};
+
/* The following structs hold the PWM attributes, some of which are optional.
* Their creation depends on the chip configuration which is determined during
* module load. */
@@ -1902,6 +1911,9 @@ static void dme1737_remove_files(struct device *dev)
if (data->type != sch5027) {
sysfs_remove_group(&dev->kobj, &dme1737_misc_group);
}
+ if (data->type == dme1737) {
+ sysfs_remove_group(&dev->kobj, &dme1737_vid_group);
+ }
sysfs_remove_group(&dev->kobj, &dme1737_group);
@@ -1933,6 +1945,13 @@ static int dme1737_create_files(struct device *dev)
goto exit_remove;
}
+ /* Create VID-related sysfs attributes */
+ if ((data->type == dme1737) &&
+ (err = sysfs_create_group(&dev->kobj,
+ &dme1737_vid_group))) {
+ goto exit_remove;
+ }
+
/* Create fan sysfs attributes */
for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
if (data->has_fan & (1 << ix)) {
@@ -2127,7 +2146,7 @@ static int dme1737_init_device(struct device *dev)
data->pwm_acz[2] = 4; /* pwm3 -> zone3 */
/* Set VRM */
- if (data->type != sch5027) {
+ if (data->type == dme1737) {
data->vrm = vid_which_vrm();
}
@@ -2201,33 +2220,23 @@ static int dme1737_i2c_detect(struct i2c_client *client, int kind,
return -ENODEV;
}
- /* A negative kind means that the driver was loaded with no force
- * parameter (default), so we must identify the chip. */
- if (kind < 0) {
- company = i2c_smbus_read_byte_data(client, DME1737_REG_COMPANY);
- verstep = i2c_smbus_read_byte_data(client, DME1737_REG_VERSTEP);
-
- if (company == DME1737_COMPANY_SMSC &&
- (verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) {
- kind = dme1737;
- } else if (company == DME1737_COMPANY_SMSC &&
- verstep == SCH5027_VERSTEP) {
- kind = sch5027;
- } else {
- return -ENODEV;
- }
- }
+ company = i2c_smbus_read_byte_data(client, DME1737_REG_COMPANY);
+ verstep = i2c_smbus_read_byte_data(client, DME1737_REG_VERSTEP);
- if (kind == sch5027) {
+ if (company == DME1737_COMPANY_SMSC &&
+ verstep == SCH5027_VERSTEP) {
name = "sch5027";
- } else {
- kind = dme1737;
+
+ } else if (company == DME1737_COMPANY_SMSC &&
+ (verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) {
name = "dme1737";
+ } else {
+ return -ENODEV;
}
dev_info(dev, "Found a %s chip at 0x%02x (rev 0x%02x).\n",
- kind == sch5027 ? "SCH5027" : "DME1737", client->addr,
- verstep);
+ verstep == SCH5027_VERSTEP ? "SCH5027" : "DME1737",
+ client->addr, verstep);
strlcpy(info->type, name, I2C_NAME_SIZE);
return 0;
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
index 53f88f511816..2a4c6a05b14f 100644
--- a/drivers/hwmon/ds1621.c
+++ b/drivers/hwmon/ds1621.c
@@ -237,20 +237,16 @@ static int ds1621_detect(struct i2c_client *client, int kind,
return -ENODEV;
/* Now, we do the remaining detection. It is lousy. */
- if (kind < 0) {
- /* The NVB bit should be low if no EEPROM write has been
- requested during the latest 10ms, which is highly
- improbable in our case. */
- conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
- if (conf < 0 || conf & DS1621_REG_CONFIG_NVB)
+ /* The NVB bit should be low if no EEPROM write has been requested
+ during the latest 10ms, which is highly improbable in our case. */
+ conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
+ if (conf < 0 || conf & DS1621_REG_CONFIG_NVB)
+ return -ENODEV;
+ /* The 7 lowest bits of a temperature should always be 0. */
+ for (i = 0; i < ARRAY_SIZE(DS1621_REG_TEMP); i++) {
+ temp = i2c_smbus_read_word_data(client, DS1621_REG_TEMP[i]);
+ if (temp < 0 || (temp & 0x7f00))
return -ENODEV;
- /* The 7 lowest bits of a temperature should always be 0. */
- for (i = 0; i < ARRAY_SIZE(DS1621_REG_TEMP); i++) {
- temp = i2c_smbus_read_word_data(client,
- DS1621_REG_TEMP[i]);
- if (temp < 0 || (temp & 0x7f00))
- return -ENODEV;
- }
}
strlcpy(info->type, "ds1621", I2C_NAME_SIZE);
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c
index e2107e533ede..ac5b12ce5148 100644
--- a/drivers/hwmon/f75375s.c
+++ b/drivers/hwmon/f75375s.c
@@ -681,30 +681,19 @@ static int f75375_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
- u8 version = 0;
- const char *name = "";
-
- if (kind < 0) {
- u16 vendid = f75375_read16(client, F75375_REG_VENDOR);
- u16 chipid = f75375_read16(client, F75375_CHIP_ID);
- version = f75375_read8(client, F75375_REG_VERSION);
- if (chipid == 0x0306 && vendid == 0x1934) {
- kind = f75375;
- } else if (chipid == 0x0204 && vendid == 0x1934) {
- kind = f75373;
- } else {
- dev_err(&adapter->dev,
- "failed,%02X,%02X,%02X\n",
- chipid, version, vendid);
- return -ENODEV;
- }
- }
+ u8 vendid, chipid, version;
+ const char *name;
- if (kind == f75375) {
+ vendid = f75375_read16(client, F75375_REG_VENDOR);
+ chipid = f75375_read16(client, F75375_CHIP_ID);
+ if (chipid == 0x0306 && vendid == 0x1934)
name = "f75375";
- } else if (kind == f75373) {
+ else if (chipid == 0x0204 && vendid == 0x1934)
name = "f75373";
- }
+ else
+ return -ENODEV;
+
+ version = f75375_read8(client, F75375_REG_VERSION);
dev_info(&adapter->dev, "found %s version: %02X\n", name, version);
strlcpy(info->type, name, I2C_NAME_SIZE);
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
index 2a7a85a6dc36..281829cd1533 100644
--- a/drivers/hwmon/fschmd.c
+++ b/drivers/hwmon/fschmd.c
@@ -819,7 +819,7 @@ static int watchdog_release(struct inode *inode, struct file *filp)
static ssize_t watchdog_write(struct file *filp, const char __user *buf,
size_t count, loff_t *offset)
{
- size_t ret;
+ int ret;
struct fschmd_data *data = filp->private_data;
if (count) {
@@ -1000,43 +1000,38 @@ static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy)
}
}
-static int fschmd_detect(struct i2c_client *client, int kind,
+static int fschmd_detect(struct i2c_client *client, int _kind,
struct i2c_board_info *info)
{
+ enum chips kind;
struct i2c_adapter *adapter = client->adapter;
+ char id[4];
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
/* Detect & Identify the chip */
- if (kind <= 0) {
- char id[4];
-
- id[0] = i2c_smbus_read_byte_data(client,
- FSCHMD_REG_IDENT_0);
- id[1] = i2c_smbus_read_byte_data(client,
- FSCHMD_REG_IDENT_1);
- id[2] = i2c_smbus_read_byte_data(client,
- FSCHMD_REG_IDENT_2);
- id[3] = '\0';
-
- if (!strcmp(id, "PEG"))
- kind = fscpos;
- else if (!strcmp(id, "HER"))
- kind = fscher;
- else if (!strcmp(id, "SCY"))
- kind = fscscy;
- else if (!strcmp(id, "HRC"))
- kind = fschrc;
- else if (!strcmp(id, "HMD"))
- kind = fschmd;
- else if (!strcmp(id, "HDS"))
- kind = fschds;
- else if (!strcmp(id, "SYL"))
- kind = fscsyl;
- else
- return -ENODEV;
- }
+ id[0] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_0);
+ id[1] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_1);
+ id[2] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_2);
+ id[3] = '\0';
+
+ if (!strcmp(id, "PEG"))
+ kind = fscpos;
+ else if (!strcmp(id, "HER"))
+ kind = fscher;
+ else if (!strcmp(id, "SCY"))
+ kind = fscscy;
+ else if (!strcmp(id, "HRC"))
+ kind = fschrc;
+ else if (!strcmp(id, "HMD"))
+ kind = fschmd;
+ else if (!strcmp(id, "HDS"))
+ kind = fschds;
+ else if (!strcmp(id, "SYL"))
+ kind = fscsyl;
+ else
+ return -ENODEV;
strlcpy(info->type, fschmd_id[kind - 1].name, I2C_NAME_SIZE);
diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c
index 7820df45d77a..1d69458aa0b6 100644
--- a/drivers/hwmon/gl518sm.c
+++ b/drivers/hwmon/gl518sm.c
@@ -488,36 +488,21 @@ static int gl518_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
- int i;
+ int rev;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
/* Now, we do the remaining detection. */
-
- if (kind < 0) {
- if ((gl518_read_value(client, GL518_REG_CHIP_ID) != 0x80)
- || (gl518_read_value(client, GL518_REG_CONF) & 0x80))
- return -ENODEV;
- }
+ if ((gl518_read_value(client, GL518_REG_CHIP_ID) != 0x80)
+ || (gl518_read_value(client, GL518_REG_CONF) & 0x80))
+ return -ENODEV;
/* Determine the chip type. */
- if (kind <= 0) {
- i = gl518_read_value(client, GL518_REG_REVISION);
- if (i == 0x00) {
- kind = gl518sm_r00;
- } else if (i == 0x80) {
- kind = gl518sm_r80;
- } else {
- if (kind <= 0)
- dev_info(&adapter->dev,
- "Ignoring 'force' parameter for unknown "
- "chip at adapter %d, address 0x%02x\n",
- i2c_adapter_id(adapter), client->addr);
- return -ENODEV;
- }
- }
+ rev = gl518_read_value(client, GL518_REG_REVISION);
+ if (rev != 0x00 && rev != 0x80)
+ return -ENODEV;
strlcpy(info->type, "gl518sm", I2C_NAME_SIZE);
diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c
index 19616f2242b0..92b5720ceaff 100644
--- a/drivers/hwmon/gl520sm.c
+++ b/drivers/hwmon/gl520sm.c
@@ -691,13 +691,11 @@ static int gl520_detect(struct i2c_client *client, int kind,
return -ENODEV;
/* Determine the chip type. */
- if (kind < 0) {
- if ((gl520_read_value(client, GL520_REG_CHIP_ID) != 0x20) ||
- ((gl520_read_value(client, GL520_REG_REVISION) & 0x7f) != 0x00) ||
- ((gl520_read_value(client, GL520_REG_CONF) & 0x80) != 0x00)) {
- dev_dbg(&client->dev, "Unknown chip type, skipping\n");
- return -ENODEV;
- }
+ if ((gl520_read_value(client, GL520_REG_CHIP_ID) != 0x20) ||
+ ((gl520_read_value(client, GL520_REG_REVISION) & 0x7f) != 0x00) ||
+ ((gl520_read_value(client, GL520_REG_CONF) & 0x80) != 0x00)) {
+ dev_dbg(&client->dev, "Unknown chip type, skipping\n");
+ return -ENODEV;
}
strlcpy(info->type, "gl520sm", I2C_NAME_SIZE);
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index ffeb2a10e1a7..0ffe84d190bb 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -124,6 +124,8 @@ superio_exit(void)
#define IT87_BASE_REG 0x60
/* Logical device 7 registers (IT8712F and later) */
+#define IT87_SIO_GPIO3_REG 0x27
+#define IT87_SIO_GPIO5_REG 0x29
#define IT87_SIO_PINX2_REG 0x2c /* Pin selection */
#define IT87_SIO_VID_REG 0xfc /* VID value */
@@ -244,7 +246,9 @@ struct it87_sio_data {
/* Values read from Super-I/O config space */
u8 revision;
u8 vid_value;
- /* Values set based on DMI strings */
+ /* Features skipped based on config or DMI */
+ u8 skip_vid;
+ u8 skip_fan;
u8 skip_pwm;
};
@@ -1028,12 +1032,35 @@ static int __init it87_find(unsigned short *address,
chip_type, *address, sio_data->revision);
/* Read GPIO config and VID value from LDN 7 (GPIO) */
- if (chip_type != IT8705F_DEVID) {
+ if (sio_data->type == it87) {
+ /* The IT8705F doesn't have VID pins at all */
+ sio_data->skip_vid = 1;
+ } else {
int reg;
superio_select(GPIO);
- if ((chip_type == it8718) ||
- (chip_type == it8720))
+ /* We need at least 4 VID pins */
+ reg = superio_inb(IT87_SIO_GPIO3_REG);
+ if (reg & 0x0f) {
+ pr_info("it87: VID is disabled (pins used for GPIO)\n");
+ sio_data->skip_vid = 1;
+ }
+
+ /* Check if fan3 is there or not */
+ if (reg & (1 << 6))
+ sio_data->skip_pwm |= (1 << 2);
+ if (reg & (1 << 7))
+ sio_data->skip_fan |= (1 << 2);
+
+ /* Check if fan2 is there or not */
+ reg = superio_inb(IT87_SIO_GPIO5_REG);
+ if (reg & (1 << 1))
+ sio_data->skip_pwm |= (1 << 1);
+ if (reg & (1 << 2))
+ sio_data->skip_fan |= (1 << 1);
+
+ if ((sio_data->type == it8718 || sio_data->type == it8720)
+ && !(sio_data->skip_vid))
sio_data->vid_value = superio_inb(IT87_SIO_VID_REG);
reg = superio_inb(IT87_SIO_PINX2_REG);
@@ -1237,8 +1264,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
}
}
- if (data->type == it8712 || data->type == it8716
- || data->type == it8718 || data->type == it8720) {
+ if (!sio_data->skip_vid) {
data->vrm = vid_which_vrm();
/* VID reading from Super-I/O config space if available */
data->vid = sio_data->vid_value;
@@ -1356,8 +1382,10 @@ static int __devinit it87_check_pwm(struct device *dev)
/* Called when we have found a new IT87. */
static void __devinit it87_init_device(struct platform_device *pdev)
{
+ struct it87_sio_data *sio_data = pdev->dev.platform_data;
struct it87_data *data = platform_get_drvdata(pdev);
int tmp, i;
+ u8 mask;
/* initialize to sane defaults:
* - if the chip is in manual pwm mode, this will be overwritten with
@@ -1403,10 +1431,11 @@ static void __devinit it87_init_device(struct platform_device *pdev)
}
/* Check if tachometers are reset manually or by some reason */
+ mask = 0x70 & ~(sio_data->skip_fan << 4);
data->fan_main_ctrl = it87_read_value(data, IT87_REG_FAN_MAIN_CTRL);
- if ((data->fan_main_ctrl & 0x70) == 0) {
+ if ((data->fan_main_ctrl & mask) == 0) {
/* Enable all fan tachometers */
- data->fan_main_ctrl |= 0x70;
+ data->fan_main_ctrl |= mask;
it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
}
data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
@@ -1429,6 +1458,9 @@ static void __devinit it87_init_device(struct platform_device *pdev)
}
}
+ /* Fan input pins may be used for alternative functions */
+ data->has_fan &= ~sio_data->skip_fan;
+
/* Set current fan mode registers and the default settings for the
* other mode registers */
for (i = 0; i < 3; i++) {
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index 3195a265f0e9..5da66ab04f74 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -427,40 +427,34 @@ static int lm63_detect(struct i2c_client *new_client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = new_client->adapter;
+ u8 man_id, chip_id, reg_config1, reg_config2;
+ u8 reg_alert_status, reg_alert_mask;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- if (kind < 0) { /* must identify */
- u8 man_id, chip_id, reg_config1, reg_config2;
- u8 reg_alert_status, reg_alert_mask;
-
- man_id = i2c_smbus_read_byte_data(new_client,
- LM63_REG_MAN_ID);
- chip_id = i2c_smbus_read_byte_data(new_client,
- LM63_REG_CHIP_ID);
- reg_config1 = i2c_smbus_read_byte_data(new_client,
- LM63_REG_CONFIG1);
- reg_config2 = i2c_smbus_read_byte_data(new_client,
- LM63_REG_CONFIG2);
- reg_alert_status = i2c_smbus_read_byte_data(new_client,
- LM63_REG_ALERT_STATUS);
- reg_alert_mask = i2c_smbus_read_byte_data(new_client,
- LM63_REG_ALERT_MASK);
-
- if (man_id == 0x01 /* National Semiconductor */
- && chip_id == 0x41 /* LM63 */
- && (reg_config1 & 0x18) == 0x00
- && (reg_config2 & 0xF8) == 0x00
- && (reg_alert_status & 0x20) == 0x00
- && (reg_alert_mask & 0xA4) == 0xA4) {
- kind = lm63;
- } else { /* failed */
- dev_dbg(&adapter->dev, "Unsupported chip "
- "(man_id=0x%02X, chip_id=0x%02X).\n",
- man_id, chip_id);
- return -ENODEV;
- }
+ man_id = i2c_smbus_read_byte_data(new_client, LM63_REG_MAN_ID);
+ chip_id = i2c_smbus_read_byte_data(new_client, LM63_REG_CHIP_ID);
+
+ reg_config1 = i2c_smbus_read_byte_data(new_client,
+ LM63_REG_CONFIG1);
+ reg_config2 = i2c_smbus_read_byte_data(new_client,
+ LM63_REG_CONFIG2);
+ reg_alert_status = i2c_smbus_read_byte_data(new_client,
+ LM63_REG_ALERT_STATUS);
+ reg_alert_mask = i2c_smbus_read_byte_data(new_client,
+ LM63_REG_ALERT_MASK);
+
+ if (man_id != 0x01 /* National Semiconductor */
+ || chip_id != 0x41 /* LM63 */
+ || (reg_config1 & 0x18) != 0x00
+ || (reg_config2 & 0xF8) != 0x00
+ || (reg_alert_status & 0x20) != 0x00
+ || (reg_alert_mask & 0xA4) != 0xA4) {
+ dev_dbg(&adapter->dev,
+ "Unsupported chip (man_id=0x%02X, chip_id=0x%02X)\n",
+ man_id, chip_id);
+ return -ENODEV;
}
strlcpy(info->type, "lm63", I2C_NAME_SIZE);
diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c
new file mode 100644
index 000000000000..e10dc507f0e7
--- /dev/null
+++ b/drivers/hwmon/lm73.c
@@ -0,0 +1,205 @@
+/*
+ * LM73 Sensor driver
+ * Based on LM75
+ *
+ * Copyright (C) 2007, CenoSYS (www.cenosys.com).
+ * Copyright (C) 2009, Bollore telecom (www.bolloretelecom.eu).
+ *
+ * Guillaume Ligneul <guillaume.ligneul@cenosys.com>
+ * Adrien Demarez <adrien.demarez@bolloretelecom.eu>
+ * Jeremy Laine <jeremy.laine@bolloretelecom.eu>
+ *
+ * This software program is licensed subject to the GNU General Public License
+ * (GPL).Version 2,June 1991, available at
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+
+
+/* Addresses scanned */
+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c,
+ 0x4d, 0x4e, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(lm73);
+
+/* LM73 registers */
+#define LM73_REG_INPUT 0x00
+#define LM73_REG_CONF 0x01
+#define LM73_REG_MAX 0x02
+#define LM73_REG_MIN 0x03
+#define LM73_REG_CTRL 0x04
+#define LM73_REG_ID 0x07
+
+#define LM73_ID 0x9001 /* or 0x190 after a swab16() */
+#define DRVNAME "lm73"
+#define LM73_TEMP_MIN (-40)
+#define LM73_TEMP_MAX 150
+
+/*-----------------------------------------------------------------------*/
+
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ long temp;
+ short value;
+
+ int status = strict_strtol(buf, 10, &temp);
+ if (status < 0)
+ return status;
+
+ /* Write value */
+ value = (short) SENSORS_LIMIT(temp/250, (LM73_TEMP_MIN*4),
+ (LM73_TEMP_MAX*4)) << 5;
+ i2c_smbus_write_word_data(client, attr->index, swab16(value));
+ return count;
+}
+
+static ssize_t show_temp(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);
+ /* use integer division instead of equivalent right shift to
+ guarantee arithmetic shift and preserve the sign */
+ int temp = ((s16) (swab16(i2c_smbus_read_word_data(client,
+ attr->index)))*250) / 32;
+ return sprintf(buf, "%d\n", temp);
+}
+
+
+/*-----------------------------------------------------------------------*/
+
+/* sysfs attributes for hwmon */
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+ show_temp, set_temp, LM73_REG_MAX);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
+ show_temp, set_temp, LM73_REG_MIN);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
+ show_temp, NULL, LM73_REG_INPUT);
+
+
+static struct attribute *lm73_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+
+ NULL
+};
+
+static const struct attribute_group lm73_group = {
+ .attrs = lm73_attributes,
+};
+
+/*-----------------------------------------------------------------------*/
+
+/* device probe and removal */
+
+static int
+lm73_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct device *hwmon_dev;
+ int status;
+
+ /* Register sysfs hooks */
+ status = sysfs_create_group(&client->dev.kobj, &lm73_group);
+ if (status)
+ return status;
+
+ hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(hwmon_dev)) {
+ status = PTR_ERR(hwmon_dev);
+ goto exit_remove;
+ }
+ i2c_set_clientdata(client, hwmon_dev);
+
+ dev_info(&client->dev, "%s: sensor '%s'\n",
+ dev_name(hwmon_dev), client->name);
+
+ return 0;
+
+exit_remove:
+ sysfs_remove_group(&client->dev.kobj, &lm73_group);
+ return status;
+}
+
+static int lm73_remove(struct i2c_client *client)
+{
+ struct device *hwmon_dev = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm73_group);
+ i2c_set_clientdata(client, NULL);
+ return 0;
+}
+
+static const struct i2c_device_id lm73_ids[] = {
+ { "lm73", lm73 },
+ { /* LIST END */ }
+};
+MODULE_DEVICE_TABLE(i2c, lm73_ids);
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm73_detect(struct i2c_client *new_client, int kind,
+ struct i2c_board_info *info)
+{
+ struct i2c_adapter *adapter = new_client->adapter;
+ u16 id;
+ u8 ctrl;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA))
+ return -ENODEV;
+
+ /* Check device ID */
+ id = i2c_smbus_read_word_data(new_client, LM73_REG_ID);
+ ctrl = i2c_smbus_read_byte_data(new_client, LM73_REG_CTRL);
+ if ((id != LM73_ID) || (ctrl & 0x10))
+ return -ENODEV;
+
+ strlcpy(info->type, "lm73", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static struct i2c_driver lm73_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "lm73",
+ },
+ .probe = lm73_probe,
+ .remove = lm73_remove,
+ .id_table = lm73_ids,
+ .detect = lm73_detect,
+ .address_data = &addr_data,
+};
+
+/* module glue */
+
+static int __init sensors_lm73_init(void)
+{
+ return i2c_add_driver(&lm73_driver);
+}
+
+static void __exit sensors_lm73_exit(void)
+{
+ i2c_del_driver(&lm73_driver);
+}
+
+MODULE_AUTHOR("Guillaume Ligneul <guillaume.ligneul@cenosys.com>");
+MODULE_DESCRIPTION("LM73 driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_lm73_init);
+module_exit(sensors_lm73_exit);
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index 55bd87c15c9a..e392548cccb8 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -239,6 +239,7 @@ static int lm75_detect(struct i2c_client *new_client, int kind,
{
struct i2c_adapter *adapter = new_client->adapter;
int i;
+ int cur, conf, hyst, os;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA))
@@ -251,40 +252,35 @@ static int lm75_detect(struct i2c_client *new_client, int kind,
The cycling+unused addresses combination is not tested,
since it would significantly slow the detection down and would
hardly add any value. */
- if (kind < 0) {
- int cur, conf, hyst, os;
-
- /* Unused addresses */
- cur = i2c_smbus_read_word_data(new_client, 0);
- conf = i2c_smbus_read_byte_data(new_client, 1);
- hyst = i2c_smbus_read_word_data(new_client, 2);
- if (i2c_smbus_read_word_data(new_client, 4) != hyst
- || i2c_smbus_read_word_data(new_client, 5) != hyst
- || i2c_smbus_read_word_data(new_client, 6) != hyst
- || i2c_smbus_read_word_data(new_client, 7) != hyst)
- return -ENODEV;
- os = i2c_smbus_read_word_data(new_client, 3);
- if (i2c_smbus_read_word_data(new_client, 4) != os
- || i2c_smbus_read_word_data(new_client, 5) != os
- || i2c_smbus_read_word_data(new_client, 6) != os
- || i2c_smbus_read_word_data(new_client, 7) != os)
- return -ENODEV;
- /* Unused bits */
- if (conf & 0xe0)
- return -ENODEV;
+ /* Unused addresses */
+ cur = i2c_smbus_read_word_data(new_client, 0);
+ conf = i2c_smbus_read_byte_data(new_client, 1);
+ hyst = i2c_smbus_read_word_data(new_client, 2);
+ if (i2c_smbus_read_word_data(new_client, 4) != hyst
+ || i2c_smbus_read_word_data(new_client, 5) != hyst
+ || i2c_smbus_read_word_data(new_client, 6) != hyst
+ || i2c_smbus_read_word_data(new_client, 7) != hyst)
+ return -ENODEV;
+ os = i2c_smbus_read_word_data(new_client, 3);
+ if (i2c_smbus_read_word_data(new_client, 4) != os
+ || i2c_smbus_read_word_data(new_client, 5) != os
+ || i2c_smbus_read_word_data(new_client, 6) != os
+ || i2c_smbus_read_word_data(new_client, 7) != os)
+ return -ENODEV;
- /* Addresses cycling */
- for (i = 8; i < 0xff; i += 8)
- if (i2c_smbus_read_byte_data(new_client, i + 1) != conf
- || i2c_smbus_read_word_data(new_client, i + 2) != hyst
- || i2c_smbus_read_word_data(new_client, i + 3) != os)
- return -ENODEV;
+ /* Unused bits */
+ if (conf & 0xe0)
+ return -ENODEV;
+
+ /* Addresses cycling */
+ for (i = 8; i < 0xff; i += 8) {
+ if (i2c_smbus_read_byte_data(new_client, i + 1) != conf
+ || i2c_smbus_read_word_data(new_client, i + 2) != hyst
+ || i2c_smbus_read_word_data(new_client, i + 3) != os)
+ return -ENODEV;
}
- /* NOTE: we treat "force=..." and "force_lm75=..." the same.
- * Only new-style driver binding distinguishes chip types.
- */
strlcpy(info->type, "lm75", I2C_NAME_SIZE);
return 0;
diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c
index 866b401ab6e8..ac067fd19482 100644
--- a/drivers/hwmon/lm77.c
+++ b/drivers/hwmon/lm77.c
@@ -249,6 +249,7 @@ static int lm77_detect(struct i2c_client *new_client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = new_client->adapter;
+ int i, cur, conf, hyst, crit, min, max;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA))
@@ -265,51 +266,48 @@ static int lm77_detect(struct i2c_client *new_client, int kind,
4. registers cycling over 8-address boundaries
Word-sized registers are high-byte first. */
- if (kind < 0) {
- int i, cur, conf, hyst, crit, min, max;
-
- /* addresses cycling */
- cur = i2c_smbus_read_word_data(new_client, 0);
- conf = i2c_smbus_read_byte_data(new_client, 1);
- hyst = i2c_smbus_read_word_data(new_client, 2);
- crit = i2c_smbus_read_word_data(new_client, 3);
- min = i2c_smbus_read_word_data(new_client, 4);
- max = i2c_smbus_read_word_data(new_client, 5);
- for (i = 8; i <= 0xff; i += 8)
- if (i2c_smbus_read_byte_data(new_client, i + 1) != conf
- || i2c_smbus_read_word_data(new_client, i + 2) != hyst
- || i2c_smbus_read_word_data(new_client, i + 3) != crit
- || i2c_smbus_read_word_data(new_client, i + 4) != min
- || i2c_smbus_read_word_data(new_client, i + 5) != max)
- return -ENODEV;
-
- /* sign bits */
- if (((cur & 0x00f0) != 0xf0 && (cur & 0x00f0) != 0x0)
- || ((hyst & 0x00f0) != 0xf0 && (hyst & 0x00f0) != 0x0)
- || ((crit & 0x00f0) != 0xf0 && (crit & 0x00f0) != 0x0)
- || ((min & 0x00f0) != 0xf0 && (min & 0x00f0) != 0x0)
- || ((max & 0x00f0) != 0xf0 && (max & 0x00f0) != 0x0))
- return -ENODEV;
- /* unused bits */
- if (conf & 0xe0)
+ /* addresses cycling */
+ cur = i2c_smbus_read_word_data(new_client, 0);
+ conf = i2c_smbus_read_byte_data(new_client, 1);
+ hyst = i2c_smbus_read_word_data(new_client, 2);
+ crit = i2c_smbus_read_word_data(new_client, 3);
+ min = i2c_smbus_read_word_data(new_client, 4);
+ max = i2c_smbus_read_word_data(new_client, 5);
+ for (i = 8; i <= 0xff; i += 8) {
+ if (i2c_smbus_read_byte_data(new_client, i + 1) != conf
+ || i2c_smbus_read_word_data(new_client, i + 2) != hyst
+ || i2c_smbus_read_word_data(new_client, i + 3) != crit
+ || i2c_smbus_read_word_data(new_client, i + 4) != min
+ || i2c_smbus_read_word_data(new_client, i + 5) != max)
return -ENODEV;
+ }
- /* 0x06 and 0x07 return the last read value */
- cur = i2c_smbus_read_word_data(new_client, 0);
- if (i2c_smbus_read_word_data(new_client, 6) != cur
- || i2c_smbus_read_word_data(new_client, 7) != cur)
- return -ENODEV;
- hyst = i2c_smbus_read_word_data(new_client, 2);
- if (i2c_smbus_read_word_data(new_client, 6) != hyst
- || i2c_smbus_read_word_data(new_client, 7) != hyst)
- return -ENODEV;
- min = i2c_smbus_read_word_data(new_client, 4);
- if (i2c_smbus_read_word_data(new_client, 6) != min
- || i2c_smbus_read_word_data(new_client, 7) != min)
- return -ENODEV;
+ /* sign bits */
+ if (((cur & 0x00f0) != 0xf0 && (cur & 0x00f0) != 0x0)
+ || ((hyst & 0x00f0) != 0xf0 && (hyst & 0x00f0) != 0x0)
+ || ((crit & 0x00f0) != 0xf0 && (crit & 0x00f0) != 0x0)
+ || ((min & 0x00f0) != 0xf0 && (min & 0x00f0) != 0x0)
+ || ((max & 0x00f0) != 0xf0 && (max & 0x00f0) != 0x0))
+ return -ENODEV;
- }
+ /* unused bits */
+ if (conf & 0xe0)
+ return -ENODEV;
+
+ /* 0x06 and 0x07 return the last read value */
+ cur = i2c_smbus_read_word_data(new_client, 0);
+ if (i2c_smbus_read_word_data(new_client, 6) != cur
+ || i2c_smbus_read_word_data(new_client, 7) != cur)
+ return -ENODEV;
+ hyst = i2c_smbus_read_word_data(new_client, 2);
+ if (i2c_smbus_read_word_data(new_client, 6) != hyst
+ || i2c_smbus_read_word_data(new_client, 7) != hyst)
+ return -ENODEV;
+ min = i2c_smbus_read_word_data(new_client, 4);
+ if (i2c_smbus_read_word_data(new_client, 6) != min
+ || i2c_smbus_read_word_data(new_client, 7) != min)
+ return -ENODEV;
strlcpy(info->type, "lm77", I2C_NAME_SIZE);
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index f7e70163e016..5978291cebb3 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -576,52 +576,34 @@ static int lm78_i2c_detect(struct i2c_client *client, int kind,
if (isa)
mutex_lock(&isa->update_lock);
- if (kind < 0) {
- if ((i2c_smbus_read_byte_data(client, LM78_REG_CONFIG) & 0x80)
- || i2c_smbus_read_byte_data(client, LM78_REG_I2C_ADDR)
- != address)
- goto err_nodev;
-
- /* Explicitly prevent the misdetection of Winbond chips */
- i = i2c_smbus_read_byte_data(client, 0x4f);
- if (i == 0xa3 || i == 0x5c)
- goto err_nodev;
- }
+ if ((i2c_smbus_read_byte_data(client, LM78_REG_CONFIG) & 0x80)
+ || i2c_smbus_read_byte_data(client, LM78_REG_I2C_ADDR) != address)
+ goto err_nodev;
+
+ /* Explicitly prevent the misdetection of Winbond chips */
+ i = i2c_smbus_read_byte_data(client, 0x4f);
+ if (i == 0xa3 || i == 0x5c)
+ goto err_nodev;
/* Determine the chip type. */
- if (kind <= 0) {
- i = i2c_smbus_read_byte_data(client, LM78_REG_CHIPID);
- if (i == 0x00 || i == 0x20 /* LM78 */
- || i == 0x40) /* LM78-J */
- kind = lm78;
- else if ((i & 0xfe) == 0xc0)
- kind = lm79;
- else {
- if (kind == 0)
- dev_warn(&adapter->dev, "Ignoring 'force' "
- "parameter for unknown chip at "
- "adapter %d, address 0x%02x\n",
- i2c_adapter_id(adapter), address);
- goto err_nodev;
- }
+ i = i2c_smbus_read_byte_data(client, LM78_REG_CHIPID);
+ if (i == 0x00 || i == 0x20 /* LM78 */
+ || i == 0x40) /* LM78-J */
+ client_name = "lm78";
+ else if ((i & 0xfe) == 0xc0)
+ client_name = "lm79";
+ else
+ goto err_nodev;
- if (lm78_alias_detect(client, i)) {
- dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
- "be the same as ISA device\n", address);
- goto err_nodev;
- }
+ if (lm78_alias_detect(client, i)) {
+ dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
+ "be the same as ISA device\n", address);
+ goto err_nodev;
}
if (isa)
mutex_unlock(&isa->update_lock);
- switch (kind) {
- case lm79:
- client_name = "lm79";
- break;
- default:
- client_name = "lm78";
- }
strlcpy(info->type, client_name, I2C_NAME_SIZE);
return 0;
diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c
index e59e2d1f080c..08b03e6ed0b7 100644
--- a/drivers/hwmon/lm83.c
+++ b/drivers/hwmon/lm83.c
@@ -1,7 +1,7 @@
/*
* lm83.c - Part of lm_sensors, Linux kernel modules for hardware
* monitoring
- * Copyright (C) 2003-2008 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2003-2009 Jean Delvare <khali@linux-fr.org>
*
* Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is
* a sensor chip made by National Semiconductor. It reports up to four
@@ -295,69 +295,40 @@ static int lm83_detect(struct i2c_client *new_client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = new_client->adapter;
- const char *name = "";
+ const char *name;
+ u8 man_id, chip_id;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- /* Now we do the detection and identification. A negative kind
- * means that the driver was loaded with no force parameter
- * (default), so we must both detect and identify the chip
- * (actually there is only one possible kind of chip for now, LM83).
- * A zero kind means that the driver was loaded with the force
- * parameter, the detection step shall be skipped. A positive kind
- * means that the driver was loaded with the force parameter and a
- * given kind of chip is requested, so both the detection and the
- * identification steps are skipped. */
-
- /* Default to an LM83 if forced */
- if (kind == 0)
- kind = lm83;
-
- if (kind < 0) { /* detection */
- if (((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS1)
- & 0xA8) != 0x00) ||
- ((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS2)
- & 0x48) != 0x00) ||
- ((i2c_smbus_read_byte_data(new_client, LM83_REG_R_CONFIG)
- & 0x41) != 0x00)) {
- dev_dbg(&adapter->dev,
- "LM83 detection failed at 0x%02x.\n",
- new_client->addr);
- return -ENODEV;
- }
+ /* Detection */
+ if ((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS1) & 0xA8) ||
+ (i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS2) & 0x48) ||
+ (i2c_smbus_read_byte_data(new_client, LM83_REG_R_CONFIG) & 0x41)) {
+ dev_dbg(&adapter->dev, "LM83 detection failed at 0x%02x\n",
+ new_client->addr);
+ return -ENODEV;
}
- if (kind <= 0) { /* identification */
- u8 man_id, chip_id;
-
- man_id = i2c_smbus_read_byte_data(new_client,
- LM83_REG_R_MAN_ID);
- chip_id = i2c_smbus_read_byte_data(new_client,
- LM83_REG_R_CHIP_ID);
-
- if (man_id == 0x01) { /* National Semiconductor */
- if (chip_id == 0x03) {
- kind = lm83;
- } else
- if (chip_id == 0x01) {
- kind = lm82;
- }
- }
-
- if (kind <= 0) { /* identification failed */
- dev_info(&adapter->dev,
- "Unsupported chip (man_id=0x%02X, "
- "chip_id=0x%02X).\n", man_id, chip_id);
- return -ENODEV;
- }
- }
+ /* Identification */
+ man_id = i2c_smbus_read_byte_data(new_client, LM83_REG_R_MAN_ID);
+ if (man_id != 0x01) /* National Semiconductor */
+ return -ENODEV;
- if (kind == lm83) {
+ chip_id = i2c_smbus_read_byte_data(new_client, LM83_REG_R_CHIP_ID);
+ switch (chip_id) {
+ case 0x03:
name = "lm83";
- } else
- if (kind == lm82) {
+ break;
+ case 0x01:
name = "lm82";
+ break;
+ default:
+ /* identification failed */
+ dev_info(&adapter->dev,
+ "Unsupported chip (man_id=0x%02X, chip_id=0x%02X)\n",
+ man_id, chip_id);
+ return -ENODEV;
}
strlcpy(info->type, name, I2C_NAME_SIZE);
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index 6c53d987de10..44f9bc21afbe 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -5,7 +5,7 @@
Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com>
Copyright (c) 2003 Margit Schubert-While <margitsw@t-online.de>
Copyright (c) 2004 Justin Thiessen <jthiessen@penguincomputing.com>
- Copyright (C) 2007, 2008 Jean Delvare <khali@linux-fr.org>
+ Copyright (C) 2007- 2009 Jean Delvare <khali@linux-fr.org>
Chip details at <http://www.national.com/ds/LM/LM85.pdf>
@@ -1162,107 +1162,80 @@ static int lm85_detect(struct i2c_client *client, int kind,
struct i2c_adapter *adapter = client->adapter;
int address = client->addr;
const char *type_name;
+ int company, verstep;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
/* We need to be able to do byte I/O */
return -ENODEV;
}
- /* If auto-detecting, determine the chip type */
- if (kind < 0) {
- int company = lm85_read_value(client, LM85_REG_COMPANY);
- int verstep = lm85_read_value(client, LM85_REG_VERSTEP);
-
- dev_dbg(&adapter->dev, "Detecting device at 0x%02x with "
- "COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
- address, company, verstep);
-
- /* All supported chips have the version in common */
- if ((verstep & LM85_VERSTEP_VMASK) != LM85_VERSTEP_GENERIC &&
- (verstep & LM85_VERSTEP_VMASK) != LM85_VERSTEP_GENERIC2) {
- dev_dbg(&adapter->dev, "Autodetection failed: "
- "unsupported version\n");
- return -ENODEV;
- }
- kind = any_chip;
-
- /* Now, refine the detection */
- if (company == LM85_COMPANY_NATIONAL) {
- switch (verstep) {
- case LM85_VERSTEP_LM85C:
- kind = lm85c;
- break;
- case LM85_VERSTEP_LM85B:
- kind = lm85b;
- break;
- case LM85_VERSTEP_LM96000_1:
- case LM85_VERSTEP_LM96000_2:
- /* Check for Winbond WPCD377I */
- if (lm85_is_fake(client)) {
- dev_dbg(&adapter->dev,
- "Found Winbond WPCD377I, "
- "ignoring\n");
- return -ENODEV;
- }
- break;
- }
- } else if (company == LM85_COMPANY_ANALOG_DEV) {
- switch (verstep) {
- case LM85_VERSTEP_ADM1027:
- kind = adm1027;
- break;
- case LM85_VERSTEP_ADT7463:
- case LM85_VERSTEP_ADT7463C:
- kind = adt7463;
- break;
- case LM85_VERSTEP_ADT7468_1:
- case LM85_VERSTEP_ADT7468_2:
- kind = adt7468;
- break;
- }
- } else if (company == LM85_COMPANY_SMSC) {
- switch (verstep) {
- case LM85_VERSTEP_EMC6D100_A0:
- case LM85_VERSTEP_EMC6D100_A1:
- /* Note: we can't tell a '100 from a '101 */
- kind = emc6d100;
- break;
- case LM85_VERSTEP_EMC6D102:
- kind = emc6d102;
- break;
+ /* Determine the chip type */
+ company = lm85_read_value(client, LM85_REG_COMPANY);
+ verstep = lm85_read_value(client, LM85_REG_VERSTEP);
+
+ dev_dbg(&adapter->dev, "Detecting device at 0x%02x with "
+ "COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
+ address, company, verstep);
+
+ /* All supported chips have the version in common */
+ if ((verstep & LM85_VERSTEP_VMASK) != LM85_VERSTEP_GENERIC &&
+ (verstep & LM85_VERSTEP_VMASK) != LM85_VERSTEP_GENERIC2) {
+ dev_dbg(&adapter->dev,
+ "Autodetection failed: unsupported version\n");
+ return -ENODEV;
+ }
+ type_name = "lm85";
+
+ /* Now, refine the detection */
+ if (company == LM85_COMPANY_NATIONAL) {
+ switch (verstep) {
+ case LM85_VERSTEP_LM85C:
+ type_name = "lm85c";
+ break;
+ case LM85_VERSTEP_LM85B:
+ type_name = "lm85b";
+ break;
+ case LM85_VERSTEP_LM96000_1:
+ case LM85_VERSTEP_LM96000_2:
+ /* Check for Winbond WPCD377I */
+ if (lm85_is_fake(client)) {
+ dev_dbg(&adapter->dev,
+ "Found Winbond WPCD377I, ignoring\n");
+ return -ENODEV;
}
- } else {
- dev_dbg(&adapter->dev, "Autodetection failed: "
- "unknown vendor\n");
- return -ENODEV;
+ break;
+ }
+ } else if (company == LM85_COMPANY_ANALOG_DEV) {
+ switch (verstep) {
+ case LM85_VERSTEP_ADM1027:
+ type_name = "adm1027";
+ break;
+ case LM85_VERSTEP_ADT7463:
+ case LM85_VERSTEP_ADT7463C:
+ type_name = "adt7463";
+ break;
+ case LM85_VERSTEP_ADT7468_1:
+ case LM85_VERSTEP_ADT7468_2:
+ type_name = "adt7468";
+ break;
}
+ } else if (company == LM85_COMPANY_SMSC) {
+ switch (verstep) {
+ case LM85_VERSTEP_EMC6D100_A0:
+ case LM85_VERSTEP_EMC6D100_A1:
+ /* Note: we can't tell a '100 from a '101 */
+ type_name = "emc6d100";
+ break;
+ case LM85_VERSTEP_EMC6D102:
+ type_name = "emc6d102";
+ break;
+ }
+ } else {
+ dev_dbg(&adapter->dev,
+ "Autodetection failed: unknown vendor\n");
+ return -ENODEV;
}
- switch (kind) {
- case lm85b:
- type_name = "lm85b";
- break;
- case lm85c:
- type_name = "lm85c";
- break;
- case adm1027:
- type_name = "adm1027";
- break;
- case adt7463:
- type_name = "adt7463";
- break;
- case adt7468:
- type_name = "adt7468";
- break;
- case emc6d100:
- type_name = "emc6d100";
- break;
- case emc6d102:
- type_name = "emc6d102";
- break;
- default:
- type_name = "lm85";
- }
strlcpy(info->type, type_name, I2C_NAME_SIZE);
return 0;
diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c
index 2e4a3cea95f7..4929b1815eee 100644
--- a/drivers/hwmon/lm87.c
+++ b/drivers/hwmon/lm87.c
@@ -666,37 +666,32 @@ static int lm87_detect(struct i2c_client *new_client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = new_client->adapter;
- static const char *names[] = { "lm87", "adm1024" };
+ const char *name;
+ u8 cid, rev;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- /* Default to an LM87 if forced */
- if (kind == 0)
- kind = lm87;
+ if (lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80)
+ return -ENODEV;
/* Now, we do the remaining detection. */
- if (kind < 0) {
- u8 cid = lm87_read_value(new_client, LM87_REG_COMPANY_ID);
- u8 rev = lm87_read_value(new_client, LM87_REG_REVISION);
-
- if (cid == 0x02 /* National Semiconductor */
- && (rev >= 0x01 && rev <= 0x08))
- kind = lm87;
- else if (cid == 0x41 /* Analog Devices */
- && (rev & 0xf0) == 0x10)
- kind = adm1024;
-
- if (kind < 0
- || (lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80)) {
- dev_dbg(&adapter->dev,
- "LM87 detection failed at 0x%02x.\n",
- new_client->addr);
- return -ENODEV;
- }
+ cid = lm87_read_value(new_client, LM87_REG_COMPANY_ID);
+ rev = lm87_read_value(new_client, LM87_REG_REVISION);
+
+ if (cid == 0x02 /* National Semiconductor */
+ && (rev >= 0x01 && rev <= 0x08))
+ name = "lm87";
+ else if (cid == 0x41 /* Analog Devices */
+ && (rev & 0xf0) == 0x10)
+ name = "adm1024";
+ else {
+ dev_dbg(&adapter->dev, "LM87 detection failed at 0x%02x\n",
+ new_client->addr);
+ return -ENODEV;
}
- strlcpy(info->type, names[kind - 1], I2C_NAME_SIZE);
+ strlcpy(info->type, name, I2C_NAME_SIZE);
return 0;
}
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 1aff7575799d..b7c905f50ed4 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -1,7 +1,7 @@
/*
* lm90.c - Part of lm_sensors, Linux kernel modules for hardware
* monitoring
- * Copyright (C) 2003-2008 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2003-2009 Jean Delvare <khali@linux-fr.org>
*
* Based on the lm83 driver. The LM90 is a sensor chip made by National
* Semiconductor. It reports up to two temperatures (its own plus up to
@@ -661,154 +661,118 @@ static int lm90_detect(struct i2c_client *new_client, int kind,
{
struct i2c_adapter *adapter = new_client->adapter;
int address = new_client->addr;
- const char *name = "";
+ const char *name = NULL;
+ int man_id, chip_id, reg_config1, reg_convrate;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- /*
- * Now we do the remaining detection. A negative kind means that
- * the driver was loaded with no force parameter (default), so we
- * must both detect and identify the chip. A zero kind means that
- * the driver was loaded with the force parameter, the detection
- * step shall be skipped. A positive kind means that the driver
- * was loaded with the force parameter and a given kind of chip is
- * requested, so both the detection and the identification steps
- * are skipped.
- */
-
- /* Default to an LM90 if forced */
- if (kind == 0)
- kind = lm90;
-
- if (kind < 0) { /* detection and identification */
- int man_id, chip_id, reg_config1, reg_convrate;
-
- if ((man_id = i2c_smbus_read_byte_data(new_client,
+ /* detection and identification */
+ if ((man_id = i2c_smbus_read_byte_data(new_client,
LM90_REG_R_MAN_ID)) < 0
- || (chip_id = i2c_smbus_read_byte_data(new_client,
+ || (chip_id = i2c_smbus_read_byte_data(new_client,
LM90_REG_R_CHIP_ID)) < 0
- || (reg_config1 = i2c_smbus_read_byte_data(new_client,
+ || (reg_config1 = i2c_smbus_read_byte_data(new_client,
LM90_REG_R_CONFIG1)) < 0
- || (reg_convrate = i2c_smbus_read_byte_data(new_client,
+ || (reg_convrate = i2c_smbus_read_byte_data(new_client,
LM90_REG_R_CONVRATE)) < 0)
+ return -ENODEV;
+
+ if ((address == 0x4C || address == 0x4D)
+ && man_id == 0x01) { /* National Semiconductor */
+ int reg_config2;
+
+ reg_config2 = i2c_smbus_read_byte_data(new_client,
+ LM90_REG_R_CONFIG2);
+ if (reg_config2 < 0)
return -ENODEV;
-
- if ((address == 0x4C || address == 0x4D)
- && man_id == 0x01) { /* National Semiconductor */
- int reg_config2;
-
- if ((reg_config2 = i2c_smbus_read_byte_data(new_client,
- LM90_REG_R_CONFIG2)) < 0)
- return -ENODEV;
-
- if ((reg_config1 & 0x2A) == 0x00
- && (reg_config2 & 0xF8) == 0x00
- && reg_convrate <= 0x09) {
- if (address == 0x4C
- && (chip_id & 0xF0) == 0x20) { /* LM90 */
- kind = lm90;
- } else
- if ((chip_id & 0xF0) == 0x30) { /* LM89/LM99 */
- kind = lm99;
- dev_info(&adapter->dev,
- "Assuming LM99 chip at "
- "0x%02x\n", address);
- dev_info(&adapter->dev,
- "If it is an LM89, pass "
- "force_lm86=%d,0x%02x when "
- "loading the lm90 driver\n",
- i2c_adapter_id(adapter),
- address);
- } else
- if (address == 0x4C
- && (chip_id & 0xF0) == 0x10) { /* LM86 */
- kind = lm86;
- }
- }
- } else
- if ((address == 0x4C || address == 0x4D)
- && man_id == 0x41) { /* Analog Devices */
- if ((chip_id & 0xF0) == 0x40 /* ADM1032 */
- && (reg_config1 & 0x3F) == 0x00
- && reg_convrate <= 0x0A) {
- kind = adm1032;
- } else
- if (chip_id == 0x51 /* ADT7461 */
- && (reg_config1 & 0x1B) == 0x00
- && reg_convrate <= 0x0A) {
- kind = adt7461;
- }
- } else
- if (man_id == 0x4D) { /* Maxim */
- /*
- * The MAX6657, MAX6658 and MAX6659 do NOT have a
- * chip_id register. Reading from that address will
- * return the last read value, which in our case is
- * those of the man_id register. Likewise, the config1
- * register seems to lack a low nibble, so the value
- * will be those of the previous read, so in our case
- * those of the man_id register.
- */
- if (chip_id == man_id
- && (address == 0x4C || address == 0x4D)
- && (reg_config1 & 0x1F) == (man_id & 0x0F)
- && reg_convrate <= 0x09) {
- kind = max6657;
+
+ if ((reg_config1 & 0x2A) == 0x00
+ && (reg_config2 & 0xF8) == 0x00
+ && reg_convrate <= 0x09) {
+ if (address == 0x4C
+ && (chip_id & 0xF0) == 0x20) { /* LM90 */
+ name = "lm90";
} else
- /* The chip_id register of the MAX6680 and MAX6681
- * holds the revision of the chip.
- * the lowest bit of the config1 register is unused
- * and should return zero when read, so should the
- * second to last bit of config1 (software reset)
- */
- if (chip_id == 0x01
- && (reg_config1 & 0x03) == 0x00
- && reg_convrate <= 0x07) {
- kind = max6680;
+ if ((chip_id & 0xF0) == 0x30) { /* LM89/LM99 */
+ name = "lm99";
+ dev_info(&adapter->dev,
+ "Assuming LM99 chip at 0x%02x\n",
+ address);
+ dev_info(&adapter->dev,
+ "If it is an LM89, instantiate it "
+ "with the new_device sysfs "
+ "interface\n");
} else
- /* The chip_id register of the MAX6646/6647/6649
- * holds the revision of the chip.
- * The lowest 6 bits of the config1 register are
- * unused and should return zero when read.
- */
- if (chip_id == 0x59
- && (reg_config1 & 0x3f) == 0x00
- && reg_convrate <= 0x07) {
- kind = max6646;
+ if (address == 0x4C
+ && (chip_id & 0xF0) == 0x10) { /* LM86 */
+ name = "lm86";
}
}
-
- if (kind <= 0) { /* identification failed */
- dev_dbg(&adapter->dev,
- "Unsupported chip at 0x%02x (man_id=0x%02X, "
- "chip_id=0x%02X)\n", address, man_id, chip_id);
- return -ENODEV;
+ } else
+ if ((address == 0x4C || address == 0x4D)
+ && man_id == 0x41) { /* Analog Devices */
+ if ((chip_id & 0xF0) == 0x40 /* ADM1032 */
+ && (reg_config1 & 0x3F) == 0x00
+ && reg_convrate <= 0x0A) {
+ name = "adm1032";
+ /* The ADM1032 supports PEC, but only if combined
+ transactions are not used. */
+ if (i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_BYTE))
+ info->flags |= I2C_CLIENT_PEC;
+ } else
+ if (chip_id == 0x51 /* ADT7461 */
+ && (reg_config1 & 0x1B) == 0x00
+ && reg_convrate <= 0x0A) {
+ name = "adt7461";
+ }
+ } else
+ if (man_id == 0x4D) { /* Maxim */
+ /*
+ * The MAX6657, MAX6658 and MAX6659 do NOT have a chip_id
+ * register. Reading from that address will return the last
+ * read value, which in our case is those of the man_id
+ * register. Likewise, the config1 register seems to lack a
+ * low nibble, so the value will be those of the previous
+ * read, so in our case those of the man_id register.
+ */
+ if (chip_id == man_id
+ && (address == 0x4C || address == 0x4D)
+ && (reg_config1 & 0x1F) == (man_id & 0x0F)
+ && reg_convrate <= 0x09) {
+ name = "max6657";
+ } else
+ /*
+ * The chip_id register of the MAX6680 and MAX6681 holds the
+ * revision of the chip. The lowest bit of the config1 register
+ * is unused and should return zero when read, so should the
+ * second to last bit of config1 (software reset).
+ */
+ if (chip_id == 0x01
+ && (reg_config1 & 0x03) == 0x00
+ && reg_convrate <= 0x07) {
+ name = "max6680";
+ } else
+ /*
+ * The chip_id register of the MAX6646/6647/6649 holds the
+ * revision of the chip. The lowest 6 bits of the config1
+ * register are unused and should return zero when read.
+ */
+ if (chip_id == 0x59
+ && (reg_config1 & 0x3f) == 0x00
+ && reg_convrate <= 0x07) {
+ name = "max6646";
}
}
- /* Fill the i2c board info */
- if (kind == lm90) {
- name = "lm90";
- } else if (kind == adm1032) {
- name = "adm1032";
- /* The ADM1032 supports PEC, but only if combined
- transactions are not used. */
- if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
- info->flags |= I2C_CLIENT_PEC;
- } else if (kind == lm99) {
- name = "lm99";
- } else if (kind == lm86) {
- name = "lm86";
- } else if (kind == max6657) {
- name = "max6657";
- } else if (kind == max6680) {
- name = "max6680";
- } else if (kind == adt7461) {
- name = "adt7461";
- } else if (kind == max6646) {
- name = "max6646";
+ if (!name) { /* identification failed */
+ dev_dbg(&adapter->dev,
+ "Unsupported chip at 0x%02x (man_id=0x%02X, "
+ "chip_id=0x%02X)\n", address, man_id, chip_id);
+ return -ENODEV;
}
+
strlcpy(info->type, name, I2C_NAME_SIZE);
return 0;
diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c
index b2e00c5a7eec..47ac698709dc 100644
--- a/drivers/hwmon/lm92.c
+++ b/drivers/hwmon/lm92.c
@@ -323,31 +323,22 @@ static int lm92_detect(struct i2c_client *new_client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = new_client->adapter;
+ u8 config;
+ u16 man_id;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
| I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
- /* A negative kind means that the driver was loaded with no force
- parameter (default), so we must identify the chip. */
- if (kind < 0) {
- u8 config = i2c_smbus_read_byte_data(new_client,
- LM92_REG_CONFIG);
- u16 man_id = i2c_smbus_read_word_data(new_client,
- LM92_REG_MAN_ID);
-
- if ((config & 0xe0) == 0x00
- && man_id == 0x0180) {
- pr_info("lm92: Found National Semiconductor LM92 chip\n");
- kind = lm92;
- } else
- if (max6635_check(new_client)) {
- pr_info("lm92: Found Maxim MAX6635 chip\n");
- kind = lm92; /* No separate prefix */
- }
- else
- return -ENODEV;
- }
+ config = i2c_smbus_read_byte_data(new_client, LM92_REG_CONFIG);
+ man_id = i2c_smbus_read_word_data(new_client, LM92_REG_MAN_ID);
+
+ if ((config & 0xe0) == 0x00 && man_id == 0x0180)
+ pr_info("lm92: Found National Semiconductor LM92 chip\n");
+ else if (max6635_check(new_client))
+ pr_info("lm92: Found Maxim MAX6635 chip\n");
+ else
+ return -ENODEV;
strlcpy(info->type, "lm92", I2C_NAME_SIZE);
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
index fc36cadf36fb..495e7ce6f8a1 100644
--- a/drivers/hwmon/lm93.c
+++ b/drivers/hwmon/lm93.c
@@ -2505,34 +2505,24 @@ static int lm93_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
+ int mfr, ver;
if (!i2c_check_functionality(adapter, LM93_SMBUS_FUNC_MIN))
return -ENODEV;
/* detection */
- if (kind < 0) {
- int mfr = lm93_read_byte(client, LM93_REG_MFR_ID);
-
- if (mfr != 0x01) {
- dev_dbg(&adapter->dev,"detect failed, "
- "bad manufacturer id 0x%02x!\n", mfr);
- return -ENODEV;
- }
+ mfr = lm93_read_byte(client, LM93_REG_MFR_ID);
+ if (mfr != 0x01) {
+ dev_dbg(&adapter->dev,
+ "detect failed, bad manufacturer id 0x%02x!\n", mfr);
+ return -ENODEV;
}
- if (kind <= 0) {
- int ver = lm93_read_byte(client, LM93_REG_VER);
-
- if ((ver == LM93_MFR_ID) || (ver == LM93_MFR_ID_PROTOTYPE)) {
- kind = lm93;
- } else {
- dev_dbg(&adapter->dev,"detect failed, "
- "bad version id 0x%02x!\n", ver);
- if (kind == 0)
- dev_dbg(&adapter->dev,
- "(ignored 'force' parameter)\n");
- return -ENODEV;
- }
+ ver = lm93_read_byte(client, LM93_REG_VER);
+ if (ver != LM93_MFR_ID && ver != LM93_MFR_ID_PROTOTYPE) {
+ dev_dbg(&adapter->dev,
+ "detect failed, bad version id 0x%02x!\n", ver);
+ return -ENODEV;
}
strlcpy(info->type, "lm93", I2C_NAME_SIZE);
diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c
index e34f9e402a2c..906b896cf1d0 100644
--- a/drivers/hwmon/lm95241.c
+++ b/drivers/hwmon/lm95241.c
@@ -315,51 +315,23 @@ static int lm95241_detect(struct i2c_client *new_client, int kind,
{
struct i2c_adapter *adapter = new_client->adapter;
int address = new_client->addr;
- const char *name = "";
+ const char *name;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- /*
- * Now we do the remaining detection. A negative kind means that
- * the driver was loaded with no force parameter (default), so we
- * must both detect and identify the chip. A zero kind means that
- * the driver was loaded with the force parameter, the detection
- * step shall be skipped. A positive kind means that the driver
- * was loaded with the force parameter and a given kind of chip is
- * requested, so both the detection and the identification steps
- * are skipped.
- */
- if (kind < 0) { /* detection */
- if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID)
- != MANUFACTURER_ID)
- || (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID)
- < DEFAULT_REVISION)) {
- dev_dbg(&adapter->dev,
- "LM95241 detection failed at 0x%02x.\n",
- address);
- return -ENODEV;
- }
- }
-
- if (kind <= 0) { /* identification */
- if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID)
- == MANUFACTURER_ID)
- && (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID)
- >= DEFAULT_REVISION)) {
-
- kind = lm95241;
-
- if (kind <= 0) { /* identification failed */
- dev_info(&adapter->dev, "Unsupported chip\n");
- return -ENODEV;
- }
- }
+ if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID)
+ == MANUFACTURER_ID)
+ && (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID)
+ >= DEFAULT_REVISION)) {
+ name = "lm95241";
+ } else {
+ dev_dbg(&adapter->dev, "LM95241 detection failed at 0x%02x\n",
+ address);
+ return -ENODEV;
}
/* Fill the i2c board info */
- if (kind == lm95241)
- name = "lm95241";
strlcpy(info->type, name, I2C_NAME_SIZE);
return 0;
}
diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c
index 7897754f3a5c..7fcf5ff89e7f 100644
--- a/drivers/hwmon/max1619.c
+++ b/drivers/hwmon/max1619.c
@@ -226,58 +226,34 @@ static const struct attribute_group max1619_group = {
*/
/* Return 0 if detection is successful, -ENODEV otherwise */
-static int max1619_detect(struct i2c_client *new_client, int kind,
+static int max1619_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
- struct i2c_adapter *adapter = new_client->adapter;
- u8 reg_config=0, reg_convrate=0, reg_status=0;
+ struct i2c_adapter *adapter = client->adapter;
+ u8 reg_config, reg_convrate, reg_status, man_id, chip_id;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- /*
- * Now we do the remaining detection. A negative kind means that
- * the driver was loaded with no force parameter (default), so we
- * must both detect and identify the chip. A zero kind means that
- * the driver was loaded with the force parameter, the detection
- * step shall be skipped. A positive kind means that the driver
- * was loaded with the force parameter and a given kind of chip is
- * requested, so both the detection and the identification steps
- * are skipped.
- */
- if (kind < 0) { /* detection */
- reg_config = i2c_smbus_read_byte_data(new_client,
- MAX1619_REG_R_CONFIG);
- reg_convrate = i2c_smbus_read_byte_data(new_client,
- MAX1619_REG_R_CONVRATE);
- reg_status = i2c_smbus_read_byte_data(new_client,
- MAX1619_REG_R_STATUS);
- if ((reg_config & 0x03) != 0x00
- || reg_convrate > 0x07 || (reg_status & 0x61 ) !=0x00) {
- dev_dbg(&adapter->dev,
- "MAX1619 detection failed at 0x%02x.\n",
- new_client->addr);
- return -ENODEV;
- }
+ /* detection */
+ reg_config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG);
+ reg_convrate = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONVRATE);
+ reg_status = i2c_smbus_read_byte_data(client, MAX1619_REG_R_STATUS);
+ if ((reg_config & 0x03) != 0x00
+ || reg_convrate > 0x07 || (reg_status & 0x61) != 0x00) {
+ dev_dbg(&adapter->dev, "MAX1619 detection failed at 0x%02x\n",
+ client->addr);
+ return -ENODEV;
}
- if (kind <= 0) { /* identification */
- u8 man_id, chip_id;
-
- man_id = i2c_smbus_read_byte_data(new_client,
- MAX1619_REG_R_MAN_ID);
- chip_id = i2c_smbus_read_byte_data(new_client,
- MAX1619_REG_R_CHIP_ID);
-
- if ((man_id == 0x4D) && (chip_id == 0x04))
- kind = max1619;
-
- if (kind <= 0) { /* identification failed */
- dev_info(&adapter->dev,
- "Unsupported chip (man_id=0x%02X, "
- "chip_id=0x%02X).\n", man_id, chip_id);
- return -ENODEV;
- }
+ /* identification */
+ man_id = i2c_smbus_read_byte_data(client, MAX1619_REG_R_MAN_ID);
+ chip_id = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CHIP_ID);
+ if (man_id != 0x4D || chip_id != 0x04) {
+ dev_info(&adapter->dev,
+ "Unsupported chip (man_id=0x%02X, chip_id=0x%02X).\n",
+ man_id, chip_id);
+ return -ENODEV;
}
strlcpy(info->type, "max1619", I2C_NAME_SIZE);
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c
index 58f66be61b1f..1da561e0cb37 100644
--- a/drivers/hwmon/max6650.c
+++ b/drivers/hwmon/max6650.c
@@ -534,7 +534,7 @@ static int max6650_detect(struct i2c_client *client, int kind,
struct i2c_adapter *adapter = client->adapter;
int address = client->addr;
- dev_dbg(&adapter->dev, "max6650_detect called, kind = %d\n", kind);
+ dev_dbg(&adapter->dev, "max6650_detect called\n");
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_dbg(&adapter->dev, "max6650: I2C bus doesn't support "
@@ -542,23 +542,7 @@ static int max6650_detect(struct i2c_client *client, int kind,
return -ENODEV;
}
- /*
- * Now we do the remaining detection. A negative kind means that
- * the driver was loaded with no force parameter (default), so we
- * must both detect and identify the chip (actually there is only
- * one possible kind of chip for now, max6650). A zero kind means that
- * the driver was loaded with the force parameter, the detection
- * step shall be skipped. A positive kind means that the driver
- * was loaded with the force parameter and a given kind of chip is
- * requested, so both the detection and the identification steps
- * are skipped.
- *
- * Currently I can find no way to distinguish between a MAX6650 and
- * a MAX6651. This driver has only been tried on the former.
- */
-
- if ((kind < 0) &&
- ( (i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG) & 0xC0)
+ if (((i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG) & 0xC0)
||(i2c_smbus_read_byte_data(client, MAX6650_REG_GPIO_STAT) & 0xE0)
||(i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN) & 0xE0)
||(i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM) & 0xE0)
diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c
new file mode 100644
index 000000000000..fafb1935950c
--- /dev/null
+++ b/drivers/hwmon/mc13783-adc.c
@@ -0,0 +1,224 @@
+/*
+ * Driver for the Freescale Semiconductor MC13783 adc.
+ *
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2009 Sascha Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/mfd/mc13783-private.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/hwmon.h>
+#include <linux/init.h>
+#include <linux/err.h>
+
+#define MC13783_ADC_NAME "mc13783-adc"
+
+struct mc13783_adc_priv {
+ struct mc13783 *mc13783;
+ struct device *hwmon_dev;
+};
+
+static ssize_t mc13783_adc_show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ return sprintf(buf, "mc13783_adc\n");
+}
+
+static unsigned int mc13783_adc_read(struct device *dev,
+ struct device_attribute *devattr)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ unsigned int channel = attr->index;
+ unsigned int sample[4];
+
+ mc13783_adc_do_conversion(priv->mc13783, MC13783_ADC_MODE_MULT_CHAN,
+ channel, sample);
+
+ channel &= 0x7;
+
+ return (sample[channel % 4] >> (channel > 3 ? 14 : 2)) & 0x3ff;
+}
+
+static ssize_t mc13783_adc_read_bp(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ unsigned res = mc13783_adc_read(dev, devattr);
+
+ /*
+ * BP (channel 2) reports with offset 2.4V to the actual value to fit
+ * the input range of the ADC. unit = 2.25mV = 9/4 mV.
+ */
+ res = DIV_ROUND_CLOSEST(res * 9, 4) + 2400;
+
+ return sprintf(buf, "%u\n", res);
+}
+
+static ssize_t mc13783_adc_read_gp(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ unsigned res = mc13783_adc_read(dev, devattr);
+
+ /*
+ * input range is [0, 2.3V], res has 10 bits, so each bit
+ * is worth 9/4 mV.
+ */
+ res = DIV_ROUND_CLOSEST(res * 9, 4);
+
+ return sprintf(buf, "%u\n", res);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, mc13783_adc_show_name, NULL);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, mc13783_adc_read_bp, NULL, 2);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, mc13783_adc_read_gp, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, mc13783_adc_read_gp, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, mc13783_adc_read_gp, NULL, 7);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, mc13783_adc_read_gp, NULL, 8);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, mc13783_adc_read_gp, NULL, 9);
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, mc13783_adc_read_gp, NULL, 10);
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, mc13783_adc_read_gp, NULL, 11);
+static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, mc13783_adc_read_gp, NULL, 12);
+static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, mc13783_adc_read_gp, NULL, 13);
+static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, mc13783_adc_read_gp, NULL, 14);
+static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, mc13783_adc_read_gp, NULL, 15);
+
+static struct attribute *mc13783_attr[] =
+{
+ &dev_attr_name.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in8_input.dev_attr.attr,
+ &sensor_dev_attr_in9_input.dev_attr.attr,
+ &sensor_dev_attr_in10_input.dev_attr.attr,
+ &sensor_dev_attr_in11_input.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group mc13783_group = {
+ .attrs = mc13783_attr,
+};
+
+/* last four channels may be occupied by the touchscreen */
+static struct attribute *mc13783_attr_ts[] =
+{
+ &sensor_dev_attr_in12_input.dev_attr.attr,
+ &sensor_dev_attr_in13_input.dev_attr.attr,
+ &sensor_dev_attr_in14_input.dev_attr.attr,
+ &sensor_dev_attr_in15_input.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group mc13783_group_ts = {
+ .attrs = mc13783_attr_ts,
+};
+
+static int __init mc13783_adc_probe(struct platform_device *pdev)
+{
+ struct mc13783_adc_priv *priv;
+ int ret;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->mc13783 = dev_get_drvdata(pdev->dev.parent);
+
+ platform_set_drvdata(pdev, priv);
+
+ /* Register sysfs hooks */
+ ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group);
+ if (ret)
+ goto out_err_create1;
+
+ if (!(priv->mc13783->flags & MC13783_USE_TOUCHSCREEN))
+ ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_ts);
+ if (ret)
+ goto out_err_create2;
+
+ priv->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(priv->hwmon_dev)) {
+ ret = PTR_ERR(priv->hwmon_dev);
+ dev_err(&pdev->dev,
+ "hwmon_device_register failed with %d.\n", ret);
+ goto out_err_register;
+ }
+
+
+ return 0;
+
+out_err_register:
+
+ if (!(priv->mc13783->flags & MC13783_USE_TOUCHSCREEN))
+ sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
+out_err_create2:
+
+ sysfs_remove_group(&pdev->dev.kobj, &mc13783_group);
+out_err_create1:
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(priv);
+
+ return ret;
+}
+
+static int __devexit mc13783_adc_remove(struct platform_device *pdev)
+{
+ struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
+
+ hwmon_device_unregister(priv->hwmon_dev);
+
+ if (!(priv->mc13783->flags & MC13783_USE_TOUCHSCREEN))
+ sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
+
+ sysfs_remove_group(&pdev->dev.kobj, &mc13783_group);
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(priv);
+
+ return 0;
+}
+
+static struct platform_driver mc13783_adc_driver = {
+ .remove = __devexit_p(mc13783_adc_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = MC13783_ADC_NAME,
+ },
+};
+
+static int __init mc13783_adc_init(void)
+{
+ return platform_driver_probe(&mc13783_adc_driver, mc13783_adc_probe);
+}
+
+static void __exit mc13783_adc_exit(void)
+{
+ platform_driver_unregister(&mc13783_adc_driver);
+}
+
+module_init(mc13783_adc_init);
+module_exit(mc13783_adc_exit);
+
+MODULE_DESCRIPTION("MC13783 ADC driver");
+MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" MC13783_ADC_NAME);
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
index 8bb5cb532d4d..4d88c045781c 100644
--- a/drivers/hwmon/smsc47m192.c
+++ b/drivers/hwmon/smsc47m192.c
@@ -491,24 +491,22 @@ static int smsc47m192_detect(struct i2c_client *client, int kind,
return -ENODEV;
/* Detection criteria from sensors_detect script */
- if (kind < 0) {
- if (i2c_smbus_read_byte_data(client,
+ version = i2c_smbus_read_byte_data(client, SMSC47M192_REG_VERSION);
+ if (i2c_smbus_read_byte_data(client,
SMSC47M192_REG_COMPANY_ID) == 0x55
- && ((version = i2c_smbus_read_byte_data(client,
- SMSC47M192_REG_VERSION)) & 0xf0) == 0x20
- && (i2c_smbus_read_byte_data(client,
+ && (version & 0xf0) == 0x20
+ && (i2c_smbus_read_byte_data(client,
SMSC47M192_REG_VID) & 0x70) == 0x00
- && (i2c_smbus_read_byte_data(client,
+ && (i2c_smbus_read_byte_data(client,
SMSC47M192_REG_VID4) & 0xfe) == 0x80) {
- dev_info(&adapter->dev,
- "found SMSC47M192 or compatible, "
- "version 2, stepping A%d\n", version & 0x0f);
- } else {
- dev_dbg(&adapter->dev,
- "SMSC47M192 detection failed at 0x%02x\n",
- client->addr);
- return -ENODEV;
- }
+ dev_info(&adapter->dev,
+ "found SMSC47M192 or compatible, "
+ "version 2, stepping A%d\n", version & 0x0f);
+ } else {
+ dev_dbg(&adapter->dev,
+ "SMSC47M192 detection failed at 0x%02x\n",
+ client->addr);
+ return -ENODEV;
}
strlcpy(info->type, "smsc47m192", I2C_NAME_SIZE);
diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c
index 7d97431e132f..4b793849c738 100644
--- a/drivers/hwmon/thmc50.c
+++ b/drivers/hwmon/thmc50.c
@@ -36,7 +36,11 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_2(thmc50, adm1022);
-I2C_CLIENT_MODULE_PARM(adm1022_temp3, "List of adapter,address pairs "
+
+static unsigned short adm1022_temp3[16];
+static unsigned int adm1022_temp3_num;
+module_param_array(adm1022_temp3, ushort, &adm1022_temp3_num, 0);
+MODULE_PARM_DESC(adm1022_temp3, "List of adapter,address pairs "
"to enable 3rd temperature (ADM1022 only)");
/* Many THMC50 constants specified below */
@@ -289,7 +293,6 @@ static int thmc50_detect(struct i2c_client *client, int kind,
unsigned revision;
unsigned config;
struct i2c_adapter *adapter = client->adapter;
- int err = 0;
const char *type_name;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
@@ -301,31 +304,13 @@ static int thmc50_detect(struct i2c_client *client, int kind,
pr_debug("thmc50: Probing for THMC50 at 0x%2X on bus %d\n",
client->addr, i2c_adapter_id(client->adapter));
- /* Now, we do the remaining detection. */
company = i2c_smbus_read_byte_data(client, THMC50_REG_COMPANY_ID);
revision = i2c_smbus_read_byte_data(client, THMC50_REG_DIE_CODE);
config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
+ if (revision < 0xc0 || (config & 0x10))
+ return -ENODEV;
- if (kind == 0)
- kind = thmc50;
- else if (kind < 0) {
- err = -ENODEV;
- if (revision >= 0xc0 && ((config & 0x10) == 0)) {
- if (company == 0x49) {
- kind = thmc50;
- err = 0;
- } else if (company == 0x41) {
- kind = adm1022;
- err = 0;
- }
- }
- }
- if (err == -ENODEV) {
- pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n");
- return err;
- }
-
- if (kind == adm1022) {
+ if (company == 0x41) {
int id = i2c_adapter_id(client->adapter);
int i;
@@ -340,9 +325,13 @@ static int thmc50_detect(struct i2c_client *client, int kind,
config);
break;
}
- } else {
+ } else if (company == 0x49) {
type_name = "thmc50";
+ } else {
+ pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n");
+ return -ENODEV;
}
+
pr_debug("thmc50: Detected %s (version %x, revision %x)\n",
type_name, (revision >> 4) - 0xc, revision & 0xf);
diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c
index 7b34f2cd08bb..ee9673467c4a 100644
--- a/drivers/hwmon/tmp401.c
+++ b/drivers/hwmon/tmp401.c
@@ -488,46 +488,43 @@ static void tmp401_init_client(struct i2c_client *client)
i2c_smbus_write_byte_data(client, TMP401_CONFIG_WRITE, config);
}
-static int tmp401_detect(struct i2c_client *client, int kind,
+static int tmp401_detect(struct i2c_client *client, int _kind,
struct i2c_board_info *info)
{
+ enum chips kind;
struct i2c_adapter *adapter = client->adapter;
+ u8 reg;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
/* Detect and identify the chip */
- if (kind <= 0) {
- u8 reg;
-
- reg = i2c_smbus_read_byte_data(client,
- TMP401_MANUFACTURER_ID_REG);
- if (reg != TMP401_MANUFACTURER_ID)
- return -ENODEV;
-
- reg = i2c_smbus_read_byte_data(client, TMP401_DEVICE_ID_REG);
-
- switch (reg) {
- case TMP401_DEVICE_ID:
- kind = tmp401;
- break;
- case TMP411_DEVICE_ID:
- kind = tmp411;
- break;
- default:
- return -ENODEV;
- }
+ reg = i2c_smbus_read_byte_data(client, TMP401_MANUFACTURER_ID_REG);
+ if (reg != TMP401_MANUFACTURER_ID)
+ return -ENODEV;
- reg = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
- if (reg & 0x1b)
- return -ENODEV;
+ reg = i2c_smbus_read_byte_data(client, TMP401_DEVICE_ID_REG);
- reg = i2c_smbus_read_byte_data(client,
- TMP401_CONVERSION_RATE_READ);
- /* Datasheet says: 0x1-0x6 */
- if (reg > 15)
- return -ENODEV;
+ switch (reg) {
+ case TMP401_DEVICE_ID:
+ kind = tmp401;
+ break;
+ case TMP411_DEVICE_ID:
+ kind = tmp411;
+ break;
+ default:
+ return -ENODEV;
}
+
+ reg = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
+ if (reg & 0x1b)
+ return -ENODEV;
+
+ reg = i2c_smbus_read_byte_data(client, TMP401_CONVERSION_RATE_READ);
+ /* Datasheet says: 0x1-0x6 */
+ if (reg > 15)
+ return -ENODEV;
+
strlcpy(info->type, tmp401_id[kind - 1].name, I2C_NAME_SIZE);
return 0;
diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c
index 20924343431b..bb5464a289ca 100644
--- a/drivers/hwmon/tmp421.c
+++ b/drivers/hwmon/tmp421.c
@@ -223,39 +223,36 @@ static int tmp421_init_client(struct i2c_client *client)
return 0;
}
-static int tmp421_detect(struct i2c_client *client, int kind,
+static int tmp421_detect(struct i2c_client *client, int _kind,
struct i2c_board_info *info)
{
+ enum chips kind;
struct i2c_adapter *adapter = client->adapter;
const char *names[] = { "TMP421", "TMP422", "TMP423" };
+ u8 reg;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- if (kind <= 0) {
- u8 reg;
-
- reg = i2c_smbus_read_byte_data(client,
- TMP421_MANUFACTURER_ID_REG);
- if (reg != TMP421_MANUFACTURER_ID)
- return -ENODEV;
-
- reg = i2c_smbus_read_byte_data(client,
- TMP421_DEVICE_ID_REG);
- switch (reg) {
- case TMP421_DEVICE_ID:
- kind = tmp421;
- break;
- case TMP422_DEVICE_ID:
- kind = tmp422;
- break;
- case TMP423_DEVICE_ID:
- kind = tmp423;
- break;
- default:
- return -ENODEV;
- }
+ reg = i2c_smbus_read_byte_data(client, TMP421_MANUFACTURER_ID_REG);
+ if (reg != TMP421_MANUFACTURER_ID)
+ return -ENODEV;
+
+ reg = i2c_smbus_read_byte_data(client, TMP421_DEVICE_ID_REG);
+ switch (reg) {
+ case TMP421_DEVICE_ID:
+ kind = tmp421;
+ break;
+ case TMP422_DEVICE_ID:
+ kind = tmp422;
+ break;
+ case TMP423_DEVICE_ID:
+ kind = tmp423;
+ break;
+ default:
+ return -ENODEV;
}
+
strlcpy(info->type, tmp421_id[kind - 1].name, I2C_NAME_SIZE);
dev_info(&adapter->dev, "Detected TI %s chip at 0x%02x\n",
names[kind - 1], client->addr);
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 2be28ac4ede0..b257c7223733 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -59,10 +59,11 @@ static struct platform_device *pdev;
#define DRVNAME "w83627hf"
enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
-static u16 force_addr;
-module_param(force_addr, ushort, 0);
-MODULE_PARM_DESC(force_addr,
- "Initialize the base address of the sensors");
+struct w83627hf_sio_data {
+ enum chips type;
+ int sioaddr;
+};
+
static u8 force_i2c = 0x1f;
module_param(force_i2c, byte, 0);
MODULE_PARM_DESC(force_i2c,
@@ -77,9 +78,7 @@ module_param(force_id, ushort, 0);
MODULE_PARM_DESC(force_id, "Override the detected device ID");
/* modified from kernel/include/traps.c */
-static int REG; /* The register to read/write */
#define DEV 0x07 /* Register: Logical device select */
-static int VAL; /* The value to read/write */
/* logical device numbers for superio_select (below) */
#define W83627HF_LD_FDC 0x00
@@ -109,37 +108,37 @@ static int VAL; /* The value to read/write */
#define W83687THF_VID_DATA 0xF1 /* w83687thf only */
static inline void
-superio_outb(int reg, int val)
+superio_outb(struct w83627hf_sio_data *sio, int reg, int val)
{
- outb(reg, REG);
- outb(val, VAL);
+ outb(reg, sio->sioaddr);
+ outb(val, sio->sioaddr + 1);
}
static inline int
-superio_inb(int reg)
+superio_inb(struct w83627hf_sio_data *sio, int reg)
{
- outb(reg, REG);
- return inb(VAL);
+ outb(reg, sio->sioaddr);
+ return inb(sio->sioaddr + 1);
}
static inline void
-superio_select(int ld)
+superio_select(struct w83627hf_sio_data *sio, int ld)
{
- outb(DEV, REG);
- outb(ld, VAL);
+ outb(DEV, sio->sioaddr);
+ outb(ld, sio->sioaddr + 1);
}
static inline void
-superio_enter(void)
+superio_enter(struct w83627hf_sio_data *sio)
{
- outb(0x87, REG);
- outb(0x87, REG);
+ outb(0x87, sio->sioaddr);
+ outb(0x87, sio->sioaddr);
}
static inline void
-superio_exit(void)
+superio_exit(struct w83627hf_sio_data *sio)
{
- outb(0xAA, REG);
+ outb(0xAA, sio->sioaddr);
}
#define W627_DEVID 0x52
@@ -380,10 +379,6 @@ struct w83627hf_data {
u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */
};
-struct w83627hf_sio_data {
- enum chips type;
-};
-
static int w83627hf_probe(struct platform_device *pdev);
static int __devexit w83627hf_remove(struct platform_device *pdev);
@@ -1140,11 +1135,8 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
"W83687THF",
};
- REG = sioaddr;
- VAL = sioaddr + 1;
-
- superio_enter();
- val = force_id ? force_id : superio_inb(DEVID);
+ superio_enter(sio_data);
+ val = force_id ? force_id : superio_inb(sio_data, DEVID);
switch (val) {
case W627_DEVID:
sio_data->type = w83627hf;
@@ -1168,16 +1160,9 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
goto exit;
}
- superio_select(W83627HF_LD_HWM);
- force_addr &= WINB_ALIGNMENT;
- if (force_addr) {
- printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
- force_addr);
- superio_outb(WINB_BASE_REG, force_addr >> 8);
- superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
- }
- val = (superio_inb(WINB_BASE_REG) << 8) |
- superio_inb(WINB_BASE_REG + 1);
+ superio_select(sio_data, W83627HF_LD_HWM);
+ val = (superio_inb(sio_data, WINB_BASE_REG) << 8) |
+ superio_inb(sio_data, WINB_BASE_REG + 1);
*addr = val & WINB_ALIGNMENT;
if (*addr == 0) {
printk(KERN_WARNING DRVNAME ": Base address not set, "
@@ -1185,18 +1170,19 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
goto exit;
}
- val = superio_inb(WINB_ACT_REG);
+ val = superio_inb(sio_data, WINB_ACT_REG);
if (!(val & 0x01)) {
printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
- superio_outb(WINB_ACT_REG, val | 0x01);
+ superio_outb(sio_data, WINB_ACT_REG, val | 0x01);
}
err = 0;
+ sio_data->sioaddr = sioaddr;
pr_info(DRVNAME ": Found %s chip at %#x\n",
names[sio_data->type], *addr);
exit:
- superio_exit();
+ superio_exit(sio_data);
return err;
}
@@ -1511,20 +1497,21 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
{
+ struct w83627hf_sio_data *sio_data = pdev->dev.platform_data;
int res = 0xff, sel;
- superio_enter();
- superio_select(W83627HF_LD_GPIO5);
+ superio_enter(sio_data);
+ superio_select(sio_data, W83627HF_LD_GPIO5);
/* Make sure these GPIO pins are enabled */
- if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
+ if (!(superio_inb(sio_data, W83627THF_GPIO5_EN) & (1<<3))) {
dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
goto exit;
}
/* Make sure the pins are configured for input
There must be at least five (VRM 9), and possibly 6 (VRM 10) */
- sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
+ sel = superio_inb(sio_data, W83627THF_GPIO5_IOSR) & 0x3f;
if ((sel & 0x1f) != 0x1f) {
dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
"function\n");
@@ -1532,37 +1519,38 @@ static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
}
dev_info(&pdev->dev, "Reading VID from GPIO5\n");
- res = superio_inb(W83627THF_GPIO5_DR) & sel;
+ res = superio_inb(sio_data, W83627THF_GPIO5_DR) & sel;
exit:
- superio_exit();
+ superio_exit(sio_data);
return res;
}
static int __devinit w83687thf_read_vid(struct platform_device *pdev)
{
+ struct w83627hf_sio_data *sio_data = pdev->dev.platform_data;
int res = 0xff;
- superio_enter();
- superio_select(W83627HF_LD_HWM);
+ superio_enter(sio_data);
+ superio_select(sio_data, W83627HF_LD_HWM);
/* Make sure these GPIO pins are enabled */
- if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
+ if (!(superio_inb(sio_data, W83687THF_VID_EN) & (1 << 2))) {
dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
goto exit;
}
/* Make sure the pins are configured for input */
- if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
+ if (!(superio_inb(sio_data, W83687THF_VID_CFG) & (1 << 4))) {
dev_dbg(&pdev->dev, "VID configured as output, "
"no VID function\n");
goto exit;
}
- res = superio_inb(W83687THF_VID_DATA) & 0x3f;
+ res = superio_inb(sio_data, W83687THF_VID_DATA) & 0x3f;
exit:
- superio_exit();
+ superio_exit(sio_data);
return res;
}
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index d27ed1bac002..7ab7967da0a0 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -1054,11 +1054,11 @@ static int
w83781d_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
- int val1 = 0, val2;
+ int val1, val2;
struct w83781d_data *isa = w83781d_data_if_isa();
struct i2c_adapter *adapter = client->adapter;
int address = client->addr;
- const char *client_name = "";
+ const char *client_name;
enum vendor { winbond, asus } vendid;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -1070,98 +1070,73 @@ w83781d_detect(struct i2c_client *client, int kind,
if (isa)
mutex_lock(&isa->update_lock);
- /* The w8378?d may be stuck in some other bank than bank 0. This may
- make reading other information impossible. Specify a force=... or
- force_*=... parameter, and the Winbond will be reset to the right
- bank. */
- if (kind < 0) {
- if (i2c_smbus_read_byte_data
- (client, W83781D_REG_CONFIG) & 0x80) {
- dev_dbg(&adapter->dev, "Detection of w83781d chip "
- "failed at step 3\n");
- goto err_nodev;
- }
- val1 = i2c_smbus_read_byte_data(client, W83781D_REG_BANK);
- val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
- /* Check for Winbond or Asus ID if in bank 0 */
- if ((!(val1 & 0x07)) &&
- (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3))
- || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) {
- dev_dbg(&adapter->dev, "Detection of w83781d chip "
- "failed at step 4\n");
+ if (i2c_smbus_read_byte_data(client, W83781D_REG_CONFIG) & 0x80) {
+ dev_dbg(&adapter->dev,
+ "Detection of w83781d chip failed at step 3\n");
+ goto err_nodev;
+ }
+
+ val1 = i2c_smbus_read_byte_data(client, W83781D_REG_BANK);
+ val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
+ /* Check for Winbond or Asus ID if in bank 0 */
+ if (!(val1 & 0x07) &&
+ ((!(val1 & 0x80) && val2 != 0xa3 && val2 != 0xc3) ||
+ ( (val1 & 0x80) && val2 != 0x5c && val2 != 0x12))) {
+ dev_dbg(&adapter->dev,
+ "Detection of w83781d chip failed at step 4\n");
+ goto err_nodev;
+ }
+ /* If Winbond SMBus, check address at 0x48.
+ Asus doesn't support, except for as99127f rev.2 */
+ if ((!(val1 & 0x80) && val2 == 0xa3) ||
+ ( (val1 & 0x80) && val2 == 0x5c)) {
+ if (i2c_smbus_read_byte_data(client, W83781D_REG_I2C_ADDR)
+ != address) {
+ dev_dbg(&adapter->dev,
+ "Detection of w83781d chip failed at step 5\n");
goto err_nodev;
}
- /* If Winbond SMBus, check address at 0x48.
- Asus doesn't support, except for as99127f rev.2 */
- if ((!(val1 & 0x80) && (val2 == 0xa3)) ||
- ((val1 & 0x80) && (val2 == 0x5c))) {
- if (i2c_smbus_read_byte_data
- (client, W83781D_REG_I2C_ADDR) != address) {
- dev_dbg(&adapter->dev, "Detection of w83781d "
- "chip failed at step 5\n");
- goto err_nodev;
- }
- }
}
- /* We have either had a force parameter, or we have already detected the
- Winbond. Put it now into bank 0 and Vendor ID High Byte */
+ /* Put it now into bank 0 and Vendor ID High Byte */
i2c_smbus_write_byte_data(client, W83781D_REG_BANK,
(i2c_smbus_read_byte_data(client, W83781D_REG_BANK)
& 0x78) | 0x80);
- /* Determine the chip type. */
- if (kind <= 0) {
- /* get vendor ID */
- val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
- if (val2 == 0x5c)
- vendid = winbond;
- else if (val2 == 0x12)
- vendid = asus;
- else {
- dev_dbg(&adapter->dev, "w83781d chip vendor is "
- "neither Winbond nor Asus\n");
- goto err_nodev;
- }
-
- val1 = i2c_smbus_read_byte_data(client, W83781D_REG_WCHIPID);
- if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
- kind = w83781d;
- else if (val1 == 0x30 && vendid == winbond)
- kind = w83782d;
- else if (val1 == 0x40 && vendid == winbond && address == 0x2d)
- kind = w83783s;
- else if (val1 == 0x31)
- kind = as99127f;
- else {
- if (kind == 0)
- dev_warn(&adapter->dev, "Ignoring 'force' "
- "parameter for unknown chip at "
- "address 0x%02x\n", address);
- goto err_nodev;
- }
-
- if ((kind == w83781d || kind == w83782d)
- && w83781d_alias_detect(client, val1)) {
- dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
- "be the same as ISA device\n", address);
- goto err_nodev;
- }
+ /* Get the vendor ID */
+ val2 = i2c_smbus_read_byte_data(client, W83781D_REG_CHIPMAN);
+ if (val2 == 0x5c)
+ vendid = winbond;
+ else if (val2 == 0x12)
+ vendid = asus;
+ else {
+ dev_dbg(&adapter->dev,
+ "w83781d chip vendor is neither Winbond nor Asus\n");
+ goto err_nodev;
}
- if (isa)
- mutex_unlock(&isa->update_lock);
-
- if (kind == w83781d) {
+ /* Determine the chip type. */
+ val1 = i2c_smbus_read_byte_data(client, W83781D_REG_WCHIPID);
+ if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
client_name = "w83781d";
- } else if (kind == w83782d) {
+ else if (val1 == 0x30 && vendid == winbond)
client_name = "w83782d";
- } else if (kind == w83783s) {
+ else if (val1 == 0x40 && vendid == winbond && address == 0x2d)
client_name = "w83783s";
- } else if (kind == as99127f) {
+ else if (val1 == 0x31)
client_name = "as99127f";
+ else
+ goto err_nodev;
+
+ if (val1 <= 0x30 && w83781d_alias_detect(client, val1)) {
+ dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
+ "be the same as ISA device\n", address);
+ goto err_nodev;
}
+ if (isa)
+ mutex_unlock(&isa->update_lock);
+
strlcpy(info->type, client_name, I2C_NAME_SIZE);
return 0;
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index 97851c5ba3a3..0410bf12c521 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -1270,56 +1270,32 @@ static int w83791d_detect(struct i2c_client *client, int kind,
return -ENODEV;
}
- /* The w83791d may be stuck in some other bank than bank 0. This may
- make reading other information impossible. Specify a force=...
- parameter, and the Winbond will be reset to the right bank. */
- if (kind < 0) {
- if (w83791d_read(client, W83791D_REG_CONFIG) & 0x80) {
- return -ENODEV;
- }
- val1 = w83791d_read(client, W83791D_REG_BANK);
- val2 = w83791d_read(client, W83791D_REG_CHIPMAN);
- /* Check for Winbond ID if in bank 0 */
- if (!(val1 & 0x07)) {
- /* yes it is Bank0 */
- if (((!(val1 & 0x80)) && (val2 != 0xa3)) ||
- ((val1 & 0x80) && (val2 != 0x5c))) {
- return -ENODEV;
- }
- }
- /* If Winbond chip, address of chip and W83791D_REG_I2C_ADDR
- should match */
- if (w83791d_read(client, W83791D_REG_I2C_ADDR) != address) {
+ if (w83791d_read(client, W83791D_REG_CONFIG) & 0x80)
+ return -ENODEV;
+
+ val1 = w83791d_read(client, W83791D_REG_BANK);
+ val2 = w83791d_read(client, W83791D_REG_CHIPMAN);
+ /* Check for Winbond ID if in bank 0 */
+ if (!(val1 & 0x07)) {
+ if ((!(val1 & 0x80) && val2 != 0xa3) ||
+ ( (val1 & 0x80) && val2 != 0x5c)) {
return -ENODEV;
}
}
+ /* If Winbond chip, address of chip and W83791D_REG_I2C_ADDR
+ should match */
+ if (w83791d_read(client, W83791D_REG_I2C_ADDR) != address)
+ return -ENODEV;
- /* We either have a force parameter or we have reason to
- believe it is a Winbond chip. Either way, we want bank 0 and
- Vendor ID high byte */
+ /* We want bank 0 and Vendor ID high byte */
val1 = w83791d_read(client, W83791D_REG_BANK) & 0x78;
w83791d_write(client, W83791D_REG_BANK, val1 | 0x80);
/* Verify it is a Winbond w83791d */
- if (kind <= 0) {
- /* get vendor ID */
- val2 = w83791d_read(client, W83791D_REG_CHIPMAN);
- if (val2 != 0x5c) { /* the vendor is NOT Winbond */
- return -ENODEV;
- }
- val1 = w83791d_read(client, W83791D_REG_WCHIPID);
- if (val1 == 0x71) {
- kind = w83791d;
- } else {
- if (kind == 0)
- dev_warn(&adapter->dev,
- "w83791d: Ignoring 'force' parameter "
- "for unknown chip at adapter %d, "
- "address 0x%02x\n",
- i2c_adapter_id(adapter), address);
- return -ENODEV;
- }
- }
+ val1 = w83791d_read(client, W83791D_REG_WCHIPID);
+ val2 = w83791d_read(client, W83791D_REG_CHIPMAN);
+ if (val1 != 0x71 || val2 != 0x5c)
+ return -ENODEV;
strlcpy(info->type, "w83791d", I2C_NAME_SIZE);
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
index 2be16194ddf3..38978851333f 100644
--- a/drivers/hwmon/w83792d.c
+++ b/drivers/hwmon/w83792d.c
@@ -1273,58 +1273,33 @@ w83792d_detect(struct i2c_client *client, int kind, struct i2c_board_info *info)
return -ENODEV;
}
- /* The w83792d may be stuck in some other bank than bank 0. This may
- make reading other information impossible. Specify a force=... or
- force_*=... parameter, and the Winbond will be reset to the right
- bank. */
- if (kind < 0) {
- if (w83792d_read_value(client, W83792D_REG_CONFIG) & 0x80) {
- return -ENODEV;
- }
- val1 = w83792d_read_value(client, W83792D_REG_BANK);
- val2 = w83792d_read_value(client, W83792D_REG_CHIPMAN);
- /* Check for Winbond ID if in bank 0 */
- if (!(val1 & 0x07)) { /* is Bank0 */
- if (((!(val1 & 0x80)) && (val2 != 0xa3)) ||
- ((val1 & 0x80) && (val2 != 0x5c))) {
- return -ENODEV;
- }
- }
- /* If Winbond chip, address of chip and W83792D_REG_I2C_ADDR
- should match */
- if (w83792d_read_value(client,
- W83792D_REG_I2C_ADDR) != address) {
+ if (w83792d_read_value(client, W83792D_REG_CONFIG) & 0x80)
+ return -ENODEV;
+
+ val1 = w83792d_read_value(client, W83792D_REG_BANK);
+ val2 = w83792d_read_value(client, W83792D_REG_CHIPMAN);
+ /* Check for Winbond ID if in bank 0 */
+ if (!(val1 & 0x07)) { /* is Bank0 */
+ if ((!(val1 & 0x80) && val2 != 0xa3) ||
+ ( (val1 & 0x80) && val2 != 0x5c))
return -ENODEV;
- }
}
+ /* If Winbond chip, address of chip and W83792D_REG_I2C_ADDR
+ should match */
+ if (w83792d_read_value(client, W83792D_REG_I2C_ADDR) != address)
+ return -ENODEV;
- /* We have either had a force parameter, or we have already detected the
- Winbond. Put it now into bank 0 and Vendor ID High Byte */
+ /* Put it now into bank 0 and Vendor ID High Byte */
w83792d_write_value(client,
W83792D_REG_BANK,
(w83792d_read_value(client,
W83792D_REG_BANK) & 0x78) | 0x80);
/* Determine the chip type. */
- if (kind <= 0) {
- /* get vendor ID */
- val2 = w83792d_read_value(client, W83792D_REG_CHIPMAN);
- if (val2 != 0x5c) { /* the vendor is NOT Winbond */
- return -ENODEV;
- }
- val1 = w83792d_read_value(client, W83792D_REG_WCHIPID);
- if (val1 == 0x7a) {
- kind = w83792d;
- } else {
- if (kind == 0)
- dev_warn(&adapter->dev,
- "w83792d: Ignoring 'force' parameter for"
- " unknown chip at adapter %d, address"
- " 0x%02x\n", i2c_adapter_id(adapter),
- address);
- return -ENODEV;
- }
- }
+ val1 = w83792d_read_value(client, W83792D_REG_WCHIPID);
+ val2 = w83792d_read_value(client, W83792D_REG_CHIPMAN);
+ if (val1 != 0x7a || val2 != 0x5c)
+ return -ENODEV;
strlcpy(info->type, "w83792d", I2C_NAME_SIZE);
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index 47dd398f7258..80a2191bf127 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -1164,7 +1164,7 @@ ERROR_SC_0:
static int w83793_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
- u8 tmp, bank;
+ u8 tmp, bank, chip_id;
struct i2c_adapter *adapter = client->adapter;
unsigned short address = client->addr;
@@ -1174,44 +1174,27 @@ static int w83793_detect(struct i2c_client *client, int kind,
bank = i2c_smbus_read_byte_data(client, W83793_REG_BANKSEL);
- if (kind < 0) {
- tmp = bank & 0x80 ? 0x5c : 0xa3;
- /* Check Winbond vendor ID */
- if (tmp != i2c_smbus_read_byte_data(client,
- W83793_REG_VENDORID)) {
- pr_debug("w83793: Detection failed at check "
- "vendor id\n");
- return -ENODEV;
- }
-
- /* If Winbond chip, address of chip and W83793_REG_I2C_ADDR
- should match */
- if ((bank & 0x07) == 0
- && i2c_smbus_read_byte_data(client, W83793_REG_I2C_ADDR) !=
- (address << 1)) {
- pr_debug("w83793: Detection failed at check "
- "i2c addr\n");
- return -ENODEV;
- }
-
+ tmp = bank & 0x80 ? 0x5c : 0xa3;
+ /* Check Winbond vendor ID */
+ if (tmp != i2c_smbus_read_byte_data(client, W83793_REG_VENDORID)) {
+ pr_debug("w83793: Detection failed at check vendor id\n");
+ return -ENODEV;
}
- /* We have either had a force parameter, or we have already detected the
- Winbond. Determine the chip type now */
-
- if (kind <= 0) {
- if (0x7b == i2c_smbus_read_byte_data(client,
- W83793_REG_CHIPID)) {
- kind = w83793;
- } else {
- if (kind == 0)
- dev_warn(&adapter->dev, "w83793: Ignoring "
- "'force' parameter for unknown chip "
- "at address 0x%02x\n", address);
- return -ENODEV;
- }
+ /* If Winbond chip, address of chip and W83793_REG_I2C_ADDR
+ should match */
+ if ((bank & 0x07) == 0
+ && i2c_smbus_read_byte_data(client, W83793_REG_I2C_ADDR) !=
+ (address << 1)) {
+ pr_debug("w83793: Detection failed at check i2c addr\n");
+ return -ENODEV;
}
+ /* Determine the chip type now */
+ chip_id = i2c_smbus_read_byte_data(client, W83793_REG_CHIPID);
+ if (chip_id != 0x7b)
+ return -ENODEV;
+
strlcpy(info->type, "w83793", I2C_NAME_SIZE);
return 0;
diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c
index ea295b9fc4f4..9b6c4c10fba7 100644
--- a/drivers/hwmon/w83l785ts.c
+++ b/drivers/hwmon/w83l785ts.c
@@ -1,7 +1,7 @@
/*
* w83l785ts.c - Part of lm_sensors, Linux kernel modules for hardware
* monitoring
- * Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2003-2009 Jean Delvare <khali@linux-fr.org>
*
* Inspired from the lm83 driver. The W83L785TS-S is a sensor chip made
* by Winbond. It reports a single external temperature with a 1 deg
@@ -146,60 +146,36 @@ static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL, 1);
*/
/* Return 0 if detection is successful, -ENODEV otherwise */
-static int w83l785ts_detect(struct i2c_client *new_client, int kind,
+static int w83l785ts_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
- struct i2c_adapter *adapter = new_client->adapter;
+ struct i2c_adapter *adapter = client->adapter;
+ u16 man_id;
+ u8 chip_id;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- /*
- * Now we do the remaining detection. A negative kind means that
- * the driver was loaded with no force parameter (default), so we
- * must both detect and identify the chip (actually there is only
- * one possible kind of chip for now, W83L785TS-S). A zero kind means
- * that the driver was loaded with the force parameter, the detection
- * step shall be skipped. A positive kind means that the driver
- * was loaded with the force parameter and a given kind of chip is
- * requested, so both the detection and the identification steps
- * are skipped.
- */
- if (kind < 0) { /* detection */
- if (((w83l785ts_read_value(new_client,
- W83L785TS_REG_CONFIG, 0) & 0x80) != 0x00)
- || ((w83l785ts_read_value(new_client,
- W83L785TS_REG_TYPE, 0) & 0xFC) != 0x00)) {
- dev_dbg(&adapter->dev,
- "W83L785TS-S detection failed at 0x%02x.\n",
- new_client->addr);
- return -ENODEV;
- }
+ /* detection */
+ if ((w83l785ts_read_value(client, W83L785TS_REG_CONFIG, 0) & 0x80)
+ || (w83l785ts_read_value(client, W83L785TS_REG_TYPE, 0) & 0xFC)) {
+ dev_dbg(&adapter->dev,
+ "W83L785TS-S detection failed at 0x%02x\n",
+ client->addr);
+ return -ENODEV;
}
- if (kind <= 0) { /* identification */
- u16 man_id;
- u8 chip_id;
-
- man_id = (w83l785ts_read_value(new_client,
- W83L785TS_REG_MAN_ID1, 0) << 8) +
- w83l785ts_read_value(new_client,
- W83L785TS_REG_MAN_ID2, 0);
- chip_id = w83l785ts_read_value(new_client,
- W83L785TS_REG_CHIP_ID, 0);
-
- if (man_id == 0x5CA3) { /* Winbond */
- if (chip_id == 0x70) { /* W83L785TS-S */
- kind = w83l785ts;
- }
- }
-
- if (kind <= 0) { /* identification failed */
- dev_info(&adapter->dev,
- "Unsupported chip (man_id=0x%04X, "
- "chip_id=0x%02X).\n", man_id, chip_id);
- return -ENODEV;
- }
+ /* Identification */
+ man_id = (w83l785ts_read_value(client, W83L785TS_REG_MAN_ID1, 0) << 8)
+ + w83l785ts_read_value(client, W83L785TS_REG_MAN_ID2, 0);
+ chip_id = w83l785ts_read_value(client, W83L785TS_REG_CHIP_ID, 0);
+
+ if (man_id != 0x5CA3 /* Winbond */
+ || chip_id != 0x70) { /* W83L785TS-S */
+ dev_dbg(&adapter->dev,
+ "Unsupported chip (man_id=0x%04X, chip_id=0x%02X)\n",
+ man_id, chip_id);
+ return -ENODEV;
}
strlcpy(info->type, "w83l785ts", I2C_NAME_SIZE);
diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c
index badca769f350..27da7d2b15fb 100644
--- a/drivers/hwmon/w83l786ng.c
+++ b/drivers/hwmon/w83l786ng.c
@@ -590,53 +590,31 @@ w83l786ng_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
+ u16 man_id;
+ u8 chip_id;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
return -ENODEV;
}
- /*
- * Now we do the remaining detection. A negative kind means that
- * the driver was loaded with no force parameter (default), so we
- * must both detect and identify the chip (actually there is only
- * one possible kind of chip for now, W83L786NG). A zero kind means
- * that the driver was loaded with the force parameter, the detection
- * step shall be skipped. A positive kind means that the driver
- * was loaded with the force parameter and a given kind of chip is
- * requested, so both the detection and the identification steps
- * are skipped.
- */
- if (kind < 0) { /* detection */
- if (((w83l786ng_read_value(client,
- W83L786NG_REG_CONFIG) & 0x80) != 0x00)) {
- dev_dbg(&adapter->dev,
- "W83L786NG detection failed at 0x%02x.\n",
- client->addr);
- return -ENODEV;
- }
+ /* Detection */
+ if ((w83l786ng_read_value(client, W83L786NG_REG_CONFIG) & 0x80)) {
+ dev_dbg(&adapter->dev, "W83L786NG detection failed at 0x%02x\n",
+ client->addr);
+ return -ENODEV;
}
- if (kind <= 0) { /* identification */
- u16 man_id;
- u8 chip_id;
-
- man_id = (w83l786ng_read_value(client,
- W83L786NG_REG_MAN_ID1) << 8) +
- w83l786ng_read_value(client, W83L786NG_REG_MAN_ID2);
- chip_id = w83l786ng_read_value(client, W83L786NG_REG_CHIP_ID);
-
- if (man_id == 0x5CA3) { /* Winbond */
- if (chip_id == 0x80) { /* W83L786NG */
- kind = w83l786ng;
- }
- }
+ /* Identification */
+ man_id = (w83l786ng_read_value(client, W83L786NG_REG_MAN_ID1) << 8) +
+ w83l786ng_read_value(client, W83L786NG_REG_MAN_ID2);
+ chip_id = w83l786ng_read_value(client, W83L786NG_REG_CHIP_ID);
- if (kind <= 0) { /* identification failed */
- dev_info(&adapter->dev,
- "Unsupported chip (man_id=0x%04X, "
- "chip_id=0x%02X).\n", man_id, chip_id);
- return -ENODEV;
- }
+ if (man_id != 0x5CA3 || /* Winbond */
+ chip_id != 0x80) { /* W83L786NG */
+ dev_dbg(&adapter->dev,
+ "Unsupported chip (man_id=0x%04X, chip_id=0x%02X)\n",
+ man_id, chip_id);
+ return -ENODEV;
}
strlcpy(info->type, "w83l786ng", I2C_NAME_SIZE);
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index d7ece131b4f4..8d8a00e5a30e 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -5,6 +5,7 @@
menuconfig I2C
tristate "I2C support"
depends on HAS_IOMEM
+ select RT_MUTEXES
---help---
I2C (pronounce: I-square-C) is a slow serial bus protocol used in
many micro controller applications and developed by Philips. SMBus,
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 737335ff2b21..5f318ce29770 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -128,7 +128,7 @@ config I2C_PIIX4
ATI SB600
ATI SB700
ATI SB800
- AMD SB900
+ AMD Hudson-2
Serverworks OSB4
Serverworks CSB5
Serverworks CSB6
@@ -640,22 +640,6 @@ config I2C_TINY_USB
This driver can also be built as a module. If so, the module
will be called i2c-tiny-usb.
-comment "Graphics adapter I2C/DDC channel drivers"
- depends on PCI
-
-config I2C_VOODOO3
- tristate "Voodoo 3 (DEPRECATED)"
- depends on PCI
- select I2C_ALGOBIT
- help
- If you say yes to this option, support will be included for the
- Voodoo 3 I2C interface. This driver is deprecated and you should
- use the tdfxfb driver instead, which additionally provides
- framebuffer support.
-
- This driver can also be built as a module. If so, the module
- will be called i2c-voodoo3.
-
comment "Other I2C/SMBus bus drivers"
config I2C_ACORN
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index ff937ac69f5b..302c551977bb 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -61,9 +61,6 @@ obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o
obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o
-# Graphics adapter I2C/DDC channel drivers
-obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
-
# Other I2C/SMBus bus drivers
obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
index d108450df064..8de7d7b87bb0 100644
--- a/drivers/i2c/busses/i2c-ali1535.c
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -138,7 +138,7 @@ static unsigned short ali1535_smba;
Note the differences between kernels with the old PCI BIOS interface and
newer kernels with the real PCI interface. In compat.h some things are
defined to make the transition easier. */
-static int ali1535_setup(struct pci_dev *dev)
+static int __devinit ali1535_setup(struct pci_dev *dev)
{
int retval = -ENODEV;
unsigned char temp;
diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
index d627fceb790b..e7e3205f1286 100644
--- a/drivers/i2c/busses/i2c-ali15x3.c
+++ b/drivers/i2c/busses/i2c-ali15x3.c
@@ -131,7 +131,7 @@ MODULE_PARM_DESC(force_addr,
static struct pci_driver ali15x3_driver;
static unsigned short ali15x3_smba;
-static int ali15x3_setup(struct pci_dev *ALI15X3_dev)
+static int __devinit ali15x3_setup(struct pci_dev *ALI15X3_dev)
{
u16 a;
unsigned char temp;
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index a75c75e77b92..5901707fc66a 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -56,12 +56,6 @@ iic_cook_addr(struct i2c_msg *msg)
if (msg->flags & I2C_M_RD)
addr |= 1;
- /*
- * Read or Write?
- */
- if (msg->flags & I2C_M_REV_DIR_ADDR)
- addr ^= 1;
-
return addr;
}
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index bbab0e166630..ed387ffa4730 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -338,9 +338,6 @@ mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
if (msg->flags & I2C_M_RD)
dir = 1;
- if (msg->flags & I2C_M_REV_DIR_ADDR)
- dir ^= 1;
-
if (msg->flags & I2C_M_TEN) {
drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir;
drv_data->addr2 = (u32)msg->addr & 0xff;
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index d26a972aacaa..1e245e9cad31 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -22,7 +22,7 @@
Intel PIIX4, 440MX
Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100
ATI IXP200, IXP300, IXP400, SB600, SB700, SB800
- AMD SB900
+ AMD Hudson-2
SMSC Victory66
Note: we assume there can only be one device, with one SMBus interface.
@@ -233,9 +233,9 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
unsigned short smba_idx = 0xcd6;
u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en = 0x2c;
- /* SB800 SMBus does not support forcing address */
+ /* SB800 and later SMBus does not support forcing address */
if (force || force_addr) {
- dev_err(&PIIX4_dev->dev, "SB800 SMBus does not support "
+ dev_err(&PIIX4_dev->dev, "SMBus does not support "
"forcing address!\n");
return -EINVAL;
}
@@ -480,7 +480,7 @@ static struct pci_device_id piix4_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_SB900_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
PCI_DEVICE_ID_SERVERWORKS_OSB4) },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index 3c9d71f60187..f63d7816c941 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -49,48 +49,38 @@ static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap,
int rc = 0;
int read = (read_write == I2C_SMBUS_READ);
int addrdir = (addr << 1) | read;
+ int mode, subsize, len;
+ u32 subaddr;
+ u8 *buf;
u8 local[2];
- rc = pmac_i2c_open(bus, 0);
- if (rc)
- return rc;
+ if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE) {
+ mode = pmac_i2c_mode_std;
+ subsize = 0;
+ subaddr = 0;
+ } else {
+ mode = read ? pmac_i2c_mode_combined : pmac_i2c_mode_stdsub;
+ subsize = 1;
+ subaddr = command;
+ }
switch (size) {
case I2C_SMBUS_QUICK:
- rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
- if (rc)
- goto bail;
- rc = pmac_i2c_xfer(bus, addrdir, 0, 0, NULL, 0);
+ buf = NULL;
+ len = 0;
break;
case I2C_SMBUS_BYTE:
- rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
- if (rc)
- goto bail;
- rc = pmac_i2c_xfer(bus, addrdir, 0, 0, &data->byte, 1);
- break;
case I2C_SMBUS_BYTE_DATA:
- rc = pmac_i2c_setmode(bus, read ?
- pmac_i2c_mode_combined :
- pmac_i2c_mode_stdsub);
- if (rc)
- goto bail;
- rc = pmac_i2c_xfer(bus, addrdir, 1, command, &data->byte, 1);
+ buf = &data->byte;
+ len = 1;
break;
case I2C_SMBUS_WORD_DATA:
- rc = pmac_i2c_setmode(bus, read ?
- pmac_i2c_mode_combined :
- pmac_i2c_mode_stdsub);
- if (rc)
- goto bail;
if (!read) {
local[0] = data->word & 0xff;
local[1] = (data->word >> 8) & 0xff;
}
- rc = pmac_i2c_xfer(bus, addrdir, 1, command, local, 2);
- if (rc == 0 && read) {
- data->word = ((u16)local[1]) << 8;
- data->word |= local[0];
- }
+ buf = local;
+ len = 2;
break;
/* Note that these are broken vs. the expected smbus API where
@@ -105,28 +95,44 @@ static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap,
* a repeat start/addr phase (but not stop in between)
*/
case I2C_SMBUS_BLOCK_DATA:
- rc = pmac_i2c_setmode(bus, read ?
- pmac_i2c_mode_combined :
- pmac_i2c_mode_stdsub);
- if (rc)
- goto bail;
- rc = pmac_i2c_xfer(bus, addrdir, 1, command, data->block,
- data->block[0] + 1);
-
+ buf = data->block;
+ len = data->block[0] + 1;
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
- rc = pmac_i2c_setmode(bus, read ?
- pmac_i2c_mode_combined :
- pmac_i2c_mode_stdsub);
- if (rc)
- goto bail;
- rc = pmac_i2c_xfer(bus, addrdir, 1, command,
- &data->block[1], data->block[0]);
+ buf = &data->block[1];
+ len = data->block[0];
break;
default:
- rc = -EINVAL;
+ return -EINVAL;
+ }
+
+ rc = pmac_i2c_open(bus, 0);
+ if (rc) {
+ dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);
+ return rc;
+ }
+
+ rc = pmac_i2c_setmode(bus, mode);
+ if (rc) {
+ dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",
+ mode, rc);
+ goto bail;
+ }
+
+ rc = pmac_i2c_xfer(bus, addrdir, subsize, subaddr, buf, len);
+ if (rc) {
+ dev_err(&adap->dev,
+ "I2C transfer at 0x%02x failed, size %d, err %d\n",
+ addrdir >> 1, size, rc);
+ goto bail;
+ }
+
+ if (size == I2C_SMBUS_WORD_DATA && read) {
+ data->word = ((u16)local[1]) << 8;
+ data->word |= local[0];
}
+
bail:
pmac_i2c_close(bus);
return rc;
@@ -146,20 +152,33 @@ static int i2c_powermac_master_xfer( struct i2c_adapter *adap,
int read;
int addrdir;
+ if (num != 1) {
+ dev_err(&adap->dev,
+ "Multi-message I2C transactions not supported\n");
+ return -EOPNOTSUPP;
+ }
+
if (msgs->flags & I2C_M_TEN)
return -EINVAL;
read = (msgs->flags & I2C_M_RD) != 0;
addrdir = (msgs->addr << 1) | read;
- if (msgs->flags & I2C_M_REV_DIR_ADDR)
- addrdir ^= 1;
rc = pmac_i2c_open(bus, 0);
- if (rc)
+ if (rc) {
+ dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);
return rc;
+ }
rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
- if (rc)
+ if (rc) {
+ dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",
+ pmac_i2c_mode_std, rc);
goto bail;
+ }
rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len);
+ if (rc < 0)
+ dev_err(&adap->dev, "I2C %s 0x%02x failed, err %d\n",
+ addrdir & 1 ? "read from" : "write to", addrdir >> 1,
+ rc);
bail:
pmac_i2c_close(bus);
return rc < 0 ? rc : 1;
diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c
index b4a55d407bf5..8ca6362603b4 100644
--- a/drivers/i2c/busses/i2c-scmi.c
+++ b/drivers/i2c/busses/i2c-scmi.c
@@ -33,6 +33,7 @@ struct acpi_smbus_cmi {
u8 cap_info:1;
u8 cap_read:1;
u8 cap_write:1;
+ struct smbus_methods_t *methods;
};
static const struct smbus_methods_t smbus_methods = {
@@ -41,8 +42,18 @@ static const struct smbus_methods_t smbus_methods = {
.mt_sbw = "_SBW",
};
+/* Some IBM BIOSes omit the leading underscore */
+static const struct smbus_methods_t ibm_smbus_methods = {
+ .mt_info = "SBI_",
+ .mt_sbr = "SBR_",
+ .mt_sbw = "SBW_",
+};
+
+/* The define below will go away in the final version */
+#define ACPI_SMBUS_IBM_HID "SMBUSIBM"
static const struct acpi_device_id acpi_smbus_cmi_ids[] = {
- {"SMBUS01", 0},
+ {"SMBUS01", (kernel_ulong_t)&smbus_methods},
+ {ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods},
{"", 0}
};
@@ -150,11 +161,11 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
if (read_write == I2C_SMBUS_READ) {
protocol |= ACPI_SMBUS_PRTCL_READ;
- method = smbus_methods.mt_sbr;
+ method = smbus_cmi->methods->mt_sbr;
input.count = 3;
} else {
protocol |= ACPI_SMBUS_PRTCL_WRITE;
- method = smbus_methods.mt_sbw;
+ method = smbus_cmi->methods->mt_sbw;
input.count = 5;
}
@@ -290,13 +301,13 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
union acpi_object *obj;
acpi_status status;
- if (!strcmp(name, smbus_methods.mt_info)) {
+ if (!strcmp(name, smbus_cmi->methods->mt_info)) {
status = acpi_evaluate_object(smbus_cmi->handle,
- smbus_methods.mt_info,
+ smbus_cmi->methods->mt_info,
NULL, &buffer);
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO, "Evaluating %s: %i",
- smbus_methods.mt_info, status));
+ smbus_cmi->methods->mt_info, status));
return -EIO;
}
@@ -319,9 +330,9 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
kfree(buffer.pointer);
smbus_cmi->cap_info = 1;
- } else if (!strcmp(name, smbus_methods.mt_sbr))
+ } else if (!strcmp(name, smbus_cmi->methods->mt_sbr))
smbus_cmi->cap_read = 1;
- else if (!strcmp(name, smbus_methods.mt_sbw))
+ else if (!strcmp(name, smbus_cmi->methods->mt_sbw))
smbus_cmi->cap_write = 1;
else
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported CMI method: %s\n",
@@ -349,6 +360,7 @@ static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level,
static int acpi_smbus_cmi_add(struct acpi_device *device)
{
struct acpi_smbus_cmi *smbus_cmi;
+ const struct acpi_device_id *id;
smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL);
if (!smbus_cmi)
@@ -362,6 +374,11 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
smbus_cmi->cap_read = 0;
smbus_cmi->cap_write = 0;
+ for (id = acpi_smbus_cmi_ids; id->id[0]; id++)
+ if (!strcmp(id->id, acpi_device_hid(device)))
+ smbus_cmi->methods =
+ (struct smbus_methods_t *) id->driver_data;
+
acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1,
acpi_smbus_cmi_query_methods, smbus_cmi, NULL);
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
index 139f0c7f12a4..844569f7d8b7 100644
--- a/drivers/i2c/busses/i2c-sis5595.c
+++ b/drivers/i2c/busses/i2c-sis5595.c
@@ -142,7 +142,7 @@ static void sis5595_write(u8 reg, u8 data)
outb(data, sis5595_base + SMB_DAT);
}
-static int sis5595_setup(struct pci_dev *SIS5595_dev)
+static int __devinit sis5595_setup(struct pci_dev *SIS5595_dev)
{
u16 a;
u8 val;
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
index 70ca41e90e58..68cff7af7013 100644
--- a/drivers/i2c/busses/i2c-sis630.c
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -389,7 +389,7 @@ static u32 sis630_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BLOCK_DATA;
}
-static int sis630_setup(struct pci_dev *sis630_dev)
+static int __devinit sis630_setup(struct pci_dev *sis630_dev)
{
unsigned char b;
struct pci_dev *dummy = NULL;
diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c
deleted file mode 100644
index 7663d57833a0..000000000000
--- a/drivers/i2c/busses/i2c-voodoo3.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>,
- Philip Edelbrock <phil@netroedge.com>,
- Ralph Metzler <rjkm@thp.uni-koeln.de>, and
- Mark D. Studebaker <mdsxyz123@yahoo.com>
-
- Based on code written by Ralph Metzler <rjkm@thp.uni-koeln.de> and
- Simon Vogl
-
- This 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.
-*/
-
-/* This interfaces to the I2C bus of the Voodoo3 to gain access to
- the BT869 and possibly other I2C devices. */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <asm/io.h>
-
-/* the only registers we use */
-#define REG 0x78
-#define REG2 0x70
-
-/* bit locations in the register */
-#define DDC_ENAB 0x00040000
-#define DDC_SCL_OUT 0x00080000
-#define DDC_SDA_OUT 0x00100000
-#define DDC_SCL_IN 0x00200000
-#define DDC_SDA_IN 0x00400000
-#define I2C_ENAB 0x00800000
-#define I2C_SCL_OUT 0x01000000
-#define I2C_SDA_OUT 0x02000000
-#define I2C_SCL_IN 0x04000000
-#define I2C_SDA_IN 0x08000000
-
-/* initialization states */
-#define INIT2 0x2
-#define INIT3 0x4
-
-/* delays */
-#define CYCLE_DELAY 10
-#define TIMEOUT (HZ / 2)
-
-
-static void __iomem *ioaddr;
-
-/* The voo GPIO registers don't have individual masks for each bit
- so we always have to read before writing. */
-
-static void bit_vooi2c_setscl(void *data, int val)
-{
- unsigned int r;
- r = readl(ioaddr + REG);
- if (val)
- r |= I2C_SCL_OUT;
- else
- r &= ~I2C_SCL_OUT;
- writel(r, ioaddr + REG);
- readl(ioaddr + REG); /* flush posted write */
-}
-
-static void bit_vooi2c_setsda(void *data, int val)
-{
- unsigned int r;
- r = readl(ioaddr + REG);
- if (val)
- r |= I2C_SDA_OUT;
- else
- r &= ~I2C_SDA_OUT;
- writel(r, ioaddr + REG);
- readl(ioaddr + REG); /* flush posted write */
-}
-
-/* The GPIO pins are open drain, so the pins always remain outputs.
- We rely on the i2c-algo-bit routines to set the pins high before
- reading the input from other chips. */
-
-static int bit_vooi2c_getscl(void *data)
-{
- return (0 != (readl(ioaddr + REG) & I2C_SCL_IN));
-}
-
-static int bit_vooi2c_getsda(void *data)
-{
- return (0 != (readl(ioaddr + REG) & I2C_SDA_IN));
-}
-
-static void bit_vooddc_setscl(void *data, int val)
-{
- unsigned int r;
- r = readl(ioaddr + REG);
- if (val)
- r |= DDC_SCL_OUT;
- else
- r &= ~DDC_SCL_OUT;
- writel(r, ioaddr + REG);
- readl(ioaddr + REG); /* flush posted write */
-}
-
-static void bit_vooddc_setsda(void *data, int val)
-{
- unsigned int r;
- r = readl(ioaddr + REG);
- if (val)
- r |= DDC_SDA_OUT;
- else
- r &= ~DDC_SDA_OUT;
- writel(r, ioaddr + REG);
- readl(ioaddr + REG); /* flush posted write */
-}
-
-static int bit_vooddc_getscl(void *data)
-{
- return (0 != (readl(ioaddr + REG) & DDC_SCL_IN));
-}
-
-static int bit_vooddc_getsda(void *data)
-{
- return (0 != (readl(ioaddr + REG) & DDC_SDA_IN));
-}
-
-static int config_v3(struct pci_dev *dev)
-{
- unsigned long cadr;
-
- /* map Voodoo3 memory */
- cadr = dev->resource[0].start;
- cadr &= PCI_BASE_ADDRESS_MEM_MASK;
- ioaddr = ioremap_nocache(cadr, 0x1000);
- if (ioaddr) {
- writel(0x8160, ioaddr + REG2);
- writel(0xcffc0020, ioaddr + REG);
- dev_info(&dev->dev, "Using Banshee/Voodoo3 I2C device at %p\n", ioaddr);
- return 0;
- }
- return -ENODEV;
-}
-
-static struct i2c_algo_bit_data voo_i2c_bit_data = {
- .setsda = bit_vooi2c_setsda,
- .setscl = bit_vooi2c_setscl,
- .getsda = bit_vooi2c_getsda,
- .getscl = bit_vooi2c_getscl,
- .udelay = CYCLE_DELAY,
- .timeout = TIMEOUT
-};
-
-static struct i2c_adapter voodoo3_i2c_adapter = {
- .owner = THIS_MODULE,
- .name = "I2C Voodoo3/Banshee adapter",
- .algo_data = &voo_i2c_bit_data,
-};
-
-static struct i2c_algo_bit_data voo_ddc_bit_data = {
- .setsda = bit_vooddc_setsda,
- .setscl = bit_vooddc_setscl,
- .getsda = bit_vooddc_getsda,
- .getscl = bit_vooddc_getscl,
- .udelay = CYCLE_DELAY,
- .timeout = TIMEOUT
-};
-
-static struct i2c_adapter voodoo3_ddc_adapter = {
- .owner = THIS_MODULE,
- .class = I2C_CLASS_DDC,
- .name = "DDC Voodoo3/Banshee adapter",
- .algo_data = &voo_ddc_bit_data,
-};
-
-static struct pci_device_id voodoo3_ids[] __devinitdata = {
- { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3) },
- { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE) },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE (pci, voodoo3_ids);
-
-static int __devinit voodoo3_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
- int retval;
-
- retval = config_v3(dev);
- if (retval)
- return retval;
-
- /* set up the sysfs linkage to our parent device */
- voodoo3_i2c_adapter.dev.parent = &dev->dev;
- voodoo3_ddc_adapter.dev.parent = &dev->dev;
-
- retval = i2c_bit_add_bus(&voodoo3_i2c_adapter);
- if (retval)
- return retval;
- retval = i2c_bit_add_bus(&voodoo3_ddc_adapter);
- if (retval)
- i2c_del_adapter(&voodoo3_i2c_adapter);
- return retval;
-}
-
-static void __devexit voodoo3_remove(struct pci_dev *dev)
-{
- i2c_del_adapter(&voodoo3_i2c_adapter);
- i2c_del_adapter(&voodoo3_ddc_adapter);
- iounmap(ioaddr);
-}
-
-static struct pci_driver voodoo3_driver = {
- .name = "voodoo3_smbus",
- .id_table = voodoo3_ids,
- .probe = voodoo3_probe,
- .remove = __devexit_p(voodoo3_remove),
-};
-
-static int __init i2c_voodoo3_init(void)
-{
- return pci_register_driver(&voodoo3_driver);
-}
-
-static void __exit i2c_voodoo3_exit(void)
-{
- pci_unregister_driver(&voodoo3_driver);
-}
-
-
-MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
- "Philip Edelbrock <phil@netroedge.com>, "
- "Ralph Metzler <rjkm@thp.uni-koeln.de>, "
- "and Mark D. Studebaker <mdsxyz123@yahoo.com>");
-MODULE_DESCRIPTION("Voodoo3 I2C/SMBus driver");
-MODULE_LICENSE("GPL");
-
-module_init(i2c_voodoo3_init);
-module_exit(i2c_voodoo3_exit);
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index f9618f4d4e47..ae4539d99bef 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -6,16 +6,6 @@
menu "Miscellaneous I2C Chip support"
-config DS1682
- tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm"
- depends on EXPERIMENTAL
- help
- If you say yes here you get support for Dallas Semiconductor
- DS1682 Total Elapsed Time Recorder.
-
- This driver can also be built as a module. If so, the module
- will be called ds1682.
-
config SENSORS_TSL2550
tristate "Taos TSL2550 ambient light sensor"
depends on EXPERIMENTAL
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
index 749cf3606294..fe0af0f81f2d 100644
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -10,7 +10,6 @@
# * I/O expander drivers go to drivers/gpio
#
-obj-$(CONFIG_DS1682) += ds1682.o
obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 8d80fceca6a4..4c4088c7fd66 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -584,7 +584,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
goto out_list;
}
- mutex_init(&adap->bus_lock);
+ rt_mutex_init(&adap->bus_lock);
/* Set default timeout to 1 second if not already set */
if (adap->timeout == 0)
@@ -1081,12 +1081,12 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
#endif
if (in_atomic() || irqs_disabled()) {
- ret = mutex_trylock(&adap->bus_lock);
+ ret = rt_mutex_trylock(&adap->bus_lock);
if (!ret)
/* I2C activity is ongoing. */
return -EAGAIN;
} else {
- mutex_lock_nested(&adap->bus_lock, adap->level);
+ rt_mutex_lock(&adap->bus_lock);
}
/* Retry automatically on arbitration loss */
@@ -1098,7 +1098,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
if (time_after(jiffies, orig_jiffies + adap->timeout))
break;
}
- mutex_unlock(&adap->bus_lock);
+ rt_mutex_unlock(&adap->bus_lock);
return ret;
} else {
@@ -1169,7 +1169,7 @@ EXPORT_SYMBOL(i2c_master_recv);
* ----------------------------------------------------
*/
-static int i2c_detect_address(struct i2c_client *temp_client, int kind,
+static int i2c_detect_address(struct i2c_client *temp_client,
struct i2c_driver *driver)
{
struct i2c_board_info info;
@@ -1188,22 +1188,18 @@ static int i2c_detect_address(struct i2c_client *temp_client, int kind,
if (i2c_check_addr(adapter, addr))
return 0;
- /* Make sure there is something at this address, unless forced */
- if (kind < 0) {
- if (i2c_smbus_xfer(adapter, addr, 0, 0, 0,
- I2C_SMBUS_QUICK, NULL) < 0)
- return 0;
+ /* Make sure there is something at this address */
+ if (i2c_smbus_xfer(adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL) < 0)
+ return 0;
- /* prevent 24RF08 corruption */
- if ((addr & ~0x0f) == 0x50)
- i2c_smbus_xfer(adapter, addr, 0, 0, 0,
- I2C_SMBUS_QUICK, NULL);
- }
+ /* Prevent 24RF08 corruption */
+ if ((addr & ~0x0f) == 0x50)
+ i2c_smbus_xfer(adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL);
/* Finally call the custom detection function */
memset(&info, 0, sizeof(struct i2c_board_info));
info.addr = addr;
- err = driver->detect(temp_client, kind, &info);
+ err = driver->detect(temp_client, -1, &info);
if (err) {
/* -ENODEV is returned if the detection fails. We catch it
here as this isn't an error. */
@@ -1248,40 +1244,13 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
return -ENOMEM;
temp_client->adapter = adapter;
- /* Force entries are done first, and are not affected by ignore
- entries */
- if (address_data->forces) {
- const unsigned short * const *forces = address_data->forces;
- int kind;
-
- for (kind = 0; forces[kind]; kind++) {
- for (i = 0; forces[kind][i] != I2C_CLIENT_END;
- i += 2) {
- if (forces[kind][i] == adap_id
- || forces[kind][i] == ANY_I2C_BUS) {
- dev_dbg(&adapter->dev, "found force "
- "parameter for adapter %d, "
- "addr 0x%02x, kind %d\n",
- adap_id, forces[kind][i + 1],
- kind);
- temp_client->addr = forces[kind][i + 1];
- err = i2c_detect_address(temp_client,
- kind, driver);
- if (err)
- goto exit_free;
- }
- }
- }
- }
-
/* Stop here if the classes do not match */
if (!(adapter->class & driver->class))
goto exit_free;
/* Stop here if we can't use SMBUS_QUICK */
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {
- if (address_data->probe[0] == I2C_CLIENT_END
- && address_data->normal_i2c[0] == I2C_CLIENT_END)
+ if (address_data->normal_i2c[0] == I2C_CLIENT_END)
goto exit_free;
dev_warn(&adapter->dev, "SMBus Quick command not supported, "
@@ -1290,48 +1259,12 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
goto exit_free;
}
- /* Probe entries are done second, and are not affected by ignore
- entries either */
- for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) {
- if (address_data->probe[i] == adap_id
- || address_data->probe[i] == ANY_I2C_BUS) {
- dev_dbg(&adapter->dev, "found probe parameter for "
- "adapter %d, addr 0x%02x\n", adap_id,
- address_data->probe[i + 1]);
- temp_client->addr = address_data->probe[i + 1];
- err = i2c_detect_address(temp_client, -1, driver);
- if (err)
- goto exit_free;
- }
- }
-
- /* Normal entries are done last, unless shadowed by an ignore entry */
for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) {
- int j, ignore;
-
- ignore = 0;
- for (j = 0; address_data->ignore[j] != I2C_CLIENT_END;
- j += 2) {
- if ((address_data->ignore[j] == adap_id ||
- address_data->ignore[j] == ANY_I2C_BUS)
- && address_data->ignore[j + 1]
- == address_data->normal_i2c[i]) {
- dev_dbg(&adapter->dev, "found ignore "
- "parameter for adapter %d, "
- "addr 0x%02x\n", adap_id,
- address_data->ignore[j + 1]);
- ignore = 1;
- break;
- }
- }
- if (ignore)
- continue;
-
dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
"addr 0x%02x\n", adap_id,
address_data->normal_i2c[i]);
temp_client->addr = address_data->normal_i2c[i];
- err = i2c_detect_address(temp_client, -1, driver);
+ err = i2c_detect_address(temp_client, driver);
if (err)
goto exit_free;
}
@@ -1902,7 +1835,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
flags &= I2C_M_TEN | I2C_CLIENT_PEC;
if (adapter->algo->smbus_xfer) {
- mutex_lock(&adapter->bus_lock);
+ rt_mutex_lock(&adapter->bus_lock);
/* Retry automatically on arbitration loss */
orig_jiffies = jiffies;
@@ -1916,7 +1849,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
orig_jiffies + adapter->timeout))
break;
}
- mutex_unlock(&adapter->bus_lock);
+ rt_mutex_unlock(&adapter->bus_lock);
} else
res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
command, protocol, data);
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 7e13d2df9af3..f4110aa49600 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -34,7 +34,6 @@
#include <linux/list.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
-#include <linux/smp_lock.h>
#include <linux/jiffies.h>
#include <asm/uaccess.h>
@@ -445,20 +444,14 @@ static int i2cdev_open(struct inode *inode, struct file *file)
struct i2c_client *client;
struct i2c_adapter *adap;
struct i2c_dev *i2c_dev;
- int ret = 0;
- lock_kernel();
i2c_dev = i2c_dev_get_by_minor(minor);
- if (!i2c_dev) {
- ret = -ENODEV;
- goto out;
- }
+ if (!i2c_dev)
+ return -ENODEV;
adap = i2c_get_adapter(i2c_dev->adap->nr);
- if (!adap) {
- ret = -ENODEV;
- goto out;
- }
+ if (!adap)
+ return -ENODEV;
/* This creates an anonymous i2c_client, which may later be
* pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
@@ -470,8 +463,7 @@ static int i2cdev_open(struct inode *inode, struct file *file)
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client) {
i2c_put_adapter(adap);
- ret = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
client->driver = &i2cdev_driver;
@@ -479,9 +471,7 @@ static int i2cdev_open(struct inode *inode, struct file *file)
client->adapter = adap;
file->private_data = client;
-out:
- unlock_kernel();
- return ret;
+ return 0;
}
static int i2cdev_release(struct inode *inode, struct file *file)
diff --git a/drivers/ide/atiixp.c b/drivers/ide/atiixp.c
index 6396c3ad3252..837322b10a4c 100644
--- a/drivers/ide/atiixp.c
+++ b/drivers/ide/atiixp.c
@@ -177,7 +177,7 @@ static const struct pci_device_id atiixp_pci_tbl[] = {
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), 0 },
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), 1 },
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP700_IDE), 0 },
- { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_SB900_IDE), 0 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_HUDSON2_IDE), 0 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl);
diff --git a/drivers/ide/au1xxx-ide.c b/drivers/ide/au1xxx-ide.c
index 58121bd6c115..bcf41760d864 100644
--- a/drivers/ide/au1xxx-ide.c
+++ b/drivers/ide/au1xxx-ide.c
@@ -56,8 +56,8 @@ static inline void auide_insw(unsigned long port, void *addr, u32 count)
chan_tab_t *ctp;
au1x_ddma_desc_t *dp;
- if(!put_dest_flags(ahwif->rx_chan, (void*)addr, count << 1,
- DDMA_FLAGS_NOIE)) {
+ if (!au1xxx_dbdma_put_dest(ahwif->rx_chan, virt_to_phys(addr),
+ count << 1, DDMA_FLAGS_NOIE)) {
printk(KERN_ERR "%s failed %d\n", __func__, __LINE__);
return;
}
@@ -74,8 +74,8 @@ static inline void auide_outsw(unsigned long port, void *addr, u32 count)
chan_tab_t *ctp;
au1x_ddma_desc_t *dp;
- if(!put_source_flags(ahwif->tx_chan, (void*)addr,
- count << 1, DDMA_FLAGS_NOIE)) {
+ if (!au1xxx_dbdma_put_source(ahwif->tx_chan, virt_to_phys(addr),
+ count << 1, DDMA_FLAGS_NOIE)) {
printk(KERN_ERR "%s failed %d\n", __func__, __LINE__);
return;
}
@@ -246,17 +246,14 @@ static int auide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
flags = DDMA_FLAGS_NOIE;
if (iswrite) {
- if(!put_source_flags(ahwif->tx_chan,
- (void*) sg_virt(sg),
- tc, flags)) {
+ if (!au1xxx_dbdma_put_source(ahwif->tx_chan,
+ sg_phys(sg), tc, flags)) {
printk(KERN_ERR "%s failed %d\n",
__func__, __LINE__);
}
- } else
- {
- if(!put_dest_flags(ahwif->rx_chan,
- (void*) sg_virt(sg),
- tc, flags)) {
+ } else {
+ if (!au1xxx_dbdma_put_dest(ahwif->rx_chan,
+ sg_phys(sg), tc, flags)) {
printk(KERN_ERR "%s failed %d\n",
__func__, __LINE__);
}
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
index 72ed3396b721..0677fc7dfd51 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -589,7 +589,7 @@ static int cxio_hal_destroy_ctrl_qp(struct cxio_rdev *rdev_p)
/* write len bytes of data into addr (32B aligned address)
* If data is NULL, clear len byte of memory to zero.
- * caller aquires the ctrl_qp lock before the call
+ * caller acquires the ctrl_qp lock before the call
*/
static int cxio_hal_ctrl_qp_write_mem(struct cxio_rdev *rdev_p, u32 addr,
u32 len, void *data)
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index 4b89b791be6a..42be0b15084b 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -826,8 +826,7 @@ static void __cpuinit take_over_work(struct ehca_comp_pool *pool, int cpu)
cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
list_del(&cq->entry);
- __queue_comp_task(cq, per_cpu_ptr(pool->cpu_comp_tasks,
- smp_processor_id()));
+ __queue_comp_task(cq, this_cpu_ptr(pool->cpu_comp_tasks));
}
spin_unlock_irqrestore(&cct->task_lock, flags_cct);
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index e593af3354b8..de18fdfdadf2 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -1080,11 +1080,14 @@ static int nes_netdev_set_rx_csum(struct net_device *netdev, u32 enable)
/**
- * nes_netdev_get_stats_count
+ * nes_netdev_get_sset_count
*/
-static int nes_netdev_get_stats_count(struct net_device *netdev)
+static int nes_netdev_get_sset_count(struct net_device *netdev, int stringset)
{
- return NES_ETHTOOL_STAT_COUNT;
+ if (stringset == ETH_SS_STATS)
+ return NES_ETHTOOL_STAT_COUNT;
+ else
+ return -EINVAL;
}
@@ -1264,7 +1267,6 @@ static void nes_netdev_get_drvinfo(struct net_device *netdev,
sprintf(drvinfo->fw_version, "%u.%u", nesadapter->firmware_version>>16,
nesadapter->firmware_version & 0x000000ff);
strcpy(drvinfo->version, DRV_VERSION);
- drvinfo->n_stats = nes_netdev_get_stats_count(netdev);
drvinfo->testinfo_len = 0;
drvinfo->eedump_len = 0;
drvinfo->regdump_len = 0;
@@ -1516,7 +1518,7 @@ static const struct ethtool_ops nes_ethtool_ops = {
.get_rx_csum = nes_netdev_get_rx_csum,
.get_sg = ethtool_op_get_sg,
.get_strings = nes_netdev_get_strings,
- .get_stats_count = nes_netdev_get_stats_count,
+ .get_sset_count = nes_netdev_get_sset_count,
.get_ethtool_stats = nes_netdev_get_ethtool_stats,
.get_drvinfo = nes_netdev_get_drvinfo,
.get_coalesce = nes_netdev_get_coalesce,
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index ea9e1556e0d6..8579f32ce38e 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -499,7 +499,7 @@ void iser_conn_init(struct iser_conn *ib_conn)
/**
* starts the process of connecting to the target
- * sleeps untill the connection is established or rejected
+ * sleeps until the connection is established or rejected
*/
int iser_connect(struct iser_conn *ib_conn,
struct sockaddr_in *src_addr,
diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c
index 0d3ce7a50fb1..910220c127cb 100644
--- a/drivers/input/input-polldev.c
+++ b/drivers/input/input-polldev.c
@@ -80,8 +80,8 @@ static int input_open_polled_device(struct input_dev *input)
if (error)
return error;
- if (dev->flush)
- dev->flush(dev);
+ if (dev->open)
+ dev->open(dev);
queue_delayed_work(polldev_wq, &dev->work,
msecs_to_jiffies(dev->poll_interval));
@@ -95,6 +95,9 @@ static void input_close_polled_device(struct input_dev *input)
cancel_delayed_work_sync(&dev->work);
input_polldev_stop_workqueue();
+
+ if (dev->close)
+ dev->close(dev);
}
/**
diff --git a/drivers/input/input.c b/drivers/input/input.c
index c6f88ebb40c7..cc763c96fada 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -782,10 +782,29 @@ static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait)
return 0;
}
+union input_seq_state {
+ struct {
+ unsigned short pos;
+ bool mutex_acquired;
+ };
+ void *p;
+};
+
static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos)
{
- if (mutex_lock_interruptible(&input_mutex))
- return NULL;
+ union input_seq_state *state = (union input_seq_state *)&seq->private;
+ int error;
+
+ /* We need to fit into seq->private pointer */
+ BUILD_BUG_ON(sizeof(union input_seq_state) != sizeof(seq->private));
+
+ error = mutex_lock_interruptible(&input_mutex);
+ if (error) {
+ state->mutex_acquired = false;
+ return ERR_PTR(error);
+ }
+
+ state->mutex_acquired = true;
return seq_list_start(&input_dev_list, *pos);
}
@@ -795,9 +814,12 @@ static void *input_devices_seq_next(struct seq_file *seq, void *v, loff_t *pos)
return seq_list_next(v, &input_dev_list, pos);
}
-static void input_devices_seq_stop(struct seq_file *seq, void *v)
+static void input_seq_stop(struct seq_file *seq, void *v)
{
- mutex_unlock(&input_mutex);
+ union input_seq_state *state = (union input_seq_state *)&seq->private;
+
+ if (state->mutex_acquired)
+ mutex_unlock(&input_mutex);
}
static void input_seq_print_bitmap(struct seq_file *seq, const char *name,
@@ -861,7 +883,7 @@ static int input_devices_seq_show(struct seq_file *seq, void *v)
static const struct seq_operations input_devices_seq_ops = {
.start = input_devices_seq_start,
.next = input_devices_seq_next,
- .stop = input_devices_seq_stop,
+ .stop = input_seq_stop,
.show = input_devices_seq_show,
};
@@ -881,40 +903,49 @@ static const struct file_operations input_devices_fileops = {
static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos)
{
- if (mutex_lock_interruptible(&input_mutex))
- return NULL;
+ union input_seq_state *state = (union input_seq_state *)&seq->private;
+ int error;
+
+ /* We need to fit into seq->private pointer */
+ BUILD_BUG_ON(sizeof(union input_seq_state) != sizeof(seq->private));
+
+ error = mutex_lock_interruptible(&input_mutex);
+ if (error) {
+ state->mutex_acquired = false;
+ return ERR_PTR(error);
+ }
+
+ state->mutex_acquired = true;
+ state->pos = *pos;
- seq->private = (void *)(unsigned long)*pos;
return seq_list_start(&input_handler_list, *pos);
}
static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- seq->private = (void *)(unsigned long)(*pos + 1);
- return seq_list_next(v, &input_handler_list, pos);
-}
+ union input_seq_state *state = (union input_seq_state *)&seq->private;
-static void input_handlers_seq_stop(struct seq_file *seq, void *v)
-{
- mutex_unlock(&input_mutex);
+ state->pos = *pos + 1;
+ return seq_list_next(v, &input_handler_list, pos);
}
static int input_handlers_seq_show(struct seq_file *seq, void *v)
{
struct input_handler *handler = container_of(v, struct input_handler, node);
+ union input_seq_state *state = (union input_seq_state *)&seq->private;
- seq_printf(seq, "N: Number=%ld Name=%s",
- (unsigned long)seq->private, handler->name);
+ seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name);
if (handler->fops)
seq_printf(seq, " Minor=%d", handler->minor);
seq_putc(seq, '\n');
return 0;
}
+
static const struct seq_operations input_handlers_seq_ops = {
.start = input_handlers_seq_start,
.next = input_handlers_seq_next,
- .stop = input_handlers_seq_stop,
+ .stop = input_seq_stop,
.show = input_handlers_seq_show,
};
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index ee98b1bc5d89..02c836e11813 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -24,6 +24,16 @@ config KEYBOARD_AAED2000
To compile this driver as a module, choose M here: the
module will be called aaed2000_kbd.
+config KEYBOARD_ADP5520
+ tristate "Keypad Support for ADP5520 PMIC"
+ depends on PMIC_ADP5520
+ help
+ This option enables support for the keypad scan matrix
+ on Analog Devices ADP5520 PMICs.
+
+ To compile this driver as a module, choose M here: the module will
+ be called adp5520-keys.
+
config KEYBOARD_ADP5588
tristate "ADP5588 I2C QWERTY Keypad and IO Expander"
depends on I2C
@@ -361,6 +371,16 @@ config KEYBOARD_SH_KEYSC
To compile this driver as a module, choose M here: the
module will be called sh_keysc.
+config KEYBOARD_DAVINCI
+ tristate "TI DaVinci Key Scan"
+ depends on ARCH_DAVINCI_DM365
+ help
+ Say Y to enable keypad module support for the TI DaVinci
+ platforms (DM365).
+
+ To compile this driver as a module, choose M here: the
+ module will be called davinci_keyscan.
+
config KEYBOARD_OMAP
tristate "TI OMAP keypad support"
depends on (ARCH_OMAP1 || ARCH_OMAP2)
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index babad5e58b77..78654ef65206 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -5,12 +5,14 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
+obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o
obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o
+obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
diff --git a/drivers/input/keyboard/adp5520-keys.c b/drivers/input/keyboard/adp5520-keys.c
new file mode 100644
index 000000000000..a7ba27fb4109
--- /dev/null
+++ b/drivers/input/keyboard/adp5520-keys.c
@@ -0,0 +1,220 @@
+/*
+ * Keypad driver for Analog Devices ADP5520 MFD PMICs
+ *
+ * Copyright 2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/mfd/adp5520.h>
+
+struct adp5520_keys {
+ struct input_dev *input;
+ struct notifier_block notifier;
+ struct device *master;
+ unsigned short keycode[ADP5520_KEYMAPSIZE];
+};
+
+static void adp5520_keys_report_event(struct adp5520_keys *dev,
+ unsigned short keymask, int value)
+{
+ int i;
+
+ for (i = 0; i < ADP5520_MAXKEYS; i++)
+ if (keymask & (1 << i))
+ input_report_key(dev->input, dev->keycode[i], value);
+
+ input_sync(dev->input);
+}
+
+static int adp5520_keys_notifier(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct adp5520_keys *dev;
+ uint8_t reg_val_lo, reg_val_hi;
+ unsigned short keymask;
+
+ dev = container_of(nb, struct adp5520_keys, notifier);
+
+ if (event & ADP5520_KP_INT) {
+ adp5520_read(dev->master, ADP5520_KP_INT_STAT_1, &reg_val_lo);
+ adp5520_read(dev->master, ADP5520_KP_INT_STAT_2, &reg_val_hi);
+
+ keymask = (reg_val_hi << 8) | reg_val_lo;
+ /* Read twice to clear */
+ adp5520_read(dev->master, ADP5520_KP_INT_STAT_1, &reg_val_lo);
+ adp5520_read(dev->master, ADP5520_KP_INT_STAT_2, &reg_val_hi);
+ keymask |= (reg_val_hi << 8) | reg_val_lo;
+ adp5520_keys_report_event(dev, keymask, 1);
+ }
+
+ if (event & ADP5520_KR_INT) {
+ adp5520_read(dev->master, ADP5520_KR_INT_STAT_1, &reg_val_lo);
+ adp5520_read(dev->master, ADP5520_KR_INT_STAT_2, &reg_val_hi);
+
+ keymask = (reg_val_hi << 8) | reg_val_lo;
+ /* Read twice to clear */
+ adp5520_read(dev->master, ADP5520_KR_INT_STAT_1, &reg_val_lo);
+ adp5520_read(dev->master, ADP5520_KR_INT_STAT_2, &reg_val_hi);
+ keymask |= (reg_val_hi << 8) | reg_val_lo;
+ adp5520_keys_report_event(dev, keymask, 0);
+ }
+
+ return 0;
+}
+
+static int __devinit adp5520_keys_probe(struct platform_device *pdev)
+{
+ struct adp5520_keys_platform_data *pdata = pdev->dev.platform_data;
+ struct input_dev *input;
+ struct adp5520_keys *dev;
+ int ret, i;
+ unsigned char en_mask, ctl_mask = 0;
+
+ if (pdev->id != ID_ADP5520) {
+ dev_err(&pdev->dev, "only ADP5520 supports Keypad\n");
+ return -EINVAL;
+ }
+
+ if (pdata == NULL) {
+ dev_err(&pdev->dev, "missing platform data\n");
+ return -EINVAL;
+ }
+
+ if (!(pdata->rows_en_mask && pdata->cols_en_mask))
+ return -EINVAL;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&pdev->dev, "failed to alloc memory\n");
+ return -ENOMEM;
+ }
+
+ input = input_allocate_device();
+ if (!input) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ dev->master = pdev->dev.parent;
+ dev->input = input;
+
+ input->name = pdev->name;
+ input->phys = "adp5520-keys/input0";
+ input->dev.parent = &pdev->dev;
+
+ input_set_drvdata(input, dev);
+
+ input->id.bustype = BUS_I2C;
+ input->id.vendor = 0x0001;
+ input->id.product = 0x5520;
+ input->id.version = 0x0001;
+
+ input->keycodesize = sizeof(dev->keycode[0]);
+ input->keycodemax = pdata->keymapsize;
+ input->keycode = dev->keycode;
+
+ memcpy(dev->keycode, pdata->keymap,
+ pdata->keymapsize * input->keycodesize);
+
+ /* setup input device */
+ __set_bit(EV_KEY, input->evbit);
+
+ if (pdata->repeat)
+ __set_bit(EV_REP, input->evbit);
+
+ for (i = 0; i < input->keycodemax; i++)
+ __set_bit(dev->keycode[i], input->keybit);
+ __clear_bit(KEY_RESERVED, input->keybit);
+
+ ret = input_register_device(input);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to register input device\n");
+ goto err;
+ }
+
+ en_mask = pdata->rows_en_mask | pdata->cols_en_mask;
+
+ ret = adp5520_set_bits(dev->master, ADP5520_GPIO_CFG_1, en_mask);
+
+ if (en_mask & ADP5520_COL_C3)
+ ctl_mask |= ADP5520_C3_MODE;
+
+ if (en_mask & ADP5520_ROW_R3)
+ ctl_mask |= ADP5520_R3_MODE;
+
+ if (ctl_mask)
+ ret |= adp5520_set_bits(dev->master, ADP5520_LED_CONTROL,
+ ctl_mask);
+
+ ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_PULLUP,
+ pdata->rows_en_mask);
+
+ if (ret) {
+ dev_err(&pdev->dev, "failed to write\n");
+ ret = -EIO;
+ goto err1;
+ }
+
+ dev->notifier.notifier_call = adp5520_keys_notifier;
+ ret = adp5520_register_notifier(dev->master, &dev->notifier,
+ ADP5520_KP_IEN | ADP5520_KR_IEN);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register notifier\n");
+ goto err1;
+ }
+
+ platform_set_drvdata(pdev, dev);
+ return 0;
+
+err1:
+ input_unregister_device(input);
+ input = NULL;
+err:
+ input_free_device(input);
+ kfree(dev);
+ return ret;
+}
+
+static int __devexit adp5520_keys_remove(struct platform_device *pdev)
+{
+ struct adp5520_keys *dev = platform_get_drvdata(pdev);
+
+ adp5520_unregister_notifier(dev->master, &dev->notifier,
+ ADP5520_KP_IEN | ADP5520_KR_IEN);
+
+ input_unregister_device(dev->input);
+ kfree(dev);
+ return 0;
+}
+
+static struct platform_driver adp5520_keys_driver = {
+ .driver = {
+ .name = "adp5520-keys",
+ .owner = THIS_MODULE,
+ },
+ .probe = adp5520_keys_probe,
+ .remove = __devexit_p(adp5520_keys_remove),
+};
+
+static int __init adp5520_keys_init(void)
+{
+ return platform_driver_register(&adp5520_keys_driver);
+}
+module_init(adp5520_keys_init);
+
+static void __exit adp5520_keys_exit(void)
+{
+ platform_driver_unregister(&adp5520_keys_driver);
+}
+module_exit(adp5520_keys_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Keys ADP5520 Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:adp5520-keys");
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 4709e15af607..4452eabbee6d 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -233,6 +233,7 @@ struct atkbd {
*/
static void (*atkbd_platform_fixup)(struct atkbd *, const void *data);
static void *atkbd_platform_fixup_data;
+static unsigned int (*atkbd_platform_scancode_fixup)(struct atkbd *, unsigned int);
static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
ssize_t (*handler)(struct atkbd *, char *));
@@ -393,6 +394,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
input_event(dev, EV_MSC, MSC_RAW, code);
+ if (atkbd_platform_scancode_fixup)
+ code = atkbd_platform_scancode_fixup(atkbd, code);
+
if (atkbd->translated) {
if (atkbd->emul || atkbd_need_xlate(atkbd->xl_bit, code)) {
@@ -574,11 +578,22 @@ static void atkbd_event_work(struct work_struct *work)
mutex_lock(&atkbd->event_mutex);
- if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask))
- atkbd_set_leds(atkbd);
+ if (!atkbd->enabled) {
+ /*
+ * Serio ports are resumed asynchronously so while driver core
+ * thinks that device is already fully operational in reality
+ * it may not be ready yet. In this case we need to keep
+ * rescheduling till reconnect completes.
+ */
+ schedule_delayed_work(&atkbd->event_work,
+ msecs_to_jiffies(100));
+ } else {
+ if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask))
+ atkbd_set_leds(atkbd);
- if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask))
- atkbd_set_repeat_rate(atkbd);
+ if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask))
+ atkbd_set_repeat_rate(atkbd);
+ }
mutex_unlock(&atkbd->event_mutex);
}
@@ -770,6 +785,30 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra
return 3;
}
+static int atkbd_reset_state(struct atkbd *atkbd)
+{
+ struct ps2dev *ps2dev = &atkbd->ps2dev;
+ unsigned char param[1];
+
+/*
+ * Set the LEDs to a predefined state (all off).
+ */
+
+ param[0] = 0;
+ if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
+ return -1;
+
+/*
+ * Set autorepeat to fastest possible.
+ */
+
+ param[0] = 0;
+ if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP))
+ return -1;
+
+ return 0;
+}
+
static int atkbd_activate(struct atkbd *atkbd)
{
struct ps2dev *ps2dev = &atkbd->ps2dev;
@@ -852,29 +891,6 @@ static unsigned int atkbd_hp_forced_release_keys[] = {
};
/*
- * Inventec system with broken key release on volume keys
- */
-static unsigned int atkbd_inventec_forced_release_keys[] = {
- 0xae, 0xb0, -1U
-};
-
-/*
- * Perform fixup for HP Pavilion ZV6100 laptop that doesn't generate release
- * for its volume buttons
- */
-static unsigned int atkbd_hp_zv6100_forced_release_keys[] = {
- 0xae, 0xb0, -1U
-};
-
-/*
- * Perform fixup for HP (Compaq) Presario R4000 R4100 R4200 that don't generate
- * release for their volume buttons
- */
-static unsigned int atkbd_hp_r4000_forced_release_keys[] = {
- 0xae, 0xb0, -1U
-};
-
-/*
* Samsung NC10,NC20 with Fn+F? key release not working
*/
static unsigned int atkbd_samsung_forced_release_keys[] = {
@@ -882,14 +898,6 @@ static unsigned int atkbd_samsung_forced_release_keys[] = {
};
/*
- * The volume up and volume down special keys on a Fujitsu Amilo PA 1510 laptop
- * do not generate release events so we have to do it ourselves.
- */
-static unsigned int atkbd_amilo_pa1510_forced_release_keys[] = {
- 0xb0, 0xae, -1U
-};
-
-/*
* Amilo Pi 3525 key release for Fn+Volume keys not working
*/
static unsigned int atkbd_amilo_pi3525_forced_release_keys[] = {
@@ -911,6 +919,30 @@ static unsigned int atkdb_soltech_ta12_forced_release_keys[] = {
};
/*
+ * Many notebooks don't send key release event for volume up/down
+ * keys, with key list below common among them
+ */
+static unsigned int atkbd_volume_forced_release_keys[] = {
+ 0xae, 0xb0, -1U
+};
+
+/*
+ * OQO 01+ multimedia keys (64--66) generate e0 6x upon release whereas
+ * they should be generating e4-e6 (0x80 | code).
+ */
+static unsigned int atkbd_oqo_01plus_scancode_fixup(struct atkbd *atkbd,
+ unsigned int code)
+{
+ if (atkbd->translated && atkbd->emul == 1 &&
+ (code == 0x64 || code == 0x65 || code == 0x66)) {
+ atkbd->emul = 0;
+ code |= 0x80;
+ }
+
+ return code;
+}
+
+/*
* atkbd_set_keycode_table() initializes keyboard's keycode table
* according to the selected scancode set
*/
@@ -1087,6 +1119,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
}
atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra);
+ atkbd_reset_state(atkbd);
atkbd_activate(atkbd);
} else {
@@ -1267,6 +1300,7 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun
atkbd->dev = new_dev;
atkbd->set = atkbd_select_set(atkbd, atkbd->set, value);
+ atkbd_reset_state(atkbd);
atkbd_activate(atkbd);
atkbd_set_keycode_table(atkbd);
atkbd_set_device_attrs(atkbd);
@@ -1513,6 +1547,13 @@ static int __init atkbd_setup_forced_release(const struct dmi_system_id *id)
return 0;
}
+static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id)
+{
+ atkbd_platform_scancode_fixup = id->driver_data;
+
+ return 0;
+}
+
static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
{
.ident = "Dell Laptop",
@@ -1548,7 +1589,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"),
},
.callback = atkbd_setup_forced_release,
- .driver_data = atkbd_hp_zv6100_forced_release_keys,
+ .driver_data = atkbd_volume_forced_release_keys,
},
{
.ident = "HP Presario R4000",
@@ -1557,7 +1598,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4000"),
},
.callback = atkbd_setup_forced_release,
- .driver_data = atkbd_hp_r4000_forced_release_keys,
+ .driver_data = atkbd_volume_forced_release_keys,
},
{
.ident = "HP Presario R4100",
@@ -1566,7 +1607,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4100"),
},
.callback = atkbd_setup_forced_release,
- .driver_data = atkbd_hp_r4000_forced_release_keys,
+ .driver_data = atkbd_volume_forced_release_keys,
},
{
.ident = "HP Presario R4200",
@@ -1575,7 +1616,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4200"),
},
.callback = atkbd_setup_forced_release,
- .driver_data = atkbd_hp_r4000_forced_release_keys,
+ .driver_data = atkbd_volume_forced_release_keys,
},
{
.ident = "Inventec Symphony",
@@ -1584,7 +1625,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"),
},
.callback = atkbd_setup_forced_release,
- .driver_data = atkbd_inventec_forced_release_keys,
+ .driver_data = atkbd_volume_forced_release_keys,
},
{
.ident = "Samsung NC10",
@@ -1620,7 +1661,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 1510"),
},
.callback = atkbd_setup_forced_release,
- .driver_data = atkbd_amilo_pa1510_forced_release_keys,
+ .driver_data = atkbd_volume_forced_release_keys,
},
{
.ident = "Fujitsu Amilo Pi 3525",
@@ -1649,6 +1690,15 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
.callback = atkbd_setup_forced_release,
.driver_data = atkdb_soltech_ta12_forced_release_keys,
},
+ {
+ .ident = "OQO Model 01+",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "OQO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"),
+ },
+ .callback = atkbd_setup_scancode_fixup,
+ .driver_data = atkbd_oqo_01plus_scancode_fixup,
+ },
{ }
};
diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c
new file mode 100644
index 000000000000..6e52d855f637
--- /dev/null
+++ b/drivers/input/keyboard/davinci_keyscan.c
@@ -0,0 +1,337 @@
+/*
+ * DaVinci Key Scan Driver for TI platforms
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc
+ *
+ * Author: Miguel Aguilar <miguel.aguilar@ridgerun.com>
+ *
+ * Intial Code: Sandeep Paulraj <s-paulraj@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/types.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+
+#include <asm/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/keyscan.h>
+
+/* Key scan registers */
+#define DAVINCI_KEYSCAN_KEYCTRL 0x0000
+#define DAVINCI_KEYSCAN_INTENA 0x0004
+#define DAVINCI_KEYSCAN_INTFLAG 0x0008
+#define DAVINCI_KEYSCAN_INTCLR 0x000c
+#define DAVINCI_KEYSCAN_STRBWIDTH 0x0010
+#define DAVINCI_KEYSCAN_INTERVAL 0x0014
+#define DAVINCI_KEYSCAN_CONTTIME 0x0018
+#define DAVINCI_KEYSCAN_CURRENTST 0x001c
+#define DAVINCI_KEYSCAN_PREVSTATE 0x0020
+#define DAVINCI_KEYSCAN_EMUCTRL 0x0024
+#define DAVINCI_KEYSCAN_IODFTCTRL 0x002c
+
+/* Key Control Register (KEYCTRL) */
+#define DAVINCI_KEYSCAN_KEYEN 0x00000001
+#define DAVINCI_KEYSCAN_PREVMODE 0x00000002
+#define DAVINCI_KEYSCAN_CHATOFF 0x00000004
+#define DAVINCI_KEYSCAN_AUTODET 0x00000008
+#define DAVINCI_KEYSCAN_SCANMODE 0x00000010
+#define DAVINCI_KEYSCAN_OUTTYPE 0x00000020
+
+/* Masks for the interrupts */
+#define DAVINCI_KEYSCAN_INT_CONT 0x00000008
+#define DAVINCI_KEYSCAN_INT_OFF 0x00000004
+#define DAVINCI_KEYSCAN_INT_ON 0x00000002
+#define DAVINCI_KEYSCAN_INT_CHANGE 0x00000001
+#define DAVINCI_KEYSCAN_INT_ALL 0x0000000f
+
+struct davinci_ks {
+ struct input_dev *input;
+ struct davinci_ks_platform_data *pdata;
+ int irq;
+ void __iomem *base;
+ resource_size_t pbase;
+ size_t base_size;
+ unsigned short keymap[];
+};
+
+/* Initializing the kp Module */
+static int __init davinci_ks_initialize(struct davinci_ks *davinci_ks)
+{
+ struct device *dev = &davinci_ks->input->dev;
+ struct davinci_ks_platform_data *pdata = davinci_ks->pdata;
+ u32 matrix_ctrl;
+
+ /* Enable all interrupts */
+ __raw_writel(DAVINCI_KEYSCAN_INT_ALL,
+ davinci_ks->base + DAVINCI_KEYSCAN_INTENA);
+
+ /* Clear interrupts if any */
+ __raw_writel(DAVINCI_KEYSCAN_INT_ALL,
+ davinci_ks->base + DAVINCI_KEYSCAN_INTCLR);
+
+ /* Setup the scan period = strobe + interval */
+ __raw_writel(pdata->strobe,
+ davinci_ks->base + DAVINCI_KEYSCAN_STRBWIDTH);
+ __raw_writel(pdata->interval,
+ davinci_ks->base + DAVINCI_KEYSCAN_INTERVAL);
+ __raw_writel(0x01,
+ davinci_ks->base + DAVINCI_KEYSCAN_CONTTIME);
+
+ /* Define matrix type */
+ switch (pdata->matrix_type) {
+ case DAVINCI_KEYSCAN_MATRIX_4X4:
+ matrix_ctrl = 0;
+ break;
+ case DAVINCI_KEYSCAN_MATRIX_5X3:
+ matrix_ctrl = (1 << 6);
+ break;
+ default:
+ dev_err(dev->parent, "wrong matrix type\n");
+ return -EINVAL;
+ }
+
+ /* Enable key scan module and set matrix type */
+ __raw_writel(DAVINCI_KEYSCAN_AUTODET | DAVINCI_KEYSCAN_KEYEN |
+ matrix_ctrl, davinci_ks->base + DAVINCI_KEYSCAN_KEYCTRL);
+
+ return 0;
+}
+
+static irqreturn_t davinci_ks_interrupt(int irq, void *dev_id)
+{
+ struct davinci_ks *davinci_ks = dev_id;
+ struct device *dev = &davinci_ks->input->dev;
+ unsigned short *keymap = davinci_ks->keymap;
+ int keymapsize = davinci_ks->pdata->keymapsize;
+ u32 prev_status, new_status, changed;
+ bool release;
+ int keycode = KEY_UNKNOWN;
+ int i;
+
+ /* Disable interrupt */
+ __raw_writel(0x0, davinci_ks->base + DAVINCI_KEYSCAN_INTENA);
+
+ /* Reading previous and new status of the key scan */
+ prev_status = __raw_readl(davinci_ks->base + DAVINCI_KEYSCAN_PREVSTATE);
+ new_status = __raw_readl(davinci_ks->base + DAVINCI_KEYSCAN_CURRENTST);
+
+ changed = prev_status ^ new_status;
+
+ if (changed) {
+ /*
+ * It goes through all bits in 'changed' to ensure
+ * that no key changes are being missed
+ */
+ for (i = 0 ; i < keymapsize; i++) {
+ if ((changed>>i) & 0x1) {
+ keycode = keymap[i];
+ release = (new_status >> i) & 0x1;
+ dev_dbg(dev->parent, "key %d %s\n", keycode,
+ release ? "released" : "pressed");
+ input_report_key(davinci_ks->input, keycode,
+ !release);
+ input_sync(davinci_ks->input);
+ }
+ }
+ /* Clearing interrupt */
+ __raw_writel(DAVINCI_KEYSCAN_INT_ALL,
+ davinci_ks->base + DAVINCI_KEYSCAN_INTCLR);
+ }
+
+ /* Enable interrupts */
+ __raw_writel(0x1, davinci_ks->base + DAVINCI_KEYSCAN_INTENA);
+
+ return IRQ_HANDLED;
+}
+
+static int __init davinci_ks_probe(struct platform_device *pdev)
+{
+ struct davinci_ks *davinci_ks;
+ struct input_dev *key_dev;
+ struct resource *res, *mem;
+ struct device *dev = &pdev->dev;
+ struct davinci_ks_platform_data *pdata = pdev->dev.platform_data;
+ int error, i;
+
+ if (!pdata->keymap) {
+ dev_dbg(dev, "no keymap from pdata\n");
+ return -EINVAL;
+ }
+
+ davinci_ks = kzalloc(sizeof(struct davinci_ks) +
+ sizeof(unsigned short) * pdata->keymapsize, GFP_KERNEL);
+ if (!davinci_ks) {
+ dev_dbg(dev, "could not allocate memory for private data\n");
+ return -ENOMEM;
+ }
+
+ memcpy(davinci_ks->keymap, pdata->keymap,
+ sizeof(unsigned short) * pdata->keymapsize);
+
+ key_dev = input_allocate_device();
+ if (!key_dev) {
+ dev_dbg(dev, "could not allocate input device\n");
+ error = -ENOMEM;
+ goto fail1;
+ }
+
+ davinci_ks->input = key_dev;
+
+ davinci_ks->irq = platform_get_irq(pdev, 0);
+ if (davinci_ks->irq < 0) {
+ dev_err(dev, "no key scan irq\n");
+ error = davinci_ks->irq;
+ goto fail2;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "no mem resource\n");
+ error = -EINVAL;
+ goto fail2;
+ }
+
+ davinci_ks->pbase = res->start;
+ davinci_ks->base_size = resource_size(res);
+
+ mem = request_mem_region(davinci_ks->pbase, davinci_ks->base_size,
+ pdev->name);
+ if (!mem) {
+ dev_err(dev, "key scan registers at %08x are not free\n",
+ davinci_ks->pbase);
+ error = -EBUSY;
+ goto fail2;
+ }
+
+ davinci_ks->base = ioremap(davinci_ks->pbase, davinci_ks->base_size);
+ if (!davinci_ks->base) {
+ dev_err(dev, "can't ioremap MEM resource.\n");
+ error = -ENOMEM;
+ goto fail3;
+ }
+
+ /* Enable auto repeat feature of Linux input subsystem */
+ if (pdata->rep)
+ __set_bit(EV_REP, key_dev->evbit);
+
+ /* Setup input device */
+ __set_bit(EV_KEY, key_dev->evbit);
+
+ /* Setup the platform data */
+ davinci_ks->pdata = pdata;
+
+ for (i = 0; i < davinci_ks->pdata->keymapsize; i++)
+ __set_bit(davinci_ks->pdata->keymap[i], key_dev->keybit);
+
+ key_dev->name = "davinci_keyscan";
+ key_dev->phys = "davinci_keyscan/input0";
+ key_dev->dev.parent = &pdev->dev;
+ key_dev->id.bustype = BUS_HOST;
+ key_dev->id.vendor = 0x0001;
+ key_dev->id.product = 0x0001;
+ key_dev->id.version = 0x0001;
+ key_dev->keycode = davinci_ks->keymap;
+ key_dev->keycodesize = sizeof(davinci_ks->keymap[0]);
+ key_dev->keycodemax = davinci_ks->pdata->keymapsize;
+
+ error = input_register_device(davinci_ks->input);
+ if (error < 0) {
+ dev_err(dev, "unable to register davinci key scan device\n");
+ goto fail4;
+ }
+
+ error = request_irq(davinci_ks->irq, davinci_ks_interrupt,
+ IRQF_DISABLED, pdev->name, davinci_ks);
+ if (error < 0) {
+ dev_err(dev, "unable to register davinci key scan interrupt\n");
+ goto fail5;
+ }
+
+ error = davinci_ks_initialize(davinci_ks);
+ if (error < 0) {
+ dev_err(dev, "unable to initialize davinci key scan device\n");
+ goto fail6;
+ }
+
+ platform_set_drvdata(pdev, davinci_ks);
+ return 0;
+
+fail6:
+ free_irq(davinci_ks->irq, davinci_ks);
+fail5:
+ input_unregister_device(davinci_ks->input);
+ key_dev = NULL;
+fail4:
+ iounmap(davinci_ks->base);
+fail3:
+ release_mem_region(davinci_ks->pbase, davinci_ks->base_size);
+fail2:
+ input_free_device(key_dev);
+fail1:
+ kfree(davinci_ks);
+
+ return error;
+}
+
+static int __devexit davinci_ks_remove(struct platform_device *pdev)
+{
+ struct davinci_ks *davinci_ks = platform_get_drvdata(pdev);
+
+ free_irq(davinci_ks->irq, davinci_ks);
+
+ input_unregister_device(davinci_ks->input);
+
+ iounmap(davinci_ks->base);
+ release_mem_region(davinci_ks->pbase, davinci_ks->base_size);
+
+ platform_set_drvdata(pdev, NULL);
+
+ kfree(davinci_ks);
+
+ return 0;
+}
+
+static struct platform_driver davinci_ks_driver = {
+ .driver = {
+ .name = "davinci_keyscan",
+ .owner = THIS_MODULE,
+ },
+ .remove = __devexit_p(davinci_ks_remove),
+};
+
+static int __init davinci_ks_init(void)
+{
+ return platform_driver_probe(&davinci_ks_driver, davinci_ks_probe);
+}
+module_init(davinci_ks_init);
+
+static void __exit davinci_ks_exit(void)
+{
+ platform_driver_unregister(&davinci_ks_driver);
+}
+module_exit(davinci_ks_exit);
+
+MODULE_AUTHOR("Miguel Aguilar");
+MODULE_DESCRIPTION("Texas Instruments DaVinci Key Scan Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c
index f9847e0fb553..fa9bb6d235e2 100644
--- a/drivers/input/keyboard/lkkbd.c
+++ b/drivers/input/keyboard/lkkbd.c
@@ -72,9 +72,9 @@
#define DRIVER_DESC "LK keyboard driver"
-MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
-MODULE_DESCRIPTION (DRIVER_DESC);
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
/*
* Known parameters:
@@ -85,27 +85,27 @@ MODULE_LICENSE ("GPL");
* Please notice that there's not yet an API to set these at runtime.
*/
static int bell_volume = 100; /* % */
-module_param (bell_volume, int, 0);
-MODULE_PARM_DESC (bell_volume, "Bell volume (in %). default is 100%");
+module_param(bell_volume, int, 0);
+MODULE_PARM_DESC(bell_volume, "Bell volume (in %). default is 100%");
static int keyclick_volume = 100; /* % */
-module_param (keyclick_volume, int, 0);
-MODULE_PARM_DESC (keyclick_volume, "Keyclick volume (in %), default is 100%");
+module_param(keyclick_volume, int, 0);
+MODULE_PARM_DESC(keyclick_volume, "Keyclick volume (in %), default is 100%");
static int ctrlclick_volume = 100; /* % */
-module_param (ctrlclick_volume, int, 0);
-MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%");
+module_param(ctrlclick_volume, int, 0);
+MODULE_PARM_DESC(ctrlclick_volume, "Ctrlclick volume (in %), default is 100%");
static int lk201_compose_is_alt;
-module_param (lk201_compose_is_alt, int, 0);
-MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key "
- "will act as an Alt key");
+module_param(lk201_compose_is_alt, int, 0);
+MODULE_PARM_DESC(lk201_compose_is_alt,
+ "If set non-zero, LK201' Compose key will act as an Alt key");
#undef LKKBD_DEBUG
#ifdef LKKBD_DEBUG
-#define DBG(x...) printk (x)
+#define DBG(x...) printk(x)
#else
#define DBG(x...) do {} while (0)
#endif
@@ -122,7 +122,7 @@ MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key "
#define LK_MODE_DOWN 0x80
#define LK_MODE_AUTODOWN 0x82
#define LK_MODE_UPDOWN 0x86
-#define LK_CMD_SET_MODE(mode,div) ((mode) | ((div) << 3))
+#define LK_CMD_SET_MODE(mode, div) ((mode) | ((div) << 3))
/* Misc commands */
#define LK_CMD_ENABLE_KEYCLICK 0x1b
@@ -152,11 +152,8 @@ MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key "
#define LK_NUM_KEYCODES 256
#define LK_NUM_IGNORE_BYTES 6
-typedef u_int16_t lk_keycode_t;
-
-
-static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = {
+static unsigned short lkkbd_keycode[LK_NUM_KEYCODES] = {
[0x56] = KEY_F1,
[0x57] = KEY_F2,
[0x58] = KEY_F3,
@@ -268,7 +265,7 @@ static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = {
};
#define CHECK_LED(LK, VAR_ON, VAR_OFF, LED, BITS) do { \
- if (test_bit (LED, (LK)->dev->led)) \
+ if (test_bit(LED, (LK)->dev->led)) \
VAR_ON |= BITS; \
else \
VAR_OFF |= BITS; \
@@ -278,7 +275,7 @@ static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = {
* Per-keyboard data
*/
struct lkkbd {
- lk_keycode_t keycode[LK_NUM_KEYCODES];
+ unsigned short keycode[LK_NUM_KEYCODES];
int ignore_bytes;
unsigned char id[LK_NUM_IGNORE_BYTES];
struct input_dev *dev;
@@ -301,26 +298,25 @@ static struct {
unsigned char *name;
} lk_response[] = {
#define RESPONSE(x) { .value = (x), .name = #x, }
- RESPONSE (LK_STUCK_KEY),
- RESPONSE (LK_SELFTEST_FAILED),
- RESPONSE (LK_ALL_KEYS_UP),
- RESPONSE (LK_METRONOME),
- RESPONSE (LK_OUTPUT_ERROR),
- RESPONSE (LK_INPUT_ERROR),
- RESPONSE (LK_KBD_LOCKED),
- RESPONSE (LK_KBD_TEST_MODE_ACK),
- RESPONSE (LK_PREFIX_KEY_DOWN),
- RESPONSE (LK_MODE_CHANGE_ACK),
- RESPONSE (LK_RESPONSE_RESERVED),
+ RESPONSE(LK_STUCK_KEY),
+ RESPONSE(LK_SELFTEST_FAILED),
+ RESPONSE(LK_ALL_KEYS_UP),
+ RESPONSE(LK_METRONOME),
+ RESPONSE(LK_OUTPUT_ERROR),
+ RESPONSE(LK_INPUT_ERROR),
+ RESPONSE(LK_KBD_LOCKED),
+ RESPONSE(LK_KBD_TEST_MODE_ACK),
+ RESPONSE(LK_PREFIX_KEY_DOWN),
+ RESPONSE(LK_MODE_CHANGE_ACK),
+ RESPONSE(LK_RESPONSE_RESERVED),
#undef RESPONSE
};
-static unsigned char *
-response_name (unsigned char value)
+static unsigned char *response_name(unsigned char value)
{
int i;
- for (i = 0; i < ARRAY_SIZE (lk_response); i++)
+ for (i = 0; i < ARRAY_SIZE(lk_response); i++)
if (lk_response[i].value == value)
return lk_response[i].name;
@@ -331,8 +327,7 @@ response_name (unsigned char value)
/*
* Calculate volume parameter byte for a given volume.
*/
-static unsigned char
-volume_to_hw (int volume_percent)
+static unsigned char volume_to_hw(int volume_percent)
{
unsigned char ret = 0;
@@ -363,8 +358,7 @@ volume_to_hw (int volume_percent)
return ret;
}
-static void
-lkkbd_detection_done (struct lkkbd *lk)
+static void lkkbd_detection_done(struct lkkbd *lk)
{
int i;
@@ -377,190 +371,202 @@ lkkbd_detection_done (struct lkkbd *lk)
* Print keyboard name and modify Compose=Alt on user's request.
*/
switch (lk->id[4]) {
- case 1:
- strlcpy (lk->name, "DEC LK201 keyboard",
- sizeof (lk->name));
-
- if (lk201_compose_is_alt)
- lk->keycode[0xb1] = KEY_LEFTALT;
- break;
-
- case 2:
- strlcpy (lk->name, "DEC LK401 keyboard",
- sizeof (lk->name));
- break;
-
- default:
- strlcpy (lk->name, "Unknown DEC keyboard",
- sizeof (lk->name));
- printk (KERN_ERR "lkkbd: keyboard on %s is unknown, "
- "please report to Jan-Benedict Glaw "
- "<jbglaw@lug-owl.de>\n", lk->phys);
- printk (KERN_ERR "lkkbd: keyboard ID'ed as:");
- for (i = 0; i < LK_NUM_IGNORE_BYTES; i++)
- printk (" 0x%02x", lk->id[i]);
- printk ("\n");
- break;
+ case 1:
+ strlcpy(lk->name, "DEC LK201 keyboard", sizeof(lk->name));
+
+ if (lk201_compose_is_alt)
+ lk->keycode[0xb1] = KEY_LEFTALT;
+ break;
+
+ case 2:
+ strlcpy(lk->name, "DEC LK401 keyboard", sizeof(lk->name));
+ break;
+
+ default:
+ strlcpy(lk->name, "Unknown DEC keyboard", sizeof(lk->name));
+ printk(KERN_ERR
+ "lkkbd: keyboard on %s is unknown, please report to "
+ "Jan-Benedict Glaw <jbglaw@lug-owl.de>\n", lk->phys);
+ printk(KERN_ERR "lkkbd: keyboard ID'ed as:");
+ for (i = 0; i < LK_NUM_IGNORE_BYTES; i++)
+ printk(" 0x%02x", lk->id[i]);
+ printk("\n");
+ break;
}
- printk (KERN_INFO "lkkbd: keyboard on %s identified as: %s\n",
- lk->phys, lk->name);
+
+ printk(KERN_INFO "lkkbd: keyboard on %s identified as: %s\n",
+ lk->phys, lk->name);
/*
* Report errors during keyboard boot-up.
*/
switch (lk->id[2]) {
- case 0x00:
- /* All okay */
- break;
-
- case LK_STUCK_KEY:
- printk (KERN_ERR "lkkbd: Stuck key on keyboard at "
- "%s\n", lk->phys);
- break;
-
- case LK_SELFTEST_FAILED:
- printk (KERN_ERR "lkkbd: Selftest failed on keyboard "
- "at %s, keyboard may not work "
- "properly\n", lk->phys);
- break;
-
- default:
- printk (KERN_ERR "lkkbd: Unknown error %02x on "
- "keyboard at %s\n", lk->id[2],
- lk->phys);
- break;
+ case 0x00:
+ /* All okay */
+ break;
+
+ case LK_STUCK_KEY:
+ printk(KERN_ERR "lkkbd: Stuck key on keyboard at %s\n",
+ lk->phys);
+ break;
+
+ case LK_SELFTEST_FAILED:
+ printk(KERN_ERR
+ "lkkbd: Selftest failed on keyboard at %s, "
+ "keyboard may not work properly\n", lk->phys);
+ break;
+
+ default:
+ printk(KERN_ERR
+ "lkkbd: Unknown error %02x on keyboard at %s\n",
+ lk->id[2], lk->phys);
+ break;
}
/*
* Try to hint user if there's a stuck key.
*/
if (lk->id[2] == LK_STUCK_KEY && lk->id[3] != 0)
- printk (KERN_ERR "Scancode of stuck key is 0x%02x, keycode "
- "is 0x%04x\n", lk->id[3],
- lk->keycode[lk->id[3]]);
-
- return;
+ printk(KERN_ERR
+ "Scancode of stuck key is 0x%02x, keycode is 0x%04x\n",
+ lk->id[3], lk->keycode[lk->id[3]]);
}
/*
* lkkbd_interrupt() is called by the low level driver when a character
* is received.
*/
-static irqreturn_t
-lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags)
+static irqreturn_t lkkbd_interrupt(struct serio *serio,
+ unsigned char data, unsigned int flags)
{
- struct lkkbd *lk = serio_get_drvdata (serio);
+ struct lkkbd *lk = serio_get_drvdata(serio);
+ struct input_dev *input_dev = lk->dev;
+ unsigned int keycode;
int i;
- DBG (KERN_INFO "Got byte 0x%02x\n", data);
+ DBG(KERN_INFO "Got byte 0x%02x\n", data);
if (lk->ignore_bytes > 0) {
- DBG (KERN_INFO "Ignoring a byte on %s\n", lk->name);
+ DBG(KERN_INFO "Ignoring a byte on %s\n", lk->name);
lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data;
if (lk->ignore_bytes == 0)
- lkkbd_detection_done (lk);
+ lkkbd_detection_done(lk);
return IRQ_HANDLED;
}
switch (data) {
- case LK_ALL_KEYS_UP:
- for (i = 0; i < ARRAY_SIZE (lkkbd_keycode); i++)
- if (lk->keycode[i] != KEY_RESERVED)
- input_report_key (lk->dev, lk->keycode[i], 0);
- input_sync (lk->dev);
- break;
-
- case 0x01:
- DBG (KERN_INFO "Got 0x01, scheduling re-initialization\n");
- lk->ignore_bytes = LK_NUM_IGNORE_BYTES;
- lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data;
- schedule_work (&lk->tq);
- break;
-
- case LK_METRONOME:
- case LK_OUTPUT_ERROR:
- case LK_INPUT_ERROR:
- case LK_KBD_LOCKED:
- case LK_KBD_TEST_MODE_ACK:
- case LK_PREFIX_KEY_DOWN:
- case LK_MODE_CHANGE_ACK:
- case LK_RESPONSE_RESERVED:
- DBG (KERN_INFO "Got %s and don't know how to handle...\n",
- response_name (data));
- break;
-
- default:
- if (lk->keycode[data] != KEY_RESERVED) {
- if (!test_bit (lk->keycode[data], lk->dev->key))
- input_report_key (lk->dev, lk->keycode[data], 1);
- else
- input_report_key (lk->dev, lk->keycode[data], 0);
- input_sync (lk->dev);
- } else
- printk (KERN_WARNING "%s: Unknown key with "
- "scancode 0x%02x on %s.\n",
- __FILE__, data, lk->name);
+ case LK_ALL_KEYS_UP:
+ for (i = 0; i < ARRAY_SIZE(lkkbd_keycode); i++)
+ input_report_key(input_dev, lk->keycode[i], 0);
+ input_sync(input_dev);
+ break;
+
+ case 0x01:
+ DBG(KERN_INFO "Got 0x01, scheduling re-initialization\n");
+ lk->ignore_bytes = LK_NUM_IGNORE_BYTES;
+ lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data;
+ schedule_work(&lk->tq);
+ break;
+
+ case LK_METRONOME:
+ case LK_OUTPUT_ERROR:
+ case LK_INPUT_ERROR:
+ case LK_KBD_LOCKED:
+ case LK_KBD_TEST_MODE_ACK:
+ case LK_PREFIX_KEY_DOWN:
+ case LK_MODE_CHANGE_ACK:
+ case LK_RESPONSE_RESERVED:
+ DBG(KERN_INFO "Got %s and don't know how to handle...\n",
+ response_name(data));
+ break;
+
+ default:
+ keycode = lk->keycode[data];
+ if (keycode != KEY_RESERVED) {
+ input_report_key(input_dev, keycode,
+ !test_bit(keycode, input_dev->key));
+ input_sync(input_dev);
+ } else {
+ printk(KERN_WARNING
+ "%s: Unknown key with scancode 0x%02x on %s.\n",
+ __FILE__, data, lk->name);
+ }
}
return IRQ_HANDLED;
}
+static void lkkbd_toggle_leds(struct lkkbd *lk)
+{
+ struct serio *serio = lk->serio;
+ unsigned char leds_on = 0;
+ unsigned char leds_off = 0;
+
+ CHECK_LED(lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK);
+ CHECK_LED(lk, leds_on, leds_off, LED_COMPOSE, LK_LED_COMPOSE);
+ CHECK_LED(lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK);
+ CHECK_LED(lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT);
+ if (leds_on != 0) {
+ serio_write(serio, LK_CMD_LED_ON);
+ serio_write(serio, leds_on);
+ }
+ if (leds_off != 0) {
+ serio_write(serio, LK_CMD_LED_OFF);
+ serio_write(serio, leds_off);
+ }
+}
+
+static void lkkbd_toggle_keyclick(struct lkkbd *lk, bool on)
+{
+ struct serio *serio = lk->serio;
+
+ if (on) {
+ DBG("%s: Activating key clicks\n", __func__);
+ serio_write(serio, LK_CMD_ENABLE_KEYCLICK);
+ serio_write(serio, volume_to_hw(lk->keyclick_volume));
+ serio_write(serio, LK_CMD_ENABLE_CTRCLICK);
+ serio_write(serio, volume_to_hw(lk->ctrlclick_volume));
+ } else {
+ DBG("%s: Deactivating key clicks\n", __func__);
+ serio_write(serio, LK_CMD_DISABLE_KEYCLICK);
+ serio_write(serio, LK_CMD_DISABLE_CTRCLICK);
+ }
+
+}
+
/*
* lkkbd_event() handles events from the input module.
*/
-static int
-lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code,
- int value)
+static int lkkbd_event(struct input_dev *dev,
+ unsigned int type, unsigned int code, int value)
{
- struct lkkbd *lk = input_get_drvdata (dev);
- unsigned char leds_on = 0;
- unsigned char leds_off = 0;
+ struct lkkbd *lk = input_get_drvdata(dev);
switch (type) {
- case EV_LED:
- CHECK_LED (lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK);
- CHECK_LED (lk, leds_on, leds_off, LED_COMPOSE, LK_LED_COMPOSE);
- CHECK_LED (lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK);
- CHECK_LED (lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT);
- if (leds_on != 0) {
- serio_write (lk->serio, LK_CMD_LED_ON);
- serio_write (lk->serio, leds_on);
- }
- if (leds_off != 0) {
- serio_write (lk->serio, LK_CMD_LED_OFF);
- serio_write (lk->serio, leds_off);
- }
+ case EV_LED:
+ lkkbd_toggle_leds(lk);
+ return 0;
+
+ case EV_SND:
+ switch (code) {
+ case SND_CLICK:
+ lkkbd_toggle_keyclick(lk, value);
return 0;
- case EV_SND:
- switch (code) {
- case SND_CLICK:
- if (value == 0) {
- DBG ("%s: Deactivating key clicks\n", __func__);
- serio_write (lk->serio, LK_CMD_DISABLE_KEYCLICK);
- serio_write (lk->serio, LK_CMD_DISABLE_CTRCLICK);
- } else {
- DBG ("%s: Activating key clicks\n", __func__);
- serio_write (lk->serio, LK_CMD_ENABLE_KEYCLICK);
- serio_write (lk->serio, volume_to_hw (lk->keyclick_volume));
- serio_write (lk->serio, LK_CMD_ENABLE_CTRCLICK);
- serio_write (lk->serio, volume_to_hw (lk->ctrlclick_volume));
- }
- return 0;
-
- case SND_BELL:
- if (value != 0)
- serio_write (lk->serio, LK_CMD_SOUND_BELL);
-
- return 0;
- }
- break;
-
- default:
- printk (KERN_ERR "%s (): Got unknown type %d, code %d, value %d\n",
- __func__, type, code, value);
+ case SND_BELL:
+ if (value != 0)
+ serio_write(lk->serio, LK_CMD_SOUND_BELL);
+
+ return 0;
+ }
+
+ break;
+
+ default:
+ printk(KERN_ERR "%s(): Got unknown type %d, code %d, value %d\n",
+ __func__, type, code, value);
}
return -1;
@@ -570,79 +576,56 @@ lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code,
* lkkbd_reinit() sets leds and beeps to a state the computer remembers they
* were in.
*/
-static void
-lkkbd_reinit (struct work_struct *work)
+static void lkkbd_reinit(struct work_struct *work)
{
struct lkkbd *lk = container_of(work, struct lkkbd, tq);
int division;
- unsigned char leds_on = 0;
- unsigned char leds_off = 0;
/* Ask for ID */
- serio_write (lk->serio, LK_CMD_REQUEST_ID);
+ serio_write(lk->serio, LK_CMD_REQUEST_ID);
/* Reset parameters */
- serio_write (lk->serio, LK_CMD_SET_DEFAULTS);
+ serio_write(lk->serio, LK_CMD_SET_DEFAULTS);
/* Set LEDs */
- CHECK_LED (lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK);
- CHECK_LED (lk, leds_on, leds_off, LED_COMPOSE, LK_LED_COMPOSE);
- CHECK_LED (lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK);
- CHECK_LED (lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT);
- if (leds_on != 0) {
- serio_write (lk->serio, LK_CMD_LED_ON);
- serio_write (lk->serio, leds_on);
- }
- if (leds_off != 0) {
- serio_write (lk->serio, LK_CMD_LED_OFF);
- serio_write (lk->serio, leds_off);
- }
+ lkkbd_toggle_leds(lk);
/*
* Try to activate extended LK401 mode. This command will
* only work with a LK401 keyboard and grants access to
* LAlt, RAlt, RCompose and RShift.
*/
- serio_write (lk->serio, LK_CMD_ENABLE_LK401);
+ serio_write(lk->serio, LK_CMD_ENABLE_LK401);
/* Set all keys to UPDOWN mode */
for (division = 1; division <= 14; division++)
- serio_write (lk->serio, LK_CMD_SET_MODE (LK_MODE_UPDOWN,
- division));
+ serio_write(lk->serio,
+ LK_CMD_SET_MODE(LK_MODE_UPDOWN, division));
/* Enable bell and set volume */
- serio_write (lk->serio, LK_CMD_ENABLE_BELL);
- serio_write (lk->serio, volume_to_hw (lk->bell_volume));
+ serio_write(lk->serio, LK_CMD_ENABLE_BELL);
+ serio_write(lk->serio, volume_to_hw(lk->bell_volume));
/* Enable/disable keyclick (and possibly set volume) */
- if (test_bit (SND_CLICK, lk->dev->snd)) {
- serio_write (lk->serio, LK_CMD_ENABLE_KEYCLICK);
- serio_write (lk->serio, volume_to_hw (lk->keyclick_volume));
- serio_write (lk->serio, LK_CMD_ENABLE_CTRCLICK);
- serio_write (lk->serio, volume_to_hw (lk->ctrlclick_volume));
- } else {
- serio_write (lk->serio, LK_CMD_DISABLE_KEYCLICK);
- serio_write (lk->serio, LK_CMD_DISABLE_CTRCLICK);
- }
+ lkkbd_toggle_keyclick(lk, test_bit(SND_CLICK, lk->dev->snd));
/* Sound the bell if needed */
- if (test_bit (SND_BELL, lk->dev->snd))
- serio_write (lk->serio, LK_CMD_SOUND_BELL);
+ if (test_bit(SND_BELL, lk->dev->snd))
+ serio_write(lk->serio, LK_CMD_SOUND_BELL);
}
/*
* lkkbd_connect() probes for a LK keyboard and fills the necessary structures.
*/
-static int
-lkkbd_connect (struct serio *serio, struct serio_driver *drv)
+static int lkkbd_connect(struct serio *serio, struct serio_driver *drv)
{
struct lkkbd *lk;
struct input_dev *input_dev;
int i;
int err;
- lk = kzalloc (sizeof (struct lkkbd), GFP_KERNEL);
- input_dev = input_allocate_device ();
+ lk = kzalloc(sizeof(struct lkkbd), GFP_KERNEL);
+ input_dev = input_allocate_device();
if (!lk || !input_dev) {
err = -ENOMEM;
goto fail1;
@@ -650,14 +633,14 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv)
lk->serio = serio;
lk->dev = input_dev;
- INIT_WORK (&lk->tq, lkkbd_reinit);
+ INIT_WORK(&lk->tq, lkkbd_reinit);
lk->bell_volume = bell_volume;
lk->keyclick_volume = keyclick_volume;
lk->ctrlclick_volume = ctrlclick_volume;
- memcpy (lk->keycode, lkkbd_keycode, sizeof (lk_keycode_t) * LK_NUM_KEYCODES);
+ memcpy(lk->keycode, lkkbd_keycode, sizeof(lk->keycode));
- strlcpy (lk->name, "DEC LK keyboard", sizeof(lk->name));
- snprintf (lk->phys, sizeof(lk->phys), "%s/input0", serio->phys);
+ strlcpy(lk->name, "DEC LK keyboard", sizeof(lk->name));
+ snprintf(lk->phys, sizeof(lk->phys), "%s/input0", serio->phys);
input_dev->name = lk->name;
input_dev->phys = lk->phys;
@@ -668,62 +651,61 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv)
input_dev->dev.parent = &serio->dev;
input_dev->event = lkkbd_event;
- input_set_drvdata (input_dev, lk);
+ input_set_drvdata(input_dev, lk);
- set_bit (EV_KEY, input_dev->evbit);
- set_bit (EV_LED, input_dev->evbit);
- set_bit (EV_SND, input_dev->evbit);
- set_bit (EV_REP, input_dev->evbit);
- set_bit (LED_CAPSL, input_dev->ledbit);
- set_bit (LED_SLEEP, input_dev->ledbit);
- set_bit (LED_COMPOSE, input_dev->ledbit);
- set_bit (LED_SCROLLL, input_dev->ledbit);
- set_bit (SND_BELL, input_dev->sndbit);
- set_bit (SND_CLICK, input_dev->sndbit);
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(EV_LED, input_dev->evbit);
+ __set_bit(EV_SND, input_dev->evbit);
+ __set_bit(EV_REP, input_dev->evbit);
+ __set_bit(LED_CAPSL, input_dev->ledbit);
+ __set_bit(LED_SLEEP, input_dev->ledbit);
+ __set_bit(LED_COMPOSE, input_dev->ledbit);
+ __set_bit(LED_SCROLLL, input_dev->ledbit);
+ __set_bit(SND_BELL, input_dev->sndbit);
+ __set_bit(SND_CLICK, input_dev->sndbit);
input_dev->keycode = lk->keycode;
- input_dev->keycodesize = sizeof (lk_keycode_t);
- input_dev->keycodemax = LK_NUM_KEYCODES;
+ input_dev->keycodesize = sizeof(lk->keycode[0]);
+ input_dev->keycodemax = ARRAY_SIZE(lk->keycode);
for (i = 0; i < LK_NUM_KEYCODES; i++)
- __set_bit (lk->keycode[i], input_dev->keybit);
+ __set_bit(lk->keycode[i], input_dev->keybit);
__clear_bit(KEY_RESERVED, input_dev->keybit);
- serio_set_drvdata (serio, lk);
+ serio_set_drvdata(serio, lk);
- err = serio_open (serio, drv);
+ err = serio_open(serio, drv);
if (err)
goto fail2;
- err = input_register_device (lk->dev);
+ err = input_register_device(lk->dev);
if (err)
goto fail3;
- serio_write (lk->serio, LK_CMD_POWERCYCLE_RESET);
+ serio_write(lk->serio, LK_CMD_POWERCYCLE_RESET);
return 0;
- fail3: serio_close (serio);
- fail2: serio_set_drvdata (serio, NULL);
- fail1: input_free_device (input_dev);
- kfree (lk);
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
+ kfree(lk);
return err;
}
/*
* lkkbd_disconnect() unregisters and closes behind us.
*/
-static void
-lkkbd_disconnect (struct serio *serio)
+static void lkkbd_disconnect(struct serio *serio)
{
- struct lkkbd *lk = serio_get_drvdata (serio);
-
- input_get_device (lk->dev);
- input_unregister_device (lk->dev);
- serio_close (serio);
- serio_set_drvdata (serio, NULL);
- input_put_device (lk->dev);
- kfree (lk);
+ struct lkkbd *lk = serio_get_drvdata(serio);
+
+ input_get_device(lk->dev);
+ input_unregister_device(lk->dev);
+ serio_close(serio);
+ serio_set_drvdata(serio, NULL);
+ input_put_device(lk->dev);
+ kfree(lk);
}
static struct serio_device_id lkkbd_serio_ids[] = {
@@ -752,18 +734,16 @@ static struct serio_driver lkkbd_drv = {
/*
* The functions for insering/removing us as a module.
*/
-static int __init
-lkkbd_init (void)
+static int __init lkkbd_init(void)
{
return serio_register_driver(&lkkbd_drv);
}
-static void __exit
-lkkbd_exit (void)
+static void __exit lkkbd_exit(void)
{
serio_unregister_driver(&lkkbd_drv);
}
-module_init (lkkbd_init);
-module_exit (lkkbd_exit);
+module_init(lkkbd_init);
+module_exit(lkkbd_exit);
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
index bba85add35a3..1a494d505431 100644
--- a/drivers/input/keyboard/omap-keypad.c
+++ b/drivers/input/keyboard/omap-keypad.c
@@ -35,12 +35,12 @@
#include <linux/mutex.h>
#include <linux/errno.h>
#include <mach/gpio.h>
-#include <mach/keypad.h>
-#include <mach/menelaus.h>
+#include <plat/keypad.h>
+#include <plat/menelaus.h>
#include <asm/irq.h>
#include <mach/hardware.h>
#include <asm/io.h>
-#include <mach/mux.h>
+#include <plat/mux.h>
#undef NEW_BOARD_LEARNING_MODE
diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c
index 216a559f55ea..ea821b546969 100644
--- a/drivers/input/misc/hp_sdc_rtc.c
+++ b/drivers/input/misc/hp_sdc_rtc.c
@@ -209,7 +209,7 @@ static inline int hp_sdc_rtc_read_rt(struct timeval *res) {
/* Read the i8042 fast handshake timer */
static inline int hp_sdc_rtc_read_fhs(struct timeval *res) {
- uint64_t raw;
+ int64_t raw;
unsigned int tenms;
raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_FHS, 2);
diff --git a/drivers/input/misc/pcf50633-input.c b/drivers/input/misc/pcf50633-input.c
index 039dcb00ebd9..008de0c5834b 100644
--- a/drivers/input/misc/pcf50633-input.c
+++ b/drivers/input/misc/pcf50633-input.c
@@ -55,7 +55,6 @@ pcf50633_input_irq(int irq, void *data)
static int __devinit pcf50633_input_probe(struct platform_device *pdev)
{
struct pcf50633_input *input;
- struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data;
struct input_dev *input_dev;
int ret;
@@ -71,7 +70,7 @@ static int __devinit pcf50633_input_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, input);
- input->pcf = pdata->pcf;
+ input->pcf = dev_to_pcf50633(pdev->dev.parent);
input->input_dev = input_dev;
input_dev->name = "PCF50633 PMU events";
@@ -85,9 +84,9 @@ static int __devinit pcf50633_input_probe(struct platform_device *pdev)
kfree(input);
return ret;
}
- pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ONKEYR,
+ pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYR,
pcf50633_input_irq, input);
- pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ONKEYF,
+ pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYF,
pcf50633_input_irq, input);
return 0;
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index a932179c4c9e..00eb9d651d97 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -1263,7 +1263,7 @@ static int __devinit setup_input_dev(void)
if (!wistron_idev)
return -ENOMEM;
- wistron_idev->flush = wistron_flush;
+ wistron_idev->open = wistron_flush;
wistron_idev->poll = wistron_poll;
wistron_idev->poll_interval = POLL_INTERVAL_DEFAULT;
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
index de745d751162..ab5dc5f5fd83 100644
--- a/drivers/input/mouse/logips2pp.c
+++ b/drivers/input/mouse/logips2pp.c
@@ -219,7 +219,7 @@ static const struct ps2pp_info *get_model_info(unsigned char model)
PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL },
{ 72, PS2PP_KIND_TRACKMAN, 0 }, /* T-CH11: TrackMan Marble */
- { 73, 0, PS2PP_SIDE_BTN },
+ { 73, PS2PP_KIND_TRACKMAN, PS2PP_SIDE_BTN }, /* TrackMan FX */
{ 75, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 76, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 79, PS2PP_KIND_TRACKMAN, PS2PP_WHEEL }, /* TrackMan with wheel */
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index b66ff1ac7dea..f4a61252bcc9 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -652,6 +652,16 @@ static const struct dmi_system_id toshiba_dmi_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M300"),
},
+
+ },
+ {
+ .ident = "Toshiba Portege M300",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Portable PC"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Version 1.0"),
+ },
+
},
{ }
};
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
index 70111443678e..bf2c0c80d6cc 100644
--- a/drivers/input/mouse/vsxxxaa.c
+++ b/drivers/input/mouse/vsxxxaa.c
@@ -86,27 +86,28 @@
#define DRIVER_DESC "Driver for DEC VSXXX-AA and -GA mice and VSXXX-AB tablet"
-MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
-MODULE_DESCRIPTION (DRIVER_DESC);
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
#undef VSXXXAA_DEBUG
#ifdef VSXXXAA_DEBUG
-#define DBG(x...) printk (x)
+#define DBG(x...) printk(x)
#else
#define DBG(x...) do {} while (0)
#endif
#define VSXXXAA_INTRO_MASK 0x80
#define VSXXXAA_INTRO_HEAD 0x80
-#define IS_HDR_BYTE(x) (((x) & VSXXXAA_INTRO_MASK) \
- == VSXXXAA_INTRO_HEAD)
+#define IS_HDR_BYTE(x) \
+ (((x) & VSXXXAA_INTRO_MASK) == VSXXXAA_INTRO_HEAD)
#define VSXXXAA_PACKET_MASK 0xe0
#define VSXXXAA_PACKET_REL 0x80
#define VSXXXAA_PACKET_ABS 0xc0
#define VSXXXAA_PACKET_POR 0xa0
-#define MATCH_PACKET_TYPE(data, type) (((data) & VSXXXAA_PACKET_MASK) == (type))
+#define MATCH_PACKET_TYPE(data, type) \
+ (((data) & VSXXXAA_PACKET_MASK) == (type))
@@ -123,52 +124,50 @@ struct vsxxxaa {
char phys[32];
};
-static void
-vsxxxaa_drop_bytes (struct vsxxxaa *mouse, int num)
+static void vsxxxaa_drop_bytes(struct vsxxxaa *mouse, int num)
{
- if (num >= mouse->count)
+ if (num >= mouse->count) {
mouse->count = 0;
- else {
- memmove (mouse->buf, mouse->buf + num - 1, BUFLEN - num);
+ } else {
+ memmove(mouse->buf, mouse->buf + num - 1, BUFLEN - num);
mouse->count -= num;
}
}
-static void
-vsxxxaa_queue_byte (struct vsxxxaa *mouse, unsigned char byte)
+static void vsxxxaa_queue_byte(struct vsxxxaa *mouse, unsigned char byte)
{
if (mouse->count == BUFLEN) {
- printk (KERN_ERR "%s on %s: Dropping a byte of full buffer.\n",
- mouse->name, mouse->phys);
- vsxxxaa_drop_bytes (mouse, 1);
+ printk(KERN_ERR "%s on %s: Dropping a byte of full buffer.\n",
+ mouse->name, mouse->phys);
+ vsxxxaa_drop_bytes(mouse, 1);
}
- DBG (KERN_INFO "Queueing byte 0x%02x\n", byte);
+
+ DBG(KERN_INFO "Queueing byte 0x%02x\n", byte);
mouse->buf[mouse->count++] = byte;
}
-static void
-vsxxxaa_detection_done (struct vsxxxaa *mouse)
+static void vsxxxaa_detection_done(struct vsxxxaa *mouse)
{
switch (mouse->type) {
- case 0x02:
- strlcpy (mouse->name, "DEC VSXXX-AA/-GA mouse",
- sizeof (mouse->name));
- break;
-
- case 0x04:
- strlcpy (mouse->name, "DEC VSXXX-AB digitizer",
- sizeof (mouse->name));
- break;
-
- default:
- snprintf (mouse->name, sizeof (mouse->name),
- "unknown DEC pointer device (type = 0x%02x)",
- mouse->type);
- break;
+ case 0x02:
+ strlcpy(mouse->name, "DEC VSXXX-AA/-GA mouse",
+ sizeof(mouse->name));
+ break;
+
+ case 0x04:
+ strlcpy(mouse->name, "DEC VSXXX-AB digitizer",
+ sizeof(mouse->name));
+ break;
+
+ default:
+ snprintf(mouse->name, sizeof(mouse->name),
+ "unknown DEC pointer device (type = 0x%02x)",
+ mouse->type);
+ break;
}
- printk (KERN_INFO
+ printk(KERN_INFO
"Found %s version 0x%02x from country 0x%02x on port %s\n",
mouse->name, mouse->version, mouse->country, mouse->phys);
}
@@ -176,42 +175,38 @@ vsxxxaa_detection_done (struct vsxxxaa *mouse)
/*
* Returns number of bytes to be dropped, 0 if packet is okay.
*/
-static int
-vsxxxaa_check_packet (struct vsxxxaa *mouse, int packet_len)
+static int vsxxxaa_check_packet(struct vsxxxaa *mouse, int packet_len)
{
int i;
/* First byte must be a header byte */
- if (!IS_HDR_BYTE (mouse->buf[0])) {
- DBG ("vsck: len=%d, 1st=0x%02x\n", packet_len, mouse->buf[0]);
+ if (!IS_HDR_BYTE(mouse->buf[0])) {
+ DBG("vsck: len=%d, 1st=0x%02x\n", packet_len, mouse->buf[0]);
return 1;
}
/* Check all following bytes */
- if (packet_len > 1) {
- for (i = 1; i < packet_len; i++) {
- if (IS_HDR_BYTE (mouse->buf[i])) {
- printk (KERN_ERR "Need to drop %d bytes "
- "of a broken packet.\n",
- i - 1);
- DBG (KERN_INFO "check: len=%d, b[%d]=0x%02x\n",
- packet_len, i, mouse->buf[i]);
- return i - 1;
- }
+ for (i = 1; i < packet_len; i++) {
+ if (IS_HDR_BYTE(mouse->buf[i])) {
+ printk(KERN_ERR
+ "Need to drop %d bytes of a broken packet.\n",
+ i - 1);
+ DBG(KERN_INFO "check: len=%d, b[%d]=0x%02x\n",
+ packet_len, i, mouse->buf[i]);
+ return i - 1;
}
}
return 0;
}
-static __inline__ int
-vsxxxaa_smells_like_packet (struct vsxxxaa *mouse, unsigned char type, size_t len)
+static inline int vsxxxaa_smells_like_packet(struct vsxxxaa *mouse,
+ unsigned char type, size_t len)
{
- return (mouse->count >= len) && MATCH_PACKET_TYPE (mouse->buf[0], type);
+ return mouse->count >= len && MATCH_PACKET_TYPE(mouse->buf[0], type);
}
-static void
-vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse)
+static void vsxxxaa_handle_REL_packet(struct vsxxxaa *mouse)
{
struct input_dev *dev = mouse->dev;
unsigned char *buf = mouse->buf;
@@ -232,43 +227,42 @@ vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse)
* 0, bit 4 of byte 0 is direction.
*/
dx = buf[1] & 0x7f;
- dx *= ((buf[0] >> 4) & 0x01)? 1: -1;
+ dx *= ((buf[0] >> 4) & 0x01) ? 1 : -1;
/*
* Low 7 bit of byte 2 are abs(dy), bit 7 is
* 0, bit 3 of byte 0 is direction.
*/
dy = buf[2] & 0x7f;
- dy *= ((buf[0] >> 3) & 0x01)? -1: 1;
+ dy *= ((buf[0] >> 3) & 0x01) ? -1 : 1;
/*
* Get button state. It's the low three bits
* (for three buttons) of byte 0.
*/
- left = (buf[0] & 0x04)? 1: 0;
- middle = (buf[0] & 0x02)? 1: 0;
- right = (buf[0] & 0x01)? 1: 0;
+ left = buf[0] & 0x04;
+ middle = buf[0] & 0x02;
+ right = buf[0] & 0x01;
- vsxxxaa_drop_bytes (mouse, 3);
+ vsxxxaa_drop_bytes(mouse, 3);
- DBG (KERN_INFO "%s on %s: dx=%d, dy=%d, buttons=%s%s%s\n",
- mouse->name, mouse->phys, dx, dy,
- left? "L": "l", middle? "M": "m", right? "R": "r");
+ DBG(KERN_INFO "%s on %s: dx=%d, dy=%d, buttons=%s%s%s\n",
+ mouse->name, mouse->phys, dx, dy,
+ left ? "L" : "l", middle ? "M" : "m", right ? "R" : "r");
/*
* Report what we've found so far...
*/
- input_report_key (dev, BTN_LEFT, left);
- input_report_key (dev, BTN_MIDDLE, middle);
- input_report_key (dev, BTN_RIGHT, right);
- input_report_key (dev, BTN_TOUCH, 0);
- input_report_rel (dev, REL_X, dx);
- input_report_rel (dev, REL_Y, dy);
- input_sync (dev);
+ input_report_key(dev, BTN_LEFT, left);
+ input_report_key(dev, BTN_MIDDLE, middle);
+ input_report_key(dev, BTN_RIGHT, right);
+ input_report_key(dev, BTN_TOUCH, 0);
+ input_report_rel(dev, REL_X, dx);
+ input_report_rel(dev, REL_Y, dy);
+ input_sync(dev);
}
-static void
-vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse)
+static void vsxxxaa_handle_ABS_packet(struct vsxxxaa *mouse)
{
struct input_dev *dev = mouse->dev;
unsigned char *buf = mouse->buf;
@@ -296,32 +290,31 @@ vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse)
/*
* Get button state. It's bits <4..1> of byte 0.
*/
- left = (buf[0] & 0x02)? 1: 0;
- middle = (buf[0] & 0x04)? 1: 0;
- right = (buf[0] & 0x08)? 1: 0;
- touch = (buf[0] & 0x10)? 1: 0;
+ left = buf[0] & 0x02;
+ middle = buf[0] & 0x04;
+ right = buf[0] & 0x08;
+ touch = buf[0] & 0x10;
- vsxxxaa_drop_bytes (mouse, 5);
+ vsxxxaa_drop_bytes(mouse, 5);
- DBG (KERN_INFO "%s on %s: x=%d, y=%d, buttons=%s%s%s%s\n",
- mouse->name, mouse->phys, x, y,
- left? "L": "l", middle? "M": "m",
- right? "R": "r", touch? "T": "t");
+ DBG(KERN_INFO "%s on %s: x=%d, y=%d, buttons=%s%s%s%s\n",
+ mouse->name, mouse->phys, x, y,
+ left ? "L" : "l", middle ? "M" : "m",
+ right ? "R" : "r", touch ? "T" : "t");
/*
* Report what we've found so far...
*/
- input_report_key (dev, BTN_LEFT, left);
- input_report_key (dev, BTN_MIDDLE, middle);
- input_report_key (dev, BTN_RIGHT, right);
- input_report_key (dev, BTN_TOUCH, touch);
- input_report_abs (dev, ABS_X, x);
- input_report_abs (dev, ABS_Y, y);
- input_sync (dev);
+ input_report_key(dev, BTN_LEFT, left);
+ input_report_key(dev, BTN_MIDDLE, middle);
+ input_report_key(dev, BTN_RIGHT, right);
+ input_report_key(dev, BTN_TOUCH, touch);
+ input_report_abs(dev, ABS_X, x);
+ input_report_abs(dev, ABS_Y, y);
+ input_sync(dev);
}
-static void
-vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse)
+static void vsxxxaa_handle_POR_packet(struct vsxxxaa *mouse)
{
struct input_dev *dev = mouse->dev;
unsigned char *buf = mouse->buf;
@@ -356,24 +349,24 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse)
* (for three buttons) of byte 0. Maybe even the bit <3>
* has some meaning if a tablet is attached.
*/
- left = (buf[0] & 0x04)? 1: 0;
- middle = (buf[0] & 0x02)? 1: 0;
- right = (buf[0] & 0x01)? 1: 0;
+ left = buf[0] & 0x04;
+ middle = buf[0] & 0x02;
+ right = buf[0] & 0x01;
- vsxxxaa_drop_bytes (mouse, 4);
- vsxxxaa_detection_done (mouse);
+ vsxxxaa_drop_bytes(mouse, 4);
+ vsxxxaa_detection_done(mouse);
if (error <= 0x1f) {
/* No (serious) error. Report buttons */
- input_report_key (dev, BTN_LEFT, left);
- input_report_key (dev, BTN_MIDDLE, middle);
- input_report_key (dev, BTN_RIGHT, right);
- input_report_key (dev, BTN_TOUCH, 0);
- input_sync (dev);
+ input_report_key(dev, BTN_LEFT, left);
+ input_report_key(dev, BTN_MIDDLE, middle);
+ input_report_key(dev, BTN_RIGHT, right);
+ input_report_key(dev, BTN_TOUCH, 0);
+ input_sync(dev);
if (error != 0)
- printk (KERN_INFO "Your %s on %s reports error=0x%02x\n",
- mouse->name, mouse->phys, error);
+ printk(KERN_INFO "Your %s on %s reports error=0x%02x\n",
+ mouse->name, mouse->phys, error);
}
@@ -381,18 +374,18 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse)
* If the mouse was hot-plugged, we need to force differential mode
* now... However, give it a second to recover from it's reset.
*/
- printk (KERN_NOTICE "%s on %s: Forceing standard packet format, "
- "incremental streaming mode and 72 samples/sec\n",
- mouse->name, mouse->phys);
- serio_write (mouse->serio, 'S'); /* Standard format */
- mdelay (50);
- serio_write (mouse->serio, 'R'); /* Incremental */
- mdelay (50);
- serio_write (mouse->serio, 'L'); /* 72 samples/sec */
+ printk(KERN_NOTICE
+ "%s on %s: Forcing standard packet format, "
+ "incremental streaming mode and 72 samples/sec\n",
+ mouse->name, mouse->phys);
+ serio_write(mouse->serio, 'S'); /* Standard format */
+ mdelay(50);
+ serio_write(mouse->serio, 'R'); /* Incremental */
+ mdelay(50);
+ serio_write(mouse->serio, 'L'); /* 72 samples/sec */
}
-static void
-vsxxxaa_parse_buffer (struct vsxxxaa *mouse)
+static void vsxxxaa_parse_buffer(struct vsxxxaa *mouse)
{
unsigned char *buf = mouse->buf;
int stray_bytes;
@@ -409,122 +402,107 @@ vsxxxaa_parse_buffer (struct vsxxxaa *mouse)
* activity on the mouse.
*/
while (mouse->count > 0 && !IS_HDR_BYTE(buf[0])) {
- printk (KERN_ERR "%s on %s: Dropping a byte to regain "
- "sync with mouse data stream...\n",
- mouse->name, mouse->phys);
- vsxxxaa_drop_bytes (mouse, 1);
+ printk(KERN_ERR "%s on %s: Dropping a byte to regain "
+ "sync with mouse data stream...\n",
+ mouse->name, mouse->phys);
+ vsxxxaa_drop_bytes(mouse, 1);
}
/*
* Check for packets we know about.
*/
- if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_REL, 3)) {
+ if (vsxxxaa_smells_like_packet(mouse, VSXXXAA_PACKET_REL, 3)) {
/* Check for broken packet */
- stray_bytes = vsxxxaa_check_packet (mouse, 3);
- if (stray_bytes > 0) {
- printk (KERN_ERR "Dropping %d bytes now...\n",
- stray_bytes);
- vsxxxaa_drop_bytes (mouse, stray_bytes);
- continue;
- }
-
- vsxxxaa_handle_REL_packet (mouse);
- continue; /* More to parse? */
- }
+ stray_bytes = vsxxxaa_check_packet(mouse, 3);
+ if (!stray_bytes)
+ vsxxxaa_handle_REL_packet(mouse);
- if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_ABS, 5)) {
+ } else if (vsxxxaa_smells_like_packet(mouse,
+ VSXXXAA_PACKET_ABS, 5)) {
/* Check for broken packet */
- stray_bytes = vsxxxaa_check_packet (mouse, 5);
- if (stray_bytes > 0) {
- printk (KERN_ERR "Dropping %d bytes now...\n",
- stray_bytes);
- vsxxxaa_drop_bytes (mouse, stray_bytes);
- continue;
- }
-
- vsxxxaa_handle_ABS_packet (mouse);
- continue; /* More to parse? */
- }
+ stray_bytes = vsxxxaa_check_packet(mouse, 5);
+ if (!stray_bytes)
+ vsxxxaa_handle_ABS_packet(mouse);
- if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_POR, 4)) {
+ } else if (vsxxxaa_smells_like_packet(mouse,
+ VSXXXAA_PACKET_POR, 4)) {
/* Check for broken packet */
- stray_bytes = vsxxxaa_check_packet (mouse, 4);
- if (stray_bytes > 0) {
- printk (KERN_ERR "Dropping %d bytes now...\n",
- stray_bytes);
- vsxxxaa_drop_bytes (mouse, stray_bytes);
- continue;
- }
-
- vsxxxaa_handle_POR_packet (mouse);
- continue; /* More to parse? */
+ stray_bytes = vsxxxaa_check_packet(mouse, 4);
+ if (!stray_bytes)
+ vsxxxaa_handle_POR_packet(mouse);
+
+ } else {
+ break; /* No REL, ABS or POR packet found */
+ }
+
+ if (stray_bytes > 0) {
+ printk(KERN_ERR "Dropping %d bytes now...\n",
+ stray_bytes);
+ vsxxxaa_drop_bytes(mouse, stray_bytes);
}
- break; /* No REL, ABS or POR packet found */
} while (1);
}
-static irqreturn_t
-vsxxxaa_interrupt (struct serio *serio, unsigned char data, unsigned int flags)
+static irqreturn_t vsxxxaa_interrupt(struct serio *serio,
+ unsigned char data, unsigned int flags)
{
- struct vsxxxaa *mouse = serio_get_drvdata (serio);
+ struct vsxxxaa *mouse = serio_get_drvdata(serio);
- vsxxxaa_queue_byte (mouse, data);
- vsxxxaa_parse_buffer (mouse);
+ vsxxxaa_queue_byte(mouse, data);
+ vsxxxaa_parse_buffer(mouse);
return IRQ_HANDLED;
}
-static void
-vsxxxaa_disconnect (struct serio *serio)
+static void vsxxxaa_disconnect(struct serio *serio)
{
- struct vsxxxaa *mouse = serio_get_drvdata (serio);
+ struct vsxxxaa *mouse = serio_get_drvdata(serio);
- serio_close (serio);
- serio_set_drvdata (serio, NULL);
- input_unregister_device (mouse->dev);
- kfree (mouse);
+ serio_close(serio);
+ serio_set_drvdata(serio, NULL);
+ input_unregister_device(mouse->dev);
+ kfree(mouse);
}
-static int
-vsxxxaa_connect (struct serio *serio, struct serio_driver *drv)
+static int vsxxxaa_connect(struct serio *serio, struct serio_driver *drv)
{
struct vsxxxaa *mouse;
struct input_dev *input_dev;
int err = -ENOMEM;
- mouse = kzalloc (sizeof (struct vsxxxaa), GFP_KERNEL);
- input_dev = input_allocate_device ();
+ mouse = kzalloc(sizeof(struct vsxxxaa), GFP_KERNEL);
+ input_dev = input_allocate_device();
if (!mouse || !input_dev)
goto fail1;
mouse->dev = input_dev;
mouse->serio = serio;
- strlcat (mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer",
- sizeof (mouse->name));
- snprintf (mouse->phys, sizeof (mouse->phys), "%s/input0", serio->phys);
+ strlcat(mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer",
+ sizeof(mouse->name));
+ snprintf(mouse->phys, sizeof(mouse->phys), "%s/input0", serio->phys);
input_dev->name = mouse->name;
input_dev->phys = mouse->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->dev.parent = &serio->dev;
- set_bit (EV_KEY, input_dev->evbit); /* We have buttons */
- set_bit (EV_REL, input_dev->evbit);
- set_bit (EV_ABS, input_dev->evbit);
- set_bit (BTN_LEFT, input_dev->keybit); /* We have 3 buttons */
- set_bit (BTN_MIDDLE, input_dev->keybit);
- set_bit (BTN_RIGHT, input_dev->keybit);
- set_bit (BTN_TOUCH, input_dev->keybit); /* ...and Tablet */
- set_bit (REL_X, input_dev->relbit);
- set_bit (REL_Y, input_dev->relbit);
- input_set_abs_params (input_dev, ABS_X, 0, 1023, 0, 0);
- input_set_abs_params (input_dev, ABS_Y, 0, 1023, 0, 0);
-
- serio_set_drvdata (serio, mouse);
-
- err = serio_open (serio, drv);
+ __set_bit(EV_KEY, input_dev->evbit); /* We have buttons */
+ __set_bit(EV_REL, input_dev->evbit);
+ __set_bit(EV_ABS, input_dev->evbit);
+ __set_bit(BTN_LEFT, input_dev->keybit); /* We have 3 buttons */
+ __set_bit(BTN_MIDDLE, input_dev->keybit);
+ __set_bit(BTN_RIGHT, input_dev->keybit);
+ __set_bit(BTN_TOUCH, input_dev->keybit); /* ...and Tablet */
+ __set_bit(REL_X, input_dev->relbit);
+ __set_bit(REL_Y, input_dev->relbit);
+ input_set_abs_params(input_dev, ABS_X, 0, 1023, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, 1023, 0, 0);
+
+ serio_set_drvdata(serio, mouse);
+
+ err = serio_open(serio, drv);
if (err)
goto fail2;
@@ -532,18 +510,18 @@ vsxxxaa_connect (struct serio *serio, struct serio_driver *drv)
* Request selftest. Standard packet format and differential
* mode will be requested after the device ID'ed successfully.
*/
- serio_write (serio, 'T'); /* Test */
+ serio_write(serio, 'T'); /* Test */
- err = input_register_device (input_dev);
+ err = input_register_device(input_dev);
if (err)
goto fail3;
return 0;
- fail3: serio_close (serio);
- fail2: serio_set_drvdata (serio, NULL);
- fail1: input_free_device (input_dev);
- kfree (mouse);
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
+ kfree(mouse);
return err;
}
@@ -570,18 +548,16 @@ static struct serio_driver vsxxxaa_drv = {
.disconnect = vsxxxaa_disconnect,
};
-static int __init
-vsxxxaa_init (void)
+static int __init vsxxxaa_init(void)
{
return serio_register_driver(&vsxxxaa_drv);
}
-static void __exit
-vsxxxaa_exit (void)
+static void __exit vsxxxaa_exit(void)
{
serio_unregister_driver(&vsxxxaa_drv);
}
-module_init (vsxxxaa_init);
-module_exit (vsxxxaa_exit);
+module_init(vsxxxaa_init);
+module_exit(vsxxxaa_exit);
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index aa533ceffe34..7e319d65ec57 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -201,4 +201,12 @@ config SERIO_XILINX_XPS_PS2
To compile this driver as a module, choose M here: the
module will be called xilinx_ps2.
+config SERIO_ALTERA_PS2
+ tristate "Altera UP PS/2 controller"
+ help
+ Say Y here if you have Altera University Program PS/2 ports.
+
+ To compile this driver as a module, choose M here: the
+ module will be called altera_ps2.
+
endif
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
index 9b6c8135955f..bf945f789d05 100644
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o
obj-$(CONFIG_SERIO_LIBPS2) += libps2.o
obj-$(CONFIG_SERIO_RAW) += serio_raw.o
obj-$(CONFIG_SERIO_XILINX_XPS_PS2) += xilinx_ps2.o
+obj-$(CONFIG_SERIO_ALTERA_PS2) += altera_ps2.o
diff --git a/drivers/input/serio/altera_ps2.c b/drivers/input/serio/altera_ps2.c
new file mode 100644
index 000000000000..f479ea50919f
--- /dev/null
+++ b/drivers/input/serio/altera_ps2.c
@@ -0,0 +1,200 @@
+/*
+ * Altera University Program PS2 controller driver
+ *
+ * Copyright (C) 2008 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * Based on sa1111ps2.c, which is:
+ * Copyright (C) 2002 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRV_NAME "altera_ps2"
+
+struct ps2if {
+ struct serio *io;
+ struct resource *iomem_res;
+ void __iomem *base;
+ unsigned irq;
+};
+
+/*
+ * Read all bytes waiting in the PS2 port. There should be
+ * at the most one, but we loop for safety.
+ */
+static irqreturn_t altera_ps2_rxint(int irq, void *dev_id)
+{
+ struct ps2if *ps2if = dev_id;
+ unsigned int status;
+ int handled = IRQ_NONE;
+
+ while ((status = readl(ps2if->base)) & 0xffff0000) {
+ serio_interrupt(ps2if->io, status & 0xff, 0);
+ handled = IRQ_HANDLED;
+ }
+
+ return handled;
+}
+
+/*
+ * Write a byte to the PS2 port.
+ */
+static int altera_ps2_write(struct serio *io, unsigned char val)
+{
+ struct ps2if *ps2if = io->port_data;
+
+ writel(val, ps2if->base);
+ return 0;
+}
+
+static int altera_ps2_open(struct serio *io)
+{
+ struct ps2if *ps2if = io->port_data;
+
+ /* clear fifo */
+ while (readl(ps2if->base) & 0xffff0000)
+ /* empty */;
+
+ writel(1, ps2if->base + 4); /* enable rx irq */
+ return 0;
+}
+
+static void altera_ps2_close(struct serio *io)
+{
+ struct ps2if *ps2if = io->port_data;
+
+ writel(0, ps2if->base); /* disable rx irq */
+}
+
+/*
+ * Add one device to this driver.
+ */
+static int altera_ps2_probe(struct platform_device *pdev)
+{
+ struct ps2if *ps2if;
+ struct serio *serio;
+ int error;
+
+ ps2if = kzalloc(sizeof(struct ps2if), GFP_KERNEL);
+ serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!ps2if || !serio) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ serio->id.type = SERIO_8042;
+ serio->write = altera_ps2_write;
+ serio->open = altera_ps2_open;
+ serio->close = altera_ps2_close;
+ strlcpy(serio->name, dev_name(&pdev->dev), sizeof(serio->name));
+ strlcpy(serio->phys, dev_name(&pdev->dev), sizeof(serio->phys));
+ serio->port_data = ps2if;
+ serio->dev.parent = &pdev->dev;
+ ps2if->io = serio;
+
+ ps2if->iomem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (ps2if->iomem_res == NULL) {
+ error = -ENOENT;
+ goto err_free_mem;
+ }
+
+ ps2if->irq = platform_get_irq(pdev, 0);
+ if (ps2if->irq < 0) {
+ error = -ENXIO;
+ goto err_free_mem;
+ }
+
+ if (!request_mem_region(ps2if->iomem_res->start,
+ resource_size(ps2if->iomem_res), pdev->name)) {
+ error = -EBUSY;
+ goto err_free_mem;
+ }
+
+ ps2if->base = ioremap(ps2if->iomem_res->start,
+ resource_size(ps2if->iomem_res));
+ if (!ps2if->base) {
+ error = -ENOMEM;
+ goto err_free_res;
+ }
+
+ error = request_irq(ps2if->irq, altera_ps2_rxint, 0, pdev->name, ps2if);
+ if (error) {
+ dev_err(&pdev->dev, "could not allocate IRQ %d: %d\n",
+ ps2if->irq, error);
+ goto err_unmap;
+ }
+
+ dev_info(&pdev->dev, "base %p, irq %d\n", ps2if->base, ps2if->irq);
+
+ serio_register_port(ps2if->io);
+ platform_set_drvdata(pdev, ps2if);
+
+ return 0;
+
+ err_unmap:
+ iounmap(ps2if->base);
+ err_free_res:
+ release_mem_region(ps2if->iomem_res->start,
+ resource_size(ps2if->iomem_res));
+ err_free_mem:
+ kfree(ps2if);
+ kfree(serio);
+ return error;
+}
+
+/*
+ * Remove one device from this driver.
+ */
+static int altera_ps2_remove(struct platform_device *pdev)
+{
+ struct ps2if *ps2if = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ serio_unregister_port(ps2if->io);
+ free_irq(ps2if->irq, ps2if);
+ iounmap(ps2if->base);
+ release_mem_region(ps2if->iomem_res->start,
+ resource_size(ps2if->iomem_res));
+ kfree(ps2if);
+
+ return 0;
+}
+
+/*
+ * Our device driver structure
+ */
+static struct platform_driver altera_ps2_driver = {
+ .probe = altera_ps2_probe,
+ .remove = altera_ps2_remove,
+ .driver = {
+ .name = DRV_NAME,
+ },
+};
+
+static int __init altera_ps2_init(void)
+{
+ return platform_driver_register(&altera_ps2_driver);
+}
+
+static void __exit altera_ps2_exit(void)
+{
+ platform_driver_unregister(&altera_ps2_driver);
+}
+
+module_init(altera_ps2_init);
+module_exit(altera_ps2_exit);
+
+MODULE_DESCRIPTION("Altera University Program PS2 controller driver");
+MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index a39bc4eb902b..a537925f7651 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -327,6 +327,17 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
},
},
{
+ /*
+ * Reset and GET ID commands issued via KBD port are
+ * sometimes being delivered to AUX3.
+ */
+ .ident = "Sony Vaio FZ-240E",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ240E"),
+ },
+ },
+ {
.ident = "Amoi M636/A737",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."),
@@ -661,7 +672,7 @@ static void i8042_pnp_exit(void)
static int __init i8042_pnp_init(void)
{
char kbd_irq_str[4] = { 0 }, aux_irq_str[4] = { 0 };
- int pnp_data_busted = false;
+ bool pnp_data_busted = false;
int err;
#ifdef CONFIG_X86
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 8cc453c85ea7..f7ad1a13c74e 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -111,6 +111,18 @@ config TOUCHSCREEN_DA9034
Say Y here to enable the support for the touchscreen found
on Dialog Semiconductor DA9034 PMIC.
+config TOUCHSCREEN_DYNAPRO
+ tristate "Dynapro serial touchscreen"
+ select SERIO
+ help
+ Say Y here if you have a Dynapro serial touchscreen connected to
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called elo.
+
config TOUCHSCREEN_EETI
tristate "EETI touchscreen panel support"
depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 15fa62cffc77..1f5cccd3a16a 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -12,6 +12,7 @@ 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_CORGI) += corgi_ts.o
+obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
diff --git a/drivers/input/touchscreen/dynapro.c b/drivers/input/touchscreen/dynapro.c
new file mode 100644
index 000000000000..455353908bdf
--- /dev/null
+++ b/drivers/input/touchscreen/dynapro.c
@@ -0,0 +1,206 @@
+/*
+ * Dynapro serial touchscreen driver
+ *
+ * Copyright (c) 2009 Tias Guns
+ * Based on the inexio driver (c) Vojtech Pavlik and Dan Streetman and
+ * Richard Lemon
+ *
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * 2009/09/19 Tias Guns <tias@ulyssis.org>
+ * Copied inexio.c and edited for Dynapro protocol (from retired Xorg module)
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC "Dynapro serial touchscreen driver"
+
+MODULE_AUTHOR("Tias Guns <tias@ulyssis.org>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define DYNAPRO_FORMAT_TOUCH_BIT 0x40
+#define DYNAPRO_FORMAT_LENGTH 3
+#define DYNAPRO_RESPONSE_BEGIN_BYTE 0x80
+
+#define DYNAPRO_MIN_XC 0
+#define DYNAPRO_MAX_XC 0x3ff
+#define DYNAPRO_MIN_YC 0
+#define DYNAPRO_MAX_YC 0x3ff
+
+#define DYNAPRO_GET_XC(data) (data[1] | ((data[0] & 0x38) << 4))
+#define DYNAPRO_GET_YC(data) (data[2] | ((data[0] & 0x07) << 7))
+#define DYNAPRO_GET_TOUCHED(data) (DYNAPRO_FORMAT_TOUCH_BIT & data[0])
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct dynapro {
+ struct input_dev *dev;
+ struct serio *serio;
+ int idx;
+ unsigned char data[DYNAPRO_FORMAT_LENGTH];
+ char phys[32];
+};
+
+static void dynapro_process_data(struct dynapro *pdynapro)
+{
+ struct input_dev *dev = pdynapro->dev;
+
+ if (DYNAPRO_FORMAT_LENGTH == ++pdynapro->idx) {
+ input_report_abs(dev, ABS_X, DYNAPRO_GET_XC(pdynapro->data));
+ input_report_abs(dev, ABS_Y, DYNAPRO_GET_YC(pdynapro->data));
+ input_report_key(dev, BTN_TOUCH,
+ DYNAPRO_GET_TOUCHED(pdynapro->data));
+ input_sync(dev);
+
+ pdynapro->idx = 0;
+ }
+}
+
+static irqreturn_t dynapro_interrupt(struct serio *serio,
+ unsigned char data, unsigned int flags)
+{
+ struct dynapro *pdynapro = serio_get_drvdata(serio);
+
+ pdynapro->data[pdynapro->idx] = data;
+
+ if (DYNAPRO_RESPONSE_BEGIN_BYTE & pdynapro->data[0])
+ dynapro_process_data(pdynapro);
+ else
+ dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n",
+ pdynapro->data[0]);
+
+ return IRQ_HANDLED;
+}
+
+static void dynapro_disconnect(struct serio *serio)
+{
+ struct dynapro *pdynapro = serio_get_drvdata(serio);
+
+ input_get_device(pdynapro->dev);
+ input_unregister_device(pdynapro->dev);
+ serio_close(serio);
+ serio_set_drvdata(serio, NULL);
+ input_put_device(pdynapro->dev);
+ kfree(pdynapro);
+}
+
+/*
+ * dynapro_connect() is the routine that is called when someone adds a
+ * new serio device that supports dynapro protocol and registers it as
+ * an input device. This is usually accomplished using inputattach.
+ */
+
+static int dynapro_connect(struct serio *serio, struct serio_driver *drv)
+{
+ struct dynapro *pdynapro;
+ struct input_dev *input_dev;
+ int err;
+
+ pdynapro = kzalloc(sizeof(struct dynapro), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!pdynapro || !input_dev) {
+ err = -ENOMEM;
+ goto fail1;
+ }
+
+ pdynapro->serio = serio;
+ pdynapro->dev = input_dev;
+ snprintf(pdynapro->phys, sizeof(pdynapro->phys),
+ "%s/input0", serio->phys);
+
+ input_dev->name = "Dynapro Serial TouchScreen";
+ input_dev->phys = pdynapro->phys;
+ input_dev->id.bustype = BUS_RS232;
+ input_dev->id.vendor = SERIO_DYNAPRO;
+ input_dev->id.product = 0;
+ input_dev->id.version = 0x0001;
+ input_dev->dev.parent = &serio->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(pdynapro->dev, ABS_X,
+ DYNAPRO_MIN_XC, DYNAPRO_MAX_XC, 0, 0);
+ input_set_abs_params(pdynapro->dev, ABS_Y,
+ DYNAPRO_MIN_YC, DYNAPRO_MAX_YC, 0, 0);
+
+ serio_set_drvdata(serio, pdynapro);
+
+ err = serio_open(serio, drv);
+ if (err)
+ goto fail2;
+
+ err = input_register_device(pdynapro->dev);
+ if (err)
+ goto fail3;
+
+ return 0;
+
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
+ kfree(pdynapro);
+ return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id dynapro_serio_ids[] = {
+ {
+ .type = SERIO_RS232,
+ .proto = SERIO_DYNAPRO,
+ .id = SERIO_ANY,
+ .extra = SERIO_ANY,
+ },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, dynapro_serio_ids);
+
+static struct serio_driver dynapro_drv = {
+ .driver = {
+ .name = "dynapro",
+ },
+ .description = DRIVER_DESC,
+ .id_table = dynapro_serio_ids,
+ .interrupt = dynapro_interrupt,
+ .connect = dynapro_connect,
+ .disconnect = dynapro_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init dynapro_init(void)
+{
+ return serio_register_driver(&dynapro_drv);
+}
+
+static void __exit dynapro_exit(void)
+{
+ serio_unregister_driver(&dynapro_drv);
+}
+
+module_init(dynapro_init);
+module_exit(dynapro_exit);
diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c
index b115726dc088..c721c0a23eb8 100644
--- a/drivers/input/xen-kbdfront.c
+++ b/drivers/input/xen-kbdfront.c
@@ -21,7 +21,10 @@
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/input.h>
+
#include <asm/xen/hypervisor.h>
+
+#include <xen/xen.h>
#include <xen/events.h>
#include <xen/page.h>
#include <xen/interface/io/fbif.h>
diff --git a/drivers/isdn/act2000/Kconfig b/drivers/isdn/act2000/Kconfig
index 3fc1a5434ef7..fa2673fc69c2 100644
--- a/drivers/isdn/act2000/Kconfig
+++ b/drivers/isdn/act2000/Kconfig
@@ -1,6 +1,3 @@
-#
-# Config.in for IBM Active 2000 ISDN driver
-#
config ISDN_DRV_ACT2000
tristate "IBM Active 2000 support"
depends on ISA
@@ -10,4 +7,3 @@ config ISDN_DRV_ACT2000
into the card using a utility which is part of the latest
isdn4k-utils package. Please read the file
<file:Documentation/isdn/README.act2000> for more information.
-
diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig
index e1afd60924fb..b2a04755c96a 100644
--- a/drivers/isdn/capi/Kconfig
+++ b/drivers/isdn/capi/Kconfig
@@ -1,6 +1,3 @@
-#
-# Config.in for the CAPI subsystem
-#
config ISDN_DRV_AVMB1_VERBOSE_REASON
bool "Verbose reason code reporting"
default y
@@ -59,4 +56,3 @@ config ISDN_CAPI_CAPIDRV
the legacy isdn4linux link layer. If you have a card which is
supported by a CAPI driver, but still want to use old features like
ippp interfaces or ttyI emulation, say Y/M here.
-
diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig
index 18ab8652aa57..dcefedc7044a 100644
--- a/drivers/isdn/gigaset/Kconfig
+++ b/drivers/isdn/gigaset/Kconfig
@@ -1,6 +1,5 @@
menuconfig ISDN_DRV_GIGASET
tristate "Siemens Gigaset support"
- depends on ISDN_I4L
select CRC_CCITT
select BITREVERSE
help
@@ -11,9 +10,33 @@ menuconfig ISDN_DRV_GIGASET
If you have one of these devices, say M here and for at least
one of the connection specific parts that follow.
This will build a module called "gigaset".
+ Note: If you build your ISDN subsystem (ISDN_CAPI or ISDN_I4L)
+ as a module, you have to build this driver as a module too,
+ otherwise the Gigaset device won't show up as an ISDN device.
if ISDN_DRV_GIGASET
+config GIGASET_CAPI
+ bool "Gigaset CAPI support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ depends on ISDN_CAPI='y'||(ISDN_CAPI='m'&&ISDN_DRV_GIGASET='m')
+ default ISDN_I4L='n'
+ help
+ Build the Gigaset driver as a CAPI 2.0 driver interfacing with
+ the Kernel CAPI subsystem. To use it with the old ISDN4Linux
+ subsystem you'll have to enable the capidrv glue driver.
+ (select ISDN_CAPI_CAPIDRV.)
+ Say N to build the old native ISDN4Linux variant.
+
+config GIGASET_I4L
+ bool
+ depends on ISDN_I4L='y'||(ISDN_I4L='m'&&ISDN_DRV_GIGASET='m')
+ default !GIGASET_CAPI
+
+config GIGASET_DUMMYLL
+ bool
+ default !GIGASET_CAPI&&!GIGASET_I4L
+
config GIGASET_BASE
tristate "Gigaset base station support"
depends on USB
diff --git a/drivers/isdn/gigaset/Makefile b/drivers/isdn/gigaset/Makefile
index e9d3189f56b7..c453b72272a0 100644
--- a/drivers/isdn/gigaset/Makefile
+++ b/drivers/isdn/gigaset/Makefile
@@ -1,4 +1,7 @@
-gigaset-y := common.o interface.o proc.o ev-layer.o i4l.o asyncdata.o
+gigaset-y := common.o interface.o proc.o ev-layer.o asyncdata.o
+gigaset-$(CONFIG_GIGASET_CAPI) += capi.o
+gigaset-$(CONFIG_GIGASET_I4L) += i4l.o
+gigaset-$(CONFIG_GIGASET_DUMMYLL) += dummyll.o
usb_gigaset-y := usb-gigaset.o
ser_gigaset-y := ser-gigaset.o
bas_gigaset-y := bas-gigaset.o isocdata.o
diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c
index 44a58e6f8f65..a25216bf475e 100644
--- a/drivers/isdn/gigaset/asyncdata.c
+++ b/drivers/isdn/gigaset/asyncdata.c
@@ -119,10 +119,7 @@ static inline int hdlc_loop(unsigned char c, unsigned char *src, int numbytes,
int inputstate = bcs->inputstate;
__u16 fcs = bcs->fcs;
struct sk_buff *skb = bcs->skb;
- unsigned char error;
- struct sk_buff *compskb;
int startbytes = numbytes;
- int l;
if (unlikely(inputstate & INS_byte_stuff)) {
inputstate &= ~INS_byte_stuff;
@@ -158,8 +155,8 @@ byte_stuff:
#endif
/* end of frame */
- error = 1;
- gigaset_rcv_error(NULL, cs, bcs);
+ gigaset_isdn_rcv_err(bcs);
+ dev_kfree_skb(skb);
} else if (!(inputstate & INS_have_data)) { /* 7E 7E */
#ifdef CONFIG_GIGASET_DEBUG
++bcs->emptycount;
@@ -170,54 +167,39 @@ byte_stuff:
"7e----------------------------");
/* end of frame */
- error = 0;
-
if (unlikely(fcs != PPP_GOODFCS)) {
dev_err(cs->dev,
"Checksum failed, %u bytes corrupted!\n",
skb->len);
- compskb = NULL;
- gigaset_rcv_error(compskb, cs, bcs);
- error = 1;
+ gigaset_isdn_rcv_err(bcs);
+ dev_kfree_skb(skb);
+ } else if (likely(skb->len > 2)) {
+ __skb_trim(skb, skb->len - 2);
+ gigaset_skb_rcvd(bcs, skb);
} else {
- if (likely((l = skb->len) > 2)) {
- skb->tail -= 2;
- skb->len -= 2;
- } else {
- dev_kfree_skb(skb);
- skb = NULL;
- inputstate |= INS_skip_frame;
- if (l == 1) {
- dev_err(cs->dev,
- "invalid packet size (1)!\n");
- error = 1;
- gigaset_rcv_error(NULL,
- cs, bcs);
- }
- }
- if (likely(!(error ||
- (inputstate &
- INS_skip_frame)))) {
- gigaset_rcv_skb(skb, cs, bcs);
+ if (skb->len) {
+ dev_err(cs->dev,
+ "invalid packet size (%d)\n", skb->len);
+ gigaset_isdn_rcv_err(bcs);
}
+ dev_kfree_skb(skb);
}
}
- if (unlikely(error))
- if (skb)
- dev_kfree_skb(skb);
-
fcs = PPP_INITFCS;
inputstate &= ~(INS_have_data | INS_skip_frame);
if (unlikely(bcs->ignore)) {
inputstate |= INS_skip_frame;
skb = NULL;
- } else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)) {
- skb_reserve(skb, HW_HDR_LEN);
} else {
- dev_warn(cs->dev,
- "could not allocate new skb\n");
- inputstate |= INS_skip_frame;
+ skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len);
+ if (skb != NULL) {
+ skb_reserve(skb, cs->hw_hdr_len);
+ } else {
+ dev_warn(cs->dev,
+ "could not allocate new skb\n");
+ inputstate |= INS_skip_frame;
+ }
}
break;
@@ -314,18 +296,21 @@ static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes,
/* pass data up */
if (likely(inputstate & INS_have_data)) {
if (likely(!(inputstate & INS_skip_frame))) {
- gigaset_rcv_skb(skb, cs, bcs);
+ gigaset_skb_rcvd(bcs, skb);
}
inputstate &= ~(INS_have_data | INS_skip_frame);
if (unlikely(bcs->ignore)) {
inputstate |= INS_skip_frame;
skb = NULL;
- } else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN))
- != NULL)) {
- skb_reserve(skb, HW_HDR_LEN);
} else {
- dev_warn(cs->dev, "could not allocate new skb\n");
- inputstate |= INS_skip_frame;
+ skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len);
+ if (skb != NULL) {
+ skb_reserve(skb, cs->hw_hdr_len);
+ } else {
+ dev_warn(cs->dev,
+ "could not allocate new skb\n");
+ inputstate |= INS_skip_frame;
+ }
}
}
@@ -383,7 +368,7 @@ void gigaset_m10x_input(struct inbuf_t *inbuf)
/* FIXME use function pointers? */
if (inbuf->inputstate & INS_command)
procbytes = cmd_loop(c, src, numbytes, inbuf);
- else if (inbuf->bcs->proto2 == ISDN_PROTO_L2_HDLC)
+ else if (inbuf->bcs->proto2 == L2_HDLC)
procbytes = hdlc_loop(c, src, numbytes, inbuf);
else
procbytes = iraw_loop(c, src, numbytes, inbuf);
@@ -440,16 +425,16 @@ EXPORT_SYMBOL_GPL(gigaset_m10x_input);
/* == data output ========================================================== */
-/* Encoding of a PPP packet into an octet stuffed HDLC frame
- * with FCS, opening and closing flags.
+/*
+ * Encode a data packet into an octet stuffed HDLC frame with FCS,
+ * opening and closing flags, preserving headroom data.
* parameters:
- * skb skb containing original packet (freed upon return)
- * head number of headroom bytes to allocate in result skb
- * tail number of tailroom bytes to allocate in result skb
+ * skb skb containing original packet (freed upon return)
+ * headroom number of headroom bytes to preserve
* Return value:
* pointer to newly allocated skb containing the result frame
*/
-static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail)
+static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int headroom)
{
struct sk_buff *hdlc_skb;
__u16 fcs;
@@ -471,16 +456,17 @@ static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail)
/* size of new buffer: original size + number of stuffing bytes
* + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes
+ * + room for acknowledgement header
*/
- hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + tail + head);
+ hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + headroom);
if (!hdlc_skb) {
dev_kfree_skb(skb);
return NULL;
}
- skb_reserve(hdlc_skb, head);
- /* Copy acknowledge request into new skb */
- memcpy(hdlc_skb->head, skb->head, 2);
+ /* Copy acknowledgement header into new skb */
+ skb_reserve(hdlc_skb, headroom);
+ memcpy(hdlc_skb->head, skb->head, headroom);
/* Add flag sequence in front of everything.. */
*(skb_put(hdlc_skb, 1)) = PPP_FLAG;
@@ -515,15 +501,16 @@ static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail)
return hdlc_skb;
}
-/* Encoding of a raw packet into an octet stuffed bit inverted frame
+/*
+ * Encode a data packet into an octet stuffed raw bit inverted frame,
+ * preserving headroom data.
* parameters:
- * skb skb containing original packet (freed upon return)
- * head number of headroom bytes to allocate in result skb
- * tail number of tailroom bytes to allocate in result skb
+ * skb skb containing original packet (freed upon return)
+ * headroom number of headroom bytes to preserve
* Return value:
* pointer to newly allocated skb containing the result frame
*/
-static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
+static struct sk_buff *iraw_encode(struct sk_buff *skb, int headroom)
{
struct sk_buff *iraw_skb;
unsigned char c;
@@ -531,12 +518,15 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
int len;
/* worst case: every byte must be stuffed */
- iraw_skb = dev_alloc_skb(2*skb->len + tail + head);
+ iraw_skb = dev_alloc_skb(2*skb->len + headroom);
if (!iraw_skb) {
dev_kfree_skb(skb);
return NULL;
}
- skb_reserve(iraw_skb, head);
+
+ /* Copy acknowledgement header into new skb */
+ skb_reserve(iraw_skb, headroom);
+ memcpy(iraw_skb->head, skb->head, headroom);
cp = skb->data;
len = skb->len;
@@ -555,8 +545,10 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
* @bcs: B channel descriptor structure.
* @skb: data to send.
*
- * Called by i4l.c to encode and queue an skb for sending, and start
+ * Called by LL to encode and queue an skb for sending, and start
* transmission if necessary.
+ * Once the payload data has been transmitted completely, gigaset_skb_sent()
+ * will be called with the first cs->hw_hdr_len bytes of skb->head preserved.
*
* Return value:
* number of bytes accepted for sending (skb->len) if ok,
@@ -567,10 +559,10 @@ int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb)
unsigned len = skb->len;
unsigned long flags;
- if (bcs->proto2 == ISDN_PROTO_L2_HDLC)
- skb = HDLC_Encode(skb, HW_HDR_LEN, 0);
+ if (bcs->proto2 == L2_HDLC)
+ skb = HDLC_Encode(skb, bcs->cs->hw_hdr_len);
else
- skb = iraw_encode(skb, HW_HDR_LEN, 0);
+ skb = iraw_encode(skb, bcs->cs->hw_hdr_len);
if (!skb) {
dev_err(bcs->cs->dev,
"unable to allocate memory for encoding!\n");
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index 5ed1d99eb9f3..388e63a8ae94 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -911,7 +911,7 @@ static int starturbs(struct bc_state *bcs)
int rc;
/* initialize L2 reception */
- if (bcs->proto2 == ISDN_PROTO_L2_HDLC)
+ if (bcs->proto2 == L2_HDLC)
bcs->inputstate |= INS_flag_hunt;
/* submit all isochronous input URBs */
@@ -1064,7 +1064,7 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx)
"%s: buffer busy at frame %d",
__func__, nframe);
/* tasklet will be restarted from
- gigaset_send_skb() */
+ gigaset_isoc_send_skb() */
} else {
dev_err(ucx->bcs->cs->dev,
"%s: buffer error %d at frame %d\n",
diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c
new file mode 100644
index 000000000000..c276a925b36f
--- /dev/null
+++ b/drivers/isdn/gigaset/capi.c
@@ -0,0 +1,2273 @@
+/*
+ * Kernel CAPI interface for the Gigaset driver
+ *
+ * Copyright (c) 2009 by Tilman Schmidt <tilman@imap.cc>.
+ *
+ * =====================================================================
+ * This 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 "gigaset.h"
+#include <linux/ctype.h>
+#include <linux/isdn/capilli.h>
+#include <linux/isdn/capicmd.h>
+#include <linux/isdn/capiutil.h>
+
+/* missing from kernelcapi.h */
+#define CapiNcpiNotSupportedByProtocol 0x0001
+#define CapiFlagsNotSupportedByProtocol 0x0002
+#define CapiAlertAlreadySent 0x0003
+#define CapiFacilitySpecificFunctionNotSupported 0x3011
+
+/* missing from capicmd.h */
+#define CAPI_CONNECT_IND_BASELEN (CAPI_MSG_BASELEN+4+2+8*1)
+#define CAPI_CONNECT_ACTIVE_IND_BASELEN (CAPI_MSG_BASELEN+4+3*1)
+#define CAPI_CONNECT_B3_IND_BASELEN (CAPI_MSG_BASELEN+4+1)
+#define CAPI_CONNECT_B3_ACTIVE_IND_BASELEN (CAPI_MSG_BASELEN+4+1)
+#define CAPI_DATA_B3_REQ_LEN64 (CAPI_MSG_BASELEN+4+4+2+2+2+8)
+#define CAPI_DATA_B3_CONF_LEN (CAPI_MSG_BASELEN+4+2+2)
+#define CAPI_DISCONNECT_IND_LEN (CAPI_MSG_BASELEN+4+2)
+#define CAPI_DISCONNECT_B3_IND_BASELEN (CAPI_MSG_BASELEN+4+2+1)
+#define CAPI_FACILITY_CONF_BASELEN (CAPI_MSG_BASELEN+4+2+2+1)
+/* most _CONF messages contain only Controller/PLCI/NCCI and Info parameters */
+#define CAPI_STDCONF_LEN (CAPI_MSG_BASELEN+4+2)
+
+#define CAPI_FACILITY_HANDSET 0x0000
+#define CAPI_FACILITY_DTMF 0x0001
+#define CAPI_FACILITY_V42BIS 0x0002
+#define CAPI_FACILITY_SUPPSVC 0x0003
+#define CAPI_FACILITY_WAKEUP 0x0004
+#define CAPI_FACILITY_LI 0x0005
+
+#define CAPI_SUPPSVC_GETSUPPORTED 0x0000
+
+/* missing from capiutil.h */
+#define CAPIMSG_PLCI_PART(m) CAPIMSG_U8(m, 9)
+#define CAPIMSG_NCCI_PART(m) CAPIMSG_U16(m, 10)
+#define CAPIMSG_HANDLE_REQ(m) CAPIMSG_U16(m, 18) /* DATA_B3_REQ/_IND only! */
+#define CAPIMSG_FLAGS(m) CAPIMSG_U16(m, 20)
+#define CAPIMSG_SETCONTROLLER(m, contr) capimsg_setu8(m, 8, contr)
+#define CAPIMSG_SETPLCI_PART(m, plci) capimsg_setu8(m, 9, plci)
+#define CAPIMSG_SETNCCI_PART(m, ncci) capimsg_setu16(m, 10, ncci)
+#define CAPIMSG_SETFLAGS(m, flags) capimsg_setu16(m, 20, flags)
+
+/* parameters with differing location in DATA_B3_CONF/_RESP: */
+#define CAPIMSG_SETHANDLE_CONF(m, handle) capimsg_setu16(m, 12, handle)
+#define CAPIMSG_SETINFO_CONF(m, info) capimsg_setu16(m, 14, info)
+
+/* Flags (DATA_B3_REQ/_IND) */
+#define CAPI_FLAGS_DELIVERY_CONFIRMATION 0x04
+#define CAPI_FLAGS_RESERVED (~0x1f)
+
+/* buffer sizes */
+#define MAX_BC_OCTETS 11
+#define MAX_HLC_OCTETS 3
+#define MAX_NUMBER_DIGITS 20
+#define MAX_FMT_IE_LEN 20
+
+/* values for gigaset_capi_appl.connected */
+#define APCONN_NONE 0 /* inactive/listening */
+#define APCONN_SETUP 1 /* connecting */
+#define APCONN_ACTIVE 2 /* B channel up */
+
+/* registered application data structure */
+struct gigaset_capi_appl {
+ struct list_head ctrlist;
+ struct gigaset_capi_appl *bcnext;
+ u16 id;
+ u16 nextMessageNumber;
+ u32 listenInfoMask;
+ u32 listenCIPmask;
+ int connected;
+};
+
+/* CAPI specific controller data structure */
+struct gigaset_capi_ctr {
+ struct capi_ctr ctr;
+ struct list_head appls;
+ struct sk_buff_head sendqueue;
+ atomic_t sendqlen;
+ /* two _cmsg structures possibly used concurrently: */
+ _cmsg hcmsg; /* for message composition triggered from hardware */
+ _cmsg acmsg; /* for dissection of messages sent from application */
+ u8 bc_buf[MAX_BC_OCTETS+1];
+ u8 hlc_buf[MAX_HLC_OCTETS+1];
+ u8 cgpty_buf[MAX_NUMBER_DIGITS+3];
+ u8 cdpty_buf[MAX_NUMBER_DIGITS+2];
+};
+
+/* CIP Value table (from CAPI 2.0 standard, ch. 6.1) */
+static struct {
+ u8 *bc;
+ u8 *hlc;
+} cip2bchlc[] = {
+ [1] = { "8090A3", NULL },
+ /* Speech (A-law) */
+ [2] = { "8890", NULL },
+ /* Unrestricted digital information */
+ [3] = { "8990", NULL },
+ /* Restricted digital information */
+ [4] = { "9090A3", NULL },
+ /* 3,1 kHz audio (A-law) */
+ [5] = { "9190", NULL },
+ /* 7 kHz audio */
+ [6] = { "9890", NULL },
+ /* Video */
+ [7] = { "88C0C6E6", NULL },
+ /* Packet mode */
+ [8] = { "8890218F", NULL },
+ /* 56 kbit/s rate adaptation */
+ [9] = { "9190A5", NULL },
+ /* Unrestricted digital information with tones/announcements */
+ [16] = { "8090A3", "9181" },
+ /* Telephony */
+ [17] = { "9090A3", "9184" },
+ /* Group 2/3 facsimile */
+ [18] = { "8890", "91A1" },
+ /* Group 4 facsimile Class 1 */
+ [19] = { "8890", "91A4" },
+ /* Teletex service basic and mixed mode
+ and Group 4 facsimile service Classes II and III */
+ [20] = { "8890", "91A8" },
+ /* Teletex service basic and processable mode */
+ [21] = { "8890", "91B1" },
+ /* Teletex service basic mode */
+ [22] = { "8890", "91B2" },
+ /* International interworking for Videotex */
+ [23] = { "8890", "91B5" },
+ /* Telex */
+ [24] = { "8890", "91B8" },
+ /* Message Handling Systems in accordance with X.400 */
+ [25] = { "8890", "91C1" },
+ /* OSI application in accordance with X.200 */
+ [26] = { "9190A5", "9181" },
+ /* 7 kHz telephony */
+ [27] = { "9190A5", "916001" },
+ /* Video telephony, first connection */
+ [28] = { "8890", "916002" },
+ /* Video telephony, second connection */
+};
+
+/*
+ * helper functions
+ * ================
+ */
+
+/*
+ * emit unsupported parameter warning
+ */
+static inline void ignore_cstruct_param(struct cardstate *cs, _cstruct param,
+ char *msgname, char *paramname)
+{
+ if (param && *param)
+ dev_warn(cs->dev, "%s: ignoring unsupported parameter: %s\n",
+ msgname, paramname);
+}
+
+static inline void ignore_cmstruct_param(struct cardstate *cs, _cmstruct param,
+ char *msgname, char *paramname)
+{
+ if (param != CAPI_DEFAULT)
+ dev_warn(cs->dev, "%s: ignoring unsupported parameter: %s\n",
+ msgname, paramname);
+}
+
+/*
+ * check for legal hex digit
+ */
+static inline int ishexdigit(char c)
+{
+ if (c >= '0' && c <= '9')
+ return 1;
+ if (c >= 'A' && c <= 'F')
+ return 1;
+ if (c >= 'a' && c <= 'f')
+ return 1;
+ return 0;
+}
+
+/*
+ * convert hex to binary
+ */
+static inline u8 hex2bin(char c)
+{
+ int result = c & 0x0f;
+ if (c & 0x40)
+ result += 9;
+ return result;
+}
+
+/*
+ * convert an IE from Gigaset hex string to ETSI binary representation
+ * including length byte
+ * return value: result length, -1 on error
+ */
+static int encode_ie(char *in, u8 *out, int maxlen)
+{
+ int l = 0;
+ while (*in) {
+ if (!ishexdigit(in[0]) || !ishexdigit(in[1]) || l >= maxlen)
+ return -1;
+ out[++l] = (hex2bin(in[0]) << 4) + hex2bin(in[1]);
+ in += 2;
+ }
+ out[0] = l;
+ return l;
+}
+
+/*
+ * convert an IE from ETSI binary representation including length byte
+ * to Gigaset hex string
+ */
+static void decode_ie(u8 *in, char *out)
+{
+ int i = *in;
+ while (i-- > 0) {
+ /* ToDo: conversion to upper case necessary? */
+ *out++ = toupper(hex_asc_hi(*++in));
+ *out++ = toupper(hex_asc_lo(*in));
+ }
+}
+
+/*
+ * retrieve application data structure for an application ID
+ */
+static inline struct gigaset_capi_appl *
+get_appl(struct gigaset_capi_ctr *iif, u16 appl)
+{
+ struct gigaset_capi_appl *ap;
+
+ list_for_each_entry(ap, &iif->appls, ctrlist)
+ if (ap->id == appl)
+ return ap;
+ return NULL;
+}
+
+/*
+ * dump CAPI message to kernel messages for debugging
+ */
+static inline void dump_cmsg(enum debuglevel level, const char *tag, _cmsg *p)
+{
+#ifdef CONFIG_GIGASET_DEBUG
+ _cdebbuf *cdb;
+
+ if (!(gigaset_debuglevel & level))
+ return;
+
+ cdb = capi_cmsg2str(p);
+ if (cdb) {
+ gig_dbg(level, "%s: [%d] %s", tag, p->ApplId, cdb->buf);
+ cdebbuf_free(cdb);
+ } else {
+ gig_dbg(level, "%s: [%d] %s", tag, p->ApplId,
+ capi_cmd2str(p->Command, p->Subcommand));
+ }
+#endif
+}
+
+static inline void dump_rawmsg(enum debuglevel level, const char *tag,
+ unsigned char *data)
+{
+#ifdef CONFIG_GIGASET_DEBUG
+ char *dbgline;
+ int i, l;
+
+ if (!(gigaset_debuglevel & level))
+ return;
+
+ l = CAPIMSG_LEN(data);
+ if (l < 12) {
+ gig_dbg(level, "%s: ??? LEN=%04d", tag, l);
+ return;
+ }
+ gig_dbg(level, "%s: 0x%02x:0x%02x: ID=%03d #0x%04x LEN=%04d NCCI=0x%x",
+ tag, CAPIMSG_COMMAND(data), CAPIMSG_SUBCOMMAND(data),
+ CAPIMSG_APPID(data), CAPIMSG_MSGID(data), l,
+ CAPIMSG_CONTROL(data));
+ l -= 12;
+ dbgline = kmalloc(3*l, GFP_ATOMIC);
+ if (!dbgline)
+ return;
+ for (i = 0; i < l; i++) {
+ dbgline[3*i] = hex_asc_hi(data[12+i]);
+ dbgline[3*i+1] = hex_asc_lo(data[12+i]);
+ dbgline[3*i+2] = ' ';
+ }
+ dbgline[3*l-1] = '\0';
+ gig_dbg(level, " %s", dbgline);
+ kfree(dbgline);
+ if (CAPIMSG_COMMAND(data) == CAPI_DATA_B3 &&
+ (CAPIMSG_SUBCOMMAND(data) == CAPI_REQ ||
+ CAPIMSG_SUBCOMMAND(data) == CAPI_IND) &&
+ CAPIMSG_DATALEN(data) > 0) {
+ l = CAPIMSG_DATALEN(data);
+ dbgline = kmalloc(3*l, GFP_ATOMIC);
+ if (!dbgline)
+ return;
+ data += CAPIMSG_LEN(data);
+ for (i = 0; i < l; i++) {
+ dbgline[3*i] = hex_asc_hi(data[i]);
+ dbgline[3*i+1] = hex_asc_lo(data[i]);
+ dbgline[3*i+2] = ' ';
+ }
+ dbgline[3*l-1] = '\0';
+ gig_dbg(level, " %s", dbgline);
+ kfree(dbgline);
+ }
+#endif
+}
+
+/*
+ * format CAPI IE as string
+ */
+
+static const char *format_ie(const char *ie)
+{
+ static char result[3*MAX_FMT_IE_LEN];
+ int len, count;
+ char *pout = result;
+
+ if (!ie)
+ return "NULL";
+
+ count = len = ie[0];
+ if (count > MAX_FMT_IE_LEN)
+ count = MAX_FMT_IE_LEN-1;
+ while (count--) {
+ *pout++ = hex_asc_hi(*++ie);
+ *pout++ = hex_asc_lo(*ie);
+ *pout++ = ' ';
+ }
+ if (len > MAX_FMT_IE_LEN) {
+ *pout++ = '.';
+ *pout++ = '.';
+ *pout++ = '.';
+ }
+ *--pout = 0;
+ return result;
+}
+
+
+/*
+ * driver interface functions
+ * ==========================
+ */
+
+/**
+ * gigaset_skb_sent() - acknowledge transmission of outgoing skb
+ * @bcs: B channel descriptor structure.
+ * @skb: sent data.
+ *
+ * Called by hardware module {bas,ser,usb}_gigaset when the data in a
+ * skb has been successfully sent, for signalling completion to the LL.
+ */
+void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *dskb)
+{
+ struct cardstate *cs = bcs->cs;
+ struct gigaset_capi_ctr *iif = cs->iif;
+ struct gigaset_capi_appl *ap = bcs->ap;
+ struct sk_buff *cskb;
+ u16 flags;
+
+ /* update statistics */
+ ++bcs->trans_up;
+
+ if (!ap) {
+ dev_err(cs->dev, "%s: no application\n", __func__);
+ return;
+ }
+
+ /* don't send further B3 messages if disconnected */
+ if (ap->connected < APCONN_ACTIVE) {
+ gig_dbg(DEBUG_LLDATA, "disconnected, discarding ack");
+ return;
+ }
+
+ /* ToDo: honor unset "delivery confirmation" bit */
+ flags = CAPIMSG_FLAGS(dskb->head);
+
+ /* build DATA_B3_CONF message */
+ cskb = alloc_skb(CAPI_DATA_B3_CONF_LEN, GFP_ATOMIC);
+ if (!cskb) {
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
+ return;
+ }
+ /* frequent message, avoid _cmsg overhead */
+ CAPIMSG_SETLEN(cskb->data, CAPI_DATA_B3_CONF_LEN);
+ CAPIMSG_SETAPPID(cskb->data, ap->id);
+ CAPIMSG_SETCOMMAND(cskb->data, CAPI_DATA_B3);
+ CAPIMSG_SETSUBCOMMAND(cskb->data, CAPI_CONF);
+ CAPIMSG_SETMSGID(cskb->data, CAPIMSG_MSGID(dskb->head));
+ CAPIMSG_SETCONTROLLER(cskb->data, iif->ctr.cnr);
+ CAPIMSG_SETPLCI_PART(cskb->data, bcs->channel + 1);
+ CAPIMSG_SETNCCI_PART(cskb->data, 1);
+ CAPIMSG_SETHANDLE_CONF(cskb->data, CAPIMSG_HANDLE_REQ(dskb->head));
+ if (flags & ~CAPI_FLAGS_DELIVERY_CONFIRMATION)
+ CAPIMSG_SETINFO_CONF(cskb->data,
+ CapiFlagsNotSupportedByProtocol);
+ else
+ CAPIMSG_SETINFO_CONF(cskb->data, CAPI_NOERROR);
+
+ /* emit message */
+ dump_rawmsg(DEBUG_LLDATA, "DATA_B3_CONF", cskb->data);
+ capi_ctr_handle_message(&iif->ctr, ap->id, cskb);
+}
+EXPORT_SYMBOL_GPL(gigaset_skb_sent);
+
+/**
+ * gigaset_skb_rcvd() - pass received skb to LL
+ * @bcs: B channel descriptor structure.
+ * @skb: received data.
+ *
+ * Called by hardware module {bas,ser,usb}_gigaset when user data has
+ * been successfully received, for passing to the LL.
+ * Warning: skb must not be accessed anymore!
+ */
+void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb)
+{
+ struct cardstate *cs = bcs->cs;
+ struct gigaset_capi_ctr *iif = cs->iif;
+ struct gigaset_capi_appl *ap = bcs->ap;
+ int len = skb->len;
+
+ /* update statistics */
+ bcs->trans_down++;
+
+ if (!ap) {
+ dev_err(cs->dev, "%s: no application\n", __func__);
+ return;
+ }
+
+ /* don't send further B3 messages if disconnected */
+ if (ap->connected < APCONN_ACTIVE) {
+ gig_dbg(DEBUG_LLDATA, "disconnected, discarding data");
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ /*
+ * prepend DATA_B3_IND message to payload
+ * Parameters: NCCI = 1, all others 0/unused
+ * frequent message, avoid _cmsg overhead
+ */
+ skb_push(skb, CAPI_DATA_B3_REQ_LEN);
+ CAPIMSG_SETLEN(skb->data, CAPI_DATA_B3_REQ_LEN);
+ CAPIMSG_SETAPPID(skb->data, ap->id);
+ CAPIMSG_SETCOMMAND(skb->data, CAPI_DATA_B3);
+ CAPIMSG_SETSUBCOMMAND(skb->data, CAPI_IND);
+ CAPIMSG_SETMSGID(skb->data, ap->nextMessageNumber++);
+ CAPIMSG_SETCONTROLLER(skb->data, iif->ctr.cnr);
+ CAPIMSG_SETPLCI_PART(skb->data, bcs->channel + 1);
+ CAPIMSG_SETNCCI_PART(skb->data, 1);
+ /* Data parameter not used */
+ CAPIMSG_SETDATALEN(skb->data, len);
+ /* Data handle parameter not used */
+ CAPIMSG_SETFLAGS(skb->data, 0);
+ /* Data64 parameter not present */
+
+ /* emit message */
+ dump_rawmsg(DEBUG_LLDATA, "DATA_B3_IND", skb->data);
+ capi_ctr_handle_message(&iif->ctr, ap->id, skb);
+}
+EXPORT_SYMBOL_GPL(gigaset_skb_rcvd);
+
+/**
+ * gigaset_isdn_rcv_err() - signal receive error
+ * @bcs: B channel descriptor structure.
+ *
+ * Called by hardware module {bas,ser,usb}_gigaset when a receive error
+ * has occurred, for signalling to the LL.
+ */
+void gigaset_isdn_rcv_err(struct bc_state *bcs)
+{
+ /* if currently ignoring packets, just count down */
+ if (bcs->ignore) {
+ bcs->ignore--;
+ return;
+ }
+
+ /* update statistics */
+ bcs->corrupted++;
+
+ /* ToDo: signal error -> LL */
+}
+EXPORT_SYMBOL_GPL(gigaset_isdn_rcv_err);
+
+/**
+ * gigaset_isdn_icall() - signal incoming call
+ * @at_state: connection state structure.
+ *
+ * Called by main module at tasklet level to notify the LL that an incoming
+ * call has been received. @at_state contains the parameters of the call.
+ *
+ * Return value: call disposition (ICALL_*)
+ */
+int gigaset_isdn_icall(struct at_state_t *at_state)
+{
+ struct cardstate *cs = at_state->cs;
+ struct bc_state *bcs = at_state->bcs;
+ struct gigaset_capi_ctr *iif = cs->iif;
+ struct gigaset_capi_appl *ap;
+ u32 actCIPmask;
+ struct sk_buff *skb;
+ unsigned int msgsize;
+ int i;
+
+ /*
+ * ToDo: signal calls without a free B channel, too
+ * (requires a u8 handle for the at_state structure that can
+ * be stored in the PLCI and used in the CONNECT_RESP message
+ * handler to retrieve it)
+ */
+ if (!bcs)
+ return ICALL_IGNORE;
+
+ /* prepare CONNECT_IND message, using B channel number as PLCI */
+ capi_cmsg_header(&iif->hcmsg, 0, CAPI_CONNECT, CAPI_IND, 0,
+ iif->ctr.cnr | ((bcs->channel + 1) << 8));
+
+ /* minimum size, all structs empty */
+ msgsize = CAPI_CONNECT_IND_BASELEN;
+
+ /* Bearer Capability (mandatory) */
+ if (at_state->str_var[STR_ZBC]) {
+ /* pass on BC from Gigaset */
+ if (encode_ie(at_state->str_var[STR_ZBC], iif->bc_buf,
+ MAX_BC_OCTETS) < 0) {
+ dev_warn(cs->dev, "RING ignored - bad BC %s\n",
+ at_state->str_var[STR_ZBC]);
+ return ICALL_IGNORE;
+ }
+
+ /* look up corresponding CIP value */
+ iif->hcmsg.CIPValue = 0; /* default if nothing found */
+ for (i = 0; i < ARRAY_SIZE(cip2bchlc); i++)
+ if (cip2bchlc[i].bc != NULL &&
+ cip2bchlc[i].hlc == NULL &&
+ !strcmp(cip2bchlc[i].bc,
+ at_state->str_var[STR_ZBC])) {
+ iif->hcmsg.CIPValue = i;
+ break;
+ }
+ } else {
+ /* no BC (internal call): assume CIP 1 (speech, A-law) */
+ iif->hcmsg.CIPValue = 1;
+ encode_ie(cip2bchlc[1].bc, iif->bc_buf, MAX_BC_OCTETS);
+ }
+ iif->hcmsg.BC = iif->bc_buf;
+ msgsize += iif->hcmsg.BC[0];
+
+ /* High Layer Compatibility (optional) */
+ if (at_state->str_var[STR_ZHLC]) {
+ /* pass on HLC from Gigaset */
+ if (encode_ie(at_state->str_var[STR_ZHLC], iif->hlc_buf,
+ MAX_HLC_OCTETS) < 0) {
+ dev_warn(cs->dev, "RING ignored - bad HLC %s\n",
+ at_state->str_var[STR_ZHLC]);
+ return ICALL_IGNORE;
+ }
+ iif->hcmsg.HLC = iif->hlc_buf;
+ msgsize += iif->hcmsg.HLC[0];
+
+ /* look up corresponding CIP value */
+ /* keep BC based CIP value if none found */
+ if (at_state->str_var[STR_ZBC])
+ for (i = 0; i < ARRAY_SIZE(cip2bchlc); i++)
+ if (cip2bchlc[i].hlc != NULL &&
+ !strcmp(cip2bchlc[i].hlc,
+ at_state->str_var[STR_ZHLC]) &&
+ !strcmp(cip2bchlc[i].bc,
+ at_state->str_var[STR_ZBC])) {
+ iif->hcmsg.CIPValue = i;
+ break;
+ }
+ }
+
+ /* Called Party Number (optional) */
+ if (at_state->str_var[STR_ZCPN]) {
+ i = strlen(at_state->str_var[STR_ZCPN]);
+ if (i > MAX_NUMBER_DIGITS) {
+ dev_warn(cs->dev, "RING ignored - bad number %s\n",
+ at_state->str_var[STR_ZBC]);
+ return ICALL_IGNORE;
+ }
+ iif->cdpty_buf[0] = i + 1;
+ iif->cdpty_buf[1] = 0x80; /* type / numbering plan unknown */
+ memcpy(iif->cdpty_buf+2, at_state->str_var[STR_ZCPN], i);
+ iif->hcmsg.CalledPartyNumber = iif->cdpty_buf;
+ msgsize += iif->hcmsg.CalledPartyNumber[0];
+ }
+
+ /* Calling Party Number (optional) */
+ if (at_state->str_var[STR_NMBR]) {
+ i = strlen(at_state->str_var[STR_NMBR]);
+ if (i > MAX_NUMBER_DIGITS) {
+ dev_warn(cs->dev, "RING ignored - bad number %s\n",
+ at_state->str_var[STR_ZBC]);
+ return ICALL_IGNORE;
+ }
+ iif->cgpty_buf[0] = i + 2;
+ iif->cgpty_buf[1] = 0x00; /* type / numbering plan unknown */
+ iif->cgpty_buf[2] = 0x80; /* pres. allowed, not screened */
+ memcpy(iif->cgpty_buf+3, at_state->str_var[STR_NMBR], i);
+ iif->hcmsg.CallingPartyNumber = iif->cgpty_buf;
+ msgsize += iif->hcmsg.CallingPartyNumber[0];
+ }
+
+ /* remaining parameters (not supported, always left NULL):
+ * - CalledPartySubaddress
+ * - CallingPartySubaddress
+ * - AdditionalInfo
+ * - BChannelinformation
+ * - Keypadfacility
+ * - Useruserdata
+ * - Facilitydataarray
+ */
+
+ gig_dbg(DEBUG_CMD, "icall: PLCI %x CIP %d BC %s",
+ iif->hcmsg.adr.adrPLCI, iif->hcmsg.CIPValue,
+ format_ie(iif->hcmsg.BC));
+ gig_dbg(DEBUG_CMD, "icall: HLC %s",
+ format_ie(iif->hcmsg.HLC));
+ gig_dbg(DEBUG_CMD, "icall: CgPty %s",
+ format_ie(iif->hcmsg.CallingPartyNumber));
+ gig_dbg(DEBUG_CMD, "icall: CdPty %s",
+ format_ie(iif->hcmsg.CalledPartyNumber));
+
+ /* scan application list for matching listeners */
+ bcs->ap = NULL;
+ actCIPmask = 1 | (1 << iif->hcmsg.CIPValue);
+ list_for_each_entry(ap, &iif->appls, ctrlist)
+ if (actCIPmask & ap->listenCIPmask) {
+ /* build CONNECT_IND message for this application */
+ iif->hcmsg.ApplId = ap->id;
+ iif->hcmsg.Messagenumber = ap->nextMessageNumber++;
+
+ skb = alloc_skb(msgsize, GFP_ATOMIC);
+ if (!skb) {
+ dev_err(cs->dev, "%s: out of memory\n",
+ __func__);
+ break;
+ }
+ capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize));
+ dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg);
+
+ /* add to listeners on this B channel, update state */
+ ap->bcnext = bcs->ap;
+ bcs->ap = ap;
+ bcs->chstate |= CHS_NOTIFY_LL;
+ ap->connected = APCONN_SETUP;
+
+ /* emit message */
+ capi_ctr_handle_message(&iif->ctr, ap->id, skb);
+ }
+
+ /*
+ * Return "accept" if any listeners.
+ * Gigaset will send ALERTING.
+ * There doesn't seem to be a way to avoid this.
+ */
+ return bcs->ap ? ICALL_ACCEPT : ICALL_IGNORE;
+}
+
+/*
+ * send a DISCONNECT_IND message to an application
+ * does not sleep, clobbers the controller's hcmsg structure
+ */
+static void send_disconnect_ind(struct bc_state *bcs,
+ struct gigaset_capi_appl *ap, u16 reason)
+{
+ struct cardstate *cs = bcs->cs;
+ struct gigaset_capi_ctr *iif = cs->iif;
+ struct sk_buff *skb;
+
+ if (ap->connected == APCONN_NONE)
+ return;
+
+ capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT, CAPI_IND,
+ ap->nextMessageNumber++,
+ iif->ctr.cnr | ((bcs->channel + 1) << 8));
+ iif->hcmsg.Reason = reason;
+ skb = alloc_skb(CAPI_DISCONNECT_IND_LEN, GFP_ATOMIC);
+ if (!skb) {
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
+ return;
+ }
+ capi_cmsg2message(&iif->hcmsg, __skb_put(skb, CAPI_DISCONNECT_IND_LEN));
+ dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg);
+ ap->connected = APCONN_NONE;
+ capi_ctr_handle_message(&iif->ctr, ap->id, skb);
+}
+
+/*
+ * send a DISCONNECT_B3_IND message to an application
+ * Parameters: NCCI = 1, NCPI empty, Reason_B3 = 0
+ * does not sleep, clobbers the controller's hcmsg structure
+ */
+static void send_disconnect_b3_ind(struct bc_state *bcs,
+ struct gigaset_capi_appl *ap)
+{
+ struct cardstate *cs = bcs->cs;
+ struct gigaset_capi_ctr *iif = cs->iif;
+ struct sk_buff *skb;
+
+ /* nothing to do if no logical connection active */
+ if (ap->connected < APCONN_ACTIVE)
+ return;
+ ap->connected = APCONN_SETUP;
+
+ capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT_B3, CAPI_IND,
+ ap->nextMessageNumber++,
+ iif->ctr.cnr | ((bcs->channel + 1) << 8) | (1 << 16));
+ skb = alloc_skb(CAPI_DISCONNECT_B3_IND_BASELEN, GFP_ATOMIC);
+ if (!skb) {
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
+ return;
+ }
+ capi_cmsg2message(&iif->hcmsg,
+ __skb_put(skb, CAPI_DISCONNECT_B3_IND_BASELEN));
+ dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg);
+ capi_ctr_handle_message(&iif->ctr, ap->id, skb);
+}
+
+/**
+ * gigaset_isdn_connD() - signal D channel connect
+ * @bcs: B channel descriptor structure.
+ *
+ * Called by main module at tasklet level to notify the LL that the D channel
+ * connection has been established.
+ */
+void gigaset_isdn_connD(struct bc_state *bcs)
+{
+ struct cardstate *cs = bcs->cs;
+ struct gigaset_capi_ctr *iif = cs->iif;
+ struct gigaset_capi_appl *ap = bcs->ap;
+ struct sk_buff *skb;
+ unsigned int msgsize;
+
+ if (!ap) {
+ dev_err(cs->dev, "%s: no application\n", __func__);
+ return;
+ }
+ while (ap->bcnext) {
+ /* this should never happen */
+ dev_warn(cs->dev, "%s: dropping extra application %u\n",
+ __func__, ap->bcnext->id);
+ send_disconnect_ind(bcs, ap->bcnext,
+ CapiCallGivenToOtherApplication);
+ ap->bcnext = ap->bcnext->bcnext;
+ }
+ if (ap->connected == APCONN_NONE) {
+ dev_warn(cs->dev, "%s: application %u not connected\n",
+ __func__, ap->id);
+ return;
+ }
+
+ /* prepare CONNECT_ACTIVE_IND message
+ * Note: LLC not supported by device
+ */
+ capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_CONNECT_ACTIVE, CAPI_IND,
+ ap->nextMessageNumber++,
+ iif->ctr.cnr | ((bcs->channel + 1) << 8));
+
+ /* minimum size, all structs empty */
+ msgsize = CAPI_CONNECT_ACTIVE_IND_BASELEN;
+
+ /* ToDo: set parameter: Connected number
+ * (requires ev-layer state machine extension to collect
+ * ZCON device reply)
+ */
+
+ /* build and emit CONNECT_ACTIVE_IND message */
+ skb = alloc_skb(msgsize, GFP_ATOMIC);
+ if (!skb) {
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
+ return;
+ }
+ capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize));
+ dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg);
+ capi_ctr_handle_message(&iif->ctr, ap->id, skb);
+}
+
+/**
+ * gigaset_isdn_hupD() - signal D channel hangup
+ * @bcs: B channel descriptor structure.
+ *
+ * Called by main module at tasklet level to notify the LL that the D channel
+ * connection has been shut down.
+ */
+void gigaset_isdn_hupD(struct bc_state *bcs)
+{
+ struct gigaset_capi_appl *ap;
+
+ /*
+ * ToDo: pass on reason code reported by device
+ * (requires ev-layer state machine extension to collect
+ * ZCAU device reply)
+ */
+ for (ap = bcs->ap; ap != NULL; ap = ap->bcnext) {
+ send_disconnect_b3_ind(bcs, ap);
+ send_disconnect_ind(bcs, ap, 0);
+ }
+ bcs->ap = NULL;
+}
+
+/**
+ * gigaset_isdn_connB() - signal B channel connect
+ * @bcs: B channel descriptor structure.
+ *
+ * Called by main module at tasklet level to notify the LL that the B channel
+ * connection has been established.
+ */
+void gigaset_isdn_connB(struct bc_state *bcs)
+{
+ struct cardstate *cs = bcs->cs;
+ struct gigaset_capi_ctr *iif = cs->iif;
+ struct gigaset_capi_appl *ap = bcs->ap;
+ struct sk_buff *skb;
+ unsigned int msgsize;
+ u8 command;
+
+ if (!ap) {
+ dev_err(cs->dev, "%s: no application\n", __func__);
+ return;
+ }
+ while (ap->bcnext) {
+ /* this should never happen */
+ dev_warn(cs->dev, "%s: dropping extra application %u\n",
+ __func__, ap->bcnext->id);
+ send_disconnect_ind(bcs, ap->bcnext,
+ CapiCallGivenToOtherApplication);
+ ap->bcnext = ap->bcnext->bcnext;
+ }
+ if (!ap->connected) {
+ dev_warn(cs->dev, "%s: application %u not connected\n",
+ __func__, ap->id);
+ return;
+ }
+
+ /*
+ * emit CONNECT_B3_ACTIVE_IND if we already got CONNECT_B3_REQ;
+ * otherwise we have to emit CONNECT_B3_IND first, and follow up with
+ * CONNECT_B3_ACTIVE_IND in reply to CONNECT_B3_RESP
+ * Parameters in both cases always: NCCI = 1, NCPI empty
+ */
+ if (ap->connected >= APCONN_ACTIVE) {
+ command = CAPI_CONNECT_B3_ACTIVE;
+ msgsize = CAPI_CONNECT_B3_ACTIVE_IND_BASELEN;
+ } else {
+ command = CAPI_CONNECT_B3;
+ msgsize = CAPI_CONNECT_B3_IND_BASELEN;
+ }
+ capi_cmsg_header(&iif->hcmsg, ap->id, command, CAPI_IND,
+ ap->nextMessageNumber++,
+ iif->ctr.cnr | ((bcs->channel + 1) << 8) | (1 << 16));
+ skb = alloc_skb(msgsize, GFP_ATOMIC);
+ if (!skb) {
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
+ return;
+ }
+ capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize));
+ dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg);
+ ap->connected = APCONN_ACTIVE;
+ capi_ctr_handle_message(&iif->ctr, ap->id, skb);
+}
+
+/**
+ * gigaset_isdn_hupB() - signal B channel hangup
+ * @bcs: B channel descriptor structure.
+ *
+ * Called by main module to notify the LL that the B channel connection has
+ * been shut down.
+ */
+void gigaset_isdn_hupB(struct bc_state *bcs)
+{
+ struct cardstate *cs = bcs->cs;
+ struct gigaset_capi_appl *ap = bcs->ap;
+
+ /* ToDo: assure order of DISCONNECT_B3_IND and DISCONNECT_IND ? */
+
+ if (!ap) {
+ dev_err(cs->dev, "%s: no application\n", __func__);
+ return;
+ }
+
+ send_disconnect_b3_ind(bcs, ap);
+}
+
+/**
+ * gigaset_isdn_start() - signal device availability
+ * @cs: device descriptor structure.
+ *
+ * Called by main module to notify the LL that the device is available for
+ * use.
+ */
+void gigaset_isdn_start(struct cardstate *cs)
+{
+ struct gigaset_capi_ctr *iif = cs->iif;
+
+ /* fill profile data: manufacturer name */
+ strcpy(iif->ctr.manu, "Siemens");
+ /* CAPI and device version */
+ iif->ctr.version.majorversion = 2; /* CAPI 2.0 */
+ iif->ctr.version.minorversion = 0;
+ /* ToDo: check/assert cs->gotfwver? */
+ iif->ctr.version.majormanuversion = cs->fwver[0];
+ iif->ctr.version.minormanuversion = cs->fwver[1];
+ /* number of B channels supported */
+ iif->ctr.profile.nbchannel = cs->channels;
+ /* global options: internal controller, supplementary services */
+ iif->ctr.profile.goptions = 0x11;
+ /* B1 protocols: 64 kbit/s HDLC or transparent */
+ iif->ctr.profile.support1 = 0x03;
+ /* B2 protocols: transparent only */
+ /* ToDo: X.75 SLP ? */
+ iif->ctr.profile.support2 = 0x02;
+ /* B3 protocols: transparent only */
+ iif->ctr.profile.support3 = 0x01;
+ /* no serial number */
+ strcpy(iif->ctr.serial, "0");
+ capi_ctr_ready(&iif->ctr);
+}
+
+/**
+ * gigaset_isdn_stop() - signal device unavailability
+ * @cs: device descriptor structure.
+ *
+ * Called by main module to notify the LL that the device is no longer
+ * available for use.
+ */
+void gigaset_isdn_stop(struct cardstate *cs)
+{
+ struct gigaset_capi_ctr *iif = cs->iif;
+ capi_ctr_down(&iif->ctr);
+}
+
+/*
+ * kernel CAPI callback methods
+ * ============================
+ */
+
+/*
+ * load firmware
+ */
+static int gigaset_load_firmware(struct capi_ctr *ctr, capiloaddata *data)
+{
+ struct cardstate *cs = ctr->driverdata;
+
+ /* AVM specific operation, not needed for Gigaset -- ignore */
+ dev_notice(cs->dev, "load_firmware ignored\n");
+
+ return 0;
+}
+
+/*
+ * reset (deactivate) controller
+ */
+static void gigaset_reset_ctr(struct capi_ctr *ctr)
+{
+ struct cardstate *cs = ctr->driverdata;
+
+ /* AVM specific operation, not needed for Gigaset -- ignore */
+ dev_notice(cs->dev, "reset_ctr ignored\n");
+}
+
+/*
+ * register CAPI application
+ */
+static void gigaset_register_appl(struct capi_ctr *ctr, u16 appl,
+ capi_register_params *rp)
+{
+ struct gigaset_capi_ctr *iif
+ = container_of(ctr, struct gigaset_capi_ctr, ctr);
+ struct cardstate *cs = ctr->driverdata;
+ struct gigaset_capi_appl *ap;
+
+ list_for_each_entry(ap, &iif->appls, ctrlist)
+ if (ap->id == appl) {
+ dev_notice(cs->dev,
+ "application %u already registered\n", appl);
+ return;
+ }
+
+ ap = kzalloc(sizeof(*ap), GFP_KERNEL);
+ if (!ap) {
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
+ return;
+ }
+ ap->id = appl;
+
+ list_add(&ap->ctrlist, &iif->appls);
+}
+
+/*
+ * release CAPI application
+ */
+static void gigaset_release_appl(struct capi_ctr *ctr, u16 appl)
+{
+ struct gigaset_capi_ctr *iif
+ = container_of(ctr, struct gigaset_capi_ctr, ctr);
+ struct cardstate *cs = iif->ctr.driverdata;
+ struct gigaset_capi_appl *ap, *tmp;
+
+ list_for_each_entry_safe(ap, tmp, &iif->appls, ctrlist)
+ if (ap->id == appl) {
+ if (ap->connected != APCONN_NONE) {
+ dev_err(cs->dev,
+ "%s: application %u still connected\n",
+ __func__, ap->id);
+ /* ToDo: clear active connection */
+ }
+ list_del(&ap->ctrlist);
+ kfree(ap);
+ }
+
+}
+
+/*
+ * =====================================================================
+ * outgoing CAPI message handler
+ * =====================================================================
+ */
+
+/*
+ * helper function: emit reply message with given Info value
+ */
+static void send_conf(struct gigaset_capi_ctr *iif,
+ struct gigaset_capi_appl *ap,
+ struct sk_buff *skb,
+ u16 info)
+{
+ /*
+ * _CONF replies always only have NCCI and Info parameters
+ * so they'll fit into the _REQ message skb
+ */
+ capi_cmsg_answer(&iif->acmsg);
+ iif->acmsg.Info = info;
+ capi_cmsg2message(&iif->acmsg, skb->data);
+ __skb_trim(skb, CAPI_STDCONF_LEN);
+ dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+ capi_ctr_handle_message(&iif->ctr, ap->id, skb);
+}
+
+/*
+ * process FACILITY_REQ message
+ */
+static void do_facility_req(struct gigaset_capi_ctr *iif,
+ struct gigaset_capi_appl *ap,
+ struct sk_buff *skb)
+{
+ struct cardstate *cs = iif->ctr.driverdata;
+ struct sk_buff *cskb;
+ u8 *pparam;
+ unsigned int msgsize = CAPI_FACILITY_CONF_BASELEN;
+ u16 function, info;
+ static u8 confparam[10]; /* max. 9 octets + length byte */
+
+ /* decode message */
+ capi_message2cmsg(&iif->acmsg, skb->data);
+ dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+
+ /*
+ * Facility Request Parameter is not decoded by capi_message2cmsg()
+ * encoding depends on Facility Selector
+ */
+ switch (iif->acmsg.FacilitySelector) {
+ case CAPI_FACILITY_DTMF: /* ToDo */
+ info = CapiFacilityNotSupported;
+ confparam[0] = 2; /* length */
+ /* DTMF information: Unknown DTMF request */
+ capimsg_setu16(confparam, 1, 2);
+ break;
+
+ case CAPI_FACILITY_V42BIS: /* not supported */
+ info = CapiFacilityNotSupported;
+ confparam[0] = 2; /* length */
+ /* V.42 bis information: not available */
+ capimsg_setu16(confparam, 1, 1);
+ break;
+
+ case CAPI_FACILITY_SUPPSVC:
+ /* decode Function parameter */
+ pparam = iif->acmsg.FacilityRequestParameter;
+ if (pparam == NULL || *pparam < 2) {
+ dev_notice(cs->dev, "%s: %s missing\n", "FACILITY_REQ",
+ "Facility Request Parameter");
+ send_conf(iif, ap, skb, CapiIllMessageParmCoding);
+ return;
+ }
+ function = CAPIMSG_U16(pparam, 1);
+ switch (function) {
+ case CAPI_SUPPSVC_GETSUPPORTED:
+ info = CapiSuccess;
+ /* Supplementary Service specific parameter */
+ confparam[3] = 6; /* length */
+ /* Supplementary services info: Success */
+ capimsg_setu16(confparam, 4, CapiSuccess);
+ /* Supported Services: none */
+ capimsg_setu32(confparam, 6, 0);
+ break;
+ /* ToDo: add supported services */
+ default:
+ info = CapiFacilitySpecificFunctionNotSupported;
+ /* Supplementary Service specific parameter */
+ confparam[3] = 2; /* length */
+ /* Supplementary services info: not supported */
+ capimsg_setu16(confparam, 4,
+ CapiSupplementaryServiceNotSupported);
+ }
+
+ /* Facility confirmation parameter */
+ confparam[0] = confparam[3] + 3; /* total length */
+ /* Function: copy from _REQ message */
+ capimsg_setu16(confparam, 1, function);
+ /* Supplementary Service specific parameter already set above */
+ break;
+
+ case CAPI_FACILITY_WAKEUP: /* ToDo */
+ info = CapiFacilityNotSupported;
+ confparam[0] = 2; /* length */
+ /* Number of accepted awake request parameters: 0 */
+ capimsg_setu16(confparam, 1, 0);
+ break;
+
+ default:
+ info = CapiFacilityNotSupported;
+ confparam[0] = 0; /* empty struct */
+ }
+
+ /* send FACILITY_CONF with given Info and confirmation parameter */
+ capi_cmsg_answer(&iif->acmsg);
+ iif->acmsg.Info = info;
+ iif->acmsg.FacilityConfirmationParameter = confparam;
+ msgsize += confparam[0]; /* length */
+ cskb = alloc_skb(msgsize, GFP_ATOMIC);
+ if (!cskb) {
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
+ return;
+ }
+ capi_cmsg2message(&iif->acmsg, __skb_put(cskb, msgsize));
+ dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+ capi_ctr_handle_message(&iif->ctr, ap->id, cskb);
+}
+
+
+/*
+ * process LISTEN_REQ message
+ * just store the masks in the application data structure
+ */
+static void do_listen_req(struct gigaset_capi_ctr *iif,
+ struct gigaset_capi_appl *ap,
+ struct sk_buff *skb)
+{
+ /* decode message */
+ capi_message2cmsg(&iif->acmsg, skb->data);
+ dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+
+ /* store listening parameters */
+ ap->listenInfoMask = iif->acmsg.InfoMask;
+ ap->listenCIPmask = iif->acmsg.CIPmask;
+ send_conf(iif, ap, skb, CapiSuccess);
+}
+
+/*
+ * process ALERT_REQ message
+ * nothing to do, Gigaset always alerts anyway
+ */
+static void do_alert_req(struct gigaset_capi_ctr *iif,
+ struct gigaset_capi_appl *ap,
+ struct sk_buff *skb)
+{
+ /* decode message */
+ capi_message2cmsg(&iif->acmsg, skb->data);
+ dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+ send_conf(iif, ap, skb, CapiAlertAlreadySent);
+}
+
+/*
+ * process CONNECT_REQ message
+ * allocate a B channel, prepare dial commands, queue a DIAL event,
+ * emit CONNECT_CONF reply
+ */
+static void do_connect_req(struct gigaset_capi_ctr *iif,
+ struct gigaset_capi_appl *ap,
+ struct sk_buff *skb)
+{
+ struct cardstate *cs = iif->ctr.driverdata;
+ _cmsg *cmsg = &iif->acmsg;
+ struct bc_state *bcs;
+ char **commands;
+ char *s;
+ u8 *pp;
+ int i, l;
+ u16 info;
+
+ /* decode message */
+ capi_message2cmsg(&iif->acmsg, skb->data);
+ dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+
+ /* get free B channel & construct PLCI */
+ bcs = gigaset_get_free_channel(cs);
+ if (!bcs) {
+ dev_notice(cs->dev, "%s: no B channel available\n",
+ "CONNECT_REQ");
+ send_conf(iif, ap, skb, CapiNoPlciAvailable);
+ return;
+ }
+ ap->bcnext = NULL;
+ bcs->ap = ap;
+ cmsg->adr.adrPLCI |= (bcs->channel + 1) << 8;
+
+ /* build command table */
+ commands = kzalloc(AT_NUM*(sizeof *commands), GFP_KERNEL);
+ if (!commands)
+ goto oom;
+
+ /* encode parameter: Called party number */
+ pp = cmsg->CalledPartyNumber;
+ if (pp == NULL || *pp == 0) {
+ dev_notice(cs->dev, "%s: %s missing\n",
+ "CONNECT_REQ", "Called party number");
+ info = CapiIllMessageParmCoding;
+ goto error;
+ }
+ l = *pp++;
+ /* check type of number/numbering plan byte */
+ switch (*pp) {
+ case 0x80: /* unknown type / unknown numbering plan */
+ case 0x81: /* unknown type / ISDN/Telephony numbering plan */
+ break;
+ default: /* others: warn about potential misinterpretation */
+ dev_notice(cs->dev, "%s: %s type/plan 0x%02x unsupported\n",
+ "CONNECT_REQ", "Called party number", *pp);
+ }
+ pp++;
+ l--;
+ /* translate "**" internal call prefix to CTP value */
+ if (l >= 2 && pp[0] == '*' && pp[1] == '*') {
+ s = "^SCTP=0\r";
+ pp += 2;
+ l -= 2;
+ } else {
+ s = "^SCTP=1\r";
+ }
+ commands[AT_TYPE] = kstrdup(s, GFP_KERNEL);
+ if (!commands[AT_TYPE])
+ goto oom;
+ commands[AT_DIAL] = kmalloc(l+3, GFP_KERNEL);
+ if (!commands[AT_DIAL])
+ goto oom;
+ snprintf(commands[AT_DIAL], l+3, "D%*s\r", l, pp);
+
+ /* encode parameter: Calling party number */
+ pp = cmsg->CallingPartyNumber;
+ if (pp != NULL && *pp > 0) {
+ l = *pp++;
+
+ /* check type of number/numbering plan byte */
+ /* ToDo: allow for/handle Ext=1? */
+ switch (*pp) {
+ case 0x00: /* unknown type / unknown numbering plan */
+ case 0x01: /* unknown type / ISDN/Telephony num. plan */
+ break;
+ default:
+ dev_notice(cs->dev,
+ "%s: %s type/plan 0x%02x unsupported\n",
+ "CONNECT_REQ", "Calling party number", *pp);
+ }
+ pp++;
+ l--;
+
+ /* check presentation indicator */
+ if (!l) {
+ dev_notice(cs->dev, "%s: %s IE truncated\n",
+ "CONNECT_REQ", "Calling party number");
+ info = CapiIllMessageParmCoding;
+ goto error;
+ }
+ switch (*pp & 0xfc) { /* ignore Screening indicator */
+ case 0x80: /* Presentation allowed */
+ s = "^SCLIP=1\r";
+ break;
+ case 0xa0: /* Presentation restricted */
+ s = "^SCLIP=0\r";
+ break;
+ default:
+ dev_notice(cs->dev, "%s: invalid %s 0x%02x\n",
+ "CONNECT_REQ",
+ "Presentation/Screening indicator",
+ *pp);
+ s = "^SCLIP=1\r";
+ }
+ commands[AT_CLIP] = kstrdup(s, GFP_KERNEL);
+ if (!commands[AT_CLIP])
+ goto oom;
+ pp++;
+ l--;
+
+ if (l) {
+ /* number */
+ commands[AT_MSN] = kmalloc(l+8, GFP_KERNEL);
+ if (!commands[AT_MSN])
+ goto oom;
+ snprintf(commands[AT_MSN], l+8, "^SMSN=%*s\r", l, pp);
+ }
+ }
+
+ /* check parameter: CIP Value */
+ if (cmsg->CIPValue > ARRAY_SIZE(cip2bchlc) ||
+ (cmsg->CIPValue > 0 && cip2bchlc[cmsg->CIPValue].bc == NULL)) {
+ dev_notice(cs->dev, "%s: unknown CIP value %d\n",
+ "CONNECT_REQ", cmsg->CIPValue);
+ info = CapiCipValueUnknown;
+ goto error;
+ }
+
+ /* check/encode parameter: BC */
+ if (cmsg->BC && cmsg->BC[0]) {
+ /* explicit BC overrides CIP */
+ l = 2*cmsg->BC[0] + 7;
+ commands[AT_BC] = kmalloc(l, GFP_KERNEL);
+ if (!commands[AT_BC])
+ goto oom;
+ strcpy(commands[AT_BC], "^SBC=");
+ decode_ie(cmsg->BC, commands[AT_BC]+5);
+ strcpy(commands[AT_BC] + l - 2, "\r");
+ } else if (cip2bchlc[cmsg->CIPValue].bc) {
+ l = strlen(cip2bchlc[cmsg->CIPValue].bc) + 7;
+ commands[AT_BC] = kmalloc(l, GFP_KERNEL);
+ if (!commands[AT_BC])
+ goto oom;
+ snprintf(commands[AT_BC], l, "^SBC=%s\r",
+ cip2bchlc[cmsg->CIPValue].bc);
+ }
+
+ /* check/encode parameter: HLC */
+ if (cmsg->HLC && cmsg->HLC[0]) {
+ /* explicit HLC overrides CIP */
+ l = 2*cmsg->HLC[0] + 7;
+ commands[AT_HLC] = kmalloc(l, GFP_KERNEL);
+ if (!commands[AT_HLC])
+ goto oom;
+ strcpy(commands[AT_HLC], "^SHLC=");
+ decode_ie(cmsg->HLC, commands[AT_HLC]+5);
+ strcpy(commands[AT_HLC] + l - 2, "\r");
+ } else if (cip2bchlc[cmsg->CIPValue].hlc) {
+ l = strlen(cip2bchlc[cmsg->CIPValue].hlc) + 7;
+ commands[AT_HLC] = kmalloc(l, GFP_KERNEL);
+ if (!commands[AT_HLC])
+ goto oom;
+ snprintf(commands[AT_HLC], l, "^SHLC=%s\r",
+ cip2bchlc[cmsg->CIPValue].hlc);
+ }
+
+ /* check/encode parameter: B Protocol */
+ if (cmsg->BProtocol == CAPI_DEFAULT) {
+ bcs->proto2 = L2_HDLC;
+ dev_warn(cs->dev,
+ "B2 Protocol X.75 SLP unsupported, using Transparent\n");
+ } else {
+ switch (cmsg->B1protocol) {
+ case 0:
+ bcs->proto2 = L2_HDLC;
+ break;
+ case 1:
+ bcs->proto2 = L2_BITSYNC;
+ break;
+ default:
+ dev_warn(cs->dev,
+ "B1 Protocol %u unsupported, using Transparent\n",
+ cmsg->B1protocol);
+ bcs->proto2 = L2_BITSYNC;
+ }
+ if (cmsg->B2protocol != 1)
+ dev_warn(cs->dev,
+ "B2 Protocol %u unsupported, using Transparent\n",
+ cmsg->B2protocol);
+ if (cmsg->B3protocol != 0)
+ dev_warn(cs->dev,
+ "B3 Protocol %u unsupported, using Transparent\n",
+ cmsg->B3protocol);
+ ignore_cstruct_param(cs, cmsg->B1configuration,
+ "CONNECT_REQ", "B1 Configuration");
+ ignore_cstruct_param(cs, cmsg->B2configuration,
+ "CONNECT_REQ", "B2 Configuration");
+ ignore_cstruct_param(cs, cmsg->B3configuration,
+ "CONNECT_REQ", "B3 Configuration");
+ }
+ commands[AT_PROTO] = kmalloc(9, GFP_KERNEL);
+ if (!commands[AT_PROTO])
+ goto oom;
+ snprintf(commands[AT_PROTO], 9, "^SBPR=%u\r", bcs->proto2);
+
+ /* ToDo: check/encode remaining parameters */
+ ignore_cstruct_param(cs, cmsg->CalledPartySubaddress,
+ "CONNECT_REQ", "Called pty subaddr");
+ ignore_cstruct_param(cs, cmsg->CallingPartySubaddress,
+ "CONNECT_REQ", "Calling pty subaddr");
+ ignore_cstruct_param(cs, cmsg->LLC,
+ "CONNECT_REQ", "LLC");
+ ignore_cmstruct_param(cs, cmsg->AdditionalInfo,
+ "CONNECT_REQ", "Additional Info");
+
+ /* encode parameter: B channel to use */
+ commands[AT_ISO] = kmalloc(9, GFP_KERNEL);
+ if (!commands[AT_ISO])
+ goto oom;
+ snprintf(commands[AT_ISO], 9, "^SISO=%u\r",
+ (unsigned) bcs->channel + 1);
+
+ /* queue & schedule EV_DIAL event */
+ if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, commands,
+ bcs->at_state.seq_index, NULL))
+ goto oom;
+ gig_dbg(DEBUG_CMD, "scheduling DIAL");
+ gigaset_schedule_event(cs);
+ ap->connected = APCONN_SETUP;
+ send_conf(iif, ap, skb, CapiSuccess);
+ return;
+
+oom:
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
+ info = CAPI_MSGOSRESOURCEERR;
+error:
+ if (commands)
+ for (i = 0; i < AT_NUM; i++)
+ kfree(commands[i]);
+ kfree(commands);
+ gigaset_free_channel(bcs);
+ send_conf(iif, ap, skb, info);
+}
+
+/*
+ * process CONNECT_RESP message
+ * checks protocol parameters and queues an ACCEPT or HUP event
+ */
+static void do_connect_resp(struct gigaset_capi_ctr *iif,
+ struct gigaset_capi_appl *ap,
+ struct sk_buff *skb)
+{
+ struct cardstate *cs = iif->ctr.driverdata;
+ _cmsg *cmsg = &iif->acmsg;
+ struct bc_state *bcs;
+ struct gigaset_capi_appl *oap;
+ int channel;
+
+ /* decode message */
+ capi_message2cmsg(&iif->acmsg, skb->data);
+ dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+ dev_kfree_skb(skb);
+
+ /* extract and check channel number from PLCI */
+ channel = (cmsg->adr.adrPLCI >> 8) & 0xff;
+ if (!channel || channel > cs->channels) {
+ dev_notice(cs->dev, "%s: invalid %s 0x%02x\n",
+ "CONNECT_RESP", "PLCI", cmsg->adr.adrPLCI);
+ return;
+ }
+ bcs = cs->bcs + channel - 1;
+
+ switch (cmsg->Reject) {
+ case 0: /* Accept */
+ /* drop all competing applications, keep only this one */
+ for (oap = bcs->ap; oap != NULL; oap = oap->bcnext)
+ if (oap != ap)
+ send_disconnect_ind(bcs, oap,
+ CapiCallGivenToOtherApplication);
+ ap->bcnext = NULL;
+ bcs->ap = ap;
+ bcs->chstate |= CHS_NOTIFY_LL;
+
+ /* check/encode B channel protocol */
+ if (cmsg->BProtocol == CAPI_DEFAULT) {
+ bcs->proto2 = L2_HDLC;
+ dev_warn(cs->dev,
+ "B2 Protocol X.75 SLP unsupported, using Transparent\n");
+ } else {
+ switch (cmsg->B1protocol) {
+ case 0:
+ bcs->proto2 = L2_HDLC;
+ break;
+ case 1:
+ bcs->proto2 = L2_BITSYNC;
+ break;
+ default:
+ dev_warn(cs->dev,
+ "B1 Protocol %u unsupported, using Transparent\n",
+ cmsg->B1protocol);
+ bcs->proto2 = L2_BITSYNC;
+ }
+ if (cmsg->B2protocol != 1)
+ dev_warn(cs->dev,
+ "B2 Protocol %u unsupported, using Transparent\n",
+ cmsg->B2protocol);
+ if (cmsg->B3protocol != 0)
+ dev_warn(cs->dev,
+ "B3 Protocol %u unsupported, using Transparent\n",
+ cmsg->B3protocol);
+ ignore_cstruct_param(cs, cmsg->B1configuration,
+ "CONNECT_RESP", "B1 Configuration");
+ ignore_cstruct_param(cs, cmsg->B2configuration,
+ "CONNECT_RESP", "B2 Configuration");
+ ignore_cstruct_param(cs, cmsg->B3configuration,
+ "CONNECT_RESP", "B3 Configuration");
+ }
+
+ /* ToDo: check/encode remaining parameters */
+ ignore_cstruct_param(cs, cmsg->ConnectedNumber,
+ "CONNECT_RESP", "Connected Number");
+ ignore_cstruct_param(cs, cmsg->ConnectedSubaddress,
+ "CONNECT_RESP", "Connected Subaddress");
+ ignore_cstruct_param(cs, cmsg->LLC,
+ "CONNECT_RESP", "LLC");
+ ignore_cmstruct_param(cs, cmsg->AdditionalInfo,
+ "CONNECT_RESP", "Additional Info");
+
+ /* Accept call */
+ if (!gigaset_add_event(cs, &cs->bcs[channel-1].at_state,
+ EV_ACCEPT, NULL, 0, NULL))
+ return;
+ gig_dbg(DEBUG_CMD, "scheduling ACCEPT");
+ gigaset_schedule_event(cs);
+ return;
+
+ case 1: /* Ignore */
+ /* send DISCONNECT_IND to this application */
+ send_disconnect_ind(bcs, ap, 0);
+
+ /* remove it from the list of listening apps */
+ if (bcs->ap == ap) {
+ bcs->ap = ap->bcnext;
+ if (bcs->ap == NULL)
+ /* last one: stop ev-layer hupD notifications */
+ bcs->chstate &= ~CHS_NOTIFY_LL;
+ return;
+ }
+ for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) {
+ if (oap->bcnext == ap) {
+ oap->bcnext = oap->bcnext->bcnext;
+ return;
+ }
+ }
+ dev_err(cs->dev, "%s: application %u not found\n",
+ __func__, ap->id);
+ return;
+
+ default: /* Reject */
+ /* drop all competing applications, keep only this one */
+ for (oap = bcs->ap; oap != NULL; oap = oap->bcnext)
+ if (oap != ap)
+ send_disconnect_ind(bcs, oap,
+ CapiCallGivenToOtherApplication);
+ ap->bcnext = NULL;
+ bcs->ap = ap;
+
+ /* reject call - will trigger DISCONNECT_IND for this app */
+ dev_info(cs->dev, "%s: Reject=%x\n",
+ "CONNECT_RESP", cmsg->Reject);
+ if (!gigaset_add_event(cs, &cs->bcs[channel-1].at_state,
+ EV_HUP, NULL, 0, NULL))
+ return;
+ gig_dbg(DEBUG_CMD, "scheduling HUP");
+ gigaset_schedule_event(cs);
+ return;
+ }
+}
+
+/*
+ * process CONNECT_B3_REQ message
+ * build NCCI and emit CONNECT_B3_CONF reply
+ */
+static void do_connect_b3_req(struct gigaset_capi_ctr *iif,
+ struct gigaset_capi_appl *ap,
+ struct sk_buff *skb)
+{
+ struct cardstate *cs = iif->ctr.driverdata;
+ int channel;
+
+ /* decode message */
+ capi_message2cmsg(&iif->acmsg, skb->data);
+ dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+
+ /* extract and check channel number from PLCI */
+ channel = (iif->acmsg.adr.adrPLCI >> 8) & 0xff;
+ if (!channel || channel > cs->channels) {
+ dev_notice(cs->dev, "%s: invalid %s 0x%02x\n",
+ "CONNECT_B3_REQ", "PLCI", iif->acmsg.adr.adrPLCI);
+ send_conf(iif, ap, skb, CapiIllContrPlciNcci);
+ return;
+ }
+
+ /* mark logical connection active */
+ ap->connected = APCONN_ACTIVE;
+
+ /* build NCCI: always 1 (one B3 connection only) */
+ iif->acmsg.adr.adrNCCI |= 1 << 16;
+
+ /* NCPI parameter: not applicable for B3 Transparent */
+ ignore_cstruct_param(cs, iif->acmsg.NCPI,
+ "CONNECT_B3_REQ", "NCPI");
+ send_conf(iif, ap, skb,
+ (iif->acmsg.NCPI && iif->acmsg.NCPI[0]) ?
+ CapiNcpiNotSupportedByProtocol : CapiSuccess);
+}
+
+/*
+ * process CONNECT_B3_RESP message
+ * Depending on the Reject parameter, either emit CONNECT_B3_ACTIVE_IND
+ * or queue EV_HUP and emit DISCONNECT_B3_IND.
+ * The emitted message is always shorter than the received one,
+ * allowing to reuse the skb.
+ */
+static void do_connect_b3_resp(struct gigaset_capi_ctr *iif,
+ struct gigaset_capi_appl *ap,
+ struct sk_buff *skb)
+{
+ struct cardstate *cs = iif->ctr.driverdata;
+ struct bc_state *bcs = NULL;
+ int channel;
+ unsigned int msgsize;
+ u8 command;
+
+ /* decode message */
+ capi_message2cmsg(&iif->acmsg, skb->data);
+ dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+
+ /* extract and check channel number and NCCI */
+ channel = (iif->acmsg.adr.adrNCCI >> 8) & 0xff;
+ if (!channel || channel > cs->channels ||
+ ((iif->acmsg.adr.adrNCCI >> 16) & 0xffff) != 1) {
+ dev_notice(cs->dev, "%s: invalid %s 0x%02x\n",
+ "CONNECT_B3_RESP", "NCCI", iif->acmsg.adr.adrNCCI);
+ dev_kfree_skb(skb);
+ return;
+ }
+ bcs = &cs->bcs[channel-1];
+
+ if (iif->acmsg.Reject) {
+ /* Reject: clear B3 connect received flag */
+ ap->connected = APCONN_SETUP;
+
+ /* trigger hangup, causing eventual DISCONNECT_IND */
+ if (!gigaset_add_event(cs, &bcs->at_state,
+ EV_HUP, NULL, 0, NULL)) {
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
+ dev_kfree_skb(skb);
+ return;
+ }
+ gig_dbg(DEBUG_CMD, "scheduling HUP");
+ gigaset_schedule_event(cs);
+
+ /* emit DISCONNECT_B3_IND */
+ command = CAPI_DISCONNECT_B3;
+ msgsize = CAPI_DISCONNECT_B3_IND_BASELEN;
+ } else {
+ /*
+ * Accept: emit CONNECT_B3_ACTIVE_IND immediately, as
+ * we only send CONNECT_B3_IND if the B channel is up
+ */
+ command = CAPI_CONNECT_B3_ACTIVE;
+ msgsize = CAPI_CONNECT_B3_ACTIVE_IND_BASELEN;
+ }
+ capi_cmsg_header(&iif->acmsg, ap->id, command, CAPI_IND,
+ ap->nextMessageNumber++, iif->acmsg.adr.adrNCCI);
+ __skb_trim(skb, msgsize);
+ capi_cmsg2message(&iif->acmsg, skb->data);
+ dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+ capi_ctr_handle_message(&iif->ctr, ap->id, skb);
+}
+
+/*
+ * process DISCONNECT_REQ message
+ * schedule EV_HUP and emit DISCONNECT_B3_IND if necessary,
+ * emit DISCONNECT_CONF reply
+ */
+static void do_disconnect_req(struct gigaset_capi_ctr *iif,
+ struct gigaset_capi_appl *ap,
+ struct sk_buff *skb)
+{
+ struct cardstate *cs = iif->ctr.driverdata;
+ struct bc_state *bcs;
+ _cmsg *b3cmsg;
+ struct sk_buff *b3skb;
+ int channel;
+
+ /* decode message */
+ capi_message2cmsg(&iif->acmsg, skb->data);
+ dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+
+ /* extract and check channel number from PLCI */
+ channel = (iif->acmsg.adr.adrPLCI >> 8) & 0xff;
+ if (!channel || channel > cs->channels) {
+ dev_notice(cs->dev, "%s: invalid %s 0x%02x\n",
+ "DISCONNECT_REQ", "PLCI", iif->acmsg.adr.adrPLCI);
+ send_conf(iif, ap, skb, CapiIllContrPlciNcci);
+ return;
+ }
+ bcs = cs->bcs + channel - 1;
+
+ /* ToDo: process parameter: Additional info */
+ ignore_cmstruct_param(cs, iif->acmsg.AdditionalInfo,
+ "DISCONNECT_REQ", "Additional Info");
+
+ /* skip if DISCONNECT_IND already sent */
+ if (!ap->connected)
+ return;
+
+ /* check for active logical connection */
+ if (ap->connected >= APCONN_ACTIVE) {
+ /*
+ * emit DISCONNECT_B3_IND with cause 0x3301
+ * use separate cmsg structure, as the content of iif->acmsg
+ * is still needed for creating the _CONF message
+ */
+ b3cmsg = kmalloc(sizeof(*b3cmsg), GFP_KERNEL);
+ if (!b3cmsg) {
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
+ send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR);
+ return;
+ }
+ capi_cmsg_header(b3cmsg, ap->id, CAPI_DISCONNECT_B3, CAPI_IND,
+ ap->nextMessageNumber++,
+ iif->acmsg.adr.adrPLCI | (1 << 16));
+ b3cmsg->Reason_B3 = CapiProtocolErrorLayer1;
+ b3skb = alloc_skb(CAPI_DISCONNECT_B3_IND_BASELEN, GFP_KERNEL);
+ if (b3skb == NULL) {
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
+ send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR);
+ return;
+ }
+ capi_cmsg2message(b3cmsg,
+ __skb_put(b3skb, CAPI_DISCONNECT_B3_IND_BASELEN));
+ kfree(b3cmsg);
+ capi_ctr_handle_message(&iif->ctr, ap->id, b3skb);
+ }
+
+ /* trigger hangup, causing eventual DISCONNECT_IND */
+ if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) {
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
+ send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR);
+ return;
+ }
+ gig_dbg(DEBUG_CMD, "scheduling HUP");
+ gigaset_schedule_event(cs);
+
+ /* emit reply */
+ send_conf(iif, ap, skb, CapiSuccess);
+}
+
+/*
+ * process DISCONNECT_B3_REQ message
+ * schedule EV_HUP and emit DISCONNECT_B3_CONF reply
+ */
+static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif,
+ struct gigaset_capi_appl *ap,
+ struct sk_buff *skb)
+{
+ struct cardstate *cs = iif->ctr.driverdata;
+ int channel;
+
+ /* decode message */
+ capi_message2cmsg(&iif->acmsg, skb->data);
+ dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+
+ /* extract and check channel number and NCCI */
+ channel = (iif->acmsg.adr.adrNCCI >> 8) & 0xff;
+ if (!channel || channel > cs->channels ||
+ ((iif->acmsg.adr.adrNCCI >> 16) & 0xffff) != 1) {
+ dev_notice(cs->dev, "%s: invalid %s 0x%02x\n",
+ "DISCONNECT_B3_REQ", "NCCI", iif->acmsg.adr.adrNCCI);
+ send_conf(iif, ap, skb, CapiIllContrPlciNcci);
+ return;
+ }
+
+ /* reject if logical connection not active */
+ if (ap->connected < APCONN_ACTIVE) {
+ send_conf(iif, ap, skb,
+ CapiMessageNotSupportedInCurrentState);
+ return;
+ }
+
+ /* trigger hangup, causing eventual DISCONNECT_B3_IND */
+ if (!gigaset_add_event(cs, &cs->bcs[channel-1].at_state,
+ EV_HUP, NULL, 0, NULL)) {
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
+ send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR);
+ return;
+ }
+ gig_dbg(DEBUG_CMD, "scheduling HUP");
+ gigaset_schedule_event(cs);
+
+ /* NCPI parameter: not applicable for B3 Transparent */
+ ignore_cstruct_param(cs, iif->acmsg.NCPI,
+ "DISCONNECT_B3_REQ", "NCPI");
+ send_conf(iif, ap, skb,
+ (iif->acmsg.NCPI && iif->acmsg.NCPI[0]) ?
+ CapiNcpiNotSupportedByProtocol : CapiSuccess);
+}
+
+/*
+ * process DATA_B3_REQ message
+ */
+static void do_data_b3_req(struct gigaset_capi_ctr *iif,
+ struct gigaset_capi_appl *ap,
+ struct sk_buff *skb)
+{
+ struct cardstate *cs = iif->ctr.driverdata;
+ int channel = CAPIMSG_PLCI_PART(skb->data);
+ u16 ncci = CAPIMSG_NCCI_PART(skb->data);
+ u16 msglen = CAPIMSG_LEN(skb->data);
+ u16 datalen = CAPIMSG_DATALEN(skb->data);
+ u16 flags = CAPIMSG_FLAGS(skb->data);
+
+ /* frequent message, avoid _cmsg overhead */
+ dump_rawmsg(DEBUG_LLDATA, "DATA_B3_REQ", skb->data);
+
+ gig_dbg(DEBUG_LLDATA,
+ "Receiving data from LL (ch: %d, flg: %x, sz: %d|%d)",
+ channel, flags, msglen, datalen);
+
+ /* check parameters */
+ if (channel == 0 || channel > cs->channels || ncci != 1) {
+ dev_notice(cs->dev, "%s: invalid %s 0x%02x\n",
+ "DATA_B3_REQ", "NCCI", CAPIMSG_NCCI(skb->data));
+ send_conf(iif, ap, skb, CapiIllContrPlciNcci);
+ return;
+ }
+ if (msglen != CAPI_DATA_B3_REQ_LEN && msglen != CAPI_DATA_B3_REQ_LEN64)
+ dev_notice(cs->dev, "%s: unexpected length %d\n",
+ "DATA_B3_REQ", msglen);
+ if (msglen + datalen != skb->len)
+ dev_notice(cs->dev, "%s: length mismatch (%d+%d!=%d)\n",
+ "DATA_B3_REQ", msglen, datalen, skb->len);
+ if (msglen + datalen > skb->len) {
+ /* message too short for announced data length */
+ send_conf(iif, ap, skb, CapiIllMessageParmCoding); /* ? */
+ return;
+ }
+ if (flags & CAPI_FLAGS_RESERVED) {
+ dev_notice(cs->dev, "%s: reserved flags set (%x)\n",
+ "DATA_B3_REQ", flags);
+ send_conf(iif, ap, skb, CapiIllMessageParmCoding);
+ return;
+ }
+
+ /* reject if logical connection not active */
+ if (ap->connected < APCONN_ACTIVE) {
+ send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState);
+ return;
+ }
+
+ /*
+ * pull CAPI message from skb,
+ * pass payload data to device-specific module
+ * CAPI message will be preserved in headroom
+ */
+ skb_pull(skb, msglen);
+ if (cs->ops->send_skb(&cs->bcs[channel-1], skb) < 0) {
+ send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR);
+ return;
+ }
+
+ /* DATA_B3_CONF reply will be sent by gigaset_skb_sent() */
+
+ /*
+ * ToDo: honor unset "delivery confirmation" bit
+ * (send DATA_B3_CONF immediately?)
+ */
+}
+
+/*
+ * process RESET_B3_REQ message
+ * just always reply "not supported by current protocol"
+ */
+static void do_reset_b3_req(struct gigaset_capi_ctr *iif,
+ struct gigaset_capi_appl *ap,
+ struct sk_buff *skb)
+{
+ /* decode message */
+ capi_message2cmsg(&iif->acmsg, skb->data);
+ dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+ send_conf(iif, ap, skb,
+ CapiResetProcedureNotSupportedByCurrentProtocol);
+}
+
+/*
+ * dump unsupported/ignored messages at most twice per minute,
+ * some apps send those very frequently
+ */
+static unsigned long ignored_msg_dump_time;
+
+/*
+ * unsupported CAPI message handler
+ */
+static void do_unsupported(struct gigaset_capi_ctr *iif,
+ struct gigaset_capi_appl *ap,
+ struct sk_buff *skb)
+{
+ /* decode message */
+ capi_message2cmsg(&iif->acmsg, skb->data);
+ if (printk_timed_ratelimit(&ignored_msg_dump_time, 30 * 1000))
+ dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+ send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState);
+}
+
+/*
+ * CAPI message handler: no-op
+ */
+static void do_nothing(struct gigaset_capi_ctr *iif,
+ struct gigaset_capi_appl *ap,
+ struct sk_buff *skb)
+{
+ if (printk_timed_ratelimit(&ignored_msg_dump_time, 30 * 1000)) {
+ /* decode message */
+ capi_message2cmsg(&iif->acmsg, skb->data);
+ dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg);
+ }
+ dev_kfree_skb(skb);
+}
+
+static void do_data_b3_resp(struct gigaset_capi_ctr *iif,
+ struct gigaset_capi_appl *ap,
+ struct sk_buff *skb)
+{
+ dump_rawmsg(DEBUG_LLDATA, __func__, skb->data);
+ dev_kfree_skb(skb);
+}
+
+/* table of outgoing CAPI message handlers with lookup function */
+typedef void (*capi_send_handler_t)(struct gigaset_capi_ctr *,
+ struct gigaset_capi_appl *,
+ struct sk_buff *);
+
+static struct {
+ u16 cmd;
+ capi_send_handler_t handler;
+} capi_send_handler_table[] = {
+ /* most frequent messages first for faster lookup */
+ { CAPI_DATA_B3_REQ, do_data_b3_req },
+ { CAPI_DATA_B3_RESP, do_data_b3_resp },
+
+ { CAPI_ALERT_REQ, do_alert_req },
+ { CAPI_CONNECT_ACTIVE_RESP, do_nothing },
+ { CAPI_CONNECT_B3_ACTIVE_RESP, do_nothing },
+ { CAPI_CONNECT_B3_REQ, do_connect_b3_req },
+ { CAPI_CONNECT_B3_RESP, do_connect_b3_resp },
+ { CAPI_CONNECT_B3_T90_ACTIVE_RESP, do_nothing },
+ { CAPI_CONNECT_REQ, do_connect_req },
+ { CAPI_CONNECT_RESP, do_connect_resp },
+ { CAPI_DISCONNECT_B3_REQ, do_disconnect_b3_req },
+ { CAPI_DISCONNECT_B3_RESP, do_nothing },
+ { CAPI_DISCONNECT_REQ, do_disconnect_req },
+ { CAPI_DISCONNECT_RESP, do_nothing },
+ { CAPI_FACILITY_REQ, do_facility_req },
+ { CAPI_FACILITY_RESP, do_nothing },
+ { CAPI_LISTEN_REQ, do_listen_req },
+ { CAPI_SELECT_B_PROTOCOL_REQ, do_unsupported },
+ { CAPI_RESET_B3_REQ, do_reset_b3_req },
+ { CAPI_RESET_B3_RESP, do_nothing },
+
+ /*
+ * ToDo: support overlap sending (requires ev-layer state
+ * machine extension to generate additional ATD commands)
+ */
+ { CAPI_INFO_REQ, do_unsupported },
+ { CAPI_INFO_RESP, do_nothing },
+
+ /*
+ * ToDo: what's the proper response for these?
+ */
+ { CAPI_MANUFACTURER_REQ, do_nothing },
+ { CAPI_MANUFACTURER_RESP, do_nothing },
+};
+
+/* look up handler */
+static inline capi_send_handler_t lookup_capi_send_handler(const u16 cmd)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(capi_send_handler_table); i++)
+ if (capi_send_handler_table[i].cmd == cmd)
+ return capi_send_handler_table[i].handler;
+ return NULL;
+}
+
+
+/**
+ * gigaset_send_message() - accept a CAPI message from an application
+ * @ctr: controller descriptor structure.
+ * @skb: CAPI message.
+ *
+ * Return value: CAPI error code
+ * Note: capidrv (and probably others, too) only uses the return value to
+ * decide whether it has to free the skb (only if result != CAPI_NOERROR (0))
+ */
+static u16 gigaset_send_message(struct capi_ctr *ctr, struct sk_buff *skb)
+{
+ struct gigaset_capi_ctr *iif
+ = container_of(ctr, struct gigaset_capi_ctr, ctr);
+ struct cardstate *cs = ctr->driverdata;
+ struct gigaset_capi_appl *ap;
+ capi_send_handler_t handler;
+
+ /* can only handle linear sk_buffs */
+ if (skb_linearize(skb) < 0) {
+ dev_warn(cs->dev, "%s: skb_linearize failed\n", __func__);
+ return CAPI_MSGOSRESOURCEERR;
+ }
+
+ /* retrieve application data structure */
+ ap = get_appl(iif, CAPIMSG_APPID(skb->data));
+ if (!ap) {
+ dev_notice(cs->dev, "%s: application %u not registered\n",
+ __func__, CAPIMSG_APPID(skb->data));
+ return CAPI_ILLAPPNR;
+ }
+
+ /* look up command */
+ handler = lookup_capi_send_handler(CAPIMSG_CMD(skb->data));
+ if (!handler) {
+ /* unknown/unsupported message type */
+ if (printk_ratelimit())
+ dev_notice(cs->dev, "%s: unsupported message %u\n",
+ __func__, CAPIMSG_CMD(skb->data));
+ return CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
+ }
+
+ /* serialize */
+ if (atomic_add_return(1, &iif->sendqlen) > 1) {
+ /* queue behind other messages */
+ skb_queue_tail(&iif->sendqueue, skb);
+ return CAPI_NOERROR;
+ }
+
+ /* process message */
+ handler(iif, ap, skb);
+
+ /* process other messages arrived in the meantime */
+ while (atomic_sub_return(1, &iif->sendqlen) > 0) {
+ skb = skb_dequeue(&iif->sendqueue);
+ if (!skb) {
+ /* should never happen */
+ dev_err(cs->dev, "%s: send queue empty\n", __func__);
+ continue;
+ }
+ ap = get_appl(iif, CAPIMSG_APPID(skb->data));
+ if (!ap) {
+ /* could that happen? */
+ dev_warn(cs->dev, "%s: application %u vanished\n",
+ __func__, CAPIMSG_APPID(skb->data));
+ continue;
+ }
+ handler = lookup_capi_send_handler(CAPIMSG_CMD(skb->data));
+ if (!handler) {
+ /* should never happen */
+ dev_err(cs->dev, "%s: handler %x vanished\n",
+ __func__, CAPIMSG_CMD(skb->data));
+ continue;
+ }
+ handler(iif, ap, skb);
+ }
+
+ return CAPI_NOERROR;
+}
+
+/**
+ * gigaset_procinfo() - build single line description for controller
+ * @ctr: controller descriptor structure.
+ *
+ * Return value: pointer to generated string (null terminated)
+ */
+static char *gigaset_procinfo(struct capi_ctr *ctr)
+{
+ return ctr->name; /* ToDo: more? */
+}
+
+/**
+ * gigaset_ctr_read_proc() - build controller proc file entry
+ * @page: buffer of PAGE_SIZE bytes for receiving the entry.
+ * @start: unused.
+ * @off: unused.
+ * @count: unused.
+ * @eof: unused.
+ * @ctr: controller descriptor structure.
+ *
+ * Return value: length of generated entry
+ */
+static int gigaset_ctr_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, struct capi_ctr *ctr)
+{
+ struct cardstate *cs = ctr->driverdata;
+ char *s;
+ int i;
+ int len = 0;
+ len += sprintf(page+len, "%-16s %s\n", "name", ctr->name);
+ len += sprintf(page+len, "%-16s %s %s\n", "dev",
+ dev_driver_string(cs->dev), dev_name(cs->dev));
+ len += sprintf(page+len, "%-16s %d\n", "id", cs->myid);
+ if (cs->gotfwver)
+ len += sprintf(page+len, "%-16s %d.%d.%d.%d\n", "firmware",
+ cs->fwver[0], cs->fwver[1], cs->fwver[2], cs->fwver[3]);
+ len += sprintf(page+len, "%-16s %d\n", "channels",
+ cs->channels);
+ len += sprintf(page+len, "%-16s %s\n", "onechannel",
+ cs->onechannel ? "yes" : "no");
+
+ switch (cs->mode) {
+ case M_UNKNOWN:
+ s = "unknown";
+ break;
+ case M_CONFIG:
+ s = "config";
+ break;
+ case M_UNIMODEM:
+ s = "Unimodem";
+ break;
+ case M_CID:
+ s = "CID";
+ break;
+ default:
+ s = "??";
+ }
+ len += sprintf(page+len, "%-16s %s\n", "mode", s);
+
+ switch (cs->mstate) {
+ case MS_UNINITIALIZED:
+ s = "uninitialized";
+ break;
+ case MS_INIT:
+ s = "init";
+ break;
+ case MS_LOCKED:
+ s = "locked";
+ break;
+ case MS_SHUTDOWN:
+ s = "shutdown";
+ break;
+ case MS_RECOVER:
+ s = "recover";
+ break;
+ case MS_READY:
+ s = "ready";
+ break;
+ default:
+ s = "??";
+ }
+ len += sprintf(page+len, "%-16s %s\n", "mstate", s);
+
+ len += sprintf(page+len, "%-16s %s\n", "running",
+ cs->running ? "yes" : "no");
+ len += sprintf(page+len, "%-16s %s\n", "connected",
+ cs->connected ? "yes" : "no");
+ len += sprintf(page+len, "%-16s %s\n", "isdn_up",
+ cs->isdn_up ? "yes" : "no");
+ len += sprintf(page+len, "%-16s %s\n", "cidmode",
+ cs->cidmode ? "yes" : "no");
+
+ for (i = 0; i < cs->channels; i++) {
+ len += sprintf(page+len, "[%d]%-13s %d\n", i, "corrupted",
+ cs->bcs[i].corrupted);
+ len += sprintf(page+len, "[%d]%-13s %d\n", i, "trans_down",
+ cs->bcs[i].trans_down);
+ len += sprintf(page+len, "[%d]%-13s %d\n", i, "trans_up",
+ cs->bcs[i].trans_up);
+ len += sprintf(page+len, "[%d]%-13s %d\n", i, "chstate",
+ cs->bcs[i].chstate);
+ switch (cs->bcs[i].proto2) {
+ case L2_BITSYNC:
+ s = "bitsync";
+ break;
+ case L2_HDLC:
+ s = "HDLC";
+ break;
+ case L2_VOICE:
+ s = "voice";
+ break;
+ default:
+ s = "??";
+ }
+ len += sprintf(page+len, "[%d]%-13s %s\n", i, "proto2", s);
+ }
+ return len;
+}
+
+
+static struct capi_driver capi_driver_gigaset = {
+ .name = "gigaset",
+ .revision = "1.0",
+};
+
+/**
+ * gigaset_isdn_register() - register to LL
+ * @cs: device descriptor structure.
+ * @isdnid: device name.
+ *
+ * Called by main module to register the device with the LL.
+ *
+ * Return value: 1 for success, 0 for failure
+ */
+int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
+{
+ struct gigaset_capi_ctr *iif;
+ int rc;
+
+ pr_info("Kernel CAPI interface\n");
+
+ iif = kmalloc(sizeof(*iif), GFP_KERNEL);
+ if (!iif) {
+ pr_err("%s: out of memory\n", __func__);
+ return 0;
+ }
+
+ /* register driver with CAPI (ToDo: what for?) */
+ register_capi_driver(&capi_driver_gigaset);
+
+ /* prepare controller structure */
+ iif->ctr.owner = THIS_MODULE;
+ iif->ctr.driverdata = cs;
+ strncpy(iif->ctr.name, isdnid, sizeof(iif->ctr.name));
+ iif->ctr.driver_name = "gigaset";
+ iif->ctr.load_firmware = gigaset_load_firmware;
+ iif->ctr.reset_ctr = gigaset_reset_ctr;
+ iif->ctr.register_appl = gigaset_register_appl;
+ iif->ctr.release_appl = gigaset_release_appl;
+ iif->ctr.send_message = gigaset_send_message;
+ iif->ctr.procinfo = gigaset_procinfo;
+ iif->ctr.ctr_read_proc = gigaset_ctr_read_proc;
+ INIT_LIST_HEAD(&iif->appls);
+ skb_queue_head_init(&iif->sendqueue);
+ atomic_set(&iif->sendqlen, 0);
+
+ /* register controller with CAPI */
+ rc = attach_capi_ctr(&iif->ctr);
+ if (rc) {
+ pr_err("attach_capi_ctr failed (%d)\n", rc);
+ unregister_capi_driver(&capi_driver_gigaset);
+ kfree(iif);
+ return 0;
+ }
+
+ cs->iif = iif;
+ cs->hw_hdr_len = CAPI_DATA_B3_REQ_LEN;
+ return 1;
+}
+
+/**
+ * gigaset_isdn_unregister() - unregister from LL
+ * @cs: device descriptor structure.
+ *
+ * Called by main module to unregister the device from the LL.
+ */
+void gigaset_isdn_unregister(struct cardstate *cs)
+{
+ struct gigaset_capi_ctr *iif = cs->iif;
+
+ detach_capi_ctr(&iif->ctr);
+ kfree(iif);
+ cs->iif = NULL;
+ unregister_capi_driver(&capi_driver_gigaset);
+}
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
index 33dcd8d72b7c..1d2ae2e05e0b 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -207,6 +207,32 @@ int gigaset_get_channel(struct bc_state *bcs)
return 1;
}
+struct bc_state *gigaset_get_free_channel(struct cardstate *cs)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&cs->lock, flags);
+ if (!try_module_get(cs->driver->owner)) {
+ gig_dbg(DEBUG_ANY,
+ "could not get module for allocating channel");
+ spin_unlock_irqrestore(&cs->lock, flags);
+ return NULL;
+ }
+ for (i = 0; i < cs->channels; ++i)
+ if (!cs->bcs[i].use_count) {
+ ++cs->bcs[i].use_count;
+ cs->bcs[i].busy = 1;
+ spin_unlock_irqrestore(&cs->lock, flags);
+ gig_dbg(DEBUG_ANY, "allocated channel %d", i);
+ return cs->bcs + i;
+ }
+ module_put(cs->driver->owner);
+ spin_unlock_irqrestore(&cs->lock, flags);
+ gig_dbg(DEBUG_ANY, "no free channel");
+ return NULL;
+}
+
void gigaset_free_channel(struct bc_state *bcs)
{
unsigned long flags;
@@ -463,6 +489,12 @@ void gigaset_freecs(struct cardstate *cs)
switch (cs->cs_init) {
default:
+ /* clear B channel structures */
+ for (i = 0; i < cs->channels; ++i) {
+ gig_dbg(DEBUG_INIT, "clearing bcs[%d]", i);
+ gigaset_freebcs(cs->bcs + i);
+ }
+
/* clear device sysfs */
gigaset_free_dev_sysfs(cs);
@@ -477,22 +509,16 @@ void gigaset_freecs(struct cardstate *cs)
case 2: /* error in initcshw */
/* Deregister from LL */
make_invalid(cs, VALID_ID);
- gig_dbg(DEBUG_INIT, "clearing iif");
- gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD);
+ gigaset_isdn_unregister(cs);
/* fall through */
- case 1: /* error when regestering to LL */
+ case 1: /* error when registering to LL */
gig_dbg(DEBUG_INIT, "clearing at_state");
clear_at_state(&cs->at_state);
dealloc_at_states(cs);
/* fall through */
- case 0: /* error in one call to initbcs */
- for (i = 0; i < cs->channels; ++i) {
- gig_dbg(DEBUG_INIT, "clearing bcs[%d]", i);
- gigaset_freebcs(cs->bcs + i);
- }
-
+ case 0: /* error in basic setup */
clear_events(cs);
gig_dbg(DEBUG_INIT, "freeing inbuf");
kfree(cs->inbuf);
@@ -620,11 +646,14 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs,
if (cs->ignoreframes) {
bcs->inputstate |= INS_skip_frame;
bcs->skb = NULL;
- } else if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
- skb_reserve(bcs->skb, HW_HDR_LEN);
- else {
- pr_err("out of memory\n");
- bcs->inputstate |= INS_skip_frame;
+ } else {
+ bcs->skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len);
+ if (bcs->skb != NULL)
+ skb_reserve(bcs->skb, cs->hw_hdr_len);
+ else {
+ pr_err("out of memory\n");
+ bcs->inputstate |= INS_skip_frame;
+ }
}
bcs->channel = channel;
@@ -726,14 +755,6 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
cs->mode = M_UNKNOWN;
cs->mstate = MS_UNINITIALIZED;
- for (i = 0; i < channels; ++i) {
- gig_dbg(DEBUG_INIT, "setting up bcs[%d].read", i);
- if (!gigaset_initbcs(cs->bcs + i, cs, i)) {
- pr_err("could not allocate channel %d data\n", i);
- goto error;
- }
- }
-
++cs->cs_init;
gig_dbg(DEBUG_INIT, "setting up at_state");
@@ -758,7 +779,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
cs->cmdbytes = 0;
gig_dbg(DEBUG_INIT, "setting up iif");
- if (!gigaset_register_to_LL(cs, modulename)) {
+ if (!gigaset_isdn_register(cs, modulename)) {
pr_err("error registering ISDN device\n");
goto error;
}
@@ -777,6 +798,15 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
/* set up device sysfs */
gigaset_init_dev_sysfs(cs);
+ /* set up channel data structures */
+ for (i = 0; i < channels; ++i) {
+ gig_dbg(DEBUG_INIT, "setting up bcs[%d]", i);
+ if (!gigaset_initbcs(cs->bcs + i, cs, i)) {
+ pr_err("could not allocate channel %d data\n", i);
+ goto error;
+ }
+ }
+
spin_lock_irqsave(&cs->lock, flags);
cs->running = 1;
spin_unlock_irqrestore(&cs->lock, flags);
diff --git a/drivers/isdn/gigaset/dummyll.c b/drivers/isdn/gigaset/dummyll.c
new file mode 100644
index 000000000000..5b27c996af6d
--- /dev/null
+++ b/drivers/isdn/gigaset/dummyll.c
@@ -0,0 +1,68 @@
+/*
+ * Dummy LL interface for the Gigaset driver
+ *
+ * Copyright (c) 2009 by Tilman Schmidt <tilman@imap.cc>.
+ *
+ * =====================================================================
+ * This 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 "gigaset.h"
+
+void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
+{
+}
+EXPORT_SYMBOL_GPL(gigaset_skb_sent);
+
+void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb)
+{
+}
+EXPORT_SYMBOL_GPL(gigaset_skb_rcvd);
+
+void gigaset_isdn_rcv_err(struct bc_state *bcs)
+{
+}
+EXPORT_SYMBOL_GPL(gigaset_isdn_rcv_err);
+
+int gigaset_isdn_icall(struct at_state_t *at_state)
+{
+ return ICALL_IGNORE;
+}
+
+void gigaset_isdn_connD(struct bc_state *bcs)
+{
+}
+
+void gigaset_isdn_hupD(struct bc_state *bcs)
+{
+}
+
+void gigaset_isdn_connB(struct bc_state *bcs)
+{
+}
+
+void gigaset_isdn_hupB(struct bc_state *bcs)
+{
+}
+
+void gigaset_isdn_start(struct cardstate *cs)
+{
+}
+
+void gigaset_isdn_stop(struct cardstate *cs)
+{
+}
+
+int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
+{
+ pr_info("no ISDN subsystem interface\n");
+ return 1;
+}
+
+void gigaset_isdn_unregister(struct cardstate *cs)
+{
+}
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
index cc768caa38f5..369927f90729 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -127,7 +127,6 @@
#define ACT_NOTIFY_BC_UP 39
#define ACT_DIAL 40
#define ACT_ACCEPT 41
-#define ACT_PROTO_L2 42
#define ACT_HUP 43
#define ACT_IF_LOCK 44
#define ACT_START 45
@@ -292,21 +291,23 @@ struct reply_t gigaset_tab_cid[] =
{RSP_OK, 602,602, -1, 603, 5, {ACT_CMD+AT_PROTO}},
{RSP_OK, 603,603, -1, 604, 5, {ACT_CMD+AT_TYPE}},
{RSP_OK, 604,604, -1, 605, 5, {ACT_CMD+AT_MSN}},
- {RSP_OK, 605,605, -1, 606, 5, {ACT_CMD+AT_ISO}},
- {RSP_NULL, 605,605, -1, 606, 5, {ACT_CMD+AT_ISO}},
- {RSP_OK, 606,606, -1, 607, 5, {0}, "+VLS=17\r"},
- {RSP_OK, 607,607, -1, 608,-1},
- {RSP_ZSAU, 608,608,ZSAU_PROCEEDING, 609, 5, {ACT_CMD+AT_DIAL}},
- {RSP_OK, 609,609, -1, 650, 0, {ACT_DIALING}},
-
- {RSP_ERROR, 601,609, -1, 0, 0, {ACT_ABORTDIAL}},
- {EV_TIMEOUT, 601,609, -1, 0, 0, {ACT_ABORTDIAL}},
+ {RSP_NULL, 605, 605, -1, 606, 5, {ACT_CMD+AT_CLIP} },
+ {RSP_OK, 605, 605, -1, 606, 5, {ACT_CMD+AT_CLIP} },
+ {RSP_NULL, 606, 606, -1, 607, 5, {ACT_CMD+AT_ISO} },
+ {RSP_OK, 606, 606, -1, 607, 5, {ACT_CMD+AT_ISO} },
+ {RSP_OK, 607, 607, -1, 608, 5, {0}, "+VLS=17\r"},
+ {RSP_OK, 608, 608, -1, 609, -1},
+ {RSP_ZSAU, 609, 609, ZSAU_PROCEEDING, 610, 5, {ACT_CMD+AT_DIAL} },
+ {RSP_OK, 610, 610, -1, 650, 0, {ACT_DIALING} },
+
+ {RSP_ERROR, 601, 610, -1, 0, 0, {ACT_ABORTDIAL} },
+ {EV_TIMEOUT, 601, 610, -1, 0, 0, {ACT_ABORTDIAL} },
/* optional dialing responses */
{EV_BC_OPEN, 650,650, -1, 651,-1},
- {RSP_ZVLS, 608,651, 17, -1,-1, {ACT_DEBUG}},
- {RSP_ZCTP, 609,651, -1, -1,-1, {ACT_DEBUG}},
- {RSP_ZCPN, 609,651, -1, -1,-1, {ACT_DEBUG}},
+ {RSP_ZVLS, 609, 651, 17, -1, -1, {ACT_DEBUG} },
+ {RSP_ZCTP, 610, 651, -1, -1, -1, {ACT_DEBUG} },
+ {RSP_ZCPN, 610, 651, -1, -1, -1, {ACT_DEBUG} },
{RSP_ZSAU, 650,651,ZSAU_CALL_DELIVERED, -1,-1, {ACT_DEBUG}},
/* connect */
@@ -365,8 +366,6 @@ struct reply_t gigaset_tab_cid[] =
{EV_BC_CLOSED, -1, -1, -1, -1,-1, {ACT_NOTIFY_BC_DOWN}}, //FIXME
/* misc. */
- {EV_PROTO_L2, -1, -1, -1, -1,-1, {ACT_PROTO_L2}}, //FIXME
-
{RSP_ZCON, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME
{RSP_ZCCR, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME
{RSP_ZAOC, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME
@@ -714,7 +713,7 @@ static void disconnect(struct at_state_t **at_state_p)
/* notify LL */
if (bcs->chstate & (CHS_D_UP | CHS_NOTIFY_LL)) {
bcs->chstate &= ~(CHS_D_UP | CHS_NOTIFY_LL);
- gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DHUP);
+ gigaset_isdn_hupD(bcs);
}
} else {
/* no B channel assigned: just deallocate */
@@ -872,12 +871,12 @@ static void bchannel_down(struct bc_state *bcs)
{
if (bcs->chstate & CHS_B_UP) {
bcs->chstate &= ~CHS_B_UP;
- gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BHUP);
+ gigaset_isdn_hupB(bcs);
}
if (bcs->chstate & (CHS_D_UP | CHS_NOTIFY_LL)) {
bcs->chstate &= ~(CHS_D_UP | CHS_NOTIFY_LL);
- gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DHUP);
+ gigaset_isdn_hupD(bcs);
}
gigaset_free_channel(bcs);
@@ -894,15 +893,16 @@ static void bchannel_up(struct bc_state *bcs)
}
bcs->chstate |= CHS_B_UP;
- gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN);
+ gigaset_isdn_connB(bcs);
}
static void start_dial(struct at_state_t *at_state, void *data, unsigned seq_index)
{
struct bc_state *bcs = at_state->bcs;
struct cardstate *cs = at_state->cs;
- int retval;
+ char **commands = data;
unsigned long flags;
+ int i;
bcs->chstate |= CHS_NOTIFY_LL;
@@ -913,10 +913,10 @@ static void start_dial(struct at_state_t *at_state, void *data, unsigned seq_ind
}
spin_unlock_irqrestore(&cs->lock, flags);
- retval = gigaset_isdn_setup_dial(at_state, data);
- if (retval != 0)
- goto error;
-
+ for (i = 0; i < AT_NUM; ++i) {
+ kfree(bcs->commands[i]);
+ bcs->commands[i] = commands[i];
+ }
at_state->pending_commands |= PC_CID;
gig_dbg(DEBUG_CMD, "Scheduling PC_CID");
@@ -924,6 +924,10 @@ static void start_dial(struct at_state_t *at_state, void *data, unsigned seq_ind
return;
error:
+ for (i = 0; i < AT_NUM; ++i) {
+ kfree(commands[i]);
+ commands[i] = NULL;
+ }
at_state->pending_commands |= PC_NOCID;
gig_dbg(DEBUG_CMD, "Scheduling PC_NOCID");
cs->commands_pending = 1;
@@ -933,20 +937,31 @@ error:
static void start_accept(struct at_state_t *at_state)
{
struct cardstate *cs = at_state->cs;
- int retval;
+ struct bc_state *bcs = at_state->bcs;
+ int i;
- retval = gigaset_isdn_setup_accept(at_state);
+ for (i = 0; i < AT_NUM; ++i) {
+ kfree(bcs->commands[i]);
+ bcs->commands[i] = NULL;
+ }
- if (retval == 0) {
- at_state->pending_commands |= PC_ACCEPT;
- gig_dbg(DEBUG_CMD, "Scheduling PC_ACCEPT");
- cs->commands_pending = 1;
- } else {
+ bcs->commands[AT_PROTO] = kmalloc(9, GFP_ATOMIC);
+ bcs->commands[AT_ISO] = kmalloc(9, GFP_ATOMIC);
+ if (!bcs->commands[AT_PROTO] || !bcs->commands[AT_ISO]) {
+ dev_err(at_state->cs->dev, "out of memory\n");
/* error reset */
at_state->pending_commands |= PC_HUP;
gig_dbg(DEBUG_CMD, "Scheduling PC_HUP");
cs->commands_pending = 1;
+ return;
}
+
+ snprintf(bcs->commands[AT_PROTO], 9, "^SBPR=%u\r", bcs->proto2);
+ snprintf(bcs->commands[AT_ISO], 9, "^SISO=%u\r", bcs->channel + 1);
+
+ at_state->pending_commands |= PC_ACCEPT;
+ gig_dbg(DEBUG_CMD, "Scheduling PC_ACCEPT");
+ cs->commands_pending = 1;
}
static void do_start(struct cardstate *cs)
@@ -957,7 +972,7 @@ static void do_start(struct cardstate *cs)
schedule_init(cs, MS_INIT);
cs->isdn_up = 1;
- gigaset_i4l_cmd(cs, ISDN_STAT_RUN);
+ gigaset_isdn_start(cs);
// FIXME: not in locked mode
// FIXME 2: only after init sequence
@@ -975,7 +990,7 @@ static void finish_shutdown(struct cardstate *cs)
/* Tell the LL that the device is not available .. */
if (cs->isdn_up) {
cs->isdn_up = 0;
- gigaset_i4l_cmd(cs, ISDN_STAT_STOP);
+ gigaset_isdn_stop(cs);
}
/* The rest is done by cleanup_cs () in user mode. */
@@ -1276,7 +1291,7 @@ static void do_action(int action, struct cardstate *cs,
break;
}
bcs->chstate |= CHS_D_UP;
- gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN);
+ gigaset_isdn_connD(bcs);
cs->ops->init_bchannel(bcs);
break;
case ACT_DLE1:
@@ -1284,7 +1299,7 @@ static void do_action(int action, struct cardstate *cs,
bcs = cs->bcs + cs->curchannel;
bcs->chstate |= CHS_D_UP;
- gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN);
+ gigaset_isdn_connD(bcs);
cs->ops->init_bchannel(bcs);
break;
case ACT_FAKEHUP:
@@ -1474,11 +1489,6 @@ static void do_action(int action, struct cardstate *cs,
case ACT_ACCEPT:
start_accept(at_state);
break;
- case ACT_PROTO_L2:
- gig_dbg(DEBUG_CMD, "set protocol to %u",
- (unsigned) ev->parameter);
- at_state->bcs->proto2 = ev->parameter;
- break;
case ACT_HUP:
at_state->pending_commands |= PC_HUP;
cs->commands_pending = 1;
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
index a2f6125739eb..4749ef100fd3 100644
--- a/drivers/isdn/gigaset/gigaset.h
+++ b/drivers/isdn/gigaset/gigaset.h
@@ -23,7 +23,6 @@
#include <linux/compiler.h>
#include <linux/types.h>
#include <linux/spinlock.h>
-#include <linux/isdnif.h>
#include <linux/usb.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
@@ -40,7 +39,6 @@
#define MAX_REC_PARAMS 10 /* Max. number of params in response string */
#define MAX_RESP_SIZE 512 /* Max. size of a response string */
-#define HW_HDR_LEN 2 /* Header size used to store ack info */
#define MAX_EVENTS 64 /* size of event queue */
@@ -193,7 +191,9 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
#define AT_PROTO 4
#define AT_TYPE 5
#define AT_HLC 6
-#define AT_NUM 7
+#define AT_CLIP 7
+/* total number */
+#define AT_NUM 8
/* variables in struct at_state_t */
#define VAR_ZSAU 0
@@ -216,7 +216,6 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
#define EV_START -110
#define EV_STOP -111
#define EV_IF_LOCK -112
-#define EV_PROTO_L2 -113
#define EV_ACCEPT -114
#define EV_DIAL -115
#define EV_HUP -116
@@ -259,6 +258,11 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
#define SM_LOCKED 0
#define SM_ISDN 1 /* default */
+/* layer 2 protocols (AT^SBPR=...) */
+#define L2_BITSYNC 0
+#define L2_HDLC 1
+#define L2_VOICE 2
+
struct gigaset_ops;
struct gigaset_driver;
@@ -395,7 +399,7 @@ struct bc_state {
unsigned chstate; /* bitmap (CHS_*) */
int ignore;
- unsigned proto2; /* Layer 2 protocol (ISDN_PROTO_L2_*) */
+ unsigned proto2; /* layer 2 protocol (L2_*) */
char *commands[AT_NUM]; /* see AT_XXXX */
#ifdef CONFIG_GIGASET_DEBUG
@@ -410,6 +414,8 @@ struct bc_state {
struct usb_bc_state *usb; /* usb hardware driver (m105) */
struct bas_bc_state *bas; /* usb hardware driver (base) */
} hw;
+
+ void *ap; /* LL application structure */
};
struct cardstate {
@@ -456,12 +462,13 @@ struct cardstate {
unsigned running; /* !=0 if events are handled */
unsigned connected; /* !=0 if hardware is connected */
- unsigned isdn_up; /* !=0 after ISDN_STAT_RUN */
+ unsigned isdn_up; /* !=0 after gigaset_isdn_start() */
unsigned cidmode;
int myid; /* id for communication with LL */
- isdn_if iif;
+ void *iif; /* LL interface structure */
+ unsigned short hw_hdr_len; /* headroom needed in data skbs */
struct reply_t *tabnocid;
struct reply_t *tabcid;
@@ -616,7 +623,9 @@ struct gigaset_ops {
int (*baud_rate)(struct cardstate *cs, unsigned cflag);
int (*set_line_ctrl)(struct cardstate *cs, unsigned cflag);
- /* Called from i4l.c to put an skb into the send-queue. */
+ /* Called from LL interface to put an skb into the send-queue.
+ * After sending is completed, gigaset_skb_sent() must be called
+ * with the first cs->hw_hdr_len bytes of skb->head preserved. */
int (*send_skb)(struct bc_state *bcs, struct sk_buff *skb);
/* Called from ev-layer.c to process a block of data
@@ -638,8 +647,7 @@ struct gigaset_ops {
* Functions implemented in asyncdata.c
*/
-/* Called from i4l.c to put an skb into the send-queue.
- * After sending gigaset_skb_sent() should be called. */
+/* Called from LL interface to put an skb into the send queue. */
int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb);
/* Called from ev-layer.c to process a block of data
@@ -650,8 +658,7 @@ void gigaset_m10x_input(struct inbuf_t *inbuf);
* Functions implemented in isocdata.c
*/
-/* Called from i4l.c to put an skb into the send-queue.
- * After sending gigaset_skb_sent() should be called. */
+/* Called from LL interface to put an skb into the send queue. */
int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb);
/* Called from ev-layer.c to process a block of data
@@ -674,36 +681,26 @@ void gigaset_isowbuf_init(struct isowbuf_t *iwb, unsigned char idle);
int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size);
/* ===========================================================================
- * Functions implemented in i4l.c/gigaset.h
+ * Functions implemented in LL interface
*/
-/* Called by gigaset_initcs() for setting up with the isdn4linux subsystem */
-int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid);
+/* Called from common.c for setting up/shutting down with the ISDN subsystem */
+int gigaset_isdn_register(struct cardstate *cs, const char *isdnid);
+void gigaset_isdn_unregister(struct cardstate *cs);
-/* Called from xxx-gigaset.c to indicate completion of sending an skb */
+/* Called from hardware module to indicate completion of an skb */
void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb);
+void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb);
+void gigaset_isdn_rcv_err(struct bc_state *bcs);
/* Called from common.c/ev-layer.c to indicate events relevant to the LL */
+void gigaset_isdn_start(struct cardstate *cs);
+void gigaset_isdn_stop(struct cardstate *cs);
int gigaset_isdn_icall(struct at_state_t *at_state);
-int gigaset_isdn_setup_accept(struct at_state_t *at_state);
-int gigaset_isdn_setup_dial(struct at_state_t *at_state, void *data);
-
-void gigaset_i4l_cmd(struct cardstate *cs, int cmd);
-void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd);
-
-
-static inline void gigaset_isdn_rcv_err(struct bc_state *bcs)
-{
- isdn_ctrl response;
-
- /* error -> LL */
- gig_dbg(DEBUG_CMD, "sending L1ERR");
- response.driver = bcs->cs->myid;
- response.command = ISDN_STAT_L1ERR;
- response.arg = bcs->channel;
- response.parm.errcode = ISDN_STAT_L1ERR_RECV;
- bcs->cs->iif.statcallb(&response);
-}
+void gigaset_isdn_connD(struct bc_state *bcs);
+void gigaset_isdn_hupD(struct bc_state *bcs);
+void gigaset_isdn_connB(struct bc_state *bcs);
+void gigaset_isdn_hupB(struct bc_state *bcs);
/* ===========================================================================
* Functions implemented in ev-layer.c
@@ -732,6 +729,7 @@ void gigaset_bcs_reinit(struct bc_state *bcs);
void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs,
struct cardstate *cs, int cid);
int gigaset_get_channel(struct bc_state *bcs);
+struct bc_state *gigaset_get_free_channel(struct cardstate *cs);
void gigaset_free_channel(struct bc_state *bcs);
int gigaset_get_channels(struct cardstate *cs);
void gigaset_free_channels(struct cardstate *cs);
@@ -816,35 +814,6 @@ static inline void gigaset_bchannel_up(struct bc_state *bcs)
/* handling routines for sk_buff */
/* ============================= */
-/* pass received skb to LL
- * Warning: skb must not be accessed anymore!
- */
-static inline void gigaset_rcv_skb(struct sk_buff *skb,
- struct cardstate *cs,
- struct bc_state *bcs)
-{
- cs->iif.rcvcallb_skb(cs->myid, bcs->channel, skb);
- bcs->trans_down++;
-}
-
-/* handle reception of corrupted skb
- * Warning: skb must not be accessed anymore!
- */
-static inline void gigaset_rcv_error(struct sk_buff *procskb,
- struct cardstate *cs,
- struct bc_state *bcs)
-{
- if (procskb)
- dev_kfree_skb(procskb);
-
- if (bcs->ignore)
- --bcs->ignore;
- else {
- ++bcs->corrupted;
- gigaset_isdn_rcv_err(bcs);
- }
-}
-
/* append received bytes to inbuf */
int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src,
unsigned numbytes);
diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c
index 654489d836cd..aca72a06184e 100644
--- a/drivers/isdn/gigaset/i4l.c
+++ b/drivers/isdn/gigaset/i4l.c
@@ -14,6 +14,9 @@
*/
#include "gigaset.h"
+#include <linux/isdnif.h>
+
+#define HW_HDR_LEN 2 /* Header size used to store ack info */
/* == Handling of I4L IO =====================================================*/
@@ -95,6 +98,7 @@ static int writebuf_from_LL(int driverID, int channel, int ack,
*/
void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
{
+ isdn_if *iif = bcs->cs->iif;
unsigned len;
isdn_ctrl response;
@@ -114,71 +118,177 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
response.command = ISDN_STAT_BSENT;
response.arg = bcs->channel;
response.parm.length = len;
- bcs->cs->iif.statcallb(&response);
+ iif->statcallb(&response);
}
}
EXPORT_SYMBOL_GPL(gigaset_skb_sent);
+/**
+ * gigaset_skb_rcvd() - pass received skb to LL
+ * @bcs: B channel descriptor structure.
+ * @skb: received data.
+ *
+ * Called by hardware module {bas,ser,usb}_gigaset when user data has
+ * been successfully received, for passing to the LL.
+ * Warning: skb must not be accessed anymore!
+ */
+void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb)
+{
+ isdn_if *iif = bcs->cs->iif;
+
+ iif->rcvcallb_skb(bcs->cs->myid, bcs->channel, skb);
+ bcs->trans_down++;
+}
+EXPORT_SYMBOL_GPL(gigaset_skb_rcvd);
+
+/**
+ * gigaset_isdn_rcv_err() - signal receive error
+ * @bcs: B channel descriptor structure.
+ *
+ * Called by hardware module {bas,ser,usb}_gigaset when a receive error
+ * has occurred, for signalling to the LL.
+ */
+void gigaset_isdn_rcv_err(struct bc_state *bcs)
+{
+ isdn_if *iif = bcs->cs->iif;
+ isdn_ctrl response;
+
+ /* if currently ignoring packets, just count down */
+ if (bcs->ignore) {
+ bcs->ignore--;
+ return;
+ }
+
+ /* update statistics */
+ bcs->corrupted++;
+
+ /* error -> LL */
+ gig_dbg(DEBUG_CMD, "sending L1ERR");
+ response.driver = bcs->cs->myid;
+ response.command = ISDN_STAT_L1ERR;
+ response.arg = bcs->channel;
+ response.parm.errcode = ISDN_STAT_L1ERR_RECV;
+ iif->statcallb(&response);
+}
+EXPORT_SYMBOL_GPL(gigaset_isdn_rcv_err);
+
/* This function will be called by LL to send commands
* NOTE: LL ignores the returned value, for commands other than ISDN_CMD_IOCTL,
* so don't put too much effort into it.
*/
static int command_from_LL(isdn_ctrl *cntrl)
{
- struct cardstate *cs = gigaset_get_cs_by_id(cntrl->driver);
+ struct cardstate *cs;
struct bc_state *bcs;
int retval = 0;
- struct setup_parm *sp;
+ char **commands;
+ int ch;
+ int i;
+ size_t l;
gigaset_debugdrivers();
- if (!cs) {
+ gig_dbg(DEBUG_CMD, "driver: %d, command: %d, arg: 0x%lx",
+ cntrl->driver, cntrl->command, cntrl->arg);
+
+ cs = gigaset_get_cs_by_id(cntrl->driver);
+ if (cs == NULL) {
pr_err("%s: invalid driver ID (%d)\n", __func__, cntrl->driver);
return -ENODEV;
}
+ ch = cntrl->arg & 0xff;
switch (cntrl->command) {
case ISDN_CMD_IOCTL:
- gig_dbg(DEBUG_ANY, "ISDN_CMD_IOCTL (driver: %d, arg: %ld)",
- cntrl->driver, cntrl->arg);
-
dev_warn(cs->dev, "ISDN_CMD_IOCTL not supported\n");
return -EINVAL;
case ISDN_CMD_DIAL:
gig_dbg(DEBUG_ANY,
- "ISDN_CMD_DIAL (driver: %d, ch: %ld, "
- "phone: %s, ownmsn: %s, si1: %d, si2: %d)",
- cntrl->driver, cntrl->arg,
+ "ISDN_CMD_DIAL (phone: %s, msn: %s, si1: %d, si2: %d)",
cntrl->parm.setup.phone, cntrl->parm.setup.eazmsn,
cntrl->parm.setup.si1, cntrl->parm.setup.si2);
- if (cntrl->arg >= cs->channels) {
+ if (ch >= cs->channels) {
dev_err(cs->dev,
- "ISDN_CMD_DIAL: invalid channel (%d)\n",
- (int) cntrl->arg);
+ "ISDN_CMD_DIAL: invalid channel (%d)\n", ch);
return -EINVAL;
}
-
- bcs = cs->bcs + cntrl->arg;
-
+ bcs = cs->bcs + ch;
if (!gigaset_get_channel(bcs)) {
dev_err(cs->dev, "ISDN_CMD_DIAL: channel not free\n");
return -EBUSY;
}
- sp = kmalloc(sizeof *sp, GFP_ATOMIC);
- if (!sp) {
+ commands = kzalloc(AT_NUM*(sizeof *commands), GFP_ATOMIC);
+ if (!commands) {
gigaset_free_channel(bcs);
dev_err(cs->dev, "ISDN_CMD_DIAL: out of memory\n");
return -ENOMEM;
}
- *sp = cntrl->parm.setup;
- if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp,
+ l = 3 + strlen(cntrl->parm.setup.phone);
+ commands[AT_DIAL] = kmalloc(l, GFP_ATOMIC);
+ if (!commands[AT_DIAL])
+ goto oom;
+ if (cntrl->parm.setup.phone[0] == '*' &&
+ cntrl->parm.setup.phone[1] == '*') {
+ /* internal call: translate ** prefix to CTP value */
+ commands[AT_TYPE] = kstrdup("^SCTP=0\r", GFP_ATOMIC);
+ if (!commands[AT_TYPE])
+ goto oom;
+ snprintf(commands[AT_DIAL], l,
+ "D%s\r", cntrl->parm.setup.phone+2);
+ } else {
+ commands[AT_TYPE] = kstrdup("^SCTP=1\r", GFP_ATOMIC);
+ if (!commands[AT_TYPE])
+ goto oom;
+ snprintf(commands[AT_DIAL], l,
+ "D%s\r", cntrl->parm.setup.phone);
+ }
+
+ l = strlen(cntrl->parm.setup.eazmsn);
+ if (l) {
+ l += 8;
+ commands[AT_MSN] = kmalloc(l, GFP_ATOMIC);
+ if (!commands[AT_MSN])
+ goto oom;
+ snprintf(commands[AT_MSN], l, "^SMSN=%s\r",
+ cntrl->parm.setup.eazmsn);
+ }
+
+ switch (cntrl->parm.setup.si1) {
+ case 1: /* audio */
+ /* BC = 9090A3: 3.1 kHz audio, A-law */
+ commands[AT_BC] = kstrdup("^SBC=9090A3\r", GFP_ATOMIC);
+ if (!commands[AT_BC])
+ goto oom;
+ break;
+ case 7: /* data */
+ default: /* hope the app knows what it is doing */
+ /* BC = 8890: unrestricted digital information */
+ commands[AT_BC] = kstrdup("^SBC=8890\r", GFP_ATOMIC);
+ if (!commands[AT_BC])
+ goto oom;
+ }
+ /* ToDo: other si1 values, inspect si2, set HLC/LLC */
+
+ commands[AT_PROTO] = kmalloc(9, GFP_ATOMIC);
+ if (!commands[AT_PROTO])
+ goto oom;
+ snprintf(commands[AT_PROTO], 9, "^SBPR=%u\r", bcs->proto2);
+
+ commands[AT_ISO] = kmalloc(9, GFP_ATOMIC);
+ if (!commands[AT_ISO])
+ goto oom;
+ snprintf(commands[AT_ISO], 9, "^SISO=%u\r",
+ (unsigned) bcs->channel + 1);
+
+ if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, commands,
bcs->at_state.seq_index, NULL)) {
- //FIXME what should we do?
- kfree(sp);
+ for (i = 0; i < AT_NUM; ++i)
+ kfree(commands[i]);
+ kfree(commands);
gigaset_free_channel(bcs);
return -ENOMEM;
}
@@ -186,93 +296,83 @@ static int command_from_LL(isdn_ctrl *cntrl)
gig_dbg(DEBUG_CMD, "scheduling DIAL");
gigaset_schedule_event(cs);
break;
- case ISDN_CMD_ACCEPTD: //FIXME
- gig_dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTD");
-
- if (cntrl->arg >= cs->channels) {
+ case ISDN_CMD_ACCEPTD:
+ if (ch >= cs->channels) {
dev_err(cs->dev,
- "ISDN_CMD_ACCEPTD: invalid channel (%d)\n",
- (int) cntrl->arg);
+ "ISDN_CMD_ACCEPTD: invalid channel (%d)\n", ch);
return -EINVAL;
}
-
- if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg].at_state,
- EV_ACCEPT, NULL, 0, NULL)) {
- //FIXME what should we do?
+ bcs = cs->bcs + ch;
+ if (!gigaset_add_event(cs, &bcs->at_state,
+ EV_ACCEPT, NULL, 0, NULL))
return -ENOMEM;
- }
gig_dbg(DEBUG_CMD, "scheduling ACCEPT");
gigaset_schedule_event(cs);
break;
case ISDN_CMD_ACCEPTB:
- gig_dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTB");
break;
case ISDN_CMD_HANGUP:
- gig_dbg(DEBUG_ANY, "ISDN_CMD_HANGUP (ch: %d)",
- (int) cntrl->arg);
-
- if (cntrl->arg >= cs->channels) {
+ if (ch >= cs->channels) {
dev_err(cs->dev,
- "ISDN_CMD_HANGUP: invalid channel (%d)\n",
- (int) cntrl->arg);
+ "ISDN_CMD_HANGUP: invalid channel (%d)\n", ch);
return -EINVAL;
}
-
- if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg].at_state,
- EV_HUP, NULL, 0, NULL)) {
- //FIXME what should we do?
+ bcs = cs->bcs + ch;
+ if (!gigaset_add_event(cs, &bcs->at_state,
+ EV_HUP, NULL, 0, NULL))
return -ENOMEM;
- }
gig_dbg(DEBUG_CMD, "scheduling HUP");
gigaset_schedule_event(cs);
break;
- case ISDN_CMD_CLREAZ: /* Do not signal incoming signals */ //FIXME
- gig_dbg(DEBUG_ANY, "ISDN_CMD_CLREAZ");
+ case ISDN_CMD_CLREAZ: /* Do not signal incoming signals */
+ dev_info(cs->dev, "ignoring ISDN_CMD_CLREAZ\n");
break;
- case ISDN_CMD_SETEAZ: /* Signal incoming calls for given MSN */ //FIXME
- gig_dbg(DEBUG_ANY,
- "ISDN_CMD_SETEAZ (id: %d, ch: %ld, number: %s)",
- cntrl->driver, cntrl->arg, cntrl->parm.num);
+ case ISDN_CMD_SETEAZ: /* Signal incoming calls for given MSN */
+ dev_info(cs->dev, "ignoring ISDN_CMD_SETEAZ (%s)\n",
+ cntrl->parm.num);
break;
case ISDN_CMD_SETL2: /* Set L2 to given protocol */
- gig_dbg(DEBUG_ANY, "ISDN_CMD_SETL2 (ch: %ld, proto: %lx)",
- cntrl->arg & 0xff, (cntrl->arg >> 8));
-
- if ((cntrl->arg & 0xff) >= cs->channels) {
+ if (ch >= cs->channels) {
dev_err(cs->dev,
- "ISDN_CMD_SETL2: invalid channel (%d)\n",
- (int) cntrl->arg & 0xff);
+ "ISDN_CMD_SETL2: invalid channel (%d)\n", ch);
return -EINVAL;
}
-
- if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg & 0xff].at_state,
- EV_PROTO_L2, NULL, cntrl->arg >> 8,
- NULL)) {
- //FIXME what should we do?
- return -ENOMEM;
+ bcs = cs->bcs + ch;
+ if (bcs->chstate & CHS_D_UP) {
+ dev_err(cs->dev,
+ "ISDN_CMD_SETL2: channel active (%d)\n", ch);
+ return -EINVAL;
+ }
+ switch (cntrl->arg >> 8) {
+ case ISDN_PROTO_L2_HDLC:
+ gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL2: setting L2_HDLC");
+ bcs->proto2 = L2_HDLC;
+ break;
+ case ISDN_PROTO_L2_TRANS:
+ gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL2: setting L2_VOICE");
+ bcs->proto2 = L2_VOICE;
+ break;
+ default:
+ dev_err(cs->dev,
+ "ISDN_CMD_SETL2: unsupported protocol (%lu)\n",
+ cntrl->arg >> 8);
+ return -EINVAL;
}
-
- gig_dbg(DEBUG_CMD, "scheduling PROTO_L2");
- gigaset_schedule_event(cs);
break;
case ISDN_CMD_SETL3: /* Set L3 to given protocol */
- gig_dbg(DEBUG_ANY, "ISDN_CMD_SETL3 (ch: %ld, proto: %lx)",
- cntrl->arg & 0xff, (cntrl->arg >> 8));
-
- if ((cntrl->arg & 0xff) >= cs->channels) {
+ if (ch >= cs->channels) {
dev_err(cs->dev,
- "ISDN_CMD_SETL3: invalid channel (%d)\n",
- (int) cntrl->arg & 0xff);
+ "ISDN_CMD_SETL3: invalid channel (%d)\n", ch);
return -EINVAL;
}
if (cntrl->arg >> 8 != ISDN_PROTO_L3_TRANS) {
dev_err(cs->dev,
- "ISDN_CMD_SETL3: invalid protocol %lu\n",
+ "ISDN_CMD_SETL3: unsupported protocol (%lu)\n",
cntrl->arg >> 8);
return -EINVAL;
}
@@ -324,149 +424,34 @@ static int command_from_LL(isdn_ctrl *cntrl)
}
return retval;
+
+oom:
+ dev_err(bcs->cs->dev, "out of memory\n");
+ for (i = 0; i < AT_NUM; ++i)
+ kfree(commands[i]);
+ return -ENOMEM;
}
-void gigaset_i4l_cmd(struct cardstate *cs, int cmd)
+static void gigaset_i4l_cmd(struct cardstate *cs, int cmd)
{
+ isdn_if *iif = cs->iif;
isdn_ctrl command;
command.driver = cs->myid;
command.command = cmd;
command.arg = 0;
- cs->iif.statcallb(&command);
+ iif->statcallb(&command);
}
-void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd)
+static void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd)
{
+ isdn_if *iif = bcs->cs->iif;
isdn_ctrl command;
command.driver = bcs->cs->myid;
command.command = cmd;
command.arg = bcs->channel;
- bcs->cs->iif.statcallb(&command);
-}
-
-int gigaset_isdn_setup_dial(struct at_state_t *at_state, void *data)
-{
- struct bc_state *bcs = at_state->bcs;
- unsigned proto;
- const char *bc;
- size_t length[AT_NUM];
- size_t l;
- int i;
- struct setup_parm *sp = data;
-
- switch (bcs->proto2) {
- case ISDN_PROTO_L2_HDLC:
- proto = 1; /* 0: Bitsynchron, 1: HDLC, 2: voice */
- break;
- case ISDN_PROTO_L2_TRANS:
- proto = 2; /* 0: Bitsynchron, 1: HDLC, 2: voice */
- break;
- default:
- dev_err(bcs->cs->dev, "%s: invalid L2 protocol: %u\n",
- __func__, bcs->proto2);
- return -EINVAL;
- }
-
- switch (sp->si1) {
- case 1: /* audio */
- bc = "9090A3"; /* 3.1 kHz audio, A-law */
- break;
- case 7: /* data */
- default: /* hope the app knows what it is doing */
- bc = "8890"; /* unrestricted digital information */
- }
- //FIXME add missing si1 values from 1TR6, inspect si2, set HLC/LLC
-
- length[AT_DIAL ] = 1 + strlen(sp->phone) + 1 + 1;
- l = strlen(sp->eazmsn);
- length[AT_MSN ] = l ? 6 + l + 1 + 1 : 0;
- length[AT_BC ] = 5 + strlen(bc) + 1 + 1;
- length[AT_PROTO] = 6 + 1 + 1 + 1; /* proto: 1 character */
- length[AT_ISO ] = 6 + 1 + 1 + 1; /* channel: 1 character */
- length[AT_TYPE ] = 6 + 1 + 1 + 1; /* call type: 1 character */
- length[AT_HLC ] = 0;
-
- for (i = 0; i < AT_NUM; ++i) {
- kfree(bcs->commands[i]);
- bcs->commands[i] = NULL;
- if (length[i] &&
- !(bcs->commands[i] = kmalloc(length[i], GFP_ATOMIC))) {
- dev_err(bcs->cs->dev, "out of memory\n");
- return -ENOMEM;
- }
- }
-
- /* type = 1: extern, 0: intern, 2: recall, 3: door, 4: centrex */
- if (sp->phone[0] == '*' && sp->phone[1] == '*') {
- /* internal call: translate ** prefix to CTP value */
- snprintf(bcs->commands[AT_DIAL], length[AT_DIAL],
- "D%s\r", sp->phone+2);
- strncpy(bcs->commands[AT_TYPE], "^SCTP=0\r", length[AT_TYPE]);
- } else {
- snprintf(bcs->commands[AT_DIAL], length[AT_DIAL],
- "D%s\r", sp->phone);
- strncpy(bcs->commands[AT_TYPE], "^SCTP=1\r", length[AT_TYPE]);
- }
-
- if (bcs->commands[AT_MSN])
- snprintf(bcs->commands[AT_MSN], length[AT_MSN],
- "^SMSN=%s\r", sp->eazmsn);
- snprintf(bcs->commands[AT_BC ], length[AT_BC ],
- "^SBC=%s\r", bc);
- snprintf(bcs->commands[AT_PROTO], length[AT_PROTO],
- "^SBPR=%u\r", proto);
- snprintf(bcs->commands[AT_ISO ], length[AT_ISO ],
- "^SISO=%u\r", (unsigned)bcs->channel + 1);
-
- return 0;
-}
-
-int gigaset_isdn_setup_accept(struct at_state_t *at_state)
-{
- unsigned proto;
- size_t length[AT_NUM];
- int i;
- struct bc_state *bcs = at_state->bcs;
-
- switch (bcs->proto2) {
- case ISDN_PROTO_L2_HDLC:
- proto = 1; /* 0: Bitsynchron, 1: HDLC, 2: voice */
- break;
- case ISDN_PROTO_L2_TRANS:
- proto = 2; /* 0: Bitsynchron, 1: HDLC, 2: voice */
- break;
- default:
- dev_err(at_state->cs->dev, "%s: invalid protocol: %u\n",
- __func__, bcs->proto2);
- return -EINVAL;
- }
-
- length[AT_DIAL ] = 0;
- length[AT_MSN ] = 0;
- length[AT_BC ] = 0;
- length[AT_PROTO] = 6 + 1 + 1 + 1; /* proto: 1 character */
- length[AT_ISO ] = 6 + 1 + 1 + 1; /* channel: 1 character */
- length[AT_TYPE ] = 0;
- length[AT_HLC ] = 0;
-
- for (i = 0; i < AT_NUM; ++i) {
- kfree(bcs->commands[i]);
- bcs->commands[i] = NULL;
- if (length[i] &&
- !(bcs->commands[i] = kmalloc(length[i], GFP_ATOMIC))) {
- dev_err(at_state->cs->dev, "out of memory\n");
- return -ENOMEM;
- }
- }
-
- snprintf(bcs->commands[AT_PROTO], length[AT_PROTO],
- "^SBPR=%u\r", proto);
- snprintf(bcs->commands[AT_ISO ], length[AT_ISO ],
- "^SISO=%u\r", (unsigned) bcs->channel + 1);
-
- return 0;
+ iif->statcallb(&command);
}
/**
@@ -482,6 +467,7 @@ int gigaset_isdn_icall(struct at_state_t *at_state)
{
struct cardstate *cs = at_state->cs;
struct bc_state *bcs = at_state->bcs;
+ isdn_if *iif = cs->iif;
isdn_ctrl response;
int retval;
@@ -531,7 +517,7 @@ int gigaset_isdn_icall(struct at_state_t *at_state)
response.arg = bcs->channel; //FIXME
}
response.driver = cs->myid;
- retval = cs->iif.statcallb(&response);
+ retval = iif->statcallb(&response);
gig_dbg(DEBUG_CMD, "Response: %d", retval);
switch (retval) {
case 0: /* no takers */
@@ -560,16 +546,109 @@ int gigaset_isdn_icall(struct at_state_t *at_state)
}
}
-/* Set Callback function pointer */
-int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid)
+/**
+ * gigaset_isdn_connD() - signal D channel connect
+ * @bcs: B channel descriptor structure.
+ *
+ * Called by main module to notify the LL that the D channel connection has
+ * been established.
+ */
+void gigaset_isdn_connD(struct bc_state *bcs)
{
- isdn_if *iif = &cs->iif;
+ gig_dbg(DEBUG_CMD, "sending DCONN");
+ gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN);
+}
- gig_dbg(DEBUG_ANY, "Register driver capabilities to LL");
+/**
+ * gigaset_isdn_hupD() - signal D channel hangup
+ * @bcs: B channel descriptor structure.
+ *
+ * Called by main module to notify the LL that the D channel connection has
+ * been shut down.
+ */
+void gigaset_isdn_hupD(struct bc_state *bcs)
+{
+ gig_dbg(DEBUG_CMD, "sending DHUP");
+ gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DHUP);
+}
+
+/**
+ * gigaset_isdn_connB() - signal B channel connect
+ * @bcs: B channel descriptor structure.
+ *
+ * Called by main module to notify the LL that the B channel connection has
+ * been established.
+ */
+void gigaset_isdn_connB(struct bc_state *bcs)
+{
+ gig_dbg(DEBUG_CMD, "sending BCONN");
+ gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN);
+}
+
+/**
+ * gigaset_isdn_hupB() - signal B channel hangup
+ * @bcs: B channel descriptor structure.
+ *
+ * Called by main module to notify the LL that the B channel connection has
+ * been shut down.
+ */
+void gigaset_isdn_hupB(struct bc_state *bcs)
+{
+ gig_dbg(DEBUG_CMD, "sending BHUP");
+ gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BHUP);
+}
+
+/**
+ * gigaset_isdn_start() - signal device availability
+ * @cs: device descriptor structure.
+ *
+ * Called by main module to notify the LL that the device is available for
+ * use.
+ */
+void gigaset_isdn_start(struct cardstate *cs)
+{
+ gig_dbg(DEBUG_CMD, "sending RUN");
+ gigaset_i4l_cmd(cs, ISDN_STAT_RUN);
+}
+
+/**
+ * gigaset_isdn_stop() - signal device unavailability
+ * @cs: device descriptor structure.
+ *
+ * Called by main module to notify the LL that the device is no longer
+ * available for use.
+ */
+void gigaset_isdn_stop(struct cardstate *cs)
+{
+ gig_dbg(DEBUG_CMD, "sending STOP");
+ gigaset_i4l_cmd(cs, ISDN_STAT_STOP);
+}
+
+/**
+ * gigaset_isdn_register() - register to LL
+ * @cs: device descriptor structure.
+ * @isdnid: device name.
+ *
+ * Called by main module to register the device with the LL.
+ *
+ * Return value: 1 for success, 0 for failure
+ */
+int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
+{
+ isdn_if *iif;
+
+ pr_info("ISDN4Linux interface\n");
+
+ iif = kmalloc(sizeof *iif, GFP_KERNEL);
+ if (!iif) {
+ pr_err("out of memory\n");
+ return 0;
+ }
if (snprintf(iif->id, sizeof iif->id, "%s_%u", isdnid, cs->minor_index)
>= sizeof iif->id) {
pr_err("ID too long: %s\n", isdnid);
+ kfree(iif);
return 0;
}
@@ -593,9 +672,26 @@ int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid)
if (!register_isdn(iif)) {
pr_err("register_isdn failed\n");
+ kfree(iif);
return 0;
}
+ cs->iif = iif;
cs->myid = iif->channels; /* Set my device id */
+ cs->hw_hdr_len = HW_HDR_LEN;
return 1;
}
+
+/**
+ * gigaset_isdn_unregister() - unregister from LL
+ * @cs: device descriptor structure.
+ *
+ * Called by main module to unregister the device from the LL.
+ */
+void gigaset_isdn_unregister(struct cardstate *cs)
+{
+ gig_dbg(DEBUG_CMD, "sending UNLOAD");
+ gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD);
+ kfree(cs->iif);
+ cs->iif = NULL;
+}
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c
index 9f3ef7b4248c..7dabfd35874c 100644
--- a/drivers/isdn/gigaset/isocdata.c
+++ b/drivers/isdn/gigaset/isocdata.c
@@ -500,7 +500,7 @@ int gigaset_isoc_buildframe(struct bc_state *bcs, unsigned char *in, int len)
int result;
switch (bcs->proto2) {
- case ISDN_PROTO_L2_HDLC:
+ case L2_HDLC:
result = hdlc_buildframe(bcs->hw.bas->isooutbuf, in, len);
gig_dbg(DEBUG_ISO, "%s: %d bytes HDLC -> %d",
__func__, len, result);
@@ -542,8 +542,9 @@ static inline void hdlc_flush(struct bc_state *bcs)
if (likely(bcs->skb != NULL))
skb_trim(bcs->skb, 0);
else if (!bcs->ignore) {
- if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
- skb_reserve(bcs->skb, HW_HDR_LEN);
+ bcs->skb = dev_alloc_skb(SBUFSIZE + bcs->cs->hw_hdr_len);
+ if (bcs->skb)
+ skb_reserve(bcs->skb, bcs->cs->hw_hdr_len);
else
dev_err(bcs->cs->dev, "could not allocate skb\n");
}
@@ -557,7 +558,9 @@ static inline void hdlc_flush(struct bc_state *bcs)
*/
static inline void hdlc_done(struct bc_state *bcs)
{
+ struct cardstate *cs = bcs->cs;
struct sk_buff *procskb;
+ unsigned int len;
if (unlikely(bcs->ignore)) {
bcs->ignore--;
@@ -568,32 +571,33 @@ static inline void hdlc_done(struct bc_state *bcs)
if ((procskb = bcs->skb) == NULL) {
/* previous error */
gig_dbg(DEBUG_ISO, "%s: skb=NULL", __func__);
- gigaset_rcv_error(NULL, bcs->cs, bcs);
+ gigaset_isdn_rcv_err(bcs);
} else if (procskb->len < 2) {
- dev_notice(bcs->cs->dev, "received short frame (%d octets)\n",
+ dev_notice(cs->dev, "received short frame (%d octets)\n",
procskb->len);
bcs->hw.bas->runts++;
- gigaset_rcv_error(procskb, bcs->cs, bcs);
+ dev_kfree_skb(procskb);
+ gigaset_isdn_rcv_err(bcs);
} else if (bcs->fcs != PPP_GOODFCS) {
- dev_notice(bcs->cs->dev, "frame check error (0x%04x)\n",
- bcs->fcs);
+ dev_notice(cs->dev, "frame check error (0x%04x)\n", bcs->fcs);
bcs->hw.bas->fcserrs++;
- gigaset_rcv_error(procskb, bcs->cs, bcs);
+ dev_kfree_skb(procskb);
+ gigaset_isdn_rcv_err(bcs);
} else {
- procskb->len -= 2; /* subtract FCS */
- procskb->tail -= 2;
- gig_dbg(DEBUG_ISO, "%s: good frame (%d octets)",
- __func__, procskb->len);
+ len = procskb->len;
+ __skb_trim(procskb, len -= 2); /* subtract FCS */
+ gig_dbg(DEBUG_ISO, "%s: good frame (%d octets)", __func__, len);
dump_bytes(DEBUG_STREAM_DUMP,
- "rcv data", procskb->data, procskb->len);
- bcs->hw.bas->goodbytes += procskb->len;
- gigaset_rcv_skb(procskb, bcs->cs, bcs);
+ "rcv data", procskb->data, len);
+ bcs->hw.bas->goodbytes += len;
+ gigaset_skb_rcvd(bcs, procskb);
}
- if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
- skb_reserve(bcs->skb, HW_HDR_LEN);
+ bcs->skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len);
+ if (bcs->skb)
+ skb_reserve(bcs->skb, cs->hw_hdr_len);
else
- dev_err(bcs->cs->dev, "could not allocate skb\n");
+ dev_err(cs->dev, "could not allocate skb\n");
bcs->fcs = PPP_INITFCS;
}
@@ -610,12 +614,8 @@ static inline void hdlc_frag(struct bc_state *bcs, unsigned inbits)
dev_notice(bcs->cs->dev, "received partial byte (%d bits)\n", inbits);
bcs->hw.bas->alignerrs++;
- gigaset_rcv_error(bcs->skb, bcs->cs, bcs);
-
- if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
- skb_reserve(bcs->skb, HW_HDR_LEN);
- else
- dev_err(bcs->cs->dev, "could not allocate skb\n");
+ gigaset_isdn_rcv_err(bcs);
+ __skb_trim(bcs->skb, 0);
bcs->fcs = PPP_INITFCS;
}
@@ -648,8 +648,8 @@ static const unsigned char bitcounts[256] = {
/* hdlc_unpack
* perform HDLC frame processing (bit unstuffing, flag detection, FCS calculation)
* on a sequence of received data bytes (8 bits each, LSB first)
- * pass on successfully received, complete frames as SKBs via gigaset_rcv_skb
- * notify of errors via gigaset_rcv_error
+ * pass on successfully received, complete frames as SKBs via gigaset_skb_rcvd
+ * notify of errors via gigaset_isdn_rcv_err
* tally frames, errors etc. in BC structure counters
* parameters:
* src received data
@@ -841,7 +841,7 @@ static inline void hdlc_unpack(unsigned char *src, unsigned count,
}
/* trans_receive
- * pass on received USB frame transparently as SKB via gigaset_rcv_skb
+ * pass on received USB frame transparently as SKB via gigaset_skb_rcvd
* invert bytes
* tally frames, errors etc. in BC structure counters
* parameters:
@@ -852,6 +852,7 @@ static inline void hdlc_unpack(unsigned char *src, unsigned count,
static inline void trans_receive(unsigned char *src, unsigned count,
struct bc_state *bcs)
{
+ struct cardstate *cs = bcs->cs;
struct sk_buff *skb;
int dobytes;
unsigned char *dst;
@@ -862,12 +863,12 @@ static inline void trans_receive(unsigned char *src, unsigned count,
return;
}
if (unlikely((skb = bcs->skb) == NULL)) {
- bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN);
+ bcs->skb = skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len);
if (!skb) {
- dev_err(bcs->cs->dev, "could not allocate skb\n");
+ dev_err(cs->dev, "could not allocate skb\n");
return;
}
- skb_reserve(skb, HW_HDR_LEN);
+ skb_reserve(skb, cs->hw_hdr_len);
}
bcs->hw.bas->goodbytes += skb->len;
dobytes = TRANSBUFSIZE - skb->len;
@@ -881,14 +882,14 @@ static inline void trans_receive(unsigned char *src, unsigned count,
if (dobytes == 0) {
dump_bytes(DEBUG_STREAM_DUMP,
"rcv data", skb->data, skb->len);
- gigaset_rcv_skb(skb, bcs->cs, bcs);
- bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN);
+ gigaset_skb_rcvd(bcs, skb);
+ bcs->skb = skb =
+ dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len);
if (!skb) {
- dev_err(bcs->cs->dev,
- "could not allocate skb\n");
+ dev_err(cs->dev, "could not allocate skb\n");
return;
}
- skb_reserve(bcs->skb, HW_HDR_LEN);
+ skb_reserve(skb, cs->hw_hdr_len);
dobytes = TRANSBUFSIZE;
}
}
@@ -897,7 +898,7 @@ static inline void trans_receive(unsigned char *src, unsigned count,
void gigaset_isoc_receive(unsigned char *src, unsigned count, struct bc_state *bcs)
{
switch (bcs->proto2) {
- case ISDN_PROTO_L2_HDLC:
+ case L2_HDLC:
hdlc_unpack(src, count, bcs);
break;
default: /* assume transparent */
@@ -981,8 +982,10 @@ void gigaset_isoc_input(struct inbuf_t *inbuf)
* @bcs: B channel descriptor structure.
* @skb: data to send.
*
- * Called by i4l.c to queue an skb for sending, and start transmission if
+ * Called by LL to queue an skb for sending, and start transmission if
* necessary.
+ * Once the payload data has been transmitted completely, gigaset_skb_sent()
+ * will be called with the first cs->hw_hdr_len bytes of skb->head preserved.
*
* Return value:
* number of bytes accepted for sending (skb->len) if ok,
diff --git a/drivers/isdn/hysdn/Kconfig b/drivers/isdn/hysdn/Kconfig
index c9e4231968ef..e86bc6583d71 100644
--- a/drivers/isdn/hysdn/Kconfig
+++ b/drivers/isdn/hysdn/Kconfig
@@ -1,6 +1,3 @@
-#
-# Config.in for HYSDN ISDN driver
-#
config HYSDN
tristate "Hypercope HYSDN cards (Champ, Ergo, Metro) support (module only)"
depends on m && PROC_FS && PCI
@@ -15,4 +12,3 @@ config HYSDN_CAPI
depends on HYSDN && ISDN_CAPI
help
Say Y here if you like to use Hypercope's CAPI 2.0 interface.
-
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index 90b56ed8651f..507e13d9a57c 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -1563,7 +1563,7 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
*(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_KEEPALIVE);
*(__be32 *)(p + 8) = cpu_to_be32(lp->cisco_myseq);
*(__be32 *)(p + 12) = cpu_to_be32(lp->cisco_yourseq);
- *(__be16 *)(p + 16) = cpu_to_be16(0xffff); // reliablity, always 0xffff
+ *(__be16 *)(p + 16) = cpu_to_be16(0xffff); // reliability, always 0xffff
p += 18;
isdn_net_write_super(lp, skb);
diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h
index 74032d0881ef..7511f08effa5 100644
--- a/drivers/isdn/i4l/isdn_net.h
+++ b/drivers/isdn/i4l/isdn_net.h
@@ -83,19 +83,19 @@ static __inline__ isdn_net_local * isdn_net_get_locked_lp(isdn_net_dev *nd)
spin_lock_irqsave(&nd->queue_lock, flags);
lp = nd->queue; /* get lp on top of queue */
- spin_lock(&nd->queue->xmit_lock);
while (isdn_net_lp_busy(nd->queue)) {
- spin_unlock(&nd->queue->xmit_lock);
nd->queue = nd->queue->next;
if (nd->queue == lp) { /* not found -- should never happen */
lp = NULL;
goto errout;
}
- spin_lock(&nd->queue->xmit_lock);
}
lp = nd->queue;
nd->queue = nd->queue->next;
+ spin_unlock_irqrestore(&nd->queue_lock, flags);
+ spin_lock(&lp->xmit_lock);
local_bh_disable();
+ return lp;
errout:
spin_unlock_irqrestore(&nd->queue_lock, flags);
return lp;
diff --git a/drivers/isdn/icn/Kconfig b/drivers/isdn/icn/Kconfig
index 89d15eed765e..4534f21a1852 100644
--- a/drivers/isdn/icn/Kconfig
+++ b/drivers/isdn/icn/Kconfig
@@ -1,6 +1,3 @@
-#
-# Config.in for ICN ISDN driver
-#
config ISDN_DRV_ICN
tristate "ICN 2B and 4B support"
depends on ISA
@@ -13,4 +10,3 @@ config ISDN_DRV_ICN
separately. See <file:Documentation/isdn/README> and
<file:Documentation/isdn/README.icn> for more
information.
-
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
index feb0fa45b664..28182ed8dea1 100644
--- a/drivers/isdn/mISDN/socket.c
+++ b/drivers/isdn/mISDN/socket.c
@@ -808,8 +808,7 @@ mISDN_sock_create(struct net *net, struct socket *sock, int proto)
return err;
}
-static struct
-net_proto_family mISDN_sock_family_ops = {
+static const struct net_proto_family mISDN_sock_family_ops = {
.owner = THIS_MODULE,
.family = PF_ISDN,
.create = mISDN_sock_create,
diff --git a/drivers/isdn/pcbit/Kconfig b/drivers/isdn/pcbit/Kconfig
index ffba6eca1244..e9b2dd85d410 100644
--- a/drivers/isdn/pcbit/Kconfig
+++ b/drivers/isdn/pcbit/Kconfig
@@ -1,6 +1,3 @@
-#
-# Config.in for PCBIT ISDN driver
-#
config ISDN_DRV_PCBIT
tristate "PCBIT-D support"
depends on ISA && (BROKEN || X86)
@@ -11,4 +8,3 @@ config ISDN_DRV_PCBIT
the card using a utility which is distributed separately. See
<file:Documentation/isdn/README> and
<file:Documentation/isdn/README.pcbit> for more information.
-
diff --git a/drivers/isdn/sc/Kconfig b/drivers/isdn/sc/Kconfig
index e6510ca7bf43..7469863a7925 100644
--- a/drivers/isdn/sc/Kconfig
+++ b/drivers/isdn/sc/Kconfig
@@ -1,6 +1,3 @@
-#
-# Config.in for Spellcaster ISDN driver
-#
config ISDN_DRV_SC
tristate "Spellcaster support"
depends on ISA
@@ -9,4 +6,3 @@ config ISDN_DRV_SC
driver currently builds only in a modularized version.
To build it, choose M here: the module will be called sc.
See <file:Documentation/isdn/README.sc> for more information.
-
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index e4f599f20e38..e481d3c52a54 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -236,6 +236,15 @@ config LEDS_BD2802
This option enables support for BD2802GU RGB LED driver chips
accessed via the I2C bus.
+config LEDS_INTEL_SS4200
+ tristate "LED driver for Intel NAS SS4200 series"
+ depends on LEDS_CLASS && PCI && DMI
+ help
+ This option enables support for the Intel SS4200 series of
+ Network Attached Storage servers. You may control the hard
+ drive or power LEDs on the front panel. Using this driver
+ can stop the front LED from blinking after startup.
+
comment "LED Triggers"
config LEDS_TRIGGERS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 46d72704d606..12b7a20fcfe0 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o
obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o
obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o
obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
+obj-$(CONFIG_LEDS_INTEL_SS4200) += leds-ss4200.o
# LED SPI Drivers
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
diff --git a/drivers/leds/leds-alix2.c b/drivers/leds/leds-alix2.c
index 731d4eef3425..f59ffadf5125 100644
--- a/drivers/leds/leds-alix2.c
+++ b/drivers/leds/leds-alix2.c
@@ -11,11 +11,24 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/string.h>
+#include <linux/pci.h>
static int force = 0;
module_param(force, bool, 0444);
MODULE_PARM_DESC(force, "Assume system has ALIX.2/ALIX.3 style LEDs");
+#define MSR_LBAR_GPIO 0x5140000C
+#define CS5535_GPIO_SIZE 256
+
+static u32 gpio_base;
+
+static struct pci_device_id divil_pci[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
+ { } /* NULL entry */
+};
+MODULE_DEVICE_TABLE(pci, divil_pci);
+
struct alix_led {
struct led_classdev cdev;
unsigned short port;
@@ -30,9 +43,9 @@ static void alix_led_set(struct led_classdev *led_cdev,
container_of(led_cdev, struct alix_led, cdev);
if (brightness)
- outl(led_dev->on_value, led_dev->port);
+ outl(led_dev->on_value, gpio_base + led_dev->port);
else
- outl(led_dev->off_value, led_dev->port);
+ outl(led_dev->off_value, gpio_base + led_dev->port);
}
static struct alix_led alix_leds[] = {
@@ -41,7 +54,7 @@ static struct alix_led alix_leds[] = {
.name = "alix:1",
.brightness_set = alix_led_set,
},
- .port = 0x6100,
+ .port = 0x00,
.on_value = 1 << 22,
.off_value = 1 << 6,
},
@@ -50,7 +63,7 @@ static struct alix_led alix_leds[] = {
.name = "alix:2",
.brightness_set = alix_led_set,
},
- .port = 0x6180,
+ .port = 0x80,
.on_value = 1 << 25,
.off_value = 1 << 9,
},
@@ -59,7 +72,7 @@ static struct alix_led alix_leds[] = {
.name = "alix:3",
.brightness_set = alix_led_set,
},
- .port = 0x6180,
+ .port = 0x80,
.on_value = 1 << 27,
.off_value = 1 << 11,
},
@@ -101,64 +114,104 @@ static struct platform_driver alix_led_driver = {
},
};
-static int __init alix_present(void)
+static int __init alix_present(unsigned long bios_phys,
+ const char *alix_sig,
+ size_t alix_sig_len)
{
- const unsigned long bios_phys = 0x000f0000;
const size_t bios_len = 0x00010000;
- const char alix_sig[] = "PC Engines ALIX.";
- const size_t alix_sig_len = sizeof(alix_sig) - 1;
-
const char *bios_virt;
const char *scan_end;
const char *p;
- int ret = 0;
+ char name[64];
if (force) {
printk(KERN_NOTICE "%s: forced to skip BIOS test, "
"assume system has ALIX.2 style LEDs\n",
KBUILD_MODNAME);
- ret = 1;
- goto out;
+ return 1;
}
bios_virt = phys_to_virt(bios_phys);
scan_end = bios_virt + bios_len - (alix_sig_len + 2);
for (p = bios_virt; p < scan_end; p++) {
const char *tail;
+ char *a;
- if (memcmp(p, alix_sig, alix_sig_len) != 0) {
+ if (memcmp(p, alix_sig, alix_sig_len) != 0)
continue;
- }
+
+ memcpy(name, p, sizeof(name));
+
+ /* remove the first \0 character from string */
+ a = strchr(name, '\0');
+ if (a)
+ *a = ' ';
+
+ /* cut the string at a newline */
+ a = strchr(name, '\r');
+ if (a)
+ *a = '\0';
tail = p + alix_sig_len;
- if ((tail[0] == '2' || tail[0] == '3') && tail[1] == '\0') {
+ if ((tail[0] == '2' || tail[0] == '3')) {
printk(KERN_INFO
"%s: system is recognized as \"%s\"\n",
- KBUILD_MODNAME, p);
- ret = 1;
- break;
+ KBUILD_MODNAME, name);
+ return 1;
}
}
-out:
- return ret;
+ return 0;
}
static struct platform_device *pdev;
-static int __init alix_led_init(void)
+static int __init alix_pci_led_init(void)
{
- int ret;
+ u32 low, hi;
- if (!alix_present()) {
- ret = -ENODEV;
- goto out;
+ if (pci_dev_present(divil_pci) == 0) {
+ printk(KERN_WARNING KBUILD_MODNAME": DIVIL not found\n");
+ return -ENODEV;
}
- /* enable output on GPIO for LED 1,2,3 */
- outl(1 << 6, 0x6104);
- outl(1 << 9, 0x6184);
- outl(1 << 11, 0x6184);
+ /* Grab the GPIO I/O range */
+ rdmsr(MSR_LBAR_GPIO, low, hi);
+
+ /* Check the mask and whether GPIO is enabled (sanity check) */
+ if (hi != 0x0000f001) {
+ printk(KERN_WARNING KBUILD_MODNAME": GPIO not enabled\n");
+ return -ENODEV;
+ }
+
+ /* Mask off the IO base address */
+ gpio_base = low & 0x0000ff00;
+
+ if (!request_region(gpio_base, CS5535_GPIO_SIZE, KBUILD_MODNAME)) {
+ printk(KERN_ERR KBUILD_MODNAME": can't allocate I/O for GPIO\n");
+ return -ENODEV;
+ }
+
+ /* Set GPIO function to output */
+ outl(1 << 6, gpio_base + 0x04);
+ outl(1 << 9, gpio_base + 0x84);
+ outl(1 << 11, gpio_base + 0x84);
+
+ return 0;
+}
+
+static int __init alix_led_init(void)
+{
+ int ret = -ENODEV;
+ const char tinybios_sig[] = "PC Engines ALIX.";
+ const char coreboot_sig[] = "PC Engines\0ALIX.";
+
+ if (alix_present(0xf0000, tinybios_sig, sizeof(tinybios_sig) - 1) ||
+ alix_present(0x500, coreboot_sig, sizeof(coreboot_sig) - 1))
+ ret = alix_pci_led_init();
+
+ if (ret < 0)
+ return ret;
pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
if (!IS_ERR(pdev)) {
@@ -168,7 +221,6 @@ static int __init alix_led_init(void)
} else
ret = PTR_ERR(pdev);
-out:
return ret;
}
@@ -176,6 +228,7 @@ static void __exit alix_led_exit(void)
{
platform_device_unregister(pdev);
platform_driver_unregister(&alix_led_driver);
+ release_region(gpio_base, CS5535_GPIO_SIZE);
}
module_init(alix_led_init);
diff --git a/drivers/leds/leds-ams-delta.c b/drivers/leds/leds-ams-delta.c
index 446050759b4d..b9826032450b 100644
--- a/drivers/leds/leds-ams-delta.c
+++ b/drivers/leds/leds-ams-delta.c
@@ -12,7 +12,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/leds.h>
-#include <mach/board-ams-delta.h>
+#include <plat/board-ams-delta.h>
/*
* Our context
diff --git a/drivers/leds/leds-ss4200.c b/drivers/leds/leds-ss4200.c
new file mode 100644
index 000000000000..0ec4ec3bc823
--- /dev/null
+++ b/drivers/leds/leds-ss4200.c
@@ -0,0 +1,552 @@
+/*
+ * SS4200-E Hardware API
+ * Copyright (c) 2009, Intel Corporation.
+ * Copyright IBM Corporation, 2009
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Author: Dave Hansen <dave@sr71.net>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/dmi.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+
+MODULE_AUTHOR("Rodney Girod <rgirod@confocus.com>, Dave Hansen <dave@sr71.net>");
+MODULE_DESCRIPTION("Intel NAS/Home Server ICH7 GPIO Driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * ICH7 LPC/GPIO PCI Config register offsets
+ */
+#define PMBASE 0x040
+#define GPIO_BASE 0x048
+#define GPIO_CTRL 0x04c
+#define GPIO_EN 0x010
+
+/*
+ * The ICH7 GPIO register block is 64 bytes in size.
+ */
+#define ICH7_GPIO_SIZE 64
+
+/*
+ * Define register offsets within the ICH7 register block.
+ */
+#define GPIO_USE_SEL 0x000
+#define GP_IO_SEL 0x004
+#define GP_LVL 0x00c
+#define GPO_BLINK 0x018
+#define GPI_INV 0x030
+#define GPIO_USE_SEL2 0x034
+#define GP_IO_SEL2 0x038
+#define GP_LVL2 0x03c
+
+/*
+ * PCI ID of the Intel ICH7 LPC Device within which the GPIO block lives.
+ */
+static struct pci_device_id ich7_lpc_pci_id[] =
+{
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_30) },
+ { } /* NULL entry */
+};
+
+MODULE_DEVICE_TABLE(pci, ich7_lpc_pci_id);
+
+static int __init ss4200_led_dmi_callback(const struct dmi_system_id *id)
+{
+ pr_info("detected '%s'\n", id->ident);
+ return 1;
+}
+
+static unsigned int __initdata nodetect;
+module_param_named(nodetect, nodetect, bool, 0);
+MODULE_PARM_DESC(nodetect, "Skip DMI-based hardware detection");
+
+/*
+ * struct nas_led_whitelist - List of known good models
+ *
+ * Contains the known good models this driver is compatible with.
+ * When adding a new model try to be as strict as possible. This
+ * makes it possible to keep the false positives (the model is
+ * detected as working, but in reality it is not) as low as
+ * possible.
+ */
+static struct dmi_system_id __initdata nas_led_whitelist[] = {
+ {
+ .callback = ss4200_led_dmi_callback,
+ .ident = "Intel SS4200-E",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "SS4200-E"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "1.00.00")
+ }
+ },
+};
+
+/*
+ * Base I/O address assigned to the Power Management register block
+ */
+static u32 g_pm_io_base;
+
+/*
+ * Base I/O address assigned to the ICH7 GPIO register block
+ */
+static u32 nas_gpio_io_base;
+
+/*
+ * When we successfully register a region, we are returned a resource.
+ * We use these to identify which regions we need to release on our way
+ * back out.
+ */
+static struct resource *gp_gpio_resource;
+
+struct nasgpio_led {
+ char *name;
+ u32 gpio_bit;
+ struct led_classdev led_cdev;
+};
+
+/*
+ * gpio_bit(s) are the ICH7 GPIO bit assignments
+ */
+static struct nasgpio_led nasgpio_leds[] = {
+ { .name = "hdd1:blue:sata", .gpio_bit = 0 },
+ { .name = "hdd1:amber:sata", .gpio_bit = 1 },
+ { .name = "hdd2:blue:sata", .gpio_bit = 2 },
+ { .name = "hdd2:amber:sata", .gpio_bit = 3 },
+ { .name = "hdd3:blue:sata", .gpio_bit = 4 },
+ { .name = "hdd3:amber:sata", .gpio_bit = 5 },
+ { .name = "hdd4:blue:sata", .gpio_bit = 6 },
+ { .name = "hdd4:amber:sata", .gpio_bit = 7 },
+ { .name = "power:blue:power", .gpio_bit = 27},
+ { .name = "power:amber:power", .gpio_bit = 28},
+};
+
+#define NAS_RECOVERY 0x00000400 /* GPIO10 */
+
+static struct nasgpio_led *
+led_classdev_to_nasgpio_led(struct led_classdev *led_cdev)
+{
+ return container_of(led_cdev, struct nasgpio_led, led_cdev);
+}
+
+static struct nasgpio_led *get_led_named(char *name)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++) {
+ if (strcmp(nasgpio_leds[i].name, name))
+ continue;
+ return &nasgpio_leds[i];
+ }
+ return NULL;
+}
+
+/*
+ * This protects access to the gpio ports.
+ */
+static DEFINE_SPINLOCK(nasgpio_gpio_lock);
+
+/*
+ * There are two gpio ports, one for blinking and the other
+ * for power. @port tells us if we're doing blinking or
+ * power control.
+ *
+ * Caller must hold nasgpio_gpio_lock
+ */
+static void __nasgpio_led_set_attr(struct led_classdev *led_cdev,
+ u32 port, u32 value)
+{
+ struct nasgpio_led *led = led_classdev_to_nasgpio_led(led_cdev);
+ u32 gpio_out;
+
+ gpio_out = inl(nas_gpio_io_base + port);
+ if (value)
+ gpio_out |= (1<<led->gpio_bit);
+ else
+ gpio_out &= ~(1<<led->gpio_bit);
+
+ outl(gpio_out, nas_gpio_io_base + port);
+}
+
+static void nasgpio_led_set_attr(struct led_classdev *led_cdev,
+ u32 port, u32 value)
+{
+ spin_lock(&nasgpio_gpio_lock);
+ __nasgpio_led_set_attr(led_cdev, port, value);
+ spin_unlock(&nasgpio_gpio_lock);
+}
+
+u32 nasgpio_led_get_attr(struct led_classdev *led_cdev, u32 port)
+{
+ struct nasgpio_led *led = led_classdev_to_nasgpio_led(led_cdev);
+ u32 gpio_in;
+
+ spin_lock(&nasgpio_gpio_lock);
+ gpio_in = inl(nas_gpio_io_base + port);
+ spin_unlock(&nasgpio_gpio_lock);
+ if (gpio_in & (1<<led->gpio_bit))
+ return 1;
+ return 0;
+}
+
+/*
+ * There is actual brightness control in the hardware,
+ * but it is via smbus commands and not implemented
+ * in this driver.
+ */
+static void nasgpio_led_set_brightness(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ u32 setting = 0;
+ if (brightness >= LED_HALF)
+ setting = 1;
+ /*
+ * Hold the lock across both operations. This ensures
+ * consistency so that both the "turn off blinking"
+ * and "turn light off" operations complete as a set.
+ */
+ spin_lock(&nasgpio_gpio_lock);
+ /*
+ * LED class documentation asks that past blink state
+ * be disabled when brightness is turned to zero.
+ */
+ if (brightness == 0)
+ __nasgpio_led_set_attr(led_cdev, GPO_BLINK, 0);
+ __nasgpio_led_set_attr(led_cdev, GP_LVL, setting);
+ spin_unlock(&nasgpio_gpio_lock);
+}
+
+static int nasgpio_led_set_blink(struct led_classdev *led_cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ u32 setting = 1;
+ if (!(*delay_on == 0 && *delay_off == 0) &&
+ !(*delay_on == 500 && *delay_off == 500))
+ return -EINVAL;
+ /*
+ * These are very approximate.
+ */
+ *delay_on = 500;
+ *delay_off = 500;
+
+ nasgpio_led_set_attr(led_cdev, GPO_BLINK, setting);
+
+ return 0;
+}
+
+
+/*
+ * Initialize the ICH7 GPIO registers for NAS usage. The BIOS should have
+ * already taken care of this, but we will do so in a non destructive manner
+ * so that we have what we need whether the BIOS did it or not.
+ */
+static int __devinit ich7_gpio_init(struct device *dev)
+{
+ int i;
+ u32 config_data = 0;
+ u32 all_nas_led = 0;
+
+ for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++)
+ all_nas_led |= (1<<nasgpio_leds[i].gpio_bit);
+
+ spin_lock(&nasgpio_gpio_lock);
+ /*
+ * We need to enable all of the GPIO lines used by the NAS box,
+ * so we will read the current Use Selection and add our usage
+ * to it. This should be benign with regard to the original
+ * BIOS configuration.
+ */
+ config_data = inl(nas_gpio_io_base + GPIO_USE_SEL);
+ dev_dbg(dev, ": Data read from GPIO_USE_SEL = 0x%08x\n", config_data);
+ config_data |= all_nas_led + NAS_RECOVERY;
+ outl(config_data, nas_gpio_io_base + GPIO_USE_SEL);
+ config_data = inl(nas_gpio_io_base + GPIO_USE_SEL);
+ dev_dbg(dev, ": GPIO_USE_SEL = 0x%08x\n\n", config_data);
+
+ /*
+ * The LED GPIO outputs need to be configured for output, so we
+ * will ensure that all LED lines are cleared for output and the
+ * RECOVERY line ready for input. This too should be benign with
+ * regard to BIOS configuration.
+ */
+ config_data = inl(nas_gpio_io_base + GP_IO_SEL);
+ dev_dbg(dev, ": Data read from GP_IO_SEL = 0x%08x\n",
+ config_data);
+ config_data &= ~all_nas_led;
+ config_data |= NAS_RECOVERY;
+ outl(config_data, nas_gpio_io_base + GP_IO_SEL);
+ config_data = inl(nas_gpio_io_base + GP_IO_SEL);
+ dev_dbg(dev, ": GP_IO_SEL = 0x%08x\n", config_data);
+
+ /*
+ * In our final system, the BIOS will initialize the state of all
+ * of the LEDs. For now, we turn them all off (or Low).
+ */
+ config_data = inl(nas_gpio_io_base + GP_LVL);
+ dev_dbg(dev, ": Data read from GP_LVL = 0x%08x\n", config_data);
+ /*
+ * In our final system, the BIOS will initialize the blink state of all
+ * of the LEDs. For now, we turn blink off for all of them.
+ */
+ config_data = inl(nas_gpio_io_base + GPO_BLINK);
+ dev_dbg(dev, ": Data read from GPO_BLINK = 0x%08x\n", config_data);
+
+ /*
+ * At this moment, I am unsure if anything needs to happen with GPI_INV
+ */
+ config_data = inl(nas_gpio_io_base + GPI_INV);
+ dev_dbg(dev, ": Data read from GPI_INV = 0x%08x\n", config_data);
+
+ spin_unlock(&nasgpio_gpio_lock);
+ return 0;
+}
+
+static void ich7_lpc_cleanup(struct device *dev)
+{
+ /*
+ * If we were given exclusive use of the GPIO
+ * I/O Address range, we must return it.
+ */
+ if (gp_gpio_resource) {
+ dev_dbg(dev, ": Releasing GPIO I/O addresses\n");
+ release_region(nas_gpio_io_base, ICH7_GPIO_SIZE);
+ gp_gpio_resource = NULL;
+ }
+}
+
+/*
+ * The OS has determined that the LPC of the Intel ICH7 Southbridge is present
+ * so we can retrive the required operational information and prepare the GPIO.
+ */
+static struct pci_dev *nas_gpio_pci_dev;
+static int __devinit ich7_lpc_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ int status = 0;
+ u32 gc = 0;
+
+ pci_enable_device(dev);
+
+ nas_gpio_pci_dev = dev;
+ status = pci_read_config_dword(dev, PMBASE, &g_pm_io_base);
+ if (status)
+ goto out;
+ g_pm_io_base &= 0x00000ff80;
+
+ status = pci_read_config_dword(dev, GPIO_CTRL, &gc);
+ if (!(GPIO_EN & gc)) {
+ status = -EEXIST;
+ dev_info(&dev->dev,
+ "ERROR: The LPC GPIO Block has not been enabled.\n");
+ goto out;
+ }
+
+ status = pci_read_config_dword(dev, GPIO_BASE, &nas_gpio_io_base);
+ if (0 > status) {
+ dev_info(&dev->dev, "Unable to read GPIOBASE.\n");
+ goto out;
+ }
+ dev_dbg(&dev->dev, ": GPIOBASE = 0x%08x\n", nas_gpio_io_base);
+ nas_gpio_io_base &= 0x00000ffc0;
+
+ /*
+ * Insure that we have exclusive access to the GPIO I/O address range.
+ */
+ gp_gpio_resource = request_region(nas_gpio_io_base, ICH7_GPIO_SIZE,
+ KBUILD_MODNAME);
+ if (NULL == gp_gpio_resource) {
+ dev_info(&dev->dev,
+ "ERROR Unable to register GPIO I/O addresses.\n");
+ status = -1;
+ goto out;
+ }
+
+ /*
+ * Initialize the GPIO for NAS/Home Server Use
+ */
+ ich7_gpio_init(&dev->dev);
+
+out:
+ if (status) {
+ ich7_lpc_cleanup(&dev->dev);
+ pci_disable_device(dev);
+ }
+ return status;
+}
+
+static void ich7_lpc_remove(struct pci_dev *dev)
+{
+ ich7_lpc_cleanup(&dev->dev);
+ pci_disable_device(dev);
+}
+
+/*
+ * pci_driver structure passed to the PCI modules
+ */
+static struct pci_driver nas_gpio_pci_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = ich7_lpc_pci_id,
+ .probe = ich7_lpc_probe,
+ .remove = ich7_lpc_remove,
+};
+
+static struct led_classdev *get_classdev_for_led_nr(int nr)
+{
+ struct nasgpio_led *nas_led = &nasgpio_leds[nr];
+ struct led_classdev *led = &nas_led->led_cdev;
+ return led;
+}
+
+
+static void set_power_light_amber_noblink(void)
+{
+ struct nasgpio_led *amber = get_led_named("power:amber:power");
+ struct nasgpio_led *blue = get_led_named("power:blue:power");
+
+ if (!amber || !blue)
+ return;
+ /*
+ * LED_OFF implies disabling future blinking
+ */
+ pr_debug("setting blue off and amber on\n");
+
+ nasgpio_led_set_brightness(&blue->led_cdev, LED_OFF);
+ nasgpio_led_set_brightness(&amber->led_cdev, LED_FULL);
+}
+
+static ssize_t nas_led_blink_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led = dev_get_drvdata(dev);
+ int blinking = 0;
+ if (nasgpio_led_get_attr(led, GPO_BLINK))
+ blinking = 1;
+ return sprintf(buf, "%u\n", blinking);
+}
+
+static ssize_t nas_led_blink_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ struct led_classdev *led = dev_get_drvdata(dev);
+ unsigned long blink_state;
+
+ ret = strict_strtoul(buf, 10, &blink_state);
+ if (ret)
+ return ret;
+
+ nasgpio_led_set_attr(led, GPO_BLINK, blink_state);
+
+ return size;
+}
+
+static DEVICE_ATTR(blink, 0644, nas_led_blink_show, nas_led_blink_store);
+
+static int register_nasgpio_led(int led_nr)
+{
+ int ret;
+ struct nasgpio_led *nas_led = &nasgpio_leds[led_nr];
+ struct led_classdev *led = get_classdev_for_led_nr(led_nr);
+
+ led->name = nas_led->name;
+ led->brightness = LED_OFF;
+ if (nasgpio_led_get_attr(led, GP_LVL))
+ led->brightness = LED_FULL;
+ led->brightness_set = nasgpio_led_set_brightness;
+ led->blink_set = nasgpio_led_set_blink;
+ ret = led_classdev_register(&nas_gpio_pci_dev->dev, led);
+ if (ret)
+ return ret;
+ ret = device_create_file(led->dev, &dev_attr_blink);
+ if (ret)
+ led_classdev_unregister(led);
+ return ret;
+}
+
+static void unregister_nasgpio_led(int led_nr)
+{
+ struct led_classdev *led = get_classdev_for_led_nr(led_nr);
+ led_classdev_unregister(led);
+ device_remove_file(led->dev, &dev_attr_blink);
+}
+/*
+ * module load/initialization
+ */
+static int __init nas_gpio_init(void)
+{
+ int i;
+ int ret = 0;
+ int nr_devices = 0;
+
+ nr_devices = dmi_check_system(nas_led_whitelist);
+ if (nodetect) {
+ pr_info("skipping hardware autodetection\n");
+ pr_info("Please send 'dmidecode' output to dave@sr71.net\n");
+ nr_devices++;
+ }
+
+ if (nr_devices <= 0) {
+ pr_info("no LED devices found\n");
+ return -ENODEV;
+ }
+
+ pr_info("registering PCI driver\n");
+ ret = pci_register_driver(&nas_gpio_pci_driver);
+ if (ret)
+ return ret;
+ for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++) {
+ ret = register_nasgpio_led(i);
+ if (ret)
+ goto out_err;
+ }
+ /*
+ * When the system powers on, the BIOS leaves the power
+ * light blue and blinking. This will turn it solid
+ * amber once the driver is loaded.
+ */
+ set_power_light_amber_noblink();
+ return 0;
+out_err:
+ for (; i >= 0; i--)
+ unregister_nasgpio_led(i);
+ pci_unregister_driver(&nas_gpio_pci_driver);
+ return ret;
+}
+
+/*
+ * module unload
+ */
+static void __exit nas_gpio_exit(void)
+{
+ int i;
+ pr_info("Unregistering driver\n");
+ for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++)
+ unregister_nasgpio_led(i);
+ pci_unregister_driver(&nas_gpio_pci_driver);
+}
+
+module_init(nas_gpio_init);
+module_exit(nas_gpio_exit);
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index 1dc4185bd781..e355e7f6a536 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -46,7 +46,7 @@ obj-$(CONFIG_DM_LOG_USERSPACE) += dm-log-userspace.o
obj-$(CONFIG_DM_ZERO) += dm-zero.o
quiet_cmd_unroll = UNROLL $@
- cmd_unroll = $(PERL) $(srctree)/$(src)/unroll.pl $(UNROLL) \
+ cmd_unroll = $(AWK) -f$(srctree)/$(src)/unroll.awk -vN=$(UNROLL) \
< $< > $@ || ( rm -f $@ && exit 1 )
ifeq ($(CONFIG_ALTIVEC),y)
@@ -59,56 +59,56 @@ endif
targets += raid6int1.c
$(obj)/raid6int1.c: UNROLL := 1
-$(obj)/raid6int1.c: $(src)/raid6int.uc $(src)/unroll.pl FORCE
+$(obj)/raid6int1.c: $(src)/raid6int.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
targets += raid6int2.c
$(obj)/raid6int2.c: UNROLL := 2
-$(obj)/raid6int2.c: $(src)/raid6int.uc $(src)/unroll.pl FORCE
+$(obj)/raid6int2.c: $(src)/raid6int.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
targets += raid6int4.c
$(obj)/raid6int4.c: UNROLL := 4
-$(obj)/raid6int4.c: $(src)/raid6int.uc $(src)/unroll.pl FORCE
+$(obj)/raid6int4.c: $(src)/raid6int.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
targets += raid6int8.c
$(obj)/raid6int8.c: UNROLL := 8
-$(obj)/raid6int8.c: $(src)/raid6int.uc $(src)/unroll.pl FORCE
+$(obj)/raid6int8.c: $(src)/raid6int.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
targets += raid6int16.c
$(obj)/raid6int16.c: UNROLL := 16
-$(obj)/raid6int16.c: $(src)/raid6int.uc $(src)/unroll.pl FORCE
+$(obj)/raid6int16.c: $(src)/raid6int.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
targets += raid6int32.c
$(obj)/raid6int32.c: UNROLL := 32
-$(obj)/raid6int32.c: $(src)/raid6int.uc $(src)/unroll.pl FORCE
+$(obj)/raid6int32.c: $(src)/raid6int.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
CFLAGS_raid6altivec1.o += $(altivec_flags)
targets += raid6altivec1.c
$(obj)/raid6altivec1.c: UNROLL := 1
-$(obj)/raid6altivec1.c: $(src)/raid6altivec.uc $(src)/unroll.pl FORCE
+$(obj)/raid6altivec1.c: $(src)/raid6altivec.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
CFLAGS_raid6altivec2.o += $(altivec_flags)
targets += raid6altivec2.c
$(obj)/raid6altivec2.c: UNROLL := 2
-$(obj)/raid6altivec2.c: $(src)/raid6altivec.uc $(src)/unroll.pl FORCE
+$(obj)/raid6altivec2.c: $(src)/raid6altivec.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
CFLAGS_raid6altivec4.o += $(altivec_flags)
targets += raid6altivec4.c
$(obj)/raid6altivec4.c: UNROLL := 4
-$(obj)/raid6altivec4.c: $(src)/raid6altivec.uc $(src)/unroll.pl FORCE
+$(obj)/raid6altivec4.c: $(src)/raid6altivec.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
CFLAGS_raid6altivec8.o += $(altivec_flags)
targets += raid6altivec8.c
$(obj)/raid6altivec8.c: UNROLL := 8
-$(obj)/raid6altivec8.c: $(src)/raid6altivec.uc $(src)/unroll.pl FORCE
+$(obj)/raid6altivec8.c: $(src)/raid6altivec.uc $(src)/unroll.awk FORCE
$(call if_changed,unroll)
quiet_cmd_mktable = TABLE $@
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 6986b0059d23..60e2b322db11 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -1624,10 +1624,11 @@ int bitmap_create(mddev_t *mddev)
bitmap->offset = mddev->bitmap_offset;
if (file) {
get_file(file);
- do_sync_mapping_range(file->f_mapping, 0, LLONG_MAX,
- SYNC_FILE_RANGE_WAIT_BEFORE |
- SYNC_FILE_RANGE_WRITE |
- SYNC_FILE_RANGE_WAIT_AFTER);
+ /* As future accesses to this file will use bmap,
+ * and bypass the page cache, we must sync the file
+ * first.
+ */
+ vfs_fsync(file, file->f_dentry, 1);
}
/* read superblock from bitmap file (this sets bitmap->chunksize) */
err = bitmap_read_sb(bitmap);
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index ed1038164019..e412980763bd 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -988,7 +988,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad_cipher;
}
- /* Compatiblity mode for old dm-crypt cipher strings */
+ /* Compatibility mode for old dm-crypt cipher strings */
if (!chainmode || (strcmp(chainmode, "plain") == 0 && !ivmode)) {
chainmode = "cbc";
ivmode = "plain";
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index 556acff3952f..2b7907b6dd09 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -138,16 +138,6 @@ int dm_exception_store_type_unregister(struct dm_exception_store_type *type)
}
EXPORT_SYMBOL(dm_exception_store_type_unregister);
-/*
- * Round a number up to the nearest 'size' boundary. size must
- * be a power of 2.
- */
-static ulong round_up(ulong n, ulong size)
-{
- size--;
- return (n + size) & ~size;
-}
-
static int set_chunk_size(struct dm_exception_store *store,
const char *chunk_size_arg, char **error)
{
@@ -155,7 +145,8 @@ static int set_chunk_size(struct dm_exception_store *store,
char *value;
chunk_size_ulong = simple_strtoul(chunk_size_arg, &value, 10);
- if (*chunk_size_arg == '\0' || *value != '\0') {
+ if (*chunk_size_arg == '\0' || *value != '\0' ||
+ chunk_size_ulong > UINT_MAX) {
*error = "Invalid chunk size";
return -EINVAL;
}
@@ -165,45 +156,42 @@ static int set_chunk_size(struct dm_exception_store *store,
return 0;
}
- /*
- * Chunk size must be multiple of page size. Silently
- * round up if it's not.
- */
- chunk_size_ulong = round_up(chunk_size_ulong, PAGE_SIZE >> 9);
-
- return dm_exception_store_set_chunk_size(store, chunk_size_ulong,
+ return dm_exception_store_set_chunk_size(store,
+ (unsigned) chunk_size_ulong,
error);
}
int dm_exception_store_set_chunk_size(struct dm_exception_store *store,
- unsigned long chunk_size_ulong,
+ unsigned chunk_size,
char **error)
{
/* Check chunk_size is a power of 2 */
- if (!is_power_of_2(chunk_size_ulong)) {
+ if (!is_power_of_2(chunk_size)) {
*error = "Chunk size is not a power of 2";
return -EINVAL;
}
/* Validate the chunk size against the device block size */
- if (chunk_size_ulong % (bdev_logical_block_size(store->cow->bdev) >> 9)) {
+ if (chunk_size %
+ (bdev_logical_block_size(dm_snap_cow(store->snap)->bdev) >> 9)) {
*error = "Chunk size is not a multiple of device blocksize";
return -EINVAL;
}
- if (chunk_size_ulong > INT_MAX >> SECTOR_SHIFT) {
+ if (chunk_size > INT_MAX >> SECTOR_SHIFT) {
*error = "Chunk size is too high";
return -EINVAL;
}
- store->chunk_size = chunk_size_ulong;
- store->chunk_mask = chunk_size_ulong - 1;
- store->chunk_shift = ffs(chunk_size_ulong) - 1;
+ store->chunk_size = chunk_size;
+ store->chunk_mask = chunk_size - 1;
+ store->chunk_shift = ffs(chunk_size) - 1;
return 0;
}
int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
+ struct dm_snapshot *snap,
unsigned *args_used,
struct dm_exception_store **store)
{
@@ -212,7 +200,7 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
struct dm_exception_store *tmp_store;
char persistent;
- if (argc < 3) {
+ if (argc < 2) {
ti->error = "Insufficient exception store arguments";
return -EINVAL;
}
@@ -223,14 +211,15 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
return -ENOMEM;
}
- persistent = toupper(*argv[1]);
+ persistent = toupper(*argv[0]);
if (persistent == 'P')
type = get_type("P");
else if (persistent == 'N')
type = get_type("N");
else {
ti->error = "Persistent flag is not P or N";
- return -EINVAL;
+ r = -EINVAL;
+ goto bad_type;
}
if (!type) {
@@ -240,32 +229,23 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
}
tmp_store->type = type;
- tmp_store->ti = ti;
-
- r = dm_get_device(ti, argv[0], 0, 0,
- FMODE_READ | FMODE_WRITE, &tmp_store->cow);
- if (r) {
- ti->error = "Cannot get COW device";
- goto bad_cow;
- }
+ tmp_store->snap = snap;
- r = set_chunk_size(tmp_store, argv[2], &ti->error);
+ r = set_chunk_size(tmp_store, argv[1], &ti->error);
if (r)
- goto bad_cow;
+ goto bad;
r = type->ctr(tmp_store, 0, NULL);
if (r) {
ti->error = "Exception store type constructor failed";
- goto bad_ctr;
+ goto bad;
}
- *args_used = 3;
+ *args_used = 2;
*store = tmp_store;
return 0;
-bad_ctr:
- dm_put_device(ti, tmp_store->cow);
-bad_cow:
+bad:
put_type(type);
bad_type:
kfree(tmp_store);
@@ -276,7 +256,6 @@ EXPORT_SYMBOL(dm_exception_store_create);
void dm_exception_store_destroy(struct dm_exception_store *store)
{
store->type->dtr(store);
- dm_put_device(store->ti, store->cow);
put_type(store->type);
kfree(store);
}
diff --git a/drivers/md/dm-exception-store.h b/drivers/md/dm-exception-store.h
index 812c71872ba0..bb8874653de1 100644
--- a/drivers/md/dm-exception-store.h
+++ b/drivers/md/dm-exception-store.h
@@ -26,7 +26,7 @@ typedef sector_t chunk_t;
* of chunks that follow contiguously. Remaining bits hold the number of the
* chunk within the device.
*/
-struct dm_snap_exception {
+struct dm_exception {
struct list_head hash_list;
chunk_t old_chunk;
@@ -64,13 +64,13 @@ struct dm_exception_store_type {
* Find somewhere to store the next exception.
*/
int (*prepare_exception) (struct dm_exception_store *store,
- struct dm_snap_exception *e);
+ struct dm_exception *e);
/*
* Update the metadata with this exception.
*/
void (*commit_exception) (struct dm_exception_store *store,
- struct dm_snap_exception *e,
+ struct dm_exception *e,
void (*callback) (void *, int success),
void *callback_context);
@@ -86,29 +86,34 @@ struct dm_exception_store_type {
/*
* Return how full the snapshot is.
*/
- void (*fraction_full) (struct dm_exception_store *store,
- sector_t *numerator,
- sector_t *denominator);
+ void (*usage) (struct dm_exception_store *store,
+ sector_t *total_sectors, sector_t *sectors_allocated,
+ sector_t *metadata_sectors);
/* For internal device-mapper use only. */
struct list_head list;
};
+struct dm_snapshot;
+
struct dm_exception_store {
struct dm_exception_store_type *type;
- struct dm_target *ti;
-
- struct dm_dev *cow;
+ struct dm_snapshot *snap;
/* Size of data blocks saved - must be a power of 2 */
- chunk_t chunk_size;
- chunk_t chunk_mask;
- chunk_t chunk_shift;
+ unsigned chunk_size;
+ unsigned chunk_mask;
+ unsigned chunk_shift;
void *context;
};
/*
+ * Obtain the cow device used by a given snapshot.
+ */
+struct dm_dev *dm_snap_cow(struct dm_snapshot *snap);
+
+/*
* Funtions to manipulate consecutive chunks
*/
# if defined(CONFIG_LBDAF) || (BITS_PER_LONG == 64)
@@ -120,12 +125,12 @@ static inline chunk_t dm_chunk_number(chunk_t chunk)
return chunk & (chunk_t)((1ULL << DM_CHUNK_NUMBER_BITS) - 1ULL);
}
-static inline unsigned dm_consecutive_chunk_count(struct dm_snap_exception *e)
+static inline unsigned dm_consecutive_chunk_count(struct dm_exception *e)
{
return e->new_chunk >> DM_CHUNK_NUMBER_BITS;
}
-static inline void dm_consecutive_chunk_count_inc(struct dm_snap_exception *e)
+static inline void dm_consecutive_chunk_count_inc(struct dm_exception *e)
{
e->new_chunk += (1ULL << DM_CHUNK_NUMBER_BITS);
@@ -140,12 +145,12 @@ static inline chunk_t dm_chunk_number(chunk_t chunk)
return chunk;
}
-static inline unsigned dm_consecutive_chunk_count(struct dm_snap_exception *e)
+static inline unsigned dm_consecutive_chunk_count(struct dm_exception *e)
{
return 0;
}
-static inline void dm_consecutive_chunk_count_inc(struct dm_snap_exception *e)
+static inline void dm_consecutive_chunk_count_inc(struct dm_exception *e)
{
}
@@ -162,17 +167,18 @@ static inline sector_t get_dev_size(struct block_device *bdev)
static inline chunk_t sector_to_chunk(struct dm_exception_store *store,
sector_t sector)
{
- return (sector & ~store->chunk_mask) >> store->chunk_shift;
+ return sector >> store->chunk_shift;
}
int dm_exception_store_type_register(struct dm_exception_store_type *type);
int dm_exception_store_type_unregister(struct dm_exception_store_type *type);
int dm_exception_store_set_chunk_size(struct dm_exception_store *store,
- unsigned long chunk_size_ulong,
+ unsigned chunk_size,
char **error);
int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
+ struct dm_snapshot *snap,
unsigned *args_used,
struct dm_exception_store **store);
void dm_exception_store_destroy(struct dm_exception_store *store);
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index a67942931582..1292c3e877b5 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -634,9 +634,9 @@ static struct mapped_device *find_device(struct dm_ioctl *param)
* Sneakily write in both the name and the uuid
* while we have the cell.
*/
- strncpy(param->name, hc->name, sizeof(param->name));
+ strlcpy(param->name, hc->name, sizeof(param->name));
if (hc->uuid)
- strncpy(param->uuid, hc->uuid, sizeof(param->uuid)-1);
+ strlcpy(param->uuid, hc->uuid, sizeof(param->uuid));
else
param->uuid[0] = '\0';
diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c
index 652bd33109e3..7ac2c1450d10 100644
--- a/drivers/md/dm-log-userspace-base.c
+++ b/drivers/md/dm-log-userspace-base.c
@@ -156,7 +156,7 @@ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti,
}
/* The ptr value is sufficient for local unique id */
- lc->luid = (uint64_t)lc;
+ lc->luid = (unsigned long)lc;
lc->ti = ti;
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c
index d5b2e08750d5..157999ebd236 100644
--- a/drivers/md/dm-snap-persistent.c
+++ b/drivers/md/dm-snap-persistent.c
@@ -214,7 +214,7 @@ static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int rw,
int metadata)
{
struct dm_io_region where = {
- .bdev = ps->store->cow->bdev,
+ .bdev = dm_snap_cow(ps->store->snap)->bdev,
.sector = ps->store->chunk_size * chunk,
.count = ps->store->chunk_size,
};
@@ -284,16 +284,18 @@ static int read_header(struct pstore *ps, int *new_snapshot)
{
int r;
struct disk_header *dh;
- chunk_t chunk_size;
+ unsigned chunk_size;
int chunk_size_supplied = 1;
char *chunk_err;
/*
- * Use default chunk size (or hardsect_size, if larger) if none supplied
+ * Use default chunk size (or logical_block_size, if larger)
+ * if none supplied
*/
if (!ps->store->chunk_size) {
ps->store->chunk_size = max(DM_CHUNK_SIZE_DEFAULT_SECTORS,
- bdev_logical_block_size(ps->store->cow->bdev) >> 9);
+ bdev_logical_block_size(dm_snap_cow(ps->store->snap)->
+ bdev) >> 9);
ps->store->chunk_mask = ps->store->chunk_size - 1;
ps->store->chunk_shift = ffs(ps->store->chunk_size) - 1;
chunk_size_supplied = 0;
@@ -334,10 +336,9 @@ static int read_header(struct pstore *ps, int *new_snapshot)
return 0;
if (chunk_size_supplied)
- DMWARN("chunk size %llu in device metadata overrides "
- "table chunk size of %llu.",
- (unsigned long long)chunk_size,
- (unsigned long long)ps->store->chunk_size);
+ DMWARN("chunk size %u in device metadata overrides "
+ "table chunk size of %u.",
+ chunk_size, ps->store->chunk_size);
/* We had a bogus chunk_size. Fix stuff up. */
free_area(ps);
@@ -345,8 +346,8 @@ static int read_header(struct pstore *ps, int *new_snapshot)
r = dm_exception_store_set_chunk_size(ps->store, chunk_size,
&chunk_err);
if (r) {
- DMERR("invalid on-disk chunk size %llu: %s.",
- (unsigned long long)chunk_size, chunk_err);
+ DMERR("invalid on-disk chunk size %u: %s.",
+ chunk_size, chunk_err);
return r;
}
@@ -489,11 +490,22 @@ static struct pstore *get_info(struct dm_exception_store *store)
return (struct pstore *) store->context;
}
-static void persistent_fraction_full(struct dm_exception_store *store,
- sector_t *numerator, sector_t *denominator)
+static void persistent_usage(struct dm_exception_store *store,
+ sector_t *total_sectors,
+ sector_t *sectors_allocated,
+ sector_t *metadata_sectors)
{
- *numerator = get_info(store)->next_free * store->chunk_size;
- *denominator = get_dev_size(store->cow->bdev);
+ struct pstore *ps = get_info(store);
+
+ *sectors_allocated = ps->next_free * store->chunk_size;
+ *total_sectors = get_dev_size(dm_snap_cow(store->snap)->bdev);
+
+ /*
+ * First chunk is the fixed header.
+ * Then there are (ps->current_area + 1) metadata chunks, each one
+ * separated from the next by ps->exceptions_per_area data chunks.
+ */
+ *metadata_sectors = (ps->current_area + 2) * store->chunk_size;
}
static void persistent_dtr(struct dm_exception_store *store)
@@ -552,44 +564,40 @@ static int persistent_read_metadata(struct dm_exception_store *store,
ps->current_area = 0;
zero_memory_area(ps);
r = zero_disk_area(ps, 0);
- if (r) {
+ if (r)
DMWARN("zero_disk_area(0) failed");
- return r;
- }
- } else {
- /*
- * Sanity checks.
- */
- if (ps->version != SNAPSHOT_DISK_VERSION) {
- DMWARN("unable to handle snapshot disk version %d",
- ps->version);
- return -EINVAL;
- }
+ return r;
+ }
+ /*
+ * Sanity checks.
+ */
+ if (ps->version != SNAPSHOT_DISK_VERSION) {
+ DMWARN("unable to handle snapshot disk version %d",
+ ps->version);
+ return -EINVAL;
+ }
- /*
- * Metadata are valid, but snapshot is invalidated
- */
- if (!ps->valid)
- return 1;
+ /*
+ * Metadata are valid, but snapshot is invalidated
+ */
+ if (!ps->valid)
+ return 1;
- /*
- * Read the metadata.
- */
- r = read_exceptions(ps, callback, callback_context);
- if (r)
- return r;
- }
+ /*
+ * Read the metadata.
+ */
+ r = read_exceptions(ps, callback, callback_context);
- return 0;
+ return r;
}
static int persistent_prepare_exception(struct dm_exception_store *store,
- struct dm_snap_exception *e)
+ struct dm_exception *e)
{
struct pstore *ps = get_info(store);
uint32_t stride;
chunk_t next_free;
- sector_t size = get_dev_size(store->cow->bdev);
+ sector_t size = get_dev_size(dm_snap_cow(store->snap)->bdev);
/* Is there enough room ? */
if (size < ((ps->next_free + 1) * store->chunk_size))
@@ -611,7 +619,7 @@ static int persistent_prepare_exception(struct dm_exception_store *store,
}
static void persistent_commit_exception(struct dm_exception_store *store,
- struct dm_snap_exception *e,
+ struct dm_exception *e,
void (*callback) (void *, int success),
void *callback_context)
{
@@ -726,8 +734,7 @@ static unsigned persistent_status(struct dm_exception_store *store,
case STATUSTYPE_INFO:
break;
case STATUSTYPE_TABLE:
- DMEMIT(" %s P %llu", store->cow->name,
- (unsigned long long)store->chunk_size);
+ DMEMIT(" P %llu", (unsigned long long)store->chunk_size);
}
return sz;
@@ -742,7 +749,7 @@ static struct dm_exception_store_type _persistent_type = {
.prepare_exception = persistent_prepare_exception,
.commit_exception = persistent_commit_exception,
.drop_snapshot = persistent_drop_snapshot,
- .fraction_full = persistent_fraction_full,
+ .usage = persistent_usage,
.status = persistent_status,
};
@@ -755,7 +762,7 @@ static struct dm_exception_store_type _persistent_compat_type = {
.prepare_exception = persistent_prepare_exception,
.commit_exception = persistent_commit_exception,
.drop_snapshot = persistent_drop_snapshot,
- .fraction_full = persistent_fraction_full,
+ .usage = persistent_usage,
.status = persistent_status,
};
diff --git a/drivers/md/dm-snap-transient.c b/drivers/md/dm-snap-transient.c
index cde5aa558e6d..a0898a66a2f8 100644
--- a/drivers/md/dm-snap-transient.c
+++ b/drivers/md/dm-snap-transient.c
@@ -36,10 +36,10 @@ static int transient_read_metadata(struct dm_exception_store *store,
}
static int transient_prepare_exception(struct dm_exception_store *store,
- struct dm_snap_exception *e)
+ struct dm_exception *e)
{
struct transient_c *tc = store->context;
- sector_t size = get_dev_size(store->cow->bdev);
+ sector_t size = get_dev_size(dm_snap_cow(store->snap)->bdev);
if (size < (tc->next_free + store->chunk_size))
return -1;
@@ -51,7 +51,7 @@ static int transient_prepare_exception(struct dm_exception_store *store,
}
static void transient_commit_exception(struct dm_exception_store *store,
- struct dm_snap_exception *e,
+ struct dm_exception *e,
void (*callback) (void *, int success),
void *callback_context)
{
@@ -59,11 +59,14 @@ static void transient_commit_exception(struct dm_exception_store *store,
callback(callback_context, 1);
}
-static void transient_fraction_full(struct dm_exception_store *store,
- sector_t *numerator, sector_t *denominator)
+static void transient_usage(struct dm_exception_store *store,
+ sector_t *total_sectors,
+ sector_t *sectors_allocated,
+ sector_t *metadata_sectors)
{
- *numerator = ((struct transient_c *) store->context)->next_free;
- *denominator = get_dev_size(store->cow->bdev);
+ *sectors_allocated = ((struct transient_c *) store->context)->next_free;
+ *total_sectors = get_dev_size(dm_snap_cow(store->snap)->bdev);
+ *metadata_sectors = 0;
}
static int transient_ctr(struct dm_exception_store *store,
@@ -91,8 +94,7 @@ static unsigned transient_status(struct dm_exception_store *store,
case STATUSTYPE_INFO:
break;
case STATUSTYPE_TABLE:
- DMEMIT(" %s N %llu", store->cow->name,
- (unsigned long long)store->chunk_size);
+ DMEMIT(" N %llu", (unsigned long long)store->chunk_size);
}
return sz;
@@ -106,7 +108,7 @@ static struct dm_exception_store_type _transient_type = {
.read_metadata = transient_read_metadata,
.prepare_exception = transient_prepare_exception,
.commit_exception = transient_commit_exception,
- .fraction_full = transient_fraction_full,
+ .usage = transient_usage,
.status = transient_status,
};
@@ -118,7 +120,7 @@ static struct dm_exception_store_type _transient_compat_type = {
.read_metadata = transient_read_metadata,
.prepare_exception = transient_prepare_exception,
.commit_exception = transient_commit_exception,
- .fraction_full = transient_fraction_full,
+ .usage = transient_usage,
.status = transient_status,
};
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 57f1bf7f3b7a..9e660ce05c26 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -49,7 +49,7 @@
#define DM_TRACKED_CHUNK_HASH(x) ((unsigned long)(x) & \
(DM_TRACKED_CHUNK_HASH_SIZE - 1))
-struct exception_table {
+struct dm_exception_table {
uint32_t hash_mask;
unsigned hash_shift;
struct list_head *table;
@@ -59,6 +59,9 @@ struct dm_snapshot {
struct rw_semaphore lock;
struct dm_dev *origin;
+ struct dm_dev *cow;
+
+ struct dm_target *ti;
/* List of snapshots per Origin */
struct list_head list;
@@ -73,8 +76,8 @@ struct dm_snapshot {
atomic_t pending_exceptions_count;
- struct exception_table pending;
- struct exception_table complete;
+ struct dm_exception_table pending;
+ struct dm_exception_table complete;
/*
* pe_lock protects all pending_exception operations and access
@@ -97,6 +100,12 @@ struct dm_snapshot {
struct hlist_head tracked_chunk_hash[DM_TRACKED_CHUNK_HASH_SIZE];
};
+struct dm_dev *dm_snap_cow(struct dm_snapshot *s)
+{
+ return s->cow;
+}
+EXPORT_SYMBOL(dm_snap_cow);
+
static struct workqueue_struct *ksnapd;
static void flush_queued_bios(struct work_struct *work);
@@ -116,7 +125,7 @@ static int bdev_equal(struct block_device *lhs, struct block_device *rhs)
}
struct dm_snap_pending_exception {
- struct dm_snap_exception e;
+ struct dm_exception e;
/*
* Origin buffers waiting for this to complete are held
@@ -296,6 +305,7 @@ static void __insert_origin(struct origin *o)
*/
static int register_snapshot(struct dm_snapshot *snap)
{
+ struct dm_snapshot *l;
struct origin *o, *new_o;
struct block_device *bdev = snap->origin->bdev;
@@ -319,7 +329,11 @@ static int register_snapshot(struct dm_snapshot *snap)
__insert_origin(o);
}
- list_add_tail(&snap->list, &o->snapshots);
+ /* Sort the list according to chunk size, largest-first smallest-last */
+ list_for_each_entry(l, &o->snapshots, list)
+ if (l->store->chunk_size < snap->store->chunk_size)
+ break;
+ list_add_tail(&snap->list, &l->list);
up_write(&_origins_lock);
return 0;
@@ -346,8 +360,8 @@ static void unregister_snapshot(struct dm_snapshot *s)
* The lowest hash_shift bits of the chunk number are ignored, allowing
* some consecutive chunks to be grouped together.
*/
-static int init_exception_table(struct exception_table *et, uint32_t size,
- unsigned hash_shift)
+static int dm_exception_table_init(struct dm_exception_table *et,
+ uint32_t size, unsigned hash_shift)
{
unsigned int i;
@@ -363,10 +377,11 @@ static int init_exception_table(struct exception_table *et, uint32_t size,
return 0;
}
-static void exit_exception_table(struct exception_table *et, struct kmem_cache *mem)
+static void dm_exception_table_exit(struct dm_exception_table *et,
+ struct kmem_cache *mem)
{
struct list_head *slot;
- struct dm_snap_exception *ex, *next;
+ struct dm_exception *ex, *next;
int i, size;
size = et->hash_mask + 1;
@@ -380,19 +395,12 @@ static void exit_exception_table(struct exception_table *et, struct kmem_cache *
vfree(et->table);
}
-static uint32_t exception_hash(struct exception_table *et, chunk_t chunk)
+static uint32_t exception_hash(struct dm_exception_table *et, chunk_t chunk)
{
return (chunk >> et->hash_shift) & et->hash_mask;
}
-static void insert_exception(struct exception_table *eh,
- struct dm_snap_exception *e)
-{
- struct list_head *l = &eh->table[exception_hash(eh, e->old_chunk)];
- list_add(&e->hash_list, l);
-}
-
-static void remove_exception(struct dm_snap_exception *e)
+static void dm_remove_exception(struct dm_exception *e)
{
list_del(&e->hash_list);
}
@@ -401,11 +409,11 @@ static void remove_exception(struct dm_snap_exception *e)
* Return the exception data for a sector, or NULL if not
* remapped.
*/
-static struct dm_snap_exception *lookup_exception(struct exception_table *et,
- chunk_t chunk)
+static struct dm_exception *dm_lookup_exception(struct dm_exception_table *et,
+ chunk_t chunk)
{
struct list_head *slot;
- struct dm_snap_exception *e;
+ struct dm_exception *e;
slot = &et->table[exception_hash(et, chunk)];
list_for_each_entry (e, slot, hash_list)
@@ -416,9 +424,9 @@ static struct dm_snap_exception *lookup_exception(struct exception_table *et,
return NULL;
}
-static struct dm_snap_exception *alloc_exception(void)
+static struct dm_exception *alloc_completed_exception(void)
{
- struct dm_snap_exception *e;
+ struct dm_exception *e;
e = kmem_cache_alloc(exception_cache, GFP_NOIO);
if (!e)
@@ -427,7 +435,7 @@ static struct dm_snap_exception *alloc_exception(void)
return e;
}
-static void free_exception(struct dm_snap_exception *e)
+static void free_completed_exception(struct dm_exception *e)
{
kmem_cache_free(exception_cache, e);
}
@@ -452,12 +460,11 @@ static void free_pending_exception(struct dm_snap_pending_exception *pe)
atomic_dec(&s->pending_exceptions_count);
}
-static void insert_completed_exception(struct dm_snapshot *s,
- struct dm_snap_exception *new_e)
+static void dm_insert_exception(struct dm_exception_table *eh,
+ struct dm_exception *new_e)
{
- struct exception_table *eh = &s->complete;
struct list_head *l;
- struct dm_snap_exception *e = NULL;
+ struct dm_exception *e = NULL;
l = &eh->table[exception_hash(eh, new_e->old_chunk)];
@@ -473,7 +480,7 @@ static void insert_completed_exception(struct dm_snapshot *s,
new_e->new_chunk == (dm_chunk_number(e->new_chunk) +
dm_consecutive_chunk_count(e) + 1)) {
dm_consecutive_chunk_count_inc(e);
- free_exception(new_e);
+ free_completed_exception(new_e);
return;
}
@@ -483,7 +490,7 @@ static void insert_completed_exception(struct dm_snapshot *s,
dm_consecutive_chunk_count_inc(e);
e->old_chunk--;
e->new_chunk--;
- free_exception(new_e);
+ free_completed_exception(new_e);
return;
}
@@ -502,9 +509,9 @@ out:
static int dm_add_exception(void *context, chunk_t old, chunk_t new)
{
struct dm_snapshot *s = context;
- struct dm_snap_exception *e;
+ struct dm_exception *e;
- e = alloc_exception();
+ e = alloc_completed_exception();
if (!e)
return -ENOMEM;
@@ -513,11 +520,30 @@ static int dm_add_exception(void *context, chunk_t old, chunk_t new)
/* Consecutive_count is implicitly initialised to zero */
e->new_chunk = new;
- insert_completed_exception(s, e);
+ dm_insert_exception(&s->complete, e);
return 0;
}
+#define min_not_zero(l, r) (((l) == 0) ? (r) : (((r) == 0) ? (l) : min(l, r)))
+
+/*
+ * Return a minimum chunk size of all snapshots that have the specified origin.
+ * Return zero if the origin has no snapshots.
+ */
+static sector_t __minimum_chunk_size(struct origin *o)
+{
+ struct dm_snapshot *snap;
+ unsigned chunk_size = 0;
+
+ if (o)
+ list_for_each_entry(snap, &o->snapshots, list)
+ chunk_size = min_not_zero(chunk_size,
+ snap->store->chunk_size);
+
+ return chunk_size;
+}
+
/*
* Hard coded magic.
*/
@@ -541,7 +567,7 @@ static int init_hash_tables(struct dm_snapshot *s)
* Calculate based on the size of the original volume or
* the COW volume...
*/
- cow_dev_size = get_dev_size(s->store->cow->bdev);
+ cow_dev_size = get_dev_size(s->cow->bdev);
origin_dev_size = get_dev_size(s->origin->bdev);
max_buckets = calc_max_buckets();
@@ -549,8 +575,8 @@ static int init_hash_tables(struct dm_snapshot *s)
hash_size = min(hash_size, max_buckets);
hash_size = rounddown_pow_of_two(hash_size);
- if (init_exception_table(&s->complete, hash_size,
- DM_CHUNK_CONSECUTIVE_BITS))
+ if (dm_exception_table_init(&s->complete, hash_size,
+ DM_CHUNK_CONSECUTIVE_BITS))
return -ENOMEM;
/*
@@ -561,8 +587,8 @@ static int init_hash_tables(struct dm_snapshot *s)
if (hash_size < 64)
hash_size = 64;
- if (init_exception_table(&s->pending, hash_size, 0)) {
- exit_exception_table(&s->complete, exception_cache);
+ if (dm_exception_table_init(&s->pending, hash_size, 0)) {
+ dm_exception_table_exit(&s->complete, exception_cache);
return -ENOMEM;
}
@@ -577,45 +603,55 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
struct dm_snapshot *s;
int i;
int r = -EINVAL;
- char *origin_path;
- struct dm_exception_store *store;
+ char *origin_path, *cow_path;
unsigned args_used;
if (argc != 4) {
ti->error = "requires exactly 4 arguments";
r = -EINVAL;
- goto bad_args;
+ goto bad;
}
origin_path = argv[0];
argv++;
argc--;
- r = dm_exception_store_create(ti, argc, argv, &args_used, &store);
+ s = kmalloc(sizeof(*s), GFP_KERNEL);
+ if (!s) {
+ ti->error = "Cannot allocate snapshot context private "
+ "structure";
+ r = -ENOMEM;
+ goto bad;
+ }
+
+ cow_path = argv[0];
+ argv++;
+ argc--;
+
+ r = dm_get_device(ti, cow_path, 0, 0,
+ FMODE_READ | FMODE_WRITE, &s->cow);
+ if (r) {
+ ti->error = "Cannot get COW device";
+ goto bad_cow;
+ }
+
+ r = dm_exception_store_create(ti, argc, argv, s, &args_used, &s->store);
if (r) {
ti->error = "Couldn't create exception store";
r = -EINVAL;
- goto bad_args;
+ goto bad_store;
}
argv += args_used;
argc -= args_used;
- s = kmalloc(sizeof(*s), GFP_KERNEL);
- if (!s) {
- ti->error = "Cannot allocate snapshot context private "
- "structure";
- r = -ENOMEM;
- goto bad_snap;
- }
-
r = dm_get_device(ti, origin_path, 0, ti->len, FMODE_READ, &s->origin);
if (r) {
ti->error = "Cannot get origin device";
goto bad_origin;
}
- s->store = store;
+ s->ti = ti;
s->valid = 1;
s->active = 0;
atomic_set(&s->pending_exceptions_count, 0);
@@ -668,6 +704,11 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
bio_list_init(&s->queued_bios);
INIT_WORK(&s->queued_bios_work, flush_queued_bios);
+ if (!s->store->chunk_size) {
+ ti->error = "Chunk size not set";
+ goto bad_load_and_register;
+ }
+
/* Add snapshot to the list of snapshots for this origin */
/* Exceptions aren't triggered till snapshot_resume() is called */
if (register_snapshot(s)) {
@@ -692,19 +733,22 @@ bad_pending_pool:
dm_kcopyd_client_destroy(s->kcopyd_client);
bad_kcopyd:
- exit_exception_table(&s->pending, pending_cache);
- exit_exception_table(&s->complete, exception_cache);
+ dm_exception_table_exit(&s->pending, pending_cache);
+ dm_exception_table_exit(&s->complete, exception_cache);
bad_hash_tables:
dm_put_device(ti, s->origin);
bad_origin:
- kfree(s);
+ dm_exception_store_destroy(s->store);
-bad_snap:
- dm_exception_store_destroy(store);
+bad_store:
+ dm_put_device(ti, s->cow);
+
+bad_cow:
+ kfree(s);
-bad_args:
+bad:
return r;
}
@@ -713,8 +757,8 @@ static void __free_exceptions(struct dm_snapshot *s)
dm_kcopyd_client_destroy(s->kcopyd_client);
s->kcopyd_client = NULL;
- exit_exception_table(&s->pending, pending_cache);
- exit_exception_table(&s->complete, exception_cache);
+ dm_exception_table_exit(&s->pending, pending_cache);
+ dm_exception_table_exit(&s->complete, exception_cache);
}
static void snapshot_dtr(struct dm_target *ti)
@@ -753,6 +797,8 @@ static void snapshot_dtr(struct dm_target *ti)
dm_exception_store_destroy(s->store);
+ dm_put_device(ti, s->cow);
+
kfree(s);
}
@@ -815,7 +861,7 @@ static void __invalidate_snapshot(struct dm_snapshot *s, int err)
s->valid = 0;
- dm_table_event(s->store->ti->table);
+ dm_table_event(s->ti->table);
}
static void get_pending_exception(struct dm_snap_pending_exception *pe)
@@ -853,7 +899,7 @@ static struct bio *put_pending_exception(struct dm_snap_pending_exception *pe)
static void pending_complete(struct dm_snap_pending_exception *pe, int success)
{
- struct dm_snap_exception *e;
+ struct dm_exception *e;
struct dm_snapshot *s = pe->snap;
struct bio *origin_bios = NULL;
struct bio *snapshot_bios = NULL;
@@ -867,7 +913,7 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success)
goto out;
}
- e = alloc_exception();
+ e = alloc_completed_exception();
if (!e) {
down_write(&s->lock);
__invalidate_snapshot(s, -ENOMEM);
@@ -878,7 +924,7 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success)
down_write(&s->lock);
if (!s->valid) {
- free_exception(e);
+ free_completed_exception(e);
error = 1;
goto out;
}
@@ -894,10 +940,10 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success)
* Add a proper exception, and remove the
* in-flight exception from the list.
*/
- insert_completed_exception(s, e);
+ dm_insert_exception(&s->complete, e);
out:
- remove_exception(&pe->e);
+ dm_remove_exception(&pe->e);
snapshot_bios = bio_list_get(&pe->snapshot_bios);
origin_bios = put_pending_exception(pe);
@@ -951,9 +997,9 @@ static void start_copy(struct dm_snap_pending_exception *pe)
src.bdev = bdev;
src.sector = chunk_to_sector(s->store, pe->e.old_chunk);
- src.count = min(s->store->chunk_size, dev_size - src.sector);
+ src.count = min((sector_t)s->store->chunk_size, dev_size - src.sector);
- dest.bdev = s->store->cow->bdev;
+ dest.bdev = s->cow->bdev;
dest.sector = chunk_to_sector(s->store, pe->e.new_chunk);
dest.count = src.count;
@@ -965,7 +1011,7 @@ static void start_copy(struct dm_snap_pending_exception *pe)
static struct dm_snap_pending_exception *
__lookup_pending_exception(struct dm_snapshot *s, chunk_t chunk)
{
- struct dm_snap_exception *e = lookup_exception(&s->pending, chunk);
+ struct dm_exception *e = dm_lookup_exception(&s->pending, chunk);
if (!e)
return NULL;
@@ -1006,15 +1052,15 @@ __find_pending_exception(struct dm_snapshot *s,
}
get_pending_exception(pe);
- insert_exception(&s->pending, &pe->e);
+ dm_insert_exception(&s->pending, &pe->e);
return pe;
}
-static void remap_exception(struct dm_snapshot *s, struct dm_snap_exception *e,
+static void remap_exception(struct dm_snapshot *s, struct dm_exception *e,
struct bio *bio, chunk_t chunk)
{
- bio->bi_bdev = s->store->cow->bdev;
+ bio->bi_bdev = s->cow->bdev;
bio->bi_sector = chunk_to_sector(s->store,
dm_chunk_number(e->new_chunk) +
(chunk - e->old_chunk)) +
@@ -1025,14 +1071,14 @@ static void remap_exception(struct dm_snapshot *s, struct dm_snap_exception *e,
static int snapshot_map(struct dm_target *ti, struct bio *bio,
union map_info *map_context)
{
- struct dm_snap_exception *e;
+ struct dm_exception *e;
struct dm_snapshot *s = ti->private;
int r = DM_MAPIO_REMAPPED;
chunk_t chunk;
struct dm_snap_pending_exception *pe = NULL;
if (unlikely(bio_empty_barrier(bio))) {
- bio->bi_bdev = s->store->cow->bdev;
+ bio->bi_bdev = s->cow->bdev;
return DM_MAPIO_REMAPPED;
}
@@ -1053,7 +1099,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
}
/* If the block is already remapped - use that, else remap it */
- e = lookup_exception(&s->complete, chunk);
+ e = dm_lookup_exception(&s->complete, chunk);
if (e) {
remap_exception(s, e, bio, chunk);
goto out_unlock;
@@ -1077,7 +1123,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
goto out_unlock;
}
- e = lookup_exception(&s->complete, chunk);
+ e = dm_lookup_exception(&s->complete, chunk);
if (e) {
free_pending_exception(pe);
remap_exception(s, e, bio, chunk);
@@ -1142,19 +1188,24 @@ static int snapshot_status(struct dm_target *ti, status_type_t type,
unsigned sz = 0;
struct dm_snapshot *snap = ti->private;
+ down_write(&snap->lock);
+
switch (type) {
case STATUSTYPE_INFO:
if (!snap->valid)
DMEMIT("Invalid");
else {
- if (snap->store->type->fraction_full) {
- sector_t numerator, denominator;
- snap->store->type->fraction_full(snap->store,
- &numerator,
- &denominator);
- DMEMIT("%llu/%llu",
- (unsigned long long)numerator,
- (unsigned long long)denominator);
+ if (snap->store->type->usage) {
+ sector_t total_sectors, sectors_allocated,
+ metadata_sectors;
+ snap->store->type->usage(snap->store,
+ &total_sectors,
+ &sectors_allocated,
+ &metadata_sectors);
+ DMEMIT("%llu/%llu %llu",
+ (unsigned long long)sectors_allocated,
+ (unsigned long long)total_sectors,
+ (unsigned long long)metadata_sectors);
}
else
DMEMIT("Unknown");
@@ -1167,12 +1218,14 @@ static int snapshot_status(struct dm_target *ti, status_type_t type,
* to make private copies if the output is to
* make sense.
*/
- DMEMIT("%s", snap->origin->name);
+ DMEMIT("%s %s", snap->origin->name, snap->cow->name);
snap->store->type->status(snap->store, type, result + sz,
maxlen - sz);
break;
}
+ up_write(&snap->lock);
+
return 0;
}
@@ -1192,7 +1245,7 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
{
int r = DM_MAPIO_REMAPPED, first = 0;
struct dm_snapshot *snap;
- struct dm_snap_exception *e;
+ struct dm_exception *e;
struct dm_snap_pending_exception *pe, *next_pe, *primary_pe = NULL;
chunk_t chunk;
LIST_HEAD(pe_queue);
@@ -1207,7 +1260,7 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
goto next_snapshot;
/* Nothing to do if writing beyond end of snapshot */
- if (bio->bi_sector >= dm_table_get_size(snap->store->ti->table))
+ if (bio->bi_sector >= dm_table_get_size(snap->ti->table))
goto next_snapshot;
/*
@@ -1224,7 +1277,7 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
* ref_count is initialised to 1 so pending_complete()
* won't destroy the primary_pe while we're inside this loop.
*/
- e = lookup_exception(&snap->complete, chunk);
+ e = dm_lookup_exception(&snap->complete, chunk);
if (e)
goto next_snapshot;
@@ -1239,7 +1292,7 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
goto next_snapshot;
}
- e = lookup_exception(&snap->complete, chunk);
+ e = dm_lookup_exception(&snap->complete, chunk);
if (e) {
free_pending_exception(pe);
goto next_snapshot;
@@ -1377,8 +1430,6 @@ static int origin_map(struct dm_target *ti, struct bio *bio,
return (bio_rw(bio) == WRITE) ? do_origin(dev, bio) : DM_MAPIO_REMAPPED;
}
-#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r))
-
/*
* Set the target "split_io" field to the minimum of all the snapshots'
* chunk sizes.
@@ -1386,19 +1437,12 @@ static int origin_map(struct dm_target *ti, struct bio *bio,
static void origin_resume(struct dm_target *ti)
{
struct dm_dev *dev = ti->private;
- struct dm_snapshot *snap;
- struct origin *o;
- chunk_t chunk_size = 0;
down_read(&_origins_lock);
- o = __lookup_origin(dev->bdev);
- if (o)
- list_for_each_entry (snap, &o->snapshots, list)
- chunk_size = min_not_zero(chunk_size,
- snap->store->chunk_size);
- up_read(&_origins_lock);
- ti->split_io = chunk_size;
+ ti->split_io = __minimum_chunk_size(__lookup_origin(dev->bdev));
+
+ up_read(&_origins_lock);
}
static int origin_status(struct dm_target *ti, status_type_t type, char *result,
@@ -1441,7 +1485,7 @@ static struct target_type origin_target = {
static struct target_type snapshot_target = {
.name = "snapshot",
- .version = {1, 7, 0},
+ .version = {1, 8, 0},
.module = THIS_MODULE,
.ctr = snapshot_ctr,
.dtr = snapshot_dtr,
@@ -1465,7 +1509,7 @@ static int __init dm_snapshot_init(void)
r = dm_register_target(&snapshot_target);
if (r) {
DMERR("snapshot target register failed %d", r);
- return r;
+ goto bad_register_snapshot_target;
}
r = dm_register_target(&origin_target);
@@ -1480,7 +1524,7 @@ static int __init dm_snapshot_init(void)
goto bad2;
}
- exception_cache = KMEM_CACHE(dm_snap_exception, 0);
+ exception_cache = KMEM_CACHE(dm_exception, 0);
if (!exception_cache) {
DMERR("Couldn't create exception cache.");
r = -ENOMEM;
@@ -1522,6 +1566,9 @@ bad2:
dm_unregister_target(&origin_target);
bad1:
dm_unregister_target(&snapshot_target);
+
+bad_register_snapshot_target:
+ dm_exception_store_exit();
return r;
}
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 376f1ab48a24..68b66f3e4607 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -47,6 +47,7 @@ struct dm_io {
atomic_t io_count;
struct bio *bio;
unsigned long start_time;
+ spinlock_t endio_lock;
};
/*
@@ -429,9 +430,10 @@ static void free_tio(struct mapped_device *md, struct dm_target_io *tio)
mempool_free(tio, md->tio_pool);
}
-static struct dm_rq_target_io *alloc_rq_tio(struct mapped_device *md)
+static struct dm_rq_target_io *alloc_rq_tio(struct mapped_device *md,
+ gfp_t gfp_mask)
{
- return mempool_alloc(md->tio_pool, GFP_ATOMIC);
+ return mempool_alloc(md->tio_pool, gfp_mask);
}
static void free_rq_tio(struct dm_rq_target_io *tio)
@@ -449,6 +451,12 @@ static void free_bio_info(struct dm_rq_clone_bio_info *info)
mempool_free(info, info->tio->md->io_pool);
}
+static int md_in_flight(struct mapped_device *md)
+{
+ return atomic_read(&md->pending[READ]) +
+ atomic_read(&md->pending[WRITE]);
+}
+
static void start_io_acct(struct dm_io *io)
{
struct mapped_device *md = io->md;
@@ -578,8 +586,12 @@ static void dec_pending(struct dm_io *io, int error)
struct mapped_device *md = io->md;
/* Push-back supersedes any I/O errors */
- if (error && !(io->error > 0 && __noflush_suspending(md)))
- io->error = error;
+ if (unlikely(error)) {
+ spin_lock_irqsave(&io->endio_lock, flags);
+ if (!(io->error > 0 && __noflush_suspending(md)))
+ io->error = error;
+ spin_unlock_irqrestore(&io->endio_lock, flags);
+ }
if (atomic_dec_and_test(&io->io_count)) {
if (io->error == DM_ENDIO_REQUEUE) {
@@ -1226,6 +1238,7 @@ static void __split_and_process_bio(struct mapped_device *md, struct bio *bio)
atomic_set(&ci.io->io_count, 1);
ci.io->bio = bio;
ci.io->md = md;
+ spin_lock_init(&ci.io->endio_lock);
ci.sector = bio->bi_sector;
ci.sector_count = bio_sectors(bio);
if (unlikely(bio_empty_barrier(bio)))
@@ -1430,6 +1443,32 @@ static int setup_clone(struct request *clone, struct request *rq,
return 0;
}
+static struct request *clone_rq(struct request *rq, struct mapped_device *md,
+ gfp_t gfp_mask)
+{
+ struct request *clone;
+ struct dm_rq_target_io *tio;
+
+ tio = alloc_rq_tio(md, gfp_mask);
+ if (!tio)
+ return NULL;
+
+ tio->md = md;
+ tio->ti = NULL;
+ tio->orig = rq;
+ tio->error = 0;
+ memset(&tio->info, 0, sizeof(tio->info));
+
+ clone = &tio->clone;
+ if (setup_clone(clone, rq, tio)) {
+ /* -ENOMEM */
+ free_rq_tio(tio);
+ return NULL;
+ }
+
+ return clone;
+}
+
static int dm_rq_flush_suspending(struct mapped_device *md)
{
return !md->suspend_rq.special;
@@ -1441,7 +1480,6 @@ static int dm_rq_flush_suspending(struct mapped_device *md)
static int dm_prep_fn(struct request_queue *q, struct request *rq)
{
struct mapped_device *md = q->queuedata;
- struct dm_rq_target_io *tio;
struct request *clone;
if (unlikely(rq == &md->suspend_rq)) {
@@ -1457,23 +1495,9 @@ static int dm_prep_fn(struct request_queue *q, struct request *rq)
return BLKPREP_KILL;
}
- tio = alloc_rq_tio(md); /* Only one for each original request */
- if (!tio)
- /* -ENOMEM */
- return BLKPREP_DEFER;
-
- tio->md = md;
- tio->ti = NULL;
- tio->orig = rq;
- tio->error = 0;
- memset(&tio->info, 0, sizeof(tio->info));
-
- clone = &tio->clone;
- if (setup_clone(clone, rq, tio)) {
- /* -ENOMEM */
- free_rq_tio(tio);
+ clone = clone_rq(rq, md, GFP_ATOMIC);
+ if (!clone)
return BLKPREP_DEFER;
- }
rq->special = clone;
rq->cmd_flags |= REQ_DONTPREP;
@@ -1481,11 +1505,10 @@ static int dm_prep_fn(struct request_queue *q, struct request *rq)
return BLKPREP_OK;
}
-static void map_request(struct dm_target *ti, struct request *rq,
+static void map_request(struct dm_target *ti, struct request *clone,
struct mapped_device *md)
{
int r;
- struct request *clone = rq->special;
struct dm_rq_target_io *tio = clone->end_io_data;
/*
@@ -1562,7 +1585,7 @@ static void dm_request_fn(struct request_queue *q)
blk_start_request(rq);
spin_unlock(q->queue_lock);
- map_request(ti, rq, md);
+ map_request(ti, rq->special, md);
spin_lock_irq(q->queue_lock);
}
@@ -1822,6 +1845,7 @@ static struct mapped_device *alloc_dev(int minor)
bad_bdev:
destroy_workqueue(md->wq);
bad_thread:
+ del_gendisk(md->disk);
put_disk(md->disk);
bad_disk:
blk_cleanup_queue(md->queue);
@@ -2091,8 +2115,7 @@ static int dm_wait_for_completion(struct mapped_device *md, int interruptible)
break;
}
spin_unlock_irqrestore(q->queue_lock, flags);
- } else if (!atomic_read(&md->pending[0]) &&
- !atomic_read(&md->pending[1]))
+ } else if (!md_in_flight(md))
break;
if (interruptible == TASK_INTERRUPTIBLE &&
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 26ba42a79129..10eb1fce975e 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -2631,7 +2631,7 @@ static void analyze_sbs(mddev_t * mddev)
rdev->desc_nr = i++;
rdev->raid_disk = rdev->desc_nr;
set_bit(In_sync, &rdev->flags);
- } else if (rdev->raid_disk >= mddev->raid_disks) {
+ } else if (rdev->raid_disk >= (mddev->raid_disks - min(0, mddev->delta_disks))) {
rdev->raid_disk = -1;
clear_bit(In_sync, &rdev->flags);
}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index d1b9bd5fd4f6..a053423785c9 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -64,7 +64,7 @@ static void * r1bio_pool_alloc(gfp_t gfp_flags, void *data)
/* allocate a r1bio with room for raid_disks entries in the bios array */
r1_bio = kzalloc(size, gfp_flags);
- if (!r1_bio)
+ if (!r1_bio && pi->mddev)
unplug_slaves(pi->mddev);
return r1_bio;
@@ -1683,6 +1683,7 @@ static void raid1d(mddev_t *mddev)
generic_make_request(bio);
}
}
+ cond_resched();
}
if (unplug)
unplug_slaves(mddev);
@@ -1978,13 +1979,14 @@ static int run(mddev_t *mddev)
conf->poolinfo = kmalloc(sizeof(*conf->poolinfo), GFP_KERNEL);
if (!conf->poolinfo)
goto out_no_mem;
- conf->poolinfo->mddev = mddev;
+ conf->poolinfo->mddev = NULL;
conf->poolinfo->raid_disks = mddev->raid_disks;
conf->r1bio_pool = mempool_create(NR_RAID1_BIOS, r1bio_pool_alloc,
r1bio_pool_free,
conf->poolinfo);
if (!conf->r1bio_pool)
goto out_no_mem;
+ conf->poolinfo->mddev = mddev;
spin_lock_init(&conf->device_lock);
mddev->queue->queue_lock = &conf->device_lock;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 51c4c5c4d87a..c2cb7b87b440 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -68,7 +68,7 @@ static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data)
/* allocate a r10bio with room for raid_disks entries in the bios array */
r10_bio = kzalloc(size, gfp_flags);
- if (!r10_bio)
+ if (!r10_bio && conf->mddev)
unplug_slaves(conf->mddev);
return r10_bio;
@@ -1632,6 +1632,7 @@ static void raid10d(mddev_t *mddev)
generic_make_request(bio);
}
}
+ cond_resched();
}
if (unplug)
unplug_slaves(mddev);
@@ -2095,7 +2096,6 @@ static int run(mddev_t *mddev)
if (!conf->tmppage)
goto out_free_conf;
- conf->mddev = mddev;
conf->raid_disks = mddev->raid_disks;
conf->near_copies = nc;
conf->far_copies = fc;
@@ -2132,6 +2132,7 @@ static int run(mddev_t *mddev)
goto out_free_conf;
}
+ conf->mddev = mddev;
spin_lock_init(&conf->device_lock);
mddev->queue->queue_lock = &conf->device_lock;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 94829804ab7f..81abefc172d9 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -156,13 +156,16 @@ static inline int raid6_next_disk(int disk, int raid_disks)
static int raid6_idx_to_slot(int idx, struct stripe_head *sh,
int *count, int syndrome_disks)
{
- int slot;
+ int slot = *count;
+ if (sh->ddf_layout)
+ (*count)++;
if (idx == sh->pd_idx)
return syndrome_disks;
if (idx == sh->qd_idx)
return syndrome_disks + 1;
- slot = (*count)++;
+ if (!sh->ddf_layout)
+ (*count)++;
return slot;
}
@@ -717,7 +720,7 @@ static int set_syndrome_sources(struct page **srcs, struct stripe_head *sh)
int i;
for (i = 0; i < disks; i++)
- srcs[i] = (void *)raid6_empty_zero_page;
+ srcs[i] = NULL;
count = 0;
i = d0_idx;
@@ -727,9 +730,8 @@ static int set_syndrome_sources(struct page **srcs, struct stripe_head *sh)
srcs[slot] = sh->dev[i].page;
i = raid6_next_disk(i, disks);
} while (i != d0_idx);
- BUG_ON(count != syndrome_disks);
- return count;
+ return syndrome_disks;
}
static struct dma_async_tx_descriptor *
@@ -814,7 +816,7 @@ ops_run_compute6_2(struct stripe_head *sh, struct raid5_percpu *percpu)
* slot number conversion for 'faila' and 'failb'
*/
for (i = 0; i < disks ; i++)
- blocks[i] = (void *)raid6_empty_zero_page;
+ blocks[i] = NULL;
count = 0;
i = d0_idx;
do {
@@ -828,7 +830,6 @@ ops_run_compute6_2(struct stripe_head *sh, struct raid5_percpu *percpu)
failb = slot;
i = raid6_next_disk(i, disks);
} while (i != d0_idx);
- BUG_ON(count != syndrome_disks);
BUG_ON(faila == failb);
if (failb < faila)
@@ -845,7 +846,7 @@ ops_run_compute6_2(struct stripe_head *sh, struct raid5_percpu *percpu)
init_async_submit(&submit, ASYNC_TX_FENCE, NULL,
ops_complete_compute, sh,
to_addr_conv(sh, percpu));
- return async_gen_syndrome(blocks, 0, count+2,
+ return async_gen_syndrome(blocks, 0, syndrome_disks+2,
STRIPE_SIZE, &submit);
} else {
struct page *dest;
@@ -1139,7 +1140,7 @@ static void ops_run_check_pq(struct stripe_head *sh, struct raid5_percpu *percpu
&sh->ops.zero_sum_result, percpu->spare_page, &submit);
}
-static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request)
+static void __raid_run_ops(struct stripe_head *sh, unsigned long ops_request)
{
int overlap_clear = 0, i, disks = sh->disks;
struct dma_async_tx_descriptor *tx = NULL;
@@ -1204,22 +1205,55 @@ static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request)
put_cpu();
}
+#ifdef CONFIG_MULTICORE_RAID456
+static void async_run_ops(void *param, async_cookie_t cookie)
+{
+ struct stripe_head *sh = param;
+ unsigned long ops_request = sh->ops.request;
+
+ clear_bit_unlock(STRIPE_OPS_REQ_PENDING, &sh->state);
+ wake_up(&sh->ops.wait_for_ops);
+
+ __raid_run_ops(sh, ops_request);
+ release_stripe(sh);
+}
+
+static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request)
+{
+ /* since handle_stripe can be called outside of raid5d context
+ * we need to ensure sh->ops.request is de-staged before another
+ * request arrives
+ */
+ wait_event(sh->ops.wait_for_ops,
+ !test_and_set_bit_lock(STRIPE_OPS_REQ_PENDING, &sh->state));
+ sh->ops.request = ops_request;
+
+ atomic_inc(&sh->count);
+ async_schedule(async_run_ops, sh);
+}
+#else
+#define raid_run_ops __raid_run_ops
+#endif
+
static int grow_one_stripe(raid5_conf_t *conf)
{
struct stripe_head *sh;
+ int disks = max(conf->raid_disks, conf->previous_raid_disks);
sh = kmem_cache_alloc(conf->slab_cache, GFP_KERNEL);
if (!sh)
return 0;
- memset(sh, 0, sizeof(*sh) + (conf->raid_disks-1)*sizeof(struct r5dev));
+ memset(sh, 0, sizeof(*sh) + (disks-1)*sizeof(struct r5dev));
sh->raid_conf = conf;
spin_lock_init(&sh->lock);
+ #ifdef CONFIG_MULTICORE_RAID456
+ init_waitqueue_head(&sh->ops.wait_for_ops);
+ #endif
- if (grow_buffers(sh, conf->raid_disks)) {
- shrink_buffers(sh, conf->raid_disks);
+ if (grow_buffers(sh, disks)) {
+ shrink_buffers(sh, disks);
kmem_cache_free(conf->slab_cache, sh);
return 0;
}
- sh->disks = conf->raid_disks;
/* we just created an active stripe so... */
atomic_set(&sh->count, 1);
atomic_inc(&conf->active_stripes);
@@ -1231,7 +1265,7 @@ static int grow_one_stripe(raid5_conf_t *conf)
static int grow_stripes(raid5_conf_t *conf, int num)
{
struct kmem_cache *sc;
- int devs = conf->raid_disks;
+ int devs = max(conf->raid_disks, conf->previous_raid_disks);
sprintf(conf->cache_name[0],
"raid%d-%s", conf->level, mdname(conf->mddev));
@@ -1329,6 +1363,9 @@ static int resize_stripes(raid5_conf_t *conf, int newsize)
nsh->raid_conf = conf;
spin_lock_init(&nsh->lock);
+ #ifdef CONFIG_MULTICORE_RAID456
+ init_waitqueue_head(&nsh->ops.wait_for_ops);
+ #endif
list_add(&nsh->lru, &newstripes);
}
@@ -1899,10 +1936,15 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i, int previous)
case ALGORITHM_PARITY_N:
break;
case ALGORITHM_ROTATING_N_CONTINUE:
+ /* Like left_symmetric, but P is before Q */
if (sh->pd_idx == 0)
i--; /* P D D D Q */
- else if (i > sh->pd_idx)
- i -= 2; /* D D Q P D */
+ else {
+ /* D D Q P D */
+ if (i < sh->pd_idx)
+ i += raid_disks;
+ i -= (sh->pd_idx + 1);
+ }
break;
case ALGORITHM_LEFT_ASYMMETRIC_6:
case ALGORITHM_RIGHT_ASYMMETRIC_6:
@@ -2896,7 +2938,7 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh,
*
*/
-static bool handle_stripe5(struct stripe_head *sh)
+static void handle_stripe5(struct stripe_head *sh)
{
raid5_conf_t *conf = sh->raid_conf;
int disks = sh->disks, i;
@@ -3167,11 +3209,9 @@ static bool handle_stripe5(struct stripe_head *sh)
ops_run_io(sh, &s);
return_io(return_bi);
-
- return blocked_rdev == NULL;
}
-static bool handle_stripe6(struct stripe_head *sh)
+static void handle_stripe6(struct stripe_head *sh)
{
raid5_conf_t *conf = sh->raid_conf;
int disks = sh->disks;
@@ -3455,17 +3495,14 @@ static bool handle_stripe6(struct stripe_head *sh)
ops_run_io(sh, &s);
return_io(return_bi);
-
- return blocked_rdev == NULL;
}
-/* returns true if the stripe was handled */
-static bool handle_stripe(struct stripe_head *sh)
+static void handle_stripe(struct stripe_head *sh)
{
if (sh->raid_conf->level == 6)
- return handle_stripe6(sh);
+ handle_stripe6(sh);
else
- return handle_stripe5(sh);
+ handle_stripe5(sh);
}
static void raid5_activate_delayed(raid5_conf_t *conf)
@@ -3503,9 +3540,10 @@ static void unplug_slaves(mddev_t *mddev)
{
raid5_conf_t *conf = mddev->private;
int i;
+ int devs = max(conf->raid_disks, conf->previous_raid_disks);
rcu_read_lock();
- for (i = 0; i < conf->raid_disks; i++) {
+ for (i = 0; i < devs; i++) {
mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
struct request_queue *r_queue = bdev_get_queue(rdev->bdev);
@@ -4277,9 +4315,7 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
clear_bit(STRIPE_INSYNC, &sh->state);
spin_unlock(&sh->lock);
- /* wait for any blocked device to be handled */
- while (unlikely(!handle_stripe(sh)))
- ;
+ handle_stripe(sh);
release_stripe(sh);
return STRIPE_SECTORS;
@@ -4349,37 +4385,6 @@ static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio)
return handled;
}
-#ifdef CONFIG_MULTICORE_RAID456
-static void __process_stripe(void *param, async_cookie_t cookie)
-{
- struct stripe_head *sh = param;
-
- handle_stripe(sh);
- release_stripe(sh);
-}
-
-static void process_stripe(struct stripe_head *sh, struct list_head *domain)
-{
- async_schedule_domain(__process_stripe, sh, domain);
-}
-
-static void synchronize_stripe_processing(struct list_head *domain)
-{
- async_synchronize_full_domain(domain);
-}
-#else
-static void process_stripe(struct stripe_head *sh, struct list_head *domain)
-{
- handle_stripe(sh);
- release_stripe(sh);
- cond_resched();
-}
-
-static void synchronize_stripe_processing(struct list_head *domain)
-{
-}
-#endif
-
/*
* This is our raid5 kernel thread.
@@ -4393,7 +4398,6 @@ static void raid5d(mddev_t *mddev)
struct stripe_head *sh;
raid5_conf_t *conf = mddev->private;
int handled;
- LIST_HEAD(raid_domain);
pr_debug("+++ raid5d active\n");
@@ -4430,7 +4434,9 @@ static void raid5d(mddev_t *mddev)
spin_unlock_irq(&conf->device_lock);
handled++;
- process_stripe(sh, &raid_domain);
+ handle_stripe(sh);
+ release_stripe(sh);
+ cond_resched();
spin_lock_irq(&conf->device_lock);
}
@@ -4438,7 +4444,6 @@ static void raid5d(mddev_t *mddev)
spin_unlock_irq(&conf->device_lock);
- synchronize_stripe_processing(&raid_domain);
async_tx_issue_pending_all();
unplug_slaves(mddev);
@@ -4558,13 +4563,9 @@ raid5_size(mddev_t *mddev, sector_t sectors, int raid_disks)
if (!sectors)
sectors = mddev->dev_sectors;
- if (!raid_disks) {
+ if (!raid_disks)
/* size is defined by the smallest of previous and new size */
- if (conf->raid_disks < conf->previous_raid_disks)
- raid_disks = conf->raid_disks;
- else
- raid_disks = conf->previous_raid_disks;
- }
+ raid_disks = min(conf->raid_disks, conf->previous_raid_disks);
sectors &= ~((sector_t)mddev->chunk_sectors - 1);
sectors &= ~((sector_t)mddev->new_chunk_sectors - 1);
@@ -4665,7 +4666,7 @@ static int raid5_alloc_percpu(raid5_conf_t *conf)
}
per_cpu_ptr(conf->percpu, cpu)->spare_page = spare_page;
}
- scribble = kmalloc(scribble_len(conf->raid_disks), GFP_KERNEL);
+ scribble = kmalloc(conf->scribble_len, GFP_KERNEL);
if (!scribble) {
err = -ENOMEM;
break;
@@ -4686,7 +4687,7 @@ static int raid5_alloc_percpu(raid5_conf_t *conf)
static raid5_conf_t *setup_conf(mddev_t *mddev)
{
raid5_conf_t *conf;
- int raid_disk, memory;
+ int raid_disk, memory, max_disks;
mdk_rdev_t *rdev;
struct disk_info *disk;
@@ -4722,15 +4723,28 @@ static raid5_conf_t *setup_conf(mddev_t *mddev)
conf = kzalloc(sizeof(raid5_conf_t), GFP_KERNEL);
if (conf == NULL)
goto abort;
+ spin_lock_init(&conf->device_lock);
+ init_waitqueue_head(&conf->wait_for_stripe);
+ init_waitqueue_head(&conf->wait_for_overlap);
+ INIT_LIST_HEAD(&conf->handle_list);
+ INIT_LIST_HEAD(&conf->hold_list);
+ INIT_LIST_HEAD(&conf->delayed_list);
+ INIT_LIST_HEAD(&conf->bitmap_list);
+ INIT_LIST_HEAD(&conf->inactive_list);
+ atomic_set(&conf->active_stripes, 0);
+ atomic_set(&conf->preread_active_stripes, 0);
+ atomic_set(&conf->active_aligned_reads, 0);
+ conf->bypass_threshold = BYPASS_THRESHOLD;
conf->raid_disks = mddev->raid_disks;
- conf->scribble_len = scribble_len(conf->raid_disks);
if (mddev->reshape_position == MaxSector)
conf->previous_raid_disks = mddev->raid_disks;
else
conf->previous_raid_disks = mddev->raid_disks - mddev->delta_disks;
+ max_disks = max(conf->raid_disks, conf->previous_raid_disks);
+ conf->scribble_len = scribble_len(max_disks);
- conf->disks = kzalloc(conf->raid_disks * sizeof(struct disk_info),
+ conf->disks = kzalloc(max_disks * sizeof(struct disk_info),
GFP_KERNEL);
if (!conf->disks)
goto abort;
@@ -4744,24 +4758,11 @@ static raid5_conf_t *setup_conf(mddev_t *mddev)
if (raid5_alloc_percpu(conf) != 0)
goto abort;
- spin_lock_init(&conf->device_lock);
- init_waitqueue_head(&conf->wait_for_stripe);
- init_waitqueue_head(&conf->wait_for_overlap);
- INIT_LIST_HEAD(&conf->handle_list);
- INIT_LIST_HEAD(&conf->hold_list);
- INIT_LIST_HEAD(&conf->delayed_list);
- INIT_LIST_HEAD(&conf->bitmap_list);
- INIT_LIST_HEAD(&conf->inactive_list);
- atomic_set(&conf->active_stripes, 0);
- atomic_set(&conf->preread_active_stripes, 0);
- atomic_set(&conf->active_aligned_reads, 0);
- conf->bypass_threshold = BYPASS_THRESHOLD;
-
pr_debug("raid5: run(%s) called.\n", mdname(mddev));
list_for_each_entry(rdev, &mddev->disks, same_set) {
raid_disk = rdev->raid_disk;
- if (raid_disk >= conf->raid_disks
+ if (raid_disk >= max_disks
|| raid_disk < 0)
continue;
disk = conf->disks + raid_disk;
@@ -4793,7 +4794,7 @@ static raid5_conf_t *setup_conf(mddev_t *mddev)
}
memory = conf->max_nr_stripes * (sizeof(struct stripe_head) +
- conf->raid_disks * ((sizeof(struct bio) + PAGE_SIZE))) / 1024;
+ max_disks * ((sizeof(struct bio) + PAGE_SIZE))) / 1024;
if (grow_stripes(conf, conf->max_nr_stripes)) {
printk(KERN_ERR
"raid5: couldn't allocate %dkB for buffers\n", memory);
@@ -4918,7 +4919,8 @@ static int run(mddev_t *mddev)
test_bit(In_sync, &rdev->flags))
working_disks++;
- mddev->degraded = conf->raid_disks - working_disks;
+ mddev->degraded = (max(conf->raid_disks, conf->previous_raid_disks)
+ - working_disks);
if (mddev->degraded > conf->max_degraded) {
printk(KERN_ERR "raid5: not enough operational devices for %s"
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
index 2390e0e83daf..dd708359b451 100644
--- a/drivers/md/raid5.h
+++ b/drivers/md/raid5.h
@@ -214,12 +214,20 @@ struct stripe_head {
int disks; /* disks in stripe */
enum check_states check_state;
enum reconstruct_states reconstruct_state;
- /* stripe_operations
+ /**
+ * struct stripe_operations
* @target - STRIPE_OP_COMPUTE_BLK target
+ * @target2 - 2nd compute target in the raid6 case
+ * @zero_sum_result - P and Q verification flags
+ * @request - async service request flags for raid_run_ops
*/
struct stripe_operations {
int target, target2;
enum sum_check_flags zero_sum_result;
+ #ifdef CONFIG_MULTICORE_RAID456
+ unsigned long request;
+ wait_queue_head_t wait_for_ops;
+ #endif
} ops;
struct r5dev {
struct bio req;
@@ -294,6 +302,8 @@ struct r6_state {
#define STRIPE_FULL_WRITE 13 /* all blocks are set to be overwritten */
#define STRIPE_BIOFILL_RUN 14
#define STRIPE_COMPUTE_RUN 15
+#define STRIPE_OPS_REQ_PENDING 16
+
/*
* Operation request flags
*/
@@ -478,7 +488,7 @@ static inline int algorithm_valid_raid6(int layout)
{
return (layout >= 0 && layout <= 5)
||
- (layout == 8 || layout == 10)
+ (layout >= 8 && layout <= 10)
||
(layout >= 16 && layout <= 20);
}
diff --git a/drivers/md/raid6altivec.uc b/drivers/md/raid6altivec.uc
index 699dfeee4944..2654d5c854be 100644
--- a/drivers/md/raid6altivec.uc
+++ b/drivers/md/raid6altivec.uc
@@ -15,7 +15,7 @@
*
* $#-way unrolled portable integer math RAID-6 instruction set
*
- * This file is postprocessed using unroll.pl
+ * This file is postprocessed using unroll.awk
*
* <benh> hpa: in process,
* you can just "steal" the vec unit with enable_kernel_altivec() (but
diff --git a/drivers/md/raid6int.uc b/drivers/md/raid6int.uc
index f9bf9cba357f..d1e276a14fab 100644
--- a/drivers/md/raid6int.uc
+++ b/drivers/md/raid6int.uc
@@ -15,7 +15,7 @@
*
* $#-way unrolled portable integer math RAID-6 instruction set
*
- * This file is postprocessed using unroll.pl
+ * This file is postprocessed using unroll.awk
*/
#include <linux/raid/pq.h>
diff --git a/drivers/md/raid6test/Makefile b/drivers/md/raid6test/Makefile
index 58ffdf4f5161..2874cbef529d 100644
--- a/drivers/md/raid6test/Makefile
+++ b/drivers/md/raid6test/Makefile
@@ -7,7 +7,7 @@ CC = gcc
OPTFLAGS = -O2 # Adjust as desired
CFLAGS = -I.. -I ../../../include -g $(OPTFLAGS)
LD = ld
-PERL = perl
+AWK = awk
AR = ar
RANLIB = ranlib
@@ -35,35 +35,35 @@ raid6.a: raid6int1.o raid6int2.o raid6int4.o raid6int8.o raid6int16.o \
raid6test: test.c raid6.a
$(CC) $(CFLAGS) -o raid6test $^
-raid6altivec1.c: raid6altivec.uc ../unroll.pl
- $(PERL) ../unroll.pl 1 < raid6altivec.uc > $@
+raid6altivec1.c: raid6altivec.uc ../unroll.awk
+ $(AWK) ../unroll.awk -vN=1 < raid6altivec.uc > $@
-raid6altivec2.c: raid6altivec.uc ../unroll.pl
- $(PERL) ../unroll.pl 2 < raid6altivec.uc > $@
+raid6altivec2.c: raid6altivec.uc ../unroll.awk
+ $(AWK) ../unroll.awk -vN=2 < raid6altivec.uc > $@
-raid6altivec4.c: raid6altivec.uc ../unroll.pl
- $(PERL) ../unroll.pl 4 < raid6altivec.uc > $@
+raid6altivec4.c: raid6altivec.uc ../unroll.awk
+ $(AWK) ../unroll.awk -vN=4 < raid6altivec.uc > $@
-raid6altivec8.c: raid6altivec.uc ../unroll.pl
- $(PERL) ../unroll.pl 8 < raid6altivec.uc > $@
+raid6altivec8.c: raid6altivec.uc ../unroll.awk
+ $(AWK) ../unroll.awk -vN=8 < raid6altivec.uc > $@
-raid6int1.c: raid6int.uc ../unroll.pl
- $(PERL) ../unroll.pl 1 < raid6int.uc > $@
+raid6int1.c: raid6int.uc ../unroll.awk
+ $(AWK) ../unroll.awk -vN=1 < raid6int.uc > $@
-raid6int2.c: raid6int.uc ../unroll.pl
- $(PERL) ../unroll.pl 2 < raid6int.uc > $@
+raid6int2.c: raid6int.uc ../unroll.awk
+ $(AWK) ../unroll.awk -vN=2 < raid6int.uc > $@
-raid6int4.c: raid6int.uc ../unroll.pl
- $(PERL) ../unroll.pl 4 < raid6int.uc > $@
+raid6int4.c: raid6int.uc ../unroll.awk
+ $(AWK) ../unroll.awk -vN=4 < raid6int.uc > $@
-raid6int8.c: raid6int.uc ../unroll.pl
- $(PERL) ../unroll.pl 8 < raid6int.uc > $@
+raid6int8.c: raid6int.uc ../unroll.awk
+ $(AWK) ../unroll.awk -vN=8 < raid6int.uc > $@
-raid6int16.c: raid6int.uc ../unroll.pl
- $(PERL) ../unroll.pl 16 < raid6int.uc > $@
+raid6int16.c: raid6int.uc ../unroll.awk
+ $(AWK) ../unroll.awk -vN=16 < raid6int.uc > $@
-raid6int32.c: raid6int.uc ../unroll.pl
- $(PERL) ../unroll.pl 32 < raid6int.uc > $@
+raid6int32.c: raid6int.uc ../unroll.awk
+ $(AWK) ../unroll.awk -vN=32 < raid6int.uc > $@
raid6tables.c: mktables
./mktables > raid6tables.c
diff --git a/drivers/md/unroll.awk b/drivers/md/unroll.awk
new file mode 100644
index 000000000000..c6aa03631df8
--- /dev/null
+++ b/drivers/md/unroll.awk
@@ -0,0 +1,20 @@
+
+# This filter requires one command line option of form -vN=n
+# where n must be a decimal number.
+#
+# Repeat each input line containing $$ n times, replacing $$ with 0...n-1.
+# Replace each $# with n, and each $* with a single $.
+
+BEGIN {
+ n = N + 0
+}
+{
+ if (/\$\$/) { rep = n } else { rep = 1 }
+ for (i = 0; i < rep; ++i) {
+ tmp = $0
+ gsub(/\$\$/, i, tmp)
+ gsub(/\$\#/, n, tmp)
+ gsub(/\$\*/, "$", tmp)
+ print tmp
+ }
+}
diff --git a/drivers/md/unroll.pl b/drivers/md/unroll.pl
deleted file mode 100644
index 3acc710a20ea..000000000000
--- a/drivers/md/unroll.pl
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/perl
-#
-# Take a piece of C code and for each line which contains the sequence $$
-# repeat n times with $ replaced by 0...n-1; the sequence $# is replaced
-# by the unrolling factor, and $* with a single $
-#
-
-($n) = @ARGV;
-$n += 0;
-
-while ( defined($line = <STDIN>) ) {
- if ( $line =~ /\$\$/ ) {
- $rep = $n;
- } else {
- $rep = 1;
- }
- for ( $i = 0 ; $i < $rep ; $i++ ) {
- $tmp = $line;
- $tmp =~ s/\$\$/$i/g;
- $tmp =~ s/\$\#/$n/g;
- $tmp =~ s/\$\*/\$/g;
- print $tmp;
- }
-}
diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c
index f270e605da83..72baaf13207c 100644
--- a/drivers/media/common/tuners/tuner-xc2028.c
+++ b/drivers/media/common/tuners/tuner-xc2028.c
@@ -99,6 +99,7 @@ struct xc2028_data {
if (size != _rc) \
tuner_info("i2c output error: rc = %d (should be %d)\n",\
_rc, (int)size); \
+ msleep(priv->ctrl.msleep); \
_rc; \
})
@@ -118,6 +119,7 @@ struct xc2028_data {
if (isize != _rc) \
tuner_err("i2c input error: rc = %d (should be %d)\n", \
_rc, (int)isize); \
+ msleep(priv->ctrl.msleep); \
_rc; \
})
@@ -129,7 +131,7 @@ struct xc2028_data {
_val, sizeof(_val)))) { \
tuner_err("Error on line %d: %d\n", __LINE__, _rc); \
} else \
- msleep(10); \
+ msleep(priv->ctrl.msleep); \
_rc; \
})
@@ -808,10 +810,20 @@ check_device:
hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
(version & 0xf0) >> 4, version & 0xf);
+
+ if (priv->ctrl.read_not_reliable)
+ goto read_not_reliable;
+
/* Check firmware version against what we downloaded. */
if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) {
- tuner_err("Incorrect readback of firmware version.\n");
- goto fail;
+ if (!priv->ctrl.read_not_reliable) {
+ tuner_err("Incorrect readback of firmware version.\n");
+ goto fail;
+ } else {
+ tuner_err("Returned an incorrect version. However, "
+ "read is not reliable enough. Ignoring it.\n");
+ hwmodel = 3028;
+ }
}
/* Check that the tuner hardware model remains consistent over time. */
@@ -825,6 +837,7 @@ check_device:
goto fail;
}
+read_not_reliable:
memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
/*
@@ -957,6 +970,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
The reset CLK is needed only with tm6000.
Driver should work fine even if this fails.
*/
+ msleep(priv->ctrl.msleep);
do_tuner_callback(fe, XC2028_RESET_CLK, 1);
msleep(10);
diff --git a/drivers/media/common/tuners/tuner-xc2028.h b/drivers/media/common/tuners/tuner-xc2028.h
index a90c35d50add..9778c96a5006 100644
--- a/drivers/media/common/tuners/tuner-xc2028.h
+++ b/drivers/media/common/tuners/tuner-xc2028.h
@@ -33,12 +33,14 @@ enum firmware_type {
struct xc2028_ctrl {
char *fname;
int max_len;
+ int msleep;
unsigned int scode_table;
unsigned int mts :1;
unsigned int input1:1;
unsigned int vhfbw7:1;
unsigned int uhfbw8:1;
unsigned int disable_power_mgmt:1;
+ unsigned int read_not_reliable:1;
unsigned int demod;
enum firmware_type type:2;
};
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 0241a7c5c34a..8b8558fcb042 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -1396,7 +1396,7 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file,
return ret;
}
- /* binary compatiblity cruft */
+ /* binary compatibility cruft */
case __NET_ADD_IF_OLD:
{
struct __dvb_net_if_old *dvbnetif = parg;
diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c
index 010075535221..868b78bfae75 100644
--- a/drivers/media/dvb/frontends/drx397xD.c
+++ b/drivers/media/dvb/frontends/drx397xD.c
@@ -81,7 +81,7 @@ static struct {
#include "drx397xD_fw.h"
};
-/* use only with writer lock aquired */
+/* use only with writer lock acquired */
static void _drx_release_fw(struct drx397xD_state *s, enum fw_ix ix)
{
memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 6dd51e27582c..e12082b8a08d 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -1200,7 +1200,7 @@ static struct pci_driver cx18_pci_driver = {
.remove = cx18_remove,
};
-static int module_start(void)
+static int __init module_start(void)
{
printk(KERN_INFO "cx18: Start initialization, version %s\n", CX18_VERSION);
@@ -1224,7 +1224,7 @@ static int module_start(void)
return 0;
}
-static void module_cleanup(void)
+static void __exit module_cleanup(void)
{
pci_unregister_driver(&cx18_pci_driver);
}
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index c31284ba19dd..fa2d350e20fd 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -1957,7 +1957,7 @@ static struct pci_driver cx23885_pci_driver = {
.resume = NULL,
};
-static int cx23885_init(void)
+static int __init cx23885_init(void)
{
printk(KERN_INFO "cx23885 driver version %d.%d.%d loaded\n",
(CX23885_VERSION_CODE >> 16) & 0xff,
@@ -1970,7 +1970,7 @@ static int cx23885_init(void)
return pci_register_driver(&cx23885_pci_driver);
}
-static void cx23885_fini(void)
+static void __exit cx23885_fini(void)
{
pci_unregister_driver(&cx23885_pci_driver);
}
diff --git a/drivers/media/video/davinci/dm355_ccdc.c b/drivers/media/video/davinci/dm355_ccdc.c
index 4629cabe3f28..56fbefe036ae 100644
--- a/drivers/media/video/davinci/dm355_ccdc.c
+++ b/drivers/media/video/davinci/dm355_ccdc.c
@@ -959,7 +959,7 @@ static struct ccdc_hw_device ccdc_hw_dev = {
},
};
-static int dm355_ccdc_init(void)
+static int __init dm355_ccdc_init(void)
{
printk(KERN_NOTICE "dm355_ccdc_init\n");
if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0)
@@ -969,7 +969,7 @@ static int dm355_ccdc_init(void)
return 0;
}
-static void dm355_ccdc_exit(void)
+static void __exit dm355_ccdc_exit(void)
{
vpfe_unregister_ccdc_device(&ccdc_hw_dev);
}
diff --git a/drivers/media/video/davinci/dm644x_ccdc.c b/drivers/media/video/davinci/dm644x_ccdc.c
index 2f19a919f477..d5fa193f32d2 100644
--- a/drivers/media/video/davinci/dm644x_ccdc.c
+++ b/drivers/media/video/davinci/dm644x_ccdc.c
@@ -859,7 +859,7 @@ static struct ccdc_hw_device ccdc_hw_dev = {
},
};
-static int dm644x_ccdc_init(void)
+static int __init dm644x_ccdc_init(void)
{
printk(KERN_NOTICE "dm644x_ccdc_init\n");
if (vpfe_register_ccdc_device(&ccdc_hw_dev) < 0)
@@ -869,7 +869,7 @@ static int dm644x_ccdc_init(void)
return 0;
}
-static void dm644x_ccdc_exit(void)
+static void __exit dm644x_ccdc_exit(void)
{
vpfe_unregister_ccdc_device(&ccdc_hw_dev);
}
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 463ec3457d7b..7cdbc1a8f218 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -1361,7 +1361,7 @@ static struct pci_driver ivtv_pci_driver = {
.remove = ivtv_remove,
};
-static int module_start(void)
+static int __init module_start(void)
{
printk(KERN_INFO "ivtv: Start initialization, version %s\n", IVTV_VERSION);
@@ -1385,7 +1385,7 @@ static int module_start(void)
return 0;
}
-static void module_cleanup(void)
+static void __exit module_cleanup(void)
{
pci_unregister_driver(&ivtv_pci_driver);
}
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
index eccb40ab7fec..205229333466 100644
--- a/drivers/media/video/ov772x.c
+++ b/drivers/media/video/ov772x.c
@@ -247,7 +247,7 @@
/* COM5 */
#define AFR_ON_OFF 0x80 /* Auto frame rate control ON/OFF selection */
-#define AFR_SPPED 0x40 /* Auto frame rate control speed slection */
+#define AFR_SPPED 0x40 /* Auto frame rate control speed selection */
/* Auto frame rate max rate control */
#define AFR_NO_RATE 0x00 /* No reduction of frame rate */
#define AFR_1p2 0x10 /* Max reduction to 1/2 frame rate */
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index f87757fccc72..c673901cb2b5 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -1319,7 +1319,7 @@ static struct pci_driver saa7134_pci_driver = {
#endif
};
-static int saa7134_init(void)
+static int __init saa7134_init(void)
{
INIT_LIST_HEAD(&saa7134_devlist);
printk(KERN_INFO "saa7130/34: v4l2 driver version %d.%d.%d loaded\n",
@@ -1333,7 +1333,7 @@ static int saa7134_init(void)
return pci_register_driver(&saa7134_pci_driver);
}
-static void saa7134_fini(void)
+static void __exit saa7134_fini(void)
{
pci_unregister_driver(&saa7134_pci_driver);
}
diff --git a/drivers/media/video/saa7164/saa7164-core.c b/drivers/media/video/saa7164/saa7164-core.c
index 709affc31042..e6aa0fbd1e91 100644
--- a/drivers/media/video/saa7164/saa7164-core.c
+++ b/drivers/media/video/saa7164/saa7164-core.c
@@ -724,13 +724,13 @@ static struct pci_driver saa7164_pci_driver = {
.resume = NULL,
};
-static int saa7164_init(void)
+static int __init saa7164_init(void)
{
printk(KERN_INFO "saa7164 driver loaded\n");
return pci_register_driver(&saa7164_pci_driver);
}
-static void saa7164_fini(void)
+static void __exit saa7164_fini(void)
{
pci_unregister_driver(&saa7164_pci_driver);
}
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index 8dd4d219e433..b4948671eb92 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -76,8 +76,8 @@
#define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR
#endif
-#define MPT_LINUX_VERSION_COMMON "3.04.12"
-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.12"
+#define MPT_LINUX_VERSION_COMMON "3.04.13"
+#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.13"
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
#define show_mptmod_ver(s,ver) \
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index 9b2e2198aee9..352acd05c46b 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -621,11 +621,8 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
*/
iocnumX = khdr.iocnum & 0xFF;
if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
- (iocp == NULL)) {
- printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
- __FILE__, __LINE__, iocnumX);
+ (iocp == NULL))
return -ENODEV;
- }
if (!iocp->active) {
printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - Controller disabled.\n",
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index c29578614504..f68ec48a881e 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -792,11 +792,36 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
* precedence!
*/
sc->result = (DID_OK << 16) | scsi_status;
- if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
- /* Have already saved the status and sense data
+ if (!(scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)) {
+
+ /*
+ * For an Errata on LSI53C1030
+ * When the length of request data
+ * and transfer data are different
+ * with result of command (READ or VERIFY),
+ * DID_SOFT_ERROR is set.
*/
- ;
- } else {
+ if (ioc->bus_type == SPI) {
+ if (pScsiReq->CDB[0] == READ_6 ||
+ pScsiReq->CDB[0] == READ_10 ||
+ pScsiReq->CDB[0] == READ_12 ||
+ pScsiReq->CDB[0] == READ_16 ||
+ pScsiReq->CDB[0] == VERIFY ||
+ pScsiReq->CDB[0] == VERIFY_16) {
+ if (scsi_bufflen(sc) !=
+ xfer_cnt) {
+ sc->result =
+ DID_SOFT_ERROR << 16;
+ printk(KERN_WARNING "Errata"
+ "on LSI53C1030 occurred."
+ "sc->req_bufflen=0x%02x,"
+ "xfer_cnt=0x%02x\n",
+ scsi_bufflen(sc),
+ xfer_cnt);
+ }
+ }
+ }
+
if (xfer_cnt < sc->underflow) {
if (scsi_status == SAM_STAT_BUSY)
sc->result = SAM_STAT_BUSY;
@@ -835,7 +860,58 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
sc->result = (DID_OK << 16) | scsi_status;
if (scsi_state == 0) {
;
- } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+ } else if (scsi_state &
+ MPI_SCSI_STATE_AUTOSENSE_VALID) {
+
+ /*
+ * For potential trouble on LSI53C1030.
+ * (date:2007.xx.)
+ * It is checked whether the length of
+ * request data is equal to
+ * the length of transfer and residual.
+ * MEDIUM_ERROR is set by incorrect data.
+ */
+ if ((ioc->bus_type == SPI) &&
+ (sc->sense_buffer[2] & 0x20)) {
+ u32 difftransfer;
+ difftransfer =
+ sc->sense_buffer[3] << 24 |
+ sc->sense_buffer[4] << 16 |
+ sc->sense_buffer[5] << 8 |
+ sc->sense_buffer[6];
+ if (((sc->sense_buffer[3] & 0x80) ==
+ 0x80) && (scsi_bufflen(sc)
+ != xfer_cnt)) {
+ sc->sense_buffer[2] =
+ MEDIUM_ERROR;
+ sc->sense_buffer[12] = 0xff;
+ sc->sense_buffer[13] = 0xff;
+ printk(KERN_WARNING"Errata"
+ "on LSI53C1030 occurred."
+ "sc->req_bufflen=0x%02x,"
+ "xfer_cnt=0x%02x\n" ,
+ scsi_bufflen(sc),
+ xfer_cnt);
+ }
+ if (((sc->sense_buffer[3] & 0x80)
+ != 0x80) &&
+ (scsi_bufflen(sc) !=
+ xfer_cnt + difftransfer)) {
+ sc->sense_buffer[2] =
+ MEDIUM_ERROR;
+ sc->sense_buffer[12] = 0xff;
+ sc->sense_buffer[13] = 0xff;
+ printk(KERN_WARNING
+ "Errata on LSI53C1030 occurred"
+ "sc->req_bufflen=0x%02x,"
+ " xfer_cnt=0x%02x,"
+ "difftransfer=0x%02x\n",
+ scsi_bufflen(sc),
+ xfer_cnt,
+ difftransfer);
+ }
+ }
+
/*
* If running against circa 200003dd 909 MPT f/w,
* may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
diff --git a/drivers/mfd/88pm8607.c b/drivers/mfd/88pm8607.c
new file mode 100644
index 000000000000..7e3f65907993
--- /dev/null
+++ b/drivers/mfd/88pm8607.c
@@ -0,0 +1,302 @@
+/*
+ * Base driver for Marvell 88PM8607
+ *
+ * Copyright (C) 2009 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/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/88pm8607.h>
+
+
+#define PM8607_REG_RESOURCE(_start, _end) \
+{ \
+ .start = PM8607_##_start, \
+ .end = PM8607_##_end, \
+ .flags = IORESOURCE_IO, \
+}
+
+static struct resource pm8607_regulator_resources[] = {
+ PM8607_REG_RESOURCE(BUCK1, BUCK1),
+ PM8607_REG_RESOURCE(BUCK2, BUCK2),
+ PM8607_REG_RESOURCE(BUCK3, BUCK3),
+ PM8607_REG_RESOURCE(LDO1, LDO1),
+ PM8607_REG_RESOURCE(LDO2, LDO2),
+ PM8607_REG_RESOURCE(LDO3, LDO3),
+ PM8607_REG_RESOURCE(LDO4, LDO4),
+ PM8607_REG_RESOURCE(LDO5, LDO5),
+ PM8607_REG_RESOURCE(LDO6, LDO6),
+ PM8607_REG_RESOURCE(LDO7, LDO7),
+ PM8607_REG_RESOURCE(LDO8, LDO8),
+ PM8607_REG_RESOURCE(LDO9, LDO9),
+ PM8607_REG_RESOURCE(LDO10, LDO10),
+ PM8607_REG_RESOURCE(LDO12, LDO12),
+ PM8607_REG_RESOURCE(LDO14, LDO14),
+};
+
+#define PM8607_REG_DEVS(_name, _id) \
+{ \
+ .name = "88pm8607-" #_name, \
+ .num_resources = 1, \
+ .resources = &pm8607_regulator_resources[PM8607_ID_##_id], \
+}
+
+static struct mfd_cell pm8607_devs[] = {
+ PM8607_REG_DEVS(buck1, BUCK1),
+ PM8607_REG_DEVS(buck2, BUCK2),
+ PM8607_REG_DEVS(buck3, BUCK3),
+ PM8607_REG_DEVS(ldo1, LDO1),
+ PM8607_REG_DEVS(ldo2, LDO2),
+ PM8607_REG_DEVS(ldo3, LDO3),
+ PM8607_REG_DEVS(ldo4, LDO4),
+ PM8607_REG_DEVS(ldo5, LDO5),
+ PM8607_REG_DEVS(ldo6, LDO6),
+ PM8607_REG_DEVS(ldo7, LDO7),
+ PM8607_REG_DEVS(ldo8, LDO8),
+ PM8607_REG_DEVS(ldo9, LDO9),
+ PM8607_REG_DEVS(ldo10, LDO10),
+ PM8607_REG_DEVS(ldo12, LDO12),
+ PM8607_REG_DEVS(ldo14, LDO14),
+};
+
+static inline int pm8607_read_device(struct pm8607_chip *chip,
+ int reg, int bytes, void *dest)
+{
+ struct i2c_client *i2c = chip->client;
+ unsigned char data;
+ int ret;
+
+ data = (unsigned char)reg;
+ ret = i2c_master_send(i2c, &data, 1);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_master_recv(i2c, dest, bytes);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static inline int pm8607_write_device(struct pm8607_chip *chip,
+ int reg, int bytes, void *src)
+{
+ struct i2c_client *i2c = chip->client;
+ unsigned char buf[bytes + 1];
+ int ret;
+
+ buf[0] = (unsigned char)reg;
+ memcpy(&buf[1], src, bytes);
+
+ ret = i2c_master_send(i2c, buf, bytes + 1);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+int pm8607_reg_read(struct pm8607_chip *chip, int reg)
+{
+ unsigned char data;
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ ret = chip->read(chip, reg, 1, &data);
+ mutex_unlock(&chip->io_lock);
+
+ if (ret < 0)
+ return ret;
+ else
+ return (int)data;
+}
+EXPORT_SYMBOL(pm8607_reg_read);
+
+int pm8607_reg_write(struct pm8607_chip *chip, int reg,
+ unsigned char data)
+{
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ ret = chip->write(chip, reg, 1, &data);
+ mutex_unlock(&chip->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(pm8607_reg_write);
+
+int pm8607_bulk_read(struct pm8607_chip *chip, int reg,
+ int count, unsigned char *buf)
+{
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ ret = chip->read(chip, reg, count, buf);
+ mutex_unlock(&chip->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(pm8607_bulk_read);
+
+int pm8607_bulk_write(struct pm8607_chip *chip, int reg,
+ int count, unsigned char *buf)
+{
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ ret = chip->write(chip, reg, count, buf);
+ mutex_unlock(&chip->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(pm8607_bulk_write);
+
+int pm8607_set_bits(struct pm8607_chip *chip, int reg,
+ unsigned char mask, unsigned char data)
+{
+ unsigned char value;
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ ret = chip->read(chip, reg, 1, &value);
+ if (ret < 0)
+ goto out;
+ value &= ~mask;
+ value |= data;
+ ret = chip->write(chip, reg, 1, &value);
+out:
+ mutex_unlock(&chip->io_lock);
+ return ret;
+}
+EXPORT_SYMBOL(pm8607_set_bits);
+
+
+static const struct i2c_device_id pm8607_id_table[] = {
+ { "88PM8607", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, pm8607_id_table);
+
+
+static int __devinit pm8607_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pm8607_platform_data *pdata = client->dev.platform_data;
+ struct pm8607_chip *chip;
+ int i, count;
+ int ret;
+
+ chip = kzalloc(sizeof(struct pm8607_chip), GFP_KERNEL);
+ if (chip == NULL)
+ return -ENOMEM;
+
+ chip->client = client;
+ chip->dev = &client->dev;
+ chip->read = pm8607_read_device;
+ chip->write = pm8607_write_device;
+ i2c_set_clientdata(client, chip);
+
+ mutex_init(&chip->io_lock);
+ dev_set_drvdata(chip->dev, chip);
+
+ ret = pm8607_reg_read(chip, PM8607_CHIP_ID);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
+ goto out;
+ }
+ if ((ret & CHIP_ID_MASK) == CHIP_ID)
+ dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n",
+ ret);
+ else {
+ dev_err(chip->dev, "Failed to detect Marvell 88PM8607. "
+ "Chip ID: %02x\n", ret);
+ goto out;
+ }
+ chip->chip_id = ret;
+
+ ret = pm8607_reg_read(chip, PM8607_BUCK3);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret);
+ goto out;
+ }
+ if (ret & PM8607_BUCK3_DOUBLE)
+ chip->buck3_double = 1;
+
+ ret = pm8607_reg_read(chip, PM8607_MISC1);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret);
+ goto out;
+ }
+ if (pdata->i2c_port == PI2C_PORT)
+ ret |= PM8607_MISC1_PI2C;
+ else
+ ret &= ~PM8607_MISC1_PI2C;
+ ret = pm8607_reg_write(chip, PM8607_MISC1, ret);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to write MISC1 register: %d\n", ret);
+ goto out;
+ }
+
+
+ count = ARRAY_SIZE(pm8607_devs);
+ for (i = 0; i < count; i++) {
+ ret = mfd_add_devices(chip->dev, i, &pm8607_devs[i],
+ 1, NULL, 0);
+ if (ret != 0) {
+ dev_err(chip->dev, "Failed to add subdevs\n");
+ goto out;
+ }
+ }
+
+ return 0;
+
+out:
+ i2c_set_clientdata(client, NULL);
+ kfree(chip);
+ return ret;
+}
+
+static int __devexit pm8607_remove(struct i2c_client *client)
+{
+ struct pm8607_chip *chip = i2c_get_clientdata(client);
+
+ mfd_remove_devices(chip->dev);
+ kfree(chip);
+ return 0;
+}
+
+static struct i2c_driver pm8607_driver = {
+ .driver = {
+ .name = "88PM8607",
+ .owner = THIS_MODULE,
+ },
+ .probe = pm8607_probe,
+ .remove = __devexit_p(pm8607_remove),
+ .id_table = pm8607_id_table,
+};
+
+static int __init pm8607_init(void)
+{
+ int ret;
+ ret = i2c_add_driver(&pm8607_driver);
+ if (ret != 0)
+ pr_err("Failed to register 88PM8607 I2C driver: %d\n", ret);
+ return ret;
+}
+subsys_initcall(pm8607_init);
+
+static void __exit pm8607_exit(void)
+{
+ i2c_del_driver(&pm8607_driver);
+}
+module_exit(pm8607_exit);
+
+MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM8607");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 570be139f9df..e8db83ec9962 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -35,6 +35,14 @@ config MFD_ASIC3
This driver supports the ASIC3 multifunction chip found on many
PDAs (mainly iPAQ and HTC based ones)
+config MFD_SH_MOBILE_SDHI
+ bool "Support for SuperH Mobile SDHI"
+ depends on SUPERH
+ select MFD_CORE
+ ---help---
+ This driver supports the SDHI hardware block found in many
+ SuperH Mobile SoCs.
+
config MFD_DM355EVM_MSP
bool "DaVinci DM355 EVM microcontroller"
depends on I2C && MACH_DAVINCI_DM355_EVM
@@ -160,6 +168,16 @@ config PMIC_DA903X
individual components like LCD backlight, voltage regulators,
LEDs and battery-charger under the corresponding menus.
+config PMIC_ADP5520
+ bool "Analog Devices ADP5520/01 MFD PMIC Core Support"
+ depends on I2C=y
+ help
+ Say yes here to add support for Analog Devices AD5520 and ADP5501,
+ Multifunction Power Management IC. This includes
+ the I2C driver and the core APIs _only_, you have to select
+ individual components like LCD backlight, LEDs, GPIOs and Kepad
+ under the corresponding menus.
+
config MFD_WM8400
tristate "Support Wolfson Microelectronics WM8400"
select MFD_CORE
@@ -171,12 +189,12 @@ config MFD_WM8400
the functionality of the device.
config MFD_WM831X
- tristate "Support Wolfson Microelectronics WM831x PMICs"
+ tristate "Support Wolfson Microelectronics WM831x/2x PMICs"
select MFD_CORE
depends on I2C
help
- Support for the Wolfson Microelecronics WM831x PMICs. This
- driver provides common support for accessing the device,
+ Support for the Wolfson Microelecronics WM831x and WM832x PMICs.
+ This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the
functionality of the device.
@@ -305,6 +323,26 @@ config EZX_PCAP
This enables the PCAP ASIC present on EZX Phones. This is
needed for MMC, TouchScreen, Sound, USB, etc..
+config MFD_88PM8607
+ bool "Support Marvell 88PM8607"
+ depends on I2C=y
+ select MFD_CORE
+ help
+ This supports for Marvell 88PM8607 Power Management IC. This includes
+ the I2C driver and the core APIs _only_, you have to select
+ individual components like voltage regulators, RTC and
+ battery-charger under the corresponding menus.
+
+config AB4500_CORE
+ tristate "ST-Ericsson's AB4500 Mixed Signal Power management chip"
+ depends on SPI
+ default y
+ help
+ Select this option to enable access to AB4500 power management
+ chip. This connects to U8500 on the SSP/SPI bus and exports
+ read/write functions for the devices to get access to this chip.
+ This chip embeds various other multimedia funtionalities as well.
+
endmenu
menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index f3b277b90d40..e5fe56eb7c65 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -4,20 +4,22 @@
obj-$(CONFIG_MFD_SM501) += sm501.o
obj-$(CONFIG_MFD_ASIC3) += asic3.o
+obj-$(CONFIG_MFD_SH_MOBILE_SDHI) += sh_mobile_sdhi.o
obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o
obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o
obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
-obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o
-obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o
-obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o
+obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o
+obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o
+obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o
obj-$(CONFIG_MFD_WM8400) += wm8400-core.o
wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o
obj-$(CONFIG_MFD_WM831X) += wm831x.o
wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
+wm8350-objs += wm8350-irq.o
obj-$(CONFIG_MFD_WM8350) += wm8350.o
obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
@@ -50,3 +52,6 @@ obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o
obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o
obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
+obj-$(CONFIG_AB4500_CORE) += ab4500-core.o
+obj-$(CONFIG_MFD_88PM8607) += 88pm8607.o
+obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c
index 613481028272..fd42a80e7bf9 100644
--- a/drivers/mfd/ab3100-core.c
+++ b/drivers/mfd/ab3100-core.c
@@ -900,9 +900,6 @@ static int __init ab3100_probe(struct i2c_client *client,
goto exit_no_testreg_client;
}
- strlcpy(ab3100->testreg_client->name, id->name,
- sizeof(ab3100->testreg_client->name));
-
err = ab3100_setup(ab3100);
if (err)
goto exit_no_setup;
diff --git a/drivers/mfd/ab4500-core.c b/drivers/mfd/ab4500-core.c
new file mode 100644
index 000000000000..1c44c19e073a
--- /dev/null
+++ b/drivers/mfd/ab4500-core.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2009 ST-Ericsson
+ *
+ * Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.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.
+ *
+ * AB4500 is a companion power management chip used with U8500.
+ * On this platform, this is interfaced with SSP0 controller
+ * which is a ARM primecell pl022.
+ *
+ * At the moment the module just exports read/write features.
+ * Interrupt management to be added - TODO.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/mfd/ab4500.h>
+
+/* just required if probe fails, we need to
+ * unregister the device
+ */
+static struct spi_driver ab4500_driver;
+
+/*
+ * This funtion writes to any AB4500 registers using
+ * SPI protocol & before it writes it packs the data
+ * in the below 24 bit frame format
+ *
+ * *|------------------------------------|
+ * *| 23|22...18|17.......10|9|8|7......0|
+ * *| r/w bank adr data |
+ * * ------------------------------------
+ *
+ * This function shouldn't be called from interrupt
+ * context
+ */
+int ab4500_write(struct ab4500 *ab4500, unsigned char block,
+ unsigned long addr, unsigned char data)
+{
+ struct spi_transfer xfer;
+ struct spi_message msg;
+ int err;
+ unsigned long spi_data =
+ block << 18 | addr << 10 | data;
+
+ mutex_lock(&ab4500->lock);
+ ab4500->tx_buf[0] = spi_data;
+ ab4500->rx_buf[0] = 0;
+
+ xfer.tx_buf = ab4500->tx_buf;
+ xfer.rx_buf = NULL;
+ xfer.len = sizeof(unsigned long);
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+
+ err = spi_sync(ab4500->spi, &msg);
+ mutex_unlock(&ab4500->lock);
+
+ return err;
+}
+EXPORT_SYMBOL(ab4500_write);
+
+int ab4500_read(struct ab4500 *ab4500, unsigned char block,
+ unsigned long addr)
+{
+ struct spi_transfer xfer;
+ struct spi_message msg;
+ unsigned long spi_data =
+ 1 << 23 | block << 18 | addr << 10;
+
+ mutex_lock(&ab4500->lock);
+ ab4500->tx_buf[0] = spi_data;
+ ab4500->rx_buf[0] = 0;
+
+ xfer.tx_buf = ab4500->tx_buf;
+ xfer.rx_buf = ab4500->rx_buf;
+ xfer.len = sizeof(unsigned long);
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+
+ spi_sync(ab4500->spi, &msg);
+ mutex_unlock(&ab4500->lock);
+
+ return ab4500->rx_buf[0];
+}
+EXPORT_SYMBOL(ab4500_read);
+
+/* ref: ab3100 core */
+#define AB4500_DEVICE(devname, devid) \
+static struct platform_device ab4500_##devname##_device = { \
+ .name = devid, \
+ .id = -1, \
+}
+
+/* list of childern devices of ab4500 - all are
+ * not populated here - TODO
+ */
+AB4500_DEVICE(charger, "ab4500-charger");
+AB4500_DEVICE(audio, "ab4500-audio");
+AB4500_DEVICE(usb, "ab4500-usb");
+AB4500_DEVICE(tvout, "ab4500-tvout");
+AB4500_DEVICE(sim, "ab4500-sim");
+AB4500_DEVICE(gpadc, "ab4500-gpadc");
+AB4500_DEVICE(clkmgt, "ab4500-clkmgt");
+AB4500_DEVICE(misc, "ab4500-misc");
+
+static struct platform_device *ab4500_platform_devs[] = {
+ &ab4500_charger_device,
+ &ab4500_audio_device,
+ &ab4500_usb_device,
+ &ab4500_tvout_device,
+ &ab4500_sim_device,
+ &ab4500_gpadc_device,
+ &ab4500_clkmgt_device,
+ &ab4500_misc_device,
+};
+
+static int __init ab4500_probe(struct spi_device *spi)
+{
+ struct ab4500 *ab4500;
+ unsigned char revision;
+ int err = 0;
+ int i;
+
+ ab4500 = kzalloc(sizeof *ab4500, GFP_KERNEL);
+ if (!ab4500) {
+ dev_err(&spi->dev, "could not allocate AB4500\n");
+ err = -ENOMEM;
+ goto not_detect;
+ }
+
+ ab4500->spi = spi;
+ spi_set_drvdata(spi, ab4500);
+
+ mutex_init(&ab4500->lock);
+
+ /* read the revision register */
+ revision = ab4500_read(ab4500, AB4500_MISC, AB4500_REV_REG);
+
+ /* revision id 0x0 is for early drop, 0x10 is for cut1.0 */
+ if (revision == 0x0 || revision == 0x10)
+ dev_info(&spi->dev, "Detected chip: %s, revision = %x\n",
+ ab4500_driver.driver.name, revision);
+ else {
+ dev_err(&spi->dev, "unknown chip: 0x%x\n", revision);
+ goto not_detect;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ab4500_platform_devs); i++) {
+ ab4500_platform_devs[i]->dev.parent =
+ &spi->dev;
+ platform_set_drvdata(ab4500_platform_devs[i], ab4500);
+ }
+
+ /* register the ab4500 platform devices */
+ platform_add_devices(ab4500_platform_devs,
+ ARRAY_SIZE(ab4500_platform_devs));
+
+ return err;
+
+ not_detect:
+ spi_unregister_driver(&ab4500_driver);
+ kfree(ab4500);
+ return err;
+}
+
+static int __devexit ab4500_remove(struct spi_device *spi)
+{
+ struct ab4500 *ab4500 =
+ spi_get_drvdata(spi);
+
+ kfree(ab4500);
+
+ return 0;
+}
+
+static struct spi_driver ab4500_driver = {
+ .driver = {
+ .name = "ab4500",
+ .owner = THIS_MODULE,
+ },
+ .probe = ab4500_probe,
+ .remove = __devexit_p(ab4500_remove)
+};
+
+static int __devinit ab4500_init(void)
+{
+ return spi_register_driver(&ab4500_driver);
+}
+
+static void __exit ab4500_exit(void)
+{
+ spi_unregister_driver(&ab4500_driver);
+}
+
+subsys_initcall(ab4500_init);
+module_exit(ab4500_exit);
+
+MODULE_AUTHOR("Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com");
+MODULE_DESCRIPTION("AB4500 core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c
new file mode 100644
index 000000000000..b26644772d02
--- /dev/null
+++ b/drivers/mfd/adp5520.c
@@ -0,0 +1,379 @@
+/*
+ * Base driver for Analog Devices ADP5520/ADP5501 MFD PMICs
+ * LCD Backlight: drivers/video/backlight/adp5520_bl
+ * LEDs : drivers/led/leds-adp5520
+ * GPIO : drivers/gpio/adp5520-gpio (ADP5520 only)
+ * Keys : drivers/input/keyboard/adp5520-keys (ADP5520 only)
+ *
+ * Copyright 2009 Analog Devices Inc.
+ *
+ * Derived from da903x:
+ * Copyright (C) 2008 Compulab, Ltd.
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ * Copyright (C) 2006-2008 Marvell International Ltd.
+ * Eric Miao <eric.miao@marvell.com>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+
+#include <linux/mfd/adp5520.h>
+
+struct adp5520_chip {
+ struct i2c_client *client;
+ struct device *dev;
+ struct mutex lock;
+ struct blocking_notifier_head notifier_list;
+ int irq;
+ unsigned long id;
+};
+
+static int __adp5520_read(struct i2c_client *client,
+ int reg, uint8_t *val)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, reg);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
+ return ret;
+ }
+
+ *val = (uint8_t)ret;
+ return 0;
+}
+
+static int __adp5520_write(struct i2c_client *client,
+ int reg, uint8_t val)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, reg, val);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n",
+ val, reg);
+ return ret;
+ }
+ return 0;
+}
+
+static int __adp5520_ack_bits(struct i2c_client *client, int reg,
+ uint8_t bit_mask)
+{
+ struct adp5520_chip *chip = i2c_get_clientdata(client);
+ uint8_t reg_val;
+ int ret;
+
+ mutex_lock(&chip->lock);
+
+ ret = __adp5520_read(client, reg, &reg_val);
+
+ if (!ret) {
+ reg_val |= bit_mask;
+ ret = __adp5520_write(client, reg, reg_val);
+ }
+
+ mutex_unlock(&chip->lock);
+ return ret;
+}
+
+int adp5520_write(struct device *dev, int reg, uint8_t val)
+{
+ return __adp5520_write(to_i2c_client(dev), reg, val);
+}
+EXPORT_SYMBOL_GPL(adp5520_write);
+
+int adp5520_read(struct device *dev, int reg, uint8_t *val)
+{
+ return __adp5520_read(to_i2c_client(dev), reg, val);
+}
+EXPORT_SYMBOL_GPL(adp5520_read);
+
+int adp5520_set_bits(struct device *dev, int reg, uint8_t bit_mask)
+{
+ struct adp5520_chip *chip = dev_get_drvdata(dev);
+ uint8_t reg_val;
+ int ret;
+
+ mutex_lock(&chip->lock);
+
+ ret = __adp5520_read(chip->client, reg, &reg_val);
+
+ if (!ret && ((reg_val & bit_mask) == 0)) {
+ reg_val |= bit_mask;
+ ret = __adp5520_write(chip->client, reg, reg_val);
+ }
+
+ mutex_unlock(&chip->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(adp5520_set_bits);
+
+int adp5520_clr_bits(struct device *dev, int reg, uint8_t bit_mask)
+{
+ struct adp5520_chip *chip = dev_get_drvdata(dev);
+ uint8_t reg_val;
+ int ret;
+
+ mutex_lock(&chip->lock);
+
+ ret = __adp5520_read(chip->client, reg, &reg_val);
+
+ if (!ret && (reg_val & bit_mask)) {
+ reg_val &= ~bit_mask;
+ ret = __adp5520_write(chip->client, reg, reg_val);
+ }
+
+ mutex_unlock(&chip->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(adp5520_clr_bits);
+
+int adp5520_register_notifier(struct device *dev, struct notifier_block *nb,
+ unsigned int events)
+{
+ struct adp5520_chip *chip = dev_get_drvdata(dev);
+
+ if (chip->irq) {
+ adp5520_set_bits(chip->dev, ADP5520_INTERRUPT_ENABLE,
+ events & (ADP5520_KP_IEN | ADP5520_KR_IEN |
+ ADP5520_OVP_IEN | ADP5520_CMPR_IEN));
+
+ return blocking_notifier_chain_register(&chip->notifier_list,
+ nb);
+ }
+
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(adp5520_register_notifier);
+
+int adp5520_unregister_notifier(struct device *dev, struct notifier_block *nb,
+ unsigned int events)
+{
+ struct adp5520_chip *chip = dev_get_drvdata(dev);
+
+ adp5520_clr_bits(chip->dev, ADP5520_INTERRUPT_ENABLE,
+ events & (ADP5520_KP_IEN | ADP5520_KR_IEN |
+ ADP5520_OVP_IEN | ADP5520_CMPR_IEN));
+
+ return blocking_notifier_chain_unregister(&chip->notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(adp5520_unregister_notifier);
+
+static irqreturn_t adp5520_irq_thread(int irq, void *data)
+{
+ struct adp5520_chip *chip = data;
+ unsigned int events;
+ uint8_t reg_val;
+ int ret;
+
+ ret = __adp5520_read(chip->client, ADP5520_MODE_STATUS, &reg_val);
+ if (ret)
+ goto out;
+
+ events = reg_val & (ADP5520_OVP_INT | ADP5520_CMPR_INT |
+ ADP5520_GPI_INT | ADP5520_KR_INT | ADP5520_KP_INT);
+
+ blocking_notifier_call_chain(&chip->notifier_list, events, NULL);
+ /* ACK, Sticky bits are W1C */
+ __adp5520_ack_bits(chip->client, ADP5520_MODE_STATUS, events);
+
+out:
+ return IRQ_HANDLED;
+}
+
+static int __remove_subdev(struct device *dev, void *unused)
+{
+ platform_device_unregister(to_platform_device(dev));
+ return 0;
+}
+
+static int adp5520_remove_subdevs(struct adp5520_chip *chip)
+{
+ return device_for_each_child(chip->dev, NULL, __remove_subdev);
+}
+
+static int __devinit adp5520_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adp5520_platform_data *pdata = client->dev.platform_data;
+ struct platform_device *pdev;
+ struct adp5520_chip *chip;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&client->dev, "SMBUS Word Data not Supported\n");
+ return -EIO;
+ }
+
+ if (pdata == NULL) {
+ dev_err(&client->dev, "missing platform data\n");
+ return -ENODEV;
+ }
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, chip);
+ chip->client = client;
+
+ chip->dev = &client->dev;
+ chip->irq = client->irq;
+ chip->id = id->driver_data;
+ mutex_init(&chip->lock);
+
+ if (chip->irq) {
+ BLOCKING_INIT_NOTIFIER_HEAD(&chip->notifier_list);
+
+ ret = request_threaded_irq(chip->irq, NULL, adp5520_irq_thread,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "adp5520", chip);
+ if (ret) {
+ dev_err(&client->dev, "failed to request irq %d\n",
+ chip->irq);
+ goto out_free_chip;
+ }
+ }
+
+ ret = adp5520_write(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY);
+ if (ret) {
+ dev_err(&client->dev, "failed to write\n");
+ goto out_free_irq;
+ }
+
+ if (pdata->keys) {
+ pdev = platform_device_register_data(chip->dev, "adp5520-keys",
+ chip->id, pdata->keys, sizeof(*pdata->keys));
+ if (IS_ERR(pdev)) {
+ ret = PTR_ERR(pdev);
+ goto out_remove_subdevs;
+ }
+ }
+
+ if (pdata->gpio) {
+ pdev = platform_device_register_data(chip->dev, "adp5520-gpio",
+ chip->id, pdata->gpio, sizeof(*pdata->gpio));
+ if (IS_ERR(pdev)) {
+ ret = PTR_ERR(pdev);
+ goto out_remove_subdevs;
+ }
+ }
+
+ if (pdata->leds) {
+ pdev = platform_device_register_data(chip->dev, "adp5520-led",
+ chip->id, pdata->leds, sizeof(*pdata->leds));
+ if (IS_ERR(pdev)) {
+ ret = PTR_ERR(pdev);
+ goto out_remove_subdevs;
+ }
+ }
+
+ if (pdata->backlight) {
+ pdev = platform_device_register_data(chip->dev,
+ "adp5520-backlight",
+ chip->id,
+ pdata->backlight,
+ sizeof(*pdata->backlight));
+ if (IS_ERR(pdev)) {
+ ret = PTR_ERR(pdev);
+ goto out_remove_subdevs;
+ }
+ }
+
+ return 0;
+
+out_remove_subdevs:
+ adp5520_remove_subdevs(chip);
+
+out_free_irq:
+ if (chip->irq)
+ free_irq(chip->irq, chip);
+
+out_free_chip:
+ i2c_set_clientdata(client, NULL);
+ kfree(chip);
+
+ return ret;
+}
+
+static int __devexit adp5520_remove(struct i2c_client *client)
+{
+ struct adp5520_chip *chip = dev_get_drvdata(&client->dev);
+
+ if (chip->irq)
+ free_irq(chip->irq, chip);
+
+ adp5520_remove_subdevs(chip);
+ adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0);
+ i2c_set_clientdata(client, NULL);
+ kfree(chip);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int adp5520_suspend(struct i2c_client *client,
+ pm_message_t state)
+{
+ struct adp5520_chip *chip = dev_get_drvdata(&client->dev);
+
+ adp5520_clr_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY);
+ return 0;
+}
+
+static int adp5520_resume(struct i2c_client *client)
+{
+ struct adp5520_chip *chip = dev_get_drvdata(&client->dev);
+
+ adp5520_set_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY);
+ return 0;
+}
+#else
+#define adp5520_suspend NULL
+#define adp5520_resume NULL
+#endif
+
+static const struct i2c_device_id adp5520_id[] = {
+ { "pmic-adp5520", ID_ADP5520 },
+ { "pmic-adp5501", ID_ADP5501 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adp5520_id);
+
+static struct i2c_driver adp5520_driver = {
+ .driver = {
+ .name = "adp5520",
+ .owner = THIS_MODULE,
+ },
+ .probe = adp5520_probe,
+ .remove = __devexit_p(adp5520_remove),
+ .suspend = adp5520_suspend,
+ .resume = adp5520_resume,
+ .id_table = adp5520_id,
+};
+
+static int __init adp5520_init(void)
+{
+ return i2c_add_driver(&adp5520_driver);
+}
+module_init(adp5520_init);
+
+static void __exit adp5520_exit(void)
+{
+ i2c_del_driver(&adp5520_driver);
+}
+module_exit(adp5520_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADP5520(01) PMIC-MFD Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index 63a2a6632106..ff79b00d14f2 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -80,6 +80,7 @@ struct asic3 {
u16 irq_bothedge[4];
struct gpio_chip gpio;
struct device *dev;
+ void __iomem *tmio_cnf;
struct asic3_clk clocks[ARRAY_SIZE(asic3_clk_init)];
};
@@ -685,8 +686,24 @@ static struct mfd_cell asic3_cell_ds1wm = {
.resources = ds1wm_resources,
};
+static void asic3_mmc_pwr(struct platform_device *pdev, int state)
+{
+ struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
+
+ tmio_core_mmc_pwr(asic->tmio_cnf, state);
+}
+
+static void asic3_mmc_clk_div(struct platform_device *pdev, int state)
+{
+ struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
+
+ tmio_core_mmc_clk_div(asic->tmio_cnf, state);
+}
+
static struct tmio_mmc_data asic3_mmc_data = {
- .hclk = 24576000,
+ .hclk = 24576000,
+ .set_pwr = asic3_mmc_pwr,
+ .set_no_clk_div = asic3_mmc_clk_div,
};
static struct resource asic3_mmc_resources[] = {
@@ -696,11 +713,6 @@ static struct resource asic3_mmc_resources[] = {
.flags = IORESOURCE_MEM,
},
{
- .start = ASIC3_SD_CONFIG_BASE,
- .end = ASIC3_SD_CONFIG_BASE + 0x1ff,
- .flags = IORESOURCE_MEM,
- },
- {
.start = 0,
.end = 0,
.flags = IORESOURCE_IRQ,
@@ -743,6 +755,9 @@ static int asic3_mmc_enable(struct platform_device *pdev)
asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF),
ASIC3_SDHWCTRL_SDPWR, 1);
+ /* ASIC3_SD_CTRL_BASE assumes 32-bit addressing, TMIO is 16-bit */
+ tmio_core_mmc_enable(asic->tmio_cnf, ASIC3_SD_CTRL_BASE >> 1);
+
return 0;
}
@@ -766,6 +781,8 @@ static struct mfd_cell asic3_cell_mmc = {
.name = "tmio-mmc",
.enable = asic3_mmc_enable,
.disable = asic3_mmc_disable,
+ .suspend = asic3_mmc_disable,
+ .resume = asic3_mmc_enable,
.driver_data = &asic3_mmc_data,
.num_resources = ARRAY_SIZE(asic3_mmc_resources),
.resources = asic3_mmc_resources,
@@ -797,14 +814,21 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
asic3_cell_ds1wm.data_size = sizeof(asic3_cell_ds1wm);
/* MMC */
+ asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) +
+ mem_sdio->start, 0x400 >> asic->bus_shift);
+ if (!asic->tmio_cnf) {
+ ret = -ENOMEM;
+ dev_dbg(asic->dev, "Couldn't ioremap SD_CONFIG\n");
+ goto out;
+ }
asic3_mmc_resources[0].start >>= asic->bus_shift;
asic3_mmc_resources[0].end >>= asic->bus_shift;
- asic3_mmc_resources[1].start >>= asic->bus_shift;
- asic3_mmc_resources[1].end >>= asic->bus_shift;
asic3_cell_mmc.platform_data = &asic3_cell_mmc;
asic3_cell_mmc.data_size = sizeof(asic3_cell_mmc);
+ tmio_core_set_bus_shift(1 - asic->bus_shift);
+
ret = mfd_add_devices(&pdev->dev, pdev->id,
&asic3_cell_ds1wm, 1, mem, asic->irq_base);
if (ret < 0)
@@ -820,7 +844,10 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
static void asic3_mfd_remove(struct platform_device *pdev)
{
+ struct asic3 *asic = platform_get_drvdata(pdev);
+
mfd_remove_devices(&pdev->dev);
+ iounmap(asic->tmio_cnf);
}
/* Core */
@@ -908,7 +935,7 @@ static int __init asic3_probe(struct platform_device *pdev)
return ret;
}
-static int asic3_remove(struct platform_device *pdev)
+static int __devexit asic3_remove(struct platform_device *pdev)
{
int ret;
struct asic3 *asic = platform_get_drvdata(pdev);
diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c
index 4b364bae6b3e..970afa103261 100644
--- a/drivers/mfd/menelaus.c
+++ b/drivers/mfd/menelaus.c
@@ -44,7 +44,7 @@
#include <asm/mach/irq.h>
#include <mach/gpio.h>
-#include <mach/menelaus.h>
+#include <plat/menelaus.h>
#define DRIVER_NAME "menelaus"
diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c
index 3d31e97d6a45..6d2e8466df1d 100644
--- a/drivers/mfd/pcf50633-adc.c
+++ b/drivers/mfd/pcf50633-adc.c
@@ -209,17 +209,16 @@ static void pcf50633_adc_irq(int irq, void *data)
static int __devinit pcf50633_adc_probe(struct platform_device *pdev)
{
- struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data;
struct pcf50633_adc *adc;
adc = kzalloc(sizeof(*adc), GFP_KERNEL);
if (!adc)
return -ENOMEM;
- adc->pcf = pdata->pcf;
+ adc->pcf = dev_to_pcf50633(pdev->dev.parent);
platform_set_drvdata(pdev, adc);
- pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ADCRDY,
+ pcf50633_register_irq(adc->pcf, PCF50633_IRQ_ADCRDY,
pcf50633_adc_irq, adc);
mutex_init(&adc->queue_mutex);
diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c
index d26d7747175e..03dcc9200707 100644
--- a/drivers/mfd/pcf50633-core.c
+++ b/drivers/mfd/pcf50633-core.c
@@ -290,7 +290,7 @@ out:
int pcf50633_irq_mask(struct pcf50633 *pcf, int irq)
{
- dev_info(pcf->dev, "Masking IRQ %d\n", irq);
+ dev_dbg(pcf->dev, "Masking IRQ %d\n", irq);
return __pcf50633_irq_mask_set(pcf, irq, 1);
}
@@ -298,7 +298,7 @@ EXPORT_SYMBOL_GPL(pcf50633_irq_mask);
int pcf50633_irq_unmask(struct pcf50633 *pcf, int irq)
{
- dev_info(pcf->dev, "Unmasking IRQ %d\n", irq);
+ dev_dbg(pcf->dev, "Unmasking IRQ %d\n", irq);
return __pcf50633_irq_mask_set(pcf, irq, 0);
}
@@ -345,6 +345,9 @@ static void pcf50633_irq_worker(struct work_struct *work)
goto out;
}
+ /* defeat 8s death from lowsys on A5 */
+ pcf50633_reg_write(pcf, PCF50633_REG_OOCSHDWN, 0x04);
+
/* We immediately read the usb and adapter status. We thus make sure
* only of USBINS/USBREM IRQ handlers are called */
if (pcf_int[0] & (PCF50633_INT1_USBINS | PCF50633_INT1_USBREM)) {
@@ -453,7 +456,6 @@ static void
pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
struct platform_device **pdev)
{
- struct pcf50633_subdev_pdata *subdev_pdata;
int ret;
*pdev = platform_device_alloc(name, -1);
@@ -462,15 +464,6 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
return;
}
- subdev_pdata = kmalloc(sizeof(*subdev_pdata), GFP_KERNEL);
- if (!subdev_pdata) {
- dev_err(pcf->dev, "Error allocating subdev pdata\n");
- platform_device_put(*pdev);
- }
-
- subdev_pdata->pcf = pcf;
- platform_device_add_data(*pdev, subdev_pdata, sizeof(*subdev_pdata));
-
(*pdev)->dev.parent = pcf->dev;
ret = platform_device_add(*pdev);
@@ -482,13 +475,13 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
}
#ifdef CONFIG_PM
-static int pcf50633_suspend(struct device *dev, pm_message_t state)
+static int pcf50633_suspend(struct i2c_client *client, pm_message_t state)
{
struct pcf50633 *pcf;
int ret = 0, i;
u8 res[5];
- pcf = dev_get_drvdata(dev);
+ pcf = i2c_get_clientdata(client);
/* Make sure our interrupt handlers are not called
* henceforth */
@@ -523,12 +516,12 @@ out:
return ret;
}
-static int pcf50633_resume(struct device *dev)
+static int pcf50633_resume(struct i2c_client *client)
{
struct pcf50633 *pcf;
int ret;
- pcf = dev_get_drvdata(dev);
+ pcf = i2c_get_clientdata(client);
/* Write the saved mask registers */
ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M,
@@ -560,9 +553,14 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
{
struct pcf50633 *pcf;
struct pcf50633_platform_data *pdata = client->dev.platform_data;
- int i, ret = 0;
+ int i, ret;
int version, variant;
+ if (!client->irq) {
+ dev_err(&client->dev, "Missing IRQ\n");
+ return -ENOENT;
+ }
+
pcf = kzalloc(sizeof(*pcf), GFP_KERNEL);
if (!pcf)
return -ENOMEM;
@@ -577,6 +575,12 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
pcf->irq = client->irq;
pcf->work_queue = create_singlethread_workqueue("pcf50633");
+ if (!pcf->work_queue) {
+ dev_err(&client->dev, "Failed to alloc workqueue\n");
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
INIT_WORK(&pcf->irq_work, pcf50633_irq_worker);
version = pcf50633_reg_read(pcf, 0);
@@ -584,7 +588,7 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
if (version < 0 || variant < 0) {
dev_err(pcf->dev, "Unable to probe pcf50633\n");
ret = -ENODEV;
- goto err;
+ goto err_destroy_workqueue;
}
dev_info(pcf->dev, "Probed device version %d variant %d\n",
@@ -598,6 +602,14 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
pcf50633_reg_write(pcf, PCF50633_REG_INT4M, 0x00);
pcf50633_reg_write(pcf, PCF50633_REG_INT5M, 0x00);
+ ret = request_irq(client->irq, pcf50633_irq,
+ IRQF_TRIGGER_LOW, "pcf50633", pcf);
+
+ if (ret) {
+ dev_err(pcf->dev, "Failed to request IRQ %d\n", ret);
+ goto err_destroy_workqueue;
+ }
+
/* Create sub devices */
pcf50633_client_dev_register(pcf, "pcf50633-input",
&pcf->input_pdev);
@@ -613,31 +625,18 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
pdev = platform_device_alloc("pcf50633-regltr", i);
if (!pdev) {
- dev_err(pcf->dev, "Cannot create regulator\n");
+ dev_err(pcf->dev, "Cannot create regulator %d\n", i);
continue;
}
pdev->dev.parent = pcf->dev;
- pdev->dev.platform_data = &pdata->reg_init_data[i];
- dev_set_drvdata(&pdev->dev, pcf);
+ platform_device_add_data(pdev, &pdata->reg_init_data[i],
+ sizeof(pdata->reg_init_data[i]));
pcf->regulator_pdev[i] = pdev;
platform_device_add(pdev);
}
- if (client->irq) {
- ret = request_irq(client->irq, pcf50633_irq,
- IRQF_TRIGGER_LOW, "pcf50633", pcf);
-
- if (ret) {
- dev_err(pcf->dev, "Failed to request IRQ %d\n", ret);
- goto err;
- }
- } else {
- dev_err(pcf->dev, "No IRQ configured\n");
- goto err;
- }
-
if (enable_irq_wake(client->irq) < 0)
dev_err(pcf->dev, "IRQ %u cannot be enabled as wake-up source"
"in this hardware revision", client->irq);
@@ -651,9 +650,12 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
return 0;
-err:
+err_destroy_workqueue:
destroy_workqueue(pcf->work_queue);
+err_free:
+ i2c_set_clientdata(client, NULL);
kfree(pcf);
+
return ret;
}
@@ -686,12 +688,12 @@ static struct i2c_device_id pcf50633_id_table[] = {
static struct i2c_driver pcf50633_driver = {
.driver = {
.name = "pcf50633",
- .suspend = pcf50633_suspend,
- .resume = pcf50633_resume,
},
.id_table = pcf50633_id_table,
.probe = pcf50633_probe,
.remove = __devexit_p(pcf50633_remove),
+ .suspend = pcf50633_suspend,
+ .resume = pcf50633_resume,
};
static int __init pcf50633_init(void)
diff --git a/drivers/mfd/sh_mobile_sdhi.c b/drivers/mfd/sh_mobile_sdhi.c
new file mode 100644
index 000000000000..56f72cc1d569
--- /dev/null
+++ b/drivers/mfd/sh_mobile_sdhi.c
@@ -0,0 +1,145 @@
+/*
+ * SuperH Mobile SDHI
+ *
+ * Copyright (C) 2009 Magnus Damm
+ *
+ * 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.
+ *
+ * Based on "Compaq ASIC3 support":
+ *
+ * Copyright 2001 Compaq Computer Corporation.
+ * Copyright 2004-2005 Phil Blundell
+ * Copyright 2007-2008 OpenedHand Ltd.
+ *
+ * Authors: Phil Blundell <pb@handhelds.org>,
+ * Samuel Ortiz <sameo@openedhand.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/core.h>
+#include <linux/mfd/tmio.h>
+
+struct sh_mobile_sdhi {
+ struct clk *clk;
+ struct tmio_mmc_data mmc_data;
+ struct mfd_cell cell_mmc;
+};
+
+static struct resource sh_mobile_sdhi_resources[] = {
+ {
+ .start = 0x000,
+ .end = 0x1ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mfd_cell sh_mobile_sdhi_cell = {
+ .name = "tmio-mmc",
+ .num_resources = ARRAY_SIZE(sh_mobile_sdhi_resources),
+ .resources = sh_mobile_sdhi_resources,
+};
+
+static int __init sh_mobile_sdhi_probe(struct platform_device *pdev)
+{
+ struct sh_mobile_sdhi *priv;
+ struct resource *mem;
+ char clk_name[8];
+ int ret, irq;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem)
+ dev_err(&pdev->dev, "missing MEM resource\n");
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ dev_err(&pdev->dev, "missing IRQ resource\n");
+
+ if (!mem || (irq < 0))
+ return -EINVAL;
+
+ priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL);
+ if (priv == NULL) {
+ dev_err(&pdev->dev, "kzalloc failed\n");
+ return -ENOMEM;
+ }
+
+ snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
+ priv->clk = clk_get(&pdev->dev, clk_name);
+ if (IS_ERR(priv->clk)) {
+ dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
+ ret = PTR_ERR(priv->clk);
+ kfree(priv);
+ return ret;
+ }
+
+ clk_enable(priv->clk);
+
+ /* FIXME: silly const unsigned int hclk */
+ *(unsigned int *)&priv->mmc_data.hclk = clk_get_rate(priv->clk);
+
+ memcpy(&priv->cell_mmc, &sh_mobile_sdhi_cell, sizeof(priv->cell_mmc));
+ priv->cell_mmc.driver_data = &priv->mmc_data;
+ priv->cell_mmc.platform_data = &priv->cell_mmc;
+ priv->cell_mmc.data_size = sizeof(priv->cell_mmc);
+
+ platform_set_drvdata(pdev, priv);
+
+ ret = mfd_add_devices(&pdev->dev, pdev->id,
+ &priv->cell_mmc, 1, mem, irq);
+ if (ret) {
+ clk_disable(priv->clk);
+ clk_put(priv->clk);
+ kfree(priv);
+ }
+
+ return ret;
+}
+
+static int sh_mobile_sdhi_remove(struct platform_device *pdev)
+{
+ struct sh_mobile_sdhi *priv = platform_get_drvdata(pdev);
+
+ mfd_remove_devices(&pdev->dev);
+ clk_disable(priv->clk);
+ clk_put(priv->clk);
+ kfree(priv);
+
+ return 0;
+}
+
+static struct platform_driver sh_mobile_sdhi_driver = {
+ .driver = {
+ .name = "sh_mobile_sdhi",
+ .owner = THIS_MODULE,
+ },
+ .probe = sh_mobile_sdhi_probe,
+ .remove = __devexit_p(sh_mobile_sdhi_remove),
+};
+
+static int __init sh_mobile_sdhi_init(void)
+{
+ return platform_driver_register(&sh_mobile_sdhi_driver);
+}
+
+static void __exit sh_mobile_sdhi_exit(void)
+{
+ platform_driver_unregister(&sh_mobile_sdhi_driver);
+}
+
+module_init(sh_mobile_sdhi_init);
+module_exit(sh_mobile_sdhi_exit);
+
+MODULE_DESCRIPTION("SuperH Mobile SDHI driver");
+MODULE_AUTHOR("Magnus Damm");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c
index 0a255c1f1ce7..2fa070361f05 100644
--- a/drivers/mfd/t7l66xb.c
+++ b/drivers/mfd/t7l66xb.c
@@ -38,6 +38,8 @@ enum {
T7L66XB_CELL_MMC,
};
+static const struct resource t7l66xb_mmc_resources[];
+
#define SCR_REVID 0x08 /* b Revision ID */
#define SCR_IMR 0x42 /* b Interrupt Mask */
#define SCR_DEV_CTL 0xe0 /* b Device control */
@@ -83,6 +85,9 @@ static int t7l66xb_mmc_enable(struct platform_device *mmc)
spin_unlock_irqrestore(&t7l66xb->lock, flags);
+ tmio_core_mmc_enable(t7l66xb->scr + 0x200,
+ t7l66xb_mmc_resources[0].start & 0xfffe);
+
return 0;
}
@@ -106,10 +111,28 @@ static int t7l66xb_mmc_disable(struct platform_device *mmc)
return 0;
}
+static void t7l66xb_mmc_pwr(struct platform_device *mmc, int state)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_pwr(t7l66xb->scr + 0x200, state);
+}
+
+static void t7l66xb_mmc_clk_div(struct platform_device *mmc, int state)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_clk_div(t7l66xb->scr + 0x200, state);
+}
+
/*--------------------------------------------------------------------------*/
static struct tmio_mmc_data t7166xb_mmc_data = {
.hclk = 24000000,
+ .set_pwr = t7l66xb_mmc_pwr,
+ .set_no_clk_div = t7l66xb_mmc_clk_div,
};
static const struct resource t7l66xb_mmc_resources[] = {
@@ -119,11 +142,6 @@ static const struct resource t7l66xb_mmc_resources[] = {
.flags = IORESOURCE_MEM,
},
{
- .start = 0x200,
- .end = 0x2ff,
- .flags = IORESOURCE_MEM,
- },
- {
.start = IRQ_T7L66XB_MMC,
.end = IRQ_T7L66XB_MMC,
.flags = IORESOURCE_IRQ,
@@ -282,6 +300,9 @@ static int t7l66xb_resume(struct platform_device *dev)
if (pdata && pdata->resume)
pdata->resume(dev);
+ tmio_core_mmc_enable(t7l66xb->scr + 0x200,
+ t7l66xb_mmc_resources[0].start & 0xfffe);
+
return 0;
}
#else
diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c
index 3280ab33f88a..fa8da0264a9f 100644
--- a/drivers/mfd/tc6387xb.c
+++ b/drivers/mfd/tc6387xb.c
@@ -22,28 +22,41 @@ enum {
TC6387XB_CELL_MMC,
};
+struct tc6387xb {
+ void __iomem *scr;
+ struct clk *clk32k;
+ struct resource rscr;
+};
+
+static struct resource tc6387xb_mmc_resources[];
+
+/*--------------------------------------------------------------------------*/
+
#ifdef CONFIG_PM
static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state)
{
- struct clk *clk32k = platform_get_drvdata(dev);
+ struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
if (pdata && pdata->suspend)
pdata->suspend(dev);
- clk_disable(clk32k);
+ clk_disable(tc6387xb->clk32k);
return 0;
}
static int tc6387xb_resume(struct platform_device *dev)
{
- struct clk *clk32k = platform_get_drvdata(dev);
+ struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
- clk_enable(clk32k);
+ clk_enable(tc6387xb->clk32k);
if (pdata && pdata->resume)
pdata->resume(dev);
+ tmio_core_mmc_resume(tc6387xb->scr + 0x200,
+ tc6387xb_mmc_resources[0].start & 0xfffe);
+
return 0;
}
#else
@@ -53,12 +66,32 @@ static int tc6387xb_resume(struct platform_device *dev)
/*--------------------------------------------------------------------------*/
+static void tc6387xb_mmc_pwr(struct platform_device *mmc, int state)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_pwr(tc6387xb->scr + 0x200, state);
+}
+
+static void tc6387xb_mmc_clk_div(struct platform_device *mmc, int state)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_clk_div(tc6387xb->scr + 0x200, state);
+}
+
+
static int tc6387xb_mmc_enable(struct platform_device *mmc)
{
struct platform_device *dev = to_platform_device(mmc->dev.parent);
- struct clk *clk32k = platform_get_drvdata(dev);
+ struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
- clk_enable(clk32k);
+ clk_enable(tc6387xb->clk32k);
+
+ tmio_core_mmc_enable(tc6387xb->scr + 0x200,
+ tc6387xb_mmc_resources[0].start & 0xfffe);
return 0;
}
@@ -66,19 +99,21 @@ static int tc6387xb_mmc_enable(struct platform_device *mmc)
static int tc6387xb_mmc_disable(struct platform_device *mmc)
{
struct platform_device *dev = to_platform_device(mmc->dev.parent);
- struct clk *clk32k = platform_get_drvdata(dev);
+ struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
- clk_disable(clk32k);
+ clk_disable(tc6387xb->clk32k);
return 0;
}
-/*--------------------------------------------------------------------------*/
-
static struct tmio_mmc_data tc6387xb_mmc_data = {
.hclk = 24000000,
+ .set_pwr = tc6387xb_mmc_pwr,
+ .set_no_clk_div = tc6387xb_mmc_clk_div,
};
+/*--------------------------------------------------------------------------*/
+
static struct resource tc6387xb_mmc_resources[] = {
{
.start = 0x800,
@@ -86,11 +121,6 @@ static struct resource tc6387xb_mmc_resources[] = {
.flags = IORESOURCE_MEM,
},
{
- .start = 0x200,
- .end = 0x2ff,
- .flags = IORESOURCE_MEM,
- },
- {
.start = 0,
.end = 0,
.flags = IORESOURCE_IRQ,
@@ -111,8 +141,9 @@ static struct mfd_cell tc6387xb_cells[] = {
static int tc6387xb_probe(struct platform_device *dev)
{
struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
- struct resource *iomem;
+ struct resource *iomem, *rscr;
struct clk *clk32k;
+ struct tc6387xb *tc6387xb;
int irq, ret;
iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
@@ -120,18 +151,40 @@ static int tc6387xb_probe(struct platform_device *dev)
return -EINVAL;
}
+ tc6387xb = kzalloc(sizeof *tc6387xb, GFP_KERNEL);
+ if (!tc6387xb)
+ return -ENOMEM;
+
ret = platform_get_irq(dev, 0);
if (ret >= 0)
irq = ret;
else
- goto err_resource;
+ goto err_no_irq;
clk32k = clk_get(&dev->dev, "CLK_CK32K");
if (IS_ERR(clk32k)) {
ret = PTR_ERR(clk32k);
+ goto err_no_clk;
+ }
+
+ rscr = &tc6387xb->rscr;
+ rscr->name = "tc6387xb-core";
+ rscr->start = iomem->start;
+ rscr->end = iomem->start + 0xff;
+ rscr->flags = IORESOURCE_MEM;
+
+ ret = request_resource(iomem, rscr);
+ if (ret)
goto err_resource;
+
+ tc6387xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1);
+ if (!tc6387xb->scr) {
+ ret = -ENOMEM;
+ goto err_ioremap;
}
- platform_set_drvdata(dev, clk32k);
+
+ tc6387xb->clk32k = clk32k;
+ platform_set_drvdata(dev, tc6387xb);
if (pdata && pdata->enable)
pdata->enable(dev);
@@ -149,8 +202,13 @@ static int tc6387xb_probe(struct platform_device *dev)
if (!ret)
return 0;
- clk_put(clk32k);
+err_ioremap:
+ release_resource(&tc6387xb->rscr);
err_resource:
+ clk_put(clk32k);
+err_no_clk:
+err_no_irq:
+ kfree(tc6387xb);
return ret;
}
@@ -195,3 +253,4 @@ MODULE_DESCRIPTION("Toshiba TC6387XB core driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Ian Molton");
MODULE_ALIAS("platform:tc6387xb");
+
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
index 1429a7341a9a..40bb375c605e 100644
--- a/drivers/mfd/tc6393xb.c
+++ b/drivers/mfd/tc6393xb.c
@@ -136,10 +136,6 @@ static int tc6393xb_nand_enable(struct platform_device *nand)
return 0;
}
-static struct tmio_mmc_data tc6393xb_mmc_data = {
- .hclk = 24000000,
-};
-
static struct resource __devinitdata tc6393xb_nand_resources[] = {
{
.start = 0x1000,
@@ -165,11 +161,6 @@ static struct resource __devinitdata tc6393xb_mmc_resources[] = {
.flags = IORESOURCE_MEM,
},
{
- .start = 0x200,
- .end = 0x2ff,
- .flags = IORESOURCE_MEM,
- },
- {
.start = IRQ_TC6393_MMC,
.end = IRQ_TC6393_MMC,
.flags = IORESOURCE_IRQ,
@@ -346,6 +337,50 @@ int tc6393xb_lcd_mode(struct platform_device *fb,
}
EXPORT_SYMBOL(tc6393xb_lcd_mode);
+static int tc6393xb_mmc_enable(struct platform_device *mmc)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_enable(tc6393xb->scr + 0x200,
+ tc6393xb_mmc_resources[0].start & 0xfffe);
+
+ return 0;
+}
+
+static int tc6393xb_mmc_resume(struct platform_device *mmc)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_resume(tc6393xb->scr + 0x200,
+ tc6393xb_mmc_resources[0].start & 0xfffe);
+
+ return 0;
+}
+
+static void tc6393xb_mmc_pwr(struct platform_device *mmc, int state)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_pwr(tc6393xb->scr + 0x200, state);
+}
+
+static void tc6393xb_mmc_clk_div(struct platform_device *mmc, int state)
+{
+ struct platform_device *dev = to_platform_device(mmc->dev.parent);
+ struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
+
+ tmio_core_mmc_clk_div(tc6393xb->scr + 0x200, state);
+}
+
+static struct tmio_mmc_data tc6393xb_mmc_data = {
+ .hclk = 33000000,
+ .set_pwr = tc6393xb_mmc_pwr,
+ .set_no_clk_div = tc6393xb_mmc_clk_div,
+};
+
static struct mfd_cell __devinitdata tc6393xb_cells[] = {
[TC6393XB_CELL_NAND] = {
.name = "tmio-nand",
@@ -355,6 +390,8 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = {
},
[TC6393XB_CELL_MMC] = {
.name = "tmio-mmc",
+ .enable = tc6393xb_mmc_enable,
+ .resume = tc6393xb_mmc_resume,
.driver_data = &tc6393xb_mmc_data,
.num_resources = ARRAY_SIZE(tc6393xb_mmc_resources),
.resources = tc6393xb_mmc_resources,
@@ -836,3 +873,4 @@ MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov and Dirk Opfer");
MODULE_DESCRIPTION("tc6393xb Toshiba Mobile IO Controller");
MODULE_ALIAS("platform:tc6393xb");
+
diff --git a/drivers/mfd/tmio_core.c b/drivers/mfd/tmio_core.c
new file mode 100644
index 000000000000..f88b06393540
--- /dev/null
+++ b/drivers/mfd/tmio_core.c
@@ -0,0 +1,62 @@
+/*
+ * Toshiba TC6393XB SoC support
+ *
+ * Copyright(c) 2009 Ian Molton <spyro@f2s.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/mfd/tmio.h>
+
+static int shift;
+
+int tmio_core_mmc_enable(void __iomem *cnf, unsigned long base)
+{
+ /* Enable the MMC/SD Control registers */
+ sd_config_write16(cnf, shift, CNF_CMD, SDCREN);
+ sd_config_write32(cnf, shift, CNF_CTL_BASE, base & 0xfffe);
+
+ /* Disable SD power during suspend */
+ sd_config_write8(cnf, shift, CNF_PWR_CTL_3, 0x01);
+
+ /* The below is required but why? FIXME */
+ sd_config_write8(cnf, shift, CNF_STOP_CLK_CTL, 0x1f);
+
+ /* Power down SD bus*/
+ sd_config_write8(cnf, shift, CNF_PWR_CTL_2, 0x00);
+
+ return 0;
+}
+EXPORT_SYMBOL(tmio_core_mmc_enable);
+
+int tmio_core_mmc_resume(void __iomem *cnf, unsigned long base)
+{
+
+ /* Enable the MMC/SD Control registers */
+ sd_config_write16(cnf, shift, CNF_CMD, SDCREN);
+ sd_config_write32(cnf, shift, CNF_CTL_BASE, base & 0xfffe);
+
+ return 0;
+}
+EXPORT_SYMBOL(tmio_core_mmc_resume);
+
+void tmio_core_mmc_pwr(void __iomem *cnf, int state)
+{
+ sd_config_write8(cnf, shift, CNF_PWR_CTL_2, state ? 0x02 : 0x00);
+}
+EXPORT_SYMBOL(tmio_core_mmc_pwr);
+
+void tmio_core_mmc_clk_div(void __iomem *cnf, int state)
+{
+ sd_config_write8(cnf, shift, CNF_SD_CLK_MODE, state ? 1 : 0);
+}
+EXPORT_SYMBOL(tmio_core_mmc_clk_div);
+
+void tmio_core_set_bus_shift(int bus_shift)
+{
+ shift = bus_shift;
+}
+EXPORT_SYMBOL(tmio_core_set_bus_shift);
+
diff --git a/drivers/mfd/twl4030-core.c b/drivers/mfd/twl4030-core.c
index e832e975da60..548711db29d6 100644
--- a/drivers/mfd/twl4030-core.c
+++ b/drivers/mfd/twl4030-core.c
@@ -39,7 +39,7 @@
#include <linux/i2c/twl4030.h>
#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-#include <mach/cpu.h>
+#include <plat/cpu.h>
#endif
/*
@@ -177,6 +177,7 @@
#define HFCLK_FREQ_26_MHZ (2 << 0)
#define HFCLK_FREQ_38p4_MHZ (3 << 0)
#define HIGH_PERF_SQ (1 << 3)
+#define CK32K_LOWPWR_EN (1 << 7)
/* chip-specific feature flags, for i2c_device_id.driver_data */
@@ -681,7 +682,8 @@ static inline int __init unprotect_pm_master(void)
return e;
}
-static void clocks_init(struct device *dev)
+static void clocks_init(struct device *dev,
+ struct twl4030_clock_init_data *clock)
{
int e = 0;
struct clk *osc;
@@ -728,6 +730,9 @@ static void clocks_init(struct device *dev)
}
ctrl |= HIGH_PERF_SQ;
+ if (clock && clock->ck32k_lowpwr_enable)
+ ctrl |= CK32K_LOWPWR_EN;
+
e |= unprotect_pm_master();
/* effect->MADC+USB ck en */
e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, ctrl, R_CFG_BOOT);
@@ -795,20 +800,18 @@ twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id)
twl->client = i2c_new_dummy(client->adapter,
twl->address);
if (!twl->client) {
- dev_err(&twl->client->dev,
+ dev_err(&client->dev,
"can't attach client %d\n", i);
status = -ENOMEM;
goto fail;
}
- strlcpy(twl->client->name, id->name,
- sizeof(twl->client->name));
}
mutex_init(&twl->xfer_lock);
}
inuse = true;
/* setup clock framework */
- clocks_init(&client->dev);
+ clocks_init(&client->dev, pdata->clock);
/* load power event scripts */
if (twl_has_power() && pdata->power)
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index d423e0c4176b..3048f18e0419 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -67,19 +67,35 @@ static u8 twl4030_start_script_address = 0x2b;
#define R_KEY_1 0xC0
#define R_KEY_2 0x0C
-/* resource configuration registers */
-
-#define DEVGROUP_OFFSET 0
+/* resource configuration registers
+ <RESOURCE>_DEV_GRP at address 'n+0'
+ <RESOURCE>_TYPE at address 'n+1'
+ <RESOURCE>_REMAP at address 'n+2'
+ <RESOURCE>_DEDICATED at address 'n+3'
+*/
+#define DEV_GRP_OFFSET 0
#define TYPE_OFFSET 1
+#define REMAP_OFFSET 2
+#define DEDICATED_OFFSET 3
+
+/* Bit positions in the registers */
+
+/* <RESOURCE>_DEV_GRP */
+#define DEV_GRP_SHIFT 5
+#define DEV_GRP_MASK (7 << DEV_GRP_SHIFT)
-/* Bit positions */
-#define DEVGROUP_SHIFT 5
-#define DEVGROUP_MASK (7 << DEVGROUP_SHIFT)
+/* <RESOURCE>_TYPE */
#define TYPE_SHIFT 0
#define TYPE_MASK (7 << TYPE_SHIFT)
#define TYPE2_SHIFT 3
#define TYPE2_MASK (3 << TYPE2_SHIFT)
+/* <RESOURCE>_REMAP */
+#define SLEEP_STATE_SHIFT 0
+#define SLEEP_STATE_MASK (0xf << SLEEP_STATE_SHIFT)
+#define OFF_STATE_SHIFT 4
+#define OFF_STATE_MASK (0xf << OFF_STATE_SHIFT)
+
static u8 res_config_addrs[] = {
[RES_VAUX1] = 0x17,
[RES_VAUX2] = 0x1b,
@@ -317,6 +333,7 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig)
int err;
u8 type;
u8 grp;
+ u8 remap;
if (rconfig->resource > TOTAL_RESOURCES) {
pr_err("TWL4030 Resource %d does not exist\n",
@@ -328,18 +345,18 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig)
/* Set resource group */
err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &grp,
- rconfig_addr + DEVGROUP_OFFSET);
+ rconfig_addr + DEV_GRP_OFFSET);
if (err) {
pr_err("TWL4030 Resource %d group could not be read\n",
rconfig->resource);
return err;
}
- if (rconfig->devgroup >= 0) {
- grp &= ~DEVGROUP_MASK;
- grp |= rconfig->devgroup << DEVGROUP_SHIFT;
+ if (rconfig->devgroup != TWL4030_RESCONFIG_UNDEF) {
+ grp &= ~DEV_GRP_MASK;
+ grp |= rconfig->devgroup << DEV_GRP_SHIFT;
err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
- grp, rconfig_addr + DEVGROUP_OFFSET);
+ grp, rconfig_addr + DEV_GRP_OFFSET);
if (err < 0) {
pr_err("TWL4030 failed to program devgroup\n");
return err;
@@ -355,12 +372,12 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig)
return err;
}
- if (rconfig->type >= 0) {
+ if (rconfig->type != TWL4030_RESCONFIG_UNDEF) {
type &= ~TYPE_MASK;
type |= rconfig->type << TYPE_SHIFT;
}
- if (rconfig->type2 >= 0) {
+ if (rconfig->type2 != TWL4030_RESCONFIG_UNDEF) {
type &= ~TYPE2_MASK;
type |= rconfig->type2 << TYPE2_SHIFT;
}
@@ -372,6 +389,33 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig)
return err;
}
+ /* Set remap states */
+ err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &remap,
+ rconfig_addr + REMAP_OFFSET);
+ if (err < 0) {
+ pr_err("TWL4030 Resource %d remap could not be read\n",
+ rconfig->resource);
+ return err;
+ }
+
+ if (rconfig->remap_off != TWL4030_RESCONFIG_UNDEF) {
+ remap &= ~OFF_STATE_MASK;
+ remap |= rconfig->remap_off << OFF_STATE_SHIFT;
+ }
+
+ if (rconfig->remap_sleep != TWL4030_RESCONFIG_UNDEF) {
+ remap &= ~SLEEP_STATE_MASK;
+ remap |= rconfig->remap_off << SLEEP_STATE_SHIFT;
+ }
+
+ err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ remap,
+ rconfig_addr + REMAP_OFFSET);
+ if (err < 0) {
+ pr_err("TWL4030 failed to program remap\n");
+ return err;
+ }
+
return 0;
}
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 49b7885c2702..e9ce8c66b495 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -90,9 +90,10 @@ int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL] = {
EXPORT_SYMBOL_GPL(wm831x_isinkv_values);
enum wm831x_parent {
- WM8310 = 0,
- WM8311 = 1,
- WM8312 = 2,
+ WM8310 = 0x8310,
+ WM8311 = 0x8311,
+ WM8312 = 0x8312,
+ WM8320 = 0x8320,
};
static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
@@ -478,6 +479,20 @@ static struct resource wm831x_dcdc4_resources[] = {
},
};
+static struct resource wm8320_dcdc4_buck_resources[] = {
+ {
+ .start = WM831X_DC4_CONTROL,
+ .end = WM832X_DC4_SLEEP_CONTROL,
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .name = "UV",
+ .start = WM831X_IRQ_UV_DC4,
+ .end = WM831X_IRQ_UV_DC4,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
static struct resource wm831x_gpio_resources[] = {
{
.start = WM831X_IRQ_GPIO_1,
@@ -1237,6 +1252,137 @@ static struct mfd_cell wm8312_devs[] = {
},
};
+static struct mfd_cell wm8320_devs[] = {
+ {
+ .name = "wm831x-backup",
+ },
+ {
+ .name = "wm831x-buckv",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
+ .resources = wm831x_dcdc1_resources,
+ },
+ {
+ .name = "wm831x-buckv",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
+ .resources = wm831x_dcdc2_resources,
+ },
+ {
+ .name = "wm831x-buckp",
+ .id = 3,
+ .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
+ .resources = wm831x_dcdc3_resources,
+ },
+ {
+ .name = "wm831x-buckp",
+ .id = 4,
+ .num_resources = ARRAY_SIZE(wm8320_dcdc4_buck_resources),
+ .resources = wm8320_dcdc4_buck_resources,
+ },
+ {
+ .name = "wm831x-gpio",
+ .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
+ .resources = wm831x_gpio_resources,
+ },
+ {
+ .name = "wm831x-hwmon",
+ },
+ {
+ .name = "wm831x-ldo",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
+ .resources = wm831x_ldo1_resources,
+ },
+ {
+ .name = "wm831x-ldo",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
+ .resources = wm831x_ldo2_resources,
+ },
+ {
+ .name = "wm831x-ldo",
+ .id = 3,
+ .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
+ .resources = wm831x_ldo3_resources,
+ },
+ {
+ .name = "wm831x-ldo",
+ .id = 4,
+ .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
+ .resources = wm831x_ldo4_resources,
+ },
+ {
+ .name = "wm831x-ldo",
+ .id = 5,
+ .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
+ .resources = wm831x_ldo5_resources,
+ },
+ {
+ .name = "wm831x-ldo",
+ .id = 6,
+ .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
+ .resources = wm831x_ldo6_resources,
+ },
+ {
+ .name = "wm831x-aldo",
+ .id = 7,
+ .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
+ .resources = wm831x_ldo7_resources,
+ },
+ {
+ .name = "wm831x-aldo",
+ .id = 8,
+ .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
+ .resources = wm831x_ldo8_resources,
+ },
+ {
+ .name = "wm831x-aldo",
+ .id = 9,
+ .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
+ .resources = wm831x_ldo9_resources,
+ },
+ {
+ .name = "wm831x-aldo",
+ .id = 10,
+ .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
+ .resources = wm831x_ldo10_resources,
+ },
+ {
+ .name = "wm831x-alive-ldo",
+ .id = 11,
+ .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
+ .resources = wm831x_ldo11_resources,
+ },
+ {
+ .name = "wm831x-on",
+ .num_resources = ARRAY_SIZE(wm831x_on_resources),
+ .resources = wm831x_on_resources,
+ },
+ {
+ .name = "wm831x-rtc",
+ .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
+ .resources = wm831x_rtc_resources,
+ },
+ {
+ .name = "wm831x-status",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(wm831x_status1_resources),
+ .resources = wm831x_status1_resources,
+ },
+ {
+ .name = "wm831x-status",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(wm831x_status2_resources),
+ .resources = wm831x_status2_resources,
+ },
+ {
+ .name = "wm831x-watchdog",
+ .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
+ .resources = wm831x_wdt_resources,
+ },
+};
+
static struct mfd_cell backlight_devs[] = {
{
.name = "wm831x-backlight",
@@ -1282,50 +1428,37 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
goto err;
}
+ /* Some engineering samples do not have the ID set, rely on
+ * the device being registered correctly.
+ */
+ if (ret == 0) {
+ dev_info(wm831x->dev, "Device is an engineering sample\n");
+ ret = id;
+ }
+
switch (ret) {
- case 0x8310:
+ case WM8310:
parent = WM8310;
- switch (rev) {
- case 0:
- dev_info(wm831x->dev, "WM8310 revision %c\n",
- 'A' + rev);
- break;
- }
+ wm831x->num_gpio = 16;
+ dev_info(wm831x->dev, "WM8310 revision %c\n", 'A' + rev);
break;
- case 0x8311:
+ case WM8311:
parent = WM8311;
- switch (rev) {
- case 0:
- dev_info(wm831x->dev, "WM8311 revision %c\n",
- 'A' + rev);
- break;
- }
+ wm831x->num_gpio = 16;
+ dev_info(wm831x->dev, "WM8311 revision %c\n", 'A' + rev);
break;
- case 0x8312:
+ case WM8312:
parent = WM8312;
- switch (rev) {
- case 0:
- dev_info(wm831x->dev, "WM8312 revision %c\n",
- 'A' + rev);
- break;
- }
+ wm831x->num_gpio = 16;
+ dev_info(wm831x->dev, "WM8312 revision %c\n", 'A' + rev);
break;
- case 0:
- /* Some engineering samples do not have the ID set,
- * rely on the device being registered correctly.
- * This will need revisiting for future devices with
- * multiple dies.
- */
- parent = id;
- switch (rev) {
- case 0:
- dev_info(wm831x->dev, "WM831%d ES revision %c\n",
- parent, 'A' + rev);
- break;
- }
+ case WM8320:
+ parent = WM8320;
+ wm831x->num_gpio = 12;
+ dev_info(wm831x->dev, "WM8320 revision %c\n", 'A' + rev);
break;
default:
@@ -1338,7 +1471,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
* current parts.
*/
if (parent != id)
- dev_warn(wm831x->dev, "Device was registered as a WM831%lu\n",
+ dev_warn(wm831x->dev, "Device was registered as a WM%lx\n",
id);
/* Bootstrap the user key */
@@ -1386,6 +1519,12 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
NULL, 0);
break;
+ case WM8320:
+ ret = mfd_add_devices(wm831x->dev, -1,
+ wm8320_devs, ARRAY_SIZE(wm8320_devs),
+ NULL, 0);
+ break;
+
default:
/* If this happens the bus probe function is buggy */
BUG();
@@ -1511,6 +1650,7 @@ static const struct i2c_device_id wm831x_i2c_id[] = {
{ "wm8310", WM8310 },
{ "wm8311", WM8311 },
{ "wm8312", WM8312 },
+ { "wm8320", WM8320 },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c
index d3015dfb9134..ac056ea6b66e 100644
--- a/drivers/mfd/wm831x-irq.c
+++ b/drivers/mfd/wm831x-irq.c
@@ -507,6 +507,8 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
{
int i, ret;
+ mutex_init(&wm831x->irq_lock);
+
if (!irq) {
dev_warn(wm831x->dev,
"No interrupt specified - functionality limited\n");
@@ -521,7 +523,6 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
}
wm831x->irq = irq;
- mutex_init(&wm831x->irq_lock);
INIT_WORK(&wm831x->irq_work, wm831x_irq_worker);
/* Mask the individual interrupt sources */
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c
index ba27c9dc1ad3..242795feb90d 100644
--- a/drivers/mfd/wm8350-core.c
+++ b/drivers/mfd/wm8350-core.c
@@ -337,733 +337,6 @@ int wm8350_reg_unlock(struct wm8350 *wm8350)
}
EXPORT_SYMBOL_GPL(wm8350_reg_unlock);
-static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq)
-{
- mutex_lock(&wm8350->irq_mutex);
-
- if (wm8350->irq[irq].handler)
- wm8350->irq[irq].handler(wm8350, irq, wm8350->irq[irq].data);
- else {
- dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n",
- irq);
- wm8350_mask_irq(wm8350, irq);
- }
-
- mutex_unlock(&wm8350->irq_mutex);
-}
-
-/*
- * This is a threaded IRQ handler so can access I2C/SPI. Since all
- * interrupts are clear on read the IRQ line will be reasserted and
- * the physical IRQ will be handled again if another interrupt is
- * asserted while we run - in the normal course of events this is a
- * rare occurrence so we save I2C/SPI reads.
- */
-static irqreturn_t wm8350_irq(int irq, void *data)
-{
- struct wm8350 *wm8350 = data;
- u16 level_one, status1, status2, comp;
-
- /* TODO: Use block reads to improve performance? */
- level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS)
- & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK);
- status1 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_1)
- & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_1_MASK);
- status2 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_2)
- & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_2_MASK);
- comp = wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS)
- & ~wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK);
-
- /* over current */
- if (level_one & WM8350_OC_INT) {
- u16 oc;
-
- oc = wm8350_reg_read(wm8350, WM8350_OVER_CURRENT_INT_STATUS);
- oc &= ~wm8350_reg_read(wm8350,
- WM8350_OVER_CURRENT_INT_STATUS_MASK);
-
- if (oc & WM8350_OC_LS_EINT) /* limit switch */
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_OC_LS);
- }
-
- /* under voltage */
- if (level_one & WM8350_UV_INT) {
- u16 uv;
-
- uv = wm8350_reg_read(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS);
- uv &= ~wm8350_reg_read(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK);
-
- if (uv & WM8350_UV_DC1_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC1);
- if (uv & WM8350_UV_DC2_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC2);
- if (uv & WM8350_UV_DC3_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC3);
- if (uv & WM8350_UV_DC4_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC4);
- if (uv & WM8350_UV_DC5_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC5);
- if (uv & WM8350_UV_DC6_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC6);
- if (uv & WM8350_UV_LDO1_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO1);
- if (uv & WM8350_UV_LDO2_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO2);
- if (uv & WM8350_UV_LDO3_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO3);
- if (uv & WM8350_UV_LDO4_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO4);
- }
-
- /* charger, RTC */
- if (status1) {
- if (status1 & WM8350_CHG_BAT_HOT_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_CHG_BAT_HOT);
- if (status1 & WM8350_CHG_BAT_COLD_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_CHG_BAT_COLD);
- if (status1 & WM8350_CHG_BAT_FAIL_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_CHG_BAT_FAIL);
- if (status1 & WM8350_CHG_TO_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_TO);
- if (status1 & WM8350_CHG_END_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_END);
- if (status1 & WM8350_CHG_START_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_START);
- if (status1 & WM8350_CHG_FAST_RDY_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_CHG_FAST_RDY);
- if (status1 & WM8350_CHG_VBATT_LT_3P9_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_CHG_VBATT_LT_3P9);
- if (status1 & WM8350_CHG_VBATT_LT_3P1_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_CHG_VBATT_LT_3P1);
- if (status1 & WM8350_CHG_VBATT_LT_2P85_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_CHG_VBATT_LT_2P85);
- if (status1 & WM8350_RTC_ALM_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_ALM);
- if (status1 & WM8350_RTC_SEC_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_SEC);
- if (status1 & WM8350_RTC_PER_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_PER);
- }
-
- /* current sink, system, aux adc */
- if (status2) {
- if (status2 & WM8350_CS1_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS1);
- if (status2 & WM8350_CS2_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS2);
-
- if (status2 & WM8350_SYS_HYST_COMP_FAIL_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_SYS_HYST_COMP_FAIL);
- if (status2 & WM8350_SYS_CHIP_GT115_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_SYS_CHIP_GT115);
- if (status2 & WM8350_SYS_CHIP_GT140_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_SYS_CHIP_GT140);
- if (status2 & WM8350_SYS_WDOG_TO_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_SYS_WDOG_TO);
-
- if (status2 & WM8350_AUXADC_DATARDY_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_AUXADC_DATARDY);
- if (status2 & WM8350_AUXADC_DCOMP4_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_AUXADC_DCOMP4);
- if (status2 & WM8350_AUXADC_DCOMP3_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_AUXADC_DCOMP3);
- if (status2 & WM8350_AUXADC_DCOMP2_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_AUXADC_DCOMP2);
- if (status2 & WM8350_AUXADC_DCOMP1_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_AUXADC_DCOMP1);
-
- if (status2 & WM8350_USB_LIMIT_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_USB_LIMIT);
- }
-
- /* wake, codec, ext */
- if (comp) {
- if (comp & WM8350_WKUP_OFF_STATE_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_WKUP_OFF_STATE);
- if (comp & WM8350_WKUP_HIB_STATE_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_WKUP_HIB_STATE);
- if (comp & WM8350_WKUP_CONV_FAULT_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_WKUP_CONV_FAULT);
- if (comp & WM8350_WKUP_WDOG_RST_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_WKUP_WDOG_RST);
- if (comp & WM8350_WKUP_GP_PWR_ON_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_WKUP_GP_PWR_ON);
- if (comp & WM8350_WKUP_ONKEY_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_WKUP_ONKEY);
- if (comp & WM8350_WKUP_GP_WAKEUP_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_WKUP_GP_WAKEUP);
-
- if (comp & WM8350_CODEC_JCK_DET_L_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_CODEC_JCK_DET_L);
- if (comp & WM8350_CODEC_JCK_DET_R_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_CODEC_JCK_DET_R);
- if (comp & WM8350_CODEC_MICSCD_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_CODEC_MICSCD);
- if (comp & WM8350_CODEC_MICD_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_CODEC_MICD);
-
- if (comp & WM8350_EXT_USB_FB_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_USB_FB);
- if (comp & WM8350_EXT_WALL_FB_EINT)
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_EXT_WALL_FB);
- if (comp & WM8350_EXT_BAT_FB_EINT)
- wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_BAT_FB);
- }
-
- if (level_one & WM8350_GP_INT) {
- int i;
- u16 gpio;
-
- gpio = wm8350_reg_read(wm8350, WM8350_GPIO_INT_STATUS);
- gpio &= ~wm8350_reg_read(wm8350,
- WM8350_GPIO_INT_STATUS_MASK);
-
- for (i = 0; i < 12; i++) {
- if (gpio & (1 << i))
- wm8350_irq_call_handler(wm8350,
- WM8350_IRQ_GPIO(i));
- }
- }
-
- return IRQ_HANDLED;
-}
-
-int wm8350_register_irq(struct wm8350 *wm8350, int irq,
- void (*handler) (struct wm8350 *, int, void *),
- void *data)
-{
- if (irq < 0 || irq > WM8350_NUM_IRQ || !handler)
- return -EINVAL;
-
- if (wm8350->irq[irq].handler)
- return -EBUSY;
-
- mutex_lock(&wm8350->irq_mutex);
- wm8350->irq[irq].handler = handler;
- wm8350->irq[irq].data = data;
- mutex_unlock(&wm8350->irq_mutex);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(wm8350_register_irq);
-
-int wm8350_free_irq(struct wm8350 *wm8350, int irq)
-{
- if (irq < 0 || irq > WM8350_NUM_IRQ)
- return -EINVAL;
-
- mutex_lock(&wm8350->irq_mutex);
- wm8350->irq[irq].handler = NULL;
- mutex_unlock(&wm8350->irq_mutex);
- return 0;
-}
-EXPORT_SYMBOL_GPL(wm8350_free_irq);
-
-int wm8350_mask_irq(struct wm8350 *wm8350, int irq)
-{
- switch (irq) {
- case WM8350_IRQ_CHG_BAT_HOT:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_BAT_HOT_EINT);
- case WM8350_IRQ_CHG_BAT_COLD:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_BAT_COLD_EINT);
- case WM8350_IRQ_CHG_BAT_FAIL:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_BAT_FAIL_EINT);
- case WM8350_IRQ_CHG_TO:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_TO_EINT);
- case WM8350_IRQ_CHG_END:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_END_EINT);
- case WM8350_IRQ_CHG_START:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_START_EINT);
- case WM8350_IRQ_CHG_FAST_RDY:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_FAST_RDY_EINT);
- case WM8350_IRQ_RTC_PER:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_RTC_PER_EINT);
- case WM8350_IRQ_RTC_SEC:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_RTC_SEC_EINT);
- case WM8350_IRQ_RTC_ALM:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_RTC_ALM_EINT);
- case WM8350_IRQ_CHG_VBATT_LT_3P9:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_VBATT_LT_3P9_EINT);
- case WM8350_IRQ_CHG_VBATT_LT_3P1:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_VBATT_LT_3P1_EINT);
- case WM8350_IRQ_CHG_VBATT_LT_2P85:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_VBATT_LT_2P85_EINT);
- case WM8350_IRQ_CS1:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_CS1_EINT);
- case WM8350_IRQ_CS2:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_CS2_EINT);
- case WM8350_IRQ_USB_LIMIT:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_USB_LIMIT_EINT);
- case WM8350_IRQ_AUXADC_DATARDY:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_AUXADC_DATARDY_EINT);
- case WM8350_IRQ_AUXADC_DCOMP4:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_AUXADC_DCOMP4_EINT);
- case WM8350_IRQ_AUXADC_DCOMP3:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_AUXADC_DCOMP3_EINT);
- case WM8350_IRQ_AUXADC_DCOMP2:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_AUXADC_DCOMP2_EINT);
- case WM8350_IRQ_AUXADC_DCOMP1:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_AUXADC_DCOMP1_EINT);
- case WM8350_IRQ_SYS_HYST_COMP_FAIL:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_SYS_HYST_COMP_FAIL_EINT);
- case WM8350_IRQ_SYS_CHIP_GT115:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_SYS_CHIP_GT115_EINT);
- case WM8350_IRQ_SYS_CHIP_GT140:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_SYS_CHIP_GT140_EINT);
- case WM8350_IRQ_SYS_WDOG_TO:
- return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_SYS_WDOG_TO_EINT);
- case WM8350_IRQ_UV_LDO4:
- return wm8350_set_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_LDO4_EINT);
- case WM8350_IRQ_UV_LDO3:
- return wm8350_set_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_LDO3_EINT);
- case WM8350_IRQ_UV_LDO2:
- return wm8350_set_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_LDO2_EINT);
- case WM8350_IRQ_UV_LDO1:
- return wm8350_set_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_LDO1_EINT);
- case WM8350_IRQ_UV_DC6:
- return wm8350_set_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_DC6_EINT);
- case WM8350_IRQ_UV_DC5:
- return wm8350_set_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_DC5_EINT);
- case WM8350_IRQ_UV_DC4:
- return wm8350_set_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_DC4_EINT);
- case WM8350_IRQ_UV_DC3:
- return wm8350_set_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_DC3_EINT);
- case WM8350_IRQ_UV_DC2:
- return wm8350_set_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_DC2_EINT);
- case WM8350_IRQ_UV_DC1:
- return wm8350_set_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_DC1_EINT);
- case WM8350_IRQ_OC_LS:
- return wm8350_set_bits(wm8350,
- WM8350_OVER_CURRENT_INT_STATUS_MASK,
- WM8350_IM_OC_LS_EINT);
- case WM8350_IRQ_EXT_USB_FB:
- return wm8350_set_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_EXT_USB_FB_EINT);
- case WM8350_IRQ_EXT_WALL_FB:
- return wm8350_set_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_EXT_WALL_FB_EINT);
- case WM8350_IRQ_EXT_BAT_FB:
- return wm8350_set_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_EXT_BAT_FB_EINT);
- case WM8350_IRQ_CODEC_JCK_DET_L:
- return wm8350_set_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_CODEC_JCK_DET_L_EINT);
- case WM8350_IRQ_CODEC_JCK_DET_R:
- return wm8350_set_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_CODEC_JCK_DET_R_EINT);
- case WM8350_IRQ_CODEC_MICSCD:
- return wm8350_set_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_CODEC_MICSCD_EINT);
- case WM8350_IRQ_CODEC_MICD:
- return wm8350_set_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_CODEC_MICD_EINT);
- case WM8350_IRQ_WKUP_OFF_STATE:
- return wm8350_set_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_WKUP_OFF_STATE_EINT);
- case WM8350_IRQ_WKUP_HIB_STATE:
- return wm8350_set_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_WKUP_HIB_STATE_EINT);
- case WM8350_IRQ_WKUP_CONV_FAULT:
- return wm8350_set_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_WKUP_CONV_FAULT_EINT);
- case WM8350_IRQ_WKUP_WDOG_RST:
- return wm8350_set_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_WKUP_OFF_STATE_EINT);
- case WM8350_IRQ_WKUP_GP_PWR_ON:
- return wm8350_set_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_WKUP_GP_PWR_ON_EINT);
- case WM8350_IRQ_WKUP_ONKEY:
- return wm8350_set_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_WKUP_ONKEY_EINT);
- case WM8350_IRQ_WKUP_GP_WAKEUP:
- return wm8350_set_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_WKUP_GP_WAKEUP_EINT);
- case WM8350_IRQ_GPIO(0):
- return wm8350_set_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP0_EINT);
- case WM8350_IRQ_GPIO(1):
- return wm8350_set_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP1_EINT);
- case WM8350_IRQ_GPIO(2):
- return wm8350_set_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP2_EINT);
- case WM8350_IRQ_GPIO(3):
- return wm8350_set_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP3_EINT);
- case WM8350_IRQ_GPIO(4):
- return wm8350_set_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP4_EINT);
- case WM8350_IRQ_GPIO(5):
- return wm8350_set_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP5_EINT);
- case WM8350_IRQ_GPIO(6):
- return wm8350_set_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP6_EINT);
- case WM8350_IRQ_GPIO(7):
- return wm8350_set_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP7_EINT);
- case WM8350_IRQ_GPIO(8):
- return wm8350_set_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP8_EINT);
- case WM8350_IRQ_GPIO(9):
- return wm8350_set_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP9_EINT);
- case WM8350_IRQ_GPIO(10):
- return wm8350_set_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP10_EINT);
- case WM8350_IRQ_GPIO(11):
- return wm8350_set_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP11_EINT);
- case WM8350_IRQ_GPIO(12):
- return wm8350_set_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP12_EINT);
- default:
- dev_warn(wm8350->dev, "Attempting to mask unknown IRQ %d\n",
- irq);
- return -EINVAL;
- }
- return 0;
-}
-EXPORT_SYMBOL_GPL(wm8350_mask_irq);
-
-int wm8350_unmask_irq(struct wm8350 *wm8350, int irq)
-{
- switch (irq) {
- case WM8350_IRQ_CHG_BAT_HOT:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_BAT_HOT_EINT);
- case WM8350_IRQ_CHG_BAT_COLD:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_BAT_COLD_EINT);
- case WM8350_IRQ_CHG_BAT_FAIL:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_BAT_FAIL_EINT);
- case WM8350_IRQ_CHG_TO:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_TO_EINT);
- case WM8350_IRQ_CHG_END:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_END_EINT);
- case WM8350_IRQ_CHG_START:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_START_EINT);
- case WM8350_IRQ_CHG_FAST_RDY:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_FAST_RDY_EINT);
- case WM8350_IRQ_RTC_PER:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_RTC_PER_EINT);
- case WM8350_IRQ_RTC_SEC:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_RTC_SEC_EINT);
- case WM8350_IRQ_RTC_ALM:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_RTC_ALM_EINT);
- case WM8350_IRQ_CHG_VBATT_LT_3P9:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_VBATT_LT_3P9_EINT);
- case WM8350_IRQ_CHG_VBATT_LT_3P1:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_VBATT_LT_3P1_EINT);
- case WM8350_IRQ_CHG_VBATT_LT_2P85:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
- WM8350_IM_CHG_VBATT_LT_2P85_EINT);
- case WM8350_IRQ_CS1:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_CS1_EINT);
- case WM8350_IRQ_CS2:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_CS2_EINT);
- case WM8350_IRQ_USB_LIMIT:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_USB_LIMIT_EINT);
- case WM8350_IRQ_AUXADC_DATARDY:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_AUXADC_DATARDY_EINT);
- case WM8350_IRQ_AUXADC_DCOMP4:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_AUXADC_DCOMP4_EINT);
- case WM8350_IRQ_AUXADC_DCOMP3:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_AUXADC_DCOMP3_EINT);
- case WM8350_IRQ_AUXADC_DCOMP2:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_AUXADC_DCOMP2_EINT);
- case WM8350_IRQ_AUXADC_DCOMP1:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_AUXADC_DCOMP1_EINT);
- case WM8350_IRQ_SYS_HYST_COMP_FAIL:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_SYS_HYST_COMP_FAIL_EINT);
- case WM8350_IRQ_SYS_CHIP_GT115:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_SYS_CHIP_GT115_EINT);
- case WM8350_IRQ_SYS_CHIP_GT140:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_SYS_CHIP_GT140_EINT);
- case WM8350_IRQ_SYS_WDOG_TO:
- return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
- WM8350_IM_SYS_WDOG_TO_EINT);
- case WM8350_IRQ_UV_LDO4:
- return wm8350_clear_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_LDO4_EINT);
- case WM8350_IRQ_UV_LDO3:
- return wm8350_clear_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_LDO3_EINT);
- case WM8350_IRQ_UV_LDO2:
- return wm8350_clear_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_LDO2_EINT);
- case WM8350_IRQ_UV_LDO1:
- return wm8350_clear_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_LDO1_EINT);
- case WM8350_IRQ_UV_DC6:
- return wm8350_clear_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_DC6_EINT);
- case WM8350_IRQ_UV_DC5:
- return wm8350_clear_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_DC5_EINT);
- case WM8350_IRQ_UV_DC4:
- return wm8350_clear_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_DC4_EINT);
- case WM8350_IRQ_UV_DC3:
- return wm8350_clear_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_DC3_EINT);
- case WM8350_IRQ_UV_DC2:
- return wm8350_clear_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_DC2_EINT);
- case WM8350_IRQ_UV_DC1:
- return wm8350_clear_bits(wm8350,
- WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
- WM8350_IM_UV_DC1_EINT);
- case WM8350_IRQ_OC_LS:
- return wm8350_clear_bits(wm8350,
- WM8350_OVER_CURRENT_INT_STATUS_MASK,
- WM8350_IM_OC_LS_EINT);
- case WM8350_IRQ_EXT_USB_FB:
- return wm8350_clear_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_EXT_USB_FB_EINT);
- case WM8350_IRQ_EXT_WALL_FB:
- return wm8350_clear_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_EXT_WALL_FB_EINT);
- case WM8350_IRQ_EXT_BAT_FB:
- return wm8350_clear_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_EXT_BAT_FB_EINT);
- case WM8350_IRQ_CODEC_JCK_DET_L:
- return wm8350_clear_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_CODEC_JCK_DET_L_EINT);
- case WM8350_IRQ_CODEC_JCK_DET_R:
- return wm8350_clear_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_CODEC_JCK_DET_R_EINT);
- case WM8350_IRQ_CODEC_MICSCD:
- return wm8350_clear_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_CODEC_MICSCD_EINT);
- case WM8350_IRQ_CODEC_MICD:
- return wm8350_clear_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_CODEC_MICD_EINT);
- case WM8350_IRQ_WKUP_OFF_STATE:
- return wm8350_clear_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_WKUP_OFF_STATE_EINT);
- case WM8350_IRQ_WKUP_HIB_STATE:
- return wm8350_clear_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_WKUP_HIB_STATE_EINT);
- case WM8350_IRQ_WKUP_CONV_FAULT:
- return wm8350_clear_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_WKUP_CONV_FAULT_EINT);
- case WM8350_IRQ_WKUP_WDOG_RST:
- return wm8350_clear_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_WKUP_OFF_STATE_EINT);
- case WM8350_IRQ_WKUP_GP_PWR_ON:
- return wm8350_clear_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_WKUP_GP_PWR_ON_EINT);
- case WM8350_IRQ_WKUP_ONKEY:
- return wm8350_clear_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_WKUP_ONKEY_EINT);
- case WM8350_IRQ_WKUP_GP_WAKEUP:
- return wm8350_clear_bits(wm8350,
- WM8350_COMPARATOR_INT_STATUS_MASK,
- WM8350_IM_WKUP_GP_WAKEUP_EINT);
- case WM8350_IRQ_GPIO(0):
- return wm8350_clear_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP0_EINT);
- case WM8350_IRQ_GPIO(1):
- return wm8350_clear_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP1_EINT);
- case WM8350_IRQ_GPIO(2):
- return wm8350_clear_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP2_EINT);
- case WM8350_IRQ_GPIO(3):
- return wm8350_clear_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP3_EINT);
- case WM8350_IRQ_GPIO(4):
- return wm8350_clear_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP4_EINT);
- case WM8350_IRQ_GPIO(5):
- return wm8350_clear_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP5_EINT);
- case WM8350_IRQ_GPIO(6):
- return wm8350_clear_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP6_EINT);
- case WM8350_IRQ_GPIO(7):
- return wm8350_clear_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP7_EINT);
- case WM8350_IRQ_GPIO(8):
- return wm8350_clear_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP8_EINT);
- case WM8350_IRQ_GPIO(9):
- return wm8350_clear_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP9_EINT);
- case WM8350_IRQ_GPIO(10):
- return wm8350_clear_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP10_EINT);
- case WM8350_IRQ_GPIO(11):
- return wm8350_clear_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP11_EINT);
- case WM8350_IRQ_GPIO(12):
- return wm8350_clear_bits(wm8350,
- WM8350_GPIO_INT_STATUS_MASK,
- WM8350_IM_GP12_EINT);
- default:
- dev_warn(wm8350->dev, "Attempting to unmask unknown IRQ %d\n",
- irq);
- return -EINVAL;
- }
- return 0;
-}
-EXPORT_SYMBOL_GPL(wm8350_unmask_irq);
-
int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref)
{
u16 reg, result = 0;
@@ -1409,49 +682,18 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
return ret;
}
- wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF);
- wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK, 0xFFFF);
- wm8350_reg_write(wm8350, WM8350_INT_STATUS_2_MASK, 0xFFFF);
- wm8350_reg_write(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 0xFFFF);
- wm8350_reg_write(wm8350, WM8350_GPIO_INT_STATUS_MASK, 0xFFFF);
- wm8350_reg_write(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK, 0xFFFF);
-
mutex_init(&wm8350->auxadc_mutex);
- mutex_init(&wm8350->irq_mutex);
- if (irq) {
- int flags = IRQF_ONESHOT;
-
- if (pdata && pdata->irq_high) {
- flags |= IRQF_TRIGGER_HIGH;
-
- wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
- WM8350_IRQ_POL);
- } else {
- flags |= IRQF_TRIGGER_LOW;
-
- wm8350_clear_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
- WM8350_IRQ_POL);
- }
- ret = request_threaded_irq(irq, NULL, wm8350_irq, flags,
- "wm8350", wm8350);
- if (ret != 0) {
- dev_err(wm8350->dev, "Failed to request IRQ: %d\n",
- ret);
- goto err;
- }
- } else {
- dev_err(wm8350->dev, "No IRQ configured\n");
+ ret = wm8350_irq_init(wm8350, irq, pdata);
+ if (ret < 0)
goto err;
- }
- wm8350->chip_irq = irq;
if (pdata && pdata->init) {
ret = pdata->init(wm8350);
if (ret != 0) {
dev_err(wm8350->dev, "Platform init() failed: %d\n",
ret);
- goto err;
+ goto err_irq;
}
}
@@ -1470,6 +712,8 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
return 0;
+err_irq:
+ wm8350_irq_exit(wm8350);
err:
kfree(wm8350->reg_cache);
return ret;
@@ -1493,7 +737,8 @@ void wm8350_device_exit(struct wm8350 *wm8350)
platform_device_unregister(wm8350->gpio.pdev);
platform_device_unregister(wm8350->codec.pdev);
- free_irq(wm8350->chip_irq, wm8350);
+ wm8350_irq_exit(wm8350);
+
kfree(wm8350->reg_cache);
}
EXPORT_SYMBOL_GPL(wm8350_device_exit);
diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c
new file mode 100644
index 000000000000..d9abfc94c685
--- /dev/null
+++ b/drivers/mfd/wm8350-irq.c
@@ -0,0 +1,525 @@
+/*
+ * wm8350-irq.c -- IRQ support for Wolfson WM8350
+ *
+ * Copyright 2007, 2008, 2009 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood, Mark Brown
+ *
+ * This 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/init.h>
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/audio.h>
+#include <linux/mfd/wm8350/comparator.h>
+#include <linux/mfd/wm8350/gpio.h>
+#include <linux/mfd/wm8350/pmic.h>
+#include <linux/mfd/wm8350/rtc.h>
+#include <linux/mfd/wm8350/supply.h>
+#include <linux/mfd/wm8350/wdt.h>
+
+#define WM8350_NUM_IRQ_REGS 7
+
+#define WM8350_INT_OFFSET_1 0
+#define WM8350_INT_OFFSET_2 1
+#define WM8350_POWER_UP_INT_OFFSET 2
+#define WM8350_UNDER_VOLTAGE_INT_OFFSET 3
+#define WM8350_OVER_CURRENT_INT_OFFSET 4
+#define WM8350_GPIO_INT_OFFSET 5
+#define WM8350_COMPARATOR_INT_OFFSET 6
+
+struct wm8350_irq_data {
+ int primary;
+ int reg;
+ int mask;
+ int primary_only;
+};
+
+static struct wm8350_irq_data wm8350_irqs[] = {
+ [WM8350_IRQ_OC_LS] = {
+ .primary = WM8350_OC_INT,
+ .reg = WM8350_OVER_CURRENT_INT_OFFSET,
+ .mask = WM8350_OC_LS_EINT,
+ .primary_only = 1,
+ },
+ [WM8350_IRQ_UV_DC1] = {
+ .primary = WM8350_UV_INT,
+ .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+ .mask = WM8350_UV_DC1_EINT,
+ },
+ [WM8350_IRQ_UV_DC2] = {
+ .primary = WM8350_UV_INT,
+ .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+ .mask = WM8350_UV_DC2_EINT,
+ },
+ [WM8350_IRQ_UV_DC3] = {
+ .primary = WM8350_UV_INT,
+ .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+ .mask = WM8350_UV_DC3_EINT,
+ },
+ [WM8350_IRQ_UV_DC4] = {
+ .primary = WM8350_UV_INT,
+ .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+ .mask = WM8350_UV_DC4_EINT,
+ },
+ [WM8350_IRQ_UV_DC5] = {
+ .primary = WM8350_UV_INT,
+ .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+ .mask = WM8350_UV_DC5_EINT,
+ },
+ [WM8350_IRQ_UV_DC6] = {
+ .primary = WM8350_UV_INT,
+ .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+ .mask = WM8350_UV_DC6_EINT,
+ },
+ [WM8350_IRQ_UV_LDO1] = {
+ .primary = WM8350_UV_INT,
+ .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+ .mask = WM8350_UV_LDO1_EINT,
+ },
+ [WM8350_IRQ_UV_LDO2] = {
+ .primary = WM8350_UV_INT,
+ .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+ .mask = WM8350_UV_LDO2_EINT,
+ },
+ [WM8350_IRQ_UV_LDO3] = {
+ .primary = WM8350_UV_INT,
+ .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+ .mask = WM8350_UV_LDO3_EINT,
+ },
+ [WM8350_IRQ_UV_LDO4] = {
+ .primary = WM8350_UV_INT,
+ .reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
+ .mask = WM8350_UV_LDO4_EINT,
+ },
+ [WM8350_IRQ_CHG_BAT_HOT] = {
+ .primary = WM8350_CHG_INT,
+ .reg = WM8350_INT_OFFSET_1,
+ .mask = WM8350_CHG_BAT_HOT_EINT,
+ },
+ [WM8350_IRQ_CHG_BAT_COLD] = {
+ .primary = WM8350_CHG_INT,
+ .reg = WM8350_INT_OFFSET_1,
+ .mask = WM8350_CHG_BAT_COLD_EINT,
+ },
+ [WM8350_IRQ_CHG_BAT_FAIL] = {
+ .primary = WM8350_CHG_INT,
+ .reg = WM8350_INT_OFFSET_1,
+ .mask = WM8350_CHG_BAT_FAIL_EINT,
+ },
+ [WM8350_IRQ_CHG_TO] = {
+ .primary = WM8350_CHG_INT,
+ .reg = WM8350_INT_OFFSET_1,
+ .mask = WM8350_CHG_TO_EINT,
+ },
+ [WM8350_IRQ_CHG_END] = {
+ .primary = WM8350_CHG_INT,
+ .reg = WM8350_INT_OFFSET_1,
+ .mask = WM8350_CHG_END_EINT,
+ },
+ [WM8350_IRQ_CHG_START] = {
+ .primary = WM8350_CHG_INT,
+ .reg = WM8350_INT_OFFSET_1,
+ .mask = WM8350_CHG_START_EINT,
+ },
+ [WM8350_IRQ_CHG_FAST_RDY] = {
+ .primary = WM8350_CHG_INT,
+ .reg = WM8350_INT_OFFSET_1,
+ .mask = WM8350_CHG_FAST_RDY_EINT,
+ },
+ [WM8350_IRQ_CHG_VBATT_LT_3P9] = {
+ .primary = WM8350_CHG_INT,
+ .reg = WM8350_INT_OFFSET_1,
+ .mask = WM8350_CHG_VBATT_LT_3P9_EINT,
+ },
+ [WM8350_IRQ_CHG_VBATT_LT_3P1] = {
+ .primary = WM8350_CHG_INT,
+ .reg = WM8350_INT_OFFSET_1,
+ .mask = WM8350_CHG_VBATT_LT_3P1_EINT,
+ },
+ [WM8350_IRQ_CHG_VBATT_LT_2P85] = {
+ .primary = WM8350_CHG_INT,
+ .reg = WM8350_INT_OFFSET_1,
+ .mask = WM8350_CHG_VBATT_LT_2P85_EINT,
+ },
+ [WM8350_IRQ_RTC_ALM] = {
+ .primary = WM8350_RTC_INT,
+ .reg = WM8350_INT_OFFSET_1,
+ .mask = WM8350_RTC_ALM_EINT,
+ },
+ [WM8350_IRQ_RTC_SEC] = {
+ .primary = WM8350_RTC_INT,
+ .reg = WM8350_INT_OFFSET_1,
+ .mask = WM8350_RTC_SEC_EINT,
+ },
+ [WM8350_IRQ_RTC_PER] = {
+ .primary = WM8350_RTC_INT,
+ .reg = WM8350_INT_OFFSET_1,
+ .mask = WM8350_RTC_PER_EINT,
+ },
+ [WM8350_IRQ_CS1] = {
+ .primary = WM8350_CS_INT,
+ .reg = WM8350_INT_OFFSET_2,
+ .mask = WM8350_CS1_EINT,
+ },
+ [WM8350_IRQ_CS2] = {
+ .primary = WM8350_CS_INT,
+ .reg = WM8350_INT_OFFSET_2,
+ .mask = WM8350_CS2_EINT,
+ },
+ [WM8350_IRQ_SYS_HYST_COMP_FAIL] = {
+ .primary = WM8350_SYS_INT,
+ .reg = WM8350_INT_OFFSET_2,
+ .mask = WM8350_SYS_HYST_COMP_FAIL_EINT,
+ },
+ [WM8350_IRQ_SYS_CHIP_GT115] = {
+ .primary = WM8350_SYS_INT,
+ .reg = WM8350_INT_OFFSET_2,
+ .mask = WM8350_SYS_CHIP_GT115_EINT,
+ },
+ [WM8350_IRQ_SYS_CHIP_GT140] = {
+ .primary = WM8350_SYS_INT,
+ .reg = WM8350_INT_OFFSET_2,
+ .mask = WM8350_SYS_CHIP_GT140_EINT,
+ },
+ [WM8350_IRQ_SYS_WDOG_TO] = {
+ .primary = WM8350_SYS_INT,
+ .reg = WM8350_INT_OFFSET_2,
+ .mask = WM8350_SYS_WDOG_TO_EINT,
+ },
+ [WM8350_IRQ_AUXADC_DATARDY] = {
+ .primary = WM8350_AUXADC_INT,
+ .reg = WM8350_INT_OFFSET_2,
+ .mask = WM8350_AUXADC_DATARDY_EINT,
+ },
+ [WM8350_IRQ_AUXADC_DCOMP4] = {
+ .primary = WM8350_AUXADC_INT,
+ .reg = WM8350_INT_OFFSET_2,
+ .mask = WM8350_AUXADC_DCOMP4_EINT,
+ },
+ [WM8350_IRQ_AUXADC_DCOMP3] = {
+ .primary = WM8350_AUXADC_INT,
+ .reg = WM8350_INT_OFFSET_2,
+ .mask = WM8350_AUXADC_DCOMP3_EINT,
+ },
+ [WM8350_IRQ_AUXADC_DCOMP2] = {
+ .primary = WM8350_AUXADC_INT,
+ .reg = WM8350_INT_OFFSET_2,
+ .mask = WM8350_AUXADC_DCOMP2_EINT,
+ },
+ [WM8350_IRQ_AUXADC_DCOMP1] = {
+ .primary = WM8350_AUXADC_INT,
+ .reg = WM8350_INT_OFFSET_2,
+ .mask = WM8350_AUXADC_DCOMP1_EINT,
+ },
+ [WM8350_IRQ_USB_LIMIT] = {
+ .primary = WM8350_USB_INT,
+ .reg = WM8350_INT_OFFSET_2,
+ .mask = WM8350_USB_LIMIT_EINT,
+ .primary_only = 1,
+ },
+ [WM8350_IRQ_WKUP_OFF_STATE] = {
+ .primary = WM8350_WKUP_INT,
+ .reg = WM8350_COMPARATOR_INT_OFFSET,
+ .mask = WM8350_WKUP_OFF_STATE_EINT,
+ },
+ [WM8350_IRQ_WKUP_HIB_STATE] = {
+ .primary = WM8350_WKUP_INT,
+ .reg = WM8350_COMPARATOR_INT_OFFSET,
+ .mask = WM8350_WKUP_HIB_STATE_EINT,
+ },
+ [WM8350_IRQ_WKUP_CONV_FAULT] = {
+ .primary = WM8350_WKUP_INT,
+ .reg = WM8350_COMPARATOR_INT_OFFSET,
+ .mask = WM8350_WKUP_CONV_FAULT_EINT,
+ },
+ [WM8350_IRQ_WKUP_WDOG_RST] = {
+ .primary = WM8350_WKUP_INT,
+ .reg = WM8350_COMPARATOR_INT_OFFSET,
+ .mask = WM8350_WKUP_WDOG_RST_EINT,
+ },
+ [WM8350_IRQ_WKUP_GP_PWR_ON] = {
+ .primary = WM8350_WKUP_INT,
+ .reg = WM8350_COMPARATOR_INT_OFFSET,
+ .mask = WM8350_WKUP_GP_PWR_ON_EINT,
+ },
+ [WM8350_IRQ_WKUP_ONKEY] = {
+ .primary = WM8350_WKUP_INT,
+ .reg = WM8350_COMPARATOR_INT_OFFSET,
+ .mask = WM8350_WKUP_ONKEY_EINT,
+ },
+ [WM8350_IRQ_WKUP_GP_WAKEUP] = {
+ .primary = WM8350_WKUP_INT,
+ .reg = WM8350_COMPARATOR_INT_OFFSET,
+ .mask = WM8350_WKUP_GP_WAKEUP_EINT,
+ },
+ [WM8350_IRQ_CODEC_JCK_DET_L] = {
+ .primary = WM8350_CODEC_INT,
+ .reg = WM8350_COMPARATOR_INT_OFFSET,
+ .mask = WM8350_CODEC_JCK_DET_L_EINT,
+ },
+ [WM8350_IRQ_CODEC_JCK_DET_R] = {
+ .primary = WM8350_CODEC_INT,
+ .reg = WM8350_COMPARATOR_INT_OFFSET,
+ .mask = WM8350_CODEC_JCK_DET_R_EINT,
+ },
+ [WM8350_IRQ_CODEC_MICSCD] = {
+ .primary = WM8350_CODEC_INT,
+ .reg = WM8350_COMPARATOR_INT_OFFSET,
+ .mask = WM8350_CODEC_MICSCD_EINT,
+ },
+ [WM8350_IRQ_CODEC_MICD] = {
+ .primary = WM8350_CODEC_INT,
+ .reg = WM8350_COMPARATOR_INT_OFFSET,
+ .mask = WM8350_CODEC_MICD_EINT,
+ },
+ [WM8350_IRQ_EXT_USB_FB] = {
+ .primary = WM8350_EXT_INT,
+ .reg = WM8350_COMPARATOR_INT_OFFSET,
+ .mask = WM8350_EXT_USB_FB_EINT,
+ },
+ [WM8350_IRQ_EXT_WALL_FB] = {
+ .primary = WM8350_EXT_INT,
+ .reg = WM8350_COMPARATOR_INT_OFFSET,
+ .mask = WM8350_EXT_WALL_FB_EINT,
+ },
+ [WM8350_IRQ_EXT_BAT_FB] = {
+ .primary = WM8350_EXT_INT,
+ .reg = WM8350_COMPARATOR_INT_OFFSET,
+ .mask = WM8350_EXT_BAT_FB_EINT,
+ },
+ [WM8350_IRQ_GPIO(0)] = {
+ .primary = WM8350_GP_INT,
+ .reg = WM8350_GPIO_INT_OFFSET,
+ .mask = WM8350_GP0_EINT,
+ },
+ [WM8350_IRQ_GPIO(1)] = {
+ .primary = WM8350_GP_INT,
+ .reg = WM8350_GPIO_INT_OFFSET,
+ .mask = WM8350_GP1_EINT,
+ },
+ [WM8350_IRQ_GPIO(2)] = {
+ .primary = WM8350_GP_INT,
+ .reg = WM8350_GPIO_INT_OFFSET,
+ .mask = WM8350_GP2_EINT,
+ },
+ [WM8350_IRQ_GPIO(3)] = {
+ .primary = WM8350_GP_INT,
+ .reg = WM8350_GPIO_INT_OFFSET,
+ .mask = WM8350_GP3_EINT,
+ },
+ [WM8350_IRQ_GPIO(4)] = {
+ .primary = WM8350_GP_INT,
+ .reg = WM8350_GPIO_INT_OFFSET,
+ .mask = WM8350_GP4_EINT,
+ },
+ [WM8350_IRQ_GPIO(5)] = {
+ .primary = WM8350_GP_INT,
+ .reg = WM8350_GPIO_INT_OFFSET,
+ .mask = WM8350_GP5_EINT,
+ },
+ [WM8350_IRQ_GPIO(6)] = {
+ .primary = WM8350_GP_INT,
+ .reg = WM8350_GPIO_INT_OFFSET,
+ .mask = WM8350_GP6_EINT,
+ },
+ [WM8350_IRQ_GPIO(7)] = {
+ .primary = WM8350_GP_INT,
+ .reg = WM8350_GPIO_INT_OFFSET,
+ .mask = WM8350_GP7_EINT,
+ },
+ [WM8350_IRQ_GPIO(8)] = {
+ .primary = WM8350_GP_INT,
+ .reg = WM8350_GPIO_INT_OFFSET,
+ .mask = WM8350_GP8_EINT,
+ },
+ [WM8350_IRQ_GPIO(9)] = {
+ .primary = WM8350_GP_INT,
+ .reg = WM8350_GPIO_INT_OFFSET,
+ .mask = WM8350_GP9_EINT,
+ },
+ [WM8350_IRQ_GPIO(10)] = {
+ .primary = WM8350_GP_INT,
+ .reg = WM8350_GPIO_INT_OFFSET,
+ .mask = WM8350_GP10_EINT,
+ },
+ [WM8350_IRQ_GPIO(11)] = {
+ .primary = WM8350_GP_INT,
+ .reg = WM8350_GPIO_INT_OFFSET,
+ .mask = WM8350_GP11_EINT,
+ },
+ [WM8350_IRQ_GPIO(12)] = {
+ .primary = WM8350_GP_INT,
+ .reg = WM8350_GPIO_INT_OFFSET,
+ .mask = WM8350_GP12_EINT,
+ },
+};
+
+static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq)
+{
+ mutex_lock(&wm8350->irq_mutex);
+
+ if (wm8350->irq[irq].handler)
+ wm8350->irq[irq].handler(wm8350, irq, wm8350->irq[irq].data);
+ else {
+ dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n",
+ irq);
+ wm8350_mask_irq(wm8350, irq);
+ }
+
+ mutex_unlock(&wm8350->irq_mutex);
+}
+
+/*
+ * This is a threaded IRQ handler so can access I2C/SPI. Since all
+ * interrupts are clear on read the IRQ line will be reasserted and
+ * the physical IRQ will be handled again if another interrupt is
+ * asserted while we run - in the normal course of events this is a
+ * rare occurrence so we save I2C/SPI reads.
+ */
+static irqreturn_t wm8350_irq(int irq, void *irq_data)
+{
+ struct wm8350 *wm8350 = irq_data;
+ u16 level_one;
+ u16 sub_reg[WM8350_NUM_IRQ_REGS];
+ int read_done[WM8350_NUM_IRQ_REGS];
+ struct wm8350_irq_data *data;
+ int i;
+
+ /* TODO: Use block reads to improve performance? */
+ level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS)
+ & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK);
+
+ if (!level_one)
+ return IRQ_NONE;
+
+ memset(&read_done, 0, sizeof(read_done));
+
+ for (i = 0; i < ARRAY_SIZE(wm8350_irqs); i++) {
+ data = &wm8350_irqs[i];
+
+ if (!(level_one & data->primary))
+ continue;
+
+ if (!read_done[data->reg]) {
+ sub_reg[data->reg] =
+ wm8350_reg_read(wm8350, WM8350_INT_STATUS_1 +
+ data->reg);
+ sub_reg[data->reg] &=
+ ~wm8350_reg_read(wm8350,
+ WM8350_INT_STATUS_1_MASK +
+ data->reg);
+ read_done[data->reg] = 1;
+ }
+
+ if (sub_reg[data->reg] & data->mask)
+ wm8350_irq_call_handler(wm8350, i);
+ }
+
+ return IRQ_HANDLED;
+}
+
+int wm8350_register_irq(struct wm8350 *wm8350, int irq,
+ void (*handler) (struct wm8350 *, int, void *),
+ void *data)
+{
+ if (irq < 0 || irq > WM8350_NUM_IRQ || !handler)
+ return -EINVAL;
+
+ if (wm8350->irq[irq].handler)
+ return -EBUSY;
+
+ mutex_lock(&wm8350->irq_mutex);
+ wm8350->irq[irq].handler = handler;
+ wm8350->irq[irq].data = data;
+ mutex_unlock(&wm8350->irq_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_register_irq);
+
+int wm8350_free_irq(struct wm8350 *wm8350, int irq)
+{
+ if (irq < 0 || irq > WM8350_NUM_IRQ)
+ return -EINVAL;
+
+ mutex_lock(&wm8350->irq_mutex);
+ wm8350->irq[irq].handler = NULL;
+ mutex_unlock(&wm8350->irq_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_free_irq);
+
+int wm8350_mask_irq(struct wm8350 *wm8350, int irq)
+{
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK +
+ wm8350_irqs[irq].reg,
+ wm8350_irqs[irq].mask);
+}
+EXPORT_SYMBOL_GPL(wm8350_mask_irq);
+
+int wm8350_unmask_irq(struct wm8350 *wm8350, int irq)
+{
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK +
+ wm8350_irqs[irq].reg,
+ wm8350_irqs[irq].mask);
+}
+EXPORT_SYMBOL_GPL(wm8350_unmask_irq);
+
+int wm8350_irq_init(struct wm8350 *wm8350, int irq,
+ struct wm8350_platform_data *pdata)
+{
+ int ret;
+ int flags = IRQF_ONESHOT;
+
+ if (!irq) {
+ dev_err(wm8350->dev, "No IRQ configured\n");
+ return -EINVAL;
+ }
+
+ wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF);
+ wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK, 0xFFFF);
+ wm8350_reg_write(wm8350, WM8350_INT_STATUS_2_MASK, 0xFFFF);
+ wm8350_reg_write(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 0xFFFF);
+ wm8350_reg_write(wm8350, WM8350_GPIO_INT_STATUS_MASK, 0xFFFF);
+ wm8350_reg_write(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK, 0xFFFF);
+
+ mutex_init(&wm8350->irq_mutex);
+ wm8350->chip_irq = irq;
+
+ if (pdata && pdata->irq_high) {
+ flags |= IRQF_TRIGGER_HIGH;
+
+ wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
+ WM8350_IRQ_POL);
+ } else {
+ flags |= IRQF_TRIGGER_LOW;
+
+ wm8350_clear_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
+ WM8350_IRQ_POL);
+ }
+
+ ret = request_threaded_irq(irq, NULL, wm8350_irq, flags,
+ "wm8350", wm8350);
+ if (ret != 0)
+ dev_err(wm8350->dev, "Failed to request IRQ: %d\n", ret);
+
+ return ret;
+}
+
+int wm8350_irq_exit(struct wm8350 *wm8350)
+{
+ free_irq(wm8350->chip_irq, wm8350);
+ return 0;
+}
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index df1f86b5c83e..cccd46e4f325 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -76,6 +76,35 @@ config IBM_ASM
information on the specific driver level and support statement
for your IBM server.
+config HWLAT_DETECTOR
+ tristate "Testing module to detect hardware-induced latencies"
+ depends on DEBUG_FS
+ depends on RING_BUFFER
+ default m
+ ---help---
+ A simple hardware latency detector. Use this module to detect
+ large latencies introduced by the behavior of the underlying
+ system firmware external to Linux. We do this using periodic
+ use of stop_machine to grab all available CPUs and measure
+ for unexplainable gaps in the CPU timestamp counter(s). By
+ default, the module is not enabled until the "enable" file
+ within the "hwlat_detector" debugfs directory is toggled.
+
+ This module is often used to detect SMI (System Management
+ Interrupts) on x86 systems, though is not x86 specific. To
+ this end, we default to using a sample window of 1 second,
+ during which we will sample for 0.5 seconds. If an SMI or
+ similar event occurs during that time, it is recorded
+ into an 8K samples global ring buffer until retreived.
+
+ WARNING: This software should never be enabled (it can be built
+ but should not be turned on after it is loaded) in a production
+ environment where high latencies are a concern since the
+ sampling mechanism actually introduces latencies for
+ regular tasks while the CPU(s) are being held.
+
+ If unsure, say N
+
config PHANTOM
tristate "Sensable PHANToM (PCI)"
depends on PCI
@@ -246,8 +275,19 @@ config EP93XX_PWM
To compile this driver as a module, choose M here: the module will
be called ep93xx_pwm.
+config DS1682
+ tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for Dallas Semiconductor
+ DS1682 Total Elapsed Time Recorder.
+
+ This driver can also be built as a module. If so, the module
+ will be called ds1682.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
+source "drivers/misc/iwmc3200top/Kconfig"
endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index f982d2ecfde7..a9401cefb666 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -20,6 +20,9 @@ obj-$(CONFIG_SGI_GRU) += sgi-gru/
obj-$(CONFIG_HP_ILO) += hpilo.o
obj-$(CONFIG_ISL29003) += isl29003.o
obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o
+obj-$(CONFIG_DS1682) += ds1682.o
obj-$(CONFIG_C2PORT) += c2port/
+obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/
+obj-$(CONFIG_HWLAT_DETECTOR) += hwlat_detector.o
obj-y += eeprom/
obj-y += cb710/
diff --git a/drivers/i2c/chips/ds1682.c b/drivers/misc/ds1682.c
index f3ee4a1abb77..f3ee4a1abb77 100644
--- a/drivers/i2c/chips/ds1682.c
+++ b/drivers/misc/ds1682.c
diff --git a/drivers/misc/hwlat_detector.c b/drivers/misc/hwlat_detector.c
new file mode 100644
index 000000000000..e02d8e17b484
--- /dev/null
+++ b/drivers/misc/hwlat_detector.c
@@ -0,0 +1,1208 @@
+/*
+ * hwlat_detector.c - A simple Hardware Latency detector.
+ *
+ * Use this module to detect large system latencies induced by the behavior of
+ * certain underlying system hardware or firmware, independent of Linux itself.
+ * The code was developed originally to detect the presence of SMIs on Intel
+ * and AMD systems, although there is no dependency upon x86 herein.
+ *
+ * The classical example usage of this module is in detecting the presence of
+ * SMIs or System Management Interrupts on Intel and AMD systems. An SMI is a
+ * somewhat special form of hardware interrupt spawned from earlier CPU debug
+ * modes in which the (BIOS/EFI/etc.) firmware arranges for the South Bridge
+ * LPC (or other device) to generate a special interrupt under certain
+ * circumstances, for example, upon expiration of a special SMI timer device,
+ * due to certain external thermal readings, on certain I/O address accesses,
+ * and other situations. An SMI hits a special CPU pin, triggers a special
+ * SMI mode (complete with special memory map), and the OS is unaware.
+ *
+ * Although certain hardware-inducing latencies are necessary (for example,
+ * a modern system often requires an SMI handler for correct thermal control
+ * and remote management) they can wreak havoc upon any OS-level performance
+ * guarantees toward low-latency, especially when the OS is not even made
+ * aware of the presence of these interrupts. For this reason, we need a
+ * somewhat brute force mechanism to detect these interrupts. In this case,
+ * we do it by hogging all of the CPU(s) for configurable timer intervals,
+ * sampling the built-in CPU timer, looking for discontiguous readings.
+ *
+ * WARNING: This implementation necessarily introduces latencies. Therefore,
+ * you should NEVER use this module in a production environment
+ * requiring any kind of low-latency performance guarantee(s).
+ *
+ * Copyright (C) 2008-2009 Jon Masters, Red Hat, Inc. <jcm@redhat.com>
+ *
+ * Includes useful feedback from Clark Williams <clark@redhat.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/module.h>
+#include <linux/init.h>
+#include <linux/ring_buffer.h>
+#include <linux/stop_machine.h>
+#include <linux/time.h>
+#include <linux/hrtimer.h>
+#include <linux/kthread.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+
+#define BUF_SIZE_DEFAULT 262144UL /* 8K*(sizeof(entry)) */
+#define BUF_FLAGS (RB_FL_OVERWRITE) /* no block on full */
+#define U64STR_SIZE 22 /* 20 digits max */
+
+#define VERSION "1.0.0"
+#define BANNER "hwlat_detector: "
+#define DRVNAME "hwlat_detector"
+#define DEFAULT_SAMPLE_WINDOW 1000000 /* 1s */
+#define DEFAULT_SAMPLE_WIDTH 500000 /* 0.5s */
+#define DEFAULT_LAT_THRESHOLD 10 /* 10us */
+
+/* Module metadata */
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jon Masters <jcm@redhat.com>");
+MODULE_DESCRIPTION("A simple hardware latency detector");
+MODULE_VERSION(VERSION);
+
+/* Module parameters */
+
+static int debug;
+static int enabled;
+static int threshold;
+
+module_param(debug, int, 0); /* enable debug */
+module_param(enabled, int, 0); /* enable detector */
+module_param(threshold, int, 0); /* latency threshold */
+
+/* Buffering and sampling */
+
+static struct ring_buffer *ring_buffer; /* sample buffer */
+static DEFINE_MUTEX(ring_buffer_mutex); /* lock changes */
+static unsigned long buf_size = BUF_SIZE_DEFAULT;
+static struct task_struct *kthread; /* sampling thread */
+
+/* DebugFS filesystem entries */
+
+static struct dentry *debug_dir; /* debugfs directory */
+static struct dentry *debug_max; /* maximum TSC delta */
+static struct dentry *debug_count; /* total detect count */
+static struct dentry *debug_sample_width; /* sample width us */
+static struct dentry *debug_sample_window; /* sample window us */
+static struct dentry *debug_sample; /* raw samples us */
+static struct dentry *debug_threshold; /* threshold us */
+static struct dentry *debug_enable; /* enable/disable */
+
+/* Individual samples and global state */
+
+struct sample; /* latency sample */
+struct data; /* Global state */
+
+/* Sampling functions */
+static int __buffer_add_sample(struct sample *sample);
+static struct sample *buffer_get_sample(struct sample *sample);
+static int get_sample(void *unused);
+
+/* Threading and state */
+static int kthread_fn(void *unused);
+static int start_kthread(void);
+static int stop_kthread(void);
+static void __reset_stats(void);
+static int init_stats(void);
+
+/* Debugfs interface */
+static ssize_t simple_data_read(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos, const u64 *entry);
+static ssize_t simple_data_write(struct file *filp, const char __user *ubuf,
+ size_t cnt, loff_t *ppos, u64 *entry);
+static int debug_sample_fopen(struct inode *inode, struct file *filp);
+static ssize_t debug_sample_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos);
+static int debug_sample_release(struct inode *inode, struct file *filp);
+static int debug_enable_fopen(struct inode *inode, struct file *filp);
+static ssize_t debug_enable_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos);
+static ssize_t debug_enable_fwrite(struct file *file,
+ const char __user *user_buffer,
+ size_t user_size, loff_t *offset);
+
+/* Initialization functions */
+static int init_debugfs(void);
+static void free_debugfs(void);
+static int detector_init(void);
+static void detector_exit(void);
+
+/* Individual latency samples are stored here when detected and packed into
+ * the ring_buffer circular buffer, where they are overwritten when
+ * more than buf_size/sizeof(sample) samples are received. */
+struct sample {
+ u64 seqnum; /* unique sequence */
+ u64 duration; /* ktime delta */
+ struct timespec timestamp; /* wall time */
+};
+
+/* keep the global state somewhere. Mostly used under stop_machine. */
+static struct data {
+
+ struct mutex lock; /* protect changes */
+
+ u64 count; /* total since reset */
+ u64 max_sample; /* max hardware latency */
+ u64 threshold; /* sample threshold level */
+
+ u64 sample_window; /* total sampling window (on+off) */
+ u64 sample_width; /* active sampling portion of window */
+
+ atomic_t sample_open; /* whether the sample file is open */
+
+ wait_queue_head_t wq; /* waitqeue for new sample values */
+
+} data;
+
+/**
+ * __buffer_add_sample - add a new latency sample recording to the ring buffer
+ * @sample: The new latency sample value
+ *
+ * This receives a new latency sample and records it in a global ring buffer.
+ * No additional locking is used in this case - suited for stop_machine use.
+ */
+static int __buffer_add_sample(struct sample *sample)
+{
+ return ring_buffer_write(ring_buffer,
+ sizeof(struct sample), sample);
+}
+
+/**
+ * buffer_get_sample - remove a hardware latency sample from the ring buffer
+ * @sample: Pre-allocated storage for the sample
+ *
+ * This retrieves a hardware latency sample from the global circular buffer
+ */
+static struct sample *buffer_get_sample(struct sample *sample)
+{
+ struct ring_buffer_event *e = NULL;
+ struct sample *s = NULL;
+ unsigned int cpu = 0;
+
+ if (!sample)
+ return NULL;
+
+ /* ring_buffers are per-cpu but we just want any value */
+ /* so we'll start with this cpu and try others if not */
+ /* Steven is planning to add a generic mechanism */
+ mutex_lock(&ring_buffer_mutex);
+ e = ring_buffer_consume(ring_buffer, smp_processor_id(), NULL);
+ if (!e) {
+ for_each_online_cpu(cpu) {
+ e = ring_buffer_consume(ring_buffer, cpu, NULL);
+ if (e)
+ break;
+ }
+ }
+
+ if (e) {
+ s = ring_buffer_event_data(e);
+ memcpy(sample, s, sizeof(struct sample));
+ } else
+ sample = NULL;
+ mutex_unlock(&ring_buffer_mutex);
+
+ return sample;
+}
+
+/**
+ * get_sample - sample the CPU TSC and look for likely hardware latencies
+ * @unused: This is not used but is a part of the stop_machine API
+ *
+ * Used to repeatedly capture the CPU TSC (or similar), looking for potential
+ * hardware-induced latency. Called under stop_machine, with data.lock held.
+ */
+static int get_sample(void *unused)
+{
+ ktime_t start, t1, t2;
+ s64 diff, total = 0;
+ u64 sample = 0;
+ int ret = 1;
+
+ start = ktime_get(); /* start timestamp */
+
+ do {
+
+ t1 = ktime_get(); /* we'll look for a discontinuity */
+ t2 = ktime_get();
+
+ total = ktime_to_us(ktime_sub(t2, start)); /* sample width */
+ diff = ktime_to_us(ktime_sub(t2, t1)); /* current diff */
+
+ /* This shouldn't happen */
+ if (diff < 0) {
+ printk(KERN_ERR BANNER "time running backwards\n");
+ goto out;
+ }
+
+ if (diff > sample)
+ sample = diff; /* only want highest value */
+
+ } while (total <= data.sample_width);
+
+ /* If we exceed the threshold value, we have found a hardware latency */
+ if (sample > data.threshold) {
+ struct sample s;
+
+ data.count++;
+ s.seqnum = data.count;
+ s.duration = sample;
+ s.timestamp = CURRENT_TIME;
+ __buffer_add_sample(&s);
+
+ /* Keep a running maximum ever recorded hardware latency */
+ if (sample > data.max_sample)
+ data.max_sample = sample;
+
+ wake_up(&data.wq); /* wake up reader(s) */
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+/*
+ * kthread_fn - The CPU time sampling/hardware latency detection kernel thread
+ * @unused: A required part of the kthread API.
+ *
+ * Used to periodically sample the CPU TSC via a call to get_sample. We
+ * use stop_machine, whith does (intentionally) introduce latency since we
+ * need to ensure nothing else might be running (and thus pre-empting).
+ * Obviously this should never be used in production environments.
+ *
+ * stop_machine will schedule us typically only on CPU0 which is fine for
+ * almost every real-world hardware latency situation - but we might later
+ * generalize this if we find there are any actualy systems with alternate
+ * SMI delivery or other non CPU0 hardware latencies.
+ */
+static int kthread_fn(void *unused)
+{
+ int err = 0;
+ u64 interval = 0;
+
+ while (!kthread_should_stop()) {
+
+ mutex_lock(&data.lock);
+
+ err = stop_machine(get_sample, unused, 0);
+ if (err) {
+ /* Houston, we have a problem */
+ mutex_unlock(&data.lock);
+ goto err_out;
+ }
+
+ interval = data.sample_window - data.sample_width;
+ do_div(interval, USEC_PER_MSEC); /* modifies interval value */
+
+ mutex_unlock(&data.lock);
+
+ if (msleep_interruptible(interval))
+ goto out;
+ }
+ goto out;
+err_out:
+ printk(KERN_ERR BANNER "could not call stop_machine, disabling\n");
+ enabled = 0;
+out:
+ return err;
+
+}
+
+/**
+ * start_kthread - Kick off the hardware latency sampling/detector kthread
+ *
+ * This starts a kernel thread that will sit and sample the CPU timestamp
+ * counter (TSC or similar) and look for potential hardware latencies.
+ */
+static int start_kthread(void)
+{
+ kthread = kthread_run(kthread_fn, NULL,
+ DRVNAME);
+ if (IS_ERR(kthread)) {
+ printk(KERN_ERR BANNER "could not start sampling thread\n");
+ enabled = 0;
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * stop_kthread - Inform the hardware latency samping/detector kthread to stop
+ *
+ * This kicks the running hardware latency sampling/detector kernel thread and
+ * tells it to stop sampling now. Use this on unload and at system shutdown.
+ */
+static int stop_kthread(void)
+{
+ int ret;
+
+ ret = kthread_stop(kthread);
+
+ return ret;
+}
+
+/**
+ * __reset_stats - Reset statistics for the hardware latency detector
+ *
+ * We use data to store various statistics and global state. We call this
+ * function in order to reset those when "enable" is toggled on or off, and
+ * also at initialization. Should be called with data.lock held.
+ */
+static void __reset_stats(void)
+{
+ data.count = 0;
+ data.max_sample = 0;
+ ring_buffer_reset(ring_buffer); /* flush out old sample entries */
+}
+
+/**
+ * init_stats - Setup global state statistics for the hardware latency detector
+ *
+ * We use data to store various statistics and global state. We also use
+ * a global ring buffer (ring_buffer) to keep raw samples of detected hardware
+ * induced system latencies. This function initializes these structures and
+ * allocates the global ring buffer also.
+ */
+static int init_stats(void)
+{
+ int ret = -ENOMEM;
+
+ mutex_init(&data.lock);
+ init_waitqueue_head(&data.wq);
+ atomic_set(&data.sample_open, 0);
+
+ ring_buffer = ring_buffer_alloc(buf_size, BUF_FLAGS);
+
+ if (WARN(!ring_buffer, KERN_ERR BANNER
+ "failed to allocate ring buffer!\n"))
+ goto out;
+
+ __reset_stats();
+ data.threshold = DEFAULT_LAT_THRESHOLD; /* threshold us */
+ data.sample_window = DEFAULT_SAMPLE_WINDOW; /* window us */
+ data.sample_width = DEFAULT_SAMPLE_WIDTH; /* width us */
+
+ ret = 0;
+
+out:
+ return ret;
+
+}
+
+/*
+ * simple_data_read - Wrapper read function for global state debugfs entries
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The userspace provided buffer to read value into
+ * @cnt: The maximum number of bytes to read
+ * @ppos: The current "file" position
+ * @entry: The entry to read from
+ *
+ * This function provides a generic read implementation for the global state
+ * "data" structure debugfs filesystem entries. It would be nice to use
+ * simple_attr_read directly, but we need to make sure that the data.lock
+ * spinlock is held during the actual read (even though we likely won't ever
+ * actually race here as the updater runs under a stop_machine context).
+ */
+static ssize_t simple_data_read(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos, const u64 *entry)
+{
+ char buf[U64STR_SIZE];
+ u64 val = 0;
+ int len = 0;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (!entry)
+ return -EFAULT;
+
+ mutex_lock(&data.lock);
+ val = *entry;
+ mutex_unlock(&data.lock);
+
+ len = snprintf(buf, sizeof(buf), "%llu\n", (unsigned long long)val);
+
+ return simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
+
+}
+
+/*
+ * simple_data_write - Wrapper write function for global state debugfs entries
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The userspace provided buffer to write value from
+ * @cnt: The maximum number of bytes to write
+ * @ppos: The current "file" position
+ * @entry: The entry to write to
+ *
+ * This function provides a generic write implementation for the global state
+ * "data" structure debugfs filesystem entries. It would be nice to use
+ * simple_attr_write directly, but we need to make sure that the data.lock
+ * spinlock is held during the actual write (even though we likely won't ever
+ * actually race here as the updater runs under a stop_machine context).
+ */
+static ssize_t simple_data_write(struct file *filp, const char __user *ubuf,
+ size_t cnt, loff_t *ppos, u64 *entry)
+{
+ char buf[U64STR_SIZE];
+ int csize = min(cnt, sizeof(buf));
+ u64 val = 0;
+ int err = 0;
+
+ memset(buf, '\0', sizeof(buf));
+ if (copy_from_user(buf, ubuf, csize))
+ return -EFAULT;
+
+ buf[U64STR_SIZE-1] = '\0'; /* just in case */
+ err = strict_strtoull(buf, 10, &val);
+ if (err)
+ return -EINVAL;
+
+ mutex_lock(&data.lock);
+ *entry = val;
+ mutex_unlock(&data.lock);
+
+ return csize;
+}
+
+/**
+ * debug_count_fopen - Open function for "count" debugfs entry
+ * @inode: The in-kernel inode representation of the debugfs "file"
+ * @filp: The active open file structure for the debugfs "file"
+ *
+ * This function provides an open implementation for the "count" debugfs
+ * interface to the hardware latency detector.
+ */
+static int debug_count_fopen(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+/**
+ * debug_count_fread - Read function for "count" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The userspace provided buffer to read value into
+ * @cnt: The maximum number of bytes to read
+ * @ppos: The current "file" position
+ *
+ * This function provides a read implementation for the "count" debugfs
+ * interface to the hardware latency detector. Can be used to read the
+ * number of latency readings exceeding the configured threshold since
+ * the detector was last reset (e.g. by writing a zero into "count").
+ */
+static ssize_t debug_count_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ return simple_data_read(filp, ubuf, cnt, ppos, &data.count);
+}
+
+/**
+ * debug_count_fwrite - Write function for "count" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The user buffer that contains the value to write
+ * @cnt: The maximum number of bytes to write to "file"
+ * @ppos: The current position in the debugfs "file"
+ *
+ * This function provides a write implementation for the "count" debugfs
+ * interface to the hardware latency detector. Can be used to write a
+ * desired value, especially to zero the total count.
+ */
+static ssize_t debug_count_fwrite(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ return simple_data_write(filp, ubuf, cnt, ppos, &data.count);
+}
+
+/**
+ * debug_enable_fopen - Dummy open function for "enable" debugfs interface
+ * @inode: The in-kernel inode representation of the debugfs "file"
+ * @filp: The active open file structure for the debugfs "file"
+ *
+ * This function provides an open implementation for the "enable" debugfs
+ * interface to the hardware latency detector.
+ */
+static int debug_enable_fopen(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+/**
+ * debug_enable_fread - Read function for "enable" debugfs interface
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The userspace provided buffer to read value into
+ * @cnt: The maximum number of bytes to read
+ * @ppos: The current "file" position
+ *
+ * This function provides a read implementation for the "enable" debugfs
+ * interface to the hardware latency detector. Can be used to determine
+ * whether the detector is currently enabled ("0\n" or "1\n" returned).
+ */
+static ssize_t debug_enable_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ char buf[4];
+
+ if ((cnt < sizeof(buf)) || (*ppos))
+ return 0;
+
+ buf[0] = enabled ? '1' : '0';
+ buf[1] = '\n';
+ buf[2] = '\0';
+ if (copy_to_user(ubuf, buf, strlen(buf)))
+ return -EFAULT;
+ return *ppos = strlen(buf);
+}
+
+/**
+ * debug_enable_fwrite - Write function for "enable" debugfs interface
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The user buffer that contains the value to write
+ * @cnt: The maximum number of bytes to write to "file"
+ * @ppos: The current position in the debugfs "file"
+ *
+ * This function provides a write implementation for the "enable" debugfs
+ * interface to the hardware latency detector. Can be used to enable or
+ * disable the detector, which will have the side-effect of possibly
+ * also resetting the global stats and kicking off the measuring
+ * kthread (on an enable) or the converse (upon a disable).
+ */
+static ssize_t debug_enable_fwrite(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ char buf[4];
+ int csize = min(cnt, sizeof(buf));
+ long val = 0;
+ int err = 0;
+
+ memset(buf, '\0', sizeof(buf));
+ if (copy_from_user(buf, ubuf, csize))
+ return -EFAULT;
+
+ buf[sizeof(buf)-1] = '\0'; /* just in case */
+ err = strict_strtoul(buf, 10, &val);
+ if (0 != err)
+ return -EINVAL;
+
+ if (val) {
+ if (enabled)
+ goto unlock;
+ enabled = 1;
+ __reset_stats();
+ if (start_kthread())
+ return -EFAULT;
+ } else {
+ if (!enabled)
+ goto unlock;
+ enabled = 0;
+ stop_kthread();
+ wake_up(&data.wq); /* reader(s) should return */
+ }
+unlock:
+ return csize;
+}
+
+/**
+ * debug_max_fopen - Open function for "max" debugfs entry
+ * @inode: The in-kernel inode representation of the debugfs "file"
+ * @filp: The active open file structure for the debugfs "file"
+ *
+ * This function provides an open implementation for the "max" debugfs
+ * interface to the hardware latency detector.
+ */
+static int debug_max_fopen(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+/**
+ * debug_max_fread - Read function for "max" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The userspace provided buffer to read value into
+ * @cnt: The maximum number of bytes to read
+ * @ppos: The current "file" position
+ *
+ * This function provides a read implementation for the "max" debugfs
+ * interface to the hardware latency detector. Can be used to determine
+ * the maximum latency value observed since it was last reset.
+ */
+static ssize_t debug_max_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ return simple_data_read(filp, ubuf, cnt, ppos, &data.max_sample);
+}
+
+/**
+ * debug_max_fwrite - Write function for "max" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The user buffer that contains the value to write
+ * @cnt: The maximum number of bytes to write to "file"
+ * @ppos: The current position in the debugfs "file"
+ *
+ * This function provides a write implementation for the "max" debugfs
+ * interface to the hardware latency detector. Can be used to reset the
+ * maximum or set it to some other desired value - if, then, subsequent
+ * measurements exceed this value, the maximum will be updated.
+ */
+static ssize_t debug_max_fwrite(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ return simple_data_write(filp, ubuf, cnt, ppos, &data.max_sample);
+}
+
+
+/**
+ * debug_sample_fopen - An open function for "sample" debugfs interface
+ * @inode: The in-kernel inode representation of this debugfs "file"
+ * @filp: The active open file structure for the debugfs "file"
+ *
+ * This function handles opening the "sample" file within the hardware
+ * latency detector debugfs directory interface. This file is used to read
+ * raw samples from the global ring_buffer and allows the user to see a
+ * running latency history. Can be opened blocking or non-blocking,
+ * affecting whether it behaves as a buffer read pipe, or does not.
+ * Implements simple locking to prevent multiple simultaneous use.
+ */
+static int debug_sample_fopen(struct inode *inode, struct file *filp)
+{
+ if (!atomic_add_unless(&data.sample_open, 1, 1))
+ return -EBUSY;
+ else
+ return 0;
+}
+
+/**
+ * debug_sample_fread - A read function for "sample" debugfs interface
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The user buffer that will contain the samples read
+ * @cnt: The maximum bytes to read from the debugfs "file"
+ * @ppos: The current position in the debugfs "file"
+ *
+ * This function handles reading from the "sample" file within the hardware
+ * latency detector debugfs directory interface. This file is used to read
+ * raw samples from the global ring_buffer and allows the user to see a
+ * running latency history. By default this will block pending a new
+ * value written into the sample buffer, unless there are already a
+ * number of value(s) waiting in the buffer, or the sample file was
+ * previously opened in a non-blocking mode of operation.
+ */
+static ssize_t debug_sample_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ int len = 0;
+ char buf[64];
+ struct sample *sample = NULL;
+
+ if (!enabled)
+ return 0;
+
+ sample = kzalloc(sizeof(struct sample), GFP_KERNEL);
+ if (!sample)
+ return -ENOMEM;
+
+ while (!buffer_get_sample(sample)) {
+
+ DEFINE_WAIT(wait);
+
+ if (filp->f_flags & O_NONBLOCK) {
+ len = -EAGAIN;
+ goto out;
+ }
+
+ prepare_to_wait(&data.wq, &wait, TASK_INTERRUPTIBLE);
+ schedule();
+ finish_wait(&data.wq, &wait);
+
+ if (signal_pending(current)) {
+ len = -EINTR;
+ goto out;
+ }
+
+ if (!enabled) { /* enable was toggled */
+ len = 0;
+ goto out;
+ }
+ }
+
+ len = snprintf(buf, sizeof(buf), "%010lu.%010lu\t%llu\n",
+ sample->timestamp.tv_sec,
+ sample->timestamp.tv_nsec,
+ sample->duration);
+
+
+ /* handling partial reads is more trouble than it's worth */
+ if (len > cnt)
+ goto out;
+
+ if (copy_to_user(ubuf, buf, len))
+ len = -EFAULT;
+
+out:
+ kfree(sample);
+ return len;
+}
+
+/**
+ * debug_sample_release - Release function for "sample" debugfs interface
+ * @inode: The in-kernel inode represenation of the debugfs "file"
+ * @filp: The active open file structure for the debugfs "file"
+ *
+ * This function completes the close of the debugfs interface "sample" file.
+ * Frees the sample_open "lock" so that other users may open the interface.
+ */
+static int debug_sample_release(struct inode *inode, struct file *filp)
+{
+ atomic_dec(&data.sample_open);
+
+ return 0;
+}
+
+/**
+ * debug_threshold_fopen - Open function for "threshold" debugfs entry
+ * @inode: The in-kernel inode representation of the debugfs "file"
+ * @filp: The active open file structure for the debugfs "file"
+ *
+ * This function provides an open implementation for the "threshold" debugfs
+ * interface to the hardware latency detector.
+ */
+static int debug_threshold_fopen(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+/**
+ * debug_threshold_fread - Read function for "threshold" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The userspace provided buffer to read value into
+ * @cnt: The maximum number of bytes to read
+ * @ppos: The current "file" position
+ *
+ * This function provides a read implementation for the "threshold" debugfs
+ * interface to the hardware latency detector. It can be used to determine
+ * the current threshold level at which a latency will be recorded in the
+ * global ring buffer, typically on the order of 10us.
+ */
+static ssize_t debug_threshold_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ return simple_data_read(filp, ubuf, cnt, ppos, &data.threshold);
+}
+
+/**
+ * debug_threshold_fwrite - Write function for "threshold" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The user buffer that contains the value to write
+ * @cnt: The maximum number of bytes to write to "file"
+ * @ppos: The current position in the debugfs "file"
+ *
+ * This function provides a write implementation for the "threshold" debugfs
+ * interface to the hardware latency detector. It can be used to configure
+ * the threshold level at which any subsequently detected latencies will
+ * be recorded into the global ring buffer.
+ */
+static ssize_t debug_threshold_fwrite(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ int ret;
+
+ ret = simple_data_write(filp, ubuf, cnt, ppos, &data.threshold);
+
+ if (enabled)
+ wake_up_process(kthread);
+
+ return ret;
+}
+
+/**
+ * debug_width_fopen - Open function for "width" debugfs entry
+ * @inode: The in-kernel inode representation of the debugfs "file"
+ * @filp: The active open file structure for the debugfs "file"
+ *
+ * This function provides an open implementation for the "width" debugfs
+ * interface to the hardware latency detector.
+ */
+static int debug_width_fopen(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+/**
+ * debug_width_fread - Read function for "width" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The userspace provided buffer to read value into
+ * @cnt: The maximum number of bytes to read
+ * @ppos: The current "file" position
+ *
+ * This function provides a read implementation for the "width" debugfs
+ * interface to the hardware latency detector. It can be used to determine
+ * for how many us of the total window us we will actively sample for any
+ * hardware-induced latecy periods. Obviously, it is not possible to
+ * sample constantly and have the system respond to a sample reader, or,
+ * worse, without having the system appear to have gone out to lunch.
+ */
+static ssize_t debug_width_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ return simple_data_read(filp, ubuf, cnt, ppos, &data.sample_width);
+}
+
+/**
+ * debug_width_fwrite - Write function for "width" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The user buffer that contains the value to write
+ * @cnt: The maximum number of bytes to write to "file"
+ * @ppos: The current position in the debugfs "file"
+ *
+ * This function provides a write implementation for the "width" debugfs
+ * interface to the hardware latency detector. It can be used to configure
+ * for how many us of the total window us we will actively sample for any
+ * hardware-induced latency periods. Obviously, it is not possible to
+ * sample constantly and have the system respond to a sample reader, or,
+ * worse, without having the system appear to have gone out to lunch. It
+ * is enforced that width is less that the total window size.
+ */
+static ssize_t debug_width_fwrite(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ char buf[U64STR_SIZE];
+ int csize = min(cnt, sizeof(buf));
+ u64 val = 0;
+ int err = 0;
+
+ memset(buf, '\0', sizeof(buf));
+ if (copy_from_user(buf, ubuf, csize))
+ return -EFAULT;
+
+ buf[U64STR_SIZE-1] = '\0'; /* just in case */
+ err = strict_strtoull(buf, 10, &val);
+ if (0 != err)
+ return -EINVAL;
+
+ mutex_lock(&data.lock);
+ if (val < data.sample_window)
+ data.sample_width = val;
+ else {
+ mutex_unlock(&data.lock);
+ return -EINVAL;
+ }
+ mutex_unlock(&data.lock);
+
+ if (enabled)
+ wake_up_process(kthread);
+
+ return csize;
+}
+
+/**
+ * debug_window_fopen - Open function for "window" debugfs entry
+ * @inode: The in-kernel inode representation of the debugfs "file"
+ * @filp: The active open file structure for the debugfs "file"
+ *
+ * This function provides an open implementation for the "window" debugfs
+ * interface to the hardware latency detector. The window is the total time
+ * in us that will be considered one sample period. Conceptually, windows
+ * occur back-to-back and contain a sample width period during which
+ * actual sampling occurs.
+ */
+static int debug_window_fopen(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+/**
+ * debug_window_fread - Read function for "window" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The userspace provided buffer to read value into
+ * @cnt: The maximum number of bytes to read
+ * @ppos: The current "file" position
+ *
+ * This function provides a read implementation for the "window" debugfs
+ * interface to the hardware latency detector. The window is the total time
+ * in us that will be considered one sample period. Conceptually, windows
+ * occur back-to-back and contain a sample width period during which
+ * actual sampling occurs. Can be used to read the total window size.
+ */
+static ssize_t debug_window_fread(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ return simple_data_read(filp, ubuf, cnt, ppos, &data.sample_window);
+}
+
+/**
+ * debug_window_fwrite - Write function for "window" debugfs entry
+ * @filp: The active open file structure for the debugfs "file"
+ * @ubuf: The user buffer that contains the value to write
+ * @cnt: The maximum number of bytes to write to "file"
+ * @ppos: The current position in the debugfs "file"
+ *
+ * This function provides a write implementation for the "window" debufds
+ * interface to the hardware latency detetector. The window is the total time
+ * in us that will be considered one sample period. Conceptually, windows
+ * occur back-to-back and contain a sample width period during which
+ * actual sampling occurs. Can be used to write a new total window size. It
+ * is enfoced that any value written must be greater than the sample width
+ * size, or an error results.
+ */
+static ssize_t debug_window_fwrite(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ char buf[U64STR_SIZE];
+ int csize = min(cnt, sizeof(buf));
+ u64 val = 0;
+ int err = 0;
+
+ memset(buf, '\0', sizeof(buf));
+ if (copy_from_user(buf, ubuf, csize))
+ return -EFAULT;
+
+ buf[U64STR_SIZE-1] = '\0'; /* just in case */
+ err = strict_strtoull(buf, 10, &val);
+ if (0 != err)
+ return -EINVAL;
+
+ mutex_lock(&data.lock);
+ if (data.sample_width < val)
+ data.sample_window = val;
+ else {
+ mutex_unlock(&data.lock);
+ return -EINVAL;
+ }
+ mutex_unlock(&data.lock);
+
+ return csize;
+}
+
+/*
+ * Function pointers for the "count" debugfs file operations
+ */
+static const struct file_operations count_fops = {
+ .open = debug_count_fopen,
+ .read = debug_count_fread,
+ .write = debug_count_fwrite,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Function pointers for the "enable" debugfs file operations
+ */
+static const struct file_operations enable_fops = {
+ .open = debug_enable_fopen,
+ .read = debug_enable_fread,
+ .write = debug_enable_fwrite,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Function pointers for the "max" debugfs file operations
+ */
+static const struct file_operations max_fops = {
+ .open = debug_max_fopen,
+ .read = debug_max_fread,
+ .write = debug_max_fwrite,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Function pointers for the "sample" debugfs file operations
+ */
+static const struct file_operations sample_fops = {
+ .open = debug_sample_fopen,
+ .read = debug_sample_fread,
+ .release = debug_sample_release,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Function pointers for the "threshold" debugfs file operations
+ */
+static const struct file_operations threshold_fops = {
+ .open = debug_threshold_fopen,
+ .read = debug_threshold_fread,
+ .write = debug_threshold_fwrite,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Function pointers for the "width" debugfs file operations
+ */
+static const struct file_operations width_fops = {
+ .open = debug_width_fopen,
+ .read = debug_width_fread,
+ .write = debug_width_fwrite,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Function pointers for the "window" debugfs file operations
+ */
+static const struct file_operations window_fops = {
+ .open = debug_window_fopen,
+ .read = debug_window_fread,
+ .write = debug_window_fwrite,
+ .owner = THIS_MODULE,
+};
+
+/**
+ * init_debugfs - A function to initialize the debugfs interface files
+ *
+ * This function creates entries in debugfs for "hwlat_detector", including
+ * files to read values from the detector, current samples, and the
+ * maximum sample that has been captured since the hardware latency
+ * dectector was started.
+ */
+static int init_debugfs(void)
+{
+ int ret = -ENOMEM;
+
+ debug_dir = debugfs_create_dir(DRVNAME, NULL);
+ if (!debug_dir)
+ goto err_debug_dir;
+
+ debug_sample = debugfs_create_file("sample", 0444,
+ debug_dir, NULL,
+ &sample_fops);
+ if (!debug_sample)
+ goto err_sample;
+
+ debug_count = debugfs_create_file("count", 0444,
+ debug_dir, NULL,
+ &count_fops);
+ if (!debug_count)
+ goto err_count;
+
+ debug_max = debugfs_create_file("max", 0444,
+ debug_dir, NULL,
+ &max_fops);
+ if (!debug_max)
+ goto err_max;
+
+ debug_sample_window = debugfs_create_file("window", 0644,
+ debug_dir, NULL,
+ &window_fops);
+ if (!debug_sample_window)
+ goto err_window;
+
+ debug_sample_width = debugfs_create_file("width", 0644,
+ debug_dir, NULL,
+ &width_fops);
+ if (!debug_sample_width)
+ goto err_width;
+
+ debug_threshold = debugfs_create_file("threshold", 0644,
+ debug_dir, NULL,
+ &threshold_fops);
+ if (!debug_threshold)
+ goto err_threshold;
+
+ debug_enable = debugfs_create_file("enable", 0644,
+ debug_dir, &enabled,
+ &enable_fops);
+ if (!debug_enable)
+ goto err_enable;
+
+ else {
+ ret = 0;
+ goto out;
+ }
+
+err_enable:
+ debugfs_remove(debug_threshold);
+err_threshold:
+ debugfs_remove(debug_sample_width);
+err_width:
+ debugfs_remove(debug_sample_window);
+err_window:
+ debugfs_remove(debug_max);
+err_max:
+ debugfs_remove(debug_count);
+err_count:
+ debugfs_remove(debug_sample);
+err_sample:
+ debugfs_remove(debug_dir);
+err_debug_dir:
+out:
+ return ret;
+}
+
+/**
+ * free_debugfs - A function to cleanup the debugfs file interface
+ */
+static void free_debugfs(void)
+{
+ /* could also use a debugfs_remove_recursive */
+ debugfs_remove(debug_enable);
+ debugfs_remove(debug_threshold);
+ debugfs_remove(debug_sample_width);
+ debugfs_remove(debug_sample_window);
+ debugfs_remove(debug_max);
+ debugfs_remove(debug_count);
+ debugfs_remove(debug_sample);
+ debugfs_remove(debug_dir);
+}
+
+/**
+ * detector_init - Standard module initialization code
+ */
+static int detector_init(void)
+{
+ int ret = -ENOMEM;
+
+ printk(KERN_INFO BANNER "version %s\n", VERSION);
+
+ ret = init_stats();
+ if (0 != ret)
+ goto out;
+
+ ret = init_debugfs();
+ if (0 != ret)
+ goto err_stats;
+
+ if (enabled)
+ ret = start_kthread();
+
+ goto out;
+
+err_stats:
+ ring_buffer_free(ring_buffer);
+out:
+ return ret;
+
+}
+
+/**
+ * detector_exit - Standard module cleanup code
+ */
+static void detector_exit(void)
+{
+ if (enabled) {
+ enabled = 0;
+ stop_kthread();
+ }
+
+ free_debugfs();
+ ring_buffer_free(ring_buffer); /* free up the ring buffer */
+
+}
+
+module_init(detector_init);
+module_exit(detector_exit);
diff --git a/drivers/misc/ics932s401.c b/drivers/misc/ics932s401.c
index 6e43ab4231ae..4bb7a3af9ad9 100644
--- a/drivers/misc/ics932s401.c
+++ b/drivers/misc/ics932s401.c
@@ -417,32 +417,25 @@ static int ics932s401_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
+ int vendor, device, revision;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- if (kind <= 0) {
- int vendor, device, revision;
-
- vendor = i2c_smbus_read_word_data(client,
- ICS932S401_REG_VENDOR_REV);
- vendor >>= 8;
- revision = vendor >> ICS932S401_REV_SHIFT;
- vendor &= ICS932S401_VENDOR_MASK;
- if (vendor != ICS932S401_VENDOR)
- return -ENODEV;
-
- device = i2c_smbus_read_word_data(client,
- ICS932S401_REG_DEVICE);
- device >>= 8;
- if (device != ICS932S401_DEVICE)
- return -ENODEV;
-
- if (revision != ICS932S401_REV)
- dev_info(&adapter->dev, "Unknown revision %d\n",
- revision);
- } else
- dev_dbg(&adapter->dev, "detection forced\n");
+ vendor = i2c_smbus_read_word_data(client, ICS932S401_REG_VENDOR_REV);
+ vendor >>= 8;
+ revision = vendor >> ICS932S401_REV_SHIFT;
+ vendor &= ICS932S401_VENDOR_MASK;
+ if (vendor != ICS932S401_VENDOR)
+ return -ENODEV;
+
+ device = i2c_smbus_read_word_data(client, ICS932S401_REG_DEVICE);
+ device >>= 8;
+ if (device != ICS932S401_DEVICE)
+ return -ENODEV;
+
+ if (revision != ICS932S401_REV)
+ dev_info(&adapter->dev, "Unknown revision %d\n", revision);
strlcpy(info->type, "ics932s401", I2C_NAME_SIZE);
diff --git a/drivers/misc/iwmc3200top/Kconfig b/drivers/misc/iwmc3200top/Kconfig
new file mode 100644
index 000000000000..9e4b88fb57f1
--- /dev/null
+++ b/drivers/misc/iwmc3200top/Kconfig
@@ -0,0 +1,20 @@
+config IWMC3200TOP
+ tristate "Intel Wireless MultiCom Top Driver"
+ depends on MMC && EXPERIMENTAL
+ select FW_LOADER
+ ---help---
+ Intel Wireless MultiCom 3200 Top driver is responsible for
+ for firmware load and enabled coms enumeration
+
+config IWMC3200TOP_DEBUG
+ bool "Enable full debug output of iwmc3200top Driver"
+ depends on IWMC3200TOP
+ ---help---
+ Enable full debug output of iwmc3200top Driver
+
+config IWMC3200TOP_DEBUGFS
+ bool "Enable Debugfs debugging interface for iwmc3200top"
+ depends on IWMC3200TOP
+ ---help---
+ Enable creation of debugfs files for iwmc3200top
+
diff --git a/drivers/misc/iwmc3200top/Makefile b/drivers/misc/iwmc3200top/Makefile
new file mode 100644
index 000000000000..fbf53fb4634e
--- /dev/null
+++ b/drivers/misc/iwmc3200top/Makefile
@@ -0,0 +1,29 @@
+# iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+# drivers/misc/iwmc3200top/Makefile
+#
+# Copyright (C) 2009 Intel 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.
+#
+# 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.
+#
+#
+# Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+# -
+#
+#
+
+obj-$(CONFIG_IWMC3200TOP) += iwmc3200top.o
+iwmc3200top-objs := main.o fw-download.o
+iwmc3200top-$(CONFIG_IWMC3200TOP_DEBUG) += log.o
+iwmc3200top-$(CONFIG_IWMC3200TOP_DEBUGFS) += debugfs.o
diff --git a/drivers/misc/iwmc3200top/debugfs.c b/drivers/misc/iwmc3200top/debugfs.c
new file mode 100644
index 000000000000..0c8ea0a1c8a3
--- /dev/null
+++ b/drivers/misc/iwmc3200top/debugfs.c
@@ -0,0 +1,133 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/debufs.c
+ *
+ * Copyright (C) 2009 Intel 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.
+ *
+ * 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.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ * -
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio.h>
+#include <linux/debugfs.h>
+
+#include "iwmc3200top.h"
+#include "fw-msg.h"
+#include "log.h"
+#include "debugfs.h"
+
+
+
+/* Constants definition */
+#define HEXADECIMAL_RADIX 16
+
+/* Functions definition */
+
+
+#define DEBUGFS_ADD(name, parent) do { \
+ dbgfs->dbgfs_##parent##_files.file_##name = \
+ debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \
+ &iwmct_dbgfs_##name##_ops); \
+} while (0)
+
+#define DEBUGFS_RM(name) do { \
+ debugfs_remove(name); \
+ name = NULL; \
+} while (0)
+
+#define DEBUGFS_READ_FUNC(name) \
+ssize_t iwmct_dbgfs_##name##_read(struct file *file, \
+ char __user *user_buf, \
+ size_t count, loff_t *ppos);
+
+#define DEBUGFS_WRITE_FUNC(name) \
+ssize_t iwmct_dbgfs_##name##_write(struct file *file, \
+ const char __user *user_buf, \
+ size_t count, loff_t *ppos);
+
+#define DEBUGFS_READ_FILE_OPS(name) \
+ DEBUGFS_READ_FUNC(name) \
+ static const struct file_operations iwmct_dbgfs_##name##_ops = { \
+ .read = iwmct_dbgfs_##name##_read, \
+ .open = iwmct_dbgfs_open_file_generic, \
+ };
+
+#define DEBUGFS_WRITE_FILE_OPS(name) \
+ DEBUGFS_WRITE_FUNC(name) \
+ static const struct file_operations iwmct_dbgfs_##name##_ops = { \
+ .write = iwmct_dbgfs_##name##_write, \
+ .open = iwmct_dbgfs_open_file_generic, \
+ };
+
+#define DEBUGFS_READ_WRITE_FILE_OPS(name) \
+ DEBUGFS_READ_FUNC(name) \
+ DEBUGFS_WRITE_FUNC(name) \
+ static const struct file_operations iwmct_dbgfs_##name##_ops = {\
+ .write = iwmct_dbgfs_##name##_write, \
+ .read = iwmct_dbgfs_##name##_read, \
+ .open = iwmct_dbgfs_open_file_generic, \
+ };
+
+
+/* Debugfs file ops definitions */
+
+/*
+ * Create the debugfs files and directories
+ *
+ */
+void iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name)
+{
+ struct iwmct_debugfs *dbgfs;
+
+ dbgfs = kzalloc(sizeof(struct iwmct_debugfs), GFP_KERNEL);
+ if (!dbgfs) {
+ LOG_ERROR(priv, DEBUGFS, "failed to allocate %zd bytes\n",
+ sizeof(struct iwmct_debugfs));
+ return;
+ }
+
+ priv->dbgfs = dbgfs;
+ dbgfs->name = name;
+ dbgfs->dir_drv = debugfs_create_dir(name, NULL);
+ if (!dbgfs->dir_drv) {
+ LOG_ERROR(priv, DEBUGFS, "failed to create debugfs dir\n");
+ return;
+ }
+
+ return;
+}
+
+/**
+ * Remove the debugfs files and directories
+ *
+ */
+void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs)
+{
+ if (!dbgfs)
+ return;
+
+ DEBUGFS_RM(dbgfs->dir_drv);
+ kfree(dbgfs);
+ dbgfs = NULL;
+}
+
diff --git a/drivers/misc/iwmc3200top/debugfs.h b/drivers/misc/iwmc3200top/debugfs.h
new file mode 100644
index 000000000000..71d45759b40f
--- /dev/null
+++ b/drivers/misc/iwmc3200top/debugfs.h
@@ -0,0 +1,58 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/debufs.h
+ *
+ * Copyright (C) 2009 Intel 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.
+ *
+ * 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.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ * -
+ *
+ */
+
+#ifndef __DEBUGFS_H__
+#define __DEBUGFS_H__
+
+
+#ifdef CONFIG_IWMC3200TOP_DEBUGFS
+
+struct iwmct_debugfs {
+ const char *name;
+ struct dentry *dir_drv;
+ struct dir_drv_files {
+ } dbgfs_drv_files;
+};
+
+void iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name);
+void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs);
+
+#else /* CONFIG_IWMC3200TOP_DEBUGFS */
+
+struct iwmct_debugfs;
+
+static inline void
+iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name)
+{}
+
+static inline void
+iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs)
+{}
+
+#endif /* CONFIG_IWMC3200TOP_DEBUGFS */
+
+#endif /* __DEBUGFS_H__ */
+
diff --git a/drivers/misc/iwmc3200top/fw-download.c b/drivers/misc/iwmc3200top/fw-download.c
new file mode 100644
index 000000000000..33cb693dd37c
--- /dev/null
+++ b/drivers/misc/iwmc3200top/fw-download.c
@@ -0,0 +1,359 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/fw-download.c
+ *
+ * Copyright (C) 2009 Intel 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.
+ *
+ * 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.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ * -
+ *
+ */
+
+#include <linux/firmware.h>
+#include <linux/mmc/sdio_func.h>
+#include <asm/unaligned.h>
+
+#include "iwmc3200top.h"
+#include "log.h"
+#include "fw-msg.h"
+
+#define CHECKSUM_BYTES_NUM sizeof(u32)
+
+/**
+ init parser struct with file
+ */
+static int iwmct_fw_parser_init(struct iwmct_priv *priv, const u8 *file,
+ size_t file_size, size_t block_size)
+{
+ struct iwmct_parser *parser = &priv->parser;
+ struct iwmct_fw_hdr *fw_hdr = &parser->versions;
+
+ LOG_INFOEX(priv, INIT, "-->\n");
+
+ LOG_INFO(priv, FW_DOWNLOAD, "file_size=%zd\n", file_size);
+
+ parser->file = file;
+ parser->file_size = file_size;
+ parser->cur_pos = 0;
+ parser->buf = NULL;
+
+ parser->buf = kzalloc(block_size, GFP_KERNEL);
+ if (!parser->buf) {
+ LOG_ERROR(priv, FW_DOWNLOAD, "kzalloc error\n");
+ return -ENOMEM;
+ }
+ parser->buf_size = block_size;
+
+ /* extract fw versions */
+ memcpy(fw_hdr, parser->file, sizeof(struct iwmct_fw_hdr));
+ LOG_INFO(priv, FW_DOWNLOAD, "fw versions are:\n"
+ "top %u.%u.%u gps %u.%u.%u bt %u.%u.%u tic %s\n",
+ fw_hdr->top_major, fw_hdr->top_minor, fw_hdr->top_revision,
+ fw_hdr->gps_major, fw_hdr->gps_minor, fw_hdr->gps_revision,
+ fw_hdr->bt_major, fw_hdr->bt_minor, fw_hdr->bt_revision,
+ fw_hdr->tic_name);
+
+ parser->cur_pos += sizeof(struct iwmct_fw_hdr);
+
+ LOG_INFOEX(priv, INIT, "<--\n");
+ return 0;
+}
+
+static bool iwmct_checksum(struct iwmct_priv *priv)
+{
+ struct iwmct_parser *parser = &priv->parser;
+ __le32 *file = (__le32 *)parser->file;
+ int i, pad, steps;
+ u32 accum = 0;
+ u32 checksum;
+ u32 mask = 0xffffffff;
+
+ pad = (parser->file_size - CHECKSUM_BYTES_NUM) % 4;
+ steps = (parser->file_size - CHECKSUM_BYTES_NUM) / 4;
+
+ LOG_INFO(priv, FW_DOWNLOAD, "pad=%d steps=%d\n", pad, steps);
+
+ for (i = 0; i < steps; i++)
+ accum += le32_to_cpu(file[i]);
+
+ if (pad) {
+ mask <<= 8 * (4 - pad);
+ accum += le32_to_cpu(file[steps]) & mask;
+ }
+
+ checksum = get_unaligned_le32((__le32 *)(parser->file +
+ parser->file_size - CHECKSUM_BYTES_NUM));
+
+ LOG_INFO(priv, FW_DOWNLOAD,
+ "compare checksum accum=0x%x to checksum=0x%x\n",
+ accum, checksum);
+
+ return checksum == accum;
+}
+
+static int iwmct_parse_next_section(struct iwmct_priv *priv, const u8 **p_sec,
+ size_t *sec_size, __le32 *sec_addr)
+{
+ struct iwmct_parser *parser = &priv->parser;
+ struct iwmct_dbg *dbg = &priv->dbg;
+ struct iwmct_fw_sec_hdr *sec_hdr;
+
+ LOG_INFOEX(priv, INIT, "-->\n");
+
+ while (parser->cur_pos + sizeof(struct iwmct_fw_sec_hdr)
+ <= parser->file_size) {
+
+ sec_hdr = (struct iwmct_fw_sec_hdr *)
+ (parser->file + parser->cur_pos);
+ parser->cur_pos += sizeof(struct iwmct_fw_sec_hdr);
+
+ LOG_INFO(priv, FW_DOWNLOAD,
+ "sec hdr: type=%s addr=0x%x size=%d\n",
+ sec_hdr->type, sec_hdr->target_addr,
+ sec_hdr->data_size);
+
+ if (strcmp(sec_hdr->type, "ENT") == 0)
+ parser->entry_point = le32_to_cpu(sec_hdr->target_addr);
+ else if (strcmp(sec_hdr->type, "LBL") == 0)
+ strcpy(dbg->label_fw, parser->file + parser->cur_pos);
+ else if (((strcmp(sec_hdr->type, "TOP") == 0) &&
+ (priv->barker & BARKER_DNLOAD_TOP_MSK)) ||
+ ((strcmp(sec_hdr->type, "GPS") == 0) &&
+ (priv->barker & BARKER_DNLOAD_GPS_MSK)) ||
+ ((strcmp(sec_hdr->type, "BTH") == 0) &&
+ (priv->barker & BARKER_DNLOAD_BT_MSK))) {
+ *sec_addr = sec_hdr->target_addr;
+ *sec_size = le32_to_cpu(sec_hdr->data_size);
+ *p_sec = parser->file + parser->cur_pos;
+ parser->cur_pos += le32_to_cpu(sec_hdr->data_size);
+ return 1;
+ } else if (strcmp(sec_hdr->type, "LOG") != 0)
+ LOG_WARNING(priv, FW_DOWNLOAD,
+ "skipping section type %s\n",
+ sec_hdr->type);
+
+ parser->cur_pos += le32_to_cpu(sec_hdr->data_size);
+ LOG_INFO(priv, FW_DOWNLOAD,
+ "finished with section cur_pos=%zd\n", parser->cur_pos);
+ }
+
+ LOG_INFOEX(priv, INIT, "<--\n");
+ return 0;
+}
+
+static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec,
+ size_t sec_size, __le32 addr)
+{
+ struct iwmct_parser *parser = &priv->parser;
+ struct iwmct_fw_load_hdr *hdr = (struct iwmct_fw_load_hdr *)parser->buf;
+ const u8 *cur_block = p_sec;
+ size_t sent = 0;
+ int cnt = 0;
+ int ret = 0;
+ u32 cmd = 0;
+
+ LOG_INFOEX(priv, INIT, "-->\n");
+ LOG_INFO(priv, FW_DOWNLOAD, "Download address 0x%x size 0x%zx\n",
+ addr, sec_size);
+
+ while (sent < sec_size) {
+ int i;
+ u32 chksm = 0;
+ u32 reset = atomic_read(&priv->reset);
+ /* actual FW data */
+ u32 data_size = min(parser->buf_size - sizeof(*hdr),
+ sec_size - sent);
+ /* Pad to block size */
+ u32 trans_size = (data_size + sizeof(*hdr) +
+ IWMC_SDIO_BLK_SIZE - 1) &
+ ~(IWMC_SDIO_BLK_SIZE - 1);
+ ++cnt;
+
+ /* in case of reset, interrupt FW DOWNLAOD */
+ if (reset) {
+ LOG_INFO(priv, FW_DOWNLOAD,
+ "Reset detected. Abort FW download!!!");
+ ret = -ECANCELED;
+ goto exit;
+ }
+
+ memset(parser->buf, 0, parser->buf_size);
+ cmd |= IWMC_OPCODE_WRITE << CMD_HDR_OPCODE_POS;
+ cmd |= IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS;
+ cmd |= (priv->dbg.direct ? 1 : 0) << CMD_HDR_DIRECT_ACCESS_POS;
+ cmd |= (priv->dbg.checksum ? 1 : 0) << CMD_HDR_USE_CHECKSUM_POS;
+ hdr->data_size = cpu_to_le32(data_size);
+ hdr->target_addr = addr;
+
+ /* checksum is allowed for sizes divisible by 4 */
+ if (data_size & 0x3)
+ cmd &= ~CMD_HDR_USE_CHECKSUM_MSK;
+
+ memcpy(hdr->data, cur_block, data_size);
+
+
+ if (cmd & CMD_HDR_USE_CHECKSUM_MSK) {
+
+ chksm = data_size + le32_to_cpu(addr) + cmd;
+ for (i = 0; i < data_size >> 2; i++)
+ chksm += ((u32 *)cur_block)[i];
+
+ hdr->block_chksm = cpu_to_le32(chksm);
+ LOG_INFO(priv, FW_DOWNLOAD, "Checksum = 0x%X\n",
+ hdr->block_chksm);
+ }
+
+ LOG_INFO(priv, FW_DOWNLOAD, "trans#%d, len=%d, sent=%zd, "
+ "sec_size=%zd, startAddress 0x%X\n",
+ cnt, trans_size, sent, sec_size, addr);
+
+ if (priv->dbg.dump)
+ LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, trans_size);
+
+
+ hdr->cmd = cpu_to_le32(cmd);
+ /* send it down */
+ /* TODO: add more proper sending and error checking */
+ ret = iwmct_tx(priv, 0, parser->buf, trans_size);
+ if (ret != 0) {
+ LOG_INFO(priv, FW_DOWNLOAD,
+ "iwmct_tx returned %d\n", ret);
+ goto exit;
+ }
+
+ addr = cpu_to_le32(le32_to_cpu(addr) + data_size);
+ sent += data_size;
+ cur_block = p_sec + sent;
+
+ if (priv->dbg.blocks && (cnt + 1) >= priv->dbg.blocks) {
+ LOG_INFO(priv, FW_DOWNLOAD,
+ "Block number limit is reached [%d]\n",
+ priv->dbg.blocks);
+ break;
+ }
+ }
+
+ if (sent < sec_size)
+ ret = -EINVAL;
+exit:
+ LOG_INFOEX(priv, INIT, "<--\n");
+ return ret;
+}
+
+static int iwmct_kick_fw(struct iwmct_priv *priv, bool jump)
+{
+ struct iwmct_parser *parser = &priv->parser;
+ struct iwmct_fw_load_hdr *hdr = (struct iwmct_fw_load_hdr *)parser->buf;
+ int ret;
+ u32 cmd;
+
+ LOG_INFOEX(priv, INIT, "-->\n");
+
+ memset(parser->buf, 0, parser->buf_size);
+ cmd = IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS;
+ if (jump) {
+ cmd |= IWMC_OPCODE_JUMP << CMD_HDR_OPCODE_POS;
+ hdr->target_addr = cpu_to_le32(parser->entry_point);
+ LOG_INFO(priv, FW_DOWNLOAD, "jump address 0x%x\n",
+ parser->entry_point);
+ } else {
+ cmd |= IWMC_OPCODE_LAST_COMMAND << CMD_HDR_OPCODE_POS;
+ LOG_INFO(priv, FW_DOWNLOAD, "last command\n");
+ }
+
+ hdr->cmd = cpu_to_le32(cmd);
+
+ LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, sizeof(*hdr));
+ /* send it down */
+ /* TODO: add more proper sending and error checking */
+ ret = iwmct_tx(priv, 0, parser->buf, IWMC_SDIO_BLK_SIZE);
+ if (ret)
+ LOG_INFO(priv, FW_DOWNLOAD, "iwmct_tx returned %d", ret);
+
+ LOG_INFOEX(priv, INIT, "<--\n");
+ return 0;
+}
+
+int iwmct_fw_load(struct iwmct_priv *priv)
+{
+ const struct firmware *raw = NULL;
+ __le32 addr;
+ size_t len;
+ const u8 *pdata;
+ const u8 *name = "iwmc3200top.1.fw";
+ int ret = 0;
+
+ /* clear parser struct */
+ memset(&priv->parser, 0, sizeof(struct iwmct_parser));
+ if (!name) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* get the firmware */
+ ret = request_firmware(&raw, name, &priv->func->dev);
+ if (ret < 0) {
+ LOG_ERROR(priv, FW_DOWNLOAD, "%s request_firmware failed %d\n",
+ name, ret);
+ goto exit;
+ }
+
+ if (raw->size < sizeof(struct iwmct_fw_sec_hdr)) {
+ LOG_ERROR(priv, FW_DOWNLOAD, "%s smaller then (%zd) (%zd)\n",
+ name, sizeof(struct iwmct_fw_sec_hdr), raw->size);
+ goto exit;
+ }
+
+ LOG_INFO(priv, FW_DOWNLOAD, "Read firmware '%s'\n", name);
+
+ ret = iwmct_fw_parser_init(priv, raw->data, raw->size, priv->trans_len);
+ if (ret < 0) {
+ LOG_ERROR(priv, FW_DOWNLOAD,
+ "iwmct_parser_init failed: Reason %d\n", ret);
+ goto exit;
+ }
+
+ /* checksum */
+ if (!iwmct_checksum(priv)) {
+ LOG_ERROR(priv, FW_DOWNLOAD, "checksum error\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* download firmware to device */
+ while (iwmct_parse_next_section(priv, &pdata, &len, &addr)) {
+ if (iwmct_download_section(priv, pdata, len, addr)) {
+ LOG_ERROR(priv, FW_DOWNLOAD,
+ "%s download section failed\n", name);
+ ret = -EIO;
+ goto exit;
+ }
+ }
+
+ iwmct_kick_fw(priv, !!(priv->barker & BARKER_DNLOAD_JUMP_MSK));
+
+exit:
+ kfree(priv->parser.buf);
+
+ if (raw)
+ release_firmware(raw);
+
+ raw = NULL;
+
+ return ret;
+}
diff --git a/drivers/misc/iwmc3200top/fw-msg.h b/drivers/misc/iwmc3200top/fw-msg.h
new file mode 100644
index 000000000000..9e26b75bd482
--- /dev/null
+++ b/drivers/misc/iwmc3200top/fw-msg.h
@@ -0,0 +1,113 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/fw-msg.h
+ *
+ * Copyright (C) 2009 Intel 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.
+ *
+ * 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.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ * -
+ *
+ */
+
+#ifndef __FWMSG_H__
+#define __FWMSG_H__
+
+#define COMM_TYPE_D2H 0xFF
+#define COMM_TYPE_H2D 0xEE
+
+#define COMM_CATEGORY_OPERATIONAL 0x00
+#define COMM_CATEGORY_DEBUG 0x01
+#define COMM_CATEGORY_TESTABILITY 0x02
+#define COMM_CATEGORY_DIAGNOSTICS 0x03
+
+#define OP_DBG_ZSTR_MSG cpu_to_le16(0x1A)
+
+#define FW_LOG_SRC_MAX 32
+#define FW_LOG_SRC_ALL 255
+
+#define FW_STRING_TABLE_ADDR cpu_to_le32(0x0C000000)
+
+#define CMD_DBG_LOG_LEVEL cpu_to_le16(0x0001)
+#define CMD_TST_DEV_RESET cpu_to_le16(0x0060)
+#define CMD_TST_FUNC_RESET cpu_to_le16(0x0062)
+#define CMD_TST_IFACE_RESET cpu_to_le16(0x0064)
+#define CMD_TST_CPU_UTILIZATION cpu_to_le16(0x0065)
+#define CMD_TST_TOP_DEEP_SLEEP cpu_to_le16(0x0080)
+#define CMD_TST_WAKEUP cpu_to_le16(0x0081)
+#define CMD_TST_FUNC_WAKEUP cpu_to_le16(0x0082)
+#define CMD_TST_FUNC_DEEP_SLEEP_REQUEST cpu_to_le16(0x0083)
+#define CMD_TST_GET_MEM_DUMP cpu_to_le16(0x0096)
+
+#define OP_OPR_ALIVE cpu_to_le16(0x0010)
+#define OP_OPR_CMD_ACK cpu_to_le16(0x001F)
+#define OP_OPR_CMD_NACK cpu_to_le16(0x0020)
+#define OP_TST_MEM_DUMP cpu_to_le16(0x0043)
+
+#define CMD_FLAG_PADDING_256 0x80
+
+#define FW_HCMD_BLOCK_SIZE 256
+
+struct msg_hdr {
+ u8 type;
+ u8 category;
+ __le16 opcode;
+ u8 seqnum;
+ u8 flags;
+ __le16 length;
+} __attribute__((__packed__));
+
+struct log_hdr {
+ __le32 timestamp;
+ u8 severity;
+ u8 logsource;
+ __le16 reserved;
+} __attribute__((__packed__));
+
+struct mdump_hdr {
+ u8 dmpid;
+ u8 frag;
+ __le16 size;
+ __le32 addr;
+} __attribute__((__packed__));
+
+struct top_msg {
+ struct msg_hdr hdr;
+ union {
+ /* D2H messages */
+ struct {
+ struct log_hdr log_hdr;
+ u8 data[1];
+ } __attribute__((__packed__)) log;
+
+ struct {
+ struct log_hdr log_hdr;
+ struct mdump_hdr md_hdr;
+ u8 data[1];
+ } __attribute__((__packed__)) mdump;
+
+ /* H2D messages */
+ struct {
+ u8 logsource;
+ u8 sevmask;
+ } __attribute__((__packed__)) logdefs[FW_LOG_SRC_MAX];
+ struct mdump_hdr mdump_req;
+ } u;
+} __attribute__((__packed__));
+
+
+#endif /* __FWMSG_H__ */
diff --git a/drivers/misc/iwmc3200top/iwmc3200top.h b/drivers/misc/iwmc3200top/iwmc3200top.h
new file mode 100644
index 000000000000..f572fcf177a1
--- /dev/null
+++ b/drivers/misc/iwmc3200top/iwmc3200top.h
@@ -0,0 +1,206 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/iwmc3200top.h
+ *
+ * Copyright (C) 2009 Intel 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.
+ *
+ * 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.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ * -
+ *
+ */
+
+#ifndef __IWMC3200TOP_H__
+#define __IWMC3200TOP_H__
+
+#include <linux/workqueue.h>
+
+#define DRV_NAME "iwmc3200top"
+
+#define IWMC_SDIO_BLK_SIZE 256
+#define IWMC_DEFAULT_TR_BLK 64
+#define IWMC_SDIO_DATA_ADDR 0x0
+#define IWMC_SDIO_INTR_ENABLE_ADDR 0x14
+#define IWMC_SDIO_INTR_STATUS_ADDR 0x13
+#define IWMC_SDIO_INTR_CLEAR_ADDR 0x13
+#define IWMC_SDIO_INTR_GET_SIZE_ADDR 0x2C
+
+#define COMM_HUB_HEADER_LENGTH 16
+#define LOGGER_HEADER_LENGTH 10
+
+
+#define BARKER_DNLOAD_BT_POS 0
+#define BARKER_DNLOAD_BT_MSK BIT(BARKER_DNLOAD_BT_POS)
+#define BARKER_DNLOAD_GPS_POS 1
+#define BARKER_DNLOAD_GPS_MSK BIT(BARKER_DNLOAD_GPS_POS)
+#define BARKER_DNLOAD_TOP_POS 2
+#define BARKER_DNLOAD_TOP_MSK BIT(BARKER_DNLOAD_TOP_POS)
+#define BARKER_DNLOAD_RESERVED1_POS 3
+#define BARKER_DNLOAD_RESERVED1_MSK BIT(BARKER_DNLOAD_RESERVED1_POS)
+#define BARKER_DNLOAD_JUMP_POS 4
+#define BARKER_DNLOAD_JUMP_MSK BIT(BARKER_DNLOAD_JUMP_POS)
+#define BARKER_DNLOAD_SYNC_POS 5
+#define BARKER_DNLOAD_SYNC_MSK BIT(BARKER_DNLOAD_SYNC_POS)
+#define BARKER_DNLOAD_RESERVED2_POS 6
+#define BARKER_DNLOAD_RESERVED2_MSK (0x3 << BARKER_DNLOAD_RESERVED2_POS)
+#define BARKER_DNLOAD_BARKER_POS 8
+#define BARKER_DNLOAD_BARKER_MSK (0xffffff << BARKER_DNLOAD_BARKER_POS)
+
+#define IWMC_BARKER_REBOOT (0xdeadbe << BARKER_DNLOAD_BARKER_POS)
+/* whole field barker */
+#define IWMC_BARKER_ACK 0xfeedbabe
+
+#define IWMC_CMD_SIGNATURE 0xcbbc
+
+#define CMD_HDR_OPCODE_POS 0
+#define CMD_HDR_OPCODE_MSK_MSK (0xf << CMD_HDR_OPCODE_MSK_POS)
+#define CMD_HDR_RESPONSE_CODE_POS 4
+#define CMD_HDR_RESPONSE_CODE_MSK (0xf << CMD_HDR_RESPONSE_CODE_POS)
+#define CMD_HDR_USE_CHECKSUM_POS 8
+#define CMD_HDR_USE_CHECKSUM_MSK BIT(CMD_HDR_USE_CHECKSUM_POS)
+#define CMD_HDR_RESPONSE_REQUIRED_POS 9
+#define CMD_HDR_RESPONSE_REQUIRED_MSK BIT(CMD_HDR_RESPONSE_REQUIRED_POS)
+#define CMD_HDR_DIRECT_ACCESS_POS 10
+#define CMD_HDR_DIRECT_ACCESS_MSK BIT(CMD_HDR_DIRECT_ACCESS_POS)
+#define CMD_HDR_RESERVED_POS 11
+#define CMD_HDR_RESERVED_MSK BIT(0x1f << CMD_HDR_RESERVED_POS)
+#define CMD_HDR_SIGNATURE_POS 16
+#define CMD_HDR_SIGNATURE_MSK BIT(0xffff << CMD_HDR_SIGNATURE_POS)
+
+enum {
+ IWMC_OPCODE_PING = 0,
+ IWMC_OPCODE_READ = 1,
+ IWMC_OPCODE_WRITE = 2,
+ IWMC_OPCODE_JUMP = 3,
+ IWMC_OPCODE_REBOOT = 4,
+ IWMC_OPCODE_PERSISTENT_WRITE = 5,
+ IWMC_OPCODE_PERSISTENT_READ = 6,
+ IWMC_OPCODE_READ_MODIFY_WRITE = 7,
+ IWMC_OPCODE_LAST_COMMAND = 15
+};
+
+struct iwmct_fw_load_hdr {
+ __le32 cmd;
+ __le32 target_addr;
+ __le32 data_size;
+ __le32 block_chksm;
+ u8 data[0];
+};
+
+/**
+ * struct iwmct_fw_hdr
+ * holds all sw components versions
+ */
+struct iwmct_fw_hdr {
+ u8 top_major;
+ u8 top_minor;
+ u8 top_revision;
+ u8 gps_major;
+ u8 gps_minor;
+ u8 gps_revision;
+ u8 bt_major;
+ u8 bt_minor;
+ u8 bt_revision;
+ u8 tic_name[31];
+};
+
+/**
+ * struct iwmct_fw_sec_hdr
+ * @type: function type
+ * @data_size: section's data size
+ * @target_addr: download address
+ */
+struct iwmct_fw_sec_hdr {
+ u8 type[4];
+ __le32 data_size;
+ __le32 target_addr;
+};
+
+/**
+ * struct iwmct_parser
+ * @file: fw image
+ * @file_size: fw size
+ * @cur_pos: position in file
+ * @buf: temp buf for download
+ * @buf_size: size of buf
+ * @entry_point: address to jump in fw kick-off
+ */
+struct iwmct_parser {
+ const u8 *file;
+ size_t file_size;
+ size_t cur_pos;
+ u8 *buf;
+ size_t buf_size;
+ u32 entry_point;
+ struct iwmct_fw_hdr versions;
+};
+
+
+struct iwmct_work_struct {
+ struct list_head list;
+ ssize_t iosize;
+};
+
+struct iwmct_dbg {
+ int blocks;
+ bool dump;
+ bool jump;
+ bool direct;
+ bool checksum;
+ bool fw_download;
+ int block_size;
+ int download_trans_blks;
+
+ char label_fw[256];
+};
+
+struct iwmct_debugfs;
+
+struct iwmct_priv {
+ struct sdio_func *func;
+ struct iwmct_debugfs *dbgfs;
+ struct iwmct_parser parser;
+ atomic_t reset;
+ atomic_t dev_sync;
+ u32 trans_len;
+ u32 barker;
+ struct iwmct_dbg dbg;
+
+ /* drivers work queue */
+ struct workqueue_struct *wq;
+ struct workqueue_struct *bus_rescan_wq;
+ struct work_struct bus_rescan_worker;
+ struct work_struct isr_worker;
+
+ /* drivers wait queue */
+ wait_queue_head_t wait_q;
+
+ /* rx request list */
+ struct list_head read_req_list;
+};
+
+extern int iwmct_tx(struct iwmct_priv *priv, unsigned int addr,
+ void *src, int count);
+
+extern int iwmct_fw_load(struct iwmct_priv *priv);
+
+extern void iwmct_dbg_init_params(struct iwmct_priv *drv);
+extern void iwmct_dbg_init_drv_attrs(struct device_driver *drv);
+extern void iwmct_dbg_remove_drv_attrs(struct device_driver *drv);
+extern int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len);
+
+#endif /* __IWMC3200TOP_H__ */
diff --git a/drivers/misc/iwmc3200top/log.c b/drivers/misc/iwmc3200top/log.c
new file mode 100644
index 000000000000..d569279698f6
--- /dev/null
+++ b/drivers/misc/iwmc3200top/log.c
@@ -0,0 +1,347 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/log.c
+ *
+ * Copyright (C) 2009 Intel 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.
+ *
+ * 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.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ * -
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/ctype.h>
+#include "fw-msg.h"
+#include "iwmc3200top.h"
+#include "log.h"
+
+/* Maximal hexadecimal string size of the FW memdump message */
+#define LOG_MSG_SIZE_MAX 12400
+
+/* iwmct_logdefs is a global used by log macros */
+u8 iwmct_logdefs[LOG_SRC_MAX];
+static u8 iwmct_fw_logdefs[FW_LOG_SRC_MAX];
+
+
+static int _log_set_log_filter(u8 *logdefs, int size, u8 src, u8 logmask)
+{
+ int i;
+
+ if (src < size)
+ logdefs[src] = logmask;
+ else if (src == LOG_SRC_ALL)
+ for (i = 0; i < size; i++)
+ logdefs[i] = logmask;
+ else
+ return -1;
+
+ return 0;
+}
+
+
+int iwmct_log_set_filter(u8 src, u8 logmask)
+{
+ return _log_set_log_filter(iwmct_logdefs, LOG_SRC_MAX, src, logmask);
+}
+
+
+int iwmct_log_set_fw_filter(u8 src, u8 logmask)
+{
+ return _log_set_log_filter(iwmct_fw_logdefs,
+ FW_LOG_SRC_MAX, src, logmask);
+}
+
+
+static int log_msg_format_hex(char *str, int slen, u8 *ibuf,
+ int ilen, char *pref)
+{
+ int pos = 0;
+ int i;
+ int len;
+
+ for (pos = 0, i = 0; pos < slen - 2 && pref[i] != '\0'; i++, pos++)
+ str[pos] = pref[i];
+
+ for (i = 0; pos < slen - 2 && i < ilen; pos += len, i++)
+ len = snprintf(&str[pos], slen - pos - 1, " %2.2X", ibuf[i]);
+
+ if (i < ilen)
+ return -1;
+
+ return 0;
+}
+
+/* NOTE: This function is not thread safe.
+ Currently it's called only from sdio rx worker - no race there
+*/
+void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len)
+{
+ struct top_msg *msg;
+ static char logbuf[LOG_MSG_SIZE_MAX];
+
+ msg = (struct top_msg *)buf;
+
+ if (len < sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr)) {
+ LOG_ERROR(priv, FW_MSG, "Log message from TOP "
+ "is too short %d (expected %zd)\n",
+ len, sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr));
+ return;
+ }
+
+ if (!(iwmct_fw_logdefs[msg->u.log.log_hdr.logsource] &
+ BIT(msg->u.log.log_hdr.severity)) ||
+ !(iwmct_logdefs[LOG_SRC_FW_MSG] & BIT(msg->u.log.log_hdr.severity)))
+ return;
+
+ switch (msg->hdr.category) {
+ case COMM_CATEGORY_TESTABILITY:
+ if (!(iwmct_logdefs[LOG_SRC_TST] &
+ BIT(msg->u.log.log_hdr.severity)))
+ return;
+ if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf,
+ le16_to_cpu(msg->hdr.length) +
+ sizeof(msg->hdr), "<TST>"))
+ LOG_WARNING(priv, TST,
+ "TOP TST message is too long, truncating...");
+ LOG_WARNING(priv, TST, "%s\n", logbuf);
+ break;
+ case COMM_CATEGORY_DEBUG:
+ if (msg->hdr.opcode == OP_DBG_ZSTR_MSG)
+ LOG_INFO(priv, FW_MSG, "%s %s", "<DBG>",
+ ((u8 *)msg) + sizeof(msg->hdr)
+ + sizeof(msg->u.log.log_hdr));
+ else {
+ if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf,
+ le16_to_cpu(msg->hdr.length)
+ + sizeof(msg->hdr),
+ "<DBG>"))
+ LOG_WARNING(priv, FW_MSG,
+ "TOP DBG message is too long,"
+ "truncating...");
+ LOG_WARNING(priv, FW_MSG, "%s\n", logbuf);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static int _log_get_filter_str(u8 *logdefs, int logdefsz, char *buf, int size)
+{
+ int i, pos, len;
+ for (i = 0, pos = 0; (pos < size-1) && (i < logdefsz); i++) {
+ len = snprintf(&buf[pos], size - pos - 1, "0x%02X%02X,",
+ i, logdefs[i]);
+ pos += len;
+ }
+ buf[pos-1] = '\n';
+ buf[pos] = '\0';
+
+ if (i < logdefsz)
+ return -1;
+ return 0;
+}
+
+int log_get_filter_str(char *buf, int size)
+{
+ return _log_get_filter_str(iwmct_logdefs, LOG_SRC_MAX, buf, size);
+}
+
+int log_get_fw_filter_str(char *buf, int size)
+{
+ return _log_get_filter_str(iwmct_fw_logdefs, FW_LOG_SRC_MAX, buf, size);
+}
+
+#define HEXADECIMAL_RADIX 16
+#define LOG_SRC_FORMAT 7 /* log level is in format of "0xXXXX," */
+
+ssize_t show_iwmct_log_level(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwmct_priv *priv = dev_get_drvdata(d);
+ char *str_buf;
+ int buf_size;
+ ssize_t ret;
+
+ buf_size = (LOG_SRC_FORMAT * LOG_SRC_MAX) + 1;
+ str_buf = kzalloc(buf_size, GFP_KERNEL);
+ if (!str_buf) {
+ LOG_ERROR(priv, DEBUGFS,
+ "failed to allocate %d bytes\n", buf_size);
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ if (log_get_filter_str(str_buf, buf_size) < 0) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = sprintf(buf, "%s", str_buf);
+
+exit:
+ kfree(str_buf);
+ return ret;
+}
+
+ssize_t store_iwmct_log_level(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwmct_priv *priv = dev_get_drvdata(d);
+ char *token, *str_buf = NULL;
+ long val;
+ ssize_t ret = count;
+ u8 src, mask;
+
+ if (!count)
+ goto exit;
+
+ str_buf = kzalloc(count, GFP_KERNEL);
+ if (!str_buf) {
+ LOG_ERROR(priv, DEBUGFS,
+ "failed to allocate %zd bytes\n", count);
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ memcpy(str_buf, buf, count);
+
+ while ((token = strsep(&str_buf, ",")) != NULL) {
+ while (isspace(*token))
+ ++token;
+ if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) {
+ LOG_ERROR(priv, DEBUGFS,
+ "failed to convert string to long %s\n",
+ token);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ mask = val & 0xFF;
+ src = (val & 0XFF00) >> 8;
+ iwmct_log_set_filter(src, mask);
+ }
+
+exit:
+ kfree(str_buf);
+ return ret;
+}
+
+ssize_t show_iwmct_log_level_fw(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwmct_priv *priv = dev_get_drvdata(d);
+ char *str_buf;
+ int buf_size;
+ ssize_t ret;
+
+ buf_size = (LOG_SRC_FORMAT * FW_LOG_SRC_MAX) + 2;
+
+ str_buf = kzalloc(buf_size, GFP_KERNEL);
+ if (!str_buf) {
+ LOG_ERROR(priv, DEBUGFS,
+ "failed to allocate %d bytes\n", buf_size);
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ if (log_get_fw_filter_str(str_buf, buf_size) < 0) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = sprintf(buf, "%s", str_buf);
+
+exit:
+ kfree(str_buf);
+ return ret;
+}
+
+ssize_t store_iwmct_log_level_fw(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwmct_priv *priv = dev_get_drvdata(d);
+ struct top_msg cmd;
+ char *token, *str_buf = NULL;
+ ssize_t ret = count;
+ u16 cmdlen = 0;
+ int i;
+ long val;
+ u8 src, mask;
+
+ if (!count)
+ goto exit;
+
+ str_buf = kzalloc(count, GFP_KERNEL);
+ if (!str_buf) {
+ LOG_ERROR(priv, DEBUGFS,
+ "failed to allocate %zd bytes\n", count);
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ memcpy(str_buf, buf, count);
+
+ cmd.hdr.type = COMM_TYPE_H2D;
+ cmd.hdr.category = COMM_CATEGORY_DEBUG;
+ cmd.hdr.opcode = CMD_DBG_LOG_LEVEL;
+
+ for (i = 0; ((token = strsep(&str_buf, ",")) != NULL) &&
+ (i < FW_LOG_SRC_MAX); i++) {
+
+ while (isspace(*token))
+ ++token;
+
+ if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) {
+ LOG_ERROR(priv, DEBUGFS,
+ "failed to convert string to long %s\n",
+ token);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ mask = val & 0xFF; /* LSB */
+ src = (val & 0XFF00) >> 8; /* 2nd least significant byte. */
+ iwmct_log_set_fw_filter(src, mask);
+
+ cmd.u.logdefs[i].logsource = src;
+ cmd.u.logdefs[i].sevmask = mask;
+ }
+
+ cmd.hdr.length = cpu_to_le16(i * sizeof(cmd.u.logdefs[0]));
+ cmdlen = (i * sizeof(cmd.u.logdefs[0]) + sizeof(cmd.hdr));
+
+ ret = iwmct_send_hcmd(priv, (u8 *)&cmd, cmdlen);
+ if (ret) {
+ LOG_ERROR(priv, DEBUGFS,
+ "Failed to send %d bytes of fwcmd, ret=%zd\n",
+ cmdlen, ret);
+ goto exit;
+ } else
+ LOG_INFO(priv, DEBUGFS, "fwcmd sent (%d bytes)\n", cmdlen);
+
+ ret = count;
+
+exit:
+ kfree(str_buf);
+ return ret;
+}
+
diff --git a/drivers/misc/iwmc3200top/log.h b/drivers/misc/iwmc3200top/log.h
new file mode 100644
index 000000000000..aba8121f978c
--- /dev/null
+++ b/drivers/misc/iwmc3200top/log.h
@@ -0,0 +1,158 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/log.h
+ *
+ * Copyright (C) 2009 Intel 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.
+ *
+ * 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.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ * -
+ *
+ */
+
+#ifndef __LOG_H__
+#define __LOG_H__
+
+
+/* log severity:
+ * The log levels here match FW log levels
+ * so values need to stay as is */
+#define LOG_SEV_CRITICAL 0
+#define LOG_SEV_ERROR 1
+#define LOG_SEV_WARNING 2
+#define LOG_SEV_INFO 3
+#define LOG_SEV_INFOEX 4
+
+#define LOG_SEV_FILTER_ALL \
+ (BIT(LOG_SEV_CRITICAL) | \
+ BIT(LOG_SEV_ERROR) | \
+ BIT(LOG_SEV_WARNING) | \
+ BIT(LOG_SEV_INFO) | \
+ BIT(LOG_SEV_INFOEX))
+
+/* log source */
+#define LOG_SRC_INIT 0
+#define LOG_SRC_DEBUGFS 1
+#define LOG_SRC_FW_DOWNLOAD 2
+#define LOG_SRC_FW_MSG 3
+#define LOG_SRC_TST 4
+#define LOG_SRC_IRQ 5
+
+#define LOG_SRC_MAX 6
+#define LOG_SRC_ALL 0xFF
+
+/**
+ * Default intitialization runtime log level
+ */
+#ifndef LOG_SEV_FILTER_RUNTIME
+#define LOG_SEV_FILTER_RUNTIME \
+ (BIT(LOG_SEV_CRITICAL) | \
+ BIT(LOG_SEV_ERROR) | \
+ BIT(LOG_SEV_WARNING))
+#endif
+
+#ifndef FW_LOG_SEV_FILTER_RUNTIME
+#define FW_LOG_SEV_FILTER_RUNTIME LOG_SEV_FILTER_ALL
+#endif
+
+#ifdef CONFIG_IWMC3200TOP_DEBUG
+/**
+ * Log macros
+ */
+
+#define priv2dev(priv) (&(priv->func)->dev)
+
+#define LOG_CRITICAL(priv, src, fmt, args...) \
+do { \
+ if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_CRITICAL)) \
+ dev_crit(priv2dev(priv), "%s %d: " fmt, \
+ __func__, __LINE__, ##args); \
+} while (0)
+
+#define LOG_ERROR(priv, src, fmt, args...) \
+do { \
+ if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_ERROR)) \
+ dev_err(priv2dev(priv), "%s %d: " fmt, \
+ __func__, __LINE__, ##args); \
+} while (0)
+
+#define LOG_WARNING(priv, src, fmt, args...) \
+do { \
+ if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_WARNING)) \
+ dev_warn(priv2dev(priv), "%s %d: " fmt, \
+ __func__, __LINE__, ##args); \
+} while (0)
+
+#define LOG_INFO(priv, src, fmt, args...) \
+do { \
+ if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFO)) \
+ dev_info(priv2dev(priv), "%s %d: " fmt, \
+ __func__, __LINE__, ##args); \
+} while (0)
+
+#define LOG_INFOEX(priv, src, fmt, args...) \
+do { \
+ if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFOEX)) \
+ dev_dbg(priv2dev(priv), "%s %d: " fmt, \
+ __func__, __LINE__, ##args); \
+} while (0)
+
+#define LOG_HEXDUMP(src, ptr, len) \
+do { \
+ if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFOEX)) \
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, \
+ 16, 1, ptr, len, false); \
+} while (0)
+
+void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len);
+
+extern u8 iwmct_logdefs[];
+
+int iwmct_log_set_filter(u8 src, u8 logmask);
+int iwmct_log_set_fw_filter(u8 src, u8 logmask);
+
+ssize_t show_iwmct_log_level(struct device *d,
+ struct device_attribute *attr, char *buf);
+ssize_t store_iwmct_log_level(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+ssize_t show_iwmct_log_level_fw(struct device *d,
+ struct device_attribute *attr, char *buf);
+ssize_t store_iwmct_log_level_fw(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+
+#else
+
+#define LOG_CRITICAL(priv, src, fmt, args...)
+#define LOG_ERROR(priv, src, fmt, args...)
+#define LOG_WARNING(priv, src, fmt, args...)
+#define LOG_INFO(priv, src, fmt, args...)
+#define LOG_INFOEX(priv, src, fmt, args...)
+#define LOG_HEXDUMP(src, ptr, len)
+
+static inline void iwmct_log_top_message(struct iwmct_priv *priv,
+ u8 *buf, int len) {}
+static inline int iwmct_log_set_filter(u8 src, u8 logmask) { return 0; }
+static inline int iwmct_log_set_fw_filter(u8 src, u8 logmask) { return 0; }
+
+#endif /* CONFIG_IWMC3200TOP_DEBUG */
+
+int log_get_filter_str(char *buf, int size);
+int log_get_fw_filter_str(char *buf, int size);
+
+#endif /* __LOG_H__ */
diff --git a/drivers/misc/iwmc3200top/main.c b/drivers/misc/iwmc3200top/main.c
new file mode 100644
index 000000000000..6e4e49113ab4
--- /dev/null
+++ b/drivers/misc/iwmc3200top/main.c
@@ -0,0 +1,699 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/main.c
+ *
+ * Copyright (C) 2009 Intel 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.
+ *
+ * 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.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ * -
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio.h>
+
+#include "iwmc3200top.h"
+#include "log.h"
+#include "fw-msg.h"
+#include "debugfs.h"
+
+
+#define DRIVER_DESCRIPTION "Intel(R) IWMC 3200 Top Driver"
+#define DRIVER_COPYRIGHT "Copyright (c) 2008 Intel Corporation."
+
+#define IWMCT_VERSION "0.1.62"
+
+#ifdef REPOSITORY_LABEL
+#define RL REPOSITORY_LABEL
+#else
+#define RL local
+#endif
+
+#ifdef CONFIG_IWMC3200TOP_DEBUG
+#define VD "-d"
+#else
+#define VD
+#endif
+
+#define DRIVER_VERSION IWMCT_VERSION "-" __stringify(RL) VD
+
+MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRIVER_COPYRIGHT);
+
+
+/* FIXME: These can be found in sdio_ids.h in newer kernels */
+#ifndef SDIO_INTEL_VENDOR_ID
+#define SDIO_INTEL_VENDOR_ID 0x0089
+#endif
+#ifndef SDIO_DEVICE_ID_INTEL_IWMC3200TOP
+#define SDIO_DEVICE_ID_INTEL_IWMC3200TOP 0x1404
+#endif
+
+/*
+ * This workers main task is to wait for OP_OPR_ALIVE
+ * from TOP FW until ALIVE_MSG_TIMOUT timeout is elapsed.
+ * When OP_OPR_ALIVE received it will issue
+ * a call to "bus_rescan_devices".
+ */
+static void iwmct_rescan_worker(struct work_struct *ws)
+{
+ struct iwmct_priv *priv;
+ int ret;
+
+ priv = container_of(ws, struct iwmct_priv, bus_rescan_worker);
+
+ LOG_INFO(priv, FW_MSG, "Calling bus_rescan\n");
+
+ ret = bus_rescan_devices(priv->func->dev.bus);
+ if (ret < 0)
+ LOG_INFO(priv, FW_DOWNLOAD, "bus_rescan_devices FAILED!!!\n");
+}
+
+static void op_top_message(struct iwmct_priv *priv, struct top_msg *msg)
+{
+ switch (msg->hdr.opcode) {
+ case OP_OPR_ALIVE:
+ LOG_INFO(priv, FW_MSG, "Got ALIVE from device, wake rescan\n");
+ queue_work(priv->bus_rescan_wq, &priv->bus_rescan_worker);
+ break;
+ default:
+ LOG_INFO(priv, FW_MSG, "Received msg opcode 0x%X\n",
+ msg->hdr.opcode);
+ break;
+ }
+}
+
+
+static void handle_top_message(struct iwmct_priv *priv, u8 *buf, int len)
+{
+ struct top_msg *msg;
+
+ msg = (struct top_msg *)buf;
+
+ if (msg->hdr.type != COMM_TYPE_D2H) {
+ LOG_ERROR(priv, FW_MSG,
+ "Message from TOP with invalid message type 0x%X\n",
+ msg->hdr.type);
+ return;
+ }
+
+ if (len < sizeof(msg->hdr)) {
+ LOG_ERROR(priv, FW_MSG,
+ "Message from TOP is too short for message header "
+ "received %d bytes, expected at least %zd bytes\n",
+ len, sizeof(msg->hdr));
+ return;
+ }
+
+ if (len < le16_to_cpu(msg->hdr.length) + sizeof(msg->hdr)) {
+ LOG_ERROR(priv, FW_MSG,
+ "Message length (%d bytes) is shorter than "
+ "in header (%d bytes)\n",
+ len, le16_to_cpu(msg->hdr.length));
+ return;
+ }
+
+ switch (msg->hdr.category) {
+ case COMM_CATEGORY_OPERATIONAL:
+ op_top_message(priv, (struct top_msg *)buf);
+ break;
+
+ case COMM_CATEGORY_DEBUG:
+ case COMM_CATEGORY_TESTABILITY:
+ case COMM_CATEGORY_DIAGNOSTICS:
+ iwmct_log_top_message(priv, buf, len);
+ break;
+
+ default:
+ LOG_ERROR(priv, FW_MSG,
+ "Message from TOP with unknown category 0x%X\n",
+ msg->hdr.category);
+ break;
+ }
+}
+
+int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len)
+{
+ int ret;
+ u8 *buf;
+
+ LOG_INFOEX(priv, FW_MSG, "Sending hcmd:\n");
+
+ /* add padding to 256 for IWMC */
+ ((struct top_msg *)cmd)->hdr.flags |= CMD_FLAG_PADDING_256;
+
+ LOG_HEXDUMP(FW_MSG, cmd, len);
+
+ if (len > FW_HCMD_BLOCK_SIZE) {
+ LOG_ERROR(priv, FW_MSG, "size %d exceeded hcmd max size %d\n",
+ len, FW_HCMD_BLOCK_SIZE);
+ return -1;
+ }
+
+ buf = kzalloc(FW_HCMD_BLOCK_SIZE, GFP_KERNEL);
+ if (!buf) {
+ LOG_ERROR(priv, FW_MSG, "kzalloc error, buf size %d\n",
+ FW_HCMD_BLOCK_SIZE);
+ return -1;
+ }
+
+ memcpy(buf, cmd, len);
+
+ sdio_claim_host(priv->func);
+ ret = sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR, buf,
+ FW_HCMD_BLOCK_SIZE);
+ sdio_release_host(priv->func);
+
+ kfree(buf);
+ return ret;
+}
+
+int iwmct_tx(struct iwmct_priv *priv, unsigned int addr,
+ void *src, int count)
+{
+ int ret;
+
+ sdio_claim_host(priv->func);
+ ret = sdio_memcpy_toio(priv->func, addr, src, count);
+ sdio_release_host(priv->func);
+
+ return ret;
+}
+
+static void iwmct_irq_read_worker(struct work_struct *ws)
+{
+ struct iwmct_priv *priv;
+ struct iwmct_work_struct *read_req;
+ __le32 *buf = NULL;
+ int ret;
+ int iosize;
+ u32 barker;
+ bool is_barker;
+
+ priv = container_of(ws, struct iwmct_priv, isr_worker);
+
+ LOG_INFO(priv, IRQ, "enter iwmct_irq_read_worker %p\n", ws);
+
+ /* --------------------- Handshake with device -------------------- */
+ sdio_claim_host(priv->func);
+
+ /* all list manipulations have to be protected by
+ * sdio_claim_host/sdio_release_host */
+ if (list_empty(&priv->read_req_list)) {
+ LOG_ERROR(priv, IRQ, "read_req_list empty in read worker\n");
+ goto exit_release;
+ }
+
+ read_req = list_entry(priv->read_req_list.next,
+ struct iwmct_work_struct, list);
+
+ list_del(&read_req->list);
+ iosize = read_req->iosize;
+ kfree(read_req);
+
+ buf = kzalloc(iosize, GFP_KERNEL);
+ if (!buf) {
+ LOG_ERROR(priv, IRQ, "kzalloc error, buf size %d\n", iosize);
+ goto exit_release;
+ }
+
+ LOG_INFO(priv, IRQ, "iosize=%d, buf=%p, func=%d\n",
+ iosize, buf, priv->func->num);
+
+ /* read from device */
+ ret = sdio_memcpy_fromio(priv->func, buf, IWMC_SDIO_DATA_ADDR, iosize);
+ if (ret) {
+ LOG_ERROR(priv, IRQ, "error %d reading buffer\n", ret);
+ goto exit_release;
+ }
+
+ LOG_HEXDUMP(IRQ, (u8 *)buf, iosize);
+
+ barker = le32_to_cpu(buf[0]);
+
+ /* Verify whether it's a barker and if not - treat as regular Rx */
+ if (barker == IWMC_BARKER_ACK ||
+ (barker & BARKER_DNLOAD_BARKER_MSK) == IWMC_BARKER_REBOOT) {
+
+ /* Valid Barker is equal on first 4 dwords */
+ is_barker = (buf[1] == buf[0]) &&
+ (buf[2] == buf[0]) &&
+ (buf[3] == buf[0]);
+
+ if (!is_barker) {
+ LOG_WARNING(priv, IRQ,
+ "Potentially inconsistent barker "
+ "%08X_%08X_%08X_%08X\n",
+ le32_to_cpu(buf[0]), le32_to_cpu(buf[1]),
+ le32_to_cpu(buf[2]), le32_to_cpu(buf[3]));
+ }
+ } else {
+ is_barker = false;
+ }
+
+ /* Handle Top CommHub message */
+ if (!is_barker) {
+ sdio_release_host(priv->func);
+ handle_top_message(priv, (u8 *)buf, iosize);
+ goto exit;
+ } else if (barker == IWMC_BARKER_ACK) { /* Handle barkers */
+ if (atomic_read(&priv->dev_sync) == 0) {
+ LOG_ERROR(priv, IRQ,
+ "ACK barker arrived out-of-sync\n");
+ goto exit_release;
+ }
+
+ /* Continuing to FW download (after Sync is completed)*/
+ atomic_set(&priv->dev_sync, 0);
+ LOG_INFO(priv, IRQ, "ACK barker arrived "
+ "- starting FW download\n");
+ } else { /* REBOOT barker */
+ LOG_INFO(priv, IRQ, "Recieved reboot barker: %x\n", barker);
+ priv->barker = barker;
+
+ if (barker & BARKER_DNLOAD_SYNC_MSK) {
+ /* Send the same barker back */
+ ret = sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR,
+ buf, iosize);
+ if (ret) {
+ LOG_ERROR(priv, IRQ,
+ "error %d echoing barker\n", ret);
+ goto exit_release;
+ }
+ LOG_INFO(priv, IRQ, "Echoing barker to device\n");
+ atomic_set(&priv->dev_sync, 1);
+ goto exit_release;
+ }
+
+ /* Continuing to FW download (without Sync) */
+ LOG_INFO(priv, IRQ, "No sync requested "
+ "- starting FW download\n");
+ }
+
+ sdio_release_host(priv->func);
+
+
+ LOG_INFO(priv, IRQ, "barker download request 0x%x is:\n", priv->barker);
+ LOG_INFO(priv, IRQ, "******* Top FW %s requested ********\n",
+ (priv->barker & BARKER_DNLOAD_TOP_MSK) ? "was" : "not");
+ LOG_INFO(priv, IRQ, "******* GPS FW %s requested ********\n",
+ (priv->barker & BARKER_DNLOAD_GPS_MSK) ? "was" : "not");
+ LOG_INFO(priv, IRQ, "******* BT FW %s requested ********\n",
+ (priv->barker & BARKER_DNLOAD_BT_MSK) ? "was" : "not");
+
+ if (priv->dbg.fw_download)
+ iwmct_fw_load(priv);
+ else
+ LOG_ERROR(priv, IRQ, "FW download not allowed\n");
+
+ goto exit;
+
+exit_release:
+ sdio_release_host(priv->func);
+exit:
+ kfree(buf);
+ LOG_INFO(priv, IRQ, "exit iwmct_irq_read_worker\n");
+}
+
+static void iwmct_irq(struct sdio_func *func)
+{
+ struct iwmct_priv *priv;
+ int val, ret;
+ int iosize;
+ int addr = IWMC_SDIO_INTR_GET_SIZE_ADDR;
+ struct iwmct_work_struct *read_req;
+
+ priv = sdio_get_drvdata(func);
+
+ LOG_INFO(priv, IRQ, "enter iwmct_irq\n");
+
+ /* read the function's status register */
+ val = sdio_readb(func, IWMC_SDIO_INTR_STATUS_ADDR, &ret);
+
+ LOG_INFO(priv, IRQ, "iir value = %d, ret=%d\n", val, ret);
+
+ if (!val) {
+ LOG_ERROR(priv, IRQ, "iir = 0, exiting ISR\n");
+ goto exit_clear_intr;
+ }
+
+
+ /*
+ * read 2 bytes of the transaction size
+ * IMPORTANT: sdio transaction size has to be read before clearing
+ * sdio interrupt!!!
+ */
+ val = sdio_readb(priv->func, addr++, &ret);
+ iosize = val;
+ val = sdio_readb(priv->func, addr++, &ret);
+ iosize += val << 8;
+
+ LOG_INFO(priv, IRQ, "READ size %d\n", iosize);
+
+ if (iosize == 0) {
+ LOG_ERROR(priv, IRQ, "READ size %d, exiting ISR\n", iosize);
+ goto exit_clear_intr;
+ }
+
+ /* allocate a work structure to pass iosize to the worker */
+ read_req = kzalloc(sizeof(struct iwmct_work_struct), GFP_KERNEL);
+ if (!read_req) {
+ LOG_ERROR(priv, IRQ, "failed to allocate read_req, exit ISR\n");
+ goto exit_clear_intr;
+ }
+
+ INIT_LIST_HEAD(&read_req->list);
+ read_req->iosize = iosize;
+
+ list_add_tail(&priv->read_req_list, &read_req->list);
+
+ /* clear the function's interrupt request bit (write 1 to clear) */
+ sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret);
+
+ queue_work(priv->wq, &priv->isr_worker);
+
+ LOG_INFO(priv, IRQ, "exit iwmct_irq\n");
+
+ return;
+
+exit_clear_intr:
+ /* clear the function's interrupt request bit (write 1 to clear) */
+ sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret);
+}
+
+
+static int blocks;
+module_param(blocks, int, 0604);
+MODULE_PARM_DESC(blocks, "max_blocks_to_send");
+
+static int dump;
+module_param(dump, bool, 0604);
+MODULE_PARM_DESC(dump, "dump_hex_content");
+
+static int jump = 1;
+module_param(jump, bool, 0604);
+
+static int direct = 1;
+module_param(direct, bool, 0604);
+
+static int checksum = 1;
+module_param(checksum, bool, 0604);
+
+static int fw_download = 1;
+module_param(fw_download, bool, 0604);
+
+static int block_size = IWMC_SDIO_BLK_SIZE;
+module_param(block_size, int, 0404);
+
+static int download_trans_blks = IWMC_DEFAULT_TR_BLK;
+module_param(download_trans_blks, int, 0604);
+
+static int rubbish_barker;
+module_param(rubbish_barker, bool, 0604);
+
+#ifdef CONFIG_IWMC3200TOP_DEBUG
+static int log_level[LOG_SRC_MAX];
+static unsigned int log_level_argc;
+module_param_array(log_level, int, &log_level_argc, 0604);
+MODULE_PARM_DESC(log_level, "log_level");
+
+static int log_level_fw[FW_LOG_SRC_MAX];
+static unsigned int log_level_fw_argc;
+module_param_array(log_level_fw, int, &log_level_fw_argc, 0604);
+MODULE_PARM_DESC(log_level_fw, "log_level_fw");
+#endif
+
+void iwmct_dbg_init_params(struct iwmct_priv *priv)
+{
+#ifdef CONFIG_IWMC3200TOP_DEBUG
+ int i;
+
+ for (i = 0; i < log_level_argc; i++) {
+ dev_notice(&priv->func->dev, "log_level[%d]=0x%X\n",
+ i, log_level[i]);
+ iwmct_log_set_filter((log_level[i] >> 8) & 0xFF,
+ log_level[i] & 0xFF);
+ }
+ for (i = 0; i < log_level_fw_argc; i++) {
+ dev_notice(&priv->func->dev, "log_level_fw[%d]=0x%X\n",
+ i, log_level_fw[i]);
+ iwmct_log_set_fw_filter((log_level_fw[i] >> 8) & 0xFF,
+ log_level_fw[i] & 0xFF);
+ }
+#endif
+
+ priv->dbg.blocks = blocks;
+ LOG_INFO(priv, INIT, "blocks=%d\n", blocks);
+ priv->dbg.dump = (bool)dump;
+ LOG_INFO(priv, INIT, "dump=%d\n", dump);
+ priv->dbg.jump = (bool)jump;
+ LOG_INFO(priv, INIT, "jump=%d\n", jump);
+ priv->dbg.direct = (bool)direct;
+ LOG_INFO(priv, INIT, "direct=%d\n", direct);
+ priv->dbg.checksum = (bool)checksum;
+ LOG_INFO(priv, INIT, "checksum=%d\n", checksum);
+ priv->dbg.fw_download = (bool)fw_download;
+ LOG_INFO(priv, INIT, "fw_download=%d\n", fw_download);
+ priv->dbg.block_size = block_size;
+ LOG_INFO(priv, INIT, "block_size=%d\n", block_size);
+ priv->dbg.download_trans_blks = download_trans_blks;
+ LOG_INFO(priv, INIT, "download_trans_blks=%d\n", download_trans_blks);
+}
+
+/*****************************************************************************
+ *
+ * sysfs attributes
+ *
+ *****************************************************************************/
+static ssize_t show_iwmct_fw_version(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwmct_priv *priv = dev_get_drvdata(d);
+ return sprintf(buf, "%s\n", priv->dbg.label_fw);
+}
+static DEVICE_ATTR(cc_label_fw, S_IRUGO, show_iwmct_fw_version, NULL);
+
+#ifdef CONFIG_IWMC3200TOP_DEBUG
+static DEVICE_ATTR(log_level, S_IWUSR | S_IRUGO,
+ show_iwmct_log_level, store_iwmct_log_level);
+static DEVICE_ATTR(log_level_fw, S_IWUSR | S_IRUGO,
+ show_iwmct_log_level_fw, store_iwmct_log_level_fw);
+#endif
+
+static struct attribute *iwmct_sysfs_entries[] = {
+ &dev_attr_cc_label_fw.attr,
+#ifdef CONFIG_IWMC3200TOP_DEBUG
+ &dev_attr_log_level.attr,
+ &dev_attr_log_level_fw.attr,
+#endif
+ NULL
+};
+
+static struct attribute_group iwmct_attribute_group = {
+ .name = NULL, /* put in device directory */
+ .attrs = iwmct_sysfs_entries,
+};
+
+
+static int iwmct_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ struct iwmct_priv *priv;
+ int ret;
+ int val = 1;
+ int addr = IWMC_SDIO_INTR_ENABLE_ADDR;
+
+ dev_dbg(&func->dev, "enter iwmct_probe\n");
+
+ dev_dbg(&func->dev, "IRQ polling period id %u msecs, HZ is %d\n",
+ jiffies_to_msecs(2147483647), HZ);
+
+ priv = kzalloc(sizeof(struct iwmct_priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&func->dev, "kzalloc error\n");
+ return -ENOMEM;
+ }
+ priv->func = func;
+ sdio_set_drvdata(func, priv);
+
+
+ /* create drivers work queue */
+ priv->wq = create_workqueue(DRV_NAME "_wq");
+ priv->bus_rescan_wq = create_workqueue(DRV_NAME "_rescan_wq");
+ INIT_WORK(&priv->bus_rescan_worker, iwmct_rescan_worker);
+ INIT_WORK(&priv->isr_worker, iwmct_irq_read_worker);
+
+ init_waitqueue_head(&priv->wait_q);
+
+ sdio_claim_host(func);
+ /* FIXME: Remove after it is fixed in the Boot ROM upgrade */
+ func->enable_timeout = 10;
+
+ /* In our HW, setting the block size also wakes up the boot rom. */
+ ret = sdio_set_block_size(func, priv->dbg.block_size);
+ if (ret) {
+ LOG_ERROR(priv, INIT,
+ "sdio_set_block_size() failure: %d\n", ret);
+ goto error_sdio_enable;
+ }
+
+ ret = sdio_enable_func(func);
+ if (ret) {
+ LOG_ERROR(priv, INIT, "sdio_enable_func() failure: %d\n", ret);
+ goto error_sdio_enable;
+ }
+
+ /* init reset and dev_sync states */
+ atomic_set(&priv->reset, 0);
+ atomic_set(&priv->dev_sync, 0);
+
+ /* init read req queue */
+ INIT_LIST_HEAD(&priv->read_req_list);
+
+ /* process configurable parameters */
+ iwmct_dbg_init_params(priv);
+ ret = sysfs_create_group(&func->dev.kobj, &iwmct_attribute_group);
+ if (ret) {
+ LOG_ERROR(priv, INIT, "Failed to register attributes and "
+ "initialize module_params\n");
+ goto error_dev_attrs;
+ }
+
+ iwmct_dbgfs_register(priv, DRV_NAME);
+
+ if (!priv->dbg.direct && priv->dbg.download_trans_blks > 8) {
+ LOG_INFO(priv, INIT,
+ "Reducing transaction to 8 blocks = 2K (from %d)\n",
+ priv->dbg.download_trans_blks);
+ priv->dbg.download_trans_blks = 8;
+ }
+ priv->trans_len = priv->dbg.download_trans_blks * priv->dbg.block_size;
+ LOG_INFO(priv, INIT, "Transaction length = %d\n", priv->trans_len);
+
+ ret = sdio_claim_irq(func, iwmct_irq);
+ if (ret) {
+ LOG_ERROR(priv, INIT, "sdio_claim_irq() failure: %d\n", ret);
+ goto error_claim_irq;
+ }
+
+
+ /* Enable function's interrupt */
+ sdio_writeb(priv->func, val, addr, &ret);
+ if (ret) {
+ LOG_ERROR(priv, INIT, "Failure writing to "
+ "Interrupt Enable Register (%d): %d\n", addr, ret);
+ goto error_enable_int;
+ }
+
+ sdio_release_host(func);
+
+ LOG_INFO(priv, INIT, "exit iwmct_probe\n");
+
+ return ret;
+
+error_enable_int:
+ sdio_release_irq(func);
+error_claim_irq:
+ sdio_disable_func(func);
+error_dev_attrs:
+ iwmct_dbgfs_unregister(priv->dbgfs);
+ sysfs_remove_group(&func->dev.kobj, &iwmct_attribute_group);
+error_sdio_enable:
+ sdio_release_host(func);
+ return ret;
+}
+
+static void iwmct_remove(struct sdio_func *func)
+{
+ struct iwmct_work_struct *read_req;
+ struct iwmct_priv *priv = sdio_get_drvdata(func);
+
+ priv = sdio_get_drvdata(func);
+
+ LOG_INFO(priv, INIT, "enter\n");
+
+ sdio_claim_host(func);
+ sdio_release_irq(func);
+ sdio_release_host(func);
+
+ /* Safely destroy osc workqueue */
+ destroy_workqueue(priv->bus_rescan_wq);
+ destroy_workqueue(priv->wq);
+
+ sdio_claim_host(func);
+ sdio_disable_func(func);
+ sysfs_remove_group(&func->dev.kobj, &iwmct_attribute_group);
+ iwmct_dbgfs_unregister(priv->dbgfs);
+ sdio_release_host(func);
+
+ /* free read requests */
+ while (!list_empty(&priv->read_req_list)) {
+ read_req = list_entry(priv->read_req_list.next,
+ struct iwmct_work_struct, list);
+
+ list_del(&read_req->list);
+ kfree(read_req);
+ }
+
+ kfree(priv);
+}
+
+
+static const struct sdio_device_id iwmct_ids[] = {
+ { SDIO_DEVICE(SDIO_INTEL_VENDOR_ID, SDIO_DEVICE_ID_INTEL_IWMC3200TOP)},
+ { /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(sdio, iwmct_ids);
+
+static struct sdio_driver iwmct_driver = {
+ .probe = iwmct_probe,
+ .remove = iwmct_remove,
+ .name = DRV_NAME,
+ .id_table = iwmct_ids,
+};
+
+static int __init iwmct_init(void)
+{
+ int rc;
+
+ /* Default log filter settings */
+ iwmct_log_set_filter(LOG_SRC_ALL, LOG_SEV_FILTER_RUNTIME);
+ iwmct_log_set_filter(LOG_SRC_FW_MSG, LOG_SEV_FILTER_ALL);
+ iwmct_log_set_fw_filter(LOG_SRC_ALL, FW_LOG_SEV_FILTER_RUNTIME);
+
+ rc = sdio_register_driver(&iwmct_driver);
+
+ return rc;
+}
+
+static void __exit iwmct_exit(void)
+{
+ sdio_unregister_driver(&iwmct_driver);
+}
+
+module_init(iwmct_init);
+module_exit(iwmct_exit);
+
diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c
index c76677afda1b..b5bbe59f9c57 100644
--- a/drivers/misc/sgi-xp/xpc_uv.c
+++ b/drivers/misc/sgi-xp/xpc_uv.c
@@ -106,7 +106,8 @@ xpc_get_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq, int cpu, char *irq_name)
int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade);
#if defined CONFIG_X86_64
- mq->irq = uv_setup_irq(irq_name, cpu, mq->mmr_blade, mq->mmr_offset);
+ mq->irq = uv_setup_irq(irq_name, cpu, mq->mmr_blade, mq->mmr_offset,
+ UV_AFFINITY_CPU);
if (mq->irq < 0) {
dev_err(xpc_part, "uv_setup_irq() returned error=%d\n",
-mq->irq);
@@ -136,7 +137,7 @@ static void
xpc_release_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq)
{
#if defined CONFIG_X86_64
- uv_teardown_irq(mq->irq, mq->mmr_blade, mq->mmr_offset);
+ uv_teardown_irq(mq->irq);
#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
int mmr_pnode;
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index 36a8d53ad2a2..b8e7c5ae981e 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -231,7 +231,8 @@ static unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port)
return ret;
}
-static void sdio_uart_write_mctrl(struct sdio_uart_port *port, unsigned int mctrl)
+static void sdio_uart_write_mctrl(struct sdio_uart_port *port,
+ unsigned int mctrl)
{
unsigned char mcr = 0;
@@ -387,7 +388,8 @@ static void sdio_uart_stop_rx(struct sdio_uart_port *port)
sdio_out(port, UART_IER, port->ier);
}
-static void sdio_uart_receive_chars(struct sdio_uart_port *port, unsigned int *status)
+static void sdio_uart_receive_chars(struct sdio_uart_port *port,
+ unsigned int *status)
{
struct tty_struct *tty = port->tty;
unsigned int ch, flag;
@@ -399,7 +401,7 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port, unsigned int *s
port->icount.rx++;
if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
- UART_LSR_FE | UART_LSR_OE))) {
+ UART_LSR_FE | UART_LSR_OE))) {
/*
* For statistics only
*/
@@ -417,9 +419,9 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port, unsigned int *s
* Mask off conditions which should be ignored.
*/
*status &= port->read_status_mask;
- if (*status & UART_LSR_BI) {
+ if (*status & UART_LSR_BI)
flag = TTY_BREAK;
- } else if (*status & UART_LSR_PE)
+ else if (*status & UART_LSR_PE)
flag = TTY_PARITY;
else if (*status & UART_LSR_FE)
flag = TTY_FRAME;
@@ -574,7 +576,7 @@ static int sdio_uart_startup(struct sdio_uart_port *port)
*/
sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO);
sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO |
- UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
sdio_out(port, UART_FCR, 0);
/*
@@ -635,7 +637,7 @@ static void sdio_uart_shutdown(struct sdio_uart_port *port)
if (port->tty->termios->c_cflag & HUPCL)
sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
- /* Disable interrupts from this port */
+ /* Disable interrupts from this port */
sdio_release_irq(port->func);
port->ier = 0;
sdio_out(port, UART_IER, 0);
@@ -659,7 +661,7 @@ skip:
free_page((unsigned long)port->xmit.buf);
}
-static int sdio_uart_open (struct tty_struct *tty, struct file * filp)
+static int sdio_uart_open(struct tty_struct *tty, struct file *filp)
{
struct sdio_uart_port *port;
int ret;
@@ -846,7 +848,7 @@ static void sdio_uart_set_termios(struct tty_struct *tty, struct ktermios *old_t
struct sdio_uart_port *port = tty->driver_data;
unsigned int cflag = tty->termios->c_cflag;
-#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
if ((cflag ^ old_termios->c_cflag) == 0 &&
RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)
@@ -925,7 +927,7 @@ static int sdio_uart_tiocmset(struct tty_struct *tty, struct file *file,
struct sdio_uart_port *port = tty->driver_data;
int result;
- result =sdio_uart_claim_func(port);
+ result = sdio_uart_claim_func(port);
if(!result) {
sdio_uart_update_mctrl(port, set, clear);
sdio_uart_release_func(port);
@@ -946,31 +948,31 @@ static int sdio_uart_proc_show(struct seq_file *m, void *v)
seq_printf(m, "%d: uart:SDIO", i);
if(capable(CAP_SYS_ADMIN)) {
seq_printf(m, " tx:%d rx:%d",
- port->icount.tx, port->icount.rx);
+ port->icount.tx, port->icount.rx);
if (port->icount.frame)
seq_printf(m, " fe:%d",
- port->icount.frame);
+ port->icount.frame);
if (port->icount.parity)
seq_printf(m, " pe:%d",
- port->icount.parity);
+ port->icount.parity);
if (port->icount.brk)
seq_printf(m, " brk:%d",
- port->icount.brk);
+ port->icount.brk);
if (port->icount.overrun)
seq_printf(m, " oe:%d",
- port->icount.overrun);
+ port->icount.overrun);
if (port->icount.cts)
seq_printf(m, " cts:%d",
- port->icount.cts);
+ port->icount.cts);
if (port->icount.dsr)
seq_printf(m, " dsr:%d",
- port->icount.dsr);
+ port->icount.dsr);
if (port->icount.rng)
seq_printf(m, " rng:%d",
- port->icount.rng);
+ port->icount.rng);
if (port->icount.dcd)
seq_printf(m, " dcd:%d",
- port->icount.dcd);
+ port->icount.dcd);
}
sdio_uart_port_put(port);
seq_putc(m, '\n');
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 7dab2e5f4bc9..d98b0e2ffac8 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -891,12 +891,12 @@ static void mmc_power_up(struct mmc_host *host)
*/
mmc_delay(10);
- if (host->f_min > 400000) {
+ if (host->f_min > MMC_INIT_FREQ) {
pr_warning("%s: Minimum clock frequency too high for "
"identification mode\n", mmc_hostname(host));
host->ios.clock = host->f_min;
} else
- host->ios.clock = 400000;
+ host->ios.clock = MMC_INIT_FREQ;
host->ios.power_mode = MMC_POWER_ON;
mmc_set_ios(host);
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 67ae6abc4230..1c687830c959 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -15,6 +15,16 @@
#define MMC_CMD_RETRIES 3
+/* Spec says initialisation must happen at or below 400kHz.
+ * Some MMC cards fail to initialise at 400kHz (even as low as 200kHz) and
+ * Some host controllers (eg. tmio_mmc) cannot garantee to set the clock below
+ * 400kHz (it rounds to the closest clock freq available).
+ *
+ * 64 kHz seems like a good speed/reliability compromise.
+ */
+
+#define MMC_INIT_FREQ 64000
+
struct mmc_bus_ops {
int (*awake)(struct mmc_host *);
int (*sleep)(struct mmc_host *);
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 432ae8358c86..e04b751680d0 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -329,7 +329,7 @@ config MMC_SDRICOH_CS
config MMC_TMIO
tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support"
- depends on MFD_TMIO || MFD_ASIC3
+ depends on MFD_TMIO || MFD_ASIC3 || SUPERH
help
This provides support for the SD/MMC cell found in TC6393XB,
T7L66XB and also HTC ASIC3
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index e556d42cc45a..63924e0c7ea9 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -72,7 +72,6 @@
#include <asm/irq.h>
#include <asm/gpio.h>
-#include <asm/mach/mmc.h>
#include <mach/board.h>
#include <mach/cpu.h>
#include <mach/at91_mci.h>
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index d3f55615c099..c8649dfb2d0c 100644
--- a/drivers/mmc/host/au1xmmc.c
+++ b/drivers/mmc/host/au1xmmc.c
@@ -650,11 +650,11 @@ static int au1xmmc_prepare_data(struct au1xmmc_host *host,
flags = DDMA_FLAGS_IE;
if (host->flags & HOST_F_XMIT) {
- ret = au1xxx_dbdma_put_source_flags(channel,
- (void *)sg_virt(sg), len, flags);
+ ret = au1xxx_dbdma_put_source(channel,
+ sg_phys(sg), len, flags);
} else {
- ret = au1xxx_dbdma_put_dest_flags(channel,
- (void *)sg_virt(sg), len, flags);
+ ret = au1xxx_dbdma_put_dest(channel,
+ sg_phys(sg), len, flags);
}
if (!ret)
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index e7a331de5733..5d773b89af7c 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -30,12 +30,12 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <mach/board.h>
-#include <mach/mmc.h>
+#include <plat/board.h>
+#include <plat/mmc.h>
#include <mach/gpio.h>
-#include <mach/dma.h>
-#include <mach/mux.h>
-#include <mach/fpga.h>
+#include <plat/dma.h>
+#include <plat/mux.h>
+#include <plat/fpga.h>
#define OMAP_MMC_REG_CMD 0x00
#define OMAP_MMC_REG_ARGL 0x04
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 4487cc097911..c8f3e0245f1d 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -30,11 +30,11 @@
#include <linux/mmc/core.h>
#include <linux/io.h>
#include <linux/semaphore.h>
-#include <mach/dma.h>
+#include <plat/dma.h>
#include <mach/hardware.h>
-#include <mach/board.h>
-#include <mach/mmc.h>
-#include <mach/cpu.h>
+#include <plat/board.h>
+#include <plat/mmc.h>
+#include <plat/cpu.h>
/* OMAP HSMMC Host Controller Registers */
#define OMAP_HSMMC_SYSCONFIG 0x0010
diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
index 91991b460c45..f233867f54bb 100644
--- a/drivers/mmc/host/tmio_mmc.c
+++ b/drivers/mmc/host/tmio_mmc.c
@@ -43,10 +43,21 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock)
for (clock = host->mmc->f_min, clk = 0x80000080;
new_clock >= (clock<<1); clk >>= 1)
clock <<= 1;
+
+ /* Round the clock to the closest available. This is required
+ * for some fussy cards that dont like to initialise below 400kHz
+ */
+ if (new_clock - clock >= (clock << 1) - new_clock) {
+ clk >>= 1; clock <<= 1;
+ }
+
+ /* Clock enable */
clk |= 0x100;
}
- sd_config_write8(host, CNF_SD_CLK_MODE, clk >> 22);
+ if (host->set_no_clk_div)
+ host->set_no_clk_div(host->pdev, (clk>>22) & 1);
+
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff);
}
@@ -424,17 +435,18 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (ios->clock)
tmio_mmc_set_clock(host, ios->clock);
- /* Power sequence - OFF -> ON -> UP */
+ /* Power sequence - OFF -> UP -> ON */
switch (ios->power_mode) {
case MMC_POWER_OFF: /* power down SD bus */
- sd_config_write8(host, CNF_PWR_CTL_2, 0x00);
+ if (host->set_pwr)
+ host->set_pwr(host->pdev, 0);
tmio_mmc_clk_stop(host);
break;
- case MMC_POWER_ON: /* power up SD bus */
-
- sd_config_write8(host, CNF_PWR_CTL_2, 0x02);
+ case MMC_POWER_UP: /* power up SD bus */
+ if (host->set_pwr)
+ host->set_pwr(host->pdev, 1);
break;
- case MMC_POWER_UP: /* start bus clock */
+ case MMC_POWER_ON: /* enable bus clock */
tmio_mmc_clk_start(host);
break;
}
@@ -475,8 +487,8 @@ static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
ret = mmc_suspend_host(mmc, state);
/* Tell MFD core it can disable us now.*/
- if (!ret && cell->disable)
- cell->disable(dev);
+ if (!ret && cell->suspend)
+ cell->suspend(dev);
return ret;
}
@@ -485,21 +497,15 @@ static int tmio_mmc_resume(struct platform_device *dev)
{
struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data;
struct mmc_host *mmc = platform_get_drvdata(dev);
- struct tmio_mmc_host *host = mmc_priv(mmc);
int ret = 0;
/* Tell the MFD core we are ready to be enabled */
- if (cell->enable) {
- ret = cell->enable(dev);
+ if (cell->resume) {
+ ret = cell->resume(dev);
if (ret)
goto out;
}
- /* Enable the MMC/SD Control registers */
- sd_config_write16(host, CNF_CMD, SDCREN);
- sd_config_write32(host, CNF_CTL_BASE,
- (dev->resource[0].start >> host->bus_shift) & 0xfffe);
-
mmc_resume_host(mmc);
out:
@@ -514,17 +520,16 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
{
struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data;
struct tmio_mmc_data *pdata;
- struct resource *res_ctl, *res_cnf;
+ struct resource *res_ctl;
struct tmio_mmc_host *host;
struct mmc_host *mmc;
int ret = -EINVAL;
- if (dev->num_resources != 3)
+ if (dev->num_resources != 2)
goto out;
res_ctl = platform_get_resource(dev, IORESOURCE_MEM, 0);
- res_cnf = platform_get_resource(dev, IORESOURCE_MEM, 1);
- if (!res_ctl || !res_cnf)
+ if (!res_ctl)
goto out;
pdata = cell->driver_data;
@@ -539,8 +544,12 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
host = mmc_priv(mmc);
host->mmc = mmc;
+ host->pdev = dev;
platform_set_drvdata(dev, mmc);
+ host->set_pwr = pdata->set_pwr;
+ host->set_no_clk_div = pdata->set_no_clk_div;
+
/* SD control register space size is 0x200, 0x400 for bus_shift=1 */
host->bus_shift = resource_size(res_ctl) >> 10;
@@ -548,10 +557,6 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
if (!host->ctl)
goto host_free;
- host->cnf = ioremap(res_cnf->start, resource_size(res_cnf));
- if (!host->cnf)
- goto unmap_ctl;
-
mmc->ops = &tmio_mmc_ops;
mmc->caps = MMC_CAP_4_BIT_DATA;
mmc->f_max = pdata->hclk;
@@ -562,23 +567,9 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
if (cell->enable) {
ret = cell->enable(dev);
if (ret)
- goto unmap_cnf;
+ goto unmap_ctl;
}
- /* Enable the MMC/SD Control registers */
- sd_config_write16(host, CNF_CMD, SDCREN);
- sd_config_write32(host, CNF_CTL_BASE,
- (dev->resource[0].start >> host->bus_shift) & 0xfffe);
-
- /* Disable SD power during suspend */
- sd_config_write8(host, CNF_PWR_CTL_3, 0x01);
-
- /* The below is required but why? FIXME */
- sd_config_write8(host, CNF_STOP_CLK_CTL, 0x1f);
-
- /* Power down SD bus*/
- sd_config_write8(host, CNF_PWR_CTL_2, 0x00);
-
tmio_mmc_clk_stop(host);
reset(host);
@@ -586,14 +577,14 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
if (ret >= 0)
host->irq = ret;
else
- goto unmap_cnf;
+ goto unmap_ctl;
disable_mmc_irqs(host, TMIO_MASK_ALL);
ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED |
IRQF_TRIGGER_FALLING, "tmio-mmc", host);
if (ret)
- goto unmap_cnf;
+ goto unmap_ctl;
mmc_add_host(mmc);
@@ -605,8 +596,6 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
return 0;
-unmap_cnf:
- iounmap(host->cnf);
unmap_ctl:
iounmap(host->ctl);
host_free:
@@ -626,7 +615,6 @@ static int __devexit tmio_mmc_remove(struct platform_device *dev)
mmc_remove_host(mmc);
free_irq(host->irq, host);
iounmap(host->ctl);
- iounmap(host->cnf);
mmc_free_host(mmc);
}
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 9fa998594974..c676767cce8d 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -11,26 +11,6 @@
#include <linux/highmem.h>
-#define CNF_CMD 0x04
-#define CNF_CTL_BASE 0x10
-#define CNF_INT_PIN 0x3d
-#define CNF_STOP_CLK_CTL 0x40
-#define CNF_GCLK_CTL 0x41
-#define CNF_SD_CLK_MODE 0x42
-#define CNF_PIN_STATUS 0x44
-#define CNF_PWR_CTL_1 0x48
-#define CNF_PWR_CTL_2 0x49
-#define CNF_PWR_CTL_3 0x4a
-#define CNF_CARD_DETECT_MODE 0x4c
-#define CNF_SD_SLOT 0x50
-#define CNF_EXT_GCLK_CTL_1 0xf0
-#define CNF_EXT_GCLK_CTL_2 0xf1
-#define CNF_EXT_GCLK_CTL_3 0xf9
-#define CNF_SD_LED_EN_1 0xfa
-#define CNF_SD_LED_EN_2 0xfe
-
-#define SDCREN 0x2 /* Enable access to MMC CTL regs. (flag in COMMAND_REG)*/
-
#define CTL_SD_CMD 0x00
#define CTL_ARG_REG 0x04
#define CTL_STOP_INTERNAL_ACTION 0x08
@@ -110,7 +90,6 @@
struct tmio_mmc_host {
- void __iomem *cnf;
void __iomem *ctl;
unsigned long bus_shift;
struct mmc_command *cmd;
@@ -119,10 +98,16 @@ struct tmio_mmc_host {
struct mmc_host *mmc;
int irq;
+ /* Callbacks for clock / power control */
+ void (*set_pwr)(struct platform_device *host, int state);
+ void (*set_no_clk_div)(struct platform_device *host, int state);
+
/* pio related stuff */
struct scatterlist *sg_ptr;
unsigned int sg_len;
unsigned int sg_off;
+
+ struct platform_device *pdev;
};
#include <linux/io.h>
@@ -163,25 +148,6 @@ static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr,
writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift));
}
-static inline void sd_config_write8(struct tmio_mmc_host *host, int addr,
- u8 val)
-{
- writeb(val, host->cnf + (addr << host->bus_shift));
-}
-
-static inline void sd_config_write16(struct tmio_mmc_host *host, int addr,
- u16 val)
-{
- writew(val, host->cnf + (addr << host->bus_shift));
-}
-
-static inline void sd_config_write32(struct tmio_mmc_host *host, int addr,
- u32 val)
-{
- writew(val, host->cnf + (addr << host->bus_shift));
- writew(val >> 16, host->cnf + ((addr + 2) << host->bus_shift));
-}
-
#include <linux/scatterlist.h>
#include <linux/blkdev.h>
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index 9408099eec48..35c6a23b183b 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -1,5 +1,3 @@
-# drivers/mtd/chips/Kconfig
-
menu "RAM/ROM/Flash chip drivers"
depends on MTD!=n
@@ -242,4 +240,3 @@ config MTD_XIP
then say N.
endmenu
-
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index c222514bb70d..35081ce77fbd 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -1,5 +1,3 @@
-# drivers/mtd/maps/Kconfig
-
menu "Self-contained MTD device drivers"
depends on MTD!=n
@@ -308,4 +306,3 @@ config MTD_DOCPROBE_55AA
you have managed to wipe the first block.
endmenu
-
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 4c19269de91a..d17ee6bdbd6c 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -776,11 +776,12 @@ static int __devinit m25p_probe(struct spi_device *spi)
dev_set_drvdata(&spi->dev, flash);
/*
- * Atmel serial flash tend to power up
- * with the software protection bits set
+ * Atmel and SST serial flash tend to power
+ * up with the software protection bits set
*/
- if (info->jedec_id >> 16 == 0x1f) {
+ if (info->jedec_id >> 16 == 0x1f ||
+ info->jedec_id >> 16 == 0xbf) {
write_enable(flash);
write_sr(flash, 0);
}
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
index 93e3627be74c..19817404ce7d 100644
--- a/drivers/mtd/devices/mtd_dataflash.c
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -636,6 +636,7 @@ add_dataflash_otp(struct spi_device *spi, char *name,
struct mtd_info *device;
struct flash_platform_data *pdata = spi->dev.platform_data;
char *otp_tag = "";
+ int err = 0;
priv = kzalloc(sizeof *priv, GFP_KERNEL);
if (!priv)
@@ -693,13 +694,23 @@ add_dataflash_otp(struct spi_device *spi, char *name,
if (nr_parts > 0) {
priv->partitioned = 1;
- return add_mtd_partitions(device, parts, nr_parts);
+ err = add_mtd_partitions(device, parts, nr_parts);
+ goto out;
}
} else if (pdata && pdata->nr_parts)
dev_warn(&spi->dev, "ignoring %d default partitions on %s\n",
pdata->nr_parts, device->name);
- return add_mtd_device(device) == 1 ? -ENODEV : 0;
+ if (add_mtd_device(device) == 1)
+ err = -ENODEV;
+
+out:
+ if (!err)
+ return 0;
+
+ dev_set_drvdata(&spi->dev, NULL);
+ kfree(priv);
+ return err;
}
static inline int __devinit
@@ -932,8 +943,10 @@ static int __devexit dataflash_remove(struct spi_device *spi)
status = del_mtd_partitions(&flash->mtd);
else
status = del_mtd_device(&flash->mtd);
- if (status == 0)
+ if (status == 0) {
+ dev_set_drvdata(&spi->dev, NULL);
kfree(flash);
+ }
return status;
}
diff --git a/drivers/mtd/lpddr/Kconfig b/drivers/mtd/lpddr/Kconfig
index 5a401d8047ab..265f969817e3 100644
--- a/drivers/mtd/lpddr/Kconfig
+++ b/drivers/mtd/lpddr/Kconfig
@@ -1,5 +1,3 @@
-# drivers/mtd/chips/Kconfig
-
menu "LPDDR flash memory drivers"
depends on MTD!=n
@@ -20,4 +18,3 @@ config MTD_QINFO_PROBE
families of devices. This serves similar purpose of CFI on legacy
Flash products
endmenu
-
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 841e085ab74a..0aa9efae1eb1 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -1,5 +1,3 @@
-# drivers/mtd/maps/Kconfig
-
menu "Mapping drivers for chip access"
depends on MTD!=n
@@ -361,12 +359,6 @@ config MTD_SA1100
the SA1100 and SA1110, including the Assabet and the Compaq iPAQ.
If you have such a board, say 'Y'.
-config MTD_IPAQ
- tristate "CFI Flash device mapped on Compaq/HP iPAQ"
- depends on IPAQ_HANDHELD && MTD_CFI
- help
- This provides a driver for the on-board flash of the iPAQ.
-
config MTD_DC21285
tristate "CFI Flash device mapped on DC21285 Footbridge"
depends on MTD_CFI && ARCH_FOOTBRIDGE && MTD_COMPLEX_MAPPINGS
@@ -486,6 +478,7 @@ config MTD_BFIN_ASYNC
config MTD_GPIO_ADDR
tristate "GPIO-assisted Flash Chip Support"
+ depends on GENERIC_GPIO || GPIOLIB
depends on MTD_COMPLEX_MAPPINGS
select MTD_PARTITIONS
help
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index 1d5cf8636723..34f3cddb384b 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -29,7 +29,6 @@ obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o
obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o
-obj-$(CONFIG_MTD_IPAQ) += ipaq-flash.o
obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o
obj-$(CONFIG_MTD_SC520CDP) += sc520cdp.o
obj-$(CONFIG_MTD_NETSC520) += netsc520.o
diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c
index 44ef9a49a860..1ad5caf9fe69 100644
--- a/drivers/mtd/maps/gpio-addr-flash.c
+++ b/drivers/mtd/maps/gpio-addr-flash.c
@@ -13,7 +13,9 @@
* Licensed under the GPL-2 or later.
*/
+#include <linux/gpio.h>
#include <linux/init.h>
+#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
@@ -23,9 +25,6 @@
#include <linux/platform_device.h>
#include <linux/types.h>
-#include <asm/gpio.h>
-#include <asm/io.h>
-
#define pr_devinit(fmt, args...) ({ static const __devinitconst char __fmt[] = fmt; printk(__fmt, ## args); })
#define DRIVER_NAME "gpio-addr-flash"
diff --git a/drivers/mtd/maps/ipaq-flash.c b/drivers/mtd/maps/ipaq-flash.c
deleted file mode 100644
index 76708e796b70..000000000000
--- a/drivers/mtd/maps/ipaq-flash.c
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * Flash memory access on iPAQ Handhelds (either SA1100 or PXA250 based)
- *
- * (C) 2000 Nicolas Pitre <nico@fluxnic.net>
- * (C) 2002 Hewlett-Packard Company <jamey.hicks@hp.com>
- * (C) 2003 Christian Pellegrin <chri@ascensit.com>, <chri@infis.univ.ts.it>: concatenation of multiple flashes
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <asm/page.h>
-#include <asm/mach-types.h>
-#include <asm/system.h>
-#include <asm/errno.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-#ifdef CONFIG_MTD_CONCAT
-#include <linux/mtd/concat.h>
-#endif
-
-#include <mach/hardware.h>
-#include <mach/h3600.h>
-#include <asm/io.h>
-
-
-#ifndef CONFIG_IPAQ_HANDHELD
-#error This is for iPAQ Handhelds only
-#endif
-#ifdef CONFIG_SA1100_JORNADA56X
-
-static void jornada56x_set_vpp(struct map_info *map, int vpp)
-{
- if (vpp)
- GPSR = GPIO_GPIO26;
- else
- GPCR = GPIO_GPIO26;
- GPDR |= GPIO_GPIO26;
-}
-
-#endif
-
-#ifdef CONFIG_SA1100_JORNADA720
-
-static void jornada720_set_vpp(struct map_info *map, int vpp)
-{
- if (vpp)
- PPSR |= 0x80;
- else
- PPSR &= ~0x80;
- PPDR |= 0x80;
-}
-
-#endif
-
-#define MAX_IPAQ_CS 2 /* Number of CS we are going to test */
-
-#define IPAQ_MAP_INIT(X) \
- { \
- name: "IPAQ flash " X, \
- }
-
-
-static struct map_info ipaq_map[MAX_IPAQ_CS] = {
- IPAQ_MAP_INIT("bank 1"),
- IPAQ_MAP_INIT("bank 2")
-};
-
-static struct mtd_info *my_sub_mtd[MAX_IPAQ_CS] = {
- NULL,
- NULL
-};
-
-/*
- * Here are partition information for all known IPAQ-based devices.
- * See include/linux/mtd/partitions.h for definition of the mtd_partition
- * structure.
- *
- * The *_max_flash_size is the maximum possible mapped flash size which
- * is not necessarily the actual flash size. It must be no more than
- * the value specified in the "struct map_desc *_io_desc" mapping
- * definition for the corresponding machine.
- *
- * Please keep these in alphabetical order, and formatted as per existing
- * entries. Thanks.
- */
-
-#ifdef CONFIG_IPAQ_HANDHELD
-static unsigned long h3xxx_max_flash_size = 0x04000000;
-static struct mtd_partition h3xxx_partitions[] = {
- {
- name: "H3XXX boot firmware",
-#ifndef CONFIG_LAB
- size: 0x00040000,
-#else
- size: 0x00080000,
-#endif
- offset: 0,
-#ifndef CONFIG_LAB
- mask_flags: MTD_WRITEABLE, /* force read-only */
-#endif
- },
- {
- name: "H3XXX root jffs2",
-#ifndef CONFIG_LAB
- size: 0x2000000 - 2*0x40000, /* Warning, this is fixed later */
- offset: 0x00040000,
-#else
- size: 0x2000000 - 0x40000 - 0x80000, /* Warning, this is fixed later */
- offset: 0x00080000,
-#endif
- },
- {
- name: "asset",
- size: 0x40000,
- offset: 0x2000000 - 0x40000, /* Warning, this is fixed later */
- mask_flags: MTD_WRITEABLE, /* force read-only */
- }
-};
-
-#ifndef CONFIG_MTD_CONCAT
-static struct mtd_partition h3xxx_partitions_bank2[] = {
- /* this is used only on 2 CS machines when concat is not present */
- {
- name: "second H3XXX root jffs2",
- size: 0x1000000 - 0x40000, /* Warning, this is fixed later */
- offset: 0x00000000,
- },
- {
- name: "second asset",
- size: 0x40000,
- offset: 0x1000000 - 0x40000, /* Warning, this is fixed later */
- mask_flags: MTD_WRITEABLE, /* force read-only */
- }
-};
-#endif
-
-static DEFINE_SPINLOCK(ipaq_vpp_lock);
-
-static void h3xxx_set_vpp(struct map_info *map, int vpp)
-{
- static int nest = 0;
-
- spin_lock(&ipaq_vpp_lock);
- if (vpp)
- nest++;
- else
- nest--;
- if (nest)
- assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, 1);
- else
- assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, 0);
- spin_unlock(&ipaq_vpp_lock);
-}
-
-#endif
-
-#if defined(CONFIG_SA1100_JORNADA56X) || defined(CONFIG_SA1100_JORNADA720)
-static unsigned long jornada_max_flash_size = 0x02000000;
-static struct mtd_partition jornada_partitions[] = {
- {
- name: "Jornada boot firmware",
- size: 0x00040000,
- offset: 0,
- mask_flags: MTD_WRITEABLE, /* force read-only */
- }, {
- name: "Jornada root jffs2",
- size: MTDPART_SIZ_FULL,
- offset: 0x00040000,
- }
-};
-#endif
-
-
-static struct mtd_partition *parsed_parts;
-static struct mtd_info *mymtd;
-
-static unsigned long cs_phys[] = {
-#ifdef CONFIG_ARCH_SA1100
- SA1100_CS0_PHYS,
- SA1100_CS1_PHYS,
- SA1100_CS2_PHYS,
- SA1100_CS3_PHYS,
- SA1100_CS4_PHYS,
- SA1100_CS5_PHYS,
-#else
- PXA_CS0_PHYS,
- PXA_CS1_PHYS,
- PXA_CS2_PHYS,
- PXA_CS3_PHYS,
- PXA_CS4_PHYS,
- PXA_CS5_PHYS,
-#endif
-};
-
-static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
-
-static int __init h1900_special_case(void);
-
-static int __init ipaq_mtd_init(void)
-{
- struct mtd_partition *parts = NULL;
- int nb_parts = 0;
- int parsed_nr_parts = 0;
- const char *part_type;
- int i; /* used when we have >1 flash chips */
- unsigned long tot_flashsize = 0; /* used when we have >1 flash chips */
-
- /* Default flash bankwidth */
- // ipaq_map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
-
- if (machine_is_h1900())
- {
- /* For our intents, the h1900 is not a real iPAQ, so we special-case it. */
- return h1900_special_case();
- }
-
- if (machine_is_h3100() || machine_is_h1900())
- for(i=0; i<MAX_IPAQ_CS; i++)
- ipaq_map[i].bankwidth = 2;
- else
- for(i=0; i<MAX_IPAQ_CS; i++)
- ipaq_map[i].bankwidth = 4;
-
- /*
- * Static partition definition selection
- */
- part_type = "static";
-
- simple_map_init(&ipaq_map[0]);
- simple_map_init(&ipaq_map[1]);
-
-#ifdef CONFIG_IPAQ_HANDHELD
- if (machine_is_ipaq()) {
- parts = h3xxx_partitions;
- nb_parts = ARRAY_SIZE(h3xxx_partitions);
- for(i=0; i<MAX_IPAQ_CS; i++) {
- ipaq_map[i].size = h3xxx_max_flash_size;
- ipaq_map[i].set_vpp = h3xxx_set_vpp;
- ipaq_map[i].phys = cs_phys[i];
- ipaq_map[i].virt = ioremap(cs_phys[i], 0x04000000);
- if (machine_is_h3100 () || machine_is_h1900())
- ipaq_map[i].bankwidth = 2;
- }
- if (machine_is_h3600()) {
- /* No asset partition here */
- h3xxx_partitions[1].size += 0x40000;
- nb_parts--;
- }
- }
-#endif
-#ifdef CONFIG_ARCH_H5400
- if (machine_is_h5400()) {
- ipaq_map[0].size = 0x02000000;
- ipaq_map[1].size = 0x02000000;
- ipaq_map[1].phys = 0x02000000;
- ipaq_map[1].virt = ipaq_map[0].virt + 0x02000000;
- }
-#endif
-#ifdef CONFIG_ARCH_H1900
- if (machine_is_h1900()) {
- ipaq_map[0].size = 0x00400000;
- ipaq_map[1].size = 0x02000000;
- ipaq_map[1].phys = 0x00080000;
- ipaq_map[1].virt = ipaq_map[0].virt + 0x00080000;
- }
-#endif
-
-#ifdef CONFIG_SA1100_JORNADA56X
- if (machine_is_jornada56x()) {
- parts = jornada_partitions;
- nb_parts = ARRAY_SIZE(jornada_partitions);
- ipaq_map[0].size = jornada_max_flash_size;
- ipaq_map[0].set_vpp = jornada56x_set_vpp;
- ipaq_map[0].virt = (__u32)ioremap(0x0, 0x04000000);
- }
-#endif
-#ifdef CONFIG_SA1100_JORNADA720
- if (machine_is_jornada720()) {
- parts = jornada_partitions;
- nb_parts = ARRAY_SIZE(jornada_partitions);
- ipaq_map[0].size = jornada_max_flash_size;
- ipaq_map[0].set_vpp = jornada720_set_vpp;
- }
-#endif
-
-
- if (machine_is_ipaq()) { /* for iPAQs only */
- for(i=0; i<MAX_IPAQ_CS; i++) {
- printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with CFI.\n", ipaq_map[i].bankwidth*8, ipaq_map[i].virt);
- my_sub_mtd[i] = do_map_probe("cfi_probe", &ipaq_map[i]);
- if (!my_sub_mtd[i]) {
- printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with JEDEC.\n", ipaq_map[i].bankwidth*8, ipaq_map[i].virt);
- my_sub_mtd[i] = do_map_probe("jedec_probe", &ipaq_map[i]);
- }
- if (!my_sub_mtd[i]) {
- printk(KERN_NOTICE "iPAQ flash: failed to find flash.\n");
- if (i)
- break;
- else
- return -ENXIO;
- } else
- printk(KERN_NOTICE "iPAQ flash: found %d bytes\n", my_sub_mtd[i]->size);
-
- /* do we really need this debugging? --joshua 20030703 */
- // printk("my_sub_mtd[%d]=%p\n", i, my_sub_mtd[i]);
- my_sub_mtd[i]->owner = THIS_MODULE;
- tot_flashsize += my_sub_mtd[i]->size;
- }
-#ifdef CONFIG_MTD_CONCAT
- /* fix the asset location */
-# ifdef CONFIG_LAB
- h3xxx_partitions[1].size = tot_flashsize - 0x40000 - 0x80000 /* extra big boot block */;
-# else
- h3xxx_partitions[1].size = tot_flashsize - 2 * 0x40000;
-# endif
- h3xxx_partitions[2].offset = tot_flashsize - 0x40000;
- /* and concat the devices */
- mymtd = mtd_concat_create(&my_sub_mtd[0], i,
- "ipaq");
- if (!mymtd) {
- printk("Cannot create iPAQ concat device\n");
- return -ENXIO;
- }
-#else
- mymtd = my_sub_mtd[0];
-
- /*
- *In the very near future, command line partition parsing
- * will use the device name as 'mtd-id' instead of a value
- * passed to the parse_cmdline_partitions() routine. Since
- * the bootldr says 'ipaq', make sure it continues to work.
- */
- mymtd->name = "ipaq";
-
- if ((machine_is_h3600())) {
-# ifdef CONFIG_LAB
- h3xxx_partitions[1].size = my_sub_mtd[0]->size - 0x80000;
-# else
- h3xxx_partitions[1].size = my_sub_mtd[0]->size - 0x40000;
-# endif
- nb_parts = 2;
- } else {
-# ifdef CONFIG_LAB
- h3xxx_partitions[1].size = my_sub_mtd[0]->size - 0x40000 - 0x80000; /* extra big boot block */
-# else
- h3xxx_partitions[1].size = my_sub_mtd[0]->size - 2*0x40000;
-# endif
- h3xxx_partitions[2].offset = my_sub_mtd[0]->size - 0x40000;
- }
-
- if (my_sub_mtd[1]) {
-# ifdef CONFIG_LAB
- h3xxx_partitions_bank2[0].size = my_sub_mtd[1]->size - 0x80000;
-# else
- h3xxx_partitions_bank2[0].size = my_sub_mtd[1]->size - 0x40000;
-# endif
- h3xxx_partitions_bank2[1].offset = my_sub_mtd[1]->size - 0x40000;
- }
-#endif
- }
- else {
- /*
- * Now let's probe for the actual flash. Do it here since
- * specific machine settings might have been set above.
- */
- printk(KERN_NOTICE "IPAQ flash: probing %d-bit flash bus, window=%lx\n", ipaq_map[0].bankwidth*8, ipaq_map[0].virt);
- mymtd = do_map_probe("cfi_probe", &ipaq_map[0]);
- if (!mymtd)
- return -ENXIO;
- mymtd->owner = THIS_MODULE;
- }
-
-
- /*
- * Dynamic partition selection stuff (might override the static ones)
- */
-
- i = parse_mtd_partitions(mymtd, part_probes, &parsed_parts, 0);
-
- if (i > 0) {
- nb_parts = parsed_nr_parts = i;
- parts = parsed_parts;
- part_type = "dynamic";
- }
-
- if (!parts) {
- printk(KERN_NOTICE "IPAQ flash: no partition info available, registering whole flash at once\n");
- add_mtd_device(mymtd);
-#ifndef CONFIG_MTD_CONCAT
- if (my_sub_mtd[1])
- add_mtd_device(my_sub_mtd[1]);
-#endif
- } else {
- printk(KERN_NOTICE "Using %s partition definition\n", part_type);
- add_mtd_partitions(mymtd, parts, nb_parts);
-#ifndef CONFIG_MTD_CONCAT
- if (my_sub_mtd[1])
- add_mtd_partitions(my_sub_mtd[1], h3xxx_partitions_bank2, ARRAY_SIZE(h3xxx_partitions_bank2));
-#endif
- }
-
- return 0;
-}
-
-static void __exit ipaq_mtd_cleanup(void)
-{
- int i;
-
- if (mymtd) {
- del_mtd_partitions(mymtd);
-#ifndef CONFIG_MTD_CONCAT
- if (my_sub_mtd[1])
- del_mtd_partitions(my_sub_mtd[1]);
-#endif
- map_destroy(mymtd);
-#ifdef CONFIG_MTD_CONCAT
- for(i=0; i<MAX_IPAQ_CS; i++)
-#else
- for(i=1; i<MAX_IPAQ_CS; i++)
-#endif
- {
- if (my_sub_mtd[i])
- map_destroy(my_sub_mtd[i]);
- }
- kfree(parsed_parts);
- }
-}
-
-static int __init h1900_special_case(void)
-{
- /* The iPAQ h1900 is a special case - it has weird ROM. */
- simple_map_init(&ipaq_map[0]);
- ipaq_map[0].size = 0x80000;
- ipaq_map[0].set_vpp = h3xxx_set_vpp;
- ipaq_map[0].phys = 0x0;
- ipaq_map[0].virt = ioremap(0x0, 0x04000000);
- ipaq_map[0].bankwidth = 2;
-
- printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with JEDEC.\n", ipaq_map[0].bankwidth*8, ipaq_map[0].virt);
- mymtd = do_map_probe("jedec_probe", &ipaq_map[0]);
- if (!mymtd)
- return -ENODEV;
- add_mtd_device(mymtd);
- printk(KERN_NOTICE "iPAQ flash: registered h1910 flash\n");
-
- return 0;
-}
-
-module_init(ipaq_mtd_init);
-module_exit(ipaq_mtd_cleanup);
-
-MODULE_AUTHOR("Jamey Hicks");
-MODULE_DESCRIPTION("IPAQ CFI map driver");
-MODULE_LICENSE("MIT");
diff --git a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c
index a24478102b11..ead0b2fab670 100644
--- a/drivers/mtd/maps/omap_nor.c
+++ b/drivers/mtd/maps/omap_nor.c
@@ -45,7 +45,7 @@
#include <asm/io.h>
#include <mach/hardware.h>
#include <asm/mach/flash.h>
-#include <mach/tc.h>
+#include <plat/tc.h>
#ifdef CONFIG_MTD_PARTITIONS
static const char *part_probes[] = { /* "RedBoot", */ "cmdlinepart", NULL };
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
index d600c2deff73..52c07f21be01 100644
--- a/drivers/mtd/maps/pcmciamtd.c
+++ b/drivers/mtd/maps/pcmciamtd.c
@@ -354,101 +354,108 @@ static void pcmciamtd_release(struct pcmcia_device *link)
}
-static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *link, int *new_name)
+#ifdef CONFIG_MTD_DEBUG
+static int pcmciamtd_cistpl_format(struct pcmcia_device *p_dev,
+ tuple_t *tuple,
+ void *priv_data)
{
- int rc;
- tuple_t tuple;
cisparse_t parse;
- u_char buf[64];
-
- tuple.Attributes = 0;
- tuple.TupleData = (cisdata_t *)buf;
- tuple.TupleDataMax = sizeof(buf);
- tuple.TupleOffset = 0;
- tuple.DesiredTuple = RETURN_FIRST_TUPLE;
-
- rc = pcmcia_get_first_tuple(link, &tuple);
- while (rc == 0) {
- rc = pcmcia_get_tuple_data(link, &tuple);
- if (rc != 0) {
- cs_error(link, GetTupleData, rc);
- break;
- }
- rc = pcmcia_parse_tuple(&tuple, &parse);
- if (rc != 0) {
- cs_error(link, ParseTuple, rc);
- break;
- }
- switch(tuple.TupleCode) {
- case CISTPL_FORMAT: {
- cistpl_format_t *t = &parse.format;
- (void)t; /* Shut up, gcc */
- DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u",
- t->type, t->edc, t->offset, t->length);
- break;
+ if (!pcmcia_parse_tuple(tuple, &parse)) {
+ cistpl_format_t *t = &parse.format;
+ (void)t; /* Shut up, gcc */
+ DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u",
+ t->type, t->edc, t->offset, t->length);
+ }
+ return -ENOSPC;
+}
- }
+static int pcmciamtd_cistpl_jedec(struct pcmcia_device *p_dev,
+ tuple_t *tuple,
+ void *priv_data)
+{
+ cisparse_t parse;
+ int i;
- case CISTPL_DEVICE: {
- cistpl_device_t *t = &parse.device;
- int i;
- DEBUG(2, "Common memory:");
- dev->pcmcia_map.size = t->dev[0].size;
- for(i = 0; i < t->ndev; i++) {
- DEBUG(2, "Region %d, type = %u", i, t->dev[i].type);
- DEBUG(2, "Region %d, wp = %u", i, t->dev[i].wp);
- DEBUG(2, "Region %d, speed = %u ns", i, t->dev[i].speed);
- DEBUG(2, "Region %d, size = %u bytes", i, t->dev[i].size);
- }
- break;
- }
+ if (!pcmcia_parse_tuple(tuple, &parse)) {
+ cistpl_jedec_t *t = &parse.jedec;
+ for (i = 0; i < t->nid; i++)
+ DEBUG(2, "JEDEC: 0x%02x 0x%02x", t->id[i].mfr, t->id[i].info);
+ }
+ return -ENOSPC;
+}
+#endif
- case CISTPL_VERS_1: {
- cistpl_vers_1_t *t = &parse.version_1;
- int i;
- if(t->ns) {
- dev->mtd_name[0] = '\0';
- for(i = 0; i < t->ns; i++) {
- if(i)
- strcat(dev->mtd_name, " ");
- strcat(dev->mtd_name, t->str+t->ofs[i]);
- }
- }
- DEBUG(2, "Found name: %s", dev->mtd_name);
- break;
- }
+static int pcmciamtd_cistpl_device(struct pcmcia_device *p_dev,
+ tuple_t *tuple,
+ void *priv_data)
+{
+ struct pcmciamtd_dev *dev = priv_data;
+ cisparse_t parse;
+ cistpl_device_t *t = &parse.device;
+
+ if (pcmcia_parse_tuple(tuple, &parse))
+ return -EINVAL;
+
+ DEBUG(2, "Common memory:");
+ dev->pcmcia_map.size = t->dev[0].size;
+ /* from here on: DEBUG only */
+ for (i = 0; i < t->ndev; i++) {
+ DEBUG(2, "Region %d, type = %u", i, t->dev[i].type);
+ DEBUG(2, "Region %d, wp = %u", i, t->dev[i].wp);
+ DEBUG(2, "Region %d, speed = %u ns", i, t->dev[i].speed);
+ DEBUG(2, "Region %d, size = %u bytes", i, t->dev[i].size);
+ }
+ return 0;
+}
- case CISTPL_JEDEC_C: {
- cistpl_jedec_t *t = &parse.jedec;
- int i;
- for(i = 0; i < t->nid; i++) {
- DEBUG(2, "JEDEC: 0x%02x 0x%02x", t->id[i].mfr, t->id[i].info);
- }
- break;
- }
+static int pcmciamtd_cistpl_geo(struct pcmcia_device *p_dev,
+ tuple_t *tuple,
+ void *priv_data)
+{
+ struct pcmciamtd_dev *dev = priv_data;
+ cisparse_t parse;
+ cistpl_device_geo_t *t = &parse.device_geo;
+
+ if (pcmcia_parse_tuple(tuple, &parse))
+ return -EINVAL;
+
+ dev->pcmcia_map.bankwidth = t->geo[0].buswidth;
+ /* from here on: DEBUG only */
+ for (i = 0; i < t->ngeo; i++) {
+ DEBUG(2, "region: %d bankwidth = %u", i, t->geo[i].buswidth);
+ DEBUG(2, "region: %d erase_block = %u", i, t->geo[i].erase_block);
+ DEBUG(2, "region: %d read_block = %u", i, t->geo[i].read_block);
+ DEBUG(2, "region: %d write_block = %u", i, t->geo[i].write_block);
+ DEBUG(2, "region: %d partition = %u", i, t->geo[i].partition);
+ DEBUG(2, "region: %d interleave = %u", i, t->geo[i].interleave);
+ }
+ return 0;
+}
- case CISTPL_DEVICE_GEO: {
- cistpl_device_geo_t *t = &parse.device_geo;
- int i;
- dev->pcmcia_map.bankwidth = t->geo[0].buswidth;
- for(i = 0; i < t->ngeo; i++) {
- DEBUG(2, "region: %d bankwidth = %u", i, t->geo[i].buswidth);
- DEBUG(2, "region: %d erase_block = %u", i, t->geo[i].erase_block);
- DEBUG(2, "region: %d read_block = %u", i, t->geo[i].read_block);
- DEBUG(2, "region: %d write_block = %u", i, t->geo[i].write_block);
- DEBUG(2, "region: %d partition = %u", i, t->geo[i].partition);
- DEBUG(2, "region: %d interleave = %u", i, t->geo[i].interleave);
- }
- break;
- }
- default:
- DEBUG(2, "Unknown tuple code %d", tuple.TupleCode);
- }
+static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *link, int *new_name)
+{
+ int i;
- rc = pcmcia_get_next_tuple(link, &tuple);
+ if (p_dev->prod_id[0]) {
+ dev->mtd_name[0] = '\0';
+ for (i = 0; i < 4; i++) {
+ if (i)
+ strcat(dev->mtd_name, " ");
+ if (p_dev->prod_id[i])
+ strcat(dev->mtd_name, p_dev->prod_id[i]);
+ }
+ DEBUG(2, "Found name: %s", dev->mtd_name);
}
+
+#ifdef CONFIG_MTD_DEBUG
+ pcmcia_loop_tuple(p_dev, CISTPL_FORMAT, pcmciamtd_cistpl_format, NULL);
+ pcmcia_loop_tuple(p_dev, CISTPL_JEDEC_C, pcmciamtd_cistpl_jedec, NULL);
+#endif
+ pcmcia_loop_tuple(p_dev, CISTPL_DEVICE, pcmciamtd_cistpl_device, dev);
+ pcmcia_loop_tuple(p_dev, CISTPL_DEVICE_GEO, pcmciamtd_cistpl_geo, dev);
+
if(!dev->pcmcia_map.size)
dev->pcmcia_map.size = MAX_PCMCIA_ADDR;
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
index 380648e9051a..3f13a9673e7f 100644
--- a/drivers/mtd/maps/physmap.c
+++ b/drivers/mtd/maps/physmap.c
@@ -48,23 +48,22 @@ static int physmap_flash_remove(struct platform_device *dev)
if (info->cmtd) {
#ifdef CONFIG_MTD_PARTITIONS
- if (info->nr_parts || physmap_data->nr_parts)
+ if (info->nr_parts || physmap_data->nr_parts) {
del_mtd_partitions(info->cmtd);
- else
+
+ if (info->nr_parts)
+ kfree(info->parts);
+ } else {
del_mtd_device(info->cmtd);
+ }
#else
del_mtd_device(info->cmtd);
#endif
- }
-#ifdef CONFIG_MTD_PARTITIONS
- if (info->nr_parts)
- kfree(info->parts);
-#endif
-
#ifdef CONFIG_MTD_CONCAT
- if (info->cmtd != info->mtd[0])
- mtd_concat_destroy(info->cmtd);
+ if (info->cmtd != info->mtd[0])
+ mtd_concat_destroy(info->cmtd);
#endif
+ }
for (i = 0; i < MAX_RESOURCES; i++) {
if (info->mtd[i] != NULL)
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c
index fdb97f3d30e9..f3af87e08ecd 100644
--- a/drivers/mtd/maps/sa1100-flash.c
+++ b/drivers/mtd/maps/sa1100-flash.c
@@ -209,8 +209,8 @@ static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *r
}
subdev->mtd->owner = THIS_MODULE;
- printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, "
- "%d-bit\n", phys, subdev->mtd->size >> 20,
+ printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %uMiB, %d-bit\n",
+ phys, (unsigned)(subdev->mtd->size >> 20),
subdev->map.bankwidth * 8);
return 0;
@@ -248,7 +248,7 @@ static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *pla
plat->exit();
}
-static struct sa_info *__init
+static struct sa_info *__devinit
sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
{
struct sa_info *info;
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 8ca17a3e96ea..b76d6e5e0bc0 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -379,7 +379,7 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
tr->blkcore_priv->thread = kthread_run(mtd_blktrans_thread, tr,
"%sd", tr->name);
if (IS_ERR(tr->blkcore_priv->thread)) {
- int ret = PTR_ERR(tr->blkcore_priv->thread);
+ ret = PTR_ERR(tr->blkcore_priv->thread);
blk_cleanup_queue(tr->blkcore_priv->rq);
unregister_blkdev(tr->major, tr->name);
kfree(tr->blkcore_priv);
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 2fda0b615246..7678538344f4 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -1,5 +1,3 @@
-# drivers/mtd/nand/Kconfig
-
menuconfig MTD_NAND
tristate "NAND Device Support"
depends on MTD
@@ -203,6 +201,22 @@ config MTD_NAND_S3C2410_CLKSTOP
when the is NAND chip selected or released, but will save
approximately 5mA of power when there is nothing happening.
+config MTD_NAND_BCM_UMI
+ tristate "NAND Flash support for BCM Reference Boards"
+ depends on ARCH_BCMRING && MTD_NAND
+ help
+ This enables the NAND flash controller on the BCM UMI block.
+
+ No board specfic support is done by this driver, each board
+ must advertise a platform_device for the driver to attach.
+
+config MTD_NAND_BCM_UMI_HWCS
+ bool "BCM UMI NAND Hardware CS"
+ depends on MTD_NAND_BCM_UMI
+ help
+ Enable the use of the BCM UMI block's internal CS using NAND.
+ This should only be used if you know the external NAND CS can toggle.
+
config MTD_NAND_DISKONCHIP
tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)"
depends on EXPERIMENTAL
@@ -358,7 +372,7 @@ endchoice
config MTD_NAND_PXA3xx
tristate "Support for NAND flash devices on PXA3xx"
- depends on MTD_NAND && PXA3xx
+ depends on MTD_NAND && (PXA3xx || ARCH_MMP)
help
This enables the driver for the NAND flash device found on
PXA3xx processors
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 6950d3dabf10..460a1f39a8d1 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -42,5 +42,6 @@ obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
obj-$(CONFIG_MTD_NAND_W90P910) += w90p910_nand.o
obj-$(CONFIG_MTD_NAND_NOMADIK) += nomadik_nand.o
+obj-$(CONFIG_MTD_NAND_BCM_UMI) += bcm_umi_nand.o nand_bcm_umi.o
nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c
index 005b91f096f2..2548e1065bf8 100644
--- a/drivers/mtd/nand/ams-delta.c
+++ b/drivers/mtd/nand/ams-delta.c
@@ -25,7 +25,7 @@
#include <mach/hardware.h>
#include <asm/sizes.h>
#include <mach/gpio.h>
-#include <mach/board-ams-delta.h>
+#include <plat/board-ams-delta.h>
/*
* MTD structure for E3 (Delta)
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index f8e9975c86e5..4f62d207b87b 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -192,7 +192,6 @@ static int atmel_nand_calculate(struct mtd_info *mtd,
{
struct nand_chip *nand_chip = mtd->priv;
struct atmel_nand_host *host = nand_chip->priv;
- uint32_t *eccpos = nand_chip->ecc.layout->eccpos;
unsigned int ecc_value;
/* get the first 2 ECC bytes */
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c
index 92c334ff4508..43d46e424040 100644
--- a/drivers/mtd/nand/au1550nd.c
+++ b/drivers/mtd/nand/au1550nd.c
@@ -19,6 +19,7 @@
#include <asm/io.h>
#include <asm/mach-au1x00/au1xxx.h>
+#include <asm/mach-db1x00/bcsr.h>
/*
* MTD structure for NAND controller
@@ -475,7 +476,8 @@ static int __init au1xxx_nand_init(void)
/* set gpio206 high */
au_writel(au_readl(GPIO2_DIR) & ~(1 << 6), GPIO2_DIR);
- boot_swapboot = (au_readl(MEM_STSTAT) & (0x7 << 1)) | ((bcsr->status >> 6) & 0x1);
+ boot_swapboot = (au_readl(MEM_STSTAT) & (0x7 << 1)) | ((bcsr_read(BCSR_STATUS) >> 6) & 0x1);
+
switch (boot_swapboot) {
case 0:
case 2:
diff --git a/drivers/mtd/nand/bcm_umi_bch.c b/drivers/mtd/nand/bcm_umi_bch.c
new file mode 100644
index 000000000000..a930666d0687
--- /dev/null
+++ b/drivers/mtd/nand/bcm_umi_bch.c
@@ -0,0 +1,213 @@
+/*****************************************************************************
+* Copyright 2004 - 2009 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+/* ---- Include Files ---------------------------------------------------- */
+#include "nand_bcm_umi.h"
+
+/* ---- External Variable Declarations ----------------------------------- */
+/* ---- External Function Prototypes ------------------------------------- */
+/* ---- Public Variables ------------------------------------------------- */
+/* ---- Private Constants and Types -------------------------------------- */
+
+/* ---- Private Function Prototypes -------------------------------------- */
+static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
+ struct nand_chip *chip, uint8_t *buf, int page);
+static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
+ struct nand_chip *chip, const uint8_t *buf);
+
+/* ---- Private Variables ------------------------------------------------ */
+
+/*
+** nand_hw_eccoob
+** New oob placement block for use with hardware ecc generation.
+*/
+static struct nand_ecclayout nand_hw_eccoob_512 = {
+ /* Reserve 5 for BI indicator */
+ .oobfree = {
+#if (NAND_ECC_NUM_BYTES > 3)
+ {.offset = 0, .length = 2}
+#else
+ {.offset = 0, .length = 5},
+ {.offset = 6, .length = 7}
+#endif
+ }
+};
+
+/*
+** We treat the OOB for a 2K page as if it were 4 512 byte oobs,
+** except the BI is at byte 0.
+*/
+static struct nand_ecclayout nand_hw_eccoob_2048 = {
+ /* Reserve 0 as BI indicator */
+ .oobfree = {
+#if (NAND_ECC_NUM_BYTES > 10)
+ {.offset = 1, .length = 2},
+#elif (NAND_ECC_NUM_BYTES > 7)
+ {.offset = 1, .length = 5},
+ {.offset = 16, .length = 6},
+ {.offset = 32, .length = 6},
+ {.offset = 48, .length = 6}
+#else
+ {.offset = 1, .length = 8},
+ {.offset = 16, .length = 9},
+ {.offset = 32, .length = 9},
+ {.offset = 48, .length = 9}
+#endif
+ }
+};
+
+/* We treat the OOB for a 4K page as if it were 8 512 byte oobs,
+ * except the BI is at byte 0. */
+static struct nand_ecclayout nand_hw_eccoob_4096 = {
+ /* Reserve 0 as BI indicator */
+ .oobfree = {
+#if (NAND_ECC_NUM_BYTES > 10)
+ {.offset = 1, .length = 2},
+ {.offset = 16, .length = 3},
+ {.offset = 32, .length = 3},
+ {.offset = 48, .length = 3},
+ {.offset = 64, .length = 3},
+ {.offset = 80, .length = 3},
+ {.offset = 96, .length = 3},
+ {.offset = 112, .length = 3}
+#else
+ {.offset = 1, .length = 5},
+ {.offset = 16, .length = 6},
+ {.offset = 32, .length = 6},
+ {.offset = 48, .length = 6},
+ {.offset = 64, .length = 6},
+ {.offset = 80, .length = 6},
+ {.offset = 96, .length = 6},
+ {.offset = 112, .length = 6}
+#endif
+ }
+};
+
+/* ---- Private Functions ------------------------------------------------ */
+/* ==== Public Functions ================================================= */
+
+/****************************************************************************
+*
+* bcm_umi_bch_read_page_hwecc - hardware ecc based page read function
+* @mtd: mtd info structure
+* @chip: nand chip info structure
+* @buf: buffer to store read data
+*
+***************************************************************************/
+static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
+ struct nand_chip *chip, uint8_t * buf,
+ int page)
+{
+ int sectorIdx = 0;
+ int eccsize = chip->ecc.size;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *datap = buf;
+ uint8_t eccCalc[NAND_ECC_NUM_BYTES];
+ int sectorOobSize = mtd->oobsize / eccsteps;
+ int stat;
+
+ for (sectorIdx = 0; sectorIdx < eccsteps;
+ sectorIdx++, datap += eccsize) {
+ if (sectorIdx > 0) {
+ /* Seek to page location within sector */
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, sectorIdx * eccsize,
+ -1);
+ }
+
+ /* Enable hardware ECC before reading the buf */
+ nand_bcm_umi_bch_enable_read_hwecc();
+
+ /* Read in data */
+ bcm_umi_nand_read_buf(mtd, datap, eccsize);
+
+ /* Pause hardware ECC after reading the buf */
+ nand_bcm_umi_bch_pause_read_ecc_calc();
+
+ /* Read the OOB ECC */
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
+ mtd->writesize + sectorIdx * sectorOobSize, -1);
+ nand_bcm_umi_bch_read_oobEcc(mtd->writesize, eccCalc,
+ NAND_ECC_NUM_BYTES,
+ chip->oob_poi +
+ sectorIdx * sectorOobSize);
+
+ /* Correct any ECC detected errors */
+ stat =
+ nand_bcm_umi_bch_correct_page(datap, eccCalc,
+ NAND_ECC_NUM_BYTES);
+
+ /* Update Stats */
+ if (stat < 0) {
+#if defined(NAND_BCM_UMI_DEBUG)
+ printk(KERN_WARNING "%s uncorr_err sectorIdx=%d\n",
+ __func__, sectorIdx);
+ printk(KERN_WARNING
+ "%s data %02x %02x %02x %02x "
+ "%02x %02x %02x %02x\n",
+ __func__, datap[0], datap[1], datap[2], datap[3],
+ datap[4], datap[5], datap[6], datap[7]);
+ printk(KERN_WARNING
+ "%s ecc %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x\n",
+ __func__, eccCalc[0], eccCalc[1], eccCalc[2],
+ eccCalc[3], eccCalc[4], eccCalc[5], eccCalc[6],
+ eccCalc[7], eccCalc[8], eccCalc[9], eccCalc[10],
+ eccCalc[11], eccCalc[12]);
+ BUG();
+#endif
+ mtd->ecc_stats.failed++;
+ } else {
+#if defined(NAND_BCM_UMI_DEBUG)
+ if (stat > 0) {
+ printk(KERN_INFO
+ "%s %d correctable_errors detected\n",
+ __func__, stat);
+ }
+#endif
+ mtd->ecc_stats.corrected += stat;
+ }
+ }
+ return 0;
+}
+
+/****************************************************************************
+*
+* bcm_umi_bch_write_page_hwecc - hardware ecc based page write function
+* @mtd: mtd info structure
+* @chip: nand chip info structure
+* @buf: data buffer
+*
+***************************************************************************/
+static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
+ struct nand_chip *chip, const uint8_t *buf)
+{
+ int sectorIdx = 0;
+ int eccsize = chip->ecc.size;
+ int eccsteps = chip->ecc.steps;
+ const uint8_t *datap = buf;
+ uint8_t *oobp = chip->oob_poi;
+ int sectorOobSize = mtd->oobsize / eccsteps;
+
+ for (sectorIdx = 0; sectorIdx < eccsteps;
+ sectorIdx++, datap += eccsize, oobp += sectorOobSize) {
+ /* Enable hardware ECC before writing the buf */
+ nand_bcm_umi_bch_enable_write_hwecc();
+ bcm_umi_nand_write_buf(mtd, datap, eccsize);
+ nand_bcm_umi_bch_write_oobEcc(mtd->writesize, oobp,
+ NAND_ECC_NUM_BYTES);
+ }
+
+ bcm_umi_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+}
diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c
new file mode 100644
index 000000000000..087bcd745bb7
--- /dev/null
+++ b/drivers/mtd/nand/bcm_umi_nand.c
@@ -0,0 +1,581 @@
+/*****************************************************************************
+* Copyright 2004 - 2009 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+/* ---- Include Files ---------------------------------------------------- */
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach-types.h>
+#include <asm/system.h>
+
+#include <mach/reg_nand.h>
+#include <mach/reg_umi.h>
+
+#include "nand_bcm_umi.h"
+
+#include <mach/memory_settings.h>
+
+#define USE_DMA 1
+#include <mach/dma.h>
+#include <linux/dma-mapping.h>
+#include <linux/completion.h>
+
+/* ---- External Variable Declarations ----------------------------------- */
+/* ---- External Function Prototypes ------------------------------------- */
+/* ---- Public Variables ------------------------------------------------- */
+/* ---- Private Constants and Types -------------------------------------- */
+static const __devinitconst char gBanner[] = KERN_INFO \
+ "BCM UMI MTD NAND Driver: 1.00\n";
+
+#ifdef CONFIG_MTD_PARTITIONS
+const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
+#if NAND_ECC_BCH
+static uint8_t scan_ff_pattern[] = { 0xff };
+
+static struct nand_bbt_descr largepage_bbt = {
+ .options = 0,
+ .offs = 0,
+ .len = 1,
+ .pattern = scan_ff_pattern
+};
+#endif
+
+/*
+** Preallocate a buffer to avoid having to do this every dma operation.
+** This is the size of the preallocated coherent DMA buffer.
+*/
+#if USE_DMA
+#define DMA_MIN_BUFLEN 512
+#define DMA_MAX_BUFLEN PAGE_SIZE
+#define USE_DIRECT_IO(len) (((len) < DMA_MIN_BUFLEN) || \
+ ((len) > DMA_MAX_BUFLEN))
+
+/*
+ * The current NAND data space goes from 0x80001900 to 0x80001FFF,
+ * which is only 0x700 = 1792 bytes long. This is too small for 2K, 4K page
+ * size NAND flash. Need to break the DMA down to multiple 1Ks.
+ *
+ * Need to make sure REG_NAND_DATA_PADDR + DMA_MAX_LEN < 0x80002000
+ */
+#define DMA_MAX_LEN 1024
+
+#else /* !USE_DMA */
+#define DMA_MIN_BUFLEN 0
+#define DMA_MAX_BUFLEN 0
+#define USE_DIRECT_IO(len) 1
+#endif
+/* ---- Private Function Prototypes -------------------------------------- */
+static void bcm_umi_nand_read_buf(struct mtd_info *mtd, u_char * buf, int len);
+static void bcm_umi_nand_write_buf(struct mtd_info *mtd, const u_char * buf,
+ int len);
+
+/* ---- Private Variables ------------------------------------------------ */
+static struct mtd_info *board_mtd;
+static void __iomem *bcm_umi_io_base;
+static void *virtPtr;
+static dma_addr_t physPtr;
+static struct completion nand_comp;
+
+/* ---- Private Functions ------------------------------------------------ */
+#if NAND_ECC_BCH
+#include "bcm_umi_bch.c"
+#else
+#include "bcm_umi_hamming.c"
+#endif
+
+#if USE_DMA
+
+/* Handler called when the DMA finishes. */
+static void nand_dma_handler(DMA_Device_t dev, int reason, void *userData)
+{
+ complete(&nand_comp);
+}
+
+static int nand_dma_init(void)
+{
+ int rc;
+
+ rc = dma_set_device_handler(DMA_DEVICE_NAND_MEM_TO_MEM,
+ nand_dma_handler, NULL);
+ if (rc != 0) {
+ printk(KERN_ERR "dma_set_device_handler failed: %d\n", rc);
+ return rc;
+ }
+
+ virtPtr =
+ dma_alloc_coherent(NULL, DMA_MAX_BUFLEN, &physPtr, GFP_KERNEL);
+ if (virtPtr == NULL) {
+ printk(KERN_ERR "NAND - Failed to allocate memory for DMA buffer\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void nand_dma_term(void)
+{
+ if (virtPtr != NULL)
+ dma_free_coherent(NULL, DMA_MAX_BUFLEN, virtPtr, physPtr);
+}
+
+static void nand_dma_read(void *buf, int len)
+{
+ int offset = 0;
+ int tmp_len = 0;
+ int len_left = len;
+ DMA_Handle_t hndl;
+
+ if (virtPtr == NULL)
+ panic("nand_dma_read: virtPtr == NULL\n");
+
+ if ((void *)physPtr == NULL)
+ panic("nand_dma_read: physPtr == NULL\n");
+
+ hndl = dma_request_channel(DMA_DEVICE_NAND_MEM_TO_MEM);
+ if (hndl < 0) {
+ printk(KERN_ERR
+ "nand_dma_read: unable to allocate dma channel: %d\n",
+ (int)hndl);
+ panic("\n");
+ }
+
+ while (len_left > 0) {
+ if (len_left > DMA_MAX_LEN) {
+ tmp_len = DMA_MAX_LEN;
+ len_left -= DMA_MAX_LEN;
+ } else {
+ tmp_len = len_left;
+ len_left = 0;
+ }
+
+ init_completion(&nand_comp);
+ dma_transfer_mem_to_mem(hndl, REG_NAND_DATA_PADDR,
+ physPtr + offset, tmp_len);
+ wait_for_completion(&nand_comp);
+
+ offset += tmp_len;
+ }
+
+ dma_free_channel(hndl);
+
+ if (buf != NULL)
+ memcpy(buf, virtPtr, len);
+}
+
+static void nand_dma_write(const void *buf, int len)
+{
+ int offset = 0;
+ int tmp_len = 0;
+ int len_left = len;
+ DMA_Handle_t hndl;
+
+ if (buf == NULL)
+ panic("nand_dma_write: buf == NULL\n");
+
+ if (virtPtr == NULL)
+ panic("nand_dma_write: virtPtr == NULL\n");
+
+ if ((void *)physPtr == NULL)
+ panic("nand_dma_write: physPtr == NULL\n");
+
+ memcpy(virtPtr, buf, len);
+
+
+ hndl = dma_request_channel(DMA_DEVICE_NAND_MEM_TO_MEM);
+ if (hndl < 0) {
+ printk(KERN_ERR
+ "nand_dma_write: unable to allocate dma channel: %d\n",
+ (int)hndl);
+ panic("\n");
+ }
+
+ while (len_left > 0) {
+ if (len_left > DMA_MAX_LEN) {
+ tmp_len = DMA_MAX_LEN;
+ len_left -= DMA_MAX_LEN;
+ } else {
+ tmp_len = len_left;
+ len_left = 0;
+ }
+
+ init_completion(&nand_comp);
+ dma_transfer_mem_to_mem(hndl, physPtr + offset,
+ REG_NAND_DATA_PADDR, tmp_len);
+ wait_for_completion(&nand_comp);
+
+ offset += tmp_len;
+ }
+
+ dma_free_channel(hndl);
+}
+
+#endif
+
+static int nand_dev_ready(struct mtd_info *mtd)
+{
+ return nand_bcm_umi_dev_ready();
+}
+
+/****************************************************************************
+*
+* bcm_umi_nand_inithw
+*
+* This routine does the necessary hardware (board-specific)
+* initializations. This includes setting up the timings, etc.
+*
+***************************************************************************/
+int bcm_umi_nand_inithw(void)
+{
+ /* Configure nand timing parameters */
+ REG_UMI_NAND_TCR &= ~0x7ffff;
+ REG_UMI_NAND_TCR |= HW_CFG_NAND_TCR;
+
+#if !defined(CONFIG_MTD_NAND_BCM_UMI_HWCS)
+ /* enable software control of CS */
+ REG_UMI_NAND_TCR |= REG_UMI_NAND_TCR_CS_SWCTRL;
+#endif
+
+ /* keep NAND chip select asserted */
+ REG_UMI_NAND_RCSR |= REG_UMI_NAND_RCSR_CS_ASSERTED;
+
+ REG_UMI_NAND_TCR &= ~REG_UMI_NAND_TCR_WORD16;
+ /* enable writes to flash */
+ REG_UMI_MMD_ICR |= REG_UMI_MMD_ICR_FLASH_WP;
+
+ writel(NAND_CMD_RESET, bcm_umi_io_base + REG_NAND_CMD_OFFSET);
+ nand_bcm_umi_wait_till_ready();
+
+#if NAND_ECC_BCH
+ nand_bcm_umi_bch_config_ecc(NAND_ECC_NUM_BYTES);
+#endif
+
+ return 0;
+}
+
+/* Used to turn latch the proper register for access. */
+static void bcm_umi_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
+{
+ /* send command to hardware */
+ struct nand_chip *chip = mtd->priv;
+ if (ctrl & NAND_CTRL_CHANGE) {
+ if (ctrl & NAND_CLE) {
+ chip->IO_ADDR_W = bcm_umi_io_base + REG_NAND_CMD_OFFSET;
+ goto CMD;
+ }
+ if (ctrl & NAND_ALE) {
+ chip->IO_ADDR_W =
+ bcm_umi_io_base + REG_NAND_ADDR_OFFSET;
+ goto CMD;
+ }
+ chip->IO_ADDR_W = bcm_umi_io_base + REG_NAND_DATA8_OFFSET;
+ }
+
+CMD:
+ /* Send command to chip directly */
+ if (cmd != NAND_CMD_NONE)
+ writeb(cmd, chip->IO_ADDR_W);
+}
+
+static void bcm_umi_nand_write_buf(struct mtd_info *mtd, const u_char * buf,
+ int len)
+{
+ if (USE_DIRECT_IO(len)) {
+ /* Do it the old way if the buffer is small or too large.
+ * Probably quicker than starting and checking dma. */
+ int i;
+ struct nand_chip *this = mtd->priv;
+
+ for (i = 0; i < len; i++)
+ writeb(buf[i], this->IO_ADDR_W);
+ }
+#if USE_DMA
+ else
+ nand_dma_write(buf, len);
+#endif
+}
+
+static void bcm_umi_nand_read_buf(struct mtd_info *mtd, u_char * buf, int len)
+{
+ if (USE_DIRECT_IO(len)) {
+ int i;
+ struct nand_chip *this = mtd->priv;
+
+ for (i = 0; i < len; i++)
+ buf[i] = readb(this->IO_ADDR_R);
+ }
+#if USE_DMA
+ else
+ nand_dma_read(buf, len);
+#endif
+}
+
+static uint8_t readbackbuf[NAND_MAX_PAGESIZE];
+static int bcm_umi_nand_verify_buf(struct mtd_info *mtd, const u_char * buf,
+ int len)
+{
+ /*
+ * Try to readback page with ECC correction. This is necessary
+ * for MLC parts which may have permanently stuck bits.
+ */
+ struct nand_chip *chip = mtd->priv;
+ int ret = chip->ecc.read_page(mtd, chip, readbackbuf, 0);
+ if (ret < 0)
+ return -EFAULT;
+ else {
+ if (memcmp(readbackbuf, buf, len) == 0)
+ return 0;
+
+ return -EFAULT;
+ }
+ return 0;
+}
+
+static int __devinit bcm_umi_nand_probe(struct platform_device *pdev)
+{
+ struct nand_chip *this;
+ struct resource *r;
+ int err = 0;
+
+ printk(gBanner);
+
+ /* Allocate memory for MTD device structure and private data */
+ board_mtd =
+ kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip),
+ GFP_KERNEL);
+ if (!board_mtd) {
+ printk(KERN_WARNING
+ "Unable to allocate NAND MTD device structure.\n");
+ return -ENOMEM;
+ }
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!r)
+ return -ENXIO;
+
+ /* map physical adress */
+ bcm_umi_io_base = ioremap(r->start, r->end - r->start + 1);
+
+ if (!bcm_umi_io_base) {
+ printk(KERN_ERR "ioremap to access BCM UMI NAND chip failed\n");
+ kfree(board_mtd);
+ return -EIO;
+ }
+
+ /* Get pointer to private data */
+ this = (struct nand_chip *)(&board_mtd[1]);
+
+ /* Initialize structures */
+ memset((char *)board_mtd, 0, sizeof(struct mtd_info));
+ memset((char *)this, 0, sizeof(struct nand_chip));
+
+ /* Link the private data with the MTD structure */
+ board_mtd->priv = this;
+
+ /* Initialize the NAND hardware. */
+ if (bcm_umi_nand_inithw() < 0) {
+ printk(KERN_ERR "BCM UMI NAND chip could not be initialized\n");
+ iounmap(bcm_umi_io_base);
+ kfree(board_mtd);
+ return -EIO;
+ }
+
+ /* Set address of NAND IO lines */
+ this->IO_ADDR_W = bcm_umi_io_base + REG_NAND_DATA8_OFFSET;
+ this->IO_ADDR_R = bcm_umi_io_base + REG_NAND_DATA8_OFFSET;
+
+ /* Set command delay time, see datasheet for correct value */
+ this->chip_delay = 0;
+ /* Assign the device ready function, if available */
+ this->dev_ready = nand_dev_ready;
+ this->options = 0;
+
+ this->write_buf = bcm_umi_nand_write_buf;
+ this->read_buf = bcm_umi_nand_read_buf;
+ this->verify_buf = bcm_umi_nand_verify_buf;
+
+ this->cmd_ctrl = bcm_umi_nand_hwcontrol;
+ this->ecc.mode = NAND_ECC_HW;
+ this->ecc.size = 512;
+ this->ecc.bytes = NAND_ECC_NUM_BYTES;
+#if NAND_ECC_BCH
+ this->ecc.read_page = bcm_umi_bch_read_page_hwecc;
+ this->ecc.write_page = bcm_umi_bch_write_page_hwecc;
+#else
+ this->ecc.correct = nand_correct_data512;
+ this->ecc.calculate = bcm_umi_hamming_get_hw_ecc;
+ this->ecc.hwctl = bcm_umi_hamming_enable_hwecc;
+#endif
+
+#if USE_DMA
+ err = nand_dma_init();
+ if (err != 0)
+ return err;
+#endif
+
+ /* Figure out the size of the device that we have.
+ * We need to do this to figure out which ECC
+ * layout we'll be using.
+ */
+
+ err = nand_scan_ident(board_mtd, 1);
+ if (err) {
+ printk(KERN_ERR "nand_scan failed: %d\n", err);
+ iounmap(bcm_umi_io_base);
+ kfree(board_mtd);
+ return err;
+ }
+
+ /* Now that we know the nand size, we can setup the ECC layout */
+
+ switch (board_mtd->writesize) { /* writesize is the pagesize */
+ case 4096:
+ this->ecc.layout = &nand_hw_eccoob_4096;
+ break;
+ case 2048:
+ this->ecc.layout = &nand_hw_eccoob_2048;
+ break;
+ case 512:
+ this->ecc.layout = &nand_hw_eccoob_512;
+ break;
+ default:
+ {
+ printk(KERN_ERR "NAND - Unrecognized pagesize: %d\n",
+ board_mtd->writesize);
+ return -EINVAL;
+ }
+ }
+
+#if NAND_ECC_BCH
+ if (board_mtd->writesize > 512) {
+ if (this->options & NAND_USE_FLASH_BBT)
+ largepage_bbt.options = NAND_BBT_SCAN2NDPAGE;
+ this->badblock_pattern = &largepage_bbt;
+ }
+#endif
+
+ /* Now finish off the scan, now that ecc.layout has been initialized. */
+
+ err = nand_scan_tail(board_mtd);
+ if (err) {
+ printk(KERN_ERR "nand_scan failed: %d\n", err);
+ iounmap(bcm_umi_io_base);
+ kfree(board_mtd);
+ return err;
+ }
+
+ /* Register the partitions */
+ {
+ int nr_partitions;
+ struct mtd_partition *partition_info;
+
+ board_mtd->name = "bcm_umi-nand";
+ nr_partitions =
+ parse_mtd_partitions(board_mtd, part_probes,
+ &partition_info, 0);
+
+ if (nr_partitions <= 0) {
+ printk(KERN_ERR "BCM UMI NAND: Too few partitions - %d\n",
+ nr_partitions);
+ iounmap(bcm_umi_io_base);
+ kfree(board_mtd);
+ return -EIO;
+ }
+ add_mtd_partitions(board_mtd, partition_info, nr_partitions);
+ }
+
+ /* Return happy */
+ return 0;
+}
+
+static int bcm_umi_nand_remove(struct platform_device *pdev)
+{
+#if USE_DMA
+ nand_dma_term();
+#endif
+
+ /* Release resources, unregister device */
+ nand_release(board_mtd);
+
+ /* unmap physical adress */
+ iounmap(bcm_umi_io_base);
+
+ /* Free the MTD device structure */
+ kfree(board_mtd);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int bcm_umi_nand_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ printk(KERN_ERR "MTD NAND suspend is being called\n");
+ return 0;
+}
+
+static int bcm_umi_nand_resume(struct platform_device *pdev)
+{
+ printk(KERN_ERR "MTD NAND resume is being called\n");
+ return 0;
+}
+#else
+#define bcm_umi_nand_suspend NULL
+#define bcm_umi_nand_resume NULL
+#endif
+
+static struct platform_driver nand_driver = {
+ .driver = {
+ .name = "bcm-nand",
+ .owner = THIS_MODULE,
+ },
+ .probe = bcm_umi_nand_probe,
+ .remove = bcm_umi_nand_remove,
+ .suspend = bcm_umi_nand_suspend,
+ .resume = bcm_umi_nand_resume,
+};
+
+static int __init nand_init(void)
+{
+ return platform_driver_register(&nand_driver);
+}
+
+static void __exit nand_exit(void)
+{
+ platform_driver_unregister(&nand_driver);
+}
+
+module_init(nand_init);
+module_exit(nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Broadcom");
+MODULE_DESCRIPTION("BCM UMI MTD NAND driver");
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index f13f5b9afaf7..68cc9247fdb0 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -599,7 +599,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
info->mask_chipsel = pdata->mask_chipsel;
/* use nandboot-capable ALE/CLE masks by default */
- info->mask_ale = pdata->mask_cle ? : MASK_ALE;
+ info->mask_ale = pdata->mask_ale ? : MASK_ALE;
info->mask_cle = pdata->mask_cle ? : MASK_CLE;
/* Set address of hardware control function */
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index 65b26d5a5c0d..06c531485df9 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -857,17 +857,6 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
}
}
-/* Define some generic bad / good block scan pattern which are used
- * while scanning a device for factory marked good / bad blocks. */
-static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
-
-static struct nand_bbt_descr smallpage_memorybased = {
- .options = NAND_BBT_SCAN2NDPAGE,
- .offs = 5,
- .len = 1,
- .pattern = scan_ff_pattern
-};
-
static int __init mxcnd_probe(struct platform_device *pdev)
{
struct nand_chip *this;
@@ -984,10 +973,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
goto escan;
}
- if (mtd->writesize == 2048) {
- host->pagesize_2k = 1;
- this->badblock_pattern = &smallpage_memorybased;
- }
+ host->pagesize_2k = (mtd->writesize == 2048) ? 1 : 0;
if (this->ecc.mode == NAND_ECC_HW) {
switch (mtd->oobsize) {
@@ -1052,7 +1038,7 @@ eclk:
return err;
}
-static int __devexit mxcnd_remove(struct platform_device *pdev)
+static int __exit mxcnd_remove(struct platform_device *pdev)
{
struct mxc_nand_host *host = platform_get_drvdata(pdev);
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 22113865438b..2957cc70da3d 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -761,6 +761,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
+ * @page: page number to read
*
* Not for syndrome calculating ecc controllers, which use a special oob layout
*/
@@ -777,6 +778,7 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
+ * @page: page number to read
*
* We need a special oob layout and handling even when OOB isn't used.
*/
@@ -818,6 +820,7 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *c
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
+ * @page: page number to read
*/
static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int page)
@@ -939,6 +942,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
+ * @page: page number to read
*
* Not for syndrome calculating ecc controllers which need a special oob layout
*/
@@ -983,6 +987,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
+ * @page: page number to read
*
* Hardware ECC for large page chips, require OOB to be read first.
* For this ECC mode, the write_page method is re-used from ECC_HW.
@@ -1031,6 +1036,7 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
+ * @page: page number to read
*
* The hw generator calculates the error syndrome automatically. Therefor
* we need a special oob layout and handling.
diff --git a/drivers/mtd/nand/nand_bcm_umi.c b/drivers/mtd/nand/nand_bcm_umi.c
new file mode 100644
index 000000000000..46a6bc9c4b74
--- /dev/null
+++ b/drivers/mtd/nand/nand_bcm_umi.c
@@ -0,0 +1,149 @@
+/*****************************************************************************
+* Copyright 2004 - 2009 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+/* ---- Include Files ---------------------------------------------------- */
+#include <mach/reg_umi.h>
+#include "nand_bcm_umi.h"
+#ifdef BOOT0_BUILD
+#include <uart.h>
+#endif
+
+/* ---- External Variable Declarations ----------------------------------- */
+/* ---- External Function Prototypes ------------------------------------- */
+/* ---- Public Variables ------------------------------------------------- */
+/* ---- Private Constants and Types -------------------------------------- */
+/* ---- Private Function Prototypes -------------------------------------- */
+/* ---- Private Variables ------------------------------------------------ */
+/* ---- Private Functions ------------------------------------------------ */
+
+#if NAND_ECC_BCH
+/****************************************************************************
+* nand_bch_ecc_flip_bit - Routine to flip an errored bit
+*
+* PURPOSE:
+* This is a helper routine that flips the bit (0 -> 1 or 1 -> 0) of the
+* errored bit specified
+*
+* PARAMETERS:
+* datap - Container that holds the 512 byte data
+* errorLocation - Location of the bit that needs to be flipped
+*
+* RETURNS:
+* None
+****************************************************************************/
+static void nand_bcm_umi_bch_ecc_flip_bit(uint8_t *datap, int errorLocation)
+{
+ int locWithinAByte = (errorLocation & REG_UMI_BCH_ERR_LOC_BYTE) >> 0;
+ int locWithinAWord = (errorLocation & REG_UMI_BCH_ERR_LOC_WORD) >> 3;
+ int locWithinAPage = (errorLocation & REG_UMI_BCH_ERR_LOC_PAGE) >> 5;
+
+ uint8_t errorByte = 0;
+ uint8_t byteMask = 1 << locWithinAByte;
+
+ /* BCH uses big endian, need to change the location
+ * bits to little endian */
+ locWithinAWord = 3 - locWithinAWord;
+
+ errorByte = datap[locWithinAPage * sizeof(uint32_t) + locWithinAWord];
+
+#ifdef BOOT0_BUILD
+ puthexs("\nECC Correct Offset: ",
+ locWithinAPage * sizeof(uint32_t) + locWithinAWord);
+ puthexs(" errorByte:", errorByte);
+ puthex8(" Bit: ", locWithinAByte);
+#endif
+
+ if (errorByte & byteMask) {
+ /* bit needs to be cleared */
+ errorByte &= ~byteMask;
+ } else {
+ /* bit needs to be set */
+ errorByte |= byteMask;
+ }
+
+ /* write back the value with the fixed bit */
+ datap[locWithinAPage * sizeof(uint32_t) + locWithinAWord] = errorByte;
+}
+
+/****************************************************************************
+* nand_correct_page_bch - Routine to correct bit errors when reading NAND
+*
+* PURPOSE:
+* This routine reads the BCH registers to determine if there are any bit
+* errors during the read of the last 512 bytes of data + ECC bytes. If
+* errors exists, the routine fixes it.
+*
+* PARAMETERS:
+* datap - Container that holds the 512 byte data
+*
+* RETURNS:
+* 0 or greater = Number of errors corrected
+* (No errors are found or errors have been fixed)
+* -1 = Error(s) cannot be fixed
+****************************************************************************/
+int nand_bcm_umi_bch_correct_page(uint8_t *datap, uint8_t *readEccData,
+ int numEccBytes)
+{
+ int numErrors;
+ int errorLocation;
+ int idx;
+ uint32_t regValue;
+
+ /* wait for read ECC to be valid */
+ regValue = nand_bcm_umi_bch_poll_read_ecc_calc();
+
+ /*
+ * read the control status register to determine if there
+ * are error'ed bits
+ * see if errors are correctible
+ */
+ if ((regValue & REG_UMI_BCH_CTRL_STATUS_UNCORR_ERR) > 0) {
+ int i;
+
+ for (i = 0; i < numEccBytes; i++) {
+ if (readEccData[i] != 0xff) {
+ /* errors cannot be fixed, return -1 */
+ return -1;
+ }
+ }
+ /* If ECC is unprogrammed then we can't correct,
+ * assume everything OK */
+ return 0;
+ }
+
+ if ((regValue & REG_UMI_BCH_CTRL_STATUS_CORR_ERR) == 0) {
+ /* no errors */
+ return 0;
+ }
+
+ /*
+ * Fix errored bits by doing the following:
+ * 1. Read the number of errors in the control and status register
+ * 2. Read the error location registers that corresponds to the number
+ * of errors reported
+ * 3. Invert the bit in the data
+ */
+ numErrors = (regValue & REG_UMI_BCH_CTRL_STATUS_NB_CORR_ERROR) >> 20;
+
+ for (idx = 0; idx < numErrors; idx++) {
+ errorLocation =
+ REG_UMI_BCH_ERR_LOC_ADDR(idx) & REG_UMI_BCH_ERR_LOC_MASK;
+
+ /* Flip bit */
+ nand_bcm_umi_bch_ecc_flip_bit(datap, errorLocation);
+ }
+ /* Errors corrected */
+ return numErrors;
+}
+#endif
diff --git a/drivers/mtd/nand/nand_bcm_umi.h b/drivers/mtd/nand/nand_bcm_umi.h
new file mode 100644
index 000000000000..7cec2cd97854
--- /dev/null
+++ b/drivers/mtd/nand/nand_bcm_umi.h
@@ -0,0 +1,358 @@
+/*****************************************************************************
+* Copyright 2003 - 2009 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+#ifndef NAND_BCM_UMI_H
+#define NAND_BCM_UMI_H
+
+/* ---- Include Files ---------------------------------------------------- */
+#include <mach/reg_umi.h>
+#include <mach/reg_nand.h>
+#include <cfg_global.h>
+
+/* ---- Constants and Types ---------------------------------------------- */
+#if (CFG_GLOBAL_CHIP_FAMILY == CFG_GLOBAL_CHIP_FAMILY_BCMRING)
+#define NAND_ECC_BCH (CFG_GLOBAL_CHIP_REV > 0xA0)
+#else
+#define NAND_ECC_BCH 0
+#endif
+
+#define CFG_GLOBAL_NAND_ECC_BCH_NUM_BYTES 13
+
+#if NAND_ECC_BCH
+#ifdef BOOT0_BUILD
+#define NAND_ECC_NUM_BYTES 13
+#else
+#define NAND_ECC_NUM_BYTES CFG_GLOBAL_NAND_ECC_BCH_NUM_BYTES
+#endif
+#else
+#define NAND_ECC_NUM_BYTES 3
+#endif
+
+#define NAND_DATA_ACCESS_SIZE 512
+
+/* ---- Variable Externs ------------------------------------------ */
+/* ---- Function Prototypes --------------------------------------- */
+int nand_bcm_umi_bch_correct_page(uint8_t *datap, uint8_t *readEccData,
+ int numEccBytes);
+
+/* Check in device is ready */
+static inline int nand_bcm_umi_dev_ready(void)
+{
+ return REG_UMI_NAND_RCSR & REG_UMI_NAND_RCSR_RDY;
+}
+
+/* Wait until device is ready */
+static inline void nand_bcm_umi_wait_till_ready(void)
+{
+ while (nand_bcm_umi_dev_ready() == 0)
+ ;
+}
+
+/* Enable Hamming ECC */
+static inline void nand_bcm_umi_hamming_enable_hwecc(void)
+{
+ /* disable and reset ECC, 512 byte page */
+ REG_UMI_NAND_ECC_CSR &= ~(REG_UMI_NAND_ECC_CSR_ECC_ENABLE |
+ REG_UMI_NAND_ECC_CSR_256BYTE);
+ /* enable ECC */
+ REG_UMI_NAND_ECC_CSR |= REG_UMI_NAND_ECC_CSR_ECC_ENABLE;
+}
+
+#if NAND_ECC_BCH
+/* BCH ECC specifics */
+#define ECC_BITS_PER_CORRECTABLE_BIT 13
+
+/* Enable BCH Read ECC */
+static inline void nand_bcm_umi_bch_enable_read_hwecc(void)
+{
+ /* disable and reset ECC */
+ REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID;
+ /* Turn on ECC */
+ REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN;
+}
+
+/* Enable BCH Write ECC */
+static inline void nand_bcm_umi_bch_enable_write_hwecc(void)
+{
+ /* disable and reset ECC */
+ REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID;
+ /* Turn on ECC */
+ REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_WR_EN;
+}
+
+/* Config number of BCH ECC bytes */
+static inline void nand_bcm_umi_bch_config_ecc(uint8_t numEccBytes)
+{
+ uint32_t nValue;
+ uint32_t tValue;
+ uint32_t kValue;
+ uint32_t numBits = numEccBytes * 8;
+
+ /* disable and reset ECC */
+ REG_UMI_BCH_CTRL_STATUS =
+ REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID |
+ REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID;
+
+ /* Every correctible bit requires 13 ECC bits */
+ tValue = (uint32_t) (numBits / ECC_BITS_PER_CORRECTABLE_BIT);
+
+ /* Total data in number of bits for generating and computing BCH ECC */
+ nValue = (NAND_DATA_ACCESS_SIZE + numEccBytes) * 8;
+
+ /* K parameter is used internally. K = N - (T * 13) */
+ kValue = nValue - (tValue * ECC_BITS_PER_CORRECTABLE_BIT);
+
+ /* Write the settings */
+ REG_UMI_BCH_N = nValue;
+ REG_UMI_BCH_T = tValue;
+ REG_UMI_BCH_K = kValue;
+}
+
+/* Pause during ECC read calculation to skip bytes in OOB */
+static inline void nand_bcm_umi_bch_pause_read_ecc_calc(void)
+{
+ REG_UMI_BCH_CTRL_STATUS =
+ REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN |
+ REG_UMI_BCH_CTRL_STATUS_PAUSE_ECC_DEC;
+}
+
+/* Resume during ECC read calculation after skipping bytes in OOB */
+static inline void nand_bcm_umi_bch_resume_read_ecc_calc(void)
+{
+ REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN;
+}
+
+/* Poll read ECC calc to check when hardware completes */
+static inline uint32_t nand_bcm_umi_bch_poll_read_ecc_calc(void)
+{
+ uint32_t regVal;
+
+ do {
+ /* wait for ECC to be valid */
+ regVal = REG_UMI_BCH_CTRL_STATUS;
+ } while ((regVal & REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID) == 0);
+
+ return regVal;
+}
+
+/* Poll write ECC calc to check when hardware completes */
+static inline void nand_bcm_umi_bch_poll_write_ecc_calc(void)
+{
+ /* wait for ECC to be valid */
+ while ((REG_UMI_BCH_CTRL_STATUS & REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID)
+ == 0)
+ ;
+}
+
+/* Read the OOB and ECC, for kernel write OOB to a buffer */
+#if defined(__KERNEL__) && !defined(STANDALONE)
+static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize,
+ uint8_t *eccCalc, int numEccBytes, uint8_t *oobp)
+#else
+static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize,
+ uint8_t *eccCalc, int numEccBytes)
+#endif
+{
+ int eccPos = 0;
+ int numToRead = 16; /* There are 16 bytes per sector in the OOB */
+
+ /* ECC is already paused when this function is called */
+
+ if (pageSize == NAND_DATA_ACCESS_SIZE) {
+ while (numToRead > numEccBytes) {
+ /* skip free oob region */
+#if defined(__KERNEL__) && !defined(STANDALONE)
+ *oobp++ = REG_NAND_DATA8;
+#else
+ REG_NAND_DATA8;
+#endif
+ numToRead--;
+ }
+
+ /* read ECC bytes before BI */
+ nand_bcm_umi_bch_resume_read_ecc_calc();
+
+ while (numToRead > 11) {
+#if defined(__KERNEL__) && !defined(STANDALONE)
+ *oobp = REG_NAND_DATA8;
+ eccCalc[eccPos++] = *oobp;
+ oobp++;
+#else
+ eccCalc[eccPos++] = REG_NAND_DATA8;
+#endif
+ }
+
+ nand_bcm_umi_bch_pause_read_ecc_calc();
+
+ if (numToRead == 11) {
+ /* read BI */
+#if defined(__KERNEL__) && !defined(STANDALONE)
+ *oobp++ = REG_NAND_DATA8;
+#else
+ REG_NAND_DATA8;
+#endif
+ numToRead--;
+ }
+
+ /* read ECC bytes */
+ nand_bcm_umi_bch_resume_read_ecc_calc();
+ while (numToRead) {
+#if defined(__KERNEL__) && !defined(STANDALONE)
+ *oobp = REG_NAND_DATA8;
+ eccCalc[eccPos++] = *oobp;
+ oobp++;
+#else
+ eccCalc[eccPos++] = REG_NAND_DATA8;
+#endif
+ numToRead--;
+ }
+ } else {
+ /* skip BI */
+#if defined(__KERNEL__) && !defined(STANDALONE)
+ *oobp++ = REG_NAND_DATA8;
+#else
+ REG_NAND_DATA8;
+#endif
+ numToRead--;
+
+ while (numToRead > numEccBytes) {
+ /* skip free oob region */
+#if defined(__KERNEL__) && !defined(STANDALONE)
+ *oobp++ = REG_NAND_DATA8;
+#else
+ REG_NAND_DATA8;
+#endif
+ numToRead--;
+ }
+
+ /* read ECC bytes */
+ nand_bcm_umi_bch_resume_read_ecc_calc();
+ while (numToRead) {
+#if defined(__KERNEL__) && !defined(STANDALONE)
+ *oobp = REG_NAND_DATA8;
+ eccCalc[eccPos++] = *oobp;
+ oobp++;
+#else
+ eccCalc[eccPos++] = REG_NAND_DATA8;
+#endif
+ numToRead--;
+ }
+ }
+}
+
+/* Helper function to write ECC */
+static inline void NAND_BCM_UMI_ECC_WRITE(int numEccBytes, int eccBytePos,
+ uint8_t *oobp, uint8_t eccVal)
+{
+ if (eccBytePos <= numEccBytes)
+ *oobp = eccVal;
+}
+
+/* Write OOB with ECC */
+static inline void nand_bcm_umi_bch_write_oobEcc(uint32_t pageSize,
+ uint8_t *oobp, int numEccBytes)
+{
+ uint32_t eccVal = 0xffffffff;
+
+ /* wait for write ECC to be valid */
+ nand_bcm_umi_bch_poll_write_ecc_calc();
+
+ /*
+ ** Get the hardware ecc from the 32-bit result registers.
+ ** Read after 512 byte accesses. Format B3B2B1B0
+ ** where B3 = ecc3, etc.
+ */
+
+ if (pageSize == NAND_DATA_ACCESS_SIZE) {
+ /* Now fill in the ECC bytes */
+ if (numEccBytes >= 13)
+ eccVal = REG_UMI_BCH_WR_ECC_3;
+
+ /* Usually we skip CM in oob[0,1] */
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[0],
+ (eccVal >> 16) & 0xff);
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 14, &oobp[1],
+ (eccVal >> 8) & 0xff);
+
+ /* Write ECC in oob[2,3,4] */
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 13, &oobp[2],
+ eccVal & 0xff); /* ECC 12 */
+
+ if (numEccBytes >= 9)
+ eccVal = REG_UMI_BCH_WR_ECC_2;
+
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[3],
+ (eccVal >> 24) & 0xff); /* ECC11 */
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 11, &oobp[4],
+ (eccVal >> 16) & 0xff); /* ECC10 */
+
+ /* Always Skip BI in oob[5] */
+ } else {
+ /* Always Skip BI in oob[0] */
+
+ /* Now fill in the ECC bytes */
+ if (numEccBytes >= 13)
+ eccVal = REG_UMI_BCH_WR_ECC_3;
+
+ /* Usually skip CM in oob[1,2] */
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[1],
+ (eccVal >> 16) & 0xff);
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 14, &oobp[2],
+ (eccVal >> 8) & 0xff);
+
+ /* Write ECC in oob[3-15] */
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 13, &oobp[3],
+ eccVal & 0xff); /* ECC12 */
+
+ if (numEccBytes >= 9)
+ eccVal = REG_UMI_BCH_WR_ECC_2;
+
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[4],
+ (eccVal >> 24) & 0xff); /* ECC11 */
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 11, &oobp[5],
+ (eccVal >> 16) & 0xff); /* ECC10 */
+ }
+
+ /* Fill in the remainder of ECC locations */
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 10, &oobp[6],
+ (eccVal >> 8) & 0xff); /* ECC9 */
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 9, &oobp[7],
+ eccVal & 0xff); /* ECC8 */
+
+ if (numEccBytes >= 5)
+ eccVal = REG_UMI_BCH_WR_ECC_1;
+
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 8, &oobp[8],
+ (eccVal >> 24) & 0xff); /* ECC7 */
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 7, &oobp[9],
+ (eccVal >> 16) & 0xff); /* ECC6 */
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 6, &oobp[10],
+ (eccVal >> 8) & 0xff); /* ECC5 */
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 5, &oobp[11],
+ eccVal & 0xff); /* ECC4 */
+
+ if (numEccBytes >= 1)
+ eccVal = REG_UMI_BCH_WR_ECC_0;
+
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 4, &oobp[12],
+ (eccVal >> 24) & 0xff); /* ECC3 */
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 3, &oobp[13],
+ (eccVal >> 16) & 0xff); /* ECC2 */
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 2, &oobp[14],
+ (eccVal >> 8) & 0xff); /* ECC1 */
+ NAND_BCM_UMI_ECC_WRITE(numEccBytes, 1, &oobp[15],
+ eccVal & 0xff); /* ECC0 */
+}
+#endif
+
+#endif /* NAND_BCM_UMI_H */
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 090ab87086b5..1bb799f0125c 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -18,9 +18,9 @@
#include <linux/mtd/partitions.h>
#include <linux/io.h>
-#include <mach/dma.h>
-#include <mach/gpmc.h>
-#include <mach/nand.h>
+#include <plat/dma.h>
+#include <plat/gpmc.h>
+#include <plat/nand.h>
#define GPMC_IRQ_STATUS 0x18
#define GPMC_ECC_CONFIG 0x1F4
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c
index 4e16c6f5bdd5..8d467315f02b 100644
--- a/drivers/mtd/nand/plat_nand.c
+++ b/drivers/mtd/nand/plat_nand.c
@@ -34,7 +34,12 @@ static int __devinit plat_nand_probe(struct platform_device *pdev)
{
struct platform_nand_data *pdata = pdev->dev.platform_data;
struct plat_nand_data *data;
- int res = 0;
+ struct resource *res;
+ int err = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENXIO;
/* Allocate memory for the device structure (and zero it) */
data = kzalloc(sizeof(struct plat_nand_data), GFP_KERNEL);
@@ -43,12 +48,18 @@ static int __devinit plat_nand_probe(struct platform_device *pdev)
return -ENOMEM;
}
- data->io_base = ioremap(pdev->resource[0].start,
- pdev->resource[0].end - pdev->resource[0].start + 1);
+ if (!request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev))) {
+ dev_err(&pdev->dev, "request_mem_region failed\n");
+ err = -EBUSY;
+ goto out_free;
+ }
+
+ data->io_base = ioremap(res->start, resource_size(res));
if (data->io_base == NULL) {
dev_err(&pdev->dev, "ioremap failed\n");
- kfree(data);
- return -EIO;
+ err = -EIO;
+ goto out_release_io;
}
data->chip.priv = &data;
@@ -74,24 +85,24 @@ static int __devinit plat_nand_probe(struct platform_device *pdev)
/* Handle any platform specific setup */
if (pdata->ctrl.probe) {
- res = pdata->ctrl.probe(pdev);
- if (res)
+ err = pdata->ctrl.probe(pdev);
+ if (err)
goto out;
}
/* Scan to find existance of the device */
if (nand_scan(&data->mtd, 1)) {
- res = -ENXIO;
+ err = -ENXIO;
goto out;
}
#ifdef CONFIG_MTD_PARTITIONS
if (pdata->chip.part_probe_types) {
- res = parse_mtd_partitions(&data->mtd,
+ err = parse_mtd_partitions(&data->mtd,
pdata->chip.part_probe_types,
&data->parts, 0);
- if (res > 0) {
- add_mtd_partitions(&data->mtd, data->parts, res);
+ if (err > 0) {
+ add_mtd_partitions(&data->mtd, data->parts, err);
return 0;
}
}
@@ -99,14 +110,14 @@ static int __devinit plat_nand_probe(struct platform_device *pdev)
pdata->chip.set_parts(data->mtd.size, &pdata->chip);
if (pdata->chip.partitions) {
data->parts = pdata->chip.partitions;
- res = add_mtd_partitions(&data->mtd, data->parts,
+ err = add_mtd_partitions(&data->mtd, data->parts,
pdata->chip.nr_partitions);
} else
#endif
- res = add_mtd_device(&data->mtd);
+ err = add_mtd_device(&data->mtd);
- if (!res)
- return res;
+ if (!err)
+ return err;
nand_release(&data->mtd);
out:
@@ -114,8 +125,11 @@ out:
pdata->ctrl.remove(pdev);
platform_set_drvdata(pdev, NULL);
iounmap(data->io_base);
+out_release_io:
+ release_mem_region(res->start, resource_size(res));
+out_free:
kfree(data);
- return res;
+ return err;
}
/*
@@ -125,6 +139,9 @@ static int __devexit plat_nand_remove(struct platform_device *pdev)
{
struct plat_nand_data *data = platform_get_drvdata(pdev);
struct platform_nand_data *pdata = pdev->dev.platform_data;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nand_release(&data->mtd);
#ifdef CONFIG_MTD_PARTITIONS
@@ -134,6 +151,7 @@ static int __devexit plat_nand_remove(struct platform_device *pdev)
if (pdata->ctrl.remove)
pdata->ctrl.remove(pdev);
iounmap(data->io_base);
+ release_mem_region(res->start, resource_size(res));
kfree(data);
return 0;
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index 6ea520ae2410..1a5a0365c983 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -9,6 +9,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
@@ -22,7 +23,7 @@
#include <linux/irq.h>
#include <mach/dma.h>
-#include <mach/pxa3xx_nand.h>
+#include <plat/pxa3xx_nand.h>
#define CHIP_DELAY_TIMEOUT (2 * HZ/10)
@@ -84,10 +85,6 @@
#define NDCB0_CMD1_MASK (0xff)
#define NDCB0_ADDR_CYC_SHIFT (16)
-/* dma-able I/O address for the NAND data and commands */
-#define NDCB0_DMA_ADDR (0x43100048)
-#define NDDB_DMA_ADDR (0x43100040)
-
/* macros for registers read/write */
#define nand_writel(info, off, val) \
__raw_writel((val), (info)->mmio_base + (off))
@@ -123,6 +120,7 @@ struct pxa3xx_nand_info {
struct clk *clk;
void __iomem *mmio_base;
+ unsigned long mmio_phys;
unsigned int buf_start;
unsigned int buf_count;
@@ -228,13 +226,35 @@ static struct pxa3xx_nand_flash samsung512MbX16 = {
.chip_id = 0x46ec,
};
+static struct pxa3xx_nand_flash samsung2GbX8 = {
+ .timing = &samsung512MbX16_timing,
+ .cmdset = &smallpage_cmdset,
+ .page_per_block = 64,
+ .page_size = 2048,
+ .flash_width = 8,
+ .dfc_width = 8,
+ .num_blocks = 2048,
+ .chip_id = 0xdaec,
+};
+
+static struct pxa3xx_nand_flash samsung32GbX8 = {
+ .timing = &samsung512MbX16_timing,
+ .cmdset = &smallpage_cmdset,
+ .page_per_block = 128,
+ .page_size = 4096,
+ .flash_width = 8,
+ .dfc_width = 8,
+ .num_blocks = 8192,
+ .chip_id = 0xd7ec,
+};
+
static struct pxa3xx_nand_timing micron_timing = {
.tCH = 10,
.tCS = 25,
.tWH = 15,
.tWP = 25,
.tRH = 15,
- .tRP = 25,
+ .tRP = 30,
.tR = 25000,
.tWHR = 60,
.tAR = 10,
@@ -262,6 +282,28 @@ static struct pxa3xx_nand_flash micron1GbX16 = {
.chip_id = 0xb12c,
};
+static struct pxa3xx_nand_flash micron4GbX8 = {
+ .timing = &micron_timing,
+ .cmdset = &largepage_cmdset,
+ .page_per_block = 64,
+ .page_size = 2048,
+ .flash_width = 8,
+ .dfc_width = 8,
+ .num_blocks = 4096,
+ .chip_id = 0xdc2c,
+};
+
+static struct pxa3xx_nand_flash micron4GbX16 = {
+ .timing = &micron_timing,
+ .cmdset = &largepage_cmdset,
+ .page_per_block = 64,
+ .page_size = 2048,
+ .flash_width = 16,
+ .dfc_width = 16,
+ .num_blocks = 4096,
+ .chip_id = 0xcc2c,
+};
+
static struct pxa3xx_nand_timing stm2GbX16_timing = {
.tCH = 10,
.tCS = 35,
@@ -287,8 +329,12 @@ static struct pxa3xx_nand_flash stm2GbX16 = {
static struct pxa3xx_nand_flash *builtin_flash_types[] = {
&samsung512MbX16,
+ &samsung2GbX8,
+ &samsung32GbX8,
&micron1GbX8,
&micron1GbX16,
+ &micron4GbX8,
+ &micron4GbX16,
&stm2GbX16,
};
#endif /* CONFIG_MTD_NAND_PXA3xx_BUILTIN */
@@ -489,7 +535,7 @@ static int handle_data_pio(struct pxa3xx_nand_info *info)
switch (info->state) {
case STATE_PIO_WRITING:
__raw_writesl(info->mmio_base + NDDB, info->data_buff,
- info->data_size << 2);
+ DIV_ROUND_UP(info->data_size, 4));
enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);
@@ -501,7 +547,7 @@ static int handle_data_pio(struct pxa3xx_nand_info *info)
break;
case STATE_PIO_READING:
__raw_readsl(info->mmio_base + NDDB, info->data_buff,
- info->data_size << 2);
+ DIV_ROUND_UP(info->data_size, 4));
break;
default:
printk(KERN_ERR "%s: invalid state %d\n", __func__,
@@ -523,11 +569,11 @@ static void start_data_dma(struct pxa3xx_nand_info *info, int dir_out)
if (dir_out) {
desc->dsadr = info->data_buff_phys;
- desc->dtadr = NDDB_DMA_ADDR;
+ desc->dtadr = info->mmio_phys + NDDB;
desc->dcmd |= DCMD_INCSRCADDR | DCMD_FLOWTRG;
} else {
desc->dtadr = info->data_buff_phys;
- desc->dsadr = NDDB_DMA_ADDR;
+ desc->dsadr = info->mmio_phys + NDDB;
desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC;
}
@@ -669,6 +715,7 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
/* disable HW ECC to get all the OOB data */
info->buf_count = mtd->writesize + mtd->oobsize;
info->buf_start = mtd->writesize + column;
+ memset(info->data_buff, 0xFF, info->buf_count);
if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr))
break;
@@ -1239,13 +1286,17 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
ret = -ENODEV;
goto fail_free_res;
}
+ info->mmio_phys = r->start;
ret = pxa3xx_nand_init_buff(info);
if (ret)
goto fail_free_io;
- ret = request_irq(IRQ_NAND, pxa3xx_nand_irq, IRQF_DISABLED,
- pdev->name, info);
+ /* initialize all interrupts to be disabled */
+ disable_int(info, NDSR_MASK);
+
+ ret = request_irq(irq, pxa3xx_nand_irq, IRQF_DISABLED,
+ pdev->name, info);
if (ret < 0) {
dev_err(&pdev->dev, "failed to request IRQ\n");
goto fail_free_buf;
@@ -1271,7 +1322,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
return add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts);
fail_free_irq:
- free_irq(IRQ_NAND, info);
+ free_irq(irq, info);
fail_free_buf:
if (use_dma) {
pxa_free_dma(info->data_dma_ch);
@@ -1296,12 +1347,15 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
struct mtd_info *mtd = platform_get_drvdata(pdev);
struct pxa3xx_nand_info *info = mtd->priv;
struct resource *r;
+ int irq;
platform_set_drvdata(pdev, NULL);
del_mtd_device(mtd);
del_mtd_partitions(mtd);
- free_irq(IRQ_NAND, info);
+ irq = platform_get_irq(pdev, 0);
+ if (irq >= 0)
+ free_irq(irq, info);
if (use_dma) {
pxa_free_dma(info->data_dma_ch);
dma_free_writecombine(&pdev->dev, info->data_buff_size,
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
index a38f580c2bb3..3a9f15784600 100644
--- a/drivers/mtd/onenand/Kconfig
+++ b/drivers/mtd/onenand/Kconfig
@@ -1,7 +1,3 @@
-#
-# linux/drivers/mtd/onenand/Kconfig
-#
-
menuconfig MTD_ONENAND
tristate "OneNAND Device Support"
depends on MTD
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index 0108ed42e877..86c4f6dcdc65 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -36,13 +36,13 @@
#include <linux/io.h>
#include <asm/mach/flash.h>
-#include <mach/gpmc.h>
-#include <mach/onenand.h>
+#include <plat/gpmc.h>
+#include <plat/onenand.h>
#include <mach/gpio.h>
-#include <mach/dma.h>
+#include <plat/dma.h>
-#include <mach/board.h>
+#include <plat/board.h>
#define DRIVER_NAME "omap2-onenand"
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index ff66e4330aa7..6e250f3a4a16 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -500,25 +500,28 @@ static int onenand_wait(struct mtd_info *mtd, int state)
int ecc = onenand_read_ecc(this);
if (ecc) {
if (ecc & ONENAND_ECC_2BIT_ALL) {
- printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc);
+ printk(KERN_ERR "%s: ECC error = 0x%04x\n",
+ __func__, ecc);
mtd->ecc_stats.failed++;
return -EBADMSG;
} else if (ecc & ONENAND_ECC_1BIT_ALL) {
- printk(KERN_DEBUG "onenand_wait: correctable ECC error = 0x%04x\n", ecc);
+ printk(KERN_DEBUG "%s: correctable ECC error = 0x%04x\n",
+ __func__, ecc);
mtd->ecc_stats.corrected++;
}
}
} else if (state == FL_READING) {
- printk(KERN_ERR "onenand_wait: read timeout! ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
+ printk(KERN_ERR "%s: read timeout! ctrl=0x%04x intr=0x%04x\n",
+ __func__, ctrl, interrupt);
return -EIO;
}
/* If there's controller error, it's a real error */
if (ctrl & ONENAND_CTRL_ERROR) {
- printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n",
- ctrl);
+ printk(KERN_ERR "%s: controller error = 0x%04x\n",
+ __func__, ctrl);
if (ctrl & ONENAND_CTRL_LOCK)
- printk(KERN_ERR "onenand_wait: it's locked error.\n");
+ printk(KERN_ERR "%s: it's locked error.\n", __func__);
return -EIO;
}
@@ -1015,7 +1018,8 @@ static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status)
/* We are attempting to reread, so decrement stats.failed
* which was incremented by onenand_wait due to read failure
*/
- printk(KERN_INFO "onenand_recover_lsb: Attempting to recover from uncorrectable read\n");
+ printk(KERN_INFO "%s: Attempting to recover from uncorrectable read\n",
+ __func__);
mtd->ecc_stats.failed--;
/* Issue the LSB page recovery command */
@@ -1046,7 +1050,8 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,
int ret = 0;
int writesize = this->writesize;
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_mlc_read_ops_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+ DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n",
+ __func__, (unsigned int) from, (int) len);
if (ops->mode == MTD_OOB_AUTO)
oobsize = this->ecclayout->oobavail;
@@ -1057,7 +1062,8 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,
/* Do not allow reads past end of device */
if (from + len > mtd->size) {
- printk(KERN_ERR "onenand_mlc_read_ops_nolock: Attempt read beyond end of device\n");
+ printk(KERN_ERR "%s: Attempt read beyond end of device\n",
+ __func__);
ops->retlen = 0;
ops->oobretlen = 0;
return -EINVAL;
@@ -1146,7 +1152,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
int ret = 0, boundary = 0;
int writesize = this->writesize;
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+ DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n",
+ __func__, (unsigned int) from, (int) len);
if (ops->mode == MTD_OOB_AUTO)
oobsize = this->ecclayout->oobavail;
@@ -1157,7 +1164,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
/* Do not allow reads past end of device */
if ((from + len) > mtd->size) {
- printk(KERN_ERR "onenand_read_ops_nolock: Attempt read beyond end of device\n");
+ printk(KERN_ERR "%s: Attempt read beyond end of device\n",
+ __func__);
ops->retlen = 0;
ops->oobretlen = 0;
return -EINVAL;
@@ -1275,7 +1283,8 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
from += ops->ooboffs;
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+ DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n",
+ __func__, (unsigned int) from, (int) len);
/* Initialize return length value */
ops->oobretlen = 0;
@@ -1288,7 +1297,8 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
column = from & (mtd->oobsize - 1);
if (unlikely(column >= oobsize)) {
- printk(KERN_ERR "onenand_read_oob_nolock: Attempted to start read outside oob\n");
+ printk(KERN_ERR "%s: Attempted to start read outside oob\n",
+ __func__);
return -EINVAL;
}
@@ -1296,7 +1306,8 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
if (unlikely(from >= mtd->size ||
column + len > ((mtd->size >> this->page_shift) -
(from >> this->page_shift)) * oobsize)) {
- printk(KERN_ERR "onenand_read_oob_nolock: Attempted to read beyond end of device\n");
+ printk(KERN_ERR "%s: Attempted to read beyond end of device\n",
+ __func__);
return -EINVAL;
}
@@ -1319,7 +1330,8 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
ret = onenand_recover_lsb(mtd, from, ret);
if (ret && ret != -EBADMSG) {
- printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret);
+ printk(KERN_ERR "%s: read failed = 0x%x\n",
+ __func__, ret);
break;
}
@@ -1450,20 +1462,21 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state)
if (interrupt & ONENAND_INT_READ) {
int ecc = onenand_read_ecc(this);
if (ecc & ONENAND_ECC_2BIT_ALL) {
- printk(KERN_INFO "onenand_bbt_wait: ecc error = 0x%04x"
- ", controller error 0x%04x\n", ecc, ctrl);
+ printk(KERN_WARNING "%s: ecc error = 0x%04x, "
+ "controller error 0x%04x\n",
+ __func__, ecc, ctrl);
return ONENAND_BBT_READ_ECC_ERROR;
}
} else {
- printk(KERN_ERR "onenand_bbt_wait: read timeout!"
- "ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
+ printk(KERN_ERR "%s: read timeout! ctrl=0x%04x intr=0x%04x\n",
+ __func__, ctrl, interrupt);
return ONENAND_BBT_READ_FATAL_ERROR;
}
/* Initial bad block case: 0x2400 or 0x0400 */
if (ctrl & ONENAND_CTRL_ERROR) {
- printk(KERN_DEBUG "onenand_bbt_wait: "
- "controller error = 0x%04x\n", ctrl);
+ printk(KERN_DEBUG "%s: controller error = 0x%04x\n",
+ __func__, ctrl);
return ONENAND_BBT_READ_ERROR;
}
@@ -1487,14 +1500,16 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
size_t len = ops->ooblen;
u_char *buf = ops->oobbuf;
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_bbt_read_oob: from = 0x%08x, len = %zi\n", (unsigned int) from, len);
+ DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %zi\n",
+ __func__, (unsigned int) from, len);
/* Initialize return value */
ops->oobretlen = 0;
/* Do not allow reads past end of device */
if (unlikely((from + len) > mtd->size)) {
- printk(KERN_ERR "onenand_bbt_read_oob: Attempt read beyond end of device\n");
+ printk(KERN_ERR "%s: Attempt read beyond end of device\n",
+ __func__);
return ONENAND_BBT_READ_FATAL_ERROR;
}
@@ -1661,21 +1676,23 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
/* Wait for any existing operation to clear */
onenand_panic_wait(mtd);
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_panic_write: to = 0x%08x, len = %i\n",
- (unsigned int) to, (int) len);
+ DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n",
+ __func__, (unsigned int) to, (int) len);
/* Initialize retlen, in case of early exit */
*retlen = 0;
/* Do not allow writes past end of device */
if (unlikely((to + len) > mtd->size)) {
- printk(KERN_ERR "onenand_panic_write: Attempt write to past end of device\n");
+ printk(KERN_ERR "%s: Attempt write to past end of device\n",
+ __func__);
return -EINVAL;
}
/* Reject writes, which are not page aligned */
if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
- printk(KERN_ERR "onenand_panic_write: Attempt to write not page aligned data\n");
+ printk(KERN_ERR "%s: Attempt to write not page aligned data\n",
+ __func__);
return -EINVAL;
}
@@ -1711,7 +1728,7 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
}
if (ret) {
- printk(KERN_ERR "onenand_panic_write: write failed %d\n", ret);
+ printk(KERN_ERR "%s: write failed %d\n", __func__, ret);
break;
}
@@ -1792,7 +1809,8 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
u_char *oobbuf;
int ret = 0;
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
+ DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n",
+ __func__, (unsigned int) to, (int) len);
/* Initialize retlen, in case of early exit */
ops->retlen = 0;
@@ -1800,13 +1818,15 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
/* Do not allow writes past end of device */
if (unlikely((to + len) > mtd->size)) {
- printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n");
+ printk(KERN_ERR "%s: Attempt write to past end of device\n",
+ __func__);
return -EINVAL;
}
/* Reject writes, which are not page aligned */
if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
- printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");
+ printk(KERN_ERR "%s: Attempt to write not page aligned data\n",
+ __func__);
return -EINVAL;
}
@@ -1879,7 +1899,8 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
onenand_update_bufferram(mtd, prev, !ret && !prev_subpage);
if (ret) {
written -= prevlen;
- printk(KERN_ERR "onenand_write_ops_nolock: write failed %d\n", ret);
+ printk(KERN_ERR "%s: write failed %d\n",
+ __func__, ret);
break;
}
@@ -1887,7 +1908,8 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
/* Only check verify write turn on */
ret = onenand_verify(mtd, buf - len, to - len, len);
if (ret)
- printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
+ printk(KERN_ERR "%s: verify failed %d\n",
+ __func__, ret);
break;
}
@@ -1905,14 +1927,16 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
/* In partial page write we don't update bufferram */
onenand_update_bufferram(mtd, to, !ret && !subpage);
if (ret) {
- printk(KERN_ERR "onenand_write_ops_nolock: write failed %d\n", ret);
+ printk(KERN_ERR "%s: write failed %d\n",
+ __func__, ret);
break;
}
/* Only check verify write turn on */
ret = onenand_verify(mtd, buf, to, thislen);
if (ret) {
- printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
+ printk(KERN_ERR "%s: verify failed %d\n",
+ __func__, ret);
break;
}
@@ -1968,7 +1992,8 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
to += ops->ooboffs;
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
+ DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n",
+ __func__, (unsigned int) to, (int) len);
/* Initialize retlen, in case of early exit */
ops->oobretlen = 0;
@@ -1981,14 +2006,15 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
column = to & (mtd->oobsize - 1);
if (unlikely(column >= oobsize)) {
- printk(KERN_ERR "onenand_write_oob_nolock: Attempted to start write outside oob\n");
+ printk(KERN_ERR "%s: Attempted to start write outside oob\n",
+ __func__);
return -EINVAL;
}
/* For compatibility with NAND: Do not allow write past end of page */
if (unlikely(column + len > oobsize)) {
- printk(KERN_ERR "onenand_write_oob_nolock: "
- "Attempt to write past end of page\n");
+ printk(KERN_ERR "%s: Attempt to write past end of page\n",
+ __func__);
return -EINVAL;
}
@@ -1996,7 +2022,8 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
if (unlikely(to >= mtd->size ||
column + len > ((mtd->size >> this->page_shift) -
(to >> this->page_shift)) * oobsize)) {
- printk(KERN_ERR "onenand_write_oob_nolock: Attempted to write past end of device\n");
+ printk(KERN_ERR "%s: Attempted to write past end of device\n",
+ __func__);
return -EINVAL;
}
@@ -2038,13 +2065,14 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
ret = this->wait(mtd, FL_WRITING);
if (ret) {
- printk(KERN_ERR "onenand_write_oob_nolock: write failed %d\n", ret);
+ printk(KERN_ERR "%s: write failed %d\n", __func__, ret);
break;
}
ret = onenand_verify_oob(mtd, oobbuf, to);
if (ret) {
- printk(KERN_ERR "onenand_write_oob_nolock: verify failed %d\n", ret);
+ printk(KERN_ERR "%s: verify failed %d\n",
+ __func__, ret);
break;
}
@@ -2161,7 +2189,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
/* Do not allow erase past end of device */
if (unlikely((len + addr) > mtd->size)) {
- printk(KERN_ERR "onenand_erase: Erase past end of device\n");
+ printk(KERN_ERR "%s: Erase past end of device\n", __func__);
return -EINVAL;
}
@@ -2177,7 +2205,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
* Erase region's start offset is always block start address.
*/
if (unlikely((addr - region->offset) & (block_size - 1))) {
- printk(KERN_ERR "onenand_erase: Unaligned address\n");
+ printk(KERN_ERR "%s: Unaligned address\n", __func__);
return -EINVAL;
}
} else {
@@ -2185,14 +2213,14 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
/* Start address must align on block boundary */
if (unlikely(addr & (block_size - 1))) {
- printk(KERN_ERR "onenand_erase: Unaligned address\n");
+ printk(KERN_ERR "%s: Unaligned address\n", __func__);
return -EINVAL;
}
}
/* Length must align on block boundary */
if (unlikely(len & (block_size - 1))) {
- printk(KERN_ERR "onenand_erase: Length not block aligned\n");
+ printk(KERN_ERR "%s: Length not block aligned\n", __func__);
return -EINVAL;
}
@@ -2209,7 +2237,9 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
/* Check if we have a bad block, we do not erase bad blocks */
if (onenand_block_isbad_nolock(mtd, addr, 0)) {
- printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%012llx\n", (unsigned long long) addr);
+ printk(KERN_WARNING "%s: attempt to erase a bad block "
+ "at addr 0x%012llx\n",
+ __func__, (unsigned long long) addr);
instr->state = MTD_ERASE_FAILED;
goto erase_exit;
}
@@ -2221,8 +2251,8 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
ret = this->wait(mtd, FL_ERASING);
/* Check, if it is write protected */
if (ret) {
- printk(KERN_ERR "onenand_erase: Failed erase, block %d\n",
- onenand_block(this, addr));
+ printk(KERN_ERR "%s: Failed erase, block %d\n",
+ __func__, onenand_block(this, addr));
instr->state = MTD_ERASE_FAILED;
instr->fail_addr = addr;
goto erase_exit;
@@ -2241,7 +2271,8 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
if (len & (block_size - 1)) {
/* FIXME: This should be handled at MTD partitioning level. */
- printk(KERN_ERR "onenand_erase: Unaligned address\n");
+ printk(KERN_ERR "%s: Unaligned address\n",
+ __func__);
goto erase_exit;
}
}
@@ -2272,7 +2303,7 @@ erase_exit:
*/
static void onenand_sync(struct mtd_info *mtd)
{
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_sync: called\n");
+ DEBUG(MTD_DEBUG_LEVEL3, "%s: called\n", __func__);
/* Grab the lock and see if the device is available */
onenand_get_device(mtd, FL_SYNCING);
@@ -2406,7 +2437,8 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int
/* Check lock status */
status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
if (!(status & wp_status_mask))
- printk(KERN_ERR "wp status = 0x%x\n", status);
+ printk(KERN_ERR "%s: wp status = 0x%x\n",
+ __func__, status);
return 0;
}
@@ -2435,7 +2467,8 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int
/* Check lock status */
status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
if (!(status & wp_status_mask))
- printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status);
+ printk(KERN_ERR "%s: block = %d, wp status = 0x%x\n",
+ __func__, block, status);
}
return 0;
@@ -2502,7 +2535,8 @@ static int onenand_check_lock_status(struct onenand_chip *this)
/* Check lock status */
status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
if (!(status & ONENAND_WP_US)) {
- printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status);
+ printk(KERN_ERR "%s: block = %d, wp status = 0x%x\n",
+ __func__, block, status);
return 0;
}
}
@@ -3172,7 +3206,8 @@ static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int
break;
if (i != mtd->oobsize) {
- printk(KERN_WARNING "Block %d not erased.\n", block);
+ printk(KERN_WARNING "%s: Block %d not erased.\n",
+ __func__, block);
return 1;
}
}
@@ -3204,8 +3239,8 @@ int flexonenand_set_boundary(struct mtd_info *mtd, int die,
blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0;
if (boundary >= blksperdie) {
- printk(KERN_ERR "flexonenand_set_boundary: Invalid boundary value. "
- "Boundary not changed.\n");
+ printk(KERN_ERR "%s: Invalid boundary value. "
+ "Boundary not changed.\n", __func__);
return -EINVAL;
}
@@ -3214,7 +3249,8 @@ int flexonenand_set_boundary(struct mtd_info *mtd, int die,
new = boundary + (die * this->density_mask);
ret = flexonenand_check_blocks_erased(mtd, min(old, new) + 1, max(old, new));
if (ret) {
- printk(KERN_ERR "flexonenand_set_boundary: Please erase blocks before boundary change\n");
+ printk(KERN_ERR "%s: Please erase blocks "
+ "before boundary change\n", __func__);
return ret;
}
@@ -3227,12 +3263,12 @@ int flexonenand_set_boundary(struct mtd_info *mtd, int die,
thisboundary = this->read_word(this->base + ONENAND_DATARAM);
if ((thisboundary >> FLEXONENAND_PI_UNLOCK_SHIFT) != 3) {
- printk(KERN_ERR "flexonenand_set_boundary: boundary locked\n");
+ printk(KERN_ERR "%s: boundary locked\n", __func__);
ret = 1;
goto out;
}
- printk(KERN_INFO "flexonenand_set_boundary: Changing die %d boundary: %d%s\n",
+ printk(KERN_INFO "Changing die %d boundary: %d%s\n",
die, boundary, lock ? "(Locked)" : "(Unlocked)");
addr = die ? this->diesize[0] : 0;
@@ -3243,7 +3279,8 @@ int flexonenand_set_boundary(struct mtd_info *mtd, int die,
this->command(mtd, ONENAND_CMD_ERASE, addr, 0);
ret = this->wait(mtd, FL_ERASING);
if (ret) {
- printk(KERN_ERR "flexonenand_set_boundary: Failed PI erase for Die %d\n", die);
+ printk(KERN_ERR "%s: flexonenand_set_boundary: "
+ "Failed PI erase for Die %d\n", __func__, die);
goto out;
}
@@ -3251,7 +3288,8 @@ int flexonenand_set_boundary(struct mtd_info *mtd, int die,
this->command(mtd, ONENAND_CMD_PROG, addr, 0);
ret = this->wait(mtd, FL_WRITING);
if (ret) {
- printk(KERN_ERR "flexonenand_set_boundary: Failed PI write for Die %d\n", die);
+ printk(KERN_ERR "%s: Failed PI write for Die %d\n",
+ __func__, die);
goto out;
}
@@ -3408,8 +3446,8 @@ static void onenand_resume(struct mtd_info *mtd)
if (this->state == FL_PM_SUSPENDED)
onenand_release_device(mtd);
else
- printk(KERN_ERR "resume() called for the chip which is not"
- "in suspended state\n");
+ printk(KERN_ERR "%s: resume() called for the chip which is not "
+ "in suspended state\n", __func__);
}
/**
@@ -3464,7 +3502,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
if (!this->page_buf) {
this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL);
if (!this->page_buf) {
- printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n");
+ printk(KERN_ERR "%s: Can't allocate page_buf\n",
+ __func__);
return -ENOMEM;
}
this->options |= ONENAND_PAGEBUF_ALLOC;
@@ -3472,7 +3511,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
if (!this->oob_buf) {
this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
if (!this->oob_buf) {
- printk(KERN_ERR "onenand_scan(): Can't allocate oob_buf\n");
+ printk(KERN_ERR "%s: Can't allocate oob_buf\n",
+ __func__);
if (this->options & ONENAND_PAGEBUF_ALLOC) {
this->options &= ~ONENAND_PAGEBUF_ALLOC;
kfree(this->page_buf);
@@ -3505,8 +3545,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
break;
default:
- printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n",
- mtd->oobsize);
+ printk(KERN_WARNING "%s: No OOB scheme defined for oobsize %d\n",
+ __func__, mtd->oobsize);
mtd->subpage_sft = 0;
/* To prevent kernel oops */
this->ecclayout = &onenand_oob_32;
diff --git a/drivers/mtd/tests/mtd_oobtest.c b/drivers/mtd/tests/mtd_oobtest.c
index 5553cd4eab20..5813920e79a5 100644
--- a/drivers/mtd/tests/mtd_oobtest.c
+++ b/drivers/mtd/tests/mtd_oobtest.c
@@ -343,7 +343,6 @@ static int scan_for_bad_eraseblocks(void)
printk(PRINT_PREF "error: cannot allocate memory\n");
return -ENOMEM;
}
- memset(bbt, 0 , ebcnt);
printk(PRINT_PREF "scanning for bad eraseblocks\n");
for (i = 0; i < ebcnt; ++i) {
@@ -392,7 +391,6 @@ static int __init mtd_oobtest_init(void)
mtd->writesize, ebcnt, pgcnt, mtd->oobsize);
err = -ENOMEM;
- mtd->erasesize = mtd->erasesize;
readbuf = kmalloc(mtd->erasesize, GFP_KERNEL);
if (!readbuf) {
printk(PRINT_PREF "error: cannot allocate memory\n");
@@ -476,18 +474,10 @@ static int __init mtd_oobtest_init(void)
use_len_max = mtd->ecclayout->oobavail;
vary_offset = 1;
simple_srand(5);
- printk(PRINT_PREF "writing OOBs of whole device\n");
- for (i = 0; i < ebcnt; ++i) {
- if (bbt[i])
- continue;
- err = write_eraseblock(i);
- if (err)
- goto out;
- if (i % 256 == 0)
- printk(PRINT_PREF "written up to eraseblock %u\n", i);
- cond_resched();
- }
- printk(PRINT_PREF "written %u eraseblocks\n", i);
+
+ err = write_whole_device();
+ if (err)
+ goto out;
/* Check all eraseblocks */
use_offset = 0;
diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
index b1cd7a1a2191..0a8c7ea764ae 100644
--- a/drivers/mtd/ubi/Kconfig
+++ b/drivers/mtd/ubi/Kconfig
@@ -1,5 +1,3 @@
-# drivers/mtd/ubi/Kconfig
-
menu "UBI - Unsorted block images"
depends on MTD
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index e1f7d0a78b9d..14cec04c34f9 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -42,6 +42,7 @@
#include <linux/log2.h>
#include <linux/kthread.h>
#include <linux/reboot.h>
+#include <linux/kernel.h>
#include "ubi.h"
/* Maximum length of the 'mtd=' parameter */
@@ -1257,7 +1258,7 @@ static int __init bytes_str_to_int(const char *str)
unsigned long result;
result = simple_strtoul(str, &endp, 0);
- if (str == endp || result < 0) {
+ if (str == endp || result >= INT_MAX) {
printk(KERN_ERR "UBI error: incorrect bytes count: \"%s\"\n",
str);
return -EINVAL;
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index 88a72e9c8beb..277786ebaa2c 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -22,6 +22,8 @@
#include <linux/module.h>
#include <linux/err.h>
+#include <linux/namei.h>
+#include <linux/fs.h>
#include <asm/div64.h>
#include "ubi.h"
@@ -280,6 +282,44 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
/**
+ * ubi_open_volume_path - open UBI volume by its character device node path.
+ * @pathname: volume character device node path
+ * @mode: open mode
+ *
+ * This function is similar to 'ubi_open_volume()', but opens a volume the path
+ * to its character device node.
+ */
+struct ubi_volume_desc *ubi_open_volume_path(const char *pathname, int mode)
+{
+ int error, ubi_num, vol_id;
+ struct ubi_volume_desc *ret;
+ struct inode *inode;
+ struct path path;
+
+ dbg_gen("open volume %s, mode %d", pathname, mode);
+
+ if (!pathname || !*pathname)
+ return ERR_PTR(-EINVAL);
+
+ error = kern_path(pathname, LOOKUP_FOLLOW, &path);
+ if (error)
+ return ERR_PTR(error);
+
+ inode = path.dentry->d_inode;
+ ubi_num = ubi_major2num(imajor(inode));
+ vol_id = iminor(inode) - 1;
+
+ if (vol_id >= 0 && ubi_num >= 0)
+ ret = ubi_open_volume(ubi_num, vol_id, mode);
+ else
+ ret = ERR_PTR(-ENODEV);
+
+ path_put(&path);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ubi_open_volume_path);
+
+/**
* ubi_close_volume - close UBI volume.
* @desc: volume descriptor
*/
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index e7161adc419d..90af61a2c3e4 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -794,16 +794,15 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
* number.
*/
image_seq = be32_to_cpu(ech->image_seq);
- if (!si->image_seq_set) {
+ if (!ubi->image_seq && image_seq)
ubi->image_seq = image_seq;
- si->image_seq_set = 1;
- } else if (ubi->image_seq && ubi->image_seq != image_seq) {
+ if (ubi->image_seq && image_seq &&
+ ubi->image_seq != image_seq) {
ubi_err("bad image sequence number %d in PEB %d, "
"expected %d", image_seq, pnum, ubi->image_seq);
ubi_dbg_dump_ec_hdr(ech);
return -EINVAL;
}
-
}
/* OK, we've done with the EC header, let's look at the VID header */
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h
index bab31695dace..ff179ad7ca55 100644
--- a/drivers/mtd/ubi/scan.h
+++ b/drivers/mtd/ubi/scan.h
@@ -103,7 +103,6 @@ struct ubi_scan_volume {
* @ec_sum: a temporary variable used when calculating @mean_ec
* @ec_count: a temporary variable used when calculating @mean_ec
* @corr_count: count of corrupted PEBs
- * @image_seq_set: indicates @ubi->image_seq is known
*
* This data structure contains the result of scanning and may be used by other
* UBI sub-systems to build final UBI data structures, further error-recovery
@@ -127,7 +126,6 @@ struct ubi_scan_info {
uint64_t ec_sum;
int ec_count;
int corr_count;
- int image_seq_set;
};
struct ubi_device;
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 975e25b19ebe..32031eaf4910 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -2560,7 +2560,7 @@ boomerang_rx(struct net_device *dev)
struct sk_buff *skb;
entry = vp->dirty_rx % RX_RING_SIZE;
if (vp->rx_skbuff[entry] == NULL) {
- skb = netdev_alloc_skb(dev, PKT_BUF_SZ + NET_IP_ALIGN);
+ skb = netdev_alloc_skb_ip_align(dev, PKT_BUF_SZ);
if (skb == NULL) {
static unsigned long last_jif;
if (time_after(jiffies, last_jif + 10 * HZ)) {
@@ -2572,7 +2572,6 @@ boomerang_rx(struct net_device *dev)
break; /* Bad news! */
}
- skb_reserve(skb, NET_IP_ALIGN);
vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
vp->rx_skbuff[entry] = skb;
}
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 83a1922e68e0..ab451bb8995a 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -549,14 +549,12 @@ rx_status_loop:
pr_debug("%s: rx slot %d status 0x%x len %d\n",
dev->name, rx_tail, status, len);
- new_skb = netdev_alloc_skb(dev, buflen + NET_IP_ALIGN);
+ new_skb = netdev_alloc_skb_ip_align(dev, buflen);
if (!new_skb) {
dev->stats.rx_dropped++;
goto rx_next;
}
- skb_reserve(new_skb, NET_IP_ALIGN);
-
dma_unmap_single(&cp->pdev->dev, mapping,
buflen, PCI_DMA_FROMDEVICE);
@@ -1057,12 +1055,10 @@ static int cp_refill_rx(struct cp_private *cp)
struct sk_buff *skb;
dma_addr_t mapping;
- skb = netdev_alloc_skb(dev, cp->rx_buf_sz + NET_IP_ALIGN);
+ skb = netdev_alloc_skb_ip_align(dev, cp->rx_buf_sz);
if (!skb)
goto err_out;
- skb_reserve(skb, NET_IP_ALIGN);
-
mapping = dma_map_single(&cp->pdev->dev, skb->data,
cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
cp->rx_skb[i] = skb;
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 4a3628755026..7e333f73b228 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -2004,9 +2004,8 @@ no_early_rx:
/* Malloc up new buffer, compatible with net-2e. */
/* Omit the four octet CRC from the length. */
- skb = netdev_alloc_skb(dev, pkt_size + NET_IP_ALIGN);
+ skb = netdev_alloc_skb_ip_align(dev, pkt_size);
if (likely(skb)) {
- skb_reserve (skb, NET_IP_ALIGN); /* 16 byte align the IP fields. */
#if RX_BUF_IDX == 3
wrap_copy(skb, rx_ring, ring_offset+4, pkt_size);
#else
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index e19ca4bb7510..5f961293083d 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1001,7 +1001,7 @@ config SMC911X
config SMSC911X
tristate "SMSC LAN911x/LAN921x families embedded ethernet support"
- depends on ARM || SUPERH || BLACKFIN
+ depends on ARM || SUPERH || BLACKFIN || MIPS
select CRC32
select MII
select PHYLIB
@@ -3241,4 +3241,18 @@ config VMXNET3
To compile this driver as a module, choose M here: the
module will be called vmxnet3.
+config VBUS_ENET
+ tristate "VBUS Ethernet Driver"
+ default n
+ depends on VBUS_PROXY
+ help
+ A virtualized 802.x network device based on the VBUS
+ "virtual-ethernet" interface. It can be used with any
+ hypervisor/kernel that supports the vbus+venet protocol.
+
+config VBUS_ENET_DEBUG
+ bool "Enable Debugging"
+ depends on VBUS_ENET
+ default n
+
endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 246323d7f161..f3dabbcdac41 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -282,6 +282,7 @@ obj-$(CONFIG_FS_ENET) += fs_enet/
obj-$(CONFIG_NETXEN_NIC) += netxen/
obj-$(CONFIG_NIU) += niu.o
obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
+obj-$(CONFIG_VBUS_ENET) += vbus-enet.o
obj-$(CONFIG_SFC) += sfc/
obj-$(CONFIG_WIMAX) += wimax/
diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c
index 955da733c2ad..8b889ab544b0 100644
--- a/drivers/net/atl1e/atl1e_main.c
+++ b/drivers/net/atl1e/atl1e_main.c
@@ -1433,14 +1433,12 @@ static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que,
packet_size = ((prrs->word1 >> RRS_PKT_SIZE_SHIFT) &
RRS_PKT_SIZE_MASK) - 4; /* CRC */
- skb = netdev_alloc_skb(netdev,
- packet_size + NET_IP_ALIGN);
+ skb = netdev_alloc_skb_ip_align(netdev, packet_size);
if (skb == NULL) {
dev_warn(&pdev->dev, "%s: Memory squeeze,"
"deferring packet.\n", netdev->name);
goto skip_pkt;
}
- skb_reserve(skb, NET_IP_ALIGN);
skb->dev = netdev;
memcpy(skb->data, (u8 *)(prrs + 1), packet_size);
skb_put(skb, packet_size);
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
index 00569dc1313c..963df502260a 100644
--- a/drivers/net/atlx/atl1.c
+++ b/drivers/net/atlx/atl1.c
@@ -1864,21 +1864,14 @@ static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter)
rfd_desc = ATL1_RFD_DESC(rfd_ring, rfd_next_to_use);
- skb = netdev_alloc_skb(adapter->netdev,
- adapter->rx_buffer_len + NET_IP_ALIGN);
+ skb = netdev_alloc_skb_ip_align(adapter->netdev,
+ adapter->rx_buffer_len);
if (unlikely(!skb)) {
/* Better luck next round */
adapter->netdev->stats.rx_dropped++;
break;
}
- /*
- * Make buffer alignment 2 beyond a 16 byte boundary
- * this will result in a 16 byte aligned IP header after
- * the 14 byte MAC header is removed
- */
- skb_reserve(skb, NET_IP_ALIGN);
-
buffer_info->alloced = 1;
buffer_info->skb = skb;
buffer_info->length = (u16) adapter->rx_buffer_len;
diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c
index ab688862093f..0d268075bad5 100644
--- a/drivers/net/atlx/atl2.c
+++ b/drivers/net/atlx/atl2.c
@@ -409,7 +409,7 @@ static void atl2_intr_rx(struct atl2_adapter *adapter)
if (rxd->status.ok && rxd->status.pkt_size >= 60) {
int rx_size = (int)(rxd->status.pkt_size - 4);
/* alloc new buffer */
- skb = netdev_alloc_skb(netdev, rx_size + NET_IP_ALIGN);
+ skb = netdev_alloc_skb_ip_align(netdev, rx_size);
if (NULL == skb) {
printk(KERN_WARNING
"%s: Mem squeeze, deferring packet.\n",
@@ -421,7 +421,6 @@ static void atl2_intr_rx(struct atl2_adapter *adapter)
netdev->stats.rx_dropped++;
break;
}
- skb_reserve(skb, NET_IP_ALIGN);
skb->dev = netdev;
memcpy(skb->data, rxd->packet, rx_size);
skb_put(skb, rx_size);
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index 04f63c77071d..ce6f1ac25df8 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -34,6 +34,7 @@
*
*
*/
+#include <linux/capability.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c
index ba29dc319b34..1f6c5486d715 100644
--- a/drivers/net/bcm63xx_enet.c
+++ b/drivers/net/bcm63xx_enet.c
@@ -320,16 +320,13 @@ static int bcm_enet_receive_queue(struct net_device *dev, int budget)
if (len < copybreak) {
struct sk_buff *nskb;
- nskb = netdev_alloc_skb(dev, len + NET_IP_ALIGN);
+ nskb = netdev_alloc_skb_ip_align(dev, len);
if (!nskb) {
/* forget packet, just rearm desc */
priv->stats.rx_dropped++;
continue;
}
- /* since we're copying the data, we can align
- * them properly */
- skb_reserve(nskb, NET_IP_ALIGN);
dma_sync_single_for_cpu(kdev, desc->address,
len, DMA_FROM_DEVICE);
memcpy(nskb->data, skb->data, len);
diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h
index a80da0e14a52..ce7563175cef 100644
--- a/drivers/net/benet/be.h
+++ b/drivers/net/benet/be.h
@@ -35,20 +35,31 @@
#define DRV_VER "2.101.205"
#define DRV_NAME "be2net"
#define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC"
+#define BE3_NAME "ServerEngines BladeEngine3 10Gbps NIC"
#define OC_NAME "Emulex OneConnect 10Gbps NIC"
+#define OC_NAME1 "Emulex OneConnect 10Gbps NIC (be3)"
#define DRV_DESC BE_NAME "Driver"
#define BE_VENDOR_ID 0x19a2
#define BE_DEVICE_ID1 0x211
+#define BE_DEVICE_ID2 0x221
#define OC_DEVICE_ID1 0x700
#define OC_DEVICE_ID2 0x701
+#define OC_DEVICE_ID3 0x710
static inline char *nic_name(struct pci_dev *pdev)
{
- if (pdev->device == OC_DEVICE_ID1 || pdev->device == OC_DEVICE_ID2)
+ switch (pdev->device) {
+ case OC_DEVICE_ID1:
+ case OC_DEVICE_ID2:
return OC_NAME;
- else
+ case OC_DEVICE_ID3:
+ return OC_NAME1;
+ case BE_DEVICE_ID2:
+ return BE3_NAME;
+ default:
return BE_NAME;
+ }
}
/* Number of bytes of an RX frame that are copied to skb->data */
@@ -181,7 +192,6 @@ struct be_drvr_stats {
struct be_stats_obj {
struct be_drvr_stats drvr_stats;
- struct net_device_stats net_stats;
struct be_dma_mem cmd;
};
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c
index 89876ade5e33..827d86b5e70b 100644
--- a/drivers/net/benet/be_cmds.c
+++ b/drivers/net/benet/be_cmds.c
@@ -243,15 +243,26 @@ static int be_POST_stage_get(struct be_adapter *adapter, u16 *stage)
int be_cmd_POST(struct be_adapter *adapter)
{
- u16 stage, error;
+ u16 stage;
+ int status, timeout = 0;
- error = be_POST_stage_get(adapter, &stage);
- if (error || stage != POST_STAGE_ARMFW_RDY) {
- dev_err(&adapter->pdev->dev, "POST failed.\n");
- return -1;
- }
+ do {
+ status = be_POST_stage_get(adapter, &stage);
+ if (status) {
+ dev_err(&adapter->pdev->dev, "POST error; stage=0x%x\n",
+ stage);
+ return -1;
+ } else if (stage != POST_STAGE_ARMFW_RDY) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(2 * HZ);
+ timeout += 2;
+ } else {
+ return 0;
+ }
+ } while (timeout < 20);
- return 0;
+ dev_err(&adapter->pdev->dev, "POST timeout; stage=0x%x\n", stage);
+ return -1;
}
static inline void *embedded_payload(struct be_mcc_wrb *wrb)
@@ -729,8 +740,8 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
/* Create an rx filtering policy configuration on an i/f
* Uses mbox
*/
-int be_cmd_if_create(struct be_adapter *adapter, u32 flags, u8 *mac,
- bool pmac_invalid, u32 *if_handle, u32 *pmac_id)
+int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags,
+ u8 *mac, bool pmac_invalid, u32 *if_handle, u32 *pmac_id)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_if_create *req;
@@ -746,8 +757,8 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 flags, u8 *mac,
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_NTWK_INTERFACE_CREATE, sizeof(*req));
- req->capability_flags = cpu_to_le32(flags);
- req->enable_flags = cpu_to_le32(flags);
+ req->capability_flags = cpu_to_le32(cap_flags);
+ req->enable_flags = cpu_to_le32(en_flags);
req->pmac_invalid = pmac_invalid;
if (!pmac_invalid)
memcpy(req->mac_addr, mac, ETH_ALEN);
@@ -1118,6 +1129,65 @@ int be_cmd_reset_function(struct be_adapter *adapter)
return status;
}
+/* Uses sync mcc */
+int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num,
+ u8 bcn, u8 sts, u8 state)
+{
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_enable_disable_beacon *req;
+ int status;
+
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
+ req = embedded_payload(wrb);
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_ENABLE_DISABLE_BEACON, sizeof(*req));
+
+ req->port_num = port_num;
+ req->beacon_state = state;
+ req->beacon_duration = bcn;
+ req->status_duration = sts;
+
+ status = be_mcc_notify_wait(adapter);
+
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+}
+
+/* Uses sync mcc */
+int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num, u32 *state)
+{
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_get_beacon_state *req;
+ int status;
+
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
+ req = embedded_payload(wrb);
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_GET_BEACON_STATE, sizeof(*req));
+
+ req->port_num = port_num;
+
+ status = be_mcc_notify_wait(adapter);
+ if (!status) {
+ struct be_cmd_resp_get_beacon_state *resp =
+ embedded_payload(wrb);
+ *state = resp->beacon_state;
+ }
+
+ 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 a86f917f85f4..fe9f535eff12 100644
--- a/drivers/net/benet/be_cmds.h
+++ b/drivers/net/benet/be_cmds.h
@@ -138,6 +138,8 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_NTWK_PMAC_ADD 59
#define OPCODE_COMMON_NTWK_PMAC_DEL 60
#define OPCODE_COMMON_FUNCTION_RESET 61
+#define OPCODE_COMMON_ENABLE_DISABLE_BEACON 69
+#define OPCODE_COMMON_GET_BEACON_STATE 70
#define OPCODE_ETH_ACPI_CONFIG 2
#define OPCODE_ETH_PROMISCUOUS 3
@@ -699,6 +701,37 @@ struct be_cmd_resp_query_fw_cfg {
u32 rsvd[26];
};
+/******************** Port Beacon ***************************/
+
+#define BEACON_STATE_ENABLED 0x1
+#define BEACON_STATE_DISABLED 0x0
+
+struct be_cmd_req_enable_disable_beacon {
+ struct be_cmd_req_hdr hdr;
+ u8 port_num;
+ u8 beacon_state;
+ u8 beacon_duration;
+ u8 status_duration;
+} __packed;
+
+struct be_cmd_resp_enable_disable_beacon {
+ struct be_cmd_resp_hdr resp_hdr;
+ u32 rsvd0;
+} __packed;
+
+struct be_cmd_req_get_beacon_state {
+ struct be_cmd_req_hdr hdr;
+ u8 port_num;
+ u8 rsvd0;
+ u16 rsvd1;
+} __packed;
+
+struct be_cmd_resp_get_beacon_state {
+ struct be_cmd_resp_hdr resp_hdr;
+ u8 beacon_state;
+ u8 rsvd0[3];
+} __packed;
+
/****************** Firmware Flash ******************/
struct flashrom_params {
u32 op_code;
@@ -720,8 +753,9 @@ extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
extern int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr,
u32 if_id, u32 *pmac_id);
extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id);
-extern int be_cmd_if_create(struct be_adapter *adapter, u32 if_flags, u8 *mac,
- bool pmac_invalid, u32 *if_handle, u32 *pmac_id);
+extern int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags,
+ u32 en_flags, u8 *mac, bool pmac_invalid,
+ u32 *if_handle, u32 *pmac_id);
extern int be_cmd_if_destroy(struct be_adapter *adapter, u32 if_handle);
extern int be_cmd_eq_create(struct be_adapter *adapter,
struct be_queue_info *eq, int eq_delay);
@@ -764,6 +798,10 @@ extern int be_cmd_query_fw_cfg(struct be_adapter *adapter,
u32 *port_num, u32 *cap);
extern int be_cmd_reset_function(struct be_adapter *adapter);
extern int be_process_mcc(struct be_adapter *adapter);
+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_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 cda5bf2fc50a..280471e18695 100644
--- a/drivers/net/benet/be_ethtool.c
+++ b/drivers/net/benet/be_ethtool.c
@@ -234,7 +234,7 @@ be_get_ethtool_stats(struct net_device *netdev,
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 = &adapter->stats.net_stats;
+ struct net_device_stats *net_stats = &netdev->stats;
struct be_erx_stats *erx_stats = &hw_stats->erx;
void *p = NULL;
int i;
@@ -281,9 +281,14 @@ be_get_stat_strings(struct net_device *netdev, uint32_t stringset,
}
}
-static int be_get_stats_count(struct net_device *netdev)
+static int be_get_sset_count(struct net_device *netdev, int stringset)
{
- return ETHTOOL_STATS_NUM;
+ switch (stringset) {
+ case ETH_SS_STATS:
+ return ETHTOOL_STATS_NUM;
+ default:
+ return -EINVAL;
+ }
}
static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
@@ -333,6 +338,35 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
}
static int
+be_phys_id(struct net_device *netdev, u32 data)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+ int status;
+ u32 cur;
+
+ if (!netif_running(netdev))
+ return 0;
+
+ be_cmd_get_beacon_state(adapter, adapter->port_num, &cur);
+
+ if (cur == BEACON_STATE_ENABLED)
+ return 0;
+
+ if (data < 2)
+ data = 2;
+
+ status = be_cmd_set_beacon_state(adapter, adapter->port_num, 0, 0,
+ BEACON_STATE_ENABLED);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(data*HZ);
+
+ status = be_cmd_set_beacon_state(adapter, adapter->port_num, 0, 0,
+ BEACON_STATE_DISABLED);
+
+ return status;
+}
+
+static int
be_do_flash(struct net_device *netdev, struct ethtool_flash *efl)
{
struct be_adapter *adapter = netdev_priv(netdev);
@@ -364,7 +398,8 @@ const struct ethtool_ops be_ethtool_ops = {
.get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
.get_strings = be_get_stat_strings,
- .get_stats_count = be_get_stats_count,
+ .phys_id = be_phys_id,
+ .get_sset_count = be_get_sset_count,
.get_ethtool_stats = be_get_ethtool_stats,
.flash_device = be_do_flash,
};
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index 6d5e81f7046f..21b0657de9e8 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -141,7 +141,7 @@ void netdev_stats_update(struct be_adapter *adapter)
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->stats.net_stats;
+ struct net_device_stats *dev_stats = &adapter->netdev->stats;
struct be_erx_stats *erx_stats = &hw_stats->erx;
dev_stats->rx_packets = port_stats->rx_total_frames;
@@ -269,9 +269,7 @@ static void be_rx_eqd_update(struct be_adapter *adapter)
static struct net_device_stats *be_get_stats(struct net_device *dev)
{
- struct be_adapter *adapter = netdev_priv(dev);
-
- return &adapter->stats.net_stats;
+ return &dev->stats;
}
static u32 be_calc_rate(u64 bytes, unsigned long ticks)
@@ -758,7 +756,7 @@ static void be_rx_compl_process(struct be_adapter *adapter,
if ((adapter->cap == 0x400) && !vtm)
vlanf = 0;
- skb = netdev_alloc_skb(adapter->netdev, BE_HDR_LEN + NET_IP_ALIGN);
+ skb = netdev_alloc_skb_ip_align(adapter->netdev, BE_HDR_LEN);
if (!skb) {
if (net_ratelimit())
dev_warn(&adapter->pdev->dev, "skb alloc failed\n");
@@ -766,8 +764,6 @@ static void be_rx_compl_process(struct be_adapter *adapter,
return;
}
- skb_reserve(skb, NET_IP_ALIGN);
-
skb_fill_rx_data(adapter, skb, rxcp);
if (do_pkt_csum(rxcp, adapter->rx_csum))
@@ -1620,19 +1616,22 @@ static int be_open(struct net_device *netdev)
static int be_setup(struct be_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
- u32 if_flags;
+ u32 cap_flags, en_flags;
int status;
- if_flags = BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_PROMISCUOUS |
- BE_IF_FLAGS_MCAST_PROMISCUOUS | BE_IF_FLAGS_UNTAGGED |
- BE_IF_FLAGS_PASS_L3L4_ERRORS;
- status = be_cmd_if_create(adapter, if_flags, netdev->dev_addr,
- false/* pmac_invalid */, &adapter->if_handle,
- &adapter->pmac_id);
+ cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
+ BE_IF_FLAGS_MCAST_PROMISCUOUS |
+ BE_IF_FLAGS_PROMISCUOUS |
+ BE_IF_FLAGS_PASS_L3L4_ERRORS;
+ en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
+ BE_IF_FLAGS_PASS_L3L4_ERRORS;
+
+ status = be_cmd_if_create(adapter, cap_flags, en_flags,
+ netdev->dev_addr, false/* pmac_invalid */,
+ &adapter->if_handle, &adapter->pmac_id);
if (status != 0)
goto do_none;
-
status = be_tx_queues_create(adapter);
if (status != 0)
goto if_destroy;
@@ -2055,6 +2054,10 @@ static int be_hw_up(struct be_adapter *adapter)
if (status)
return status;
+ status = be_cmd_reset_function(adapter);
+ if (status)
+ return status;
+
status = be_cmd_get_fw_ver(adapter, adapter->fw_ver);
if (status)
return status;
@@ -2108,10 +2111,6 @@ static int __devinit be_probe(struct pci_dev *pdev,
if (status)
goto free_netdev;
- status = be_cmd_reset_function(adapter);
- if (status)
- goto ctrl_clean;
-
status = be_stats_init(adapter);
if (status)
goto ctrl_clean;
diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h
index bbf842284ebb..c3b32f71e024 100644
--- a/drivers/net/bnx2x.h
+++ b/drivers/net/bnx2x.h
@@ -24,6 +24,10 @@
#define BCM_VLAN 1
#endif
+#if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
+#define BCM_CNIC 1
+#include "cnic_if.h"
+#endif
#define BNX2X_MULTI_QUEUE
@@ -762,7 +766,11 @@ struct bnx2x_eth_stats {
(offsetof(struct bnx2x_eth_stats, stat_name) / 4)
+#ifdef BCM_CNIC
+#define MAX_CONTEXT 15
+#else
#define MAX_CONTEXT 16
+#endif
union cdu_context {
struct eth_context eth;
@@ -811,13 +819,21 @@ struct bnx2x {
struct bnx2x_fastpath fp[MAX_CONTEXT];
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
struct net_device *dev;
struct pci_dev *pdev;
atomic_t intr_sem;
+#ifdef BCM_CNIC
+ struct msix_entry msix_table[MAX_CONTEXT+2];
+#else
struct msix_entry msix_table[MAX_CONTEXT+1];
+#endif
#define INT_MODE_INTx 1
#define INT_MODE_MSI 2
#define INT_MODE_MSIX 3
@@ -863,8 +879,8 @@ struct bnx2x {
/* Flags for marking that there is a STAT_QUERY or
SET_MAC ramrod pending */
- u8 stats_pending;
- u8 set_mac_pending;
+ int stats_pending;
+ int set_mac_pending;
/* End of fields used in the performance code paths */
@@ -884,6 +900,7 @@ struct bnx2x {
#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)
@@ -891,6 +908,11 @@ struct bnx2x {
#define BP_E1HVN(bp) (bp->func >> 1)
#define BP_L_ID(bp) (BP_E1HVN(bp) << 2)
+#ifdef BCM_CNIC
+#define BCM_CNIC_CID_START 16
+#define BCM_ISCSI_ETH_CL_ID 17
+#endif
+
int pm_cap;
int pcie_cap;
int mrrs;
@@ -944,7 +966,6 @@ 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_DISABLED 0xd000
#define BNX2X_STATE_DIAG 0xe000
#define BNX2X_STATE_ERROR 0xf000
@@ -960,28 +981,51 @@ struct bnx2x {
#define BNX2X_MAX_MULTICAST 64
#define BNX2X_MAX_EMUL_MULTI 16
+ u32 rx_mode_cl_mask;
+
dma_addr_t def_status_blk_mapping;
struct bnx2x_slowpath *slowpath;
dma_addr_t slowpath_mapping;
-#ifdef BCM_ISCSI
- 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;
-#endif
-
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;
+ dma_addr_t cnic_sb_mapping;
+#define CNIC_SB_ID(bp) BP_L_ID(bp)
+ struct eth_spe *cnic_kwq;
+ struct eth_spe *cnic_kwq_prod;
+ struct eth_spe *cnic_kwq_cons;
+ struct eth_spe *cnic_kwq_last;
+ u16 cnic_kwq_pending;
+ u16 cnic_spq_pending;
+ struct mutex cnic_mutex;
+ u8 iscsi_mac[6];
+#endif
+
int dmae_ready;
/* used to synchronize dmae accesses */
struct mutex dmae_mutex;
+ /* used to protect the FW mail box */
+ struct mutex fw_mb_mutex;
+
/* used to synchronize stats collecting */
int stats_state;
/* used by dmae command loader */
diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x_hsi.h
index 8e2261fad485..dc2f8ed5fd07 100644
--- a/drivers/net/bnx2x_hsi.h
+++ b/drivers/net/bnx2x_hsi.h
@@ -7,6 +7,20 @@
* the Free Software Foundation.
*/
+struct license_key {
+ u32 reserved[6];
+
+#if defined(__BIG_ENDIAN)
+ u16 max_iscsi_init_conn;
+ u16 max_iscsi_trgt_conn;
+#elif defined(__LITTLE_ENDIAN)
+ u16 max_iscsi_trgt_conn;
+ u16 max_iscsi_init_conn;
+#endif
+
+ u32 reserved_a[6];
+};
+
#define PORT_0 0
#define PORT_1 1
@@ -881,7 +895,7 @@ struct shmem_region { /* SharedMem Offset (size) */
struct shm_dev_info dev_info; /* 0x8 (0x438) */
- u8 reserved[52*PORT_MAX];
+ struct license_key drv_lic_key[PORT_MAX]; /* 0x440 (52*2=0x68) */
/* FW information (for internal FW use) */
u32 fw_info_fio_offset; /* 0x4a8 (0x4) */
@@ -1245,8 +1259,8 @@ struct host_func_stats {
#define BCM_5710_FW_MAJOR_VERSION 5
-#define BCM_5710_FW_MINOR_VERSION 0
-#define BCM_5710_FW_REVISION_VERSION 21
+#define BCM_5710_FW_MINOR_VERSION 2
+#define BCM_5710_FW_REVISION_VERSION 7
#define BCM_5710_FW_ENGINEERING_VERSION 0
#define BCM_5710_FW_COMPILE_FLAGS 1
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index 20f0ed956df2..59b58d8f0fa8 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -56,8 +56,8 @@
#include "bnx2x_init_ops.h"
#include "bnx2x_dump.h"
-#define DRV_MODULE_VERSION "1.52.1"
-#define DRV_MODULE_RELDATE "2009/08/12"
+#define DRV_MODULE_VERSION "1.52.1-1"
+#define DRV_MODULE_RELDATE "2009/10/13"
#define BNX2X_BC_VER 0x040200
#include <linux/firmware.h>
@@ -742,6 +742,9 @@ static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
if (msix) {
synchronize_irq(bp->msix_table[0].vector);
offset = 1;
+#ifdef BCM_CNIC
+ offset++;
+#endif
for_each_queue(bp, i)
synchronize_irq(bp->msix_table[i + offset].vector);
} else
@@ -966,6 +969,9 @@ static void bnx2x_tx_int(struct bnx2x_fastpath *fp)
}
}
+#ifdef BCM_CNIC
+static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid);
+#endif
static void bnx2x_sp_event(struct bnx2x_fastpath *fp,
union eth_rx_cqe *rr_cqe)
@@ -1022,16 +1028,24 @@ static void bnx2x_sp_event(struct bnx2x_fastpath *fp,
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 = 0;
+ bp->set_mac_pending--;
+ smp_wmb();
break;
case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_CLOSING_WAIT4_HALT):
- case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_DISABLED):
DP(NETIF_MSG_IFDOWN, "got (un)set mac ramrod\n");
+ bp->set_mac_pending--;
+ smp_wmb();
break;
default:
@@ -1804,6 +1818,20 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
}
}
+#ifdef BCM_CNIC
+ mask = 0x2 << CNIC_SB_ID(bp);
+ if (status & (mask | 0x1)) {
+ struct cnic_ops *c_ops = NULL;
+
+ rcu_read_lock();
+ c_ops = rcu_dereference(bp->cnic_ops);
+ if (c_ops)
+ c_ops->cnic_handler(bp->cnic_data, NULL);
+ rcu_read_unlock();
+
+ status &= ~mask;
+ }
+#endif
if (unlikely(status & 0x1)) {
queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
@@ -2128,18 +2156,30 @@ static void bnx2x_calc_fc_adv(struct bnx2x *bp)
static void bnx2x_link_report(struct bnx2x *bp)
{
- if (bp->state == BNX2X_STATE_DISABLED) {
+ if (bp->flags & MF_FUNC_DIS) {
netif_carrier_off(bp->dev);
printk(KERN_ERR PFX "%s NIC Link is Down\n", bp->dev->name);
return;
}
if (bp->link_vars.link_up) {
+ u16 line_speed;
+
if (bp->state == BNX2X_STATE_OPEN)
netif_carrier_on(bp->dev);
printk(KERN_INFO PFX "%s NIC Link is Up, ", bp->dev->name);
- printk("%d Mbps ", bp->link_vars.line_speed);
+ line_speed = bp->link_vars.line_speed;
+ 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 < line_speed)
+ line_speed = vn_max_rate;
+ }
+ printk("%d Mbps ", line_speed);
if (bp->link_vars.duplex == DUPLEX_FULL)
printk("full duplex");
@@ -2304,8 +2344,14 @@ static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp)
}
/* ... only if all min rates are zeros - disable fairness */
- if (all_zero)
- bp->vn_weight_sum = 0;
+ if (all_zero) {
+ bp->cmng.flags.cmng_enables &=
+ ~CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
+ DP(NETIF_MSG_IFUP, "All MIN values are zeroes"
+ " fairness will be disabled\n");
+ } else
+ bp->cmng.flags.cmng_enables |=
+ CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
}
static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func)
@@ -2324,17 +2370,14 @@ static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func)
} else {
vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >>
FUNC_MF_CFG_MIN_BW_SHIFT) * 100;
- /* If fairness is enabled (not all min rates are zeroes) and
- if current min rate is zero - set it to 1.
- This is a requirement of the algorithm. */
- if (bp->vn_weight_sum && (vn_min_rate == 0))
+ /* If min rate is zero - set it to 1 */
+ if (!vn_min_rate)
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 %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);
memset(&m_rs_vn, 0, sizeof(struct rate_shaping_vars_per_vn));
@@ -2405,8 +2448,7 @@ static void bnx2x_link_attn(struct bnx2x *bp)
memset(&(pstats->mac_stx[0]), 0,
sizeof(struct mac_stx));
}
- if ((bp->state == BNX2X_STATE_OPEN) ||
- (bp->state == BNX2X_STATE_DISABLED))
+ if (bp->state == BNX2X_STATE_OPEN)
bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
}
@@ -2449,9 +2491,7 @@ static void bnx2x_link_attn(struct bnx2x *bp)
static void bnx2x__link_status_update(struct bnx2x *bp)
{
- int func = BP_FUNC(bp);
-
- if (bp->state != BNX2X_STATE_OPEN)
+ if ((bp->state != BNX2X_STATE_OPEN) || (bp->flags & MF_FUNC_DIS))
return;
bnx2x_link_status_update(&bp->link_params, &bp->link_vars);
@@ -2461,7 +2501,6 @@ static void bnx2x__link_status_update(struct bnx2x *bp)
else
bnx2x_stats_handle(bp, STATS_EVENT_STOP);
- bp->mf_config = SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
bnx2x_calc_vn_weight_sum(bp);
/* indicate link status */
@@ -2501,6 +2540,7 @@ u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
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));
DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB\n", (command | seq));
@@ -2510,8 +2550,8 @@ u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
rc = SHMEM_RD(bp, func_mb[func].fw_mb_header);
- /* Give the FW up to 2 second (200*10ms) */
- } while ((seq != (rc & FW_MSG_SEQ_NUMBER_MASK)) && (cnt++ < 200));
+ /* Give the FW up to 5 second (500*10ms) */
+ } while ((seq != (rc & FW_MSG_SEQ_NUMBER_MASK)) && (cnt++ < 500));
DP(BNX2X_MSG_MCP, "[after %d ms] read (%x) seq is (%x) from FW MB\n",
cnt*delay, rc, seq);
@@ -2525,32 +2565,24 @@ u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
bnx2x_fw_dump(bp);
rc = 0;
}
+ mutex_unlock(&bp->fw_mb_mutex);
return rc;
}
static void bnx2x_set_storm_rx_mode(struct bnx2x *bp);
-static void bnx2x_set_mac_addr_e1h(struct bnx2x *bp, int set);
+static void bnx2x_set_eth_mac_addr_e1h(struct bnx2x *bp, int set);
static void bnx2x_set_rx_mode(struct net_device *dev);
static void bnx2x_e1h_disable(struct bnx2x *bp)
{
int port = BP_PORT(bp);
- int i;
-
- bp->rx_mode = BNX2X_RX_MODE_NONE;
- bnx2x_set_storm_rx_mode(bp);
netif_tx_disable(bp->dev);
bp->dev->trans_start = jiffies; /* prevent tx timeout */
REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0);
- bnx2x_set_mac_addr_e1h(bp, 0);
-
- for (i = 0; i < MC_HASH_SIZE; i++)
- REG_WR(bp, MC_HASH_OFFSET(bp, i), 0);
-
netif_carrier_off(bp->dev);
}
@@ -2560,13 +2592,13 @@ static void bnx2x_e1h_enable(struct bnx2x *bp)
REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1);
- bnx2x_set_mac_addr_e1h(bp, 1);
-
/* Tx queue should be only reenabled */
netif_tx_wake_all_queues(bp->dev);
- /* Initialize the receive filter. */
- bnx2x_set_rx_mode(bp->dev);
+ /*
+ * Should not call netif_carrier_on since it will be called if the link
+ * is up when checking for link state
+ */
}
static void bnx2x_update_min_max(struct bnx2x *bp)
@@ -2605,21 +2637,23 @@ static void bnx2x_update_min_max(struct bnx2x *bp)
static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event)
{
- int func = BP_FUNC(bp);
-
DP(BNX2X_MSG_MCP, "dcc_event 0x%x\n", dcc_event);
- bp->mf_config = SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
if (dcc_event & DRV_STATUS_DCC_DISABLE_ENABLE_PF) {
+ /*
+ * This is the only place besides the function initialization
+ * where the bp->flags can change so it is done without any
+ * locks
+ */
if (bp->mf_config & FUNC_MF_CFG_FUNC_DISABLED) {
DP(NETIF_MSG_IFDOWN, "mf_cfg function disabled\n");
- bp->state = BNX2X_STATE_DISABLED;
+ bp->flags |= MF_FUNC_DIS;
bnx2x_e1h_disable(bp);
} else {
DP(NETIF_MSG_IFUP, "mf_cfg function enabled\n");
- bp->state = BNX2X_STATE_OPEN;
+ bp->flags &= ~MF_FUNC_DIS;
bnx2x_e1h_enable(bp);
}
@@ -2638,11 +2672,40 @@ static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event)
bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_OK);
}
+/* must be called under the spq lock */
+static inline struct eth_spe *bnx2x_sp_get_next(struct bnx2x *bp)
+{
+ struct eth_spe *next_spe = bp->spq_prod_bd;
+
+ if (bp->spq_prod_bd == bp->spq_last_bd) {
+ bp->spq_prod_bd = bp->spq;
+ bp->spq_prod_idx = 0;
+ DP(NETIF_MSG_TIMER, "end of spq\n");
+ } else {
+ bp->spq_prod_bd++;
+ bp->spq_prod_idx++;
+ }
+ return next_spe;
+}
+
+/* must be called under the spq lock */
+static inline void bnx2x_sp_prod_update(struct bnx2x *bp)
+{
+ int func = BP_FUNC(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);
+ mmiowb();
+}
+
/* the slow path queue is odd since completions arrive on the fastpath ring */
static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
u32 data_hi, u32 data_lo, int common)
{
- int func = BP_FUNC(bp);
+ struct eth_spe *spe;
DP(BNX2X_MSG_SP/*NETIF_MSG_TIMER*/,
"SPQE (%x:%x) command %d hw_cid %x data (%x:%x) left %x\n",
@@ -2664,38 +2727,23 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
return -EBUSY;
}
+ spe = bnx2x_sp_get_next(bp);
+
/* CID needs port number to be encoded int it */
- bp->spq_prod_bd->hdr.conn_and_cmd_data =
+ spe->hdr.conn_and_cmd_data =
cpu_to_le32(((command << SPE_HDR_CMD_ID_SHIFT) |
HW_CID(bp, cid)));
- bp->spq_prod_bd->hdr.type = cpu_to_le16(ETH_CONNECTION_TYPE);
+ spe->hdr.type = cpu_to_le16(ETH_CONNECTION_TYPE);
if (common)
- bp->spq_prod_bd->hdr.type |=
+ spe->hdr.type |=
cpu_to_le16((1 << SPE_HDR_COMMON_RAMROD_SHIFT));
- bp->spq_prod_bd->data.mac_config_addr.hi = cpu_to_le32(data_hi);
- bp->spq_prod_bd->data.mac_config_addr.lo = cpu_to_le32(data_lo);
+ spe->data.mac_config_addr.hi = cpu_to_le32(data_hi);
+ spe->data.mac_config_addr.lo = cpu_to_le32(data_lo);
bp->spq_left--;
- if (bp->spq_prod_bd == bp->spq_last_bd) {
- bp->spq_prod_bd = bp->spq;
- bp->spq_prod_idx = 0;
- DP(NETIF_MSG_TIMER, "end of spq\n");
-
- } else {
- bp->spq_prod_bd++;
- bp->spq_prod_idx++;
- }
-
- /* Make sure that BD data is updated before writing the producer */
- wmb();
-
- REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func),
- bp->spq_prod_idx);
-
- mmiowb();
-
+ bnx2x_sp_prod_update(bp);
spin_unlock_bh(&bp->spq_lock);
return 0;
}
@@ -3024,6 +3072,8 @@ 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);
if (val & DRV_STATUS_DCC_EVENT_MASK)
bnx2x_dcc_event(bp,
@@ -3227,6 +3277,17 @@ static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
return IRQ_HANDLED;
#endif
+#ifdef BCM_CNIC
+ {
+ struct cnic_ops *c_ops;
+
+ rcu_read_lock();
+ c_ops = rcu_dereference(bp->cnic_ops);
+ if (c_ops)
+ c_ops->cnic_handler(bp->cnic_data, NULL);
+ rcu_read_unlock();
+ }
+#endif
queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
return IRQ_HANDLED;
@@ -4640,8 +4701,7 @@ static void bnx2x_timer(unsigned long data)
}
}
- if ((bp->state == BNX2X_STATE_OPEN) ||
- (bp->state == BNX2X_STATE_DISABLED))
+ if (bp->state == BNX2X_STATE_OPEN)
bnx2x_stats_handle(bp, STATS_EVENT_UPDATE);
timer_restart:
@@ -5235,7 +5295,7 @@ static 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 = (1 << BP_L_ID(bp));
+ int mask = bp->rx_mode_cl_mask;
int func = BP_FUNC(bp);
int port = BP_PORT(bp);
int i;
@@ -5348,6 +5408,7 @@ static void bnx2x_init_internal_func(struct bnx2x *bp)
(*(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);
for_each_queue(bp, i) {
@@ -5504,20 +5565,18 @@ static void bnx2x_init_internal_func(struct bnx2x *bp)
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 =
+ bp->cmng.flags.cmng_enables |=
CMNG_FLAGS_PER_PORT_RATE_SHAPING_VN;
- if (bp->vn_weight_sum)
- bp->cmng.flags.cmng_enables |=
- CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
- else
- DP(NETIF_MSG_IFUP, "All MIN values are zeroes"
- " fairness will be disabled\n");
+
} else {
/* rate shaping and fairness are disabled */
DP(NETIF_MSG_IFUP,
@@ -5565,7 +5624,11 @@ static void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
fp->state = BNX2X_FP_STATE_CLOSED;
fp->index = i;
fp->cl_id = BP_L_ID(bp) + i;
+#ifdef BCM_CNIC
+ fp->sb_id = fp->cl_id + 1;
+#else
fp->sb_id = fp->cl_id;
+#endif
/* Suitable Rx and Tx SBs are served by the same client */
if (i >= bp->num_rx_queues)
fp->cl_id -= bp->num_rx_queues;
@@ -5867,7 +5930,7 @@ static int bnx2x_int_mem_test(struct bnx2x *bp)
msleep(50);
bnx2x_init_block(bp, BRB1_BLOCK, COMMON_STAGE);
bnx2x_init_block(bp, PRS_BLOCK, COMMON_STAGE);
-#ifndef BCM_ISCSI
+#ifndef BCM_CNIC
/* set NIC mode */
REG_WR(bp, PRS_REG_NIC_MODE, 1);
#endif
@@ -6006,6 +6069,9 @@ static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
static int bnx2x_init_common(struct bnx2x *bp)
{
u32 val, i;
+#ifdef BCM_CNIC
+ u32 wb_write[2];
+#endif
DP(BNX2X_MSG_MCP, "starting common init func %d\n", BP_FUNC(bp));
@@ -6048,7 +6114,7 @@ static int bnx2x_init_common(struct bnx2x *bp)
#endif
REG_WR(bp, PXP2_REG_RQ_CDU_P_SIZE, 2);
-#ifdef BCM_ISCSI
+#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);
@@ -6091,11 +6157,26 @@ static int bnx2x_init_common(struct bnx2x *bp)
bnx2x_read_dmae(bp, USEM_REG_PASSIVE_BUFFER, 3);
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_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);
-#ifdef BCM_ISCSI
+#ifdef BCM_CNIC
bnx2x_init_block(bp, TIMERS_BLOCK, COMMON_STAGE);
#endif
@@ -6109,8 +6190,10 @@ static int bnx2x_init_common(struct bnx2x *bp)
bnx2x_init_block(bp, BRB1_BLOCK, COMMON_STAGE);
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));
@@ -6145,6 +6228,18 @@ static int bnx2x_init_common(struct bnx2x *bp)
/* TODO: replace with something meaningful */
}
bnx2x_init_block(bp, SRCH_BLOCK, COMMON_STAGE);
+#ifdef BCM_CNIC
+ REG_WR(bp, SRC_REG_KEYSEARCH_0, 0x63285672);
+ REG_WR(bp, SRC_REG_KEYSEARCH_1, 0x24b8f2cc);
+ REG_WR(bp, SRC_REG_KEYSEARCH_2, 0x223aef9b);
+ REG_WR(bp, SRC_REG_KEYSEARCH_3, 0x26001e3a);
+ REG_WR(bp, SRC_REG_KEYSEARCH_4, 0x7ae91116);
+ REG_WR(bp, SRC_REG_KEYSEARCH_5, 0x5ce5230b);
+ REG_WR(bp, SRC_REG_KEYSEARCH_6, 0x298d8adf);
+ REG_WR(bp, SRC_REG_KEYSEARCH_7, 0x6eb0ff09);
+ REG_WR(bp, SRC_REG_KEYSEARCH_8, 0x1830f82f);
+ REG_WR(bp, SRC_REG_KEYSEARCH_9, 0x01e46be7);
+#endif
REG_WR(bp, SRC_REG_SOFT_RST, 0);
if (sizeof(union cdu_context) != 1024)
@@ -6261,38 +6356,14 @@ static int bnx2x_init_port(struct bnx2x *bp)
bnx2x_init_block(bp, TCM_BLOCK, init_stage);
bnx2x_init_block(bp, UCM_BLOCK, init_stage);
bnx2x_init_block(bp, CCM_BLOCK, init_stage);
-#ifdef BCM_ISCSI
- /* Port0 1
- * Port1 385 */
- i++;
- wb_write[0] = ONCHIP_ADDR1(bp->timers_mapping);
- wb_write[1] = ONCHIP_ADDR2(bp->timers_mapping);
- REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2);
- REG_WR(bp, PXP2_REG_PSWRQ_TM0_L2P + func*4, PXP_ONE_ILT(i));
-
- /* Port0 2
- * Port1 386 */
- i++;
- wb_write[0] = ONCHIP_ADDR1(bp->qm_mapping);
- wb_write[1] = ONCHIP_ADDR2(bp->qm_mapping);
- REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2);
- REG_WR(bp, PXP2_REG_PSWRQ_QM0_L2P + func*4, PXP_ONE_ILT(i));
-
- /* Port0 3
- * Port1 387 */
- i++;
- wb_write[0] = ONCHIP_ADDR1(bp->t1_mapping);
- wb_write[1] = ONCHIP_ADDR2(bp->t1_mapping);
- REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2);
- REG_WR(bp, PXP2_REG_PSWRQ_SRC0_L2P + func*4, PXP_ONE_ILT(i));
-#endif
bnx2x_init_block(bp, XCM_BLOCK, init_stage);
-#ifdef BCM_ISCSI
- REG_WR(bp, TM_REG_LIN0_SCAN_TIME + func*4, 1024/64*20);
- REG_WR(bp, TM_REG_LIN0_MAX_ACTIVE_CID + func*4, 31);
+#ifdef BCM_CNIC
+ REG_WR(bp, QM_REG_CONNNUM_0 + port*4, 1024/16 - 1);
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);
#endif
bnx2x_init_block(bp, DQ_BLOCK, init_stage);
@@ -6350,18 +6421,8 @@ static int bnx2x_init_port(struct bnx2x *bp)
msleep(5);
REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0);
-#ifdef BCM_ISCSI
- /* tell the searcher where the T2 table is */
- REG_WR(bp, SRC_REG_COUNTFREE0 + func*4, 16*1024/64);
-
- wb_write[0] = U64_LO(bp->t2_mapping);
- wb_write[1] = U64_HI(bp->t2_mapping);
- REG_WR_DMAE(bp, SRC_REG_FIRSTFREE0 + func*4, wb_write, 2);
- wb_write[0] = U64_LO((u64)bp->t2_mapping + 16*1024 - 64);
- wb_write[1] = U64_HI((u64)bp->t2_mapping + 16*1024 - 64);
- REG_WR_DMAE(bp, SRC_REG_LASTFREE0 + func*4, wb_write, 2);
-
- REG_WR(bp, SRC_REG_NUMBER_HASH_BITS0 + func*4, 10);
+#ifdef BCM_CNIC
+ bnx2x_init_block(bp, SRCH_BLOCK, init_stage);
#endif
bnx2x_init_block(bp, CDU_BLOCK, init_stage);
bnx2x_init_block(bp, CFC_BLOCK, init_stage);
@@ -6470,7 +6531,12 @@ static int bnx2x_init_port(struct bnx2x *bp)
#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)
{
@@ -6509,6 +6575,46 @@ static int bnx2x_init_func(struct bnx2x *bp)
REG_WR(bp, PXP2_REG_PSWRQ_CDU0_L2P + func*4,
PXP_ILT_RANGE(i, i + CNIC_ILT_LINES));
+#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);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ /* tell the searcher where the T2 table is */
+ REG_WR(bp, SRC_REG_COUNTFREE0 + port*4, 16*1024/64);
+
+ bnx2x_wb_wr(bp, SRC_REG_FIRSTFREE0 + port*16,
+ U64_LO(bp->t2_mapping), U64_HI(bp->t2_mapping));
+
+ 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));
+
+ REG_WR(bp, SRC_REG_NUMBER_HASH_BITS0 + port*4, 10);
+#endif
if (CHIP_IS_E1H(bp)) {
bnx2x_init_block(bp, MISC_BLOCK, FUNC0_STAGE + func);
@@ -6593,6 +6699,9 @@ static int bnx2x_init_hw(struct bnx2x *bp, u32 load_code)
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);
@@ -6668,11 +6777,13 @@ static void bnx2x_free_mem(struct bnx2x *bp)
BNX2X_PCI_FREE(bp->slowpath, bp->slowpath_mapping,
sizeof(struct bnx2x_slowpath));
-#ifdef BCM_ISCSI
+#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));
#endif
BNX2X_PCI_FREE(bp->spq, bp->spq_mapping, BCM_PAGE_SIZE);
@@ -6751,32 +6862,26 @@ static int bnx2x_alloc_mem(struct bnx2x *bp)
BNX2X_PCI_ALLOC(bp->slowpath, &bp->slowpath_mapping,
sizeof(struct bnx2x_slowpath));
-#ifdef BCM_ISCSI
+#ifdef BCM_CNIC
BNX2X_PCI_ALLOC(bp->t1, &bp->t1_mapping, 64*1024);
- /* Initialize T1 */
- for (i = 0; i < 64*1024; i += 64) {
- *(u64 *)((char *)bp->t1 + i + 56) = 0x0UL;
- *(u64 *)((char *)bp->t1 + i + 3) = 0x0UL;
- }
-
/* 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 */
+ /* Initialize T2 (for 1024 connections) */
for (i = 0; i < 16*1024; i += 64)
- * (u64 *)((char *)bp->t2 + i + 56) = bp->t2_mapping + i + 64;
-
- /* now fixup the last line in the block to point to the next block */
- *(u64 *)((char *)bp->t2 + 1024*16-8) = bp->t2_mapping;
+ *(u64 *)((char *)bp->t2 + i + 56) = bp->t2_mapping + i + 64;
- /* Timer block array (MAX_CONN*8) phys uncached for now 1024 conns */
+ /* Timer block array (8*MAX_CONN) phys uncached for now 1024 conns */
BNX2X_PCI_ALLOC(bp->timers, &bp->timers_mapping, 8*1024);
/* QM queues (128*MAX_CONN) */
BNX2X_PCI_ALLOC(bp->qm, &bp->qm_mapping, 128*1024);
+
+ BNX2X_PCI_ALLOC(bp->cnic_sb, &bp->cnic_sb_mapping,
+ sizeof(struct host_status_block));
#endif
/* Slow path ring */
@@ -6852,6 +6957,9 @@ static void bnx2x_free_msix_irqs(struct bnx2x *bp)
DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n",
bp->msix_table[0].vector);
+#ifdef BCM_CNIC
+ offset++;
+#endif
for_each_queue(bp, i) {
DP(NETIF_MSG_IFDOWN, "about to release fp #%d->%d irq "
"state %x\n", i, bp->msix_table[i + offset].vector,
@@ -6885,6 +6993,12 @@ static int bnx2x_enable_msix(struct bnx2x *bp)
bp->msix_table[0].entry = igu_vec;
DP(NETIF_MSG_IFUP, "msix_table[0].entry = %d (slowpath)\n", igu_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++;
+#endif
for_each_queue(bp, i) {
igu_vec = BP_L_ID(bp) + offset + i;
bp->msix_table[i + offset].entry = igu_vec;
@@ -6915,6 +7029,9 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
return -EBUSY;
}
+#ifdef BCM_CNIC
+ offset++;
+#endif
for_each_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
@@ -7022,7 +7139,19 @@ static void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
* Init service functions
*/
-static void bnx2x_set_mac_addr_e1(struct bnx2x *bp, int set)
+/**
+ * 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)
{
struct mac_configuration_cmd *config = bnx2x_sp(bp, mac_config);
int port = BP_PORT(bp);
@@ -7031,25 +7160,25 @@ static void bnx2x_set_mac_addr_e1(struct bnx2x *bp, int set)
* unicasts 0-31:port0 32-63:port1
* multicast 64-127:port0 128-191:port1
*/
- config->hdr.length = 2;
- config->hdr.offset = port ? 32 : 0;
- config->hdr.client_id = bp->fp->cl_id;
+ config->hdr.length = 1 + (with_bcast ? 1 : 0);
+ config->hdr.offset = cam_offset;
+ config->hdr.client_id = 0xff;
config->hdr.reserved1 = 0;
/* primary MAC */
config->config_table[0].cam_entry.msb_mac_addr =
- swab16(*(u16 *)&bp->dev->dev_addr[0]);
+ swab16(*(u16 *)&mac[0]);
config->config_table[0].cam_entry.middle_mac_addr =
- swab16(*(u16 *)&bp->dev->dev_addr[2]);
+ swab16(*(u16 *)&mac[2]);
config->config_table[0].cam_entry.lsb_mac_addr =
- swab16(*(u16 *)&bp->dev->dev_addr[4]);
+ 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(1 << BP_L_ID(bp));
+ cpu_to_le32(cl_bit_vec);
config->config_table[0].target_table_entry.vlan_id = 0;
DP(NETIF_MSG_IFUP, "%s MAC (%04x:%04x:%04x)\n",
@@ -7059,47 +7188,58 @@ static void bnx2x_set_mac_addr_e1(struct bnx2x *bp, int set)
config->config_table[0].cam_entry.lsb_mac_addr);
/* broadcast */
- 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(1 << BP_L_ID(bp));
- config->config_table[1].target_table_entry.vlan_id = 0;
+ 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;
+ }
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);
}
-static void bnx2x_set_mac_addr_e1h(struct bnx2x *bp, int set)
+/**
+ * Sets a MAC in a CAM for a few L2 Clients for E1H 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
+ */
+static void bnx2x_set_mac_addr_e1h_gen(struct bnx2x *bp, int set, u8 *mac,
+ u32 cl_bit_vec, u8 cam_offset)
{
struct mac_configuration_cmd_e1h *config =
(struct mac_configuration_cmd_e1h *)bnx2x_sp(bp, mac_config);
- /* CAM allocation for E1H
- * unicasts: by func number
- * multicast: 20+FUNC*20, 20 each
- */
config->hdr.length = 1;
- config->hdr.offset = BP_FUNC(bp);
- config->hdr.client_id = bp->fp->cl_id;
+ config->hdr.offset = cam_offset;
+ config->hdr.client_id = 0xff;
config->hdr.reserved1 = 0;
/* primary MAC */
config->config_table[0].msb_mac_addr =
- swab16(*(u16 *)&bp->dev->dev_addr[0]);
+ swab16(*(u16 *)&mac[0]);
config->config_table[0].middle_mac_addr =
- swab16(*(u16 *)&bp->dev->dev_addr[2]);
+ swab16(*(u16 *)&mac[2]);
config->config_table[0].lsb_mac_addr =
- swab16(*(u16 *)&bp->dev->dev_addr[4]);
+ swab16(*(u16 *)&mac[4]);
config->config_table[0].clients_bit_vector =
- cpu_to_le32(1 << BP_L_ID(bp));
+ cpu_to_le32(cl_bit_vec);
config->config_table[0].vlan_id = 0;
config->config_table[0].e1hov_id = cpu_to_le16(bp->e1hov);
if (set)
@@ -7108,11 +7248,11 @@ static void bnx2x_set_mac_addr_e1h(struct bnx2x *bp, int set)
config->config_table[0].flags =
MAC_CONFIGURATION_ENTRY_E1H_ACTION_TYPE;
- DP(NETIF_MSG_IFUP, "%s MAC (%04x:%04x:%04x) E1HOV %d CLID %d\n",
+ DP(NETIF_MSG_IFUP, "%s MAC (%04x:%04x:%04x) E1HOV %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, BP_L_ID(bp));
+ config->config_table[0].lsb_mac_addr, bp->e1hov, cl_bit_vec);
bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
U64_HI(bnx2x_sp_mapping(bp, mac_config)),
@@ -7164,6 +7304,69 @@ static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx,
return -EBUSY;
}
+static void bnx2x_set_eth_mac_addr_e1h(struct bnx2x *bp, int set)
+{
+ bp->set_mac_pending++;
+ smp_wmb();
+
+ bnx2x_set_mac_addr_e1h_gen(bp, set, bp->dev->dev_addr,
+ (1 << bp->fp->cl_id), BP_FUNC(bp));
+
+ /* Wait for a completion */
+ bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, set ? 0 : 1);
+}
+
+static void bnx2x_set_eth_mac_addr_e1(struct bnx2x *bp, int set)
+{
+ bp->set_mac_pending++;
+ 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);
+
+ /* Wait for a completion */
+ bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, set ? 0 : 1);
+}
+
+#ifdef BCM_CNIC
+/**
+ * Set iSCSI MAC(s) at the next enties in the CAM after the ETH
+ * MAC(s). This function will wait until the ramdord completion
+ * returns.
+ *
+ * @param bp driver handle
+ * @param set set or clear the CAM entry
+ *
+ * @return 0 if cussess, -ENODEV if ramrod doesn't return.
+ */
+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();
+
+ /* 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);
+
+ return 0;
+}
+#endif
+
static int bnx2x_setup_leading(struct bnx2x *bp)
{
int rc;
@@ -7289,6 +7492,10 @@ static int bnx2x_set_int_mode(struct bnx2x *bp)
return rc;
}
+#ifdef BCM_CNIC
+static int bnx2x_cnic_notify(struct bnx2x *bp, int cmd);
+static void bnx2x_setup_cnic_irq_info(struct bnx2x *bp);
+#endif
/* must be called with rtnl_lock */
static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
@@ -7427,20 +7634,37 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
if (CHIP_IS_E1H(bp))
if (bp->mf_config & FUNC_MF_CFG_FUNC_DISABLED) {
DP(NETIF_MSG_IFUP, "mf_cfg function disabled\n");
- bp->state = BNX2X_STATE_DISABLED;
+ 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;
+#endif
}
if (CHIP_IS_E1(bp))
- bnx2x_set_mac_addr_e1(bp, 1);
+ bnx2x_set_eth_mac_addr_e1(bp, 1);
else
- bnx2x_set_mac_addr_e1h(bp, 1);
+ bnx2x_set_eth_mac_addr_e1h(bp, 1);
+#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;
+ }
+ mutex_unlock(&bp->cnic_mutex);
+#endif
}
if (bp->port.pmf)
@@ -7481,9 +7705,19 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
/* start the timer */
mod_timer(&bp->timer, jiffies + bp->current_interval);
+#ifdef BCM_CNIC
+ bnx2x_setup_cnic_irq_info(bp);
+ if (bp->state == BNX2X_STATE_OPEN)
+ bnx2x_cnic_notify(bp, CNIC_CTL_START_CMD);
+#endif
return 0;
+#ifdef BCM_CNIC
+load_error4:
+ /* Disable Timer scan */
+ REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + BP_PORT(bp)*4, 0);
+#endif
load_error3:
bnx2x_int_disable_sync(bp, 1);
if (!BP_NOMCP(bp)) {
@@ -7591,6 +7825,19 @@ static void bnx2x_reset_func(struct bnx2x *bp)
REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0);
REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0);
+#ifdef BCM_CNIC
+ /* Disable Timer scan */
+ REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 0);
+ /*
+ * Wait for at least 10ms and up to 2 second for the timers scan to
+ * complete
+ */
+ for (i = 0; i < 200; i++) {
+ msleep(10);
+ if (!REG_RD(bp, TM_REG_LIN0_SCAN_ON + port*4))
+ break;
+ }
+#endif
/* Clear ILT */
base = FUNC_ILT_BASE(func);
for (i = base; i < base + ILT_PER_FUNC; i++)
@@ -7657,6 +7904,9 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
u32 reset_code = 0;
int i, cnt, rc;
+#ifdef BCM_CNIC
+ bnx2x_cnic_notify(bp, CNIC_CTL_STOP_CMD);
+#endif
bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT;
/* Set "drop all" */
@@ -7703,7 +7953,7 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
struct mac_configuration_cmd *config =
bnx2x_sp(bp, mcast_config);
- bnx2x_set_mac_addr_e1(bp, 0);
+ bnx2x_set_eth_mac_addr_e1(bp, 0);
for (i = 0; i < config->hdr.length; i++)
CAM_INVALIDATE(config->config_table[i]);
@@ -7716,6 +7966,9 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
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);
@@ -7723,13 +7976,22 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
} else { /* E1H */
REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0);
- bnx2x_set_mac_addr_e1h(bp, 0);
+ bnx2x_set_eth_mac_addr_e1h(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);
+ if (bp->cnic_flags & BNX2X_CNIC_FLAG_MAC_SET) {
+ bnx2x_set_iscsi_eth_mac_addr(bp, 0);
+ bp->cnic_flags &= ~BNX2X_CNIC_FLAG_MAC_SET;
+ }
+ mutex_unlock(&bp->cnic_mutex);
+#endif
if (unload_mode == UNLOAD_NORMAL)
reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
@@ -8506,6 +8768,14 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
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)
+{
+ mac_hi = cpu_to_be16(mac_hi);
+ mac_lo = cpu_to_be32(mac_lo);
+ memcpy(mac_buf, &mac_hi, sizeof(mac_hi));
+ memcpy(mac_buf + sizeof(mac_hi), &mac_lo, sizeof(mac_lo));
+}
+
static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
{
int port = BP_PORT(bp);
@@ -8587,14 +8857,15 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper);
val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower);
- bp->dev->dev_addr[0] = (u8)(val2 >> 8 & 0xff);
- bp->dev->dev_addr[1] = (u8)(val2 & 0xff);
- bp->dev->dev_addr[2] = (u8)(val >> 24 & 0xff);
- bp->dev->dev_addr[3] = (u8)(val >> 16 & 0xff);
- bp->dev->dev_addr[4] = (u8)(val >> 8 & 0xff);
- bp->dev->dev_addr[5] = (u8)(val & 0xff);
+ bnx2x_set_mac_buf(bp->dev->dev_addr, val, val2);
memcpy(bp->link_params.mac_addr, bp->dev->dev_addr, ETH_ALEN);
memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN);
+
+#ifdef BCM_CNIC
+ val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].iscsi_mac_upper);
+ val = SHMEM_RD(bp, dev_info.port_hw_config[port].iscsi_mac_lower);
+ bnx2x_set_mac_buf(bp->iscsi_mac, val, val2);
+#endif
}
static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
@@ -8690,6 +8961,10 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
mutex_init(&bp->port.phy_mutex);
+ mutex_init(&bp->fw_mb_mutex);
+#ifdef BCM_CNIC
+ mutex_init(&bp->cnic_mutex);
+#endif
INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
INIT_WORK(&bp->reset_task, bnx2x_reset_task);
@@ -8765,20 +9040,23 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->supported = bp->port.supported;
cmd->advertising = bp->port.advertising;
- if (netif_carrier_ok(dev)) {
+ 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;
- } else {
- cmd->speed = bp->link_params.req_line_speed;
- cmd->duplex = bp->link_params.req_duplex;
- }
- if (IS_E1HMF(bp)) {
- u16 vn_max_rate;
+ if (IS_E1HMF(bp)) {
+ u16 vn_max_rate;
- vn_max_rate = ((bp->mf_config & FUNC_MF_CFG_MAX_BW_MASK) >>
+ 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;
+ 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) {
@@ -9163,6 +9441,9 @@ static u32 bnx2x_get_link(struct net_device *dev)
{
struct bnx2x *bp = netdev_priv(dev);
+ if (bp->flags & MF_FUNC_DIS)
+ return 0;
+
return bp->link_vars.link_up;
}
@@ -9567,8 +9848,7 @@ static int bnx2x_set_eeprom(struct net_device *dev,
} else if (eeprom->magic == 0x50485952) {
/* 'PHYR' (0x50485952): re-init link after FW upgrade */
- if ((bp->state == BNX2X_STATE_OPEN) ||
- (bp->state == BNX2X_STATE_DISABLED)) {
+ if (bp->state == BNX2X_STATE_OPEN) {
bnx2x_acquire_phy_lock(bp);
rc |= bnx2x_link_reset(&bp->link_params,
&bp->link_vars, 1);
@@ -9818,11 +10098,6 @@ static const struct {
{ "idle check (online)" }
};
-static int bnx2x_self_test_count(struct net_device *dev)
-{
- return BNX2X_NUM_TESTS;
-}
-
static int bnx2x_test_registers(struct bnx2x *bp)
{
int idx, i, rc = -ENODEV;
@@ -10223,14 +10498,16 @@ static int bnx2x_test_intr(struct bnx2x *bp)
config->hdr.client_id = bp->fp->cl_id;
config->hdr.reserved1 = 0;
+ bp->set_mac_pending++;
+ smp_wmb();
rc = 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);
if (rc == 0) {
- bp->set_mac_pending++;
for (i = 0; i < 10; i++) {
if (!bp->set_mac_pending)
break;
+ smp_rmb();
msleep_interruptible(10);
}
if (i == 10)
@@ -10264,7 +10541,7 @@ 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 = bp->link_vars.link_up;
+ link_up = (bnx2x_link_test(bp) == 0);
bnx2x_nic_unload(bp, UNLOAD_NORMAL);
bnx2x_nic_load(bp, LOAD_DIAG);
/* wait until link state is restored */
@@ -10436,6 +10713,36 @@ static const struct {
#define IS_E1HMF_MODE_STAT(bp) \
(IS_E1HMF(bp) && !(bp->msglevel & BNX2X_MSG_STATS))
+static int bnx2x_get_sset_count(struct net_device *dev, int stringset)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int i, num_stats;
+
+ switch(stringset) {
+ case ETH_SS_STATS:
+ if (is_multi(bp)) {
+ num_stats = BNX2X_NUM_Q_STATS * bp->num_rx_queues;
+ if (!IS_E1HMF_MODE_STAT(bp))
+ num_stats += BNX2X_NUM_STATS;
+ } else {
+ if (IS_E1HMF_MODE_STAT(bp)) {
+ num_stats = 0;
+ for (i = 0; i < BNX2X_NUM_STATS; i++)
+ if (IS_FUNC_STAT(i))
+ num_stats++;
+ } else
+ num_stats = BNX2X_NUM_STATS;
+ }
+ return num_stats;
+
+ case ETH_SS_TEST:
+ return BNX2X_NUM_TESTS;
+
+ default:
+ return -EINVAL;
+ }
+}
+
static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
{
struct bnx2x *bp = netdev_priv(dev);
@@ -10473,28 +10780,6 @@ static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
}
}
-static int bnx2x_get_stats_count(struct net_device *dev)
-{
- struct bnx2x *bp = netdev_priv(dev);
- int i, num_stats;
-
- if (is_multi(bp)) {
- num_stats = BNX2X_NUM_Q_STATS * bp->num_rx_queues;
- if (!IS_E1HMF_MODE_STAT(bp))
- num_stats += BNX2X_NUM_STATS;
- } else {
- if (IS_E1HMF_MODE_STAT(bp)) {
- num_stats = 0;
- for (i = 0; i < BNX2X_NUM_STATS; i++)
- if (IS_FUNC_STAT(i))
- num_stats++;
- } else
- num_stats = BNX2X_NUM_STATS;
- }
-
- return num_stats;
-}
-
static void bnx2x_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *buf)
{
@@ -10637,11 +10922,10 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
.set_sg = ethtool_op_set_sg,
.get_tso = ethtool_op_get_tso,
.set_tso = bnx2x_set_tso,
- .self_test_count = bnx2x_self_test_count,
.self_test = bnx2x_self_test,
+ .get_sset_count = bnx2x_get_sset_count,
.get_strings = bnx2x_get_strings,
.phys_id = bnx2x_phys_id,
- .get_stats_count = bnx2x_get_stats_count,
.get_ethtool_stats = bnx2x_get_ethtool_stats,
};
@@ -11321,6 +11605,9 @@ static void bnx2x_set_rx_mode(struct net_device *dev)
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)),
@@ -11370,9 +11657,9 @@ static int bnx2x_change_mac_addr(struct net_device *dev, void *p)
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
if (netif_running(dev)) {
if (CHIP_IS_E1(bp))
- bnx2x_set_mac_addr_e1(bp, 1);
+ bnx2x_set_eth_mac_addr_e1(bp, 1);
else
- bnx2x_set_mac_addr_e1h(bp, 1);
+ bnx2x_set_eth_mac_addr_e1h(bp, 1);
}
return 0;
@@ -12276,4 +12563,287 @@ static void __exit bnx2x_cleanup(void)
module_init(bnx2x_init);
module_exit(bnx2x_cleanup);
+#ifdef BCM_CNIC
+
+/* count denotes the number of new completions we have seen */
+static void bnx2x_cnic_sp_post(struct bnx2x *bp, int count)
+{
+ struct eth_spe *spe;
+
+#ifdef BNX2X_STOP_ON_ERROR
+ if (unlikely(bp->panic))
+ return;
+#endif
+
+ spin_lock_bh(&bp->spq_lock);
+ 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)
+ 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);
+
+ if (bp->cnic_kwq_cons == bp->cnic_kwq_last)
+ bp->cnic_kwq_cons = bp->cnic_kwq;
+ else
+ bp->cnic_kwq_cons++;
+ }
+ bnx2x_sp_prod_update(bp);
+ spin_unlock_bh(&bp->spq_lock);
+}
+
+static int bnx2x_cnic_sp_queue(struct net_device *dev,
+ struct kwqe_16 *kwqes[], u32 count)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int i;
+
+#ifdef BNX2X_STOP_ON_ERROR
+ if (unlikely(bp->panic))
+ return -EIO;
+#endif
+
+ spin_lock_bh(&bp->spq_lock);
+
+ for (i = 0; i < count; i++) {
+ struct eth_spe *spe = (struct eth_spe *)kwqes[i];
+
+ if (bp->cnic_kwq_pending == MAX_SP_DESC_CNT)
+ break;
+
+ *bp->cnic_kwq_prod = *spe;
+
+ bp->cnic_kwq_pending++;
+
+ 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,
+ bp->cnic_kwq_pending);
+
+ if (bp->cnic_kwq_prod == bp->cnic_kwq_last)
+ bp->cnic_kwq_prod = bp->cnic_kwq;
+ else
+ bp->cnic_kwq_prod++;
+ }
+
+ spin_unlock_bh(&bp->spq_lock);
+
+ if (bp->cnic_spq_pending < bp->cnic_eth_dev.max_kwqe_pending)
+ bnx2x_cnic_sp_post(bp, 0);
+
+ return i;
+}
+
+static int bnx2x_cnic_ctl_send(struct bnx2x *bp, struct cnic_ctl_info *ctl)
+{
+ struct cnic_ops *c_ops;
+ int rc = 0;
+
+ mutex_lock(&bp->cnic_mutex);
+ c_ops = bp->cnic_ops;
+ if (c_ops)
+ rc = c_ops->cnic_ctl(bp->cnic_data, ctl);
+ mutex_unlock(&bp->cnic_mutex);
+
+ return rc;
+}
+
+static int bnx2x_cnic_ctl_send_bh(struct bnx2x *bp, struct cnic_ctl_info *ctl)
+{
+ struct cnic_ops *c_ops;
+ int rc = 0;
+
+ rcu_read_lock();
+ c_ops = rcu_dereference(bp->cnic_ops);
+ if (c_ops)
+ rc = c_ops->cnic_ctl(bp->cnic_data, ctl);
+ rcu_read_unlock();
+
+ return rc;
+}
+
+/*
+ * for commands that have no data
+ */
+static int bnx2x_cnic_notify(struct bnx2x *bp, int cmd)
+{
+ struct cnic_ctl_info ctl = {0};
+
+ ctl.cmd = cmd;
+
+ return bnx2x_cnic_ctl_send(bp, &ctl);
+}
+
+static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid)
+{
+ struct cnic_ctl_info ctl;
+
+ /* first we tell CNIC and only then we count this as a completion */
+ ctl.cmd = CNIC_CTL_COMPLETION_CMD;
+ ctl.data.comp.cid = cid;
+
+ bnx2x_cnic_ctl_send_bh(bp, &ctl);
+ bnx2x_cnic_sp_post(bp, 1);
+}
+
+static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int rc = 0;
+
+ switch (ctl->cmd) {
+ case DRV_CTL_CTXTBL_WR_CMD: {
+ u32 index = ctl->data.io.offset;
+ dma_addr_t addr = ctl->data.io.dma_addr;
+
+ bnx2x_ilt_wr(bp, index, addr);
+ break;
+ }
+
+ case DRV_CTL_COMPLETION_CMD: {
+ int count = ctl->data.comp.comp_count;
+
+ bnx2x_cnic_sp_post(bp, count);
+ break;
+ }
+
+ /* rtnl_lock is held. */
+ 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);
+ break;
+ }
+
+ /* rtnl_lock is held. */
+ 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);
+ break;
+ }
+
+ default:
+ BNX2X_ERR("unknown command %x\n", ctl->cmd);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+static void bnx2x_setup_cnic_irq_info(struct bnx2x *bp)
+{
+ struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+ if (bp->flags & USING_MSIX_FLAG) {
+ cp->drv_state |= CNIC_DRV_STATE_USING_MSIX;
+ cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX;
+ cp->irq_arr[0].vector = bp->msix_table[1].vector;
+ } else {
+ 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;
+ cp->irq_arr[0].status_blk_num = CNIC_SB_ID(bp);
+ cp->irq_arr[1].status_blk = bp->def_status_blk;
+ cp->irq_arr[1].status_blk_num = DEF_SB_ID;
+
+ cp->num_irq = 2;
+}
+
+static int bnx2x_register_cnic(struct net_device *dev, struct cnic_ops *ops,
+ void *data)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+ if (ops == NULL)
+ return -EINVAL;
+
+ if (atomic_read(&bp->intr_sem) != 0)
+ return -EBUSY;
+
+ bp->cnic_kwq = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!bp->cnic_kwq)
+ return -ENOMEM;
+
+ bp->cnic_kwq_cons = bp->cnic_kwq;
+ bp->cnic_kwq_prod = bp->cnic_kwq;
+ bp->cnic_kwq_last = bp->cnic_kwq + MAX_SP_DESC_CNT;
+
+ bp->cnic_spq_pending = 0;
+ bp->cnic_kwq_pending = 0;
+
+ bp->cnic_data = data;
+
+ 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));
+
+ 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;
+}
+
+static int bnx2x_unregister_cnic(struct net_device *dev)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+ mutex_lock(&bp->cnic_mutex);
+ if (bp->cnic_flags & BNX2X_CNIC_FLAG_MAC_SET) {
+ bp->cnic_flags &= ~BNX2X_CNIC_FLAG_MAC_SET;
+ bnx2x_set_iscsi_eth_mac_addr(bp, 0);
+ }
+ cp->drv_state = 0;
+ rcu_assign_pointer(bp->cnic_ops, NULL);
+ mutex_unlock(&bp->cnic_mutex);
+ synchronize_rcu();
+ kfree(bp->cnic_kwq);
+ bp->cnic_kwq = NULL;
+
+ return 0;
+}
+
+struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+ cp->drv_owner = THIS_MODULE;
+ cp->chip_id = CHIP_ID(bp);
+ cp->pdev = bp->pdev;
+ 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_tbl_len = CNIC_ILT_LINES;
+ cp->starting_cid = BCM_CNIC_CID_START;
+ 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;
+
+ return cp;
+}
+EXPORT_SYMBOL(bnx2x_cnic_probe);
+
+#endif /* BCM_CNIC */
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index c3fa31c9f2a7..3cd8153b906c 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -1956,7 +1956,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
struct port *port, *prev_port, *temp_port;
struct aggregator *aggregator, *new_aggregator, *temp_aggregator;
int select_new_active_agg = 0;
-
+
// find the aggregator related to this slave
aggregator = &(SLAVE_AD_INFO(slave).aggregator);
@@ -2024,7 +2024,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
// clear the aggregator
ad_clear_agg(aggregator);
-
+
if (select_new_active_agg) {
ad_agg_selection_logic(__get_first_agg(port));
}
@@ -2075,7 +2075,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
}
}
}
- port->slave=NULL;
+ port->slave=NULL;
}
/**
@@ -2301,7 +2301,7 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
}
/*
- * set link state for bonding master: if we have an active
+ * set link state for bonding master: if we have an active
* aggregator, we're up, if not, we're down. Presumes that we cannot
* have an active aggregator if there are no slaves with link up.
*
@@ -2395,7 +2395,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
goto out;
}
- slave_agg_no = bond->xmit_hash_policy(skb, dev, slaves_in_agg);
+ slave_agg_no = bond->xmit_hash_policy(skb, slaves_in_agg);
bond_for_each_slave(bond, slave, i) {
struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
@@ -2468,4 +2468,3 @@ out:
return ret;
}
-
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 9b5936f072dc..a1e7eb92bbf1 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -559,7 +559,7 @@ static void rlb_update_rx_clients(struct bonding *bond)
}
}
- /* do not update the entries again untill this counter is zero so that
+ /* do not update the entries again until this counter is zero so that
* not to confuse the clients.
*/
bond_info->rlb_update_delay_counter = RLB_UPDATE_DELAY;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 69c5b15e22da..8c5ebfb0680f 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -94,6 +94,7 @@ static int downdelay;
static int use_carrier = 1;
static char *mode;
static char *primary;
+static char *primary_reselect;
static char *lacp_rate;
static char *ad_select;
static char *xmit_hash_policy;
@@ -126,6 +127,14 @@ MODULE_PARM_DESC(mode, "Mode of operation : 0 for balance-rr, "
"6 for balance-alb");
module_param(primary, charp, 0);
MODULE_PARM_DESC(primary, "Primary network device to use");
+module_param(primary_reselect, charp, 0);
+MODULE_PARM_DESC(primary_reselect, "Reselect primary slave "
+ "once it comes up; "
+ "0 for always (default), "
+ "1 for only if speed of primary is "
+ "better, "
+ "2 for only on active slave "
+ "failure");
module_param(lacp_rate, charp, 0);
MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner "
"(slow/fast)");
@@ -200,6 +209,13 @@ const struct bond_parm_tbl fail_over_mac_tbl[] = {
{ NULL, -1},
};
+const struct bond_parm_tbl pri_reselect_tbl[] = {
+{ "always", BOND_PRI_RESELECT_ALWAYS},
+{ "better", BOND_PRI_RESELECT_BETTER},
+{ "failure", BOND_PRI_RESELECT_FAILURE},
+{ NULL, -1},
+};
+
struct bond_parm_tbl ad_select_tbl[] = {
{ "stable", BOND_AD_STABLE},
{ "bandwidth", BOND_AD_BANDWIDTH},
@@ -1070,6 +1086,25 @@ out:
}
+static bool bond_should_change_active(struct bonding *bond)
+{
+ struct slave *prim = bond->primary_slave;
+ struct slave *curr = bond->curr_active_slave;
+
+ if (!prim || !curr || curr->link != BOND_LINK_UP)
+ return true;
+ if (bond->force_primary) {
+ bond->force_primary = false;
+ return true;
+ }
+ if (bond->params.primary_reselect == BOND_PRI_RESELECT_BETTER &&
+ (prim->speed < curr->speed ||
+ (prim->speed == curr->speed && prim->duplex <= curr->duplex)))
+ return false;
+ if (bond->params.primary_reselect == BOND_PRI_RESELECT_FAILURE)
+ return false;
+ return true;
+}
/**
* find_best_interface - select the best available slave to be the active one
@@ -1084,7 +1119,7 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
int mintime = bond->params.updelay;
int i;
- new_active = old_active = bond->curr_active_slave;
+ new_active = bond->curr_active_slave;
if (!new_active) { /* there were no active slaves left */
if (bond->slave_cnt > 0) /* found one slave */
@@ -1094,7 +1129,8 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
}
if ((bond->primary_slave) &&
- bond->primary_slave->link == BOND_LINK_UP) {
+ bond->primary_slave->link == BOND_LINK_UP &&
+ bond_should_change_active(bond)) {
new_active = bond->primary_slave;
}
@@ -1678,8 +1714,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) {
/* if there is a primary slave, remember it */
- if (strcmp(bond->params.primary, new_slave->dev->name) == 0)
+ if (strcmp(bond->params.primary, new_slave->dev->name) == 0) {
bond->primary_slave = new_slave;
+ bond->force_primary = true;
+ }
}
write_lock_bh(&bond->curr_slave_lock);
@@ -3201,11 +3239,14 @@ static void bond_info_show_master(struct seq_file *seq)
}
if (USES_PRIMARY(bond->params.mode)) {
- seq_printf(seq, "Primary Slave: %s\n",
+ seq_printf(seq, "Primary Slave: %s",
(bond->primary_slave) ?
bond->primary_slave->dev->name : "None");
+ if (bond->primary_slave)
+ seq_printf(seq, " (primary_reselect %s)",
+ pri_reselect_tbl[bond->params.primary_reselect].modename);
- seq_printf(seq, "Currently Active Slave: %s\n",
+ seq_printf(seq, "\nCurrently Active Slave: %s\n",
(curr) ? curr->dev->name : "None");
}
@@ -3334,7 +3375,7 @@ static const struct file_operations bond_info_fops = {
.release = seq_release,
};
-static int bond_create_proc_entry(struct bonding *bond)
+static void bond_create_proc_entry(struct bonding *bond)
{
struct net_device *bond_dev = bond->dev;
@@ -3349,8 +3390,6 @@ static int bond_create_proc_entry(struct bonding *bond)
else
memcpy(bond->proc_file_name, bond_dev->name, IFNAMSIZ);
}
-
- return 0;
}
static void bond_remove_proc_entry(struct bonding *bond)
@@ -3389,7 +3428,7 @@ static void bond_destroy_proc_dir(void)
#else /* !CONFIG_PROC_FS */
-static int bond_create_proc_entry(struct bonding *bond)
+static void bond_create_proc_entry(struct bonding *bond)
{
}
@@ -3657,18 +3696,17 @@ void bond_unregister_arp(struct bonding *bond)
* Hash for the output device based upon layer 2 and layer 3 data. If
* the packet is not IP mimic bond_xmit_hash_policy_l2()
*/
-static int bond_xmit_hash_policy_l23(struct sk_buff *skb,
- struct net_device *bond_dev, int count)
+static int bond_xmit_hash_policy_l23(struct sk_buff *skb, int count)
{
struct ethhdr *data = (struct ethhdr *)skb->data;
struct iphdr *iph = ip_hdr(skb);
if (skb->protocol == htons(ETH_P_IP)) {
return ((ntohl(iph->saddr ^ iph->daddr) & 0xffff) ^
- (data->h_dest[5] ^ bond_dev->dev_addr[5])) % count;
+ (data->h_dest[5] ^ data->h_source[5])) % count;
}
- return (data->h_dest[5] ^ bond_dev->dev_addr[5]) % count;
+ return (data->h_dest[5] ^ data->h_source[5]) % count;
}
/*
@@ -3676,8 +3714,7 @@ static int bond_xmit_hash_policy_l23(struct sk_buff *skb,
* the packet is a frag or not TCP or UDP, just use layer 3 data. If it is
* altogether not IP, mimic bond_xmit_hash_policy_l2()
*/
-static int bond_xmit_hash_policy_l34(struct sk_buff *skb,
- struct net_device *bond_dev, int count)
+static int bond_xmit_hash_policy_l34(struct sk_buff *skb, int count)
{
struct ethhdr *data = (struct ethhdr *)skb->data;
struct iphdr *iph = ip_hdr(skb);
@@ -3695,18 +3732,17 @@ static int bond_xmit_hash_policy_l34(struct sk_buff *skb,
}
- return (data->h_dest[5] ^ bond_dev->dev_addr[5]) % count;
+ return (data->h_dest[5] ^ data->h_source[5]) % count;
}
/*
* Hash for the output device based upon layer 2 data
*/
-static int bond_xmit_hash_policy_l2(struct sk_buff *skb,
- struct net_device *bond_dev, int count)
+static int bond_xmit_hash_policy_l2(struct sk_buff *skb, int count)
{
struct ethhdr *data = (struct ethhdr *)skb->data;
- return (data->h_dest[5] ^ bond_dev->dev_addr[5]) % count;
+ return (data->h_dest[5] ^ data->h_source[5]) % count;
}
/*-------------------------- Device entry points ----------------------------*/
@@ -4295,7 +4331,7 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
if (!BOND_IS_OK(bond))
goto out;
- slave_no = bond->xmit_hash_policy(skb, bond_dev, bond->slave_cnt);
+ slave_no = bond->xmit_hash_policy(skb, bond->slave_cnt);
bond_for_each_slave(bond, slave, i) {
slave_no--;
@@ -4646,7 +4682,7 @@ int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl)
static int bond_check_params(struct bond_params *params)
{
- int arp_validate_value, fail_over_mac_value;
+ int arp_validate_value, fail_over_mac_value, primary_reselect_value;
/*
* Convert string parameters.
@@ -4665,7 +4701,8 @@ static int bond_check_params(struct bond_params *params)
if ((bond_mode != BOND_MODE_XOR) &&
(bond_mode != BOND_MODE_8023AD)) {
pr_info(DRV_NAME
- ": xor_mode param is irrelevant in mode %s\n",
+ ": xmit_hash_policy param is irrelevant in"
+ " mode %s\n",
bond_mode_name(bond_mode));
} else {
xmit_hashtype = bond_parse_parm(xmit_hash_policy,
@@ -4945,6 +4982,20 @@ static int bond_check_params(struct bond_params *params)
primary = NULL;
}
+ if (primary && primary_reselect) {
+ primary_reselect_value = bond_parse_parm(primary_reselect,
+ pri_reselect_tbl);
+ if (primary_reselect_value == -1) {
+ pr_err(DRV_NAME
+ ": Error: Invalid primary_reselect \"%s\"\n",
+ primary_reselect ==
+ NULL ? "NULL" : primary_reselect);
+ return -EINVAL;
+ }
+ } else {
+ primary_reselect_value = BOND_PRI_RESELECT_ALWAYS;
+ }
+
if (fail_over_mac) {
fail_over_mac_value = bond_parse_parm(fail_over_mac,
fail_over_mac_tbl);
@@ -4976,6 +5027,7 @@ static int bond_check_params(struct bond_params *params)
params->use_carrier = use_carrier;
params->lacp_fast = lacp_fast;
params->primary[0] = 0;
+ params->primary_reselect = primary_reselect_value;
params->fail_over_mac = fail_over_mac_value;
if (primary) {
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 8762a27a2a18..535b457f5d4c 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -1214,6 +1214,58 @@ static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR,
bonding_show_primary, bonding_store_primary);
/*
+ * Show and set the primary_reselect flag.
+ */
+static ssize_t bonding_show_primary_reselect(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct bonding *bond = to_bond(d);
+
+ return sprintf(buf, "%s %d\n",
+ pri_reselect_tbl[bond->params.primary_reselect].modename,
+ bond->params.primary_reselect);
+}
+
+static ssize_t bonding_store_primary_reselect(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 (!rtnl_trylock())
+ return restart_syscall();
+
+ new_value = bond_parse_parm(buf, pri_reselect_tbl);
+ if (new_value < 0) {
+ pr_err(DRV_NAME
+ ": %s: Ignoring invalid primary_reselect value %.*s.\n",
+ bond->dev->name,
+ (int) strlen(buf) - 1, buf);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ bond->params.primary_reselect = new_value;
+ pr_info(DRV_NAME ": %s: setting primary_reselect to %s (%d).\n",
+ bond->dev->name, pri_reselect_tbl[new_value].modename,
+ new_value);
+
+ 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);
+out:
+ rtnl_unlock();
+ return ret;
+}
+static DEVICE_ATTR(primary_reselect, S_IRUGO | S_IWUSR,
+ bonding_show_primary_reselect,
+ bonding_store_primary_reselect);
+
+/*
* Show and set the use_carrier flag.
*/
static ssize_t bonding_show_carrier(struct device *d,
@@ -1502,6 +1554,7 @@ static struct attribute *per_bond_attrs[] = {
&dev_attr_num_unsol_na.attr,
&dev_attr_miimon.attr,
&dev_attr_primary.attr,
+ &dev_attr_primary_reselect.attr,
&dev_attr_use_carrier.attr,
&dev_attr_active_slave.attr,
&dev_attr_mii_status.attr,
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 68247714466f..9b520b05fbac 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -23,8 +23,8 @@
#include "bond_3ad.h"
#include "bond_alb.h"
-#define DRV_VERSION "3.5.0"
-#define DRV_RELDATE "November 4, 2008"
+#define DRV_VERSION "3.6.0"
+#define DRV_RELDATE "September 26, 2009"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
@@ -131,6 +131,7 @@ struct bond_params {
int lacp_fast;
int ad_select;
char primary[IFNAMSIZ];
+ int primary_reselect;
__be32 arp_targets[BOND_MAX_ARP_TARGETS];
};
@@ -190,6 +191,7 @@ struct bonding {
struct slave *curr_active_slave;
struct slave *current_arp_slave;
struct slave *primary_slave;
+ bool force_primary;
s32 slave_cnt; /* never change this value outside the attach/detach wrappers */
rwlock_t lock;
rwlock_t curr_slave_lock;
@@ -204,7 +206,7 @@ struct bonding {
#endif /* CONFIG_PROC_FS */
struct list_head bond_list;
struct dev_mc_list *mc_list;
- int (*xmit_hash_policy)(struct sk_buff *, struct net_device *, int);
+ int (*xmit_hash_policy)(struct sk_buff *, int);
__be32 master_ip;
u16 flags;
u16 rr_tx_counter;
@@ -258,6 +260,10 @@ static inline bool bond_is_lb(const struct bonding *bond)
|| bond->params.mode == BOND_MODE_ALB;
}
+#define BOND_PRI_RESELECT_ALWAYS 0
+#define BOND_PRI_RESELECT_BETTER 1
+#define BOND_PRI_RESELECT_FAILURE 2
+
#define BOND_FOM_NONE 0
#define BOND_FOM_ACTIVE 1
#define BOND_FOM_FOLLOW 2
@@ -348,6 +354,7 @@ extern const struct bond_parm_tbl bond_mode_tbl[];
extern const struct bond_parm_tbl xmit_hashtype_tbl[];
extern const struct bond_parm_tbl arp_validate_tbl[];
extern const struct bond_parm_tbl fail_over_mac_tbl[];
+extern const struct bond_parm_tbl pri_reselect_tbl[];
extern struct bond_parm_tbl ad_select_tbl[];
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -370,4 +377,3 @@ static inline void bond_unregister_ipv6_notifier(void)
#endif
#endif /* _LINUX_BONDING_H */
-
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index df32c109b7ac..26d77cc0ded7 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -95,6 +95,13 @@ config CAN_AT91
---help---
This is a driver for the SoC CAN controller in Atmel's AT91SAM9263.
+config CAN_TI_HECC
+ depends on CAN_DEV && ARCH_OMAP3
+ tristate "TI High End CAN Controller"
+ ---help---
+ Driver for TI HECC (High End CAN Controller) module found on many
+ TI devices. The device specifications are available from www.ti.com
+
config CAN_DEBUG_DEVICES
bool "CAN devices debugging messages"
depends on CAN
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 0dea62721f2f..31f4ab5df28b 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -11,5 +11,6 @@ obj-y += usb/
obj-$(CONFIG_CAN_SJA1000) += sja1000/
obj-$(CONFIG_CAN_AT91) += at91_can.o
+obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
index f67ae285a35a..cbe3fce53e3b 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -221,38 +221,6 @@ static inline void set_mb_mode(const struct at91_priv *priv, unsigned int mb,
set_mb_mode_prio(priv, mb, mode, 0);
}
-static struct sk_buff *alloc_can_skb(struct net_device *dev,
- struct can_frame **cf)
-{
- struct sk_buff *skb;
-
- skb = netdev_alloc_skb(dev, sizeof(struct can_frame));
- if (unlikely(!skb))
- return NULL;
-
- skb->protocol = htons(ETH_P_CAN);
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- *cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
-
- return skb;
-}
-
-static struct sk_buff *alloc_can_err_skb(struct net_device *dev,
- struct can_frame **cf)
-{
- struct sk_buff *skb;
-
- skb = alloc_can_skb(dev, cf);
- if (unlikely(!skb))
- return NULL;
-
- memset(*cf, 0, sizeof(struct can_frame));
- (*cf)->can_id = CAN_ERR_FLAG;
- (*cf)->can_dlc = CAN_ERR_DLC;
-
- return skb;
-}
-
/*
* Swtich transceiver on or off
*/
@@ -1087,7 +1055,7 @@ static int __init at91_can_probe(struct platform_device *pdev)
goto exit_release;
}
- dev = alloc_candev(sizeof(struct at91_priv));
+ dev = alloc_candev(sizeof(struct at91_priv), AT91_MB_TX_NUM);
if (!dev) {
err = -ENOMEM;
goto exit_iounmap;
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
index f0b9a1e1db46..c3db111d2ff5 100644
--- a/drivers/net/can/dev.c
+++ b/drivers/net/can/dev.c
@@ -245,7 +245,7 @@ static void can_flush_echo_skb(struct net_device *dev)
struct net_device_stats *stats = &dev->stats;
int i;
- for (i = 0; i < CAN_ECHO_SKB_MAX; i++) {
+ for (i = 0; i < priv->echo_skb_max; i++) {
if (priv->echo_skb[i]) {
kfree_skb(priv->echo_skb[i]);
priv->echo_skb[i] = NULL;
@@ -262,10 +262,13 @@ static void can_flush_echo_skb(struct net_device *dev)
* of the device driver. The driver must protect access to
* priv->echo_skb, if necessary.
*/
-void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, int idx)
+void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
+ unsigned int idx)
{
struct can_priv *priv = netdev_priv(dev);
+ BUG_ON(idx >= priv->echo_skb_max);
+
/* check flag whether this packet has to be looped back */
if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK) {
kfree_skb(skb);
@@ -311,10 +314,12 @@ EXPORT_SYMBOL_GPL(can_put_echo_skb);
* is handled in the device driver. The driver must protect
* access to priv->echo_skb, if necessary.
*/
-void can_get_echo_skb(struct net_device *dev, int idx)
+void can_get_echo_skb(struct net_device *dev, unsigned int idx)
{
struct can_priv *priv = netdev_priv(dev);
+ BUG_ON(idx >= priv->echo_skb_max);
+
if (priv->echo_skb[idx]) {
netif_rx(priv->echo_skb[idx]);
priv->echo_skb[idx] = NULL;
@@ -327,10 +332,12 @@ EXPORT_SYMBOL_GPL(can_get_echo_skb);
*
* The function is typically called when TX failed.
*/
-void can_free_echo_skb(struct net_device *dev, int idx)
+void can_free_echo_skb(struct net_device *dev, unsigned int idx)
{
struct can_priv *priv = netdev_priv(dev);
+ BUG_ON(idx >= priv->echo_skb_max);
+
if (priv->echo_skb[idx]) {
kfree_skb(priv->echo_skb[idx]);
priv->echo_skb[idx] = NULL;
@@ -359,17 +366,12 @@ void can_restart(unsigned long data)
can_flush_echo_skb(dev);
/* send restart message upstream */
- skb = dev_alloc_skb(sizeof(struct can_frame));
+ skb = alloc_can_err_skb(dev, &cf);
if (skb == NULL) {
err = -ENOMEM;
goto restart;
}
- skb->dev = dev;
- skb->protocol = htons(ETH_P_CAN);
- cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
- memset(cf, 0, sizeof(struct can_frame));
- cf->can_id = CAN_ERR_FLAG | CAN_ERR_RESTARTED;
- cf->can_dlc = CAN_ERR_DLC;
+ cf->can_id |= CAN_ERR_RESTARTED;
netif_rx(skb);
@@ -442,20 +444,66 @@ static void can_setup(struct net_device *dev)
dev->features = NETIF_F_NO_CSUM;
}
+struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
+{
+ struct sk_buff *skb;
+
+ skb = netdev_alloc_skb(dev, sizeof(struct can_frame));
+ if (unlikely(!skb))
+ return NULL;
+
+ skb->protocol = htons(ETH_P_CAN);
+ skb->pkt_type = PACKET_BROADCAST;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ *cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
+ memset(*cf, 0, sizeof(struct can_frame));
+
+ return skb;
+}
+EXPORT_SYMBOL_GPL(alloc_can_skb);
+
+struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf)
+{
+ struct sk_buff *skb;
+
+ skb = alloc_can_skb(dev, cf);
+ if (unlikely(!skb))
+ return NULL;
+
+ (*cf)->can_id = CAN_ERR_FLAG;
+ (*cf)->can_dlc = CAN_ERR_DLC;
+
+ return skb;
+}
+EXPORT_SYMBOL_GPL(alloc_can_err_skb);
+
/*
* Allocate and setup space for the CAN network device
*/
-struct net_device *alloc_candev(int sizeof_priv)
+struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max)
{
struct net_device *dev;
struct can_priv *priv;
+ int size;
- dev = alloc_netdev(sizeof_priv, "can%d", can_setup);
+ if (echo_skb_max)
+ size = ALIGN(sizeof_priv, sizeof(struct sk_buff *)) +
+ echo_skb_max * sizeof(struct sk_buff *);
+ else
+ size = sizeof_priv;
+
+ dev = alloc_netdev(size, "can%d", can_setup);
if (!dev)
return NULL;
priv = netdev_priv(dev);
+ if (echo_skb_max) {
+ priv->echo_skb_max = echo_skb_max;
+ priv->echo_skb = (void *)priv +
+ ALIGN(sizeof_priv, sizeof(struct sk_buff *));
+ }
+
priv->state = CAN_STATE_STOPPED;
init_timer(&priv->restart_timer);
diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
index 16d2ecd2a3b7..782a47fabf2c 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -296,11 +296,9 @@ static void sja1000_rx(struct net_device *dev)
uint8_t dlc;
int i;
- skb = dev_alloc_skb(sizeof(struct can_frame));
+ skb = alloc_can_skb(dev, &cf);
if (skb == NULL)
return;
- skb->dev = dev;
- skb->protocol = htons(ETH_P_CAN);
fi = priv->read_reg(priv, REG_FI);
dlc = fi & 0x0F;
@@ -323,8 +321,6 @@ static void sja1000_rx(struct net_device *dev)
if (fi & FI_RTR)
id |= CAN_RTR_FLAG;
- cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
- memset(cf, 0, sizeof(struct can_frame));
cf->can_id = id;
cf->can_dlc = dlc;
for (i = 0; i < dlc; i++)
@@ -351,15 +347,9 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
enum can_state state = priv->can.state;
uint8_t ecc, alc;
- skb = dev_alloc_skb(sizeof(struct can_frame));
+ skb = alloc_can_err_skb(dev, &cf);
if (skb == NULL)
return -ENOMEM;
- skb->dev = dev;
- skb->protocol = htons(ETH_P_CAN);
- cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
- memset(cf, 0, sizeof(struct can_frame));
- cf->can_id = CAN_ERR_FLAG;
- cf->can_dlc = CAN_ERR_DLC;
if (isrc & IRQ_DOI) {
/* data overrun interrupt */
@@ -565,7 +555,8 @@ struct net_device *alloc_sja1000dev(int sizeof_priv)
struct net_device *dev;
struct sja1000_priv *priv;
- dev = alloc_candev(sizeof(struct sja1000_priv) + sizeof_priv);
+ dev = alloc_candev(sizeof(struct sja1000_priv) + sizeof_priv,
+ SJA1000_ECHO_SKB_MAX);
if (!dev)
return NULL;
diff --git a/drivers/net/can/sja1000/sja1000.h b/drivers/net/can/sja1000/sja1000.h
index 302d2c763ad7..97a622b9302f 100644
--- a/drivers/net/can/sja1000/sja1000.h
+++ b/drivers/net/can/sja1000/sja1000.h
@@ -50,6 +50,8 @@
#include <linux/can/dev.h>
#include <linux/can/platform/sja1000.h>
+#define SJA1000_ECHO_SKB_MAX 1 /* the SJA1000 has one TX buffer object */
+
#define SJA1000_MAX_IRQ 20 /* max. number of interrupts handled in ISR */
/* SJA1000 registers - manual section 6.4 (Pelican Mode) */
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
new file mode 100644
index 000000000000..07e8016b17ec
--- /dev/null
+++ b/drivers/net/can/ti_hecc.c
@@ -0,0 +1,993 @@
+/*
+ * TI HECC (CAN) device driver
+ *
+ * This driver supports TI's HECC (High End CAN Controller module) and the
+ * specs for the same is available at <http://www.ti.com>
+ *
+ * Copyright (C) 2009 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 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.
+ *
+ */
+
+/*
+ * Your platform definitions should specify module ram offsets and interrupt
+ * number to use as follows:
+ *
+ * static struct ti_hecc_platform_data am3517_evm_hecc_pdata = {
+ * .scc_hecc_offset = 0,
+ * .scc_ram_offset = 0x3000,
+ * .hecc_ram_offset = 0x3000,
+ * .mbx_offset = 0x2000,
+ * .int_line = 0,
+ * .revision = 1,
+ * };
+ *
+ * Please see include/can/platform/ti_hecc.h for description of above fields
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+#include <linux/can/platform/ti_hecc.h>
+
+#define DRV_NAME "ti_hecc"
+#define HECC_MODULE_VERSION "0.7"
+MODULE_VERSION(HECC_MODULE_VERSION);
+#define DRV_DESC "TI High End CAN Controller Driver " HECC_MODULE_VERSION
+
+/* TX / RX Mailbox Configuration */
+#define HECC_MAX_MAILBOXES 32 /* hardware mailboxes - do not change */
+#define MAX_TX_PRIO 0x3F /* hardware value - do not change */
+
+/*
+ * Important Note: TX mailbox configuration
+ * TX mailboxes should be restricted to the number of SKB buffers to avoid
+ * maintaining SKB buffers separately. TX mailboxes should be a power of 2
+ * for the mailbox logic to work. Top mailbox numbers are reserved for RX
+ * and lower mailboxes for TX.
+ *
+ * HECC_MAX_TX_MBOX HECC_MB_TX_SHIFT
+ * 4 (default) 2
+ * 8 3
+ * 16 4
+ */
+#define HECC_MB_TX_SHIFT 2 /* as per table above */
+#define HECC_MAX_TX_MBOX BIT(HECC_MB_TX_SHIFT)
+
+#define HECC_TX_PRIO_SHIFT (HECC_MB_TX_SHIFT)
+#define HECC_TX_PRIO_MASK (MAX_TX_PRIO << HECC_MB_TX_SHIFT)
+#define HECC_TX_MB_MASK (HECC_MAX_TX_MBOX - 1)
+#define HECC_TX_MASK ((HECC_MAX_TX_MBOX - 1) | HECC_TX_PRIO_MASK)
+#define HECC_TX_MBOX_MASK (~(BIT(HECC_MAX_TX_MBOX) - 1))
+#define HECC_DEF_NAPI_WEIGHT HECC_MAX_RX_MBOX
+
+/*
+ * Important Note: RX mailbox configuration
+ * RX mailboxes are further logically split into two - main and buffer
+ * mailboxes. The goal is to get all packets into main mailboxes as
+ * driven by mailbox number and receive priority (higher to lower) and
+ * buffer mailboxes are used to receive pkts while main mailboxes are being
+ * processed. This ensures in-order packet reception.
+ *
+ * Here are the recommended values for buffer mailbox. Note that RX mailboxes
+ * start after TX mailboxes:
+ *
+ * HECC_MAX_RX_MBOX HECC_RX_BUFFER_MBOX No of buffer mailboxes
+ * 28 12 8
+ * 16 20 4
+ */
+
+#define HECC_MAX_RX_MBOX (HECC_MAX_MAILBOXES - HECC_MAX_TX_MBOX)
+#define HECC_RX_BUFFER_MBOX 12 /* as per table above */
+#define HECC_RX_FIRST_MBOX (HECC_MAX_MAILBOXES - 1)
+#define HECC_RX_HIGH_MBOX_MASK (~(BIT(HECC_RX_BUFFER_MBOX) - 1))
+
+/* TI HECC module registers */
+#define HECC_CANME 0x0 /* Mailbox enable */
+#define HECC_CANMD 0x4 /* Mailbox direction */
+#define HECC_CANTRS 0x8 /* Transmit request set */
+#define HECC_CANTRR 0xC /* Transmit request */
+#define HECC_CANTA 0x10 /* Transmission acknowledge */
+#define HECC_CANAA 0x14 /* Abort acknowledge */
+#define HECC_CANRMP 0x18 /* Receive message pending */
+#define HECC_CANRML 0x1C /* Remote message lost */
+#define HECC_CANRFP 0x20 /* Remote frame pending */
+#define HECC_CANGAM 0x24 /* SECC only:Global acceptance mask */
+#define HECC_CANMC 0x28 /* Master control */
+#define HECC_CANBTC 0x2C /* Bit timing configuration */
+#define HECC_CANES 0x30 /* Error and status */
+#define HECC_CANTEC 0x34 /* Transmit error counter */
+#define HECC_CANREC 0x38 /* Receive error counter */
+#define HECC_CANGIF0 0x3C /* Global interrupt flag 0 */
+#define HECC_CANGIM 0x40 /* Global interrupt mask */
+#define HECC_CANGIF1 0x44 /* Global interrupt flag 1 */
+#define HECC_CANMIM 0x48 /* Mailbox interrupt mask */
+#define HECC_CANMIL 0x4C /* Mailbox interrupt level */
+#define HECC_CANOPC 0x50 /* Overwrite protection control */
+#define HECC_CANTIOC 0x54 /* Transmit I/O control */
+#define HECC_CANRIOC 0x58 /* Receive I/O control */
+#define HECC_CANLNT 0x5C /* HECC only: Local network time */
+#define HECC_CANTOC 0x60 /* HECC only: Time-out control */
+#define HECC_CANTOS 0x64 /* HECC only: Time-out status */
+#define HECC_CANTIOCE 0x68 /* SCC only:Enhanced TX I/O control */
+#define HECC_CANRIOCE 0x6C /* SCC only:Enhanced RX I/O control */
+
+/* Mailbox registers */
+#define HECC_CANMID 0x0
+#define HECC_CANMCF 0x4
+#define HECC_CANMDL 0x8
+#define HECC_CANMDH 0xC
+
+#define HECC_SET_REG 0xFFFFFFFF
+#define HECC_CANID_MASK 0x3FF /* 18 bits mask for extended id's */
+#define HECC_CCE_WAIT_COUNT 100 /* Wait for ~1 sec for CCE bit */
+
+#define HECC_CANMC_SCM BIT(13) /* SCC compat mode */
+#define HECC_CANMC_CCR BIT(12) /* Change config request */
+#define HECC_CANMC_PDR BIT(11) /* Local Power down - for sleep mode */
+#define HECC_CANMC_ABO BIT(7) /* Auto Bus On */
+#define HECC_CANMC_STM BIT(6) /* Self test mode - loopback */
+#define HECC_CANMC_SRES BIT(5) /* Software reset */
+
+#define HECC_CANTIOC_EN BIT(3) /* Enable CAN TX I/O pin */
+#define HECC_CANRIOC_EN BIT(3) /* Enable CAN RX I/O pin */
+
+#define HECC_CANMID_IDE BIT(31) /* Extended frame format */
+#define HECC_CANMID_AME BIT(30) /* Acceptance mask enable */
+#define HECC_CANMID_AAM BIT(29) /* Auto answer mode */
+
+#define HECC_CANES_FE BIT(24) /* form error */
+#define HECC_CANES_BE BIT(23) /* bit error */
+#define HECC_CANES_SA1 BIT(22) /* stuck at dominant error */
+#define HECC_CANES_CRCE BIT(21) /* CRC error */
+#define HECC_CANES_SE BIT(20) /* stuff bit error */
+#define HECC_CANES_ACKE BIT(19) /* ack error */
+#define HECC_CANES_BO BIT(18) /* Bus off status */
+#define HECC_CANES_EP BIT(17) /* Error passive status */
+#define HECC_CANES_EW BIT(16) /* Error warning status */
+#define HECC_CANES_SMA BIT(5) /* suspend mode ack */
+#define HECC_CANES_CCE BIT(4) /* Change config enabled */
+#define HECC_CANES_PDA BIT(3) /* Power down mode ack */
+
+#define HECC_CANBTC_SAM BIT(7) /* sample points */
+
+#define HECC_BUS_ERROR (HECC_CANES_FE | HECC_CANES_BE |\
+ HECC_CANES_CRCE | HECC_CANES_SE |\
+ HECC_CANES_ACKE)
+
+#define HECC_CANMCF_RTR BIT(4) /* Remote transmit request */
+
+#define HECC_CANGIF_MAIF BIT(17) /* Message alarm interrupt */
+#define HECC_CANGIF_TCOIF BIT(16) /* Timer counter overflow int */
+#define HECC_CANGIF_GMIF BIT(15) /* Global mailbox interrupt */
+#define HECC_CANGIF_AAIF BIT(14) /* Abort ack interrupt */
+#define HECC_CANGIF_WDIF BIT(13) /* Write denied interrupt */
+#define HECC_CANGIF_WUIF BIT(12) /* Wake up interrupt */
+#define HECC_CANGIF_RMLIF BIT(11) /* Receive message lost interrupt */
+#define HECC_CANGIF_BOIF BIT(10) /* Bus off interrupt */
+#define HECC_CANGIF_EPIF BIT(9) /* Error passive interrupt */
+#define HECC_CANGIF_WLIF BIT(8) /* Warning level interrupt */
+#define HECC_CANGIF_MBOX_MASK 0x1F /* Mailbox number mask */
+#define HECC_CANGIM_I1EN BIT(1) /* Int line 1 enable */
+#define HECC_CANGIM_I0EN BIT(0) /* Int line 0 enable */
+#define HECC_CANGIM_DEF_MASK 0x700 /* only busoff/warning/passive */
+#define HECC_CANGIM_SIL BIT(2) /* system interrupts to int line 1 */
+
+/* CAN Bittiming constants as per HECC specs */
+static struct can_bittiming_const ti_hecc_bittiming_const = {
+ .name = DRV_NAME,
+ .tseg1_min = 1,
+ .tseg1_max = 16,
+ .tseg2_min = 1,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 256,
+ .brp_inc = 1,
+};
+
+struct ti_hecc_priv {
+ struct can_priv can; /* MUST be first member/field */
+ struct napi_struct napi;
+ struct net_device *ndev;
+ struct clk *clk;
+ void __iomem *base;
+ u32 scc_ram_offset;
+ u32 hecc_ram_offset;
+ u32 mbx_offset;
+ u32 int_line;
+ spinlock_t mbx_lock; /* CANME register needs protection */
+ u32 tx_head;
+ u32 tx_tail;
+ u32 rx_next;
+};
+
+static inline int get_tx_head_mb(struct ti_hecc_priv *priv)
+{
+ return priv->tx_head & HECC_TX_MB_MASK;
+}
+
+static inline int get_tx_tail_mb(struct ti_hecc_priv *priv)
+{
+ return priv->tx_tail & HECC_TX_MB_MASK;
+}
+
+static inline int get_tx_head_prio(struct ti_hecc_priv *priv)
+{
+ return (priv->tx_head >> HECC_TX_PRIO_SHIFT) & MAX_TX_PRIO;
+}
+
+static inline void hecc_write_lam(struct ti_hecc_priv *priv, u32 mbxno, u32 val)
+{
+ __raw_writel(val, priv->base + priv->hecc_ram_offset + mbxno * 4);
+}
+
+static inline void hecc_write_mbx(struct ti_hecc_priv *priv, u32 mbxno,
+ u32 reg, u32 val)
+{
+ __raw_writel(val, priv->base + priv->mbx_offset + mbxno * 0x10 +
+ reg);
+}
+
+static inline u32 hecc_read_mbx(struct ti_hecc_priv *priv, u32 mbxno, u32 reg)
+{
+ return __raw_readl(priv->base + priv->mbx_offset + mbxno * 0x10 +
+ reg);
+}
+
+static inline void hecc_write(struct ti_hecc_priv *priv, u32 reg, u32 val)
+{
+ __raw_writel(val, priv->base + reg);
+}
+
+static inline u32 hecc_read(struct ti_hecc_priv *priv, int reg)
+{
+ return __raw_readl(priv->base + reg);
+}
+
+static inline void hecc_set_bit(struct ti_hecc_priv *priv, int reg,
+ u32 bit_mask)
+{
+ hecc_write(priv, reg, hecc_read(priv, reg) | bit_mask);
+}
+
+static inline void hecc_clear_bit(struct ti_hecc_priv *priv, int reg,
+ u32 bit_mask)
+{
+ hecc_write(priv, reg, hecc_read(priv, reg) & ~bit_mask);
+}
+
+static inline u32 hecc_get_bit(struct ti_hecc_priv *priv, int reg, u32 bit_mask)
+{
+ return (hecc_read(priv, reg) & bit_mask) ? 1 : 0;
+}
+
+static int ti_hecc_get_state(const struct net_device *ndev,
+ enum can_state *state)
+{
+ struct ti_hecc_priv *priv = netdev_priv(ndev);
+
+ *state = priv->can.state;
+ return 0;
+}
+
+static int ti_hecc_set_btc(struct ti_hecc_priv *priv)
+{
+ struct can_bittiming *bit_timing = &priv->can.bittiming;
+ u32 can_btc;
+
+ can_btc = (bit_timing->phase_seg2 - 1) & 0x7;
+ can_btc |= ((bit_timing->phase_seg1 + bit_timing->prop_seg - 1)
+ & 0xF) << 3;
+ if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) {
+ if (bit_timing->brp > 4)
+ can_btc |= HECC_CANBTC_SAM;
+ else
+ dev_warn(priv->ndev->dev.parent, "WARN: Triple" \
+ "sampling not set due to h/w limitations");
+ }
+ can_btc |= ((bit_timing->sjw - 1) & 0x3) << 8;
+ can_btc |= ((bit_timing->brp - 1) & 0xFF) << 16;
+
+ /* ERM being set to 0 by default meaning resync at falling edge */
+
+ hecc_write(priv, HECC_CANBTC, can_btc);
+ dev_info(priv->ndev->dev.parent, "setting CANBTC=%#x\n", can_btc);
+
+ return 0;
+}
+
+static void ti_hecc_reset(struct net_device *ndev)
+{
+ u32 cnt;
+ struct ti_hecc_priv *priv = netdev_priv(ndev);
+
+ dev_dbg(ndev->dev.parent, "resetting hecc ...\n");
+ hecc_set_bit(priv, HECC_CANMC, HECC_CANMC_SRES);
+
+ /* Set change control request and wait till enabled */
+ hecc_set_bit(priv, HECC_CANMC, HECC_CANMC_CCR);
+
+ /*
+ * INFO: It has been observed that at times CCE bit may not be
+ * set and hw seems to be ok even if this bit is not set so
+ * timing out with a timing of 1ms to respect the specs
+ */
+ cnt = HECC_CCE_WAIT_COUNT;
+ while (!hecc_get_bit(priv, HECC_CANES, HECC_CANES_CCE) && cnt != 0) {
+ --cnt;
+ udelay(10);
+ }
+
+ /*
+ * Note: On HECC, BTC can be programmed only in initialization mode, so
+ * it is expected that the can bittiming parameters are set via ip
+ * utility before the device is opened
+ */
+ ti_hecc_set_btc(priv);
+
+ /* Clear CCR (and CANMC register) and wait for CCE = 0 enable */
+ hecc_write(priv, HECC_CANMC, 0);
+
+ /*
+ * INFO: CAN net stack handles bus off and hence disabling auto-bus-on
+ * hecc_set_bit(priv, HECC_CANMC, HECC_CANMC_ABO);
+ */
+
+ /*
+ * INFO: It has been observed that at times CCE bit may not be
+ * set and hw seems to be ok even if this bit is not set so
+ */
+ cnt = HECC_CCE_WAIT_COUNT;
+ while (hecc_get_bit(priv, HECC_CANES, HECC_CANES_CCE) && cnt != 0) {
+ --cnt;
+ udelay(10);
+ }
+
+ /* Enable TX and RX I/O Control pins */
+ hecc_write(priv, HECC_CANTIOC, HECC_CANTIOC_EN);
+ hecc_write(priv, HECC_CANRIOC, HECC_CANRIOC_EN);
+
+ /* Clear registers for clean operation */
+ hecc_write(priv, HECC_CANTA, HECC_SET_REG);
+ hecc_write(priv, HECC_CANRMP, HECC_SET_REG);
+ hecc_write(priv, HECC_CANGIF0, HECC_SET_REG);
+ hecc_write(priv, HECC_CANGIF1, HECC_SET_REG);
+ hecc_write(priv, HECC_CANME, 0);
+ hecc_write(priv, HECC_CANMD, 0);
+
+ /* SCC compat mode NOT supported (and not needed too) */
+ hecc_set_bit(priv, HECC_CANMC, HECC_CANMC_SCM);
+}
+
+static void ti_hecc_start(struct net_device *ndev)
+{
+ struct ti_hecc_priv *priv = netdev_priv(ndev);
+ u32 cnt, mbxno, mbx_mask;
+
+ /* put HECC in initialization mode and set btc */
+ ti_hecc_reset(ndev);
+
+ priv->tx_head = priv->tx_tail = HECC_TX_MASK;
+ priv->rx_next = HECC_RX_FIRST_MBOX;
+
+ /* Enable local and global acceptance mask registers */
+ hecc_write(priv, HECC_CANGAM, HECC_SET_REG);
+
+ /* Prepare configured mailboxes to receive messages */
+ for (cnt = 0; cnt < HECC_MAX_RX_MBOX; cnt++) {
+ mbxno = HECC_MAX_MAILBOXES - 1 - cnt;
+ mbx_mask = BIT(mbxno);
+ hecc_clear_bit(priv, HECC_CANME, mbx_mask);
+ hecc_write_mbx(priv, mbxno, HECC_CANMID, HECC_CANMID_AME);
+ hecc_write_lam(priv, mbxno, HECC_SET_REG);
+ hecc_set_bit(priv, HECC_CANMD, mbx_mask);
+ hecc_set_bit(priv, HECC_CANME, mbx_mask);
+ hecc_set_bit(priv, HECC_CANMIM, mbx_mask);
+ }
+
+ /* Prevent message over-write & Enable interrupts */
+ hecc_write(priv, HECC_CANOPC, HECC_SET_REG);
+ if (priv->int_line) {
+ hecc_write(priv, HECC_CANMIL, HECC_SET_REG);
+ hecc_write(priv, HECC_CANGIM, HECC_CANGIM_DEF_MASK |
+ HECC_CANGIM_I1EN | HECC_CANGIM_SIL);
+ } else {
+ hecc_write(priv, HECC_CANMIL, 0);
+ hecc_write(priv, HECC_CANGIM,
+ HECC_CANGIM_DEF_MASK | HECC_CANGIM_I0EN);
+ }
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+}
+
+static void ti_hecc_stop(struct net_device *ndev)
+{
+ struct ti_hecc_priv *priv = netdev_priv(ndev);
+
+ /* Disable interrupts and disable mailboxes */
+ hecc_write(priv, HECC_CANGIM, 0);
+ hecc_write(priv, HECC_CANMIM, 0);
+ hecc_write(priv, HECC_CANME, 0);
+ priv->can.state = CAN_STATE_STOPPED;
+}
+
+static int ti_hecc_do_set_mode(struct net_device *ndev, enum can_mode mode)
+{
+ int ret = 0;
+
+ switch (mode) {
+ case CAN_MODE_START:
+ ti_hecc_start(ndev);
+ netif_wake_queue(ndev);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * ti_hecc_xmit: HECC Transmit
+ *
+ * The transmit mailboxes start from 0 to HECC_MAX_TX_MBOX. In HECC the
+ * priority of the mailbox for tranmission is dependent upon priority setting
+ * field in mailbox registers. The mailbox with highest value in priority field
+ * is transmitted first. Only when two mailboxes have the same value in
+ * priority field the highest numbered mailbox is transmitted first.
+ *
+ * To utilize the HECC priority feature as described above we start with the
+ * highest numbered mailbox with highest priority level and move on to the next
+ * mailbox with the same priority level and so on. Once we loop through all the
+ * transmit mailboxes we choose the next priority level (lower) and so on
+ * until we reach the lowest priority level on the lowest numbered mailbox
+ * when we stop transmission until all mailboxes are transmitted and then
+ * restart at highest numbered mailbox with highest priority.
+ *
+ * Two counters (head and tail) are used to track the next mailbox to transmit
+ * and to track the echo buffer for already transmitted mailbox. The queue
+ * is stopped when all the mailboxes are busy or when there is a priority
+ * value roll-over happens.
+ */
+static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct ti_hecc_priv *priv = netdev_priv(ndev);
+ struct can_frame *cf = (struct can_frame *)skb->data;
+ u32 mbxno, mbx_mask, data;
+ unsigned long flags;
+
+ mbxno = get_tx_head_mb(priv);
+ mbx_mask = BIT(mbxno);
+ spin_lock_irqsave(&priv->mbx_lock, flags);
+ if (unlikely(hecc_read(priv, HECC_CANME) & mbx_mask)) {
+ spin_unlock_irqrestore(&priv->mbx_lock, flags);
+ netif_stop_queue(ndev);
+ dev_err(priv->ndev->dev.parent,
+ "BUG: TX mbx not ready tx_head=%08X, tx_tail=%08X\n",
+ priv->tx_head, priv->tx_tail);
+ return NETDEV_TX_BUSY;
+ }
+ spin_unlock_irqrestore(&priv->mbx_lock, flags);
+
+ /* Prepare mailbox for transmission */
+ data = min_t(u8, cf->can_dlc, 8);
+ if (cf->can_id & CAN_RTR_FLAG) /* Remote transmission request */
+ data |= HECC_CANMCF_RTR;
+ data |= get_tx_head_prio(priv) << 8;
+ hecc_write_mbx(priv, mbxno, HECC_CANMCF, data);
+
+ if (cf->can_id & CAN_EFF_FLAG) /* Extended frame format */
+ data = (cf->can_id & CAN_EFF_MASK) | HECC_CANMID_IDE;
+ else /* Standard frame format */
+ data = (cf->can_id & CAN_SFF_MASK) << 18;
+ hecc_write_mbx(priv, mbxno, HECC_CANMID, data);
+ hecc_write_mbx(priv, mbxno, HECC_CANMDL,
+ be32_to_cpu(*(u32 *)(cf->data)));
+ if (cf->can_dlc > 4)
+ hecc_write_mbx(priv, mbxno, HECC_CANMDH,
+ be32_to_cpu(*(u32 *)(cf->data + 4)));
+ else
+ *(u32 *)(cf->data + 4) = 0;
+ can_put_echo_skb(skb, ndev, mbxno);
+
+ spin_lock_irqsave(&priv->mbx_lock, flags);
+ --priv->tx_head;
+ if ((hecc_read(priv, HECC_CANME) & BIT(get_tx_head_mb(priv))) ||
+ (priv->tx_head & HECC_TX_MASK) == HECC_TX_MASK) {
+ netif_stop_queue(ndev);
+ }
+ hecc_set_bit(priv, HECC_CANME, mbx_mask);
+ spin_unlock_irqrestore(&priv->mbx_lock, flags);
+
+ hecc_clear_bit(priv, HECC_CANMD, mbx_mask);
+ hecc_set_bit(priv, HECC_CANMIM, mbx_mask);
+ hecc_write(priv, HECC_CANTRS, mbx_mask);
+
+ return NETDEV_TX_OK;
+}
+
+static int ti_hecc_rx_pkt(struct ti_hecc_priv *priv, int mbxno)
+{
+ struct net_device_stats *stats = &priv->ndev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ u32 data, mbx_mask;
+ unsigned long flags;
+
+ skb = alloc_can_skb(priv->ndev, &cf);
+ if (!skb) {
+ if (printk_ratelimit())
+ dev_err(priv->ndev->dev.parent,
+ "ti_hecc_rx_pkt: alloc_can_skb() failed\n");
+ return -ENOMEM;
+ }
+
+ mbx_mask = BIT(mbxno);
+ data = hecc_read_mbx(priv, mbxno, HECC_CANMID);
+ if (data & HECC_CANMID_IDE)
+ cf->can_id = (data & CAN_EFF_MASK) | CAN_EFF_FLAG;
+ else
+ cf->can_id = (data >> 18) & CAN_SFF_MASK;
+ data = hecc_read_mbx(priv, mbxno, HECC_CANMCF);
+ if (data & HECC_CANMCF_RTR)
+ cf->can_id |= CAN_RTR_FLAG;
+ cf->can_dlc = data & 0xF;
+ data = hecc_read_mbx(priv, mbxno, HECC_CANMDL);
+ *(u32 *)(cf->data) = cpu_to_be32(data);
+ if (cf->can_dlc > 4) {
+ data = hecc_read_mbx(priv, mbxno, HECC_CANMDH);
+ *(u32 *)(cf->data + 4) = cpu_to_be32(data);
+ } else {
+ *(u32 *)(cf->data + 4) = 0;
+ }
+ spin_lock_irqsave(&priv->mbx_lock, flags);
+ hecc_clear_bit(priv, HECC_CANME, mbx_mask);
+ hecc_write(priv, HECC_CANRMP, mbx_mask);
+ /* enable mailbox only if it is part of rx buffer mailboxes */
+ if (priv->rx_next < HECC_RX_BUFFER_MBOX)
+ hecc_set_bit(priv, HECC_CANME, mbx_mask);
+ spin_unlock_irqrestore(&priv->mbx_lock, flags);
+
+ stats->rx_bytes += cf->can_dlc;
+ netif_receive_skb(skb);
+ stats->rx_packets++;
+
+ return 0;
+}
+
+/*
+ * ti_hecc_rx_poll - HECC receive pkts
+ *
+ * The receive mailboxes start from highest numbered mailbox till last xmit
+ * mailbox. On CAN frame reception the hardware places the data into highest
+ * numbered mailbox that matches the CAN ID filter. Since all receive mailboxes
+ * have same filtering (ALL CAN frames) packets will arrive in the highest
+ * available RX mailbox and we need to ensure in-order packet reception.
+ *
+ * To ensure the packets are received in the right order we logically divide
+ * the RX mailboxes into main and buffer mailboxes. Packets are received as per
+ * mailbox priotity (higher to lower) in the main bank and once it is full we
+ * disable further reception into main mailboxes. While the main mailboxes are
+ * processed in NAPI, further packets are received in buffer mailboxes.
+ *
+ * We maintain a RX next mailbox counter to process packets and once all main
+ * mailboxe packets are passed to the upper stack we enable all of them but
+ * continue to process packets received in buffer mailboxes. With each packet
+ * received from buffer mailbox we enable it immediately so as to handle the
+ * overflow from higher mailboxes.
+ */
+static int ti_hecc_rx_poll(struct napi_struct *napi, int quota)
+{
+ struct net_device *ndev = napi->dev;
+ struct ti_hecc_priv *priv = netdev_priv(ndev);
+ u32 num_pkts = 0;
+ u32 mbx_mask;
+ unsigned long pending_pkts, flags;
+
+ if (!netif_running(ndev))
+ return 0;
+
+ while ((pending_pkts = hecc_read(priv, HECC_CANRMP)) &&
+ num_pkts < quota) {
+ mbx_mask = BIT(priv->rx_next); /* next rx mailbox to process */
+ if (mbx_mask & pending_pkts) {
+ if (ti_hecc_rx_pkt(priv, priv->rx_next) < 0)
+ return num_pkts;
+ ++num_pkts;
+ } else if (priv->rx_next > HECC_RX_BUFFER_MBOX) {
+ break; /* pkt not received yet */
+ }
+ --priv->rx_next;
+ if (priv->rx_next == HECC_RX_BUFFER_MBOX) {
+ /* enable high bank mailboxes */
+ spin_lock_irqsave(&priv->mbx_lock, flags);
+ mbx_mask = hecc_read(priv, HECC_CANME);
+ mbx_mask |= HECC_RX_HIGH_MBOX_MASK;
+ hecc_write(priv, HECC_CANME, mbx_mask);
+ spin_unlock_irqrestore(&priv->mbx_lock, flags);
+ } else if (priv->rx_next == HECC_MAX_TX_MBOX - 1) {
+ priv->rx_next = HECC_RX_FIRST_MBOX;
+ break;
+ }
+ }
+
+ /* Enable packet interrupt if all pkts are handled */
+ if (hecc_read(priv, HECC_CANRMP) == 0) {
+ napi_complete(napi);
+ /* Re-enable RX mailbox interrupts */
+ mbx_mask = hecc_read(priv, HECC_CANMIM);
+ mbx_mask |= HECC_TX_MBOX_MASK;
+ hecc_write(priv, HECC_CANMIM, mbx_mask);
+ }
+
+ return num_pkts;
+}
+
+static int ti_hecc_error(struct net_device *ndev, int int_status,
+ int err_status)
+{
+ struct ti_hecc_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+
+ /* propogate the error condition to the can stack */
+ skb = alloc_can_err_skb(ndev, &cf);
+ if (!skb) {
+ if (printk_ratelimit())
+ dev_err(priv->ndev->dev.parent,
+ "ti_hecc_error: alloc_can_err_skb() failed\n");
+ return -ENOMEM;
+ }
+
+ if (int_status & HECC_CANGIF_WLIF) { /* warning level int */
+ if ((int_status & HECC_CANGIF_BOIF) == 0) {
+ priv->can.state = CAN_STATE_ERROR_WARNING;
+ ++priv->can.can_stats.error_warning;
+ cf->can_id |= CAN_ERR_CRTL;
+ if (hecc_read(priv, HECC_CANTEC) > 96)
+ cf->data[1] |= CAN_ERR_CRTL_TX_WARNING;
+ if (hecc_read(priv, HECC_CANREC) > 96)
+ cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
+ }
+ hecc_set_bit(priv, HECC_CANES, HECC_CANES_EW);
+ dev_dbg(priv->ndev->dev.parent, "Error Warning interrupt\n");
+ hecc_clear_bit(priv, HECC_CANMC, HECC_CANMC_CCR);
+ }
+
+ if (int_status & HECC_CANGIF_EPIF) { /* error passive int */
+ if ((int_status & HECC_CANGIF_BOIF) == 0) {
+ priv->can.state = CAN_STATE_ERROR_PASSIVE;
+ ++priv->can.can_stats.error_passive;
+ cf->can_id |= CAN_ERR_CRTL;
+ if (hecc_read(priv, HECC_CANTEC) > 127)
+ cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+ if (hecc_read(priv, HECC_CANREC) > 127)
+ cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+ }
+ hecc_set_bit(priv, HECC_CANES, HECC_CANES_EP);
+ dev_dbg(priv->ndev->dev.parent, "Error passive interrupt\n");
+ hecc_clear_bit(priv, HECC_CANMC, HECC_CANMC_CCR);
+ }
+
+ /*
+ * Need to check busoff condition in error status register too to
+ * ensure warning interrupts don't hog the system
+ */
+ if ((int_status & HECC_CANGIF_BOIF) || (err_status & HECC_CANES_BO)) {
+ priv->can.state = CAN_STATE_BUS_OFF;
+ cf->can_id |= CAN_ERR_BUSOFF;
+ hecc_set_bit(priv, HECC_CANES, HECC_CANES_BO);
+ hecc_clear_bit(priv, HECC_CANMC, HECC_CANMC_CCR);
+ /* Disable all interrupts in bus-off to avoid int hog */
+ hecc_write(priv, HECC_CANGIM, 0);
+ can_bus_off(ndev);
+ }
+
+ if (err_status & HECC_BUS_ERROR) {
+ ++priv->can.can_stats.bus_error;
+ cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
+ cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+ if (err_status & HECC_CANES_FE) {
+ hecc_set_bit(priv, HECC_CANES, HECC_CANES_FE);
+ cf->data[2] |= CAN_ERR_PROT_FORM;
+ }
+ if (err_status & HECC_CANES_BE) {
+ hecc_set_bit(priv, HECC_CANES, HECC_CANES_BE);
+ cf->data[2] |= CAN_ERR_PROT_BIT;
+ }
+ if (err_status & HECC_CANES_SE) {
+ hecc_set_bit(priv, HECC_CANES, HECC_CANES_SE);
+ cf->data[2] |= CAN_ERR_PROT_STUFF;
+ }
+ if (err_status & HECC_CANES_CRCE) {
+ hecc_set_bit(priv, HECC_CANES, HECC_CANES_CRCE);
+ cf->data[2] |= CAN_ERR_PROT_LOC_CRC_SEQ |
+ CAN_ERR_PROT_LOC_CRC_DEL;
+ }
+ if (err_status & HECC_CANES_ACKE) {
+ hecc_set_bit(priv, HECC_CANES, HECC_CANES_ACKE);
+ cf->data[2] |= CAN_ERR_PROT_LOC_ACK |
+ CAN_ERR_PROT_LOC_ACK_DEL;
+ }
+ }
+
+ netif_receive_skb(skb);
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+ return 0;
+}
+
+static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id)
+{
+ struct net_device *ndev = (struct net_device *)dev_id;
+ struct ti_hecc_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+ u32 mbxno, mbx_mask, int_status, err_status;
+ unsigned long ack, flags;
+
+ int_status = hecc_read(priv,
+ (priv->int_line) ? HECC_CANGIF1 : HECC_CANGIF0);
+
+ if (!int_status)
+ return IRQ_NONE;
+
+ err_status = hecc_read(priv, HECC_CANES);
+ if (err_status & (HECC_BUS_ERROR | HECC_CANES_BO |
+ HECC_CANES_EP | HECC_CANES_EW))
+ ti_hecc_error(ndev, int_status, err_status);
+
+ if (int_status & HECC_CANGIF_GMIF) {
+ while (priv->tx_tail - priv->tx_head > 0) {
+ mbxno = get_tx_tail_mb(priv);
+ mbx_mask = BIT(mbxno);
+ if (!(mbx_mask & hecc_read(priv, HECC_CANTA)))
+ break;
+ hecc_clear_bit(priv, HECC_CANMIM, mbx_mask);
+ hecc_write(priv, HECC_CANTA, mbx_mask);
+ spin_lock_irqsave(&priv->mbx_lock, flags);
+ hecc_clear_bit(priv, HECC_CANME, mbx_mask);
+ spin_unlock_irqrestore(&priv->mbx_lock, flags);
+ stats->tx_bytes += hecc_read_mbx(priv, mbxno,
+ HECC_CANMCF) & 0xF;
+ stats->tx_packets++;
+ can_get_echo_skb(ndev, mbxno);
+ --priv->tx_tail;
+ }
+
+ /* restart queue if wrap-up or if queue stalled on last pkt */
+ if (((priv->tx_head == priv->tx_tail) &&
+ ((priv->tx_head & HECC_TX_MASK) != HECC_TX_MASK)) ||
+ (((priv->tx_tail & HECC_TX_MASK) == HECC_TX_MASK) &&
+ ((priv->tx_head & HECC_TX_MASK) == HECC_TX_MASK)))
+ netif_wake_queue(ndev);
+
+ /* Disable RX mailbox interrupts and let NAPI reenable them */
+ if (hecc_read(priv, HECC_CANRMP)) {
+ ack = hecc_read(priv, HECC_CANMIM);
+ ack &= BIT(HECC_MAX_TX_MBOX) - 1;
+ hecc_write(priv, HECC_CANMIM, ack);
+ napi_schedule(&priv->napi);
+ }
+ }
+
+ /* clear all interrupt conditions - read back to avoid spurious ints */
+ if (priv->int_line) {
+ hecc_write(priv, HECC_CANGIF1, HECC_SET_REG);
+ int_status = hecc_read(priv, HECC_CANGIF1);
+ } else {
+ hecc_write(priv, HECC_CANGIF0, HECC_SET_REG);
+ int_status = hecc_read(priv, HECC_CANGIF0);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int ti_hecc_open(struct net_device *ndev)
+{
+ struct ti_hecc_priv *priv = netdev_priv(ndev);
+ int err;
+
+ err = request_irq(ndev->irq, ti_hecc_interrupt, IRQF_SHARED,
+ ndev->name, ndev);
+ if (err) {
+ dev_err(ndev->dev.parent, "error requesting interrupt\n");
+ return err;
+ }
+
+ /* Open common can device */
+ err = open_candev(ndev);
+ if (err) {
+ dev_err(ndev->dev.parent, "open_candev() failed %d\n", err);
+ free_irq(ndev->irq, ndev);
+ return err;
+ }
+
+ clk_enable(priv->clk);
+ ti_hecc_start(ndev);
+ napi_enable(&priv->napi);
+ netif_start_queue(ndev);
+
+ return 0;
+}
+
+static int ti_hecc_close(struct net_device *ndev)
+{
+ struct ti_hecc_priv *priv = netdev_priv(ndev);
+
+ netif_stop_queue(ndev);
+ napi_disable(&priv->napi);
+ ti_hecc_stop(ndev);
+ free_irq(ndev->irq, ndev);
+ clk_disable(priv->clk);
+ close_candev(ndev);
+
+ return 0;
+}
+
+static const struct net_device_ops ti_hecc_netdev_ops = {
+ .ndo_open = ti_hecc_open,
+ .ndo_stop = ti_hecc_close,
+ .ndo_start_xmit = ti_hecc_xmit,
+};
+
+static int ti_hecc_probe(struct platform_device *pdev)
+{
+ struct net_device *ndev = (struct net_device *)0;
+ struct ti_hecc_priv *priv;
+ struct ti_hecc_platform_data *pdata;
+ struct resource *mem, *irq;
+ void __iomem *addr;
+ int err = -ENODEV;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform data\n");
+ goto probe_exit;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "No mem resources\n");
+ goto probe_exit;
+ }
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "No irq resource\n");
+ goto probe_exit;
+ }
+ if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
+ dev_err(&pdev->dev, "HECC region already claimed\n");
+ err = -EBUSY;
+ goto probe_exit;
+ }
+ addr = ioremap(mem->start, resource_size(mem));
+ if (!addr) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ err = -ENOMEM;
+ goto probe_exit_free_region;
+ }
+
+ ndev = alloc_candev(sizeof(struct ti_hecc_priv), HECC_MAX_TX_MBOX);
+ if (!ndev) {
+ dev_err(&pdev->dev, "alloc_candev failed\n");
+ err = -ENOMEM;
+ goto probe_exit_iounmap;
+ }
+
+ priv = netdev_priv(ndev);
+ priv->ndev = ndev;
+ priv->base = addr;
+ priv->scc_ram_offset = pdata->scc_ram_offset;
+ priv->hecc_ram_offset = pdata->hecc_ram_offset;
+ priv->mbx_offset = pdata->mbx_offset;
+ priv->int_line = pdata->int_line;
+
+ priv->can.bittiming_const = &ti_hecc_bittiming_const;
+ priv->can.do_set_mode = ti_hecc_do_set_mode;
+ priv->can.do_get_state = ti_hecc_get_state;
+
+ ndev->irq = irq->start;
+ ndev->flags |= IFF_ECHO;
+ platform_set_drvdata(pdev, ndev);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+ ndev->netdev_ops = &ti_hecc_netdev_ops;
+
+ priv->clk = clk_get(&pdev->dev, "hecc_ck");
+ if (IS_ERR(priv->clk)) {
+ dev_err(&pdev->dev, "No clock available\n");
+ err = PTR_ERR(priv->clk);
+ priv->clk = NULL;
+ goto probe_exit_candev;
+ }
+ priv->can.clock.freq = clk_get_rate(priv->clk);
+ netif_napi_add(ndev, &priv->napi, ti_hecc_rx_poll,
+ HECC_DEF_NAPI_WEIGHT);
+
+ err = register_candev(ndev);
+ if (err) {
+ dev_err(&pdev->dev, "register_candev() failed\n");
+ goto probe_exit_clk;
+ }
+ dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n",
+ priv->base, (u32) ndev->irq);
+
+ return 0;
+
+probe_exit_clk:
+ clk_put(priv->clk);
+probe_exit_candev:
+ free_candev(ndev);
+probe_exit_iounmap:
+ iounmap(addr);
+probe_exit_free_region:
+ release_mem_region(mem->start, resource_size(mem));
+probe_exit:
+ return err;
+}
+
+static int __devexit ti_hecc_remove(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct ti_hecc_priv *priv = netdev_priv(ndev);
+
+ clk_put(priv->clk);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ iounmap(priv->base);
+ release_mem_region(res->start, resource_size(res));
+ unregister_candev(ndev);
+ free_candev(ndev);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+/* TI HECC netdevice driver: platform driver structure */
+static struct platform_driver ti_hecc_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ti_hecc_probe,
+ .remove = __devexit_p(ti_hecc_remove),
+};
+
+static int __init ti_hecc_init_driver(void)
+{
+ printk(KERN_INFO DRV_DESC "\n");
+ return platform_driver_register(&ti_hecc_driver);
+}
+module_init(ti_hecc_init_driver);
+
+static void __exit ti_hecc_exit_driver(void)
+{
+ printk(KERN_INFO DRV_DESC " unloaded\n");
+ platform_driver_unregister(&ti_hecc_driver);
+}
+module_exit(ti_hecc_exit_driver);
+
+MODULE_AUTHOR("Anant Gole <anantgole@ti.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION(DRV_DESC);
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index 9012e0abc626..3685f3e42d12 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -232,7 +232,7 @@ MODULE_DEVICE_TABLE(usb, ems_usb_table);
#define INTR_IN_BUFFER_SIZE 4
#define MAX_RX_URBS 10
-#define MAX_TX_URBS CAN_ECHO_SKB_MAX
+#define MAX_TX_URBS 10
struct ems_usb;
@@ -311,14 +311,10 @@ static void ems_usb_rx_can_msg(struct ems_usb *dev, struct ems_cpc_msg *msg)
int i;
struct net_device_stats *stats = &dev->netdev->stats;
- skb = netdev_alloc_skb(dev->netdev, sizeof(struct can_frame));
+ skb = alloc_can_skb(dev->netdev, &cf);
if (skb == NULL)
return;
- skb->protocol = htons(ETH_P_CAN);
-
- cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
-
cf->can_id = msg->msg.can_msg.id;
cf->can_dlc = min_t(u8, msg->msg.can_msg.length, 8);
@@ -346,18 +342,10 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
struct sk_buff *skb;
struct net_device_stats *stats = &dev->netdev->stats;
- skb = netdev_alloc_skb(dev->netdev, sizeof(struct can_frame));
+ skb = alloc_can_err_skb(dev->netdev, &cf);
if (skb == NULL)
return;
- skb->protocol = htons(ETH_P_CAN);
-
- cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
- memset(cf, 0, sizeof(struct can_frame));
-
- cf->can_id = CAN_ERR_FLAG;
- cf->can_dlc = CAN_ERR_DLC;
-
if (msg->type == CPC_MSG_TYPE_CAN_STATE) {
u8 state = msg->msg.can_state;
@@ -1012,7 +1000,7 @@ static int ems_usb_probe(struct usb_interface *intf,
struct ems_usb *dev;
int i, err = -ENOMEM;
- netdev = alloc_candev(sizeof(struct ems_usb));
+ netdev = alloc_candev(sizeof(struct ems_usb), MAX_TX_URBS);
if (!netdev) {
dev_err(netdev->dev.parent, "Couldn't alloc candev\n");
return -ENOMEM;
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index 8c658cf6f62f..109d2783e4d8 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -1378,7 +1378,7 @@ static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
}
__skb_pull(skb, sizeof(*p));
- st = per_cpu_ptr(sge->port_stats[p->iff], smp_processor_id());
+ st = this_cpu_ptr(sge->port_stats[p->iff]);
skb->protocol = eth_type_trans(skb, adapter->port[p->iff].dev);
if ((adapter->flags & RX_CSUM_ENABLED) && p->csum == 0xffff &&
@@ -1780,8 +1780,7 @@ netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct adapter *adapter = dev->ml_priv;
struct sge *sge = adapter->sge;
- struct sge_port_stats *st = per_cpu_ptr(sge->port_stats[dev->if_port],
- smp_processor_id());
+ struct sge_port_stats *st = this_cpu_ptr(sge->port_stats[dev->if_port]);
struct cpl_tx_pkt *cpl;
struct sk_buff *orig_skb = skb;
int ret;
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 46c87ec7960c..333b1d1e7435 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -33,10 +33,16 @@
#include <net/route.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
+#include <net/ip6_checksum.h>
#include <scsi/iscsi_if.h>
#include "cnic_if.h"
#include "bnx2.h"
+#include "bnx2x_reg.h"
+#include "bnx2x_fw_defs.h"
+#include "bnx2x_hsi.h"
+#include "../scsi/bnx2i/57xx_iscsi_constants.h"
+#include "../scsi/bnx2i/57xx_iscsi_hsi.h"
#include "cnic.h"
#include "cnic_defs.h"
@@ -59,6 +65,7 @@ static DEFINE_MUTEX(cnic_lock);
static struct cnic_ulp_ops *cnic_ulp_tbl[MAX_CNIC_ULP_TYPE];
static int cnic_service_bnx2(void *, void *);
+static int cnic_service_bnx2x(void *, void *);
static int cnic_ctl(void *, struct cnic_ctl_info *);
static struct cnic_ops cnic_bnx2_ops = {
@@ -67,9 +74,14 @@ static struct cnic_ops cnic_bnx2_ops = {
.cnic_ctl = cnic_ctl,
};
-static void cnic_shutdown_bnx2_rx_ring(struct cnic_dev *);
-static void cnic_init_bnx2_tx_ring(struct cnic_dev *);
-static void cnic_init_bnx2_rx_ring(struct cnic_dev *);
+static struct cnic_ops cnic_bnx2x_ops = {
+ .cnic_owner = THIS_MODULE,
+ .cnic_handler = cnic_service_bnx2x,
+ .cnic_ctl = cnic_ctl,
+};
+
+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)
@@ -83,10 +95,16 @@ static int cnic_uio_open(struct uio_info *uinfo, struct inode *inode)
if (cp->uio_dev != -1)
return -EBUSY;
+ rtnl_lock();
+ if (!test_bit(CNIC_F_CNIC_UP, &dev->flags)) {
+ rtnl_unlock();
+ return -ENODEV;
+ }
+
cp->uio_dev = iminor(inode);
- cnic_init_bnx2_tx_ring(dev);
- cnic_init_bnx2_rx_ring(dev);
+ cnic_init_rings(dev);
+ rtnl_unlock();
return 0;
}
@@ -96,7 +114,7 @@ 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_bnx2_rx_ring(dev);
+ cnic_shutdown_rings(dev);
cp->uio_dev = -1;
return 0;
@@ -162,6 +180,36 @@ static void cnic_ctx_wr(struct cnic_dev *dev, u32 cid_addr, u32 off, u32 val)
ethdev->drv_ctl(dev->netdev, &info);
}
+static void cnic_ctx_tbl_wr(struct cnic_dev *dev, u32 off, dma_addr_t addr)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_eth_dev *ethdev = cp->ethdev;
+ struct drv_ctl_info info;
+ struct drv_ctl_io *io = &info.data.io;
+
+ info.cmd = DRV_CTL_CTXTBL_WR_CMD;
+ io->offset = off;
+ io->dma_addr = addr;
+ ethdev->drv_ctl(dev->netdev, &info);
+}
+
+static void cnic_ring_ctl(struct cnic_dev *dev, u32 cid, u32 cl_id, int start)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_eth_dev *ethdev = cp->ethdev;
+ struct drv_ctl_info info;
+ struct drv_ctl_l2_ring *ring = &info.data.ring;
+
+ if (start)
+ info.cmd = DRV_CTL_START_L2_CMD;
+ else
+ info.cmd = DRV_CTL_STOP_L2_CMD;
+
+ ring->cid = cid;
+ ring->client_id = cl_id;
+ ethdev->drv_ctl(dev->netdev, &info);
+}
+
static void cnic_reg_wr_ind(struct cnic_dev *dev, u32 off, u32 val)
{
struct cnic_local *cp = dev->cnic_priv;
@@ -204,6 +252,19 @@ static void cnic_kwq_completion(struct cnic_dev *dev, u32 count)
ethdev->drv_ctl(dev->netdev, &info);
}
+static int cnic_get_l5_cid(struct cnic_local *cp, u32 cid, u32 *l5_cid)
+{
+ u32 i;
+
+ for (i = 0; i < MAX_ISCSI_TBL_SZ; i++) {
+ if (cp->ctx_tbl[i].cid == cid) {
+ *l5_cid = i;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
static int cnic_send_nlmsg(struct cnic_local *cp, u32 type,
struct cnic_sock *csk)
{
@@ -635,6 +696,20 @@ static void cnic_setup_page_tbl(struct cnic_dev *dev, struct cnic_dma *dma)
}
}
+static void cnic_setup_page_tbl_le(struct cnic_dev *dev, struct cnic_dma *dma)
+{
+ int i;
+ u32 *page_table = dma->pgtbl;
+
+ for (i = 0; i < dma->num_pages; i++) {
+ /* Each entry needs to be in little endian format. */
+ *page_table = dma->pg_map_arr[i] & 0xffffffff;
+ page_table++;
+ *page_table = (u32) ((u64) dma->pg_map_arr[i] >> 32);
+ page_table++;
+ }
+}
+
static int cnic_alloc_dma(struct cnic_dev *dev, struct cnic_dma *dma,
int pages, int use_pg_tbl)
{
@@ -675,6 +750,21 @@ error:
return -ENOMEM;
}
+static void cnic_free_context(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int i;
+
+ for (i = 0; i < cp->ctx_blks; i++) {
+ if (cp->ctx_arr[i].ctx) {
+ pci_free_consistent(dev->pcidev, cp->ctx_blk_size,
+ cp->ctx_arr[i].ctx,
+ cp->ctx_arr[i].mapping);
+ cp->ctx_arr[i].ctx = NULL;
+ }
+ }
+}
+
static void cnic_free_resc(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
@@ -702,14 +792,7 @@ static void cnic_free_resc(struct cnic_dev *dev)
cp->l2_ring = NULL;
}
- for (i = 0; i < cp->ctx_blks; i++) {
- if (cp->ctx_arr[i].ctx) {
- pci_free_consistent(dev->pcidev, cp->ctx_blk_size,
- cp->ctx_arr[i].ctx,
- cp->ctx_arr[i].mapping);
- cp->ctx_arr[i].ctx = NULL;
- }
- }
+ cnic_free_context(dev);
kfree(cp->ctx_arr);
cp->ctx_arr = NULL;
cp->ctx_blks = 0;
@@ -717,6 +800,7 @@ static void cnic_free_resc(struct cnic_dev *dev)
cnic_free_dma(dev, &cp->gbl_buf_info);
cnic_free_dma(dev, &cp->conn_buf_info);
cnic_free_dma(dev, &cp->kwq_info);
+ cnic_free_dma(dev, &cp->kwq_16_data_info);
cnic_free_dma(dev, &cp->kcq_info);
kfree(cp->iscsi_tbl);
cp->iscsi_tbl = NULL;
@@ -808,14 +892,20 @@ static int cnic_alloc_uio(struct cnic_dev *dev) {
uinfo->mem[0].size = dev->netdev->mem_end - dev->netdev->mem_start;
uinfo->mem[0].memtype = UIO_MEM_PHYS;
- uinfo->mem[1].addr = (unsigned long) cp->status_blk & PAGE_MASK;
if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) {
+ uinfo->mem[1].addr = (unsigned long) cp->status_blk & PAGE_MASK;
if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX)
uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE * 9;
else
uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE;
uinfo->name = "bnx2_cnic";
+ } 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->name = "bnx2x_cnic";
}
uinfo->mem[1].memtype = UIO_MEM_LOGICAL;
@@ -880,6 +970,151 @@ error:
return ret;
}
+static int cnic_alloc_bnx2x_context(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_eth_dev *ethdev = cp->ethdev;
+ int ctx_blk_size = cp->ethdev->ctx_blk_size;
+ int total_mem, blks, i, cid_space;
+
+ if (BNX2X_ISCSI_START_CID < ethdev->starting_cid)
+ return -EINVAL;
+
+ cid_space = MAX_ISCSI_TBL_SZ +
+ (BNX2X_ISCSI_START_CID - ethdev->starting_cid);
+
+ total_mem = BNX2X_CONTEXT_MEM_SIZE * cid_space;
+ blks = total_mem / ctx_blk_size;
+ if (total_mem % ctx_blk_size)
+ blks++;
+
+ if (blks > cp->ethdev->ctx_tbl_len)
+ return -ENOMEM;
+
+ cp->ctx_arr = kzalloc(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))
+ cp->ctx_align = 0;
+ else
+ cp->ctx_align = ctx_blk_size;
+
+ cp->cids_per_blk = ctx_blk_size / BNX2X_CONTEXT_MEM_SIZE;
+
+ for (i = 0; i < blks; i++) {
+ cp->ctx_arr[i].ctx =
+ pci_alloc_consistent(dev->pcidev, cp->ctx_blk_size,
+ &cp->ctx_arr[i].mapping);
+ if (cp->ctx_arr[i].ctx == NULL)
+ return -ENOMEM;
+
+ if (cp->ctx_align && cp->ctx_blk_size == ctx_blk_size) {
+ if (cp->ctx_arr[i].mapping & (cp->ctx_align - 1)) {
+ cnic_free_context(dev);
+ cp->ctx_blk_size += cp->ctx_align;
+ i = -1;
+ continue;
+ }
+ }
+ }
+ return 0;
+}
+
+static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int i, j, n, ret, pages;
+ struct cnic_dma *kwq_16_dma = &cp->kwq_16_data_info;
+
+ cp->iscsi_tbl = kzalloc(sizeof(struct cnic_iscsi) * MAX_ISCSI_TBL_SZ,
+ GFP_KERNEL);
+ if (!cp->iscsi_tbl)
+ goto error;
+
+ cp->ctx_tbl = kzalloc(sizeof(struct cnic_context) *
+ MAX_CNIC_L5_CONTEXT, GFP_KERNEL);
+ if (!cp->ctx_tbl)
+ goto error;
+
+ for (i = 0; i < MAX_ISCSI_TBL_SZ; i++) {
+ cp->ctx_tbl[i].proto.iscsi = &cp->iscsi_tbl[i];
+ cp->ctx_tbl[i].ulp_proto_id = CNIC_ULP_ISCSI;
+ }
+
+ pages = PAGE_ALIGN(MAX_CNIC_L5_CONTEXT * CNIC_KWQ16_DATA_SIZE) /
+ PAGE_SIZE;
+
+ ret = cnic_alloc_dma(dev, kwq_16_dma, pages, 0);
+ if (ret)
+ return -ENOMEM;
+
+ n = PAGE_SIZE / CNIC_KWQ16_DATA_SIZE;
+ for (i = 0, j = 0; i < MAX_ISCSI_TBL_SZ; i++) {
+ long off = CNIC_KWQ16_DATA_SIZE * (i % n);
+
+ cp->ctx_tbl[i].kwqe_data = kwq_16_dma->pg_arr[j] + off;
+ cp->ctx_tbl[i].kwqe_data_mapping = kwq_16_dma->pg_map_arr[j] +
+ off;
+
+ if ((i % n) == (n - 1))
+ j++;
+ }
+
+ ret = cnic_alloc_dma(dev, &cp->kcq_info, KCQ_PAGE_CNT, 0);
+ if (ret)
+ goto error;
+ cp->kcq = (struct kcqe **) cp->kcq_info.pg_arr;
+
+ for (i = 0; i < KCQ_PAGE_CNT; i++) {
+ struct bnx2x_bd_chain_next *next =
+ (struct bnx2x_bd_chain_next *)
+ &cp->kcq[i][MAX_KCQE_CNT];
+ int j = i + 1;
+
+ if (j >= KCQ_PAGE_CNT)
+ j = 0;
+ next->addr_hi = (u64) cp->kcq_info.pg_map_arr[j] >> 32;
+ next->addr_lo = cp->kcq_info.pg_map_arr[j] & 0xffffffff;
+ }
+
+ pages = PAGE_ALIGN(BNX2X_ISCSI_NUM_CONNECTIONS *
+ BNX2X_ISCSI_CONN_BUF_SIZE) / PAGE_SIZE;
+ ret = cnic_alloc_dma(dev, &cp->conn_buf_info, pages, 1);
+ if (ret)
+ goto error;
+
+ pages = PAGE_ALIGN(BNX2X_ISCSI_GLB_BUF_SIZE) / PAGE_SIZE;
+ ret = cnic_alloc_dma(dev, &cp->gbl_buf_info, pages, 0);
+ if (ret)
+ goto error;
+
+ ret = cnic_alloc_bnx2x_context(dev);
+ if (ret)
+ goto error;
+
+ cp->bnx2x_status_blk = cp->status_blk;
+ cp->bnx2x_def_status_blk = cp->ethdev->irq_arr[1].status_blk;
+
+ cp->l2_rx_ring_size = 15;
+
+ ret = cnic_alloc_l2_rings(dev, 4);
+ if (ret)
+ goto error;
+
+ ret = cnic_alloc_uio(dev);
+ if (ret)
+ goto error;
+
+ return 0;
+
+error:
+ cnic_free_resc(dev);
+ return -ENOMEM;
+}
+
static inline u32 cnic_kwq_avail(struct cnic_local *cp)
{
return cp->max_kwq_idx -
@@ -921,6 +1156,880 @@ static int cnic_submit_bnx2_kwqes(struct cnic_dev *dev, struct kwqe *wqes[],
return 0;
}
+static void *cnic_get_kwqe_16_data(struct cnic_local *cp, u32 l5_cid,
+ union l5cm_specific_data *l5_data)
+{
+ struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
+ dma_addr_t map;
+
+ map = ctx->kwqe_data_mapping;
+ l5_data->phy_address.lo = (u64) map & 0xffffffff;
+ l5_data->phy_address.hi = (u64) map >> 32;
+ return ctx->kwqe_data;
+}
+
+static int cnic_submit_kwqe_16(struct cnic_dev *dev, u32 cmd, u32 cid,
+ u32 type, union l5cm_specific_data *l5_data)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct l5cm_spe kwqe;
+ struct kwqe_16 *kwq[1];
+ int ret;
+
+ kwqe.hdr.conn_and_cmd_data =
+ cpu_to_le32(((cmd << SPE_HDR_CMD_ID_SHIFT) |
+ BNX2X_HW_CID(cid, cp->func)));
+ kwqe.hdr.type = cpu_to_le16(type);
+ kwqe.hdr.reserved = 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);
+
+ kwq[0] = (struct kwqe_16 *) &kwqe;
+
+ spin_lock_bh(&cp->cnic_ulp_lock);
+ ret = cp->ethdev->drv_submit_kwqes_16(dev->netdev, kwq, 1);
+ spin_unlock_bh(&cp->cnic_ulp_lock);
+
+ if (ret == 1)
+ return 0;
+
+ return -EBUSY;
+}
+
+static void cnic_reply_bnx2x_kcqes(struct cnic_dev *dev, int ulp_type,
+ struct kcqe *cqes[], u32 num_cqes)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_ulp_ops *ulp_ops;
+
+ rcu_read_lock();
+ ulp_ops = rcu_dereference(cp->ulp_ops[ulp_type]);
+ if (likely(ulp_ops)) {
+ ulp_ops->indicate_kcqes(cp->ulp_handle[ulp_type],
+ cqes, num_cqes);
+ }
+ rcu_read_unlock();
+}
+
+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;
+
+ cp->num_iscsi_tasks = req1->num_tasks_per_conn;
+ cp->num_ccells = req1->num_ccells_per_conn;
+ cp->task_array_size = BNX2X_ISCSI_TASK_CONTEXT_SIZE *
+ cp->num_iscsi_tasks;
+ cp->r2tq_size = cp->num_iscsi_tasks * BNX2X_ISCSI_MAX_PENDING_R2TS *
+ BNX2X_ISCSI_R2TQE_SIZE;
+ cp->hq_size = cp->num_ccells * BNX2X_ISCSI_HQ_BD_SIZE;
+ pages = PAGE_ALIGN(cp->hq_size) / PAGE_SIZE;
+ hq_bds = pages * (PAGE_SIZE / BNX2X_ISCSI_HQ_BD_SIZE);
+ cp->num_cqs = req1->num_cqs;
+
+ if (!dev->max_iscsi_conn)
+ return 0;
+
+ /* init Tstorm RAM */
+ CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_RQ_SIZE_OFFSET(func),
+ req1->rq_num_wqes);
+ CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_PAGE_SIZE_OFFSET(func),
+ PAGE_SIZE);
+ CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(func), PAGE_SHIFT);
+ CNIC_WR16(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(func),
+ req1->num_tasks_per_conn);
+
+ /* init Ustorm RAM */
+ CNIC_WR16(dev, BAR_USTRORM_INTMEM +
+ USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(func),
+ req1->rq_buffer_size);
+ CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_PAGE_SIZE_OFFSET(func),
+ PAGE_SIZE);
+ CNIC_WR8(dev, BAR_USTRORM_INTMEM +
+ USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(func), PAGE_SHIFT);
+ CNIC_WR16(dev, BAR_USTRORM_INTMEM +
+ USTORM_ISCSI_NUM_OF_TASKS_OFFSET(func),
+ req1->num_tasks_per_conn);
+ CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_RQ_SIZE_OFFSET(func),
+ req1->rq_num_wqes);
+ CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_CQ_SIZE_OFFSET(func),
+ req1->cq_num_wqes);
+ CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_R2TQ_SIZE_OFFSET(func),
+ cp->num_iscsi_tasks * BNX2X_ISCSI_MAX_PENDING_R2TS);
+
+ /* init Xstorm RAM */
+ CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_PAGE_SIZE_OFFSET(func),
+ PAGE_SIZE);
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(func), PAGE_SHIFT);
+ CNIC_WR16(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(func),
+ req1->num_tasks_per_conn);
+ CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_HQ_SIZE_OFFSET(func),
+ hq_bds);
+ CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_SQ_SIZE_OFFSET(func),
+ req1->num_tasks_per_conn);
+ CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_R2TQ_SIZE_OFFSET(func),
+ cp->num_iscsi_tasks * BNX2X_ISCSI_MAX_PENDING_R2TS);
+
+ /* init Cstorm RAM */
+ CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_PAGE_SIZE_OFFSET(func),
+ PAGE_SIZE);
+ CNIC_WR8(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(func), PAGE_SHIFT);
+ CNIC_WR16(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(func),
+ req1->num_tasks_per_conn);
+ CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_CQ_SIZE_OFFSET(func),
+ req1->cq_num_wqes);
+ CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_HQ_SIZE_OFFSET(func),
+ hq_bds);
+
+ return 0;
+}
+
+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;
+ struct iscsi_kcqe kcqe;
+ struct kcqe *cqes[1];
+
+ memset(&kcqe, 0, sizeof(kcqe));
+ if (!dev->max_iscsi_conn) {
+ kcqe.completion_status =
+ ISCSI_KCQE_COMPLETION_STATUS_ISCSI_NOT_SUPPORTED;
+ goto done;
+ }
+
+ CNIC_WR(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_ERROR_BITMAP_OFFSET(func), req2->error_bit_map[0]);
+ CNIC_WR(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_ERROR_BITMAP_OFFSET(func) + 4,
+ req2->error_bit_map[1]);
+
+ CNIC_WR16(dev, BAR_USTRORM_INTMEM +
+ USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(func), req2->max_cq_sqn);
+ CNIC_WR(dev, BAR_USTRORM_INTMEM +
+ USTORM_ISCSI_ERROR_BITMAP_OFFSET(func), req2->error_bit_map[0]);
+ CNIC_WR(dev, BAR_USTRORM_INTMEM +
+ USTORM_ISCSI_ERROR_BITMAP_OFFSET(func) + 4,
+ req2->error_bit_map[1]);
+
+ CNIC_WR16(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(func), req2->max_cq_sqn);
+
+ kcqe.completion_status = ISCSI_KCQE_COMPLETION_STATUS_SUCCESS;
+
+done:
+ kcqe.op_code = ISCSI_KCQE_OPCODE_INIT;
+ cqes[0] = (struct kcqe *) &kcqe;
+ cnic_reply_bnx2x_kcqes(dev, CNIC_ULP_ISCSI, cqes, 1);
+
+ return 0;
+}
+
+static void cnic_free_bnx2x_conn_resc(struct cnic_dev *dev, u32 l5_cid)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
+
+ if (ctx->ulp_proto_id == CNIC_ULP_ISCSI) {
+ struct cnic_iscsi *iscsi = ctx->proto.iscsi;
+
+ cnic_free_dma(dev, &iscsi->hq_info);
+ cnic_free_dma(dev, &iscsi->r2tq_info);
+ cnic_free_dma(dev, &iscsi->task_array_info);
+ }
+ cnic_free_id(&cp->cid_tbl, ctx->cid);
+ ctx->cid = 0;
+}
+
+static int cnic_alloc_bnx2x_conn_resc(struct cnic_dev *dev, u32 l5_cid)
+{
+ u32 cid;
+ int ret, pages;
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
+ struct cnic_iscsi *iscsi = ctx->proto.iscsi;
+
+ cid = cnic_alloc_new_id(&cp->cid_tbl);
+ if (cid == -1) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ctx->cid = cid;
+ pages = PAGE_ALIGN(cp->task_array_size) / PAGE_SIZE;
+
+ ret = cnic_alloc_dma(dev, &iscsi->task_array_info, pages, 1);
+ if (ret)
+ goto error;
+
+ pages = PAGE_ALIGN(cp->r2tq_size) / PAGE_SIZE;
+ ret = cnic_alloc_dma(dev, &iscsi->r2tq_info, pages, 1);
+ if (ret)
+ goto error;
+
+ pages = PAGE_ALIGN(cp->hq_size) / PAGE_SIZE;
+ ret = cnic_alloc_dma(dev, &iscsi->hq_info, pages, 1);
+ if (ret)
+ goto error;
+
+ return 0;
+
+error:
+ cnic_free_bnx2x_conn_resc(dev, l5_cid);
+ return ret;
+}
+
+static void *cnic_get_bnx2x_ctx(struct cnic_dev *dev, u32 cid, int init,
+ struct regpair *ctx_addr)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_eth_dev *ethdev = cp->ethdev;
+ int blk = (cid - ethdev->starting_cid) / cp->cids_per_blk;
+ int off = (cid - ethdev->starting_cid) % cp->cids_per_blk;
+ unsigned long align_off = 0;
+ dma_addr_t ctx_map;
+ void *ctx;
+
+ if (cp->ctx_align) {
+ unsigned long mask = cp->ctx_align - 1;
+
+ if (cp->ctx_arr[blk].mapping & mask)
+ align_off = cp->ctx_align -
+ (cp->ctx_arr[blk].mapping & mask);
+ }
+ ctx_map = cp->ctx_arr[blk].mapping + align_off +
+ (off * BNX2X_CONTEXT_MEM_SIZE);
+ ctx = cp->ctx_arr[blk].ctx + align_off +
+ (off * BNX2X_CONTEXT_MEM_SIZE);
+ if (init)
+ memset(ctx, 0, BNX2X_CONTEXT_MEM_SIZE);
+
+ ctx_addr->lo = ctx_map & 0xffffffff;
+ ctx_addr->hi = (u64) ctx_map >> 32;
+ return ctx;
+}
+
+static int cnic_setup_bnx2x_ctx(struct cnic_dev *dev, struct kwqe *wqes[],
+ u32 num)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct iscsi_kwqe_conn_offload1 *req1 =
+ (struct iscsi_kwqe_conn_offload1 *) wqes[0];
+ struct iscsi_kwqe_conn_offload2 *req2 =
+ (struct iscsi_kwqe_conn_offload2 *) wqes[1];
+ struct iscsi_kwqe_conn_offload3 *req3;
+ 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);
+ struct iscsi_context *ictx;
+ struct regpair context_addr;
+ int i, j, n = 2, n_max;
+
+ ctx->ctx_flags = 0;
+ if (!req2->num_additional_wqes)
+ return -EINVAL;
+
+ n_max = req2->num_additional_wqes + 2;
+
+ ictx = cnic_get_bnx2x_ctx(dev, cid, 1, &context_addr);
+ if (ictx == NULL)
+ return -ENOMEM;
+
+ req3 = (struct iscsi_kwqe_conn_offload3 *) wqes[n++];
+
+ ictx->xstorm_ag_context.hq_prod = 1;
+
+ ictx->xstorm_st_context.iscsi.first_burst_length =
+ ISCSI_DEF_FIRST_BURST_LEN;
+ ictx->xstorm_st_context.iscsi.max_send_pdu_length =
+ ISCSI_DEF_MAX_RECV_SEG_LEN;
+ ictx->xstorm_st_context.iscsi.sq_pbl_base.lo =
+ req1->sq_page_table_addr_lo;
+ ictx->xstorm_st_context.iscsi.sq_pbl_base.hi =
+ req1->sq_page_table_addr_hi;
+ ictx->xstorm_st_context.iscsi.sq_curr_pbe.lo = req2->sq_first_pte.hi;
+ ictx->xstorm_st_context.iscsi.sq_curr_pbe.hi = req2->sq_first_pte.lo;
+ ictx->xstorm_st_context.iscsi.hq_pbl_base.lo =
+ iscsi->hq_info.pgtbl_map & 0xffffffff;
+ ictx->xstorm_st_context.iscsi.hq_pbl_base.hi =
+ (u64) iscsi->hq_info.pgtbl_map >> 32;
+ ictx->xstorm_st_context.iscsi.hq_curr_pbe_base.lo =
+ iscsi->hq_info.pgtbl[0];
+ ictx->xstorm_st_context.iscsi.hq_curr_pbe_base.hi =
+ iscsi->hq_info.pgtbl[1];
+ ictx->xstorm_st_context.iscsi.r2tq_pbl_base.lo =
+ iscsi->r2tq_info.pgtbl_map & 0xffffffff;
+ ictx->xstorm_st_context.iscsi.r2tq_pbl_base.hi =
+ (u64) iscsi->r2tq_info.pgtbl_map >> 32;
+ ictx->xstorm_st_context.iscsi.r2tq_curr_pbe_base.lo =
+ iscsi->r2tq_info.pgtbl[0];
+ ictx->xstorm_st_context.iscsi.r2tq_curr_pbe_base.hi =
+ iscsi->r2tq_info.pgtbl[1];
+ ictx->xstorm_st_context.iscsi.task_pbl_base.lo =
+ iscsi->task_array_info.pgtbl_map & 0xffffffff;
+ ictx->xstorm_st_context.iscsi.task_pbl_base.hi =
+ (u64) iscsi->task_array_info.pgtbl_map >> 32;
+ ictx->xstorm_st_context.iscsi.task_pbl_cache_idx =
+ BNX2X_ISCSI_PBL_NOT_CACHED;
+ ictx->xstorm_st_context.iscsi.flags.flags |=
+ XSTORM_ISCSI_CONTEXT_FLAGS_B_IMMEDIATE_DATA;
+ ictx->xstorm_st_context.iscsi.flags.flags |=
+ XSTORM_ISCSI_CONTEXT_FLAGS_B_INITIAL_R2T;
+
+ ictx->tstorm_st_context.iscsi.hdr_bytes_2_fetch = ISCSI_HEADER_SIZE;
+ /* TSTORM requires the base address of RQ DB & not PTE */
+ ictx->tstorm_st_context.iscsi.rq_db_phy_addr.lo =
+ req2->rq_page_table_addr_lo & PAGE_MASK;
+ ictx->tstorm_st_context.iscsi.rq_db_phy_addr.hi =
+ req2->rq_page_table_addr_hi;
+ ictx->tstorm_st_context.iscsi.iscsi_conn_id = req1->iscsi_conn_id;
+ ictx->tstorm_st_context.tcp.cwnd = 0x5A8;
+ ictx->tstorm_st_context.tcp.flags2 |=
+ TSTORM_TCP_ST_CONTEXT_SECTION_DA_EN;
+
+ ictx->timers_context.flags |= ISCSI_TIMERS_BLOCK_CONTEXT_CONN_VALID_FLG;
+
+ ictx->ustorm_st_context.ring.rq.pbl_base.lo =
+ req2->rq_page_table_addr_lo & 0xffffffff;
+ ictx->ustorm_st_context.ring.rq.pbl_base.hi =
+ (u64) req2->rq_page_table_addr_hi >> 32;
+ ictx->ustorm_st_context.ring.rq.curr_pbe.lo = req3->qp_first_pte[0].hi;
+ ictx->ustorm_st_context.ring.rq.curr_pbe.hi = req3->qp_first_pte[0].lo;
+ ictx->ustorm_st_context.ring.r2tq.pbl_base.lo =
+ iscsi->r2tq_info.pgtbl_map & 0xffffffff;
+ ictx->ustorm_st_context.ring.r2tq.pbl_base.hi =
+ (u64) iscsi->r2tq_info.pgtbl_map >> 32;
+ ictx->ustorm_st_context.ring.r2tq.curr_pbe.lo =
+ iscsi->r2tq_info.pgtbl[0];
+ ictx->ustorm_st_context.ring.r2tq.curr_pbe.hi =
+ iscsi->r2tq_info.pgtbl[1];
+ ictx->ustorm_st_context.ring.cq_pbl_base.lo =
+ req1->cq_page_table_addr_lo;
+ ictx->ustorm_st_context.ring.cq_pbl_base.hi =
+ req1->cq_page_table_addr_hi;
+ ictx->ustorm_st_context.ring.cq[0].cq_sn = ISCSI_INITIAL_SN;
+ ictx->ustorm_st_context.ring.cq[0].curr_pbe.lo = req2->cq_first_pte.hi;
+ ictx->ustorm_st_context.ring.cq[0].curr_pbe.hi = req2->cq_first_pte.lo;
+ ictx->ustorm_st_context.task_pbe_cache_index =
+ BNX2X_ISCSI_PBL_NOT_CACHED;
+ ictx->ustorm_st_context.task_pdu_cache_index =
+ BNX2X_ISCSI_PDU_HEADER_NOT_CACHED;
+
+ for (i = 1, j = 1; i < cp->num_cqs; i++, j++) {
+ if (j == 3) {
+ if (n >= n_max)
+ break;
+ req3 = (struct iscsi_kwqe_conn_offload3 *) wqes[n++];
+ j = 0;
+ }
+ ictx->ustorm_st_context.ring.cq[i].cq_sn = ISCSI_INITIAL_SN;
+ ictx->ustorm_st_context.ring.cq[i].curr_pbe.lo =
+ req3->qp_first_pte[j].hi;
+ ictx->ustorm_st_context.ring.cq[i].curr_pbe.hi =
+ req3->qp_first_pte[j].lo;
+ }
+
+ ictx->ustorm_st_context.task_pbl_base.lo =
+ iscsi->task_array_info.pgtbl_map & 0xffffffff;
+ ictx->ustorm_st_context.task_pbl_base.hi =
+ (u64) iscsi->task_array_info.pgtbl_map >> 32;
+ ictx->ustorm_st_context.tce_phy_addr.lo =
+ iscsi->task_array_info.pgtbl[0];
+ ictx->ustorm_st_context.tce_phy_addr.hi =
+ iscsi->task_array_info.pgtbl[1];
+ ictx->ustorm_st_context.iscsi_conn_id = req1->iscsi_conn_id;
+ ictx->ustorm_st_context.num_cqs = cp->num_cqs;
+ ictx->ustorm_st_context.negotiated_rx |= ISCSI_DEF_MAX_RECV_SEG_LEN;
+ ictx->ustorm_st_context.negotiated_rx_and_flags |=
+ ISCSI_DEF_MAX_BURST_LEN;
+ ictx->ustorm_st_context.negotiated_rx |=
+ ISCSI_DEFAULT_MAX_OUTSTANDING_R2T <<
+ USTORM_ISCSI_ST_CONTEXT_MAX_OUTSTANDING_R2TS_SHIFT;
+
+ ictx->cstorm_st_context.hq_pbl_base.lo =
+ iscsi->hq_info.pgtbl_map & 0xffffffff;
+ ictx->cstorm_st_context.hq_pbl_base.hi =
+ (u64) iscsi->hq_info.pgtbl_map >> 32;
+ ictx->cstorm_st_context.hq_curr_pbe.lo = iscsi->hq_info.pgtbl[0];
+ ictx->cstorm_st_context.hq_curr_pbe.hi = iscsi->hq_info.pgtbl[1];
+ ictx->cstorm_st_context.task_pbl_base.lo =
+ iscsi->task_array_info.pgtbl_map & 0xffffffff;
+ ictx->cstorm_st_context.task_pbl_base.hi =
+ (u64) iscsi->task_array_info.pgtbl_map >> 32;
+ /* CSTORM and USTORM initialization is different, CSTORM requires
+ * CQ DB base & not PTE addr */
+ ictx->cstorm_st_context.cq_db_base.lo =
+ req1->cq_page_table_addr_lo & PAGE_MASK;
+ ictx->cstorm_st_context.cq_db_base.hi = req1->cq_page_table_addr_hi;
+ ictx->cstorm_st_context.iscsi_conn_id = req1->iscsi_conn_id;
+ ictx->cstorm_st_context.cq_proc_en_bit_map = (1 << cp->num_cqs) - 1;
+ for (i = 0; i < cp->num_cqs; i++) {
+ ictx->cstorm_st_context.cq_c_prod_sqn_arr.sqn[i] =
+ ISCSI_INITIAL_SN;
+ ictx->cstorm_st_context.cq_c_sqn_2_notify_arr.sqn[i] =
+ ISCSI_INITIAL_SN;
+ }
+
+ ictx->xstorm_ag_context.cdu_reserved =
+ CDU_RSRVD_VALUE_TYPE_A(hw_cid, CDU_REGION_NUMBER_XCM_AG,
+ ISCSI_CONNECTION_TYPE);
+ ictx->ustorm_ag_context.cdu_usage =
+ CDU_RSRVD_VALUE_TYPE_A(hw_cid, CDU_REGION_NUMBER_UCM_AG,
+ ISCSI_CONNECTION_TYPE);
+ return 0;
+
+}
+
+static int cnic_bnx2x_iscsi_ofld1(struct cnic_dev *dev, struct kwqe *wqes[],
+ u32 num, int *work)
+{
+ struct iscsi_kwqe_conn_offload1 *req1;
+ struct iscsi_kwqe_conn_offload2 *req2;
+ struct cnic_local *cp = dev->cnic_priv;
+ struct iscsi_kcqe kcqe;
+ struct kcqe *cqes[1];
+ u32 l5_cid;
+ int ret;
+
+ if (num < 2) {
+ *work = num;
+ return -EINVAL;
+ }
+
+ req1 = (struct iscsi_kwqe_conn_offload1 *) wqes[0];
+ req2 = (struct iscsi_kwqe_conn_offload2 *) wqes[1];
+ if ((num - 2) < req2->num_additional_wqes) {
+ *work = num;
+ return -EINVAL;
+ }
+ *work = 2 + req2->num_additional_wqes;;
+
+ l5_cid = req1->iscsi_conn_id;
+ if (l5_cid >= MAX_ISCSI_TBL_SZ)
+ return -EINVAL;
+
+ memset(&kcqe, 0, sizeof(kcqe));
+ kcqe.op_code = ISCSI_KCQE_OPCODE_OFFLOAD_CONN;
+ kcqe.iscsi_conn_id = l5_cid;
+ kcqe.completion_status = ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE;
+
+ 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);
+ if (ret) {
+ atomic_dec(&cp->iscsi_conn);
+ ret = 0;
+ goto done;
+ }
+ ret = cnic_setup_bnx2x_ctx(dev, wqes, num);
+ if (ret < 0) {
+ cnic_free_bnx2x_conn_resc(dev, l5_cid);
+ atomic_dec(&cp->iscsi_conn);
+ goto done;
+ }
+
+ kcqe.completion_status = ISCSI_KCQE_COMPLETION_STATUS_SUCCESS;
+ kcqe.iscsi_conn_context_id = BNX2X_HW_CID(cp->ctx_tbl[l5_cid].cid,
+ cp->func);
+
+done:
+ cqes[0] = (struct kcqe *) &kcqe;
+ cnic_reply_bnx2x_kcqes(dev, CNIC_ULP_ISCSI, cqes, 1);
+ return ret;
+}
+
+
+static int cnic_bnx2x_iscsi_update(struct cnic_dev *dev, struct kwqe *kwqe)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct iscsi_kwqe_conn_update *req =
+ (struct iscsi_kwqe_conn_update *) kwqe;
+ void *data;
+ union l5cm_specific_data l5_data;
+ u32 l5_cid, cid = BNX2X_SW_CID(req->context_id);
+ int ret;
+
+ if (cnic_get_l5_cid(cp, cid, &l5_cid) != 0)
+ return -EINVAL;
+
+ data = cnic_get_kwqe_16_data(cp, l5_cid, &l5_data);
+ if (!data)
+ return -ENOMEM;
+
+ memcpy(data, kwqe, sizeof(struct kwqe));
+
+ ret = cnic_submit_kwqe_16(dev, ISCSI_RAMROD_CMD_ID_UPDATE_CONN,
+ req->context_id, ISCSI_CONNECTION_TYPE, &l5_data);
+ 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))
+ goto skip_cfc_delete;
+
+ while (!time_after(jiffies, ctx->timestamp + (2 * HZ)))
+ msleep(250);
+
+ 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);
+
+skip_cfc_delete:
+ cnic_free_bnx2x_conn_resc(dev, l5_cid);
+
+ atomic_dec(&cp->iscsi_conn);
+
+ memset(&kcqe, 0, sizeof(kcqe));
+ kcqe.op_code = ISCSI_KCQE_OPCODE_DESTROY_CONN;
+ kcqe.iscsi_conn_id = l5_cid;
+ kcqe.completion_status = ISCSI_KCQE_COMPLETION_STATUS_SUCCESS;
+ kcqe.iscsi_conn_context_id = req->context_id;
+
+ cqes[0] = (struct kcqe *) &kcqe;
+ cnic_reply_bnx2x_kcqes(dev, CNIC_ULP_ISCSI, cqes, 1);
+
+ return ret;
+}
+
+static void cnic_init_storm_conn_bufs(struct cnic_dev *dev,
+ struct l4_kwq_connect_req1 *kwqe1,
+ struct l4_kwq_connect_req3 *kwqe3,
+ struct l5cm_active_conn_buffer *conn_buf)
+{
+ struct l5cm_conn_addr_params *conn_addr = &conn_buf->conn_addr_buf;
+ struct l5cm_xstorm_conn_buffer *xstorm_buf =
+ &conn_buf->xstorm_conn_buffer;
+ struct l5cm_tstorm_conn_buffer *tstorm_buf =
+ &conn_buf->tstorm_conn_buffer;
+ struct regpair context_addr;
+ u32 cid = BNX2X_SW_CID(kwqe1->cid);
+ struct in6_addr src_ip, dst_ip;
+ int i;
+ u32 *addrp;
+
+ addrp = (u32 *) &conn_addr->local_ip_addr;
+ for (i = 0; i < 4; i++, addrp++)
+ src_ip.in6_u.u6_addr32[i] = cpu_to_be32(*addrp);
+
+ addrp = (u32 *) &conn_addr->remote_ip_addr;
+ for (i = 0; i < 4; i++, addrp++)
+ dst_ip.in6_u.u6_addr32[i] = cpu_to_be32(*addrp);
+
+ cnic_get_bnx2x_ctx(dev, cid, 0, &context_addr);
+
+ xstorm_buf->context_addr.hi = context_addr.hi;
+ xstorm_buf->context_addr.lo = context_addr.lo;
+ xstorm_buf->mss = 0xffff;
+ xstorm_buf->rcv_buf = kwqe3->rcv_buf;
+ if (kwqe1->tcp_flags & L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE)
+ xstorm_buf->params |= L5CM_XSTORM_CONN_BUFFER_NAGLE_ENABLE;
+ xstorm_buf->pseudo_header_checksum =
+ swab16(~csum_ipv6_magic(&src_ip, &dst_ip, 0, IPPROTO_TCP, 0));
+
+ if (!(kwqe1->tcp_flags & L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK))
+ tstorm_buf->params |=
+ L5CM_TSTORM_CONN_BUFFER_DELAYED_ACK_ENABLE;
+ if (kwqe3->ka_timeout) {
+ tstorm_buf->ka_enable = 1;
+ tstorm_buf->ka_timeout = kwqe3->ka_timeout;
+ tstorm_buf->ka_interval = kwqe3->ka_interval;
+ tstorm_buf->ka_max_probe_count = kwqe3->ka_max_probe_count;
+ }
+ tstorm_buf->rcv_buf = kwqe3->rcv_buf;
+ tstorm_buf->snd_buf = kwqe3->snd_buf;
+ tstorm_buf->max_rt_time = 0xffffffff;
+}
+
+static void cnic_init_bnx2x_mac(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int func = CNIC_FUNC(cp);
+ u8 *mac = dev->mac_addr;
+
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(func), mac[0]);
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(func), mac[1]);
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(func), mac[2]);
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(func), mac[3]);
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(func), mac[4]);
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(func), mac[5]);
+
+ CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(func), mac[5]);
+ CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(func) + 1,
+ mac[4]);
+ CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(func), mac[3]);
+ CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(func) + 1,
+ mac[2]);
+ CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(func) + 2,
+ mac[1]);
+ CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(func) + 3,
+ mac[0]);
+}
+
+static void cnic_bnx2x_set_tcp_timestamp(struct cnic_dev *dev, int tcp_ts)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ u8 xstorm_flags = XSTORM_L5CM_TCP_FLAGS_WND_SCL_EN;
+ u16 tstorm_flags = 0;
+
+ if (tcp_ts) {
+ xstorm_flags |= XSTORM_L5CM_TCP_FLAGS_TS_ENABLED;
+ tstorm_flags |= TSTORM_L5CM_TCP_FLAGS_TS_ENABLED;
+ }
+
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->func), xstorm_flags);
+
+ CNIC_WR16(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->func), tstorm_flags);
+}
+
+static int cnic_bnx2x_connect(struct cnic_dev *dev, struct kwqe *wqes[],
+ u32 num, int *work)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct l4_kwq_connect_req1 *kwqe1 =
+ (struct l4_kwq_connect_req1 *) wqes[0];
+ struct l4_kwq_connect_req3 *kwqe3;
+ struct l5cm_active_conn_buffer *conn_buf;
+ struct l5cm_conn_addr_params *conn_addr;
+ union l5cm_specific_data l5_data;
+ u32 l5_cid = kwqe1->pg_cid;
+ struct cnic_sock *csk = &cp->csk_tbl[l5_cid];
+ struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
+ int ret;
+
+ if (num < 2) {
+ *work = num;
+ return -EINVAL;
+ }
+
+ if (kwqe1->conn_flags & L4_KWQ_CONNECT_REQ1_IP_V6)
+ *work = 3;
+ else
+ *work = 2;
+
+ if (num < *work) {
+ *work = num;
+ return -EINVAL;
+ }
+
+ if (sizeof(*conn_buf) > CNIC_KWQ16_DATA_SIZE) {
+ printk(KERN_ERR PFX "%s: conn_buf size too big\n",
+ dev->netdev->name);
+ return -ENOMEM;
+ }
+ conn_buf = cnic_get_kwqe_16_data(cp, l5_cid, &l5_data);
+ if (!conn_buf)
+ return -ENOMEM;
+
+ memset(conn_buf, 0, sizeof(*conn_buf));
+
+ conn_addr = &conn_buf->conn_addr_buf;
+ conn_addr->remote_addr_0 = csk->ha[0];
+ conn_addr->remote_addr_1 = csk->ha[1];
+ conn_addr->remote_addr_2 = csk->ha[2];
+ conn_addr->remote_addr_3 = csk->ha[3];
+ conn_addr->remote_addr_4 = csk->ha[4];
+ conn_addr->remote_addr_5 = csk->ha[5];
+
+ if (kwqe1->conn_flags & L4_KWQ_CONNECT_REQ1_IP_V6) {
+ struct l4_kwq_connect_req2 *kwqe2 =
+ (struct l4_kwq_connect_req2 *) wqes[1];
+
+ conn_addr->local_ip_addr.ip_addr_hi_hi = kwqe2->src_ip_v6_4;
+ conn_addr->local_ip_addr.ip_addr_hi_lo = kwqe2->src_ip_v6_3;
+ conn_addr->local_ip_addr.ip_addr_lo_hi = kwqe2->src_ip_v6_2;
+
+ conn_addr->remote_ip_addr.ip_addr_hi_hi = kwqe2->dst_ip_v6_4;
+ conn_addr->remote_ip_addr.ip_addr_hi_lo = kwqe2->dst_ip_v6_3;
+ conn_addr->remote_ip_addr.ip_addr_lo_hi = kwqe2->dst_ip_v6_2;
+ conn_addr->params |= L5CM_CONN_ADDR_PARAMS_IP_VERSION;
+ }
+ kwqe3 = (struct l4_kwq_connect_req3 *) wqes[*work - 1];
+
+ conn_addr->local_ip_addr.ip_addr_lo_lo = kwqe1->src_ip;
+ conn_addr->remote_ip_addr.ip_addr_lo_lo = kwqe1->dst_ip;
+ conn_addr->local_tcp_port = kwqe1->src_port;
+ conn_addr->remote_tcp_port = kwqe1->dst_port;
+
+ conn_addr->pmtu = kwqe3->pmtu;
+ 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);
+
+ cnic_bnx2x_set_tcp_timestamp(dev,
+ kwqe1->tcp_flags & L4_KWQ_CONNECT_REQ1_TIME_STAMP);
+
+ 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;
+
+ return ret;
+}
+
+static int cnic_bnx2x_close(struct cnic_dev *dev, struct kwqe *kwqe)
+{
+ struct l4_kwq_close_req *req = (struct l4_kwq_close_req *) kwqe;
+ union l5cm_specific_data l5_data;
+ int ret;
+
+ memset(&l5_data, 0, sizeof(l5_data));
+ ret = cnic_submit_kwqe_16(dev, L5CM_RAMROD_CMD_ID_CLOSE,
+ req->cid, ISCSI_CONNECTION_TYPE, &l5_data);
+ return ret;
+}
+
+static int cnic_bnx2x_reset(struct cnic_dev *dev, struct kwqe *kwqe)
+{
+ struct l4_kwq_reset_req *req = (struct l4_kwq_reset_req *) kwqe;
+ union l5cm_specific_data l5_data;
+ int ret;
+
+ memset(&l5_data, 0, sizeof(l5_data));
+ ret = cnic_submit_kwqe_16(dev, L5CM_RAMROD_CMD_ID_ABORT,
+ req->cid, ISCSI_CONNECTION_TYPE, &l5_data);
+ return ret;
+}
+static int cnic_bnx2x_offload_pg(struct cnic_dev *dev, struct kwqe *kwqe)
+{
+ struct l4_kwq_offload_pg *req = (struct l4_kwq_offload_pg *) kwqe;
+ struct l4_kcq kcqe;
+ struct kcqe *cqes[1];
+
+ memset(&kcqe, 0, sizeof(kcqe));
+ kcqe.pg_host_opaque = req->host_opaque;
+ kcqe.pg_cid = req->host_opaque;
+ kcqe.op_code = L4_KCQE_OPCODE_VALUE_OFFLOAD_PG;
+ cqes[0] = (struct kcqe *) &kcqe;
+ cnic_reply_bnx2x_kcqes(dev, CNIC_ULP_L4, cqes, 1);
+ return 0;
+}
+
+static int cnic_bnx2x_update_pg(struct cnic_dev *dev, struct kwqe *kwqe)
+{
+ struct l4_kwq_update_pg *req = (struct l4_kwq_update_pg *) kwqe;
+ struct l4_kcq kcqe;
+ struct kcqe *cqes[1];
+
+ memset(&kcqe, 0, sizeof(kcqe));
+ kcqe.pg_host_opaque = req->pg_host_opaque;
+ kcqe.pg_cid = req->pg_cid;
+ kcqe.op_code = L4_KCQE_OPCODE_VALUE_UPDATE_PG;
+ cqes[0] = (struct kcqe *) &kcqe;
+ cnic_reply_bnx2x_kcqes(dev, CNIC_ULP_L4, cqes, 1);
+ return 0;
+}
+
+static int cnic_submit_bnx2x_kwqes(struct cnic_dev *dev, struct kwqe *wqes[],
+ u32 num_wqes)
+{
+ int i, work, ret;
+ u32 opcode;
+ struct kwqe *kwqe;
+
+ if (!test_bit(CNIC_F_CNIC_UP, &dev->flags))
+ return -EAGAIN; /* bnx2 is down */
+
+ for (i = 0; i < num_wqes; ) {
+ kwqe = wqes[i];
+ opcode = KWQE_OPCODE(kwqe->kwqe_op_flag);
+ work = 1;
+
+ switch (opcode) {
+ case ISCSI_KWQE_OPCODE_INIT1:
+ ret = cnic_bnx2x_iscsi_init1(dev, kwqe);
+ break;
+ case ISCSI_KWQE_OPCODE_INIT2:
+ ret = cnic_bnx2x_iscsi_init2(dev, kwqe);
+ break;
+ case ISCSI_KWQE_OPCODE_OFFLOAD_CONN1:
+ ret = cnic_bnx2x_iscsi_ofld1(dev, &wqes[i],
+ num_wqes - i, &work);
+ break;
+ case ISCSI_KWQE_OPCODE_UPDATE_CONN:
+ ret = cnic_bnx2x_iscsi_update(dev, kwqe);
+ break;
+ case ISCSI_KWQE_OPCODE_DESTROY_CONN:
+ ret = cnic_bnx2x_iscsi_destroy(dev, kwqe);
+ break;
+ case L4_KWQE_OPCODE_VALUE_CONNECT1:
+ ret = cnic_bnx2x_connect(dev, &wqes[i], num_wqes - i,
+ &work);
+ break;
+ case L4_KWQE_OPCODE_VALUE_CLOSE:
+ ret = cnic_bnx2x_close(dev, kwqe);
+ break;
+ case L4_KWQE_OPCODE_VALUE_RESET:
+ ret = cnic_bnx2x_reset(dev, kwqe);
+ break;
+ case L4_KWQE_OPCODE_VALUE_OFFLOAD_PG:
+ ret = cnic_bnx2x_offload_pg(dev, kwqe);
+ break;
+ case L4_KWQE_OPCODE_VALUE_UPDATE_PG:
+ ret = cnic_bnx2x_update_pg(dev, kwqe);
+ break;
+ case L4_KWQE_OPCODE_VALUE_UPLOAD_PG:
+ ret = 0;
+ break;
+ default:
+ ret = 0;
+ printk(KERN_ERR PFX "%s: Unknown type of KWQE(0x%x)\n",
+ dev->netdev->name, opcode);
+ break;
+ }
+ if (ret < 0)
+ printk(KERN_ERR PFX "%s: KWQE(0x%x) failed\n",
+ dev->netdev->name, opcode);
+ i += work;
+ }
+ return 0;
+}
+
static void service_kcqes(struct cnic_dev *dev, int num_cqes)
{
struct cnic_local *cp = dev->cnic_priv;
@@ -987,6 +2096,22 @@ static u16 cnic_bnx2_hw_idx(u16 idx)
return idx;
}
+static u16 cnic_bnx2x_next_idx(u16 idx)
+{
+ idx++;
+ if ((idx & MAX_KCQE_CNT) == MAX_KCQE_CNT)
+ idx++;
+
+ return idx;
+}
+
+static u16 cnic_bnx2x_hw_idx(u16 idx)
+{
+ if ((idx & MAX_KCQE_CNT) == MAX_KCQE_CNT)
+ idx++;
+ return idx;
+}
+
static int cnic_get_kcqes(struct cnic_dev *dev, u16 hw_prod, u16 *sw_prod)
{
struct cnic_local *cp = dev->cnic_priv;
@@ -1012,7 +2137,7 @@ static int cnic_get_kcqes(struct cnic_dev *dev, u16 hw_prod, u16 *sw_prod)
return last_cnt;
}
-static void cnic_chk_bnx2_pkt_rings(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;
@@ -1020,6 +2145,7 @@ static void cnic_chk_bnx2_pkt_rings(struct cnic_local *cp)
if (cp->tx_cons != tx_cons || cp->rx_cons != rx_cons) {
cp->tx_cons = tx_cons;
cp->rx_cons = rx_cons;
+
uio_event_notify(cp->cnic_uinfo);
}
}
@@ -1062,7 +2188,7 @@ done:
cp->kcq_prod_idx = sw_prod;
- cnic_chk_bnx2_pkt_rings(cp);
+ cnic_chk_pkt_rings(cp);
return status_idx;
}
@@ -1100,7 +2226,7 @@ done:
CNIC_WR16(dev, cp->kcq_io_addr, sw_prod);
cp->kcq_prod_idx = sw_prod;
- cnic_chk_bnx2_pkt_rings(cp);
+ cnic_chk_pkt_rings(cp);
cp->last_status_idx = status_idx;
CNIC_WR(dev, BNX2_PCICFG_INT_ACK_CMD, cp->int_num |
@@ -1125,6 +2251,91 @@ static irqreturn_t cnic_irq(int irq, void *dev_instance)
return IRQ_HANDLED;
}
+static inline void cnic_ack_bnx2x_int(struct cnic_dev *dev, u8 id, u8 storm,
+ u16 index, u8 op, u8 update)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ u32 hc_addr = (HC_REG_COMMAND_REG + CNIC_PORT(cp) * 32 +
+ COMMAND_REG_INT_ACK);
+ struct igu_ack_register igu_ack;
+
+ igu_ack.status_block_index = index;
+ igu_ack.sb_id_and_flags =
+ ((id << IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT) |
+ (storm << IGU_ACK_REGISTER_STORM_ID_SHIFT) |
+ (update << IGU_ACK_REGISTER_UPDATE_INDEX_SHIFT) |
+ (op << IGU_ACK_REGISTER_INTERRUPT_MODE_SHIFT));
+
+ CNIC_WR(dev, hc_addr, (*(u32 *)&igu_ack));
+}
+
+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,
+ IGU_INT_DISABLE, 0);
+}
+
+static void cnic_service_bnx2x_bh(unsigned long data)
+{
+ struct cnic_dev *dev = (struct cnic_dev *) data;
+ struct cnic_local *cp = dev->cnic_priv;
+ u16 hw_prod, sw_prod;
+ struct cstorm_status_block_c *sblk =
+ &cp->bnx2x_status_blk->c_status_block;
+ u32 status_idx = sblk->status_block_index;
+ int kcqe_cnt;
+
+ if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags)))
+ return;
+
+ hw_prod = sblk->index_values[HC_INDEX_C_ISCSI_EQ_CONS];
+ hw_prod = cp->hw_idx(hw_prod);
+ sw_prod = cp->kcq_prod_idx;
+ while (sw_prod != hw_prod) {
+ kcqe_cnt = cnic_get_kcqes(dev, hw_prod, &sw_prod);
+ if (kcqe_cnt == 0)
+ goto done;
+
+ service_kcqes(dev, kcqe_cnt);
+
+ /* Tell compiler that sblk fields can change. */
+ barrier();
+ if (status_idx == sblk->status_block_index)
+ break;
+
+ status_idx = sblk->status_block_index;
+ hw_prod = sblk->index_values[HC_INDEX_C_ISCSI_EQ_CONS];
+ hw_prod = cp->hw_idx(hw_prod);
+ }
+
+done:
+ CNIC_WR16(dev, cp->kcq_io_addr, sw_prod + MAX_KCQ_IDX);
+ cnic_ack_bnx2x_int(dev, cp->status_blk_num, CSTORM_ID,
+ status_idx, IGU_INT_ENABLE, 1);
+
+ cp->kcq_prod_idx = sw_prod;
+ return;
+}
+
+static int cnic_service_bnx2x(void *data, void *status_blk)
+{
+ struct cnic_dev *dev = data;
+ struct cnic_local *cp = dev->cnic_priv;
+ u16 prod = cp->kcq_prod_idx & MAX_KCQ_IDX;
+
+ prefetch(cp->status_blk);
+ prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
+
+ if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags)))
+ tasklet_schedule(&cp->cnic_irq_task);
+
+ cnic_chk_pkt_rings(cp);
+
+ return 0;
+}
+
static void cnic_ulp_stop(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
@@ -1197,6 +2408,19 @@ static int cnic_ctl(void *data, struct cnic_ctl_info *info)
cnic_put(dev);
break;
+ case CNIC_CTL_COMPLETION_CMD: {
+ u32 cid = BNX2X_SW_CID(info->data.comp.cid);
+ u32 l5_cid;
+ struct cnic_local *cp = dev->cnic_priv;
+
+ if (cnic_get_l5_cid(cp, cid, &l5_cid) == 0) {
+ struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
+
+ ctx->wait_cond = 1;
+ wake_up(&ctx->waitq);
+ }
+ break;
+ }
default:
return -EINVAL;
}
@@ -1872,6 +3096,8 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
/* fall through */
case L4_KCQE_OPCODE_VALUE_CLOSE_COMP:
case L4_KCQE_OPCODE_VALUE_RESET_COMP:
+ case L5CM_RAMROD_CMD_ID_SEARCHER_DELETE:
+ case L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD:
cp->close_conn(csk, opcode);
break;
@@ -1957,6 +3183,76 @@ static int cnic_cm_init_bnx2_hw(struct cnic_dev *dev)
return 0;
}
+static void cnic_close_bnx2x_conn(struct cnic_sock *csk, u32 opcode)
+{
+ struct cnic_dev *dev = csk->dev;
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_context *ctx = &cp->ctx_tbl[csk->l5_cid];
+ union l5cm_specific_data l5_data;
+ u32 cmd = 0;
+ int close_complete = 0;
+
+ switch (opcode) {
+ case L4_KCQE_OPCODE_VALUE_RESET_RECEIVED:
+ case L4_KCQE_OPCODE_VALUE_CLOSE_COMP:
+ case L4_KCQE_OPCODE_VALUE_RESET_COMP:
+ if (cnic_ready_to_close(csk, opcode))
+ cmd = L5CM_RAMROD_CMD_ID_SEARCHER_DELETE;
+ break;
+ case L5CM_RAMROD_CMD_ID_SEARCHER_DELETE:
+ cmd = L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD;
+ break;
+ case L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD:
+ close_complete = 1;
+ break;
+ }
+ if (cmd) {
+ memset(&l5_data, 0, sizeof(l5_data));
+
+ cnic_submit_kwqe_16(dev, cmd, csk->cid, ISCSI_CONNECTION_TYPE,
+ &l5_data);
+ } else if (close_complete) {
+ ctx->timestamp = jiffies;
+ cnic_close_conn(csk);
+ cnic_cm_upcall(cp, csk, csk->state);
+ }
+}
+
+static void cnic_cm_stop_bnx2x_hw(struct cnic_dev *dev)
+{
+}
+
+static int cnic_cm_init_bnx2x_hw(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int func = CNIC_FUNC(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);
+
+ CNIC_WR(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_ENABLED_OFFSET(func), 1);
+ CNIC_WR(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_MAX_COUNT_OFFSET(func),
+ DEF_MAX_DA_COUNT);
+
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_TCP_VARS_TTL_OFFSET(func), DEF_TTL);
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_TCP_VARS_TOS_OFFSET(func), DEF_TOS);
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_TCP_VARS_ADV_WND_SCL_OFFSET(func), 2);
+ CNIC_WR(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_TCP_TX_SWS_TIMER_VAL_OFFSET(func), DEF_SWS_TIMER);
+
+ CNIC_WR(dev, BAR_TSTRORM_INTMEM + TSTORM_TCP_MAX_CWND_OFFSET(func),
+ DEF_MAX_CWND);
+ return 0;
+}
+
static int cnic_cm_open(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
@@ -2464,6 +3760,417 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
return 0;
}
+static void cnic_setup_bnx2x_context(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_eth_dev *ethdev = cp->ethdev;
+ u32 start_offset = ethdev->ctx_tbl_offset;
+ int i;
+
+ for (i = 0; i < cp->ctx_blks; i++) {
+ struct cnic_ctx *ctx = &cp->ctx_arr[i];
+ dma_addr_t map = ctx->mapping;
+
+ if (cp->ctx_align) {
+ unsigned long mask = cp->ctx_align - 1;
+
+ map = (map + mask) & ~mask;
+ }
+
+ cnic_ctx_tbl_wr(dev, start_offset + i, map);
+ }
+}
+
+static int cnic_init_bnx2x_irq(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_eth_dev *ethdev = cp->ethdev;
+ int err = 0;
+
+ 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);
+ }
+ return err;
+}
+
+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);
+}
+
+static void cnic_disable_bnx2x_int_sync(struct cnic_dev *dev)
+{
+}
+
+static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev)
+{
+ 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);
+ int port = CNIC_PORT(cp);
+ int i;
+ int cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp));
+ u32 val;
+
+ memset(txbd, 0, BCM_PAGE_SIZE);
+
+ buf_map = cp->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);
+
+ start_bd->addr_hi = cpu_to_le32((u64) buf_map >> 32);
+ start_bd->addr_lo = cpu_to_le32(buf_map & 0xffffffff);
+ reg_bd->addr_hi = start_bd->addr_hi;
+ reg_bd->addr_lo = start_bd->addr_lo + 0x10;
+ start_bd->nbytes = cpu_to_le16(0x10);
+ start_bd->nbd = cpu_to_le16(3);
+ start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
+ start_bd->general_data = (UNICAST_ADDRESS <<
+ ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT);
+ 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;
+ txbd->next_bd.addr_hi = cpu_to_le32(val);
+
+ context->xstorm_st_context.tx_bd_page_base_hi = val;
+
+ val = (u64) cp->l2_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;
+
+ 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);
+
+ /* reset xstorm per client statistics */
+ val = BAR_XSTRORM_INTMEM +
+ XSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli);
+ for (i = 0; i < sizeof(struct xstorm_per_client_stats) / 4; i++)
+ CNIC_WR(dev, val + i * 4, 0);
+
+ cp->tx_cons_ptr =
+ &cp->bnx2x_def_status_blk->c_def_status_block.index_values[
+ HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS];
+}
+
+static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct eth_rx_bd *rxbd = (struct eth_rx_bd *) (cp->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;
+ int i;
+ int port = CNIC_PORT(cp);
+ int func = CNIC_FUNC(cp);
+ int cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp));
+ u32 val;
+ struct tstorm_eth_client_config tstorm_client = {0};
+
+ 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);
+ 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;
+ rxbd->addr_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;
+ 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;
+ 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);
+
+ rxcqe += BNX2X_MAX_RCQ_DESC_CNT;
+ val = (u64) (cp->l2_ring_map + (2 * BCM_PAGE_SIZE)) >> 32;
+ rxcqe->addr_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;
+ rxcqe->addr_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 |
+ TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE);
+ tstorm_client.statistics_counter_id = cli;
+
+ 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]);
+
+ /* reset tstorm per client statistics */
+ 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 */
+ val = BAR_USTRORM_INTMEM +
+ USTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli);
+ for (i = 0; i < sizeof(struct ustorm_per_client_stats) / 4; i++)
+ CNIC_WR(dev, val + i * 4, 0);
+
+ cp->rx_cons_ptr =
+ &cp->bnx2x_def_status_blk->u_def_status_block.index_values[
+ HC_INDEX_DEF_U_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;
+ int port = CNIC_PORT(cp);
+
+ dev->max_iscsi_conn = 0;
+ base = CNIC_RD(dev, MISC_REG_SHARED_MEM_ADDR);
+ if (base < 0xa0000 || base >= 0xc0000)
+ return;
+
+ val = BNX2X_SHMEM_ADDR(base,
+ dev_info.port_hw_config[port].iscsi_mac_upper);
+
+ dev->mac_addr[0] = (u8) (val >> 8);
+ dev->mac_addr[1] = (u8) val;
+
+ val = BNX2X_SHMEM_ADDR(base,
+ dev_info.port_hw_config[port].iscsi_mac_lower);
+
+ dev->mac_addr[2] = (u8) (val >> 24);
+ dev->mac_addr[3] = (u8) (val >> 16);
+ dev->mac_addr[4] = (u8) (val >> 8);
+ dev->mac_addr[5] = (u8) val;
+
+ addr = BNX2X_SHMEM_ADDR(base, validity_map[port]);
+ val = CNIC_RD(dev, addr);
+
+ if (!(val & SHR_MEM_VALIDITY_LIC_NO_KEY_IN_EFFECT)) {
+ u16 val16;
+
+ addr = BNX2X_SHMEM_ADDR(base,
+ drv_lic_key[port].max_iscsi_init_conn);
+ val16 = CNIC_RD16(dev, addr);
+
+ if (val16)
+ val16 ^= 0x1e1e;
+ dev->max_iscsi_conn = val16;
+ }
+ if (BNX2X_CHIP_IS_E1H(cp->chip_id)) {
+ int func = CNIC_FUNC(cp);
+
+ 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);
+ val = CNIC_RD(dev, addr);
+ val &= FUNC_MF_CFG_PROTOCOL_MASK;
+ if (val != FUNC_MF_CFG_PROTOCOL_ISCSI)
+ dev->max_iscsi_conn = 0;
+ }
+ }
+}
+
+static int cnic_start_bnx2x_hw(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int func = CNIC_FUNC(cp), ret, i;
+ int port = CNIC_PORT(cp);
+ u16 eq_idx;
+ u8 sb_id = cp->status_blk_num;
+
+ ret = cnic_init_id_tbl(&cp->cid_tbl, MAX_ISCSI_TBL_SZ,
+ BNX2X_ISCSI_START_CID);
+
+ if (ret)
+ return -ENOMEM;
+
+ cp->kcq_io_addr = BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_EQ_PROD_OFFSET(func, 0);
+ cp->kcq_prod_idx = 0;
+
+ cnic_get_bnx2x_iscsi_info(dev);
+
+ /* Only 1 EQ */
+ CNIC_WR16(dev, cp->kcq_io_addr, MAX_KCQ_IDX);
+ CNIC_WR(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_EQ_CONS_OFFSET(func, 0), 0);
+ CNIC_WR(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(func, 0),
+ cp->kcq_info.pg_map_arr[1] & 0xffffffff);
+ CNIC_WR(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(func, 0) + 4,
+ (u64) cp->kcq_info.pg_map_arr[1] >> 32);
+ CNIC_WR(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(func, 0),
+ cp->kcq_info.pg_map_arr[0] & 0xffffffff);
+ CNIC_WR(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(func, 0) + 4,
+ (u64) cp->kcq_info.pg_map_arr[0] >> 32);
+ CNIC_WR8(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(func, 0), 1);
+ CNIC_WR16(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_EQ_SB_NUM_OFFSET(func, 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);
+
+ 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),
+ cp->conn_buf_info.pgtbl[2 * i]);
+ CNIC_WR(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_CONN_BUF_PBL_OFFSET(func, i) + 4,
+ cp->conn_buf_info.pgtbl[(2 * i) + 1]);
+ }
+
+ CNIC_WR(dev, BAR_USTRORM_INTMEM +
+ USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(func),
+ cp->gbl_buf_info.pg_map_arr[0] & 0xffffffff);
+ CNIC_WR(dev, BAR_USTRORM_INTMEM +
+ USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(func) + 4,
+ (u64) cp->gbl_buf_info.pg_map_arr[0] >> 32);
+
+ 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) {
+ printk(KERN_ERR PFX "%s: EQ cons index %x != 0\n",
+ dev->netdev->name, 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)
+{
+ if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) {
+ cnic_init_bnx2_tx_ring(dev);
+ cnic_init_bnx2_rx_ring(dev);
+ } else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_eth_dev *ethdev = cp->ethdev;
+ u32 cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp));
+ union l5cm_specific_data l5_data;
+ struct ustorm_eth_rx_producers rx_prods = {0};
+ void __iomem *doorbell;
+ int i;
+
+ rx_prods.bd_prod = 0;
+ rx_prods.cqe_prod = BNX2X_MAX_RCQ_DESC_CNT;
+ barrier();
+
+ doorbell = ethdev->io_base2 + BAR_USTRORM_INTMEM +
+ USTORM_RX_PRODS_OFFSET(CNIC_PORT(cp), cli);
+
+ for (i = 0; i < sizeof(struct ustorm_eth_rx_producers) / 4; i++)
+ writel(((u32 *) &rx_prods)[i], doorbell + i * 4);
+
+ cnic_init_bnx2x_tx_ring(dev);
+ cnic_init_bnx2x_rx_ring(dev);
+
+ 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);
+ cnic_ring_ctl(dev, BNX2X_ISCSI_L2_CID, cli, 1);
+ }
+}
+
+static void cnic_shutdown_rings(struct cnic_dev *dev)
+{
+ 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)) {
+ struct cnic_local *cp = dev->cnic_priv;
+ u32 cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp));
+
+ cnic_ring_ctl(dev, BNX2X_ISCSI_L2_CID, cli, 0);
+ }
+}
+
static int cnic_register_netdev(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
@@ -2554,6 +4261,22 @@ static void cnic_stop_bnx2_hw(struct cnic_dev *dev)
cnic_free_resc(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);
+ cnic_free_resc(dev);
+}
+
static void cnic_stop_hw(struct cnic_dev *dev)
{
if (test_bit(CNIC_F_CNIC_UP, &dev->flags)) {
@@ -2685,6 +4408,57 @@ cnic_err:
return NULL;
}
+static struct cnic_dev *init_bnx2x_cnic(struct net_device *dev)
+{
+ struct pci_dev *pdev;
+ struct cnic_dev *cdev;
+ struct cnic_local *cp;
+ struct cnic_eth_dev *ethdev = NULL;
+ struct cnic_eth_dev *(*probe)(struct net_device *) = NULL;
+
+ probe = symbol_get(bnx2x_cnic_probe);
+ if (probe) {
+ ethdev = (*probe)(dev);
+ symbol_put(bnx2x_cnic_probe);
+ }
+ if (!ethdev)
+ return NULL;
+
+ pdev = ethdev->pdev;
+ if (!pdev)
+ return NULL;
+
+ dev_hold(dev);
+ cdev = cnic_alloc_dev(dev, pdev);
+ if (cdev == NULL) {
+ dev_put(dev);
+ return NULL;
+ }
+
+ set_bit(CNIC_F_BNX2X_CLASS, &cdev->flags);
+ cdev->submit_kwqes = cnic_submit_bnx2x_kwqes;
+
+ cp = cdev->cnic_priv;
+ cp->ethdev = ethdev;
+ cdev->pcidev = pdev;
+
+ cp->cnic_ops = &cnic_bnx2x_ops;
+ cp->start_hw = cnic_start_bnx2x_hw;
+ cp->stop_hw = cnic_stop_bnx2x_hw;
+ cp->setup_pgtbl = cnic_setup_page_tbl_le;
+ cp->alloc_resc = cnic_alloc_bnx2x_resc;
+ cp->free_resc = cnic_free_resc;
+ cp->start_cm = cnic_cm_init_bnx2x_hw;
+ 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;
+ cp->close_conn = cnic_close_bnx2x_conn;
+ cp->next_idx = cnic_bnx2x_next_idx;
+ cp->hw_idx = cnic_bnx2x_hw_idx;
+ return cdev;
+}
+
static struct cnic_dev *is_cnic_dev(struct net_device *dev)
{
struct ethtool_drvinfo drvinfo;
@@ -2696,6 +4470,8 @@ static struct cnic_dev *is_cnic_dev(struct net_device *dev)
if (!strcmp(drvinfo.driver, "bnx2"))
cdev = init_bnx2_cnic(dev);
+ if (!strcmp(drvinfo.driver, "bnx2x"))
+ cdev = init_bnx2x_cnic(dev);
if (cdev) {
write_lock(&cnic_dev_lock);
list_add(&cdev->list, &cnic_dev_list);
diff --git a/drivers/net/cnic.h b/drivers/net/cnic.h
index a94b302bb464..241d09acc0d4 100644
--- a/drivers/net/cnic.h
+++ b/drivers/net/cnic.h
@@ -227,6 +227,7 @@ struct cnic_local {
void *status_blk;
struct status_block_msix *bnx2_status_blk;
struct host_status_block *bnx2x_status_blk;
+ struct host_def_status_block *bnx2x_def_status_blk;
u32 status_blk_num;
u32 int_num;
@@ -258,6 +259,7 @@ struct cnic_local {
struct cnic_ctx *ctx_arr;
int ctx_blks;
int ctx_blk_size;
+ unsigned long ctx_align;
int cids_per_blk;
u32 chip_id;
@@ -290,11 +292,73 @@ struct bnx2x_bd_chain_next {
u8 reserved[8];
};
+#define ISCSI_DEFAULT_MAX_OUTSTANDING_R2T (1)
+
#define ISCSI_RAMROD_CMD_ID_UPDATE_CONN (ISCSI_KCQE_OPCODE_UPDATE_CONN)
#define ISCSI_RAMROD_CMD_ID_INIT (ISCSI_KCQE_OPCODE_INIT)
#define CDU_REGION_NUMBER_XCM_AG 2
#define CDU_REGION_NUMBER_UCM_AG 4
+#define CDU_VALID_DATA(_cid, _region, _type) \
+ (((_cid) << 8) | (((_region)&0xf)<<4) | (((_type)&0xf)))
+
+#define CDU_CRC8(_cid, _region, _type) \
+ (calc_crc8(CDU_VALID_DATA(_cid, _region, _type), 0xff))
+
+#define CDU_RSRVD_VALUE_TYPE_A(_cid, _region, _type) \
+ (0x80 | ((CDU_CRC8(_cid, _region, _type)) & 0x7f))
+
+#define BNX2X_CONTEXT_MEM_SIZE 1024
+#define BNX2X_FCOE_CID 16
+
+/* iSCSI client IDs are 17, 19, 21, 23 */
+#define BNX2X_ISCSI_BASE_CL_ID 17
+#define BNX2X_ISCSI_CL_ID(vn) (BNX2X_ISCSI_BASE_CL_ID + ((vn) << 1))
+
+#define BNX2X_ISCSI_L2_CID 17
+#define BNX2X_ISCSI_START_CID 18
+#define BNX2X_ISCSI_NUM_CONNECTIONS 128
+#define BNX2X_ISCSI_TASK_CONTEXT_SIZE 128
+#define BNX2X_ISCSI_MAX_PENDING_R2TS 4
+#define BNX2X_ISCSI_R2TQE_SIZE 8
+#define BNX2X_ISCSI_HQ_BD_SIZE 64
+#define BNX2X_ISCSI_CONN_BUF_SIZE 64
+#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_57711 0x164f
+#define BNX2X_CHIP_NUM_57711E 0x1650
+#define BNX2X_CHIP_NUM(x) (x >> 16)
+#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 IS_E1H_OFFSET BNX2X_CHIP_IS_E1H(cp->chip_id)
+
+#define BNX2X_RX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_rx_bd))
+#define BNX2X_MAX_RX_DESC_CNT (BNX2X_RX_DESC_CNT - 2)
+#define BNX2X_RCQ_DESC_CNT (BCM_PAGE_SIZE / sizeof(union eth_rx_cqe))
+#define BNX2X_MAX_RCQ_DESC_CNT (BNX2X_RCQ_DESC_CNT - 1)
+
+#define BNX2X_DEF_SB_ID 16
+
+#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_ADDR(base, field) (base + \
+ offsetof(struct shmem_region, field))
+
+#define CNIC_PORT(cp) ((cp)->func % PORT_MAX)
+#define CNIC_FUNC(cp) ((cp)->func)
+#define CNIC_E1HVN(cp) ((cp)->func >> 1)
+
#endif
diff --git a/drivers/net/cnic_defs.h b/drivers/net/cnic_defs.h
index cee80f694457..9827b278dc7c 100644
--- a/drivers/net/cnic_defs.h
+++ b/drivers/net/cnic_defs.h
@@ -51,6 +51,9 @@
#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_LAYER_CODE (4)
#define L2_LAYER_CODE (2)
@@ -577,4 +580,1918 @@ struct l4_kwq_upload {
u32 reserved2[6];
};
+/*
+ * bnx2x structures
+ */
+
+/*
+ * iSCSI context region, used only in iSCSI
+ */
+struct ustorm_iscsi_rq_db {
+ struct regpair pbl_base;
+ struct regpair curr_pbe;
+};
+
+/*
+ * iSCSI context region, used only in iSCSI
+ */
+struct ustorm_iscsi_r2tq_db {
+ struct regpair pbl_base;
+ struct regpair curr_pbe;
+};
+
+/*
+ * iSCSI context region, used only in iSCSI
+ */
+struct ustorm_iscsi_cq_db {
+#if defined(__BIG_ENDIAN)
+ u16 cq_sn;
+ u16 prod;
+#elif defined(__LITTLE_ENDIAN)
+ u16 prod;
+ u16 cq_sn;
+#endif
+ struct regpair curr_pbe;
+};
+
+/*
+ * iSCSI context region, used only in iSCSI
+ */
+struct rings_db {
+ struct ustorm_iscsi_rq_db rq;
+ struct ustorm_iscsi_r2tq_db r2tq;
+ struct ustorm_iscsi_cq_db cq[8];
+#if defined(__BIG_ENDIAN)
+ u16 rq_prod;
+ u16 r2tq_prod;
+#elif defined(__LITTLE_ENDIAN)
+ u16 r2tq_prod;
+ u16 rq_prod;
+#endif
+ struct regpair cq_pbl_base;
+};
+
+/*
+ * iSCSI context region, used only in iSCSI
+ */
+struct ustorm_iscsi_placement_db {
+ u32 sgl_base_lo;
+ u32 sgl_base_hi;
+ u32 local_sge_0_address_hi;
+ u32 local_sge_0_address_lo;
+#if defined(__BIG_ENDIAN)
+ u16 curr_sge_offset;
+ u16 local_sge_0_size;
+#elif defined(__LITTLE_ENDIAN)
+ u16 local_sge_0_size;
+ u16 curr_sge_offset;
+#endif
+ u32 local_sge_1_address_hi;
+ u32 local_sge_1_address_lo;
+#if defined(__BIG_ENDIAN)
+ u16 reserved6;
+ u16 local_sge_1_size;
+#elif defined(__LITTLE_ENDIAN)
+ u16 local_sge_1_size;
+ u16 reserved6;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 sgl_size;
+ u8 local_sge_index_2b;
+ u16 reserved7;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved7;
+ u8 local_sge_index_2b;
+ u8 sgl_size;
+#endif
+ u32 rem_pdu;
+ u32 place_db_bitfield_1;
+#define USTORM_ISCSI_PLACEMENT_DB_REM_PDU_PAYLOAD (0xFFFFFF<<0)
+#define USTORM_ISCSI_PLACEMENT_DB_REM_PDU_PAYLOAD_SHIFT 0
+#define USTORM_ISCSI_PLACEMENT_DB_CQ_ID (0xFF<<24)
+#define USTORM_ISCSI_PLACEMENT_DB_CQ_ID_SHIFT 24
+ u32 place_db_bitfield_2;
+#define USTORM_ISCSI_PLACEMENT_DB_BYTES_2_TRUNCATE (0xFFFFFF<<0)
+#define USTORM_ISCSI_PLACEMENT_DB_BYTES_2_TRUNCATE_SHIFT 0
+#define USTORM_ISCSI_PLACEMENT_DB_HOST_SGE_INDEX (0xFF<<24)
+#define USTORM_ISCSI_PLACEMENT_DB_HOST_SGE_INDEX_SHIFT 24
+ u32 nal;
+#define USTORM_ISCSI_PLACEMENT_DB_REM_SGE_SIZE (0xFFFFFF<<0)
+#define USTORM_ISCSI_PLACEMENT_DB_REM_SGE_SIZE_SHIFT 0
+#define USTORM_ISCSI_PLACEMENT_DB_EXP_PADDING_2B (0x3<<24)
+#define USTORM_ISCSI_PLACEMENT_DB_EXP_PADDING_2B_SHIFT 24
+#define USTORM_ISCSI_PLACEMENT_DB_EXP_DIGEST_3B (0x7<<26)
+#define USTORM_ISCSI_PLACEMENT_DB_EXP_DIGEST_3B_SHIFT 26
+#define USTORM_ISCSI_PLACEMENT_DB_NAL_LEN_3B (0x7<<29)
+#define USTORM_ISCSI_PLACEMENT_DB_NAL_LEN_3B_SHIFT 29
+};
+
+/*
+ * Ustorm iSCSI Storm Context
+ */
+struct ustorm_iscsi_st_context {
+ u32 exp_stat_sn;
+ u32 exp_data_sn;
+ struct rings_db ring;
+ struct regpair task_pbl_base;
+ struct regpair tce_phy_addr;
+ struct ustorm_iscsi_placement_db place_db;
+ u32 data_rcv_seq;
+ u32 rem_rcv_len;
+#if defined(__BIG_ENDIAN)
+ u16 hdr_itt;
+ u16 iscsi_conn_id;
+#elif defined(__LITTLE_ENDIAN)
+ u16 iscsi_conn_id;
+ u16 hdr_itt;
+#endif
+ u32 nal_bytes;
+#if defined(__BIG_ENDIAN)
+ u8 hdr_second_byte_union;
+ u8 bitfield_0;
+#define USTORM_ISCSI_ST_CONTEXT_BMIDDLEOFPDU (0x1<<0)
+#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
+ u8 task_pdu_cache_index;
+ u8 task_pbe_cache_index;
+#elif defined(__LITTLE_ENDIAN)
+ u8 task_pbe_cache_index;
+ u8 task_pdu_cache_index;
+ u8 bitfield_0;
+#define USTORM_ISCSI_ST_CONTEXT_BMIDDLEOFPDU (0x1<<0)
+#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
+ u8 hdr_second_byte_union;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 reserved3;
+ u8 reserved2;
+ u8 acDecrement;
+#elif defined(__LITTLE_ENDIAN)
+ u8 acDecrement;
+ u8 reserved2;
+ u16 reserved3;
+#endif
+ u32 task_stat;
+#if defined(__BIG_ENDIAN)
+ u8 hdr_opcode;
+ u8 num_cqs;
+ u16 reserved5;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved5;
+ u8 num_cqs;
+ u8 hdr_opcode;
+#endif
+ u32 negotiated_rx;
+#define USTORM_ISCSI_ST_CONTEXT_MAX_RECV_PDU_LENGTH (0xFFFFFF<<0)
+#define USTORM_ISCSI_ST_CONTEXT_MAX_RECV_PDU_LENGTH_SHIFT 0
+#define USTORM_ISCSI_ST_CONTEXT_MAX_OUTSTANDING_R2TS (0xFF<<24)
+#define USTORM_ISCSI_ST_CONTEXT_MAX_OUTSTANDING_R2TS_SHIFT 24
+ u32 negotiated_rx_and_flags;
+#define USTORM_ISCSI_ST_CONTEXT_MAX_BURST_LENGTH (0xFFFFFF<<0)
+#define USTORM_ISCSI_ST_CONTEXT_MAX_BURST_LENGTH_SHIFT 0
+#define USTORM_ISCSI_ST_CONTEXT_B_CQE_POSTED_OR_HEADER_CACHED (0x1<<24)
+#define USTORM_ISCSI_ST_CONTEXT_B_CQE_POSTED_OR_HEADER_CACHED_SHIFT 24
+#define USTORM_ISCSI_ST_CONTEXT_B_HDR_DIGEST_EN (0x1<<25)
+#define USTORM_ISCSI_ST_CONTEXT_B_HDR_DIGEST_EN_SHIFT 25
+#define USTORM_ISCSI_ST_CONTEXT_B_DATA_DIGEST_EN (0x1<<26)
+#define USTORM_ISCSI_ST_CONTEXT_B_DATA_DIGEST_EN_SHIFT 26
+#define USTORM_ISCSI_ST_CONTEXT_B_PROTOCOL_ERROR (0x1<<27)
+#define USTORM_ISCSI_ST_CONTEXT_B_PROTOCOL_ERROR_SHIFT 27
+#define USTORM_ISCSI_ST_CONTEXT_B_TASK_VALID (0x1<<28)
+#define USTORM_ISCSI_ST_CONTEXT_B_TASK_VALID_SHIFT 28
+#define USTORM_ISCSI_ST_CONTEXT_TASK_TYPE (0x3<<29)
+#define USTORM_ISCSI_ST_CONTEXT_TASK_TYPE_SHIFT 29
+#define USTORM_ISCSI_ST_CONTEXT_B_ALL_DATA_ACKED (0x1<<31)
+#define USTORM_ISCSI_ST_CONTEXT_B_ALL_DATA_ACKED_SHIFT 31
+};
+
+/*
+ * TCP context region, shared in TOE, RDMA and ISCSI
+ */
+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_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_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)
+#define TSTORM_TCP_ST_CONTEXT_SECTION_KA_ENABLED_SHIFT 28
+#define TSTORM_TCP_ST_CONTEXT_SECTION_FIRST_RTO_ESTIMATE (0x1<<29)
+#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
+ 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_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)
+#define TSTORM_TCP_ST_CONTEXT_SECTION_DA_COUNTER_EN_SHIFT 25
+#define __TSTORM_TCP_ST_CONTEXT_SECTION_KA_PROBE_SENT (0x1<<26)
+#define __TSTORM_TCP_ST_CONTEXT_SECTION_KA_PROBE_SENT_SHIFT 26
+#define __TSTORM_TCP_ST_CONTEXT_SECTION_PERSIST_PROBE_SENT (0x1<<27)
+#define __TSTORM_TCP_ST_CONTEXT_SECTION_PERSIST_PROBE_SENT_SHIFT 27
+#define TSTORM_TCP_ST_CONTEXT_SECTION_UPDATE_L2_STATSTICS (0x1<<28)
+#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
+#if defined(__BIG_ENDIAN)
+ u16 reserved_slowpath;
+ u8 tcp_sm_state_3b;
+ u8 rto_exp_3b;
+#elif defined(__LITTLE_ENDIAN)
+ u8 rto_exp_3b;
+ u8 tcp_sm_state_3b;
+ u16 reserved_slowpath;
+#endif
+ u32 rcv_nxt;
+ u32 timestamp_recent;
+ u32 timestamp_recent_time;
+ u32 cwnd;
+ u32 ss_thresh;
+ u32 cwnd_accum;
+ u32 prev_seg_seq;
+ u32 expected_rel_seq;
+ u32 recover;
+#if defined(__BIG_ENDIAN)
+ u8 retransmit_count;
+ u8 ka_max_probe_count;
+ u8 persist_probe_count;
+ u8 ka_probe_count;
+#elif defined(__LITTLE_ENDIAN)
+ u8 ka_probe_count;
+ u8 persist_probe_count;
+ u8 ka_max_probe_count;
+ u8 retransmit_count;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 statistics_counter_id;
+ u8 ooo_support_mode;
+ u8 snd_wnd_scale_4b;
+ u8 dup_ack_count;
+#elif defined(__LITTLE_ENDIAN)
+ u8 dup_ack_count;
+ u8 snd_wnd_scale_4b;
+ u8 ooo_support_mode;
+ u8 statistics_counter_id;
+#endif
+ u32 retransmit_start_time;
+ u32 ka_timeout;
+ u32 ka_interval;
+ u32 isle_start_seq;
+ u32 isle_end_seq;
+#if defined(__BIG_ENDIAN)
+ u16 mss;
+ u16 recent_seg_wnd;
+#elif defined(__LITTLE_ENDIAN)
+ u16 recent_seg_wnd;
+ u16 mss;
+#endif
+ u32 reserved4;
+ u32 max_rt_time;
+#if defined(__BIG_ENDIAN)
+ u16 lsb_mac_address;
+ u16 vlan_id;
+#elif defined(__LITTLE_ENDIAN)
+ u16 vlan_id;
+ u16 lsb_mac_address;
+#endif
+ u32 msb_mac_address;
+ u32 reserved2;
+};
+
+/*
+ * Termination variables
+ */
+struct iscsi_term_vars {
+ u8 BitMap;
+#define ISCSI_TERM_VARS_TCP_STATE (0xF<<0)
+#define ISCSI_TERM_VARS_TCP_STATE_SHIFT 0
+#define ISCSI_TERM_VARS_FIN_RECEIVED_SBIT (0x1<<4)
+#define ISCSI_TERM_VARS_FIN_RECEIVED_SBIT_SHIFT 4
+#define ISCSI_TERM_VARS_ACK_ON_FIN_RECEIVED_SBIT (0x1<<5)
+#define ISCSI_TERM_VARS_ACK_ON_FIN_RECEIVED_SBIT_SHIFT 5
+#define ISCSI_TERM_VARS_TERM_ON_CHIP (0x1<<6)
+#define ISCSI_TERM_VARS_TERM_ON_CHIP_SHIFT 6
+#define ISCSI_TERM_VARS_RSRV (0x1<<7)
+#define ISCSI_TERM_VARS_RSRV_SHIFT 7
+};
+
+/*
+ * iSCSI context region, used only in iSCSI
+ */
+struct tstorm_iscsi_st_context_section {
+#if defined(__BIG_ENDIAN)
+ u16 rem_tcp_data_len;
+ u16 brb_offset;
+#elif defined(__LITTLE_ENDIAN)
+ u16 brb_offset;
+ u16 rem_tcp_data_len;
+#endif
+ u32 b2nh;
+#if defined(__BIG_ENDIAN)
+ u16 rq_cons;
+ u8 flags;
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_HDR_DIGEST_EN (0x1<<0)
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_HDR_DIGEST_EN_SHIFT 0
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_DATA_DIGEST_EN (0x1<<1)
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_DATA_DIGEST_EN_SHIFT 1
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_PARTIAL_HEADER (0x1<<2)
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_PARTIAL_HEADER_SHIFT 2
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_FULL_FEATURE (0x1<<3)
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_FULL_FEATURE_SHIFT 3
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_DROP_ALL_PDUS (0x1<<4)
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_DROP_ALL_PDUS_SHIFT 4
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_FLAGS_RSRV (0x7<<5)
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_FLAGS_RSRV_SHIFT 5
+ u8 hdr_bytes_2_fetch;
+#elif defined(__LITTLE_ENDIAN)
+ u8 hdr_bytes_2_fetch;
+ u8 flags;
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_HDR_DIGEST_EN (0x1<<0)
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_HDR_DIGEST_EN_SHIFT 0
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_DATA_DIGEST_EN (0x1<<1)
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_DATA_DIGEST_EN_SHIFT 1
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_PARTIAL_HEADER (0x1<<2)
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_PARTIAL_HEADER_SHIFT 2
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_FULL_FEATURE (0x1<<3)
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_FULL_FEATURE_SHIFT 3
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_DROP_ALL_PDUS (0x1<<4)
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_B_DROP_ALL_PDUS_SHIFT 4
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_FLAGS_RSRV (0x7<<5)
+#define TSTORM_ISCSI_ST_CONTEXT_SECTION_FLAGS_RSRV_SHIFT 5
+ u16 rq_cons;
+#endif
+ struct regpair rq_db_phy_addr;
+#if defined(__BIG_ENDIAN)
+ struct iscsi_term_vars term_vars;
+ u8 scratchpad_idx;
+ u16 iscsi_conn_id;
+#elif defined(__LITTLE_ENDIAN)
+ u16 iscsi_conn_id;
+ u8 scratchpad_idx;
+ struct iscsi_term_vars term_vars;
+#endif
+ u32 reserved2;
+};
+
+/*
+ * The iSCSI non-aggregative context of Tstorm
+ */
+struct tstorm_iscsi_st_context {
+ struct tstorm_tcp_st_context_section tcp;
+ struct tstorm_iscsi_st_context_section iscsi;
+};
+
+/*
+ * The tcp aggregative context section of Xstorm
+ */
+struct xstorm_tcp_tcp_ag_context_section {
+#if defined(__BIG_ENDIAN)
+ u8 __tcp_agg_vars1;
+ u8 __da_cnt;
+ u16 mss;
+#elif defined(__LITTLE_ENDIAN)
+ u16 mss;
+ u8 __da_cnt;
+ u8 __tcp_agg_vars1;
+#endif
+ u32 snd_nxt;
+ u32 tx_wnd;
+ u32 snd_una;
+ u32 local_adv_wnd;
+#if defined(__BIG_ENDIAN)
+ u8 __agg_val8_th;
+ u8 __agg_val8;
+ u16 tcp_agg_vars2;
+#define XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TX_FIN_FLAG (0x1<<0)
+#define XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TX_FIN_FLAG_SHIFT 0
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TX_UNBLOCKED (0x1<<1)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TX_UNBLOCKED_SHIFT 1
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_DA_TIMER_ACTIVE (0x1<<2)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_DA_TIMER_ACTIVE_SHIFT 2
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX3_FLAG (0x1<<3)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX3_FLAG_SHIFT 3
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX4_FLAG (0x1<<4)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX4_FLAG_SHIFT 4
+#define XSTORM_TCP_TCP_AG_CONTEXT_SECTION_DA_ENABLE (0x1<<5)
+#define XSTORM_TCP_TCP_AG_CONTEXT_SECTION_DA_ENABLE_SHIFT 5
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_ACK_TO_FE_UPDATED_EN (0x1<<6)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_ACK_TO_FE_UPDATED_EN_SHIFT 6
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX3_CF_EN (0x1<<7)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX3_CF_EN_SHIFT 7
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TX_FIN_FLAG_EN (0x1<<8)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TX_FIN_FLAG_EN_SHIFT 8
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX1_FLAG (0x1<<9)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX1_FLAG_SHIFT 9
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_SET_RTO_CF (0x3<<10)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_SET_RTO_CF_SHIFT 10
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TS_TO_ECHO_UPDATED_CF (0x3<<12)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TS_TO_ECHO_UPDATED_CF_SHIFT 12
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX8_CF (0x3<<14)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX8_CF_SHIFT 14
+#elif defined(__LITTLE_ENDIAN)
+ u16 tcp_agg_vars2;
+#define XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TX_FIN_FLAG (0x1<<0)
+#define XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TX_FIN_FLAG_SHIFT 0
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TX_UNBLOCKED (0x1<<1)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TX_UNBLOCKED_SHIFT 1
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_DA_TIMER_ACTIVE (0x1<<2)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_DA_TIMER_ACTIVE_SHIFT 2
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX3_FLAG (0x1<<3)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX3_FLAG_SHIFT 3
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX4_FLAG (0x1<<4)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX4_FLAG_SHIFT 4
+#define XSTORM_TCP_TCP_AG_CONTEXT_SECTION_DA_ENABLE (0x1<<5)
+#define XSTORM_TCP_TCP_AG_CONTEXT_SECTION_DA_ENABLE_SHIFT 5
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_ACK_TO_FE_UPDATED_EN (0x1<<6)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_ACK_TO_FE_UPDATED_EN_SHIFT 6
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX3_CF_EN (0x1<<7)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX3_CF_EN_SHIFT 7
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TX_FIN_FLAG_EN (0x1<<8)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TX_FIN_FLAG_EN_SHIFT 8
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX1_FLAG (0x1<<9)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX1_FLAG_SHIFT 9
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_SET_RTO_CF (0x3<<10)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_SET_RTO_CF_SHIFT 10
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TS_TO_ECHO_UPDATED_CF (0x3<<12)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TS_TO_ECHO_UPDATED_CF_SHIFT 12
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX8_CF (0x3<<14)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX8_CF_SHIFT 14
+ u8 __agg_val8;
+ u8 __agg_val8_th;
+#endif
+ u32 ack_to_far_end;
+ u32 rto_timer;
+ u32 ka_timer;
+ u32 ts_to_echo;
+#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 __force_pure_ack_cnt;
+#elif defined(__LITTLE_ENDIAN)
+ u8 __force_pure_ack_cnt;
+ u8 __tcp_agg_vars3;
+ u8 __tcp_agg_vars4;
+ u8 __tcp_agg_vars5;
+#endif
+ u32 tcp_agg_vars6;
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TS_TO_ECHO_CF_EN (0x1<<0)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TS_TO_ECHO_CF_EN_SHIFT 0
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX8_CF_EN (0x1<<1)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX8_CF_EN_SHIFT 1
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX9_CF_EN (0x1<<2)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX9_CF_EN_SHIFT 2
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX10_CF_EN (0x1<<3)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX10_CF_EN_SHIFT 3
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX6_FLAG (0x1<<4)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX6_FLAG_SHIFT 4
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX7_FLAG (0x1<<5)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX7_FLAG_SHIFT 5
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX5_CF (0x3<<6)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX5_CF_SHIFT 6
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX9_CF (0x3<<8)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX9_CF_SHIFT 8
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX10_CF (0x3<<10)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX10_CF_SHIFT 10
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX11_CF (0x3<<12)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX11_CF_SHIFT 12
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX12_CF (0x3<<14)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX12_CF_SHIFT 14
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX13_CF (0x3<<16)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX13_CF_SHIFT 16
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX14_CF (0x3<<18)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX14_CF_SHIFT 18
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX15_CF (0x3<<20)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX15_CF_SHIFT 20
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX16_CF (0x3<<22)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX16_CF_SHIFT 22
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX17_CF (0x3<<24)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX17_CF_SHIFT 24
+#define XSTORM_TCP_TCP_AG_CONTEXT_SECTION_ECE_FLAG (0x1<<26)
+#define XSTORM_TCP_TCP_AG_CONTEXT_SECTION_ECE_FLAG_SHIFT 26
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_RESERVED71 (0x1<<27)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_RESERVED71_SHIFT 27
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_FORCE_PURE_ACK_CNT_DIRTY (0x1<<28)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_FORCE_PURE_ACK_CNT_DIRTY_SHIFT 28
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TCP_AUTO_STOP_FLAG (0x1<<29)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_TCP_AUTO_STOP_FLAG_SHIFT 29
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_DO_TS_UPDATE_FLAG (0x1<<30)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_DO_TS_UPDATE_FLAG_SHIFT 30
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_CANCEL_RETRANSMIT_FLAG (0x1<<31)
+#define __XSTORM_TCP_TCP_AG_CONTEXT_SECTION_CANCEL_RETRANSMIT_FLAG_SHIFT 31
+#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 iscsi aggregative context of Xstorm
+ */
+struct xstorm_iscsi_ag_context {
+#if defined(__BIG_ENDIAN)
+ u16 agg_val1;
+ u8 agg_vars1;
+#define __XSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM0 (0x1<<0)
+#define __XSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM0_SHIFT 0
+#define XSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM1 (0x1<<1)
+#define XSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM1_SHIFT 1
+#define XSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM2 (0x1<<2)
+#define XSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM2_SHIFT 2
+#define XSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM3 (0x1<<3)
+#define XSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM3_SHIFT 3
+#define __XSTORM_ISCSI_AG_CONTEXT_MORE_TO_SEND_EN (0x1<<4)
+#define __XSTORM_ISCSI_AG_CONTEXT_MORE_TO_SEND_EN_SHIFT 4
+#define XSTORM_ISCSI_AG_CONTEXT_NAGLE_EN (0x1<<5)
+#define XSTORM_ISCSI_AG_CONTEXT_NAGLE_EN_SHIFT 5
+#define __XSTORM_ISCSI_AG_CONTEXT_DQ_SPARE_FLAG (0x1<<6)
+#define __XSTORM_ISCSI_AG_CONTEXT_DQ_SPARE_FLAG_SHIFT 6
+#define __XSTORM_ISCSI_AG_CONTEXT_UNA_GT_NXT_EN (0x1<<7)
+#define __XSTORM_ISCSI_AG_CONTEXT_UNA_GT_NXT_EN_SHIFT 7
+ u8 state;
+#elif defined(__LITTLE_ENDIAN)
+ u8 state;
+ u8 agg_vars1;
+#define __XSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM0 (0x1<<0)
+#define __XSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM0_SHIFT 0
+#define XSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM1 (0x1<<1)
+#define XSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM1_SHIFT 1
+#define XSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM2 (0x1<<2)
+#define XSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM2_SHIFT 2
+#define XSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM3 (0x1<<3)
+#define XSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM3_SHIFT 3
+#define __XSTORM_ISCSI_AG_CONTEXT_MORE_TO_SEND_EN (0x1<<4)
+#define __XSTORM_ISCSI_AG_CONTEXT_MORE_TO_SEND_EN_SHIFT 4
+#define XSTORM_ISCSI_AG_CONTEXT_NAGLE_EN (0x1<<5)
+#define XSTORM_ISCSI_AG_CONTEXT_NAGLE_EN_SHIFT 5
+#define __XSTORM_ISCSI_AG_CONTEXT_DQ_SPARE_FLAG (0x1<<6)
+#define __XSTORM_ISCSI_AG_CONTEXT_DQ_SPARE_FLAG_SHIFT 6
+#define __XSTORM_ISCSI_AG_CONTEXT_UNA_GT_NXT_EN (0x1<<7)
+#define __XSTORM_ISCSI_AG_CONTEXT_UNA_GT_NXT_EN_SHIFT 7
+ u16 agg_val1;
+#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_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_vars2;
+#define __XSTORM_ISCSI_AG_CONTEXT_DQ_CF (0x3<<0)
+#define __XSTORM_ISCSI_AG_CONTEXT_DQ_CF_SHIFT 0
+#define __XSTORM_ISCSI_AG_CONTEXT_DQ_SPARE_FLAG_EN (0x1<<2)
+#define __XSTORM_ISCSI_AG_CONTEXT_DQ_SPARE_FLAG_EN_SHIFT 2
+#define __XSTORM_ISCSI_AG_CONTEXT_AUX8_FLAG (0x1<<3)
+#define __XSTORM_ISCSI_AG_CONTEXT_AUX8_FLAG_SHIFT 3
+#define __XSTORM_ISCSI_AG_CONTEXT_AUX9_FLAG (0x1<<4)
+#define __XSTORM_ISCSI_AG_CONTEXT_AUX9_FLAG_SHIFT 4
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE1 (0x3<<5)
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE1_SHIFT 5
+#define __XSTORM_ISCSI_AG_CONTEXT_DQ_CF_EN (0x1<<7)
+#define __XSTORM_ISCSI_AG_CONTEXT_DQ_CF_EN_SHIFT 7
+#elif defined(__LITTLE_ENDIAN)
+ u8 agg_vars2;
+#define __XSTORM_ISCSI_AG_CONTEXT_DQ_CF (0x3<<0)
+#define __XSTORM_ISCSI_AG_CONTEXT_DQ_CF_SHIFT 0
+#define __XSTORM_ISCSI_AG_CONTEXT_DQ_SPARE_FLAG_EN (0x1<<2)
+#define __XSTORM_ISCSI_AG_CONTEXT_DQ_SPARE_FLAG_EN_SHIFT 2
+#define __XSTORM_ISCSI_AG_CONTEXT_AUX8_FLAG (0x1<<3)
+#define __XSTORM_ISCSI_AG_CONTEXT_AUX8_FLAG_SHIFT 3
+#define __XSTORM_ISCSI_AG_CONTEXT_AUX9_FLAG (0x1<<4)
+#define __XSTORM_ISCSI_AG_CONTEXT_AUX9_FLAG_SHIFT 4
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE1 (0x3<<5)
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE1_SHIFT 5
+#define __XSTORM_ISCSI_AG_CONTEXT_DQ_CF_EN (0x1<<7)
+#define __XSTORM_ISCSI_AG_CONTEXT_DQ_CF_EN_SHIFT 7
+ 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
+ u8 cdu_reserved;
+#endif
+ u32 more_to_send;
+#if defined(__BIG_ENDIAN)
+ u16 agg_vars5;
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE5 (0x3<<0)
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE5_SHIFT 0
+#define XSTORM_ISCSI_AG_CONTEXT_PHYSICAL_QUEUE_NUM0 (0x3F<<2)
+#define XSTORM_ISCSI_AG_CONTEXT_PHYSICAL_QUEUE_NUM0_SHIFT 2
+#define XSTORM_ISCSI_AG_CONTEXT_PHYSICAL_QUEUE_NUM1 (0x3F<<8)
+#define XSTORM_ISCSI_AG_CONTEXT_PHYSICAL_QUEUE_NUM1_SHIFT 8
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE2 (0x3<<14)
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE2_SHIFT 14
+ u16 sq_cons;
+#elif defined(__LITTLE_ENDIAN)
+ u16 sq_cons;
+ u16 agg_vars5;
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE5 (0x3<<0)
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE5_SHIFT 0
+#define XSTORM_ISCSI_AG_CONTEXT_PHYSICAL_QUEUE_NUM0 (0x3F<<2)
+#define XSTORM_ISCSI_AG_CONTEXT_PHYSICAL_QUEUE_NUM0_SHIFT 2
+#define XSTORM_ISCSI_AG_CONTEXT_PHYSICAL_QUEUE_NUM1 (0x3F<<8)
+#define XSTORM_ISCSI_AG_CONTEXT_PHYSICAL_QUEUE_NUM1_SHIFT 8
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE2 (0x3<<14)
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE2_SHIFT 14
+#endif
+ struct xstorm_tcp_tcp_ag_context_section tcp;
+#if defined(__BIG_ENDIAN)
+ u16 agg_vars7;
+#define __XSTORM_ISCSI_AG_CONTEXT_AGG_VAL11_DECISION_RULE (0x7<<0)
+#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_DECISION_RULE3 (0x3<<6)
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE3_SHIFT 6
+#define XSTORM_ISCSI_AG_CONTEXT_AUX1_CF (0x3<<8)
+#define XSTORM_ISCSI_AG_CONTEXT_AUX1_CF_SHIFT 8
+#define __XSTORM_ISCSI_AG_CONTEXT_COMPLETION_SEQ_DECISION_MASK (0x1<<10)
+#define __XSTORM_ISCSI_AG_CONTEXT_COMPLETION_SEQ_DECISION_MASK_SHIFT 10
+#define __XSTORM_ISCSI_AG_CONTEXT_AUX1_CF_EN (0x1<<11)
+#define __XSTORM_ISCSI_AG_CONTEXT_AUX1_CF_EN_SHIFT 11
+#define __XSTORM_ISCSI_AG_CONTEXT_AUX10_FLAG (0x1<<12)
+#define __XSTORM_ISCSI_AG_CONTEXT_AUX10_FLAG_SHIFT 12
+#define __XSTORM_ISCSI_AG_CONTEXT_AUX11_FLAG (0x1<<13)
+#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
+ u8 agg_val3_th;
+ u8 agg_vars6;
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE6 (0x7<<0)
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE6_SHIFT 0
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE7 (0x7<<3)
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE7_SHIFT 3
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE4 (0x3<<6)
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE4_SHIFT 6
+#elif defined(__LITTLE_ENDIAN)
+ u8 agg_vars6;
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE6 (0x7<<0)
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE6_SHIFT 0
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE7 (0x7<<3)
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE7_SHIFT 3
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE4 (0x3<<6)
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE4_SHIFT 6
+ u8 agg_val3_th;
+ u16 agg_vars7;
+#define __XSTORM_ISCSI_AG_CONTEXT_AGG_VAL11_DECISION_RULE (0x7<<0)
+#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_DECISION_RULE3 (0x3<<6)
+#define XSTORM_ISCSI_AG_CONTEXT_DECISION_RULE3_SHIFT 6
+#define XSTORM_ISCSI_AG_CONTEXT_AUX1_CF (0x3<<8)
+#define XSTORM_ISCSI_AG_CONTEXT_AUX1_CF_SHIFT 8
+#define __XSTORM_ISCSI_AG_CONTEXT_COMPLETION_SEQ_DECISION_MASK (0x1<<10)
+#define __XSTORM_ISCSI_AG_CONTEXT_COMPLETION_SEQ_DECISION_MASK_SHIFT 10
+#define __XSTORM_ISCSI_AG_CONTEXT_AUX1_CF_EN (0x1<<11)
+#define __XSTORM_ISCSI_AG_CONTEXT_AUX1_CF_EN_SHIFT 11
+#define __XSTORM_ISCSI_AG_CONTEXT_AUX10_FLAG (0x1<<12)
+#define __XSTORM_ISCSI_AG_CONTEXT_AUX10_FLAG_SHIFT 12
+#define __XSTORM_ISCSI_AG_CONTEXT_AUX11_FLAG (0x1<<13)
+#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
+#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 hq_prod;
+ u16 hq_cons;
+#elif defined(__LITTLE_ENDIAN)
+ u16 hq_cons;
+ u16 hq_prod;
+#endif
+ u32 agg_vars8;
+#define XSTORM_ISCSI_AG_CONTEXT_AGG_MISC2 (0xFFFFFF<<0)
+#define XSTORM_ISCSI_AG_CONTEXT_AGG_MISC2_SHIFT 0
+#define XSTORM_ISCSI_AG_CONTEXT_AGG_MISC3 (0xFF<<24)
+#define XSTORM_ISCSI_AG_CONTEXT_AGG_MISC3_SHIFT 24
+#if defined(__BIG_ENDIAN)
+ u16 r2tq_prod;
+ u16 sq_prod;
+#elif defined(__LITTLE_ENDIAN)
+ u16 sq_prod;
+ u16 r2tq_prod;
+#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 agg_limit1;
+#elif defined(__LITTLE_ENDIAN)
+ u16 agg_limit1;
+ u16 __agg_misc1;
+#endif
+ u32 hq_cons_tcp_seq;
+ u32 exp_stat_sn;
+ u32 agg_misc5;
+};
+
+/*
+ * The tcp aggregative context section of Tstorm
+ */
+struct tstorm_tcp_tcp_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 snd_nxt;
+ u32 rtt_seq;
+ u32 rtt_time;
+ u32 __reserved66;
+ u32 wnd_right_edge;
+ u32 tcp_agg_vars1;
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_FIN_SENT_FLAG (0x1<<0)
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_FIN_SENT_FLAG_SHIFT 0
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_LAST_PACKET_FIN_FLAG (0x1<<1)
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_LAST_PACKET_FIN_FLAG_SHIFT 1
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_WND_UPD_CF (0x3<<2)
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_WND_UPD_CF_SHIFT 2
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_TIMEOUT_CF (0x3<<4)
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_TIMEOUT_CF_SHIFT 4
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_WND_UPD_CF_EN (0x1<<6)
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_WND_UPD_CF_EN_SHIFT 6
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_TIMEOUT_CF_EN (0x1<<7)
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_TIMEOUT_CF_EN_SHIFT 7
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_RETRANSMIT_SEQ_EN (0x1<<8)
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_RETRANSMIT_SEQ_EN_SHIFT 8
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_SND_NXT_EN (0x1<<9)
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_SND_NXT_EN_SHIFT 9
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX1_FLAG (0x1<<10)
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX1_FLAG_SHIFT 10
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX2_FLAG (0x1<<11)
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX2_FLAG_SHIFT 11
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX1_CF_EN (0x1<<12)
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX1_CF_EN_SHIFT 12
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX2_CF_EN (0x1<<13)
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX2_CF_EN_SHIFT 13
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX1_CF (0x3<<14)
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX1_CF_SHIFT 14
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX2_CF (0x3<<16)
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX2_CF_SHIFT 16
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_TX_BLOCKED (0x1<<18)
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_TX_BLOCKED_SHIFT 18
+#define __TSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX10_CF_EN (0x1<<19)
+#define __TSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX10_CF_EN_SHIFT 19
+#define __TSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX11_CF_EN (0x1<<20)
+#define __TSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX11_CF_EN_SHIFT 20
+#define __TSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX12_CF_EN (0x1<<21)
+#define __TSTORM_TCP_TCP_AG_CONTEXT_SECTION_AUX12_CF_EN_SHIFT 21
+#define __TSTORM_TCP_TCP_AG_CONTEXT_SECTION_RESERVED1 (0x3<<22)
+#define __TSTORM_TCP_TCP_AG_CONTEXT_SECTION_RESERVED1_SHIFT 22
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_RETRANSMIT_PEND_SEQ (0xF<<24)
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_RETRANSMIT_PEND_SEQ_SHIFT 24
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_RETRANSMIT_DONE_SEQ (0xF<<28)
+#define TSTORM_TCP_TCP_AG_CONTEXT_SECTION_RETRANSMIT_DONE_SEQ_SHIFT 28
+ u32 snd_max;
+ u32 snd_una;
+ u32 __reserved2;
+};
+
+/*
+ * The iscsi aggregative context of Tstorm
+ */
+struct tstorm_iscsi_ag_context {
+#if defined(__BIG_ENDIAN)
+ u16 ulp_credit;
+ u8 agg_vars1;
+#define TSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM0 (0x1<<0)
+#define TSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM0_SHIFT 0
+#define TSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM1 (0x1<<1)
+#define TSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM1_SHIFT 1
+#define TSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM2 (0x1<<2)
+#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_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
+ u8 state;
+#elif defined(__LITTLE_ENDIAN)
+ u8 state;
+ u8 agg_vars1;
+#define TSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM0 (0x1<<0)
+#define TSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM0_SHIFT 0
+#define TSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM1 (0x1<<1)
+#define TSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM1_SHIFT 1
+#define TSTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM2 (0x1<<2)
+#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_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
+ 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_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_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_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_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
+ u16 __agg_val4;
+#endif
+ struct tstorm_tcp_tcp_ag_context_section tcp;
+};
+
+/*
+ * 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 {
+#if defined(__BIG_ENDIAN)
+ u8 __aux_counter_flags;
+ u8 agg_vars2;
+#define USTORM_ISCSI_AG_CONTEXT_TX_CF (0x3<<0)
+#define USTORM_ISCSI_AG_CONTEXT_TX_CF_SHIFT 0
+#define __USTORM_ISCSI_AG_CONTEXT_TIMER_CF (0x3<<2)
+#define __USTORM_ISCSI_AG_CONTEXT_TIMER_CF_SHIFT 2
+#define USTORM_ISCSI_AG_CONTEXT_AGG_MISC4_RULE (0x7<<4)
+#define USTORM_ISCSI_AG_CONTEXT_AGG_MISC4_RULE_SHIFT 4
+#define __USTORM_ISCSI_AG_CONTEXT_AGG_VAL2_MASK (0x1<<7)
+#define __USTORM_ISCSI_AG_CONTEXT_AGG_VAL2_MASK_SHIFT 7
+ u8 agg_vars1;
+#define __USTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM0 (0x1<<0)
+#define __USTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM0_SHIFT 0
+#define USTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM1 (0x1<<1)
+#define USTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM1_SHIFT 1
+#define USTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM2 (0x1<<2)
+#define USTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM2_SHIFT 2
+#define USTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM3 (0x1<<3)
+#define USTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM3_SHIFT 3
+#define USTORM_ISCSI_AG_CONTEXT_INV_CF (0x3<<4)
+#define USTORM_ISCSI_AG_CONTEXT_INV_CF_SHIFT 4
+#define USTORM_ISCSI_AG_CONTEXT_COMPLETION_CF (0x3<<6)
+#define USTORM_ISCSI_AG_CONTEXT_COMPLETION_CF_SHIFT 6
+ u8 state;
+#elif defined(__LITTLE_ENDIAN)
+ u8 state;
+ u8 agg_vars1;
+#define __USTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM0 (0x1<<0)
+#define __USTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM0_SHIFT 0
+#define USTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM1 (0x1<<1)
+#define USTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM1_SHIFT 1
+#define USTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM2 (0x1<<2)
+#define USTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM2_SHIFT 2
+#define USTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM3 (0x1<<3)
+#define USTORM_ISCSI_AG_CONTEXT_EXISTS_IN_QM3_SHIFT 3
+#define USTORM_ISCSI_AG_CONTEXT_INV_CF (0x3<<4)
+#define USTORM_ISCSI_AG_CONTEXT_INV_CF_SHIFT 4
+#define USTORM_ISCSI_AG_CONTEXT_COMPLETION_CF (0x3<<6)
+#define USTORM_ISCSI_AG_CONTEXT_COMPLETION_CF_SHIFT 6
+ u8 agg_vars2;
+#define USTORM_ISCSI_AG_CONTEXT_TX_CF (0x3<<0)
+#define USTORM_ISCSI_AG_CONTEXT_TX_CF_SHIFT 0
+#define __USTORM_ISCSI_AG_CONTEXT_TIMER_CF (0x3<<2)
+#define __USTORM_ISCSI_AG_CONTEXT_TIMER_CF_SHIFT 2
+#define USTORM_ISCSI_AG_CONTEXT_AGG_MISC4_RULE (0x7<<4)
+#define USTORM_ISCSI_AG_CONTEXT_AGG_MISC4_RULE_SHIFT 4
+#define __USTORM_ISCSI_AG_CONTEXT_AGG_VAL2_MASK (0x1<<7)
+#define __USTORM_ISCSI_AG_CONTEXT_AGG_VAL2_MASK_SHIFT 7
+ u8 __aux_counter_flags;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 cdu_usage;
+ u8 agg_misc2;
+ u16 __cq_local_comp_itt_val;
+#elif defined(__LITTLE_ENDIAN)
+ u16 __cq_local_comp_itt_val;
+ u8 agg_misc2;
+ 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;
+#define USTORM_ISCSI_AG_CONTEXT_AGG_VAL2_RULE (0x7<<0)
+#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_RESERVED1 (0x1<<7)
+#define __USTORM_ISCSI_AG_CONTEXT_RESERVED1_SHIFT 7
+ u8 decision_rule_enable_bits;
+#define USTORM_ISCSI_AG_CONTEXT_INV_CF_EN (0x1<<0)
+#define USTORM_ISCSI_AG_CONTEXT_INV_CF_EN_SHIFT 0
+#define USTORM_ISCSI_AG_CONTEXT_COMPLETION_CF_EN (0x1<<1)
+#define USTORM_ISCSI_AG_CONTEXT_COMPLETION_CF_EN_SHIFT 1
+#define USTORM_ISCSI_AG_CONTEXT_TX_CF_EN (0x1<<2)
+#define USTORM_ISCSI_AG_CONTEXT_TX_CF_EN_SHIFT 2
+#define __USTORM_ISCSI_AG_CONTEXT_TIMER_CF_EN (0x1<<3)
+#define __USTORM_ISCSI_AG_CONTEXT_TIMER_CF_EN_SHIFT 3
+#define __USTORM_ISCSI_AG_CONTEXT_CQ_LOCAL_COMP_CF_EN (0x1<<4)
+#define __USTORM_ISCSI_AG_CONTEXT_CQ_LOCAL_COMP_CF_EN_SHIFT 4
+#define __USTORM_ISCSI_AG_CONTEXT_QUEUES_FLUSH_Q0_CF_EN (0x1<<5)
+#define __USTORM_ISCSI_AG_CONTEXT_QUEUES_FLUSH_Q0_CF_EN_SHIFT 5
+#define __USTORM_ISCSI_AG_CONTEXT_AUX3_CF_EN (0x1<<6)
+#define __USTORM_ISCSI_AG_CONTEXT_AUX3_CF_EN_SHIFT 6
+#define __USTORM_ISCSI_AG_CONTEXT_DQ_CF_EN (0x1<<7)
+#define __USTORM_ISCSI_AG_CONTEXT_DQ_CF_EN_SHIFT 7
+#elif defined(__LITTLE_ENDIAN)
+ u8 decision_rule_enable_bits;
+#define USTORM_ISCSI_AG_CONTEXT_INV_CF_EN (0x1<<0)
+#define USTORM_ISCSI_AG_CONTEXT_INV_CF_EN_SHIFT 0
+#define USTORM_ISCSI_AG_CONTEXT_COMPLETION_CF_EN (0x1<<1)
+#define USTORM_ISCSI_AG_CONTEXT_COMPLETION_CF_EN_SHIFT 1
+#define USTORM_ISCSI_AG_CONTEXT_TX_CF_EN (0x1<<2)
+#define USTORM_ISCSI_AG_CONTEXT_TX_CF_EN_SHIFT 2
+#define __USTORM_ISCSI_AG_CONTEXT_TIMER_CF_EN (0x1<<3)
+#define __USTORM_ISCSI_AG_CONTEXT_TIMER_CF_EN_SHIFT 3
+#define __USTORM_ISCSI_AG_CONTEXT_CQ_LOCAL_COMP_CF_EN (0x1<<4)
+#define __USTORM_ISCSI_AG_CONTEXT_CQ_LOCAL_COMP_CF_EN_SHIFT 4
+#define __USTORM_ISCSI_AG_CONTEXT_QUEUES_FLUSH_Q0_CF_EN (0x1<<5)
+#define __USTORM_ISCSI_AG_CONTEXT_QUEUES_FLUSH_Q0_CF_EN_SHIFT 5
+#define __USTORM_ISCSI_AG_CONTEXT_AUX3_CF_EN (0x1<<6)
+#define __USTORM_ISCSI_AG_CONTEXT_AUX3_CF_EN_SHIFT 6
+#define __USTORM_ISCSI_AG_CONTEXT_DQ_CF_EN (0x1<<7)
+#define __USTORM_ISCSI_AG_CONTEXT_DQ_CF_EN_SHIFT 7
+ u8 decision_rules;
+#define USTORM_ISCSI_AG_CONTEXT_AGG_VAL2_RULE (0x7<<0)
+#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_RESERVED1 (0x1<<7)
+#define __USTORM_ISCSI_AG_CONTEXT_RESERVED1_SHIFT 7
+ u16 __reserved2;
+#endif
+};
+
+/*
+ * 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 {
+#if defined(__BIG_ENDIAN)
+ u8 remote_addr_4;
+ u8 remote_addr_5;
+ u8 local_addr_0;
+ u8 local_addr_1;
+#elif defined(__LITTLE_ENDIAN)
+ u8 local_addr_1;
+ u8 local_addr_0;
+ u8 remote_addr_5;
+ u8 remote_addr_4;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 remote_addr_0;
+ u8 remote_addr_1;
+ u8 remote_addr_2;
+ u8 remote_addr_3;
+#elif defined(__LITTLE_ENDIAN)
+ u8 remote_addr_3;
+ u8 remote_addr_2;
+ u8 remote_addr_1;
+ u8 remote_addr_0;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 reserved_vlan_type;
+ u16 params;
+#define XSTORM_ETH_CONTEXT_SECTION_VLAN_ID (0xFFF<<0)
+#define XSTORM_ETH_CONTEXT_SECTION_VLAN_ID_SHIFT 0
+#define XSTORM_ETH_CONTEXT_SECTION_CFI (0x1<<12)
+#define XSTORM_ETH_CONTEXT_SECTION_CFI_SHIFT 12
+#define XSTORM_ETH_CONTEXT_SECTION_PRIORITY (0x7<<13)
+#define XSTORM_ETH_CONTEXT_SECTION_PRIORITY_SHIFT 13
+#elif defined(__LITTLE_ENDIAN)
+ u16 params;
+#define XSTORM_ETH_CONTEXT_SECTION_VLAN_ID (0xFFF<<0)
+#define XSTORM_ETH_CONTEXT_SECTION_VLAN_ID_SHIFT 0
+#define XSTORM_ETH_CONTEXT_SECTION_CFI (0x1<<12)
+#define XSTORM_ETH_CONTEXT_SECTION_CFI_SHIFT 12
+#define XSTORM_ETH_CONTEXT_SECTION_PRIORITY (0x7<<13)
+#define XSTORM_ETH_CONTEXT_SECTION_PRIORITY_SHIFT 13
+ u16 reserved_vlan_type;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 local_addr_2;
+ u8 local_addr_3;
+ u8 local_addr_4;
+ u8 local_addr_5;
+#elif defined(__LITTLE_ENDIAN)
+ u8 local_addr_5;
+ u8 local_addr_4;
+ u8 local_addr_3;
+ u8 local_addr_2;
+#endif
+};
+
+/*
+ * IpV4 context section, shared in TOE, RDMA and ISCSI
+ */
+struct xstorm_ip_v4_context_section {
+#if defined(__BIG_ENDIAN)
+ u16 __pbf_hdr_cmd_rsvd_id;
+ u16 __pbf_hdr_cmd_rsvd_flags_offset;
+#elif defined(__LITTLE_ENDIAN)
+ u16 __pbf_hdr_cmd_rsvd_flags_offset;
+ u16 __pbf_hdr_cmd_rsvd_id;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 __pbf_hdr_cmd_rsvd_ver_ihl;
+ u8 tos;
+ u16 __pbf_hdr_cmd_rsvd_length;
+#elif defined(__LITTLE_ENDIAN)
+ u16 __pbf_hdr_cmd_rsvd_length;
+ u8 tos;
+ u8 __pbf_hdr_cmd_rsvd_ver_ihl;
+#endif
+ u32 ip_local_addr;
+#if defined(__BIG_ENDIAN)
+ u8 ttl;
+ u8 __pbf_hdr_cmd_rsvd_protocol;
+ u16 __pbf_hdr_cmd_rsvd_csum;
+#elif defined(__LITTLE_ENDIAN)
+ u16 __pbf_hdr_cmd_rsvd_csum;
+ u8 __pbf_hdr_cmd_rsvd_protocol;
+ u8 ttl;
+#endif
+ u32 __pbf_hdr_cmd_rsvd_1;
+ u32 ip_remote_addr;
+};
+
+/*
+ * context section, shared in TOE, RDMA and ISCSI
+ */
+struct xstorm_padded_ip_v4_context_section {
+ struct xstorm_ip_v4_context_section ip_v4;
+ u32 reserved1[4];
+};
+
+/*
+ * IpV6 context section, shared in TOE, RDMA and ISCSI
+ */
+struct xstorm_ip_v6_context_section {
+#if defined(__BIG_ENDIAN)
+ u16 pbf_hdr_cmd_rsvd_payload_len;
+ u8 pbf_hdr_cmd_rsvd_nxt_hdr;
+ u8 hop_limit;
+#elif defined(__LITTLE_ENDIAN)
+ u8 hop_limit;
+ u8 pbf_hdr_cmd_rsvd_nxt_hdr;
+ u16 pbf_hdr_cmd_rsvd_payload_len;
+#endif
+ u32 priority_flow_label;
+#define XSTORM_IP_V6_CONTEXT_SECTION_FLOW_LABEL (0xFFFFF<<0)
+#define XSTORM_IP_V6_CONTEXT_SECTION_FLOW_LABEL_SHIFT 0
+#define XSTORM_IP_V6_CONTEXT_SECTION_TRAFFIC_CLASS (0xFF<<20)
+#define XSTORM_IP_V6_CONTEXT_SECTION_TRAFFIC_CLASS_SHIFT 20
+#define XSTORM_IP_V6_CONTEXT_SECTION_PBF_HDR_CMD_RSVD_VER (0xF<<28)
+#define XSTORM_IP_V6_CONTEXT_SECTION_PBF_HDR_CMD_RSVD_VER_SHIFT 28
+ u32 ip_local_addr_lo_hi;
+ u32 ip_local_addr_lo_lo;
+ u32 ip_local_addr_hi_hi;
+ u32 ip_local_addr_hi_lo;
+ u32 ip_remote_addr_lo_hi;
+ u32 ip_remote_addr_lo_lo;
+ u32 ip_remote_addr_hi_hi;
+ u32 ip_remote_addr_hi_lo;
+};
+
+union xstorm_ip_context_section_types {
+ struct xstorm_padded_ip_v4_context_section padded_ip_v4;
+ struct xstorm_ip_v6_context_section ip_v6;
+};
+
+/*
+ * TCP context section, shared in TOE, RDMA and ISCSI
+ */
+struct xstorm_tcp_context_section {
+ u32 snd_max;
+#if defined(__BIG_ENDIAN)
+ u16 remote_port;
+ u16 local_port;
+#elif defined(__LITTLE_ENDIAN)
+ u16 local_port;
+ u16 remote_port;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 original_nagle_1b;
+ u8 ts_enabled_1b;
+ u16 tcp_params;
+#define XSTORM_TCP_CONTEXT_SECTION_TOTAL_HEADER_SIZE (0xFF<<0)
+#define XSTORM_TCP_CONTEXT_SECTION_TOTAL_HEADER_SIZE_SHIFT 0
+#define __XSTORM_TCP_CONTEXT_SECTION_ECT_BIT (0x1<<8)
+#define __XSTORM_TCP_CONTEXT_SECTION_ECT_BIT_SHIFT 8
+#define __XSTORM_TCP_CONTEXT_SECTION_ECN_ENABLED (0x1<<9)
+#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_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
+#elif defined(__LITTLE_ENDIAN)
+ u16 tcp_params;
+#define XSTORM_TCP_CONTEXT_SECTION_TOTAL_HEADER_SIZE (0xFF<<0)
+#define XSTORM_TCP_CONTEXT_SECTION_TOTAL_HEADER_SIZE_SHIFT 0
+#define __XSTORM_TCP_CONTEXT_SECTION_ECT_BIT (0x1<<8)
+#define __XSTORM_TCP_CONTEXT_SECTION_ECT_BIT_SHIFT 8
+#define __XSTORM_TCP_CONTEXT_SECTION_ECN_ENABLED (0x1<<9)
+#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_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 original_nagle_1b;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 pseudo_csum;
+ u16 window_scaling_factor;
+#elif defined(__LITTLE_ENDIAN)
+ u16 window_scaling_factor;
+ u16 pseudo_csum;
+#endif
+ u32 reserved2;
+ u32 ts_time_diff;
+ u32 __next_timer_expir;
+};
+
+/*
+ * Common context section, shared in TOE, RDMA and ISCSI
+ */
+struct xstorm_common_context_section {
+ struct xstorm_eth_context_section ethernet;
+ union xstorm_ip_context_section_types ip_union;
+ struct xstorm_tcp_context_section tcp;
+#if defined(__BIG_ENDIAN)
+ u16 reserved;
+ u8 statistics_params;
+#define XSTORM_COMMON_CONTEXT_SECTION_UPDATE_L2_STATSTICS (0x1<<0)
+#define XSTORM_COMMON_CONTEXT_SECTION_UPDATE_L2_STATSTICS_SHIFT 0
+#define XSTORM_COMMON_CONTEXT_SECTION_UPDATE_L4_STATSTICS (0x1<<1)
+#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
+ u8 ip_version_1b;
+#elif defined(__LITTLE_ENDIAN)
+ u8 ip_version_1b;
+ u8 statistics_params;
+#define XSTORM_COMMON_CONTEXT_SECTION_UPDATE_L2_STATSTICS (0x1<<0)
+#define XSTORM_COMMON_CONTEXT_SECTION_UPDATE_L2_STATSTICS_SHIFT 0
+#define XSTORM_COMMON_CONTEXT_SECTION_UPDATE_L4_STATSTICS (0x1<<1)
+#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
+ u16 reserved;
+#endif
+};
+
+/*
+ * Flags used in ISCSI context section
+ */
+struct xstorm_iscsi_context_flags {
+ u8 flags;
+#define XSTORM_ISCSI_CONTEXT_FLAGS_B_IMMEDIATE_DATA (0x1<<0)
+#define XSTORM_ISCSI_CONTEXT_FLAGS_B_IMMEDIATE_DATA_SHIFT 0
+#define XSTORM_ISCSI_CONTEXT_FLAGS_B_INITIAL_R2T (0x1<<1)
+#define XSTORM_ISCSI_CONTEXT_FLAGS_B_INITIAL_R2T_SHIFT 1
+#define XSTORM_ISCSI_CONTEXT_FLAGS_B_EN_HEADER_DIGEST (0x1<<2)
+#define XSTORM_ISCSI_CONTEXT_FLAGS_B_EN_HEADER_DIGEST_SHIFT 2
+#define XSTORM_ISCSI_CONTEXT_FLAGS_B_EN_DATA_DIGEST (0x1<<3)
+#define XSTORM_ISCSI_CONTEXT_FLAGS_B_EN_DATA_DIGEST_SHIFT 3
+#define XSTORM_ISCSI_CONTEXT_FLAGS_B_HQ_BD_WRITTEN (0x1<<4)
+#define XSTORM_ISCSI_CONTEXT_FLAGS_B_HQ_BD_WRITTEN_SHIFT 4
+#define XSTORM_ISCSI_CONTEXT_FLAGS_B_LAST_OP_SQ (0x1<<5)
+#define XSTORM_ISCSI_CONTEXT_FLAGS_B_LAST_OP_SQ_SHIFT 5
+#define XSTORM_ISCSI_CONTEXT_FLAGS_B_UPDATE_SND_NXT (0x1<<6)
+#define XSTORM_ISCSI_CONTEXT_FLAGS_B_UPDATE_SND_NXT_SHIFT 6
+#define XSTORM_ISCSI_CONTEXT_FLAGS_RESERVED4 (0x1<<7)
+#define XSTORM_ISCSI_CONTEXT_FLAGS_RESERVED4_SHIFT 7
+};
+
+struct iscsi_task_context_entry_x {
+ u32 data_out_buffer_offset;
+ u32 itt;
+ u32 data_sn;
+};
+
+struct iscsi_task_context_entry_xuc_x_write_only {
+ u32 tx_r2t_sn;
+};
+
+struct iscsi_task_context_entry_xuc_xu_write_both {
+ u32 sgl_base_lo;
+ u32 sgl_base_hi;
+#if defined(__BIG_ENDIAN)
+ u8 sgl_size;
+ u8 sge_index;
+ u16 sge_offset;
+#elif defined(__LITTLE_ENDIAN)
+ u16 sge_offset;
+ u8 sge_index;
+ u8 sgl_size;
+#endif
+};
+
+/*
+ * iSCSI context section
+ */
+struct xstorm_iscsi_context_section {
+ u32 first_burst_length;
+ u32 max_send_pdu_length;
+ struct regpair sq_pbl_base;
+ struct regpair sq_curr_pbe;
+ struct regpair hq_pbl_base;
+ struct regpair hq_curr_pbe_base;
+ struct regpair r2tq_pbl_base;
+ struct regpair r2tq_curr_pbe_base;
+ struct regpair task_pbl_base;
+#if defined(__BIG_ENDIAN)
+ u16 data_out_count;
+ struct xstorm_iscsi_context_flags flags;
+ u8 task_pbl_cache_idx;
+#elif defined(__LITTLE_ENDIAN)
+ u8 task_pbl_cache_idx;
+ struct xstorm_iscsi_context_flags flags;
+ u16 data_out_count;
+#endif
+ u32 seq_more_2_send;
+ u32 pdu_more_2_send;
+ struct iscsi_task_context_entry_x temp_tce_x;
+ struct iscsi_task_context_entry_xuc_x_write_only temp_tce_x_wr;
+ struct iscsi_task_context_entry_xuc_xu_write_both temp_tce_xu_wr;
+ struct regpair lun;
+ u32 exp_data_transfer_len_ttt;
+ u32 pdu_data_2_rxmit;
+ u32 rxmit_bytes_2_dr;
+#if defined(__BIG_ENDIAN)
+ u16 rxmit_sge_offset;
+ u16 hq_rxmit_cons;
+#elif defined(__LITTLE_ENDIAN)
+ u16 hq_rxmit_cons;
+ u16 rxmit_sge_offset;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 r2tq_cons;
+ u8 rxmit_flags;
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_NEW_HQ_BD (0x1<<0)
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_NEW_HQ_BD_SHIFT 0
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_PDU_HDR (0x1<<1)
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_PDU_HDR_SHIFT 1
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_END_PDU (0x1<<2)
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_END_PDU_SHIFT 2
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_DR (0x1<<3)
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_DR_SHIFT 3
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_START_DR (0x1<<4)
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_START_DR_SHIFT 4
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_PADDING (0x3<<5)
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_PADDING_SHIFT 5
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_ISCSI_CONT_FAST_RXMIT (0x1<<7)
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_ISCSI_CONT_FAST_RXMIT_SHIFT 7
+ u8 rxmit_sge_idx;
+#elif defined(__LITTLE_ENDIAN)
+ u8 rxmit_sge_idx;
+ u8 rxmit_flags;
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_NEW_HQ_BD (0x1<<0)
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_NEW_HQ_BD_SHIFT 0
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_PDU_HDR (0x1<<1)
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_PDU_HDR_SHIFT 1
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_END_PDU (0x1<<2)
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_END_PDU_SHIFT 2
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_DR (0x1<<3)
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_DR_SHIFT 3
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_START_DR (0x1<<4)
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_START_DR_SHIFT 4
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_PADDING (0x3<<5)
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_RXMIT_PADDING_SHIFT 5
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_ISCSI_CONT_FAST_RXMIT (0x1<<7)
+#define XSTORM_ISCSI_CONTEXT_SECTION_B_ISCSI_CONT_FAST_RXMIT_SHIFT 7
+ u16 r2tq_cons;
+#endif
+ u32 hq_rxmit_tcp_seq;
+};
+
+/*
+ * Xstorm iSCSI Storm Context
+ */
+struct xstorm_iscsi_st_context {
+ struct xstorm_common_context_section common;
+ struct xstorm_iscsi_context_section iscsi;
+};
+
+/*
+ * CQ DB CQ producer and pending completion counter
+ */
+struct iscsi_cq_db_prod_pnd_cmpltn_cnt {
+#if defined(__BIG_ENDIAN)
+ u16 cntr;
+ u16 prod;
+#elif defined(__LITTLE_ENDIAN)
+ u16 prod;
+ u16 cntr;
+#endif
+};
+
+/*
+ * CQ DB pending completion ITT array
+ */
+struct iscsi_cq_db_prod_pnd_cmpltn_cnt_arr {
+ struct iscsi_cq_db_prod_pnd_cmpltn_cnt prod_pend_comp[8];
+};
+
+/*
+ * Cstorm CQ sequence to notify array, updated by driver
+ */
+struct iscsi_cq_db_sqn_2_notify_arr {
+ u16 sqn[8];
+};
+
+/*
+ * Cstorm iSCSI Storm Context
+ */
+struct cstorm_iscsi_st_context {
+ struct iscsi_cq_db_prod_pnd_cmpltn_cnt_arr cq_c_prod_pend_comp_ctr_arr;
+ struct iscsi_cq_db_sqn_2_notify_arr cq_c_prod_sqn_arr;
+ struct iscsi_cq_db_sqn_2_notify_arr cq_c_sqn_2_notify_arr;
+ struct regpair hq_pbl_base;
+ struct regpair hq_curr_pbe;
+ struct regpair task_pbl_base;
+ struct regpair cq_db_base;
+#if defined(__BIG_ENDIAN)
+ u16 hq_bd_itt;
+ u16 iscsi_conn_id;
+#elif defined(__LITTLE_ENDIAN)
+ u16 iscsi_conn_id;
+ u16 hq_bd_itt;
+#endif
+ u32 hq_bd_data_segment_len;
+ u32 hq_bd_buffer_offset;
+#if defined(__BIG_ENDIAN)
+ u8 timer_entry_idx;
+ u8 cq_proc_en_bit_map;
+ u8 cq_pend_comp_itt_valid_bit_map;
+ u8 hq_bd_opcode;
+#elif defined(__LITTLE_ENDIAN)
+ u8 hq_bd_opcode;
+ u8 cq_pend_comp_itt_valid_bit_map;
+ u8 cq_proc_en_bit_map;
+ u8 timer_entry_idx;
+#endif
+ u32 hq_tcp_seq;
+#if defined(__BIG_ENDIAN)
+ u16 flags;
+#define CSTORM_ISCSI_ST_CONTEXT_DATA_DIGEST_EN (0x1<<0)
+#define CSTORM_ISCSI_ST_CONTEXT_DATA_DIGEST_EN_SHIFT 0
+#define CSTORM_ISCSI_ST_CONTEXT_HDR_DIGEST_EN (0x1<<1)
+#define CSTORM_ISCSI_ST_CONTEXT_HDR_DIGEST_EN_SHIFT 1
+#define CSTORM_ISCSI_ST_CONTEXT_HQ_BD_CTXT_VALID (0x1<<2)
+#define CSTORM_ISCSI_ST_CONTEXT_HQ_BD_CTXT_VALID_SHIFT 2
+#define CSTORM_ISCSI_ST_CONTEXT_HQ_BD_LCL_CMPLN_FLG (0x1<<3)
+#define CSTORM_ISCSI_ST_CONTEXT_HQ_BD_LCL_CMPLN_FLG_SHIFT 3
+#define CSTORM_ISCSI_ST_CONTEXT_HQ_BD_WRITE_TASK (0x1<<4)
+#define CSTORM_ISCSI_ST_CONTEXT_HQ_BD_WRITE_TASK_SHIFT 4
+#define CSTORM_ISCSI_ST_CONTEXT_CTRL_FLAGS_RSRV (0x7FF<<5)
+#define CSTORM_ISCSI_ST_CONTEXT_CTRL_FLAGS_RSRV_SHIFT 5
+ u16 hq_cons;
+#elif defined(__LITTLE_ENDIAN)
+ u16 hq_cons;
+ u16 flags;
+#define CSTORM_ISCSI_ST_CONTEXT_DATA_DIGEST_EN (0x1<<0)
+#define CSTORM_ISCSI_ST_CONTEXT_DATA_DIGEST_EN_SHIFT 0
+#define CSTORM_ISCSI_ST_CONTEXT_HDR_DIGEST_EN (0x1<<1)
+#define CSTORM_ISCSI_ST_CONTEXT_HDR_DIGEST_EN_SHIFT 1
+#define CSTORM_ISCSI_ST_CONTEXT_HQ_BD_CTXT_VALID (0x1<<2)
+#define CSTORM_ISCSI_ST_CONTEXT_HQ_BD_CTXT_VALID_SHIFT 2
+#define CSTORM_ISCSI_ST_CONTEXT_HQ_BD_LCL_CMPLN_FLG (0x1<<3)
+#define CSTORM_ISCSI_ST_CONTEXT_HQ_BD_LCL_CMPLN_FLG_SHIFT 3
+#define CSTORM_ISCSI_ST_CONTEXT_HQ_BD_WRITE_TASK (0x1<<4)
+#define CSTORM_ISCSI_ST_CONTEXT_HQ_BD_WRITE_TASK_SHIFT 4
+#define CSTORM_ISCSI_ST_CONTEXT_CTRL_FLAGS_RSRV (0x7FF<<5)
+#define CSTORM_ISCSI_ST_CONTEXT_CTRL_FLAGS_RSRV_SHIFT 5
+#endif
+ struct regpair rsrv1;
+};
+
+/*
+ * Iscsi connection context
+ */
+struct iscsi_context {
+ struct ustorm_iscsi_st_context ustorm_st_context;
+ struct tstorm_iscsi_st_context tstorm_st_context;
+ struct xstorm_iscsi_ag_context xstorm_ag_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 regpair upb_context;
+ struct xstorm_iscsi_st_context xstorm_st_context;
+ struct regpair xpb_context;
+ struct cstorm_iscsi_st_context cstorm_st_context;
+};
+
+/*
+ * Buffer per connection, used in Tstorm
+ */
+struct iscsi_conn_buf {
+ struct regpair reserved[8];
+};
+
+/*
+ * ipv6 structure
+ */
+struct ip_v6_addr {
+ u32 ip_addr_lo_lo;
+ u32 ip_addr_lo_hi;
+ u32 ip_addr_hi_lo;
+ u32 ip_addr_hi_hi;
+};
+
+/*
+ * l5cm- connection identification params
+ */
+struct l5cm_conn_addr_params {
+ u32 pmtu;
+#if defined(__BIG_ENDIAN)
+ u8 remote_addr_3;
+ u8 remote_addr_2;
+ u8 remote_addr_1;
+ u8 remote_addr_0;
+#elif defined(__LITTLE_ENDIAN)
+ u8 remote_addr_0;
+ u8 remote_addr_1;
+ u8 remote_addr_2;
+ u8 remote_addr_3;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 params;
+#define L5CM_CONN_ADDR_PARAMS_IP_VERSION (0x1<<0)
+#define L5CM_CONN_ADDR_PARAMS_IP_VERSION_SHIFT 0
+#define L5CM_CONN_ADDR_PARAMS_RSRV (0x7FFF<<1)
+#define L5CM_CONN_ADDR_PARAMS_RSRV_SHIFT 1
+ u8 remote_addr_5;
+ u8 remote_addr_4;
+#elif defined(__LITTLE_ENDIAN)
+ u8 remote_addr_4;
+ u8 remote_addr_5;
+ u16 params;
+#define L5CM_CONN_ADDR_PARAMS_IP_VERSION (0x1<<0)
+#define L5CM_CONN_ADDR_PARAMS_IP_VERSION_SHIFT 0
+#define L5CM_CONN_ADDR_PARAMS_RSRV (0x7FFF<<1)
+#define L5CM_CONN_ADDR_PARAMS_RSRV_SHIFT 1
+#endif
+ struct ip_v6_addr local_ip_addr;
+ struct ip_v6_addr remote_ip_addr;
+ u32 ipv6_flow_label_20b;
+ u32 reserved1;
+#if defined(__BIG_ENDIAN)
+ u16 remote_tcp_port;
+ u16 local_tcp_port;
+#elif defined(__LITTLE_ENDIAN)
+ u16 local_tcp_port;
+ u16 remote_tcp_port;
+#endif
+};
+
+/*
+ * l5cm-xstorm connection buffer
+ */
+struct l5cm_xstorm_conn_buffer {
+#if defined(__BIG_ENDIAN)
+ u16 rsrv1;
+ u16 params;
+#define L5CM_XSTORM_CONN_BUFFER_NAGLE_ENABLE (0x1<<0)
+#define L5CM_XSTORM_CONN_BUFFER_NAGLE_ENABLE_SHIFT 0
+#define L5CM_XSTORM_CONN_BUFFER_RSRV (0x7FFF<<1)
+#define L5CM_XSTORM_CONN_BUFFER_RSRV_SHIFT 1
+#elif defined(__LITTLE_ENDIAN)
+ u16 params;
+#define L5CM_XSTORM_CONN_BUFFER_NAGLE_ENABLE (0x1<<0)
+#define L5CM_XSTORM_CONN_BUFFER_NAGLE_ENABLE_SHIFT 0
+#define L5CM_XSTORM_CONN_BUFFER_RSRV (0x7FFF<<1)
+#define L5CM_XSTORM_CONN_BUFFER_RSRV_SHIFT 1
+ u16 rsrv1;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 mss;
+ u16 pseudo_header_checksum;
+#elif defined(__LITTLE_ENDIAN)
+ u16 pseudo_header_checksum;
+ u16 mss;
+#endif
+ u32 rcv_buf;
+ u32 rsrv2;
+ struct regpair context_addr;
+};
+
+/*
+ * l5cm-tstorm connection buffer
+ */
+struct l5cm_tstorm_conn_buffer {
+ u32 snd_buf;
+ u32 rcv_buf;
+#if defined(__BIG_ENDIAN)
+ u16 params;
+#define L5CM_TSTORM_CONN_BUFFER_DELAYED_ACK_ENABLE (0x1<<0)
+#define L5CM_TSTORM_CONN_BUFFER_DELAYED_ACK_ENABLE_SHIFT 0
+#define L5CM_TSTORM_CONN_BUFFER_RSRV (0x7FFF<<1)
+#define L5CM_TSTORM_CONN_BUFFER_RSRV_SHIFT 1
+ u8 ka_max_probe_count;
+ u8 ka_enable;
+#elif defined(__LITTLE_ENDIAN)
+ u8 ka_enable;
+ u8 ka_max_probe_count;
+ u16 params;
+#define L5CM_TSTORM_CONN_BUFFER_DELAYED_ACK_ENABLE (0x1<<0)
+#define L5CM_TSTORM_CONN_BUFFER_DELAYED_ACK_ENABLE_SHIFT 0
+#define L5CM_TSTORM_CONN_BUFFER_RSRV (0x7FFF<<1)
+#define L5CM_TSTORM_CONN_BUFFER_RSRV_SHIFT 1
+#endif
+ u32 ka_timeout;
+ u32 ka_interval;
+ u32 max_rt_time;
+};
+
+/*
+ * l5cm connection buffer for active side
+ */
+struct l5cm_active_conn_buffer {
+ struct l5cm_conn_addr_params conn_addr_buf;
+ struct l5cm_xstorm_conn_buffer xstorm_conn_buffer;
+ struct l5cm_tstorm_conn_buffer tstorm_conn_buffer;
+};
+
+/*
+ * l5cm slow path element
+ */
+struct l5cm_packet_size {
+ u32 size;
+ u32 rsrv;
+};
+
+/*
+ * l5cm connection parameters
+ */
+union l5cm_reduce_param_union {
+ u32 passive_side_scramble_key;
+ u32 pcs_id;
+};
+
+/*
+ * l5cm connection parameters
+ */
+struct l5cm_reduce_conn {
+ union l5cm_reduce_param_union param;
+ u32 isn;
+};
+
+/*
+ * l5cm slow path element
+ */
+union l5cm_specific_data {
+ u8 protocol_data[8];
+ struct regpair phy_address;
+ struct l5cm_packet_size packet_size;
+ struct l5cm_reduce_conn reduced_conn;
+};
+
+/*
+ * l5 slow path element
+ */
+struct l5cm_spe {
+ struct spe_hdr hdr;
+ union l5cm_specific_data data;
+};
+
+/*
+ * Tstorm Tcp flags
+ */
+struct tstorm_l5cm_tcp_flags {
+ u16 flags;
+#define TSTORM_L5CM_TCP_FLAGS_VLAN_ID (0xFFF<<0)
+#define TSTORM_L5CM_TCP_FLAGS_VLAN_ID_SHIFT 0
+#define TSTORM_L5CM_TCP_FLAGS_RSRV0 (0x1<<12)
+#define TSTORM_L5CM_TCP_FLAGS_RSRV0_SHIFT 12
+#define TSTORM_L5CM_TCP_FLAGS_TS_ENABLED (0x1<<13)
+#define TSTORM_L5CM_TCP_FLAGS_TS_ENABLED_SHIFT 13
+#define TSTORM_L5CM_TCP_FLAGS_RSRV1 (0x3<<14)
+#define TSTORM_L5CM_TCP_FLAGS_RSRV1_SHIFT 14
+};
+
+/*
+ * Xstorm Tcp flags
+ */
+struct xstorm_l5cm_tcp_flags {
+ u8 flags;
+#define XSTORM_L5CM_TCP_FLAGS_ENC_ENABLED (0x1<<0)
+#define XSTORM_L5CM_TCP_FLAGS_ENC_ENABLED_SHIFT 0
+#define XSTORM_L5CM_TCP_FLAGS_TS_ENABLED (0x1<<1)
+#define XSTORM_L5CM_TCP_FLAGS_TS_ENABLED_SHIFT 1
+#define XSTORM_L5CM_TCP_FLAGS_WND_SCL_EN (0x1<<2)
+#define XSTORM_L5CM_TCP_FLAGS_WND_SCL_EN_SHIFT 2
+#define XSTORM_L5CM_TCP_FLAGS_RSRV (0x1F<<3)
+#define XSTORM_L5CM_TCP_FLAGS_RSRV_SHIFT 3
+};
+
#endif /* CNIC_DEFS_H */
diff --git a/drivers/net/cnic_if.h b/drivers/net/cnic_if.h
index d8b09efdcb52..8aaf98bdd4f7 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.0.1"
-#define CNIC_MODULE_RELDATE "Oct 01, 2009"
+#define CNIC_MODULE_VERSION "2.1.0"
+#define CNIC_MODULE_RELDATE "Oct 10, 2009"
#define CNIC_ULP_RDMA 0
#define CNIC_ULP_ISCSI 1
@@ -81,6 +81,8 @@ struct kcqe {
#define DRV_CTL_CTX_WR_CMD 0x103
#define DRV_CTL_CTXTBL_WR_CMD 0x104
#define DRV_CTL_COMPLETION_CMD 0x105
+#define DRV_CTL_START_L2_CMD 0x106
+#define DRV_CTL_STOP_L2_CMD 0x107
struct cnic_ctl_completion {
u32 cid;
@@ -105,11 +107,17 @@ struct drv_ctl_io {
dma_addr_t dma_addr;
};
+struct drv_ctl_l2_ring {
+ u32 client_id;
+ u32 cid;
+};
+
struct drv_ctl_info {
int cmd;
union {
struct drv_ctl_completion comp;
struct drv_ctl_io io;
+ struct drv_ctl_l2_ring ring;
char bytes[MAX_DRV_CTL_DATA];
} data;
};
@@ -143,6 +151,7 @@ struct cnic_eth_dev {
u32 max_kwqe_pending;
struct pci_dev *pdev;
void __iomem *io_base;
+ void __iomem *io_base2;
u32 ctx_tbl_offset;
u32 ctx_tbl_len;
@@ -298,5 +307,6 @@ extern int cnic_register_driver(int ulp_type, struct cnic_ulp_ops *ulp_ops);
extern int cnic_unregister_driver(int ulp_type);
extern struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev);
+extern struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev);
#endif
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c
index 61f9da2b4943..678222389407 100644
--- a/drivers/net/cpmac.c
+++ b/drivers/net/cpmac.c
@@ -380,9 +380,8 @@ static struct sk_buff *cpmac_rx_one(struct cpmac_priv *priv,
return NULL;
}
- skb = netdev_alloc_skb(priv->dev, CPMAC_SKB_SIZE);
+ skb = netdev_alloc_skb_ip_align(priv->dev, CPMAC_SKB_SIZE);
if (likely(skb)) {
- skb_reserve(skb, 2);
skb_put(desc->skb, desc->datalen);
desc->skb->protocol = eth_type_trans(desc->skb, priv->dev);
desc->skb->ip_summed = CHECKSUM_NONE;
@@ -991,12 +990,11 @@ static int cpmac_open(struct net_device *dev)
priv->rx_head = &priv->desc_ring[CPMAC_QUEUES];
for (i = 0, desc = priv->rx_head; i < priv->ring_size; i++, desc++) {
- skb = netdev_alloc_skb(dev, CPMAC_SKB_SIZE);
+ skb = netdev_alloc_skb_ip_align(dev, CPMAC_SKB_SIZE);
if (unlikely(!skb)) {
res = -ENOMEM;
goto fail_desc;
}
- skb_reserve(skb, 2);
desc->skb = skb;
desc->data_mapping = dma_map_single(&dev->dev, skb->data,
CPMAC_SKB_SIZE,
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index 2b1aea6aa558..3e8618b4efbc 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -48,12 +48,27 @@
struct vlan_group;
struct adapter;
struct sge_qset;
+struct port_info;
enum { /* rx_offload flags */
T3_RX_CSUM = 1 << 0,
T3_LRO = 1 << 1,
};
+enum mac_idx_types {
+ LAN_MAC_IDX = 0,
+ SAN_MAC_IDX,
+
+ MAX_MAC_IDX
+};
+
+struct iscsi_config {
+ __u8 mac_addr[ETH_ALEN];
+ __u32 flags;
+ int (*send)(struct port_info *pi, struct sk_buff **skb);
+ int (*recv)(struct port_info *pi, struct sk_buff *skb);
+};
+
struct port_info {
struct adapter *adapter;
struct vlan_group *vlan_grp;
@@ -68,6 +83,7 @@ struct port_info {
struct net_device_stats netstats;
int activity;
__be32 iscsi_ipv4addr;
+ struct iscsi_config iscsic;
int link_fault; /* link fault was detected */
};
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 34e776c5f06b..c9113d3297ee 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -344,8 +344,10 @@ static void link_start(struct net_device *dev)
init_rx_mode(&rm, dev, dev->mc_list);
t3_mac_reset(mac);
+ t3_mac_set_num_ucast(mac, MAX_MAC_IDX);
t3_mac_set_mtu(mac, dev->mtu);
- t3_mac_set_address(mac, 0, dev->dev_addr);
+ t3_mac_set_address(mac, LAN_MAC_IDX, dev->dev_addr);
+ t3_mac_set_address(mac, SAN_MAC_IDX, pi->iscsic.mac_addr);
t3_mac_set_rx_mode(mac, &rm);
t3_link_start(&pi->phy, mac, &pi->link_config);
t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
@@ -903,6 +905,7 @@ static inline int offload_tx(struct t3cdev *tdev, struct sk_buff *skb)
static int write_smt_entry(struct adapter *adapter, int idx)
{
struct cpl_smt_write_req *req;
+ struct port_info *pi = netdev_priv(adapter->port[idx]);
struct sk_buff *skb = alloc_skb(sizeof(*req), GFP_KERNEL);
if (!skb)
@@ -913,8 +916,8 @@ static int write_smt_entry(struct adapter *adapter, int idx)
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */
req->iff = idx;
- memset(req->src_mac1, 0, sizeof(req->src_mac1));
memcpy(req->src_mac0, adapter->port[idx]->dev_addr, ETH_ALEN);
+ memcpy(req->src_mac1, pi->iscsic.mac_addr, ETH_ALEN);
skb->priority = 1;
offload_tx(&adapter->tdev, skb);
return 0;
@@ -2516,7 +2519,7 @@ static int cxgb_set_mac_addr(struct net_device *dev, void *p)
return -EINVAL;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
- t3_mac_set_address(&pi->mac, 0, dev->dev_addr);
+ t3_mac_set_address(&pi->mac, LAN_MAC_IDX, dev->dev_addr);
if (offload_running(adapter))
write_smt_entry(adapter, pi->port_id);
return 0;
@@ -2654,7 +2657,7 @@ static void check_t3b2_mac(struct adapter *adapter)
struct cmac *mac = &p->mac;
t3_mac_set_mtu(mac, dev->mtu);
- t3_mac_set_address(mac, 0, dev->dev_addr);
+ t3_mac_set_address(mac, LAN_MAC_IDX, dev->dev_addr);
cxgb_set_rxmode(dev);
t3_link_start(&p->phy, mac, &p->link_config);
t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
@@ -3112,6 +3115,14 @@ static const struct net_device_ops cxgb_netdev_ops = {
#endif
};
+static void __devinit cxgb3_init_iscsi_mac(struct net_device *dev)
+{
+ struct port_info *pi = netdev_priv(dev);
+
+ memcpy(pi->iscsic.mac_addr, dev->dev_addr, ETH_ALEN);
+ pi->iscsic.mac_addr[3] |= 0x80;
+}
+
static int __devinit init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -3270,6 +3281,9 @@ static int __devinit init_one(struct pci_dev *pdev,
goto out_free_dev;
}
+ for_each_port(adapter, i)
+ cxgb3_init_iscsi_mac(adapter->port[i]);
+
/* Driver's ready. Reflect it on LEDs */
t3_led_ready(adapter);
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index f86612857a73..cf2e1d3c0d8d 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -1260,7 +1260,7 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
if (should_restart_tx(q) &&
test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) {
q->restarts++;
- netif_tx_wake_queue(txq);
+ netif_tx_start_queue(txq);
}
}
@@ -1946,10 +1946,9 @@ static void restart_tx(struct sge_qset *qs)
* Check if the ARP request is probing the private IP address
* dedicated to iSCSI, generate an ARP reply if so.
*/
-static void cxgb3_arp_process(struct adapter *adapter, struct sk_buff *skb)
+static void cxgb3_arp_process(struct port_info *pi, struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
- struct port_info *pi;
struct arphdr *arp;
unsigned char *arp_ptr;
unsigned char *sha;
@@ -1972,12 +1971,11 @@ static void cxgb3_arp_process(struct adapter *adapter, struct sk_buff *skb)
arp_ptr += dev->addr_len;
memcpy(&tip, arp_ptr, sizeof(tip));
- pi = netdev_priv(dev);
if (tip != pi->iscsi_ipv4addr)
return;
arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha,
- dev->dev_addr, sha);
+ pi->iscsic.mac_addr, sha);
}
@@ -1986,6 +1984,19 @@ static inline int is_arp(struct sk_buff *skb)
return skb->protocol == htons(ETH_P_ARP);
}
+static void cxgb3_process_iscsi_prov_pack(struct port_info *pi,
+ struct sk_buff *skb)
+{
+ if (is_arp(skb)) {
+ cxgb3_arp_process(pi, skb);
+ return;
+ }
+
+ if (pi->iscsic.recv)
+ pi->iscsic.recv(pi, skb);
+
+}
+
/**
* rx_eth - process an ingress ethernet packet
* @adap: the adapter
@@ -2024,13 +2035,12 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
vlan_gro_receive(&qs->napi, grp,
ntohs(p->vlan), skb);
else {
- if (unlikely(pi->iscsi_ipv4addr &&
- is_arp(skb))) {
+ if (unlikely(pi->iscsic.flags)) {
unsigned short vtag = ntohs(p->vlan) &
VLAN_VID_MASK;
skb->dev = vlan_group_get_device(grp,
vtag);
- cxgb3_arp_process(adap, skb);
+ cxgb3_process_iscsi_prov_pack(pi, skb);
}
__vlan_hwaccel_rx(skb, grp, ntohs(p->vlan),
rq->polling);
@@ -2041,8 +2051,8 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
if (lro)
napi_gro_receive(&qs->napi, skb);
else {
- if (unlikely(pi->iscsi_ipv4addr && is_arp(skb)))
- cxgb3_arp_process(adap, skb);
+ if (unlikely(pi->iscsic.flags))
+ cxgb3_process_iscsi_prov_pack(pi, skb);
netif_receive_skb(skb);
}
} else
@@ -2125,6 +2135,7 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
if (!complete)
return;
+ skb_record_rx_queue(skb, qs - &adap->sge.qs[0]);
skb->ip_summed = CHECKSUM_UNNECESSARY;
cpl = qs->lro_va;
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
index f72c56dec33c..a876dce13b9e 100644
--- a/drivers/net/davinci_emac.c
+++ b/drivers/net/davinci_emac.c
@@ -164,16 +164,14 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
# define EMAC_MBP_MCASTCHAN(ch) ((ch) & 0x7)
/* EMAC mac_control register */
-#define EMAC_MACCONTROL_TXPTYPE (0x200)
-#define EMAC_MACCONTROL_TXPACEEN (0x40)
-#define EMAC_MACCONTROL_MIIEN (0x20)
-#define EMAC_MACCONTROL_GIGABITEN (0x80)
-#define EMAC_MACCONTROL_GIGABITEN_SHIFT (7)
-#define EMAC_MACCONTROL_FULLDUPLEXEN (0x1)
+#define EMAC_MACCONTROL_TXPTYPE BIT(9)
+#define EMAC_MACCONTROL_TXPACEEN BIT(6)
+#define EMAC_MACCONTROL_GMIIEN BIT(5)
+#define EMAC_MACCONTROL_GIGABITEN BIT(7)
+#define EMAC_MACCONTROL_FULLDUPLEXEN BIT(0)
#define EMAC_MACCONTROL_RMIISPEED_MASK BIT(15)
/* GIGABIT MODE related bits */
-#define EMAC_DM646X_MACCONTORL_GMIIEN BIT(5)
#define EMAC_DM646X_MACCONTORL_GIG BIT(7)
#define EMAC_DM646X_MACCONTORL_GIGFORCE BIT(17)
@@ -192,10 +190,10 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
#define EMAC_RX_BUFFER_OFFSET_MASK (0xFFFF)
/* MAC_IN_VECTOR (0x180) register bit fields */
-#define EMAC_DM644X_MAC_IN_VECTOR_HOST_INT (0x20000)
-#define EMAC_DM644X_MAC_IN_VECTOR_STATPEND_INT (0x10000)
-#define EMAC_DM644X_MAC_IN_VECTOR_RX_INT_VEC (0x0100)
-#define EMAC_DM644X_MAC_IN_VECTOR_TX_INT_VEC (0x01)
+#define EMAC_DM644X_MAC_IN_VECTOR_HOST_INT BIT(17)
+#define EMAC_DM644X_MAC_IN_VECTOR_STATPEND_INT BIT(16)
+#define EMAC_DM644X_MAC_IN_VECTOR_RX_INT_VEC BIT(8)
+#define EMAC_DM644X_MAC_IN_VECTOR_TX_INT_VEC BIT(0)
/** NOTE:: For DM646x the IN_VECTOR has changed */
#define EMAC_DM646X_MAC_IN_VECTOR_RX_INT_VEC BIT(EMAC_DEF_RX_CH)
@@ -203,7 +201,6 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
#define EMAC_DM646X_MAC_IN_VECTOR_HOST_INT BIT(26)
#define EMAC_DM646X_MAC_IN_VECTOR_STATPEND_INT BIT(27)
-
/* CPPI bit positions */
#define EMAC_CPPI_SOP_BIT BIT(31)
#define EMAC_CPPI_EOP_BIT BIT(30)
@@ -750,8 +747,7 @@ static void emac_update_phystatus(struct emac_priv *priv)
if (priv->speed == SPEED_1000 && (priv->version == EMAC_VERSION_2)) {
mac_control = emac_read(EMAC_MACCONTROL);
- mac_control |= (EMAC_DM646X_MACCONTORL_GMIIEN |
- EMAC_DM646X_MACCONTORL_GIG |
+ mac_control |= (EMAC_DM646X_MACCONTORL_GIG |
EMAC_DM646X_MACCONTORL_GIGFORCE);
} else {
/* Clear the GIG bit and GIGFORCE bit */
@@ -2108,7 +2104,7 @@ static int emac_hw_enable(struct emac_priv *priv)
/* Enable MII */
val = emac_read(EMAC_MACCONTROL);
- val |= (EMAC_MACCONTROL_MIIEN);
+ val |= (EMAC_MACCONTROL_GMIIEN);
emac_write(EMAC_MACCONTROL, val);
/* Enable NAPI and interrupts */
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index 7fa7a907f134..ce8fef184f2c 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -505,7 +505,8 @@ rio_timer (unsigned long data)
entry = np->old_rx % RX_RING_SIZE;
/* Dropped packets don't need to re-allocate */
if (np->rx_skbuff[entry] == NULL) {
- skb = netdev_alloc_skb (dev, np->rx_buf_sz);
+ skb = netdev_alloc_skb_ip_align(dev,
+ np->rx_buf_sz);
if (skb == NULL) {
np->rx_ring[entry].fraginfo = 0;
printk (KERN_INFO
@@ -514,8 +515,6 @@ rio_timer (unsigned long data)
break;
}
np->rx_skbuff[entry] = skb;
- /* 16 byte align the IP header */
- skb_reserve (skb, 2);
np->rx_ring[entry].fraginfo =
cpu_to_le64 (pci_map_single
(np->pdev, skb->data, np->rx_buf_sz,
@@ -576,7 +575,9 @@ alloc_list (struct net_device *dev)
/* Allocate the rx buffers */
for (i = 0; i < RX_RING_SIZE; i++) {
/* Allocated fixed size of skbuff */
- struct sk_buff *skb = netdev_alloc_skb (dev, np->rx_buf_sz);
+ struct sk_buff *skb;
+
+ skb = netdev_alloc_skb_ip_align(dev, np->rx_buf_sz);
np->rx_skbuff[i] = skb;
if (skb == NULL) {
printk (KERN_ERR
@@ -584,7 +585,6 @@ alloc_list (struct net_device *dev)
dev->name);
break;
}
- skb_reserve (skb, 2); /* 16 byte align the IP header. */
/* Rubicon now supports 40 bits of addressing space. */
np->rx_ring[i].fraginfo =
cpu_to_le64 ( pci_map_single (
@@ -871,13 +871,11 @@ receive_packet (struct net_device *dev)
PCI_DMA_FROMDEVICE);
skb_put (skb = np->rx_skbuff[entry], pkt_len);
np->rx_skbuff[entry] = NULL;
- } else if ((skb = netdev_alloc_skb(dev, pkt_len + 2))) {
+ } else if ((skb = netdev_alloc_skb_ip_align(dev, pkt_len))) {
pci_dma_sync_single_for_cpu(np->pdev,
desc_to_dma(desc),
np->rx_buf_sz,
PCI_DMA_FROMDEVICE);
- /* 16 byte align the IP header */
- skb_reserve (skb, 2);
skb_copy_to_linear_data (skb,
np->rx_skbuff[entry]->data,
pkt_len);
@@ -907,7 +905,7 @@ receive_packet (struct net_device *dev)
struct sk_buff *skb;
/* Dropped packets don't need to re-allocate */
if (np->rx_skbuff[entry] == NULL) {
- skb = netdev_alloc_skb(dev, np->rx_buf_sz);
+ skb = netdev_alloc_skb_ip_align(dev, np->rx_buf_sz);
if (skb == NULL) {
np->rx_ring[entry].fraginfo = 0;
printk (KERN_INFO
@@ -917,8 +915,6 @@ receive_packet (struct net_device *dev)
break;
}
np->rx_skbuff[entry] = skb;
- /* 16 byte align the IP header */
- skb_reserve (skb, 2);
np->rx_ring[entry].fraginfo =
cpu_to_le64 (pci_map_single
(np->pdev, skb->data, np->rx_buf_sz,
diff --git a/drivers/net/dm9000.h b/drivers/net/dm9000.h
index 80817c2edfb3..fb1c924d79b4 100644
--- a/drivers/net/dm9000.h
+++ b/drivers/net/dm9000.h
@@ -50,7 +50,7 @@
#define DM9000_RCSR 0x32
#define CHIPR_DM9000A 0x19
-#define CHIPR_DM9000B 0x1B
+#define CHIPR_DM9000B 0x1A
#define DM9000_MRCMDX 0xF0
#define DM9000_MRCMD 0xF2
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 5d2f48f02251..fab9cd4a4f26 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1840,11 +1840,10 @@ static inline void e100_start_receiver(struct nic *nic, struct rx *rx)
#define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN)
static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
{
- if (!(rx->skb = netdev_alloc_skb(nic->netdev, RFD_BUF_LEN + NET_IP_ALIGN)))
+ if (!(rx->skb = netdev_alloc_skb_ip_align(nic->netdev, RFD_BUF_LEN)))
return -ENOMEM;
- /* Align, init, and map the RFD. */
- skb_reserve(rx->skb, NET_IP_ALIGN);
+ /* Init, and map the RFD. */
skb_copy_to_linear_data(rx->skb, &nic->blank_rfd, sizeof(struct rfd));
rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data,
RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 42e2b7e21c29..a5665287bd64 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -302,7 +302,6 @@ struct e1000_adapter {
/* OS defined structs */
struct net_device *netdev;
struct pci_dev *pdev;
- struct net_device_stats net_stats;
/* structs defined in e1000_hw.h */
struct e1000_hw hw;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index 490b2b7cd3ab..ffbae0a0b4f1 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -31,14 +31,22 @@
#include "e1000.h"
#include <asm/uaccess.h>
+enum {NETDEV_STATS, E1000_STATS};
+
struct e1000_stats {
char stat_string[ETH_GSTRING_LEN];
+ int type;
int sizeof_stat;
int stat_offset;
};
-#define E1000_STAT(m) FIELD_SIZEOF(struct e1000_adapter, m), \
- offsetof(struct e1000_adapter, m)
+#define E1000_STAT(m) E1000_STATS, \
+ sizeof(((struct e1000_adapter *)0)->m), \
+ offsetof(struct e1000_adapter, m)
+#define E1000_NETDEV_STAT(m) NETDEV_STATS, \
+ sizeof(((struct net_device *)0)->m), \
+ offsetof(struct net_device, m)
+
static const struct e1000_stats e1000_gstrings_stats[] = {
{ "rx_packets", E1000_STAT(stats.gprc) },
{ "tx_packets", E1000_STAT(stats.gptc) },
@@ -50,19 +58,19 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
{ "tx_multicast", E1000_STAT(stats.mptc) },
{ "rx_errors", E1000_STAT(stats.rxerrc) },
{ "tx_errors", E1000_STAT(stats.txerrc) },
- { "tx_dropped", E1000_STAT(net_stats.tx_dropped) },
+ { "tx_dropped", E1000_NETDEV_STAT(stats.tx_dropped) },
{ "multicast", E1000_STAT(stats.mprc) },
{ "collisions", E1000_STAT(stats.colc) },
{ "rx_length_errors", E1000_STAT(stats.rlerrc) },
- { "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) },
+ { "rx_over_errors", E1000_NETDEV_STAT(stats.rx_over_errors) },
{ "rx_crc_errors", E1000_STAT(stats.crcerrs) },
- { "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) },
+ { "rx_frame_errors", E1000_NETDEV_STAT(stats.rx_frame_errors) },
{ "rx_no_buffer_count", E1000_STAT(stats.rnbc) },
{ "rx_missed_errors", E1000_STAT(stats.mpc) },
{ "tx_aborted_errors", E1000_STAT(stats.ecol) },
{ "tx_carrier_errors", E1000_STAT(stats.tncrs) },
- { "tx_fifo_errors", E1000_STAT(net_stats.tx_fifo_errors) },
- { "tx_heartbeat_errors", E1000_STAT(net_stats.tx_heartbeat_errors) },
+ { "tx_fifo_errors", E1000_NETDEV_STAT(stats.tx_fifo_errors) },
+ { "tx_heartbeat_errors", E1000_NETDEV_STAT(stats.tx_heartbeat_errors) },
{ "tx_window_errors", E1000_STAT(stats.latecol) },
{ "tx_abort_late_coll", E1000_STAT(stats.latecol) },
{ "tx_deferred_ok", E1000_STAT(stats.dc) },
@@ -1830,10 +1838,21 @@ static void e1000_get_ethtool_stats(struct net_device *netdev,
{
struct e1000_adapter *adapter = netdev_priv(netdev);
int i;
+ char *p = NULL;
e1000_update_stats(adapter);
for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
- char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset;
+ switch (e1000_gstrings_stats[i].type) {
+ case NETDEV_STATS:
+ p = (char *) netdev +
+ e1000_gstrings_stats[i].stat_offset;
+ break;
+ case E1000_STATS:
+ p = (char *) adapter +
+ e1000_gstrings_stats[i].stat_offset;
+ break;
+ }
+
data[i] = (e1000_gstrings_stats[i].sizeof_stat ==
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
}
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index bcd192ca47b0..c938114a34ab 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -3101,10 +3101,8 @@ static void e1000_reset_task(struct work_struct *work)
static struct net_device_stats *e1000_get_stats(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev_priv(netdev);
-
/* only return the current stats */
- return &adapter->net_stats;
+ return &netdev->stats;
}
/**
@@ -3196,6 +3194,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
void e1000_update_stats(struct e1000_adapter *adapter)
{
+ struct net_device *netdev = adapter->netdev;
struct e1000_hw *hw = &adapter->hw;
struct pci_dev *pdev = adapter->pdev;
unsigned long flags;
@@ -3288,32 +3287,32 @@ void e1000_update_stats(struct e1000_adapter *adapter)
}
/* Fill out the OS statistics structure */
- adapter->net_stats.multicast = adapter->stats.mprc;
- adapter->net_stats.collisions = adapter->stats.colc;
+ netdev->stats.multicast = adapter->stats.mprc;
+ netdev->stats.collisions = adapter->stats.colc;
/* Rx Errors */
/* RLEC on some newer hardware can be incorrect so build
* our own version based on RUC and ROC */
- adapter->net_stats.rx_errors = adapter->stats.rxerrc +
+ netdev->stats.rx_errors = adapter->stats.rxerrc +
adapter->stats.crcerrs + adapter->stats.algnerrc +
adapter->stats.ruc + adapter->stats.roc +
adapter->stats.cexterr;
adapter->stats.rlerrc = adapter->stats.ruc + adapter->stats.roc;
- adapter->net_stats.rx_length_errors = adapter->stats.rlerrc;
- adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
- adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc;
- adapter->net_stats.rx_missed_errors = adapter->stats.mpc;
+ netdev->stats.rx_length_errors = adapter->stats.rlerrc;
+ netdev->stats.rx_crc_errors = adapter->stats.crcerrs;
+ netdev->stats.rx_frame_errors = adapter->stats.algnerrc;
+ netdev->stats.rx_missed_errors = adapter->stats.mpc;
/* Tx Errors */
adapter->stats.txerrc = adapter->stats.ecol + adapter->stats.latecol;
- adapter->net_stats.tx_errors = adapter->stats.txerrc;
- adapter->net_stats.tx_aborted_errors = adapter->stats.ecol;
- adapter->net_stats.tx_window_errors = adapter->stats.latecol;
- adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs;
+ netdev->stats.tx_errors = adapter->stats.txerrc;
+ netdev->stats.tx_aborted_errors = adapter->stats.ecol;
+ netdev->stats.tx_window_errors = adapter->stats.latecol;
+ netdev->stats.tx_carrier_errors = adapter->stats.tncrs;
if (hw->bad_tx_carr_stats_fd &&
adapter->link_duplex == FULL_DUPLEX) {
- adapter->net_stats.tx_carrier_errors = 0;
+ netdev->stats.tx_carrier_errors = 0;
adapter->stats.tncrs = 0;
}
@@ -3514,8 +3513,8 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
}
adapter->total_tx_bytes += total_tx_bytes;
adapter->total_tx_packets += total_tx_packets;
- adapter->net_stats.tx_bytes += total_tx_bytes;
- adapter->net_stats.tx_packets += total_tx_packets;
+ netdev->stats.tx_bytes += total_tx_bytes;
+ netdev->stats.tx_packets += total_tx_packets;
return (count < tx_ring->count);
}
@@ -3767,8 +3766,8 @@ next_desc:
adapter->total_rx_packets += total_rx_packets;
adapter->total_rx_bytes += total_rx_bytes;
- adapter->net_stats.rx_bytes += total_rx_bytes;
- adapter->net_stats.rx_packets += total_rx_packets;
+ netdev->stats.rx_bytes += total_rx_bytes;
+ netdev->stats.rx_packets += total_rx_packets;
return cleaned;
}
@@ -3867,9 +3866,8 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
* of reassembly being done in the stack */
if (length < copybreak) {
struct sk_buff *new_skb =
- netdev_alloc_skb(netdev, length + NET_IP_ALIGN);
+ netdev_alloc_skb_ip_align(netdev, length);
if (new_skb) {
- skb_reserve(new_skb, NET_IP_ALIGN);
skb_copy_to_linear_data_offset(new_skb,
-NET_IP_ALIGN,
(skb->data -
@@ -3916,8 +3914,8 @@ next_desc:
adapter->total_rx_packets += total_rx_packets;
adapter->total_rx_bytes += total_rx_bytes;
- adapter->net_stats.rx_bytes += total_rx_bytes;
- adapter->net_stats.rx_packets += total_rx_packets;
+ netdev->stats.rx_bytes += total_rx_bytes;
+ netdev->stats.rx_packets += total_rx_packets;
return cleaned;
}
@@ -3938,9 +3936,7 @@ e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
struct e1000_buffer *buffer_info;
struct sk_buff *skb;
unsigned int i;
- unsigned int bufsz = 256 -
- 16 /*for skb_reserve */ -
- NET_IP_ALIGN;
+ unsigned int bufsz = 256 - 16 /*for skb_reserve */ ;
i = rx_ring->next_to_use;
buffer_info = &rx_ring->buffer_info[i];
@@ -3952,7 +3948,7 @@ e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
goto check_page;
}
- skb = netdev_alloc_skb(netdev, bufsz);
+ skb = netdev_alloc_skb_ip_align(netdev, bufsz);
if (unlikely(!skb)) {
/* Better luck next round */
adapter->alloc_rx_buff_failed++;
@@ -3965,7 +3961,7 @@ e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
DPRINTK(PROBE, ERR, "skb align check failed: %u bytes "
"at %p\n", bufsz, skb->data);
/* Try again, without freeing the previous */
- skb = netdev_alloc_skb(netdev, bufsz);
+ skb = netdev_alloc_skb_ip_align(netdev, bufsz);
/* Failed allocation, critical failure */
if (!skb) {
dev_kfree_skb(oldskb);
@@ -3983,12 +3979,6 @@ e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
/* Use new allocation */
dev_kfree_skb(oldskb);
}
- /* Make buffer alignment 2 beyond a 16 byte boundary
- * this will result in a 16 byte aligned IP header after
- * the 14 byte MAC header is removed
- */
- skb_reserve(skb, NET_IP_ALIGN);
-
buffer_info->skb = skb;
buffer_info->length = adapter->rx_buffer_len;
check_page:
@@ -4045,7 +4035,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
struct e1000_buffer *buffer_info;
struct sk_buff *skb;
unsigned int i;
- unsigned int bufsz = adapter->rx_buffer_len + NET_IP_ALIGN;
+ unsigned int bufsz = adapter->rx_buffer_len;
i = rx_ring->next_to_use;
buffer_info = &rx_ring->buffer_info[i];
@@ -4057,7 +4047,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
goto map_skb;
}
- skb = netdev_alloc_skb(netdev, bufsz);
+ skb = netdev_alloc_skb_ip_align(netdev, bufsz);
if (unlikely(!skb)) {
/* Better luck next round */
adapter->alloc_rx_buff_failed++;
@@ -4070,7 +4060,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
DPRINTK(RX_ERR, ERR, "skb align check failed: %u bytes "
"at %p\n", bufsz, skb->data);
/* Try again, without freeing the previous */
- skb = netdev_alloc_skb(netdev, bufsz);
+ skb = netdev_alloc_skb_ip_align(netdev, bufsz);
/* Failed allocation, critical failure */
if (!skb) {
dev_kfree_skb(oldskb);
@@ -4089,12 +4079,6 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
/* Use new allocation */
dev_kfree_skb(oldskb);
}
- /* Make buffer alignment 2 beyond a 16 byte boundary
- * this will result in a 16 byte aligned IP header after
- * the 14 byte MAC header is removed
- */
- skb_reserve(skb, NET_IP_ALIGN);
-
buffer_info->skb = skb;
buffer_info->length = adapter->rx_buffer_len;
map_skb:
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index 981936c1fb46..08a4f9dd20e9 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -315,7 +315,6 @@ struct e1000_adapter {
/* OS defined structs */
struct net_device *netdev;
struct pci_dev *pdev;
- struct net_device_stats net_stats;
/* structs defined in e1000_hw.h */
struct e1000_hw hw;
@@ -519,9 +518,13 @@ extern s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw);
extern s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw);
extern s32 e1000e_get_phy_info_igp(struct e1000_hw *hw);
extern s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000e_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset,
+ u16 *data);
extern s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw);
extern s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active);
extern s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
+extern s32 e1000e_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset,
+ u16 data);
extern s32 e1000e_phy_sw_reset(struct e1000_hw *hw);
extern s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw);
extern s32 e1000e_get_cfg_done(struct e1000_hw *hw);
@@ -538,7 +541,11 @@ extern s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data);
extern s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data);
extern void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
extern s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
+extern s32 e1000e_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset,
+ u16 data);
extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000e_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset,
+ u16 *data);
extern s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
u32 usec_interval, bool *success);
extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw);
@@ -546,7 +553,11 @@ extern s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
extern s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
extern s32 e1000e_check_downshift(struct e1000_hw *hw);
extern s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000_read_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset,
+ u16 *data);
extern s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data);
+extern s32 e1000_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset,
+ u16 data);
extern s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow);
extern s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw);
extern s32 e1000_copper_link_setup_82577(struct e1000_hw *hw);
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index 1bf4d2a5d34f..a70999b8c6cf 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -35,14 +35,22 @@
#include "e1000.h"
+enum {NETDEV_STATS, E1000_STATS};
+
struct e1000_stats {
char stat_string[ETH_GSTRING_LEN];
+ int type;
int sizeof_stat;
int stat_offset;
};
-#define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \
- offsetof(struct e1000_adapter, m)
+#define E1000_STAT(m) E1000_STATS, \
+ sizeof(((struct e1000_adapter *)0)->m), \
+ offsetof(struct e1000_adapter, m)
+#define E1000_NETDEV_STAT(m) NETDEV_STATS, \
+ sizeof(((struct net_device *)0)->m), \
+ offsetof(struct net_device, m)
+
static const struct e1000_stats e1000_gstrings_stats[] = {
{ "rx_packets", E1000_STAT(stats.gprc) },
{ "tx_packets", E1000_STAT(stats.gptc) },
@@ -52,21 +60,21 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
{ "tx_broadcast", E1000_STAT(stats.bptc) },
{ "rx_multicast", E1000_STAT(stats.mprc) },
{ "tx_multicast", E1000_STAT(stats.mptc) },
- { "rx_errors", E1000_STAT(net_stats.rx_errors) },
- { "tx_errors", E1000_STAT(net_stats.tx_errors) },
- { "tx_dropped", E1000_STAT(net_stats.tx_dropped) },
+ { "rx_errors", E1000_NETDEV_STAT(stats.rx_errors) },
+ { "tx_errors", E1000_NETDEV_STAT(stats.tx_errors) },
+ { "tx_dropped", E1000_NETDEV_STAT(stats.tx_dropped) },
{ "multicast", E1000_STAT(stats.mprc) },
{ "collisions", E1000_STAT(stats.colc) },
- { "rx_length_errors", E1000_STAT(net_stats.rx_length_errors) },
- { "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) },
+ { "rx_length_errors", E1000_NETDEV_STAT(stats.rx_length_errors) },
+ { "rx_over_errors", E1000_NETDEV_STAT(stats.rx_over_errors) },
{ "rx_crc_errors", E1000_STAT(stats.crcerrs) },
- { "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) },
+ { "rx_frame_errors", E1000_NETDEV_STAT(stats.rx_frame_errors) },
{ "rx_no_buffer_count", E1000_STAT(stats.rnbc) },
{ "rx_missed_errors", E1000_STAT(stats.mpc) },
{ "tx_aborted_errors", E1000_STAT(stats.ecol) },
{ "tx_carrier_errors", E1000_STAT(stats.tncrs) },
- { "tx_fifo_errors", E1000_STAT(net_stats.tx_fifo_errors) },
- { "tx_heartbeat_errors", E1000_STAT(net_stats.tx_heartbeat_errors) },
+ { "tx_fifo_errors", E1000_NETDEV_STAT(stats.tx_fifo_errors) },
+ { "tx_heartbeat_errors", E1000_NETDEV_STAT(stats.tx_heartbeat_errors) },
{ "tx_window_errors", E1000_STAT(stats.latecol) },
{ "tx_abort_late_coll", E1000_STAT(stats.latecol) },
{ "tx_deferred_ok", E1000_STAT(stats.dc) },
@@ -1904,10 +1912,21 @@ static void e1000_get_ethtool_stats(struct net_device *netdev,
{
struct e1000_adapter *adapter = netdev_priv(netdev);
int i;
+ char *p = NULL;
e1000e_update_stats(adapter);
for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
- char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset;
+ switch (e1000_gstrings_stats[i].type) {
+ case NETDEV_STATS:
+ p = (char *) netdev +
+ e1000_gstrings_stats[i].stat_offset;
+ break;
+ case E1000_STATS:
+ p = (char *) adapter +
+ e1000_gstrings_stats[i].stat_offset;
+ break;
+ }
+
data[i] = (e1000_gstrings_stats[i].sizeof_stat ==
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
}
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h
index fd44d9f90769..7b05cf47f7f5 100644
--- a/drivers/net/e1000e/hw.h
+++ b/drivers/net/e1000e/hw.h
@@ -764,11 +764,13 @@ struct e1000_phy_operations {
s32 (*get_cable_length)(struct e1000_hw *);
s32 (*get_phy_info)(struct e1000_hw *);
s32 (*read_phy_reg)(struct e1000_hw *, u32, u16 *);
+ s32 (*read_phy_reg_locked)(struct e1000_hw *, u32, u16 *);
void (*release_phy)(struct e1000_hw *);
s32 (*reset_phy)(struct e1000_hw *);
s32 (*set_d0_lplu_state)(struct e1000_hw *, bool);
s32 (*set_d3_lplu_state)(struct e1000_hw *, bool);
s32 (*write_phy_reg)(struct e1000_hw *, u32, u16);
+ s32 (*write_phy_reg_locked)(struct e1000_hw *, u32, u16);
s32 (*cfg_on_link_up)(struct e1000_hw *);
};
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
index 99df2abf82a9..b6388b9535fd 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/e1000e/ich8lan.c
@@ -122,6 +122,13 @@
#define HV_LED_CONFIG PHY_REG(768, 30) /* LED Configuration */
+#define SW_FLAG_TIMEOUT 1000 /* SW Semaphore flag timeout in milliseconds */
+
+/* OEM Bits Phy Register */
+#define HV_OEM_BITS PHY_REG(768, 25)
+#define HV_OEM_BITS_LPLU 0x0004 /* Low Power Link Up */
+#define HV_OEM_BITS_RESTART_AN 0x0400 /* Restart Auto-negotiation */
+
/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
/* Offset 04h HSFSTS */
union ich8_hws_flash_status {
@@ -200,6 +207,7 @@ static s32 e1000_setup_led_pchlan(struct e1000_hw *hw);
static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw);
static s32 e1000_led_on_pchlan(struct e1000_hw *hw);
static s32 e1000_led_off_pchlan(struct e1000_hw *hw);
+static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active);
static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
{
@@ -242,7 +250,11 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
phy->ops.check_polarity = e1000_check_polarity_ife_ich8lan;
phy->ops.read_phy_reg = e1000_read_phy_reg_hv;
+ phy->ops.read_phy_reg_locked = e1000_read_phy_reg_hv_locked;
+ phy->ops.set_d0_lplu_state = e1000_set_lplu_state_pchlan;
+ phy->ops.set_d3_lplu_state = e1000_set_lplu_state_pchlan;
phy->ops.write_phy_reg = e1000_write_phy_reg_hv;
+ phy->ops.write_phy_reg_locked = e1000_write_phy_reg_hv_locked;
phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
phy->id = e1000_phy_unknown;
@@ -303,6 +315,8 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
case IGP03E1000_E_PHY_ID:
phy->type = e1000_phy_igp_3;
phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ phy->ops.read_phy_reg_locked = e1000e_read_phy_reg_igp_locked;
+ phy->ops.write_phy_reg_locked = e1000e_write_phy_reg_igp_locked;
break;
case IFE_E_PHY_ID:
case IFE_PLUS_E_PHY_ID:
@@ -568,12 +582,39 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
static DEFINE_MUTEX(nvm_mutex);
/**
+ * e1000_acquire_nvm_ich8lan - Acquire NVM mutex
+ * @hw: pointer to the HW structure
+ *
+ * Acquires the mutex for performing NVM operations.
+ **/
+static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw)
+{
+ mutex_lock(&nvm_mutex);
+
+ return 0;
+}
+
+/**
+ * e1000_release_nvm_ich8lan - Release NVM mutex
+ * @hw: pointer to the HW structure
+ *
+ * Releases the mutex used while performing NVM operations.
+ **/
+static void e1000_release_nvm_ich8lan(struct e1000_hw *hw)
+{
+ mutex_unlock(&nvm_mutex);
+
+ return;
+}
+
+static DEFINE_MUTEX(swflag_mutex);
+
+/**
* e1000_acquire_swflag_ich8lan - Acquire software control flag
* @hw: pointer to the HW structure
*
- * Acquires the software control flag for performing NVM and PHY
- * operations. This is a function pointer entry point only called by
- * read/write routines for the PHY and NVM parts.
+ * Acquires the software control flag for performing PHY and select
+ * MAC CSR accesses.
**/
static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
{
@@ -582,7 +623,7 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
might_sleep();
- mutex_lock(&nvm_mutex);
+ mutex_lock(&swflag_mutex);
while (timeout) {
extcnf_ctrl = er32(EXTCNF_CTRL);
@@ -599,7 +640,7 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
goto out;
}
- timeout = PHY_CFG_TIMEOUT * 2;
+ timeout = SW_FLAG_TIMEOUT;
extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
ew32(EXTCNF_CTRL, extcnf_ctrl);
@@ -623,7 +664,7 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
out:
if (ret_val)
- mutex_unlock(&nvm_mutex);
+ mutex_unlock(&swflag_mutex);
return ret_val;
}
@@ -632,9 +673,8 @@ out:
* e1000_release_swflag_ich8lan - Release software control flag
* @hw: pointer to the HW structure
*
- * Releases the software control flag for performing NVM and PHY operations.
- * This is a function pointer entry point only called by read/write
- * routines for the PHY and NVM parts.
+ * Releases the software control flag for performing PHY and select
+ * MAC CSR accesses.
**/
static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
{
@@ -644,7 +684,9 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
ew32(EXTCNF_CTRL, extcnf_ctrl);
- mutex_unlock(&nvm_mutex);
+ mutex_unlock(&swflag_mutex);
+
+ return;
}
/**
@@ -844,7 +886,7 @@ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
u32 i;
u32 data, cnf_size, cnf_base_addr, sw_cfg_mask;
s32 ret_val;
- u16 word_addr, reg_data, reg_addr, phy_page = 0;
+ u16 reg, word_addr, reg_data, reg_addr, phy_page = 0;
ret_val = e1000e_phy_hw_reset_generic(hw);
if (ret_val)
@@ -859,6 +901,10 @@ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
return ret_val;
}
+ /* Dummy read to clear the phy wakeup bit after lcd reset */
+ if (hw->mac.type == e1000_pchlan)
+ e1e_rphy(hw, BM_WUC, &reg);
+
/*
* Initialize the PHY from the NVM on ICH platforms. This
* is needed due to an issue where the NVM configuration is
@@ -1054,6 +1100,38 @@ static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw)
}
/**
+ * e1000_set_lplu_state_pchlan - Set Low Power Link Up state
+ * @hw: pointer to the HW structure
+ * @active: true to enable LPLU, false to disable
+ *
+ * Sets the LPLU state according to the active flag. For PCH, if OEM write
+ * bit are disabled in the NVM, writing the LPLU bits in the MAC will not set
+ * the phy speed. This function will manually set the LPLU bit and restart
+ * auto-neg as hw would do. D3 and D0 LPLU will call the same function
+ * since it configures the same bit.
+ **/
+static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active)
+{
+ s32 ret_val = 0;
+ u16 oem_reg;
+
+ ret_val = e1e_rphy(hw, HV_OEM_BITS, &oem_reg);
+ if (ret_val)
+ goto out;
+
+ if (active)
+ oem_reg |= HV_OEM_BITS_LPLU;
+ else
+ oem_reg &= ~HV_OEM_BITS_LPLU;
+
+ oem_reg |= HV_OEM_BITS_RESTART_AN;
+ ret_val = e1e_wphy(hw, HV_OEM_BITS, oem_reg);
+
+out:
+ return ret_val;
+}
+
+/**
* e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
* @hw: pointer to the HW structure
* @active: TRUE to enable LPLU, FALSE to disable
@@ -1314,12 +1392,11 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
(words == 0)) {
hw_dbg(hw, "nvm parameter(s) out of bounds\n");
- return -E1000_ERR_NVM;
+ ret_val = -E1000_ERR_NVM;
+ goto out;
}
- ret_val = e1000_acquire_swflag_ich8lan(hw);
- if (ret_val)
- goto out;
+ nvm->ops.acquire_nvm(hw);
ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
if (ret_val) {
@@ -1345,7 +1422,7 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
}
}
- e1000_release_swflag_ich8lan(hw);
+ nvm->ops.release_nvm(hw);
out:
if (ret_val)
@@ -1603,11 +1680,15 @@ static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
return -E1000_ERR_NVM;
}
+ nvm->ops.acquire_nvm(hw);
+
for (i = 0; i < words; i++) {
dev_spec->shadow_ram[offset+i].modified = 1;
dev_spec->shadow_ram[offset+i].value = data[i];
}
+ nvm->ops.release_nvm(hw);
+
return 0;
}
@@ -1637,9 +1718,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
if (nvm->type != e1000_nvm_flash_sw)
goto out;
- ret_val = e1000_acquire_swflag_ich8lan(hw);
- if (ret_val)
- goto out;
+ nvm->ops.acquire_nvm(hw);
/*
* We're writing to the opposite bank so if we're on bank 1,
@@ -1657,7 +1736,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
old_bank_offset = 0;
ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
if (ret_val) {
- e1000_release_swflag_ich8lan(hw);
+ nvm->ops.release_nvm(hw);
goto out;
}
} else {
@@ -1665,7 +1744,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
new_bank_offset = 0;
ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
if (ret_val) {
- e1000_release_swflag_ich8lan(hw);
+ nvm->ops.release_nvm(hw);
goto out;
}
}
@@ -1723,7 +1802,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
if (ret_val) {
/* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */
hw_dbg(hw, "Flash commit failed.\n");
- e1000_release_swflag_ich8lan(hw);
+ nvm->ops.release_nvm(hw);
goto out;
}
@@ -1736,7 +1815,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data);
if (ret_val) {
- e1000_release_swflag_ich8lan(hw);
+ nvm->ops.release_nvm(hw);
goto out;
}
data &= 0xBFFF;
@@ -1744,7 +1823,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
act_offset * 2 + 1,
(u8)(data >> 8));
if (ret_val) {
- e1000_release_swflag_ich8lan(hw);
+ nvm->ops.release_nvm(hw);
goto out;
}
@@ -1757,7 +1836,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
if (ret_val) {
- e1000_release_swflag_ich8lan(hw);
+ nvm->ops.release_nvm(hw);
goto out;
}
@@ -1767,7 +1846,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
dev_spec->shadow_ram[i].value = 0xFFFF;
}
- e1000_release_swflag_ich8lan(hw);
+ nvm->ops.release_nvm(hw);
/*
* Reload the EEPROM, or else modifications will not appear
@@ -1831,14 +1910,12 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
**/
void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw)
{
+ struct e1000_nvm_info *nvm = &hw->nvm;
union ich8_flash_protected_range pr0;
union ich8_hws_flash_status hsfsts;
u32 gfpreg;
- s32 ret_val;
- ret_val = e1000_acquire_swflag_ich8lan(hw);
- if (ret_val)
- return;
+ nvm->ops.acquire_nvm(hw);
gfpreg = er32flash(ICH_FLASH_GFPREG);
@@ -1859,7 +1936,7 @@ void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw)
hsfsts.hsf_status.flockdn = true;
ew32flash(ICH_FLASH_HSFSTS, hsfsts.regval);
- e1000_release_swflag_ich8lan(hw);
+ nvm->ops.release_nvm(hw);
}
/**
@@ -2229,6 +2306,7 @@ static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
**/
static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
{
+ u16 reg;
u32 ctrl, icr, kab;
s32 ret_val;
@@ -2304,6 +2382,9 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
hw_dbg(hw, "Auto Read Done did not complete\n");
}
}
+ /* Dummy read to clear the phy wakeup bit after lcd reset */
+ if (hw->mac.type == e1000_pchlan)
+ e1e_rphy(hw, BM_WUC, &reg);
/*
* For PCH, this write will make sure that any noise
@@ -2843,9 +2924,8 @@ void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw)
E1000_PHY_CTRL_GBE_DISABLE;
ew32(PHY_CTRL, phy_ctrl);
- /* Workaround SWFLAG unexpectedly set during S0->Sx */
if (hw->mac.type == e1000_pchlan)
- udelay(500);
+ e1000_phy_hw_reset_ich8lan(hw);
default:
break;
}
@@ -3113,9 +3193,9 @@ static struct e1000_phy_operations ich8_phy_ops = {
};
static struct e1000_nvm_operations ich8_nvm_ops = {
- .acquire_nvm = e1000_acquire_swflag_ich8lan,
+ .acquire_nvm = e1000_acquire_nvm_ich8lan,
.read_nvm = e1000_read_nvm_ich8lan,
- .release_nvm = e1000_release_swflag_ich8lan,
+ .release_nvm = e1000_release_nvm_ich8lan,
.update_nvm = e1000_update_nvm_checksum_ich8lan,
.valid_led_default = e1000_valid_led_default_ich8lan,
.validate_nvm = e1000_validate_nvm_checksum_ich8lan,
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 0687c6aa4e46..376924804f3f 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -167,7 +167,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
struct e1000_buffer *buffer_info;
struct sk_buff *skb;
unsigned int i;
- unsigned int bufsz = adapter->rx_buffer_len + NET_IP_ALIGN;
+ unsigned int bufsz = adapter->rx_buffer_len;
i = rx_ring->next_to_use;
buffer_info = &rx_ring->buffer_info[i];
@@ -179,20 +179,13 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
goto map_skb;
}
- skb = netdev_alloc_skb(netdev, bufsz);
+ skb = netdev_alloc_skb_ip_align(netdev, bufsz);
if (!skb) {
/* Better luck next round */
adapter->alloc_rx_buff_failed++;
break;
}
- /*
- * Make buffer alignment 2 beyond a 16 byte boundary
- * this will result in a 16 byte aligned IP header after
- * the 14 byte MAC header is removed
- */
- skb_reserve(skb, NET_IP_ALIGN);
-
buffer_info->skb = skb;
map_skb:
buffer_info->dma = pci_map_single(pdev, skb->data,
@@ -284,21 +277,14 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
cpu_to_le64(ps_page->dma);
}
- skb = netdev_alloc_skb(netdev,
- adapter->rx_ps_bsize0 + NET_IP_ALIGN);
+ skb = netdev_alloc_skb_ip_align(netdev,
+ adapter->rx_ps_bsize0);
if (!skb) {
adapter->alloc_rx_buff_failed++;
break;
}
- /*
- * Make buffer alignment 2 beyond a 16 byte boundary
- * this will result in a 16 byte aligned IP header after
- * the 14 byte MAC header is removed
- */
- skb_reserve(skb, NET_IP_ALIGN);
-
buffer_info->skb = skb;
buffer_info->dma = pci_map_single(pdev, skb->data,
adapter->rx_ps_bsize0,
@@ -359,9 +345,7 @@ static void e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
struct e1000_buffer *buffer_info;
struct sk_buff *skb;
unsigned int i;
- unsigned int bufsz = 256 -
- 16 /* for skb_reserve */ -
- NET_IP_ALIGN;
+ unsigned int bufsz = 256 - 16 /* for skb_reserve */;
i = rx_ring->next_to_use;
buffer_info = &rx_ring->buffer_info[i];
@@ -373,19 +357,13 @@ static void e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
goto check_page;
}
- skb = netdev_alloc_skb(netdev, bufsz);
+ skb = netdev_alloc_skb_ip_align(netdev, bufsz);
if (unlikely(!skb)) {
/* Better luck next round */
adapter->alloc_rx_buff_failed++;
break;
}
- /* Make buffer alignment 2 beyond a 16 byte boundary
- * this will result in a 16 byte aligned IP header after
- * the 14 byte MAC header is removed
- */
- skb_reserve(skb, NET_IP_ALIGN);
-
buffer_info->skb = skb;
check_page:
/* allocate a new page if necessary */
@@ -513,9 +491,8 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
*/
if (length < copybreak) {
struct sk_buff *new_skb =
- netdev_alloc_skb(netdev, length + NET_IP_ALIGN);
+ netdev_alloc_skb_ip_align(netdev, length);
if (new_skb) {
- skb_reserve(new_skb, NET_IP_ALIGN);
skb_copy_to_linear_data_offset(new_skb,
-NET_IP_ALIGN,
(skb->data -
@@ -560,8 +537,8 @@ next_desc:
adapter->total_rx_bytes += total_rx_bytes;
adapter->total_rx_packets += total_rx_packets;
- adapter->net_stats.rx_bytes += total_rx_bytes;
- adapter->net_stats.rx_packets += total_rx_packets;
+ netdev->stats.rx_bytes += total_rx_bytes;
+ netdev->stats.rx_packets += total_rx_packets;
return cleaned;
}
@@ -690,8 +667,8 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)
}
adapter->total_tx_bytes += total_tx_bytes;
adapter->total_tx_packets += total_tx_packets;
- adapter->net_stats.tx_bytes += total_tx_bytes;
- adapter->net_stats.tx_packets += total_tx_packets;
+ netdev->stats.tx_bytes += total_tx_bytes;
+ netdev->stats.tx_packets += total_tx_packets;
return (count < tx_ring->count);
}
@@ -871,8 +848,8 @@ next_desc:
adapter->total_rx_bytes += total_rx_bytes;
adapter->total_rx_packets += total_rx_packets;
- adapter->net_stats.rx_bytes += total_rx_bytes;
- adapter->net_stats.rx_packets += total_rx_packets;
+ netdev->stats.rx_bytes += total_rx_bytes;
+ netdev->stats.rx_packets += total_rx_packets;
return cleaned;
}
@@ -1051,8 +1028,8 @@ next_desc:
adapter->total_rx_bytes += total_rx_bytes;
adapter->total_rx_packets += total_rx_packets;
- adapter->net_stats.rx_bytes += total_rx_bytes;
- adapter->net_stats.rx_packets += total_rx_packets;
+ netdev->stats.rx_bytes += total_rx_bytes;
+ netdev->stats.rx_packets += total_rx_packets;
return cleaned;
}
@@ -3287,6 +3264,7 @@ static void e1000_update_phy_info(unsigned long data)
**/
void e1000e_update_stats(struct e1000_adapter *adapter)
{
+ struct net_device *netdev = adapter->netdev;
struct e1000_hw *hw = &adapter->hw;
struct pci_dev *pdev = adapter->pdev;
u16 phy_data;
@@ -3381,8 +3359,8 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
adapter->stats.tsctfc += er32(TSCTFC);
/* Fill out the OS statistics structure */
- adapter->net_stats.multicast = adapter->stats.mprc;
- adapter->net_stats.collisions = adapter->stats.colc;
+ netdev->stats.multicast = adapter->stats.mprc;
+ netdev->stats.collisions = adapter->stats.colc;
/* Rx Errors */
@@ -3390,22 +3368,22 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
* RLEC on some newer hardware can be incorrect so build
* our own version based on RUC and ROC
*/
- adapter->net_stats.rx_errors = adapter->stats.rxerrc +
+ netdev->stats.rx_errors = adapter->stats.rxerrc +
adapter->stats.crcerrs + adapter->stats.algnerrc +
adapter->stats.ruc + adapter->stats.roc +
adapter->stats.cexterr;
- adapter->net_stats.rx_length_errors = adapter->stats.ruc +
+ netdev->stats.rx_length_errors = adapter->stats.ruc +
adapter->stats.roc;
- adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
- adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc;
- adapter->net_stats.rx_missed_errors = adapter->stats.mpc;
+ netdev->stats.rx_crc_errors = adapter->stats.crcerrs;
+ netdev->stats.rx_frame_errors = adapter->stats.algnerrc;
+ netdev->stats.rx_missed_errors = adapter->stats.mpc;
/* Tx Errors */
- adapter->net_stats.tx_errors = adapter->stats.ecol +
+ netdev->stats.tx_errors = adapter->stats.ecol +
adapter->stats.latecol;
- adapter->net_stats.tx_aborted_errors = adapter->stats.ecol;
- adapter->net_stats.tx_window_errors = adapter->stats.latecol;
- adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs;
+ netdev->stats.tx_aborted_errors = adapter->stats.ecol;
+ netdev->stats.tx_window_errors = adapter->stats.latecol;
+ netdev->stats.tx_carrier_errors = adapter->stats.tncrs;
/* Tx Dropped needs to be maintained elsewhere */
@@ -4254,10 +4232,8 @@ static void e1000_reset_task(struct work_struct *work)
**/
static struct net_device_stats *e1000_get_stats(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev_priv(netdev);
-
/* only return the current stats */
- return &adapter->net_stats;
+ return &netdev->stats;
}
/**
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c
index 994401fd0664..f9d33ab05e97 100644
--- a/drivers/net/e1000e/phy.c
+++ b/drivers/net/e1000e/phy.c
@@ -164,16 +164,25 @@ s32 e1000e_get_phy_id(struct e1000_hw *hw)
* MDIC mode. No harm in trying again in this case since
* the PHY ID is unknown at this point anyway
*/
+ ret_val = phy->ops.acquire_phy(hw);
+ if (ret_val)
+ goto out;
ret_val = e1000_set_mdio_slow_mode_hv(hw, true);
if (ret_val)
goto out;
+ phy->ops.release_phy(hw);
retry_count++;
}
out:
/* Revert to MDIO fast mode, if applicable */
- if (retry_count)
+ if (retry_count) {
+ ret_val = phy->ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
ret_val = e1000_set_mdio_slow_mode_hv(hw, false);
+ phy->ops.release_phy(hw);
+ }
return ret_val;
}
@@ -354,94 +363,173 @@ s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data)
}
/**
- * e1000e_read_phy_reg_igp - Read igp PHY register
+ * __e1000e_read_phy_reg_igp - Read igp PHY register
* @hw: pointer to the HW structure
* @offset: register offset to be read
* @data: pointer to the read data
+ * @locked: semaphore has already been acquired or not
*
* Acquires semaphore, if necessary, then reads the PHY register at offset
- * and storing the retrieved information in data. Release any acquired
+ * and stores the retrieved information in data. Release any acquired
* semaphores before exiting.
**/
-s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
+static s32 __e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data,
+ bool locked)
{
- s32 ret_val;
+ s32 ret_val = 0;
- ret_val = hw->phy.ops.acquire_phy(hw);
- if (ret_val)
- return ret_val;
+ if (!locked) {
+ if (!(hw->phy.ops.acquire_phy))
+ goto out;
+
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ goto out;
+ }
if (offset > MAX_PHY_MULTI_PAGE_REG) {
ret_val = e1000e_write_phy_reg_mdic(hw,
IGP01E1000_PHY_PAGE_SELECT,
(u16)offset);
- if (ret_val) {
- hw->phy.ops.release_phy(hw);
- return ret_val;
- }
+ if (ret_val)
+ goto release;
}
ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
- data);
-
- hw->phy.ops.release_phy(hw);
+ data);
+release:
+ if (!locked)
+ hw->phy.ops.release_phy(hw);
+out:
return ret_val;
}
/**
+ * e1000e_read_phy_reg_igp - Read igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore then reads the PHY register at offset and stores the
+ * retrieved information in data.
+ * Release the acquired semaphore before exiting.
+ **/
+s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ return __e1000e_read_phy_reg_igp(hw, offset, data, false);
+}
+
+/**
+ * e1000e_read_phy_reg_igp_locked - Read igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the PHY register at offset and stores the retrieved information
+ * in data. Assumes semaphore already acquired.
+ **/
+s32 e1000e_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ return __e1000e_read_phy_reg_igp(hw, offset, data, true);
+}
+
+/**
* e1000e_write_phy_reg_igp - Write igp PHY register
* @hw: pointer to the HW structure
* @offset: register offset to write to
* @data: data to write at register offset
+ * @locked: semaphore has already been acquired or not
*
* Acquires semaphore, if necessary, then writes the data to PHY register
* at the offset. Release any acquired semaphores before exiting.
**/
-s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
+static s32 __e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data,
+ bool locked)
{
- s32 ret_val;
+ s32 ret_val = 0;
- ret_val = hw->phy.ops.acquire_phy(hw);
- if (ret_val)
- return ret_val;
+ if (!locked) {
+ if (!(hw->phy.ops.acquire_phy))
+ goto out;
+
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ goto out;
+ }
if (offset > MAX_PHY_MULTI_PAGE_REG) {
ret_val = e1000e_write_phy_reg_mdic(hw,
IGP01E1000_PHY_PAGE_SELECT,
(u16)offset);
- if (ret_val) {
- hw->phy.ops.release_phy(hw);
- return ret_val;
- }
+ if (ret_val)
+ goto release;
}
ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
data);
- hw->phy.ops.release_phy(hw);
+release:
+ if (!locked)
+ hw->phy.ops.release_phy(hw);
+out:
return ret_val;
}
/**
- * e1000e_read_kmrn_reg - Read kumeran register
+ * e1000e_write_phy_reg_igp - Write igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ return __e1000e_write_phy_reg_igp(hw, offset, data, false);
+}
+
+/**
+ * e1000e_write_phy_reg_igp_locked - Write igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Writes the data to PHY register at the offset.
+ * Assumes semaphore already acquired.
+ **/
+s32 e1000e_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ return __e1000e_write_phy_reg_igp(hw, offset, data, true);
+}
+
+/**
+ * __e1000_read_kmrn_reg - Read kumeran register
* @hw: pointer to the HW structure
* @offset: register offset to be read
* @data: pointer to the read data
+ * @locked: semaphore has already been acquired or not
*
* Acquires semaphore, if necessary. Then reads the PHY register at offset
* using the kumeran interface. The information retrieved is stored in data.
* Release any acquired semaphores before exiting.
**/
-s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data)
+static s32 __e1000_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data,
+ bool locked)
{
u32 kmrnctrlsta;
- s32 ret_val;
+ s32 ret_val = 0;
- ret_val = hw->phy.ops.acquire_phy(hw);
- if (ret_val)
- return ret_val;
+ if (!locked) {
+ if (!(hw->phy.ops.acquire_phy))
+ goto out;
+
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ goto out;
+ }
kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
@@ -452,41 +540,111 @@ s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data)
kmrnctrlsta = er32(KMRNCTRLSTA);
*data = (u16)kmrnctrlsta;
- hw->phy.ops.release_phy(hw);
+ if (!locked)
+ hw->phy.ops.release_phy(hw);
+out:
return ret_val;
}
/**
- * e1000e_write_kmrn_reg - Write kumeran register
+ * e1000e_read_kmrn_reg - Read kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore then reads the PHY register at offset using the
+ * kumeran interface. The information retrieved is stored in data.
+ * Release the acquired semaphore before exiting.
+ **/
+s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ return __e1000_read_kmrn_reg(hw, offset, data, false);
+}
+
+/**
+ * e1000_read_kmrn_reg_locked - Read kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the PHY register at offset using the kumeran interface. The
+ * information retrieved is stored in data.
+ * Assumes semaphore already acquired.
+ **/
+s32 e1000_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ return __e1000_read_kmrn_reg(hw, offset, data, true);
+}
+
+/**
+ * __e1000_write_kmrn_reg - Write kumeran register
* @hw: pointer to the HW structure
* @offset: register offset to write to
* @data: data to write at register offset
+ * @locked: semaphore has already been acquired or not
*
* Acquires semaphore, if necessary. Then write the data to PHY register
* at the offset using the kumeran interface. Release any acquired semaphores
* before exiting.
**/
-s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data)
+static s32 __e1000_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data,
+ bool locked)
{
u32 kmrnctrlsta;
- s32 ret_val;
+ s32 ret_val = 0;
- ret_val = hw->phy.ops.acquire_phy(hw);
- if (ret_val)
- return ret_val;
+ if (!locked) {
+ if (!(hw->phy.ops.acquire_phy))
+ goto out;
+
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ goto out;
+ }
kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
E1000_KMRNCTRLSTA_OFFSET) | data;
ew32(KMRNCTRLSTA, kmrnctrlsta);
udelay(2);
- hw->phy.ops.release_phy(hw);
+ if (!locked)
+ hw->phy.ops.release_phy(hw);
+
+out:
return ret_val;
}
/**
+ * e1000e_write_kmrn_reg - Write kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore then writes the data to the PHY register at the offset
+ * using the kumeran interface. Release the acquired semaphore before exiting.
+ **/
+s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ return __e1000_write_kmrn_reg(hw, offset, data, false);
+}
+
+/**
+ * e1000_write_kmrn_reg_locked - Write kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Write the data to PHY register at the offset using the kumeran interface.
+ * Assumes semaphore already acquired.
+ **/
+s32 e1000_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ return __e1000_write_kmrn_reg(hw, offset, data, true);
+}
+
+/**
* e1000_copper_link_setup_82577 - Setup 82577 PHY for copper link
* @hw: pointer to the HW structure
*
@@ -2105,6 +2263,10 @@ s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data)
u32 page = offset >> IGP_PAGE_SHIFT;
u32 page_shift = 0;
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+
/* Page 800 works differently than the rest so it has its own func */
if (page == BM_WUC_PAGE) {
ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data,
@@ -2112,10 +2274,6 @@ s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data)
goto out;
}
- ret_val = hw->phy.ops.acquire_phy(hw);
- if (ret_val)
- goto out;
-
hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);
if (offset > MAX_PHY_MULTI_PAGE_REG) {
@@ -2135,18 +2293,15 @@ s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data)
/* Page is shifted left, PHY expects (page x 32) */
ret_val = e1000e_write_phy_reg_mdic(hw, page_select,
(page << page_shift));
- if (ret_val) {
- hw->phy.ops.release_phy(hw);
+ if (ret_val)
goto out;
- }
}
ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
data);
- hw->phy.ops.release_phy(hw);
-
out:
+ hw->phy.ops.release_phy(hw);
return ret_val;
}
@@ -2167,6 +2322,10 @@ s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data)
u32 page = offset >> IGP_PAGE_SHIFT;
u32 page_shift = 0;
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+
/* Page 800 works differently than the rest so it has its own func */
if (page == BM_WUC_PAGE) {
ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data,
@@ -2174,10 +2333,6 @@ s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data)
goto out;
}
- ret_val = hw->phy.ops.acquire_phy(hw);
- if (ret_val)
- goto out;
-
hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);
if (offset > MAX_PHY_MULTI_PAGE_REG) {
@@ -2197,17 +2352,14 @@ s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data)
/* Page is shifted left, PHY expects (page x 32) */
ret_val = e1000e_write_phy_reg_mdic(hw, page_select,
(page << page_shift));
- if (ret_val) {
- hw->phy.ops.release_phy(hw);
+ if (ret_val)
goto out;
- }
}
ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
data);
- hw->phy.ops.release_phy(hw);
-
out:
+ hw->phy.ops.release_phy(hw);
return ret_val;
}
@@ -2226,17 +2378,17 @@ s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data)
s32 ret_val;
u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+
/* Page 800 works differently than the rest so it has its own func */
if (page == BM_WUC_PAGE) {
ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data,
true);
- return ret_val;
+ goto out;
}
- ret_val = hw->phy.ops.acquire_phy(hw);
- if (ret_val)
- return ret_val;
-
hw->phy.addr = 1;
if (offset > MAX_PHY_MULTI_PAGE_REG) {
@@ -2245,16 +2397,14 @@ s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data)
ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
page);
- if (ret_val) {
- hw->phy.ops.release_phy(hw);
- return ret_val;
- }
+ if (ret_val)
+ goto out;
}
ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
data);
+out:
hw->phy.ops.release_phy(hw);
-
return ret_val;
}
@@ -2272,17 +2422,17 @@ s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data)
s32 ret_val;
u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+
/* Page 800 works differently than the rest so it has its own func */
if (page == BM_WUC_PAGE) {
ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data,
false);
- return ret_val;
+ goto out;
}
- ret_val = hw->phy.ops.acquire_phy(hw);
- if (ret_val)
- return ret_val;
-
hw->phy.addr = 1;
if (offset > MAX_PHY_MULTI_PAGE_REG) {
@@ -2290,17 +2440,15 @@ s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data)
ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
page);
- if (ret_val) {
- hw->phy.ops.release_phy(hw);
- return ret_val;
- }
+ if (ret_val)
+ goto out;
}
ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
data);
+out:
hw->phy.ops.release_phy(hw);
-
return ret_val;
}
@@ -2320,6 +2468,8 @@ s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data)
* 3) Write the address using the address opcode (0x11)
* 4) Read or write the data using the data opcode (0x12)
* 5) Restore 769_17.2 to its original value
+ *
+ * Assumes semaphore already acquired.
**/
static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
u16 *data, bool read)
@@ -2327,20 +2477,12 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
s32 ret_val;
u16 reg = BM_PHY_REG_NUM(offset);
u16 phy_reg = 0;
- u8 phy_acquired = 1;
-
/* Gig must be disabled for MDIO accesses to page 800 */
if ((hw->mac.type == e1000_pchlan) &&
(!(er32(PHY_CTRL) & E1000_PHY_CTRL_GBE_DISABLE)))
hw_dbg(hw, "Attempting to access page 800 while gig enabled\n");
- ret_val = hw->phy.ops.acquire_phy(hw);
- if (ret_val) {
- phy_acquired = 0;
- goto out;
- }
-
/* All operations in this function are phy address 1 */
hw->phy.addr = 1;
@@ -2397,8 +2539,6 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);
out:
- if (phy_acquired == 1)
- hw->phy.ops.release_phy(hw);
return ret_val;
}
@@ -2439,52 +2579,63 @@ static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active)
return 0;
}
+/**
+ * e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode
+ * @hw: pointer to the HW structure
+ * @slow: true for slow mode, false for normal mode
+ *
+ * Assumes semaphore already acquired.
+ **/
s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow)
{
s32 ret_val = 0;
u16 data = 0;
- ret_val = hw->phy.ops.acquire_phy(hw);
- if (ret_val)
- return ret_val;
-
/* Set MDIO mode - page 769, register 16: 0x2580==slow, 0x2180==fast */
hw->phy.addr = 1;
ret_val = e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
(BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT));
- if (ret_val) {
- hw->phy.ops.release_phy(hw);
- return ret_val;
- }
+ if (ret_val)
+ goto out;
+
ret_val = e1000e_write_phy_reg_mdic(hw, BM_CS_CTRL1,
(0x2180 | (slow << 10)));
+ if (ret_val)
+ goto out;
/* dummy read when reverting to fast mode - throw away result */
if (!slow)
- e1000e_read_phy_reg_mdic(hw, BM_CS_CTRL1, &data);
-
- hw->phy.ops.release_phy(hw);
+ ret_val = e1000e_read_phy_reg_mdic(hw, BM_CS_CTRL1, &data);
+out:
return ret_val;
}
/**
- * e1000_read_phy_reg_hv - Read HV PHY register
+ * __e1000_read_phy_reg_hv - Read HV PHY register
* @hw: pointer to the HW structure
* @offset: register offset to be read
* @data: pointer to the read data
+ * @locked: semaphore has already been acquired or not
*
* Acquires semaphore, if necessary, then reads the PHY register at offset
- * and storing the retrieved information in data. Release any acquired
+ * and stores the retrieved information in data. Release any acquired
* semaphore before exiting.
**/
-s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data)
+static s32 __e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data,
+ bool locked)
{
s32 ret_val;
u16 page = BM_PHY_REG_PAGE(offset);
u16 reg = BM_PHY_REG_NUM(offset);
bool in_slow_mode = false;
+ if (!locked) {
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
/* Workaround failure in MDIO access while cable is disconnected */
if ((hw->phy.type == e1000_phy_82577) &&
!(er32(STATUS) & E1000_STATUS_LU)) {
@@ -2508,10 +2659,6 @@ s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data)
goto out;
}
- ret_val = hw->phy.ops.acquire_phy(hw);
- if (ret_val)
- goto out;
-
hw->phy.addr = e1000_get_phy_addr_for_hv_page(page);
if (page == HV_INTC_FC_PAGE_START)
@@ -2529,42 +2676,76 @@ s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data)
ret_val = e1000e_write_phy_reg_mdic(hw,
IGP01E1000_PHY_PAGE_SELECT,
(page << IGP_PAGE_SHIFT));
- if (ret_val) {
- hw->phy.ops.release_phy(hw);
- goto out;
- }
hw->phy.addr = phy_addr;
}
}
ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
data);
- hw->phy.ops.release_phy(hw);
-
out:
/* Revert to MDIO fast mode, if applicable */
if ((hw->phy.type == e1000_phy_82577) && in_slow_mode)
ret_val = e1000_set_mdio_slow_mode_hv(hw, false);
+ if (!locked)
+ hw->phy.ops.release_phy(hw);
+
return ret_val;
}
/**
- * e1000_write_phy_reg_hv - Write HV PHY register
+ * e1000_read_phy_reg_hv - Read HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore then reads the PHY register at offset and stores
+ * the retrieved information in data. Release the acquired semaphore
+ * before exiting.
+ **/
+s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ return __e1000_read_phy_reg_hv(hw, offset, data, false);
+}
+
+/**
+ * e1000_read_phy_reg_hv_locked - Read HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the PHY register at offset and stores the retrieved information
+ * in data. Assumes semaphore already acquired.
+ **/
+s32 e1000_read_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ return __e1000_read_phy_reg_hv(hw, offset, data, true);
+}
+
+/**
+ * __e1000_write_phy_reg_hv - Write HV PHY register
* @hw: pointer to the HW structure
* @offset: register offset to write to
* @data: data to write at register offset
+ * @locked: semaphore has already been acquired or not
*
* Acquires semaphore, if necessary, then writes the data to PHY register
* at the offset. Release any acquired semaphores before exiting.
**/
-s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data)
+static s32 __e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data,
+ bool locked)
{
s32 ret_val;
u16 page = BM_PHY_REG_PAGE(offset);
u16 reg = BM_PHY_REG_NUM(offset);
bool in_slow_mode = false;
+ if (!locked) {
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
/* Workaround failure in MDIO access while cable is disconnected */
if ((hw->phy.type == e1000_phy_82577) &&
!(er32(STATUS) & E1000_STATUS_LU)) {
@@ -2588,10 +2769,6 @@ s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data)
goto out;
}
- ret_val = hw->phy.ops.acquire_phy(hw);
- if (ret_val)
- goto out;
-
hw->phy.addr = e1000_get_phy_addr_for_hv_page(page);
if (page == HV_INTC_FC_PAGE_START)
@@ -2607,15 +2784,10 @@ s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data)
((MAX_PHY_REG_ADDRESS & reg) == 0) &&
(data & (1 << 11))) {
u16 data2 = 0x7EFF;
- hw->phy.ops.release_phy(hw);
ret_val = e1000_access_phy_debug_regs_hv(hw, (1 << 6) | 0x3,
&data2, false);
if (ret_val)
goto out;
-
- ret_val = hw->phy.ops.acquire_phy(hw);
- if (ret_val)
- goto out;
}
if (reg > MAX_PHY_MULTI_PAGE_REG) {
@@ -2630,27 +2802,53 @@ s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data)
ret_val = e1000e_write_phy_reg_mdic(hw,
IGP01E1000_PHY_PAGE_SELECT,
(page << IGP_PAGE_SHIFT));
- if (ret_val) {
- hw->phy.ops.release_phy(hw);
- goto out;
- }
hw->phy.addr = phy_addr;
}
}
ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
data);
- hw->phy.ops.release_phy(hw);
out:
/* Revert to MDIO fast mode, if applicable */
if ((hw->phy.type == e1000_phy_82577) && in_slow_mode)
ret_val = e1000_set_mdio_slow_mode_hv(hw, false);
+ if (!locked)
+ hw->phy.ops.release_phy(hw);
+
return ret_val;
}
/**
+ * e1000_write_phy_reg_hv - Write HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore then writes the data to PHY register at the offset.
+ * Release the acquired semaphores before exiting.
+ **/
+s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ return __e1000_write_phy_reg_hv(hw, offset, data, false);
+}
+
+/**
+ * e1000_write_phy_reg_hv_locked - Write HV PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Writes the data to PHY register at the offset. Assumes semaphore
+ * already acquired.
+ **/
+s32 e1000_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ return __e1000_write_phy_reg_hv(hw, offset, data, true);
+}
+
+/**
* e1000_get_phy_addr_for_hv_page - Get PHY adrress based on page
* @page: page to be accessed
**/
@@ -2671,10 +2869,9 @@ static u32 e1000_get_phy_addr_for_hv_page(u32 page)
* @data: pointer to the data to be read or written
* @read: determines if operation is read or written
*
- * Acquires semaphore, if necessary, then reads the PHY register at offset
- * and storing the retreived information in data. Release any acquired
- * semaphores before exiting. Note that the procedure to read these regs
- * uses the address port and data port to read/write.
+ * Reads the PHY register at offset and stores the retreived information
+ * in data. Assumes semaphore already acquired. Note that the procedure
+ * to read these regs uses the address port and data port to read/write.
**/
static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
u16 *data, bool read)
@@ -2682,20 +2879,12 @@ static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
s32 ret_val;
u32 addr_reg = 0;
u32 data_reg = 0;
- u8 phy_acquired = 1;
/* This takes care of the difference with desktop vs mobile phy */
addr_reg = (hw->phy.type == e1000_phy_82578) ?
I82578_ADDR_REG : I82577_ADDR_REG;
data_reg = addr_reg + 1;
- ret_val = hw->phy.ops.acquire_phy(hw);
- if (ret_val) {
- hw_dbg(hw, "Could not acquire PHY\n");
- phy_acquired = 0;
- goto out;
- }
-
/* All operations in this function are phy address 2 */
hw->phy.addr = 2;
@@ -2718,8 +2907,6 @@ static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
}
out:
- if (phy_acquired == 1)
- hw->phy.ops.release_phy(hw);
return ret_val;
}
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 41bd7aeafd82..7f8fcc2fa748 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -447,7 +447,9 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr,
max_index_mask = q_skba->len - 1;
for (i = 0; i < fill_wqes; i++) {
u64 tmp_addr;
- struct sk_buff *skb = netdev_alloc_skb(dev, packet_size);
+ struct sk_buff *skb;
+
+ skb = netdev_alloc_skb_ip_align(dev, packet_size);
if (!skb) {
q_skba->os_skbs = fill_wqes - i;
if (q_skba->os_skbs == q_skba->len - 2) {
@@ -457,7 +459,6 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr,
}
break;
}
- skb_reserve(skb, NET_IP_ALIGN);
skb_arr[index] = skb;
tmp_addr = ehea_map_vaddr(skb->data);
@@ -500,7 +501,7 @@ static int ehea_refill_rq2(struct ehea_port_res *pr, int nr_of_wqes)
{
return ehea_refill_rq_def(pr, &pr->rq2_skba, 2,
nr_of_wqes, EHEA_RWQE2_TYPE,
- EHEA_RQ2_PKT_SIZE + NET_IP_ALIGN);
+ EHEA_RQ2_PKT_SIZE);
}
@@ -508,7 +509,7 @@ static int ehea_refill_rq3(struct ehea_port_res *pr, int nr_of_wqes)
{
return ehea_refill_rq_def(pr, &pr->rq3_skba, 3,
nr_of_wqes, EHEA_RWQE3_TYPE,
- EHEA_MAX_PACKET_SIZE + NET_IP_ALIGN);
+ EHEA_MAX_PACKET_SIZE);
}
static inline int ehea_check_cqe(struct ehea_cqe *cqe, int *rq_num)
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index d69d52ed7726..f875751af15e 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -870,19 +870,6 @@ static void enic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf)
dev_kfree_skb_any(buf->os_buf);
}
-static inline struct sk_buff *enic_rq_alloc_skb(struct net_device *netdev,
- unsigned int size)
-{
- struct sk_buff *skb;
-
- skb = netdev_alloc_skb(netdev, size + NET_IP_ALIGN);
-
- if (skb)
- skb_reserve(skb, NET_IP_ALIGN);
-
- return skb;
-}
-
static int enic_rq_alloc_buf(struct vnic_rq *rq)
{
struct enic *enic = vnic_dev_priv(rq->vdev);
@@ -892,7 +879,7 @@ static int enic_rq_alloc_buf(struct vnic_rq *rq)
unsigned int os_buf_index = 0;
dma_addr_t dma_addr;
- skb = enic_rq_alloc_skb(netdev, len);
+ skb = netdev_alloc_skb_ip_align(netdev, len);
if (!skb)
return -ENOMEM;
diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c
index 9c950bb5e90c..50f192325164 100644
--- a/drivers/net/ethoc.c
+++ b/drivers/net/ethoc.c
@@ -223,24 +223,25 @@ struct ethoc_bd {
u32 addr;
};
-static u32 ethoc_read(struct ethoc *dev, loff_t offset)
+static inline u32 ethoc_read(struct ethoc *dev, loff_t offset)
{
return ioread32(dev->iobase + offset);
}
-static void ethoc_write(struct ethoc *dev, loff_t offset, u32 data)
+static inline void ethoc_write(struct ethoc *dev, loff_t offset, u32 data)
{
iowrite32(data, dev->iobase + offset);
}
-static void ethoc_read_bd(struct ethoc *dev, int index, struct ethoc_bd *bd)
+static inline void ethoc_read_bd(struct ethoc *dev, int index,
+ struct ethoc_bd *bd)
{
loff_t offset = ETHOC_BD_BASE + (index * sizeof(struct ethoc_bd));
bd->stat = ethoc_read(dev, offset + 0);
bd->addr = ethoc_read(dev, offset + 4);
}
-static void ethoc_write_bd(struct ethoc *dev, int index,
+static inline void ethoc_write_bd(struct ethoc *dev, int index,
const struct ethoc_bd *bd)
{
loff_t offset = ETHOC_BD_BASE + (index * sizeof(struct ethoc_bd));
@@ -248,33 +249,33 @@ static void ethoc_write_bd(struct ethoc *dev, int index,
ethoc_write(dev, offset + 4, bd->addr);
}
-static void ethoc_enable_irq(struct ethoc *dev, u32 mask)
+static inline void ethoc_enable_irq(struct ethoc *dev, u32 mask)
{
u32 imask = ethoc_read(dev, INT_MASK);
imask |= mask;
ethoc_write(dev, INT_MASK, imask);
}
-static void ethoc_disable_irq(struct ethoc *dev, u32 mask)
+static inline void ethoc_disable_irq(struct ethoc *dev, u32 mask)
{
u32 imask = ethoc_read(dev, INT_MASK);
imask &= ~mask;
ethoc_write(dev, INT_MASK, imask);
}
-static void ethoc_ack_irq(struct ethoc *dev, u32 mask)
+static inline void ethoc_ack_irq(struct ethoc *dev, u32 mask)
{
ethoc_write(dev, INT_SOURCE, mask);
}
-static void ethoc_enable_rx_and_tx(struct ethoc *dev)
+static inline void ethoc_enable_rx_and_tx(struct ethoc *dev)
{
u32 mode = ethoc_read(dev, MODER);
mode |= MODER_RXEN | MODER_TXEN;
ethoc_write(dev, MODER, mode);
}
-static void ethoc_disable_rx_and_tx(struct ethoc *dev)
+static inline void ethoc_disable_rx_and_tx(struct ethoc *dev)
{
u32 mode = ethoc_read(dev, MODER);
mode &= ~(MODER_RXEN | MODER_TXEN);
@@ -405,10 +406,10 @@ static int ethoc_rx(struct net_device *dev, int limit)
if (ethoc_update_rx_stats(priv, &bd) == 0) {
int size = bd.stat >> 16;
- struct sk_buff *skb = netdev_alloc_skb(dev, size);
+ struct sk_buff *skb;
size -= 4; /* strip the CRC */
- skb_reserve(skb, 2); /* align TCP/IP header */
+ skb = netdev_alloc_skb_ip_align(dev, size);
if (likely(skb)) {
void *src = phys_to_virt(bd.addr);
@@ -508,7 +509,7 @@ static irqreturn_t ethoc_interrupt(int irq, void *dev_id)
return IRQ_NONE;
}
- ethoc_ack_irq(priv, INT_MASK_ALL);
+ ethoc_ack_irq(priv, pending);
if (pending & INT_MASK_BUSY) {
dev_err(&dev->dev, "packet dropped\n");
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 29234380e6c6..16a1d58419d9 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -1654,7 +1654,7 @@ static const struct net_device_ops fec_netdev_ops = {
*
* index is only used in legacy code
*/
-int __init fec_enet_init(struct net_device *dev, int index)
+static int fec_enet_init(struct net_device *dev, int index)
{
struct fec_enet_private *fep = netdev_priv(dev);
struct bufdesc *cbd_base;
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 5bf31f1509c9..f7141865869d 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -147,6 +147,208 @@ MODULE_AUTHOR("Freescale Semiconductor, Inc");
MODULE_DESCRIPTION("Gianfar Ethernet Driver");
MODULE_LICENSE("GPL");
+static void gfar_init_rxbdp(struct net_device *dev, struct rxbd8 *bdp,
+ dma_addr_t buf)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ u32 lstatus;
+
+ bdp->bufPtr = buf;
+
+ lstatus = BD_LFLAG(RXBD_EMPTY | RXBD_INTERRUPT);
+ if (bdp == priv->rx_bd_base + priv->rx_ring_size - 1)
+ lstatus |= BD_LFLAG(RXBD_WRAP);
+
+ eieio();
+
+ bdp->lstatus = lstatus;
+}
+
+static int gfar_init_bds(struct net_device *ndev)
+{
+ struct gfar_private *priv = netdev_priv(ndev);
+ struct txbd8 *txbdp;
+ struct rxbd8 *rxbdp;
+ int i;
+
+ /* Initialize some variables in our dev structure */
+ priv->num_txbdfree = priv->tx_ring_size;
+ priv->dirty_tx = priv->cur_tx = priv->tx_bd_base;
+ priv->cur_rx = priv->rx_bd_base;
+ priv->skb_curtx = priv->skb_dirtytx = 0;
+ priv->skb_currx = 0;
+
+ /* Initialize Transmit Descriptor Ring */
+ txbdp = priv->tx_bd_base;
+ for (i = 0; i < priv->tx_ring_size; i++) {
+ txbdp->lstatus = 0;
+ txbdp->bufPtr = 0;
+ txbdp++;
+ }
+
+ /* Set the last descriptor in the ring to indicate wrap */
+ txbdp--;
+ txbdp->status |= TXBD_WRAP;
+
+ rxbdp = priv->rx_bd_base;
+ for (i = 0; i < priv->rx_ring_size; i++) {
+ struct sk_buff *skb = priv->rx_skbuff[i];
+
+ if (skb) {
+ gfar_init_rxbdp(ndev, rxbdp, rxbdp->bufPtr);
+ } else {
+ skb = gfar_new_skb(ndev);
+ if (!skb) {
+ pr_err("%s: Can't allocate RX buffers\n",
+ ndev->name);
+ return -ENOMEM;
+ }
+ priv->rx_skbuff[i] = skb;
+
+ gfar_new_rxbdp(ndev, rxbdp, skb);
+ }
+
+ rxbdp++;
+ }
+
+ return 0;
+}
+
+static int gfar_alloc_skb_resources(struct net_device *ndev)
+{
+ void *vaddr;
+ int i;
+ struct gfar_private *priv = netdev_priv(ndev);
+ struct device *dev = &priv->ofdev->dev;
+
+ /* Allocate memory for the buffer descriptors */
+ vaddr = dma_alloc_coherent(dev,
+ sizeof(*priv->tx_bd_base) * priv->tx_ring_size +
+ sizeof(*priv->rx_bd_base) * priv->rx_ring_size,
+ &priv->tx_bd_dma_base, GFP_KERNEL);
+ if (!vaddr) {
+ if (netif_msg_ifup(priv))
+ pr_err("%s: Could not allocate buffer descriptors!\n",
+ ndev->name);
+ return -ENOMEM;
+ }
+
+ priv->tx_bd_base = vaddr;
+
+ /* Start the rx descriptor ring where the tx ring leaves off */
+ vaddr = vaddr + sizeof(*priv->tx_bd_base) * priv->tx_ring_size;
+ priv->rx_bd_base = vaddr;
+
+ /* Setup the skbuff rings */
+ priv->tx_skbuff = kmalloc(sizeof(*priv->tx_skbuff) *
+ priv->tx_ring_size, GFP_KERNEL);
+ if (!priv->tx_skbuff) {
+ if (netif_msg_ifup(priv))
+ pr_err("%s: Could not allocate tx_skbuff\n",
+ ndev->name);
+ goto cleanup;
+ }
+
+ for (i = 0; i < priv->tx_ring_size; i++)
+ priv->tx_skbuff[i] = NULL;
+
+ priv->rx_skbuff = kmalloc(sizeof(*priv->rx_skbuff) *
+ priv->rx_ring_size, GFP_KERNEL);
+ if (!priv->rx_skbuff) {
+ if (netif_msg_ifup(priv))
+ pr_err("%s: Could not allocate rx_skbuff\n",
+ ndev->name);
+ goto cleanup;
+ }
+
+ for (i = 0; i < priv->rx_ring_size; i++)
+ priv->rx_skbuff[i] = NULL;
+
+ if (gfar_init_bds(ndev))
+ goto cleanup;
+
+ return 0;
+
+cleanup:
+ free_skb_resources(priv);
+ return -ENOMEM;
+}
+
+static void gfar_init_mac(struct net_device *ndev)
+{
+ struct gfar_private *priv = netdev_priv(ndev);
+ struct gfar __iomem *regs = priv->regs;
+ u32 rctrl = 0;
+ u32 tctrl = 0;
+ u32 attrs = 0;
+
+ /* enet DMA only understands physical addresses */
+ gfar_write(&regs->tbase0, priv->tx_bd_dma_base);
+ gfar_write(&regs->rbase0, priv->tx_bd_dma_base +
+ sizeof(*priv->tx_bd_base) *
+ priv->tx_ring_size);
+
+ /* Configure the coalescing support */
+ gfar_write(&regs->txic, 0);
+ if (priv->txcoalescing)
+ gfar_write(&regs->txic, priv->txic);
+
+ gfar_write(&regs->rxic, 0);
+ if (priv->rxcoalescing)
+ gfar_write(&regs->rxic, priv->rxic);
+
+ if (priv->rx_csum_enable)
+ rctrl |= RCTRL_CHECKSUMMING;
+
+ if (priv->extended_hash) {
+ rctrl |= RCTRL_EXTHASH;
+
+ gfar_clear_exact_match(ndev);
+ rctrl |= RCTRL_EMEN;
+ }
+
+ if (priv->padding) {
+ rctrl &= ~RCTRL_PAL_MASK;
+ rctrl |= RCTRL_PADDING(priv->padding);
+ }
+
+ /* keep vlan related bits if it's enabled */
+ if (priv->vlgrp) {
+ rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;
+ tctrl |= TCTRL_VLINS;
+ }
+
+ /* Init rctrl based on our settings */
+ gfar_write(&regs->rctrl, rctrl);
+
+ if (ndev->features & NETIF_F_IP_CSUM)
+ tctrl |= TCTRL_INIT_CSUM;
+
+ gfar_write(&regs->tctrl, tctrl);
+
+ /* Set the extraction length and index */
+ attrs = ATTRELI_EL(priv->rx_stash_size) |
+ ATTRELI_EI(priv->rx_stash_index);
+
+ gfar_write(&regs->attreli, attrs);
+
+ /* Start with defaults, and add stashing or locking
+ * depending on the approprate variables */
+ attrs = ATTR_INIT_SETTINGS;
+
+ if (priv->bd_stash_en)
+ attrs |= ATTR_BDSTASH;
+
+ if (priv->rx_stash_size != 0)
+ attrs |= ATTR_BUFSTASH;
+
+ gfar_write(&regs->attr, attrs);
+
+ gfar_write(&regs->fifo_tx_thr, priv->fifo_threshold);
+ gfar_write(&regs->fifo_tx_starve, priv->fifo_starve);
+ gfar_write(&regs->fifo_tx_starve_shutoff, priv->fifo_starve_off);
+}
+
static const struct net_device_ops gfar_netdev_ops = {
.ndo_open = gfar_enet_open,
.ndo_start_xmit = gfar_start_xmit,
@@ -498,23 +700,24 @@ static int gfar_remove(struct of_device *ofdev)
}
#ifdef CONFIG_PM
-static int gfar_suspend(struct of_device *ofdev, pm_message_t state)
+
+static int gfar_suspend(struct device *dev)
{
- struct gfar_private *priv = dev_get_drvdata(&ofdev->dev);
- struct net_device *dev = priv->ndev;
+ struct gfar_private *priv = dev_get_drvdata(dev);
+ struct net_device *ndev = priv->ndev;
unsigned long flags;
u32 tempval;
int magic_packet = priv->wol_en &&
(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
- netif_device_detach(dev);
+ netif_device_detach(ndev);
- if (netif_running(dev)) {
+ if (netif_running(ndev)) {
spin_lock_irqsave(&priv->txlock, flags);
spin_lock(&priv->rxlock);
- gfar_halt_nodisable(dev);
+ gfar_halt_nodisable(ndev);
/* Disable Tx, and Rx if wake-on-LAN is disabled. */
tempval = gfar_read(&priv->regs->maccfg1);
@@ -547,17 +750,17 @@ static int gfar_suspend(struct of_device *ofdev, pm_message_t state)
return 0;
}
-static int gfar_resume(struct of_device *ofdev)
+static int gfar_resume(struct device *dev)
{
- struct gfar_private *priv = dev_get_drvdata(&ofdev->dev);
- struct net_device *dev = priv->ndev;
+ struct gfar_private *priv = dev_get_drvdata(dev);
+ struct net_device *ndev = priv->ndev;
unsigned long flags;
u32 tempval;
int magic_packet = priv->wol_en &&
(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
- if (!netif_running(dev)) {
- netif_device_attach(dev);
+ if (!netif_running(ndev)) {
+ netif_device_attach(ndev);
return 0;
}
@@ -575,20 +778,71 @@ static int gfar_resume(struct of_device *ofdev)
tempval &= ~MACCFG2_MPEN;
gfar_write(&priv->regs->maccfg2, tempval);
- gfar_start(dev);
+ gfar_start(ndev);
spin_unlock(&priv->rxlock);
spin_unlock_irqrestore(&priv->txlock, flags);
- netif_device_attach(dev);
+ netif_device_attach(ndev);
+
+ napi_enable(&priv->napi);
+
+ return 0;
+}
+
+static int gfar_restore(struct device *dev)
+{
+ struct gfar_private *priv = dev_get_drvdata(dev);
+ struct net_device *ndev = priv->ndev;
+
+ if (!netif_running(ndev))
+ return 0;
+
+ gfar_init_bds(ndev);
+ init_registers(ndev);
+ gfar_set_mac_address(ndev);
+ gfar_init_mac(ndev);
+ gfar_start(ndev);
+
+ priv->oldlink = 0;
+ priv->oldspeed = 0;
+ priv->oldduplex = -1;
+
+ if (priv->phydev)
+ phy_start(priv->phydev);
+ netif_device_attach(ndev);
napi_enable(&priv->napi);
return 0;
}
+
+static struct dev_pm_ops gfar_pm_ops = {
+ .suspend = gfar_suspend,
+ .resume = gfar_resume,
+ .freeze = gfar_suspend,
+ .thaw = gfar_resume,
+ .restore = gfar_restore,
+};
+
+#define GFAR_PM_OPS (&gfar_pm_ops)
+
+static int gfar_legacy_suspend(struct of_device *ofdev, pm_message_t state)
+{
+ return gfar_suspend(&ofdev->dev);
+}
+
+static int gfar_legacy_resume(struct of_device *ofdev)
+{
+ return gfar_resume(&ofdev->dev);
+}
+
#else
-#define gfar_suspend NULL
-#define gfar_resume NULL
+
+#define GFAR_PM_OPS NULL
+#define gfar_legacy_suspend NULL
+#define gfar_legacy_resume NULL
+
#endif
/* Reads the controller's registers to determine what interface
@@ -806,7 +1060,6 @@ void gfar_halt(struct net_device *dev)
void stop_gfar(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
- struct gfar __iomem *regs = priv->regs;
unsigned long flags;
phy_stop(priv->phydev);
@@ -830,18 +1083,13 @@ void stop_gfar(struct net_device *dev)
}
free_skb_resources(priv);
-
- dma_free_coherent(&priv->ofdev->dev,
- sizeof(struct txbd8)*priv->tx_ring_size
- + sizeof(struct rxbd8)*priv->rx_ring_size,
- priv->tx_bd_base,
- gfar_read(&regs->tbase0));
}
/* If there are any tx skbs or rx skbs still around, free them.
* Then free tx_skbuff and rx_skbuff */
static void free_skb_resources(struct gfar_private *priv)
{
+ struct device *dev = &priv->ofdev->dev;
struct rxbd8 *rxbdp;
struct txbd8 *txbdp;
int i, j;
@@ -849,6 +1097,9 @@ static void free_skb_resources(struct gfar_private *priv)
/* Go through all the buffer descriptors and free their data buffers */
txbdp = priv->tx_bd_base;
+ if (!priv->tx_skbuff)
+ goto skip_tx_skbuff;
+
for (i = 0; i < priv->tx_ring_size; i++) {
if (!priv->tx_skbuff[i])
continue;
@@ -867,30 +1118,33 @@ static void free_skb_resources(struct gfar_private *priv)
}
kfree(priv->tx_skbuff);
+skip_tx_skbuff:
rxbdp = priv->rx_bd_base;
- /* rx_skbuff is not guaranteed to be allocated, so only
- * free it and its contents if it is allocated */
- if(priv->rx_skbuff != NULL) {
- for (i = 0; i < priv->rx_ring_size; i++) {
- if (priv->rx_skbuff[i]) {
- dma_unmap_single(&priv->ofdev->dev, rxbdp->bufPtr,
- priv->rx_buffer_size,
- DMA_FROM_DEVICE);
-
- dev_kfree_skb_any(priv->rx_skbuff[i]);
- priv->rx_skbuff[i] = NULL;
- }
-
- rxbdp->lstatus = 0;
- rxbdp->bufPtr = 0;
+ if (!priv->rx_skbuff)
+ goto skip_rx_skbuff;
- rxbdp++;
+ for (i = 0; i < priv->rx_ring_size; i++) {
+ if (priv->rx_skbuff[i]) {
+ dma_unmap_single(&priv->ofdev->dev, rxbdp->bufPtr,
+ priv->rx_buffer_size,
+ DMA_FROM_DEVICE);
+ dev_kfree_skb_any(priv->rx_skbuff[i]);
+ priv->rx_skbuff[i] = NULL;
}
- kfree(priv->rx_skbuff);
+ rxbdp->lstatus = 0;
+ rxbdp->bufPtr = 0;
+ rxbdp++;
}
+
+ kfree(priv->rx_skbuff);
+skip_rx_skbuff:
+
+ dma_free_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size +
+ sizeof(*rxbdp) * priv->rx_ring_size,
+ priv->tx_bd_base, priv->tx_bd_dma_base);
}
void gfar_start(struct net_device *dev)
@@ -925,249 +1179,75 @@ void gfar_start(struct net_device *dev)
}
/* Bring the controller up and running */
-int startup_gfar(struct net_device *dev)
+int startup_gfar(struct net_device *ndev)
{
- struct txbd8 *txbdp;
- struct rxbd8 *rxbdp;
- dma_addr_t addr = 0;
- unsigned long vaddr;
- int i;
- struct gfar_private *priv = netdev_priv(dev);
+ struct gfar_private *priv = netdev_priv(ndev);
struct gfar __iomem *regs = priv->regs;
- int err = 0;
- u32 rctrl = 0;
- u32 tctrl = 0;
- u32 attrs = 0;
+ int err;
gfar_write(&regs->imask, IMASK_INIT_CLEAR);
- /* Allocate memory for the buffer descriptors */
- vaddr = (unsigned long) dma_alloc_coherent(&priv->ofdev->dev,
- sizeof (struct txbd8) * priv->tx_ring_size +
- sizeof (struct rxbd8) * priv->rx_ring_size,
- &addr, GFP_KERNEL);
-
- if (vaddr == 0) {
- if (netif_msg_ifup(priv))
- printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n",
- dev->name);
- return -ENOMEM;
- }
-
- priv->tx_bd_base = (struct txbd8 *) vaddr;
-
- /* enet DMA only understands physical addresses */
- gfar_write(&regs->tbase0, addr);
-
- /* Start the rx descriptor ring where the tx ring leaves off */
- addr = addr + sizeof (struct txbd8) * priv->tx_ring_size;
- vaddr = vaddr + sizeof (struct txbd8) * priv->tx_ring_size;
- priv->rx_bd_base = (struct rxbd8 *) vaddr;
- gfar_write(&regs->rbase0, addr);
-
- /* Setup the skbuff rings */
- priv->tx_skbuff =
- (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) *
- priv->tx_ring_size, GFP_KERNEL);
-
- if (NULL == priv->tx_skbuff) {
- if (netif_msg_ifup(priv))
- printk(KERN_ERR "%s: Could not allocate tx_skbuff\n",
- dev->name);
- err = -ENOMEM;
- goto tx_skb_fail;
- }
-
- for (i = 0; i < priv->tx_ring_size; i++)
- priv->tx_skbuff[i] = NULL;
-
- priv->rx_skbuff =
- (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) *
- priv->rx_ring_size, GFP_KERNEL);
-
- if (NULL == priv->rx_skbuff) {
- if (netif_msg_ifup(priv))
- printk(KERN_ERR "%s: Could not allocate rx_skbuff\n",
- dev->name);
- err = -ENOMEM;
- goto rx_skb_fail;
- }
-
- for (i = 0; i < priv->rx_ring_size; i++)
- priv->rx_skbuff[i] = NULL;
-
- /* Initialize some variables in our dev structure */
- priv->num_txbdfree = priv->tx_ring_size;
- priv->dirty_tx = priv->cur_tx = priv->tx_bd_base;
- priv->cur_rx = priv->rx_bd_base;
- priv->skb_curtx = priv->skb_dirtytx = 0;
- priv->skb_currx = 0;
-
- /* Initialize Transmit Descriptor Ring */
- txbdp = priv->tx_bd_base;
- for (i = 0; i < priv->tx_ring_size; i++) {
- txbdp->lstatus = 0;
- txbdp->bufPtr = 0;
- txbdp++;
- }
-
- /* Set the last descriptor in the ring to indicate wrap */
- txbdp--;
- txbdp->status |= TXBD_WRAP;
-
- rxbdp = priv->rx_bd_base;
- for (i = 0; i < priv->rx_ring_size; i++) {
- struct sk_buff *skb;
-
- skb = gfar_new_skb(dev);
-
- if (!skb) {
- printk(KERN_ERR "%s: Can't allocate RX buffers\n",
- dev->name);
-
- goto err_rxalloc_fail;
- }
-
- priv->rx_skbuff[i] = skb;
-
- gfar_new_rxbdp(dev, rxbdp, skb);
-
- rxbdp++;
- }
+ err = gfar_alloc_skb_resources(ndev);
+ if (err)
+ return err;
- /* Set the last descriptor in the ring to wrap */
- rxbdp--;
- rxbdp->status |= RXBD_WRAP;
+ gfar_init_mac(ndev);
/* If the device has multiple interrupts, register for
* them. Otherwise, only register for the one */
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
/* Install our interrupt handlers for Error,
* Transmit, and Receive */
- if (request_irq(priv->interruptError, gfar_error,
- 0, priv->int_name_er, dev) < 0) {
+ err = request_irq(priv->interruptError, gfar_error, 0,
+ priv->int_name_er, ndev);
+ if (err) {
if (netif_msg_intr(priv))
- printk(KERN_ERR "%s: Can't get IRQ %d\n",
- dev->name, priv->interruptError);
-
- err = -1;
+ pr_err("%s: Can't get IRQ %d\n", ndev->name,
+ priv->interruptError);
goto err_irq_fail;
}
- if (request_irq(priv->interruptTransmit, gfar_transmit,
- 0, priv->int_name_tx, dev) < 0) {
+ err = request_irq(priv->interruptTransmit, gfar_transmit, 0,
+ priv->int_name_tx, ndev);
+ if (err) {
if (netif_msg_intr(priv))
- printk(KERN_ERR "%s: Can't get IRQ %d\n",
- dev->name, priv->interruptTransmit);
-
- err = -1;
-
+ pr_err("%s: Can't get IRQ %d\n", ndev->name,
+ priv->interruptTransmit);
goto tx_irq_fail;
}
- if (request_irq(priv->interruptReceive, gfar_receive,
- 0, priv->int_name_rx, dev) < 0) {
+ err = request_irq(priv->interruptReceive, gfar_receive, 0,
+ priv->int_name_rx, ndev);
+ if (err) {
if (netif_msg_intr(priv))
- printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n",
- dev->name, priv->interruptReceive);
-
- err = -1;
+ pr_err("%s: Can't get IRQ %d (receive0)\n",
+ ndev->name, priv->interruptReceive);
goto rx_irq_fail;
}
} else {
- if (request_irq(priv->interruptTransmit, gfar_interrupt,
- 0, priv->int_name_tx, dev) < 0) {
+ err = request_irq(priv->interruptTransmit, gfar_interrupt,
+ 0, priv->int_name_tx, ndev);
+ if (err) {
if (netif_msg_intr(priv))
- printk(KERN_ERR "%s: Can't get IRQ %d\n",
- dev->name, priv->interruptTransmit);
-
- err = -1;
+ pr_err("%s: Can't get IRQ %d\n", ndev->name,
+ priv->interruptTransmit);
goto err_irq_fail;
}
}
- phy_start(priv->phydev);
-
- /* Configure the coalescing support */
- gfar_write(&regs->txic, 0);
- if (priv->txcoalescing)
- gfar_write(&regs->txic, priv->txic);
-
- gfar_write(&regs->rxic, 0);
- if (priv->rxcoalescing)
- gfar_write(&regs->rxic, priv->rxic);
-
- if (priv->rx_csum_enable)
- rctrl |= RCTRL_CHECKSUMMING;
-
- if (priv->extended_hash) {
- rctrl |= RCTRL_EXTHASH;
-
- gfar_clear_exact_match(dev);
- rctrl |= RCTRL_EMEN;
- }
-
- if (priv->padding) {
- rctrl &= ~RCTRL_PAL_MASK;
- rctrl |= RCTRL_PADDING(priv->padding);
- }
-
- /* keep vlan related bits if it's enabled */
- if (priv->vlgrp) {
- rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;
- tctrl |= TCTRL_VLINS;
- }
-
- /* Init rctrl based on our settings */
- gfar_write(&priv->regs->rctrl, rctrl);
-
- if (dev->features & NETIF_F_IP_CSUM)
- tctrl |= TCTRL_INIT_CSUM;
-
- gfar_write(&priv->regs->tctrl, tctrl);
-
- /* Set the extraction length and index */
- attrs = ATTRELI_EL(priv->rx_stash_size) |
- ATTRELI_EI(priv->rx_stash_index);
-
- gfar_write(&priv->regs->attreli, attrs);
-
- /* Start with defaults, and add stashing or locking
- * depending on the approprate variables */
- attrs = ATTR_INIT_SETTINGS;
-
- if (priv->bd_stash_en)
- attrs |= ATTR_BDSTASH;
-
- if (priv->rx_stash_size != 0)
- attrs |= ATTR_BUFSTASH;
-
- gfar_write(&priv->regs->attr, attrs);
-
- gfar_write(&priv->regs->fifo_tx_thr, priv->fifo_threshold);
- gfar_write(&priv->regs->fifo_tx_starve, priv->fifo_starve);
- gfar_write(&priv->regs->fifo_tx_starve_shutoff, priv->fifo_starve_off);
-
/* Start the controller */
- gfar_start(dev);
+ gfar_start(ndev);
+
+ phy_start(priv->phydev);
return 0;
rx_irq_fail:
- free_irq(priv->interruptTransmit, dev);
+ free_irq(priv->interruptTransmit, ndev);
tx_irq_fail:
- free_irq(priv->interruptError, dev);
+ free_irq(priv->interruptError, ndev);
err_irq_fail:
-err_rxalloc_fail:
-rx_skb_fail:
free_skb_resources(priv);
-tx_skb_fail:
- dma_free_coherent(&priv->ofdev->dev,
- sizeof(struct txbd8)*priv->tx_ring_size
- + sizeof(struct rxbd8)*priv->rx_ring_size,
- priv->tx_bd_base,
- gfar_read(&regs->tbase0));
-
return err;
}
@@ -1681,19 +1761,11 @@ static void gfar_new_rxbdp(struct net_device *dev, struct rxbd8 *bdp,
struct sk_buff *skb)
{
struct gfar_private *priv = netdev_priv(dev);
- u32 lstatus;
-
- bdp->bufPtr = dma_map_single(&priv->ofdev->dev, skb->data,
- priv->rx_buffer_size, DMA_FROM_DEVICE);
+ dma_addr_t buf;
- lstatus = BD_LFLAG(RXBD_EMPTY | RXBD_INTERRUPT);
-
- if (bdp == priv->rx_bd_base + priv->rx_ring_size - 1)
- lstatus |= BD_LFLAG(RXBD_WRAP);
-
- eieio();
-
- bdp->lstatus = lstatus;
+ buf = dma_map_single(&priv->ofdev->dev, skb->data,
+ priv->rx_buffer_size, DMA_FROM_DEVICE);
+ gfar_init_rxbdp(dev, bdp, buf);
}
@@ -2342,8 +2414,9 @@ static struct of_platform_driver gfar_driver = {
.probe = gfar_probe,
.remove = gfar_remove,
- .suspend = gfar_suspend,
- .resume = gfar_resume,
+ .suspend = gfar_legacy_suspend,
+ .resume = gfar_legacy_resume,
+ .driver.pm = GFAR_PM_OPS,
};
static int __init gfar_init(void)
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 2cd94338b5d3..05732faa2f90 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -726,6 +726,7 @@ struct gfar_private {
unsigned long txic;
/* Buffer descriptor pointers */
+ dma_addr_t tx_bd_dma_base;
struct txbd8 *tx_bd_base; /* First tx buffer descriptor */
struct txbd8 *cur_tx; /* Next free ring entry */
struct txbd8 *dirty_tx; /* First buffer in line
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index f7519a594945..c9ac46118e6f 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -407,10 +407,9 @@ that case.
/* A few values that may be tweaked. */
/* Size of each temporary Rx buffer, calculated as:
* 1518 bytes (ethernet packet) + 2 bytes (to get 8 byte alignment for
- * the card) + 8 bytes of status info + 8 bytes for the Rx Checksum +
- * 2 more because we use skb_reserve.
+ * the card) + 8 bytes of status info + 8 bytes for the Rx Checksum
*/
-#define PKT_BUF_SZ 1538
+#define PKT_BUF_SZ 1536
/* For now, this is going to be set to the maximum size of an ethernet
* packet. Eventually, we may want to make it a variable that is
@@ -1152,12 +1151,13 @@ static void hamachi_tx_timeout(struct net_device *dev)
}
/* Fill in the Rx buffers. Handle allocation failure gracefully. */
for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb = netdev_alloc_skb(dev, hmp->rx_buf_sz);
+ struct sk_buff *skb;
+
+ skb = netdev_alloc_skb_ip_align(dev, hmp->rx_buf_sz);
hmp->rx_skbuff[i] = skb;
if (skb == NULL)
break;
- skb_reserve(skb, 2); /* 16 byte align the IP header. */
hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));
hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn |
@@ -1196,7 +1196,7 @@ static void hamachi_init_ring(struct net_device *dev)
* card. -KDU
*/
hmp->rx_buf_sz = (dev->mtu <= 1492 ? PKT_BUF_SZ :
- (((dev->mtu+26+7) & ~7) + 2 + 16));
+ (((dev->mtu+26+7) & ~7) + 16));
/* Initialize all Rx descriptors. */
for (i = 0; i < RX_RING_SIZE; i++) {
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index e344c84c0ef9..a3c0dc9d8b98 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -596,16 +596,16 @@ static int receive(struct net_device *dev, int cnt)
if (!(notbitstream & (0x1fc << j)))
state = 0;
- /* not flag received */
- else if (!(bitstream & (0x1fe << j)) != (0x0fc << j)) {
+ /* flag received */
+ else if ((bitstream & (0x1fe << j)) == (0x0fc << j)) {
if (state)
do_rxpacket(dev);
bc->hdlcrx.bufcnt = 0;
bc->hdlcrx.bufptr = bc->hdlcrx.buf;
state = 1;
numbits = 7-j;
- }
}
+ }
/* stuffed bit */
else if (unlikely((bitstream & (0x1f8 << j)) == (0xf8 << j))) {
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index 3fae87559791..af117c626e73 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -2149,9 +2149,12 @@ static int emac_ethtool_nway_reset(struct net_device *ndev)
return res;
}
-static int emac_ethtool_get_stats_count(struct net_device *ndev)
+static int emac_ethtool_get_sset_count(struct net_device *ndev, int stringset)
{
- return EMAC_ETHTOOL_STATS_COUNT;
+ if (stringset == ETH_SS_STATS)
+ return EMAC_ETHTOOL_STATS_COUNT;
+ else
+ return -EINVAL;
}
static void emac_ethtool_get_strings(struct net_device *ndev, u32 stringset,
@@ -2182,7 +2185,6 @@ static void emac_ethtool_get_drvinfo(struct net_device *ndev,
info->fw_version[0] = '\0';
sprintf(info->bus_info, "PPC 4xx EMAC-%d %s",
dev->cell_index, dev->ofdev->node->full_name);
- info->n_stats = emac_ethtool_get_stats_count(ndev);
info->regdump_len = emac_ethtool_get_regs_len(ndev);
}
@@ -2202,7 +2204,7 @@ static const struct ethtool_ops emac_ethtool_ops = {
.get_rx_csum = emac_ethtool_get_rx_csum,
.get_strings = emac_ethtool_get_strings,
- .get_stats_count = emac_ethtool_get_stats_count,
+ .get_sset_count = emac_ethtool_get_sset_count,
.get_ethtool_stats = emac_ethtool_get_ethtool_stats,
.get_link = ethtool_op_get_link,
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index 801f088c134f..030913f8bd26 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -98,12 +98,13 @@ static void ri_tasklet(unsigned long dev)
stats->tx_packets++;
stats->tx_bytes +=skb->len;
- skb->dev = __dev_get_by_index(&init_net, skb->iif);
+ skb->dev = dev_get_by_index(&init_net, skb->iif);
if (!skb->dev) {
dev_kfree_skb(skb);
stats->tx_dropped++;
break;
}
+ dev_put(skb->dev);
skb->iif = _dev->ifindex;
if (from & AT_EGRESS) {
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c
index f8f5772557ce..5d345e3036a4 100644
--- a/drivers/net/igb/e1000_82575.c
+++ b/drivers/net/igb/e1000_82575.c
@@ -81,6 +81,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
break;
case E1000_DEV_ID_82576:
case E1000_DEV_ID_82576_NS:
+ case E1000_DEV_ID_82576_NS_SERDES:
case E1000_DEV_ID_82576_FIBER:
case E1000_DEV_ID_82576_SERDES:
case E1000_DEV_ID_82576_QUAD_COPPER:
@@ -240,9 +241,10 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
**/
static s32 igb_acquire_phy_82575(struct e1000_hw *hw)
{
- u16 mask;
+ u16 mask = E1000_SWFW_PHY0_SM;
- mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+ if (hw->bus.func == E1000_FUNC_1)
+ mask = E1000_SWFW_PHY1_SM;
return igb_acquire_swfw_sync_82575(hw, mask);
}
@@ -256,9 +258,11 @@ static s32 igb_acquire_phy_82575(struct e1000_hw *hw)
**/
static void igb_release_phy_82575(struct e1000_hw *hw)
{
- u16 mask;
+ u16 mask = E1000_SWFW_PHY0_SM;
+
+ if (hw->bus.func == E1000_FUNC_1)
+ mask = E1000_SWFW_PHY1_SM;
- mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
igb_release_swfw_sync_82575(hw, mask);
}
@@ -274,45 +278,23 @@ static void igb_release_phy_82575(struct e1000_hw *hw)
static s32 igb_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
u16 *data)
{
- struct e1000_phy_info *phy = &hw->phy;
- u32 i, i2ccmd = 0;
+ s32 ret_val = -E1000_ERR_PARAM;
if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
hw_dbg("PHY Address %u is out of range\n", offset);
- return -E1000_ERR_PARAM;
+ goto out;
}
- /*
- * Set up Op-code, Phy Address, and register address in the I2CCMD
- * register. The MAC will take care of interfacing with the
- * PHY to retrieve the desired data.
- */
- i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
- (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
- (E1000_I2CCMD_OPCODE_READ));
-
- wr32(E1000_I2CCMD, i2ccmd);
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
- /* Poll the ready bit to see if the I2C read completed */
- for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
- udelay(50);
- i2ccmd = rd32(E1000_I2CCMD);
- if (i2ccmd & E1000_I2CCMD_READY)
- break;
- }
- if (!(i2ccmd & E1000_I2CCMD_READY)) {
- hw_dbg("I2CCMD Read did not complete\n");
- return -E1000_ERR_PHY;
- }
- if (i2ccmd & E1000_I2CCMD_ERROR) {
- hw_dbg("I2CCMD Error bit set\n");
- return -E1000_ERR_PHY;
- }
+ ret_val = igb_read_phy_reg_i2c(hw, offset, data);
- /* Need to byte-swap the 16-bit value. */
- *data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00);
+ hw->phy.ops.release(hw);
- return 0;
+out:
+ return ret_val;
}
/**
@@ -327,47 +309,24 @@ static s32 igb_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
u16 data)
{
- struct e1000_phy_info *phy = &hw->phy;
- u32 i, i2ccmd = 0;
- u16 phy_data_swapped;
+ s32 ret_val = -E1000_ERR_PARAM;
+
if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
hw_dbg("PHY Address %d is out of range\n", offset);
- return -E1000_ERR_PARAM;
+ goto out;
}
- /* Swap the data bytes for the I2C interface */
- phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ goto out;
- /*
- * Set up Op-code, Phy Address, and register address in the I2CCMD
- * register. The MAC will take care of interfacing with the
- * PHY to retrieve the desired data.
- */
- i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
- (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
- E1000_I2CCMD_OPCODE_WRITE |
- phy_data_swapped);
-
- wr32(E1000_I2CCMD, i2ccmd);
-
- /* Poll the ready bit to see if the I2C read completed */
- for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
- udelay(50);
- i2ccmd = rd32(E1000_I2CCMD);
- if (i2ccmd & E1000_I2CCMD_READY)
- break;
- }
- if (!(i2ccmd & E1000_I2CCMD_READY)) {
- hw_dbg("I2CCMD Write did not complete\n");
- return -E1000_ERR_PHY;
- }
- if (i2ccmd & E1000_I2CCMD_ERROR) {
- hw_dbg("I2CCMD Error bit set\n");
- return -E1000_ERR_PHY;
- }
+ ret_val = igb_write_phy_reg_i2c(hw, offset, data);
- return 0;
+ hw->phy.ops.release(hw);
+
+out:
+ return ret_val;
}
/**
@@ -706,9 +665,7 @@ static s32 igb_check_for_link_82575(struct e1000_hw *hw)
s32 ret_val;
u16 speed, duplex;
- /* SGMII link check is done through the PCS register. */
- if ((hw->phy.media_type != e1000_media_type_copper) ||
- (igb_sgmii_active_82575(hw))) {
+ if (hw->phy.media_type != e1000_media_type_copper) {
ret_val = igb_get_pcs_speed_and_duplex_82575(hw, &speed,
&duplex);
/*
@@ -723,6 +680,7 @@ static s32 igb_check_for_link_82575(struct e1000_hw *hw)
return ret_val;
}
+
/**
* igb_get_pcs_speed_and_duplex_82575 - Retrieve current speed/duplex
* @hw: pointer to the HW structure
@@ -788,13 +746,23 @@ static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, u16 *speed,
void igb_shutdown_serdes_link_82575(struct e1000_hw *hw)
{
u32 reg;
+ u16 eeprom_data = 0;
if (hw->phy.media_type != e1000_media_type_internal_serdes ||
igb_sgmii_active_82575(hw))
return;
- /* if the management interface is not enabled, then power down */
- if (!igb_enable_mng_pass_thru(hw)) {
+ if (hw->bus.func == E1000_FUNC_0)
+ hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
+ else if (hw->bus.func == E1000_FUNC_1)
+ hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data);
+
+ /*
+ * If APM is not enabled in the EEPROM and management interface is
+ * not enabled, then power down.
+ */
+ if (!(eeprom_data & E1000_NVM_APME_82575) &&
+ !igb_enable_mng_pass_thru(hw)) {
/* Disable PCS to turn off link */
reg = rd32(E1000_PCS_CFG0);
reg &= ~E1000_PCS_CFG_PCS_EN;
@@ -908,6 +876,11 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw)
for (i = 0; i < mac->mta_reg_count; i++)
array_wr32(E1000_MTA, i, 0);
+ /* Zero out the Unicast HASH table */
+ hw_dbg("Zeroing the UTA\n");
+ for (i = 0; i < mac->uta_reg_count; i++)
+ array_wr32(E1000_UTA, i, 0);
+
/* Setup link and flow control */
ret_val = igb_setup_link(hw);
@@ -934,7 +907,6 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
{
u32 ctrl;
s32 ret_val;
- bool link;
ctrl = rd32(E1000_CTRL);
ctrl |= E1000_CTRL_SLU;
@@ -967,53 +939,19 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
if (ret_val)
goto out;
- if (hw->mac.autoneg) {
- /*
- * Setup autoneg and flow control advertisement
- * and perform autonegotiation.
- */
- ret_val = igb_copper_link_autoneg(hw);
- if (ret_val)
- goto out;
- } else {
- /*
- * PHY will be set to 10H, 10F, 100H or 100F
- * depending on user settings.
- */
- hw_dbg("Forcing Speed and Duplex\n");
- ret_val = hw->phy.ops.force_speed_duplex(hw);
- if (ret_val) {
- hw_dbg("Error Forcing Speed and Duplex\n");
- goto out;
- }
- }
-
- /*
- * Check link status. Wait up to 100 microseconds for link to become
- * valid.
- */
- ret_val = igb_phy_has_link(hw, COPPER_LINK_UP_LIMIT, 10, &link);
- if (ret_val)
- goto out;
-
- if (link) {
- hw_dbg("Valid link established!!!\n");
- /* Config the MAC and PHY after link is up */
- igb_config_collision_dist(hw);
- ret_val = igb_config_fc_after_link_up(hw);
- } else {
- hw_dbg("Unable to establish link!!!\n");
- }
-
+ ret_val = igb_setup_copper_link(hw);
out:
return ret_val;
}
/**
- * igb_setup_serdes_link_82575 - Setup link for fiber/serdes
+ * igb_setup_serdes_link_82575 - Setup link for serdes
* @hw: pointer to the HW structure
*
- * Configures speed and duplex for fiber and serdes links.
+ * Configure the physical coding sub-layer (PCS) link. The PCS link is
+ * used on copper connections where the serialized gigabit media independent
+ * interface (sgmii), or serdes fiber is being used. Configures the link
+ * for auto-negotiation or forces speed/duplex.
**/
static s32 igb_setup_serdes_link_82575(struct e1000_hw *hw)
{
@@ -1086,18 +1024,27 @@ static s32 igb_setup_serdes_link_82575(struct e1000_hw *hw)
*/
if (hw->mac.autoneg || igb_sgmii_active_82575(hw)) {
/* Set PCS register for autoneg */
- reg |= E1000_PCS_LCTL_FSV_1000 | /* Force 1000 */
- E1000_PCS_LCTL_FDV_FULL | /* SerDes Full duplex */
- E1000_PCS_LCTL_AN_ENABLE | /* Enable Autoneg */
- E1000_PCS_LCTL_AN_RESTART; /* Restart autoneg */
+ reg |= E1000_PCS_LCTL_FSV_1000 | /* Force 1000 */
+ E1000_PCS_LCTL_FDV_FULL | /* SerDes Full dplx */
+ E1000_PCS_LCTL_AN_ENABLE | /* Enable Autoneg */
+ E1000_PCS_LCTL_AN_RESTART; /* Restart autoneg */
hw_dbg("Configuring Autoneg; PCS_LCTL = 0x%08X\n", reg);
} else {
- /* Set PCS register for forced speed */
- reg |= E1000_PCS_LCTL_FLV_LINK_UP | /* Force link up */
- E1000_PCS_LCTL_FSV_1000 | /* Force 1000 */
- E1000_PCS_LCTL_FDV_FULL | /* SerDes Full duplex */
- E1000_PCS_LCTL_FSD | /* Force Speed */
- E1000_PCS_LCTL_FORCE_LINK; /* Force Link */
+ /* Check for duplex first */
+ if (hw->mac.forced_speed_duplex & E1000_ALL_FULL_DUPLEX)
+ reg |= E1000_PCS_LCTL_FDV_FULL;
+
+ /* No need to check for 1000/full since the spec states that
+ * it requires autoneg to be enabled */
+ /* Now set speed */
+ if (hw->mac.forced_speed_duplex & E1000_ALL_100_SPEED)
+ reg |= E1000_PCS_LCTL_FSV_100;
+
+ /* Force speed and force link */
+ reg |= E1000_PCS_LCTL_FSD |
+ E1000_PCS_LCTL_FORCE_LINK |
+ E1000_PCS_LCTL_FLV_LINK_UP;
+
hw_dbg("Configuring Forced Link; PCS_LCTL = 0x%08X\n", reg);
}
@@ -1167,9 +1114,18 @@ static s32 igb_read_mac_addr_82575(struct e1000_hw *hw)
{
s32 ret_val = 0;
- if (igb_check_alt_mac_addr(hw))
- ret_val = igb_read_mac_addr(hw);
+ /*
+ * If there's an alternate MAC address place it in RAR0
+ * so that it will override the Si installed default perm
+ * address.
+ */
+ ret_val = igb_check_alt_mac_addr(hw);
+ if (ret_val)
+ goto out;
+
+ ret_val = igb_read_mac_addr(hw);
+out:
return ret_val;
}
@@ -1181,61 +1137,59 @@ static s32 igb_read_mac_addr_82575(struct e1000_hw *hw)
**/
static void igb_clear_hw_cntrs_82575(struct e1000_hw *hw)
{
- u32 temp;
-
igb_clear_hw_cntrs_base(hw);
- temp = rd32(E1000_PRC64);
- temp = rd32(E1000_PRC127);
- temp = rd32(E1000_PRC255);
- temp = rd32(E1000_PRC511);
- temp = rd32(E1000_PRC1023);
- temp = rd32(E1000_PRC1522);
- temp = rd32(E1000_PTC64);
- temp = rd32(E1000_PTC127);
- temp = rd32(E1000_PTC255);
- temp = rd32(E1000_PTC511);
- temp = rd32(E1000_PTC1023);
- temp = rd32(E1000_PTC1522);
-
- temp = rd32(E1000_ALGNERRC);
- temp = rd32(E1000_RXERRC);
- temp = rd32(E1000_TNCRS);
- temp = rd32(E1000_CEXTERR);
- temp = rd32(E1000_TSCTC);
- temp = rd32(E1000_TSCTFC);
-
- temp = rd32(E1000_MGTPRC);
- temp = rd32(E1000_MGTPDC);
- temp = rd32(E1000_MGTPTC);
-
- temp = rd32(E1000_IAC);
- temp = rd32(E1000_ICRXOC);
-
- temp = rd32(E1000_ICRXPTC);
- temp = rd32(E1000_ICRXATC);
- temp = rd32(E1000_ICTXPTC);
- temp = rd32(E1000_ICTXATC);
- temp = rd32(E1000_ICTXQEC);
- temp = rd32(E1000_ICTXQMTC);
- temp = rd32(E1000_ICRXDMTC);
-
- temp = rd32(E1000_CBTMPC);
- temp = rd32(E1000_HTDPMC);
- temp = rd32(E1000_CBRMPC);
- temp = rd32(E1000_RPTHC);
- temp = rd32(E1000_HGPTC);
- temp = rd32(E1000_HTCBDPC);
- temp = rd32(E1000_HGORCL);
- temp = rd32(E1000_HGORCH);
- temp = rd32(E1000_HGOTCL);
- temp = rd32(E1000_HGOTCH);
- temp = rd32(E1000_LENERRS);
+ rd32(E1000_PRC64);
+ rd32(E1000_PRC127);
+ rd32(E1000_PRC255);
+ rd32(E1000_PRC511);
+ rd32(E1000_PRC1023);
+ rd32(E1000_PRC1522);
+ rd32(E1000_PTC64);
+ rd32(E1000_PTC127);
+ rd32(E1000_PTC255);
+ rd32(E1000_PTC511);
+ rd32(E1000_PTC1023);
+ rd32(E1000_PTC1522);
+
+ rd32(E1000_ALGNERRC);
+ rd32(E1000_RXERRC);
+ rd32(E1000_TNCRS);
+ rd32(E1000_CEXTERR);
+ rd32(E1000_TSCTC);
+ rd32(E1000_TSCTFC);
+
+ rd32(E1000_MGTPRC);
+ rd32(E1000_MGTPDC);
+ rd32(E1000_MGTPTC);
+
+ rd32(E1000_IAC);
+ rd32(E1000_ICRXOC);
+
+ rd32(E1000_ICRXPTC);
+ rd32(E1000_ICRXATC);
+ rd32(E1000_ICTXPTC);
+ rd32(E1000_ICTXATC);
+ rd32(E1000_ICTXQEC);
+ rd32(E1000_ICTXQMTC);
+ rd32(E1000_ICRXDMTC);
+
+ rd32(E1000_CBTMPC);
+ rd32(E1000_HTDPMC);
+ rd32(E1000_CBRMPC);
+ rd32(E1000_RPTHC);
+ rd32(E1000_HGPTC);
+ rd32(E1000_HTCBDPC);
+ rd32(E1000_HGORCL);
+ rd32(E1000_HGORCH);
+ rd32(E1000_HGOTCL);
+ rd32(E1000_HGOTCH);
+ rd32(E1000_LENERRS);
/* This register should not be read in copper configurations */
if (hw->phy.media_type == e1000_media_type_internal_serdes ||
igb_sgmii_active_82575(hw))
- temp = rd32(E1000_SCVPC);
+ rd32(E1000_SCVPC);
}
/**
diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h
index ebd146fd4e15..7be3a0b6a057 100644
--- a/drivers/net/igb/e1000_82575.h
+++ b/drivers/net/igb/e1000_82575.h
@@ -167,6 +167,7 @@ struct e1000_adv_tx_context_desc {
#define E1000_DCA_TXCTRL_CPUID_SHIFT 24 /* Tx CPUID now in the last byte */
#define E1000_DCA_RXCTRL_CPUID_SHIFT 24 /* Rx CPUID now in the last byte */
+#define E1000_NVM_APME_82575 0x0400
#define MAX_NUM_VFS 8
#define E1000_DTXSWC_VMDQ_LOOPBACK_EN (1 << 31) /* global VF LB enable */
diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h
index 119869b1124d..2dc929419df0 100644
--- a/drivers/net/igb/e1000_hw.h
+++ b/drivers/net/igb/e1000_hw.h
@@ -42,6 +42,7 @@ struct e1000_hw;
#define E1000_DEV_ID_82576_SERDES 0x10E7
#define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8
#define E1000_DEV_ID_82576_NS 0x150A
+#define E1000_DEV_ID_82576_NS_SERDES 0x1518
#define E1000_DEV_ID_82576_SERDES_QUAD 0x150D
#define E1000_DEV_ID_82575EB_COPPER 0x10A7
#define E1000_DEV_ID_82575EB_FIBER_SERDES 0x10A9
@@ -50,8 +51,11 @@ struct e1000_hw;
#define E1000_REVISION_2 2
#define E1000_REVISION_4 4
+#define E1000_FUNC_0 0
#define E1000_FUNC_1 1
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1 3
+
enum e1000_mac_type {
e1000_undefined = 0,
e1000_82575,
@@ -70,7 +74,6 @@ enum e1000_nvm_type {
e1000_nvm_unknown = 0,
e1000_nvm_none,
e1000_nvm_eeprom_spi,
- e1000_nvm_eeprom_microwire,
e1000_nvm_flash_hw,
e1000_nvm_flash_sw
};
@@ -79,8 +82,6 @@ enum e1000_nvm_override {
e1000_nvm_override_none = 0,
e1000_nvm_override_spi_small,
e1000_nvm_override_spi_large,
- e1000_nvm_override_microwire_small,
- e1000_nvm_override_microwire_large
};
enum e1000_phy_type {
@@ -339,6 +340,7 @@ struct e1000_mac_info {
u16 ifs_ratio;
u16 ifs_step_size;
u16 mta_reg_count;
+ u16 uta_reg_count;
/* Maximum size of the MTA register table in all supported adapters */
#define MAX_MTA_REG 128
diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c
index 7d76bb085e10..2ad358a240bf 100644
--- a/drivers/net/igb/e1000_mac.c
+++ b/drivers/net/igb/e1000_mac.c
@@ -185,13 +185,12 @@ s32 igb_check_alt_mac_addr(struct e1000_hw *hw)
}
if (nvm_alt_mac_addr_offset == 0xFFFF) {
- ret_val = -(E1000_NOT_IMPLEMENTED);
+ /* There is no Alternate MAC Address */
goto out;
}
if (hw->bus.func == E1000_FUNC_1)
- nvm_alt_mac_addr_offset += ETH_ALEN/sizeof(u16);
-
+ nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1;
for (i = 0; i < ETH_ALEN; i += 2) {
offset = nvm_alt_mac_addr_offset + (i >> 1);
ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
@@ -206,14 +205,16 @@ s32 igb_check_alt_mac_addr(struct e1000_hw *hw)
/* if multicast bit is set, the alternate address will not be used */
if (alt_mac_addr[0] & 0x01) {
- ret_val = -(E1000_NOT_IMPLEMENTED);
+ hw_dbg("Ignoring Alternate Mac Address with MC bit set\n");
goto out;
}
- for (i = 0; i < ETH_ALEN; i++)
- hw->mac.addr[i] = hw->mac.perm_addr[i] = alt_mac_addr[i];
-
- hw->mac.ops.rar_set(hw, hw->mac.perm_addr, 0);
+ /*
+ * We have a valid alternate MAC address, and we want to treat it the
+ * same as the normal permanent MAC address stored by the HW into the
+ * RAR. Do this by mapping this address into RAR0.
+ */
+ hw->mac.ops.rar_set(hw, alt_mac_addr, 0);
out:
return ret_val;
@@ -246,8 +247,15 @@ void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index)
if (rar_low || rar_high)
rar_high |= E1000_RAH_AV;
+ /*
+ * Some bridges will combine consecutive 32-bit writes into
+ * a single burst write, which will malfunction on some parts.
+ * The flushes avoid this.
+ */
wr32(E1000_RAL(index), rar_low);
+ wrfl();
wr32(E1000_RAH(index), rar_high);
+ wrfl();
}
/**
@@ -399,45 +407,43 @@ void igb_update_mc_addr_list(struct e1000_hw *hw,
**/
void igb_clear_hw_cntrs_base(struct e1000_hw *hw)
{
- u32 temp;
-
- temp = rd32(E1000_CRCERRS);
- temp = rd32(E1000_SYMERRS);
- temp = rd32(E1000_MPC);
- temp = rd32(E1000_SCC);
- temp = rd32(E1000_ECOL);
- temp = rd32(E1000_MCC);
- temp = rd32(E1000_LATECOL);
- temp = rd32(E1000_COLC);
- temp = rd32(E1000_DC);
- temp = rd32(E1000_SEC);
- temp = rd32(E1000_RLEC);
- temp = rd32(E1000_XONRXC);
- temp = rd32(E1000_XONTXC);
- temp = rd32(E1000_XOFFRXC);
- temp = rd32(E1000_XOFFTXC);
- temp = rd32(E1000_FCRUC);
- temp = rd32(E1000_GPRC);
- temp = rd32(E1000_BPRC);
- temp = rd32(E1000_MPRC);
- temp = rd32(E1000_GPTC);
- temp = rd32(E1000_GORCL);
- temp = rd32(E1000_GORCH);
- temp = rd32(E1000_GOTCL);
- temp = rd32(E1000_GOTCH);
- temp = rd32(E1000_RNBC);
- temp = rd32(E1000_RUC);
- temp = rd32(E1000_RFC);
- temp = rd32(E1000_ROC);
- temp = rd32(E1000_RJC);
- temp = rd32(E1000_TORL);
- temp = rd32(E1000_TORH);
- temp = rd32(E1000_TOTL);
- temp = rd32(E1000_TOTH);
- temp = rd32(E1000_TPR);
- temp = rd32(E1000_TPT);
- temp = rd32(E1000_MPTC);
- temp = rd32(E1000_BPTC);
+ rd32(E1000_CRCERRS);
+ rd32(E1000_SYMERRS);
+ rd32(E1000_MPC);
+ rd32(E1000_SCC);
+ rd32(E1000_ECOL);
+ rd32(E1000_MCC);
+ rd32(E1000_LATECOL);
+ rd32(E1000_COLC);
+ rd32(E1000_DC);
+ rd32(E1000_SEC);
+ rd32(E1000_RLEC);
+ rd32(E1000_XONRXC);
+ rd32(E1000_XONTXC);
+ rd32(E1000_XOFFRXC);
+ rd32(E1000_XOFFTXC);
+ rd32(E1000_FCRUC);
+ rd32(E1000_GPRC);
+ rd32(E1000_BPRC);
+ rd32(E1000_MPRC);
+ rd32(E1000_GPTC);
+ rd32(E1000_GORCL);
+ rd32(E1000_GORCH);
+ rd32(E1000_GOTCL);
+ rd32(E1000_GOTCH);
+ rd32(E1000_RNBC);
+ rd32(E1000_RUC);
+ rd32(E1000_RFC);
+ rd32(E1000_ROC);
+ rd32(E1000_RJC);
+ rd32(E1000_TORL);
+ rd32(E1000_TORH);
+ rd32(E1000_TOTL);
+ rd32(E1000_TOTH);
+ rd32(E1000_TPR);
+ rd32(E1000_TPT);
+ rd32(E1000_MPTC);
+ rd32(E1000_BPTC);
}
/**
diff --git a/drivers/net/igb/e1000_mbx.c b/drivers/net/igb/e1000_mbx.c
index ed9058eca45c..c474cdb70047 100644
--- a/drivers/net/igb/e1000_mbx.c
+++ b/drivers/net/igb/e1000_mbx.c
@@ -143,12 +143,16 @@ static s32 igb_poll_for_msg(struct e1000_hw *hw, u16 mbx_id)
if (!countdown || !mbx->ops.check_for_msg)
goto out;
- while (mbx->ops.check_for_msg(hw, mbx_id)) {
+ while (countdown && mbx->ops.check_for_msg(hw, mbx_id)) {
countdown--;
if (!countdown)
break;
udelay(mbx->usec_delay);
}
+
+ /* if we failed, all future posted messages fail until reset */
+ if (!countdown)
+ mbx->timeout = 0;
out:
return countdown ? 0 : -E1000_ERR_MBX;
}
@@ -168,12 +172,16 @@ static s32 igb_poll_for_ack(struct e1000_hw *hw, u16 mbx_id)
if (!countdown || !mbx->ops.check_for_ack)
goto out;
- while (mbx->ops.check_for_ack(hw, mbx_id)) {
+ while (countdown && mbx->ops.check_for_ack(hw, mbx_id)) {
countdown--;
if (!countdown)
break;
udelay(mbx->usec_delay);
}
+
+ /* if we failed, all future posted messages fail until reset */
+ if (!countdown)
+ mbx->timeout = 0;
out:
return countdown ? 0 : -E1000_ERR_MBX;
}
@@ -217,12 +225,13 @@ out:
static s32 igb_write_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id)
{
struct e1000_mbx_info *mbx = &hw->mbx;
- s32 ret_val = 0;
+ s32 ret_val = -E1000_ERR_MBX;
- if (!mbx->ops.write)
+ /* exit if either we can't write or there isn't a defined timeout */
+ if (!mbx->ops.write || !mbx->timeout)
goto out;
- /* send msg*/
+ /* send msg */
ret_val = mbx->ops.write(hw, msg, size, mbx_id);
/* if msg sent wait until we receive an ack */
@@ -305,6 +314,30 @@ static s32 igb_check_for_rst_pf(struct e1000_hw *hw, u16 vf_number)
}
/**
+ * igb_obtain_mbx_lock_pf - obtain mailbox lock
+ * @hw: pointer to the HW structure
+ * @vf_number: the VF index
+ *
+ * return SUCCESS if we obtained the mailbox lock
+ **/
+static s32 igb_obtain_mbx_lock_pf(struct e1000_hw *hw, u16 vf_number)
+{
+ s32 ret_val = -E1000_ERR_MBX;
+ u32 p2v_mailbox;
+
+
+ /* Take ownership of the buffer */
+ wr32(E1000_P2VMAILBOX(vf_number), E1000_P2VMAILBOX_PFU);
+
+ /* reserve mailbox for vf use */
+ p2v_mailbox = rd32(E1000_P2VMAILBOX(vf_number));
+ if (p2v_mailbox & E1000_P2VMAILBOX_PFU)
+ ret_val = 0;
+
+ return ret_val;
+}
+
+/**
* igb_write_mbx_pf - Places a message in the mailbox
* @hw: pointer to the HW structure
* @msg: The message buffer
@@ -316,27 +349,17 @@ static s32 igb_check_for_rst_pf(struct e1000_hw *hw, u16 vf_number)
static s32 igb_write_mbx_pf(struct e1000_hw *hw, u32 *msg, u16 size,
u16 vf_number)
{
- u32 p2v_mailbox;
- s32 ret_val = 0;
+ s32 ret_val;
u16 i;
- /* Take ownership of the buffer */
- wr32(E1000_P2VMAILBOX(vf_number), E1000_P2VMAILBOX_PFU);
-
- /* Make sure we have ownership now... */
- p2v_mailbox = rd32(E1000_P2VMAILBOX(vf_number));
- if (!(p2v_mailbox & E1000_P2VMAILBOX_PFU)) {
- /* failed to grab ownership */
- ret_val = -E1000_ERR_MBX;
+ /* lock the mailbox to prevent pf/vf race condition */
+ ret_val = igb_obtain_mbx_lock_pf(hw, vf_number);
+ if (ret_val)
goto out_no_write;
- }
- /*
- * flush any ack or msg which may already be in the queue
- * as they are likely the result of an error
- */
- igb_check_for_ack_pf(hw, vf_number);
+ /* flush msg and acks as we are overwriting the message buffer */
igb_check_for_msg_pf(hw, vf_number);
+ igb_check_for_ack_pf(hw, vf_number);
/* copy the caller specified message to the mailbox memory buffer */
for (i = 0; i < size; i++)
@@ -367,20 +390,13 @@ out_no_write:
static s32 igb_read_mbx_pf(struct e1000_hw *hw, u32 *msg, u16 size,
u16 vf_number)
{
- u32 p2v_mailbox;
- s32 ret_val = 0;
+ s32 ret_val;
u16 i;
- /* Take ownership of the buffer */
- wr32(E1000_P2VMAILBOX(vf_number), E1000_P2VMAILBOX_PFU);
-
- /* Make sure we have ownership now... */
- p2v_mailbox = rd32(E1000_P2VMAILBOX(vf_number));
- if (!(p2v_mailbox & E1000_P2VMAILBOX_PFU)) {
- /* failed to grab ownership */
- ret_val = -E1000_ERR_MBX;
+ /* lock the mailbox to prevent pf/vf race condition */
+ ret_val = igb_obtain_mbx_lock_pf(hw, vf_number);
+ if (ret_val)
goto out_no_read;
- }
/* copy the message to the mailbox memory buffer */
for (i = 0; i < size; i++)
@@ -392,8 +408,6 @@ static s32 igb_read_mbx_pf(struct e1000_hw *hw, u32 *msg, u16 size,
/* update stats */
hw->mbx.stats.msgs_rx++;
- ret_val = 0;
-
out_no_read:
return ret_val;
}
diff --git a/drivers/net/igb/e1000_nvm.c b/drivers/net/igb/e1000_nvm.c
index a88bfe2f1e8f..d83b77fa4038 100644
--- a/drivers/net/igb/e1000_nvm.c
+++ b/drivers/net/igb/e1000_nvm.c
@@ -78,9 +78,7 @@ static void igb_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count)
u32 mask;
mask = 0x01 << (count - 1);
- if (nvm->type == e1000_nvm_eeprom_microwire)
- eecd &= ~E1000_EECD_DO;
- else if (nvm->type == e1000_nvm_eeprom_spi)
+ if (nvm->type == e1000_nvm_eeprom_spi)
eecd |= E1000_EECD_DO;
do {
@@ -220,22 +218,7 @@ static void igb_standby_nvm(struct e1000_hw *hw)
struct e1000_nvm_info *nvm = &hw->nvm;
u32 eecd = rd32(E1000_EECD);
- if (nvm->type == e1000_nvm_eeprom_microwire) {
- eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
- wr32(E1000_EECD, eecd);
- wrfl();
- udelay(nvm->delay_usec);
-
- igb_raise_eec_clk(hw, &eecd);
-
- /* Select EEPROM */
- eecd |= E1000_EECD_CS;
- wr32(E1000_EECD, eecd);
- wrfl();
- udelay(nvm->delay_usec);
-
- igb_lower_eec_clk(hw, &eecd);
- } else if (nvm->type == e1000_nvm_eeprom_spi) {
+ if (nvm->type == e1000_nvm_eeprom_spi) {
/* Toggle CS to flush commands */
eecd |= E1000_EECD_CS;
wr32(E1000_EECD, eecd);
@@ -263,12 +246,6 @@ static void e1000_stop_nvm(struct e1000_hw *hw)
/* Pull CS high */
eecd |= E1000_EECD_CS;
igb_lower_eec_clk(hw, &eecd);
- } else if (hw->nvm.type == e1000_nvm_eeprom_microwire) {
- /* CS on Microcwire is active-high */
- eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
- wr32(E1000_EECD, eecd);
- igb_raise_eec_clk(hw, &eecd);
- igb_lower_eec_clk(hw, &eecd);
}
}
@@ -304,14 +281,7 @@ static s32 igb_ready_nvm_eeprom(struct e1000_hw *hw)
u8 spi_stat_reg;
- if (nvm->type == e1000_nvm_eeprom_microwire) {
- /* Clear SK and DI */
- eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
- wr32(E1000_EECD, eecd);
- /* Set CS */
- eecd |= E1000_EECD_CS;
- wr32(E1000_EECD, eecd);
- } else if (nvm->type == e1000_nvm_eeprom_spi) {
+ if (nvm->type == e1000_nvm_eeprom_spi) {
/* Clear SK and CS */
eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
wr32(E1000_EECD, eecd);
diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c
index ee460600e74b..83b706c460b3 100644
--- a/drivers/net/igb/e1000_phy.c
+++ b/drivers/net/igb/e1000_phy.c
@@ -39,6 +39,9 @@ static s32 igb_wait_autoneg(struct e1000_hw *hw);
/* Cable length tables */
static const u16 e1000_m88_cable_length_table[] =
{ 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
+#define M88E1000_CABLE_LENGTH_TABLE_SIZE \
+ (sizeof(e1000_m88_cable_length_table) / \
+ sizeof(e1000_m88_cable_length_table[0]))
static const u16 e1000_igp_2_cable_length_table[] =
{ 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
@@ -109,7 +112,10 @@ out:
**/
static s32 igb_phy_reset_dsp(struct e1000_hw *hw)
{
- s32 ret_val;
+ s32 ret_val = 0;
+
+ if (!(hw->phy.ops.write_reg))
+ goto out;
ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
if (ret_val)
@@ -239,6 +245,103 @@ out:
}
/**
+ * igb_read_phy_reg_i2c - Read PHY register using i2c
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the PHY register at offset using the i2c interface and stores the
+ * retrieved information in data.
+ **/
+s32 igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ u32 i, i2ccmd = 0;
+
+
+ /*
+ * Set up Op-code, Phy Address, and register address in the I2CCMD
+ * register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+ */
+ i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
+ (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
+ (E1000_I2CCMD_OPCODE_READ));
+
+ wr32(E1000_I2CCMD, i2ccmd);
+
+ /* Poll the ready bit to see if the I2C read completed */
+ for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
+ udelay(50);
+ i2ccmd = rd32(E1000_I2CCMD);
+ if (i2ccmd & E1000_I2CCMD_READY)
+ break;
+ }
+ if (!(i2ccmd & E1000_I2CCMD_READY)) {
+ hw_dbg("I2CCMD Read did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ if (i2ccmd & E1000_I2CCMD_ERROR) {
+ hw_dbg("I2CCMD Error bit set\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* Need to byte-swap the 16-bit value. */
+ *data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00);
+
+ return 0;
+}
+
+/**
+ * igb_write_phy_reg_i2c - Write PHY register using i2c
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Writes the data to PHY register at the offset using the i2c interface.
+ **/
+s32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ u32 i, i2ccmd = 0;
+ u16 phy_data_swapped;
+
+
+ /* Swap the data bytes for the I2C interface */
+ phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
+
+ /*
+ * Set up Op-code, Phy Address, and register address in the I2CCMD
+ * register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+ */
+ i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
+ (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
+ E1000_I2CCMD_OPCODE_WRITE |
+ phy_data_swapped);
+
+ wr32(E1000_I2CCMD, i2ccmd);
+
+ /* Poll the ready bit to see if the I2C read completed */
+ for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
+ udelay(50);
+ i2ccmd = rd32(E1000_I2CCMD);
+ if (i2ccmd & E1000_I2CCMD_READY)
+ break;
+ }
+ if (!(i2ccmd & E1000_I2CCMD_READY)) {
+ hw_dbg("I2CCMD Write did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ if (i2ccmd & E1000_I2CCMD_ERROR) {
+ hw_dbg("I2CCMD Error bit set\n");
+ return -E1000_ERR_PHY;
+ }
+
+ return 0;
+}
+
+/**
* igb_read_phy_reg_igp - Read igp PHY register
* @hw: pointer to the HW structure
* @offset: register offset to be read
@@ -572,7 +675,7 @@ out:
* and restart the negotiation process between the link partner. If
* autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
**/
-s32 igb_copper_link_autoneg(struct e1000_hw *hw)
+static s32 igb_copper_link_autoneg(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
s32 ret_val;
@@ -796,6 +899,65 @@ out:
}
/**
+ * igb_setup_copper_link - Configure copper link settings
+ * @hw: pointer to the HW structure
+ *
+ * Calls the appropriate function to configure the link for auto-neg or forced
+ * speed and duplex. Then we check for link, once link is established calls
+ * to configure collision distance and flow control are called. If link is
+ * not established, we return -E1000_ERR_PHY (-2).
+ **/
+s32 igb_setup_copper_link(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ bool link;
+
+
+ if (hw->mac.autoneg) {
+ /*
+ * Setup autoneg and flow control advertisement and perform
+ * autonegotiation.
+ */
+ ret_val = igb_copper_link_autoneg(hw);
+ if (ret_val)
+ goto out;
+ } else {
+ /*
+ * PHY will be set to 10H, 10F, 100H or 100F
+ * depending on user settings.
+ */
+ hw_dbg("Forcing Speed and Duplex\n");
+ ret_val = hw->phy.ops.force_speed_duplex(hw);
+ if (ret_val) {
+ hw_dbg("Error Forcing Speed and Duplex\n");
+ goto out;
+ }
+ }
+
+ /*
+ * Check link status. Wait up to 100 microseconds for link to become
+ * valid.
+ */
+ ret_val = igb_phy_has_link(hw,
+ COPPER_LINK_UP_LIMIT,
+ 10,
+ &link);
+ if (ret_val)
+ goto out;
+
+ if (link) {
+ hw_dbg("Valid link established!!!\n");
+ igb_config_collision_dist(hw);
+ ret_val = igb_config_fc_after_link_up(hw);
+ } else {
+ hw_dbg("Unable to establish link!!!\n");
+ }
+
+out:
+ return ret_val;
+}
+
+/**
* igb_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
* @hw: pointer to the HW structure
*
@@ -903,22 +1065,19 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
igb_phy_force_speed_duplex_setup(hw, &phy_data);
- /* Reset the phy to commit changes. */
- phy_data |= MII_CR_RESET;
-
ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
if (ret_val)
goto out;
- udelay(1);
+ /* Reset the phy to commit changes. */
+ ret_val = igb_phy_sw_reset(hw);
+ if (ret_val)
+ goto out;
if (phy->autoneg_wait_to_complete) {
hw_dbg("Waiting for forced speed/duplex link on M88 phy.\n");
- ret_val = igb_phy_has_link(hw,
- PHY_FORCE_LIMIT,
- 100000,
- &link);
+ ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT, 100000, &link);
if (ret_val)
goto out;
@@ -928,8 +1087,8 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
* Reset the DSP and cross our fingers.
*/
ret_val = phy->ops.write_reg(hw,
- M88E1000_PHY_PAGE_SELECT,
- 0x001d);
+ M88E1000_PHY_PAGE_SELECT,
+ 0x001d);
if (ret_val)
goto out;
ret_val = igb_phy_reset_dsp(hw);
@@ -939,7 +1098,7 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
/* Try once more */
ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT,
- 100000, &link);
+ 100000, &link);
if (ret_val)
goto out;
}
@@ -1051,9 +1210,12 @@ static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw,
s32 igb_set_d3_lplu_state(struct e1000_hw *hw, bool active)
{
struct e1000_phy_info *phy = &hw->phy;
- s32 ret_val;
+ s32 ret_val = 0;
u16 data;
+ if (!(hw->phy.ops.read_reg))
+ goto out;
+
ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
if (ret_val)
goto out;
@@ -1288,8 +1450,14 @@ s32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations,
* it across the board.
*/
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
- if (ret_val)
- break;
+ if (ret_val) {
+ /*
+ * If the first read fails, another entity may have
+ * ownership of the resources, wait and try again to
+ * see if they have relinquished the resources yet.
+ */
+ udelay(usec_interval);
+ }
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
if (ret_val)
break;
@@ -1333,8 +1501,13 @@ s32 igb_get_cable_length_m88(struct e1000_hw *hw)
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->max_cable_length = e1000_m88_cable_length_table[index + 1];
phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
diff --git a/drivers/net/igb/e1000_phy.h b/drivers/net/igb/e1000_phy.h
index ebe4b616db8a..adb9436b7336 100644
--- a/drivers/net/igb/e1000_phy.h
+++ b/drivers/net/igb/e1000_phy.h
@@ -43,7 +43,6 @@ enum e1000_smart_speed {
s32 igb_check_downshift(struct e1000_hw *hw);
s32 igb_check_reset_block(struct e1000_hw *hw);
-s32 igb_copper_link_autoneg(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_phy_force_speed_duplex_igp(struct e1000_hw *hw);
@@ -57,10 +56,13 @@ s32 igb_phy_sw_reset(struct e1000_hw *hw);
s32 igb_phy_hw_reset(struct e1000_hw *hw);
s32 igb_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
s32 igb_set_d3_lplu_state(struct e1000_hw *hw, bool active);
+s32 igb_setup_copper_link(struct e1000_hw *hw);
s32 igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
s32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations,
u32 usec_interval, bool *success);
s32 igb_phy_init_script_igp3(struct e1000_hw *hw);
+s32 igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data);
/* IGP01E1000 Specific Registers */
#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */
diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h
index 345d1442d6d6..76c338929f68 100644
--- a/drivers/net/igb/e1000_regs.h
+++ b/drivers/net/igb/e1000_regs.h
@@ -331,6 +331,7 @@ enum {
#define E1000_QDE 0x02408 /* Queue Drop Enable - RW */
#define E1000_DTXSWC 0x03500 /* DMA Tx Switch Control - RW */
#define E1000_RPLOLR 0x05AF0 /* Replication Offload - RW */
+#define E1000_UTA 0x0A000 /* Unicast Table Array - RW */
#define E1000_IOVTCL 0x05BBC /* IOV Control Register */
/* These act per VF so an array friendly macro is used */
#define E1000_P2VMAILBOX(_n) (0x00C00 + (4 * (_n)))
diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h
index 7126fea26fec..b805b1c63f80 100644
--- a/drivers/net/igb/igb.h
+++ b/drivers/net/igb/igb.h
@@ -256,7 +256,6 @@ struct igb_adapter {
struct net_device *netdev;
struct napi_struct napi;
struct pci_dev *pdev;
- struct net_device_stats net_stats;
struct cyclecounter cycles;
struct timecounter clock;
struct timecompare compare;
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c
index deaea8fa1032..f7303d106ec2 100644
--- a/drivers/net/igb/igb_ethtool.c
+++ b/drivers/net/igb/igb_ethtool.c
@@ -38,14 +38,22 @@
#include "igb.h"
+enum {NETDEV_STATS, IGB_STATS};
+
struct igb_stats {
char stat_string[ETH_GSTRING_LEN];
+ int type;
int sizeof_stat;
int stat_offset;
};
-#define IGB_STAT(m) FIELD_SIZEOF(struct igb_adapter, m), \
- offsetof(struct igb_adapter, m)
+#define IGB_STAT(m) IGB_STATS, \
+ FIELD_SIZEOF(struct igb_adapter, m), \
+ offsetof(struct igb_adapter, m)
+#define IGB_NETDEV_STAT(m) NETDEV_STATS, \
+ FIELD_SIZEOF(struct net_device, m), \
+ offsetof(struct net_device, m)
+
static const struct igb_stats igb_gstrings_stats[] = {
{ "rx_packets", IGB_STAT(stats.gprc) },
{ "tx_packets", IGB_STAT(stats.gptc) },
@@ -55,22 +63,22 @@ static const struct igb_stats igb_gstrings_stats[] = {
{ "tx_broadcast", IGB_STAT(stats.bptc) },
{ "rx_multicast", IGB_STAT(stats.mprc) },
{ "tx_multicast", IGB_STAT(stats.mptc) },
- { "rx_errors", IGB_STAT(net_stats.rx_errors) },
- { "tx_errors", IGB_STAT(net_stats.tx_errors) },
- { "tx_dropped", IGB_STAT(net_stats.tx_dropped) },
+ { "rx_errors", IGB_NETDEV_STAT(stats.rx_errors) },
+ { "tx_errors", IGB_NETDEV_STAT(stats.tx_errors) },
+ { "tx_dropped", IGB_NETDEV_STAT(stats.tx_dropped) },
{ "multicast", IGB_STAT(stats.mprc) },
{ "collisions", IGB_STAT(stats.colc) },
- { "rx_length_errors", IGB_STAT(net_stats.rx_length_errors) },
- { "rx_over_errors", IGB_STAT(net_stats.rx_over_errors) },
+ { "rx_length_errors", IGB_NETDEV_STAT(stats.rx_length_errors) },
+ { "rx_over_errors", IGB_NETDEV_STAT(stats.rx_over_errors) },
{ "rx_crc_errors", IGB_STAT(stats.crcerrs) },
- { "rx_frame_errors", IGB_STAT(net_stats.rx_frame_errors) },
+ { "rx_frame_errors", IGB_NETDEV_STAT(stats.rx_frame_errors) },
{ "rx_no_buffer_count", IGB_STAT(stats.rnbc) },
- { "rx_queue_drop_packet_count", IGB_STAT(net_stats.rx_fifo_errors) },
+ { "rx_queue_drop_packet_count", IGB_NETDEV_STAT(stats.rx_fifo_errors) },
{ "rx_missed_errors", IGB_STAT(stats.mpc) },
{ "tx_aborted_errors", IGB_STAT(stats.ecol) },
{ "tx_carrier_errors", IGB_STAT(stats.tncrs) },
- { "tx_fifo_errors", IGB_STAT(net_stats.tx_fifo_errors) },
- { "tx_heartbeat_errors", IGB_STAT(net_stats.tx_heartbeat_errors) },
+ { "tx_fifo_errors", IGB_NETDEV_STAT(stats.tx_fifo_errors) },
+ { "tx_heartbeat_errors", IGB_NETDEV_STAT(stats.tx_heartbeat_errors) },
{ "tx_window_errors", IGB_STAT(stats.latecol) },
{ "tx_abort_late_coll", IGB_STAT(stats.latecol) },
{ "tx_deferred_ok", IGB_STAT(stats.dc) },
@@ -732,7 +740,7 @@ static int igb_set_ringparam(struct net_device *netdev,
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct igb_ring *temp_ring;
- int i, err;
+ int i, err = 0;
u32 new_rx_count, new_tx_count;
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
@@ -752,18 +760,30 @@ static int igb_set_ringparam(struct net_device *netdev,
return 0;
}
+ while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
+ msleep(1);
+
+ 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 (adapter->num_tx_queues > adapter->num_rx_queues)
temp_ring = vmalloc(adapter->num_tx_queues * sizeof(struct igb_ring));
else
temp_ring = vmalloc(adapter->num_rx_queues * sizeof(struct igb_ring));
- if (!temp_ring)
- return -ENOMEM;
- while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
- msleep(1);
+ if (!temp_ring) {
+ err = -ENOMEM;
+ goto clear_reset;
+ }
- if (netif_running(adapter->netdev))
- igb_down(adapter);
+ igb_down(adapter);
/*
* We can't just free everything and then setup again,
@@ -820,14 +840,11 @@ static int igb_set_ringparam(struct net_device *netdev,
adapter->rx_ring_count = new_rx_count;
}
-
- err = 0;
err_setup:
- if (netif_running(adapter->netdev))
- igb_up(adapter);
-
- clear_bit(__IGB_RESETTING, &adapter->state);
+ igb_up(adapter);
vfree(temp_ring);
+clear_reset:
+ clear_bit(__IGB_RESETTING, &adapter->state);
return err;
}
@@ -1958,10 +1975,21 @@ static void igb_get_ethtool_stats(struct net_device *netdev,
int stat_count_rx = sizeof(struct igb_rx_queue_stats) / sizeof(u64);
int j;
int i;
+ char *p = NULL;
igb_update_stats(adapter);
for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) {
- char *p = (char *)adapter+igb_gstrings_stats[i].stat_offset;
+ switch (igb_gstrings_stats[i].type) {
+ case NETDEV_STATS:
+ p = (char *) netdev +
+ igb_gstrings_stats[i].stat_offset;
+ break;
+ case IGB_STATS:
+ p = (char *) adapter +
+ igb_gstrings_stats[i].stat_offset;
+ break;
+ }
+
data[i] = (igb_gstrings_stats[i].sizeof_stat ==
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
}
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index 714c3a4a44ef..2ffe0997b838 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -63,6 +63,7 @@ static const struct e1000_info *igb_info_tbl[] = {
static struct pci_device_id igb_pci_tbl[] = {
{ 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 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_FIBER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES_QUAD), board_82575 },
@@ -106,6 +107,7 @@ static netdev_tx_t igb_xmit_frame_adv(struct sk_buff *skb,
static struct net_device_stats *igb_get_stats(struct net_device *);
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);
static irqreturn_t igb_intr(int irq, void *);
static irqreturn_t igb_intr_msi(int irq, void *);
static irqreturn_t igb_msix_other(int irq, void *);
@@ -127,10 +129,10 @@ static void igb_vlan_rx_register(struct net_device *, struct vlan_group *);
static void igb_vlan_rx_add_vid(struct net_device *, u16);
static void igb_vlan_rx_kill_vid(struct net_device *, u16);
static void igb_restore_vlan(struct igb_adapter *);
+static void igb_rar_set_qsel(struct igb_adapter *, u8 *, u32 , u8);
static void igb_ping_all_vfs(struct igb_adapter *);
static void igb_msg_task(struct igb_adapter *);
static int igb_rcv_msg_from_vf(struct igb_adapter *, u32);
-static inline void igb_set_rah_pool(struct e1000_hw *, int , int);
static void igb_vmm_control(struct igb_adapter *);
static int igb_set_vf_mac(struct igb_adapter *adapter, int, unsigned char *);
static void igb_restore_vf_multicasts(struct igb_adapter *adapter);
@@ -141,7 +143,6 @@ static inline void igb_set_vmolr(struct e1000_hw *hw, int vfn)
reg_data = rd32(E1000_VMOLR(vfn));
reg_data |= E1000_VMOLR_BAM | /* Accept broadcast */
- E1000_VMOLR_ROPE | /* Accept packets matched in UTA */
E1000_VMOLR_ROMPE | /* Accept packets matched in MTA */
E1000_VMOLR_AUPE | /* Accept untagged packets */
E1000_VMOLR_STRVLAN; /* Strip vlan tags */
@@ -168,16 +169,6 @@ static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size,
return 0;
}
-static inline void igb_set_rah_pool(struct e1000_hw *hw, int pool, int entry)
-{
- u32 reg_data;
-
- reg_data = rd32(E1000_RAH(entry));
- reg_data &= ~E1000_RAH_POOL_MASK;
- reg_data |= E1000_RAH_POOL_1 << pool;;
- wr32(E1000_RAH(entry), reg_data);
-}
-
#ifdef CONFIG_PM
static int igb_suspend(struct pci_dev *, pm_message_t);
static int igb_resume(struct pci_dev *);
@@ -982,7 +973,6 @@ int igb_up(struct igb_adapter *adapter)
igb_configure_msix(adapter);
igb_vmm_control(adapter);
- igb_set_rah_pool(hw, adapter->vfs_allocated_count, 0);
igb_set_vmolr(hw, adapter->vfs_allocated_count);
/* Clear any pending interrupts. */
@@ -1769,7 +1759,6 @@ static int igb_open(struct net_device *netdev)
igb_configure(adapter);
igb_vmm_control(adapter);
- igb_set_rah_pool(hw, adapter->vfs_allocated_count, 0);
igb_set_vmolr(hw, adapter->vfs_allocated_count);
err = igb_request_irq(adapter);
@@ -2298,6 +2287,13 @@ static void igb_configure_rx(struct igb_adapter *adapter)
/* Set the default pool for the PF's first queue */
igb_configure_vt_default_pool(adapter);
+ /* set UTA to appropriate mode */
+ igb_set_uta(adapter);
+
+ /* set the correct pool for the PF default MAC address in entry 0 */
+ igb_rar_set_qsel(adapter, adapter->hw.mac.addr, 0,
+ adapter->vfs_allocated_count);
+
igb_rlpml_set(adapter);
/* Enable Receives */
@@ -2521,61 +2517,90 @@ static int igb_set_mac(struct net_device *netdev, void *p)
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len);
- igb_rar_set(hw, hw->mac.addr, 0);
- igb_set_rah_pool(hw, adapter->vfs_allocated_count, 0);
+ /* set the correct pool for the new PF MAC address in entry 0 */
+ igb_rar_set_qsel(adapter, hw->mac.addr, 0,
+ adapter->vfs_allocated_count);
return 0;
}
/**
- * igb_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set
+ * igb_write_mc_addr_list - write multicast addresses to MTA
* @netdev: network interface device structure
*
- * The set_rx_mode entry point is called whenever the unicast or multicast
- * address lists or the network interface flags are updated. This routine is
- * responsible for configuring the hardware for proper unicast, multicast,
- * promiscuous mode, and all-multi behavior.
+ * Writes multicast address list to the MTA hash table.
+ * Returns: -ENOMEM on failure
+ * 0 on no addresses written
+ * X on writing X addresses to MTA
**/
-static void igb_set_rx_mode(struct net_device *netdev)
+static int igb_write_mc_addr_list(struct net_device *netdev)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- unsigned int rar_entries = hw->mac.rar_entry_count -
- (adapter->vfs_allocated_count + 1);
struct dev_mc_list *mc_ptr = netdev->mc_list;
- u8 *mta_list = NULL;
- u32 rctl;
+ u8 *mta_list;
+ u32 vmolr = 0;
int i;
- /* Check for Promiscuous and All Multicast modes */
- rctl = rd32(E1000_RCTL);
+ if (!netdev->mc_count) {
+ /* nothing to program, so clear mc list */
+ igb_update_mc_addr_list(hw, NULL, 0);
+ igb_restore_vf_multicasts(adapter);
+ return 0;
+ }
- if (netdev->flags & IFF_PROMISC) {
- rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
- rctl &= ~E1000_RCTL_VFE;
- } else {
- if (netdev->flags & IFF_ALLMULTI)
- rctl |= E1000_RCTL_MPE;
- else
- rctl &= ~E1000_RCTL_MPE;
+ mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC);
+ if (!mta_list)
+ return -ENOMEM;
- if (netdev->uc.count > rar_entries)
- rctl |= E1000_RCTL_UPE;
- else
- rctl &= ~E1000_RCTL_UPE;
- rctl |= E1000_RCTL_VFE;
+ /* set vmolr receive overflow multicast bit */
+ vmolr |= E1000_VMOLR_ROMPE;
+
+ /* The shared function expects a packed array of only addresses. */
+ mc_ptr = netdev->mc_list;
+
+ for (i = 0; i < netdev->mc_count; i++) {
+ if (!mc_ptr)
+ break;
+ memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN);
+ mc_ptr = mc_ptr->next;
}
- wr32(E1000_RCTL, rctl);
+ igb_update_mc_addr_list(hw, mta_list, i);
+ kfree(mta_list);
+
+ return netdev->mc_count;
+}
+
+/**
+ * igb_write_uc_addr_list - write unicast addresses to RAR table
+ * @netdev: network interface device structure
+ *
+ * Writes unicast address list to the RAR table.
+ * Returns: -ENOMEM on failure/insufficient address space
+ * 0 on no addresses written
+ * X on writing X addresses to the RAR table
+ **/
+static int igb_write_uc_addr_list(struct net_device *netdev)
+{
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ unsigned int vfn = adapter->vfs_allocated_count;
+ unsigned int rar_entries = hw->mac.rar_entry_count - (vfn + 1);
+ int count = 0;
+
+ /* return ENOMEM indicating insufficient memory for addresses */
+ if (netdev->uc.count > rar_entries)
+ return -ENOMEM;
if (netdev->uc.count && rar_entries) {
struct netdev_hw_addr *ha;
list_for_each_entry(ha, &netdev->uc.list, list) {
if (!rar_entries)
break;
- igb_rar_set(hw, ha->addr, rar_entries);
- igb_set_rah_pool(hw, adapter->vfs_allocated_count,
- rar_entries);
- rar_entries--;
+ igb_rar_set_qsel(adapter, ha->addr,
+ rar_entries--,
+ vfn);
+ count++;
}
}
/* write the addresses in reverse order to avoid write combining */
@@ -2585,29 +2610,79 @@ static void igb_set_rx_mode(struct net_device *netdev)
}
wrfl();
- if (!netdev->mc_count) {
- /* nothing to program, so clear mc list */
- igb_update_mc_addr_list(hw, NULL, 0);
- igb_restore_vf_multicasts(adapter);
- return;
+ return count;
+}
+
+/**
+ * igb_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_rx_mode entry point is called whenever the unicast or multicast
+ * address lists or the network interface flags are updated. This routine is
+ * responsible for configuring the hardware for proper unicast, multicast,
+ * promiscuous mode, and all-multi behavior.
+ **/
+static void igb_set_rx_mode(struct net_device *netdev)
+{
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ unsigned int vfn = adapter->vfs_allocated_count;
+ u32 rctl, vmolr = 0;
+ int count;
+
+ /* Check for Promiscuous and All Multicast modes */
+ rctl = rd32(E1000_RCTL);
+
+ /* clear the effected bits */
+ rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_VFE);
+
+ if (netdev->flags & IFF_PROMISC) {
+ rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
+ vmolr |= (E1000_VMOLR_ROPE | E1000_VMOLR_MPME);
+ } else {
+ if (netdev->flags & IFF_ALLMULTI) {
+ rctl |= E1000_RCTL_MPE;
+ vmolr |= E1000_VMOLR_MPME;
+ } else {
+ /*
+ * Write addresses to the MTA, if the attempt fails
+ * then we should just turn on promiscous mode so
+ * that we can at least receive multicast traffic
+ */
+ count = igb_write_mc_addr_list(netdev);
+ if (count < 0) {
+ rctl |= E1000_RCTL_MPE;
+ vmolr |= E1000_VMOLR_MPME;
+ } else if (count) {
+ vmolr |= E1000_VMOLR_ROMPE;
+ }
+ }
+ /*
+ * Write addresses to available RAR registers, if there is not
+ * sufficient space to store all the addresses then enable
+ * unicast promiscous mode
+ */
+ count = igb_write_uc_addr_list(netdev);
+ if (count < 0) {
+ rctl |= E1000_RCTL_UPE;
+ vmolr |= E1000_VMOLR_ROPE;
+ }
+ rctl |= E1000_RCTL_VFE;
}
+ wr32(E1000_RCTL, rctl);
- mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC);
- if (!mta_list) {
- dev_err(&adapter->pdev->dev,
- "failed to allocate multicast filter list\n");
+ /*
+ * In order to support SR-IOV and eventually VMDq it is necessary to set
+ * the VMOLR to enable the appropriate modes. Without this workaround
+ * we will have issues with VLAN tag stripping not being done for frames
+ * that are only arriving because we are the default pool
+ */
+ if (hw->mac.type < e1000_82576)
return;
- }
- /* The shared function expects a packed array of only addresses. */
- for (i = 0; i < netdev->mc_count; i++) {
- if (!mc_ptr)
- break;
- memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN);
- mc_ptr = mc_ptr->next;
- }
- igb_update_mc_addr_list(hw, mta_list, i);
- kfree(mta_list);
+ vmolr |= rd32(E1000_VMOLR(vfn)) &
+ ~(E1000_VMOLR_ROPE | E1000_VMOLR_MPME | E1000_VMOLR_ROMPE);
+ wr32(E1000_VMOLR(vfn), vmolr);
igb_restore_vf_multicasts(adapter);
}
@@ -3459,10 +3534,8 @@ static void igb_reset_task(struct work_struct *work)
**/
static struct net_device_stats *igb_get_stats(struct net_device *netdev)
{
- struct igb_adapter *adapter = netdev_priv(netdev);
-
/* only return the current stats */
- return &adapter->net_stats;
+ return &netdev->stats;
}
/**
@@ -3548,6 +3621,7 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu)
void igb_update_stats(struct igb_adapter *adapter)
{
+ struct net_device *netdev = adapter->netdev;
struct e1000_hw *hw = &adapter->hw;
struct pci_dev *pdev = adapter->pdev;
u16 phy_tmp;
@@ -3637,8 +3711,8 @@ void igb_update_stats(struct igb_adapter *adapter)
adapter->stats.icrxdmtc += rd32(E1000_ICRXDMTC);
/* Fill out the OS statistics structure */
- adapter->net_stats.multicast = adapter->stats.mprc;
- adapter->net_stats.collisions = adapter->stats.colc;
+ netdev->stats.multicast = adapter->stats.mprc;
+ netdev->stats.collisions = adapter->stats.colc;
/* Rx Errors */
@@ -3659,7 +3733,7 @@ void igb_update_stats(struct igb_adapter *adapter)
adapter->rx_ring[i].rx_stats.drops += rqdpc_tmp;
rqdpc_total += adapter->rx_ring[i].rx_stats.drops;
}
- adapter->net_stats.rx_fifo_errors = rqdpc_total;
+ netdev->stats.rx_fifo_errors = rqdpc_total;
}
/* Note RNBC (Receive No Buffers Count) is an not an exact
@@ -3667,26 +3741,26 @@ void igb_update_stats(struct igb_adapter *adapter)
* one of the reason for saving it in rx_fifo_errors, as its
* potentially not a true drop.
*/
- adapter->net_stats.rx_fifo_errors += adapter->stats.rnbc;
+ netdev->stats.rx_fifo_errors += adapter->stats.rnbc;
/* RLEC on some newer hardware can be incorrect so build
* our own version based on RUC and ROC */
- adapter->net_stats.rx_errors = adapter->stats.rxerrc +
+ netdev->stats.rx_errors = adapter->stats.rxerrc +
adapter->stats.crcerrs + adapter->stats.algnerrc +
adapter->stats.ruc + adapter->stats.roc +
adapter->stats.cexterr;
- adapter->net_stats.rx_length_errors = adapter->stats.ruc +
+ netdev->stats.rx_length_errors = adapter->stats.ruc +
adapter->stats.roc;
- adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
- adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc;
- adapter->net_stats.rx_missed_errors = adapter->stats.mpc;
+ netdev->stats.rx_crc_errors = adapter->stats.crcerrs;
+ netdev->stats.rx_frame_errors = adapter->stats.algnerrc;
+ netdev->stats.rx_missed_errors = adapter->stats.mpc;
/* Tx Errors */
- adapter->net_stats.tx_errors = adapter->stats.ecol +
+ netdev->stats.tx_errors = adapter->stats.ecol +
adapter->stats.latecol;
- adapter->net_stats.tx_aborted_errors = adapter->stats.ecol;
- adapter->net_stats.tx_window_errors = adapter->stats.latecol;
- adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs;
+ netdev->stats.tx_aborted_errors = adapter->stats.ecol;
+ netdev->stats.tx_window_errors = adapter->stats.latecol;
+ netdev->stats.tx_carrier_errors = adapter->stats.tncrs;
/* Tx Dropped needs to be maintained elsewhere */
@@ -4142,8 +4216,7 @@ static inline void igb_vf_reset_msg(struct igb_adapter *adapter, u32 vf)
igb_vf_reset_event(adapter, vf);
/* set vf mac address */
- igb_rar_set(hw, vf_mac, rar_entry);
- igb_set_rah_pool(hw, vf, rar_entry);
+ igb_rar_set_qsel(adapter, vf_mac, rar_entry, vf);
/* enable transmit and receive for vf */
reg = rd32(E1000_VFTE);
@@ -4273,6 +4346,33 @@ static int igb_rcv_msg_from_vf(struct igb_adapter *adapter, u32 vf)
}
/**
+ * igb_set_uta - Set unicast filter table address
+ * @adapter: board private structure
+ *
+ * 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 promiscous
+ * enable bit to allow vlan tag stripping when promiscous mode is enabled
+ **/
+static void igb_set_uta(struct igb_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ int i;
+
+ /* The UTA table only exists on 82576 hardware and newer */
+ if (hw->mac.type < e1000_82576)
+ return;
+
+ /* we only need to do this if VMDq is enabled */
+ if (!adapter->vfs_allocated_count)
+ return;
+
+ for (i = 0; i < hw->mac.uta_reg_count; i++)
+ array_wr32(E1000_UTA, i, ~0);
+}
+
+/**
* igb_intr_msi - Interrupt Handler
* @irq: interrupt number
* @data: pointer to a network interface device structure
@@ -4539,8 +4639,8 @@ static bool igb_clean_tx_irq(struct igb_ring *tx_ring)
tx_ring->total_packets += total_packets;
tx_ring->tx_stats.bytes += total_bytes;
tx_ring->tx_stats.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->count);
}
@@ -4783,8 +4883,8 @@ next_desc:
rx_ring->total_bytes += total_bytes;
rx_ring->rx_stats.packets += total_packets;
rx_ring->rx_stats.bytes += total_bytes;
- adapter->net_stats.rx_bytes += total_bytes;
- adapter->net_stats.rx_packets += total_packets;
+ netdev->stats.rx_bytes += total_bytes;
+ netdev->stats.rx_packets += total_packets;
return cleaned;
}
@@ -4834,18 +4934,12 @@ static void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring,
}
if (!buffer_info->skb) {
- skb = netdev_alloc_skb(netdev, bufsz + NET_IP_ALIGN);
+ skb = netdev_alloc_skb_ip_align(netdev, bufsz);
if (!skb) {
adapter->alloc_rx_buff_failed++;
goto no_buffers;
}
- /* Make buffer alignment 2 beyond a 16 byte boundary
- * this will result in a 16 byte aligned IP header after
- * the 14 byte MAC header is removed
- */
- skb_reserve(skb, NET_IP_ALIGN);
-
buffer_info->skb = skb;
buffer_info->dma = pci_map_single(pdev, skb->data,
bufsz,
@@ -5532,6 +5626,33 @@ static void igb_io_resume(struct pci_dev *pdev)
igb_get_hw_control(adapter);
}
+static void igb_rar_set_qsel(struct igb_adapter *adapter, u8 *addr, u32 index,
+ u8 qsel)
+{
+ u32 rar_low, rar_high;
+ struct e1000_hw *hw = &adapter->hw;
+
+ /* HW expects these in little endian so we reverse the byte order
+ * from network order (big endian) to little endian
+ */
+ rar_low = ((u32) addr[0] | ((u32) addr[1] << 8) |
+ ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
+ rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
+
+ /* Indicate to hardware the Address is Valid. */
+ rar_high |= E1000_RAH_AV;
+
+ if (hw->mac.type == e1000_82575)
+ rar_high |= E1000_RAH_POOL_1 * qsel;
+ else
+ rar_high |= E1000_RAH_POOL_1 << qsel;
+
+ wr32(E1000_RAL(index), rar_low);
+ wrfl();
+ wr32(E1000_RAH(index), rar_high);
+ wrfl();
+}
+
static int igb_set_vf_mac(struct igb_adapter *adapter,
int vf, unsigned char *mac_addr)
{
@@ -5542,8 +5663,7 @@ static int igb_set_vf_mac(struct igb_adapter *adapter,
memcpy(adapter->vf_data[vf].vf_mac_addresses, mac_addr, ETH_ALEN);
- igb_rar_set(hw, mac_addr, rar_entry);
- igb_set_rah_pool(hw, vf, rar_entry);
+ igb_rar_set_qsel(adapter, mac_addr, rar_entry, vf);
return 0;
}
diff --git a/drivers/net/igbvf/ethtool.c b/drivers/net/igbvf/ethtool.c
index ee17a097d1ca..8afff07ff559 100644
--- a/drivers/net/igbvf/ethtool.c
+++ b/drivers/net/igbvf/ethtool.c
@@ -279,7 +279,7 @@ static int igbvf_set_ringparam(struct net_device *netdev,
{
struct igbvf_adapter *adapter = netdev_priv(netdev);
struct igbvf_ring *temp_ring;
- int err;
+ int err = 0;
u32 new_rx_count, new_tx_count;
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
@@ -299,15 +299,22 @@ static int igbvf_set_ringparam(struct net_device *netdev,
return 0;
}
- temp_ring = vmalloc(sizeof(struct igbvf_ring));
- if (!temp_ring)
- return -ENOMEM;
-
while (test_and_set_bit(__IGBVF_RESETTING, &adapter->state))
msleep(1);
- if (netif_running(adapter->netdev))
- igbvf_down(adapter);
+ if (!netif_running(adapter->netdev)) {
+ adapter->tx_ring->count = new_tx_count;
+ adapter->rx_ring->count = new_rx_count;
+ goto clear_reset;
+ }
+
+ temp_ring = vmalloc(sizeof(struct igbvf_ring));
+ if (!temp_ring) {
+ err = -ENOMEM;
+ goto clear_reset;
+ }
+
+ igbvf_down(adapter);
/*
* We can't just free everything and then setup again,
@@ -339,14 +346,11 @@ static int igbvf_set_ringparam(struct net_device *netdev,
memcpy(adapter->rx_ring, temp_ring,sizeof(struct igbvf_ring));
}
-
- err = 0;
err_setup:
- if (netif_running(adapter->netdev))
- igbvf_up(adapter);
-
- clear_bit(__IGBVF_RESETTING, &adapter->state);
+ igbvf_up(adapter);
vfree(temp_ring);
+clear_reset:
+ clear_bit(__IGBVF_RESETTING, &adapter->state);
return err;
}
@@ -363,16 +367,6 @@ static int igbvf_link_test(struct igbvf_adapter *adapter, u64 *data)
return *data;
}
-static int igbvf_get_self_test_count(struct net_device *netdev)
-{
- return IGBVF_TEST_LEN;
-}
-
-static int igbvf_get_stats_count(struct net_device *netdev)
-{
- return IGBVF_GLOBAL_STATS_LEN;
-}
-
static void igbvf_diag_test(struct net_device *netdev,
struct ethtool_test *eth_test, u64 *data)
{
@@ -480,6 +474,18 @@ static void igbvf_get_ethtool_stats(struct net_device *netdev,
}
+static int igbvf_get_sset_count(struct net_device *dev, int stringset)
+{
+ switch(stringset) {
+ case ETH_SS_TEST:
+ return IGBVF_TEST_LEN;
+ case ETH_SS_STATS:
+ return IGBVF_GLOBAL_STATS_LEN;
+ default:
+ return -EINVAL;
+ }
+}
+
static void igbvf_get_strings(struct net_device *netdev, u32 stringset,
u8 *data)
{
@@ -528,11 +534,10 @@ static const struct ethtool_ops igbvf_ethtool_ops = {
.get_tso = ethtool_op_get_tso,
.set_tso = igbvf_set_tso,
.self_test = igbvf_diag_test,
+ .get_sset_count = igbvf_get_sset_count,
.get_strings = igbvf_get_strings,
.phys_id = igbvf_phys_id,
.get_ethtool_stats = igbvf_get_ethtool_stats,
- .self_test_count = igbvf_get_self_test_count,
- .get_stats_count = igbvf_get_stats_count,
.get_coalesce = igbvf_get_coalesce,
.set_coalesce = igbvf_set_coalesce,
};
diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c
index 91024a3cdad3..fad7f348dd1b 100644
--- a/drivers/net/igbvf/netdev.c
+++ b/drivers/net/igbvf/netdev.c
@@ -170,18 +170,12 @@ static void igbvf_alloc_rx_buffers(struct igbvf_ring *rx_ring,
}
if (!buffer_info->skb) {
- skb = netdev_alloc_skb(netdev, bufsz + NET_IP_ALIGN);
+ skb = netdev_alloc_skb_ip_align(netdev, bufsz);
if (!skb) {
adapter->alloc_rx_buff_failed++;
goto no_buffers;
}
- /* Make buffer alignment 2 beyond a 16 byte boundary
- * this will result in a 16 byte aligned IP header after
- * the 14 byte MAC header is removed
- */
- skb_reserve(skb, NET_IP_ALIGN);
-
buffer_info->skb = skb;
buffer_info->dma = pci_map_single(pdev, skb->data,
bufsz,
diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c
index 9f7b5d4172b8..63056e7b9e22 100644
--- a/drivers/net/ipg.c
+++ b/drivers/net/ipg.c
@@ -738,17 +738,12 @@ static int ipg_get_rxbuff(struct net_device *dev, int entry)
IPG_DEBUG_MSG("_get_rxbuff\n");
- skb = netdev_alloc_skb(dev, sp->rxsupport_size + NET_IP_ALIGN);
+ skb = netdev_alloc_skb_ip_align(dev, sp->rxsupport_size);
if (!skb) {
sp->rx_buff[entry] = NULL;
return -ENOMEM;
}
- /* Adjust the data start location within the buffer to
- * align IP address field to a 16 byte boundary.
- */
- skb_reserve(skb, NET_IP_ALIGN);
-
/* Associate the receive buffer with the IPG NIC. */
skb->dev = dev;
diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c
index eb424681202d..955f04e5167f 100644
--- a/drivers/net/irda/au1k_ir.c
+++ b/drivers/net/irda/au1k_ir.c
@@ -36,6 +36,7 @@
#include <asm/pb1000.h>
#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
#include <asm/db1x00.h>
+#include <asm/mach-db1x00/bcsr.h>
#else
#error au1k_ir: unsupported board
#endif
@@ -66,10 +67,6 @@ static char version[] __devinitdata =
#define RUN_AT(x) (jiffies + (x))
-#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
-static BCSR * const bcsr = (BCSR *)0xAE000000;
-#endif
-
static DEFINE_SPINLOCK(ir_lock);
/*
@@ -282,9 +279,8 @@ static int au1k_irda_net_init(struct net_device *dev)
#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
/* power on */
- bcsr->resets &= ~BCSR_RESETS_IRDA_MODE_MASK;
- bcsr->resets |= BCSR_RESETS_IRDA_MODE_FULL;
- au_sync();
+ bcsr_mod(BCSR_RESETS, BCSR_RESETS_IRDA_MODE_MASK,
+ BCSR_RESETS_IRDA_MODE_FULL);
#endif
return 0;
@@ -720,14 +716,14 @@ au1k_irda_set_speed(struct net_device *dev, int speed)
if (speed == 4000000) {
#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
- bcsr->resets |= BCSR_RESETS_FIR_SEL;
+ bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_FIR_SEL);
#else /* Pb1000 and Pb1100 */
writel(1<<13, CPLD_AUX1);
#endif
}
else {
#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
- bcsr->resets &= ~BCSR_RESETS_FIR_SEL;
+ bcsr_mod(BCSR_RESETS, BCSR_RESETS_FIR_SEL, 0);
#else /* Pb1000 and Pb1100 */
writel(readl(CPLD_AUX1) & ~(1<<13), CPLD_AUX1);
#endif
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 215adf6377d0..5e462b9169ed 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -1124,11 +1124,12 @@ 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)) {
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 1e8dd8c74a64..8f7d0d146f24 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -115,7 +115,7 @@ struct smsc_ircc_subsystem_configuration {
unsigned short vendor; /* PCI vendor ID */
unsigned short device; /* PCI vendor ID */
unsigned short subvendor; /* PCI subsystem vendor ID */
- unsigned short subdevice; /* PCI sybsystem device ID */
+ unsigned short subdevice; /* PCI subsystem device ID */
unsigned short sir_io; /* I/O port for SIR */
unsigned short fir_io; /* I/O port for FIR */
unsigned char fir_irq; /* FIR IRQ */
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
index d85717e3022a..e95d9b6f1f2d 100644
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ixgb/ixgb.h
@@ -183,7 +183,6 @@ struct ixgb_adapter {
struct napi_struct napi;
struct net_device *netdev;
struct pci_dev *pdev;
- struct net_device_stats net_stats;
/* structs defined in ixgb_hw.h */
struct ixgb_hw hw;
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index 288ee1d0f431..a4ed96caae69 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -34,38 +34,46 @@
#define IXGB_ALL_RAR_ENTRIES 16
+enum {NETDEV_STATS, IXGB_STATS};
+
struct ixgb_stats {
char stat_string[ETH_GSTRING_LEN];
+ int type;
int sizeof_stat;
int stat_offset;
};
-#define IXGB_STAT(m) FIELD_SIZEOF(struct ixgb_adapter, m), \
- offsetof(struct ixgb_adapter, m)
+#define IXGB_STAT(m) IXGB_STATS, \
+ FIELD_SIZEOF(struct ixgb_adapter, m), \
+ offsetof(struct ixgb_adapter, m)
+#define IXGB_NETDEV_STAT(m) NETDEV_STATS, \
+ FIELD_SIZEOF(struct net_device, m), \
+ offsetof(struct net_device, m)
+
static struct ixgb_stats ixgb_gstrings_stats[] = {
- {"rx_packets", IXGB_STAT(net_stats.rx_packets)},
- {"tx_packets", IXGB_STAT(net_stats.tx_packets)},
- {"rx_bytes", IXGB_STAT(net_stats.rx_bytes)},
- {"tx_bytes", IXGB_STAT(net_stats.tx_bytes)},
- {"rx_errors", IXGB_STAT(net_stats.rx_errors)},
- {"tx_errors", IXGB_STAT(net_stats.tx_errors)},
- {"rx_dropped", IXGB_STAT(net_stats.rx_dropped)},
- {"tx_dropped", IXGB_STAT(net_stats.tx_dropped)},
- {"multicast", IXGB_STAT(net_stats.multicast)},
- {"collisions", IXGB_STAT(net_stats.collisions)},
-
-/* { "rx_length_errors", IXGB_STAT(net_stats.rx_length_errors) }, */
- {"rx_over_errors", IXGB_STAT(net_stats.rx_over_errors)},
- {"rx_crc_errors", IXGB_STAT(net_stats.rx_crc_errors)},
- {"rx_frame_errors", IXGB_STAT(net_stats.rx_frame_errors)},
+ {"rx_packets", IXGB_NETDEV_STAT(stats.rx_packets)},
+ {"tx_packets", IXGB_NETDEV_STAT(stats.tx_packets)},
+ {"rx_bytes", IXGB_NETDEV_STAT(stats.rx_bytes)},
+ {"tx_bytes", IXGB_NETDEV_STAT(stats.tx_bytes)},
+ {"rx_errors", IXGB_NETDEV_STAT(stats.rx_errors)},
+ {"tx_errors", IXGB_NETDEV_STAT(stats.tx_errors)},
+ {"rx_dropped", IXGB_NETDEV_STAT(stats.rx_dropped)},
+ {"tx_dropped", IXGB_NETDEV_STAT(stats.tx_dropped)},
+ {"multicast", IXGB_NETDEV_STAT(stats.multicast)},
+ {"collisions", IXGB_NETDEV_STAT(stats.collisions)},
+
+/* { "rx_length_errors", IXGB_NETDEV_STAT(stats.rx_length_errors) }, */
+ {"rx_over_errors", IXGB_NETDEV_STAT(stats.rx_over_errors)},
+ {"rx_crc_errors", IXGB_NETDEV_STAT(stats.rx_crc_errors)},
+ {"rx_frame_errors", IXGB_NETDEV_STAT(stats.rx_frame_errors)},
{"rx_no_buffer_count", IXGB_STAT(stats.rnbc)},
- {"rx_fifo_errors", IXGB_STAT(net_stats.rx_fifo_errors)},
- {"rx_missed_errors", IXGB_STAT(net_stats.rx_missed_errors)},
- {"tx_aborted_errors", IXGB_STAT(net_stats.tx_aborted_errors)},
- {"tx_carrier_errors", IXGB_STAT(net_stats.tx_carrier_errors)},
- {"tx_fifo_errors", IXGB_STAT(net_stats.tx_fifo_errors)},
- {"tx_heartbeat_errors", IXGB_STAT(net_stats.tx_heartbeat_errors)},
- {"tx_window_errors", IXGB_STAT(net_stats.tx_window_errors)},
+ {"rx_fifo_errors", IXGB_NETDEV_STAT(stats.rx_fifo_errors)},
+ {"rx_missed_errors", IXGB_NETDEV_STAT(stats.rx_missed_errors)},
+ {"tx_aborted_errors", IXGB_NETDEV_STAT(stats.tx_aborted_errors)},
+ {"tx_carrier_errors", IXGB_NETDEV_STAT(stats.tx_carrier_errors)},
+ {"tx_fifo_errors", IXGB_NETDEV_STAT(stats.tx_fifo_errors)},
+ {"tx_heartbeat_errors", IXGB_NETDEV_STAT(stats.tx_heartbeat_errors)},
+ {"tx_window_errors", IXGB_NETDEV_STAT(stats.tx_window_errors)},
{"tx_deferred_ok", IXGB_STAT(stats.dc)},
{"tx_timeout_count", IXGB_STAT(tx_timeout_count) },
{"tx_restart_queue", IXGB_STAT(restart_queue) },
@@ -662,10 +670,21 @@ ixgb_get_ethtool_stats(struct net_device *netdev,
{
struct ixgb_adapter *adapter = netdev_priv(netdev);
int i;
+ char *p = NULL;
ixgb_update_stats(adapter);
for (i = 0; i < IXGB_STATS_LEN; i++) {
- char *p = (char *)adapter+ixgb_gstrings_stats[i].stat_offset;
+ switch (ixgb_gstrings_stats[i].type) {
+ case NETDEV_STATS:
+ p = (char *) netdev +
+ ixgb_gstrings_stats[i].stat_offset;
+ break;
+ case IXGB_STATS:
+ p = (char *) adapter +
+ ixgb_gstrings_stats[i].stat_offset;
+ break;
+ }
+
data[i] = (ixgb_gstrings_stats[i].sizeof_stat ==
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
}
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index 8aa44dca57eb..1bd0ca1b0465 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -1537,9 +1537,7 @@ ixgb_tx_timeout_task(struct work_struct *work)
static struct net_device_stats *
ixgb_get_stats(struct net_device *netdev)
{
- struct ixgb_adapter *adapter = netdev_priv(netdev);
-
- return &adapter->net_stats;
+ return &netdev->stats;
}
/**
@@ -1676,16 +1674,16 @@ ixgb_update_stats(struct ixgb_adapter *adapter)
/* Fill out the OS statistics structure */
- adapter->net_stats.rx_packets = adapter->stats.gprcl;
- adapter->net_stats.tx_packets = adapter->stats.gptcl;
- adapter->net_stats.rx_bytes = adapter->stats.gorcl;
- adapter->net_stats.tx_bytes = adapter->stats.gotcl;
- adapter->net_stats.multicast = adapter->stats.mprcl;
- adapter->net_stats.collisions = 0;
+ netdev->stats.rx_packets = adapter->stats.gprcl;
+ netdev->stats.tx_packets = adapter->stats.gptcl;
+ netdev->stats.rx_bytes = adapter->stats.gorcl;
+ netdev->stats.tx_bytes = adapter->stats.gotcl;
+ netdev->stats.multicast = adapter->stats.mprcl;
+ netdev->stats.collisions = 0;
/* ignore RLEC as it reports errors for padded (<64bytes) frames
* with a length in the type/len field */
- adapter->net_stats.rx_errors =
+ netdev->stats.rx_errors =
/* adapter->stats.rnbc + */ adapter->stats.crcerrs +
adapter->stats.ruc +
adapter->stats.roc /*+ adapter->stats.rlec */ +
@@ -1693,21 +1691,21 @@ ixgb_update_stats(struct ixgb_adapter *adapter)
adapter->stats.ecbc + adapter->stats.mpc;
/* see above
- * adapter->net_stats.rx_length_errors = adapter->stats.rlec;
+ * netdev->stats.rx_length_errors = adapter->stats.rlec;
*/
- adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
- adapter->net_stats.rx_fifo_errors = adapter->stats.mpc;
- adapter->net_stats.rx_missed_errors = adapter->stats.mpc;
- adapter->net_stats.rx_over_errors = adapter->stats.mpc;
-
- adapter->net_stats.tx_errors = 0;
- adapter->net_stats.rx_frame_errors = 0;
- adapter->net_stats.tx_aborted_errors = 0;
- adapter->net_stats.tx_carrier_errors = 0;
- adapter->net_stats.tx_fifo_errors = 0;
- adapter->net_stats.tx_heartbeat_errors = 0;
- adapter->net_stats.tx_window_errors = 0;
+ netdev->stats.rx_crc_errors = adapter->stats.crcerrs;
+ netdev->stats.rx_fifo_errors = adapter->stats.mpc;
+ netdev->stats.rx_missed_errors = adapter->stats.mpc;
+ netdev->stats.rx_over_errors = adapter->stats.mpc;
+
+ netdev->stats.tx_errors = 0;
+ netdev->stats.rx_frame_errors = 0;
+ netdev->stats.tx_aborted_errors = 0;
+ netdev->stats.tx_carrier_errors = 0;
+ netdev->stats.tx_fifo_errors = 0;
+ netdev->stats.tx_heartbeat_errors = 0;
+ netdev->stats.tx_window_errors = 0;
}
#define IXGB_MAX_INTR 10
@@ -1974,9 +1972,8 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter, int *work_done, int work_to_do)
* of reassembly being done in the stack */
if (length < copybreak) {
struct sk_buff *new_skb =
- netdev_alloc_skb(netdev, length + NET_IP_ALIGN);
+ netdev_alloc_skb_ip_align(netdev, length);
if (new_skb) {
- skb_reserve(new_skb, NET_IP_ALIGN);
skb_copy_to_linear_data_offset(new_skb,
-NET_IP_ALIGN,
(skb->data -
@@ -2059,20 +2056,13 @@ ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter, int cleaned_count)
goto map_skb;
}
- skb = netdev_alloc_skb(netdev, adapter->rx_buffer_len
- + NET_IP_ALIGN);
+ skb = netdev_alloc_skb_ip_align(netdev, adapter->rx_buffer_len);
if (unlikely(!skb)) {
/* Better luck next round */
adapter->alloc_rx_buff_failed++;
break;
}
- /* Make buffer alignment 2 beyond a 16 byte boundary
- * this will result in a 16 byte aligned IP header after
- * the 14 byte MAC header is removed
- */
- skb_reserve(skb, NET_IP_ALIGN);
-
buffer_info->skb = skb;
buffer_info->length = adapter->rx_buffer_len;
map_skb:
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index 385be6016667..2b854161c61b 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -340,7 +340,6 @@ struct ixgbe_adapter {
/* OS defined structs */
struct net_device *netdev;
struct pci_dev *pdev;
- struct net_device_stats net_stats;
u32 test_icr;
struct ixgbe_ring test_tx_ring;
@@ -397,7 +396,7 @@ enum ixgbe_boards {
extern struct ixgbe_info ixgbe_82598_info;
extern struct ixgbe_info ixgbe_82599_info;
#ifdef CONFIG_IXGBE_DCB
-extern struct dcbnl_rtnl_ops dcbnl_ops;
+extern const struct dcbnl_rtnl_ops dcbnl_ops;
extern int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg,
struct ixgbe_dcb_config *dst_dcb_cfg,
int tc_max);
diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c
index 34b04924c8a1..ae27c41222e3 100644
--- a/drivers/net/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ixgbe/ixgbe_82599.c
@@ -42,6 +42,10 @@ 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,
@@ -64,7 +68,13 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw)
/* Set up dual speed SFP+ support */
mac->ops.setup_link = &ixgbe_setup_mac_link_multispeed_fiber;
} else {
- mac->ops.setup_link = &ixgbe_setup_mac_link_82599;
+ if ((mac->ops.get_media_type(hw) ==
+ ixgbe_media_type_backplane) &&
+ (hw->phy.smart_speed == ixgbe_smart_speed_auto ||
+ hw->phy.smart_speed == ixgbe_smart_speed_on))
+ mac->ops.setup_link = &ixgbe_setup_mac_link_smartspeed;
+ else
+ mac->ops.setup_link = &ixgbe_setup_mac_link_82599;
}
}
@@ -337,6 +347,7 @@ static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw)
media_type = ixgbe_media_type_backplane;
break;
case IXGBE_DEV_ID_82599_SFP:
+ case IXGBE_DEV_ID_82599_SFP_EM:
media_type = ixgbe_media_type_fiber;
break;
case IXGBE_DEV_ID_82599_CX4:
@@ -479,7 +490,12 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
hw->mac.autotry_restart = false;
}
- /* The controller may take up to 500ms at 10g to acquire link */
+ /*
+ * Wait for the controller to acquire link. Per IEEE 802.3ap,
+ * Section 73.10.2, we may have to wait up to 500ms if KR is
+ * attempted. 82599 uses the same timing for 10g SFI.
+ */
+
for (i = 0; i < 5; i++) {
/* Wait for the link partner to also set speed */
msleep(100);
@@ -567,6 +583,111 @@ out:
}
/**
+ * ixgbe_setup_mac_link_smartspeed - Set MAC link speed using SmartSpeed
+ * @hw: pointer to hardware structure
+ * @speed: new link speed
+ * @autoneg: true if autonegotiation enabled
+ * @autoneg_wait_to_complete: true when waiting for completion is needed
+ *
+ * Implements the Intel SmartSpeed algorithm.
+ **/
+static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
+ ixgbe_link_speed speed, bool autoneg,
+ bool autoneg_wait_to_complete)
+{
+ s32 status = 0;
+ ixgbe_link_speed link_speed;
+ s32 i, j;
+ bool link_up = false;
+ u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+
+ hw_dbg(hw, "ixgbe_setup_mac_link_smartspeed.\n");
+
+ /* Set autoneg_advertised value based on input link speed */
+ hw->phy.autoneg_advertised = 0;
+
+ if (speed & IXGBE_LINK_SPEED_10GB_FULL)
+ hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
+
+ if (speed & IXGBE_LINK_SPEED_1GB_FULL)
+ hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
+
+ if (speed & IXGBE_LINK_SPEED_100_FULL)
+ hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_100_FULL;
+
+ /*
+ * Implement Intel SmartSpeed algorithm. SmartSpeed will reduce the
+ * autoneg advertisement if link is unable to be established at the
+ * highest negotiated rate. This can sometimes happen due to integrity
+ * issues with the physical media connection.
+ */
+
+ /* First, try to get link with full advertisement */
+ hw->phy.smart_speed_active = false;
+ for (j = 0; j < IXGBE_SMARTSPEED_MAX_RETRIES; j++) {
+ status = ixgbe_setup_mac_link_82599(hw, speed, autoneg,
+ autoneg_wait_to_complete);
+ if (status)
+ goto out;
+
+ /*
+ * Wait for the controller to acquire link. Per IEEE 802.3ap,
+ * Section 73.10.2, we may have to wait up to 500ms if KR is
+ * attempted, or 200ms if KX/KX4/BX/BX4 is attempted, per
+ * Table 9 in the AN MAS.
+ */
+ for (i = 0; i < 5; i++) {
+ mdelay(100);
+
+ /* If we have link, just jump out */
+ hw->mac.ops.check_link(hw, &link_speed,
+ &link_up, false);
+ if (link_up)
+ goto out;
+ }
+ }
+
+ /*
+ * We didn't get link. If we advertised KR plus one of KX4/KX
+ * (or BX4/BX), then disable KR and try again.
+ */
+ if (((autoc_reg & IXGBE_AUTOC_KR_SUPP) == 0) ||
+ ((autoc_reg & IXGBE_AUTOC_KX4_KX_SUPP_MASK) == 0))
+ goto out;
+
+ /* Turn SmartSpeed on to disable KR support */
+ hw->phy.smart_speed_active = true;
+ status = ixgbe_setup_mac_link_82599(hw, speed, autoneg,
+ autoneg_wait_to_complete);
+ if (status)
+ goto out;
+
+ /*
+ * Wait for the controller to acquire link. 600ms will allow for
+ * the AN link_fail_inhibit_timer as well for multiple cycles of
+ * parallel detect, both 10g and 1g. This allows for the maximum
+ * connect attempts as defined in the AN MAS table 73-7.
+ */
+ for (i = 0; i < 6; i++) {
+ mdelay(100);
+
+ /* If we have link, just jump out */
+ hw->mac.ops.check_link(hw, &link_speed,
+ &link_up, false);
+ if (link_up)
+ goto out;
+ }
+
+ /* We didn't get link. Turn SmartSpeed back off. */
+ hw->phy.smart_speed_active = false;
+ status = ixgbe_setup_mac_link_82599(hw, speed, autoneg,
+ autoneg_wait_to_complete);
+
+out:
+ return status;
+}
+
+/**
* ixgbe_check_mac_link_82599 - Determine link and speed status
* @hw: pointer to hardware structure
* @speed: pointer to link speed
@@ -669,7 +790,8 @@ s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
if (speed & IXGBE_LINK_SPEED_10GB_FULL)
if (orig_autoc & IXGBE_AUTOC_KX4_SUPP)
autoc |= IXGBE_AUTOC_KX4_SUPP;
- if (orig_autoc & IXGBE_AUTOC_KR_SUPP)
+ if ((orig_autoc & IXGBE_AUTOC_KR_SUPP) &&
+ (hw->phy.smart_speed_active == false))
autoc |= IXGBE_AUTOC_KR_SUPP;
if (speed & IXGBE_LINK_SPEED_1GB_FULL)
autoc |= IXGBE_AUTOC_KX_SUPP;
diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c
index a6bc1ef28f92..3c7a79a7d7c6 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c
@@ -563,7 +563,7 @@ static u8 ixgbe_dcbnl_setapp(struct net_device *netdev,
return rval;
}
-struct dcbnl_rtnl_ops dcbnl_ops = {
+const struct dcbnl_rtnl_ops dcbnl_ops = {
.getstate = ixgbe_dcbnl_get_state,
.setstate = ixgbe_dcbnl_set_state,
.getpermhwaddr = ixgbe_dcbnl_get_perm_hw_addr,
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index fa314cb005a4..9d2cc833691b 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -40,19 +40,27 @@
#define IXGBE_ALL_RAR_ENTRIES 16
+enum {NETDEV_STATS, IXGBE_STATS};
+
struct ixgbe_stats {
char stat_string[ETH_GSTRING_LEN];
+ int type;
int sizeof_stat;
int stat_offset;
};
-#define IXGBE_STAT(m) sizeof(((struct ixgbe_adapter *)0)->m), \
- offsetof(struct ixgbe_adapter, m)
+#define IXGBE_STAT(m) IXGBE_STATS, \
+ sizeof(((struct ixgbe_adapter *)0)->m), \
+ offsetof(struct ixgbe_adapter, m)
+#define IXGBE_NETDEV_STAT(m) NETDEV_STATS, \
+ sizeof(((struct net_device *)0)->m), \
+ offsetof(struct net_device, m)
+
static struct ixgbe_stats ixgbe_gstrings_stats[] = {
- {"rx_packets", IXGBE_STAT(net_stats.rx_packets)},
- {"tx_packets", IXGBE_STAT(net_stats.tx_packets)},
- {"rx_bytes", IXGBE_STAT(net_stats.rx_bytes)},
- {"tx_bytes", IXGBE_STAT(net_stats.tx_bytes)},
+ {"rx_packets", IXGBE_NETDEV_STAT(stats.rx_packets)},
+ {"tx_packets", IXGBE_NETDEV_STAT(stats.tx_packets)},
+ {"rx_bytes", IXGBE_NETDEV_STAT(stats.rx_bytes)},
+ {"tx_bytes", IXGBE_NETDEV_STAT(stats.tx_bytes)},
{"rx_pkts_nic", IXGBE_STAT(stats.gprc)},
{"tx_pkts_nic", IXGBE_STAT(stats.gptc)},
{"rx_bytes_nic", IXGBE_STAT(stats.gorc)},
@@ -60,26 +68,26 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = {
{"lsc_int", IXGBE_STAT(lsc_int)},
{"tx_busy", IXGBE_STAT(tx_busy)},
{"non_eop_descs", IXGBE_STAT(non_eop_descs)},
- {"rx_errors", IXGBE_STAT(net_stats.rx_errors)},
- {"tx_errors", IXGBE_STAT(net_stats.tx_errors)},
- {"rx_dropped", IXGBE_STAT(net_stats.rx_dropped)},
- {"tx_dropped", IXGBE_STAT(net_stats.tx_dropped)},
- {"multicast", IXGBE_STAT(net_stats.multicast)},
+ {"rx_errors", IXGBE_NETDEV_STAT(stats.rx_errors)},
+ {"tx_errors", IXGBE_NETDEV_STAT(stats.tx_errors)},
+ {"rx_dropped", IXGBE_NETDEV_STAT(stats.rx_dropped)},
+ {"tx_dropped", IXGBE_NETDEV_STAT(stats.tx_dropped)},
+ {"multicast", IXGBE_NETDEV_STAT(stats.multicast)},
{"broadcast", IXGBE_STAT(stats.bprc)},
{"rx_no_buffer_count", IXGBE_STAT(stats.rnbc[0]) },
- {"collisions", IXGBE_STAT(net_stats.collisions)},
- {"rx_over_errors", IXGBE_STAT(net_stats.rx_over_errors)},
- {"rx_crc_errors", IXGBE_STAT(net_stats.rx_crc_errors)},
- {"rx_frame_errors", IXGBE_STAT(net_stats.rx_frame_errors)},
+ {"collisions", IXGBE_NETDEV_STAT(stats.collisions)},
+ {"rx_over_errors", IXGBE_NETDEV_STAT(stats.rx_over_errors)},
+ {"rx_crc_errors", IXGBE_NETDEV_STAT(stats.rx_crc_errors)},
+ {"rx_frame_errors", IXGBE_NETDEV_STAT(stats.rx_frame_errors)},
{"hw_rsc_count", IXGBE_STAT(rsc_count)},
{"fdir_match", IXGBE_STAT(stats.fdirmatch)},
{"fdir_miss", IXGBE_STAT(stats.fdirmiss)},
- {"rx_fifo_errors", IXGBE_STAT(net_stats.rx_fifo_errors)},
- {"rx_missed_errors", IXGBE_STAT(net_stats.rx_missed_errors)},
- {"tx_aborted_errors", IXGBE_STAT(net_stats.tx_aborted_errors)},
- {"tx_carrier_errors", IXGBE_STAT(net_stats.tx_carrier_errors)},
- {"tx_fifo_errors", IXGBE_STAT(net_stats.tx_fifo_errors)},
- {"tx_heartbeat_errors", IXGBE_STAT(net_stats.tx_heartbeat_errors)},
+ {"rx_fifo_errors", IXGBE_NETDEV_STAT(stats.rx_fifo_errors)},
+ {"rx_missed_errors", IXGBE_NETDEV_STAT(stats.rx_missed_errors)},
+ {"tx_aborted_errors", IXGBE_NETDEV_STAT(stats.tx_aborted_errors)},
+ {"tx_carrier_errors", IXGBE_NETDEV_STAT(stats.tx_carrier_errors)},
+ {"tx_fifo_errors", IXGBE_NETDEV_STAT(stats.tx_fifo_errors)},
+ {"tx_heartbeat_errors", IXGBE_NETDEV_STAT(stats.tx_heartbeat_errors)},
{"tx_timeout_count", IXGBE_STAT(tx_timeout_count)},
{"tx_restart_queue", IXGBE_STAT(restart_queue)},
{"rx_long_length_errors", IXGBE_STAT(stats.roc)},
@@ -798,7 +806,7 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_ring *temp_tx_ring, *temp_rx_ring;
- int i, err;
+ int i, err = 0;
u32 new_rx_count, new_tx_count;
bool need_update = false;
@@ -822,6 +830,16 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
msleep(1);
+ 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 err_setup;
+ }
+
temp_tx_ring = kcalloc(adapter->num_tx_queues,
sizeof(struct ixgbe_ring), GFP_KERNEL);
if (!temp_tx_ring) {
@@ -879,8 +897,7 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
/* if rings need to be updated, here's the place to do it in one shot */
if (need_update) {
- if (netif_running(netdev))
- ixgbe_down(adapter);
+ ixgbe_down(adapter);
/* tx */
if (new_tx_count != adapter->tx_ring_count) {
@@ -897,13 +914,8 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
temp_rx_ring = NULL;
adapter->rx_ring_count = new_rx_count;
}
- }
-
- /* success! */
- err = 0;
- if (netif_running(netdev))
ixgbe_up(adapter);
-
+ }
err_setup:
clear_bit(__IXGBE_RESETTING, &adapter->state);
return err;
@@ -929,10 +941,21 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64);
int j, k;
int i;
+ char *p = NULL;
ixgbe_update_stats(adapter);
for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
- char *p = (char *)adapter + ixgbe_gstrings_stats[i].stat_offset;
+ switch (ixgbe_gstrings_stats[i].type) {
+ case NETDEV_STATS:
+ p = (char *) netdev +
+ ixgbe_gstrings_stats[i].stat_offset;
+ break;
+ case IXGBE_STATS:
+ p = (char *) adapter +
+ ixgbe_gstrings_stats[i].stat_offset;
+ break;
+ }
+
data[i] = (ixgbe_gstrings_stats[i].sizeof_stat ==
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
}
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index cbb143ca1eb8..4c8a44919705 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -97,6 +97,8 @@ static struct pci_device_id ixgbe_pci_tbl[] = {
board_82599 },
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP),
board_82599 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_EM),
+ board_82599 },
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KX4_MEZZ),
board_82599 },
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_CX4),
@@ -372,8 +374,8 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
tx_ring->total_packets += total_packets;
tx_ring->stats.packets += total_packets;
tx_ring->stats.bytes += total_bytes;
- 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);
}
@@ -614,22 +616,14 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
if (!bi->skb) {
struct sk_buff *skb;
- skb = netdev_alloc_skb(adapter->netdev,
- (rx_ring->rx_buf_len +
- NET_IP_ALIGN));
+ skb = netdev_alloc_skb_ip_align(adapter->netdev,
+ rx_ring->rx_buf_len);
if (!skb) {
adapter->alloc_rx_buff_failed++;
goto no_buffers;
}
- /*
- * Make buffer alignment 2 beyond a 16 byte boundary
- * this will result in a 16 byte aligned IP header after
- * the 14 byte MAC header is removed
- */
- skb_reserve(skb, NET_IP_ALIGN);
-
bi->skb = skb;
bi->dma = pci_map_single(pdev, skb->data,
rx_ring->rx_buf_len,
@@ -709,6 +703,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
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;
@@ -880,8 +875,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;
+ netdev->stats.rx_bytes += total_rx_bytes;
+ netdev->stats.rx_packets += total_rx_packets;
return cleaned;
}
@@ -4403,6 +4398,7 @@ static void ixgbe_shutdown(struct pci_dev *pdev)
**/
void ixgbe_update_stats(struct ixgbe_adapter *adapter)
{
+ struct net_device *netdev = adapter->netdev;
struct ixgbe_hw *hw = &adapter->hw;
u64 total_mpc = 0;
u32 i, missed_rx = 0, mpc, bprc, lxon, lxoff, xon_off_tot;
@@ -4522,15 +4518,15 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
adapter->stats.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC);
/* Fill out the OS statistics structure */
- adapter->net_stats.multicast = adapter->stats.mprc;
+ netdev->stats.multicast = adapter->stats.mprc;
/* Rx Errors */
- adapter->net_stats.rx_errors = adapter->stats.crcerrs +
+ netdev->stats.rx_errors = adapter->stats.crcerrs +
adapter->stats.rlec;
- adapter->net_stats.rx_dropped = 0;
- adapter->net_stats.rx_length_errors = adapter->stats.rlec;
- adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
- adapter->net_stats.rx_missed_errors = total_mpc;
+ netdev->stats.rx_dropped = 0;
+ netdev->stats.rx_length_errors = adapter->stats.rlec;
+ netdev->stats.rx_crc_errors = adapter->stats.crcerrs;
+ netdev->stats.rx_missed_errors = total_mpc;
}
/**
@@ -5300,10 +5296,8 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
**/
static struct net_device_stats *ixgbe_get_stats(struct net_device *netdev)
{
- struct ixgbe_adapter *adapter = netdev_priv(netdev);
-
/* only return the current stats */
- return &adapter->net_stats;
+ return &netdev->stats;
}
/**
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
index ef4bdd58e016..1cab53eb22f3 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -52,6 +52,7 @@
#define IXGBE_DEV_ID_82599_KX4_MEZZ 0x1514
#define IXGBE_DEV_ID_82599_CX4 0x10F9
#define IXGBE_DEV_ID_82599_SFP 0x10FB
+#define IXGBE_DEV_ID_82599_SFP_EM 0x1507
#define IXGBE_DEV_ID_82599_XAUI_LOM 0x10FC
#define IXGBE_DEV_ID_82599_COMBO_BACKPLANE 0x10F8
@@ -2171,6 +2172,14 @@ enum ixgbe_fc_mode {
ixgbe_fc_default
};
+/* Smart Speed Settings */
+#define IXGBE_SMARTSPEED_MAX_RETRIES 3
+enum ixgbe_smart_speed {
+ ixgbe_smart_speed_auto = 0,
+ ixgbe_smart_speed_on,
+ ixgbe_smart_speed_off
+};
+
/* PCI bus types */
enum ixgbe_bus_type {
ixgbe_bus_type_unknown = 0,
@@ -2431,6 +2440,8 @@ struct ixgbe_phy_info {
enum ixgbe_media_type media_type;
bool reset_disable;
ixgbe_autoneg_advertised autoneg_advertised;
+ enum ixgbe_smart_speed smart_speed;
+ bool smart_speed_active;
bool multispeed_fiber;
};
diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c
index 9aee0cc922c9..e9d9d595e1b7 100644
--- a/drivers/net/ixp2000/ixpdev.c
+++ b/drivers/net/ixp2000/ixpdev.c
@@ -109,9 +109,8 @@ static int ixpdev_rx(struct net_device *dev, int processed, int budget)
if (unlikely(!netif_running(nds[desc->channel])))
goto err;
- skb = netdev_alloc_skb(dev, desc->pkt_length + 2);
+ skb = netdev_alloc_skb_ip_align(dev, desc->pkt_length);
if (likely(skb != NULL)) {
- skb_reserve(skb, 2);
skb_copy_to_linear_data(skb, buf, desc->pkt_length);
skb_put(skb, desc->pkt_length);
skb->protocol = eth_type_trans(skb, nds[desc->channel]);
diff --git a/drivers/net/korina.c b/drivers/net/korina.c
index 03199fa10003..a07a5972b57e 100644
--- a/drivers/net/korina.c
+++ b/drivers/net/korina.c
@@ -400,7 +400,7 @@ static int korina_rx(struct net_device *dev, int limit)
dma_cache_inv((unsigned long)pkt_buf, pkt_len - 4);
/* Malloc up new buffer. */
- skb_new = netdev_alloc_skb(dev, KORINA_RBSIZE + 2);
+ skb_new = netdev_alloc_skb_ip_align(dev, KORINA_RBSIZE);
if (!skb_new)
break;
@@ -417,9 +417,6 @@ static int korina_rx(struct net_device *dev, int limit)
if (devcs & ETH_RX_MP)
dev->stats.multicast++;
- /* 16 bit align */
- skb_reserve(skb_new, 2);
-
lp->rx_skb[lp->rx_next_done] = skb_new;
}
diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c
index 99e954167fa6..5c45cb58d023 100644
--- a/drivers/net/ks8842.c
+++ b/drivers/net/ks8842.c
@@ -357,7 +357,7 @@ static void ks8842_rx_frame(struct net_device *netdev,
/* check the status */
if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) {
- struct sk_buff *skb = netdev_alloc_skb(netdev, len + 2);
+ struct sk_buff *skb = netdev_alloc_skb_ip_align(netdev, len);
dev_dbg(&adapter->pdev->dev, "%s, got package, len: %d\n",
__func__, len);
@@ -369,9 +369,6 @@ static void ks8842_rx_frame(struct net_device *netdev,
if (status & RXSR_MULTICAST)
netdev->stats.multicast++;
- /* Align socket buffer in 4-byte boundary for
- better performance. */
- skb_reserve(skb, 2);
data = (u32 *)skb_put(skb, len);
ks8842_select_bank(adapter, 17);
diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c
index 237835864357..a23f739d222f 100644
--- a/drivers/net/ks8851.c
+++ b/drivers/net/ks8851.c
@@ -171,6 +171,36 @@ static void ks8851_wrreg16(struct ks8851_net *ks, unsigned reg, unsigned val)
}
/**
+ * ks8851_wrreg8 - write 8bit register value to chip
+ * @ks: The chip state
+ * @reg: The register address
+ * @val: The value to write
+ *
+ * Issue a write to put the value @val into the register specified in @reg.
+ */
+static void ks8851_wrreg8(struct ks8851_net *ks, unsigned reg, unsigned val)
+{
+ struct spi_transfer *xfer = &ks->spi_xfer1;
+ struct spi_message *msg = &ks->spi_msg1;
+ __le16 txb[2];
+ int ret;
+ int bit;
+
+ bit = 1 << (reg & 3);
+
+ txb[0] = cpu_to_le16(MK_OP(bit, reg) | KS_SPIOP_WR);
+ txb[1] = val;
+
+ xfer->tx_buf = txb;
+ xfer->rx_buf = NULL;
+ xfer->len = 3;
+
+ ret = spi_sync(ks->spidev, msg);
+ if (ret < 0)
+ ks_err(ks, "spi_sync() failed\n");
+}
+
+/**
* ks8851_rx_1msg - select whether to use one or two messages for spi read
* @ks: The device structure
*
@@ -322,13 +352,12 @@ static void ks8851_soft_reset(struct ks8851_net *ks, unsigned op)
static int ks8851_write_mac_addr(struct net_device *dev)
{
struct ks8851_net *ks = netdev_priv(dev);
- u16 *mcp = (u16 *)dev->dev_addr;
+ int i;
mutex_lock(&ks->lock);
- ks8851_wrreg16(ks, KS_MARL, mcp[0]);
- ks8851_wrreg16(ks, KS_MARM, mcp[1]);
- ks8851_wrreg16(ks, KS_MARH, mcp[2]);
+ for (i = 0; i < ETH_ALEN; i++)
+ ks8851_wrreg8(ks, KS_MAR(i), dev->dev_addr[i]);
mutex_unlock(&ks->lock);
@@ -951,7 +980,7 @@ static void ks8851_set_rx_mode(struct net_device *dev)
mcptr = mcptr->next;
}
- rxctrl.rxcr1 = RXCR1_RXME | RXCR1_RXAE | RXCR1_RXPAFMA;
+ rxctrl.rxcr1 = RXCR1_RXME | RXCR1_RXPAFMA;
} else {
/* just accept broadcast / unicast */
rxctrl.rxcr1 = RXCR1_RXPAFMA;
@@ -1239,6 +1268,9 @@ static int __devinit ks8851_probe(struct spi_device *spi)
ndev->netdev_ops = &ks8851_netdev_ops;
ndev->irq = spi->irq;
+ /* issue a global soft reset to reset the device. */
+ ks8851_soft_reset(ks, GRR_GSR);
+
/* simple check for a valid chip being connected to the bus */
if ((ks8851_rdreg16(ks, KS_CIDER) & ~CIDER_REV_MASK) != CIDER_ID) {
diff --git a/drivers/net/ks8851.h b/drivers/net/ks8851.h
index 85abe147afbf..f52c312cc356 100644
--- a/drivers/net/ks8851.h
+++ b/drivers/net/ks8851.h
@@ -16,6 +16,7 @@
#define CCR_32PIN (1 << 0)
/* MAC address registers */
+#define KS_MAR(_m) 0x15 - (_m)
#define KS_MARL 0x10
#define KS_MARM 0x12
#define KS_MARH 0x14
diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c
index 51e11c3e53e1..5b24c67de25e 100644
--- a/drivers/net/lib82596.c
+++ b/drivers/net/lib82596.c
@@ -470,11 +470,11 @@ static inline int init_rx_bufs(struct net_device *dev)
for (i = 0, rbd = dma->rbds; i < rx_ring_size; i++, rbd++) {
dma_addr_t dma_addr;
- struct sk_buff *skb = netdev_alloc_skb(dev, PKT_BUF_SZ + 4);
+ struct sk_buff *skb;
+ skb = netdev_alloc_skb_ip_align(dev, PKT_BUF_SZ);
if (skb == NULL)
return -1;
- skb_reserve(skb, 2);
dma_addr = dma_map_single(dev->dev.parent, skb->data,
PKT_BUF_SZ, DMA_FROM_DEVICE);
rbd->v_next = rbd+1;
@@ -697,12 +697,12 @@ static inline int i596_rx(struct net_device *dev)
(dma_addr_t)SWAP32(rbd->b_data),
PKT_BUF_SZ, DMA_FROM_DEVICE);
/* Get fresh skbuff to replace filled one. */
- newskb = netdev_alloc_skb(dev, PKT_BUF_SZ + 4);
+ newskb = netdev_alloc_skb_ip_align(dev,
+ PKT_BUF_SZ);
if (newskb == NULL) {
skb = NULL; /* drop pkt */
goto memory_squeeze;
}
- skb_reserve(newskb, 2);
/* Pass up the skb already on the Rx ring. */
skb_put(skb, pkt_len);
@@ -716,7 +716,7 @@ static inline int i596_rx(struct net_device *dev)
rbd->b_data = SWAP32(dma_addr);
DMA_WBACK_INV(dev, rbd, sizeof(struct i596_rbd));
} else
- skb = netdev_alloc_skb(dev, pkt_len + 2);
+ skb = netdev_alloc_skb_ip_align(dev, pkt_len);
memory_squeeze:
if (skb == NULL) {
/* XXX tulip.c can defer packets here!! */
@@ -730,7 +730,6 @@ memory_squeeze:
dma_sync_single_for_cpu(dev->dev.parent,
(dma_addr_t)SWAP32(rbd->b_data),
PKT_BUF_SZ, DMA_FROM_DEVICE);
- skb_reserve(skb, 2);
memcpy(skb_put(skb, pkt_len), rbd->v_data, pkt_len);
dma_sync_single_for_device(dev->dev.parent,
(dma_addr_t)SWAP32(rbd->b_data),
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 1bc654a73c47..8ebeb76a373d 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -81,7 +81,7 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
/* it's OK to use per_cpu_ptr() because BHs are off */
pcpu_lstats = dev->ml_priv;
- lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id());
+ lb_stats = this_cpu_ptr(pcpu_lstats);
len = skb->len;
if (likely(netif_rx(skb) == NET_RX_SUCCESS)) {
diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c
index 21f8754fcf4c..e85bf04cf813 100644
--- a/drivers/net/mdio.c
+++ b/drivers/net/mdio.c
@@ -162,6 +162,10 @@ static u32 mdio45_get_an(const struct mdio_if_info *mdio, u16 addr)
result |= ADVERTISED_100baseT_Half;
if (reg & ADVERTISE_100FULL)
result |= ADVERTISED_100baseT_Full;
+ if (reg & ADVERTISE_PAUSE_CAP)
+ result |= ADVERTISED_Pause;
+ if (reg & ADVERTISE_PAUSE_ASYM)
+ result |= ADVERTISED_Asym_Pause;
return result;
}
@@ -344,11 +348,9 @@ void mdio45_ethtool_spauseparam_an(const struct mdio_if_info *mdio,
old_adv = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN,
MDIO_AN_ADVERTISE);
- adv = old_adv & ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
- if (ecmd->autoneg)
- adv |= mii_advertise_flowctrl(
- (ecmd->rx_pause ? FLOW_CTRL_RX : 0) |
- (ecmd->tx_pause ? FLOW_CTRL_TX : 0));
+ adv = ((old_adv & ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) |
+ mii_advertise_flowctrl((ecmd->rx_pause ? FLOW_CTRL_RX : 0) |
+ (ecmd->tx_pause ? FLOW_CTRL_TX : 0)));
if (adv != old_adv) {
mdio->mdio_write(mdio->dev, mdio->prtad, MDIO_MMD_AN,
MDIO_AN_ADVERTISE, adv);
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index 5dd7225b178e..291a505fd4fc 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -1282,6 +1282,7 @@ static struct pci_device_id mlx4_pci_table[] = {
{ PCI_VDEVICE(MELLANOX, 0x6372) }, /* MT25458 ConnectX EN 10GBASE-T 10GigE */
{ PCI_VDEVICE(MELLANOX, 0x675a) }, /* MT25458 ConnectX EN 10GBASE-T+Gen2 10GigE */
{ PCI_VDEVICE(MELLANOX, 0x6764) }, /* MT26468 ConnectX EN 10GigE PCIe gen2*/
+ { PCI_VDEVICE(MELLANOX, 0x6746) }, /* MT26438 ConnectX EN 40GigE PCIe gen2 5GT/s */
{ PCI_VDEVICE(MELLANOX, 0x676e) }, /* MT26478 ConnectX2 40GigE PCIe gen2 */
{ 0, }
};
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 6930c87f362e..5319db9901d8 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -75,7 +75,7 @@
#include "myri10ge_mcp.h"
#include "myri10ge_mcp_gen_header.h"
-#define MYRI10GE_VERSION_STR "1.5.0-1.432"
+#define MYRI10GE_VERSION_STR "1.5.1-1.451"
MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");
MODULE_AUTHOR("Maintainer: help@myri.com");
@@ -207,7 +207,6 @@ struct myri10ge_priv {
int big_bytes;
int max_intr_slots;
struct net_device *dev;
- struct net_device_stats stats;
spinlock_t stats_lock;
u8 __iomem *sram;
int sram_size;
@@ -1624,10 +1623,21 @@ myri10ge_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
return 0;
}
}
- if (*ptr == 'R' || *ptr == 'Q') {
- /* We've found either an XFP or quad ribbon fiber */
+ if (*ptr == '2')
+ ptr++;
+ if (*ptr == 'R' || *ptr == 'Q' || *ptr == 'S') {
+ /* We've found either an XFP, quad ribbon fiber, or SFP+ */
cmd->port = PORT_FIBRE;
+ cmd->supported |= SUPPORTED_FIBRE;
+ cmd->advertising |= ADVERTISED_FIBRE;
+ } else {
+ cmd->port = PORT_OTHER;
}
+ if (*ptr == 'R' || *ptr == 'S')
+ cmd->transceiver = XCVR_EXTERNAL;
+ else
+ cmd->transceiver = XCVR_INTERNAL;
+
return 0;
}
@@ -1821,7 +1831,7 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
/* force stats update */
(void)myri10ge_get_stats(netdev);
for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++)
- data[i] = ((unsigned long *)&mgp->stats)[i];
+ data[i] = ((unsigned long *)&netdev->stats)[i];
data[i++] = (unsigned int)mgp->tx_boundary;
data[i++] = (unsigned int)mgp->wc_enabled;
@@ -2991,7 +3001,7 @@ static struct net_device_stats *myri10ge_get_stats(struct net_device *dev)
{
struct myri10ge_priv *mgp = netdev_priv(dev);
struct myri10ge_slice_netstats *slice_stats;
- struct net_device_stats *stats = &mgp->stats;
+ struct net_device_stats *stats = &dev->stats;
int i;
spin_lock(&mgp->stats_lock);
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index 7384f59df615..e98cfa6baa8f 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -53,8 +53,8 @@
#define _NETXEN_NIC_LINUX_MAJOR 4
#define _NETXEN_NIC_LINUX_MINOR 0
-#define _NETXEN_NIC_LINUX_SUBVERSION 50
-#define NETXEN_NIC_LINUX_VERSIONID "4.0.50"
+#define _NETXEN_NIC_LINUX_SUBVERSION 62
+#define NETXEN_NIC_LINUX_VERSIONID "4.0.62"
#define NETXEN_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c))
#define _major(v) (((v) >> 24) & 0xff)
@@ -117,9 +117,11 @@
#define NX_P3_B0 0x40
#define NX_P3_B1 0x41
#define NX_P3_B2 0x42
+#define NX_P3P_A0 0x50
#define NX_IS_REVISION_P2(REVISION) (REVISION <= NX_P2_C1)
#define NX_IS_REVISION_P3(REVISION) (REVISION >= NX_P3_A0)
+#define NX_IS_REVISION_P3P(REVISION) (REVISION >= NX_P3P_A0)
#define FIRST_PAGE_GROUP_START 0
#define FIRST_PAGE_GROUP_END 0x100000
@@ -543,13 +545,16 @@ struct netxen_hardware_context {
void __iomem *pci_base1;
void __iomem *pci_base2;
void __iomem *db_base;
+ void __iomem *ocm_win_crb;
+
unsigned long db_len;
unsigned long pci_len0;
- int qdr_sn_window;
- int ddr_mn_window;
- u32 mn_win_crb;
- u32 ms_win_crb;
+ u32 ocm_win;
+ u32 crb_win;
+
+ rwlock_t crb_lock;
+ spinlock_t mem_lock;
u8 cut_through;
u8 revision_id;
@@ -1039,6 +1044,9 @@ typedef struct {
#define LINKEVENT_LINKSPEED_MBPS 0
#define LINKEVENT_LINKSPEED_ENCODED 1
+#define AUTO_FW_RESET_ENABLED 0xEF10AF12
+#define AUTO_FW_RESET_DISABLED 0xDCBAAF12
+
/* firmware response header:
* 63:58 - message type
* 57:56 - owner
@@ -1086,6 +1094,7 @@ typedef struct {
#define NETXEN_NIC_MSIX_ENABLED 0x04
#define NETXEN_NIC_LRO_ENABLED 0x08
#define NETXEN_NIC_BRIDGE_ENABLED 0X10
+#define NETXEN_NIC_DIAG_ENABLED 0x20
#define NETXEN_IS_MSI_FAMILY(adapter) \
((adapter)->flags & (NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED))
@@ -1115,10 +1124,6 @@ struct netxen_adapter {
struct pci_dev *pdev;
struct list_head mac_list;
- u32 curr_window;
- u32 crb_win;
- rwlock_t adapter_lock;
-
spinlock_t tx_clean_lock;
u16 num_txd;
@@ -1180,11 +1185,10 @@ struct netxen_adapter {
u32 (*crb_read)(struct netxen_adapter *, ulong);
int (*crb_write)(struct netxen_adapter *, ulong, u32);
- int (*pci_mem_read)(struct netxen_adapter *, u64, void *, int);
- int (*pci_mem_write)(struct netxen_adapter *, u64, void *, int);
+ int (*pci_mem_read)(struct netxen_adapter *, u64, u64 *);
+ int (*pci_mem_write)(struct netxen_adapter *, u64, u64);
- unsigned long (*pci_set_window)(struct netxen_adapter *,
- unsigned long long);
+ int (*pci_set_window)(struct netxen_adapter *, u64, u32 *);
u32 (*io_read)(struct netxen_adapter *, void __iomem *);
void (*io_write)(struct netxen_adapter *, void __iomem *, u32);
@@ -1203,8 +1207,6 @@ struct netxen_adapter {
struct work_struct tx_timeout_task;
- struct net_device_stats net_stats;
-
nx_nic_intr_coalesce_t coal;
unsigned long state;
@@ -1271,7 +1273,7 @@ int netxen_load_firmware(struct netxen_adapter *adapter);
int netxen_need_fw_reset(struct netxen_adapter *adapter);
void netxen_request_firmware(struct netxen_adapter *adapter);
void netxen_release_firmware(struct netxen_adapter *adapter);
-int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose);
+int netxen_pinit_from_rom(struct netxen_adapter *adapter);
int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp);
int netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index 714f38791a9a..a3b18e0c9670 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -85,11 +85,9 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
strncpy(drvinfo->driver, netxen_nic_driver_name, 32);
strncpy(drvinfo->version, NETXEN_NIC_LINUX_VERSIONID, 32);
- read_lock(&adapter->adapter_lock);
fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR);
fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR);
fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB);
- read_unlock(&adapter->adapter_lock);
sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h
index 7a7177421d7c..a39155d61bad 100644
--- a/drivers/net/netxen/netxen_nic_hdr.h
+++ b/drivers/net/netxen/netxen_nic_hdr.h
@@ -419,6 +419,7 @@ enum {
#define NETXEN_CRB_ROMUSB \
NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_ROMUSB)
#define NETXEN_CRB_I2Q NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_I2Q)
+#define NETXEN_CRB_I2C0 NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_I2C0)
#define NETXEN_CRB_SMB NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_SMB)
#define NETXEN_CRB_MAX NETXEN_PCI_CRB_WINDOW(64)
@@ -661,40 +662,51 @@ enum {
#define NETXEN_NIU_AP_STATION_ADDR_0(I) (NETXEN_CRB_NIU+0xa0040+(I)*0x10000)
#define NETXEN_NIU_AP_STATION_ADDR_1(I) (NETXEN_CRB_NIU+0xa0044+(I)*0x10000)
+
+#define TEST_AGT_CTRL (0x00)
+
+#define TA_CTL_START 1
+#define TA_CTL_ENABLE 2
+#define TA_CTL_WRITE 4
+#define TA_CTL_BUSY 8
+
/*
* Register offsets for MN
*/
-#define MIU_CONTROL (0x000)
-#define MIU_TEST_AGT_CTRL (0x090)
-#define MIU_TEST_AGT_ADDR_LO (0x094)
-#define MIU_TEST_AGT_ADDR_HI (0x098)
-#define MIU_TEST_AGT_WRDATA_LO (0x0a0)
-#define MIU_TEST_AGT_WRDATA_HI (0x0a4)
-#define MIU_TEST_AGT_WRDATA(i) (0x0a0+(4*(i)))
-#define MIU_TEST_AGT_RDDATA_LO (0x0a8)
-#define MIU_TEST_AGT_RDDATA_HI (0x0ac)
-#define MIU_TEST_AGT_RDDATA(i) (0x0a8+(4*(i)))
-#define MIU_TEST_AGT_ADDR_MASK 0xfffffff8
-#define MIU_TEST_AGT_UPPER_ADDR(off) (0)
-
-/* MIU_TEST_AGT_CTRL flags. work for SIU as well */
-#define MIU_TA_CTL_START 1
-#define MIU_TA_CTL_ENABLE 2
-#define MIU_TA_CTL_WRITE 4
-#define MIU_TA_CTL_BUSY 8
-
-#define SIU_TEST_AGT_CTRL (0x060)
-#define SIU_TEST_AGT_ADDR_LO (0x064)
-#define SIU_TEST_AGT_ADDR_HI (0x078)
-#define SIU_TEST_AGT_WRDATA_LO (0x068)
-#define SIU_TEST_AGT_WRDATA_HI (0x06c)
-#define SIU_TEST_AGT_WRDATA(i) (0x068+(4*(i)))
-#define SIU_TEST_AGT_RDDATA_LO (0x070)
-#define SIU_TEST_AGT_RDDATA_HI (0x074)
-#define SIU_TEST_AGT_RDDATA(i) (0x070+(4*(i)))
-
-#define SIU_TEST_AGT_ADDR_MASK 0x3ffff8
-#define SIU_TEST_AGT_UPPER_ADDR(off) ((off)>>22)
+#define MIU_TEST_AGT_BASE (0x90)
+
+#define MIU_TEST_AGT_ADDR_LO (0x04)
+#define MIU_TEST_AGT_ADDR_HI (0x08)
+#define MIU_TEST_AGT_WRDATA_LO (0x10)
+#define MIU_TEST_AGT_WRDATA_HI (0x14)
+#define MIU_TEST_AGT_WRDATA_UPPER_LO (0x20)
+#define MIU_TEST_AGT_WRDATA_UPPER_HI (0x24)
+#define MIU_TEST_AGT_WRDATA(i) (0x10+(0x10*((i)>>1))+(4*((i)&1)))
+#define MIU_TEST_AGT_RDDATA_LO (0x18)
+#define MIU_TEST_AGT_RDDATA_HI (0x1c)
+#define MIU_TEST_AGT_RDDATA_UPPER_LO (0x28)
+#define MIU_TEST_AGT_RDDATA_UPPER_HI (0x2c)
+#define MIU_TEST_AGT_RDDATA(i) (0x18+(0x10*((i)>>1))+(4*((i)&1)))
+
+#define MIU_TEST_AGT_ADDR_MASK 0xfffffff8
+#define MIU_TEST_AGT_UPPER_ADDR(off) (0)
+
+/*
+ * Register offsets for MS
+ */
+#define SIU_TEST_AGT_BASE (0x60)
+
+#define SIU_TEST_AGT_ADDR_LO (0x04)
+#define SIU_TEST_AGT_ADDR_HI (0x18)
+#define SIU_TEST_AGT_WRDATA_LO (0x08)
+#define SIU_TEST_AGT_WRDATA_HI (0x0c)
+#define SIU_TEST_AGT_WRDATA(i) (0x08+(4*(i)))
+#define SIU_TEST_AGT_RDDATA_LO (0x10)
+#define SIU_TEST_AGT_RDDATA_HI (0x14)
+#define SIU_TEST_AGT_RDDATA(i) (0x10+(4*(i)))
+
+#define SIU_TEST_AGT_ADDR_MASK 0x3ffff8
+#define SIU_TEST_AGT_UPPER_ADDR(off) ((off)>>22)
/* XG Link status */
#define XG_LINK_UP 0x10
@@ -856,6 +868,9 @@ enum {
(PCIX_SN_WINDOW_F0 + (0x20 * (func))) :\
(PCIX_SN_WINDOW_F4 + (0x10 * ((func)-4))))
+#define PCIX_OCM_WINDOW (0x10800)
+#define PCIX_OCM_WINDOW_REG(func) (PCIX_OCM_WINDOW + 0x20 * (func))
+
#define PCIX_TARGET_STATUS (0x10118)
#define PCIX_TARGET_STATUS_F1 (0x10160)
#define PCIX_TARGET_STATUS_F2 (0x10164)
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index 32314000dfcd..69205ace16eb 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -31,6 +31,7 @@
#define MASK(n) ((1ULL<<(n))-1)
#define MN_WIN(addr) (((addr & 0x1fc0000) >> 1) | ((addr >> 25) & 0x3ff))
#define OCM_WIN(addr) (((addr & 0x1ff0000) >> 1) | ((addr >> 25) & 0x3ff))
+#define OCM_WIN_P3P(addr) (addr & 0xffc0000)
#define MS_WIN(addr) (addr & 0x0ffc0000)
#define GET_MEM_OFFS_2M(addr) (addr & MASK(18))
@@ -41,6 +42,11 @@
#define CRB_HI(off) ((crb_hub_agt[CRB_BLK(off)] << 20) | ((off) & 0xf0000))
#define CRB_INDIRECT_2M (0x1e0000UL)
+static void netxen_nic_io_write_128M(struct netxen_adapter *adapter,
+ void __iomem *addr, u32 data);
+static u32 netxen_nic_io_read_128M(struct netxen_adapter *adapter,
+ void __iomem *addr);
+
#ifndef readq
static inline u64 readq(void __iomem *addr)
{
@@ -326,7 +332,7 @@ netxen_pcie_sem_lock(struct netxen_adapter *adapter, int sem, u32 id_reg)
if (done == 1)
break;
if (++timeout >= NETXEN_PCIE_SEM_TIMEOUT)
- return -1;
+ return -EIO;
msleep(1);
}
@@ -1046,50 +1052,38 @@ int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac)
* Changes the CRB window to the specified window.
*/
static void
-netxen_nic_pci_change_crbwindow_128M(struct netxen_adapter *adapter, u32 wndw)
+netxen_nic_pci_set_crbwindow_128M(struct netxen_adapter *adapter,
+ u32 window)
{
void __iomem *offset;
- u32 tmp;
- int count = 0;
- uint8_t func = adapter->ahw.pci_func;
+ int count = 10;
+ u8 func = adapter->ahw.pci_func;
- if (adapter->curr_window == wndw)
+ if (adapter->ahw.crb_win == window)
return;
- /*
- * Move the CRB window.
- * We need to write to the "direct access" region of PCI
- * to avoid a race condition where the window register has
- * not been successfully written across CRB before the target
- * register address is received by PCI. The direct region bypasses
- * the CRB bus.
- */
+
offset = PCI_OFFSET_SECOND_RANGE(adapter,
NETXEN_PCIX_PH_REG(PCIE_CRB_WINDOW_REG(func)));
- if (wndw & 0x1)
- wndw = NETXEN_WINDOW_ONE;
+ writel(window, offset);
+ do {
+ if (window == readl(offset))
+ break;
- writel(wndw, offset);
+ if (printk_ratelimit())
+ dev_warn(&adapter->pdev->dev,
+ "failed to set CRB window to %d\n",
+ (window == NETXEN_WINDOW_ONE));
+ udelay(1);
- /* MUST make sure window is set before we forge on... */
- while ((tmp = readl(offset)) != wndw) {
- printk(KERN_WARNING "%s: %s WARNING: CRB window value not "
- "registered properly: 0x%08x.\n",
- netxen_nic_driver_name, __func__, tmp);
- mdelay(1);
- if (count >= 10)
- break;
- count++;
- }
+ } while (--count > 0);
- if (wndw == NETXEN_WINDOW_ONE)
- adapter->curr_window = 1;
- else
- adapter->curr_window = 0;
+ if (count > 0)
+ adapter->ahw.crb_win = window;
}
/*
- * Return -1 if off is not valid,
+ * Returns < 0 if off is not valid,
* 1 if window access is needed. 'off' is set to offset from
* CRB space in 128M pci map
* 0 if no window access is needed. 'off' is set to 2M addr
@@ -1102,7 +1096,7 @@ netxen_nic_pci_get_crb_addr_2M(struct netxen_adapter *adapter, ulong *off)
if (*off >= NETXEN_CRB_MAX)
- return -1;
+ return -EINVAL;
if (*off >= NETXEN_PCI_CAMQM && (*off < NETXEN_PCI_CAMQM_2M_END)) {
*off = (*off - NETXEN_PCI_CAMQM) + NETXEN_PCI_CAMQM_2M_BASE +
@@ -1111,7 +1105,7 @@ netxen_nic_pci_get_crb_addr_2M(struct netxen_adapter *adapter, ulong *off)
}
if (*off < NETXEN_PCI_CRBSPACE)
- return -1;
+ return -EINVAL;
*off -= NETXEN_PCI_CRBSPACE;
@@ -1140,20 +1134,24 @@ netxen_nic_pci_get_crb_addr_2M(struct netxen_adapter *adapter, ulong *off)
static void
netxen_nic_pci_set_crbwindow_2M(struct netxen_adapter *adapter, ulong *off)
{
- u32 win_read;
+ u32 window;
+ void __iomem *addr = adapter->ahw.pci_base0 + CRB_WINDOW_2M;
- adapter->crb_win = CRB_HI(*off);
- writel(adapter->crb_win, (adapter->ahw.pci_base0 + CRB_WINDOW_2M));
- /*
- * Read back value to make sure write has gone through before trying
- * to use it.
- */
- win_read = readl(adapter->ahw.pci_base0 + CRB_WINDOW_2M);
- if (win_read != adapter->crb_win) {
- printk(KERN_ERR "%s: Written crbwin (0x%x) != "
- "Read crbwin (0x%x), off=0x%lx\n",
- __func__, adapter->crb_win, win_read, *off);
+ window = CRB_HI(*off);
+
+ if (adapter->ahw.crb_win == window)
+ goto done;
+
+ writel(window, addr);
+ if (readl(addr) != window) {
+ if (printk_ratelimit())
+ dev_warn(&adapter->pdev->dev,
+ "failed to set CRB window to %d off 0x%lx\n",
+ window, *off);
}
+ adapter->ahw.crb_win = window;
+
+done:
*off = (*off & MASK(16)) + CRB_INDIRECT_2M +
(ulong)adapter->ahw.pci_base0;
}
@@ -1172,16 +1170,15 @@ netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter, ulong off, u32 data)
BUG_ON(!addr);
if (ADDR_IN_WINDOW1(off)) { /* Window 1 */
- read_lock(&adapter->adapter_lock);
- writel(data, addr);
- read_unlock(&adapter->adapter_lock);
+ netxen_nic_io_write_128M(adapter, addr, data);
} else { /* Window 0 */
- write_lock_irqsave(&adapter->adapter_lock, flags);
+ write_lock_irqsave(&adapter->ahw.crb_lock, flags);
addr = pci_base_offset(adapter, off);
- netxen_nic_pci_change_crbwindow_128M(adapter, 0);
+ netxen_nic_pci_set_crbwindow_128M(adapter, 0);
writel(data, addr);
- netxen_nic_pci_change_crbwindow_128M(adapter, 1);
- write_unlock_irqrestore(&adapter->adapter_lock, flags);
+ netxen_nic_pci_set_crbwindow_128M(adapter,
+ NETXEN_WINDOW_ONE);
+ write_unlock_irqrestore(&adapter->ahw.crb_lock, flags);
}
return 0;
@@ -1202,15 +1199,14 @@ netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter, ulong off)
BUG_ON(!addr);
if (ADDR_IN_WINDOW1(off)) { /* Window 1 */
- read_lock(&adapter->adapter_lock);
- data = readl(addr);
- read_unlock(&adapter->adapter_lock);
+ data = netxen_nic_io_read_128M(adapter, addr);
} else { /* Window 0 */
- write_lock_irqsave(&adapter->adapter_lock, flags);
- netxen_nic_pci_change_crbwindow_128M(adapter, 0);
+ write_lock_irqsave(&adapter->ahw.crb_lock, flags);
+ netxen_nic_pci_set_crbwindow_128M(adapter, 0);
data = readl(addr);
- netxen_nic_pci_change_crbwindow_128M(adapter, 1);
- write_unlock_irqrestore(&adapter->adapter_lock, flags);
+ netxen_nic_pci_set_crbwindow_128M(adapter,
+ NETXEN_WINDOW_ONE);
+ write_unlock_irqrestore(&adapter->ahw.crb_lock, flags);
}
return data;
@@ -1224,25 +1220,26 @@ netxen_nic_hw_write_wx_2M(struct netxen_adapter *adapter, ulong off, u32 data)
rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off);
- if (rv == -1) {
- printk(KERN_ERR "%s: invalid offset: 0x%016lx\n",
- __func__, off);
- dump_stack();
- return -1;
+ if (rv == 0) {
+ writel(data, (void __iomem *)off);
+ return 0;
}
- if (rv == 1) {
- write_lock_irqsave(&adapter->adapter_lock, flags);
+ if (rv > 0) {
+ /* indirect access */
+ write_lock_irqsave(&adapter->ahw.crb_lock, flags);
crb_win_lock(adapter);
netxen_nic_pci_set_crbwindow_2M(adapter, &off);
writel(data, (void __iomem *)off);
crb_win_unlock(adapter);
- write_unlock_irqrestore(&adapter->adapter_lock, flags);
- } else
- writel(data, (void __iomem *)off);
-
+ write_unlock_irqrestore(&adapter->ahw.crb_lock, flags);
+ return 0;
+ }
- return 0;
+ dev_err(&adapter->pdev->dev,
+ "%s: invalid offset: 0x%016lx\n", __func__, off);
+ dump_stack();
+ return -EIO;
}
static u32
@@ -1254,99 +1251,33 @@ netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, ulong off)
rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off);
- if (rv == -1) {
- printk(KERN_ERR "%s: invalid offset: 0x%016lx\n",
- __func__, off);
- dump_stack();
- return -1;
- }
+ if (rv == 0)
+ return readl((void __iomem *)off);
- if (rv == 1) {
- write_lock_irqsave(&adapter->adapter_lock, flags);
+ if (rv > 0) {
+ /* indirect access */
+ write_lock_irqsave(&adapter->ahw.crb_lock, flags);
crb_win_lock(adapter);
netxen_nic_pci_set_crbwindow_2M(adapter, &off);
data = readl((void __iomem *)off);
crb_win_unlock(adapter);
- write_unlock_irqrestore(&adapter->adapter_lock, flags);
- } else
- data = readl((void __iomem *)off);
-
- return data;
-}
-
-static int netxen_pci_set_window_warning_count;
-
-static unsigned long
-netxen_nic_pci_set_window_128M(struct netxen_adapter *adapter,
- unsigned long long addr)
-{
- void __iomem *offset;
- int window;
- unsigned long long qdr_max;
- uint8_t func = adapter->ahw.pci_func;
-
- if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
- qdr_max = NETXEN_ADDR_QDR_NET_MAX_P2;
- } else {
- qdr_max = NETXEN_ADDR_QDR_NET_MAX_P3;
+ write_unlock_irqrestore(&adapter->ahw.crb_lock, flags);
+ return data;
}
- if (ADDR_IN_RANGE(addr, NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) {
- /* DDR network side */
- addr -= NETXEN_ADDR_DDR_NET;
- window = (addr >> 25) & 0x3ff;
- if (adapter->ahw.ddr_mn_window != window) {
- adapter->ahw.ddr_mn_window = window;
- offset = PCI_OFFSET_SECOND_RANGE(adapter,
- NETXEN_PCIX_PH_REG(PCIE_MN_WINDOW_REG(func)));
- writel(window, offset);
- /* MUST make sure window is set before we forge on... */
- readl(offset);
- }
- addr -= (window * NETXEN_WINDOW_ONE);
- addr += NETXEN_PCI_DDR_NET;
- } else if (ADDR_IN_RANGE(addr, NETXEN_ADDR_OCM0, NETXEN_ADDR_OCM0_MAX)) {
- addr -= NETXEN_ADDR_OCM0;
- addr += NETXEN_PCI_OCM0;
- } else if (ADDR_IN_RANGE(addr, NETXEN_ADDR_OCM1, NETXEN_ADDR_OCM1_MAX)) {
- addr -= NETXEN_ADDR_OCM1;
- addr += NETXEN_PCI_OCM1;
- } else if (ADDR_IN_RANGE(addr, NETXEN_ADDR_QDR_NET, qdr_max)) {
- /* QDR network side */
- addr -= NETXEN_ADDR_QDR_NET;
- window = (addr >> 22) & 0x3f;
- if (adapter->ahw.qdr_sn_window != window) {
- adapter->ahw.qdr_sn_window = window;
- offset = PCI_OFFSET_SECOND_RANGE(adapter,
- NETXEN_PCIX_PH_REG(PCIE_SN_WINDOW_REG(func)));
- writel((window << 22), offset);
- /* MUST make sure window is set before we forge on... */
- readl(offset);
- }
- addr -= (window * 0x400000);
- addr += NETXEN_PCI_QDR_NET;
- } else {
- /*
- * peg gdb frequently accesses memory that doesn't exist,
- * this limits the chit chat so debugging isn't slowed down.
- */
- if ((netxen_pci_set_window_warning_count++ < 8)
- || (netxen_pci_set_window_warning_count % 64 == 0))
- printk("%s: Warning:netxen_nic_pci_set_window()"
- " Unknown address range!\n",
- netxen_nic_driver_name);
- addr = -1UL;
- }
- return addr;
+ dev_err(&adapter->pdev->dev,
+ "%s: invalid offset: 0x%016lx\n", __func__, off);
+ dump_stack();
+ return -1;
}
/* window 1 registers only */
static void netxen_nic_io_write_128M(struct netxen_adapter *adapter,
void __iomem *addr, u32 data)
{
- read_lock(&adapter->adapter_lock);
+ read_lock(&adapter->ahw.crb_lock);
writel(data, addr);
- read_unlock(&adapter->adapter_lock);
+ read_unlock(&adapter->ahw.crb_lock);
}
static u32 netxen_nic_io_read_128M(struct netxen_adapter *adapter,
@@ -1354,9 +1285,9 @@ static u32 netxen_nic_io_read_128M(struct netxen_adapter *adapter,
{
u32 val;
- read_lock(&adapter->adapter_lock);
+ read_lock(&adapter->ahw.crb_lock);
val = readl(addr);
- read_unlock(&adapter->adapter_lock);
+ read_unlock(&adapter->ahw.crb_lock);
return val;
}
@@ -1389,475 +1320,421 @@ netxen_get_ioaddr(struct netxen_adapter *adapter, u32 offset)
return (void __iomem *)off;
}
-static unsigned long
-netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter,
- unsigned long long addr)
+static int
+netxen_nic_pci_set_window_128M(struct netxen_adapter *adapter,
+ u64 addr, u32 *start)
{
- int window;
- u32 win_read;
-
- if (ADDR_IN_RANGE(addr, NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) {
- /* DDR network side */
- window = MN_WIN(addr);
- adapter->ahw.ddr_mn_window = window;
- NXWR32(adapter, adapter->ahw.mn_win_crb, window);
- win_read = NXRD32(adapter, adapter->ahw.mn_win_crb);
- if ((win_read << 17) != window) {
- printk(KERN_INFO "Written MNwin (0x%x) != "
- "Read MNwin (0x%x)\n", window, win_read);
- }
- addr = GET_MEM_OFFS_2M(addr) + NETXEN_PCI_DDR_NET;
+ if (ADDR_IN_RANGE(addr, NETXEN_ADDR_OCM0, NETXEN_ADDR_OCM0_MAX)) {
+ *start = (addr - NETXEN_ADDR_OCM0 + NETXEN_PCI_OCM0);
+ return 0;
} else if (ADDR_IN_RANGE(addr,
- NETXEN_ADDR_OCM0, NETXEN_ADDR_OCM0_MAX)) {
- if ((addr & 0x00ff800) == 0xff800) {
- printk("%s: QM access not handled.\n", __func__);
- addr = -1UL;
- }
+ NETXEN_ADDR_OCM1, NETXEN_ADDR_OCM1_MAX)) {
+ *start = (addr - NETXEN_ADDR_OCM1 + NETXEN_PCI_OCM1);
+ return 0;
+ }
+ return -EIO;
+}
+
+static int
+netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter,
+ u64 addr, u32 *start)
+{
+ u32 window;
+ struct pci_dev *pdev = adapter->pdev;
+
+ if ((addr & 0x00ff800) == 0xff800) {
+ if (printk_ratelimit())
+ dev_warn(&pdev->dev, "QM access not handled\n");
+ return -EIO;
+ }
+
+ if (NX_IS_REVISION_P3P(adapter->ahw.revision_id))
+ window = OCM_WIN_P3P(addr);
+ else
window = OCM_WIN(addr);
- adapter->ahw.ddr_mn_window = window;
- NXWR32(adapter, adapter->ahw.mn_win_crb, window);
- win_read = NXRD32(adapter, adapter->ahw.mn_win_crb);
- if ((win_read >> 7) != window) {
- printk(KERN_INFO "%s: Written OCMwin (0x%x) != "
- "Read OCMwin (0x%x)\n",
- __func__, window, win_read);
- }
- addr = GET_MEM_OFFS_2M(addr) + NETXEN_PCI_OCM0_2M;
- } else if (ADDR_IN_RANGE(addr,
- NETXEN_ADDR_QDR_NET, NETXEN_ADDR_QDR_NET_MAX_P3)) {
- /* QDR network side */
- window = MS_WIN(addr);
- adapter->ahw.qdr_sn_window = window;
- NXWR32(adapter, adapter->ahw.ms_win_crb, window);
- win_read = NXRD32(adapter, adapter->ahw.ms_win_crb);
- if (win_read != window) {
- printk(KERN_INFO "%s: Written MSwin (0x%x) != "
- "Read MSwin (0x%x)\n",
- __func__, window, win_read);
- }
- addr = GET_MEM_OFFS_2M(addr) + NETXEN_PCI_QDR_NET;
+ writel(window, adapter->ahw.ocm_win_crb);
+ /* read back to flush */
+ readl(adapter->ahw.ocm_win_crb);
- } else {
- /*
- * peg gdb frequently accesses memory that doesn't exist,
- * this limits the chit chat so debugging isn't slowed down.
- */
- if ((netxen_pci_set_window_warning_count++ < 8)
- || (netxen_pci_set_window_warning_count%64 == 0)) {
- printk("%s: Warning:%s Unknown address range!\n",
- __func__, netxen_nic_driver_name);
+ adapter->ahw.ocm_win = window;
+ *start = NETXEN_PCI_OCM0_2M + GET_MEM_OFFS_2M(addr);
+ return 0;
}
- addr = -1UL;
+
+static int
+netxen_nic_pci_mem_access_direct(struct netxen_adapter *adapter, u64 off,
+ u64 *data, int op)
+{
+ void __iomem *addr, *mem_ptr = NULL;
+ resource_size_t mem_base;
+ int ret = -EIO;
+ u32 start;
+
+ spin_lock(&adapter->ahw.mem_lock);
+
+ ret = adapter->pci_set_window(adapter, off, &start);
+ if (ret != 0)
+ goto unlock;
+
+ addr = pci_base_offset(adapter, start);
+ if (addr)
+ goto noremap;
+
+ mem_base = pci_resource_start(adapter->pdev, 0) + (start & PAGE_MASK);
+
+ mem_ptr = ioremap(mem_base, PAGE_SIZE);
+ if (mem_ptr == NULL) {
+ ret = -EIO;
+ goto unlock;
}
- return addr;
+
+ addr = mem_ptr + (start & (PAGE_SIZE - 1));
+
+noremap:
+ if (op == 0) /* read */
+ *data = readq(addr);
+ else /* write */
+ writeq(*data, addr);
+
+unlock:
+ spin_unlock(&adapter->ahw.mem_lock);
+
+ if (mem_ptr)
+ iounmap(mem_ptr);
+ return ret;
}
#define MAX_CTL_CHECK 1000
static int
netxen_nic_pci_mem_write_128M(struct netxen_adapter *adapter,
- u64 off, void *data, int size)
+ u64 off, u64 data)
{
- unsigned long flags;
- int i, j, ret = 0, loop, sz[2], off0;
- uint32_t temp;
- uint64_t off8, tmpw, word[2] = {0, 0};
+ int j, ret;
+ u32 temp, off_lo, off_hi, addr_hi, data_hi, data_lo;
void __iomem *mem_crb;
- if (size != 8)
+ /* Only 64-bit aligned access */
+ if (off & 7)
return -EIO;
+ /* P2 has different SIU and MIU test agent base addr */
if (ADDR_IN_RANGE(off, NETXEN_ADDR_QDR_NET,
NETXEN_ADDR_QDR_NET_MAX_P2)) {
- mem_crb = pci_base_offset(adapter, NETXEN_CRB_QDR_NET);
+ mem_crb = pci_base_offset(adapter,
+ NETXEN_CRB_QDR_NET+SIU_TEST_AGT_BASE);
+ addr_hi = SIU_TEST_AGT_ADDR_HI;
+ data_lo = SIU_TEST_AGT_WRDATA_LO;
+ data_hi = SIU_TEST_AGT_WRDATA_HI;
+ off_lo = off & SIU_TEST_AGT_ADDR_MASK;
+ off_hi = SIU_TEST_AGT_UPPER_ADDR(off);
goto correct;
}
if (ADDR_IN_RANGE(off, NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) {
- mem_crb = pci_base_offset(adapter, NETXEN_CRB_DDR_NET);
+ mem_crb = pci_base_offset(adapter,
+ NETXEN_CRB_DDR_NET+MIU_TEST_AGT_BASE);
+ addr_hi = MIU_TEST_AGT_ADDR_HI;
+ data_lo = MIU_TEST_AGT_WRDATA_LO;
+ data_hi = MIU_TEST_AGT_WRDATA_HI;
+ off_lo = off & MIU_TEST_AGT_ADDR_MASK;
+ off_hi = 0;
goto correct;
}
- return -EIO;
-
-correct:
- off8 = off & 0xfffffff8;
- off0 = off & 0x7;
- sz[0] = (size < (8 - off0)) ? size : (8 - off0);
- sz[1] = size - sz[0];
- loop = ((off0 + size - 1) >> 3) + 1;
-
- if ((size != 8) || (off0 != 0)) {
- for (i = 0; i < loop; i++) {
- if (adapter->pci_mem_read(adapter,
- off8 + (i << 3), &word[i], 8))
- return -1;
+ if (ADDR_IN_RANGE(off, NETXEN_ADDR_OCM0, NETXEN_ADDR_OCM0_MAX) ||
+ ADDR_IN_RANGE(off, NETXEN_ADDR_OCM1, NETXEN_ADDR_OCM1_MAX)) {
+ if (adapter->ahw.pci_len0 != 0) {
+ return netxen_nic_pci_mem_access_direct(adapter,
+ off, &data, 1);
}
}
- switch (size) {
- case 1:
- tmpw = *((uint8_t *)data);
- break;
- case 2:
- tmpw = *((uint16_t *)data);
- break;
- case 4:
- tmpw = *((uint32_t *)data);
- break;
- case 8:
- default:
- tmpw = *((uint64_t *)data);
- break;
- }
- word[0] &= ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
- word[0] |= tmpw << (off0 * 8);
+ return -EIO;
- if (loop == 2) {
- word[1] &= ~(~0ULL << (sz[1] * 8));
- word[1] |= tmpw >> (sz[0] * 8);
+correct:
+ spin_lock(&adapter->ahw.mem_lock);
+ netxen_nic_pci_set_crbwindow_128M(adapter, 0);
+
+ writel(off_lo, (mem_crb + MIU_TEST_AGT_ADDR_LO));
+ writel(off_hi, (mem_crb + addr_hi));
+ writel(data & 0xffffffff, (mem_crb + data_lo));
+ writel((data >> 32) & 0xffffffff, (mem_crb + data_hi));
+ writel((TA_CTL_ENABLE | TA_CTL_WRITE), (mem_crb + TEST_AGT_CTRL));
+ writel((TA_CTL_START | TA_CTL_ENABLE | TA_CTL_WRITE),
+ (mem_crb + TEST_AGT_CTRL));
+
+ for (j = 0; j < MAX_CTL_CHECK; j++) {
+ temp = readl((mem_crb + TEST_AGT_CTRL));
+ if ((temp & TA_CTL_BUSY) == 0)
+ break;
}
- write_lock_irqsave(&adapter->adapter_lock, flags);
- netxen_nic_pci_change_crbwindow_128M(adapter, 0);
-
- for (i = 0; i < loop; i++) {
- writel((uint32_t)(off8 + (i << 3)),
- (mem_crb+MIU_TEST_AGT_ADDR_LO));
- writel(0,
- (mem_crb+MIU_TEST_AGT_ADDR_HI));
- writel(word[i] & 0xffffffff,
- (mem_crb+MIU_TEST_AGT_WRDATA_LO));
- writel((word[i] >> 32) & 0xffffffff,
- (mem_crb+MIU_TEST_AGT_WRDATA_HI));
- writel(MIU_TA_CTL_ENABLE|MIU_TA_CTL_WRITE,
- (mem_crb+MIU_TEST_AGT_CTRL));
- writel(MIU_TA_CTL_START|MIU_TA_CTL_ENABLE|MIU_TA_CTL_WRITE,
- (mem_crb+MIU_TEST_AGT_CTRL));
-
- for (j = 0; j < MAX_CTL_CHECK; j++) {
- temp = readl(
- (mem_crb+MIU_TEST_AGT_CTRL));
- if ((temp & MIU_TA_CTL_BUSY) == 0)
- break;
- }
-
- if (j >= MAX_CTL_CHECK) {
- if (printk_ratelimit())
- dev_err(&adapter->pdev->dev,
+ if (j >= MAX_CTL_CHECK) {
+ if (printk_ratelimit())
+ dev_err(&adapter->pdev->dev,
"failed to write through agent\n");
- ret = -1;
- break;
- }
- }
+ ret = -EIO;
+ } else
+ ret = 0;
- netxen_nic_pci_change_crbwindow_128M(adapter, 1);
- write_unlock_irqrestore(&adapter->adapter_lock, flags);
+ netxen_nic_pci_set_crbwindow_128M(adapter, NETXEN_WINDOW_ONE);
+ spin_unlock(&adapter->ahw.mem_lock);
return ret;
}
static int
netxen_nic_pci_mem_read_128M(struct netxen_adapter *adapter,
- u64 off, void *data, int size)
+ u64 off, u64 *data)
{
- unsigned long flags;
- int i, j = 0, k, start, end, loop, sz[2], off0[2];
- uint32_t temp;
- uint64_t off8, val, word[2] = {0, 0};
+ int j, ret;
+ u32 temp, off_lo, off_hi, addr_hi, data_hi, data_lo;
+ u64 val;
void __iomem *mem_crb;
- if (size != 8)
+ /* Only 64-bit aligned access */
+ if (off & 7)
return -EIO;
+ /* P2 has different SIU and MIU test agent base addr */
if (ADDR_IN_RANGE(off, NETXEN_ADDR_QDR_NET,
NETXEN_ADDR_QDR_NET_MAX_P2)) {
- mem_crb = pci_base_offset(adapter, NETXEN_CRB_QDR_NET);
+ mem_crb = pci_base_offset(adapter,
+ NETXEN_CRB_QDR_NET+SIU_TEST_AGT_BASE);
+ addr_hi = SIU_TEST_AGT_ADDR_HI;
+ data_lo = SIU_TEST_AGT_RDDATA_LO;
+ data_hi = SIU_TEST_AGT_RDDATA_HI;
+ off_lo = off & SIU_TEST_AGT_ADDR_MASK;
+ off_hi = SIU_TEST_AGT_UPPER_ADDR(off);
goto correct;
}
if (ADDR_IN_RANGE(off, NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) {
- mem_crb = pci_base_offset(adapter, NETXEN_CRB_DDR_NET);
+ mem_crb = pci_base_offset(adapter,
+ NETXEN_CRB_DDR_NET+MIU_TEST_AGT_BASE);
+ addr_hi = MIU_TEST_AGT_ADDR_HI;
+ data_lo = MIU_TEST_AGT_RDDATA_LO;
+ data_hi = MIU_TEST_AGT_RDDATA_HI;
+ off_lo = off & MIU_TEST_AGT_ADDR_MASK;
+ off_hi = 0;
goto correct;
}
+ if (ADDR_IN_RANGE(off, NETXEN_ADDR_OCM0, NETXEN_ADDR_OCM0_MAX) ||
+ ADDR_IN_RANGE(off, NETXEN_ADDR_OCM1, NETXEN_ADDR_OCM1_MAX)) {
+ if (adapter->ahw.pci_len0 != 0) {
+ return netxen_nic_pci_mem_access_direct(adapter,
+ off, data, 0);
+ }
+ }
+
return -EIO;
correct:
- off8 = off & 0xfffffff8;
- off0[0] = off & 0x7;
- off0[1] = 0;
- sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]);
- sz[1] = size - sz[0];
- loop = ((off0[0] + size - 1) >> 3) + 1;
-
- write_lock_irqsave(&adapter->adapter_lock, flags);
- netxen_nic_pci_change_crbwindow_128M(adapter, 0);
-
- for (i = 0; i < loop; i++) {
- writel((uint32_t)(off8 + (i << 3)),
- (mem_crb+MIU_TEST_AGT_ADDR_LO));
- writel(0,
- (mem_crb+MIU_TEST_AGT_ADDR_HI));
- writel(MIU_TA_CTL_ENABLE,
- (mem_crb+MIU_TEST_AGT_CTRL));
- writel(MIU_TA_CTL_START|MIU_TA_CTL_ENABLE,
- (mem_crb+MIU_TEST_AGT_CTRL));
+ spin_lock(&adapter->ahw.mem_lock);
+ netxen_nic_pci_set_crbwindow_128M(adapter, 0);
- for (j = 0; j < MAX_CTL_CHECK; j++) {
- temp = readl(
- (mem_crb+MIU_TEST_AGT_CTRL));
- if ((temp & MIU_TA_CTL_BUSY) == 0)
- break;
- }
+ writel(off_lo, (mem_crb + MIU_TEST_AGT_ADDR_LO));
+ writel(off_hi, (mem_crb + addr_hi));
+ writel(TA_CTL_ENABLE, (mem_crb + TEST_AGT_CTRL));
+ writel((TA_CTL_START|TA_CTL_ENABLE), (mem_crb + TEST_AGT_CTRL));
- if (j >= MAX_CTL_CHECK) {
- if (printk_ratelimit())
- dev_err(&adapter->pdev->dev,
- "failed to read through agent\n");
+ for (j = 0; j < MAX_CTL_CHECK; j++) {
+ temp = readl(mem_crb + TEST_AGT_CTRL);
+ if ((temp & TA_CTL_BUSY) == 0)
break;
- }
-
- start = off0[i] >> 2;
- end = (off0[i] + sz[i] - 1) >> 2;
- for (k = start; k <= end; k++) {
- word[i] |= ((uint64_t) readl(
- (mem_crb +
- MIU_TEST_AGT_RDDATA(k))) << (32*k));
- }
}
- netxen_nic_pci_change_crbwindow_128M(adapter, 1);
- write_unlock_irqrestore(&adapter->adapter_lock, flags);
-
- if (j >= MAX_CTL_CHECK)
- return -1;
-
- if (sz[0] == 8) {
- val = word[0];
+ if (j >= MAX_CTL_CHECK) {
+ if (printk_ratelimit())
+ dev_err(&adapter->pdev->dev,
+ "failed to read through agent\n");
+ ret = -EIO;
} else {
- val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) |
- ((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8));
- }
- switch (size) {
- case 1:
- *(uint8_t *)data = val;
- break;
- case 2:
- *(uint16_t *)data = val;
- break;
- case 4:
- *(uint32_t *)data = val;
- break;
- case 8:
- *(uint64_t *)data = val;
- break;
+ temp = readl(mem_crb + data_hi);
+ val = ((u64)temp << 32);
+ val |= readl(mem_crb + data_lo);
+ *data = val;
+ ret = 0;
}
- return 0;
+
+ netxen_nic_pci_set_crbwindow_128M(adapter, NETXEN_WINDOW_ONE);
+ spin_unlock(&adapter->ahw.mem_lock);
+
+ return ret;
}
static int
netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter,
- u64 off, void *data, int size)
+ u64 off, u64 data)
{
- int i, j, ret = 0, loop, sz[2], off0;
- uint32_t temp;
- uint64_t off8, tmpw, word[2] = {0, 0};
+ int i, j, ret;
+ u32 temp, off8;
+ u64 stride;
void __iomem *mem_crb;
- if (size != 8)
+ /* Only 64-bit aligned access */
+ if (off & 7)
return -EIO;
+ /* P3 onward, test agent base for MIU and SIU is same */
if (ADDR_IN_RANGE(off, NETXEN_ADDR_QDR_NET,
NETXEN_ADDR_QDR_NET_MAX_P3)) {
- mem_crb = netxen_get_ioaddr(adapter, NETXEN_CRB_QDR_NET);
+ mem_crb = netxen_get_ioaddr(adapter,
+ NETXEN_CRB_QDR_NET+MIU_TEST_AGT_BASE);
goto correct;
}
if (ADDR_IN_RANGE(off, NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) {
- mem_crb = netxen_get_ioaddr(adapter, NETXEN_CRB_DDR_NET);
+ mem_crb = netxen_get_ioaddr(adapter,
+ NETXEN_CRB_DDR_NET+MIU_TEST_AGT_BASE);
goto correct;
}
+ if (ADDR_IN_RANGE(off, NETXEN_ADDR_OCM0, NETXEN_ADDR_OCM0_MAX))
+ return netxen_nic_pci_mem_access_direct(adapter, off, &data, 1);
+
return -EIO;
correct:
- off8 = off & 0xfffffff8;
- off0 = off & 0x7;
- sz[0] = (size < (8 - off0)) ? size : (8 - off0);
- sz[1] = size - sz[0];
- loop = ((off0 + size - 1) >> 3) + 1;
-
- if ((size != 8) || (off0 != 0)) {
- for (i = 0; i < loop; i++) {
- if (adapter->pci_mem_read(adapter,
- off8 + (i << 3), &word[i], 8))
- return -1;
- }
- }
-
- switch (size) {
- case 1:
- tmpw = *((uint8_t *)data);
- break;
- case 2:
- tmpw = *((uint16_t *)data);
- break;
- case 4:
- tmpw = *((uint32_t *)data);
- break;
- case 8:
- default:
- tmpw = *((uint64_t *)data);
- break;
- }
+ stride = NX_IS_REVISION_P3P(adapter->ahw.revision_id) ? 16 : 8;
- word[0] &= ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
- word[0] |= tmpw << (off0 * 8);
+ off8 = off & ~(stride-1);
- if (loop == 2) {
- word[1] &= ~(~0ULL << (sz[1] * 8));
- word[1] |= tmpw >> (sz[0] * 8);
- }
+ spin_lock(&adapter->ahw.mem_lock);
- /*
- * don't lock here - write_wx gets the lock if each time
- * write_lock_irqsave(&adapter->adapter_lock, flags);
- * netxen_nic_pci_change_crbwindow_128M(adapter, 0);
- */
+ writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO));
+ writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI));
- for (i = 0; i < loop; i++) {
- writel(off8 + (i << 3), mem_crb+MIU_TEST_AGT_ADDR_LO);
- writel(0, mem_crb+MIU_TEST_AGT_ADDR_HI);
- writel(word[i] & 0xffffffff, mem_crb+MIU_TEST_AGT_WRDATA_LO);
- writel((word[i] >> 32) & 0xffffffff,
- mem_crb+MIU_TEST_AGT_WRDATA_HI);
- writel((MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE),
- mem_crb+MIU_TEST_AGT_CTRL);
- writel(MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE,
- mem_crb+MIU_TEST_AGT_CTRL);
+ i = 0;
+ if (stride == 16) {
+ writel(TA_CTL_ENABLE, (mem_crb + TEST_AGT_CTRL));
+ writel((TA_CTL_START | TA_CTL_ENABLE),
+ (mem_crb + TEST_AGT_CTRL));
for (j = 0; j < MAX_CTL_CHECK; j++) {
- temp = readl(mem_crb + MIU_TEST_AGT_CTRL);
- if ((temp & MIU_TA_CTL_BUSY) == 0)
+ temp = readl(mem_crb + TEST_AGT_CTRL);
+ if ((temp & TA_CTL_BUSY) == 0)
break;
}
if (j >= MAX_CTL_CHECK) {
- if (printk_ratelimit())
- dev_err(&adapter->pdev->dev,
- "failed to write through agent\n");
- ret = -1;
- break;
+ ret = -EIO;
+ goto done;
}
+
+ i = (off & 0xf) ? 0 : 2;
+ writel(readl(mem_crb + MIU_TEST_AGT_RDDATA(i)),
+ mem_crb + MIU_TEST_AGT_WRDATA(i));
+ writel(readl(mem_crb + MIU_TEST_AGT_RDDATA(i+1)),
+ mem_crb + MIU_TEST_AGT_WRDATA(i+1));
+ i = (off & 0xf) ? 2 : 0;
}
- /*
- * netxen_nic_pci_change_crbwindow_128M(adapter, 1);
- * write_unlock_irqrestore(&adapter->adapter_lock, flags);
- */
+ writel(data & 0xffffffff,
+ mem_crb + MIU_TEST_AGT_WRDATA(i));
+ writel((data >> 32) & 0xffffffff,
+ mem_crb + MIU_TEST_AGT_WRDATA(i+1));
+
+ writel((TA_CTL_ENABLE | TA_CTL_WRITE), (mem_crb + TEST_AGT_CTRL));
+ writel((TA_CTL_START | TA_CTL_ENABLE | TA_CTL_WRITE),
+ (mem_crb + TEST_AGT_CTRL));
+
+ for (j = 0; j < MAX_CTL_CHECK; j++) {
+ temp = readl(mem_crb + TEST_AGT_CTRL);
+ if ((temp & TA_CTL_BUSY) == 0)
+ break;
+ }
+
+ if (j >= MAX_CTL_CHECK) {
+ if (printk_ratelimit())
+ dev_err(&adapter->pdev->dev,
+ "failed to write through agent\n");
+ ret = -EIO;
+ } else
+ ret = 0;
+
+done:
+ spin_unlock(&adapter->ahw.mem_lock);
+
return ret;
}
static int
netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter,
- u64 off, void *data, int size)
+ u64 off, u64 *data)
{
- int i, j = 0, k, start, end, loop, sz[2], off0[2];
- uint32_t temp;
- uint64_t off8, val, word[2] = {0, 0};
+ int j, ret;
+ u32 temp, off8;
+ u64 val, stride;
void __iomem *mem_crb;
- if (size != 8)
+ /* Only 64-bit aligned access */
+ if (off & 7)
return -EIO;
+ /* P3 onward, test agent base for MIU and SIU is same */
if (ADDR_IN_RANGE(off, NETXEN_ADDR_QDR_NET,
NETXEN_ADDR_QDR_NET_MAX_P3)) {
- mem_crb = netxen_get_ioaddr(adapter, NETXEN_CRB_QDR_NET);
+ mem_crb = netxen_get_ioaddr(adapter,
+ NETXEN_CRB_QDR_NET+MIU_TEST_AGT_BASE);
goto correct;
}
if (ADDR_IN_RANGE(off, NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) {
- mem_crb = netxen_get_ioaddr(adapter, NETXEN_CRB_DDR_NET);
+ mem_crb = netxen_get_ioaddr(adapter,
+ NETXEN_CRB_DDR_NET+MIU_TEST_AGT_BASE);
goto correct;
}
+ if (ADDR_IN_RANGE(off, NETXEN_ADDR_OCM0, NETXEN_ADDR_OCM0_MAX)) {
+ return netxen_nic_pci_mem_access_direct(adapter,
+ off, data, 0);
+ }
+
return -EIO;
correct:
- off8 = off & 0xfffffff8;
- off0[0] = off & 0x7;
- off0[1] = 0;
- sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]);
- sz[1] = size - sz[0];
- loop = ((off0[0] + size - 1) >> 3) + 1;
+ stride = NX_IS_REVISION_P3P(adapter->ahw.revision_id) ? 16 : 8;
- /*
- * don't lock here - write_wx gets the lock if each time
- * write_lock_irqsave(&adapter->adapter_lock, flags);
- * netxen_nic_pci_change_crbwindow_128M(adapter, 0);
- */
+ off8 = off & ~(stride-1);
- for (i = 0; i < loop; i++) {
- writel(off8 + (i << 3), mem_crb + MIU_TEST_AGT_ADDR_LO);
- writel(0, mem_crb + MIU_TEST_AGT_ADDR_HI);
- writel(MIU_TA_CTL_ENABLE, mem_crb + MIU_TEST_AGT_CTRL);
- writel(MIU_TA_CTL_START | MIU_TA_CTL_ENABLE,
- mem_crb + MIU_TEST_AGT_CTRL);
+ spin_lock(&adapter->ahw.mem_lock);
- for (j = 0; j < MAX_CTL_CHECK; j++) {
- temp = readl(mem_crb + MIU_TEST_AGT_CTRL);
- if ((temp & MIU_TA_CTL_BUSY) == 0)
- break;
- }
+ writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO));
+ writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI));
+ writel(TA_CTL_ENABLE, (mem_crb + TEST_AGT_CTRL));
+ writel((TA_CTL_START | TA_CTL_ENABLE), (mem_crb + TEST_AGT_CTRL));
- if (j >= MAX_CTL_CHECK) {
- if (printk_ratelimit())
- dev_err(&adapter->pdev->dev,
- "failed to read through agent\n");
+ for (j = 0; j < MAX_CTL_CHECK; j++) {
+ temp = readl(mem_crb + TEST_AGT_CTRL);
+ if ((temp & TA_CTL_BUSY) == 0)
break;
- }
-
- start = off0[i] >> 2;
- end = (off0[i] + sz[i] - 1) >> 2;
- for (k = start; k <= end; k++) {
- temp = readl(mem_crb + MIU_TEST_AGT_RDDATA(k));
- word[i] |= ((uint64_t)temp << (32 * k));
- }
}
- /*
- * netxen_nic_pci_change_crbwindow_128M(adapter, 1);
- * write_unlock_irqrestore(&adapter->adapter_lock, flags);
- */
-
- if (j >= MAX_CTL_CHECK)
- return -1;
-
- if (sz[0] == 8) {
- val = word[0];
+ if (j >= MAX_CTL_CHECK) {
+ if (printk_ratelimit())
+ dev_err(&adapter->pdev->dev,
+ "failed to read through agent\n");
+ ret = -EIO;
} else {
- val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) |
- ((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8));
- }
+ off8 = MIU_TEST_AGT_RDDATA_LO;
+ if ((stride == 16) && (off & 0xf))
+ off8 = MIU_TEST_AGT_RDDATA_UPPER_LO;
- switch (size) {
- case 1:
- *(uint8_t *)data = val;
- break;
- case 2:
- *(uint16_t *)data = val;
- break;
- case 4:
- *(uint32_t *)data = val;
- break;
- case 8:
- *(uint64_t *)data = val;
- break;
+ temp = readl(mem_crb + off8 + 4);
+ val = (u64)temp << 32;
+ val |= readl(mem_crb + off8);
+ *data = val;
+ ret = 0;
}
- return 0;
+
+ spin_unlock(&adapter->ahw.mem_lock);
+
+ return ret;
}
void
@@ -1901,22 +1778,16 @@ netxen_setup_hwops(struct netxen_adapter *adapter)
int netxen_nic_get_board_info(struct netxen_adapter *adapter)
{
- int offset, board_type, magic, header_version;
+ int offset, board_type, magic;
struct pci_dev *pdev = adapter->pdev;
offset = NX_FW_MAGIC_OFFSET;
if (netxen_rom_fast_read(adapter, offset, &magic))
return -EIO;
- offset = NX_HDR_VERSION_OFFSET;
- if (netxen_rom_fast_read(adapter, offset, &header_version))
- return -EIO;
-
- if (magic != NETXEN_BDINFO_MAGIC ||
- header_version != NETXEN_BDINFO_VERSION) {
- dev_err(&pdev->dev,
- "invalid board config, magic=%08x, version=%08x\n",
- magic, header_version);
+ if (magic != NETXEN_BDINFO_MAGIC) {
+ dev_err(&pdev->dev, "invalid board config, magic=%08x\n",
+ magic);
return -EIO;
}
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 91c2bc61c8eb..27d20cbae0aa 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -437,7 +437,7 @@ int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
#define NETXEN_BOARDNUM 0x400c
#define NETXEN_CHIPNUM 0x4010
-int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
+int netxen_pinit_from_rom(struct netxen_adapter *adapter)
{
int addr, val;
int i, n, init_delay = 0;
@@ -450,21 +450,6 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0xffffffff);
netxen_rom_unlock(adapter);
- if (verbose) {
- if (netxen_rom_fast_read(adapter, NETXEN_BOARDTYPE, &val) == 0)
- printk("P2 ROM board type: 0x%08x\n", val);
- else
- printk("Could not read board type\n");
- if (netxen_rom_fast_read(adapter, NETXEN_BOARDNUM, &val) == 0)
- printk("P2 ROM board num: 0x%08x\n", val);
- else
- printk("Could not read board number\n");
- if (netxen_rom_fast_read(adapter, NETXEN_CHIPNUM, &val) == 0)
- printk("P2 ROM chip num: 0x%08x\n", val);
- else
- printk("Could not read chip number\n");
- }
-
if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
if (netxen_rom_fast_read(adapter, 0, &n) != 0 ||
(n != 0xcafecafe) ||
@@ -486,11 +471,7 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
n &= ~0x80000000;
}
- if (n < 1024) {
- if (verbose)
- printk(KERN_DEBUG "%s: %d CRB init values found"
- " in ROM.\n", netxen_nic_driver_name, n);
- } else {
+ if (n >= 1024) {
printk(KERN_ERR "%s:n=0x%x Error! NetXen card flash not"
" initialized.\n", __func__, n);
return -EIO;
@@ -502,6 +483,7 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
netxen_nic_driver_name);
return -ENOMEM;
}
+
for (i = 0; i < n; i++) {
if (netxen_rom_fast_read(adapter, 8*i + 4*offset, &val) != 0 ||
netxen_rom_fast_read(adapter, 8*i + 4*offset + 4, &addr) != 0) {
@@ -512,11 +494,8 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
buf[i].addr = addr;
buf[i].data = val;
- if (verbose)
- printk(KERN_DEBUG "%s: PCI: 0x%08x == 0x%08x\n",
- netxen_nic_driver_name,
- (u32)netxen_decode_crb_addr(addr), val);
}
+
for (i = 0; i < n; i++) {
off = netxen_decode_crb_addr(buf[i].addr);
@@ -526,11 +505,17 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
continue;
}
off += NETXEN_PCI_CRBSPACE;
+
+ if (off & 1)
+ continue;
+
/* skipping cold reboot MAGIC */
if (off == NETXEN_CAM_RAM(0x1fc))
continue;
if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
+ if (off == (NETXEN_CRB_I2C0 + 0x1c))
+ continue;
/* do not reset PCI */
if (off == (ROMUSB_GLB + 0xbc))
continue;
@@ -542,7 +527,8 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
continue;
if (off == (ROMUSB_GLB + 0x1c)) /* MS clock */
continue;
- if (off == (NETXEN_CRB_PEG_NET_1 + 0x18))
+ if (off == (NETXEN_CRB_PEG_NET_1 + 0x18) &&
+ !NX_IS_REVISION_P3P(adapter->ahw.revision_id))
buf[i].data = 0x1020;
/* skip the function enable register */
if (off == NETXEN_PCIE_REG(PCIE_SETUP_FUNCTION))
@@ -553,12 +539,6 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
continue;
}
- if (off == NETXEN_ADDR_ERROR) {
- printk(KERN_ERR "%s: Err: Unknown addr: 0x%08x\n",
- netxen_nic_driver_name, buf[i].addr);
- continue;
- }
-
init_delay = 1;
/* After writing this register, HW needs time for CRB */
/* to quiet down (else crb_window returns 0xffffffff) */
@@ -702,7 +682,10 @@ netxen_load_firmware(struct netxen_adapter *adapter)
for (i = 0; i < size; i++) {
data = cpu_to_le64(ptr64[i]);
- adapter->pci_mem_write(adapter, flashaddr, &data, 8);
+ if (adapter->pci_mem_write(adapter,
+ flashaddr, data))
+ return -EIO;
+
flashaddr += 8;
}
@@ -716,7 +699,7 @@ netxen_load_firmware(struct netxen_adapter *adapter)
data = cpu_to_le64(ptr64[i]);
if (adapter->pci_mem_write(adapter,
- flashaddr, &data, 8))
+ flashaddr, data))
return -EIO;
flashaddr += 8;
@@ -730,17 +713,17 @@ netxen_load_firmware(struct netxen_adapter *adapter)
for (i = 0; i < size; i++) {
if (netxen_rom_fast_read(adapter,
- flashaddr, &lo) != 0)
+ flashaddr, (int *)&lo) != 0)
return -EIO;
if (netxen_rom_fast_read(adapter,
- flashaddr + 4, &hi) != 0)
+ flashaddr + 4, (int *)&hi) != 0)
return -EIO;
/* hi, lo are already in host endian byteorder */
data = (((u64)hi << 32) | lo);
if (adapter->pci_mem_write(adapter,
- flashaddr, &data, 8))
+ flashaddr, data))
return -EIO;
flashaddr += 8;
@@ -748,7 +731,10 @@ netxen_load_firmware(struct netxen_adapter *adapter)
}
msleep(1);
- if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+ if (NX_IS_REVISION_P3P(adapter->ahw.revision_id)) {
+ NXWR32(adapter, NETXEN_CRB_PEG_NET_0 + 0x18, 0x1020);
+ NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0x80001e);
+ } else if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0x80001d);
else {
NXWR32(adapter, NETXEN_ROMUSB_GLB_CHIP_CLK_CTRL, 0x3fff);
@@ -842,6 +828,12 @@ void netxen_request_firmware(struct netxen_adapter *adapter)
goto request_fw;
}
+ if (NX_IS_REVISION_P3P(adapter->ahw.revision_id)) {
+ /* No file firmware for the time being */
+ fw_type = NX_FLASH_ROMIMAGE;
+ goto done;
+ }
+
fw_type = netxen_p3_has_mn(adapter) ?
NX_P3_MN_ROMIMAGE : NX_P3_CT_ROMIMAGE;
@@ -1510,10 +1502,8 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid,
(rds_ring->num_desc - 1)));
netxen_set_msg_ctxid(msg, adapter->portnum);
netxen_set_msg_opcode(msg, NETXEN_RCV_PRODUCER(ringid));
- read_lock(&adapter->adapter_lock);
- writel(msg, DB_NORMALIZE(adapter,
- NETXEN_RCV_PRODUCER_OFFSET));
- read_unlock(&adapter->adapter_lock);
+ NXWRIO(adapter, DB_NORMALIZE(adapter,
+ NETXEN_RCV_PRODUCER_OFFSET), msg);
}
}
}
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 7fc15e9e8adb..c2bdfd3c7aad 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -52,6 +52,8 @@ static int use_msi = 1;
static int use_msi_x = 1;
+static unsigned long auto_fw_reset = AUTO_FW_RESET_ENABLED;
+
/* Local functions to NetXen NIC driver */
static int __devinit netxen_nic_probe(struct pci_dev *pdev,
const struct pci_device_id *ent);
@@ -73,6 +75,8 @@ static void netxen_nic_poll_controller(struct net_device *netdev);
static void netxen_create_sysfs_entries(struct netxen_adapter *adapter);
static void netxen_remove_sysfs_entries(struct netxen_adapter *adapter);
+static void netxen_create_diag_entries(struct netxen_adapter *adapter);
+static void netxen_remove_diag_entries(struct netxen_adapter *adapter);
static int nx_decr_dev_ref_cnt(struct netxen_adapter *adapter);
static int netxen_can_start_firmware(struct netxen_adapter *adapter);
@@ -607,14 +611,12 @@ netxen_setup_pci_map(struct netxen_adapter *adapter)
* Set the CRB window to invalid. If any register in window 0 is
* accessed it should set the window to 0 and then reset it to 1.
*/
- adapter->curr_window = 255;
- adapter->ahw.qdr_sn_window = -1;
- adapter->ahw.ddr_mn_window = -1;
+ adapter->ahw.crb_win = -1;
+ adapter->ahw.ocm_win = -1;
/* remap phys address */
mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
mem_len = pci_resource_len(pdev, 0);
- pci_len0 = 0;
/* 128 Meg of memory */
if (mem_len == NETXEN_PCI_128MB_SIZE) {
@@ -623,6 +625,7 @@ netxen_setup_pci_map(struct netxen_adapter *adapter)
SECOND_PAGE_GROUP_SIZE);
mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START,
THIRD_PAGE_GROUP_SIZE);
+ pci_len0 = FIRST_PAGE_GROUP_SIZE;
} else if (mem_len == NETXEN_PCI_32MB_SIZE) {
mem_ptr1 = ioremap(mem_base, SECOND_PAGE_GROUP_SIZE);
mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START -
@@ -635,19 +638,6 @@ netxen_setup_pci_map(struct netxen_adapter *adapter)
return -EIO;
}
pci_len0 = mem_len;
-
- adapter->ahw.ddr_mn_window = 0;
- adapter->ahw.qdr_sn_window = 0;
-
- adapter->ahw.mn_win_crb = NETXEN_PCI_CRBSPACE +
- 0x100000 + PCIX_MN_WINDOW + (pci_func * 0x20);
- adapter->ahw.ms_win_crb = NETXEN_PCI_CRBSPACE +
- 0x100000 + PCIX_SN_WINDOW;
- if (pci_func < 4)
- adapter->ahw.ms_win_crb += (pci_func * 0x20);
- else
- adapter->ahw.ms_win_crb +=
- 0xA0 + ((pci_func - 4) * 0x10);
} else {
return -EIO;
}
@@ -661,6 +651,15 @@ netxen_setup_pci_map(struct netxen_adapter *adapter)
adapter->ahw.pci_base1 = mem_ptr1;
adapter->ahw.pci_base2 = mem_ptr2;
+ if (NX_IS_REVISION_P3P(adapter->ahw.revision_id)) {
+ adapter->ahw.ocm_win_crb = netxen_get_ioaddr(adapter,
+ NETXEN_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(pci_func)));
+
+ } else if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
+ adapter->ahw.ocm_win_crb = netxen_get_ioaddr(adapter,
+ NETXEN_PCIX_PS_REG(PCIE_MN_WINDOW_REG(pci_func)));
+ }
+
if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
goto skip_doorbell;
@@ -817,7 +816,7 @@ netxen_start_firmware(struct netxen_adapter *adapter)
if (first_boot != 0x55555555) {
NXWR32(adapter, CRB_CMDPEG_STATE, 0);
- netxen_pinit_from_rom(adapter, 0);
+ netxen_pinit_from_rom(adapter);
msleep(1);
}
@@ -1250,7 +1249,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
revision_id = pdev->revision;
adapter->ahw.revision_id = revision_id;
- rwlock_init(&adapter->adapter_lock);
+ rwlock_init(&adapter->ahw.crb_lock);
+ spin_lock_init(&adapter->ahw.mem_lock);
+
spin_lock_init(&adapter->tx_clean_lock);
INIT_LIST_HEAD(&adapter->mac_list);
@@ -1315,6 +1316,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
break;
}
+ netxen_create_diag_entries(adapter);
+
return 0;
err_out_disable_msi:
@@ -1367,6 +1370,8 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
netxen_teardown_intr(adapter);
+ netxen_remove_diag_entries(adapter);
+
netxen_cleanup_pci_map(adapter);
netxen_release_firmware(adapter);
@@ -1447,7 +1452,8 @@ netxen_nic_resume(struct pci_dev *pdev)
if (err)
return err;
- adapter->curr_window = 255;
+ adapter->ahw.crb_win = -1;
+ adapter->ahw.ocm_win = -1;
err = netxen_start_firmware(adapter);
if (err) {
@@ -1919,12 +1925,13 @@ static void netxen_tx_timeout_task(struct work_struct *work)
request_reset:
adapter->need_fw_reset = 1;
+ clear_bit(__NX_RESETTING, &adapter->state);
}
struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev)
{
struct netxen_adapter *adapter = netdev_priv(netdev);
- struct net_device_stats *stats = &adapter->net_stats;
+ struct net_device_stats *stats = &netdev->stats;
memset(stats, 0, sizeof(*stats));
@@ -2260,7 +2267,8 @@ netxen_check_health(struct netxen_adapter *adapter)
dev_info(&netdev->dev, "firmware hang detected\n");
detach:
- if (!test_and_set_bit(__NX_RESETTING, &adapter->state))
+ if ((auto_fw_reset == AUTO_FW_RESET_ENABLED) &&
+ !test_and_set_bit(__NX_RESETTING, &adapter->state))
netxen_schedule_work(adapter, netxen_detach_work, 0);
return 1;
}
@@ -2338,6 +2346,195 @@ static struct device_attribute dev_attr_bridged_mode = {
.store = netxen_store_bridged_mode,
};
+static ssize_t
+netxen_store_diag_mode(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct netxen_adapter *adapter = dev_get_drvdata(dev);
+ unsigned long new;
+
+ if (strict_strtoul(buf, 2, &new))
+ return -EINVAL;
+
+ if (!!new != !!(adapter->flags & NETXEN_NIC_DIAG_ENABLED))
+ adapter->flags ^= NETXEN_NIC_DIAG_ENABLED;
+
+ return len;
+}
+
+static ssize_t
+netxen_show_diag_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct netxen_adapter *adapter = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n",
+ !!(adapter->flags & NETXEN_NIC_DIAG_ENABLED));
+}
+
+static struct device_attribute dev_attr_diag_mode = {
+ .attr = {.name = "diag_mode", .mode = (S_IRUGO | S_IWUSR)},
+ .show = netxen_show_diag_mode,
+ .store = netxen_store_diag_mode,
+};
+
+static int
+netxen_sysfs_validate_crb(struct netxen_adapter *adapter,
+ loff_t offset, size_t size)
+{
+ if (!(adapter->flags & NETXEN_NIC_DIAG_ENABLED))
+ return -EIO;
+
+ if ((size != 4) || (offset & 0x3))
+ return -EINVAL;
+
+ if (offset < NETXEN_PCI_CRBSPACE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static ssize_t
+netxen_sysfs_read_crb(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 netxen_adapter *adapter = dev_get_drvdata(dev);
+ u32 data;
+ int ret;
+
+ ret = netxen_sysfs_validate_crb(adapter, offset, size);
+ if (ret != 0)
+ return ret;
+
+ data = NXRD32(adapter, offset);
+ memcpy(buf, &data, size);
+ return size;
+}
+
+static ssize_t
+netxen_sysfs_write_crb(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 netxen_adapter *adapter = dev_get_drvdata(dev);
+ u32 data;
+ int ret;
+
+ ret = netxen_sysfs_validate_crb(adapter, offset, size);
+ if (ret != 0)
+ return ret;
+
+ memcpy(&data, buf, size);
+ NXWR32(adapter, offset, data);
+ return size;
+}
+
+static int
+netxen_sysfs_validate_mem(struct netxen_adapter *adapter,
+ loff_t offset, size_t size)
+{
+ if (!(adapter->flags & NETXEN_NIC_DIAG_ENABLED))
+ return -EIO;
+
+ if ((size != 8) || (offset & 0x7))
+ return -EIO;
+
+ return 0;
+}
+
+static ssize_t
+netxen_sysfs_read_mem(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 netxen_adapter *adapter = dev_get_drvdata(dev);
+ u64 data;
+ int ret;
+
+ ret = netxen_sysfs_validate_mem(adapter, offset, size);
+ if (ret != 0)
+ return ret;
+
+ if (adapter->pci_mem_read(adapter, offset, &data))
+ return -EIO;
+
+ memcpy(buf, &data, size);
+
+ return size;
+}
+
+ssize_t netxen_sysfs_write_mem(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 netxen_adapter *adapter = dev_get_drvdata(dev);
+ u64 data;
+ int ret;
+
+ ret = netxen_sysfs_validate_mem(adapter, offset, size);
+ if (ret != 0)
+ return ret;
+
+ memcpy(&data, buf, size);
+
+ if (adapter->pci_mem_write(adapter, offset, data))
+ return -EIO;
+
+ return size;
+}
+
+
+static struct bin_attribute bin_attr_crb = {
+ .attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = netxen_sysfs_read_crb,
+ .write = netxen_sysfs_write_crb,
+};
+
+static struct bin_attribute bin_attr_mem = {
+ .attr = {.name = "mem", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = netxen_sysfs_read_mem,
+ .write = netxen_sysfs_write_mem,
+};
+
+static ssize_t
+netxen_store_auto_fw_reset(struct module_attribute *mattr,
+ struct module *mod, const char *buf, size_t count)
+
+{
+ unsigned long new;
+
+ if (strict_strtoul(buf, 16, &new))
+ return -EINVAL;
+
+ if ((new == AUTO_FW_RESET_ENABLED) || (new == AUTO_FW_RESET_DISABLED)) {
+ auto_fw_reset = new;
+ return count;
+ }
+
+ return -EINVAL;
+}
+
+static ssize_t
+netxen_show_auto_fw_reset(struct module_attribute *mattr,
+ struct module *mod, char *buf)
+
+{
+ if (auto_fw_reset == AUTO_FW_RESET_ENABLED)
+ return sprintf(buf, "enabled\n");
+ else
+ return sprintf(buf, "disabled\n");
+}
+
+static struct module_attribute mod_attr_fw_reset = {
+ .attr = {.name = "auto_fw_reset", .mode = (S_IRUGO | S_IWUSR)},
+ .show = netxen_show_auto_fw_reset,
+ .store = netxen_store_auto_fw_reset,
+};
+
static void
netxen_create_sysfs_entries(struct netxen_adapter *adapter)
{
@@ -2363,6 +2560,33 @@ netxen_remove_sysfs_entries(struct netxen_adapter *adapter)
device_remove_file(dev, &dev_attr_bridged_mode);
}
+static void
+netxen_create_diag_entries(struct netxen_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct device *dev;
+
+ dev = &pdev->dev;
+ if (device_create_file(dev, &dev_attr_diag_mode))
+ dev_info(dev, "failed to create diag_mode sysfs entry\n");
+ if (device_create_bin_file(dev, &bin_attr_crb))
+ dev_info(dev, "failed to create crb sysfs entry\n");
+ if (device_create_bin_file(dev, &bin_attr_mem))
+ dev_info(dev, "failed to create mem sysfs entry\n");
+}
+
+
+static void
+netxen_remove_diag_entries(struct netxen_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct device *dev = &pdev->dev;
+
+ device_remove_file(dev, &dev_attr_diag_mode);
+ device_remove_bin_file(dev, &bin_attr_crb);
+ device_remove_bin_file(dev, &bin_attr_mem);
+}
+
#ifdef CONFIG_INET
#define is_netxen_netdev(dev) (dev->netdev_ops == &netxen_netdev_ops)
@@ -2515,6 +2739,8 @@ static struct pci_driver netxen_driver = {
static int __init netxen_init_module(void)
{
+ struct module *mod = THIS_MODULE;
+
printk(KERN_INFO "%s\n", netxen_nic_driver_string);
#ifdef CONFIG_INET
@@ -2522,6 +2748,10 @@ static int __init netxen_init_module(void)
register_inetaddr_notifier(&netxen_inetaddr_cb);
#endif
+ if (sysfs_create_file(&mod->mkobj.kobj, &mod_attr_fw_reset.attr))
+ printk(KERN_ERR "%s: Failed to create auto_fw_reset "
+ "sysfs entry.", netxen_nic_driver_name);
+
return pci_register_driver(&netxen_driver);
}
@@ -2529,6 +2759,10 @@ module_init(netxen_init_module);
static void __exit netxen_exit_module(void)
{
+ struct module *mod = THIS_MODULE;
+
+ sysfs_remove_file(&mod->mkobj.kobj, &mod_attr_fw_reset.attr);
+
pci_unregister_driver(&netxen_driver);
#ifdef CONFIG_INET
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index f9364d0678f2..5506f870037f 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -3545,7 +3545,7 @@ static int niu_process_rx_pkt(struct napi_struct *napi, struct niu *np,
rp->rcr_index = index;
skb_reserve(skb, NET_IP_ALIGN);
- __pskb_pull_tail(skb, min(len, NIU_RXPULL_MAX));
+ __pskb_pull_tail(skb, min(len, VLAN_ETH_HLEN));
rp->rx_packets++;
rp->rx_bytes += skb->len;
@@ -7855,10 +7855,13 @@ static void niu_get_strings(struct net_device *dev, u32 stringset, u8 *data)
}
}
-static int niu_get_stats_count(struct net_device *dev)
+static int niu_get_sset_count(struct net_device *dev, int stringset)
{
struct niu *np = netdev_priv(dev);
+ if (stringset != ETH_SS_STATS)
+ return -EINVAL;
+
return ((np->flags & NIU_FLAGS_XMAC ?
NUM_XMAC_STAT_KEYS :
NUM_BMAC_STAT_KEYS) +
@@ -7978,7 +7981,7 @@ static const struct ethtool_ops niu_ethtool_ops = {
.get_settings = niu_get_settings,
.set_settings = niu_set_settings,
.get_strings = niu_get_strings,
- .get_stats_count = niu_get_stats_count,
+ .get_sset_count = niu_get_sset_count,
.get_ethtool_stats = niu_get_ethtool_stats,
.phys_id = niu_phys_id,
.get_rxnfc = niu_get_nfc,
diff --git a/drivers/net/pasemi_mac_ethtool.c b/drivers/net/pasemi_mac_ethtool.c
index 28a86224879d..fefa79e34b95 100644
--- a/drivers/net/pasemi_mac_ethtool.c
+++ b/drivers/net/pasemi_mac_ethtool.c
@@ -77,6 +77,19 @@ pasemi_mac_ethtool_get_settings(struct net_device *netdev,
return phy_ethtool_gset(phydev, cmd);
}
+static int
+pasemi_mac_ethtool_set_settings(struct net_device *netdev,
+ struct ethtool_cmd *cmd)
+{
+ struct pasemi_mac *mac = netdev_priv(netdev);
+ struct phy_device *phydev = mac->phydev;
+
+ if (!phydev)
+ return -EOPNOTSUPP;
+
+ return phy_ethtool_sset(phydev, cmd);
+}
+
static void
pasemi_mac_ethtool_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *drvinfo)
@@ -150,6 +163,7 @@ 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,
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index b58965a2b3ae..6449290c62ff 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -344,13 +344,13 @@ static int tc574_config(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
struct el3_private *lp = netdev_priv(dev);
- tuple_t tuple;
- __le16 buf[32];
int last_fn, last_ret, i, j;
unsigned int ioaddr;
__be16 *phys_addr;
char *cardname;
__u32 config;
+ u8 *buf;
+ size_t len;
phys_addr = (__be16 *)dev->dev_addr;
@@ -378,16 +378,14 @@ static int tc574_config(struct pcmcia_device *link)
/* The 3c574 normally uses an EEPROM for configuration info, including
the hardware address. The future products may include a modem chip
and put the address in the CIS. */
- tuple.Attributes = 0;
- tuple.TupleData = (cisdata_t *)buf;
- tuple.TupleDataMax = 64;
- tuple.TupleOffset = 0;
- tuple.DesiredTuple = 0x88;
- if (pcmcia_get_first_tuple(link, &tuple) == 0) {
- pcmcia_get_tuple_data(link, &tuple);
+
+ len = pcmcia_get_tuple(link, 0x88, &buf);
+ if (buf && len >= 6) {
for (i = 0; i < 3; i++)
- phys_addr[i] = htons(le16_to_cpu(buf[i]));
+ phys_addr[i] = htons(le16_to_cpu(buf[i * 2]));
+ kfree(buf);
} else {
+ kfree(buf); /* 0 < len < 6 */
EL3WINDOW(0);
for (i = 0; i < 3; i++)
phys_addr[i] = htons(read_eeprom(ioaddr, i + 10));
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 569fb06793cf..fc6123ea6fa7 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -256,22 +256,16 @@ static int tc589_config(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
struct el3_private *lp = netdev_priv(dev);
- tuple_t tuple;
- __le16 buf[32];
__be16 *phys_addr;
int last_fn, last_ret, i, j, multi = 0, fifo;
unsigned int ioaddr;
char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+ u8 *buf;
+ size_t len;
DEBUG(0, "3c589_config(0x%p)\n", link);
phys_addr = (__be16 *)dev->dev_addr;
- tuple.Attributes = 0;
- tuple.TupleData = (cisdata_t *)buf;
- tuple.TupleDataMax = sizeof(buf);
- tuple.TupleOffset = 0;
- tuple.Attributes = TUPLE_RETURN_COMMON;
-
/* Is this a 3c562? */
if (link->manf_id != MANFID_3COM)
printk(KERN_INFO "3c589_cs: hmmm, is this really a "
@@ -301,12 +295,13 @@ static int tc589_config(struct pcmcia_device *link)
/* The 3c589 has an extra EEPROM for configuration info, including
the hardware address. The 3c562 puts the address in the CIS. */
- tuple.DesiredTuple = 0x88;
- if (pcmcia_get_first_tuple(link, &tuple) == 0) {
- pcmcia_get_tuple_data(link, &tuple);
- for (i = 0; i < 3; i++)
- phys_addr[i] = htons(le16_to_cpu(buf[i]));
+ len = pcmcia_get_tuple(link, 0x88, &buf);
+ if (buf && len >= 6) {
+ for (i = 0; i < 3; i++)
+ phys_addr[i] = htons(le16_to_cpu(buf[i*2]));
+ kfree(buf);
} else {
+ kfree(buf); /* 0 < len < 6 */
for (i = 0; i < 3; i++)
phys_addr[i] = htons(read_eeprom(ioaddr, i));
if (phys_addr[0] == htons(0x6060)) {
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 7e01fbdb87e0..58954a616ec0 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -341,33 +341,39 @@ static int ungermann_try_io_port(struct pcmcia_device *link)
return ret; /* RequestIO failed */
}
+static int fmvj18x_ioprobe(struct pcmcia_device *p_dev,
+ cistpl_cftable_entry_t *cfg,
+ cistpl_cftable_entry_t *dflt,
+ unsigned int vcc,
+ void *priv_data)
+{
+ return 0; /* strange, but that's what the code did already before... */
+}
+
static int fmvj18x_config(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
local_info_t *lp = netdev_priv(dev);
- tuple_t tuple;
- cisparse_t parse;
- u_short buf[32];
- int i, last_fn = 0, last_ret = 0, ret;
+ int i, last_fn = RequestIO, last_ret = 0, ret;
unsigned int ioaddr;
cardtype_t cardtype;
char *card_name = "unknown";
- u_char *node_id;
+ u8 *buf;
+ size_t len;
+ u_char buggybuf[32];
DEBUG(0, "fmvj18x_config(0x%p)\n", link);
- tuple.TupleData = (u_char *)buf;
- tuple.TupleDataMax = 64;
- tuple.TupleOffset = 0;
- tuple.DesiredTuple = CISTPL_FUNCE;
- tuple.TupleOffset = 0;
- if (pcmcia_get_first_tuple(link, &tuple) == 0) {
+ len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf);
+ if (buf)
+ kfree(buf);
+
+ if (len) {
/* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */
- tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
- CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
- CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
- CS_CHECK(ParseTuple, pcmcia_parse_tuple(&tuple, &parse));
- link->conf.ConfigIndex = parse.cftable_entry.index;
+ last_ret = pcmcia_loop_config(link, fmvj18x_ioprobe, NULL);
+ if (last_ret != 0)
+ goto cs_failed;
+
switch (link->manf_id) {
case MANFID_TDK:
cardtype = TDK;
@@ -474,21 +480,21 @@ static int fmvj18x_config(struct pcmcia_device *link)
case CONTEC:
case NEC:
case KME:
- tuple.DesiredTuple = CISTPL_FUNCE;
- tuple.TupleOffset = 0;
- CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
- tuple.TupleOffset = 0;
- CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
if (cardtype == MBH10304) {
- /* MBH10304's CIS_FUNCE is corrupted */
- node_id = &(tuple.TupleData[5]);
card_name = "FMV-J182";
- } else {
- while (tuple.TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID ) {
- CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
- CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+
+ len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf);
+ if (len < 11) {
+ kfree(buf);
+ goto failed;
}
- node_id = &(tuple.TupleData[2]);
+ /* Read MACID from CIS */
+ for (i = 5; i < 11; i++)
+ dev->dev_addr[i] = buf[i];
+ kfree(buf);
+ } else {
+ if (pcmcia_get_mac_from_cis(link, dev))
+ goto failed;
if( cardtype == TDK ) {
card_name = "TDK LAK-CD021";
} else if( cardtype == LA501 ) {
@@ -501,9 +507,6 @@ static int fmvj18x_config(struct pcmcia_device *link)
card_name = "C-NET(PC)C";
}
}
- /* Read MACID from CIS */
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = node_id[i];
break;
case UNGERMANN:
/* Read MACID from register */
@@ -513,12 +516,12 @@ static int fmvj18x_config(struct pcmcia_device *link)
break;
case XXX10304:
/* Read MACID from Buggy CIS */
- if (fmvj18x_get_hwinfo(link, tuple.TupleData) == -1) {
+ if (fmvj18x_get_hwinfo(link, buggybuf) == -1) {
printk(KERN_NOTICE "fmvj18x_cs: unable to read hardware net address.\n");
goto failed;
}
for (i = 0 ; i < 6; i++) {
- dev->dev_addr[i] = tuple.TupleData[i];
+ dev->dev_addr[i] = buggybuf[i];
}
card_name = "FMV-J182";
break;
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 5ed6339c52bc..4b96b356d979 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -661,8 +661,8 @@ static int nmclan_config(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
mace_private *lp = netdev_priv(dev);
- tuple_t tuple;
- u_char buf[64];
+ u8 *buf;
+ size_t len;
int i, last_ret, last_fn;
unsigned int ioaddr;
@@ -677,14 +677,13 @@ static int nmclan_config(struct pcmcia_device *link)
ioaddr = dev->base_addr;
/* Read the ethernet address from the CIS. */
- tuple.DesiredTuple = 0x80 /* CISTPL_CFTABLE_ENTRY_MISC */;
- tuple.TupleData = buf;
- tuple.TupleDataMax = 64;
- tuple.TupleOffset = 0;
- tuple.Attributes = 0;
- CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
- CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
- memcpy(dev->dev_addr, tuple.TupleData, ETHER_ADDR_LEN);
+ len = pcmcia_get_tuple(link, 0x80, &buf);
+ if (!buf || len < ETHER_ADDR_LEN) {
+ kfree(buf);
+ goto failed;
+ }
+ memcpy(dev->dev_addr, buf, ETHER_ADDR_LEN);
+ kfree(buf);
/* Verify configuration by reading the MACE ID. */
{
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 7bde2cd34c7e..df92bcde9bcf 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -126,12 +126,6 @@ struct smc_private {
int rx_ovrn;
};
-struct smc_cfg_mem {
- tuple_t tuple;
- cisparse_t parse;
- u_char buf[255];
-};
-
/* Special definitions for Megahertz multifunction cards */
#define MEGAHERTZ_ISR 0x0380
@@ -408,34 +402,7 @@ static int cvt_ascii_address(struct net_device *dev, char *s)
return 0;
}
-/*====================================================================*/
-
-static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple,
- cisparse_t *parse)
-{
- int i;
-
- i = pcmcia_get_first_tuple(handle, tuple);
- if (i != 0)
- return i;
- i = pcmcia_get_tuple_data(handle, tuple);
- if (i != 0)
- return i;
- return pcmcia_parse_tuple(tuple, parse);
-}
-
-static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple,
- cisparse_t *parse)
-{
- int i;
-
- if ((i = pcmcia_get_next_tuple(handle, tuple)) != 0 ||
- (i = pcmcia_get_tuple_data(handle, tuple)) != 0)
- return i;
- return pcmcia_parse_tuple(tuple, parse);
-}
-
-/*======================================================================
+/*====================================================================
Configuration stuff for Megahertz cards
@@ -490,15 +457,10 @@ static int mhz_mfc_config(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
struct smc_private *smc = netdev_priv(dev);
- struct smc_cfg_mem *cfg_mem;
win_req_t req;
memreq_t mem;
int i;
- cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
- if (!cfg_mem)
- return -ENOMEM;
-
link->conf.Attributes |= CONF_ENABLE_SPKR;
link->conf.Status = CCSR_AUDIO_ENA;
link->irq.Attributes =
@@ -510,7 +472,8 @@ static int mhz_mfc_config(struct pcmcia_device *link)
/* The Megahertz combo cards have modem-like CIS entries, so
we have to explicitly try a bunch of port combinations. */
if (pcmcia_loop_config(link, mhz_mfc_config_check, NULL))
- goto free_cfg_mem;
+ return -ENODEV;
+
dev->base_addr = link->io.BasePort1;
/* Allocate a memory window, for accessing the ISR */
@@ -519,7 +482,8 @@ static int mhz_mfc_config(struct pcmcia_device *link)
req.AccessSpeed = 0;
i = pcmcia_request_window(&link, &req, &link->win);
if (i != 0)
- goto free_cfg_mem;
+ return -ENODEV;
+
smc->base = ioremap(req.Base, req.Size);
mem.CardOffset = mem.Page = 0;
if (smc->manfid == MANFID_MOTOROLA)
@@ -531,70 +495,57 @@ static int mhz_mfc_config(struct pcmcia_device *link)
&& (smc->cardid == PRODID_MEGAHERTZ_EM3288))
mhz_3288_power(link);
-free_cfg_mem:
- kfree(cfg_mem);
- return -ENODEV;
+ return 0;
}
-static int mhz_setup(struct pcmcia_device *link)
+static int pcmcia_get_versmac(struct pcmcia_device *p_dev,
+ tuple_t *tuple,
+ void *priv)
{
- struct net_device *dev = link->priv;
- struct smc_cfg_mem *cfg_mem;
- tuple_t *tuple;
- cisparse_t *parse;
- u_char *buf, *station_addr;
- int rc;
+ struct net_device *dev = priv;
+ cisparse_t parse;
- cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
- if (!cfg_mem)
- return -1;
+ if (pcmcia_parse_tuple(tuple, &parse))
+ return -EINVAL;
+
+ if ((parse.version_1.ns > 3) &&
+ (cvt_ascii_address(dev,
+ (parse.version_1.str + parse.version_1.ofs[3]))))
+ return 0;
- tuple = &cfg_mem->tuple;
- parse = &cfg_mem->parse;
- buf = cfg_mem->buf;
+ return -EINVAL;
+};
- tuple->Attributes = tuple->TupleOffset = 0;
- tuple->TupleData = (cisdata_t *)buf;
- tuple->TupleDataMax = 255;
+static int mhz_setup(struct pcmcia_device *link)
+{
+ struct net_device *dev = link->priv;
+ size_t len;
+ u8 *buf;
+ int rc;
/* Read the station address from the CIS. It is stored as the last
(fourth) string in the Version 1 Version/ID tuple. */
- tuple->DesiredTuple = CISTPL_VERS_1;
- if (first_tuple(link, tuple, parse) != 0) {
- rc = -1;
- goto free_cfg_mem;
- }
+ if ((link->prod_id[3]) &&
+ (cvt_ascii_address(dev, link->prod_id[3]) == 0))
+ return 0;
+
+ /* Workarounds for broken cards start here. */
/* Ugh -- the EM1144 card has two VERS_1 tuples!?! */
- if (next_tuple(link, tuple, parse) != 0)
- first_tuple(link, tuple, parse);
- if (parse->version_1.ns > 3) {
- station_addr = parse->version_1.str + parse->version_1.ofs[3];
- if (cvt_ascii_address(dev, station_addr) == 0) {
- rc = 0;
- goto free_cfg_mem;
- }
- }
+ if (!pcmcia_loop_tuple(link, CISTPL_VERS_1, pcmcia_get_versmac, dev))
+ return 0;
/* Another possibility: for the EM3288, in a special tuple */
- tuple->DesiredTuple = 0x81;
- if (pcmcia_get_first_tuple(link, tuple) != 0) {
- rc = -1;
- goto free_cfg_mem;
- }
- if (pcmcia_get_tuple_data(link, tuple) != 0) {
- rc = -1;
- goto free_cfg_mem;
- }
- buf[12] = '\0';
- if (cvt_ascii_address(dev, buf) == 0) {
- rc = 0;
- goto free_cfg_mem;
- }
rc = -1;
-free_cfg_mem:
- kfree(cfg_mem);
- return rc;
-}
+ len = pcmcia_get_tuple(link, 0x81, &buf);
+ if (buf && len >= 13) {
+ buf[12] = '\0';
+ if (cvt_ascii_address(dev, buf))
+ rc = 0;
+ }
+ kfree(buf);
+
+ return rc;
+};
/*======================================================================
@@ -684,58 +635,21 @@ static int smc_config(struct pcmcia_device *link)
return i;
}
+
static int smc_setup(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
- struct smc_cfg_mem *cfg_mem;
- tuple_t *tuple;
- cisparse_t *parse;
- cistpl_lan_node_id_t *node_id;
- u_char *buf, *station_addr;
- int i, rc;
-
- cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
- if (!cfg_mem)
- return -ENOMEM;
-
- tuple = &cfg_mem->tuple;
- parse = &cfg_mem->parse;
- buf = cfg_mem->buf;
-
- tuple->Attributes = tuple->TupleOffset = 0;
- tuple->TupleData = (cisdata_t *)buf;
- tuple->TupleDataMax = 255;
/* Check for a LAN function extension tuple */
- tuple->DesiredTuple = CISTPL_FUNCE;
- i = first_tuple(link, tuple, parse);
- while (i == 0) {
- if (parse->funce.type == CISTPL_FUNCE_LAN_NODE_ID)
- break;
- i = next_tuple(link, tuple, parse);
- }
- if (i == 0) {
- node_id = (cistpl_lan_node_id_t *)parse->funce.data;
- if (node_id->nb == 6) {
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = node_id->id[i];
- rc = 0;
- goto free_cfg_mem;
- }
- }
+ if (!pcmcia_get_mac_from_cis(link, dev))
+ return 0;
+
/* Try the third string in the Version 1 Version/ID tuple. */
if (link->prod_id[2]) {
- station_addr = link->prod_id[2];
- if (cvt_ascii_address(dev, station_addr) == 0) {
- rc = 0;
- goto free_cfg_mem;
- }
+ if (cvt_ascii_address(dev, link->prod_id[2]) == 0)
+ return 0;
}
-
- rc = -1;
-free_cfg_mem:
- kfree(cfg_mem);
- return rc;
+ return -1;
}
/*====================================================================*/
@@ -794,41 +708,31 @@ static int osi_load_firmware(struct pcmcia_device *link)
return err;
}
-static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid)
+static int pcmcia_osi_mac(struct pcmcia_device *p_dev,
+ tuple_t *tuple,
+ void *priv)
{
- struct net_device *dev = link->priv;
- struct smc_cfg_mem *cfg_mem;
- tuple_t *tuple;
- u_char *buf;
- int i, rc;
+ struct net_device *dev = priv;
+ int i;
- cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
- if (!cfg_mem)
- return -1;
+ if (tuple->TupleDataLen < 8)
+ return -EINVAL;
+ if (tuple->TupleData[0] != 0x04)
+ return -EINVAL;
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = tuple->TupleData[i+2];
+ return 0;
+};
- tuple = &cfg_mem->tuple;
- buf = cfg_mem->buf;
- tuple->Attributes = TUPLE_RETURN_COMMON;
- tuple->TupleData = (cisdata_t *)buf;
- tuple->TupleDataMax = 255;
- tuple->TupleOffset = 0;
+static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid)
+{
+ struct net_device *dev = link->priv;
+ int rc;
/* Read the station address from tuple 0x90, subtuple 0x04 */
- tuple->DesiredTuple = 0x90;
- i = pcmcia_get_first_tuple(link, tuple);
- while (i == 0) {
- i = pcmcia_get_tuple_data(link, tuple);
- if ((i != 0) || (buf[0] == 0x04))
- break;
- i = pcmcia_get_next_tuple(link, tuple);
- }
- if (i != 0) {
- rc = -1;
- goto free_cfg_mem;
- }
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = buf[i+2];
+ if (pcmcia_loop_tuple(link, 0x90, pcmcia_osi_mac, dev))
+ return -1;
if (((manfid == MANFID_OSITECH) &&
(cardid == PRODID_OSITECH_SEVEN)) ||
@@ -836,7 +740,7 @@ static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid)
(cardid == PRODID_PSION_NET100))) {
rc = osi_load_firmware(link);
if (rc)
- goto free_cfg_mem;
+ return rc;
} else if (manfid == MANFID_OSITECH) {
/* Make sure both functions are powered up */
set_bits(0x300, link->io.BasePort1 + OSITECH_AUI_PWR);
@@ -846,10 +750,7 @@ static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid)
inw(link->io.BasePort1 + OSITECH_AUI_PWR),
inw(link->io.BasePort1 + OSITECH_RESET_ISR));
}
- rc = 0;
-free_cfg_mem:
- kfree(cfg_mem);
- return rc;
+ return 0;
}
static int smc91c92_suspend(struct pcmcia_device *link)
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index cf8423102538..197108b45d78 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -359,7 +359,7 @@ static void xirc_tx_timeout(struct net_device *dev);
static void xirc2ps_tx_timeout_task(struct work_struct *work);
static void set_addresses(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
-static int set_card_type(struct pcmcia_device *link, const void *s);
+static int set_card_type(struct pcmcia_device *link);
static int do_config(struct net_device *dev, struct ifmap *map);
static int do_open(struct net_device *dev);
static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -371,28 +371,6 @@ static void do_powerdown(struct net_device *dev);
static int do_stop(struct net_device *dev);
/*=============== Helper functions =========================*/
-static int
-first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
-{
- int err;
-
- if ((err = pcmcia_get_first_tuple(handle, tuple)) == 0 &&
- (err = pcmcia_get_tuple_data(handle, tuple)) == 0)
- err = pcmcia_parse_tuple(tuple, parse);
- return err;
-}
-
-static int
-next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
-{
- int err;
-
- if ((err = pcmcia_get_next_tuple(handle, tuple)) == 0 &&
- (err = pcmcia_get_tuple_data(handle, tuple)) == 0)
- err = pcmcia_parse_tuple(tuple, parse);
- return err;
-}
-
#define SelectPage(pgnr) outb((pgnr), ioaddr + XIRCREG_PR)
#define GetByte(reg) ((unsigned)inb(ioaddr + (reg)))
#define GetWord(reg) ((unsigned)inw(ioaddr + (reg)))
@@ -644,15 +622,23 @@ xirc2ps_detach(struct pcmcia_device *link)
*
*/
static int
-set_card_type(struct pcmcia_device *link, const void *s)
+set_card_type(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
local_info_t *local = netdev_priv(dev);
- #ifdef PCMCIA_DEBUG
- unsigned cisrev = ((const unsigned char *)s)[2];
- #endif
- unsigned mediaid= ((const unsigned char *)s)[3];
- unsigned prodid = ((const unsigned char *)s)[4];
+ u8 *buf;
+ unsigned int cisrev, mediaid, prodid;
+ size_t len;
+
+ len = pcmcia_get_tuple(link, CISTPL_MANFID, &buf);
+ if (len < 5) {
+ dev_err(&link->dev, "invalid CIS -- sorry\n");
+ return 0;
+ }
+
+ cisrev = buf[2];
+ mediaid= buf[3];
+ prodid = buf[4];
DEBUG(0, "cisrev=%02x mediaid=%02x prodid=%02x\n",
cisrev, mediaid, prodid);
@@ -761,6 +747,26 @@ xirc2ps_config_check(struct pcmcia_device *p_dev,
}
+
+static int pcmcia_get_mac_ce(struct pcmcia_device *p_dev,
+ tuple_t *tuple,
+ void *priv)
+{
+ struct net_device *dev = priv;
+ int i;
+
+ if (tuple->TupleDataLen != 13)
+ return -EINVAL;
+ if ((tuple->TupleData[0] != 2) || (tuple->TupleData[1] != 1) ||
+ (tuple->TupleData[2] != 6))
+ return -EINVAL;
+ /* another try (James Lehmer's CE2 version 4.1)*/
+ for (i = 2; i < 6; i++)
+ dev->dev_addr[i] = tuple->TupleData[i+2];
+ return 0;
+};
+
+
/****************
* xirc2ps_config() is scheduled to run after a CARD_INSERTION event
* is received, to configure the PCMCIA socket, and to make the
@@ -774,9 +780,9 @@ xirc2ps_config(struct pcmcia_device * link)
unsigned int ioaddr;
tuple_t tuple;
cisparse_t parse;
- int err, i;
- u_char buf[64];
- cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data;
+ int err;
+ u8 *buf;
+ size_t len;
local->dingo_ccr = NULL;
@@ -792,13 +798,12 @@ xirc2ps_config(struct pcmcia_device * link)
tuple.TupleOffset = 0;
/* Is this a valid card */
- tuple.DesiredTuple = CISTPL_MANFID;
- if ((err=first_tuple(link, &tuple, &parse))) {
+ if (link->has_manf_id == 0) {
printk(KNOT_XIRC "manfid not found in CIS\n");
goto failure;
}
- switch(parse.manfid.manf) {
+ switch (link->manf_id) {
case MANFID_XIRCOM:
local->manf_str = "Xircom";
break;
@@ -822,55 +827,34 @@ xirc2ps_config(struct pcmcia_device * link)
}
DEBUG(0, "found %s card\n", local->manf_str);
- if (!set_card_type(link, buf)) {
+ if (!set_card_type(link)) {
printk(KNOT_XIRC "this card is not supported\n");
goto failure;
}
/* get the ethernet address from the CIS */
- tuple.DesiredTuple = CISTPL_FUNCE;
- for (err = first_tuple(link, &tuple, &parse); !err;
- err = next_tuple(link, &tuple, &parse)) {
- /* Once I saw two CISTPL_FUNCE_LAN_NODE_ID entries:
- * the first one with a length of zero the second correct -
- * so I skip all entries with length 0 */
- if (parse.funce.type == CISTPL_FUNCE_LAN_NODE_ID
- && ((cistpl_lan_node_id_t *)parse.funce.data)->nb)
- break;
- }
- if (err) { /* not found: try to get the node-id from tuple 0x89 */
- tuple.DesiredTuple = 0x89; /* data layout looks like tuple 0x22 */
- if ((err = pcmcia_get_first_tuple(link, &tuple)) == 0 &&
- (err = pcmcia_get_tuple_data(link, &tuple)) == 0) {
- if (tuple.TupleDataLen == 8 && *buf == CISTPL_FUNCE_LAN_NODE_ID)
- memcpy(&parse, buf, 8);
- else
- err = -1;
- }
- }
- if (err) { /* another try (James Lehmer's CE2 version 4.1)*/
- tuple.DesiredTuple = CISTPL_FUNCE;
- for (err = first_tuple(link, &tuple, &parse); !err;
- err = next_tuple(link, &tuple, &parse)) {
- if (parse.funce.type == 0x02 && parse.funce.data[0] == 1
- && parse.funce.data[1] == 6 && tuple.TupleDataLen == 13) {
- buf[1] = 4;
- memcpy(&parse, buf+1, 8);
- break;
+ err = pcmcia_get_mac_from_cis(link, dev);
+
+ /* not found: try to get the node-id from tuple 0x89 */
+ if (err) {
+ len = pcmcia_get_tuple(link, 0x89, &buf);
+ /* data layout looks like tuple 0x22 */
+ if (buf && len == 8) {
+ if (*buf == CISTPL_FUNCE_LAN_NODE_ID)
+ memcpy(&parse, buf, 8);
+ else
+ err = -1;
}
- }
+ kfree(buf);
}
+
+ if (err)
+ err = pcmcia_loop_tuple(link, CISTPL_FUNCE, pcmcia_get_mac_ce, dev);
+
if (err) {
printk(KNOT_XIRC "node-id not found in CIS\n");
goto failure;
}
- node_id = (cistpl_lan_node_id_t *)parse.funce.data;
- if (node_id->nb != 6) {
- printk(KNOT_XIRC "malformed node-id in CIS\n");
- goto failure;
- }
- for (i=0; i < 6; i++)
- dev->dev_addr[i] = node_id->id[i];
link->io.IOAddrLines =10;
link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index 6de8399d6dd9..30b1b3326765 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -337,10 +337,7 @@ ppp_asynctty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
return 0;
}
-/*
- * This can now be called from hard interrupt level as well
- * as soft interrupt level or mainline.
- */
+/* May sleep, don't call from interrupt level or with interrupts disabled */
static void
ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
char *cflags, int count)
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index d2fa2db13586..c908b08dc981 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -378,10 +378,7 @@ ppp_sync_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
return 0;
}
-/*
- * This can now be called from hard interrupt level as well
- * as soft interrupt level or mainline.
- */
+/* May sleep, don't call from interrupt level or with interrupts disabled */
static void
ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
char *cflags, int count)
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 7cbf6f9b51de..2559991eea6a 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -111,9 +111,6 @@ struct pppoe_net {
rwlock_t hash_lock;
};
-/* to eliminate a race btw pppoe_flush_dev and pppoe_release */
-static DEFINE_SPINLOCK(flush_lock);
-
/*
* PPPoE could be in the following stages:
* 1) Discovery stage (to obtain remote MAC and Session ID)
@@ -303,45 +300,48 @@ static void pppoe_flush_dev(struct net_device *dev)
write_lock_bh(&pn->hash_lock);
for (i = 0; i < PPPOE_HASH_SIZE; i++) {
struct pppox_sock *po = pn->hash_table[i];
+ struct sock *sk;
- while (po != NULL) {
- struct sock *sk;
- if (po->pppoe_dev != dev) {
+ while (po) {
+ while (po && po->pppoe_dev != dev) {
po = po->next;
- continue;
}
+
+ if (!po)
+ break;
+
sk = sk_pppox(po);
- spin_lock(&flush_lock);
- po->pppoe_dev = NULL;
- spin_unlock(&flush_lock);
- dev_put(dev);
/* We always grab the socket lock, followed by the
- * hash_lock, in that order. Since we should
- * hold the sock lock while doing any unbinding,
- * we need to release the lock we're holding.
- * Hold a reference to the sock so it doesn't disappear
- * as we're jumping between locks.
+ * hash_lock, in that order. Since we should hold the
+ * sock lock while doing any unbinding, we need to
+ * release the lock we're holding. Hold a reference to
+ * the sock so it doesn't disappear as we're jumping
+ * between locks.
*/
sock_hold(sk);
-
write_unlock_bh(&pn->hash_lock);
lock_sock(sk);
- if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) {
+ if (po->pppoe_dev == dev
+ && sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) {
pppox_unbind_sock(sk);
sk->sk_state = PPPOX_ZOMBIE;
sk->sk_state_change(sk);
+ po->pppoe_dev = NULL;
+ dev_put(dev);
}
release_sock(sk);
sock_put(sk);
- /* Restart scan at the beginning of this hash chain.
- * While the lock was dropped the chain contents may
- * have changed.
+ /* Restart the process from the start of the current
+ * hash chain. We dropped locks so the world may have
+ * change from underneath us.
*/
+
+ BUG_ON(pppoe_pernet(dev_net(dev)) == NULL);
write_lock_bh(&pn->hash_lock);
po = pn->hash_table[i];
}
@@ -388,11 +388,16 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)
struct pppox_sock *po = pppox_sk(sk);
struct pppox_sock *relay_po;
+ /* Backlog receive. Semantics of backlog rcv preclude any code from
+ * executing in lock_sock()/release_sock() bounds; meaning sk->sk_state
+ * can't change.
+ */
+
if (sk->sk_state & PPPOX_BOUND) {
ppp_input(&po->chan, skb);
} else if (sk->sk_state & PPPOX_RELAY) {
- relay_po = get_item_by_addr(dev_net(po->pppoe_dev),
- &po->pppoe_relay);
+ relay_po = get_item_by_addr(sock_net(sk),
+ &po->pppoe_relay);
if (relay_po == NULL)
goto abort_kfree;
@@ -447,6 +452,10 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev,
goto drop;
pn = pppoe_pernet(dev_net(dev));
+
+ /* Note that get_item does a sock_hold(), so sk_pppox(po)
+ * is known to be safe.
+ */
po = get_item(pn, ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
if (!po)
goto drop;
@@ -561,6 +570,7 @@ static int pppoe_release(struct socket *sock)
struct sock *sk = sock->sk;
struct pppox_sock *po;
struct pppoe_net *pn;
+ struct net *net = NULL;
if (!sk)
return 0;
@@ -571,44 +581,28 @@ static int pppoe_release(struct socket *sock)
return -EBADF;
}
+ po = pppox_sk(sk);
+
+ if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) {
+ dev_put(po->pppoe_dev);
+ po->pppoe_dev = NULL;
+ }
+
pppox_unbind_sock(sk);
/* Signal the death of the socket. */
sk->sk_state = PPPOX_DEAD;
- /*
- * pppoe_flush_dev could lead to a race with
- * this routine so we use flush_lock to eliminate
- * such a case (we only need per-net specific data)
- */
- spin_lock(&flush_lock);
- po = pppox_sk(sk);
- if (!po->pppoe_dev) {
- spin_unlock(&flush_lock);
- goto out;
- }
- pn = pppoe_pernet(dev_net(po->pppoe_dev));
- spin_unlock(&flush_lock);
+ net = sock_net(sk);
+ pn = pppoe_pernet(net);
/*
* protect "po" from concurrent updates
* on pppoe_flush_dev
*/
- write_lock_bh(&pn->hash_lock);
+ delete_item(pn, po->pppoe_pa.sid, po->pppoe_pa.remote,
+ po->pppoe_ifindex);
- po = pppox_sk(sk);
- if (stage_session(po->pppoe_pa.sid))
- __delete_item(pn, po->pppoe_pa.sid, po->pppoe_pa.remote,
- po->pppoe_ifindex);
-
- if (po->pppoe_dev) {
- dev_put(po->pppoe_dev);
- po->pppoe_dev = NULL;
- }
-
- write_unlock_bh(&pn->hash_lock);
-
-out:
sock_orphan(sk);
sock->sk = NULL;
@@ -625,8 +619,9 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
struct sock *sk = sock->sk;
struct sockaddr_pppox *sp = (struct sockaddr_pppox *)uservaddr;
struct pppox_sock *po = pppox_sk(sk);
- struct net_device *dev;
+ struct net_device *dev = NULL;
struct pppoe_net *pn;
+ struct net *net = NULL;
int error;
lock_sock(sk);
@@ -652,12 +647,14 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
/* Delete the old binding */
if (stage_session(po->pppoe_pa.sid)) {
pppox_unbind_sock(sk);
+ pn = pppoe_pernet(sock_net(sk));
+ delete_item(pn, po->pppoe_pa.sid,
+ po->pppoe_pa.remote, po->pppoe_ifindex);
if (po->pppoe_dev) {
- pn = pppoe_pernet(dev_net(po->pppoe_dev));
- delete_item(pn, po->pppoe_pa.sid,
- po->pppoe_pa.remote, po->pppoe_ifindex);
dev_put(po->pppoe_dev);
+ po->pppoe_dev = NULL;
}
+
memset(sk_pppox(po) + 1, 0,
sizeof(struct pppox_sock) - sizeof(struct sock));
sk->sk_state = PPPOX_NONE;
@@ -666,16 +663,15 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
/* Re-bind in session stage only */
if (stage_session(sp->sa_addr.pppoe.sid)) {
error = -ENODEV;
- dev = dev_get_by_name(sock_net(sk), sp->sa_addr.pppoe.dev);
+ net = sock_net(sk);
+ dev = dev_get_by_name(net, sp->sa_addr.pppoe.dev);
if (!dev)
- goto end;
+ goto err_put;
po->pppoe_dev = dev;
po->pppoe_ifindex = dev->ifindex;
- pn = pppoe_pernet(dev_net(dev));
- write_lock_bh(&pn->hash_lock);
+ pn = pppoe_pernet(net);
if (!(dev->flags & IFF_UP)) {
- write_unlock_bh(&pn->hash_lock);
goto err_put;
}
@@ -683,6 +679,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
&sp->sa_addr.pppoe,
sizeof(struct pppoe_addr));
+ write_lock_bh(&pn->hash_lock);
error = __set_item(pn, po);
write_unlock_bh(&pn->hash_lock);
if (error < 0)
@@ -696,8 +693,11 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
po->chan.ops = &pppoe_chan_ops;
error = ppp_register_net_channel(dev_net(dev), &po->chan);
- if (error)
+ if (error) {
+ delete_item(pn, po->pppoe_pa.sid,
+ po->pppoe_pa.remote, po->pppoe_ifindex);
goto err_put;
+ }
sk->sk_state = PPPOX_CONNECTED;
}
@@ -915,6 +915,14 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
struct pppoe_hdr *ph;
int data_len = skb->len;
+ /* The higher-level PPP code (ppp_unregister_channel()) ensures the PPP
+ * xmit operations conclude prior to an unregistration call. Thus
+ * sk->sk_state cannot change, so we don't need to do lock_sock().
+ * But, we also can't do a lock_sock since that introduces a potential
+ * deadlock as we'd reverse the lock ordering used when calling
+ * ppp_unregister_channel().
+ */
+
if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
goto abort;
@@ -944,7 +952,6 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
po->pppoe_pa.remote, NULL, data_len);
dev_queue_xmit(skb);
-
return 1;
abort:
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
index 5910df60c93e..849cc9c62c2a 100644
--- a/drivers/net/pppol2tp.c
+++ b/drivers/net/pppol2tp.c
@@ -516,7 +516,7 @@ static inline int pppol2tp_verify_udp_checksum(struct sock *sk,
return 0;
inet = inet_sk(sk);
- psum = csum_tcpudp_nofold(inet->saddr, inet->daddr, ulen,
+ psum = csum_tcpudp_nofold(inet->inet_saddr, inet->inet_daddr, ulen,
IPPROTO_UDP, 0);
if ((skb->ip_summed == CHECKSUM_COMPLETE) &&
@@ -949,8 +949,8 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
inet = inet_sk(sk_tun);
udp_len = hdr_len + sizeof(ppph) + total_len;
uh = (struct udphdr *) skb->data;
- uh->source = inet->sport;
- uh->dest = inet->dport;
+ uh->source = inet->inet_sport;
+ uh->dest = inet->inet_dport;
uh->len = htons(udp_len);
uh->check = 0;
skb_put(skb, sizeof(struct udphdr));
@@ -978,7 +978,8 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
else if (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) {
skb->ip_summed = CHECKSUM_COMPLETE;
csum = skb_checksum(skb, 0, udp_len, 0);
- uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr,
+ uh->check = csum_tcpudp_magic(inet->inet_saddr,
+ inet->inet_daddr,
udp_len, IPPROTO_UDP, csum);
if (uh->check == 0)
uh->check = CSUM_MANGLED_0;
@@ -986,7 +987,8 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
skb->ip_summed = CHECKSUM_PARTIAL;
skb->csum_start = skb_transport_header(skb) - skb->head;
skb->csum_offset = offsetof(struct udphdr, check);
- uh->check = ~csum_tcpudp_magic(inet->saddr, inet->daddr,
+ uh->check = ~csum_tcpudp_magic(inet->inet_saddr,
+ inet->inet_daddr,
udp_len, IPPROTO_UDP, 0);
}
@@ -1136,8 +1138,8 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
__skb_push(skb, sizeof(*uh));
skb_reset_transport_header(skb);
uh = udp_hdr(skb);
- uh->source = inet->sport;
- uh->dest = inet->dport;
+ uh->source = inet->inet_sport;
+ uh->dest = inet->inet_dport;
uh->len = htons(udp_len);
uh->check = 0;
@@ -1181,7 +1183,8 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
else if (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) {
skb->ip_summed = CHECKSUM_COMPLETE;
csum = skb_checksum(skb, 0, udp_len, 0);
- uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr,
+ uh->check = csum_tcpudp_magic(inet->inet_saddr,
+ inet->inet_daddr,
udp_len, IPPROTO_UDP, csum);
if (uh->check == 0)
uh->check = CSUM_MANGLED_0;
@@ -1189,7 +1192,8 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
skb->ip_summed = CHECKSUM_PARTIAL;
skb->csum_start = skb_transport_header(skb) - skb->head;
skb->csum_offset = offsetof(struct udphdr, check);
- uh->check = ~csum_tcpudp_magic(inet->saddr, inet->daddr,
+ uh->check = ~csum_tcpudp_magic(inet->inet_saddr,
+ inet->inet_daddr,
udp_len, IPPROTO_UDP, 0);
}
diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c
index 4f6d33fbc673..c14ee24c05a8 100644
--- a/drivers/net/pppox.c
+++ b/drivers/net/pppox.c
@@ -125,7 +125,7 @@ out:
return rc;
}
-static struct net_proto_family pppox_proto_family = {
+static const struct net_proto_family pppox_proto_family = {
.family = PF_PPPOX,
.create = pppox_create,
.owner = THIS_MODULE,
diff --git a/drivers/net/ps3_gelic_wireless.h b/drivers/net/ps3_gelic_wireless.h
index 5b631c6c9775..0a88b535197a 100644
--- a/drivers/net/ps3_gelic_wireless.h
+++ b/drivers/net/ps3_gelic_wireless.h
@@ -199,7 +199,7 @@ struct gelic_eurus_rssi_info {
/* for 'stat' member of gelic_wl_info */
enum gelic_wl_info_status_bit {
GELIC_WL_STAT_CONFIGURED,
- GELIC_WL_STAT_CH_INFO, /* ch info aquired */
+ GELIC_WL_STAT_CH_INFO, /* ch info acquired */
GELIC_WL_STAT_ESSID_SET, /* ESSID specified by userspace */
GELIC_WL_STAT_BSSID_SET, /* BSSID specified by userspace */
GELIC_WL_STAT_WPA_PSK_SET, /* PMK specified by userspace */
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index 4c610511eb40..f72643313bab 100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -3651,7 +3651,7 @@ static int ql_adapter_up(struct ql3_adapter *qdev)
ql_sem_unlock(qdev, QL_DRVR_SEM_MASK);
} else {
printk(KERN_ERR PFX
- "%s: Could not aquire driver lock.\n",
+ "%s: Could not acquire driver lock.\n",
ndev->name);
goto err_lock;
}
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index e7285f01bd04..4b954e13c007 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -54,8 +54,10 @@
#define RX_RING_SHADOW_SPACE (sizeof(u64) + \
MAX_DB_PAGES_PER_BQ(NUM_SMALL_BUFFERS) * sizeof(u64) + \
MAX_DB_PAGES_PER_BQ(NUM_LARGE_BUFFERS) * sizeof(u64))
-#define SMALL_BUFFER_SIZE 256
-#define LARGE_BUFFER_SIZE PAGE_SIZE
+#define SMALL_BUFFER_SIZE 512
+#define SMALL_BUF_MAP_SIZE (SMALL_BUFFER_SIZE / 2)
+#define LARGE_BUFFER_MAX_SIZE 8192
+#define LARGE_BUFFER_MIN_SIZE 2048
#define MAX_SPLIT_SIZE 1023
#define QLGE_SB_PAD 32
@@ -794,6 +796,7 @@ enum {
MB_WOL_BCAST = (1 << 5),
MB_WOL_LINK_UP = (1 << 6),
MB_WOL_LINK_DOWN = (1 << 7),
+ MB_WOL_MODE_ON = (1 << 16), /* Wake on Lan Mode on */
MB_CMD_SET_WOL_FLTR = 0x00000111, /* Wake On Lan Filter */
MB_CMD_CLEAR_WOL_FLTR = 0x00000112, /* Wake On Lan Filter */
MB_CMD_SET_WOL_MAGIC = 0x00000113, /* Wake On Lan Magic Packet */
@@ -803,6 +806,9 @@ enum {
MB_CMD_SET_PORT_CFG = 0x00000122,
MB_CMD_GET_PORT_CFG = 0x00000123,
MB_CMD_GET_LINK_STS = 0x00000124,
+ MB_CMD_SET_LED_CFG = 0x00000125, /* Set LED Configuration Register */
+ QL_LED_BLINK = 0x03e803e8,
+ MB_CMD_GET_LED_CFG = 0x00000126, /* Get LED Configuration Register */
MB_CMD_SET_MGMNT_TFK_CTL = 0x00000160, /* Set Mgmnt Traffic Control */
MB_SET_MPI_TFK_STOP = (1 << 0),
MB_SET_MPI_TFK_RESUME = (1 << 1),
@@ -1200,9 +1206,17 @@ struct tx_ring_desc {
struct tx_ring_desc *next;
};
+struct page_chunk {
+ struct page *page; /* master page */
+ char *va; /* virt addr for this chunk */
+ u64 map; /* mapping for master */
+ unsigned int offset; /* offset for this chunk */
+ unsigned int last_flag; /* flag set for last chunk in page */
+};
+
struct bq_desc {
union {
- struct page *lbq_page;
+ struct page_chunk pg_chunk;
struct sk_buff *skb;
} p;
__le64 *addr;
@@ -1271,6 +1285,7 @@ struct rx_ring {
dma_addr_t lbq_base_dma;
void *lbq_base_indirect;
dma_addr_t lbq_base_indirect_dma;
+ struct page_chunk pg_chunk; /* current page for chunks */
struct bq_desc *lbq; /* array of control blocks */
void __iomem *lbq_prod_idx_db_reg; /* PCI doorbell mem area + 0x18 */
u32 lbq_prod_idx; /* current sw prod idx */
@@ -1362,6 +1377,174 @@ struct nic_stats {
u64 rx_1024_to_1518_pkts;
u64 rx_1519_to_max_pkts;
u64 rx_len_err_pkts;
+ /*
+ * These stats come from offset 500h to 5C8h
+ * in the XGMAC register.
+ */
+ u64 tx_cbfc_pause_frames0;
+ u64 tx_cbfc_pause_frames1;
+ u64 tx_cbfc_pause_frames2;
+ u64 tx_cbfc_pause_frames3;
+ u64 tx_cbfc_pause_frames4;
+ u64 tx_cbfc_pause_frames5;
+ u64 tx_cbfc_pause_frames6;
+ u64 tx_cbfc_pause_frames7;
+ u64 rx_cbfc_pause_frames0;
+ u64 rx_cbfc_pause_frames1;
+ u64 rx_cbfc_pause_frames2;
+ u64 rx_cbfc_pause_frames3;
+ u64 rx_cbfc_pause_frames4;
+ u64 rx_cbfc_pause_frames5;
+ u64 rx_cbfc_pause_frames6;
+ u64 rx_cbfc_pause_frames7;
+ u64 rx_nic_fifo_drop;
+};
+
+/* Address/Length pairs for the coredump. */
+enum {
+ MPI_CORE_REGS_ADDR = 0x00030000,
+ MPI_CORE_REGS_CNT = 127,
+ MPI_CORE_SH_REGS_CNT = 16,
+ TEST_REGS_ADDR = 0x00001000,
+ TEST_REGS_CNT = 23,
+ RMII_REGS_ADDR = 0x00001040,
+ RMII_REGS_CNT = 64,
+ FCMAC1_REGS_ADDR = 0x00001080,
+ FCMAC2_REGS_ADDR = 0x000010c0,
+ FCMAC_REGS_CNT = 64,
+ FC1_MBX_REGS_ADDR = 0x00001100,
+ FC2_MBX_REGS_ADDR = 0x00001240,
+ FC_MBX_REGS_CNT = 64,
+ IDE_REGS_ADDR = 0x00001140,
+ IDE_REGS_CNT = 64,
+ NIC1_MBX_REGS_ADDR = 0x00001180,
+ NIC2_MBX_REGS_ADDR = 0x00001280,
+ NIC_MBX_REGS_CNT = 64,
+ SMBUS_REGS_ADDR = 0x00001200,
+ SMBUS_REGS_CNT = 64,
+ I2C_REGS_ADDR = 0x00001fc0,
+ I2C_REGS_CNT = 64,
+ MEMC_REGS_ADDR = 0x00003000,
+ MEMC_REGS_CNT = 256,
+ PBUS_REGS_ADDR = 0x00007c00,
+ PBUS_REGS_CNT = 256,
+ MDE_REGS_ADDR = 0x00010000,
+ MDE_REGS_CNT = 6,
+ CODE_RAM_ADDR = 0x00020000,
+ CODE_RAM_CNT = 0x2000,
+ MEMC_RAM_ADDR = 0x00100000,
+ MEMC_RAM_CNT = 0x2000,
+};
+
+#define MPI_COREDUMP_COOKIE 0x5555aaaa
+struct mpi_coredump_global_header {
+ u32 cookie;
+ u8 idString[16];
+ u32 timeLo;
+ u32 timeHi;
+ u32 imageSize;
+ u32 headerSize;
+ u8 info[220];
+};
+
+struct mpi_coredump_segment_header {
+ u32 cookie;
+ u32 segNum;
+ u32 segSize;
+ u32 extra;
+ u8 description[16];
+};
+
+/* Reg dump segment numbers. */
+enum {
+ CORE_SEG_NUM = 1,
+ TEST_LOGIC_SEG_NUM = 2,
+ RMII_SEG_NUM = 3,
+ FCMAC1_SEG_NUM = 4,
+ FCMAC2_SEG_NUM = 5,
+ FC1_MBOX_SEG_NUM = 6,
+ IDE_SEG_NUM = 7,
+ NIC1_MBOX_SEG_NUM = 8,
+ SMBUS_SEG_NUM = 9,
+ FC2_MBOX_SEG_NUM = 10,
+ NIC2_MBOX_SEG_NUM = 11,
+ I2C_SEG_NUM = 12,
+ MEMC_SEG_NUM = 13,
+ PBUS_SEG_NUM = 14,
+ MDE_SEG_NUM = 15,
+ NIC1_CONTROL_SEG_NUM = 16,
+ NIC2_CONTROL_SEG_NUM = 17,
+ NIC1_XGMAC_SEG_NUM = 18,
+ NIC2_XGMAC_SEG_NUM = 19,
+ WCS_RAM_SEG_NUM = 20,
+ MEMC_RAM_SEG_NUM = 21,
+ XAUI_AN_SEG_NUM = 22,
+ XAUI_HSS_PCS_SEG_NUM = 23,
+ XFI_AN_SEG_NUM = 24,
+ XFI_TRAIN_SEG_NUM = 25,
+ XFI_HSS_PCS_SEG_NUM = 26,
+ XFI_HSS_TX_SEG_NUM = 27,
+ XFI_HSS_RX_SEG_NUM = 28,
+ XFI_HSS_PLL_SEG_NUM = 29,
+ MISC_NIC_INFO_SEG_NUM = 30,
+ INTR_STATES_SEG_NUM = 31,
+ CAM_ENTRIES_SEG_NUM = 32,
+ ROUTING_WORDS_SEG_NUM = 33,
+ ETS_SEG_NUM = 34,
+ PROBE_DUMP_SEG_NUM = 35,
+ ROUTING_INDEX_SEG_NUM = 36,
+ MAC_PROTOCOL_SEG_NUM = 37,
+ XAUI2_AN_SEG_NUM = 38,
+ XAUI2_HSS_PCS_SEG_NUM = 39,
+ XFI2_AN_SEG_NUM = 40,
+ XFI2_TRAIN_SEG_NUM = 41,
+ XFI2_HSS_PCS_SEG_NUM = 42,
+ XFI2_HSS_TX_SEG_NUM = 43,
+ XFI2_HSS_RX_SEG_NUM = 44,
+ XFI2_HSS_PLL_SEG_NUM = 45,
+ SEM_REGS_SEG_NUM = 50
+
+};
+
+struct ql_nic_misc {
+ u32 rx_ring_count;
+ u32 tx_ring_count;
+ u32 intr_count;
+ u32 function;
+};
+
+struct ql_reg_dump {
+
+ /* segment 0 */
+ struct mpi_coredump_global_header mpi_global_header;
+
+ /* segment 16 */
+ struct mpi_coredump_segment_header nic_regs_seg_hdr;
+ u32 nic_regs[64];
+
+ /* segment 30 */
+ struct mpi_coredump_segment_header misc_nic_seg_hdr;
+ struct ql_nic_misc misc_nic_info;
+
+ /* segment 31 */
+ /* one interrupt state for each CQ */
+ struct mpi_coredump_segment_header intr_states_seg_hdr;
+ u32 intr_states[MAX_CPUS];
+
+ /* segment 32 */
+ /* 3 cam words each for 16 unicast,
+ * 2 cam words for each of 32 multicast.
+ */
+ struct mpi_coredump_segment_header cam_entries_seg_hdr;
+ u32 cam_entries[(16 * 3) + (32 * 3)];
+
+ /* segment 33 */
+ struct mpi_coredump_segment_header nic_routing_words_seg_hdr;
+ u32 nic_routing_words[16];
+
+ /* segment 34 */
+ struct mpi_coredump_segment_header ets_seg_hdr;
+ u32 ets[8+2];
};
/*
@@ -1504,6 +1687,7 @@ struct ql_adapter {
struct rx_ring rx_ring[MAX_RX_RINGS];
struct tx_ring tx_ring[MAX_TX_RINGS];
+ unsigned int lbq_buf_order;
int rx_csum;
u32 default_rx_queue;
@@ -1518,11 +1702,11 @@ struct ql_adapter {
u32 port_init;
u32 link_status;
u32 link_config;
+ u32 led_config;
u32 max_frame_size;
union flash_params flash;
- struct net_device_stats stats;
struct workqueue_struct *workqueue;
struct delayed_work asic_reset_work;
struct delayed_work mpi_reset_work;
@@ -1610,10 +1794,19 @@ int ql_mb_get_fw_state(struct ql_adapter *qdev);
int ql_cam_route_initialize(struct ql_adapter *qdev);
int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data);
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);
+int ql_mb_get_led_cfg(struct ql_adapter *qdev);
void ql_link_on(struct ql_adapter *qdev);
void ql_link_off(struct ql_adapter *qdev);
int ql_mb_set_mgmnt_traffic_ctl(struct ql_adapter *qdev, u32 control);
+int ql_mb_get_port_cfg(struct ql_adapter *qdev);
+int ql_mb_set_port_cfg(struct ql_adapter *qdev);
int ql_wait_fifo_empty(struct ql_adapter *qdev);
+void ql_gen_reg_dump(struct ql_adapter *qdev,
+ struct ql_reg_dump *mpi_coredump);
#if 1
#define QL_ALL_DUMP
diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c
index aa88cb3f41c7..9f58c4710761 100644
--- a/drivers/net/qlge/qlge_dbg.c
+++ b/drivers/net/qlge/qlge_dbg.c
@@ -1,5 +1,185 @@
#include "qlge.h"
+
+static int ql_get_ets_regs(struct ql_adapter *qdev, u32 * buf)
+{
+ int status = 0;
+ int i;
+
+ for (i = 0; i < 8; i++, buf++) {
+ ql_write32(qdev, NIC_ETS, i << 29 | 0x08000000);
+ *buf = ql_read32(qdev, NIC_ETS);
+ }
+
+ for (i = 0; i < 2; i++, buf++) {
+ ql_write32(qdev, CNA_ETS, i << 29 | 0x08000000);
+ *buf = ql_read32(qdev, CNA_ETS);
+ }
+
+ return status;
+}
+
+static void ql_get_intr_states(struct ql_adapter *qdev, u32 * buf)
+{
+ int i;
+
+ for (i = 0; i < qdev->rx_ring_count; i++, buf++) {
+ ql_write32(qdev, INTR_EN,
+ qdev->intr_context[i].intr_read_mask);
+ *buf = ql_read32(qdev, INTR_EN);
+ }
+}
+
+static int ql_get_cam_entries(struct ql_adapter *qdev, u32 * buf)
+{
+ int i, status;
+ u32 value[3];
+
+ status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
+ if (status)
+ return status;
+
+ for (i = 0; i < 16; i++) {
+ status = ql_get_mac_addr_reg(qdev,
+ MAC_ADDR_TYPE_CAM_MAC, i, value);
+ if (status) {
+ QPRINTK(qdev, DRV, ERR,
+ "Failed read of mac index register.\n");
+ goto err;
+ }
+ *buf++ = value[0]; /* lower MAC address */
+ *buf++ = value[1]; /* upper MAC address */
+ *buf++ = value[2]; /* output */
+ }
+ for (i = 0; i < 32; i++) {
+ status = ql_get_mac_addr_reg(qdev,
+ MAC_ADDR_TYPE_MULTI_MAC, i, value);
+ if (status) {
+ QPRINTK(qdev, DRV, ERR,
+ "Failed read of mac index register.\n");
+ goto err;
+ }
+ *buf++ = value[0]; /* lower Mcast address */
+ *buf++ = value[1]; /* upper Mcast address */
+ }
+err:
+ ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
+ return status;
+}
+
+static int ql_get_routing_entries(struct ql_adapter *qdev, u32 * buf)
+{
+ int status;
+ u32 value, i;
+
+ status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
+ if (status)
+ return status;
+
+ for (i = 0; i < 16; i++) {
+ status = ql_get_routing_reg(qdev, i, &value);
+ if (status) {
+ QPRINTK(qdev, DRV, ERR,
+ "Failed read of routing index register.\n");
+ goto err;
+ } else {
+ *buf++ = value;
+ }
+ }
+err:
+ ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
+ return status;
+}
+
+/* Create a coredump segment header */
+static void ql_build_coredump_seg_header(
+ struct mpi_coredump_segment_header *seg_hdr,
+ u32 seg_number, u32 seg_size, u8 *desc)
+{
+ memset(seg_hdr, 0, sizeof(struct mpi_coredump_segment_header));
+ seg_hdr->cookie = MPI_COREDUMP_COOKIE;
+ seg_hdr->segNum = seg_number;
+ seg_hdr->segSize = seg_size;
+ memcpy(seg_hdr->description, desc, (sizeof(seg_hdr->description)) - 1);
+}
+
+void ql_gen_reg_dump(struct ql_adapter *qdev,
+ struct ql_reg_dump *mpi_coredump)
+{
+ int i, status;
+
+
+ memset(&(mpi_coredump->mpi_global_header), 0,
+ sizeof(struct mpi_coredump_global_header));
+ mpi_coredump->mpi_global_header.cookie = MPI_COREDUMP_COOKIE;
+ mpi_coredump->mpi_global_header.headerSize =
+ sizeof(struct mpi_coredump_global_header);
+ mpi_coredump->mpi_global_header.imageSize =
+ sizeof(struct ql_reg_dump);
+ memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump",
+ sizeof(mpi_coredump->mpi_global_header.idString));
+
+
+ /* segment 16 */
+ ql_build_coredump_seg_header(&mpi_coredump->misc_nic_seg_hdr,
+ MISC_NIC_INFO_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->misc_nic_info),
+ "MISC NIC INFO");
+ mpi_coredump->misc_nic_info.rx_ring_count = qdev->rx_ring_count;
+ mpi_coredump->misc_nic_info.tx_ring_count = qdev->tx_ring_count;
+ mpi_coredump->misc_nic_info.intr_count = qdev->intr_count;
+ mpi_coredump->misc_nic_info.function = qdev->func;
+
+ /* Segment 16, Rev C. Step 18 */
+ ql_build_coredump_seg_header(&mpi_coredump->nic_regs_seg_hdr,
+ NIC1_CONTROL_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->nic_regs),
+ "NIC Registers");
+ /* Get generic reg dump */
+ for (i = 0; i < 64; i++)
+ mpi_coredump->nic_regs[i] = ql_read32(qdev, i * sizeof(u32));
+
+ /* Segment 31 */
+ /* Get indexed register values. */
+ ql_build_coredump_seg_header(&mpi_coredump->intr_states_seg_hdr,
+ INTR_STATES_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->intr_states),
+ "INTR States");
+ ql_get_intr_states(qdev, &mpi_coredump->intr_states[0]);
+
+ ql_build_coredump_seg_header(&mpi_coredump->cam_entries_seg_hdr,
+ CAM_ENTRIES_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->cam_entries),
+ "CAM Entries");
+ status = ql_get_cam_entries(qdev, &mpi_coredump->cam_entries[0]);
+ if (status)
+ return;
+
+ ql_build_coredump_seg_header(&mpi_coredump->nic_routing_words_seg_hdr,
+ ROUTING_WORDS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->nic_routing_words),
+ "Routing Words");
+ status = ql_get_routing_entries(qdev,
+ &mpi_coredump->nic_routing_words[0]);
+ if (status)
+ return;
+
+ /* Segment 34 (Rev C. step 23) */
+ ql_build_coredump_seg_header(&mpi_coredump->ets_seg_hdr,
+ ETS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->ets),
+ "ETS Registers");
+ status = ql_get_ets_regs(qdev, &mpi_coredump->ets[0]);
+ if (status)
+ return;
+}
+
#ifdef QL_REG_DUMP
static void ql_dump_intr_states(struct ql_adapter *qdev)
{
diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c
index 52073946bce3..62c4af057800 100644
--- a/drivers/net/qlge/qlge_ethtool.c
+++ b/drivers/net/qlge/qlge_ethtool.c
@@ -132,6 +132,41 @@ static void ql_update_stats(struct ql_adapter *qdev)
iter++;
}
+ /*
+ * Get Per-priority TX pause frame counter statistics.
+ */
+ for (i = 0x500; i < 0x540; i += 8) {
+ if (ql_read_xgmac_reg64(qdev, i, &data)) {
+ QPRINTK(qdev, DRV, ERR,
+ "Error reading status register 0x%.04x.\n", i);
+ goto end;
+ } else
+ *iter = data;
+ iter++;
+ }
+
+ /*
+ * Get Per-priority RX pause frame counter statistics.
+ */
+ for (i = 0x568; i < 0x5a8; i += 8) {
+ if (ql_read_xgmac_reg64(qdev, i, &data)) {
+ QPRINTK(qdev, DRV, ERR,
+ "Error reading status register 0x%.04x.\n", i);
+ goto end;
+ } else
+ *iter = data;
+ iter++;
+ }
+
+ /*
+ * Get RX NIC FIFO DROP statistics.
+ */
+ if (ql_read_xgmac_reg64(qdev, 0x5b8, &data)) {
+ QPRINTK(qdev, DRV, ERR,
+ "Error reading status register 0x%.04x.\n", i);
+ goto end;
+ } else
+ *iter = data;
end:
ql_sem_unlock(qdev, qdev->xg_sem_mask);
quit:
@@ -185,6 +220,23 @@ static char ql_stats_str_arr[][ETH_GSTRING_LEN] = {
{"rx_1024_to_1518_pkts"},
{"rx_1519_to_max_pkts"},
{"rx_len_err_pkts"},
+ {"tx_cbfc_pause_frames0"},
+ {"tx_cbfc_pause_frames1"},
+ {"tx_cbfc_pause_frames2"},
+ {"tx_cbfc_pause_frames3"},
+ {"tx_cbfc_pause_frames4"},
+ {"tx_cbfc_pause_frames5"},
+ {"tx_cbfc_pause_frames6"},
+ {"tx_cbfc_pause_frames7"},
+ {"rx_cbfc_pause_frames0"},
+ {"rx_cbfc_pause_frames1"},
+ {"rx_cbfc_pause_frames2"},
+ {"rx_cbfc_pause_frames3"},
+ {"rx_cbfc_pause_frames4"},
+ {"rx_cbfc_pause_frames5"},
+ {"rx_cbfc_pause_frames6"},
+ {"rx_cbfc_pause_frames7"},
+ {"rx_nic_fifo_drop"},
};
static void ql_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
@@ -257,6 +309,23 @@ ql_get_ethtool_stats(struct net_device *ndev,
*data++ = s->rx_1024_to_1518_pkts;
*data++ = s->rx_1519_to_max_pkts;
*data++ = s->rx_len_err_pkts;
+ *data++ = s->tx_cbfc_pause_frames0;
+ *data++ = s->tx_cbfc_pause_frames1;
+ *data++ = s->tx_cbfc_pause_frames2;
+ *data++ = s->tx_cbfc_pause_frames3;
+ *data++ = s->tx_cbfc_pause_frames4;
+ *data++ = s->tx_cbfc_pause_frames5;
+ *data++ = s->tx_cbfc_pause_frames6;
+ *data++ = s->tx_cbfc_pause_frames7;
+ *data++ = s->rx_cbfc_pause_frames0;
+ *data++ = s->rx_cbfc_pause_frames1;
+ *data++ = s->rx_cbfc_pause_frames2;
+ *data++ = s->rx_cbfc_pause_frames3;
+ *data++ = s->rx_cbfc_pause_frames4;
+ *data++ = s->rx_cbfc_pause_frames5;
+ *data++ = s->rx_cbfc_pause_frames6;
+ *data++ = s->rx_cbfc_pause_frames7;
+ *data++ = s->rx_nic_fifo_drop;
}
static int ql_get_settings(struct net_device *ndev,
@@ -302,6 +371,77 @@ static void ql_get_drvinfo(struct net_device *ndev,
drvinfo->eedump_len = 0;
}
+static void ql_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
+{
+ struct ql_adapter *qdev = netdev_priv(ndev);
+ /* What we support. */
+ wol->supported = WAKE_MAGIC;
+ /* What we've currently got set. */
+ wol->wolopts = qdev->wol;
+}
+
+static int ql_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
+{
+ struct ql_adapter *qdev = netdev_priv(ndev);
+ int status;
+
+ if (wol->wolopts & ~WAKE_MAGIC)
+ return -EINVAL;
+ qdev->wol = wol->wolopts;
+
+ QPRINTK(qdev, DRV, INFO, "Set wol option 0x%x on %s\n",
+ qdev->wol, ndev->name);
+ if (!qdev->wol) {
+ u32 wol = 0;
+ status = ql_mb_wol_mode(qdev, wol);
+ QPRINTK(qdev, DRV, ERR, "WOL %s (wol code 0x%x) on %s\n",
+ (status == 0) ? "cleared sucessfully" : "clear failed",
+ wol, qdev->ndev->name);
+ }
+
+ return 0;
+}
+
+static int ql_phys_id(struct net_device *ndev, u32 data)
+{
+ struct ql_adapter *qdev = netdev_priv(ndev);
+ u32 led_reg, i;
+ int status;
+
+ /* Save the current LED settings */
+ status = ql_mb_get_led_cfg(qdev);
+ if (status)
+ return status;
+ led_reg = qdev->led_config;
+
+ /* Start blinking the led */
+ if (!data || data > 300)
+ data = 300;
+
+ for (i = 0; i < (data * 10); i++)
+ ql_mb_set_led_cfg(qdev, QL_LED_BLINK);
+
+ /* Restore LED settings */
+ status = ql_mb_set_led_cfg(qdev, led_reg);
+ if (status)
+ return status;
+
+ return 0;
+}
+
+static int ql_get_regs_len(struct net_device *ndev)
+{
+ return sizeof(struct ql_reg_dump);
+}
+
+static void ql_get_regs(struct net_device *ndev,
+ struct ethtool_regs *regs, void *p)
+{
+ struct ql_adapter *qdev = netdev_priv(ndev);
+
+ ql_gen_reg_dump(qdev, p);
+}
+
static int ql_get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
{
struct ql_adapter *qdev = netdev_priv(dev);
@@ -355,6 +495,37 @@ static int ql_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *c)
return ql_update_ring_coalescing(qdev);
}
+static void ql_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct ql_adapter *qdev = netdev_priv(netdev);
+
+ ql_mb_get_port_cfg(qdev);
+ if (qdev->link_config & CFG_PAUSE_STD) {
+ pause->rx_pause = 1;
+ pause->tx_pause = 1;
+ }
+}
+
+static int ql_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct ql_adapter *qdev = netdev_priv(netdev);
+ int status = 0;
+
+ if ((pause->rx_pause) && (pause->tx_pause))
+ qdev->link_config |= CFG_PAUSE_STD;
+ else if (!pause->rx_pause && !pause->tx_pause)
+ qdev->link_config &= ~CFG_PAUSE_STD;
+ else
+ return -EINVAL;
+
+ status = ql_mb_set_port_cfg(qdev);
+ if (status)
+ return status;
+ return status;
+}
+
static u32 ql_get_rx_csum(struct net_device *netdev)
{
struct ql_adapter *qdev = netdev_priv(netdev);
@@ -396,9 +567,16 @@ static void ql_set_msglevel(struct net_device *ndev, u32 value)
const struct ethtool_ops qlge_ethtool_ops = {
.get_settings = ql_get_settings,
.get_drvinfo = ql_get_drvinfo,
+ .get_wol = ql_get_wol,
+ .set_wol = ql_set_wol,
+ .get_regs_len = ql_get_regs_len,
+ .get_regs = ql_get_regs,
.get_msglevel = ql_get_msglevel,
.set_msglevel = ql_set_msglevel,
.get_link = ethtool_op_get_link,
+ .phys_id = ql_phys_id,
+ .get_pauseparam = ql_get_pauseparam,
+ .set_pauseparam = ql_set_pauseparam,
.get_rx_csum = ql_get_rx_csum,
.set_rx_csum = ql_set_rx_csum,
.get_tx_csum = ethtool_op_get_tx_csum,
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 48b45df85ec9..dd0ea0277550 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -1025,6 +1025,11 @@ end:
return status;
}
+static inline unsigned int ql_lbq_block_size(struct ql_adapter *qdev)
+{
+ return PAGE_SIZE << qdev->lbq_buf_order;
+}
+
/* Get the next large buffer. */
static struct bq_desc *ql_get_curr_lbuf(struct rx_ring *rx_ring)
{
@@ -1036,6 +1041,28 @@ static struct bq_desc *ql_get_curr_lbuf(struct rx_ring *rx_ring)
return lbq_desc;
}
+static struct bq_desc *ql_get_curr_lchunk(struct ql_adapter *qdev,
+ struct rx_ring *rx_ring)
+{
+ struct bq_desc *lbq_desc = ql_get_curr_lbuf(rx_ring);
+
+ pci_dma_sync_single_for_cpu(qdev->pdev,
+ pci_unmap_addr(lbq_desc, mapaddr),
+ rx_ring->lbq_buf_size,
+ PCI_DMA_FROMDEVICE);
+
+ /* If it's the last chunk of our master page then
+ * we unmap it.
+ */
+ if ((lbq_desc->p.pg_chunk.offset + rx_ring->lbq_buf_size)
+ == ql_lbq_block_size(qdev))
+ pci_unmap_page(qdev->pdev,
+ lbq_desc->p.pg_chunk.map,
+ ql_lbq_block_size(qdev),
+ PCI_DMA_FROMDEVICE);
+ return lbq_desc;
+}
+
/* Get the next small buffer. */
static struct bq_desc *ql_get_curr_sbuf(struct rx_ring *rx_ring)
{
@@ -1063,6 +1090,53 @@ static void ql_write_cq_idx(struct rx_ring *rx_ring)
ql_write_db_reg(rx_ring->cnsmr_idx, rx_ring->cnsmr_idx_db_reg);
}
+static int ql_get_next_chunk(struct ql_adapter *qdev, struct rx_ring *rx_ring,
+ struct bq_desc *lbq_desc)
+{
+ if (!rx_ring->pg_chunk.page) {
+ u64 map;
+ rx_ring->pg_chunk.page = alloc_pages(__GFP_COLD | __GFP_COMP |
+ GFP_ATOMIC,
+ qdev->lbq_buf_order);
+ if (unlikely(!rx_ring->pg_chunk.page)) {
+ QPRINTK(qdev, DRV, ERR,
+ "page allocation failed.\n");
+ return -ENOMEM;
+ }
+ rx_ring->pg_chunk.offset = 0;
+ map = pci_map_page(qdev->pdev, rx_ring->pg_chunk.page,
+ 0, ql_lbq_block_size(qdev),
+ PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(qdev->pdev, map)) {
+ __free_pages(rx_ring->pg_chunk.page,
+ qdev->lbq_buf_order);
+ QPRINTK(qdev, DRV, ERR,
+ "PCI mapping failed.\n");
+ return -ENOMEM;
+ }
+ rx_ring->pg_chunk.map = map;
+ rx_ring->pg_chunk.va = page_address(rx_ring->pg_chunk.page);
+ }
+
+ /* Copy the current master pg_chunk info
+ * to the current descriptor.
+ */
+ lbq_desc->p.pg_chunk = rx_ring->pg_chunk;
+
+ /* Adjust the master page chunk for next
+ * buffer get.
+ */
+ rx_ring->pg_chunk.offset += rx_ring->lbq_buf_size;
+ if (rx_ring->pg_chunk.offset == ql_lbq_block_size(qdev)) {
+ rx_ring->pg_chunk.page = NULL;
+ lbq_desc->p.pg_chunk.last_flag = 1;
+ } else {
+ rx_ring->pg_chunk.va += rx_ring->lbq_buf_size;
+ get_page(rx_ring->pg_chunk.page);
+ lbq_desc->p.pg_chunk.last_flag = 0;
+ }
+ return 0;
+}
/* Process (refill) a large buffer queue. */
static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
{
@@ -1072,39 +1146,28 @@ static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
u64 map;
int i;
- while (rx_ring->lbq_free_cnt > 16) {
+ while (rx_ring->lbq_free_cnt > 32) {
for (i = 0; i < 16; i++) {
QPRINTK(qdev, RX_STATUS, DEBUG,
"lbq: try cleaning clean_idx = %d.\n",
clean_idx);
lbq_desc = &rx_ring->lbq[clean_idx];
- if (lbq_desc->p.lbq_page == NULL) {
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "lbq: getting new page for index %d.\n",
- lbq_desc->index);
- lbq_desc->p.lbq_page = alloc_page(GFP_ATOMIC);
- if (lbq_desc->p.lbq_page == NULL) {
- rx_ring->lbq_clean_idx = clean_idx;
- QPRINTK(qdev, RX_STATUS, ERR,
- "Couldn't get a page.\n");
- return;
- }
- map = pci_map_page(qdev->pdev,
- lbq_desc->p.lbq_page,
- 0, PAGE_SIZE,
- PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(qdev->pdev, map)) {
- rx_ring->lbq_clean_idx = clean_idx;
- put_page(lbq_desc->p.lbq_page);
- lbq_desc->p.lbq_page = NULL;
- QPRINTK(qdev, RX_STATUS, ERR,
- "PCI mapping failed.\n");
+ if (ql_get_next_chunk(qdev, rx_ring, lbq_desc)) {
+ QPRINTK(qdev, IFUP, ERR,
+ "Could not get a page chunk.\n");
return;
}
+
+ map = lbq_desc->p.pg_chunk.map +
+ lbq_desc->p.pg_chunk.offset;
pci_unmap_addr_set(lbq_desc, mapaddr, map);
- pci_unmap_len_set(lbq_desc, maplen, PAGE_SIZE);
+ pci_unmap_len_set(lbq_desc, maplen,
+ rx_ring->lbq_buf_size);
*lbq_desc->addr = cpu_to_le64(map);
- }
+
+ pci_dma_sync_single_for_device(qdev->pdev, map,
+ rx_ring->lbq_buf_size,
+ PCI_DMA_FROMDEVICE);
clean_idx++;
if (clean_idx == rx_ring->lbq_len)
clean_idx = 0;
@@ -1147,7 +1210,7 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
sbq_desc->index);
sbq_desc->p.skb =
netdev_alloc_skb(qdev->ndev,
- rx_ring->sbq_buf_size);
+ SMALL_BUFFER_SIZE);
if (sbq_desc->p.skb == NULL) {
QPRINTK(qdev, PROBE, ERR,
"Couldn't get an skb.\n");
@@ -1157,8 +1220,8 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
skb_reserve(sbq_desc->p.skb, QLGE_SB_PAD);
map = pci_map_single(qdev->pdev,
sbq_desc->p.skb->data,
- rx_ring->sbq_buf_size /
- 2, PCI_DMA_FROMDEVICE);
+ rx_ring->sbq_buf_size,
+ PCI_DMA_FROMDEVICE);
if (pci_dma_mapping_error(qdev->pdev, map)) {
QPRINTK(qdev, IFUP, ERR, "PCI mapping failed.\n");
rx_ring->sbq_clean_idx = clean_idx;
@@ -1168,7 +1231,7 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
}
pci_unmap_addr_set(sbq_desc, mapaddr, map);
pci_unmap_len_set(sbq_desc, maplen,
- rx_ring->sbq_buf_size / 2);
+ rx_ring->sbq_buf_size);
*sbq_desc->addr = cpu_to_le64(map);
}
@@ -1480,27 +1543,24 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
* chain it to the header buffer's skb and let
* it rip.
*/
- lbq_desc = ql_get_curr_lbuf(rx_ring);
- pci_unmap_page(qdev->pdev,
- pci_unmap_addr(lbq_desc,
- mapaddr),
- pci_unmap_len(lbq_desc, maplen),
- PCI_DMA_FROMDEVICE);
+ lbq_desc = ql_get_curr_lchunk(qdev, rx_ring);
QPRINTK(qdev, RX_STATUS, DEBUG,
- "Chaining page to skb.\n");
- skb_fill_page_desc(skb, 0, lbq_desc->p.lbq_page,
- 0, length);
+ "Chaining page at offset = %d,"
+ "for %d bytes to skb.\n",
+ lbq_desc->p.pg_chunk.offset, length);
+ skb_fill_page_desc(skb, 0, lbq_desc->p.pg_chunk.page,
+ lbq_desc->p.pg_chunk.offset,
+ length);
skb->len += length;
skb->data_len += length;
skb->truesize += length;
- lbq_desc->p.lbq_page = NULL;
} else {
/*
* The headers and data are in a single large buffer. We
* copy it to a new skb and let it go. This can happen with
* jumbo mtu on a non-TCP/UDP frame.
*/
- lbq_desc = ql_get_curr_lbuf(rx_ring);
+ lbq_desc = ql_get_curr_lchunk(qdev, rx_ring);
skb = netdev_alloc_skb(qdev->ndev, length);
if (skb == NULL) {
QPRINTK(qdev, PROBE, DEBUG,
@@ -1515,13 +1575,14 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
skb_reserve(skb, NET_IP_ALIGN);
QPRINTK(qdev, RX_STATUS, DEBUG,
"%d bytes of headers and data in large. Chain page to new skb and pull tail.\n", length);
- skb_fill_page_desc(skb, 0, lbq_desc->p.lbq_page,
- 0, length);
+ skb_fill_page_desc(skb, 0,
+ lbq_desc->p.pg_chunk.page,
+ lbq_desc->p.pg_chunk.offset,
+ length);
skb->len += length;
skb->data_len += length;
skb->truesize += length;
length -= length;
- lbq_desc->p.lbq_page = NULL;
__pskb_pull_tail(skb,
(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) ?
VLAN_ETH_HLEN : ETH_HLEN);
@@ -1538,8 +1599,7 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
* frames. If the MTU goes up we could
* eventually be in trouble.
*/
- int size, offset, i = 0;
- __le64 *bq, bq_array[8];
+ int size, i = 0;
sbq_desc = ql_get_curr_sbuf(rx_ring);
pci_unmap_single(qdev->pdev,
pci_unmap_addr(sbq_desc, mapaddr),
@@ -1558,37 +1618,25 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
QPRINTK(qdev, RX_STATUS, DEBUG,
"%d bytes of headers & data in chain of large.\n", length);
skb = sbq_desc->p.skb;
- bq = &bq_array[0];
- memcpy(bq, skb->data, sizeof(bq_array));
sbq_desc->p.skb = NULL;
skb_reserve(skb, NET_IP_ALIGN);
- } else {
- QPRINTK(qdev, RX_STATUS, DEBUG,
- "Headers in small, %d bytes of data in chain of large.\n", length);
- bq = (__le64 *)sbq_desc->p.skb->data;
}
while (length > 0) {
- lbq_desc = ql_get_curr_lbuf(rx_ring);
- pci_unmap_page(qdev->pdev,
- pci_unmap_addr(lbq_desc,
- mapaddr),
- pci_unmap_len(lbq_desc,
- maplen),
- PCI_DMA_FROMDEVICE);
- size = (length < PAGE_SIZE) ? length : PAGE_SIZE;
- offset = 0;
+ lbq_desc = ql_get_curr_lchunk(qdev, rx_ring);
+ size = (length < rx_ring->lbq_buf_size) ? length :
+ rx_ring->lbq_buf_size;
QPRINTK(qdev, RX_STATUS, DEBUG,
"Adding page %d to skb for %d bytes.\n",
i, size);
- skb_fill_page_desc(skb, i, lbq_desc->p.lbq_page,
- offset, size);
+ skb_fill_page_desc(skb, i,
+ lbq_desc->p.pg_chunk.page,
+ lbq_desc->p.pg_chunk.offset,
+ size);
skb->len += size;
skb->data_len += size;
skb->truesize += size;
length -= size;
- lbq_desc->p.lbq_page = NULL;
- bq++;
i++;
}
__pskb_pull_tail(skb, (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) ?
@@ -1673,8 +1721,8 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev,
}
}
- qdev->stats.rx_packets++;
- qdev->stats.rx_bytes += skb->len;
+ ndev->stats.rx_packets++;
+ ndev->stats.rx_bytes += skb->len;
skb_record_rx_queue(skb, rx_ring->cq_id);
if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
if (qdev->vlgrp &&
@@ -1698,6 +1746,7 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev,
static void ql_process_mac_tx_intr(struct ql_adapter *qdev,
struct ob_mac_iocb_rsp *mac_rsp)
{
+ struct net_device *ndev = qdev->ndev;
struct tx_ring *tx_ring;
struct tx_ring_desc *tx_ring_desc;
@@ -1705,8 +1754,8 @@ static void ql_process_mac_tx_intr(struct ql_adapter *qdev,
tx_ring = &qdev->tx_ring[mac_rsp->txq_idx];
tx_ring_desc = &tx_ring->q[mac_rsp->tid];
ql_unmap_send(qdev, tx_ring_desc, tx_ring_desc->map_cnt);
- qdev->stats.tx_bytes += (tx_ring_desc->skb)->len;
- qdev->stats.tx_packets++;
+ ndev->stats.tx_bytes += (tx_ring_desc->skb)->len;
+ ndev->stats.tx_packets++;
dev_kfree_skb(tx_ring_desc->skb);
tx_ring_desc->skb = NULL;
@@ -2304,20 +2353,29 @@ err:
static void ql_free_lbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring)
{
- int i;
struct bq_desc *lbq_desc;
- for (i = 0; i < rx_ring->lbq_len; i++) {
- lbq_desc = &rx_ring->lbq[i];
- if (lbq_desc->p.lbq_page) {
+ uint32_t curr_idx, clean_idx;
+
+ curr_idx = rx_ring->lbq_curr_idx;
+ clean_idx = rx_ring->lbq_clean_idx;
+ while (curr_idx != clean_idx) {
+ lbq_desc = &rx_ring->lbq[curr_idx];
+
+ if (lbq_desc->p.pg_chunk.last_flag) {
pci_unmap_page(qdev->pdev,
- pci_unmap_addr(lbq_desc, mapaddr),
- pci_unmap_len(lbq_desc, maplen),
+ lbq_desc->p.pg_chunk.map,
+ ql_lbq_block_size(qdev),
PCI_DMA_FROMDEVICE);
-
- put_page(lbq_desc->p.lbq_page);
- lbq_desc->p.lbq_page = NULL;
+ lbq_desc->p.pg_chunk.last_flag = 0;
}
+
+ put_page(lbq_desc->p.pg_chunk.page);
+ lbq_desc->p.pg_chunk.page = NULL;
+
+ if (++curr_idx == rx_ring->lbq_len)
+ curr_idx = 0;
+
}
}
@@ -2615,6 +2673,7 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
/* Set up the shadow registers for this ring. */
rx_ring->prod_idx_sh_reg = shadow_reg;
rx_ring->prod_idx_sh_reg_dma = shadow_reg_dma;
+ *rx_ring->prod_idx_sh_reg = 0;
shadow_reg += sizeof(u64);
shadow_reg_dma += sizeof(u64);
rx_ring->lbq_base_indirect = shadow_reg;
@@ -2692,7 +2751,7 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
cqicb->sbq_addr =
cpu_to_le64(rx_ring->sbq_base_indirect_dma);
cqicb->sbq_buf_size =
- cpu_to_le16((u16)(rx_ring->sbq_buf_size/2));
+ cpu_to_le16((u16)(rx_ring->sbq_buf_size));
bq_len = (rx_ring->sbq_len == 65536) ? 0 :
(u16) rx_ring->sbq_len;
cqicb->sbq_len = cpu_to_le16(bq_len);
@@ -3268,7 +3327,7 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
ql_write32(qdev, FSC, mask | value);
ql_write32(qdev, SPLT_HDR, SPLT_HDR_EP |
- min(SMALL_BUFFER_SIZE, MAX_SPLIT_SIZE));
+ min(SMALL_BUF_MAP_SIZE, MAX_SPLIT_SIZE));
/* Set RX packet routing to use port/pci function on which the
* packet arrived on in addition to usual frame routing.
@@ -3276,6 +3335,22 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
* the same MAC address.
*/
ql_write32(qdev, RST_FO, RST_FO_RR_MASK | RST_FO_RR_RCV_FUNC_CQ);
+ /* Reroute all packets to our Interface.
+ * They may have been routed to MPI firmware
+ * due to WOL.
+ */
+ value = ql_read32(qdev, MGMT_RCV_CFG);
+ value &= ~MGMT_RCV_CFG_RM;
+ mask = 0xffff0000;
+
+ /* Sticky reg needs clearing due to WOL. */
+ ql_write32(qdev, MGMT_RCV_CFG, mask);
+ ql_write32(qdev, MGMT_RCV_CFG, mask | value);
+
+ /* Default WOL is enable on Mezz cards */
+ if (qdev->pdev->subsystem_device == 0x0068 ||
+ qdev->pdev->subsystem_device == 0x0180)
+ qdev->wol = WAKE_MAGIC;
/* Start up the rx queues. */
for (i = 0; i < qdev->rx_ring_count; i++) {
@@ -3310,10 +3385,8 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
/* Initialize the port and set the max framesize. */
status = qdev->nic_ops->port_initialize(qdev);
- if (status) {
- QPRINTK(qdev, IFUP, ERR, "Failed to start port.\n");
- return status;
- }
+ if (status)
+ QPRINTK(qdev, IFUP, ERR, "Failed to start port.\n");
/* Set up the MAC address and frame routing filter. */
status = ql_cam_route_initialize(qdev);
@@ -3392,6 +3465,55 @@ static void ql_display_dev_info(struct net_device *ndev)
QPRINTK(qdev, PROBE, INFO, "MAC address %pM\n", ndev->dev_addr);
}
+int ql_wol(struct ql_adapter *qdev)
+{
+ int status = 0;
+ u32 wol = MB_WOL_DISABLE;
+
+ /* The CAM is still intact after a reset, but if we
+ * are doing WOL, then we may need to program the
+ * routing regs. We would also need to issue the mailbox
+ * commands to instruct the MPI what to do per the ethtool
+ * settings.
+ */
+
+ if (qdev->wol & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_PHY | WAKE_UCAST |
+ WAKE_MCAST | WAKE_BCAST)) {
+ QPRINTK(qdev, IFDOWN, ERR,
+ "Unsupported WOL paramter. qdev->wol = 0x%x.\n",
+ qdev->wol);
+ return -EINVAL;
+ }
+
+ if (qdev->wol & WAKE_MAGIC) {
+ status = ql_mb_wol_set_magic(qdev, 1);
+ if (status) {
+ QPRINTK(qdev, IFDOWN, ERR,
+ "Failed to set magic packet on %s.\n",
+ qdev->ndev->name);
+ return status;
+ } else
+ QPRINTK(qdev, DRV, INFO,
+ "Enabled magic packet successfully on %s.\n",
+ qdev->ndev->name);
+
+ wol |= MB_WOL_MAGIC_PKT;
+ }
+
+ if (qdev->wol) {
+ /* Reroute all packets to Management Interface */
+ ql_write32(qdev, MGMT_RCV_CFG, (MGMT_RCV_CFG_RM |
+ (MGMT_RCV_CFG_RM << 16)));
+ wol |= MB_WOL_MODE_ON;
+ status = ql_mb_wol_mode(qdev, wol);
+ QPRINTK(qdev, DRV, ERR, "WOL %s (wol code 0x%x) on %s\n",
+ (status == 0) ? "Sucessfully set" : "Failed", wol,
+ qdev->ndev->name);
+ }
+
+ return status;
+}
+
static int ql_adapter_down(struct ql_adapter *qdev)
{
int i, status = 0;
@@ -3497,6 +3619,10 @@ static int ql_configure_rings(struct ql_adapter *qdev)
struct rx_ring *rx_ring;
struct tx_ring *tx_ring;
int cpu_cnt = min(MAX_CPUS, (int)num_online_cpus());
+ unsigned int lbq_buf_len = (qdev->ndev->mtu > 1500) ?
+ LARGE_BUFFER_MAX_SIZE : LARGE_BUFFER_MIN_SIZE;
+
+ qdev->lbq_buf_order = get_order(lbq_buf_len);
/* In a perfect world we have one RSS ring for each CPU
* and each has it's own vector. To do that we ask for
@@ -3544,11 +3670,14 @@ static int ql_configure_rings(struct ql_adapter *qdev)
rx_ring->lbq_len = NUM_LARGE_BUFFERS;
rx_ring->lbq_size =
rx_ring->lbq_len * sizeof(__le64);
- rx_ring->lbq_buf_size = LARGE_BUFFER_SIZE;
+ rx_ring->lbq_buf_size = (u16)lbq_buf_len;
+ QPRINTK(qdev, IFUP, DEBUG,
+ "lbq_buf_size %d, order = %d\n",
+ rx_ring->lbq_buf_size, qdev->lbq_buf_order);
rx_ring->sbq_len = NUM_SMALL_BUFFERS;
rx_ring->sbq_size =
rx_ring->sbq_len * sizeof(__le64);
- rx_ring->sbq_buf_size = SMALL_BUFFER_SIZE * 2;
+ rx_ring->sbq_buf_size = SMALL_BUF_MAP_SIZE;
rx_ring->type = RX_Q;
} else {
/*
@@ -3594,14 +3723,63 @@ error_up:
return err;
}
+static int ql_change_rx_buffers(struct ql_adapter *qdev)
+{
+ struct rx_ring *rx_ring;
+ int i, status;
+ u32 lbq_buf_len;
+
+ /* Wait for an oustanding reset to complete. */
+ if (!test_bit(QL_ADAPTER_UP, &qdev->flags)) {
+ int i = 3;
+ while (i-- && !test_bit(QL_ADAPTER_UP, &qdev->flags)) {
+ QPRINTK(qdev, IFUP, ERR,
+ "Waiting for adapter UP...\n");
+ ssleep(1);
+ }
+
+ if (!i) {
+ QPRINTK(qdev, IFUP, ERR,
+ "Timed out waiting for adapter UP\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ status = ql_adapter_down(qdev);
+ if (status)
+ goto error;
+
+ /* Get the new rx buffer size. */
+ lbq_buf_len = (qdev->ndev->mtu > 1500) ?
+ LARGE_BUFFER_MAX_SIZE : LARGE_BUFFER_MIN_SIZE;
+ qdev->lbq_buf_order = get_order(lbq_buf_len);
+
+ for (i = 0; i < qdev->rss_ring_count; i++) {
+ rx_ring = &qdev->rx_ring[i];
+ /* Set the new size. */
+ rx_ring->lbq_buf_size = lbq_buf_len;
+ }
+
+ status = ql_adapter_up(qdev);
+ if (status)
+ goto error;
+
+ return status;
+error:
+ QPRINTK(qdev, IFUP, ALERT,
+ "Driver up/down cycle failed, closing device.\n");
+ set_bit(QL_ADAPTER_UP, &qdev->flags);
+ dev_close(qdev->ndev);
+ return status;
+}
+
static int qlge_change_mtu(struct net_device *ndev, int new_mtu)
{
struct ql_adapter *qdev = netdev_priv(ndev);
+ int status;
if (ndev->mtu == 1500 && new_mtu == 9000) {
QPRINTK(qdev, IFUP, ERR, "Changing to jumbo MTU.\n");
- queue_delayed_work(qdev->workqueue,
- &qdev->mpi_port_cfg_work, 0);
} else if (ndev->mtu == 9000 && new_mtu == 1500) {
QPRINTK(qdev, IFUP, ERR, "Changing to normal MTU.\n");
} else if ((ndev->mtu == 1500 && new_mtu == 1500) ||
@@ -3609,15 +3787,29 @@ static int qlge_change_mtu(struct net_device *ndev, int new_mtu)
return 0;
} else
return -EINVAL;
+
+ queue_delayed_work(qdev->workqueue,
+ &qdev->mpi_port_cfg_work, 3*HZ);
+
+ if (!netif_running(qdev->ndev)) {
+ ndev->mtu = new_mtu;
+ return 0;
+ }
+
ndev->mtu = new_mtu;
- return 0;
+ status = ql_change_rx_buffers(qdev);
+ if (status) {
+ QPRINTK(qdev, IFUP, ERR,
+ "Changing MTU failed.\n");
+ }
+
+ return status;
}
static struct net_device_stats *qlge_get_stats(struct net_device
*ndev)
{
- struct ql_adapter *qdev = netdev_priv(ndev);
- return &qdev->stats;
+ return &ndev->stats;
}
static void qlge_set_multicast_list(struct net_device *ndev)
@@ -3868,8 +4060,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
struct net_device *ndev, int cards_found)
{
struct ql_adapter *qdev = netdev_priv(ndev);
- int pos, err = 0;
- u16 val16;
+ int err = 0;
memset((void *)qdev, 0, sizeof(*qdev));
err = pci_enable_device(pdev);
@@ -3881,18 +4072,12 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
qdev->ndev = ndev;
qdev->pdev = pdev;
pci_set_drvdata(pdev, ndev);
- pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
- if (pos <= 0) {
- dev_err(&pdev->dev, PFX "Cannot find PCI Express capability, "
- "aborting.\n");
- return pos;
- } else {
- pci_read_config_word(pdev, pos + PCI_EXP_DEVCTL, &val16);
- val16 &= ~PCI_EXP_DEVCTL_NOSNOOP_EN;
- val16 |= (PCI_EXP_DEVCTL_CERE |
- PCI_EXP_DEVCTL_NFERE |
- PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
- pci_write_config_word(pdev, pos + PCI_EXP_DEVCTL, val16);
+
+ /* Set PCIe read request size */
+ err = pcie_set_readrq(pdev, 4096);
+ if (err) {
+ dev_err(&pdev->dev, "Set readrq failed.\n");
+ goto err_out;
}
err = pci_request_regions(pdev, DRV_NAME);
@@ -4165,6 +4350,7 @@ static int qlge_suspend(struct pci_dev *pdev, pm_message_t state)
return err;
}
+ ql_wol(qdev);
err = pci_save_state(pdev);
if (err)
return err;
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c
index 99e58e3f8e22..80b68539c5aa 100644
--- a/drivers/net/qlge/qlge_mpi.c
+++ b/drivers/net/qlge/qlge_mpi.c
@@ -1,25 +1,5 @@
#include "qlge.h"
-static void ql_display_mb_sts(struct ql_adapter *qdev,
- struct mbox_params *mbcp)
-{
- int i;
- static char *err_sts[] = {
- "Command Complete",
- "Command Not Supported",
- "Host Interface Error",
- "Checksum Error",
- "Unused Completion Status",
- "Test Failed",
- "Command Parameter Error"};
-
- QPRINTK(qdev, DRV, DEBUG, "%s.\n",
- err_sts[mbcp->mbox_out[0] & 0x0000000f]);
- for (i = 0; i < mbcp->out_count; i++)
- QPRINTK(qdev, DRV, DEBUG, "mbox_out[%d] = 0x%.08x.\n",
- i, mbcp->mbox_out[i]);
-}
-
int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data)
{
int status;
@@ -317,6 +297,7 @@ static void ql_init_fw_done(struct ql_adapter *qdev, struct mbox_params *mbcp)
} else {
QPRINTK(qdev, DRV, ERR, "Firmware Revision = 0x%.08x.\n",
mbcp->mbox_out[1]);
+ qdev->fw_rev_id = mbcp->mbox_out[1];
status = ql_cam_route_initialize(qdev);
if (status)
QPRINTK(qdev, IFUP, ERR,
@@ -446,6 +427,9 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp)
ql_aen_lost(qdev, mbcp);
break;
+ case AEN_DCBX_CHG:
+ /* Need to support AEN 8110 */
+ break;
default:
QPRINTK(qdev, DRV, ERR,
"Unsupported AE %.08x.\n", mbcp->mbox_out[0]);
@@ -536,7 +520,6 @@ static int ql_mailbox_command(struct ql_adapter *qdev, struct mbox_params *mbcp)
MB_CMD_STS_GOOD) &&
((mbcp->mbox_out[0] & 0x0000f000) !=
MB_CMD_STS_INTRMDT)) {
- ql_display_mb_sts(qdev, mbcp);
status = -EIO;
}
end:
@@ -654,7 +637,7 @@ int ql_mb_idc_ack(struct ql_adapter *qdev)
* for the current port.
* Most likely will block.
*/
-static int ql_mb_set_port_cfg(struct ql_adapter *qdev)
+int ql_mb_set_port_cfg(struct ql_adapter *qdev)
{
struct mbox_params mbc;
struct mbox_params *mbcp = &mbc;
@@ -689,7 +672,7 @@ static int ql_mb_set_port_cfg(struct ql_adapter *qdev)
* for the current port.
* Most likely will block.
*/
-static int ql_mb_get_port_cfg(struct ql_adapter *qdev)
+int ql_mb_get_port_cfg(struct ql_adapter *qdev)
{
struct mbox_params mbc;
struct mbox_params *mbcp = &mbc;
@@ -719,6 +702,76 @@ static int ql_mb_get_port_cfg(struct ql_adapter *qdev)
return status;
}
+int ql_mb_wol_mode(struct ql_adapter *qdev, u32 wol)
+{
+ struct mbox_params mbc;
+ struct mbox_params *mbcp = &mbc;
+ int status;
+
+ memset(mbcp, 0, sizeof(struct mbox_params));
+
+ mbcp->in_count = 2;
+ mbcp->out_count = 1;
+
+ mbcp->mbox_in[0] = MB_CMD_SET_WOL_MODE;
+ mbcp->mbox_in[1] = wol;
+
+
+ status = ql_mailbox_command(qdev, mbcp);
+ if (status)
+ return status;
+
+ if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
+ QPRINTK(qdev, DRV, ERR,
+ "Failed to set WOL mode.\n");
+ status = -EIO;
+ }
+ return status;
+}
+
+int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol)
+{
+ struct mbox_params mbc;
+ struct mbox_params *mbcp = &mbc;
+ int status;
+ u8 *addr = qdev->ndev->dev_addr;
+
+ memset(mbcp, 0, sizeof(struct mbox_params));
+
+ mbcp->in_count = 8;
+ mbcp->out_count = 1;
+
+ mbcp->mbox_in[0] = MB_CMD_SET_WOL_MAGIC;
+ if (enable_wol) {
+ mbcp->mbox_in[1] = (u32)addr[0];
+ mbcp->mbox_in[2] = (u32)addr[1];
+ mbcp->mbox_in[3] = (u32)addr[2];
+ mbcp->mbox_in[4] = (u32)addr[3];
+ mbcp->mbox_in[5] = (u32)addr[4];
+ mbcp->mbox_in[6] = (u32)addr[5];
+ mbcp->mbox_in[7] = 0;
+ } else {
+ mbcp->mbox_in[1] = 0;
+ mbcp->mbox_in[2] = 1;
+ mbcp->mbox_in[3] = 1;
+ mbcp->mbox_in[4] = 1;
+ mbcp->mbox_in[5] = 1;
+ mbcp->mbox_in[6] = 1;
+ mbcp->mbox_in[7] = 0;
+ }
+
+ status = ql_mailbox_command(qdev, mbcp);
+ if (status)
+ return status;
+
+ if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
+ QPRINTK(qdev, DRV, ERR,
+ "Failed to set WOL mode.\n");
+ status = -EIO;
+ }
+ return status;
+}
+
/* IDC - Inter Device Communication...
* Some firmware commands require consent of adjacent FCOE
* function. This function waits for the OK, or a
@@ -768,6 +821,61 @@ static int ql_idc_wait(struct ql_adapter *qdev)
return status;
}
+int ql_mb_set_led_cfg(struct ql_adapter *qdev, u32 led_config)
+{
+ struct mbox_params mbc;
+ struct mbox_params *mbcp = &mbc;
+ int status;
+
+ memset(mbcp, 0, sizeof(struct mbox_params));
+
+ mbcp->in_count = 2;
+ mbcp->out_count = 1;
+
+ mbcp->mbox_in[0] = MB_CMD_SET_LED_CFG;
+ mbcp->mbox_in[1] = led_config;
+
+
+ status = ql_mailbox_command(qdev, mbcp);
+ if (status)
+ return status;
+
+ if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
+ QPRINTK(qdev, DRV, ERR,
+ "Failed to set LED Configuration.\n");
+ status = -EIO;
+ }
+
+ return status;
+}
+
+int ql_mb_get_led_cfg(struct ql_adapter *qdev)
+{
+ struct mbox_params mbc;
+ struct mbox_params *mbcp = &mbc;
+ int status;
+
+ memset(mbcp, 0, sizeof(struct mbox_params));
+
+ mbcp->in_count = 1;
+ mbcp->out_count = 2;
+
+ mbcp->mbox_in[0] = MB_CMD_GET_LED_CFG;
+
+ status = ql_mailbox_command(qdev, mbcp);
+ if (status)
+ return status;
+
+ if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
+ QPRINTK(qdev, DRV, ERR,
+ "Failed to get LED Configuration.\n");
+ status = -EIO;
+ } else
+ qdev->led_config = mbcp->mbox_out[1];
+
+ return status;
+}
+
int ql_mb_set_mgmnt_traffic_ctl(struct ql_adapter *qdev, u32 control)
{
struct mbox_params mbc;
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 83c47d95c3aa..1f7946c7d4e8 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -1029,7 +1029,10 @@ static void rtl8169_vlan_rx_register(struct net_device *dev,
spin_lock_irqsave(&tp->lock, flags);
tp->vlgrp = grp;
- if (tp->vlgrp)
+ /*
+ * Do not disable RxVlan on 8110SCd.
+ */
+ if (tp->vlgrp || (tp->mac_version == RTL_GIGA_MAC_VER_05))
tp->cp_cmd |= RxVlan;
else
tp->cp_cmd &= ~RxVlan;
@@ -3197,6 +3200,14 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
rtl8169_init_phy(dev, tp);
+
+ /*
+ * Pretend we are using VLANs; This bypasses a nasty bug where
+ * Interrupts stop flowing on high load on 8110SCd controllers.
+ */
+ if (tp->mac_version == RTL_GIGA_MAC_VER_05)
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | RxVlan);
+
device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL);
out:
@@ -4432,13 +4443,12 @@ static inline bool rtl8169_try_rx_copy(struct sk_buff **sk_buff,
if (pkt_size >= rx_copybreak)
goto out;
- skb = netdev_alloc_skb(tp->dev, pkt_size + NET_IP_ALIGN);
+ skb = netdev_alloc_skb_ip_align(tp->dev, pkt_size);
if (!skb)
goto out;
pci_dma_sync_single_for_cpu(tp->pci_dev, addr, pkt_size,
PCI_DMA_FROMDEVICE);
- skb_reserve(skb, NET_IP_ALIGN);
skb_copy_from_linear_data(*sk_buff, skb->data, pkt_size);
*sk_buff = skb;
done = true;
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index 508551f1b3fc..7269a875326e 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -1476,7 +1476,6 @@ static void sbmac_channel_start(struct sbmac_softc *s)
V_MAC_TX_RL_THRSH(4) |
V_MAC_RX_PL_THRSH(4) |
V_MAC_RX_RD_THRSH(4) | /* Must be '4' */
- V_MAC_RX_PL_THRSH(4) |
V_MAC_RX_RL_THRSH(8) |
0;
diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c
index 8d6030022d14..b7e0eb40a8bd 100644
--- a/drivers/net/sc92031.c
+++ b/drivers/net/sc92031.c
@@ -793,7 +793,7 @@ static void _sc92031_rx_tasklet(struct net_device *dev)
rx_len -= rx_size_align + 4;
- skb = netdev_alloc_skb(dev, pkt_size + NET_IP_ALIGN);
+ skb = netdev_alloc_skb_ip_align(dev, pkt_size);
if (unlikely(!skb)) {
if (printk_ratelimit())
printk(KERN_ERR "%s: Couldn't allocate a skb_buff for a packet of size %u\n",
@@ -801,8 +801,6 @@ static void _sc92031_rx_tasklet(struct net_device *dev)
goto next;
}
- skb_reserve(skb, NET_IP_ALIGN);
-
if ((rx_ring_offset + pkt_size) > RX_BUF_LEN) {
memcpy(skb_put(skb, RX_BUF_LEN - rx_ring_offset),
rx_ring + rx_ring_offset, RX_BUF_LEN - rx_ring_offset);
diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile
index b89f9be3cb13..7b52fe10d38f 100644
--- a/drivers/net/sfc/Makefile
+++ b/drivers/net/sfc/Makefile
@@ -1,6 +1,6 @@
sfc-y += efx.o falcon.o tx.o rx.o falcon_gmac.o \
- falcon_xmac.o selftest.o ethtool.o xfp_phy.o \
- mdio_10g.o tenxpress.o boards.o sfe4001.o
+ falcon_xmac.o selftest.o ethtool.o qt202x_phy.o \
+ mdio_10g.o tenxpress.o falcon_boards.o
sfc-$(CONFIG_SFC_MTD) += mtd.o
obj-$(CONFIG_SFC) += sfc.o
diff --git a/drivers/net/sfc/bitfield.h b/drivers/net/sfc/bitfield.h
index d54d84c267b9..6ad909bba957 100644
--- a/drivers/net/sfc/bitfield.h
+++ b/drivers/net/sfc/bitfield.h
@@ -520,19 +520,6 @@ typedef union efx_oword {
#define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD32
#endif
-#define EFX_SET_OWORD_FIELD_VER(efx, oword, field, value) do { \
- if (falcon_rev(efx) >= FALCON_REV_B0) { \
- EFX_SET_OWORD_FIELD((oword), field##_B0, (value)); \
- } else { \
- EFX_SET_OWORD_FIELD((oword), field##_A1, (value)); \
- } \
-} while (0)
-
-#define EFX_QWORD_FIELD_VER(efx, qword, field) \
- (falcon_rev(efx) >= FALCON_REV_B0 ? \
- EFX_QWORD_FIELD((qword), field##_B0) : \
- EFX_QWORD_FIELD((qword), field##_A1))
-
/* Used to avoid compiler warnings about shift range exceeding width
* of the data types when dma_addr_t is only 32 bits wide.
*/
diff --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c
deleted file mode 100644
index 4a4c74c891b7..000000000000
--- a/drivers/net/sfc/boards.c
+++ /dev/null
@@ -1,328 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2007-2008 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 "net_driver.h"
-#include "phy.h"
-#include "boards.h"
-#include "efx.h"
-#include "workarounds.h"
-
-/* Macros for unpacking the board revision */
-/* The revision info is in host byte order. */
-#define BOARD_TYPE(_rev) (_rev >> 8)
-#define BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf)
-#define BOARD_MINOR(_rev) (_rev & 0xf)
-
-/* Blink support. If the PHY has no auto-blink mode so we hang it off a timer */
-#define BLINK_INTERVAL (HZ/2)
-
-static void blink_led_timer(unsigned long context)
-{
- struct efx_nic *efx = (struct efx_nic *)context;
- struct efx_blinker *bl = &efx->board_info.blinker;
- efx->board_info.set_id_led(efx, bl->state);
- bl->state = !bl->state;
- if (bl->resubmit)
- mod_timer(&bl->timer, jiffies + BLINK_INTERVAL);
-}
-
-static void board_blink(struct efx_nic *efx, bool blink)
-{
- struct efx_blinker *blinker = &efx->board_info.blinker;
-
- /* The rtnl mutex serialises all ethtool ioctls, so
- * nothing special needs doing here. */
- if (blink) {
- blinker->resubmit = true;
- blinker->state = false;
- setup_timer(&blinker->timer, blink_led_timer,
- (unsigned long)efx);
- mod_timer(&blinker->timer, jiffies + BLINK_INTERVAL);
- } else {
- blinker->resubmit = false;
- if (blinker->timer.function)
- del_timer_sync(&blinker->timer);
- efx->board_info.init_leds(efx);
- }
-}
-
-/*****************************************************************************
- * Support for LM87 sensor chip used on several boards
- */
-#define LM87_REG_ALARMS1 0x41
-#define LM87_REG_ALARMS2 0x42
-#define LM87_IN_LIMITS(nr, _min, _max) \
- 0x2B + (nr) * 2, _max, 0x2C + (nr) * 2, _min
-#define LM87_AIN_LIMITS(nr, _min, _max) \
- 0x3B + (nr), _max, 0x1A + (nr), _min
-#define LM87_TEMP_INT_LIMITS(_min, _max) \
- 0x39, _max, 0x3A, _min
-#define LM87_TEMP_EXT1_LIMITS(_min, _max) \
- 0x37, _max, 0x38, _min
-
-#define LM87_ALARM_TEMP_INT 0x10
-#define LM87_ALARM_TEMP_EXT1 0x20
-
-#if defined(CONFIG_SENSORS_LM87) || defined(CONFIG_SENSORS_LM87_MODULE)
-
-static int efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info,
- const u8 *reg_values)
-{
- struct i2c_client *client = i2c_new_device(&efx->i2c_adap, info);
- int rc;
-
- if (!client)
- return -EIO;
-
- while (*reg_values) {
- u8 reg = *reg_values++;
- u8 value = *reg_values++;
- rc = i2c_smbus_write_byte_data(client, reg, value);
- if (rc)
- goto err;
- }
-
- efx->board_info.hwmon_client = client;
- return 0;
-
-err:
- i2c_unregister_device(client);
- return rc;
-}
-
-static void efx_fini_lm87(struct efx_nic *efx)
-{
- i2c_unregister_device(efx->board_info.hwmon_client);
-}
-
-static int efx_check_lm87(struct efx_nic *efx, unsigned mask)
-{
- struct i2c_client *client = efx->board_info.hwmon_client;
- s32 alarms1, alarms2;
-
- /* If link is up then do not monitor temperature */
- if (EFX_WORKAROUND_7884(efx) && efx->link_up)
- return 0;
-
- alarms1 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1);
- alarms2 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2);
- if (alarms1 < 0)
- return alarms1;
- if (alarms2 < 0)
- return alarms2;
- alarms1 &= mask;
- alarms2 &= mask >> 8;
- if (alarms1 || alarms2) {
- EFX_ERR(efx,
- "LM87 detected a hardware failure (status %02x:%02x)"
- "%s%s\n",
- alarms1, alarms2,
- (alarms1 & LM87_ALARM_TEMP_INT) ? " INTERNAL" : "",
- (alarms1 & LM87_ALARM_TEMP_EXT1) ? " EXTERNAL" : "");
- return -ERANGE;
- }
-
- return 0;
-}
-
-#else /* !CONFIG_SENSORS_LM87 */
-
-static inline int
-efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info,
- const u8 *reg_values)
-{
- return 0;
-}
-static inline void efx_fini_lm87(struct efx_nic *efx)
-{
-}
-static inline int efx_check_lm87(struct efx_nic *efx, unsigned mask)
-{
- return 0;
-}
-
-#endif /* CONFIG_SENSORS_LM87 */
-
-/*****************************************************************************
- * Support for the SFE4002
- *
- */
-static u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */
-
-static const u8 sfe4002_lm87_regs[] = {
- LM87_IN_LIMITS(0, 0x83, 0x91), /* 2.5V: 1.8V +/- 5% */
- LM87_IN_LIMITS(1, 0x51, 0x5a), /* Vccp1: 1.2V +/- 5% */
- LM87_IN_LIMITS(2, 0xb6, 0xca), /* 3.3V: 3.3V +/- 5% */
- LM87_IN_LIMITS(3, 0xb0, 0xc9), /* 5V: 4.6-5.2V */
- LM87_IN_LIMITS(4, 0xb0, 0xe0), /* 12V: 11-14V */
- LM87_IN_LIMITS(5, 0x44, 0x4b), /* Vccp2: 1.0V +/- 5% */
- LM87_AIN_LIMITS(0, 0xa0, 0xb2), /* AIN1: 1.66V +/- 5% */
- LM87_AIN_LIMITS(1, 0x91, 0xa1), /* AIN2: 1.5V +/- 5% */
- LM87_TEMP_INT_LIMITS(10, 60), /* board */
- LM87_TEMP_EXT1_LIMITS(10, 70), /* Falcon */
- 0
-};
-
-static struct i2c_board_info sfe4002_hwmon_info = {
- I2C_BOARD_INFO("lm87", 0x2e),
- .platform_data = &sfe4002_lm87_channel,
-};
-
-/****************************************************************************/
-/* LED allocations. Note that on rev A0 boards the schematic and the reality
- * differ: red and green are swapped. Below is the fixed (A1) layout (there
- * are only 3 A0 boards in existence, so no real reason to make this
- * conditional).
- */
-#define SFE4002_FAULT_LED (2) /* Red */
-#define SFE4002_RX_LED (0) /* Green */
-#define SFE4002_TX_LED (1) /* Amber */
-
-static void sfe4002_init_leds(struct efx_nic *efx)
-{
- /* Set the TX and RX LEDs to reflect status and activity, and the
- * fault LED off */
- xfp_set_led(efx, SFE4002_TX_LED,
- QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT);
- xfp_set_led(efx, SFE4002_RX_LED,
- QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT);
- xfp_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF);
-}
-
-static void sfe4002_set_id_led(struct efx_nic *efx, bool state)
-{
- xfp_set_led(efx, SFE4002_FAULT_LED, state ? QUAKE_LED_ON :
- QUAKE_LED_OFF);
-}
-
-static int sfe4002_check_hw(struct efx_nic *efx)
-{
- /* A0 board rev. 4002s report a temperature fault the whole time
- * (bad sensor) so we mask it out. */
- unsigned alarm_mask =
- (efx->board_info.major == 0 && efx->board_info.minor == 0) ?
- ~LM87_ALARM_TEMP_EXT1 : ~0;
-
- return efx_check_lm87(efx, alarm_mask);
-}
-
-static int sfe4002_init(struct efx_nic *efx)
-{
- int rc = efx_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs);
- if (rc)
- return rc;
- efx->board_info.monitor = sfe4002_check_hw;
- efx->board_info.init_leds = sfe4002_init_leds;
- efx->board_info.set_id_led = sfe4002_set_id_led;
- efx->board_info.blink = board_blink;
- efx->board_info.fini = efx_fini_lm87;
- return 0;
-}
-
-/*****************************************************************************
- * Support for the SFN4112F
- *
- */
-static u8 sfn4112f_lm87_channel = 0x03; /* use AIN not FAN inputs */
-
-static const u8 sfn4112f_lm87_regs[] = {
- LM87_IN_LIMITS(0, 0x83, 0x91), /* 2.5V: 1.8V +/- 5% */
- LM87_IN_LIMITS(1, 0x51, 0x5a), /* Vccp1: 1.2V +/- 5% */
- LM87_IN_LIMITS(2, 0xb6, 0xca), /* 3.3V: 3.3V +/- 5% */
- LM87_IN_LIMITS(4, 0xb0, 0xe0), /* 12V: 11-14V */
- LM87_IN_LIMITS(5, 0x44, 0x4b), /* Vccp2: 1.0V +/- 5% */
- LM87_AIN_LIMITS(1, 0x91, 0xa1), /* AIN2: 1.5V +/- 5% */
- LM87_TEMP_INT_LIMITS(10, 60), /* board */
- LM87_TEMP_EXT1_LIMITS(10, 70), /* Falcon */
- 0
-};
-
-static struct i2c_board_info sfn4112f_hwmon_info = {
- I2C_BOARD_INFO("lm87", 0x2e),
- .platform_data = &sfn4112f_lm87_channel,
-};
-
-#define SFN4112F_ACT_LED 0
-#define SFN4112F_LINK_LED 1
-
-static void sfn4112f_init_leds(struct efx_nic *efx)
-{
- xfp_set_led(efx, SFN4112F_ACT_LED,
- QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACT);
- xfp_set_led(efx, SFN4112F_LINK_LED,
- QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT);
-}
-
-static void sfn4112f_set_id_led(struct efx_nic *efx, bool state)
-{
- xfp_set_led(efx, SFN4112F_LINK_LED,
- state ? QUAKE_LED_ON : QUAKE_LED_OFF);
-}
-
-static int sfn4112f_check_hw(struct efx_nic *efx)
-{
- /* Mask out unused sensors */
- return efx_check_lm87(efx, ~0x48);
-}
-
-static int sfn4112f_init(struct efx_nic *efx)
-{
- int rc = efx_init_lm87(efx, &sfn4112f_hwmon_info, sfn4112f_lm87_regs);
- if (rc)
- return rc;
- efx->board_info.monitor = sfn4112f_check_hw;
- efx->board_info.init_leds = sfn4112f_init_leds;
- efx->board_info.set_id_led = sfn4112f_set_id_led;
- efx->board_info.blink = board_blink;
- efx->board_info.fini = efx_fini_lm87;
- return 0;
-}
-
-/* This will get expanded as board-specific details get moved out of the
- * PHY drivers. */
-struct efx_board_data {
- enum efx_board_type type;
- const char *ref_model;
- const char *gen_type;
- int (*init) (struct efx_nic *nic);
-};
-
-
-static struct efx_board_data board_data[] = {
- { EFX_BOARD_SFE4001, "SFE4001", "10GBASE-T adapter", sfe4001_init },
- { EFX_BOARD_SFE4002, "SFE4002", "XFP adapter", sfe4002_init },
- { EFX_BOARD_SFN4111T, "SFN4111T", "100/1000/10GBASE-T adapter",
- sfn4111t_init },
- { EFX_BOARD_SFN4112F, "SFN4112F", "SFP+ adapter",
- sfn4112f_init },
-};
-
-void efx_set_board_info(struct efx_nic *efx, u16 revision_info)
-{
- struct efx_board_data *data = NULL;
- int i;
-
- efx->board_info.type = BOARD_TYPE(revision_info);
- efx->board_info.major = BOARD_MAJOR(revision_info);
- efx->board_info.minor = BOARD_MINOR(revision_info);
-
- for (i = 0; i < ARRAY_SIZE(board_data); i++)
- if (board_data[i].type == efx->board_info.type)
- data = &board_data[i];
-
- if (data) {
- EFX_INFO(efx, "board is %s rev %c%d\n",
- (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC)
- ? data->ref_model : data->gen_type,
- 'A' + efx->board_info.major, efx->board_info.minor);
- efx->board_info.init = data->init;
- } else {
- EFX_ERR(efx, "unknown board type %d\n", efx->board_info.type);
- }
-}
diff --git a/drivers/net/sfc/boards.h b/drivers/net/sfc/boards.h
deleted file mode 100644
index 44942de0e080..000000000000
--- a/drivers/net/sfc/boards.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2007-2008 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_BOARDS_H
-#define EFX_BOARDS_H
-
-/* Board IDs (must fit in 8 bits) */
-enum efx_board_type {
- EFX_BOARD_SFE4001 = 1,
- EFX_BOARD_SFE4002 = 2,
- EFX_BOARD_SFN4111T = 0x51,
- EFX_BOARD_SFN4112F = 0x52,
-};
-
-extern void efx_set_board_info(struct efx_nic *efx, u16 revision_info);
-
-/* SFE4001 (10GBASE-T) */
-extern int sfe4001_init(struct efx_nic *efx);
-/* SFN4111T (100/1000/10GBASE-T) */
-extern int sfn4111t_init(struct efx_nic *efx);
-
-#endif
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index cc4b2f99989d..0d0243b7ac34 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -228,26 +228,20 @@ static int efx_poll(struct napi_struct *napi, int budget)
if (channel->used_flags & EFX_USED_BY_RX &&
efx->irq_rx_adaptive &&
unlikely(++channel->irq_count == 1000)) {
- unsigned old_irq_moderation = channel->irq_moderation;
-
if (unlikely(channel->irq_mod_score <
irq_adapt_low_thresh)) {
- channel->irq_moderation =
- max_t(int,
- channel->irq_moderation -
- FALCON_IRQ_MOD_RESOLUTION,
- FALCON_IRQ_MOD_RESOLUTION);
+ if (channel->irq_moderation > 1) {
+ channel->irq_moderation -= 1;
+ falcon_set_int_moderation(channel);
+ }
} else if (unlikely(channel->irq_mod_score >
irq_adapt_high_thresh)) {
- channel->irq_moderation =
- min(channel->irq_moderation +
- FALCON_IRQ_MOD_RESOLUTION,
- efx->irq_rx_moderation);
+ if (channel->irq_moderation <
+ efx->irq_rx_moderation) {
+ channel->irq_moderation += 1;
+ falcon_set_int_moderation(channel);
+ }
}
-
- if (channel->irq_moderation != old_irq_moderation)
- falcon_set_int_moderation(channel);
-
channel->irq_count = 0;
channel->irq_mod_score = 0;
}
@@ -290,7 +284,7 @@ void efx_process_channel_now(struct efx_channel *channel)
napi_disable(&channel->napi_str);
/* Poll the channel */
- efx_process_channel(channel, efx->type->evq_size);
+ efx_process_channel(channel, EFX_EVQ_SIZE);
/* Ack the eventq. This may cause an interrupt to be generated
* when they are reenabled */
@@ -824,9 +818,8 @@ static int efx_init_io(struct efx_nic *efx)
goto fail2;
}
- efx->membase_phys = pci_resource_start(efx->pci_dev,
- efx->type->mem_bar);
- rc = pci_request_region(pci_dev, efx->type->mem_bar, "sfc");
+ efx->membase_phys = pci_resource_start(efx->pci_dev, EFX_MEM_BAR);
+ rc = pci_request_region(pci_dev, EFX_MEM_BAR, "sfc");
if (rc) {
EFX_ERR(efx, "request for memory BAR failed\n");
rc = -EIO;
@@ -835,21 +828,20 @@ static int efx_init_io(struct efx_nic *efx)
efx->membase = ioremap_nocache(efx->membase_phys,
efx->type->mem_map_size);
if (!efx->membase) {
- EFX_ERR(efx, "could not map memory BAR %d at %llx+%x\n",
- efx->type->mem_bar,
+ EFX_ERR(efx, "could not map memory BAR at %llx+%x\n",
(unsigned long long)efx->membase_phys,
efx->type->mem_map_size);
rc = -ENOMEM;
goto fail4;
}
- EFX_LOG(efx, "memory BAR %u at %llx+%x (virtual %p)\n",
- efx->type->mem_bar, (unsigned long long)efx->membase_phys,
+ EFX_LOG(efx, "memory BAR at %llx+%x (virtual %p)\n",
+ (unsigned long long)efx->membase_phys,
efx->type->mem_map_size, efx->membase);
return 0;
fail4:
- pci_release_region(efx->pci_dev, efx->type->mem_bar);
+ pci_release_region(efx->pci_dev, EFX_MEM_BAR);
fail3:
efx->membase_phys = 0;
fail2:
@@ -868,7 +860,7 @@ static void efx_fini_io(struct efx_nic *efx)
}
if (efx->membase_phys) {
- pci_release_region(efx->pci_dev, efx->type->mem_bar);
+ pci_release_region(efx->pci_dev, EFX_MEM_BAR);
efx->membase_phys = 0;
}
@@ -1220,22 +1212,33 @@ void efx_flush_queues(struct efx_nic *efx)
*
**************************************************************************/
+static unsigned irq_mod_ticks(int usecs, int resolution)
+{
+ if (usecs <= 0)
+ return 0; /* cannot receive interrupts ahead of time :-) */
+ if (usecs < resolution)
+ return 1; /* never round down to 0 */
+ return usecs / resolution;
+}
+
/* Set interrupt moderation parameters */
void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs,
bool rx_adaptive)
{
struct efx_tx_queue *tx_queue;
struct efx_rx_queue *rx_queue;
+ unsigned tx_ticks = irq_mod_ticks(tx_usecs, FALCON_IRQ_MOD_RESOLUTION);
+ unsigned rx_ticks = irq_mod_ticks(rx_usecs, FALCON_IRQ_MOD_RESOLUTION);
EFX_ASSERT_RESET_SERIALISED(efx);
efx_for_each_tx_queue(tx_queue, efx)
- tx_queue->channel->irq_moderation = tx_usecs;
+ tx_queue->channel->irq_moderation = tx_ticks;
efx->irq_rx_adaptive = rx_adaptive;
- efx->irq_rx_moderation = rx_usecs;
+ efx->irq_rx_moderation = rx_ticks;
efx_for_each_rx_queue(rx_queue, efx)
- rx_queue->channel->irq_moderation = rx_usecs;
+ rx_queue->channel->irq_moderation = rx_ticks;
}
/**************************************************************************
@@ -1981,17 +1984,9 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
efx->type = type;
- /* Sanity-check NIC type */
- EFX_BUG_ON_PARANOID(efx->type->txd_ring_mask &
- (efx->type->txd_ring_mask + 1));
- EFX_BUG_ON_PARANOID(efx->type->rxd_ring_mask &
- (efx->type->rxd_ring_mask + 1));
- EFX_BUG_ON_PARANOID(efx->type->evq_size &
- (efx->type->evq_size - 1));
/* As close as we can get to guaranteeing that we don't overflow */
- EFX_BUG_ON_PARANOID(efx->type->evq_size <
- (efx->type->txd_ring_mask + 1 +
- efx->type->rxd_ring_mask + 1));
+ 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! */
@@ -2027,18 +2022,12 @@ static void efx_fini_struct(struct efx_nic *efx)
*/
static void efx_pci_remove_main(struct efx_nic *efx)
{
- EFX_ASSERT_RESET_SERIALISED(efx);
-
- /* Skip everything if we never obtained a valid membase */
- if (!efx->membase)
- return;
-
+ falcon_fini_interrupt(efx);
efx_fini_channels(efx);
efx_fini_port(efx);
/* Shutdown the board, then the NIC and board state */
efx->board_info.fini(efx);
- falcon_fini_interrupt(efx);
efx_fini_napi(efx);
efx_remove_all(efx);
@@ -2063,9 +2052,6 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
/* Allow any queued efx_resets() to complete */
rtnl_unlock();
- if (efx->membase == NULL)
- goto out;
-
efx_unregister_netdev(efx);
efx_mtd_remove(efx);
@@ -2078,7 +2064,6 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
efx_pci_remove_main(efx);
-out:
efx_fini_io(efx);
EFX_LOG(efx, "shutdown successful\n");
@@ -2224,13 +2209,15 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
* MAC stats succeeds. */
efx->state = STATE_RUNNING;
- efx_mtd_probe(efx); /* allowed to fail */
-
rc = efx_register_netdev(efx);
if (rc)
goto fail5;
EFX_LOG(efx, "initialisation successful\n");
+
+ rtnl_lock();
+ efx_mtd_probe(efx); /* allowed to fail */
+ rtnl_unlock();
return 0;
fail5:
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h
index aecaf62f4929..179e0e3b0ec6 100644
--- a/drivers/net/sfc/efx.h
+++ b/drivers/net/sfc/efx.h
@@ -19,22 +19,31 @@
#define FALCON_A_S_DEVID 0x6703
#define FALCON_B_P_DEVID 0x0710
+/* Solarstorm controllers use BAR 0 for I/O space and BAR 2(&3) for memory */
+#define EFX_MEM_BAR 2
+
/* TX */
extern netdev_tx_t efx_xmit(struct efx_nic *efx,
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_nic *efx);
extern void efx_wake_queue(struct efx_nic *efx);
+#define EFX_TXQ_SIZE 1024
+#define EFX_TXQ_MASK (EFX_TXQ_SIZE - 1)
/* RX */
-extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
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, int delay);
+#define EFX_RXQ_SIZE 1024
+#define EFX_RXQ_MASK (EFX_RXQ_SIZE - 1)
/* Channels */
extern void efx_process_channel_now(struct efx_channel *channel);
extern void efx_flush_queues(struct efx_nic *efx);
+#define EFX_EVQ_SIZE 4096
+#define EFX_EVQ_MASK (EFX_EVQ_SIZE - 1)
/* Ports */
extern void efx_stats_disable(struct efx_nic *efx);
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 45018f283ffa..a313b61c8ff4 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -618,6 +618,9 @@ static int efx_ethtool_get_coalesce(struct net_device *net_dev,
coalesce->use_adaptive_rx_coalesce = efx->irq_rx_adaptive;
coalesce->rx_coalesce_usecs_irq = efx->irq_rx_moderation;
+ coalesce->tx_coalesce_usecs_irq *= FALCON_IRQ_MOD_RESOLUTION;
+ coalesce->rx_coalesce_usecs_irq *= FALCON_IRQ_MOD_RESOLUTION;
+
return 0;
}
@@ -656,11 +659,6 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev,
}
efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive);
-
- /* Reset channel to pick up new moderation value. Note that
- * this may change the value of the irq_moderation field
- * (e.g. to allow for hardware timer granularity).
- */
efx_for_each_channel(channel, efx)
falcon_set_int_moderation(channel);
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index c049364aec46..8776432f683c 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -22,11 +22,10 @@
#include "mac.h"
#include "spi.h"
#include "falcon.h"
-#include "falcon_hwdefs.h"
-#include "falcon_io.h"
+#include "regs.h"
+#include "io.h"
#include "mdio_10g.h"
#include "phy.h"
-#include "boards.h"
#include "workarounds.h"
/* Falcon hardware control.
@@ -36,19 +35,12 @@
/**
* struct falcon_nic_data - Falcon NIC state
- * @next_buffer_table: First available buffer table id
* @pci_dev2: The secondary PCI device if present
* @i2c_data: Operations and state for I2C bit-bashing algorithm
- * @int_error_count: Number of internal errors seen recently
- * @int_error_expire: Time at which error count will be expired
*/
struct falcon_nic_data {
- unsigned next_buffer_table;
struct pci_dev *pci_dev2;
struct i2c_algo_bit_data i2c_data;
-
- unsigned int_error_count;
- unsigned long int_error_expire;
};
/**************************************************************************
@@ -109,21 +101,6 @@ static int rx_xon_thresh_bytes = -1;
module_param(rx_xon_thresh_bytes, int, 0644);
MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
-/* TX descriptor ring size - min 512 max 4k */
-#define FALCON_TXD_RING_ORDER TX_DESCQ_SIZE_1K
-#define FALCON_TXD_RING_SIZE 1024
-#define FALCON_TXD_RING_MASK (FALCON_TXD_RING_SIZE - 1)
-
-/* RX descriptor ring size - min 512 max 4k */
-#define FALCON_RXD_RING_ORDER RX_DESCQ_SIZE_1K
-#define FALCON_RXD_RING_SIZE 1024
-#define FALCON_RXD_RING_MASK (FALCON_RXD_RING_SIZE - 1)
-
-/* Event queue size - max 32k */
-#define FALCON_EVQ_ORDER EVQ_SIZE_4K
-#define FALCON_EVQ_SIZE 4096
-#define FALCON_EVQ_MASK (FALCON_EVQ_SIZE - 1)
-
/* If FALCON_MAX_INT_ERRORS internal errors occur within
* FALCON_INT_ERROR_EXPIRE seconds, we consider the NIC broken and
* disable it.
@@ -143,12 +120,6 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
**************************************************************************
*/
-/* DMA address mask */
-#define FALCON_DMA_MASK DMA_BIT_MASK(46)
-
-/* TX DMA length mask (13-bit) */
-#define FALCON_TX_DMA_MASK (4096 - 1)
-
/* Size and alignment of special buffers (4KB) */
#define FALCON_BUF_SIZE 4096
@@ -164,6 +135,13 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
*
**************************************************************************/
+static inline void falcon_write_buf_tbl(struct efx_nic *efx, efx_qword_t *value,
+ unsigned int index)
+{
+ efx_sram_writeq(efx, efx->membase + efx->type->buf_tbl_base,
+ value, index);
+}
+
/* Read the current event from the event queue */
static inline efx_qword_t *falcon_event(struct efx_channel *channel,
unsigned int index)
@@ -200,9 +178,9 @@ static void falcon_setsda(void *data, int state)
struct efx_nic *efx = (struct efx_nic *)data;
efx_oword_t reg;
- falcon_read(efx, &reg, GPIO_CTL_REG_KER);
- EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, !state);
- falcon_write(efx, &reg, GPIO_CTL_REG_KER);
+ efx_reado(efx, &reg, FR_AB_GPIO_CTL);
+ EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO3_OEN, !state);
+ efx_writeo(efx, &reg, FR_AB_GPIO_CTL);
}
static void falcon_setscl(void *data, int state)
@@ -210,9 +188,9 @@ static void falcon_setscl(void *data, int state)
struct efx_nic *efx = (struct efx_nic *)data;
efx_oword_t reg;
- falcon_read(efx, &reg, GPIO_CTL_REG_KER);
- EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, !state);
- falcon_write(efx, &reg, GPIO_CTL_REG_KER);
+ efx_reado(efx, &reg, FR_AB_GPIO_CTL);
+ EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO0_OEN, !state);
+ efx_writeo(efx, &reg, FR_AB_GPIO_CTL);
}
static int falcon_getsda(void *data)
@@ -220,8 +198,8 @@ static int falcon_getsda(void *data)
struct efx_nic *efx = (struct efx_nic *)data;
efx_oword_t reg;
- falcon_read(efx, &reg, GPIO_CTL_REG_KER);
- return EFX_OWORD_FIELD(reg, GPIO3_IN);
+ efx_reado(efx, &reg, FR_AB_GPIO_CTL);
+ return EFX_OWORD_FIELD(reg, FRF_AB_GPIO3_IN);
}
static int falcon_getscl(void *data)
@@ -229,8 +207,8 @@ static int falcon_getscl(void *data)
struct efx_nic *efx = (struct efx_nic *)data;
efx_oword_t reg;
- falcon_read(efx, &reg, GPIO_CTL_REG_KER);
- return EFX_OWORD_FIELD(reg, GPIO0_IN);
+ efx_reado(efx, &reg, FR_AB_GPIO_CTL);
+ return EFX_OWORD_FIELD(reg, FRF_AB_GPIO0_IN);
}
static struct i2c_algo_bit_data falcon_i2c_bit_operations = {
@@ -275,12 +253,11 @@ falcon_init_special_buffer(struct efx_nic *efx,
dma_addr = buffer->dma_addr + (i * 4096);
EFX_LOG(efx, "mapping special buffer %d at %llx\n",
index, (unsigned long long)dma_addr);
- EFX_POPULATE_QWORD_4(buf_desc,
- IP_DAT_BUF_SIZE, IP_DAT_BUF_SIZE_4K,
- BUF_ADR_REGION, 0,
- BUF_ADR_FBUF, (dma_addr >> 12),
- BUF_OWNER_ID_FBUF, 0);
- falcon_write_sram(efx, &buf_desc, index);
+ EFX_POPULATE_QWORD_3(buf_desc,
+ FRF_AZ_BUF_ADR_REGION, 0,
+ FRF_AZ_BUF_ADR_FBUF, dma_addr >> 12,
+ FRF_AZ_BUF_OWNER_ID_FBUF, 0);
+ falcon_write_buf_tbl(efx, &buf_desc, index);
}
}
@@ -300,11 +277,11 @@ falcon_fini_special_buffer(struct efx_nic *efx,
buffer->index, buffer->index + buffer->entries - 1);
EFX_POPULATE_OWORD_4(buf_tbl_upd,
- BUF_UPD_CMD, 0,
- BUF_CLR_CMD, 1,
- BUF_CLR_END_ID, end,
- BUF_CLR_START_ID, start);
- falcon_write(efx, &buf_tbl_upd, BUF_TBL_UPD_REG_KER);
+ FRF_AZ_BUF_UPD_CMD, 0,
+ FRF_AZ_BUF_CLR_CMD, 1,
+ FRF_AZ_BUF_CLR_END_ID, end,
+ FRF_AZ_BUF_CLR_START_ID, start);
+ efx_writeo(efx, &buf_tbl_upd, FR_AZ_BUF_TBL_UPD);
}
/*
@@ -320,8 +297,6 @@ static int falcon_alloc_special_buffer(struct efx_nic *efx,
struct efx_special_buffer *buffer,
unsigned int len)
{
- struct falcon_nic_data *nic_data = efx->nic_data;
-
len = ALIGN(len, FALCON_BUF_SIZE);
buffer->addr = pci_alloc_consistent(efx->pci_dev, len,
@@ -336,8 +311,8 @@ static int falcon_alloc_special_buffer(struct efx_nic *efx,
memset(buffer->addr, 0xff, len);
/* Select new buffer ID */
- buffer->index = nic_data->next_buffer_table;
- nic_data->next_buffer_table += buffer->entries;
+ buffer->index = efx->next_buffer_table;
+ efx->next_buffer_table += buffer->entries;
EFX_LOG(efx, "allocating special buffers %d-%d at %llx+%x "
"(virt %p phys %llx)\n", buffer->index,
@@ -415,10 +390,10 @@ static inline void falcon_notify_tx_desc(struct efx_tx_queue *tx_queue)
unsigned write_ptr;
efx_dword_t reg;
- write_ptr = tx_queue->write_count & FALCON_TXD_RING_MASK;
- EFX_POPULATE_DWORD_1(reg, TX_DESC_WPTR_DWORD, write_ptr);
- falcon_writel_page(tx_queue->efx, &reg,
- TX_DESC_UPD_REG_KER_DWORD, tx_queue->queue);
+ write_ptr = tx_queue->write_count & EFX_TXQ_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);
}
@@ -436,18 +411,17 @@ void falcon_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 & FALCON_TXD_RING_MASK;
+ write_ptr = tx_queue->write_count & EFX_TXQ_MASK;
buffer = &tx_queue->buffer[write_ptr];
txd = falcon_tx_desc(tx_queue, write_ptr);
++tx_queue->write_count;
/* Create TX descriptor ring entry */
- EFX_POPULATE_QWORD_5(*txd,
- TX_KER_PORT, 0,
- TX_KER_CONT, buffer->continuation,
- TX_KER_BYTE_CNT, buffer->len,
- TX_KER_BUF_REGION, 0,
- TX_KER_BUF_ADR, buffer->dma_addr);
+ EFX_POPULATE_QWORD_4(*txd,
+ FSF_AZ_TX_KER_CONT, buffer->continuation,
+ FSF_AZ_TX_KER_BYTE_COUNT, buffer->len,
+ FSF_AZ_TX_KER_BUF_REGION, 0,
+ FSF_AZ_TX_KER_BUF_ADDR, buffer->dma_addr);
} while (tx_queue->write_count != tx_queue->insert_count);
wmb(); /* Ensure descriptors are written before they are fetched */
@@ -458,9 +432,10 @@ void falcon_push_buffers(struct efx_tx_queue *tx_queue)
int falcon_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);
return falcon_alloc_special_buffer(efx, &tx_queue->txd,
- FALCON_TXD_RING_SIZE *
- sizeof(efx_qword_t));
+ EFX_TXQ_SIZE * sizeof(efx_qword_t));
}
void falcon_init_tx(struct efx_tx_queue *tx_queue)
@@ -475,25 +450,28 @@ void falcon_init_tx(struct efx_tx_queue *tx_queue)
/* Push TX descriptor ring to card */
EFX_POPULATE_OWORD_10(tx_desc_ptr,
- TX_DESCQ_EN, 1,
- TX_ISCSI_DDIG_EN, 0,
- TX_ISCSI_HDIG_EN, 0,
- TX_DESCQ_BUF_BASE_ID, tx_queue->txd.index,
- TX_DESCQ_EVQ_ID, tx_queue->channel->channel,
- TX_DESCQ_OWNER_ID, 0,
- TX_DESCQ_LABEL, tx_queue->queue,
- TX_DESCQ_SIZE, FALCON_TXD_RING_ORDER,
- TX_DESCQ_TYPE, 0,
- TX_NON_IP_DROP_DIS_B0, 1);
+ FRF_AZ_TX_DESCQ_EN, 1,
+ FRF_AZ_TX_ISCSI_DDIG_EN, 0,
+ FRF_AZ_TX_ISCSI_HDIG_EN, 0,
+ FRF_AZ_TX_DESCQ_BUF_BASE_ID, tx_queue->txd.index,
+ FRF_AZ_TX_DESCQ_EVQ_ID,
+ tx_queue->channel->channel,
+ FRF_AZ_TX_DESCQ_OWNER_ID, 0,
+ FRF_AZ_TX_DESCQ_LABEL, tx_queue->queue,
+ FRF_AZ_TX_DESCQ_SIZE,
+ __ffs(tx_queue->txd.entries),
+ FRF_AZ_TX_DESCQ_TYPE, 0,
+ FRF_BZ_TX_NON_IP_DROP_DIS, 1);
if (falcon_rev(efx) >= FALCON_REV_B0) {
int csum = tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM;
- EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_IP_CHKSM_DIS_B0, !csum);
- EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_TCP_CHKSM_DIS_B0, !csum);
+ EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_IP_CHKSM_DIS, !csum);
+ EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_TCP_CHKSM_DIS,
+ !csum);
}
- falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
- tx_queue->queue);
+ efx_writeo_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
+ tx_queue->queue);
if (falcon_rev(efx) < FALCON_REV_B0) {
efx_oword_t reg;
@@ -501,12 +479,12 @@ void falcon_init_tx(struct efx_tx_queue *tx_queue)
/* Only 128 bits in this register */
BUILD_BUG_ON(EFX_TX_QUEUE_COUNT >= 128);
- falcon_read(efx, &reg, TX_CHKSM_CFG_REG_KER_A1);
+ efx_reado(efx, &reg, FR_AA_TX_CHKSM_CFG);
if (tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM)
clear_bit_le(tx_queue->queue, (void *)&reg);
else
set_bit_le(tx_queue->queue, (void *)&reg);
- falcon_write(efx, &reg, TX_CHKSM_CFG_REG_KER_A1);
+ efx_writeo(efx, &reg, FR_AA_TX_CHKSM_CFG);
}
}
@@ -517,9 +495,9 @@ static void falcon_flush_tx_queue(struct efx_tx_queue *tx_queue)
/* Post a flush command */
EFX_POPULATE_OWORD_2(tx_flush_descq,
- TX_FLUSH_DESCQ_CMD, 1,
- TX_FLUSH_DESCQ, tx_queue->queue);
- falcon_write(efx, &tx_flush_descq, TX_FLUSH_DESCQ_REG_KER);
+ FRF_AZ_TX_FLUSH_DESCQ_CMD, 1,
+ FRF_AZ_TX_FLUSH_DESCQ, tx_queue->queue);
+ efx_writeo(efx, &tx_flush_descq, FR_AZ_TX_FLUSH_DESCQ);
}
void falcon_fini_tx(struct efx_tx_queue *tx_queue)
@@ -532,8 +510,8 @@ void falcon_fini_tx(struct efx_tx_queue *tx_queue)
/* Remove TX descriptor ring from card */
EFX_ZERO_OWORD(tx_desc_ptr);
- falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
- tx_queue->queue);
+ efx_writeo_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
+ tx_queue->queue);
/* Unpin TX descriptor ring */
falcon_fini_special_buffer(efx, &tx_queue->txd);
@@ -568,11 +546,11 @@ static inline void falcon_build_rx_desc(struct efx_rx_queue *rx_queue,
rxd = falcon_rx_desc(rx_queue, index);
rx_buf = efx_rx_buffer(rx_queue, index);
EFX_POPULATE_QWORD_3(*rxd,
- RX_KER_BUF_SIZE,
+ FSF_AZ_RX_KER_BUF_SIZE,
rx_buf->len -
rx_queue->efx->type->rx_buffer_padding,
- RX_KER_BUF_REGION, 0,
- RX_KER_BUF_ADR, rx_buf->dma_addr);
+ FSF_AZ_RX_KER_BUF_REGION, 0,
+ FSF_AZ_RX_KER_BUF_ADDR, rx_buf->dma_addr);
}
/* This writes to the RX_DESC_WPTR register for the specified receive
@@ -586,23 +564,24 @@ void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue)
while (rx_queue->notified_count != rx_queue->added_count) {
falcon_build_rx_desc(rx_queue,
rx_queue->notified_count &
- FALCON_RXD_RING_MASK);
+ EFX_RXQ_MASK);
++rx_queue->notified_count;
}
wmb();
- write_ptr = rx_queue->added_count & FALCON_RXD_RING_MASK;
- EFX_POPULATE_DWORD_1(reg, RX_DESC_WPTR_DWORD, write_ptr);
- falcon_writel_page(rx_queue->efx, &reg,
- RX_DESC_UPD_REG_KER_DWORD, rx_queue->queue);
+ write_ptr = rx_queue->added_count & EFX_RXQ_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);
}
int falcon_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);
return falcon_alloc_special_buffer(efx, &rx_queue->rxd,
- FALCON_RXD_RING_SIZE *
- sizeof(efx_qword_t));
+ EFX_RXQ_SIZE * sizeof(efx_qword_t));
}
void falcon_init_rx(struct efx_rx_queue *rx_queue)
@@ -623,19 +602,21 @@ void falcon_init_rx(struct efx_rx_queue *rx_queue)
/* Push RX descriptor ring to card */
EFX_POPULATE_OWORD_10(rx_desc_ptr,
- RX_ISCSI_DDIG_EN, iscsi_digest_en,
- RX_ISCSI_HDIG_EN, iscsi_digest_en,
- RX_DESCQ_BUF_BASE_ID, rx_queue->rxd.index,
- RX_DESCQ_EVQ_ID, rx_queue->channel->channel,
- RX_DESCQ_OWNER_ID, 0,
- RX_DESCQ_LABEL, rx_queue->queue,
- RX_DESCQ_SIZE, FALCON_RXD_RING_ORDER,
- RX_DESCQ_TYPE, 0 /* kernel queue */ ,
+ FRF_AZ_RX_ISCSI_DDIG_EN, iscsi_digest_en,
+ 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,
+ FRF_AZ_RX_DESCQ_OWNER_ID, 0,
+ FRF_AZ_RX_DESCQ_LABEL, rx_queue->queue,
+ FRF_AZ_RX_DESCQ_SIZE,
+ __ffs(rx_queue->rxd.entries),
+ FRF_AZ_RX_DESCQ_TYPE, 0 /* kernel queue */ ,
/* For >=B0 this is scatter so disable */
- RX_DESCQ_JUMBO, !is_b0,
- RX_DESCQ_EN, 1);
- falcon_write_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
- rx_queue->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);
}
static void falcon_flush_rx_queue(struct efx_rx_queue *rx_queue)
@@ -645,9 +626,9 @@ static void falcon_flush_rx_queue(struct efx_rx_queue *rx_queue)
/* Post a flush command */
EFX_POPULATE_OWORD_2(rx_flush_descq,
- RX_FLUSH_DESCQ_CMD, 1,
- RX_FLUSH_DESCQ, rx_queue->queue);
- falcon_write(efx, &rx_flush_descq, RX_FLUSH_DESCQ_REG_KER);
+ FRF_AZ_RX_FLUSH_DESCQ_CMD, 1,
+ FRF_AZ_RX_FLUSH_DESCQ, rx_queue->queue);
+ efx_writeo(efx, &rx_flush_descq, FR_AZ_RX_FLUSH_DESCQ);
}
void falcon_fini_rx(struct efx_rx_queue *rx_queue)
@@ -660,8 +641,8 @@ void falcon_fini_rx(struct efx_rx_queue *rx_queue)
/* Remove RX descriptor ring from card */
EFX_ZERO_OWORD(rx_desc_ptr);
- falcon_write_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
- rx_queue->queue);
+ efx_writeo_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
+ rx_queue->queue);
/* Unpin RX descriptor ring */
falcon_fini_special_buffer(efx, &rx_queue->rxd);
@@ -694,8 +675,8 @@ void falcon_eventq_read_ack(struct efx_channel *channel)
efx_dword_t reg;
struct efx_nic *efx = channel->efx;
- EFX_POPULATE_DWORD_1(reg, EVQ_RPTR_DWORD, channel->eventq_read_ptr);
- falcon_writel_table(efx, &reg, efx->type->evq_rptr_tbl_base,
+ EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR, channel->eventq_read_ptr);
+ efx_writed_table(efx, &reg, efx->type->evq_rptr_tbl_base,
channel->channel);
}
@@ -704,11 +685,14 @@ void falcon_generate_event(struct efx_channel *channel, efx_qword_t *event)
{
efx_oword_t drv_ev_reg;
- EFX_POPULATE_OWORD_2(drv_ev_reg,
- DRV_EV_QID, channel->channel,
- DRV_EV_DATA,
- EFX_QWORD_FIELD64(*event, WHOLE_EVENT));
- falcon_write(channel->efx, &drv_ev_reg, DRV_EV_REG_KER);
+ BUILD_BUG_ON(FRF_AZ_DRV_EV_DATA_LBN != 0 ||
+ FRF_AZ_DRV_EV_DATA_WIDTH != 64);
+ drv_ev_reg.u32[0] = event->u32[0];
+ drv_ev_reg.u32[1] = event->u32[1];
+ drv_ev_reg.u32[2] = 0;
+ drv_ev_reg.u32[3] = 0;
+ EFX_SET_OWORD_FIELD(drv_ev_reg, FRF_AZ_DRV_EV_QID, channel->channel);
+ efx_writeo(channel->efx, &drv_ev_reg, FR_AZ_DRV_EV);
}
/* Handle a transmit completion event
@@ -724,18 +708,18 @@ static void falcon_handle_tx_event(struct efx_channel *channel,
struct efx_tx_queue *tx_queue;
struct efx_nic *efx = channel->efx;
- if (likely(EFX_QWORD_FIELD(*event, TX_EV_COMP))) {
+ if (likely(EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_COMP))) {
/* Transmit completion */
- tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, TX_EV_DESC_PTR);
- tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL);
+ 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];
channel->irq_mod_score +=
(tx_ev_desc_ptr - tx_queue->read_count) &
- efx->type->txd_ring_mask;
+ EFX_TXQ_MASK;
efx_xmit_done(tx_queue, tx_ev_desc_ptr);
- } else if (EFX_QWORD_FIELD(*event, TX_EV_WQ_FF_FULL)) {
+ } 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, TX_EV_Q_LABEL);
+ tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL);
tx_queue = &efx->tx_queue[tx_ev_q_label];
if (efx_dev_registered(efx))
@@ -743,7 +727,7 @@ static void falcon_handle_tx_event(struct efx_channel *channel,
falcon_notify_tx_desc(tx_queue);
if (efx_dev_registered(efx))
netif_tx_unlock(efx->net_dev);
- } else if (EFX_QWORD_FIELD(*event, TX_EV_PKT_ERR) &&
+ } else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_PKT_ERR) &&
EFX_WORKAROUND_10727(efx)) {
efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
} else {
@@ -767,22 +751,22 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
bool rx_ev_ip_frag_err, rx_ev_hdr_type, rx_ev_mcast_pkt;
unsigned rx_ev_pkt_type;
- rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE);
- rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, RX_EV_MCAST_PKT);
- rx_ev_tobe_disc = EFX_QWORD_FIELD(*event, RX_EV_TOBE_DISC);
- rx_ev_pkt_type = EFX_QWORD_FIELD(*event, RX_EV_PKT_TYPE);
+ rx_ev_hdr_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_HDR_TYPE);
+ rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_PKT);
+ rx_ev_tobe_disc = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_TOBE_DISC);
+ rx_ev_pkt_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PKT_TYPE);
rx_ev_buf_owner_id_err = EFX_QWORD_FIELD(*event,
- RX_EV_BUF_OWNER_ID_ERR);
- rx_ev_ip_frag_err = EFX_QWORD_FIELD(*event, RX_EV_IF_FRAG_ERR);
+ FSF_AZ_RX_EV_BUF_OWNER_ID_ERR);
+ rx_ev_ip_frag_err = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_IP_FRAG_ERR);
rx_ev_ip_hdr_chksum_err = EFX_QWORD_FIELD(*event,
- RX_EV_IP_HDR_CHKSUM_ERR);
+ FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR);
rx_ev_tcp_udp_chksum_err = EFX_QWORD_FIELD(*event,
- RX_EV_TCP_UDP_CHKSUM_ERR);
- rx_ev_eth_crc_err = EFX_QWORD_FIELD(*event, RX_EV_ETH_CRC_ERR);
- rx_ev_frm_trunc = EFX_QWORD_FIELD(*event, RX_EV_FRM_TRUNC);
+ FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR);
+ rx_ev_eth_crc_err = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_ETH_CRC_ERR);
+ rx_ev_frm_trunc = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_FRM_TRUNC);
rx_ev_drib_nib = ((falcon_rev(efx) >= FALCON_REV_B0) ?
- 0 : EFX_QWORD_FIELD(*event, RX_EV_DRIB_NIB));
- rx_ev_pause_frm = EFX_QWORD_FIELD(*event, RX_EV_PAUSE_FRM_ERR);
+ 0 : EFX_QWORD_FIELD(*event, FSF_AA_RX_EV_DRIB_NIB));
+ rx_ev_pause_frm = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PAUSE_FRM_ERR);
/* Every error apart from tobe_disc and pause_frm */
rx_ev_other_err = (rx_ev_drib_nib | rx_ev_tcp_udp_chksum_err |
@@ -838,9 +822,8 @@ static void falcon_handle_rx_bad_index(struct efx_rx_queue *rx_queue,
struct efx_nic *efx = rx_queue->efx;
unsigned expected, dropped;
- expected = rx_queue->removed_count & FALCON_RXD_RING_MASK;
- dropped = ((index + FALCON_RXD_RING_SIZE - expected) &
- FALCON_RXD_RING_MASK);
+ expected = rx_queue->removed_count & EFX_RXQ_MASK;
+ dropped = (index - expected) & EFX_RXQ_MASK;
EFX_INFO(efx, "dropped %d events (index=%d expected=%d)\n",
dropped, index, expected);
@@ -866,17 +849,18 @@ static void falcon_handle_rx_event(struct efx_channel *channel,
struct efx_nic *efx = channel->efx;
/* Basic packet information */
- rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, RX_EV_BYTE_CNT);
- rx_ev_pkt_ok = EFX_QWORD_FIELD(*event, RX_EV_PKT_OK);
- rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE);
- WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_JUMBO_CONT));
- WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_SOP) != 1);
- WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_Q_LABEL) != channel->channel);
+ rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_BYTE_CNT);
+ rx_ev_pkt_ok = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PKT_OK);
+ rx_ev_hdr_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_HDR_TYPE);
+ WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_JUMBO_CONT));
+ WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_SOP) != 1);
+ WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_Q_LABEL) !=
+ channel->channel);
rx_queue = &efx->rx_queue[channel->channel];
- rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, RX_EV_DESC_PTR);
- expected_ptr = rx_queue->removed_count & FALCON_RXD_RING_MASK;
+ rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_DESC_PTR);
+ expected_ptr = rx_queue->removed_count & EFX_RXQ_MASK;
if (unlikely(rx_ev_desc_ptr != expected_ptr))
falcon_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr);
@@ -884,7 +868,9 @@ static void falcon_handle_rx_event(struct efx_channel *channel,
/* If packet is marked as OK and packet type is TCP/IPv4 or
* UDP/IPv4, then we can rely on the hardware checksum.
*/
- checksummed = RX_EV_HDR_TYPE_HAS_CHECKSUMS(rx_ev_hdr_type);
+ checksummed =
+ rx_ev_hdr_type == FSE_AB_RX_EV_HDR_TYPE_IPV4_TCP ||
+ rx_ev_hdr_type == FSE_AB_RX_EV_HDR_TYPE_IPV4_UDP;
} else {
falcon_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok,
&discard);
@@ -892,10 +878,10 @@ static void falcon_handle_rx_event(struct efx_channel *channel,
}
/* Detect multicast packets that didn't match the filter */
- rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, RX_EV_MCAST_PKT);
+ rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_PKT);
if (rx_ev_mcast_pkt) {
unsigned int rx_ev_mcast_hash_match =
- EFX_QWORD_FIELD(*event, RX_EV_MCAST_HASH_MATCH);
+ EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_HASH_MATCH);
if (unlikely(!rx_ev_mcast_hash_match))
discard = true;
@@ -915,22 +901,23 @@ static void falcon_handle_global_event(struct efx_channel *channel,
struct efx_nic *efx = channel->efx;
bool handled = false;
- if (EFX_QWORD_FIELD(*event, G_PHY0_INTR) ||
- EFX_QWORD_FIELD(*event, G_PHY1_INTR) ||
- EFX_QWORD_FIELD(*event, XG_PHY_INTR) ||
- EFX_QWORD_FIELD(*event, XFP_PHY_INTR)) {
+ if (EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_G_PHY0_INTR) ||
+ EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XG_PHY0_INTR) ||
+ EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XFP_PHY0_INTR)) {
efx->phy_op->clear_interrupt(efx);
queue_work(efx->workqueue, &efx->phy_work);
handled = true;
}
if ((falcon_rev(efx) >= FALCON_REV_B0) &&
- EFX_QWORD_FIELD(*event, XG_MNT_INTR_B0)) {
+ EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_XG_MGT_INTR)) {
queue_work(efx->workqueue, &efx->mac_work);
handled = true;
}
- if (EFX_QWORD_FIELD_VER(efx, *event, RX_RECOVERY)) {
+ if (falcon_rev(efx) <= FALCON_REV_A1 ?
+ EFX_QWORD_FIELD(*event, FSF_AA_GLB_EV_RX_RECOVERY) :
+ EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_RX_RECOVERY)) {
EFX_ERR(efx, "channel %d seen global RX_RESET "
"event. Resetting.\n", channel->channel);
@@ -953,35 +940,35 @@ static void falcon_handle_driver_event(struct efx_channel *channel,
unsigned int ev_sub_code;
unsigned int ev_sub_data;
- ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
- ev_sub_data = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_DATA);
+ ev_sub_code = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBCODE);
+ ev_sub_data = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBDATA);
switch (ev_sub_code) {
- case TX_DESCQ_FLS_DONE_EV_DECODE:
+ case FSE_AZ_TX_DESCQ_FLS_DONE_EV:
EFX_TRACE(efx, "channel %d TXQ %d flushed\n",
channel->channel, ev_sub_data);
break;
- case RX_DESCQ_FLS_DONE_EV_DECODE:
+ case FSE_AZ_RX_DESCQ_FLS_DONE_EV:
EFX_TRACE(efx, "channel %d RXQ %d flushed\n",
channel->channel, ev_sub_data);
break;
- case EVQ_INIT_DONE_EV_DECODE:
+ case FSE_AZ_EVQ_INIT_DONE_EV:
EFX_LOG(efx, "channel %d EVQ %d initialised\n",
channel->channel, ev_sub_data);
break;
- case SRM_UPD_DONE_EV_DECODE:
+ case FSE_AZ_SRM_UPD_DONE_EV:
EFX_TRACE(efx, "channel %d SRAM update done\n",
channel->channel);
break;
- case WAKE_UP_EV_DECODE:
+ case FSE_AZ_WAKE_UP_EV:
EFX_TRACE(efx, "channel %d RXQ %d wakeup event\n",
channel->channel, ev_sub_data);
break;
- case TIMER_EV_DECODE:
+ case FSE_AZ_TIMER_EV:
EFX_TRACE(efx, "channel %d RX queue %d timer expired\n",
channel->channel, ev_sub_data);
break;
- case RX_RECOVERY_EV_DECODE:
+ case FSE_AA_RX_RECOVER_EV:
EFX_ERR(efx, "channel %d seen DRIVER RX_RESET event. "
"Resetting.\n", channel->channel);
atomic_inc(&efx->rx_reset);
@@ -990,12 +977,12 @@ static void falcon_handle_driver_event(struct efx_channel *channel,
RESET_TYPE_RX_RECOVERY :
RESET_TYPE_DISABLE);
break;
- case RX_DSC_ERROR_EV_DECODE:
+ case FSE_BZ_RX_DSC_ERROR_EV:
EFX_ERR(efx, "RX DMA Q %d reports descriptor fetch error."
" RX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
efx_schedule_reset(efx, RESET_TYPE_RX_DESC_FETCH);
break;
- case TX_DSC_ERROR_EV_DECODE:
+ case FSE_BZ_TX_DSC_ERROR_EV:
EFX_ERR(efx, "TX DMA Q %d reports descriptor fetch error."
" TX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
@@ -1031,27 +1018,27 @@ int falcon_process_eventq(struct efx_channel *channel, int rx_quota)
/* Clear this event by marking it all ones */
EFX_SET_QWORD(*p_event);
- ev_code = EFX_QWORD_FIELD(event, EV_CODE);
+ ev_code = EFX_QWORD_FIELD(event, FSF_AZ_EV_CODE);
switch (ev_code) {
- case RX_IP_EV_DECODE:
+ case FSE_AZ_EV_CODE_RX_EV:
falcon_handle_rx_event(channel, &event);
++rx_packets;
break;
- case TX_IP_EV_DECODE:
+ case FSE_AZ_EV_CODE_TX_EV:
falcon_handle_tx_event(channel, &event);
break;
- case DRV_GEN_EV_DECODE:
- channel->eventq_magic
- = EFX_QWORD_FIELD(event, EVQ_MAGIC);
+ case FSE_AZ_EV_CODE_DRV_GEN_EV:
+ channel->eventq_magic = EFX_QWORD_FIELD(
+ event, FSF_AZ_DRV_GEN_EV_MAGIC);
EFX_LOG(channel->efx, "channel %d received generated "
"event "EFX_QWORD_FMT"\n", channel->channel,
EFX_QWORD_VAL(event));
break;
- case GLOBAL_EV_DECODE:
+ case FSE_AZ_EV_CODE_GLOBAL_EV:
falcon_handle_global_event(channel, &event);
break;
- case DRIVER_EV_DECODE:
+ case FSE_AZ_EV_CODE_DRIVER_EV:
falcon_handle_driver_event(channel, &event);
break;
default:
@@ -1061,7 +1048,7 @@ int falcon_process_eventq(struct efx_channel *channel, int rx_quota)
}
/* Increment read pointer */
- read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
+ read_ptr = (read_ptr + 1) & EFX_EVQ_MASK;
} while (rx_packets < rx_quota);
@@ -1076,26 +1063,20 @@ void falcon_set_int_moderation(struct efx_channel *channel)
/* Set timer register */
if (channel->irq_moderation) {
- /* Round to resolution supported by hardware. The value we
- * program is based at 0. So actual interrupt moderation
- * achieved is ((x + 1) * res).
- */
- channel->irq_moderation -= (channel->irq_moderation %
- FALCON_IRQ_MOD_RESOLUTION);
- if (channel->irq_moderation < FALCON_IRQ_MOD_RESOLUTION)
- channel->irq_moderation = FALCON_IRQ_MOD_RESOLUTION;
EFX_POPULATE_DWORD_2(timer_cmd,
- TIMER_MODE, TIMER_MODE_INT_HLDOFF,
- TIMER_VAL,
- channel->irq_moderation /
- FALCON_IRQ_MOD_RESOLUTION - 1);
+ FRF_AB_TC_TIMER_MODE,
+ FFE_BB_TIMER_MODE_INT_HLDOFF,
+ FRF_AB_TC_TIMER_VAL,
+ channel->irq_moderation - 1);
} else {
EFX_POPULATE_DWORD_2(timer_cmd,
- TIMER_MODE, TIMER_MODE_DIS,
- TIMER_VAL, 0);
+ FRF_AB_TC_TIMER_MODE,
+ FFE_BB_TIMER_MODE_DIS,
+ FRF_AB_TC_TIMER_VAL, 0);
}
- falcon_writel_page_locked(efx, &timer_cmd, TIMER_CMD_REG_KER,
- channel->channel);
+ BUILD_BUG_ON(FR_AA_TIMER_COMMAND_KER != FR_BZ_TIMER_COMMAND_P0);
+ efx_writed_page_locked(efx, &timer_cmd, FR_BZ_TIMER_COMMAND_P0,
+ channel->channel);
}
@@ -1103,10 +1084,10 @@ void falcon_set_int_moderation(struct efx_channel *channel)
int falcon_probe_eventq(struct efx_channel *channel)
{
struct efx_nic *efx = channel->efx;
- unsigned int evq_size;
-
- evq_size = FALCON_EVQ_SIZE * sizeof(efx_qword_t);
- return falcon_alloc_special_buffer(efx, &channel->eventq, evq_size);
+ BUILD_BUG_ON(EFX_EVQ_SIZE < 512 || EFX_EVQ_SIZE > 32768 ||
+ EFX_EVQ_SIZE & EFX_EVQ_MASK);
+ return falcon_alloc_special_buffer(efx, &channel->eventq,
+ EFX_EVQ_SIZE * sizeof(efx_qword_t));
}
void falcon_init_eventq(struct efx_channel *channel)
@@ -1126,11 +1107,11 @@ void falcon_init_eventq(struct efx_channel *channel)
/* Push event queue to card */
EFX_POPULATE_OWORD_3(evq_ptr,
- EVQ_EN, 1,
- EVQ_SIZE, FALCON_EVQ_ORDER,
- EVQ_BUF_BASE_ID, channel->eventq.index);
- falcon_write_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base,
- channel->channel);
+ FRF_AZ_EVQ_EN, 1,
+ FRF_AZ_EVQ_SIZE, __ffs(channel->eventq.entries),
+ FRF_AZ_EVQ_BUF_BASE_ID, channel->eventq.index);
+ efx_writeo_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base,
+ channel->channel);
falcon_set_int_moderation(channel);
}
@@ -1142,8 +1123,8 @@ void falcon_fini_eventq(struct efx_channel *channel)
/* Remove event queue from card */
EFX_ZERO_OWORD(eventq_ptr);
- falcon_write_table(efx, &eventq_ptr, efx->type->evq_ptr_tbl_base,
- channel->channel);
+ efx_writeo_table(efx, &eventq_ptr, efx->type->evq_ptr_tbl_base,
+ channel->channel);
/* Unpin event queue */
falcon_fini_special_buffer(efx, &channel->eventq);
@@ -1164,9 +1145,9 @@ void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic)
{
efx_qword_t test_event;
- EFX_POPULATE_QWORD_2(test_event,
- EV_CODE, DRV_GEN_EV_DECODE,
- EVQ_MAGIC, magic);
+ EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE,
+ FSE_AZ_EV_CODE_DRV_GEN_EV,
+ FSF_AZ_DRV_GEN_EV_MAGIC, magic);
falcon_generate_event(channel, &test_event);
}
@@ -1174,11 +1155,12 @@ void falcon_sim_phy_event(struct efx_nic *efx)
{
efx_qword_t phy_event;
- EFX_POPULATE_QWORD_1(phy_event, EV_CODE, GLOBAL_EV_DECODE);
+ EFX_POPULATE_QWORD_1(phy_event, FSF_AZ_EV_CODE,
+ FSE_AZ_EV_CODE_GLOBAL_EV);
if (EFX_IS10G(efx))
- EFX_SET_QWORD_FIELD(phy_event, XG_PHY_INTR, 1);
+ EFX_SET_QWORD_FIELD(phy_event, FSF_AB_GLB_EV_XG_PHY0_INTR, 1);
else
- EFX_SET_QWORD_FIELD(phy_event, G_PHY0_INTR, 1);
+ EFX_SET_QWORD_FIELD(phy_event, FSF_AB_GLB_EV_G_PHY0_INTR, 1);
falcon_generate_event(&efx->channel[0], &phy_event);
}
@@ -1196,7 +1178,7 @@ static void falcon_poll_flush_events(struct efx_nic *efx)
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) & FALCON_EVQ_MASK;
+ unsigned int end_ptr = (read_ptr - 1) & EFX_EVQ_MASK;
do {
efx_qword_t *event = falcon_event(channel, read_ptr);
@@ -1206,22 +1188,23 @@ static void falcon_poll_flush_events(struct efx_nic *efx)
if (!falcon_event_present(event))
break;
- ev_code = EFX_QWORD_FIELD(*event, EV_CODE);
- ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
- if (ev_code == DRIVER_EV_DECODE &&
- ev_sub_code == TX_DESCQ_FLS_DONE_EV_DECODE) {
+ ev_code = EFX_QWORD_FIELD(*event, FSF_AZ_EV_CODE);
+ ev_sub_code = EFX_QWORD_FIELD(*event,
+ FSF_AZ_DRIVER_EV_SUBCODE);
+ if (ev_code == FSE_AZ_EV_CODE_DRIVER_EV &&
+ ev_sub_code == FSE_AZ_TX_DESCQ_FLS_DONE_EV) {
ev_queue = EFX_QWORD_FIELD(*event,
- DRIVER_EV_TX_DESCQ_ID);
+ FSF_AZ_DRIVER_EV_SUBDATA);
if (ev_queue < EFX_TX_QUEUE_COUNT) {
tx_queue = efx->tx_queue + ev_queue;
tx_queue->flushed = true;
}
- } else if (ev_code == DRIVER_EV_DECODE &&
- ev_sub_code == RX_DESCQ_FLS_DONE_EV_DECODE) {
- ev_queue = EFX_QWORD_FIELD(*event,
- DRIVER_EV_RX_DESCQ_ID);
- ev_failed = EFX_QWORD_FIELD(*event,
- DRIVER_EV_RX_FLUSH_FAIL);
+ } else if (ev_code == FSE_AZ_EV_CODE_DRIVER_EV &&
+ ev_sub_code == FSE_AZ_RX_DESCQ_FLS_DONE_EV) {
+ ev_queue = EFX_QWORD_FIELD(
+ *event, FSF_AZ_DRIVER_EV_RX_DESCQ_ID);
+ ev_failed = EFX_QWORD_FIELD(
+ *event, FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL);
if (ev_queue < efx->n_rx_queues) {
rx_queue = efx->rx_queue + ev_queue;
@@ -1233,7 +1216,7 @@ static void falcon_poll_flush_events(struct efx_nic *efx)
}
}
- read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
+ read_ptr = (read_ptr + 1) & EFX_EVQ_MASK;
} while (read_ptr != end_ptr);
}
@@ -1311,9 +1294,9 @@ static inline void falcon_interrupts(struct efx_nic *efx, int enabled,
efx_oword_t int_en_reg_ker;
EFX_POPULATE_OWORD_2(int_en_reg_ker,
- KER_INT_KER, force,
- DRV_INT_EN_KER, enabled);
- falcon_write(efx, &int_en_reg_ker, INT_EN_REG_KER);
+ FRF_AZ_KER_INT_KER, force,
+ FRF_AZ_DRV_INT_EN_KER, enabled);
+ efx_writeo(efx, &int_en_reg_ker, FR_AZ_INT_EN_KER);
}
void falcon_enable_interrupts(struct efx_nic *efx)
@@ -1326,9 +1309,10 @@ void falcon_enable_interrupts(struct efx_nic *efx)
/* Program address */
EFX_POPULATE_OWORD_2(int_adr_reg_ker,
- NORM_INT_VEC_DIS_KER, EFX_INT_MODE_USE_MSI(efx),
- INT_ADR_KER, efx->irq_status.dma_addr);
- falcon_write(efx, &int_adr_reg_ker, INT_ADR_REG_KER);
+ FRF_AZ_NORM_INT_VEC_DIS_KER,
+ EFX_INT_MODE_USE_MSI(efx),
+ FRF_AZ_INT_ADR_KER, efx->irq_status.dma_addr);
+ efx_writeo(efx, &int_adr_reg_ker, FR_AZ_INT_ADR_KER);
/* Enable interrupts */
falcon_interrupts(efx, 1, 0);
@@ -1368,9 +1352,9 @@ static inline void falcon_irq_ack_a1(struct efx_nic *efx)
{
efx_dword_t reg;
- EFX_POPULATE_DWORD_1(reg, INT_ACK_DUMMY_DATA, 0xb7eb7e);
- falcon_writel(efx, &reg, INT_ACK_REG_KER_A1);
- falcon_readl(efx, &reg, WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1);
+ EFX_POPULATE_DWORD_1(reg, FRF_AA_INT_ACK_KER_FIELD, 0xb7eb7e);
+ efx_writed(efx, &reg, FR_AA_INT_ACK_KER);
+ efx_readd(efx, &reg, FR_AA_WORK_AROUND_BROKEN_PCI_READS);
}
/* Process a fatal interrupt
@@ -1383,8 +1367,8 @@ static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx)
efx_oword_t fatal_intr;
int error, mem_perr;
- falcon_read(efx, &fatal_intr, FATAL_INTR_REG_KER);
- error = EFX_OWORD_FIELD(fatal_intr, INT_KER_ERROR);
+ efx_reado(efx, &fatal_intr, FR_AZ_FATAL_INTR_KER);
+ error = EFX_OWORD_FIELD(fatal_intr, FRF_AZ_FATAL_INTR);
EFX_ERR(efx, "SYSTEM ERROR " EFX_OWORD_FMT " status "
EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker),
@@ -1394,10 +1378,10 @@ static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx)
goto out;
/* If this is a memory parity error dump which blocks are offending */
- mem_perr = EFX_OWORD_FIELD(fatal_intr, MEM_PERR_INT_KER);
+ mem_perr = EFX_OWORD_FIELD(fatal_intr, FRF_AZ_MEM_PERR_INT_KER);
if (mem_perr) {
efx_oword_t reg;
- falcon_read(efx, &reg, MEM_STAT_REG_KER);
+ efx_reado(efx, &reg, FR_AZ_MEM_STAT);
EFX_ERR(efx, "SYSTEM ERROR: memory parity error "
EFX_OWORD_FMT "\n", EFX_OWORD_VAL(reg));
}
@@ -1409,13 +1393,13 @@ static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx)
falcon_disable_interrupts(efx);
/* Count errors and reset or disable the NIC accordingly */
- if (nic_data->int_error_count == 0 ||
- time_after(jiffies, nic_data->int_error_expire)) {
- nic_data->int_error_count = 0;
- nic_data->int_error_expire =
+ if (efx->int_error_count == 0 ||
+ time_after(jiffies, efx->int_error_expire)) {
+ efx->int_error_count = 0;
+ efx->int_error_expire =
jiffies + FALCON_INT_ERROR_EXPIRE * HZ;
}
- if (++nic_data->int_error_count < FALCON_MAX_INT_ERRORS) {
+ if (++efx->int_error_count < FALCON_MAX_INT_ERRORS) {
EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n");
efx_schedule_reset(efx, RESET_TYPE_INT_ERROR);
} else {
@@ -1441,11 +1425,11 @@ static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id)
int syserr;
/* Read the ISR which also ACKs the interrupts */
- falcon_readl(efx, &reg, INT_ISR0_B0);
+ efx_readd(efx, &reg, FR_BZ_INT_ISR0);
queues = EFX_EXTRACT_DWORD(reg, 0, 31);
/* Check to see if we have a serious error condition */
- syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT);
+ syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
if (unlikely(syserr))
return falcon_fatal_interrupt(efx);
@@ -1491,7 +1475,7 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
/* Check to see if we have a serious error condition */
- syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT);
+ syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
if (unlikely(syserr))
return falcon_fatal_interrupt(efx);
@@ -1558,12 +1542,12 @@ static void falcon_setup_rss_indir_table(struct efx_nic *efx)
if (falcon_rev(efx) < FALCON_REV_B0)
return;
- for (offset = RX_RSS_INDIR_TBL_B0;
- offset < RX_RSS_INDIR_TBL_B0 + 0x800;
+ for (offset = FR_BZ_RX_INDIRECTION_TBL;
+ offset < FR_BZ_RX_INDIRECTION_TBL + 0x800;
offset += 0x10) {
- EFX_POPULATE_DWORD_1(dword, RX_RSS_INDIR_ENT_B0,
+ EFX_POPULATE_DWORD_1(dword, FRF_BZ_IT_QUEUE,
i % efx->n_rx_queues);
- falcon_writel(efx, &dword, offset);
+ efx_writed(efx, &dword, offset);
i++;
}
}
@@ -1626,7 +1610,7 @@ void falcon_fini_interrupt(struct efx_nic *efx)
/* ACK legacy interrupt */
if (falcon_rev(efx) >= FALCON_REV_B0)
- falcon_read(efx, &reg, INT_ISR0_B0);
+ efx_reado(efx, &reg, FR_BZ_INT_ISR0);
else
falcon_irq_ack_a1(efx);
@@ -1647,8 +1631,8 @@ void falcon_fini_interrupt(struct efx_nic *efx)
static int falcon_spi_poll(struct efx_nic *efx)
{
efx_oword_t reg;
- falcon_read(efx, &reg, EE_SPI_HCMD_REG_KER);
- return EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN) ? -EBUSY : 0;
+ efx_reado(efx, &reg, FR_AB_EE_SPI_HCMD);
+ return EFX_OWORD_FIELD(reg, FRF_AB_EE_SPI_HCMD_CMD_EN) ? -EBUSY : 0;
}
/* Wait for SPI command completion */
@@ -1700,27 +1684,27 @@ int falcon_spi_cmd(const struct efx_spi_device *spi,
/* Program address register, if we have an address */
if (addressed) {
- EFX_POPULATE_OWORD_1(reg, EE_SPI_HADR_ADR, address);
- falcon_write(efx, &reg, EE_SPI_HADR_REG_KER);
+ EFX_POPULATE_OWORD_1(reg, FRF_AB_EE_SPI_HADR_ADR, address);
+ efx_writeo(efx, &reg, FR_AB_EE_SPI_HADR);
}
/* Program data register, if we have data */
if (in != NULL) {
memcpy(&reg, in, len);
- falcon_write(efx, &reg, EE_SPI_HDATA_REG_KER);
+ efx_writeo(efx, &reg, FR_AB_EE_SPI_HDATA);
}
/* Issue read/write command */
EFX_POPULATE_OWORD_7(reg,
- EE_SPI_HCMD_CMD_EN, 1,
- EE_SPI_HCMD_SF_SEL, spi->device_id,
- EE_SPI_HCMD_DABCNT, len,
- EE_SPI_HCMD_READ, reading,
- EE_SPI_HCMD_DUBCNT, 0,
- EE_SPI_HCMD_ADBCNT,
+ FRF_AB_EE_SPI_HCMD_CMD_EN, 1,
+ FRF_AB_EE_SPI_HCMD_SF_SEL, spi->device_id,
+ FRF_AB_EE_SPI_HCMD_DABCNT, len,
+ FRF_AB_EE_SPI_HCMD_READ, reading,
+ FRF_AB_EE_SPI_HCMD_DUBCNT, 0,
+ FRF_AB_EE_SPI_HCMD_ADBCNT,
(addressed ? spi->addr_len : 0),
- EE_SPI_HCMD_ENC, command);
- falcon_write(efx, &reg, EE_SPI_HCMD_REG_KER);
+ FRF_AB_EE_SPI_HCMD_ENC, command);
+ efx_writeo(efx, &reg, FR_AB_EE_SPI_HCMD);
/* Wait for read/write to complete */
rc = falcon_spi_wait(efx);
@@ -1729,7 +1713,7 @@ int falcon_spi_cmd(const struct efx_spi_device *spi,
/* Read data */
if (out != NULL) {
- falcon_read(efx, &reg, EE_SPI_HDATA_REG_KER);
+ efx_reado(efx, &reg, FR_AB_EE_SPI_HDATA);
memcpy(out, &reg, len);
}
@@ -1870,21 +1854,22 @@ static int falcon_reset_macs(struct efx_nic *efx)
* macs, so instead use the internal MAC resets
*/
if (!EFX_IS10G(efx)) {
- EFX_POPULATE_OWORD_1(reg, GM_SW_RST, 1);
- falcon_write(efx, &reg, GM_CFG1_REG);
+ 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, GM_SW_RST, 0);
- falcon_write(efx, &reg, GM_CFG1_REG);
+ EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_SW_RST, 0);
+ efx_writeo(efx, &reg, FR_AB_GM_CFG1);
udelay(1000);
return 0;
} else {
- EFX_POPULATE_OWORD_1(reg, XM_CORE_RST, 1);
- falcon_write(efx, &reg, XM_GLB_CFG_REG);
+ 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++) {
- falcon_read(efx, &reg, XM_GLB_CFG_REG);
- if (EFX_OWORD_FIELD(reg, XM_CORE_RST) == 0)
+ efx_reado(efx, &reg, FR_AB_XM_GLB_CFG);
+ if (EFX_OWORD_FIELD(reg, FRF_AB_XM_CORE_RST) ==
+ 0)
return 0;
udelay(10);
}
@@ -1898,22 +1883,22 @@ static int falcon_reset_macs(struct efx_nic *efx)
* the drain sequence with the statistics fetch */
efx_stats_disable(efx);
- falcon_read(efx, &reg, MAC0_CTRL_REG_KER);
- EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0, 1);
- falcon_write(efx, &reg, MAC0_CTRL_REG_KER);
+ efx_reado(efx, &reg, FR_AB_MAC_CTRL);
+ EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, 1);
+ efx_writeo(efx, &reg, FR_AB_MAC_CTRL);
- falcon_read(efx, &reg, GLB_CTL_REG_KER);
- EFX_SET_OWORD_FIELD(reg, RST_XGTX, 1);
- EFX_SET_OWORD_FIELD(reg, RST_XGRX, 1);
- EFX_SET_OWORD_FIELD(reg, RST_EM, 1);
- falcon_write(efx, &reg, GLB_CTL_REG_KER);
+ efx_reado(efx, &reg, FR_AB_GLB_CTL);
+ EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_XGTX, 1);
+ EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_XGRX, 1);
+ EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_EM, 1);
+ efx_writeo(efx, &reg, FR_AB_GLB_CTL);
count = 0;
while (1) {
- falcon_read(efx, &reg, GLB_CTL_REG_KER);
- if (!EFX_OWORD_FIELD(reg, RST_XGTX) &&
- !EFX_OWORD_FIELD(reg, RST_XGRX) &&
- !EFX_OWORD_FIELD(reg, RST_EM)) {
+ efx_reado(efx, &reg, FR_AB_GLB_CTL);
+ if (!EFX_OWORD_FIELD(reg, FRF_AB_RST_XGTX) &&
+ !EFX_OWORD_FIELD(reg, FRF_AB_RST_XGRX) &&
+ !EFX_OWORD_FIELD(reg, FRF_AB_RST_EM)) {
EFX_LOG(efx, "Completed MAC reset after %d loops\n",
count);
break;
@@ -1944,9 +1929,9 @@ void falcon_drain_tx_fifo(struct efx_nic *efx)
(efx->loopback_mode != LOOPBACK_NONE))
return;
- falcon_read(efx, &reg, MAC0_CTRL_REG_KER);
+ efx_reado(efx, &reg, FR_AB_MAC_CTRL);
/* There is no point in draining more than once */
- if (EFX_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0))
+ if (EFX_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN))
return;
falcon_reset_macs(efx);
@@ -1960,9 +1945,9 @@ void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
return;
/* Isolate the MAC -> RX */
- falcon_read(efx, &reg, RX_CFG_REG_KER);
- EFX_SET_OWORD_FIELD(reg, RX_INGR_EN_B0, 0);
- falcon_write(efx, &reg, RX_CFG_REG_KER);
+ efx_reado(efx, &reg, FR_AZ_RX_CFG);
+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 0);
+ efx_writeo(efx, &reg, FR_AZ_RX_CFG);
if (!efx->link_up)
falcon_drain_tx_fifo(efx);
@@ -1985,19 +1970,19 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
* indefinitely held and TX queue can be flushed at any point
* while the link is down. */
EFX_POPULATE_OWORD_5(reg,
- MAC_XOFF_VAL, 0xffff /* max pause time */,
- MAC_BCAD_ACPT, 1,
- MAC_UC_PROM, efx->promiscuous,
- MAC_LINK_STATUS, 1, /* always set */
- MAC_SPEED, link_speed);
+ FRF_AB_MAC_XOFF_VAL, 0xffff /* max pause time */,
+ FRF_AB_MAC_BCAD_ACPT, 1,
+ FRF_AB_MAC_UC_PROM, efx->promiscuous,
+ FRF_AB_MAC_LINK_STATUS, 1, /* always set */
+ FRF_AB_MAC_SPEED, link_speed);
/* On B0, MAC backpressure can be disabled and packets get
* discarded. */
if (falcon_rev(efx) >= FALCON_REV_B0) {
- EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0,
+ EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN,
!efx->link_up);
}
- falcon_write(efx, &reg, MAC0_CTRL_REG_KER);
+ efx_writeo(efx, &reg, FR_AB_MAC_CTRL);
/* Restore the multicast hash registers. */
falcon_set_multicast_hash(efx);
@@ -2006,13 +1991,13 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
* covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL.
* Action on receipt of pause frames is controller by XM_DIS_FCNTL */
tx_fc = !!(efx->link_fc & EFX_FC_TX);
- falcon_read(efx, &reg, RX_CFG_REG_KER);
- EFX_SET_OWORD_FIELD_VER(efx, reg, RX_XOFF_MAC_EN, tx_fc);
+ efx_reado(efx, &reg, FR_AZ_RX_CFG);
+ EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, tx_fc);
/* Unisolate the MAC -> RX */
if (falcon_rev(efx) >= FALCON_REV_B0)
- EFX_SET_OWORD_FIELD(reg, RX_INGR_EN_B0, 1);
- falcon_write(efx, &reg, RX_CFG_REG_KER);
+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1);
+ efx_writeo(efx, &reg, FR_AZ_RX_CFG);
}
int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset)
@@ -2027,8 +2012,8 @@ int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset)
/* Statistics fetch will fail if the MAC is in TX drain */
if (falcon_rev(efx) >= FALCON_REV_B0) {
efx_oword_t temp;
- falcon_read(efx, &temp, MAC0_CTRL_REG_KER);
- if (EFX_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0))
+ efx_reado(efx, &temp, FR_AB_MAC_CTRL);
+ if (EFX_OWORD_FIELD(temp, FRF_BB_TXFIFO_DRAIN_EN))
return 0;
}
@@ -2038,10 +2023,10 @@ int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset)
/* Initiate DMA transfer of stats */
EFX_POPULATE_OWORD_2(reg,
- MAC_STAT_DMA_CMD, 1,
- MAC_STAT_DMA_ADR,
+ FRF_AB_MAC_STAT_DMA_CMD, 1,
+ FRF_AB_MAC_STAT_DMA_ADR,
efx->stats_buffer.dma_addr);
- falcon_write(efx, &reg, MAC0_STAT_DMA_REG_KER);
+ efx_writeo(efx, &reg, FR_AB_MAC_STAT_DMA);
/* Wait for transfer to complete */
for (i = 0; i < 400; i++) {
@@ -2071,10 +2056,10 @@ static int falcon_gmii_wait(struct efx_nic *efx)
/* wait upto 50ms - taken max from datasheet */
for (count = 0; count < 5000; count++) {
- falcon_readl(efx, &md_stat, MD_STAT_REG_KER);
- if (EFX_DWORD_FIELD(md_stat, MD_BSY) == 0) {
- if (EFX_DWORD_FIELD(md_stat, MD_LNFL) != 0 ||
- EFX_DWORD_FIELD(md_stat, MD_BSERR) != 0) {
+ efx_readd(efx, &md_stat, FR_AB_MD_STAT);
+ if (EFX_DWORD_FIELD(md_stat, FRF_AB_MD_BSY) == 0) {
+ if (EFX_DWORD_FIELD(md_stat, FRF_AB_MD_LNFL) != 0 ||
+ EFX_DWORD_FIELD(md_stat, FRF_AB_MD_BSERR) != 0) {
EFX_ERR(efx, "error from GMII access "
EFX_DWORD_FMT"\n",
EFX_DWORD_VAL(md_stat));
@@ -2107,29 +2092,30 @@ static int falcon_mdio_write(struct net_device *net_dev,
goto out;
/* Write the address/ID register */
- EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr);
- falcon_write(efx, &reg, MD_PHY_ADR_REG_KER);
+ EFX_POPULATE_OWORD_1(reg, FRF_AB_MD_PHY_ADR, addr);
+ efx_writeo(efx, &reg, FR_AB_MD_PHY_ADR);
- EFX_POPULATE_OWORD_2(reg, MD_PRT_ADR, prtad, MD_DEV_ADR, devad);
- falcon_write(efx, &reg, MD_ID_REG_KER);
+ EFX_POPULATE_OWORD_2(reg, FRF_AB_MD_PRT_ADR, prtad,
+ FRF_AB_MD_DEV_ADR, devad);
+ efx_writeo(efx, &reg, FR_AB_MD_ID);
/* Write data */
- EFX_POPULATE_OWORD_1(reg, MD_TXD, value);
- falcon_write(efx, &reg, MD_TXD_REG_KER);
+ EFX_POPULATE_OWORD_1(reg, FRF_AB_MD_TXD, value);
+ efx_writeo(efx, &reg, FR_AB_MD_TXD);
EFX_POPULATE_OWORD_2(reg,
- MD_WRC, 1,
- MD_GC, 0);
- falcon_write(efx, &reg, MD_CS_REG_KER);
+ FRF_AB_MD_WRC, 1,
+ FRF_AB_MD_GC, 0);
+ efx_writeo(efx, &reg, FR_AB_MD_CS);
/* Wait for data to be written */
rc = falcon_gmii_wait(efx);
if (rc) {
/* Abort the write operation */
EFX_POPULATE_OWORD_2(reg,
- MD_WRC, 0,
- MD_GC, 1);
- falcon_write(efx, &reg, MD_CS_REG_KER);
+ FRF_AB_MD_WRC, 0,
+ FRF_AB_MD_GC, 1);
+ efx_writeo(efx, &reg, FR_AB_MD_CS);
udelay(10);
}
@@ -2153,29 +2139,30 @@ static int falcon_mdio_read(struct net_device *net_dev,
if (rc)
goto out;
- EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr);
- falcon_write(efx, &reg, MD_PHY_ADR_REG_KER);
+ EFX_POPULATE_OWORD_1(reg, FRF_AB_MD_PHY_ADR, addr);
+ efx_writeo(efx, &reg, FR_AB_MD_PHY_ADR);
- EFX_POPULATE_OWORD_2(reg, MD_PRT_ADR, prtad, MD_DEV_ADR, devad);
- falcon_write(efx, &reg, MD_ID_REG_KER);
+ EFX_POPULATE_OWORD_2(reg, FRF_AB_MD_PRT_ADR, prtad,
+ FRF_AB_MD_DEV_ADR, devad);
+ efx_writeo(efx, &reg, FR_AB_MD_ID);
/* Request data to be read */
- EFX_POPULATE_OWORD_2(reg, MD_RDC, 1, MD_GC, 0);
- falcon_write(efx, &reg, MD_CS_REG_KER);
+ EFX_POPULATE_OWORD_2(reg, FRF_AB_MD_RDC, 1, FRF_AB_MD_GC, 0);
+ efx_writeo(efx, &reg, FR_AB_MD_CS);
/* Wait for data to become available */
rc = falcon_gmii_wait(efx);
if (rc == 0) {
- falcon_read(efx, &reg, MD_RXD_REG_KER);
- rc = EFX_OWORD_FIELD(reg, MD_RXD);
+ efx_reado(efx, &reg, FR_AB_MD_RXD);
+ rc = EFX_OWORD_FIELD(reg, FRF_AB_MD_RXD);
EFX_REGDUMP(efx, "read from MDIO %d register %d.%d, got %04x\n",
prtad, devad, addr, rc);
} else {
/* Abort the read operation */
EFX_POPULATE_OWORD_2(reg,
- MD_RIC, 0,
- MD_GC, 1);
- falcon_write(efx, &reg, MD_CS_REG_KER);
+ FRF_AB_MD_RIC, 0,
+ FRF_AB_MD_GC, 1);
+ efx_writeo(efx, &reg, FR_AB_MD_CS);
EFX_LOG(efx, "read from MDIO %d register %d.%d, got error %d\n",
prtad, devad, addr, rc);
@@ -2186,37 +2173,6 @@ static int falcon_mdio_read(struct net_device *net_dev,
return rc;
}
-static int falcon_probe_phy(struct efx_nic *efx)
-{
- 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_xfp_phy_ops;
- break;
- default:
- EFX_ERR(efx, "Unknown PHY type %d\n",
- efx->phy_type);
- return -1;
- }
-
- if (efx->phy_op->macs & EFX_XMAC)
- efx->loopback_modes |= ((1 << LOOPBACK_XGMII) |
- (1 << LOOPBACK_XGXS) |
- (1 << LOOPBACK_XAUI));
- if (efx->phy_op->macs & EFX_GMAC)
- efx->loopback_modes |= (1 << LOOPBACK_GMAC);
- efx->loopback_modes |= efx->phy_op->loopbacks;
-
- return 0;
-}
-
int falcon_switch_mac(struct efx_nic *efx)
{
struct efx_mac_operations *old_mac_op = efx->mac_op;
@@ -2242,16 +2198,17 @@ int falcon_switch_mac(struct efx_nic *efx)
/* Always push the NIC_STAT_REG setting even if the mac hasn't
* changed, because this function is run post online reset */
- falcon_read(efx, &nic_stat, NIC_STAT_REG);
+ efx_reado(efx, &nic_stat, FR_AB_NIC_STAT);
strap_val = EFX_IS10G(efx) ? 5 : 3;
if (falcon_rev(efx) >= FALCON_REV_B0) {
- EFX_SET_OWORD_FIELD(nic_stat, EE_STRAP_EN, 1);
- EFX_SET_OWORD_FIELD(nic_stat, EE_STRAP_OVR, strap_val);
- falcon_write(efx, &nic_stat, NIC_STAT_REG);
+ 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, STRAP_PINS) != strap_val);
+ BUG_ON(EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_PINS) !=
+ strap_val);
}
if (old_mac_op == efx->mac_op)
@@ -2272,10 +2229,31 @@ int falcon_probe_port(struct efx_nic *efx)
{
int rc;
- /* Hook in PHY operations table */
- rc = falcon_probe_phy(efx);
- if (rc)
- return 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;
+ default:
+ EFX_ERR(efx, "Unknown PHY type %d\n",
+ efx->phy_type);
+ return -ENODEV;
+ }
+
+ if (efx->phy_op->macs & EFX_XMAC)
+ efx->loopback_modes |= ((1 << LOOPBACK_XGMII) |
+ (1 << LOOPBACK_XGXS) |
+ (1 << LOOPBACK_XAUI));
+ if (efx->phy_op->macs & EFX_GMAC)
+ efx->loopback_modes |= (1 << LOOPBACK_GMAC);
+ efx->loopback_modes |= efx->phy_op->loopbacks;
/* Set up MDIO structure for PHY */
efx->mdio.mmds = efx->phy_op->mmds;
@@ -2324,8 +2302,8 @@ void falcon_set_multicast_hash(struct efx_nic *efx)
*/
set_bit_le(0xff, mc_hash->byte);
- falcon_write(efx, &mc_hash->oword[0], MAC_MCAST_HASH_REG0_KER);
- falcon_write(efx, &mc_hash->oword[1], MAC_MCAST_HASH_REG1_KER);
+ efx_writeo(efx, &mc_hash->oword[0], FR_AB_MAC_MC_HASH_REG0);
+ efx_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1);
}
@@ -2351,7 +2329,7 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)
region = kmalloc(FALCON_NVCONFIG_END, GFP_KERNEL);
if (!region)
return -ENOMEM;
- nvconfig = region + NVCONFIG_OFFSET;
+ nvconfig = region + FALCON_NVCONFIG_OFFSET;
mutex_lock(&efx->spi_lock);
rc = falcon_spi_read(spi, 0, FALCON_NVCONFIG_END, NULL, region);
@@ -2367,7 +2345,7 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)
struct_ver = le16_to_cpu(nvconfig->board_struct_ver);
rc = -EINVAL;
- if (magic_num != NVCONFIG_BOARD_MAGIC_NUM) {
+ if (magic_num != FALCON_NVCONFIG_BOARD_MAGIC_NUM) {
EFX_ERR(efx, "NVRAM bad magic 0x%x\n", magic_num);
goto out;
}
@@ -2403,41 +2381,41 @@ static struct {
unsigned address;
efx_oword_t mask;
} efx_test_registers[] = {
- { ADR_REGION_REG_KER,
+ { FR_AZ_ADR_REGION,
EFX_OWORD32(0x0001FFFF, 0x0001FFFF, 0x0001FFFF, 0x0001FFFF) },
- { RX_CFG_REG_KER,
+ { FR_AZ_RX_CFG,
EFX_OWORD32(0xFFFFFFFE, 0x00017FFF, 0x00000000, 0x00000000) },
- { TX_CFG_REG_KER,
+ { FR_AZ_TX_CFG,
EFX_OWORD32(0x7FFF0037, 0x00000000, 0x00000000, 0x00000000) },
- { TX_CFG2_REG_KER,
+ { FR_AZ_TX_RESERVED,
EFX_OWORD32(0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF) },
- { MAC0_CTRL_REG_KER,
+ { FR_AB_MAC_CTRL,
EFX_OWORD32(0xFFFF0000, 0x00000000, 0x00000000, 0x00000000) },
- { SRM_TX_DC_CFG_REG_KER,
+ { FR_AZ_SRM_TX_DC_CFG,
EFX_OWORD32(0x001FFFFF, 0x00000000, 0x00000000, 0x00000000) },
- { RX_DC_CFG_REG_KER,
+ { FR_AZ_RX_DC_CFG,
EFX_OWORD32(0x0000000F, 0x00000000, 0x00000000, 0x00000000) },
- { RX_DC_PF_WM_REG_KER,
+ { FR_AZ_RX_DC_PF_WM,
EFX_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) },
- { DP_CTRL_REG,
+ { FR_BZ_DP_CTRL,
EFX_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) },
- { GM_CFG2_REG,
+ { FR_AB_GM_CFG2,
EFX_OWORD32(0x00007337, 0x00000000, 0x00000000, 0x00000000) },
- { GMF_CFG0_REG,
+ { FR_AB_GMF_CFG0,
EFX_OWORD32(0x00001F1F, 0x00000000, 0x00000000, 0x00000000) },
- { XM_GLB_CFG_REG,
+ { FR_AB_XM_GLB_CFG,
EFX_OWORD32(0x00000C68, 0x00000000, 0x00000000, 0x00000000) },
- { XM_TX_CFG_REG,
+ { FR_AB_XM_TX_CFG,
EFX_OWORD32(0x00080164, 0x00000000, 0x00000000, 0x00000000) },
- { XM_RX_CFG_REG,
+ { FR_AB_XM_RX_CFG,
EFX_OWORD32(0x07100A0C, 0x00000000, 0x00000000, 0x00000000) },
- { XM_RX_PARAM_REG,
+ { FR_AB_XM_RX_PARAM,
EFX_OWORD32(0x00001FF8, 0x00000000, 0x00000000, 0x00000000) },
- { XM_FC_REG,
+ { FR_AB_XM_FC,
EFX_OWORD32(0xFFFF0001, 0x00000000, 0x00000000, 0x00000000) },
- { XM_ADR_LO_REG,
+ { FR_AB_XM_ADR_LO,
EFX_OWORD32(0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000) },
- { XX_SD_CTL_REG,
+ { FR_AB_XX_SD_CTL,
EFX_OWORD32(0x0003FF0F, 0x00000000, 0x00000000, 0x00000000) },
};
@@ -2461,7 +2439,7 @@ int falcon_test_registers(struct efx_nic *efx)
mask = imask = efx_test_registers[i].mask;
EFX_INVERT_OWORD(imask);
- falcon_read(efx, &original, address);
+ efx_reado(efx, &original, address);
/* bit sweep on and off */
for (j = 0; j < 128; j++) {
@@ -2472,8 +2450,8 @@ int falcon_test_registers(struct efx_nic *efx)
EFX_AND_OWORD(reg, original, mask);
EFX_SET_OWORD32(reg, j, j, 1);
- falcon_write(efx, &reg, address);
- falcon_read(efx, &buf, address);
+ efx_writeo(efx, &reg, address);
+ efx_reado(efx, &buf, address);
if (efx_masked_compare_oword(&reg, &buf, &mask))
goto fail;
@@ -2482,14 +2460,14 @@ int falcon_test_registers(struct efx_nic *efx)
EFX_OR_OWORD(reg, original, mask);
EFX_SET_OWORD32(reg, j, j, 0);
- falcon_write(efx, &reg, address);
- falcon_read(efx, &buf, address);
+ efx_writeo(efx, &reg, address);
+ efx_reado(efx, &buf, address);
if (efx_masked_compare_oword(&reg, &buf, &mask))
goto fail;
}
- falcon_write(efx, &original, address);
+ efx_writeo(efx, &original, address);
}
return 0;
@@ -2537,22 +2515,24 @@ int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
}
EFX_POPULATE_OWORD_2(glb_ctl_reg_ker,
- EXT_PHY_RST_DUR, 0x7,
- SWRST, 1);
+ FRF_AB_EXT_PHY_RST_DUR,
+ FFE_AB_EXT_PHY_RST_DUR_10240US,
+ FRF_AB_SWRST, 1);
} else {
- int reset_phy = (method == RESET_TYPE_INVISIBLE ?
- EXCLUDE_FROM_RESET : 0);
-
EFX_POPULATE_OWORD_7(glb_ctl_reg_ker,
- EXT_PHY_RST_CTL, reset_phy,
- PCIE_CORE_RST_CTL, EXCLUDE_FROM_RESET,
- PCIE_NSTCK_RST_CTL, EXCLUDE_FROM_RESET,
- PCIE_SD_RST_CTL, EXCLUDE_FROM_RESET,
- EE_RST_CTL, EXCLUDE_FROM_RESET,
- EXT_PHY_RST_DUR, 0x7 /* 10ms */,
- SWRST, 1);
- }
- falcon_write(efx, &glb_ctl_reg_ker, GLB_CTL_REG_KER);
+ /* exclude PHY from "invisible" reset */
+ FRF_AB_EXT_PHY_RST_CTL,
+ method == RESET_TYPE_INVISIBLE,
+ /* exclude EEPROM/flash and PCIe */
+ FRF_AB_PCIE_CORE_RST_CTL, 1,
+ FRF_AB_PCIE_NSTKY_RST_CTL, 1,
+ FRF_AB_PCIE_SD_RST_CTL, 1,
+ FRF_AB_EE_RST_CTL, 1,
+ FRF_AB_EXT_PHY_RST_DUR,
+ FFE_AB_EXT_PHY_RST_DUR_10240US,
+ FRF_AB_SWRST, 1);
+ }
+ efx_writeo(efx, &glb_ctl_reg_ker, FR_AB_GLB_CTL);
EFX_LOG(efx, "waiting for hardware reset\n");
schedule_timeout_uninterruptible(HZ / 20);
@@ -2577,8 +2557,8 @@ int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
}
/* Assert that reset complete */
- falcon_read(efx, &glb_ctl_reg_ker, GLB_CTL_REG_KER);
- if (EFX_OWORD_FIELD(glb_ctl_reg_ker, SWRST) != 0) {
+ efx_reado(efx, &glb_ctl_reg_ker, FR_AB_GLB_CTL);
+ if (EFX_OWORD_FIELD(glb_ctl_reg_ker, FRF_AB_SWRST) != 0) {
rc = -ETIMEDOUT;
EFX_ERR(efx, "timed out waiting for hardware reset\n");
goto fail5;
@@ -2606,16 +2586,16 @@ static int falcon_reset_sram(struct efx_nic *efx)
int count;
/* Set the SRAM wake/sleep GPIO appropriately. */
- falcon_read(efx, &gpio_cfg_reg_ker, GPIO_CTL_REG_KER);
- EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, GPIO1_OEN, 1);
- EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, GPIO1_OUT, 1);
- falcon_write(efx, &gpio_cfg_reg_ker, GPIO_CTL_REG_KER);
+ efx_reado(efx, &gpio_cfg_reg_ker, FR_AB_GPIO_CTL);
+ EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, FRF_AB_GPIO1_OEN, 1);
+ EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, FRF_AB_GPIO1_OUT, 1);
+ efx_writeo(efx, &gpio_cfg_reg_ker, FR_AB_GPIO_CTL);
/* Initiate SRAM reset */
EFX_POPULATE_OWORD_2(srm_cfg_reg_ker,
- SRAM_OOB_BT_INIT_EN, 1,
- SRM_NUM_BANKS_AND_BANK_SIZE, 0);
- falcon_write(efx, &srm_cfg_reg_ker, SRM_CFG_REG_KER);
+ FRF_AZ_SRM_INIT_EN, 1,
+ FRF_AZ_SRM_NB_SZ, 0);
+ efx_writeo(efx, &srm_cfg_reg_ker, FR_AZ_SRM_CFG);
/* Wait for SRAM reset to complete */
count = 0;
@@ -2626,8 +2606,8 @@ static int falcon_reset_sram(struct efx_nic *efx)
schedule_timeout_uninterruptible(HZ / 50);
/* Check for reset complete */
- falcon_read(efx, &srm_cfg_reg_ker, SRM_CFG_REG_KER);
- if (!EFX_OWORD_FIELD(srm_cfg_reg_ker, SRAM_OOB_BT_INIT_EN)) {
+ efx_reado(efx, &srm_cfg_reg_ker, FR_AZ_SRM_CFG);
+ if (!EFX_OWORD_FIELD(srm_cfg_reg_ker, FRF_AZ_SRM_INIT_EN)) {
EFX_LOG(efx, "SRAM reset complete\n");
return 0;
@@ -2712,16 +2692,16 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
board_rev = le16_to_cpu(v2->board_revision);
if (le16_to_cpu(nvconfig->board_struct_ver) >= 3) {
- __le32 fl = v3->spi_device_type[EE_SPI_FLASH];
- __le32 ee = v3->spi_device_type[EE_SPI_EEPROM];
- rc = falcon_spi_device_init(efx, &efx->spi_flash,
- EE_SPI_FLASH,
- le32_to_cpu(fl));
+ rc = falcon_spi_device_init(
+ efx, &efx->spi_flash, FFE_AB_SPI_DEVICE_FLASH,
+ le32_to_cpu(v3->spi_device_type
+ [FFE_AB_SPI_DEVICE_FLASH]));
if (rc)
goto fail2;
- rc = falcon_spi_device_init(efx, &efx->spi_eeprom,
- EE_SPI_EEPROM,
- le32_to_cpu(ee));
+ rc = falcon_spi_device_init(
+ efx, &efx->spi_eeprom, FFE_AB_SPI_DEVICE_EEPROM,
+ le32_to_cpu(v3->spi_device_type
+ [FFE_AB_SPI_DEVICE_EEPROM]));
if (rc)
goto fail2;
}
@@ -2732,7 +2712,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mdio.prtad);
- efx_set_board_info(efx, board_rev);
+ falcon_probe_board(efx, board_rev);
kfree(nvconfig);
return 0;
@@ -2752,13 +2732,13 @@ static int falcon_probe_nic_variant(struct efx_nic *efx)
efx_oword_t altera_build;
efx_oword_t nic_stat;
- falcon_read(efx, &altera_build, ALTERA_BUILD_REG_KER);
- if (EFX_OWORD_FIELD(altera_build, VER_ALL)) {
+ efx_reado(efx, &altera_build, FR_AZ_ALTERA_BUILD);
+ if (EFX_OWORD_FIELD(altera_build, FRF_AZ_ALTERA_BUILD_VER)) {
EFX_ERR(efx, "Falcon FPGA not supported\n");
return -ENODEV;
}
- falcon_read(efx, &nic_stat, NIC_STAT_REG);
+ efx_reado(efx, &nic_stat, FR_AB_NIC_STAT);
switch (falcon_rev(efx)) {
case FALCON_REV_A0:
@@ -2767,7 +2747,7 @@ static int falcon_probe_nic_variant(struct efx_nic *efx)
return -ENODEV;
case FALCON_REV_A1:
- if (EFX_OWORD_FIELD(nic_stat, STRAP_PCIE) == 0) {
+ if (EFX_OWORD_FIELD(nic_stat, FRF_AA_STRAP_PCIE) == 0) {
EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n");
return -ENODEV;
}
@@ -2782,7 +2762,7 @@ static int falcon_probe_nic_variant(struct efx_nic *efx)
}
/* Initial assumed speed */
- efx->link_speed = EFX_OWORD_FIELD(nic_stat, STRAP_10G) ? 10000 : 1000;
+ efx->link_speed = EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) ? 10000 : 1000;
return 0;
}
@@ -2793,34 +2773,36 @@ static void falcon_probe_spi_devices(struct efx_nic *efx)
efx_oword_t nic_stat, gpio_ctl, ee_vpd_cfg;
int boot_dev;
- falcon_read(efx, &gpio_ctl, GPIO_CTL_REG_KER);
- falcon_read(efx, &nic_stat, NIC_STAT_REG);
- falcon_read(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER);
+ efx_reado(efx, &gpio_ctl, FR_AB_GPIO_CTL);
+ efx_reado(efx, &nic_stat, FR_AB_NIC_STAT);
+ efx_reado(efx, &ee_vpd_cfg, FR_AB_EE_VPD_CFG0);
- if (EFX_OWORD_FIELD(gpio_ctl, BOOTED_USING_NVDEVICE)) {
- boot_dev = (EFX_OWORD_FIELD(nic_stat, SF_PRST) ?
- EE_SPI_FLASH : EE_SPI_EEPROM);
+ if (EFX_OWORD_FIELD(gpio_ctl, FRF_AB_GPIO3_PWRUP_VALUE)) {
+ boot_dev = (EFX_OWORD_FIELD(nic_stat, FRF_AB_SF_PRST) ?
+ FFE_AB_SPI_DEVICE_FLASH : FFE_AB_SPI_DEVICE_EEPROM);
EFX_LOG(efx, "Booted from %s\n",
- boot_dev == EE_SPI_FLASH ? "flash" : "EEPROM");
+ boot_dev == FFE_AB_SPI_DEVICE_FLASH ? "flash" : "EEPROM");
} else {
/* Disable VPD and set clock dividers to safe
* values for initial programming. */
boot_dev = -1;
EFX_LOG(efx, "Booted from internal ASIC settings;"
" setting SPI config\n");
- EFX_POPULATE_OWORD_3(ee_vpd_cfg, EE_VPD_EN, 0,
+ EFX_POPULATE_OWORD_3(ee_vpd_cfg, FRF_AB_EE_VPD_EN, 0,
/* 125 MHz / 7 ~= 20 MHz */
- EE_SF_CLOCK_DIV, 7,
+ FRF_AB_EE_SF_CLOCK_DIV, 7,
/* 125 MHz / 63 ~= 2 MHz */
- EE_EE_CLOCK_DIV, 63);
- falcon_write(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER);
+ FRF_AB_EE_EE_CLOCK_DIV, 63);
+ efx_writeo(efx, &ee_vpd_cfg, FR_AB_EE_VPD_CFG0);
}
- if (boot_dev == EE_SPI_FLASH)
- falcon_spi_device_init(efx, &efx->spi_flash, EE_SPI_FLASH,
+ if (boot_dev == FFE_AB_SPI_DEVICE_FLASH)
+ falcon_spi_device_init(efx, &efx->spi_flash,
+ FFE_AB_SPI_DEVICE_FLASH,
default_flash_type);
- if (boot_dev == EE_SPI_EEPROM)
- falcon_spi_device_init(efx, &efx->spi_eeprom, EE_SPI_EEPROM,
+ if (boot_dev == FFE_AB_SPI_DEVICE_EEPROM)
+ falcon_spi_device_init(efx, &efx->spi_eeprom,
+ FFE_AB_SPI_DEVICE_EEPROM,
large_eeprom_type);
}
@@ -2911,6 +2893,52 @@ int falcon_probe_nic(struct efx_nic *efx)
return rc;
}
+static void falcon_init_rx_cfg(struct efx_nic *efx)
+{
+ /* Prior to Siena the RX DMA engine will split each frame at
+ * intervals of RX_USR_BUF_SIZE (32-byte units). We set it to
+ * be so large that that never happens. */
+ const unsigned huge_buf_size = (3 * 4096) >> 5;
+ /* RX control FIFO thresholds (32 entries) */
+ const unsigned ctrl_xon_thr = 20;
+ const unsigned ctrl_xoff_thr = 25;
+ /* RX data FIFO thresholds (256-byte units; size varies) */
+ int data_xon_thr = rx_xon_thresh_bytes >> 8;
+ int data_xoff_thr = rx_xoff_thresh_bytes >> 8;
+ efx_oword_t reg;
+
+ efx_reado(efx, &reg, FR_AZ_RX_CFG);
+ if (falcon_rev(efx) <= FALCON_REV_A1) {
+ /* Data FIFO size is 5.5K */
+ if (data_xon_thr < 0)
+ data_xon_thr = 512 >> 8;
+ if (data_xoff_thr < 0)
+ data_xoff_thr = 2048 >> 8;
+ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_DESC_PUSH_EN, 0);
+ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_USR_BUF_SIZE,
+ huge_buf_size);
+ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_MAC_TH, data_xon_thr);
+ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_MAC_TH, data_xoff_thr);
+ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_TX_TH, ctrl_xon_thr);
+ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_TX_TH, ctrl_xoff_thr);
+ } else {
+ /* Data FIFO size is 80K; register fields moved */
+ if (data_xon_thr < 0)
+ data_xon_thr = 27648 >> 8; /* ~3*max MTU */
+ if (data_xoff_thr < 0)
+ data_xoff_thr = 54272 >> 8; /* ~80Kb - 3*max MTU */
+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_DESC_PUSH_EN, 0);
+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_USR_BUF_SIZE,
+ huge_buf_size);
+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_MAC_TH, data_xon_thr);
+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_MAC_TH, data_xoff_thr);
+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_TX_TH, ctrl_xon_thr);
+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_TX_TH, ctrl_xoff_thr);
+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1);
+ }
+ efx_writeo(efx, &reg, FR_AZ_RX_CFG);
+}
+
/* This call performs hardware-specific global initialisation, such as
* defining the descriptor cache sizes and number of RSS channels.
* It does not set up any buffers, descriptor rings or event queues.
@@ -2918,56 +2946,51 @@ int falcon_probe_nic(struct efx_nic *efx)
int falcon_init_nic(struct efx_nic *efx)
{
efx_oword_t temp;
- unsigned thresh;
int rc;
/* Use on-chip SRAM */
- falcon_read(efx, &temp, NIC_STAT_REG);
- EFX_SET_OWORD_FIELD(temp, ONCHIP_SRAM, 1);
- falcon_write(efx, &temp, NIC_STAT_REG);
+ efx_reado(efx, &temp, FR_AB_NIC_STAT);
+ 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 (falcon_rev(efx) == FALCON_REV_B0) {
- falcon_read(efx, &temp, GPIO_CTL_REG_KER);
- EFX_SET_OWORD_FIELD(temp, GPIO_USE_NIC_CLK, true);
- falcon_write(efx, &temp, GPIO_CTL_REG_KER);
+ 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);
}
- /* Set buffer table mode */
- EFX_POPULATE_OWORD_1(temp, BUF_TBL_MODE, BUF_TBL_MODE_FULL);
- falcon_write(efx, &temp, BUF_TBL_CFG_REG_KER);
-
rc = falcon_reset_sram(efx);
if (rc)
return rc;
/* Set positions of descriptor caches in SRAM. */
- EFX_POPULATE_OWORD_1(temp, SRM_TX_DC_BASE_ADR, TX_DC_BASE / 8);
- falcon_write(efx, &temp, SRM_TX_DC_CFG_REG_KER);
- EFX_POPULATE_OWORD_1(temp, SRM_RX_DC_BASE_ADR, RX_DC_BASE / 8);
- falcon_write(efx, &temp, SRM_RX_DC_CFG_REG_KER);
+ EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_TX_DC_BASE_ADR, TX_DC_BASE / 8);
+ efx_writeo(efx, &temp, FR_AZ_SRM_TX_DC_CFG);
+ EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_RX_DC_BASE_ADR, RX_DC_BASE / 8);
+ efx_writeo(efx, &temp, FR_AZ_SRM_RX_DC_CFG);
/* Set TX descriptor cache size. */
BUILD_BUG_ON(TX_DC_ENTRIES != (16 << TX_DC_ENTRIES_ORDER));
- EFX_POPULATE_OWORD_1(temp, TX_DC_SIZE, TX_DC_ENTRIES_ORDER);
- falcon_write(efx, &temp, TX_DC_CFG_REG_KER);
+ EFX_POPULATE_OWORD_1(temp, FRF_AZ_TX_DC_SIZE, TX_DC_ENTRIES_ORDER);
+ efx_writeo(efx, &temp, FR_AZ_TX_DC_CFG);
/* Set RX descriptor cache size. Set low watermark to size-8, as
* this allows most efficient prefetching.
*/
BUILD_BUG_ON(RX_DC_ENTRIES != (16 << RX_DC_ENTRIES_ORDER));
- EFX_POPULATE_OWORD_1(temp, RX_DC_SIZE, RX_DC_ENTRIES_ORDER);
- falcon_write(efx, &temp, RX_DC_CFG_REG_KER);
- EFX_POPULATE_OWORD_1(temp, RX_DC_PF_LWM, RX_DC_ENTRIES - 8);
- falcon_write(efx, &temp, RX_DC_PF_WM_REG_KER);
+ EFX_POPULATE_OWORD_1(temp, FRF_AZ_RX_DC_SIZE, RX_DC_ENTRIES_ORDER);
+ efx_writeo(efx, &temp, FR_AZ_RX_DC_CFG);
+ EFX_POPULATE_OWORD_1(temp, FRF_AZ_RX_DC_PF_LWM, RX_DC_ENTRIES - 8);
+ efx_writeo(efx, &temp, FR_AZ_RX_DC_PF_WM);
/* Clear the parity enables on the TX data fifos as
* they produce false parity errors because of timing issues
*/
if (EFX_WORKAROUND_5129(efx)) {
- falcon_read(efx, &temp, SPARE_REG_KER);
- EFX_SET_OWORD_FIELD(temp, MEM_PERR_EN_TX_DATA, 0);
- falcon_write(efx, &temp, SPARE_REG_KER);
+ efx_reado(efx, &temp, FR_AZ_CSR_SPARE);
+ EFX_SET_OWORD_FIELD(temp, FRF_AB_MEM_PERR_EN_TX_DATA, 0);
+ efx_writeo(efx, &temp, FR_AZ_CSR_SPARE);
}
/* Enable all the genuinely fatal interrupts. (They are still
@@ -2977,83 +3000,65 @@ int falcon_init_nic(struct efx_nic *efx)
* Note: All other fatal interrupts are enabled
*/
EFX_POPULATE_OWORD_3(temp,
- ILL_ADR_INT_KER_EN, 1,
- RBUF_OWN_INT_KER_EN, 1,
- TBUF_OWN_INT_KER_EN, 1);
+ FRF_AZ_ILL_ADR_INT_KER_EN, 1,
+ FRF_AZ_RBUF_OWN_INT_KER_EN, 1,
+ FRF_AZ_TBUF_OWN_INT_KER_EN, 1);
EFX_INVERT_OWORD(temp);
- falcon_write(efx, &temp, FATAL_INTR_REG_KER);
+ efx_writeo(efx, &temp, FR_AZ_FATAL_INTR_KER);
if (EFX_WORKAROUND_7244(efx)) {
- falcon_read(efx, &temp, RX_FILTER_CTL_REG);
- EFX_SET_OWORD_FIELD(temp, UDP_FULL_SRCH_LIMIT, 8);
- EFX_SET_OWORD_FIELD(temp, UDP_WILD_SRCH_LIMIT, 8);
- EFX_SET_OWORD_FIELD(temp, TCP_FULL_SRCH_LIMIT, 8);
- EFX_SET_OWORD_FIELD(temp, TCP_WILD_SRCH_LIMIT, 8);
- falcon_write(efx, &temp, RX_FILTER_CTL_REG);
+ efx_reado(efx, &temp, FR_BZ_RX_FILTER_CTL);
+ EFX_SET_OWORD_FIELD(temp, FRF_BZ_UDP_FULL_SRCH_LIMIT, 8);
+ EFX_SET_OWORD_FIELD(temp, FRF_BZ_UDP_WILD_SRCH_LIMIT, 8);
+ EFX_SET_OWORD_FIELD(temp, FRF_BZ_TCP_FULL_SRCH_LIMIT, 8);
+ EFX_SET_OWORD_FIELD(temp, FRF_BZ_TCP_WILD_SRCH_LIMIT, 8);
+ efx_writeo(efx, &temp, FR_BZ_RX_FILTER_CTL);
}
falcon_setup_rss_indir_table(efx);
+ /* XXX This is documented only for Falcon A0/A1 */
/* Setup RX. Wait for descriptor is broken and must
* be disabled. RXDP recovery shouldn't be needed, but is.
*/
- falcon_read(efx, &temp, RX_SELF_RST_REG_KER);
- EFX_SET_OWORD_FIELD(temp, RX_NODESC_WAIT_DIS, 1);
- EFX_SET_OWORD_FIELD(temp, RX_RECOVERY_EN, 1);
+ efx_reado(efx, &temp, FR_AA_RX_SELF_RST);
+ EFX_SET_OWORD_FIELD(temp, FRF_AA_RX_NODESC_WAIT_DIS, 1);
+ EFX_SET_OWORD_FIELD(temp, FRF_AA_RX_SELF_RST_EN, 1);
if (EFX_WORKAROUND_5583(efx))
- EFX_SET_OWORD_FIELD(temp, RX_ISCSI_DIS, 1);
- falcon_write(efx, &temp, RX_SELF_RST_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, FRF_AA_RX_ISCSI_DIS, 1);
+ efx_writeo(efx, &temp, FR_AA_RX_SELF_RST);
/* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be
* controlled by the RX FIFO fill level. Set arbitration to one pkt/Q.
*/
- falcon_read(efx, &temp, TX_CFG2_REG_KER);
- EFX_SET_OWORD_FIELD(temp, TX_RX_SPACER, 0xfe);
- EFX_SET_OWORD_FIELD(temp, TX_RX_SPACER_EN, 1);
- EFX_SET_OWORD_FIELD(temp, TX_ONE_PKT_PER_Q, 1);
- EFX_SET_OWORD_FIELD(temp, TX_CSR_PUSH_EN, 0);
- EFX_SET_OWORD_FIELD(temp, TX_DIS_NON_IP_EV, 1);
+ efx_reado(efx, &temp, FR_AZ_TX_RESERVED);
+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER, 0xfe);
+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER_EN, 1);
+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_ONE_PKT_PER_Q, 1);
+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PUSH_EN, 0);
+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_DIS_NON_IP_EV, 1);
/* Enable SW_EV to inherit in char driver - assume harmless here */
- EFX_SET_OWORD_FIELD(temp, TX_SW_EV_EN, 1);
+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_SOFT_EVT_EN, 1);
/* Prefetch threshold 2 => fetch when descriptor cache half empty */
- EFX_SET_OWORD_FIELD(temp, TX_PREF_THRESHOLD, 2);
+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_THRESHOLD, 2);
/* Squash TX of packets of 16 bytes or less */
if (falcon_rev(efx) >= FALCON_REV_B0 && EFX_WORKAROUND_9141(efx))
- EFX_SET_OWORD_FIELD(temp, TX_FLUSH_MIN_LEN_EN_B0, 1);
- falcon_write(efx, &temp, TX_CFG2_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1);
+ efx_writeo(efx, &temp, FR_AZ_TX_RESERVED);
/* Do not enable TX_NO_EOP_DISC_EN, since it limits packets to 16
* descriptors (which is bad).
*/
- falcon_read(efx, &temp, TX_CFG_REG_KER);
- EFX_SET_OWORD_FIELD(temp, TX_NO_EOP_DISC_EN, 0);
- falcon_write(efx, &temp, TX_CFG_REG_KER);
-
- /* RX config */
- falcon_read(efx, &temp, RX_CFG_REG_KER);
- EFX_SET_OWORD_FIELD_VER(efx, temp, RX_DESC_PUSH_EN, 0);
- if (EFX_WORKAROUND_7575(efx))
- EFX_SET_OWORD_FIELD_VER(efx, temp, RX_USR_BUF_SIZE,
- (3 * 4096) / 32);
- if (falcon_rev(efx) >= FALCON_REV_B0)
- EFX_SET_OWORD_FIELD(temp, RX_INGR_EN_B0, 1);
-
- /* RX FIFO flow control thresholds */
- thresh = ((rx_xon_thresh_bytes >= 0) ?
- rx_xon_thresh_bytes : efx->type->rx_xon_thresh);
- EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_MAC_TH, thresh / 256);
- thresh = ((rx_xoff_thresh_bytes >= 0) ?
- rx_xoff_thresh_bytes : efx->type->rx_xoff_thresh);
- EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_MAC_TH, thresh / 256);
- /* RX control FIFO thresholds [32 entries] */
- EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_TX_TH, 20);
- EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_TX_TH, 25);
- falcon_write(efx, &temp, RX_CFG_REG_KER);
+ efx_reado(efx, &temp, FR_AZ_TX_CFG);
+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_NO_EOP_DISC_EN, 0);
+ efx_writeo(efx, &temp, FR_AZ_TX_CFG);
+
+ falcon_init_rx_cfg(efx);
/* Set destination of both TX and RX Flush events */
if (falcon_rev(efx) >= FALCON_REV_B0) {
- EFX_POPULATE_OWORD_1(temp, FLS_EVQ_ID, 0);
- falcon_write(efx, &temp, DP_CTRL_REG);
+ EFX_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0);
+ efx_writeo(efx, &temp, FR_BZ_DP_CTRL);
}
return 0;
@@ -3089,8 +3094,9 @@ void falcon_update_nic_stats(struct efx_nic *efx)
{
efx_oword_t cnt;
- falcon_read(efx, &cnt, RX_NODESC_DROP_REG_KER);
- efx->n_rx_nodesc_drop_cnt += EFX_OWORD_FIELD(cnt, RX_NODESC_DROP_CNT);
+ efx_reado(efx, &cnt, FR_AZ_RX_NODESC_DROP);
+ efx->n_rx_nodesc_drop_cnt +=
+ EFX_OWORD_FIELD(cnt, FRF_AB_RX_NODESC_DROP_CNT);
}
/**************************************************************************
@@ -3101,45 +3107,31 @@ void falcon_update_nic_stats(struct efx_nic *efx)
*/
struct efx_nic_type falcon_a_nic_type = {
- .mem_bar = 2,
.mem_map_size = 0x20000,
- .txd_ptr_tbl_base = TX_DESC_PTR_TBL_KER_A1,
- .rxd_ptr_tbl_base = RX_DESC_PTR_TBL_KER_A1,
- .buf_tbl_base = BUF_TBL_KER_A1,
- .evq_ptr_tbl_base = EVQ_PTR_TBL_KER_A1,
- .evq_rptr_tbl_base = EVQ_RPTR_REG_KER_A1,
- .txd_ring_mask = FALCON_TXD_RING_MASK,
- .rxd_ring_mask = FALCON_RXD_RING_MASK,
- .evq_size = FALCON_EVQ_SIZE,
- .max_dma_mask = FALCON_DMA_MASK,
- .tx_dma_mask = FALCON_TX_DMA_MASK,
- .bug5391_mask = 0xf,
- .rx_xoff_thresh = 2048,
- .rx_xon_thresh = 512,
+ .txd_ptr_tbl_base = FR_AA_TX_DESC_PTR_TBL_KER,
+ .rxd_ptr_tbl_base = FR_AA_RX_DESC_PTR_TBL_KER,
+ .buf_tbl_base = FR_AA_BUF_FULL_TBL_KER,
+ .evq_ptr_tbl_base = FR_AA_EVQ_PTR_TBL_KER,
+ .evq_rptr_tbl_base = FR_AA_EVQ_RPTR_KER,
+ .max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH),
.rx_buffer_padding = 0x24,
.max_interrupt_mode = EFX_INT_MODE_MSI,
.phys_addr_channels = 4,
};
struct efx_nic_type falcon_b_nic_type = {
- .mem_bar = 2,
/* Map everything up to and including the RSS indirection
* table. Don't map MSI-X table, MSI-X PBA since Linux
* requires that they not be mapped. */
- .mem_map_size = RX_RSS_INDIR_TBL_B0 + 0x800,
- .txd_ptr_tbl_base = TX_DESC_PTR_TBL_KER_B0,
- .rxd_ptr_tbl_base = RX_DESC_PTR_TBL_KER_B0,
- .buf_tbl_base = BUF_TBL_KER_B0,
- .evq_ptr_tbl_base = EVQ_PTR_TBL_KER_B0,
- .evq_rptr_tbl_base = EVQ_RPTR_REG_KER_B0,
- .txd_ring_mask = FALCON_TXD_RING_MASK,
- .rxd_ring_mask = FALCON_RXD_RING_MASK,
- .evq_size = FALCON_EVQ_SIZE,
- .max_dma_mask = FALCON_DMA_MASK,
- .tx_dma_mask = FALCON_TX_DMA_MASK,
- .bug5391_mask = 0,
- .rx_xoff_thresh = 54272, /* ~80Kb - 3*max MTU */
- .rx_xon_thresh = 27648, /* ~3*max MTU */
+ .mem_map_size = (FR_BZ_RX_INDIRECTION_TBL +
+ FR_BZ_RX_INDIRECTION_TBL_STEP *
+ FR_BZ_RX_INDIRECTION_TBL_ROWS),
+ .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL,
+ .rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL,
+ .buf_tbl_base = FR_BZ_BUF_FULL_TBL,
+ .evq_ptr_tbl_base = FR_BZ_EVQ_PTR_TBL,
+ .evq_rptr_tbl_base = FR_BZ_EVQ_RPTR,
+ .max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH),
.rx_buffer_padding = 0,
.max_interrupt_mode = EFX_INT_MODE_MSIX,
.phys_addr_channels = 32, /* Hardware limit is 64, but the legacy
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
index 77f2e0db7ca1..4dd965774a90 100644
--- a/drivers/net/sfc/falcon.h
+++ b/drivers/net/sfc/falcon.h
@@ -39,6 +39,8 @@ extern struct efx_nic_type falcon_b_nic_type;
**************************************************************************
*/
+extern void falcon_probe_board(struct efx_nic *efx, u16 revision_info);
+
/* TX data path */
extern int falcon_probe_tx(struct efx_tx_queue *tx_queue);
extern void falcon_init_tx(struct efx_tx_queue *tx_queue);
@@ -89,11 +91,9 @@ extern void falcon_fini_interrupt(struct efx_nic *efx);
/* Global Resources */
extern int falcon_probe_nic(struct efx_nic *efx);
-extern int falcon_probe_resources(struct efx_nic *efx);
extern int falcon_init_nic(struct efx_nic *efx);
extern int falcon_flush_queues(struct efx_nic *efx);
extern int falcon_reset_hw(struct efx_nic *efx, enum reset_type method);
-extern void falcon_remove_resources(struct efx_nic *efx);
extern void falcon_remove_nic(struct efx_nic *efx);
extern void falcon_update_nic_stats(struct efx_nic *efx);
extern void falcon_set_multicast_hash(struct efx_nic *efx);
diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/falcon_boards.c
index cee00ad49b57..788b3365efc1 100644
--- a/drivers/net/sfc/sfe4001.c
+++ b/drivers/net/sfc/falcon_boards.c
@@ -7,6 +7,159 @@
* by the Free Software Foundation, incorporated herein by reference.
*/
+#include <linux/rtnetlink.h>
+
+#include "net_driver.h"
+#include "phy.h"
+#include "efx.h"
+#include "falcon.h"
+#include "regs.h"
+#include "io.h"
+#include "workarounds.h"
+
+/* Macros for unpacking the board revision */
+/* The revision info is in host byte order. */
+#define FALCON_BOARD_TYPE(_rev) (_rev >> 8)
+#define FALCON_BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf)
+#define FALCON_BOARD_MINOR(_rev) (_rev & 0xf)
+
+/* Board types */
+#define FALCON_BOARD_SFE4001 0x01
+#define FALCON_BOARD_SFE4002 0x02
+#define FALCON_BOARD_SFN4111T 0x51
+#define FALCON_BOARD_SFN4112F 0x52
+
+/* Blink support. If the PHY has no auto-blink mode so we hang it off a timer */
+#define BLINK_INTERVAL (HZ/2)
+
+static void blink_led_timer(unsigned long context)
+{
+ struct efx_nic *efx = (struct efx_nic *)context;
+ struct efx_board *board = &efx->board_info;
+
+ board->set_id_led(efx, board->blink_state);
+ board->blink_state = !board->blink_state;
+ if (board->blink_resubmit)
+ mod_timer(&board->blink_timer, jiffies + BLINK_INTERVAL);
+}
+
+static void board_blink(struct efx_nic *efx, bool blink)
+{
+ struct efx_board *board = &efx->board_info;
+
+ /* The rtnl mutex serialises all ethtool ioctls, so
+ * nothing special needs doing here. */
+ if (blink) {
+ board->blink_resubmit = true;
+ board->blink_state = false;
+ setup_timer(&board->blink_timer, blink_led_timer,
+ (unsigned long)efx);
+ mod_timer(&board->blink_timer, jiffies + BLINK_INTERVAL);
+ } else {
+ board->blink_resubmit = false;
+ if (board->blink_timer.function)
+ del_timer_sync(&board->blink_timer);
+ board->init_leds(efx);
+ }
+}
+
+/*****************************************************************************
+ * Support for LM87 sensor chip used on several boards
+ */
+#define LM87_REG_ALARMS1 0x41
+#define LM87_REG_ALARMS2 0x42
+#define LM87_IN_LIMITS(nr, _min, _max) \
+ 0x2B + (nr) * 2, _max, 0x2C + (nr) * 2, _min
+#define LM87_AIN_LIMITS(nr, _min, _max) \
+ 0x3B + (nr), _max, 0x1A + (nr), _min
+#define LM87_TEMP_INT_LIMITS(_min, _max) \
+ 0x39, _max, 0x3A, _min
+#define LM87_TEMP_EXT1_LIMITS(_min, _max) \
+ 0x37, _max, 0x38, _min
+
+#define LM87_ALARM_TEMP_INT 0x10
+#define LM87_ALARM_TEMP_EXT1 0x20
+
+#if defined(CONFIG_SENSORS_LM87) || defined(CONFIG_SENSORS_LM87_MODULE)
+
+static int efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info,
+ const u8 *reg_values)
+{
+ struct i2c_client *client = i2c_new_device(&efx->i2c_adap, info);
+ int rc;
+
+ if (!client)
+ return -EIO;
+
+ while (*reg_values) {
+ u8 reg = *reg_values++;
+ u8 value = *reg_values++;
+ rc = i2c_smbus_write_byte_data(client, reg, value);
+ if (rc)
+ goto err;
+ }
+
+ efx->board_info.hwmon_client = client;
+ return 0;
+
+err:
+ i2c_unregister_device(client);
+ return rc;
+}
+
+static void efx_fini_lm87(struct efx_nic *efx)
+{
+ i2c_unregister_device(efx->board_info.hwmon_client);
+}
+
+static int efx_check_lm87(struct efx_nic *efx, unsigned mask)
+{
+ struct i2c_client *client = efx->board_info.hwmon_client;
+ s32 alarms1, alarms2;
+
+ /* If link is up then do not monitor temperature */
+ if (EFX_WORKAROUND_7884(efx) && efx->link_up)
+ return 0;
+
+ alarms1 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1);
+ alarms2 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2);
+ if (alarms1 < 0)
+ return alarms1;
+ if (alarms2 < 0)
+ return alarms2;
+ alarms1 &= mask;
+ alarms2 &= mask >> 8;
+ if (alarms1 || alarms2) {
+ EFX_ERR(efx,
+ "LM87 detected a hardware failure (status %02x:%02x)"
+ "%s%s\n",
+ alarms1, alarms2,
+ (alarms1 & LM87_ALARM_TEMP_INT) ? " INTERNAL" : "",
+ (alarms1 & LM87_ALARM_TEMP_EXT1) ? " EXTERNAL" : "");
+ return -ERANGE;
+ }
+
+ return 0;
+}
+
+#else /* !CONFIG_SENSORS_LM87 */
+
+static inline int
+efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info,
+ const u8 *reg_values)
+{
+ return 0;
+}
+static inline void efx_fini_lm87(struct efx_nic *efx)
+{
+}
+static inline int efx_check_lm87(struct efx_nic *efx, unsigned mask)
+{
+ return 0;
+}
+
+#endif /* CONFIG_SENSORS_LM87 */
+
/*****************************************************************************
* Support for the SFE4001 and SFN4111T NICs.
*
@@ -23,23 +176,9 @@
* exclusive with the network device being open.
*/
-#include <linux/delay.h>
-#include <linux/rtnetlink.h>
-#include "net_driver.h"
-#include "efx.h"
-#include "phy.h"
-#include "boards.h"
-#include "falcon.h"
-#include "falcon_hwdefs.h"
-#include "falcon_io.h"
-#include "mac.h"
-#include "workarounds.h"
-
/**************************************************************************
- *
- * I2C IO Expander device
- *
- **************************************************************************/
+ * Support for I2C IO Expander device on SFE40001
+ */
#define PCA9539 0x74
#define P0_IN 0x00
@@ -188,23 +327,23 @@ static int sfn4111t_reset(struct efx_nic *efx)
efx_oword_t reg;
/* GPIO 3 and the GPIO register are shared with I2C, so block that */
- mutex_lock(&efx->i2c_adap.bus_lock);
+ rt_mutex_lock(&efx->i2c_adap.bus_lock);
/* 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. */
- falcon_read(efx, &reg, GPIO_CTL_REG_KER);
- EFX_SET_OWORD_FIELD(reg, GPIO2_OEN, true);
- falcon_write(efx, &reg, GPIO_CTL_REG_KER);
+ 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, GPIO2_OEN, false);
- EFX_SET_OWORD_FIELD(reg, GPIO3_OEN,
+ 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));
- falcon_write(efx, &reg, GPIO_CTL_REG_KER);
+ efx_writeo(efx, &reg, FR_AB_GPIO_CTL);
msleep(1);
- mutex_unlock(&efx->i2c_adap.bus_lock);
+ rt_mutex_unlock(&efx->i2c_adap.bus_lock);
ssleep(1);
return 0;
@@ -241,7 +380,7 @@ static ssize_t set_phy_flash_cfg(struct device *dev,
efx->phy_mode = new_mode;
if (new_mode & PHY_MODE_SPECIAL)
efx_stats_disable(efx);
- if (efx->board_info.type == EFX_BOARD_SFE4001)
+ if (efx->board_info.type == FALCON_BOARD_SFE4001)
err = sfe4001_poweron(efx);
else
err = sfn4111t_reset(efx);
@@ -302,7 +441,7 @@ static struct i2c_board_info sfe4001_hwmon_info = {
* be turned on before the PHY can be used.
* Context: Process context, rtnl lock held
*/
-int sfe4001_init(struct efx_nic *efx)
+static int sfe4001_init(struct efx_nic *efx)
{
int rc;
@@ -394,7 +533,7 @@ static struct i2c_board_info sfn4111t_r5_hwmon_info = {
I2C_BOARD_INFO("max6646", 0x4d),
};
-int sfn4111t_init(struct efx_nic *efx)
+static int sfn4111t_init(struct efx_nic *efx)
{
int i = 0;
int rc;
@@ -433,3 +572,181 @@ fail_hwmon:
i2c_unregister_device(efx->board_info.hwmon_client);
return rc;
}
+
+/*****************************************************************************
+ * Support for the SFE4002
+ *
+ */
+static u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */
+
+static const u8 sfe4002_lm87_regs[] = {
+ LM87_IN_LIMITS(0, 0x83, 0x91), /* 2.5V: 1.8V +/- 5% */
+ LM87_IN_LIMITS(1, 0x51, 0x5a), /* Vccp1: 1.2V +/- 5% */
+ LM87_IN_LIMITS(2, 0xb6, 0xca), /* 3.3V: 3.3V +/- 5% */
+ LM87_IN_LIMITS(3, 0xb0, 0xc9), /* 5V: 4.6-5.2V */
+ LM87_IN_LIMITS(4, 0xb0, 0xe0), /* 12V: 11-14V */
+ LM87_IN_LIMITS(5, 0x44, 0x4b), /* Vccp2: 1.0V +/- 5% */
+ LM87_AIN_LIMITS(0, 0xa0, 0xb2), /* AIN1: 1.66V +/- 5% */
+ LM87_AIN_LIMITS(1, 0x91, 0xa1), /* AIN2: 1.5V +/- 5% */
+ LM87_TEMP_INT_LIMITS(10, 60), /* board */
+ LM87_TEMP_EXT1_LIMITS(10, 70), /* Falcon */
+ 0
+};
+
+static struct i2c_board_info sfe4002_hwmon_info = {
+ I2C_BOARD_INFO("lm87", 0x2e),
+ .platform_data = &sfe4002_lm87_channel,
+};
+
+/****************************************************************************/
+/* LED allocations. Note that on rev A0 boards the schematic and the reality
+ * differ: red and green are swapped. Below is the fixed (A1) layout (there
+ * are only 3 A0 boards in existence, so no real reason to make this
+ * conditional).
+ */
+#define SFE4002_FAULT_LED (2) /* Red */
+#define SFE4002_RX_LED (0) /* Green */
+#define SFE4002_TX_LED (1) /* Amber */
+
+static void sfe4002_init_leds(struct efx_nic *efx)
+{
+ /* Set the TX and RX LEDs to reflect status and activity, and the
+ * fault LED off */
+ falcon_qt202x_set_led(efx, SFE4002_TX_LED,
+ QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT);
+ falcon_qt202x_set_led(efx, SFE4002_RX_LED,
+ QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT);
+ falcon_qt202x_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF);
+}
+
+static void sfe4002_set_id_led(struct efx_nic *efx, bool state)
+{
+ falcon_qt202x_set_led(efx, SFE4002_FAULT_LED, state ? QUAKE_LED_ON :
+ QUAKE_LED_OFF);
+}
+
+static int sfe4002_check_hw(struct efx_nic *efx)
+{
+ /* A0 board rev. 4002s report a temperature fault the whole time
+ * (bad sensor) so we mask it out. */
+ unsigned alarm_mask =
+ (efx->board_info.major == 0 && efx->board_info.minor == 0) ?
+ ~LM87_ALARM_TEMP_EXT1 : ~0;
+
+ return efx_check_lm87(efx, alarm_mask);
+}
+
+static int sfe4002_init(struct efx_nic *efx)
+{
+ int rc = efx_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs);
+ if (rc)
+ return rc;
+ efx->board_info.monitor = sfe4002_check_hw;
+ efx->board_info.init_leds = sfe4002_init_leds;
+ efx->board_info.set_id_led = sfe4002_set_id_led;
+ efx->board_info.blink = board_blink;
+ efx->board_info.fini = efx_fini_lm87;
+ return 0;
+}
+
+/*****************************************************************************
+ * Support for the SFN4112F
+ *
+ */
+static u8 sfn4112f_lm87_channel = 0x03; /* use AIN not FAN inputs */
+
+static const u8 sfn4112f_lm87_regs[] = {
+ LM87_IN_LIMITS(0, 0x83, 0x91), /* 2.5V: 1.8V +/- 5% */
+ LM87_IN_LIMITS(1, 0x51, 0x5a), /* Vccp1: 1.2V +/- 5% */
+ LM87_IN_LIMITS(2, 0xb6, 0xca), /* 3.3V: 3.3V +/- 5% */
+ LM87_IN_LIMITS(4, 0xb0, 0xe0), /* 12V: 11-14V */
+ LM87_IN_LIMITS(5, 0x44, 0x4b), /* Vccp2: 1.0V +/- 5% */
+ LM87_AIN_LIMITS(1, 0x91, 0xa1), /* AIN2: 1.5V +/- 5% */
+ LM87_TEMP_INT_LIMITS(10, 60), /* board */
+ LM87_TEMP_EXT1_LIMITS(10, 70), /* Falcon */
+ 0
+};
+
+static struct i2c_board_info sfn4112f_hwmon_info = {
+ I2C_BOARD_INFO("lm87", 0x2e),
+ .platform_data = &sfn4112f_lm87_channel,
+};
+
+#define SFN4112F_ACT_LED 0
+#define SFN4112F_LINK_LED 1
+
+static void sfn4112f_init_leds(struct efx_nic *efx)
+{
+ falcon_qt202x_set_led(efx, SFN4112F_ACT_LED,
+ QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACT);
+ falcon_qt202x_set_led(efx, SFN4112F_LINK_LED,
+ QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT);
+}
+
+static void sfn4112f_set_id_led(struct efx_nic *efx, bool state)
+{
+ falcon_qt202x_set_led(efx, SFN4112F_LINK_LED,
+ state ? QUAKE_LED_ON : QUAKE_LED_OFF);
+}
+
+static int sfn4112f_check_hw(struct efx_nic *efx)
+{
+ /* Mask out unused sensors */
+ return efx_check_lm87(efx, ~0x48);
+}
+
+static int sfn4112f_init(struct efx_nic *efx)
+{
+ int rc = efx_init_lm87(efx, &sfn4112f_hwmon_info, sfn4112f_lm87_regs);
+ if (rc)
+ return rc;
+ efx->board_info.monitor = sfn4112f_check_hw;
+ efx->board_info.init_leds = sfn4112f_init_leds;
+ efx->board_info.set_id_led = sfn4112f_set_id_led;
+ efx->board_info.blink = board_blink;
+ efx->board_info.fini = efx_fini_lm87;
+ return 0;
+}
+
+/* This will get expanded as board-specific details get moved out of the
+ * PHY drivers. */
+struct falcon_board_data {
+ u8 type;
+ const char *ref_model;
+ const char *gen_type;
+ int (*init) (struct efx_nic *nic);
+};
+
+
+static struct falcon_board_data board_data[] = {
+ { FALCON_BOARD_SFE4001, "SFE4001", "10GBASE-T adapter", sfe4001_init },
+ { FALCON_BOARD_SFE4002, "SFE4002", "XFP adapter", sfe4002_init },
+ { FALCON_BOARD_SFN4111T, "SFN4111T", "100/1000/10GBASE-T adapter",
+ sfn4111t_init },
+ { FALCON_BOARD_SFN4112F, "SFN4112F", "SFP+ adapter",
+ sfn4112f_init },
+};
+
+void falcon_probe_board(struct efx_nic *efx, u16 revision_info)
+{
+ struct falcon_board_data *data = NULL;
+ int i;
+
+ efx->board_info.type = FALCON_BOARD_TYPE(revision_info);
+ efx->board_info.major = FALCON_BOARD_MAJOR(revision_info);
+ efx->board_info.minor = FALCON_BOARD_MINOR(revision_info);
+
+ for (i = 0; i < ARRAY_SIZE(board_data); i++)
+ if (board_data[i].type == efx->board_info.type)
+ data = &board_data[i];
+
+ if (data) {
+ EFX_INFO(efx, "board is %s rev %c%d\n",
+ (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC)
+ ? data->ref_model : data->gen_type,
+ 'A' + efx->board_info.major, efx->board_info.minor);
+ efx->board_info.init = data->init;
+ } else {
+ EFX_ERR(efx, "unknown board type %d\n", efx->board_info.type);
+ }
+}
diff --git a/drivers/net/sfc/falcon_gmac.c b/drivers/net/sfc/falcon_gmac.c
index 8865eae20ac5..8a1b80d1ff28 100644
--- a/drivers/net/sfc/falcon_gmac.c
+++ b/drivers/net/sfc/falcon_gmac.c
@@ -13,9 +13,8 @@
#include "efx.h"
#include "falcon.h"
#include "mac.h"
-#include "falcon_hwdefs.h"
-#include "falcon_io.h"
-#include "gmii.h"
+#include "regs.h"
+#include "io.h"
/**************************************************************************
*
@@ -37,89 +36,89 @@ static void falcon_reconfigure_gmac(struct efx_nic *efx)
bytemode = (efx->link_speed == 1000);
EFX_POPULATE_OWORD_5(reg,
- GM_LOOP, loopback,
- GM_TX_EN, 1,
- GM_TX_FC_EN, tx_fc,
- GM_RX_EN, 1,
- GM_RX_FC_EN, rx_fc);
- falcon_write(efx, &reg, GM_CFG1_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,
- GM_IF_MODE, if_mode,
- GM_PAD_CRC_EN, 1,
- GM_LEN_CHK, 1,
- GM_FD, efx->link_fd,
- GM_PAMBL_LEN, 0x7/*datasheet recommended */);
+ FRF_AB_GM_IF_MODE, if_mode,
+ FRF_AB_GM_PAD_CRC_EN, 1,
+ FRF_AB_GM_LEN_CHK, 1,
+ FRF_AB_GM_FD, efx->link_fd,
+ FRF_AB_GM_PAMBL_LEN, 0x7/*datasheet recommended */);
- falcon_write(efx, &reg, GM_CFG2_REG);
+ 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, GM_MAX_FLEN, max_frame_len);
- falcon_write(efx, &reg, GM_MAX_FLEN_REG);
+ 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,
- GMF_FTFENREQ, 1,
- GMF_STFENREQ, 1,
- GMF_FRFENREQ, 1,
- GMF_SRFENREQ, 1,
- GMF_WTMENREQ, 1);
- falcon_write(efx, &reg, GMF_CFG0_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,
- GMF_CFGFRTH, 0x12,
- GMF_CFGXOFFRTX, 0xffff);
- falcon_write(efx, &reg, GMF_CFG1_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,
- GMF_CFGHWM, 0x3f,
- GMF_CFGLWM, 0xa);
- falcon_write(efx, &reg, GMF_CFG2_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,
- GMF_CFGHWMFT, 0x1c,
- GMF_CFGFTTH, 0x08);
- falcon_write(efx, &reg, GMF_CFG3_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, GMF_HSTFLTRFRM_PAUSE, 1);
- falcon_write(efx, &reg, GMF_CFG4_REG);
+ 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 */
- falcon_read(efx, &reg, GMF_CFG5_REG);
- EFX_SET_OWORD_FIELD(reg, GMF_CFGBYTMODE, bytemode);
- EFX_SET_OWORD_FIELD(reg, GMF_CFGHDPLX, !efx->link_fd);
- EFX_SET_OWORD_FIELD(reg, GMF_HSTDRPLT64, !efx->link_fd);
- EFX_SET_OWORD_FIELD(reg, GMF_HSTFLTRFRMDC_PAUSE, 0);
- falcon_write(efx, &reg, GMF_CFG5_REG);
+ 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, !efx->link_fd);
+ EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_HSTDRPLT64, !efx->link_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,
- GM_HWADDR_5, efx->net_dev->dev_addr[5],
- GM_HWADDR_4, efx->net_dev->dev_addr[4],
- GM_HWADDR_3, efx->net_dev->dev_addr[3],
- GM_HWADDR_2, efx->net_dev->dev_addr[2]);
- falcon_write(efx, &reg, GM_ADR1_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,
- GM_HWADDR_1, efx->net_dev->dev_addr[1],
- GM_HWADDR_0, efx->net_dev->dev_addr[0]);
- falcon_write(efx, &reg, GM_ADR2_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);
diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h
deleted file mode 100644
index 2d2261117ace..000000000000
--- a/drivers/net/sfc/falcon_hwdefs.h
+++ /dev/null
@@ -1,1333 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006-2008 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_FALCON_HWDEFS_H
-#define EFX_FALCON_HWDEFS_H
-
-/*
- * Falcon hardware value definitions.
- * Falcon is the internal codename for the SFC4000 controller that is
- * present in SFE400X evaluation boards
- */
-
-/**************************************************************************
- *
- * Falcon registers
- *
- **************************************************************************
- */
-
-/* Address region register */
-#define ADR_REGION_REG_KER 0x00
-#define ADR_REGION0_LBN 0
-#define ADR_REGION0_WIDTH 18
-#define ADR_REGION1_LBN 32
-#define ADR_REGION1_WIDTH 18
-#define ADR_REGION2_LBN 64
-#define ADR_REGION2_WIDTH 18
-#define ADR_REGION3_LBN 96
-#define ADR_REGION3_WIDTH 18
-
-/* Interrupt enable register */
-#define INT_EN_REG_KER 0x0010
-#define KER_INT_KER_LBN 3
-#define KER_INT_KER_WIDTH 1
-#define DRV_INT_EN_KER_LBN 0
-#define DRV_INT_EN_KER_WIDTH 1
-
-/* Interrupt status address register */
-#define INT_ADR_REG_KER 0x0030
-#define NORM_INT_VEC_DIS_KER_LBN 64
-#define NORM_INT_VEC_DIS_KER_WIDTH 1
-#define INT_ADR_KER_LBN 0
-#define INT_ADR_KER_WIDTH EFX_DMA_TYPE_WIDTH(64) /* not 46 for this one */
-
-/* Interrupt status register (B0 only) */
-#define INT_ISR0_B0 0x90
-#define INT_ISR1_B0 0xA0
-
-/* Interrupt acknowledge register (A0/A1 only) */
-#define INT_ACK_REG_KER_A1 0x0050
-#define INT_ACK_DUMMY_DATA_LBN 0
-#define INT_ACK_DUMMY_DATA_WIDTH 32
-
-/* Interrupt acknowledge work-around register (A0/A1 only )*/
-#define WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 0x0070
-
-/* SPI host command register */
-#define EE_SPI_HCMD_REG_KER 0x0100
-#define EE_SPI_HCMD_CMD_EN_LBN 31
-#define EE_SPI_HCMD_CMD_EN_WIDTH 1
-#define EE_WR_TIMER_ACTIVE_LBN 28
-#define EE_WR_TIMER_ACTIVE_WIDTH 1
-#define EE_SPI_HCMD_SF_SEL_LBN 24
-#define EE_SPI_HCMD_SF_SEL_WIDTH 1
-#define EE_SPI_EEPROM 0
-#define EE_SPI_FLASH 1
-#define EE_SPI_HCMD_DABCNT_LBN 16
-#define EE_SPI_HCMD_DABCNT_WIDTH 5
-#define EE_SPI_HCMD_READ_LBN 15
-#define EE_SPI_HCMD_READ_WIDTH 1
-#define EE_SPI_READ 1
-#define EE_SPI_WRITE 0
-#define EE_SPI_HCMD_DUBCNT_LBN 12
-#define EE_SPI_HCMD_DUBCNT_WIDTH 2
-#define EE_SPI_HCMD_ADBCNT_LBN 8
-#define EE_SPI_HCMD_ADBCNT_WIDTH 2
-#define EE_SPI_HCMD_ENC_LBN 0
-#define EE_SPI_HCMD_ENC_WIDTH 8
-
-/* SPI host address register */
-#define EE_SPI_HADR_REG_KER 0x0110
-#define EE_SPI_HADR_ADR_LBN 0
-#define EE_SPI_HADR_ADR_WIDTH 24
-
-/* SPI host data register */
-#define EE_SPI_HDATA_REG_KER 0x0120
-
-/* SPI/VPD config register */
-#define EE_VPD_CFG_REG_KER 0x0140
-#define EE_VPD_EN_LBN 0
-#define EE_VPD_EN_WIDTH 1
-#define EE_VPD_EN_AD9_MODE_LBN 1
-#define EE_VPD_EN_AD9_MODE_WIDTH 1
-#define EE_EE_CLOCK_DIV_LBN 112
-#define EE_EE_CLOCK_DIV_WIDTH 7
-#define EE_SF_CLOCK_DIV_LBN 120
-#define EE_SF_CLOCK_DIV_WIDTH 7
-
-/* PCIE CORE ACCESS REG */
-#define PCIE_CORE_ADDR_PCIE_DEVICE_CTRL_STAT 0x68
-#define PCIE_CORE_ADDR_PCIE_LINK_CTRL_STAT 0x70
-#define PCIE_CORE_ADDR_ACK_RPL_TIMER 0x700
-#define PCIE_CORE_ADDR_ACK_FREQ 0x70C
-
-/* NIC status register */
-#define NIC_STAT_REG 0x0200
-#define EE_STRAP_EN_LBN 31
-#define EE_STRAP_EN_WIDTH 1
-#define EE_STRAP_OVR_LBN 24
-#define EE_STRAP_OVR_WIDTH 4
-#define ONCHIP_SRAM_LBN 16
-#define ONCHIP_SRAM_WIDTH 1
-#define SF_PRST_LBN 9
-#define SF_PRST_WIDTH 1
-#define EE_PRST_LBN 8
-#define EE_PRST_WIDTH 1
-#define STRAP_PINS_LBN 0
-#define STRAP_PINS_WIDTH 3
-/* These bit definitions are extrapolated from the list of numerical
- * values for STRAP_PINS.
- */
-#define STRAP_10G_LBN 2
-#define STRAP_10G_WIDTH 1
-#define STRAP_PCIE_LBN 0
-#define STRAP_PCIE_WIDTH 1
-
-#define BOOTED_USING_NVDEVICE_LBN 3
-#define BOOTED_USING_NVDEVICE_WIDTH 1
-
-/* GPIO control register */
-#define GPIO_CTL_REG_KER 0x0210
-#define GPIO_USE_NIC_CLK_LBN (30)
-#define GPIO_USE_NIC_CLK_WIDTH (1)
-#define GPIO_OUTPUTS_LBN (16)
-#define GPIO_OUTPUTS_WIDTH (4)
-#define GPIO_INPUTS_LBN (8)
-#define GPIO_DIRECTION_LBN (24)
-#define GPIO_DIRECTION_WIDTH (4)
-#define GPIO_DIRECTION_OUT (1)
-#define GPIO_SRAM_SLEEP (1 << 1)
-
-#define GPIO3_OEN_LBN (GPIO_DIRECTION_LBN + 3)
-#define GPIO3_OEN_WIDTH 1
-#define GPIO2_OEN_LBN (GPIO_DIRECTION_LBN + 2)
-#define GPIO2_OEN_WIDTH 1
-#define GPIO1_OEN_LBN (GPIO_DIRECTION_LBN + 1)
-#define GPIO1_OEN_WIDTH 1
-#define GPIO0_OEN_LBN (GPIO_DIRECTION_LBN + 0)
-#define GPIO0_OEN_WIDTH 1
-
-#define GPIO3_OUT_LBN (GPIO_OUTPUTS_LBN + 3)
-#define GPIO3_OUT_WIDTH 1
-#define GPIO2_OUT_LBN (GPIO_OUTPUTS_LBN + 2)
-#define GPIO2_OUT_WIDTH 1
-#define GPIO1_OUT_LBN (GPIO_OUTPUTS_LBN + 1)
-#define GPIO1_OUT_WIDTH 1
-#define GPIO0_OUT_LBN (GPIO_OUTPUTS_LBN + 0)
-#define GPIO0_OUT_WIDTH 1
-
-#define GPIO3_IN_LBN (GPIO_INPUTS_LBN + 3)
-#define GPIO3_IN_WIDTH 1
-#define GPIO2_IN_WIDTH 1
-#define GPIO1_IN_WIDTH 1
-#define GPIO0_IN_LBN (GPIO_INPUTS_LBN + 0)
-#define GPIO0_IN_WIDTH 1
-
-/* Global control register */
-#define GLB_CTL_REG_KER 0x0220
-#define EXT_PHY_RST_CTL_LBN 63
-#define EXT_PHY_RST_CTL_WIDTH 1
-#define PCIE_SD_RST_CTL_LBN 61
-#define PCIE_SD_RST_CTL_WIDTH 1
-
-#define PCIE_NSTCK_RST_CTL_LBN 58
-#define PCIE_NSTCK_RST_CTL_WIDTH 1
-#define PCIE_CORE_RST_CTL_LBN 57
-#define PCIE_CORE_RST_CTL_WIDTH 1
-#define EE_RST_CTL_LBN 49
-#define EE_RST_CTL_WIDTH 1
-#define RST_XGRX_LBN 24
-#define RST_XGRX_WIDTH 1
-#define RST_XGTX_LBN 23
-#define RST_XGTX_WIDTH 1
-#define RST_EM_LBN 22
-#define RST_EM_WIDTH 1
-#define EXT_PHY_RST_DUR_LBN 1
-#define EXT_PHY_RST_DUR_WIDTH 3
-#define SWRST_LBN 0
-#define SWRST_WIDTH 1
-#define INCLUDE_IN_RESET 0
-#define EXCLUDE_FROM_RESET 1
-
-/* Fatal interrupt register */
-#define FATAL_INTR_REG_KER 0x0230
-#define RBUF_OWN_INT_KER_EN_LBN 39
-#define RBUF_OWN_INT_KER_EN_WIDTH 1
-#define TBUF_OWN_INT_KER_EN_LBN 38
-#define TBUF_OWN_INT_KER_EN_WIDTH 1
-#define ILL_ADR_INT_KER_EN_LBN 33
-#define ILL_ADR_INT_KER_EN_WIDTH 1
-#define MEM_PERR_INT_KER_LBN 8
-#define MEM_PERR_INT_KER_WIDTH 1
-#define INT_KER_ERROR_LBN 0
-#define INT_KER_ERROR_WIDTH 12
-
-#define DP_CTRL_REG 0x250
-#define FLS_EVQ_ID_LBN 0
-#define FLS_EVQ_ID_WIDTH 11
-
-#define MEM_STAT_REG_KER 0x260
-
-/* Debug probe register */
-#define DEBUG_BLK_SEL_MISC 7
-#define DEBUG_BLK_SEL_SERDES 6
-#define DEBUG_BLK_SEL_EM 5
-#define DEBUG_BLK_SEL_SR 4
-#define DEBUG_BLK_SEL_EV 3
-#define DEBUG_BLK_SEL_RX 2
-#define DEBUG_BLK_SEL_TX 1
-#define DEBUG_BLK_SEL_BIU 0
-
-/* FPGA build version */
-#define ALTERA_BUILD_REG_KER 0x0300
-#define VER_ALL_LBN 0
-#define VER_ALL_WIDTH 32
-
-/* Spare EEPROM bits register (flash 0x390) */
-#define SPARE_REG_KER 0x310
-#define MEM_PERR_EN_TX_DATA_LBN 72
-#define MEM_PERR_EN_TX_DATA_WIDTH 2
-
-/* Timer table for kernel access */
-#define TIMER_CMD_REG_KER 0x420
-#define TIMER_MODE_LBN 12
-#define TIMER_MODE_WIDTH 2
-#define TIMER_MODE_DIS 0
-#define TIMER_MODE_INT_HLDOFF 2
-#define TIMER_VAL_LBN 0
-#define TIMER_VAL_WIDTH 12
-
-/* Driver generated event register */
-#define DRV_EV_REG_KER 0x440
-#define DRV_EV_QID_LBN 64
-#define DRV_EV_QID_WIDTH 12
-#define DRV_EV_DATA_LBN 0
-#define DRV_EV_DATA_WIDTH 64
-
-/* Buffer table configuration register */
-#define BUF_TBL_CFG_REG_KER 0x600
-#define BUF_TBL_MODE_LBN 3
-#define BUF_TBL_MODE_WIDTH 1
-#define BUF_TBL_MODE_HALF 0
-#define BUF_TBL_MODE_FULL 1
-
-/* SRAM receive descriptor cache configuration register */
-#define SRM_RX_DC_CFG_REG_KER 0x610
-#define SRM_RX_DC_BASE_ADR_LBN 0
-#define SRM_RX_DC_BASE_ADR_WIDTH 21
-
-/* SRAM transmit descriptor cache configuration register */
-#define SRM_TX_DC_CFG_REG_KER 0x620
-#define SRM_TX_DC_BASE_ADR_LBN 0
-#define SRM_TX_DC_BASE_ADR_WIDTH 21
-
-/* SRAM configuration register */
-#define SRM_CFG_REG_KER 0x630
-#define SRAM_OOB_BT_INIT_EN_LBN 3
-#define SRAM_OOB_BT_INIT_EN_WIDTH 1
-#define SRM_NUM_BANKS_AND_BANK_SIZE_LBN 0
-#define SRM_NUM_BANKS_AND_BANK_SIZE_WIDTH 3
-#define SRM_NB_BSZ_1BANKS_2M 0
-#define SRM_NB_BSZ_1BANKS_4M 1
-#define SRM_NB_BSZ_1BANKS_8M 2
-#define SRM_NB_BSZ_DEFAULT 3 /* char driver will set the default */
-#define SRM_NB_BSZ_2BANKS_4M 4
-#define SRM_NB_BSZ_2BANKS_8M 5
-#define SRM_NB_BSZ_2BANKS_16M 6
-#define SRM_NB_BSZ_RESERVED 7
-
-/* Special buffer table update register */
-#define BUF_TBL_UPD_REG_KER 0x0650
-#define BUF_UPD_CMD_LBN 63
-#define BUF_UPD_CMD_WIDTH 1
-#define BUF_CLR_CMD_LBN 62
-#define BUF_CLR_CMD_WIDTH 1
-#define BUF_CLR_END_ID_LBN 32
-#define BUF_CLR_END_ID_WIDTH 20
-#define BUF_CLR_START_ID_LBN 0
-#define BUF_CLR_START_ID_WIDTH 20
-
-/* Receive configuration register */
-#define RX_CFG_REG_KER 0x800
-
-/* B0 */
-#define RX_INGR_EN_B0_LBN 47
-#define RX_INGR_EN_B0_WIDTH 1
-#define RX_DESC_PUSH_EN_B0_LBN 43
-#define RX_DESC_PUSH_EN_B0_WIDTH 1
-#define RX_XON_TX_TH_B0_LBN 33
-#define RX_XON_TX_TH_B0_WIDTH 5
-#define RX_XOFF_TX_TH_B0_LBN 28
-#define RX_XOFF_TX_TH_B0_WIDTH 5
-#define RX_USR_BUF_SIZE_B0_LBN 19
-#define RX_USR_BUF_SIZE_B0_WIDTH 9
-#define RX_XON_MAC_TH_B0_LBN 10
-#define RX_XON_MAC_TH_B0_WIDTH 9
-#define RX_XOFF_MAC_TH_B0_LBN 1
-#define RX_XOFF_MAC_TH_B0_WIDTH 9
-#define RX_XOFF_MAC_EN_B0_LBN 0
-#define RX_XOFF_MAC_EN_B0_WIDTH 1
-
-/* A1 */
-#define RX_DESC_PUSH_EN_A1_LBN 35
-#define RX_DESC_PUSH_EN_A1_WIDTH 1
-#define RX_XON_TX_TH_A1_LBN 25
-#define RX_XON_TX_TH_A1_WIDTH 5
-#define RX_XOFF_TX_TH_A1_LBN 20
-#define RX_XOFF_TX_TH_A1_WIDTH 5
-#define RX_USR_BUF_SIZE_A1_LBN 11
-#define RX_USR_BUF_SIZE_A1_WIDTH 9
-#define RX_XON_MAC_TH_A1_LBN 6
-#define RX_XON_MAC_TH_A1_WIDTH 5
-#define RX_XOFF_MAC_TH_A1_LBN 1
-#define RX_XOFF_MAC_TH_A1_WIDTH 5
-#define RX_XOFF_MAC_EN_A1_LBN 0
-#define RX_XOFF_MAC_EN_A1_WIDTH 1
-
-/* Receive filter control register */
-#define RX_FILTER_CTL_REG 0x810
-#define UDP_FULL_SRCH_LIMIT_LBN 32
-#define UDP_FULL_SRCH_LIMIT_WIDTH 8
-#define NUM_KER_LBN 24
-#define NUM_KER_WIDTH 2
-#define UDP_WILD_SRCH_LIMIT_LBN 16
-#define UDP_WILD_SRCH_LIMIT_WIDTH 8
-#define TCP_WILD_SRCH_LIMIT_LBN 8
-#define TCP_WILD_SRCH_LIMIT_WIDTH 8
-#define TCP_FULL_SRCH_LIMIT_LBN 0
-#define TCP_FULL_SRCH_LIMIT_WIDTH 8
-
-/* RX queue flush register */
-#define RX_FLUSH_DESCQ_REG_KER 0x0820
-#define RX_FLUSH_DESCQ_CMD_LBN 24
-#define RX_FLUSH_DESCQ_CMD_WIDTH 1
-#define RX_FLUSH_DESCQ_LBN 0
-#define RX_FLUSH_DESCQ_WIDTH 12
-
-/* Receive descriptor update register */
-#define RX_DESC_UPD_REG_KER_DWORD (0x830 + 12)
-#define RX_DESC_WPTR_DWORD_LBN 0
-#define RX_DESC_WPTR_DWORD_WIDTH 12
-
-/* Receive descriptor cache configuration register */
-#define RX_DC_CFG_REG_KER 0x840
-#define RX_DC_SIZE_LBN 0
-#define RX_DC_SIZE_WIDTH 2
-
-#define RX_DC_PF_WM_REG_KER 0x850
-#define RX_DC_PF_LWM_LBN 0
-#define RX_DC_PF_LWM_WIDTH 6
-
-/* RX no descriptor drop counter */
-#define RX_NODESC_DROP_REG_KER 0x880
-#define RX_NODESC_DROP_CNT_LBN 0
-#define RX_NODESC_DROP_CNT_WIDTH 16
-
-/* RX black magic register */
-#define RX_SELF_RST_REG_KER 0x890
-#define RX_ISCSI_DIS_LBN 17
-#define RX_ISCSI_DIS_WIDTH 1
-#define RX_NODESC_WAIT_DIS_LBN 9
-#define RX_NODESC_WAIT_DIS_WIDTH 1
-#define RX_RECOVERY_EN_LBN 8
-#define RX_RECOVERY_EN_WIDTH 1
-
-/* TX queue flush register */
-#define TX_FLUSH_DESCQ_REG_KER 0x0a00
-#define TX_FLUSH_DESCQ_CMD_LBN 12
-#define TX_FLUSH_DESCQ_CMD_WIDTH 1
-#define TX_FLUSH_DESCQ_LBN 0
-#define TX_FLUSH_DESCQ_WIDTH 12
-
-/* Transmit descriptor update register */
-#define TX_DESC_UPD_REG_KER_DWORD (0xa10 + 12)
-#define TX_DESC_WPTR_DWORD_LBN 0
-#define TX_DESC_WPTR_DWORD_WIDTH 12
-
-/* Transmit descriptor cache configuration register */
-#define TX_DC_CFG_REG_KER 0xa20
-#define TX_DC_SIZE_LBN 0
-#define TX_DC_SIZE_WIDTH 2
-
-/* Transmit checksum configuration register (A0/A1 only) */
-#define TX_CHKSM_CFG_REG_KER_A1 0xa30
-
-/* Transmit configuration register */
-#define TX_CFG_REG_KER 0xa50
-#define TX_NO_EOP_DISC_EN_LBN 5
-#define TX_NO_EOP_DISC_EN_WIDTH 1
-
-/* Transmit configuration register 2 */
-#define TX_CFG2_REG_KER 0xa80
-#define TX_CSR_PUSH_EN_LBN 89
-#define TX_CSR_PUSH_EN_WIDTH 1
-#define TX_RX_SPACER_LBN 64
-#define TX_RX_SPACER_WIDTH 8
-#define TX_SW_EV_EN_LBN 59
-#define TX_SW_EV_EN_WIDTH 1
-#define TX_RX_SPACER_EN_LBN 57
-#define TX_RX_SPACER_EN_WIDTH 1
-#define TX_PREF_THRESHOLD_LBN 19
-#define TX_PREF_THRESHOLD_WIDTH 2
-#define TX_ONE_PKT_PER_Q_LBN 18
-#define TX_ONE_PKT_PER_Q_WIDTH 1
-#define TX_DIS_NON_IP_EV_LBN 17
-#define TX_DIS_NON_IP_EV_WIDTH 1
-#define TX_FLUSH_MIN_LEN_EN_B0_LBN 7
-#define TX_FLUSH_MIN_LEN_EN_B0_WIDTH 1
-
-/* PHY management transmit data register */
-#define MD_TXD_REG_KER 0xc00
-#define MD_TXD_LBN 0
-#define MD_TXD_WIDTH 16
-
-/* PHY management receive data register */
-#define MD_RXD_REG_KER 0xc10
-#define MD_RXD_LBN 0
-#define MD_RXD_WIDTH 16
-
-/* PHY management configuration & status register */
-#define MD_CS_REG_KER 0xc20
-#define MD_GC_LBN 4
-#define MD_GC_WIDTH 1
-#define MD_RIC_LBN 2
-#define MD_RIC_WIDTH 1
-#define MD_RDC_LBN 1
-#define MD_RDC_WIDTH 1
-#define MD_WRC_LBN 0
-#define MD_WRC_WIDTH 1
-
-/* PHY management PHY address register */
-#define MD_PHY_ADR_REG_KER 0xc30
-#define MD_PHY_ADR_LBN 0
-#define MD_PHY_ADR_WIDTH 16
-
-/* PHY management ID register */
-#define MD_ID_REG_KER 0xc40
-#define MD_PRT_ADR_LBN 11
-#define MD_PRT_ADR_WIDTH 5
-#define MD_DEV_ADR_LBN 6
-#define MD_DEV_ADR_WIDTH 5
-
-/* PHY management status & mask register (DWORD read only) */
-#define MD_STAT_REG_KER 0xc50
-#define MD_BSERR_LBN 2
-#define MD_BSERR_WIDTH 1
-#define MD_LNFL_LBN 1
-#define MD_LNFL_WIDTH 1
-#define MD_BSY_LBN 0
-#define MD_BSY_WIDTH 1
-
-/* Port 0 and 1 MAC stats registers */
-#define MAC0_STAT_DMA_REG_KER 0xc60
-#define MAC_STAT_DMA_CMD_LBN 48
-#define MAC_STAT_DMA_CMD_WIDTH 1
-#define MAC_STAT_DMA_ADR_LBN 0
-#define MAC_STAT_DMA_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46)
-
-/* Port 0 and 1 MAC control registers */
-#define MAC0_CTRL_REG_KER 0xc80
-#define MAC_XOFF_VAL_LBN 16
-#define MAC_XOFF_VAL_WIDTH 16
-#define TXFIFO_DRAIN_EN_B0_LBN 7
-#define TXFIFO_DRAIN_EN_B0_WIDTH 1
-#define MAC_BCAD_ACPT_LBN 4
-#define MAC_BCAD_ACPT_WIDTH 1
-#define MAC_UC_PROM_LBN 3
-#define MAC_UC_PROM_WIDTH 1
-#define MAC_LINK_STATUS_LBN 2
-#define MAC_LINK_STATUS_WIDTH 1
-#define MAC_SPEED_LBN 0
-#define MAC_SPEED_WIDTH 2
-
-/* 10G XAUI XGXS default values */
-#define XX_TXDRV_DEQ_DEFAULT 0xe /* deq=.6 */
-#define XX_TXDRV_DTX_DEFAULT 0x5 /* 1.25 */
-#define XX_SD_CTL_DRV_DEFAULT 0 /* 20mA */
-
-/* Multicast address hash table */
-#define MAC_MCAST_HASH_REG0_KER 0xca0
-#define MAC_MCAST_HASH_REG1_KER 0xcb0
-
-/* GMAC configuration register 1 */
-#define GM_CFG1_REG 0xe00
-#define GM_SW_RST_LBN 31
-#define GM_SW_RST_WIDTH 1
-#define GM_LOOP_LBN 8
-#define GM_LOOP_WIDTH 1
-#define GM_RX_FC_EN_LBN 5
-#define GM_RX_FC_EN_WIDTH 1
-#define GM_TX_FC_EN_LBN 4
-#define GM_TX_FC_EN_WIDTH 1
-#define GM_RX_EN_LBN 2
-#define GM_RX_EN_WIDTH 1
-#define GM_TX_EN_LBN 0
-#define GM_TX_EN_WIDTH 1
-
-/* GMAC configuration register 2 */
-#define GM_CFG2_REG 0xe10
-#define GM_PAMBL_LEN_LBN 12
-#define GM_PAMBL_LEN_WIDTH 4
-#define GM_IF_MODE_LBN 8
-#define GM_IF_MODE_WIDTH 2
-#define GM_LEN_CHK_LBN 4
-#define GM_LEN_CHK_WIDTH 1
-#define GM_PAD_CRC_EN_LBN 2
-#define GM_PAD_CRC_EN_WIDTH 1
-#define GM_FD_LBN 0
-#define GM_FD_WIDTH 1
-
-/* GMAC maximum frame length register */
-#define GM_MAX_FLEN_REG 0xe40
-#define GM_MAX_FLEN_LBN 0
-#define GM_MAX_FLEN_WIDTH 16
-
-/* GMAC station address register 1 */
-#define GM_ADR1_REG 0xf00
-#define GM_HWADDR_5_LBN 24
-#define GM_HWADDR_5_WIDTH 8
-#define GM_HWADDR_4_LBN 16
-#define GM_HWADDR_4_WIDTH 8
-#define GM_HWADDR_3_LBN 8
-#define GM_HWADDR_3_WIDTH 8
-#define GM_HWADDR_2_LBN 0
-#define GM_HWADDR_2_WIDTH 8
-
-/* GMAC station address register 2 */
-#define GM_ADR2_REG 0xf10
-#define GM_HWADDR_1_LBN 24
-#define GM_HWADDR_1_WIDTH 8
-#define GM_HWADDR_0_LBN 16
-#define GM_HWADDR_0_WIDTH 8
-
-/* GMAC FIFO configuration register 0 */
-#define GMF_CFG0_REG 0xf20
-#define GMF_FTFENREQ_LBN 12
-#define GMF_FTFENREQ_WIDTH 1
-#define GMF_STFENREQ_LBN 11
-#define GMF_STFENREQ_WIDTH 1
-#define GMF_FRFENREQ_LBN 10
-#define GMF_FRFENREQ_WIDTH 1
-#define GMF_SRFENREQ_LBN 9
-#define GMF_SRFENREQ_WIDTH 1
-#define GMF_WTMENREQ_LBN 8
-#define GMF_WTMENREQ_WIDTH 1
-
-/* GMAC FIFO configuration register 1 */
-#define GMF_CFG1_REG 0xf30
-#define GMF_CFGFRTH_LBN 16
-#define GMF_CFGFRTH_WIDTH 5
-#define GMF_CFGXOFFRTX_LBN 0
-#define GMF_CFGXOFFRTX_WIDTH 16
-
-/* GMAC FIFO configuration register 2 */
-#define GMF_CFG2_REG 0xf40
-#define GMF_CFGHWM_LBN 16
-#define GMF_CFGHWM_WIDTH 6
-#define GMF_CFGLWM_LBN 0
-#define GMF_CFGLWM_WIDTH 6
-
-/* GMAC FIFO configuration register 3 */
-#define GMF_CFG3_REG 0xf50
-#define GMF_CFGHWMFT_LBN 16
-#define GMF_CFGHWMFT_WIDTH 6
-#define GMF_CFGFTTH_LBN 0
-#define GMF_CFGFTTH_WIDTH 6
-
-/* GMAC FIFO configuration register 4 */
-#define GMF_CFG4_REG 0xf60
-#define GMF_HSTFLTRFRM_PAUSE_LBN 12
-#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12
-
-/* GMAC FIFO configuration register 5 */
-#define GMF_CFG5_REG 0xf70
-#define GMF_CFGHDPLX_LBN 22
-#define GMF_CFGHDPLX_WIDTH 1
-#define GMF_CFGBYTMODE_LBN 19
-#define GMF_CFGBYTMODE_WIDTH 1
-#define GMF_HSTDRPLT64_LBN 18
-#define GMF_HSTDRPLT64_WIDTH 1
-#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12
-#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1
-
-/* XGMAC address register low */
-#define XM_ADR_LO_REG 0x1200
-#define XM_ADR_3_LBN 24
-#define XM_ADR_3_WIDTH 8
-#define XM_ADR_2_LBN 16
-#define XM_ADR_2_WIDTH 8
-#define XM_ADR_1_LBN 8
-#define XM_ADR_1_WIDTH 8
-#define XM_ADR_0_LBN 0
-#define XM_ADR_0_WIDTH 8
-
-/* XGMAC address register high */
-#define XM_ADR_HI_REG 0x1210
-#define XM_ADR_5_LBN 8
-#define XM_ADR_5_WIDTH 8
-#define XM_ADR_4_LBN 0
-#define XM_ADR_4_WIDTH 8
-
-/* XGMAC global configuration */
-#define XM_GLB_CFG_REG 0x1220
-#define XM_RX_STAT_EN_LBN 11
-#define XM_RX_STAT_EN_WIDTH 1
-#define XM_TX_STAT_EN_LBN 10
-#define XM_TX_STAT_EN_WIDTH 1
-#define XM_RX_JUMBO_MODE_LBN 6
-#define XM_RX_JUMBO_MODE_WIDTH 1
-#define XM_INTCLR_MODE_LBN 3
-#define XM_INTCLR_MODE_WIDTH 1
-#define XM_CORE_RST_LBN 0
-#define XM_CORE_RST_WIDTH 1
-
-/* XGMAC transmit configuration */
-#define XM_TX_CFG_REG 0x1230
-#define XM_IPG_LBN 16
-#define XM_IPG_WIDTH 4
-#define XM_FCNTL_LBN 10
-#define XM_FCNTL_WIDTH 1
-#define XM_TXCRC_LBN 8
-#define XM_TXCRC_WIDTH 1
-#define XM_AUTO_PAD_LBN 5
-#define XM_AUTO_PAD_WIDTH 1
-#define XM_TX_PRMBL_LBN 2
-#define XM_TX_PRMBL_WIDTH 1
-#define XM_TXEN_LBN 1
-#define XM_TXEN_WIDTH 1
-
-/* XGMAC receive configuration */
-#define XM_RX_CFG_REG 0x1240
-#define XM_PASS_CRC_ERR_LBN 25
-#define XM_PASS_CRC_ERR_WIDTH 1
-#define XM_ACPT_ALL_MCAST_LBN 11
-#define XM_ACPT_ALL_MCAST_WIDTH 1
-#define XM_ACPT_ALL_UCAST_LBN 9
-#define XM_ACPT_ALL_UCAST_WIDTH 1
-#define XM_AUTO_DEPAD_LBN 8
-#define XM_AUTO_DEPAD_WIDTH 1
-#define XM_RXEN_LBN 1
-#define XM_RXEN_WIDTH 1
-
-/* XGMAC management interrupt mask register */
-#define XM_MGT_INT_MSK_REG_B0 0x1250
-#define XM_MSK_PRMBLE_ERR_LBN 2
-#define XM_MSK_PRMBLE_ERR_WIDTH 1
-#define XM_MSK_RMTFLT_LBN 1
-#define XM_MSK_RMTFLT_WIDTH 1
-#define XM_MSK_LCLFLT_LBN 0
-#define XM_MSK_LCLFLT_WIDTH 1
-
-/* XGMAC flow control register */
-#define XM_FC_REG 0x1270
-#define XM_PAUSE_TIME_LBN 16
-#define XM_PAUSE_TIME_WIDTH 16
-#define XM_DIS_FCNTL_LBN 0
-#define XM_DIS_FCNTL_WIDTH 1
-
-/* XGMAC pause time count register */
-#define XM_PAUSE_TIME_REG 0x1290
-
-/* XGMAC transmit parameter register */
-#define XM_TX_PARAM_REG 0x012d0
-#define XM_TX_JUMBO_MODE_LBN 31
-#define XM_TX_JUMBO_MODE_WIDTH 1
-#define XM_MAX_TX_FRM_SIZE_LBN 16
-#define XM_MAX_TX_FRM_SIZE_WIDTH 14
-
-/* XGMAC receive parameter register */
-#define XM_RX_PARAM_REG 0x12e0
-#define XM_MAX_RX_FRM_SIZE_LBN 0
-#define XM_MAX_RX_FRM_SIZE_WIDTH 14
-
-/* XGMAC management interrupt status register */
-#define XM_MGT_INT_REG_B0 0x12f0
-#define XM_PRMBLE_ERR 2
-#define XM_PRMBLE_WIDTH 1
-#define XM_RMTFLT_LBN 1
-#define XM_RMTFLT_WIDTH 1
-#define XM_LCLFLT_LBN 0
-#define XM_LCLFLT_WIDTH 1
-
-/* XGXS/XAUI powerdown/reset register */
-#define XX_PWR_RST_REG 0x1300
-
-#define XX_SD_RST_ACT_LBN 16
-#define XX_SD_RST_ACT_WIDTH 1
-#define XX_PWRDND_EN_LBN 15
-#define XX_PWRDND_EN_WIDTH 1
-#define XX_PWRDNC_EN_LBN 14
-#define XX_PWRDNC_EN_WIDTH 1
-#define XX_PWRDNB_EN_LBN 13
-#define XX_PWRDNB_EN_WIDTH 1
-#define XX_PWRDNA_EN_LBN 12
-#define XX_PWRDNA_EN_WIDTH 1
-#define XX_RSTPLLCD_EN_LBN 9
-#define XX_RSTPLLCD_EN_WIDTH 1
-#define XX_RSTPLLAB_EN_LBN 8
-#define XX_RSTPLLAB_EN_WIDTH 1
-#define XX_RESETD_EN_LBN 7
-#define XX_RESETD_EN_WIDTH 1
-#define XX_RESETC_EN_LBN 6
-#define XX_RESETC_EN_WIDTH 1
-#define XX_RESETB_EN_LBN 5
-#define XX_RESETB_EN_WIDTH 1
-#define XX_RESETA_EN_LBN 4
-#define XX_RESETA_EN_WIDTH 1
-#define XX_RSTXGXSRX_EN_LBN 2
-#define XX_RSTXGXSRX_EN_WIDTH 1
-#define XX_RSTXGXSTX_EN_LBN 1
-#define XX_RSTXGXSTX_EN_WIDTH 1
-#define XX_RST_XX_EN_LBN 0
-#define XX_RST_XX_EN_WIDTH 1
-
-/* XGXS/XAUI powerdown/reset control register */
-#define XX_SD_CTL_REG 0x1310
-#define XX_HIDRVD_LBN 15
-#define XX_HIDRVD_WIDTH 1
-#define XX_LODRVD_LBN 14
-#define XX_LODRVD_WIDTH 1
-#define XX_HIDRVC_LBN 13
-#define XX_HIDRVC_WIDTH 1
-#define XX_LODRVC_LBN 12
-#define XX_LODRVC_WIDTH 1
-#define XX_HIDRVB_LBN 11
-#define XX_HIDRVB_WIDTH 1
-#define XX_LODRVB_LBN 10
-#define XX_LODRVB_WIDTH 1
-#define XX_HIDRVA_LBN 9
-#define XX_HIDRVA_WIDTH 1
-#define XX_LODRVA_LBN 8
-#define XX_LODRVA_WIDTH 1
-#define XX_LPBKD_LBN 3
-#define XX_LPBKD_WIDTH 1
-#define XX_LPBKC_LBN 2
-#define XX_LPBKC_WIDTH 1
-#define XX_LPBKB_LBN 1
-#define XX_LPBKB_WIDTH 1
-#define XX_LPBKA_LBN 0
-#define XX_LPBKA_WIDTH 1
-
-#define XX_TXDRV_CTL_REG 0x1320
-#define XX_DEQD_LBN 28
-#define XX_DEQD_WIDTH 4
-#define XX_DEQC_LBN 24
-#define XX_DEQC_WIDTH 4
-#define XX_DEQB_LBN 20
-#define XX_DEQB_WIDTH 4
-#define XX_DEQA_LBN 16
-#define XX_DEQA_WIDTH 4
-#define XX_DTXD_LBN 12
-#define XX_DTXD_WIDTH 4
-#define XX_DTXC_LBN 8
-#define XX_DTXC_WIDTH 4
-#define XX_DTXB_LBN 4
-#define XX_DTXB_WIDTH 4
-#define XX_DTXA_LBN 0
-#define XX_DTXA_WIDTH 4
-
-/* XAUI XGXS core status register */
-#define XX_CORE_STAT_REG 0x1360
-#define XX_FORCE_SIG_LBN 24
-#define XX_FORCE_SIG_WIDTH 8
-#define XX_FORCE_SIG_DECODE_FORCED 0xff
-#define XX_XGXS_LB_EN_LBN 23
-#define XX_XGXS_LB_EN_WIDTH 1
-#define XX_XGMII_LB_EN_LBN 22
-#define XX_XGMII_LB_EN_WIDTH 1
-#define XX_ALIGN_DONE_LBN 20
-#define XX_ALIGN_DONE_WIDTH 1
-#define XX_SYNC_STAT_LBN 16
-#define XX_SYNC_STAT_WIDTH 4
-#define XX_SYNC_STAT_DECODE_SYNCED 0xf
-#define XX_COMMA_DET_LBN 12
-#define XX_COMMA_DET_WIDTH 4
-#define XX_COMMA_DET_DECODE_DETECTED 0xf
-#define XX_COMMA_DET_RESET 0xf
-#define XX_CHARERR_LBN 4
-#define XX_CHARERR_WIDTH 4
-#define XX_CHARERR_RESET 0xf
-#define XX_DISPERR_LBN 0
-#define XX_DISPERR_WIDTH 4
-#define XX_DISPERR_RESET 0xf
-
-/* Receive filter table */
-#define RX_FILTER_TBL0 0xF00000
-
-/* Receive descriptor pointer table */
-#define RX_DESC_PTR_TBL_KER_A1 0x11800
-#define RX_DESC_PTR_TBL_KER_B0 0xF40000
-#define RX_DESC_PTR_TBL_KER_P0 0x900
-#define RX_ISCSI_DDIG_EN_LBN 88
-#define RX_ISCSI_DDIG_EN_WIDTH 1
-#define RX_ISCSI_HDIG_EN_LBN 87
-#define RX_ISCSI_HDIG_EN_WIDTH 1
-#define RX_DESCQ_BUF_BASE_ID_LBN 36
-#define RX_DESCQ_BUF_BASE_ID_WIDTH 20
-#define RX_DESCQ_EVQ_ID_LBN 24
-#define RX_DESCQ_EVQ_ID_WIDTH 12
-#define RX_DESCQ_OWNER_ID_LBN 10
-#define RX_DESCQ_OWNER_ID_WIDTH 14
-#define RX_DESCQ_LABEL_LBN 5
-#define RX_DESCQ_LABEL_WIDTH 5
-#define RX_DESCQ_SIZE_LBN 3
-#define RX_DESCQ_SIZE_WIDTH 2
-#define RX_DESCQ_SIZE_4K 3
-#define RX_DESCQ_SIZE_2K 2
-#define RX_DESCQ_SIZE_1K 1
-#define RX_DESCQ_SIZE_512 0
-#define RX_DESCQ_TYPE_LBN 2
-#define RX_DESCQ_TYPE_WIDTH 1
-#define RX_DESCQ_JUMBO_LBN 1
-#define RX_DESCQ_JUMBO_WIDTH 1
-#define RX_DESCQ_EN_LBN 0
-#define RX_DESCQ_EN_WIDTH 1
-
-/* Transmit descriptor pointer table */
-#define TX_DESC_PTR_TBL_KER_A1 0x11900
-#define TX_DESC_PTR_TBL_KER_B0 0xF50000
-#define TX_DESC_PTR_TBL_KER_P0 0xa40
-#define TX_NON_IP_DROP_DIS_B0_LBN 91
-#define TX_NON_IP_DROP_DIS_B0_WIDTH 1
-#define TX_IP_CHKSM_DIS_B0_LBN 90
-#define TX_IP_CHKSM_DIS_B0_WIDTH 1
-#define TX_TCP_CHKSM_DIS_B0_LBN 89
-#define TX_TCP_CHKSM_DIS_B0_WIDTH 1
-#define TX_DESCQ_EN_LBN 88
-#define TX_DESCQ_EN_WIDTH 1
-#define TX_ISCSI_DDIG_EN_LBN 87
-#define TX_ISCSI_DDIG_EN_WIDTH 1
-#define TX_ISCSI_HDIG_EN_LBN 86
-#define TX_ISCSI_HDIG_EN_WIDTH 1
-#define TX_DESCQ_BUF_BASE_ID_LBN 36
-#define TX_DESCQ_BUF_BASE_ID_WIDTH 20
-#define TX_DESCQ_EVQ_ID_LBN 24
-#define TX_DESCQ_EVQ_ID_WIDTH 12
-#define TX_DESCQ_OWNER_ID_LBN 10
-#define TX_DESCQ_OWNER_ID_WIDTH 14
-#define TX_DESCQ_LABEL_LBN 5
-#define TX_DESCQ_LABEL_WIDTH 5
-#define TX_DESCQ_SIZE_LBN 3
-#define TX_DESCQ_SIZE_WIDTH 2
-#define TX_DESCQ_SIZE_4K 3
-#define TX_DESCQ_SIZE_2K 2
-#define TX_DESCQ_SIZE_1K 1
-#define TX_DESCQ_SIZE_512 0
-#define TX_DESCQ_TYPE_LBN 1
-#define TX_DESCQ_TYPE_WIDTH 2
-
-/* Event queue pointer */
-#define EVQ_PTR_TBL_KER_A1 0x11a00
-#define EVQ_PTR_TBL_KER_B0 0xf60000
-#define EVQ_PTR_TBL_KER_P0 0x500
-#define EVQ_EN_LBN 23
-#define EVQ_EN_WIDTH 1
-#define EVQ_SIZE_LBN 20
-#define EVQ_SIZE_WIDTH 3
-#define EVQ_SIZE_32K 6
-#define EVQ_SIZE_16K 5
-#define EVQ_SIZE_8K 4
-#define EVQ_SIZE_4K 3
-#define EVQ_SIZE_2K 2
-#define EVQ_SIZE_1K 1
-#define EVQ_SIZE_512 0
-#define EVQ_BUF_BASE_ID_LBN 0
-#define EVQ_BUF_BASE_ID_WIDTH 20
-
-/* Event queue read pointer */
-#define EVQ_RPTR_REG_KER_A1 0x11b00
-#define EVQ_RPTR_REG_KER_B0 0xfa0000
-#define EVQ_RPTR_REG_KER_DWORD (EVQ_RPTR_REG_KER + 0)
-#define EVQ_RPTR_DWORD_LBN 0
-#define EVQ_RPTR_DWORD_WIDTH 14
-
-/* RSS indirection table */
-#define RX_RSS_INDIR_TBL_B0 0xFB0000
-#define RX_RSS_INDIR_ENT_B0_LBN 0
-#define RX_RSS_INDIR_ENT_B0_WIDTH 6
-
-/* Special buffer descriptors (full-mode) */
-#define BUF_FULL_TBL_KER_A1 0x8000
-#define BUF_FULL_TBL_KER_B0 0x800000
-#define IP_DAT_BUF_SIZE_LBN 50
-#define IP_DAT_BUF_SIZE_WIDTH 1
-#define IP_DAT_BUF_SIZE_8K 1
-#define IP_DAT_BUF_SIZE_4K 0
-#define BUF_ADR_REGION_LBN 48
-#define BUF_ADR_REGION_WIDTH 2
-#define BUF_ADR_FBUF_LBN 14
-#define BUF_ADR_FBUF_WIDTH 34
-#define BUF_OWNER_ID_FBUF_LBN 0
-#define BUF_OWNER_ID_FBUF_WIDTH 14
-
-/* Transmit descriptor */
-#define TX_KER_PORT_LBN 63
-#define TX_KER_PORT_WIDTH 1
-#define TX_KER_CONT_LBN 62
-#define TX_KER_CONT_WIDTH 1
-#define TX_KER_BYTE_CNT_LBN 48
-#define TX_KER_BYTE_CNT_WIDTH 14
-#define TX_KER_BUF_REGION_LBN 46
-#define TX_KER_BUF_REGION_WIDTH 2
-#define TX_KER_BUF_REGION0_DECODE 0
-#define TX_KER_BUF_REGION1_DECODE 1
-#define TX_KER_BUF_REGION2_DECODE 2
-#define TX_KER_BUF_REGION3_DECODE 3
-#define TX_KER_BUF_ADR_LBN 0
-#define TX_KER_BUF_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46)
-
-/* Receive descriptor */
-#define RX_KER_BUF_SIZE_LBN 48
-#define RX_KER_BUF_SIZE_WIDTH 14
-#define RX_KER_BUF_REGION_LBN 46
-#define RX_KER_BUF_REGION_WIDTH 2
-#define RX_KER_BUF_REGION0_DECODE 0
-#define RX_KER_BUF_REGION1_DECODE 1
-#define RX_KER_BUF_REGION2_DECODE 2
-#define RX_KER_BUF_REGION3_DECODE 3
-#define RX_KER_BUF_ADR_LBN 0
-#define RX_KER_BUF_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46)
-
-/**************************************************************************
- *
- * Falcon events
- *
- **************************************************************************
- */
-
-/* Event queue entries */
-#define EV_CODE_LBN 60
-#define EV_CODE_WIDTH 4
-#define RX_IP_EV_DECODE 0
-#define TX_IP_EV_DECODE 2
-#define DRIVER_EV_DECODE 5
-#define GLOBAL_EV_DECODE 6
-#define DRV_GEN_EV_DECODE 7
-#define WHOLE_EVENT_LBN 0
-#define WHOLE_EVENT_WIDTH 64
-
-/* Receive events */
-#define RX_EV_PKT_OK_LBN 56
-#define RX_EV_PKT_OK_WIDTH 1
-#define RX_EV_PAUSE_FRM_ERR_LBN 55
-#define RX_EV_PAUSE_FRM_ERR_WIDTH 1
-#define RX_EV_BUF_OWNER_ID_ERR_LBN 54
-#define RX_EV_BUF_OWNER_ID_ERR_WIDTH 1
-#define RX_EV_IF_FRAG_ERR_LBN 53
-#define RX_EV_IF_FRAG_ERR_WIDTH 1
-#define RX_EV_IP_HDR_CHKSUM_ERR_LBN 52
-#define RX_EV_IP_HDR_CHKSUM_ERR_WIDTH 1
-#define RX_EV_TCP_UDP_CHKSUM_ERR_LBN 51
-#define RX_EV_TCP_UDP_CHKSUM_ERR_WIDTH 1
-#define RX_EV_ETH_CRC_ERR_LBN 50
-#define RX_EV_ETH_CRC_ERR_WIDTH 1
-#define RX_EV_FRM_TRUNC_LBN 49
-#define RX_EV_FRM_TRUNC_WIDTH 1
-#define RX_EV_DRIB_NIB_LBN 48
-#define RX_EV_DRIB_NIB_WIDTH 1
-#define RX_EV_TOBE_DISC_LBN 47
-#define RX_EV_TOBE_DISC_WIDTH 1
-#define RX_EV_PKT_TYPE_LBN 44
-#define RX_EV_PKT_TYPE_WIDTH 3
-#define RX_EV_PKT_TYPE_ETH_DECODE 0
-#define RX_EV_PKT_TYPE_LLC_DECODE 1
-#define RX_EV_PKT_TYPE_JUMBO_DECODE 2
-#define RX_EV_PKT_TYPE_VLAN_DECODE 3
-#define RX_EV_PKT_TYPE_VLAN_LLC_DECODE 4
-#define RX_EV_PKT_TYPE_VLAN_JUMBO_DECODE 5
-#define RX_EV_HDR_TYPE_LBN 42
-#define RX_EV_HDR_TYPE_WIDTH 2
-#define RX_EV_HDR_TYPE_TCP_IPV4_DECODE 0
-#define RX_EV_HDR_TYPE_UDP_IPV4_DECODE 1
-#define RX_EV_HDR_TYPE_OTHER_IP_DECODE 2
-#define RX_EV_HDR_TYPE_NON_IP_DECODE 3
-#define RX_EV_HDR_TYPE_HAS_CHECKSUMS(hdr_type) \
- ((hdr_type) <= RX_EV_HDR_TYPE_UDP_IPV4_DECODE)
-#define RX_EV_MCAST_HASH_MATCH_LBN 40
-#define RX_EV_MCAST_HASH_MATCH_WIDTH 1
-#define RX_EV_MCAST_PKT_LBN 39
-#define RX_EV_MCAST_PKT_WIDTH 1
-#define RX_EV_Q_LABEL_LBN 32
-#define RX_EV_Q_LABEL_WIDTH 5
-#define RX_EV_JUMBO_CONT_LBN 31
-#define RX_EV_JUMBO_CONT_WIDTH 1
-#define RX_EV_BYTE_CNT_LBN 16
-#define RX_EV_BYTE_CNT_WIDTH 14
-#define RX_EV_SOP_LBN 15
-#define RX_EV_SOP_WIDTH 1
-#define RX_EV_DESC_PTR_LBN 0
-#define RX_EV_DESC_PTR_WIDTH 12
-
-/* Transmit events */
-#define TX_EV_PKT_ERR_LBN 38
-#define TX_EV_PKT_ERR_WIDTH 1
-#define TX_EV_Q_LABEL_LBN 32
-#define TX_EV_Q_LABEL_WIDTH 5
-#define TX_EV_WQ_FF_FULL_LBN 15
-#define TX_EV_WQ_FF_FULL_WIDTH 1
-#define TX_EV_COMP_LBN 12
-#define TX_EV_COMP_WIDTH 1
-#define TX_EV_DESC_PTR_LBN 0
-#define TX_EV_DESC_PTR_WIDTH 12
-
-/* Driver events */
-#define DRIVER_EV_SUB_CODE_LBN 56
-#define DRIVER_EV_SUB_CODE_WIDTH 4
-#define DRIVER_EV_SUB_DATA_LBN 0
-#define DRIVER_EV_SUB_DATA_WIDTH 14
-#define TX_DESCQ_FLS_DONE_EV_DECODE 0
-#define RX_DESCQ_FLS_DONE_EV_DECODE 1
-#define EVQ_INIT_DONE_EV_DECODE 2
-#define EVQ_NOT_EN_EV_DECODE 3
-#define RX_DESCQ_FLSFF_OVFL_EV_DECODE 4
-#define SRM_UPD_DONE_EV_DECODE 5
-#define WAKE_UP_EV_DECODE 6
-#define TX_PKT_NON_TCP_UDP_DECODE 9
-#define TIMER_EV_DECODE 10
-#define RX_RECOVERY_EV_DECODE 11
-#define RX_DSC_ERROR_EV_DECODE 14
-#define TX_DSC_ERROR_EV_DECODE 15
-#define DRIVER_EV_TX_DESCQ_ID_LBN 0
-#define DRIVER_EV_TX_DESCQ_ID_WIDTH 12
-#define DRIVER_EV_RX_FLUSH_FAIL_LBN 12
-#define DRIVER_EV_RX_FLUSH_FAIL_WIDTH 1
-#define DRIVER_EV_RX_DESCQ_ID_LBN 0
-#define DRIVER_EV_RX_DESCQ_ID_WIDTH 12
-#define SRM_CLR_EV_DECODE 0
-#define SRM_UPD_EV_DECODE 1
-#define SRM_ILLCLR_EV_DECODE 2
-
-/* Global events */
-#define RX_RECOVERY_B0_LBN 12
-#define RX_RECOVERY_B0_WIDTH 1
-#define XG_MNT_INTR_B0_LBN 11
-#define XG_MNT_INTR_B0_WIDTH 1
-#define RX_RECOVERY_A1_LBN 11
-#define RX_RECOVERY_A1_WIDTH 1
-#define XFP_PHY_INTR_LBN 10
-#define XFP_PHY_INTR_WIDTH 1
-#define XG_PHY_INTR_LBN 9
-#define XG_PHY_INTR_WIDTH 1
-#define G_PHY1_INTR_LBN 8
-#define G_PHY1_INTR_WIDTH 1
-#define G_PHY0_INTR_LBN 7
-#define G_PHY0_INTR_WIDTH 1
-
-/* Driver-generated test events */
-#define EVQ_MAGIC_LBN 0
-#define EVQ_MAGIC_WIDTH 32
-
-/**************************************************************************
- *
- * Falcon MAC stats
- *
- **************************************************************************
- *
- */
-
-#define GRxGoodOct_offset 0x0
-#define GRxGoodOct_WIDTH 48
-#define GRxBadOct_offset 0x8
-#define GRxBadOct_WIDTH 48
-#define GRxMissPkt_offset 0x10
-#define GRxMissPkt_WIDTH 32
-#define GRxFalseCRS_offset 0x14
-#define GRxFalseCRS_WIDTH 32
-#define GRxPausePkt_offset 0x18
-#define GRxPausePkt_WIDTH 32
-#define GRxBadPkt_offset 0x1C
-#define GRxBadPkt_WIDTH 32
-#define GRxUcastPkt_offset 0x20
-#define GRxUcastPkt_WIDTH 32
-#define GRxMcastPkt_offset 0x24
-#define GRxMcastPkt_WIDTH 32
-#define GRxBcastPkt_offset 0x28
-#define GRxBcastPkt_WIDTH 32
-#define GRxGoodLt64Pkt_offset 0x2C
-#define GRxGoodLt64Pkt_WIDTH 32
-#define GRxBadLt64Pkt_offset 0x30
-#define GRxBadLt64Pkt_WIDTH 32
-#define GRx64Pkt_offset 0x34
-#define GRx64Pkt_WIDTH 32
-#define GRx65to127Pkt_offset 0x38
-#define GRx65to127Pkt_WIDTH 32
-#define GRx128to255Pkt_offset 0x3C
-#define GRx128to255Pkt_WIDTH 32
-#define GRx256to511Pkt_offset 0x40
-#define GRx256to511Pkt_WIDTH 32
-#define GRx512to1023Pkt_offset 0x44
-#define GRx512to1023Pkt_WIDTH 32
-#define GRx1024to15xxPkt_offset 0x48
-#define GRx1024to15xxPkt_WIDTH 32
-#define GRx15xxtoJumboPkt_offset 0x4C
-#define GRx15xxtoJumboPkt_WIDTH 32
-#define GRxGtJumboPkt_offset 0x50
-#define GRxGtJumboPkt_WIDTH 32
-#define GRxFcsErr64to15xxPkt_offset 0x54
-#define GRxFcsErr64to15xxPkt_WIDTH 32
-#define GRxFcsErr15xxtoJumboPkt_offset 0x58
-#define GRxFcsErr15xxtoJumboPkt_WIDTH 32
-#define GRxFcsErrGtJumboPkt_offset 0x5C
-#define GRxFcsErrGtJumboPkt_WIDTH 32
-#define GTxGoodBadOct_offset 0x80
-#define GTxGoodBadOct_WIDTH 48
-#define GTxGoodOct_offset 0x88
-#define GTxGoodOct_WIDTH 48
-#define GTxSglColPkt_offset 0x90
-#define GTxSglColPkt_WIDTH 32
-#define GTxMultColPkt_offset 0x94
-#define GTxMultColPkt_WIDTH 32
-#define GTxExColPkt_offset 0x98
-#define GTxExColPkt_WIDTH 32
-#define GTxDefPkt_offset 0x9C
-#define GTxDefPkt_WIDTH 32
-#define GTxLateCol_offset 0xA0
-#define GTxLateCol_WIDTH 32
-#define GTxExDefPkt_offset 0xA4
-#define GTxExDefPkt_WIDTH 32
-#define GTxPausePkt_offset 0xA8
-#define GTxPausePkt_WIDTH 32
-#define GTxBadPkt_offset 0xAC
-#define GTxBadPkt_WIDTH 32
-#define GTxUcastPkt_offset 0xB0
-#define GTxUcastPkt_WIDTH 32
-#define GTxMcastPkt_offset 0xB4
-#define GTxMcastPkt_WIDTH 32
-#define GTxBcastPkt_offset 0xB8
-#define GTxBcastPkt_WIDTH 32
-#define GTxLt64Pkt_offset 0xBC
-#define GTxLt64Pkt_WIDTH 32
-#define GTx64Pkt_offset 0xC0
-#define GTx64Pkt_WIDTH 32
-#define GTx65to127Pkt_offset 0xC4
-#define GTx65to127Pkt_WIDTH 32
-#define GTx128to255Pkt_offset 0xC8
-#define GTx128to255Pkt_WIDTH 32
-#define GTx256to511Pkt_offset 0xCC
-#define GTx256to511Pkt_WIDTH 32
-#define GTx512to1023Pkt_offset 0xD0
-#define GTx512to1023Pkt_WIDTH 32
-#define GTx1024to15xxPkt_offset 0xD4
-#define GTx1024to15xxPkt_WIDTH 32
-#define GTx15xxtoJumboPkt_offset 0xD8
-#define GTx15xxtoJumboPkt_WIDTH 32
-#define GTxGtJumboPkt_offset 0xDC
-#define GTxGtJumboPkt_WIDTH 32
-#define GTxNonTcpUdpPkt_offset 0xE0
-#define GTxNonTcpUdpPkt_WIDTH 16
-#define GTxMacSrcErrPkt_offset 0xE4
-#define GTxMacSrcErrPkt_WIDTH 16
-#define GTxIpSrcErrPkt_offset 0xE8
-#define GTxIpSrcErrPkt_WIDTH 16
-#define GDmaDone_offset 0xEC
-#define GDmaDone_WIDTH 32
-
-#define XgRxOctets_offset 0x0
-#define XgRxOctets_WIDTH 48
-#define XgRxOctetsOK_offset 0x8
-#define XgRxOctetsOK_WIDTH 48
-#define XgRxPkts_offset 0x10
-#define XgRxPkts_WIDTH 32
-#define XgRxPktsOK_offset 0x14
-#define XgRxPktsOK_WIDTH 32
-#define XgRxBroadcastPkts_offset 0x18
-#define XgRxBroadcastPkts_WIDTH 32
-#define XgRxMulticastPkts_offset 0x1C
-#define XgRxMulticastPkts_WIDTH 32
-#define XgRxUnicastPkts_offset 0x20
-#define XgRxUnicastPkts_WIDTH 32
-#define XgRxUndersizePkts_offset 0x24
-#define XgRxUndersizePkts_WIDTH 32
-#define XgRxOversizePkts_offset 0x28
-#define XgRxOversizePkts_WIDTH 32
-#define XgRxJabberPkts_offset 0x2C
-#define XgRxJabberPkts_WIDTH 32
-#define XgRxUndersizeFCSerrorPkts_offset 0x30
-#define XgRxUndersizeFCSerrorPkts_WIDTH 32
-#define XgRxDropEvents_offset 0x34
-#define XgRxDropEvents_WIDTH 32
-#define XgRxFCSerrorPkts_offset 0x38
-#define XgRxFCSerrorPkts_WIDTH 32
-#define XgRxAlignError_offset 0x3C
-#define XgRxAlignError_WIDTH 32
-#define XgRxSymbolError_offset 0x40
-#define XgRxSymbolError_WIDTH 32
-#define XgRxInternalMACError_offset 0x44
-#define XgRxInternalMACError_WIDTH 32
-#define XgRxControlPkts_offset 0x48
-#define XgRxControlPkts_WIDTH 32
-#define XgRxPausePkts_offset 0x4C
-#define XgRxPausePkts_WIDTH 32
-#define XgRxPkts64Octets_offset 0x50
-#define XgRxPkts64Octets_WIDTH 32
-#define XgRxPkts65to127Octets_offset 0x54
-#define XgRxPkts65to127Octets_WIDTH 32
-#define XgRxPkts128to255Octets_offset 0x58
-#define XgRxPkts128to255Octets_WIDTH 32
-#define XgRxPkts256to511Octets_offset 0x5C
-#define XgRxPkts256to511Octets_WIDTH 32
-#define XgRxPkts512to1023Octets_offset 0x60
-#define XgRxPkts512to1023Octets_WIDTH 32
-#define XgRxPkts1024to15xxOctets_offset 0x64
-#define XgRxPkts1024to15xxOctets_WIDTH 32
-#define XgRxPkts15xxtoMaxOctets_offset 0x68
-#define XgRxPkts15xxtoMaxOctets_WIDTH 32
-#define XgRxLengthError_offset 0x6C
-#define XgRxLengthError_WIDTH 32
-#define XgTxPkts_offset 0x80
-#define XgTxPkts_WIDTH 32
-#define XgTxOctets_offset 0x88
-#define XgTxOctets_WIDTH 48
-#define XgTxMulticastPkts_offset 0x90
-#define XgTxMulticastPkts_WIDTH 32
-#define XgTxBroadcastPkts_offset 0x94
-#define XgTxBroadcastPkts_WIDTH 32
-#define XgTxUnicastPkts_offset 0x98
-#define XgTxUnicastPkts_WIDTH 32
-#define XgTxControlPkts_offset 0x9C
-#define XgTxControlPkts_WIDTH 32
-#define XgTxPausePkts_offset 0xA0
-#define XgTxPausePkts_WIDTH 32
-#define XgTxPkts64Octets_offset 0xA4
-#define XgTxPkts64Octets_WIDTH 32
-#define XgTxPkts65to127Octets_offset 0xA8
-#define XgTxPkts65to127Octets_WIDTH 32
-#define XgTxPkts128to255Octets_offset 0xAC
-#define XgTxPkts128to255Octets_WIDTH 32
-#define XgTxPkts256to511Octets_offset 0xB0
-#define XgTxPkts256to511Octets_WIDTH 32
-#define XgTxPkts512to1023Octets_offset 0xB4
-#define XgTxPkts512to1023Octets_WIDTH 32
-#define XgTxPkts1024to15xxOctets_offset 0xB8
-#define XgTxPkts1024to15xxOctets_WIDTH 32
-#define XgTxPkts1519toMaxOctets_offset 0xBC
-#define XgTxPkts1519toMaxOctets_WIDTH 32
-#define XgTxUndersizePkts_offset 0xC0
-#define XgTxUndersizePkts_WIDTH 32
-#define XgTxOversizePkts_offset 0xC4
-#define XgTxOversizePkts_WIDTH 32
-#define XgTxNonTcpUdpPkt_offset 0xC8
-#define XgTxNonTcpUdpPkt_WIDTH 16
-#define XgTxMacSrcErrPkt_offset 0xCC
-#define XgTxMacSrcErrPkt_WIDTH 16
-#define XgTxIpSrcErrPkt_offset 0xD0
-#define XgTxIpSrcErrPkt_WIDTH 16
-#define XgDmaDone_offset 0xD4
-
-#define FALCON_STATS_NOT_DONE 0x00000000
-#define FALCON_STATS_DONE 0xffffffff
-
-/* Interrupt status register bits */
-#define FATAL_INT_LBN 64
-#define FATAL_INT_WIDTH 1
-#define INT_EVQS_LBN 40
-#define INT_EVQS_WIDTH 4
-
-/**************************************************************************
- *
- * Falcon non-volatile configuration
- *
- **************************************************************************
- */
-
-/* Board configuration v2 (v1 is obsolete; later versions are compatible) */
-struct falcon_nvconfig_board_v2 {
- __le16 nports;
- u8 port0_phy_addr;
- u8 port0_phy_type;
- u8 port1_phy_addr;
- u8 port1_phy_type;
- __le16 asic_sub_revision;
- __le16 board_revision;
-} __packed;
-
-/* Board configuration v3 extra information */
-struct falcon_nvconfig_board_v3 {
- __le32 spi_device_type[2];
-} __packed;
-
-/* Bit numbers for spi_device_type */
-#define SPI_DEV_TYPE_SIZE_LBN 0
-#define SPI_DEV_TYPE_SIZE_WIDTH 5
-#define SPI_DEV_TYPE_ADDR_LEN_LBN 6
-#define SPI_DEV_TYPE_ADDR_LEN_WIDTH 2
-#define SPI_DEV_TYPE_ERASE_CMD_LBN 8
-#define SPI_DEV_TYPE_ERASE_CMD_WIDTH 8
-#define SPI_DEV_TYPE_ERASE_SIZE_LBN 16
-#define SPI_DEV_TYPE_ERASE_SIZE_WIDTH 5
-#define SPI_DEV_TYPE_BLOCK_SIZE_LBN 24
-#define SPI_DEV_TYPE_BLOCK_SIZE_WIDTH 5
-#define SPI_DEV_TYPE_FIELD(type, field) \
- (((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(EFX_WIDTH(field)))
-
-#define NVCONFIG_OFFSET 0x300
-
-#define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C
-struct falcon_nvconfig {
- efx_oword_t ee_vpd_cfg_reg; /* 0x300 */
- u8 mac_address[2][8]; /* 0x310 */
- efx_oword_t pcie_sd_ctl0123_reg; /* 0x320 */
- efx_oword_t pcie_sd_ctl45_reg; /* 0x330 */
- efx_oword_t pcie_pcs_ctl_stat_reg; /* 0x340 */
- efx_oword_t hw_init_reg; /* 0x350 */
- efx_oword_t nic_stat_reg; /* 0x360 */
- efx_oword_t glb_ctl_reg; /* 0x370 */
- efx_oword_t srm_cfg_reg; /* 0x380 */
- efx_oword_t spare_reg; /* 0x390 */
- __le16 board_magic_num; /* 0x3A0 */
- __le16 board_struct_ver;
- __le16 board_checksum;
- struct falcon_nvconfig_board_v2 board_v2;
- efx_oword_t ee_base_page_reg; /* 0x3B0 */
- struct falcon_nvconfig_board_v3 board_v3;
-} __packed;
-
-#endif /* EFX_FALCON_HWDEFS_H */
diff --git a/drivers/net/sfc/falcon_io.h b/drivers/net/sfc/falcon_io.h
deleted file mode 100644
index 8883092dae97..000000000000
--- a/drivers/net/sfc/falcon_io.h
+++ /dev/null
@@ -1,258 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006-2008 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_FALCON_IO_H
-#define EFX_FALCON_IO_H
-
-#include <linux/io.h>
-#include <linux/spinlock.h>
-
-/**************************************************************************
- *
- * Falcon hardware access
- *
- **************************************************************************
- *
- * Notes on locking strategy:
- *
- * Most Falcon registers require 16-byte (or 8-byte, for SRAM
- * registers) atomic writes which necessitates locking.
- * Under normal operation few writes to the Falcon BAR are made and these
- * registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and TX_DESC_UPD_REG) are special
- * cased to allow 4-byte (hence lockless) accesses.
- *
- * It *is* safe to write to these 4-byte registers in the middle of an
- * access to an 8-byte or 16-byte register. We therefore use a
- * spinlock to protect accesses to the larger registers, but no locks
- * for the 4-byte registers.
- *
- * A write barrier is needed to ensure that DW3 is written after DW0/1/2
- * due to the way the 16byte registers are "collected" in the Falcon BIU
- *
- * We also lock when carrying out reads, to ensure consistency of the
- * data (made possible since the BIU reads all 128 bits into a cache).
- * Reads are very rare, so this isn't a significant performance
- * impact. (Most data transferred from NIC to host is DMAed directly
- * into host memory).
- *
- * I/O BAR access uses locks for both reads and writes (but is only provided
- * for testing purposes).
- */
-
-/* Special buffer descriptors (Falcon SRAM) */
-#define BUF_TBL_KER_A1 0x18000
-#define BUF_TBL_KER_B0 0x800000
-
-
-#if BITS_PER_LONG == 64
-#define FALCON_USE_QWORD_IO 1
-#endif
-
-#ifdef FALCON_USE_QWORD_IO
-static inline void _falcon_writeq(struct efx_nic *efx, __le64 value,
- unsigned int reg)
-{
- __raw_writeq((__force u64)value, efx->membase + reg);
-}
-static inline __le64 _falcon_readq(struct efx_nic *efx, unsigned int reg)
-{
- return (__force __le64)__raw_readq(efx->membase + reg);
-}
-#endif
-
-static inline void _falcon_writel(struct efx_nic *efx, __le32 value,
- unsigned int reg)
-{
- __raw_writel((__force u32)value, efx->membase + reg);
-}
-static inline __le32 _falcon_readl(struct efx_nic *efx, unsigned int reg)
-{
- return (__force __le32)__raw_readl(efx->membase + reg);
-}
-
-/* Writes to a normal 16-byte Falcon register, locking as appropriate. */
-static inline void falcon_write(struct efx_nic *efx, efx_oword_t *value,
- unsigned int reg)
-{
- unsigned long flags;
-
- EFX_REGDUMP(efx, "writing register %x with " EFX_OWORD_FMT "\n", reg,
- EFX_OWORD_VAL(*value));
-
- spin_lock_irqsave(&efx->biu_lock, flags);
-#ifdef FALCON_USE_QWORD_IO
- _falcon_writeq(efx, value->u64[0], reg + 0);
- wmb();
- _falcon_writeq(efx, value->u64[1], reg + 8);
-#else
- _falcon_writel(efx, value->u32[0], reg + 0);
- _falcon_writel(efx, value->u32[1], reg + 4);
- _falcon_writel(efx, value->u32[2], reg + 8);
- wmb();
- _falcon_writel(efx, value->u32[3], reg + 12);
-#endif
- mmiowb();
- spin_unlock_irqrestore(&efx->biu_lock, flags);
-}
-
-/* Writes to an 8-byte Falcon SRAM register, locking as appropriate. */
-static inline void falcon_write_sram(struct efx_nic *efx, efx_qword_t *value,
- unsigned int index)
-{
- unsigned int reg = efx->type->buf_tbl_base + (index * sizeof(*value));
- unsigned long flags;
-
- EFX_REGDUMP(efx, "writing SRAM register %x with " EFX_QWORD_FMT "\n",
- reg, EFX_QWORD_VAL(*value));
-
- spin_lock_irqsave(&efx->biu_lock, flags);
-#ifdef FALCON_USE_QWORD_IO
- _falcon_writeq(efx, value->u64[0], reg + 0);
-#else
- _falcon_writel(efx, value->u32[0], reg + 0);
- wmb();
- _falcon_writel(efx, value->u32[1], reg + 4);
-#endif
- mmiowb();
- spin_unlock_irqrestore(&efx->biu_lock, flags);
-}
-
-/* Write dword to Falcon register that allows partial writes
- *
- * Some Falcon registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and
- * TX_DESC_UPD_REG) can be written to as a single dword. This allows
- * for lockless writes.
- */
-static inline void falcon_writel(struct efx_nic *efx, efx_dword_t *value,
- unsigned int reg)
-{
- EFX_REGDUMP(efx, "writing partial register %x with "EFX_DWORD_FMT"\n",
- reg, EFX_DWORD_VAL(*value));
-
- /* No lock required */
- _falcon_writel(efx, value->u32[0], reg);
-}
-
-/* Read from a Falcon register
- *
- * This reads an entire 16-byte Falcon register in one go, locking as
- * appropriate. It is essential to read the first dword first, as this
- * prompts Falcon to load the current value into the shadow register.
- */
-static inline void falcon_read(struct efx_nic *efx, efx_oword_t *value,
- unsigned int reg)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&efx->biu_lock, flags);
- value->u32[0] = _falcon_readl(efx, reg + 0);
- rmb();
- value->u32[1] = _falcon_readl(efx, reg + 4);
- value->u32[2] = _falcon_readl(efx, reg + 8);
- value->u32[3] = _falcon_readl(efx, reg + 12);
- spin_unlock_irqrestore(&efx->biu_lock, flags);
-
- EFX_REGDUMP(efx, "read from register %x, got " EFX_OWORD_FMT "\n", reg,
- EFX_OWORD_VAL(*value));
-}
-
-/* This reads an 8-byte Falcon SRAM entry in one go. */
-static inline void falcon_read_sram(struct efx_nic *efx, efx_qword_t *value,
- unsigned int index)
-{
- unsigned int reg = efx->type->buf_tbl_base + (index * sizeof(*value));
- unsigned long flags;
-
- spin_lock_irqsave(&efx->biu_lock, flags);
-#ifdef FALCON_USE_QWORD_IO
- value->u64[0] = _falcon_readq(efx, reg + 0);
-#else
- value->u32[0] = _falcon_readl(efx, reg + 0);
- rmb();
- value->u32[1] = _falcon_readl(efx, reg + 4);
-#endif
- spin_unlock_irqrestore(&efx->biu_lock, flags);
-
- EFX_REGDUMP(efx, "read from SRAM register %x, got "EFX_QWORD_FMT"\n",
- reg, EFX_QWORD_VAL(*value));
-}
-
-/* Read dword from Falcon register that allows partial writes (sic) */
-static inline void falcon_readl(struct efx_nic *efx, efx_dword_t *value,
- unsigned int reg)
-{
- value->u32[0] = _falcon_readl(efx, reg);
- EFX_REGDUMP(efx, "read from register %x, got "EFX_DWORD_FMT"\n",
- reg, EFX_DWORD_VAL(*value));
-}
-
-/* Write to a register forming part of a table */
-static inline void falcon_write_table(struct efx_nic *efx, efx_oword_t *value,
- unsigned int reg, unsigned int index)
-{
- falcon_write(efx, value, reg + index * sizeof(efx_oword_t));
-}
-
-/* Read to a register forming part of a table */
-static inline void falcon_read_table(struct efx_nic *efx, efx_oword_t *value,
- unsigned int reg, unsigned int index)
-{
- falcon_read(efx, value, reg + index * sizeof(efx_oword_t));
-}
-
-/* Write to a dword register forming part of a table */
-static inline void falcon_writel_table(struct efx_nic *efx, efx_dword_t *value,
- unsigned int reg, unsigned int index)
-{
- falcon_writel(efx, value, reg + index * sizeof(efx_oword_t));
-}
-
-/* Page-mapped register block size */
-#define FALCON_PAGE_BLOCK_SIZE 0x2000
-
-/* Calculate offset to page-mapped register block */
-#define FALCON_PAGED_REG(page, reg) \
- ((page) * FALCON_PAGE_BLOCK_SIZE + (reg))
-
-/* As for falcon_write(), but for a page-mapped register. */
-static inline void falcon_write_page(struct efx_nic *efx, efx_oword_t *value,
- unsigned int reg, unsigned int page)
-{
- falcon_write(efx, value, FALCON_PAGED_REG(page, reg));
-}
-
-/* As for falcon_writel(), but for a page-mapped register. */
-static inline void falcon_writel_page(struct efx_nic *efx, efx_dword_t *value,
- unsigned int reg, unsigned int page)
-{
- falcon_writel(efx, value, FALCON_PAGED_REG(page, reg));
-}
-
-/* Write dword to Falcon page-mapped register with an extra lock.
- *
- * As for falcon_writel_page(), but for a register that suffers from
- * SFC bug 3181. If writing to page 0, take out a lock so the BIU
- * collector cannot be confused.
- */
-static inline void falcon_writel_page_locked(struct efx_nic *efx,
- efx_dword_t *value,
- unsigned int reg,
- unsigned int page)
-{
- unsigned long flags = 0;
-
- if (page == 0)
- spin_lock_irqsave(&efx->biu_lock, flags);
- falcon_writel(efx, value, FALCON_PAGED_REG(page, reg));
- if (page == 0)
- spin_unlock_irqrestore(&efx->biu_lock, flags);
-}
-
-#endif /* EFX_FALCON_IO_H */
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
index bec52ca37eee..7e57b4a54b37 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -12,12 +12,11 @@
#include "net_driver.h"
#include "efx.h"
#include "falcon.h"
-#include "falcon_hwdefs.h"
-#include "falcon_io.h"
+#include "regs.h"
+#include "io.h"
#include "mac.h"
#include "mdio_10g.h"
#include "phy.h"
-#include "boards.h"
#include "workarounds.h"
/**************************************************************************
@@ -36,27 +35,27 @@ static void falcon_setup_xaui(struct efx_nic *efx)
if (efx->phy_type == PHY_TYPE_NONE)
return;
- falcon_read(efx, &sdctl, XX_SD_CTL_REG);
- EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT);
- EFX_SET_OWORD_FIELD(sdctl, XX_LODRVD, XX_SD_CTL_DRV_DEFAULT);
- EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT);
- EFX_SET_OWORD_FIELD(sdctl, XX_LODRVC, XX_SD_CTL_DRV_DEFAULT);
- EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT);
- EFX_SET_OWORD_FIELD(sdctl, XX_LODRVB, XX_SD_CTL_DRV_DEFAULT);
- EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT);
- EFX_SET_OWORD_FIELD(sdctl, XX_LODRVA, XX_SD_CTL_DRV_DEFAULT);
- falcon_write(efx, &sdctl, XX_SD_CTL_REG);
+ efx_reado(efx, &sdctl, FR_AB_XX_SD_CTL);
+ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVD, FFE_AB_XX_SD_CTL_DRV_DEF);
+ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVD, FFE_AB_XX_SD_CTL_DRV_DEF);
+ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVC, FFE_AB_XX_SD_CTL_DRV_DEF);
+ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVC, FFE_AB_XX_SD_CTL_DRV_DEF);
+ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVB, FFE_AB_XX_SD_CTL_DRV_DEF);
+ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVB, FFE_AB_XX_SD_CTL_DRV_DEF);
+ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVA, FFE_AB_XX_SD_CTL_DRV_DEF);
+ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVA, FFE_AB_XX_SD_CTL_DRV_DEF);
+ efx_writeo(efx, &sdctl, FR_AB_XX_SD_CTL);
EFX_POPULATE_OWORD_8(txdrv,
- XX_DEQD, XX_TXDRV_DEQ_DEFAULT,
- XX_DEQC, XX_TXDRV_DEQ_DEFAULT,
- XX_DEQB, XX_TXDRV_DEQ_DEFAULT,
- XX_DEQA, XX_TXDRV_DEQ_DEFAULT,
- XX_DTXD, XX_TXDRV_DTX_DEFAULT,
- XX_DTXC, XX_TXDRV_DTX_DEFAULT,
- XX_DTXB, XX_TXDRV_DTX_DEFAULT,
- XX_DTXA, XX_TXDRV_DTX_DEFAULT);
- falcon_write(efx, &txdrv, XX_TXDRV_CTL_REG);
+ FRF_AB_XX_DEQD, FFE_AB_XX_TXDRV_DEQ_DEF,
+ FRF_AB_XX_DEQC, FFE_AB_XX_TXDRV_DEQ_DEF,
+ FRF_AB_XX_DEQB, FFE_AB_XX_TXDRV_DEQ_DEF,
+ FRF_AB_XX_DEQA, FFE_AB_XX_TXDRV_DEQ_DEF,
+ FRF_AB_XX_DTXD, FFE_AB_XX_TXDRV_DTX_DEF,
+ FRF_AB_XX_DTXC, FFE_AB_XX_TXDRV_DTX_DEF,
+ FRF_AB_XX_DTXB, FFE_AB_XX_TXDRV_DTX_DEF,
+ FRF_AB_XX_DTXA, FFE_AB_XX_TXDRV_DTX_DEF);
+ efx_writeo(efx, &txdrv, FR_AB_XX_TXDRV_CTL);
}
int falcon_reset_xaui(struct efx_nic *efx)
@@ -65,14 +64,14 @@ int falcon_reset_xaui(struct efx_nic *efx)
int count;
/* Start reset sequence */
- EFX_POPULATE_DWORD_1(reg, XX_RST_XX_EN, 1);
- falcon_write(efx, &reg, XX_PWR_RST_REG);
+ EFX_POPULATE_DWORD_1(reg, FRF_AB_XX_RST_XX_EN, 1);
+ efx_writeo(efx, &reg, FR_AB_XX_PWR_RST);
/* Wait up to 10 ms for completion, then reinitialise */
for (count = 0; count < 1000; count++) {
- falcon_read(efx, &reg, XX_PWR_RST_REG);
- if (EFX_OWORD_FIELD(reg, XX_RST_XX_EN) == 0 &&
- EFX_OWORD_FIELD(reg, XX_SD_RST_ACT) == 0) {
+ efx_reado(efx, &reg, FR_AB_XX_PWR_RST);
+ if (EFX_OWORD_FIELD(reg, FRF_AB_XX_RST_XX_EN) == 0 &&
+ EFX_OWORD_FIELD(reg, FRF_AB_XX_SD_RST_ACT) == 0) {
falcon_setup_xaui(efx);
return 0;
}
@@ -100,12 +99,12 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable)
/* Flush the ISR */
if (enable)
- falcon_read(efx, &reg, XM_MGT_INT_REG_B0);
+ efx_reado(efx, &reg, FR_AB_XM_MGT_INT_MSK);
EFX_POPULATE_OWORD_2(reg,
- XM_MSK_RMTFLT, !enable,
- XM_MSK_LCLFLT, !enable);
- falcon_write(efx, &reg, XM_MGT_INT_MSK_REG_B0);
+ FRF_AB_XM_MSK_RMTFLT, !enable,
+ FRF_AB_XM_MSK_LCLFLT, !enable);
+ efx_writeo(efx, &reg, FR_AB_XM_MGT_INT_MASK);
}
/* Get status of XAUI link */
@@ -119,18 +118,18 @@ bool falcon_xaui_link_ok(struct efx_nic *efx)
return true;
/* Read link status */
- falcon_read(efx, &reg, XX_CORE_STAT_REG);
+ efx_reado(efx, &reg, FR_AB_XX_CORE_STAT);
- align_done = EFX_OWORD_FIELD(reg, XX_ALIGN_DONE);
- sync_status = EFX_OWORD_FIELD(reg, XX_SYNC_STAT);
- if (align_done && (sync_status == XX_SYNC_STAT_DECODE_SYNCED))
+ align_done = EFX_OWORD_FIELD(reg, FRF_AB_XX_ALIGN_DONE);
+ sync_status = EFX_OWORD_FIELD(reg, FRF_AB_XX_SYNC_STAT);
+ if (align_done && (sync_status == FFE_AB_XX_STAT_ALL_LANES))
link_ok = true;
/* Clear link status ready for next read */
- EFX_SET_OWORD_FIELD(reg, XX_COMMA_DET, XX_COMMA_DET_RESET);
- EFX_SET_OWORD_FIELD(reg, XX_CHARERR, XX_CHARERR_RESET);
- EFX_SET_OWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET);
- falcon_write(efx, &reg, XX_CORE_STAT_REG);
+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_COMMA_DET, FFE_AB_XX_STAT_ALL_LANES);
+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_CHAR_ERR, FFE_AB_XX_STAT_ALL_LANES);
+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_DISPERR, FFE_AB_XX_STAT_ALL_LANES);
+ efx_writeo(efx, &reg, FR_AB_XX_CORE_STAT);
/* If the link is up, then check the phy side of the xaui link */
if (efx->link_up && link_ok)
@@ -148,55 +147,49 @@ static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
/* Configure MAC - cut-thru mode is hard wired on */
EFX_POPULATE_DWORD_3(reg,
- XM_RX_JUMBO_MODE, 1,
- XM_TX_STAT_EN, 1,
- XM_RX_STAT_EN, 1);
- falcon_write(efx, &reg, XM_GLB_CFG_REG);
+ FRF_AB_XM_RX_JUMBO_MODE, 1,
+ FRF_AB_XM_TX_STAT_EN, 1,
+ FRF_AB_XM_RX_STAT_EN, 1);
+ efx_writeo(efx, &reg, FR_AB_XM_GLB_CFG);
/* Configure TX */
EFX_POPULATE_DWORD_6(reg,
- XM_TXEN, 1,
- XM_TX_PRMBL, 1,
- XM_AUTO_PAD, 1,
- XM_TXCRC, 1,
- XM_FCNTL, 1,
- XM_IPG, 0x3);
- falcon_write(efx, &reg, XM_TX_CFG_REG);
+ FRF_AB_XM_TXEN, 1,
+ FRF_AB_XM_TX_PRMBL, 1,
+ FRF_AB_XM_AUTO_PAD, 1,
+ FRF_AB_XM_TXCRC, 1,
+ FRF_AB_XM_FCNTL, 1,
+ FRF_AB_XM_IPG, 0x3);
+ efx_writeo(efx, &reg, FR_AB_XM_TX_CFG);
/* Configure RX */
EFX_POPULATE_DWORD_5(reg,
- XM_RXEN, 1,
- XM_AUTO_DEPAD, 0,
- XM_ACPT_ALL_MCAST, 1,
- XM_ACPT_ALL_UCAST, efx->promiscuous,
- XM_PASS_CRC_ERR, 1);
- falcon_write(efx, &reg, XM_RX_CFG_REG);
+ FRF_AB_XM_RXEN, 1,
+ FRF_AB_XM_AUTO_DEPAD, 0,
+ FRF_AB_XM_ACPT_ALL_MCAST, 1,
+ FRF_AB_XM_ACPT_ALL_UCAST, efx->promiscuous,
+ FRF_AB_XM_PASS_CRC_ERR, 1);
+ efx_writeo(efx, &reg, FR_AB_XM_RX_CFG);
/* Set frame length */
max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu);
- EFX_POPULATE_DWORD_1(reg, XM_MAX_RX_FRM_SIZE, max_frame_len);
- falcon_write(efx, &reg, XM_RX_PARAM_REG);
+ EFX_POPULATE_DWORD_1(reg, FRF_AB_XM_MAX_RX_FRM_SIZE, max_frame_len);
+ efx_writeo(efx, &reg, FR_AB_XM_RX_PARAM);
EFX_POPULATE_DWORD_2(reg,
- XM_MAX_TX_FRM_SIZE, max_frame_len,
- XM_TX_JUMBO_MODE, 1);
- falcon_write(efx, &reg, XM_TX_PARAM_REG);
+ FRF_AB_XM_MAX_TX_FRM_SIZE, max_frame_len,
+ FRF_AB_XM_TX_JUMBO_MODE, 1);
+ efx_writeo(efx, &reg, FR_AB_XM_TX_PARAM);
EFX_POPULATE_DWORD_2(reg,
- XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */
- XM_DIS_FCNTL, !rx_fc);
- falcon_write(efx, &reg, XM_FC_REG);
+ FRF_AB_XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */
+ FRF_AB_XM_DIS_FCNTL, !rx_fc);
+ efx_writeo(efx, &reg, FR_AB_XM_FC);
/* Set MAC address */
- EFX_POPULATE_DWORD_4(reg,
- XM_ADR_0, efx->net_dev->dev_addr[0],
- XM_ADR_1, efx->net_dev->dev_addr[1],
- XM_ADR_2, efx->net_dev->dev_addr[2],
- XM_ADR_3, efx->net_dev->dev_addr[3]);
- falcon_write(efx, &reg, XM_ADR_LO_REG);
- EFX_POPULATE_DWORD_2(reg,
- XM_ADR_4, efx->net_dev->dev_addr[4],
- XM_ADR_5, efx->net_dev->dev_addr[5]);
- falcon_write(efx, &reg, XM_ADR_HI_REG);
+ memcpy(&reg, &efx->net_dev->dev_addr[0], 4);
+ efx_writeo(efx, &reg, FR_AB_XM_ADR_LO);
+ memcpy(&reg, &efx->net_dev->dev_addr[4], 2);
+ efx_writeo(efx, &reg, FR_AB_XM_ADR_HI);
}
static void falcon_reconfigure_xgxs_core(struct efx_nic *efx)
@@ -212,12 +205,13 @@ static void falcon_reconfigure_xgxs_core(struct efx_nic *efx)
bool old_xgmii_loopback, old_xgxs_loopback, old_xaui_loopback;
bool reset_xgxs;
- falcon_read(efx, &reg, XX_CORE_STAT_REG);
- old_xgxs_loopback = EFX_OWORD_FIELD(reg, XX_XGXS_LB_EN);
- old_xgmii_loopback = EFX_OWORD_FIELD(reg, XX_XGMII_LB_EN);
+ efx_reado(efx, &reg, FR_AB_XX_CORE_STAT);
+ old_xgxs_loopback = EFX_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN);
+ old_xgmii_loopback =
+ EFX_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN);
- falcon_read(efx, &reg, XX_SD_CTL_REG);
- old_xaui_loopback = EFX_OWORD_FIELD(reg, XX_LPBKA);
+ efx_reado(efx, &reg, FR_AB_XX_SD_CTL);
+ old_xaui_loopback = EFX_OWORD_FIELD(reg, FRF_AB_XX_LPBKA);
/* The PHY driver may have turned XAUI off */
reset_xgxs = ((xgxs_loopback != old_xgxs_loopback) ||
@@ -228,20 +222,20 @@ static void falcon_reconfigure_xgxs_core(struct efx_nic *efx)
falcon_reset_xaui(efx);
}
- falcon_read(efx, &reg, XX_CORE_STAT_REG);
- EFX_SET_OWORD_FIELD(reg, XX_FORCE_SIG,
+ efx_reado(efx, &reg, FR_AB_XX_CORE_STAT);
+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_FORCE_SIG,
(xgxs_loopback || xaui_loopback) ?
- XX_FORCE_SIG_DECODE_FORCED : 0);
- EFX_SET_OWORD_FIELD(reg, XX_XGXS_LB_EN, xgxs_loopback);
- EFX_SET_OWORD_FIELD(reg, XX_XGMII_LB_EN, xgmii_loopback);
- falcon_write(efx, &reg, XX_CORE_STAT_REG);
-
- falcon_read(efx, &reg, XX_SD_CTL_REG);
- EFX_SET_OWORD_FIELD(reg, XX_LPBKD, xaui_loopback);
- EFX_SET_OWORD_FIELD(reg, XX_LPBKC, xaui_loopback);
- EFX_SET_OWORD_FIELD(reg, XX_LPBKB, xaui_loopback);
- EFX_SET_OWORD_FIELD(reg, XX_LPBKA, xaui_loopback);
- falcon_write(efx, &reg, XX_SD_CTL_REG);
+ FFE_AB_XX_FORCE_SIG_ALL_LANES : 0);
+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN, xgxs_loopback);
+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN, xgmii_loopback);
+ efx_writeo(efx, &reg, FR_AB_XX_CORE_STAT);
+
+ efx_reado(efx, &reg, FR_AB_XX_SD_CTL);
+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKD, xaui_loopback);
+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKC, xaui_loopback);
+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKB, xaui_loopback);
+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKA, xaui_loopback);
+ efx_writeo(efx, &reg, FR_AB_XX_SD_CTL);
}
diff --git a/drivers/net/sfc/gmii.h b/drivers/net/sfc/gmii.h
deleted file mode 100644
index dfccaa7b573e..000000000000
--- a/drivers/net/sfc/gmii.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2005-2006 Fen Systems Ltd.
- * Copyright 2006-2008 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_GMII_H
-#define EFX_GMII_H
-
-/*
- * GMII interface
- */
-
-#include <linux/mii.h>
-
-/* GMII registers, excluding registers already defined as MII
- * registers in mii.h
- */
-#define GMII_IER 0x12 /* Interrupt enable register */
-#define GMII_ISR 0x13 /* Interrupt status register */
-
-/* Interrupt enable register */
-#define IER_ANEG_ERR 0x8000 /* Bit 15 - autonegotiation error */
-#define IER_SPEED_CHG 0x4000 /* Bit 14 - speed changed */
-#define IER_DUPLEX_CHG 0x2000 /* Bit 13 - duplex changed */
-#define IER_PAGE_RCVD 0x1000 /* Bit 12 - page received */
-#define IER_ANEG_DONE 0x0800 /* Bit 11 - autonegotiation complete */
-#define IER_LINK_CHG 0x0400 /* Bit 10 - link status changed */
-#define IER_SYM_ERR 0x0200 /* Bit 9 - symbol error */
-#define IER_FALSE_CARRIER 0x0100 /* Bit 8 - false carrier */
-#define IER_FIFO_ERR 0x0080 /* Bit 7 - FIFO over/underflow */
-#define IER_MDIX_CHG 0x0040 /* Bit 6 - MDI crossover changed */
-#define IER_DOWNSHIFT 0x0020 /* Bit 5 - downshift */
-#define IER_ENERGY 0x0010 /* Bit 4 - energy detect */
-#define IER_DTE_POWER 0x0004 /* Bit 2 - DTE power detect */
-#define IER_POLARITY_CHG 0x0002 /* Bit 1 - polarity changed */
-#define IER_JABBER 0x0001 /* Bit 0 - jabber */
-
-/* Interrupt status register */
-#define ISR_ANEG_ERR 0x8000 /* Bit 15 - autonegotiation error */
-#define ISR_SPEED_CHG 0x4000 /* Bit 14 - speed changed */
-#define ISR_DUPLEX_CHG 0x2000 /* Bit 13 - duplex changed */
-#define ISR_PAGE_RCVD 0x1000 /* Bit 12 - page received */
-#define ISR_ANEG_DONE 0x0800 /* Bit 11 - autonegotiation complete */
-#define ISR_LINK_CHG 0x0400 /* Bit 10 - link status changed */
-#define ISR_SYM_ERR 0x0200 /* Bit 9 - symbol error */
-#define ISR_FALSE_CARRIER 0x0100 /* Bit 8 - false carrier */
-#define ISR_FIFO_ERR 0x0080 /* Bit 7 - FIFO over/underflow */
-#define ISR_MDIX_CHG 0x0040 /* Bit 6 - MDI crossover changed */
-#define ISR_DOWNSHIFT 0x0020 /* Bit 5 - downshift */
-#define ISR_ENERGY 0x0010 /* Bit 4 - energy detect */
-#define ISR_DTE_POWER 0x0004 /* Bit 2 - DTE power detect */
-#define ISR_POLARITY_CHG 0x0002 /* Bit 1 - polarity changed */
-#define ISR_JABBER 0x0001 /* Bit 0 - jabber */
-
-#endif /* EFX_GMII_H */
diff --git a/drivers/net/sfc/io.h b/drivers/net/sfc/io.h
new file mode 100644
index 000000000000..b89177c27f4a
--- /dev/null
+++ b/drivers/net/sfc/io.h
@@ -0,0 +1,256 @@
+/****************************************************************************
+ * 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.
+ */
+
+#ifndef EFX_IO_H
+#define EFX_IO_H
+
+#include <linux/io.h>
+#include <linux/spinlock.h>
+
+/**************************************************************************
+ *
+ * NIC register I/O
+ *
+ **************************************************************************
+ *
+ * Notes on locking strategy:
+ *
+ * Most NIC registers require 16-byte (or 8-byte, for SRAM) atomic writes
+ * which necessitates locking.
+ * Under normal operation few writes to NIC registers are made and these
+ * registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and TX_DESC_UPD_REG) are special
+ * cased to allow 4-byte (hence lockless) accesses.
+ *
+ * It *is* safe to write to these 4-byte registers in the middle of an
+ * access to an 8-byte or 16-byte register. We therefore use a
+ * spinlock to protect accesses to the larger registers, but no locks
+ * for the 4-byte registers.
+ *
+ * A write barrier is needed to ensure that DW3 is written after DW0/1/2
+ * due to the way the 16byte registers are "collected" in the BIU.
+ *
+ * We also lock when carrying out reads, to ensure consistency of the
+ * data (made possible since the BIU reads all 128 bits into a cache).
+ * Reads are very rare, so this isn't a significant performance
+ * impact. (Most data transferred from NIC to host is DMAed directly
+ * into host memory).
+ *
+ * I/O BAR access uses locks for both reads and writes (but is only provided
+ * for testing purposes).
+ */
+
+#if BITS_PER_LONG == 64
+#define EFX_USE_QWORD_IO 1
+#endif
+
+#ifdef EFX_USE_QWORD_IO
+static inline void _efx_writeq(struct efx_nic *efx, __le64 value,
+ unsigned int reg)
+{
+ __raw_writeq((__force u64)value, efx->membase + reg);
+}
+static inline __le64 _efx_readq(struct efx_nic *efx, unsigned int reg)
+{
+ return (__force __le64)__raw_readq(efx->membase + reg);
+}
+#endif
+
+static inline void _efx_writed(struct efx_nic *efx, __le32 value,
+ unsigned int reg)
+{
+ __raw_writel((__force u32)value, efx->membase + reg);
+}
+static inline __le32 _efx_readd(struct efx_nic *efx, unsigned int reg)
+{
+ return (__force __le32)__raw_readl(efx->membase + reg);
+}
+
+/* Writes to a normal 16-byte Efx register, locking as appropriate. */
+static inline void efx_writeo(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg)
+{
+ unsigned long flags __attribute__ ((unused));
+
+ EFX_REGDUMP(efx, "writing register %x with " EFX_OWORD_FMT "\n", reg,
+ EFX_OWORD_VAL(*value));
+
+ spin_lock_irqsave(&efx->biu_lock, flags);
+#ifdef EFX_USE_QWORD_IO
+ _efx_writeq(efx, value->u64[0], reg + 0);
+ wmb();
+ _efx_writeq(efx, value->u64[1], reg + 8);
+#else
+ _efx_writed(efx, value->u32[0], reg + 0);
+ _efx_writed(efx, value->u32[1], reg + 4);
+ _efx_writed(efx, value->u32[2], reg + 8);
+ wmb();
+ _efx_writed(efx, value->u32[3], reg + 12);
+#endif
+ mmiowb();
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+}
+
+/* Write an 8-byte NIC SRAM entry through the supplied mapping,
+ * locking as appropriate. */
+static inline void efx_sram_writeq(struct efx_nic *efx, void __iomem *membase,
+ efx_qword_t *value, unsigned int index)
+{
+ unsigned int addr = index * sizeof(*value);
+ unsigned long flags __attribute__ ((unused));
+
+ EFX_REGDUMP(efx, "writing SRAM address %x with " EFX_QWORD_FMT "\n",
+ addr, EFX_QWORD_VAL(*value));
+
+ spin_lock_irqsave(&efx->biu_lock, flags);
+#ifdef EFX_USE_QWORD_IO
+ __raw_writeq((__force u64)value->u64[0], membase + addr);
+#else
+ __raw_writel((__force u32)value->u32[0], membase + addr);
+ wmb();
+ __raw_writel((__force u32)value->u32[1], membase + addr + 4);
+#endif
+ mmiowb();
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+}
+
+/* Write dword to NIC register that allows partial writes
+ *
+ * Some registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and
+ * TX_DESC_UPD_REG) can be written to as a single dword. This allows
+ * for lockless writes.
+ */
+static inline void efx_writed(struct efx_nic *efx, efx_dword_t *value,
+ unsigned int reg)
+{
+ EFX_REGDUMP(efx, "writing partial register %x with "EFX_DWORD_FMT"\n",
+ reg, EFX_DWORD_VAL(*value));
+
+ /* No lock required */
+ _efx_writed(efx, value->u32[0], reg);
+}
+
+/* Read from a NIC register
+ *
+ * This reads an entire 16-byte register in one go, locking as
+ * appropriate. It is essential to read the first dword first, as this
+ * prompts the NIC to load the current value into the shadow register.
+ */
+static inline void efx_reado(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg)
+{
+ unsigned long flags __attribute__ ((unused));
+
+ spin_lock_irqsave(&efx->biu_lock, flags);
+ value->u32[0] = _efx_readd(efx, reg + 0);
+ rmb();
+ value->u32[1] = _efx_readd(efx, reg + 4);
+ value->u32[2] = _efx_readd(efx, reg + 8);
+ value->u32[3] = _efx_readd(efx, reg + 12);
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+
+ EFX_REGDUMP(efx, "read from register %x, got " EFX_OWORD_FMT "\n", reg,
+ EFX_OWORD_VAL(*value));
+}
+
+/* Read an 8-byte SRAM entry through supplied mapping,
+ * locking as appropriate. */
+static inline void efx_sram_readq(struct efx_nic *efx, void __iomem *membase,
+ efx_qword_t *value, unsigned int index)
+{
+ unsigned int addr = index * sizeof(*value);
+ unsigned long flags __attribute__ ((unused));
+
+ spin_lock_irqsave(&efx->biu_lock, flags);
+#ifdef EFX_USE_QWORD_IO
+ value->u64[0] = (__force __le64)__raw_readq(membase + addr);
+#else
+ value->u32[0] = (__force __le32)__raw_readl(membase + addr);
+ rmb();
+ value->u32[1] = (__force __le32)__raw_readl(membase + addr + 4);
+#endif
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+
+ EFX_REGDUMP(efx, "read from SRAM address %x, got "EFX_QWORD_FMT"\n",
+ addr, EFX_QWORD_VAL(*value));
+}
+
+/* Read dword from register that allows partial writes (sic) */
+static inline void efx_readd(struct efx_nic *efx, efx_dword_t *value,
+ unsigned int reg)
+{
+ value->u32[0] = _efx_readd(efx, reg);
+ EFX_REGDUMP(efx, "read from register %x, got "EFX_DWORD_FMT"\n",
+ reg, EFX_DWORD_VAL(*value));
+}
+
+/* Write to a register forming part of a table */
+static inline void efx_writeo_table(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg, unsigned int index)
+{
+ efx_writeo(efx, value, reg + index * sizeof(efx_oword_t));
+}
+
+/* Read to a register forming part of a table */
+static inline void efx_reado_table(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg, unsigned int index)
+{
+ efx_reado(efx, value, reg + index * sizeof(efx_oword_t));
+}
+
+/* Write to a dword register forming part of a table */
+static inline void efx_writed_table(struct efx_nic *efx, efx_dword_t *value,
+ unsigned int reg, unsigned int index)
+{
+ efx_writed(efx, value, reg + index * sizeof(efx_oword_t));
+}
+
+/* Page-mapped register block size */
+#define EFX_PAGE_BLOCK_SIZE 0x2000
+
+/* Calculate offset to page-mapped register block */
+#define EFX_PAGED_REG(page, reg) \
+ ((page) * EFX_PAGE_BLOCK_SIZE + (reg))
+
+/* As for efx_writeo(), but for a page-mapped register. */
+static inline void efx_writeo_page(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg, unsigned int page)
+{
+ efx_writeo(efx, value, EFX_PAGED_REG(page, reg));
+}
+
+/* As for efx_writed(), but for a page-mapped register. */
+static inline void efx_writed_page(struct efx_nic *efx, efx_dword_t *value,
+ unsigned int reg, unsigned int page)
+{
+ efx_writed(efx, value, EFX_PAGED_REG(page, reg));
+}
+
+/* Write dword to page-mapped register with an extra lock.
+ *
+ * As for efx_writed_page(), but for a register that suffers from
+ * SFC bug 3181. Take out a lock so the BIU collector cannot be
+ * confused. */
+static inline void efx_writed_page_locked(struct efx_nic *efx,
+ efx_dword_t *value,
+ unsigned int reg,
+ unsigned int page)
+{
+ unsigned long flags __attribute__ ((unused));
+
+ if (page == 0) {
+ spin_lock_irqsave(&efx->biu_lock, flags);
+ efx_writed(efx, value, EFX_PAGED_REG(page, reg));
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+ } else {
+ efx_writed(efx, value, EFX_PAGED_REG(page, reg));
+ }
+}
+
+#endif /* EFX_IO_H */
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
index 6c33459f9ea9..231e580acc9a 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/sfc/mdio_10g.c
@@ -14,7 +14,6 @@
#include <linux/delay.h>
#include "net_driver.h"
#include "mdio_10g.h"
-#include "boards.h"
#include "workarounds.h"
unsigned efx_mdio_id_oui(u32 id)
@@ -249,7 +248,7 @@ void efx_mdio_set_mmds_lpower(struct efx_nic *efx,
int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
{
struct ethtool_cmd prev;
- u32 required;
+ bool xnp;
int reg;
efx->phy_op->get_settings(efx, &prev);
@@ -266,86 +265,60 @@ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
return -EINVAL;
/* Check that PHY supports these settings */
- if (ecmd->autoneg) {
- required = SUPPORTED_Autoneg;
- } else if (ecmd->duplex) {
- switch (ecmd->speed) {
- case SPEED_10: required = SUPPORTED_10baseT_Full; break;
- case SPEED_100: required = SUPPORTED_100baseT_Full; break;
- default: return -EINVAL;
- }
- } else {
- switch (ecmd->speed) {
- case SPEED_10: required = SUPPORTED_10baseT_Half; break;
- case SPEED_100: required = SUPPORTED_100baseT_Half; break;
- default: return -EINVAL;
- }
- }
- required |= ecmd->advertising;
- if (required & ~prev.supported)
+ if (!ecmd->autoneg ||
+ (ecmd->advertising | SUPPORTED_Autoneg) & ~prev.supported)
return -EINVAL;
- if (ecmd->autoneg) {
- bool xnp = (ecmd->advertising & ADVERTISED_10000baseT_Full
- || EFX_WORKAROUND_13204(efx));
-
- /* Set up the base page */
- reg = ADVERTISE_CSMA;
- if (ecmd->advertising & ADVERTISED_10baseT_Half)
- reg |= ADVERTISE_10HALF;
- if (ecmd->advertising & ADVERTISED_10baseT_Full)
- reg |= ADVERTISE_10FULL;
- if (ecmd->advertising & ADVERTISED_100baseT_Half)
- reg |= ADVERTISE_100HALF;
- if (ecmd->advertising & ADVERTISED_100baseT_Full)
- reg |= ADVERTISE_100FULL;
- if (xnp)
- reg |= ADVERTISE_RESV;
- else if (ecmd->advertising & (ADVERTISED_1000baseT_Half |
- ADVERTISED_1000baseT_Full))
- reg |= ADVERTISE_NPAGE;
- reg |= mii_advertise_flowctrl(efx->wanted_fc);
- 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, ecmd->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_MASK(efx) & efx->phy_op->loopbacks))
- reg |= MDIO_AN_CTRL1_RESTART;
- if (xnp)
- reg |= MDIO_AN_CTRL1_XNP;
- else
- reg &= ~MDIO_AN_CTRL1_XNP;
- efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg);
- } else {
- /* Disable AN */
- efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_CTRL1,
- MDIO_AN_CTRL1_ENABLE, false);
-
- /* Set the basic control bits */
- reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1);
- reg &= ~(MDIO_CTRL1_SPEEDSEL | MDIO_CTRL1_FULLDPLX);
- if (ecmd->speed == SPEED_100)
- reg |= MDIO_PMA_CTRL1_SPEED100;
- if (ecmd->duplex)
- reg |= MDIO_CTRL1_FULLDPLX;
- efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1, reg);
- }
+ xnp = (ecmd->advertising & ADVERTISED_10000baseT_Full
+ || EFX_WORKAROUND_13204(efx));
+
+ /* Set up the base page */
+ reg = ADVERTISE_CSMA;
+ if (ecmd->advertising & ADVERTISED_10baseT_Half)
+ reg |= ADVERTISE_10HALF;
+ if (ecmd->advertising & ADVERTISED_10baseT_Full)
+ reg |= ADVERTISE_10FULL;
+ if (ecmd->advertising & ADVERTISED_100baseT_Half)
+ reg |= ADVERTISE_100HALF;
+ if (ecmd->advertising & ADVERTISED_100baseT_Full)
+ reg |= ADVERTISE_100FULL;
+ if (xnp)
+ reg |= ADVERTISE_RESV;
+ else if (ecmd->advertising & (ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full))
+ reg |= ADVERTISE_NPAGE;
+ reg |= mii_advertise_flowctrl(efx->wanted_fc);
+ 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, ecmd->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_MASK(efx) & efx->phy_op->loopbacks))
+ reg |= MDIO_AN_CTRL1_RESTART;
+ if (xnp)
+ reg |= MDIO_AN_CTRL1_XNP;
+ else
+ reg &= ~MDIO_AN_CTRL1_XNP;
+ efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg);
return 0;
}
enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx)
{
- int lpa;
+ BUILD_BUG_ON(EFX_FC_AUTO & (EFX_FC_RX | EFX_FC_TX));
- if (!(efx->phy_op->mmds & MDIO_DEVS_AN))
+ if (!(efx->wanted_fc & EFX_FC_AUTO))
return efx->wanted_fc;
- lpa = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_LPA);
- return efx_fc_resolve(efx->wanted_fc, lpa);
+
+ WARN_ON(!(efx->mdio.mmds & MDIO_DEVS_AN));
+
+ return mii_resolve_flowctrl_fdx(
+ mii_advertise_flowctrl(efx->wanted_fc),
+ efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_LPA));
}
diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h
index 6b14421a7444..75b37f101231 100644
--- a/drivers/net/sfc/mdio_10g.h
+++ b/drivers/net/sfc/mdio_10g.h
@@ -17,7 +17,6 @@
*/
#include "efx.h"
-#include "boards.h"
static inline unsigned efx_mdio_id_rev(u32 id) { return id & 0xf; }
static inline unsigned efx_mdio_id_model(u32 id) { return (id >> 4) & 0x3f; }
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 298566da638b..bb3d258bd5e8 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -327,7 +327,7 @@ enum efx_rx_alloc_method {
* @used_flags: Channel is used by net driver
* @enabled: Channel enabled indicator
* @irq: IRQ number (MSI and MSI-X only)
- * @irq_moderation: IRQ moderation value (in us)
+ * @irq_moderation: IRQ moderation value (in hardware ticks)
* @napi_dev: Net device used with NAPI
* @napi_str: NAPI control structure
* @reset_work: Scheduled reset work thread
@@ -389,19 +389,6 @@ struct efx_channel {
};
/**
- * struct efx_blinker - S/W LED blinking context
- * @state: Current state - on or off
- * @resubmit: Timer resubmission flag
- * @timer: Control timer for blinking
- */
-struct efx_blinker {
- bool state;
- bool resubmit;
- struct timer_list timer;
-};
-
-
-/**
* struct efx_board - board information
* @type: Board model type
* @major: Major rev. ('A', 'B' ...)
@@ -412,7 +399,9 @@ struct efx_blinker {
* @blink: Starts/stops blinking
* @monitor: Board-specific health check function
* @fini: Cleanup function
- * @blinker: used to blink LEDs in software
+ * @blink_state: Current blink state
+ * @blink_resubmit: Blink timer resubmission flag
+ * @blink_timer: Blink timer
* @hwmon_client: I2C client for hardware monitor
* @ioexp_client: I2C client for power/port control
*/
@@ -429,7 +418,9 @@ struct efx_board {
int (*monitor) (struct efx_nic *nic);
void (*blink) (struct efx_nic *efx, bool start);
void (*fini) (struct efx_nic *nic);
- struct efx_blinker blinker;
+ bool blink_state;
+ bool blink_resubmit;
+ struct timer_list blink_timer;
struct i2c_client *hwmon_client, *ioexp_client;
};
@@ -506,17 +497,6 @@ enum efx_mac_type {
EFX_XMAC = 2,
};
-static inline enum efx_fc_type efx_fc_resolve(enum efx_fc_type wanted_fc,
- unsigned int lpa)
-{
- BUILD_BUG_ON(EFX_FC_AUTO & (EFX_FC_RX | EFX_FC_TX));
-
- if (!(wanted_fc & EFX_FC_AUTO))
- return wanted_fc;
-
- return mii_resolve_flowctrl_fdx(mii_advertise_flowctrl(wanted_fc), lpa);
-}
-
/**
* struct efx_mac_operations - Efx MAC operations table
* @reconfigure: Reconfigure MAC. Serialised by the mac_lock
@@ -537,7 +517,6 @@ struct efx_mac_operations {
* @fini: Shut down PHY
* @reconfigure: Reconfigure PHY (e.g. for new link parameters)
* @clear_interrupt: Clear down interrupt
- * @blink: Blink LEDs
* @poll: Poll for hardware state. Serialised by the mac_lock.
* @get_settings: Get ethtool settings. Serialised by the mac_lock.
* @set_settings: Set ethtool settings. Serialised by the mac_lock.
@@ -697,10 +676,13 @@ union efx_multicast_hash {
* @tx_queue: TX DMA queues
* @rx_queue: RX DMA queues
* @channel: Channels
+ * @next_buffer_table: First available buffer table id
* @n_rx_queues: Number of RX queues
* @n_channels: Number of channels in use
* @rx_buffer_len: RX buffer length
* @rx_buffer_order: Order (log2) of number of pages for each RX buffer
+ * @int_error_count: Number of internal errors seen recently
+ * @int_error_expire: Time at which error count will be expired
* @irq_status: Interrupt status buffer
* @last_irq_cpu: Last CPU to handle interrupt.
* This register is written with the SMP processor ID whenever an
@@ -784,11 +766,15 @@ struct efx_nic {
struct efx_rx_queue rx_queue[EFX_MAX_RX_QUEUES];
struct efx_channel channel[EFX_MAX_CHANNELS];
+ unsigned next_buffer_table;
int n_rx_queues;
int n_channels;
unsigned int rx_buffer_len;
unsigned int rx_buffer_order;
+ unsigned int_error_count;
+ unsigned long int_error_expire;
+
struct efx_buffer irq_status;
volatile signed int last_irq_cpu;
@@ -869,14 +855,7 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
* @buf_tbl_base: Buffer table base address
* @evq_ptr_tbl_base: Event queue pointer table base address
* @evq_rptr_tbl_base: Event queue read-pointer table base address
- * @txd_ring_mask: TX descriptor ring size - 1 (must be a power of two - 1)
- * @rxd_ring_mask: RX descriptor ring size - 1 (must be a power of two - 1)
- * @evq_size: Event queue size (must be a power of two)
* @max_dma_mask: Maximum possible DMA mask
- * @tx_dma_mask: TX DMA mask
- * @bug5391_mask: Address mask for bug 5391 workaround
- * @rx_xoff_thresh: RX FIFO XOFF watermark (bytes)
- * @rx_xon_thresh: RX FIFO XON watermark (bytes)
* @rx_buffer_padding: Padding added to each RX buffer
* @max_interrupt_mode: Highest capability interrupt mode supported
* from &enum efx_init_mode.
@@ -892,15 +871,8 @@ struct efx_nic_type {
unsigned int evq_ptr_tbl_base;
unsigned int evq_rptr_tbl_base;
- unsigned int txd_ring_mask;
- unsigned int rxd_ring_mask;
- unsigned int evq_size;
u64 max_dma_mask;
- unsigned int tx_dma_mask;
- unsigned bug5391_mask;
- int rx_xoff_thresh;
- int rx_xon_thresh;
unsigned int rx_buffer_padding;
unsigned int max_interrupt_mode;
unsigned int phys_addr_channels;
diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h
index c1cff9c0c173..b5150f3bca31 100644
--- a/drivers/net/sfc/phy.h
+++ b/drivers/net/sfc/phy.h
@@ -23,9 +23,9 @@ extern void tenxpress_phy_blink(struct efx_nic *efx, bool blink);
extern int sft9001_wait_boot(struct efx_nic *efx);
/****************************************************************************
- * AMCC/Quake QT20xx PHYs
+ * AMCC/Quake QT202x PHYs
*/
-extern struct efx_phy_operations falcon_xfp_phy_ops;
+extern struct efx_phy_operations falcon_qt202x_phy_ops;
/* These PHYs provide various H/W control states for LEDs */
#define QUAKE_LED_LINK_INVAL (0)
@@ -39,6 +39,6 @@ extern struct efx_phy_operations falcon_xfp_phy_ops;
#define QUAKE_LED_TXLINK (0)
#define QUAKE_LED_RXLINK (8)
-extern void xfp_set_led(struct efx_nic *p, int led, int state);
+extern void falcon_qt202x_set_led(struct efx_nic *p, int led, int state);
#endif
diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/qt202x_phy.c
index e6b3d5eaddba..560eb18280e1 100644
--- a/drivers/net/sfc/xfp_phy.c
+++ b/drivers/net/sfc/qt202x_phy.c
@@ -7,8 +7,7 @@
* by the Free Software Foundation, incorporated herein by reference.
*/
/*
- * Driver for SFP+ and XFP optical PHYs plus some support specific to the
- * AMCC QT20xx adapters; see www.amcc.com for details
+ * Driver for AMCC QT202x SFP+ and XFP adapters; see www.amcc.com for details
*/
#include <linux/timer.h>
@@ -18,13 +17,13 @@
#include "phy.h"
#include "falcon.h"
-#define XFP_REQUIRED_DEVS (MDIO_DEVS_PCS | \
- MDIO_DEVS_PMAPMD | \
- MDIO_DEVS_PHYXS)
+#define QT202X_REQUIRED_DEVS (MDIO_DEVS_PCS | \
+ MDIO_DEVS_PMAPMD | \
+ MDIO_DEVS_PHYXS)
-#define XFP_LOOPBACKS ((1 << LOOPBACK_PCS) | \
- (1 << LOOPBACK_PMAPMD) | \
- (1 << LOOPBACK_NETWORK))
+#define QT202X_LOOPBACKS ((1 << LOOPBACK_PCS) | \
+ (1 << LOOPBACK_PMAPMD) | \
+ (1 << LOOPBACK_NETWORK))
/****************************************************************************/
/* Quake-specific MDIO registers */
@@ -45,18 +44,18 @@
#define PCS_VEND1_REG 0xc000
#define PCS_VEND1_LBTXD_LBN 5
-void xfp_set_led(struct efx_nic *p, int led, int mode)
+void falcon_qt202x_set_led(struct efx_nic *p, int led, int mode)
{
int addr = MDIO_QUAKE_LED0_REG + led;
efx_mdio_write(p, MDIO_MMD_PMAPMD, addr, mode);
}
-struct xfp_phy_data {
+struct qt202x_phy_data {
enum efx_phy_mode phy_mode;
};
-#define XFP_MAX_RESET_TIME 500
-#define XFP_RESET_WAIT 10
+#define QT2022C2_MAX_RESET_TIME 500
+#define QT2022C2_RESET_WAIT 10
static int qt2025c_wait_reset(struct efx_nic *efx)
{
@@ -97,7 +96,7 @@ static int qt2025c_wait_reset(struct efx_nic *efx)
return 0;
}
-static int xfp_reset_phy(struct efx_nic *efx)
+static int qt202x_reset_phy(struct efx_nic *efx)
{
int rc;
@@ -111,8 +110,9 @@ static int xfp_reset_phy(struct efx_nic *efx)
/* Reset the PHYXS MMD. This is documented as doing
* a complete soft reset. */
rc = efx_mdio_reset_mmd(efx, MDIO_MMD_PHYXS,
- XFP_MAX_RESET_TIME / XFP_RESET_WAIT,
- XFP_RESET_WAIT);
+ QT2022C2_MAX_RESET_TIME /
+ QT2022C2_RESET_WAIT,
+ QT2022C2_RESET_WAIT);
if (rc < 0)
goto fail;
}
@@ -122,7 +122,7 @@ static int xfp_reset_phy(struct efx_nic *efx)
/* Check that all the MMDs we expect are present and responding. We
* expect faults on some if the link is down, but not on the PHY XS */
- rc = efx_mdio_check_mmds(efx, XFP_REQUIRED_DEVS, MDIO_DEVS_PHYXS);
+ rc = efx_mdio_check_mmds(efx, QT202X_REQUIRED_DEVS, MDIO_DEVS_PHYXS);
if (rc < 0)
goto fail;
@@ -135,13 +135,13 @@ static int xfp_reset_phy(struct efx_nic *efx)
return rc;
}
-static int xfp_phy_init(struct efx_nic *efx)
+static int qt202x_phy_init(struct efx_nic *efx)
{
- struct xfp_phy_data *phy_data;
+ struct qt202x_phy_data *phy_data;
u32 devid = efx_mdio_read_id(efx, MDIO_MMD_PHYXS);
int rc;
- phy_data = kzalloc(sizeof(struct xfp_phy_data), GFP_KERNEL);
+ phy_data = kzalloc(sizeof(struct qt202x_phy_data), GFP_KERNEL);
if (!phy_data)
return -ENOMEM;
efx->phy_data = phy_data;
@@ -152,7 +152,7 @@ static int xfp_phy_init(struct efx_nic *efx)
phy_data->phy_mode = efx->phy_mode;
- rc = xfp_reset_phy(efx);
+ rc = qt202x_reset_phy(efx);
EFX_INFO(efx, "PHY init %s.\n",
rc ? "failed" : "successful");
@@ -167,28 +167,28 @@ static int xfp_phy_init(struct efx_nic *efx)
return rc;
}
-static void xfp_phy_clear_interrupt(struct efx_nic *efx)
+static void qt202x_phy_clear_interrupt(struct efx_nic *efx)
{
/* Read to clear link status alarm */
efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT);
}
-static int xfp_link_ok(struct efx_nic *efx)
+static int qt202x_link_ok(struct efx_nic *efx)
{
- return efx_mdio_links_ok(efx, XFP_REQUIRED_DEVS);
+ return efx_mdio_links_ok(efx, QT202X_REQUIRED_DEVS);
}
-static void xfp_phy_poll(struct efx_nic *efx)
+static void qt202x_phy_poll(struct efx_nic *efx)
{
- int link_up = xfp_link_ok(efx);
+ int link_up = qt202x_link_ok(efx);
/* Simulate a PHY event if link state has changed */
if (link_up != efx->link_up)
falcon_sim_phy_event(efx);
}
-static void xfp_phy_reconfigure(struct efx_nic *efx)
+static void qt202x_phy_reconfigure(struct efx_nic *efx)
{
- struct xfp_phy_data *phy_data = efx->phy_data;
+ struct qt202x_phy_data *phy_data = efx->phy_data;
if (efx->phy_type == PHY_TYPE_QT2025C) {
/* There are several different register bits which can
@@ -207,7 +207,7 @@ static void xfp_phy_reconfigure(struct efx_nic *efx)
/* Reset the PHY when moving from tx off to tx on */
if (!(efx->phy_mode & PHY_MODE_TX_DISABLED) &&
(phy_data->phy_mode & PHY_MODE_TX_DISABLED))
- xfp_reset_phy(efx);
+ qt202x_reset_phy(efx);
efx_mdio_transmit_disable(efx);
}
@@ -215,18 +215,18 @@ static void xfp_phy_reconfigure(struct efx_nic *efx)
efx_mdio_phy_reconfigure(efx);
phy_data->phy_mode = efx->phy_mode;
- efx->link_up = xfp_link_ok(efx);
+ efx->link_up = qt202x_link_ok(efx);
efx->link_speed = 10000;
efx->link_fd = true;
efx->link_fc = efx->wanted_fc;
}
-static void xfp_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+static void qt202x_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
{
mdio45_ethtool_gset(&efx->mdio, ecmd);
}
-static void xfp_phy_fini(struct efx_nic *efx)
+static void qt202x_phy_fini(struct efx_nic *efx)
{
/* Clobber the LED if it was blinking */
efx->board_info.blink(efx, false);
@@ -236,15 +236,15 @@ static void xfp_phy_fini(struct efx_nic *efx)
efx->phy_data = NULL;
}
-struct efx_phy_operations falcon_xfp_phy_ops = {
+struct efx_phy_operations falcon_qt202x_phy_ops = {
.macs = EFX_XMAC,
- .init = xfp_phy_init,
- .reconfigure = xfp_phy_reconfigure,
- .poll = xfp_phy_poll,
- .fini = xfp_phy_fini,
- .clear_interrupt = xfp_phy_clear_interrupt,
- .get_settings = xfp_phy_get_settings,
+ .init = qt202x_phy_init,
+ .reconfigure = qt202x_phy_reconfigure,
+ .poll = qt202x_phy_poll,
+ .fini = qt202x_phy_fini,
+ .clear_interrupt = qt202x_phy_clear_interrupt,
+ .get_settings = qt202x_phy_get_settings,
.set_settings = efx_mdio_set_settings,
- .mmds = XFP_REQUIRED_DEVS,
- .loopbacks = XFP_LOOPBACKS,
+ .mmds = QT202X_REQUIRED_DEVS,
+ .loopbacks = QT202X_LOOPBACKS,
};
diff --git a/drivers/net/sfc/regs.h b/drivers/net/sfc/regs.h
new file mode 100644
index 000000000000..f336d83d5fa0
--- /dev/null
+++ b/drivers/net/sfc/regs.h
@@ -0,0 +1,3180 @@
+/****************************************************************************
+ * 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.
+ */
+
+#ifndef EFX_REGS_H
+#define EFX_REGS_H
+
+/*
+ * Falcon hardware architecture definitions have a name prefix following
+ * the format:
+ *
+ * F<type>_<min-rev><max-rev>_
+ *
+ * The following <type> strings are used:
+ *
+ * MMIO register MC register Host memory structure
+ * -------------------------------------------------------------
+ * Address R MCR
+ * Bitfield RF MCRF SF
+ * Enumerator FE MCFE SE
+ *
+ * <min-rev> is the first revision to which the definition applies:
+ *
+ * A: Falcon A1 (SFC4000AB)
+ * B: Falcon B0 (SFC4000BA)
+ * C: Siena A0 (SFL9021AA)
+ *
+ * If the definition has been changed or removed in later revisions
+ * then <max-rev> is the last revision to which the definition applies;
+ * otherwise it is "Z".
+ */
+
+/**************************************************************************
+ *
+ * Falcon/Siena registers and descriptors
+ *
+ **************************************************************************
+ */
+
+/* ADR_REGION_REG: Address region register */
+#define FR_AZ_ADR_REGION 0x00000000
+#define FRF_AZ_ADR_REGION3_LBN 96
+#define FRF_AZ_ADR_REGION3_WIDTH 18
+#define FRF_AZ_ADR_REGION2_LBN 64
+#define FRF_AZ_ADR_REGION2_WIDTH 18
+#define FRF_AZ_ADR_REGION1_LBN 32
+#define FRF_AZ_ADR_REGION1_WIDTH 18
+#define FRF_AZ_ADR_REGION0_LBN 0
+#define FRF_AZ_ADR_REGION0_WIDTH 18
+
+/* INT_EN_REG_KER: Kernel driver Interrupt enable register */
+#define FR_AZ_INT_EN_KER 0x00000010
+#define FRF_AZ_KER_INT_LEVE_SEL_LBN 8
+#define FRF_AZ_KER_INT_LEVE_SEL_WIDTH 6
+#define FRF_AZ_KER_INT_CHAR_LBN 4
+#define FRF_AZ_KER_INT_CHAR_WIDTH 1
+#define FRF_AZ_KER_INT_KER_LBN 3
+#define FRF_AZ_KER_INT_KER_WIDTH 1
+#define FRF_AZ_DRV_INT_EN_KER_LBN 0
+#define FRF_AZ_DRV_INT_EN_KER_WIDTH 1
+
+/* INT_EN_REG_CHAR: Char Driver interrupt enable register */
+#define FR_BZ_INT_EN_CHAR 0x00000020
+#define FRF_BZ_CHAR_INT_LEVE_SEL_LBN 8
+#define FRF_BZ_CHAR_INT_LEVE_SEL_WIDTH 6
+#define FRF_BZ_CHAR_INT_CHAR_LBN 4
+#define FRF_BZ_CHAR_INT_CHAR_WIDTH 1
+#define FRF_BZ_CHAR_INT_KER_LBN 3
+#define FRF_BZ_CHAR_INT_KER_WIDTH 1
+#define FRF_BZ_DRV_INT_EN_CHAR_LBN 0
+#define FRF_BZ_DRV_INT_EN_CHAR_WIDTH 1
+
+/* INT_ADR_REG_KER: Interrupt host address for Kernel driver */
+#define FR_AZ_INT_ADR_KER 0x00000030
+#define FRF_AZ_NORM_INT_VEC_DIS_KER_LBN 64
+#define FRF_AZ_NORM_INT_VEC_DIS_KER_WIDTH 1
+#define FRF_AZ_INT_ADR_KER_LBN 0
+#define FRF_AZ_INT_ADR_KER_WIDTH 64
+
+/* INT_ADR_REG_CHAR: Interrupt host address for Char driver */
+#define FR_BZ_INT_ADR_CHAR 0x00000040
+#define FRF_BZ_NORM_INT_VEC_DIS_CHAR_LBN 64
+#define FRF_BZ_NORM_INT_VEC_DIS_CHAR_WIDTH 1
+#define FRF_BZ_INT_ADR_CHAR_LBN 0
+#define FRF_BZ_INT_ADR_CHAR_WIDTH 64
+
+/* INT_ACK_KER: Kernel interrupt acknowledge register */
+#define FR_AA_INT_ACK_KER 0x00000050
+#define FRF_AA_INT_ACK_KER_FIELD_LBN 0
+#define FRF_AA_INT_ACK_KER_FIELD_WIDTH 32
+
+/* INT_ISR0_REG: Function 0 Interrupt Acknowlege Status register */
+#define FR_BZ_INT_ISR0 0x00000090
+#define FRF_BZ_INT_ISR_REG_LBN 0
+#define FRF_BZ_INT_ISR_REG_WIDTH 64
+
+/* HW_INIT_REG: Hardware initialization register */
+#define FR_AZ_HW_INIT 0x000000c0
+#define FRF_BB_BDMRD_CPLF_FULL_LBN 124
+#define FRF_BB_BDMRD_CPLF_FULL_WIDTH 1
+#define FRF_BB_PCIE_CPL_TIMEOUT_CTRL_LBN 121
+#define FRF_BB_PCIE_CPL_TIMEOUT_CTRL_WIDTH 3
+#define FRF_CZ_TX_MRG_TAGS_LBN 120
+#define FRF_CZ_TX_MRG_TAGS_WIDTH 1
+#define FRF_AB_TRGT_MASK_ALL_LBN 100
+#define FRF_AB_TRGT_MASK_ALL_WIDTH 1
+#define FRF_AZ_DOORBELL_DROP_LBN 92
+#define FRF_AZ_DOORBELL_DROP_WIDTH 8
+#define FRF_AB_TX_RREQ_MASK_EN_LBN 76
+#define FRF_AB_TX_RREQ_MASK_EN_WIDTH 1
+#define FRF_AB_PE_EIDLE_DIS_LBN 75
+#define FRF_AB_PE_EIDLE_DIS_WIDTH 1
+#define FRF_AA_FC_BLOCKING_EN_LBN 45
+#define FRF_AA_FC_BLOCKING_EN_WIDTH 1
+#define FRF_BZ_B2B_REQ_EN_LBN 45
+#define FRF_BZ_B2B_REQ_EN_WIDTH 1
+#define FRF_AA_B2B_REQ_EN_LBN 44
+#define FRF_AA_B2B_REQ_EN_WIDTH 1
+#define FRF_BB_FC_BLOCKING_EN_LBN 44
+#define FRF_BB_FC_BLOCKING_EN_WIDTH 1
+#define FRF_AZ_POST_WR_MASK_LBN 40
+#define FRF_AZ_POST_WR_MASK_WIDTH 4
+#define FRF_AZ_TLP_TC_LBN 34
+#define FRF_AZ_TLP_TC_WIDTH 3
+#define FRF_AZ_TLP_ATTR_LBN 32
+#define FRF_AZ_TLP_ATTR_WIDTH 2
+#define FRF_AB_INTB_VEC_LBN 24
+#define FRF_AB_INTB_VEC_WIDTH 5
+#define FRF_AB_INTA_VEC_LBN 16
+#define FRF_AB_INTA_VEC_WIDTH 5
+#define FRF_AZ_WD_TIMER_LBN 8
+#define FRF_AZ_WD_TIMER_WIDTH 8
+#define FRF_AZ_US_DISABLE_LBN 5
+#define FRF_AZ_US_DISABLE_WIDTH 1
+#define FRF_AZ_TLP_EP_LBN 4
+#define FRF_AZ_TLP_EP_WIDTH 1
+#define FRF_AZ_ATTR_SEL_LBN 3
+#define FRF_AZ_ATTR_SEL_WIDTH 1
+#define FRF_AZ_TD_SEL_LBN 1
+#define FRF_AZ_TD_SEL_WIDTH 1
+#define FRF_AZ_TLP_TD_LBN 0
+#define FRF_AZ_TLP_TD_WIDTH 1
+
+/* EE_SPI_HCMD_REG: SPI host command register */
+#define FR_AB_EE_SPI_HCMD 0x00000100
+#define FRF_AB_EE_SPI_HCMD_CMD_EN_LBN 31
+#define FRF_AB_EE_SPI_HCMD_CMD_EN_WIDTH 1
+#define FRF_AB_EE_WR_TIMER_ACTIVE_LBN 28
+#define FRF_AB_EE_WR_TIMER_ACTIVE_WIDTH 1
+#define FRF_AB_EE_SPI_HCMD_SF_SEL_LBN 24
+#define FRF_AB_EE_SPI_HCMD_SF_SEL_WIDTH 1
+#define FRF_AB_EE_SPI_HCMD_DABCNT_LBN 16
+#define FRF_AB_EE_SPI_HCMD_DABCNT_WIDTH 5
+#define FRF_AB_EE_SPI_HCMD_READ_LBN 15
+#define FRF_AB_EE_SPI_HCMD_READ_WIDTH 1
+#define FRF_AB_EE_SPI_HCMD_DUBCNT_LBN 12
+#define FRF_AB_EE_SPI_HCMD_DUBCNT_WIDTH 2
+#define FRF_AB_EE_SPI_HCMD_ADBCNT_LBN 8
+#define FRF_AB_EE_SPI_HCMD_ADBCNT_WIDTH 2
+#define FRF_AB_EE_SPI_HCMD_ENC_LBN 0
+#define FRF_AB_EE_SPI_HCMD_ENC_WIDTH 8
+
+/* USR_EV_CFG: User Level Event Configuration register */
+#define FR_CZ_USR_EV_CFG 0x00000100
+#define FRF_CZ_USREV_DIS_LBN 16
+#define FRF_CZ_USREV_DIS_WIDTH 1
+#define FRF_CZ_DFLT_EVQ_LBN 0
+#define FRF_CZ_DFLT_EVQ_WIDTH 10
+
+/* EE_SPI_HADR_REG: SPI host address register */
+#define FR_AB_EE_SPI_HADR 0x00000110
+#define FRF_AB_EE_SPI_HADR_DUBYTE_LBN 24
+#define FRF_AB_EE_SPI_HADR_DUBYTE_WIDTH 8
+#define FRF_AB_EE_SPI_HADR_ADR_LBN 0
+#define FRF_AB_EE_SPI_HADR_ADR_WIDTH 24
+
+/* EE_SPI_HDATA_REG: SPI host data register */
+#define FR_AB_EE_SPI_HDATA 0x00000120
+#define FRF_AB_EE_SPI_HDATA3_LBN 96
+#define FRF_AB_EE_SPI_HDATA3_WIDTH 32
+#define FRF_AB_EE_SPI_HDATA2_LBN 64
+#define FRF_AB_EE_SPI_HDATA2_WIDTH 32
+#define FRF_AB_EE_SPI_HDATA1_LBN 32
+#define FRF_AB_EE_SPI_HDATA1_WIDTH 32
+#define FRF_AB_EE_SPI_HDATA0_LBN 0
+#define FRF_AB_EE_SPI_HDATA0_WIDTH 32
+
+/* EE_BASE_PAGE_REG: Expansion ROM base mirror register */
+#define FR_AB_EE_BASE_PAGE 0x00000130
+#define FRF_AB_EE_EXPROM_MASK_LBN 16
+#define FRF_AB_EE_EXPROM_MASK_WIDTH 13
+#define FRF_AB_EE_EXP_ROM_WINDOW_BASE_LBN 0
+#define FRF_AB_EE_EXP_ROM_WINDOW_BASE_WIDTH 13
+
+/* EE_VPD_CFG0_REG: SPI/VPD configuration register 0 */
+#define FR_AB_EE_VPD_CFG0 0x00000140
+#define FRF_AB_EE_SF_FASTRD_EN_LBN 127
+#define FRF_AB_EE_SF_FASTRD_EN_WIDTH 1
+#define FRF_AB_EE_SF_CLOCK_DIV_LBN 120
+#define FRF_AB_EE_SF_CLOCK_DIV_WIDTH 7
+#define FRF_AB_EE_VPD_WIP_POLL_LBN 119
+#define FRF_AB_EE_VPD_WIP_POLL_WIDTH 1
+#define FRF_AB_EE_EE_CLOCK_DIV_LBN 112
+#define FRF_AB_EE_EE_CLOCK_DIV_WIDTH 7
+#define FRF_AB_EE_EE_WR_TMR_VALUE_LBN 96
+#define FRF_AB_EE_EE_WR_TMR_VALUE_WIDTH 16
+#define FRF_AB_EE_VPDW_LENGTH_LBN 80
+#define FRF_AB_EE_VPDW_LENGTH_WIDTH 15
+#define FRF_AB_EE_VPDW_BASE_LBN 64
+#define FRF_AB_EE_VPDW_BASE_WIDTH 15
+#define FRF_AB_EE_VPD_WR_CMD_EN_LBN 56
+#define FRF_AB_EE_VPD_WR_CMD_EN_WIDTH 8
+#define FRF_AB_EE_VPD_BASE_LBN 32
+#define FRF_AB_EE_VPD_BASE_WIDTH 24
+#define FRF_AB_EE_VPD_LENGTH_LBN 16
+#define FRF_AB_EE_VPD_LENGTH_WIDTH 15
+#define FRF_AB_EE_VPD_AD_SIZE_LBN 8
+#define FRF_AB_EE_VPD_AD_SIZE_WIDTH 5
+#define FRF_AB_EE_VPD_ACCESS_ON_LBN 5
+#define FRF_AB_EE_VPD_ACCESS_ON_WIDTH 1
+#define FRF_AB_EE_VPD_ACCESS_BLOCK_LBN 4
+#define FRF_AB_EE_VPD_ACCESS_BLOCK_WIDTH 1
+#define FRF_AB_EE_VPD_DEV_SF_SEL_LBN 2
+#define FRF_AB_EE_VPD_DEV_SF_SEL_WIDTH 1
+#define FRF_AB_EE_VPD_EN_AD9_MODE_LBN 1
+#define FRF_AB_EE_VPD_EN_AD9_MODE_WIDTH 1
+#define FRF_AB_EE_VPD_EN_LBN 0
+#define FRF_AB_EE_VPD_EN_WIDTH 1
+
+/* EE_VPD_SW_CNTL_REG: VPD access SW control register */
+#define FR_AB_EE_VPD_SW_CNTL 0x00000150
+#define FRF_AB_EE_VPD_CYCLE_PENDING_LBN 31
+#define FRF_AB_EE_VPD_CYCLE_PENDING_WIDTH 1
+#define FRF_AB_EE_VPD_CYC_WRITE_LBN 28
+#define FRF_AB_EE_VPD_CYC_WRITE_WIDTH 1
+#define FRF_AB_EE_VPD_CYC_ADR_LBN 0
+#define FRF_AB_EE_VPD_CYC_ADR_WIDTH 15
+
+/* EE_VPD_SW_DATA_REG: VPD access SW data register */
+#define FR_AB_EE_VPD_SW_DATA 0x00000160
+#define FRF_AB_EE_VPD_CYC_DAT_LBN 0
+#define FRF_AB_EE_VPD_CYC_DAT_WIDTH 32
+
+/* PBMX_DBG_IADDR_REG: Capture Module address register */
+#define FR_CZ_PBMX_DBG_IADDR 0x000001f0
+#define FRF_CZ_PBMX_DBG_IADDR_LBN 0
+#define FRF_CZ_PBMX_DBG_IADDR_WIDTH 32
+
+/* PCIE_CORE_INDIRECT_REG: Indirect Access to PCIE Core registers */
+#define FR_BB_PCIE_CORE_INDIRECT 0x000001f0
+#define FRF_BB_PCIE_CORE_TARGET_DATA_LBN 32
+#define FRF_BB_PCIE_CORE_TARGET_DATA_WIDTH 32
+#define FRF_BB_PCIE_CORE_INDIRECT_ACCESS_DIR_LBN 15
+#define FRF_BB_PCIE_CORE_INDIRECT_ACCESS_DIR_WIDTH 1
+#define FRF_BB_PCIE_CORE_TARGET_REG_ADRS_LBN 0
+#define FRF_BB_PCIE_CORE_TARGET_REG_ADRS_WIDTH 12
+
+/* PBMX_DBG_IDATA_REG: Capture Module data register */
+#define FR_CZ_PBMX_DBG_IDATA 0x000001f8
+#define FRF_CZ_PBMX_DBG_IDATA_LBN 0
+#define FRF_CZ_PBMX_DBG_IDATA_WIDTH 64
+
+/* NIC_STAT_REG: NIC status register */
+#define FR_AB_NIC_STAT 0x00000200
+#define FRF_BB_AER_DIS_LBN 34
+#define FRF_BB_AER_DIS_WIDTH 1
+#define FRF_BB_EE_STRAP_EN_LBN 31
+#define FRF_BB_EE_STRAP_EN_WIDTH 1
+#define FRF_BB_EE_STRAP_LBN 24
+#define FRF_BB_EE_STRAP_WIDTH 4
+#define FRF_BB_REVISION_ID_LBN 17
+#define FRF_BB_REVISION_ID_WIDTH 7
+#define FRF_AB_ONCHIP_SRAM_LBN 16
+#define FRF_AB_ONCHIP_SRAM_WIDTH 1
+#define FRF_AB_SF_PRST_LBN 9
+#define FRF_AB_SF_PRST_WIDTH 1
+#define FRF_AB_EE_PRST_LBN 8
+#define FRF_AB_EE_PRST_WIDTH 1
+#define FRF_AB_ATE_MODE_LBN 3
+#define FRF_AB_ATE_MODE_WIDTH 1
+#define FRF_AB_STRAP_PINS_LBN 0
+#define FRF_AB_STRAP_PINS_WIDTH 3
+
+/* GPIO_CTL_REG: GPIO control register */
+#define FR_AB_GPIO_CTL 0x00000210
+#define FRF_AB_GPIO_OUT3_LBN 112
+#define FRF_AB_GPIO_OUT3_WIDTH 16
+#define FRF_AB_GPIO_IN3_LBN 104
+#define FRF_AB_GPIO_IN3_WIDTH 8
+#define FRF_AB_GPIO_PWRUP_VALUE3_LBN 96
+#define FRF_AB_GPIO_PWRUP_VALUE3_WIDTH 8
+#define FRF_AB_GPIO_OUT2_LBN 80
+#define FRF_AB_GPIO_OUT2_WIDTH 16
+#define FRF_AB_GPIO_IN2_LBN 72
+#define FRF_AB_GPIO_IN2_WIDTH 8
+#define FRF_AB_GPIO_PWRUP_VALUE2_LBN 64
+#define FRF_AB_GPIO_PWRUP_VALUE2_WIDTH 8
+#define FRF_AB_GPIO15_OEN_LBN 63
+#define FRF_AB_GPIO15_OEN_WIDTH 1
+#define FRF_AB_GPIO14_OEN_LBN 62
+#define FRF_AB_GPIO14_OEN_WIDTH 1
+#define FRF_AB_GPIO13_OEN_LBN 61
+#define FRF_AB_GPIO13_OEN_WIDTH 1
+#define FRF_AB_GPIO12_OEN_LBN 60
+#define FRF_AB_GPIO12_OEN_WIDTH 1
+#define FRF_AB_GPIO11_OEN_LBN 59
+#define FRF_AB_GPIO11_OEN_WIDTH 1
+#define FRF_AB_GPIO10_OEN_LBN 58
+#define FRF_AB_GPIO10_OEN_WIDTH 1
+#define FRF_AB_GPIO9_OEN_LBN 57
+#define FRF_AB_GPIO9_OEN_WIDTH 1
+#define FRF_AB_GPIO8_OEN_LBN 56
+#define FRF_AB_GPIO8_OEN_WIDTH 1
+#define FRF_AB_GPIO15_OUT_LBN 55
+#define FRF_AB_GPIO15_OUT_WIDTH 1
+#define FRF_AB_GPIO14_OUT_LBN 54
+#define FRF_AB_GPIO14_OUT_WIDTH 1
+#define FRF_AB_GPIO13_OUT_LBN 53
+#define FRF_AB_GPIO13_OUT_WIDTH 1
+#define FRF_AB_GPIO12_OUT_LBN 52
+#define FRF_AB_GPIO12_OUT_WIDTH 1
+#define FRF_AB_GPIO11_OUT_LBN 51
+#define FRF_AB_GPIO11_OUT_WIDTH 1
+#define FRF_AB_GPIO10_OUT_LBN 50
+#define FRF_AB_GPIO10_OUT_WIDTH 1
+#define FRF_AB_GPIO9_OUT_LBN 49
+#define FRF_AB_GPIO9_OUT_WIDTH 1
+#define FRF_AB_GPIO8_OUT_LBN 48
+#define FRF_AB_GPIO8_OUT_WIDTH 1
+#define FRF_AB_GPIO15_IN_LBN 47
+#define FRF_AB_GPIO15_IN_WIDTH 1
+#define FRF_AB_GPIO14_IN_LBN 46
+#define FRF_AB_GPIO14_IN_WIDTH 1
+#define FRF_AB_GPIO13_IN_LBN 45
+#define FRF_AB_GPIO13_IN_WIDTH 1
+#define FRF_AB_GPIO12_IN_LBN 44
+#define FRF_AB_GPIO12_IN_WIDTH 1
+#define FRF_AB_GPIO11_IN_LBN 43
+#define FRF_AB_GPIO11_IN_WIDTH 1
+#define FRF_AB_GPIO10_IN_LBN 42
+#define FRF_AB_GPIO10_IN_WIDTH 1
+#define FRF_AB_GPIO9_IN_LBN 41
+#define FRF_AB_GPIO9_IN_WIDTH 1
+#define FRF_AB_GPIO8_IN_LBN 40
+#define FRF_AB_GPIO8_IN_WIDTH 1
+#define FRF_AB_GPIO15_PWRUP_VALUE_LBN 39
+#define FRF_AB_GPIO15_PWRUP_VALUE_WIDTH 1
+#define FRF_AB_GPIO14_PWRUP_VALUE_LBN 38
+#define FRF_AB_GPIO14_PWRUP_VALUE_WIDTH 1
+#define FRF_AB_GPIO13_PWRUP_VALUE_LBN 37
+#define FRF_AB_GPIO13_PWRUP_VALUE_WIDTH 1
+#define FRF_AB_GPIO12_PWRUP_VALUE_LBN 36
+#define FRF_AB_GPIO12_PWRUP_VALUE_WIDTH 1
+#define FRF_AB_GPIO11_PWRUP_VALUE_LBN 35
+#define FRF_AB_GPIO11_PWRUP_VALUE_WIDTH 1
+#define FRF_AB_GPIO10_PWRUP_VALUE_LBN 34
+#define FRF_AB_GPIO10_PWRUP_VALUE_WIDTH 1
+#define FRF_AB_GPIO9_PWRUP_VALUE_LBN 33
+#define FRF_AB_GPIO9_PWRUP_VALUE_WIDTH 1
+#define FRF_AB_GPIO8_PWRUP_VALUE_LBN 32
+#define FRF_AB_GPIO8_PWRUP_VALUE_WIDTH 1
+#define FRF_AB_CLK156_OUT_EN_LBN 31
+#define FRF_AB_CLK156_OUT_EN_WIDTH 1
+#define FRF_AB_USE_NIC_CLK_LBN 30
+#define FRF_AB_USE_NIC_CLK_WIDTH 1
+#define FRF_AB_GPIO5_OEN_LBN 29
+#define FRF_AB_GPIO5_OEN_WIDTH 1
+#define FRF_AB_GPIO4_OEN_LBN 28
+#define FRF_AB_GPIO4_OEN_WIDTH 1
+#define FRF_AB_GPIO3_OEN_LBN 27
+#define FRF_AB_GPIO3_OEN_WIDTH 1
+#define FRF_AB_GPIO2_OEN_LBN 26
+#define FRF_AB_GPIO2_OEN_WIDTH 1
+#define FRF_AB_GPIO1_OEN_LBN 25
+#define FRF_AB_GPIO1_OEN_WIDTH 1
+#define FRF_AB_GPIO0_OEN_LBN 24
+#define FRF_AB_GPIO0_OEN_WIDTH 1
+#define FRF_AB_GPIO7_OUT_LBN 23
+#define FRF_AB_GPIO7_OUT_WIDTH 1
+#define FRF_AB_GPIO6_OUT_LBN 22
+#define FRF_AB_GPIO6_OUT_WIDTH 1
+#define FRF_AB_GPIO5_OUT_LBN 21
+#define FRF_AB_GPIO5_OUT_WIDTH 1
+#define FRF_AB_GPIO4_OUT_LBN 20
+#define FRF_AB_GPIO4_OUT_WIDTH 1
+#define FRF_AB_GPIO3_OUT_LBN 19
+#define FRF_AB_GPIO3_OUT_WIDTH 1
+#define FRF_AB_GPIO2_OUT_LBN 18
+#define FRF_AB_GPIO2_OUT_WIDTH 1
+#define FRF_AB_GPIO1_OUT_LBN 17
+#define FRF_AB_GPIO1_OUT_WIDTH 1
+#define FRF_AB_GPIO0_OUT_LBN 16
+#define FRF_AB_GPIO0_OUT_WIDTH 1
+#define FRF_AB_GPIO7_IN_LBN 15
+#define FRF_AB_GPIO7_IN_WIDTH 1
+#define FRF_AB_GPIO6_IN_LBN 14
+#define FRF_AB_GPIO6_IN_WIDTH 1
+#define FRF_AB_GPIO5_IN_LBN 13
+#define FRF_AB_GPIO5_IN_WIDTH 1
+#define FRF_AB_GPIO4_IN_LBN 12
+#define FRF_AB_GPIO4_IN_WIDTH 1
+#define FRF_AB_GPIO3_IN_LBN 11
+#define FRF_AB_GPIO3_IN_WIDTH 1
+#define FRF_AB_GPIO2_IN_LBN 10
+#define FRF_AB_GPIO2_IN_WIDTH 1
+#define FRF_AB_GPIO1_IN_LBN 9
+#define FRF_AB_GPIO1_IN_WIDTH 1
+#define FRF_AB_GPIO0_IN_LBN 8
+#define FRF_AB_GPIO0_IN_WIDTH 1
+#define FRF_AB_GPIO7_PWRUP_VALUE_LBN 7
+#define FRF_AB_GPIO7_PWRUP_VALUE_WIDTH 1
+#define FRF_AB_GPIO6_PWRUP_VALUE_LBN 6
+#define FRF_AB_GPIO6_PWRUP_VALUE_WIDTH 1
+#define FRF_AB_GPIO5_PWRUP_VALUE_LBN 5
+#define FRF_AB_GPIO5_PWRUP_VALUE_WIDTH 1
+#define FRF_AB_GPIO4_PWRUP_VALUE_LBN 4
+#define FRF_AB_GPIO4_PWRUP_VALUE_WIDTH 1
+#define FRF_AB_GPIO3_PWRUP_VALUE_LBN 3
+#define FRF_AB_GPIO3_PWRUP_VALUE_WIDTH 1
+#define FRF_AB_GPIO2_PWRUP_VALUE_LBN 2
+#define FRF_AB_GPIO2_PWRUP_VALUE_WIDTH 1
+#define FRF_AB_GPIO1_PWRUP_VALUE_LBN 1
+#define FRF_AB_GPIO1_PWRUP_VALUE_WIDTH 1
+#define FRF_AB_GPIO0_PWRUP_VALUE_LBN 0
+#define FRF_AB_GPIO0_PWRUP_VALUE_WIDTH 1
+
+/* GLB_CTL_REG: Global control register */
+#define FR_AB_GLB_CTL 0x00000220
+#define FRF_AB_EXT_PHY_RST_CTL_LBN 63
+#define FRF_AB_EXT_PHY_RST_CTL_WIDTH 1
+#define FRF_AB_XAUI_SD_RST_CTL_LBN 62
+#define FRF_AB_XAUI_SD_RST_CTL_WIDTH 1
+#define FRF_AB_PCIE_SD_RST_CTL_LBN 61
+#define FRF_AB_PCIE_SD_RST_CTL_WIDTH 1
+#define FRF_AA_PCIX_RST_CTL_LBN 60
+#define FRF_AA_PCIX_RST_CTL_WIDTH 1
+#define FRF_BB_BIU_RST_CTL_LBN 60
+#define FRF_BB_BIU_RST_CTL_WIDTH 1
+#define FRF_AB_PCIE_STKY_RST_CTL_LBN 59
+#define FRF_AB_PCIE_STKY_RST_CTL_WIDTH 1
+#define FRF_AB_PCIE_NSTKY_RST_CTL_LBN 58
+#define FRF_AB_PCIE_NSTKY_RST_CTL_WIDTH 1
+#define FRF_AB_PCIE_CORE_RST_CTL_LBN 57
+#define FRF_AB_PCIE_CORE_RST_CTL_WIDTH 1
+#define FRF_AB_XGRX_RST_CTL_LBN 56
+#define FRF_AB_XGRX_RST_CTL_WIDTH 1
+#define FRF_AB_XGTX_RST_CTL_LBN 55
+#define FRF_AB_XGTX_RST_CTL_WIDTH 1
+#define FRF_AB_EM_RST_CTL_LBN 54
+#define FRF_AB_EM_RST_CTL_WIDTH 1
+#define FRF_AB_EV_RST_CTL_LBN 53
+#define FRF_AB_EV_RST_CTL_WIDTH 1
+#define FRF_AB_SR_RST_CTL_LBN 52
+#define FRF_AB_SR_RST_CTL_WIDTH 1
+#define FRF_AB_RX_RST_CTL_LBN 51
+#define FRF_AB_RX_RST_CTL_WIDTH 1
+#define FRF_AB_TX_RST_CTL_LBN 50
+#define FRF_AB_TX_RST_CTL_WIDTH 1
+#define FRF_AB_EE_RST_CTL_LBN 49
+#define FRF_AB_EE_RST_CTL_WIDTH 1
+#define FRF_AB_CS_RST_CTL_LBN 48
+#define FRF_AB_CS_RST_CTL_WIDTH 1
+#define FRF_AB_HOT_RST_CTL_LBN 40
+#define FRF_AB_HOT_RST_CTL_WIDTH 2
+#define FRF_AB_RST_EXT_PHY_LBN 31
+#define FRF_AB_RST_EXT_PHY_WIDTH 1
+#define FRF_AB_RST_XAUI_SD_LBN 30
+#define FRF_AB_RST_XAUI_SD_WIDTH 1
+#define FRF_AB_RST_PCIE_SD_LBN 29
+#define FRF_AB_RST_PCIE_SD_WIDTH 1
+#define FRF_AA_RST_PCIX_LBN 28
+#define FRF_AA_RST_PCIX_WIDTH 1
+#define FRF_BB_RST_BIU_LBN 28
+#define FRF_BB_RST_BIU_WIDTH 1
+#define FRF_AB_RST_PCIE_STKY_LBN 27
+#define FRF_AB_RST_PCIE_STKY_WIDTH 1
+#define FRF_AB_RST_PCIE_NSTKY_LBN 26
+#define FRF_AB_RST_PCIE_NSTKY_WIDTH 1
+#define FRF_AB_RST_PCIE_CORE_LBN 25
+#define FRF_AB_RST_PCIE_CORE_WIDTH 1
+#define FRF_AB_RST_XGRX_LBN 24
+#define FRF_AB_RST_XGRX_WIDTH 1
+#define FRF_AB_RST_XGTX_LBN 23
+#define FRF_AB_RST_XGTX_WIDTH 1
+#define FRF_AB_RST_EM_LBN 22
+#define FRF_AB_RST_EM_WIDTH 1
+#define FRF_AB_RST_EV_LBN 21
+#define FRF_AB_RST_EV_WIDTH 1
+#define FRF_AB_RST_SR_LBN 20
+#define FRF_AB_RST_SR_WIDTH 1
+#define FRF_AB_RST_RX_LBN 19
+#define FRF_AB_RST_RX_WIDTH 1
+#define FRF_AB_RST_TX_LBN 18
+#define FRF_AB_RST_TX_WIDTH 1
+#define FRF_AB_RST_SF_LBN 17
+#define FRF_AB_RST_SF_WIDTH 1
+#define FRF_AB_RST_CS_LBN 16
+#define FRF_AB_RST_CS_WIDTH 1
+#define FRF_AB_INT_RST_DUR_LBN 4
+#define FRF_AB_INT_RST_DUR_WIDTH 3
+#define FRF_AB_EXT_PHY_RST_DUR_LBN 1
+#define FRF_AB_EXT_PHY_RST_DUR_WIDTH 3
+#define FFE_AB_EXT_PHY_RST_DUR_10240US 7
+#define FFE_AB_EXT_PHY_RST_DUR_5120US 6
+#define FFE_AB_EXT_PHY_RST_DUR_2560US 5
+#define FFE_AB_EXT_PHY_RST_DUR_1280US 4
+#define FFE_AB_EXT_PHY_RST_DUR_640US 3
+#define FFE_AB_EXT_PHY_RST_DUR_320US 2
+#define FFE_AB_EXT_PHY_RST_DUR_160US 1
+#define FFE_AB_EXT_PHY_RST_DUR_80US 0
+#define FRF_AB_SWRST_LBN 0
+#define FRF_AB_SWRST_WIDTH 1
+
+/* FATAL_INTR_REG_KER: Fatal interrupt register for Kernel */
+#define FR_AZ_FATAL_INTR_KER 0x00000230
+#define FRF_CZ_SRAM_PERR_INT_P_KER_EN_LBN 44
+#define FRF_CZ_SRAM_PERR_INT_P_KER_EN_WIDTH 1
+#define FRF_AB_PCI_BUSERR_INT_KER_EN_LBN 43
+#define FRF_AB_PCI_BUSERR_INT_KER_EN_WIDTH 1
+#define FRF_CZ_MBU_PERR_INT_KER_EN_LBN 43
+#define FRF_CZ_MBU_PERR_INT_KER_EN_WIDTH 1
+#define FRF_AZ_SRAM_OOB_INT_KER_EN_LBN 42
+#define FRF_AZ_SRAM_OOB_INT_KER_EN_WIDTH 1
+#define FRF_AZ_BUFID_OOB_INT_KER_EN_LBN 41
+#define FRF_AZ_BUFID_OOB_INT_KER_EN_WIDTH 1
+#define FRF_AZ_MEM_PERR_INT_KER_EN_LBN 40
+#define FRF_AZ_MEM_PERR_INT_KER_EN_WIDTH 1
+#define FRF_AZ_RBUF_OWN_INT_KER_EN_LBN 39
+#define FRF_AZ_RBUF_OWN_INT_KER_EN_WIDTH 1
+#define FRF_AZ_TBUF_OWN_INT_KER_EN_LBN 38
+#define FRF_AZ_TBUF_OWN_INT_KER_EN_WIDTH 1
+#define FRF_AZ_RDESCQ_OWN_INT_KER_EN_LBN 37
+#define FRF_AZ_RDESCQ_OWN_INT_KER_EN_WIDTH 1
+#define FRF_AZ_TDESCQ_OWN_INT_KER_EN_LBN 36
+#define FRF_AZ_TDESCQ_OWN_INT_KER_EN_WIDTH 1
+#define FRF_AZ_EVQ_OWN_INT_KER_EN_LBN 35
+#define FRF_AZ_EVQ_OWN_INT_KER_EN_WIDTH 1
+#define FRF_AZ_EVF_OFLO_INT_KER_EN_LBN 34
+#define FRF_AZ_EVF_OFLO_INT_KER_EN_WIDTH 1
+#define FRF_AZ_ILL_ADR_INT_KER_EN_LBN 33
+#define FRF_AZ_ILL_ADR_INT_KER_EN_WIDTH 1
+#define FRF_AZ_SRM_PERR_INT_KER_EN_LBN 32
+#define FRF_AZ_SRM_PERR_INT_KER_EN_WIDTH 1
+#define FRF_CZ_SRAM_PERR_INT_P_KER_LBN 12
+#define FRF_CZ_SRAM_PERR_INT_P_KER_WIDTH 1
+#define FRF_AB_PCI_BUSERR_INT_KER_LBN 11
+#define FRF_AB_PCI_BUSERR_INT_KER_WIDTH 1
+#define FRF_CZ_MBU_PERR_INT_KER_LBN 11
+#define FRF_CZ_MBU_PERR_INT_KER_WIDTH 1
+#define FRF_AZ_SRAM_OOB_INT_KER_LBN 10
+#define FRF_AZ_SRAM_OOB_INT_KER_WIDTH 1
+#define FRF_AZ_BUFID_DC_OOB_INT_KER_LBN 9
+#define FRF_AZ_BUFID_DC_OOB_INT_KER_WIDTH 1
+#define FRF_AZ_MEM_PERR_INT_KER_LBN 8
+#define FRF_AZ_MEM_PERR_INT_KER_WIDTH 1
+#define FRF_AZ_RBUF_OWN_INT_KER_LBN 7
+#define FRF_AZ_RBUF_OWN_INT_KER_WIDTH 1
+#define FRF_AZ_TBUF_OWN_INT_KER_LBN 6
+#define FRF_AZ_TBUF_OWN_INT_KER_WIDTH 1
+#define FRF_AZ_RDESCQ_OWN_INT_KER_LBN 5
+#define FRF_AZ_RDESCQ_OWN_INT_KER_WIDTH 1
+#define FRF_AZ_TDESCQ_OWN_INT_KER_LBN 4
+#define FRF_AZ_TDESCQ_OWN_INT_KER_WIDTH 1
+#define FRF_AZ_EVQ_OWN_INT_KER_LBN 3
+#define FRF_AZ_EVQ_OWN_INT_KER_WIDTH 1
+#define FRF_AZ_EVF_OFLO_INT_KER_LBN 2
+#define FRF_AZ_EVF_OFLO_INT_KER_WIDTH 1
+#define FRF_AZ_ILL_ADR_INT_KER_LBN 1
+#define FRF_AZ_ILL_ADR_INT_KER_WIDTH 1
+#define FRF_AZ_SRM_PERR_INT_KER_LBN 0
+#define FRF_AZ_SRM_PERR_INT_KER_WIDTH 1
+
+/* FATAL_INTR_REG_CHAR: Fatal interrupt register for Char */
+#define FR_BZ_FATAL_INTR_CHAR 0x00000240
+#define FRF_CZ_SRAM_PERR_INT_P_CHAR_EN_LBN 44
+#define FRF_CZ_SRAM_PERR_INT_P_CHAR_EN_WIDTH 1
+#define FRF_BB_PCI_BUSERR_INT_CHAR_EN_LBN 43
+#define FRF_BB_PCI_BUSERR_INT_CHAR_EN_WIDTH 1
+#define FRF_CZ_MBU_PERR_INT_CHAR_EN_LBN 43
+#define FRF_CZ_MBU_PERR_INT_CHAR_EN_WIDTH 1
+#define FRF_BZ_SRAM_OOB_INT_CHAR_EN_LBN 42
+#define FRF_BZ_SRAM_OOB_INT_CHAR_EN_WIDTH 1
+#define FRF_BZ_BUFID_OOB_INT_CHAR_EN_LBN 41
+#define FRF_BZ_BUFID_OOB_INT_CHAR_EN_WIDTH 1
+#define FRF_BZ_MEM_PERR_INT_CHAR_EN_LBN 40
+#define FRF_BZ_MEM_PERR_INT_CHAR_EN_WIDTH 1
+#define FRF_BZ_RBUF_OWN_INT_CHAR_EN_LBN 39
+#define FRF_BZ_RBUF_OWN_INT_CHAR_EN_WIDTH 1
+#define FRF_BZ_TBUF_OWN_INT_CHAR_EN_LBN 38
+#define FRF_BZ_TBUF_OWN_INT_CHAR_EN_WIDTH 1
+#define FRF_BZ_RDESCQ_OWN_INT_CHAR_EN_LBN 37
+#define FRF_BZ_RDESCQ_OWN_INT_CHAR_EN_WIDTH 1
+#define FRF_BZ_TDESCQ_OWN_INT_CHAR_EN_LBN 36
+#define FRF_BZ_TDESCQ_OWN_INT_CHAR_EN_WIDTH 1
+#define FRF_BZ_EVQ_OWN_INT_CHAR_EN_LBN 35
+#define FRF_BZ_EVQ_OWN_INT_CHAR_EN_WIDTH 1
+#define FRF_BZ_EVF_OFLO_INT_CHAR_EN_LBN 34
+#define FRF_BZ_EVF_OFLO_INT_CHAR_EN_WIDTH 1
+#define FRF_BZ_ILL_ADR_INT_CHAR_EN_LBN 33
+#define FRF_BZ_ILL_ADR_INT_CHAR_EN_WIDTH 1
+#define FRF_BZ_SRM_PERR_INT_CHAR_EN_LBN 32
+#define FRF_BZ_SRM_PERR_INT_CHAR_EN_WIDTH 1
+#define FRF_CZ_SRAM_PERR_INT_P_CHAR_LBN 12
+#define FRF_CZ_SRAM_PERR_INT_P_CHAR_WIDTH 1
+#define FRF_BB_PCI_BUSERR_INT_CHAR_LBN 11
+#define FRF_BB_PCI_BUSERR_INT_CHAR_WIDTH 1
+#define FRF_CZ_MBU_PERR_INT_CHAR_LBN 11
+#define FRF_CZ_MBU_PERR_INT_CHAR_WIDTH 1
+#define FRF_BZ_SRAM_OOB_INT_CHAR_LBN 10
+#define FRF_BZ_SRAM_OOB_INT_CHAR_WIDTH 1
+#define FRF_BZ_BUFID_DC_OOB_INT_CHAR_LBN 9
+#define FRF_BZ_BUFID_DC_OOB_INT_CHAR_WIDTH 1
+#define FRF_BZ_MEM_PERR_INT_CHAR_LBN 8
+#define FRF_BZ_MEM_PERR_INT_CHAR_WIDTH 1
+#define FRF_BZ_RBUF_OWN_INT_CHAR_LBN 7
+#define FRF_BZ_RBUF_OWN_INT_CHAR_WIDTH 1
+#define FRF_BZ_TBUF_OWN_INT_CHAR_LBN 6
+#define FRF_BZ_TBUF_OWN_INT_CHAR_WIDTH 1
+#define FRF_BZ_RDESCQ_OWN_INT_CHAR_LBN 5
+#define FRF_BZ_RDESCQ_OWN_INT_CHAR_WIDTH 1
+#define FRF_BZ_TDESCQ_OWN_INT_CHAR_LBN 4
+#define FRF_BZ_TDESCQ_OWN_INT_CHAR_WIDTH 1
+#define FRF_BZ_EVQ_OWN_INT_CHAR_LBN 3
+#define FRF_BZ_EVQ_OWN_INT_CHAR_WIDTH 1
+#define FRF_BZ_EVF_OFLO_INT_CHAR_LBN 2
+#define FRF_BZ_EVF_OFLO_INT_CHAR_WIDTH 1
+#define FRF_BZ_ILL_ADR_INT_CHAR_LBN 1
+#define FRF_BZ_ILL_ADR_INT_CHAR_WIDTH 1
+#define FRF_BZ_SRM_PERR_INT_CHAR_LBN 0
+#define FRF_BZ_SRM_PERR_INT_CHAR_WIDTH 1
+
+/* DP_CTRL_REG: Datapath control register */
+#define FR_BZ_DP_CTRL 0x00000250
+#define FRF_BZ_FLS_EVQ_ID_LBN 0
+#define FRF_BZ_FLS_EVQ_ID_WIDTH 12
+
+/* MEM_STAT_REG: Memory status register */
+#define FR_AZ_MEM_STAT 0x00000260
+#define FRF_AB_MEM_PERR_VEC_LBN 53
+#define FRF_AB_MEM_PERR_VEC_WIDTH 38
+#define FRF_AB_MBIST_CORR_LBN 38
+#define FRF_AB_MBIST_CORR_WIDTH 15
+#define FRF_AB_MBIST_ERR_LBN 0
+#define FRF_AB_MBIST_ERR_WIDTH 40
+#define FRF_CZ_MEM_PERR_VEC_LBN 0
+#define FRF_CZ_MEM_PERR_VEC_WIDTH 35
+
+/* CS_DEBUG_REG: Debug register */
+#define FR_AZ_CS_DEBUG 0x00000270
+#define FRF_AB_GLB_DEBUG2_SEL_LBN 50
+#define FRF_AB_GLB_DEBUG2_SEL_WIDTH 3
+#define FRF_AB_DEBUG_BLK_SEL2_LBN 47
+#define FRF_AB_DEBUG_BLK_SEL2_WIDTH 3
+#define FRF_AB_DEBUG_BLK_SEL1_LBN 44
+#define FRF_AB_DEBUG_BLK_SEL1_WIDTH 3
+#define FRF_AB_DEBUG_BLK_SEL0_LBN 41
+#define FRF_AB_DEBUG_BLK_SEL0_WIDTH 3
+#define FRF_CZ_CS_PORT_NUM_LBN 40
+#define FRF_CZ_CS_PORT_NUM_WIDTH 2
+#define FRF_AB_MISC_DEBUG_ADDR_LBN 36
+#define FRF_AB_MISC_DEBUG_ADDR_WIDTH 5
+#define FRF_AB_SERDES_DEBUG_ADDR_LBN 31
+#define FRF_AB_SERDES_DEBUG_ADDR_WIDTH 5
+#define FRF_CZ_CS_PORT_FPE_LBN 1
+#define FRF_CZ_CS_PORT_FPE_WIDTH 35
+#define FRF_AB_EM_DEBUG_ADDR_LBN 26
+#define FRF_AB_EM_DEBUG_ADDR_WIDTH 5
+#define FRF_AB_SR_DEBUG_ADDR_LBN 21
+#define FRF_AB_SR_DEBUG_ADDR_WIDTH 5
+#define FRF_AB_EV_DEBUG_ADDR_LBN 16
+#define FRF_AB_EV_DEBUG_ADDR_WIDTH 5
+#define FRF_AB_RX_DEBUG_ADDR_LBN 11
+#define FRF_AB_RX_DEBUG_ADDR_WIDTH 5
+#define FRF_AB_TX_DEBUG_ADDR_LBN 6
+#define FRF_AB_TX_DEBUG_ADDR_WIDTH 5
+#define FRF_AB_CS_BIU_DEBUG_ADDR_LBN 1
+#define FRF_AB_CS_BIU_DEBUG_ADDR_WIDTH 5
+#define FRF_AZ_CS_DEBUG_EN_LBN 0
+#define FRF_AZ_CS_DEBUG_EN_WIDTH 1
+
+/* DRIVER_REG: Driver scratch register [0-7] */
+#define FR_AZ_DRIVER 0x00000280
+#define FR_AZ_DRIVER_STEP 16
+#define FR_AZ_DRIVER_ROWS 8
+#define FRF_AZ_DRIVER_DW0_LBN 0
+#define FRF_AZ_DRIVER_DW0_WIDTH 32
+
+/* ALTERA_BUILD_REG: Altera build register */
+#define FR_AZ_ALTERA_BUILD 0x00000300
+#define FRF_AZ_ALTERA_BUILD_VER_LBN 0
+#define FRF_AZ_ALTERA_BUILD_VER_WIDTH 32
+
+/* CSR_SPARE_REG: Spare register */
+#define FR_AZ_CSR_SPARE 0x00000310
+#define FRF_AB_MEM_PERR_EN_LBN 64
+#define FRF_AB_MEM_PERR_EN_WIDTH 38
+#define FRF_CZ_MEM_PERR_EN_LBN 64
+#define FRF_CZ_MEM_PERR_EN_WIDTH 35
+#define FRF_AB_MEM_PERR_EN_TX_DATA_LBN 72
+#define FRF_AB_MEM_PERR_EN_TX_DATA_WIDTH 2
+#define FRF_AZ_CSR_SPARE_BITS_LBN 0
+#define FRF_AZ_CSR_SPARE_BITS_WIDTH 32
+
+/* PCIE_SD_CTL0123_REG: PCIE SerDes control register 0 to 3 */
+#define FR_AB_PCIE_SD_CTL0123 0x00000320
+#define FRF_AB_PCIE_TESTSIG_H_LBN 96
+#define FRF_AB_PCIE_TESTSIG_H_WIDTH 19
+#define FRF_AB_PCIE_TESTSIG_L_LBN 64
+#define FRF_AB_PCIE_TESTSIG_L_WIDTH 19
+#define FRF_AB_PCIE_OFFSET_LBN 56
+#define FRF_AB_PCIE_OFFSET_WIDTH 8
+#define FRF_AB_PCIE_OFFSETEN_H_LBN 55
+#define FRF_AB_PCIE_OFFSETEN_H_WIDTH 1
+#define FRF_AB_PCIE_OFFSETEN_L_LBN 54
+#define FRF_AB_PCIE_OFFSETEN_L_WIDTH 1
+#define FRF_AB_PCIE_HIVMODE_H_LBN 53
+#define FRF_AB_PCIE_HIVMODE_H_WIDTH 1
+#define FRF_AB_PCIE_HIVMODE_L_LBN 52
+#define FRF_AB_PCIE_HIVMODE_L_WIDTH 1
+#define FRF_AB_PCIE_PARRESET_H_LBN 51
+#define FRF_AB_PCIE_PARRESET_H_WIDTH 1
+#define FRF_AB_PCIE_PARRESET_L_LBN 50
+#define FRF_AB_PCIE_PARRESET_L_WIDTH 1
+#define FRF_AB_PCIE_LPBKWDRV_H_LBN 49
+#define FRF_AB_PCIE_LPBKWDRV_H_WIDTH 1
+#define FRF_AB_PCIE_LPBKWDRV_L_LBN 48
+#define FRF_AB_PCIE_LPBKWDRV_L_WIDTH 1
+#define FRF_AB_PCIE_LPBK_LBN 40
+#define FRF_AB_PCIE_LPBK_WIDTH 8
+#define FRF_AB_PCIE_PARLPBK_LBN 32
+#define FRF_AB_PCIE_PARLPBK_WIDTH 8
+#define FRF_AB_PCIE_RXTERMADJ_H_LBN 30
+#define FRF_AB_PCIE_RXTERMADJ_H_WIDTH 2
+#define FRF_AB_PCIE_RXTERMADJ_L_LBN 28
+#define FRF_AB_PCIE_RXTERMADJ_L_WIDTH 2
+#define FFE_AB_PCIE_RXTERMADJ_MIN15PCNT 3
+#define FFE_AB_PCIE_RXTERMADJ_PL10PCNT 2
+#define FFE_AB_PCIE_RXTERMADJ_MIN17PCNT 1
+#define FFE_AB_PCIE_RXTERMADJ_NOMNL 0
+#define FRF_AB_PCIE_TXTERMADJ_H_LBN 26
+#define FRF_AB_PCIE_TXTERMADJ_H_WIDTH 2
+#define FRF_AB_PCIE_TXTERMADJ_L_LBN 24
+#define FRF_AB_PCIE_TXTERMADJ_L_WIDTH 2
+#define FFE_AB_PCIE_TXTERMADJ_MIN15PCNT 3
+#define FFE_AB_PCIE_TXTERMADJ_PL10PCNT 2
+#define FFE_AB_PCIE_TXTERMADJ_MIN17PCNT 1
+#define FFE_AB_PCIE_TXTERMADJ_NOMNL 0
+#define FRF_AB_PCIE_RXEQCTL_H_LBN 18
+#define FRF_AB_PCIE_RXEQCTL_H_WIDTH 2
+#define FRF_AB_PCIE_RXEQCTL_L_LBN 16
+#define FRF_AB_PCIE_RXEQCTL_L_WIDTH 2
+#define FFE_AB_PCIE_RXEQCTL_OFF_ALT 3
+#define FFE_AB_PCIE_RXEQCTL_OFF 2
+#define FFE_AB_PCIE_RXEQCTL_MIN 1
+#define FFE_AB_PCIE_RXEQCTL_MAX 0
+#define FRF_AB_PCIE_HIDRV_LBN 8
+#define FRF_AB_PCIE_HIDRV_WIDTH 8
+#define FRF_AB_PCIE_LODRV_LBN 0
+#define FRF_AB_PCIE_LODRV_WIDTH 8
+
+/* PCIE_SD_CTL45_REG: PCIE SerDes control register 4 and 5 */
+#define FR_AB_PCIE_SD_CTL45 0x00000330
+#define FRF_AB_PCIE_DTX7_LBN 60
+#define FRF_AB_PCIE_DTX7_WIDTH 4
+#define FRF_AB_PCIE_DTX6_LBN 56
+#define FRF_AB_PCIE_DTX6_WIDTH 4
+#define FRF_AB_PCIE_DTX5_LBN 52
+#define FRF_AB_PCIE_DTX5_WIDTH 4
+#define FRF_AB_PCIE_DTX4_LBN 48
+#define FRF_AB_PCIE_DTX4_WIDTH 4
+#define FRF_AB_PCIE_DTX3_LBN 44
+#define FRF_AB_PCIE_DTX3_WIDTH 4
+#define FRF_AB_PCIE_DTX2_LBN 40
+#define FRF_AB_PCIE_DTX2_WIDTH 4
+#define FRF_AB_PCIE_DTX1_LBN 36
+#define FRF_AB_PCIE_DTX1_WIDTH 4
+#define FRF_AB_PCIE_DTX0_LBN 32
+#define FRF_AB_PCIE_DTX0_WIDTH 4
+#define FRF_AB_PCIE_DEQ7_LBN 28
+#define FRF_AB_PCIE_DEQ7_WIDTH 4
+#define FRF_AB_PCIE_DEQ6_LBN 24
+#define FRF_AB_PCIE_DEQ6_WIDTH 4
+#define FRF_AB_PCIE_DEQ5_LBN 20
+#define FRF_AB_PCIE_DEQ5_WIDTH 4
+#define FRF_AB_PCIE_DEQ4_LBN 16
+#define FRF_AB_PCIE_DEQ4_WIDTH 4
+#define FRF_AB_PCIE_DEQ3_LBN 12
+#define FRF_AB_PCIE_DEQ3_WIDTH 4
+#define FRF_AB_PCIE_DEQ2_LBN 8
+#define FRF_AB_PCIE_DEQ2_WIDTH 4
+#define FRF_AB_PCIE_DEQ1_LBN 4
+#define FRF_AB_PCIE_DEQ1_WIDTH 4
+#define FRF_AB_PCIE_DEQ0_LBN 0
+#define FRF_AB_PCIE_DEQ0_WIDTH 4
+
+/* PCIE_PCS_CTL_STAT_REG: PCIE PCS control and status register */
+#define FR_AB_PCIE_PCS_CTL_STAT 0x00000340
+#define FRF_AB_PCIE_PRBSERRCOUNT0_H_LBN 52
+#define FRF_AB_PCIE_PRBSERRCOUNT0_H_WIDTH 4
+#define FRF_AB_PCIE_PRBSERRCOUNT0_L_LBN 48
+#define FRF_AB_PCIE_PRBSERRCOUNT0_L_WIDTH 4
+#define FRF_AB_PCIE_PRBSERR_LBN 40
+#define FRF_AB_PCIE_PRBSERR_WIDTH 8
+#define FRF_AB_PCIE_PRBSERRH0_LBN 32
+#define FRF_AB_PCIE_PRBSERRH0_WIDTH 8
+#define FRF_AB_PCIE_FASTINIT_H_LBN 15
+#define FRF_AB_PCIE_FASTINIT_H_WIDTH 1
+#define FRF_AB_PCIE_FASTINIT_L_LBN 14
+#define FRF_AB_PCIE_FASTINIT_L_WIDTH 1
+#define FRF_AB_PCIE_CTCDISABLE_H_LBN 13
+#define FRF_AB_PCIE_CTCDISABLE_H_WIDTH 1
+#define FRF_AB_PCIE_CTCDISABLE_L_LBN 12
+#define FRF_AB_PCIE_CTCDISABLE_L_WIDTH 1
+#define FRF_AB_PCIE_PRBSSYNC_H_LBN 11
+#define FRF_AB_PCIE_PRBSSYNC_H_WIDTH 1
+#define FRF_AB_PCIE_PRBSSYNC_L_LBN 10
+#define FRF_AB_PCIE_PRBSSYNC_L_WIDTH 1
+#define FRF_AB_PCIE_PRBSERRACK_H_LBN 9
+#define FRF_AB_PCIE_PRBSERRACK_H_WIDTH 1
+#define FRF_AB_PCIE_PRBSERRACK_L_LBN 8
+#define FRF_AB_PCIE_PRBSERRACK_L_WIDTH 1
+#define FRF_AB_PCIE_PRBSSEL_LBN 0
+#define FRF_AB_PCIE_PRBSSEL_WIDTH 8
+
+/* DEBUG_DATA_OUT_REG: Live Debug and Debug 2 out ports */
+#define FR_BB_DEBUG_DATA_OUT 0x00000350
+#define FRF_BB_DEBUG2_PORT_LBN 25
+#define FRF_BB_DEBUG2_PORT_WIDTH 15
+#define FRF_BB_DEBUG1_PORT_LBN 0
+#define FRF_BB_DEBUG1_PORT_WIDTH 25
+
+/* EVQ_RPTR_REGP0: Event queue read pointer register */
+#define FR_BZ_EVQ_RPTR_P0 0x00000400
+#define FR_BZ_EVQ_RPTR_P0_STEP 8192
+#define FR_BZ_EVQ_RPTR_P0_ROWS 1024
+/* EVQ_RPTR_REG_KER: Event queue read pointer register */
+#define FR_AA_EVQ_RPTR_KER 0x00011b00
+#define FR_AA_EVQ_RPTR_KER_STEP 4
+#define FR_AA_EVQ_RPTR_KER_ROWS 4
+/* EVQ_RPTR_REG: Event queue read pointer register */
+#define FR_BZ_EVQ_RPTR 0x00fa0000
+#define FR_BZ_EVQ_RPTR_STEP 16
+#define FR_BB_EVQ_RPTR_ROWS 4096
+#define FR_CZ_EVQ_RPTR_ROWS 1024
+/* EVQ_RPTR_REGP123: Event queue read pointer register */
+#define FR_BB_EVQ_RPTR_P123 0x01000400
+#define FR_BB_EVQ_RPTR_P123_STEP 8192
+#define FR_BB_EVQ_RPTR_P123_ROWS 3072
+#define FRF_AZ_EVQ_RPTR_VLD_LBN 15
+#define FRF_AZ_EVQ_RPTR_VLD_WIDTH 1
+#define FRF_AZ_EVQ_RPTR_LBN 0
+#define FRF_AZ_EVQ_RPTR_WIDTH 15
+
+/* TIMER_COMMAND_REGP0: Timer Command Registers */
+#define FR_BZ_TIMER_COMMAND_P0 0x00000420
+#define FR_BZ_TIMER_COMMAND_P0_STEP 8192
+#define FR_BZ_TIMER_COMMAND_P0_ROWS 1024
+/* TIMER_COMMAND_REG_KER: Timer Command Registers */
+#define FR_AA_TIMER_COMMAND_KER 0x00000420
+#define FR_AA_TIMER_COMMAND_KER_STEP 8192
+#define FR_AA_TIMER_COMMAND_KER_ROWS 4
+/* TIMER_COMMAND_REGP123: Timer Command Registers */
+#define FR_BB_TIMER_COMMAND_P123 0x01000420
+#define FR_BB_TIMER_COMMAND_P123_STEP 8192
+#define FR_BB_TIMER_COMMAND_P123_ROWS 3072
+#define FRF_CZ_TC_TIMER_MODE_LBN 14
+#define FRF_CZ_TC_TIMER_MODE_WIDTH 2
+#define FRF_AB_TC_TIMER_MODE_LBN 12
+#define FRF_AB_TC_TIMER_MODE_WIDTH 2
+#define FRF_CZ_TC_TIMER_VAL_LBN 0
+#define FRF_CZ_TC_TIMER_VAL_WIDTH 14
+#define FRF_AB_TC_TIMER_VAL_LBN 0
+#define FRF_AB_TC_TIMER_VAL_WIDTH 12
+
+/* DRV_EV_REG: Driver generated event register */
+#define FR_AZ_DRV_EV 0x00000440
+#define FRF_AZ_DRV_EV_QID_LBN 64
+#define FRF_AZ_DRV_EV_QID_WIDTH 12
+#define FRF_AZ_DRV_EV_DATA_LBN 0
+#define FRF_AZ_DRV_EV_DATA_WIDTH 64
+
+/* EVQ_CTL_REG: Event queue control register */
+#define FR_AZ_EVQ_CTL 0x00000450
+#define FRF_CZ_RX_EVQ_WAKEUP_MASK_LBN 15
+#define FRF_CZ_RX_EVQ_WAKEUP_MASK_WIDTH 10
+#define FRF_BB_RX_EVQ_WAKEUP_MASK_LBN 15
+#define FRF_BB_RX_EVQ_WAKEUP_MASK_WIDTH 6
+#define FRF_AZ_EVQ_OWNERR_CTL_LBN 14
+#define FRF_AZ_EVQ_OWNERR_CTL_WIDTH 1
+#define FRF_AZ_EVQ_FIFO_AF_TH_LBN 7
+#define FRF_AZ_EVQ_FIFO_AF_TH_WIDTH 7
+#define FRF_AZ_EVQ_FIFO_NOTAF_TH_LBN 0
+#define FRF_AZ_EVQ_FIFO_NOTAF_TH_WIDTH 7
+
+/* EVQ_CNT1_REG: Event counter 1 register */
+#define FR_AZ_EVQ_CNT1 0x00000460
+#define FRF_AZ_EVQ_CNT_PRE_FIFO_LBN 120
+#define FRF_AZ_EVQ_CNT_PRE_FIFO_WIDTH 7
+#define FRF_AZ_EVQ_CNT_TOBIU_LBN 100
+#define FRF_AZ_EVQ_CNT_TOBIU_WIDTH 20
+#define FRF_AZ_EVQ_TX_REQ_CNT_LBN 80
+#define FRF_AZ_EVQ_TX_REQ_CNT_WIDTH 20
+#define FRF_AZ_EVQ_RX_REQ_CNT_LBN 60
+#define FRF_AZ_EVQ_RX_REQ_CNT_WIDTH 20
+#define FRF_AZ_EVQ_EM_REQ_CNT_LBN 40
+#define FRF_AZ_EVQ_EM_REQ_CNT_WIDTH 20
+#define FRF_AZ_EVQ_CSR_REQ_CNT_LBN 20
+#define FRF_AZ_EVQ_CSR_REQ_CNT_WIDTH 20
+#define FRF_AZ_EVQ_ERR_REQ_CNT_LBN 0
+#define FRF_AZ_EVQ_ERR_REQ_CNT_WIDTH 20
+
+/* EVQ_CNT2_REG: Event counter 2 register */
+#define FR_AZ_EVQ_CNT2 0x00000470
+#define FRF_AZ_EVQ_UPD_REQ_CNT_LBN 104
+#define FRF_AZ_EVQ_UPD_REQ_CNT_WIDTH 20
+#define FRF_AZ_EVQ_CLR_REQ_CNT_LBN 84
+#define FRF_AZ_EVQ_CLR_REQ_CNT_WIDTH 20
+#define FRF_AZ_EVQ_RDY_CNT_LBN 80
+#define FRF_AZ_EVQ_RDY_CNT_WIDTH 4
+#define FRF_AZ_EVQ_WU_REQ_CNT_LBN 60
+#define FRF_AZ_EVQ_WU_REQ_CNT_WIDTH 20
+#define FRF_AZ_EVQ_WET_REQ_CNT_LBN 40
+#define FRF_AZ_EVQ_WET_REQ_CNT_WIDTH 20
+#define FRF_AZ_EVQ_INIT_REQ_CNT_LBN 20
+#define FRF_AZ_EVQ_INIT_REQ_CNT_WIDTH 20
+#define FRF_AZ_EVQ_TM_REQ_CNT_LBN 0
+#define FRF_AZ_EVQ_TM_REQ_CNT_WIDTH 20
+
+/* USR_EV_REG: Event mailbox register */
+#define FR_CZ_USR_EV 0x00000540
+#define FR_CZ_USR_EV_STEP 8192
+#define FR_CZ_USR_EV_ROWS 1024
+#define FRF_CZ_USR_EV_DATA_LBN 0
+#define FRF_CZ_USR_EV_DATA_WIDTH 32
+
+/* BUF_TBL_CFG_REG: Buffer table configuration register */
+#define FR_AZ_BUF_TBL_CFG 0x00000600
+#define FRF_AZ_BUF_TBL_MODE_LBN 3
+#define FRF_AZ_BUF_TBL_MODE_WIDTH 1
+
+/* SRM_RX_DC_CFG_REG: SRAM receive descriptor cache configuration register */
+#define FR_AZ_SRM_RX_DC_CFG 0x00000610
+#define FRF_AZ_SRM_CLK_TMP_EN_LBN 21
+#define FRF_AZ_SRM_CLK_TMP_EN_WIDTH 1
+#define FRF_AZ_SRM_RX_DC_BASE_ADR_LBN 0
+#define FRF_AZ_SRM_RX_DC_BASE_ADR_WIDTH 21
+
+/* SRM_TX_DC_CFG_REG: SRAM transmit descriptor cache configuration register */
+#define FR_AZ_SRM_TX_DC_CFG 0x00000620
+#define FRF_AZ_SRM_TX_DC_BASE_ADR_LBN 0
+#define FRF_AZ_SRM_TX_DC_BASE_ADR_WIDTH 21
+
+/* SRM_CFG_REG: SRAM configuration register */
+#define FR_AZ_SRM_CFG 0x00000630
+#define FRF_AZ_SRM_OOB_ADR_INTEN_LBN 5
+#define FRF_AZ_SRM_OOB_ADR_INTEN_WIDTH 1
+#define FRF_AZ_SRM_OOB_BUF_INTEN_LBN 4
+#define FRF_AZ_SRM_OOB_BUF_INTEN_WIDTH 1
+#define FRF_AZ_SRM_INIT_EN_LBN 3
+#define FRF_AZ_SRM_INIT_EN_WIDTH 1
+#define FRF_AZ_SRM_NUM_BANK_LBN 2
+#define FRF_AZ_SRM_NUM_BANK_WIDTH 1
+#define FRF_AZ_SRM_BANK_SIZE_LBN 0
+#define FRF_AZ_SRM_BANK_SIZE_WIDTH 2
+
+/* BUF_TBL_UPD_REG: Buffer table update register */
+#define FR_AZ_BUF_TBL_UPD 0x00000650
+#define FRF_AZ_BUF_UPD_CMD_LBN 63
+#define FRF_AZ_BUF_UPD_CMD_WIDTH 1
+#define FRF_AZ_BUF_CLR_CMD_LBN 62
+#define FRF_AZ_BUF_CLR_CMD_WIDTH 1
+#define FRF_AZ_BUF_CLR_END_ID_LBN 32
+#define FRF_AZ_BUF_CLR_END_ID_WIDTH 20
+#define FRF_AZ_BUF_CLR_START_ID_LBN 0
+#define FRF_AZ_BUF_CLR_START_ID_WIDTH 20
+
+/* SRM_UPD_EVQ_REG: Buffer table update register */
+#define FR_AZ_SRM_UPD_EVQ 0x00000660
+#define FRF_AZ_SRM_UPD_EVQ_ID_LBN 0
+#define FRF_AZ_SRM_UPD_EVQ_ID_WIDTH 12
+
+/* SRAM_PARITY_REG: SRAM parity register. */
+#define FR_AZ_SRAM_PARITY 0x00000670
+#define FRF_CZ_BYPASS_ECC_LBN 3
+#define FRF_CZ_BYPASS_ECC_WIDTH 1
+#define FRF_CZ_SEC_INT_LBN 2
+#define FRF_CZ_SEC_INT_WIDTH 1
+#define FRF_CZ_FORCE_SRAM_DOUBLE_ERR_LBN 1
+#define FRF_CZ_FORCE_SRAM_DOUBLE_ERR_WIDTH 1
+#define FRF_AB_FORCE_SRAM_PERR_LBN 0
+#define FRF_AB_FORCE_SRAM_PERR_WIDTH 1
+#define FRF_CZ_FORCE_SRAM_SINGLE_ERR_LBN 0
+#define FRF_CZ_FORCE_SRAM_SINGLE_ERR_WIDTH 1
+
+/* RX_CFG_REG: Receive configuration register */
+#define FR_AZ_RX_CFG 0x00000800
+#define FRF_CZ_RX_MIN_KBUF_SIZE_LBN 72
+#define FRF_CZ_RX_MIN_KBUF_SIZE_WIDTH 14
+#define FRF_CZ_RX_HDR_SPLIT_EN_LBN 71
+#define FRF_CZ_RX_HDR_SPLIT_EN_WIDTH 1
+#define FRF_CZ_RX_HDR_SPLIT_PLD_BUF_SIZE_LBN 62
+#define FRF_CZ_RX_HDR_SPLIT_PLD_BUF_SIZE_WIDTH 9
+#define FRF_CZ_RX_HDR_SPLIT_HDR_BUF_SIZE_LBN 53
+#define FRF_CZ_RX_HDR_SPLIT_HDR_BUF_SIZE_WIDTH 9
+#define FRF_CZ_RX_PRE_RFF_IPG_LBN 49
+#define FRF_CZ_RX_PRE_RFF_IPG_WIDTH 4
+#define FRF_BZ_RX_TCP_SUP_LBN 48
+#define FRF_BZ_RX_TCP_SUP_WIDTH 1
+#define FRF_BZ_RX_INGR_EN_LBN 47
+#define FRF_BZ_RX_INGR_EN_WIDTH 1
+#define FRF_BZ_RX_IP_HASH_LBN 46
+#define FRF_BZ_RX_IP_HASH_WIDTH 1
+#define FRF_BZ_RX_HASH_ALG_LBN 45
+#define FRF_BZ_RX_HASH_ALG_WIDTH 1
+#define FRF_BZ_RX_HASH_INSRT_HDR_LBN 44
+#define FRF_BZ_RX_HASH_INSRT_HDR_WIDTH 1
+#define FRF_BZ_RX_DESC_PUSH_EN_LBN 43
+#define FRF_BZ_RX_DESC_PUSH_EN_WIDTH 1
+#define FRF_BZ_RX_RDW_PATCH_EN_LBN 42
+#define FRF_BZ_RX_RDW_PATCH_EN_WIDTH 1
+#define FRF_BB_RX_PCI_BURST_SIZE_LBN 39
+#define FRF_BB_RX_PCI_BURST_SIZE_WIDTH 3
+#define FRF_BZ_RX_OWNERR_CTL_LBN 38
+#define FRF_BZ_RX_OWNERR_CTL_WIDTH 1
+#define FRF_BZ_RX_XON_TX_TH_LBN 33
+#define FRF_BZ_RX_XON_TX_TH_WIDTH 5
+#define FRF_AA_RX_DESC_PUSH_EN_LBN 35
+#define FRF_AA_RX_DESC_PUSH_EN_WIDTH 1
+#define FRF_AA_RX_RDW_PATCH_EN_LBN 34
+#define FRF_AA_RX_RDW_PATCH_EN_WIDTH 1
+#define FRF_AA_RX_PCI_BURST_SIZE_LBN 31
+#define FRF_AA_RX_PCI_BURST_SIZE_WIDTH 3
+#define FRF_BZ_RX_XOFF_TX_TH_LBN 28
+#define FRF_BZ_RX_XOFF_TX_TH_WIDTH 5
+#define FRF_AA_RX_OWNERR_CTL_LBN 30
+#define FRF_AA_RX_OWNERR_CTL_WIDTH 1
+#define FRF_AA_RX_XON_TX_TH_LBN 25
+#define FRF_AA_RX_XON_TX_TH_WIDTH 5
+#define FRF_BZ_RX_USR_BUF_SIZE_LBN 19
+#define FRF_BZ_RX_USR_BUF_SIZE_WIDTH 9
+#define FRF_AA_RX_XOFF_TX_TH_LBN 20
+#define FRF_AA_RX_XOFF_TX_TH_WIDTH 5
+#define FRF_AA_RX_USR_BUF_SIZE_LBN 11
+#define FRF_AA_RX_USR_BUF_SIZE_WIDTH 9
+#define FRF_BZ_RX_XON_MAC_TH_LBN 10
+#define FRF_BZ_RX_XON_MAC_TH_WIDTH 9
+#define FRF_AA_RX_XON_MAC_TH_LBN 6
+#define FRF_AA_RX_XON_MAC_TH_WIDTH 5
+#define FRF_BZ_RX_XOFF_MAC_TH_LBN 1
+#define FRF_BZ_RX_XOFF_MAC_TH_WIDTH 9
+#define FRF_AA_RX_XOFF_MAC_TH_LBN 1
+#define FRF_AA_RX_XOFF_MAC_TH_WIDTH 5
+#define FRF_AZ_RX_XOFF_MAC_EN_LBN 0
+#define FRF_AZ_RX_XOFF_MAC_EN_WIDTH 1
+
+/* RX_FILTER_CTL_REG: Receive filter control registers */
+#define FR_BZ_RX_FILTER_CTL 0x00000810
+#define FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT_LBN 94
+#define FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT_WIDTH 8
+#define FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT_LBN 86
+#define FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT_WIDTH 8
+#define FRF_CZ_RX_FILTER_ALL_VLAN_ETHERTYPES_LBN 85
+#define FRF_CZ_RX_FILTER_ALL_VLAN_ETHERTYPES_WIDTH 1
+#define FRF_CZ_RX_VLAN_MATCH_ETHERTYPE_LBN 69
+#define FRF_CZ_RX_VLAN_MATCH_ETHERTYPE_WIDTH 16
+#define FRF_CZ_MULTICAST_NOMATCH_Q_ID_LBN 57
+#define FRF_CZ_MULTICAST_NOMATCH_Q_ID_WIDTH 12
+#define FRF_CZ_MULTICAST_NOMATCH_RSS_ENABLED_LBN 56
+#define FRF_CZ_MULTICAST_NOMATCH_RSS_ENABLED_WIDTH 1
+#define FRF_CZ_MULTICAST_NOMATCH_IP_OVERRIDE_LBN 55
+#define FRF_CZ_MULTICAST_NOMATCH_IP_OVERRIDE_WIDTH 1
+#define FRF_CZ_UNICAST_NOMATCH_Q_ID_LBN 43
+#define FRF_CZ_UNICAST_NOMATCH_Q_ID_WIDTH 12
+#define FRF_CZ_UNICAST_NOMATCH_RSS_ENABLED_LBN 42
+#define FRF_CZ_UNICAST_NOMATCH_RSS_ENABLED_WIDTH 1
+#define FRF_CZ_UNICAST_NOMATCH_IP_OVERRIDE_LBN 41
+#define FRF_CZ_UNICAST_NOMATCH_IP_OVERRIDE_WIDTH 1
+#define FRF_BZ_SCATTER_ENBL_NO_MATCH_Q_LBN 40
+#define FRF_BZ_SCATTER_ENBL_NO_MATCH_Q_WIDTH 1
+#define FRF_BZ_UDP_FULL_SRCH_LIMIT_LBN 32
+#define FRF_BZ_UDP_FULL_SRCH_LIMIT_WIDTH 8
+#define FRF_BZ_NUM_KER_LBN 24
+#define FRF_BZ_NUM_KER_WIDTH 2
+#define FRF_BZ_UDP_WILD_SRCH_LIMIT_LBN 16
+#define FRF_BZ_UDP_WILD_SRCH_LIMIT_WIDTH 8
+#define FRF_BZ_TCP_WILD_SRCH_LIMIT_LBN 8
+#define FRF_BZ_TCP_WILD_SRCH_LIMIT_WIDTH 8
+#define FRF_BZ_TCP_FULL_SRCH_LIMIT_LBN 0
+#define FRF_BZ_TCP_FULL_SRCH_LIMIT_WIDTH 8
+
+/* RX_FLUSH_DESCQ_REG: Receive flush descriptor queue register */
+#define FR_AZ_RX_FLUSH_DESCQ 0x00000820
+#define FRF_AZ_RX_FLUSH_DESCQ_CMD_LBN 24
+#define FRF_AZ_RX_FLUSH_DESCQ_CMD_WIDTH 1
+#define FRF_AZ_RX_FLUSH_DESCQ_LBN 0
+#define FRF_AZ_RX_FLUSH_DESCQ_WIDTH 12
+
+/* RX_DESC_UPD_REGP0: Receive descriptor update register. */
+#define FR_BZ_RX_DESC_UPD_P0 0x00000830
+#define FR_BZ_RX_DESC_UPD_P0_STEP 8192
+#define FR_BZ_RX_DESC_UPD_P0_ROWS 1024
+/* RX_DESC_UPD_REG_KER: Receive descriptor update register. */
+#define FR_AA_RX_DESC_UPD_KER 0x00000830
+#define FR_AA_RX_DESC_UPD_KER_STEP 8192
+#define FR_AA_RX_DESC_UPD_KER_ROWS 4
+/* RX_DESC_UPD_REGP123: Receive descriptor update register. */
+#define FR_BB_RX_DESC_UPD_P123 0x01000830
+#define FR_BB_RX_DESC_UPD_P123_STEP 8192
+#define FR_BB_RX_DESC_UPD_P123_ROWS 3072
+#define FRF_AZ_RX_DESC_WPTR_LBN 96
+#define FRF_AZ_RX_DESC_WPTR_WIDTH 12
+#define FRF_AZ_RX_DESC_PUSH_CMD_LBN 95
+#define FRF_AZ_RX_DESC_PUSH_CMD_WIDTH 1
+#define FRF_AZ_RX_DESC_LBN 0
+#define FRF_AZ_RX_DESC_WIDTH 64
+
+/* RX_DC_CFG_REG: Receive descriptor cache configuration register */
+#define FR_AZ_RX_DC_CFG 0x00000840
+#define FRF_AB_RX_MAX_PF_LBN 2
+#define FRF_AB_RX_MAX_PF_WIDTH 2
+#define FRF_AZ_RX_DC_SIZE_LBN 0
+#define FRF_AZ_RX_DC_SIZE_WIDTH 2
+#define FFE_AZ_RX_DC_SIZE_64 3
+#define FFE_AZ_RX_DC_SIZE_32 2
+#define FFE_AZ_RX_DC_SIZE_16 1
+#define FFE_AZ_RX_DC_SIZE_8 0
+
+/* RX_DC_PF_WM_REG: Receive descriptor cache pre-fetch watermark register */
+#define FR_AZ_RX_DC_PF_WM 0x00000850
+#define FRF_AZ_RX_DC_PF_HWM_LBN 6
+#define FRF_AZ_RX_DC_PF_HWM_WIDTH 6
+#define FRF_AZ_RX_DC_PF_LWM_LBN 0
+#define FRF_AZ_RX_DC_PF_LWM_WIDTH 6
+
+/* RX_RSS_TKEY_REG: RSS Toeplitz hash key */
+#define FR_BZ_RX_RSS_TKEY 0x00000860
+#define FRF_BZ_RX_RSS_TKEY_HI_LBN 64
+#define FRF_BZ_RX_RSS_TKEY_HI_WIDTH 64
+#define FRF_BZ_RX_RSS_TKEY_LO_LBN 0
+#define FRF_BZ_RX_RSS_TKEY_LO_WIDTH 64
+
+/* RX_NODESC_DROP_REG: Receive dropped packet counter register */
+#define FR_AZ_RX_NODESC_DROP 0x00000880
+#define FRF_CZ_RX_NODESC_DROP_CNT_LBN 0
+#define FRF_CZ_RX_NODESC_DROP_CNT_WIDTH 32
+#define FRF_AB_RX_NODESC_DROP_CNT_LBN 0
+#define FRF_AB_RX_NODESC_DROP_CNT_WIDTH 16
+
+/* RX_SELF_RST_REG: Receive self reset register */
+#define FR_AA_RX_SELF_RST 0x00000890
+#define FRF_AA_RX_ISCSI_DIS_LBN 17
+#define FRF_AA_RX_ISCSI_DIS_WIDTH 1
+#define FRF_AA_RX_SW_RST_REG_LBN 16
+#define FRF_AA_RX_SW_RST_REG_WIDTH 1
+#define FRF_AA_RX_NODESC_WAIT_DIS_LBN 9
+#define FRF_AA_RX_NODESC_WAIT_DIS_WIDTH 1
+#define FRF_AA_RX_SELF_RST_EN_LBN 8
+#define FRF_AA_RX_SELF_RST_EN_WIDTH 1
+#define FRF_AA_RX_MAX_PF_LAT_LBN 4
+#define FRF_AA_RX_MAX_PF_LAT_WIDTH 4
+#define FRF_AA_RX_MAX_LU_LAT_LBN 0
+#define FRF_AA_RX_MAX_LU_LAT_WIDTH 4
+
+/* RX_DEBUG_REG: undocumented register */
+#define FR_AZ_RX_DEBUG 0x000008a0
+#define FRF_AZ_RX_DEBUG_LBN 0
+#define FRF_AZ_RX_DEBUG_WIDTH 64
+
+/* RX_PUSH_DROP_REG: Receive descriptor push dropped counter register */
+#define FR_AZ_RX_PUSH_DROP 0x000008b0
+#define FRF_AZ_RX_PUSH_DROP_CNT_LBN 0
+#define FRF_AZ_RX_PUSH_DROP_CNT_WIDTH 32
+
+/* RX_RSS_IPV6_REG1: IPv6 RSS Toeplitz hash key low bytes */
+#define FR_CZ_RX_RSS_IPV6_REG1 0x000008d0
+#define FRF_CZ_RX_RSS_IPV6_TKEY_LO_LBN 0
+#define FRF_CZ_RX_RSS_IPV6_TKEY_LO_WIDTH 128
+
+/* RX_RSS_IPV6_REG2: IPv6 RSS Toeplitz hash key middle bytes */
+#define FR_CZ_RX_RSS_IPV6_REG2 0x000008e0
+#define FRF_CZ_RX_RSS_IPV6_TKEY_MID_LBN 0
+#define FRF_CZ_RX_RSS_IPV6_TKEY_MID_WIDTH 128
+
+/* RX_RSS_IPV6_REG3: IPv6 RSS Toeplitz hash key upper bytes and IPv6 RSS settings */
+#define FR_CZ_RX_RSS_IPV6_REG3 0x000008f0
+#define FRF_CZ_RX_RSS_IPV6_THASH_ENABLE_LBN 66
+#define FRF_CZ_RX_RSS_IPV6_THASH_ENABLE_WIDTH 1
+#define FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE_LBN 65
+#define FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE_WIDTH 1
+#define FRF_CZ_RX_RSS_IPV6_TCP_SUPPRESS_LBN 64
+#define FRF_CZ_RX_RSS_IPV6_TCP_SUPPRESS_WIDTH 1
+#define FRF_CZ_RX_RSS_IPV6_TKEY_HI_LBN 0
+#define FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH 64
+
+/* TX_FLUSH_DESCQ_REG: Transmit flush descriptor queue register */
+#define FR_AZ_TX_FLUSH_DESCQ 0x00000a00
+#define FRF_AZ_TX_FLUSH_DESCQ_CMD_LBN 12
+#define FRF_AZ_TX_FLUSH_DESCQ_CMD_WIDTH 1
+#define FRF_AZ_TX_FLUSH_DESCQ_LBN 0
+#define FRF_AZ_TX_FLUSH_DESCQ_WIDTH 12
+
+/* TX_DESC_UPD_REGP0: Transmit descriptor update register. */
+#define FR_BZ_TX_DESC_UPD_P0 0x00000a10
+#define FR_BZ_TX_DESC_UPD_P0_STEP 8192
+#define FR_BZ_TX_DESC_UPD_P0_ROWS 1024
+/* TX_DESC_UPD_REG_KER: Transmit descriptor update register. */
+#define FR_AA_TX_DESC_UPD_KER 0x00000a10
+#define FR_AA_TX_DESC_UPD_KER_STEP 8192
+#define FR_AA_TX_DESC_UPD_KER_ROWS 8
+/* TX_DESC_UPD_REGP123: Transmit descriptor update register. */
+#define FR_BB_TX_DESC_UPD_P123 0x01000a10
+#define FR_BB_TX_DESC_UPD_P123_STEP 8192
+#define FR_BB_TX_DESC_UPD_P123_ROWS 3072
+#define FRF_AZ_TX_DESC_WPTR_LBN 96
+#define FRF_AZ_TX_DESC_WPTR_WIDTH 12
+#define FRF_AZ_TX_DESC_PUSH_CMD_LBN 95
+#define FRF_AZ_TX_DESC_PUSH_CMD_WIDTH 1
+#define FRF_AZ_TX_DESC_LBN 0
+#define FRF_AZ_TX_DESC_WIDTH 95
+
+/* TX_DC_CFG_REG: Transmit descriptor cache configuration register */
+#define FR_AZ_TX_DC_CFG 0x00000a20
+#define FRF_AZ_TX_DC_SIZE_LBN 0
+#define FRF_AZ_TX_DC_SIZE_WIDTH 2
+#define FFE_AZ_TX_DC_SIZE_32 2
+#define FFE_AZ_TX_DC_SIZE_16 1
+#define FFE_AZ_TX_DC_SIZE_8 0
+
+/* TX_CHKSM_CFG_REG: Transmit checksum configuration register */
+#define FR_AA_TX_CHKSM_CFG 0x00000a30
+#define FRF_AA_TX_Q_CHKSM_DIS_96_127_LBN 96
+#define FRF_AA_TX_Q_CHKSM_DIS_96_127_WIDTH 32
+#define FRF_AA_TX_Q_CHKSM_DIS_64_95_LBN 64
+#define FRF_AA_TX_Q_CHKSM_DIS_64_95_WIDTH 32
+#define FRF_AA_TX_Q_CHKSM_DIS_32_63_LBN 32
+#define FRF_AA_TX_Q_CHKSM_DIS_32_63_WIDTH 32
+#define FRF_AA_TX_Q_CHKSM_DIS_0_31_LBN 0
+#define FRF_AA_TX_Q_CHKSM_DIS_0_31_WIDTH 32
+
+/* TX_CFG_REG: Transmit configuration register */
+#define FR_AZ_TX_CFG 0x00000a50
+#define FRF_CZ_TX_CONT_LOOKUP_THRESH_RANGE_LBN 114
+#define FRF_CZ_TX_CONT_LOOKUP_THRESH_RANGE_WIDTH 8
+#define FRF_CZ_TX_FILTER_TEST_MODE_BIT_LBN 113
+#define FRF_CZ_TX_FILTER_TEST_MODE_BIT_WIDTH 1
+#define FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE_LBN 105
+#define FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE_WIDTH 8
+#define FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE_LBN 97
+#define FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE_WIDTH 8
+#define FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE_LBN 89
+#define FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE_WIDTH 8
+#define FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE_LBN 81
+#define FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE_WIDTH 8
+#define FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE_LBN 73
+#define FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE_WIDTH 8
+#define FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE_LBN 65
+#define FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE_WIDTH 8
+#define FRF_CZ_TX_FILTER_ALL_VLAN_ETHERTYPES_BIT_LBN 64
+#define FRF_CZ_TX_FILTER_ALL_VLAN_ETHERTYPES_BIT_WIDTH 1
+#define FRF_CZ_TX_VLAN_MATCH_ETHERTYPE_RANGE_LBN 48
+#define FRF_CZ_TX_VLAN_MATCH_ETHERTYPE_RANGE_WIDTH 16
+#define FRF_CZ_TX_FILTER_EN_BIT_LBN 47
+#define FRF_CZ_TX_FILTER_EN_BIT_WIDTH 1
+#define FRF_AZ_TX_IP_ID_P0_OFS_LBN 16
+#define FRF_AZ_TX_IP_ID_P0_OFS_WIDTH 15
+#define FRF_AZ_TX_NO_EOP_DISC_EN_LBN 5
+#define FRF_AZ_TX_NO_EOP_DISC_EN_WIDTH 1
+#define FRF_AZ_TX_P1_PRI_EN_LBN 4
+#define FRF_AZ_TX_P1_PRI_EN_WIDTH 1
+#define FRF_AZ_TX_OWNERR_CTL_LBN 2
+#define FRF_AZ_TX_OWNERR_CTL_WIDTH 1
+#define FRF_AA_TX_NON_IP_DROP_DIS_LBN 1
+#define FRF_AA_TX_NON_IP_DROP_DIS_WIDTH 1
+#define FRF_AZ_TX_IP_ID_REP_EN_LBN 0
+#define FRF_AZ_TX_IP_ID_REP_EN_WIDTH 1
+
+/* TX_PUSH_DROP_REG: Transmit push dropped register */
+#define FR_AZ_TX_PUSH_DROP 0x00000a60
+#define FRF_AZ_TX_PUSH_DROP_CNT_LBN 0
+#define FRF_AZ_TX_PUSH_DROP_CNT_WIDTH 32
+
+/* TX_RESERVED_REG: Transmit configuration register */
+#define FR_AZ_TX_RESERVED 0x00000a80
+#define FRF_AZ_TX_EVT_CNT_LBN 121
+#define FRF_AZ_TX_EVT_CNT_WIDTH 7
+#define FRF_AZ_TX_PREF_AGE_CNT_LBN 119
+#define FRF_AZ_TX_PREF_AGE_CNT_WIDTH 2
+#define FRF_AZ_TX_RD_COMP_TMR_LBN 96
+#define FRF_AZ_TX_RD_COMP_TMR_WIDTH 23
+#define FRF_AZ_TX_PUSH_EN_LBN 89
+#define FRF_AZ_TX_PUSH_EN_WIDTH 1
+#define FRF_AZ_TX_PUSH_CHK_DIS_LBN 88
+#define FRF_AZ_TX_PUSH_CHK_DIS_WIDTH 1
+#define FRF_AZ_TX_D_FF_FULL_P0_LBN 85
+#define FRF_AZ_TX_D_FF_FULL_P0_WIDTH 1
+#define FRF_AZ_TX_DMAR_ST_P0_LBN 81
+#define FRF_AZ_TX_DMAR_ST_P0_WIDTH 1
+#define FRF_AZ_TX_DMAQ_ST_LBN 78
+#define FRF_AZ_TX_DMAQ_ST_WIDTH 1
+#define FRF_AZ_TX_RX_SPACER_LBN 64
+#define FRF_AZ_TX_RX_SPACER_WIDTH 8
+#define FRF_AZ_TX_DROP_ABORT_EN_LBN 60
+#define FRF_AZ_TX_DROP_ABORT_EN_WIDTH 1
+#define FRF_AZ_TX_SOFT_EVT_EN_LBN 59
+#define FRF_AZ_TX_SOFT_EVT_EN_WIDTH 1
+#define FRF_AZ_TX_PS_EVT_DIS_LBN 58
+#define FRF_AZ_TX_PS_EVT_DIS_WIDTH 1
+#define FRF_AZ_TX_RX_SPACER_EN_LBN 57
+#define FRF_AZ_TX_RX_SPACER_EN_WIDTH 1
+#define FRF_AZ_TX_XP_TIMER_LBN 52
+#define FRF_AZ_TX_XP_TIMER_WIDTH 5
+#define FRF_AZ_TX_PREF_SPACER_LBN 44
+#define FRF_AZ_TX_PREF_SPACER_WIDTH 8
+#define FRF_AZ_TX_PREF_WD_TMR_LBN 22
+#define FRF_AZ_TX_PREF_WD_TMR_WIDTH 22
+#define FRF_AZ_TX_ONLY1TAG_LBN 21
+#define FRF_AZ_TX_ONLY1TAG_WIDTH 1
+#define FRF_AZ_TX_PREF_THRESHOLD_LBN 19
+#define FRF_AZ_TX_PREF_THRESHOLD_WIDTH 2
+#define FRF_AZ_TX_ONE_PKT_PER_Q_LBN 18
+#define FRF_AZ_TX_ONE_PKT_PER_Q_WIDTH 1
+#define FRF_AZ_TX_DIS_NON_IP_EV_LBN 17
+#define FRF_AZ_TX_DIS_NON_IP_EV_WIDTH 1
+#define FRF_AA_TX_DMA_FF_THR_LBN 16
+#define FRF_AA_TX_DMA_FF_THR_WIDTH 1
+#define FRF_AZ_TX_DMA_SPACER_LBN 8
+#define FRF_AZ_TX_DMA_SPACER_WIDTH 8
+#define FRF_AA_TX_TCP_DIS_LBN 7
+#define FRF_AA_TX_TCP_DIS_WIDTH 1
+#define FRF_BZ_TX_FLUSH_MIN_LEN_EN_LBN 7
+#define FRF_BZ_TX_FLUSH_MIN_LEN_EN_WIDTH 1
+#define FRF_AA_TX_IP_DIS_LBN 6
+#define FRF_AA_TX_IP_DIS_WIDTH 1
+#define FRF_AZ_TX_MAX_CPL_LBN 2
+#define FRF_AZ_TX_MAX_CPL_WIDTH 2
+#define FFE_AZ_TX_MAX_CPL_16 3
+#define FFE_AZ_TX_MAX_CPL_8 2
+#define FFE_AZ_TX_MAX_CPL_4 1
+#define FFE_AZ_TX_MAX_CPL_NOLIMIT 0
+#define FRF_AZ_TX_MAX_PREF_LBN 0
+#define FRF_AZ_TX_MAX_PREF_WIDTH 2
+#define FFE_AZ_TX_MAX_PREF_32 3
+#define FFE_AZ_TX_MAX_PREF_16 2
+#define FFE_AZ_TX_MAX_PREF_8 1
+#define FFE_AZ_TX_MAX_PREF_OFF 0
+
+/* TX_PACE_REG: Transmit pace control register */
+#define FR_BZ_TX_PACE 0x00000a90
+#define FRF_BZ_TX_PACE_SB_NOT_AF_LBN 19
+#define FRF_BZ_TX_PACE_SB_NOT_AF_WIDTH 10
+#define FRF_BZ_TX_PACE_SB_AF_LBN 9
+#define FRF_BZ_TX_PACE_SB_AF_WIDTH 10
+#define FRF_BZ_TX_PACE_FB_BASE_LBN 5
+#define FRF_BZ_TX_PACE_FB_BASE_WIDTH 4
+#define FRF_BZ_TX_PACE_BIN_TH_LBN 0
+#define FRF_BZ_TX_PACE_BIN_TH_WIDTH 5
+
+/* TX_PACE_DROP_QID_REG: PACE Drop QID Counter */
+#define FR_BZ_TX_PACE_DROP_QID 0x00000aa0
+#define FRF_BZ_TX_PACE_QID_DRP_CNT_LBN 0
+#define FRF_BZ_TX_PACE_QID_DRP_CNT_WIDTH 16
+
+/* TX_VLAN_REG: Transmit VLAN tag register */
+#define FR_BB_TX_VLAN 0x00000ae0
+#define FRF_BB_TX_VLAN_EN_LBN 127
+#define FRF_BB_TX_VLAN_EN_WIDTH 1
+#define FRF_BB_TX_VLAN7_PORT1_EN_LBN 125
+#define FRF_BB_TX_VLAN7_PORT1_EN_WIDTH 1
+#define FRF_BB_TX_VLAN7_PORT0_EN_LBN 124
+#define FRF_BB_TX_VLAN7_PORT0_EN_WIDTH 1
+#define FRF_BB_TX_VLAN7_LBN 112
+#define FRF_BB_TX_VLAN7_WIDTH 12
+#define FRF_BB_TX_VLAN6_PORT1_EN_LBN 109
+#define FRF_BB_TX_VLAN6_PORT1_EN_WIDTH 1
+#define FRF_BB_TX_VLAN6_PORT0_EN_LBN 108
+#define FRF_BB_TX_VLAN6_PORT0_EN_WIDTH 1
+#define FRF_BB_TX_VLAN6_LBN 96
+#define FRF_BB_TX_VLAN6_WIDTH 12
+#define FRF_BB_TX_VLAN5_PORT1_EN_LBN 93
+#define FRF_BB_TX_VLAN5_PORT1_EN_WIDTH 1
+#define FRF_BB_TX_VLAN5_PORT0_EN_LBN 92
+#define FRF_BB_TX_VLAN5_PORT0_EN_WIDTH 1
+#define FRF_BB_TX_VLAN5_LBN 80
+#define FRF_BB_TX_VLAN5_WIDTH 12
+#define FRF_BB_TX_VLAN4_PORT1_EN_LBN 77
+#define FRF_BB_TX_VLAN4_PORT1_EN_WIDTH 1
+#define FRF_BB_TX_VLAN4_PORT0_EN_LBN 76
+#define FRF_BB_TX_VLAN4_PORT0_EN_WIDTH 1
+#define FRF_BB_TX_VLAN4_LBN 64
+#define FRF_BB_TX_VLAN4_WIDTH 12
+#define FRF_BB_TX_VLAN3_PORT1_EN_LBN 61
+#define FRF_BB_TX_VLAN3_PORT1_EN_WIDTH 1
+#define FRF_BB_TX_VLAN3_PORT0_EN_LBN 60
+#define FRF_BB_TX_VLAN3_PORT0_EN_WIDTH 1
+#define FRF_BB_TX_VLAN3_LBN 48
+#define FRF_BB_TX_VLAN3_WIDTH 12
+#define FRF_BB_TX_VLAN2_PORT1_EN_LBN 45
+#define FRF_BB_TX_VLAN2_PORT1_EN_WIDTH 1
+#define FRF_BB_TX_VLAN2_PORT0_EN_LBN 44
+#define FRF_BB_TX_VLAN2_PORT0_EN_WIDTH 1
+#define FRF_BB_TX_VLAN2_LBN 32
+#define FRF_BB_TX_VLAN2_WIDTH 12
+#define FRF_BB_TX_VLAN1_PORT1_EN_LBN 29
+#define FRF_BB_TX_VLAN1_PORT1_EN_WIDTH 1
+#define FRF_BB_TX_VLAN1_PORT0_EN_LBN 28
+#define FRF_BB_TX_VLAN1_PORT0_EN_WIDTH 1
+#define FRF_BB_TX_VLAN1_LBN 16
+#define FRF_BB_TX_VLAN1_WIDTH 12
+#define FRF_BB_TX_VLAN0_PORT1_EN_LBN 13
+#define FRF_BB_TX_VLAN0_PORT1_EN_WIDTH 1
+#define FRF_BB_TX_VLAN0_PORT0_EN_LBN 12
+#define FRF_BB_TX_VLAN0_PORT0_EN_WIDTH 1
+#define FRF_BB_TX_VLAN0_LBN 0
+#define FRF_BB_TX_VLAN0_WIDTH 12
+
+/* TX_IPFIL_PORTEN_REG: Transmit filter control register */
+#define FR_BZ_TX_IPFIL_PORTEN 0x00000af0
+#define FRF_BZ_TX_MADR0_FIL_EN_LBN 64
+#define FRF_BZ_TX_MADR0_FIL_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL31_PORT_EN_LBN 62
+#define FRF_BB_TX_IPFIL31_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL30_PORT_EN_LBN 60
+#define FRF_BB_TX_IPFIL30_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL29_PORT_EN_LBN 58
+#define FRF_BB_TX_IPFIL29_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL28_PORT_EN_LBN 56
+#define FRF_BB_TX_IPFIL28_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL27_PORT_EN_LBN 54
+#define FRF_BB_TX_IPFIL27_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL26_PORT_EN_LBN 52
+#define FRF_BB_TX_IPFIL26_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL25_PORT_EN_LBN 50
+#define FRF_BB_TX_IPFIL25_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL24_PORT_EN_LBN 48
+#define FRF_BB_TX_IPFIL24_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL23_PORT_EN_LBN 46
+#define FRF_BB_TX_IPFIL23_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL22_PORT_EN_LBN 44
+#define FRF_BB_TX_IPFIL22_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL21_PORT_EN_LBN 42
+#define FRF_BB_TX_IPFIL21_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL20_PORT_EN_LBN 40
+#define FRF_BB_TX_IPFIL20_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL19_PORT_EN_LBN 38
+#define FRF_BB_TX_IPFIL19_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL18_PORT_EN_LBN 36
+#define FRF_BB_TX_IPFIL18_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL17_PORT_EN_LBN 34
+#define FRF_BB_TX_IPFIL17_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL16_PORT_EN_LBN 32
+#define FRF_BB_TX_IPFIL16_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL15_PORT_EN_LBN 30
+#define FRF_BB_TX_IPFIL15_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL14_PORT_EN_LBN 28
+#define FRF_BB_TX_IPFIL14_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL13_PORT_EN_LBN 26
+#define FRF_BB_TX_IPFIL13_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL12_PORT_EN_LBN 24
+#define FRF_BB_TX_IPFIL12_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL11_PORT_EN_LBN 22
+#define FRF_BB_TX_IPFIL11_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL10_PORT_EN_LBN 20
+#define FRF_BB_TX_IPFIL10_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL9_PORT_EN_LBN 18
+#define FRF_BB_TX_IPFIL9_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL8_PORT_EN_LBN 16
+#define FRF_BB_TX_IPFIL8_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL7_PORT_EN_LBN 14
+#define FRF_BB_TX_IPFIL7_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL6_PORT_EN_LBN 12
+#define FRF_BB_TX_IPFIL6_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL5_PORT_EN_LBN 10
+#define FRF_BB_TX_IPFIL5_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL4_PORT_EN_LBN 8
+#define FRF_BB_TX_IPFIL4_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL3_PORT_EN_LBN 6
+#define FRF_BB_TX_IPFIL3_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL2_PORT_EN_LBN 4
+#define FRF_BB_TX_IPFIL2_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL1_PORT_EN_LBN 2
+#define FRF_BB_TX_IPFIL1_PORT_EN_WIDTH 1
+#define FRF_BB_TX_IPFIL0_PORT_EN_LBN 0
+#define FRF_BB_TX_IPFIL0_PORT_EN_WIDTH 1
+
+/* TX_IPFIL_TBL: Transmit IP source address filter table */
+#define FR_BB_TX_IPFIL_TBL 0x00000b00
+#define FR_BB_TX_IPFIL_TBL_STEP 16
+#define FR_BB_TX_IPFIL_TBL_ROWS 16
+#define FRF_BB_TX_IPFIL_MASK_1_LBN 96
+#define FRF_BB_TX_IPFIL_MASK_1_WIDTH 32
+#define FRF_BB_TX_IP_SRC_ADR_1_LBN 64
+#define FRF_BB_TX_IP_SRC_ADR_1_WIDTH 32
+#define FRF_BB_TX_IPFIL_MASK_0_LBN 32
+#define FRF_BB_TX_IPFIL_MASK_0_WIDTH 32
+#define FRF_BB_TX_IP_SRC_ADR_0_LBN 0
+#define FRF_BB_TX_IP_SRC_ADR_0_WIDTH 32
+
+/* MD_TXD_REG: PHY management transmit data register */
+#define FR_AB_MD_TXD 0x00000c00
+#define FRF_AB_MD_TXD_LBN 0
+#define FRF_AB_MD_TXD_WIDTH 16
+
+/* MD_RXD_REG: PHY management receive data register */
+#define FR_AB_MD_RXD 0x00000c10
+#define FRF_AB_MD_RXD_LBN 0
+#define FRF_AB_MD_RXD_WIDTH 16
+
+/* MD_CS_REG: PHY management configuration & status register */
+#define FR_AB_MD_CS 0x00000c20
+#define FRF_AB_MD_RD_EN_CMD_LBN 15
+#define FRF_AB_MD_RD_EN_CMD_WIDTH 1
+#define FRF_AB_MD_WR_EN_CMD_LBN 14
+#define FRF_AB_MD_WR_EN_CMD_WIDTH 1
+#define FRF_AB_MD_ADDR_CMD_LBN 13
+#define FRF_AB_MD_ADDR_CMD_WIDTH 1
+#define FRF_AB_MD_PT_LBN 7
+#define FRF_AB_MD_PT_WIDTH 3
+#define FRF_AB_MD_PL_LBN 6
+#define FRF_AB_MD_PL_WIDTH 1
+#define FRF_AB_MD_INT_CLR_LBN 5
+#define FRF_AB_MD_INT_CLR_WIDTH 1
+#define FRF_AB_MD_GC_LBN 4
+#define FRF_AB_MD_GC_WIDTH 1
+#define FRF_AB_MD_PRSP_LBN 3
+#define FRF_AB_MD_PRSP_WIDTH 1
+#define FRF_AB_MD_RIC_LBN 2
+#define FRF_AB_MD_RIC_WIDTH 1
+#define FRF_AB_MD_RDC_LBN 1
+#define FRF_AB_MD_RDC_WIDTH 1
+#define FRF_AB_MD_WRC_LBN 0
+#define FRF_AB_MD_WRC_WIDTH 1
+
+/* MD_PHY_ADR_REG: PHY management PHY address register */
+#define FR_AB_MD_PHY_ADR 0x00000c30
+#define FRF_AB_MD_PHY_ADR_LBN 0
+#define FRF_AB_MD_PHY_ADR_WIDTH 16
+
+/* MD_ID_REG: PHY management ID register */
+#define FR_AB_MD_ID 0x00000c40
+#define FRF_AB_MD_PRT_ADR_LBN 11
+#define FRF_AB_MD_PRT_ADR_WIDTH 5
+#define FRF_AB_MD_DEV_ADR_LBN 6
+#define FRF_AB_MD_DEV_ADR_WIDTH 5
+
+/* MD_STAT_REG: PHY management status & mask register */
+#define FR_AB_MD_STAT 0x00000c50
+#define FRF_AB_MD_PINT_LBN 4
+#define FRF_AB_MD_PINT_WIDTH 1
+#define FRF_AB_MD_DONE_LBN 3
+#define FRF_AB_MD_DONE_WIDTH 1
+#define FRF_AB_MD_BSERR_LBN 2
+#define FRF_AB_MD_BSERR_WIDTH 1
+#define FRF_AB_MD_LNFL_LBN 1
+#define FRF_AB_MD_LNFL_WIDTH 1
+#define FRF_AB_MD_BSY_LBN 0
+#define FRF_AB_MD_BSY_WIDTH 1
+
+/* MAC_STAT_DMA_REG: Port MAC statistical counter DMA register */
+#define FR_AB_MAC_STAT_DMA 0x00000c60
+#define FRF_AB_MAC_STAT_DMA_CMD_LBN 48
+#define FRF_AB_MAC_STAT_DMA_CMD_WIDTH 1
+#define FRF_AB_MAC_STAT_DMA_ADR_LBN 0
+#define FRF_AB_MAC_STAT_DMA_ADR_WIDTH 48
+
+/* MAC_CTRL_REG: Port MAC control register */
+#define FR_AB_MAC_CTRL 0x00000c80
+#define FRF_AB_MAC_XOFF_VAL_LBN 16
+#define FRF_AB_MAC_XOFF_VAL_WIDTH 16
+#define FRF_BB_TXFIFO_DRAIN_EN_LBN 7
+#define FRF_BB_TXFIFO_DRAIN_EN_WIDTH 1
+#define FRF_AB_MAC_XG_DISTXCRC_LBN 5
+#define FRF_AB_MAC_XG_DISTXCRC_WIDTH 1
+#define FRF_AB_MAC_BCAD_ACPT_LBN 4
+#define FRF_AB_MAC_BCAD_ACPT_WIDTH 1
+#define FRF_AB_MAC_UC_PROM_LBN 3
+#define FRF_AB_MAC_UC_PROM_WIDTH 1
+#define FRF_AB_MAC_LINK_STATUS_LBN 2
+#define FRF_AB_MAC_LINK_STATUS_WIDTH 1
+#define FRF_AB_MAC_SPEED_LBN 0
+#define FRF_AB_MAC_SPEED_WIDTH 2
+#define FFE_AB_MAC_SPEED_10G 3
+#define FFE_AB_MAC_SPEED_1G 2
+#define FFE_AB_MAC_SPEED_100M 1
+#define FFE_AB_MAC_SPEED_10M 0
+
+/* GEN_MODE_REG: General Purpose mode register (external interrupt mask) */
+#define FR_BB_GEN_MODE 0x00000c90
+#define FRF_BB_XFP_PHY_INT_POL_SEL_LBN 3
+#define FRF_BB_XFP_PHY_INT_POL_SEL_WIDTH 1
+#define FRF_BB_XG_PHY_INT_POL_SEL_LBN 2
+#define FRF_BB_XG_PHY_INT_POL_SEL_WIDTH 1
+#define FRF_BB_XFP_PHY_INT_MASK_LBN 1
+#define FRF_BB_XFP_PHY_INT_MASK_WIDTH 1
+#define FRF_BB_XG_PHY_INT_MASK_LBN 0
+#define FRF_BB_XG_PHY_INT_MASK_WIDTH 1
+
+/* MAC_MC_HASH_REG0: Multicast address hash table */
+#define FR_AB_MAC_MC_HASH_REG0 0x00000ca0
+#define FRF_AB_MAC_MCAST_HASH0_LBN 0
+#define FRF_AB_MAC_MCAST_HASH0_WIDTH 128
+
+/* MAC_MC_HASH_REG1: Multicast address hash table */
+#define FR_AB_MAC_MC_HASH_REG1 0x00000cb0
+#define FRF_AB_MAC_MCAST_HASH1_LBN 0
+#define FRF_AB_MAC_MCAST_HASH1_WIDTH 128
+
+/* GM_CFG1_REG: GMAC configuration register 1 */
+#define FR_AB_GM_CFG1 0x00000e00
+#define FRF_AB_GM_SW_RST_LBN 31
+#define FRF_AB_GM_SW_RST_WIDTH 1
+#define FRF_AB_GM_SIM_RST_LBN 30
+#define FRF_AB_GM_SIM_RST_WIDTH 1
+#define FRF_AB_GM_RST_RX_MAC_CTL_LBN 19
+#define FRF_AB_GM_RST_RX_MAC_CTL_WIDTH 1
+#define FRF_AB_GM_RST_TX_MAC_CTL_LBN 18
+#define FRF_AB_GM_RST_TX_MAC_CTL_WIDTH 1
+#define FRF_AB_GM_RST_RX_FUNC_LBN 17
+#define FRF_AB_GM_RST_RX_FUNC_WIDTH 1
+#define FRF_AB_GM_RST_TX_FUNC_LBN 16
+#define FRF_AB_GM_RST_TX_FUNC_WIDTH 1
+#define FRF_AB_GM_LOOP_LBN 8
+#define FRF_AB_GM_LOOP_WIDTH 1
+#define FRF_AB_GM_RX_FC_EN_LBN 5
+#define FRF_AB_GM_RX_FC_EN_WIDTH 1
+#define FRF_AB_GM_TX_FC_EN_LBN 4
+#define FRF_AB_GM_TX_FC_EN_WIDTH 1
+#define FRF_AB_GM_SYNC_RXEN_LBN 3
+#define FRF_AB_GM_SYNC_RXEN_WIDTH 1
+#define FRF_AB_GM_RX_EN_LBN 2
+#define FRF_AB_GM_RX_EN_WIDTH 1
+#define FRF_AB_GM_SYNC_TXEN_LBN 1
+#define FRF_AB_GM_SYNC_TXEN_WIDTH 1
+#define FRF_AB_GM_TX_EN_LBN 0
+#define FRF_AB_GM_TX_EN_WIDTH 1
+
+/* GM_CFG2_REG: GMAC configuration register 2 */
+#define FR_AB_GM_CFG2 0x00000e10
+#define FRF_AB_GM_PAMBL_LEN_LBN 12
+#define FRF_AB_GM_PAMBL_LEN_WIDTH 4
+#define FRF_AB_GM_IF_MODE_LBN 8
+#define FRF_AB_GM_IF_MODE_WIDTH 2
+#define FFE_AB_IF_MODE_BYTE_MODE 2
+#define FFE_AB_IF_MODE_NIBBLE_MODE 1
+#define FRF_AB_GM_HUGE_FRM_EN_LBN 5
+#define FRF_AB_GM_HUGE_FRM_EN_WIDTH 1
+#define FRF_AB_GM_LEN_CHK_LBN 4
+#define FRF_AB_GM_LEN_CHK_WIDTH 1
+#define FRF_AB_GM_PAD_CRC_EN_LBN 2
+#define FRF_AB_GM_PAD_CRC_EN_WIDTH 1
+#define FRF_AB_GM_CRC_EN_LBN 1
+#define FRF_AB_GM_CRC_EN_WIDTH 1
+#define FRF_AB_GM_FD_LBN 0
+#define FRF_AB_GM_FD_WIDTH 1
+
+/* GM_IPG_REG: GMAC IPG register */
+#define FR_AB_GM_IPG 0x00000e20
+#define FRF_AB_GM_NONB2B_IPG1_LBN 24
+#define FRF_AB_GM_NONB2B_IPG1_WIDTH 7
+#define FRF_AB_GM_NONB2B_IPG2_LBN 16
+#define FRF_AB_GM_NONB2B_IPG2_WIDTH 7
+#define FRF_AB_GM_MIN_IPG_ENF_LBN 8
+#define FRF_AB_GM_MIN_IPG_ENF_WIDTH 8
+#define FRF_AB_GM_B2B_IPG_LBN 0
+#define FRF_AB_GM_B2B_IPG_WIDTH 7
+
+/* GM_HD_REG: GMAC half duplex register */
+#define FR_AB_GM_HD 0x00000e30
+#define FRF_AB_GM_ALT_BOFF_VAL_LBN 20
+#define FRF_AB_GM_ALT_BOFF_VAL_WIDTH 4
+#define FRF_AB_GM_ALT_BOFF_EN_LBN 19
+#define FRF_AB_GM_ALT_BOFF_EN_WIDTH 1
+#define FRF_AB_GM_BP_NO_BOFF_LBN 18
+#define FRF_AB_GM_BP_NO_BOFF_WIDTH 1
+#define FRF_AB_GM_DIS_BOFF_LBN 17
+#define FRF_AB_GM_DIS_BOFF_WIDTH 1
+#define FRF_AB_GM_EXDEF_TX_EN_LBN 16
+#define FRF_AB_GM_EXDEF_TX_EN_WIDTH 1
+#define FRF_AB_GM_RTRY_LIMIT_LBN 12
+#define FRF_AB_GM_RTRY_LIMIT_WIDTH 4
+#define FRF_AB_GM_COL_WIN_LBN 0
+#define FRF_AB_GM_COL_WIN_WIDTH 10
+
+/* GM_MAX_FLEN_REG: GMAC maximum frame length register */
+#define FR_AB_GM_MAX_FLEN 0x00000e40
+#define FRF_AB_GM_MAX_FLEN_LBN 0
+#define FRF_AB_GM_MAX_FLEN_WIDTH 16
+
+/* GM_TEST_REG: GMAC test register */
+#define FR_AB_GM_TEST 0x00000e70
+#define FRF_AB_GM_MAX_BOFF_LBN 3
+#define FRF_AB_GM_MAX_BOFF_WIDTH 1
+#define FRF_AB_GM_REG_TX_FLOW_EN_LBN 2
+#define FRF_AB_GM_REG_TX_FLOW_EN_WIDTH 1
+#define FRF_AB_GM_TEST_PAUSE_LBN 1
+#define FRF_AB_GM_TEST_PAUSE_WIDTH 1
+#define FRF_AB_GM_SHORT_SLOT_LBN 0
+#define FRF_AB_GM_SHORT_SLOT_WIDTH 1
+
+/* GM_ADR1_REG: GMAC station address register 1 */
+#define FR_AB_GM_ADR1 0x00000f00
+#define FRF_AB_GM_ADR_B0_LBN 24
+#define FRF_AB_GM_ADR_B0_WIDTH 8
+#define FRF_AB_GM_ADR_B1_LBN 16
+#define FRF_AB_GM_ADR_B1_WIDTH 8
+#define FRF_AB_GM_ADR_B2_LBN 8
+#define FRF_AB_GM_ADR_B2_WIDTH 8
+#define FRF_AB_GM_ADR_B3_LBN 0
+#define FRF_AB_GM_ADR_B3_WIDTH 8
+
+/* GM_ADR2_REG: GMAC station address register 2 */
+#define FR_AB_GM_ADR2 0x00000f10
+#define FRF_AB_GM_ADR_B4_LBN 24
+#define FRF_AB_GM_ADR_B4_WIDTH 8
+#define FRF_AB_GM_ADR_B5_LBN 16
+#define FRF_AB_GM_ADR_B5_WIDTH 8
+
+/* GMF_CFG0_REG: GMAC FIFO configuration register 0 */
+#define FR_AB_GMF_CFG0 0x00000f20
+#define FRF_AB_GMF_FTFENRPLY_LBN 20
+#define FRF_AB_GMF_FTFENRPLY_WIDTH 1
+#define FRF_AB_GMF_STFENRPLY_LBN 19
+#define FRF_AB_GMF_STFENRPLY_WIDTH 1
+#define FRF_AB_GMF_FRFENRPLY_LBN 18
+#define FRF_AB_GMF_FRFENRPLY_WIDTH 1
+#define FRF_AB_GMF_SRFENRPLY_LBN 17
+#define FRF_AB_GMF_SRFENRPLY_WIDTH 1
+#define FRF_AB_GMF_WTMENRPLY_LBN 16
+#define FRF_AB_GMF_WTMENRPLY_WIDTH 1
+#define FRF_AB_GMF_FTFENREQ_LBN 12
+#define FRF_AB_GMF_FTFENREQ_WIDTH 1
+#define FRF_AB_GMF_STFENREQ_LBN 11
+#define FRF_AB_GMF_STFENREQ_WIDTH 1
+#define FRF_AB_GMF_FRFENREQ_LBN 10
+#define FRF_AB_GMF_FRFENREQ_WIDTH 1
+#define FRF_AB_GMF_SRFENREQ_LBN 9
+#define FRF_AB_GMF_SRFENREQ_WIDTH 1
+#define FRF_AB_GMF_WTMENREQ_LBN 8
+#define FRF_AB_GMF_WTMENREQ_WIDTH 1
+#define FRF_AB_GMF_HSTRSTFT_LBN 4
+#define FRF_AB_GMF_HSTRSTFT_WIDTH 1
+#define FRF_AB_GMF_HSTRSTST_LBN 3
+#define FRF_AB_GMF_HSTRSTST_WIDTH 1
+#define FRF_AB_GMF_HSTRSTFR_LBN 2
+#define FRF_AB_GMF_HSTRSTFR_WIDTH 1
+#define FRF_AB_GMF_HSTRSTSR_LBN 1
+#define FRF_AB_GMF_HSTRSTSR_WIDTH 1
+#define FRF_AB_GMF_HSTRSTWT_LBN 0
+#define FRF_AB_GMF_HSTRSTWT_WIDTH 1
+
+/* GMF_CFG1_REG: GMAC FIFO configuration register 1 */
+#define FR_AB_GMF_CFG1 0x00000f30
+#define FRF_AB_GMF_CFGFRTH_LBN 16
+#define FRF_AB_GMF_CFGFRTH_WIDTH 5
+#define FRF_AB_GMF_CFGXOFFRTX_LBN 0
+#define FRF_AB_GMF_CFGXOFFRTX_WIDTH 16
+
+/* GMF_CFG2_REG: GMAC FIFO configuration register 2 */
+#define FR_AB_GMF_CFG2 0x00000f40
+#define FRF_AB_GMF_CFGHWM_LBN 16
+#define FRF_AB_GMF_CFGHWM_WIDTH 6
+#define FRF_AB_GMF_CFGLWM_LBN 0
+#define FRF_AB_GMF_CFGLWM_WIDTH 6
+
+/* GMF_CFG3_REG: GMAC FIFO configuration register 3 */
+#define FR_AB_GMF_CFG3 0x00000f50
+#define FRF_AB_GMF_CFGHWMFT_LBN 16
+#define FRF_AB_GMF_CFGHWMFT_WIDTH 6
+#define FRF_AB_GMF_CFGFTTH_LBN 0
+#define FRF_AB_GMF_CFGFTTH_WIDTH 6
+
+/* GMF_CFG4_REG: GMAC FIFO configuration register 4 */
+#define FR_AB_GMF_CFG4 0x00000f60
+#define FRF_AB_GMF_HSTFLTRFRM_LBN 0
+#define FRF_AB_GMF_HSTFLTRFRM_WIDTH 18
+
+/* GMF_CFG5_REG: GMAC FIFO configuration register 5 */
+#define FR_AB_GMF_CFG5 0x00000f70
+#define FRF_AB_GMF_CFGHDPLX_LBN 22
+#define FRF_AB_GMF_CFGHDPLX_WIDTH 1
+#define FRF_AB_GMF_SRFULL_LBN 21
+#define FRF_AB_GMF_SRFULL_WIDTH 1
+#define FRF_AB_GMF_HSTSRFULLCLR_LBN 20
+#define FRF_AB_GMF_HSTSRFULLCLR_WIDTH 1
+#define FRF_AB_GMF_CFGBYTMODE_LBN 19
+#define FRF_AB_GMF_CFGBYTMODE_WIDTH 1
+#define FRF_AB_GMF_HSTDRPLT64_LBN 18
+#define FRF_AB_GMF_HSTDRPLT64_WIDTH 1
+#define FRF_AB_GMF_HSTFLTRFRMDC_LBN 0
+#define FRF_AB_GMF_HSTFLTRFRMDC_WIDTH 18
+
+/* TX_SRC_MAC_TBL: Transmit IP source address filter table */
+#define FR_BB_TX_SRC_MAC_TBL 0x00001000
+#define FR_BB_TX_SRC_MAC_TBL_STEP 16
+#define FR_BB_TX_SRC_MAC_TBL_ROWS 16
+#define FRF_BB_TX_SRC_MAC_ADR_1_LBN 64
+#define FRF_BB_TX_SRC_MAC_ADR_1_WIDTH 48
+#define FRF_BB_TX_SRC_MAC_ADR_0_LBN 0
+#define FRF_BB_TX_SRC_MAC_ADR_0_WIDTH 48
+
+/* TX_SRC_MAC_CTL_REG: Transmit MAC source address filter control */
+#define FR_BB_TX_SRC_MAC_CTL 0x00001100
+#define FRF_BB_TX_SRC_DROP_CTR_LBN 16
+#define FRF_BB_TX_SRC_DROP_CTR_WIDTH 16
+#define FRF_BB_TX_SRC_FLTR_EN_LBN 15
+#define FRF_BB_TX_SRC_FLTR_EN_WIDTH 1
+#define FRF_BB_TX_DROP_CTR_CLR_LBN 12
+#define FRF_BB_TX_DROP_CTR_CLR_WIDTH 1
+#define FRF_BB_TX_MAC_QID_SEL_LBN 0
+#define FRF_BB_TX_MAC_QID_SEL_WIDTH 3
+
+/* XM_ADR_LO_REG: XGMAC address register low */
+#define FR_AB_XM_ADR_LO 0x00001200
+#define FRF_AB_XM_ADR_LO_LBN 0
+#define FRF_AB_XM_ADR_LO_WIDTH 32
+
+/* XM_ADR_HI_REG: XGMAC address register high */
+#define FR_AB_XM_ADR_HI 0x00001210
+#define FRF_AB_XM_ADR_HI_LBN 0
+#define FRF_AB_XM_ADR_HI_WIDTH 16
+
+/* XM_GLB_CFG_REG: XGMAC global configuration */
+#define FR_AB_XM_GLB_CFG 0x00001220
+#define FRF_AB_XM_RMTFLT_GEN_LBN 17
+#define FRF_AB_XM_RMTFLT_GEN_WIDTH 1
+#define FRF_AB_XM_DEBUG_MODE_LBN 16
+#define FRF_AB_XM_DEBUG_MODE_WIDTH 1
+#define FRF_AB_XM_RX_STAT_EN_LBN 11
+#define FRF_AB_XM_RX_STAT_EN_WIDTH 1
+#define FRF_AB_XM_TX_STAT_EN_LBN 10
+#define FRF_AB_XM_TX_STAT_EN_WIDTH 1
+#define FRF_AB_XM_RX_JUMBO_MODE_LBN 6
+#define FRF_AB_XM_RX_JUMBO_MODE_WIDTH 1
+#define FRF_AB_XM_WAN_MODE_LBN 5
+#define FRF_AB_XM_WAN_MODE_WIDTH 1
+#define FRF_AB_XM_INTCLR_MODE_LBN 3
+#define FRF_AB_XM_INTCLR_MODE_WIDTH 1
+#define FRF_AB_XM_CORE_RST_LBN 0
+#define FRF_AB_XM_CORE_RST_WIDTH 1
+
+/* XM_TX_CFG_REG: XGMAC transmit configuration */
+#define FR_AB_XM_TX_CFG 0x00001230
+#define FRF_AB_XM_TX_PROG_LBN 24
+#define FRF_AB_XM_TX_PROG_WIDTH 1
+#define FRF_AB_XM_IPG_LBN 16
+#define FRF_AB_XM_IPG_WIDTH 4
+#define FRF_AB_XM_FCNTL_LBN 10
+#define FRF_AB_XM_FCNTL_WIDTH 1
+#define FRF_AB_XM_TXCRC_LBN 8
+#define FRF_AB_XM_TXCRC_WIDTH 1
+#define FRF_AB_XM_EDRC_LBN 6
+#define FRF_AB_XM_EDRC_WIDTH 1
+#define FRF_AB_XM_AUTO_PAD_LBN 5
+#define FRF_AB_XM_AUTO_PAD_WIDTH 1
+#define FRF_AB_XM_TX_PRMBL_LBN 2
+#define FRF_AB_XM_TX_PRMBL_WIDTH 1
+#define FRF_AB_XM_TXEN_LBN 1
+#define FRF_AB_XM_TXEN_WIDTH 1
+#define FRF_AB_XM_TX_RST_LBN 0
+#define FRF_AB_XM_TX_RST_WIDTH 1
+
+/* XM_RX_CFG_REG: XGMAC receive configuration */
+#define FR_AB_XM_RX_CFG 0x00001240
+#define FRF_AB_XM_PASS_LENERR_LBN 26
+#define FRF_AB_XM_PASS_LENERR_WIDTH 1
+#define FRF_AB_XM_PASS_CRC_ERR_LBN 25
+#define FRF_AB_XM_PASS_CRC_ERR_WIDTH 1
+#define FRF_AB_XM_PASS_PRMBLE_ERR_LBN 24
+#define FRF_AB_XM_PASS_PRMBLE_ERR_WIDTH 1
+#define FRF_AB_XM_REJ_BCAST_LBN 20
+#define FRF_AB_XM_REJ_BCAST_WIDTH 1
+#define FRF_AB_XM_ACPT_ALL_MCAST_LBN 11
+#define FRF_AB_XM_ACPT_ALL_MCAST_WIDTH 1
+#define FRF_AB_XM_ACPT_ALL_UCAST_LBN 9
+#define FRF_AB_XM_ACPT_ALL_UCAST_WIDTH 1
+#define FRF_AB_XM_AUTO_DEPAD_LBN 8
+#define FRF_AB_XM_AUTO_DEPAD_WIDTH 1
+#define FRF_AB_XM_RXCRC_LBN 3
+#define FRF_AB_XM_RXCRC_WIDTH 1
+#define FRF_AB_XM_RX_PRMBL_LBN 2
+#define FRF_AB_XM_RX_PRMBL_WIDTH 1
+#define FRF_AB_XM_RXEN_LBN 1
+#define FRF_AB_XM_RXEN_WIDTH 1
+#define FRF_AB_XM_RX_RST_LBN 0
+#define FRF_AB_XM_RX_RST_WIDTH 1
+
+/* XM_MGT_INT_MASK: documentation to be written for sum_XM_MGT_INT_MASK */
+#define FR_AB_XM_MGT_INT_MASK 0x00001250
+#define FRF_AB_XM_MSK_STA_INTR_LBN 16
+#define FRF_AB_XM_MSK_STA_INTR_WIDTH 1
+#define FRF_AB_XM_MSK_STAT_CNTR_HF_LBN 9
+#define FRF_AB_XM_MSK_STAT_CNTR_HF_WIDTH 1
+#define FRF_AB_XM_MSK_STAT_CNTR_OF_LBN 8
+#define FRF_AB_XM_MSK_STAT_CNTR_OF_WIDTH 1
+#define FRF_AB_XM_MSK_PRMBLE_ERR_LBN 2
+#define FRF_AB_XM_MSK_PRMBLE_ERR_WIDTH 1
+#define FRF_AB_XM_MSK_RMTFLT_LBN 1
+#define FRF_AB_XM_MSK_RMTFLT_WIDTH 1
+#define FRF_AB_XM_MSK_LCLFLT_LBN 0
+#define FRF_AB_XM_MSK_LCLFLT_WIDTH 1
+
+/* XM_FC_REG: XGMAC flow control register */
+#define FR_AB_XM_FC 0x00001270
+#define FRF_AB_XM_PAUSE_TIME_LBN 16
+#define FRF_AB_XM_PAUSE_TIME_WIDTH 16
+#define FRF_AB_XM_RX_MAC_STAT_LBN 11
+#define FRF_AB_XM_RX_MAC_STAT_WIDTH 1
+#define FRF_AB_XM_TX_MAC_STAT_LBN 10
+#define FRF_AB_XM_TX_MAC_STAT_WIDTH 1
+#define FRF_AB_XM_MCNTL_PASS_LBN 8
+#define FRF_AB_XM_MCNTL_PASS_WIDTH 2
+#define FRF_AB_XM_REJ_CNTL_UCAST_LBN 6
+#define FRF_AB_XM_REJ_CNTL_UCAST_WIDTH 1
+#define FRF_AB_XM_REJ_CNTL_MCAST_LBN 5
+#define FRF_AB_XM_REJ_CNTL_MCAST_WIDTH 1
+#define FRF_AB_XM_ZPAUSE_LBN 2
+#define FRF_AB_XM_ZPAUSE_WIDTH 1
+#define FRF_AB_XM_XMIT_PAUSE_LBN 1
+#define FRF_AB_XM_XMIT_PAUSE_WIDTH 1
+#define FRF_AB_XM_DIS_FCNTL_LBN 0
+#define FRF_AB_XM_DIS_FCNTL_WIDTH 1
+
+/* XM_PAUSE_TIME_REG: XGMAC pause time register */
+#define FR_AB_XM_PAUSE_TIME 0x00001290
+#define FRF_AB_XM_TX_PAUSE_CNT_LBN 16
+#define FRF_AB_XM_TX_PAUSE_CNT_WIDTH 16
+#define FRF_AB_XM_RX_PAUSE_CNT_LBN 0
+#define FRF_AB_XM_RX_PAUSE_CNT_WIDTH 16
+
+/* XM_TX_PARAM_REG: XGMAC transmit parameter register */
+#define FR_AB_XM_TX_PARAM 0x000012d0
+#define FRF_AB_XM_TX_JUMBO_MODE_LBN 31
+#define FRF_AB_XM_TX_JUMBO_MODE_WIDTH 1
+#define FRF_AB_XM_MAX_TX_FRM_SIZE_HI_LBN 19
+#define FRF_AB_XM_MAX_TX_FRM_SIZE_HI_WIDTH 11
+#define FRF_AB_XM_MAX_TX_FRM_SIZE_LO_LBN 16
+#define FRF_AB_XM_MAX_TX_FRM_SIZE_LO_WIDTH 3
+#define FRF_AB_XM_PAD_CHAR_LBN 0
+#define FRF_AB_XM_PAD_CHAR_WIDTH 8
+
+/* XM_RX_PARAM_REG: XGMAC receive parameter register */
+#define FR_AB_XM_RX_PARAM 0x000012e0
+#define FRF_AB_XM_MAX_RX_FRM_SIZE_HI_LBN 3
+#define FRF_AB_XM_MAX_RX_FRM_SIZE_HI_WIDTH 11
+#define FRF_AB_XM_MAX_RX_FRM_SIZE_LO_LBN 0
+#define FRF_AB_XM_MAX_RX_FRM_SIZE_LO_WIDTH 3
+
+/* XM_MGT_INT_MSK_REG: XGMAC management interrupt mask register */
+#define FR_AB_XM_MGT_INT_MSK 0x000012f0
+#define FRF_AB_XM_STAT_CNTR_OF_LBN 9
+#define FRF_AB_XM_STAT_CNTR_OF_WIDTH 1
+#define FRF_AB_XM_STAT_CNTR_HF_LBN 8
+#define FRF_AB_XM_STAT_CNTR_HF_WIDTH 1
+#define FRF_AB_XM_PRMBLE_ERR_LBN 2
+#define FRF_AB_XM_PRMBLE_ERR_WIDTH 1
+#define FRF_AB_XM_RMTFLT_LBN 1
+#define FRF_AB_XM_RMTFLT_WIDTH 1
+#define FRF_AB_XM_LCLFLT_LBN 0
+#define FRF_AB_XM_LCLFLT_WIDTH 1
+
+/* XX_PWR_RST_REG: XGXS/XAUI powerdown/reset register */
+#define FR_AB_XX_PWR_RST 0x00001300
+#define FRF_AB_XX_PWRDND_SIG_LBN 31
+#define FRF_AB_XX_PWRDND_SIG_WIDTH 1
+#define FRF_AB_XX_PWRDNC_SIG_LBN 30
+#define FRF_AB_XX_PWRDNC_SIG_WIDTH 1
+#define FRF_AB_XX_PWRDNB_SIG_LBN 29
+#define FRF_AB_XX_PWRDNB_SIG_WIDTH 1
+#define FRF_AB_XX_PWRDNA_SIG_LBN 28
+#define FRF_AB_XX_PWRDNA_SIG_WIDTH 1
+#define FRF_AB_XX_SIM_MODE_LBN 27
+#define FRF_AB_XX_SIM_MODE_WIDTH 1
+#define FRF_AB_XX_RSTPLLCD_SIG_LBN 25
+#define FRF_AB_XX_RSTPLLCD_SIG_WIDTH 1
+#define FRF_AB_XX_RSTPLLAB_SIG_LBN 24
+#define FRF_AB_XX_RSTPLLAB_SIG_WIDTH 1
+#define FRF_AB_XX_RESETD_SIG_LBN 23
+#define FRF_AB_XX_RESETD_SIG_WIDTH 1
+#define FRF_AB_XX_RESETC_SIG_LBN 22
+#define FRF_AB_XX_RESETC_SIG_WIDTH 1
+#define FRF_AB_XX_RESETB_SIG_LBN 21
+#define FRF_AB_XX_RESETB_SIG_WIDTH 1
+#define FRF_AB_XX_RESETA_SIG_LBN 20
+#define FRF_AB_XX_RESETA_SIG_WIDTH 1
+#define FRF_AB_XX_RSTXGXSRX_SIG_LBN 18
+#define FRF_AB_XX_RSTXGXSRX_SIG_WIDTH 1
+#define FRF_AB_XX_RSTXGXSTX_SIG_LBN 17
+#define FRF_AB_XX_RSTXGXSTX_SIG_WIDTH 1
+#define FRF_AB_XX_SD_RST_ACT_LBN 16
+#define FRF_AB_XX_SD_RST_ACT_WIDTH 1
+#define FRF_AB_XX_PWRDND_EN_LBN 15
+#define FRF_AB_XX_PWRDND_EN_WIDTH 1
+#define FRF_AB_XX_PWRDNC_EN_LBN 14
+#define FRF_AB_XX_PWRDNC_EN_WIDTH 1
+#define FRF_AB_XX_PWRDNB_EN_LBN 13
+#define FRF_AB_XX_PWRDNB_EN_WIDTH 1
+#define FRF_AB_XX_PWRDNA_EN_LBN 12
+#define FRF_AB_XX_PWRDNA_EN_WIDTH 1
+#define FRF_AB_XX_RSTPLLCD_EN_LBN 9
+#define FRF_AB_XX_RSTPLLCD_EN_WIDTH 1
+#define FRF_AB_XX_RSTPLLAB_EN_LBN 8
+#define FRF_AB_XX_RSTPLLAB_EN_WIDTH 1
+#define FRF_AB_XX_RESETD_EN_LBN 7
+#define FRF_AB_XX_RESETD_EN_WIDTH 1
+#define FRF_AB_XX_RESETC_EN_LBN 6
+#define FRF_AB_XX_RESETC_EN_WIDTH 1
+#define FRF_AB_XX_RESETB_EN_LBN 5
+#define FRF_AB_XX_RESETB_EN_WIDTH 1
+#define FRF_AB_XX_RESETA_EN_LBN 4
+#define FRF_AB_XX_RESETA_EN_WIDTH 1
+#define FRF_AB_XX_RSTXGXSRX_EN_LBN 2
+#define FRF_AB_XX_RSTXGXSRX_EN_WIDTH 1
+#define FRF_AB_XX_RSTXGXSTX_EN_LBN 1
+#define FRF_AB_XX_RSTXGXSTX_EN_WIDTH 1
+#define FRF_AB_XX_RST_XX_EN_LBN 0
+#define FRF_AB_XX_RST_XX_EN_WIDTH 1
+
+/* XX_SD_CTL_REG: XGXS/XAUI powerdown/reset control register */
+#define FR_AB_XX_SD_CTL 0x00001310
+#define FRF_AB_XX_TERMADJ1_LBN 17
+#define FRF_AB_XX_TERMADJ1_WIDTH 1
+#define FRF_AB_XX_TERMADJ0_LBN 16
+#define FRF_AB_XX_TERMADJ0_WIDTH 1
+#define FRF_AB_XX_HIDRVD_LBN 15
+#define FRF_AB_XX_HIDRVD_WIDTH 1
+#define FRF_AB_XX_LODRVD_LBN 14
+#define FRF_AB_XX_LODRVD_WIDTH 1
+#define FRF_AB_XX_HIDRVC_LBN 13
+#define FRF_AB_XX_HIDRVC_WIDTH 1
+#define FRF_AB_XX_LODRVC_LBN 12
+#define FRF_AB_XX_LODRVC_WIDTH 1
+#define FRF_AB_XX_HIDRVB_LBN 11
+#define FRF_AB_XX_HIDRVB_WIDTH 1
+#define FRF_AB_XX_LODRVB_LBN 10
+#define FRF_AB_XX_LODRVB_WIDTH 1
+#define FRF_AB_XX_HIDRVA_LBN 9
+#define FRF_AB_XX_HIDRVA_WIDTH 1
+#define FRF_AB_XX_LODRVA_LBN 8
+#define FRF_AB_XX_LODRVA_WIDTH 1
+#define FRF_AB_XX_LPBKD_LBN 3
+#define FRF_AB_XX_LPBKD_WIDTH 1
+#define FRF_AB_XX_LPBKC_LBN 2
+#define FRF_AB_XX_LPBKC_WIDTH 1
+#define FRF_AB_XX_LPBKB_LBN 1
+#define FRF_AB_XX_LPBKB_WIDTH 1
+#define FRF_AB_XX_LPBKA_LBN 0
+#define FRF_AB_XX_LPBKA_WIDTH 1
+
+/* XX_TXDRV_CTL_REG: XAUI SerDes transmit drive control register */
+#define FR_AB_XX_TXDRV_CTL 0x00001320
+#define FRF_AB_XX_DEQD_LBN 28
+#define FRF_AB_XX_DEQD_WIDTH 4
+#define FRF_AB_XX_DEQC_LBN 24
+#define FRF_AB_XX_DEQC_WIDTH 4
+#define FRF_AB_XX_DEQB_LBN 20
+#define FRF_AB_XX_DEQB_WIDTH 4
+#define FRF_AB_XX_DEQA_LBN 16
+#define FRF_AB_XX_DEQA_WIDTH 4
+#define FRF_AB_XX_DTXD_LBN 12
+#define FRF_AB_XX_DTXD_WIDTH 4
+#define FRF_AB_XX_DTXC_LBN 8
+#define FRF_AB_XX_DTXC_WIDTH 4
+#define FRF_AB_XX_DTXB_LBN 4
+#define FRF_AB_XX_DTXB_WIDTH 4
+#define FRF_AB_XX_DTXA_LBN 0
+#define FRF_AB_XX_DTXA_WIDTH 4
+
+/* XX_PRBS_CTL_REG: documentation to be written for sum_XX_PRBS_CTL_REG */
+#define FR_AB_XX_PRBS_CTL 0x00001330
+#define FRF_AB_XX_CH3_RX_PRBS_SEL_LBN 30
+#define FRF_AB_XX_CH3_RX_PRBS_SEL_WIDTH 2
+#define FRF_AB_XX_CH3_RX_PRBS_INV_LBN 29
+#define FRF_AB_XX_CH3_RX_PRBS_INV_WIDTH 1
+#define FRF_AB_XX_CH3_RX_PRBS_CHKEN_LBN 28
+#define FRF_AB_XX_CH3_RX_PRBS_CHKEN_WIDTH 1
+#define FRF_AB_XX_CH2_RX_PRBS_SEL_LBN 26
+#define FRF_AB_XX_CH2_RX_PRBS_SEL_WIDTH 2
+#define FRF_AB_XX_CH2_RX_PRBS_INV_LBN 25
+#define FRF_AB_XX_CH2_RX_PRBS_INV_WIDTH 1
+#define FRF_AB_XX_CH2_RX_PRBS_CHKEN_LBN 24
+#define FRF_AB_XX_CH2_RX_PRBS_CHKEN_WIDTH 1
+#define FRF_AB_XX_CH1_RX_PRBS_SEL_LBN 22
+#define FRF_AB_XX_CH1_RX_PRBS_SEL_WIDTH 2
+#define FRF_AB_XX_CH1_RX_PRBS_INV_LBN 21
+#define FRF_AB_XX_CH1_RX_PRBS_INV_WIDTH 1
+#define FRF_AB_XX_CH1_RX_PRBS_CHKEN_LBN 20
+#define FRF_AB_XX_CH1_RX_PRBS_CHKEN_WIDTH 1
+#define FRF_AB_XX_CH0_RX_PRBS_SEL_LBN 18
+#define FRF_AB_XX_CH0_RX_PRBS_SEL_WIDTH 2
+#define FRF_AB_XX_CH0_RX_PRBS_INV_LBN 17
+#define FRF_AB_XX_CH0_RX_PRBS_INV_WIDTH 1
+#define FRF_AB_XX_CH0_RX_PRBS_CHKEN_LBN 16
+#define FRF_AB_XX_CH0_RX_PRBS_CHKEN_WIDTH 1
+#define FRF_AB_XX_CH3_TX_PRBS_SEL_LBN 14
+#define FRF_AB_XX_CH3_TX_PRBS_SEL_WIDTH 2
+#define FRF_AB_XX_CH3_TX_PRBS_INV_LBN 13
+#define FRF_AB_XX_CH3_TX_PRBS_INV_WIDTH 1
+#define FRF_AB_XX_CH3_TX_PRBS_CHKEN_LBN 12
+#define FRF_AB_XX_CH3_TX_PRBS_CHKEN_WIDTH 1
+#define FRF_AB_XX_CH2_TX_PRBS_SEL_LBN 10
+#define FRF_AB_XX_CH2_TX_PRBS_SEL_WIDTH 2
+#define FRF_AB_XX_CH2_TX_PRBS_INV_LBN 9
+#define FRF_AB_XX_CH2_TX_PRBS_INV_WIDTH 1
+#define FRF_AB_XX_CH2_TX_PRBS_CHKEN_LBN 8
+#define FRF_AB_XX_CH2_TX_PRBS_CHKEN_WIDTH 1
+#define FRF_AB_XX_CH1_TX_PRBS_SEL_LBN 6
+#define FRF_AB_XX_CH1_TX_PRBS_SEL_WIDTH 2
+#define FRF_AB_XX_CH1_TX_PRBS_INV_LBN 5
+#define FRF_AB_XX_CH1_TX_PRBS_INV_WIDTH 1
+#define FRF_AB_XX_CH1_TX_PRBS_CHKEN_LBN 4
+#define FRF_AB_XX_CH1_TX_PRBS_CHKEN_WIDTH 1
+#define FRF_AB_XX_CH0_TX_PRBS_SEL_LBN 2
+#define FRF_AB_XX_CH0_TX_PRBS_SEL_WIDTH 2
+#define FRF_AB_XX_CH0_TX_PRBS_INV_LBN 1
+#define FRF_AB_XX_CH0_TX_PRBS_INV_WIDTH 1
+#define FRF_AB_XX_CH0_TX_PRBS_CHKEN_LBN 0
+#define FRF_AB_XX_CH0_TX_PRBS_CHKEN_WIDTH 1
+
+/* XX_PRBS_CHK_REG: documentation to be written for sum_XX_PRBS_CHK_REG */
+#define FR_AB_XX_PRBS_CHK 0x00001340
+#define FRF_AB_XX_REV_LB_EN_LBN 16
+#define FRF_AB_XX_REV_LB_EN_WIDTH 1
+#define FRF_AB_XX_CH3_DEG_DET_LBN 15
+#define FRF_AB_XX_CH3_DEG_DET_WIDTH 1
+#define FRF_AB_XX_CH3_LFSR_LOCK_IND_LBN 14
+#define FRF_AB_XX_CH3_LFSR_LOCK_IND_WIDTH 1
+#define FRF_AB_XX_CH3_PRBS_FRUN_LBN 13
+#define FRF_AB_XX_CH3_PRBS_FRUN_WIDTH 1
+#define FRF_AB_XX_CH3_ERR_CHK_LBN 12
+#define FRF_AB_XX_CH3_ERR_CHK_WIDTH 1
+#define FRF_AB_XX_CH2_DEG_DET_LBN 11
+#define FRF_AB_XX_CH2_DEG_DET_WIDTH 1
+#define FRF_AB_XX_CH2_LFSR_LOCK_IND_LBN 10
+#define FRF_AB_XX_CH2_LFSR_LOCK_IND_WIDTH 1
+#define FRF_AB_XX_CH2_PRBS_FRUN_LBN 9
+#define FRF_AB_XX_CH2_PRBS_FRUN_WIDTH 1
+#define FRF_AB_XX_CH2_ERR_CHK_LBN 8
+#define FRF_AB_XX_CH2_ERR_CHK_WIDTH 1
+#define FRF_AB_XX_CH1_DEG_DET_LBN 7
+#define FRF_AB_XX_CH1_DEG_DET_WIDTH 1
+#define FRF_AB_XX_CH1_LFSR_LOCK_IND_LBN 6
+#define FRF_AB_XX_CH1_LFSR_LOCK_IND_WIDTH 1
+#define FRF_AB_XX_CH1_PRBS_FRUN_LBN 5
+#define FRF_AB_XX_CH1_PRBS_FRUN_WIDTH 1
+#define FRF_AB_XX_CH1_ERR_CHK_LBN 4
+#define FRF_AB_XX_CH1_ERR_CHK_WIDTH 1
+#define FRF_AB_XX_CH0_DEG_DET_LBN 3
+#define FRF_AB_XX_CH0_DEG_DET_WIDTH 1
+#define FRF_AB_XX_CH0_LFSR_LOCK_IND_LBN 2
+#define FRF_AB_XX_CH0_LFSR_LOCK_IND_WIDTH 1
+#define FRF_AB_XX_CH0_PRBS_FRUN_LBN 1
+#define FRF_AB_XX_CH0_PRBS_FRUN_WIDTH 1
+#define FRF_AB_XX_CH0_ERR_CHK_LBN 0
+#define FRF_AB_XX_CH0_ERR_CHK_WIDTH 1
+
+/* XX_PRBS_ERR_REG: documentation to be written for sum_XX_PRBS_ERR_REG */
+#define FR_AB_XX_PRBS_ERR 0x00001350
+#define FRF_AB_XX_CH3_PRBS_ERR_CNT_LBN 24
+#define FRF_AB_XX_CH3_PRBS_ERR_CNT_WIDTH 8
+#define FRF_AB_XX_CH2_PRBS_ERR_CNT_LBN 16
+#define FRF_AB_XX_CH2_PRBS_ERR_CNT_WIDTH 8
+#define FRF_AB_XX_CH1_PRBS_ERR_CNT_LBN 8
+#define FRF_AB_XX_CH1_PRBS_ERR_CNT_WIDTH 8
+#define FRF_AB_XX_CH0_PRBS_ERR_CNT_LBN 0
+#define FRF_AB_XX_CH0_PRBS_ERR_CNT_WIDTH 8
+
+/* XX_CORE_STAT_REG: XAUI XGXS core status register */
+#define FR_AB_XX_CORE_STAT 0x00001360
+#define FRF_AB_XX_FORCE_SIG3_LBN 31
+#define FRF_AB_XX_FORCE_SIG3_WIDTH 1
+#define FRF_AB_XX_FORCE_SIG3_VAL_LBN 30
+#define FRF_AB_XX_FORCE_SIG3_VAL_WIDTH 1
+#define FRF_AB_XX_FORCE_SIG2_LBN 29
+#define FRF_AB_XX_FORCE_SIG2_WIDTH 1
+#define FRF_AB_XX_FORCE_SIG2_VAL_LBN 28
+#define FRF_AB_XX_FORCE_SIG2_VAL_WIDTH 1
+#define FRF_AB_XX_FORCE_SIG1_LBN 27
+#define FRF_AB_XX_FORCE_SIG1_WIDTH 1
+#define FRF_AB_XX_FORCE_SIG1_VAL_LBN 26
+#define FRF_AB_XX_FORCE_SIG1_VAL_WIDTH 1
+#define FRF_AB_XX_FORCE_SIG0_LBN 25
+#define FRF_AB_XX_FORCE_SIG0_WIDTH 1
+#define FRF_AB_XX_FORCE_SIG0_VAL_LBN 24
+#define FRF_AB_XX_FORCE_SIG0_VAL_WIDTH 1
+#define FRF_AB_XX_XGXS_LB_EN_LBN 23
+#define FRF_AB_XX_XGXS_LB_EN_WIDTH 1
+#define FRF_AB_XX_XGMII_LB_EN_LBN 22
+#define FRF_AB_XX_XGMII_LB_EN_WIDTH 1
+#define FRF_AB_XX_MATCH_FAULT_LBN 21
+#define FRF_AB_XX_MATCH_FAULT_WIDTH 1
+#define FRF_AB_XX_ALIGN_DONE_LBN 20
+#define FRF_AB_XX_ALIGN_DONE_WIDTH 1
+#define FRF_AB_XX_SYNC_STAT3_LBN 19
+#define FRF_AB_XX_SYNC_STAT3_WIDTH 1
+#define FRF_AB_XX_SYNC_STAT2_LBN 18
+#define FRF_AB_XX_SYNC_STAT2_WIDTH 1
+#define FRF_AB_XX_SYNC_STAT1_LBN 17
+#define FRF_AB_XX_SYNC_STAT1_WIDTH 1
+#define FRF_AB_XX_SYNC_STAT0_LBN 16
+#define FRF_AB_XX_SYNC_STAT0_WIDTH 1
+#define FRF_AB_XX_COMMA_DET_CH3_LBN 15
+#define FRF_AB_XX_COMMA_DET_CH3_WIDTH 1
+#define FRF_AB_XX_COMMA_DET_CH2_LBN 14
+#define FRF_AB_XX_COMMA_DET_CH2_WIDTH 1
+#define FRF_AB_XX_COMMA_DET_CH1_LBN 13
+#define FRF_AB_XX_COMMA_DET_CH1_WIDTH 1
+#define FRF_AB_XX_COMMA_DET_CH0_LBN 12
+#define FRF_AB_XX_COMMA_DET_CH0_WIDTH 1
+#define FRF_AB_XX_CGRP_ALIGN_CH3_LBN 11
+#define FRF_AB_XX_CGRP_ALIGN_CH3_WIDTH 1
+#define FRF_AB_XX_CGRP_ALIGN_CH2_LBN 10
+#define FRF_AB_XX_CGRP_ALIGN_CH2_WIDTH 1
+#define FRF_AB_XX_CGRP_ALIGN_CH1_LBN 9
+#define FRF_AB_XX_CGRP_ALIGN_CH1_WIDTH 1
+#define FRF_AB_XX_CGRP_ALIGN_CH0_LBN 8
+#define FRF_AB_XX_CGRP_ALIGN_CH0_WIDTH 1
+#define FRF_AB_XX_CHAR_ERR_CH3_LBN 7
+#define FRF_AB_XX_CHAR_ERR_CH3_WIDTH 1
+#define FRF_AB_XX_CHAR_ERR_CH2_LBN 6
+#define FRF_AB_XX_CHAR_ERR_CH2_WIDTH 1
+#define FRF_AB_XX_CHAR_ERR_CH1_LBN 5
+#define FRF_AB_XX_CHAR_ERR_CH1_WIDTH 1
+#define FRF_AB_XX_CHAR_ERR_CH0_LBN 4
+#define FRF_AB_XX_CHAR_ERR_CH0_WIDTH 1
+#define FRF_AB_XX_DISPERR_CH3_LBN 3
+#define FRF_AB_XX_DISPERR_CH3_WIDTH 1
+#define FRF_AB_XX_DISPERR_CH2_LBN 2
+#define FRF_AB_XX_DISPERR_CH2_WIDTH 1
+#define FRF_AB_XX_DISPERR_CH1_LBN 1
+#define FRF_AB_XX_DISPERR_CH1_WIDTH 1
+#define FRF_AB_XX_DISPERR_CH0_LBN 0
+#define FRF_AB_XX_DISPERR_CH0_WIDTH 1
+
+/* RX_DESC_PTR_TBL_KER: Receive descriptor pointer table */
+#define FR_AA_RX_DESC_PTR_TBL_KER 0x00011800
+#define FR_AA_RX_DESC_PTR_TBL_KER_STEP 16
+#define FR_AA_RX_DESC_PTR_TBL_KER_ROWS 4
+/* RX_DESC_PTR_TBL: Receive descriptor pointer table */
+#define FR_BZ_RX_DESC_PTR_TBL 0x00f40000
+#define FR_BZ_RX_DESC_PTR_TBL_STEP 16
+#define FR_BB_RX_DESC_PTR_TBL_ROWS 4096
+#define FR_CZ_RX_DESC_PTR_TBL_ROWS 1024
+#define FRF_CZ_RX_HDR_SPLIT_LBN 90
+#define FRF_CZ_RX_HDR_SPLIT_WIDTH 1
+#define FRF_AA_RX_RESET_LBN 89
+#define FRF_AA_RX_RESET_WIDTH 1
+#define FRF_AZ_RX_ISCSI_DDIG_EN_LBN 88
+#define FRF_AZ_RX_ISCSI_DDIG_EN_WIDTH 1
+#define FRF_AZ_RX_ISCSI_HDIG_EN_LBN 87
+#define FRF_AZ_RX_ISCSI_HDIG_EN_WIDTH 1
+#define FRF_AZ_RX_DESC_PREF_ACT_LBN 86
+#define FRF_AZ_RX_DESC_PREF_ACT_WIDTH 1
+#define FRF_AZ_RX_DC_HW_RPTR_LBN 80
+#define FRF_AZ_RX_DC_HW_RPTR_WIDTH 6
+#define FRF_AZ_RX_DESCQ_HW_RPTR_LBN 68
+#define FRF_AZ_RX_DESCQ_HW_RPTR_WIDTH 12
+#define FRF_AZ_RX_DESCQ_SW_WPTR_LBN 56
+#define FRF_AZ_RX_DESCQ_SW_WPTR_WIDTH 12
+#define FRF_AZ_RX_DESCQ_BUF_BASE_ID_LBN 36
+#define FRF_AZ_RX_DESCQ_BUF_BASE_ID_WIDTH 20
+#define FRF_AZ_RX_DESCQ_EVQ_ID_LBN 24
+#define FRF_AZ_RX_DESCQ_EVQ_ID_WIDTH 12
+#define FRF_AZ_RX_DESCQ_OWNER_ID_LBN 10
+#define FRF_AZ_RX_DESCQ_OWNER_ID_WIDTH 14
+#define FRF_AZ_RX_DESCQ_LABEL_LBN 5
+#define FRF_AZ_RX_DESCQ_LABEL_WIDTH 5
+#define FRF_AZ_RX_DESCQ_SIZE_LBN 3
+#define FRF_AZ_RX_DESCQ_SIZE_WIDTH 2
+#define FFE_AZ_RX_DESCQ_SIZE_4K 3
+#define FFE_AZ_RX_DESCQ_SIZE_2K 2
+#define FFE_AZ_RX_DESCQ_SIZE_1K 1
+#define FFE_AZ_RX_DESCQ_SIZE_512 0
+#define FRF_AZ_RX_DESCQ_TYPE_LBN 2
+#define FRF_AZ_RX_DESCQ_TYPE_WIDTH 1
+#define FRF_AZ_RX_DESCQ_JUMBO_LBN 1
+#define FRF_AZ_RX_DESCQ_JUMBO_WIDTH 1
+#define FRF_AZ_RX_DESCQ_EN_LBN 0
+#define FRF_AZ_RX_DESCQ_EN_WIDTH 1
+
+/* TX_DESC_PTR_TBL_KER: Transmit descriptor pointer */
+#define FR_AA_TX_DESC_PTR_TBL_KER 0x00011900
+#define FR_AA_TX_DESC_PTR_TBL_KER_STEP 16
+#define FR_AA_TX_DESC_PTR_TBL_KER_ROWS 8
+/* TX_DESC_PTR_TBL: Transmit descriptor pointer */
+#define FR_BZ_TX_DESC_PTR_TBL 0x00f50000
+#define FR_BZ_TX_DESC_PTR_TBL_STEP 16
+#define FR_BB_TX_DESC_PTR_TBL_ROWS 4096
+#define FR_CZ_TX_DESC_PTR_TBL_ROWS 1024
+#define FRF_CZ_TX_DPT_Q_MASK_WIDTH_LBN 94
+#define FRF_CZ_TX_DPT_Q_MASK_WIDTH_WIDTH 2
+#define FRF_CZ_TX_DPT_ETH_FILT_EN_LBN 93
+#define FRF_CZ_TX_DPT_ETH_FILT_EN_WIDTH 1
+#define FRF_CZ_TX_DPT_IP_FILT_EN_LBN 92
+#define FRF_CZ_TX_DPT_IP_FILT_EN_WIDTH 1
+#define FRF_BZ_TX_NON_IP_DROP_DIS_LBN 91
+#define FRF_BZ_TX_NON_IP_DROP_DIS_WIDTH 1
+#define FRF_BZ_TX_IP_CHKSM_DIS_LBN 90
+#define FRF_BZ_TX_IP_CHKSM_DIS_WIDTH 1
+#define FRF_BZ_TX_TCP_CHKSM_DIS_LBN 89
+#define FRF_BZ_TX_TCP_CHKSM_DIS_WIDTH 1
+#define FRF_AZ_TX_DESCQ_EN_LBN 88
+#define FRF_AZ_TX_DESCQ_EN_WIDTH 1
+#define FRF_AZ_TX_ISCSI_DDIG_EN_LBN 87
+#define FRF_AZ_TX_ISCSI_DDIG_EN_WIDTH 1
+#define FRF_AZ_TX_ISCSI_HDIG_EN_LBN 86
+#define FRF_AZ_TX_ISCSI_HDIG_EN_WIDTH 1
+#define FRF_AZ_TX_DC_HW_RPTR_LBN 80
+#define FRF_AZ_TX_DC_HW_RPTR_WIDTH 6
+#define FRF_AZ_TX_DESCQ_HW_RPTR_LBN 68
+#define FRF_AZ_TX_DESCQ_HW_RPTR_WIDTH 12
+#define FRF_AZ_TX_DESCQ_SW_WPTR_LBN 56
+#define FRF_AZ_TX_DESCQ_SW_WPTR_WIDTH 12
+#define FRF_AZ_TX_DESCQ_BUF_BASE_ID_LBN 36
+#define FRF_AZ_TX_DESCQ_BUF_BASE_ID_WIDTH 20
+#define FRF_AZ_TX_DESCQ_EVQ_ID_LBN 24
+#define FRF_AZ_TX_DESCQ_EVQ_ID_WIDTH 12
+#define FRF_AZ_TX_DESCQ_OWNER_ID_LBN 10
+#define FRF_AZ_TX_DESCQ_OWNER_ID_WIDTH 14
+#define FRF_AZ_TX_DESCQ_LABEL_LBN 5
+#define FRF_AZ_TX_DESCQ_LABEL_WIDTH 5
+#define FRF_AZ_TX_DESCQ_SIZE_LBN 3
+#define FRF_AZ_TX_DESCQ_SIZE_WIDTH 2
+#define FFE_AZ_TX_DESCQ_SIZE_4K 3
+#define FFE_AZ_TX_DESCQ_SIZE_2K 2
+#define FFE_AZ_TX_DESCQ_SIZE_1K 1
+#define FFE_AZ_TX_DESCQ_SIZE_512 0
+#define FRF_AZ_TX_DESCQ_TYPE_LBN 1
+#define FRF_AZ_TX_DESCQ_TYPE_WIDTH 2
+#define FRF_AZ_TX_DESCQ_FLUSH_LBN 0
+#define FRF_AZ_TX_DESCQ_FLUSH_WIDTH 1
+
+/* EVQ_PTR_TBL_KER: Event queue pointer table */
+#define FR_AA_EVQ_PTR_TBL_KER 0x00011a00
+#define FR_AA_EVQ_PTR_TBL_KER_STEP 16
+#define FR_AA_EVQ_PTR_TBL_KER_ROWS 4
+/* EVQ_PTR_TBL: Event queue pointer table */
+#define FR_BZ_EVQ_PTR_TBL 0x00f60000
+#define FR_BZ_EVQ_PTR_TBL_STEP 16
+#define FR_CZ_EVQ_PTR_TBL_ROWS 1024
+#define FR_BB_EVQ_PTR_TBL_ROWS 4096
+#define FRF_BZ_EVQ_RPTR_IGN_LBN 40
+#define FRF_BZ_EVQ_RPTR_IGN_WIDTH 1
+#define FRF_AB_EVQ_WKUP_OR_INT_EN_LBN 39
+#define FRF_AB_EVQ_WKUP_OR_INT_EN_WIDTH 1
+#define FRF_CZ_EVQ_DOS_PROTECT_EN_LBN 39
+#define FRF_CZ_EVQ_DOS_PROTECT_EN_WIDTH 1
+#define FRF_AZ_EVQ_NXT_WPTR_LBN 24
+#define FRF_AZ_EVQ_NXT_WPTR_WIDTH 15
+#define FRF_AZ_EVQ_EN_LBN 23
+#define FRF_AZ_EVQ_EN_WIDTH 1
+#define FRF_AZ_EVQ_SIZE_LBN 20
+#define FRF_AZ_EVQ_SIZE_WIDTH 3
+#define FFE_AZ_EVQ_SIZE_32K 6
+#define FFE_AZ_EVQ_SIZE_16K 5
+#define FFE_AZ_EVQ_SIZE_8K 4
+#define FFE_AZ_EVQ_SIZE_4K 3
+#define FFE_AZ_EVQ_SIZE_2K 2
+#define FFE_AZ_EVQ_SIZE_1K 1
+#define FFE_AZ_EVQ_SIZE_512 0
+#define FRF_AZ_EVQ_BUF_BASE_ID_LBN 0
+#define FRF_AZ_EVQ_BUF_BASE_ID_WIDTH 20
+
+/* BUF_HALF_TBL_KER: Buffer table in half buffer table mode direct access by driver */
+#define FR_AA_BUF_HALF_TBL_KER 0x00018000
+#define FR_AA_BUF_HALF_TBL_KER_STEP 8
+#define FR_AA_BUF_HALF_TBL_KER_ROWS 4096
+/* BUF_HALF_TBL: Buffer table in half buffer table mode direct access by driver */
+#define FR_BZ_BUF_HALF_TBL 0x00800000
+#define FR_BZ_BUF_HALF_TBL_STEP 8
+#define FR_CZ_BUF_HALF_TBL_ROWS 147456
+#define FR_BB_BUF_HALF_TBL_ROWS 524288
+#define FRF_AZ_BUF_ADR_HBUF_ODD_LBN 44
+#define FRF_AZ_BUF_ADR_HBUF_ODD_WIDTH 20
+#define FRF_AZ_BUF_OWNER_ID_HBUF_ODD_LBN 32
+#define FRF_AZ_BUF_OWNER_ID_HBUF_ODD_WIDTH 12
+#define FRF_AZ_BUF_ADR_HBUF_EVEN_LBN 12
+#define FRF_AZ_BUF_ADR_HBUF_EVEN_WIDTH 20
+#define FRF_AZ_BUF_OWNER_ID_HBUF_EVEN_LBN 0
+#define FRF_AZ_BUF_OWNER_ID_HBUF_EVEN_WIDTH 12
+
+/* BUF_FULL_TBL_KER: Buffer table in full buffer table mode direct access by driver */
+#define FR_AA_BUF_FULL_TBL_KER 0x00018000
+#define FR_AA_BUF_FULL_TBL_KER_STEP 8
+#define FR_AA_BUF_FULL_TBL_KER_ROWS 4096
+/* BUF_FULL_TBL: Buffer table in full buffer table mode direct access by driver */
+#define FR_BZ_BUF_FULL_TBL 0x00800000
+#define FR_BZ_BUF_FULL_TBL_STEP 8
+#define FR_CZ_BUF_FULL_TBL_ROWS 147456
+#define FR_BB_BUF_FULL_TBL_ROWS 917504
+#define FRF_AZ_BUF_FULL_UNUSED_LBN 51
+#define FRF_AZ_BUF_FULL_UNUSED_WIDTH 13
+#define FRF_AZ_IP_DAT_BUF_SIZE_LBN 50
+#define FRF_AZ_IP_DAT_BUF_SIZE_WIDTH 1
+#define FRF_AZ_BUF_ADR_REGION_LBN 48
+#define FRF_AZ_BUF_ADR_REGION_WIDTH 2
+#define FFE_AZ_BUF_ADR_REGN3 3
+#define FFE_AZ_BUF_ADR_REGN2 2
+#define FFE_AZ_BUF_ADR_REGN1 1
+#define FFE_AZ_BUF_ADR_REGN0 0
+#define FRF_AZ_BUF_ADR_FBUF_LBN 14
+#define FRF_AZ_BUF_ADR_FBUF_WIDTH 34
+#define FRF_AZ_BUF_OWNER_ID_FBUF_LBN 0
+#define FRF_AZ_BUF_OWNER_ID_FBUF_WIDTH 14
+
+/* RX_FILTER_TBL0: TCP/IPv4 Receive filter table */
+#define FR_BZ_RX_FILTER_TBL0 0x00f00000
+#define FR_BZ_RX_FILTER_TBL0_STEP 32
+#define FR_BZ_RX_FILTER_TBL0_ROWS 8192
+/* RX_FILTER_TBL1: TCP/IPv4 Receive filter table */
+#define FR_BB_RX_FILTER_TBL1 0x00f00010
+#define FR_BB_RX_FILTER_TBL1_STEP 32
+#define FR_BB_RX_FILTER_TBL1_ROWS 8192
+#define FRF_BZ_RSS_EN_LBN 110
+#define FRF_BZ_RSS_EN_WIDTH 1
+#define FRF_BZ_SCATTER_EN_LBN 109
+#define FRF_BZ_SCATTER_EN_WIDTH 1
+#define FRF_BZ_TCP_UDP_LBN 108
+#define FRF_BZ_TCP_UDP_WIDTH 1
+#define FRF_BZ_RXQ_ID_LBN 96
+#define FRF_BZ_RXQ_ID_WIDTH 12
+#define FRF_BZ_DEST_IP_LBN 64
+#define FRF_BZ_DEST_IP_WIDTH 32
+#define FRF_BZ_DEST_PORT_TCP_LBN 48
+#define FRF_BZ_DEST_PORT_TCP_WIDTH 16
+#define FRF_BZ_SRC_IP_LBN 16
+#define FRF_BZ_SRC_IP_WIDTH 32
+#define FRF_BZ_SRC_TCP_DEST_UDP_LBN 0
+#define FRF_BZ_SRC_TCP_DEST_UDP_WIDTH 16
+
+/* RX_MAC_FILTER_TBL0: Receive Ethernet filter table */
+#define FR_CZ_RX_MAC_FILTER_TBL0 0x00f00010
+#define FR_CZ_RX_MAC_FILTER_TBL0_STEP 32
+#define FR_CZ_RX_MAC_FILTER_TBL0_ROWS 512
+#define FRF_CZ_RMFT_RSS_EN_LBN 75
+#define FRF_CZ_RMFT_RSS_EN_WIDTH 1
+#define FRF_CZ_RMFT_SCATTER_EN_LBN 74
+#define FRF_CZ_RMFT_SCATTER_EN_WIDTH 1
+#define FRF_CZ_RMFT_IP_OVERRIDE_LBN 73
+#define FRF_CZ_RMFT_IP_OVERRIDE_WIDTH 1
+#define FRF_CZ_RMFT_RXQ_ID_LBN 61
+#define FRF_CZ_RMFT_RXQ_ID_WIDTH 12
+#define FRF_CZ_RMFT_WILDCARD_MATCH_LBN 60
+#define FRF_CZ_RMFT_WILDCARD_MATCH_WIDTH 1
+#define FRF_CZ_RMFT_DEST_MAC_LBN 16
+#define FRF_CZ_RMFT_DEST_MAC_WIDTH 44
+#define FRF_CZ_RMFT_VLAN_ID_LBN 0
+#define FRF_CZ_RMFT_VLAN_ID_WIDTH 12
+
+/* TIMER_TBL: Timer table */
+#define FR_BZ_TIMER_TBL 0x00f70000
+#define FR_BZ_TIMER_TBL_STEP 16
+#define FR_CZ_TIMER_TBL_ROWS 1024
+#define FR_BB_TIMER_TBL_ROWS 4096
+#define FRF_CZ_TIMER_Q_EN_LBN 33
+#define FRF_CZ_TIMER_Q_EN_WIDTH 1
+#define FRF_CZ_INT_ARMD_LBN 32
+#define FRF_CZ_INT_ARMD_WIDTH 1
+#define FRF_CZ_INT_PEND_LBN 31
+#define FRF_CZ_INT_PEND_WIDTH 1
+#define FRF_CZ_HOST_NOTIFY_MODE_LBN 30
+#define FRF_CZ_HOST_NOTIFY_MODE_WIDTH 1
+#define FRF_CZ_RELOAD_TIMER_VAL_LBN 16
+#define FRF_CZ_RELOAD_TIMER_VAL_WIDTH 14
+#define FRF_CZ_TIMER_MODE_LBN 14
+#define FRF_CZ_TIMER_MODE_WIDTH 2
+#define FFE_CZ_TIMER_MODE_INT_HLDOFF 3
+#define FFE_CZ_TIMER_MODE_TRIG_START 2
+#define FFE_CZ_TIMER_MODE_IMMED_START 1
+#define FFE_CZ_TIMER_MODE_DIS 0
+#define FRF_BB_TIMER_MODE_LBN 12
+#define FRF_BB_TIMER_MODE_WIDTH 2
+#define FFE_BB_TIMER_MODE_INT_HLDOFF 2
+#define FFE_BB_TIMER_MODE_TRIG_START 2
+#define FFE_BB_TIMER_MODE_IMMED_START 1
+#define FFE_BB_TIMER_MODE_DIS 0
+#define FRF_CZ_TIMER_VAL_LBN 0
+#define FRF_CZ_TIMER_VAL_WIDTH 14
+#define FRF_BB_TIMER_VAL_LBN 0
+#define FRF_BB_TIMER_VAL_WIDTH 12
+
+/* TX_PACE_TBL: Transmit pacing table */
+#define FR_BZ_TX_PACE_TBL 0x00f80000
+#define FR_BZ_TX_PACE_TBL_STEP 16
+#define FR_CZ_TX_PACE_TBL_ROWS 1024
+#define FR_BB_TX_PACE_TBL_ROWS 4096
+#define FRF_BZ_TX_PACE_LBN 0
+#define FRF_BZ_TX_PACE_WIDTH 5
+
+/* RX_INDIRECTION_TBL: RX Indirection Table */
+#define FR_BZ_RX_INDIRECTION_TBL 0x00fb0000
+#define FR_BZ_RX_INDIRECTION_TBL_STEP 16
+#define FR_BZ_RX_INDIRECTION_TBL_ROWS 128
+#define FRF_BZ_IT_QUEUE_LBN 0
+#define FRF_BZ_IT_QUEUE_WIDTH 6
+
+/* TX_FILTER_TBL0: TCP/IPv4 Transmit filter table */
+#define FR_CZ_TX_FILTER_TBL0 0x00fc0000
+#define FR_CZ_TX_FILTER_TBL0_STEP 16
+#define FR_CZ_TX_FILTER_TBL0_ROWS 8192
+#define FRF_CZ_TIFT_TCP_UDP_LBN 108
+#define FRF_CZ_TIFT_TCP_UDP_WIDTH 1
+#define FRF_CZ_TIFT_TXQ_ID_LBN 96
+#define FRF_CZ_TIFT_TXQ_ID_WIDTH 12
+#define FRF_CZ_TIFT_DEST_IP_LBN 64
+#define FRF_CZ_TIFT_DEST_IP_WIDTH 32
+#define FRF_CZ_TIFT_DEST_PORT_TCP_LBN 48
+#define FRF_CZ_TIFT_DEST_PORT_TCP_WIDTH 16
+#define FRF_CZ_TIFT_SRC_IP_LBN 16
+#define FRF_CZ_TIFT_SRC_IP_WIDTH 32
+#define FRF_CZ_TIFT_SRC_TCP_DEST_UDP_LBN 0
+#define FRF_CZ_TIFT_SRC_TCP_DEST_UDP_WIDTH 16
+
+/* TX_MAC_FILTER_TBL0: Transmit Ethernet filter table */
+#define FR_CZ_TX_MAC_FILTER_TBL0 0x00fe0000
+#define FR_CZ_TX_MAC_FILTER_TBL0_STEP 16
+#define FR_CZ_TX_MAC_FILTER_TBL0_ROWS 512
+#define FRF_CZ_TMFT_TXQ_ID_LBN 61
+#define FRF_CZ_TMFT_TXQ_ID_WIDTH 12
+#define FRF_CZ_TMFT_WILDCARD_MATCH_LBN 60
+#define FRF_CZ_TMFT_WILDCARD_MATCH_WIDTH 1
+#define FRF_CZ_TMFT_SRC_MAC_LBN 16
+#define FRF_CZ_TMFT_SRC_MAC_WIDTH 44
+#define FRF_CZ_TMFT_VLAN_ID_LBN 0
+#define FRF_CZ_TMFT_VLAN_ID_WIDTH 12
+
+/* MC_TREG_SMEM: MC Shared Memory */
+#define FR_CZ_MC_TREG_SMEM 0x00ff0000
+#define FR_CZ_MC_TREG_SMEM_STEP 4
+#define FR_CZ_MC_TREG_SMEM_ROWS 512
+#define FRF_CZ_MC_TREG_SMEM_ROW_LBN 0
+#define FRF_CZ_MC_TREG_SMEM_ROW_WIDTH 32
+
+/* MSIX_VECTOR_TABLE: MSIX Vector Table */
+#define FR_BB_MSIX_VECTOR_TABLE 0x00ff0000
+#define FR_BZ_MSIX_VECTOR_TABLE_STEP 16
+#define FR_BB_MSIX_VECTOR_TABLE_ROWS 64
+/* MSIX_VECTOR_TABLE: MSIX Vector Table */
+#define FR_CZ_MSIX_VECTOR_TABLE 0x00000000
+/* FR_BZ_MSIX_VECTOR_TABLE_STEP 16 */
+#define FR_CZ_MSIX_VECTOR_TABLE_ROWS 1024
+#define FRF_BZ_MSIX_VECTOR_RESERVED_LBN 97
+#define FRF_BZ_MSIX_VECTOR_RESERVED_WIDTH 31
+#define FRF_BZ_MSIX_VECTOR_MASK_LBN 96
+#define FRF_BZ_MSIX_VECTOR_MASK_WIDTH 1
+#define FRF_BZ_MSIX_MESSAGE_DATA_LBN 64
+#define FRF_BZ_MSIX_MESSAGE_DATA_WIDTH 32
+#define FRF_BZ_MSIX_MESSAGE_ADDRESS_HI_LBN 32
+#define FRF_BZ_MSIX_MESSAGE_ADDRESS_HI_WIDTH 32
+#define FRF_BZ_MSIX_MESSAGE_ADDRESS_LO_LBN 0
+#define FRF_BZ_MSIX_MESSAGE_ADDRESS_LO_WIDTH 32
+
+/* MSIX_PBA_TABLE: MSIX Pending Bit Array */
+#define FR_BB_MSIX_PBA_TABLE 0x00ff2000
+#define FR_BZ_MSIX_PBA_TABLE_STEP 4
+#define FR_BB_MSIX_PBA_TABLE_ROWS 2
+/* MSIX_PBA_TABLE: MSIX Pending Bit Array */
+#define FR_CZ_MSIX_PBA_TABLE 0x00008000
+/* FR_BZ_MSIX_PBA_TABLE_STEP 4 */
+#define FR_CZ_MSIX_PBA_TABLE_ROWS 32
+#define FRF_BZ_MSIX_PBA_PEND_DWORD_LBN 0
+#define FRF_BZ_MSIX_PBA_PEND_DWORD_WIDTH 32
+
+/* SRM_DBG_REG: SRAM debug access */
+#define FR_BZ_SRM_DBG 0x03000000
+#define FR_BZ_SRM_DBG_STEP 8
+#define FR_CZ_SRM_DBG_ROWS 262144
+#define FR_BB_SRM_DBG_ROWS 2097152
+#define FRF_BZ_SRM_DBG_LBN 0
+#define FRF_BZ_SRM_DBG_WIDTH 64
+
+/* TB_MSIX_PBA_TABLE: MSIX Pending Bit Array */
+#define FR_CZ_TB_MSIX_PBA_TABLE 0x00008000
+#define FR_CZ_TB_MSIX_PBA_TABLE_STEP 4
+#define FR_CZ_TB_MSIX_PBA_TABLE_ROWS 1024
+#define FRF_CZ_TB_MSIX_PBA_PEND_DWORD_LBN 0
+#define FRF_CZ_TB_MSIX_PBA_PEND_DWORD_WIDTH 32
+
+/* DRIVER_EV */
+#define FSF_AZ_DRIVER_EV_SUBCODE_LBN 56
+#define FSF_AZ_DRIVER_EV_SUBCODE_WIDTH 4
+#define FSE_BZ_TX_DSC_ERROR_EV 15
+#define FSE_BZ_RX_DSC_ERROR_EV 14
+#define FSE_AA_RX_RECOVER_EV 11
+#define FSE_AZ_TIMER_EV 10
+#define FSE_AZ_TX_PKT_NON_TCP_UDP 9
+#define FSE_AZ_WAKE_UP_EV 6
+#define FSE_AZ_SRM_UPD_DONE_EV 5
+#define FSE_AB_EVQ_NOT_EN_EV 3
+#define FSE_AZ_EVQ_INIT_DONE_EV 2
+#define FSE_AZ_RX_DESCQ_FLS_DONE_EV 1
+#define FSE_AZ_TX_DESCQ_FLS_DONE_EV 0
+#define FSF_AZ_DRIVER_EV_SUBDATA_LBN 0
+#define FSF_AZ_DRIVER_EV_SUBDATA_WIDTH 14
+
+/* EVENT_ENTRY */
+#define FSF_AZ_EV_CODE_LBN 60
+#define FSF_AZ_EV_CODE_WIDTH 4
+#define FSE_CZ_EV_CODE_MCDI_EV 12
+#define FSE_CZ_EV_CODE_USER_EV 8
+#define FSE_AZ_EV_CODE_DRV_GEN_EV 7
+#define FSE_AZ_EV_CODE_GLOBAL_EV 6
+#define FSE_AZ_EV_CODE_DRIVER_EV 5
+#define FSE_AZ_EV_CODE_TX_EV 2
+#define FSE_AZ_EV_CODE_RX_EV 0
+#define FSF_AZ_EV_DATA_LBN 0
+#define FSF_AZ_EV_DATA_WIDTH 60
+
+/* GLOBAL_EV */
+#define FSF_BB_GLB_EV_RX_RECOVERY_LBN 12
+#define FSF_BB_GLB_EV_RX_RECOVERY_WIDTH 1
+#define FSF_AA_GLB_EV_RX_RECOVERY_LBN 11
+#define FSF_AA_GLB_EV_RX_RECOVERY_WIDTH 1
+#define FSF_BB_GLB_EV_XG_MGT_INTR_LBN 11
+#define FSF_BB_GLB_EV_XG_MGT_INTR_WIDTH 1
+#define FSF_AB_GLB_EV_XFP_PHY0_INTR_LBN 10
+#define FSF_AB_GLB_EV_XFP_PHY0_INTR_WIDTH 1
+#define FSF_AB_GLB_EV_XG_PHY0_INTR_LBN 9
+#define FSF_AB_GLB_EV_XG_PHY0_INTR_WIDTH 1
+#define FSF_AB_GLB_EV_G_PHY0_INTR_LBN 7
+#define FSF_AB_GLB_EV_G_PHY0_INTR_WIDTH 1
+
+/* LEGACY_INT_VEC */
+#define FSF_AZ_NET_IVEC_FATAL_INT_LBN 64
+#define FSF_AZ_NET_IVEC_FATAL_INT_WIDTH 1
+#define FSF_AZ_NET_IVEC_INT_Q_LBN 40
+#define FSF_AZ_NET_IVEC_INT_Q_WIDTH 4
+#define FSF_AZ_NET_IVEC_INT_FLAG_LBN 32
+#define FSF_AZ_NET_IVEC_INT_FLAG_WIDTH 1
+#define FSF_AZ_NET_IVEC_EVQ_FIFO_HF_LBN 1
+#define FSF_AZ_NET_IVEC_EVQ_FIFO_HF_WIDTH 1
+#define FSF_AZ_NET_IVEC_EVQ_FIFO_AF_LBN 0
+#define FSF_AZ_NET_IVEC_EVQ_FIFO_AF_WIDTH 1
+
+/* MC_XGMAC_FLTR_RULE_DEF */
+#define FSF_CZ_MC_XFRC_MODE_LBN 416
+#define FSF_CZ_MC_XFRC_MODE_WIDTH 1
+#define FSE_CZ_MC_XFRC_MODE_LAYERED 1
+#define FSE_CZ_MC_XFRC_MODE_SIMPLE 0
+#define FSF_CZ_MC_XFRC_HASH_LBN 384
+#define FSF_CZ_MC_XFRC_HASH_WIDTH 32
+#define FSF_CZ_MC_XFRC_LAYER4_BYTE_MASK_LBN 256
+#define FSF_CZ_MC_XFRC_LAYER4_BYTE_MASK_WIDTH 128
+#define FSF_CZ_MC_XFRC_LAYER3_BYTE_MASK_LBN 128
+#define FSF_CZ_MC_XFRC_LAYER3_BYTE_MASK_WIDTH 128
+#define FSF_CZ_MC_XFRC_LAYER2_OR_SIMPLE_BYTE_MASK_LBN 0
+#define FSF_CZ_MC_XFRC_LAYER2_OR_SIMPLE_BYTE_MASK_WIDTH 128
+
+/* RX_EV */
+#define FSF_CZ_RX_EV_PKT_NOT_PARSED_LBN 58
+#define FSF_CZ_RX_EV_PKT_NOT_PARSED_WIDTH 1
+#define FSF_CZ_RX_EV_IPV6_PKT_LBN 57
+#define FSF_CZ_RX_EV_IPV6_PKT_WIDTH 1
+#define FSF_AZ_RX_EV_PKT_OK_LBN 56
+#define FSF_AZ_RX_EV_PKT_OK_WIDTH 1
+#define FSF_AZ_RX_EV_PAUSE_FRM_ERR_LBN 55
+#define FSF_AZ_RX_EV_PAUSE_FRM_ERR_WIDTH 1
+#define FSF_AZ_RX_EV_BUF_OWNER_ID_ERR_LBN 54
+#define FSF_AZ_RX_EV_BUF_OWNER_ID_ERR_WIDTH 1
+#define FSF_AZ_RX_EV_IP_FRAG_ERR_LBN 53
+#define FSF_AZ_RX_EV_IP_FRAG_ERR_WIDTH 1
+#define FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR_LBN 52
+#define FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR_WIDTH 1
+#define FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR_LBN 51
+#define FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR_WIDTH 1
+#define FSF_AZ_RX_EV_ETH_CRC_ERR_LBN 50
+#define FSF_AZ_RX_EV_ETH_CRC_ERR_WIDTH 1
+#define FSF_AZ_RX_EV_FRM_TRUNC_LBN 49
+#define FSF_AZ_RX_EV_FRM_TRUNC_WIDTH 1
+#define FSF_AA_RX_EV_DRIB_NIB_LBN 49
+#define FSF_AA_RX_EV_DRIB_NIB_WIDTH 1
+#define FSF_AZ_RX_EV_TOBE_DISC_LBN 47
+#define FSF_AZ_RX_EV_TOBE_DISC_WIDTH 1
+#define FSF_AZ_RX_EV_PKT_TYPE_LBN 44
+#define FSF_AZ_RX_EV_PKT_TYPE_WIDTH 3
+#define FSE_AZ_RX_EV_PKT_TYPE_VLAN_JUMBO 5
+#define FSE_AZ_RX_EV_PKT_TYPE_VLAN_LLC 4
+#define FSE_AZ_RX_EV_PKT_TYPE_VLAN 3
+#define FSE_AZ_RX_EV_PKT_TYPE_JUMBO 2
+#define FSE_AZ_RX_EV_PKT_TYPE_LLC 1
+#define FSE_AZ_RX_EV_PKT_TYPE_ETH 0
+#define FSF_AZ_RX_EV_HDR_TYPE_LBN 42
+#define FSF_AZ_RX_EV_HDR_TYPE_WIDTH 2
+#define FSE_AZ_RX_EV_HDR_TYPE_OTHER 3
+#define FSE_AB_RX_EV_HDR_TYPE_IPV4_OTHER 2
+#define FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_OTHER 2
+#define FSE_AB_RX_EV_HDR_TYPE_IPV4_UDP 1
+#define FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP 1
+#define FSE_AB_RX_EV_HDR_TYPE_IPV4_TCP 0
+#define FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP 0
+#define FSF_AZ_RX_EV_DESC_Q_EMPTY_LBN 41
+#define FSF_AZ_RX_EV_DESC_Q_EMPTY_WIDTH 1
+#define FSF_AZ_RX_EV_MCAST_HASH_MATCH_LBN 40
+#define FSF_AZ_RX_EV_MCAST_HASH_MATCH_WIDTH 1
+#define FSF_AZ_RX_EV_MCAST_PKT_LBN 39
+#define FSF_AZ_RX_EV_MCAST_PKT_WIDTH 1
+#define FSF_AA_RX_EV_RECOVERY_FLAG_LBN 37
+#define FSF_AA_RX_EV_RECOVERY_FLAG_WIDTH 1
+#define FSF_AZ_RX_EV_Q_LABEL_LBN 32
+#define FSF_AZ_RX_EV_Q_LABEL_WIDTH 5
+#define FSF_AZ_RX_EV_JUMBO_CONT_LBN 31
+#define FSF_AZ_RX_EV_JUMBO_CONT_WIDTH 1
+#define FSF_AZ_RX_EV_PORT_LBN 30
+#define FSF_AZ_RX_EV_PORT_WIDTH 1
+#define FSF_AZ_RX_EV_BYTE_CNT_LBN 16
+#define FSF_AZ_RX_EV_BYTE_CNT_WIDTH 14
+#define FSF_AZ_RX_EV_SOP_LBN 15
+#define FSF_AZ_RX_EV_SOP_WIDTH 1
+#define FSF_AZ_RX_EV_ISCSI_PKT_OK_LBN 14
+#define FSF_AZ_RX_EV_ISCSI_PKT_OK_WIDTH 1
+#define FSF_AZ_RX_EV_ISCSI_DDIG_ERR_LBN 13
+#define FSF_AZ_RX_EV_ISCSI_DDIG_ERR_WIDTH 1
+#define FSF_AZ_RX_EV_ISCSI_HDIG_ERR_LBN 12
+#define FSF_AZ_RX_EV_ISCSI_HDIG_ERR_WIDTH 1
+#define FSF_AZ_RX_EV_DESC_PTR_LBN 0
+#define FSF_AZ_RX_EV_DESC_PTR_WIDTH 12
+
+/* RX_KER_DESC */
+#define FSF_AZ_RX_KER_BUF_SIZE_LBN 48
+#define FSF_AZ_RX_KER_BUF_SIZE_WIDTH 14
+#define FSF_AZ_RX_KER_BUF_REGION_LBN 46
+#define FSF_AZ_RX_KER_BUF_REGION_WIDTH 2
+#define FSF_AZ_RX_KER_BUF_ADDR_LBN 0
+#define FSF_AZ_RX_KER_BUF_ADDR_WIDTH 46
+
+/* RX_USER_DESC */
+#define FSF_AZ_RX_USER_2BYTE_OFFSET_LBN 20
+#define FSF_AZ_RX_USER_2BYTE_OFFSET_WIDTH 12
+#define FSF_AZ_RX_USER_BUF_ID_LBN 0
+#define FSF_AZ_RX_USER_BUF_ID_WIDTH 20
+
+/* TX_EV */
+#define FSF_AZ_TX_EV_PKT_ERR_LBN 38
+#define FSF_AZ_TX_EV_PKT_ERR_WIDTH 1
+#define FSF_AZ_TX_EV_PKT_TOO_BIG_LBN 37
+#define FSF_AZ_TX_EV_PKT_TOO_BIG_WIDTH 1
+#define FSF_AZ_TX_EV_Q_LABEL_LBN 32
+#define FSF_AZ_TX_EV_Q_LABEL_WIDTH 5
+#define FSF_AZ_TX_EV_PORT_LBN 16
+#define FSF_AZ_TX_EV_PORT_WIDTH 1
+#define FSF_AZ_TX_EV_WQ_FF_FULL_LBN 15
+#define FSF_AZ_TX_EV_WQ_FF_FULL_WIDTH 1
+#define FSF_AZ_TX_EV_BUF_OWNER_ID_ERR_LBN 14
+#define FSF_AZ_TX_EV_BUF_OWNER_ID_ERR_WIDTH 1
+#define FSF_AZ_TX_EV_COMP_LBN 12
+#define FSF_AZ_TX_EV_COMP_WIDTH 1
+#define FSF_AZ_TX_EV_DESC_PTR_LBN 0
+#define FSF_AZ_TX_EV_DESC_PTR_WIDTH 12
+
+/* TX_KER_DESC */
+#define FSF_AZ_TX_KER_CONT_LBN 62
+#define FSF_AZ_TX_KER_CONT_WIDTH 1
+#define FSF_AZ_TX_KER_BYTE_COUNT_LBN 48
+#define FSF_AZ_TX_KER_BYTE_COUNT_WIDTH 14
+#define FSF_AZ_TX_KER_BUF_REGION_LBN 46
+#define FSF_AZ_TX_KER_BUF_REGION_WIDTH 2
+#define FSF_AZ_TX_KER_BUF_ADDR_LBN 0
+#define FSF_AZ_TX_KER_BUF_ADDR_WIDTH 46
+
+/* TX_USER_DESC */
+#define FSF_AZ_TX_USER_SW_EV_EN_LBN 48
+#define FSF_AZ_TX_USER_SW_EV_EN_WIDTH 1
+#define FSF_AZ_TX_USER_CONT_LBN 46
+#define FSF_AZ_TX_USER_CONT_WIDTH 1
+#define FSF_AZ_TX_USER_BYTE_CNT_LBN 33
+#define FSF_AZ_TX_USER_BYTE_CNT_WIDTH 13
+#define FSF_AZ_TX_USER_BUF_ID_LBN 13
+#define FSF_AZ_TX_USER_BUF_ID_WIDTH 20
+#define FSF_AZ_TX_USER_BYTE_OFS_LBN 0
+#define FSF_AZ_TX_USER_BYTE_OFS_WIDTH 13
+
+/* USER_EV */
+#define FSF_CZ_USER_QID_LBN 32
+#define FSF_CZ_USER_QID_WIDTH 10
+#define FSF_CZ_USER_EV_REG_VALUE_LBN 0
+#define FSF_CZ_USER_EV_REG_VALUE_WIDTH 32
+
+/**************************************************************************
+ *
+ * Falcon B0 PCIe core indirect registers
+ *
+ **************************************************************************
+ */
+
+#define FPCR_BB_PCIE_DEVICE_CTRL_STAT 0x68
+
+#define FPCR_BB_PCIE_LINK_CTRL_STAT 0x70
+
+#define FPCR_BB_ACK_RPL_TIMER 0x700
+#define FPCRF_BB_ACK_TL_LBN 0
+#define FPCRF_BB_ACK_TL_WIDTH 16
+#define FPCRF_BB_RPL_TL_LBN 16
+#define FPCRF_BB_RPL_TL_WIDTH 16
+
+#define FPCR_BB_ACK_FREQ 0x70C
+#define FPCRF_BB_ACK_FREQ_LBN 0
+#define FPCRF_BB_ACK_FREQ_WIDTH 7
+
+/**************************************************************************
+ *
+ * Pseudo-registers and fields
+ *
+ **************************************************************************
+ */
+
+/* Interrupt acknowledge work-around register (A0/A1 only) */
+#define FR_AA_WORK_AROUND_BROKEN_PCI_READS 0x0070
+
+/* EE_SPI_HCMD_REG: SPI host command register */
+/* Values for the EE_SPI_HCMD_SF_SEL register field */
+#define FFE_AB_SPI_DEVICE_EEPROM 0
+#define FFE_AB_SPI_DEVICE_FLASH 1
+
+/* NIC_STAT_REG: NIC status register */
+#define FRF_AB_STRAP_10G_LBN 2
+#define FRF_AB_STRAP_10G_WIDTH 1
+#define FRF_AA_STRAP_PCIE_LBN 0
+#define FRF_AA_STRAP_PCIE_WIDTH 1
+
+/* FATAL_INTR_REG_KER: Fatal interrupt register for Kernel */
+#define FRF_AZ_FATAL_INTR_LBN 0
+#define FRF_AZ_FATAL_INTR_WIDTH 12
+
+/* SRM_CFG_REG: SRAM configuration register */
+/* We treat the number of SRAM banks and bank size as a single field */
+#define FRF_AZ_SRM_NB_SZ_LBN FRF_AZ_SRM_BANK_SIZE_LBN
+#define FRF_AZ_SRM_NB_SZ_WIDTH \
+ (FRF_AZ_SRM_BANK_SIZE_WIDTH + FRF_AZ_SRM_NUM_BANK_WIDTH)
+#define FFE_AB_SRM_NB1_SZ2M 0
+#define FFE_AB_SRM_NB1_SZ4M 1
+#define FFE_AB_SRM_NB1_SZ8M 2
+#define FFE_AB_SRM_NB_SZ_DEF 3
+#define FFE_AB_SRM_NB2_SZ4M 4
+#define FFE_AB_SRM_NB2_SZ8M 5
+#define FFE_AB_SRM_NB2_SZ16M 6
+#define FFE_AB_SRM_NB_SZ_RES 7
+
+/* RX_DESC_UPD_REGP0: Receive descriptor update register. */
+/* We write just the last dword of these registers */
+#define FR_AZ_RX_DESC_UPD_DWORD_P0 \
+ (BUILD_BUG_ON_ZERO(FR_AA_RX_DESC_UPD_KER != FR_BZ_RX_DESC_UPD_P0) + \
+ FR_BZ_RX_DESC_UPD_P0 + 3 * 4)
+#define FRF_AZ_RX_DESC_WPTR_DWORD_LBN (FRF_AZ_RX_DESC_WPTR_LBN - 3 * 32)
+#define FRF_AZ_RX_DESC_WPTR_DWORD_WIDTH FRF_AZ_RX_DESC_WPTR_WIDTH
+
+/* TX_DESC_UPD_REGP0: Transmit descriptor update register. */
+#define FR_AZ_TX_DESC_UPD_DWORD_P0 \
+ (BUILD_BUG_ON_ZERO(FR_AA_TX_DESC_UPD_KER != FR_BZ_TX_DESC_UPD_P0) + \
+ FR_BZ_TX_DESC_UPD_P0 + 3 * 4)
+#define FRF_AZ_TX_DESC_WPTR_DWORD_LBN (FRF_AZ_TX_DESC_WPTR_LBN - 3 * 32)
+#define FRF_AZ_TX_DESC_WPTR_DWORD_WIDTH FRF_AZ_TX_DESC_WPTR_WIDTH
+
+/* GMF_CFG4_REG: GMAC FIFO configuration register 4 */
+#define FRF_AB_GMF_HSTFLTRFRM_PAUSE_LBN 12
+#define FRF_AB_GMF_HSTFLTRFRM_PAUSE_WIDTH 1
+
+/* GMF_CFG5_REG: GMAC FIFO configuration register 5 */
+#define FRF_AB_GMF_HSTFLTRFRMDC_PAUSE_LBN 12
+#define FRF_AB_GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1
+
+/* XM_TX_PARAM_REG: XGMAC transmit parameter register */
+#define FRF_AB_XM_MAX_TX_FRM_SIZE_LBN FRF_AB_XM_MAX_TX_FRM_SIZE_LO_LBN
+#define FRF_AB_XM_MAX_TX_FRM_SIZE_WIDTH (FRF_AB_XM_MAX_TX_FRM_SIZE_HI_WIDTH + \
+ FRF_AB_XM_MAX_TX_FRM_SIZE_LO_WIDTH)
+
+/* XM_RX_PARAM_REG: XGMAC receive parameter register */
+#define FRF_AB_XM_MAX_RX_FRM_SIZE_LBN FRF_AB_XM_MAX_RX_FRM_SIZE_LO_LBN
+#define FRF_AB_XM_MAX_RX_FRM_SIZE_WIDTH (FRF_AB_XM_MAX_RX_FRM_SIZE_HI_WIDTH + \
+ FRF_AB_XM_MAX_RX_FRM_SIZE_LO_WIDTH)
+
+/* XX_TXDRV_CTL_REG: XAUI SerDes transmit drive control register */
+/* Default values */
+#define FFE_AB_XX_TXDRV_DEQ_DEF 0xe /* deq=.6 */
+#define FFE_AB_XX_TXDRV_DTX_DEF 0x5 /* 1.25 */
+#define FFE_AB_XX_SD_CTL_DRV_DEF 0 /* 20mA */
+
+/* XX_CORE_STAT_REG: XAUI XGXS core status register */
+/* XGXS all-lanes status fields */
+#define FRF_AB_XX_SYNC_STAT_LBN FRF_AB_XX_SYNC_STAT0_LBN
+#define FRF_AB_XX_SYNC_STAT_WIDTH 4
+#define FRF_AB_XX_COMMA_DET_LBN FRF_AB_XX_COMMA_DET_CH0_LBN
+#define FRF_AB_XX_COMMA_DET_WIDTH 4
+#define FRF_AB_XX_CHAR_ERR_LBN FRF_AB_XX_CHAR_ERR_CH0_LBN
+#define FRF_AB_XX_CHAR_ERR_WIDTH 4
+#define FRF_AB_XX_DISPERR_LBN FRF_AB_XX_DISPERR_CH0_LBN
+#define FRF_AB_XX_DISPERR_WIDTH 4
+#define FFE_AB_XX_STAT_ALL_LANES 0xf
+#define FRF_AB_XX_FORCE_SIG_LBN FRF_AB_XX_FORCE_SIG0_VAL_LBN
+#define FRF_AB_XX_FORCE_SIG_WIDTH 8
+#define FFE_AB_XX_FORCE_SIG_ALL_LANES 0xff
+
+/* DRIVER_EV */
+/* Sub-fields of an RX flush completion event */
+#define FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL_LBN 12
+#define FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL_WIDTH 1
+#define FSF_AZ_DRIVER_EV_RX_DESCQ_ID_LBN 0
+#define FSF_AZ_DRIVER_EV_RX_DESCQ_ID_WIDTH 12
+
+/* EVENT_ENTRY */
+/* Magic number field for event test */
+#define FSF_AZ_DRV_GEN_EV_MAGIC_LBN 0
+#define FSF_AZ_DRV_GEN_EV_MAGIC_WIDTH 32
+
+/**************************************************************************
+ *
+ * Falcon MAC stats
+ *
+ **************************************************************************
+ *
+ */
+
+#define GRxGoodOct_offset 0x0
+#define GRxGoodOct_WIDTH 48
+#define GRxBadOct_offset 0x8
+#define GRxBadOct_WIDTH 48
+#define GRxMissPkt_offset 0x10
+#define GRxMissPkt_WIDTH 32
+#define GRxFalseCRS_offset 0x14
+#define GRxFalseCRS_WIDTH 32
+#define GRxPausePkt_offset 0x18
+#define GRxPausePkt_WIDTH 32
+#define GRxBadPkt_offset 0x1C
+#define GRxBadPkt_WIDTH 32
+#define GRxUcastPkt_offset 0x20
+#define GRxUcastPkt_WIDTH 32
+#define GRxMcastPkt_offset 0x24
+#define GRxMcastPkt_WIDTH 32
+#define GRxBcastPkt_offset 0x28
+#define GRxBcastPkt_WIDTH 32
+#define GRxGoodLt64Pkt_offset 0x2C
+#define GRxGoodLt64Pkt_WIDTH 32
+#define GRxBadLt64Pkt_offset 0x30
+#define GRxBadLt64Pkt_WIDTH 32
+#define GRx64Pkt_offset 0x34
+#define GRx64Pkt_WIDTH 32
+#define GRx65to127Pkt_offset 0x38
+#define GRx65to127Pkt_WIDTH 32
+#define GRx128to255Pkt_offset 0x3C
+#define GRx128to255Pkt_WIDTH 32
+#define GRx256to511Pkt_offset 0x40
+#define GRx256to511Pkt_WIDTH 32
+#define GRx512to1023Pkt_offset 0x44
+#define GRx512to1023Pkt_WIDTH 32
+#define GRx1024to15xxPkt_offset 0x48
+#define GRx1024to15xxPkt_WIDTH 32
+#define GRx15xxtoJumboPkt_offset 0x4C
+#define GRx15xxtoJumboPkt_WIDTH 32
+#define GRxGtJumboPkt_offset 0x50
+#define GRxGtJumboPkt_WIDTH 32
+#define GRxFcsErr64to15xxPkt_offset 0x54
+#define GRxFcsErr64to15xxPkt_WIDTH 32
+#define GRxFcsErr15xxtoJumboPkt_offset 0x58
+#define GRxFcsErr15xxtoJumboPkt_WIDTH 32
+#define GRxFcsErrGtJumboPkt_offset 0x5C
+#define GRxFcsErrGtJumboPkt_WIDTH 32
+#define GTxGoodBadOct_offset 0x80
+#define GTxGoodBadOct_WIDTH 48
+#define GTxGoodOct_offset 0x88
+#define GTxGoodOct_WIDTH 48
+#define GTxSglColPkt_offset 0x90
+#define GTxSglColPkt_WIDTH 32
+#define GTxMultColPkt_offset 0x94
+#define GTxMultColPkt_WIDTH 32
+#define GTxExColPkt_offset 0x98
+#define GTxExColPkt_WIDTH 32
+#define GTxDefPkt_offset 0x9C
+#define GTxDefPkt_WIDTH 32
+#define GTxLateCol_offset 0xA0
+#define GTxLateCol_WIDTH 32
+#define GTxExDefPkt_offset 0xA4
+#define GTxExDefPkt_WIDTH 32
+#define GTxPausePkt_offset 0xA8
+#define GTxPausePkt_WIDTH 32
+#define GTxBadPkt_offset 0xAC
+#define GTxBadPkt_WIDTH 32
+#define GTxUcastPkt_offset 0xB0
+#define GTxUcastPkt_WIDTH 32
+#define GTxMcastPkt_offset 0xB4
+#define GTxMcastPkt_WIDTH 32
+#define GTxBcastPkt_offset 0xB8
+#define GTxBcastPkt_WIDTH 32
+#define GTxLt64Pkt_offset 0xBC
+#define GTxLt64Pkt_WIDTH 32
+#define GTx64Pkt_offset 0xC0
+#define GTx64Pkt_WIDTH 32
+#define GTx65to127Pkt_offset 0xC4
+#define GTx65to127Pkt_WIDTH 32
+#define GTx128to255Pkt_offset 0xC8
+#define GTx128to255Pkt_WIDTH 32
+#define GTx256to511Pkt_offset 0xCC
+#define GTx256to511Pkt_WIDTH 32
+#define GTx512to1023Pkt_offset 0xD0
+#define GTx512to1023Pkt_WIDTH 32
+#define GTx1024to15xxPkt_offset 0xD4
+#define GTx1024to15xxPkt_WIDTH 32
+#define GTx15xxtoJumboPkt_offset 0xD8
+#define GTx15xxtoJumboPkt_WIDTH 32
+#define GTxGtJumboPkt_offset 0xDC
+#define GTxGtJumboPkt_WIDTH 32
+#define GTxNonTcpUdpPkt_offset 0xE0
+#define GTxNonTcpUdpPkt_WIDTH 16
+#define GTxMacSrcErrPkt_offset 0xE4
+#define GTxMacSrcErrPkt_WIDTH 16
+#define GTxIpSrcErrPkt_offset 0xE8
+#define GTxIpSrcErrPkt_WIDTH 16
+#define GDmaDone_offset 0xEC
+#define GDmaDone_WIDTH 32
+
+#define XgRxOctets_offset 0x0
+#define XgRxOctets_WIDTH 48
+#define XgRxOctetsOK_offset 0x8
+#define XgRxOctetsOK_WIDTH 48
+#define XgRxPkts_offset 0x10
+#define XgRxPkts_WIDTH 32
+#define XgRxPktsOK_offset 0x14
+#define XgRxPktsOK_WIDTH 32
+#define XgRxBroadcastPkts_offset 0x18
+#define XgRxBroadcastPkts_WIDTH 32
+#define XgRxMulticastPkts_offset 0x1C
+#define XgRxMulticastPkts_WIDTH 32
+#define XgRxUnicastPkts_offset 0x20
+#define XgRxUnicastPkts_WIDTH 32
+#define XgRxUndersizePkts_offset 0x24
+#define XgRxUndersizePkts_WIDTH 32
+#define XgRxOversizePkts_offset 0x28
+#define XgRxOversizePkts_WIDTH 32
+#define XgRxJabberPkts_offset 0x2C
+#define XgRxJabberPkts_WIDTH 32
+#define XgRxUndersizeFCSerrorPkts_offset 0x30
+#define XgRxUndersizeFCSerrorPkts_WIDTH 32
+#define XgRxDropEvents_offset 0x34
+#define XgRxDropEvents_WIDTH 32
+#define XgRxFCSerrorPkts_offset 0x38
+#define XgRxFCSerrorPkts_WIDTH 32
+#define XgRxAlignError_offset 0x3C
+#define XgRxAlignError_WIDTH 32
+#define XgRxSymbolError_offset 0x40
+#define XgRxSymbolError_WIDTH 32
+#define XgRxInternalMACError_offset 0x44
+#define XgRxInternalMACError_WIDTH 32
+#define XgRxControlPkts_offset 0x48
+#define XgRxControlPkts_WIDTH 32
+#define XgRxPausePkts_offset 0x4C
+#define XgRxPausePkts_WIDTH 32
+#define XgRxPkts64Octets_offset 0x50
+#define XgRxPkts64Octets_WIDTH 32
+#define XgRxPkts65to127Octets_offset 0x54
+#define XgRxPkts65to127Octets_WIDTH 32
+#define XgRxPkts128to255Octets_offset 0x58
+#define XgRxPkts128to255Octets_WIDTH 32
+#define XgRxPkts256to511Octets_offset 0x5C
+#define XgRxPkts256to511Octets_WIDTH 32
+#define XgRxPkts512to1023Octets_offset 0x60
+#define XgRxPkts512to1023Octets_WIDTH 32
+#define XgRxPkts1024to15xxOctets_offset 0x64
+#define XgRxPkts1024to15xxOctets_WIDTH 32
+#define XgRxPkts15xxtoMaxOctets_offset 0x68
+#define XgRxPkts15xxtoMaxOctets_WIDTH 32
+#define XgRxLengthError_offset 0x6C
+#define XgRxLengthError_WIDTH 32
+#define XgTxPkts_offset 0x80
+#define XgTxPkts_WIDTH 32
+#define XgTxOctets_offset 0x88
+#define XgTxOctets_WIDTH 48
+#define XgTxMulticastPkts_offset 0x90
+#define XgTxMulticastPkts_WIDTH 32
+#define XgTxBroadcastPkts_offset 0x94
+#define XgTxBroadcastPkts_WIDTH 32
+#define XgTxUnicastPkts_offset 0x98
+#define XgTxUnicastPkts_WIDTH 32
+#define XgTxControlPkts_offset 0x9C
+#define XgTxControlPkts_WIDTH 32
+#define XgTxPausePkts_offset 0xA0
+#define XgTxPausePkts_WIDTH 32
+#define XgTxPkts64Octets_offset 0xA4
+#define XgTxPkts64Octets_WIDTH 32
+#define XgTxPkts65to127Octets_offset 0xA8
+#define XgTxPkts65to127Octets_WIDTH 32
+#define XgTxPkts128to255Octets_offset 0xAC
+#define XgTxPkts128to255Octets_WIDTH 32
+#define XgTxPkts256to511Octets_offset 0xB0
+#define XgTxPkts256to511Octets_WIDTH 32
+#define XgTxPkts512to1023Octets_offset 0xB4
+#define XgTxPkts512to1023Octets_WIDTH 32
+#define XgTxPkts1024to15xxOctets_offset 0xB8
+#define XgTxPkts1024to15xxOctets_WIDTH 32
+#define XgTxPkts1519toMaxOctets_offset 0xBC
+#define XgTxPkts1519toMaxOctets_WIDTH 32
+#define XgTxUndersizePkts_offset 0xC0
+#define XgTxUndersizePkts_WIDTH 32
+#define XgTxOversizePkts_offset 0xC4
+#define XgTxOversizePkts_WIDTH 32
+#define XgTxNonTcpUdpPkt_offset 0xC8
+#define XgTxNonTcpUdpPkt_WIDTH 16
+#define XgTxMacSrcErrPkt_offset 0xCC
+#define XgTxMacSrcErrPkt_WIDTH 16
+#define XgTxIpSrcErrPkt_offset 0xD0
+#define XgTxIpSrcErrPkt_WIDTH 16
+#define XgDmaDone_offset 0xD4
+#define XgDmaDone_WIDTH 32
+
+#define FALCON_STATS_NOT_DONE 0x00000000
+#define FALCON_STATS_DONE 0xffffffff
+
+/* Interrupt status register bits */
+#define FATAL_INT_LBN 64
+#define FATAL_INT_WIDTH 1
+#define INT_EVQS_LBN 40
+#define INT_EVQS_WIDTH 4
+#define INT_FLAG_LBN 32
+#define INT_FLAG_WIDTH 1
+#define EVQ_FIFO_HF_LBN 1
+#define EVQ_FIFO_HF_WIDTH 1
+#define EVQ_FIFO_AF_LBN 0
+#define EVQ_FIFO_AF_WIDTH 1
+
+/**************************************************************************
+ *
+ * Falcon non-volatile configuration
+ *
+ **************************************************************************
+ */
+
+/* Board configuration v2 (v1 is obsolete; later versions are compatible) */
+struct falcon_nvconfig_board_v2 {
+ __le16 nports;
+ u8 port0_phy_addr;
+ u8 port0_phy_type;
+ u8 port1_phy_addr;
+ u8 port1_phy_type;
+ __le16 asic_sub_revision;
+ __le16 board_revision;
+} __packed;
+
+/* Board configuration v3 extra information */
+struct falcon_nvconfig_board_v3 {
+ __le32 spi_device_type[2];
+} __packed;
+
+/* Bit numbers for spi_device_type */
+#define SPI_DEV_TYPE_SIZE_LBN 0
+#define SPI_DEV_TYPE_SIZE_WIDTH 5
+#define SPI_DEV_TYPE_ADDR_LEN_LBN 6
+#define SPI_DEV_TYPE_ADDR_LEN_WIDTH 2
+#define SPI_DEV_TYPE_ERASE_CMD_LBN 8
+#define SPI_DEV_TYPE_ERASE_CMD_WIDTH 8
+#define SPI_DEV_TYPE_ERASE_SIZE_LBN 16
+#define SPI_DEV_TYPE_ERASE_SIZE_WIDTH 5
+#define SPI_DEV_TYPE_BLOCK_SIZE_LBN 24
+#define SPI_DEV_TYPE_BLOCK_SIZE_WIDTH 5
+#define SPI_DEV_TYPE_FIELD(type, field) \
+ (((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(EFX_WIDTH(field)))
+
+#define FALCON_NVCONFIG_OFFSET 0x300
+
+#define FALCON_NVCONFIG_BOARD_MAGIC_NUM 0xFA1C
+struct falcon_nvconfig {
+ efx_oword_t ee_vpd_cfg_reg; /* 0x300 */
+ u8 mac_address[2][8]; /* 0x310 */
+ efx_oword_t pcie_sd_ctl0123_reg; /* 0x320 */
+ efx_oword_t pcie_sd_ctl45_reg; /* 0x330 */
+ efx_oword_t pcie_pcs_ctl_stat_reg; /* 0x340 */
+ efx_oword_t hw_init_reg; /* 0x350 */
+ efx_oword_t nic_stat_reg; /* 0x360 */
+ efx_oword_t glb_ctl_reg; /* 0x370 */
+ efx_oword_t srm_cfg_reg; /* 0x380 */
+ efx_oword_t spare_reg; /* 0x390 */
+ __le16 board_magic_num; /* 0x3A0 */
+ __le16 board_struct_ver;
+ __le16 board_checksum;
+ struct falcon_nvconfig_board_v2 board_v2;
+ efx_oword_t ee_base_page_reg; /* 0x3B0 */
+ struct falcon_nvconfig_board_v3 board_v3; /* 0x3C0 */
+} __packed;
+
+#endif /* EFX_REGS_H */
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
index 01f9432c31ef..ea59ed25b0d8 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/sfc/rx.c
@@ -293,8 +293,7 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
* fill anyway.
*/
fill_level = (rx_queue->added_count - rx_queue->removed_count);
- EFX_BUG_ON_PARANOID(fill_level >
- rx_queue->efx->type->rxd_ring_mask + 1);
+ EFX_BUG_ON_PARANOID(fill_level > EFX_RXQ_SIZE);
/* Don't fill if we don't need to */
if (fill_level >= rx_queue->fast_fill_trigger)
@@ -316,8 +315,7 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
retry:
/* Recalculate current fill level now that we have the lock */
fill_level = (rx_queue->added_count - rx_queue->removed_count);
- EFX_BUG_ON_PARANOID(fill_level >
- rx_queue->efx->type->rxd_ring_mask + 1);
+ EFX_BUG_ON_PARANOID(fill_level > EFX_RXQ_SIZE);
space = rx_queue->fast_fill_limit - fill_level;
if (space < EFX_RX_BATCH)
goto out_unlock;
@@ -329,8 +327,7 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
do {
for (i = 0; i < EFX_RX_BATCH; ++i) {
- index = (rx_queue->added_count &
- rx_queue->efx->type->rxd_ring_mask);
+ index = rx_queue->added_count & EFX_RXQ_MASK;
rx_buf = efx_rx_buffer(rx_queue, index);
rc = efx_init_rx_buffer(rx_queue, rx_buf);
if (unlikely(rc))
@@ -629,7 +626,7 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue)
EFX_LOG(efx, "creating RX queue %d\n", rx_queue->queue);
/* Allocate RX buffers */
- rxq_size = (efx->type->rxd_ring_mask + 1) * sizeof(*rx_queue->buffer);
+ rxq_size = EFX_RXQ_SIZE * sizeof(*rx_queue->buffer);
rx_queue->buffer = kzalloc(rxq_size, GFP_KERNEL);
if (!rx_queue->buffer)
return -ENOMEM;
@@ -644,7 +641,6 @@ 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;
EFX_LOG(rx_queue->efx, "initialising RX queue %d\n", rx_queue->queue);
@@ -657,7 +653,7 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue)
rx_queue->min_overfill = -1U;
/* Initialise limit fields */
- max_fill = efx->type->rxd_ring_mask + 1 - EFX_RXD_HEAD_ROOM;
+ max_fill = EFX_RXQ_SIZE - EFX_RXD_HEAD_ROOM;
trigger = max_fill * min(rx_refill_threshold, 100U) / 100U;
limit = max_fill * min(rx_refill_limit, 100U) / 100U;
@@ -680,7 +676,7 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
/* Release RX buffers NB start at index 0 not current HW ptr */
if (rx_queue->buffer) {
- for (i = 0; i <= rx_queue->efx->type->rxd_ring_mask; i++) {
+ for (i = 0; i <= EFX_RXQ_MASK; i++) {
rx_buf = efx_rx_buffer(rx_queue, i);
efx_fini_rx_buffer(rx_queue, rx_buf);
}
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index 817c7efc11e0..7a9386f97c42 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -24,10 +24,9 @@
#include "efx.h"
#include "falcon.h"
#include "selftest.h"
-#include "boards.h"
#include "workarounds.h"
#include "spi.h"
-#include "falcon_io.h"
+#include "io.h"
#include "mdio_10g.h"
/*
@@ -527,7 +526,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->type->txd_ring_mask + 1) / 3;
+ state->packet_count = EFX_TXQ_SIZE / 3;
state->packet_count = min(1 << (i << 2), state->packet_count);
state->skbs = kzalloc(sizeof(state->skbs[0]) *
state->packet_count, GFP_KERNEL);
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index f4d509015f75..390b27b5ace9 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -14,8 +14,7 @@
#include "mdio_10g.h"
#include "falcon.h"
#include "phy.h"
-#include "falcon_hwdefs.h"
-#include "boards.h"
+#include "regs.h"
#include "workarounds.h"
#include "selftest.h"
@@ -301,6 +300,7 @@ static int tenxpress_init(struct efx_nic *efx)
static int tenxpress_phy_init(struct efx_nic *efx)
{
struct tenxpress_phy_data *phy_data;
+ u16 old_adv, adv;
int rc = 0;
phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
@@ -333,6 +333,15 @@ static int tenxpress_phy_init(struct efx_nic *efx)
if (rc < 0)
goto fail;
+ /* Set pause advertising */
+ old_adv = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
+ adv = ((old_adv & ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) |
+ mii_advertise_flowctrl(efx->wanted_fc));
+ if (adv != old_adv) {
+ efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, adv);
+ mdio45_nway_restart(&efx->mdio);
+ }
+
if (efx->phy_type == PHY_TYPE_SFT9001B) {
rc = device_create_file(&efx->pci_dev->dev,
&dev_attr_phy_short_reach);
@@ -742,6 +751,7 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa);
+ ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
if (efx->phy_type != PHY_TYPE_SFX7101) {
ecmd->supported |= (SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full);
diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c
index 489c4de31447..303919a34df6 100644
--- a/drivers/net/sfc/tx.c
+++ b/drivers/net/sfc/tx.c
@@ -26,8 +26,7 @@
* The tx_queue descriptor ring fill-level must fall below this value
* before we restart the netif queue
*/
-#define EFX_NETDEV_TX_THRESHOLD(_tx_queue) \
- (_tx_queue->efx->type->txd_ring_mask / 2u)
+#define EFX_TXQ_THRESHOLD (EFX_TXQ_MASK / 2u)
/* We want to be able to nest calls to netif_stop_queue(), since each
* channel can have an individual stop on the queue.
@@ -125,6 +124,24 @@ static void efx_tsoh_free(struct efx_tx_queue *tx_queue,
}
+static inline unsigned
+efx_max_tx_len(struct efx_nic *efx, dma_addr_t dma_addr)
+{
+ /* Depending on the NIC revision, we can use descriptor
+ * lengths up to 8K or 8K-1. However, since PCI Express
+ * devices must split read requests at 4K boundaries, there is
+ * little benefit from using descriptors that cross those
+ * boundaries and we keep things simple by not doing so.
+ */
+ unsigned len = (~dma_addr & 0xfff) + 1;
+
+ /* Work around hardware bug for unaligned buffers. */
+ if (EFX_WORKAROUND_5391(efx) && (dma_addr & 0xf))
+ len = min_t(unsigned, len, 512 - (dma_addr & 0xf));
+
+ return len;
+}
+
/*
* Add a socket buffer to a TX queue
*
@@ -147,7 +164,7 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue,
skb_frag_t *fragment;
struct page *page;
int page_offset;
- unsigned int len, unmap_len = 0, fill_level, insert_ptr, misalign;
+ unsigned int len, unmap_len = 0, fill_level, insert_ptr;
dma_addr_t dma_addr, unmap_addr = 0;
unsigned int dma_len;
bool unmap_single;
@@ -171,7 +188,7 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue,
}
fill_level = tx_queue->insert_count - tx_queue->old_read_count;
- q_space = efx->type->txd_ring_mask - 1 - fill_level;
+ q_space = EFX_TXQ_MASK - 1 - fill_level;
/* Map for DMA. Use pci_map_single rather than pci_map_page
* since this is more efficient on machines with sparse
@@ -208,16 +225,14 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue,
&tx_queue->read_count;
fill_level = (tx_queue->insert_count
- tx_queue->old_read_count);
- q_space = (efx->type->txd_ring_mask - 1 -
- fill_level);
+ q_space = EFX_TXQ_MASK - 1 - fill_level;
if (unlikely(q_space-- <= 0))
goto stop;
smp_mb();
--tx_queue->stopped;
}
- insert_ptr = (tx_queue->insert_count &
- efx->type->txd_ring_mask);
+ insert_ptr = tx_queue->insert_count & EFX_TXQ_MASK;
buffer = &tx_queue->buffer[insert_ptr];
efx_tsoh_free(tx_queue, buffer);
EFX_BUG_ON_PARANOID(buffer->tsoh);
@@ -226,14 +241,10 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue,
EFX_BUG_ON_PARANOID(!buffer->continuation);
EFX_BUG_ON_PARANOID(buffer->unmap_len);
- dma_len = (((~dma_addr) & efx->type->tx_dma_mask) + 1);
- if (likely(dma_len > len))
+ dma_len = efx_max_tx_len(efx, dma_addr);
+ if (likely(dma_len >= len))
dma_len = len;
- misalign = (unsigned)dma_addr & efx->type->bug5391_mask;
- if (misalign && dma_len + misalign > 512)
- dma_len = 512 - misalign;
-
/* Fill out per descriptor fields */
buffer->len = dma_len;
buffer->dma_addr = dma_addr;
@@ -289,7 +300,7 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue,
/* 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->type->txd_ring_mask;
+ insert_ptr = tx_queue->insert_count & EFX_TXQ_MASK;
buffer = &tx_queue->buffer[insert_ptr];
efx_dequeue_buffer(tx_queue, buffer);
buffer->len = 0;
@@ -318,10 +329,9 @@ static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue,
{
struct efx_nic *efx = tx_queue->efx;
unsigned int stop_index, read_ptr;
- unsigned int mask = tx_queue->efx->type->txd_ring_mask;
- stop_index = (index + 1) & mask;
- read_ptr = tx_queue->read_count & mask;
+ stop_index = (index + 1) & EFX_TXQ_MASK;
+ read_ptr = tx_queue->read_count & EFX_TXQ_MASK;
while (read_ptr != stop_index) {
struct efx_tx_buffer *buffer = &tx_queue->buffer[read_ptr];
@@ -338,7 +348,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 & mask;
+ read_ptr = tx_queue->read_count & EFX_TXQ_MASK;
}
}
@@ -391,7 +401,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->type->txd_ring_mask);
+ EFX_BUG_ON_PARANOID(index > EFX_TXQ_MASK);
efx_dequeue_buffers(tx_queue, index);
@@ -401,7 +411,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_NETDEV_TX_THRESHOLD(tx_queue)) {
+ if (fill_level < EFX_TXQ_THRESHOLD) {
EFX_BUG_ON_PARANOID(!efx_dev_registered(efx));
/* Do this under netif_tx_lock(), to avoid racing
@@ -425,11 +435,11 @@ int efx_probe_tx_queue(struct efx_tx_queue *tx_queue)
EFX_LOG(efx, "creating TX queue %d\n", tx_queue->queue);
/* Allocate software ring */
- txq_size = (efx->type->txd_ring_mask + 1) * sizeof(*tx_queue->buffer);
+ txq_size = EFX_TXQ_SIZE * sizeof(*tx_queue->buffer);
tx_queue->buffer = kzalloc(txq_size, GFP_KERNEL);
if (!tx_queue->buffer)
return -ENOMEM;
- for (i = 0; i <= efx->type->txd_ring_mask; ++i)
+ for (i = 0; i <= EFX_TXQ_MASK; ++i)
tx_queue->buffer[i].continuation = true;
/* Allocate hardware ring */
@@ -468,8 +478,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 &
- tx_queue->efx->type->txd_ring_mask];
+ buffer = &tx_queue->buffer[tx_queue->read_count & EFX_TXQ_MASK];
efx_dequeue_buffer(tx_queue, buffer);
buffer->continuation = true;
buffer->len = 0;
@@ -708,14 +717,14 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue,
{
struct efx_tx_buffer *buffer;
struct efx_nic *efx = tx_queue->efx;
- unsigned dma_len, fill_level, insert_ptr, misalign;
+ unsigned dma_len, fill_level, insert_ptr;
int q_space;
EFX_BUG_ON_PARANOID(len <= 0);
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->type->txd_ring_mask - 1 - fill_level;
+ q_space = EFX_TXQ_MASK - 1 - fill_level;
while (1) {
if (unlikely(q_space-- <= 0)) {
@@ -731,7 +740,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->type->txd_ring_mask - 1 - fill_level;
+ q_space = EFX_TXQ_MASK - 1 - fill_level;
if (unlikely(q_space-- <= 0)) {
*final_buffer = NULL;
return 1;
@@ -740,13 +749,13 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue,
--tx_queue->stopped;
}
- insert_ptr = tx_queue->insert_count & efx->type->txd_ring_mask;
+ insert_ptr = tx_queue->insert_count & EFX_TXQ_MASK;
buffer = &tx_queue->buffer[insert_ptr];
++tx_queue->insert_count;
EFX_BUG_ON_PARANOID(tx_queue->insert_count -
tx_queue->read_count >
- efx->type->txd_ring_mask);
+ EFX_TXQ_MASK);
efx_tsoh_free(tx_queue, buffer);
EFX_BUG_ON_PARANOID(buffer->len);
@@ -757,12 +766,7 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue,
buffer->dma_addr = dma_addr;
- /* Ensure we do not cross a boundary unsupported by H/W */
- dma_len = (~dma_addr & efx->type->tx_dma_mask) + 1;
-
- misalign = (unsigned)dma_addr & efx->type->bug5391_mask;
- if (misalign && dma_len + misalign > 512)
- dma_len = 512 - misalign;
+ dma_len = efx_max_tx_len(efx, dma_addr);
/* If there is enough space to send then do so */
if (dma_len >= len)
@@ -792,8 +796,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 &
- tx_queue->efx->type->txd_ring_mask];
+ buffer = &tx_queue->buffer[tx_queue->insert_count & EFX_TXQ_MASK];
efx_tsoh_free(tx_queue, buffer);
EFX_BUG_ON_PARANOID(buffer->len);
EFX_BUG_ON_PARANOID(buffer->unmap_len);
@@ -818,7 +821,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 &
- tx_queue->efx->type->txd_ring_mask];
+ EFX_TXQ_MASK];
efx_tsoh_free(tx_queue, buffer);
EFX_BUG_ON_PARANOID(buffer->skb);
buffer->len = 0;
@@ -1135,7 +1138,7 @@ static void efx_fini_tso(struct efx_tx_queue *tx_queue)
unsigned i;
if (tx_queue->buffer) {
- for (i = 0; i <= tx_queue->efx->type->txd_ring_mask; ++i)
+ for (i = 0; i <= EFX_TXQ_MASK; ++i)
efx_tsoh_free(tx_queue, &tx_queue->buffer[i]);
}
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
index c821c15445a0..325029949488 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/sfc/workarounds.h
@@ -41,6 +41,8 @@
/* Spurious parity errors in TSORT buffers */
#define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A
+/* Unaligned read request >512 bytes after aligning may break TSORT */
+#define EFX_WORKAROUND_5391 EFX_WORKAROUND_FALCON_A
/* iSCSI parsing errors */
#define EFX_WORKAROUND_5583 EFX_WORKAROUND_FALCON_A
/* RX events go missing */
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index f4dfd1f679a9..6b364a6c6c60 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -365,11 +365,10 @@ static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp
}
skb_reserve(newskb, 2);
} else {
- skb = netdev_alloc_skb(dev, len + 2);
- if (skb) {
- skb_reserve(skb, 2);
+ skb = netdev_alloc_skb_ip_align(dev, len);
+ if (skb)
skb_copy_to_linear_data(skb, rd->skb->data, len);
- }
+
newskb = rd->skb;
}
memory_squeeze:
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index f49d0800c1d1..5783f50d18e9 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -30,6 +30,8 @@
#include <linux/phy.h>
#include <linux/cache.h>
#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <asm/cacheflush.h>
#include "sh_eth.h"
@@ -298,16 +300,20 @@ static void update_mac_address(struct net_device *ndev)
* When you want use this device, you must set MAC address in bootloader.
*
*/
-static void read_mac_address(struct net_device *ndev)
+static void read_mac_address(struct net_device *ndev, unsigned char *mac)
{
u32 ioaddr = ndev->base_addr;
- ndev->dev_addr[0] = (ctrl_inl(ioaddr + MAHR) >> 24);
- ndev->dev_addr[1] = (ctrl_inl(ioaddr + MAHR) >> 16) & 0xFF;
- ndev->dev_addr[2] = (ctrl_inl(ioaddr + MAHR) >> 8) & 0xFF;
- ndev->dev_addr[3] = (ctrl_inl(ioaddr + MAHR) & 0xFF);
- ndev->dev_addr[4] = (ctrl_inl(ioaddr + MALR) >> 8) & 0xFF;
- ndev->dev_addr[5] = (ctrl_inl(ioaddr + MALR) & 0xFF);
+ if (mac[0] || mac[1] || mac[2] || mac[3] || mac[4] || mac[5]) {
+ memcpy(ndev->dev_addr, mac, 6);
+ } else {
+ ndev->dev_addr[0] = (ctrl_inl(ioaddr + MAHR) >> 24);
+ ndev->dev_addr[1] = (ctrl_inl(ioaddr + MAHR) >> 16) & 0xFF;
+ ndev->dev_addr[2] = (ctrl_inl(ioaddr + MAHR) >> 8) & 0xFF;
+ ndev->dev_addr[3] = (ctrl_inl(ioaddr + MAHR) & 0xFF);
+ ndev->dev_addr[4] = (ctrl_inl(ioaddr + MALR) >> 8) & 0xFF;
+ ndev->dev_addr[5] = (ctrl_inl(ioaddr + MALR) & 0xFF);
+ }
}
struct bb_info {
@@ -1008,6 +1014,8 @@ static int sh_eth_open(struct net_device *ndev)
int ret = 0;
struct sh_eth_private *mdp = netdev_priv(ndev);
+ pm_runtime_get_sync(&mdp->pdev->dev);
+
ret = request_irq(ndev->irq, &sh_eth_interrupt,
#if defined(CONFIG_CPU_SUBTYPE_SH7763) || defined(CONFIG_CPU_SUBTYPE_SH7764)
IRQF_SHARED,
@@ -1044,6 +1052,7 @@ static int sh_eth_open(struct net_device *ndev)
out_free_irq:
free_irq(ndev->irq, ndev);
+ pm_runtime_put_sync(&mdp->pdev->dev);
return ret;
}
@@ -1175,6 +1184,8 @@ static int sh_eth_close(struct net_device *ndev)
ringsize = sizeof(struct sh_eth_txdesc) * TX_RING_SIZE;
dma_free_coherent(NULL, ringsize, mdp->tx_ring, mdp->tx_desc_dma);
+ pm_runtime_put_sync(&mdp->pdev->dev);
+
return 0;
}
@@ -1183,6 +1194,8 @@ static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
struct sh_eth_private *mdp = netdev_priv(ndev);
u32 ioaddr = ndev->base_addr;
+ pm_runtime_get_sync(&mdp->pdev->dev);
+
mdp->stats.tx_dropped += ctrl_inl(ioaddr + TROCR);
ctrl_outl(0, ioaddr + TROCR); /* (write clear) */
mdp->stats.collisions += ctrl_inl(ioaddr + CDCR);
@@ -1198,6 +1211,8 @@ static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + CNDCR);
ctrl_outl(0, ioaddr + CNDCR); /* (write clear) */
#endif
+ pm_runtime_put_sync(&mdp->pdev->dev);
+
return &mdp->stats;
}
@@ -1406,6 +1421,9 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
mdp = netdev_priv(ndev);
spin_lock_init(&mdp->lock);
+ mdp->pdev = pdev;
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_resume(&pdev->dev);
pd = (struct sh_eth_plat_data *)(pdev->dev.platform_data);
/* get PHY ID */
@@ -1427,7 +1445,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
mdp->post_fw = POST_FW >> (devno << 1);
/* read and set MAC address */
- read_mac_address(ndev);
+ read_mac_address(ndev, pd->mac_addr);
/* First device only init */
if (!devno) {
@@ -1481,18 +1499,37 @@ static int sh_eth_drv_remove(struct platform_device *pdev)
sh_mdio_release(ndev);
unregister_netdev(ndev);
flush_scheduled_work();
-
+ pm_runtime_disable(&pdev->dev);
free_netdev(ndev);
platform_set_drvdata(pdev, NULL);
return 0;
}
+static int sh_eth_runtime_nop(struct device *dev)
+{
+ /*
+ * Runtime PM callback shared between ->runtime_suspend()
+ * and ->runtime_resume(). Simply returns success.
+ *
+ * This driver re-initializes all registers after
+ * pm_runtime_get_sync() anyway so there is no need
+ * to save and restore registers here.
+ */
+ return 0;
+}
+
+static struct dev_pm_ops sh_eth_dev_pm_ops = {
+ .runtime_suspend = sh_eth_runtime_nop,
+ .runtime_resume = sh_eth_runtime_nop,
+};
+
static struct platform_driver sh_eth_driver = {
.probe = sh_eth_drv_probe,
.remove = sh_eth_drv_remove,
.driver = {
.name = CARDNAME,
+ .pm = &sh_eth_dev_pm_ops,
},
};
diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h
index ba151f86ae7b..8b47763958f2 100644
--- a/drivers/net/sh_eth.h
+++ b/drivers/net/sh_eth.h
@@ -703,6 +703,7 @@ struct sh_eth_cpu_data {
};
struct sh_eth_private {
+ struct platform_device *pdev;
struct sh_eth_cpu_data *cd;
dma_addr_t rx_desc_dma;
dma_addr_t tx_desc_dma;
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index 7cc9898f4e00..31233b4c44a0 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -536,13 +536,12 @@ static bool sis190_try_rx_copy(struct sis190_private *tp,
if (pkt_size >= rx_copybreak)
goto out;
- skb = netdev_alloc_skb(tp->dev, pkt_size + 2);
+ skb = netdev_alloc_skb_ip_align(tp->dev, pkt_size);
if (!skb)
goto out;
pci_dma_sync_single_for_cpu(tp->pci_dev, addr, tp->rx_buf_sz,
PCI_DMA_FROMDEVICE);
- skb_reserve(skb, 2);
skb_copy_to_linear_data(skb, sk_buff[0]->data, pkt_size);
*sk_buff = skb;
done = true;
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 8f5414348e86..ba5eb14094ef 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -3071,11 +3071,10 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
goto error;
if (len < RX_COPY_THRESHOLD) {
- skb = netdev_alloc_skb(dev, len + 2);
+ skb = netdev_alloc_skb_ip_align(dev, len);
if (!skb)
goto resubmit;
- skb_reserve(skb, 2);
pci_dma_sync_single_for_cpu(skge->hw->pdev,
pci_unmap_addr(e, mapaddr),
len, PCI_DMA_FROMDEVICE);
@@ -3086,11 +3085,11 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
skge_rx_reuse(e, skge->rx_buf_size);
} else {
struct sk_buff *nskb;
- nskb = netdev_alloc_skb(dev, skge->rx_buf_size + NET_IP_ALIGN);
+
+ nskb = netdev_alloc_skb_ip_align(dev, skge->rx_buf_size);
if (!nskb)
goto resubmit;
- skb_reserve(nskb, NET_IP_ALIGN);
pci_unmap_single(skge->hw->pdev,
pci_unmap_addr(e, mapaddr),
pci_unmap_len(e, maplen),
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 2ab5c39f33ca..3a449d012d4b 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -2191,9 +2191,8 @@ static struct sk_buff *receive_copy(struct sky2_port *sky2,
{
struct sk_buff *skb;
- skb = netdev_alloc_skb(sky2->netdev, length + 2);
+ skb = netdev_alloc_skb_ip_align(sky2->netdev, length);
if (likely(skb)) {
- skb_reserve(skb, 2);
pci_dma_sync_single_for_cpu(sky2->hw->pdev, re->data_addr,
length, PCI_DMA_FROMDEVICE);
skb_copy_from_linear_data(re->skb, skb->data, length);
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
index ccdd196f5297..6a9f51d1d9f2 100644
--- a/drivers/net/smsc911x.c
+++ b/drivers/net/smsc911x.c
@@ -2071,6 +2071,9 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
if (is_valid_ether_addr(dev->dev_addr)) {
smsc911x_set_hw_mac_address(pdata, dev->dev_addr);
SMSC_TRACE(PROBE, "MAC Address is specified by configuration");
+ } else if (is_valid_ether_addr(pdata->config.mac)) {
+ memcpy(dev->dev_addr, pdata->config.mac, 6);
+ SMSC_TRACE(PROBE, "MAC Address specified by platform data");
} else {
/* Try reading mac address from device. if EEPROM is present
* it will already have been set */
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
index ec9dfb251f30..79d4868e75a6 100644
--- a/drivers/net/tehuti.c
+++ b/drivers/net/tehuti.c
@@ -2105,12 +2105,6 @@ err_pci:
}
/****************** Ethtool interface *********************/
-/* get strings for tests */
-static const char
- bdx_test_names[][ETH_GSTRING_LEN] = {
- "No tests defined"
-};
-
/* get strings for statistics counters */
static const char
bdx_stat_names[][ETH_GSTRING_LEN] = {
@@ -2380,9 +2374,6 @@ bdx_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)
static void bdx_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
{
switch (stringset) {
- case ETH_SS_TEST:
- memcpy(data, *bdx_test_names, sizeof(bdx_test_names));
- break;
case ETH_SS_STATS:
memcpy(data, *bdx_stat_names, sizeof(bdx_stat_names));
break;
@@ -2390,15 +2381,21 @@ static void bdx_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
}
/*
- * bdx_get_stats_count - return number of 64bit statistics counters
+ * bdx_get_sset_count - return number of statistics or tests
* @netdev
*/
-static int bdx_get_stats_count(struct net_device *netdev)
+static int bdx_get_sset_count(struct net_device *netdev, int stringset)
{
struct bdx_priv *priv = netdev_priv(netdev);
- BDX_ASSERT(ARRAY_SIZE(bdx_stat_names)
- != sizeof(struct bdx_stats) / sizeof(u64));
- return ((priv->stats_flag) ? ARRAY_SIZE(bdx_stat_names) : 0);
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ BDX_ASSERT(ARRAY_SIZE(bdx_stat_names)
+ != sizeof(struct bdx_stats) / sizeof(u64));
+ return ((priv->stats_flag) ? ARRAY_SIZE(bdx_stat_names) : 0);
+ default:
+ return -EINVAL;
+ }
}
/*
@@ -2441,7 +2438,7 @@ static void bdx_ethtool_ops(struct net_device *netdev)
.get_sg = ethtool_op_get_sg,
.get_tso = ethtool_op_get_tso,
.get_strings = bdx_get_strings,
- .get_stats_count = bdx_get_stats_count,
+ .get_sset_count = bdx_get_sset_count,
.get_ethtool_stats = bdx_get_ethtool_stats,
};
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index 3d31b47332bb..16f23f84920b 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -1549,7 +1549,8 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int )
if (tmpCStat & TLAN_CSTAT_EOC)
eoc = 1;
- new_skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 );
+ new_skb = netdev_alloc_skb_ip_align(dev,
+ TLAN_MAX_FRAME_SIZE + 5);
if ( !new_skb )
goto drop_and_reuse;
@@ -1563,7 +1564,6 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int )
skb->protocol = eth_type_trans( skb, dev );
netif_rx( skb );
- skb_reserve( new_skb, NET_IP_ALIGN );
head_list->buffer[0].address = pci_map_single(priv->pciDev,
new_skb->data,
TLAN_MAX_FRAME_SIZE,
@@ -1967,13 +1967,12 @@ static void TLan_ResetLists( struct net_device *dev )
list->cStat = TLAN_CSTAT_READY;
list->frameSize = TLAN_MAX_FRAME_SIZE;
list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;
- skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 );
+ skb = netdev_alloc_skb_ip_align(dev, TLAN_MAX_FRAME_SIZE + 5);
if ( !skb ) {
pr_err("TLAN: out of memory for received data.\n" );
break;
}
- skb_reserve( skb, NET_IP_ALIGN );
list->buffer[0].address = pci_map_single(priv->pciDev,
skb->data,
TLAN_MAX_FRAME_SIZE,
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 36cb2423bcf1..03a5d44855f9 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -96,7 +96,7 @@
*
* Change by Mike Sullivan et al.:
* + added turbo card support. No need to use lanaid to configure
- * the adapter into isa compatiblity mode.
+ * the adapter into isa compatibility mode.
*
* Changes by Burt Silverman to allow the computer to behave nicely when
* a cable is pulled or not in place, or a PCMCIA card is removed hot.
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c
index 7030bd5e9848..a69c4a48bab9 100644
--- a/drivers/net/tsi108_eth.c
+++ b/drivers/net/tsi108_eth.c
@@ -802,13 +802,11 @@ static int tsi108_refill_rx(struct net_device *dev, int budget)
int rx = data->rxhead;
struct sk_buff *skb;
- data->rxskbs[rx] = skb = netdev_alloc_skb(dev,
- TSI108_RXBUF_SIZE + 2);
+ skb = netdev_alloc_skb_ip_align(dev, TSI108_RXBUF_SIZE);
+ data->rxskbs[rx] = skb;
if (!skb)
break;
- skb_reserve(skb, 2); /* Align the data on a 4-byte boundary. */
-
data->rxring[rx].buf0 = dma_map_single(NULL, skb->data,
TSI108_RX_SKB_SIZE,
DMA_FROM_DEVICE);
@@ -1356,7 +1354,7 @@ static int tsi108_open(struct net_device *dev)
for (i = 0; i < TSI108_RXRING_LEN; i++) {
struct sk_buff *skb;
- skb = netdev_alloc_skb(dev, TSI108_RXBUF_SIZE + NET_IP_ALIGN);
+ skb = netdev_alloc_skb_ip_align(dev, TSI108_RXBUF_SIZE);
if (!skb) {
/* Bah. No memory for now, but maybe we'll get
* some more later.
@@ -1370,8 +1368,6 @@ static int tsi108_open(struct net_device *dev)
}
data->rxskbs[i] = skb;
- /* Align the payload on a 4-byte boundary */
- skb_reserve(skb, 2);
data->rxskbs[i] = skb;
data->rxring[i].buf0 = virt_to_phys(data->rxskbs[i]->data);
data->rxring[i].misc = TSI108_RX_OWN | TSI108_RX_INT;
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 4fdfa2ae5418..9c59a82784dc 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -44,7 +44,6 @@
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/poll.h>
#include <linux/fcntl.h>
#include <linux/init.h>
@@ -1285,7 +1284,6 @@ static int tun_chr_fasync(int fd, struct file *file, int on)
DBG(KERN_INFO "%s: tun_chr_fasync %d\n", tun->dev->name, on);
- lock_kernel();
if ((ret = fasync_helper(fd, file, on, &tun->fasync)) < 0)
goto out;
@@ -1298,7 +1296,6 @@ static int tun_chr_fasync(int fd, struct file *file, int on)
tun->flags &= ~TUN_FASYNC;
ret = 0;
out:
- unlock_kernel();
tun_put(tun);
return ret;
}
@@ -1306,7 +1303,7 @@ out:
static int tun_chr_open(struct inode *inode, struct file * file)
{
struct tun_file *tfile;
- cycle_kernel_lock();
+
DBG1(KERN_INFO "tunX: tun_chr_open\n");
tfile = kmalloc(sizeof(*tfile), GFP_KERNEL);
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index 4a6aff579403..71e65fc10e6f 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -420,6 +420,14 @@ static const struct driver_info cdc_info = {
.status = cdc_status,
};
+static const struct driver_info mbm_info = {
+ .description = "Mobile Broadband Network Device",
+ .flags = FLAG_WWAN,
+ .bind = cdc_bind,
+ .unbind = usbnet_cdc_unbind,
+ .status = cdc_status,
+};
+
/*-------------------------------------------------------------------------*/
@@ -532,32 +540,32 @@ static const struct usb_device_id products [] = {
/* Ericsson F3507g */
USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1900, USB_CLASS_COMM,
USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
- .driver_info = (unsigned long) &cdc_info,
+ .driver_info = (unsigned long) &mbm_info,
}, {
/* Ericsson F3507g ver. 2 */
USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1902, USB_CLASS_COMM,
USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
- .driver_info = (unsigned long) &cdc_info,
+ .driver_info = (unsigned long) &mbm_info,
}, {
/* Ericsson F3607gw */
USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1904, USB_CLASS_COMM,
USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
- .driver_info = (unsigned long) &cdc_info,
+ .driver_info = (unsigned long) &mbm_info,
}, {
/* Ericsson F3307 */
USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1906, USB_CLASS_COMM,
USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
- .driver_info = (unsigned long) &cdc_info,
+ .driver_info = (unsigned long) &mbm_info,
}, {
/* Toshiba F3507g */
USB_DEVICE_AND_INTERFACE_INFO(0x0930, 0x130b, USB_CLASS_COMM,
USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
- .driver_info = (unsigned long) &cdc_info,
+ .driver_info = (unsigned long) &mbm_info,
}, {
/* Dell F3507g */
USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x8147, USB_CLASS_COMM,
USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
- .driver_info = (unsigned long) &cdc_info,
+ .driver_info = (unsigned long) &mbm_info,
},
{ }, // END
};
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index ca5ca5ae061d..378da8c938fe 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1210,6 +1210,14 @@ static const struct net_device_ops usbnet_netdev_ops = {
// precondition: never called in_interrupt
+static struct device_type wlan_type = {
+ .name = "wlan",
+};
+
+static struct device_type wwan_type = {
+ .name = "wwan",
+};
+
int
usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
{
@@ -1295,6 +1303,9 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
/* WLAN devices should always be named "wlan%d" */
if ((dev->driver_info->flags & FLAG_WLAN) != 0)
strcpy(net->name, "wlan%d");
+ /* WWAN devices should always be named "wwan%d" */
+ if ((dev->driver_info->flags & FLAG_WWAN) != 0)
+ strcpy(net->name, "wwan%d");
/* maybe the remote can't receive an Ethernet MTU */
if (net->mtu > (dev->hard_mtu - net->hard_header_len))
@@ -1322,6 +1333,12 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1);
SET_NETDEV_DEV(net, &udev->dev);
+
+ if ((dev->driver_info->flags & FLAG_WLAN) != 0)
+ SET_NETDEV_DEVTYPE(net, &wlan_type);
+ if ((dev->driver_info->flags & FLAG_WWAN) != 0)
+ SET_NETDEV_DEVTYPE(net, &wwan_type);
+
status = register_netdev (net);
if (status)
goto out3;
diff --git a/drivers/net/vbus-enet.c b/drivers/net/vbus-enet.c
new file mode 100644
index 000000000000..228c366a50a7
--- /dev/null
+++ b/drivers/net/vbus-enet.c
@@ -0,0 +1,1553 @@
+/*
+ * vbus_enet - A virtualized 802.x network device based on the VBUS interface
+ *
+ * Copyright (C) 2009 Novell, Gregory Haskins <ghaskins@novell.com>
+ *
+ * Derived from the SNULL example from the book "Linux Device Drivers" by
+ * Alessandro Rubini, Jonathan Corbet, and Greg Kroah-Hartman, published
+ * by O'Reilly & Associates.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+
+#include <linux/in.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/skbuff.h>
+#include <linux/ioq.h>
+#include <linux/vbus_driver.h>
+
+#include <linux/in6.h>
+#include <asm/checksum.h>
+
+#include <linux/venet.h>
+
+MODULE_AUTHOR("Gregory Haskins");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("virtual-ethernet");
+MODULE_VERSION("1");
+
+static int rx_ringlen = 256;
+module_param(rx_ringlen, int, 0444);
+static int tx_ringlen = 256;
+module_param(tx_ringlen, int, 0444);
+static int sg_enabled = 1;
+module_param(sg_enabled, int, 0444);
+
+#define PDEBUG(_dev, fmt, args...) dev_dbg(&(_dev)->dev, fmt, ## args)
+
+#define SG_DESC_SIZE VSG_DESC_SIZE(MAX_SKB_FRAGS)
+
+struct vbus_enet_queue {
+ struct ioq *queue;
+ struct ioq_notifier notifier;
+ unsigned long count;
+};
+
+struct vbus_enet_priv {
+ spinlock_t lock;
+ struct net_device *dev;
+ struct vbus_device_proxy *vdev;
+ struct napi_struct napi;
+ struct vbus_enet_queue rxq;
+ struct {
+ struct vbus_enet_queue veq;
+ struct tasklet_struct task;
+ struct sk_buff_head outstanding;
+ } tx;
+ bool sg;
+ struct {
+ bool enabled;
+ char *pool;
+ } pmtd; /* pre-mapped transmit descriptors */
+ struct {
+ bool enabled;
+ bool linkstate;
+ bool txc;
+ unsigned long evsize;
+ struct vbus_enet_queue veq;
+ struct tasklet_struct task;
+ char *pool;
+ } evq;
+ struct {
+ bool available;
+ char *pool;
+ struct vbus_enet_queue pageq;
+ } l4ro;
+
+ struct sk_buff *(*import)(struct vbus_enet_priv *priv,
+ struct ioq_ring_desc *desc);
+};
+
+static void vbus_enet_tx_reap(struct vbus_enet_priv *priv);
+
+static struct vbus_enet_priv *
+napi_to_priv(struct napi_struct *napi)
+{
+ return container_of(napi, struct vbus_enet_priv, napi);
+}
+
+static int
+queue_init(struct vbus_enet_priv *priv,
+ struct vbus_enet_queue *q,
+ const char *name,
+ int qid,
+ size_t ringsize,
+ void (*func)(struct ioq_notifier *))
+{
+ struct vbus_device_proxy *dev = priv->vdev;
+ int ret;
+ char _name[64];
+
+ if (name)
+ snprintf(_name, sizeof(_name), "%s-%s", priv->dev->name, name);
+
+ ret = vbus_driver_ioq_alloc(dev, name ? _name : NULL, qid, 0,
+ ringsize, &q->queue);
+ if (ret < 0)
+ panic("ioq_alloc failed: %d\n", ret);
+
+ if (func) {
+ q->notifier.signal = func;
+ q->queue->notifier = &q->notifier;
+ }
+
+ q->count = ringsize;
+
+ return 0;
+}
+
+static int
+devcall(struct vbus_enet_priv *priv, u32 func, void *data, size_t len)
+{
+ struct vbus_device_proxy *dev = priv->vdev;
+
+ return dev->ops->call(dev, func, data, len, 0);
+}
+
+/*
+ * ---------------
+ * rx descriptors
+ * ---------------
+ */
+
+static void
+rxdesc_alloc(struct vbus_enet_priv *priv, struct ioq_ring_desc *desc, size_t len)
+{
+ struct net_device *dev = priv->dev;
+ struct sk_buff *skb;
+
+ len += ETH_HLEN;
+
+ skb = netdev_alloc_skb(dev, len + NET_IP_ALIGN);
+ BUG_ON(!skb);
+
+ skb_reserve(skb, NET_IP_ALIGN); /* align IP on 16B boundary */
+
+ if (priv->l4ro.available) {
+ /*
+ * We will populate an SG descriptor initially with one
+ * IOV filled with an MTU SKB. If the packet needs to be
+ * larger than MTU, the host will grab pages out of the
+ * page-queue and populate additional IOVs
+ */
+ struct venet_sg *vsg = (struct venet_sg *)desc->cookie;
+ struct venet_iov *iov = &vsg->iov[0];
+
+ memset(vsg, 0, SG_DESC_SIZE);
+
+ vsg->cookie = (u64)skb;
+ vsg->count = 1;
+
+ iov->ptr = (u64)__pa(skb->data);
+ iov->len = len;
+ } else {
+ desc->cookie = (u64)skb;
+ desc->ptr = (u64)__pa(skb->data);
+ desc->len = len; /* total length */
+ }
+
+ desc->valid = 1;
+}
+
+static void
+rx_pageq_refill(struct vbus_enet_priv *priv)
+{
+ struct ioq *ioq = priv->l4ro.pageq.queue;
+ struct ioq_iterator iter;
+ int ret;
+
+ if (ioq_full(ioq, ioq_idxtype_inuse))
+ /* nothing to do if the pageq is already fully populated */
+ return;
+
+ ret = ioq_iter_init(ioq, &iter, ioq_idxtype_inuse, 0);
+ BUG_ON(ret < 0); /* will never fail unless seriously broken */
+
+ ret = ioq_iter_seek(&iter, ioq_seek_tail, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * Now populate each descriptor with an empty page
+ */
+ while (!iter.desc->sown) {
+ struct page *page;
+
+ page = alloc_page(GFP_KERNEL);
+ BUG_ON(!page);
+
+ iter.desc->cookie = (u64)page;
+ iter.desc->ptr = (u64)__pa(page_address(page));
+ iter.desc->len = PAGE_SIZE;
+
+ ret = ioq_iter_push(&iter, 0);
+ BUG_ON(ret < 0);
+ }
+
+ ioq_signal(ioq, 0);
+}
+
+static void
+rx_setup(struct vbus_enet_priv *priv)
+{
+ struct ioq *ioq = priv->rxq.queue;
+ struct ioq_iterator iter;
+ int ret;
+ int i = 0;
+
+ /*
+ * We want to iterate on the "valid" index. By default the iterator
+ * will not "autoupdate" which means it will not hypercall the host
+ * with our changes. This is good, because we are really just
+ * initializing stuff here anyway. Note that you can always manually
+ * signal the host with ioq_signal() if the autoupdate feature is not
+ * used.
+ */
+ ret = ioq_iter_init(ioq, &iter, ioq_idxtype_valid, 0);
+ BUG_ON(ret < 0); /* will never fail unless seriously broken */
+
+ /*
+ * Seek to the tail of the valid index (which should be our first
+ * item, since the queue is brand-new)
+ */
+ ret = ioq_iter_seek(&iter, ioq_seek_tail, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * Now populate each descriptor with an empty buffer and mark it valid
+ */
+ while (!iter.desc->valid) {
+ if (priv->l4ro.available) {
+ size_t offset = (i * SG_DESC_SIZE);
+ void *addr = &priv->l4ro.pool[offset];
+
+ iter.desc->ptr = (u64)offset;
+ iter.desc->cookie = (u64)addr;
+ iter.desc->len = SG_DESC_SIZE;
+ }
+
+ rxdesc_alloc(priv, iter.desc, priv->dev->mtu);
+
+ /*
+ * This push operation will simultaneously advance the
+ * valid-head index and increment our position in the queue
+ * by one.
+ */
+ ret = ioq_iter_push(&iter, 0);
+ BUG_ON(ret < 0);
+
+ i++;
+ }
+
+ if (priv->l4ro.available)
+ rx_pageq_refill(priv);
+}
+
+static void
+rx_rxq_teardown(struct vbus_enet_priv *priv)
+{
+ struct ioq *ioq = priv->rxq.queue;
+ struct ioq_iterator iter;
+ int ret;
+
+ ret = ioq_iter_init(ioq, &iter, ioq_idxtype_valid, 0);
+ BUG_ON(ret < 0);
+
+ ret = ioq_iter_seek(&iter, ioq_seek_head, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * free each valid descriptor
+ */
+ while (iter.desc->valid) {
+ struct sk_buff *skb;
+
+ if (priv->l4ro.available) {
+ struct venet_sg *vsg;
+ int i;
+
+ vsg = (struct venet_sg *)iter.desc->cookie;
+
+ /* skip i=0, since that is the skb->data IOV */
+ for (i = 1; i < vsg->count; i++) {
+ struct venet_iov *iov = &vsg->iov[i];
+ struct page *page = (struct page *)iov->ptr;
+
+ put_page(page);
+ }
+
+ skb = (struct sk_buff *)vsg->cookie;
+ } else
+ skb = (struct sk_buff *)iter.desc->cookie;
+
+ iter.desc->valid = 0;
+ wmb();
+
+ iter.desc->ptr = 0;
+ iter.desc->cookie = 0;
+
+ ret = ioq_iter_pop(&iter, 0);
+ BUG_ON(ret < 0);
+
+ dev_kfree_skb(skb);
+ }
+}
+
+static void
+rx_l4ro_teardown(struct vbus_enet_priv *priv)
+{
+ struct ioq *ioq = priv->l4ro.pageq.queue;
+ struct ioq_iterator iter;
+ int ret;
+
+ ret = ioq_iter_init(ioq, &iter, ioq_idxtype_inuse, 0);
+ BUG_ON(ret < 0);
+
+ ret = ioq_iter_seek(&iter, ioq_seek_head, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * free each valid descriptor
+ */
+ while (iter.desc->sown) {
+ struct page *page = (struct page *)iter.desc->cookie;
+
+ iter.desc->valid = 0;
+ wmb();
+
+ iter.desc->ptr = 0;
+ iter.desc->cookie = 0;
+
+ ret = ioq_iter_pop(&iter, 0);
+ BUG_ON(ret < 0);
+
+ put_page(page);
+ }
+
+ ioq_put(ioq);
+ kfree(priv->l4ro.pool);
+}
+
+static void
+rx_teardown(struct vbus_enet_priv *priv)
+{
+ rx_rxq_teardown(priv);
+
+ if (priv->l4ro.available)
+ rx_l4ro_teardown(priv);
+}
+
+static int
+tx_setup(struct vbus_enet_priv *priv)
+{
+ struct ioq *ioq = priv->tx.veq.queue;
+ struct ioq_iterator iter;
+ int i;
+ int ret;
+
+ if (!priv->sg)
+ /*
+ * There is nothing to do for a ring that is not using
+ * scatter-gather
+ */
+ return 0;
+
+ /* pre-allocate our descriptor pool if pmtd is enabled */
+ if (priv->pmtd.enabled) {
+ struct vbus_device_proxy *dev = priv->vdev;
+ size_t poollen = SG_DESC_SIZE * priv->tx.veq.count;
+ char *pool;
+ int shmid;
+
+ /* pmtdquery will return the shm-id to use for the pool */
+ ret = devcall(priv, VENET_FUNC_PMTDQUERY, NULL, 0);
+ BUG_ON(ret < 0);
+
+ shmid = ret;
+
+ pool = kzalloc(poollen, GFP_KERNEL | GFP_DMA);
+ if (!pool)
+ return -ENOMEM;
+
+ priv->pmtd.pool = pool;
+
+ ret = dev->ops->shm(dev, NULL, shmid, 0, pool, poollen,
+ 0, NULL, 0);
+ BUG_ON(ret < 0);
+ }
+
+ ret = ioq_iter_init(ioq, &iter, ioq_idxtype_valid, 0);
+ BUG_ON(ret < 0);
+
+ ret = ioq_iter_seek(&iter, ioq_seek_set, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * Now populate each descriptor with an empty SG descriptor
+ */
+ for (i = 0; i < priv->tx.veq.count; i++) {
+ struct venet_sg *vsg;
+
+ if (priv->pmtd.enabled) {
+ size_t offset = (i * SG_DESC_SIZE);
+
+ vsg = (struct venet_sg *)&priv->pmtd.pool[offset];
+ iter.desc->ptr = (u64)offset;
+ } else {
+ vsg = kzalloc(SG_DESC_SIZE, GFP_KERNEL);
+ if (!vsg)
+ return -ENOMEM;
+
+ iter.desc->ptr = (u64)__pa(vsg);
+ }
+
+ iter.desc->cookie = (u64)vsg;
+ iter.desc->len = SG_DESC_SIZE;
+
+ ret = ioq_iter_seek(&iter, ioq_seek_next, 0, 0);
+ BUG_ON(ret < 0);
+ }
+
+ return 0;
+}
+
+static void
+tx_teardown(struct vbus_enet_priv *priv)
+{
+ struct ioq *ioq = priv->tx.veq.queue;
+ struct ioq_iterator iter;
+ struct sk_buff *skb;
+ int ret;
+
+ /* forcefully free all outstanding transmissions */
+ while ((skb = __skb_dequeue(&priv->tx.outstanding)))
+ dev_kfree_skb(skb);
+
+ if (!priv->sg)
+ /*
+ * There is nothing else to do for a ring that is not using
+ * scatter-gather
+ */
+ return;
+
+ if (priv->pmtd.enabled) {
+ /*
+ * PMTD mode means we only need to free the pool
+ */
+ kfree(priv->pmtd.pool);
+ return;
+ }
+
+ ret = ioq_iter_init(ioq, &iter, ioq_idxtype_valid, 0);
+ BUG_ON(ret < 0);
+
+ /* seek to position 0 */
+ ret = ioq_iter_seek(&iter, ioq_seek_set, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * free each valid descriptor
+ */
+ while (iter.desc->cookie) {
+ struct venet_sg *vsg = (struct venet_sg *)iter.desc->cookie;
+
+ iter.desc->valid = 0;
+ wmb();
+
+ iter.desc->ptr = 0;
+ iter.desc->cookie = 0;
+
+ ret = ioq_iter_seek(&iter, ioq_seek_next, 0, 0);
+ BUG_ON(ret < 0);
+
+ kfree(vsg);
+ }
+}
+
+static void
+evq_teardown(struct vbus_enet_priv *priv)
+{
+ if (!priv->evq.enabled)
+ return;
+
+ ioq_put(priv->evq.veq.queue);
+ kfree(priv->evq.pool);
+}
+
+/*
+ * Open and close
+ */
+
+static int
+vbus_enet_open(struct net_device *dev)
+{
+ struct vbus_enet_priv *priv = netdev_priv(dev);
+ int ret;
+
+ ret = devcall(priv, VENET_FUNC_LINKUP, NULL, 0);
+ BUG_ON(ret < 0);
+
+ napi_enable(&priv->napi);
+
+ return 0;
+}
+
+static int
+vbus_enet_stop(struct net_device *dev)
+{
+ struct vbus_enet_priv *priv = netdev_priv(dev);
+ int ret;
+
+ napi_disable(&priv->napi);
+
+ ret = devcall(priv, VENET_FUNC_LINKDOWN, NULL, 0);
+ BUG_ON(ret < 0);
+
+ return 0;
+}
+
+/*
+ * Configuration changes (passed on by ifconfig)
+ */
+static int
+vbus_enet_config(struct net_device *dev, struct ifmap *map)
+{
+ if (dev->flags & IFF_UP) /* can't act on a running interface */
+ return -EBUSY;
+
+ /* Don't allow changing the I/O address */
+ if (map->base_addr != dev->base_addr) {
+ dev_warn(&dev->dev, "Can't change I/O address\n");
+ return -EOPNOTSUPP;
+ }
+
+ /* ignore other fields */
+ return 0;
+}
+
+static void
+vbus_enet_schedule_rx(struct vbus_enet_priv *priv)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (napi_schedule_prep(&priv->napi)) {
+ /* Disable further interrupts */
+ ioq_notify_disable(priv->rxq.queue, 0);
+ __napi_schedule(&priv->napi);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int
+vbus_enet_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct vbus_enet_priv *priv = netdev_priv(dev);
+ int ret;
+
+ dev->mtu = new_mtu;
+
+ /*
+ * FLUSHRX will cause the device to flush any outstanding
+ * RX buffers. They will appear to come in as 0 length
+ * packets which we can simply discard and replace with new_mtu
+ * buffers for the future.
+ */
+ ret = devcall(priv, VENET_FUNC_FLUSHRX, NULL, 0);
+ BUG_ON(ret < 0);
+
+ vbus_enet_schedule_rx(priv);
+
+ return 0;
+}
+
+static struct sk_buff *
+vbus_enet_l4ro_import(struct vbus_enet_priv *priv, struct ioq_ring_desc *desc)
+{
+ struct venet_sg *vsg = (struct venet_sg *)desc->cookie;
+ struct sk_buff *skb = (struct sk_buff *)vsg->cookie;
+ struct skb_shared_info *sinfo = skb_shinfo(skb);
+ int i;
+
+ rx_pageq_refill(priv);
+
+ if (!vsg->len)
+ /*
+ * the device may send a zero-length packet when its
+ * flushing references on the ring. We can just drop
+ * these on the floor
+ */
+ goto fail;
+
+ /* advance only by the linear portion in IOV[0] */
+ skb_put(skb, vsg->iov[0].len);
+
+ /* skip i=0, since that is the skb->data IOV */
+ for (i = 1; i < vsg->count; i++) {
+ struct venet_iov *iov = &vsg->iov[i];
+ struct page *page = (struct page *)iov->ptr;
+ skb_frag_t *f = &sinfo->frags[i-1];
+
+ f->page = page;
+ f->page_offset = 0;
+ f->size = iov->len;
+
+ PDEBUG(priv->dev, "SG: Importing %d byte page[%i]\n",
+ f->size, i);
+
+ skb->data_len += f->size;
+ skb->len += f->size;
+ skb->truesize += f->size;
+ sinfo->nr_frags++;
+ }
+
+ if (vsg->flags & VENET_SG_FLAG_NEEDS_CSUM
+ && !skb_partial_csum_set(skb, vsg->csum.start,
+ vsg->csum.offset)) {
+ priv->dev->stats.rx_frame_errors++;
+ goto fail;
+ }
+
+ if (vsg->flags & VENET_SG_FLAG_GSO) {
+ PDEBUG(priv->dev, "L4RO packet detected\n");
+
+ switch (vsg->gso.type) {
+ case VENET_GSO_TYPE_TCPV4:
+ sinfo->gso_type = SKB_GSO_TCPV4;
+ break;
+ case VENET_GSO_TYPE_TCPV6:
+ sinfo->gso_type = SKB_GSO_TCPV6;
+ break;
+ case VENET_GSO_TYPE_UDP:
+ sinfo->gso_type = SKB_GSO_UDP;
+ break;
+ default:
+ PDEBUG(priv->dev, "Illegal L4RO type: %d\n",
+ vsg->gso.type);
+ priv->dev->stats.rx_frame_errors++;
+ goto fail;
+ }
+
+ if (vsg->flags & VENET_SG_FLAG_ECN)
+ sinfo->gso_type |= SKB_GSO_TCP_ECN;
+
+ sinfo->gso_size = vsg->gso.size;
+ if (sinfo->gso_size == 0) {
+ PDEBUG(priv->dev, "Illegal L4RO size: %d\n",
+ vsg->gso.size);
+ priv->dev->stats.rx_frame_errors++;
+ goto fail;
+ }
+
+ /*
+ * Header must be checked, and gso_segs
+ * computed.
+ */
+ sinfo->gso_type |= SKB_GSO_DODGY;
+ sinfo->gso_segs = 0;
+ }
+
+ return skb;
+
+fail:
+ dev_kfree_skb(skb);
+
+ return NULL;
+}
+
+static struct sk_buff *
+vbus_enet_flat_import(struct vbus_enet_priv *priv, struct ioq_ring_desc *desc)
+{
+ struct sk_buff *skb = (struct sk_buff *)desc->cookie;
+
+ if (!desc->len) {
+ /*
+ * the device may send a zero-length packet when its
+ * flushing references on the ring. We can just drop
+ * these on the floor
+ */
+ dev_kfree_skb(skb);
+ return NULL;
+ }
+
+ skb_put(skb, desc->len);
+
+ return skb;
+}
+
+/*
+ * The poll implementation.
+ */
+static int
+vbus_enet_poll(struct napi_struct *napi, int budget)
+{
+ struct vbus_enet_priv *priv = napi_to_priv(napi);
+ int npackets = 0;
+ struct ioq_iterator iter;
+ int ret;
+
+ PDEBUG(priv->dev, "polling...\n");
+
+ /* We want to iterate on the head of the in-use index */
+ ret = ioq_iter_init(priv->rxq.queue, &iter, ioq_idxtype_inuse,
+ IOQ_ITER_AUTOUPDATE);
+ BUG_ON(ret < 0);
+
+ ret = ioq_iter_seek(&iter, ioq_seek_head, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * We stop if we have met the quota or there are no more packets.
+ * The EOM is indicated by finding a packet that is still owned by
+ * the south side
+ */
+ while ((npackets < budget) && (!iter.desc->sown)) {
+ struct sk_buff *skb;
+
+ skb = priv->import(priv, iter.desc);
+ if (skb) {
+ /* Maintain stats */
+ npackets++;
+ priv->dev->stats.rx_packets++;
+ priv->dev->stats.rx_bytes += skb->len;
+
+ /* Pass the buffer up to the stack */
+ skb->dev = priv->dev;
+ skb->protocol = eth_type_trans(skb, priv->dev);
+ netif_receive_skb(skb);
+
+ mb();
+ }
+
+ /* Grab a new buffer to put in the ring */
+ rxdesc_alloc(priv, iter.desc, priv->dev->mtu);
+
+ /* Advance the in-use tail */
+ ret = ioq_iter_pop(&iter, 0);
+ BUG_ON(ret < 0);
+ }
+
+ PDEBUG(priv->dev, "%d packets received\n", npackets);
+
+ /*
+ * If we processed all packets, we're done; tell the kernel and
+ * reenable ints
+ */
+ if (ioq_empty(priv->rxq.queue, ioq_idxtype_inuse)) {
+ napi_complete(napi);
+ ioq_notify_enable(priv->rxq.queue, 0);
+ ret = 0;
+ } else
+ /* We couldn't process everything. */
+ ret = 1;
+
+ return ret;
+}
+
+/*
+ * Transmit a packet (called by the kernel)
+ */
+static int
+vbus_enet_tx_start(struct sk_buff *skb, struct net_device *dev)
+{
+ struct vbus_enet_priv *priv = netdev_priv(dev);
+ struct ioq_iterator iter;
+ int ret;
+ unsigned long flags;
+
+ PDEBUG(priv->dev, "sending %d bytes\n", skb->len);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (ioq_full(priv->tx.veq.queue, ioq_idxtype_valid)) {
+ /*
+ * We must flow-control the kernel by disabling the
+ * queue
+ */
+ spin_unlock_irqrestore(&priv->lock, flags);
+ netif_stop_queue(dev);
+ dev_err(&priv->dev->dev, "tx on full queue bug\n");
+ return 1;
+ }
+
+ /*
+ * We want to iterate on the tail of both the "inuse" and "valid" index
+ * so we specify the "both" index
+ */
+ ret = ioq_iter_init(priv->tx.veq.queue, &iter, ioq_idxtype_both,
+ IOQ_ITER_AUTOUPDATE);
+ BUG_ON(ret < 0);
+
+ ret = ioq_iter_seek(&iter, ioq_seek_tail, 0, 0);
+ BUG_ON(ret < 0);
+ BUG_ON(iter.desc->sown);
+
+ if (priv->sg) {
+ struct venet_sg *vsg = (struct venet_sg *)iter.desc->cookie;
+ struct scatterlist sgl[MAX_SKB_FRAGS+1];
+ struct scatterlist *sg;
+ int count, maxcount = ARRAY_SIZE(sgl);
+
+ sg_init_table(sgl, maxcount);
+
+ memset(vsg, 0, sizeof(*vsg));
+
+ vsg->cookie = (u64)skb;
+ vsg->len = skb->len;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ vsg->flags |= VENET_SG_FLAG_NEEDS_CSUM;
+ vsg->csum.start = skb->csum_start - skb_headroom(skb);
+ vsg->csum.offset = skb->csum_offset;
+ }
+
+ if (skb_is_gso(skb)) {
+ struct skb_shared_info *sinfo = skb_shinfo(skb);
+
+ vsg->flags |= VENET_SG_FLAG_GSO;
+
+ vsg->gso.hdrlen = skb_headlen(skb);
+ vsg->gso.size = sinfo->gso_size;
+ if (sinfo->gso_type & SKB_GSO_TCPV4)
+ vsg->gso.type = VENET_GSO_TYPE_TCPV4;
+ else if (sinfo->gso_type & SKB_GSO_TCPV6)
+ vsg->gso.type = VENET_GSO_TYPE_TCPV6;
+ else if (sinfo->gso_type & SKB_GSO_UDP)
+ vsg->gso.type = VENET_GSO_TYPE_UDP;
+ else
+ panic("Virtual-Ethernet: unknown GSO type " \
+ "0x%x\n", sinfo->gso_type);
+
+ if (sinfo->gso_type & SKB_GSO_TCP_ECN)
+ vsg->flags |= VENET_SG_FLAG_ECN;
+ }
+
+ count = skb_to_sgvec(skb, sgl, 0, skb->len);
+
+ BUG_ON(count > maxcount);
+
+ for (sg = &sgl[0]; sg; sg = sg_next(sg)) {
+ struct venet_iov *iov = &vsg->iov[vsg->count++];
+
+ iov->len = sg->length;
+ iov->ptr = (u64)sg_phys(sg);
+ }
+
+ iter.desc->len = (u64)VSG_DESC_SIZE(vsg->count);
+
+ } else {
+ /*
+ * non scatter-gather mode: simply put the skb right onto the
+ * ring.
+ */
+ iter.desc->cookie = (u64)skb;
+ iter.desc->len = (u64)skb->len;
+ iter.desc->ptr = (u64)__pa(skb->data);
+ }
+
+ iter.desc->valid = 1;
+
+ priv->dev->stats.tx_packets++;
+ priv->dev->stats.tx_bytes += skb->len;
+
+ skb_queue_tail(&priv->tx.outstanding, skb);
+
+ /*
+ * This advances both indexes together implicitly, and then
+ * signals the south side to consume the packet
+ */
+ ret = ioq_iter_push(&iter, 0);
+ BUG_ON(ret < 0);
+
+ dev->trans_start = jiffies; /* save the timestamp */
+
+ if (ioq_full(priv->tx.veq.queue, ioq_idxtype_valid)) {
+ /*
+ * If the queue is congested, we must flow-control the kernel
+ */
+ PDEBUG(priv->dev, "backpressure tx queue\n");
+ netif_stop_queue(dev);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+/* assumes priv->lock held */
+static void
+vbus_enet_skb_complete(struct vbus_enet_priv *priv, struct sk_buff *skb)
+{
+ PDEBUG(priv->dev, "completed sending %d bytes\n",
+ skb->len);
+
+ skb_unlink(skb, &priv->tx.outstanding);
+ dev_kfree_skb(skb);
+}
+
+/*
+ * reclaim any outstanding completed tx packets
+ *
+ * assumes priv->lock held
+ */
+static struct sk_buff *
+vbus_enet_tx_reap_one(struct vbus_enet_priv *priv)
+{
+ struct sk_buff *skb = NULL;
+ struct ioq_iterator iter;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /*
+ * We want to iterate on the head of the valid index, but we
+ * do not want the iter_pop (below) to flip the ownership, so
+ * we set the NOFLIPOWNER option
+ */
+ ret = ioq_iter_init(priv->tx.veq.queue, &iter, ioq_idxtype_valid,
+ IOQ_ITER_NOFLIPOWNER);
+ BUG_ON(ret < 0);
+
+ ret = ioq_iter_seek(&iter, ioq_seek_head, 0, 0);
+ BUG_ON(ret < 0);
+
+ if (iter.desc->valid && !iter.desc->sown) {
+
+ if (priv->sg) {
+ struct venet_sg *vsg;
+
+ vsg = (struct venet_sg *)iter.desc->cookie;
+ skb = (struct sk_buff *)vsg->cookie;
+ } else
+ skb = (struct sk_buff *)iter.desc->cookie;
+
+ /* Reset the descriptor */
+ iter.desc->valid = 0;
+
+ /* Advance the valid-index head */
+ ret = ioq_iter_pop(&iter, 0);
+ BUG_ON(ret < 0);
+ }
+
+ /*
+ * If we were previously stopped due to flow control, restart the
+ * processing
+ */
+ if (netif_queue_stopped(priv->dev)
+ && !ioq_full(priv->tx.veq.queue, ioq_idxtype_valid)) {
+ PDEBUG(priv->dev, "re-enabling tx queue\n");
+ netif_wake_queue(priv->dev);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return skb;
+}
+
+static void
+vbus_enet_tx_reap(struct vbus_enet_priv *priv)
+{
+ struct sk_buff *skb;
+
+ while ((skb = vbus_enet_tx_reap_one(priv))) {
+ if (!priv->evq.txc)
+ /*
+ * We are responsible for freeing the packet upon
+ * reap if TXC is not enabled
+ */
+ vbus_enet_skb_complete(priv, skb);
+ }
+}
+
+static void
+vbus_enet_timeout(struct net_device *dev)
+{
+ struct vbus_enet_priv *priv = netdev_priv(dev);
+
+ dev_dbg(&dev->dev, "Transmit timeout\n");
+
+ vbus_enet_tx_reap(priv);
+}
+
+static void
+rx_isr(struct ioq_notifier *notifier)
+{
+ struct vbus_enet_priv *priv;
+ struct net_device *dev;
+
+ priv = container_of(notifier, struct vbus_enet_priv, rxq.notifier);
+ dev = priv->dev;
+
+ if (!ioq_empty(priv->rxq.queue, ioq_idxtype_inuse))
+ vbus_enet_schedule_rx(priv);
+}
+
+static void
+deferred_tx_isr(unsigned long data)
+{
+ struct vbus_enet_priv *priv = (struct vbus_enet_priv *)data;
+
+ PDEBUG(priv->dev, "deferred_tx_isr\n");
+
+ vbus_enet_tx_reap(priv);
+
+ ioq_notify_enable(priv->tx.veq.queue, 0);
+}
+
+static void
+tx_isr(struct ioq_notifier *notifier)
+{
+ struct vbus_enet_priv *priv;
+
+ priv = container_of(notifier, struct vbus_enet_priv, tx.veq.notifier);
+
+ PDEBUG(priv->dev, "tx_isr\n");
+
+ ioq_notify_disable(priv->tx.veq.queue, 0);
+ tasklet_schedule(&priv->tx.task);
+}
+
+static void
+evq_linkstate_event(struct vbus_enet_priv *priv,
+ struct venet_event_header *header)
+{
+ struct venet_event_linkstate *event =
+ (struct venet_event_linkstate *)header;
+
+ switch (event->state) {
+ case 0:
+ netif_carrier_off(priv->dev);
+ break;
+ case 1:
+ netif_carrier_on(priv->dev);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+evq_txc_event(struct vbus_enet_priv *priv,
+ struct venet_event_header *header)
+{
+ struct venet_event_txc *event =
+ (struct venet_event_txc *)header;
+
+ vbus_enet_tx_reap(priv);
+
+ vbus_enet_skb_complete(priv, (struct sk_buff *)event->cookie);
+}
+
+static void
+deferred_evq_isr(unsigned long data)
+{
+ struct vbus_enet_priv *priv = (struct vbus_enet_priv *)data;
+ int nevents = 0;
+ struct ioq_iterator iter;
+ int ret;
+
+ PDEBUG(priv->dev, "evq: polling...\n");
+
+ /* We want to iterate on the head of the in-use index */
+ ret = ioq_iter_init(priv->evq.veq.queue, &iter, ioq_idxtype_inuse,
+ IOQ_ITER_AUTOUPDATE);
+ BUG_ON(ret < 0);
+
+ ret = ioq_iter_seek(&iter, ioq_seek_head, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * The EOM is indicated by finding a packet that is still owned by
+ * the south side
+ */
+ while (!iter.desc->sown) {
+ struct venet_event_header *header;
+
+ header = (struct venet_event_header *)iter.desc->cookie;
+
+ switch (header->id) {
+ case VENET_EVENT_LINKSTATE:
+ evq_linkstate_event(priv, header);
+ break;
+ case VENET_EVENT_TXC:
+ evq_txc_event(priv, header);
+ break;
+ default:
+ panic("venet: unexpected event id:%d of size %d\n",
+ header->id, header->size);
+ break;
+ }
+
+ memset((void *)iter.desc->cookie, 0, priv->evq.evsize);
+
+ /* Advance the in-use tail */
+ ret = ioq_iter_pop(&iter, 0);
+ BUG_ON(ret < 0);
+
+ nevents++;
+ }
+
+ PDEBUG(priv->dev, "%d events received\n", nevents);
+
+ ioq_notify_enable(priv->evq.veq.queue, 0);
+}
+
+static void
+evq_isr(struct ioq_notifier *notifier)
+{
+ struct vbus_enet_priv *priv;
+
+ priv = container_of(notifier, struct vbus_enet_priv, evq.veq.notifier);
+
+ PDEBUG(priv->dev, "evq_isr\n");
+
+ ioq_notify_disable(priv->evq.veq.queue, 0);
+ tasklet_schedule(&priv->evq.task);
+}
+
+static int
+vbus_enet_sg_negcap(struct vbus_enet_priv *priv)
+{
+ struct net_device *dev = priv->dev;
+ struct venet_capabilities caps;
+ int ret;
+
+ memset(&caps, 0, sizeof(caps));
+
+ if (sg_enabled) {
+ caps.gid = VENET_CAP_GROUP_SG;
+ caps.bits |= (VENET_CAP_SG|VENET_CAP_TSO4|VENET_CAP_TSO6
+ |VENET_CAP_ECN|VENET_CAP_PMTD);
+ /* note: exclude UFO for now due to stack bug */
+ }
+
+ ret = devcall(priv, VENET_FUNC_NEGCAP, &caps, sizeof(caps));
+ if (ret < 0)
+ return ret;
+
+ if (caps.bits & VENET_CAP_SG) {
+ priv->sg = true;
+
+ dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM|NETIF_F_FRAGLIST;
+
+ if (caps.bits & VENET_CAP_TSO4)
+ dev->features |= NETIF_F_TSO;
+ if (caps.bits & VENET_CAP_UFO)
+ dev->features |= NETIF_F_UFO;
+ if (caps.bits & VENET_CAP_TSO6)
+ dev->features |= NETIF_F_TSO6;
+ if (caps.bits & VENET_CAP_ECN)
+ dev->features |= NETIF_F_TSO_ECN;
+
+ if (caps.bits & VENET_CAP_PMTD)
+ priv->pmtd.enabled = true;
+ }
+
+ return 0;
+}
+
+static int
+vbus_enet_evq_negcap(struct vbus_enet_priv *priv, unsigned long count)
+{
+ struct venet_capabilities caps;
+ int ret;
+
+ memset(&caps, 0, sizeof(caps));
+
+ caps.gid = VENET_CAP_GROUP_EVENTQ;
+ caps.bits |= VENET_CAP_EVQ_LINKSTATE;
+ caps.bits |= VENET_CAP_EVQ_TXC;
+
+ ret = devcall(priv, VENET_FUNC_NEGCAP, &caps, sizeof(caps));
+ if (ret < 0)
+ return ret;
+
+ if (caps.bits) {
+ struct vbus_device_proxy *dev = priv->vdev;
+ struct venet_eventq_query query;
+ size_t poollen;
+ struct ioq_iterator iter;
+ char *pool;
+ int i;
+
+ priv->evq.enabled = true;
+
+ if (caps.bits & VENET_CAP_EVQ_LINKSTATE) {
+ /*
+ * We will assume there is no carrier until we get
+ * an event telling us otherwise
+ */
+ netif_carrier_off(priv->dev);
+ priv->evq.linkstate = true;
+ }
+
+ if (caps.bits & VENET_CAP_EVQ_TXC)
+ priv->evq.txc = true;
+
+ memset(&query, 0, sizeof(query));
+
+ ret = devcall(priv, VENET_FUNC_EVQQUERY, &query, sizeof(query));
+ if (ret < 0)
+ return ret;
+
+ priv->evq.evsize = query.evsize;
+ poollen = query.evsize * count;
+
+ pool = kzalloc(poollen, GFP_KERNEL | GFP_DMA);
+ if (!pool)
+ return -ENOMEM;
+
+ priv->evq.pool = pool;
+
+ ret = dev->ops->shm(dev, NULL, query.dpid, 0,
+ pool, poollen, 0, NULL, 0);
+ if (ret < 0)
+ return ret;
+
+ queue_init(priv, &priv->evq.veq, "evq",
+ query.qid, count, evq_isr);
+
+ ret = ioq_iter_init(priv->evq.veq.queue,
+ &iter, ioq_idxtype_valid, 0);
+ BUG_ON(ret < 0);
+
+ ret = ioq_iter_seek(&iter, ioq_seek_set, 0, 0);
+ BUG_ON(ret < 0);
+
+ /* Now populate each descriptor with an empty event */
+ for (i = 0; i < count; i++) {
+ size_t offset = (i * query.evsize);
+ void *addr = &priv->evq.pool[offset];
+
+ iter.desc->ptr = (u64)offset;
+ iter.desc->cookie = (u64)addr;
+ iter.desc->len = query.evsize;
+
+ ret = ioq_iter_push(&iter, 0);
+ BUG_ON(ret < 0);
+ }
+
+ /* Finally, enable interrupts */
+ tasklet_init(&priv->evq.task, deferred_evq_isr,
+ (unsigned long)priv);
+ ioq_notify_enable(priv->evq.veq.queue, 0);
+ }
+
+ return 0;
+}
+
+static int
+vbus_enet_l4ro_negcap(struct vbus_enet_priv *priv, unsigned long count)
+{
+ struct venet_capabilities caps;
+ int ret;
+
+ memset(&caps, 0, sizeof(caps));
+
+ caps.gid = VENET_CAP_GROUP_L4RO;
+ caps.bits |= (VENET_CAP_SG|VENET_CAP_TSO4|VENET_CAP_TSO6
+ |VENET_CAP_ECN);
+
+ ret = devcall(priv, VENET_FUNC_NEGCAP, &caps, sizeof(caps));
+ if (ret < 0) {
+ printk(KERN_ERR "Error negotiating L4RO: %d\n", ret);
+ return ret;
+ }
+
+ if (caps.bits & VENET_CAP_SG) {
+ struct vbus_device_proxy *dev = priv->vdev;
+ size_t poollen = SG_DESC_SIZE * count;
+ struct venet_l4ro_query query;
+ char *pool;
+
+ memset(&query, 0, sizeof(query));
+
+ ret = devcall(priv, VENET_FUNC_L4ROQUERY, &query, sizeof(query));
+ if (ret < 0) {
+ printk(KERN_ERR "Error querying L4RO: %d\n", ret);
+ return ret;
+ }
+
+ pool = kzalloc(poollen, GFP_KERNEL | GFP_DMA);
+ if (!pool)
+ return -ENOMEM;
+
+ /*
+ * pre-mapped descriptor pool
+ */
+ ret = dev->ops->shm(dev, NULL, query.dpid, 0,
+ pool, poollen, 0, NULL, 0);
+ if (ret < 0) {
+ printk(KERN_ERR "Error registering L4RO pool: %d\n",
+ ret);
+ kfree(pool);
+ return ret;
+ }
+
+ /*
+ * page-queue: contains a ring of arbitrary pages for
+ * consumption by the host for when the SG::IOV count exceeds
+ * one MTU frame. All we need to do is keep it populated
+ * with free pages.
+ */
+ queue_init(priv, &priv->l4ro.pageq, "pageq", query.pqid,
+ count, NULL);
+
+ priv->l4ro.pool = pool;
+ priv->l4ro.available = true;
+ }
+
+ return 0;
+}
+
+static int
+vbus_enet_negcap(struct vbus_enet_priv *priv)
+{
+ int ret;
+
+ ret = vbus_enet_sg_negcap(priv);
+ if (ret < 0)
+ return ret;
+
+ ret = vbus_enet_evq_negcap(priv, tx_ringlen);
+ if (ret < 0)
+ return ret;
+
+ ret = vbus_enet_l4ro_negcap(priv, rx_ringlen);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int vbus_enet_set_tx_csum(struct net_device *dev, u32 data)
+{
+ struct vbus_enet_priv *priv = netdev_priv(dev);
+
+ if (data && !priv->sg)
+ return -ENOSYS;
+
+ return ethtool_op_set_tx_hw_csum(dev, data);
+}
+
+static struct ethtool_ops vbus_enet_ethtool_ops = {
+ .set_tx_csum = vbus_enet_set_tx_csum,
+ .set_sg = ethtool_op_set_sg,
+ .set_tso = ethtool_op_set_tso,
+ .get_link = ethtool_op_get_link,
+};
+
+static const struct net_device_ops vbus_enet_netdev_ops = {
+ .ndo_open = vbus_enet_open,
+ .ndo_stop = vbus_enet_stop,
+ .ndo_set_config = vbus_enet_config,
+ .ndo_start_xmit = vbus_enet_tx_start,
+ .ndo_change_mtu = vbus_enet_change_mtu,
+ .ndo_tx_timeout = vbus_enet_timeout,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+/*
+ * This is called whenever a new vbus_device_proxy is added to the vbus
+ * with the matching VENET_ID
+ */
+static int
+vbus_enet_probe(struct vbus_device_proxy *vdev)
+{
+ struct net_device *dev;
+ struct vbus_enet_priv *priv;
+ int ret;
+
+ printk(KERN_INFO "VENET: Found new device at %lld\n", vdev->id);
+
+ ret = vdev->ops->open(vdev, VENET_VERSION, 0);
+ if (ret < 0)
+ return ret;
+
+ dev = alloc_etherdev(sizeof(struct vbus_enet_priv));
+ if (!dev)
+ return -ENOMEM;
+
+ /*
+ * establish our device-name early so we can incorporate it into
+ * the signal-path names, etc
+ */
+ rtnl_lock();
+
+ ret = dev_alloc_name(dev, dev->name);
+ if (ret < 0)
+ goto out_free;
+
+ priv = netdev_priv(dev);
+
+ spin_lock_init(&priv->lock);
+ priv->dev = dev;
+ priv->vdev = vdev;
+
+ ret = vbus_enet_negcap(priv);
+ if (ret < 0) {
+ printk(KERN_INFO "VENET: Error negotiating capabilities for " \
+ "%lld\n",
+ priv->vdev->id);
+ goto out_free;
+ }
+
+ if (priv->l4ro.available)
+ priv->import = &vbus_enet_l4ro_import;
+ else
+ priv->import = &vbus_enet_flat_import;
+
+ skb_queue_head_init(&priv->tx.outstanding);
+
+ queue_init(priv, &priv->rxq, "rx", VENET_QUEUE_RX, rx_ringlen,
+ rx_isr);
+ queue_init(priv, &priv->tx.veq, "tx", VENET_QUEUE_TX, tx_ringlen,
+ tx_isr);
+
+ rx_setup(priv);
+ tx_setup(priv);
+
+ ioq_notify_enable(priv->rxq.queue, 0); /* enable rx interrupts */
+
+ if (!priv->evq.txc) {
+ /*
+ * If the TXC feature is present, we will recieve our
+ * tx-complete notification via the event-channel. Therefore,
+ * we only enable txq interrupts if the TXC feature is not
+ * present.
+ */
+ tasklet_init(&priv->tx.task, deferred_tx_isr,
+ (unsigned long)priv);
+ ioq_notify_enable(priv->tx.veq.queue, 0);
+ }
+
+ dev->netdev_ops = &vbus_enet_netdev_ops;
+ dev->watchdog_timeo = 5 * HZ;
+ SET_ETHTOOL_OPS(dev, &vbus_enet_ethtool_ops);
+ SET_NETDEV_DEV(dev, &vdev->dev);
+
+ netif_napi_add(dev, &priv->napi, vbus_enet_poll, 128);
+
+ ret = devcall(priv, VENET_FUNC_MACQUERY, priv->dev->dev_addr, ETH_ALEN);
+ if (ret < 0) {
+ printk(KERN_INFO "VENET: Error obtaining MAC address for " \
+ "%lld\n",
+ priv->vdev->id);
+ goto out_free;
+ }
+
+ dev->features |= NETIF_F_HIGHDMA;
+
+ ret = register_netdevice(dev);
+ if (ret < 0) {
+ printk(KERN_INFO "VENET: error %i registering device \"%s\"\n",
+ ret, dev->name);
+ goto out_free;
+ }
+
+ rtnl_unlock();
+
+ vdev->priv = priv;
+
+ return 0;
+
+ out_free:
+ rtnl_unlock();
+
+ free_netdev(dev);
+
+ return ret;
+}
+
+static int
+vbus_enet_remove(struct vbus_device_proxy *vdev)
+{
+ struct vbus_enet_priv *priv = (struct vbus_enet_priv *)vdev->priv;
+ struct vbus_device_proxy *dev = priv->vdev;
+
+ unregister_netdev(priv->dev);
+ napi_disable(&priv->napi);
+
+ rx_teardown(priv);
+ ioq_put(priv->rxq.queue);
+
+ tx_teardown(priv);
+ ioq_put(priv->tx.veq.queue);
+
+ if (priv->evq.enabled)
+ evq_teardown(priv);
+
+ dev->ops->close(dev, 0);
+
+ free_netdev(priv->dev);
+
+ return 0;
+}
+
+/*
+ * Finally, the module stuff
+ */
+
+static struct vbus_driver_ops vbus_enet_driver_ops = {
+ .probe = vbus_enet_probe,
+ .remove = vbus_enet_remove,
+};
+
+static struct vbus_driver vbus_enet_driver = {
+ .type = VENET_TYPE,
+ .owner = THIS_MODULE,
+ .ops = &vbus_enet_driver_ops,
+};
+
+static __init int
+vbus_enet_init_module(void)
+{
+ printk(KERN_INFO "Virtual Ethernet: Copyright (C) 2009 Novell, Gregory Haskins\n");
+ printk(KERN_DEBUG "VENET: Using %d/%d queue depth\n",
+ rx_ringlen, tx_ringlen);
+ return vbus_driver_register(&vbus_enet_driver);
+}
+
+static __exit void
+vbus_enet_cleanup(void)
+{
+ vbus_driver_unregister(&vbus_enet_driver);
+}
+
+module_init(vbus_enet_init_module);
+module_exit(vbus_enet_cleanup);
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index ade5b344f75d..0c4a81124257 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -153,7 +153,7 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
struct net_device *rcv = NULL;
struct veth_priv *priv, *rcv_priv;
struct veth_net_stats *stats, *rcv_stats;
- int length, cpu;
+ int length;
skb_orphan(skb);
@@ -161,9 +161,8 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
rcv = priv->peer;
rcv_priv = netdev_priv(rcv);
- cpu = smp_processor_id();
- stats = per_cpu_ptr(priv->stats, cpu);
- rcv_stats = per_cpu_ptr(rcv_priv->stats, cpu);
+ stats = this_cpu_ptr(priv->stats);
+ rcv_stats = this_cpu_ptr(rcv_priv->stats);
if (!(rcv->flags & IFF_UP))
goto tx_drop;
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 1fd70583be44..4535e89dfff1 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -1484,15 +1484,15 @@ static int rhine_rx(struct net_device *dev, int limit)
}
}
} else {
- struct sk_buff *skb;
+ struct sk_buff *skb = NULL;
/* Length should omit the CRC */
int pkt_len = data_size - 4;
/* Check if the packet is long enough to accept without
copying to a minimally-sized skbuff. */
- if (pkt_len < rx_copybreak &&
- (skb = netdev_alloc_skb(dev, pkt_len + NET_IP_ALIGN)) != NULL) {
- skb_reserve(skb, NET_IP_ALIGN); /* 16 byte align the IP header */
+ if (pkt_len < rx_copybreak)
+ skb = netdev_alloc_skb_ip_align(dev, pkt_len);
+ if (skb) {
pci_dma_sync_single_for_cpu(rp->pdev,
rp->rx_skbuff_dma[entry],
rp->rx_buf_sz,
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index e04e5bee005c..144db6395c95 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -1949,10 +1949,9 @@ static int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size,
if (pkt_size < rx_copybreak) {
struct sk_buff *new_skb;
- new_skb = netdev_alloc_skb(vptr->dev, pkt_size + 2);
+ new_skb = netdev_alloc_skb_ip_align(vptr->dev, pkt_size);
if (new_skb) {
new_skb->ip_summed = rx_skb[0]->ip_summed;
- skb_reserve(new_skb, 2);
skb_copy_from_linear_data(*rx_skb, new_skb->data, pkt_size);
*rx_skb = new_skb;
ret = 0;
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 8d009760277c..a6f6edcd0c9e 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -22,7 +22,6 @@
#include <linux/ethtool.h>
#include <linux/module.h>
#include <linux/virtio.h>
-#include <linux/virtio_ids.h>
#include <linux/virtio_net.h>
#include <linux/scatterlist.h>
#include <linux/if_vlan.h>
@@ -283,13 +282,12 @@ static bool try_fill_recv_maxbufs(struct virtnet_info *vi, gfp_t gfp)
do {
struct skb_vnet_hdr *hdr;
- skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN + NET_IP_ALIGN);
+ skb = netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN);
if (unlikely(!skb)) {
oom = true;
break;
}
- skb_reserve(skb, NET_IP_ALIGN);
skb_put(skb, MAX_PACKET_LEN);
hdr = skb_vnet_hdr(skb);
@@ -344,14 +342,12 @@ static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp)
do {
skb_frag_t *f;
- skb = netdev_alloc_skb(vi->dev, GOOD_COPY_LEN + NET_IP_ALIGN);
+ skb = netdev_alloc_skb_ip_align(vi->dev, GOOD_COPY_LEN);
if (unlikely(!skb)) {
oom = true;
break;
}
- skb_reserve(skb, NET_IP_ALIGN);
-
f = &skb_shinfo(skb)->frags[0];
f->page = get_a_page(vi, gfp);
if (!f->page) {
@@ -454,7 +450,7 @@ static unsigned int free_old_xmit_skbs(struct virtnet_info *vi)
vi->dev->stats.tx_bytes += skb->len;
vi->dev->stats.tx_packets++;
tot_sgs += skb_vnet_hdr(skb)->num_sg;
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
return tot_sgs;
}
@@ -517,8 +513,7 @@ again:
/* Free up any pending old buffers before queueing new ones. */
free_old_xmit_skbs(vi);
- /* Put new one in send queue and do transmit */
- __skb_queue_head(&vi->send, skb);
+ /* Try to transmit */
capacity = xmit_skb(vi, skb);
/* This can happen with OOM and indirect buffers. */
@@ -532,8 +527,17 @@ again:
}
return NETDEV_TX_BUSY;
}
-
vi->svq->vq_ops->kick(vi->svq);
+
+ /*
+ * Put new one in send queue. You'd expect we'd need this before
+ * xmit_skb calls add_buf(), since the callback can be triggered
+ * immediately after that. But since the callback just triggers
+ * another call back here, normal network xmit locking prevents the
+ * race.
+ */
+ __skb_queue_head(&vi->send, skb);
+
/* Don't wait up for transmitted skbs to be freed. */
skb_orphan(skb);
nf_reset(skb);
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 6a16f76f277e..004353a46af0 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -481,7 +481,8 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, u32 ring_idx,
}
rq->uncommitted[ring_idx] += num_allocated;
- dprintk(KERN_ERR "alloc_rx_buf: %d allocated, next2fill %u, next2comp "
+ dev_dbg(&adapter->netdev->dev,
+ "alloc_rx_buf: %d allocated, next2fill %u, next2comp "
"%u, uncommited %u\n", num_allocated, ring->next2fill,
ring->next2comp, rq->uncommitted[ring_idx]);
@@ -539,7 +540,8 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
tbi = tq->buf_info + tq->tx_ring.next2fill;
tbi->map_type = VMXNET3_MAP_NONE;
- dprintk(KERN_ERR "txd[%u]: 0x%Lx 0x%x 0x%x\n",
+ dev_dbg(&adapter->netdev->dev,
+ "txd[%u]: 0x%Lx 0x%x 0x%x\n",
tq->tx_ring.next2fill, ctx->sop_txd->txd.addr,
ctx->sop_txd->dword[2], ctx->sop_txd->dword[3]);
vmxnet3_cmd_ring_adv_next2fill(&tq->tx_ring);
@@ -572,7 +574,8 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
gdesc->dword[2] = dw2 | buf_size;
gdesc->dword[3] = 0;
- dprintk(KERN_ERR "txd[%u]: 0x%Lx 0x%x 0x%x\n",
+ dev_dbg(&adapter->netdev->dev,
+ "txd[%u]: 0x%Lx 0x%x 0x%x\n",
tq->tx_ring.next2fill, gdesc->txd.addr,
gdesc->dword[2], gdesc->dword[3]);
vmxnet3_cmd_ring_adv_next2fill(&tq->tx_ring);
@@ -600,7 +603,8 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
gdesc->dword[2] = dw2 | frag->size;
gdesc->dword[3] = 0;
- dprintk(KERN_ERR "txd[%u]: 0x%llu %u %u\n",
+ dev_dbg(&adapter->netdev->dev,
+ "txd[%u]: 0x%llu %u %u\n",
tq->tx_ring.next2fill, gdesc->txd.addr,
gdesc->dword[2], gdesc->dword[3]);
vmxnet3_cmd_ring_adv_next2fill(&tq->tx_ring);
@@ -697,7 +701,8 @@ vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
tdd = tq->data_ring.base + tq->tx_ring.next2fill;
memcpy(tdd->data, skb->data, ctx->copy_size);
- dprintk(KERN_ERR "copy %u bytes to dataRing[%u]\n",
+ dev_dbg(&adapter->netdev->dev,
+ "copy %u bytes to dataRing[%u]\n",
ctx->copy_size, tq->tx_ring.next2fill);
return 1;
@@ -808,7 +813,8 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
if (count > vmxnet3_cmd_ring_desc_avail(&tq->tx_ring)) {
tq->stats.tx_ring_full++;
- dprintk(KERN_ERR "tx queue stopped on %s, next2comp %u"
+ dev_dbg(&adapter->netdev->dev,
+ "tx queue stopped on %s, next2comp %u"
" next2fill %u\n", adapter->netdev->name,
tq->tx_ring.next2comp, tq->tx_ring.next2fill);
@@ -853,7 +859,8 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
/* finally flips the GEN bit of the SOP desc */
gdesc->dword[2] ^= VMXNET3_TXD_GEN;
- dprintk(KERN_ERR "txd[%u]: SOP 0x%Lx 0x%x 0x%x\n",
+ dev_dbg(&adapter->netdev->dev,
+ "txd[%u]: SOP 0x%Lx 0x%x 0x%x\n",
(u32)((union Vmxnet3_GenericDesc *)ctx.sop_txd -
tq->tx_ring.base), gdesc->txd.addr, gdesc->dword[2],
gdesc->dword[3]);
@@ -990,7 +997,8 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
if (unlikely(rcd->len == 0)) {
/* Pretend the rx buffer is skipped. */
BUG_ON(!(rcd->sop && rcd->eop));
- dprintk(KERN_ERR "rxRing[%u][%u] 0 length\n",
+ dev_dbg(&adapter->netdev->dev,
+ "rxRing[%u][%u] 0 length\n",
ring_idx, idx);
goto rcd_done;
}
@@ -1683,7 +1691,8 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
int err;
u32 ret;
- dprintk(KERN_ERR "%s: skb_buf_size %d, rx_buf_per_pkt %d, ring sizes"
+ dev_dbg(&adapter->netdev->dev,
+ "%s: skb_buf_size %d, rx_buf_per_pkt %d, ring sizes"
" %u %u %u\n", adapter->netdev->name, adapter->skb_buf_size,
adapter->rx_buf_per_pkt, adapter->tx_queue.tx_ring.size,
adapter->rx_queue.rx_ring[0].size,
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index 6bb91576e999..3c0d70d58111 100644
--- a/drivers/net/vmxnet3/vmxnet3_int.h
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -30,6 +30,7 @@
#include <linux/types.h>
#include <linux/ethtool.h>
#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/ethtool.h>
@@ -59,7 +60,6 @@
#include <linux/if_vlan.h>
#include <linux/if_arp.h>
#include <linux/inetdevice.h>
-#include <linux/dst.h>
#include "vmxnet3_defs.h"
diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c
index 9e94c4b0fb18..32a75fa935ed 100644
--- a/drivers/net/vxge/vxge-config.c
+++ b/drivers/net/vxge/vxge-config.c
@@ -356,10 +356,8 @@ __vxge_hw_device_access_rights_get(u32 host_type, u32 func_id)
switch (host_type) {
case VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION:
- if (func_id == 0) {
- access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM |
- VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
- }
+ access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM |
+ VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
break;
case VXGE_HW_MR_NO_SR_VH0_BASE_FUNCTION:
access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM |
@@ -382,6 +380,22 @@ __vxge_hw_device_access_rights_get(u32 host_type, u32 func_id)
return access_rights;
}
/*
+ * __vxge_hw_device_is_privilaged
+ * This routine checks if the device function is privilaged or not
+ */
+
+enum vxge_hw_status
+__vxge_hw_device_is_privilaged(u32 host_type, u32 func_id)
+{
+ if (__vxge_hw_device_access_rights_get(host_type,
+ func_id) &
+ VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM)
+ return VXGE_HW_OK;
+ else
+ return VXGE_HW_ERR_PRIVILAGED_OPEARATION;
+}
+
+/*
* __vxge_hw_device_host_info_get
* This routine returns the host type assignments
*/
@@ -446,220 +460,6 @@ __vxge_hw_verify_pci_e_info(struct __vxge_hw_device *hldev)
return VXGE_HW_OK;
}
-enum vxge_hw_status
-__vxge_hw_device_is_privilaged(struct __vxge_hw_device *hldev)
-{
- if ((hldev->host_type == VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION ||
- hldev->host_type == VXGE_HW_MR_NO_SR_VH0_BASE_FUNCTION ||
- hldev->host_type == VXGE_HW_NO_MR_SR_VH0_FUNCTION0) &&
- (hldev->func_id == 0))
- return VXGE_HW_OK;
- else
- return VXGE_HW_ERR_PRIVILAGED_OPEARATION;
-}
-
-/*
- * vxge_hw_wrr_rebalance - Rebalance the RX_WRR and KDFC_WRR calandars.
- * Rebalance the RX_WRR and KDFC_WRR calandars.
- */
-static enum
-vxge_hw_status vxge_hw_wrr_rebalance(struct __vxge_hw_device *hldev)
-{
- u64 val64;
- u32 wrr_states[VXGE_HW_WEIGHTED_RR_SERVICE_STATES];
- u32 i, j, how_often = 1;
- enum vxge_hw_status status = VXGE_HW_OK;
-
- status = __vxge_hw_device_is_privilaged(hldev);
- if (status != VXGE_HW_OK)
- goto exit;
-
- /* Reset the priorities assigned to the WRR arbitration
- phases for the receive traffic */
- for (i = 0; i < VXGE_HW_WRR_RING_COUNT; i++)
- writeq(0, ((&hldev->mrpcim_reg->rx_w_round_robin_0) + i));
-
- /* Reset the transmit FIFO servicing calendar for FIFOs */
- for (i = 0; i < VXGE_HW_WRR_FIFO_COUNT; i++) {
- writeq(0, ((&hldev->mrpcim_reg->kdfc_w_round_robin_0) + i));
- writeq(0, ((&hldev->mrpcim_reg->kdfc_w_round_robin_20) + i));
- }
-
- /* Assign WRR priority 0 for all FIFOs */
- for (i = 1; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
- writeq(VXGE_HW_KDFC_FIFO_0_CTRL_WRR_NUMBER(0),
- ((&hldev->mrpcim_reg->kdfc_fifo_0_ctrl) + i));
-
- writeq(VXGE_HW_KDFC_FIFO_17_CTRL_WRR_NUMBER(0),
- ((&hldev->mrpcim_reg->kdfc_fifo_17_ctrl) + i));
- }
-
- /* Reset to service non-offload doorbells */
- writeq(0, &hldev->mrpcim_reg->kdfc_entry_type_sel_0);
- writeq(0, &hldev->mrpcim_reg->kdfc_entry_type_sel_1);
-
- /* Set priority 0 to all receive queues */
- writeq(0, &hldev->mrpcim_reg->rx_queue_priority_0);
- writeq(0, &hldev->mrpcim_reg->rx_queue_priority_1);
- writeq(0, &hldev->mrpcim_reg->rx_queue_priority_2);
-
- /* Initialize all the slots as unused */
- for (i = 0; i < VXGE_HW_WEIGHTED_RR_SERVICE_STATES; i++)
- wrr_states[i] = -1;
-
- /* Prepare the Fifo service states */
- for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-
- if (!hldev->config.vp_config[i].min_bandwidth)
- continue;
-
- how_often = VXGE_HW_VPATH_BANDWIDTH_MAX /
- hldev->config.vp_config[i].min_bandwidth;
- if (how_often) {
-
- for (j = 0; j < VXGE_HW_WRR_FIFO_SERVICE_STATES;) {
- if (wrr_states[j] == -1) {
- wrr_states[j] = i;
- /* Make sure each fifo is serviced
- * atleast once */
- if (i == j)
- j += VXGE_HW_MAX_VIRTUAL_PATHS;
- else
- j += how_often;
- } else
- j++;
- }
- }
- }
-
- /* Fill the unused slots with 0 */
- for (j = 0; j < VXGE_HW_WEIGHTED_RR_SERVICE_STATES; j++) {
- if (wrr_states[j] == -1)
- wrr_states[j] = 0;
- }
-
- /* Assign WRR priority number for FIFOs */
- for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
- writeq(VXGE_HW_KDFC_FIFO_0_CTRL_WRR_NUMBER(i),
- ((&hldev->mrpcim_reg->kdfc_fifo_0_ctrl) + i));
-
- writeq(VXGE_HW_KDFC_FIFO_17_CTRL_WRR_NUMBER(i),
- ((&hldev->mrpcim_reg->kdfc_fifo_17_ctrl) + i));
- }
-
- /* Modify the servicing algorithm applied to the 3 types of doorbells.
- i.e, none-offload, message and offload */
- writeq(VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_0(0) |
- VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_1(0) |
- VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_2(0) |
- VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_3(0) |
- VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_4(1) |
- VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_5(0) |
- VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_6(0) |
- VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_7(0),
- &hldev->mrpcim_reg->kdfc_entry_type_sel_0);
-
- writeq(VXGE_HW_KDFC_ENTRY_TYPE_SEL_1_NUMBER_8(1),
- &hldev->mrpcim_reg->kdfc_entry_type_sel_1);
-
- for (i = 0, j = 0; i < VXGE_HW_WRR_FIFO_COUNT; i++) {
-
- val64 = VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_0(wrr_states[j++]);
- val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_1(wrr_states[j++]);
- val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_2(wrr_states[j++]);
- val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_3(wrr_states[j++]);
- val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_4(wrr_states[j++]);
- val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_5(wrr_states[j++]);
- val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_6(wrr_states[j++]);
- val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_7(wrr_states[j++]);
-
- writeq(val64, (&hldev->mrpcim_reg->kdfc_w_round_robin_0 + i));
- writeq(val64, (&hldev->mrpcim_reg->kdfc_w_round_robin_20 + i));
- }
-
- /* Set up the priorities assigned to receive queues */
- writeq(VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_0(0) |
- VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_1(1) |
- VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_2(2) |
- VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_3(3) |
- VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_4(4) |
- VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_5(5) |
- VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_6(6) |
- VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_7(7),
- &hldev->mrpcim_reg->rx_queue_priority_0);
-
- writeq(VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_8(8) |
- VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_9(9) |
- VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_10(10) |
- VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_11(11) |
- VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_12(12) |
- VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_13(13) |
- VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_14(14) |
- VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_15(15),
- &hldev->mrpcim_reg->rx_queue_priority_1);
-
- writeq(VXGE_HW_RX_QUEUE_PRIORITY_2_RX_Q_NUMBER_16(16),
- &hldev->mrpcim_reg->rx_queue_priority_2);
-
- /* Initialize all the slots as unused */
- for (i = 0; i < VXGE_HW_WEIGHTED_RR_SERVICE_STATES; i++)
- wrr_states[i] = -1;
-
- /* Prepare the Ring service states */
- for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-
- if (!hldev->config.vp_config[i].min_bandwidth)
- continue;
-
- how_often = VXGE_HW_VPATH_BANDWIDTH_MAX /
- hldev->config.vp_config[i].min_bandwidth;
-
- if (how_often) {
- for (j = 0; j < VXGE_HW_WRR_RING_SERVICE_STATES;) {
- if (wrr_states[j] == -1) {
- wrr_states[j] = i;
- /* Make sure each ring is
- * serviced atleast once */
- if (i == j)
- j += VXGE_HW_MAX_VIRTUAL_PATHS;
- else
- j += how_often;
- } else
- j++;
- }
- }
- }
-
- /* Fill the unused slots with 0 */
- for (j = 0; j < VXGE_HW_WEIGHTED_RR_SERVICE_STATES; j++) {
- if (wrr_states[j] == -1)
- wrr_states[j] = 0;
- }
-
- for (i = 0, j = 0; i < VXGE_HW_WRR_RING_COUNT; i++) {
- val64 = VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_0(
- wrr_states[j++]);
- val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_1(
- wrr_states[j++]);
- val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_2(
- wrr_states[j++]);
- val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_3(
- wrr_states[j++]);
- val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_4(
- wrr_states[j++]);
- val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_5(
- wrr_states[j++]);
- val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_6(
- wrr_states[j++]);
- val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_7(
- wrr_states[j++]);
-
- writeq(val64, ((&hldev->mrpcim_reg->rx_w_round_robin_0) + i));
- }
-exit:
- return status;
-}
-
/*
* __vxge_hw_device_initialize
* Initialize Titan-V hardware.
@@ -668,14 +468,14 @@ enum vxge_hw_status __vxge_hw_device_initialize(struct __vxge_hw_device *hldev)
{
enum vxge_hw_status status = VXGE_HW_OK;
- if (VXGE_HW_OK == __vxge_hw_device_is_privilaged(hldev)) {
+ if (VXGE_HW_OK == __vxge_hw_device_is_privilaged(hldev->host_type,
+ hldev->func_id)) {
/* Validate the pci-e link width and speed */
status = __vxge_hw_verify_pci_e_info(hldev);
if (status != VXGE_HW_OK)
goto exit;
}
- vxge_hw_wrr_rebalance(hldev);
exit:
return status;
}
@@ -953,7 +753,8 @@ vxge_hw_mrpcim_stats_access(struct __vxge_hw_device *hldev,
u64 val64;
enum vxge_hw_status status = VXGE_HW_OK;
- status = __vxge_hw_device_is_privilaged(hldev);
+ status = __vxge_hw_device_is_privilaged(hldev->host_type,
+ hldev->func_id);
if (status != VXGE_HW_OK)
goto exit;
@@ -990,7 +791,8 @@ vxge_hw_device_xmac_aggr_stats_get(struct __vxge_hw_device *hldev, u32 port,
val64 = (u64 *)aggr_stats;
- status = __vxge_hw_device_is_privilaged(hldev);
+ status = __vxge_hw_device_is_privilaged(hldev->host_type,
+ hldev->func_id);
if (status != VXGE_HW_OK)
goto exit;
@@ -1023,7 +825,8 @@ vxge_hw_device_xmac_port_stats_get(struct __vxge_hw_device *hldev, u32 port,
u32 offset = 0x0;
val64 = (u64 *) port_stats;
- status = __vxge_hw_device_is_privilaged(hldev);
+ status = __vxge_hw_device_is_privilaged(hldev->host_type,
+ hldev->func_id);
if (status != VXGE_HW_OK)
goto exit;
@@ -1221,7 +1024,8 @@ enum vxge_hw_status vxge_hw_device_setpause_data(struct __vxge_hw_device *hldev,
goto exit;
}
- status = __vxge_hw_device_is_privilaged(hldev);
+ status = __vxge_hw_device_is_privilaged(hldev->host_type,
+ hldev->func_id);
if (status != VXGE_HW_OK)
goto exit;
@@ -2353,6 +2157,28 @@ exit:
}
/*
+ * vxge_hw_vpath_strip_fcs_check - Check for FCS strip.
+ */
+enum vxge_hw_status
+vxge_hw_vpath_strip_fcs_check(struct __vxge_hw_device *hldev, u64 vpath_mask)
+{
+ struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg;
+ enum vxge_hw_status status = VXGE_HW_OK;
+ int i = 0, j = 0;
+
+ for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+ if (!((vpath_mask) & vxge_mBIT(i)))
+ continue;
+ vpmgmt_reg = hldev->vpmgmt_reg[i];
+ for (j = 0; j < VXGE_HW_MAC_MAX_MAC_PORT_ID; j++) {
+ if (readq(&vpmgmt_reg->rxmac_cfg0_port_vpmgmt_clone[j])
+ & VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_STRIP_FCS)
+ return VXGE_HW_FAIL;
+ }
+ }
+ return status;
+}
+/*
* vxge_hw_mgmt_reg_Write - Write Titan register.
*/
enum vxge_hw_status
@@ -4056,6 +3882,30 @@ __vxge_hw_vpath_tim_configure(struct __vxge_hw_device *hldev, u32 vp_id)
return status;
}
+void
+vxge_hw_vpath_tti_ci_set(struct __vxge_hw_device *hldev, u32 vp_id)
+{
+ struct __vxge_hw_virtualpath *vpath;
+ struct vxge_hw_vpath_reg __iomem *vp_reg;
+ struct vxge_hw_vp_config *config;
+ u64 val64;
+
+ vpath = &hldev->virtual_paths[vp_id];
+ vp_reg = vpath->vp_reg;
+ config = vpath->vp_config;
+
+ if (config->fifo.enable == VXGE_HW_FIFO_ENABLE) {
+ val64 = readq(&vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]);
+
+ if (config->tti.timer_ci_en != VXGE_HW_TIM_TIMER_CI_ENABLE) {
+ config->tti.timer_ci_en = VXGE_HW_TIM_TIMER_CI_ENABLE;
+ val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI;
+ writeq(val64,
+ &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]);
+ }
+ }
+ return;
+}
/*
* __vxge_hw_vpath_initialize
* This routine is the final phase of init which initializes the
@@ -4098,8 +3948,6 @@ __vxge_hw_vpath_initialize(struct __vxge_hw_device *hldev, u32 vp_id)
if (status != VXGE_HW_OK)
goto exit;
- writeq(0, &vp_reg->gendma_int);
-
val64 = readq(&vp_reg->rtdma_rd_optimization_ctrl);
/* Get MRRS value from device control */
diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h
index 3e94f0ce0900..e7877df092f3 100644
--- a/drivers/net/vxge/vxge-config.h
+++ b/drivers/net/vxge/vxge-config.h
@@ -2201,6 +2201,8 @@ __vxge_hw_vpath_func_id_get(
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-main.c b/drivers/net/vxge/vxge-main.c
index 068d7a9d3e36..63d0f891ffae 100644
--- a/drivers/net/vxge/vxge-main.c
+++ b/drivers/net/vxge/vxge-main.c
@@ -2435,7 +2435,6 @@ static int vxge_add_isr(struct vxgedev *vdev)
int ret = 0;
#ifdef CONFIG_PCI_MSI
int vp_idx = 0, intr_idx = 0, intr_cnt = 0, msix_idx = 0, irq_req = 0;
- u64 function_mode = vdev->config.device_hw_info.function_mode;
int pci_fun = PCI_FUNC(vdev->pdev->devfn);
if (vdev->config.intr_type == MSI_X)
@@ -2444,20 +2443,9 @@ static int vxge_add_isr(struct vxgedev *vdev)
if (ret) {
vxge_debug_init(VXGE_ERR,
"%s: Enabling MSI-X Failed", VXGE_DRIVER_NAME);
- if ((function_mode == VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION) &&
- test_and_set_bit(__VXGE_STATE_CARD_UP,
- &driver_config->inta_dev_open))
- return VXGE_HW_FAIL;
- else {
- vxge_debug_init(VXGE_ERR,
- "%s: Defaulting to INTA", VXGE_DRIVER_NAME);
- vdev->config.intr_type = INTA;
- vxge_hw_device_set_intr_type(vdev->devh,
- VXGE_HW_INTR_MODE_IRQLINE);
- vxge_close_vpaths(vdev, 1);
- vdev->no_of_vpath = 1;
- vdev->stats.vpaths_open = 1;
- }
+ vxge_debug_init(VXGE_ERR,
+ "%s: Defaulting to INTA", VXGE_DRIVER_NAME);
+ vdev->config.intr_type = INTA;
}
if (vdev->config.intr_type == MSI_X) {
@@ -2505,24 +2493,11 @@ static int vxge_add_isr(struct vxgedev *vdev)
"%s: MSIX - %d Registration failed",
vdev->ndev->name, intr_cnt);
vxge_rem_msix_isr(vdev);
- if ((function_mode ==
- VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION) &&
- test_and_set_bit(__VXGE_STATE_CARD_UP,
- &driver_config->inta_dev_open))
- return VXGE_HW_FAIL;
- else {
- vxge_hw_device_set_intr_type(
- vdev->devh,
- VXGE_HW_INTR_MODE_IRQLINE);
- vdev->config.intr_type = INTA;
- vxge_debug_init(VXGE_ERR,
- "%s: Defaulting to INTA"
- , vdev->ndev->name);
- vxge_close_vpaths(vdev, 1);
- vdev->no_of_vpath = 1;
- vdev->stats.vpaths_open = 1;
+ vdev->config.intr_type = INTA;
+ vxge_debug_init(VXGE_ERR,
+ "%s: Defaulting to INTA"
+ , vdev->ndev->name);
goto INTA_MODE;
- }
}
if (irq_req) {
@@ -2555,23 +2530,11 @@ static int vxge_add_isr(struct vxgedev *vdev)
"%s: MSIX - %d Registration failed",
vdev->ndev->name, intr_cnt);
vxge_rem_msix_isr(vdev);
- if ((function_mode ==
- VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION) &&
- test_and_set_bit(__VXGE_STATE_CARD_UP,
- &driver_config->inta_dev_open))
- return VXGE_HW_FAIL;
- else {
- vxge_hw_device_set_intr_type(vdev->devh,
- VXGE_HW_INTR_MODE_IRQLINE);
- vdev->config.intr_type = INTA;
- vxge_debug_init(VXGE_ERR,
- "%s: Defaulting to INTA",
- vdev->ndev->name);
- vxge_close_vpaths(vdev, 1);
- vdev->no_of_vpath = 1;
- vdev->stats.vpaths_open = 1;
+ vdev->config.intr_type = INTA;
+ vxge_debug_init(VXGE_ERR,
+ "%s: Defaulting to INTA",
+ vdev->ndev->name);
goto INTA_MODE;
- }
}
vxge_hw_vpath_msix_unmask(vdev->vpaths[vp_idx].handle,
@@ -2584,6 +2547,10 @@ INTA_MODE:
snprintf(vdev->desc[0], VXGE_INTR_STRLEN, "%s:vxge", vdev->ndev->name);
if (vdev->config.intr_type == INTA) {
+ vxge_hw_device_set_intr_type(vdev->devh,
+ VXGE_HW_INTR_MODE_IRQLINE);
+ vxge_hw_vpath_tti_ci_set(vdev->devh,
+ vdev->vpaths[0].device_id);
ret = request_irq((int) vdev->pdev->irq,
vxge_isr_napi,
IRQF_SHARED, vdev->desc[0], vdev);
@@ -2688,13 +2655,6 @@ vxge_open(struct net_device *dev)
* initialized */
netif_carrier_off(dev);
- /* Check for another device already opn with INTA */
- if ((function_mode == VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION) &&
- test_bit(__VXGE_STATE_CARD_UP, &driver_config->inta_dev_open)) {
- ret = -EPERM;
- goto out0;
- }
-
/* Open VPATHs */
status = vxge_open_vpaths(vdev);
if (status != VXGE_HW_OK) {
@@ -2983,7 +2943,6 @@ int do_vxge_close(struct net_device *dev, int do_io)
vxge_debug_entryexit(VXGE_TRACE,
"%s: %s:%d Exiting...", dev->name, __func__, __LINE__);
- clear_bit(__VXGE_STATE_CARD_UP, &driver_config->inta_dev_open);
clear_bit(__VXGE_STATE_RESET_CARD, &vdev->state);
return 0;
@@ -4088,9 +4047,10 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
driver_config->config_dev_cnt = 0;
driver_config->total_dev_cnt = 0;
driver_config->g_no_cpus = 0;
- driver_config->vpath_per_dev = max_config_vpath;
}
+ driver_config->vpath_per_dev = max_config_vpath;
+
driver_config->total_dev_cnt++;
if (++driver_config->config_dev_cnt > max_config_dev) {
ret = 0;
@@ -4243,6 +4203,15 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
goto _exit3;
}
+ /* if FCS stripping is not disabled in MAC fail driver load */
+ if (vxge_hw_vpath_strip_fcs_check(hldev, vpath_mask) != VXGE_HW_OK) {
+ vxge_debug_init(VXGE_ERR,
+ "%s: FCS stripping is not disabled in MAC"
+ " failing driver load", VXGE_DRIVER_NAME);
+ ret = -EINVAL;
+ goto _exit4;
+ }
+
vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL);
/* set private device info */
@@ -4387,6 +4356,27 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
}
kfree(device_config);
+
+ /*
+ * INTA is shared in multi-function mode. This is unlike the INTA
+ * implementation in MR mode, where each VH has its own INTA message.
+ * - INTA is masked (disabled) as long as at least one function sets
+ * its TITAN_MASK_ALL_INT.ALARM bit.
+ * - INTA is unmasked (enabled) when all enabled functions have cleared
+ * their own TITAN_MASK_ALL_INT.ALARM bit.
+ * The TITAN_MASK_ALL_INT ALARM & TRAFFIC bits are cleared on power up.
+ * Though this driver leaves the top level interrupts unmasked while
+ * leaving the required module interrupt bits masked on exit, there
+ * could be a rougue driver around that does not follow this procedure
+ * resulting in a failure to generate interrupts. The following code is
+ * present to prevent such a failure.
+ */
+
+ if (ll_config.device_hw_info.function_mode ==
+ VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION)
+ if (vdev->config.intr_type == INTA)
+ vxge_hw_device_unmask_all(hldev);
+
vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...",
vdev->ndev->name, __func__, __LINE__);
diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h
index 9c36b3a9a63d..7c83ba4be9d7 100644
--- a/drivers/net/vxge/vxge-main.h
+++ b/drivers/net/vxge/vxge-main.h
@@ -112,7 +112,6 @@ enum vxge_mac_addr_state {
struct vxge_drv_config {
int config_dev_cnt;
int total_dev_cnt;
- unsigned long inta_dev_open;
int g_no_cpus;
unsigned int vpath_per_dev;
};
diff --git a/drivers/net/vxge/vxge-reg.h b/drivers/net/vxge/vxge-reg.h
index 9a3b823e08d4..9a0cf8eaa328 100644
--- a/drivers/net/vxge/vxge-reg.h
+++ b/drivers/net/vxge/vxge-reg.h
@@ -4326,10 +4326,6 @@ struct vxge_hw_vpath_reg {
/*0x011e0*/ u64 umq_bwr_init_byte;
#define VXGE_HW_UMQ_BWR_INIT_BYTE_COUNT(val) vxge_vBIT(val, 0, 32)
/*0x011e8*/ u64 gendma_int;
-#define VXGE_HW_GENDMA_INT_IMMED_ENABLE vxge_mBIT(6)
-#define VXGE_HW_GENDMA_INT_EVENT_ENABLE vxge_mBIT(7)
-#define VXGE_HW_GENDMA_INT_NUMBER(val) vxge_vBIT(val, 9, 7)
-#define VXGE_HW_GENDMA_INT_BITMAP(val) vxge_vBIT(val, 16, 16)
/*0x011f0*/ u64 umqdmq_ir_init_notify;
#define VXGE_HW_UMQDMQ_IR_INIT_NOTIFY_PULSE vxge_mBIT(3)
/*0x011f8*/ u64 dmq_init_notify;
diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c
index fe3ae518c69c..61ce754fa9d0 100644
--- a/drivers/net/vxge/vxge-traffic.c
+++ b/drivers/net/vxge/vxge-traffic.c
@@ -295,6 +295,8 @@ void vxge_hw_device_intr_enable(struct __vxge_hw_device *hldev)
u64 val64;
u32 val32;
+ vxge_hw_device_mask_all(hldev);
+
for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
if (!(hldev->vpaths_deployed & vxge_mBIT(i)))
@@ -1232,7 +1234,7 @@ void vxge_hw_fifo_txdl_post(struct __vxge_hw_fifo *fifo, void *txdlh)
vxge_hw_channel_dtr_post(&fifo->channel, txdlh);
__vxge_hw_non_offload_db_post(fifo,
- (u64)(size_t)txdl_priv->dma_addr,
+ (u64)txdl_priv->dma_addr,
txdl_priv->frags - 1,
fifo->no_snoop_bits);
diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h
index 461742b4442b..861c853e3e84 100644
--- a/drivers/net/vxge/vxge-traffic.h
+++ b/drivers/net/vxge/vxge-traffic.h
@@ -2389,6 +2389,8 @@ vxge_hw_channel_dtr_free(struct __vxge_hw_channel *channel, void *dtrh);
int
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 ================================= */
diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h
index 8fbce7552035..fa66248aae6d 100644
--- a/drivers/net/vxge/vxge-version.h
+++ b/drivers/net/vxge/vxge-version.h
@@ -17,7 +17,7 @@
#define VXGE_VERSION_MAJOR "2"
#define VXGE_VERSION_MINOR "0"
-#define VXGE_VERSION_FIX "5"
-#define VXGE_VERSION_BUILD "18053"
+#define VXGE_VERSION_FIX "6"
+#define VXGE_VERSION_BUILD "18707"
#define VXGE_VERSION_FOR "k"
#endif
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index e2c33c06190b..cd8f04afed8f 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -297,8 +297,8 @@ static ssize_t cosa_write(struct file *file,
static unsigned int cosa_poll(struct file *file, poll_table *poll);
static int cosa_open(struct inode *inode, struct file *file);
static int cosa_release(struct inode *inode, struct file *file);
-static int cosa_chardev_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
+static long cosa_chardev_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg);
#ifdef COSA_FASYNC_WORKING
static int cosa_fasync(struct inode *inode, struct file *file, int on);
#endif
@@ -309,7 +309,7 @@ static const struct file_operations cosa_fops = {
.read = cosa_read,
.write = cosa_write,
.poll = cosa_poll,
- .ioctl = cosa_chardev_ioctl,
+ .unlocked_ioctl = cosa_chardev_ioctl,
.open = cosa_open,
.release = cosa_release,
#ifdef COSA_FASYNC_WORKING
@@ -1204,12 +1204,18 @@ static int cosa_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return hdlc_ioctl(dev, ifr, cmd);
}
-static int cosa_chardev_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static long cosa_chardev_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
struct channel_data *channel = file->private_data;
- struct cosa_data *cosa = channel->cosa;
- return cosa_ioctl_common(cosa, channel, cmd, arg);
+ struct cosa_data *cosa;
+ long ret;
+
+ lock_kernel();
+ cosa = channel->cosa;
+ ret = cosa_ioctl_common(cosa, channel, cmd, arg);
+ unlock_kernel();
+ return ret;
}
diff --git a/drivers/net/wimax/i2400m/Kconfig b/drivers/net/wimax/i2400m/Kconfig
index d623b3d99a4b..3f703384295e 100644
--- a/drivers/net/wimax/i2400m/Kconfig
+++ b/drivers/net/wimax/i2400m/Kconfig
@@ -31,6 +31,14 @@ config WIMAX_I2400M_SDIO
If unsure, it is safe to select M (module).
+config WIMAX_IWMC3200_SDIO
+ bool "Intel Wireless Multicom WiMAX Connection 3200 over SDIO"
+ depends on WIMAX_I2400M_SDIO
+ select IWMC3200TOP
+ help
+ Select if you have a device based on the Intel Multicom WiMAX
+ Connection 3200 over SDIO.
+
config WIMAX_I2400M_DEBUG_LEVEL
int "WiMAX i2400m debug level"
depends on WIMAX_I2400M
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 18cadf099243..701e07aac810 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -5,6 +5,7 @@
menuconfig WLAN
bool "Wireless LAN"
depends on !S390
+ select WIRELESS
default y
---help---
This section contains all the 802.11 wireless LAN device
@@ -19,6 +20,8 @@ config PCMCIA_RAYCS
tristate "Aviator/Raytheon 2.4GHz wireless support"
depends on PCMCIA
select WIRELESS_EXT
+ select WEXT_SPY
+ select WEXT_PRIV
---help---
Say Y here if you intend to attach an Aviator/Raytheon PCMCIA
(PC-card) wireless Ethernet networking card to your computer.
@@ -28,45 +31,6 @@ config PCMCIA_RAYCS
To compile this driver as a module, choose M here: the module will be
called ray_cs. If unsure, say N.
-config LIBERTAS
- tristate "Marvell 8xxx Libertas WLAN driver support"
- select WIRELESS_EXT
- select LIB80211
- select FW_LOADER
- ---help---
- A library for Marvell Libertas 8xxx devices.
-
-config LIBERTAS_USB
- tristate "Marvell Libertas 8388 USB 802.11b/g cards"
- depends on LIBERTAS && USB
- ---help---
- A driver for Marvell Libertas 8388 USB devices.
-
-config LIBERTAS_CS
- tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards"
- depends on LIBERTAS && PCMCIA
- select FW_LOADER
- ---help---
- A driver for Marvell Libertas 8385 CompactFlash devices.
-
-config LIBERTAS_SDIO
- tristate "Marvell Libertas 8385/8686/8688 SDIO 802.11b/g cards"
- depends on LIBERTAS && MMC
- ---help---
- A driver for Marvell Libertas 8385/8686/8688 SDIO devices.
-
-config LIBERTAS_SPI
- tristate "Marvell Libertas 8686 SPI 802.11b/g cards"
- depends on LIBERTAS && SPI
- ---help---
- A driver for Marvell Libertas 8686 SPI devices.
-
-config LIBERTAS_DEBUG
- bool "Enable full debugging output in the Libertas module."
- depends on LIBERTAS
- ---help---
- Debugging support.
-
config LIBERTAS_THINFIRM
tristate "Marvell 8xxx Libertas WLAN driver support with thin firmware"
depends on MAC80211
@@ -85,6 +49,8 @@ config AIRO
depends on ISA_DMA_API && (PCI || BROKEN)
select WIRELESS_EXT
select CRYPTO
+ select WEXT_SPY
+ select WEXT_PRIV
---help---
This is the standard Linux driver to support Cisco/Aironet ISA and
PCI 802.11 wireless cards.
@@ -102,6 +68,7 @@ config ATMEL
tristate "Atmel at76c50x chipset 802.11b support"
depends on (PCI || PCMCIA)
select WIRELESS_EXT
+ select WEXT_PRIV
select FW_LOADER
select CRC32
---help---
@@ -161,18 +128,21 @@ config AIRO_CS
Cisco Linux utilities can be used to configure the card.
config PCMCIA_WL3501
- tristate "Planet WL3501 PCMCIA cards"
- depends on EXPERIMENTAL && PCMCIA
- select WIRELESS_EXT
- ---help---
- A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet.
- It has basic support for Linux wireless extensions and initial
- micro support for ethtool.
+ tristate "Planet WL3501 PCMCIA cards"
+ depends on EXPERIMENTAL && PCMCIA
+ select WIRELESS_EXT
+ select WEXT_SPY
+ help
+ A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet.
+ It has basic support for Linux wireless extensions and initial
+ micro support for ethtool.
config PRISM54
tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus (DEPRECATED)'
depends on PCI && EXPERIMENTAL
select WIRELESS_EXT
+ select WEXT_SPY
+ select WEXT_PRIV
select FW_LOADER
---help---
This enables support for FullMAC PCI/Cardbus prism54 devices. This
@@ -195,6 +165,7 @@ config USB_ZD1201
tristate "USB ZD1201 based Wireless device support"
depends on USB
select WIRELESS_EXT
+ select WEXT_PRIV
select FW_LOADER
---help---
Say Y if you want to use wireless LAN adapters based on the ZyDAS
@@ -371,17 +342,18 @@ config MWL8K
To compile this driver as a module, choose M here: the module
will be called mwl8k. If unsure, say N.
-source "drivers/net/wireless/p54/Kconfig"
source "drivers/net/wireless/ath/Kconfig"
-source "drivers/net/wireless/ipw2x00/Kconfig"
-source "drivers/net/wireless/iwlwifi/Kconfig"
-source "drivers/net/wireless/hostap/Kconfig"
source "drivers/net/wireless/b43/Kconfig"
source "drivers/net/wireless/b43legacy/Kconfig"
-source "drivers/net/wireless/zd1211rw/Kconfig"
-source "drivers/net/wireless/rt2x00/Kconfig"
+source "drivers/net/wireless/hostap/Kconfig"
+source "drivers/net/wireless/ipw2x00/Kconfig"
+source "drivers/net/wireless/iwlwifi/Kconfig"
+source "drivers/net/wireless/iwmc3200wifi/Kconfig"
+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/wl12xx/Kconfig"
-source "drivers/net/wireless/iwmc3200wifi/Kconfig"
+source "drivers/net/wireless/zd1211rw/Kconfig"
endif # WLAN
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 7116a1aa20ce..4eec87c3be2b 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -4790,9 +4790,8 @@ static int proc_stats_rid_open( struct inode *inode,
static int get_dec_u16( char *buffer, int *start, int limit ) {
u16 value;
int valid = 0;
- for( value = 0; buffer[*start] >= '0' &&
- buffer[*start] <= '9' &&
- *start < limit; (*start)++ ) {
+ for (value = 0; *start < limit && buffer[*start] >= '0' &&
+ buffer[*start] <= '9'; (*start)++) {
valid = 1;
value *= 10;
value += buffer[*start] - '0';
@@ -5660,7 +5659,8 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
pci_save_state(pdev);
- return pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ return 0;
}
static int airo_pci_resume(struct pci_dev *pdev)
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 8e1a55dec351..e559dc960552 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -2217,6 +2217,8 @@ static struct ieee80211_supported_band at76_supported_band = {
static int at76_init_new_device(struct at76_priv *priv,
struct usb_interface *interface)
{
+ struct wiphy *wiphy;
+ size_t len;
int ret;
/* set up the endpoint information */
@@ -2254,6 +2256,7 @@ static int at76_init_new_device(struct at76_priv *priv,
priv->device_unplugged = 0;
/* mac80211 initialisation */
+ wiphy = priv->hw->wiphy;
priv->hw->wiphy->max_scan_ssids = 1;
priv->hw->wiphy->max_scan_ie_len = 0;
priv->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
@@ -2265,6 +2268,13 @@ static int at76_init_new_device(struct at76_priv *priv,
SET_IEEE80211_DEV(priv->hw, &interface->dev);
SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+ len = sizeof(wiphy->fw_version);
+ snprintf(wiphy->fw_version, len, "%d.%d.%d-%d",
+ priv->fw_version.major, priv->fw_version.minor,
+ priv->fw_version.patch, priv->fw_version.build);
+
+ wiphy->hw_version = priv->board_type;
+
ret = ieee80211_register_hw(priv->hw);
if (ret) {
printk(KERN_ERR "cannot register mac80211 hw (status %d)!\n",
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig
index 11ded150b932..6ce86cb37654 100644
--- a/drivers/net/wireless/ath/Kconfig
+++ b/drivers/net/wireless/ath/Kconfig
@@ -16,7 +16,15 @@ menuconfig ATH_COMMON
http://wireless.kernel.org/en/users/Drivers/Atheros
if ATH_COMMON
+
+config ATH_DEBUG
+ bool "Atheros wireless debugging"
+ ---help---
+ Say Y, if you want to debug atheros wireless drivers.
+ Right now only ath9k makes use of this.
+
source "drivers/net/wireless/ath/ath5k/Kconfig"
source "drivers/net/wireless/ath/ath9k/Kconfig"
source "drivers/net/wireless/ath/ar9170/Kconfig"
+
endif
diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile
index 4bb0132ada37..8113a5042afa 100644
--- a/drivers/net/wireless/ath/Makefile
+++ b/drivers/net/wireless/ath/Makefile
@@ -1,6 +1,11 @@
obj-$(CONFIG_ATH5K) += ath5k/
-obj-$(CONFIG_ATH9K) += ath9k/
+obj-$(CONFIG_ATH9K_HW) += ath9k/
obj-$(CONFIG_AR9170_USB) += ar9170/
obj-$(CONFIG_ATH_COMMON) += ath.o
-ath-objs := main.o regd.o
+
+ath-objs := main.o \
+ regd.o \
+ hw.o
+
+ath-$(CONFIG_ATH_DEBUG) += debug.o
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h
index 914e4718a9a8..9f9459860d82 100644
--- a/drivers/net/wireless/ath/ar9170/ar9170.h
+++ b/drivers/net/wireless/ath/ar9170/ar9170.h
@@ -172,8 +172,6 @@ struct ar9170 {
/* interface mode settings */
struct ieee80211_vif *vif;
- u8 mac_addr[ETH_ALEN];
- u8 bssid[ETH_ALEN];
/* beaconing */
struct sk_buff *beacon;
@@ -204,6 +202,8 @@ struct ar9170 {
u8 power_2G_ht20[8];
u8 power_2G_ht40[8];
+ u8 phy_heavy_clip;
+
#ifdef CONFIG_AR9170_LEDS
struct delayed_work led_work;
struct ar9170_led leds[AR9170_NUM_LEDS];
@@ -231,7 +231,7 @@ struct ar9170 {
struct sk_buff_head tx_status_ampdu;
spinlock_t tx_ampdu_list_lock;
struct list_head tx_ampdu_list;
- unsigned int tx_ampdu_pending;
+ atomic_t tx_ampdu_pending;
/* rxstream mpdu merge */
struct ar9170_rxstream_mpdu_merge rx_mpdu;
diff --git a/drivers/net/wireless/ath/ar9170/cmd.c b/drivers/net/wireless/ath/ar9170/cmd.c
index f57a6200167b..cf6f5c4174a6 100644
--- a/drivers/net/wireless/ath/ar9170/cmd.c
+++ b/drivers/net/wireless/ath/ar9170/cmd.c
@@ -72,8 +72,7 @@ int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val)
return err;
}
-static int ar9170_read_mreg(struct ar9170 *ar, int nregs,
- const u32 *regs, u32 *out)
+int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out)
{
int i, err;
__le32 *offs, *res;
diff --git a/drivers/net/wireless/ath/ar9170/cmd.h b/drivers/net/wireless/ath/ar9170/cmd.h
index a4f0e50e52b4..826c45e6b274 100644
--- a/drivers/net/wireless/ath/ar9170/cmd.h
+++ b/drivers/net/wireless/ath/ar9170/cmd.h
@@ -44,6 +44,7 @@
int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len);
int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val);
int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val);
+int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out);
int ar9170_echo_test(struct ar9170 *ar, u32 v);
/*
diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h
index 6cbfb2f83391..701ddb7d8400 100644
--- a/drivers/net/wireless/ath/ar9170/hw.h
+++ b/drivers/net/wireless/ath/ar9170/hw.h
@@ -152,14 +152,14 @@ enum ar9170_cmd {
#define AR9170_MAC_REG_FTF_BIT14 BIT(14)
#define AR9170_MAC_REG_FTF_BIT15 BIT(15)
#define AR9170_MAC_REG_FTF_BAR BIT(24)
-#define AR9170_MAC_REG_FTF_BIT25 BIT(25)
+#define AR9170_MAC_REG_FTF_BA BIT(25)
#define AR9170_MAC_REG_FTF_PSPOLL BIT(26)
#define AR9170_MAC_REG_FTF_RTS BIT(27)
#define AR9170_MAC_REG_FTF_CTS BIT(28)
#define AR9170_MAC_REG_FTF_ACK BIT(29)
#define AR9170_MAC_REG_FTF_CFE BIT(30)
#define AR9170_MAC_REG_FTF_CFE_ACK BIT(31)
-#define AR9170_MAC_REG_FTF_DEFAULTS 0x0500ffff
+#define AR9170_MAC_REG_FTF_DEFAULTS 0x0700ffff
#define AR9170_MAC_REG_FTF_MONITOR 0xfd00ffff
#define AR9170_MAC_REG_RX_TOTAL (AR9170_MAC_REG_BASE + 0x6A0)
@@ -311,6 +311,8 @@ struct ar9170_tx_control {
#define AR9170_TX_PHY_SHORT_GI 0x80000000
+#define AR5416_MAX_RATE_POWER 63
+
struct ar9170_rx_head {
u8 plcp[12];
} __packed;
diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c
index 614e3218a2bc..ddc8c09dc79e 100644
--- a/drivers/net/wireless/ath/ar9170/mac.c
+++ b/drivers/net/wireless/ath/ar9170/mac.c
@@ -35,6 +35,9 @@
* 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 "ar9170.h"
#include "cmd.h"
@@ -227,11 +230,8 @@ static int ar9170_set_mac_reg(struct ar9170 *ar, const u32 reg, const u8 *mac)
ar9170_regwrite_begin(ar);
- ar9170_regwrite(reg,
- (mac[3] << 24) | (mac[2] << 16) |
- (mac[1] << 8) | mac[0]);
-
- ar9170_regwrite(reg + 4, (mac[5] << 8) | mac[4]);
+ ar9170_regwrite(reg, get_unaligned_le32(mac));
+ ar9170_regwrite(reg + 4, get_unaligned_le16(mac + 4));
ar9170_regwrite_finish();
@@ -311,13 +311,14 @@ static int ar9170_set_promiscouous(struct ar9170 *ar)
int ar9170_set_operating_mode(struct ar9170 *ar)
{
+ struct ath_common *common = &ar->common;
u32 pm_mode = AR9170_MAC_REG_POWERMGT_DEFAULTS;
u8 *mac_addr, *bssid;
int err;
if (ar->vif) {
- mac_addr = ar->mac_addr;
- bssid = ar->bssid;
+ mac_addr = common->macaddr;
+ bssid = common->curbssid;
switch (ar->vif->type) {
case NL80211_IFTYPE_MESH_POINT:
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index c1f8c69db165..7e59b82e64d3 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -414,9 +414,9 @@ static void ar9170_tx_ampdu_callback(struct ar9170 *ar, struct sk_buff *skb)
skb_queue_tail(&ar->tx_status_ampdu, skb);
ar9170_tx_fake_ampdu_status(ar);
- ar->tx_ampdu_pending--;
- if (!list_empty(&ar->tx_ampdu_list) && !ar->tx_ampdu_pending)
+ if (atomic_dec_and_test(&ar->tx_ampdu_pending) &&
+ !list_empty(&ar->tx_ampdu_list))
ar9170_tx_ampdu(ar);
}
@@ -1248,6 +1248,7 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
ar->global_ampdu_density = 6;
ar->global_ampdu_factor = 3;
+ atomic_set(&ar->tx_ampdu_pending, 0);
ar->bad_hw_nagger = jiffies;
err = ar->open(ar);
@@ -1773,7 +1774,7 @@ static void ar9170_tx(struct ar9170 *ar)
msecs_to_jiffies(AR9170_TX_TIMEOUT);
if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
- ar->tx_ampdu_pending++;
+ atomic_inc(&ar->tx_ampdu_pending);
#ifdef AR9170_QUEUE_DEBUG
printk(KERN_DEBUG "%s: send frame q:%d =>\n",
@@ -1784,7 +1785,7 @@ static void ar9170_tx(struct ar9170 *ar)
err = ar->tx(ar, skb);
if (unlikely(err)) {
if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
- ar->tx_ampdu_pending--;
+ atomic_dec(&ar->tx_ampdu_pending);
frames_failed++;
dev_kfree_skb_any(skb);
@@ -1931,7 +1932,7 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
bool run = ar9170_tx_ampdu_queue(ar, skb);
- if (run || !ar->tx_ampdu_pending)
+ if (run || !atomic_read(&ar->tx_ampdu_pending))
ar9170_tx_ampdu(ar);
} else {
unsigned int queue = skb_get_queue_mapping(skb);
@@ -1952,6 +1953,7 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
struct ar9170 *ar = hw->priv;
+ struct ath_common *common = &ar->common;
int err = 0;
mutex_lock(&ar->mutex);
@@ -1962,7 +1964,7 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw,
}
ar->vif = conf->vif;
- memcpy(ar->mac_addr, conf->mac_addr, ETH_ALEN);
+ memcpy(common->macaddr, conf->mac_addr, ETH_ALEN);
if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) {
ar->rx_software_decryption = true;
@@ -2131,12 +2133,13 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
u32 changed)
{
struct ar9170 *ar = hw->priv;
+ struct ath_common *common = &ar->common;
int err = 0;
mutex_lock(&ar->mutex);
if (changed & BSS_CHANGED_BSSID) {
- memcpy(ar->bssid, bss_conf->bssid, ETH_ALEN);
+ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
err = ar9170_set_operating_mode(ar);
if (err)
goto out;
@@ -2190,22 +2193,30 @@ static u64 ar9170_op_get_tsf(struct ieee80211_hw *hw)
{
struct ar9170 *ar = hw->priv;
int err;
- u32 tsf_low;
- u32 tsf_high;
u64 tsf;
+#define NR 3
+ static const u32 addr[NR] = { AR9170_MAC_REG_TSF_H,
+ AR9170_MAC_REG_TSF_L,
+ AR9170_MAC_REG_TSF_H };
+ u32 val[NR];
+ int loops = 0;
mutex_lock(&ar->mutex);
- err = ar9170_read_reg(ar, AR9170_MAC_REG_TSF_L, &tsf_low);
- if (!err)
- err = ar9170_read_reg(ar, AR9170_MAC_REG_TSF_H, &tsf_high);
+
+ while (loops++ < 10) {
+ err = ar9170_read_mreg(ar, NR, addr, val);
+ if (err || val[0] == val[2])
+ break;
+ }
+
mutex_unlock(&ar->mutex);
if (WARN_ON(err))
return 0;
-
- tsf = tsf_high;
- tsf = (tsf << 32) | tsf_low;
+ tsf = val[0];
+ tsf = (tsf << 32) | val[1];
return tsf;
+#undef NR
}
static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c
index dbd488da18b1..45a415ea809a 100644
--- a/drivers/net/wireless/ath/ar9170/phy.c
+++ b/drivers/net/wireless/ath/ar9170/phy.c
@@ -1239,9 +1239,6 @@ static u8 ar9170_get_max_edge_power(struct ar9170 *ar,
struct ar9170_calctl_edges edges[],
u32 freq)
{
-/* TODO: move somewhere else */
-#define AR5416_MAX_RATE_POWER 63
-
int i;
u8 rc = AR5416_MAX_RATE_POWER;
u8 f;
@@ -1259,10 +1256,11 @@ static u8 ar9170_get_max_edge_power(struct ar9170 *ar,
break;
}
if (i > 0 && f < edges[i].channel) {
- if (f > edges[i-1].channel &&
- edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) {
+ 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 &
+ rc = edges[i - 1].power_flags &
~AR9170_CALCTL_EDGE_FLAGS;
}
break;
@@ -1270,18 +1268,48 @@ static u8 ar9170_get_max_edge_power(struct ar9170 *ar,
}
if (i == AR5416_NUM_BAND_EDGES) {
- if (f > edges[i-1].channel &&
- edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) {
+ 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 &
+ rc = edges[i - 1].power_flags &
~AR9170_CALCTL_EDGE_FLAGS;
}
}
return rc;
}
-/* calculate the conformance test limits and apply them to ar->power*
- * (derived from otus hal/hpmain.c, line 3706 ff.)
+static u8 ar9170_get_heavy_clip(struct ar9170 *ar,
+ struct ar9170_calctl_edges edges[],
+ u32 freq, enum ar9170_bw bw)
+{
+ u8 f;
+ int i;
+ u8 rc = 0;
+
+ if (freq < 3000)
+ f = freq - 2300;
+ else
+ f = (freq - 4800) / 5;
+
+ if (bw == AR9170_BW_40_BELOW || bw == AR9170_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 ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
{
@@ -1295,7 +1323,8 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
int pwr_cal_len;
} *modes;
- /* order is relevant in the mode_list_*: we fall back to the
+ /*
+ * 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[] = {
@@ -1313,7 +1342,10 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
#define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n])
- /* TODO: investigate the differences between OTUS'
+ ar->phy_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
@@ -1347,6 +1379,15 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
if (ctl_idx < AR5416_NUM_CTLS) {
int f_off = 0;
+ /* determine heav clip parameter from
+ the 11G edges array */
+ if (modes[i].ctl_mode == CTL_11G) {
+ ar->phy_heavy_clip =
+ ar9170_get_heavy_clip(ar,
+ EDGES(ctl_idx, 1),
+ freq, bw);
+ }
+
/* adjust freq for 40MHz */
if (modes[i].ctl_mode == CTL_2GHT40 ||
modes[i].ctl_mode == CTL_5GHT40) {
@@ -1360,13 +1401,15 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
ar9170_get_max_edge_power(ar, EDGES(ctl_idx, 1),
freq+f_off);
- /* TODO: check if the regulatory max. power is
+ /*
+ * 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:
+ /*
+ * 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
@@ -1390,6 +1433,19 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
modes[i].max_power);
}
}
+
+ if (ar->phy_heavy_clip & 0xf0) {
+ ar->power_2G_ht40[0]--;
+ ar->power_2G_ht40[1]--;
+ ar->power_2G_ht40[2]--;
+ }
+ if (ar->phy_heavy_clip & 0xf) {
+ ar->power_2G_ht20[0]++;
+ ar->power_2G_ht20[1]++;
+ ar->power_2G_ht20[2]++;
+ }
+
+
#undef EDGES
}
@@ -1499,8 +1555,6 @@ static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
/* calc. conformance test limits and apply to ar->power*[] */
ar9170_calc_ctl(ar, freq, bw);
- /* TODO: (heavy clip) regulatory domain power level fine-tuning. */
-
/* set ACK/CTS TX power */
ar9170_regwrite_begin(ar);
@@ -1643,6 +1697,17 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
if (err)
return err;
+ if (ar->phy_heavy_clip) {
+ err = ar9170_write_reg(ar, 0x1c59e0,
+ 0x200 | ar->phy_heavy_clip);
+ if (err) {
+ if (ar9170_nag_limiter(ar))
+ printk(KERN_ERR "%s: failed to set "
+ "heavy clip\n",
+ wiphy_name(ar->hw->wiphy));
+ }
+ }
+
for (i = 0; i < 2; i++) {
ar->noise[i] = ar9170_calc_noise_dbm(
(le32_to_cpu(vals[2 + i]) >> 19) & 0x1ff);
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
index e974e5829e1a..6bdcdf6d1cc0 100644
--- a/drivers/net/wireless/ath/ar9170/usb.c
+++ b/drivers/net/wireless/ath/ar9170/usb.c
@@ -108,15 +108,15 @@ static void ar9170_usb_submit_urb(struct ar9170_usb *aru)
return ;
spin_lock_irqsave(&aru->tx_urb_lock, flags);
- if (aru->tx_submitted_urbs >= AR9170_NUM_TX_URBS) {
+ if (atomic_read(&aru->tx_submitted_urbs) >= AR9170_NUM_TX_URBS) {
spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
return ;
}
- aru->tx_submitted_urbs++;
+ atomic_inc(&aru->tx_submitted_urbs);
urb = usb_get_from_anchor(&aru->tx_pending);
if (!urb) {
- aru->tx_submitted_urbs--;
+ atomic_dec(&aru->tx_submitted_urbs);
spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
return ;
@@ -133,7 +133,7 @@ static void ar9170_usb_submit_urb(struct ar9170_usb *aru)
err);
usb_unanchor_urb(urb);
- aru->tx_submitted_urbs--;
+ atomic_dec(&aru->tx_submitted_urbs);
ar9170_tx_callback(&aru->common, urb->context);
}
@@ -151,7 +151,7 @@ static void ar9170_usb_tx_urb_complete_frame(struct urb *urb)
return ;
}
- aru->tx_submitted_urbs--;
+ atomic_dec(&aru->tx_submitted_urbs);
ar9170_tx_callback(&aru->common, skb);
@@ -794,7 +794,7 @@ static int ar9170_usb_probe(struct usb_interface *intf,
spin_lock_init(&aru->tx_urb_lock);
aru->tx_pending_urbs = 0;
- aru->tx_submitted_urbs = 0;
+ atomic_set(&aru->tx_submitted_urbs, 0);
aru->common.stop = ar9170_usb_stop;
aru->common.flush = ar9170_usb_flush;
diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h
index d098f4d5d2f2..a2ce3b169ceb 100644
--- a/drivers/net/wireless/ath/ar9170/usb.h
+++ b/drivers/net/wireless/ath/ar9170/usb.h
@@ -67,7 +67,7 @@ struct ar9170_usb {
bool req_one_stage_fw;
spinlock_t tx_urb_lock;
- unsigned int tx_submitted_urbs;
+ atomic_t tx_submitted_urbs;
unsigned int tx_pending_urbs;
struct completion cmd_wait;
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index a63e90cbf9e5..5e19a7330d39 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -18,6 +18,15 @@
#define ATH_H
#include <linux/skbuff.h>
+#include <linux/if_ether.h>
+#include <net/mac80211.h>
+
+static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+enum ath_device_state {
+ ATH_HW_UNAVAILABLE,
+ ATH_HW_INITIALIZED,
+};
struct reg_dmn_pair_mapping {
u16 regDmnEnum;
@@ -36,13 +45,45 @@ struct ath_regulatory {
struct reg_dmn_pair_mapping *regpair;
};
+struct ath_ops {
+ unsigned int (*read)(void *, u32 reg_offset);
+ void (*write)(void *, u32 val, u32 reg_offset);
+};
+
+struct ath_common;
+
+struct ath_bus_ops {
+ void (*read_cachesize)(struct ath_common *common, int *csz);
+ void (*cleanup)(struct ath_common *common);
+ bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
+ void (*bt_coex_prep)(struct ath_common *common);
+};
+
struct ath_common {
+ void *ah;
+ void *priv;
+ struct ieee80211_hw *hw;
+ int debug_mask;
+ enum ath_device_state state;
+
u16 cachelsz;
+ u16 curaid;
+ u8 macaddr[ETH_ALEN];
+ u8 curbssid[ETH_ALEN];
+ u8 bssidmask[ETH_ALEN];
+
+ u8 tx_chainmask;
+ u8 rx_chainmask;
+
struct ath_regulatory regulatory;
+ const struct ath_ops *ops;
+ const struct ath_bus_ops *bus_ops;
};
struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
u32 len,
gfp_t gfp_mask);
+void ath_hw_setbssidmask(struct ath_common *common);
+
#endif /* ATH_H */
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 6cd5efcec417..6a2a96761111 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -35,6 +35,7 @@
* TODO: Make a more generic struct (eg. add more stuff to ath5k_capabilities)
* and clean up common bits, then introduce set/get functions in eeprom.c */
#include "eeprom.h"
+#include "../ath.h"
/* PCI IDs */
#define PCI_DEVICE_ID_ATHEROS_AR5210 0x0007 /* AR5210 */
@@ -165,13 +166,6 @@
#define AR5K_INI_VAL_XR 0
#define AR5K_INI_VAL_MAX 5
-/* Used for BSSID etc manipulation */
-#define AR5K_LOW_ID(_a)( \
-(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24 \
-)
-
-#define AR5K_HIGH_ID(_a) ((_a)[4] | (_a)[5] << 8)
-
/*
* Some tuneable values (these should be changeable by the user)
* TODO: Make use of them and add more options OR use debug/configfs
@@ -204,6 +198,7 @@
#define AR5K_TUNE_CWMAX_11B 1023
#define AR5K_TUNE_CWMAX_XR 7
#define AR5K_TUNE_NOISE_FLOOR -72
+#define AR5K_TUNE_CCA_MAX_GOOD_VALUE -95
#define AR5K_TUNE_MAX_TXPOWER 63
#define AR5K_TUNE_DEFAULT_TXPOWER 25
#define AR5K_TUNE_TPC_TXPOWER false
@@ -1012,6 +1007,14 @@ struct ath5k_capabilities {
} cap_queues;
};
+/* size of noise floor history (keep it a power of two) */
+#define ATH5K_NF_CAL_HIST_MAX 8
+struct ath5k_nfcal_hist
+{
+ s16 index; /* current index into nfval */
+ s16 nfval[ATH5K_NF_CAL_HIST_MAX]; /* last few noise floors */
+};
+
/***************************************\
HARDWARE ABSTRACTION LAYER STRUCTURE
@@ -1027,6 +1030,7 @@ struct ath5k_capabilities {
/* TODO: Clean up and merge with ath5k_softc */
struct ath5k_hw {
u32 ah_magic;
+ struct ath_common common;
struct ath5k_softc *ah_sc;
void __iomem *ah_iobase;
@@ -1067,14 +1071,6 @@ struct ath5k_hw {
u8 ah_def_ant;
bool ah_software_retry;
- u8 ah_sta_id[ETH_ALEN];
-
- /* Current BSSID we are trying to assoc to / create.
- * This is passed by mac80211 on config_interface() and cached here for
- * use in resets */
- u8 ah_bssid[ETH_ALEN];
- u8 ah_bssid_mask[ETH_ALEN];
-
int ah_gpio_npins;
struct ath5k_capabilities ah_capabilities;
@@ -1125,6 +1121,8 @@ struct ath5k_hw {
struct ieee80211_channel r_last_channel;
} ah_radar;
+ struct ath5k_nfcal_hist ah_nfcal_hist;
+
/* noise floor from last periodic calibration */
s32 ah_noise_floor;
@@ -1160,7 +1158,7 @@ struct ath5k_hw {
*/
/* Attach/Detach Functions */
-extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc);
+extern int ath5k_hw_attach(struct ath5k_softc *sc);
extern void ath5k_hw_detach(struct ath5k_hw *ah);
/* LED functions */
@@ -1203,10 +1201,9 @@ extern bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah);
/* Protocol Control Unit Functions */
extern int ath5k_hw_set_opmode(struct ath5k_hw *ah);
/* BSSID Functions */
-extern void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac);
extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac);
-extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id);
-extern int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
+extern void ath5k_hw_set_associd(struct ath5k_hw *ah);
+extern void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
/* Receive start/stop functions */
extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
extern void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah);
@@ -1288,8 +1285,10 @@ extern int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah);
extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
/* PHY calibration */
+void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah);
extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel);
extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
+extern s16 ath5k_hw_get_noise_floor(struct ath5k_hw *ah);
extern void ath5k_hw_calibration_poll(struct ath5k_hw *ah);
/* Spur mitigation */
bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
@@ -1329,17 +1328,21 @@ static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo)
return turbo ? (clock / 80) : (clock / 40);
}
-/*
- * Read from a register
- */
+static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah)
+{
+ return &ah->common;
+}
+
+static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah)
+{
+ return &(ath5k_hw_common(ah)->regulatory);
+}
+
static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
{
return ioread32(ah->ah_iobase + reg);
}
-/*
- * Write to a register
- */
static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
{
iowrite32(val, ah->ah_iobase + reg);
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index 71a1bd254517..42284445b75e 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -101,25 +101,15 @@ static int ath5k_hw_post(struct ath5k_hw *ah)
* -ENODEV if the device is not supported or prints an error msg if something
* else went wrong.
*/
-struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc)
+int ath5k_hw_attach(struct ath5k_softc *sc)
{
- struct ath5k_hw *ah;
+ struct ath5k_hw *ah = sc->ah;
+ struct ath_common *common = ath5k_hw_common(ah);
struct pci_dev *pdev = sc->pdev;
struct ath5k_eeprom_info *ee;
int ret;
u32 srev;
- /*If we passed the test malloc a ath5k_hw struct*/
- ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
- if (ah == NULL) {
- ret = -ENOMEM;
- ATH5K_ERR(sc, "out of memory\n");
- goto err;
- }
-
- ah->ah_sc = sc;
- ah->ah_iobase = sc->iobase;
-
/*
* HW information
*/
@@ -278,12 +268,12 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc)
goto err_free;
}
+ ee = &ah->ah_capabilities.cap_eeprom;
+
/*
* Write PCI-E power save settings
*/
if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) {
- struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-
ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES);
ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES);
@@ -321,7 +311,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc)
}
/* Crypto settings */
- ee = &ah->ah_capabilities.cap_eeprom;
ah->ah_aes_support = srev >= AR5K_SREV_AR5212_V4 &&
(ee->ee_version >= AR5K_EEPROM_VERSION_5_0 &&
!AR5K_EEPROM_AES_DIS(ee->ee_misc5));
@@ -336,20 +325,21 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc)
ath5k_hw_set_lladdr(ah, (u8[ETH_ALEN]){});
/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
- memset(ah->ah_bssid, 0xff, ETH_ALEN);
- ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+ memcpy(common->curbssid, ath_bcast_mac, ETH_ALEN);
+ ath5k_hw_set_associd(ah);
ath5k_hw_set_opmode(ah);
ath5k_hw_rfgain_opt_init(ah);
+ ath5k_hw_init_nfcal_hist(ah);
+
/* turn on HW LEDs */
ath5k_hw_set_ledstate(ah, AR5K_LED_INIT);
- return ah;
+ return 0;
err_free:
kfree(ah);
-err:
- return ERR_PTR(ret);
+ return ret;
}
/**
@@ -369,5 +359,4 @@ void ath5k_hw_detach(struct ath5k_hw *ah)
ath5k_eeprom_detach(ah);
/* assume interrupts are down */
- kfree(ah);
}
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 9c6ab5378f6e..07c1e52b5a0c 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -195,12 +195,13 @@ 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
-static int ath5k_pci_suspend(struct pci_dev *pdev,
- pm_message_t state);
-static int ath5k_pci_resume(struct pci_dev *pdev);
+static int ath5k_pci_suspend(struct device *dev);
+static int ath5k_pci_resume(struct device *dev);
+
+SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume);
+#define ATH5K_PM_OPS (&ath5k_pm_ops)
#else
-#define ath5k_pci_suspend NULL
-#define ath5k_pci_resume NULL
+#define ATH5K_PM_OPS NULL
#endif /* CONFIG_PM */
static struct pci_driver ath5k_pci_driver = {
@@ -208,8 +209,7 @@ static struct pci_driver ath5k_pci_driver = {
.id_table = ath5k_pci_id_table,
.probe = ath5k_pci_probe,
.remove = __devexit_p(ath5k_pci_remove),
- .suspend = ath5k_pci_suspend,
- .resume = ath5k_pci_resume,
+ .driver.pm = ATH5K_PM_OPS,
};
@@ -437,6 +437,22 @@ ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val)
return name;
}
+static unsigned int ath5k_ioread32(void *hw_priv, u32 reg_offset)
+{
+ struct ath5k_hw *ah = (struct ath5k_hw *) hw_priv;
+ return ath5k_hw_reg_read(ah, reg_offset);
+}
+
+static void ath5k_iowrite32(void *hw_priv, u32 val, u32 reg_offset)
+{
+ struct ath5k_hw *ah = (struct ath5k_hw *) hw_priv;
+ ath5k_hw_reg_write(ah, val, reg_offset);
+}
+
+static const struct ath_ops ath5k_common_ops = {
+ .read = ath5k_ioread32,
+ .write = ath5k_iowrite32,
+};
static int __devinit
ath5k_pci_probe(struct pci_dev *pdev,
@@ -444,6 +460,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
{
void __iomem *mem;
struct ath5k_softc *sc;
+ struct ath_common *common;
struct ieee80211_hw *hw;
int ret;
u8 csz;
@@ -547,7 +564,6 @@ ath5k_pci_probe(struct pci_dev *pdev,
__set_bit(ATH_STAT_INVALID, sc->status);
sc->iobase = mem; /* So we can unmap it on detach */
- sc->common.cachelsz = csz << 2; /* convert to bytes */
sc->opmode = NL80211_IFTYPE_STATION;
sc->bintval = 1000;
mutex_init(&sc->lock);
@@ -565,13 +581,28 @@ ath5k_pci_probe(struct pci_dev *pdev,
goto err_free;
}
- /* Initialize device */
- sc->ah = ath5k_hw_attach(sc);
- if (IS_ERR(sc->ah)) {
- ret = PTR_ERR(sc->ah);
+ /*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;
@@ -640,6 +671,8 @@ 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:
@@ -661,6 +694,7 @@ ath5k_pci_remove(struct pci_dev *pdev)
ath5k_debug_finish_device(sc);
ath5k_detach(pdev, hw);
ath5k_hw_detach(sc->ah);
+ kfree(sc->ah);
free_irq(pdev->irq, sc);
pci_iounmap(pdev, sc->iobase);
pci_release_region(pdev, 0);
@@ -669,33 +703,20 @@ ath5k_pci_remove(struct pci_dev *pdev)
}
#ifdef CONFIG_PM
-static int
-ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+static int ath5k_pci_suspend(struct device *dev)
{
- struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+ struct ieee80211_hw *hw = pci_get_drvdata(to_pci_dev(dev));
struct ath5k_softc *sc = hw->priv;
ath5k_led_off(sc);
-
- pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
-
return 0;
}
-static int
-ath5k_pci_resume(struct pci_dev *pdev)
+static int ath5k_pci_resume(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct ath5k_softc *sc = hw->priv;
- int err;
-
- pci_restore_state(pdev);
-
- err = pci_enable_device(pdev);
- if (err)
- return err;
/*
* Suspend/Resume resets the PCI configuration space, so we have to
@@ -718,7 +739,7 @@ static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *re
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ath5k_softc *sc = hw->priv;
- struct ath_regulatory *regulatory = &sc->common.regulatory;
+ struct ath_regulatory *regulatory = ath5k_hw_regulatory(sc->ah);
return ath_reg_notifier_apply(wiphy, request, regulatory);
}
@@ -728,7 +749,7 @@ 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 = &sc->common.regulatory;
+ struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah);
u8 mac[ETH_ALEN] = {};
int ret;
@@ -815,7 +836,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
SET_IEEE80211_PERM_ADDR(hw, mac);
/* All MAC address bits matter for ACKs */
- memset(sc->bssidmask, 0xff, ETH_ALEN);
+ 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;
@@ -1153,19 +1174,20 @@ ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix)
static
struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr)
{
+ struct ath_common *common = ath5k_hw_common(sc->ah);
struct sk_buff *skb;
/*
* Allocate buffer with headroom_needed space for the
* fake physical layer header at the start.
*/
- skb = ath_rxbuf_alloc(&sc->common,
- sc->rxbufsize + sc->common.cachelsz - 1,
+ skb = ath_rxbuf_alloc(common,
+ sc->rxbufsize + common->cachelsz - 1,
GFP_ATOMIC);
if (!skb) {
ATH5K_ERR(sc, "can't alloc skbuff of size %u\n",
- sc->rxbufsize + sc->common.cachelsz - 1);
+ sc->rxbufsize + common->cachelsz - 1);
return NULL;
}
@@ -1606,13 +1628,14 @@ static int
ath5k_rx_start(struct ath5k_softc *sc)
{
struct ath5k_hw *ah = sc->ah;
+ struct ath_common *common = ath5k_hw_common(ah);
struct ath5k_buf *bf;
int ret;
- sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->common.cachelsz);
+ sc->rxbufsize = roundup(IEEE80211_MAX_LEN, common->cachelsz);
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n",
- sc->common.cachelsz, sc->rxbufsize);
+ common->cachelsz, sc->rxbufsize);
spin_lock_bh(&sc->rxbuflock);
sc->rxlink = NULL;
@@ -1685,13 +1708,14 @@ static void
ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
struct ieee80211_rx_status *rxs)
{
+ struct ath_common *common = ath5k_hw_common(sc->ah);
u64 tsf, bc_tstamp;
u32 hw_tu;
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
if (ieee80211_is_beacon(mgmt->frame_control) &&
le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS &&
- memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) {
+ memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) == 0) {
/*
* Received an IBSS beacon with the same BSSID. Hardware *must*
* have updated the local TSF. We have to work around various
@@ -3177,6 +3201,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
{
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);
@@ -3185,10 +3210,9 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
if (changes & BSS_CHANGED_BSSID) {
/* Cache for later use during resets */
- memcpy(ah->ah_bssid, bss_conf->bssid, ETH_ALEN);
- /* XXX: assoc id is set to 0 for now, mac80211 doesn't have
- * a clean way of letting us retrieve this yet. */
- ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
+ common->curaid = 0;
+ ath5k_hw_set_associd(ah);
mmiowb();
}
@@ -3201,6 +3225,14 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
set_beacon_filter(hw, sc->assoc);
ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
AR5K_LED_ASSOC : AR5K_LED_INIT);
+ if (bss_conf->assoc) {
+ ATH5K_DBG(sc, ATH5K_DEBUG_ANY,
+ "Bss Info ASSOC %d, bssid: %pM\n",
+ bss_conf->aid, common->curbssid);
+ common->curaid = bss_conf->aid;
+ ath5k_hw_set_associd(ah);
+ /* Once ANI is available you would start it here */
+ }
}
if (changes & BSS_CHANGED_BEACON) {
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index a28c42f32c9d..b73e7d38861b 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -115,7 +115,6 @@ struct ath5k_rfkill {
* associated with an instance of a device */
struct ath5k_softc {
struct pci_dev *pdev; /* for dma mapping */
- struct ath_common common;
void __iomem *iobase; /* address of the device */
struct mutex lock; /* dev-level lock */
struct ieee80211_tx_queue_stats tx_stats[AR5K_NUM_TX_QUEUES];
@@ -193,7 +192,7 @@ struct ath5k_softc {
struct ath5k_txq *cabq; /* content after beacon */
int power_level; /* Requested tx power in dbm */
- bool assoc; /* assocate state */
+ bool assoc; /* associate state */
bool enable_beacon; /* true if beacons are on */
};
@@ -202,15 +201,4 @@ struct ath5k_softc {
#define ath5k_hw_hasveol(_ah) \
(ath5k_hw_get_capability(_ah, AR5K_CAP_VEOL, 0, NULL) == 0)
-static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah)
-{
- return &ah->ah_sc->common;
-}
-
-static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah)
-{
- return &(ath5k_hw_common(ah)->regulatory);
-
-}
-
#endif
diff --git a/drivers/net/wireless/ath/ath5k/initvals.c b/drivers/net/wireless/ath/ath5k/initvals.c
index 18eb5190ce4b..8fa439308828 100644
--- a/drivers/net/wireless/ath/ath5k/initvals.c
+++ b/drivers/net/wireless/ath/ath5k/initvals.c
@@ -560,8 +560,8 @@ static const struct ath5k_ini ar5212_ini_common_start[] = {
{ AR5K_SLEEP0, 0x0002aaaa },
{ AR5K_SLEEP1, 0x02005555 },
{ AR5K_SLEEP2, 0x00000000 },
- { AR5K_BSS_IDM0, 0xffffffff },
- { AR5K_BSS_IDM1, 0x0000ffff },
+ { AR_BSSMSKL, 0xffffffff },
+ { AR_BSSMSKU, 0x0000ffff },
{ AR5K_TXPC, 0x00000000 },
{ AR5K_PROFCNT_TX, 0x00000000 },
{ AR5K_PROFCNT_RX, 0x00000000 },
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c
index 2942f13c9c4a..64fc1eb9b6d9 100644
--- a/drivers/net/wireless/ath/ath5k/pcu.c
+++ b/drivers/net/wireless/ath/ath5k/pcu.c
@@ -24,6 +24,8 @@
* Protocol Control Unit Functions *
\*********************************/
+#include <asm/unaligned.h>
+
#include "ath5k.h"
#include "reg.h"
#include "debug.h"
@@ -44,6 +46,7 @@
*/
int ath5k_hw_set_opmode(struct ath5k_hw *ah)
{
+ struct ath_common *common = ath5k_hw_common(ah);
u32 pcu_reg, beacon_reg, low_id, high_id;
@@ -95,8 +98,8 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah)
/*
* Set PCU registers
*/
- low_id = AR5K_LOW_ID(ah->ah_sta_id);
- high_id = AR5K_HIGH_ID(ah->ah_sta_id);
+ low_id = get_unaligned_le32(common->macaddr);
+ high_id = get_unaligned_le16(common->macaddr + 4);
ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
@@ -238,28 +241,6 @@ int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
return 0;
}
-
-/****************\
-* BSSID handling *
-\****************/
-
-/**
- * ath5k_hw_get_lladdr - Get station id
- *
- * @ah: The &struct ath5k_hw
- * @mac: The card's mac address
- *
- * Initialize ah->ah_sta_id using the mac address provided
- * (just a memcpy).
- *
- * TODO: Remove it once we merge ath5k_softc and ath5k_hw
- */
-void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac)
-{
- ATH5K_TRACE(ah->ah_sc);
- memcpy(mac, ah->ah_sta_id, ETH_ALEN);
-}
-
/**
* ath5k_hw_set_lladdr - Set station id
*
@@ -270,17 +251,18 @@ void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac)
*/
int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
{
+ struct ath_common *common = ath5k_hw_common(ah);
u32 low_id, high_id;
u32 pcu_reg;
ATH5K_TRACE(ah->ah_sc);
/* Set new station ID */
- memcpy(ah->ah_sta_id, mac, ETH_ALEN);
+ memcpy(common->macaddr, mac, ETH_ALEN);
pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
- low_id = AR5K_LOW_ID(mac);
- high_id = AR5K_HIGH_ID(mac);
+ low_id = get_unaligned_le32(mac);
+ high_id = get_unaligned_le16(mac + 4);
ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
@@ -297,159 +279,51 @@ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
*
* Sets the BSSID which trigers the "SME Join" operation
*/
-void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id)
+void ath5k_hw_set_associd(struct ath5k_hw *ah)
{
- u32 low_id, high_id;
+ struct ath_common *common = ath5k_hw_common(ah);
u16 tim_offset = 0;
/*
* Set simple BSSID mask on 5212
*/
- if (ah->ah_version == AR5K_AR5212) {
- ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask),
- AR5K_BSS_IDM0);
- ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask),
- AR5K_BSS_IDM1);
- }
+ if (ah->ah_version == AR5K_AR5212)
+ ath_hw_setbssidmask(common);
/*
* Set BSSID which triggers the "SME Join" operation
*/
- low_id = AR5K_LOW_ID(bssid);
- high_id = AR5K_HIGH_ID(bssid);
- ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0);
- ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) <<
- AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1);
-
- if (assoc_id == 0) {
+ ath5k_hw_reg_write(ah,
+ get_unaligned_le32(common->curbssid),
+ AR5K_BSS_ID0);
+ ath5k_hw_reg_write(ah,
+ get_unaligned_le16(common->curbssid + 4) |
+ ((common->curaid & 0x3fff) << AR5K_BSS_ID1_AID_S),
+ AR5K_BSS_ID1);
+
+ if (common->curaid == 0) {
ath5k_hw_disable_pspoll(ah);
return;
}
AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM,
- tim_offset ? tim_offset + 4 : 0);
+ tim_offset ? tim_offset + 4 : 0);
ath5k_hw_enable_pspoll(ah, NULL, 0);
}
-/**
- * ath5k_hw_set_bssid_mask - filter out bssids we listen
- *
- * @ah: the &struct ath5k_hw
- * @mask: the bssid_mask, a u8 array of size ETH_ALEN
- *
- * BSSID masking is a method used by AR5212 and newer hardware to inform PCU
- * which bits of the interface's MAC address should be looked at when trying
- * to decide which packets to ACK. In station mode and AP mode with a single
- * BSS every bit matters since we lock to only one BSS. In AP mode with
- * multiple BSSes (virtual interfaces) not every bit matters because hw must
- * accept frames for all BSSes and so we tweak some bits of our mac address
- * in order to have multiple BSSes.
- *
- * NOTE: This is a simple filter and does *not* filter out all
- * relevant frames. Some frames that are not for us might get ACKed from us
- * by PCU because they just match the mask.
- *
- * When handling multiple BSSes you can get the BSSID mask by computing the
- * set of ~ ( MAC XOR BSSID ) for all bssids we handle.
- *
- * When you do this you are essentially computing the common bits of all your
- * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with
- * the MAC address to obtain the relevant bits and compare the result with
- * (frame's BSSID & mask) to see if they match.
- */
-/*
- * Simple example: on your card you have have two BSSes you have created with
- * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address.
- * There is another BSSID-03 but you are not part of it. For simplicity's sake,
- * assuming only 4 bits for a mac address and for BSSIDs you can then have:
- *
- * \
- * MAC: 0001 |
- * BSSID-01: 0100 | --> Belongs to us
- * BSSID-02: 1001 |
- * /
- * -------------------
- * BSSID-03: 0110 | --> External
- * -------------------
- *
- * Our bssid_mask would then be:
- *
- * On loop iteration for BSSID-01:
- * ~(0001 ^ 0100) -> ~(0101)
- * -> 1010
- * bssid_mask = 1010
- *
- * On loop iteration for BSSID-02:
- * bssid_mask &= ~(0001 ^ 1001)
- * bssid_mask = (1010) & ~(0001 ^ 1001)
- * bssid_mask = (1010) & ~(1001)
- * bssid_mask = (1010) & (0110)
- * bssid_mask = 0010
- *
- * A bssid_mask of 0010 means "only pay attention to the second least
- * significant bit". This is because its the only bit common
- * amongst the MAC and all BSSIDs we support. To findout what the real
- * common bit is we can simply "&" the bssid_mask now with any BSSID we have
- * or our MAC address (we assume the hardware uses the MAC address).
- *
- * Now, suppose there's an incoming frame for BSSID-03:
- *
- * IFRAME-01: 0110
- *
- * An easy eye-inspeciton of this already should tell you that this frame
- * will not pass our check. This is beacuse the bssid_mask tells the
- * hardware to only look at the second least significant bit and the
- * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB
- * as 1, which does not match 0.
- *
- * So with IFRAME-01 we *assume* the hardware will do:
- *
- * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
- * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0;
- * --> allow = (0010) == 0000 ? 1 : 0;
- * --> allow = 0
- *
- * Lets now test a frame that should work:
- *
- * IFRAME-02: 0001 (we should allow)
- *
- * allow = (0001 & 1010) == 1010
- *
- * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
- * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0;
- * --> allow = (0010) == (0010)
- * --> allow = 1
- *
- * Other examples:
- *
- * IFRAME-03: 0100 --> allowed
- * IFRAME-04: 1001 --> allowed
- * IFRAME-05: 1101 --> allowed but its not for us!!!
- *
- */
-int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
+void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
{
- u32 low_id, high_id;
+ struct ath_common *common = ath5k_hw_common(ah);
ATH5K_TRACE(ah->ah_sc);
/* Cache bssid mask so that we can restore it
* on reset */
- memcpy(ah->ah_bssid_mask, mask, ETH_ALEN);
- if (ah->ah_version == AR5K_AR5212) {
- low_id = AR5K_LOW_ID(mask);
- high_id = AR5K_HIGH_ID(mask);
-
- ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0);
- ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1);
-
- return 0;
- }
-
- return -EIO;
+ memcpy(common->bssidmask, mask, ETH_ALEN);
+ if (ah->ah_version == AR5K_AR5212)
+ ath_hw_setbssidmask(common);
}
-
/************\
* RX Control *
\************/
@@ -1157,14 +1031,17 @@ int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac)
/* Invalid entry (key table overflow) */
AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
- /* MAC may be NULL if it's a broadcast key. In this case no need to
- * to compute AR5K_LOW_ID and AR5K_HIGH_ID as we already know it. */
+ /*
+ * 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 = AR5K_LOW_ID(mac);
- high_id = AR5K_HIGH_ID(mac) | AR5K_KEYTABLE_VALID;
+ low_id = get_unaligned_le32(mac);
+ high_id = get_unaligned_le16(mac + 4) | AR5K_KEYTABLE_VALID;
}
ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry));
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index 1a039f2bd732..895990751d36 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -1124,77 +1124,148 @@ ath5k_hw_calibration_poll(struct ath5k_hw *ah)
ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION;
AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI);
}
+}
+static int sign_extend(int val, const int nbits)
+{
+ int order = BIT(nbits-1);
+ return (val ^ order) - order;
}
-/**
- * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration
- *
- * @ah: struct ath5k_hw pointer we are operating on
- * @freq: the channel frequency, just used for error logging
- *
- * This function performs a noise floor calibration of the PHY and waits for
- * it to complete. Then the noise floor value is compared to some maximum
- * noise floor we consider valid.
- *
- * Note that this is different from what the madwifi HAL does: it reads the
- * noise floor and afterwards initiates the calibration. Since the noise floor
- * calibration can take some time to finish, depending on the current channel
- * use, that avoids the occasional timeout warnings we are seeing now.
- *
- * See the following link for an Atheros patent on noise floor calibration:
- * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \
- * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7
+static s32 ath5k_hw_read_measured_noise_floor(struct ath5k_hw *ah)
+{
+ s32 val;
+
+ val = ath5k_hw_reg_read(ah, AR5K_PHY_NF);
+ return sign_extend(AR5K_REG_MS(val, AR5K_PHY_NF_MINCCA_PWR), 9);
+}
+
+void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah)
+{
+ int i;
+
+ ah->ah_nfcal_hist.index = 0;
+ for (i = 0; i < ATH5K_NF_CAL_HIST_MAX; i++)
+ ah->ah_nfcal_hist.nfval[i] = AR5K_TUNE_CCA_MAX_GOOD_VALUE;
+}
+
+static void ath5k_hw_update_nfcal_hist(struct ath5k_hw *ah, s16 noise_floor)
+{
+ struct ath5k_nfcal_hist *hist = &ah->ah_nfcal_hist;
+ hist->index = (hist->index + 1) & (ATH5K_NF_CAL_HIST_MAX-1);
+ hist->nfval[hist->index] = noise_floor;
+}
+
+static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah)
+{
+ s16 sort[ATH5K_NF_CAL_HIST_MAX];
+ s16 tmp;
+ int i, j;
+
+ memcpy(sort, ah->ah_nfcal_hist.nfval, sizeof(sort));
+ for (i = 0; i < ATH5K_NF_CAL_HIST_MAX - 1; i++) {
+ for (j = 1; j < ATH5K_NF_CAL_HIST_MAX - i; j++) {
+ if (sort[j] > sort[j-1]) {
+ tmp = sort[j];
+ sort[j] = sort[j-1];
+ sort[j-1] = tmp;
+ }
+ }
+ }
+ for (i = 0; i < ATH5K_NF_CAL_HIST_MAX; i++) {
+ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
+ "cal %d:%d\n", i, sort[i]);
+ }
+ return sort[(ATH5K_NF_CAL_HIST_MAX-1) / 2];
+}
+
+/*
+ * When we tell the hardware to perform a noise floor calibration
+ * by setting the AR5K_PHY_AGCCTL_NF bit, it will periodically
+ * sample-and-hold the minimum noise level seen at the antennas.
+ * This value is then stored in a ring buffer of recently measured
+ * noise floor values so we have a moving window of the last few
+ * samples.
*
- * XXX: Since during noise floor calibration antennas are detached according to
- * the patent, we should stop tx queues here.
+ * The median of the values in the history is then loaded into the
+ * hardware for its own use for RSSI and CCA measurements.
*/
-int
-ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
+void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
{
- int ret;
- unsigned int i;
- s32 noise_floor;
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ u32 val;
+ s16 nf, threshold;
+ u8 ee_mode;
- /*
- * Enable noise floor calibration
- */
- AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
- AR5K_PHY_AGCCTL_NF);
+ /* keep last value if calibration hasn't completed */
+ if (ath5k_hw_reg_read(ah, AR5K_PHY_AGCCTL) & AR5K_PHY_AGCCTL_NF) {
+ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
+ "NF did not complete in calibration window\n");
- ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
- AR5K_PHY_AGCCTL_NF, 0, false);
- if (ret) {
- ATH5K_ERR(ah->ah_sc,
- "noise floor calibration timeout (%uMHz)\n", freq);
- return -EAGAIN;
+ return;
}
- /* Wait until the noise floor is calibrated and read the value */
- for (i = 20; i > 0; i--) {
- mdelay(1);
- noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF);
- noise_floor = AR5K_PHY_NF_RVAL(noise_floor);
- if (noise_floor & AR5K_PHY_NF_ACTIVE) {
- noise_floor = AR5K_PHY_NF_AVAL(noise_floor);
-
- if (noise_floor <= AR5K_TUNE_NOISE_FLOOR)
- break;
- }
+ switch (ah->ah_current_channel->hw_value & CHANNEL_MODES) {
+ case CHANNEL_A:
+ case CHANNEL_T:
+ case CHANNEL_XR:
+ ee_mode = AR5K_EEPROM_MODE_11A;
+ break;
+ case CHANNEL_G:
+ case CHANNEL_TG:
+ ee_mode = AR5K_EEPROM_MODE_11G;
+ break;
+ default:
+ case CHANNEL_B:
+ ee_mode = AR5K_EEPROM_MODE_11B;
+ break;
}
- ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
- "noise floor %d\n", noise_floor);
- if (noise_floor > AR5K_TUNE_NOISE_FLOOR) {
- ATH5K_ERR(ah->ah_sc,
- "noise floor calibration failed (%uMHz)\n", freq);
- return -EAGAIN;
+ /* completed NF calibration, test threshold */
+ nf = ath5k_hw_read_measured_noise_floor(ah);
+ threshold = ee->ee_noise_floor_thr[ee_mode];
+
+ if (nf > threshold) {
+ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
+ "noise floor failure detected; "
+ "read %d, threshold %d\n",
+ nf, threshold);
+
+ nf = AR5K_TUNE_CCA_MAX_GOOD_VALUE;
}
- ah->ah_noise_floor = noise_floor;
+ ath5k_hw_update_nfcal_hist(ah, nf);
+ nf = ath5k_hw_get_median_noise_floor(ah);
- return 0;
+ /* load noise floor (in .5 dBm) so the hardware will use it */
+ val = ath5k_hw_reg_read(ah, AR5K_PHY_NF) & ~AR5K_PHY_NF_M;
+ val |= (nf * 2) & AR5K_PHY_NF_M;
+ ath5k_hw_reg_write(ah, val, AR5K_PHY_NF);
+
+ AR5K_REG_MASKED_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_NF,
+ ~(AR5K_PHY_AGCCTL_NF_EN | AR5K_PHY_AGCCTL_NF_NOUPDATE));
+
+ ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_NF,
+ 0, false);
+
+ /*
+ * Load a high max CCA Power value (-50 dBm in .5 dBm units)
+ * so that we're not capped by the median we just loaded.
+ * This will be used as the initial value for the next noise
+ * floor calibration.
+ */
+ val = (val & ~AR5K_PHY_NF_M) | ((-50 * 2) & AR5K_PHY_NF_M);
+ ath5k_hw_reg_write(ah, val, AR5K_PHY_NF);
+ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
+ AR5K_PHY_AGCCTL_NF_EN |
+ AR5K_PHY_AGCCTL_NF_NOUPDATE |
+ AR5K_PHY_AGCCTL_NF);
+
+ ah->ah_noise_floor = nf;
+
+ ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
+ "noise floor calibrated: %d\n", nf);
}
/*
@@ -1287,7 +1358,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
return ret;
}
- ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
+ ath5k_hw_update_noise_floor(ah);
/*
* Re-enable RX/TX and beacons
@@ -1360,7 +1431,7 @@ done:
* since noise floor calibration interrupts rx path while I/Q
* calibration doesn't. We don't need to run noise floor calibration
* as often as I/Q calibration.*/
- ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
+ ath5k_hw_update_noise_floor(ah);
/* Initiate a gain_F calibration */
ath5k_hw_request_rfgain_probe(ah);
diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h
index c63ea6afd96f..4cb9c5df9f46 100644
--- a/drivers/net/wireless/ath/ath5k/reg.h
+++ b/drivers/net/wireless/ath/ath5k/reg.h
@@ -35,7 +35,7 @@
* released by Atheros and on various debug messages found on the net.
*/
-
+#include "../reg.h"
/*====MAC DMA REGISTERS====*/
@@ -1650,12 +1650,6 @@
#define AR5K_SLEEP2_DTIM_PER_S 16
/*
- * BSSID mask registers
- */
-#define AR5K_BSS_IDM0 0x80e0 /* Upper bits */
-#define AR5K_BSS_IDM1 0x80e4 /* Lower bits */
-
-/*
* TX power control (TPC) register
*
* XXX: PCDAC steps (0.5dbm) or DBM ?
@@ -2039,17 +2033,14 @@
#define AR5K_PHY_AGCCTL_NF_NOUPDATE 0x00020000 /* Don't update nf automaticaly */
/*
- * PHY noise floor status register
+ * PHY noise floor status register (CCA = Clear Channel Assessment)
*/
#define AR5K_PHY_NF 0x9864 /* Register address */
-#define AR5K_PHY_NF_M 0x000001ff /* Noise floor mask */
-#define AR5K_PHY_NF_ACTIVE 0x00000100 /* Noise floor calibration still active */
-#define AR5K_PHY_NF_RVAL(_n) (((_n) >> 19) & AR5K_PHY_NF_M)
-#define AR5K_PHY_NF_AVAL(_n) (-((_n) ^ AR5K_PHY_NF_M) + 1)
-#define AR5K_PHY_NF_SVAL(_n) (((_n) & AR5K_PHY_NF_M) | (1 << 9))
+#define AR5K_PHY_NF_M 0x000001ff /* Noise floor, written to hardware in 1/2 dBm units */
+#define AR5K_PHY_NF_SVAL(_n) (((_n) & AR5K_PHY_NF_M) | (1 << 9))
#define AR5K_PHY_NF_THRESH62 0x0007f000 /* Thresh62 -check ANI patent- (field) */
#define AR5K_PHY_NF_THRESH62_S 12
-#define AR5K_PHY_NF_MINCCA_PWR 0x0ff80000 /* ??? */
+#define AR5K_PHY_NF_MINCCA_PWR 0x0ff80000 /* Minimum measured noise level, read from hardware in 1 dBm units */
#define AR5K_PHY_NF_MINCCA_PWR_S 19
/*
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 34e13c700849..62954fc77869 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -25,6 +25,8 @@
Reset functions and helpers
\*****************************/
+#include <asm/unaligned.h>
+
#include <linux/pci.h> /* To determine if a card is pci-e */
#include <linux/log2.h>
#include "ath5k.h"
@@ -870,6 +872,7 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
struct ieee80211_channel *channel, bool change_channel)
{
+ struct ath_common *common = ath5k_hw_common(ah);
u32 s_seq[10], s_ant, s_led[3], staid1_flags, tsf_up, tsf_lo;
u32 phy_tst1;
u8 mode, freq, ee_mode, ant[2];
@@ -1171,10 +1174,12 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO);
/* Restore sta_id flags and preserve our mac address*/
- ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_sta_id),
- AR5K_STA_ID0);
- ath5k_hw_reg_write(ah, staid1_flags | AR5K_HIGH_ID(ah->ah_sta_id),
- AR5K_STA_ID1);
+ ath5k_hw_reg_write(ah,
+ get_unaligned_le32(common->macaddr),
+ AR5K_STA_ID0);
+ ath5k_hw_reg_write(ah,
+ staid1_flags | get_unaligned_le16(common->macaddr + 4),
+ AR5K_STA_ID1);
/*
@@ -1182,8 +1187,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
*/
/* Restore bssid and bssid mask */
- /* XXX: add ah->aid once mac80211 gives this to us */
- ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+ ath5k_hw_set_associd(ah);
/* Set PCU config */
ath5k_hw_set_opmode(ah);
@@ -1289,7 +1293,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
* out and/or noise floor calibration might timeout.
*/
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
- AR5K_PHY_AGCCTL_CAL);
+ AR5K_PHY_AGCCTL_CAL | AR5K_PHY_AGCCTL_NF);
/* At the same time start I/Q calibration for QAM constellation
* -no need for CCK- */
@@ -1310,21 +1314,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
channel->center_freq);
}
- /*
- * If we run NF calibration before AGC, it always times out.
- * Binary HAL starts NF and AGC calibration at the same time
- * and only waits for AGC to finish. Also if AGC or NF cal.
- * times out, reset doesn't fail on binary HAL. I believe
- * that's wrong because since rx path is routed to a detector,
- * if cal. doesn't finish we won't have RX. Sam's HAL for AR5210/5211
- * enables noise floor calibration after offset calibration and if noise
- * floor calibration fails, reset fails. I believe that's
- * a better approach, we just need to find a polling interval
- * that suits best, even if reset continues we need to make
- * sure that rx path is ready.
- */
- ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
-
/* Restore antenna mode */
ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index ef5f59c4dd80..99ce066392a7 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -1,6 +1,10 @@
+config ATH9K_HW
+ tristate
+
config ATH9K
tristate "Atheros 802.11n wireless cards support"
depends on PCI && MAC80211 && WLAN_80211
+ select ATH9K_HW
select MAC80211_LEDS
select LEDS_CLASS
select NEW_LEDS
@@ -16,6 +20,8 @@ config ATH9K
If you choose to build a module, it'll be called ath9k.
+if ATH_DEBUG
+
config ATH9K_DEBUG
bool "Atheros ath9k debugging"
depends on ATH9K
@@ -26,3 +32,5 @@ config ATH9K_DEBUG
modprobe ath9k debug=0x00000200
Look in ath9k/debug.h for possible debug masks
+
+endif # ATH_DEBUG
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index ff2c9a26c10c..8caf2a8f8953 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -1,22 +1,25 @@
-ath9k-y += hw.o \
- eeprom.o \
- eeprom_def.o \
- eeprom_4k.o \
- eeprom_9287.o \
- mac.o \
- calib.o \
- ani.o \
- phy.o \
- beacon.o \
+ath9k-y += beacon.o \
main.o \
recv.o \
xmit.o \
virtual.o \
- rc.o \
- btcoex.o
+ rc.o
ath9k-$(CONFIG_PCI) += pci.o
ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o
ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o
obj-$(CONFIG_ATH9K) += ath9k.o
+
+ath9k_hw-y:= hw.o \
+ eeprom.o \
+ eeprom_def.o \
+ eeprom_4k.o \
+ eeprom_9287.o \
+ calib.o \
+ ani.o \
+ phy.o \
+ btcoex.o \
+ mac.o \
+
+obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 2ad7d0280f7a..25531f231b67 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -22,27 +22,29 @@
#include "ath9k.h"
/* return bus cachesize in 4B word units */
-static void ath_ahb_read_cachesize(struct ath_softc *sc, int *csz)
+static void ath_ahb_read_cachesize(struct ath_common *common, int *csz)
{
*csz = L1_CACHE_BYTES >> 2;
}
-static void ath_ahb_cleanup(struct ath_softc *sc)
+static void ath_ahb_cleanup(struct ath_common *common)
{
+ struct ath_softc *sc = (struct ath_softc *)common->priv;
iounmap(sc->mem);
}
-static bool ath_ahb_eeprom_read(struct ath_hw *ah, u32 off, u16 *data)
+static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
{
- struct ath_softc *sc = ah->ah_sc;
+ struct ath_softc *sc = (struct ath_softc *)common->priv;
struct platform_device *pdev = to_platform_device(sc->dev);
struct ath9k_platform_data *pdata;
pdata = (struct ath9k_platform_data *) pdev->dev.platform_data;
if (off >= (ARRAY_SIZE(pdata->eeprom_data))) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "%s: flash read failed, offset %08x is out of range\n",
- __func__, off);
+ ath_print(common, ATH_DBG_FATAL,
+ "%s: flash read failed, offset %08x "
+ "is out of range\n",
+ __func__, off);
return false;
}
@@ -116,10 +118,9 @@ static int ath_ahb_probe(struct platform_device *pdev)
sc->hw = hw;
sc->dev = &pdev->dev;
sc->mem = mem;
- sc->bus_ops = &ath_ahb_bus_ops;
sc->irq = irq;
- ret = ath_init_device(AR5416_AR9100_DEVID, sc, 0x0);
+ ret = ath_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops);
if (ret) {
dev_err(&pdev->dev, "failed to initialize device\n");
goto err_free_hw;
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index 2b493742ef10..2a0cd64c2bfb 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "ath9k.h"
+#include "hw.h"
static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
struct ath9k_channel *chan)
@@ -31,8 +31,8 @@ static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
}
}
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "No more channel states left. Using channel 0\n");
+ ath_print(ath9k_hw_common(ah), ATH_DBG_ANI,
+ "No more channel states left. Using channel 0\n");
return 0;
}
@@ -41,16 +41,17 @@ static bool ath9k_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);
switch (cmd & ah->ani_function) {
case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
u32 level = param;
if (level >= ARRAY_SIZE(ah->totalSizeDesired)) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "level out of range (%u > %u)\n",
- level,
- (unsigned)ARRAY_SIZE(ah->totalSizeDesired));
+ ath_print(common, ATH_DBG_ANI,
+ "level out of range (%u > %u)\n",
+ level,
+ (unsigned)ARRAY_SIZE(ah->totalSizeDesired));
return false;
}
@@ -152,10 +153,10 @@ static bool ath9k_hw_ani_control(struct ath_hw *ah,
u32 level = param;
if (level >= ARRAY_SIZE(firstep)) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "level out of range (%u > %u)\n",
- level,
- (unsigned) ARRAY_SIZE(firstep));
+ ath_print(common, ATH_DBG_ANI,
+ "level out of range (%u > %u)\n",
+ level,
+ (unsigned) ARRAY_SIZE(firstep));
return false;
}
REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
@@ -174,11 +175,10 @@ static bool ath9k_hw_ani_control(struct ath_hw *ah,
u32 level = param;
if (level >= ARRAY_SIZE(cycpwrThr1)) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "level out of range (%u > %u)\n",
- level,
- (unsigned)
- ARRAY_SIZE(cycpwrThr1));
+ ath_print(common, ATH_DBG_ANI,
+ "level out of range (%u > %u)\n",
+ level,
+ (unsigned) ARRAY_SIZE(cycpwrThr1));
return false;
}
REG_RMW_FIELD(ah, AR_PHY_TIMING5,
@@ -194,25 +194,28 @@ static bool ath9k_hw_ani_control(struct ath_hw *ah,
case ATH9K_ANI_PRESENT:
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "invalid cmd %u\n", cmd);
+ ath_print(common, ATH_DBG_ANI,
+ "invalid cmd %u\n", cmd);
return false;
}
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "ANI parameters:\n");
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
- "ofdmWeakSigDetectOff=%d\n",
- aniState->noiseImmunityLevel, aniState->spurImmunityLevel,
- !aniState->ofdmWeakSigDetectOff);
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "cckWeakSigThreshold=%d, "
- "firstepLevel=%d, listenTime=%d\n",
- aniState->cckWeakSigThreshold, aniState->firstepLevel,
- aniState->listenTime);
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ ath_print(common, ATH_DBG_ANI, "ANI parameters:\n");
+ ath_print(common, ATH_DBG_ANI,
+ "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
+ "ofdmWeakSigDetectOff=%d\n",
+ aniState->noiseImmunityLevel,
+ aniState->spurImmunityLevel,
+ !aniState->ofdmWeakSigDetectOff);
+ ath_print(common, ATH_DBG_ANI,
+ "cckWeakSigThreshold=%d, "
+ "firstepLevel=%d, listenTime=%d\n",
+ aniState->cckWeakSigThreshold,
+ aniState->firstepLevel,
+ aniState->listenTime);
+ ath_print(common, ATH_DBG_ANI,
"cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
- aniState->cycleCount, aniState->ofdmPhyErrCount,
+ aniState->cycleCount,
+ aniState->ofdmPhyErrCount,
aniState->cckPhyErrCount);
return true;
@@ -231,6 +234,7 @@ static void ath9k_hw_update_mibstats(struct ath_hw *ah,
static void ath9k_ani_restart(struct ath_hw *ah)
{
struct ar5416AniState *aniState;
+ struct ath_common *common = ath9k_hw_common(ah);
if (!DO_ANI(ah))
return;
@@ -240,24 +244,24 @@ static void ath9k_ani_restart(struct ath_hw *ah)
if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
aniState->ofdmPhyErrBase = 0;
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "OFDM Trigger is too high for hw counters\n");
+ 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;
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "CCK Trigger is too high for hw counters\n");
+ ath_print(common, ATH_DBG_ANI,
+ "CCK Trigger is too high for hw counters\n");
} else {
aniState->cckPhyErrBase =
AR_PHY_COUNTMAX - aniState->cckTrigHigh;
}
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Writing ofdmbase=%u cckbase=%u\n",
- aniState->ofdmPhyErrBase,
- aniState->cckPhyErrBase);
+ ath_print(common, ATH_DBG_ANI,
+ "Writing ofdmbase=%u cckbase=%u\n",
+ aniState->ofdmPhyErrBase,
+ aniState->cckPhyErrBase);
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);
@@ -271,7 +275,7 @@ static void ath9k_ani_restart(struct ath_hw *ah)
static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
{
- struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+ struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
struct ar5416AniState *aniState;
int32_t rssi;
@@ -343,7 +347,7 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
{
- struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+ struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
struct ar5416AniState *aniState;
int32_t rssi;
@@ -464,6 +468,7 @@ void ath9k_ani_reset(struct ath_hw *ah)
{
struct ar5416AniState *aniState;
struct ath9k_channel *chan = ah->curchan;
+ struct ath_common *common = ath9k_hw_common(ah);
int index;
if (!DO_ANI(ah))
@@ -475,8 +480,8 @@ void ath9k_ani_reset(struct ath_hw *ah)
if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION
&& ah->opmode != NL80211_IFTYPE_ADHOC) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Reset ANI state opmode %u\n", ah->opmode);
+ ath_print(common, ATH_DBG_ANI,
+ "Reset ANI state opmode %u\n", ah->opmode);
ah->stats.ast_ani_reset++;
if (ah->opmode == NL80211_IFTYPE_AP) {
@@ -543,6 +548,7 @@ 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;
@@ -569,20 +575,22 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah,
if (phyCnt1 < aniState->ofdmPhyErrBase ||
phyCnt2 < aniState->cckPhyErrBase) {
if (phyCnt1 < aniState->ofdmPhyErrBase) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "phyCnt1 0x%x, resetting "
- "counter value to 0x%x\n",
- 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) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "phyCnt2 0x%x, resetting "
- "counter value to 0x%x\n",
- 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,
@@ -621,10 +629,13 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah,
}
}
}
+EXPORT_SYMBOL(ath9k_hw_ani_monitor);
void ath9k_enable_mib_counters(struct ath_hw *ah)
{
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n");
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ ath_print(common, ATH_DBG_ANI, "Enable MIB counters\n");
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
@@ -640,7 +651,10 @@ void ath9k_enable_mib_counters(struct ath_hw *ah)
/* Freeze the MIB counters, get the stats and then clear them */
void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
{
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n");
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ ath_print(common, ATH_DBG_ANI, "Disable MIB counters\n");
+
REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC);
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC);
@@ -653,6 +667,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
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;
@@ -662,8 +677,8 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
u32 cc = REG_READ(ah, AR_CCCNT);
if (cycles == 0 || cycles > cc) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "cycle counter wrap. ExtBusy = 0\n");
+ ath_print(common, ATH_DBG_ANI,
+ "cycle counter wrap. ExtBusy = 0\n");
good = 0;
} else {
u32 cc_d = cc - cycles;
@@ -742,6 +757,7 @@ void ath9k_hw_procmibevent(struct ath_hw *ah)
ath9k_ani_restart(ah);
}
}
+EXPORT_SYMBOL(ath9k_hw_procmibevent);
void ath9k_hw_ani_setup(struct ath_hw *ah)
{
@@ -762,9 +778,10 @@ void ath9k_hw_ani_setup(struct ath_hw *ah)
void ath9k_hw_ani_init(struct ath_hw *ah)
{
+ struct ath_common *common = ath9k_hw_common(ah);
int i;
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Initialize ANI\n");
+ 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++) {
@@ -786,11 +803,11 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
}
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Setting OfdmErrBase = 0x%08x\n",
- ah->ani[0].ofdmPhyErrBase);
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
- ah->ani[0].cckPhyErrBase);
+ 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);
REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
@@ -803,7 +820,7 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
void ath9k_hw_ani_disable(struct ath_hw *ah)
{
- DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling ANI\n");
+ ath_print(ath9k_hw_common(ah), ATH_DBG_ANI, "Disabling ANI\n");
ath9k_hw_disable_mib_counters(ah);
REG_WRITE(ah, AR_PHY_ERR_1, 0);
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 1d59f10f68da..13dd0202d6b5 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -26,7 +26,7 @@
#include "rc.h"
#include "debug.h"
#include "../ath.h"
-#include "btcoex.h"
+#include "../debug.h"
struct ath_node;
@@ -54,15 +54,11 @@ struct ath_node;
#define A_MAX(a, b) ((a) > (b) ? (a) : (b))
-#define ASSERT(exp) BUG_ON(!(exp))
-
#define TSF_TO_TU(_h,_l) \
((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
#define ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<<i))
-static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
struct ath_config {
u32 ath_aggr_prot;
u16 txpowlimit;
@@ -191,7 +187,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
/* minimum h/w qdepth to be sustained to maximize aggregation */
#define ATH_AGGR_MIN_QDEPTH 2
#define ATH_AMPDU_SUBFRAME_DEFAULT 32
-#define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1)
#define IEEE80211_SEQ_SEQ_SHIFT 4
#define IEEE80211_SEQ_MAX 4096
@@ -293,7 +288,6 @@ struct ath_tx_control {
#define ATH_RSSI_LPF_LEN 10
#define RSSI_LPF_THRESHOLD -20
-#define ATH9K_RSSI_BAD 0x80
#define ATH_RSSI_EP_MULTIPLIER (1<<7)
#define ATH_EP_MUL(x, mul) ((x) * (mul))
#define ATH_RSSI_IN(x) (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER))
@@ -427,7 +421,6 @@ struct ath_beacon {
void ath_beacon_tasklet(unsigned long data);
void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
-int ath_beaconq_setup(struct ath_hw *ah);
int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif);
void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
@@ -451,6 +444,26 @@ struct ath_ani {
struct timer_list timer;
};
+/* 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;
+ struct timer_list period_timer; /* Timer for BT period */
+ u32 bt_priority_cnt;
+ unsigned long bt_priority_time;
+ int bt_stomp_type; /* Types of BT stomping */
+ u32 btcoex_no_stomp; /* in usec */
+ u32 btcoex_period; /* in usec */
+ struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
+};
+
/********************/
/* LED Control */
/********************/
@@ -484,7 +497,6 @@ struct ath_led {
* Used when PCI device not fully initialized by bootrom/BIOS
*/
#define DEFAULT_CACHELINE 32
-#define ATH_DEFAULT_NOISE_FLOOR -95
#define ATH_REGCLASSIDS_MAX 10
#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */
#define ATH_MAX_SW_RETRIES 10
@@ -522,23 +534,14 @@ struct ath_led {
#define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17)
#define SC_OP_WAIT_FOR_TX_ACK BIT(18)
#define SC_OP_BEACON_SYNC BIT(19)
-#define SC_OP_BTCOEX_ENABLED BIT(20)
#define SC_OP_BT_PRIORITY_DETECTED BIT(21)
-struct ath_bus_ops {
- void (*read_cachesize)(struct ath_softc *sc, int *csz);
- void (*cleanup)(struct ath_softc *sc);
- bool (*eeprom_read)(struct ath_hw *ah, u32 off, u16 *data);
-};
-
struct ath_wiphy;
struct ath_softc {
struct ieee80211_hw *hw;
struct device *dev;
- struct ath_common common;
-
spinlock_t wiphy_lock; /* spinlock to protect ath_wiphy data */
struct ath_wiphy *pri_wiphy;
struct ath_wiphy **sec_wiphy; /* secondary wiphys (virtual radios); may
@@ -565,24 +568,17 @@ struct ath_softc {
spinlock_t sc_pm_lock;
struct mutex mutex;
- u8 curbssid[ETH_ALEN];
- u8 bssidmask[ETH_ALEN];
u32 intrstatus;
u32 sc_flags; /* SC_OP_* */
u16 curtxpow;
- u16 curaid;
u8 nbcnvifs;
u16 nvifs;
- u8 tx_chainmask;
- u8 rx_chainmask;
u32 keymax;
DECLARE_BITMAP(keymap, ATH_KEYMAX);
u8 splitmic;
bool ps_enabled;
unsigned long ps_usecount;
enum ath9k_int imask;
- enum ath9k_ht_extprotspacing ht_extprotspacing;
- enum ath9k_ht_macmode tx_chan_width;
struct ath_config config;
struct ath_rx rx;
@@ -609,10 +605,9 @@ struct ath_softc {
#ifdef CONFIG_ATH9K_DEBUG
struct ath9k_debug debug;
#endif
- struct ath_bus_ops *bus_ops;
struct ath_beacon_config cur_beacon_conf;
struct delayed_work tx_complete_work;
- struct ath_btcoex_info btcoex_info;
+ struct ath_btcoex btcoex;
};
struct ath_wiphy {
@@ -634,31 +629,22 @@ int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
int ath_cabq_update(struct ath_softc *);
-static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
-{
- return &ah->ah_sc->common;
-}
-
-static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah)
+static inline void ath_read_cachesize(struct ath_common *common, int *csz)
{
- return &(ath9k_hw_common(ah)->regulatory);
+ common->bus_ops->read_cachesize(common, csz);
}
-static inline void ath_read_cachesize(struct ath_softc *sc, int *csz)
+static inline void ath_bus_cleanup(struct ath_common *common)
{
- sc->bus_ops->read_cachesize(sc, csz);
-}
-
-static inline void ath_bus_cleanup(struct ath_softc *sc)
-{
- sc->bus_ops->cleanup(sc);
+ common->bus_ops->cleanup(common);
}
extern struct ieee80211_ops ath9k_ops;
irqreturn_t ath_isr(int irq, void *dev);
void ath_cleanup(struct ath_softc *sc);
-int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid);
+int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
+ const struct ath_bus_ops *bus_ops);
void ath_detach(struct ath_softc *sc);
const char *ath_mac_bb_name(u32 mac_bb_version);
const char *ath_rf_name(u16 rf_version);
@@ -706,8 +692,5 @@ bool ath9k_wiphy_scanning(struct ath_softc *sc);
void ath9k_wiphy_work(struct work_struct *work);
bool ath9k_all_wiphys_idle(struct ath_softc *sc);
-void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val);
-unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset);
-
int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
#endif /* ATH9K_H */
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 45c4ea57616b..b10c884f2933 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -26,6 +26,7 @@
static int ath_beaconq_config(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_tx_queue_info qi;
ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi);
@@ -42,8 +43,8 @@ static int ath_beaconq_config(struct ath_softc *sc)
}
if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to update h/w beacon queue parameters\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to update h/w beacon queue parameters\n");
return 0;
} else {
ath9k_hw_resettxqueue(ah, sc->beacon.beaconq);
@@ -61,6 +62,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
{
struct sk_buff *skb = bf->bf_mpdu;
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath_desc *ds;
struct ath9k_11n_rate_series series[4];
const struct ath_rate_table *rt;
@@ -108,7 +110,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
series[0].Tries = 1;
series[0].Rate = rate;
- series[0].ChSel = sc->tx_chainmask;
+ series[0].ChSel = common->tx_chainmask;
series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0;
ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration,
series, 4, 0);
@@ -119,6 +121,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_buf *bf;
struct ath_vif *avp;
struct sk_buff *skb;
@@ -172,7 +175,8 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
- DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error on beaconing\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "dma_mapping_error on beaconing\n");
return NULL;
}
@@ -192,8 +196,8 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
if (skb && cabq_depth) {
if (sc->nvifs > 1) {
- DPRINTF(sc, ATH_DBG_BEACON,
- "Flushing previous cabq traffic\n");
+ ath_print(common, ATH_DBG_BEACON,
+ "Flushing previous cabq traffic\n");
ath_draintxq(sc, cabq, false);
}
}
@@ -216,6 +220,7 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc,
struct ieee80211_vif *vif)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath_buf *bf;
struct ath_vif *avp;
struct sk_buff *skb;
@@ -233,25 +238,14 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc,
/* NB: caller is known to have already stopped tx dma */
ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr);
ath9k_hw_txstart(ah, sc->beacon.beaconq);
- DPRINTF(sc, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n",
- sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc);
-}
-
-int ath_beaconq_setup(struct ath_hw *ah)
-{
- struct ath9k_tx_queue_info qi;
-
- memset(&qi, 0, sizeof(qi));
- qi.tqi_aifs = 1;
- qi.tqi_cwmin = 0;
- qi.tqi_cwmax = 0;
- /* NB: don't enable any interrupts */
- return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
+ ath_print(common, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n",
+ sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc);
}
int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
{
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp;
struct ath_buf *bf;
struct sk_buff *skb;
@@ -309,7 +303,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
/* NB: the beacon data buffer must be 32-bit aligned. */
skb = ieee80211_beacon_get(sc->hw, vif);
if (skb == NULL) {
- DPRINTF(sc, ATH_DBG_BEACON, "cannot get skb\n");
+ ath_print(common, ATH_DBG_BEACON, "cannot get skb\n");
return -ENOMEM;
}
@@ -333,9 +327,10 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
tsfadjust = intval * avp->av_bslot / ATH_BCBUF;
avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust));
- DPRINTF(sc, ATH_DBG_BEACON,
- "stagger beacons, bslot %d intval %u tsfadjust %llu\n",
- avp->av_bslot, intval, (unsigned long long)tsfadjust);
+ ath_print(common, ATH_DBG_BEACON,
+ "stagger beacons, bslot %d intval "
+ "%u tsfadjust %llu\n",
+ avp->av_bslot, intval, (unsigned long long)tsfadjust);
((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp =
avp->tsf_adjust;
@@ -349,8 +344,8 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
- DPRINTF(sc, ATH_DBG_FATAL,
- "dma_mapping_error on beacon alloc\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "dma_mapping_error on beacon alloc\n");
return -ENOMEM;
}
@@ -386,6 +381,7 @@ void ath_beacon_tasklet(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath_buf *bf = NULL;
struct ieee80211_vif *vif;
struct ath_wiphy *aphy;
@@ -405,12 +401,12 @@ void ath_beacon_tasklet(unsigned long data)
sc->beacon.bmisscnt++;
if (sc->beacon.bmisscnt < BSTUCK_THRESH) {
- DPRINTF(sc, ATH_DBG_BEACON,
- "missed %u consecutive beacons\n",
- sc->beacon.bmisscnt);
+ ath_print(common, ATH_DBG_BEACON,
+ "missed %u consecutive beacons\n",
+ sc->beacon.bmisscnt);
} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
- DPRINTF(sc, ATH_DBG_BEACON,
- "beacon is officially stuck\n");
+ ath_print(common, ATH_DBG_BEACON,
+ "beacon is officially stuck\n");
sc->sc_flags |= SC_OP_TSF_RESET;
ath_reset(sc, false);
}
@@ -419,9 +415,9 @@ void ath_beacon_tasklet(unsigned long data)
}
if (sc->beacon.bmisscnt != 0) {
- DPRINTF(sc, ATH_DBG_BEACON,
- "resume beacon xmit after %u misses\n",
- sc->beacon.bmisscnt);
+ ath_print(common, ATH_DBG_BEACON,
+ "resume beacon xmit after %u misses\n",
+ sc->beacon.bmisscnt);
sc->beacon.bmisscnt = 0;
}
@@ -447,9 +443,9 @@ void ath_beacon_tasklet(unsigned long data)
vif = sc->beacon.bslot[slot];
aphy = sc->beacon.bslot_aphy[slot];
- DPRINTF(sc, ATH_DBG_BEACON,
- "slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
- slot, tsf, tsftu, intval, vif);
+ ath_print(common, ATH_DBG_BEACON,
+ "slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
+ slot, tsf, tsftu, intval, vif);
bfaddr = 0;
if (vif) {
@@ -490,7 +486,7 @@ void ath_beacon_tasklet(unsigned long data)
* are still pending on the queue.
*/
if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) {
- DPRINTF(sc, ATH_DBG_FATAL,
+ ath_print(common, ATH_DBG_FATAL,
"beacon queue %u did not stop?\n", sc->beacon.beaconq);
}
@@ -502,6 +498,19 @@ void ath_beacon_tasklet(unsigned long data)
}
}
+static void ath9k_beacon_init(struct ath_softc *sc,
+ u32 next_beacon,
+ u32 beacon_period)
+{
+ if (beacon_period & ATH9K_BEACON_RESET_TSF)
+ ath9k_ps_wakeup(sc);
+
+ ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period);
+
+ if (beacon_period & ATH9K_BEACON_RESET_TSF)
+ ath9k_ps_restore(sc);
+}
+
/*
* For multi-bss ap support beacons are either staggered evenly over N slots or
* burst together. For the former arrange for the SWBA to be delivered for each
@@ -534,7 +543,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
/* Set the computed AP beacon timers */
ath9k_hw_set_interrupts(sc->sc_ah, 0);
- ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval);
+ ath9k_beacon_init(sc, nexttbtt, intval);
sc->beacon.bmisscnt = 0;
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
@@ -555,6 +564,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
static void ath_beacon_config_sta(struct ath_softc *sc,
struct ath_beacon_config *conf)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath9k_beacon_state bs;
int dtimperiod, dtimcount, sleepduration;
int cfpperiod, cfpcount;
@@ -651,11 +661,11 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
/* TSF out of range threshold fixed at 1 second */
bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
- DPRINTF(sc, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
- DPRINTF(sc, ATH_DBG_BEACON,
- "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
- bs.bs_bmissthreshold, bs.bs_sleepduration,
- bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
+ ath_print(common, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
+ ath_print(common, ATH_DBG_BEACON,
+ "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
+ bs.bs_bmissthreshold, bs.bs_sleepduration,
+ bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
/* Set the computed STA beacon timers */
@@ -669,6 +679,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
struct ath_beacon_config *conf,
struct ieee80211_vif *vif)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
u64 tsf;
u32 tsftu, intval, nexttbtt;
@@ -689,9 +700,9 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
nexttbtt += intval;
} while (nexttbtt < tsftu);
- DPRINTF(sc, ATH_DBG_BEACON,
- "IBSS nexttbtt %u intval %u (%u)\n",
- nexttbtt, intval, conf->beacon_interval);
+ ath_print(common, ATH_DBG_BEACON,
+ "IBSS nexttbtt %u intval %u (%u)\n",
+ nexttbtt, intval, conf->beacon_interval);
/*
* In IBSS mode enable the beacon timers but only enable SWBA interrupts
@@ -707,7 +718,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
/* Set the computed ADHOC beacon timers */
ath9k_hw_set_interrupts(sc->sc_ah, 0);
- ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval);
+ ath9k_beacon_init(sc, nexttbtt, intval);
sc->beacon.bmisscnt = 0;
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
@@ -719,6 +730,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
{
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
enum nl80211_iftype iftype;
/* Setup the beacon configuration parameters */
@@ -759,8 +771,8 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
ath_beacon_config_sta(sc, cur_conf);
break;
default:
- DPRINTF(sc, ATH_DBG_CONFIG,
- "Unsupported beaconing mode\n");
+ ath_print(common, ATH_DBG_CONFIG,
+ "Unsupported beaconing mode\n");
return;
}
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c
index 55f607b7699e..fb4ac15f3b93 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.c
+++ b/drivers/net/wireless/ath/ath9k/btcoex.c
@@ -14,10 +14,26 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "ath9k.h"
+#include "hw.h"
-static const struct ath_btcoex_config ath_bt_config = { 0, true, true,
- ATH_BT_COEX_MODE_SLOTTED, true, true, 2, 5, true };
+enum ath_bt_mode {
+ ATH_BT_COEX_MODE_LEGACY, /* legacy rx_clear mode */
+ ATH_BT_COEX_MODE_UNSLOTTED, /* untimed/unslotted mode */
+ ATH_BT_COEX_MODE_SLOTTED, /* slotted mode */
+ ATH_BT_COEX_MODE_DISALBED, /* coexistence disabled */
+};
+
+struct ath_btcoex_config {
+ u8 bt_time_extend;
+ bool bt_txstate_extend;
+ bool bt_txframe_extend;
+ enum ath_bt_mode bt_mode; /* coexistence mode */
+ bool bt_quiet_collision;
+ bool bt_rxclear_polarity; /* invert rx_clear as WLAN_ACTIVE*/
+ u8 bt_priority_time;
+ u8 bt_first_slot_time;
+ bool bt_hold_rx_clear;
+};
static const u16 ath_subsysid_tbl[] = {
AR9280_COEX2WIRE_SUBSYSID,
@@ -29,141 +45,38 @@ static const u16 ath_subsysid_tbl[] = {
* Checks the subsystem id of the device to see if it
* supports btcoex
*/
-bool ath_btcoex_supported(u16 subsysid)
+bool ath9k_hw_btcoex_supported(struct ath_hw *ah)
{
int i;
- if (!subsysid)
+ if (!ah->hw_version.subsysid)
return false;
for (i = 0; i < ARRAY_SIZE(ath_subsysid_tbl); i++)
- if (subsysid == ath_subsysid_tbl[i])
+ if (ah->hw_version.subsysid == ath_subsysid_tbl[i])
return true;
return false;
}
-/*
- * Detects if there is any priority bt traffic
- */
-static void ath_detect_bt_priority(struct ath_softc *sc)
-{
- struct ath_btcoex_info *btinfo = &sc->btcoex_info;
-
- if (ath9k_hw_gpio_get(sc->sc_ah, btinfo->btpriority_gpio))
- btinfo->bt_priority_cnt++;
-
- if (time_after(jiffies, btinfo->bt_priority_time +
- msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
- if (btinfo->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
- DPRINTF(sc, ATH_DBG_BTCOEX,
- "BT priority traffic detected");
- sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
- } else {
- sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
- }
-
- btinfo->bt_priority_cnt = 0;
- btinfo->bt_priority_time = jiffies;
- }
-}
-
-/*
- * Configures appropriate weight based on stomp type.
- */
-static void ath_btcoex_bt_stomp(struct ath_softc *sc,
- struct ath_btcoex_info *btinfo,
- int stomp_type)
-{
-
- switch (stomp_type) {
- case ATH_BTCOEX_STOMP_ALL:
- ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT,
- AR_STOMP_ALL_WLAN_WGHT);
- break;
- case ATH_BTCOEX_STOMP_LOW:
- ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT,
- AR_STOMP_LOW_WLAN_WGHT);
- break;
- case ATH_BTCOEX_STOMP_NONE:
- ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT,
- AR_STOMP_NONE_WLAN_WGHT);
- break;
- default:
- DPRINTF(sc, ATH_DBG_BTCOEX, "Invalid Stomptype\n");
- break;
- }
-
- ath9k_hw_btcoex_enable(sc->sc_ah);
-}
-
-/*
- * This is the master bt coex timer 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_timer(unsigned long data)
-{
- struct ath_softc *sc = (struct ath_softc *) data;
- struct ath_btcoex_info *btinfo = &sc->btcoex_info;
-
- ath_detect_bt_priority(sc);
-
- spin_lock_bh(&btinfo->btcoex_lock);
-
- ath_btcoex_bt_stomp(sc, btinfo, btinfo->bt_stomp_type);
-
- spin_unlock_bh(&btinfo->btcoex_lock);
-
- if (btinfo->btcoex_period != btinfo->btcoex_no_stomp) {
- if (btinfo->hw_timer_enabled)
- ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer);
-
- ath_gen_timer_start(sc->sc_ah,
- btinfo->no_stomp_timer,
- (ath9k_hw_gettsf32(sc->sc_ah) +
- btinfo->btcoex_no_stomp),
- btinfo->btcoex_no_stomp * 10);
- btinfo->hw_timer_enabled = true;
- }
-
- mod_timer(&btinfo->period_timer, jiffies +
- msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
-}
-
-/*
- * Generic tsf based hw timer which configures weight
- * registers to time slice between wlan and bt traffic
- */
-
-static void ath_btcoex_no_stomp_timer(void *arg)
-{
- struct ath_softc *sc = (struct ath_softc *)arg;
- struct ath_btcoex_info *btinfo = &sc->btcoex_info;
-
- DPRINTF(sc, ATH_DBG_BTCOEX, "no stomp timer running \n");
-
- spin_lock_bh(&btinfo->btcoex_lock);
-
- if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_LOW)
- ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_NONE);
- else if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
- ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_LOW);
-
- spin_unlock_bh(&btinfo->btcoex_lock);
-}
-
-static int ath_init_btcoex_info(struct ath_hw *hw,
- struct ath_btcoex_info *btcoex_info)
+void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
{
+ struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
+ const struct ath_btcoex_config ath_bt_config = {
+ .bt_time_extend = 0,
+ .bt_txstate_extend = true,
+ .bt_txframe_extend = true,
+ .bt_mode = ATH_BT_COEX_MODE_SLOTTED,
+ .bt_quiet_collision = true,
+ .bt_rxclear_polarity = true,
+ .bt_priority_time = 2,
+ .bt_first_slot_time = 5,
+ .bt_hold_rx_clear = true,
+ };
u32 i;
- int qnum;
- qnum = ath_tx_get_qnum(hw->ah_sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
-
- btcoex_info->bt_coex_mode =
- (btcoex_info->bt_coex_mode & AR_BT_QCU_THRESH) |
+ btcoex_hw->bt_coex_mode =
+ (btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) |
SM(ath_bt_config.bt_time_extend, AR_BT_TIME_EXTEND) |
SM(ath_bt_config.bt_txstate_extend, AR_BT_TXSTATE_EXTEND) |
SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) |
@@ -174,167 +87,141 @@ static int ath_init_btcoex_info(struct ath_hw *hw,
SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) |
SM(qnum, AR_BT_QCU_THRESH);
- btcoex_info->bt_coex_mode2 =
+ btcoex_hw->bt_coex_mode2 =
SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) |
SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) |
AR_BT_DISABLE_BT_ANT;
- btcoex_info->bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+ for (i = 0; i < 32; i++)
+ ah->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i;
+}
+EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw);
- btcoex_info->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
+void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah)
+{
+ struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
- btcoex_info->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
- btcoex_info->btcoex_period / 100;
+ /* connect bt_active to baseband */
+ REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+ (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
+ AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
- for (i = 0; i < 32; i++)
- hw->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i;
+ REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+ AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
- setup_timer(&btcoex_info->period_timer, ath_btcoex_period_timer,
- (unsigned long) hw->ah_sc);
+ /* Set input mux for bt_active to gpio pin */
+ REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
+ AR_GPIO_INPUT_MUX1_BT_ACTIVE,
+ btcoex_hw->btactive_gpio);
- btcoex_info->no_stomp_timer = ath_gen_timer_alloc(hw,
- ath_btcoex_no_stomp_timer,
- ath_btcoex_no_stomp_timer,
- (void *)hw->ah_sc, AR_FIRST_NDP_TIMER);
+ /* Configure the desired gpio port for input */
+ ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio);
+}
+EXPORT_SYMBOL(ath9k_hw_btcoex_init_2wire);
+
+void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah)
+{
+ struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
- if (btcoex_info->no_stomp_timer == NULL)
- return -ENOMEM;
+ /* btcoex 3-wire */
+ REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+ (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB |
+ AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB));
- spin_lock_init(&btcoex_info->btcoex_lock);
+ /* Set input mux for bt_prority_async and
+ * bt_active_async to GPIO pins */
+ REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
+ AR_GPIO_INPUT_MUX1_BT_ACTIVE,
+ btcoex_hw->btactive_gpio);
- return 0;
+ REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
+ AR_GPIO_INPUT_MUX1_BT_PRIORITY,
+ btcoex_hw->btpriority_gpio);
+
+ /* Configure the desired GPIO ports for input */
+
+ ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio);
+ ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btpriority_gpio);
}
+EXPORT_SYMBOL(ath9k_hw_btcoex_init_3wire);
-int ath9k_hw_btcoex_init(struct ath_hw *ah)
+static void ath9k_hw_btcoex_enable_2wire(struct ath_hw *ah)
{
- struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
- int ret = 0;
-
- if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) {
- /* connect bt_active to baseband */
- REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
- (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
- AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
-
- REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
- AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
-
- /* Set input mux for bt_active to gpio pin */
- REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
- AR_GPIO_INPUT_MUX1_BT_ACTIVE,
- btcoex_info->btactive_gpio);
-
- /* Configure the desired gpio port for input */
- ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio);
- } else {
- /* btcoex 3-wire */
- REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
- (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB |
- AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB));
-
- /* Set input mux for bt_prority_async and
- * bt_active_async to GPIO pins */
- REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
- AR_GPIO_INPUT_MUX1_BT_ACTIVE,
- btcoex_info->btactive_gpio);
-
- REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
- AR_GPIO_INPUT_MUX1_BT_PRIORITY,
- btcoex_info->btpriority_gpio);
-
- /* Configure the desired GPIO ports for input */
-
- ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio);
- ath9k_hw_cfg_gpio_input(ah, btcoex_info->btpriority_gpio);
-
- ret = ath_init_btcoex_info(ah, btcoex_info);
- }
+ struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
- return ret;
+ /* Configure the desired GPIO port for TX_FRAME output */
+ ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio,
+ AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
}
-void ath9k_hw_btcoex_enable(struct ath_hw *ah)
+void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
+ u32 bt_weight,
+ u32 wlan_weight)
{
- struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
-
- if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) {
- /* Configure the desired GPIO port for TX_FRAME output */
- ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio,
- AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
- } else {
- /*
- * Program coex mode and weight registers to
- * enable coex 3-wire
- */
- REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_info->bt_coex_mode);
- REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_info->bt_coex_weights);
- REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_info->bt_coex_mode2);
-
- 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);
-
- ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio,
- AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL);
- }
+ struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
- REG_RMW(ah, AR_GPIO_PDPU,
- (0x2 << (btcoex_info->btactive_gpio * 2)),
- (0x3 << (btcoex_info->btactive_gpio * 2)));
-
- ah->ah_sc->sc_flags |= SC_OP_BTCOEX_ENABLED;
+ btcoex_hw->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) |
+ SM(wlan_weight, AR_BTCOEX_WL_WGHT);
}
+EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight);
-void ath9k_hw_btcoex_disable(struct ath_hw *ah)
+static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
{
- struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
+ struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
- ath9k_hw_set_gpio(ah, btcoex_info->wlanactive_gpio, 0);
+ /*
+ * Program coex mode and weight registers to
+ * enable coex 3-wire
+ */
+ REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_hw->bt_coex_mode);
+ REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights);
+ REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_hw->bt_coex_mode2);
- ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio,
- AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+ 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);
- if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) {
- REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE);
- REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0);
- REG_WRITE(ah, AR_BT_COEX_MODE2, 0);
- }
-
- ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED;
+ ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio,
+ AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL);
}
-/*
- * Pause btcoex timer and bt duty cycle timer
- */
-void ath_btcoex_timer_pause(struct ath_softc *sc,
- struct ath_btcoex_info *btinfo)
+void ath9k_hw_btcoex_enable(struct ath_hw *ah)
{
+ struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
- del_timer_sync(&btinfo->period_timer);
+ switch (btcoex_hw->scheme) {
+ case ATH_BTCOEX_CFG_NONE:
+ break;
+ case ATH_BTCOEX_CFG_2WIRE:
+ ath9k_hw_btcoex_enable_2wire(ah);
+ break;
+ case ATH_BTCOEX_CFG_3WIRE:
+ ath9k_hw_btcoex_enable_3wire(ah);
+ break;
+ }
- if (btinfo->hw_timer_enabled)
- ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer);
+ REG_RMW(ah, AR_GPIO_PDPU,
+ (0x2 << (btcoex_hw->btactive_gpio * 2)),
+ (0x3 << (btcoex_hw->btactive_gpio * 2)));
- btinfo->hw_timer_enabled = false;
+ ah->btcoex_hw.enabled = true;
}
+EXPORT_SYMBOL(ath9k_hw_btcoex_enable);
-/*
- * (Re)start btcoex timers
- */
-void ath_btcoex_timer_resume(struct ath_softc *sc,
- struct ath_btcoex_info *btinfo)
+void ath9k_hw_btcoex_disable(struct ath_hw *ah)
{
+ struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
- DPRINTF(sc, ATH_DBG_BTCOEX, "Starting btcoex timers");
+ ath9k_hw_set_gpio(ah, btcoex_hw->wlanactive_gpio, 0);
- /* make sure duty cycle timer is also stopped when resuming */
- if (btinfo->hw_timer_enabled)
- ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer);
+ ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio,
+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
- btinfo->bt_priority_cnt = 0;
- btinfo->bt_priority_time = jiffies;
- sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
+ if (btcoex_hw->scheme == ATH_BTCOEX_CFG_3WIRE) {
+ REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE);
+ REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0);
+ REG_WRITE(ah, AR_BT_COEX_MODE2, 0);
+ }
- mod_timer(&btinfo->period_timer, jiffies);
+ ah->btcoex_hw.enabled = false;
}
+EXPORT_SYMBOL(ath9k_hw_btcoex_disable);
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h
index 297b027fd3c3..1ba31a73317c 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.h
+++ b/drivers/net/wireless/ath/ath9k/btcoex.h
@@ -17,6 +17,8 @@
#ifndef BTCOEX_H
#define BTCOEX_H
+#include "hw.h"
+
#define ATH_WLANACTIVE_GPIO 5
#define ATH_BTACTIVE_GPIO 6
#define ATH_BTPRIORITY_GPIO 7
@@ -34,67 +36,25 @@ enum ath_btcoex_scheme {
ATH_BTCOEX_CFG_3WIRE,
};
-enum ath_stomp_type {
- ATH_BTCOEX_NO_STOMP,
- ATH_BTCOEX_STOMP_ALL,
- ATH_BTCOEX_STOMP_LOW,
- ATH_BTCOEX_STOMP_NONE
-};
-
-enum ath_bt_mode {
- ATH_BT_COEX_MODE_LEGACY, /* legacy rx_clear mode */
- ATH_BT_COEX_MODE_UNSLOTTED, /* untimed/unslotted mode */
- ATH_BT_COEX_MODE_SLOTTED, /* slotted mode */
- ATH_BT_COEX_MODE_DISALBED, /* coexistence disabled */
-};
-
-struct ath_btcoex_config {
- u8 bt_time_extend;
- bool bt_txstate_extend;
- bool bt_txframe_extend;
- enum ath_bt_mode bt_mode; /* coexistence mode */
- bool bt_quiet_collision;
- bool bt_rxclear_polarity; /* invert rx_clear as WLAN_ACTIVE*/
- u8 bt_priority_time;
- u8 bt_first_slot_time;
- bool bt_hold_rx_clear;
-};
-
-struct ath_btcoex_info {
- enum ath_btcoex_scheme btcoex_scheme;
+struct ath_btcoex_hw {
+ enum ath_btcoex_scheme scheme;
+ bool enabled;
u8 wlanactive_gpio;
u8 btactive_gpio;
u8 btpriority_gpio;
- u8 bt_duty_cycle; /* BT duty cycle in percentage */
- int bt_stomp_type; /* Types of BT stomping */
u32 bt_coex_mode; /* Register setting for AR_BT_COEX_MODE */
u32 bt_coex_weights; /* Register setting for AR_BT_COEX_WEIGHT */
u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */
- u32 btcoex_no_stomp; /* in usec */
- u32 btcoex_period; /* in usec */
- u32 bt_priority_cnt;
- unsigned long bt_priority_time;
- bool hw_timer_enabled;
- spinlock_t btcoex_lock;
- struct timer_list period_timer; /* Timer for BT period */
- struct ath_gen_timer *no_stomp_timer; /*Timer for no BT stomping*/
};
-bool ath_btcoex_supported(u16 subsysid);
-int ath9k_hw_btcoex_init(struct ath_hw *ah);
+bool ath9k_hw_btcoex_supported(struct ath_hw *ah);
+void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah);
+void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah);
+void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum);
+void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
+ u32 bt_weight,
+ u32 wlan_weight);
void ath9k_hw_btcoex_enable(struct ath_hw *ah);
void ath9k_hw_btcoex_disable(struct ath_hw *ah);
-void ath_btcoex_timer_resume(struct ath_softc *sc,
- struct ath_btcoex_info *btinfo);
-void ath_btcoex_timer_pause(struct ath_softc *sc,
- struct ath_btcoex_info *btinfo);
-
-static inline void ath_btcoex_set_weight(struct ath_btcoex_info *btcoex_info,
- u32 bt_weight,
- u32 wlan_weight)
-{
- btcoex_info->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) |
- SM(wlan_weight, AR_BTCOEX_WL_WGHT);
-}
#endif
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index 0ad6d0b76e9e..551f8801459f 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "ath9k.h"
+#include "hw.h"
/* We can tune this as we go by monitoring really low values */
#define ATH9K_NF_TOO_LOW -60
@@ -26,11 +26,11 @@
static bool ath9k_hw_nf_in_range(struct ath_hw *ah, s16 nf)
{
if (nf > ATH9K_NF_TOO_LOW) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "noise floor value detected (%d) is "
- "lower than what we think is a "
- "reasonable value (%d)\n",
- nf, ATH9K_NF_TOO_LOW);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+ "noise floor value detected (%d) is "
+ "lower than what we think is a "
+ "reasonable value (%d)\n",
+ nf, ATH9K_NF_TOO_LOW);
return false;
}
return true;
@@ -89,6 +89,7 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
static void ath9k_hw_do_getnf(struct ath_hw *ah,
int16_t nfarray[NUM_NF_READINGS])
{
+ struct ath_common *common = ath9k_hw_common(ah);
int16_t nf;
if (AR_SREV_9280_10_OR_LATER(ah))
@@ -98,8 +99,8 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah,
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "NF calibrated [ctl] [chain 0] is %d\n", nf);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "NF calibrated [ctl] [chain 0] is %d\n", nf);
nfarray[0] = nf;
if (!AR_SREV_9285(ah)) {
@@ -112,8 +113,8 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah,
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "NF calibrated [ctl] [chain 1] is %d\n", nf);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "NF calibrated [ctl] [chain 1] is %d\n", nf);
nfarray[1] = nf;
if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) {
@@ -121,8 +122,8 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah,
AR_PHY_CH2_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "NF calibrated [ctl] [chain 2] is %d\n", nf);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "NF calibrated [ctl] [chain 2] is %d\n", nf);
nfarray[2] = nf;
}
}
@@ -136,8 +137,8 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah,
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "NF calibrated [ext] [chain 0] is %d\n", nf);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "NF calibrated [ext] [chain 0] is %d\n", nf);
nfarray[3] = nf;
if (!AR_SREV_9285(ah)) {
@@ -150,8 +151,8 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah,
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "NF calibrated [ext] [chain 1] is %d\n", nf);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "NF calibrated [ext] [chain 1] is %d\n", nf);
nfarray[4] = nf;
if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) {
@@ -159,8 +160,8 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah,
AR_PHY_CH2_EXT_MINCCA_PWR);
if (nf & 0x100)
nf = 0 - ((nf ^ 0x1ff) + 1);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "NF calibrated [ext] [chain 2] is %d\n", nf);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "NF calibrated [ext] [chain 2] is %d\n", nf);
nfarray[5] = nf;
}
}
@@ -188,6 +189,8 @@ static bool getNoiseFloorThresh(struct ath_hw *ah,
static void ath9k_hw_setup_calibration(struct ath_hw *ah,
struct ath9k_cal_list *currCal)
{
+ struct ath_common *common = ath9k_hw_common(ah);
+
REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
currCal->calData->calCountMax);
@@ -195,23 +198,23 @@ static void ath9k_hw_setup_calibration(struct ath_hw *ah,
switch (currCal->calData->calType) {
case IQ_MISMATCH_CAL:
REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "starting IQ Mismatch Calibration\n");
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "starting IQ Mismatch Calibration\n");
break;
case ADC_GAIN_CAL:
REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "starting ADC Gain Calibration\n");
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "starting ADC Gain Calibration\n");
break;
case ADC_DC_CAL:
REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "starting ADC DC Calibration\n");
+ 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);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "starting Init ADC DC Calibration\n");
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "starting Init ADC DC Calibration\n");
break;
}
@@ -278,7 +281,7 @@ static bool ath9k_hw_per_calibration(struct ath_hw *ah,
static bool ath9k_hw_iscal_supported(struct ath_hw *ah,
enum ath9k_cal_types calType)
{
- struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+ 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 */
@@ -304,11 +307,11 @@ static void ath9k_hw_iqcal_collect(struct ath_hw *ah)
REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
ah->totalIqCorrMeas[i] +=
(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
- ah->cal_samples, i, ah->totalPowerMeasI[i],
- ah->totalPowerMeasQ[i],
- ah->totalIqCorrMeas[i]);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+ "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
+ ah->cal_samples, i, ah->totalPowerMeasI[i],
+ ah->totalPowerMeasQ[i],
+ ah->totalIqCorrMeas[i]);
}
}
@@ -326,14 +329,14 @@ static void ath9k_hw_adc_gaincal_collect(struct ath_hw *ah)
ah->totalAdcQEvenPhase[i] +=
REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
- "oddq=0x%08x; evenq=0x%08x;\n",
- ah->cal_samples, i,
- ah->totalAdcIOddPhase[i],
- ah->totalAdcIEvenPhase[i],
- ah->totalAdcQOddPhase[i],
- ah->totalAdcQEvenPhase[i]);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+ "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
+ "oddq=0x%08x; evenq=0x%08x;\n",
+ ah->cal_samples, i,
+ ah->totalAdcIOddPhase[i],
+ ah->totalAdcIEvenPhase[i],
+ ah->totalAdcQOddPhase[i],
+ ah->totalAdcQEvenPhase[i]);
}
}
@@ -351,19 +354,20 @@ static void ath9k_hw_adc_dccal_collect(struct ath_hw *ah)
ah->totalAdcDcOffsetQEvenPhase[i] +=
(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
- "oddq=0x%08x; evenq=0x%08x;\n",
- ah->cal_samples, i,
- ah->totalAdcDcOffsetIOddPhase[i],
- ah->totalAdcDcOffsetIEvenPhase[i],
- ah->totalAdcDcOffsetQOddPhase[i],
- ah->totalAdcDcOffsetQEvenPhase[i]);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+ "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
+ "oddq=0x%08x; evenq=0x%08x;\n",
+ ah->cal_samples, i,
+ ah->totalAdcDcOffsetIOddPhase[i],
+ ah->totalAdcDcOffsetIEvenPhase[i],
+ ah->totalAdcDcOffsetQOddPhase[i],
+ ah->totalAdcDcOffsetQEvenPhase[i]);
}
}
static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
{
+ struct ath_common *common = ath9k_hw_common(ah);
u32 powerMeasQ, powerMeasI, iqCorrMeas;
u32 qCoffDenom, iCoffDenom;
int32_t qCoff, iCoff;
@@ -374,13 +378,13 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
powerMeasQ = ah->totalPowerMeasQ[i];
iqCorrMeas = ah->totalIqCorrMeas[i];
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Starting IQ Cal and Correction for Chain %d\n",
- i);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Starting IQ Cal and Correction for Chain %d\n",
+ i);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Orignal: Chn %diq_corr_meas = 0x%08x\n",
- i, ah->totalIqCorrMeas[i]);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Orignal: Chn %diq_corr_meas = 0x%08x\n",
+ i, ah->totalIqCorrMeas[i]);
iqCorrNeg = 0;
@@ -389,27 +393,28 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
iqCorrNeg = 1;
}
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
- iqCorrNeg);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
+ ath_print(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
+ iqCorrNeg);
iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
qCoffDenom = powerMeasQ / 64;
- if (powerMeasQ != 0) {
+ if ((powerMeasQ != 0) && (iCoffDenom != 0) &&
+ (qCoffDenom != 0)) {
iCoff = iqCorrMeas / iCoffDenom;
qCoff = powerMeasI / qCoffDenom - 64;
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d iCoff = 0x%08x\n", i, iCoff);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d qCoff = 0x%08x\n", i, qCoff);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d iCoff = 0x%08x\n", i, iCoff);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d qCoff = 0x%08x\n", i, qCoff);
iCoff = iCoff & 0x3f;
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
if (iqCorrNeg == 0x0)
iCoff = 0x40 - iCoff;
@@ -418,9 +423,9 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
else if (qCoff <= -16)
qCoff = 16;
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
- i, iCoff, qCoff);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
+ i, iCoff, qCoff);
REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
@@ -428,9 +433,9 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
qCoff);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "IQ Cal and Correction done for Chain %d\n",
- i);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "IQ Cal and Correction done for Chain %d\n",
+ i);
}
}
@@ -440,6 +445,7 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
{
+ struct ath_common *common = ath9k_hw_common(ah);
u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
u32 qGainMismatch, iGainMismatch, val, i;
@@ -449,21 +455,21 @@ static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
qOddMeasOffset = ah->totalAdcQOddPhase[i];
qEvenMeasOffset = ah->totalAdcQEvenPhase[i];
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Starting ADC Gain Cal for Chain %d\n", i);
-
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
- iOddMeasOffset);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_even_i = 0x%08x\n", i,
- iEvenMeasOffset);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
- qOddMeasOffset);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_even_q = 0x%08x\n", i,
- qEvenMeasOffset);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Starting ADC Gain Cal for Chain %d\n", i);
+
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
+ iOddMeasOffset);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_i = 0x%08x\n", i,
+ iEvenMeasOffset);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
+ qOddMeasOffset);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_q = 0x%08x\n", i,
+ qEvenMeasOffset);
if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
iGainMismatch =
@@ -473,20 +479,20 @@ static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
((qOddMeasOffset * 32) /
qEvenMeasOffset) & 0x3f;
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d gain_mismatch_i = 0x%08x\n", i,
- iGainMismatch);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d gain_mismatch_q = 0x%08x\n", i,
- qGainMismatch);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d gain_mismatch_i = 0x%08x\n", i,
+ iGainMismatch);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d gain_mismatch_q = 0x%08x\n", i,
+ qGainMismatch);
val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
val &= 0xfffff000;
val |= (qGainMismatch) | (iGainMismatch << 6);
REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "ADC Gain Cal done for Chain %d\n", i);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "ADC Gain Cal done for Chain %d\n", i);
}
}
@@ -497,6 +503,7 @@ static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
{
+ struct ath_common *common = ath9k_hw_common(ah);
u32 iOddMeasOffset, iEvenMeasOffset, val, i;
int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
const struct ath9k_percal_data *calData =
@@ -510,41 +517,41 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i];
qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i];
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Starting ADC DC Offset Cal for Chain %d\n", i);
-
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_odd_i = %d\n", i,
- iOddMeasOffset);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_even_i = %d\n", i,
- iEvenMeasOffset);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_odd_q = %d\n", i,
- qOddMeasOffset);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d pwr_meas_even_q = %d\n", i,
- qEvenMeasOffset);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Starting ADC DC Offset Cal for Chain %d\n", i);
+
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_i = %d\n", i,
+ iOddMeasOffset);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_i = %d\n", i,
+ iEvenMeasOffset);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_q = %d\n", i,
+ qOddMeasOffset);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_q = %d\n", i,
+ qEvenMeasOffset);
iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
numSamples) & 0x1ff;
qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
numSamples) & 0x1ff;
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
- iDcMismatch);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
- qDcMismatch);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
+ iDcMismatch);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
+ qDcMismatch);
val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
val &= 0xc0000fff;
val |= (qDcMismatch << 12) | (iDcMismatch << 21);
REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "ADC DC Offset Cal done for Chain %d\n", i);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "ADC DC Offset Cal done for Chain %d\n", i);
}
REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
@@ -555,7 +562,8 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
/* This is done for the currently configured channel */
bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
{
- struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ieee80211_conf *conf = &common->hw->conf;
struct ath9k_cal_list *currCal = ah->cal_list_curr;
if (!ah->curchan)
@@ -568,24 +576,25 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
return true;
if (currCal->calState != CAL_DONE) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Calibration state incorrect, %d\n",
- currCal->calState);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Calibration state incorrect, %d\n",
+ currCal->calState);
return true;
}
if (!ath9k_hw_iscal_supported(ah, currCal->calData->calType))
return true;
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "Resetting Cal %d state for channel %u\n",
- currCal->calData->calType, conf->channel->center_freq);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "Resetting Cal %d state for channel %u\n",
+ currCal->calData->calType, conf->channel->center_freq);
ah->curchan->CalValid &= ~currCal->calData->calType;
currCal->calState = CAL_WAITING;
return false;
}
+EXPORT_SYMBOL(ath9k_hw_reset_calvalid);
void ath9k_hw_start_nfcal(struct ath_hw *ah)
{
@@ -645,11 +654,11 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
- for (j = 0; j < 1000; j++) {
+ for (j = 0; j < 5; j++) {
if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
AR_PHY_AGC_CONTROL_NF) == 0)
break;
- udelay(10);
+ udelay(50);
}
for (i = 0; i < NUM_NF_READINGS; i++) {
@@ -665,6 +674,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
int16_t ath9k_hw_getnf(struct ath_hw *ah,
struct ath9k_channel *chan)
{
+ struct ath_common *common = ath9k_hw_common(ah);
int16_t nf, nfThresh;
int16_t nfarray[NUM_NF_READINGS] = { 0 };
struct ath9k_nfcal_hist *h;
@@ -672,8 +682,8 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
chan->channelFlags &= (~CHANNEL_CW_INT);
if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "NF did not complete in calibration window\n");
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "NF did not complete in calibration window\n");
nf = 0;
chan->rawNoiseFloor = nf;
return chan->rawNoiseFloor;
@@ -682,10 +692,10 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
nf = nfarray[0];
if (getNoiseFloorThresh(ah, c->band, &nfThresh)
&& nf > nfThresh) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "noise floor failed detected; "
- "detected %d, threshold %d\n",
- nf, nfThresh);
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "noise floor failed detected; "
+ "detected %d, threshold %d\n",
+ nf, nfThresh);
chan->channelFlags |= CHANNEL_CW_INT;
}
}
@@ -737,51 +747,73 @@ s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
return nf;
}
+EXPORT_SYMBOL(ath9k_hw_getchan_noise);
-static void ath9k_olc_temp_compensation(struct ath_hw *ah)
+static void ath9k_olc_temp_compensation_9287(struct ath_hw *ah)
{
- u32 rddata, i;
- int delta, currPDADC, regval, slope;
+ u32 rddata;
+ int32_t delta, currPDADC, slope;
rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
+ if (ah->initPDADC == 0 || currPDADC == 0) {
+ /*
+ * Zero value indicates that no frames have been transmitted yet,
+ * can't do temperature compensation until frames are transmitted.
+ */
+ return;
+ } else {
+ slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE);
+
+ if (slope == 0) { /* to avoid divide by zero case */
+ delta = 0;
+ } else {
+ delta = ((currPDADC - ah->initPDADC)*4) / slope;
+ }
+ REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11,
+ AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
+ REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11,
+ AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
+ }
+}
+
+static void ath9k_olc_temp_compensation(struct ath_hw *ah)
+{
+ u32 rddata, i;
+ int delta, currPDADC, regval;
if (OLC_FOR_AR9287_10_LATER) {
+ ath9k_olc_temp_compensation_9287(ah);
+ } else {
+ rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
+ currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
+
if (ah->initPDADC == 0 || currPDADC == 0) {
return;
} else {
- slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE);
- if (slope == 0)
- delta = 0;
+ if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))
+ delta = (currPDADC - ah->initPDADC + 4) / 8;
else
- delta = ((currPDADC - ah->initPDADC)*4) / slope;
- REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11,
- AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
- REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11,
- AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
- }
- } else {
- if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))
- delta = (currPDADC - ah->initPDADC + 4) / 8;
- else
- delta = (currPDADC - ah->initPDADC + 5) / 10;
-
- if (delta != ah->PDADCdelta) {
- ah->PDADCdelta = delta;
- for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
- regval = ah->originalGain[i] - delta;
- if (regval < 0)
- regval = 0;
-
- REG_RMW_FIELD(ah, AR_PHY_TX_GAIN_TBL1 + i * 4,
- AR_PHY_TX_GAIN, regval);
+ delta = (currPDADC - ah->initPDADC + 5) / 10;
+
+ if (delta != ah->PDADCdelta) {
+ ah->PDADCdelta = delta;
+ for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
+ regval = ah->originalGain[i] - delta;
+ if (regval < 0)
+ regval = 0;
+
+ REG_RMW_FIELD(ah,
+ AR_PHY_TX_GAIN_TBL1 + i * 4,
+ AR_PHY_TX_GAIN, regval);
+ }
}
}
}
}
-static void ath9k_hw_9271_pa_cal(struct ath_hw *ah)
+static void ath9k_hw_9271_pa_cal(struct ath_hw *ah, bool is_reset)
{
u32 regVal;
unsigned int i;
@@ -857,10 +889,19 @@ static void ath9k_hw_9271_pa_cal(struct ath_hw *ah)
REG_WRITE(ah, 0x7834, regVal);
}
- /* Empirical offset correction */
-#if 0
- REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0x20);
-#endif
+ regVal = (regVal >>20) & 0x7f;
+
+ /* Update PA cal info */
+ if ((!is_reset) && (ah->pacal_info.prev_offset == regVal)) {
+ if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
+ ah->pacal_info.max_skipcount =
+ 2 * ah->pacal_info.max_skipcount;
+ ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
+ } else {
+ ah->pacal_info.max_skipcount = 1;
+ ah->pacal_info.skipcount = 0;
+ ah->pacal_info.prev_offset = regVal;
+ }
regVal = REG_READ(ah, 0x7834);
regVal |= 0x1;
@@ -875,7 +916,7 @@ static void ath9k_hw_9271_pa_cal(struct ath_hw *ah)
static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset)
{
-
+ struct ath_common *common = ath9k_hw_common(ah);
u32 regVal;
int i, offset, offs_6_1, offs_0;
u32 ccomp_org, reg_field;
@@ -889,7 +930,7 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset)
{ 0x7838, 0 },
};
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "Running PA Calibration\n");
+ ath_print(common, ATH_DBG_CALIBRATE, "Running PA Calibration\n");
/* PA CAL is not needed for high power solution */
if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) ==
@@ -1011,7 +1052,7 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
if (longcal) {
/* Do periodic PAOffset Cal */
if (AR_SREV_9271(ah))
- ath9k_hw_9271_pa_cal(ah);
+ ath9k_hw_9271_pa_cal(ah, false);
else if (AR_SREV_9285_11_OR_LATER(ah)) {
if (!ah->pacal_info.skipcount)
ath9k_hw_9285_pa_cal(ah, false);
@@ -1036,9 +1077,13 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
return iscaldone;
}
+EXPORT_SYMBOL(ath9k_hw_calibrate);
+/* Carrier leakage Calibration fix */
static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
{
+ struct ath_common *common = ath9k_hw_common(ah);
+
REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
if (IS_CHAN_HT20(chan)) {
REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
@@ -1049,9 +1094,9 @@ static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "offset "
- "calibration failed to complete in "
- "1ms; noisy ??\n");
+ ath_print(common, ATH_DBG_CALIBRATE, "offset "
+ "calibration failed to complete in "
+ "1ms; noisy ??\n");
return false;
}
REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
@@ -1064,8 +1109,8 @@ static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT)) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "offset calibration "
- "failed to complete in 1ms; noisy ??\n");
+ ath_print(common, ATH_DBG_CALIBRATE, "offset calibration "
+ "failed to complete in 1ms; noisy ??\n");
return false;
}
@@ -1078,7 +1123,9 @@ static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
{
- if (AR_SREV_9285_12_OR_LATER(ah)) {
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ if (AR_SREV_9271(ah) || AR_SREV_9285_12_OR_LATER(ah)) {
if (!ar9285_clc(ah, chan))
return false;
} else {
@@ -1098,9 +1145,9 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
/* Poll for offset calibration complete */
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT)) {
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "offset calibration failed to complete in 1ms; "
- "noisy environment?\n");
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "offset calibration failed to "
+ "complete in 1ms; noisy environment?\n");
return false;
}
@@ -1114,7 +1161,9 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
}
/* Do PA Calibration */
- if (AR_SREV_9285_11_OR_LATER(ah))
+ if (AR_SREV_9271(ah))
+ ath9k_hw_9271_pa_cal(ah, true);
+ else if (AR_SREV_9285_11_OR_LATER(ah))
ath9k_hw_9285_pa_cal(ah, true);
/* Do NF Calibration after DC offset and other calibrations */
@@ -1128,20 +1177,20 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) {
INIT_CAL(&ah->adcgain_caldata);
INSERT_CAL(ah, &ah->adcgain_caldata);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "enabling ADC Gain Calibration.\n");
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "enabling ADC Gain Calibration.\n");
}
if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) {
INIT_CAL(&ah->adcdc_caldata);
INSERT_CAL(ah, &ah->adcdc_caldata);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "enabling ADC DC Calibration.\n");
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "enabling ADC DC Calibration.\n");
}
if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) {
INIT_CAL(&ah->iq_caldata);
INSERT_CAL(ah, &ah->iq_caldata);
- DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
- "enabling IQ Calibration.\n");
+ ath_print(common, ATH_DBG_CALIBRATE,
+ "enabling IQ Calibration.\n");
}
ah->cal_list_curr = ah->cal_list;
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index 9028ab193e42..b2c873e97485 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -17,6 +17,8 @@
#ifndef CALIB_H
#define CALIB_H
+#include "hw.h"
+
extern const struct ath9k_percal_data iq_cal_multi_sample;
extern const struct ath9k_percal_data iq_cal_single_sample;
extern const struct ath9k_percal_data adc_gain_cal_multi_sample;
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 2be4c2252047..84f44269de47 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -18,26 +18,13 @@
#include "ath9k.h"
-static unsigned int ath9k_debug = DBG_DEFAULT;
-module_param_named(debug, ath9k_debug, uint, 0);
+#define REG_WRITE_D(_ah, _reg, _val) \
+ ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg))
+#define REG_READ_D(_ah, _reg) \
+ ath9k_hw_common(_ah)->ops->read((_ah), (_reg))
static struct dentry *ath9k_debugfs_root;
-void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...)
-{
- if (!sc)
- return;
-
- if (sc->debug.debug_mask & dbg_mask) {
- va_list args;
-
- va_start(args, fmt);
- printk(KERN_DEBUG "ath9k: ");
- vprintk(fmt, args);
- va_end(args);
- }
-}
-
static int ath9k_debugfs_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
@@ -48,10 +35,11 @@ static ssize_t read_file_debug(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
char buf[32];
unsigned int len;
- len = snprintf(buf, sizeof(buf), "0x%08x\n", sc->debug.debug_mask);
+ len = snprintf(buf, sizeof(buf), "0x%08x\n", common->debug_mask);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -59,6 +47,7 @@ static ssize_t write_file_debug(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath_softc *sc = file->private_data;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
unsigned long mask;
char buf[32];
ssize_t len;
@@ -71,7 +60,7 @@ static ssize_t write_file_debug(struct file *file, const char __user *user_buf,
if (strict_strtoul(buf, 0, &mask))
return -EINVAL;
- sc->debug.debug_mask = mask;
+ common->debug_mask = mask;
return count;
}
@@ -95,7 +84,7 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
ath9k_ps_wakeup(sc);
- REG_WRITE(ah, AR_MACMISC,
+ REG_WRITE_D(ah, AR_MACMISC,
((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
(AR_MACMISC_MISC_OBS_BUS_1 <<
AR_MACMISC_MISC_OBS_BUS_MSB_S)));
@@ -107,7 +96,7 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
if (i % 4 == 0)
len += snprintf(buf + len, sizeof(buf) - len, "\n");
- val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32)));
+ val[i] = REG_READ_D(ah, AR_DMADBG_0 + (i * sizeof(u32)));
len += snprintf(buf + len, sizeof(buf) - len, "%d: %08x ",
i, val[i]);
}
@@ -157,9 +146,9 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
(val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17);
len += snprintf(buf + len, sizeof(buf) - len, "pcu observe: 0x%x \n",
- REG_READ(ah, AR_OBS_BUS_1));
+ REG_READ_D(ah, AR_OBS_BUS_1));
len += snprintf(buf + len, sizeof(buf) - len,
- "AR_CR: 0x%x \n", REG_READ(ah, AR_CR));
+ "AR_CR: 0x%x \n", REG_READ_D(ah, AR_CR));
ath9k_ps_restore(sc);
@@ -376,12 +365,12 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
aphy->chan_idx, aphy->chan_is_ht);
}
- put_unaligned_le32(REG_READ(sc->sc_ah, AR_STA_ID0), addr);
- put_unaligned_le16(REG_READ(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4);
+ put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr);
+ put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4);
len += snprintf(buf + len, sizeof(buf) - len,
"addr: %pM\n", addr);
- put_unaligned_le32(REG_READ(sc->sc_ah, AR_BSSMSKL), addr);
- put_unaligned_le16(REG_READ(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4);
+ put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_BSSMSKL), addr);
+ put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4);
len += snprintf(buf + len, sizeof(buf) - len,
"addrmask: %pM\n", addr);
@@ -568,9 +557,10 @@ static const struct file_operations fops_xmit = {
.owner = THIS_MODULE
};
-int ath9k_init_debug(struct ath_softc *sc)
+int ath9k_init_debug(struct ath_hw *ah)
{
- sc->debug.debug_mask = ath9k_debug;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
if (!ath9k_debugfs_root)
return -ENOENT;
@@ -619,12 +609,15 @@ int ath9k_init_debug(struct ath_softc *sc)
return 0;
err:
- ath9k_exit_debug(sc);
+ ath9k_exit_debug(ah);
return -ENOMEM;
}
-void ath9k_exit_debug(struct ath_softc *sc)
+void ath9k_exit_debug(struct ath_hw *ah)
{
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+
debugfs_remove(sc->debug.debugfs_xmit);
debugfs_remove(sc->debug.debugfs_wiphy);
debugfs_remove(sc->debug.debugfs_rcstat);
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 7241f4748338..749e85d57551 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -17,25 +17,7 @@
#ifndef DEBUG_H
#define DEBUG_H
-enum ATH_DEBUG {
- ATH_DBG_RESET = 0x00000001,
- ATH_DBG_QUEUE = 0x00000002,
- ATH_DBG_EEPROM = 0x00000004,
- ATH_DBG_CALIBRATE = 0x00000008,
- ATH_DBG_INTERRUPT = 0x00000010,
- ATH_DBG_REGULATORY = 0x00000020,
- ATH_DBG_ANI = 0x00000040,
- ATH_DBG_XMIT = 0x00000080,
- ATH_DBG_BEACON = 0x00000100,
- ATH_DBG_CONFIG = 0x00000200,
- ATH_DBG_FATAL = 0x00000400,
- ATH_DBG_PS = 0x00000800,
- ATH_DBG_HWTIMER = 0x00001000,
- ATH_DBG_BTCOEX = 0x00002000,
- ATH_DBG_ANY = 0xffffffff
-};
-
-#define DBG_DEFAULT (ATH_DBG_FATAL)
+#include "hw.h"
struct ath_txq;
struct ath_buf;
@@ -140,7 +122,6 @@ struct ath_stats {
};
struct ath9k_debug {
- int debug_mask;
struct dentry *debugfs_phy;
struct dentry *debugfs_debug;
struct dentry *debugfs_dma;
@@ -151,9 +132,9 @@ struct ath9k_debug {
struct ath_stats stats;
};
-void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...);
-int ath9k_init_debug(struct ath_softc *sc);
-void ath9k_exit_debug(struct ath_softc *sc);
+int ath9k_init_debug(struct ath_hw *ah);
+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);
@@ -165,17 +146,12 @@ void ath_debug_stat_retries(struct ath_softc *sc, int rix,
#else
-static inline void DPRINTF(struct ath_softc *sc, int dbg_mask,
- const char *fmt, ...)
-{
-}
-
-static inline int ath9k_init_debug(struct ath_softc *sc)
+static inline int ath9k_init_debug(struct ath_hw *ah)
{
return 0;
}
-static inline void ath9k_exit_debug(struct ath_softc *sc)
+static inline void ath9k_exit_debug(struct ath_hw *ah)
{
}
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index b6e52d0f8c48..dacaae934148 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "ath9k.h"
+#include "hw.h"
static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz)
{
@@ -83,11 +83,9 @@ bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
return false;
}
-bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
+bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data)
{
- struct ath_softc *sc = ah->ah_sc;
-
- return sc->bus_ops->eeprom_read(ah, off, data);
+ return common->bus_ops->eeprom_read(common, off, data);
}
void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index 4fe33f7eee9d..2f2993b50e2f 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -17,6 +17,7 @@
#ifndef EEPROM_H
#define EEPROM_H
+#include "../ath.h"
#include <net/cfg80211.h>
#define AH_USE_EEPROM 0x1
@@ -133,6 +134,7 @@
#define AR5416_EEP_MINOR_VER_17 0x11
#define AR5416_EEP_MINOR_VER_19 0x13
#define AR5416_EEP_MINOR_VER_20 0x14
+#define AR5416_EEP_MINOR_VER_21 0x15
#define AR5416_EEP_MINOR_VER_22 0x16
#define AR5416_NUM_5G_CAL_PIERS 8
@@ -153,7 +155,7 @@
#define AR5416_BCHAN_UNUSED 0xFF
#define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64
#define AR5416_MAX_CHAINS 3
-#define AR5416_PWR_TABLE_OFFSET -5
+#define AR5416_PWR_TABLE_OFFSET_DB -5
/* Rx gain type values */
#define AR5416_EEP_RXGAIN_23DB_BACKOFF 0
@@ -301,7 +303,7 @@ struct base_eep_header {
u8 txGainType;
u8 rcChainMask;
u8 desiredScaleCCK;
- u8 power_table_offset;
+ u8 pwr_table_offset;
u8 frac_n_5g;
u8 futureBase_3[21];
} __packed;
@@ -638,6 +640,7 @@ struct ar9287_eeprom {
} __packed;
enum reg_ext_bitmap {
+ REG_EXT_FCC_MIDBAND = 0,
REG_EXT_JAPAN_MIDBAND = 1,
REG_EXT_FCC_DFS_HT40 = 2,
REG_EXT_JAPAN_NONDFS_HT40 = 3,
@@ -684,7 +687,7 @@ int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
int16_t targetRight);
bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
u16 *indexL, u16 *indexR);
-bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data);
+bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data);
void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
u8 *pVpdList, u16 numIntercepts,
u8 *pRetVpdList);
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index b8eca7be5f3a..58167d861dc6 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "ath9k.h"
+#include "hw.h"
static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah)
{
@@ -29,20 +29,21 @@ static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah)
static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
{
#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
+ struct ath_common *common = ath9k_hw_common(ah);
u16 *eep_data = (u16 *)&ah->eeprom.map4k;
int addr, eep_start_loc = 0;
eep_start_loc = 64;
if (!ath9k_hw_use_flash(ah)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Reading from EEPROM, not flash\n");
+ ath_print(common, ATH_DBG_EEPROM,
+ "Reading from EEPROM, not flash\n");
}
for (addr = 0; addr < SIZE_EEPROM_4K; addr++) {
- if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Unable to read eeprom region \n");
+ if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) {
+ ath_print(common, ATH_DBG_EEPROM,
+ "Unable to read eeprom region \n");
return false;
}
eep_data++;
@@ -55,6 +56,7 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
{
#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
+ struct ath_common *common = ath9k_hw_common(ah);
struct ar5416_eeprom_4k *eep =
(struct ar5416_eeprom_4k *) &ah->eeprom.map4k;
u16 *eepdata, temp, magic, magic2;
@@ -64,15 +66,15 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
if (!ath9k_hw_use_flash(ah)) {
- if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
+ if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET,
&magic)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Reading Magic # failed\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Reading Magic # failed\n");
return false;
}
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Read Magic = 0x%04X\n", magic);
+ ath_print(common, ATH_DBG_EEPROM,
+ "Read Magic = 0x%04X\n", magic);
if (magic != AR5416_EEPROM_MAGIC) {
magic2 = swab16(magic);
@@ -87,16 +89,16 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
eepdata++;
}
} else {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Invalid EEPROM Magic. "
- "endianness mismatch.\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Invalid EEPROM Magic. "
+ "endianness mismatch.\n");
return -EINVAL;
}
}
}
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
- need_swap ? "True" : "False");
+ ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n",
+ need_swap ? "True" : "False");
if (need_swap)
el = swab16(ah->eeprom.map4k.baseEepHeader.length);
@@ -117,8 +119,8 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
u32 integer;
u16 word;
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "EEPROM Endianness is not native.. Changing\n");
+ ath_print(common, ATH_DBG_EEPROM,
+ "EEPROM Endianness is not native.. Changing\n");
word = swab16(eep->baseEepHeader.length);
eep->baseEepHeader.length = word;
@@ -160,9 +162,9 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
- sum, ah->eep_ops->get_eeprom_ver(ah));
+ ath_print(common, ATH_DBG_FATAL,
+ "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+ sum, ah->eep_ops->get_eeprom_ver(ah));
return -EINVAL;
}
@@ -208,6 +210,8 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
return pBase->rxMask;
case EEP_FRAC_N_5G:
return 0;
+ case EEP_PWR_TABLE_OFFSET:
+ return AR5416_PWR_TABLE_OFFSET_DB;
default:
return 0;
}
@@ -385,6 +389,7 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
struct ath9k_channel *chan,
int16_t *pTxPowerIndexOffset)
{
+ struct ath_common *common = ath9k_hw_common(ah);
struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
struct cal_data_per_freq_4k *pRawDataset;
u8 *pCalBChans = NULL;
@@ -470,21 +475,21 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
((pdadcValues[4 * j + 3] & 0xFF) << 24);
REG_WRITE(ah, regOffset, reg32);
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PDADC (%d,%4x): %4.4x %8.8x\n",
- i, regChainOffset, regOffset,
- reg32);
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PDADC: Chain %d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d |\n",
- i, 4 * j, pdadcValues[4 * j],
- 4 * j + 1, pdadcValues[4 * j + 1],
- 4 * j + 2, pdadcValues[4 * j + 2],
- 4 * j + 3,
- pdadcValues[4 * j + 3]);
+ ath_print(common, ATH_DBG_EEPROM,
+ "PDADC (%d,%4x): %4.4x %8.8x\n",
+ i, regChainOffset, regOffset,
+ reg32);
+ ath_print(common, ATH_DBG_EEPROM,
+ "PDADC: Chain %d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d |\n",
+ i, 4 * j, pdadcValues[4 * j],
+ 4 * j + 1, pdadcValues[4 * j + 1],
+ 4 * j + 2, pdadcValues[4 * j + 2],
+ 4 * j + 3,
+ pdadcValues[4 * j + 3]);
regOffset += 4;
}
@@ -750,7 +755,7 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
if (AR_SREV_9280_10_OR_LATER(ah)) {
for (i = 0; i < Ar5416RateSize; i++)
- ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
+ ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
}
/* OFDM power per rate */
@@ -1148,20 +1153,21 @@ static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
{
#define EEP_MAP4K_SPURCHAN \
(ah->eeprom.map4k.modalHeader.spurChans[i].spurChan)
+ struct ath_common *common = ath9k_hw_common(ah);
u16 spur_val = AR_NO_SPUR;
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Getting spur idx %d is2Ghz. %d val %x\n",
- i, is2GHz, ah->config.spurchans[i][is2GHz]);
+ ath_print(common, ATH_DBG_ANI,
+ "Getting spur idx %d is2Ghz. %d val %x\n",
+ i, is2GHz, ah->config.spurchans[i][is2GHz]);
switch (ah->config.spurmode) {
case SPUR_DISABLE:
break;
case SPUR_ENABLE_IOCTL:
spur_val = ah->config.spurchans[i][is2GHz];
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Getting spur val from new loc. %d\n", spur_val);
+ ath_print(common, ATH_DBG_ANI,
+ "Getting spur val from new loc. %d\n", spur_val);
break;
case SPUR_ENABLE_EEPROM:
spur_val = EEP_MAP4K_SPURCHAN;
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index c20c21a79b21..839d05a1df29 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "ath9k.h"
+#include "hw.h"
static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah)
{
@@ -29,20 +29,22 @@ static int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah)
static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah)
{
struct ar9287_eeprom *eep = &ah->eeprom.map9287;
+ struct ath_common *common = ath9k_hw_common(ah);
u16 *eep_data;
int addr, eep_start_loc = AR9287_EEP_START_LOC;
eep_data = (u16 *)eep;
if (!ath9k_hw_use_flash(ah)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Reading from EEPROM, not flash\n");
+ ath_print(common, ATH_DBG_EEPROM,
+ "Reading from EEPROM, not flash\n");
}
for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16);
addr++) {
- if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Unable to read eeprom region \n");
+ if (!ath9k_hw_nvram_read(common,
+ addr + eep_start_loc, eep_data)) {
+ ath_print(common, ATH_DBG_EEPROM,
+ "Unable to read eeprom region \n");
return false;
}
eep_data++;
@@ -57,17 +59,18 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
int i, addr;
bool need_swap = false;
struct ar9287_eeprom *eep = &ah->eeprom.map9287;
+ struct ath_common *common = ath9k_hw_common(ah);
if (!ath9k_hw_use_flash(ah)) {
- if (!ath9k_hw_nvram_read
- (ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Reading Magic # failed\n");
+ if (!ath9k_hw_nvram_read(common,
+ AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Reading Magic # failed\n");
return false;
}
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Read Magic = 0x%04X\n", magic);
+ ath_print(common, ATH_DBG_EEPROM,
+ "Read Magic = 0x%04X\n", magic);
if (magic != AR5416_EEPROM_MAGIC) {
magic2 = swab16(magic);
@@ -83,15 +86,15 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
eepdata++;
}
} else {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Invalid EEPROM Magic. "
- "endianness mismatch.\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Invalid EEPROM Magic. "
+ "endianness mismatch.\n");
return -EINVAL;
}
}
}
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ?
- "True" : "False");
+ ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ?
+ "True" : "False");
if (need_swap)
el = swab16(ah->eeprom.map9287.baseEepHeader.length);
@@ -148,9 +151,9 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER
|| ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
- sum, ah->eep_ops->get_eeprom_ver(ah));
+ ath_print(common, ATH_DBG_FATAL,
+ "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+ sum, ah->eep_ops->get_eeprom_ver(ah));
return -EINVAL;
}
@@ -436,6 +439,7 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah,
struct ath9k_channel *chan,
int16_t *pTxPowerIndexOffset)
{
+ struct ath_common *common = ath9k_hw_common(ah);
struct cal_data_per_freq_ar9287 *pRawDataset;
struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop;
u8 *pCalBChans = NULL;
@@ -564,24 +568,25 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah,
& 0xFF) << 24) ;
REG_WRITE(ah, regOffset, reg32);
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PDADC (%d,%4x): %4.4x %8.8x\n",
- i, regChainOffset, regOffset,
- reg32);
-
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PDADC: Chain %d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d |\n",
- i, 4 * j, pdadcValues[4 * j],
- 4 * j + 1,
- pdadcValues[4 * j + 1],
- 4 * j + 2,
- pdadcValues[4 * j + 2],
- 4 * j + 3,
- pdadcValues[4 * j + 3]);
+ ath_print(common, ATH_DBG_EEPROM,
+ "PDADC (%d,%4x): %4.4x "
+ "%8.8x\n",
+ i, regChainOffset, regOffset,
+ reg32);
+
+ ath_print(common, ATH_DBG_EEPROM,
+ "PDADC: Chain %d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d |\n",
+ i, 4 * j, pdadcValues[4 * j],
+ 4 * j + 1,
+ pdadcValues[4 * j + 1],
+ 4 * j + 2,
+ pdadcValues[4 * j + 2],
+ 4 * j + 3,
+ pdadcValues[4 * j + 3]);
regOffset += 4;
}
@@ -831,6 +836,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
{
#define INCREASE_MAXPOW_BY_TWO_CHAIN 6
#define INCREASE_MAXPOW_BY_THREE_CHAIN 10
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader;
@@ -966,8 +972,8 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
INCREASE_MAXPOW_BY_THREE_CHAIN;
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Invalid chainmask configuration\n");
+ ath_print(common, ATH_DBG_EEPROM,
+ "Invalid chainmask configuration\n");
break;
}
}
@@ -1138,19 +1144,20 @@ static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah,
{
#define EEP_MAP9287_SPURCHAN \
(ah->eeprom.map9287.modalHeader.spurChans[i].spurChan)
+ struct ath_common *common = ath9k_hw_common(ah);
u16 spur_val = AR_NO_SPUR;
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Getting spur idx %d is2Ghz. %d val %x\n",
- i, is2GHz, ah->config.spurchans[i][is2GHz]);
+ ath_print(common, ATH_DBG_ANI,
+ "Getting spur idx %d is2Ghz. %d val %x\n",
+ i, is2GHz, ah->config.spurchans[i][is2GHz]);
switch (ah->config.spurmode) {
case SPUR_DISABLE:
break;
case SPUR_ENABLE_IOCTL:
spur_val = ah->config.spurchans[i][is2GHz];
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Getting spur val from new loc. %d\n", spur_val);
+ ath_print(common, ATH_DBG_ANI,
+ "Getting spur val from new loc. %d\n", spur_val);
break;
case SPUR_ENABLE_EEPROM:
spur_val = EEP_MAP9287_SPURCHAN;
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index 4071fc91da0a..404a0341242c 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "ath9k.h"
+#include "hw.h"
static void ath9k_get_txgain_index(struct ath_hw *ah,
struct ath9k_channel *chan,
@@ -89,14 +89,15 @@ static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah)
static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah)
{
#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16))
+ struct ath_common *common = ath9k_hw_common(ah);
u16 *eep_data = (u16 *)&ah->eeprom.def;
int addr, ar5416_eep_start_loc = 0x100;
for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) {
- if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc,
+ if (!ath9k_hw_nvram_read(common, addr + ar5416_eep_start_loc,
eep_data)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Unable to read eeprom region\n");
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "Unable to read eeprom region\n");
return false;
}
eep_data++;
@@ -109,19 +110,20 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
{
struct ar5416_eeprom_def *eep =
(struct ar5416_eeprom_def *) &ah->eeprom.def;
+ struct ath_common *common = ath9k_hw_common(ah);
u16 *eepdata, temp, magic, magic2;
u32 sum = 0, el;
bool need_swap = false;
int i, addr, size;
- if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Reading Magic # failed\n");
+ if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
+ ath_print(common, ATH_DBG_FATAL, "Reading Magic # failed\n");
return false;
}
if (!ath9k_hw_use_flash(ah)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Read Magic = 0x%04X\n", magic);
+ ath_print(common, ATH_DBG_EEPROM,
+ "Read Magic = 0x%04X\n", magic);
if (magic != AR5416_EEPROM_MAGIC) {
magic2 = swab16(magic);
@@ -137,16 +139,16 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
eepdata++;
}
} else {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Invalid EEPROM Magic. "
- "Endianness mismatch.\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Invalid EEPROM Magic. "
+ "Endianness mismatch.\n");
return -EINVAL;
}
}
}
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
- need_swap ? "True" : "False");
+ ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n",
+ need_swap ? "True" : "False");
if (need_swap)
el = swab16(ah->eeprom.def.baseEepHeader.length);
@@ -167,8 +169,8 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
u32 integer, j;
u16 word;
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "EEPROM Endianness is not native.. Changing.\n");
+ ath_print(common, ATH_DBG_EEPROM,
+ "EEPROM Endianness is not native.. Changing.\n");
word = swab16(eep->baseEepHeader.length);
eep->baseEepHeader.length = word;
@@ -214,8 +216,8 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+ ath_print(common, ATH_DBG_FATAL,
+ "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
sum, ah->eep_ops->get_eeprom_ver(ah));
return -EINVAL;
}
@@ -289,6 +291,11 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah,
return pBase->frac_n_5g;
else
return 0;
+ case EEP_PWR_TABLE_OFFSET:
+ if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_21)
+ return pBase->pwr_table_offset;
+ else
+ return AR5416_PWR_TABLE_OFFSET_DB;
default:
return 0;
}
@@ -739,6 +746,76 @@ static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah,
return;
}
+static int16_t ath9k_change_gain_boundary_setting(struct ath_hw *ah,
+ u16 *gb,
+ u16 numXpdGain,
+ u16 pdGainOverlap_t2,
+ int8_t pwr_table_offset,
+ int16_t *diff)
+
+{
+ u16 k;
+
+ /* Prior to writing the boundaries or the pdadc vs. power table
+ * into the chip registers the default starting point on the pdadc
+ * vs. power table needs to be checked and the curve boundaries
+ * adjusted accordingly
+ */
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
+ u16 gb_limit;
+
+ if (AR5416_PWR_TABLE_OFFSET_DB != pwr_table_offset) {
+ /* get the difference in dB */
+ *diff = (u16)(pwr_table_offset - AR5416_PWR_TABLE_OFFSET_DB);
+ /* get the number of half dB steps */
+ *diff *= 2;
+ /* change the original gain boundary settings
+ * by the number of half dB steps
+ */
+ for (k = 0; k < numXpdGain; k++)
+ gb[k] = (u16)(gb[k] - *diff);
+ }
+ /* Because of a hardware limitation, ensure the gain boundary
+ * is not larger than (63 - overlap)
+ */
+ gb_limit = (u16)(AR5416_MAX_RATE_POWER - pdGainOverlap_t2);
+
+ for (k = 0; k < numXpdGain; k++)
+ gb[k] = (u16)min(gb_limit, gb[k]);
+ }
+
+ return *diff;
+}
+
+static void ath9k_adjust_pdadc_values(struct ath_hw *ah,
+ int8_t pwr_table_offset,
+ int16_t diff,
+ u8 *pdadcValues)
+{
+#define NUM_PDADC(diff) (AR5416_NUM_PDADC_VALUES - diff)
+ u16 k;
+
+ /* If this is a board that has a pwrTableOffset that differs from
+ * the default AR5416_PWR_TABLE_OFFSET_DB then the start of the
+ * pdadc vs pwr table needs to be adjusted prior to writing to the
+ * chip.
+ */
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
+ if (AR5416_PWR_TABLE_OFFSET_DB != pwr_table_offset) {
+ /* shift the table to start at the new offset */
+ for (k = 0; k < (u16)NUM_PDADC(diff); k++ ) {
+ pdadcValues[k] = pdadcValues[k + diff];
+ }
+
+ /* fill the back of the table */
+ for (k = (u16)NUM_PDADC(diff); k < NUM_PDADC(0); k++) {
+ pdadcValues[k] = pdadcValues[NUM_PDADC(diff)];
+ }
+ }
+ }
+#undef NUM_PDADC
+}
+
static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
struct ath9k_channel *chan,
int16_t *pTxPowerIndexOffset)
@@ -746,7 +823,7 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
#define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x)
#define SM_PDGAIN_B(x, y) \
SM((gainBoundaries[x]), AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##y)
-
+ struct ath_common *common = ath9k_hw_common(ah);
struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
struct cal_data_per_freq *pRawDataset;
u8 *pCalBChans = NULL;
@@ -754,15 +831,18 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
u16 numPiers, i, j;
- int16_t tMinCalPower;
+ int16_t tMinCalPower, diff = 0;
u16 numXpdGain, xpdMask;
u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
u32 reg32, regOffset, regChainOffset;
int16_t modalIdx;
+ int8_t pwr_table_offset;
modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
xpdMask = pEepData->modalHeader[modalIdx].xpdGain;
+ pwr_table_offset = ah->eep_ops->get_eeprom(ah, EEP_PWR_TABLE_OFFSET);
+
if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
AR5416_EEP_MINOR_VER_2) {
pdGainOverlap_t2 =
@@ -842,6 +922,13 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
numXpdGain);
}
+ diff = ath9k_change_gain_boundary_setting(ah,
+ gainBoundaries,
+ numXpdGain,
+ pdGainOverlap_t2,
+ pwr_table_offset,
+ &diff);
+
if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
if (OLC_FOR_AR9280_20_LATER) {
REG_WRITE(ah,
@@ -862,6 +949,10 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
}
}
+
+ ath9k_adjust_pdadc_values(ah, pwr_table_offset,
+ diff, pdadcValues);
+
regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
for (j = 0; j < 32; j++) {
reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) |
@@ -870,20 +961,20 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
((pdadcValues[4 * j + 3] & 0xFF) << 24);
REG_WRITE(ah, regOffset, reg32);
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PDADC (%d,%4x): %4.4x %8.8x\n",
- i, regChainOffset, regOffset,
- reg32);
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PDADC: Chain %d | PDADC %3d "
- "Value %3d | PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | PDADC %3d "
- "Value %3d |\n",
- i, 4 * j, pdadcValues[4 * j],
- 4 * j + 1, pdadcValues[4 * j + 1],
- 4 * j + 2, pdadcValues[4 * j + 2],
- 4 * j + 3,
- pdadcValues[4 * j + 3]);
+ ath_print(common, ATH_DBG_EEPROM,
+ "PDADC (%d,%4x): %4.4x %8.8x\n",
+ i, regChainOffset, regOffset,
+ reg32);
+ ath_print(common, ATH_DBG_EEPROM,
+ "PDADC: Chain %d | PDADC %3d "
+ "Value %3d | PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | PDADC %3d "
+ "Value %3d |\n",
+ i, 4 * j, pdadcValues[4 * j],
+ 4 * j + 1, pdadcValues[4 * j + 1],
+ 4 * j + 2, pdadcValues[4 * j + 2],
+ 4 * j + 3,
+ pdadcValues[4 * j + 3]);
regOffset += 4;
}
@@ -1197,8 +1288,13 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
}
if (AR_SREV_9280_10_OR_LATER(ah)) {
- for (i = 0; i < Ar5416RateSize; i++)
- ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
+ for (i = 0; i < Ar5416RateSize; i++) {
+ int8_t pwr_table_offset;
+
+ pwr_table_offset = ah->eep_ops->get_eeprom(ah,
+ EEP_PWR_TABLE_OFFSET);
+ ratesArray[i] -= pwr_table_offset * 2;
+ }
}
REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
@@ -1297,7 +1393,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
if (AR_SREV_9280_10_OR_LATER(ah))
regulatory->max_power_level =
- ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2;
+ ratesArray[i] + AR5416_PWR_TABLE_OFFSET_DB * 2;
else
regulatory->max_power_level = ratesArray[i];
@@ -1311,8 +1407,8 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Invalid chainmask configuration\n");
+ ath_print(ath9k_hw_common(ah), ATH_DBG_EEPROM,
+ "Invalid chainmask configuration\n");
break;
}
}
@@ -1349,20 +1445,21 @@ static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
{
#define EEP_DEF_SPURCHAN \
(ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan)
+ struct ath_common *common = ath9k_hw_common(ah);
u16 spur_val = AR_NO_SPUR;
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Getting spur idx %d is2Ghz. %d val %x\n",
- i, is2GHz, ah->config.spurchans[i][is2GHz]);
+ ath_print(common, ATH_DBG_ANI,
+ "Getting spur idx %d is2Ghz. %d val %x\n",
+ i, is2GHz, ah->config.spurchans[i][is2GHz]);
switch (ah->config.spurmode) {
case SPUR_DISABLE:
break;
case SPUR_ENABLE_IOCTL:
spur_val = ah->config.spurchans[i][is2GHz];
- DPRINTF(ah->ah_sc, ATH_DBG_ANI,
- "Getting spur val from new loc. %d\n", spur_val);
+ ath_print(common, ATH_DBG_ANI,
+ "Getting spur val from new loc. %d\n", spur_val);
break;
case SPUR_ENABLE_EEPROM:
spur_val = EEP_DEF_SPURCHAN;
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index ca7694caf364..cab17c6c8a37 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -16,9 +16,9 @@
#include <linux/io.h>
#include <asm/unaligned.h>
-#include <linux/pci.h>
-#include "ath9k.h"
+#include "hw.h"
+#include "rc.h"
#include "initvals.h"
#define ATH9K_CLOCK_RATE_CCK 22
@@ -26,21 +26,37 @@
#define ATH9K_CLOCK_RATE_2GHZ_OFDM 44
static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type);
-static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan,
- enum ath9k_ht_macmode macmode);
+static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan);
static u32 ath9k_hw_ini_fixup(struct ath_hw *ah,
struct ar5416_eeprom_def *pEepData,
u32 reg, u32 value);
static void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan);
static void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan);
+MODULE_AUTHOR("Atheros Communications");
+MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards.");
+MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards");
+MODULE_LICENSE("Dual BSD/GPL");
+
+static int __init ath9k_init(void)
+{
+ return 0;
+}
+module_init(ath9k_init);
+
+static void __exit ath9k_exit(void)
+{
+ return;
+}
+module_exit(ath9k_exit);
+
/********************/
/* Helper Functions */
/********************/
static u32 ath9k_hw_mac_usec(struct ath_hw *ah, u32 clks)
{
- struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+ struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
if (!ah->curchan) /* should really check for CCK instead */
return clks / ATH9K_CLOCK_RATE_CCK;
@@ -52,7 +68,7 @@ static u32 ath9k_hw_mac_usec(struct ath_hw *ah, u32 clks)
static u32 ath9k_hw_mac_to_usec(struct ath_hw *ah, u32 clks)
{
- struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+ struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
if (conf_is_ht40(conf))
return ath9k_hw_mac_usec(ah, clks) / 2;
@@ -62,7 +78,7 @@ static u32 ath9k_hw_mac_to_usec(struct ath_hw *ah, u32 clks)
static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs)
{
- struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+ struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
if (!ah->curchan) /* should really check for CCK instead */
return usecs *ATH9K_CLOCK_RATE_CCK;
@@ -73,7 +89,7 @@ static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs)
static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs)
{
- struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
+ struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
if (conf_is_ht40(conf))
return ath9k_hw_mac_clks(ah, usecs) * 2;
@@ -81,38 +97,6 @@ static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs)
return ath9k_hw_mac_clks(ah, usecs);
}
-/*
- * Read and write, they both share the same lock. We do this to serialize
- * reads and writes on Atheros 802.11n PCI devices only. This is required
- * as the FIFO on these devices can only accept sanely 2 requests. After
- * that the device goes bananas. Serializing the reads/writes prevents this
- * from happening.
- */
-
-void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val)
-{
- if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
- unsigned long flags;
- spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags);
- iowrite32(val, ah->ah_sc->mem + reg_offset);
- spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags);
- } else
- iowrite32(val, ah->ah_sc->mem + reg_offset);
-}
-
-unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset)
-{
- u32 val;
- if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
- unsigned long flags;
- spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags);
- val = ioread32(ah->ah_sc->mem + reg_offset);
- spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags);
- } else
- val = ioread32(ah->ah_sc->mem + reg_offset);
- return val;
-}
-
bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout)
{
int i;
@@ -126,12 +110,13 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout)
udelay(AH_TIME_QUANTUM);
}
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
- "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
- timeout, reg, REG_READ(ah, reg), mask, val);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_ANY,
+ "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
+ timeout, reg, REG_READ(ah, reg), mask, val);
return false;
}
+EXPORT_SYMBOL(ath9k_hw_wait);
u32 ath9k_hw_reverse_bits(u32 val, u32 n)
{
@@ -210,15 +195,16 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah,
}
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Unknown phy %u (rate ix %u)\n",
- rates->info[rateix].phy, rateix);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "Unknown phy %u (rate ix %u)\n",
+ rates->info[rateix].phy, rateix);
txTime = 0;
break;
}
return txTime;
}
+EXPORT_SYMBOL(ath9k_hw_computetxtime);
void ath9k_hw_get_channel_centers(struct ath_hw *ah,
struct ath9k_channel *chan,
@@ -245,10 +231,9 @@ void ath9k_hw_get_channel_centers(struct ath_hw *ah,
centers->ctl_center =
centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT);
+ /* 25 MHz spacing is supported by hw but not on upper layers */
centers->ext_center =
- centers->synth_center + (extoff *
- ((ah->extprotspacing == ATH9K_HT_EXTPROTSPACING_20) ?
- HT40_CHANNEL_CENTER_SHIFT : 15));
+ centers->synth_center + (extoff * HT40_CHANNEL_CENTER_SHIFT);
}
/******************/
@@ -317,6 +302,7 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
static bool ath9k_hw_chip_test(struct ath_hw *ah)
{
+ struct ath_common *common = ath9k_hw_common(ah);
u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) };
u32 regHold[2];
u32 patternData[4] = { 0x55555555,
@@ -335,10 +321,11 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)
REG_WRITE(ah, addr, wrData);
rdData = REG_READ(ah, addr);
if (rdData != wrData) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "address test failed "
- "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
- addr, wrData, rdData);
+ ath_print(common, ATH_DBG_FATAL,
+ "address test failed "
+ "addr: 0x%08x - wr:0x%08x != "
+ "rd:0x%08x\n",
+ addr, wrData, rdData);
return false;
}
}
@@ -347,10 +334,11 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)
REG_WRITE(ah, addr, wrData);
rdData = REG_READ(ah, addr);
if (wrData != rdData) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "address test failed "
- "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
- addr, wrData, rdData);
+ ath_print(common, ATH_DBG_FATAL,
+ "address test failed "
+ "addr: 0x%08x - wr:0x%08x != "
+ "rd:0x%08x\n",
+ addr, wrData, rdData);
return false;
}
}
@@ -433,6 +421,7 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
if (num_possible_cpus() > 1)
ah->config.serialize_regmode = SER_REG_MODE_AUTO;
}
+EXPORT_SYMBOL(ath9k_hw_init);
static void ath9k_hw_init_defaults(struct ath_hw *ah)
{
@@ -472,8 +461,8 @@ static int ath9k_hw_rfattach(struct ath_hw *ah)
rfStatus = ath9k_hw_init_rf(ah, &ecode);
if (!rfStatus) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "RF setup failed, status: %u\n", ecode);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "RF setup failed, status: %u\n", ecode);
return ecode;
}
@@ -497,9 +486,9 @@ static int ath9k_hw_rf_claim(struct ath_hw *ah)
case AR_RAD2122_SREV_MAJOR:
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Radio Chip Rev 0x%02X not supported\n",
- val & AR_RADIO_SREV_MAJOR);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "Radio Chip Rev 0x%02X not supported\n",
+ val & AR_RADIO_SREV_MAJOR);
return -EOPNOTSUPP;
}
@@ -510,6 +499,7 @@ static int ath9k_hw_rf_claim(struct ath_hw *ah)
static int ath9k_hw_init_macaddr(struct ath_hw *ah)
{
+ struct ath_common *common = ath9k_hw_common(ah);
u32 sum;
int i;
u16 eeval;
@@ -518,8 +508,8 @@ static int ath9k_hw_init_macaddr(struct ath_hw *ah)
for (i = 0; i < 3; i++) {
eeval = ah->eep_ops->get_eeprom(ah, AR_EEPROM_MAC(i));
sum += eeval;
- ah->macaddr[2 * i] = eeval >> 8;
- ah->macaddr[2 * i + 1] = eeval & 0xff;
+ common->macaddr[2 * i] = eeval >> 8;
+ common->macaddr[2 * i + 1] = eeval & 0xff;
}
if (sum == 0 || sum == 0xffff * 3)
return -EADDRNOTAVAIL;
@@ -590,8 +580,10 @@ static int ath9k_hw_post_init(struct ath_hw *ah)
if (ecode != 0)
return ecode;
- DPRINTF(ah->ah_sc, ATH_DBG_CONFIG, "Eeprom VER: %d, REV: %d\n",
- ah->eep_ops->get_eeprom_ver(ah), ah->eep_ops->get_eeprom_rev(ah));
+ ath_print(ath9k_hw_common(ah), ATH_DBG_CONFIG,
+ "Eeprom VER: %d, REV: %d\n",
+ ah->eep_ops->get_eeprom_ver(ah),
+ ah->eep_ops->get_eeprom_rev(ah));
ecode = ath9k_hw_rfattach(ah);
if (ecode != 0)
@@ -617,6 +609,7 @@ static bool ath9k_hw_devid_supported(u16 devid)
case AR9285_DEVID_PCIE:
case AR5416_DEVID_AR9287_PCI:
case AR5416_DEVID_AR9287_PCIE:
+ case AR9271_USB:
return true;
default:
break;
@@ -634,9 +627,8 @@ static bool ath9k_hw_macversion_supported(u32 macversion)
case AR_SREV_VERSION_9280:
case AR_SREV_VERSION_9285:
case AR_SREV_VERSION_9287:
- return true;
- /* Not yet */
case AR_SREV_VERSION_9271:
+ return true;
default:
break;
}
@@ -905,21 +897,27 @@ static void ath9k_hw_init_11a_eeprom_fix(struct ath_hw *ah)
int ath9k_hw_init(struct ath_hw *ah)
{
+ struct ath_common *common = ath9k_hw_common(ah);
int r = 0;
- if (!ath9k_hw_devid_supported(ah->hw_version.devid))
+ if (!ath9k_hw_devid_supported(ah->hw_version.devid)) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unsupported device ID: 0x%0x\n",
+ ah->hw_version.devid);
return -EOPNOTSUPP;
+ }
ath9k_hw_init_defaults(ah);
ath9k_hw_init_config(ah);
if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't reset chip\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Couldn't reset chip\n");
return -EIO;
}
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n");
+ ath_print(common, ATH_DBG_FATAL, "Couldn't wakeup chip\n");
return -EIO;
}
@@ -934,14 +932,14 @@ int ath9k_hw_init(struct ath_hw *ah)
}
}
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "serialize_regmode is %d\n",
+ ath_print(common, ATH_DBG_RESET, "serialize_regmode is %d\n",
ah->config.serialize_regmode);
if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Mac Chip Rev 0x%02x.%x is not supported by "
- "this driver\n", ah->hw_version.macVersion,
- ah->hw_version.macRev);
+ ath_print(common, ATH_DBG_FATAL,
+ "Mac Chip Rev 0x%02x.%x is not supported by "
+ "this driver\n", ah->hw_version.macVersion,
+ ah->hw_version.macRev);
return -EOPNOTSUPP;
}
@@ -969,6 +967,16 @@ int ath9k_hw_init(struct ath_hw *ah)
else
ath9k_hw_disablepcie(ah);
+ /* Support for Japan ch.14 (2484) spread */
+ if (AR_SREV_9287_11_OR_LATER(ah)) {
+ INIT_INI_ARRAY(&ah->iniCckfirNormal,
+ ar9287Common_normal_cck_fir_coeff_92871_1,
+ ARRAY_SIZE(ar9287Common_normal_cck_fir_coeff_92871_1), 2);
+ INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
+ ar9287Common_japan_2484_cck_fir_coeff_92871_1,
+ ARRAY_SIZE(ar9287Common_japan_2484_cck_fir_coeff_92871_1), 2);
+ }
+
r = ath9k_hw_post_init(ah);
if (r)
return r;
@@ -979,8 +987,8 @@ int ath9k_hw_init(struct ath_hw *ah)
r = ath9k_hw_init_macaddr(ah);
if (r) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Failed to initialize MAC address\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Failed to initialize MAC address\n");
return r;
}
@@ -991,6 +999,8 @@ int ath9k_hw_init(struct ath_hw *ah)
ath9k_init_nfcal_hist_buffer(ah);
+ common->state = ATH_HW_INITIALIZED;
+
return 0;
}
@@ -1164,7 +1174,8 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
{
if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad ack timeout %u\n", us);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
+ "bad ack timeout %u\n", us);
ah->acktimeout = (u32) -1;
return false;
} else {
@@ -1178,7 +1189,8 @@ static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
{
if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad cts timeout %u\n", us);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
+ "bad cts timeout %u\n", us);
ah->ctstimeout = (u32) -1;
return false;
} else {
@@ -1192,8 +1204,8 @@ static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu)
{
if (tu > 0xFFFF) {
- DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
- "bad global tx timeout %u\n", tu);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_XMIT,
+ "bad global tx timeout %u\n", tu);
ah->globaltxtimeout = (u32) -1;
return false;
} else {
@@ -1205,8 +1217,8 @@ static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu)
static void ath9k_hw_init_user_settings(struct ath_hw *ah)
{
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "ah->misc_mode 0x%x\n",
- ah->misc_mode);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, "ah->misc_mode 0x%x\n",
+ ah->misc_mode);
if (ah->misc_mode != 0)
REG_WRITE(ah, AR_PCU_MISC,
@@ -1229,14 +1241,22 @@ const char *ath9k_hw_probe(u16 vendorid, u16 devid)
void ath9k_hw_detach(struct ath_hw *ah)
{
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ if (common->state <= ATH_HW_INITIALIZED)
+ goto free_hw;
+
if (!AR_SREV_9100(ah))
ath9k_hw_ani_disable(ah);
- ath9k_hw_rf_free(ah);
ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
+
+free_hw:
+ ath9k_hw_rf_free(ah);
kfree(ah);
ah = NULL;
}
+EXPORT_SYMBOL(ath9k_hw_detach);
/*******/
/* INI */
@@ -1298,28 +1318,29 @@ static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah,
u32 reg, u32 value)
{
struct base_eep_header *pBase = &(pEepData->baseEepHeader);
+ struct ath_common *common = ath9k_hw_common(ah);
switch (ah->hw_version.devid) {
case AR9280_DEVID_PCI:
if (reg == 0x7894) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ ath_print(common, ATH_DBG_EEPROM,
"ini VAL: %x EEPROM: %x\n", value,
(pBase->version & 0xff));
if ((pBase->version & 0xff) > 0x0a) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PWDCLKIND: %d\n",
- pBase->pwdclkind);
+ ath_print(common, ATH_DBG_EEPROM,
+ "PWDCLKIND: %d\n",
+ pBase->pwdclkind);
value &= ~AR_AN_TOP2_PWDCLKIND;
value |= AR_AN_TOP2_PWDCLKIND &
(pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S);
} else {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "PWDCLKIND Earlier Rev\n");
+ ath_print(common, ATH_DBG_EEPROM,
+ "PWDCLKIND Earlier Rev\n");
}
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "final ini VAL: %x\n", value);
+ ath_print(common, ATH_DBG_EEPROM,
+ "final ini VAL: %x\n", value);
}
break;
}
@@ -1374,8 +1395,7 @@ static u32 ath9k_regd_get_ctl(struct ath_regulatory *reg,
}
static int ath9k_hw_process_ini(struct ath_hw *ah,
- struct ath9k_channel *chan,
- enum ath9k_ht_macmode macmode)
+ struct ath9k_channel *chan)
{
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
int i, regWrites = 0;
@@ -1477,7 +1497,7 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
}
ath9k_hw_override_ini(ah, chan);
- ath9k_hw_set_regs(ah, chan, macmode);
+ ath9k_hw_set_regs(ah, chan);
ath9k_hw_init_chain_masks(ah);
if (OLC_FOR_AR9280_20_LATER)
@@ -1491,8 +1511,8 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
(u32) regulatory->power_limit));
if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "ar5416SetRfRegs failed\n");
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "ar5416SetRfRegs failed\n");
return -EIO;
}
@@ -1697,16 +1717,14 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
REG_WRITE(ah, AR_RTC_RC, 0);
if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET,
- "RTC stuck in MAC reset\n");
+ ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
+ "RTC stuck in MAC reset\n");
return false;
}
if (!AR_SREV_9100(ah))
REG_WRITE(ah, AR_RC, 0);
- ath9k_hw_init_pll(ah, NULL);
-
if (AR_SREV_9100(ah))
udelay(50);
@@ -1734,7 +1752,8 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
AR_RTC_STATUS_M,
AR_RTC_STATUS_ON,
AH_WAIT_TIMEOUT)) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "RTC not waking up\n");
+ ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
+ "RTC not waking up\n");
return false;
}
@@ -1759,8 +1778,7 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
}
}
-static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan,
- enum ath9k_ht_macmode macmode)
+static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan)
{
u32 phymode;
u32 enableDacFifo = 0;
@@ -1779,12 +1797,10 @@ static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan,
(chan->chanmode == CHANNEL_G_HT40PLUS))
phymode |= AR_PHY_FC_DYN2040_PRI_CH;
- if (ah->extprotspacing == ATH9K_HT_EXTPROTSPACING_25)
- phymode |= AR_PHY_FC_DYN2040_EXT_CH;
}
REG_WRITE(ah, AR_PHY_TURBO, phymode);
- ath9k_hw_set11nmac2040(ah, macmode);
+ ath9k_hw_set11nmac2040(ah);
REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);
REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
@@ -1810,17 +1826,18 @@ static bool ath9k_hw_chip_reset(struct ath_hw *ah,
}
static bool ath9k_hw_channel_change(struct ath_hw *ah,
- struct ath9k_channel *chan,
- enum ath9k_ht_macmode macmode)
+ struct ath9k_channel *chan)
{
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_channel *channel = chan->chan;
u32 synthDelay, qnum;
for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
if (ath9k_hw_numtxpending(ah, qnum)) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
- "Transmit frames pending on queue %d\n", qnum);
+ ath_print(common, ATH_DBG_QUEUE,
+ "Transmit frames pending on "
+ "queue %d\n", qnum);
return false;
}
}
@@ -1828,19 +1845,19 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN);
if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,
AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Could not kill baseband RX\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Could not kill baseband RX\n");
return false;
}
- ath9k_hw_set_regs(ah, chan, macmode);
+ ath9k_hw_set_regs(ah, chan);
if (AR_SREV_9280_10_OR_LATER(ah)) {
ath9k_hw_ar9280_set_channel(ah, chan);
} else {
if (!(ath9k_hw_set_channel(ah, chan))) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Failed to set channel\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Failed to set channel\n");
return false;
}
}
@@ -2342,17 +2359,16 @@ static void ath9k_enable_rfkill(struct ath_hw *ah)
int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
bool bChannelChange)
{
+ struct ath_common *common = ath9k_hw_common(ah);
u32 saveLedState;
- struct ath_softc *sc = ah->ah_sc;
struct ath9k_channel *curchan = ah->curchan;
u32 saveDefAntenna;
u32 macStaId1;
u64 tsf = 0;
int i, rx_chainmask, r;
- ah->extprotspacing = sc->ht_extprotspacing;
- ah->txchainmask = sc->tx_chainmask;
- ah->rxchainmask = sc->rx_chainmask;
+ ah->txchainmask = common->tx_chainmask;
+ ah->rxchainmask = common->rx_chainmask;
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
return -EIO;
@@ -2369,7 +2385,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
!(AR_SREV_9280(ah) || IS_CHAN_A_5MHZ_SPACED(chan) ||
IS_CHAN_A_5MHZ_SPACED(ah->curchan))) {
- if (ath9k_hw_channel_change(ah, chan, sc->tx_chan_width)) {
+ if (ath9k_hw_channel_change(ah, chan)) {
ath9k_hw_loadnf(ah, ah->curchan);
ath9k_hw_start_nfcal(ah);
return 0;
@@ -2400,7 +2416,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
}
if (!ath9k_hw_chip_reset(ah, chan)) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Chip reset failed\n");
+ ath_print(common, ATH_DBG_FATAL, "Chip reset failed\n");
return -EINVAL;
}
@@ -2429,7 +2445,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
}
- r = ath9k_hw_process_ini(ah, chan, sc->tx_chan_width);
+ r = ath9k_hw_process_ini(ah, chan);
if (r)
return r;
@@ -2462,8 +2478,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_decrease_chain_power(ah, chan);
- REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(ah->macaddr));
- REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(ah->macaddr + 4)
+ REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
+ REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4)
| macStaId1
| AR_STA_ID1_RTS_USE_DEF
| (ah->config.
@@ -2471,14 +2487,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
| ah->sta_id1_defaults);
ath9k_hw_set_operating_mode(ah, ah->opmode);
- REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(sc->bssidmask));
- REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(sc->bssidmask + 4));
+ ath_hw_setbssidmask(common);
REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
- REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(sc->curbssid));
- REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(sc->curbssid + 4) |
- ((sc->curaid & 0x3fff) << AR_BSS_ID1_AID_S));
+ ath9k_hw_write_associd(ah);
REG_WRITE(ah, AR_ISR, ~0);
@@ -2558,13 +2571,13 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
u32 mask;
mask = REG_READ(ah, AR_CFG);
if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+ ath_print(common, ATH_DBG_RESET,
"CFG Byte Swap Set 0x%x\n", mask);
} else {
mask =
INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB;
REG_WRITE(ah, AR_CFG, mask);
- DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+ ath_print(common, ATH_DBG_RESET,
"Setting CFG 0x%x\n", REG_READ(ah, AR_CFG));
}
} else {
@@ -2577,11 +2590,12 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
#endif
}
- if (ah->ah_sc->sc_flags & SC_OP_BTCOEX_ENABLED)
+ if (ah->btcoex_hw.enabled)
ath9k_hw_btcoex_enable(ah);
return 0;
}
+EXPORT_SYMBOL(ath9k_hw_reset);
/************************/
/* Key Cache Management */
@@ -2592,8 +2606,8 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry)
u32 keyType;
if (entry >= ah->caps.keycache_size) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "keychache entry %u out of range\n", entry);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "keychache entry %u out of range\n", entry);
return false;
}
@@ -2620,14 +2634,15 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry)
return true;
}
+EXPORT_SYMBOL(ath9k_hw_keyreset);
bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
{
u32 macHi, macLo;
if (entry >= ah->caps.keycache_size) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "keychache entry %u out of range\n", entry);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "keychache entry %u out of range\n", entry);
return false;
}
@@ -2648,18 +2663,20 @@ bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
return true;
}
+EXPORT_SYMBOL(ath9k_hw_keysetmac);
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) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "keycache entry %u out of range\n", entry);
+ ath_print(common, ATH_DBG_FATAL,
+ "keycache entry %u out of range\n", entry);
return false;
}
@@ -2669,9 +2686,9 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
break;
case ATH9K_CIPHER_AES_CCM:
if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
- "AES-CCM not supported by mac rev 0x%x\n",
- ah->hw_version.macRev);
+ 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;
@@ -2680,15 +2697,15 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
keyType = AR_KEYTABLE_TYPE_TKIP;
if (ATH9K_IS_MIC_ENABLED(ah)
&& entry + 64 >= pCap->keycache_size) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
- "entry %u inappropriate for TKIP\n", entry);
+ 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) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
- "WEP key length %u too small\n", k->kv_len);
+ 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)
@@ -2702,8 +2719,8 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
keyType = AR_KEYTABLE_TYPE_CLR;
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "cipher %u not supported\n", k->kv_type);
+ ath_print(common, ATH_DBG_FATAL,
+ "cipher %u not supported\n", k->kv_type);
return false;
}
@@ -2845,6 +2862,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
return true;
}
+EXPORT_SYMBOL(ath9k_hw_set_keycache_entry);
bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry)
{
@@ -2855,6 +2873,7 @@ bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry)
}
return false;
}
+EXPORT_SYMBOL(ath9k_hw_keyisvalid);
/******************************/
/* Power Management (Chipset) */
@@ -2869,8 +2888,9 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
if (!AR_SREV_9100(ah))
REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
- REG_CLR_BIT(ah, (AR_RTC_RESET),
- AR_RTC_RESET_EN);
+ if(!AR_SREV_5416(ah))
+ REG_CLR_BIT(ah, (AR_RTC_RESET),
+ AR_RTC_RESET_EN);
}
}
@@ -2902,6 +2922,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
ATH9K_RESET_POWER_ON) != true) {
return false;
}
+ ath9k_hw_init_pll(ah, NULL);
}
if (AR_SREV_9100(ah))
REG_SET_BIT(ah, AR_RTC_RESET,
@@ -2920,8 +2941,9 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
AR_RTC_FORCE_WAKE_EN);
}
if (i == 0) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Failed to wakeup in %uus\n", POWER_UP_TIME / 20);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "Failed to wakeup in %uus\n",
+ POWER_UP_TIME / 20);
return false;
}
}
@@ -2931,9 +2953,9 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
return true;
}
-static bool ath9k_hw_setpower_nolock(struct ath_hw *ah,
- enum ath9k_power_mode mode)
+bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
{
+ struct ath_common *common = ath9k_hw_common(ah);
int status = true, setChip = true;
static const char *modes[] = {
"AWAKE",
@@ -2945,8 +2967,8 @@ static bool ath9k_hw_setpower_nolock(struct ath_hw *ah,
if (ah->power_mode == mode)
return status;
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s -> %s\n",
- modes[ah->power_mode], modes[mode]);
+ ath_print(common, ATH_DBG_RESET, "%s -> %s\n",
+ modes[ah->power_mode], modes[mode]);
switch (mode) {
case ATH9K_PM_AWAKE:
@@ -2960,59 +2982,15 @@ static bool ath9k_hw_setpower_nolock(struct ath_hw *ah,
ath9k_set_power_network_sleep(ah, setChip);
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Unknown power mode %u\n", mode);
+ ath_print(common, ATH_DBG_FATAL,
+ "Unknown power mode %u\n", mode);
return false;
}
ah->power_mode = mode;
return status;
}
-
-bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
-{
- unsigned long flags;
- bool ret;
-
- spin_lock_irqsave(&ah->ah_sc->sc_pm_lock, flags);
- ret = ath9k_hw_setpower_nolock(ah, mode);
- spin_unlock_irqrestore(&ah->ah_sc->sc_pm_lock, flags);
-
- return ret;
-}
-
-void ath9k_ps_wakeup(struct ath_softc *sc)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&sc->sc_pm_lock, flags);
- if (++sc->ps_usecount != 1)
- goto unlock;
-
- ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE);
-
- unlock:
- spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
-}
-
-void ath9k_ps_restore(struct ath_softc *sc)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&sc->sc_pm_lock, flags);
- if (--sc->ps_usecount != 0)
- goto unlock;
-
- if (sc->ps_enabled &&
- !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
- SC_OP_WAIT_FOR_CAB |
- SC_OP_WAIT_FOR_PSPOLL_DATA |
- SC_OP_WAIT_FOR_TX_ACK)))
- ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
-
- unlock:
- spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
-}
+EXPORT_SYMBOL(ath9k_hw_setpower);
/*
* Helper for ASPM support.
@@ -3145,6 +3123,7 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore, int power_off)
}
}
}
+EXPORT_SYMBOL(ath9k_hw_configpcipowersave);
/**********************/
/* Interrupt Handling */
@@ -3168,6 +3147,7 @@ bool ath9k_hw_intrpend(struct ath_hw *ah)
return false;
}
+EXPORT_SYMBOL(ath9k_hw_intrpend);
bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
{
@@ -3176,6 +3156,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
struct ath9k_hw_capabilities *pCap = &ah->caps;
u32 sync_cause = 0;
bool fatal_int = false;
+ struct ath_common *common = ath9k_hw_common(ah);
if (!AR_SREV_9100(ah)) {
if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) {
@@ -3249,8 +3230,8 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
}
if (isr & AR_ISR_RXORN) {
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
- "receive FIFO overrun interrupt\n");
+ ath_print(common, ATH_DBG_INTERRUPT,
+ "receive FIFO overrun interrupt\n");
}
if (!AR_SREV_9100(ah)) {
@@ -3292,25 +3273,25 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
if (fatal_int) {
if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
- "received PCI FATAL interrupt\n");
+ ath_print(common, ATH_DBG_ANY,
+ "received PCI FATAL interrupt\n");
}
if (sync_cause & AR_INTR_SYNC_HOST1_PERR) {
- DPRINTF(ah->ah_sc, ATH_DBG_ANY,
- "received PCI PERR interrupt\n");
+ ath_print(common, ATH_DBG_ANY,
+ "received PCI PERR interrupt\n");
}
*masked |= ATH9K_INT_FATAL;
}
if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
- "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n");
+ ath_print(common, ATH_DBG_INTERRUPT,
+ "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n");
REG_WRITE(ah, AR_RC, AR_RC_HOSTIF);
REG_WRITE(ah, AR_RC, 0);
*masked |= ATH9K_INT_FATAL;
}
if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) {
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
- "AR_INTR_SYNC_LOCAL_TIMEOUT\n");
+ ath_print(common, ATH_DBG_INTERRUPT,
+ "AR_INTR_SYNC_LOCAL_TIMEOUT\n");
}
REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
@@ -3319,17 +3300,19 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
return true;
}
+EXPORT_SYMBOL(ath9k_hw_getisr);
enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
{
u32 omask = ah->mask_reg;
u32 mask, mask2;
struct ath9k_hw_capabilities *pCap = &ah->caps;
+ struct ath_common *common = ath9k_hw_common(ah);
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
+ ath_print(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
if (omask & ATH9K_INT_GLOBAL) {
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "disable IER\n");
+ ath_print(common, ATH_DBG_INTERRUPT, "disable IER\n");
REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
(void) REG_READ(ah, AR_IER);
if (!AR_SREV_9100(ah)) {
@@ -3386,7 +3369,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
mask2 |= AR_IMR_S2_CST;
}
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask);
+ ath_print(common, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask);
REG_WRITE(ah, AR_IMR, mask);
mask = REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM |
AR_IMR_S2_DTIM |
@@ -3406,7 +3389,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
}
if (ints & ATH9K_INT_GLOBAL) {
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "enable IER\n");
+ ath_print(common, ATH_DBG_INTERRUPT, "enable IER\n");
REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
if (!AR_SREV_9100(ah)) {
REG_WRITE(ah, AR_INTR_ASYNC_ENABLE,
@@ -3419,12 +3402,13 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
REG_WRITE(ah, AR_INTR_SYNC_MASK,
AR_INTR_SYNC_DEFAULT);
}
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
- REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
+ ath_print(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
+ REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
}
return omask;
}
+EXPORT_SYMBOL(ath9k_hw_set_interrupts);
/*******************/
/* Beacon Handling */
@@ -3467,9 +3451,9 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN;
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_BEACON,
- "%s: unsupported opmode: %d\n",
- __func__, ah->opmode);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_BEACON,
+ "%s: unsupported opmode: %d\n",
+ __func__, ah->opmode);
return;
break;
}
@@ -3481,18 +3465,19 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
beacon_period &= ~ATH9K_BEACON_ENA;
if (beacon_period & ATH9K_BEACON_RESET_TSF) {
- beacon_period &= ~ATH9K_BEACON_RESET_TSF;
ath9k_hw_reset_tsf(ah);
}
REG_SET_BIT(ah, AR_TIMER_MODE, flags);
}
+EXPORT_SYMBOL(ath9k_hw_beaconinit);
void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
const struct ath9k_beacon_state *bs)
{
u32 nextTbtt, beaconintval, dtimperiod, beacontimeout;
struct ath9k_hw_capabilities *pCap = &ah->caps;
+ struct ath_common *common = ath9k_hw_common(ah);
REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt));
@@ -3518,10 +3503,10 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
else
nextTbtt = bs->bs_nexttbtt;
- DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next DTIM %d\n", bs->bs_nextdtim);
- DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next beacon %d\n", nextTbtt);
- DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "beacon period %d\n", beaconintval);
- DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod);
+ ath_print(common, ATH_DBG_BEACON, "next DTIM %d\n", bs->bs_nextdtim);
+ ath_print(common, ATH_DBG_BEACON, "next beacon %d\n", nextTbtt);
+ ath_print(common, ATH_DBG_BEACON, "beacon period %d\n", beaconintval);
+ ath_print(common, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod);
REG_WRITE(ah, AR_NEXT_DTIM,
TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP));
@@ -3549,6 +3534,7 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
/* TSF Out of Range Threshold */
REG_WRITE(ah, AR_TSFOOR_THRESHOLD, bs->bs_tsfoor_threshold);
}
+EXPORT_SYMBOL(ath9k_hw_set_sta_beacon_timers);
/*******************/
/* HW Capabilities */
@@ -3558,7 +3544,8 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
{
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
- struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
u16 capField = 0, eeval;
@@ -3579,8 +3566,8 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
regulatory->current_rd += 5;
else if (regulatory->current_rd == 0x41)
regulatory->current_rd = 0x43;
- DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
- "regdomain mapped to 0x%x\n", regulatory->current_rd);
+ ath_print(common, ATH_DBG_REGULATORY,
+ "regdomain mapped to 0x%x\n", regulatory->current_rd);
}
eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE);
@@ -3719,7 +3706,10 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN;
}
- pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND;
+ /* Advertise midband for AR5416 with FCC midband set in eeprom */
+ if (regulatory->current_rd_ext & (1 << REG_EXT_FCC_MIDBAND) &&
+ AR_SREV_5416(ah))
+ pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND;
pCap->num_antcfg_5ghz =
ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_5GHZ);
@@ -3727,18 +3717,18 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ);
if (AR_SREV_9280_10_OR_LATER(ah) &&
- ath_btcoex_supported(ah->hw_version.subsysid)) {
- btcoex_info->btactive_gpio = ATH_BTACTIVE_GPIO;
- btcoex_info->wlanactive_gpio = ATH_WLANACTIVE_GPIO;
+ ath9k_hw_btcoex_supported(ah)) {
+ btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO;
+ btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO;
if (AR_SREV_9285(ah)) {
- btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_3WIRE;
- btcoex_info->btpriority_gpio = ATH_BTPRIORITY_GPIO;
+ btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
+ btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO;
} else {
- btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_2WIRE;
+ btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE;
}
} else {
- btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_NONE;
+ btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE;
}
}
@@ -3812,6 +3802,7 @@ bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
return false;
}
}
+EXPORT_SYMBOL(ath9k_hw_getcapability);
bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type,
u32 capability, u32 setting, int *status)
@@ -3845,6 +3836,7 @@ bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type,
return false;
}
}
+EXPORT_SYMBOL(ath9k_hw_setcapability);
/****************************/
/* GPIO / RFKILL / Antennae */
@@ -3882,7 +3874,7 @@ void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio)
{
u32 gpio_shift;
- ASSERT(gpio < ah->caps.num_gpio_pins);
+ BUG_ON(gpio >= ah->caps.num_gpio_pins);
gpio_shift = gpio << 1;
@@ -3891,6 +3883,7 @@ void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio)
(AR_GPIO_OE_OUT_DRV_NO << gpio_shift),
(AR_GPIO_OE_OUT_DRV << gpio_shift));
}
+EXPORT_SYMBOL(ath9k_hw_cfg_gpio_input);
u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
{
@@ -3909,6 +3902,7 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
else
return MS_REG_READ(AR, gpio) != 0;
}
+EXPORT_SYMBOL(ath9k_hw_gpio_get);
void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
u32 ah_signal_type)
@@ -3924,22 +3918,26 @@ void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
(AR_GPIO_OE_OUT_DRV_ALL << gpio_shift),
(AR_GPIO_OE_OUT_DRV << gpio_shift));
}
+EXPORT_SYMBOL(ath9k_hw_cfg_output);
void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)
{
REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio),
AR_GPIO_BIT(gpio));
}
+EXPORT_SYMBOL(ath9k_hw_set_gpio);
u32 ath9k_hw_getdefantenna(struct ath_hw *ah)
{
return REG_READ(ah, AR_DEF_ANTENNA) & 0x7;
}
+EXPORT_SYMBOL(ath9k_hw_getdefantenna);
void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna)
{
REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));
}
+EXPORT_SYMBOL(ath9k_hw_setantenna);
bool ath9k_hw_setantennaswitch(struct ath_hw *ah,
enum ath9k_ant_setting settings,
@@ -4002,6 +4000,7 @@ u32 ath9k_hw_getrxfilter(struct ath_hw *ah)
return bits;
}
+EXPORT_SYMBOL(ath9k_hw_getrxfilter);
void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
{
@@ -4023,19 +4022,30 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
REG_WRITE(ah, AR_RXCFG,
REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
}
+EXPORT_SYMBOL(ath9k_hw_setrxfilter);
bool ath9k_hw_phy_disable(struct ath_hw *ah)
{
- return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM);
+ if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
+ return false;
+
+ ath9k_hw_init_pll(ah, NULL);
+ return true;
}
+EXPORT_SYMBOL(ath9k_hw_phy_disable);
bool ath9k_hw_disable(struct ath_hw *ah)
{
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
return false;
- return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD);
+ if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD))
+ return false;
+
+ ath9k_hw_init_pll(ah, NULL);
+ return true;
}
+EXPORT_SYMBOL(ath9k_hw_disable);
void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit)
{
@@ -4052,35 +4062,36 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit)
min((u32) MAX_RATE_POWER,
(u32) regulatory->power_limit));
}
+EXPORT_SYMBOL(ath9k_hw_set_txpowerlimit);
void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac)
{
- memcpy(ah->macaddr, mac, ETH_ALEN);
+ memcpy(ath9k_hw_common(ah)->macaddr, mac, ETH_ALEN);
}
+EXPORT_SYMBOL(ath9k_hw_setmac);
void ath9k_hw_setopmode(struct ath_hw *ah)
{
ath9k_hw_set_operating_mode(ah, ah->opmode);
}
+EXPORT_SYMBOL(ath9k_hw_setopmode);
void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1)
{
REG_WRITE(ah, AR_MCAST_FIL0, filter0);
REG_WRITE(ah, AR_MCAST_FIL1, filter1);
}
+EXPORT_SYMBOL(ath9k_hw_setmcastfilter);
-void ath9k_hw_setbssidmask(struct ath_softc *sc)
+void ath9k_hw_write_associd(struct ath_hw *ah)
{
- REG_WRITE(sc->sc_ah, AR_BSSMSKL, get_unaligned_le32(sc->bssidmask));
- REG_WRITE(sc->sc_ah, AR_BSSMSKU, get_unaligned_le16(sc->bssidmask + 4));
-}
+ struct ath_common *common = ath9k_hw_common(ah);
-void ath9k_hw_write_associd(struct ath_softc *sc)
-{
- REG_WRITE(sc->sc_ah, AR_BSS_ID0, get_unaligned_le32(sc->curbssid));
- REG_WRITE(sc->sc_ah, AR_BSS_ID1, get_unaligned_le16(sc->curbssid + 4) |
- ((sc->curaid & 0x3fff) << AR_BSS_ID1_AID_S));
+ REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(common->curbssid));
+ REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(common->curbssid + 4) |
+ ((common->curaid & 0x3fff) << AR_BSS_ID1_AID_S));
}
+EXPORT_SYMBOL(ath9k_hw_write_associd);
u64 ath9k_hw_gettsf64(struct ath_hw *ah)
{
@@ -4091,24 +4102,25 @@ u64 ath9k_hw_gettsf64(struct ath_hw *ah)
return tsf;
}
+EXPORT_SYMBOL(ath9k_hw_gettsf64);
void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64)
{
REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff);
REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff);
}
+EXPORT_SYMBOL(ath9k_hw_settsf64);
void ath9k_hw_reset_tsf(struct ath_hw *ah)
{
- ath9k_ps_wakeup(ah->ah_sc);
if (!ath9k_hw_wait(ah, AR_SLP32_MODE, AR_SLP32_TSF_WRITE_STATUS, 0,
AH_TSF_WRITE_TIMEOUT))
- DPRINTF(ah->ah_sc, ATH_DBG_RESET,
- "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
+ ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
+ "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
- ath9k_ps_restore(ah->ah_sc);
}
+EXPORT_SYMBOL(ath9k_hw_reset_tsf);
void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
{
@@ -4117,11 +4129,13 @@ void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
else
ah->misc_mode &= ~AR_PCU_TX_ADD_TSF;
}
+EXPORT_SYMBOL(ath9k_hw_set_tsfadjust);
bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
{
if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad slot time %u\n", us);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
+ "bad slot time %u\n", us);
ah->slottime = (u32) -1;
return false;
} else {
@@ -4130,13 +4144,14 @@ bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
return true;
}
}
+EXPORT_SYMBOL(ath9k_hw_setslottime);
-void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode)
+void ath9k_hw_set11nmac2040(struct ath_hw *ah)
{
+ struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
u32 macmode;
- if (mode == ATH9K_HT_MACMODE_2040 &&
- !ah->config.cwm_ignore_extcca)
+ if (conf_is_ht40(conf) && !ah->config.cwm_ignore_extcca)
macmode = AR_2040_JOINED_RX_CLEAR;
else
macmode = 0;
@@ -4193,6 +4208,7 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah)
{
return REG_READ(ah, AR_TSF_L32);
}
+EXPORT_SYMBOL(ath9k_hw_gettsf32);
struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
void (*trigger)(void *),
@@ -4206,8 +4222,9 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL);
if (timer == NULL) {
- printk(KERN_DEBUG "Failed to allocate memory"
- "for hw timer[%d]\n", timer_index);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "Failed to allocate memory"
+ "for hw timer[%d]\n", timer_index);
return NULL;
}
@@ -4220,10 +4237,12 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
return timer;
}
+EXPORT_SYMBOL(ath_gen_timer_alloc);
-void ath_gen_timer_start(struct ath_hw *ah,
- struct ath_gen_timer *timer,
- u32 timer_next, u32 timer_period)
+void ath9k_hw_gen_timer_start(struct ath_hw *ah,
+ struct ath_gen_timer *timer,
+ u32 timer_next,
+ u32 timer_period)
{
struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
u32 tsf;
@@ -4234,8 +4253,9 @@ void ath_gen_timer_start(struct ath_hw *ah,
tsf = ath9k_hw_gettsf32(ah);
- DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER, "curent tsf %x period %x"
- "timer_next %x\n", tsf, timer_period, timer_next);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_HWTIMER,
+ "curent tsf %x period %x"
+ "timer_next %x\n", tsf, timer_period, timer_next);
/*
* Pull timer_next forward if the current TSF already passed it
@@ -4258,15 +4278,10 @@ void ath_gen_timer_start(struct ath_hw *ah,
REG_SET_BIT(ah, AR_IMR_S5,
(SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) |
SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG)));
-
- if ((ah->ah_sc->imask & ATH9K_INT_GENTIMER) == 0) {
- ath9k_hw_set_interrupts(ah, 0);
- ah->ah_sc->imask |= ATH9K_INT_GENTIMER;
- ath9k_hw_set_interrupts(ah, ah->ah_sc->imask);
- }
}
+EXPORT_SYMBOL(ath9k_hw_gen_timer_start);
-void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
+void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
{
struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
@@ -4285,14 +4300,8 @@ void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG)));
clear_bit(timer->index, &timer_table->timer_mask.timer_bits);
-
- /* if no timer is enabled, turn off interrupt mask */
- if (timer_table->timer_mask.val == 0) {
- ath9k_hw_set_interrupts(ah, 0);
- ah->ah_sc->imask &= ~ATH9K_INT_GENTIMER;
- ath9k_hw_set_interrupts(ah, ah->ah_sc->imask);
- }
}
+EXPORT_SYMBOL(ath9k_hw_gen_timer_stop);
void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer)
{
@@ -4302,6 +4311,7 @@ void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer)
timer_table->timers[timer->index] = NULL;
kfree(timer);
}
+EXPORT_SYMBOL(ath_gen_timer_free);
/*
* Generic Timer Interrupts handling
@@ -4310,6 +4320,7 @@ void ath_gen_timer_isr(struct ath_hw *ah)
{
struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
struct ath_gen_timer *timer;
+ struct ath_common *common = ath9k_hw_common(ah);
u32 trigger_mask, thresh_mask, index;
/* get hardware generic timer interrupt status */
@@ -4324,8 +4335,8 @@ void ath_gen_timer_isr(struct ath_hw *ah)
index = rightmost_index(timer_table, &thresh_mask);
timer = timer_table->timers[index];
BUG_ON(!timer);
- DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER,
- "TSF overflow for Gen timer %d\n", index);
+ ath_print(common, ATH_DBG_HWTIMER,
+ "TSF overflow for Gen timer %d\n", index);
timer->overflow(timer->arg);
}
@@ -4333,21 +4344,9 @@ void ath_gen_timer_isr(struct ath_hw *ah)
index = rightmost_index(timer_table, &trigger_mask);
timer = timer_table->timers[index];
BUG_ON(!timer);
- DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER,
- "Gen timer[%d] trigger\n", index);
+ ath_print(common, ATH_DBG_HWTIMER,
+ "Gen timer[%d] trigger\n", index);
timer->trigger(timer->arg);
}
}
-
-/*
- * Primitive to disable ASPM
- */
-void ath_pcie_aspm_disable(struct ath_softc *sc)
-{
- struct pci_dev *pdev = to_pci_dev(sc->dev);
- u8 aspm;
-
- pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm);
- aspm &= ~(ATH_PCIE_CAP_LINK_L0S | ATH_PCIE_CAP_LINK_L1);
- pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm);
-}
+EXPORT_SYMBOL(ath_gen_timer_isr);
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index b89234571829..cdaec526db35 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -27,17 +27,24 @@
#include "calib.h"
#include "reg.h"
#include "phy.h"
+#include "btcoex.h"
#include "../regd.h"
+#include "../debug.h"
#define ATHEROS_VENDOR_ID 0x168c
+
#define AR5416_DEVID_PCI 0x0023
#define AR5416_DEVID_PCIE 0x0024
#define AR9160_DEVID_PCI 0x0027
#define AR9280_DEVID_PCI 0x0029
#define AR9280_DEVID_PCIE 0x002a
#define AR9285_DEVID_PCIE 0x002b
+
#define AR5416_AR9100_DEVID 0x000b
+
+#define AR9271_USB 0x9271
+
#define AR_SUBVENDOR_ID_NOG 0x0e11
#define AR_SUBVENDOR_ID_NEW_A 0x7065
#define AR5416_MAGIC 0x19641014
@@ -49,9 +56,18 @@
#define AT9285_COEX3WIRE_SA_SUBSYSID 0x30aa
#define AT9285_COEX3WIRE_DA_SUBSYSID 0x30ab
+#define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1)
+
+#define ATH_DEFAULT_NOISE_FLOOR -95
+
+#define ATH9K_RSSI_BAD 0x80
+
/* Register read/write primitives */
-#define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val))
-#define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg))
+#define REG_WRITE(_ah, _reg, _val) \
+ ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg))
+
+#define REG_READ(_ah, _reg) \
+ ath9k_hw_common(_ah)->ops->read((_ah), (_reg))
#define SM(_v, _f) (((_v) << _f##_S) & _f)
#define MS(_v, _f) (((_v) & _f) >> _f##_S)
@@ -91,7 +107,7 @@
#define AR_GPIO_BIT(_gpio) (1 << (_gpio))
#define BASE_ACTIVATE_DELAY 100
-#define RTC_PLL_SETTLE_DELAY 1000
+#define RTC_PLL_SETTLE_DELAY 100
#define COEF_SCALE_S 24
#define HT40_CHANNEL_CENTER_SHIFT 10
@@ -433,7 +449,8 @@ struct ath_gen_timer_table {
};
struct ath_hw {
- struct ath_softc *ah_sc;
+ struct ieee80211_hw *hw;
+ struct ath_common common;
struct ath9k_hw_version hw_version;
struct ath9k_ops_config config;
struct ath9k_hw_capabilities caps;
@@ -450,7 +467,6 @@ struct ath_hw {
bool sw_mgmt_crypto;
bool is_pciexpress;
- u8 macaddr[ETH_ALEN];
u16 tx_trig_level;
u16 rfsilent;
u32 rfkill_gpio;
@@ -553,8 +569,10 @@ struct ath_hw {
int firpwr[5];
enum ath9k_ani_cmd ani_function;
+ /* Bluetooth coexistance */
+ struct ath_btcoex_hw btcoex_hw;
+
u32 intr_txqs;
- enum ath9k_ht_extprotspacing extprotspacing;
u8 txchainmask;
u8 rxchainmask;
@@ -578,12 +596,24 @@ struct ath_hw {
struct ar5416IniArray iniModesAdditional;
struct ar5416IniArray iniModesRxGain;
struct ar5416IniArray iniModesTxGain;
+ struct ar5416IniArray iniCckfirNormal;
+ struct ar5416IniArray iniCckfirJapan2484;
u32 intr_gen_timer_trigger;
u32 intr_gen_timer_thresh;
struct ath_gen_timer_table hw_gen_timers;
};
+static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
+{
+ return &ah->common;
+}
+
+static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah)
+{
+ return &(ath9k_hw_common(ah)->regulatory);
+}
+
/* Initialization, Detach, Reset */
const char *ath9k_hw_probe(u16 vendorid, u16 devid);
void ath9k_hw_detach(struct ath_hw *ah);
@@ -637,19 +667,20 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit);
void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac);
void ath9k_hw_setopmode(struct ath_hw *ah);
void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1);
-void ath9k_hw_setbssidmask(struct ath_softc *sc);
-void ath9k_hw_write_associd(struct ath_softc *sc);
+void ath9k_hw_setbssidmask(struct ath_hw *ah);
+void ath9k_hw_write_associd(struct ath_hw *ah);
u64 ath9k_hw_gettsf64(struct ath_hw *ah);
void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
void ath9k_hw_reset_tsf(struct ath_hw *ah);
void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting);
bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us);
-void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode);
+void ath9k_hw_set11nmac2040(struct ath_hw *ah);
void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period);
void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
const struct ath9k_beacon_state *bs);
-bool ath9k_hw_setpower(struct ath_hw *ah,
- enum ath9k_power_mode mode);
+
+bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode);
+
void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore, int power_off);
/* Interrupt Handling */
@@ -663,9 +694,12 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
void (*overflow)(void *),
void *arg,
u8 timer_index);
-void ath_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer,
- u32 timer_next, u32 timer_period);
-void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer);
+void ath9k_hw_gen_timer_start(struct ath_hw *ah,
+ struct ath_gen_timer *timer,
+ u32 timer_next,
+ u32 timer_period);
+void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer);
+
void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer);
void ath_gen_timer_isr(struct ath_hw *hw);
u32 ath9k_hw_gettsf32(struct ath_hw *ah);
@@ -674,5 +708,4 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah);
#define ATH_PCIE_CAP_LINK_L0S 1
#define ATH_PCIE_CAP_LINK_L1 2
-void ath_pcie_aspm_disable(struct ath_softc *sc);
#endif
diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h
index 8622265a030a..3ee6658d809b 100644
--- a/drivers/net/wireless/ath/ath9k/initvals.h
+++ b/drivers/net/wireless/ath/ath9k/initvals.h
@@ -21,6 +21,8 @@ static const u32 ar5416Modes[][6] = {
{ 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
{ 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
{ 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf },
+ { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 },
+ { 0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a },
{ 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
{ 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
{ 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
@@ -31,11 +33,11 @@ static const u32 ar5416Modes[][6] = {
{ 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
{ 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
{ 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
- { 0x00009850, 0x6c48b4e0, 0x6c48b4e0, 0x6c48b0de, 0x6c48b0de, 0x6c48b0de },
+ { 0x00009850, 0x6c48b4e0, 0x6d48b4e0, 0x6d48b0de, 0x6c48b0de, 0x6c48b0de },
{ 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
- { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e },
+ { 0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e },
{ 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 },
- { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+ { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
{ 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 },
{ 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
{ 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
@@ -46,10 +48,10 @@ static const u32 ar5416Modes[][6] = {
{ 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
{ 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
{ 0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120 },
- { 0x0000c9bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00 },
+ { 0x000099bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00 },
{ 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
{ 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
- { 0x000099c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c },
+ { 0x000099c8, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c },
{ 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
{ 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
{ 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
@@ -199,7 +201,6 @@ static const u32 ar5416Common[][2] = {
{ 0x00008110, 0x00000168 },
{ 0x00008118, 0x000100aa },
{ 0x0000811c, 0x00003210 },
- { 0x00008120, 0x08f04800 },
{ 0x00008124, 0x00000000 },
{ 0x00008128, 0x00000000 },
{ 0x0000812c, 0x00000000 },
@@ -215,7 +216,6 @@ static const u32 ar5416Common[][2] = {
{ 0x00008178, 0x00000100 },
{ 0x0000817c, 0x00000000 },
{ 0x000081c4, 0x00000000 },
- { 0x000081d0, 0x00003210 },
{ 0x000081ec, 0x00000000 },
{ 0x000081f0, 0x00000000 },
{ 0x000081f4, 0x00000000 },
@@ -246,6 +246,7 @@ static const u32 ar5416Common[][2] = {
{ 0x00008258, 0x00000000 },
{ 0x0000825c, 0x400000ff },
{ 0x00008260, 0x00080922 },
+ { 0x00008264, 0xa8000010 },
{ 0x00008270, 0x00000000 },
{ 0x00008274, 0x40000000 },
{ 0x00008278, 0x003e4180 },
@@ -406,9 +407,9 @@ static const u32 ar5416Common[][2] = {
{ 0x0000a25c, 0x0f0f0f01 },
{ 0x0000a260, 0xdfa91f01 },
{ 0x0000a268, 0x00000000 },
- { 0x0000a26c, 0x0ebae9c6 },
- { 0x0000b26c, 0x0ebae9c6 },
- { 0x0000c26c, 0x0ebae9c6 },
+ { 0x0000a26c, 0x0e79e5c6 },
+ { 0x0000b26c, 0x0e79e5c6 },
+ { 0x0000c26c, 0x0e79e5c6 },
{ 0x0000d270, 0x00820820 },
{ 0x0000a278, 0x1ce739ce },
{ 0x0000a27c, 0x051701ce },
@@ -2551,26 +2552,27 @@ static const u32 ar9280Modes_9280_2[][6] = {
{ 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 },
{ 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
{ 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
- { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+ { 0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e },
{ 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
{ 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
{ 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
{ 0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e },
{ 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
- { 0x00009850, 0x6c4000e2, 0x6c4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 },
+ { 0x00009850, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 },
{ 0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
- { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x3139605e, 0x31395d5e, 0x31395d5e },
+ { 0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e },
{ 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
{ 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
{ 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
{ 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
{ 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
- { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
+ { 0x00009918, 0x0000000a, 0x00000014, 0x00000268, 0x0000000b, 0x00000016 },
{ 0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
{ 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010 },
{ 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
{ 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
{ 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 },
+ { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce },
{ 0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c },
{ 0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00, 0x00000c00 },
{ 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
@@ -2585,8 +2587,10 @@ static const u32 ar9280Modes_9280_2[][6] = {
{ 0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 },
{ 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
{ 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+ { 0x0000a23c, 0x13c88000, 0x13c88000, 0x13c88001, 0x13c88000, 0x13c88000 },
{ 0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000 },
{ 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
+ { 0x0000a388, 0x0c000000, 0x0c000000, 0x08000000, 0x0c000000, 0x0c000000 },
{ 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 },
};
@@ -2813,7 +2817,6 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00009958, 0x2108ecff },
{ 0x00009940, 0x14750604 },
{ 0x0000c95c, 0x004b6a8e },
- { 0x0000c968, 0x000003ce },
{ 0x00009970, 0x190fb515 },
{ 0x00009974, 0x00000000 },
{ 0x00009978, 0x00000001 },
@@ -2849,7 +2852,6 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x0000a22c, 0x233f7180 },
{ 0x0000a234, 0x20202020 },
{ 0x0000a238, 0x20202020 },
- { 0x0000a23c, 0x13c88000 },
{ 0x0000a240, 0x38490a20 },
{ 0x0000a244, 0x00007bb6 },
{ 0x0000a248, 0x0fff3ffc },
@@ -2859,8 +2861,8 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x0000a25c, 0x0f0f0f01 },
{ 0x0000a260, 0xdfa91f01 },
{ 0x0000a268, 0x00000000 },
- { 0x0000a26c, 0x0ebae9c6 },
- { 0x0000b26c, 0x0ebae9c6 },
+ { 0x0000a26c, 0x0e79e5c6 },
+ { 0x0000b26c, 0x0e79e5c6 },
{ 0x0000d270, 0x00820820 },
{ 0x0000a278, 0x1ce739ce },
{ 0x0000d35c, 0x07ffffef },
@@ -2874,7 +2876,6 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x0000d37c, 0x7fffffe2 },
{ 0x0000d380, 0x7f3c7bba },
{ 0x0000d384, 0xf3307ff0 },
- { 0x0000a388, 0x0c000000 },
{ 0x0000a38c, 0x20202020 },
{ 0x0000a390, 0x20202020 },
{ 0x0000a394, 0x1ce739ce },
@@ -2940,7 +2941,7 @@ static const u32 ar9280Modes_fast_clock_9280_2[][3] = {
{ 0x0000801c, 0x148ec02b, 0x148ec057 },
{ 0x00008318, 0x000044c0, 0x00008980 },
{ 0x00009820, 0x02020200, 0x02020200 },
- { 0x00009824, 0x00000f0f, 0x00000f0f },
+ { 0x00009824, 0x01000f0f, 0x01000f0f },
{ 0x00009828, 0x0b020001, 0x0b020001 },
{ 0x00009834, 0x00000f0f, 0x00000f0f },
{ 0x00009844, 0x03721821, 0x03721821 },
@@ -3348,6 +3349,8 @@ static const u32 ar9280Modes_backoff_13db_rxgain_9280_2[][6] = {
};
static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = {
+ { 0x0000a274, 0x0a19e652, 0x0a19e652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
+ { 0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce },
{ 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x0000a304, 0x00003002, 0x00003002, 0x00004002, 0x00004002, 0x00004002 },
{ 0x0000a308, 0x00006004, 0x00006004, 0x00007008, 0x00007008, 0x00007008 },
@@ -3376,11 +3379,11 @@ static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = {
{ 0x00007840, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000 },
{ 0x00007820, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480 },
{ 0x00007844, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480 },
- { 0x0000a274, 0x0a19e652, 0x0a19e652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
- { 0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce },
};
static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = {
+ { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
+ { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce },
{ 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 },
{ 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 },
@@ -3409,8 +3412,6 @@ static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = {
{ 0x00007840, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000 },
{ 0x00007820, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480 },
{ 0x00007844, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480 },
- { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
- { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce },
};
static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = {
@@ -5918,9 +5919,6 @@ static const u_int32_t ar9287Common_9287_1_1[][2] = {
{ 0x000099ec, 0x0cc80caa },
{ 0x000099f0, 0x00000000 },
{ 0x000099fc, 0x00001042 },
- { 0x0000a1f4, 0x00fffeff },
- { 0x0000a1f8, 0x00f5f9ff },
- { 0x0000a1fc, 0xb79f6427 },
{ 0x0000a208, 0x803e4788 },
{ 0x0000a210, 0x4080a333 },
{ 0x0000a214, 0x40206c10 },
@@ -5980,7 +5978,7 @@ static const u_int32_t ar9287Common_9287_1_1[][2] = {
{ 0x0000b3f4, 0x00000000 },
{ 0x0000a7d8, 0x000003f1 },
{ 0x00007800, 0x00000800 },
- { 0x00007804, 0x6c35ffc2 },
+ { 0x00007804, 0x6c35ffd2 },
{ 0x00007808, 0x6db6c000 },
{ 0x0000780c, 0x6db6cb30 },
{ 0x00007810, 0x6db6cb6c },
@@ -6000,7 +5998,7 @@ static const u_int32_t ar9287Common_9287_1_1[][2] = {
{ 0x00007848, 0x934934a8 },
{ 0x00007850, 0x00000000 },
{ 0x00007854, 0x00000800 },
- { 0x00007858, 0x6c35ffc2 },
+ { 0x00007858, 0x6c35ffd2 },
{ 0x0000785c, 0x6db6c000 },
{ 0x00007860, 0x6db6cb30 },
{ 0x00007864, 0x6db6cb6c },
@@ -6027,6 +6025,22 @@ static const u_int32_t ar9287Common_9287_1_1[][2] = {
{ 0x000078b8, 0x2a850160 },
};
+/*
+ * For Japanese regulatory requirements, 2484 MHz requires the following three
+ * registers be programmed differently from the channel between 2412 and 2472 MHz.
+ */
+static const u_int32_t ar9287Common_normal_cck_fir_coeff_92871_1[][2] = {
+ { 0x0000a1f4, 0x00fffeff },
+ { 0x0000a1f8, 0x00f5f9ff },
+ { 0x0000a1fc, 0xb79f6427 },
+};
+
+static const u_int32_t ar9287Common_japan_2484_cck_fir_coeff_92871_1[][2] = {
+ { 0x0000a1f4, 0x00000000 },
+ { 0x0000a1f8, 0xefff0301 },
+ { 0x0000a1fc, 0xca9228ee },
+};
+
static const u_int32_t ar9287Modes_tx_gain_9287_1_1[][6] = {
/* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
{ 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 800bfab94635..46466ffebcb0 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -14,16 +14,16 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "ath9k.h"
+#include "hw.h"
static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
struct ath9k_tx_queue_info *qi)
{
- DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
- "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
- ah->txok_interrupt_mask, ah->txerr_interrupt_mask,
- ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
- ah->txurn_interrupt_mask);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_INTERRUPT,
+ "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
+ ah->txok_interrupt_mask, ah->txerr_interrupt_mask,
+ ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
+ ah->txurn_interrupt_mask);
REG_WRITE(ah, AR_IMR_S0,
SM(ah->txok_interrupt_mask, AR_IMR_S0_QCU_TXOK)
@@ -39,17 +39,21 @@ u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q)
{
return REG_READ(ah, AR_QTXDP(q));
}
+EXPORT_SYMBOL(ath9k_hw_gettxbuf);
void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp)
{
REG_WRITE(ah, AR_QTXDP(q), txdp);
}
+EXPORT_SYMBOL(ath9k_hw_puttxbuf);
void ath9k_hw_txstart(struct ath_hw *ah, u32 q)
{
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Enable TXE on queue: %u\n", q);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_QUEUE,
+ "Enable TXE on queue: %u\n", q);
REG_WRITE(ah, AR_Q_TXE, 1 << q);
}
+EXPORT_SYMBOL(ath9k_hw_txstart);
u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q)
{
@@ -64,6 +68,7 @@ u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q)
return npend;
}
+EXPORT_SYMBOL(ath9k_hw_numtxpending);
bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
{
@@ -93,27 +98,28 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
return newLevel != curLevel;
}
+EXPORT_SYMBOL(ath9k_hw_updatetxtriglevel);
bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
{
#define ATH9K_TX_STOP_DMA_TIMEOUT 4000 /* usec */
#define ATH9K_TIME_QUANTUM 100 /* usec */
-
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath9k_tx_queue_info *qi;
u32 tsfLow, j, wait;
u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
if (q >= pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, "
- "invalid queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Stopping TX DMA, "
+ "invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, "
- "inactive queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Stopping TX DMA, "
+ "inactive queue: %u\n", q);
return false;
}
@@ -126,9 +132,9 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
}
if (ath9k_hw_numtxpending(ah, q)) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
- "%s: Num of pending TX Frames %d on Q %d\n",
- __func__, ath9k_hw_numtxpending(ah, q), q);
+ ath_print(common, ATH_DBG_QUEUE,
+ "%s: Num of pending TX Frames %d on Q %d\n",
+ __func__, ath9k_hw_numtxpending(ah, q), q);
for (j = 0; j < 2; j++) {
tsfLow = REG_READ(ah, AR_TSF_L32);
@@ -142,9 +148,9 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10))
break;
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
- "TSF has moved while trying to set "
- "quiet time TSF: 0x%08x\n", tsfLow);
+ ath_print(common, ATH_DBG_QUEUE,
+ "TSF has moved while trying to set "
+ "quiet time TSF: 0x%08x\n", tsfLow);
}
REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
@@ -155,9 +161,9 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
wait = wait_time;
while (ath9k_hw_numtxpending(ah, q)) {
if ((--wait) == 0) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
- "Failed to stop TX DMA in 100 "
- "msec after killing last frame\n");
+ ath_print(common, ATH_DBG_QUEUE,
+ "Failed to stop TX DMA in 100 "
+ "msec after killing last frame\n");
break;
}
udelay(ATH9K_TIME_QUANTUM);
@@ -172,6 +178,7 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
#undef ATH9K_TX_STOP_DMA_TIMEOUT
#undef ATH9K_TIME_QUANTUM
}
+EXPORT_SYMBOL(ath9k_hw_stoptxdma);
void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
u32 segLen, bool firstSeg,
@@ -198,6 +205,7 @@ void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
}
+EXPORT_SYMBOL(ath9k_hw_filltxdesc);
void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds)
{
@@ -209,6 +217,7 @@ void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds)
ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
}
+EXPORT_SYMBOL(ath9k_hw_cleartxdesc);
int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds)
{
@@ -284,6 +293,7 @@ int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds)
return 0;
}
+EXPORT_SYMBOL(ath9k_hw_txprocdesc);
void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds,
u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
@@ -319,6 +329,7 @@ void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds,
ads->ds_ctl11 = 0;
}
}
+EXPORT_SYMBOL(ath9k_hw_set11n_txdesc);
void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds,
struct ath_desc *lastds,
@@ -374,6 +385,7 @@ void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds,
last_ads->ds_ctl2 = ads->ds_ctl2;
last_ads->ds_ctl3 = ads->ds_ctl3;
}
+EXPORT_SYMBOL(ath9k_hw_set11n_ratescenario);
void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds,
u32 aggrLen)
@@ -384,6 +396,7 @@ void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds,
ads->ds_ctl6 &= ~AR_AggrLen;
ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
}
+EXPORT_SYMBOL(ath9k_hw_set11n_aggr_first);
void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds,
u32 numDelims)
@@ -398,6 +411,7 @@ void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds,
ctl6 |= SM(numDelims, AR_PadDelim);
ads->ds_ctl6 = ctl6;
}
+EXPORT_SYMBOL(ath9k_hw_set11n_aggr_middle);
void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds)
{
@@ -407,6 +421,7 @@ void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds)
ads->ds_ctl1 &= ~AR_MoreAggr;
ads->ds_ctl6 &= ~AR_PadDelim;
}
+EXPORT_SYMBOL(ath9k_hw_set11n_aggr_last);
void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds)
{
@@ -414,6 +429,7 @@ void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds)
ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
}
+EXPORT_SYMBOL(ath9k_hw_clr11n_aggr);
void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds,
u32 burstDuration)
@@ -423,6 +439,7 @@ void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds,
ads->ds_ctl2 &= ~AR_BurstDur;
ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
}
+EXPORT_SYMBOL(ath9k_hw_set11n_burstduration);
void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds,
u32 vmf)
@@ -440,28 +457,30 @@ void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs)
*txqs &= ah->intr_txqs;
ah->intr_txqs &= ~(*txqs);
}
+EXPORT_SYMBOL(ath9k_hw_gettxintrtxqs);
bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
const struct ath9k_tx_queue_info *qinfo)
{
u32 cw;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath9k_tx_queue_info *qi;
if (q >= pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, "
- "invalid queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Set TXQ properties, "
+ "invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, "
- "inactive queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Set TXQ properties, "
+ "inactive queue: %u\n", q);
return false;
}
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q);
qi->tqi_ver = qinfo->tqi_ver;
qi->tqi_subtype = qinfo->tqi_subtype;
@@ -510,23 +529,25 @@ bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
return true;
}
+EXPORT_SYMBOL(ath9k_hw_set_txq_props);
bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
struct ath9k_tx_queue_info *qinfo)
{
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath9k_tx_queue_info *qi;
if (q >= pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, "
- "invalid queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Get TXQ properties, "
+ "invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, "
- "inactive queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Get TXQ properties, "
+ "inactive queue: %u\n", q);
return false;
}
@@ -547,10 +568,12 @@ bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
return true;
}
+EXPORT_SYMBOL(ath9k_hw_get_txq_props);
int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
const struct ath9k_tx_queue_info *qinfo)
{
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_tx_queue_info *qi;
struct ath9k_hw_capabilities *pCap = &ah->caps;
int q;
@@ -574,23 +597,23 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
ATH9K_TX_QUEUE_INACTIVE)
break;
if (q == pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "No available TX queue\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "No available TX queue\n");
return -1;
}
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Invalid TX queue type: %u\n",
- type);
+ ath_print(common, ATH_DBG_FATAL,
+ "Invalid TX queue type: %u\n", type);
return -1;
}
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q);
qi = &ah->txq[q];
if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "TX queue: %u already active\n", q);
+ ath_print(common, ATH_DBG_FATAL,
+ "TX queue: %u already active\n", q);
return -1;
}
memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
@@ -613,25 +636,27 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
return q;
}
+EXPORT_SYMBOL(ath9k_hw_setuptxqueue);
bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
{
struct ath9k_hw_capabilities *pCap = &ah->caps;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_tx_queue_info *qi;
if (q >= pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, "
- "invalid queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Release TXQ, "
+ "invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, "
- "inactive queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Release TXQ, "
+ "inactive queue: %u\n", q);
return false;
}
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TX queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Release TX queue: %u\n", q);
qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
ah->txok_interrupt_mask &= ~(1 << q);
@@ -643,28 +668,30 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
return true;
}
+EXPORT_SYMBOL(ath9k_hw_releasetxqueue);
bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
{
struct ath9k_hw_capabilities *pCap = &ah->caps;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_channel *chan = ah->curchan;
struct ath9k_tx_queue_info *qi;
u32 cwMin, chanCwMin, value;
if (q >= pCap->total_queues) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, "
- "invalid queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Reset TXQ, "
+ "invalid queue: %u\n", q);
return false;
}
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, "
- "inactive queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Reset TXQ, "
+ "inactive queue: %u\n", q);
return true;
}
- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q);
+ ath_print(common, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q);
if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
if (chan && IS_CHAN_B(chan))
@@ -799,6 +826,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
return true;
}
+EXPORT_SYMBOL(ath9k_hw_resettxqueue);
int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
u32 pa, struct ath_desc *nds, u64 tsf)
@@ -880,6 +908,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
return 0;
}
+EXPORT_SYMBOL(ath9k_hw_rxprocdesc);
void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
u32 size, u32 flags)
@@ -895,6 +924,7 @@ void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
memset(&(ads->u), 0, sizeof(ads->u));
}
+EXPORT_SYMBOL(ath9k_hw_setuprxdesc);
bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
{
@@ -911,8 +941,9 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
AR_DIAG_RX_ABORT));
reg = REG_READ(ah, AR_OBS_BUS_1);
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "RX failed to go idle in 10 ms RXSM=0x%x\n", reg);
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "RX failed to go idle in 10 ms RXSM=0x%x\n",
+ reg);
return false;
}
@@ -923,16 +954,19 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
return true;
}
+EXPORT_SYMBOL(ath9k_hw_setrxabort);
void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp)
{
REG_WRITE(ah, AR_RXDP, rxdp);
}
+EXPORT_SYMBOL(ath9k_hw_putrxbuf);
void ath9k_hw_rxena(struct ath_hw *ah)
{
REG_WRITE(ah, AR_CR, AR_CR_RXE);
}
+EXPORT_SYMBOL(ath9k_hw_rxena);
void ath9k_hw_startpcureceive(struct ath_hw *ah)
{
@@ -942,6 +976,7 @@ void ath9k_hw_startpcureceive(struct ath_hw *ah)
REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
}
+EXPORT_SYMBOL(ath9k_hw_startpcureceive);
void ath9k_hw_stoppcurecv(struct ath_hw *ah)
{
@@ -949,12 +984,13 @@ void ath9k_hw_stoppcurecv(struct ath_hw *ah)
ath9k_hw_disable_mib_counters(ah);
}
+EXPORT_SYMBOL(ath9k_hw_stoppcurecv);
bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
{
#define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */
#define AH_RX_TIME_QUANTUM 100 /* usec */
-
+ struct ath_common *common = ath9k_hw_common(ah);
int i;
REG_WRITE(ah, AR_CR, AR_CR_RXD);
@@ -967,12 +1003,12 @@ bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
}
if (i == 0) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "DMA failed to stop in %d ms "
- "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
- AH_RX_STOP_DMA_TIMEOUT / 1000,
- REG_READ(ah, AR_CR),
- REG_READ(ah, AR_DIAG_SW));
+ ath_print(common, ATH_DBG_FATAL,
+ "DMA failed to stop in %d ms "
+ "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
+ AH_RX_STOP_DMA_TIMEOUT / 1000,
+ REG_READ(ah, AR_CR),
+ REG_READ(ah, AR_DIAG_SW));
return false;
} else {
return true;
@@ -981,3 +1017,17 @@ bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
#undef AH_RX_TIME_QUANTUM
#undef AH_RX_STOP_DMA_TIMEOUT
}
+EXPORT_SYMBOL(ath9k_hw_stopdmarecv);
+
+int ath9k_hw_beaconq_setup(struct ath_hw *ah)
+{
+ struct ath9k_tx_queue_info qi;
+
+ memset(&qi, 0, sizeof(qi));
+ qi.tqi_aifs = 1;
+ qi.tqi_cwmin = 0;
+ qi.tqi_cwmax = 0;
+ /* NB: don't enable any interrupts */
+ return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
+}
+EXPORT_SYMBOL(ath9k_hw_beaconq_setup);
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index f56e77da6c3e..fefb65dafb1c 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -614,16 +614,6 @@ enum ath9k_cipher {
ATH9K_CIPHER_MIC = 127
};
-enum ath9k_ht_macmode {
- ATH9K_HT_MACMODE_20 = 0,
- ATH9K_HT_MACMODE_2040 = 1,
-};
-
-enum ath9k_ht_extprotspacing {
- ATH9K_HT_EXTPROTSPACING_20 = 0,
- ATH9K_HT_EXTPROTSPACING_25 = 1,
-};
-
struct ath_hw;
struct ath9k_channel;
struct ath_rate_table;
@@ -677,5 +667,6 @@ void ath9k_hw_rxena(struct ath_hw *ah);
void ath9k_hw_startpcureceive(struct ath_hw *ah);
void ath9k_hw_stoppcurecv(struct ath_hw *ah);
bool ath9k_hw_stopdmarecv(struct ath_hw *ah);
+int ath9k_hw_beaconq_setup(struct ath_hw *ah);
#endif /* MAC_H */
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 52bed89063d4..69cf702b18c2 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -16,6 +16,7 @@
#include <linux/nl80211.h>
#include "ath9k.h"
+#include "btcoex.h"
static char *dev_info = "ath9k";
@@ -28,6 +29,10 @@ static int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
+static unsigned int ath9k_debug = ATH_DBG_DEFAULT;
+module_param_named(debug, ath9k_debug, uint, 0);
+MODULE_PARM_DESC(debug, "Debugging mask");
+
/* We use the hw_value as an index into our private channel structure */
#define CHAN2G(_freq, _idx) { \
@@ -224,8 +229,9 @@ static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band)
}
sband->n_bitrates++;
- DPRINTF(sc, ATH_DBG_CONFIG, "Rate: %2dMbps, ratecode: %2d\n",
- rate[i].bitrate / 10, rate[i].hw_value);
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
+ "Rate: %2dMbps, ratecode: %2d\n",
+ rate[i].bitrate / 10, rate[i].hw_value);
}
}
@@ -242,6 +248,51 @@ static struct ath9k_channel *ath_get_curchannel(struct ath_softc *sc,
return channel;
}
+static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode)
+{
+ unsigned long flags;
+ bool ret;
+
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
+ ret = ath9k_hw_setpower(sc->sc_ah, mode);
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+
+ return ret;
+}
+
+void ath9k_ps_wakeup(struct ath_softc *sc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
+ if (++sc->ps_usecount != 1)
+ goto unlock;
+
+ ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
+
+ unlock:
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+}
+
+void ath9k_ps_restore(struct ath_softc *sc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
+ if (--sc->ps_usecount != 0)
+ goto unlock;
+
+ if (sc->ps_enabled &&
+ !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
+ SC_OP_WAIT_FOR_CAB |
+ SC_OP_WAIT_FOR_PSPOLL_DATA |
+ SC_OP_WAIT_FOR_TX_ACK)))
+ ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
+
+ unlock:
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+}
+
/*
* 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
@@ -251,6 +302,8 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
struct ath9k_channel *hchan)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ieee80211_conf *conf = &common->hw->conf;
bool fastcc = true, stopped;
struct ieee80211_channel *channel = hw->conf.channel;
int r;
@@ -280,19 +333,19 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET))
fastcc = false;
- DPRINTF(sc, ATH_DBG_CONFIG,
- "(%u MHz) -> (%u MHz), chanwidth: %d\n",
- sc->sc_ah->curchan->channel,
- channel->center_freq, sc->tx_chan_width);
+ ath_print(common, ATH_DBG_CONFIG,
+ "(%u MHz) -> (%u MHz), conf_is_ht40: %d\n",
+ sc->sc_ah->curchan->channel,
+ channel->center_freq, conf_is_ht40(conf));
spin_lock_bh(&sc->sc_resetlock);
r = ath9k_hw_reset(ah, hchan, fastcc);
if (r) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to reset channel (%u Mhz) "
- "reset status %d\n",
- channel->center_freq, r);
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to reset channel (%u Mhz) "
+ "reset status %d\n",
+ channel->center_freq, r);
spin_unlock_bh(&sc->sc_resetlock);
goto ps_restore;
}
@@ -301,8 +354,8 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
sc->sc_flags &= ~SC_OP_FULL_RESET;
if (ath_startrecv(sc) != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to restart recv logic\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to restart recv logic\n");
r = -EIO;
goto ps_restore;
}
@@ -327,6 +380,7 @@ static void ath_ani_calibrate(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
bool longcal = false;
bool shortcal = false;
bool aniflag = false;
@@ -353,7 +407,7 @@ static void ath_ani_calibrate(unsigned long data)
/* Long calibration runs independently of short calibration. */
if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
longcal = true;
- DPRINTF(sc, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
+ ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
sc->ani.longcal_timer = timestamp;
}
@@ -361,7 +415,8 @@ static void ath_ani_calibrate(unsigned long data)
if (!sc->ani.caldone) {
if ((timestamp - sc->ani.shortcal_timer) >= short_cal_interval) {
shortcal = true;
- DPRINTF(sc, ATH_DBG_ANI, "shortcal @%lu\n", jiffies);
+ ath_print(common, ATH_DBG_ANI,
+ "shortcal @%lu\n", jiffies);
sc->ani.shortcal_timer = timestamp;
sc->ani.resetcal_timer = timestamp;
}
@@ -388,16 +443,21 @@ static void ath_ani_calibrate(unsigned long data)
/* Perform calibration if necessary */
if (longcal || shortcal) {
- sc->ani.caldone = ath9k_hw_calibrate(ah, ah->curchan,
- sc->rx_chainmask, longcal);
+ sc->ani.caldone =
+ ath9k_hw_calibrate(ah,
+ ah->curchan,
+ common->rx_chainmask,
+ longcal);
if (longcal)
sc->ani.noise_floor = ath9k_hw_getchan_noise(ah,
ah->curchan);
- DPRINTF(sc, ATH_DBG_ANI," calibrate chan %u/%x nf: %d\n",
- ah->curchan->channel, ah->curchan->channelFlags,
- sc->ani.noise_floor);
+ ath_print(common, ATH_DBG_ANI,
+ " calibrate chan %u/%x nf: %d\n",
+ ah->curchan->channel,
+ ah->curchan->channelFlags,
+ sc->ani.noise_floor);
}
}
@@ -439,17 +499,22 @@ static void ath_start_ani(struct ath_softc *sc)
*/
void ath_update_chainmask(struct ath_softc *sc, int is_ht)
{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+
if ((sc->sc_flags & SC_OP_SCANNING) || is_ht ||
- (sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE)) {
- sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask;
- sc->rx_chainmask = sc->sc_ah->caps.rx_chainmask;
+ (ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE)) {
+ common->tx_chainmask = ah->caps.tx_chainmask;
+ common->rx_chainmask = ah->caps.rx_chainmask;
} else {
- sc->tx_chainmask = 1;
- sc->rx_chainmask = 1;
+ common->tx_chainmask = 1;
+ common->rx_chainmask = 1;
}
- DPRINTF(sc, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n",
- sc->tx_chainmask, sc->rx_chainmask);
+ ath_print(common, ATH_DBG_CONFIG,
+ "tx chmask: %d, rx chmask: %d\n",
+ common->tx_chainmask,
+ common->rx_chainmask);
}
static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
@@ -478,6 +543,9 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
static void ath9k_tasklet(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+
u32 status = sc->intrstatus;
ath9k_ps_wakeup(sc);
@@ -502,16 +570,17 @@ static void ath9k_tasklet(unsigned long data)
* TSF sync does not look correct; remain awake to sync with
* the next Beacon.
*/
- DPRINTF(sc, ATH_DBG_PS, "TSFOOR - Sync with next Beacon\n");
+ ath_print(common, ATH_DBG_PS,
+ "TSFOOR - Sync with next Beacon\n");
sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC;
}
- if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
+ if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
if (status & ATH9K_INT_GENTIMER)
ath_gen_timer_isr(sc->sc_ah);
/* re-enable hardware interrupt */
- ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
+ ath9k_hw_set_interrupts(ah, sc->imask);
ath9k_ps_restore(sc);
}
@@ -602,7 +671,7 @@ irqreturn_t ath_isr(int irq, void *dev)
if (status & ATH9K_INT_TIM_TIMER) {
/* Clear RxAbort bit so that we can
* receive frames */
- ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
+ ath9k_setpower(sc, ATH9K_PM_AWAKE);
ath9k_hw_setrxabort(sc->sc_ah, 0);
sc->sc_flags |= SC_OP_WAIT_FOR_BEACON;
}
@@ -702,8 +771,8 @@ static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key,
memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
if (!ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, NULL)) {
/* TX MIC entry failed. No need to proceed further */
- DPRINTF(sc, ATH_DBG_FATAL,
- "Setting TX MIC Key Failed\n");
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "Setting TX MIC Key Failed\n");
return 0;
}
@@ -890,6 +959,7 @@ static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key)
static void setup_ht_cap(struct ath_softc *sc,
struct ieee80211_sta_ht_cap *ht_info)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
u8 tx_streams, rx_streams;
ht_info->ht_supported = true;
@@ -903,12 +973,15 @@ static void setup_ht_cap(struct ath_softc *sc,
/* set up supported mcs set */
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
- tx_streams = !(sc->tx_chainmask & (sc->tx_chainmask - 1)) ? 1 : 2;
- rx_streams = !(sc->rx_chainmask & (sc->rx_chainmask - 1)) ? 1 : 2;
+ tx_streams = !(common->tx_chainmask & (common->tx_chainmask - 1)) ?
+ 1 : 2;
+ rx_streams = !(common->rx_chainmask & (common->rx_chainmask - 1)) ?
+ 1 : 2;
if (tx_streams != rx_streams) {
- DPRINTF(sc, ATH_DBG_CONFIG, "TX streams %d, RX streams: %d\n",
- tx_streams, rx_streams);
+ ath_print(common, ATH_DBG_CONFIG,
+ "TX streams %d, RX streams: %d\n",
+ tx_streams, rx_streams);
ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
ht_info->mcs.tx_params |= ((tx_streams - 1) <<
IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
@@ -925,14 +998,17 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf)
{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
if (bss_conf->assoc) {
- DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n",
- bss_conf->aid, sc->curbssid);
+ ath_print(common, ATH_DBG_CONFIG,
+ "Bss Info ASSOC %d, bssid: %pM\n",
+ bss_conf->aid, common->curbssid);
/* New association, store aid */
- sc->curaid = bss_conf->aid;
- ath9k_hw_write_associd(sc);
+ common->curaid = bss_conf->aid;
+ ath9k_hw_write_associd(ah);
/*
* Request a re-configuration of Beacon related timers
@@ -949,8 +1025,8 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
ath_start_ani(sc);
} else {
- DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
- sc->curaid = 0;
+ ath_print(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
+ common->curaid = 0;
/* Stop ANI */
del_timer_sync(&sc->ani.timer);
}
@@ -1042,8 +1118,8 @@ static int ath_register_led(struct ath_softc *sc, struct ath_led *led,
ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev);
if (ret)
- DPRINTF(sc, ATH_DBG_FATAL,
- "Failed to register led:%s", led->name);
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "Failed to register led:%s", led->name);
else
led->registered = 1;
return ret;
@@ -1127,6 +1203,7 @@ fail:
void ath_radio_enable(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_channel *channel = sc->hw->conf.channel;
int r;
@@ -1139,17 +1216,17 @@ void ath_radio_enable(struct ath_softc *sc)
spin_lock_bh(&sc->sc_resetlock);
r = ath9k_hw_reset(ah, ah->curchan, false);
if (r) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to reset channel %u (%uMhz) ",
- "reset status %d\n",
- channel->center_freq, r);
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to reset channel %u (%uMhz) ",
+ "reset status %d\n",
+ channel->center_freq, r);
}
spin_unlock_bh(&sc->sc_resetlock);
ath_update_txpow(sc);
if (ath_startrecv(sc) != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to restart recv logic\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to restart recv logic\n");
return;
}
@@ -1194,17 +1271,17 @@ void ath_radio_disable(struct ath_softc *sc)
spin_lock_bh(&sc->sc_resetlock);
r = ath9k_hw_reset(ah, ah->curchan, false);
if (r) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to reset channel %u (%uMhz) "
- "reset status %d\n",
- channel->center_freq, r);
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "Unable to reset channel %u (%uMhz) "
+ "reset status %d\n",
+ channel->center_freq, r);
}
spin_unlock_bh(&sc->sc_resetlock);
ath9k_hw_phy_disable(ah);
ath9k_hw_configpcipowersave(ah, 1, 1);
ath9k_ps_restore(sc);
- ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
+ ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
}
/*******************/
@@ -1236,23 +1313,26 @@ static void ath_start_rfkill_poll(struct ath_softc *sc)
wiphy_rfkill_start_polling(sc->hw->wiphy);
}
-void ath_cleanup(struct ath_softc *sc)
+static void ath9k_uninit_hw(struct ath_softc *sc)
{
- ath_detach(sc);
- free_irq(sc->irq, sc);
- ath_bus_cleanup(sc);
- kfree(sc->sec_wiphy);
- ieee80211_free_hw(sc->hw);
+ struct ath_hw *ah = sc->sc_ah;
+
+ BUG_ON(!ah);
+
+ ath9k_exit_debug(ah);
+ ath9k_hw_detach(ah);
+ sc->sc_ah = NULL;
}
-void ath_detach(struct ath_softc *sc)
+static void ath_clean_core(struct ath_softc *sc)
{
struct ieee80211_hw *hw = sc->hw;
+ struct ath_hw *ah = sc->sc_ah;
int i = 0;
ath9k_ps_wakeup(sc);
- DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n");
+ dev_dbg(sc->dev, "Detach ATH hw\n");
ath_deinit_leds(sc);
wiphy_rfkill_stop_polling(sc->hw->wiphy);
@@ -1273,20 +1353,36 @@ void ath_detach(struct ath_softc *sc)
tasklet_kill(&sc->bcon_tasklet);
if (!(sc->sc_flags & SC_OP_INVALID))
- ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
+ ath9k_setpower(sc, ATH9K_PM_AWAKE);
/* cleanup tx queues */
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
if (ATH_TXQ_SETUP(sc, i))
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
- if ((sc->btcoex_info.no_stomp_timer) &&
- sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
- ath_gen_timer_free(sc->sc_ah, sc->btcoex_info.no_stomp_timer);
+ if ((sc->btcoex.no_stomp_timer) &&
+ ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
+ ath_gen_timer_free(ah, sc->btcoex.no_stomp_timer);
+}
- ath9k_hw_detach(sc->sc_ah);
- sc->sc_ah = NULL;
- ath9k_exit_debug(sc);
+void ath_detach(struct ath_softc *sc)
+{
+ ath_clean_core(sc);
+ ath9k_uninit_hw(sc);
+}
+
+void ath_cleanup(struct ath_softc *sc)
+{
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ ath_clean_core(sc);
+ free_irq(sc->irq, sc);
+ ath_bus_cleanup(common);
+ kfree(sc->sec_wiphy);
+ ieee80211_free_hw(sc->hw);
+
+ ath9k_uninit_hw(sc);
}
static int ath9k_reg_notifier(struct wiphy *wiphy,
@@ -1295,29 +1391,245 @@ static int ath9k_reg_notifier(struct wiphy *wiphy,
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
- struct ath_regulatory *reg = &sc->common.regulatory;
+ struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah);
return ath_reg_notifier_apply(wiphy, request, reg);
}
/*
+ * Detects if there is any priority bt traffic
+ */
+static void ath_detect_bt_priority(struct ath_softc *sc)
+{
+ struct ath_btcoex *btcoex = &sc->btcoex;
+ struct ath_hw *ah = sc->sc_ah;
+
+ if (ath9k_hw_gpio_get(sc->sc_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))) {
+ if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX,
+ "BT priority traffic detected");
+ sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
+ } else {
+ sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
+ }
+
+ btcoex->bt_priority_cnt = 0;
+ btcoex->bt_priority_time = jiffies;
+ }
+}
+
+/*
+ * 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,
+ u32 timer_period)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+
+ ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period);
+
+ if ((sc->imask & ATH9K_INT_GENTIMER) == 0) {
+ ath9k_hw_set_interrupts(ah, 0);
+ sc->imask |= ATH9K_INT_GENTIMER;
+ ath9k_hw_set_interrupts(ah, sc->imask);
+ }
+}
+
+static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+ struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
+
+ ath9k_hw_gen_timer_stop(ah, timer);
+
+ /* if no timer is enabled, turn off interrupt mask */
+ if (timer_table->timer_mask.val == 0) {
+ ath9k_hw_set_interrupts(ah, 0);
+ sc->imask &= ~ATH9K_INT_GENTIMER;
+ ath9k_hw_set_interrupts(ah, sc->imask);
+ }
+}
+
+/*
+ * This is the master bt coex timer 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_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;
+
+ ath_detect_bt_priority(sc);
+
+ spin_lock_bh(&btcoex->btcoex_lock);
+
+ ath9k_btcoex_bt_stomp(sc, btcoex->bt_stomp_type);
+
+ spin_unlock_bh(&btcoex->btcoex_lock);
+
+ if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) {
+ if (btcoex->hw_timer_enabled)
+ ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
+
+ ath9k_gen_timer_start(ah,
+ btcoex->no_stomp_timer,
+ (ath9k_hw_gettsf32(ah) +
+ btcoex->btcoex_no_stomp),
+ btcoex->btcoex_no_stomp * 10);
+ btcoex->hw_timer_enabled = true;
+ }
+
+ mod_timer(&btcoex->period_timer, jiffies +
+ msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
+}
+
+/*
+ * Generic tsf based hw timer which configures weight
+ * registers to time slice between wlan and bt traffic
+ */
+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;
+
+ ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+ "no stomp timer running \n");
+
+ spin_lock_bh(&btcoex->btcoex_lock);
+
+ if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW)
+ ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE);
+ else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
+ ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW);
+
+ spin_unlock_bh(&btcoex->btcoex_lock);
+}
+
+static int ath_init_btcoex_timer(struct ath_softc *sc)
+{
+ struct ath_btcoex *btcoex = &sc->btcoex;
+
+ btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
+ btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
+ btcoex->btcoex_period / 100;
+
+ setup_timer(&btcoex->period_timer, ath_btcoex_period_timer,
+ (unsigned long) sc);
+
+ spin_lock_init(&btcoex->btcoex_lock);
+
+ btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah,
+ ath_btcoex_no_stomp_timer,
+ ath_btcoex_no_stomp_timer,
+ (void *) sc, AR_FIRST_NDP_TIMER);
+
+ if (!btcoex->no_stomp_timer)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/*
+ * Read and write, they both share the same lock. We do this to serialize
+ * reads and writes on Atheros 802.11n PCI devices only. This is required
+ * as the FIFO on these devices can only accept sanely 2 requests. After
+ * that the device goes bananas. Serializing the reads/writes prevents this
+ * from happening.
+ */
+
+static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset)
+{
+ struct ath_hw *ah = (struct ath_hw *) hw_priv;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+
+ if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
+ unsigned long flags;
+ spin_lock_irqsave(&sc->sc_serial_rw, flags);
+ iowrite32(val, sc->mem + reg_offset);
+ spin_unlock_irqrestore(&sc->sc_serial_rw, flags);
+ } else
+ iowrite32(val, sc->mem + reg_offset);
+}
+
+static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset)
+{
+ struct ath_hw *ah = (struct ath_hw *) hw_priv;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+ u32 val;
+
+ if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
+ unsigned long flags;
+ spin_lock_irqsave(&sc->sc_serial_rw, flags);
+ val = ioread32(sc->mem + reg_offset);
+ spin_unlock_irqrestore(&sc->sc_serial_rw, flags);
+ } else
+ val = ioread32(sc->mem + reg_offset);
+ return val;
+}
+
+static const struct ath_ops ath9k_common_ops = {
+ .read = ath9k_ioread32,
+ .write = ath9k_iowrite32,
+};
+
+/*
* Initialize and fill ath_softc, ath_sofct is the
* "Software Carrier" struct. Historically it has existed
* to allow the separation between hardware specific
* variables (now in ath_hw) and driver specific variables.
*/
-static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid)
+static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
+ const struct ath_bus_ops *bus_ops)
{
struct ath_hw *ah = NULL;
+ struct ath_common *common;
int r = 0, i;
int csz = 0;
+ int qnum;
/* XXX: hardware will not be ready until ath_open() being called */
sc->sc_flags |= SC_OP_INVALID;
- if (ath9k_init_debug(sc) < 0)
- printk(KERN_ERR "Unable to create debugfs files\n");
-
spin_lock_init(&sc->wiphy_lock);
spin_lock_init(&sc->sc_resetlock);
spin_lock_init(&sc->sc_serial_rw);
@@ -1328,39 +1640,50 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid)
tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
(unsigned long)sc);
- /*
- * Cache line size is used to size and align various
- * structures used to communicate with the hardware.
- */
- ath_read_cachesize(sc, &csz);
- /* XXX assert csz is non-zero */
- sc->common.cachelsz = csz << 2; /* convert to bytes */
-
ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
- if (!ah) {
- r = -ENOMEM;
- goto bad_no_ah;
- }
+ if (!ah)
+ return -ENOMEM;
- ah->ah_sc = sc;
ah->hw_version.devid = devid;
ah->hw_version.subsysid = subsysid;
sc->sc_ah = ah;
+ common = ath9k_hw_common(ah);
+ common->ops = &ath9k_common_ops;
+ common->bus_ops = bus_ops;
+ common->ah = ah;
+ common->hw = sc->hw;
+ common->priv = sc;
+ common->debug_mask = ath9k_debug;
+
+ /*
+ * Cache line size is used to size and align various
+ * structures used to communicate with the hardware.
+ */
+ ath_read_cachesize(common, &csz);
+ /* XXX assert csz is non-zero */
+ common->cachelsz = csz << 2; /* convert to bytes */
+
r = ath9k_hw_init(ah);
if (r) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to initialize hardware; "
- "initialization status: %d\n", r);
- goto bad;
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to initialize hardware; "
+ "initialization status: %d\n", r);
+ goto bad_free_hw;
+ }
+
+ if (ath9k_init_debug(ah) < 0) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to create debugfs files\n");
+ goto bad_free_hw;
}
/* Get the hardware key cache size. */
sc->keymax = ah->caps.keycache_size;
if (sc->keymax > ATH_KEYMAX) {
- DPRINTF(sc, ATH_DBG_ANY,
- "Warning, using only %u entries in %u key cache\n",
- ATH_KEYMAX, sc->keymax);
+ ath_print(common, ATH_DBG_ANY,
+ "Warning, using only %u entries in %u key cache\n",
+ ATH_KEYMAX, sc->keymax);
sc->keymax = ATH_KEYMAX;
}
@@ -1386,17 +1709,17 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid)
* priority. Note that the hal handles reseting
* these queues at the needed time.
*/
- sc->beacon.beaconq = ath_beaconq_setup(ah);
+ sc->beacon.beaconq = ath9k_hw_beaconq_setup(ah);
if (sc->beacon.beaconq == -1) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to setup a beacon xmit queue\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup a beacon xmit queue\n");
r = -EIO;
goto bad2;
}
sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
if (sc->beacon.cabq == NULL) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to setup CAB xmit queue\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup CAB xmit queue\n");
r = -EIO;
goto bad2;
}
@@ -1410,27 +1733,27 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid)
/* Setup data queues */
/* NB: ensure BK queue is the lowest priority h/w queue */
if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to setup xmit queue for BK traffic\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup xmit queue for BK traffic\n");
r = -EIO;
goto bad2;
}
if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to setup xmit queue for BE traffic\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup xmit queue for BE traffic\n");
r = -EIO;
goto bad2;
}
if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to setup xmit queue for VI traffic\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup xmit queue for VI traffic\n");
r = -EIO;
goto bad2;
}
if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to setup xmit queue for VO traffic\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup xmit queue for VO traffic\n");
r = -EIO;
goto bad2;
}
@@ -1480,14 +1803,14 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid)
sc->sc_flags |= SC_OP_RXAGGR;
}
- sc->tx_chainmask = ah->caps.tx_chainmask;
- sc->rx_chainmask = ah->caps.rx_chainmask;
+ common->tx_chainmask = ah->caps.tx_chainmask;
+ common->rx_chainmask = ah->caps.rx_chainmask;
ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
sc->rx.defant = ath9k_hw_getdefantenna(ah);
if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
- memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN);
+ memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */
@@ -1515,10 +1838,24 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid)
ARRAY_SIZE(ath9k_5ghz_chantable);
}
- if (sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) {
- r = ath9k_hw_btcoex_init(ah);
+ switch (ah->btcoex_hw.scheme) {
+ case ATH_BTCOEX_CFG_NONE:
+ break;
+ case ATH_BTCOEX_CFG_2WIRE:
+ ath9k_hw_btcoex_init_2wire(ah);
+ break;
+ case ATH_BTCOEX_CFG_3WIRE:
+ ath9k_hw_btcoex_init_3wire(ah);
+ r = ath_init_btcoex_timer(sc);
if (r)
goto bad2;
+ qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
+ ath9k_hw_init_btcoex_hw(ah, qnum);
+ sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+ break;
+ default:
+ WARN_ON(1);
+ break;
}
return 0;
@@ -1527,12 +1864,9 @@ bad2:
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
if (ATH_TXQ_SETUP(sc, i))
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
-bad:
- ath9k_hw_detach(ah);
- sc->sc_ah = NULL;
-bad_no_ah:
- ath9k_exit_debug(sc);
+bad_free_hw:
+ ath9k_uninit_hw(sc);
return r;
}
@@ -1574,34 +1908,40 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
}
/* Device driver core initialization */
-int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid)
+int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
+ const struct ath_bus_ops *bus_ops)
{
struct ieee80211_hw *hw = sc->hw;
+ struct ath_common *common;
+ struct ath_hw *ah;
int error = 0, i;
struct ath_regulatory *reg;
- DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n");
+ dev_dbg(sc->dev, "Attach ATH hw\n");
- error = ath_init_softc(devid, sc, subsysid);
+ error = ath_init_softc(devid, sc, subsysid, bus_ops);
if (error != 0)
return error;
+ ah = sc->sc_ah;
+ common = ath9k_hw_common(ah);
+
/* get mac address from hardware and set in mac80211 */
- SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr);
+ SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
ath_set_hw_capab(sc, hw);
- error = ath_regd_init(&sc->common.regulatory, sc->hw->wiphy,
+ error = ath_regd_init(&common->regulatory, sc->hw->wiphy,
ath9k_reg_notifier);
if (error)
return error;
- reg = &sc->common.regulatory;
+ reg = &common->regulatory;
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
- if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
+ if (test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes))
setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
}
@@ -1639,9 +1979,7 @@ error_attach:
if (ATH_TXQ_SETUP(sc, i))
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
- ath9k_hw_detach(sc->sc_ah);
- sc->sc_ah = NULL;
- ath9k_exit_debug(sc);
+ ath9k_uninit_hw(sc);
return error;
}
@@ -1649,6 +1987,7 @@ error_attach:
int ath_reset(struct ath_softc *sc, bool retry_tx)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_hw *hw = sc->hw;
int r;
@@ -1660,12 +1999,13 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
spin_lock_bh(&sc->sc_resetlock);
r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false);
if (r)
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to reset hardware; reset status %d\n", r);
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to reset hardware; reset status %d\n", r);
spin_unlock_bh(&sc->sc_resetlock);
if (ath_startrecv(sc) != 0)
- DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to start recv logic\n");
/*
* We may be doing a reset in response to a request
@@ -1708,19 +2048,20 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0)
#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096)
-
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_desc *ds;
struct ath_buf *bf;
int i, bsize, error;
- DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n",
- name, nbuf, ndesc);
+ ath_print(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n",
+ name, nbuf, ndesc);
INIT_LIST_HEAD(head);
/* ath_desc must be a multiple of DWORDs */
if ((sizeof(struct ath_desc) % 4) != 0) {
- DPRINTF(sc, ATH_DBG_FATAL, "ath_desc not DWORD aligned\n");
- ASSERT((sizeof(struct ath_desc) % 4) == 0);
+ ath_print(common, ATH_DBG_FATAL,
+ "ath_desc not DWORD aligned\n");
+ BUG_ON((sizeof(struct ath_desc) % 4) != 0);
error = -ENOMEM;
goto fail;
}
@@ -1753,9 +2094,9 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
goto fail;
}
ds = dd->dd_desc;
- DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
- name, ds, (u32) dd->dd_desc_len,
- ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
+ ath_print(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
+ name, ds, (u32) dd->dd_desc_len,
+ ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
/* allocate buffers */
bsize = sizeof(struct ath_buf) * nbuf;
@@ -1778,7 +2119,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
* descriptor fetch.
*/
while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
- ASSERT((caddr_t) bf->bf_desc <
+ BUG_ON((caddr_t) bf->bf_desc >=
((caddr_t) dd->dd_desc +
dd->dd_desc_len));
@@ -1882,31 +2223,50 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM;
}
- sc->tx_chan_width = ATH9K_HT_MACMODE_20;
-
- if (conf_is_ht(conf)) {
- if (conf_is_ht40(conf))
- sc->tx_chan_width = ATH9K_HT_MACMODE_2040;
-
+ if (conf_is_ht(conf))
ichan->chanmode = ath_get_extchanmode(sc, chan,
conf->channel_type);
- }
}
/**********************/
/* mac80211 callbacks */
/**********************/
+/*
+ * (Re)start btcoex timers
+ */
+static void ath9k_btcoex_timer_resume(struct ath_softc *sc)
+{
+ struct ath_btcoex *btcoex = &sc->btcoex;
+ struct ath_hw *ah = sc->sc_ah;
+
+ ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+ "Starting btcoex timers");
+
+ /* make sure duty cycle timer is also stopped when resuming */
+ if (btcoex->hw_timer_enabled)
+ ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
+
+ btcoex->bt_priority_cnt = 0;
+ btcoex->bt_priority_time = jiffies;
+ sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
+
+ mod_timer(&btcoex->period_timer, jiffies);
+}
+
static int ath9k_start(struct ieee80211_hw *hw)
{
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_channel *curchan = hw->conf.channel;
struct ath9k_channel *init_channel;
int r;
- DPRINTF(sc, ATH_DBG_CONFIG, "Starting driver with "
- "initial channel: %d MHz\n", curchan->center_freq);
+ ath_print(common, ATH_DBG_CONFIG,
+ "Starting driver with initial channel: %d MHz\n",
+ curchan->center_freq);
mutex_lock(&sc->mutex);
@@ -1938,7 +2298,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
init_channel = ath_get_curchannel(sc, hw);
/* Reset SERDES registers */
- ath9k_hw_configpcipowersave(sc->sc_ah, 0, 0);
+ ath9k_hw_configpcipowersave(ah, 0, 0);
/*
* The basic interface to setting the hardware in a good
@@ -1948,12 +2308,12 @@ static int ath9k_start(struct ieee80211_hw *hw)
* and then setup of the interrupt mask.
*/
spin_lock_bh(&sc->sc_resetlock);
- r = ath9k_hw_reset(sc->sc_ah, init_channel, false);
+ r = ath9k_hw_reset(ah, init_channel, false);
if (r) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to reset hardware; reset status %d "
- "(freq %u MHz)\n", r,
- curchan->center_freq);
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to reset hardware; reset status %d "
+ "(freq %u MHz)\n", r,
+ curchan->center_freq);
spin_unlock_bh(&sc->sc_resetlock);
goto mutex_unlock;
}
@@ -1973,7 +2333,8 @@ static int ath9k_start(struct ieee80211_hw *hw)
* here except setup the interrupt mask.
*/
if (ath_startrecv(sc) != 0) {
- DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to start recv logic\n");
r = -EIO;
goto mutex_unlock;
}
@@ -1983,10 +2344,10 @@ static int ath9k_start(struct ieee80211_hw *hw)
| ATH9K_INT_RXEOL | ATH9K_INT_RXORN
| ATH9K_INT_FATAL | ATH9K_INT_GLOBAL;
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_GTT)
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_GTT)
sc->imask |= ATH9K_INT_GTT;
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
sc->imask |= ATH9K_INT_CST;
ath_cache_conf_rate(sc, &hw->conf);
@@ -1995,21 +2356,22 @@ static int ath9k_start(struct ieee80211_hw *hw)
/* Disable BMISS interrupt when we're not associated */
sc->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
- ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
+ ath9k_hw_set_interrupts(ah, sc->imask);
ieee80211_wake_queues(hw);
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
- if ((sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) &&
- !(sc->sc_flags & SC_OP_BTCOEX_ENABLED)) {
- ath_btcoex_set_weight(&sc->btcoex_info, AR_BT_COEX_WGHT,
- AR_STOMP_LOW_WLAN_WGHT);
- ath9k_hw_btcoex_enable(sc->sc_ah);
+ if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) &&
+ !ah->btcoex_hw.enabled) {
+ ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+ AR_STOMP_LOW_WLAN_WGHT);
+ ath9k_hw_btcoex_enable(ah);
- ath_pcie_aspm_disable(sc);
- if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
- ath_btcoex_timer_resume(sc, &sc->btcoex_info);
+ if (common->bus_ops->bt_coex_prep)
+ common->bus_ops->bt_coex_prep(common);
+ if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
+ ath9k_btcoex_timer_resume(sc);
}
mutex_unlock:
@@ -2024,12 +2386,14 @@ static int ath9k_tx(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_tx_control txctl;
int hdrlen, padsize;
if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) {
- printk(KERN_DEBUG "ath9k: %s: TX in unexpected wiphy state "
- "%d\n", wiphy_name(hw->wiphy), aphy->state);
+ ath_print(common, ATH_DBG_XMIT,
+ "ath9k: %s: TX in unexpected wiphy state "
+ "%d\n", wiphy_name(hw->wiphy), aphy->state);
goto exit;
}
@@ -2042,8 +2406,8 @@ static int ath9k_tx(struct ieee80211_hw *hw,
if (ieee80211_is_data(hdr->frame_control) &&
!ieee80211_is_nullfunc(hdr->frame_control) &&
!ieee80211_has_pm(hdr->frame_control)) {
- DPRINTF(sc, ATH_DBG_PS, "Add PM=1 for a TX frame "
- "while in PS mode\n");
+ ath_print(common, ATH_DBG_PS, "Add PM=1 for a TX frame "
+ "while in PS mode\n");
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
}
}
@@ -2058,11 +2422,12 @@ static int ath9k_tx(struct ieee80211_hw *hw,
ath9k_ps_wakeup(sc);
ath9k_hw_setrxabort(sc->sc_ah, 0);
if (ieee80211_is_pspoll(hdr->frame_control)) {
- DPRINTF(sc, ATH_DBG_PS, "Sending PS-Poll to pick a "
- "buffered frame\n");
+ ath_print(common, ATH_DBG_PS,
+ "Sending PS-Poll to pick a buffered frame\n");
sc->sc_flags |= SC_OP_WAIT_FOR_PSPOLL_DATA;
} else {
- DPRINTF(sc, ATH_DBG_PS, "Wake up to complete TX\n");
+ ath_print(common, ATH_DBG_PS,
+ "Wake up to complete TX\n");
sc->sc_flags |= SC_OP_WAIT_FOR_TX_ACK;
}
/*
@@ -2104,10 +2469,10 @@ static int ath9k_tx(struct ieee80211_hw *hw,
if (!txctl.txq)
goto exit;
- DPRINTF(sc, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb);
+ ath_print(common, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb);
if (ath_tx_start(hw, skb, &txctl) != 0) {
- DPRINTF(sc, ATH_DBG_XMIT, "TX failed\n");
+ ath_print(common, ATH_DBG_XMIT, "TX failed\n");
goto exit;
}
@@ -2117,10 +2482,28 @@ exit:
return 0;
}
+/*
+ * Pause btcoex timer and bt duty cycle timer
+ */
+static void ath9k_btcoex_timer_pause(struct ath_softc *sc)
+{
+ struct ath_btcoex *btcoex = &sc->btcoex;
+ struct ath_hw *ah = sc->sc_ah;
+
+ del_timer_sync(&btcoex->period_timer);
+
+ if (btcoex->hw_timer_enabled)
+ ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
+
+ btcoex->hw_timer_enabled = false;
+}
+
static void ath9k_stop(struct ieee80211_hw *hw)
{
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);
mutex_lock(&sc->mutex);
@@ -2135,7 +2518,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
}
if (sc->sc_flags & SC_OP_INVALID) {
- DPRINTF(sc, ATH_DBG_ANY, "Device not present\n");
+ ath_print(common, ATH_DBG_ANY, "Device not present\n");
mutex_unlock(&sc->mutex);
return;
}
@@ -2145,33 +2528,33 @@ static void ath9k_stop(struct ieee80211_hw *hw)
return; /* another wiphy still in use */
}
- if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) {
- ath9k_hw_btcoex_disable(sc->sc_ah);
- if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
- ath_btcoex_timer_pause(sc, &sc->btcoex_info);
+ if (ah->btcoex_hw.enabled) {
+ ath9k_hw_btcoex_disable(ah);
+ if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
+ ath9k_btcoex_timer_pause(sc);
}
/* make sure h/w will not generate any interrupt
* before setting the invalid flag. */
- ath9k_hw_set_interrupts(sc->sc_ah, 0);
+ ath9k_hw_set_interrupts(ah, 0);
if (!(sc->sc_flags & SC_OP_INVALID)) {
ath_drain_all_txq(sc, false);
ath_stoprecv(sc);
- ath9k_hw_phy_disable(sc->sc_ah);
+ ath9k_hw_phy_disable(ah);
} else
sc->rx.rxlink = NULL;
/* disable HAL and put h/w to sleep */
- ath9k_hw_disable(sc->sc_ah);
- ath9k_hw_configpcipowersave(sc->sc_ah, 1, 1);
- ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
+ ath9k_hw_disable(ah);
+ ath9k_hw_configpcipowersave(ah, 1, 1);
+ ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
sc->sc_flags |= SC_OP_INVALID;
mutex_unlock(&sc->mutex);
- DPRINTF(sc, ATH_DBG_CONFIG, "Driver halt\n");
+ ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
}
static int ath9k_add_interface(struct ieee80211_hw *hw,
@@ -2179,6 +2562,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)conf->vif->drv_priv;
enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;
int ret = 0;
@@ -2205,13 +2589,14 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
ic_opmode = conf->type;
break;
default:
- DPRINTF(sc, ATH_DBG_FATAL,
+ ath_print(common, ATH_DBG_FATAL,
"Interface type %d not yet supported\n", conf->type);
ret = -EOPNOTSUPP;
goto out;
}
- DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VIF of type: %d\n", ic_opmode);
+ ath_print(common, ATH_DBG_CONFIG,
+ "Attach a VIF of type: %d\n", ic_opmode);
/* Set the VIF opmode */
avp->av_opmode = ic_opmode;
@@ -2261,10 +2646,11 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)conf->vif->drv_priv;
int i;
- DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n");
+ ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
mutex_lock(&sc->mutex);
@@ -2299,6 +2685,7 @@ 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;
bool all_wiphys_idle = false, disable_radio = false;
@@ -2318,8 +2705,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
}
else if (all_wiphys_idle) {
ath_radio_enable(sc);
- DPRINTF(sc, ATH_DBG_CONFIG,
- "not-idle: enabling radio\n");
+ ath_print(common, ATH_DBG_CONFIG,
+ "not-idle: enabling radio\n");
}
}
@@ -2337,7 +2724,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
sc->ps_enabled = true;
} else {
sc->ps_enabled = false;
- ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
+ ath9k_setpower(sc, ATH9K_PM_AWAKE);
if (!(ah->caps.hw_caps &
ATH9K_HW_CAP_AUTOSLEEP)) {
ath9k_hw_setrxabort(sc->sc_ah, 0);
@@ -2372,8 +2759,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
goto skip_chan_change;
}
- DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
- curchan->center_freq);
+ ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
+ curchan->center_freq);
/* XXX: remove me eventualy */
ath9k_update_ichannel(sc, hw, &sc->sc_ah->channels[pos]);
@@ -2381,7 +2768,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
ath_update_chainmask(sc, conf_is_ht(conf));
if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) {
- DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to set channel\n");
mutex_unlock(&sc->mutex);
return -EINVAL;
}
@@ -2392,7 +2780,7 @@ skip_chan_change:
sc->config.txpowlimit = 2 * conf->power_level;
if (disable_radio) {
- DPRINTF(sc, ATH_DBG_CONFIG, "idle: disabling radio\n");
+ ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
ath_radio_disable(sc);
}
@@ -2429,7 +2817,8 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw,
ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
ath9k_ps_restore(sc);
- DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", rfilt);
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
+ "Set HW RX filter: 0x%x\n", rfilt);
}
static void ath9k_sta_notify(struct ieee80211_hw *hw,
@@ -2457,6 +2846,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath9k_tx_queue_info qi;
int ret = 0, qnum;
@@ -2473,15 +2863,15 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
qi.tqi_burstTime = params->txop;
qnum = ath_get_hal_qnum(queue, sc);
- DPRINTF(sc, ATH_DBG_CONFIG,
- "Configure tx [queue/halq] [%d/%d], "
- "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
- queue, qnum, params->aifs, params->cw_min,
- params->cw_max, params->txop);
+ ath_print(common, ATH_DBG_CONFIG,
+ "Configure tx [queue/halq] [%d/%d], "
+ "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
+ queue, qnum, params->aifs, params->cw_min,
+ params->cw_max, params->txop);
ret = ath_txq_update(sc, qnum, &qi);
if (ret)
- DPRINTF(sc, ATH_DBG_FATAL, "TXQ Update failed\n");
+ ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
mutex_unlock(&sc->mutex);
@@ -2496,6 +2886,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int ret = 0;
if (modparam_nohwcrypt)
@@ -2503,7 +2894,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
mutex_lock(&sc->mutex);
ath9k_ps_wakeup(sc);
- DPRINTF(sc, ATH_DBG_CONFIG, "Set HW Key\n");
+ ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n");
switch (cmd) {
case SET_KEY:
@@ -2540,6 +2931,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
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 ath_vif *avp = (void *)vif->drv_priv;
u32 rfilt = 0;
int error, i;
@@ -2555,9 +2947,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
ah->opmode != NL80211_IFTYPE_AP) {
ah->opmode = NL80211_IFTYPE_STATION;
ath9k_hw_setopmode(ah);
- memcpy(sc->curbssid, sc->sc_ah->macaddr, ETH_ALEN);
- sc->curaid = 0;
- ath9k_hw_write_associd(sc);
+ memcpy(common->curbssid, common->macaddr, ETH_ALEN);
+ common->curaid = 0;
+ ath9k_hw_write_associd(ah);
/* Request full reset to get hw opmode changed properly */
sc->sc_flags |= SC_OP_FULL_RESET;
}
@@ -2569,17 +2961,17 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
/* Set BSSID */
- memcpy(sc->curbssid, bss_conf->bssid, ETH_ALEN);
+ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN);
- sc->curaid = 0;
- ath9k_hw_write_associd(sc);
+ common->curaid = 0;
+ ath9k_hw_write_associd(ah);
/* Set aggregation protection mode parameters */
sc->config.ath_aggr_prot = 0;
- DPRINTF(sc, ATH_DBG_CONFIG,
- "RX filter 0x%x bssid %pM aid 0x%x\n",
- rfilt, sc->curbssid, sc->curaid);
+ ath_print(common, ATH_DBG_CONFIG,
+ "RX filter 0x%x bssid %pM aid 0x%x\n",
+ rfilt, common->curbssid, common->curaid);
/* need to reconfigure the beacon */
sc->sc_flags &= ~SC_OP_BEACONS ;
@@ -2618,7 +3010,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i))
ath9k_hw_keysetmac(sc->sc_ah,
(u16)i,
- sc->curbssid);
+ common->curbssid);
}
/* Only legacy IBSS for now */
@@ -2626,8 +3018,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
ath_update_chainmask(sc, 0);
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
- DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
- bss_conf->use_short_preamble);
+ ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
+ bss_conf->use_short_preamble);
if (bss_conf->use_short_preamble)
sc->sc_flags |= SC_OP_PREAMBLE_SHORT;
else
@@ -2635,8 +3027,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
- DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
- bss_conf->use_cts_prot);
+ ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
+ bss_conf->use_cts_prot);
if (bss_conf->use_cts_prot &&
hw->conf.channel->band != IEEE80211_BAND_5GHZ)
sc->sc_flags |= SC_OP_PROTECT_ENABLE;
@@ -2645,7 +3037,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_ASSOC) {
- DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
+ ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
bss_conf->assoc);
ath9k_bss_assoc_info(sc, vif, bss_conf);
}
@@ -2694,7 +3086,11 @@ static void ath9k_reset_tsf(struct ieee80211_hw *hw)
struct ath_softc *sc = aphy->sc;
mutex_lock(&sc->mutex);
+
+ ath9k_ps_wakeup(sc);
ath9k_hw_reset_tsf(sc->sc_ah);
+ ath9k_ps_restore(sc);
+
mutex_unlock(&sc->mutex);
}
@@ -2726,7 +3122,8 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
ath_tx_aggr_resume(sc, sta, tid);
break;
default:
- DPRINTF(sc, ATH_DBG_FATAL, "Unknown AMPDU action\n");
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "Unknown AMPDU action\n");
}
return ret;
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index 903dd8ad9d43..63059b6a90da 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -31,8 +31,9 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = {
};
/* return bus cachesize in 4B word units */
-static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz)
+static void ath_pci_read_cachesize(struct ath_common *common, int *csz)
{
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
u8 u8tmp;
pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, &u8tmp);
@@ -48,8 +49,9 @@ static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz)
*csz = DEFAULT_CACHELINE >> 2; /* Use the default size */
}
-static void ath_pci_cleanup(struct ath_softc *sc)
+static void ath_pci_cleanup(struct ath_common *common)
{
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
struct pci_dev *pdev = to_pci_dev(sc->dev);
pci_iounmap(pdev, sc->mem);
@@ -57,9 +59,11 @@ static void ath_pci_cleanup(struct ath_softc *sc)
pci_release_region(pdev, 0);
}
-static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data)
+static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data)
{
- (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
+ struct ath_hw *ah = (struct ath_hw *) common->ah;
+
+ common->ops->read(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
if (!ath9k_hw_wait(ah,
AR_EEPROM_STATUS_DATA,
@@ -69,16 +73,34 @@ static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data)
return false;
}
- *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA),
+ *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA),
AR_EEPROM_STATUS_DATA_VAL);
return true;
}
-static struct ath_bus_ops ath_pci_bus_ops = {
+/*
+ * Bluetooth coexistance requires disabling ASPM.
+ */
+static void ath_pci_bt_coex_prep(struct ath_common *common)
+{
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+ struct pci_dev *pdev = to_pci_dev(sc->dev);
+ u8 aspm;
+
+ if (!pdev->is_pcie)
+ return;
+
+ pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm);
+ aspm &= ~(ATH_PCIE_CAP_LINK_L0S | ATH_PCIE_CAP_LINK_L1);
+ pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm);
+}
+
+const static struct ath_bus_ops ath_pci_bus_ops = {
.read_cachesize = ath_pci_read_cachesize,
.cleanup = ath_pci_cleanup,
.eeprom_read = ath_pci_eeprom_read,
+ .bt_coex_prep = ath_pci_bt_coex_prep,
};
static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -177,10 +199,9 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sc->hw = hw;
sc->dev = &pdev->dev;
sc->mem = mem;
- sc->bus_ops = &ath_pci_bus_ops;
pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid);
- ret = ath_init_device(id->device, sc, subsysid);
+ ret = ath_init_device(id->device, sc, subsysid, &ath_pci_bus_ops);
if (ret) {
dev_err(&pdev->dev, "failed to initialize device\n");
goto bad3;
diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c
index 63bf9a307c6a..72a17c43a5a0 100644
--- a/drivers/net/wireless/ath/ath9k/phy.c
+++ b/drivers/net/wireless/ath/ath9k/phy.c
@@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "ath9k.h"
+#include "hw.h"
void
ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, u32 freqIndex,
@@ -26,6 +26,7 @@ ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, u32 freqIndex,
bool
ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
{
+ struct ath_common *common = ath9k_hw_common(ah);
u32 channelSel = 0;
u32 bModeSynth = 0;
u32 aModeRefSel = 0;
@@ -46,8 +47,8 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
channelSel = ((freq - 704) * 2 - 3040) / 10;
bModeSynth = 1;
} else {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Invalid channel %u MHz\n", freq);
+ ath_print(common, ATH_DBG_FATAL,
+ "Invalid channel %u MHz\n", freq);
return false;
}
@@ -79,8 +80,8 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8);
aModeRefSel = ath9k_hw_reverse_bits(1, 2);
} else {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Invalid channel %u MHz\n", freq);
+ ath_print(common, ATH_DBG_FATAL,
+ "Invalid channel %u MHz\n", freq);
return false;
}
@@ -112,20 +113,31 @@ void ath9k_hw_ar9280_set_channel(struct ath_hw *ah,
if (freq < 4800) {
u32 txctl;
+ int regWrites = 0;
bMode = 1;
fracMode = 1;
aModeRefSel = 0;
channelSel = (freq * 0x10000) / 15;
- txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL);
- if (freq == 2484) {
-
- REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
- txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
+ if (AR_SREV_9287_11_OR_LATER(ah)) {
+ if (freq == 2484) {
+ REG_WRITE_ARRAY(&ah->iniCckfirJapan2484,
+ 1, regWrites);
+ } else {
+ REG_WRITE_ARRAY(&ah->iniCckfirNormal,
+ 1, regWrites);
+ }
} else {
- REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
- txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN);
+ txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL);
+ if (freq == 2484) {
+ /* Enable channel spreading for channel 14 */
+ REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
+ txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
+ } else {
+ REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
+ txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN);
+ }
}
} else {
bMode = 0;
@@ -285,6 +297,8 @@ ath9k_hw_rf_free(struct ath_hw *ah)
bool ath9k_hw_init_rf(struct ath_hw *ah, int *status)
{
+ struct ath_common *common = ath9k_hw_common(ah);
+
if (!AR_SREV_9280_10_OR_LATER(ah)) {
ah->analogBank0Data =
kzalloc((sizeof(u32) *
@@ -315,8 +329,8 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, int *status)
|| ah->analogBank6Data == NULL
|| ah->analogBank6TPCData == NULL
|| ah->analogBank7Data == NULL) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Cannot allocate RF banks\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Cannot allocate RF banks\n");
*status = -ENOMEM;
return false;
}
@@ -326,8 +340,8 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, int *status)
ah->iniAddac.ia_rows *
ah->iniAddac.ia_columns), GFP_KERNEL);
if (ah->addac5416_21 == NULL) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Cannot allocate addac5416_21\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Cannot allocate addac5416_21\n");
*status = -ENOMEM;
return false;
}
@@ -336,8 +350,8 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, int *status)
kzalloc((sizeof(u32) *
ah->iniBank6.ia_rows), GFP_KERNEL);
if (ah->bank6Temp == NULL) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Cannot allocate bank6Temp\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Cannot allocate bank6Temp\n");
*status = -ENOMEM;
return false;
}
diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h
index dfda6f444648..140fef74c666 100644
--- a/drivers/net/wireless/ath/ath9k/phy.h
+++ b/drivers/net/wireless/ath/ath9k/phy.h
@@ -45,6 +45,7 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
#define AR_PHY_FC_DYN2040_EN 0x00000004
#define AR_PHY_FC_DYN2040_PRI_ONLY 0x00000008
#define AR_PHY_FC_DYN2040_PRI_CH 0x00000010
+/* For 25 MHz channel spacing -- not used but supported by hw */
#define AR_PHY_FC_DYN2040_EXT_CH 0x00000020
#define AR_PHY_FC_HT_EN 0x00000040
#define AR_PHY_FC_SHORT_GI_40 0x00000080
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 16a271787b85..063936423d86 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -425,7 +425,7 @@ static void ath_rc_init_valid_txmask(struct ath_rate_priv *ath_rc_priv)
static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv,
u8 index, int valid_tx_rate)
{
- ASSERT(index <= ath_rc_priv->rate_table_size);
+ BUG_ON(index > ath_rc_priv->rate_table_size);
ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0;
}
@@ -1160,6 +1160,7 @@ struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc,
bool is_cw_40)
{
int mode = 0;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
switch(band) {
case IEEE80211_BAND_2GHZ:
@@ -1177,13 +1178,14 @@ struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc,
mode = ATH9K_MODE_11NA_HT40PLUS;
break;
default:
- DPRINTF(sc, ATH_DBG_CONFIG, "Invalid band\n");
+ ath_print(common, ATH_DBG_CONFIG, "Invalid band\n");
return NULL;
}
BUG_ON(mode >= ATH9K_MODE_MAX);
- DPRINTF(sc, ATH_DBG_CONFIG, "Choosing rate table for mode: %d\n", mode);
+ ath_print(common, ATH_DBG_CONFIG,
+ "Choosing rate table for mode: %d\n", mode);
return sc->hw_rate_table[mode];
}
@@ -1194,11 +1196,13 @@ static void ath_rc_init(struct ath_softc *sc,
const struct ath_rate_table *rate_table)
{
struct ath_rateset *rateset = &ath_rc_priv->neg_rates;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates;
u8 i, j, k, hi = 0, hthi = 0;
if (!rate_table) {
- DPRINTF(sc, ATH_DBG_FATAL, "Rate table not initialized\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "Rate table not initialized\n");
return;
}
@@ -1239,7 +1243,7 @@ static void ath_rc_init(struct ath_softc *sc,
ath_rc_priv->rate_table_size = hi + 1;
ath_rc_priv->rate_max_phy = 0;
- ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE);
+ BUG_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE);
for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) {
for (j = 0; j < ath_rc_priv->valid_phy_ratecnt[i]; j++) {
@@ -1253,16 +1257,17 @@ static void ath_rc_init(struct ath_softc *sc,
ath_rc_priv->rate_max_phy = ath_rc_priv->valid_phy_rateidx[i][j-1];
}
- ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE);
- ASSERT(k <= RATE_TABLE_SIZE);
+ BUG_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE);
+ BUG_ON(k > RATE_TABLE_SIZE);
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;
- DPRINTF(sc, ATH_DBG_CONFIG, "RC Initialized with capabilities: 0x%x\n",
- ath_rc_priv->ht_cap);
+ ath_print(common, ATH_DBG_CONFIG,
+ "RC Initialized with capabilities: 0x%x\n",
+ ath_rc_priv->ht_cap);
}
static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta,
@@ -1438,9 +1443,9 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
oper_cw40, oper_sgi40);
ath_rc_init(sc, priv_sta, sband, sta, rate_table);
- DPRINTF(sc, ATH_DBG_CONFIG,
- "Operating HT Bandwidth changed to: %d\n",
- sc->hw->conf.channel_type);
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
+ "Operating HT Bandwidth changed to: %d\n",
+ sc->hw->conf.channel_type);
}
}
}
@@ -1463,8 +1468,8 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp
rate_priv = kzalloc(sizeof(struct ath_rate_priv), gfp);
if (!rate_priv) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to allocate private rc structure\n");
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "Unable to allocate private rc structure\n");
return NULL;
}
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index ec0abf823995..c880a55939bf 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -59,7 +59,7 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
/* virtual addr of the beginning of the buffer. */
skb = bf->bf_mpdu;
- ASSERT(skb != NULL);
+ BUG_ON(skb == NULL);
ds->ds_vdata = skb->data;
/* setup rx descriptors. The rx.bufsize here tells the harware
@@ -272,6 +272,8 @@ rx_next:
static void ath_opmode_init(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+
u32 rfilt, mfilt[2];
/* configure rx filter */
@@ -280,13 +282,13 @@ static void ath_opmode_init(struct ath_softc *sc)
/* configure bssid mask */
if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
- ath9k_hw_setbssidmask(sc);
+ ath_hw_setbssidmask(common);
/* configure operational mode */
ath9k_hw_setopmode(ah);
/* Handle any link-level address change. */
- ath9k_hw_setmac(ah, sc->sc_ah->macaddr);
+ ath9k_hw_setmac(ah, common->macaddr);
/* calculate and install multicast filter */
mfilt[0] = mfilt[1] = ~0;
@@ -295,6 +297,7 @@ static void ath_opmode_init(struct ath_softc *sc)
int ath_rx_init(struct ath_softc *sc, int nbufs)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct sk_buff *skb;
struct ath_buf *bf;
int error = 0;
@@ -304,23 +307,23 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
spin_lock_init(&sc->rx.rxbuflock);
sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
- min(sc->common.cachelsz, (u16)64));
+ min(common->cachelsz, (u16)64));
- DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
- sc->common.cachelsz, sc->rx.bufsize);
+ ath_print(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
+ common->cachelsz, sc->rx.bufsize);
/* Initialize rx descriptors */
error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf,
"rx", nbufs, 1);
if (error != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "failed to allocate rx descriptors: %d\n", error);
+ ath_print(common, ATH_DBG_FATAL,
+ "failed to allocate rx descriptors: %d\n", error);
goto err;
}
list_for_each_entry(bf, &sc->rx.rxbuf, list) {
- skb = ath_rxbuf_alloc(&sc->common, sc->rx.bufsize, GFP_KERNEL);
+ skb = ath_rxbuf_alloc(common, sc->rx.bufsize, GFP_KERNEL);
if (skb == NULL) {
error = -ENOMEM;
goto err;
@@ -334,8 +337,8 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
bf->bf_buf_addr))) {
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
- DPRINTF(sc, ATH_DBG_FATAL,
- "dma_mapping_error() on RX init\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "dma_mapping_error() on RX init\n");
error = -ENOMEM;
goto err;
}
@@ -420,7 +423,10 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
else
rfilt |= ATH9K_RX_FILTER_BEACON;
- if (sc->rx.rxfilter & FIF_PSPOLL)
+ if ((AR_SREV_9280_10_OR_LATER(sc->sc_ah) ||
+ AR_SREV_9285_10_OR_LATER(sc->sc_ah)) &&
+ (sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
+ (sc->rx.rxfilter & FIF_PSPOLL))
rfilt |= ATH9K_RX_FILTER_PSPOLL;
if (conf_is_ht(&sc->hw->conf))
@@ -527,20 +533,22 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
{
struct ieee80211_mgmt *mgmt;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
if (skb->len < 24 + 8 + 2 + 2)
return;
mgmt = (struct ieee80211_mgmt *)skb->data;
- if (memcmp(sc->curbssid, mgmt->bssid, ETH_ALEN) != 0)
+ if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0)
return; /* not from our current AP */
sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
if (sc->sc_flags & SC_OP_BEACON_SYNC) {
sc->sc_flags &= ~SC_OP_BEACON_SYNC;
- DPRINTF(sc, ATH_DBG_PS, "Reconfigure Beacon timers based on "
- "timestamp from the AP\n");
+ ath_print(common, ATH_DBG_PS,
+ "Reconfigure Beacon timers based on "
+ "timestamp from the AP\n");
ath_beacon_config(sc, NULL);
}
@@ -552,8 +560,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
* a backup trigger for returning into NETWORK SLEEP state,
* so we are waiting for it as well.
*/
- DPRINTF(sc, ATH_DBG_PS, "Received DTIM beacon indicating "
- "buffered broadcast/multicast frame(s)\n");
+ ath_print(common, ATH_DBG_PS, "Received DTIM beacon indicating "
+ "buffered broadcast/multicast frame(s)\n");
sc->sc_flags |= SC_OP_WAIT_FOR_CAB | SC_OP_WAIT_FOR_BEACON;
return;
}
@@ -565,13 +573,15 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
* been delivered.
*/
sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
- DPRINTF(sc, ATH_DBG_PS, "PS wait for CAB frames timed out\n");
+ ath_print(common, ATH_DBG_PS,
+ "PS wait for CAB frames timed out\n");
}
}
static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
hdr = (struct ieee80211_hdr *)skb->data;
@@ -589,14 +599,15 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
* point.
*/
sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
- DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to "
- "sleep\n");
+ ath_print(common, ATH_DBG_PS,
+ "All PS CAB frames received, back to sleep\n");
} else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) &&
!is_multicast_ether_addr(hdr->addr1) &&
!ieee80211_has_morefrags(hdr->frame_control)) {
sc->sc_flags &= ~SC_OP_WAIT_FOR_PSPOLL_DATA;
- DPRINTF(sc, ATH_DBG_PS, "Going back to sleep after having "
- "received PS-Poll data (0x%x)\n",
+ ath_print(common, ATH_DBG_PS,
+ "Going back to sleep after having received "
+ "PS-Poll data (0x%x)\n",
sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
SC_OP_WAIT_FOR_CAB |
SC_OP_WAIT_FOR_PSPOLL_DATA |
@@ -651,6 +662,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
struct sk_buff *skb = NULL, *requeue_skb;
struct ieee80211_rx_status rx_status;
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_hdr *hdr;
int hdrlen, padsize, retval;
bool decrypt_error = false;
@@ -749,7 +761,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
/* Ensure we always have an skb to requeue once we are done
* processing the current buffer's skb */
- requeue_skb = ath_rxbuf_alloc(&sc->common, sc->rx.bufsize, GFP_ATOMIC);
+ requeue_skb = ath_rxbuf_alloc(common, sc->rx.bufsize, GFP_ATOMIC);
/* If there is no memory we ignore the current RX'd frame,
* tell hardware it can give us a new frame using the old
@@ -811,8 +823,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
bf->bf_buf_addr))) {
dev_kfree_skb_any(requeue_skb);
bf->bf_mpdu = NULL;
- DPRINTF(sc, ATH_DBG_FATAL,
- "dma_mapping_error() on RX\n");
+ ath_print(common, ATH_DBG_FATAL,
+ "dma_mapping_error() on RX\n");
ath_rx_send_to_mac80211(sc, skb, &rx_status);
break;
}
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index d83b77f821e9..ceed0095efac 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -17,6 +17,8 @@
#ifndef REG_H
#define REG_H
+#include "../reg.h"
+
#define AR_CR 0x0008
#define AR_CR_RXE 0x00000004
#define AR_CR_RXD 0x00000020
@@ -1421,9 +1423,6 @@ enum {
#define AR_SLEEP2_BEACON_TIMEOUT 0xFFE00000
#define AR_SLEEP2_BEACON_TIMEOUT_S 21
-#define AR_BSSMSKL 0x80e0
-#define AR_BSSMSKU 0x80e4
-
#define AR_TPC 0x80e8
#define AR_TPC_ACK 0x0000003f
#define AR_TPC_ACK_S 0x00
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index 19b88f8177fd..bc7d173b6fae 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -40,6 +40,7 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
{
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];
@@ -51,7 +52,7 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
*/
iter_data.addr = kmalloc(ETH_ALEN, GFP_ATOMIC);
if (iter_data.addr) {
- memcpy(iter_data.addr, sc->sc_ah->macaddr, ETH_ALEN);
+ memcpy(iter_data.addr, common->macaddr, ETH_ALEN);
iter_data.count = 1;
} else
iter_data.count = 0;
@@ -86,20 +87,21 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
kfree(iter_data.addr);
/* Invert the mask and configure hardware */
- sc->bssidmask[0] = ~mask[0];
- sc->bssidmask[1] = ~mask[1];
- sc->bssidmask[2] = ~mask[2];
- sc->bssidmask[3] = ~mask[3];
- sc->bssidmask[4] = ~mask[4];
- sc->bssidmask[5] = ~mask[5];
-
- ath9k_hw_setbssidmask(sc);
+ 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];
+
+ ath_hw_setbssidmask(common);
}
int ath9k_wiphy_add(struct ath_softc *sc)
{
int i, error;
struct ath_wiphy *aphy;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ieee80211_hw *hw;
u8 addr[ETH_ALEN];
@@ -138,7 +140,7 @@ int ath9k_wiphy_add(struct ath_softc *sc)
sc->sec_wiphy[i] = aphy;
spin_unlock_bh(&sc->wiphy_lock);
- memcpy(addr, sc->sc_ah->macaddr, ETH_ALEN);
+ memcpy(addr, common->macaddr, ETH_ALEN);
addr[0] |= 0x02; /* Locally managed address */
/*
* XOR virtual wiphy index into the least significant bits to generate
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 42551a48c8ac..2a4efcbced60 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -107,7 +107,7 @@ static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
- ASSERT(tid->paused > 0);
+ BUG_ON(tid->paused <= 0);
spin_lock_bh(&txq->axq_lock);
tid->paused--;
@@ -131,7 +131,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
struct list_head bf_head;
INIT_LIST_HEAD(&bf_head);
- ASSERT(tid->paused > 0);
+ BUG_ON(tid->paused <= 0);
spin_lock_bh(&txq->axq_lock);
tid->paused--;
@@ -143,7 +143,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
while (!list_empty(&tid->buf_q)) {
bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
- ASSERT(!bf_isretried(bf));
+ BUG_ON(bf_isretried(bf));
list_move_tail(&bf->list, &bf_head);
ath_tx_send_ht_normal(sc, txq, tid, &bf_head);
}
@@ -178,7 +178,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);
- ASSERT(tid->tx_buf[cindex] == NULL);
+ BUG_ON(tid->tx_buf[cindex] != NULL);
tid->tx_buf[cindex] = bf;
if (index >= ((tid->baw_tail - tid->baw_head) &
@@ -358,7 +358,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
else
INIT_LIST_HEAD(&bf_head);
} else {
- ASSERT(!list_empty(bf_q));
+ BUG_ON(list_empty(bf_q));
list_move_tail(&bf->list, &bf_head);
}
@@ -815,6 +815,7 @@ static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_tx_queue_info qi;
int qnum;
@@ -854,9 +855,9 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
return NULL;
}
if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "qnum %u out of range, max %u!\n",
- qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
+ ath_print(common, ATH_DBG_FATAL,
+ "qnum %u out of range, max %u!\n",
+ qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
ath9k_hw_releasetxqueue(ah, qnum);
return NULL;
}
@@ -884,9 +885,9 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
switch (qtype) {
case ATH9K_TX_QUEUE_DATA:
if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "HAL AC %u out of range, max %zu!\n",
- haltype, ARRAY_SIZE(sc->tx.hwq_map));
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "HAL AC %u out of range, max %zu!\n",
+ haltype, ARRAY_SIZE(sc->tx.hwq_map));
return -1;
}
qnum = sc->tx.hwq_map[haltype];
@@ -914,9 +915,9 @@ struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
spin_lock_bh(&txq->axq_lock);
if (txq->axq_depth >= (ATH_TXBUF - 20)) {
- DPRINTF(sc, ATH_DBG_XMIT,
- "TX queue: %d is full, depth: %d\n",
- qnum, txq->axq_depth);
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_XMIT,
+ "TX queue: %d is full, depth: %d\n",
+ qnum, txq->axq_depth);
ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb));
txq->stopped = 1;
spin_unlock_bh(&txq->axq_lock);
@@ -945,7 +946,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum,
return 0;
}
- ASSERT(sc->tx.txq[qnum].axq_qnum == qnum);
+ BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
ath9k_hw_get_txq_props(ah, qnum, &qi);
qi.tqi_aifs = qinfo->tqi_aifs;
@@ -955,8 +956,8 @@ int ath_txq_update(struct ath_softc *sc, int qnum,
qi.tqi_readyTime = qinfo->tqi_readyTime;
if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to update hardware queue %u!\n", qnum);
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "Unable to update hardware queue %u!\n", qnum);
error = -EIO;
} else {
ath9k_hw_resettxqueue(ah, qnum);
@@ -1055,6 +1056,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_txq *txq;
int i, npend = 0;
@@ -1076,14 +1078,15 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
if (npend) {
int r;
- DPRINTF(sc, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n");
+ ath_print(common, ATH_DBG_XMIT,
+ "Unable to stop TxDMA. Reset HAL!\n");
spin_lock_bh(&sc->sc_resetlock);
r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true);
if (r)
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to reset hardware; reset status %d\n",
- r);
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to reset hardware; reset status %d\n",
+ r);
spin_unlock_bh(&sc->sc_resetlock);
}
@@ -1147,8 +1150,8 @@ int ath_tx_setup(struct ath_softc *sc, int haltype)
struct ath_txq *txq;
if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "HAL AC %u out of range, max %zu!\n",
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "HAL AC %u out of range, max %zu!\n",
haltype, ARRAY_SIZE(sc->tx.hwq_map));
return 0;
}
@@ -1172,6 +1175,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
struct list_head *head)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath_buf *bf;
/*
@@ -1188,19 +1192,19 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
txq->axq_depth++;
txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list);
- DPRINTF(sc, ATH_DBG_QUEUE,
- "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
+ ath_print(common, ATH_DBG_QUEUE,
+ "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
if (txq->axq_link == NULL) {
ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
- DPRINTF(sc, ATH_DBG_XMIT,
- "TXDP[%u] = %llx (%p)\n",
- txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
+ ath_print(common, ATH_DBG_XMIT,
+ "TXDP[%u] = %llx (%p)\n",
+ txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
} else {
*txq->axq_link = bf->bf_daddr;
- DPRINTF(sc, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n",
- txq->axq_qnum, txq->axq_link,
- ito64(bf->bf_daddr), bf->bf_desc);
+ ath_print(common, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n",
+ txq->axq_qnum, txq->axq_link,
+ ito64(bf->bf_daddr), bf->bf_desc);
}
txq->axq_link = &(bf->bf_lastbf->bf_desc->ds_link);
ath9k_hw_txstart(ah, txq->axq_qnum);
@@ -1452,6 +1456,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
const struct ath_rate_table *rt = sc->cur_rate_table;
struct ath9k_11n_rate_series series[4];
struct sk_buff *skb;
@@ -1507,7 +1512,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
rix = rates[i].idx;
series[i].Tries = rates[i].count;
- series[i].ChSel = sc->tx_chainmask;
+ series[i].ChSel = common->tx_chainmask;
if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
series[i].Rate = rt->info[rix].ratecode |
@@ -1587,7 +1592,8 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
bf->bf_mpdu = NULL;
kfree(tx_info_priv);
tx_info->rate_driver_data[0] = NULL;
- DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error() on TX\n");
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "dma_mapping_error() on TX\n");
return -ENOMEM;
}
@@ -1669,12 +1675,13 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_buf *bf;
int r;
bf = ath_tx_get_buffer(sc);
if (!bf) {
- DPRINTF(sc, ATH_DBG_XMIT, "TX buffers are full\n");
+ ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
return -1;
}
@@ -1682,7 +1689,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
if (unlikely(r)) {
struct ath_txq *txq = txctl->txq;
- DPRINTF(sc, ATH_DBG_FATAL, "TX mem alloc failure\n");
+ ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n");
/* upon ath_tx_processq() this TX queue will be resumed, we
* guarantee this will happen by knowing beforehand that
@@ -1712,6 +1719,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int hdrlen, padsize;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath_tx_control txctl;
@@ -1736,7 +1744,8 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
if (hdrlen & 3) {
padsize = hdrlen % 4;
if (skb_headroom(skb) < padsize) {
- DPRINTF(sc, ATH_DBG_XMIT, "TX CABQ padding failed\n");
+ ath_print(common, ATH_DBG_XMIT,
+ "TX CABQ padding failed\n");
dev_kfree_skb_any(skb);
return;
}
@@ -1746,10 +1755,11 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
txctl.txq = sc->beacon.cabq;
- DPRINTF(sc, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb);
+ ath_print(common, ATH_DBG_XMIT,
+ "transmitting CABQ packet, skb: %p\n", skb);
if (ath_tx_start(hw, skb, &txctl) != 0) {
- DPRINTF(sc, ATH_DBG_XMIT, "CABQ TX failed\n");
+ ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
goto exit;
}
@@ -1768,10 +1778,11 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
struct ieee80211_hw *hw = sc->hw;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int hdrlen, padsize;
int frame_type = ATH9K_NOT_INTERNAL;
- DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
+ ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
if (tx_info_priv) {
hw = tx_info_priv->aphy->hw;
@@ -1805,8 +1816,9 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
if (sc->sc_flags & SC_OP_WAIT_FOR_TX_ACK) {
sc->sc_flags &= ~SC_OP_WAIT_FOR_TX_ACK;
- DPRINTF(sc, ATH_DBG_PS, "Going back to sleep after having "
- "received TX status (0x%x)\n",
+ ath_print(common, ATH_DBG_PS,
+ "Going back to sleep after having "
+ "received TX status (0x%x)\n",
sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
SC_OP_WAIT_FOR_CAB |
SC_OP_WAIT_FOR_PSPOLL_DATA |
@@ -1936,15 +1948,16 @@ static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath_buf *bf, *lastbf, *bf_held = NULL;
struct list_head bf_head;
struct ath_desc *ds;
int txok;
int status;
- DPRINTF(sc, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
- txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
- txq->axq_link);
+ ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
+ txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
+ txq->axq_link);
for (;;) {
spin_lock_bh(&txq->axq_lock);
@@ -2064,8 +2077,11 @@ static void ath_tx_complete_poll_work(struct work_struct *work)
}
if (needreset) {
- DPRINTF(sc, ATH_DBG_RESET, "tx hung, resetting the chip\n");
+ 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);
+ ath9k_ps_restore(sc);
}
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
@@ -2093,6 +2109,7 @@ void ath_tx_tasklet(struct ath_softc *sc)
int ath_tx_init(struct ath_softc *sc, int nbufs)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int error = 0;
spin_lock_init(&sc->tx.txbuflock);
@@ -2100,16 +2117,16 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
"tx", nbufs, 1);
if (error != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Failed to allocate tx descriptors: %d\n", error);
+ ath_print(common, ATH_DBG_FATAL,
+ "Failed to allocate tx descriptors: %d\n", error);
goto err;
}
error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
"beacon", ATH_BCBUF, 1);
if (error != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Failed to allocate beacon descriptors: %d\n", error);
+ ath_print(common, ATH_DBG_FATAL,
+ "Failed to allocate beacon descriptors: %d\n", error);
goto err;
}
diff --git a/drivers/net/wireless/ath/debug.c b/drivers/net/wireless/ath/debug.c
new file mode 100644
index 000000000000..53e77bd131b9
--- /dev/null
+++ b/drivers/net/wireless/ath/debug.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 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 "ath.h"
+#include "debug.h"
+
+void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...)
+{
+ va_list args;
+
+ if (likely(!(common->debug_mask & dbg_mask)))
+ return;
+
+ va_start(args, fmt);
+ printk(KERN_DEBUG "ath: ");
+ vprintk(fmt, args);
+ va_end(args);
+}
+EXPORT_SYMBOL(ath_print);
diff --git a/drivers/net/wireless/ath/debug.h b/drivers/net/wireless/ath/debug.h
new file mode 100644
index 000000000000..d6b685a06c5e
--- /dev/null
+++ b/drivers/net/wireless/ath/debug.h
@@ -0,0 +1,77 @@
+/*
+ * 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 ATH_DEBUG_H
+#define ATH_DEBUG_H
+
+#include "ath.h"
+
+/**
+ * enum ath_debug_level - atheros wireless debug level
+ *
+ * @ATH_DBG_RESET: reset processing
+ * @ATH_DBG_QUEUE: hardware queue management
+ * @ATH_DBG_EEPROM: eeprom processing
+ * @ATH_DBG_CALIBRATE: periodic calibration
+ * @ATH_DBG_INTERRUPT: interrupt processing
+ * @ATH_DBG_REGULATORY: regulatory processing
+ * @ATH_DBG_ANI: adaptive noise immunitive processing
+ * @ATH_DBG_XMIT: basic xmit operation
+ * @ATH_DBG_BEACON: beacon handling
+ * @ATH_DBG_CONFIG: configuration of the hardware
+ * @ATH_DBG_FATAL: fatal errors, this is the default, DBG_DEFAULT
+ * @ATH_DBG_PS: power save processing
+ * @ATH_DBG_HWTIMER: hardware timer handling
+ * @ATH_DBG_BTCOEX: bluetooth coexistance
+ * @ATH_DBG_ANY: enable all debugging
+ *
+ * The debug level is used to control the amount and type of debugging output
+ * we want to see. Each driver has its own method for enabling debugging and
+ * modifying debug level states -- but this is typically done through a
+ * module parameter 'debug' along with a respective 'debug' debugfs file
+ * entry.
+ */
+enum ATH_DEBUG {
+ ATH_DBG_RESET = 0x00000001,
+ ATH_DBG_QUEUE = 0x00000002,
+ ATH_DBG_EEPROM = 0x00000004,
+ ATH_DBG_CALIBRATE = 0x00000008,
+ ATH_DBG_INTERRUPT = 0x00000010,
+ ATH_DBG_REGULATORY = 0x00000020,
+ ATH_DBG_ANI = 0x00000040,
+ ATH_DBG_XMIT = 0x00000080,
+ ATH_DBG_BEACON = 0x00000100,
+ ATH_DBG_CONFIG = 0x00000200,
+ ATH_DBG_FATAL = 0x00000400,
+ ATH_DBG_PS = 0x00000800,
+ ATH_DBG_HWTIMER = 0x00001000,
+ ATH_DBG_BTCOEX = 0x00002000,
+ ATH_DBG_ANY = 0xffffffff
+};
+
+#define ATH_DBG_DEFAULT (ATH_DBG_FATAL)
+
+#ifdef CONFIG_ATH_DEBUG
+void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...);
+#else
+static inline void ath_print(struct ath_common *common,
+ int dbg_mask,
+ const char *fmt, ...)
+{
+}
+#endif /* CONFIG_ATH_DEBUG */
+
+#endif /* ATH_DEBUG_H */
diff --git a/drivers/net/wireless/ath/hw.c b/drivers/net/wireless/ath/hw.c
new file mode 100644
index 000000000000..ecc9eb01f4fa
--- /dev/null
+++ b/drivers/net/wireless/ath/hw.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 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 <asm/unaligned.h>
+
+#include "ath.h"
+#include "reg.h"
+
+#define REG_READ common->ops->read
+#define REG_WRITE common->ops->write
+
+/**
+ * ath_hw_set_bssid_mask - filter out bssids we listen
+ *
+ * @common: the ath_common struct for the device.
+ *
+ * BSSID masking is a method used by AR5212 and newer hardware to inform PCU
+ * which bits of the interface's MAC address should be looked at when trying
+ * to decide which packets to ACK. In station mode and AP mode with a single
+ * BSS every bit matters since we lock to only one BSS. In AP mode with
+ * multiple BSSes (virtual interfaces) not every bit matters because hw must
+ * accept frames for all BSSes and so we tweak some bits of our mac address
+ * in order to have multiple BSSes.
+ *
+ * NOTE: This is a simple filter and does *not* filter out all
+ * relevant frames. Some frames that are not for us might get ACKed from us
+ * by PCU because they just match the mask.
+ *
+ * When handling multiple BSSes you can get the BSSID mask by computing the
+ * set of ~ ( MAC XOR BSSID ) for all bssids we handle.
+ *
+ * When you do this you are essentially computing the common bits of all your
+ * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with
+ * the MAC address to obtain the relevant bits and compare the result with
+ * (frame's BSSID & mask) to see if they match.
+ *
+ * Simple example: on your card you have have two BSSes you have created with
+ * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address.
+ * There is another BSSID-03 but you are not part of it. For simplicity's sake,
+ * assuming only 4 bits for a mac address and for BSSIDs you can then have:
+ *
+ * \
+ * MAC: 0001 |
+ * BSSID-01: 0100 | --> Belongs to us
+ * BSSID-02: 1001 |
+ * /
+ * -------------------
+ * BSSID-03: 0110 | --> External
+ * -------------------
+ *
+ * Our bssid_mask would then be:
+ *
+ * On loop iteration for BSSID-01:
+ * ~(0001 ^ 0100) -> ~(0101)
+ * -> 1010
+ * bssid_mask = 1010
+ *
+ * On loop iteration for BSSID-02:
+ * bssid_mask &= ~(0001 ^ 1001)
+ * bssid_mask = (1010) & ~(0001 ^ 1001)
+ * bssid_mask = (1010) & ~(1001)
+ * bssid_mask = (1010) & (0110)
+ * bssid_mask = 0010
+ *
+ * A bssid_mask of 0010 means "only pay attention to the second least
+ * significant bit". This is because its the only bit common
+ * amongst the MAC and all BSSIDs we support. To findout what the real
+ * common bit is we can simply "&" the bssid_mask now with any BSSID we have
+ * or our MAC address (we assume the hardware uses the MAC address).
+ *
+ * Now, suppose there's an incoming frame for BSSID-03:
+ *
+ * IFRAME-01: 0110
+ *
+ * An easy eye-inspeciton of this already should tell you that this frame
+ * will not pass our check. This is beacuse the bssid_mask tells the
+ * hardware to only look at the second least significant bit and the
+ * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB
+ * as 1, which does not match 0.
+ *
+ * So with IFRAME-01 we *assume* the hardware will do:
+ *
+ * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
+ * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0;
+ * --> allow = (0010) == 0000 ? 1 : 0;
+ * --> allow = 0
+ *
+ * Lets now test a frame that should work:
+ *
+ * IFRAME-02: 0001 (we should allow)
+ *
+ * allow = (0001 & 1010) == 1010
+ *
+ * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
+ * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0;
+ * --> allow = (0010) == (0010)
+ * --> allow = 1
+ *
+ * Other examples:
+ *
+ * IFRAME-03: 0100 --> allowed
+ * IFRAME-04: 1001 --> allowed
+ * IFRAME-05: 1101 --> allowed but its not for us!!!
+ *
+ */
+void ath_hw_setbssidmask(struct ath_common *common)
+{
+ void *ah = common->ah;
+
+ REG_WRITE(ah, get_unaligned_le32(common->bssidmask), AR_BSSMSKL);
+ REG_WRITE(ah, get_unaligned_le16(common->bssidmask + 4), AR_BSSMSKU);
+}
+EXPORT_SYMBOL(ath_hw_setbssidmask);
diff --git a/drivers/net/wireless/ath/reg.h b/drivers/net/wireless/ath/reg.h
new file mode 100644
index 000000000000..dfe1fbec24f5
--- /dev/null
+++ b/drivers/net/wireless/ath/reg.h
@@ -0,0 +1,27 @@
+/*
+ * 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 ATH_REGISTERS_H
+#define ATH_REGISTERS_H
+
+/*
+ * BSSID mask registers. See ath_hw_set_bssid_mask()
+ * for detailed documentation about these registers.
+ */
+#define AR_BSSMSKL 0x80e0
+#define AR_BSSMSKU 0x80e4
+
+#endif /* ATH_REGISTERS_H */
diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h
index c1dd857697a7..a1c39526161a 100644
--- a/drivers/net/wireless/ath/regd.h
+++ b/drivers/net/wireless/ath/regd.h
@@ -65,10 +65,13 @@ enum CountryCode {
CTRY_ALGERIA = 12,
CTRY_ARGENTINA = 32,
CTRY_ARMENIA = 51,
+ CTRY_ARUBA = 533,
CTRY_AUSTRALIA = 36,
CTRY_AUSTRIA = 40,
CTRY_AZERBAIJAN = 31,
CTRY_BAHRAIN = 48,
+ CTRY_BANGLADESH = 50,
+ CTRY_BARBADOS = 52,
CTRY_BELARUS = 112,
CTRY_BELGIUM = 56,
CTRY_BELIZE = 84,
@@ -77,6 +80,7 @@ enum CountryCode {
CTRY_BRAZIL = 76,
CTRY_BRUNEI_DARUSSALAM = 96,
CTRY_BULGARIA = 100,
+ CTRY_CAMBODIA = 116,
CTRY_CANADA = 124,
CTRY_CHILE = 152,
CTRY_CHINA = 156,
@@ -97,7 +101,11 @@ enum CountryCode {
CTRY_GEORGIA = 268,
CTRY_GERMANY = 276,
CTRY_GREECE = 300,
+ CTRY_GREENLAND = 304,
+ CTRY_GRENEDA = 308,
+ CTRY_GUAM = 316,
CTRY_GUATEMALA = 320,
+ CTRY_HAITI = 332,
CTRY_HONDURAS = 340,
CTRY_HONG_KONG = 344,
CTRY_HUNGARY = 348,
diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h
index 9847af72208c..248c670fdfbe 100644
--- a/drivers/net/wireless/ath/regd_common.h
+++ b/drivers/net/wireless/ath/regd_common.h
@@ -288,13 +288,16 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_DEFAULT, FCC1_FCCA, "CO"},
{CTRY_ALBANIA, NULL1_WORLD, "AL"},
{CTRY_ALGERIA, NULL1_WORLD, "DZ"},
- {CTRY_ARGENTINA, APL3_WORLD, "AR"},
+ {CTRY_ARGENTINA, FCC3_WORLD, "AR"},
{CTRY_ARMENIA, ETSI4_WORLD, "AM"},
+ {CTRY_ARUBA, ETSI1_WORLD, "AW"},
{CTRY_AUSTRALIA, FCC2_WORLD, "AU"},
{CTRY_AUSTRALIA2, FCC6_WORLD, "AU"},
{CTRY_AUSTRIA, ETSI1_WORLD, "AT"},
{CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ"},
{CTRY_BAHRAIN, APL6_WORLD, "BH"},
+ {CTRY_BANGLADESH, NULL1_WORLD, "BD"},
+ {CTRY_BARBADOS, FCC2_WORLD, "BB"},
{CTRY_BELARUS, ETSI1_WORLD, "BY"},
{CTRY_BELGIUM, ETSI1_WORLD, "BE"},
{CTRY_BELGIUM2, ETSI4_WORLD, "BL"},
@@ -304,13 +307,14 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_BRAZIL, FCC3_WORLD, "BR"},
{CTRY_BRUNEI_DARUSSALAM, APL1_WORLD, "BN"},
{CTRY_BULGARIA, ETSI6_WORLD, "BG"},
- {CTRY_CANADA, FCC2_FCCA, "CA"},
+ {CTRY_CAMBODIA, ETSI1_WORLD, "KH"},
+ {CTRY_CANADA, FCC3_FCCA, "CA"},
{CTRY_CANADA2, FCC6_FCCA, "CA"},
{CTRY_CHILE, APL6_WORLD, "CL"},
{CTRY_CHINA, APL1_WORLD, "CN"},
{CTRY_COLOMBIA, FCC1_FCCA, "CO"},
{CTRY_COSTA_RICA, FCC1_WORLD, "CR"},
- {CTRY_CROATIA, ETSI3_WORLD, "HR"},
+ {CTRY_CROATIA, ETSI1_WORLD, "HR"},
{CTRY_CYPRUS, ETSI1_WORLD, "CY"},
{CTRY_CZECH, ETSI3_WORLD, "CZ"},
{CTRY_DENMARK, ETSI1_WORLD, "DK"},
@@ -324,18 +328,22 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_GEORGIA, ETSI4_WORLD, "GE"},
{CTRY_GERMANY, ETSI1_WORLD, "DE"},
{CTRY_GREECE, ETSI1_WORLD, "GR"},
+ {CTRY_GREENLAND, ETSI1_WORLD, "GL"},
+ {CTRY_GRENEDA, FCC3_FCCA, "GD"},
+ {CTRY_GUAM, FCC1_FCCA, "GU"},
{CTRY_GUATEMALA, FCC1_FCCA, "GT"},
+ {CTRY_HAITI, ETSI1_WORLD, "HT"},
{CTRY_HONDURAS, NULL1_WORLD, "HN"},
- {CTRY_HONG_KONG, FCC2_WORLD, "HK"},
+ {CTRY_HONG_KONG, FCC3_WORLD, "HK"},
{CTRY_HUNGARY, ETSI1_WORLD, "HU"},
{CTRY_ICELAND, ETSI1_WORLD, "IS"},
{CTRY_INDIA, APL6_WORLD, "IN"},
- {CTRY_INDONESIA, APL1_WORLD, "ID"},
+ {CTRY_INDONESIA, NULL1_WORLD, "ID"},
{CTRY_IRAN, APL1_WORLD, "IR"},
{CTRY_IRELAND, ETSI1_WORLD, "IE"},
{CTRY_ISRAEL, NULL1_WORLD, "IL"},
{CTRY_ITALY, ETSI1_WORLD, "IT"},
- {CTRY_JAMAICA, ETSI1_WORLD, "JM"},
+ {CTRY_JAMAICA, FCC3_WORLD, "JM"},
{CTRY_JAPAN, MKK1_MKKA, "JP"},
{CTRY_JAPAN1, MKK1_MKKB, "JP"},
@@ -402,7 +410,7 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_KOREA_ROC, APL9_WORLD, "KR"},
{CTRY_KOREA_ROC2, APL2_WORLD, "K2"},
{CTRY_KOREA_ROC3, APL9_WORLD, "K3"},
- {CTRY_KUWAIT, NULL1_WORLD, "KW"},
+ {CTRY_KUWAIT, ETSI3_WORLD, "KW"},
{CTRY_LATVIA, ETSI1_WORLD, "LV"},
{CTRY_LEBANON, NULL1_WORLD, "LB"},
{CTRY_LIECHTENSTEIN, ETSI1_WORLD, "LI"},
@@ -414,13 +422,13 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_MALTA, ETSI1_WORLD, "MT"},
{CTRY_MEXICO, FCC1_FCCA, "MX"},
{CTRY_MONACO, ETSI4_WORLD, "MC"},
- {CTRY_MOROCCO, NULL1_WORLD, "MA"},
+ {CTRY_MOROCCO, APL4_WORLD, "MA"},
{CTRY_NEPAL, APL1_WORLD, "NP"},
{CTRY_NETHERLANDS, ETSI1_WORLD, "NL"},
{CTRY_NETHERLANDS_ANTILLES, ETSI1_WORLD, "AN"},
{CTRY_NEW_ZEALAND, FCC2_ETSIC, "NZ"},
{CTRY_NORWAY, ETSI1_WORLD, "NO"},
- {CTRY_OMAN, APL6_WORLD, "OM"},
+ {CTRY_OMAN, FCC3_WORLD, "OM"},
{CTRY_PAKISTAN, NULL1_WORLD, "PK"},
{CTRY_PANAMA, FCC1_FCCA, "PA"},
{CTRY_PAPUA_NEW_GUINEA, FCC1_WORLD, "PG"},
@@ -429,7 +437,7 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_POLAND, ETSI1_WORLD, "PL"},
{CTRY_PORTUGAL, ETSI1_WORLD, "PT"},
{CTRY_PUERTO_RICO, FCC1_FCCA, "PR"},
- {CTRY_QATAR, NULL1_WORLD, "QA"},
+ {CTRY_QATAR, APL1_WORLD, "QA"},
{CTRY_ROMANIA, NULL1_WORLD, "RO"},
{CTRY_RUSSIA, NULL1_WORLD, "RU"},
{CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"},
@@ -445,7 +453,7 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_SYRIA, NULL1_WORLD, "SY"},
{CTRY_TAIWAN, APL3_FCCA, "TW"},
{CTRY_THAILAND, FCC3_WORLD, "TH"},
- {CTRY_TRINIDAD_Y_TOBAGO, ETSI4_WORLD, "TT"},
+ {CTRY_TRINIDAD_Y_TOBAGO, FCC3_WORLD, "TT"},
{CTRY_TUNISIA, ETSI3_WORLD, "TN"},
{CTRY_TURKEY, ETSI3_WORLD, "TR"},
{CTRY_UKRAINE, NULL1_WORLD, "UA"},
@@ -456,7 +464,7 @@ static struct country_code_to_enum_rd allCountries[] = {
* would need to assign new special alpha2 to CRDA db as with the world
* regdomain and use another alpha2 */
{CTRY_UNITED_STATES_FCC49, FCC4_FCCA, "PS"},
- {CTRY_URUGUAY, APL2_WORLD, "UY"},
+ {CTRY_URUGUAY, FCC3_WORLD, "UY"},
{CTRY_UZBEKISTAN, FCC3_FCCA, "UZ"},
{CTRY_VENEZUELA, APL2_ETSIC, "VE"},
{CTRY_VIET_NAM, NULL1_WORLD, "VN"},
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 660716214d49..65b23f725a04 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -749,12 +749,6 @@ struct b43_wldev {
#endif
};
-/*
- * Include goes here to avoid a dependency problem.
- * A better fix would be to integrate xmit.h into b43.h.
- */
-#include "xmit.h"
-
/* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */
struct b43_wl {
/* Pointer to the active wireless device on this chip */
@@ -830,13 +824,9 @@ struct b43_wl {
struct b43_leds leds;
#ifdef CONFIG_B43_PIO
- /*
- * RX/TX header/tail buffers used by the frame transmit functions.
- */
- struct b43_rxhdr_fw4 rxhdr;
- struct b43_txhdr txhdr;
- u8 rx_tail[4];
- u8 tx_tail[4];
+ /* Kmalloc'ed scratch space for PIO TX/RX. Protected by wl->mutex. */
+ u8 pio_scratchspace[110] __attribute__((__aligned__(8)));
+ u8 pio_tailspace[4] __attribute__((__aligned__(8)));
#endif /* CONFIG_B43_PIO */
};
diff --git a/drivers/net/wireless/b43/leds.h b/drivers/net/wireless/b43/leds.h
index 4c56187810fc..32b66d53cdac 100644
--- a/drivers/net/wireless/b43/leds.h
+++ b/drivers/net/wireless/b43/leds.h
@@ -1,6 +1,7 @@
#ifndef B43_LEDS_H_
#define B43_LEDS_H_
+struct b43_wl;
struct b43_wldev;
#ifdef CONFIG_B43_LEDS
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index df6b26a0c05e..bf3b753a7efd 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -2955,7 +2955,7 @@ static void do_periodic_work(struct b43_wldev *dev)
/* Periodic work locking policy:
* The whole periodic work handler is protected by
* wl->mutex. If another lock is needed somewhere in the
- * pwork callchain, it's aquired in-place, where it's needed.
+ * pwork callchain, it's acquired in-place, where it's needed.
*/
static void b43_periodic_work_handler(struct work_struct *work)
{
@@ -4501,7 +4501,6 @@ static void b43_op_stop(struct ieee80211_hw *hw)
cancel_work_sync(&(wl->beacon_update_trigger));
- wiphy_rfkill_stop_polling(hw->wiphy);
mutex_lock(&wl->mutex);
if (b43_status(dev) >= B43_STAT_STARTED) {
dev = b43_wireless_core_stop(dev);
@@ -4671,7 +4670,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
{
struct b43_wl *wl = dev->wl;
struct ssb_bus *bus = dev->dev->bus;
- struct pci_dev *pdev = bus->host_pci;
+ struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL;
int err;
bool have_2ghz_phy = 0, have_5ghz_phy = 0;
u32 tmp;
@@ -4804,7 +4803,7 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
if (!list_empty(&wl->devlist)) {
/* We are not the first core on this chip. */
- pdev = dev->bus->host_pci;
+ pdev = (dev->bus->bustype == SSB_BUSTYPE_PCI) ? dev->bus->host_pci : NULL;
/* Only special chips support more than one wireless
* core, although some of the other chips have more than
* one wireless core as well. Check for this and
diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c
index 6c3a74964ab8..cd14b7e8ba80 100644
--- a/drivers/net/wireless/b43/pcmcia.c
+++ b/drivers/net/wireless/b43/pcmcia.c
@@ -65,35 +65,15 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
struct ssb_bus *ssb;
win_req_t win;
memreq_t mem;
- tuple_t tuple;
- cisparse_t parse;
int err = -ENOMEM;
int res = 0;
- unsigned char buf[64];
ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
if (!ssb)
goto out_error;
err = -ENODEV;
- tuple.DesiredTuple = CISTPL_CONFIG;
- tuple.Attributes = 0;
- tuple.TupleData = buf;
- tuple.TupleDataMax = sizeof(buf);
- tuple.TupleOffset = 0;
- res = pcmcia_get_first_tuple(dev, &tuple);
- if (res != 0)
- goto err_kfree_ssb;
- res = pcmcia_get_tuple_data(dev, &tuple);
- if (res != 0)
- goto err_kfree_ssb;
- res = pcmcia_parse_tuple(&tuple, &parse);
- if (res != 0)
- goto err_kfree_ssb;
-
- dev->conf.ConfigBase = parse.config.base;
- dev->conf.Present = parse.config.rmask[0];
dev->conf.Attributes = CONF_ENABLE_IRQ;
dev->conf.IntType = INT_MEMORY_AND_IO;
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
index 1e318d815a5b..c6987b147af4 100644
--- a/drivers/net/wireless/b43/phy_lp.c
+++ b/drivers/net/wireless/b43/phy_lp.c
@@ -379,6 +379,8 @@ static void lpphy_save_dig_flt_state(struct b43_wldev *dev)
}
}
+/* lpphy_restore_dig_flt_state is unused but kept as a reference */
+#if 0
static void lpphy_restore_dig_flt_state(struct b43_wldev *dev)
{
static const u16 addr[] = {
@@ -399,6 +401,7 @@ static void lpphy_restore_dig_flt_state(struct b43_wldev *dev)
for (i = 0; i < ARRAY_SIZE(addr); i++)
b43_phy_write(dev, addr[i], lpphy->dig_flt_state[i]);
}
+#endif
static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
{
@@ -887,6 +890,8 @@ static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain)
}
}
+/* lpphy_disable_rx_gain_override is unused but kept as a reference */
+#if 0
static void lpphy_disable_rx_gain_override(struct b43_wldev *dev)
{
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE);
@@ -902,6 +907,7 @@ static void lpphy_disable_rx_gain_override(struct b43_wldev *dev)
b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF);
}
}
+#endif
static void lpphy_enable_rx_gain_override(struct b43_wldev *dev)
{
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c
index 9b9044400218..c5cd3bc861be 100644
--- a/drivers/net/wireless/b43/pio.c
+++ b/drivers/net/wireless/b43/pio.c
@@ -342,12 +342,15 @@ static u16 tx_write_2byte_queue(struct b43_pio_txqueue *q,
q->mmio_base + B43_PIO_TXDATA,
sizeof(u16));
if (data_len & 1) {
+ u8 *tail = wl->pio_tailspace;
+ BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 2);
+
/* Write the last byte. */
ctl &= ~B43_PIO_TXCTL_WRITEHI;
b43_piotx_write16(q, B43_PIO_TXCTL, ctl);
- wl->tx_tail[0] = data[data_len - 1];
- wl->tx_tail[1] = 0;
- ssb_block_write(dev->dev, wl->tx_tail, 2,
+ tail[0] = data[data_len - 1];
+ tail[1] = 0;
+ ssb_block_write(dev->dev, tail, 2,
q->mmio_base + B43_PIO_TXDATA,
sizeof(u16));
}
@@ -393,31 +396,31 @@ static u32 tx_write_4byte_queue(struct b43_pio_txqueue *q,
q->mmio_base + B43_PIO8_TXDATA,
sizeof(u32));
if (data_len & 3) {
- wl->tx_tail[3] = 0;
+ u8 *tail = wl->pio_tailspace;
+ BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 4);
+
+ memset(tail, 0, 4);
/* Write the last few bytes. */
ctl &= ~(B43_PIO8_TXCTL_8_15 | B43_PIO8_TXCTL_16_23 |
B43_PIO8_TXCTL_24_31);
switch (data_len & 3) {
case 3:
ctl |= B43_PIO8_TXCTL_16_23 | B43_PIO8_TXCTL_8_15;
- wl->tx_tail[0] = data[data_len - 3];
- wl->tx_tail[1] = data[data_len - 2];
- wl->tx_tail[2] = data[data_len - 1];
+ tail[0] = data[data_len - 3];
+ tail[1] = data[data_len - 2];
+ tail[2] = data[data_len - 1];
break;
case 2:
ctl |= B43_PIO8_TXCTL_8_15;
- wl->tx_tail[0] = data[data_len - 2];
- wl->tx_tail[1] = data[data_len - 1];
- wl->tx_tail[2] = 0;
+ tail[0] = data[data_len - 2];
+ tail[1] = data[data_len - 1];
break;
case 1:
- wl->tx_tail[0] = data[data_len - 1];
- wl->tx_tail[1] = 0;
- wl->tx_tail[2] = 0;
+ tail[0] = data[data_len - 1];
break;
}
b43_piotx_write32(q, B43_PIO8_TXCTL, ctl);
- ssb_block_write(dev->dev, wl->tx_tail, 4,
+ ssb_block_write(dev->dev, tail, 4,
q->mmio_base + B43_PIO8_TXDATA,
sizeof(u32));
}
@@ -456,6 +459,7 @@ static int pio_tx_frame(struct b43_pio_txqueue *q,
int err;
unsigned int hdrlen;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct b43_txhdr *txhdr = (struct b43_txhdr *)wl->pio_scratchspace;
B43_WARN_ON(list_empty(&q->packets_list));
pack = list_entry(q->packets_list.next,
@@ -463,7 +467,9 @@ static int pio_tx_frame(struct b43_pio_txqueue *q,
cookie = generate_cookie(q, pack);
hdrlen = b43_txhdr_size(dev);
- err = b43_generate_txhdr(dev, (u8 *)&wl->txhdr, skb,
+ BUILD_BUG_ON(sizeof(wl->pio_scratchspace) < sizeof(struct b43_txhdr));
+ B43_WARN_ON(sizeof(wl->pio_scratchspace) < hdrlen);
+ err = b43_generate_txhdr(dev, (u8 *)txhdr, skb,
info, cookie);
if (err)
return err;
@@ -477,9 +483,9 @@ static int pio_tx_frame(struct b43_pio_txqueue *q,
pack->skb = skb;
if (q->rev >= 8)
- pio_tx_frame_4byte_queue(pack, (const u8 *)&wl->txhdr, hdrlen);
+ pio_tx_frame_4byte_queue(pack, (const u8 *)txhdr, hdrlen);
else
- pio_tx_frame_2byte_queue(pack, (const u8 *)&wl->txhdr, hdrlen);
+ pio_tx_frame_2byte_queue(pack, (const u8 *)txhdr, hdrlen);
/* Remove it from the list of available packet slots.
* It will be put back when we receive the status report. */
@@ -625,8 +631,11 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q)
unsigned int i, padding;
struct sk_buff *skb;
const char *err_msg = NULL;
+ struct b43_rxhdr_fw4 *rxhdr =
+ (struct b43_rxhdr_fw4 *)wl->pio_scratchspace;
- memset(&wl->rxhdr, 0, sizeof(wl->rxhdr));
+ BUILD_BUG_ON(sizeof(wl->pio_scratchspace) < sizeof(*rxhdr));
+ memset(rxhdr, 0, sizeof(*rxhdr));
/* Check if we have data and wait for it to get ready. */
if (q->rev >= 8) {
@@ -664,16 +673,16 @@ data_ready:
/* Get the preamble (RX header) */
if (q->rev >= 8) {
- ssb_block_read(dev->dev, &wl->rxhdr, sizeof(wl->rxhdr),
+ ssb_block_read(dev->dev, rxhdr, sizeof(*rxhdr),
q->mmio_base + B43_PIO8_RXDATA,
sizeof(u32));
} else {
- ssb_block_read(dev->dev, &wl->rxhdr, sizeof(wl->rxhdr),
+ ssb_block_read(dev->dev, rxhdr, sizeof(*rxhdr),
q->mmio_base + B43_PIO_RXDATA,
sizeof(u16));
}
/* Sanity checks. */
- len = le16_to_cpu(wl->rxhdr.frame_len);
+ len = le16_to_cpu(rxhdr->frame_len);
if (unlikely(len > 0x700)) {
err_msg = "len > 0x700";
goto rx_error;
@@ -683,7 +692,7 @@ data_ready:
goto rx_error;
}
- macstat = le32_to_cpu(wl->rxhdr.mac_status);
+ macstat = le32_to_cpu(rxhdr->mac_status);
if (macstat & B43_RX_MAC_FCSERR) {
if (!(q->dev->wl->filter_flags & FIF_FCSFAIL)) {
/* Drop frames with failed FCS. */
@@ -708,22 +717,25 @@ data_ready:
q->mmio_base + B43_PIO8_RXDATA,
sizeof(u32));
if (len & 3) {
+ u8 *tail = wl->pio_tailspace;
+ BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 4);
+
/* Read the last few bytes. */
- ssb_block_read(dev->dev, wl->rx_tail, 4,
+ ssb_block_read(dev->dev, tail, 4,
q->mmio_base + B43_PIO8_RXDATA,
sizeof(u32));
switch (len & 3) {
case 3:
- skb->data[len + padding - 3] = wl->rx_tail[0];
- skb->data[len + padding - 2] = wl->rx_tail[1];
- skb->data[len + padding - 1] = wl->rx_tail[2];
+ skb->data[len + padding - 3] = tail[0];
+ skb->data[len + padding - 2] = tail[1];
+ skb->data[len + padding - 1] = tail[2];
break;
case 2:
- skb->data[len + padding - 2] = wl->rx_tail[0];
- skb->data[len + padding - 1] = wl->rx_tail[1];
+ skb->data[len + padding - 2] = tail[0];
+ skb->data[len + padding - 1] = tail[1];
break;
case 1:
- skb->data[len + padding - 1] = wl->rx_tail[0];
+ skb->data[len + padding - 1] = tail[0];
break;
}
}
@@ -732,15 +744,18 @@ data_ready:
q->mmio_base + B43_PIO_RXDATA,
sizeof(u16));
if (len & 1) {
+ u8 *tail = wl->pio_tailspace;
+ BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 2);
+
/* Read the last byte. */
- ssb_block_read(dev->dev, wl->rx_tail, 2,
+ ssb_block_read(dev->dev, tail, 2,
q->mmio_base + B43_PIO_RXDATA,
sizeof(u16));
- skb->data[len + padding - 1] = wl->rx_tail[0];
+ skb->data[len + padding - 1] = tail[0];
}
}
- b43_rx(q->dev, skb, &wl->rxhdr);
+ b43_rx(q->dev, skb, rxhdr);
return 1;
diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c
index 7a3218c5ba7d..ffdce6f3c909 100644
--- a/drivers/net/wireless/b43/rfkill.c
+++ b/drivers/net/wireless/b43/rfkill.c
@@ -33,7 +33,8 @@ bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
& B43_MMIO_RADIO_HWENABLED_HI_MASK))
return 1;
} else {
- if (b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO)
+ if (b43_status(dev) >= B43_STAT_STARTED &&
+ b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO)
& B43_MMIO_RADIO_HWENABLED_LO_MASK)
return 1;
}
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index f4e9695ec186..7a5e294be2bc 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -27,7 +27,7 @@
*/
-#include "b43.h"
+#include "xmit.h"
#include "phy_common.h"
#include "dma.h"
#include "pio.h"
@@ -690,10 +690,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
}
memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
-
- local_bh_disable();
- ieee80211_rx(dev->wl->hw, skb);
- local_bh_enable();
+ ieee80211_rx_ni(dev->wl->hw, skb);
#if B43_DEBUG
dev->rx_count++;
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 4b60148a5e61..13ac2c05ee84 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -2277,7 +2277,7 @@ static void do_periodic_work(struct b43legacy_wldev *dev)
/* Periodic work locking policy:
* The whole periodic work handler is protected by
* wl->mutex. If another lock is needed somewhere in the
- * pwork callchain, it's aquired in-place, where it's needed.
+ * pwork callchain, it's acquired in-place, where it's needed.
*/
static void b43legacy_periodic_work_handler(struct work_struct *work)
{
@@ -3593,7 +3593,7 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
{
struct b43legacy_wl *wl = dev->wl;
struct ssb_bus *bus = dev->dev->bus;
- struct pci_dev *pdev = bus->host_pci;
+ struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL;
int err;
int have_bphy = 0;
int have_gphy = 0;
@@ -3707,7 +3707,7 @@ static int b43legacy_one_core_attach(struct ssb_device *dev,
if (!list_empty(&wl->devlist)) {
/* We are not the first core on this chip. */
- pdev = dev->bus->host_pci;
+ pdev = (dev->bus->bustype == SSB_BUSTYPE_PCI) ? dev->bus->host_pci : NULL;
/* Only special chips support more than one wireless
* core, although some of the other chips have more than
* one wireless core as well. Check for this and
diff --git a/drivers/net/wireless/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig
index c15db2293515..08f1e989653d 100644
--- a/drivers/net/wireless/hostap/Kconfig
+++ b/drivers/net/wireless/hostap/Kconfig
@@ -2,6 +2,8 @@ config HOSTAP
tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)"
depends on WLAN_80211
select WIRELESS_EXT
+ select WEXT_SPY
+ select WEXT_PRIV
select CRYPTO
select CRYPTO_ARC4
select CRYPTO_ECB
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index ad8eab4a639b..31b60dd87bfe 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -274,9 +274,6 @@ static int sandisk_enable_wireless(struct net_device *dev)
conf_reg_t reg;
struct hostap_interface *iface = netdev_priv(dev);
local_info_t *local = iface->local;
- tuple_t tuple;
- cisparse_t *parse = NULL;
- u_char buf[64];
struct hostap_cs_priv *hw_priv = local->hw_priv;
if (hw_priv->link->io.NumPorts1 < 0x42) {
@@ -285,28 +282,13 @@ static int sandisk_enable_wireless(struct net_device *dev)
goto done;
}
- parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL);
- if (parse == NULL) {
- ret = -ENOMEM;
- goto done;
- }
-
- tuple.Attributes = TUPLE_RETURN_COMMON;
- tuple.TupleData = buf;
- tuple.TupleDataMax = sizeof(buf);
- tuple.TupleOffset = 0;
-
if (hw_priv->link->manf_id != 0xd601 || hw_priv->link->card_id != 0x0101) {
/* No SanDisk manfid found */
ret = -ENODEV;
goto done;
}
- tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
- if (pcmcia_get_first_tuple(hw_priv->link, &tuple) ||
- pcmcia_get_tuple_data(hw_priv->link, &tuple) ||
- pcmcia_parse_tuple(&tuple, parse) ||
- parse->longlink_mfc.nfn < 2) {
+ if (hw_priv->link->socket->functions < 2) {
/* No multi-function links found */
ret = -ENODEV;
goto done;
@@ -354,7 +336,6 @@ static int sandisk_enable_wireless(struct net_device *dev)
udelay(10);
done:
- kfree(parse);
return ret;
}
diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig
index a8131384c6b9..59ec9eec5024 100644
--- a/drivers/net/wireless/ipw2x00/Kconfig
+++ b/drivers/net/wireless/ipw2x00/Kconfig
@@ -6,6 +6,8 @@ config IPW2100
tristate "Intel PRO/Wireless 2100 Network Connection"
depends on PCI && WLAN_80211 && CFG80211
select WIRELESS_EXT
+ select WEXT_SPY
+ select WEXT_PRIV
select FW_LOADER
select LIB80211
select LIBIPW
@@ -63,8 +65,10 @@ config IPW2100_DEBUG
config IPW2200
tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
- depends on PCI && WLAN_80211 && CFG80211
+ depends on PCI && WLAN_80211 && CFG80211 && CFG80211_WEXT
select WIRELESS_EXT
+ select WEXT_SPY
+ select WEXT_PRIV
select FW_LOADER
select LIB80211
select LIBIPW
@@ -152,6 +156,7 @@ config LIBIPW
tristate
depends on PCI && WLAN_80211 && CFG80211
select WIRELESS_EXT
+ select WEXT_SPY
select CRYPTO
select CRYPTO_ARC4
select CRYPTO_ECB
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 827824d45de9..7f169e1eccf9 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -11276,6 +11276,7 @@ static int ipw_up(struct ipw_priv *priv)
if (!(priv->config & CFG_CUSTOM_MAC))
eeprom_parse_mac(priv, priv->mac_addr);
memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
+ memcpy(priv->net_dev->perm_addr, priv->mac_addr, ETH_ALEN);
for (j = 0; j < ARRAY_SIZE(ipw_geos); j++) {
if (!memcmp(&priv->eeprom[EEPROM_COUNTRY_CODE],
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 99310c033253..c82c97be7bfa 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -1,17 +1,7 @@
config IWLWIFI
tristate "Intel Wireless Wifi"
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
- select LIB80211
select FW_LOADER
- select MAC80211_LEDS if IWLWIFI_LEDS
- select LEDS_CLASS if IWLWIFI_LEDS
-
-config IWLWIFI_LEDS
- bool "Enable LED support in iwlagn and iwl3945 drivers"
- depends on IWLWIFI
- default y
- ---help---
- Select this if you want LED support.
config IWLWIFI_SPECTRUM_MEASUREMENT
bool "Enable Spectrum Measurement in iwlagn driver"
@@ -50,6 +40,24 @@ config IWLWIFI_DEBUGFS
---help---
Enable creation of debugfs files for the iwlwifi drivers.
+config IWLWIFI_DEVICE_TRACING
+ bool "iwlwifi device access tracing"
+ depends on IWLWIFI
+ depends on EVENT_TRACING
+ help
+ Say Y here to trace all commands, including TX frames and IO
+ accesses, sent to the device. If you say yes, iwlwifi will
+ register with the ftrace framework for event tracing and dump
+ all this information to the ringbuffer, you may need to
+ increase the ringbuffer size. See the ftrace documentation
+ for more information.
+
+ When tracing is not enabled, this option still has some
+ (though rather small) overhead.
+
+ If unsure, say Y so we can help you better when problems
+ occur.
+
config IWLAGN
tristate "Intel Wireless WiFi Next Gen AGN (iwlagn)"
depends on IWLWIFI
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 1d4e0a226fd4..7f82044af242 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -1,20 +1,22 @@
obj-$(CONFIG_IWLWIFI) += iwlcore.o
iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o
iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o
-iwlcore-objs += iwl-scan.o
+iwlcore-objs += iwl-scan.o iwl-led.o
iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
-iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o
iwlcore-$(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) += iwl-spectrum.o
+iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
+CFLAGS_iwl-devtrace.o := -I$(src)
+
+# AGN
obj-$(CONFIG_IWLAGN) += iwlagn.o
-iwlagn-objs := iwl-agn.o iwl-agn-rs.o
+iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o
iwlagn-$(CONFIG_IWL4965) += iwl-4965.o
iwlagn-$(CONFIG_IWL5000) += iwl-5000.o
iwlagn-$(CONFIG_IWL5000) += iwl-6000.o
iwlagn-$(CONFIG_IWL5000) += iwl-1000.o
+# 3945
obj-$(CONFIG_IWL3945) += iwl3945.o
iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl-3945-led.o
-
-
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 2716b91ba9fa..3a645e485dda 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -44,6 +44,7 @@
#include "iwl-sta.h"
#include "iwl-helpers.h"
#include "iwl-5000-hw.h"
+#include "iwl-agn-led.h"
/* Highest firmware API version supported */
#define IWL1000_UCODE_API_MAX 3
@@ -76,7 +77,10 @@ static void iwl1000_set_ct_threshold(struct iwl_priv *priv)
/* NIC configuration for 1000 series */
static void iwl1000_nic_config(struct iwl_priv *priv)
{
- iwl5000_nic_config(priv);
+ /* set CSR_HW_CONFIG_REG for uCode use */
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
+ CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
/* Setting digital SVR for 1000 card to 1.32V */
/* locking is acquired in iwl_set_bits_mask_prph() function */
@@ -106,9 +110,8 @@ static struct iwl_lib_ops iwl1000_lib = {
.send_tx_power = iwl5000_send_tx_power,
.update_chain_flags = iwl_update_chain_flags,
.apm_ops = {
- .init = iwl5000_apm_init,
- .reset = iwl5000_apm_reset,
- .stop = iwl5000_apm_stop,
+ .init = iwl_apm_init,
+ .stop = iwl_apm_stop,
.config = iwl1000_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
@@ -142,6 +145,7 @@ static struct iwl_ops iwl1000_ops = {
.lib = &iwl1000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
+ .led = &iwlagn_led_ops,
};
struct iwl_cfg iwl1000_bgn_cfg = {
@@ -152,14 +156,48 @@ struct iwl_cfg iwl1000_bgn_cfg = {
.sku = IWL_SKU_G|IWL_SKU_N,
.ops = &iwl1000_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
- .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+ .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_A,
.valid_rx_ant = ANT_AB,
- .need_pll_cfg = true,
+ .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+ .set_l0s = false,
+ .use_bsm = false,
.max_ll_items = OTP_MAX_LL_ITEMS_1000,
.shadow_ram_support = false,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .support_ct_kill_exit = true,
};
+struct iwl_cfg iwl1000_bg_cfg = {
+ .name = "1000 Series BG",
+ .fw_name_pre = IWL1000_FW_PRE,
+ .ucode_api_max = IWL1000_UCODE_API_MAX,
+ .ucode_api_min = IWL1000_UCODE_API_MIN,
+ .sku = IWL_SKU_G,
+ .ops = &iwl1000_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
+ .mod_params = &iwl50_mod_params,
+ .valid_tx_ant = ANT_A,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+ .set_l0s = false,
+ .use_bsm = false,
+ .max_ll_items = OTP_MAX_LL_ITEMS_1000,
+ .shadow_ram_support = false,
+ .ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .support_ct_kill_exit = true,
+};
+
+MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
index 16772780c5b0..6fd10d443ba3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -71,12 +71,6 @@
#include "iwl-eeprom.h"
-/*
- * uCode queue management definitions ...
- * Queue #4 is the command queue for 3945 and 4965.
- */
-#define IWL_CMD_QUEUE_NUM 4
-
/* Time constants */
#define SHORT_SLOT_TIME 9
#define LONG_SLOT_TIME 20
@@ -254,12 +248,6 @@ struct iwl3945_eeprom {
#define TFD_CTL_PAD_SET(n) (n << 28)
#define TFD_CTL_PAD_GET(ctl) (ctl >> 28)
-/*
- * RX related structures and functions
- */
-#define RX_FREE_BUFFERS 64
-#define RX_LOW_WATERMARK 8
-
/* Sizes and addresses for instruction and data memory (SRAM) in
* 3945's embedded processor. Driver access is via HBUS_TARG_MEM_* regs. */
#define IWL39_RTC_INST_LOWER_BOUND (0x000000)
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
index 8c29ded7d02c..a871d09d598f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
@@ -24,8 +24,6 @@
*
*****************************************************************************/
-#ifdef CONFIG_IWLWIFI_LEDS
-
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -43,388 +41,51 @@
#include "iwl-3945.h"
#include "iwl-core.h"
#include "iwl-dev.h"
+#include "iwl-3945-led.h"
-#ifdef CONFIG_IWLWIFI_DEBUG
-static const char *led_type_str[] = {
- __stringify(IWL_LED_TRG_TX),
- __stringify(IWL_LED_TRG_RX),
- __stringify(IWL_LED_TRG_ASSOC),
- __stringify(IWL_LED_TRG_RADIO),
- NULL
-};
-#endif /* CONFIG_IWLWIFI_DEBUG */
-
-static const struct {
- u16 brightness;
- u8 on_time;
- u8 off_time;
-} blink_tbl[] =
-{
- {300, 25, 25},
- {200, 40, 40},
- {100, 55, 55},
- {70, 65, 65},
- {50, 75, 75},
- {20, 85, 85},
- {15, 95, 95 },
- {10, 110, 110},
- {5, 130, 130},
- {0, 167, 167},
- /* SOLID_ON */
- {-1, IWL_LED_SOLID, 0}
-};
-
-#define IWL_1MB_RATE (128 * 1024)
-#define IWL_LED_THRESHOLD (16)
-#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /*Exclude Solid on*/
-#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1)
-
-static void iwl3945_led_cmd_callback(struct iwl_priv *priv,
- struct iwl_device_cmd *cmd,
- struct sk_buff *skb)
-{
-}
-
-static inline int iwl3945_brightness_to_idx(enum led_brightness brightness)
-{
- return fls(0x000000FF & (u32)brightness);
-}
/* Send led command */
-static int iwl_send_led_cmd(struct iwl_priv *priv,
- struct iwl_led_cmd *led_cmd)
+static int iwl3945_send_led_cmd(struct iwl_priv *priv,
+ struct iwl_led_cmd *led_cmd)
{
struct iwl_host_cmd cmd = {
.id = REPLY_LEDS_CMD,
.len = sizeof(struct iwl_led_cmd),
.data = led_cmd,
.flags = CMD_ASYNC,
- .callback = iwl3945_led_cmd_callback,
+ .callback = NULL,
};
return iwl_send_cmd(priv, &cmd);
}
-
-
-/* Set led on command */
-static int iwl3945_led_pattern(struct iwl_priv *priv, int led_id,
- unsigned int idx)
-{
- struct iwl_led_cmd led_cmd = {
- .id = led_id,
- .interval = IWL_DEF_LED_INTRVL
- };
-
- BUG_ON(idx > IWL_MAX_BLINK_TBL);
-
- led_cmd.on = blink_tbl[idx].on_time;
- led_cmd.off = blink_tbl[idx].off_time;
-
- return iwl_send_led_cmd(priv, &led_cmd);
-}
-
-
/* Set led on command */
-static int iwl3945_led_on(struct iwl_priv *priv, int led_id)
+static int iwl3945_led_on(struct iwl_priv *priv)
{
struct iwl_led_cmd led_cmd = {
- .id = led_id,
+ .id = IWL_LED_LINK,
.on = IWL_LED_SOLID,
.off = 0,
.interval = IWL_DEF_LED_INTRVL
};
- return iwl_send_led_cmd(priv, &led_cmd);
+ return iwl3945_send_led_cmd(priv, &led_cmd);
}
/* Set led off command */
-static int iwl3945_led_off(struct iwl_priv *priv, int led_id)
+static int iwl3945_led_off(struct iwl_priv *priv)
{
struct iwl_led_cmd led_cmd = {
- .id = led_id,
+ .id = IWL_LED_LINK,
.on = 0,
.off = 0,
.interval = IWL_DEF_LED_INTRVL
};
- IWL_DEBUG_LED(priv, "led off %d\n", led_id);
- return iwl_send_led_cmd(priv, &led_cmd);
+ IWL_DEBUG_LED(priv, "led off\n");
+ return iwl3945_send_led_cmd(priv, &led_cmd);
}
-/*
- * Set led on in case of association
- * */
-static int iwl3945_led_associate(struct iwl_priv *priv, int led_id)
-{
- IWL_DEBUG_LED(priv, "Associated\n");
-
- priv->allow_blinking = 1;
- return iwl3945_led_on(priv, led_id);
-}
-/* Set Led off in case of disassociation */
-static int iwl3945_led_disassociate(struct iwl_priv *priv, int led_id)
-{
- IWL_DEBUG_LED(priv, "Disassociated\n");
-
- priv->allow_blinking = 0;
-
- return 0;
-}
-
-/*
- * brightness call back function for Tx/Rx LED
- */
-static int iwl3945_led_associated(struct iwl_priv *priv, int led_id)
-{
- if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
- !test_bit(STATUS_READY, &priv->status))
- return 0;
-
-
- /* start counting Tx/Rx bytes */
- if (!priv->last_blink_time && priv->allow_blinking)
- priv->last_blink_time = jiffies;
- return 0;
-}
-
-/*
- * brightness call back for association and radio
- */
-static void iwl3945_led_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
-{
- struct iwl_led *led = container_of(led_cdev,
- struct iwl_led, led_dev);
- struct iwl_priv *priv = led->priv;
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
- IWL_DEBUG_LED(priv, "Led type = %s brightness = %d\n",
- led_type_str[led->type], brightness);
-
- switch (brightness) {
- case LED_FULL:
- if (led->led_on)
- led->led_on(priv, IWL_LED_LINK);
- break;
- case LED_OFF:
- if (led->led_off)
- led->led_off(priv, IWL_LED_LINK);
- break;
- default:
- if (led->led_pattern) {
- int idx = iwl3945_brightness_to_idx(brightness);
- led->led_pattern(priv, IWL_LED_LINK, idx);
- }
- break;
- }
-}
-
-/*
- * Register led class with the system
- */
-static int iwl3945_led_register_led(struct iwl_priv *priv,
- struct iwl_led *led,
- enum led_type type, u8 set_led,
- char *trigger)
-{
- struct device *device = wiphy_dev(priv->hw->wiphy);
- int ret;
-
- led->led_dev.name = led->name;
- led->led_dev.brightness_set = iwl3945_led_brightness_set;
- led->led_dev.default_trigger = trigger;
-
- led->priv = priv;
- led->type = type;
-
- ret = led_classdev_register(device, &led->led_dev);
- if (ret) {
- IWL_ERR(priv, "Error: failed to register led handler.\n");
- return ret;
- }
-
- led->registered = 1;
-
- if (set_led && led->led_on)
- led->led_on(priv, IWL_LED_LINK);
- return 0;
-}
-
-
-/*
- * calculate blink rate according to last 2 sec Tx/Rx activities
- */
-static inline u8 get_blink_rate(struct iwl_priv *priv)
-{
- int index;
- s64 tpt = priv->rxtxpackets;
-
- if (tpt < 0)
- tpt = -tpt;
-
- IWL_DEBUG_LED(priv, "tpt %lld \n", (long long)tpt);
-
- if (!priv->allow_blinking)
- index = IWL_MAX_BLINK_TBL;
- else
- for (index = 0; index < IWL_MAX_BLINK_TBL; index++)
- if (tpt > (blink_tbl[index].brightness * IWL_1MB_RATE))
- break;
-
- IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", index);
- return index;
-}
-
-/*
- * this function called from handler. Since setting Led command can
- * happen very frequent we postpone led command to be called from
- * REPLY handler so we know ucode is up
- */
-void iwl3945_led_background(struct iwl_priv *priv)
-{
- u8 blink_idx;
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
- priv->last_blink_time = 0;
- return;
- }
- if (iwl_is_rfkill(priv)) {
- priv->last_blink_time = 0;
- return;
- }
-
- if (!priv->allow_blinking) {
- priv->last_blink_time = 0;
- if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) {
- priv->last_blink_rate = IWL_SOLID_BLINK_IDX;
- iwl3945_led_pattern(priv, IWL_LED_LINK,
- IWL_SOLID_BLINK_IDX);
- }
- return;
- }
- if (!priv->last_blink_time ||
- !time_after(jiffies, priv->last_blink_time +
- msecs_to_jiffies(1000)))
- return;
-
- blink_idx = get_blink_rate(priv);
-
- /* call only if blink rate change */
- if (blink_idx != priv->last_blink_rate)
- iwl3945_led_pattern(priv, IWL_LED_LINK, blink_idx);
-
- priv->last_blink_time = jiffies;
- priv->last_blink_rate = blink_idx;
- priv->rxtxpackets = 0;
-}
-
-
-/* Register all led handler */
-int iwl3945_led_register(struct iwl_priv *priv)
-{
- char *trigger;
- int ret;
-
- priv->last_blink_rate = 0;
- priv->rxtxpackets = 0;
- priv->led_tpt = 0;
- priv->last_blink_time = 0;
- priv->allow_blinking = 0;
-
- trigger = ieee80211_get_radio_led_name(priv->hw);
- snprintf(priv->led[IWL_LED_TRG_RADIO].name,
- sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio",
- wiphy_name(priv->hw->wiphy));
-
- priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on;
- priv->led[IWL_LED_TRG_RADIO].led_off = iwl3945_led_off;
- priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
-
- ret = iwl3945_led_register_led(priv,
- &priv->led[IWL_LED_TRG_RADIO],
- IWL_LED_TRG_RADIO, 1, trigger);
-
- if (ret)
- goto exit_fail;
-
- trigger = ieee80211_get_assoc_led_name(priv->hw);
- snprintf(priv->led[IWL_LED_TRG_ASSOC].name,
- sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s::assoc",
- wiphy_name(priv->hw->wiphy));
-
- ret = iwl3945_led_register_led(priv,
- &priv->led[IWL_LED_TRG_ASSOC],
- IWL_LED_TRG_ASSOC, 0, trigger);
-
- /* for assoc always turn led on */
- priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_associate;
- priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_disassociate;
- priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL;
-
- if (ret)
- goto exit_fail;
-
- trigger = ieee80211_get_rx_led_name(priv->hw);
- snprintf(priv->led[IWL_LED_TRG_RX].name,
- sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s::RX",
- wiphy_name(priv->hw->wiphy));
-
- ret = iwl3945_led_register_led(priv,
- &priv->led[IWL_LED_TRG_RX],
- IWL_LED_TRG_RX, 0, trigger);
-
- priv->led[IWL_LED_TRG_RX].led_on = iwl3945_led_associated;
- priv->led[IWL_LED_TRG_RX].led_off = iwl3945_led_associated;
- priv->led[IWL_LED_TRG_RX].led_pattern = iwl3945_led_pattern;
-
- if (ret)
- goto exit_fail;
-
- trigger = ieee80211_get_tx_led_name(priv->hw);
- snprintf(priv->led[IWL_LED_TRG_TX].name,
- sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s::TX",
- wiphy_name(priv->hw->wiphy));
-
- ret = iwl3945_led_register_led(priv,
- &priv->led[IWL_LED_TRG_TX],
- IWL_LED_TRG_TX, 0, trigger);
-
- priv->led[IWL_LED_TRG_TX].led_on = iwl3945_led_associated;
- priv->led[IWL_LED_TRG_TX].led_off = iwl3945_led_associated;
- priv->led[IWL_LED_TRG_TX].led_pattern = iwl3945_led_pattern;
-
- if (ret)
- goto exit_fail;
-
- return 0;
-
-exit_fail:
- iwl3945_led_unregister(priv);
- return ret;
-}
-
-
-/* unregister led class */
-static void iwl3945_led_unregister_led(struct iwl_led *led, u8 set_led)
-{
- if (!led->registered)
- return;
-
- led_classdev_unregister(&led->led_dev);
-
- if (set_led)
- led->led_dev.brightness_set(&led->led_dev, LED_OFF);
- led->registered = 0;
-}
-
-/* Unregister all led handlers */
-void iwl3945_led_unregister(struct iwl_priv *priv)
-{
- iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_ASSOC], 0);
- iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_RX], 0);
- iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_TX], 0);
- iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_RADIO], 1);
-}
-
-#endif
+const struct iwl_led_ops iwl3945_led_ops = {
+ .cmd = iwl3945_send_led_cmd,
+ .on = iwl3945_led_on,
+ .off = iwl3945_led_off,
+};
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h
index 3b65642258ca..5a1033ca7aaa 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h
@@ -24,23 +24,9 @@
*
*****************************************************************************/
-#ifndef IWL3945_LEDS_H
-#define IWL3945_LEDS_H
+#ifndef __iwl_3945_led_h__
+#define __iwl_3945_led_h__
-struct iwl_priv;
+extern const struct iwl_led_ops iwl3945_led_ops;
-#ifdef CONFIG_IWLWIFI_LEDS
-
-#include "iwl-led.h"
-
-extern int iwl3945_led_register(struct iwl_priv *priv);
-extern void iwl3945_led_unregister(struct iwl_priv *priv);
-extern void iwl3945_led_background(struct iwl_priv *priv);
-
-#else
-static inline int iwl3945_led_register(struct iwl_priv *priv) { return 0; }
-static inline void iwl3945_led_unregister(struct iwl_priv *priv) {}
-static inline void iwl3945_led_background(struct iwl_priv *priv) {}
-
-#endif /* IWLWIFI_LEDS*/
-#endif /* IWL3945_LEDS_H */
+#endif /* __iwl_3945_led_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index f059b49dc691..562860b80124 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -47,7 +47,8 @@
#include "iwl-eeprom.h"
#include "iwl-helpers.h"
#include "iwl-core.h"
-#include "iwl-agn-rs.h"
+#include "iwl-led.h"
+#include "iwl-3945-led.h"
#define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np) \
[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \
@@ -293,7 +294,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
u16 sequence = le16_to_cpu(pkt->hdr.sequence);
int txq_id = SEQ_TO_QUEUE(sequence);
int index = SEQ_TO_INDEX(sequence);
@@ -353,16 +354,12 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
(int)sizeof(struct iwl3945_notif_statistics),
le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
memcpy(&priv->statistics_39, pkt->u.raw, sizeof(priv->statistics_39));
-
- iwl3945_led_background(priv);
-
- priv->last_statistics_time = jiffies;
}
/******************************************************************************
@@ -545,14 +542,18 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb,
struct ieee80211_rx_status *stats)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
- short len = le16_to_cpu(rx_hdr->len);
+ u16 len = le16_to_cpu(rx_hdr->len);
+ struct sk_buff *skb;
+ int ret;
+ __le16 fc = hdr->frame_control;
/* We received data from the HW, so stop the watchdog */
- if (unlikely((len + IWL39_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) {
+ if (unlikely(len + IWL39_RX_FRAME_SIZE >
+ PAGE_SIZE << priv->hw_params.rx_page_order)) {
IWL_DEBUG_DROP(priv, "Corruption detected!\n");
return;
}
@@ -564,24 +565,49 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
return;
}
- skb_reserve(rxb->skb, (void *)rx_hdr->payload - (void *)pkt);
- /* Set the size of the skb to the size of the frame */
- skb_put(rxb->skb, le16_to_cpu(rx_hdr->len));
+ skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC);
+ if (!skb) {
+ IWL_ERR(priv, "alloc_skb failed\n");
+ return;
+ }
if (!iwl3945_mod_params.sw_crypto)
iwl_set_decrypted_flag(priv,
- (struct ieee80211_hdr *)rxb->skb->data,
+ (struct ieee80211_hdr *)rxb_addr(rxb),
le32_to_cpu(rx_end->status), stats);
-#ifdef CONFIG_IWLWIFI_LEDS
- if (ieee80211_is_data(hdr->frame_control))
- priv->rxtxpackets += len;
-#endif
- iwl_update_stats(priv, false, hdr->frame_control, len);
+ skb_add_rx_frag(skb, 0, rxb->page,
+ (void *)rx_hdr->payload - (void *)pkt, len);
+
+ /* mac80211 currently doesn't support paged SKB. Convert it to
+ * linear SKB for management frame and data frame requires
+ * software decryption or software defragementation. */
+ if (ieee80211_is_mgmt(fc) ||
+ ieee80211_has_protected(fc) ||
+ ieee80211_has_morefrags(fc) ||
+ le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)
+ ret = skb_linearize(skb);
+ else
+ ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ?
+ 0 : -ENOMEM;
+
+ if (ret) {
+ kfree_skb(skb);
+ goto out;
+ }
- memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
- ieee80211_rx_irqsafe(priv->hw, rxb->skb);
- rxb->skb = NULL;
+ /*
+ * XXX: We cannot touch the page and its virtual memory (pkt) after
+ * here. It might have already been freed by the above skb change.
+ */
+
+ iwl_update_stats(priv, false, fc, len);
+ memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
+
+ ieee80211_rx(priv->hw, skb);
+ out:
+ priv->alloc_rxb_page--;
+ rxb->page = NULL;
}
#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
@@ -591,7 +617,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
{
struct ieee80211_hdr *header;
struct ieee80211_rx_status rx_status;
- struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
@@ -791,29 +817,31 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
u8 data_retry_limit;
__le32 tx_flags;
__le16 fc = hdr->frame_control;
- struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
+ struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
rate = iwl3945_rates[rate_index].plcp;
- tx_flags = tx->tx_flags;
+ tx_flags = tx_cmd->tx_flags;
/* We need to figure out how to get the sta->supp_rates while
* in this running context */
rate_mask = IWL_RATES_MASK;
+
+ /* Set retry limit on DATA packets and Probe Responses*/
+ if (ieee80211_is_probe_resp(fc))
+ data_retry_limit = 3;
+ else
+ data_retry_limit = IWL_DEFAULT_TX_RETRY;
+ tx_cmd->data_retry_limit = data_retry_limit;
+
if (tx_id >= IWL_CMD_QUEUE_NUM)
rts_retry_limit = 3;
else
rts_retry_limit = 7;
- if (ieee80211_is_probe_resp(fc)) {
- data_retry_limit = 3;
- if (data_retry_limit < rts_retry_limit)
- rts_retry_limit = data_retry_limit;
- } else
- data_retry_limit = IWL_DEFAULT_TX_RETRY;
-
- if (priv->data_retry_limit != -1)
- data_retry_limit = priv->data_retry_limit;
+ if (data_retry_limit < rts_retry_limit)
+ rts_retry_limit = data_retry_limit;
+ tx_cmd->rts_retry_limit = rts_retry_limit;
if (ieee80211_is_mgmt(fc)) {
switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
@@ -831,22 +859,20 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
}
}
- tx->rts_retry_limit = rts_retry_limit;
- tx->data_retry_limit = data_retry_limit;
- tx->rate = rate;
- tx->tx_flags = tx_flags;
+ tx_cmd->rate = rate;
+ tx_cmd->tx_flags = tx_flags;
/* OFDM */
- tx->supp_rates[0] =
+ tx_cmd->supp_rates[0] =
((rate_mask & IWL_OFDM_RATES_MASK) >> IWL_FIRST_OFDM_RATE) & 0xFF;
/* CCK */
- tx->supp_rates[1] = (rate_mask & 0xF);
+ tx_cmd->supp_rates[1] = (rate_mask & 0xF);
IWL_DEBUG_RATE(priv, "Tx sta id: %d, rate: %d (plcp), flags: 0x%4X "
"cck/ofdm mask: 0x%x/0x%x\n", sta_id,
- tx->rate, le32_to_cpu(tx->tx_flags),
- tx->supp_rates[1], tx->supp_rates[0]);
+ tx_cmd->rate, le32_to_cpu(tx_cmd->tx_flags),
+ tx_cmd->supp_rates[1], tx_cmd->supp_rates[0]);
}
u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags)
@@ -962,6 +988,11 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
iwl3945_hw_txq_ctx_free(priv);
+ /* allocate tx queue structure */
+ rc = iwl_alloc_txq_mem(priv);
+ if (rc)
+ return rc;
+
/* Tx CMD queue */
rc = iwl3945_tx_reset(priv);
if (rc)
@@ -986,41 +1017,25 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
return rc;
}
+
+/*
+ * Start up 3945's basic functionality after it has been reset
+ * (e.g. after platform boot, or shutdown via iwl_apm_stop())
+ * NOTE: This does not load uCode nor start the embedded processor
+ */
static int iwl3945_apm_init(struct iwl_priv *priv)
{
- int ret;
-
- iwl_power_initialize(priv);
-
- iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+ int ret = iwl_apm_init(priv);
- /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */
- iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
-
- /* set "initialization complete" bit to move adapter
- * D0U* --> D0A* state */
- iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
- ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
- if (ret < 0) {
- IWL_DEBUG_INFO(priv, "Failed to init the card\n");
- goto out;
- }
-
- /* enable DMA */
- iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT |
- APMG_CLK_VAL_BSM_CLK_RQT);
-
- udelay(20);
+ /* Clear APMG (NIC's internal power management) interrupts */
+ iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0);
+ iwl_write_prph(priv, APMG_RTC_INT_STT_REG, 0xFFFFFFFF);
- /* disable L1-Active */
- iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
- APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+ /* Reset radio chip */
+ iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ);
+ udelay(5);
+ iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ);
-out:
return ret;
}
@@ -1145,12 +1160,16 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv)
int txq_id;
/* Tx queues */
- for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
- if (txq_id == IWL_CMD_QUEUE_NUM)
- iwl_cmd_queue_free(priv);
- else
- iwl_tx_queue_free(priv, txq_id);
+ if (priv->txq)
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num;
+ txq_id++)
+ if (txq_id == IWL_CMD_QUEUE_NUM)
+ iwl_cmd_queue_free(priv);
+ else
+ iwl_tx_queue_free(priv, txq_id);
+ /* free tx queue structure */
+ iwl_free_txq_mem(priv);
}
void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
@@ -1159,6 +1178,7 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
/* stop SCD */
iwl_write_prph(priv, ALM_SCD_MODE_REG, 0);
+ iwl_write_prph(priv, ALM_SCD_TXFACT_REG, 0);
/* reset TFD queues */
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
@@ -1171,85 +1191,6 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
iwl3945_hw_txq_ctx_free(priv);
}
-static int iwl3945_apm_stop_master(struct iwl_priv *priv)
-{
- int ret = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* set stop master bit */
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
-
- iwl_poll_direct_bit(priv, CSR_RESET,
- CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
-
- if (ret < 0)
- goto out;
-
-out:
- spin_unlock_irqrestore(&priv->lock, flags);
- IWL_DEBUG_INFO(priv, "stop master\n");
-
- return ret;
-}
-
-static void iwl3945_apm_stop(struct iwl_priv *priv)
-{
- unsigned long flags;
-
- iwl3945_apm_stop_master(priv);
-
- spin_lock_irqsave(&priv->lock, flags);
-
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
-
- udelay(10);
- /* clear "init complete" move adapter D0A* --> D0U state */
- iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static int iwl3945_apm_reset(struct iwl_priv *priv)
-{
- iwl3945_apm_stop_master(priv);
-
-
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
- udelay(10);
-
- iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
- iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
-
- iwl_write_prph(priv, APMG_CLK_CTRL_REG,
- APMG_CLK_VAL_BSM_CLK_RQT);
-
- iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0);
- iwl_write_prph(priv, APMG_RTC_INT_STT_REG,
- 0xFFFFFFFF);
-
- /* enable DMA */
- iwl_write_prph(priv, APMG_CLK_EN_REG,
- APMG_CLK_VAL_DMA_CLK_RQT |
- APMG_CLK_VAL_BSM_CLK_RQT);
- udelay(10);
-
- iwl_set_bits_prph(priv, APMG_PS_CTRL_REG,
- APMG_PS_CTRL_VAL_RESET_REQ);
- udelay(5);
- iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG,
- APMG_PS_CTRL_VAL_RESET_REQ);
-
- /* Clear the 'host command active' bit... */
- clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
-
- wake_up_interruptible(&priv->wait_command_queue);
-
- return 0;
-}
-
/**
* iwl3945_hw_reg_adjust_power_by_temp
* return index delta into power gain settings table
@@ -1858,7 +1799,7 @@ int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
{
int rc = 0;
- struct iwl_rx_packet *res = NULL;
+ struct iwl_rx_packet *pkt;
struct iwl3945_rxon_assoc_cmd rxon_assoc;
struct iwl_host_cmd cmd = {
.id = REPLY_RXON_ASSOC,
@@ -1887,14 +1828,14 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
if (rc)
return rc;
- res = (struct iwl_rx_packet *)cmd.reply_skb->data;
- if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ pkt = (struct iwl_rx_packet *)cmd.reply_page;
+ if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n");
rc = -EIO;
}
- priv->alloc_rxb_skb--;
- dev_kfree_skb_any(cmd.reply_skb);
+ priv->alloc_rxb_page--;
+ free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
return rc;
}
@@ -2042,12 +1983,6 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
return 0;
}
-/* will add 3945 channel switch cmd handling later */
-int iwl3945_hw_channel_switch(struct iwl_priv *priv, u16 channel)
-{
- return 0;
-}
-
/**
* iwl3945_reg_txpower_periodic - called when time to check our temperature.
*
@@ -2557,11 +2492,10 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
}
/* Assign number of Usable TX queues */
- priv->hw_params.max_txq_num = IWL39_NUM_QUEUES;
+ priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd);
- priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K;
- priv->hw_params.max_pkt_size = 2342;
+ 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;
@@ -2844,8 +2778,7 @@ static struct iwl_lib_ops iwl3945_lib = {
.dump_nic_error_log = iwl3945_dump_nic_error_log,
.apm_ops = {
.init = iwl3945_apm_init,
- .reset = iwl3945_apm_reset,
- .stop = iwl3945_apm_stop,
+ .stop = iwl_apm_stop,
.config = iwl3945_nic_config,
.set_pwr_src = iwl3945_set_pwr_src,
},
@@ -2874,6 +2807,7 @@ static struct iwl_lib_ops iwl3945_lib = {
static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
.get_hcmd_size = iwl3945_get_hcmd_size,
.build_addsta_hcmd = iwl3945_build_addsta_hcmd,
+ .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,
};
static struct iwl_ops iwl3945_ops = {
@@ -2881,6 +2815,7 @@ static struct iwl_ops iwl3945_ops = {
.lib = &iwl3945_lib,
.hcmd = &iwl3945_hcmd,
.utils = &iwl3945_hcmd_utils,
+ .led = &iwl3945_led_ops,
};
static struct iwl_cfg iwl3945_bg_cfg = {
@@ -2892,9 +2827,14 @@ static struct iwl_cfg iwl3945_bg_cfg = {
.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,
};
static struct iwl_cfg iwl3945_abg_cfg = {
@@ -2906,9 +2846,11 @@ static struct iwl_cfg iwl3945_abg_cfg = {
.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,
};
struct pci_device_id iwl3945_hw_card_ids[] = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index 21679bf3a1aa..ebb999a51b58 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -46,7 +46,7 @@ extern struct pci_device_id iwl3945_hw_card_ids[];
#include "iwl-debug.h"
#include "iwl-power.h"
#include "iwl-dev.h"
-#include "iwl-3945-led.h"
+#include "iwl-led.h"
/* Highest firmware API version supported */
#define IWL3945_UCODE_API_MAX 2
@@ -130,12 +130,6 @@ struct iwl3945_frame {
#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
-/*
- * RX related structures and functions
- */
-#define RX_FREE_BUFFERS 64
-#define RX_LOW_WATERMARK 8
-
#define SUP_RATE_11A_MAX_NUM_CHANNELS 8
#define SUP_RATE_11B_MAX_NUM_CHANNELS 4
#define SUP_RATE_11G_MAX_NUM_CHANNELS 12
@@ -280,8 +274,6 @@ extern void iwl3945_config_ap(struct iwl_priv *priv);
*/
extern u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *bssid);
-extern int iwl3945_hw_channel_switch(struct iwl_priv *priv, u16 channel);
-
/*
* Forward declare iwl-3945.c functions for iwl-base.c
*/
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
index b34322a32458..c606366b582c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -76,12 +76,9 @@
/*
* uCode queue management definitions ...
- * Queue #4 is the command queue for 3945 and 4965; map it to Tx FIFO chnl 4.
* The first queue used for block-ack aggregation is #7 (4965 only).
* All block-ack aggregation queues should map to Tx DMA/FIFO channel 7.
*/
-#define IWL_CMD_QUEUE_NUM 4
-#define IWL_CMD_FIFO_NUM 4
#define IWL49_FIRST_AMPDU_QUEUE 7
/* Time constants */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 6f703a041847..62c95ebcbaa2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -45,6 +45,7 @@
#include "iwl-helpers.h"
#include "iwl-calib.h"
#include "iwl-sta.h"
+#include "iwl-agn-led.h"
static int iwl4965_send_tx_power(struct iwl_priv *priv);
static int iwl4965_hw_get_temperature(struct iwl_priv *priv);
@@ -62,8 +63,6 @@ static int iwl4965_hw_get_temperature(struct iwl_priv *priv);
/* module parameters */
static struct iwl_mod_params iwl4965_mod_params = {
- .num_of_queues = IWL49_NUM_QUEUES,
- .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES,
.amsdu_size_8K = 1,
.restart_fw = 1,
/* the rest are 0 by default */
@@ -319,63 +318,13 @@ static void iwl4965_txq_set_sched(struct iwl_priv *priv, u32 mask)
iwl_write_prph(priv, IWL49_SCD_TXFACT, mask);
}
-static int iwl4965_apm_init(struct iwl_priv *priv)
-{
- int ret = 0;
-
- iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
-
- /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */
- iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
-
- /* set "initialization complete" bit to move adapter
- * D0U* --> D0A* state */
- iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
- /* wait for clock stabilization */
- ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
- if (ret < 0) {
- IWL_DEBUG_INFO(priv, "Failed to init the card\n");
- goto out;
- }
-
- /* enable DMA */
- iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT |
- APMG_CLK_VAL_BSM_CLK_RQT);
-
- udelay(20);
-
- /* disable L1-Active */
- iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
- APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-
-out:
- return ret;
-}
-
-
static void iwl4965_nic_config(struct iwl_priv *priv)
{
unsigned long flags;
u16 radio_cfg;
- u16 lctl;
spin_lock_irqsave(&priv->lock, flags);
- lctl = iwl_pcie_link_ctl(priv);
-
- /* HW bug W/A - negligible power consumption */
- /* L1-ASPM is enabled by BIOS */
- if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
- /* L1-ASPM enabled: disable L0S */
- iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
- else
- /* L1-ASPM disabled: enable L0S */
- iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
-
radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
/* write radio config values to register */
@@ -396,79 +345,6 @@ static void iwl4965_nic_config(struct iwl_priv *priv)
spin_unlock_irqrestore(&priv->lock, flags);
}
-static int iwl4965_apm_stop_master(struct iwl_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* set stop master bit */
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
-
- iwl_poll_direct_bit(priv, CSR_RESET,
- CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
-
- spin_unlock_irqrestore(&priv->lock, flags);
- IWL_DEBUG_INFO(priv, "stop master\n");
-
- return 0;
-}
-
-static void iwl4965_apm_stop(struct iwl_priv *priv)
-{
- unsigned long flags;
-
- iwl4965_apm_stop_master(priv);
-
- spin_lock_irqsave(&priv->lock, flags);
-
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
-
- udelay(10);
- /* clear "init complete" move adapter D0A* --> D0U state */
- iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static int iwl4965_apm_reset(struct iwl_priv *priv)
-{
- int ret = 0;
-
- iwl4965_apm_stop_master(priv);
-
-
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
-
- udelay(10);
-
- /* FIXME: put here L1A -L0S w/a */
-
- iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
- ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
- if (ret < 0)
- goto out;
-
- udelay(10);
-
- /* Enable DMA and BSM Clock */
- iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT |
- APMG_CLK_VAL_BSM_CLK_RQT);
-
- udelay(10);
-
- /* disable L1A */
- iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
- APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-
- clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
- wake_up_interruptible(&priv->wait_command_queue);
-
-out:
- return ret;
-}
-
/* Reset differential Rx gains in NIC to prepare for chain noise calibration.
* Called after every association, but this runs only once!
* ... once chain noise is calibrated the first time, it's good forever. */
@@ -496,14 +372,15 @@ static void iwl4965_chain_noise_reset(struct iwl_priv *priv)
static void iwl4965_gain_computation(struct iwl_priv *priv,
u32 *average_noise,
u16 min_average_noise_antenna_i,
- u32 min_average_noise)
+ u32 min_average_noise,
+ u8 default_chain)
{
int i, ret;
struct iwl_chain_noise_data *data = &priv->chain_noise_data;
data->delta_gain_code[min_average_noise_antenna_i] = 0;
- for (i = 0; i < NUM_RX_CHAINS; i++) {
+ for (i = default_chain; i < NUM_RX_CHAINS; i++) {
s32 delta_g = 0;
if (!(data->disconn_array[i]) &&
@@ -557,18 +434,6 @@ static void iwl4965_gain_computation(struct iwl_priv *priv,
data->beacon_count = 0;
}
-static void iwl4965_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
- __le32 *tx_flags)
-{
- if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
- *tx_flags |= TX_CMD_FLG_RTS_MSK;
- *tx_flags &= ~TX_CMD_FLG_CTS_MSK;
- } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
- *tx_flags &= ~TX_CMD_FLG_RTS_MSK;
- *tx_flags |= TX_CMD_FLG_CTS_MSK;
- }
-}
-
static void iwl4965_bg_txpower_work(struct work_struct *work)
{
struct iwl_priv *priv = container_of(work, struct iwl_priv,
@@ -663,7 +528,8 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
iwl_write_targ_mem(priv, a, 0);
for (; a < priv->scd_base_addr + IWL49_SCD_TRANSLATE_TBL_OFFSET; a += 4)
iwl_write_targ_mem(priv, a, 0);
- for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4)
+ for (; a < priv->scd_base_addr +
+ IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(priv->hw_params.max_txq_num); a += 4)
iwl_write_targ_mem(priv, a, 0);
/* Tel 4965 where to find Tx byte count tables */
@@ -748,6 +614,10 @@ static struct iwl_sensitivity_ranges iwl4965_sensitivity = {
.nrg_th_cck = 100,
.nrg_th_ofdm = 100,
+
+ .barker_corr_th_min = 190,
+ .barker_corr_th_min_mrc = 390,
+ .nrg_th_cca = 62,
};
static void iwl4965_set_ct_threshold(struct iwl_priv *priv)
@@ -764,19 +634,16 @@ static void iwl4965_set_ct_threshold(struct iwl_priv *priv)
*/
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->mod_params->num_of_queues;
- if ((priv->cfg->mod_params->num_of_queues > IWL49_NUM_QUEUES) ||
- (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) {
- IWL_ERR(priv,
- "invalid queues_num, should be between %d and %d\n",
- IWL_MIN_NUM_QUEUES, IWL49_NUM_QUEUES);
- return -EINVAL;
- }
-
- priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues;
+ priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
priv->hw_params.dma_chnl_num = FH49_TCSR_CHNL_NUM;
priv->hw_params.scd_bc_tbls_size =
- IWL49_NUM_QUEUES * sizeof(struct iwl4965_scd_bc_tbl);
+ priv->cfg->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;
@@ -787,10 +654,10 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
- priv->hw_params.tx_chains_num = 2;
- priv->hw_params.rx_chains_num = 2;
- priv->hw_params.valid_tx_ant = ANT_A | ANT_B;
- priv->hw_params.valid_rx_ant = ANT_A | ANT_B;
+ priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
+ priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
+ priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
+ priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
@@ -1567,14 +1434,13 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
return ret;
}
-#ifdef IEEE80211_CONF_CHANNEL_SWITCH
static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
{
int rc;
u8 band = 0;
bool is_ht40 = false;
u8 ctrl_chan_high = 0;
- struct iwl4965_channel_switch_cmd cmd = { 0 };
+ struct iwl4965_channel_switch_cmd cmd;
const struct iwl_channel_info *ch_info;
band = priv->band == IEEE80211_BAND_2GHZ;
@@ -1595,8 +1461,11 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
if (ch_info)
cmd.expect_beacon = is_channel_radar(ch_info);
- else
- cmd.expect_beacon = 1;
+ else {
+ IWL_ERR(priv, "invalid channel switch from %u to %u\n",
+ priv->active_rxon.channel, channel);
+ return -EFAULT;
+ }
rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_ht40,
ctrl_chan_high, &cmd.tx_power);
@@ -1608,7 +1477,6 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
return rc;
}
-#endif
/**
* iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
@@ -1805,11 +1673,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 + IWL49_NUM_AMPDU_QUEUES <= txq_id)) {
+ (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->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 + IWL49_NUM_AMPDU_QUEUES - 1);
+ IWL49_FIRST_AMPDU_QUEUE +
+ priv->cfg->num_of_ampdu_queues - 1);
return -EINVAL;
}
@@ -1870,11 +1740,13 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
u16 ra_tid;
if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
- (IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) {
+ (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->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 + IWL49_NUM_AMPDU_QUEUES - 1);
+ IWL49_FIRST_AMPDU_QUEUE +
+ priv->cfg->num_of_ampdu_queues - 1);
return -EINVAL;
}
@@ -2078,7 +1950,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
u16 sequence = le16_to_cpu(pkt->hdr.sequence);
int txq_id = SEQ_TO_QUEUE(sequence);
int index = SEQ_TO_INDEX(sequence);
@@ -2279,7 +2151,7 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
.build_addsta_hcmd = iwl4965_build_addsta_hcmd,
.chain_noise_reset = iwl4965_chain_noise_reset,
.gain_computation = iwl4965_gain_computation,
- .rts_tx_cmd_flag = iwl4965_rts_tx_cmd_flag,
+ .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,
.calc_rssi = iwl4965_calc_rssi,
};
@@ -2301,10 +2173,10 @@ static struct iwl_lib_ops iwl4965_lib = {
.load_ucode = iwl4965_load_bsm,
.dump_nic_event_log = iwl_dump_nic_event_log,
.dump_nic_error_log = iwl_dump_nic_error_log,
+ .set_channel_switch = iwl4965_hw_channel_switch,
.apm_ops = {
- .init = iwl4965_apm_init,
- .reset = iwl4965_apm_reset,
- .stop = iwl4965_apm_stop,
+ .init = iwl_apm_init,
+ .stop = iwl_apm_stop,
.config = iwl4965_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
@@ -2340,6 +2212,7 @@ static struct iwl_ops iwl4965_ops = {
.lib = &iwl4965_lib,
.hcmd = &iwl4965_hcmd,
.utils = &iwl4965_hcmd_utils,
+ .led = &iwlagn_led_ops,
};
struct iwl_cfg iwl4965_agn_cfg = {
@@ -2352,30 +2225,40 @@ struct iwl_cfg iwl4965_agn_cfg = {
.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 = &iwl4965_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .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,
};
/* Module firmware */
MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE(IWL4965_UCODE_API_MAX));
-module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
+module_param_named(antenna, iwl4965_mod_params.antenna, int, S_IRUGO);
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
-module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444);
+module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, S_IRUGO);
MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
module_param_named(
- disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444);
+ disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, S_IRUGO);
MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
-module_param_named(queues_num, iwl4965_mod_params.num_of_queues, int, 0444);
+module_param_named(queues_num, iwl4965_mod_params.num_of_queues, int, S_IRUGO);
MODULE_PARM_DESC(queues_num, "number of hw queues.");
/* 11n */
-module_param_named(11n_disable, iwl4965_mod_params.disable_11n, int, 0444);
+module_param_named(11n_disable, iwl4965_mod_params.disable_11n, int, S_IRUGO);
MODULE_PARM_DESC(11n_disable, "disable 11n functionality");
-module_param_named(amsdu_size_8K, iwl4965_mod_params.amsdu_size_8K, int, 0444);
+module_param_named(amsdu_size_8K, iwl4965_mod_params.amsdu_size_8K,
+ int, S_IRUGO);
MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
-module_param_named(fw_restart4965, iwl4965_mod_params.restart_fw, int, 0444);
+module_param_named(fw_restart4965, iwl4965_mod_params.restart_fw, int, S_IRUGO);
MODULE_PARM_DESC(fw_restart4965, "restart firmware in case of error");
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 6e6f516ba404..b8ddd70e785f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -43,6 +43,7 @@
#include "iwl-io.h"
#include "iwl-sta.h"
#include "iwl-helpers.h"
+#include "iwl-agn-led.h"
#include "iwl-5000-hw.h"
#include "iwl-6000-hw.h"
@@ -72,157 +73,18 @@ static const u16 iwl5000_default_queue_to_tx_fifo[] = {
IWL_TX_FIFO_HCCA_2
};
-/* FIXME: same implementation as 4965 */
-static int iwl5000_apm_stop_master(struct iwl_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* set stop master bit */
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
-
- iwl_poll_direct_bit(priv, CSR_RESET,
- CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
-
- spin_unlock_irqrestore(&priv->lock, flags);
- IWL_DEBUG_INFO(priv, "stop master\n");
-
- return 0;
-}
-
-
-int iwl5000_apm_init(struct iwl_priv *priv)
-{
- int ret = 0;
-
- iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
-
- /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */
- iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
-
- /* Set FH wait threshold to maximum (HW error during stress W/A) */
- iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
-
- /* enable HAP INTA to move device L1a -> L0s */
- iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
-
- if (priv->cfg->need_pll_cfg)
- iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL);
-
- /* set "initialization complete" bit to move adapter
- * D0U* --> D0A* state */
- iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
- /* wait for clock stabilization */
- ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
- if (ret < 0) {
- IWL_DEBUG_INFO(priv, "Failed to init the card\n");
- return ret;
- }
-
- /* enable DMA */
- iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
-
- udelay(20);
-
- /* disable L1-Active */
- iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
- APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-
- return ret;
-}
-
-/* FIXME: this is identical to 4965 */
-void iwl5000_apm_stop(struct iwl_priv *priv)
-{
- unsigned long flags;
-
- iwl5000_apm_stop_master(priv);
-
- spin_lock_irqsave(&priv->lock, flags);
-
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
-
- udelay(10);
-
- /* clear "init complete" move adapter D0A* --> D0U state */
- iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-
-int iwl5000_apm_reset(struct iwl_priv *priv)
-{
- int ret = 0;
-
- iwl5000_apm_stop_master(priv);
-
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
-
- udelay(10);
-
-
- /* FIXME: put here L1A -L0S w/a */
-
- if (priv->cfg->need_pll_cfg)
- iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL);
-
- /* set "initialization complete" bit to move adapter
- * D0U* --> D0A* state */
- iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-
- /* wait for clock stabilization */
- ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
- if (ret < 0) {
- IWL_DEBUG_INFO(priv, "Failed to init the card\n");
- goto out;
- }
-
- /* enable DMA */
- iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
-
- udelay(20);
-
- /* disable L1-Active */
- iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
- APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-out:
-
- return ret;
-}
-
-
-/* NIC configuration for 5000 series and up */
+/* NIC configuration for 5000 series */
void iwl5000_nic_config(struct iwl_priv *priv)
{
unsigned long flags;
u16 radio_cfg;
- u16 lctl;
spin_lock_irqsave(&priv->lock, flags);
- lctl = iwl_pcie_link_ctl(priv);
-
- /* HW bug W/A */
- /* L1-ASPM is enabled by BIOS */
- if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
- /* L1-APSM enabled: disable L0S */
- iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
- else
- /* L1-ASPM disabled: enable L0S */
- iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
-
radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
/* write radio config values to register */
- if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) < EEPROM_5000_RF_CFG_TYPE_MAX)
+ if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) < EEPROM_RF_CONFIG_TYPE_MAX)
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
EEPROM_RF_CFG_TYPE_MSK(radio_cfg) |
EEPROM_RF_CFG_STEP_MSK(radio_cfg) |
@@ -302,19 +164,22 @@ u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv)
static void iwl5000_gain_computation(struct iwl_priv *priv,
u32 average_noise[NUM_RX_CHAINS],
u16 min_average_noise_antenna_i,
- u32 min_average_noise)
+ u32 min_average_noise,
+ u8 default_chain)
{
int i;
s32 delta_g;
struct iwl_chain_noise_data *data = &priv->chain_noise_data;
- /* Find Gain Code for the antennas B and C */
- for (i = 1; i < NUM_RX_CHAINS; i++) {
+ /*
+ * Find Gain Code for the chains based on "default chain"
+ */
+ for (i = default_chain + 1; i < NUM_RX_CHAINS; i++) {
if ((data->disconn_array[i])) {
data->delta_gain_code[i] = 0;
continue;
}
- delta_g = (1000 * ((s32)average_noise[0] -
+ delta_g = (1000 * ((s32)average_noise[default_chain] -
(s32)average_noise[i])) / 1500;
/* bound gain by 2 bits value max, 3rd bit is sign */
data->delta_gain_code[i] =
@@ -407,6 +272,10 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
.auto_corr_max_cck_mrc = 400,
.nrg_th_cck = 95,
.nrg_th_ofdm = 95,
+
+ .barker_corr_th_min = 190,
+ .barker_corr_th_min_mrc = 390,
+ .nrg_th_cca = 62,
};
static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
@@ -429,6 +298,10 @@ static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
.auto_corr_max_cck_mrc = 400,
.nrg_th_cck = 95,
.nrg_th_ofdm = 95,
+
+ .barker_corr_th_min = 190,
+ .barker_corr_th_min_mrc = 390,
+ .nrg_th_cca = 62,
};
const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
@@ -493,7 +366,7 @@ static int iwl5000_send_calib_cfg(struct iwl_priv *priv)
static void iwl5000_rx_calib_result(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw;
int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
int index;
@@ -746,7 +619,8 @@ int iwl5000_alive_notify(struct iwl_priv *priv)
for (; a < priv->scd_base_addr + IWL50_SCD_TRANSLATE_TBL_OFFSET;
a += 4)
iwl_write_targ_mem(priv, a, 0);
- for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4)
+ for (; a < priv->scd_base_addr +
+ IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(priv->hw_params.max_txq_num); a += 4)
iwl_write_targ_mem(priv, a, 0);
iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR,
@@ -818,32 +692,22 @@ int iwl5000_alive_notify(struct iwl_priv *priv)
int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
{
- if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) ||
- (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) {
- IWL_ERR(priv,
- "invalid queues_num, should be between %d and %d\n",
- IWL_MIN_NUM_QUEUES, IWL50_NUM_QUEUES);
- return -EINVAL;
- }
+ if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
+ priv->cfg->mod_params->num_of_queues <= IWL50_NUM_QUEUES)
+ priv->cfg->num_of_queues =
+ priv->cfg->mod_params->num_of_queues;
- priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues;
+ priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
priv->hw_params.scd_bc_tbls_size =
- IWL50_NUM_QUEUES * sizeof(struct iwl5000_scd_bc_tbl);
+ priv->cfg->num_of_queues *
+ sizeof(struct iwl5000_scd_bc_tbl);
priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
priv->hw_params.max_stations = IWL5000_STATION_COUNT;
priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
- switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
- case CSR_HW_REV_TYPE_6x00:
- case CSR_HW_REV_TYPE_6x50:
- priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
- priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
- break;
- default:
- priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE;
- priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE;
- }
+ priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE;
+ priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE;
priv->hw_params.max_bsm_size = 0;
priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
@@ -989,11 +853,13 @@ int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
u16 ra_tid;
if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
- (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) {
+ (IWL50_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
+ <= txq_id)) {
IWL_WARN(priv,
"queue number out of range: %d, must be %d to %d\n",
txq_id, IWL50_FIRST_AMPDU_QUEUE,
- IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1);
+ IWL50_FIRST_AMPDU_QUEUE +
+ priv->cfg->num_of_ampdu_queues - 1);
return -EINVAL;
}
@@ -1047,11 +913,13 @@ int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
u16 ssn_idx, u8 tx_fifo)
{
if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
- (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) {
+ (IWL50_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
+ <= txq_id)) {
IWL_ERR(priv,
"queue number out of range: %d, must be %d to %d\n",
txq_id, IWL50_FIRST_AMPDU_QUEUE,
- IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1);
+ IWL50_FIRST_AMPDU_QUEUE +
+ priv->cfg->num_of_ampdu_queues - 1);
return -EINVAL;
}
@@ -1218,7 +1086,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
u16 sequence = le16_to_cpu(pkt->hdr.sequence);
int txq_id = SEQ_TO_QUEUE(sequence);
int index = SEQ_TO_INDEX(sequence);
@@ -1459,6 +1327,24 @@ int iwl5000_calc_rssi(struct iwl_priv *priv,
return max_rssi - agc - IWL49_RSSI_OFFSET;
}
+static int iwl5000_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
+{
+ struct iwl_tx_ant_config_cmd tx_ant_cmd = {
+ .valid = cpu_to_le32(valid_tx_ant),
+ };
+
+ if (IWL_UCODE_API(priv->ucode_ver) > 1) {
+ IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant);
+ return iwl_send_cmd_pdu(priv, TX_ANT_CONFIGURATION_CMD,
+ sizeof(struct iwl_tx_ant_config_cmd),
+ &tx_ant_cmd);
+ } else {
+ IWL_DEBUG_HC(priv, "TX_ANT_CONFIGURATION_CMD not supported\n");
+ return -EOPNOTSUPP;
+ }
+}
+
+
#define IWL5000_UCODE_GET(item) \
static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\
u32 api_ver) \
@@ -1497,10 +1383,41 @@ IWL5000_UCODE_GET(init_size);
IWL5000_UCODE_GET(init_data_size);
IWL5000_UCODE_GET(boot_size);
+static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+{
+ struct iwl5000_channel_switch_cmd cmd;
+ const struct iwl_channel_info *ch_info;
+ struct iwl_host_cmd hcmd = {
+ .id = REPLY_CHANNEL_SWITCH,
+ .len = sizeof(cmd),
+ .flags = CMD_SIZE_HUGE,
+ .data = &cmd,
+ };
+
+ IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
+ priv->active_rxon.channel, channel);
+ cmd.band = priv->band == IEEE80211_BAND_2GHZ;
+ cmd.channel = cpu_to_le16(channel);
+ cmd.rxon_flags = priv->active_rxon.flags;
+ cmd.rxon_filter_flags = priv->active_rxon.filter_flags;
+ cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+ ch_info = iwl_get_channel_info(priv, priv->band, channel);
+ if (ch_info)
+ cmd.expect_beacon = is_channel_radar(ch_info);
+ else {
+ IWL_ERR(priv, "invalid channel switch from %u to %u\n",
+ priv->active_rxon.channel, channel);
+ return -EFAULT;
+ }
+
+ return iwl_send_cmd_sync(priv, &hcmd);
+}
+
struct iwl_hcmd_ops iwl5000_hcmd = {
.rxon_assoc = iwl5000_send_rxon_assoc,
.commit_rxon = iwl_commit_rxon,
.set_rxon_chain = iwl_set_rxon_chain,
+ .set_tx_ant = iwl5000_send_tx_ant_config,
};
struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
@@ -1543,10 +1460,10 @@ struct iwl_lib_ops iwl5000_lib = {
.alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power,
.update_chain_flags = iwl_update_chain_flags,
+ .set_channel_switch = iwl5000_hw_channel_switch,
.apm_ops = {
- .init = iwl5000_apm_init,
- .reset = iwl5000_apm_reset,
- .stop = iwl5000_apm_stop,
+ .init = iwl_apm_init,
+ .stop = iwl_apm_stop,
.config = iwl5000_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
@@ -1595,10 +1512,10 @@ static struct iwl_lib_ops iwl5150_lib = {
.alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power,
.update_chain_flags = iwl_update_chain_flags,
+ .set_channel_switch = iwl5000_hw_channel_switch,
.apm_ops = {
- .init = iwl5000_apm_init,
- .reset = iwl5000_apm_reset,
- .stop = iwl5000_apm_stop,
+ .init = iwl_apm_init,
+ .stop = iwl_apm_stop,
.config = iwl5000_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
@@ -1627,11 +1544,12 @@ static struct iwl_lib_ops iwl5150_lib = {
},
};
-struct iwl_ops iwl5000_ops = {
+static struct iwl_ops iwl5000_ops = {
.ucode = &iwl5000_ucode,
.lib = &iwl5000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
+ .led = &iwlagn_led_ops,
};
static struct iwl_ops iwl5150_ops = {
@@ -1639,11 +1557,10 @@ static struct iwl_ops iwl5150_ops = {
.lib = &iwl5150_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
+ .led = &iwlagn_led_ops,
};
struct iwl_mod_params iwl50_mod_params = {
- .num_of_queues = IWL50_NUM_QUEUES,
- .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.amsdu_size_8K = 1,
.restart_fw = 1,
/* the rest are 0 by default */
@@ -1660,11 +1577,17 @@ struct iwl_cfg iwl5300_agn_cfg = {
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC,
- .need_pll_cfg = true,
+ .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+ .set_l0s = true,
+ .use_bsm = false,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
};
struct iwl_cfg iwl5100_bg_cfg = {
@@ -1677,11 +1600,17 @@ struct iwl_cfg iwl5100_bg_cfg = {
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_B,
.valid_rx_ant = ANT_AB,
- .need_pll_cfg = true,
+ .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+ .set_l0s = true,
+ .use_bsm = false,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
};
struct iwl_cfg iwl5100_abg_cfg = {
@@ -1694,11 +1623,17 @@ struct iwl_cfg iwl5100_abg_cfg = {
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_B,
.valid_rx_ant = ANT_AB,
- .need_pll_cfg = true,
+ .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+ .set_l0s = true,
+ .use_bsm = false,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
};
struct iwl_cfg iwl5100_agn_cfg = {
@@ -1711,11 +1646,17 @@ struct iwl_cfg iwl5100_agn_cfg = {
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_B,
.valid_rx_ant = ANT_AB,
- .need_pll_cfg = true,
+ .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+ .set_l0s = true,
+ .use_bsm = false,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
};
struct iwl_cfg iwl5350_agn_cfg = {
@@ -1728,11 +1669,17 @@ struct iwl_cfg iwl5350_agn_cfg = {
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC,
- .need_pll_cfg = true,
+ .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+ .set_l0s = true,
+ .use_bsm = false,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
};
struct iwl_cfg iwl5150_agn_cfg = {
@@ -1745,24 +1692,31 @@ struct iwl_cfg iwl5150_agn_cfg = {
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_A,
.valid_rx_ant = ANT_AB,
- .need_pll_cfg = true,
+ .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
+ .set_l0s = true,
+ .use_bsm = false,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
};
MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX));
-module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444);
+module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, S_IRUGO);
MODULE_PARM_DESC(swcrypto50,
"using software crypto engine (default 0 [hardware])\n");
-module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444);
+module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, S_IRUGO);
MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series");
-module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444);
+module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, S_IRUGO);
MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality");
-module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, int, 0444);
+module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K,
+ int, S_IRUGO);
MODULE_PARM_DESC(amsdu_size_8K50, "enable 8K amsdu size in 50XX series");
-module_param_named(fw_restart50, iwl50_mod_params.restart_fw, int, 0444);
+module_param_named(fw_restart50, iwl50_mod_params.restart_fw, int, S_IRUGO);
MODULE_PARM_DESC(fw_restart50, "restart firmware in case of error");
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index c295b8ee9228..32466d38d1ae 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -44,14 +44,16 @@
#include "iwl-sta.h"
#include "iwl-helpers.h"
#include "iwl-5000-hw.h"
+#include "iwl-6000-hw.h"
+#include "iwl-agn-led.h"
/* Highest firmware API version supported */
#define IWL6000_UCODE_API_MAX 4
#define IWL6050_UCODE_API_MAX 4
/* Lowest firmware API version supported */
-#define IWL6000_UCODE_API_MIN 1
-#define IWL6050_UCODE_API_MIN 1
+#define IWL6000_UCODE_API_MIN 4
+#define IWL6050_UCODE_API_MIN 4
#define IWL6000_FW_PRE "iwlwifi-6000-"
#define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode"
@@ -71,7 +73,21 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
/* NIC configuration for 6000 series */
static void iwl6000_nic_config(struct iwl_priv *priv)
{
- iwl5000_nic_config(priv);
+ u16 radio_cfg;
+
+ radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
+
+ /* write radio config values to register */
+ if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <= EEPROM_RF_CONFIG_TYPE_MAX)
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ EEPROM_RF_CFG_TYPE_MSK(radio_cfg) |
+ EEPROM_RF_CFG_STEP_MSK(radio_cfg) |
+ EEPROM_RF_CFG_DASH_MSK(radio_cfg));
+
+ /* set CSR_HW_CONFIG_REG for uCode use */
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
+ CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
/* no locking required for register write */
if (priv->cfg->pa_type == IWL_PA_HYBRID) {
@@ -86,8 +102,109 @@ static void iwl6000_nic_config(struct iwl_priv *priv)
/* else do nothing, uCode configured */
}
+static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
+ .min_nrg_cck = 97,
+ .max_nrg_cck = 0, /* not used, set to 0 */
+ .auto_corr_min_ofdm = 80,
+ .auto_corr_min_ofdm_mrc = 128,
+ .auto_corr_min_ofdm_x1 = 105,
+ .auto_corr_min_ofdm_mrc_x1 = 192,
+
+ .auto_corr_max_ofdm = 145,
+ .auto_corr_max_ofdm_mrc = 232,
+ .auto_corr_max_ofdm_x1 = 145,
+ .auto_corr_max_ofdm_mrc_x1 = 232,
+
+ .auto_corr_min_cck = 125,
+ .auto_corr_max_cck = 175,
+ .auto_corr_min_cck_mrc = 160,
+ .auto_corr_max_cck_mrc = 310,
+ .nrg_th_cck = 97,
+ .nrg_th_ofdm = 100,
+
+ .barker_corr_th_min = 190,
+ .barker_corr_th_min_mrc = 390,
+ .nrg_th_cca = 62,
+};
+
+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 <= IWL50_NUM_QUEUES)
+ priv->cfg->num_of_queues =
+ priv->cfg->mod_params->num_of_queues;
+
+ priv->hw_params.max_txq_num = priv->cfg->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 *
+ sizeof(struct iwl5000_scd_bc_tbl);
+ priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
+ priv->hw_params.max_stations = IWL5000_STATION_COUNT;
+ priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
+
+ priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
+ priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
+
+ priv->hw_params.max_bsm_size = 0;
+ priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) |
+ BIT(IEEE80211_BAND_5GHZ);
+ priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
+
+ priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
+ priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
+ priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
+ priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
+
+ if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
+ priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
+
+ /* Set initial sensitivity parameters */
+ /* Set initial calibration set */
+ priv->hw_params.sens = &iwl6000_sensitivity;
+ priv->hw_params.calib_init_cfg =
+ BIT(IWL_CALIB_XTAL) |
+ BIT(IWL_CALIB_LO) |
+ BIT(IWL_CALIB_TX_IQ) |
+ BIT(IWL_CALIB_TX_IQ_PERD) |
+ BIT(IWL_CALIB_BASE_BAND);
+
+ return 0;
+}
+
+static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+{
+ struct iwl6000_channel_switch_cmd cmd;
+ const struct iwl_channel_info *ch_info;
+ struct iwl_host_cmd hcmd = {
+ .id = REPLY_CHANNEL_SWITCH,
+ .len = sizeof(cmd),
+ .flags = CMD_SIZE_HUGE,
+ .data = &cmd,
+ };
+
+ IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
+ priv->active_rxon.channel, channel);
+
+ cmd.band = priv->band == IEEE80211_BAND_2GHZ;
+ cmd.channel = cpu_to_le16(channel);
+ cmd.rxon_flags = priv->active_rxon.flags;
+ cmd.rxon_filter_flags = priv->active_rxon.filter_flags;
+ cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+ ch_info = iwl_get_channel_info(priv, priv->band, channel);
+ if (ch_info)
+ cmd.expect_beacon = is_channel_radar(ch_info);
+ else {
+ IWL_ERR(priv, "invalid channel switch from %u to %u\n",
+ priv->active_rxon.channel, channel);
+ return -EFAULT;
+ }
+
+ return iwl_send_cmd_sync(priv, &hcmd);
+}
+
static struct iwl_lib_ops iwl6000_lib = {
- .set_hw_params = iwl5000_hw_set_hw_params,
+ .set_hw_params = iwl6000_hw_set_hw_params,
.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
.txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
.txq_set_sched = iwl5000_txq_set_sched,
@@ -106,10 +223,10 @@ static struct iwl_lib_ops iwl6000_lib = {
.alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power,
.update_chain_flags = iwl_update_chain_flags,
+ .set_channel_switch = iwl6000_hw_channel_switch,
.apm_ops = {
- .init = iwl5000_apm_init,
- .reset = iwl5000_apm_reset,
- .stop = iwl5000_apm_stop,
+ .init = iwl_apm_init,
+ .stop = iwl_apm_stop,
.config = iwl6000_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
@@ -139,18 +256,27 @@ static struct iwl_lib_ops iwl6000_lib = {
},
};
-static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = {
+static struct iwl_ops iwl6000_ops = {
+ .ucode = &iwl5000_ucode,
+ .lib = &iwl6000_lib,
+ .hcmd = &iwl5000_hcmd,
+ .utils = &iwl5000_hcmd_utils,
+ .led = &iwlagn_led_ops,
+};
+
+static struct iwl_hcmd_utils_ops iwl6050_hcmd_utils = {
.get_hcmd_size = iwl5000_get_hcmd_size,
.build_addsta_hcmd = iwl5000_build_addsta_hcmd,
.rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag,
.calc_rssi = iwl5000_calc_rssi,
};
-static struct iwl_ops iwl6000_ops = {
+static struct iwl_ops iwl6050_ops = {
.ucode = &iwl5000_ucode,
.lib = &iwl6000_lib,
.hcmd = &iwl5000_hcmd,
- .utils = &iwl6000_hcmd_utils,
+ .utils = &iwl6050_hcmd_utils,
+ .led = &iwlagn_led_ops,
};
@@ -165,16 +291,84 @@ struct iwl_cfg iwl6000h_2agn_cfg = {
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
- .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+ .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB,
- .need_pll_cfg = false,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .use_bsm = false,
.pa_type = IWL_PA_HYBRID,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .use_rts_for_ht = 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,
+};
+
+struct iwl_cfg iwl6000h_2abg_cfg = {
+ .name = "6000 Series 2x2 ABG",
+ .fw_name_pre = IWL6000_FW_PRE,
+ .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,
+ .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
+ .mod_params = &iwl50_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .use_bsm = false,
+ .pa_type = IWL_PA_HYBRID,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .ht_greenfield_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,
+};
+
+struct iwl_cfg iwl6000h_2bg_cfg = {
+ .name = "6000 Series 2x2 BG",
+ .fw_name_pre = IWL6000_FW_PRE,
+ .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,
+ .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
+ .mod_params = &iwl50_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .use_bsm = false,
+ .pa_type = IWL_PA_HYBRID,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .ht_greenfield_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,
};
/*
@@ -188,16 +382,84 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
- .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+ .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
+ .mod_params = &iwl50_mod_params,
+ .valid_tx_ant = ANT_BC,
+ .valid_rx_ant = ANT_BC,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .use_bsm = false,
+ .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_ht = 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,
+};
+
+struct iwl_cfg iwl6000i_2abg_cfg = {
+ .name = "6000 Series 2x2 ABG",
+ .fw_name_pre = IWL6000_FW_PRE,
+ .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,
+ .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
+ .mod_params = &iwl50_mod_params,
+ .valid_tx_ant = ANT_BC,
+ .valid_rx_ant = ANT_BC,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .use_bsm = false,
+ .pa_type = IWL_PA_INTERNAL,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .ht_greenfield_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,
+};
+
+struct iwl_cfg iwl6000i_2bg_cfg = {
+ .name = "6000 Series 2x2 BG",
+ .fw_name_pre = IWL6000_FW_PRE,
+ .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,
+ .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_BC,
.valid_rx_ant = ANT_BC,
- .need_pll_cfg = false,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .use_bsm = false,
.pa_type = IWL_PA_INTERNAL,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true,
.ht_greenfield_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,
};
struct iwl_cfg iwl6050_2agn_cfg = {
@@ -206,18 +468,57 @@ 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,
+ .ops = &iwl6050_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
- .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+ .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB,
- .need_pll_cfg = false,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .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,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .use_rts_for_ht = 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,
+};
+
+struct iwl_cfg iwl6050_2abg_cfg = {
+ .name = "6050 Series 2x2 ABG",
+ .fw_name_pre = IWL6050_FW_PRE,
+ .ucode_api_max = IWL6050_UCODE_API_MAX,
+ .ucode_api_min = IWL6050_UCODE_API_MIN,
+ .sku = IWL_SKU_A|IWL_SKU_G,
+ .ops = &iwl6050_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
+ .mod_params = &iwl50_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .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,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
};
struct iwl_cfg iwl6000_3agn_cfg = {
@@ -228,16 +529,26 @@ struct iwl_cfg iwl6000_3agn_cfg = {
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
- .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+ .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC,
- .need_pll_cfg = false,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .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_ht = 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,
};
struct iwl_cfg iwl6050_3agn_cfg = {
@@ -246,18 +557,28 @@ struct iwl_cfg iwl6050_3agn_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,
+ .ops = &iwl6050_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
- .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
+ .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC,
- .need_pll_cfg = false,
+ .pll_cfg_val = 0,
+ .set_l0s = false,
+ .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,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .use_rts_for_ht = 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,
};
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.c b/drivers/net/wireless/iwlwifi/iwl-agn-led.c
new file mode 100644
index 000000000000..3bccba20f6da
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.c
@@ -0,0 +1,85 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2009 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.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <net/mac80211.h>
+#include <linux/etherdevice.h>
+#include <asm/unaligned.h>
+
+#include "iwl-commands.h"
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-io.h"
+#include "iwl-agn-led.h"
+
+/* Send led command */
+static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
+{
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_LEDS_CMD,
+ .len = sizeof(struct iwl_led_cmd),
+ .data = led_cmd,
+ .flags = CMD_ASYNC,
+ .callback = NULL,
+ };
+ u32 reg;
+
+ reg = iwl_read32(priv, CSR_LED_REG);
+ if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
+ iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK);
+
+ return iwl_send_cmd(priv, &cmd);
+}
+
+/* Set led register off */
+static int iwl_led_on_reg(struct iwl_priv *priv)
+{
+ IWL_DEBUG_LED(priv, "led on\n");
+ iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
+ return 0;
+}
+
+/* Set led register off */
+static int iwl_led_off_reg(struct iwl_priv *priv)
+{
+ IWL_DEBUG_LED(priv, "LED Reg off\n");
+ iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF);
+ return 0;
+}
+
+const struct iwl_led_ops iwlagn_led_ops = {
+ .cmd = iwl_send_led_cmd,
+ .on = iwl_led_on_reg,
+ .off = iwl_led_off_reg,
+};
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.h b/drivers/net/wireless/iwlwifi/iwl-agn-led.h
new file mode 100644
index 000000000000..ab55f92a161d
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.h
@@ -0,0 +1,32 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2009 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.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_agn_led_h__
+#define __iwl_agn_led_h__
+
+extern const struct iwl_led_ops iwlagn_led_ops;
+
+#endif /* __iwl_agn_led_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index 346dc06fa7b7..27d4ece4d467 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -75,104 +75,6 @@ static const u8 ant_toggle_lookup[] = {
/*ANT_ABC -> */ ANT_ABC,
};
-/**
- * struct iwl_rate_scale_data -- tx success history for one rate
- */
-struct iwl_rate_scale_data {
- u64 data; /* bitmap of successful frames */
- s32 success_counter; /* number of frames successful */
- s32 success_ratio; /* per-cent * 128 */
- s32 counter; /* number of frames attempted */
- s32 average_tpt; /* success ratio * expected throughput */
- unsigned long stamp;
-};
-
-/**
- * struct iwl_scale_tbl_info -- tx params and success history for all rates
- *
- * There are two of these in struct iwl_lq_sta,
- * one for "active", and one for "search".
- */
-struct iwl_scale_tbl_info {
- enum iwl_table_type lq_type;
- u8 ant_type;
- u8 is_SGI; /* 1 = short guard interval */
- u8 is_ht40; /* 1 = 40 MHz channel width */
- u8 is_dup; /* 1 = duplicated data streams */
- u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
- u8 max_search; /* maximun number of tables we can search */
- s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
- u32 current_rate; /* rate_n_flags, uCode API format */
- struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
-};
-
-struct iwl_traffic_load {
- unsigned long time_stamp; /* age of the oldest statistics */
- u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time
- * slice */
- u32 total; /* total num of packets during the
- * last TID_MAX_TIME_DIFF */
- u8 queue_count; /* number of queues that has
- * been used since the last cleanup */
- u8 head; /* start of the circular buffer */
-};
-
-/**
- * struct iwl_lq_sta -- driver's rate scaling private structure
- *
- * Pointer to this gets passed back and forth between driver and mac80211.
- */
-struct iwl_lq_sta {
- u8 active_tbl; /* index of active table, range 0-1 */
- u8 enable_counter; /* indicates HT mode */
- u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */
- u8 search_better_tbl; /* 1: currently trying alternate mode */
- s32 last_tpt;
-
- /* The following determine when to search for a new mode */
- u32 table_count_limit;
- u32 max_failure_limit; /* # failed frames before new search */
- u32 max_success_limit; /* # successful frames before new search */
- u32 table_count;
- u32 total_failed; /* total failed frames, any/all rates */
- u32 total_success; /* total successful frames, any/all rates */
- u64 flush_timer; /* time staying in mode before new search */
-
- u8 action_counter; /* # mode-switch actions tried */
- u8 is_green;
- u8 is_dup;
- enum ieee80211_band band;
- u8 ibss_sta_added;
-
- /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
- u32 supp_rates;
- u16 active_legacy_rate;
- u16 active_siso_rate;
- u16 active_mimo2_rate;
- u16 active_mimo3_rate;
- u16 active_rate_basic;
- s8 max_rate_idx; /* Max rate set by user */
- u8 missed_rate_counter;
-
- struct iwl_link_quality_cmd lq;
- struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
- struct iwl_traffic_load load[TID_MAX_LOAD_COUNT];
- u8 tx_agg_tid_en;
-#ifdef CONFIG_MAC80211_DEBUGFS
- struct dentry *rs_sta_dbgfs_scale_table_file;
- struct dentry *rs_sta_dbgfs_stats_table_file;
- struct dentry *rs_sta_dbgfs_rate_scale_data_file;
- struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
- u32 dbg_fixed_rate;
-#endif
- struct iwl_priv *drv;
-
- /* used to be in sta_info */
- int last_txrate_idx;
- /* last tx rate_n_flags */
- u32 last_rate_n_flags;
-};
-
static void rs_rate_scale_perform(struct iwl_priv *priv,
struct sk_buff *skb,
struct ieee80211_sta *sta,
@@ -190,84 +92,78 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
{}
#endif
-/*
- * Expected throughput metrics for following rates:
- * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits
- * "G" is the only table that supports CCK (the first 4 rates).
+/**
+ * The following tables contain the expected throughput metrics for all rates
+ *
+ * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits
+ *
+ * where invalid entries are zeros.
+ *
+ * CCK rates are only valid in legacy table and will only be used in G
+ * (2.4 GHz) band.
*/
-static s32 expected_tpt_A[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186
-};
-
-static s32 expected_tpt_G[IWL_RATE_COUNT] = {
- 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 186
-};
-
-static s32 expected_tpt_siso20MHz[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 42, 42, 76, 102, 124, 159, 183, 193, 202
-};
-
-static s32 expected_tpt_siso20MHzSGI[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 46, 46, 82, 110, 132, 168, 192, 202, 211
-};
-
-static s32 expected_tpt_mimo2_20MHz[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 74, 74, 123, 155, 179, 214, 236, 244, 251
-};
-
-static s32 expected_tpt_mimo2_20MHzSGI[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 81, 81, 131, 164, 188, 222, 243, 251, 257
-};
-
-static s32 expected_tpt_siso40MHz[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 77, 77, 127, 160, 184, 220, 242, 250, 257
-};
-
-static s32 expected_tpt_siso40MHzSGI[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 83, 83, 135, 169, 193, 229, 250, 257, 264
+static s32 expected_tpt_legacy[IWL_RATE_COUNT] = {
+ 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0
};
-static s32 expected_tpt_mimo2_40MHz[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 123, 123, 182, 214, 235, 264, 279, 285, 289
+static s32 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = {
+ {0, 0, 0, 0, 42, 0, 76, 102, 124, 158, 183, 193, 202}, /* Norm */
+ {0, 0, 0, 0, 46, 0, 82, 110, 132, 167, 192, 202, 210}, /* SGI */
+ {0, 0, 0, 0, 48, 0, 93, 135, 176, 251, 319, 351, 381}, /* AGG */
+ {0, 0, 0, 0, 53, 0, 102, 149, 193, 275, 348, 381, 413}, /* AGG+SGI */
};
-static s32 expected_tpt_mimo2_40MHzSGI[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293
+static s32 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] = {
+ {0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257}, /* Norm */
+ {0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264}, /* SGI */
+ {0, 0, 0, 0, 96, 0, 182, 259, 328, 451, 553, 598, 640}, /* AGG */
+ {0, 0, 0, 0, 106, 0, 199, 282, 357, 487, 593, 640, 683}, /* AGG+SGI */
};
-/* Expected throughput metric MIMO3 */
-static s32 expected_tpt_mimo3_20MHz[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 99, 99, 153, 186, 208, 239, 256, 263, 268
+static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = {
+ {0, 0, 0, 0, 74, 0, 123, 155, 179, 213, 235, 243, 250}, /* Norm */
+ {0, 0, 0, 0, 81, 0, 131, 164, 187, 221, 242, 250, 256}, /* SGI */
+ {0, 0, 0, 0, 92, 0, 175, 250, 317, 436, 534, 578, 619}, /* AGG */
+ {0, 0, 0, 0, 102, 0, 192, 273, 344, 470, 573, 619, 660}, /* AGG+SGI*/
};
-static s32 expected_tpt_mimo3_20MHzSGI[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 106, 106, 162, 194, 215, 246, 262, 268, 273
+static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = {
+ {0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289}, /* Norm */
+ {0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293}, /* SGI */
+ {0, 0, 0, 0, 180, 0, 327, 446, 545, 708, 828, 878, 922}, /* AGG */
+ {0, 0, 0, 0, 197, 0, 355, 481, 584, 752, 872, 922, 966}, /* AGG+SGI */
};
-static s32 expected_tpt_mimo3_40MHz[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 152, 152, 211, 239, 255, 279, 290, 294, 297
+static s32 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = {
+ {0, 0, 0, 0, 99, 0, 153, 186, 208, 239, 256, 263, 268}, /* Norm */
+ {0, 0, 0, 0, 106, 0, 162, 194, 215, 246, 262, 268, 273}, /* SGI */
+ {0, 0, 0, 0, 134, 0, 249, 346, 431, 574, 685, 732, 775}, /* AGG */
+ {0, 0, 0, 0, 148, 0, 272, 376, 465, 614, 727, 775, 818}, /* AGG+SGI */
};
-static s32 expected_tpt_mimo3_40MHzSGI[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 160, 160, 219, 245, 261, 284, 294, 297, 300
+static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = {
+ {0, 0, 0, 0, 152, 0, 211, 239, 255, 279, 290, 294, 297}, /* Norm */
+ {0, 0, 0, 0, 160, 0, 219, 245, 261, 284, 294, 297, 300}, /* SGI */
+ {0, 0, 0, 0, 254, 0, 443, 584, 695, 868, 984, 1030, 1070}, /* AGG */
+ {0, 0, 0, 0, 277, 0, 478, 624, 737, 911, 1026, 1070, 1109}, /* AGG+SGI */
};
/* mbps, mcs */
const static struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
- {"1", ""},
- {"2", ""},
- {"5.5", ""},
- {"11", ""},
- {"6", "BPSK 1/2"},
- {"9", "BPSK 1/2"},
- {"12", "QPSK 1/2"},
- {"18", "QPSK 3/4"},
- {"24", "16QAM 1/2"},
- {"36", "16QAM 3/4"},
- {"48", "64QAM 2/3"},
- {"54", "64QAM 3/4"},
- {"60", "64QAM 5/6"}
+ { "1", "BPSK DSSS"},
+ { "2", "QPSK DSSS"},
+ {"5.5", "BPSK CCK"},
+ { "11", "QPSK CCK"},
+ { "6", "BPSK 1/2"},
+ { "9", "BPSK 1/2"},
+ { "12", "QPSK 1/2"},
+ { "18", "QPSK 3/4"},
+ { "24", "16QAM 1/2"},
+ { "36", "16QAM 3/4"},
+ { "48", "64QAM 2/3"},
+ { "54", "64QAM 3/4"},
+ { "60", "64QAM 5/6"},
};
#define MCS_INDEX_PER_STREAM (8)
@@ -418,6 +314,15 @@ static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid,
else if (tid == IWL_AGG_ALL_TID)
for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++)
rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
+ if (priv->cfg->use_rts_for_ht) {
+ /*
+ * switch to RTS/CTS if it is the prefer protection method
+ * for HT traffic
+ */
+ IWL_DEBUG_HT(priv, "use RTS/CTS protection for HT\n");
+ priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
+ iwlcore_commit_rxon(priv);
+ }
}
static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
@@ -435,7 +340,7 @@ static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
* packets.
*/
static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
- int scale_index, s32 tpt, int retries,
+ int scale_index, s32 tpt, int attempts,
int successes)
{
struct iwl_rate_scale_data *window = NULL;
@@ -445,7 +350,7 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
return -EINVAL;
- /* Select data for current tx bit rate */
+ /* Select window for current tx bit rate */
window = &(windows[scale_index]);
/*
@@ -456,7 +361,7 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
* subtract "1" from the success counter (this is the main reason
* we keep these bitmaps!).
*/
- while (retries > 0) {
+ while (attempts > 0) {
if (window->counter >= IWL_RATE_MAX_WINDOW) {
/* remove earliest */
@@ -471,17 +376,17 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
/* Increment frames-attempted counter */
window->counter++;
- /* Shift bitmap by one frame (throw away oldest history),
- * OR in "1", and increment "success" if this
- * frame was successful. */
+ /* Shift bitmap by one frame to throw away oldest history */
window->data <<= 1;
+
+ /* Mark the most recent #successes attempts as successful */
if (successes > 0) {
window->success_counter++;
window->data |= 0x1;
successes--;
}
- retries--;
+ attempts--;
}
/* Calculate current success ratio, avoid divide-by-0! */
@@ -662,7 +567,7 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
* there are no non-GF stations present in the BSS.
*/
static inline u8 rs_use_green(struct ieee80211_sta *sta,
- struct iwl_ht_info *ht_conf)
+ struct iwl_ht_config *ht_conf)
{
return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) &&
!(ht_conf->non_GF_STA_present);
@@ -812,27 +717,45 @@ out:
}
/*
+ * Simple function to compare two rate scale table types
+ */
+static bool table_type_matches(struct iwl_scale_tbl_info *a,
+ struct iwl_scale_tbl_info *b)
+{
+ return (a->lq_type == b->lq_type) && (a->ant_type == b->ant_type) &&
+ (a->is_SGI == b->is_SGI);
+}
+/*
+ * Static function to get the expected throughput from an iwl_scale_tbl_info
+ * that wraps a NULL pointer check
+ */
+static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index)
+{
+ if (tbl->expected_tpt)
+ return tbl->expected_tpt[rs_index];
+ return 0;
+}
+
+/*
* mac80211 sends us Tx status
*/
static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta,
struct sk_buff *skb)
{
- int status;
- u8 retries;
- int rs_index, mac_index, index = 0;
+ int legacy_success;
+ int retries;
+ int rs_index, mac_index, i;
struct iwl_lq_sta *lq_sta = priv_sta;
struct iwl_link_quality_cmd *table;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct iwl_priv *priv = (struct iwl_priv *)priv_r;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl_rate_scale_data *window = NULL;
- struct iwl_rate_scale_data *search_win = NULL;
enum mac80211_rate_control_flags mac_flags;
u32 tx_rate;
struct iwl_scale_tbl_info tbl_type;
- struct iwl_scale_tbl_info *curr_tbl, *search_tbl;
- u8 active_index = 0;
+ struct iwl_scale_tbl_info *curr_tbl, *other_tbl;
s32 tpt = 0;
IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n");
@@ -841,30 +764,14 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
info->flags & IEEE80211_TX_CTL_NO_ACK)
return;
- /* This packet was aggregated but doesn't carry rate scale info */
+ /* This packet was aggregated but doesn't carry status info */
if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
!(info->flags & IEEE80211_TX_STAT_AMPDU))
return;
- if (info->flags & IEEE80211_TX_STAT_AMPDU)
- retries = 0;
- else
- retries = info->status.rates[0].count - 1;
-
- if (retries > 15)
- retries = 15;
-
if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
!lq_sta->ibss_sta_added)
- goto out;
-
- table = &lq_sta->lq;
- active_index = lq_sta->active_tbl;
-
- curr_tbl = &(lq_sta->lq_info[active_index]);
- search_tbl = &(lq_sta->lq_info[(1 - active_index)]);
- window = (struct iwl_rate_scale_data *)&(curr_tbl->win[0]);
- search_win = (struct iwl_rate_scale_data *)&(search_tbl->win[0]);
+ return;
/*
* Ignore this Tx frame response if its initial rate doesn't match
@@ -874,6 +781,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
* to check "search" mode, or a prior "search" mode after we've moved
* to a new "search" mode (which might become the new "active" mode).
*/
+ table = &lq_sta->lq;
tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags);
rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index);
if (priv->band == IEEE80211_BAND_5GHZ)
@@ -892,7 +800,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
if (priv->band == IEEE80211_BAND_2GHZ)
mac_index += IWL_FIRST_OFDM_RATE;
}
-
+ /* Here we actually compare this rate to the latest LQ command */
if ((mac_index < 0) ||
(tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) ||
(tbl_type.is_ht40 != !!(mac_flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) ||
@@ -902,124 +810,106 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
(!!(tx_rate & RATE_MCS_GF_MSK) != !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) ||
(rs_index != mac_index)) {
IWL_DEBUG_RATE(priv, "initial rate %d does not match %d (0x%x)\n", mac_index, rs_index, tx_rate);
- /* the last LQ command could failed so the LQ in ucode not
- * the same in driver sync up
+ /*
+ * Since rates mis-match, the last LQ command may have failed.
+ * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with
+ * ... driver.
*/
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);
}
- goto out;
+ /* Regardless, ignore this status info for outdated rate */
+ return;
+ } else
+ /* Rate did match, so reset the missed_rate_counter */
+ lq_sta->missed_rate_counter = 0;
+
+ /* Figure out if rate scale algorithm is in active or search table */
+ if (table_type_matches(&tbl_type,
+ &(lq_sta->lq_info[lq_sta->active_tbl]))) {
+ curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
+ } else if (table_type_matches(&tbl_type,
+ &lq_sta->lq_info[1 - lq_sta->active_tbl])) {
+ curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
+ other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ } else {
+ IWL_DEBUG_RATE(priv, "Neither active nor search matches tx rate\n");
+ return;
}
+ window = (struct iwl_rate_scale_data *)&(curr_tbl->win[0]);
- lq_sta->missed_rate_counter = 0;
- /* Update frame history window with "failure" for each Tx retry. */
- while (retries) {
- /* Look up the rate and other info used for each tx attempt.
- * Each tx attempt steps one entry deeper in the rate table. */
- tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags);
- rs_get_tbl_info_from_mcs(tx_rate, priv->band,
- &tbl_type, &rs_index);
-
- /* If type matches "search" table,
- * add failure to "search" history */
- if ((tbl_type.lq_type == search_tbl->lq_type) &&
- (tbl_type.ant_type == search_tbl->ant_type) &&
- (tbl_type.is_SGI == search_tbl->is_SGI)) {
- if (search_tbl->expected_tpt)
- tpt = search_tbl->expected_tpt[rs_index];
- else
- tpt = 0;
- rs_collect_tx_data(search_win, rs_index, tpt, 1, 0);
-
- /* Else if type matches "current/active" table,
- * add failure to "current/active" history */
- } else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
- (tbl_type.ant_type == curr_tbl->ant_type) &&
- (tbl_type.is_SGI == curr_tbl->is_SGI)) {
- if (curr_tbl->expected_tpt)
- tpt = curr_tbl->expected_tpt[rs_index];
- else
- tpt = 0;
- rs_collect_tx_data(window, rs_index, tpt, 1, 0);
+ /*
+ * Updating the frame history depends on whether packets were
+ * aggregated.
+ *
+ * For aggregation, all packets were transmitted at the same rate, the
+ * first index into rate scale table.
+ */
+ if (info->flags & IEEE80211_TX_STAT_AMPDU) {
+ tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags);
+ rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type,
+ &rs_index);
+ tpt = get_expected_tpt(curr_tbl, rs_index);
+ rs_collect_tx_data(window, rs_index, tpt,
+ info->status.ampdu_ack_len,
+ info->status.ampdu_ack_map);
+
+ /* Update success/fail counts if not searching for new mode */
+ if (lq_sta->stay_in_tbl) {
+ lq_sta->total_success += info->status.ampdu_ack_map;
+ lq_sta->total_failed += (info->status.ampdu_ack_len -
+ info->status.ampdu_ack_map);
}
-
- /* If not searching for a new mode, increment failed counter
- * ... this helps determine when to start searching again */
- if (lq_sta->stay_in_tbl)
- lq_sta->total_failed++;
- --retries;
- index++;
-
- }
-
+ } else {
/*
- * Find (by rate) the history window to update with final Tx attempt;
- * if Tx was successful first try, use original rate,
- * else look up the rate that was, finally, successful.
+ * For legacy, update frame history with for each Tx retry.
*/
- tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags);
- lq_sta->last_rate_n_flags = tx_rate;
- rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index);
-
- /* Update frame history window with "success" if Tx got ACKed ... */
- status = !!(info->flags & IEEE80211_TX_STAT_ACK);
-
- /* If type matches "search" table,
- * add final tx status to "search" history */
- if ((tbl_type.lq_type == search_tbl->lq_type) &&
- (tbl_type.ant_type == search_tbl->ant_type) &&
- (tbl_type.is_SGI == search_tbl->is_SGI)) {
- if (search_tbl->expected_tpt)
- tpt = search_tbl->expected_tpt[rs_index];
- else
- tpt = 0;
- if (info->flags & IEEE80211_TX_STAT_AMPDU)
- rs_collect_tx_data(search_win, rs_index, tpt,
- info->status.ampdu_ack_len,
- info->status.ampdu_ack_map);
- else
- rs_collect_tx_data(search_win, rs_index, tpt,
- 1, status);
- /* Else if type matches "current/active" table,
- * add final tx status to "current/active" history */
- } else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
- (tbl_type.ant_type == curr_tbl->ant_type) &&
- (tbl_type.is_SGI == curr_tbl->is_SGI)) {
- if (curr_tbl->expected_tpt)
- tpt = curr_tbl->expected_tpt[rs_index];
- else
- tpt = 0;
- if (info->flags & IEEE80211_TX_STAT_AMPDU)
- rs_collect_tx_data(window, rs_index, tpt,
- info->status.ampdu_ack_len,
- info->status.ampdu_ack_map);
- else
- rs_collect_tx_data(window, rs_index, tpt,
- 1, status);
- }
+ retries = info->status.rates[0].count - 1;
+ /* HW doesn't send more than 15 retries */
+ retries = min(retries, 15);
+
+ /* The last transmission may have been successful */
+ legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK);
+ /* Collect data for each rate used during failed TX attempts */
+ for (i = 0; i <= retries; ++i) {
+ tx_rate = le32_to_cpu(table->rs_table[i].rate_n_flags);
+ rs_get_tbl_info_from_mcs(tx_rate, priv->band,
+ &tbl_type, &rs_index);
+ /*
+ * Only collect stats if retried rate is in the same RS
+ * table as active/search.
+ */
+ if (table_type_matches(&tbl_type, curr_tbl))
+ tpt = get_expected_tpt(curr_tbl, rs_index);
+ else if (table_type_matches(&tbl_type, other_tbl))
+ tpt = get_expected_tpt(other_tbl, rs_index);
+ else
+ continue;
- /* If not searching for new mode, increment success/failed counter
- * ... these help determine when to start searching again */
- if (lq_sta->stay_in_tbl) {
- if (info->flags & IEEE80211_TX_STAT_AMPDU) {
- lq_sta->total_success += info->status.ampdu_ack_map;
- lq_sta->total_failed +=
- (info->status.ampdu_ack_len - info->status.ampdu_ack_map);
- } else {
- if (status)
- lq_sta->total_success++;
+ /* Constants mean 1 transmission, 0 successes */
+ if (i < retries)
+ rs_collect_tx_data(window, rs_index, tpt, 1,
+ 0);
else
- lq_sta->total_failed++;
+ rs_collect_tx_data(window, rs_index, tpt, 1,
+ legacy_success);
+ }
+
+ /* Update success/fail counts if not searching for new mode */
+ if (lq_sta->stay_in_tbl) {
+ lq_sta->total_success += legacy_success;
+ lq_sta->total_failed += retries + (1 - legacy_success);
}
}
+ /* The last TX rate is cached in lq_sta; it's set in if/else above */
+ lq_sta->last_rate_n_flags = tx_rate;
/* 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);
-out:
- return;
}
/*
@@ -1057,43 +947,45 @@ static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy,
static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
struct iwl_scale_tbl_info *tbl)
{
+ /* Used to choose among HT tables */
+ s32 (*ht_tbl_pointer)[IWL_RATE_COUNT];
+
+ /* Check for invalid LQ type */
+ if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_Ht(tbl->lq_type))) {
+ tbl->expected_tpt = expected_tpt_legacy;
+ return;
+ }
+
+ /* Legacy rates have only one table */
if (is_legacy(tbl->lq_type)) {
- if (!is_a_band(tbl->lq_type))
- tbl->expected_tpt = expected_tpt_G;
- else
- tbl->expected_tpt = expected_tpt_A;
- } else if (is_siso(tbl->lq_type)) {
- if (tbl->is_ht40 && !lq_sta->is_dup)
- if (tbl->is_SGI)
- tbl->expected_tpt = expected_tpt_siso40MHzSGI;
- else
- tbl->expected_tpt = expected_tpt_siso40MHz;
- else if (tbl->is_SGI)
- tbl->expected_tpt = expected_tpt_siso20MHzSGI;
- else
- tbl->expected_tpt = expected_tpt_siso20MHz;
- } else if (is_mimo2(tbl->lq_type)) {
- if (tbl->is_ht40 && !lq_sta->is_dup)
- if (tbl->is_SGI)
- tbl->expected_tpt = expected_tpt_mimo2_40MHzSGI;
- else
- tbl->expected_tpt = expected_tpt_mimo2_40MHz;
- else if (tbl->is_SGI)
- tbl->expected_tpt = expected_tpt_mimo2_20MHzSGI;
- else
- tbl->expected_tpt = expected_tpt_mimo2_20MHz;
- } else if (is_mimo3(tbl->lq_type)) {
- if (tbl->is_ht40 && !lq_sta->is_dup)
- if (tbl->is_SGI)
- tbl->expected_tpt = expected_tpt_mimo3_40MHzSGI;
- else
- tbl->expected_tpt = expected_tpt_mimo3_40MHz;
- else if (tbl->is_SGI)
- tbl->expected_tpt = expected_tpt_mimo3_20MHzSGI;
- else
- tbl->expected_tpt = expected_tpt_mimo3_20MHz;
- } else
- tbl->expected_tpt = expected_tpt_G;
+ tbl->expected_tpt = expected_tpt_legacy;
+ return;
+ }
+
+ /* Choose among many HT tables depending on number of streams
+ * (SISO/MIMO2/MIMO3), channel width (20/40), SGI, and aggregation
+ * status */
+ if (is_siso(tbl->lq_type) && (!tbl->is_ht40 || lq_sta->is_dup))
+ ht_tbl_pointer = expected_tpt_siso20MHz;
+ else if (is_siso(tbl->lq_type))
+ ht_tbl_pointer = expected_tpt_siso40MHz;
+ else if (is_mimo2(tbl->lq_type) && (!tbl->is_ht40 || lq_sta->is_dup))
+ ht_tbl_pointer = expected_tpt_mimo2_20MHz;
+ else if (is_mimo2(tbl->lq_type))
+ ht_tbl_pointer = expected_tpt_mimo2_40MHz;
+ else if (is_mimo3(tbl->lq_type) && (!tbl->is_ht40 || lq_sta->is_dup))
+ ht_tbl_pointer = expected_tpt_mimo3_20MHz;
+ else /* if (is_mimo3(tbl->lq_type)) <-- must be true */
+ ht_tbl_pointer = expected_tpt_mimo3_40MHz;
+
+ if (!tbl->is_SGI && !lq_sta->is_agg) /* Normal */
+ tbl->expected_tpt = ht_tbl_pointer[0];
+ else if (tbl->is_SGI && !lq_sta->is_agg) /* SGI */
+ tbl->expected_tpt = ht_tbl_pointer[1];
+ else if (!tbl->is_SGI && lq_sta->is_agg) /* AGG */
+ tbl->expected_tpt = ht_tbl_pointer[2];
+ else /* AGG+SGI */
+ tbl->expected_tpt = ht_tbl_pointer[3];
}
/*
@@ -2068,6 +1960,14 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
tid = rs_tl_add_packet(lq_sta, hdr);
+ if ((tid != MAX_TID_COUNT) && (lq_sta->tx_agg_tid_en & (1 << tid))) {
+ tid_data = &priv->stations[lq_sta->lq.sta_id].tid[tid];
+ if (tid_data->agg.state == IWL_AGG_OFF)
+ lq_sta->is_agg = 0;
+ else
+ lq_sta->is_agg = 1;
+ } else
+ lq_sta->is_agg = 0;
/*
* Select rate-scale / modulation-mode table to work with in
@@ -2168,10 +2068,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
goto out;
}
-
/* Else we have enough samples; calculate estimate of
* actual average throughput */
+ /* Sanity-check TPT calculations */
BUG_ON(window->average_tpt != ((window->success_ratio *
tbl->expected_tpt[index] + 64) / 128));
@@ -2575,19 +2475,17 @@ static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
gfp_t gfp)
{
struct iwl_lq_sta *lq_sta;
+ struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv;
struct iwl_priv *priv;
int i, j;
priv = (struct iwl_priv *)priv_rate;
IWL_DEBUG_RATE(priv, "create station rate scale window\n");
- lq_sta = kzalloc(sizeof(struct iwl_lq_sta), gfp);
+ lq_sta = &sta_priv->lq_sta;
- if (lq_sta == NULL)
- return NULL;
lq_sta->lq.sta_id = 0xff;
-
for (j = 0; j < LQ_SIZE; j++)
for (i = 0; i < IWL_RATE_COUNT; i++)
rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
@@ -2681,6 +2579,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
lq_sta->last_txrate_idx = rate_lowest_index(sband, sta);
if (sband->band == IEEE80211_BAND_5GHZ)
lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
+ lq_sta->is_agg = 0;
rs_initialize_lq(priv, conf, sta, lq_sta);
}
@@ -2799,7 +2698,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
repeat_rate--;
}
- lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_MAX;
+ 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);
@@ -2818,11 +2717,9 @@ static void rs_free(void *priv_rate)
static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta,
void *priv_sta)
{
- struct iwl_lq_sta *lq_sta = priv_sta;
struct iwl_priv *priv __maybe_unused = priv_r;
IWL_DEBUG_RATE(priv, "enter\n");
- kfree(lq_sta);
IWL_DEBUG_RATE(priv, "leave\n");
}
@@ -2933,8 +2830,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3"));
desc += sprintf(buff+desc, " %s",
(tbl->is_ht40) ? "40MHz" : "20MHz");
- desc += sprintf(buff+desc, " %s %s\n", (tbl->is_SGI) ? "SGI" : "",
- (lq_sta->is_green) ? "GF enabled" : "");
+ desc += sprintf(buff+desc, " %s %s %s\n", (tbl->is_SGI) ? "SGI" : "",
+ (lq_sta->is_green) ? "GF enabled" : "",
+ (lq_sta->is_agg) ? "AGG on" : "");
}
desc += sprintf(buff+desc, "last tx rate=0x%X\n",
lq_sta->last_rate_n_flags);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
index 9fac530cfb7e..affc0c5a2f2c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
@@ -54,6 +54,7 @@ struct iwl3945_rate_info {
u8 prev_table_rs; /* prev in rate table cmd */
};
+
/*
* These serve as indexes into
* struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
@@ -335,6 +336,106 @@ struct iwl_rate_mcs_info {
char mcs[IWL_MAX_MCS_DISPLAY_SIZE];
};
+/**
+ * struct iwl_rate_scale_data -- tx success history for one rate
+ */
+struct iwl_rate_scale_data {
+ u64 data; /* bitmap of successful frames */
+ s32 success_counter; /* number of frames successful */
+ s32 success_ratio; /* per-cent * 128 */
+ s32 counter; /* number of frames attempted */
+ s32 average_tpt; /* success ratio * expected throughput */
+ unsigned long stamp;
+};
+
+/**
+ * struct iwl_scale_tbl_info -- tx params and success history for all rates
+ *
+ * There are two of these in struct iwl_lq_sta,
+ * one for "active", and one for "search".
+ */
+struct iwl_scale_tbl_info {
+ enum iwl_table_type lq_type;
+ u8 ant_type;
+ u8 is_SGI; /* 1 = short guard interval */
+ u8 is_ht40; /* 1 = 40 MHz channel width */
+ u8 is_dup; /* 1 = duplicated data streams */
+ u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
+ u8 max_search; /* maximun number of tables we can search */
+ s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
+ u32 current_rate; /* rate_n_flags, uCode API format */
+ struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
+};
+
+struct iwl_traffic_load {
+ unsigned long time_stamp; /* age of the oldest statistics */
+ u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time
+ * slice */
+ u32 total; /* total num of packets during the
+ * last TID_MAX_TIME_DIFF */
+ u8 queue_count; /* number of queues that has
+ * been used since the last cleanup */
+ u8 head; /* start of the circular buffer */
+};
+
+/**
+ * struct iwl_lq_sta -- driver's rate scaling private structure
+ *
+ * Pointer to this gets passed back and forth between driver and mac80211.
+ */
+struct iwl_lq_sta {
+ u8 active_tbl; /* index of active table, range 0-1 */
+ u8 enable_counter; /* indicates HT mode */
+ u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */
+ u8 search_better_tbl; /* 1: currently trying alternate mode */
+ s32 last_tpt;
+
+ /* The following determine when to search for a new mode */
+ u32 table_count_limit;
+ u32 max_failure_limit; /* # failed frames before new search */
+ u32 max_success_limit; /* # successful frames before new search */
+ u32 table_count;
+ u32 total_failed; /* total failed frames, any/all rates */
+ u32 total_success; /* total successful frames, any/all rates */
+ u64 flush_timer; /* time staying in mode before new search */
+
+ u8 action_counter; /* # mode-switch actions tried */
+ u8 is_green;
+ u8 is_dup;
+ enum ieee80211_band band;
+ u8 ibss_sta_added;
+
+ /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
+ u32 supp_rates;
+ u16 active_legacy_rate;
+ u16 active_siso_rate;
+ u16 active_mimo2_rate;
+ u16 active_mimo3_rate;
+ u16 active_rate_basic;
+ s8 max_rate_idx; /* Max rate set by user */
+ u8 missed_rate_counter;
+
+ struct iwl_link_quality_cmd lq;
+ struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
+ struct iwl_traffic_load load[TID_MAX_LOAD_COUNT];
+ u8 tx_agg_tid_en;
+#ifdef CONFIG_MAC80211_DEBUGFS
+ struct dentry *rs_sta_dbgfs_scale_table_file;
+ struct dentry *rs_sta_dbgfs_stats_table_file;
+ struct dentry *rs_sta_dbgfs_rate_scale_data_file;
+ struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
+ u32 dbg_fixed_rate;
+#endif
+ struct iwl_priv *drv;
+
+ /* used to be in sta_info */
+ int last_txrate_idx;
+ /* last tx rate_n_flags */
+ u32 last_rate_n_flags;
+ /* packets destined for this STA are aggregated */
+ u8 is_agg;
+};
+
static inline u8 num_of_ant(u8 mask)
{
return !!((mask) & ANT_A) +
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index eaafae091f5b..06717fc945bc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -116,9 +116,6 @@ int iwl_commit_rxon(struct iwl_priv *priv)
/* always get timestamp with Rx frame */
priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
- /* allow CTS-to-self if possible. this is relevant only for
- * 5000, but will not damage 4965 */
- priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
ret = iwl_check_rxon_cmd(priv);
if (ret) {
@@ -218,6 +215,13 @@ int iwl_commit_rxon(struct iwl_priv *priv)
"Could not send WEP static key.\n");
}
+ /*
+ * allow CTS-to-self if possible for new association.
+ * this is relevant only for 5000 series and up,
+ * but will not damage 4965
+ */
+ priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
+
/* Apply the new configuration
* RXON assoc doesn't clear the station table in uCode,
*/
@@ -521,7 +525,7 @@ int iwl_hw_tx_queue_init(struct iwl_priv *priv,
static void iwl_rx_reply_alive(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_alive_resp *palive;
struct delayed_work *pwork;
@@ -607,7 +611,7 @@ 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 = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl4965_beacon_notif *beacon =
(struct iwl4965_beacon_notif *)pkt->u.raw;
u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
@@ -631,7 +635,7 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
static void iwl_rx_card_state_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
unsigned long status = priv->status;
@@ -766,7 +770,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i);
/* calculate total frames need to be restock after handling RX */
- total_empty = r - priv->rxq.write_actual;
+ total_empty = r - rxq->write_actual;
if (total_empty < 0)
total_empty += RX_QUEUE_SIZE;
@@ -783,10 +787,13 @@ void iwl_rx_handle(struct iwl_priv *priv)
rxq->queue[i] = NULL;
- pci_unmap_single(priv->pci_dev, rxb->real_dma_addr,
- priv->hw_params.rx_buf_size + 256,
- PCI_DMA_FROMDEVICE);
- pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ pci_unmap_page(priv->pci_dev, rxb->page_dma,
+ PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
+ pkt = rxb_addr(rxb);
+
+ trace_iwlwifi_dev_rx(priv, pkt,
+ le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
/* Reclaim a command buffer only if this packet is a response
* to a (driver-originated) command.
@@ -808,8 +815,8 @@ void iwl_rx_handle(struct iwl_priv *priv)
if (priv->rx_handlers[pkt->hdr.cmd]) {
IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r,
i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
- priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
priv->isr_stats.rx_handlers[pkt->hdr.cmd]++;
+ priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
} else {
/* No handling needed */
IWL_DEBUG_RX(priv,
@@ -818,35 +825,45 @@ void iwl_rx_handle(struct iwl_priv *priv)
pkt->hdr.cmd);
}
+ /*
+ * XXX: After here, we should always check rxb->page
+ * against NULL before touching it or its virtual
+ * memory (pkt). Because some rx_handler might have
+ * already taken or freed the pages.
+ */
+
if (reclaim) {
- /* Invoke any callbacks, transfer the skb to caller, and
- * fire off the (possibly) blocking iwl_send_cmd()
+ /* Invoke any callbacks, transfer the buffer to caller,
+ * and fire off the (possibly) blocking iwl_send_cmd()
* as we reclaim the driver command queue */
- if (rxb && rxb->skb)
+ if (rxb->page)
iwl_tx_cmd_complete(priv, rxb);
else
IWL_WARN(priv, "Claim null rxb?\n");
}
- /* For now we just don't re-use anything. We can tweak this
- * later to try and re-use notification packets and SKBs that
- * fail to Rx correctly */
- if (rxb->skb != NULL) {
- priv->alloc_rxb_skb--;
- dev_kfree_skb_any(rxb->skb);
- rxb->skb = NULL;
- }
-
+ /* Reuse the page if possible. For notification packets and
+ * SKBs that fail to Rx correctly, add them back into the
+ * rx_free list for reuse later. */
spin_lock_irqsave(&rxq->lock, flags);
- list_add_tail(&rxb->list, &priv->rxq.rx_used);
+ if (rxb->page != NULL) {
+ rxb->page_dma = pci_map_page(priv->pci_dev, rxb->page,
+ 0, PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
+ list_add_tail(&rxb->list, &rxq->rx_free);
+ rxq->free_count++;
+ } else
+ list_add_tail(&rxb->list, &rxq->rx_used);
+
spin_unlock_irqrestore(&rxq->lock, flags);
+
i = (i + 1) & RX_QUEUE_MASK;
/* If there are a lot of unused frames,
* restock the Rx queue so ucode wont assert. */
if (fill_rx) {
count++;
if (count >= 8) {
- priv->rxq.read = i;
+ rxq->read = i;
iwl_rx_replenish_now(priv);
count = 0;
}
@@ -854,7 +871,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
}
/* Backtrack one entry */
- priv->rxq.read = i;
+ rxq->read = i;
if (fill_rx)
iwl_rx_replenish_now(priv);
else
@@ -901,6 +918,8 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
}
#endif
+ spin_unlock_irqrestore(&priv->lock, flags);
+
/* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
* atomic, make sure that inta covers all the interrupts that
* we've discovered, even if FH interrupt came in just after
@@ -922,8 +941,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
handled |= CSR_INT_BIT_HW_ERR;
- spin_unlock_irqrestore(&priv->lock, flags);
-
return;
}
@@ -1013,6 +1030,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
iwl_rx_handle(priv);
priv->isr_stats.rx++;
+ iwl_leds_background(priv);
handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
}
@@ -1050,7 +1068,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
"flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
}
#endif
- spin_unlock_irqrestore(&priv->lock, flags);
}
/* tasklet for iwlagn interrupt */
@@ -1080,6 +1097,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
inta, inta_mask);
}
#endif
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
/* saved interrupt in inta variable now we can reset priv->inta */
priv->inta = 0;
@@ -1095,8 +1115,6 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
handled |= CSR_INT_BIT_HW_ERR;
- spin_unlock_irqrestore(&priv->lock, flags);
-
return;
}
@@ -1214,6 +1232,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
CSR_INT_PERIODIC_ENA);
priv->isr_stats.rx++;
+ iwl_leds_background(priv);
}
if (inta & CSR_INT_BIT_FH_TX) {
@@ -1236,14 +1255,10 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
inta & ~priv->inta_mask);
}
-
/* Re-enable all interrupts */
/* only Re-enable if diabled by irq */
if (test_bit(STATUS_INT_ENABLED, &priv->status))
iwl_enable_interrupts(priv);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
}
@@ -1607,6 +1622,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
+ trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line,
+ blink1, blink2, ilink1, ilink2);
+
IWL_ERR(priv, "Desc Time "
"data1 data2 line\n");
IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
@@ -1655,12 +1673,14 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
ptr += sizeof(u32);
if (mode == 0) {
/* data, ev */
+ trace_iwlwifi_dev_ucode_event(priv, 0, time, ev);
IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev);
} else {
data = iwl_read_targ_mem(priv, ptr);
ptr += sizeof(u32);
IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
time, data, ev);
+ trace_iwlwifi_dev_ucode_event(priv, time, data, ev);
}
}
}
@@ -1759,6 +1779,10 @@ static void iwl_alive_start(struct iwl_priv *priv)
priv->active_rate = priv->rates_mask;
priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+ /* Configure Tx antenna selection based on H/W config */
+ 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)) {
struct iwl_rxon_cmd *active_rxon =
(struct iwl_rxon_cmd *)&priv->active_rxon;
@@ -1786,7 +1810,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
/* At this point, the NIC is initialized and operational */
iwl_rf_kill_ct_config(priv);
- iwl_leds_register(priv);
+ iwl_leds_init(priv);
IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
set_bit(STATUS_READY, &priv->status);
@@ -1824,8 +1848,6 @@ static void __iwl_down(struct iwl_priv *priv)
if (!exit_pending)
set_bit(STATUS_EXIT_PENDING, &priv->status);
- iwl_leds_unregister(priv);
-
iwl_clear_stations_table(priv);
/* Unblock any waiting calls */
@@ -1886,11 +1908,9 @@ static void __iwl_down(struct iwl_priv *priv)
udelay(5);
- /* FIXME: apm_ops.suspend(priv) */
- if (exit_pending)
- priv->cfg->ops->lib->apm_ops.stop(priv);
- else
- priv->cfg->ops->lib->apm_ops.reset(priv);
+ /* Stop the device, and put it in low power state */
+ priv->cfg->ops->lib->apm_ops.stop(priv);
+
exit:
memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
@@ -2277,6 +2297,69 @@ void iwl_post_associate(struct iwl_priv *priv)
#define UCODE_READY_TIMEOUT (4 * HZ)
+/*
+ * Not a mac80211 entry point function, but it fits in with all the
+ * other mac80211 functions grouped here.
+ */
+static int iwl_setup_mac(struct iwl_priv *priv)
+{
+ int ret;
+ struct ieee80211_hw *hw = priv->hw;
+ hw->rate_control_algorithm = "iwl-agn-rs";
+
+ /* Tell mac80211 our characteristics */
+ hw->flags = IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_NOISE_DBM |
+ IEEE80211_HW_AMPDU_AGGREGATION |
+ IEEE80211_HW_SPECTRUM_MGMT;
+
+ if (!priv->cfg->broken_powersave)
+ hw->flags |= IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
+
+ hw->sta_data_size = sizeof(struct iwl_station_priv);
+ hw->wiphy->interface_modes =
+ BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC);
+
+ hw->wiphy->custom_regulatory = true;
+
+ /* Firmware does not support this */
+ hw->wiphy->disable_beacon_hints = true;
+
+ /*
+ * For now, disable PS by default because it affects
+ * RX performance significantly.
+ */
+ hw->wiphy->ps_default = false;
+
+ hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
+ /* we create the 802.11 header and a zero-length SSID element */
+ hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
+
+ /* Default value; 4 EDCA QOS priorities */
+ hw->queues = 4;
+
+ hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
+
+ if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
+ priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+ &priv->bands[IEEE80211_BAND_2GHZ];
+ if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
+ priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ &priv->bands[IEEE80211_BAND_5GHZ];
+
+ ret = ieee80211_register_hw(priv->hw);
+ if (ret) {
+ IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
+ return ret;
+ }
+ priv->mac80211_registered = 1;
+
+ return 0;
+}
+
+
static int iwl_mac_start(struct ieee80211_hw *hw)
{
struct iwl_priv *priv = hw->priv;
@@ -2324,6 +2407,8 @@ static int iwl_mac_start(struct ieee80211_hw *hw)
}
}
+ iwl_led_start(priv);
+
out:
priv->is_open = 1;
IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -2795,6 +2880,40 @@ static ssize_t show_statistics(struct device *d,
static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
+static ssize_t show_rts_ht_protection(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ return sprintf(buf, "%s\n",
+ priv->cfg->use_rts_for_ht ? "RTS/CTS" : "CTS-to-self");
+}
+
+static ssize_t store_rts_ht_protection(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ unsigned long val;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &val);
+ if (ret)
+ IWL_INFO(priv, "Input is not in decimal form.\n");
+ else {
+ if (!iwl_is_associated(priv))
+ priv->cfg->use_rts_for_ht = val ? true : false;
+ else
+ IWL_ERR(priv, "Sta associated with AP - "
+ "Change protection mechanism is not allowed\n");
+ ret = count;
+ }
+ return ret;
+}
+
+static DEVICE_ATTR(rts_ht_protection, S_IWUSR | S_IRUGO,
+ show_rts_ht_protection, store_rts_ht_protection);
+
/*****************************************************************************
*
@@ -2851,6 +2970,7 @@ static struct attribute *iwl_sysfs_entries[] = {
&dev_attr_statistics.attr,
&dev_attr_temperature.attr,
&dev_attr_tx_power.attr,
+ &dev_attr_rts_ht_protection.attr,
#ifdef CONFIG_IWLWIFI_DEBUG
&dev_attr_debug_level.attr,
#endif
@@ -3137,6 +3257,15 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
iwl_down(priv);
}
+ /*
+ * Make sure device is reset to low power before unloading driver.
+ * This may be redundant with iwl_down(), but there are paths to
+ * run iwl_down() without calling apm_ops.stop(), and there are
+ * 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_tt_exit(priv);
/* make sure we flush any pending irq or
@@ -3216,20 +3345,51 @@ static struct pci_device_id iwl_hw_card_ids[] = {
/* 5150 Wifi/WiMax */
{IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)},
{IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)},
-/* 6000/6050 Series */
- {IWL_PCI_DEVICE(0x008D, PCI_ANY_ID, iwl6000h_2agn_cfg)},
- {IWL_PCI_DEVICE(0x008E, PCI_ANY_ID, iwl6000h_2agn_cfg)},
- {IWL_PCI_DEVICE(0x422B, PCI_ANY_ID, iwl6000_3agn_cfg)},
- {IWL_PCI_DEVICE(0x422C, PCI_ANY_ID, iwl6000i_2agn_cfg)},
- {IWL_PCI_DEVICE(0x4238, PCI_ANY_ID, iwl6000_3agn_cfg)},
- {IWL_PCI_DEVICE(0x4239, PCI_ANY_ID, iwl6000i_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0086, PCI_ANY_ID, iwl6050_3agn_cfg)},
- {IWL_PCI_DEVICE(0x0087, PCI_ANY_ID, iwl6050_2agn_cfg)},
- {IWL_PCI_DEVICE(0x0088, PCI_ANY_ID, iwl6050_3agn_cfg)},
- {IWL_PCI_DEVICE(0x0089, PCI_ANY_ID, iwl6050_2agn_cfg)},
+
+/* 6x00 Series */
+ {IWL_PCI_DEVICE(0x008D, 0x1301, iwl6000h_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x008D, 0x1321, iwl6000h_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x008D, 0x1326, iwl6000h_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x008D, 0x1306, iwl6000h_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x008D, 0x1307, iwl6000h_2bg_cfg)},
+ {IWL_PCI_DEVICE(0x008E, 0x1311, iwl6000h_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x008E, 0x1316, iwl6000h_2abg_cfg)},
+
+ {IWL_PCI_DEVICE(0x422B, 0x1101, iwl6000_3agn_cfg)},
+ {IWL_PCI_DEVICE(0x422B, 0x1121, iwl6000_3agn_cfg)},
+ {IWL_PCI_DEVICE(0x422C, 0x1301, iwl6000i_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x422C, 0x1306, iwl6000i_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x422C, 0x1307, iwl6000i_2bg_cfg)},
+ {IWL_PCI_DEVICE(0x422C, 0x1321, iwl6000i_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x422C, 0x1326, iwl6000i_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x4238, 0x1111, iwl6000_3agn_cfg)},
+ {IWL_PCI_DEVICE(0x4239, 0x1311, iwl6000i_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)},
+
+/* 6x50 WiFi/WiMax Series */
+ {IWL_PCI_DEVICE(0x0086, 0x1101, iwl6050_3agn_cfg)},
+ {IWL_PCI_DEVICE(0x0086, 0x1121, iwl6050_3agn_cfg)},
+ {IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0087, 0x1306, iwl6050_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0087, 0x1321, iwl6050_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0087, 0x1326, iwl6050_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0088, 0x1111, iwl6050_3agn_cfg)},
+ {IWL_PCI_DEVICE(0x0089, 0x1311, iwl6050_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)},
+
/* 1000 Series WiFi */
- {IWL_PCI_DEVICE(0x0083, PCI_ANY_ID, iwl1000_bgn_cfg)},
- {IWL_PCI_DEVICE(0x0084, PCI_ANY_ID, iwl1000_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0083, 0x1205, iwl1000_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0083, 0x1305, iwl1000_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0083, 0x1225, iwl1000_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0083, 0x1325, iwl1000_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0084, 0x1215, iwl1000_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0084, 0x1315, iwl1000_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0083, 0x1206, iwl1000_bg_cfg)},
+ {IWL_PCI_DEVICE(0x0083, 0x1306, iwl1000_bg_cfg)},
+ {IWL_PCI_DEVICE(0x0083, 0x1226, iwl1000_bg_cfg)},
+ {IWL_PCI_DEVICE(0x0083, 0x1326, iwl1000_bg_cfg)},
+ {IWL_PCI_DEVICE(0x0084, 0x1216, iwl1000_bg_cfg)},
+ {IWL_PCI_DEVICE(0x0084, 0x1316, iwl1000_bg_cfg)},
#endif /* CONFIG_IWL5000 */
{0}
@@ -3284,9 +3444,9 @@ module_exit(iwl_exit);
module_init(iwl_init);
#ifdef CONFIG_IWLWIFI_DEBUG
-module_param_named(debug50, iwl_debug_level, uint, 0444);
+module_param_named(debug50, iwl_debug_level, uint, S_IRUGO);
MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)");
-module_param_named(debug, iwl_debug_level, uint, 0644);
+module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "debug output mask");
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c
index c4b565a2de94..1f801eb9fbff 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.c
@@ -447,11 +447,11 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
cpu_to_le16((u16)data->nrg_th_ofdm);
cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] =
- cpu_to_le16(190);
+ cpu_to_le16(data->barker_corr_th_min);
cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] =
- cpu_to_le16(390);
+ cpu_to_le16(data->barker_corr_th_min_mrc);
cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] =
- cpu_to_le16(62);
+ cpu_to_le16(data->nrg_th_cca);
IWL_DEBUG_CALIB(priv, "ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n",
data->auto_corr_ofdm, data->auto_corr_ofdm_mrc,
@@ -516,7 +516,7 @@ void iwl_init_sensitivity(struct iwl_priv *priv)
for (i = 0; i < NRG_NUM_PREV_STAT_L; i++)
data->nrg_silence_rssi[i] = 0;
- data->auto_corr_ofdm = 90;
+ data->auto_corr_ofdm = ranges->auto_corr_min_ofdm;
data->auto_corr_ofdm_mrc = ranges->auto_corr_min_ofdm_mrc;
data->auto_corr_ofdm_x1 = ranges->auto_corr_min_ofdm_x1;
data->auto_corr_ofdm_mrc_x1 = ranges->auto_corr_min_ofdm_mrc_x1;
@@ -524,6 +524,9 @@ void iwl_init_sensitivity(struct iwl_priv *priv)
data->auto_corr_cck_mrc = ranges->auto_corr_min_cck_mrc;
data->nrg_th_cck = ranges->nrg_th_cck;
data->nrg_th_ofdm = ranges->nrg_th_ofdm;
+ data->barker_corr_th_min = ranges->barker_corr_th_min;
+ data->barker_corr_th_min_mrc = ranges->barker_corr_th_min_mrc;
+ data->nrg_th_cca = ranges->nrg_th_cca;
data->last_bad_plcp_cnt_ofdm = 0;
data->last_fa_cnt_ofdm = 0;
@@ -643,6 +646,15 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv,
}
EXPORT_SYMBOL(iwl_sensitivity_calibration);
+static inline u8 find_first_chain(u8 mask)
+{
+ if (mask & ANT_A)
+ return CHAIN_A;
+ if (mask & ANT_B)
+ return CHAIN_B;
+ return CHAIN_C;
+}
+
/*
* Accumulate 20 beacons of signal and noise statistics for each of
* 3 receivers/antennas/rx-chains, then figure out:
@@ -675,14 +687,17 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
u8 num_tx_chains;
unsigned long flags;
struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general);
+ u8 first_chain;
if (priv->disable_chain_noise_cal)
return;
data = &(priv->chain_noise_data);
- /* Accumulate just the first 20 beacons after the first association,
- * then we're done forever. */
+ /*
+ * Accumulate just the first "chain_noise_num_beacons" after
+ * the first association, then we're done forever.
+ */
if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) {
if (data->state == IWL_CHAIN_NOISE_ALIVE)
IWL_DEBUG_CALIB(priv, "Wait for noise calib reset\n");
@@ -710,7 +725,10 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
return;
}
- /* Accumulate beacon statistics values across 20 beacons */
+ /*
+ * Accumulate beacon statistics values across
+ * "chain_noise_num_beacons"
+ */
chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) &
IN_BAND_FILTER;
chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) &
@@ -741,16 +759,19 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
IWL_DEBUG_CALIB(priv, "chain_noise: a %d b %d c %d\n",
chain_noise_a, chain_noise_b, chain_noise_c);
- /* If this is the 20th beacon, determine:
+ /* 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 != CAL_NUM_OF_BEACONS)
+ if (data->beacon_count != priv->cfg->chain_noise_num_beacons)
return;
/* Analyze signal for disconnected antenna */
- average_sig[0] = (data->chain_signal_a) / CAL_NUM_OF_BEACONS;
- average_sig[1] = (data->chain_signal_b) / CAL_NUM_OF_BEACONS;
- average_sig[2] = (data->chain_signal_c) / CAL_NUM_OF_BEACONS;
+ 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;
if (average_sig[0] >= average_sig[1]) {
max_average_sig = average_sig[0];
@@ -803,13 +824,17 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
/* there is a Tx antenna connected */
break;
if (num_tx_chains == priv->hw_params.tx_chains_num &&
- data->disconn_array[i]) {
- /* This is the last TX antenna and is also
- * disconnected connect it anyway */
- data->disconn_array[i] = 0;
- active_chains |= ant_msk;
- IWL_DEBUG_CALIB(priv, "All Tx chains are disconnected W/A - "
- "declare %d as connected\n", i);
+ data->disconn_array[i]) {
+ /*
+ * If all chains are disconnected
+ * connect the first valid tx chain
+ */
+ first_chain =
+ find_first_chain(priv->cfg->valid_tx_ant);
+ data->disconn_array[first_chain] = 0;
+ active_chains |= BIT(first_chain);
+ IWL_DEBUG_CALIB(priv, "All Tx chains are disconnected W/A - declare %d as connected\n",
+ first_chain);
break;
}
}
@@ -820,9 +845,12 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
active_chains);
/* Analyze noise for rx balance */
- average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS);
- average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS);
- average_noise[2] = ((data->chain_noise_c)/CAL_NUM_OF_BEACONS);
+ 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);
for (i = 0; i < NUM_RX_CHAINS; i++) {
if (!(data->disconn_array[i]) &&
@@ -843,7 +871,8 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
if (priv->cfg->ops->utils->gain_computation)
priv->cfg->ops->utils->gain_computation(priv, average_noise,
- min_average_noise_antenna_i, min_average_noise);
+ min_average_noise_antenna_i, min_average_noise,
+ find_first_chain(priv->cfg->valid_rx_ant));
/* Some power changes may have been made during the calibration.
* Update and commit the RXON
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 4afaf773aeac..954bad60355d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -109,11 +109,12 @@ enum {
REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */
/* WiMAX coexistence */
- COEX_PRIORITY_TABLE_CMD = 0x5a, /*5000 only */
+ COEX_PRIORITY_TABLE_CMD = 0x5a, /* for 5000 series and up */
COEX_MEDIUM_NOTIFICATION = 0x5b,
COEX_EVENT_CMD = 0x5c,
/* Calibration */
+ TEMPERATURE_NOTIFICATION = 0x62,
CALIBRATION_CFG_CMD = 0x65,
CALIBRATION_RES_NOTIFICATION = 0x66,
CALIBRATION_COMPLETE_NOTIFICATION = 0x67,
@@ -148,7 +149,7 @@ enum {
QUIET_NOTIFICATION = 0x96, /* not used */
REPLY_TX_PWR_TABLE_CMD = 0x97,
REPLY_TX_POWER_DBM_CMD_V1 = 0x98, /* old version of API */
- TX_ANT_CONFIGURATION_CMD = 0x98, /* not used */
+ TX_ANT_CONFIGURATION_CMD = 0x98,
MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */
/* Bluetooth device coexistence config command */
@@ -353,6 +354,9 @@ struct iwl3945_power_per_rate {
#define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32
#define POWER_TABLE_CCK_ENTRY 32
+#define IWL_PWR_NUM_HT_OFDM_ENTRIES 24
+#define IWL_PWR_CCK_ENTRIES 2
+
/**
* union iwl4965_tx_power_dual_stream
*
@@ -411,6 +415,16 @@ struct iwl5000_tx_power_dbm_cmd {
u8 reserved;
} __attribute__ ((packed));
+/**
+ * Command TX_ANT_CONFIGURATION_CMD = 0x98
+ * This command is used to configure valid Tx antenna.
+ * By default uCode concludes the valid antenna according to the radio flavor.
+ * This command enables the driver to override/modify this conclusion.
+ */
+struct iwl_tx_ant_config_cmd {
+ __le32 valid;
+} __attribute__ ((packed));
+
/******************************************************************************
* (0a)
* Alive and Error Commands & Responses:
@@ -793,7 +807,7 @@ struct iwl3945_channel_switch_cmd {
struct iwl3945_power_per_rate power[IWL_MAX_RATES];
} __attribute__ ((packed));
-struct iwl_channel_switch_cmd {
+struct iwl4965_channel_switch_cmd {
u8 band;
u8 expect_beacon;
__le16 channel;
@@ -803,6 +817,48 @@ struct iwl_channel_switch_cmd {
struct iwl4965_tx_power_db tx_power;
} __attribute__ ((packed));
+/**
+ * struct iwl5000_channel_switch_cmd
+ * @band: 0- 5.2GHz, 1- 2.4GHz
+ * @expect_beacon: 0- resume transmits after channel switch
+ * 1- wait for beacon to resume transmits
+ * @channel: new channel number
+ * @rxon_flags: Rx on flags
+ * @rxon_filter_flags: filtering parameters
+ * @switch_time: switch time in extended beacon format
+ * @reserved: reserved bytes
+ */
+struct iwl5000_channel_switch_cmd {
+ u8 band;
+ u8 expect_beacon;
+ __le16 channel;
+ __le32 rxon_flags;
+ __le32 rxon_filter_flags;
+ __le32 switch_time;
+ __le32 reserved[2][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES];
+} __attribute__ ((packed));
+
+/**
+ * struct iwl6000_channel_switch_cmd
+ * @band: 0- 5.2GHz, 1- 2.4GHz
+ * @expect_beacon: 0- resume transmits after channel switch
+ * 1- wait for beacon to resume transmits
+ * @channel: new channel number
+ * @rxon_flags: Rx on flags
+ * @rxon_filter_flags: filtering parameters
+ * @switch_time: switch time in extended beacon format
+ * @reserved: reserved bytes
+ */
+struct iwl6000_channel_switch_cmd {
+ u8 band;
+ u8 expect_beacon;
+ __le16 channel;
+ __le32 rxon_flags;
+ __le32 rxon_filter_flags;
+ __le32 switch_time;
+ __le32 reserved[3][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES];
+} __attribute__ ((packed));
+
/*
* CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
*/
@@ -2162,6 +2218,19 @@ struct iwl_link_quality_cmd {
__le32 reserved2;
} __attribute__ ((packed));
+#define BT_COEX_DISABLE (0x0)
+#define BT_COEX_MODE_2W (0x1)
+#define BT_COEX_MODE_3W (0x2)
+#define BT_COEX_MODE_4W (0x3)
+
+#define BT_LEAD_TIME_MIN (0x0)
+#define BT_LEAD_TIME_DEF (0x1E)
+#define BT_LEAD_TIME_MAX (0xFF)
+
+#define BT_MAX_KILL_MIN (0x1)
+#define BT_MAX_KILL_DEF (0x5)
+#define BT_MAX_KILL_MAX (0xFF)
+
/*
* REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
*
@@ -3237,12 +3306,6 @@ struct iwl_missed_beacon_notif {
* Lower values mean higher energy; this means making sure that the value
* in HD_MIN_ENERGY_CCK_DET_INDEX is at or *above* "Max cck energy".
*
- * Driver should set the following entries to fixed values:
- *
- * HD_MIN_ENERGY_OFDM_DET_INDEX 100
- * HD_BARKER_CORR_TH_ADD_MIN_INDEX 190
- * HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX 390
- * HD_OFDM_ENERGY_TH_IN_INDEX 62
*/
/*
@@ -3495,6 +3558,16 @@ struct iwl_wimax_coex_cmd {
*****************************************************************************/
struct iwl_rx_packet {
+ /*
+ * The first 4 bytes of the RX frame header contain both the RX frame
+ * size and some flags.
+ * Bit fields:
+ * 31: flag flush RB request
+ * 30: flag ignore TC (terminal counter) request
+ * 29: flag fast IRQ request
+ * 28-14: Reserved
+ * 13-00: RX frame size
+ */
__le32 len_n_flags;
struct iwl_cmd_header hdr;
union {
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 2dc928755454..1949f1aa16b4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -605,11 +605,27 @@ void iwlcore_free_geos(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwlcore_free_geos);
+/*
+ * iwlcore_rts_tx_cmd_flag: Set rts/cts. 3945 and 4965 only share this
+ * function.
+ */
+void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
+ __le32 *tx_flags)
+{
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
+ *tx_flags |= TX_CMD_FLG_RTS_MSK;
+ *tx_flags &= ~TX_CMD_FLG_CTS_MSK;
+ } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+ *tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+ *tx_flags |= TX_CMD_FLG_CTS_MSK;
+ }
+}
+EXPORT_SYMBOL(iwlcore_rts_tx_cmd_flag);
+
static bool is_single_rx_stream(struct iwl_priv *priv)
{
return !priv->current_ht_config.is_ht ||
- ((priv->current_ht_config.mcs.rx_mask[1] == 0) &&
- (priv->current_ht_config.mcs.rx_mask[2] == 0));
+ priv->current_ht_config.single_chain_sufficient;
}
static u8 iwl_is_channel_extension(struct iwl_priv *priv,
@@ -635,10 +651,9 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv,
u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
struct ieee80211_sta_ht_cap *sta_ht_inf)
{
- struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config;
+ struct iwl_ht_config *ht_conf = &priv->current_ht_config;
- if ((!iwl_ht_conf->is_ht) ||
- (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ))
+ if (!ht_conf->is_ht || !ht_conf->is_40mhz)
return 0;
/* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40
@@ -654,7 +669,7 @@ u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
#endif
return iwl_is_channel_extension(priv, priv->band,
le16_to_cpu(priv->staging_rxon.channel),
- iwl_ht_conf->extension_chan_offset);
+ ht_conf->extension_chan_offset);
}
EXPORT_SYMBOL(iwl_is_ht40_tx_allowed);
@@ -878,11 +893,11 @@ u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_rate_get_lowest_plcp);
-void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
+void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
{
struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
- if (!ht_info->is_ht) {
+ if (!ht_conf->is_ht) {
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
RXON_FLG_HT40_PROT_MSK |
@@ -893,7 +908,7 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
/* FIXME: if the definition of ht_protection changed, the "translation"
* will be needed for rxon->flags
*/
- rxon->flags |= cpu_to_le32(ht_info->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS);
+ rxon->flags |= cpu_to_le32(ht_conf->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS);
/* Set up channel bandwidth:
* 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */
@@ -902,10 +917,10 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
if (iwl_is_ht40_tx_allowed(priv, NULL)) {
/* pure ht40 */
- if (ht_info->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
+ if (ht_conf->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_info->extension_chan_offset) {
+ switch (ht_conf->extension_chan_offset) {
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
rxon->flags &= ~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
break;
@@ -915,7 +930,7 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
}
} else {
/* Note: control channel is opposite of extension channel */
- switch (ht_info->extension_chan_offset) {
+ switch (ht_conf->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;
@@ -938,14 +953,10 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
if (priv->cfg->ops->hcmd->set_rxon_chain)
priv->cfg->ops->hcmd->set_rxon_chain(priv);
- IWL_DEBUG_ASSOC(priv, "supported HT rate 0x%X 0x%X 0x%X "
- "rxon flags 0x%X operation mode :0x%X "
+ IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X "
"extension channel offset 0x%x\n",
- ht_info->mcs.rx_mask[0],
- ht_info->mcs.rx_mask[1],
- ht_info->mcs.rx_mask[2],
- le32_to_cpu(rxon->flags), ht_info->ht_protection,
- ht_info->extension_chan_offset);
+ le32_to_cpu(rxon->flags), ht_conf->ht_protection,
+ ht_conf->extension_chan_offset);
return;
}
EXPORT_SYMBOL(iwl_set_rxon_ht);
@@ -955,47 +966,37 @@ EXPORT_SYMBOL(iwl_set_rxon_ht);
#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.
+/*
+ * 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)
{
- bool is_single = is_single_rx_stream(priv);
- bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
-
/* # of Rx chains to use when expecting MIMO. */
- if (is_single || (!is_cam && (priv->current_ht_config.sm_ps ==
- WLAN_HT_CAP_SM_PS_STATIC)))
+ 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, there's no difference between
+ * using multiple chains or just a single chain, but due to the
+ * lack of SM PS we lose a lot of throughput if we use just a
+ * single chain.
+ *
+ * Therefore, use the active count here (which will use multiple
+ * chains unless connected to a legacy AP).
+ */
static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
{
- int idle_cnt;
- bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
- /* # Rx chains when idling and maybe trying to save power */
- switch (priv->current_ht_config.sm_ps) {
- case WLAN_HT_CAP_SM_PS_STATIC:
- case WLAN_HT_CAP_SM_PS_DYNAMIC:
- idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL :
- IWL_NUM_IDLE_CHAINS_SINGLE;
- break;
- case WLAN_HT_CAP_SM_PS_DISABLED:
- idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE;
- break;
- case WLAN_HT_CAP_SM_PS_INVALID:
- default:
- IWL_ERR(priv, "invalid mimo ps mode %d\n",
- priv->current_ht_config.sm_ps);
- WARN_ON(1);
- idle_cnt = -1;
- break;
- }
- return idle_cnt;
+ return active_cnt;
}
/* up to 4 chains */
@@ -1005,7 +1006,7 @@ static u8 iwl_count_chain_bitmap(u32 chain_bitmap)
res = (chain_bitmap & BIT(0)) >> 0;
res += (chain_bitmap & BIT(1)) >> 1;
res += (chain_bitmap & BIT(2)) >> 2;
- res += (chain_bitmap & BIT(4)) >> 4;
+ res += (chain_bitmap & BIT(3)) >> 3;
return res;
}
@@ -1281,13 +1282,18 @@ static void iwl_set_rate(struct iwl_priv *priv)
void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ 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);
- IWL_DEBUG_11H(priv, "CSA notif: channel %d, status %d\n",
- le16_to_cpu(csa->channel), le32_to_cpu(csa->status));
- rxon->channel = csa->channel;
- priv->staging_rxon.channel = csa->channel;
+
+ if (!le32_to_cpu(csa->status)) {
+ rxon->channel = csa->channel;
+ priv->staging_rxon.channel = csa->channel;
+ IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
+ le16_to_cpu(csa->channel));
+ } else
+ IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
+ le16_to_cpu(csa->channel));
}
EXPORT_SYMBOL(iwl_rx_csa);
@@ -1346,6 +1352,156 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_irq_handle_error);
+int iwl_apm_stop_master(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* set stop master bit */
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+
+ iwl_poll_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED,
+ CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ IWL_DEBUG_INFO(priv, "stop master\n");
+
+ return 0;
+}
+EXPORT_SYMBOL(iwl_apm_stop_master);
+
+void iwl_apm_stop(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n");
+
+ iwl_apm_stop_master(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+ udelay(10);
+ /* clear "init complete" move adapter D0A* --> D0U state */
+ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL(iwl_apm_stop);
+
+
+/*
+ * Start up NIC's basic functionality after it has been reset
+ * (e.g. after platform boot, or shutdown via iwl_apm_stop())
+ * NOTE: This does not load uCode nor start the embedded processor
+ */
+int iwl_apm_init(struct iwl_priv *priv)
+{
+ int ret = 0;
+ u16 lctl;
+
+ IWL_DEBUG_INFO(priv, "Init card's basic functions\n");
+
+ /*
+ * Use "set_bit" below rather than "write", to preserve any hardware
+ * bits already set by default after reset.
+ */
+
+ /* Disable L0S exit timer (platform NMI Work/Around) */
+ iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+ CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+
+ /*
+ * Disable L0s without affecting L1;
+ * don't wait for ICH L0s (ICH bug W/A)
+ */
+ iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+ CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
+
+ /* Set FH wait threshold to maximum (HW error during stress W/A) */
+ iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
+
+ /*
+ * Enable HAP INTA (interrupt from management bus) to
+ * wake device's PCI Express link L1a -> L0s
+ * NOTE: This is no-op for 3945 (non-existant bit)
+ */
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
+
+ /*
+ * HW bug W/A - costs negligible power consumption ...
+ * Check if BIOS (or OS) enabled L1-ASPM on this device
+ */
+ if (priv->cfg->set_l0s) {
+ lctl = iwl_pcie_link_ctl(priv);
+ if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
+ PCI_CFG_LINK_CTRL_VAL_L1_EN) {
+ /* L1-ASPM enabled; disable(!) L0S */
+ iwl_set_bit(priv, CSR_GIO_REG,
+ CSR_GIO_REG_VAL_L0S_ENABLED);
+ IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n");
+ } else {
+ /* L1-ASPM disabled; enable(!) L0S */
+ iwl_clear_bit(priv, CSR_GIO_REG,
+ CSR_GIO_REG_VAL_L0S_ENABLED);
+ IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n");
+ }
+ }
+
+ /* 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);
+
+ /*
+ * Set "initialization complete" bit to move adapter from
+ * D0U* --> D0A* (powered-up active) state.
+ */
+ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+ /*
+ * Wait for clock stabilization; once stabilized, access to
+ * device-internal resources is supported, e.g. iwl_write_prph()
+ * and accesses to uCode SRAM.
+ */
+ ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ if (ret < 0) {
+ IWL_DEBUG_INFO(priv, "Failed to init the card\n");
+ goto out;
+ }
+
+ /*
+ * Enable DMA and BSM (if used) clocks, wait for them to stabilize.
+ * BSM (Boostrap State Machine) is only in 3945 and 4965;
+ * later devices (i.e. 5000 and later) have non-volatile SRAM,
+ * and don't need BSM to restore data after power-saving sleep.
+ *
+ * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits
+ * do not disable clocks. This preserves any hardware bits already
+ * set by default in "CLK_CTRL_REG" after reset.
+ */
+ if (priv->cfg->use_bsm)
+ iwl_write_prph(priv, APMG_CLK_EN_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT);
+ else
+ iwl_write_prph(priv, APMG_CLK_EN_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT);
+ udelay(20);
+
+ /* Disable L1-Active */
+ iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
+ APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL(iwl_apm_init);
+
+
+
void iwl_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
@@ -1393,73 +1549,14 @@ void iwl_configure_filter(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(iwl_configure_filter);
-int iwl_setup_mac(struct iwl_priv *priv)
-{
- int ret;
- struct ieee80211_hw *hw = priv->hw;
- hw->rate_control_algorithm = "iwl-agn-rs";
-
- /* Tell mac80211 our characteristics */
- hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_NOISE_DBM |
- IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_SPECTRUM_MGMT;
-
- if (!priv->cfg->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);
-
- hw->wiphy->custom_regulatory = true;
-
- /* Firmware does not support this */
- hw->wiphy->disable_beacon_hints = true;
-
- /*
- * For now, disable PS by default because it affects
- * RX performance significantly.
- */
- hw->wiphy->ps_default = false;
-
- hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
- /* we create the 802.11 header and a zero-length SSID element */
- hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
-
- /* Default value; 4 EDCA QOS priorities */
- hw->queues = 4;
-
- hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
-
- if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
- priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
- &priv->bands[IEEE80211_BAND_2GHZ];
- if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
- priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
- &priv->bands[IEEE80211_BAND_5GHZ];
-
- ret = ieee80211_register_hw(priv->hw);
- if (ret) {
- IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
- return ret;
- }
- priv->mac80211_registered = 1;
-
- return 0;
-}
-EXPORT_SYMBOL(iwl_setup_mac);
-
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_buf_size = IWL_RX_BUF_SIZE_8K;
+ priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_8K);
else
- priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K;
- priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256;
+ priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_4K);
priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL;
@@ -1488,15 +1585,12 @@ int iwl_init_drv(struct iwl_priv *priv)
/* Clear the driver's (not device's) station table */
iwl_clear_stations_table(priv);
- priv->data_retry_limit = -1;
priv->ieee_channels = NULL;
priv->ieee_rates = NULL;
priv->band = IEEE80211_BAND_2GHZ;
priv->iw_mode = NL80211_IFTYPE_STATION;
- priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED;
-
/* Choose which receivers/antennas to use */
if (priv->cfg->ops->hcmd->set_rxon_chain)
priv->cfg->ops->hcmd->set_rxon_chain(priv);
@@ -1915,9 +2009,9 @@ EXPORT_SYMBOL(iwl_isr_legacy);
int iwl_send_bt_config(struct iwl_priv *priv)
{
struct iwl_bt_cmd bt_cmd = {
- .flags = 3,
- .lead_time = 0xAA,
- .max_kill = 1,
+ .flags = BT_COEX_MODE_4W,
+ .lead_time = BT_LEAD_TIME_DEF,
+ .max_kill = BT_MAX_KILL_DEF,
.kill_ack_mask = 0,
.kill_cts_mask = 0,
};
@@ -2077,10 +2171,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv)
spin_unlock_irqrestore(&priv->lock, flags);
priv->thermal_throttle.ct_kill_toggle = false;
- switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
- case CSR_HW_REV_TYPE_1000:
- case CSR_HW_REV_TYPE_6x00:
- case CSR_HW_REV_TYPE_6x50:
+ 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 =
@@ -2097,8 +2188,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv)
"exit is %d\n",
priv->hw_params.ct_kill_threshold,
priv->hw_params.ct_kill_exit_threshold);
- break;
- default:
+ } else {
cmd.critical_temperature_R =
cpu_to_le32(priv->hw_params.ct_kill_threshold);
@@ -2111,7 +2201,6 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv)
"succeeded, "
"critical temperature is %d\n",
priv->hw_params.ct_kill_threshold);
- break;
}
}
EXPORT_SYMBOL(iwl_rf_kill_ct_config);
@@ -2143,7 +2232,7 @@ void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n",
sleep->pm_sleep_mode, sleep->pm_wakeup_src);
@@ -2154,7 +2243,7 @@ EXPORT_SYMBOL(iwl_rx_pm_sleep_notif);
void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
"notification for %s:\n", len,
@@ -2166,7 +2255,7 @@ EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif);
void iwl_rx_reply_error(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) "
"seq 0x%04X ser 0x%08X\n",
@@ -2228,42 +2317,58 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
EXPORT_SYMBOL(iwl_mac_conf_tx);
static void iwl_ht_conf(struct iwl_priv *priv,
- struct ieee80211_bss_conf *bss_conf)
+ struct ieee80211_bss_conf *bss_conf)
{
- struct ieee80211_sta_ht_cap *ht_conf;
- struct iwl_ht_info *iwl_conf = &priv->current_ht_config;
+ struct iwl_ht_config *ht_conf = &priv->current_ht_config;
struct ieee80211_sta *sta;
IWL_DEBUG_MAC80211(priv, "enter: \n");
- if (!iwl_conf->is_ht)
+ if (!ht_conf->is_ht)
return;
+ ht_conf->ht_protection =
+ bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
+ ht_conf->non_GF_STA_present =
+ !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
- /*
- * It is totally wrong to base global information on something
- * that is valid only when associated, alas, this driver works
- * that way and I don't know how to fix it.
- */
+ ht_conf->single_chain_sufficient = false;
- rcu_read_lock();
- sta = ieee80211_find_sta(priv->hw, priv->bssid);
- if (!sta) {
+ switch (priv->iw_mode) {
+ case NL80211_IFTYPE_STATION:
+ rcu_read_lock();
+ sta = ieee80211_find_sta(priv->hw, priv->bssid);
+ if (sta) {
+ struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+ int maxstreams;
+
+ maxstreams = (ht_cap->mcs.tx_params &
+ IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
+ >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
+ maxstreams += 1;
+
+ if ((ht_cap->mcs.rx_mask[1] == 0) &&
+ (ht_cap->mcs.rx_mask[2] == 0))
+ ht_conf->single_chain_sufficient = true;
+ if (maxstreams <= 1)
+ ht_conf->single_chain_sufficient = true;
+ } else {
+ /*
+ * If at all, this can only happen through a race
+ * when the AP disconnects us while we're still
+ * setting up the connection, in that case mac80211
+ * will soon tell us about that.
+ */
+ ht_conf->single_chain_sufficient = true;
+ }
rcu_read_unlock();
- return;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ ht_conf->single_chain_sufficient = true;
+ break;
+ default:
+ break;
}
- ht_conf = &sta->ht_cap;
-
- iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2);
-
- memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16);
-
- iwl_conf->ht_protection =
- bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
- iwl_conf->non_GF_STA_present =
- !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
-
- rcu_read_unlock();
IWL_DEBUG_MAC80211(priv, "leave\n");
}
@@ -2387,6 +2492,8 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
priv->timestamp = bss_conf->timestamp;
priv->assoc_capability = bss_conf->assoc_capability;
+ iwl_led_associate(priv);
+
/*
* We have just associated, don't start scan too early
* leave time for EAPOL exchange to complete.
@@ -2397,9 +2504,10 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
if (!iwl_is_rfkill(priv))
priv->cfg->ops->lib->post_associate(priv);
- } else
+ } else {
priv->assoc_id = 0;
-
+ iwl_led_disassociate(priv);
+ }
}
if (changes && iwl_is_associated(priv) && priv->assoc_id) {
@@ -2570,7 +2678,7 @@ 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 iwl_ht_info *ht_conf = &priv->current_ht_config;
+ struct iwl_ht_config *ht_conf = &priv->current_ht_config;
unsigned long flags = 0;
int ret = 0;
u16 ch;
@@ -2612,6 +2720,14 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
goto set_ch_out;
}
+ if (iwl_is_associated(priv) &&
+ (le16_to_cpu(priv->active_rxon.channel) != ch) &&
+ priv->cfg->ops->lib->set_channel_switch) {
+ ret = priv->cfg->ops->lib->set_channel_switch(priv,
+ ch);
+ goto out;
+ }
+
spin_lock_irqsave(&priv->lock, flags);
/* Configure HT40 channels */
@@ -2620,21 +2736,18 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
if (conf_is_ht40_minus(conf)) {
ht_conf->extension_chan_offset =
IEEE80211_HT_PARAM_CHA_SEC_BELOW;
- ht_conf->supported_chan_width =
- IWL_CHANNEL_WIDTH_40MHZ;
+ 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->supported_chan_width =
- IWL_CHANNEL_WIDTH_40MHZ;
+ ht_conf->is_40mhz = true;
} else {
ht_conf->extension_chan_offset =
IEEE80211_HT_PARAM_CHA_SEC_NONE;
- ht_conf->supported_chan_width =
- IWL_CHANNEL_WIDTH_20MHZ;
+ ht_conf->is_40mhz = false;
}
} else
- ht_conf->supported_chan_width = IWL_CHANNEL_WIDTH_20MHZ;
+ 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;
@@ -2656,7 +2769,8 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
iwl_set_rate(priv);
}
- if (changed & IEEE80211_CONF_CHANGE_PS) {
+ if (changed & (IEEE80211_CONF_CHANGE_PS |
+ IEEE80211_CONF_CHANGE_IDLE)) {
ret = iwl_power_update_mode(priv, false);
if (ret)
IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n");
@@ -2740,7 +2854,7 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
IWL_DEBUG_MAC80211(priv, "enter\n");
spin_lock_irqsave(&priv->lock, flags);
- memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info));
+ memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_config));
spin_unlock_irqrestore(&priv->lock, flags);
iwl_reset_qos(priv);
@@ -2792,6 +2906,27 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL(iwl_mac_reset_tsf);
+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,
+ GFP_KERNEL);
+ if (!priv->txq) {
+ IWL_ERR(priv, "Not enough memory for txq \n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(iwl_alloc_txq_mem);
+
+void iwl_free_txq_mem(struct iwl_priv *priv)
+{
+ kfree(priv->txq);
+ priv->txq = NULL;
+}
+EXPORT_SYMBOL(iwl_free_txq_mem);
+
#ifdef CONFIG_IWLWIFI_DEBUGFS
#define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES)
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index e50103a956b1..b875dcfca2d6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -89,6 +89,7 @@ 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 (*set_tx_ant)(struct iwl_priv *priv, u8 valid_tx_ant);
};
struct iwl_hcmd_utils_ops {
@@ -97,7 +98,8 @@ struct iwl_hcmd_utils_ops {
void (*gain_computation)(struct iwl_priv *priv,
u32 *average_noise,
u16 min_average_noise_antennat_i,
- u32 min_average_noise);
+ u32 min_average_noise,
+ u8 default_chain);
void (*chain_noise_reset)(struct iwl_priv *priv);
void (*rts_tx_cmd_flag)(struct ieee80211_tx_info *info,
__le32 *tx_flags);
@@ -107,7 +109,6 @@ struct iwl_hcmd_utils_ops {
struct iwl_apm_ops {
int (*init)(struct iwl_priv *priv);
- int (*reset)(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);
@@ -168,6 +169,7 @@ struct iwl_lib_ops {
int (*load_ucode)(struct iwl_priv *priv);
void (*dump_nic_event_log)(struct iwl_priv *priv);
void (*dump_nic_error_log)(struct iwl_priv *priv);
+ int (*set_channel_switch)(struct iwl_priv *priv, u16 channel);
/* power management */
struct iwl_apm_ops apm_ops;
@@ -185,18 +187,24 @@ struct iwl_lib_ops {
struct iwl_temp_ops temp_ops;
};
+struct iwl_led_ops {
+ int (*cmd)(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd);
+ int (*on)(struct iwl_priv *priv);
+ int (*off)(struct iwl_priv *priv);
+};
+
struct iwl_ops {
const struct iwl_ucode_ops *ucode;
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;
};
struct iwl_mod_params {
int sw_crypto; /* def: 0 = using hardware encryption */
int disable_hw_scan; /* def: 0 = use h/w scan */
int num_of_queues; /* def: HW dependent */
- int num_of_ampdu_queues;/* def: HW dependent */
int disable_11n; /* def: 0 = 11n capabilities enabled */
int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */
int antenna; /* def: 0 = both antennas (use diversity) */
@@ -213,6 +221,13 @@ struct iwl_mod_params {
* @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_ht: 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
*
* We enable the driver to be backward compatible wrt API version. The
* driver specifies which APIs it supports (with @ucode_api_max being the
@@ -244,17 +259,30 @@ struct iwl_cfg {
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;
const struct iwl_mod_params *mod_params;
u8 valid_tx_ant;
u8 valid_rx_ant;
- bool need_pll_cfg;
+
+ /* 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_ht;
+ int chain_noise_num_beacons;
+ const bool supports_idle;
+ bool adv_thermal_throttle;
+ bool support_ct_kill_exit;
};
/***************************
@@ -273,7 +301,7 @@ 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);
-void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info);
+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);
void iwl_set_flags_for_band(struct iwl_priv *priv, enum ieee80211_band band);
@@ -287,7 +315,6 @@ void iwl_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags, u64 multicast);
int iwl_hw_nic_init(struct iwl_priv *priv);
-int iwl_setup_mac(struct iwl_priv *priv);
int iwl_set_hw_params(struct iwl_priv *priv);
int iwl_init_drv(struct iwl_priv *priv);
void iwl_uninit_drv(struct iwl_priv *priv);
@@ -309,6 +336,10 @@ void iwl_config_ap(struct iwl_priv *priv);
int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
struct ieee80211_tx_queue_stats *stats);
void iwl_mac_reset_tsf(struct ieee80211_hw *hw);
+int iwl_alloc_txq_mem(struct iwl_priv *priv);
+void iwl_free_txq_mem(struct iwl_priv *priv);
+void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
+ __le32 *tx_flags);
#ifdef CONFIG_IWLWIFI_DEBUGFS
int iwl_alloc_traffic_mem(struct iwl_priv *priv);
void iwl_free_traffic_mem(struct iwl_priv *priv);
@@ -509,7 +540,7 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
const void *data,
void (*callback)(struct iwl_priv *priv,
struct iwl_device_cmd *cmd,
- struct sk_buff *skb));
+ struct iwl_rx_packet *pkt));
int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
@@ -569,6 +600,7 @@ void iwlcore_free_geos(struct iwl_priv *priv);
#define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */
#define STATUS_INT_ENABLED 2
#define STATUS_RF_KILL_HW 3
+#define STATUS_CT_KILL 4
#define STATUS_INIT 5
#define STATUS_ALIVE 6
#define STATUS_READY 7
@@ -613,6 +645,11 @@ static inline int iwl_is_rfkill(struct iwl_priv *priv)
return iwl_is_rfkill_hw(priv);
}
+static inline int iwl_is_ctkill(struct iwl_priv *priv)
+{
+ return test_bit(STATUS_CT_KILL, &priv->status);
+}
+
static inline int iwl_is_ready_rf(struct iwl_priv *priv)
{
@@ -634,6 +671,9 @@ extern void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
+void iwl_apm_stop(struct iwl_priv *priv);
+int iwl_apm_stop_master(struct iwl_priv *priv);
+int iwl_apm_init(struct iwl_priv *priv);
void iwl_setup_rxon_timing(struct iwl_priv *priv);
static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
@@ -653,5 +693,4 @@ static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
{
return priv->hw->wiphy->bands[band];
}
-
#endif /* __iwl_core_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 06437d13e73e..b6ed5a3147a1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -109,8 +109,9 @@
* Bit fields:
* 3-2: 0 = A, 1 = B, 2 = C, 3 = D step
*/
-#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C)
-#define CSR_DBG_HPET_MEM_REG (CSR_BASE+0x240)
+#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C)
+#define CSR_DBG_HPET_MEM_REG (CSR_BASE+0x240)
+#define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250)
/* Bits for CSR_HW_IF_CONFIG_REG */
#define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010)
@@ -195,6 +196,7 @@
#define CSR_RESET_REG_FLAG_SW_RESET (0x00000080)
#define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100)
#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200)
+#define CSR_RESET_LINK_PWR_MGMT_DISABLED (0x80000000)
/* GP (general purpose) CONTROL */
#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001)
@@ -230,12 +232,22 @@
/* EEPROM GP */
#define CSR_EEPROM_GP_VALID_MSK (0x00000007)
-#define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000)
#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180)
#define CSR_OTP_GP_REG_DEVICE_SELECT (0x00010000) /* 0 - EEPROM, 1 - OTP */
#define CSR_OTP_GP_REG_OTP_ACCESS_MODE (0x00020000) /* 0 - absolute, 1 - relative */
#define CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK (0x00100000) /* bit 20 */
#define CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK (0x00200000) /* bit 21 */
+#define CSR_GP_REG_POWER_SAVE_STATUS_MSK (0x03000000) /* bit 24/25 */
+#define CSR_GP_REG_NO_POWER_SAVE (0x00000000)
+#define CSR_GP_REG_MAC_POWER_SAVE (0x01000000)
+#define CSR_GP_REG_PHY_POWER_SAVE (0x02000000)
+#define CSR_GP_REG_POWER_SAVE_ERROR (0x03000000)
+
+/* EEPROM signature */
+#define CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP (0x00000000)
+#define CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP (0x00000001)
+#define CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K (0x00000002)
+#define CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K (0x00000004)
/* CSR GIO */
#define CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index cbc62904655d..96c92eab692a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -84,9 +84,7 @@ struct iwl_debugfs {
struct dentry *file_interrupt;
struct dentry *file_qos;
struct dentry *file_thermal_throttling;
-#ifdef CONFIG_IWLWIFI_LEDS
struct dentry *file_led;
-#endif
struct dentry *file_disable_ht40;
struct dentry *file_sleep_level_override;
struct dentry *file_current_sleep_command;
@@ -108,6 +106,7 @@ struct iwl_debugfs {
struct dentry *file_sensitivity;
struct dentry *file_chain_noise;
struct dentry *file_tx_power;
+ struct dentry *file_power_save_status;
} dbgfs_debug_files;
u32 sram_offset;
u32 sram_len;
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index a198bcf61022..8784911fd56e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -383,6 +383,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
int pos = 0, ofs = 0, buf_size = 0;
const u8 *ptr;
char *buf;
+ u16 eeprom_ver;
size_t eeprom_len = priv->cfg->eeprom_size;
buf_size = 4 * eeprom_len + 256;
@@ -403,9 +404,11 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
IWL_ERR(priv, "Can not allocate Buffer\n");
return -ENOMEM;
}
- pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s\n",
+ eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
+ pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s, "
+ "version: 0x%x\n",
(priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
- ? "OTP" : "EEPROM");
+ ? "OTP" : "EEPROM", eeprom_ver);
for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) {
pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs);
hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos,
@@ -532,6 +535,8 @@ static ssize_t iwl_dbgfs_status_read(struct file *file,
test_bit(STATUS_INT_ENABLED, &priv->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n",
test_bit(STATUS_RF_KILL_HW, &priv->status));
+ pos += scnprintf(buf + pos, bufsz - pos, "STATUS_CT_KILL:\t\t %d\n",
+ test_bit(STATUS_CT_KILL, &priv->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n",
test_bit(STATUS_INIT, &priv->status));
pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n",
@@ -672,7 +677,6 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
return ret;
}
-#ifdef CONFIG_IWLWIFI_LEDS
static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -697,7 +701,6 @@ static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
return ret;
}
-#endif
static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
char __user *user_buf,
@@ -798,15 +801,20 @@ static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file,
* valid here. However, let's not confuse them and present
* IWL_POWER_INDEX_1 as "1", not "0".
*/
- if (value > 0)
+ if (value == 0)
+ return -EINVAL;
+ else if (value > 0)
value -= 1;
if (value != -1 && (value < 0 || value >= IWL_POWER_NUM))
return -EINVAL;
+ if (!iwl_is_ready_rf(priv))
+ return -EAGAIN;
+
priv->power_data.debug_sleep_level_override = value;
- iwl_power_update_mode(priv, false);
+ iwl_power_update_mode(priv, true);
return count;
}
@@ -861,9 +869,7 @@ DEBUGFS_READ_FILE_OPS(channels);
DEBUGFS_READ_FILE_OPS(status);
DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
DEBUGFS_READ_FILE_OPS(qos);
-#ifdef CONFIG_IWLWIFI_LEDS
DEBUGFS_READ_FILE_OPS(led);
-#endif
DEBUGFS_READ_FILE_OPS(thermal_throttling);
DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override);
@@ -881,10 +887,14 @@ 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) +
- (IWL_MAX_NUM_QUEUES * 32 * 8) + 400;
+ (priv->cfg->num_of_queues * 32 * 8) + 400;
const u8 *ptr;
ssize_t ret;
+ if (!priv->txq) {
+ IWL_ERR(priv, "txq not ready\n");
+ return -EAGAIN;
+ }
buf = kzalloc(bufsz, GFP_KERNEL);
if (!buf) {
IWL_ERR(priv, "Can not allocate buffer\n");
@@ -976,8 +986,12 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
int pos = 0;
int cnt;
int ret;
- const size_t bufsz = sizeof(char) * 60 * IWL_MAX_NUM_QUEUES;
+ const size_t bufsz = sizeof(char) * 60 * priv->cfg->num_of_queues;
+ if (!priv->txq) {
+ IWL_ERR(priv, "txq not ready\n");
+ return -EAGAIN;
+ }
buf = kzalloc(bufsz, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -1068,10 +1082,10 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
sizeof(struct statistics_rx_non_phy) * 20 +
sizeof(struct statistics_rx_ht_phy) * 20 + 400;
ssize_t ret;
- struct statistics_rx_phy *ofdm;
- struct statistics_rx_phy *cck;
- struct statistics_rx_non_phy *general;
- struct statistics_rx_ht_phy *ht;
+ struct statistics_rx_phy *ofdm, *accum_ofdm;
+ struct statistics_rx_phy *cck, *accum_cck;
+ struct statistics_rx_non_phy *general, *accum_general;
+ struct statistics_rx_ht_phy *ht, *accum_ht;
if (!iwl_is_alive(priv))
return -EAGAIN;
@@ -1100,155 +1114,268 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
cck = &priv->statistics.rx.cck;
general = &priv->statistics.rx.general;
ht = &priv->statistics.rx.ofdm_ht;
+ accum_ofdm = &priv->accum_statistics.rx.ofdm;
+ accum_cck = &priv->accum_statistics.rx.cck;
+ accum_general = &priv->accum_statistics.rx.general;
+ accum_ht = &priv->accum_statistics.rx.ofdm_ht;
pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM:\n");
- pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt: %u\n",
- le32_to_cpu(ofdm->ina_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt: %u\n",
- le32_to_cpu(ofdm->fina_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n",
- le32_to_cpu(ofdm->plcp_err));
- pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n",
- le32_to_cpu(ofdm->crc32_err));
- pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n",
- le32_to_cpu(ofdm->overrun_err));
- pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n",
- le32_to_cpu(ofdm->early_overrun_err));
- pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n",
- le32_to_cpu(ofdm->crc32_good));
- pos += scnprintf(buf + pos, bufsz - pos, "false_alarm_cnt: %u\n",
- le32_to_cpu(ofdm->false_alarm_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "fina_sync_err_cnt: %u\n",
- le32_to_cpu(ofdm->fina_sync_err_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "sfd_timeout: %u\n",
- le32_to_cpu(ofdm->sfd_timeout));
- pos += scnprintf(buf + pos, bufsz - pos, "fina_timeout: %u\n",
- le32_to_cpu(ofdm->fina_timeout));
- pos += scnprintf(buf + pos, bufsz - pos, "unresponded_rts: %u\n",
- le32_to_cpu(ofdm->unresponded_rts));
- pos += scnprintf(buf + pos, bufsz - pos,
- "rxe_frame_limit_overrun: %u\n",
- le32_to_cpu(ofdm->rxe_frame_limit_overrun));
- pos += scnprintf(buf + pos, bufsz - pos, "sent_ack_cnt: %u\n",
- le32_to_cpu(ofdm->sent_ack_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "sent_cts_cnt: %u\n",
- le32_to_cpu(ofdm->sent_cts_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "sent_ba_rsp_cnt: %u\n",
- le32_to_cpu(ofdm->sent_ba_rsp_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "dsp_self_kill: %u\n",
- le32_to_cpu(ofdm->dsp_self_kill));
- pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n",
- le32_to_cpu(ofdm->mh_format_err));
- pos += scnprintf(buf + pos, bufsz - pos, "re_acq_main_rssi_sum: %u\n",
- le32_to_cpu(ofdm->re_acq_main_rssi_sum));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\t\t\tcurrent\t\t\taccumulative\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->ina_cnt), accum_ofdm->ina_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err);
+ pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "overrun_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->overrun_err),
+ accum_ofdm->overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "early_overrun_err:\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->early_overrun_err),
+ accum_ofdm->early_overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->crc32_good),
+ accum_ofdm->crc32_good);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "false_alarm_cnt:\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->false_alarm_cnt),
+ accum_ofdm->false_alarm_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "fina_sync_err_cnt:\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->fina_sync_err_cnt),
+ accum_ofdm->fina_sync_err_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "sfd_timeout:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->sfd_timeout),
+ accum_ofdm->sfd_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "fina_timeout:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->fina_timeout),
+ accum_ofdm->fina_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "unresponded_rts:\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->unresponded_rts),
+ accum_ofdm->unresponded_rts);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "rxe_frame_lmt_ovrun:\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->rxe_frame_limit_overrun),
+ accum_ofdm->rxe_frame_limit_overrun);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "sent_ack_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->sent_ack_cnt),
+ accum_ofdm->sent_ack_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "sent_cts_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->sent_cts_cnt),
+ accum_ofdm->sent_cts_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "sent_ba_rsp_cnt:\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->sent_ba_rsp_cnt),
+ accum_ofdm->sent_ba_rsp_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "dsp_self_kill:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->dsp_self_kill),
+ accum_ofdm->dsp_self_kill);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "mh_format_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->mh_format_err),
+ accum_ofdm->mh_format_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "re_acq_main_rssi_sum:\t%u\t\t\t%u\n",
+ le32_to_cpu(ofdm->re_acq_main_rssi_sum),
+ accum_ofdm->re_acq_main_rssi_sum);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - CCK:\n");
- pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt: %u\n",
- le32_to_cpu(cck->ina_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt: %u\n",
- le32_to_cpu(cck->fina_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n",
- le32_to_cpu(cck->plcp_err));
- pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n",
- le32_to_cpu(cck->crc32_err));
- pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n",
- le32_to_cpu(cck->overrun_err));
- pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n",
- le32_to_cpu(cck->early_overrun_err));
- pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n",
- le32_to_cpu(cck->crc32_good));
- pos += scnprintf(buf + pos, bufsz - pos, "false_alarm_cnt: %u\n",
- le32_to_cpu(cck->false_alarm_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "fina_sync_err_cnt: %u\n",
- le32_to_cpu(cck->fina_sync_err_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "sfd_timeout: %u\n",
- le32_to_cpu(cck->sfd_timeout));
- pos += scnprintf(buf + pos, bufsz - pos, "fina_timeout: %u\n",
- le32_to_cpu(cck->fina_timeout));
- pos += scnprintf(buf + pos, bufsz - pos, "unresponded_rts: %u\n",
- le32_to_cpu(cck->unresponded_rts));
- pos += scnprintf(buf + pos, bufsz - pos,
- "rxe_frame_limit_overrun: %u\n",
- le32_to_cpu(cck->rxe_frame_limit_overrun));
- pos += scnprintf(buf + pos, bufsz - pos, "sent_ack_cnt: %u\n",
- le32_to_cpu(cck->sent_ack_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "sent_cts_cnt: %u\n",
- le32_to_cpu(cck->sent_cts_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "sent_ba_rsp_cnt: %u\n",
- le32_to_cpu(cck->sent_ba_rsp_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "dsp_self_kill: %u\n",
- le32_to_cpu(cck->dsp_self_kill));
- pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n",
- le32_to_cpu(cck->mh_format_err));
- pos += scnprintf(buf + pos, bufsz - pos, "re_acq_main_rssi_sum: %u\n",
- le32_to_cpu(cck->re_acq_main_rssi_sum));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\t\t\tcurrent\t\t\taccumulative\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->plcp_err), accum_cck->plcp_err);
+ pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->crc32_err), accum_cck->crc32_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "overrun_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->overrun_err),
+ accum_cck->overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "early_overrun_err:\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->early_overrun_err),
+ accum_cck->early_overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->crc32_good), accum_cck->crc32_good);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "false_alarm_cnt:\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->false_alarm_cnt),
+ accum_cck->false_alarm_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "fina_sync_err_cnt:\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->fina_sync_err_cnt),
+ accum_cck->fina_sync_err_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "sfd_timeout:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->sfd_timeout),
+ accum_cck->sfd_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "fina_timeout:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->fina_timeout),
+ accum_cck->fina_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "unresponded_rts:\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->unresponded_rts),
+ accum_cck->unresponded_rts);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "rxe_frame_lmt_ovrun:\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->rxe_frame_limit_overrun),
+ accum_cck->rxe_frame_limit_overrun);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "sent_ack_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->sent_ack_cnt),
+ accum_cck->sent_ack_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "sent_cts_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->sent_cts_cnt),
+ accum_cck->sent_cts_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "sent_ba_rsp_cnt:\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->sent_ba_rsp_cnt),
+ accum_cck->sent_ba_rsp_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "dsp_self_kill:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->dsp_self_kill),
+ accum_cck->dsp_self_kill);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "mh_format_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->mh_format_err),
+ accum_cck->mh_format_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "re_acq_main_rssi_sum:\t%u\t\t\t%u\n",
+ le32_to_cpu(cck->re_acq_main_rssi_sum),
+ accum_cck->re_acq_main_rssi_sum);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - GENERAL:\n");
- pos += scnprintf(buf + pos, bufsz - pos, "bogus_cts: %u\n",
- le32_to_cpu(general->bogus_cts));
- pos += scnprintf(buf + pos, bufsz - pos, "bogus_ack: %u\n",
- le32_to_cpu(general->bogus_ack));
- pos += scnprintf(buf + pos, bufsz - pos, "non_bssid_frames: %u\n",
- le32_to_cpu(general->non_bssid_frames));
- pos += scnprintf(buf + pos, bufsz - pos, "filtered_frames: %u\n",
- le32_to_cpu(general->filtered_frames));
- pos += scnprintf(buf + pos, bufsz - pos, "non_channel_beacons: %u\n",
- le32_to_cpu(general->non_channel_beacons));
- pos += scnprintf(buf + pos, bufsz - pos, "channel_beacons: %u\n",
- le32_to_cpu(general->channel_beacons));
- pos += scnprintf(buf + pos, bufsz - pos, "num_missed_bcon: %u\n",
- le32_to_cpu(general->num_missed_bcon));
- pos += scnprintf(buf + pos, bufsz - pos,
- "adc_rx_saturation_time: %u\n",
- le32_to_cpu(general->adc_rx_saturation_time));
- pos += scnprintf(buf + pos, bufsz - pos,
- "ina_detection_search_time: %u\n",
- le32_to_cpu(general->ina_detection_search_time));
- pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_a: %u\n",
- le32_to_cpu(general->beacon_silence_rssi_a));
- pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_b: %u\n",
- le32_to_cpu(general->beacon_silence_rssi_b));
- pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_c: %u\n",
- le32_to_cpu(general->beacon_silence_rssi_c));
- pos += scnprintf(buf + pos, bufsz - pos,
- "interference_data_flag: %u\n",
- le32_to_cpu(general->interference_data_flag));
- pos += scnprintf(buf + pos, bufsz - pos, "channel_load: %u\n",
- le32_to_cpu(general->channel_load));
- pos += scnprintf(buf + pos, bufsz - pos, "dsp_false_alarms: %u\n",
- le32_to_cpu(general->dsp_false_alarms));
- pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_a: %u\n",
- le32_to_cpu(general->beacon_rssi_a));
- pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_b: %u\n",
- le32_to_cpu(general->beacon_rssi_b));
- pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_c: %u\n",
- le32_to_cpu(general->beacon_rssi_c));
- pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_a: %u\n",
- le32_to_cpu(general->beacon_energy_a));
- pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_b: %u\n",
- le32_to_cpu(general->beacon_energy_b));
- pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_c: %u\n",
- le32_to_cpu(general->beacon_energy_c));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\t\t\tcurrent\t\t\taccumulative\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "bogus_cts:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->bogus_cts),
+ accum_general->bogus_cts);
+ pos += scnprintf(buf + pos, bufsz - pos, "bogus_ack:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->bogus_ack),
+ accum_general->bogus_ack);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "non_bssid_frames:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->non_bssid_frames),
+ accum_general->non_bssid_frames);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "filtered_frames:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->filtered_frames),
+ accum_general->filtered_frames);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "non_channel_beacons:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->non_channel_beacons),
+ accum_general->non_channel_beacons);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "channel_beacons:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->channel_beacons),
+ accum_general->channel_beacons);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "num_missed_bcon:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->num_missed_bcon),
+ accum_general->num_missed_bcon);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "adc_rx_saturation_time:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->adc_rx_saturation_time),
+ accum_general->adc_rx_saturation_time);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "ina_detect_search_tm:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->ina_detection_search_time),
+ accum_general->ina_detection_search_time);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "beacon_silence_rssi_a:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->beacon_silence_rssi_a),
+ accum_general->beacon_silence_rssi_a);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "beacon_silence_rssi_b:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->beacon_silence_rssi_b),
+ accum_general->beacon_silence_rssi_b);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "beacon_silence_rssi_c:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->beacon_silence_rssi_c),
+ accum_general->beacon_silence_rssi_c);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "interference_data_flag:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->interference_data_flag),
+ accum_general->interference_data_flag);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "channel_load:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->channel_load),
+ accum_general->channel_load);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "dsp_false_alarms:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->dsp_false_alarms),
+ accum_general->dsp_false_alarms);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "beacon_rssi_a:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->beacon_rssi_a),
+ accum_general->beacon_rssi_a);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "beacon_rssi_b:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->beacon_rssi_b),
+ accum_general->beacon_rssi_b);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "beacon_rssi_c:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->beacon_rssi_c),
+ accum_general->beacon_rssi_c);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "beacon_energy_a:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->beacon_energy_a),
+ accum_general->beacon_energy_a);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "beacon_energy_b:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->beacon_energy_b),
+ accum_general->beacon_energy_b);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "beacon_energy_c:\t%u\t\t\t%u\n",
+ le32_to_cpu(general->beacon_energy_c),
+ accum_general->beacon_energy_c);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM_HT:\n");
- pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n",
- le32_to_cpu(ht->plcp_err));
- pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n",
- le32_to_cpu(ht->overrun_err));
- pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n",
- le32_to_cpu(ht->early_overrun_err));
- pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n",
- le32_to_cpu(ht->crc32_good));
- pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n",
- le32_to_cpu(ht->crc32_err));
- pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n",
- le32_to_cpu(ht->mh_format_err));
- pos += scnprintf(buf + pos, bufsz - pos, "agg_crc32_good: %u\n",
- le32_to_cpu(ht->agg_crc32_good));
- pos += scnprintf(buf + pos, bufsz - pos, "agg_mpdu_cnt: %u\n",
- le32_to_cpu(ht->agg_mpdu_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt: %u\n",
- le32_to_cpu(ht->agg_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\t\t\tcurrent\t\t\taccumulative\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ht->plcp_err), accum_ht->plcp_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "overrun_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ht->overrun_err), accum_ht->overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "early_overrun_err:\t%u\t\t\t%u\n",
+ le32_to_cpu(ht->early_overrun_err),
+ accum_ht->early_overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ht->crc32_good), accum_ht->crc32_good);
+ pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ht->crc32_err), accum_ht->crc32_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "mh_format_err:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ht->mh_format_err),
+ accum_ht->mh_format_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg_crc32_good:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ht->agg_crc32_good),
+ accum_ht->agg_crc32_good);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg_mpdu_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ht->agg_mpdu_cnt),
+ accum_ht->agg_mpdu_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf);
@@ -1264,7 +1391,7 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
char *buf;
int bufsz = (sizeof(struct statistics_tx) * 24) + 250;
ssize_t ret;
- struct statistics_tx *tx;
+ struct statistics_tx *tx, *accum_tx;
if (!iwl_is_alive(priv))
return -EAGAIN;
@@ -1290,62 +1417,107 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
* might not reflect the current uCode activity
*/
tx = &priv->statistics.tx;
+ accum_tx = &priv->accum_statistics.tx;
pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Tx:\n");
- pos += scnprintf(buf + pos, bufsz - pos, "preamble: %u\n",
- le32_to_cpu(tx->preamble_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "rx_detected_cnt: %u\n",
- le32_to_cpu(tx->rx_detected_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "bt_prio_defer_cnt: %u\n",
- le32_to_cpu(tx->bt_prio_defer_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "bt_prio_kill_cnt: %u\n",
- le32_to_cpu(tx->bt_prio_kill_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "few_bytes_cnt: %u\n",
- le32_to_cpu(tx->few_bytes_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "cts_timeout: %u\n",
- le32_to_cpu(tx->cts_timeout));
- pos += scnprintf(buf + pos, bufsz - pos, "ack_timeout: %u\n",
- le32_to_cpu(tx->ack_timeout));
- pos += scnprintf(buf + pos, bufsz - pos, "expected_ack_cnt: %u\n",
- le32_to_cpu(tx->expected_ack_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "actual_ack_cnt: %u\n",
- le32_to_cpu(tx->actual_ack_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "dump_msdu_cnt: %u\n",
- le32_to_cpu(tx->dump_msdu_cnt));
- pos += scnprintf(buf + pos, bufsz - pos,
- "burst_abort_next_frame_mismatch_cnt: %u\n",
- le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt));
- pos += scnprintf(buf + pos, bufsz - pos,
- "burst_abort_missing_next_frame_cnt: %u\n",
- le32_to_cpu(tx->burst_abort_missing_next_frame_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "cts_timeout_collision: %u\n",
- le32_to_cpu(tx->cts_timeout_collision));
- pos += scnprintf(buf + pos, bufsz - pos,
- "ack_or_ba_timeout_collision: %u\n",
- le32_to_cpu(tx->ack_or_ba_timeout_collision));
- pos += scnprintf(buf + pos, bufsz - pos, "agg ba_timeout: %u\n",
- le32_to_cpu(tx->agg.ba_timeout));
- pos += scnprintf(buf + pos, bufsz - pos,
- "agg ba_reschedule_frames: %u\n",
- le32_to_cpu(tx->agg.ba_reschedule_frames));
- pos += scnprintf(buf + pos, bufsz - pos,
- "agg scd_query_agg_frame_cnt: %u\n",
- le32_to_cpu(tx->agg.scd_query_agg_frame_cnt));
- pos += scnprintf(buf + pos, bufsz - pos, "agg scd_query_no_agg: %u\n",
- le32_to_cpu(tx->agg.scd_query_no_agg));
- pos += scnprintf(buf + pos, bufsz - pos, "agg scd_query_agg: %u\n",
- le32_to_cpu(tx->agg.scd_query_agg));
- pos += scnprintf(buf + pos, bufsz - pos,
- "agg scd_query_mismatch: %u\n",
- le32_to_cpu(tx->agg.scd_query_mismatch));
- pos += scnprintf(buf + pos, bufsz - pos, "agg frame_not_ready: %u\n",
- le32_to_cpu(tx->agg.frame_not_ready));
- pos += scnprintf(buf + pos, bufsz - pos, "agg underrun: %u\n",
- le32_to_cpu(tx->agg.underrun));
- pos += scnprintf(buf + pos, bufsz - pos, "agg bt_prio_kill: %u\n",
- le32_to_cpu(tx->agg.bt_prio_kill));
- pos += scnprintf(buf + pos, bufsz - pos, "agg rx_ba_rsp_cnt: %u\n",
- le32_to_cpu(tx->agg.rx_ba_rsp_cnt));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\t\t\tcurrent\t\t\taccumulative\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "preamble:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->preamble_cnt),
+ accum_tx->preamble_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "rx_detected_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->rx_detected_cnt),
+ accum_tx->rx_detected_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "bt_prio_defer_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->bt_prio_defer_cnt),
+ accum_tx->bt_prio_defer_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "bt_prio_kill_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->bt_prio_kill_cnt),
+ accum_tx->bt_prio_kill_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "few_bytes_cnt:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->few_bytes_cnt),
+ accum_tx->few_bytes_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "cts_timeout:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "ack_timeout:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->ack_timeout),
+ accum_tx->ack_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "expected_ack_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->expected_ack_cnt),
+ accum_tx->expected_ack_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "actual_ack_cnt:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->actual_ack_cnt),
+ accum_tx->actual_ack_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "dump_msdu_cnt:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->dump_msdu_cnt),
+ accum_tx->dump_msdu_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "abort_nxt_frame_mismatch:"
+ "\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt),
+ accum_tx->burst_abort_next_frame_mismatch_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "abort_missing_nxt_frame:"
+ "\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->burst_abort_missing_next_frame_cnt),
+ accum_tx->burst_abort_missing_next_frame_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "cts_timeout_collision:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->cts_timeout_collision),
+ accum_tx->cts_timeout_collision);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "ack_ba_timeout_collision:\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->ack_or_ba_timeout_collision),
+ accum_tx->ack_or_ba_timeout_collision);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg ba_timeout:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.ba_timeout),
+ accum_tx->agg.ba_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg ba_resched_frames:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.ba_reschedule_frames),
+ accum_tx->agg.ba_reschedule_frames);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg scd_query_agg_frame:\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.scd_query_agg_frame_cnt),
+ accum_tx->agg.scd_query_agg_frame_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg scd_query_no_agg:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.scd_query_no_agg),
+ accum_tx->agg.scd_query_no_agg);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg scd_query_agg:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.scd_query_agg),
+ accum_tx->agg.scd_query_agg);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg scd_query_mismatch:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.scd_query_mismatch),
+ accum_tx->agg.scd_query_mismatch);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg frame_not_ready:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.frame_not_ready),
+ accum_tx->agg.frame_not_ready);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg underrun:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.underrun),
+ accum_tx->agg.underrun);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg bt_prio_kill:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.bt_prio_kill),
+ accum_tx->agg.bt_prio_kill);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "agg rx_ba_rsp_cnt:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(tx->agg.rx_ba_rsp_cnt),
+ accum_tx->agg.rx_ba_rsp_cnt);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf);
@@ -1361,9 +1533,9 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
char *buf;
int bufsz = sizeof(struct statistics_general) * 4 + 250;
ssize_t ret;
- struct statistics_general *general;
- struct statistics_dbg *dbg;
- struct statistics_div *div;
+ struct statistics_general *general, *accum_general;
+ struct statistics_dbg *dbg, *accum_dbg;
+ struct statistics_div *div, *accum_div;
if (!iwl_is_alive(priv))
return -EAGAIN;
@@ -1391,34 +1563,53 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
general = &priv->statistics.general;
dbg = &priv->statistics.general.dbg;
div = &priv->statistics.general.div;
+ accum_general = &priv->accum_statistics.general;
+ accum_dbg = &priv->accum_statistics.general.dbg;
+ accum_div = &priv->accum_statistics.general.div;
pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "Statistics_General:\n");
- pos += scnprintf(buf + pos, bufsz - pos, "temperature: %u\n",
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\t\t\tcurrent\t\t\taccumulative\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "temperature:\t\t\t%u\n",
le32_to_cpu(general->temperature));
- pos += scnprintf(buf + pos, bufsz - pos, "temperature_m: %u\n",
+ pos += scnprintf(buf + pos, bufsz - pos, "temperature_m:\t\t\t%u\n",
le32_to_cpu(general->temperature_m));
- pos += scnprintf(buf + pos, bufsz - pos, "burst_check: %u\n",
- le32_to_cpu(dbg->burst_check));
- pos += scnprintf(buf + pos, bufsz - pos, "burst_count: %u\n",
- le32_to_cpu(dbg->burst_count));
- pos += scnprintf(buf + pos, bufsz - pos, "sleep_time: %u\n",
- le32_to_cpu(general->sleep_time));
- pos += scnprintf(buf + pos, bufsz - pos, "slots_out: %u\n",
- le32_to_cpu(general->slots_out));
- pos += scnprintf(buf + pos, bufsz - pos, "slots_idle: %u\n",
- le32_to_cpu(general->slots_idle));
- pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp: %u\n",
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "burst_check:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(dbg->burst_check),
+ accum_dbg->burst_check);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "burst_count:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(dbg->burst_count),
+ accum_dbg->burst_count);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "sleep_time:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->sleep_time),
+ accum_general->sleep_time);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "slots_out:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->slots_out),
+ accum_general->slots_out);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "slots_idle:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->slots_idle),
+ accum_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, "tx_on_a: %u\n",
- le32_to_cpu(div->tx_on_a));
- pos += scnprintf(buf + pos, bufsz - pos, "tx_on_b: %u\n",
- le32_to_cpu(div->tx_on_b));
- pos += scnprintf(buf + pos, bufsz - pos, "exec_time: %u\n",
- le32_to_cpu(div->exec_time));
- pos += scnprintf(buf + pos, bufsz - pos, "probe_time: %u\n",
- le32_to_cpu(div->probe_time));
- pos += scnprintf(buf + pos, bufsz - pos, "rx_enable_counter: %u\n",
- le32_to_cpu(general->rx_enable_counter));
+ pos += scnprintf(buf + pos, bufsz - pos, "tx_on_a:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(div->tx_on_a), accum_div->tx_on_a);
+ pos += scnprintf(buf + pos, bufsz - pos, "tx_on_b:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(div->tx_on_b), accum_div->tx_on_b);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "exec_time:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(div->exec_time), accum_div->exec_time);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "probe_time:\t\t\t%u\t\t\t%u\n",
+ le32_to_cpu(div->probe_time), accum_div->probe_time);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "rx_enable_counter:\t\t%u\t\t\t%u\n",
+ le32_to_cpu(general->rx_enable_counter),
+ accum_general->rx_enable_counter);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf);
return ret;
@@ -1614,6 +1805,29 @@ static ssize_t iwl_dbgfs_tx_power_read(struct file *file,
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
+static ssize_t iwl_dbgfs_power_save_status_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ char buf[60];
+ int pos = 0;
+ const size_t bufsz = sizeof(buf);
+ u32 pwrsave_status;
+
+ pwrsave_status = iwl_read32(priv, CSR_GP_CNTRL) &
+ CSR_GP_REG_POWER_SAVE_STATUS_MSK;
+
+ pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: ");
+ pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
+ (pwrsave_status == CSR_GP_REG_NO_POWER_SAVE) ? "none" :
+ (pwrsave_status == CSR_GP_REG_MAC_POWER_SAVE) ? "MAC" :
+ (pwrsave_status == CSR_GP_REG_PHY_POWER_SAVE) ? "PHY" :
+ "error");
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics);
DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics);
DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@@ -1625,6 +1839,7 @@ DEBUGFS_READ_FILE_OPS(ucode_general_stats);
DEBUGFS_READ_FILE_OPS(sensitivity);
DEBUGFS_READ_FILE_OPS(chain_noise);
DEBUGFS_READ_FILE_OPS(tx_power);
+DEBUGFS_READ_FILE_OPS(power_save_status);
/*
* Create the debugfs files and directories
@@ -1661,9 +1876,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(status, data);
DEBUGFS_ADD_FILE(interrupt, data);
DEBUGFS_ADD_FILE(qos, data);
-#ifdef CONFIG_IWLWIFI_LEDS
DEBUGFS_ADD_FILE(led, data);
-#endif
DEBUGFS_ADD_FILE(sleep_level_override, data);
DEBUGFS_ADD_FILE(current_sleep_command, data);
DEBUGFS_ADD_FILE(thermal_throttling, data);
@@ -1674,6 +1887,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(rx_queue, debug);
DEBUGFS_ADD_FILE(tx_queue, debug);
DEBUGFS_ADD_FILE(tx_power, debug);
+ DEBUGFS_ADD_FILE(power_save_status, debug);
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
DEBUGFS_ADD_FILE(ucode_rx_stats, debug);
DEBUGFS_ADD_FILE(ucode_tx_stats, debug);
@@ -1716,9 +1930,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_qos);
-#ifdef CONFIG_IWLWIFI_LEDS
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led);
-#endif
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_ht40);
DEBUGFS_REMOVE(priv->dbgfs->dir_data);
@@ -1728,6 +1940,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_queue);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_power_save_status);
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
file_ucode_rx_stats);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 028d50599550..e7ce67387662 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -43,7 +43,6 @@
#include "iwl-debug.h"
#include "iwl-4965-hw.h"
#include "iwl-3945-hw.h"
-#include "iwl-3945-led.h"
#include "iwl-led.h"
#include "iwl-power.h"
#include "iwl-agn-rs.h"
@@ -57,17 +56,22 @@ extern struct iwl_cfg iwl5100_bg_cfg;
extern struct iwl_cfg iwl5100_abg_cfg;
extern struct iwl_cfg iwl5150_agn_cfg;
extern struct iwl_cfg iwl6000h_2agn_cfg;
+extern struct iwl_cfg iwl6000h_2abg_cfg;
+extern struct iwl_cfg iwl6000h_2bg_cfg;
extern struct iwl_cfg iwl6000i_2agn_cfg;
+extern struct iwl_cfg iwl6000i_2abg_cfg;
+extern struct iwl_cfg iwl6000i_2bg_cfg;
extern struct iwl_cfg iwl6000_3agn_cfg;
extern struct iwl_cfg iwl6050_2agn_cfg;
+extern struct iwl_cfg iwl6050_2abg_cfg;
extern struct iwl_cfg iwl6050_3agn_cfg;
extern struct iwl_cfg iwl1000_bgn_cfg;
+extern struct iwl_cfg iwl1000_bg_cfg;
struct iwl_tx_queue;
/* shared structures from iwl-5000.c */
extern struct iwl_mod_params iwl50_mod_params;
-extern struct iwl_ops iwl5000_ops;
extern struct iwl_ucode_ops iwl5000_ucode;
extern struct iwl_lib_ops iwl5000_lib;
extern struct iwl_hcmd_ops iwl5000_hcmd;
@@ -81,9 +85,6 @@ extern void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
__le32 *tx_flags);
extern int iwl5000_calc_rssi(struct iwl_priv *priv,
struct iwl_rx_phy_res *rx_resp);
-extern int iwl5000_apm_init(struct iwl_priv *priv);
-extern void iwl5000_apm_stop(struct iwl_priv *priv);
-extern int iwl5000_apm_reset(struct iwl_priv *priv);
extern void iwl5000_nic_config(struct iwl_priv *priv);
extern u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv);
extern const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
@@ -144,12 +145,13 @@ extern void iwl5000_temperature(struct iwl_priv *priv);
#define DEFAULT_LONG_RETRY_LIMIT 4U
struct iwl_rx_mem_buffer {
- dma_addr_t real_dma_addr;
- dma_addr_t aligned_dma_addr;
- struct sk_buff *skb;
+ dma_addr_t page_dma;
+ struct page *page;
struct list_head list;
};
+#define rxb_addr(r) page_address(r->page)
+
/* defined below */
struct iwl_device_cmd;
@@ -165,7 +167,7 @@ struct iwl_cmd_meta {
*/
void (*callback)(struct iwl_priv *priv,
struct iwl_device_cmd *cmd,
- struct sk_buff *skb);
+ struct iwl_rx_packet *pkt);
/* The CMD_SIZE_HUGE flag bit indicates that the command
* structure is stored at the end of the shared queue memory. */
@@ -321,6 +323,12 @@ struct iwl_channel_info {
* queue, 2 (unused) HCCA queues, and 4 HT queues (one for each AC) */
#define IWL_MIN_NUM_QUEUES 10
+/*
+ * uCode queue management definitions ...
+ * Queue #4 is the command queue for 3945/4965/5x00/1000/6x00.
+ */
+#define IWL_CMD_QUEUE_NUM 4
+
/* Power management (not Tx power) structures */
enum iwl_pwr_src {
@@ -356,7 +364,14 @@ enum {
CMD_WANT_SKB = (1 << 2),
};
-#define IWL_CMD_MAX_PAYLOAD 320
+#define DEF_CMD_PAYLOAD_SIZE 320
+
+/*
+ * IWL_LINK_HDR_MAX should include ieee80211_hdr, radiotap header,
+ * SNAP header and alignment. It should also be big enough for 802.11
+ * control frames.
+ */
+#define IWL_LINK_HDR_MAX 64
/**
* struct iwl_device_cmd
@@ -373,7 +388,8 @@ struct iwl_device_cmd {
u16 val16;
u32 val32;
struct iwl_tx_cmd tx;
- u8 payload[IWL_CMD_MAX_PAYLOAD];
+ struct iwl6000_channel_switch_cmd chswitch;
+ u8 payload[DEF_CMD_PAYLOAD_SIZE];
} __attribute__ ((packed)) cmd;
} __attribute__ ((packed));
@@ -382,21 +398,15 @@ struct iwl_device_cmd {
struct iwl_host_cmd {
const void *data;
- struct sk_buff *reply_skb;
+ unsigned long reply_page;
void (*callback)(struct iwl_priv *priv,
struct iwl_device_cmd *cmd,
- struct sk_buff *skb);
+ struct iwl_rx_packet *pkt);
u32 flags;
u16 len;
u8 id;
};
-/*
- * RX related structures and functions
- */
-#define RX_FREE_BUFFERS 64
-#define RX_LOW_WATERMARK 8
-
#define SUP_RATE_11A_MAX_NUM_CHANNELS 8
#define SUP_RATE_11B_MAX_NUM_CHANNELS 4
#define SUP_RATE_11G_MAX_NUM_CHANNELS 12
@@ -502,12 +512,11 @@ union iwl_ht_rate_supp {
#define CFG_HT_MPDU_DENSITY_4USEC (0x5)
#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_4USEC
-struct iwl_ht_info {
+struct iwl_ht_config {
/* self configuration data */
- u8 is_ht;
- u8 supported_chan_width;
- u8 sm_ps;
- struct ieee80211_mcs_info mcs;
+ bool is_ht;
+ bool is_40mhz;
+ bool single_chain_sufficient;
/* BSS related data */
u8 extension_chan_offset;
u8 ht_protection;
@@ -561,6 +570,19 @@ struct iwl_station_entry {
struct iwl_hw_key keyinfo;
};
+/*
+ * iwl_station_priv: Driver's private station information
+ *
+ * When mac80211 creates a station it reserves some space (hw->sta_data_size)
+ * in the structure for use by driver. This structure is places in that
+ * space.
+ *
+ * At the moment use it for the station's rate scaling information.
+ */
+struct iwl_station_priv {
+ struct iwl_lq_sta lq_sta;
+};
+
/* one for each uCode image (inst/data, boot/init/runtime) */
struct fw_desc {
void *v_addr; /* access by driver */
@@ -622,6 +644,10 @@ struct iwl_sensitivity_ranges {
u16 auto_corr_max_cck_mrc;
u16 auto_corr_min_cck;
u16 auto_corr_min_cck_mrc;
+
+ u16 barker_corr_th_min;
+ u16 barker_corr_th_min_mrc;
+ u16 nrg_th_cca;
};
@@ -639,7 +665,7 @@ struct iwl_sensitivity_ranges {
* @valid_tx/rx_ant: usable antennas
* @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2)
* @max_rxq_log: Log-base-2 of max_rxq_size
- * @rx_buf_size: Rx buffer size
+ * @rx_page_order: Rx buffer page order
* @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR
* @max_stations:
* @bcast_sta_id:
@@ -662,9 +688,8 @@ struct iwl_hw_params {
u8 valid_rx_ant;
u16 max_rxq_size;
u16 max_rxq_log;
- u32 rx_buf_size;
+ u32 rx_page_order;
u32 rx_wrt_ptr_reg;
- u32 max_pkt_size;
u8 max_stations;
u8 bcast_sta_id;
u8 ht40_channel;
@@ -711,7 +736,11 @@ static inline int iwl_queue_used(const struct iwl_queue *q, int i)
static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
{
- /* This is for scan command, the big buffer at end of command array */
+ /*
+ * This is for init calibration result and scan command which
+ * required buffer > TFD_MAX_PAYLOAD_SIZE,
+ * the big buffer at end of command array
+ */
if (is_huge)
return q->n_window; /* must be power of 2 */
@@ -726,9 +755,6 @@ struct iwl_dma_ptr {
size_t size;
};
-#define IWL_CHANNEL_WIDTH_20MHZ 0
-#define IWL_CHANNEL_WIDTH_40MHZ 1
-
#define IWL_OPERATION_MODE_AUTO 0
#define IWL_OPERATION_MODE_HT_ONLY 1
#define IWL_OPERATION_MODE_MIXED 2
@@ -741,7 +767,8 @@ struct iwl_dma_ptr {
/* Sensitivity and chain noise calibration */
#define INITIALIZATION_VALUE 0xFFFF
-#define CAL_NUM_OF_BEACONS 20
+#define IWL4965_CAL_NUM_BEACONS 20
+#define IWL_CAL_NUM_BEACONS 16
#define MAXIMUM_ALLOWED_PATHLOSS 15
#define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3
@@ -845,6 +872,10 @@ struct iwl_sensitivity_data {
s32 nrg_auto_corr_silence_diff;
u32 num_in_cck_no_fa;
u32 nrg_th_ofdm;
+
+ u16 barker_corr_th_min;
+ u16 barker_corr_th_min_mrc;
+ u16 nrg_th_cca;
};
/* Chain noise (differential Rx gain) calib data */
@@ -961,8 +992,6 @@ struct traffic_stats {
};
#endif
-#define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */
-
struct iwl_priv {
/* ieee device used by generic ieee processing code */
@@ -976,7 +1005,7 @@ struct iwl_priv {
int frames_count;
enum ieee80211_band band;
- int alloc_rxb_skb;
+ int alloc_rxb_page;
void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
@@ -1063,14 +1092,11 @@ struct iwl_priv {
struct iwl_init_alive_resp card_alive_init;
struct iwl_alive_resp card_alive;
-#ifdef CONFIG_IWLWIFI_LEDS
unsigned long last_blink_time;
u8 last_blink_rate;
u8 allow_blinking;
u64 led_tpt;
- struct iwl_led led[IWL_LED_TRG_MAX];
- unsigned int rxtxpackets;
-#endif
+
u16 active_rate;
u16 active_rate_basic;
@@ -1080,11 +1106,10 @@ struct iwl_priv {
struct iwl_chain_noise_data chain_noise_data;
__le16 sensitivity_tbl[HD_TABLE_SIZE];
- struct iwl_ht_info current_ht_config;
+ struct iwl_ht_config current_ht_config;
u8 last_phy_res[100];
/* Rate scaling data */
- s8 data_retry_limit;
u8 retry_rate;
wait_queue_head_t wait_command_queue;
@@ -1093,7 +1118,7 @@ struct iwl_priv {
/* Rx and Tx DMA processing queues */
struct iwl_rx_queue rxq;
- struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES];
+ struct iwl_tx_queue *txq;
unsigned long txq_ctx_active_msk;
struct iwl_dma_ptr kw; /* keep warm address */
struct iwl_dma_ptr scd_bc_tbls;
@@ -1116,7 +1141,9 @@ struct iwl_priv {
struct iwl_tt_mgmt thermal_throttle;
struct iwl_notif_statistics statistics;
- unsigned long last_statistics_time;
+#ifdef CONFIG_IWLWIFI_DEBUG
+ struct iwl_notif_statistics accum_statistics;
+#endif
/* context information */
u16 rates_mask;
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
new file mode 100644
index 000000000000..4ef5acaa556d
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
@@ -0,0 +1,13 @@
+#include <linux/module.h>
+
+/* sparse doesn't like tracepoint macros */
+#ifndef __CHECKER__
+#define CREATE_TRACE_POINTS
+#include "iwl-devtrace.h"
+
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ioread32);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error);
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
new file mode 100644
index 000000000000..8c7159208da1
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
@@ -0,0 +1,178 @@
+#if !defined(__IWLWIFI_DEVICE_TRACE) || defined(TRACE_HEADER_MULTI_READ)
+#define __IWLWIFI_DEVICE_TRACE
+
+#include <linux/tracepoint.h>
+#include "iwl-dev.h"
+
+#if !defined(CONFIG_IWLWIFI_DEVICE_TRACING) || defined(__CHECKER__)
+#undef TRACE_EVENT
+#define TRACE_EVENT(name, proto, ...) \
+static inline void trace_ ## name(proto) {}
+#endif
+
+#define PRIV_ENTRY __field(struct iwl_priv *, priv)
+#define PRIV_ASSIGN __entry->priv = priv
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM iwlwifi
+
+TRACE_EVENT(iwlwifi_dev_ioread32,
+ TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val),
+ TP_ARGS(priv, offs, val),
+ TP_STRUCT__entry(
+ PRIV_ENTRY
+ __field(u32, offs)
+ __field(u32, val)
+ ),
+ TP_fast_assign(
+ PRIV_ASSIGN;
+ __entry->offs = offs;
+ __entry->val = val;
+ ),
+ TP_printk("[%p] read io[%#x] = %#x", __entry->priv, __entry->offs, __entry->val)
+);
+
+TRACE_EVENT(iwlwifi_dev_iowrite32,
+ TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val),
+ TP_ARGS(priv, offs, val),
+ TP_STRUCT__entry(
+ PRIV_ENTRY
+ __field(u32, offs)
+ __field(u32, val)
+ ),
+ TP_fast_assign(
+ PRIV_ASSIGN;
+ __entry->offs = offs;
+ __entry->val = val;
+ ),
+ TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val)
+);
+
+TRACE_EVENT(iwlwifi_dev_hcmd,
+ TP_PROTO(struct iwl_priv *priv, void *hcmd, size_t len, u32 flags),
+ TP_ARGS(priv, hcmd, len, flags),
+ TP_STRUCT__entry(
+ PRIV_ENTRY
+ __dynamic_array(u8, hcmd, len)
+ __field(u32, flags)
+ ),
+ TP_fast_assign(
+ PRIV_ASSIGN;
+ memcpy(__get_dynamic_array(hcmd), hcmd, len);
+ __entry->flags = flags;
+ ),
+ TP_printk("[%p] hcmd %#.2x (%ssync)",
+ __entry->priv, ((u8 *)__get_dynamic_array(hcmd))[0],
+ __entry->flags & CMD_ASYNC ? "a" : "")
+);
+
+TRACE_EVENT(iwlwifi_dev_rx,
+ TP_PROTO(struct iwl_priv *priv, void *rxbuf, size_t len),
+ TP_ARGS(priv, rxbuf, len),
+ TP_STRUCT__entry(
+ PRIV_ENTRY
+ __dynamic_array(u8, rxbuf, len)
+ ),
+ TP_fast_assign(
+ PRIV_ASSIGN;
+ memcpy(__get_dynamic_array(rxbuf), rxbuf, len);
+ ),
+ TP_printk("[%p] RX cmd %#.2x",
+ __entry->priv, ((u8 *)__get_dynamic_array(rxbuf))[4])
+);
+
+TRACE_EVENT(iwlwifi_dev_tx,
+ TP_PROTO(struct iwl_priv *priv, void *tfd, size_t tfdlen,
+ void *buf0, size_t buf0_len,
+ void *buf1, size_t buf1_len),
+ TP_ARGS(priv, tfd, tfdlen, buf0, buf0_len, buf1, buf1_len),
+ TP_STRUCT__entry(
+ PRIV_ENTRY
+
+ __field(size_t, framelen)
+ __dynamic_array(u8, tfd, tfdlen)
+
+ /*
+ * Do not insert between or below these items,
+ * we want to keep the frame together (except
+ * for the possible padding).
+ */
+ __dynamic_array(u8, buf0, buf0_len)
+ __dynamic_array(u8, buf1, buf1_len)
+ ),
+ TP_fast_assign(
+ PRIV_ASSIGN;
+ __entry->framelen = buf0_len + buf1_len;
+ memcpy(__get_dynamic_array(tfd), tfd, tfdlen);
+ memcpy(__get_dynamic_array(buf0), buf0, buf0_len);
+ memcpy(__get_dynamic_array(buf1), buf1, buf0_len);
+ ),
+ TP_printk("[%p] TX %.2x (%zu bytes)",
+ __entry->priv,
+ ((u8 *)__get_dynamic_array(buf0))[0],
+ __entry->framelen)
+);
+
+TRACE_EVENT(iwlwifi_dev_ucode_error,
+ TP_PROTO(struct iwl_priv *priv, u32 desc, u32 time,
+ u32 data1, u32 data2, u32 line, u32 blink1,
+ u32 blink2, u32 ilink1, u32 ilink2),
+ TP_ARGS(priv, desc, time, data1, data2, line,
+ blink1, blink2, ilink1, ilink2),
+ TP_STRUCT__entry(
+ PRIV_ENTRY
+ __field(u32, desc)
+ __field(u32, time)
+ __field(u32, data1)
+ __field(u32, data2)
+ __field(u32, line)
+ __field(u32, blink1)
+ __field(u32, blink2)
+ __field(u32, ilink1)
+ __field(u32, ilink2)
+ ),
+ TP_fast_assign(
+ PRIV_ASSIGN;
+ __entry->desc = desc;
+ __entry->time = time;
+ __entry->data1 = data1;
+ __entry->data2 = data2;
+ __entry->line = line;
+ __entry->blink1 = blink1;
+ __entry->blink2 = blink2;
+ __entry->ilink1 = ilink1;
+ __entry->ilink2 = ilink2;
+ ),
+ TP_printk("[%p] #%02d %010u data 0x%08X 0x%08X line %u, "
+ "blink 0x%05X 0x%05X ilink 0x%05X 0x%05X",
+ __entry->priv, __entry->desc, __entry->time, __entry->data1,
+ __entry->data2, __entry->line, __entry->blink1,
+ __entry->blink2, __entry->ilink1, __entry->ilink2)
+);
+
+TRACE_EVENT(iwlwifi_dev_ucode_event,
+ TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev),
+ TP_ARGS(priv, time, data, ev),
+ TP_STRUCT__entry(
+ PRIV_ENTRY
+
+ __field(u32, time)
+ __field(u32, data)
+ __field(u32, ev)
+ ),
+ TP_fast_assign(
+ PRIV_ASSIGN;
+ __entry->time = time;
+ __entry->data = data;
+ __entry->ev = ev;
+ ),
+ TP_printk("[%p] EVT_LOGT:%010u:0x%08x:%04u",
+ __entry->priv, __entry->time, __entry->data, __entry->ev)
+);
+#endif /* __IWLWIFI_DEVICE_TRACE */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE iwl-devtrace
+#include <trace/define_trace.h>
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index e14c9952a935..9429cb1c69bd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -215,12 +215,35 @@ static const struct iwl_txpwr_section enhinfo[] = {
int iwlcore_eeprom_verify_signature(struct iwl_priv *priv)
{
- u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
- if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) {
- IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
- return -ENOENT;
+ u32 gp = iwl_read32(priv, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK;
+ int ret = 0;
+
+ IWL_DEBUG_INFO(priv, "EEPROM signature=0x%08x\n", gp);
+ switch (gp) {
+ case CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP:
+ if (priv->nvm_device_type != NVM_DEVICE_TYPE_OTP) {
+ IWL_ERR(priv, "EEPROM with bad signature: 0x%08x\n",
+ gp);
+ ret = -ENOENT;
+ }
+ break;
+ case CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K:
+ case CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K:
+ if (priv->nvm_device_type != NVM_DEVICE_TYPE_EEPROM) {
+ IWL_ERR(priv, "OTP with bad signature: 0x%08x\n", gp);
+ ret = -ENOENT;
+ }
+ break;
+ case CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP:
+ default:
+ IWL_ERR(priv, "bad EEPROM/OTP signature, type=%s, "
+ "EEPROM_GP=0x%08x\n",
+ (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+ ? "OTP" : "EEPROM", gp);
+ ret = -ENOENT;
+ break;
}
- return 0;
+ return ret;
}
EXPORT_SYMBOL(iwlcore_eeprom_verify_signature);
@@ -283,7 +306,8 @@ int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv)
CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
/* See if we got it */
- ret = iwl_poll_direct_bit(priv, CSR_HW_IF_CONFIG_REG,
+ 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) {
@@ -322,7 +346,8 @@ static int iwl_init_otp_access(struct iwl_priv *priv)
CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
/* wait for clock to be ready */
- ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
+ ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
25000);
if (ret < 0)
@@ -333,6 +358,14 @@ static int iwl_init_otp_access(struct iwl_priv *priv)
udelay(5);
iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_RESET_REQ);
+
+ /*
+ * CSR auto clock gate disable bit -
+ * this is only applicable for HW with OTP shadow RAM
+ */
+ if (priv->cfg->shadow_ram_support)
+ iwl_set_bit(priv, CSR_DBG_LINK_PWR_MGMT_REG,
+ CSR_RESET_LINK_PWR_MGMT_DISABLED);
}
return ret;
}
@@ -345,7 +378,8 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data)
_iwl_write32(priv, CSR_EEPROM_REG,
CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
- ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
+ ret = iwl_poll_bit(priv, CSR_EEPROM_REG,
+ CSR_EEPROM_REG_READ_VALID_MSK,
CSR_EEPROM_REG_READ_VALID_MSK,
IWL_EEPROM_ACCESS_TIMEOUT);
if (ret < 0) {
@@ -537,7 +571,8 @@ int iwl_eeprom_init(struct iwl_priv *priv)
_iwl_write32(priv, CSR_EEPROM_REG,
CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
- ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
+ ret = iwl_poll_bit(priv, CSR_EEPROM_REG,
+ CSR_EEPROM_REG_READ_VALID_MSK,
CSR_EEPROM_REG_READ_VALID_MSK,
IWL_EEPROM_ACCESS_TIMEOUT);
if (ret < 0) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index 80b9e45d9b9c..5ba5a4e9e49a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -63,6 +63,8 @@
#ifndef __iwl_eeprom_h__
#define __iwl_eeprom_h__
+#include <net/mac80211.h>
+
struct iwl_priv;
/*
@@ -256,6 +258,15 @@ struct iwl_eeprom_enhanced_txpwr {
#define EEPROM_5050_TX_POWER_VERSION (4)
#define EEPROM_5050_EEPROM_VERSION (0x21E)
+/* 1000 Specific */
+#define EEPROM_1000_EEPROM_VERSION (0x15C)
+
+/* 6x00 Specific */
+#define EEPROM_6000_EEPROM_VERSION (0x434)
+
+/* 6x50 Specific */
+#define EEPROM_6050_EEPROM_VERSION (0x532)
+
/* OTP */
/* lower blocks contain EEPROM image and calibration data */
#define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */
@@ -370,12 +381,10 @@ struct iwl_eeprom_calib_info {
#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */
#define EEPROM_VERSION (2*0x44) /* 2 bytes */
#define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */
-#define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */
#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */
#define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */
#define EEPROM_RADIO_CONFIG (2*0x48) /* 2 bytes */
#define EEPROM_3945_M_VERSION (2*0x4A) /* 1 bytes */
-#define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */
/* The following masks are to be applied on EEPROM_RADIO_CONFIG */
#define EEPROM_RF_CFG_TYPE_MSK(x) (x & 0x3) /* bits 0-1 */
@@ -387,7 +396,12 @@ struct iwl_eeprom_calib_info {
#define EEPROM_3945_RF_CFG_TYPE_MAX 0x0
#define EEPROM_4965_RF_CFG_TYPE_MAX 0x1
-#define EEPROM_5000_RF_CFG_TYPE_MAX 0x3
+
+/* Radio Config for 5000 and up */
+#define EEPROM_RF_CONFIG_TYPE_R3x3 0x0
+#define EEPROM_RF_CONFIG_TYPE_R2x2 0x1
+#define EEPROM_RF_CONFIG_TYPE_R1x2 0x2
+#define EEPROM_RF_CONFIG_TYPE_MAX 0x3
/*
* Per-channel regulatory data.
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index a6856daf14cb..d7ebc5fb69d4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -93,6 +93,8 @@ const char *get_cmd_string(u8 cmd)
IWL_CMD(CALIBRATION_RES_NOTIFICATION);
IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION);
IWL_CMD(REPLY_TX_POWER_DBM_CMD);
+ IWL_CMD(TEMPERATURE_NOTIFICATION);
+ IWL_CMD(TX_ANT_CONFIGURATION_CMD);
default:
return "UNKNOWN";
@@ -104,17 +106,8 @@ EXPORT_SYMBOL(get_cmd_string);
static void iwl_generic_cmd_callback(struct iwl_priv *priv,
struct iwl_device_cmd *cmd,
- struct sk_buff *skb)
+ struct iwl_rx_packet *pkt)
{
- struct iwl_rx_packet *pkt = NULL;
-
- if (!skb) {
- IWL_ERR(priv, "Error: Response NULL in %s.\n",
- get_cmd_string(cmd->hdr.cmd));
- return;
- }
-
- pkt = (struct iwl_rx_packet *)skb->data;
if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from %s (0x%08X)\n",
get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
@@ -216,7 +209,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
ret = -EIO;
goto fail;
}
- if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_skb) {
+ if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) {
IWL_ERR(priv, "Error: Response NULL in '%s'\n",
get_cmd_string(cmd->id));
ret = -EIO;
@@ -238,9 +231,9 @@ cancel:
~CMD_WANT_SKB;
}
fail:
- if (cmd->reply_skb) {
- dev_kfree_skb_any(cmd->reply_skb);
- cmd->reply_skb = NULL;
+ if (cmd->reply_page) {
+ free_pages(cmd->reply_page, priv->hw_params.rx_page_order);
+ cmd->reply_page = 0;
}
out:
clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status);
@@ -273,7 +266,7 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv,
u8 id, u16 len, const void *data,
void (*callback)(struct iwl_priv *priv,
struct iwl_device_cmd *cmd,
- struct sk_buff *skb))
+ struct iwl_rx_packet *pkt))
{
struct iwl_host_cmd cmd = {
.id = id,
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index d30cb0275d19..0a078b082833 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -32,6 +32,7 @@
#include <linux/io.h>
#include "iwl-debug.h"
+#include "iwl-devtrace.h"
/*
* IO, register, and NIC memory access functions
@@ -61,7 +62,12 @@
*
*/
-#define _iwl_write32(priv, ofs, val) iowrite32((val), (priv)->hw_base + (ofs))
+static inline void _iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val)
+{
+ trace_iwlwifi_dev_iowrite32(priv, ofs, val);
+ iowrite32(val, priv->hw_base + ofs);
+}
+
#ifdef CONFIG_IWLWIFI_DEBUG
static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv,
u32 ofs, u32 val)
@@ -75,7 +81,13 @@ static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv,
#define iwl_write32(priv, ofs, val) _iwl_write32(priv, ofs, val)
#endif
-#define _iwl_read32(priv, ofs) ioread32((priv)->hw_base + (ofs))
+static inline u32 _iwl_read32(struct iwl_priv *priv, u32 ofs)
+{
+ u32 val = ioread32(priv->hw_base + ofs);
+ trace_iwlwifi_dev_ioread32(priv, ofs, val);
+ return val;
+}
+
#ifdef CONFIG_IWLWIFI_DEBUG
static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs)
{
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index f420c99e7240..478c90511ebf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -42,15 +42,11 @@
#include "iwl-core.h"
#include "iwl-io.h"
-#ifdef CONFIG_IWLWIFI_DEBUG
-static const char *led_type_str[] = {
- __stringify(IWL_LED_TRG_TX),
- __stringify(IWL_LED_TRG_RX),
- __stringify(IWL_LED_TRG_ASSOC),
- __stringify(IWL_LED_TRG_RADIO),
- NULL
-};
-#endif /* CONFIG_IWLWIFI_DEBUG */
+/* default: IWL_LED_BLINK(0) using blinking index table */
+static int led_mode;
+module_param(led_mode, int, S_IRUGO);
+MODULE_PARM_DESC(led_mode, "led mode: 0=blinking, 1=On(RF On)/Off(RF Off), "
+ "(default 0)\n");
static const struct {
@@ -65,11 +61,11 @@ static const struct {
{70, 65, 65},
{50, 75, 75},
{20, 85, 85},
- {15, 95, 95 },
- {10, 110, 110},
- {5, 130, 130},
+ {10, 95, 95},
+ {5, 110, 110},
+ {1, 130, 130},
{0, 167, 167},
-/* SOLID_ON */
+ /* SOLID_ON */
{-1, IWL_LED_SOLID, 0}
};
@@ -78,191 +74,74 @@ static const struct {
#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /* exclude SOLID_ON */
#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1)
-/* [0-256] -> [0..8] FIXME: we need [0..10] */
-static inline int iwl_brightness_to_idx(enum led_brightness brightness)
-{
- return fls(0x000000FF & (u32)brightness);
-}
-
-/* Send led command */
-static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
+/*
+ * Adjust led blink rate to compensate on a MAC Clock difference on every HW
+ * Led blink rate analysis showed an average deviation of 0% on 3945,
+ * 5% on 4965 HW and 20% on 5000 series and up.
+ * Need to compensate on the led on/off time per HW according to the deviation
+ * to achieve the desired led frequency
+ * The calculation is: (100-averageDeviation)/100 * blinkTime
+ * For code efficiency the calculation will be:
+ * compensation = (100 - averageDeviation) * 64 / 100
+ * NewBlinkTime = (compensation * BlinkTime) / 64
+ */
+static inline u8 iwl_blink_compensation(struct iwl_priv *priv,
+ u8 time, u16 compensation)
{
- struct iwl_host_cmd cmd = {
- .id = REPLY_LEDS_CMD,
- .len = sizeof(struct iwl_led_cmd),
- .data = led_cmd,
- .flags = CMD_ASYNC,
- .callback = NULL,
- };
- u32 reg;
-
- reg = iwl_read32(priv, CSR_LED_REG);
- if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
- iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK);
+ if (!compensation) {
+ IWL_ERR(priv, "undefined blink compensation: "
+ "use pre-defined blinking time\n");
+ return time;
+ }
- return iwl_send_cmd(priv, &cmd);
+ return (u8)((time * compensation) >> 6);
}
/* Set led pattern command */
-static int iwl_led_pattern(struct iwl_priv *priv, int led_id,
- unsigned int idx)
+static int iwl_led_pattern(struct iwl_priv *priv, unsigned int idx)
{
struct iwl_led_cmd led_cmd = {
- .id = led_id,
+ .id = IWL_LED_LINK,
.interval = IWL_DEF_LED_INTRVL
};
BUG_ON(idx > IWL_MAX_BLINK_TBL);
- led_cmd.on = blink_tbl[idx].on_time;
- led_cmd.off = blink_tbl[idx].off_time;
-
- return iwl_send_led_cmd(priv, &led_cmd);
-}
-
-/* Set led register off */
-static int iwl_led_on_reg(struct iwl_priv *priv, int led_id)
-{
- IWL_DEBUG_LED(priv, "led on %d\n", led_id);
- iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
- return 0;
-}
+ IWL_DEBUG_LED(priv, "Led blink time compensation= %u\n",
+ priv->cfg->led_compensation);
+ led_cmd.on =
+ iwl_blink_compensation(priv, blink_tbl[idx].on_time,
+ priv->cfg->led_compensation);
+ led_cmd.off =
+ iwl_blink_compensation(priv, blink_tbl[idx].off_time,
+ priv->cfg->led_compensation);
-#if 0
-/* Set led on command */
-static int iwl_led_on(struct iwl_priv *priv, int led_id)
-{
- struct iwl_led_cmd led_cmd = {
- .id = led_id,
- .on = IWL_LED_SOLID,
- .off = 0,
- .interval = IWL_DEF_LED_INTRVL
- };
- return iwl_send_led_cmd(priv, &led_cmd);
+ return priv->cfg->ops->led->cmd(priv, &led_cmd);
}
-/* Set led off command */
-int iwl_led_off(struct iwl_priv *priv, int led_id)
+int iwl_led_start(struct iwl_priv *priv)
{
- struct iwl_led_cmd led_cmd = {
- .id = led_id,
- .on = 0,
- .off = 0,
- .interval = IWL_DEF_LED_INTRVL
- };
- IWL_DEBUG_LED(priv, "led off %d\n", led_id);
- return iwl_send_led_cmd(priv, &led_cmd);
+ return priv->cfg->ops->led->on(priv);
}
-#endif
-
+EXPORT_SYMBOL(iwl_led_start);
-/* Set led register off */
-static int iwl_led_off_reg(struct iwl_priv *priv, int led_id)
-{
- IWL_DEBUG_LED(priv, "LED Reg off\n");
- iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF);
- return 0;
-}
-
-/*
- * Set led register in case of disassociation according to rfkill state
- */
-static int iwl_led_associate(struct iwl_priv *priv, int led_id)
+int iwl_led_associate(struct iwl_priv *priv)
{
IWL_DEBUG_LED(priv, "Associated\n");
- priv->allow_blinking = 1;
- return iwl_led_on_reg(priv, led_id);
-}
-static int iwl_led_disassociate(struct iwl_priv *priv, int led_id)
-{
- priv->allow_blinking = 0;
-
- return 0;
-}
-
-/*
- * brightness call back function for Tx/Rx LED
- */
-static int iwl_led_associated(struct iwl_priv *priv, int led_id)
-{
- if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
- !test_bit(STATUS_READY, &priv->status))
- return 0;
-
+ if (led_mode == IWL_LED_BLINK)
+ priv->allow_blinking = 1;
+ priv->last_blink_time = jiffies;
- /* start counting Tx/Rx bytes */
- if (!priv->last_blink_time && priv->allow_blinking)
- priv->last_blink_time = jiffies;
return 0;
}
-/*
- * brightness call back for association and radio
- */
-static void iwl_led_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
+int iwl_led_disassociate(struct iwl_priv *priv)
{
- struct iwl_led *led = container_of(led_cdev, struct iwl_led, led_dev);
- struct iwl_priv *priv = led->priv;
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
-
- IWL_DEBUG_LED(priv, "Led type = %s brightness = %d\n",
- led_type_str[led->type], brightness);
- switch (brightness) {
- case LED_FULL:
- if (led->led_on)
- led->led_on(priv, IWL_LED_LINK);
- break;
- case LED_OFF:
- if (led->led_off)
- led->led_off(priv, IWL_LED_LINK);
- break;
- default:
- if (led->led_pattern) {
- int idx = iwl_brightness_to_idx(brightness);
- led->led_pattern(priv, IWL_LED_LINK, idx);
- }
- break;
- }
-}
-
-
-
-/*
- * Register led class with the system
- */
-static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led,
- enum led_type type, u8 set_led,
- char *trigger)
-{
- struct device *device = wiphy_dev(priv->hw->wiphy);
- int ret;
-
- led->led_dev.name = led->name;
- led->led_dev.brightness_set = iwl_led_brightness_set;
- led->led_dev.default_trigger = trigger;
-
- led->priv = priv;
- led->type = type;
-
- ret = led_classdev_register(device, &led->led_dev);
- if (ret) {
- IWL_ERR(priv, "Error: failed to register led handler.\n");
- return ret;
- }
-
- led->registered = 1;
-
- if (set_led && led->led_on)
- led->led_on(priv, IWL_LED_LINK);
+ priv->allow_blinking = 0;
return 0;
}
-
/*
* calculate blink rate according to last second Tx/Rx activities
*/
@@ -288,7 +167,7 @@ static int iwl_get_blink_rate(struct iwl_priv *priv)
i = IWL_MAX_BLINK_TBL;
else
for (i = 0; i < IWL_MAX_BLINK_TBL; i++)
- if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE))
+ if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE))
break;
IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", i);
@@ -317,8 +196,7 @@ void iwl_leds_background(struct iwl_priv *priv)
priv->last_blink_time = 0;
if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) {
priv->last_blink_rate = IWL_SOLID_BLINK_IDX;
- iwl_led_pattern(priv, IWL_LED_LINK,
- IWL_SOLID_BLINK_IDX);
+ iwl_led_pattern(priv, IWL_SOLID_BLINK_IDX);
}
return;
}
@@ -331,111 +209,18 @@ void iwl_leds_background(struct iwl_priv *priv)
/* call only if blink rate change */
if (blink_idx != priv->last_blink_rate)
- iwl_led_pattern(priv, IWL_LED_LINK, blink_idx);
+ iwl_led_pattern(priv, blink_idx);
priv->last_blink_time = jiffies;
priv->last_blink_rate = blink_idx;
}
+EXPORT_SYMBOL(iwl_leds_background);
-/* Register all led handler */
-int iwl_leds_register(struct iwl_priv *priv)
+void iwl_leds_init(struct iwl_priv *priv)
{
- char *trigger;
- int ret;
-
priv->last_blink_rate = 0;
priv->led_tpt = 0;
priv->last_blink_time = 0;
priv->allow_blinking = 0;
-
- trigger = ieee80211_get_radio_led_name(priv->hw);
- snprintf(priv->led[IWL_LED_TRG_RADIO].name,
- sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio",
- wiphy_name(priv->hw->wiphy));
-
- priv->led[IWL_LED_TRG_RADIO].led_on = iwl_led_on_reg;
- priv->led[IWL_LED_TRG_RADIO].led_off = iwl_led_off_reg;
- priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
-
- ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO],
- IWL_LED_TRG_RADIO, 1, trigger);
- if (ret)
- goto exit_fail;
-
- trigger = ieee80211_get_assoc_led_name(priv->hw);
- snprintf(priv->led[IWL_LED_TRG_ASSOC].name,
- sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s::assoc",
- wiphy_name(priv->hw->wiphy));
-
- ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_ASSOC],
- IWL_LED_TRG_ASSOC, 0, trigger);
-
- /* for assoc always turn led on */
- priv->led[IWL_LED_TRG_ASSOC].led_on = iwl_led_associate;
- priv->led[IWL_LED_TRG_ASSOC].led_off = iwl_led_disassociate;
- priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL;
-
- if (ret)
- goto exit_fail;
-
- trigger = ieee80211_get_rx_led_name(priv->hw);
- snprintf(priv->led[IWL_LED_TRG_RX].name,
- sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s::RX",
- wiphy_name(priv->hw->wiphy));
-
- ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RX],
- IWL_LED_TRG_RX, 0, trigger);
-
- priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated;
- priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated;
- priv->led[IWL_LED_TRG_RX].led_pattern = iwl_led_pattern;
-
- if (ret)
- goto exit_fail;
-
- trigger = ieee80211_get_tx_led_name(priv->hw);
- snprintf(priv->led[IWL_LED_TRG_TX].name,
- sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s::TX",
- wiphy_name(priv->hw->wiphy));
-
- ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_TX],
- IWL_LED_TRG_TX, 0, trigger);
-
- priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated;
- priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated;
- priv->led[IWL_LED_TRG_TX].led_pattern = iwl_led_pattern;
-
- if (ret)
- goto exit_fail;
-
- return 0;
-
-exit_fail:
- iwl_leds_unregister(priv);
- return ret;
}
-EXPORT_SYMBOL(iwl_leds_register);
-
-/* unregister led class */
-static void iwl_leds_unregister_led(struct iwl_led *led, u8 set_led)
-{
- if (!led->registered)
- return;
-
- led_classdev_unregister(&led->led_dev);
-
- if (set_led)
- led->led_dev.brightness_set(&led->led_dev, LED_OFF);
- led->registered = 0;
-}
-
-/* Unregister all led handlers */
-void iwl_leds_unregister(struct iwl_priv *priv)
-{
- iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_ASSOC], 0);
- iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_RX], 0);
- iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_TX], 0);
- iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_RADIO], 1);
-}
-EXPORT_SYMBOL(iwl_leds_unregister);
-
+EXPORT_SYMBOL(iwl_leds_init);
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h
index ef9b174c37ff..f47f053f02ea 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-led.h
@@ -30,9 +30,6 @@
struct iwl_priv;
-#ifdef CONFIG_IWLWIFI_LEDS
-#include <linux/leds.h>
-
#define IWL_LED_SOLID 11
#define IWL_LED_NAME_LEN 31
#define IWL_DEF_LED_INTRVL cpu_to_le32(1000)
@@ -47,38 +44,23 @@ enum led_type {
IWL_LED_TRG_RADIO,
IWL_LED_TRG_MAX,
};
-#endif
-
-#ifdef CONFIG_IWLWIFI_LEDS
-
-struct iwl_led {
- struct iwl_priv *priv;
- struct led_classdev led_dev;
- char name[32];
- int (*led_on) (struct iwl_priv *priv, int led_id);
- int (*led_off) (struct iwl_priv *priv, int led_id);
- int (*led_pattern) (struct iwl_priv *priv, int led_id, unsigned int idx);
-
- enum led_type type;
- unsigned int registered;
+/*
+ * LED mode
+ * IWL_LED_BLINK: adjust led blink rate based on blink table
+ * IWL_LED_RF_STATE: turn LED on/off based on RF state
+ * LED ON = RF ON
+ * LED OFF = RF OFF
+ */
+enum iwl_led_mode {
+ IWL_LED_BLINK,
+ IWL_LED_RF_STATE,
};
-int iwl_leds_register(struct iwl_priv *priv);
-void iwl_leds_unregister(struct iwl_priv *priv);
+void iwl_leds_init(struct iwl_priv *priv);
void iwl_leds_background(struct iwl_priv *priv);
+int iwl_led_start(struct iwl_priv *priv);
+int iwl_led_associate(struct iwl_priv *priv);
+int iwl_led_disassociate(struct iwl_priv *priv);
-#else
-static inline int iwl_leds_register(struct iwl_priv *priv)
-{
- return 0;
-}
-static inline void iwl_leds_unregister(struct iwl_priv *priv)
-{
-}
-static inline void iwl_leds_background(struct iwl_priv *priv)
-{
-}
-
-#endif /* CONFIG_IWLWIFI_LEDS */
#endif /* __iwl_leds_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index 60be976afff8..9bce2c1625e3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -66,7 +66,7 @@ MODULE_PARM_DESC(no_sleep_autoadjust,
struct iwl_power_vec_entry {
struct iwl_powertable_cmd cmd;
- u8 no_dtim;
+ u8 no_dtim; /* number of skip dtim */
};
#define IWL_DTIM_RANGE_0_MAX 2
@@ -83,8 +83,9 @@ struct iwl_power_vec_entry {
cpu_to_le32(X4)}
/* default power management (not Tx power) table values */
/* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */
+/* DTIM 0 - 2 */
static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = {
- {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
+ {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 1, 2, 2, 0xFF)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0},
{{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 2, 4, 4, 0xFF)}, 1},
@@ -93,15 +94,17 @@ static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = {
/* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */
+/* DTIM 3 - 10 */
static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = {
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0},
{{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0},
{{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 4, 6, 9, 10)}, 1},
- {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2}
+ {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 6, 10, 10)}, 2}
};
/* for DTIM period > IWL_DTIM_RANGE_1_MAX */
+/* DTIM 11 - */
static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = {
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
@@ -115,13 +118,15 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
enum iwl_power_level lvl, int period)
{
const struct iwl_power_vec_entry *table;
- int max_sleep, i;
- bool skip;
+ int max_sleep[IWL_POWER_VEC_SIZE] = { 0 };
+ int i;
+ u8 skip;
+ u32 slp_itrvl;
table = range_2;
- if (period < IWL_DTIM_RANGE_1_MAX)
+ if (period <= IWL_DTIM_RANGE_1_MAX)
table = range_1;
- if (period < IWL_DTIM_RANGE_0_MAX)
+ if (period <= IWL_DTIM_RANGE_0_MAX)
table = range_0;
BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM);
@@ -129,34 +134,60 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
*cmd = table[lvl].cmd;
if (period == 0) {
- skip = false;
+ skip = 0;
period = 1;
+ for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
+ max_sleep[i] = 1;
+
} else {
- skip = !!table[lvl].no_dtim;
+ skip = table[lvl].no_dtim;
+ for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
+ max_sleep[i] = le32_to_cpu(cmd->sleep_interval[i]);
+ max_sleep[IWL_POWER_VEC_SIZE - 1] = skip + 1;
}
- if (skip) {
- __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1];
- max_sleep = le32_to_cpu(slp_itrvl);
- if (max_sleep == 0xFF)
- max_sleep = period * (skip + 1);
- else if (max_sleep > period)
- max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
+ slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
+ /* figure out the listen interval based on dtim period and skip */
+ if (slp_itrvl == 0xFF)
+ cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
+ cpu_to_le32(period * (skip + 1));
+
+ slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
+ if (slp_itrvl > period)
+ cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
+ cpu_to_le32((slp_itrvl / period) * period);
+
+ if (skip)
cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
- } else {
- max_sleep = period;
+ else
cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
- }
- for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
- if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
- cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
+ slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]);
+ if (slp_itrvl > IWL_CONN_MAX_LISTEN_INTERVAL)
+ cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] =
+ cpu_to_le32(IWL_CONN_MAX_LISTEN_INTERVAL);
+
+ /* enforce max sleep interval */
+ for (i = IWL_POWER_VEC_SIZE - 1; i >= 0 ; i--) {
+ if (le32_to_cpu(cmd->sleep_interval[i]) >
+ (max_sleep[i] * period))
+ cmd->sleep_interval[i] =
+ cpu_to_le32(max_sleep[i] * period);
+ if (i != (IWL_POWER_VEC_SIZE - 1)) {
+ if (le32_to_cpu(cmd->sleep_interval[i]) >
+ le32_to_cpu(cmd->sleep_interval[i+1]))
+ cmd->sleep_interval[i] =
+ cmd->sleep_interval[i+1];
+ }
+ }
if (priv->power_data.pci_pm)
cmd->flags |= IWL_POWER_PCI_PM_MSK;
else
cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
+ IWL_DEBUG_POWER(priv, "numSkipDtim = %u, dtimPeriod = %d\n",
+ skip, period);
IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1);
}
@@ -165,26 +196,26 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
*=============================================================================
* Condition Nxt State Condition Nxt State Condition Nxt State
*-----------------------------------------------------------------------------
- * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A
- * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0
- * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1
+ * 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},
- {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+ {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},
- {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+ {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 + 1, IWL_ABSOLUTE_MAX},
- {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+ {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},
@@ -294,6 +325,9 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
if (priv->cfg->broken_powersave)
iwl_power_sleep_cam_cmd(priv, &cmd);
+ else if (priv->cfg->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)
@@ -348,6 +382,23 @@ bool iwl_ht_enabled(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_ht_enabled);
+bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
+{
+ s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */
+ bool within_margin = false;
+
+ if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
+ 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;
@@ -372,6 +423,7 @@ enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv)
}
#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
@@ -409,6 +461,7 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data)
/* 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);
}
@@ -432,6 +485,33 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
}
}
+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, 0);
+ /* 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)
@@ -445,7 +525,7 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
* 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)
+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;
@@ -474,6 +554,8 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
#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:
@@ -494,17 +576,28 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
break;
}
mutex_lock(&priv->mutex);
- if (iwl_power_update_mode(priv, true)) {
+ 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)
- iwl_perform_ct_kill_task(priv, true);
- else if (old_state == IWL_TI_CT_KILL &&
+ 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",
@@ -531,13 +624,13 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp)
*=============================================================================
* Condition Nxt State Condition Nxt State Condition Nxt State
*-----------------------------------------------------------------------------
- * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A
- * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0
- * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1
+ * 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)
+static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
{
struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
int i;
@@ -582,6 +675,8 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
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;
@@ -613,12 +708,17 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
iwl_set_rxon_ht(priv, &priv->current_ht_config);
}
mutex_lock(&priv->mutex);
- if (iwl_power_update_mode(priv, true)) {
+ 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,
@@ -626,9 +726,15 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp)
tt->state);
if (old_state != IWL_TI_CT_KILL &&
tt->state == IWL_TI_CT_KILL) {
- IWL_DEBUG_POWER(priv, "Enter IWL_TI_CT_KILL\n");
- iwl_perform_ct_kill_task(priv, true);
-
+ 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");
@@ -665,10 +771,11 @@ static void iwl_bg_ct_enter(struct work_struct *work)
"- ucode going to sleep!\n");
if (!priv->thermal_throttle.advanced_tt)
iwl_legacy_tt_handler(priv,
- IWL_MINIMAL_POWER_THRESHOLD);
+ IWL_MINIMAL_POWER_THRESHOLD,
+ true);
else
iwl_advance_tt_handler(priv,
- CT_KILL_THRESHOLD + 1);
+ CT_KILL_THRESHOLD + 1, true);
}
}
@@ -695,11 +802,18 @@ static void iwl_bg_ct_exit(struct work_struct *work)
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);
+ IWL_REDUCED_PERFORMANCE_THRESHOLD_2,
+ true);
else
- iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD);
+ iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD,
+ true);
}
}
@@ -735,9 +849,9 @@ static void iwl_bg_tt_work(struct work_struct *work)
temp = KELVIN_TO_CELSIUS(priv->temperature);
if (!priv->thermal_throttle.advanced_tt)
- iwl_legacy_tt_handler(priv, temp);
+ iwl_legacy_tt_handler(priv, temp, false);
else
- iwl_advance_tt_handler(priv, temp);
+ iwl_advance_tt_handler(priv, temp, false);
}
void iwl_tt_handler(struct iwl_priv *priv)
@@ -768,16 +882,18 @@ void iwl_tt_initialize(struct iwl_priv *priv)
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;
-
+ 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);
- switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
- case CSR_HW_REV_TYPE_6x00:
- case CSR_HW_REV_TYPE_6x50:
+ 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);
@@ -810,11 +926,9 @@ void iwl_tt_initialize(struct iwl_priv *priv)
&restriction_range[0], size);
priv->thermal_throttle.advanced_tt = true;
}
- break;
- default:
+ } else {
IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n");
priv->thermal_throttle.advanced_tt = false;
- break;
}
}
EXPORT_SYMBOL(iwl_tt_initialize);
@@ -826,6 +940,8 @@ void iwl_tt_exit(struct iwl_priv *priv)
/* 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);
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index df6f6a49712b..310c32e8f698 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -33,6 +33,7 @@
#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,
@@ -110,6 +111,7 @@ struct iwl_tt_mgmt {
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 {
@@ -129,6 +131,7 @@ 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);
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 493626bcd3ec..e5339c9ad13e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -200,7 +200,7 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
list_del(element);
/* Point to Rx buffer via next RBD in circular buffer */
- rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->aligned_dma_addr);
+ rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->page_dma);
rxq->queue[rxq->write] = rxb;
rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
rxq->free_count--;
@@ -239,8 +239,9 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
struct iwl_rx_queue *rxq = &priv->rxq;
struct list_head *element;
struct iwl_rx_mem_buffer *rxb;
- struct sk_buff *skb;
+ struct page *page;
unsigned long flags;
+ gfp_t gfp_mask = priority;
while (1) {
spin_lock_irqsave(&rxq->lock, flags);
@@ -251,30 +252,35 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
spin_unlock_irqrestore(&rxq->lock, flags);
if (rxq->free_count > RX_LOW_WATERMARK)
- priority |= __GFP_NOWARN;
- /* Alloc a new receive buffer */
- skb = alloc_skb(priv->hw_params.rx_buf_size + 256,
- priority);
+ gfp_mask |= __GFP_NOWARN;
+
+ if (priv->hw_params.rx_page_order > 0)
+ gfp_mask |= __GFP_COMP;
- if (!skb) {
+ /* Alloc a new receive buffer */
+ page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order);
+ if (!page) {
if (net_ratelimit())
- IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n");
+ IWL_DEBUG_INFO(priv, "alloc_pages failed, "
+ "order: %d\n",
+ priv->hw_params.rx_page_order);
+
if ((rxq->free_count <= RX_LOW_WATERMARK) &&
net_ratelimit())
- IWL_CRIT(priv, "Failed to allocate SKB buffer with %s. Only %u free buffers remaining.\n",
+ IWL_CRIT(priv, "Failed to alloc_pages with %s. Only %u free buffers remaining.\n",
priority == GFP_ATOMIC ? "GFP_ATOMIC" : "GFP_KERNEL",
rxq->free_count);
/* We don't reschedule replenish work here -- we will
* call the restock method and if it still needs
* more buffers it will schedule replenish */
- break;
+ return;
}
spin_lock_irqsave(&rxq->lock, flags);
if (list_empty(&rxq->rx_used)) {
spin_unlock_irqrestore(&rxq->lock, flags);
- dev_kfree_skb_any(skb);
+ __free_pages(page, priv->hw_params.rx_page_order);
return;
}
element = rxq->rx_used.next;
@@ -283,24 +289,21 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
spin_unlock_irqrestore(&rxq->lock, flags);
- rxb->skb = skb;
- /* Get physical address of RB/SKB */
- rxb->real_dma_addr = pci_map_single(
- priv->pci_dev,
- rxb->skb->data,
- priv->hw_params.rx_buf_size + 256,
- PCI_DMA_FROMDEVICE);
+ rxb->page = page;
+ /* Get physical address of the RB */
+ rxb->page_dma = pci_map_page(priv->pci_dev, page, 0,
+ PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
/* dma address must be no more than 36 bits */
- BUG_ON(rxb->real_dma_addr & ~DMA_BIT_MASK(36));
+ BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
/* and also 256 byte aligned! */
- rxb->aligned_dma_addr = ALIGN(rxb->real_dma_addr, 256);
- skb_reserve(rxb->skb, rxb->aligned_dma_addr - rxb->real_dma_addr);
+ BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
spin_lock_irqsave(&rxq->lock, flags);
list_add_tail(&rxb->list, &rxq->rx_free);
rxq->free_count++;
- priv->alloc_rxb_skb++;
+ priv->alloc_rxb_page++;
spin_unlock_irqrestore(&rxq->lock, flags);
}
@@ -336,12 +339,14 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
{
int i;
for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
- if (rxq->pool[i].skb != NULL) {
- pci_unmap_single(priv->pci_dev,
- rxq->pool[i].real_dma_addr,
- priv->hw_params.rx_buf_size + 256,
- PCI_DMA_FROMDEVICE);
- dev_kfree_skb(rxq->pool[i].skb);
+ if (rxq->pool[i].page != NULL) {
+ pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
+ PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
+ __free_pages(rxq->pool[i].page,
+ priv->hw_params.rx_page_order);
+ rxq->pool[i].page = NULL;
+ priv->alloc_rxb_page--;
}
}
@@ -405,14 +410,14 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
/* In the reset function, these buffers may have been allocated
* to an SKB, so we need to unmap and free potential storage */
- if (rxq->pool[i].skb != NULL) {
- pci_unmap_single(priv->pci_dev,
- rxq->pool[i].real_dma_addr,
- priv->hw_params.rx_buf_size + 256,
- PCI_DMA_FROMDEVICE);
- priv->alloc_rxb_skb--;
- dev_kfree_skb(rxq->pool[i].skb);
- rxq->pool[i].skb = NULL;
+ if (rxq->pool[i].page != NULL) {
+ pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
+ PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
+ priv->alloc_rxb_page--;
+ __free_pages(rxq->pool[i].page,
+ priv->hw_params.rx_page_order);
+ rxq->pool[i].page = NULL;
}
list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
}
@@ -491,7 +496,7 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_missed_beacon_notif *missed_beacon;
missed_beacon = &pkt->u.missed_beacon;
@@ -548,13 +553,51 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)
priv->last_rx_noise);
}
+#ifdef CONFIG_IWLWIFI_DEBUG
+/*
+ * based on the assumption of all statistics counter are in DWORD
+ * FIXME: This function is for debugging, do not deal with
+ * the case of counters roll-over.
+ */
+static void iwl_accumulative_statistics(struct iwl_priv *priv,
+ __le32 *stats)
+{
+ int i;
+ __le32 *prev_stats;
+ u32 *accum_stats;
+
+ prev_stats = (__le32 *)&priv->statistics;
+ accum_stats = (u32 *)&priv->accum_statistics;
+
+ for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics);
+ i += sizeof(__le32), stats++, prev_stats++, accum_stats++)
+ if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats))
+ *accum_stats += (le32_to_cpu(*stats) -
+ le32_to_cpu(*prev_stats));
+
+ /* reset accumulative statistics for "no-counter" type statistics */
+ priv->accum_statistics.general.temperature =
+ priv->statistics.general.temperature;
+ priv->accum_statistics.general.temperature_m =
+ priv->statistics.general.temperature_m;
+ priv->accum_statistics.general.ttl_timestamp =
+ priv->statistics.general.ttl_timestamp;
+ priv->accum_statistics.tx.tx_power.ant_a =
+ priv->statistics.tx.tx_power.ant_a;
+ priv->accum_statistics.tx.tx_power.ant_b =
+ priv->statistics.tx.tx_power.ant_b;
+ priv->accum_statistics.tx.tx_power.ant_c =
+ priv->statistics.tx.tx_power.ant_c;
+}
+#endif
+
#define REG_RECALIB_PERIOD (60)
void iwl_rx_statistics(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
int change;
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
(int)sizeof(priv->statistics),
@@ -566,6 +609,9 @@ void iwl_rx_statistics(struct iwl_priv *priv,
STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
(pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
+#ifdef CONFIG_IWLWIFI_DEBUG
+ iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
+#endif
memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
set_bit(STATUS_STATISTICS, &priv->status);
@@ -582,9 +628,6 @@ void iwl_rx_statistics(struct iwl_priv *priv,
iwl_rx_calc_noise(priv);
queue_work(priv->workqueue, &priv->run_time_calib_work);
}
-
- iwl_leds_background(priv);
-
if (priv->cfg->ops->lib->temp_ops.temperature && change)
priv->cfg->ops->lib->temp_ops.temperature(priv);
}
@@ -878,6 +921,10 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb,
struct ieee80211_rx_status *stats)
{
+ struct sk_buff *skb;
+ int ret = 0;
+ __le16 fc = hdr->frame_control;
+
/* We only process data packets if the interface is open */
if (unlikely(!priv->is_open)) {
IWL_DEBUG_DROP_LIMIT(priv,
@@ -890,15 +937,43 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
return;
- /* Resize SKB from mac header to end of packet */
- skb_reserve(rxb->skb, (void *)hdr - (void *)rxb->skb->data);
- skb_put(rxb->skb, len);
+ skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC);
+ if (!skb) {
+ IWL_ERR(priv, "alloc_skb failed\n");
+ return;
+ }
+
+ skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len);
+
+ /* mac80211 currently doesn't support paged SKB. Convert it to
+ * linear SKB for management frame and data frame requires
+ * software decryption or software defragementation. */
+ if (ieee80211_is_mgmt(fc) ||
+ ieee80211_has_protected(fc) ||
+ ieee80211_has_morefrags(fc) ||
+ le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)
+ ret = skb_linearize(skb);
+ else
+ ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ?
+ 0 : -ENOMEM;
+
+ if (ret) {
+ kfree_skb(skb);
+ goto out;
+ }
+
+ /*
+ * XXX: We cannot touch the page and its virtual memory (hdr) after
+ * here. It might have already been freed by the above skb change.
+ */
+
+ iwl_update_stats(priv, false, fc, len);
+ memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
- iwl_update_stats(priv, false, hdr->frame_control, len);
- memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
- ieee80211_rx_irqsafe(priv->hw, rxb->skb);
- priv->alloc_rxb_skb--;
- rxb->skb = NULL;
+ ieee80211_rx(priv->hw, skb);
+ out:
+ priv->alloc_rxb_page--;
+ rxb->page = NULL;
}
/* This is necessary only for a number of statistics, see the caller. */
@@ -926,7 +1001,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
{
struct ieee80211_hdr *header;
struct ieee80211_rx_status rx_status;
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_rx_phy_res *phy_res;
__le32 rx_pkt_status;
struct iwl4965_rx_mpdu_res_start *amsdu;
@@ -1087,7 +1162,7 @@ EXPORT_SYMBOL(iwl_rx_reply_rx);
void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
priv->last_phy_res[0] = 1;
memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
sizeof(struct iwl_rx_phy_res));
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 4f3a108fa990..4fca65a2fe9c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -27,7 +27,6 @@
*****************************************************************************/
#include <linux/types.h>
#include <linux/etherdevice.h>
-#include <net/lib80211.h>
#include <net/mac80211.h>
#include "iwl-eeprom.h"
@@ -112,7 +111,7 @@ EXPORT_SYMBOL(iwl_scan_cancel_timeout);
static int iwl_send_scan_abort(struct iwl_priv *priv)
{
int ret = 0;
- struct iwl_rx_packet *res;
+ struct iwl_rx_packet *pkt;
struct iwl_host_cmd cmd = {
.id = REPLY_SCAN_ABORT_CMD,
.flags = CMD_WANT_SKB,
@@ -132,21 +131,21 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
return ret;
}
- res = (struct iwl_rx_packet *)cmd.reply_skb->data;
- if (res->u.status != CAN_ABORT_STATUS) {
+ 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", res->u.status);
+ 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);
}
- priv->alloc_rxb_skb--;
- dev_kfree_skb_any(cmd.reply_skb);
+ priv->alloc_rxb_page--;
+ free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
return ret;
}
@@ -156,7 +155,7 @@ static void iwl_rx_reply_scan(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_scanreq_notification *notif =
(struct iwl_scanreq_notification *)pkt->u.raw;
@@ -168,7 +167,7 @@ static void iwl_rx_reply_scan(struct iwl_priv *priv,
static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_scanstart_notification *notif =
(struct iwl_scanstart_notification *)pkt->u.raw;
priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
@@ -187,7 +186,7 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_scanresults_notification *notif =
(struct iwl_scanresults_notification *)pkt->u.raw;
@@ -214,7 +213,7 @@ 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 = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.c b/drivers/net/wireless/iwlwifi/iwl-spectrum.c
index 022bcf115731..1ea5cd345fe8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-spectrum.c
+++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.c
@@ -177,7 +177,7 @@ static int iwl_get_measurement(struct iwl_priv *priv,
static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
if (!report->state) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index c6633fec8216..dc74c16d36a8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -99,32 +99,25 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
static void iwl_add_sta_callback(struct iwl_priv *priv,
struct iwl_device_cmd *cmd,
- struct sk_buff *skb)
+ struct iwl_rx_packet *pkt)
{
- struct iwl_rx_packet *res = NULL;
struct iwl_addsta_cmd *addsta =
(struct iwl_addsta_cmd *)cmd->cmd.payload;
u8 sta_id = addsta->sta.sta_id;
- if (!skb) {
- IWL_ERR(priv, "Error: Response NULL in REPLY_ADD_STA.\n");
- return;
- }
-
- res = (struct iwl_rx_packet *)skb->data;
- if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
- res->hdr.flags);
+ pkt->hdr.flags);
return;
}
- switch (res->u.add_sta.status) {
+ switch (pkt->u.add_sta.status) {
case ADD_STA_SUCCESS_MSK:
iwl_sta_ucode_activate(priv, sta_id);
/* fall through */
default:
IWL_DEBUG_HC(priv, "Received REPLY_ADD_STA:(0x%08X)\n",
- res->u.add_sta.status);
+ pkt->u.add_sta.status);
break;
}
}
@@ -132,7 +125,7 @@ static void iwl_add_sta_callback(struct iwl_priv *priv,
int iwl_send_add_sta(struct iwl_priv *priv,
struct iwl_addsta_cmd *sta, u8 flags)
{
- struct iwl_rx_packet *res = NULL;
+ struct iwl_rx_packet *pkt = NULL;
int ret = 0;
u8 data[sizeof(*sta)];
struct iwl_host_cmd cmd = {
@@ -152,15 +145,15 @@ int iwl_send_add_sta(struct iwl_priv *priv,
if (ret || (flags & CMD_ASYNC))
return ret;
- res = (struct iwl_rx_packet *)cmd.reply_skb->data;
- if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ pkt = (struct iwl_rx_packet *)cmd.reply_page;
+ if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
- res->hdr.flags);
+ pkt->hdr.flags);
ret = -EIO;
}
if (ret == 0) {
- switch (res->u.add_sta.status) {
+ switch (pkt->u.add_sta.status) {
case ADD_STA_SUCCESS_MSK:
iwl_sta_ucode_activate(priv, sta->sta.sta_id);
IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
@@ -172,8 +165,8 @@ int iwl_send_add_sta(struct iwl_priv *priv,
}
}
- priv->alloc_rxb_skb--;
- dev_kfree_skb_any(cmd.reply_skb);
+ priv->alloc_rxb_page--;
+ free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
return ret;
}
@@ -324,26 +317,19 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
static void iwl_remove_sta_callback(struct iwl_priv *priv,
struct iwl_device_cmd *cmd,
- struct sk_buff *skb)
+ struct iwl_rx_packet *pkt)
{
- struct iwl_rx_packet *res = NULL;
struct iwl_rem_sta_cmd *rm_sta =
- (struct iwl_rem_sta_cmd *)cmd->cmd.payload;
+ (struct iwl_rem_sta_cmd *)cmd->cmd.payload;
const char *addr = rm_sta->addr;
- if (!skb) {
- IWL_ERR(priv, "Error: Response NULL in REPLY_REMOVE_STA.\n");
- return;
- }
-
- res = (struct iwl_rx_packet *)skb->data;
- if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
- res->hdr.flags);
+ pkt->hdr.flags);
return;
}
- switch (res->u.rem_sta.status) {
+ switch (pkt->u.rem_sta.status) {
case REM_STA_SUCCESS_MSK:
iwl_sta_ucode_deactivate(priv, addr);
break;
@@ -356,7 +342,7 @@ static void iwl_remove_sta_callback(struct iwl_priv *priv,
static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
u8 flags)
{
- struct iwl_rx_packet *res = NULL;
+ struct iwl_rx_packet *pkt;
int ret;
struct iwl_rem_sta_cmd rm_sta_cmd;
@@ -381,15 +367,15 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
if (ret || (flags & CMD_ASYNC))
return ret;
- res = (struct iwl_rx_packet *)cmd.reply_skb->data;
- if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ pkt = (struct iwl_rx_packet *)cmd.reply_page;
+ if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
- res->hdr.flags);
+ pkt->hdr.flags);
ret = -EIO;
}
if (!ret) {
- switch (res->u.rem_sta.status) {
+ switch (pkt->u.rem_sta.status) {
case REM_STA_SUCCESS_MSK:
iwl_sta_ucode_deactivate(priv, addr);
IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
@@ -401,8 +387,8 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
}
}
- priv->alloc_rxb_skb--;
- dev_kfree_skb_any(cmd.reply_skb);
+ priv->alloc_rxb_page--;
+ free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
return ret;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index fb9bcfa6d947..2afa003939a6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -132,7 +132,7 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
struct iwl_tx_queue *txq = &priv->txq[txq_id];
struct iwl_queue *q = &txq->q;
struct pci_dev *dev = priv->pci_dev;
- int i, len;
+ int i;
if (q->n_bd == 0)
return;
@@ -142,8 +142,6 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd))
priv->cfg->ops->lib->txq_free_tfd(priv, txq);
- len = sizeof(struct iwl_device_cmd) * q->n_window;
-
/* De-alloc array of command/tx buffers */
for (i = 0; i < TFD_TX_CMD_SLOTS; i++)
kfree(txq->cmd[i]);
@@ -181,14 +179,11 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
struct iwl_queue *q = &txq->q;
struct pci_dev *dev = priv->pci_dev;
- int i, len;
+ int i;
if (q->n_bd == 0)
return;
- len = sizeof(struct iwl_device_cmd) * q->n_window;
- len += IWL_MAX_SCAN_SIZE;
-
/* De-alloc array of command/tx buffers */
for (i = 0; i <= TFD_CMD_SLOTS; i++)
kfree(txq->cmd[i]);
@@ -406,15 +401,19 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
int txq_id;
/* Tx queues */
- for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
- if (txq_id == IWL_CMD_QUEUE_NUM)
- iwl_cmd_queue_free(priv);
- else
- iwl_tx_queue_free(priv, txq_id);
-
+ if (priv->txq)
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num;
+ txq_id++)
+ if (txq_id == IWL_CMD_QUEUE_NUM)
+ iwl_cmd_queue_free(priv);
+ else
+ iwl_tx_queue_free(priv, txq_id);
iwl_free_dma_ptr(priv, &priv->kw);
iwl_free_dma_ptr(priv, &priv->scd_bc_tbls);
+
+ /* free tx queue structure */
+ iwl_free_txq_mem(priv);
}
EXPORT_SYMBOL(iwl_hw_txq_ctx_free);
@@ -446,6 +445,12 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
IWL_ERR(priv, "Keep Warm allocation failed\n");
goto error_kw;
}
+
+ /* allocate tx queue structure */
+ ret = iwl_alloc_txq_mem(priv);
+ if (ret)
+ goto error;
+
spin_lock_irqsave(&priv->lock, flags);
/* Turn off all Tx DMA fifos */
@@ -582,9 +587,7 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv,
u8 rate_plcp;
/* Set retry limit on DATA packets and Probe Responses*/
- if (priv->data_retry_limit != -1)
- data_retry_limit = priv->data_retry_limit;
- else if (ieee80211_is_probe_resp(fc))
+ if (ieee80211_is_probe_resp(fc))
data_retry_limit = 3;
else
data_retry_limit = IWL_DEFAULT_TX_RETRY;
@@ -710,7 +713,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
dma_addr_t phys_addr;
dma_addr_t txcmd_phys;
dma_addr_t scratch_phys;
- u16 len, len_org;
+ u16 len, len_org, firstlen, secondlen;
u16 seq_number = 0;
__le16 fc;
u8 hdr_len;
@@ -843,7 +846,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
sizeof(struct iwl_cmd_header) + hdr_len;
len_org = len;
- len = (len + 3) & ~3;
+ firstlen = len = (len + 3) & ~3;
if (len_org != len)
len_org = 1;
@@ -877,7 +880,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Set up TFD's 2nd entry to point directly to remainder of skb,
* if any (802.11 null frames have no payload). */
- len = skb->len - hdr_len;
+ secondlen = len = skb->len - hdr_len;
if (len) {
phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
len, PCI_DMA_TODEVICE);
@@ -911,6 +914,12 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys,
len, PCI_DMA_BIDIRECTIONAL);
+ trace_iwlwifi_dev_tx(priv,
+ &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr],
+ sizeof(struct iwl_tfd),
+ &out_cmd->hdr, firstlen,
+ skb->data + hdr_len, secondlen);
+
/* Tell device the write index *just past* this latest filled TFD */
q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
ret = iwl_txq_update_write_ptr(priv, txq);
@@ -970,13 +979,19 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
!(cmd->flags & CMD_SIZE_HUGE));
- if (iwl_is_rfkill(priv)) {
- IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n");
+ if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) {
+ IWL_DEBUG_INFO(priv, "Not sending command - RF/CT KILL\n");
return -EIO;
}
if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
IWL_ERR(priv, "No space for Tx\n");
+ if (iwl_within_ct_kill_margin(priv))
+ iwl_tt_enter_ct_kill(priv);
+ else {
+ IWL_ERR(priv, "Restarting adapter due to queue full\n");
+ queue_work(priv->workqueue, &priv->restart);
+ }
return -ENOSPC;
}
@@ -1039,6 +1054,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
pci_unmap_addr_set(out_meta, mapping, phys_addr);
pci_unmap_len_set(out_meta, len, fix_size);
+ trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags);
+
priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
phys_addr, fix_size, 1,
U32_PAD(cmd->len));
@@ -1132,7 +1149,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id,
*/
void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
u16 sequence = le16_to_cpu(pkt->hdr.sequence);
int txq_id = SEQ_TO_QUEUE(sequence);
int index = SEQ_TO_INDEX(sequence);
@@ -1159,10 +1176,10 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
/* Input error checking is done when commands are added to queue. */
if (meta->flags & CMD_WANT_SKB) {
- meta->source->reply_skb = rxb->skb;
- rxb->skb = NULL;
+ meta->source->reply_page = (unsigned long)rxb_addr(rxb);
+ rxb->page = NULL;
} else if (meta->callback)
- meta->callback(priv, cmd, rxb->skb);
+ meta->callback(priv, cmd, pkt);
iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index);
@@ -1401,7 +1418,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv,
info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]);
memset(&info->status, 0, sizeof(info->status));
- info->flags = IEEE80211_TX_STAT_ACK;
+ info->flags |= IEEE80211_TX_STAT_ACK;
info->flags |= IEEE80211_TX_STAT_AMPDU;
info->status.ampdu_ack_map = successes;
info->status.ampdu_ack_len = agg->frame_count;
@@ -1421,7 +1438,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv,
void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
struct iwl_tx_queue *txq = NULL;
struct iwl_ht_agg *agg;
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index d00a80334095..c3b06696dcef 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -42,7 +42,6 @@
#include <linux/if_arp.h>
#include <net/ieee80211_radiotap.h>
-#include <net/lib80211.h>
#include <net/mac80211.h>
#include <asm/div64.h>
@@ -90,7 +89,6 @@ MODULE_LICENSE("GPL");
/* module parameters */
struct iwl_mod_params iwl3945_mod_params = {
- .num_of_queues = IWL39_NUM_QUEUES, /* Not used */
.sw_crypto = 1,
.restart_fw = 1,
/* the rest are 0 by default */
@@ -368,13 +366,13 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
struct sk_buff *skb_frag,
int sta_id)
{
- struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
+ 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->sec_ctl = TX_CMD_SEC_CCM;
- memcpy(tx->key, keyinfo->key, keyinfo->keylen);
+ 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;
@@ -382,13 +380,13 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
break;
case ALG_WEP:
- tx->sec_ctl = TX_CMD_SEC_WEP |
+ 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->sec_ctl |= TX_CMD_SEC_KEY128;
+ tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
- memcpy(&tx->key[3], keyinfo->key, keyinfo->keylen);
+ memcpy(&tx_cmd->key[3], keyinfo->key, keyinfo->keylen);
IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
"with key %d\n", info->control.hw_key->hw_key_idx);
@@ -408,12 +406,11 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr, u8 std_id)
{
- struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
- __le32 tx_flags = tx->tx_flags;
+ struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
+ __le32 tx_flags = tx_cmd->tx_flags;
__le16 fc = hdr->frame_control;
- u8 rc_flags = info->control.rates[0].flags;
- tx->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+ tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
tx_flags |= TX_CMD_FLG_ACK_MSK;
if (ieee80211_is_mgmt(fc))
@@ -426,25 +423,19 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
}
- tx->sta_id = std_id;
+ tx_cmd->sta_id = std_id;
if (ieee80211_has_morefrags(fc))
tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
if (ieee80211_is_data_qos(fc)) {
u8 *qc = ieee80211_get_qos_ctl(hdr);
- tx->tid_tspec = qc[0] & 0xf;
+ tx_cmd->tid_tspec = qc[0] & 0xf;
tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
} else {
tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
}
- if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
- tx_flags |= TX_CMD_FLG_RTS_MSK;
- tx_flags &= ~TX_CMD_FLG_CTS_MSK;
- } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
- tx_flags &= ~TX_CMD_FLG_RTS_MSK;
- tx_flags |= TX_CMD_FLG_CTS_MSK;
- }
+ priv->cfg->ops->utils->rts_tx_cmd_flag(info, &tx_flags);
if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
@@ -452,19 +443,16 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
if (ieee80211_is_mgmt(fc)) {
if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc))
- tx->timeout.pm_frame_timeout = cpu_to_le16(3);
+ tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(3);
else
- tx->timeout.pm_frame_timeout = cpu_to_le16(2);
+ tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2);
} else {
- tx->timeout.pm_frame_timeout = 0;
-#ifdef CONFIG_IWLWIFI_LEDS
- priv->rxtxpackets += le16_to_cpu(cmd->cmd.tx.len);
-#endif
+ tx_cmd->timeout.pm_frame_timeout = 0;
}
- tx->driver_txop = 0;
- tx->tx_flags = tx_flags;
- tx->next_frame_len = 0;
+ tx_cmd->driver_txop = 0;
+ tx_cmd->tx_flags = tx_flags;
+ tx_cmd->next_frame_len = 0;
}
/*
@@ -474,7 +462,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct iwl3945_tx_cmd *tx;
+ struct iwl3945_tx_cmd *tx_cmd;
struct iwl_tx_queue *txq = NULL;
struct iwl_queue *q = NULL;
struct iwl_device_cmd *out_cmd;
@@ -573,9 +561,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Init first empty entry in queue's array of Tx/cmd buffers */
out_cmd = txq->cmd[idx];
out_meta = &txq->meta[idx];
- tx = (struct iwl3945_tx_cmd *)out_cmd->cmd.payload;
+ tx_cmd = (struct iwl3945_tx_cmd *)out_cmd->cmd.payload;
memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
- memset(tx, 0, sizeof(*tx));
+ memset(tx_cmd, 0, sizeof(*tx_cmd));
/*
* Set up the Tx-command (not MAC!) header.
@@ -588,7 +576,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
INDEX_TO_SEQ(q->write_ptr)));
/* Copy MAC header from skb into command buffer */
- memcpy(tx->hdr, hdr, hdr_len);
+ memcpy(tx_cmd->hdr, hdr, hdr_len);
if (info->control.hw_key)
@@ -602,12 +590,12 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Total # bytes to be transmitted */
len = (u16)skb->len;
- tx->len = cpu_to_le16(len);
+ tx_cmd->len = cpu_to_le16(len);
iwl_dbg_log_tx_data_frame(priv, len, hdr);
iwl_update_stats(priv, true, fc, len);
- tx->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
- tx->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
+ tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
+ tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
if (!ieee80211_has_morefrags(hdr->frame_control)) {
txq->need_update = 1;
@@ -620,9 +608,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n",
le16_to_cpu(out_cmd->hdr.sequence));
- IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx->tx_flags));
- iwl_print_hex_dump(priv, IWL_DL_TX, tx, sizeof(*tx));
- iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx->hdr,
+ IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags));
+ iwl_print_hex_dump(priv, IWL_DL_TX, tx_cmd, sizeof(*tx_cmd));
+ iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr,
ieee80211_hdrlen(fc));
/*
@@ -758,7 +746,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
u8 type)
{
struct iwl_spectrum_cmd spectrum;
- struct iwl_rx_packet *res;
+ struct iwl_rx_packet *pkt;
struct iwl_host_cmd cmd = {
.id = REPLY_SPECTRUM_MEASUREMENT_CMD,
.data = (void *)&spectrum,
@@ -803,18 +791,18 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
if (rc)
return rc;
- res = (struct iwl_rx_packet *)cmd.reply_skb->data;
- if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ pkt = (struct iwl_rx_packet *)cmd.reply_page;
+ if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n");
rc = -EIO;
}
- spectrum_resp_status = le16_to_cpu(res->u.spectrum.status);
+ spectrum_resp_status = le16_to_cpu(pkt->u.spectrum.status);
switch (spectrum_resp_status) {
case 0: /* Command will be handled */
- if (res->u.spectrum.id != 0xff) {
+ if (pkt->u.spectrum.id != 0xff) {
IWL_DEBUG_INFO(priv, "Replaced existing measurement: %d\n",
- res->u.spectrum.id);
+ pkt->u.spectrum.id);
priv->measurement_status &= ~MEASUREMENT_READY;
}
priv->measurement_status |= MEASUREMENT_ACTIVE;
@@ -826,7 +814,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
break;
}
- dev_kfree_skb_any(cmd.reply_skb);
+ free_pages(cmd.reply_page, priv->hw_params.rx_page_order);
return rc;
}
@@ -835,7 +823,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
static void iwl3945_rx_reply_alive(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_alive_resp *palive;
struct delayed_work *pwork;
@@ -872,7 +860,7 @@ static void iwl3945_rx_reply_add_sta(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
- struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
#endif
IWL_DEBUG_RX(priv, "Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status);
@@ -908,7 +896,7 @@ 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 = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl3945_beacon_notif *beacon = &(pkt->u.beacon_status);
u8 rate = beacon->beacon_notify_hdr.rate;
@@ -931,7 +919,7 @@ static void iwl3945_rx_beacon_notif(struct iwl_priv *priv,
static void iwl3945_rx_card_state_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
- struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
unsigned long status = priv->status;
@@ -1095,7 +1083,7 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv)
list_del(element);
/* Point to Rx buffer via next RBD in circular buffer */
- rxq->bd[rxq->write] = iwl3945_dma_addr2rbd_ptr(priv, rxb->real_dma_addr);
+ rxq->bd[rxq->write] = iwl3945_dma_addr2rbd_ptr(priv, rxb->page_dma);
rxq->queue[rxq->write] = rxb;
rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
rxq->free_count--;
@@ -1135,8 +1123,9 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
struct iwl_rx_queue *rxq = &priv->rxq;
struct list_head *element;
struct iwl_rx_mem_buffer *rxb;
- struct sk_buff *skb;
+ struct page *page;
unsigned long flags;
+ gfp_t gfp_mask = priority;
while (1) {
spin_lock_irqsave(&rxq->lock, flags);
@@ -1148,10 +1137,14 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
spin_unlock_irqrestore(&rxq->lock, flags);
if (rxq->free_count > RX_LOW_WATERMARK)
- priority |= __GFP_NOWARN;
+ gfp_mask |= __GFP_NOWARN;
+
+ if (priv->hw_params.rx_page_order > 0)
+ gfp_mask |= __GFP_COMP;
+
/* Alloc a new receive buffer */
- skb = alloc_skb(priv->hw_params.rx_buf_size, priority);
- if (!skb) {
+ page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order);
+ if (!page) {
if (net_ratelimit())
IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n");
if ((rxq->free_count <= RX_LOW_WATERMARK) &&
@@ -1168,7 +1161,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
spin_lock_irqsave(&rxq->lock, flags);
if (list_empty(&rxq->rx_used)) {
spin_unlock_irqrestore(&rxq->lock, flags);
- dev_kfree_skb_any(skb);
+ __free_pages(page, priv->hw_params.rx_page_order);
return;
}
element = rxq->rx_used.next;
@@ -1176,26 +1169,18 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
list_del(element);
spin_unlock_irqrestore(&rxq->lock, flags);
- rxb->skb = skb;
-
- /* If radiotap head is required, reserve some headroom here.
- * The physical head count is a variable rx_stats->phy_count.
- * We reserve 4 bytes here. Plus these extra bytes, the
- * headroom of the physical head should be enough for the
- * radiotap head that iwl3945 supported. See iwl3945_rt.
- */
- skb_reserve(rxb->skb, 4);
-
+ rxb->page = page;
/* Get physical address of RB/SKB */
- rxb->real_dma_addr = pci_map_single(priv->pci_dev,
- rxb->skb->data,
- priv->hw_params.rx_buf_size,
- PCI_DMA_FROMDEVICE);
+ rxb->page_dma = pci_map_page(priv->pci_dev, page, 0,
+ PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
spin_lock_irqsave(&rxq->lock, flags);
+
list_add_tail(&rxb->list, &rxq->rx_free);
- priv->alloc_rxb_skb++;
rxq->free_count++;
+ priv->alloc_rxb_page++;
+
spin_unlock_irqrestore(&rxq->lock, flags);
}
}
@@ -1211,14 +1196,14 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
/* In the reset function, these buffers may have been allocated
* to an SKB, so we need to unmap and free potential storage */
- if (rxq->pool[i].skb != NULL) {
- pci_unmap_single(priv->pci_dev,
- rxq->pool[i].real_dma_addr,
- priv->hw_params.rx_buf_size,
- PCI_DMA_FROMDEVICE);
- priv->alloc_rxb_skb--;
- dev_kfree_skb(rxq->pool[i].skb);
- rxq->pool[i].skb = NULL;
+ if (rxq->pool[i].page != NULL) {
+ pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
+ PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
+ priv->alloc_rxb_page--;
+ __free_pages(rxq->pool[i].page,
+ priv->hw_params.rx_page_order);
+ rxq->pool[i].page = NULL;
}
list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
}
@@ -1226,8 +1211,8 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
/* Set us so that we have processed and used all buffers, but have
* not restocked the Rx queue with fresh buffers */
rxq->read = rxq->write = 0;
- rxq->free_count = 0;
rxq->write_actual = 0;
+ rxq->free_count = 0;
spin_unlock_irqrestore(&rxq->lock, flags);
}
@@ -1260,12 +1245,14 @@ static void iwl3945_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rx
{
int i;
for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
- if (rxq->pool[i].skb != NULL) {
- pci_unmap_single(priv->pci_dev,
- rxq->pool[i].real_dma_addr,
- priv->hw_params.rx_buf_size,
- PCI_DMA_FROMDEVICE);
- dev_kfree_skb(rxq->pool[i].skb);
+ if (rxq->pool[i].page != NULL) {
+ pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
+ PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
+ __free_pages(rxq->pool[i].page,
+ priv->hw_params.rx_page_order);
+ rxq->pool[i].page = NULL;
+ priv->alloc_rxb_page--;
}
}
@@ -1381,7 +1368,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
i = rxq->read;
/* calculate total frames need to be restock after handling RX */
- total_empty = r - priv->rxq.write_actual;
+ total_empty = r - rxq->write_actual;
if (total_empty < 0)
total_empty += RX_QUEUE_SIZE;
@@ -1401,10 +1388,13 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
rxq->queue[i] = NULL;
- pci_unmap_single(priv->pci_dev, rxb->real_dma_addr,
- priv->hw_params.rx_buf_size,
- PCI_DMA_FROMDEVICE);
- pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ pci_unmap_page(priv->pci_dev, rxb->page_dma,
+ PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
+ pkt = rxb_addr(rxb);
+
+ trace_iwlwifi_dev_rx(priv, pkt,
+ le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
/* Reclaim a command buffer only if this packet is a response
* to a (driver-originated) command.
@@ -1422,44 +1412,55 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
if (priv->rx_handlers[pkt->hdr.cmd]) {
IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, i,
get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
- priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
priv->isr_stats.rx_handlers[pkt->hdr.cmd]++;
+ priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
} else {
/* No handling needed */
- IWL_DEBUG_RX(priv, "r %d i %d No handler needed for %s, 0x%02x\n",
+ IWL_DEBUG_RX(priv,
+ "r %d i %d No handler needed for %s, 0x%02x\n",
r, i, get_cmd_string(pkt->hdr.cmd),
pkt->hdr.cmd);
}
+ /*
+ * XXX: After here, we should always check rxb->page
+ * against NULL before touching it or its virtual
+ * memory (pkt). Because some rx_handler might have
+ * already taken or freed the pages.
+ */
+
if (reclaim) {
- /* Invoke any callbacks, transfer the skb to caller, and
- * fire off the (possibly) blocking iwl_send_cmd()
+ /* Invoke any callbacks, transfer the buffer to caller,
+ * and fire off the (possibly) blocking iwl_send_cmd()
* as we reclaim the driver command queue */
- if (rxb && rxb->skb)
+ if (rxb->page)
iwl_tx_cmd_complete(priv, rxb);
else
IWL_WARN(priv, "Claim null rxb?\n");
}
- /* For now we just don't re-use anything. We can tweak this
- * later to try and re-use notification packets and SKBs that
- * fail to Rx correctly */
- if (rxb->skb != NULL) {
- priv->alloc_rxb_skb--;
- dev_kfree_skb_any(rxb->skb);
- rxb->skb = NULL;
- }
-
+ /* Reuse the page if possible. For notification packets and
+ * SKBs that fail to Rx correctly, add them back into the
+ * rx_free list for reuse later. */
spin_lock_irqsave(&rxq->lock, flags);
- list_add_tail(&rxb->list, &priv->rxq.rx_used);
+ if (rxb->page != NULL) {
+ rxb->page_dma = pci_map_page(priv->pci_dev, rxb->page,
+ 0, PAGE_SIZE << priv->hw_params.rx_page_order,
+ PCI_DMA_FROMDEVICE);
+ list_add_tail(&rxb->list, &rxq->rx_free);
+ rxq->free_count++;
+ } else
+ list_add_tail(&rxb->list, &rxq->rx_used);
+
spin_unlock_irqrestore(&rxq->lock, flags);
+
i = (i + 1) & RX_QUEUE_MASK;
/* If there are a lot of unused frames,
* restock the Rx queue so ucode won't assert. */
if (fill_rx) {
count++;
if (count >= 8) {
- priv->rxq.read = i;
+ rxq->read = i;
iwl3945_rx_replenish_now(priv);
count = 0;
}
@@ -1467,7 +1468,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
}
/* Backtrack one entry */
- priv->rxq.read = i;
+ rxq->read = i;
if (fill_rx)
iwl3945_rx_replenish_now(priv);
else
@@ -1551,8 +1552,9 @@ void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
"%-13s (#%d) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n",
desc_lookup(desc), desc, time, blink1, blink2,
ilink1, ilink2, data1);
+ trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, 0,
+ 0, blink1, blink2, ilink1, ilink2);
}
-
}
#define EVENT_START_OFFSET (6 * sizeof(u32))
@@ -1592,10 +1594,12 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
if (mode == 0) {
/* data, ev */
IWL_ERR(priv, "0x%08x\t%04u\n", time, ev);
+ trace_iwlwifi_dev_ucode_event(priv, 0, time, ev);
} else {
data = iwl_read_targ_mem(priv, ptr);
ptr += sizeof(u32);
IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", time, data, ev);
+ trace_iwlwifi_dev_ucode_event(priv, time, data, ev);
}
}
}
@@ -1685,6 +1689,8 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
}
#endif
+ spin_unlock_irqrestore(&priv->lock, flags);
+
/* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
* atomic, make sure that inta covers all the interrupts that
* we've discovered, even if FH interrupt came in just after
@@ -1706,8 +1712,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
handled |= CSR_INT_BIT_HW_ERR;
- spin_unlock_irqrestore(&priv->lock, flags);
-
return;
}
@@ -1799,7 +1803,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
"flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
}
#endif
- spin_unlock_irqrestore(&priv->lock, flags);
}
static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
@@ -2479,7 +2482,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
iwl3945_reg_txpower_periodic(priv);
- iwl3945_led_register(priv);
+ iwl_leds_init(priv);
IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
set_bit(STATUS_READY, &priv->status);
@@ -2517,7 +2520,6 @@ static void __iwl3945_down(struct iwl_priv *priv)
if (!exit_pending)
set_bit(STATUS_EXIT_PENDING, &priv->status);
- iwl3945_led_unregister(priv);
iwl_clear_stations_table(priv);
/* Unblock any waiting calls */
@@ -2563,11 +2565,6 @@ static void __iwl3945_down(struct iwl_priv *priv)
test_bit(STATUS_EXIT_PENDING, &priv->status) <<
STATUS_EXIT_PENDING;
- priv->cfg->ops->lib->apm_ops.reset(priv);
- spin_lock_irqsave(&priv->lock, flags);
- iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
- spin_unlock_irqrestore(&priv->lock, flags);
-
iwl3945_hw_txq_ctx_stop(priv);
iwl3945_hw_rxq_stop(priv);
@@ -2576,10 +2573,8 @@ static void __iwl3945_down(struct iwl_priv *priv)
udelay(5);
- if (exit_pending)
- priv->cfg->ops->lib->apm_ops.stop(priv);
- else
- priv->cfg->ops->lib->apm_ops.reset(priv);
+ /* Stop the device, and put it in low power state */
+ priv->cfg->ops->lib->apm_ops.stop(priv);
exit:
memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
@@ -2724,19 +2719,34 @@ static void iwl3945_bg_alive_start(struct work_struct *data)
mutex_unlock(&priv->mutex);
}
+/*
+ * 3945 cannot interrupt driver when hardware rf kill switch toggles;
+ * driver must poll CSR_GP_CNTRL_REG register for change. This register
+ * *is* readable even when device has been SW_RESET into low power mode
+ * (e.g. during RF KILL).
+ */
static void iwl3945_rfkill_poll(struct work_struct *data)
{
struct iwl_priv *priv =
container_of(data, struct iwl_priv, rfkill_poll.work);
+ bool old_rfkill = test_bit(STATUS_RF_KILL_HW, &priv->status);
+ bool new_rfkill = !(iwl_read32(priv, CSR_GP_CNTRL)
+ & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
- if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
- clear_bit(STATUS_RF_KILL_HW, &priv->status);
- else
- set_bit(STATUS_RF_KILL_HW, &priv->status);
+ if (new_rfkill != old_rfkill) {
+ if (new_rfkill)
+ set_bit(STATUS_RF_KILL_HW, &priv->status);
+ else
+ clear_bit(STATUS_RF_KILL_HW, &priv->status);
- wiphy_rfkill_set_hw_state(priv->hw->wiphy,
- test_bit(STATUS_RF_KILL_HW, &priv->status));
+ wiphy_rfkill_set_hw_state(priv->hw->wiphy, new_rfkill);
+ IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n",
+ new_rfkill ? "disable radio" : "enable radio");
+ }
+
+ /* Keep this running, even if radio now enabled. This will be
+ * cancelled in mac_start() if system decides to start again */
queue_delayed_work(priv->workqueue, &priv->rfkill_poll,
round_jiffies_relative(2 * HZ));
@@ -3152,6 +3162,8 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw)
* no need to poll the killswitch state anymore */
cancel_delayed_work(&priv->rfkill_poll);
+ iwl_led_start(priv);
+
priv->is_open = 1;
IWL_DEBUG_MAC80211(priv, "leave\n");
return 0;
@@ -3795,7 +3807,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
/* Clear the driver's (not device's) station table */
iwl_clear_stations_table(priv);
- priv->data_retry_limit = -1;
priv->ieee_channels = NULL;
priv->ieee_rates = NULL;
priv->band = IEEE80211_BAND_2GHZ;
@@ -4054,6 +4065,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
&priv->bands[IEEE80211_BAND_2GHZ].channels[5]);
iwl3945_setup_deferred_work(priv);
iwl3945_setup_rx_handlers(priv);
+ iwl_power_initialize(priv);
/*********************************
* 8. Setup and Register mac80211
@@ -4124,6 +4136,15 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
iwl3945_down(priv);
}
+ /*
+ * Make sure device is reset to low power before unloading driver.
+ * This may be redundant with iwl_down(), but there are paths to
+ * run iwl_down() without calling apm_ops.stop(), and there are
+ * 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);
+
/* make sure we flush any pending irq or
* tasklet for the driver
*/
@@ -4226,18 +4247,19 @@ static void __exit iwl3945_exit(void)
MODULE_FIRMWARE(IWL3945_MODULE_FIRMWARE(IWL3945_UCODE_API_MAX));
-module_param_named(antenna, iwl3945_mod_params.antenna, int, 0444);
+module_param_named(antenna, iwl3945_mod_params.antenna, int, S_IRUGO);
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
-module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, 0444);
+module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, S_IRUGO);
MODULE_PARM_DESC(swcrypto,
"using software crypto (default 1 [software])\n");
#ifdef CONFIG_IWLWIFI_DEBUG
-module_param_named(debug, iwl_debug_level, uint, 0644);
+module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "debug output mask");
#endif
-module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, 0444);
+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_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, 0444);
+module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, S_IRUGO);
MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error");
module_exit(iwl3945_exit);
diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig
index c25a04371ca8..9606b3100fde 100644
--- a/drivers/net/wireless/iwmc3200wifi/Kconfig
+++ b/drivers/net/wireless/iwmc3200wifi/Kconfig
@@ -3,6 +3,7 @@ config IWM
depends on MMC && WLAN_80211 && EXPERIMENTAL
depends on CFG80211
select FW_LOADER
+ select IWMC3200TOP
help
The Intel Wireless Multicomm 3200 hardware is a combo
card with GPS, Bluetooth, WiMax and 802.11 radios. It
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index f3c55658225b..2e00a4b389e6 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -405,39 +405,21 @@ static int iwm_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
{
struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
struct ieee80211_channel *chan = params->channel;
- struct cfg80211_bss *bss;
if (!test_bit(IWM_STATUS_READY, &iwm->status))
return -EIO;
- /* UMAC doesn't support creating IBSS network with specified bssid.
- * This should be removed after we have join only mode supported. */
+ /* UMAC doesn't support creating or joining an IBSS network
+ * with specified bssid. */
if (params->bssid)
return -EOPNOTSUPP;
- bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
- params->ssid, params->ssid_len);
- if (!bss) {
- iwm_scan_one_ssid(iwm, params->ssid, params->ssid_len);
- schedule_timeout_interruptible(2 * HZ);
- bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
- params->ssid, params->ssid_len);
- }
- /* IBSS join only mode is not supported by UMAC ATM */
- if (bss) {
- cfg80211_put_bss(bss);
- return -EOPNOTSUPP;
- }
-
iwm->channel = ieee80211_frequency_to_channel(chan->center_freq);
iwm->umac_profile->ibss.band = chan->band;
iwm->umac_profile->ibss.channel = iwm->channel;
iwm->umac_profile->ssid.ssid_len = params->ssid_len;
memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len);
- if (params->bssid)
- memcpy(&iwm->umac_profile->bssid[0], params->bssid, ETH_ALEN);
-
return iwm_send_mlme_profile(iwm);
}
@@ -490,12 +472,12 @@ static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version)
return 0;
}
+ if (wpa_version & NL80211_WPA_VERSION_1)
+ iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
+
if (wpa_version & NL80211_WPA_VERSION_2)
iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
- if (wpa_version & NL80211_WPA_VERSION_1)
- iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK;
-
return 0;
}
@@ -646,6 +628,13 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
iwm->default_key = sme->key_idx;
}
+ /* WPA and open AUTH type from wpa_s means WPS (a.k.a. WSC) */
+ if ((iwm->umac_profile->sec.flags &
+ (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) &&
+ iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN) {
+ iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WSC_ON_MSK;
+ }
+
ret = iwm_send_mlme_profile(iwm);
if (iwm->umac_profile->sec.auth_type != UMAC_AUTH_TYPE_LEGACY_PSK ||
@@ -682,9 +671,19 @@ static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
enum tx_power_setting type, int dbm)
{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+ int ret;
+
switch (type) {
case TX_POWER_AUTOMATIC:
return 0;
+ case TX_POWER_FIXED:
+ ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+ CFG_TX_PWR_LIMIT_USR, dbm * 2);
+ if (ret < 0)
+ return ret;
+
+ return iwm_tx_power_trigger(iwm);
default:
return -EOPNOTSUPP;
}
@@ -696,7 +695,7 @@ static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
{
struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
- *dbm = iwm->txpower;
+ *dbm = iwm->txpower >> 1;
return 0;
}
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c
index 84158b6d35d8..7e12438551ba 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.c
+++ b/drivers/net/wireless/iwmc3200wifi/commands.c
@@ -77,6 +77,11 @@ int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
int ret;
u8 oid = hdr->oid;
+ if (!test_bit(IWM_STATUS_READY, &iwm->status)) {
+ IWM_ERR(iwm, "Interface is not ready yet");
+ return -EAGAIN;
+ }
+
umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER;
umac_cmd.resp = resp;
@@ -275,6 +280,17 @@ int iwm_send_calib_results(struct iwm_priv *iwm)
return ret;
}
+int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit)
+{
+ struct iwm_ct_kill_cfg_cmd cmd;
+
+ cmd.entry_threshold = entry;
+ cmd.exit_threshold = exit;
+
+ return iwm_send_lmac_ptrough_cmd(iwm, REPLY_CT_KILL_CONFIG_CMD, &cmd,
+ sizeof(struct iwm_ct_kill_cfg_cmd), 0);
+}
+
int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp)
{
struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
@@ -778,11 +794,24 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
return ret;
ret = wait_event_interruptible_timeout(iwm->mlme_queue,
- (iwm->umac_profile_active == 0), 2 * HZ);
+ (iwm->umac_profile_active == 0), 5 * HZ);
return ret ? 0 : -EBUSY;
}
+int iwm_tx_power_trigger(struct iwm_priv *iwm)
+{
+ struct iwm_umac_pwr_trigger pwr_trigger;
+
+ pwr_trigger.hdr.oid = UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER;
+ pwr_trigger.hdr.buf_size =
+ cpu_to_le16(sizeof(struct iwm_umac_pwr_trigger) -
+ sizeof(struct iwm_umac_wifi_if));
+
+
+ return iwm_send_wifi_if_cmd(iwm, &pwr_trigger, sizeof(pwr_trigger), 1);
+}
+
int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags)
{
struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h
index e24d5b633997..b36be2b23a3c 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.h
+++ b/drivers/net/wireless/iwmc3200wifi/commands.h
@@ -102,7 +102,6 @@ enum {
CFG_SCAN_NUM_PASSIVE_CHAN_PER_PARTIAL_SCAN,
CFG_TLC_SUPPORTED_TX_HT_RATES,
CFG_TLC_SUPPORTED_TX_RATES,
- CFG_TLC_VALID_ANTENNA,
CFG_TLC_SPATIAL_STREAM_SUPPORTED,
CFG_TLC_RETRY_PER_RATE,
CFG_TLC_RETRY_PER_HT_RATE,
@@ -136,6 +135,10 @@ enum {
CFG_TLC_RENEW_ADDBA_DELAY,
CFG_TLC_NUM_OF_MULTISEC_TO_COUN_LOAD,
CFG_TLC_IS_STABLE_IN_HT,
+ CFG_TLC_SR_SIC_1ST_FAIL,
+ CFG_TLC_SR_SIC_1ST_PASS,
+ CFG_TLC_SR_SIC_TOTAL_FAIL,
+ CFG_TLC_SR_SIC_TOTAL_PASS,
CFG_RLC_CHAIN_CTRL,
CFG_TRK_TABLE_OP_MODE,
CFG_TRK_TABLE_RSSI_THRESHOLD,
@@ -147,6 +150,58 @@ enum {
CFG_MLME_DBG_NOTIF_BLOCK,
CFG_BT_OFF_BECONS_INTERVALS,
CFG_BT_FRAG_DURATION,
+ CFG_ACTIVE_CHAINS,
+ CFG_CALIB_CTRL,
+ CFG_CAPABILITY_SUPPORTED_HT_RATES,
+ CFG_HT_MAC_PARAM_INFO,
+ CFG_MIMO_PS_MODE,
+ CFG_HT_DEFAULT_CAPABILIES_INFO,
+ CFG_LED_SC_RESOLUTION_FACTOR,
+ CFG_PTAM_ENERGY_CCK_DET_DEFAULT,
+ CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_DEFAULT,
+ CFG_PTAM_CORR40_4_TH_ADD_MIN_DEFAULT,
+ CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_DEFAULT,
+ CFG_PTAM_CORR32_4_TH_ADD_MIN_DEFAULT,
+ CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_DEFAULT,
+ CFG_PTAM_CORR32_1_TH_ADD_MIN_DEFAULT,
+ CFG_PTAM_ENERGY_CCK_DET_MIN_VAL,
+ CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_MIN_VAL,
+ CFG_PTAM_CORR40_4_TH_ADD_MIN_MIN_VAL,
+ CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_MIN_VAL,
+ CFG_PTAM_CORR32_4_TH_ADD_MIN_MIN_VAL,
+ CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_MIN_VAL,
+ CFG_PTAM_CORR32_1_TH_ADD_MIN_MIN_VAL,
+ CFG_PTAM_ENERGY_CCK_DET_MAX_VAL,
+ CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_MAX_VAL,
+ CFG_PTAM_CORR40_4_TH_ADD_MIN_MAX_VAL,
+ CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_MAX_VAL,
+ CFG_PTAM_CORR32_4_TH_ADD_MIN_MAX_VAL,
+ CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_MAX_VAL,
+ CFG_PTAM_CORR32_1_TH_ADD_MIN_MAX_VAL,
+ CFG_PTAM_ENERGY_CCK_DET_STEP_VAL,
+ CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_STEP_VAL,
+ CFG_PTAM_CORR40_4_TH_ADD_MIN_STEP_VAL,
+ CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_STEP_VAL,
+ CFG_PTAM_CORR32_4_TH_ADD_MIN_STEP_VAL,
+ CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_STEP_VAL,
+ CFG_PTAM_CORR32_1_TH_ADD_MIN_STEP_VAL,
+ CFG_PTAM_LINK_SENS_FA_OFDM_MAX,
+ CFG_PTAM_LINK_SENS_FA_OFDM_MIN,
+ CFG_PTAM_LINK_SENS_FA_CCK_MAX,
+ CFG_PTAM_LINK_SENS_FA_CCK_MIN,
+ CFG_PTAM_LINK_SENS_NRG_DIFF,
+ CFG_PTAM_LINK_SENS_NRG_MARGIN,
+ CFG_PTAM_LINK_SENS_MAX_NUMBER_OF_TIMES_IN_CCK_NO_FA,
+ CFG_PTAM_LINK_SENS_AUTO_CORR_MAX_TH_CCK,
+ CFG_AGG_MGG_TID_LOAD_ADDBA_THRESHOLD,
+ CFG_AGG_MGG_TID_LOAD_DELBA_THRESHOLD,
+ CFG_AGG_MGG_ADDBA_BUF_SIZE,
+ CFG_AGG_MGG_ADDBA_INACTIVE_TIMEOUT,
+ CFG_AGG_MGG_ADDBA_DEBUG_FLAGS,
+ CFG_SCAN_PERIODIC_RSSI_HIGH_THRESHOLD,
+ CFG_SCAN_PERIODIC_COEF_RSSI_HIGH,
+ CFG_11D_ENABLED,
+ CFG_11H_FEATURE_FLAGS,
/* <-- LAST --> */
CFG_TBL_FIX_LAST
@@ -155,7 +210,8 @@ enum {
/* variable size table */
enum {
CFG_NET_ADDR = 0,
- CFG_PROFILE,
+ CFG_LED_PATTERN_TABLE,
+
/* <-- LAST --> */
CFG_TBL_VAR_LAST
};
@@ -288,6 +344,9 @@ struct iwm_umac_cmd_scan_request {
/* iwm_umac_security.flag is WSC mode on -- bits [2:2] */
#define UMAC_SEC_FLG_WSC_ON_POS 2
#define UMAC_SEC_FLG_WSC_ON_SEED 1
+#define UMAC_SEC_FLG_WSC_ON_MSK (UMAC_SEC_FLG_WSC_ON_SEED << \
+ UMAC_SEC_FLG_WSC_ON_POS)
+
/* Legacy profile can use only WEP40 and WEP104 for encryption and
* OPEN or PSK for authentication */
@@ -382,6 +441,11 @@ struct iwm_umac_tx_key_id {
u8 reserved[3];
} __attribute__ ((packed));
+struct iwm_umac_pwr_trigger {
+ struct iwm_umac_wifi_if hdr;
+ __le32 reseved;
+} __attribute__ ((packed));
+
struct iwm_umac_cmd_stats_req {
__le32 flags;
} __attribute__ ((packed));
@@ -393,6 +457,7 @@ int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested);
int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested);
int iwm_send_calib_results(struct iwm_priv *iwm);
int iwm_store_rxiq_calib_result(struct iwm_priv *iwm);
+int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit);
/* UMAC commands */
int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
@@ -407,6 +472,7 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm);
int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id);
int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx);
int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key);
+int iwm_tx_power_trigger(struct iwm_priv *iwm);
int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags);
int iwm_send_umac_channel_list(struct iwm_priv *iwm);
int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c
index 6b0bcad758ca..49067092d336 100644
--- a/drivers/net/wireless/iwmc3200wifi/fw.c
+++ b/drivers/net/wireless/iwmc3200wifi/fw.c
@@ -217,6 +217,13 @@ static int iwm_load_img(struct iwm_priv *iwm, const char *img_name)
IWM_BUILD_YEAR(build_date), IWM_BUILD_MONTH(build_date),
IWM_BUILD_DAY(build_date));
+ if (!strcmp(img_name, iwm->bus_ops->umac_name))
+ sprintf(iwm->umac_version, "%02X.%02X",
+ ver->major, ver->minor);
+
+ if (!strcmp(img_name, iwm->bus_ops->lmac_name))
+ sprintf(iwm->lmac_version, "%02X.%02X",
+ ver->major, ver->minor);
err_release_fw:
release_firmware(fw);
@@ -398,6 +405,8 @@ int iwm_load_fw(struct iwm_priv *iwm)
iwm_send_prio_table(iwm);
iwm_send_calib_results(iwm);
iwm_send_periodic_calib_cfg(iwm, periodic_calib_map);
+ iwm_send_ct_kill_cfg(iwm, iwm->conf.ct_kill_entry,
+ iwm->conf.ct_kill_exit);
return 0;
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index 1b02a4e2a1ac..a9bf6bc97bea 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -65,6 +65,8 @@ struct iwm_conf {
u32 sdio_ior_timeout;
unsigned long calib_map;
unsigned long expected_calib_map;
+ u8 ct_kill_entry;
+ u8 ct_kill_exit;
bool reset_on_fatal_err;
bool auto_connect;
bool wimax_not_present;
@@ -276,12 +278,14 @@ struct iwm_priv {
struct iw_statistics wstats;
struct delayed_work stats_request;
struct delayed_work disconnect;
+ struct delayed_work ct_kill_delay;
struct iwm_debugfs dbg;
u8 *eeprom;
struct timer_list watchdog;
struct work_struct reset_worker;
+ struct work_struct auth_retry_worker;
struct mutex mutex;
u8 *req_ie;
@@ -290,6 +294,8 @@ struct iwm_priv {
int resp_ie_len;
struct iwm_fw_error_hdr *last_fw_err;
+ char umac_version[8];
+ char lmac_version[8];
char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
};
diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h
index 6c1a14c4480f..a3a79b5e2898 100644
--- a/drivers/net/wireless/iwmc3200wifi/lmac.h
+++ b/drivers/net/wireless/iwmc3200wifi/lmac.h
@@ -187,6 +187,14 @@ struct iwm_coex_prio_table_cmd {
COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \
COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK)
+/* CT kill config command */
+struct iwm_ct_kill_cfg_cmd {
+ u32 exit_threshold;
+ u32 reserved;
+ u32 entry_threshold;
+} __attribute__ ((packed));
+
+
/* LMAC OP CODES */
#define REPLY_PAD 0x0
#define REPLY_ALIVE 0x1
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
index 222eb2cf1b30..75f105a59543 100644
--- a/drivers/net/wireless/iwmc3200wifi/main.c
+++ b/drivers/net/wireless/iwmc3200wifi/main.c
@@ -64,6 +64,8 @@ static struct iwm_conf def_iwm_conf = {
BIT(PHY_CALIBRATE_TX_IQ_CMD) |
BIT(PHY_CALIBRATE_RX_IQ_CMD) |
BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD),
+ .ct_kill_entry = 110,
+ .ct_kill_exit = 110,
.reset_on_fatal_err = 1,
.auto_connect = 1,
.wimax_not_present = 0,
@@ -134,6 +136,17 @@ static void iwm_disconnect_work(struct work_struct *work)
cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL);
}
+static void iwm_ct_kill_work(struct work_struct *work)
+{
+ struct iwm_priv *iwm =
+ container_of(work, struct iwm_priv, ct_kill_delay.work);
+ struct wiphy *wiphy = iwm_to_wiphy(iwm);
+
+ IWM_INFO(iwm, "CT kill delay timeout\n");
+
+ wiphy_rfkill_set_hw_state(wiphy, false);
+}
+
static int __iwm_up(struct iwm_priv *iwm);
static int __iwm_down(struct iwm_priv *iwm);
@@ -195,6 +208,33 @@ static void iwm_reset_worker(struct work_struct *work)
mutex_unlock(&iwm->mutex);
}
+static void iwm_auth_retry_worker(struct work_struct *work)
+{
+ struct iwm_priv *iwm;
+ int i, ret;
+
+ iwm = container_of(work, struct iwm_priv, auth_retry_worker);
+ if (iwm->umac_profile_active) {
+ ret = iwm_invalidate_mlme_profile(iwm);
+ if (ret < 0)
+ return;
+ }
+
+ iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+
+ ret = iwm_send_mlme_profile(iwm);
+ if (ret < 0)
+ return;
+
+ for (i = 0; i < IWM_NUM_KEYS; i++)
+ if (iwm->keys[i].key_len)
+ iwm_set_key(iwm, 0, &iwm->keys[i]);
+
+ iwm_set_tx_key(iwm, iwm->default_key);
+}
+
+
+
static void iwm_watchdog(unsigned long data)
{
struct iwm_priv *iwm = (struct iwm_priv *)data;
@@ -226,7 +266,9 @@ int iwm_priv_init(struct iwm_priv *iwm)
iwm->scan_id = 1;
INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request);
INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work);
+ INIT_DELAYED_WORK(&iwm->ct_kill_delay, iwm_ct_kill_work);
INIT_WORK(&iwm->reset_worker, iwm_reset_worker);
+ INIT_WORK(&iwm->auth_retry_worker, iwm_auth_retry_worker);
INIT_LIST_HEAD(&iwm->bss_list);
skb_queue_head_init(&iwm->rx_list);
@@ -587,6 +629,7 @@ static int __iwm_up(struct iwm_priv *iwm)
{
int ret;
struct iwm_notif *notif_reboot, *notif_ack = NULL;
+ struct wiphy *wiphy = iwm_to_wiphy(iwm);
ret = iwm_bus_enable(iwm);
if (ret) {
@@ -638,6 +681,8 @@ static int __iwm_up(struct iwm_priv *iwm)
IWM_ERR(iwm, "MAC reading failed\n");
goto err_disable;
}
+ memcpy(iwm_to_ndev(iwm)->perm_addr, iwm_to_ndev(iwm)->dev_addr,
+ ETH_ALEN);
/* We can load the FWs */
ret = iwm_load_fw(iwm);
@@ -646,6 +691,9 @@ static int __iwm_up(struct iwm_priv *iwm)
goto err_disable;
}
+ snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "L%s_U%s",
+ iwm->lmac_version, iwm->umac_version);
+
/* We configure the UMAC and enable the wifi module */
ret = iwm_send_umac_config(iwm,
cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_CORE_EN) |
diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c
index 35ec006c2d2c..4f8dbdd7b917 100644
--- a/drivers/net/wireless/iwmc3200wifi/netdev.c
+++ b/drivers/net/wireless/iwmc3200wifi/netdev.c
@@ -152,6 +152,7 @@ void iwm_if_free(struct iwm_priv *iwm)
if (!iwm_to_ndev(iwm))
return;
+ cancel_delayed_work_sync(&iwm->ct_kill_delay);
free_netdev(iwm_to_ndev(iwm));
iwm_priv_deinit(iwm);
kfree(iwm->umac_profile);
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index 771a301003c9..bdb1d7e7979d 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -423,7 +423,9 @@ static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf,
if (IS_ERR(ticket_node))
return PTR_ERR(ticket_node);
- IWM_DBG_RX(iwm, DBG, "TICKET RELEASE(%d)\n",
+ IWM_DBG_RX(iwm, DBG, "TICKET %s(%d)\n",
+ ticket->action == IWM_RX_TICKET_RELEASE ?
+ "RELEASE" : "DROP",
ticket->id);
list_add_tail(&ticket_node->node, &iwm->rx_tickets);
@@ -500,6 +502,18 @@ static int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf,
return 0;
}
+static u8 iwm_is_open_wep_profile(struct iwm_priv *iwm)
+{
+ if ((iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_40 ||
+ iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_104) &&
+ (iwm->umac_profile->sec.ucast_cipher ==
+ iwm->umac_profile->sec.mcast_cipher) &&
+ (iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN))
+ return 1;
+
+ return 0;
+}
+
static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size,
struct iwm_wifi_cmd *cmd)
@@ -565,11 +579,17 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
goto ibss;
if (!test_bit(IWM_STATUS_RESETTING, &iwm->status))
- cfg80211_connect_result(iwm_to_ndev(iwm),
- complete->bssid,
- NULL, 0, NULL, 0,
- WLAN_STATUS_UNSPECIFIED_FAILURE,
- GFP_KERNEL);
+ if (!iwm_is_open_wep_profile(iwm)) {
+ cfg80211_connect_result(iwm_to_ndev(iwm),
+ complete->bssid,
+ NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ GFP_KERNEL);
+ } else {
+ /* Let's try shared WEP auth */
+ IWM_ERR(iwm, "Trying WEP shared auth\n");
+ schedule_work(&iwm->auth_retry_worker);
+ }
else
cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0,
GFP_KERNEL);
@@ -713,6 +733,19 @@ static int iwm_mlme_update_sta_table(struct iwm_priv *iwm, u8 *buf,
return 0;
}
+static int iwm_mlme_medium_lost(struct iwm_priv *iwm, u8 *buf,
+ unsigned long buf_size,
+ struct iwm_wifi_cmd *cmd)
+{
+ struct wiphy *wiphy = iwm_to_wiphy(iwm);
+
+ IWM_DBG_NTF(iwm, DBG, "WiFi/WiMax coexistence radio is OFF\n");
+
+ wiphy_rfkill_set_hw_state(wiphy, true);
+
+ return 0;
+}
+
static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size,
struct iwm_wifi_cmd *cmd)
@@ -899,6 +932,8 @@ static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf,
case WIFI_IF_NTFY_EXTENDED_IE_REQUIRED:
IWM_DBG_MLME(iwm, DBG, "Extended IE required\n");
break;
+ case WIFI_IF_NTFY_RADIO_PREEMPTION:
+ return iwm_mlme_medium_lost(iwm, buf, buf_size, cmd);
case WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED:
return iwm_mlme_update_bss_table(iwm, buf, buf_size, cmd);
case WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED:
@@ -1056,8 +1091,14 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size,
struct iwm_wifi_cmd *cmd)
{
- struct iwm_umac_wifi_if *hdr =
- (struct iwm_umac_wifi_if *)cmd->buf.payload;
+ struct iwm_umac_wifi_if *hdr;
+
+ if (cmd == NULL) {
+ IWM_ERR(iwm, "Couldn't find expected wifi command\n");
+ return -EINVAL;
+ }
+
+ hdr = (struct iwm_umac_wifi_if *)cmd->buf.payload;
IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: "
"oid is 0x%x\n", hdr->oid);
@@ -1079,6 +1120,7 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
return 0;
}
+#define CT_KILL_DELAY (30 * HZ)
static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size, struct iwm_wifi_cmd *cmd)
{
@@ -1091,7 +1133,20 @@ static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF",
flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF");
- wiphy_rfkill_set_hw_state(wiphy, flags & IWM_CARD_STATE_HW_DISABLED);
+ if (flags & IWM_CARD_STATE_CTKILL_DISABLED) {
+ /*
+ * We got a CTKILL event: We bring the interface down in
+ * oder to cool the device down, and try to bring it up
+ * 30 seconds later. If it's still too hot, we'll go through
+ * this code path again.
+ */
+ cancel_delayed_work_sync(&iwm->ct_kill_delay);
+ schedule_delayed_work(&iwm->ct_kill_delay, CT_KILL_DELAY);
+ }
+
+ wiphy_rfkill_set_hw_state(wiphy, flags &
+ (IWM_CARD_STATE_HW_DISABLED |
+ IWM_CARD_STATE_CTKILL_DISABLED));
return 0;
}
@@ -1282,6 +1337,14 @@ int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size)
switch (le32_to_cpu(hdr->cmd)) {
case UMAC_REBOOT_BARKER:
+ if (test_bit(IWM_STATUS_READY, &iwm->status)) {
+ IWM_ERR(iwm, "Unexpected BARKER\n");
+
+ schedule_work(&iwm->reset_worker);
+
+ return 0;
+ }
+
return iwm_notif_send(iwm, NULL, IWM_BARKER_REBOOT_NOTIFICATION,
IWM_SRC_UDMA, buf, buf_size);
case UMAC_ACK_BARKER:
@@ -1444,7 +1507,8 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
}
break;
case IWM_RX_TICKET_DROP:
- IWM_DBG_RX(iwm, DBG, "DROP packet\n");
+ IWM_DBG_RX(iwm, DBG, "DROP packet: 0x%x\n",
+ le16_to_cpu(ticket_node->ticket->flags));
kfree_skb(packet->skb);
break;
default:
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c
index 8b1de84003ca..cf86294f719b 100644
--- a/drivers/net/wireless/iwmc3200wifi/sdio.c
+++ b/drivers/net/wireless/iwmc3200wifi/sdio.c
@@ -224,8 +224,6 @@ static int if_sdio_disable(struct iwm_priv *iwm)
struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm);
int ret;
- iwm_reset(iwm);
-
sdio_claim_host(hw->func);
sdio_writeb(hw->func, 0, IWM_SDIO_INTR_ENABLE_ADDR, &ret);
if (ret < 0)
@@ -237,6 +235,8 @@ static int if_sdio_disable(struct iwm_priv *iwm)
iwm_sdio_rx_free(hw);
+ iwm_reset(iwm);
+
IWM_DBG_SDIO(iwm, INFO, "IWM SDIO disable\n");
return 0;
@@ -493,8 +493,10 @@ static void iwm_sdio_remove(struct sdio_func *func)
}
static const struct sdio_device_id iwm_sdio_ids[] = {
- { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL,
- SDIO_DEVICE_ID_INTEL_IWMC3200WIFI) },
+ /* Global/AGN SKU */
+ { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1403) },
+ /* BGN SKU */
+ { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1408) },
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids);
diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h
index c5a14ae3160a..be903543bb47 100644
--- a/drivers/net/wireless/iwmc3200wifi/umac.h
+++ b/drivers/net/wireless/iwmc3200wifi/umac.h
@@ -687,6 +687,9 @@ struct iwm_umac_notif_rx_ticket {
/* Tx/Rx rates window (number of max of last update window per second) */
#define UMAC_NTF_RATE_SAMPLE_NR 4
+/* Max numbers of bits required to go through all antennae in bitmasks */
+#define UMAC_PHY_NUM_CHAINS 3
+
#define IWM_UMAC_MGMT_TID 8
#define IWM_UMAC_TID_NR 8
@@ -697,9 +700,11 @@ struct iwm_umac_notif_stats {
__le16 tid_load[IWM_UMAC_TID_NR + 2]; /* 1 non-QoS + 1 dword align */
__le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR];
__le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR];
+ __le32 chain_energy[UMAC_PHY_NUM_CHAINS];
s32 rssi_dbm;
s32 noise_dbm;
__le32 supp_rates;
+ __le32 supp_ht_rates;
__le32 missed_beacons;
__le32 rx_beacons;
__le32 rx_dir_pkts;
diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c
deleted file mode 100644
index 5c6968101f0d..000000000000
--- a/drivers/net/wireless/libertas/11d.c
+++ /dev/null
@@ -1,696 +0,0 @@
-/**
- * This file contains functions for 802.11D.
- */
-#include <linux/ctype.h>
-#include <linux/kernel.h>
-#include <linux/wireless.h>
-
-#include "host.h"
-#include "decl.h"
-#include "11d.h"
-#include "dev.h"
-#include "wext.h"
-
-#define TX_PWR_DEFAULT 10
-
-static struct region_code_mapping region_code_mapping[] = {
- {"US ", 0x10}, /* US FCC */
- {"CA ", 0x10}, /* IC Canada */
- {"SG ", 0x10}, /* Singapore */
- {"EU ", 0x30}, /* ETSI */
- {"AU ", 0x30}, /* Australia */
- {"KR ", 0x30}, /* Republic Of Korea */
- {"ES ", 0x31}, /* Spain */
- {"FR ", 0x32}, /* France */
- {"JP ", 0x40}, /* Japan */
-};
-
-/* Following 2 structure defines the supported channels */
-static struct chan_freq_power channel_freq_power_UN_BG[] = {
- {1, 2412, TX_PWR_DEFAULT},
- {2, 2417, TX_PWR_DEFAULT},
- {3, 2422, TX_PWR_DEFAULT},
- {4, 2427, TX_PWR_DEFAULT},
- {5, 2432, TX_PWR_DEFAULT},
- {6, 2437, TX_PWR_DEFAULT},
- {7, 2442, TX_PWR_DEFAULT},
- {8, 2447, TX_PWR_DEFAULT},
- {9, 2452, TX_PWR_DEFAULT},
- {10, 2457, TX_PWR_DEFAULT},
- {11, 2462, TX_PWR_DEFAULT},
- {12, 2467, TX_PWR_DEFAULT},
- {13, 2472, TX_PWR_DEFAULT},
- {14, 2484, TX_PWR_DEFAULT}
-};
-
-static u8 lbs_region_2_code(u8 *region)
-{
- u8 i;
-
- for (i = 0; i < COUNTRY_CODE_LEN && region[i]; i++)
- region[i] = toupper(region[i]);
-
- for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
- if (!memcmp(region, region_code_mapping[i].region,
- COUNTRY_CODE_LEN))
- return (region_code_mapping[i].code);
- }
-
- /* default is US */
- return (region_code_mapping[0].code);
-}
-
-static u8 *lbs_code_2_region(u8 code)
-{
- u8 i;
-
- for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
- if (region_code_mapping[i].code == code)
- return (region_code_mapping[i].region);
- }
- /* default is US */
- return (region_code_mapping[0].region);
-}
-
-/**
- * @brief This function finds the nrchan-th chan after the firstchan
- * @param band band
- * @param firstchan first channel number
- * @param nrchan number of channels
- * @return the nrchan-th chan number
-*/
-static u8 lbs_get_chan_11d(u8 firstchan, u8 nrchan, u8 *chan)
-/*find the nrchan-th chan after the firstchan*/
-{
- u8 i;
- struct chan_freq_power *cfp;
- u8 cfp_no;
-
- cfp = channel_freq_power_UN_BG;
- cfp_no = ARRAY_SIZE(channel_freq_power_UN_BG);
-
- for (i = 0; i < cfp_no; i++) {
- if ((cfp + i)->channel == firstchan) {
- lbs_deb_11d("firstchan found\n");
- break;
- }
- }
-
- if (i < cfp_no) {
- /*if beyond the boundary */
- if (i + nrchan < cfp_no) {
- *chan = (cfp + i + nrchan)->channel;
- return 1;
- }
- }
-
- return 0;
-}
-
-/**
- * @brief This function Checks if chan txpwr is learned from AP/IBSS
- * @param chan chan number
- * @param parsed_region_chan pointer to parsed_region_chan_11d
- * @return TRUE; FALSE
-*/
-static u8 lbs_channel_known_11d(u8 chan,
- struct parsed_region_chan_11d * parsed_region_chan)
-{
- struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr;
- u8 nr_chan = parsed_region_chan->nr_chan;
- u8 i = 0;
-
- lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)chanpwr,
- sizeof(struct chan_power_11d) * nr_chan);
-
- for (i = 0; i < nr_chan; i++) {
- if (chan == chanpwr[i].chan) {
- lbs_deb_11d("found chan %d\n", chan);
- return 1;
- }
- }
-
- lbs_deb_11d("chan %d not found\n", chan);
- return 0;
-}
-
-u32 lbs_chan_2_freq(u8 chan)
-{
- struct chan_freq_power *cf;
- u16 i;
- u32 freq = 0;
-
- cf = channel_freq_power_UN_BG;
-
- for (i = 0; i < ARRAY_SIZE(channel_freq_power_UN_BG); i++) {
- if (chan == cf[i].channel)
- freq = cf[i].freq;
- }
-
- return freq;
-}
-
-static int generate_domain_info_11d(struct parsed_region_chan_11d
- *parsed_region_chan,
- struct lbs_802_11d_domain_reg *domaininfo)
-{
- u8 nr_subband = 0;
-
- u8 nr_chan = parsed_region_chan->nr_chan;
- u8 nr_parsedchan = 0;
-
- u8 firstchan = 0, nextchan = 0, maxpwr = 0;
-
- u8 i, flag = 0;
-
- memcpy(domaininfo->countrycode, parsed_region_chan->countrycode,
- COUNTRY_CODE_LEN);
-
- lbs_deb_11d("nrchan %d\n", nr_chan);
- lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)parsed_region_chan,
- sizeof(struct parsed_region_chan_11d));
-
- for (i = 0; i < nr_chan; i++) {
- if (!flag) {
- flag = 1;
- nextchan = firstchan =
- parsed_region_chan->chanpwr[i].chan;
- maxpwr = parsed_region_chan->chanpwr[i].pwr;
- nr_parsedchan = 1;
- continue;
- }
-
- if (parsed_region_chan->chanpwr[i].chan == nextchan + 1 &&
- parsed_region_chan->chanpwr[i].pwr == maxpwr) {
- nextchan++;
- nr_parsedchan++;
- } else {
- domaininfo->subband[nr_subband].firstchan = firstchan;
- domaininfo->subband[nr_subband].nrchan =
- nr_parsedchan;
- domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
- nr_subband++;
- nextchan = firstchan =
- parsed_region_chan->chanpwr[i].chan;
- maxpwr = parsed_region_chan->chanpwr[i].pwr;
- }
- }
-
- if (flag) {
- domaininfo->subband[nr_subband].firstchan = firstchan;
- domaininfo->subband[nr_subband].nrchan = nr_parsedchan;
- domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
- nr_subband++;
- }
- domaininfo->nr_subband = nr_subband;
-
- lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband);
- lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo,
- COUNTRY_CODE_LEN + 1 +
- sizeof(struct ieee_subbandset) * nr_subband);
- return 0;
-}
-
-/**
- * @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS
- * @param region_chan pointer to struct region_channel
- * @param *parsed_region_chan pointer to parsed_region_chan_11d
- * @return N/A
-*/
-static void lbs_generate_parsed_region_chan_11d(struct region_channel *region_chan,
- struct parsed_region_chan_11d *
- parsed_region_chan)
-{
- u8 i;
- struct chan_freq_power *cfp;
-
- if (region_chan == NULL) {
- lbs_deb_11d("region_chan is NULL\n");
- return;
- }
-
- cfp = region_chan->CFP;
- if (cfp == NULL) {
- lbs_deb_11d("cfp is NULL \n");
- return;
- }
-
- parsed_region_chan->band = region_chan->band;
- parsed_region_chan->region = region_chan->region;
- memcpy(parsed_region_chan->countrycode,
- lbs_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
-
- lbs_deb_11d("region 0x%x, band %d\n", parsed_region_chan->region,
- parsed_region_chan->band);
-
- for (i = 0; i < region_chan->nrcfp; i++, cfp++) {
- parsed_region_chan->chanpwr[i].chan = cfp->channel;
- parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower;
- lbs_deb_11d("chan %d, pwr %d\n",
- parsed_region_chan->chanpwr[i].chan,
- parsed_region_chan->chanpwr[i].pwr);
- }
- parsed_region_chan->nr_chan = region_chan->nrcfp;
-
- lbs_deb_11d("nrchan %d\n", parsed_region_chan->nr_chan);
-
- return;
-}
-
-/**
- * @brief generate parsed_region_chan from Domain Info learned from AP/IBSS
- * @param region region ID
- * @param band band
- * @param chan chan
- * @return TRUE;FALSE
-*/
-static u8 lbs_region_chan_supported_11d(u8 region, u8 chan)
-{
- struct chan_freq_power *cfp;
- int cfp_no;
- u8 idx;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_11D);
-
- cfp = lbs_get_region_cfp_table(region, &cfp_no);
- if (cfp == NULL)
- return 0;
-
- for (idx = 0; idx < cfp_no; idx++) {
- if (chan == (cfp + idx)->channel) {
- /* If Mrvl Chip Supported? */
- if ((cfp + idx)->unsupported) {
- ret = 0;
- } else {
- ret = 1;
- }
- goto done;
- }
- }
-
- /*chan is not in the region table */
-
-done:
- lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief This function checks if chan txpwr is learned from AP/IBSS
- * @param chan chan number
- * @param parsed_region_chan pointer to parsed_region_chan_11d
- * @return 0
-*/
-static int parse_domain_info_11d(struct ieee_ie_country_info_full_set *countryinfo,
- u8 band,
- struct parsed_region_chan_11d *parsed_region_chan)
-{
- u8 nr_subband, nrchan;
- u8 lastchan, firstchan;
- u8 region;
- u8 curchan = 0;
-
- u8 idx = 0; /*chan index in parsed_region_chan */
-
- u8 j, i;
-
- lbs_deb_enter(LBS_DEB_11D);
-
- /*validation Rules:
- 1. valid region Code
- 2. First Chan increment
- 3. channel range no overlap
- 4. channel is valid?
- 5. channel is supported by region?
- 6. Others
- */
-
- lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30);
-
- if ((*(countryinfo->countrycode)) == 0
- || (countryinfo->header.len <= COUNTRY_CODE_LEN)) {
- /* No region Info or Wrong region info: treat as No 11D info */
- goto done;
- }
-
- /*Step1: check region_code */
- parsed_region_chan->region = region =
- lbs_region_2_code(countryinfo->countrycode);
-
- lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region);
- lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode,
- COUNTRY_CODE_LEN);
-
- parsed_region_chan->band = band;
-
- memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
- COUNTRY_CODE_LEN);
-
- nr_subband = (countryinfo->header.len - COUNTRY_CODE_LEN) /
- sizeof(struct ieee_subbandset);
-
- for (j = 0, lastchan = 0; j < nr_subband; j++) {
-
- if (countryinfo->subband[j].firstchan <= lastchan) {
- /*Step2&3. Check First Chan Num increment and no overlap */
- lbs_deb_11d("chan %d>%d, overlap\n",
- countryinfo->subband[j].firstchan, lastchan);
- continue;
- }
-
- firstchan = countryinfo->subband[j].firstchan;
- nrchan = countryinfo->subband[j].nrchan;
-
- for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) {
- /*step4: channel is supported? */
-
- if (!lbs_get_chan_11d(firstchan, i, &curchan)) {
- /* Chan is not found in UN table */
- lbs_deb_11d("chan is not supported: %d \n", i);
- break;
- }
-
- lastchan = curchan;
-
- if (lbs_region_chan_supported_11d(region, curchan)) {
- /*step5: Check if curchan is supported by mrvl in region */
- parsed_region_chan->chanpwr[idx].chan = curchan;
- parsed_region_chan->chanpwr[idx].pwr =
- countryinfo->subband[j].maxtxpwr;
- idx++;
- } else {
- /*not supported and ignore the chan */
- lbs_deb_11d(
- "i %d, chan %d unsupported in region %x, band %d\n",
- i, curchan, region, band);
- }
- }
-
- /*Step6: Add other checking if any */
-
- }
-
- parsed_region_chan->nr_chan = idx;
-
- lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan);
- lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (u8 *) parsed_region_chan,
- 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
-
-done:
- lbs_deb_enter(LBS_DEB_11D);
- return 0;
-}
-
-/**
- * @brief This function calculates the scan type for channels
- * @param chan chan number
- * @param parsed_region_chan pointer to parsed_region_chan_11d
- * @return PASSIVE if chan is unknown; ACTIVE if chan is known
-*/
-u8 lbs_get_scan_type_11d(u8 chan,
- struct parsed_region_chan_11d * parsed_region_chan)
-{
- u8 scan_type = CMD_SCAN_TYPE_PASSIVE;
-
- lbs_deb_enter(LBS_DEB_11D);
-
- if (lbs_channel_known_11d(chan, parsed_region_chan)) {
- lbs_deb_11d("found, do active scan\n");
- scan_type = CMD_SCAN_TYPE_ACTIVE;
- } else {
- lbs_deb_11d("not found, do passive scan\n");
- }
-
- lbs_deb_leave_args(LBS_DEB_11D, "ret scan_type %d", scan_type);
- return scan_type;
-
-}
-
-void lbs_init_11d(struct lbs_private *priv)
-{
- priv->enable11d = 0;
- memset(&(priv->parsed_region_chan), 0,
- sizeof(struct parsed_region_chan_11d));
- return;
-}
-
-/**
- * @brief This function sets DOMAIN INFO to FW
- * @param priv pointer to struct lbs_private
- * @return 0; -1
-*/
-static int set_domain_info_11d(struct lbs_private *priv)
-{
- int ret;
-
- if (!priv->enable11d) {
- lbs_deb_11d("dnld domain Info with 11d disabled\n");
- return 0;
- }
-
- ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
- CMD_ACT_SET,
- CMD_OPTION_WAITFORRSP, 0, NULL);
- if (ret)
- lbs_deb_11d("fail to dnld domain info\n");
-
- return ret;
-}
-
-/**
- * @brief This function setups scan channels
- * @param priv pointer to struct lbs_private
- * @param band band
- * @return 0
-*/
-int lbs_set_universaltable(struct lbs_private *priv, u8 band)
-{
- u16 size = sizeof(struct chan_freq_power);
- u16 i = 0;
-
- memset(priv->universal_channel, 0,
- sizeof(priv->universal_channel));
-
- priv->universal_channel[i].nrcfp =
- sizeof(channel_freq_power_UN_BG) / size;
- lbs_deb_11d("BG-band nrcfp %d\n",
- priv->universal_channel[i].nrcfp);
-
- priv->universal_channel[i].CFP = channel_freq_power_UN_BG;
- priv->universal_channel[i].valid = 1;
- priv->universal_channel[i].region = UNIVERSAL_REGION_CODE;
- priv->universal_channel[i].band = band;
- i++;
-
- return 0;
-}
-
-/**
- * @brief This function implements command CMD_802_11D_DOMAIN_INFO
- * @param priv pointer to struct lbs_private
- * @param cmd pointer to cmd buffer
- * @param cmdno cmd ID
- * @param cmdOption cmd action
- * @return 0
-*/
-int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
- struct cmd_ds_command *cmd, u16 cmdno,
- u16 cmdoption)
-{
- struct cmd_ds_802_11d_domain_info *pdomaininfo =
- &cmd->params.domaininfo;
- struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain;
- u8 nr_subband = priv->domainreg.nr_subband;
-
- lbs_deb_enter(LBS_DEB_11D);
-
- lbs_deb_11d("nr_subband=%x\n", nr_subband);
-
- cmd->command = cpu_to_le16(cmdno);
- pdomaininfo->action = cpu_to_le16(cmdoption);
- if (cmdoption == CMD_ACT_GET) {
- cmd->size =
- cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
- lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
- le16_to_cpu(cmd->size));
- goto done;
- }
-
- domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
- memcpy(domain->countrycode, priv->domainreg.countrycode,
- sizeof(domain->countrycode));
-
- domain->header.len =
- cpu_to_le16(nr_subband * sizeof(struct ieee_subbandset) +
- sizeof(domain->countrycode));
-
- if (nr_subband) {
- memcpy(domain->subband, priv->domainreg.subband,
- nr_subband * sizeof(struct ieee_subbandset));
-
- cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
- le16_to_cpu(domain->header.len) +
- sizeof(struct mrvl_ie_header) +
- S_DS_GEN);
- } else {
- cmd->size =
- cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
- }
-
- lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size));
-
-done:
- lbs_deb_enter(LBS_DEB_11D);
- return 0;
-}
-
-/**
- * @brief This function parses countryinfo from AP and download country info to FW
- * @param priv pointer to struct lbs_private
- * @param resp pointer to command response buffer
- * @return 0; -1
- */
-int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp)
-{
- struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp;
- struct mrvl_ie_domain_param_set *domain = &domaininfo->domain;
- u16 action = le16_to_cpu(domaininfo->action);
- s16 ret = 0;
- u8 nr_subband = 0;
-
- lbs_deb_enter(LBS_DEB_11D);
-
- lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
- (int)le16_to_cpu(resp->size));
-
- nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
- sizeof(struct ieee_subbandset);
-
- lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband);
-
- if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
- lbs_deb_11d("Invalid Numrer of Subband returned!!\n");
- return -1;
- }
-
- switch (action) {
- case CMD_ACT_SET: /*Proc Set action */
- break;
-
- case CMD_ACT_GET:
- break;
- default:
- lbs_deb_11d("Invalid action:%d\n", domaininfo->action);
- ret = -1;
- break;
- }
-
- lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief This function parses countryinfo from AP and download country info to FW
- * @param priv pointer to struct lbs_private
- * @return 0; -1
- */
-int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv,
- struct bss_descriptor * bss)
-{
- int ret;
-
- lbs_deb_enter(LBS_DEB_11D);
- if (priv->enable11d) {
- memset(&priv->parsed_region_chan, 0,
- sizeof(struct parsed_region_chan_11d));
- ret = parse_domain_info_11d(&bss->countryinfo, 0,
- &priv->parsed_region_chan);
-
- if (ret == -1) {
- lbs_deb_11d("error parsing domain_info from AP\n");
- goto done;
- }
-
- memset(&priv->domainreg, 0,
- sizeof(struct lbs_802_11d_domain_reg));
- generate_domain_info_11d(&priv->parsed_region_chan,
- &priv->domainreg);
-
- ret = set_domain_info_11d(priv);
-
- if (ret) {
- lbs_deb_11d("error setting domain info\n");
- goto done;
- }
- }
- ret = 0;
-
-done:
- lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
- return ret;
-}
-
-/**
- * @brief This function generates 11D info from user specified regioncode and download to FW
- * @param priv pointer to struct lbs_private
- * @return 0; -1
- */
-int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv)
-{
- int ret;
- struct region_channel *region_chan;
- u8 j;
-
- lbs_deb_enter(LBS_DEB_11D);
- lbs_deb_11d("curbssparams.band %d\n", priv->curbssparams.band);
-
- if (priv->enable11d) {
- /* update parsed_region_chan_11; dnld domaininf to FW */
-
- for (j = 0; j < ARRAY_SIZE(priv->region_channel); j++) {
- region_chan = &priv->region_channel[j];
-
- lbs_deb_11d("%d region_chan->band %d\n", j,
- region_chan->band);
-
- if (!region_chan || !region_chan->valid
- || !region_chan->CFP)
- continue;
- if (region_chan->band != priv->curbssparams.band)
- continue;
- break;
- }
-
- if (j >= ARRAY_SIZE(priv->region_channel)) {
- lbs_deb_11d("region_chan not found, band %d\n",
- priv->curbssparams.band);
- ret = -1;
- goto done;
- }
-
- memset(&priv->parsed_region_chan, 0,
- sizeof(struct parsed_region_chan_11d));
- lbs_generate_parsed_region_chan_11d(region_chan,
- &priv->
- parsed_region_chan);
-
- memset(&priv->domainreg, 0,
- sizeof(struct lbs_802_11d_domain_reg));
- generate_domain_info_11d(&priv->parsed_region_chan,
- &priv->domainreg);
-
- ret = set_domain_info_11d(priv);
-
- if (ret) {
- lbs_deb_11d("error setting domain info\n");
- goto done;
- }
-
- }
- ret = 0;
-
-done:
- lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
- return ret;
-}
diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h
deleted file mode 100644
index fb75d3e321a0..000000000000
--- a/drivers/net/wireless/libertas/11d.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/**
- * This header file contains data structures and
- * function declarations of 802.11d
- */
-#ifndef _LBS_11D_
-#define _LBS_11D_
-
-#include "types.h"
-#include "defs.h"
-
-#define UNIVERSAL_REGION_CODE 0xff
-
-/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr)
- */
-#define MRVDRV_MAX_SUBBAND_802_11D 83
-
-#define COUNTRY_CODE_LEN 3
-#define MAX_NO_OF_CHAN 40
-
-struct cmd_ds_command;
-
-/** Data structure for Country IE*/
-struct ieee_subbandset {
- u8 firstchan;
- u8 nrchan;
- u8 maxtxpwr;
-} __attribute__ ((packed));
-
-struct ieee_ie_country_info_set {
- struct ieee_ie_header header;
-
- u8 countrycode[COUNTRY_CODE_LEN];
- struct ieee_subbandset subband[1];
-};
-
-struct ieee_ie_country_info_full_set {
- struct ieee_ie_header header;
-
- u8 countrycode[COUNTRY_CODE_LEN];
- struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
-} __attribute__ ((packed));
-
-struct mrvl_ie_domain_param_set {
- struct mrvl_ie_header header;
-
- u8 countrycode[COUNTRY_CODE_LEN];
- struct ieee_subbandset subband[1];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11d_domain_info {
- __le16 action;
- struct mrvl_ie_domain_param_set domain;
-} __attribute__ ((packed));
-
-/** domain regulatory information */
-struct lbs_802_11d_domain_reg {
- /** country Code*/
- u8 countrycode[COUNTRY_CODE_LEN];
- /** No. of subband*/
- u8 nr_subband;
- struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
-};
-
-struct chan_power_11d {
- u8 chan;
- u8 pwr;
-} __attribute__ ((packed));
-
-struct parsed_region_chan_11d {
- u8 band;
- u8 region;
- s8 countrycode[COUNTRY_CODE_LEN];
- struct chan_power_11d chanpwr[MAX_NO_OF_CHAN];
- u8 nr_chan;
-} __attribute__ ((packed));
-
-struct region_code_mapping {
- u8 region[COUNTRY_CODE_LEN];
- u8 code;
-};
-
-struct lbs_private;
-
-u8 lbs_get_scan_type_11d(u8 chan,
- struct parsed_region_chan_11d *parsed_region_chan);
-
-u32 lbs_chan_2_freq(u8 chan);
-
-void lbs_init_11d(struct lbs_private *priv);
-
-int lbs_set_universaltable(struct lbs_private *priv, u8 band);
-
-int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
- struct cmd_ds_command *cmd, u16 cmdno,
- u16 cmdOption);
-
-int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp);
-
-struct bss_descriptor;
-int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv,
- struct bss_descriptor * bss);
-
-int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv);
-
-#endif
diff --git a/drivers/net/wireless/libertas/Kconfig b/drivers/net/wireless/libertas/Kconfig
new file mode 100644
index 000000000000..30aa9d48d67e
--- /dev/null
+++ b/drivers/net/wireless/libertas/Kconfig
@@ -0,0 +1,39 @@
+config LIBERTAS
+ tristate "Marvell 8xxx Libertas WLAN driver support"
+ depends on CFG80211
+ select WIRELESS_EXT
+ select WEXT_SPY
+ select LIB80211
+ select FW_LOADER
+ ---help---
+ A library for Marvell Libertas 8xxx devices.
+
+config LIBERTAS_USB
+ tristate "Marvell Libertas 8388 USB 802.11b/g cards"
+ depends on LIBERTAS && USB
+ ---help---
+ A driver for Marvell Libertas 8388 USB devices.
+
+config LIBERTAS_CS
+ tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards"
+ depends on LIBERTAS && PCMCIA
+ ---help---
+ A driver for Marvell Libertas 8385 CompactFlash devices.
+
+config LIBERTAS_SDIO
+ tristate "Marvell Libertas 8385/8686/8688 SDIO 802.11b/g cards"
+ depends on LIBERTAS && MMC
+ ---help---
+ A driver for Marvell Libertas 8385/8686/8688 SDIO devices.
+
+config LIBERTAS_SPI
+ tristate "Marvell Libertas 8686 SPI 802.11b/g cards"
+ depends on LIBERTAS && SPI
+ ---help---
+ A driver for Marvell Libertas 8686 SPI devices.
+
+config LIBERTAS_DEBUG
+ bool "Enable full debugging output in the Libertas module."
+ depends on LIBERTAS
+ ---help---
+ Debugging support.
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
index 0b6918584503..fa37039e0eae 100644
--- a/drivers/net/wireless/libertas/Makefile
+++ b/drivers/net/wireless/libertas/Makefile
@@ -1,5 +1,15 @@
-libertas-objs := main.o wext.o rx.o tx.o cmd.o cmdresp.o scan.o 11d.o \
- debugfs.o persistcfg.o ethtool.o assoc.o
+libertas-y += assoc.o
+libertas-y += cfg.o
+libertas-y += cmd.o
+libertas-y += cmdresp.o
+libertas-y += debugfs.o
+libertas-y += ethtool.o
+libertas-y += main.o
+libertas-y += persistcfg.o
+libertas-y += rx.o
+libertas-y += scan.o
+libertas-y += tx.o
+libertas-y += wext.o
usb8xxx-objs += if_usb.o
libertas_cs-objs += if_cs.o
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
index ab6a2d518af0..2726c044430f 100644
--- a/drivers/net/wireless/libertas/README
+++ b/drivers/net/wireless/libertas/README
@@ -1,5 +1,5 @@
================================================================================
- README for USB8388
+ README for Libertas
(c) Copyright © 2003-2006, Marvell International Ltd.
All Rights Reserved
@@ -226,4 +226,28 @@ setuserscan
All entries in the scan table (not just the new scan data when keep=1)
will be displayed upon completion by use of the getscantable ioctl.
+========================
+IWCONFIG COMMANDS
+========================
+power period
+
+ This command is used to configure the station in deep sleep mode /
+ auto deep sleep mode.
+
+ The timer is implemented to monitor the activities (command, event,
+ etc.). When an activity is detected station will exit from deep
+ sleep mode automatically and restart the timer. At timer expiry
+ (no activity for defined time period) the deep sleep mode is entered
+ automatically.
+
+ Note: this command is for SDIO interface only.
+
+ Usage:
+ To enable deep sleep mode do:
+ iwconfig wlan0 power period 0
+ To enable auto deep sleep mode with idle time period 5 seconds do:
+ iwconfig wlan0 power period 5
+ To disable deep sleep/auto deep sleep mode do:
+ iwconfig wlan0 power period -1
+
==============================================================================
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index dd8732611ba9..751067369ba8 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -23,6 +23,13 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) =
*/
#define CAPINFO_MASK (~(0xda00))
+/**
+ * 802.11b/g supported bitrates (in 500Kb/s units)
+ */
+u8 lbs_bg_rates[MAX_RATES] =
+ { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+0x00, 0x00 };
+
/**
* @brief This function finds common rates between rates and card rates.
@@ -147,6 +154,397 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth
}
+int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
+ struct assoc_request *assoc)
+{
+ struct cmd_ds_802_11_set_wep cmd;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP);
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+
+ cmd.action = cpu_to_le16(cmd_action);
+
+ if (cmd_action == CMD_ACT_ADD) {
+ int i;
+
+ /* default tx key index */
+ cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx &
+ CMD_WEP_KEY_INDEX_MASK);
+
+ /* Copy key types and material to host command structure */
+ for (i = 0; i < 4; i++) {
+ struct enc_key *pkey = &assoc->wep_keys[i];
+
+ switch (pkey->len) {
+ case KEY_LEN_WEP_40:
+ cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
+ memmove(cmd.keymaterial[i], pkey->key, pkey->len);
+ lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
+ break;
+ case KEY_LEN_WEP_104:
+ cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
+ memmove(cmd.keymaterial[i], pkey->key, pkey->len);
+ lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
+ break;
+ case 0:
+ break;
+ default:
+ lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
+ i, pkey->len);
+ ret = -1;
+ goto done;
+ break;
+ }
+ }
+ } else if (cmd_action == CMD_ACT_REMOVE) {
+ /* ACT_REMOVE clears _all_ WEP keys */
+
+ /* default tx key index */
+ cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx &
+ CMD_WEP_KEY_INDEX_MASK);
+ lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
+ }
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
+done:
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
+ uint16_t *enable)
+{
+ struct cmd_ds_802_11_enable_rsn cmd;
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ cmd.action = cpu_to_le16(cmd_action);
+
+ if (cmd_action == CMD_ACT_GET)
+ cmd.enable = 0;
+ else {
+ if (*enable)
+ cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
+ else
+ cmd.enable = cpu_to_le16(CMD_DISABLE_RSN);
+ lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
+ }
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
+ if (!ret && cmd_action == CMD_ACT_GET)
+ *enable = le16_to_cpu(cmd.enable);
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam,
+ struct enc_key *key)
+{
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (key->flags & KEY_INFO_WPA_ENABLED)
+ keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
+ if (key->flags & KEY_INFO_WPA_UNICAST)
+ keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
+ if (key->flags & KEY_INFO_WPA_MCAST)
+ keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
+
+ keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ keyparam->keytypeid = cpu_to_le16(key->type);
+ keyparam->keylen = cpu_to_le16(key->len);
+ memcpy(keyparam->key, key->key, key->len);
+
+ /* Length field doesn't include the {type,length} header */
+ keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4);
+ lbs_deb_leave(LBS_DEB_CMD);
+}
+
+int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
+ struct assoc_request *assoc)
+{
+ struct cmd_ds_802_11_key_material cmd;
+ int ret = 0;
+ int index = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ cmd.action = cpu_to_le16(cmd_action);
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+
+ if (cmd_action == CMD_ACT_GET) {
+ cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_header) + 2);
+ } else {
+ memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet));
+
+ if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) {
+ set_one_wpa_key(&cmd.keyParamSet[index],
+ &assoc->wpa_unicast_key);
+ index++;
+ }
+
+ if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) {
+ set_one_wpa_key(&cmd.keyParamSet[index],
+ &assoc->wpa_mcast_key);
+ index++;
+ }
+
+ /* The common header and as many keys as we included */
+ cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd),
+ keyParamSet[index]));
+ }
+ ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
+ /* Copy the returned key to driver private data */
+ if (!ret && cmd_action == CMD_ACT_GET) {
+ void *buf_ptr = cmd.keyParamSet;
+ void *resp_end = &(&cmd)[1];
+
+ while (buf_ptr < resp_end) {
+ struct MrvlIEtype_keyParamSet *keyparam = buf_ptr;
+ struct enc_key *key;
+ uint16_t param_set_len = le16_to_cpu(keyparam->length);
+ uint16_t key_len = le16_to_cpu(keyparam->keylen);
+ uint16_t key_flags = le16_to_cpu(keyparam->keyinfo);
+ uint16_t key_type = le16_to_cpu(keyparam->keytypeid);
+ void *end;
+
+ end = (void *)keyparam + sizeof(keyparam->type)
+ + sizeof(keyparam->length) + param_set_len;
+
+ /* Make sure we don't access past the end of the IEs */
+ if (end > resp_end)
+ break;
+
+ if (key_flags & KEY_INFO_WPA_UNICAST)
+ key = &priv->wpa_unicast_key;
+ else if (key_flags & KEY_INFO_WPA_MCAST)
+ key = &priv->wpa_mcast_key;
+ else
+ break;
+
+ /* Copy returned key into driver */
+ memset(key, 0, sizeof(struct enc_key));
+ if (key_len > sizeof(key->key))
+ break;
+ key->type = key_type;
+ key->flags = key_flags;
+ key->len = key_len;
+ memcpy(key->key, keyparam->key, key->len);
+
+ buf_ptr = end + 1;
+ }
+ }
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok)
+{
+/* Bit Rate
+* 15:13 Reserved
+* 12 54 Mbps
+* 11 48 Mbps
+* 10 36 Mbps
+* 9 24 Mbps
+* 8 18 Mbps
+* 7 12 Mbps
+* 6 9 Mbps
+* 5 6 Mbps
+* 4 Reserved
+* 3 11 Mbps
+* 2 5.5 Mbps
+* 1 2 Mbps
+* 0 1 Mbps
+**/
+
+ uint16_t ratemask;
+ int i = lbs_data_rate_to_fw_index(rate);
+ if (lower_rates_ok)
+ ratemask = (0x1fef >> (12 - i));
+ else
+ ratemask = (1 << i);
+ return cpu_to_le16(ratemask);
+}
+
+int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
+ uint16_t cmd_action)
+{
+ struct cmd_ds_802_11_rate_adapt_rateset cmd;
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (!priv->cur_rate && !priv->enablehwauto)
+ return -EINVAL;
+
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+
+ cmd.action = cpu_to_le16(cmd_action);
+ cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
+ cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
+ ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
+ if (!ret && cmd_action == CMD_ACT_GET) {
+ priv->ratebitmap = le16_to_cpu(cmd.bitmap);
+ priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
+ }
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+/**
+ * @brief Set the data rate
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param rate The desired data rate, or 0 to clear a locked rate
+ *
+ * @return 0 on success, error on failure
+ */
+int lbs_set_data_rate(struct lbs_private *priv, u8 rate)
+{
+ struct cmd_ds_802_11_data_rate cmd;
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+
+ if (rate > 0) {
+ cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE);
+ cmd.rates[0] = lbs_data_rate_to_fw_index(rate);
+ if (cmd.rates[0] == 0) {
+ lbs_deb_cmd("DATA_RATE: invalid requested rate of"
+ " 0x%02X\n", rate);
+ ret = 0;
+ goto out;
+ }
+ lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]);
+ } else {
+ cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO);
+ lbs_deb_cmd("DATA_RATE: setting auto\n");
+ }
+
+ ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
+ if (ret)
+ goto out;
+
+ lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof(cmd));
+
+ /* FIXME: get actual rates FW can do if this command actually returns
+ * all data rates supported.
+ */
+ priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]);
+ lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate);
+
+out:
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+
+int lbs_cmd_802_11_rssi(struct lbs_private *priv,
+ struct cmd_ds_command *cmd)
+{
+
+ lbs_deb_enter(LBS_DEB_CMD);
+ cmd->command = cpu_to_le16(CMD_802_11_RSSI);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) +
+ sizeof(struct cmd_header));
+ cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
+
+ /* reset Beacon SNR/NF/RSSI values */
+ priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
+ priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
+ priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
+ priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
+ priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
+ priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+}
+
+int lbs_ret_802_11_rssi(struct lbs_private *priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ /* store the non average value */
+ priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR);
+ priv->NF[TYPE_BEACON][TYPE_NOAVG] =
+ get_unaligned_le16(&rssirsp->noisefloor);
+
+ priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR);
+ priv->NF[TYPE_BEACON][TYPE_AVG] =
+ get_unaligned_le16(&rssirsp->avgnoisefloor);
+
+ priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
+ CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
+ priv->NF[TYPE_BEACON][TYPE_NOAVG]);
+
+ priv->RSSI[TYPE_BEACON][TYPE_AVG] =
+ CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
+ priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
+
+ lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
+ priv->RSSI[TYPE_BEACON][TYPE_NOAVG],
+ priv->RSSI[TYPE_BEACON][TYPE_AVG]);
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+}
+
+
+int lbs_cmd_bcn_ctrl(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ struct cmd_ds_802_11_beacon_control
+ *bcn_ctrl = &cmd->params.bcn_ctrl;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
+ + sizeof(struct cmd_header));
+ cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);
+
+ bcn_ctrl->action = cpu_to_le16(cmd_action);
+ bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
+ bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+}
+
+int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_beacon_control *bcn_ctrl =
+ &resp->params.bcn_ctrl;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (bcn_ctrl->action == CMD_ACT_GET) {
+ priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
+ priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
+ }
+
+ lbs_deb_enter(LBS_DEB_CMD);
+ return 0;
+}
+
+
+
static int lbs_assoc_post(struct lbs_private *priv,
struct cmd_ds_802_11_associate_response *resp)
{
@@ -226,7 +624,7 @@ static int lbs_assoc_post(struct lbs_private *priv,
priv->connect_status = LBS_CONNECTED;
/* Update current SSID and BSSID */
- memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
+ memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN);
priv->curbssparams.ssid_len = bss->ssid_len;
memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
@@ -369,12 +767,7 @@ static int lbs_associate(struct lbs_private *priv,
(u16)(pos - (u8 *) &cmd.iebuf));
/* update curbssparams */
- priv->curbssparams.channel = bss->phy.ds.channel;
-
- if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
- ret = -1;
- goto done;
- }
+ priv->channel = bss->phy.ds.channel;
ret = lbs_cmd_with_response(priv, command, &cmd);
if (ret == 0) {
@@ -472,7 +865,7 @@ static int lbs_adhoc_post(struct lbs_private *priv,
memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
/* Set the new SSID to current SSID */
- memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
+ memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN);
priv->curbssparams.ssid_len = bss->ssid_len;
netif_carrier_on(priv->dev);
@@ -487,7 +880,7 @@ static int lbs_adhoc_post(struct lbs_private *priv,
lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n",
print_ssid(ssid, bss->ssid, bss->ssid_len),
priv->curbssparams.bssid,
- priv->curbssparams.channel);
+ priv->channel);
done:
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
@@ -560,7 +953,7 @@ static int lbs_adhoc_join(struct lbs_private *priv,
lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
priv->adhoccreate = 0;
- priv->curbssparams.channel = bss->channel;
+ priv->channel = bss->channel;
/* Build the join command */
memset(&cmd, 0, sizeof(cmd));
@@ -633,11 +1026,6 @@ static int lbs_adhoc_join(struct lbs_private *priv,
}
}
- if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
- ret = -1;
- goto out;
- }
-
ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
if (ret == 0) {
ret = lbs_adhoc_post(priv,
@@ -737,12 +1125,6 @@ static int lbs_adhoc_start(struct lbs_private *priv,
lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n",
cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]);
- if (lbs_create_dnld_countryinfo_11d(priv)) {
- lbs_deb_join("ADHOC_START: dnld_countryinfo_11d failed\n");
- ret = -1;
- goto out;
- }
-
lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n",
assoc_req->channel, assoc_req->band);
@@ -1099,7 +1481,7 @@ static int assoc_helper_essid(struct lbs_private *priv,
/* else send START command */
lbs_deb_assoc("SSID not found, creating adhoc network\n");
memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
- IW_ESSID_MAX_SIZE);
+ IEEE80211_MAX_SSID_LEN);
assoc_req->bss.ssid_len = assoc_req->ssid_len;
lbs_adhoc_start(priv, assoc_req);
}
@@ -1185,7 +1567,8 @@ static int assoc_helper_mode(struct lbs_private *priv,
}
priv->mode = assoc_req->mode;
- ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, assoc_req->mode);
+ ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE,
+ assoc_req->mode == IW_MODE_ADHOC ? 2 : 1);
done:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@@ -1205,7 +1588,7 @@ static int assoc_helper_channel(struct lbs_private *priv,
goto done;
}
- if (assoc_req->channel == priv->curbssparams.channel)
+ if (assoc_req->channel == priv->channel)
goto done;
if (priv->mesh_dev) {
@@ -1217,7 +1600,7 @@ static int assoc_helper_channel(struct lbs_private *priv,
}
lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
- priv->curbssparams.channel, assoc_req->channel);
+ priv->channel, assoc_req->channel);
ret = lbs_set_channel(priv, assoc_req->channel);
if (ret < 0)
@@ -1232,7 +1615,7 @@ static int assoc_helper_channel(struct lbs_private *priv,
goto done;
}
- if (assoc_req->channel != priv->curbssparams.channel) {
+ if (assoc_req->channel != priv->channel) {
lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n",
assoc_req->channel);
goto restore_mesh;
@@ -1253,7 +1636,7 @@ static int assoc_helper_channel(struct lbs_private *priv,
restore_mesh:
if (priv->mesh_dev)
lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->curbssparams.channel);
+ priv->channel);
done:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@@ -1475,7 +1858,7 @@ static int should_stop_adhoc(struct lbs_private *priv,
}
if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
- if (assoc_req->channel != priv->curbssparams.channel)
+ if (assoc_req->channel != priv->channel)
return 1;
}
@@ -1557,7 +1940,7 @@ static int lbs_find_best_network_ssid(struct lbs_private *priv,
found = lbs_find_best_ssid_in_list(priv, preferred_mode);
if (found && (found->ssid_len > 0)) {
- memcpy(out_ssid, &found->ssid, IW_ESSID_MAX_SIZE);
+ memcpy(out_ssid, &found->ssid, IEEE80211_MAX_SSID_LEN);
*out_ssid_len = found->ssid_len;
*out_mode = found->mode;
ret = 0;
@@ -1775,12 +2158,12 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
assoc_req = priv->pending_assoc_req;
if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
memcpy(&assoc_req->ssid, &priv->curbssparams.ssid,
- IW_ESSID_MAX_SIZE);
+ IEEE80211_MAX_SSID_LEN);
assoc_req->ssid_len = priv->curbssparams.ssid_len;
}
if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
- assoc_req->channel = priv->curbssparams.channel;
+ assoc_req->channel = priv->channel;
if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
assoc_req->band = priv->curbssparams.band;
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
index 6e765e9f91a3..40621b789fc5 100644
--- a/drivers/net/wireless/libertas/assoc.h
+++ b/drivers/net/wireless/libertas/assoc.h
@@ -3,7 +3,126 @@
#ifndef _LBS_ASSOC_H_
#define _LBS_ASSOC_H_
-#include "dev.h"
+
+#include "defs.h"
+#include "host.h"
+
+
+struct lbs_private;
+
+/*
+ * In theory, the IE is limited to the IE length, 255,
+ * but in practice 64 bytes are enough.
+ */
+#define MAX_WPA_IE_LEN 64
+
+
+
+struct lbs_802_11_security {
+ u8 WPAenabled;
+ u8 WPA2enabled;
+ u8 wep_enabled;
+ u8 auth_mode;
+ u32 key_mgmt;
+};
+
+/** Current Basic Service Set State Structure */
+struct current_bss_params {
+ /** bssid */
+ u8 bssid[ETH_ALEN];
+ /** ssid */
+ u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
+ u8 ssid_len;
+
+ /** band */
+ u8 band;
+ /** channel is directly in priv->channel */
+ /** zero-terminated array of supported data rates */
+ u8 rates[MAX_RATES + 1];
+};
+
+/**
+ * @brief Structure used to store information for each beacon/probe response
+ */
+struct bss_descriptor {
+ u8 bssid[ETH_ALEN];
+
+ u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
+ u8 ssid_len;
+
+ u16 capability;
+ u32 rssi;
+ u32 channel;
+ u16 beaconperiod;
+ __le16 atimwindow;
+
+ /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
+ u8 mode;
+
+ /* zero-terminated array of supported data rates */
+ u8 rates[MAX_RATES + 1];
+
+ unsigned long last_scanned;
+
+ union ieee_phy_param_set phy;
+ union ieee_ss_param_set ss;
+
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ size_t wpa_ie_len;
+ u8 rsn_ie[MAX_WPA_IE_LEN];
+ size_t rsn_ie_len;
+
+ u8 mesh;
+
+ struct list_head list;
+};
+
+/** Association request
+ *
+ * Encapsulates all the options that describe a specific assocation request
+ * or configuration of the wireless card's radio, mode, and security settings.
+ */
+struct assoc_request {
+#define ASSOC_FLAG_SSID 1
+#define ASSOC_FLAG_CHANNEL 2
+#define ASSOC_FLAG_BAND 3
+#define ASSOC_FLAG_MODE 4
+#define ASSOC_FLAG_BSSID 5
+#define ASSOC_FLAG_WEP_KEYS 6
+#define ASSOC_FLAG_WEP_TX_KEYIDX 7
+#define ASSOC_FLAG_WPA_MCAST_KEY 8
+#define ASSOC_FLAG_WPA_UCAST_KEY 9
+#define ASSOC_FLAG_SECINFO 10
+#define ASSOC_FLAG_WPA_IE 11
+ unsigned long flags;
+
+ u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
+ u8 ssid_len;
+ u8 channel;
+ u8 band;
+ u8 mode;
+ u8 bssid[ETH_ALEN] __attribute__ ((aligned (2)));
+
+ /** WEP keys */
+ struct enc_key wep_keys[4];
+ u16 wep_tx_keyidx;
+
+ /** WPA keys */
+ struct enc_key wpa_mcast_key;
+ struct enc_key wpa_unicast_key;
+
+ struct lbs_802_11_security secinfo;
+
+ /** WPA Information Elements*/
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ u8 wpa_ie_len;
+
+ /* BSS to associate with for infrastructure of Ad-Hoc join */
+ struct bss_descriptor bss;
+};
+
+
+extern u8 lbs_bg_rates[MAX_RATES];
void lbs_association_worker(struct work_struct *work);
struct assoc_request *lbs_get_association_request(struct lbs_private *priv);
@@ -13,4 +132,24 @@ int lbs_adhoc_stop(struct lbs_private *priv);
int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
u8 bssid[ETH_ALEN], u16 reason);
+int lbs_cmd_802_11_rssi(struct lbs_private *priv,
+ struct cmd_ds_command *cmd);
+int lbs_ret_802_11_rssi(struct lbs_private *priv,
+ struct cmd_ds_command *resp);
+
+int lbs_cmd_bcn_ctrl(struct lbs_private *priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action);
+int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv,
+ struct cmd_ds_command *resp);
+
+int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
+ struct assoc_request *assoc);
+
+int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
+ uint16_t *enable);
+
+int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
+ struct assoc_request *assoc);
+
#endif /* _LBS_ASSOC_H */
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
new file mode 100644
index 000000000000..4396dccd12ac
--- /dev/null
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -0,0 +1,198 @@
+/*
+ * Implement cfg80211 ("iw") support.
+ *
+ * Copyright (C) 2009 M&N Solutions GmbH, 61191 Rosbach, Germany
+ * Holger Schurig <hs4233@mail.mn-solutions.de>
+ *
+ */
+
+#include <net/cfg80211.h>
+
+#include "cfg.h"
+#include "cmd.h"
+
+
+#define CHAN2G(_channel, _freq, _flags) { \
+ .band = IEEE80211_BAND_2GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_channel), \
+ .flags = (_flags), \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+
+static struct ieee80211_channel lbs_2ghz_channels[] = {
+ CHAN2G(1, 2412, 0),
+ CHAN2G(2, 2417, 0),
+ CHAN2G(3, 2422, 0),
+ CHAN2G(4, 2427, 0),
+ CHAN2G(5, 2432, 0),
+ CHAN2G(6, 2437, 0),
+ CHAN2G(7, 2442, 0),
+ CHAN2G(8, 2447, 0),
+ CHAN2G(9, 2452, 0),
+ CHAN2G(10, 2457, 0),
+ CHAN2G(11, 2462, 0),
+ CHAN2G(12, 2467, 0),
+ CHAN2G(13, 2472, 0),
+ CHAN2G(14, 2484, 0),
+};
+
+#define RATETAB_ENT(_rate, _rateid, _flags) { \
+ .bitrate = (_rate), \
+ .hw_value = (_rateid), \
+ .flags = (_flags), \
+}
+
+
+static struct ieee80211_rate lbs_rates[] = {
+ RATETAB_ENT(10, 0x1, 0),
+ RATETAB_ENT(20, 0x2, 0),
+ RATETAB_ENT(55, 0x4, 0),
+ RATETAB_ENT(110, 0x8, 0),
+ RATETAB_ENT(60, 0x10, 0),
+ RATETAB_ENT(90, 0x20, 0),
+ RATETAB_ENT(120, 0x40, 0),
+ RATETAB_ENT(180, 0x80, 0),
+ RATETAB_ENT(240, 0x100, 0),
+ RATETAB_ENT(360, 0x200, 0),
+ RATETAB_ENT(480, 0x400, 0),
+ RATETAB_ENT(540, 0x800, 0),
+};
+
+static struct ieee80211_supported_band lbs_band_2ghz = {
+ .channels = lbs_2ghz_channels,
+ .n_channels = ARRAY_SIZE(lbs_2ghz_channels),
+ .bitrates = lbs_rates,
+ .n_bitrates = ARRAY_SIZE(lbs_rates),
+};
+
+
+static const u32 cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+};
+
+
+
+static int lbs_cfg_set_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ int ret = -ENOTSUPP;
+
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d", chan->center_freq, channel_type);
+
+ if (channel_type != NL80211_CHAN_NO_HT)
+ goto out;
+
+ ret = lbs_set_channel(priv, chan->hw_value);
+
+ out:
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+
+
+
+static struct cfg80211_ops lbs_cfg80211_ops = {
+ .set_channel = lbs_cfg_set_channel,
+};
+
+
+/*
+ * At this time lbs_private *priv doesn't even exist, so we just allocate
+ * memory and don't initialize the wiphy further. This is postponed until we
+ * can talk to the firmware and happens at registration time in
+ * lbs_cfg_wiphy_register().
+ */
+struct wireless_dev *lbs_cfg_alloc(struct device *dev)
+{
+ int ret = 0;
+ struct wireless_dev *wdev;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+ if (!wdev) {
+ dev_err(dev, "cannot allocate wireless device\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ wdev->wiphy = wiphy_new(&lbs_cfg80211_ops, sizeof(struct lbs_private));
+ if (!wdev->wiphy) {
+ dev_err(dev, "cannot allocate wiphy\n");
+ ret = -ENOMEM;
+ goto err_wiphy_new;
+ }
+
+ lbs_deb_leave(LBS_DEB_CFG80211);
+ return wdev;
+
+ err_wiphy_new:
+ kfree(wdev);
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ERR_PTR(ret);
+}
+
+
+/*
+ * This function get's called after lbs_setup_firmware() determined the
+ * firmware capabities. So we can setup the wiphy according to our
+ * hardware/firmware.
+ */
+int lbs_cfg_register(struct lbs_private *priv)
+{
+ struct wireless_dev *wdev = priv->wdev;
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ wdev->wiphy->max_scan_ssids = 1;
+ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+ /* TODO: BIT(NL80211_IFTYPE_ADHOC); */
+ wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+
+ /* TODO: honor priv->regioncode */
+ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz;
+
+ /*
+ * We could check priv->fwcapinfo && FW_CAPINFO_WPA, but I have
+ * never seen a firmware without WPA
+ */
+ wdev->wiphy->cipher_suites = cipher_suites;
+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
+ ret = wiphy_register(wdev->wiphy);
+ if (ret < 0)
+ lbs_pr_err("cannot register wiphy device\n");
+
+ ret = register_netdev(priv->dev);
+ if (ret)
+ lbs_pr_err("cannot register network device\n");
+
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+
+void lbs_cfg_free(struct lbs_private *priv)
+{
+ struct wireless_dev *wdev = priv->wdev;
+
+ lbs_deb_enter(LBS_DEB_CFG80211);
+
+ if (!wdev)
+ return;
+
+ if (wdev->wiphy) {
+ wiphy_unregister(wdev->wiphy);
+ wiphy_free(wdev->wiphy);
+ }
+ kfree(wdev);
+}
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h
new file mode 100644
index 000000000000..e09a193a34d6
--- /dev/null
+++ b/drivers/net/wireless/libertas/cfg.h
@@ -0,0 +1,16 @@
+#ifndef __LBS_CFG80211_H__
+#define __LBS_CFG80211_H__
+
+#include "dev.h"
+
+struct wireless_dev *lbs_cfg_alloc(struct device *dev);
+int lbs_cfg_register(struct lbs_private *priv);
+void lbs_cfg_free(struct lbs_private *priv);
+
+int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,
+ u8 ssid_len);
+int lbs_scan_networks(struct lbs_private *priv, int full_scan);
+void lbs_cfg_scan_worker(struct work_struct *work);
+
+
+#endif
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 0a324dcd264c..1065ce29cd08 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -3,21 +3,21 @@
* It prepares command and sends it to firmware when it is ready.
*/
-#include <net/iw_handler.h>
#include <net/lib80211.h>
#include <linux/kfifo.h>
#include <linux/sched.h>
+
#include "host.h"
-#include "hostcmd.h"
#include "decl.h"
#include "defs.h"
#include "dev.h"
#include "assoc.h"
#include "wext.h"
+#include "scan.h"
#include "cmd.h"
-static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
+static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
/**
* @brief Simple callback that copies response back into command
@@ -77,6 +77,30 @@ static u8 is_command_allowed_in_ps(u16 cmd)
}
/**
+ * @brief This function checks if the command is allowed.
+ *
+ * @param priv A pointer to lbs_private structure
+ * @return allowed or not allowed.
+ */
+
+static int lbs_is_cmd_allowed(struct lbs_private *priv)
+{
+ int ret = 1;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (!priv->is_auto_deep_sleep_enabled) {
+ if (priv->is_deep_sleep) {
+ lbs_deb_cmd("command not allowed in deep sleep\n");
+ ret = 0;
+ }
+ }
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return ret;
+}
+
+/**
* @brief Updates the hardware details like MAC address and regulatory region
*
* @param priv A pointer to struct lbs_private structure
@@ -169,11 +193,6 @@ int lbs_update_hw_spec(struct lbs_private *priv)
goto out;
}
- if (lbs_set_universaltable(priv, 0)) {
- ret = -1;
- goto out;
- }
-
out:
lbs_deb_leave(LBS_DEB_CMD);
return ret;
@@ -222,7 +241,7 @@ static int lbs_cmd_802_11_ps_mode(struct cmd_ds_command *cmd,
cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
- S_DS_GEN);
+ sizeof(struct cmd_header));
psm->action = cpu_to_le16(cmd_action);
psm->multipledtim = 0;
switch (cmd_action) {
@@ -251,33 +270,6 @@ static int lbs_cmd_802_11_ps_mode(struct cmd_ds_command *cmd,
return 0;
}
-int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
- uint16_t cmd_action, uint16_t *timeout)
-{
- struct cmd_ds_802_11_inactivity_timeout cmd;
- int ret;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- cmd.hdr.command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- cmd.action = cpu_to_le16(cmd_action);
-
- if (cmd_action == CMD_ACT_SET)
- cmd.timeout = cpu_to_le16(*timeout);
- else
- cmd.timeout = 0;
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_INACTIVITY_TIMEOUT, &cmd);
-
- if (!ret)
- *timeout = le16_to_cpu(cmd.timeout);
-
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return 0;
-}
-
int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
struct sleep_params *sp)
{
@@ -320,190 +312,53 @@ int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
return 0;
}
-int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
- struct assoc_request *assoc)
+static int lbs_wait_for_ds_awake(struct lbs_private *priv)
{
- struct cmd_ds_802_11_set_wep cmd;
int ret = 0;
lbs_deb_enter(LBS_DEB_CMD);
- memset(&cmd, 0, sizeof(cmd));
- cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP);
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- cmd.action = cpu_to_le16(cmd_action);
-
- if (cmd_action == CMD_ACT_ADD) {
- int i;
-
- /* default tx key index */
- cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx &
- CMD_WEP_KEY_INDEX_MASK);
-
- /* Copy key types and material to host command structure */
- for (i = 0; i < 4; i++) {
- struct enc_key *pkey = &assoc->wep_keys[i];
-
- switch (pkey->len) {
- case KEY_LEN_WEP_40:
- cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
- memmove(cmd.keymaterial[i], pkey->key, pkey->len);
- lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
- break;
- case KEY_LEN_WEP_104:
- cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
- memmove(cmd.keymaterial[i], pkey->key, pkey->len);
- lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
- break;
- case 0:
- break;
- default:
- lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
- i, pkey->len);
- ret = -1;
- goto done;
- break;
- }
+ if (priv->is_deep_sleep) {
+ if (!wait_event_interruptible_timeout(priv->ds_awake_q,
+ !priv->is_deep_sleep, (10 * HZ))) {
+ lbs_pr_err("ds_awake_q: timer expired\n");
+ ret = -1;
}
- } else if (cmd_action == CMD_ACT_REMOVE) {
- /* ACT_REMOVE clears _all_ WEP keys */
-
- /* default tx key index */
- cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx &
- CMD_WEP_KEY_INDEX_MASK);
- lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
- }
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
-done:
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-
-int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
- uint16_t *enable)
-{
- struct cmd_ds_802_11_enable_rsn cmd;
- int ret;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
- cmd.action = cpu_to_le16(cmd_action);
-
- if (cmd_action == CMD_ACT_GET)
- cmd.enable = 0;
- else {
- if (*enable)
- cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
- else
- cmd.enable = cpu_to_le16(CMD_DISABLE_RSN);
- lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
}
- ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
- if (!ret && cmd_action == CMD_ACT_GET)
- *enable = le16_to_cpu(cmd.enable);
-
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
-static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam,
- struct enc_key *key)
-{
- lbs_deb_enter(LBS_DEB_CMD);
-
- if (key->flags & KEY_INFO_WPA_ENABLED)
- keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
- if (key->flags & KEY_INFO_WPA_UNICAST)
- keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
- if (key->flags & KEY_INFO_WPA_MCAST)
- keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
-
- keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
- keyparam->keytypeid = cpu_to_le16(key->type);
- keyparam->keylen = cpu_to_le16(key->len);
- memcpy(keyparam->key, key->key, key->len);
-
- /* Length field doesn't include the {type,length} header */
- keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4);
- lbs_deb_leave(LBS_DEB_CMD);
-}
-
-int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
- struct assoc_request *assoc)
+int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
{
- struct cmd_ds_802_11_key_material cmd;
- int ret = 0;
- int index = 0;
+ int ret = 0;
lbs_deb_enter(LBS_DEB_CMD);
- cmd.action = cpu_to_le16(cmd_action);
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- if (cmd_action == CMD_ACT_GET) {
- cmd.hdr.size = cpu_to_le16(S_DS_GEN + 2);
- } else {
- memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet));
-
- if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) {
- set_one_wpa_key(&cmd.keyParamSet[index],
- &assoc->wpa_unicast_key);
- index++;
- }
-
- if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) {
- set_one_wpa_key(&cmd.keyParamSet[index],
- &assoc->wpa_mcast_key);
- index++;
+ if (deep_sleep) {
+ if (priv->is_deep_sleep != 1) {
+ lbs_deb_cmd("deep sleep: sleep\n");
+ BUG_ON(!priv->enter_deep_sleep);
+ ret = priv->enter_deep_sleep(priv);
+ if (!ret) {
+ netif_stop_queue(priv->dev);
+ netif_carrier_off(priv->dev);
+ }
+ } else {
+ lbs_pr_err("deep sleep: already enabled\n");
}
-
- /* The common header and as many keys as we included */
- cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd),
- keyParamSet[index]));
- }
- ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
- /* Copy the returned key to driver private data */
- if (!ret && cmd_action == CMD_ACT_GET) {
- void *buf_ptr = cmd.keyParamSet;
- void *resp_end = &(&cmd)[1];
-
- while (buf_ptr < resp_end) {
- struct MrvlIEtype_keyParamSet *keyparam = buf_ptr;
- struct enc_key *key;
- uint16_t param_set_len = le16_to_cpu(keyparam->length);
- uint16_t key_len = le16_to_cpu(keyparam->keylen);
- uint16_t key_flags = le16_to_cpu(keyparam->keyinfo);
- uint16_t key_type = le16_to_cpu(keyparam->keytypeid);
- void *end;
-
- end = (void *)keyparam + sizeof(keyparam->type)
- + sizeof(keyparam->length) + param_set_len;
-
- /* Make sure we don't access past the end of the IEs */
- if (end > resp_end)
- break;
-
- if (key_flags & KEY_INFO_WPA_UNICAST)
- key = &priv->wpa_unicast_key;
- else if (key_flags & KEY_INFO_WPA_MCAST)
- key = &priv->wpa_mcast_key;
- else
- break;
-
- /* Copy returned key into driver */
- memset(key, 0, sizeof(struct enc_key));
- if (key_len > sizeof(key->key))
- break;
- key->type = key_type;
- key->flags = key_flags;
- key->len = key_len;
- memcpy(key->key, keyparam->key, key->len);
-
- buf_ptr = end + 1;
+ } else {
+ if (priv->is_deep_sleep) {
+ lbs_deb_cmd("deep sleep: wakeup\n");
+ BUG_ON(!priv->exit_deep_sleep);
+ ret = priv->exit_deep_sleep(priv);
+ if (!ret) {
+ ret = lbs_wait_for_ds_awake(priv);
+ if (ret)
+ lbs_pr_err("deep sleep: wakeup"
+ "failed\n");
+ }
}
}
@@ -535,7 +390,7 @@ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val)
switch (oid) {
case SNMP_MIB_OID_BSS_TYPE:
cmd.bufsize = cpu_to_le16(sizeof(u8));
- cmd.value[0] = (val == IW_MODE_ADHOC) ? 2 : 1;
+ cmd.value[0] = val;
break;
case SNMP_MIB_OID_11D_ENABLE:
case SNMP_MIB_OID_FRAG_THRESHOLD:
@@ -588,13 +443,7 @@ int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val)
switch (le16_to_cpu(cmd.bufsize)) {
case sizeof(u8):
- if (oid == SNMP_MIB_OID_BSS_TYPE) {
- if (cmd.value[0] == 2)
- *out_val = IW_MODE_ADHOC;
- else
- *out_val = IW_MODE_INFRA;
- } else
- *out_val = cmd.value[0];
+ *out_val = cmd.value[0];
break;
case sizeof(u16):
*out_val = le16_to_cpu(*((__le16 *)(&cmd.value)));
@@ -681,7 +530,7 @@ static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
cmd->command = cpu_to_le16(CMD_802_11_MONITOR_MODE);
cmd->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_monitor_mode) +
- S_DS_GEN);
+ sizeof(struct cmd_header));
monitor->action = cpu_to_le16(cmd_action);
if (cmd_action == CMD_ACT_SET) {
@@ -692,111 +541,6 @@ static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
return 0;
}
-static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok)
-{
-/* Bit Rate
-* 15:13 Reserved
-* 12 54 Mbps
-* 11 48 Mbps
-* 10 36 Mbps
-* 9 24 Mbps
-* 8 18 Mbps
-* 7 12 Mbps
-* 6 9 Mbps
-* 5 6 Mbps
-* 4 Reserved
-* 3 11 Mbps
-* 2 5.5 Mbps
-* 1 2 Mbps
-* 0 1 Mbps
-**/
-
- uint16_t ratemask;
- int i = lbs_data_rate_to_fw_index(rate);
- if (lower_rates_ok)
- ratemask = (0x1fef >> (12 - i));
- else
- ratemask = (1 << i);
- return cpu_to_le16(ratemask);
-}
-
-int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
- uint16_t cmd_action)
-{
- struct cmd_ds_802_11_rate_adapt_rateset cmd;
- int ret;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- if (!priv->cur_rate && !priv->enablehwauto)
- return -EINVAL;
-
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- cmd.action = cpu_to_le16(cmd_action);
- cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
- cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
- ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
- if (!ret && cmd_action == CMD_ACT_GET) {
- priv->ratebitmap = le16_to_cpu(cmd.bitmap);
- priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
- }
-
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-EXPORT_SYMBOL_GPL(lbs_cmd_802_11_rate_adapt_rateset);
-
-/**
- * @brief Set the data rate
- *
- * @param priv A pointer to struct lbs_private structure
- * @param rate The desired data rate, or 0 to clear a locked rate
- *
- * @return 0 on success, error on failure
- */
-int lbs_set_data_rate(struct lbs_private *priv, u8 rate)
-{
- struct cmd_ds_802_11_data_rate cmd;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
- if (rate > 0) {
- cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE);
- cmd.rates[0] = lbs_data_rate_to_fw_index(rate);
- if (cmd.rates[0] == 0) {
- lbs_deb_cmd("DATA_RATE: invalid requested rate of"
- " 0x%02X\n", rate);
- ret = 0;
- goto out;
- }
- lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]);
- } else {
- cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO);
- lbs_deb_cmd("DATA_RATE: setting auto\n");
- }
-
- ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
- if (ret)
- goto out;
-
- lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd));
-
- /* FIXME: get actual rates FW can do if this command actually returns
- * all data rates supported.
- */
- priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]);
- lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate);
-
-out:
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
- return ret;
-}
-
/**
* @brief Get the radio channel
*
@@ -804,7 +548,7 @@ out:
*
* @return The channel on success, error on failure
*/
-int lbs_get_channel(struct lbs_private *priv)
+static int lbs_get_channel(struct lbs_private *priv)
{
struct cmd_ds_802_11_rf_channel cmd;
int ret = 0;
@@ -836,7 +580,7 @@ int lbs_update_channel(struct lbs_private *priv)
ret = lbs_get_channel(priv);
if (ret > 0) {
- priv->curbssparams.channel = ret;
+ priv->channel = ret;
ret = 0;
}
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@@ -855,7 +599,7 @@ int lbs_set_channel(struct lbs_private *priv, u8 channel)
{
struct cmd_ds_802_11_rf_channel cmd;
#ifdef DEBUG
- u8 old_channel = priv->curbssparams.channel;
+ u8 old_channel = priv->channel;
#endif
int ret = 0;
@@ -870,36 +614,15 @@ int lbs_set_channel(struct lbs_private *priv, u8 channel)
if (ret)
goto out;
- priv->curbssparams.channel = (uint8_t) le16_to_cpu(cmd.channel);
+ priv->channel = (uint8_t) le16_to_cpu(cmd.channel);
lbs_deb_cmd("channel switch from %d to %d\n", old_channel,
- priv->curbssparams.channel);
+ priv->channel);
out:
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
-static int lbs_cmd_802_11_rssi(struct lbs_private *priv,
- struct cmd_ds_command *cmd)
-{
-
- lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(CMD_802_11_RSSI);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
- cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
-
- /* reset Beacon SNR/NF/RSSI values */
- priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
- priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
- priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
- priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
- priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
- priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
u8 cmd_action, void *pdata_buf)
{
@@ -916,7 +639,7 @@ static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
cmdptr->size =
cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
- + S_DS_GEN);
+ + sizeof(struct cmd_header));
macreg =
(struct cmd_ds_mac_reg_access *)&cmdptr->params.
macreg;
@@ -935,7 +658,7 @@ static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
cmdptr->size =
cpu_to_le16(sizeof
(struct cmd_ds_bbp_reg_access)
- + S_DS_GEN);
+ + sizeof(struct cmd_header));
bbpreg =
(struct cmd_ds_bbp_reg_access *)&cmdptr->params.
bbpreg;
@@ -954,7 +677,7 @@ static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
cmdptr->size =
cpu_to_le16(sizeof
(struct cmd_ds_rf_reg_access) +
- S_DS_GEN);
+ sizeof(struct cmd_header));
rfreg =
(struct cmd_ds_rf_reg_access *)&cmdptr->params.
rfreg;
@@ -981,7 +704,8 @@ static int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
cmd->command = cpu_to_le16(CMD_BT_ACCESS);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) +
+ sizeof(struct cmd_header));
cmd->result = 0;
bt_access->action = cpu_to_le16(cmd_action);
@@ -1018,7 +742,8 @@ static int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) +
+ sizeof(struct cmd_header));
cmd->result = 0;
if (pdata_buf)
@@ -1124,7 +849,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
ie->val.mesh_id_len = priv->mesh_ssid_len;
memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
ie->len = sizeof(struct mrvl_meshie_val) -
- IW_ESSID_MAX_SIZE + priv->mesh_ssid_len;
+ IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
break;
case CMD_ACT_MESH_CONFIG_STOP:
@@ -1139,27 +864,6 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
}
-static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
- struct cmd_ds_command *cmd,
- u16 cmd_action)
-{
- struct cmd_ds_802_11_beacon_control
- *bcn_ctrl = &cmd->params.bcn_ctrl;
-
- lbs_deb_enter(LBS_DEB_CMD);
- cmd->size =
- cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
- + S_DS_GEN);
- cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);
-
- bcn_ctrl->action = cpu_to_le16(cmd_action);
- bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
- bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
static void lbs_queue_cmd(struct lbs_private *priv,
struct cmd_ctrl_node *cmdnode)
{
@@ -1243,8 +947,17 @@ static void lbs_submit_command(struct lbs_private *priv,
timeo = HZ/4;
}
- /* Setup the timer after transmit command */
- mod_timer(&priv->command_timer, jiffies + timeo);
+ if (command == CMD_802_11_DEEP_SLEEP) {
+ if (priv->is_auto_deep_sleep_enabled) {
+ priv->wakeup_dev_required = 1;
+ priv->dnld_sent = 0;
+ }
+ priv->is_deep_sleep = 1;
+ lbs_complete_command(priv, cmdnode, 0);
+ } else {
+ /* Setup the timer after transmit command */
+ mod_timer(&priv->command_timer, jiffies + timeo);
+ }
lbs_deb_leave(LBS_DEB_HOST);
}
@@ -1391,6 +1104,11 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
goto done;
}
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto done;
+ }
+
cmdnode = lbs_get_cmd_ctrl_node(priv);
if (cmdnode == NULL) {
@@ -1441,7 +1159,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
cmdptr->command = cpu_to_le16(cmd_no);
cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
- S_DS_GEN);
+ sizeof(struct cmd_header));
memmove(&cmdptr->params.afc,
pdata_buf, sizeof(struct cmd_ds_802_11_afc));
@@ -1449,45 +1167,17 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
ret = 0;
goto done;
- case CMD_802_11D_DOMAIN_INFO:
- ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
- cmd_no, cmd_action);
- break;
-
case CMD_802_11_TPC_CFG:
cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
cmdptr->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
- S_DS_GEN);
+ sizeof(struct cmd_header));
memmove(&cmdptr->params.tpccfg,
pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));
ret = 0;
break;
- case CMD_802_11_LED_GPIO_CTRL:
- {
- struct mrvl_ie_ledgpio *gpio =
- (struct mrvl_ie_ledgpio*)
- cmdptr->params.ledgpio.data;
-
- memmove(&cmdptr->params.ledgpio,
- pdata_buf,
- sizeof(struct cmd_ds_802_11_led_ctrl));
-
- cmdptr->command =
- cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
-
-#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
- cmdptr->size =
- cpu_to_le16(le16_to_cpu(gpio->header.len)
- + S_DS_GEN
- + ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
- gpio->header.len = gpio->header.len;
-
- ret = 0;
- break;
- }
case CMD_BT_ACCESS:
ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf);
@@ -1497,15 +1187,13 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf);
break;
- case CMD_GET_TSF:
- cmdptr->command = cpu_to_le16(CMD_GET_TSF);
- cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
- S_DS_GEN);
- ret = 0;
- break;
case CMD_802_11_BEACON_CTRL:
ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
break;
+ case CMD_802_11_DEEP_SLEEP:
+ cmdptr->command = cpu_to_le16(CMD_802_11_DEEP_SLEEP);
+ cmdptr->size = cpu_to_le16(sizeof(struct cmd_header));
+ break;
default:
lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
ret = -1;
@@ -1823,30 +1511,6 @@ done:
return ret;
}
-void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
-{
- union iwreq_data iwrq;
- u8 buf[50];
-
- lbs_deb_enter(LBS_DEB_WEXT);
-
- memset(&iwrq, 0, sizeof(union iwreq_data));
- memset(buf, 0, sizeof(buf));
-
- snprintf(buf, sizeof(buf) - 1, "%s", str);
-
- iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
-
- /* Send Event to upper layer */
- lbs_deb_wext("event indication string %s\n", (char *)buf);
- lbs_deb_wext("event indication length %d\n", iwrq.data.length);
- lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
-
- wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
-
- lbs_deb_leave(LBS_DEB_WEXT);
-}
-
static void lbs_send_confirmsleep(struct lbs_private *priv)
{
unsigned long flags;
@@ -2024,7 +1688,7 @@ int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
}
-static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
+struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
unsigned long callback_arg)
@@ -2039,6 +1703,11 @@ static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
goto done;
}
+ if (!lbs_is_cmd_allowed(priv)) {
+ cmdnode = ERR_PTR(-EBUSY);
+ goto done;
+ }
+
cmdnode = lbs_get_cmd_ctrl_node(priv);
if (cmdnode == NULL) {
lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
@@ -2117,5 +1786,3 @@ done:
return ret;
}
EXPORT_SYMBOL_GPL(__lbs_cmd);
-
-
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index 392e578ca095..2862748aef70 100644
--- a/drivers/net/wireless/libertas/cmd.h
+++ b/drivers/net/wireless/libertas/cmd.h
@@ -3,11 +3,30 @@
#ifndef _LBS_CMD_H_
#define _LBS_CMD_H_
-#include "hostcmd.h"
+#include "host.h"
#include "dev.h"
+
+/* Command & response transfer between host and card */
+
+struct cmd_ctrl_node {
+ struct list_head list;
+ int result;
+ /* command response */
+ int (*callback)(struct lbs_private *,
+ unsigned long,
+ struct cmd_header *);
+ unsigned long callback_arg;
+ /* command data */
+ struct cmd_header *cmdbuf;
+ /* wait queue */
+ u16 cmdwaitqwoken;
+ wait_queue_head_t cmdwait_q;
+};
+
+
/* lbs_cmd() infers the size of the buffer to copy data back into, from
- the size of the target of the pointer. Since the command to be sent
+ the size of the target of the pointer. Since the command to be sent
may often be smaller, that size is set in cmd->size by the caller.*/
#define lbs_cmd(priv, cmdnr, cmd, cb, cb_arg) ({ \
uint16_t __sz = le16_to_cpu((cmd)->hdr.size); \
@@ -18,6 +37,11 @@
#define lbs_cmd_with_response(priv, cmdnr, cmd) \
lbs_cmd(priv, cmdnr, cmd, lbs_cmd_copyback, (unsigned long) (cmd))
+int lbs_prepare_and_send_command(struct lbs_private *priv,
+ u16 cmd_no,
+ u16 cmd_action,
+ u16 wait_option, u32 cmd_oid, void *pdata_buf);
+
void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
struct cmd_header *in_cmd, int in_cmd_size);
@@ -26,62 +50,93 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command,
int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
unsigned long callback_arg);
-int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
- int8_t p1, int8_t p2);
+struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
+ uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
+ int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
+ unsigned long callback_arg);
-int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
- int8_t p2, int usesnr);
+int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
+ struct cmd_header *resp);
-int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
- int8_t p1, int8_t p2);
+int lbs_allocate_cmd_buffer(struct lbs_private *priv);
+int lbs_free_cmd_buffer(struct lbs_private *priv);
-int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
- int8_t p2, int usesnr);
+int lbs_execute_next_command(struct lbs_private *priv);
+void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
+ int result);
+int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
-int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
- struct cmd_header *resp);
-int lbs_update_hw_spec(struct lbs_private *priv);
+/* From cmdresp.c */
-int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
- struct cmd_ds_mesh_access *cmd);
+void lbs_mac_event_disconnected(struct lbs_private *priv);
-int lbs_set_data_rate(struct lbs_private *priv, u8 rate);
-int lbs_get_channel(struct lbs_private *priv);
+
+/* Events */
+
+int lbs_process_event(struct lbs_private *priv, u32 event);
+
+
+/* Actual commands */
+
+int lbs_update_hw_spec(struct lbs_private *priv);
+
int lbs_set_channel(struct lbs_private *priv, u8 channel);
-int lbs_mesh_config_send(struct lbs_private *priv,
- struct cmd_ds_mesh_config *cmd,
- uint16_t action, uint16_t type);
-int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
+int lbs_update_channel(struct lbs_private *priv);
int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
struct wol_config *p_wol_config);
-int lbs_suspend(struct lbs_private *priv);
-void lbs_resume(struct lbs_private *priv);
-int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
- uint16_t cmd_action);
-int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
- uint16_t cmd_action, uint16_t *timeout);
int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
struct sleep_params *sp);
-int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
- struct assoc_request *assoc);
-int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
- uint16_t *enable);
-int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
- struct assoc_request *assoc);
-int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
- s16 *maxlevel);
-int lbs_set_tx_power(struct lbs_private *priv, s16 dbm);
+void lbs_ps_sleep(struct lbs_private *priv, int wait_option);
+
+void lbs_ps_wakeup(struct lbs_private *priv, int wait_option);
+
+void lbs_ps_confirm_sleep(struct lbs_private *priv);
int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on);
+void lbs_set_mac_control(struct lbs_private *priv);
+
+int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
+ s16 *maxlevel);
+
int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val);
int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val);
+
+/* Mesh related */
+
+int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
+ struct cmd_ds_mesh_access *cmd);
+
+int lbs_mesh_config_send(struct lbs_private *priv,
+ struct cmd_ds_mesh_config *cmd,
+ uint16_t action, uint16_t type);
+
+int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
+
+
+/* Commands only used in wext.c, assoc. and scan.c */
+
+int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
+ int8_t p1, int8_t p2);
+
+int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
+ int8_t p2, int usesnr);
+
+int lbs_set_data_rate(struct lbs_private *priv, u8 rate);
+
+int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
+ uint16_t cmd_action);
+
+int lbs_set_tx_power(struct lbs_private *priv, s16 dbm);
+
+int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep);
+
#endif /* _LBS_CMD_H */
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 23f684337fdd..21d57690c20a 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -11,6 +11,7 @@
#include "host.h"
#include "decl.h"
+#include "cmd.h"
#include "defs.h"
#include "dev.h"
#include "assoc.h"
@@ -26,23 +27,17 @@
*/
void lbs_mac_event_disconnected(struct lbs_private *priv)
{
- union iwreq_data wrqu;
-
if (priv->connect_status != LBS_CONNECTED)
return;
lbs_deb_enter(LBS_DEB_ASSOC);
- memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-
/*
* Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
* It causes problem in the Supplicant
*/
-
msleep_interruptible(1000);
- wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+ lbs_send_disconnect_notification(priv);
/* report disconnect to upper layer */
netif_stop_queue(priv->dev);
@@ -67,7 +62,7 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
* no longer valid.
*/
memset(&priv->curbssparams.bssid, 0, ETH_ALEN);
- memset(&priv->curbssparams.ssid, 0, IW_ESSID_MAX_SIZE);
+ memset(&priv->curbssparams.ssid, 0, IEEE80211_MAX_SSID_LEN);
priv->curbssparams.ssid_len = 0;
if (priv->psstate != PS_STATE_FULL_POWER) {
@@ -78,32 +73,6 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
lbs_deb_leave(LBS_DEB_ASSOC);
}
-/**
- * @brief This function handles MIC failure event.
- *
- * @param priv A pointer to struct lbs_private structure
- * @para event the event id
- * @return n/a
- */
-static void handle_mic_failureevent(struct lbs_private *priv, u32 event)
-{
- char buf[50];
-
- lbs_deb_enter(LBS_DEB_CMD);
- memset(buf, 0, sizeof(buf));
-
- sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
-
- if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) {
- strcat(buf, "unicast ");
- } else {
- strcat(buf, "multicast ");
- }
-
- lbs_send_iwevcustom_event(priv, buf);
- lbs_deb_leave(LBS_DEB_CMD);
-}
-
static int lbs_ret_reg_access(struct lbs_private *priv,
u16 type, struct cmd_ds_command *resp)
{
@@ -147,53 +116,6 @@ static int lbs_ret_reg_access(struct lbs_private *priv,
return ret;
}
-static int lbs_ret_802_11_rssi(struct lbs_private *priv,
- struct cmd_ds_command *resp)
-{
- struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- /* store the non average value */
- priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR);
- priv->NF[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->noisefloor);
-
- priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR);
- priv->NF[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgnoisefloor);
-
- priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
- CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
- priv->NF[TYPE_BEACON][TYPE_NOAVG]);
-
- priv->RSSI[TYPE_BEACON][TYPE_AVG] =
- CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
- priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
-
- lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
- priv->RSSI[TYPE_BEACON][TYPE_NOAVG],
- priv->RSSI[TYPE_BEACON][TYPE_AVG]);
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
-static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv,
- struct cmd_ds_command *resp)
-{
- struct cmd_ds_802_11_beacon_control *bcn_ctrl =
- &resp->params.bcn_ctrl;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- if (bcn_ctrl->action == CMD_ACT_GET) {
- priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
- priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
- }
-
- lbs_deb_enter(LBS_DEB_CMD);
- return 0;
-}
-
static inline int handle_cmd_response(struct lbs_private *priv,
struct cmd_header *cmd_response)
{
@@ -227,29 +149,13 @@ static inline int handle_cmd_response(struct lbs_private *priv,
ret = lbs_ret_802_11_rssi(priv, resp);
break;
- case CMD_RET(CMD_802_11D_DOMAIN_INFO):
- ret = lbs_ret_802_11d_domain_info(resp);
- break;
-
case CMD_RET(CMD_802_11_TPC_CFG):
spin_lock_irqsave(&priv->driver_lock, flags);
memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg,
sizeof(struct cmd_ds_802_11_tpc_cfg));
spin_unlock_irqrestore(&priv->driver_lock, flags);
break;
- case CMD_RET(CMD_802_11_LED_GPIO_CTRL):
- spin_lock_irqsave(&priv->driver_lock, flags);
- memmove((void *)priv->cur_cmd->callback_arg, &resp->params.ledgpio,
- sizeof(struct cmd_ds_802_11_led_ctrl));
- spin_unlock_irqrestore(&priv->driver_lock, flags);
- break;
- case CMD_RET(CMD_GET_TSF):
- spin_lock_irqsave(&priv->driver_lock, flags);
- memcpy((void *)priv->cur_cmd->callback_arg,
- &resp->params.gettsf.tsfvalue, sizeof(u64));
- spin_unlock_irqrestore(&priv->driver_lock, flags);
- break;
case CMD_RET(CMD_BT_ACCESS):
spin_lock_irqsave(&priv->driver_lock, flags);
if (priv->cur_cmd->callback_arg)
@@ -505,9 +411,21 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
case MACREG_INT_CODE_HOST_AWAKE:
lbs_deb_cmd("EVENT: host awake\n");
+ if (priv->reset_deep_sleep_wakeup)
+ priv->reset_deep_sleep_wakeup(priv);
+ priv->is_deep_sleep = 0;
lbs_send_confirmwake(priv);
break;
+ case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
+ if (priv->reset_deep_sleep_wakeup)
+ priv->reset_deep_sleep_wakeup(priv);
+ lbs_deb_cmd("EVENT: ds awake\n");
+ priv->is_deep_sleep = 0;
+ priv->wakeup_dev_required = 0;
+ wake_up_interruptible(&priv->ds_awake_q);
+ break;
+
case MACREG_INT_CODE_PS_AWAKE:
lbs_deb_cmd("EVENT: ps awake\n");
/* handle unexpected PS AWAKE event */
@@ -533,12 +451,12 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
case MACREG_INT_CODE_MIC_ERR_UNICAST:
lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
- handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
+ lbs_send_mic_failureevent(priv, event);
break;
case MACREG_INT_CODE_MIC_ERR_MULTICAST:
lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
- handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST);
+ lbs_send_mic_failureevent(priv, event);
break;
case MACREG_INT_CODE_MIB_CHANGED:
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index 893a55ca344a..587b0cb0088d 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -451,10 +451,12 @@ static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
CMD_MAC_REG_ACCESS, 0,
CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
- pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
+ if (!ret) {
+ pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
priv->mac_offset, priv->offsetvalue.value);
- ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ }
free_page(addr);
return ret;
}
@@ -514,7 +516,8 @@ static ssize_t lbs_wrmac_write(struct file *file,
CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
- res = count;
+ if (!res)
+ res = count;
out_unlock:
free_page(addr);
return res;
@@ -539,10 +542,12 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
CMD_BBP_REG_ACCESS, 0,
CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
- pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
+ if (!ret) {
+ pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
priv->bbp_offset, priv->offsetvalue.value);
- ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ }
free_page(addr);
return ret;
@@ -603,7 +608,8 @@ static ssize_t lbs_wrbbp_write(struct file *file,
CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
- res = count;
+ if (!res)
+ res = count;
out_unlock:
free_page(addr);
return res;
@@ -628,10 +634,12 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
CMD_RF_REG_ACCESS, 0,
CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
- pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
+ if (!ret) {
+ pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
priv->rf_offset, priv->offsetvalue.value);
- ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ }
free_page(addr);
return ret;
@@ -692,7 +700,8 @@ static ssize_t lbs_wrrf_write(struct file *file,
CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
- res = count;
+ if (!res)
+ res = count;
out_unlock:
free_page(addr);
return res;
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 8b15380ae6e1..678f7c9f7503 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -8,71 +8,48 @@
#include <linux/netdevice.h>
-#include "defs.h"
-/** Function Prototype Declaration */
struct lbs_private;
struct sk_buff;
struct net_device;
-struct cmd_ctrl_node;
-struct cmd_ds_command;
-void lbs_set_mac_control(struct lbs_private *priv);
-void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count);
-
-int lbs_free_cmd_buffer(struct lbs_private *priv);
-
-int lbs_prepare_and_send_command(struct lbs_private *priv,
- u16 cmd_no,
- u16 cmd_action,
- u16 wait_option, u32 cmd_oid, void *pdata_buf);
+/* ethtool.c */
+extern const struct ethtool_ops lbs_ethtool_ops;
-int lbs_allocate_cmd_buffer(struct lbs_private *priv);
-int lbs_execute_next_command(struct lbs_private *priv);
-int lbs_process_event(struct lbs_private *priv, u32 event);
-void lbs_queue_event(struct lbs_private *priv, u32 event);
-void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
-u32 lbs_fw_index_to_data_rate(u8 index);
-u8 lbs_data_rate_to_fw_index(u32 rate);
-
-/** The proc fs interface */
-int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
-void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
- int result);
+/* tx.c */
+void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count);
netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb,
struct net_device *dev);
-int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band);
+/* rx.c */
int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *);
-void lbs_ps_sleep(struct lbs_private *priv, int wait_option);
-void lbs_ps_confirm_sleep(struct lbs_private *priv);
-void lbs_ps_wakeup(struct lbs_private *priv, int wait_option);
-
-struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
- struct lbs_private *priv,
- u8 band,
- u16 channel);
-
-void lbs_mac_event_disconnected(struct lbs_private *priv);
-
-void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str);
/* persistcfg.c */
void lbs_persist_config_init(struct net_device *net);
void lbs_persist_config_remove(struct net_device *net);
+
/* main.c */
-struct chan_freq_power *lbs_get_region_cfp_table(u8 region,
- int *cfp_no);
struct lbs_private *lbs_add_card(void *card, struct device *dmdev);
void lbs_remove_card(struct lbs_private *priv);
int lbs_start_card(struct lbs_private *priv);
void lbs_stop_card(struct lbs_private *priv);
void lbs_host_to_card_done(struct lbs_private *priv);
-int lbs_update_channel(struct lbs_private *priv);
+int lbs_suspend(struct lbs_private *priv);
+void lbs_resume(struct lbs_private *priv);
+
+void lbs_queue_event(struct lbs_private *priv, u32 event);
+void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
+
+int lbs_enter_auto_deep_sleep(struct lbs_private *priv);
+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);
+
#endif
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index 72f3479a4d70..6b6ea9f7bf5b 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -42,6 +42,7 @@
#define LBS_DEB_SDIO 0x00400000
#define LBS_DEB_SYSFS 0x00800000
#define LBS_DEB_SPI 0x01000000
+#define LBS_DEB_CFG80211 0x02000000
extern unsigned int lbs_debug;
@@ -86,6 +87,7 @@ do { if ((lbs_debug & (grp)) == (grp)) \
#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args)
#define lbs_deb_sysfs(fmt, args...) LBS_DEB_LL(LBS_DEB_SYSFS, " sysfs", fmt, ##args)
#define lbs_deb_spi(fmt, args...) LBS_DEB_LL(LBS_DEB_SPI, " spi", fmt, ##args)
+#define lbs_deb_cfg80211(fmt, args...) LBS_DEB_LL(LBS_DEB_CFG80211, " cfg80211", fmt, ##args)
#define lbs_pr_info(format, args...) \
printk(KERN_INFO DRV_NAME": " format, ## args)
@@ -320,7 +322,6 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
extern const char lbs_driver_version[];
extern u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE];
-extern u8 lbs_bg_rates[MAX_RATES];
/** ENUM definition*/
/** SNRNF_TYPE */
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index d3b69a4b4b5e..1a675111300d 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -6,75 +6,10 @@
#ifndef _LBS_DEV_H_
#define _LBS_DEV_H_
-#include <linux/netdevice.h>
-#include <linux/wireless.h>
-#include <linux/ethtool.h>
-#include <linux/debugfs.h>
+#include "scan.h"
+#include "assoc.h"
-#include "defs.h"
-#include "hostcmd.h"
-extern const struct ethtool_ops lbs_ethtool_ops;
-
-#define MAX_BSSID_PER_CHANNEL 16
-
-#define NR_TX_QUEUE 3
-
-/* For the extended Scan */
-#define MAX_EXTENDED_SCAN_BSSID_LIST MAX_BSSID_PER_CHANNEL * \
- MRVDRV_MAX_CHANNEL_SIZE + 1
-
-#define MAX_REGION_CHANNEL_NUM 2
-
-/** Chan-freq-TxPower mapping table*/
-struct chan_freq_power {
- /** channel Number */
- u16 channel;
- /** frequency of this channel */
- u32 freq;
- /** Max allowed Tx power level */
- u16 maxtxpower;
- /** TRUE:channel unsupported; FLASE:supported*/
- u8 unsupported;
-};
-
-/** region-band mapping table*/
-struct region_channel {
- /** TRUE if this entry is valid */
- u8 valid;
- /** region code for US, Japan ... */
- u8 region;
- /** band B/G/A, used for BAND_CONFIG cmd */
- u8 band;
- /** Actual No. of elements in the array below */
- u8 nrcfp;
- /** chan-freq-txpower mapping table*/
- struct chan_freq_power *CFP;
-};
-
-struct lbs_802_11_security {
- u8 WPAenabled;
- u8 WPA2enabled;
- u8 wep_enabled;
- u8 auth_mode;
- u32 key_mgmt;
-};
-
-/** Current Basic Service Set State Structure */
-struct current_bss_params {
- /** bssid */
- u8 bssid[ETH_ALEN];
- /** ssid */
- u8 ssid[IW_ESSID_MAX_SIZE + 1];
- u8 ssid_len;
-
- /** band */
- u8 band;
- /** channel */
- u8 channel;
- /** zero-terminated array of supported data rates */
- u8 rates[MAX_RATES + 1];
-};
/** sleep_params */
struct sleep_params {
@@ -100,95 +35,96 @@ struct lbs_mesh_stats {
/** Private structure for the MV device */
struct lbs_private {
- int mesh_open;
- int mesh_fw_ver;
- int infra_open;
- int mesh_autostart_enabled;
- char name[DEV_NAME_LEN];
-
- void *card;
+ /* Basic networking */
struct net_device *dev;
+ u32 connect_status;
+ int infra_open;
+ struct work_struct mcast_work;
+ u32 nr_of_multicastmacaddr;
+ u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
+ /* CFG80211 */
+ struct wireless_dev *wdev;
+
+ /* Mesh */
struct net_device *mesh_dev; /* Virtual device */
+ u32 mesh_connect_status;
+ struct lbs_mesh_stats mstats;
+ int mesh_open;
+ int mesh_fw_ver;
+ int mesh_autostart_enabled;
+ uint16_t mesh_tlv;
+ u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];
+ u8 mesh_ssid_len;
+ struct work_struct sync_channel;
+
+ /* Monitor mode */
struct net_device *rtap_net_dev;
+ u32 monitormode;
- struct iw_statistics wstats;
- struct lbs_mesh_stats mstats;
+ /* Debugfs */
struct dentry *debugfs_dir;
struct dentry *debugfs_debug;
struct dentry *debugfs_files[6];
-
struct dentry *events_dir;
struct dentry *debugfs_events_files[6];
-
struct dentry *regs_dir;
struct dentry *debugfs_regs_files[6];
+ /* Hardware debugging */
u32 mac_offset;
u32 bbp_offset;
u32 rf_offset;
+ struct lbs_offset_value offsetvalue;
- /* Download sent:
- bit0 1/0=data_sent/data_tx_done,
- bit1 1/0=cmd_sent/cmd_tx_done,
- all other bits reserved 0 */
- u8 dnld_sent;
-
- /** thread to service interrupts */
- struct task_struct *main_thread;
- wait_queue_head_t waitq;
- struct workqueue_struct *work_thread;
+ /* Power management */
+ u16 psmode;
+ u32 psstate;
+ u8 needtowakeup;
- struct work_struct mcast_work;
+ /* Deep sleep */
+ int is_deep_sleep;
+ int is_auto_deep_sleep_enabled;
+ int wakeup_dev_required;
+ int is_activity_detected;
+ int auto_deep_sleep_timeout; /* in ms */
+ wait_queue_head_t ds_awake_q;
+ struct timer_list auto_deepsleep_timer;
- /** Scanning */
- struct delayed_work scan_work;
- struct delayed_work assoc_work;
- struct work_struct sync_channel;
- /* remember which channel was scanned last, != 0 if currently scanning */
- int scan_channel;
- u8 scan_ssid[IW_ESSID_MAX_SIZE + 1];
- u8 scan_ssid_len;
-
- /** Hardware access */
+ /* Hardware access */
+ void *card;
+ u8 fw_ready;
+ u8 surpriseremoved;
int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
void (*reset_card) (struct lbs_private *priv);
+ int (*enter_deep_sleep) (struct lbs_private *priv);
+ int (*exit_deep_sleep) (struct lbs_private *priv);
+ int (*reset_deep_sleep_wakeup) (struct lbs_private *priv);
- /* Wake On LAN */
- uint32_t wol_criteria;
- uint8_t wol_gpio;
- uint8_t wol_gap;
-
- /** Wlan adapter data structure*/
- /** STATUS variables */
+ /* Adapter info (from EEPROM) */
u32 fwrelease;
u32 fwcapinfo;
+ u16 regioncode;
+ u8 current_addr[ETH_ALEN];
- struct mutex lock;
-
- /* TX packet ready to be sent... */
- int tx_pending_len; /* -1 while building packet */
-
- u8 tx_pending_buf[LBS_UPLD_SIZE];
- /* protected by hard_start_xmit serialization */
-
- /** command-related variables */
+ /* Command download */
+ u8 dnld_sent;
+ /* bit0 1/0=data_sent/data_tx_done,
+ bit1 1/0=cmd_sent/cmd_tx_done,
+ all other bits reserved 0 */
u16 seqnum;
-
struct cmd_ctrl_node *cmd_array;
- /** Current command */
struct cmd_ctrl_node *cur_cmd;
- int cur_cmd_retcode;
- /** command Queues */
- /** Free command buffers */
- struct list_head cmdfreeq;
- /** Pending command buffers */
- struct list_head cmdpendingq;
-
+ struct list_head cmdfreeq; /* free command buffers */
+ struct list_head cmdpendingq; /* pending command buffers */
wait_queue_head_t cmd_pending;
+ struct timer_list command_timer;
+ int nr_retries;
+ int cmd_timed_out;
/* Command responses sent from the hardware to the driver */
+ int cur_cmd_retcode;
u8 resp_idx;
u8 resp_buf[2][LBS_UPLD_SIZE];
u32 resp_len[2];
@@ -196,95 +132,76 @@ struct lbs_private {
/* Events sent from hardware to driver */
struct kfifo *event_fifo;
- /* nickname */
- u8 nodename[16];
-
- /** spin locks */
- spinlock_t driver_lock;
-
- /** Timers */
- struct timer_list command_timer;
- int nr_retries;
- int cmd_timed_out;
-
- /** current ssid/bssid related parameters*/
- struct current_bss_params curbssparams;
-
- uint16_t mesh_tlv;
- u8 mesh_ssid[IW_ESSID_MAX_SIZE + 1];
- u8 mesh_ssid_len;
-
- /* IW_MODE_* */
- u8 mode;
-
- /* Scan results list */
- struct list_head network_list;
- struct list_head network_free_list;
- struct bss_descriptor *networks;
-
- u16 beacon_period;
- u8 beacon_enable;
- u8 adhoccreate;
-
- /** capability Info used in Association, start, join */
- u16 capability;
-
- /** MAC address information */
- u8 current_addr[ETH_ALEN];
- u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
- u32 nr_of_multicastmacaddr;
+ /** thread to service interrupts */
+ struct task_struct *main_thread;
+ wait_queue_head_t waitq;
+ struct workqueue_struct *work_thread;
- /** 802.11 statistics */
-// struct cmd_DS_802_11_GET_STAT wlan802_11Stat;
+ /** Encryption stuff */
+ struct lbs_802_11_security secinfo;
+ struct enc_key wpa_mcast_key;
+ struct enc_key wpa_unicast_key;
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ u8 wpa_ie_len;
+ u16 wep_tx_keyidx;
+ struct enc_key wep_keys[4];
- uint16_t enablehwauto;
- uint16_t ratebitmap;
+ /* Wake On LAN */
+ uint32_t wol_criteria;
+ uint8_t wol_gpio;
+ uint8_t wol_gap;
+ /* Transmitting */
+ int tx_pending_len; /* -1 while building packet */
+ u8 tx_pending_buf[LBS_UPLD_SIZE];
+ /* protected by hard_start_xmit serialization */
u8 txretrycount;
-
- /** Tx-related variables (for single packet tx) */
struct sk_buff *currenttxskb;
- /** NIC Operation characteristics */
+ /* Locks */
+ struct mutex lock;
+ spinlock_t driver_lock;
+
+ /* NIC/link operation characteristics */
u16 mac_control;
- u32 connect_status;
- u32 mesh_connect_status;
- u16 regioncode;
+ u8 radio_on;
+ u8 channel;
s16 txpower_cur;
s16 txpower_min;
s16 txpower_max;
- /** POWER MANAGEMENT AND PnP SUPPORT */
- u8 surpriseremoved;
-
- u16 psmode; /* Wlan802_11PowermodeCAM=disable
- Wlan802_11PowermodeMAX_PSP=enable */
- u32 psstate;
- u8 needtowakeup;
+ /** Scanning */
+ struct delayed_work scan_work;
+ int scan_channel;
+ /* remember which channel was scanned last, != 0 if currently scanning */
+ u8 scan_ssid[IEEE80211_MAX_SSID_LEN + 1];
+ u8 scan_ssid_len;
+ /* Associating */
+ struct delayed_work assoc_work;
+ struct current_bss_params curbssparams;
+ u8 mode;
+ struct list_head network_list;
+ struct list_head network_free_list;
+ struct bss_descriptor *networks;
struct assoc_request * pending_assoc_req;
struct assoc_request * in_progress_assoc_req;
+ u16 capability;
+ uint16_t enablehwauto;
+ uint16_t ratebitmap;
- /** Encryption parameter */
- struct lbs_802_11_security secinfo;
-
- /** WEP keys */
- struct enc_key wep_keys[4];
- u16 wep_tx_keyidx;
-
- /** WPA keys */
- struct enc_key wpa_mcast_key;
- struct enc_key wpa_unicast_key;
-
-/*
- * In theory, the IE is limited to the IE length, 255,
- * but in practice 64 bytes are enough.
- */
-#define MAX_WPA_IE_LEN 64
+ /* ADHOC */
+ u16 beacon_period;
+ u8 beacon_enable;
+ u8 adhoccreate;
- /** WPA Information Elements*/
- u8 wpa_ie[MAX_WPA_IE_LEN];
- u8 wpa_ie_len;
+ /* WEXT */
+ char name[DEV_NAME_LEN];
+ u8 nodename[16];
+ struct iw_statistics wstats;
+ u8 cur_rate;
+#define MAX_REGION_CHANNEL_NUM 2
+ struct region_channel region_channel[MAX_REGION_CHANNEL_NUM];
/** Requested Signal Strength*/
u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
@@ -294,116 +211,8 @@ struct lbs_private {
u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
u16 nextSNRNF;
u16 numSNRNF;
-
- u8 radio_on;
-
- /** data rate stuff */
- u8 cur_rate;
-
- /** RF calibration data */
-
-#define MAX_REGION_CHANNEL_NUM 2
- /** region channel data */
- struct region_channel region_channel[MAX_REGION_CHANNEL_NUM];
-
- struct region_channel universal_channel[MAX_REGION_CHANNEL_NUM];
-
- /** 11D and Domain Regulatory Data */
- struct lbs_802_11d_domain_reg domainreg;
- struct parsed_region_chan_11d parsed_region_chan;
-
- /** FSM variable for 11d support */
- u32 enable11d;
-
- /** MISCELLANEOUS */
- struct lbs_offset_value offsetvalue;
-
- u32 monitormode;
- u8 fw_ready;
};
extern struct cmd_confirm_sleep confirm_sleep;
-/**
- * @brief Structure used to store information for each beacon/probe response
- */
-struct bss_descriptor {
- u8 bssid[ETH_ALEN];
-
- u8 ssid[IW_ESSID_MAX_SIZE + 1];
- u8 ssid_len;
-
- u16 capability;
- u32 rssi;
- u32 channel;
- u16 beaconperiod;
- __le16 atimwindow;
-
- /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
- u8 mode;
-
- /* zero-terminated array of supported data rates */
- u8 rates[MAX_RATES + 1];
-
- unsigned long last_scanned;
-
- union ieee_phy_param_set phy;
- union ieee_ss_param_set ss;
-
- struct ieee_ie_country_info_full_set countryinfo;
-
- u8 wpa_ie[MAX_WPA_IE_LEN];
- size_t wpa_ie_len;
- u8 rsn_ie[MAX_WPA_IE_LEN];
- size_t rsn_ie_len;
-
- u8 mesh;
-
- struct list_head list;
-};
-
-/** Association request
- *
- * Encapsulates all the options that describe a specific assocation request
- * or configuration of the wireless card's radio, mode, and security settings.
- */
-struct assoc_request {
-#define ASSOC_FLAG_SSID 1
-#define ASSOC_FLAG_CHANNEL 2
-#define ASSOC_FLAG_BAND 3
-#define ASSOC_FLAG_MODE 4
-#define ASSOC_FLAG_BSSID 5
-#define ASSOC_FLAG_WEP_KEYS 6
-#define ASSOC_FLAG_WEP_TX_KEYIDX 7
-#define ASSOC_FLAG_WPA_MCAST_KEY 8
-#define ASSOC_FLAG_WPA_UCAST_KEY 9
-#define ASSOC_FLAG_SECINFO 10
-#define ASSOC_FLAG_WPA_IE 11
- unsigned long flags;
-
- u8 ssid[IW_ESSID_MAX_SIZE + 1];
- u8 ssid_len;
- u8 channel;
- u8 band;
- u8 mode;
- u8 bssid[ETH_ALEN] __attribute__ ((aligned (2)));
-
- /** WEP keys */
- struct enc_key wep_keys[4];
- u16 wep_tx_keyidx;
-
- /** WPA keys */
- struct enc_key wpa_mcast_key;
- struct enc_key wpa_unicast_key;
-
- struct lbs_802_11_security secinfo;
-
- /** WPA Information Elements*/
- u8 wpa_ie[MAX_WPA_IE_LEN];
- u8 wpa_ie_len;
-
- /* BSS to associate with for infrastructure of Ad-Hoc join */
- struct bss_descriptor bss;
-};
-
#endif
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index fe8f0cb737bc..3809c0b49464 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -1,201 +1,190 @@
/**
- * This file contains definitions of WLAN commands.
+ * This file function prototypes, data structure
+ * and definitions for all the host/station commands
*/
#ifndef _LBS_HOST_H_
#define _LBS_HOST_H_
-/** PUBLIC DEFINITIONS */
-#define DEFAULT_AD_HOC_CHANNEL 6
-#define DEFAULT_AD_HOC_CHANNEL_A 36
+#include "types.h"
+#include "defs.h"
-#define CMD_OPTION_WAITFORRSP 0x0002
+#define DEFAULT_AD_HOC_CHANNEL 6
+
+#define CMD_OPTION_WAITFORRSP 0x0002
/** Host command IDs */
/* Return command are almost always the same as the host command, but with
* bit 15 set high. There are a few exceptions, though...
*/
-#define CMD_RET(cmd) (0x8000 | cmd)
+#define CMD_RET(cmd) (0x8000 | cmd)
/* Return command convention exceptions: */
-#define CMD_RET_802_11_ASSOCIATE 0x8012
+#define CMD_RET_802_11_ASSOCIATE 0x8012
/* Command codes */
-#define CMD_GET_HW_SPEC 0x0003
-#define CMD_EEPROM_UPDATE 0x0004
-#define CMD_802_11_RESET 0x0005
-#define CMD_802_11_SCAN 0x0006
-#define CMD_802_11_GET_LOG 0x000b
-#define CMD_MAC_MULTICAST_ADR 0x0010
-#define CMD_802_11_AUTHENTICATE 0x0011
-#define CMD_802_11_EEPROM_ACCESS 0x0059
-#define CMD_802_11_ASSOCIATE 0x0050
-#define CMD_802_11_SET_WEP 0x0013
-#define CMD_802_11_GET_STAT 0x0014
-#define CMD_802_3_GET_STAT 0x0015
-#define CMD_802_11_SNMP_MIB 0x0016
-#define CMD_MAC_REG_MAP 0x0017
-#define CMD_BBP_REG_MAP 0x0018
-#define CMD_MAC_REG_ACCESS 0x0019
-#define CMD_BBP_REG_ACCESS 0x001a
-#define CMD_RF_REG_ACCESS 0x001b
-#define CMD_802_11_RADIO_CONTROL 0x001c
-#define CMD_802_11_RF_CHANNEL 0x001d
-#define CMD_802_11_RF_TX_POWER 0x001e
-#define CMD_802_11_RSSI 0x001f
-#define CMD_802_11_RF_ANTENNA 0x0020
-#define CMD_802_11_PS_MODE 0x0021
-#define CMD_802_11_DATA_RATE 0x0022
-#define CMD_RF_REG_MAP 0x0023
-#define CMD_802_11_DEAUTHENTICATE 0x0024
-#define CMD_802_11_REASSOCIATE 0x0025
-#define CMD_MAC_CONTROL 0x0028
-#define CMD_802_11_AD_HOC_START 0x002b
-#define CMD_802_11_AD_HOC_JOIN 0x002c
-#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS 0x002e
-#define CMD_802_11_ENABLE_RSN 0x002f
-#define CMD_802_11_SET_AFC 0x003c
-#define CMD_802_11_GET_AFC 0x003d
-#define CMD_802_11_AD_HOC_STOP 0x0040
-#define CMD_802_11_HOST_SLEEP_CFG 0x0043
-#define CMD_802_11_WAKEUP_CONFIRM 0x0044
-#define CMD_802_11_HOST_SLEEP_ACTIVATE 0x0045
-#define CMD_802_11_BEACON_STOP 0x0049
-#define CMD_802_11_MAC_ADDRESS 0x004d
-#define CMD_802_11_LED_GPIO_CTRL 0x004e
-#define CMD_802_11_EEPROM_ACCESS 0x0059
-#define CMD_802_11_BAND_CONFIG 0x0058
-#define CMD_GSPI_BUS_CONFIG 0x005a
-#define CMD_802_11D_DOMAIN_INFO 0x005b
-#define CMD_802_11_KEY_MATERIAL 0x005e
-#define CMD_802_11_SLEEP_PARAMS 0x0066
-#define CMD_802_11_INACTIVITY_TIMEOUT 0x0067
-#define CMD_802_11_SLEEP_PERIOD 0x0068
-#define CMD_802_11_TPC_CFG 0x0072
-#define CMD_802_11_PA_CFG 0x0073
-#define CMD_802_11_FW_WAKE_METHOD 0x0074
-#define CMD_802_11_SUBSCRIBE_EVENT 0x0075
-#define CMD_802_11_RATE_ADAPT_RATESET 0x0076
-#define CMD_802_11_TX_RATE_QUERY 0x007f
-#define CMD_GET_TSF 0x0080
-#define CMD_BT_ACCESS 0x0087
-#define CMD_FWT_ACCESS 0x0095
-#define CMD_802_11_MONITOR_MODE 0x0098
-#define CMD_MESH_ACCESS 0x009b
-#define CMD_MESH_CONFIG_OLD 0x00a3
-#define CMD_MESH_CONFIG 0x00ac
-#define CMD_SET_BOOT2_VER 0x00a5
-#define CMD_FUNC_INIT 0x00a9
-#define CMD_FUNC_SHUTDOWN 0x00aa
-#define CMD_802_11_BEACON_CTRL 0x00b0
+#define CMD_GET_HW_SPEC 0x0003
+#define CMD_EEPROM_UPDATE 0x0004
+#define CMD_802_11_RESET 0x0005
+#define CMD_802_11_SCAN 0x0006
+#define CMD_802_11_GET_LOG 0x000b
+#define CMD_MAC_MULTICAST_ADR 0x0010
+#define CMD_802_11_AUTHENTICATE 0x0011
+#define CMD_802_11_EEPROM_ACCESS 0x0059
+#define CMD_802_11_ASSOCIATE 0x0050
+#define CMD_802_11_SET_WEP 0x0013
+#define CMD_802_11_GET_STAT 0x0014
+#define CMD_802_3_GET_STAT 0x0015
+#define CMD_802_11_SNMP_MIB 0x0016
+#define CMD_MAC_REG_MAP 0x0017
+#define CMD_BBP_REG_MAP 0x0018
+#define CMD_MAC_REG_ACCESS 0x0019
+#define CMD_BBP_REG_ACCESS 0x001a
+#define CMD_RF_REG_ACCESS 0x001b
+#define CMD_802_11_RADIO_CONTROL 0x001c
+#define CMD_802_11_RF_CHANNEL 0x001d
+#define CMD_802_11_RF_TX_POWER 0x001e
+#define CMD_802_11_RSSI 0x001f
+#define CMD_802_11_RF_ANTENNA 0x0020
+#define CMD_802_11_PS_MODE 0x0021
+#define CMD_802_11_DATA_RATE 0x0022
+#define CMD_RF_REG_MAP 0x0023
+#define CMD_802_11_DEAUTHENTICATE 0x0024
+#define CMD_802_11_REASSOCIATE 0x0025
+#define CMD_MAC_CONTROL 0x0028
+#define CMD_802_11_AD_HOC_START 0x002b
+#define CMD_802_11_AD_HOC_JOIN 0x002c
+#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS 0x002e
+#define CMD_802_11_ENABLE_RSN 0x002f
+#define CMD_802_11_SET_AFC 0x003c
+#define CMD_802_11_GET_AFC 0x003d
+#define CMD_802_11_DEEP_SLEEP 0x003e
+#define CMD_802_11_AD_HOC_STOP 0x0040
+#define CMD_802_11_HOST_SLEEP_CFG 0x0043
+#define CMD_802_11_WAKEUP_CONFIRM 0x0044
+#define CMD_802_11_HOST_SLEEP_ACTIVATE 0x0045
+#define CMD_802_11_BEACON_STOP 0x0049
+#define CMD_802_11_MAC_ADDRESS 0x004d
+#define CMD_802_11_LED_GPIO_CTRL 0x004e
+#define CMD_802_11_EEPROM_ACCESS 0x0059
+#define CMD_802_11_BAND_CONFIG 0x0058
+#define CMD_GSPI_BUS_CONFIG 0x005a
+#define CMD_802_11D_DOMAIN_INFO 0x005b
+#define CMD_802_11_KEY_MATERIAL 0x005e
+#define CMD_802_11_SLEEP_PARAMS 0x0066
+#define CMD_802_11_INACTIVITY_TIMEOUT 0x0067
+#define CMD_802_11_SLEEP_PERIOD 0x0068
+#define CMD_802_11_TPC_CFG 0x0072
+#define CMD_802_11_PA_CFG 0x0073
+#define CMD_802_11_FW_WAKE_METHOD 0x0074
+#define CMD_802_11_SUBSCRIBE_EVENT 0x0075
+#define CMD_802_11_RATE_ADAPT_RATESET 0x0076
+#define CMD_802_11_TX_RATE_QUERY 0x007f
+#define CMD_GET_TSF 0x0080
+#define CMD_BT_ACCESS 0x0087
+#define CMD_FWT_ACCESS 0x0095
+#define CMD_802_11_MONITOR_MODE 0x0098
+#define CMD_MESH_ACCESS 0x009b
+#define CMD_MESH_CONFIG_OLD 0x00a3
+#define CMD_MESH_CONFIG 0x00ac
+#define CMD_SET_BOOT2_VER 0x00a5
+#define CMD_FUNC_INIT 0x00a9
+#define CMD_FUNC_SHUTDOWN 0x00aa
+#define CMD_802_11_BEACON_CTRL 0x00b0
/* For the IEEE Power Save */
-#define CMD_SUBCMD_ENTER_PS 0x0030
-#define CMD_SUBCMD_EXIT_PS 0x0031
-#define CMD_SUBCMD_SLEEP_CONFIRMED 0x0034
-#define CMD_SUBCMD_FULL_POWERDOWN 0x0035
-#define CMD_SUBCMD_FULL_POWERUP 0x0036
+#define CMD_SUBCMD_ENTER_PS 0x0030
+#define CMD_SUBCMD_EXIT_PS 0x0031
+#define CMD_SUBCMD_SLEEP_CONFIRMED 0x0034
+#define CMD_SUBCMD_FULL_POWERDOWN 0x0035
+#define CMD_SUBCMD_FULL_POWERUP 0x0036
-#define CMD_ENABLE_RSN 0x0001
-#define CMD_DISABLE_RSN 0x0000
+#define CMD_ENABLE_RSN 0x0001
+#define CMD_DISABLE_RSN 0x0000
-#define CMD_ACT_GET 0x0000
-#define CMD_ACT_SET 0x0001
-#define CMD_ACT_GET_AES 0x0002
-#define CMD_ACT_SET_AES 0x0003
-#define CMD_ACT_REMOVE_AES 0x0004
+#define CMD_ACT_GET 0x0000
+#define CMD_ACT_SET 0x0001
/* Define action or option for CMD_802_11_SET_WEP */
-#define CMD_ACT_ADD 0x0002
-#define CMD_ACT_REMOVE 0x0004
-#define CMD_ACT_USE_DEFAULT 0x0008
-
-#define CMD_TYPE_WEP_40_BIT 0x01
-#define CMD_TYPE_WEP_104_BIT 0x02
+#define CMD_ACT_ADD 0x0002
+#define CMD_ACT_REMOVE 0x0004
-#define CMD_NUM_OF_WEP_KEYS 4
+#define CMD_TYPE_WEP_40_BIT 0x01
+#define CMD_TYPE_WEP_104_BIT 0x02
-#define CMD_WEP_KEY_INDEX_MASK 0x3fff
+#define CMD_NUM_OF_WEP_KEYS 4
-/* Define action or option for CMD_802_11_RESET */
-#define CMD_ACT_HALT 0x0003
+#define CMD_WEP_KEY_INDEX_MASK 0x3fff
/* Define action or option for CMD_802_11_SCAN */
-#define CMD_BSS_TYPE_BSS 0x0001
-#define CMD_BSS_TYPE_IBSS 0x0002
-#define CMD_BSS_TYPE_ANY 0x0003
+#define CMD_BSS_TYPE_BSS 0x0001
+#define CMD_BSS_TYPE_IBSS 0x0002
+#define CMD_BSS_TYPE_ANY 0x0003
/* Define action or option for CMD_802_11_SCAN */
-#define CMD_SCAN_TYPE_ACTIVE 0x0000
-#define CMD_SCAN_TYPE_PASSIVE 0x0001
+#define CMD_SCAN_TYPE_ACTIVE 0x0000
+#define CMD_SCAN_TYPE_PASSIVE 0x0001
-#define CMD_SCAN_RADIO_TYPE_BG 0
+#define CMD_SCAN_RADIO_TYPE_BG 0
-#define CMD_SCAN_PROBE_DELAY_TIME 0
+#define CMD_SCAN_PROBE_DELAY_TIME 0
/* Define action or option for CMD_MAC_CONTROL */
-#define CMD_ACT_MAC_RX_ON 0x0001
-#define CMD_ACT_MAC_TX_ON 0x0002
-#define CMD_ACT_MAC_LOOPBACK_ON 0x0004
-#define CMD_ACT_MAC_WEP_ENABLE 0x0008
-#define CMD_ACT_MAC_INT_ENABLE 0x0010
-#define CMD_ACT_MAC_MULTICAST_ENABLE 0x0020
-#define CMD_ACT_MAC_BROADCAST_ENABLE 0x0040
-#define CMD_ACT_MAC_PROMISCUOUS_ENABLE 0x0080
-#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
-#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400
+#define CMD_ACT_MAC_RX_ON 0x0001
+#define CMD_ACT_MAC_TX_ON 0x0002
+#define CMD_ACT_MAC_LOOPBACK_ON 0x0004
+#define CMD_ACT_MAC_WEP_ENABLE 0x0008
+#define CMD_ACT_MAC_INT_ENABLE 0x0010
+#define CMD_ACT_MAC_MULTICAST_ENABLE 0x0020
+#define CMD_ACT_MAC_BROADCAST_ENABLE 0x0040
+#define CMD_ACT_MAC_PROMISCUOUS_ENABLE 0x0080
+#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
+#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400
/* Event flags for CMD_802_11_SUBSCRIBE_EVENT */
-#define CMD_SUBSCRIBE_RSSI_LOW 0x0001
-#define CMD_SUBSCRIBE_SNR_LOW 0x0002
-#define CMD_SUBSCRIBE_FAILCOUNT 0x0004
-#define CMD_SUBSCRIBE_BCNMISS 0x0008
-#define CMD_SUBSCRIBE_RSSI_HIGH 0x0010
-#define CMD_SUBSCRIBE_SNR_HIGH 0x0020
+#define CMD_SUBSCRIBE_RSSI_LOW 0x0001
+#define CMD_SUBSCRIBE_SNR_LOW 0x0002
+#define CMD_SUBSCRIBE_FAILCOUNT 0x0004
+#define CMD_SUBSCRIBE_BCNMISS 0x0008
+#define CMD_SUBSCRIBE_RSSI_HIGH 0x0010
+#define CMD_SUBSCRIBE_SNR_HIGH 0x0020
-#define RADIO_PREAMBLE_LONG 0x00
-#define RADIO_PREAMBLE_SHORT 0x02
-#define RADIO_PREAMBLE_AUTO 0x04
+#define RADIO_PREAMBLE_LONG 0x00
+#define RADIO_PREAMBLE_SHORT 0x02
+#define RADIO_PREAMBLE_AUTO 0x04
/* Define action or option for CMD_802_11_RF_CHANNEL */
-#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00
-#define CMD_OPT_802_11_RF_CHANNEL_SET 0x01
+#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00
+#define CMD_OPT_802_11_RF_CHANNEL_SET 0x01
/* Define action or option for CMD_802_11_DATA_RATE */
-#define CMD_ACT_SET_TX_AUTO 0x0000
-#define CMD_ACT_SET_TX_FIX_RATE 0x0001
-#define CMD_ACT_GET_TX_RATE 0x0002
-
-#define CMD_ACT_SET_RX 0x0001
-#define CMD_ACT_SET_TX 0x0002
-#define CMD_ACT_SET_BOTH 0x0003
-#define CMD_ACT_GET_RX 0x0004
-#define CMD_ACT_GET_TX 0x0008
-#define CMD_ACT_GET_BOTH 0x000c
+#define CMD_ACT_SET_TX_AUTO 0x0000
+#define CMD_ACT_SET_TX_FIX_RATE 0x0001
+#define CMD_ACT_GET_TX_RATE 0x0002
/* Define action or option for CMD_802_11_PS_MODE */
-#define CMD_TYPE_CAM 0x0000
-#define CMD_TYPE_MAX_PSP 0x0001
-#define CMD_TYPE_FAST_PSP 0x0002
+#define CMD_TYPE_CAM 0x0000
+#define CMD_TYPE_MAX_PSP 0x0001
+#define CMD_TYPE_FAST_PSP 0x0002
/* Options for CMD_802_11_FW_WAKE_METHOD */
-#define CMD_WAKE_METHOD_UNCHANGED 0x0000
-#define CMD_WAKE_METHOD_COMMAND_INT 0x0001
-#define CMD_WAKE_METHOD_GPIO 0x0002
+#define CMD_WAKE_METHOD_UNCHANGED 0x0000
+#define CMD_WAKE_METHOD_COMMAND_INT 0x0001
+#define CMD_WAKE_METHOD_GPIO 0x0002
/* Object IDs for CMD_802_11_SNMP_MIB */
-#define SNMP_MIB_OID_BSS_TYPE 0x0000
-#define SNMP_MIB_OID_OP_RATE_SET 0x0001
-#define SNMP_MIB_OID_BEACON_PERIOD 0x0002 /* Reserved on v9+ */
-#define SNMP_MIB_OID_DTIM_PERIOD 0x0003 /* Reserved on v9+ */
-#define SNMP_MIB_OID_ASSOC_TIMEOUT 0x0004 /* Reserved on v9+ */
-#define SNMP_MIB_OID_RTS_THRESHOLD 0x0005
-#define SNMP_MIB_OID_SHORT_RETRY_LIMIT 0x0006
-#define SNMP_MIB_OID_LONG_RETRY_LIMIT 0x0007
-#define SNMP_MIB_OID_FRAG_THRESHOLD 0x0008
-#define SNMP_MIB_OID_11D_ENABLE 0x0009
-#define SNMP_MIB_OID_11H_ENABLE 0x000A
+#define SNMP_MIB_OID_BSS_TYPE 0x0000
+#define SNMP_MIB_OID_OP_RATE_SET 0x0001
+#define SNMP_MIB_OID_BEACON_PERIOD 0x0002 /* Reserved on v9+ */
+#define SNMP_MIB_OID_DTIM_PERIOD 0x0003 /* Reserved on v9+ */
+#define SNMP_MIB_OID_ASSOC_TIMEOUT 0x0004 /* Reserved on v9+ */
+#define SNMP_MIB_OID_RTS_THRESHOLD 0x0005
+#define SNMP_MIB_OID_SHORT_RETRY_LIMIT 0x0006
+#define SNMP_MIB_OID_LONG_RETRY_LIMIT 0x0007
+#define SNMP_MIB_OID_FRAG_THRESHOLD 0x0008
+#define SNMP_MIB_OID_11D_ENABLE 0x0009
+#define SNMP_MIB_OID_11H_ENABLE 0x000A
/* Define action or option for CMD_BT_ACCESS */
enum cmd_bt_access_opts {
@@ -302,4 +291,672 @@ enum cmd_mesh_config_types {
#define MACREG_INT_CODE_MESH_AUTO_STARTED 35
#define MACREG_INT_CODE_FIRMWARE_READY 48
+
+/* 802.11-related definitions */
+
+/* TxPD descriptor */
+struct txpd {
+ /* union to cope up with later FW revisions */
+ union {
+ /* Current Tx packet status */
+ __le32 tx_status;
+ struct {
+ /* BSS type: client, AP, etc. */
+ u8 bss_type;
+ /* BSS number */
+ u8 bss_num;
+ /* Reserved */
+ __le16 reserved;
+ } bss;
+ } u;
+ /* Tx control */
+ __le32 tx_control;
+ __le32 tx_packet_location;
+ /* Tx packet length */
+ __le16 tx_packet_length;
+ /* First 2 byte of destination MAC address */
+ u8 tx_dest_addr_high[2];
+ /* Last 4 byte of destination MAC address */
+ u8 tx_dest_addr_low[4];
+ /* Pkt Priority */
+ u8 priority;
+ /* Pkt Trasnit Power control */
+ u8 powermgmt;
+ /* Amount of time the packet has been queued (units = 2ms) */
+ u8 pktdelay_2ms;
+ /* reserved */
+ u8 reserved1;
+} __attribute__ ((packed));
+
+/* RxPD Descriptor */
+struct rxpd {
+ /* union to cope up with later FW revisions */
+ union {
+ /* Current Rx packet status */
+ __le16 status;
+ struct {
+ /* BSS type: client, AP, etc. */
+ u8 bss_type;
+ /* BSS number */
+ u8 bss_num;
+ } __attribute__ ((packed)) bss;
+ } __attribute__ ((packed)) u;
+
+ /* SNR */
+ u8 snr;
+
+ /* Tx control */
+ u8 rx_control;
+
+ /* Pkt length */
+ __le16 pkt_len;
+
+ /* Noise Floor */
+ u8 nf;
+
+ /* Rx Packet Rate */
+ u8 rx_rate;
+
+ /* Pkt addr */
+ __le32 pkt_ptr;
+
+ /* Next Rx RxPD addr */
+ __le32 next_rxpd_ptr;
+
+ /* Pkt Priority */
+ u8 priority;
+ u8 reserved[3];
+} __attribute__ ((packed));
+
+struct cmd_header {
+ __le16 command;
+ __le16 size;
+ __le16 seqnum;
+ __le16 result;
+} __attribute__ ((packed));
+
+/* Generic structure to hold all key types. */
+struct enc_key {
+ u16 len;
+ u16 flags; /* KEY_INFO_* from defs.h */
+ u16 type; /* KEY_TYPE_* from defs.h */
+ u8 key[32];
+};
+
+/* lbs_offset_value */
+struct lbs_offset_value {
+ u32 offset;
+ u32 value;
+} __attribute__ ((packed));
+
+/*
+ * Define data structure for CMD_GET_HW_SPEC
+ * This structure defines the response for the GET_HW_SPEC command
+ */
+struct cmd_ds_get_hw_spec {
+ struct cmd_header hdr;
+
+ /* HW Interface version number */
+ __le16 hwifversion;
+ /* HW version number */
+ __le16 version;
+ /* Max number of TxPD FW can handle */
+ __le16 nr_txpd;
+ /* Max no of Multicast address */
+ __le16 nr_mcast_adr;
+ /* MAC address */
+ u8 permanentaddr[6];
+
+ /* region Code */
+ __le16 regioncode;
+
+ /* Number of antenna used */
+ __le16 nr_antenna;
+
+ /* FW release number, example 0x01030304 = 2.3.4p1 */
+ __le32 fwrelease;
+
+ /* Base Address of TxPD queue */
+ __le32 wcb_base;
+ /* Read Pointer of RxPd queue */
+ __le32 rxpd_rdptr;
+
+ /* Write Pointer of RxPd queue */
+ __le32 rxpd_wrptr;
+
+ /*FW/HW capability */
+ __le32 fwcapinfo;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_subscribe_event {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 events;
+
+ /* A TLV to the CMD_802_11_SUBSCRIBE_EVENT command can contain a
+ * number of TLVs. From the v5.1 manual, those TLVs would add up to
+ * 40 bytes. However, future firmware might add additional TLVs, so I
+ * bump this up a bit.
+ */
+ uint8_t tlv[128];
+} __attribute__ ((packed));
+
+/*
+ * This scan handle Country Information IE(802.11d compliant)
+ * Define data structure for CMD_802_11_SCAN
+ */
+struct cmd_ds_802_11_scan {
+ struct cmd_header hdr;
+
+ uint8_t bsstype;
+ uint8_t bssid[ETH_ALEN];
+ uint8_t tlvbuffer[0];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_scan_rsp {
+ struct cmd_header hdr;
+
+ __le16 bssdescriptsize;
+ uint8_t nr_sets;
+ uint8_t bssdesc_and_tlvbuffer[0];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_get_log {
+ struct cmd_header hdr;
+
+ __le32 mcasttxframe;
+ __le32 failed;
+ __le32 retry;
+ __le32 multiretry;
+ __le32 framedup;
+ __le32 rtssuccess;
+ __le32 rtsfailure;
+ __le32 ackfailure;
+ __le32 rxfrag;
+ __le32 mcastrxframe;
+ __le32 fcserror;
+ __le32 txframe;
+ __le32 wepundecryptable;
+} __attribute__ ((packed));
+
+struct cmd_ds_mac_control {
+ struct cmd_header hdr;
+ __le16 action;
+ u16 reserved;
+} __attribute__ ((packed));
+
+struct cmd_ds_mac_multicast_adr {
+ struct cmd_header hdr;
+ __le16 action;
+ __le16 nr_of_adrs;
+ u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_authenticate {
+ struct cmd_header hdr;
+
+ u8 bssid[ETH_ALEN];
+ u8 authtype;
+ u8 reserved[10];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_deauthenticate {
+ struct cmd_header hdr;
+
+ u8 macaddr[ETH_ALEN];
+ __le16 reasoncode;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_associate {
+ struct cmd_header hdr;
+
+ u8 bssid[6];
+ __le16 capability;
+ __le16 listeninterval;
+ __le16 bcnperiod;
+ u8 dtimperiod;
+ u8 iebuf[512]; /* Enough for required and most optional IEs */
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_associate_response {
+ struct cmd_header hdr;
+
+ __le16 capability;
+ __le16 statuscode;
+ __le16 aid;
+ u8 iebuf[512];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_set_wep {
+ struct cmd_header hdr;
+
+ /* ACT_ADD, ACT_REMOVE or ACT_ENABLE */
+ __le16 action;
+
+ /* key Index selected for Tx */
+ __le16 keyindex;
+
+ /* 40, 128bit or TXWEP */
+ uint8_t keytype[4];
+ uint8_t keymaterial[4][16];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_snmp_mib {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 oid;
+ __le16 bufsize;
+ u8 value[128];
+} __attribute__ ((packed));
+
+struct cmd_ds_mac_reg_access {
+ __le16 action;
+ __le16 offset;
+ __le32 value;
+} __attribute__ ((packed));
+
+struct cmd_ds_bbp_reg_access {
+ __le16 action;
+ __le16 offset;
+ u8 value;
+ u8 reserved[3];
+} __attribute__ ((packed));
+
+struct cmd_ds_rf_reg_access {
+ __le16 action;
+ __le16 offset;
+ u8 value;
+ u8 reserved[3];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_radio_control {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 control;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_beacon_control {
+ __le16 action;
+ __le16 beacon_enable;
+ __le16 beacon_period;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_sleep_params {
+ struct cmd_header hdr;
+
+ /* ACT_GET/ACT_SET */
+ __le16 action;
+
+ /* Sleep clock error in ppm */
+ __le16 error;
+
+ /* Wakeup offset in usec */
+ __le16 offset;
+
+ /* Clock stabilization time in usec */
+ __le16 stabletime;
+
+ /* control periodic calibration */
+ uint8_t calcontrol;
+
+ /* control the use of external sleep clock */
+ uint8_t externalsleepclk;
+
+ /* reserved field, should be set to zero */
+ __le16 reserved;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_rf_channel {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 channel;
+ __le16 rftype; /* unused */
+ __le16 reserved; /* unused */
+ u8 channellist[32]; /* unused */
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_rssi {
+ /* weighting factor */
+ __le16 N;
+
+ __le16 reserved_0;
+ __le16 reserved_1;
+ __le16 reserved_2;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_rssi_rsp {
+ __le16 SNR;
+ __le16 noisefloor;
+ __le16 avgSNR;
+ __le16 avgnoisefloor;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_mac_address {
+ struct cmd_header hdr;
+
+ __le16 action;
+ u8 macadd[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_rf_tx_power {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 curlevel;
+ s8 maxlevel;
+ s8 minlevel;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_monitor_mode {
+ __le16 action;
+ __le16 mode;
+} __attribute__ ((packed));
+
+struct cmd_ds_set_boot2_ver {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 version;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_fw_wake_method {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 method;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_ps_mode {
+ __le16 action;
+ __le16 nullpktinterval;
+ __le16 multipledtim;
+ __le16 reserved;
+ __le16 locallisteninterval;
+} __attribute__ ((packed));
+
+struct cmd_confirm_sleep {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 nullpktinterval;
+ __le16 multipledtim;
+ __le16 reserved;
+ __le16 locallisteninterval;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_data_rate {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 reserved;
+ u8 rates[MAX_RATES];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_rate_adapt_rateset {
+ struct cmd_header hdr;
+ __le16 action;
+ __le16 enablehwauto;
+ __le16 bitmap;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_ad_hoc_start {
+ struct cmd_header hdr;
+
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ u8 bsstype;
+ __le16 beaconperiod;
+ u8 dtimperiod; /* Reserved on v9 and later */
+ struct ieee_ie_ibss_param_set ibss;
+ u8 reserved1[4];
+ struct ieee_ie_ds_param_set ds;
+ u8 reserved2[4];
+ __le16 probedelay; /* Reserved on v9 and later */
+ __le16 capability;
+ u8 rates[MAX_RATES];
+ u8 tlv_memory_size_pad[100];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_ad_hoc_result {
+ struct cmd_header hdr;
+
+ u8 pad[3];
+ u8 bssid[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct adhoc_bssdesc {
+ u8 bssid[ETH_ALEN];
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ u8 type;
+ __le16 beaconperiod;
+ u8 dtimperiod;
+ __le64 timestamp;
+ __le64 localtime;
+ struct ieee_ie_ds_param_set ds;
+ u8 reserved1[4];
+ struct ieee_ie_ibss_param_set ibss;
+ u8 reserved2[4];
+ __le16 capability;
+ u8 rates[MAX_RATES];
+
+ /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
+ * Adhoc join command and will cause a binary layout mismatch with
+ * the firmware
+ */
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_ad_hoc_join {
+ struct cmd_header hdr;
+
+ struct adhoc_bssdesc bss;
+ __le16 failtimeout; /* Reserved on v9 and later */
+ __le16 probedelay; /* Reserved on v9 and later */
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_ad_hoc_stop {
+ struct cmd_header hdr;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_enable_rsn {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 enable;
+} __attribute__ ((packed));
+
+struct MrvlIEtype_keyParamSet {
+ /* type ID */
+ __le16 type;
+
+ /* length of Payload */
+ __le16 length;
+
+ /* type of key: WEP=0, TKIP=1, AES=2 */
+ __le16 keytypeid;
+
+ /* key control Info specific to a keytypeid */
+ __le16 keyinfo;
+
+ /* length of key */
+ __le16 keylen;
+
+ /* key material of size keylen */
+ u8 key[32];
+} __attribute__ ((packed));
+
+#define MAX_WOL_RULES 16
+
+struct host_wol_rule {
+ uint8_t rule_no;
+ uint8_t rule_ops;
+ __le16 sig_offset;
+ __le16 sig_length;
+ __le16 reserve;
+ __be32 sig_mask;
+ __be32 signature;
+} __attribute__ ((packed));
+
+struct wol_config {
+ uint8_t action;
+ uint8_t pattern;
+ uint8_t no_rules_in_cmd;
+ uint8_t result;
+ struct host_wol_rule rule[MAX_WOL_RULES];
+} __attribute__ ((packed));
+
+struct cmd_ds_host_sleep {
+ struct cmd_header hdr;
+ __le32 criteria;
+ uint8_t gpio;
+ uint16_t gap;
+ struct wol_config wol_conf;
+} __attribute__ ((packed));
+
+
+
+struct cmd_ds_802_11_key_material {
+ struct cmd_header hdr;
+
+ __le16 action;
+ struct MrvlIEtype_keyParamSet keyParamSet[2];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_eeprom_access {
+ struct cmd_header hdr;
+ __le16 action;
+ __le16 offset;
+ __le16 len;
+ /* firmware says it returns a maximum of 20 bytes */
+#define LBS_EEPROM_READ_LEN 20
+ u8 value[LBS_EEPROM_READ_LEN];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_tpc_cfg {
+ struct cmd_header hdr;
+
+ __le16 action;
+ uint8_t enable;
+ int8_t P0;
+ int8_t P1;
+ int8_t P2;
+ uint8_t usesnr;
+} __attribute__ ((packed));
+
+
+struct cmd_ds_802_11_pa_cfg {
+ struct cmd_header hdr;
+
+ __le16 action;
+ uint8_t enable;
+ int8_t P0;
+ int8_t P1;
+ int8_t P2;
+} __attribute__ ((packed));
+
+
+struct cmd_ds_802_11_led_ctrl {
+ __le16 action;
+ __le16 numled;
+ u8 data[256];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_afc {
+ __le16 afc_auto;
+ union {
+ struct {
+ __le16 threshold;
+ __le16 period;
+ };
+ struct {
+ __le16 timing_offset; /* signed */
+ __le16 carrier_offset; /* signed */
+ };
+ };
+} __attribute__ ((packed));
+
+struct cmd_tx_rate_query {
+ __le16 txrate;
+} __attribute__ ((packed));
+
+struct cmd_ds_get_tsf {
+ __le64 tsfvalue;
+} __attribute__ ((packed));
+
+struct cmd_ds_bt_access {
+ __le16 action;
+ __le32 id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct cmd_ds_fwt_access {
+ __le16 action;
+ __le32 id;
+ u8 valid;
+ u8 da[ETH_ALEN];
+ u8 dir;
+ u8 ra[ETH_ALEN];
+ __le32 ssn;
+ __le32 dsn;
+ __le32 metric;
+ u8 rate;
+ u8 hopcount;
+ u8 ttl;
+ __le32 expiration;
+ u8 sleepmode;
+ __le32 snr;
+ __le32 references;
+ u8 prec[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct cmd_ds_mesh_config {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le16 channel;
+ __le16 type;
+ __le16 length;
+ u8 data[128]; /* last position reserved */
+} __attribute__ ((packed));
+
+struct cmd_ds_mesh_access {
+ struct cmd_header hdr;
+
+ __le16 action;
+ __le32 data[32]; /* last position reserved */
+} __attribute__ ((packed));
+
+/* Number of stats counters returned by the firmware */
+#define MESH_STATS_NUM 8
+
+struct cmd_ds_command {
+ /* command header */
+ __le16 command;
+ __le16 size;
+ __le16 seqnum;
+ __le16 result;
+
+ /* command Body */
+ union {
+ struct cmd_ds_802_11_ps_mode psmode;
+ struct cmd_ds_802_11_monitor_mode monitor;
+ struct cmd_ds_802_11_rssi rssi;
+ struct cmd_ds_802_11_rssi_rsp rssirsp;
+ struct cmd_ds_mac_reg_access macreg;
+ struct cmd_ds_bbp_reg_access bbpreg;
+ struct cmd_ds_rf_reg_access rfreg;
+
+ struct cmd_ds_802_11_tpc_cfg tpccfg;
+ struct cmd_ds_802_11_afc afc;
+ struct cmd_ds_802_11_led_ctrl ledgpio;
+
+ struct cmd_ds_bt_access bt;
+ struct cmd_ds_fwt_access fwt;
+ struct cmd_ds_802_11_beacon_control bcn_ctrl;
+ } params;
+} __attribute__ ((packed));
+
#endif
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
deleted file mode 100644
index c8a1998d4744..000000000000
--- a/drivers/net/wireless/libertas/hostcmd.h
+++ /dev/null
@@ -1,800 +0,0 @@
-/*
- * This file contains the function prototypes, data structure
- * and defines for all the host/station commands
- */
-#ifndef _LBS_HOSTCMD_H
-#define _LBS_HOSTCMD_H
-
-#include <linux/wireless.h>
-#include "11d.h"
-#include "types.h"
-
-/* 802.11-related definitions */
-
-/* TxPD descriptor */
-struct txpd {
- /* union to cope up with later FW revisions */
- union {
- /* Current Tx packet status */
- __le32 tx_status;
- struct {
- /* BSS type: client, AP, etc. */
- u8 bss_type;
- /* BSS number */
- u8 bss_num;
- /* Reserved */
- __le16 reserved;
- } bss;
- } u;
- /* Tx control */
- __le32 tx_control;
- __le32 tx_packet_location;
- /* Tx packet length */
- __le16 tx_packet_length;
- /* First 2 byte of destination MAC address */
- u8 tx_dest_addr_high[2];
- /* Last 4 byte of destination MAC address */
- u8 tx_dest_addr_low[4];
- /* Pkt Priority */
- u8 priority;
- /* Pkt Trasnit Power control */
- u8 powermgmt;
- /* Amount of time the packet has been queued in the driver (units = 2ms) */
- u8 pktdelay_2ms;
- /* reserved */
- u8 reserved1;
-} __attribute__ ((packed));
-
-/* RxPD Descriptor */
-struct rxpd {
- /* union to cope up with later FW revisions */
- union {
- /* Current Rx packet status */
- __le16 status;
- struct {
- /* BSS type: client, AP, etc. */
- u8 bss_type;
- /* BSS number */
- u8 bss_num;
- } __attribute__ ((packed)) bss;
- } __attribute__ ((packed)) u;
-
- /* SNR */
- u8 snr;
-
- /* Tx control */
- u8 rx_control;
-
- /* Pkt length */
- __le16 pkt_len;
-
- /* Noise Floor */
- u8 nf;
-
- /* Rx Packet Rate */
- u8 rx_rate;
-
- /* Pkt addr */
- __le32 pkt_ptr;
-
- /* Next Rx RxPD addr */
- __le32 next_rxpd_ptr;
-
- /* Pkt Priority */
- u8 priority;
- u8 reserved[3];
-} __attribute__ ((packed));
-
-struct cmd_header {
- __le16 command;
- __le16 size;
- __le16 seqnum;
- __le16 result;
-} __attribute__ ((packed));
-
-struct cmd_ctrl_node {
- struct list_head list;
- int result;
- /* command response */
- int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *);
- unsigned long callback_arg;
- /* command data */
- struct cmd_header *cmdbuf;
- /* wait queue */
- u16 cmdwaitqwoken;
- wait_queue_head_t cmdwait_q;
-};
-
-/* Generic structure to hold all key types. */
-struct enc_key {
- u16 len;
- u16 flags; /* KEY_INFO_* from defs.h */
- u16 type; /* KEY_TYPE_* from defs.h */
- u8 key[32];
-};
-
-/* lbs_offset_value */
-struct lbs_offset_value {
- u32 offset;
- u32 value;
-} __attribute__ ((packed));
-
-/* Define general data structure */
-/* cmd_DS_GEN */
-struct cmd_ds_gen {
- __le16 command;
- __le16 size;
- __le16 seqnum;
- __le16 result;
- void *cmdresp[0];
-} __attribute__ ((packed));
-
-#define S_DS_GEN sizeof(struct cmd_ds_gen)
-
-
-/*
- * Define data structure for CMD_GET_HW_SPEC
- * This structure defines the response for the GET_HW_SPEC command
- */
-struct cmd_ds_get_hw_spec {
- struct cmd_header hdr;
-
- /* HW Interface version number */
- __le16 hwifversion;
- /* HW version number */
- __le16 version;
- /* Max number of TxPD FW can handle */
- __le16 nr_txpd;
- /* Max no of Multicast address */
- __le16 nr_mcast_adr;
- /* MAC address */
- u8 permanentaddr[6];
-
- /* region Code */
- __le16 regioncode;
-
- /* Number of antenna used */
- __le16 nr_antenna;
-
- /* FW release number, example 0x01030304 = 2.3.4p1 */
- __le32 fwrelease;
-
- /* Base Address of TxPD queue */
- __le32 wcb_base;
- /* Read Pointer of RxPd queue */
- __le32 rxpd_rdptr;
-
- /* Write Pointer of RxPd queue */
- __le32 rxpd_wrptr;
-
- /*FW/HW capability */
- __le32 fwcapinfo;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_subscribe_event {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 events;
-
- /* A TLV to the CMD_802_11_SUBSCRIBE_EVENT command can contain a
- * number of TLVs. From the v5.1 manual, those TLVs would add up to
- * 40 bytes. However, future firmware might add additional TLVs, so I
- * bump this up a bit.
- */
- uint8_t tlv[128];
-} __attribute__ ((packed));
-
-/*
- * This scan handle Country Information IE(802.11d compliant)
- * Define data structure for CMD_802_11_SCAN
- */
-struct cmd_ds_802_11_scan {
- struct cmd_header hdr;
-
- uint8_t bsstype;
- uint8_t bssid[ETH_ALEN];
- uint8_t tlvbuffer[0];
-#if 0
- mrvlietypes_ssidparamset_t ssidParamSet;
- mrvlietypes_chanlistparamset_t ChanListParamSet;
- mrvlietypes_ratesparamset_t OpRateSet;
-#endif
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_scan_rsp {
- struct cmd_header hdr;
-
- __le16 bssdescriptsize;
- uint8_t nr_sets;
- uint8_t bssdesc_and_tlvbuffer[0];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_get_log {
- struct cmd_header hdr;
-
- __le32 mcasttxframe;
- __le32 failed;
- __le32 retry;
- __le32 multiretry;
- __le32 framedup;
- __le32 rtssuccess;
- __le32 rtsfailure;
- __le32 ackfailure;
- __le32 rxfrag;
- __le32 mcastrxframe;
- __le32 fcserror;
- __le32 txframe;
- __le32 wepundecryptable;
-} __attribute__ ((packed));
-
-struct cmd_ds_mac_control {
- struct cmd_header hdr;
- __le16 action;
- u16 reserved;
-} __attribute__ ((packed));
-
-struct cmd_ds_mac_multicast_adr {
- struct cmd_header hdr;
- __le16 action;
- __le16 nr_of_adrs;
- u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
-} __attribute__ ((packed));
-
-struct cmd_ds_gspi_bus_config {
- struct cmd_header hdr;
- __le16 action;
- __le16 bus_delay_mode;
- __le16 host_time_delay_to_read_port;
- __le16 host_time_delay_to_read_register;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_authenticate {
- struct cmd_header hdr;
-
- u8 bssid[ETH_ALEN];
- u8 authtype;
- u8 reserved[10];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_deauthenticate {
- struct cmd_header hdr;
-
- u8 macaddr[ETH_ALEN];
- __le16 reasoncode;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_associate {
- struct cmd_header hdr;
-
- u8 bssid[6];
- __le16 capability;
- __le16 listeninterval;
- __le16 bcnperiod;
- u8 dtimperiod;
- u8 iebuf[512]; /* Enough for required and most optional IEs */
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_associate_response {
- struct cmd_header hdr;
-
- __le16 capability;
- __le16 statuscode;
- __le16 aid;
- u8 iebuf[512];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_set_wep {
- struct cmd_header hdr;
-
- /* ACT_ADD, ACT_REMOVE or ACT_ENABLE */
- __le16 action;
-
- /* key Index selected for Tx */
- __le16 keyindex;
-
- /* 40, 128bit or TXWEP */
- uint8_t keytype[4];
- uint8_t keymaterial[4][16];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_3_get_stat {
- __le32 xmitok;
- __le32 rcvok;
- __le32 xmiterror;
- __le32 rcverror;
- __le32 rcvnobuffer;
- __le32 rcvcrcerror;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_get_stat {
- __le32 txfragmentcnt;
- __le32 mcasttxframecnt;
- __le32 failedcnt;
- __le32 retrycnt;
- __le32 Multipleretrycnt;
- __le32 rtssuccesscnt;
- __le32 rtsfailurecnt;
- __le32 ackfailurecnt;
- __le32 frameduplicatecnt;
- __le32 rxfragmentcnt;
- __le32 mcastrxframecnt;
- __le32 fcserrorcnt;
- __le32 bcasttxframecnt;
- __le32 bcastrxframecnt;
- __le32 txbeacon;
- __le32 rxbeacon;
- __le32 wepundecryptable;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_snmp_mib {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 oid;
- __le16 bufsize;
- u8 value[128];
-} __attribute__ ((packed));
-
-struct cmd_ds_mac_reg_map {
- __le16 buffersize;
- u8 regmap[128];
- __le16 reserved;
-} __attribute__ ((packed));
-
-struct cmd_ds_bbp_reg_map {
- __le16 buffersize;
- u8 regmap[128];
- __le16 reserved;
-} __attribute__ ((packed));
-
-struct cmd_ds_rf_reg_map {
- __le16 buffersize;
- u8 regmap[64];
- __le16 reserved;
-} __attribute__ ((packed));
-
-struct cmd_ds_mac_reg_access {
- __le16 action;
- __le16 offset;
- __le32 value;
-} __attribute__ ((packed));
-
-struct cmd_ds_bbp_reg_access {
- __le16 action;
- __le16 offset;
- u8 value;
- u8 reserved[3];
-} __attribute__ ((packed));
-
-struct cmd_ds_rf_reg_access {
- __le16 action;
- __le16 offset;
- u8 value;
- u8 reserved[3];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_radio_control {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 control;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_beacon_control {
- __le16 action;
- __le16 beacon_enable;
- __le16 beacon_period;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_sleep_params {
- struct cmd_header hdr;
-
- /* ACT_GET/ACT_SET */
- __le16 action;
-
- /* Sleep clock error in ppm */
- __le16 error;
-
- /* Wakeup offset in usec */
- __le16 offset;
-
- /* Clock stabilization time in usec */
- __le16 stabletime;
-
- /* control periodic calibration */
- uint8_t calcontrol;
-
- /* control the use of external sleep clock */
- uint8_t externalsleepclk;
-
- /* reserved field, should be set to zero */
- __le16 reserved;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_inactivity_timeout {
- struct cmd_header hdr;
-
- /* ACT_GET/ACT_SET */
- __le16 action;
-
- /* Inactivity timeout in msec */
- __le16 timeout;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_rf_channel {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 channel;
- __le16 rftype; /* unused */
- __le16 reserved; /* unused */
- u8 channellist[32]; /* unused */
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_rssi {
- /* weighting factor */
- __le16 N;
-
- __le16 reserved_0;
- __le16 reserved_1;
- __le16 reserved_2;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_rssi_rsp {
- __le16 SNR;
- __le16 noisefloor;
- __le16 avgSNR;
- __le16 avgnoisefloor;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_mac_address {
- struct cmd_header hdr;
-
- __le16 action;
- u8 macadd[ETH_ALEN];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_rf_tx_power {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 curlevel;
- s8 maxlevel;
- s8 minlevel;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_rf_antenna {
- __le16 action;
-
- /* Number of antennas or 0xffff(diversity) */
- __le16 antennamode;
-
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_monitor_mode {
- __le16 action;
- __le16 mode;
-} __attribute__ ((packed));
-
-struct cmd_ds_set_boot2_ver {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 version;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_fw_wake_method {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 method;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_sleep_period {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 period;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_ps_mode {
- __le16 action;
- __le16 nullpktinterval;
- __le16 multipledtim;
- __le16 reserved;
- __le16 locallisteninterval;
-} __attribute__ ((packed));
-
-struct cmd_confirm_sleep {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 nullpktinterval;
- __le16 multipledtim;
- __le16 reserved;
- __le16 locallisteninterval;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_data_rate {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 reserved;
- u8 rates[MAX_RATES];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_rate_adapt_rateset {
- struct cmd_header hdr;
- __le16 action;
- __le16 enablehwauto;
- __le16 bitmap;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_ad_hoc_start {
- struct cmd_header hdr;
-
- u8 ssid[IW_ESSID_MAX_SIZE];
- u8 bsstype;
- __le16 beaconperiod;
- u8 dtimperiod; /* Reserved on v9 and later */
- struct ieee_ie_ibss_param_set ibss;
- u8 reserved1[4];
- struct ieee_ie_ds_param_set ds;
- u8 reserved2[4];
- __le16 probedelay; /* Reserved on v9 and later */
- __le16 capability;
- u8 rates[MAX_RATES];
- u8 tlv_memory_size_pad[100];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_ad_hoc_result {
- struct cmd_header hdr;
-
- u8 pad[3];
- u8 bssid[ETH_ALEN];
-} __attribute__ ((packed));
-
-struct adhoc_bssdesc {
- u8 bssid[ETH_ALEN];
- u8 ssid[IW_ESSID_MAX_SIZE];
- u8 type;
- __le16 beaconperiod;
- u8 dtimperiod;
- __le64 timestamp;
- __le64 localtime;
- struct ieee_ie_ds_param_set ds;
- u8 reserved1[4];
- struct ieee_ie_ibss_param_set ibss;
- u8 reserved2[4];
- __le16 capability;
- u8 rates[MAX_RATES];
-
- /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
- * Adhoc join command and will cause a binary layout mismatch with
- * the firmware
- */
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_ad_hoc_join {
- struct cmd_header hdr;
-
- struct adhoc_bssdesc bss;
- __le16 failtimeout; /* Reserved on v9 and later */
- __le16 probedelay; /* Reserved on v9 and later */
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_ad_hoc_stop {
- struct cmd_header hdr;
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_enable_rsn {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 enable;
-} __attribute__ ((packed));
-
-struct MrvlIEtype_keyParamSet {
- /* type ID */
- __le16 type;
-
- /* length of Payload */
- __le16 length;
-
- /* type of key: WEP=0, TKIP=1, AES=2 */
- __le16 keytypeid;
-
- /* key control Info specific to a keytypeid */
- __le16 keyinfo;
-
- /* length of key */
- __le16 keylen;
-
- /* key material of size keylen */
- u8 key[32];
-} __attribute__ ((packed));
-
-#define MAX_WOL_RULES 16
-
-struct host_wol_rule {
- uint8_t rule_no;
- uint8_t rule_ops;
- __le16 sig_offset;
- __le16 sig_length;
- __le16 reserve;
- __be32 sig_mask;
- __be32 signature;
-} __attribute__ ((packed));
-
-struct wol_config {
- uint8_t action;
- uint8_t pattern;
- uint8_t no_rules_in_cmd;
- uint8_t result;
- struct host_wol_rule rule[MAX_WOL_RULES];
-} __attribute__ ((packed));
-
-struct cmd_ds_host_sleep {
- struct cmd_header hdr;
- __le32 criteria;
- uint8_t gpio;
- uint16_t gap;
- struct wol_config wol_conf;
-} __attribute__ ((packed));
-
-
-
-struct cmd_ds_802_11_key_material {
- struct cmd_header hdr;
-
- __le16 action;
- struct MrvlIEtype_keyParamSet keyParamSet[2];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_eeprom_access {
- struct cmd_header hdr;
- __le16 action;
- __le16 offset;
- __le16 len;
- /* firmware says it returns a maximum of 20 bytes */
-#define LBS_EEPROM_READ_LEN 20
- u8 value[LBS_EEPROM_READ_LEN];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_tpc_cfg {
- struct cmd_header hdr;
-
- __le16 action;
- uint8_t enable;
- int8_t P0;
- int8_t P1;
- int8_t P2;
- uint8_t usesnr;
-} __attribute__ ((packed));
-
-
-struct cmd_ds_802_11_pa_cfg {
- struct cmd_header hdr;
-
- __le16 action;
- uint8_t enable;
- int8_t P0;
- int8_t P1;
- int8_t P2;
-} __attribute__ ((packed));
-
-
-struct cmd_ds_802_11_led_ctrl {
- __le16 action;
- __le16 numled;
- u8 data[256];
-} __attribute__ ((packed));
-
-struct cmd_ds_802_11_afc {
- __le16 afc_auto;
- union {
- struct {
- __le16 threshold;
- __le16 period;
- };
- struct {
- __le16 timing_offset; /* signed */
- __le16 carrier_offset; /* signed */
- };
- };
-} __attribute__ ((packed));
-
-struct cmd_tx_rate_query {
- __le16 txrate;
-} __attribute__ ((packed));
-
-struct cmd_ds_get_tsf {
- __le64 tsfvalue;
-} __attribute__ ((packed));
-
-struct cmd_ds_bt_access {
- __le16 action;
- __le32 id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
-} __attribute__ ((packed));
-
-struct cmd_ds_fwt_access {
- __le16 action;
- __le32 id;
- u8 valid;
- u8 da[ETH_ALEN];
- u8 dir;
- u8 ra[ETH_ALEN];
- __le32 ssn;
- __le32 dsn;
- __le32 metric;
- u8 rate;
- u8 hopcount;
- u8 ttl;
- __le32 expiration;
- u8 sleepmode;
- __le32 snr;
- __le32 references;
- u8 prec[ETH_ALEN];
-} __attribute__ ((packed));
-
-
-struct cmd_ds_mesh_config {
- struct cmd_header hdr;
-
- __le16 action;
- __le16 channel;
- __le16 type;
- __le16 length;
- u8 data[128]; /* last position reserved */
-} __attribute__ ((packed));
-
-
-struct cmd_ds_mesh_access {
- struct cmd_header hdr;
-
- __le16 action;
- __le32 data[32]; /* last position reserved */
-} __attribute__ ((packed));
-
-/* Number of stats counters returned by the firmware */
-#define MESH_STATS_NUM 8
-
-struct cmd_ds_command {
- /* command header */
- __le16 command;
- __le16 size;
- __le16 seqnum;
- __le16 result;
-
- /* command Body */
- union {
- struct cmd_ds_802_11_ps_mode psmode;
- struct cmd_ds_802_11_get_stat gstat;
- struct cmd_ds_802_3_get_stat gstat_8023;
- struct cmd_ds_802_11_rf_antenna rant;
- struct cmd_ds_802_11_monitor_mode monitor;
- struct cmd_ds_802_11_rssi rssi;
- struct cmd_ds_802_11_rssi_rsp rssirsp;
- struct cmd_ds_mac_reg_access macreg;
- struct cmd_ds_bbp_reg_access bbpreg;
- struct cmd_ds_rf_reg_access rfreg;
-
- struct cmd_ds_802_11d_domain_info domaininfo;
- struct cmd_ds_802_11d_domain_info domaininforesp;
-
- struct cmd_ds_802_11_tpc_cfg tpccfg;
- struct cmd_ds_802_11_afc afc;
- struct cmd_ds_802_11_led_ctrl ledgpio;
-
- struct cmd_tx_rate_query txrate;
- struct cmd_ds_bt_access bt;
- struct cmd_ds_fwt_access fwt;
- struct cmd_ds_get_tsf gettsf;
- struct cmd_ds_802_11_beacon_control bcn_ctrl;
- } params;
-} __attribute__ ((packed));
-
-#endif
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 62381768f2d5..9127d2aabeec 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -793,18 +793,37 @@ static void if_cs_release(struct pcmcia_device *p_dev)
* configure the card at this point -- we wait until we receive a card
* insertion event.
*/
+
+static int if_cs_ioprobe(struct pcmcia_device *p_dev,
+ cistpl_cftable_entry_t *cfg,
+ cistpl_cftable_entry_t *dflt,
+ unsigned int vcc,
+ void *priv_data)
+{
+ p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ p_dev->io.BasePort1 = cfg->io.win[0].base;
+ p_dev->io.NumPorts1 = cfg->io.win[0].len;
+
+ /* Do we need to allocate an interrupt? */
+ if (cfg->irq.IRQInfo1)
+ p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+
+ /* IO window settings */
+ if (cfg->io.nwin != 1) {
+ lbs_pr_err("wrong CIS (check number of IO windows)\n");
+ return -ENODEV;
+ }
+
+ /* This reserves IO space but doesn't actually enable it */
+ return pcmcia_request_io(p_dev, &p_dev->io);
+}
+
static int if_cs_probe(struct pcmcia_device *p_dev)
{
int ret = -ENOMEM;
unsigned int prod_id;
struct lbs_private *priv;
struct if_cs_card *card;
- /* CIS parsing */
- tuple_t tuple;
- cisparse_t parse;
- cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
- cistpl_io_t *io = &cfg->io;
- u_char buf[64];
lbs_deb_enter(LBS_DEB_CS);
@@ -823,43 +842,11 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
p_dev->conf.Attributes = 0;
p_dev->conf.IntType = INT_MEMORY_AND_IO;
- tuple.Attributes = 0;
- tuple.TupleData = buf;
- tuple.TupleDataMax = sizeof(buf);
- tuple.TupleOffset = 0;
-
- tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
- if ((ret = pcmcia_get_first_tuple(p_dev, &tuple)) != 0 ||
- (ret = pcmcia_get_tuple_data(p_dev, &tuple)) != 0 ||
- (ret = pcmcia_parse_tuple(&tuple, &parse)) != 0)
- {
- lbs_pr_err("error in pcmcia_get_first_tuple etc\n");
- goto out1;
- }
-
- p_dev->conf.ConfigIndex = cfg->index;
-
- /* Do we need to allocate an interrupt? */
- if (cfg->irq.IRQInfo1) {
- p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
- }
-
- /* IO window settings */
- if (cfg->io.nwin != 1) {
- lbs_pr_err("wrong CIS (check number of IO windows)\n");
- ret = -ENODEV;
+ if (pcmcia_loop_config(p_dev, if_cs_ioprobe, NULL)) {
+ lbs_pr_err("error in pcmcia_loop_config\n");
goto out1;
}
- p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- p_dev->io.BasePort1 = io->win[0].base;
- p_dev->io.NumPorts1 = io->win[0].len;
- /* This reserves IO space but doesn't actually enable it */
- ret = pcmcia_request_io(p_dev, &p_dev->io);
- if (ret) {
- lbs_pr_err("error in pcmcia_request_io\n");
- goto out1;
- }
/*
* Allocate an interrupt line. Note that this does not assign
@@ -946,6 +933,9 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
card->priv = priv;
priv->card = card;
priv->hw_host_to_card = if_cs_host_to_card;
+ priv->enter_deep_sleep = NULL;
+ priv->exit_deep_sleep = NULL;
+ priv->reset_deep_sleep_wakeup = NULL;
priv->fw_ready = 1;
/* Now actually get the IRQ */
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 485a8d406525..9716728a33cb 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -831,6 +831,58 @@ out:
return ret;
}
+static int if_sdio_enter_deep_sleep(struct lbs_private *priv)
+{
+ int ret = -1;
+ struct cmd_header cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ lbs_deb_sdio("send DEEP_SLEEP command\n");
+ ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd),
+ lbs_cmd_copyback, (unsigned long) &cmd);
+ if (ret)
+ lbs_pr_err("DEEP_SLEEP cmd failed\n");
+
+ mdelay(200);
+ return ret;
+}
+
+static int if_sdio_exit_deep_sleep(struct lbs_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+ int ret = -1;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+ sdio_claim_host(card->func);
+
+ sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
+ if (ret)
+ lbs_pr_err("sdio_writeb failed!\n");
+
+ sdio_release_host(card->func);
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+ return ret;
+}
+
+static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+ int ret = -1;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+ sdio_claim_host(card->func);
+
+ sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret);
+ if (ret)
+ lbs_pr_err("sdio_writeb failed!\n");
+
+ sdio_release_host(card->func);
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+ return ret;
+
+}
+
/*******************************************************************/
/* SDIO callbacks */
/*******************************************************************/
@@ -859,6 +911,7 @@ static void if_sdio_interrupt(struct sdio_func *func)
* Ignore the define name, this really means the card has
* successfully received the command.
*/
+ card->priv->is_activity_detected = 1;
if (cause & IF_SDIO_H_INT_DNLD)
lbs_host_to_card_done(card->priv);
@@ -998,6 +1051,9 @@ static int if_sdio_probe(struct sdio_func *func,
priv->card = card;
priv->hw_host_to_card = if_sdio_host_to_card;
+ priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
+ priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
+ priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
priv->fw_ready = 1;
diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h
index 60c9b2fcef03..12179c1dc9c9 100644
--- a/drivers/net/wireless/libertas/if_sdio.h
+++ b/drivers/net/wireless/libertas/if_sdio.h
@@ -51,5 +51,6 @@
#define IF_SDIO_EVENT 0x80fc
#define IF_SDIO_BLOCK_SIZE 256
-
+#define CONFIGURATION_REG 0x03
+#define HOST_POWER_UP (0x1U << 1)
#endif
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index cb8be8d7abc1..30d9d0ea28eb 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -134,7 +134,7 @@ static void spu_transaction_finish(struct if_spi_card *card)
static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len)
{
int err = 0;
- u16 reg_out = cpu_to_le16(reg | IF_SPI_WRITE_OPERATION_MASK);
+ __le16 reg_out = cpu_to_le16(reg | IF_SPI_WRITE_OPERATION_MASK);
struct spi_message m;
struct spi_transfer reg_trans;
struct spi_transfer data_trans;
@@ -166,7 +166,7 @@ static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len)
static inline int spu_write_u16(struct if_spi_card *card, u16 reg, u16 val)
{
- u16 buff;
+ __le16 buff;
buff = cpu_to_le16(val);
return spu_write(card, reg, (u8 *)&buff, sizeof(u16));
@@ -188,7 +188,7 @@ static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len)
{
unsigned int delay;
int err = 0;
- u16 reg_out = cpu_to_le16(reg | IF_SPI_READ_OPERATION_MASK);
+ __le16 reg_out = cpu_to_le16(reg | IF_SPI_READ_OPERATION_MASK);
struct spi_message m;
struct spi_transfer reg_trans;
struct spi_transfer dummy_trans;
@@ -235,7 +235,7 @@ static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len)
/* Read 16 bits from an SPI register */
static inline int spu_read_u16(struct if_spi_card *card, u16 reg, u16 *val)
{
- u16 buf;
+ __le16 buf;
int ret;
ret = spu_read(card, reg, (u8 *)&buf, sizeof(buf));
@@ -248,7 +248,7 @@ static inline int spu_read_u16(struct if_spi_card *card, u16 reg, u16 *val)
* The low 16 bits are read first. */
static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val)
{
- u32 buf;
+ __le32 buf;
int err;
err = spu_read(card, reg, (u8 *)&buf, sizeof(buf));
@@ -1117,6 +1117,9 @@ static int __devinit if_spi_probe(struct spi_device *spi)
card->priv = priv;
priv->card = card;
priv->hw_host_to_card = if_spi_host_to_card;
+ priv->enter_deep_sleep = NULL;
+ priv->exit_deep_sleep = NULL;
+ priv->reset_deep_sleep_wakeup = NULL;
priv->fw_ready = 1;
/* Initialize interrupt handling stuff. */
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 92bc8c5f1ca2..a8262dea9b1f 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -300,6 +300,9 @@ static int if_usb_probe(struct usb_interface *intf,
cardp->priv->fw_ready = 1;
priv->hw_host_to_card = if_usb_host_to_card;
+ priv->enter_deep_sleep = NULL;
+ priv->exit_deep_sleep = NULL;
+ priv->reset_deep_sleep_wakeup = NULL;
#ifdef CONFIG_OLPC
if (machine_is_olpc())
priv->reset_card = if_usb_reset_olpc_card;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 87b4e497faa2..01f46cf288d7 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -14,11 +14,13 @@
#include <linux/stddef.h>
#include <linux/ieee80211.h>
#include <net/iw_handler.h>
+#include <net/cfg80211.h>
#include "host.h"
#include "decl.h"
#include "dev.h"
#include "wext.h"
+#include "cfg.h"
#include "debugfs.h"
#include "scan.h"
#include "assoc.h"
@@ -43,119 +45,6 @@ module_param_named(libertas_debug, lbs_debug, int, 0644);
struct cmd_confirm_sleep confirm_sleep;
-#define LBS_TX_PWR_DEFAULT 20 /*100mW */
-#define LBS_TX_PWR_US_DEFAULT 20 /*100mW */
-#define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */
-#define LBS_TX_PWR_FR_DEFAULT 20 /*100mW */
-#define LBS_TX_PWR_EMEA_DEFAULT 20 /*100mW */
-
-/* Format { channel, frequency (MHz), maxtxpower } */
-/* band: 'B/G', region: USA FCC/Canada IC */
-static struct chan_freq_power channel_freq_power_US_BG[] = {
- {1, 2412, LBS_TX_PWR_US_DEFAULT},
- {2, 2417, LBS_TX_PWR_US_DEFAULT},
- {3, 2422, LBS_TX_PWR_US_DEFAULT},
- {4, 2427, LBS_TX_PWR_US_DEFAULT},
- {5, 2432, LBS_TX_PWR_US_DEFAULT},
- {6, 2437, LBS_TX_PWR_US_DEFAULT},
- {7, 2442, LBS_TX_PWR_US_DEFAULT},
- {8, 2447, LBS_TX_PWR_US_DEFAULT},
- {9, 2452, LBS_TX_PWR_US_DEFAULT},
- {10, 2457, LBS_TX_PWR_US_DEFAULT},
- {11, 2462, LBS_TX_PWR_US_DEFAULT}
-};
-
-/* band: 'B/G', region: Europe ETSI */
-static struct chan_freq_power channel_freq_power_EU_BG[] = {
- {1, 2412, LBS_TX_PWR_EMEA_DEFAULT},
- {2, 2417, LBS_TX_PWR_EMEA_DEFAULT},
- {3, 2422, LBS_TX_PWR_EMEA_DEFAULT},
- {4, 2427, LBS_TX_PWR_EMEA_DEFAULT},
- {5, 2432, LBS_TX_PWR_EMEA_DEFAULT},
- {6, 2437, LBS_TX_PWR_EMEA_DEFAULT},
- {7, 2442, LBS_TX_PWR_EMEA_DEFAULT},
- {8, 2447, LBS_TX_PWR_EMEA_DEFAULT},
- {9, 2452, LBS_TX_PWR_EMEA_DEFAULT},
- {10, 2457, LBS_TX_PWR_EMEA_DEFAULT},
- {11, 2462, LBS_TX_PWR_EMEA_DEFAULT},
- {12, 2467, LBS_TX_PWR_EMEA_DEFAULT},
- {13, 2472, LBS_TX_PWR_EMEA_DEFAULT}
-};
-
-/* band: 'B/G', region: Spain */
-static struct chan_freq_power channel_freq_power_SPN_BG[] = {
- {10, 2457, LBS_TX_PWR_DEFAULT},
- {11, 2462, LBS_TX_PWR_DEFAULT}
-};
-
-/* band: 'B/G', region: France */
-static struct chan_freq_power channel_freq_power_FR_BG[] = {
- {10, 2457, LBS_TX_PWR_FR_DEFAULT},
- {11, 2462, LBS_TX_PWR_FR_DEFAULT},
- {12, 2467, LBS_TX_PWR_FR_DEFAULT},
- {13, 2472, LBS_TX_PWR_FR_DEFAULT}
-};
-
-/* band: 'B/G', region: Japan */
-static struct chan_freq_power channel_freq_power_JPN_BG[] = {
- {1, 2412, LBS_TX_PWR_JP_DEFAULT},
- {2, 2417, LBS_TX_PWR_JP_DEFAULT},
- {3, 2422, LBS_TX_PWR_JP_DEFAULT},
- {4, 2427, LBS_TX_PWR_JP_DEFAULT},
- {5, 2432, LBS_TX_PWR_JP_DEFAULT},
- {6, 2437, LBS_TX_PWR_JP_DEFAULT},
- {7, 2442, LBS_TX_PWR_JP_DEFAULT},
- {8, 2447, LBS_TX_PWR_JP_DEFAULT},
- {9, 2452, LBS_TX_PWR_JP_DEFAULT},
- {10, 2457, LBS_TX_PWR_JP_DEFAULT},
- {11, 2462, LBS_TX_PWR_JP_DEFAULT},
- {12, 2467, LBS_TX_PWR_JP_DEFAULT},
- {13, 2472, LBS_TX_PWR_JP_DEFAULT},
- {14, 2484, LBS_TX_PWR_JP_DEFAULT}
-};
-
-/**
- * the structure for channel, frequency and power
- */
-struct region_cfp_table {
- u8 region;
- struct chan_freq_power *cfp_BG;
- int cfp_no_BG;
-};
-
-/**
- * the structure for the mapping between region and CFP
- */
-static struct region_cfp_table region_cfp_table[] = {
- {0x10, /*US FCC */
- channel_freq_power_US_BG,
- ARRAY_SIZE(channel_freq_power_US_BG),
- }
- ,
- {0x20, /*CANADA IC */
- channel_freq_power_US_BG,
- ARRAY_SIZE(channel_freq_power_US_BG),
- }
- ,
- {0x30, /*EU*/ channel_freq_power_EU_BG,
- ARRAY_SIZE(channel_freq_power_EU_BG),
- }
- ,
- {0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
- ARRAY_SIZE(channel_freq_power_SPN_BG),
- }
- ,
- {0x32, /*FRANCE*/ channel_freq_power_FR_BG,
- ARRAY_SIZE(channel_freq_power_FR_BG),
- }
- ,
- {0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
- ARRAY_SIZE(channel_freq_power_JPN_BG),
- }
- ,
-/*Add new region here */
-};
-
/**
* the table to keep region code
*/
@@ -163,13 +52,6 @@ u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
{ 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
/**
- * 802.11b/g supported bitrates (in 500Kb/s units)
- */
-u8 lbs_bg_rates[MAX_RATES] =
- { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
-0x00, 0x00 };
-
-/**
* FW rate table. FW refers to rates by their index in this table, not by the
* rate value itself. Values of 0x00 are
* reserved positions.
@@ -403,7 +285,7 @@ static ssize_t lbs_mesh_set(struct device *dev,
return count;
if (enable)
action = CMD_ACT_MESH_CONFIG_START;
- ret = lbs_mesh_config(priv, action, priv->curbssparams.channel);
+ ret = lbs_mesh_config(priv, action, priv->channel);
if (ret)
return ret;
@@ -574,8 +456,10 @@ void lbs_host_to_card_done(struct lbs_private *priv)
priv->dnld_sent = DNLD_RES_RECEIVED;
/* Wake main thread if commands are pending */
- if (!priv->cur_cmd || priv->tx_pending_len > 0)
- wake_up_interruptible(&priv->waitq);
+ if (!priv->cur_cmd || priv->tx_pending_len > 0) {
+ if (!priv->wakeup_dev_required)
+ wake_up_interruptible(&priv->waitq);
+ }
spin_unlock_irqrestore(&priv->driver_lock, flags);
lbs_deb_leave(LBS_DEB_THREAD);
@@ -770,7 +654,8 @@ static int lbs_thread(void *data)
shouldsleep = 0; /* We have a command response */
else if (priv->cur_cmd)
shouldsleep = 1; /* Can't send a command; one already running */
- else if (!list_empty(&priv->cmdpendingq))
+ else if (!list_empty(&priv->cmdpendingq) &&
+ !(priv->wakeup_dev_required))
shouldsleep = 0; /* We have a command to send */
else if (__kfifo_len(priv->event_fifo))
shouldsleep = 0; /* We have an event to process */
@@ -822,6 +707,26 @@ static int lbs_thread(void *data)
}
spin_unlock_irq(&priv->driver_lock);
+ /* Process hardware events, e.g. card removed, link lost */
+ spin_lock_irq(&priv->driver_lock);
+ while (__kfifo_len(priv->event_fifo)) {
+ u32 event;
+ __kfifo_get(priv->event_fifo, (unsigned char *) &event,
+ sizeof(event));
+ spin_unlock_irq(&priv->driver_lock);
+ lbs_process_event(priv, event);
+ spin_lock_irq(&priv->driver_lock);
+ }
+ spin_unlock_irq(&priv->driver_lock);
+
+ if (priv->wakeup_dev_required) {
+ lbs_deb_thread("Waking up device...\n");
+ /* Wake up device */
+ if (priv->exit_deep_sleep(priv))
+ lbs_deb_thread("Wakeup device failed\n");
+ continue;
+ }
+
/* command timeout stuff */
if (priv->cmd_timed_out && priv->cur_cmd) {
struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
@@ -849,18 +754,7 @@ static int lbs_thread(void *data)
}
priv->cmd_timed_out = 0;
- /* Process hardware events, e.g. card removed, link lost */
- spin_lock_irq(&priv->driver_lock);
- while (__kfifo_len(priv->event_fifo)) {
- u32 event;
- __kfifo_get(priv->event_fifo, (unsigned char *) &event,
- sizeof(event));
- spin_unlock_irq(&priv->driver_lock);
- lbs_process_event(priv, event);
- spin_lock_irq(&priv->driver_lock);
- }
- spin_unlock_irq(&priv->driver_lock);
if (!priv->fw_ready)
continue;
@@ -894,6 +788,9 @@ static int lbs_thread(void *data)
(priv->psstate == PS_STATE_PRE_SLEEP))
continue;
+ if (priv->is_deep_sleep)
+ continue;
+
/* Execute the next command */
if (!priv->dnld_sent && !priv->cur_cmd)
lbs_execute_next_command(priv);
@@ -928,6 +825,7 @@ static int lbs_thread(void *data)
}
del_timer(&priv->command_timer);
+ del_timer(&priv->auto_deepsleep_timer);
wake_up_all(&priv->cmd_pending);
lbs_deb_leave(LBS_DEB_THREAD);
@@ -1050,6 +948,62 @@ out:
lbs_deb_leave(LBS_DEB_CMD);
}
+/**
+ * This function put the device back to deep sleep mode when timer expires
+ * and no activity (command, event, data etc.) is detected.
+ */
+static void auto_deepsleep_timer_fn(unsigned long data)
+{
+ struct lbs_private *priv = (struct lbs_private *)data;
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (priv->is_activity_detected) {
+ priv->is_activity_detected = 0;
+ } else {
+ if (priv->is_auto_deep_sleep_enabled &&
+ (!priv->wakeup_dev_required) &&
+ (priv->connect_status != LBS_CONNECTED)) {
+ lbs_deb_main("Entering auto deep sleep mode...\n");
+ ret = lbs_prepare_and_send_command(priv,
+ CMD_802_11_DEEP_SLEEP, 0,
+ 0, 0, NULL);
+ if (ret)
+ lbs_pr_err("Enter Deep Sleep command failed\n");
+ }
+ }
+ mod_timer(&priv->auto_deepsleep_timer , jiffies +
+ (priv->auto_deep_sleep_timeout * HZ)/1000);
+ lbs_deb_leave(LBS_DEB_CMD);
+}
+
+int lbs_enter_auto_deep_sleep(struct lbs_private *priv)
+{
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ priv->is_auto_deep_sleep_enabled = 1;
+ if (priv->is_deep_sleep)
+ priv->wakeup_dev_required = 1;
+ mod_timer(&priv->auto_deepsleep_timer ,
+ jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000);
+
+ lbs_deb_leave(LBS_DEB_SDIO);
+ return 0;
+}
+
+int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
+{
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ priv->is_auto_deep_sleep_enabled = 0;
+ priv->auto_deep_sleep_timeout = 0;
+ del_timer(&priv->auto_deepsleep_timer);
+
+ lbs_deb_leave(LBS_DEB_SDIO);
+ return 0;
+}
+
static void lbs_sync_channel_worker(struct work_struct *work)
{
struct lbs_private *priv = container_of(work, struct lbs_private,
@@ -1092,18 +1046,24 @@ static int lbs_init_adapter(struct lbs_private *priv)
priv->mesh_connect_status = LBS_DISCONNECTED;
priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
priv->mode = IW_MODE_INFRA;
- priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
+ priv->channel = DEFAULT_AD_HOC_CHANNEL;
priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
priv->radio_on = 1;
priv->enablehwauto = 1;
priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
priv->psmode = LBS802_11POWERMODECAM;
priv->psstate = PS_STATE_FULL_POWER;
+ priv->is_deep_sleep = 0;
+ priv->is_auto_deep_sleep_enabled = 0;
+ priv->wakeup_dev_required = 0;
+ init_waitqueue_head(&priv->ds_awake_q);
mutex_init(&priv->lock);
setup_timer(&priv->command_timer, command_timer_fn,
(unsigned long)priv);
+ setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn,
+ (unsigned long)priv);
INIT_LIST_HEAD(&priv->cmdfreeq);
INIT_LIST_HEAD(&priv->cmdpendingq);
@@ -1142,6 +1102,7 @@ static void lbs_free_adapter(struct lbs_private *priv)
if (priv->event_fifo)
kfifo_free(priv->event_fifo);
del_timer(&priv->command_timer);
+ del_timer(&priv->auto_deepsleep_timer);
kfree(priv->networks);
priv->networks = NULL;
@@ -1168,31 +1129,41 @@ static const struct net_device_ops lbs_netdev_ops = {
*/
struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
{
- struct net_device *dev = NULL;
+ struct net_device *dev;
+ struct wireless_dev *wdev;
struct lbs_private *priv = NULL;
lbs_deb_enter(LBS_DEB_MAIN);
/* Allocate an Ethernet device and register it */
- dev = alloc_etherdev(sizeof(struct lbs_private));
- if (!dev) {
- lbs_pr_err("init wlanX device failed\n");
+ wdev = lbs_cfg_alloc(dmdev);
+ if (IS_ERR(wdev)) {
+ lbs_pr_err("cfg80211 init failed\n");
goto done;
}
- priv = netdev_priv(dev);
- dev->ml_priv = priv;
+ /* TODO? */
+ wdev->iftype = NL80211_IFTYPE_STATION;
+ priv = wdev_priv(wdev);
+ priv->wdev = wdev;
if (lbs_init_adapter(priv)) {
lbs_pr_err("failed to initialize adapter structure.\n");
- goto err_init_adapter;
+ goto err_wdev;
}
+ //TODO? dev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES);
+ dev = alloc_netdev(0, "wlan%d", ether_setup);
+ if (!dev) {
+ dev_err(dmdev, "no memory for network device instance\n");
+ goto err_adapter;
+ }
+
+ dev->ieee80211_ptr = wdev;
+ dev->ml_priv = priv;
+ SET_NETDEV_DEV(dev, dmdev);
+ wdev->netdev = dev;
priv->dev = dev;
- priv->card = card;
- priv->mesh_open = 0;
- priv->infra_open = 0;
- /* Setup the OS Interface to our functions */
dev->netdev_ops = &lbs_netdev_ops;
dev->watchdog_timeo = 5 * HZ;
dev->ethtool_ops = &lbs_ethtool_ops;
@@ -1201,7 +1172,14 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
#endif
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
- SET_NETDEV_DEV(dev, dmdev);
+
+ // TODO: kzalloc + iwm_init_default_profile(iwm, iwm->umac_profile); ??
+
+
+ priv->card = card;
+ priv->mesh_open = 0;
+ priv->infra_open = 0;
+
priv->rtap_net_dev = NULL;
strcpy(dev->name, "wlan%d");
@@ -1211,7 +1189,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main");
if (IS_ERR(priv->main_thread)) {
lbs_deb_thread("Error creating main thread.\n");
- goto err_init_adapter;
+ goto err_ndev;
}
priv->work_thread = create_singlethread_workqueue("lbs_worker");
@@ -1228,9 +1206,15 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
goto done;
-err_init_adapter:
- lbs_free_adapter(priv);
+ err_ndev:
free_netdev(dev);
+
+ err_adapter:
+ lbs_free_adapter(priv);
+
+ err_wdev:
+ lbs_cfg_free(priv);
+
priv = NULL;
done:
@@ -1243,7 +1227,6 @@ EXPORT_SYMBOL_GPL(lbs_add_card);
void lbs_remove_card(struct lbs_private *priv)
{
struct net_device *dev = priv->dev;
- union iwreq_data wrqu;
lbs_deb_enter(LBS_DEB_MAIN);
@@ -1268,15 +1251,19 @@ void lbs_remove_card(struct lbs_private *priv)
lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
}
- memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+ lbs_send_disconnect_notification(priv);
+
+ if (priv->is_deep_sleep) {
+ priv->is_deep_sleep = 0;
+ wake_up_interruptible(&priv->ds_awake_q);
+ }
/* Stop the thread servicing the interrupts */
priv->surpriseremoved = 1;
kthread_stop(priv->main_thread);
lbs_free_adapter(priv);
+ lbs_cfg_free(priv);
priv->dev = NULL;
free_netdev(dev);
@@ -1298,11 +1285,8 @@ int lbs_start_card(struct lbs_private *priv)
if (ret)
goto done;
- /* init 802.11d */
- lbs_init_11d(priv);
-
- if (register_netdev(dev)) {
- lbs_pr_err("cannot register ethX device\n");
+ if (lbs_cfg_register(priv)) {
+ lbs_pr_err("cannot register device\n");
goto done;
}
@@ -1327,10 +1311,10 @@ int lbs_start_card(struct lbs_private *priv)
priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->curbssparams.channel)) {
+ priv->channel)) {
priv->mesh_tlv = TLV_TYPE_MESH_ID;
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->curbssparams.channel))
+ priv->channel))
priv->mesh_tlv = 0;
}
} else if (priv->mesh_fw_ver == MESH_FW_NEW) {
@@ -1339,7 +1323,7 @@ int lbs_start_card(struct lbs_private *priv)
*/
priv->mesh_tlv = TLV_TYPE_MESH_ID;
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->curbssparams.channel))
+ priv->channel))
priv->mesh_tlv = 0;
}
if (priv->mesh_tlv) {
@@ -1392,6 +1376,7 @@ void lbs_stop_card(struct lbs_private *priv)
/* Delete the timeout of the currently processing command */
del_timer_sync(&priv->command_timer);
+ del_timer_sync(&priv->auto_deepsleep_timer);
/* Flush pending command nodes */
spin_lock_irqsave(&priv->driver_lock, flags);
@@ -1509,68 +1494,6 @@ static void lbs_remove_mesh(struct lbs_private *priv)
lbs_deb_leave(LBS_DEB_MESH);
}
-/**
- * @brief This function finds the CFP in
- * region_cfp_table based on region and band parameter.
- *
- * @param region The region code
- * @param band The band
- * @param cfp_no A pointer to CFP number
- * @return A pointer to CFP
- */
-struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no)
-{
- int i, end;
-
- lbs_deb_enter(LBS_DEB_MAIN);
-
- end = ARRAY_SIZE(region_cfp_table);
-
- for (i = 0; i < end ; i++) {
- lbs_deb_main("region_cfp_table[i].region=%d\n",
- region_cfp_table[i].region);
- if (region_cfp_table[i].region == region) {
- *cfp_no = region_cfp_table[i].cfp_no_BG;
- lbs_deb_leave(LBS_DEB_MAIN);
- return region_cfp_table[i].cfp_BG;
- }
- }
-
- lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL");
- return NULL;
-}
-
-int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band)
-{
- int ret = 0;
- int i = 0;
-
- struct chan_freq_power *cfp;
- int cfp_no;
-
- lbs_deb_enter(LBS_DEB_MAIN);
-
- memset(priv->region_channel, 0, sizeof(priv->region_channel));
-
- cfp = lbs_get_region_cfp_table(region, &cfp_no);
- if (cfp != NULL) {
- priv->region_channel[i].nrcfp = cfp_no;
- priv->region_channel[i].CFP = cfp;
- } else {
- lbs_deb_main("wrong region code %#x in band B/G\n",
- region);
- ret = -1;
- goto out;
- }
- priv->region_channel[i].valid = 1;
- priv->region_channel[i].region = region;
- priv->region_channel[i].band = band;
- i++;
-out:
- lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
- return ret;
-}
-
void lbs_queue_event(struct lbs_private *priv, u32 event)
{
unsigned long flags;
diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c
index 18fe29faf99b..871f914a75fc 100644
--- a/drivers/net/wireless/libertas/persistcfg.c
+++ b/drivers/net/wireless/libertas/persistcfg.c
@@ -187,9 +187,9 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
if (ret)
return ret;
- if (defs.meshie.val.mesh_id_len > IW_ESSID_MAX_SIZE) {
+ if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
lbs_pr_err("inconsistent mesh ID length");
- defs.meshie.val.mesh_id_len = IW_ESSID_MAX_SIZE;
+ defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
}
/* SSID not null terminated: reserve room for \0 + \n */
@@ -214,7 +214,7 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
int len;
int ret;
- if (count < 2 || count > IW_ESSID_MAX_SIZE + 1)
+ if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
return -EINVAL;
memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
@@ -233,7 +233,7 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
/* SSID len */
ie->val.mesh_id_len = len;
/* IE len */
- ie->len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len;
+ ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_MESH_IE);
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index 65f02cc6752f..9f18a19cc49d 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -4,7 +4,7 @@
#include <linux/etherdevice.h>
#include <linux/types.h>
-#include "hostcmd.h"
+#include "host.h"
#include "radiotap.h"
#include "decl.h"
#include "dev.h"
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index 6c95af3023cc..c6a6c042b82f 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -12,18 +12,19 @@
#include <net/lib80211.h>
#include "host.h"
-#include "decl.h"
#include "dev.h"
#include "scan.h"
+#include "assoc.h"
+#include "wext.h"
#include "cmd.h"
//! Approximate amount of data needed to pass a scan result back to iwlist
#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \
- + IW_ESSID_MAX_SIZE \
+ + IEEE80211_MAX_SSID_LEN \
+ IW_EV_UINT_LEN \
+ IW_EV_FREQ_LEN \
+ IW_EV_QUAL_LEN \
- + IW_ESSID_MAX_SIZE \
+ + IEEE80211_MAX_SSID_LEN \
+ IW_EV_PARAM_LEN \
+ 40) /* 40 for WPAIE */
@@ -121,6 +122,189 @@ static inline int is_same_network(struct bss_descriptor *src,
+/*********************************************************************/
+/* */
+/* Region channel support */
+/* */
+/*********************************************************************/
+
+#define LBS_TX_PWR_DEFAULT 20 /*100mW */
+#define LBS_TX_PWR_US_DEFAULT 20 /*100mW */
+#define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */
+#define LBS_TX_PWR_FR_DEFAULT 20 /*100mW */
+#define LBS_TX_PWR_EMEA_DEFAULT 20 /*100mW */
+
+/* Format { channel, frequency (MHz), maxtxpower } */
+/* band: 'B/G', region: USA FCC/Canada IC */
+static struct chan_freq_power channel_freq_power_US_BG[] = {
+ {1, 2412, LBS_TX_PWR_US_DEFAULT},
+ {2, 2417, LBS_TX_PWR_US_DEFAULT},
+ {3, 2422, LBS_TX_PWR_US_DEFAULT},
+ {4, 2427, LBS_TX_PWR_US_DEFAULT},
+ {5, 2432, LBS_TX_PWR_US_DEFAULT},
+ {6, 2437, LBS_TX_PWR_US_DEFAULT},
+ {7, 2442, LBS_TX_PWR_US_DEFAULT},
+ {8, 2447, LBS_TX_PWR_US_DEFAULT},
+ {9, 2452, LBS_TX_PWR_US_DEFAULT},
+ {10, 2457, LBS_TX_PWR_US_DEFAULT},
+ {11, 2462, LBS_TX_PWR_US_DEFAULT}
+};
+
+/* band: 'B/G', region: Europe ETSI */
+static struct chan_freq_power channel_freq_power_EU_BG[] = {
+ {1, 2412, LBS_TX_PWR_EMEA_DEFAULT},
+ {2, 2417, LBS_TX_PWR_EMEA_DEFAULT},
+ {3, 2422, LBS_TX_PWR_EMEA_DEFAULT},
+ {4, 2427, LBS_TX_PWR_EMEA_DEFAULT},
+ {5, 2432, LBS_TX_PWR_EMEA_DEFAULT},
+ {6, 2437, LBS_TX_PWR_EMEA_DEFAULT},
+ {7, 2442, LBS_TX_PWR_EMEA_DEFAULT},
+ {8, 2447, LBS_TX_PWR_EMEA_DEFAULT},
+ {9, 2452, LBS_TX_PWR_EMEA_DEFAULT},
+ {10, 2457, LBS_TX_PWR_EMEA_DEFAULT},
+ {11, 2462, LBS_TX_PWR_EMEA_DEFAULT},
+ {12, 2467, LBS_TX_PWR_EMEA_DEFAULT},
+ {13, 2472, LBS_TX_PWR_EMEA_DEFAULT}
+};
+
+/* band: 'B/G', region: Spain */
+static struct chan_freq_power channel_freq_power_SPN_BG[] = {
+ {10, 2457, LBS_TX_PWR_DEFAULT},
+ {11, 2462, LBS_TX_PWR_DEFAULT}
+};
+
+/* band: 'B/G', region: France */
+static struct chan_freq_power channel_freq_power_FR_BG[] = {
+ {10, 2457, LBS_TX_PWR_FR_DEFAULT},
+ {11, 2462, LBS_TX_PWR_FR_DEFAULT},
+ {12, 2467, LBS_TX_PWR_FR_DEFAULT},
+ {13, 2472, LBS_TX_PWR_FR_DEFAULT}
+};
+
+/* band: 'B/G', region: Japan */
+static struct chan_freq_power channel_freq_power_JPN_BG[] = {
+ {1, 2412, LBS_TX_PWR_JP_DEFAULT},
+ {2, 2417, LBS_TX_PWR_JP_DEFAULT},
+ {3, 2422, LBS_TX_PWR_JP_DEFAULT},
+ {4, 2427, LBS_TX_PWR_JP_DEFAULT},
+ {5, 2432, LBS_TX_PWR_JP_DEFAULT},
+ {6, 2437, LBS_TX_PWR_JP_DEFAULT},
+ {7, 2442, LBS_TX_PWR_JP_DEFAULT},
+ {8, 2447, LBS_TX_PWR_JP_DEFAULT},
+ {9, 2452, LBS_TX_PWR_JP_DEFAULT},
+ {10, 2457, LBS_TX_PWR_JP_DEFAULT},
+ {11, 2462, LBS_TX_PWR_JP_DEFAULT},
+ {12, 2467, LBS_TX_PWR_JP_DEFAULT},
+ {13, 2472, LBS_TX_PWR_JP_DEFAULT},
+ {14, 2484, LBS_TX_PWR_JP_DEFAULT}
+};
+
+/**
+ * the structure for channel, frequency and power
+ */
+struct region_cfp_table {
+ u8 region;
+ struct chan_freq_power *cfp_BG;
+ int cfp_no_BG;
+};
+
+/**
+ * the structure for the mapping between region and CFP
+ */
+static struct region_cfp_table region_cfp_table[] = {
+ {0x10, /*US FCC */
+ channel_freq_power_US_BG,
+ ARRAY_SIZE(channel_freq_power_US_BG),
+ }
+ ,
+ {0x20, /*CANADA IC */
+ channel_freq_power_US_BG,
+ ARRAY_SIZE(channel_freq_power_US_BG),
+ }
+ ,
+ {0x30, /*EU*/ channel_freq_power_EU_BG,
+ ARRAY_SIZE(channel_freq_power_EU_BG),
+ }
+ ,
+ {0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
+ ARRAY_SIZE(channel_freq_power_SPN_BG),
+ }
+ ,
+ {0x32, /*FRANCE*/ channel_freq_power_FR_BG,
+ ARRAY_SIZE(channel_freq_power_FR_BG),
+ }
+ ,
+ {0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
+ ARRAY_SIZE(channel_freq_power_JPN_BG),
+ }
+ ,
+/*Add new region here */
+};
+
+/**
+ * @brief This function finds the CFP in
+ * region_cfp_table based on region and band parameter.
+ *
+ * @param region The region code
+ * @param band The band
+ * @param cfp_no A pointer to CFP number
+ * @return A pointer to CFP
+ */
+static struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no)
+{
+ int i, end;
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+
+ end = ARRAY_SIZE(region_cfp_table);
+
+ for (i = 0; i < end ; i++) {
+ lbs_deb_main("region_cfp_table[i].region=%d\n",
+ region_cfp_table[i].region);
+ if (region_cfp_table[i].region == region) {
+ *cfp_no = region_cfp_table[i].cfp_no_BG;
+ lbs_deb_leave(LBS_DEB_MAIN);
+ return region_cfp_table[i].cfp_BG;
+ }
+ }
+
+ lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL");
+ return NULL;
+}
+
+int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band)
+{
+ int ret = 0;
+ int i = 0;
+
+ struct chan_freq_power *cfp;
+ int cfp_no;
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+
+ memset(priv->region_channel, 0, sizeof(priv->region_channel));
+
+ cfp = lbs_get_region_cfp_table(region, &cfp_no);
+ if (cfp != NULL) {
+ priv->region_channel[i].nrcfp = cfp_no;
+ priv->region_channel[i].CFP = cfp;
+ } else {
+ lbs_deb_main("wrong region code %#x in band B/G\n",
+ region);
+ ret = -1;
+ goto out;
+ }
+ priv->region_channel[i].valid = 1;
+ priv->region_channel[i].region = region;
+ priv->region_channel[i].band = band;
+ i++;
+out:
+ lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+ return ret;
+}
+
+
+
/*********************************************************************/
/* */
@@ -161,31 +345,15 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv,
scantype = CMD_SCAN_TYPE_ACTIVE;
for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) {
- if (priv->enable11d && (priv->connect_status != LBS_CONNECTED)
- && (priv->mesh_connect_status != LBS_CONNECTED)) {
- /* Scan all the supported chan for the first scan */
- if (!priv->universal_channel[rgnidx].valid)
- continue;
- scanregion = &priv->universal_channel[rgnidx];
-
- /* clear the parsed_region_chan for the first scan */
- memset(&priv->parsed_region_chan, 0x00,
- sizeof(priv->parsed_region_chan));
- } else {
- if (!priv->region_channel[rgnidx].valid)
- continue;
- scanregion = &priv->region_channel[rgnidx];
- }
+ if (!priv->region_channel[rgnidx].valid)
+ continue;
+ scanregion = &priv->region_channel[rgnidx];
for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) {
struct chanscanparamset *chan = &scanchanlist[chanidx];
cfp = scanregion->CFP + nextchan;
- if (priv->enable11d)
- scantype = lbs_get_scan_type_11d(cfp->channel,
- &priv->parsed_region_chan);
-
if (scanregion->band == BAND_B || scanregion->band == BAND_G)
chan->radiotype = CMD_SCAN_RADIO_TYPE_BG;
@@ -519,7 +687,6 @@ static int lbs_process_bss(struct bss_descriptor *bss,
struct ieee_ie_cf_param_set *cf;
struct ieee_ie_ibss_param_set *ibss;
DECLARE_SSID_BUF(ssid);
- struct ieee_ie_country_info_set *pcountryinfo;
uint8_t *pos, *end, *p;
uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
uint16_t beaconsize = 0;
@@ -642,26 +809,6 @@ static int lbs_process_bss(struct bss_descriptor *bss,
lbs_deb_scan("got IBSS IE\n");
break;
- case WLAN_EID_COUNTRY:
- pcountryinfo = (struct ieee_ie_country_info_set *) pos;
- lbs_deb_scan("got COUNTRY IE\n");
- if (pcountryinfo->header.len < sizeof(pcountryinfo->countrycode)
- || pcountryinfo->header.len > 254) {
- lbs_deb_scan("%s: 11D- Err CountryInfo len %d, min %zd, max 254\n",
- __func__,
- pcountryinfo->header.len,
- sizeof(pcountryinfo->countrycode));
- ret = -1;
- goto done;
- }
-
- memcpy(&bss->countryinfo, pcountryinfo,
- pcountryinfo->header.len + 2);
- lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo",
- (uint8_t *) pcountryinfo,
- (int) (pcountryinfo->header.len + 2));
- break;
-
case WLAN_EID_EXT_SUPP_RATES:
/* only process extended supported rate if data rate is
* already found. Data rate IE should come before
@@ -812,7 +959,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
/* SSID */
iwe.cmd = SIOCGIWESSID;
iwe.u.data.flags = 1;
- iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IW_ESSID_MAX_SIZE);
+ iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IEEE80211_MAX_SSID_LEN);
start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);
/* Mode */
@@ -1022,9 +1169,12 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
return -EAGAIN;
/* Update RSSI if current BSS is a locally created ad-hoc BSS */
- if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate)
- lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
- CMD_OPTION_WAITFORRSP, 0, NULL);
+ if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) {
+ err = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
+ if (err)
+ goto out;
+ }
mutex_lock(&priv->lock);
list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {
@@ -1058,7 +1208,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
dwrq->length = (ev - extra);
dwrq->flags = 0;
-
+out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err);
return err;
}
@@ -1141,11 +1291,11 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
/* The size of the TLV buffer is equal to the entire command response
* size (scanrespsize) minus the fixed fields (sizeof()'s), the
* BSS Descriptions (bssdescriptsize as bytesLef) and the command
- * response header (S_DS_GEN)
+ * response header (sizeof(struct cmd_header))
*/
tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize)
+ sizeof(scanresp->nr_sets)
- + S_DS_GEN);
+ + sizeof(struct cmd_header));
/*
* Process each scan response returned (scanresp->nr_sets). Save
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
index fab7d5d097fc..8fb1706d7526 100644
--- a/drivers/net/wireless/libertas/scan.h
+++ b/drivers/net/wireless/libertas/scan.h
@@ -9,8 +9,36 @@
#include <net/iw_handler.h>
+struct lbs_private;
+
#define MAX_NETWORK_COUNT 128
+/** Chan-freq-TxPower mapping table*/
+struct chan_freq_power {
+ /** channel Number */
+ u16 channel;
+ /** frequency of this channel */
+ u32 freq;
+ /** Max allowed Tx power level */
+ u16 maxtxpower;
+ /** TRUE:channel unsupported; FLASE:supported*/
+ u8 unsupported;
+};
+
+/** region-band mapping table*/
+struct region_channel {
+ /** TRUE if this entry is valid */
+ u8 valid;
+ /** region code for US, Japan ... */
+ u8 region;
+ /** band B/G/A, used for BAND_CONFIG cmd */
+ u8 band;
+ /** Actual No. of elements in the array below */
+ u8 nrcfp;
+ /** chan-freq-txpower mapping table*/
+ struct chan_freq_power *CFP;
+};
+
/**
* @brief Maximum number of channels that can be sent in a setuserscan ioctl
*/
@@ -18,6 +46,8 @@
int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
+int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band);
+
int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,
u8 ssid_len);
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index 8c3766a6e8e7..eb856adbf8ea 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -5,7 +5,7 @@
#include <linux/etherdevice.h>
#include <linux/sched.h>
-#include "hostcmd.h"
+#include "host.h"
#include "radiotap.h"
#include "decl.h"
#include "defs.h"
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
index 99905df65b25..3e72c86ceca8 100644
--- a/drivers/net/wireless/libertas/types.h
+++ b/drivers/net/wireless/libertas/types.h
@@ -5,8 +5,8 @@
#define _LBS_TYPES_H_
#include <linux/if_ether.h>
+#include <linux/ieee80211.h>
#include <asm/byteorder.h>
-#include <linux/wireless.h>
struct ieee_ie_header {
u8 id;
@@ -247,7 +247,7 @@ struct mrvl_meshie_val {
uint8_t active_metric_id;
uint8_t mesh_capability;
uint8_t mesh_id_len;
- uint8_t mesh_id[IW_ESSID_MAX_SIZE];
+ uint8_t mesh_id[IEEE80211_MAX_SSID_LEN];
} __attribute__ ((packed));
struct mrvl_meshie {
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index be837a0d2517..a8eb9e1fcf36 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -45,6 +45,63 @@ static inline void lbs_cancel_association_work(struct lbs_private *priv)
priv->pending_assoc_req = NULL;
}
+void lbs_send_disconnect_notification(struct lbs_private *priv)
+{
+ union iwreq_data wrqu;
+
+ memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+}
+
+static void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
+{
+ union iwreq_data iwrq;
+ u8 buf[50];
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+ memset(&iwrq, 0, sizeof(union iwreq_data));
+ memset(buf, 0, sizeof(buf));
+
+ snprintf(buf, sizeof(buf) - 1, "%s", str);
+
+ iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
+
+ /* Send Event to upper layer */
+ lbs_deb_wext("event indication string %s\n", (char *)buf);
+ lbs_deb_wext("event indication length %d\n", iwrq.data.length);
+ lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
+
+ wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
+
+ lbs_deb_leave(LBS_DEB_WEXT);
+}
+
+/**
+ * @brief This function handles MIC failure event.
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @para event the event id
+ * @return n/a
+ */
+void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event)
+{
+ char buf[50];
+
+ lbs_deb_enter(LBS_DEB_CMD);
+ memset(buf, 0, sizeof(buf));
+
+ sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
+
+ if (event == MACREG_INT_CODE_MIC_ERR_UNICAST)
+ strcat(buf, "unicast ");
+ else
+ strcat(buf, "multicast ");
+
+ lbs_send_iwevcustom_event(priv, buf);
+ lbs_deb_leave(LBS_DEB_CMD);
+}
/**
* @brief Find the channel frequency power info with specific channel
@@ -66,8 +123,6 @@ struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
rc = &priv->region_channel[j];
- if (priv->enable11d)
- rc = &priv->universal_channel[j];
if (!rc->valid || !rc->CFP)
continue;
if (rc->band != band)
@@ -107,8 +162,6 @@ static struct chan_freq_power *find_cfp_by_band_and_freq(
for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
rc = &priv->region_channel[j];
- if (priv->enable11d)
- rc = &priv->universal_channel[j];
if (!rc->valid || !rc->CFP)
continue;
if (rc->band != band)
@@ -169,12 +222,12 @@ static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
cfp = lbs_find_cfp_by_band_and_channel(priv, 0,
- priv->curbssparams.channel);
+ priv->channel);
if (!cfp) {
- if (priv->curbssparams.channel)
+ if (priv->channel)
lbs_deb_wext("invalid channel %d\n",
- priv->curbssparams.channel);
+ priv->channel);
return -EINVAL;
}
@@ -547,8 +600,6 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
struct chan_freq_power *cfp;
u8 rates[MAX_RATES + 1];
- u8 flag = 0;
-
lbs_deb_enter(LBS_DEB_WEXT);
dwrq->length = sizeof(struct iw_range);
@@ -570,52 +621,21 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
range->scan_capa = IW_SCAN_CAPA_ESSID;
- if (priv->enable11d &&
- (priv->connect_status == LBS_CONNECTED ||
- priv->mesh_connect_status == LBS_CONNECTED)) {
- u8 chan_no;
- u8 band;
-
- struct parsed_region_chan_11d *parsed_region_chan =
- &priv->parsed_region_chan;
-
- if (parsed_region_chan == NULL) {
- lbs_deb_wext("11d: parsed_region_chan is NULL\n");
- goto out;
- }
- band = parsed_region_chan->band;
- lbs_deb_wext("band %d, nr_char %d\n", band,
- parsed_region_chan->nr_chan);
-
+ for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+ && (j < ARRAY_SIZE(priv->region_channel)); j++) {
+ cfp = priv->region_channel[j].CFP;
for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
- && (i < parsed_region_chan->nr_chan); i++) {
- chan_no = parsed_region_chan->chanpwr[i].chan;
- lbs_deb_wext("chan_no %d\n", chan_no);
- range->freq[range->num_frequency].i = (long)chan_no;
+ && priv->region_channel[j].valid
+ && cfp
+ && (i < priv->region_channel[j].nrcfp); i++) {
+ range->freq[range->num_frequency].i =
+ (long)cfp->channel;
range->freq[range->num_frequency].m =
- (long)lbs_chan_2_freq(chan_no) * 100000;
+ (long)cfp->freq * 100000;
range->freq[range->num_frequency].e = 1;
+ cfp++;
range->num_frequency++;
}
- flag = 1;
- }
- if (!flag) {
- for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
- && (j < ARRAY_SIZE(priv->region_channel)); j++) {
- cfp = priv->region_channel[j].CFP;
- for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
- && priv->region_channel[j].valid
- && cfp
- && (i < priv->region_channel[j].nrcfp); i++) {
- range->freq[range->num_frequency].i =
- (long)cfp->channel;
- range->freq[range->num_frequency].m =
- (long)cfp->freq * 100000;
- range->freq[range->num_frequency].e = 1;
- cfp++;
- range->num_frequency++;
- }
- }
}
lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n",
@@ -700,7 +720,6 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
| IW_ENC_CAPA_CIPHER_CCMP;
}
-out:
lbs_deb_leave(LBS_DEB_WEXT);
return 0;
}
@@ -709,6 +728,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
struct lbs_private *priv = dev->ml_priv;
+ int ret = 0;
lbs_deb_enter(LBS_DEB_WEXT);
@@ -737,8 +757,54 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
"setting power timeout is not supported\n");
return -EINVAL;
} else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
- lbs_deb_wext("setting power period not supported\n");
- return -EINVAL;
+ vwrq->value = vwrq->value / 1000;
+ if (!priv->enter_deep_sleep) {
+ lbs_pr_err("deep sleep feature is not implemented "
+ "for this interface driver\n");
+ return -EINVAL;
+ }
+
+ if (priv->connect_status == LBS_CONNECTED) {
+ if ((priv->is_auto_deep_sleep_enabled) &&
+ (vwrq->value == -1000)) {
+ lbs_exit_auto_deep_sleep(priv);
+ return 0;
+ } else {
+ lbs_pr_err("can't use deep sleep cmd in "
+ "connected state\n");
+ return -EINVAL;
+ }
+ }
+
+ if ((vwrq->value < 0) && (vwrq->value != -1000)) {
+ lbs_pr_err("unknown option\n");
+ return -EINVAL;
+ }
+
+ if (vwrq->value > 0) {
+ if (!priv->is_auto_deep_sleep_enabled) {
+ priv->is_activity_detected = 0;
+ priv->auto_deep_sleep_timeout = vwrq->value;
+ lbs_enter_auto_deep_sleep(priv);
+ } else {
+ priv->auto_deep_sleep_timeout = vwrq->value;
+ lbs_deb_debugfs("auto deep sleep: "
+ "already enabled\n");
+ }
+ return 0;
+ } else {
+ if (priv->is_auto_deep_sleep_enabled) {
+ lbs_exit_auto_deep_sleep(priv);
+ /* Try to exit deep sleep if auto */
+ /*deep sleep disabled */
+ ret = lbs_set_deep_sleep(priv, 0);
+ }
+ if (vwrq->value == 0)
+ ret = lbs_set_deep_sleep(priv, 1);
+ else if (vwrq->value == -1000)
+ ret = lbs_set_deep_sleep(priv, 0);
+ return ret;
+ }
}
if (priv->psmode != LBS802_11POWERMODECAM) {
@@ -752,6 +818,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
}
lbs_deb_leave(LBS_DEB_WEXT);
+
return 0;
}
@@ -785,7 +852,7 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
u32 rssi_qual;
u32 tx_qual;
u32 quality = 0;
- int stats_valid = 0;
+ int ret, stats_valid = 0;
u8 rssi;
u32 tx_retries;
struct cmd_ds_802_11_get_log log;
@@ -834,7 +901,9 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
memset(&log, 0, sizeof(log));
log.hdr.size = cpu_to_le16(sizeof(log));
- lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log);
+ ret = lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log);
+ if (ret)
+ goto out;
tx_retries = le32_to_cpu(log.retry);
@@ -862,8 +931,10 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
stats_valid = 1;
/* update stats asynchronously for future calls */
- lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
+ ret = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
0, 0, NULL);
+ if (ret)
+ lbs_pr_err("RSSI command failed\n");
out:
if (!stats_valid) {
priv->wstats.miss.beacon = 0;
@@ -973,7 +1044,7 @@ static int lbs_mesh_set_freq(struct net_device *dev,
goto out;
}
- if (fwrq->m != priv->curbssparams.channel) {
+ if (fwrq->m != priv->channel) {
lbs_deb_wext("mesh channel change forces eth disconnect\n");
if (priv->mode == IW_MODE_INFRA)
lbs_cmd_80211_deauthenticate(priv,
@@ -1000,6 +1071,7 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
u8 rates[MAX_RATES + 1];
lbs_deb_enter(LBS_DEB_WEXT);
+
lbs_deb_wext("vwrq->value %d\n", vwrq->value);
lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed);
@@ -1975,7 +2047,7 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
{
struct lbs_private *priv = dev->ml_priv;
int ret = 0;
- u8 ssid[IW_ESSID_MAX_SIZE];
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 ssid_len = 0;
struct assoc_request * assoc_req;
int in_ssid_len = dwrq->length;
@@ -1989,7 +2061,7 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
}
/* Check the size of the string */
- if (in_ssid_len > IW_ESSID_MAX_SIZE) {
+ if (in_ssid_len > IEEE80211_MAX_SSID_LEN) {
ret = -E2BIG;
goto out;
}
@@ -2020,7 +2092,7 @@ out:
ret = -ENOMEM;
} else {
/* Copy the SSID to the association request */
- memcpy(&assoc_req->ssid, &ssid, IW_ESSID_MAX_SIZE);
+ memcpy(&assoc_req->ssid, &ssid, IEEE80211_MAX_SSID_LEN);
assoc_req->ssid_len = ssid_len;
set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
lbs_postpone_association_work(priv);
@@ -2071,7 +2143,7 @@ static int lbs_mesh_set_essid(struct net_device *dev,
}
/* Check the size of the string */
- if (dwrq->length > IW_ESSID_MAX_SIZE) {
+ if (dwrq->length > IEEE80211_MAX_SSID_LEN) {
ret = -E2BIG;
goto out;
}
@@ -2086,7 +2158,7 @@ static int lbs_mesh_set_essid(struct net_device *dev,
}
lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
- priv->curbssparams.channel);
+ priv->channel);
out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret;
diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h
index 4c08db497606..7863baf7d234 100644
--- a/drivers/net/wireless/libertas/wext.h
+++ b/drivers/net/wireless/libertas/wext.h
@@ -4,7 +4,15 @@
#ifndef _LBS_WEXT_H_
#define _LBS_WEXT_H_
+void lbs_send_disconnect_notification(struct lbs_private *priv);
+void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
+
extern struct iw_handler_def lbs_handler_def;
extern struct iw_handler_def mesh_handler_def;
+struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
+ struct lbs_private *priv,
+ u8 band,
+ u16 channel);
+
#endif
diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig
index 83b635fd7784..dce652054afd 100644
--- a/drivers/net/wireless/orinoco/Kconfig
+++ b/drivers/net/wireless/orinoco/Kconfig
@@ -1,8 +1,10 @@
config HERMES
tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)"
depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211
- depends on CFG80211
+ depends on CFG80211 && CFG80211_WEXT
select WIRELESS_EXT
+ select WEXT_SPY
+ select WEXT_PRIV
select FW_LOADER
select CRYPTO
select CRYPTO_MICHAEL_MIC
diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c
index a3eefe109df4..84200da900b6 100644
--- a/drivers/net/wireless/orinoco/hermes_dld.c
+++ b/drivers/net/wireless/orinoco/hermes_dld.c
@@ -550,7 +550,7 @@ static const struct { \
#define DEFAULT_PDR(pid) default_pdr_data_##pid
-/* HWIF Compatiblity */
+/* HWIF Compatibility */
DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00");
/* PPPPSign */
@@ -656,7 +656,7 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
record_id + 1, pdi);
}
break;
- case 0x5: /* HWIF Compatiblity */
+ case 0x5: /* HWIF Compatibility */
default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005);
break;
case 0x108: /* PPPPSign */
diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c
index 359652d35e63..404830f47ab2 100644
--- a/drivers/net/wireless/orinoco/hw.c
+++ b/drivers/net/wireless/orinoco/hw.c
@@ -60,8 +60,15 @@ static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
/* Set priv->firmware type, determine firmware properties
* This function can be called before we have registerred with netdev,
* so all errors go out with dev_* rather than printk
+ *
+ * If non-NULL stores a firmware description in fw_name.
+ * If non-NULL stores a HW version in hw_ver
+ *
+ * These are output via generic cfg80211 ethtool support.
*/
-int determine_fw_capabilities(struct orinoco_private *priv)
+int determine_fw_capabilities(struct orinoco_private *priv,
+ char *fw_name, size_t fw_name_len,
+ u32 *hw_ver)
{
struct device *dev = priv->dev;
hermes_t *hw = &priv->hw;
@@ -85,6 +92,12 @@ int determine_fw_capabilities(struct orinoco_private *priv)
dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n",
nic_id.id, nic_id.variant, nic_id.major, nic_id.minor);
+ if (hw_ver)
+ *hw_ver = (((nic_id.id & 0xff) << 24) |
+ ((nic_id.variant & 0xff) << 16) |
+ ((nic_id.major & 0xff) << 8) |
+ (nic_id.minor & 0xff));
+
priv->firmware_type = determine_firmware_type(&nic_id);
/* Get the firmware version */
@@ -135,8 +148,9 @@ int determine_fw_capabilities(struct orinoco_private *priv)
case FIRMWARE_TYPE_AGERE:
/* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
- snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
- "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor);
+ if (fw_name)
+ snprintf(fw_name, fw_name_len, "Lucent/Agere %d.%02d",
+ sta_id.major, sta_id.minor);
firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
@@ -185,8 +199,8 @@ int determine_fw_capabilities(struct orinoco_private *priv)
tmp[SYMBOL_MAX_VER_LEN] = '\0';
}
- snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
- "Symbol %s", tmp);
+ if (fw_name)
+ snprintf(fw_name, fw_name_len, "Symbol %s", tmp);
priv->has_ibss = (firmver >= 0x20000);
priv->has_wep = (firmver >= 0x15012);
@@ -224,9 +238,9 @@ int determine_fw_capabilities(struct orinoco_private *priv)
* different and less well tested */
/* D-Link MAC : 00:40:05:* */
/* Addtron MAC : 00:90:D1:* */
- snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
- "Intersil %d.%d.%d", sta_id.major, sta_id.minor,
- sta_id.variant);
+ if (fw_name)
+ snprintf(fw_name, fw_name_len, "Intersil %d.%d.%d",
+ sta_id.major, sta_id.minor, sta_id.variant);
firmver = ((unsigned long)sta_id.major << 16) |
((unsigned long)sta_id.minor << 8) | sta_id.variant;
@@ -245,7 +259,8 @@ int determine_fw_capabilities(struct orinoco_private *priv)
}
break;
}
- dev_info(dev, "Firmware determined as %s\n", priv->fw_name);
+ if (fw_name)
+ dev_info(dev, "Firmware determined as %s\n", fw_name);
return 0;
}
diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h
index 8df6e8752be6..e2f7fdc4d45a 100644
--- a/drivers/net/wireless/orinoco/hw.h
+++ b/drivers/net/wireless/orinoco/hw.h
@@ -24,7 +24,8 @@
struct orinoco_private;
struct dev_addr_list;
-int determine_fw_capabilities(struct orinoco_private *priv);
+int determine_fw_capabilities(struct orinoco_private *priv, char *fw_name,
+ size_t fw_name_len, u32 *hw_ver);
int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr);
int orinoco_hw_allocate_fid(struct orinoco_private *priv);
int orinoco_get_bitratemode(int bitrate, int automatic);
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index 7a32bcb0c037..753a1804eee7 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -83,7 +83,6 @@
#include <linux/device.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
#include <linux/suspend.h>
#include <linux/if_arp.h>
#include <linux/wireless.h>
@@ -162,8 +161,6 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
| HERMES_EV_WTERR | HERMES_EV_INFO \
| HERMES_EV_INFDROP)
-static const struct ethtool_ops orinoco_ethtool_ops;
-
/********************************************************************/
/* Data types */
/********************************************************************/
@@ -1994,7 +1991,9 @@ int orinoco_init(struct orinoco_private *priv)
goto out;
}
- err = determine_fw_capabilities(priv);
+ err = determine_fw_capabilities(priv, wiphy->fw_version,
+ sizeof(wiphy->fw_version),
+ &wiphy->hw_version);
if (err != 0) {
dev_err(dev, "Incompatible firmware, aborting\n");
goto out;
@@ -2010,7 +2009,9 @@ int orinoco_init(struct orinoco_private *priv)
priv->do_fw_download = 0;
/* Check firmware version again */
- err = determine_fw_capabilities(priv);
+ err = determine_fw_capabilities(priv, wiphy->fw_version,
+ sizeof(wiphy->fw_version),
+ &wiphy->hw_version);
if (err != 0) {
dev_err(dev, "Incompatible firmware, aborting\n");
goto out;
@@ -2212,7 +2213,6 @@ int orinoco_if_add(struct orinoco_private *priv,
dev->ieee80211_ptr = wdev;
dev->netdev_ops = &orinoco_netdev_ops;
dev->watchdog_timeo = HZ; /* 1 second timeout */
- dev->ethtool_ops = &orinoco_ethtool_ops;
dev->wireless_handlers = &orinoco_handler_def;
#ifdef WIRELESS_SPY
dev->wireless_data = &priv->wireless_data;
@@ -2225,6 +2225,7 @@ int orinoco_if_add(struct orinoco_private *priv,
netif_carrier_off(dev);
memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN);
+ memcpy(dev->perm_addr, wiphy->perm_addr, ETH_ALEN);
dev->base_addr = base_addr;
dev->irq = irq;
@@ -2348,27 +2349,6 @@ void orinoco_down(struct orinoco_private *priv)
}
EXPORT_SYMBOL(orinoco_down);
-static void orinoco_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- struct orinoco_private *priv = ndev_priv(dev);
-
- strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
- strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
- strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1);
- if (dev->dev.parent)
- strncpy(info->bus_info, dev_name(dev->dev.parent),
- sizeof(info->bus_info) - 1);
- else
- snprintf(info->bus_info, sizeof(info->bus_info) - 1,
- "PCMCIA %p", priv->hw.iobase);
-}
-
-static const struct ethtool_ops orinoco_ethtool_ops = {
- .get_drvinfo = orinoco_get_drvinfo,
- .get_link = ethtool_op_get_link,
-};
-
/********************************************************************/
/* Module initialization */
/********************************************************************/
diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h
index 9ac6f1dda4b0..665ef56f8382 100644
--- a/drivers/net/wireless/orinoco/orinoco.h
+++ b/drivers/net/wireless/orinoco/orinoco.h
@@ -93,7 +93,6 @@ struct orinoco_private {
/* Capabilities of the hardware/firmware */
fwtype_t firmware_type;
- char fw_name[32];
int ibss_port;
int nicbuf_size;
u16 channel_mask;
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index ed1f997e3521..390c0c7b3ac2 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -53,6 +53,32 @@ config RT61PCI
When compiled as a module, this driver will be called rt61pci.
+config RT2800PCI_PCI
+ tristate
+ depends on PCI
+ default y
+
+config RT2800PCI_SOC
+ tristate
+ depends on RALINK_RT288X || RALINK_RT305X
+ default y
+
+config RT2800PCI
+ tristate "Ralink rt2800 (PCI/PCMCIA) support"
+ depends on (RT2800PCI_PCI || RT2800PCI_SOC) && EXPERIMENTAL
+ select RT2X00_LIB_PCI if RT2800PCI_PCI
+ select RT2X00_LIB_SOC if RT2800PCI_SOC
+ select RT2X00_LIB_HT
+ select RT2X00_LIB_FIRMWARE
+ select RT2X00_LIB_CRYPTO
+ select CRC_CCITT
+ select EEPROM_93CX6
+ ---help---
+ This adds support for rt2800 wireless chipset family.
+ Supported chips: RT2760, RT2790, RT2860, RT2880, RT2890 & RT3052
+
+ When compiled as a module, this driver will be called "rt2800pci.ko".
+
config RT2500USB
tristate "Ralink rt2500 (USB) support"
depends on USB
@@ -95,6 +121,10 @@ config RT2X00_LIB_PCI
tristate
select RT2X00_LIB
+config RT2X00_LIB_SOC
+ tristate
+ select RT2X00_LIB
+
config RT2X00_LIB_USB
tristate
select RT2X00_LIB
diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile
index 13043ea97667..912f5f67e159 100644
--- a/drivers/net/wireless/rt2x00/Makefile
+++ b/drivers/net/wireless/rt2x00/Makefile
@@ -11,10 +11,12 @@ rt2x00lib-$(CONFIG_RT2X00_LIB_HT) += rt2x00ht.o
obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o
obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o
+obj-$(CONFIG_RT2X00_LIB_SOC) += rt2x00soc.o
obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o
obj-$(CONFIG_RT2400PCI) += rt2400pci.o
obj-$(CONFIG_RT2500PCI) += rt2500pci.o
obj-$(CONFIG_RT61PCI) += rt61pci.o
+obj-$(CONFIG_RT2800PCI) += rt2800pci.o
obj-$(CONFIG_RT2500USB) += rt2500usb.o
obj-$(CONFIG_RT73USB) += rt73usb.o
obj-$(CONFIG_RT2800USB) += rt2800usb.o
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
new file mode 100644
index 000000000000..be81788b80c7
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -0,0 +1,3323 @@
+/*
+ Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2800pci
+ Abstract: rt2800pci device specific routines.
+ Supported chipsets: RT2800E & RT2800ED.
+ */
+
+#include <linux/crc-ccitt.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/eeprom_93cx6.h>
+
+#include "rt2x00.h"
+#include "rt2x00pci.h"
+#include "rt2x00soc.h"
+#include "rt2800pci.h"
+
+#ifdef CONFIG_RT2800PCI_PCI_MODULE
+#define CONFIG_RT2800PCI_PCI
+#endif
+
+#ifdef CONFIG_RT2800PCI_WISOC_MODULE
+#define CONFIG_RT2800PCI_WISOC
+#endif
+
+/*
+ * Allow hardware encryption to be disabled.
+ */
+static int modparam_nohwcrypt = 1;
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+
+/*
+ * Register access.
+ * BBP and RF register require indirect register access,
+ * and use the CSR registers PHY_CSR3 and PHY_CSR4 to achieve this.
+ * These indirect registers work with busy bits,
+ * and we will try maximal REGISTER_BUSY_COUNT times to access
+ * the register while taking a REGISTER_BUSY_DELAY us delay
+ * between each attampt. When the busy bit is still set at that time,
+ * the access attempt is considered to have failed,
+ * and we will print an error.
+ */
+#define WAIT_FOR_BBP(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg))
+#define WAIT_FOR_RFCSR(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY, (__reg))
+#define WAIT_FOR_RF(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), RF_CSR_CFG0, RF_CSR_CFG0_BUSY, (__reg))
+#define WAIT_FOR_MCU(__dev, __reg) \
+ rt2x00pci_regbusy_read((__dev), H2M_MAILBOX_CSR, \
+ H2M_MAILBOX_CSR_OWNER, (__reg))
+
+static void rt2800pci_bbp_write(struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u8 value)
+{
+ u32 reg;
+
+ mutex_lock(&rt2x00dev->csr_mutex);
+
+ /*
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the new data into the register.
+ */
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_VALUE, value);
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_REGNUM, word);
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_BUSY, 1);
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_READ_CONTROL, 0);
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
+
+ rt2x00pci_register_write(rt2x00dev, BBP_CSR_CFG, reg);
+ }
+
+ mutex_unlock(&rt2x00dev->csr_mutex);
+}
+
+static void rt2800pci_bbp_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u8 *value)
+{
+ u32 reg;
+
+ mutex_lock(&rt2x00dev->csr_mutex);
+
+ /*
+ * Wait until the BBP becomes available, afterwards we
+ * can safely write the read request into the register.
+ * After the data has been written, we wait until hardware
+ * returns the correct value, if at any time the register
+ * doesn't become available in time, reg will be 0xffffffff
+ * which means we return 0xff to the caller.
+ */
+ if (WAIT_FOR_BBP(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_REGNUM, word);
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_BUSY, 1);
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_READ_CONTROL, 1);
+ rt2x00_set_field32(&reg, BBP_CSR_CFG_BBP_RW_MODE, 1);
+
+ rt2x00pci_register_write(rt2x00dev, BBP_CSR_CFG, reg);
+
+ WAIT_FOR_BBP(rt2x00dev, &reg);
+ }
+
+ *value = rt2x00_get_field32(reg, BBP_CSR_CFG_VALUE);
+
+ mutex_unlock(&rt2x00dev->csr_mutex);
+}
+
+static void rt2800pci_rfcsr_write(struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u8 value)
+{
+ u32 reg;
+
+ mutex_lock(&rt2x00dev->csr_mutex);
+
+ /*
+ * Wait until the RFCSR becomes available, afterwards we
+ * can safely write the new data into the register.
+ */
+ if (WAIT_FOR_RFCSR(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, RF_CSR_CFG_DATA, value);
+ rt2x00_set_field32(&reg, RF_CSR_CFG_REGNUM, word);
+ rt2x00_set_field32(&reg, RF_CSR_CFG_WRITE, 1);
+ rt2x00_set_field32(&reg, RF_CSR_CFG_BUSY, 1);
+
+ rt2x00pci_register_write(rt2x00dev, RF_CSR_CFG, reg);
+ }
+
+ mutex_unlock(&rt2x00dev->csr_mutex);
+}
+
+static void rt2800pci_rfcsr_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u8 *value)
+{
+ u32 reg;
+
+ mutex_lock(&rt2x00dev->csr_mutex);
+
+ /*
+ * Wait until the RFCSR becomes available, afterwards we
+ * can safely write the read request into the register.
+ * After the data has been written, we wait until hardware
+ * returns the correct value, if at any time the register
+ * doesn't become available in time, reg will be 0xffffffff
+ * which means we return 0xff to the caller.
+ */
+ if (WAIT_FOR_RFCSR(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, RF_CSR_CFG_REGNUM, word);
+ rt2x00_set_field32(&reg, RF_CSR_CFG_WRITE, 0);
+ rt2x00_set_field32(&reg, RF_CSR_CFG_BUSY, 1);
+
+ rt2x00pci_register_write(rt2x00dev, RF_CSR_CFG, reg);
+
+ WAIT_FOR_RFCSR(rt2x00dev, &reg);
+ }
+
+ *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA);
+
+ mutex_unlock(&rt2x00dev->csr_mutex);
+}
+
+static void rt2800pci_rf_write(struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u32 value)
+{
+ u32 reg;
+
+ mutex_lock(&rt2x00dev->csr_mutex);
+
+ /*
+ * Wait until the RF becomes available, afterwards we
+ * can safely write the new data into the register.
+ */
+ if (WAIT_FOR_RF(rt2x00dev, &reg)) {
+ reg = 0;
+ rt2x00_set_field32(&reg, RF_CSR_CFG0_REG_VALUE_BW, value);
+ rt2x00_set_field32(&reg, RF_CSR_CFG0_STANDBYMODE, 0);
+ rt2x00_set_field32(&reg, RF_CSR_CFG0_SEL, 0);
+ rt2x00_set_field32(&reg, RF_CSR_CFG0_BUSY, 1);
+
+ rt2x00pci_register_write(rt2x00dev, RF_CSR_CFG0, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+ }
+
+ mutex_unlock(&rt2x00dev->csr_mutex);
+}
+
+static void rt2800pci_mcu_request(struct rt2x00_dev *rt2x00dev,
+ const u8 command, const u8 token,
+ const u8 arg0, const u8 arg1)
+{
+ u32 reg;
+
+ /*
+ * RT2880 and RT3052 don't support MCU requests.
+ */
+ if (rt2x00_rt(&rt2x00dev->chip, RT2880) ||
+ rt2x00_rt(&rt2x00dev->chip, RT3052))
+ return;
+
+ mutex_lock(&rt2x00dev->csr_mutex);
+
+ /*
+ * Wait until the MCU becomes available, afterwards we
+ * can safely write the new data into the register.
+ */
+ if (WAIT_FOR_MCU(rt2x00dev, &reg)) {
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_OWNER, 1);
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_CMD_TOKEN, token);
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG0, arg0);
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG1, arg1);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg);
+
+ reg = 0;
+ rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command);
+ rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg);
+ }
+
+ mutex_unlock(&rt2x00dev->csr_mutex);
+}
+
+static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)
+{
+ unsigned int i;
+ u32 reg;
+
+ for (i = 0; i < 200; i++) {
+ rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CID, &reg);
+
+ if ((rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD0) == token) ||
+ (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD1) == token) ||
+ (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD2) == token) ||
+ (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD3) == token))
+ break;
+
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ if (i == 200)
+ ERROR(rt2x00dev, "MCU request failed, no response from hardware\n");
+
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
+}
+
+#ifdef CONFIG_RT2800PCI_WISOC
+static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
+{
+ u32 *base_addr = (u32 *) KSEG1ADDR(0x1F040000); /* XXX for RT3052 */
+
+ memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE);
+}
+#else
+static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
+{
+}
+#endif /* CONFIG_RT2800PCI_WISOC */
+
+#ifdef CONFIG_RT2800PCI_PCI
+static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
+{
+ struct rt2x00_dev *rt2x00dev = eeprom->data;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
+
+ eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN);
+ eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT);
+ eeprom->reg_data_clock =
+ !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_CLOCK);
+ eeprom->reg_chip_select =
+ !!rt2x00_get_field32(reg, E2PROM_CSR_CHIP_SELECT);
+}
+
+static void rt2800pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
+{
+ struct rt2x00_dev *rt2x00dev = eeprom->data;
+ u32 reg = 0;
+
+ rt2x00_set_field32(&reg, E2PROM_CSR_DATA_IN, !!eeprom->reg_data_in);
+ rt2x00_set_field32(&reg, E2PROM_CSR_DATA_OUT, !!eeprom->reg_data_out);
+ rt2x00_set_field32(&reg, E2PROM_CSR_DATA_CLOCK,
+ !!eeprom->reg_data_clock);
+ rt2x00_set_field32(&reg, E2PROM_CSR_CHIP_SELECT,
+ !!eeprom->reg_chip_select);
+
+ rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg);
+}
+
+static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
+{
+ struct eeprom_93cx6 eeprom;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
+
+ eeprom.data = rt2x00dev;
+ eeprom.register_read = rt2800pci_eepromregister_read;
+ eeprom.register_write = rt2800pci_eepromregister_write;
+ eeprom.width = !rt2x00_get_field32(reg, E2PROM_CSR_TYPE) ?
+ PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66;
+ eeprom.reg_data_in = 0;
+ eeprom.reg_data_out = 0;
+ eeprom.reg_data_clock = 0;
+ eeprom.reg_chip_select = 0;
+
+ eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom,
+ EEPROM_SIZE / sizeof(u16));
+}
+
+static void rt2800pci_efuse_read(struct rt2x00_dev *rt2x00dev,
+ unsigned int i)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, EFUSE_CTRL, &reg);
+ rt2x00_set_field32(&reg, EFUSE_CTRL_ADDRESS_IN, i);
+ rt2x00_set_field32(&reg, EFUSE_CTRL_MODE, 0);
+ rt2x00_set_field32(&reg, EFUSE_CTRL_KICK, 1);
+ rt2x00pci_register_write(rt2x00dev, EFUSE_CTRL, reg);
+
+ /* Wait until the EEPROM has been loaded */
+ rt2x00pci_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, &reg);
+
+ /* Apparently the data is read from end to start */
+ rt2x00pci_register_read(rt2x00dev, EFUSE_DATA3,
+ (u32 *)&rt2x00dev->eeprom[i]);
+ rt2x00pci_register_read(rt2x00dev, EFUSE_DATA2,
+ (u32 *)&rt2x00dev->eeprom[i + 2]);
+ rt2x00pci_register_read(rt2x00dev, EFUSE_DATA1,
+ (u32 *)&rt2x00dev->eeprom[i + 4]);
+ rt2x00pci_register_read(rt2x00dev, EFUSE_DATA0,
+ (u32 *)&rt2x00dev->eeprom[i + 6]);
+}
+
+static void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+
+ for (i = 0; i < EEPROM_SIZE / sizeof(u16); i += 8)
+ rt2800pci_efuse_read(rt2x00dev, i);
+}
+#else
+static inline void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
+{
+}
+
+static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
+{
+}
+#endif /* CONFIG_RT2800PCI_PCI */
+
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+static const struct rt2x00debug rt2800pci_rt2x00debug = {
+ .owner = THIS_MODULE,
+ .csr = {
+ .read = rt2x00pci_register_read,
+ .write = rt2x00pci_register_write,
+ .flags = RT2X00DEBUGFS_OFFSET,
+ .word_base = CSR_REG_BASE,
+ .word_size = sizeof(u32),
+ .word_count = CSR_REG_SIZE / sizeof(u32),
+ },
+ .eeprom = {
+ .read = rt2x00_eeprom_read,
+ .write = rt2x00_eeprom_write,
+ .word_base = EEPROM_BASE,
+ .word_size = sizeof(u16),
+ .word_count = EEPROM_SIZE / sizeof(u16),
+ },
+ .bbp = {
+ .read = rt2800pci_bbp_read,
+ .write = rt2800pci_bbp_write,
+ .word_base = BBP_BASE,
+ .word_size = sizeof(u8),
+ .word_count = BBP_SIZE / sizeof(u8),
+ },
+ .rf = {
+ .read = rt2x00_rf_read,
+ .write = rt2800pci_rf_write,
+ .word_base = RF_BASE,
+ .word_size = sizeof(u32),
+ .word_count = RF_SIZE / sizeof(u32),
+ },
+};
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+static int rt2800pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, GPIO_CTRL_CFG, &reg);
+ return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2);
+}
+
+#ifdef CONFIG_RT2X00_LIB_LEDS
+static void rt2800pci_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct rt2x00_led *led =
+ container_of(led_cdev, struct rt2x00_led, led_dev);
+ unsigned int enabled = brightness != LED_OFF;
+ unsigned int bg_mode =
+ (enabled && led->rt2x00dev->curr_band == IEEE80211_BAND_2GHZ);
+ unsigned int polarity =
+ rt2x00_get_field16(led->rt2x00dev->led_mcu_reg,
+ EEPROM_FREQ_LED_POLARITY);
+ unsigned int ledmode =
+ rt2x00_get_field16(led->rt2x00dev->led_mcu_reg,
+ EEPROM_FREQ_LED_MODE);
+
+ if (led->type == LED_TYPE_RADIO) {
+ rt2800pci_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode,
+ enabled ? 0x20 : 0);
+ } else if (led->type == LED_TYPE_ASSOC) {
+ rt2800pci_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode,
+ enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20);
+ } else if (led->type == LED_TYPE_QUALITY) {
+ /*
+ * The brightness is divided into 6 levels (0 - 5),
+ * The specs tell us the following levels:
+ * 0, 1 ,3, 7, 15, 31
+ * to determine the level in a simple way we can simply
+ * work with bitshifting:
+ * (1 << level) - 1
+ */
+ rt2800pci_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff,
+ (1 << brightness / (LED_FULL / 6)) - 1,
+ polarity);
+ }
+}
+
+static int rt2800pci_blink_set(struct led_classdev *led_cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ struct rt2x00_led *led =
+ container_of(led_cdev, struct rt2x00_led, led_dev);
+ u32 reg;
+
+ rt2x00pci_register_read(led->rt2x00dev, LED_CFG, &reg);
+ rt2x00_set_field32(&reg, LED_CFG_ON_PERIOD, *delay_on);
+ rt2x00_set_field32(&reg, LED_CFG_OFF_PERIOD, *delay_off);
+ rt2x00_set_field32(&reg, LED_CFG_SLOW_BLINK_PERIOD, 3);
+ rt2x00_set_field32(&reg, LED_CFG_R_LED_MODE, 3);
+ rt2x00_set_field32(&reg, LED_CFG_G_LED_MODE, 12);
+ rt2x00_set_field32(&reg, LED_CFG_Y_LED_MODE, 3);
+ rt2x00_set_field32(&reg, LED_CFG_LED_POLAR, 1);
+ rt2x00pci_register_write(led->rt2x00dev, LED_CFG, reg);
+
+ return 0;
+}
+
+static void rt2800pci_init_led(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_led *led,
+ enum led_type type)
+{
+ led->rt2x00dev = rt2x00dev;
+ led->type = type;
+ led->led_dev.brightness_set = rt2800pci_brightness_set;
+ led->led_dev.blink_set = rt2800pci_blink_set;
+ led->flags = LED_INITIALIZED;
+}
+#endif /* CONFIG_RT2X00_LIB_LEDS */
+
+/*
+ * Configuration handlers.
+ */
+static void rt2800pci_config_wcid_attr(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_crypto *crypto,
+ struct ieee80211_key_conf *key)
+{
+ struct mac_wcid_entry wcid_entry;
+ struct mac_iveiv_entry iveiv_entry;
+ u32 offset;
+ u32 reg;
+
+ offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx);
+
+ rt2x00pci_register_read(rt2x00dev, offset, &reg);
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_KEYTAB,
+ !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE));
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER,
+ (crypto->cmd == SET_KEY) * crypto->cipher);
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX,
+ (crypto->cmd == SET_KEY) * crypto->bssidx);
+ rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher);
+ rt2x00pci_register_write(rt2x00dev, offset, reg);
+
+ offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
+
+ memset(&iveiv_entry, 0, sizeof(iveiv_entry));
+ if ((crypto->cipher == CIPHER_TKIP) ||
+ (crypto->cipher == CIPHER_TKIP_NO_MIC) ||
+ (crypto->cipher == CIPHER_AES))
+ iveiv_entry.iv[3] |= 0x20;
+ iveiv_entry.iv[3] |= key->keyidx << 6;
+ rt2x00pci_register_multiwrite(rt2x00dev, offset,
+ &iveiv_entry, sizeof(iveiv_entry));
+
+ offset = MAC_WCID_ENTRY(key->hw_key_idx);
+
+ memset(&wcid_entry, 0, sizeof(wcid_entry));
+ if (crypto->cmd == SET_KEY)
+ memcpy(&wcid_entry, crypto->address, ETH_ALEN);
+ rt2x00pci_register_multiwrite(rt2x00dev, offset,
+ &wcid_entry, sizeof(wcid_entry));
+}
+
+static int rt2800pci_config_shared_key(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_crypto *crypto,
+ struct ieee80211_key_conf *key)
+{
+ struct hw_key_entry key_entry;
+ struct rt2x00_field32 field;
+ u32 offset;
+ u32 reg;
+
+ if (crypto->cmd == SET_KEY) {
+ key->hw_key_idx = (4 * crypto->bssidx) + key->keyidx;
+
+ memcpy(key_entry.key, crypto->key,
+ sizeof(key_entry.key));
+ memcpy(key_entry.tx_mic, crypto->tx_mic,
+ sizeof(key_entry.tx_mic));
+ memcpy(key_entry.rx_mic, crypto->rx_mic,
+ sizeof(key_entry.rx_mic));
+
+ offset = SHARED_KEY_ENTRY(key->hw_key_idx);
+ rt2x00pci_register_multiwrite(rt2x00dev, offset,
+ &key_entry, sizeof(key_entry));
+ }
+
+ /*
+ * The cipher types are stored over multiple registers
+ * starting with SHARED_KEY_MODE_BASE each word will have
+ * 32 bits and contains the cipher types for 2 bssidx each.
+ * Using the correct defines correctly will cause overhead,
+ * so just calculate the correct offset.
+ */
+ field.bit_offset = 4 * (key->hw_key_idx % 8);
+ field.bit_mask = 0x7 << field.bit_offset;
+
+ offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8);
+
+ rt2x00pci_register_read(rt2x00dev, offset, &reg);
+ rt2x00_set_field32(&reg, field,
+ (crypto->cmd == SET_KEY) * crypto->cipher);
+ rt2x00pci_register_write(rt2x00dev, offset, reg);
+
+ /*
+ * Update WCID information
+ */
+ rt2800pci_config_wcid_attr(rt2x00dev, crypto, key);
+
+ return 0;
+}
+
+static int rt2800pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_crypto *crypto,
+ struct ieee80211_key_conf *key)
+{
+ struct hw_key_entry key_entry;
+ u32 offset;
+
+ if (crypto->cmd == SET_KEY) {
+ /*
+ * 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.
+ */
+ if (crypto->aid > (256 - 32))
+ return -ENOSPC;
+
+ key->hw_key_idx = 32 + crypto->aid;
+
+
+ memcpy(key_entry.key, crypto->key,
+ sizeof(key_entry.key));
+ memcpy(key_entry.tx_mic, crypto->tx_mic,
+ sizeof(key_entry.tx_mic));
+ memcpy(key_entry.rx_mic, crypto->rx_mic,
+ sizeof(key_entry.rx_mic));
+
+ offset = PAIRWISE_KEY_ENTRY(key->hw_key_idx);
+ rt2x00pci_register_multiwrite(rt2x00dev, offset,
+ &key_entry, sizeof(key_entry));
+ }
+
+ /*
+ * Update WCID information
+ */
+ rt2800pci_config_wcid_attr(rt2x00dev, crypto, key);
+
+ return 0;
+}
+
+static void rt2800pci_config_filter(struct rt2x00_dev *rt2x00dev,
+ const unsigned int filter_flags)
+{
+ u32 reg;
+
+ /*
+ * Start configuration steps.
+ * Note that the version error will always be dropped
+ * and broadcast frames will always be accepted since
+ * there is no filter for it at this time.
+ */
+ rt2x00pci_register_read(rt2x00dev, RX_FILTER_CFG, &reg);
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CRC_ERROR,
+ !(filter_flags & FIF_FCSFAIL));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PHY_ERROR,
+ !(filter_flags & FIF_PLCPFAIL));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_TO_ME,
+ !(filter_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0);
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_VER_ERROR, 1);
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_MULTICAST,
+ !(filter_flags & FIF_ALLMULTI));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BROADCAST, 0);
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_DUPLICATE, 1);
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CF_END_ACK,
+ !(filter_flags & FIF_CONTROL));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CF_END,
+ !(filter_flags & FIF_CONTROL));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_ACK,
+ !(filter_flags & FIF_CONTROL));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CTS,
+ !(filter_flags & FIF_CONTROL));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_RTS,
+ !(filter_flags & FIF_CONTROL));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PSPOLL,
+ !(filter_flags & FIF_PSPOLL));
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA, 1);
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BAR, 0);
+ rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CNTL,
+ !(filter_flags & FIF_CONTROL));
+ rt2x00pci_register_write(rt2x00dev, RX_FILTER_CFG, reg);
+}
+
+static void rt2800pci_config_intf(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_intf *intf,
+ struct rt2x00intf_conf *conf,
+ const unsigned int flags)
+{
+ unsigned int beacon_base;
+ u32 reg;
+
+ if (flags & CONFIG_UPDATE_TYPE) {
+ /*
+ * Clear current synchronisation setup.
+ * For the Beacon base registers we only need to clear
+ * the first byte since that byte contains the VALID and OWNER
+ * bits which (when set to 0) will invalidate the entire beacon.
+ */
+ beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
+ rt2x00pci_register_write(rt2x00dev, beacon_base, 0);
+
+ /*
+ * Enable synchronisation.
+ */
+ rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_SYNC, conf->sync);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
+ rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ }
+
+ 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);
+
+ rt2x00pci_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, 0);
+ rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 0);
+ conf->bssid[1] = cpu_to_le32(reg);
+
+ rt2x00pci_register_multiwrite(rt2x00dev, MAC_BSSID_DW0,
+ conf->bssid, sizeof(conf->bssid));
+ }
+}
+
+static void rt2800pci_config_erp(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_erp *erp)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, TX_TIMEOUT_CFG, &reg);
+ rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 0x20);
+ rt2x00pci_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg);
+
+ rt2x00pci_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);
+ rt2x00pci_register_write(rt2x00dev, AUTO_RSP_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, OFDM_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_CTRL,
+ erp->cts_protection ? 2 : 0);
+ rt2x00pci_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
+
+ rt2x00pci_register_write(rt2x00dev, LEGACY_BASIC_RATE,
+ erp->basic_rates);
+ rt2x00pci_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003);
+
+ rt2x00pci_register_read(rt2x00dev, BKOFF_SLOT_CFG, &reg);
+ rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time);
+ rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2);
+ rt2x00pci_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, XIFS_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, XIFS_TIME_CFG_CCKM_SIFS_TIME, erp->sifs);
+ rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_SIFS_TIME, erp->sifs);
+ rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4);
+ rt2x00_set_field32(&reg, XIFS_TIME_CFG_EIFS, erp->eifs);
+ rt2x00_set_field32(&reg, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1);
+ rt2x00pci_register_write(rt2x00dev, XIFS_TIME_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL,
+ erp->beacon_int * 16);
+ rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+}
+
+static void rt2800pci_config_ant(struct rt2x00_dev *rt2x00dev,
+ struct antenna_setup *ant)
+{
+ u8 r1;
+ u8 r3;
+
+ rt2800pci_bbp_read(rt2x00dev, 1, &r1);
+ rt2800pci_bbp_read(rt2x00dev, 3, &r3);
+
+ /*
+ * Configure the TX antenna.
+ */
+ switch ((int)ant->tx) {
+ case 1:
+ rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0);
+ rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0);
+ break;
+ case 2:
+ rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2);
+ break;
+ case 3:
+ /* Do nothing */
+ break;
+ }
+
+ /*
+ * Configure the RX antenna.
+ */
+ switch ((int)ant->rx) {
+ case 1:
+ rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0);
+ break;
+ case 2:
+ rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 1);
+ break;
+ case 3:
+ rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 2);
+ break;
+ }
+
+ rt2800pci_bbp_write(rt2x00dev, 3, r3);
+ rt2800pci_bbp_write(rt2x00dev, 1, r1);
+}
+
+static void rt2800pci_config_lna_gain(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
+ u16 eeprom;
+ short lna_gain;
+
+ if (libconf->rf.channel <= 14) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom);
+ lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_BG);
+ } else if (libconf->rf.channel <= 64) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom);
+ lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_A0);
+ } else if (libconf->rf.channel <= 128) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom);
+ lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_LNA_A1);
+ } else {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom);
+ lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_LNA_A2);
+ }
+
+ rt2x00dev->lna_gain = lna_gain;
+}
+
+static void rt2800pci_config_channel_rt2x(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf,
+ struct rf_channel *rf,
+ struct channel_info *info)
+{
+ rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
+
+ if (rt2x00dev->default_ant.tx == 1)
+ rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_TX1, 1);
+
+ if (rt2x00dev->default_ant.rx == 1) {
+ rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX1, 1);
+ rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1);
+ } else if (rt2x00dev->default_ant.rx == 2)
+ rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1);
+
+ if (rf->channel > 14) {
+ /*
+ * When TX power is below 0, we should increase it by 7 to
+ * make it a positive value (Minumum value is -7).
+ * However this means that values between 0 and 7 have
+ * double meaning, and we should set a 7DBm boost flag.
+ */
+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A_7DBM_BOOST,
+ (info->tx_power1 >= 0));
+
+ if (info->tx_power1 < 0)
+ info->tx_power1 += 7;
+
+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A,
+ TXPOWER_A_TO_DEV(info->tx_power1));
+
+ rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A_7DBM_BOOST,
+ (info->tx_power2 >= 0));
+
+ if (info->tx_power2 < 0)
+ info->tx_power2 += 7;
+
+ rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A,
+ TXPOWER_A_TO_DEV(info->tx_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->rf4, RF4_HT40, conf_is_ht40(conf));
+
+ rt2800pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2800pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt2800pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+ rt2800pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+ udelay(200);
+
+ rt2800pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2800pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt2800pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
+ rt2800pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+ udelay(200);
+
+ rt2800pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2800pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt2800pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+ rt2800pci_rf_write(rt2x00dev, 4, rf->rf4);
+}
+
+static void rt2800pci_config_channel_rt3x(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf,
+ struct rf_channel *rf,
+ struct channel_info *info)
+{
+ u8 rfcsr;
+
+ rt2800pci_rfcsr_write(rt2x00dev, 2, rf->rf1);
+ rt2800pci_rfcsr_write(rt2x00dev, 2, rf->rf3);
+
+ rt2800pci_rfcsr_read(rt2x00dev, 6, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR6_R, rf->rf2);
+ rt2800pci_rfcsr_write(rt2x00dev, 6, rfcsr);
+
+ rt2800pci_rfcsr_read(rt2x00dev, 12, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER,
+ TXPOWER_G_TO_DEV(info->tx_power1));
+ rt2800pci_rfcsr_write(rt2x00dev, 12, rfcsr);
+
+ rt2800pci_rfcsr_read(rt2x00dev, 23, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset);
+ rt2800pci_rfcsr_write(rt2x00dev, 23, rfcsr);
+
+ rt2800pci_rfcsr_write(rt2x00dev, 24,
+ rt2x00dev->calibration[conf_is_ht40(conf)]);
+
+ rt2800pci_rfcsr_read(rt2x00dev, 23, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1);
+ rt2800pci_rfcsr_write(rt2x00dev, 23, rfcsr);
+}
+
+static void rt2800pci_config_channel(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf,
+ struct rf_channel *rf,
+ struct channel_info *info)
+{
+ u32 reg;
+ unsigned int tx_pin;
+ u8 bbp;
+
+ if (rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION)
+ rt2800pci_config_channel_rt2x(rt2x00dev, conf, rf, info);
+ else
+ rt2800pci_config_channel_rt3x(rt2x00dev, conf, rf, info);
+
+ /*
+ * Change BBP settings
+ */
+ rt2800pci_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
+ rt2800pci_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
+ rt2800pci_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain);
+ rt2800pci_bbp_write(rt2x00dev, 86, 0);
+
+ if (rf->channel <= 14) {
+ if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) {
+ rt2800pci_bbp_write(rt2x00dev, 82, 0x62);
+ rt2800pci_bbp_write(rt2x00dev, 75, 0x46);
+ } else {
+ rt2800pci_bbp_write(rt2x00dev, 82, 0x84);
+ rt2800pci_bbp_write(rt2x00dev, 75, 0x50);
+ }
+ } else {
+ rt2800pci_bbp_write(rt2x00dev, 82, 0xf2);
+
+ if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
+ rt2800pci_bbp_write(rt2x00dev, 75, 0x46);
+ else
+ rt2800pci_bbp_write(rt2x00dev, 75, 0x50);
+ }
+
+ rt2x00pci_register_read(rt2x00dev, TX_BAND_CFG, &reg);
+ rt2x00_set_field32(&reg, TX_BAND_CFG_HT40_PLUS, conf_is_ht40_plus(conf));
+ rt2x00_set_field32(&reg, TX_BAND_CFG_A, rf->channel > 14);
+ rt2x00_set_field32(&reg, TX_BAND_CFG_BG, rf->channel <= 14);
+ rt2x00pci_register_write(rt2x00dev, TX_BAND_CFG, reg);
+
+ tx_pin = 0;
+
+ /* Turn on unused PA or LNA when not using 1T or 1R */
+ if (rt2x00dev->default_ant.tx != 1) {
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, 1);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 1);
+ }
+
+ /* Turn on unused PA or LNA when not using 1T or 1R */
+ if (rt2x00dev->default_ant.rx != 1) {
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 1);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 1);
+ }
+
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN, 1);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFTR_EN, 1);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_TRSW_EN, 1);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, rf->channel <= 14);
+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, rf->channel > 14);
+
+ rt2x00pci_register_write(rt2x00dev, TX_PIN_CFG, tx_pin);
+
+ rt2800pci_bbp_read(rt2x00dev, 4, &bbp);
+ rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf));
+ rt2800pci_bbp_write(rt2x00dev, 4, bbp);
+
+ rt2800pci_bbp_read(rt2x00dev, 3, &bbp);
+ rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf));
+ rt2800pci_bbp_write(rt2x00dev, 3, bbp);
+
+ if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) {
+ if (conf_is_ht40(conf)) {
+ rt2800pci_bbp_write(rt2x00dev, 69, 0x1a);
+ rt2800pci_bbp_write(rt2x00dev, 70, 0x0a);
+ rt2800pci_bbp_write(rt2x00dev, 73, 0x16);
+ } else {
+ rt2800pci_bbp_write(rt2x00dev, 69, 0x16);
+ rt2800pci_bbp_write(rt2x00dev, 70, 0x08);
+ rt2800pci_bbp_write(rt2x00dev, 73, 0x11);
+ }
+ }
+
+ msleep(1);
+}
+
+static void rt2800pci_config_txpower(struct rt2x00_dev *rt2x00dev,
+ const int txpower)
+{
+ u32 reg;
+ u32 value = TXPOWER_G_TO_DEV(txpower);
+ u8 r1;
+
+ rt2800pci_bbp_read(rt2x00dev, 1, &r1);
+ rt2x00_set_field8(&reg, BBP1_TX_POWER, 0);
+ rt2800pci_bbp_write(rt2x00dev, 1, r1);
+
+ rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_0, &reg);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_0_1MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_0_2MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_0_55MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_0_11MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_0_6MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_0_9MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_0_12MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_0_18MBS, value);
+ rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_1, &reg);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_1_24MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_1_36MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_1_48MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_1_54MBS, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS0, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS1, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS2, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_1_MCS3, value);
+ rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_2, &reg);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS4, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS5, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS6, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS7, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS8, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS9, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS10, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_2_MCS11, value);
+ rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_2, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_3, &reg);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS12, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS13, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS14, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_3_MCS15, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN1, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN2, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN3, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_3_UKNOWN4, value);
+ rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_3, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_4, &reg);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN5, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN6, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN7, value);
+ rt2x00_set_field32(&reg, TX_PWR_CFG_4_UKNOWN8, value);
+ rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_4, reg);
+}
+
+static void rt2800pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, TX_RTY_CFG, &reg);
+ rt2x00_set_field32(&reg, TX_RTY_CFG_SHORT_RTY_LIMIT,
+ libconf->conf->short_frame_max_tx_count);
+ rt2x00_set_field32(&reg, TX_RTY_CFG_LONG_RTY_LIMIT,
+ libconf->conf->long_frame_max_tx_count);
+ rt2x00_set_field32(&reg, TX_RTY_CFG_LONG_RTY_THRE, 2000);
+ rt2x00_set_field32(&reg, TX_RTY_CFG_NON_AGG_RTY_MODE, 0);
+ rt2x00_set_field32(&reg, TX_RTY_CFG_AGG_RTY_MODE, 0);
+ rt2x00_set_field32(&reg, TX_RTY_CFG_TX_AUTO_FB_ENABLE, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_RTY_CFG, reg);
+}
+
+static void rt2800pci_config_ps(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
+ enum dev_state state =
+ (libconf->conf->flags & IEEE80211_CONF_PS) ?
+ STATE_SLEEP : STATE_AWAKE;
+ u32 reg;
+
+ if (state == STATE_SLEEP) {
+ rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0);
+
+ rt2x00pci_register_read(rt2x00dev, AUTOWAKEUP_CFG, &reg);
+ rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 5);
+ rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE,
+ libconf->conf->listen_interval - 1);
+ rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTOWAKE, 1);
+ rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg);
+
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
+ } else {
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
+
+ rt2x00pci_register_read(rt2x00dev, AUTOWAKEUP_CFG, &reg);
+ rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0);
+ rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, 0);
+ rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTOWAKE, 0);
+ rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg);
+ }
+}
+
+static void rt2800pci_config(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf,
+ const unsigned int flags)
+{
+ /* Always recalculate LNA gain before changing configuration */
+ rt2800pci_config_lna_gain(rt2x00dev, libconf);
+
+ if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
+ rt2800pci_config_channel(rt2x00dev, libconf->conf,
+ &libconf->rf, &libconf->channel);
+ if (flags & IEEE80211_CONF_CHANGE_POWER)
+ rt2800pci_config_txpower(rt2x00dev, libconf->conf->power_level);
+ if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+ rt2800pci_config_retry_limit(rt2x00dev, libconf);
+ if (flags & IEEE80211_CONF_CHANGE_PS)
+ rt2800pci_config_ps(rt2x00dev, libconf);
+}
+
+/*
+ * Link tuning
+ */
+static void rt2800pci_link_stats(struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual)
+{
+ u32 reg;
+
+ /*
+ * Update FCS error count from register.
+ */
+ rt2x00pci_register_read(rt2x00dev, RX_STA_CNT0, &reg);
+ qual->rx_failed = rt2x00_get_field32(reg, RX_STA_CNT0_CRC_ERR);
+}
+
+static u8 rt2800pci_get_default_vgc(struct rt2x00_dev *rt2x00dev)
+{
+ if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ)
+ return 0x2e + rt2x00dev->lna_gain;
+
+ if (!test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags))
+ return 0x32 + (rt2x00dev->lna_gain * 5) / 3;
+ else
+ return 0x3a + (rt2x00dev->lna_gain * 5) / 3;
+}
+
+static inline void rt2800pci_set_vgc(struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual, u8 vgc_level)
+{
+ if (qual->vgc_level != vgc_level) {
+ rt2800pci_bbp_write(rt2x00dev, 66, vgc_level);
+ qual->vgc_level = vgc_level;
+ qual->vgc_level_reg = vgc_level;
+ }
+}
+
+static void rt2800pci_reset_tuner(struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual)
+{
+ rt2800pci_set_vgc(rt2x00dev, qual,
+ rt2800pci_get_default_vgc(rt2x00dev));
+}
+
+static void rt2800pci_link_tuner(struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual, const u32 count)
+{
+ if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION)
+ return;
+
+ /*
+ * When RSSI is better then -80 increase VGC level with 0x10
+ */
+ rt2800pci_set_vgc(rt2x00dev, qual,
+ rt2800pci_get_default_vgc(rt2x00dev) +
+ ((qual->rssi > -80) * 0x10));
+}
+
+/*
+ * Firmware functions
+ */
+static char *rt2800pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
+{
+ return FIRMWARE_RT2860;
+}
+
+static int rt2800pci_check_firmware(struct rt2x00_dev *rt2x00dev,
+ const u8 *data, const size_t len)
+{
+ u16 fw_crc;
+ u16 crc;
+
+ /*
+ * Only support 8kb firmware files.
+ */
+ if (len != 8192)
+ return FW_BAD_LENGTH;
+
+ /*
+ * The last 2 bytes in the firmware array are the crc checksum itself,
+ * this means that we should never pass those 2 bytes to the crc
+ * algorithm.
+ */
+ fw_crc = (data[len - 2] << 8 | data[len - 1]);
+
+ /*
+ * Use the crc ccitt algorithm.
+ * This will return the same value as the legacy driver which
+ * used bit ordering reversion on the both the firmware bytes
+ * before input input as well as on the final output.
+ * Obviously using crc ccitt directly is much more efficient.
+ */
+ crc = crc_ccitt(~0, data, len - 2);
+
+ /*
+ * There is a small difference between the crc-itu-t + bitrev and
+ * the crc-ccitt crc calculation. In the latter method the 2 bytes
+ * will be swapped, use swab16 to convert the crc to the correct
+ * value.
+ */
+ crc = swab16(crc);
+
+ return (fw_crc == crc) ? FW_OK : FW_BAD_CRC;
+}
+
+static int rt2800pci_load_firmware(struct rt2x00_dev *rt2x00dev,
+ const u8 *data, const size_t len)
+{
+ unsigned int i;
+ u32 reg;
+
+ /*
+ * Wait for stable hardware.
+ */
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
+ if (reg && reg != ~0)
+ break;
+ msleep(1);
+ }
+
+ if (i == REGISTER_BUSY_COUNT) {
+ ERROR(rt2x00dev, "Unstable hardware.\n");
+ return -EBUSY;
+ }
+
+ rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002);
+ rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000);
+
+ /*
+ * Disable DMA, will be reenabled later when enabling
+ * the radio.
+ */
+ rt2x00pci_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);
+ rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+
+ /*
+ * enable Host program ram write selection
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, PBF_SYS_CTRL_HOST_RAM_WRITE, 1);
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, reg);
+
+ /*
+ * Write firmware to device.
+ */
+ rt2x00pci_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
+ data, len);
+
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000);
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001);
+
+ /*
+ * Wait for device to stabilize.
+ */
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
+ if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY))
+ break;
+ msleep(1);
+ }
+
+ if (i == REGISTER_BUSY_COUNT) {
+ ERROR(rt2x00dev, "PBF system register not ready.\n");
+ return -EBUSY;
+ }
+
+ /*
+ * Disable interrupts
+ */
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_IRQ_OFF);
+
+ /*
+ * Initialize BBP R/W access agent
+ */
+ rt2x00pci_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+
+ return 0;
+}
+
+/*
+ * Initialization functions.
+ */
+static bool rt2800pci_get_entry_state(struct queue_entry *entry)
+{
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ u32 word;
+
+ if (entry->queue->qid == QID_RX) {
+ rt2x00_desc_read(entry_priv->desc, 1, &word);
+
+ return (!rt2x00_get_field32(word, RXD_W1_DMA_DONE));
+ } else {
+ rt2x00_desc_read(entry_priv->desc, 1, &word);
+
+ return (!rt2x00_get_field32(word, TXD_W1_DMA_DONE));
+ }
+}
+
+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);
+ u32 word;
+
+ if (entry->queue->qid == QID_RX) {
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
+ rt2x00_set_field32(&word, RXD_W0_SDP0, skbdesc->skb_dma);
+ rt2x00_desc_write(entry_priv->desc, 0, word);
+
+ 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);
+ } else {
+ rt2x00_desc_read(entry_priv->desc, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 1);
+ rt2x00_desc_write(entry_priv->desc, 1, word);
+ }
+}
+
+static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev)
+{
+ struct queue_entry_priv_pci *entry_priv;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX4, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX5, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DRX_IDX0, 1);
+ rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
+
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
+
+ /*
+ * Initialize registers.
+ */
+ entry_priv = rt2x00dev->tx[0].entries[0].priv_data;
+ rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR0, entry_priv->desc_dma);
+ rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT0, rt2x00dev->tx[0].limit);
+ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX0, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX0, 0);
+
+ entry_priv = rt2x00dev->tx[1].entries[0].priv_data;
+ rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR1, entry_priv->desc_dma);
+ rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT1, rt2x00dev->tx[1].limit);
+ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX1, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX1, 0);
+
+ entry_priv = rt2x00dev->tx[2].entries[0].priv_data;
+ rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR2, entry_priv->desc_dma);
+ rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT2, rt2x00dev->tx[2].limit);
+ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX2, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX2, 0);
+
+ entry_priv = rt2x00dev->tx[3].entries[0].priv_data;
+ rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR3, entry_priv->desc_dma);
+ rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT3, rt2x00dev->tx[3].limit);
+ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX3, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX3, 0);
+
+ entry_priv = rt2x00dev->rx->entries[0].priv_data;
+ rt2x00pci_register_write(rt2x00dev, RX_BASE_PTR, entry_priv->desc_dma);
+ rt2x00pci_register_write(rt2x00dev, RX_MAX_CNT, rt2x00dev->rx[0].limit);
+ rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX, rt2x00dev->rx[0].limit - 1);
+ rt2x00pci_register_write(rt2x00dev, RX_DRX_IDX, 0);
+
+ /*
+ * Enable global DMA configuration
+ */
+ rt2x00pci_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);
+ rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
+ rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+
+ rt2x00pci_register_write(rt2x00dev, DELAY_INT_CFG, 0);
+
+ return 0;
+}
+
+static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ unsigned int i;
+
+ rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
+
+ rt2x00pci_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);
+ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
+
+ rt2x00pci_register_read(rt2x00dev, BCN_OFFSET0, &reg);
+ rt2x00_set_field32(&reg, BCN_OFFSET0_BCN0, 0xe0); /* 0x3800 */
+ rt2x00_set_field32(&reg, BCN_OFFSET0_BCN1, 0xe8); /* 0x3a00 */
+ rt2x00_set_field32(&reg, BCN_OFFSET0_BCN2, 0xf0); /* 0x3c00 */
+ rt2x00_set_field32(&reg, BCN_OFFSET0_BCN3, 0xf8); /* 0x3e00 */
+ rt2x00pci_register_write(rt2x00dev, BCN_OFFSET0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, BCN_OFFSET1, &reg);
+ rt2x00_set_field32(&reg, BCN_OFFSET1_BCN4, 0xc8); /* 0x3200 */
+ rt2x00_set_field32(&reg, BCN_OFFSET1_BCN5, 0xd0); /* 0x3400 */
+ rt2x00_set_field32(&reg, BCN_OFFSET1_BCN6, 0x77); /* 0x1dc0 */
+ rt2x00_set_field32(&reg, BCN_OFFSET1_BCN7, 0x6f); /* 0x1bc0 */
+ rt2x00pci_register_write(rt2x00dev, BCN_OFFSET1, reg);
+
+ rt2x00pci_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f);
+ rt2x00pci_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003);
+
+ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
+
+ rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_SYNC, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TX_TIME_COMPENSATE, 0);
+ rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+
+ rt2x00pci_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000);
+ rt2x00pci_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
+
+ rt2x00pci_register_read(rt2x00dev, TX_LINK_CFG, &reg);
+ rt2x00_set_field32(&reg, TX_LINK_CFG_REMOTE_MFB_LIFETIME, 32);
+ rt2x00_set_field32(&reg, TX_LINK_CFG_MFB_ENABLE, 0);
+ rt2x00_set_field32(&reg, TX_LINK_CFG_REMOTE_UMFS_ENABLE, 0);
+ rt2x00_set_field32(&reg, TX_LINK_CFG_TX_MRQ_EN, 0);
+ rt2x00_set_field32(&reg, TX_LINK_CFG_TX_RDG_EN, 0);
+ rt2x00_set_field32(&reg, TX_LINK_CFG_TX_CF_ACK_EN, 1);
+ rt2x00_set_field32(&reg, TX_LINK_CFG_REMOTE_MFB, 0);
+ rt2x00_set_field32(&reg, TX_LINK_CFG_REMOTE_MFS, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_LINK_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TX_TIMEOUT_CFG, &reg);
+ rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_MPDU_LIFETIME, 9);
+ rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_TX_OP_TIMEOUT, 10);
+ rt2x00pci_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MAX_LEN_CFG, &reg);
+ rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE);
+ if (rt2x00_rev(&rt2x00dev->chip) >= RT2880E_VERSION &&
+ rt2x00_rev(&rt2x00dev->chip) < RT3070_VERSION)
+ rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 2);
+ else
+ rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 1);
+ rt2x00_set_field32(&reg, MAX_LEN_CFG_MIN_PSDU, 0);
+ rt2x00_set_field32(&reg, MAX_LEN_CFG_MIN_MPDU, 0);
+ rt2x00pci_register_write(rt2x00dev, MAX_LEN_CFG, reg);
+
+ rt2x00pci_register_write(rt2x00dev, PBF_MAX_PCNT, 0x1f3fbf9f);
+
+ rt2x00pci_register_read(rt2x00dev, AUTO_RSP_CFG, &reg);
+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_AUTORESPONDER, 1);
+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_CTS_40_MMODE, 0);
+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_CTS_40_MREF, 0);
+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_DUAL_CTS_EN, 0);
+ rt2x00_set_field32(&reg, AUTO_RSP_CFG_ACK_CTS_PSM_BIT, 0);
+ rt2x00pci_register_write(rt2x00dev, AUTO_RSP_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CCK_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_RATE, 8);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_CTRL, 0);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_NAV, 1);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_CCK, 1);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_MM20, 1);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 1);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 1);
+ rt2x00pci_register_write(rt2x00dev, CCK_PROT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, OFDM_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_RATE, 8);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_CTRL, 0);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_NAV, 1);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_CCK, 1);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_MM20, 1);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 1);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 1);
+ rt2x00pci_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MM20_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_PROTECT_RATE, 0x4004);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_PROTECT_CTRL, 0);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_PROTECT_NAV, 1);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_CCK, 1);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_MM20, 1);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_MM40, 0);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_GF20, 1);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_GF40, 0);
+ rt2x00pci_register_write(rt2x00dev, MM20_PROT_CFG, reg);
+
+ rt2x00pci_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, 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);
+ rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_MM20, 1);
+ rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_MM40, 1);
+ rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_GF20, 1);
+ rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_GF40, 1);
+ rt2x00pci_register_write(rt2x00dev, MM40_PROT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, GF20_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_PROTECT_RATE, 0x4004);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_PROTECT_CTRL, 0);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_PROTECT_NAV, 1);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_CCK, 1);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_MM20, 1);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_MM40, 0);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_GF20, 1);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_GF40, 0);
+ rt2x00pci_register_write(rt2x00dev, GF20_PROT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, GF40_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_PROTECT_RATE, 0x4084);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_PROTECT_CTRL, 0);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_PROTECT_NAV, 1);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_CCK, 1);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_MM20, 1);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_MM40, 1);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_GF20, 1);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_GF40, 1);
+ rt2x00pci_register_write(rt2x00dev, GF40_PROT_CFG, reg);
+
+ rt2x00pci_register_write(rt2x00dev, TXOP_CTRL_CFG, 0x0000583f);
+ rt2x00pci_register_write(rt2x00dev, TXOP_HLDR_ET, 0x00000002);
+
+ rt2x00pci_register_read(rt2x00dev, TX_RTS_CFG, &reg);
+ rt2x00_set_field32(&reg, TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT, 32);
+ rt2x00_set_field32(&reg, TX_RTS_CFG_RTS_THRES,
+ IEEE80211_MAX_RTS_THRESHOLD);
+ rt2x00_set_field32(&reg, TX_RTS_CFG_RTS_FBK_EN, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_RTS_CFG, reg);
+
+ rt2x00pci_register_write(rt2x00dev, EXP_ACK_TIME, 0x002400ca);
+ rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
+
+ /*
+ * ASIC will keep garbage value after boot, clear encryption keys.
+ */
+ for (i = 0; i < 4; i++)
+ rt2x00pci_register_write(rt2x00dev,
+ SHARED_KEY_MODE_ENTRY(i), 0);
+
+ for (i = 0; i < 256; i++) {
+ u32 wcid[2] = { 0xffffffff, 0x00ffffff };
+ rt2x00pci_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i),
+ wcid, sizeof(wcid));
+
+ rt2x00pci_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 1);
+ rt2x00pci_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0);
+ }
+
+ /*
+ * Clear all beacons
+ * For the Beacon base registers we only need to clear
+ * the first byte since that byte contains the VALID and OWNER
+ * bits which (when set to 0) will invalidate the entire beacon.
+ */
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE4, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE5, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE6, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE7, 0);
+
+ rt2x00pci_register_read(rt2x00dev, HT_FBK_CFG0, &reg);
+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS0FBK, 0);
+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS1FBK, 0);
+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS2FBK, 1);
+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS3FBK, 2);
+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS4FBK, 3);
+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS5FBK, 4);
+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS6FBK, 5);
+ rt2x00_set_field32(&reg, HT_FBK_CFG0_HTMCS7FBK, 6);
+ rt2x00pci_register_write(rt2x00dev, HT_FBK_CFG0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, HT_FBK_CFG1, &reg);
+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS8FBK, 8);
+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS9FBK, 8);
+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS10FBK, 9);
+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS11FBK, 10);
+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS12FBK, 11);
+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS13FBK, 12);
+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS14FBK, 13);
+ rt2x00_set_field32(&reg, HT_FBK_CFG1_HTMCS15FBK, 14);
+ rt2x00pci_register_write(rt2x00dev, HT_FBK_CFG1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, LG_FBK_CFG0, &reg);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS0FBK, 8);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS1FBK, 8);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS2FBK, 9);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS3FBK, 10);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS4FBK, 11);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS5FBK, 12);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS6FBK, 13);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_OFDMMCS7FBK, 14);
+ rt2x00pci_register_write(rt2x00dev, LG_FBK_CFG0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, LG_FBK_CFG1, &reg);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_CCKMCS0FBK, 0);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_CCKMCS1FBK, 0);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_CCKMCS2FBK, 1);
+ rt2x00_set_field32(&reg, LG_FBK_CFG0_CCKMCS3FBK, 2);
+ rt2x00pci_register_write(rt2x00dev, LG_FBK_CFG1, reg);
+
+ /*
+ * We must clear the error counters.
+ * These registers are cleared on read,
+ * so we may pass a useless variable to store the value.
+ */
+ rt2x00pci_register_read(rt2x00dev, RX_STA_CNT0, &reg);
+ rt2x00pci_register_read(rt2x00dev, RX_STA_CNT1, &reg);
+ rt2x00pci_register_read(rt2x00dev, RX_STA_CNT2, &reg);
+ rt2x00pci_register_read(rt2x00dev, TX_STA_CNT0, &reg);
+ rt2x00pci_register_read(rt2x00dev, TX_STA_CNT1, &reg);
+ rt2x00pci_register_read(rt2x00dev, TX_STA_CNT2, &reg);
+
+ return 0;
+}
+
+static int rt2800pci_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u32 reg;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, MAC_STATUS_CFG, &reg);
+ if (!rt2x00_get_field32(reg, MAC_STATUS_CFG_BBP_RF_BUSY))
+ return 0;
+
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "BBP/RF register access failed, aborting.\n");
+ return -EACCES;
+}
+
+static int rt2800pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u8 value;
+
+ /*
+ * BBP was enabled after firmware was loaded,
+ * but we need to reactivate it now.
+ */
+ rt2x00pci_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+ msleep(1);
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2800pci_bbp_read(rt2x00dev, 0, &value);
+ if ((value != 0xff) && (value != 0x00))
+ return 0;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+ return -EACCES;
+}
+
+static int rt2800pci_init_bbp(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u16 eeprom;
+ u8 reg_id;
+ u8 value;
+
+ if (unlikely(rt2800pci_wait_bbp_rf_ready(rt2x00dev) ||
+ rt2800pci_wait_bbp_ready(rt2x00dev)))
+ return -EACCES;
+
+ rt2800pci_bbp_write(rt2x00dev, 65, 0x2c);
+ rt2800pci_bbp_write(rt2x00dev, 66, 0x38);
+ rt2800pci_bbp_write(rt2x00dev, 69, 0x12);
+ rt2800pci_bbp_write(rt2x00dev, 70, 0x0a);
+ rt2800pci_bbp_write(rt2x00dev, 73, 0x10);
+ rt2800pci_bbp_write(rt2x00dev, 81, 0x37);
+ rt2800pci_bbp_write(rt2x00dev, 82, 0x62);
+ rt2800pci_bbp_write(rt2x00dev, 83, 0x6a);
+ rt2800pci_bbp_write(rt2x00dev, 84, 0x99);
+ rt2800pci_bbp_write(rt2x00dev, 86, 0x00);
+ rt2800pci_bbp_write(rt2x00dev, 91, 0x04);
+ rt2800pci_bbp_write(rt2x00dev, 92, 0x00);
+ rt2800pci_bbp_write(rt2x00dev, 103, 0x00);
+ rt2800pci_bbp_write(rt2x00dev, 105, 0x05);
+
+ if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) {
+ rt2800pci_bbp_write(rt2x00dev, 69, 0x16);
+ rt2800pci_bbp_write(rt2x00dev, 73, 0x12);
+ }
+
+ if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION)
+ rt2800pci_bbp_write(rt2x00dev, 84, 0x19);
+
+ if (rt2x00_rt(&rt2x00dev->chip, RT3052)) {
+ rt2800pci_bbp_write(rt2x00dev, 31, 0x08);
+ rt2800pci_bbp_write(rt2x00dev, 78, 0x0e);
+ rt2800pci_bbp_write(rt2x00dev, 80, 0x08);
+ }
+
+ for (i = 0; i < EEPROM_BBP_SIZE; i++) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
+
+ if (eeprom != 0xffff && eeprom != 0x0000) {
+ reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
+ rt2800pci_bbp_write(rt2x00dev, reg_id, value);
+ }
+ }
+
+ return 0;
+}
+
+static u8 rt2800pci_init_rx_filter(struct rt2x00_dev *rt2x00dev,
+ bool bw40, u8 rfcsr24, u8 filter_target)
+{
+ unsigned int i;
+ u8 bbp;
+ u8 rfcsr;
+ u8 passband;
+ u8 stopband;
+ u8 overtuned = 0;
+
+ rt2800pci_rfcsr_write(rt2x00dev, 24, rfcsr24);
+
+ rt2800pci_bbp_read(rt2x00dev, 4, &bbp);
+ rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40);
+ rt2800pci_bbp_write(rt2x00dev, 4, bbp);
+
+ rt2800pci_rfcsr_read(rt2x00dev, 22, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 1);
+ rt2800pci_rfcsr_write(rt2x00dev, 22, rfcsr);
+
+ /*
+ * Set power & frequency of passband test tone
+ */
+ rt2800pci_bbp_write(rt2x00dev, 24, 0);
+
+ for (i = 0; i < 100; i++) {
+ rt2800pci_bbp_write(rt2x00dev, 25, 0x90);
+ msleep(1);
+
+ rt2800pci_bbp_read(rt2x00dev, 55, &passband);
+ if (passband)
+ break;
+ }
+
+ /*
+ * Set power & frequency of stopband test tone
+ */
+ rt2800pci_bbp_write(rt2x00dev, 24, 0x06);
+
+ for (i = 0; i < 100; i++) {
+ rt2800pci_bbp_write(rt2x00dev, 25, 0x90);
+ msleep(1);
+
+ rt2800pci_bbp_read(rt2x00dev, 55, &stopband);
+
+ if ((passband - stopband) <= filter_target) {
+ rfcsr24++;
+ overtuned += ((passband - stopband) == filter_target);
+ } else
+ break;
+
+ rt2800pci_rfcsr_write(rt2x00dev, 24, rfcsr24);
+ }
+
+ rfcsr24 -= !!overtuned;
+
+ rt2800pci_rfcsr_write(rt2x00dev, 24, rfcsr24);
+ return rfcsr24;
+}
+
+static int rt2800pci_init_rfcsr(struct rt2x00_dev *rt2x00dev)
+{
+ u8 rfcsr;
+ u8 bbp;
+
+ if (!rt2x00_rf(&rt2x00dev->chip, RF3020) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF3021) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF3022))
+ return 0;
+
+ /*
+ * Init RF calibration.
+ */
+ rt2800pci_rfcsr_read(rt2x00dev, 30, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1);
+ rt2800pci_rfcsr_write(rt2x00dev, 30, rfcsr);
+ msleep(1);
+ rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0);
+ rt2800pci_rfcsr_write(rt2x00dev, 30, rfcsr);
+
+ rt2800pci_rfcsr_write(rt2x00dev, 0, 0x50);
+ rt2800pci_rfcsr_write(rt2x00dev, 1, 0x01);
+ rt2800pci_rfcsr_write(rt2x00dev, 2, 0xf7);
+ rt2800pci_rfcsr_write(rt2x00dev, 3, 0x75);
+ rt2800pci_rfcsr_write(rt2x00dev, 4, 0x40);
+ rt2800pci_rfcsr_write(rt2x00dev, 5, 0x03);
+ rt2800pci_rfcsr_write(rt2x00dev, 6, 0x02);
+ rt2800pci_rfcsr_write(rt2x00dev, 7, 0x50);
+ rt2800pci_rfcsr_write(rt2x00dev, 8, 0x39);
+ rt2800pci_rfcsr_write(rt2x00dev, 9, 0x0f);
+ rt2800pci_rfcsr_write(rt2x00dev, 10, 0x60);
+ rt2800pci_rfcsr_write(rt2x00dev, 11, 0x21);
+ rt2800pci_rfcsr_write(rt2x00dev, 12, 0x75);
+ rt2800pci_rfcsr_write(rt2x00dev, 13, 0x75);
+ rt2800pci_rfcsr_write(rt2x00dev, 14, 0x90);
+ rt2800pci_rfcsr_write(rt2x00dev, 15, 0x58);
+ rt2800pci_rfcsr_write(rt2x00dev, 16, 0xb3);
+ rt2800pci_rfcsr_write(rt2x00dev, 17, 0x92);
+ rt2800pci_rfcsr_write(rt2x00dev, 18, 0x2c);
+ rt2800pci_rfcsr_write(rt2x00dev, 19, 0x02);
+ rt2800pci_rfcsr_write(rt2x00dev, 20, 0xba);
+ rt2800pci_rfcsr_write(rt2x00dev, 21, 0xdb);
+ rt2800pci_rfcsr_write(rt2x00dev, 22, 0x00);
+ rt2800pci_rfcsr_write(rt2x00dev, 23, 0x31);
+ rt2800pci_rfcsr_write(rt2x00dev, 24, 0x08);
+ rt2800pci_rfcsr_write(rt2x00dev, 25, 0x01);
+ rt2800pci_rfcsr_write(rt2x00dev, 26, 0x25);
+ rt2800pci_rfcsr_write(rt2x00dev, 27, 0x23);
+ rt2800pci_rfcsr_write(rt2x00dev, 28, 0x13);
+ rt2800pci_rfcsr_write(rt2x00dev, 29, 0x83);
+
+ /*
+ * Set RX Filter calibration for 20MHz and 40MHz
+ */
+ rt2x00dev->calibration[0] =
+ rt2800pci_init_rx_filter(rt2x00dev, false, 0x07, 0x16);
+ rt2x00dev->calibration[1] =
+ rt2800pci_init_rx_filter(rt2x00dev, true, 0x27, 0x19);
+
+ /*
+ * Set back to initial state
+ */
+ rt2800pci_bbp_write(rt2x00dev, 24, 0);
+
+ rt2800pci_rfcsr_read(rt2x00dev, 22, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 0);
+ rt2800pci_rfcsr_write(rt2x00dev, 22, rfcsr);
+
+ /*
+ * set BBP back to BW20
+ */
+ rt2800pci_bbp_read(rt2x00dev, 4, &bbp);
+ rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 0);
+ rt2800pci_bbp_write(rt2x00dev, 4, bbp);
+
+ return 0;
+}
+
+/*
+ * Device state switch handlers.
+ */
+static void rt2800pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX,
+ (state == STATE_RADIO_RX_ON) ||
+ (state == STATE_RADIO_RX_ON_LINK));
+ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+}
+
+static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int mask = (state == STATE_RADIO_IRQ_ON);
+ u32 reg;
+
+ /*
+ * When interrupts are being enabled, the interrupt registers
+ * should clear the register to assure a clean state.
+ */
+ if (state == STATE_RADIO_IRQ_ON) {
+ rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+ rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+ }
+
+ rt2x00pci_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_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_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);
+ rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
+}
+
+static int rt2800pci_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u32 reg;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+ if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) &&
+ !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY))
+ return 0;
+
+ msleep(1);
+ }
+
+ ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n");
+ return -EACCES;
+}
+
+static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ u16 word;
+
+ /*
+ * Initialize all registers.
+ */
+ if (unlikely(rt2800pci_wait_wpdma_ready(rt2x00dev) ||
+ rt2800pci_init_queues(rt2x00dev) ||
+ rt2800pci_init_registers(rt2x00dev) ||
+ rt2800pci_wait_wpdma_ready(rt2x00dev) ||
+ rt2800pci_init_bbp(rt2x00dev) ||
+ rt2800pci_init_rfcsr(rt2x00dev)))
+ return -EIO;
+
+ /*
+ * Send signal to firmware during boot time.
+ */
+ rt2800pci_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0);
+
+ /*
+ * Enable RX.
+ */
+ rt2x00pci_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);
+ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+ rt2x00pci_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);
+ rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+
+ rt2x00pci_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);
+ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+ /*
+ * Initialize LED control
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word);
+ rt2800pci_mcu_request(rt2x00dev, MCU_LED_1, 0xff,
+ word & 0xff, (word >> 8) & 0xff);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word);
+ rt2800pci_mcu_request(rt2x00dev, MCU_LED_2, 0xff,
+ word & 0xff, (word >> 8) & 0xff);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word);
+ rt2800pci_mcu_request(rt2x00dev, MCU_LED_3, 0xff,
+ word & 0xff, (word >> 8) & 0xff);
+
+ return 0;
+}
+
+static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_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);
+ rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+
+ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, 0);
+ rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_PIN_CFG, 0);
+
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001280);
+
+ rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX4, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX5, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DRX_IDX0, 1);
+ rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
+
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
+
+ /* Wait for DMA, ignore error */
+ rt2800pci_wait_wpdma_ready(rt2x00dev);
+}
+
+static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ /*
+ * Always put the device to sleep (even when we intend to wakeup!)
+ * if the device is booting and wasn't asleep it will return
+ * failure when attempting to wakeup.
+ */
+ rt2800pci_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 2);
+
+ if (state == STATE_AWAKE) {
+ rt2800pci_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0);
+ rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKUP);
+ }
+
+ return 0;
+}
+
+static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int retval = 0;
+
+ switch (state) {
+ case STATE_RADIO_ON:
+ /*
+ * Before the radio can be enabled, the device first has
+ * to be woken up. After that it needs a bit of time
+ * to be fully awake and then the radio can be enabled.
+ */
+ rt2800pci_set_state(rt2x00dev, STATE_AWAKE);
+ msleep(1);
+ retval = rt2800pci_enable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_OFF:
+ /*
+ * After the radio has been disabled, the device should
+ * be put to sleep for powersaving.
+ */
+ rt2800pci_disable_radio(rt2x00dev);
+ rt2800pci_set_state(rt2x00dev, STATE_SLEEP);
+ break;
+ case STATE_RADIO_RX_ON:
+ case STATE_RADIO_RX_ON_LINK:
+ case STATE_RADIO_RX_OFF:
+ case STATE_RADIO_RX_OFF_LINK:
+ rt2800pci_toggle_rx(rt2x00dev, state);
+ break;
+ case STATE_RADIO_IRQ_ON:
+ case STATE_RADIO_IRQ_OFF:
+ rt2800pci_toggle_irq(rt2x00dev, state);
+ break;
+ case STATE_DEEP_SLEEP:
+ case STATE_SLEEP:
+ case STATE_STANDBY:
+ case STATE_AWAKE:
+ retval = rt2800pci_set_state(rt2x00dev, state);
+ break;
+ default:
+ retval = -ENOTSUPP;
+ break;
+ }
+
+ if (unlikely(retval))
+ ERROR(rt2x00dev, "Device failed to enter state %d (%d).\n",
+ state, retval);
+
+ return retval;
+}
+
+/*
+ * TX descriptor initialization
+ */
+static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+ struct sk_buff *skb,
+ struct txentry_desc *txdesc)
+{
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+ __le32 *txd = skbdesc->desc;
+ __le32 *txwi = (__le32 *)(skb->data - rt2x00dev->hw->extra_tx_headroom);
+ u32 word;
+
+ /*
+ * Initialize TX Info descriptor
+ */
+ 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_CF_ACK, 0);
+ rt2x00_set_field32(&word, TXWI_W0_TS,
+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
+ rt2x00_set_field32(&word, TXWI_W0_AMPDU,
+ test_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags));
+ rt2x00_set_field32(&word, TXWI_W0_MPDU_DENSITY, txdesc->mpdu_density);
+ rt2x00_set_field32(&word, TXWI_W0_TX_OP, txdesc->ifs);
+ rt2x00_set_field32(&word, TXWI_W0_MCS, txdesc->mcs);
+ rt2x00_set_field32(&word, TXWI_W0_BW,
+ test_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags));
+ rt2x00_set_field32(&word, TXWI_W0_SHORT_GI,
+ test_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags));
+ rt2x00_set_field32(&word, TXWI_W0_STBC, txdesc->stbc);
+ rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode);
+ rt2x00_desc_write(txwi, 0, word);
+
+ rt2x00_desc_read(txwi, 1, &word);
+ rt2x00_set_field32(&word, TXWI_W1_ACK,
+ test_bit(ENTRY_TXD_ACK, &txdesc->flags));
+ rt2x00_set_field32(&word, TXWI_W1_NSEQ,
+ test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
+ rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size);
+ rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
+ test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
+ (skbdesc->entry->entry_idx + 1) : 0xff);
+ rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
+ skb->len - txdesc->l2pad);
+ rt2x00_set_field32(&word, TXWI_W1_PACKETID,
+ skbdesc->entry->queue->qid + 1);
+ rt2x00_desc_write(txwi, 1, word);
+
+ /*
+ * Always write 0 to IV/EIV fields, hardware will insert the IV
+ * from the IVEIV register when ENTRY_TXD_ENCRYPT_IV is set to 0.
+ * When ENTRY_TXD_ENCRYPT_IV is set to 1 it will use the IV data
+ * from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which
+ * crypto entry in the registers should be used to encrypt the frame.
+ */
+ _rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */);
+ _rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */);
+
+ /*
+ * The buffers pointed by SD_PTR0/SD_LEN0 and SD_PTR1/SD_LEN1
+ * must contains a TXWI structure + 802.11 header + padding + 802.11
+ * data. We choose to have SD_PTR0/SD_LEN0 only contains TXWI and
+ * SD_PTR1/SD_LEN1 contains 802.11 header + padding + 802.11
+ * data. It means that LAST_SEC0 is always 0.
+ */
+
+ /*
+ * Initialize TX descriptor
+ */
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_SD_PTR0, skbdesc->skb_dma);
+ 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_LAST_SEC1,
+ !test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W1_BURST,
+ test_bit(ENTRY_TXD_BURST, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W1_SD_LEN0,
+ rt2x00dev->hw->extra_tx_headroom);
+ rt2x00_set_field32(&word, TXD_W1_LAST_SEC0, 0);
+ rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 0);
+ rt2x00_desc_write(txd, 1, word);
+
+ rt2x00_desc_read(txd, 2, &word);
+ rt2x00_set_field32(&word, TXD_W2_SD_PTR1,
+ skbdesc->skb_dma + rt2x00dev->hw->extra_tx_headroom);
+ rt2x00_desc_write(txd, 2, word);
+
+ rt2x00_desc_read(txd, 3, &word);
+ rt2x00_set_field32(&word, TXD_W3_WIV,
+ !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W3_QSEL, 2);
+ rt2x00_desc_write(txd, 3, word);
+}
+
+/*
+ * TX data initialization
+ */
+static void rt2800pci_write_beacon(struct queue_entry *entry)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ unsigned int beacon_base;
+ u32 reg;
+
+ /*
+ * Disable beaconing while we are reloading the beacon data,
+ * otherwise we might be sending out invalid data.
+ */
+ rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+
+ /*
+ * Write entire beacon with descriptor to register.
+ */
+ beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
+ rt2x00pci_register_multiwrite(rt2x00dev,
+ beacon_base,
+ skbdesc->desc, skbdesc->desc_len);
+ rt2x00pci_register_multiwrite(rt2x00dev,
+ beacon_base + skbdesc->desc_len,
+ entry->skb->data, entry->skb->len);
+
+ /*
+ * Clean up beacon skb.
+ */
+ dev_kfree_skb_any(entry->skb);
+ entry->skb = NULL;
+}
+
+static void rt2800pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
+ const enum data_queue_qid queue_idx)
+{
+ struct data_queue *queue;
+ unsigned int idx, qidx = 0;
+ u32 reg;
+
+ if (queue_idx == QID_BEACON) {
+ rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ if (!rt2x00_get_field32(reg, BCN_TIME_CFG_BEACON_GEN)) {
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
+ rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ }
+ return;
+ }
+
+ 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)
+ qidx = 5;
+ else
+ qidx = queue_idx;
+
+ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(qidx), idx);
+}
+
+static void rt2800pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
+ const enum data_queue_qid qid)
+{
+ u32 reg;
+
+ if (qid == QID_BEACON) {
+ rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, 0);
+ return;
+ }
+
+ rt2x00pci_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));
+ rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
+}
+
+/*
+ * RX control handlers
+ */
+static void rt2800pci_fill_rxdone(struct queue_entry *entry,
+ struct rxdone_entry_desc *rxdesc)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ __le32 *rxd = entry_priv->desc;
+ __le32 *rxwi = (__le32 *)entry->skb->data;
+ u32 rxd3;
+ u32 rxwi0;
+ u32 rxwi1;
+ u32 rxwi2;
+ u32 rxwi3;
+
+ rt2x00_desc_read(rxd, 3, &rxd3);
+ rt2x00_desc_read(rxwi, 0, &rxwi0);
+ rt2x00_desc_read(rxwi, 1, &rxwi1);
+ rt2x00_desc_read(rxwi, 2, &rxwi2);
+ rt2x00_desc_read(rxwi, 3, &rxwi3);
+
+ if (rt2x00_get_field32(rxd3, RXD_W3_CRC_ERROR))
+ rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
+
+ if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
+ /*
+ * Unfortunately we don't know the cipher type used during
+ * decryption. This prevents us from correct providing
+ * correct statistics through debugfs.
+ */
+ rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF);
+ rxdesc->cipher_status =
+ rt2x00_get_field32(rxd3, RXD_W3_CIPHER_ERROR);
+ }
+
+ if (rt2x00_get_field32(rxd3, RXD_W3_DECRYPTED)) {
+ /*
+ * Hardware has stripped IV/EIV data from 802.11 frame during
+ * decryption. Unfortunately the descriptor doesn't contain
+ * any fields with the EIV/IV data either, so they can't
+ * be restored by rt2x00lib.
+ */
+ rxdesc->flags |= RX_FLAG_IV_STRIPPED;
+
+ if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS)
+ rxdesc->flags |= RX_FLAG_DECRYPTED;
+ else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC)
+ rxdesc->flags |= RX_FLAG_MMIC_ERROR;
+ }
+
+ if (rt2x00_get_field32(rxd3, RXD_W3_MY_BSS))
+ rxdesc->dev_flags |= RXDONE_MY_BSS;
+
+ if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD)) {
+ rxdesc->dev_flags |= RXDONE_L2PAD;
+ skbdesc->flags |= SKBDESC_L2_PADDED;
+ }
+
+ if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))
+ rxdesc->flags |= RX_FLAG_SHORT_GI;
+
+ if (rt2x00_get_field32(rxwi1, RXWI_W1_BW))
+ rxdesc->flags |= RX_FLAG_40MHZ;
+
+ /*
+ * Detect RX rate, always use MCS as signal type.
+ */
+ rxdesc->dev_flags |= RXDONE_SIGNAL_MCS;
+ rxdesc->rate_mode = rt2x00_get_field32(rxwi1, RXWI_W1_PHYMODE);
+ rxdesc->signal = rt2x00_get_field32(rxwi1, RXWI_W1_MCS);
+
+ /*
+ * Mask of 0x8 bit to remove the short preamble flag.
+ */
+ if (rxdesc->rate_mode == RATE_MODE_CCK)
+ rxdesc->signal &= ~0x8;
+
+ rxdesc->rssi =
+ (rt2x00_get_field32(rxwi2, RXWI_W2_RSSI0) +
+ rt2x00_get_field32(rxwi2, RXWI_W2_RSSI1)) / 2;
+
+ rxdesc->noise =
+ (rt2x00_get_field32(rxwi3, RXWI_W3_SNR0) +
+ rt2x00_get_field32(rxwi3, RXWI_W3_SNR1)) / 2;
+
+ rxdesc->size = rt2x00_get_field32(rxwi0, RXWI_W0_MPDU_TOTAL_BYTE_COUNT);
+
+ /*
+ * Set RX IDX in register to inform hardware that we have handled
+ * this entry and it is available for reuse again.
+ */
+ rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX, entry->entry_idx);
+
+ /*
+ * Remove TXWI descriptor from start of buffer.
+ */
+ skb_pull(entry->skb, RXWI_DESC_SIZE);
+ skb_trim(entry->skb, rxdesc->size);
+}
+
+/*
+ * Interrupt functions.
+ */
+static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+ struct queue_entry *entry;
+ struct queue_entry *entry_done;
+ struct queue_entry_priv_pci *entry_priv;
+ struct txdone_entry_desc txdesc;
+ u32 word;
+ u32 reg;
+ u32 old_reg;
+ unsigned int type;
+ unsigned int index;
+ u16 mcs, real_mcs;
+
+ /*
+ * During each loop we will compare the freshly read
+ * TX_STA_FIFO register value with the value read from
+ * the previous loop. If the 2 values are equal then
+ * we should stop processing because the chance it
+ * quite big that the device has been unplugged and
+ * we risk going into an endless loop.
+ */
+ old_reg = 0;
+
+ while (1) {
+ rt2x00pci_register_read(rt2x00dev, TX_STA_FIFO, &reg);
+ if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID))
+ break;
+
+ if (old_reg == reg)
+ break;
+ old_reg = reg;
+
+ /*
+ * Skip this entry when it contains an invalid
+ * queue identication number.
+ */
+ type = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE) - 1;
+ if (type >= QID_RX)
+ continue;
+
+ queue = rt2x00queue_get_queue(rt2x00dev, type);
+ if (unlikely(!queue))
+ continue;
+
+ /*
+ * Skip this entry when it contains an invalid
+ * index number.
+ */
+ index = rt2x00_get_field32(reg, TX_STA_FIFO_WCID) - 1;
+ if (unlikely(index >= queue->limit))
+ continue;
+
+ entry = &queue->entries[index];
+ entry_priv = entry->priv_data;
+ rt2x00_desc_read((__le32 *)entry->skb->data, 0, &word);
+
+ entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+ while (entry != entry_done) {
+ /*
+ * Catch up.
+ * Just report any entries we missed as failed.
+ */
+ WARNING(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);
+ entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+ }
+
+ /*
+ * Obtain the status about this packet.
+ */
+ txdesc.flags = 0;
+ if (rt2x00_get_field32(reg, TX_STA_FIFO_TX_SUCCESS))
+ __set_bit(TXDONE_SUCCESS, &txdesc.flags);
+ else
+ __set_bit(TXDONE_FAILURE, &txdesc.flags);
+
+ /*
+ * Ralink has a retry mechanism using a global fallback
+ * table. We setup this fallback table to try immediate
+ * lower rate for all rates. In the TX_STA_FIFO,
+ * the MCS field contains the MCS used for the successfull
+ * transmission. If the first transmission succeed,
+ * we have mcs == tx_mcs. On the second transmission,
+ * we have mcs = tx_mcs - 1. So the number of
+ * retry is (tx_mcs - mcs).
+ */
+ mcs = rt2x00_get_field32(word, TXWI_W0_MCS);
+ real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS);
+ __set_bit(TXDONE_FALLBACK, &txdesc.flags);
+ txdesc.retry = mcs - min(mcs, real_mcs);
+
+ rt2x00lib_txdone(entry, &txdesc);
+ }
+}
+
+static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
+{
+ struct rt2x00_dev *rt2x00dev = dev_instance;
+ u32 reg;
+
+ /* Read status and ACK all interrupts */
+ rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+ rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+
+ if (!reg)
+ return IRQ_NONE;
+
+ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+ return IRQ_HANDLED;
+
+ /*
+ * 1 - Rx ring done interrupt.
+ */
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE))
+ rt2x00pci_rxdone(rt2x00dev);
+
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
+ rt2800pci_txdone(rt2x00dev);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Device probe functions.
+ */
+static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ u16 word;
+ u8 *mac;
+ u8 default_lna_gain;
+
+ /*
+ * Read EEPROM into buffer
+ */
+ switch(rt2x00dev->chip.rt) {
+ case RT2880:
+ case RT3052:
+ rt2800pci_read_eeprom_soc(rt2x00dev);
+ break;
+ case RT3090:
+ rt2800pci_read_eeprom_efuse(rt2x00dev);
+ break;
+ default:
+ rt2800pci_read_eeprom_pci(rt2x00dev);
+ break;
+ }
+
+ /*
+ * Start validation of the data that has been read.
+ */
+ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+ if (!is_valid_ether_addr(mac)) {
+ random_ether_addr(mac);
+ EEPROM(rt2x00dev, "MAC: %pM\n", mac);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_TXPATH, 1);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+ EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
+ } else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) {
+ /*
+ * There is a max of 2 RX streams for RT2860 series
+ */
+ if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2)
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_NIC_HW_RADIO, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_DYNAMIC_TX_AGC, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_BG, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_A, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
+ EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
+ if ((word & 0x00ff) == 0x00ff) {
+ rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
+ rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE,
+ LED_MODE_TXRX_ACTIVITY);
+ rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8);
+ EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
+ }
+
+ /*
+ * During the LNA validation we are going to use
+ * lna0 as correct value. Note that EEPROM_LNA
+ * is never validated.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &word);
+ default_lna_gain = rt2x00_get_field16(word, EEPROM_LNA_A0);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word);
+ if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET0)) > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET0, 0);
+ if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET1)) > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET1, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word);
+ if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0);
+ if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 ||
+ rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff)
+ rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1,
+ default_lna_gain);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word);
+ if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET0, 0);
+ if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET1)) > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET1, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word);
+ if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0);
+ if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 ||
+ rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff)
+ rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2,
+ default_lna_gain);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word);
+
+ return 0;
+}
+
+static int rt2800pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ u16 value;
+ u16 eeprom;
+
+ /*
+ * Read EEPROM word for configuration.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+
+ /*
+ * Identify RF chipset.
+ */
+ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
+ rt2x00_set_chip_rf(rt2x00dev, value, reg);
+
+ if (!rt2x00_rf(&rt2x00dev->chip, RF2820) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2850) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2720) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2750) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF3020) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2020) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF3021) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF3022)) {
+ ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Identify default antenna configuration.
+ */
+ rt2x00dev->default_ant.tx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH);
+ rt2x00dev->default_ant.rx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH);
+
+ /*
+ * Read frequency offset and RF programming sequence.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
+ rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
+
+ /*
+ * Read external LNA informations.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A))
+ __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG))
+ __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+
+ /*
+ * Detect if this device has an hardware controlled radio.
+ */
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO))
+ __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+
+ /*
+ * Store led settings, for correct led behaviour.
+ */
+#ifdef CONFIG_RT2X00_LIB_LEDS
+ rt2800pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO);
+ rt2800pci_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC);
+ rt2800pci_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &rt2x00dev->led_mcu_reg);
+#endif /* CONFIG_RT2X00_LIB_LEDS */
+
+ return 0;
+}
+
+/*
+ * RF value list for rt2860
+ * Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750)
+ */
+static const struct rf_channel rf_vals[] = {
+ { 1, 0x18402ecc, 0x184c0786, 0x1816b455, 0x1800510b },
+ { 2, 0x18402ecc, 0x184c0786, 0x18168a55, 0x1800519f },
+ { 3, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800518b },
+ { 4, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800519f },
+ { 5, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800518b },
+ { 6, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800519f },
+ { 7, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800518b },
+ { 8, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800519f },
+ { 9, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800518b },
+ { 10, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800519f },
+ { 11, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800518b },
+ { 12, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800519f },
+ { 13, 0x18402ecc, 0x184c079e, 0x18168a55, 0x1800518b },
+ { 14, 0x18402ecc, 0x184c07a2, 0x18168a55, 0x18005193 },
+
+ /* 802.11 UNI / HyperLan 2 */
+ { 36, 0x18402ecc, 0x184c099a, 0x18158a55, 0x180ed1a3 },
+ { 38, 0x18402ecc, 0x184c099e, 0x18158a55, 0x180ed193 },
+ { 40, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed183 },
+ { 44, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed1a3 },
+ { 46, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed18b },
+ { 48, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed19b },
+ { 52, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed193 },
+ { 54, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed1a3 },
+ { 56, 0x18402ec8, 0x184c068e, 0x18158a55, 0x180ed18b },
+ { 60, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed183 },
+ { 62, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed193 },
+ { 64, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed1a3 },
+
+ /* 802.11 HyperLan 2 */
+ { 100, 0x18402ec8, 0x184c06b2, 0x18178a55, 0x180ed783 },
+ { 102, 0x18402ec8, 0x184c06b2, 0x18578a55, 0x180ed793 },
+ { 104, 0x18402ec8, 0x185c06b2, 0x18578a55, 0x180ed1a3 },
+ { 108, 0x18402ecc, 0x185c0a32, 0x18578a55, 0x180ed193 },
+ { 110, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed183 },
+ { 112, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed19b },
+ { 116, 0x18402ecc, 0x184c0a3a, 0x18178a55, 0x180ed1a3 },
+ { 118, 0x18402ecc, 0x184c0a3e, 0x18178a55, 0x180ed193 },
+ { 120, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed183 },
+ { 124, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed193 },
+ { 126, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed15b },
+ { 128, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed1a3 },
+ { 132, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed18b },
+ { 134, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed193 },
+ { 136, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed19b },
+ { 140, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed183 },
+
+ /* 802.11 UNII */
+ { 149, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed1a7 },
+ { 151, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed187 },
+ { 153, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed18f },
+ { 157, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed19f },
+ { 159, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed1a7 },
+ { 161, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed187 },
+ { 165, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed197 },
+
+ /* 802.11 Japan */
+ { 184, 0x15002ccc, 0x1500491e, 0x1509be55, 0x150c0a0b },
+ { 188, 0x15002ccc, 0x15004922, 0x1509be55, 0x150c0a13 },
+ { 192, 0x15002ccc, 0x15004926, 0x1509be55, 0x150c0a1b },
+ { 196, 0x15002ccc, 0x1500492a, 0x1509be55, 0x150c0a23 },
+ { 208, 0x15002ccc, 0x1500493a, 0x1509be55, 0x150c0a13 },
+ { 212, 0x15002ccc, 0x1500493e, 0x1509be55, 0x150c0a1b },
+ { 216, 0x15002ccc, 0x15004982, 0x1509be55, 0x150c0a23 },
+};
+
+static int rt2800pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+{
+ struct hw_mode_spec *spec = &rt2x00dev->spec;
+ struct channel_info *info;
+ char *tx_power1;
+ char *tx_power2;
+ unsigned int i;
+ u16 eeprom;
+
+ /*
+ * 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;
+ rt2x00dev->hw->extra_tx_headroom = TXWI_DESC_SIZE;
+
+ SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
+ SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+ rt2x00_eeprom_addr(rt2x00dev,
+ EEPROM_MAC_ADDR_0));
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+
+ /*
+ * Initialize hw_mode information.
+ */
+ spec->supported_bands = SUPPORT_BAND_2GHZ;
+ spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
+
+ if (rt2x00_rf(&rt2x00dev->chip, RF2820) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2720) ||
+ rt2x00_rf(&rt2x00dev->chip, RF3020) ||
+ rt2x00_rf(&rt2x00dev->chip, RF3021) ||
+ rt2x00_rf(&rt2x00dev->chip, RF3022) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2020) ||
+ rt2x00_rf(&rt2x00dev->chip, RF3052)) {
+ spec->num_channels = 14;
+ spec->channels = rf_vals;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2850) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2750)) {
+ spec->supported_bands |= SUPPORT_BAND_5GHZ;
+ spec->num_channels = ARRAY_SIZE(rf_vals);
+ spec->channels = rf_vals;
+ }
+
+ /*
+ * Initialize HT information.
+ */
+ spec->ht.ht_supported = true;
+ spec->ht.cap =
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+ IEEE80211_HT_CAP_GRN_FLD |
+ IEEE80211_HT_CAP_SGI_20 |
+ IEEE80211_HT_CAP_SGI_40 |
+ IEEE80211_HT_CAP_TX_STBC |
+ IEEE80211_HT_CAP_RX_STBC |
+ IEEE80211_HT_CAP_PSMP_SUPPORT;
+ spec->ht.ampdu_factor = 3;
+ spec->ht.ampdu_density = 4;
+ spec->ht.mcs.tx_params =
+ IEEE80211_HT_MCS_TX_DEFINED |
+ IEEE80211_HT_MCS_TX_RX_DIFF |
+ ((rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) - 1) <<
+ IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
+
+ switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) {
+ case 3:
+ spec->ht.mcs.rx_mask[2] = 0xff;
+ case 2:
+ spec->ht.mcs.rx_mask[1] = 0xff;
+ case 1:
+ spec->ht.mcs.rx_mask[0] = 0xff;
+ spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */
+ break;
+ }
+
+ /*
+ * Create channel information array
+ */
+ info = kzalloc(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);
+
+ 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]);
+ }
+
+ if (spec->num_channels > 14) {
+ tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1);
+ tx_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]);
+ }
+ }
+
+ return 0;
+}
+
+static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+ int retval;
+
+ /*
+ * Allocate eeprom data.
+ */
+ retval = rt2800pci_validate_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ retval = rt2800pci_init_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ /*
+ * Initialize hw specifications.
+ */
+ retval = rt2800pci_probe_hw_mode(rt2x00dev);
+ if (retval)
+ return retval;
+
+ /*
+ * This device has multiple filters for control frames
+ * and has a separate filter for PS Poll frames.
+ */
+ __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags);
+ __set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags);
+
+ /*
+ * This device requires firmware.
+ */
+ if (!rt2x00_rt(&rt2x00dev->chip, RT2880) &&
+ !rt2x00_rt(&rt2x00dev->chip, RT3052))
+ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
+ __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
+ __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
+ if (!modparam_nohwcrypt)
+ __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
+
+ /*
+ * Set the rssi offset.
+ */
+ rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
+ return 0;
+}
+
+/*
+ * IEEE80211 stack callback functions.
+ */
+static void rt2800pci_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx,
+ u32 *iv32, u16 *iv16)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct mac_iveiv_entry iveiv_entry;
+ u32 offset;
+
+ offset = MAC_IVEIV_ENTRY(hw_key_idx);
+ rt2x00pci_register_multiread(rt2x00dev, offset,
+ &iveiv_entry, sizeof(iveiv_entry));
+
+ memcpy(&iveiv_entry.iv[0], iv16, sizeof(iv16));
+ memcpy(&iveiv_entry.iv[4], iv32, sizeof(iv32));
+}
+
+static int rt2800pci_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u32 reg;
+ bool enabled = (value < IEEE80211_MAX_RTS_THRESHOLD);
+
+ rt2x00pci_register_read(rt2x00dev, TX_RTS_CFG, &reg);
+ rt2x00_set_field32(&reg, TX_RTS_CFG_RTS_THRES, value);
+ rt2x00pci_register_write(rt2x00dev, TX_RTS_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CCK_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_RTS_TH_EN, enabled);
+ rt2x00pci_register_write(rt2x00dev, CCK_PROT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, OFDM_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_RTS_TH_EN, enabled);
+ rt2x00pci_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MM20_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, MM20_PROT_CFG_RTS_TH_EN, enabled);
+ rt2x00pci_register_write(rt2x00dev, MM20_PROT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MM40_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, MM40_PROT_CFG_RTS_TH_EN, enabled);
+ rt2x00pci_register_write(rt2x00dev, MM40_PROT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, GF20_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, GF20_PROT_CFG_RTS_TH_EN, enabled);
+ rt2x00pci_register_write(rt2x00dev, GF20_PROT_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, GF40_PROT_CFG, &reg);
+ rt2x00_set_field32(&reg, GF40_PROT_CFG_RTS_TH_EN, enabled);
+ rt2x00pci_register_write(rt2x00dev, GF40_PROT_CFG, reg);
+
+ return 0;
+}
+
+static int rt2800pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct data_queue *queue;
+ struct rt2x00_field32 field;
+ int retval;
+ u32 reg;
+ u32 offset;
+
+ /*
+ * First pass the configuration through rt2x00lib, that will
+ * update the queue settings and validate the input. After that
+ * we are free to update the registers based on the value
+ * in the queue parameter.
+ */
+ retval = rt2x00mac_conf_tx(hw, queue_idx, params);
+ if (retval)
+ return retval;
+
+ /*
+ * We only need to perform additional register initialization
+ * for WMM queues/
+ */
+ if (queue_idx >= 4)
+ return 0;
+
+ queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
+
+ /* Update WMM TXOP register */
+ offset = WMM_TXOP0_CFG + (sizeof(u32) * (!!(queue_idx & 2)));
+ field.bit_offset = (queue_idx & 1) * 16;
+ field.bit_mask = 0xffff << field.bit_offset;
+
+ rt2x00pci_register_read(rt2x00dev, offset, &reg);
+ rt2x00_set_field32(&reg, field, queue->txop);
+ rt2x00pci_register_write(rt2x00dev, offset, reg);
+
+ /* Update WMM registers */
+ field.bit_offset = queue_idx * 4;
+ field.bit_mask = 0xf << field.bit_offset;
+
+ rt2x00pci_register_read(rt2x00dev, WMM_AIFSN_CFG, &reg);
+ rt2x00_set_field32(&reg, field, queue->aifs);
+ rt2x00pci_register_write(rt2x00dev, WMM_AIFSN_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, WMM_CWMIN_CFG, &reg);
+ rt2x00_set_field32(&reg, field, queue->cw_min);
+ rt2x00pci_register_write(rt2x00dev, WMM_CWMIN_CFG, reg);
+
+ rt2x00pci_register_read(rt2x00dev, WMM_CWMAX_CFG, &reg);
+ rt2x00_set_field32(&reg, field, queue->cw_max);
+ rt2x00pci_register_write(rt2x00dev, WMM_CWMAX_CFG, reg);
+
+ /* Update EDCA registers */
+ offset = EDCA_AC0_CFG + (sizeof(u32) * queue_idx);
+
+ rt2x00pci_register_read(rt2x00dev, offset, &reg);
+ rt2x00_set_field32(&reg, EDCA_AC0_CFG_TX_OP, queue->txop);
+ rt2x00_set_field32(&reg, EDCA_AC0_CFG_AIFSN, queue->aifs);
+ rt2x00_set_field32(&reg, EDCA_AC0_CFG_CWMIN, queue->cw_min);
+ rt2x00_set_field32(&reg, EDCA_AC0_CFG_CWMAX, queue->cw_max);
+ rt2x00pci_register_write(rt2x00dev, offset, reg);
+
+ return 0;
+}
+
+static u64 rt2800pci_get_tsf(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u64 tsf;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, TSF_TIMER_DW1, &reg);
+ tsf = (u64) rt2x00_get_field32(reg, TSF_TIMER_DW1_HIGH_WORD) << 32;
+ rt2x00pci_register_read(rt2x00dev, TSF_TIMER_DW0, &reg);
+ tsf |= rt2x00_get_field32(reg, TSF_TIMER_DW0_LOW_WORD);
+
+ return tsf;
+}
+
+static const struct ieee80211_ops rt2800pci_mac80211_ops = {
+ .tx = rt2x00mac_tx,
+ .start = rt2x00mac_start,
+ .stop = rt2x00mac_stop,
+ .add_interface = rt2x00mac_add_interface,
+ .remove_interface = rt2x00mac_remove_interface,
+ .config = rt2x00mac_config,
+ .configure_filter = rt2x00mac_configure_filter,
+ .set_key = rt2x00mac_set_key,
+ .get_stats = rt2x00mac_get_stats,
+ .get_tkip_seq = rt2800pci_get_tkip_seq,
+ .set_rts_threshold = rt2800pci_set_rts_threshold,
+ .bss_info_changed = rt2x00mac_bss_info_changed,
+ .conf_tx = rt2800pci_conf_tx,
+ .get_tx_stats = rt2x00mac_get_tx_stats,
+ .get_tsf = rt2800pci_get_tsf,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
+};
+
+static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
+ .irq_handler = rt2800pci_interrupt,
+ .probe_hw = rt2800pci_probe_hw,
+ .get_firmware_name = rt2800pci_get_firmware_name,
+ .check_firmware = rt2800pci_check_firmware,
+ .load_firmware = rt2800pci_load_firmware,
+ .initialize = rt2x00pci_initialize,
+ .uninitialize = rt2x00pci_uninitialize,
+ .get_entry_state = rt2800pci_get_entry_state,
+ .clear_entry = rt2800pci_clear_entry,
+ .set_device_state = rt2800pci_set_device_state,
+ .rfkill_poll = rt2800pci_rfkill_poll,
+ .link_stats = rt2800pci_link_stats,
+ .reset_tuner = rt2800pci_reset_tuner,
+ .link_tuner = rt2800pci_link_tuner,
+ .write_tx_desc = rt2800pci_write_tx_desc,
+ .write_tx_data = rt2x00pci_write_tx_data,
+ .write_beacon = rt2800pci_write_beacon,
+ .kick_tx_queue = rt2800pci_kick_tx_queue,
+ .kill_tx_queue = rt2800pci_kill_tx_queue,
+ .fill_rxdone = rt2800pci_fill_rxdone,
+ .config_shared_key = rt2800pci_config_shared_key,
+ .config_pairwise_key = rt2800pci_config_pairwise_key,
+ .config_filter = rt2800pci_config_filter,
+ .config_intf = rt2800pci_config_intf,
+ .config_erp = rt2800pci_config_erp,
+ .config_ant = rt2800pci_config_ant,
+ .config = rt2800pci_config,
+};
+
+static const struct data_queue_desc rt2800pci_queue_rx = {
+ .entry_num = RX_ENTRIES,
+ .data_size = AGGREGATION_SIZE,
+ .desc_size = RXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_pci),
+};
+
+static const struct data_queue_desc rt2800pci_queue_tx = {
+ .entry_num = TX_ENTRIES,
+ .data_size = AGGREGATION_SIZE,
+ .desc_size = TXD_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_pci),
+};
+
+static const struct data_queue_desc rt2800pci_queue_bcn = {
+ .entry_num = 8 * BEACON_ENTRIES,
+ .data_size = 0, /* No DMA required for beacons */
+ .desc_size = TXWI_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_pci),
+};
+
+static const struct rt2x00_ops rt2800pci_ops = {
+ .name = KBUILD_MODNAME,
+ .max_sta_intf = 1,
+ .max_ap_intf = 8,
+ .eeprom_size = EEPROM_SIZE,
+ .rf_size = RF_SIZE,
+ .tx_queues = NUM_TX_QUEUES,
+ .rx = &rt2800pci_queue_rx,
+ .tx = &rt2800pci_queue_tx,
+ .bcn = &rt2800pci_queue_bcn,
+ .lib = &rt2800pci_rt2x00_ops,
+ .hw = &rt2800pci_mac80211_ops,
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+ .debugfs = &rt2800pci_rt2x00debug,
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * RT2800pci module information.
+ */
+static struct pci_device_id rt2800pci_device_table[] = {
+ { PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1432, 0x7708), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1432, 0x7727), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1432, 0x7728), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1432, 0x7738), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1432, 0x7748), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1432, 0x7758), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1432, 0x7768), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x0701), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x0781), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x3090), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x3091), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x3092), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x3562), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x3592), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { 0, }
+};
+
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Ralink RT2800 PCI & PCMCIA Wireless LAN driver.");
+MODULE_SUPPORTED_DEVICE("Ralink RT2860 PCI & PCMCIA chipset based cards");
+#ifdef CONFIG_RT2800PCI_PCI
+MODULE_FIRMWARE(FIRMWARE_RT2860);
+MODULE_DEVICE_TABLE(pci, rt2800pci_device_table);
+#endif /* CONFIG_RT2800PCI_PCI */
+MODULE_LICENSE("GPL");
+
+#ifdef CONFIG_RT2800PCI_WISOC
+#if defined(CONFIG_RALINK_RT288X)
+__rt2x00soc_probe(RT2880, &rt2800pci_ops);
+#elif defined(CONFIG_RALINK_RT305X)
+__rt2x00soc_probe(RT3052, &rt2800pci_ops);
+#endif
+
+static struct platform_driver rt2800soc_driver = {
+ .driver = {
+ .name = "rt2800_wmac",
+ .owner = THIS_MODULE,
+ .mod_name = KBUILD_MODNAME,
+ },
+ .probe = __rt2x00soc_probe,
+ .remove = __devexit_p(rt2x00soc_remove),
+ .suspend = rt2x00soc_suspend,
+ .resume = rt2x00soc_resume,
+};
+#endif /* CONFIG_RT2800PCI_WISOC */
+
+#ifdef CONFIG_RT2800PCI_PCI
+static struct pci_driver rt2800pci_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = rt2800pci_device_table,
+ .probe = rt2x00pci_probe,
+ .remove = __devexit_p(rt2x00pci_remove),
+ .suspend = rt2x00pci_suspend,
+ .resume = rt2x00pci_resume,
+};
+#endif /* CONFIG_RT2800PCI_PCI */
+
+static int __init rt2800pci_init(void)
+{
+ int ret = 0;
+
+#ifdef CONFIG_RT2800PCI_WISOC
+ ret = platform_driver_register(&rt2800soc_driver);
+ if (ret)
+ return ret;
+#endif
+#ifdef CONFIG_RT2800PCI_PCI
+ ret = pci_register_driver(&rt2800pci_driver);
+ if (ret) {
+#ifdef CONFIG_RT2800PCI_WISOC
+ platform_driver_unregister(&rt2800soc_driver);
+#endif
+ return ret;
+ }
+#endif
+
+ return ret;
+}
+
+static void __exit rt2800pci_exit(void)
+{
+#ifdef CONFIG_RT2800PCI_PCI
+ pci_unregister_driver(&rt2800pci_driver);
+#endif
+#ifdef CONFIG_RT2800PCI_WISOC
+ platform_driver_unregister(&rt2800soc_driver);
+#endif
+}
+
+module_init(rt2800pci_init);
+module_exit(rt2800pci_exit);
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h
new file mode 100644
index 000000000000..856908815221
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2800pci.h
@@ -0,0 +1,1960 @@
+/*
+ Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2800pci
+ Abstract: Data structures and registers for the rt2800pci module.
+ Supported chipsets: RT2800E & RT2800ED.
+ */
+
+#ifndef RT2800PCI_H
+#define RT2800PCI_H
+
+/*
+ * RF chip defines.
+ *
+ * RF2820 2.4G 2T3R
+ * RF2850 2.4G/5G 2T3R
+ * RF2720 2.4G 1T2R
+ * RF2750 2.4G/5G 1T2R
+ * RF3020 2.4G 1T1R
+ * RF2020 2.4G B/G
+ * RF3021 2.4G 1T2R
+ * RF3022 2.4G 2T2R
+ * RF3052 2.4G 2T2R
+ */
+#define RF2820 0x0001
+#define RF2850 0x0002
+#define RF2720 0x0003
+#define RF2750 0x0004
+#define RF3020 0x0005
+#define RF2020 0x0006
+#define RF3021 0x0007
+#define RF3022 0x0008
+#define RF3052 0x0009
+
+/*
+ * RT2860 version
+ */
+#define RT2860C_VERSION 0x28600100
+#define RT2860D_VERSION 0x28600101
+#define RT2880E_VERSION 0x28720200
+#define RT2883_VERSION 0x28830300
+#define RT3070_VERSION 0x30700200
+
+/*
+ * Signal information.
+ * Default offset is required for RSSI <-> dBm conversion.
+ */
+#define DEFAULT_RSSI_OFFSET 120 /* FIXME */
+
+/*
+ * Register layout information.
+ */
+#define CSR_REG_BASE 0x1000
+#define CSR_REG_SIZE 0x0800
+#define EEPROM_BASE 0x0000
+#define EEPROM_SIZE 0x0110
+#define BBP_BASE 0x0000
+#define BBP_SIZE 0x0080
+#define RF_BASE 0x0004
+#define RF_SIZE 0x0010
+
+/*
+ * Number of TX queues.
+ */
+#define NUM_TX_QUEUES 4
+
+/*
+ * PCI registers.
+ */
+
+/*
+ * E2PROM_CSR: EEPROM control register.
+ * RELOAD: Write 1 to reload eeprom content.
+ * TYPE: 0: 93c46, 1:93c66.
+ * LOAD_STATUS: 1:loading, 0:done.
+ */
+#define E2PROM_CSR 0x0004
+#define E2PROM_CSR_DATA_CLOCK FIELD32(0x00000001)
+#define E2PROM_CSR_CHIP_SELECT FIELD32(0x00000002)
+#define E2PROM_CSR_DATA_IN FIELD32(0x00000004)
+#define E2PROM_CSR_DATA_OUT FIELD32(0x00000008)
+#define E2PROM_CSR_TYPE FIELD32(0x00000030)
+#define E2PROM_CSR_LOAD_STATUS FIELD32(0x00000040)
+#define E2PROM_CSR_RELOAD FIELD32(0x00000080)
+
+/*
+ * INT_SOURCE_CSR: Interrupt source register.
+ * Write one to clear corresponding bit.
+ * TX_FIFO_STATUS: FIFO Statistics is full, sw should read 0x171c
+ */
+#define INT_SOURCE_CSR 0x0200
+#define INT_SOURCE_CSR_RXDELAYINT FIELD32(0x00000001)
+#define INT_SOURCE_CSR_TXDELAYINT FIELD32(0x00000002)
+#define INT_SOURCE_CSR_RX_DONE FIELD32(0x00000004)
+#define INT_SOURCE_CSR_AC0_DMA_DONE FIELD32(0x00000008)
+#define INT_SOURCE_CSR_AC1_DMA_DONE FIELD32(0x00000010)
+#define INT_SOURCE_CSR_AC2_DMA_DONE FIELD32(0x00000020)
+#define INT_SOURCE_CSR_AC3_DMA_DONE FIELD32(0x00000040)
+#define INT_SOURCE_CSR_HCCA_DMA_DONE FIELD32(0x00000080)
+#define INT_SOURCE_CSR_MGMT_DMA_DONE FIELD32(0x00000100)
+#define INT_SOURCE_CSR_MCU_COMMAND FIELD32(0x00000200)
+#define INT_SOURCE_CSR_RXTX_COHERENT FIELD32(0x00000400)
+#define INT_SOURCE_CSR_TBTT FIELD32(0x00000800)
+#define INT_SOURCE_CSR_PRE_TBTT FIELD32(0x00001000)
+#define INT_SOURCE_CSR_TX_FIFO_STATUS FIELD32(0x00002000)
+#define INT_SOURCE_CSR_AUTO_WAKEUP FIELD32(0x00004000)
+#define INT_SOURCE_CSR_GPTIMER FIELD32(0x00008000)
+#define INT_SOURCE_CSR_RX_COHERENT FIELD32(0x00010000)
+#define INT_SOURCE_CSR_TX_COHERENT FIELD32(0x00020000)
+
+/*
+ * INT_MASK_CSR: Interrupt MASK register. 1: the interrupt is mask OFF.
+ */
+#define INT_MASK_CSR 0x0204
+#define INT_MASK_CSR_RXDELAYINT FIELD32(0x00000001)
+#define INT_MASK_CSR_TXDELAYINT FIELD32(0x00000002)
+#define INT_MASK_CSR_RX_DONE FIELD32(0x00000004)
+#define INT_MASK_CSR_AC0_DMA_DONE FIELD32(0x00000008)
+#define INT_MASK_CSR_AC1_DMA_DONE FIELD32(0x00000010)
+#define INT_MASK_CSR_AC2_DMA_DONE FIELD32(0x00000020)
+#define INT_MASK_CSR_AC3_DMA_DONE FIELD32(0x00000040)
+#define INT_MASK_CSR_HCCA_DMA_DONE FIELD32(0x00000080)
+#define INT_MASK_CSR_MGMT_DMA_DONE FIELD32(0x00000100)
+#define INT_MASK_CSR_MCU_COMMAND FIELD32(0x00000200)
+#define INT_MASK_CSR_RXTX_COHERENT FIELD32(0x00000400)
+#define INT_MASK_CSR_TBTT FIELD32(0x00000800)
+#define INT_MASK_CSR_PRE_TBTT FIELD32(0x00001000)
+#define INT_MASK_CSR_TX_FIFO_STATUS FIELD32(0x00002000)
+#define INT_MASK_CSR_AUTO_WAKEUP FIELD32(0x00004000)
+#define INT_MASK_CSR_GPTIMER FIELD32(0x00008000)
+#define INT_MASK_CSR_RX_COHERENT FIELD32(0x00010000)
+#define INT_MASK_CSR_TX_COHERENT FIELD32(0x00020000)
+
+/*
+ * WPDMA_GLO_CFG
+ */
+#define WPDMA_GLO_CFG 0x0208
+#define WPDMA_GLO_CFG_ENABLE_TX_DMA FIELD32(0x00000001)
+#define WPDMA_GLO_CFG_TX_DMA_BUSY FIELD32(0x00000002)
+#define WPDMA_GLO_CFG_ENABLE_RX_DMA FIELD32(0x00000004)
+#define WPDMA_GLO_CFG_RX_DMA_BUSY FIELD32(0x00000008)
+#define WPDMA_GLO_CFG_WP_DMA_BURST_SIZE FIELD32(0x00000030)
+#define WPDMA_GLO_CFG_TX_WRITEBACK_DONE FIELD32(0x00000040)
+#define WPDMA_GLO_CFG_BIG_ENDIAN FIELD32(0x00000080)
+#define WPDMA_GLO_CFG_RX_HDR_SCATTER FIELD32(0x0000ff00)
+#define WPDMA_GLO_CFG_HDR_SEG_LEN FIELD32(0xffff0000)
+
+/*
+ * WPDMA_RST_IDX
+ */
+#define WPDMA_RST_IDX 0x020c
+#define WPDMA_RST_IDX_DTX_IDX0 FIELD32(0x00000001)
+#define WPDMA_RST_IDX_DTX_IDX1 FIELD32(0x00000002)
+#define WPDMA_RST_IDX_DTX_IDX2 FIELD32(0x00000004)
+#define WPDMA_RST_IDX_DTX_IDX3 FIELD32(0x00000008)
+#define WPDMA_RST_IDX_DTX_IDX4 FIELD32(0x00000010)
+#define WPDMA_RST_IDX_DTX_IDX5 FIELD32(0x00000020)
+#define WPDMA_RST_IDX_DRX_IDX0 FIELD32(0x00010000)
+
+/*
+ * DELAY_INT_CFG
+ */
+#define DELAY_INT_CFG 0x0210
+#define DELAY_INT_CFG_RXMAX_PTIME FIELD32(0x000000ff)
+#define DELAY_INT_CFG_RXMAX_PINT FIELD32(0x00007f00)
+#define DELAY_INT_CFG_RXDLY_INT_EN FIELD32(0x00008000)
+#define DELAY_INT_CFG_TXMAX_PTIME FIELD32(0x00ff0000)
+#define DELAY_INT_CFG_TXMAX_PINT FIELD32(0x7f000000)
+#define DELAY_INT_CFG_TXDLY_INT_EN FIELD32(0x80000000)
+
+/*
+ * WMM_AIFSN_CFG: Aifsn for each EDCA AC
+ * AIFSN0: AC_BE
+ * AIFSN1: AC_BK
+ * AIFSN1: AC_VI
+ * AIFSN1: AC_VO
+ */
+#define WMM_AIFSN_CFG 0x0214
+#define WMM_AIFSN_CFG_AIFSN0 FIELD32(0x0000000f)
+#define WMM_AIFSN_CFG_AIFSN1 FIELD32(0x000000f0)
+#define WMM_AIFSN_CFG_AIFSN2 FIELD32(0x00000f00)
+#define WMM_AIFSN_CFG_AIFSN3 FIELD32(0x0000f000)
+
+/*
+ * WMM_CWMIN_CSR: CWmin for each EDCA AC
+ * CWMIN0: AC_BE
+ * CWMIN1: AC_BK
+ * CWMIN1: AC_VI
+ * CWMIN1: AC_VO
+ */
+#define WMM_CWMIN_CFG 0x0218
+#define WMM_CWMIN_CFG_CWMIN0 FIELD32(0x0000000f)
+#define WMM_CWMIN_CFG_CWMIN1 FIELD32(0x000000f0)
+#define WMM_CWMIN_CFG_CWMIN2 FIELD32(0x00000f00)
+#define WMM_CWMIN_CFG_CWMIN3 FIELD32(0x0000f000)
+
+/*
+ * WMM_CWMAX_CSR: CWmax for each EDCA AC
+ * CWMAX0: AC_BE
+ * CWMAX1: AC_BK
+ * CWMAX1: AC_VI
+ * CWMAX1: AC_VO
+ */
+#define WMM_CWMAX_CFG 0x021c
+#define WMM_CWMAX_CFG_CWMAX0 FIELD32(0x0000000f)
+#define WMM_CWMAX_CFG_CWMAX1 FIELD32(0x000000f0)
+#define WMM_CWMAX_CFG_CWMAX2 FIELD32(0x00000f00)
+#define WMM_CWMAX_CFG_CWMAX3 FIELD32(0x0000f000)
+
+/*
+ * AC_TXOP0: AC_BK/AC_BE TXOP register
+ * AC0TXOP: AC_BK in unit of 32us
+ * AC1TXOP: AC_BE in unit of 32us
+ */
+#define WMM_TXOP0_CFG 0x0220
+#define WMM_TXOP0_CFG_AC0TXOP FIELD32(0x0000ffff)
+#define WMM_TXOP0_CFG_AC1TXOP FIELD32(0xffff0000)
+
+/*
+ * AC_TXOP1: AC_VO/AC_VI TXOP register
+ * AC2TXOP: AC_VI in unit of 32us
+ * AC3TXOP: AC_VO in unit of 32us
+ */
+#define WMM_TXOP1_CFG 0x0224
+#define WMM_TXOP1_CFG_AC2TXOP FIELD32(0x0000ffff)
+#define WMM_TXOP1_CFG_AC3TXOP FIELD32(0xffff0000)
+
+/*
+ * GPIO_CTRL_CFG:
+ */
+#define GPIO_CTRL_CFG 0x0228
+#define GPIO_CTRL_CFG_BIT0 FIELD32(0x00000001)
+#define GPIO_CTRL_CFG_BIT1 FIELD32(0x00000002)
+#define GPIO_CTRL_CFG_BIT2 FIELD32(0x00000004)
+#define GPIO_CTRL_CFG_BIT3 FIELD32(0x00000008)
+#define GPIO_CTRL_CFG_BIT4 FIELD32(0x00000010)
+#define GPIO_CTRL_CFG_BIT5 FIELD32(0x00000020)
+#define GPIO_CTRL_CFG_BIT6 FIELD32(0x00000040)
+#define GPIO_CTRL_CFG_BIT7 FIELD32(0x00000080)
+#define GPIO_CTRL_CFG_BIT8 FIELD32(0x00000100)
+
+/*
+ * MCU_CMD_CFG
+ */
+#define MCU_CMD_CFG 0x022c
+
+/*
+ * AC_BK register offsets
+ */
+#define TX_BASE_PTR0 0x0230
+#define TX_MAX_CNT0 0x0234
+#define TX_CTX_IDX0 0x0238
+#define TX_DTX_IDX0 0x023c
+
+/*
+ * AC_BE register offsets
+ */
+#define TX_BASE_PTR1 0x0240
+#define TX_MAX_CNT1 0x0244
+#define TX_CTX_IDX1 0x0248
+#define TX_DTX_IDX1 0x024c
+
+/*
+ * AC_VI register offsets
+ */
+#define TX_BASE_PTR2 0x0250
+#define TX_MAX_CNT2 0x0254
+#define TX_CTX_IDX2 0x0258
+#define TX_DTX_IDX2 0x025c
+
+/*
+ * AC_VO register offsets
+ */
+#define TX_BASE_PTR3 0x0260
+#define TX_MAX_CNT3 0x0264
+#define TX_CTX_IDX3 0x0268
+#define TX_DTX_IDX3 0x026c
+
+/*
+ * HCCA register offsets
+ */
+#define TX_BASE_PTR4 0x0270
+#define TX_MAX_CNT4 0x0274
+#define TX_CTX_IDX4 0x0278
+#define TX_DTX_IDX4 0x027c
+
+/*
+ * MGMT register offsets
+ */
+#define TX_BASE_PTR5 0x0280
+#define TX_MAX_CNT5 0x0284
+#define TX_CTX_IDX5 0x0288
+#define TX_DTX_IDX5 0x028c
+
+/*
+ * Queue register offset macros
+ */
+#define TX_QUEUE_REG_OFFSET 0x10
+#define TX_BASE_PTR(__x) TX_BASE_PTR0 + ((__x) * TX_QUEUE_REG_OFFSET)
+#define TX_MAX_CNT(__x) TX_MAX_CNT0 + ((__x) * TX_QUEUE_REG_OFFSET)
+#define TX_CTX_IDX(__x) TX_CTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET)
+#define TX_DTX_IDX(__x) TX_DTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET)
+
+/*
+ * RX register offsets
+ */
+#define RX_BASE_PTR 0x0290
+#define RX_MAX_CNT 0x0294
+#define RX_CRX_IDX 0x0298
+#define RX_DRX_IDX 0x029c
+
+/*
+ * PBF_SYS_CTRL
+ * HOST_RAM_WRITE: enable Host program ram write selection
+ */
+#define PBF_SYS_CTRL 0x0400
+#define PBF_SYS_CTRL_READY FIELD32(0x00000080)
+#define PBF_SYS_CTRL_HOST_RAM_WRITE FIELD32(0x00010000)
+
+/*
+ * HOST-MCU shared memory
+ */
+#define HOST_CMD_CSR 0x0404
+#define HOST_CMD_CSR_HOST_COMMAND FIELD32(0x000000ff)
+
+/*
+ * PBF registers
+ * Most are for debug. Driver doesn't touch PBF register.
+ */
+#define PBF_CFG 0x0408
+#define PBF_MAX_PCNT 0x040c
+#define PBF_CTRL 0x0410
+#define PBF_INT_STA 0x0414
+#define PBF_INT_ENA 0x0418
+
+/*
+ * BCN_OFFSET0:
+ */
+#define BCN_OFFSET0 0x042c
+#define BCN_OFFSET0_BCN0 FIELD32(0x000000ff)
+#define BCN_OFFSET0_BCN1 FIELD32(0x0000ff00)
+#define BCN_OFFSET0_BCN2 FIELD32(0x00ff0000)
+#define BCN_OFFSET0_BCN3 FIELD32(0xff000000)
+
+/*
+ * BCN_OFFSET1:
+ */
+#define BCN_OFFSET1 0x0430
+#define BCN_OFFSET1_BCN4 FIELD32(0x000000ff)
+#define BCN_OFFSET1_BCN5 FIELD32(0x0000ff00)
+#define BCN_OFFSET1_BCN6 FIELD32(0x00ff0000)
+#define BCN_OFFSET1_BCN7 FIELD32(0xff000000)
+
+/*
+ * PBF registers
+ * Most are for debug. Driver doesn't touch PBF register.
+ */
+#define TXRXQ_PCNT 0x0438
+#define PBF_DBG 0x043c
+
+/*
+ * RF registers
+ */
+#define RF_CSR_CFG 0x0500
+#define RF_CSR_CFG_DATA FIELD32(0x000000ff)
+#define RF_CSR_CFG_REGNUM FIELD32(0x00001f00)
+#define RF_CSR_CFG_WRITE FIELD32(0x00010000)
+#define RF_CSR_CFG_BUSY FIELD32(0x00020000)
+
+/*
+ * EFUSE_CSR: RT3090 EEPROM
+ */
+#define EFUSE_CTRL 0x0580
+#define EFUSE_CTRL_ADDRESS_IN FIELD32(0x03fe0000)
+#define EFUSE_CTRL_MODE FIELD32(0x000000c0)
+#define EFUSE_CTRL_KICK FIELD32(0x40000000)
+
+/*
+ * EFUSE_DATA0
+ */
+#define EFUSE_DATA0 0x0590
+
+/*
+ * EFUSE_DATA1
+ */
+#define EFUSE_DATA1 0x0594
+
+/*
+ * EFUSE_DATA2
+ */
+#define EFUSE_DATA2 0x0598
+
+/*
+ * EFUSE_DATA3
+ */
+#define EFUSE_DATA3 0x059c
+
+/*
+ * MAC Control/Status Registers(CSR).
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * MAC_CSR0: ASIC revision number.
+ * ASIC_REV: 0
+ * ASIC_VER: 2860
+ */
+#define MAC_CSR0 0x1000
+#define MAC_CSR0_ASIC_REV FIELD32(0x0000ffff)
+#define MAC_CSR0_ASIC_VER FIELD32(0xffff0000)
+
+/*
+ * MAC_SYS_CTRL:
+ */
+#define MAC_SYS_CTRL 0x1004
+#define MAC_SYS_CTRL_RESET_CSR FIELD32(0x00000001)
+#define MAC_SYS_CTRL_RESET_BBP FIELD32(0x00000002)
+#define MAC_SYS_CTRL_ENABLE_TX FIELD32(0x00000004)
+#define MAC_SYS_CTRL_ENABLE_RX FIELD32(0x00000008)
+#define MAC_SYS_CTRL_CONTINUOUS_TX FIELD32(0x00000010)
+#define MAC_SYS_CTRL_LOOPBACK FIELD32(0x00000020)
+#define MAC_SYS_CTRL_WLAN_HALT FIELD32(0x00000040)
+#define MAC_SYS_CTRL_RX_TIMESTAMP FIELD32(0x00000080)
+
+/*
+ * MAC_ADDR_DW0: STA MAC register 0
+ */
+#define MAC_ADDR_DW0 0x1008
+#define MAC_ADDR_DW0_BYTE0 FIELD32(0x000000ff)
+#define MAC_ADDR_DW0_BYTE1 FIELD32(0x0000ff00)
+#define MAC_ADDR_DW0_BYTE2 FIELD32(0x00ff0000)
+#define MAC_ADDR_DW0_BYTE3 FIELD32(0xff000000)
+
+/*
+ * MAC_ADDR_DW1: STA MAC register 1
+ * UNICAST_TO_ME_MASK:
+ * Used to mask off bits from byte 5 of the MAC address
+ * to determine the UNICAST_TO_ME bit for RX frames.
+ * The full mask is complemented by BSS_ID_MASK:
+ * MASK = BSS_ID_MASK & UNICAST_TO_ME_MASK
+ */
+#define MAC_ADDR_DW1 0x100c
+#define MAC_ADDR_DW1_BYTE4 FIELD32(0x000000ff)
+#define MAC_ADDR_DW1_BYTE5 FIELD32(0x0000ff00)
+#define MAC_ADDR_DW1_UNICAST_TO_ME_MASK FIELD32(0x00ff0000)
+
+/*
+ * MAC_BSSID_DW0: BSSID register 0
+ */
+#define MAC_BSSID_DW0 0x1010
+#define MAC_BSSID_DW0_BYTE0 FIELD32(0x000000ff)
+#define MAC_BSSID_DW0_BYTE1 FIELD32(0x0000ff00)
+#define MAC_BSSID_DW0_BYTE2 FIELD32(0x00ff0000)
+#define MAC_BSSID_DW0_BYTE3 FIELD32(0xff000000)
+
+/*
+ * MAC_BSSID_DW1: BSSID register 1
+ * BSS_ID_MASK:
+ * 0: 1-BSSID mode (BSS index = 0)
+ * 1: 2-BSSID mode (BSS index: Byte5, bit 0)
+ * 2: 4-BSSID mode (BSS index: byte5, bit 0 - 1)
+ * 3: 8-BSSID mode (BSS index: byte5, bit 0 - 2)
+ * This mask is used to mask off bits 0, 1 and 2 of byte 5 of the
+ * BSSID. This will make sure that those bits will be ignored
+ * when determining the MY_BSS of RX frames.
+ */
+#define MAC_BSSID_DW1 0x1014
+#define MAC_BSSID_DW1_BYTE4 FIELD32(0x000000ff)
+#define MAC_BSSID_DW1_BYTE5 FIELD32(0x0000ff00)
+#define MAC_BSSID_DW1_BSS_ID_MASK FIELD32(0x00030000)
+#define MAC_BSSID_DW1_BSS_BCN_NUM FIELD32(0x001c0000)
+
+/*
+ * MAX_LEN_CFG: Maximum frame length register.
+ * MAX_MPDU: rt2860b max 16k bytes
+ * MAX_PSDU: Maximum PSDU length
+ * (power factor) 0:2^13, 1:2^14, 2:2^15, 3:2^16
+ */
+#define MAX_LEN_CFG 0x1018
+#define MAX_LEN_CFG_MAX_MPDU FIELD32(0x00000fff)
+#define MAX_LEN_CFG_MAX_PSDU FIELD32(0x00003000)
+#define MAX_LEN_CFG_MIN_PSDU FIELD32(0x0000c000)
+#define MAX_LEN_CFG_MIN_MPDU FIELD32(0x000f0000)
+
+/*
+ * BBP_CSR_CFG: BBP serial control register
+ * VALUE: Register value to program into BBP
+ * REG_NUM: Selected BBP register
+ * READ_CONTROL: 0 write BBP, 1 read BBP
+ * BUSY: ASIC is busy executing BBP commands
+ * BBP_PAR_DUR: 0 4 MAC clocks, 1 8 MAC clocks
+ * BBP_RW_MODE: 0 serial, 1 paralell
+ */
+#define BBP_CSR_CFG 0x101c
+#define BBP_CSR_CFG_VALUE FIELD32(0x000000ff)
+#define BBP_CSR_CFG_REGNUM FIELD32(0x0000ff00)
+#define BBP_CSR_CFG_READ_CONTROL FIELD32(0x00010000)
+#define BBP_CSR_CFG_BUSY FIELD32(0x00020000)
+#define BBP_CSR_CFG_BBP_PAR_DUR FIELD32(0x00040000)
+#define BBP_CSR_CFG_BBP_RW_MODE FIELD32(0x00080000)
+
+/*
+ * RF_CSR_CFG0: RF control register
+ * REGID_AND_VALUE: Register value to program into RF
+ * BITWIDTH: Selected RF register
+ * STANDBYMODE: 0 high when standby, 1 low when standby
+ * SEL: 0 RF_LE0 activate, 1 RF_LE1 activate
+ * BUSY: ASIC is busy executing RF commands
+ */
+#define RF_CSR_CFG0 0x1020
+#define RF_CSR_CFG0_REGID_AND_VALUE FIELD32(0x00ffffff)
+#define RF_CSR_CFG0_BITWIDTH FIELD32(0x1f000000)
+#define RF_CSR_CFG0_REG_VALUE_BW FIELD32(0x1fffffff)
+#define RF_CSR_CFG0_STANDBYMODE FIELD32(0x20000000)
+#define RF_CSR_CFG0_SEL FIELD32(0x40000000)
+#define RF_CSR_CFG0_BUSY FIELD32(0x80000000)
+
+/*
+ * RF_CSR_CFG1: RF control register
+ * REGID_AND_VALUE: Register value to program into RF
+ * RFGAP: Gap between BB_CONTROL_RF and RF_LE
+ * 0: 3 system clock cycle (37.5usec)
+ * 1: 5 system clock cycle (62.5usec)
+ */
+#define RF_CSR_CFG1 0x1024
+#define RF_CSR_CFG1_REGID_AND_VALUE FIELD32(0x00ffffff)
+#define RF_CSR_CFG1_RFGAP FIELD32(0x1f000000)
+
+/*
+ * RF_CSR_CFG2: RF control register
+ * VALUE: Register value to program into RF
+ * RFGAP: Gap between BB_CONTROL_RF and RF_LE
+ * 0: 3 system clock cycle (37.5usec)
+ * 1: 5 system clock cycle (62.5usec)
+ */
+#define RF_CSR_CFG2 0x1028
+#define RF_CSR_CFG2_VALUE FIELD32(0x00ffffff)
+
+/*
+ * LED_CFG: LED control
+ * color LED's:
+ * 0: off
+ * 1: blinking upon TX2
+ * 2: periodic slow blinking
+ * 3: always on
+ * LED polarity:
+ * 0: active low
+ * 1: active high
+ */
+#define LED_CFG 0x102c
+#define LED_CFG_ON_PERIOD FIELD32(0x000000ff)
+#define LED_CFG_OFF_PERIOD FIELD32(0x0000ff00)
+#define LED_CFG_SLOW_BLINK_PERIOD FIELD32(0x003f0000)
+#define LED_CFG_R_LED_MODE FIELD32(0x03000000)
+#define LED_CFG_G_LED_MODE FIELD32(0x0c000000)
+#define LED_CFG_Y_LED_MODE FIELD32(0x30000000)
+#define LED_CFG_LED_POLAR FIELD32(0x40000000)
+
+/*
+ * 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
+ * OFDM_XIFS_TIME: unit 1us. Applied after OFDM RX
+ * when MAC doesn't reference BBP signal BBRXEND
+ * EIFS: unit 1us
+ * BB_RXEND_ENABLE: reference RXEND signal to begin XIFS defer
+ *
+ */
+#define XIFS_TIME_CFG 0x1100
+#define XIFS_TIME_CFG_CCKM_SIFS_TIME FIELD32(0x000000ff)
+#define XIFS_TIME_CFG_OFDM_SIFS_TIME FIELD32(0x0000ff00)
+#define XIFS_TIME_CFG_OFDM_XIFS_TIME FIELD32(0x000f0000)
+#define XIFS_TIME_CFG_EIFS FIELD32(0x1ff00000)
+#define XIFS_TIME_CFG_BB_RXEND_ENABLE FIELD32(0x20000000)
+
+/*
+ * BKOFF_SLOT_CFG:
+ */
+#define BKOFF_SLOT_CFG 0x1104
+#define BKOFF_SLOT_CFG_SLOT_TIME FIELD32(0x000000ff)
+#define BKOFF_SLOT_CFG_CC_DELAY_TIME FIELD32(0x0000ff00)
+
+/*
+ * NAV_TIME_CFG:
+ */
+#define NAV_TIME_CFG 0x1108
+#define NAV_TIME_CFG_SIFS FIELD32(0x000000ff)
+#define NAV_TIME_CFG_SLOT_TIME FIELD32(0x0000ff00)
+#define NAV_TIME_CFG_EIFS FIELD32(0x01ff0000)
+#define NAV_TIME_ZERO_SIFS FIELD32(0x02000000)
+
+/*
+ * CH_TIME_CFG: count as channel busy
+ */
+#define CH_TIME_CFG 0x110c
+
+/*
+ * PBF_LIFE_TIMER: TX/RX MPDU timestamp timer (free run) Unit: 1us
+ */
+#define PBF_LIFE_TIMER 0x1110
+
+/*
+ * BCN_TIME_CFG:
+ * BEACON_INTERVAL: in unit of 1/16 TU
+ * TSF_TICKING: Enable TSF auto counting
+ * TSF_SYNC: Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode
+ * BEACON_GEN: Enable beacon generator
+ */
+#define BCN_TIME_CFG 0x1114
+#define BCN_TIME_CFG_BEACON_INTERVAL FIELD32(0x0000ffff)
+#define BCN_TIME_CFG_TSF_TICKING FIELD32(0x00010000)
+#define BCN_TIME_CFG_TSF_SYNC FIELD32(0x00060000)
+#define BCN_TIME_CFG_TBTT_ENABLE FIELD32(0x00080000)
+#define BCN_TIME_CFG_BEACON_GEN FIELD32(0x00100000)
+#define BCN_TIME_CFG_TX_TIME_COMPENSATE FIELD32(0xf0000000)
+
+/*
+ * TBTT_SYNC_CFG:
+ */
+#define TBTT_SYNC_CFG 0x1118
+
+/*
+ * TSF_TIMER_DW0: Local lsb TSF timer, read-only
+ */
+#define TSF_TIMER_DW0 0x111c
+#define TSF_TIMER_DW0_LOW_WORD FIELD32(0xffffffff)
+
+/*
+ * TSF_TIMER_DW1: Local msb TSF timer, read-only
+ */
+#define TSF_TIMER_DW1 0x1120
+#define TSF_TIMER_DW1_HIGH_WORD FIELD32(0xffffffff)
+
+/*
+ * TBTT_TIMER: TImer remains till next TBTT, read-only
+ */
+#define TBTT_TIMER 0x1124
+
+/*
+ * INT_TIMER_CFG:
+ */
+#define INT_TIMER_CFG 0x1128
+
+/*
+ * INT_TIMER_EN: GP-timer and pre-tbtt Int enable
+ */
+#define INT_TIMER_EN 0x112c
+
+/*
+ * CH_IDLE_STA: channel idle time
+ */
+#define CH_IDLE_STA 0x1130
+
+/*
+ * CH_BUSY_STA: channel busy time
+ */
+#define CH_BUSY_STA 0x1134
+
+/*
+ * 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.
+ */
+#define MAC_STATUS_CFG 0x1200
+#define MAC_STATUS_CFG_BBP_RF_BUSY FIELD32(0x00000003)
+
+/*
+ * PWR_PIN_CFG:
+ */
+#define PWR_PIN_CFG 0x1204
+
+/*
+ * AUTOWAKEUP_CFG: Manual power control / status register
+ * TBCN_BEFORE_WAKE: ForceWake has high privilege than PutToSleep when both set
+ * AUTOWAKE: 0:sleep, 1:awake
+ */
+#define AUTOWAKEUP_CFG 0x1208
+#define AUTOWAKEUP_CFG_AUTO_LEAD_TIME FIELD32(0x000000ff)
+#define AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE FIELD32(0x00007f00)
+#define AUTOWAKEUP_CFG_AUTOWAKE FIELD32(0x00008000)
+
+/*
+ * EDCA_AC0_CFG:
+ */
+#define EDCA_AC0_CFG 0x1300
+#define EDCA_AC0_CFG_TX_OP FIELD32(0x000000ff)
+#define EDCA_AC0_CFG_AIFSN FIELD32(0x00000f00)
+#define EDCA_AC0_CFG_CWMIN FIELD32(0x0000f000)
+#define EDCA_AC0_CFG_CWMAX FIELD32(0x000f0000)
+
+/*
+ * EDCA_AC1_CFG:
+ */
+#define EDCA_AC1_CFG 0x1304
+#define EDCA_AC1_CFG_TX_OP FIELD32(0x000000ff)
+#define EDCA_AC1_CFG_AIFSN FIELD32(0x00000f00)
+#define EDCA_AC1_CFG_CWMIN FIELD32(0x0000f000)
+#define EDCA_AC1_CFG_CWMAX FIELD32(0x000f0000)
+
+/*
+ * EDCA_AC2_CFG:
+ */
+#define EDCA_AC2_CFG 0x1308
+#define EDCA_AC2_CFG_TX_OP FIELD32(0x000000ff)
+#define EDCA_AC2_CFG_AIFSN FIELD32(0x00000f00)
+#define EDCA_AC2_CFG_CWMIN FIELD32(0x0000f000)
+#define EDCA_AC2_CFG_CWMAX FIELD32(0x000f0000)
+
+/*
+ * EDCA_AC3_CFG:
+ */
+#define EDCA_AC3_CFG 0x130c
+#define EDCA_AC3_CFG_TX_OP FIELD32(0x000000ff)
+#define EDCA_AC3_CFG_AIFSN FIELD32(0x00000f00)
+#define EDCA_AC3_CFG_CWMIN FIELD32(0x0000f000)
+#define EDCA_AC3_CFG_CWMAX FIELD32(0x000f0000)
+
+/*
+ * EDCA_TID_AC_MAP:
+ */
+#define EDCA_TID_AC_MAP 0x1310
+
+/*
+ * TX_PWR_CFG_0:
+ */
+#define TX_PWR_CFG_0 0x1314
+#define TX_PWR_CFG_0_1MBS FIELD32(0x0000000f)
+#define TX_PWR_CFG_0_2MBS FIELD32(0x000000f0)
+#define TX_PWR_CFG_0_55MBS FIELD32(0x00000f00)
+#define TX_PWR_CFG_0_11MBS FIELD32(0x0000f000)
+#define TX_PWR_CFG_0_6MBS FIELD32(0x000f0000)
+#define TX_PWR_CFG_0_9MBS FIELD32(0x00f00000)
+#define TX_PWR_CFG_0_12MBS FIELD32(0x0f000000)
+#define TX_PWR_CFG_0_18MBS FIELD32(0xf0000000)
+
+/*
+ * TX_PWR_CFG_1:
+ */
+#define TX_PWR_CFG_1 0x1318
+#define TX_PWR_CFG_1_24MBS FIELD32(0x0000000f)
+#define TX_PWR_CFG_1_36MBS FIELD32(0x000000f0)
+#define TX_PWR_CFG_1_48MBS FIELD32(0x00000f00)
+#define TX_PWR_CFG_1_54MBS FIELD32(0x0000f000)
+#define TX_PWR_CFG_1_MCS0 FIELD32(0x000f0000)
+#define TX_PWR_CFG_1_MCS1 FIELD32(0x00f00000)
+#define TX_PWR_CFG_1_MCS2 FIELD32(0x0f000000)
+#define TX_PWR_CFG_1_MCS3 FIELD32(0xf0000000)
+
+/*
+ * TX_PWR_CFG_2:
+ */
+#define TX_PWR_CFG_2 0x131c
+#define TX_PWR_CFG_2_MCS4 FIELD32(0x0000000f)
+#define TX_PWR_CFG_2_MCS5 FIELD32(0x000000f0)
+#define TX_PWR_CFG_2_MCS6 FIELD32(0x00000f00)
+#define TX_PWR_CFG_2_MCS7 FIELD32(0x0000f000)
+#define TX_PWR_CFG_2_MCS8 FIELD32(0x000f0000)
+#define TX_PWR_CFG_2_MCS9 FIELD32(0x00f00000)
+#define TX_PWR_CFG_2_MCS10 FIELD32(0x0f000000)
+#define TX_PWR_CFG_2_MCS11 FIELD32(0xf0000000)
+
+/*
+ * TX_PWR_CFG_3:
+ */
+#define TX_PWR_CFG_3 0x1320
+#define TX_PWR_CFG_3_MCS12 FIELD32(0x0000000f)
+#define TX_PWR_CFG_3_MCS13 FIELD32(0x000000f0)
+#define TX_PWR_CFG_3_MCS14 FIELD32(0x00000f00)
+#define TX_PWR_CFG_3_MCS15 FIELD32(0x0000f000)
+#define TX_PWR_CFG_3_UKNOWN1 FIELD32(0x000f0000)
+#define TX_PWR_CFG_3_UKNOWN2 FIELD32(0x00f00000)
+#define TX_PWR_CFG_3_UKNOWN3 FIELD32(0x0f000000)
+#define TX_PWR_CFG_3_UKNOWN4 FIELD32(0xf0000000)
+
+/*
+ * TX_PWR_CFG_4:
+ */
+#define TX_PWR_CFG_4 0x1324
+#define TX_PWR_CFG_4_UKNOWN5 FIELD32(0x0000000f)
+#define TX_PWR_CFG_4_UKNOWN6 FIELD32(0x000000f0)
+#define TX_PWR_CFG_4_UKNOWN7 FIELD32(0x00000f00)
+#define TX_PWR_CFG_4_UKNOWN8 FIELD32(0x0000f000)
+
+/*
+ * TX_PIN_CFG:
+ */
+#define TX_PIN_CFG 0x1328
+#define TX_PIN_CFG_PA_PE_A0_EN FIELD32(0x00000001)
+#define TX_PIN_CFG_PA_PE_G0_EN FIELD32(0x00000002)
+#define TX_PIN_CFG_PA_PE_A1_EN FIELD32(0x00000004)
+#define TX_PIN_CFG_PA_PE_G1_EN FIELD32(0x00000008)
+#define TX_PIN_CFG_PA_PE_A0_POL FIELD32(0x00000010)
+#define TX_PIN_CFG_PA_PE_G0_POL FIELD32(0x00000020)
+#define TX_PIN_CFG_PA_PE_A1_POL FIELD32(0x00000040)
+#define TX_PIN_CFG_PA_PE_G1_POL FIELD32(0x00000080)
+#define TX_PIN_CFG_LNA_PE_A0_EN FIELD32(0x00000100)
+#define TX_PIN_CFG_LNA_PE_G0_EN FIELD32(0x00000200)
+#define TX_PIN_CFG_LNA_PE_A1_EN FIELD32(0x00000400)
+#define TX_PIN_CFG_LNA_PE_G1_EN FIELD32(0x00000800)
+#define TX_PIN_CFG_LNA_PE_A0_POL FIELD32(0x00001000)
+#define TX_PIN_CFG_LNA_PE_G0_POL FIELD32(0x00002000)
+#define TX_PIN_CFG_LNA_PE_A1_POL FIELD32(0x00004000)
+#define TX_PIN_CFG_LNA_PE_G1_POL FIELD32(0x00008000)
+#define TX_PIN_CFG_RFTR_EN FIELD32(0x00010000)
+#define TX_PIN_CFG_RFTR_POL FIELD32(0x00020000)
+#define TX_PIN_CFG_TRSW_EN FIELD32(0x00040000)
+#define TX_PIN_CFG_TRSW_POL FIELD32(0x00080000)
+
+/*
+ * TX_BAND_CFG: 0x1 use upper 20MHz, 0x0 use lower 20MHz
+ */
+#define TX_BAND_CFG 0x132c
+#define TX_BAND_CFG_HT40_PLUS FIELD32(0x00000001)
+#define TX_BAND_CFG_A FIELD32(0x00000002)
+#define TX_BAND_CFG_BG FIELD32(0x00000004)
+
+/*
+ * TX_SW_CFG0:
+ */
+#define TX_SW_CFG0 0x1330
+
+/*
+ * TX_SW_CFG1:
+ */
+#define TX_SW_CFG1 0x1334
+
+/*
+ * TX_SW_CFG2:
+ */
+#define TX_SW_CFG2 0x1338
+
+/*
+ * TXOP_THRES_CFG:
+ */
+#define TXOP_THRES_CFG 0x133c
+
+/*
+ * TXOP_CTRL_CFG:
+ */
+#define TXOP_CTRL_CFG 0x1340
+
+/*
+ * TX_RTS_CFG:
+ * RTS_THRES: unit:byte
+ * RTS_FBK_EN: enable rts rate fallback
+ */
+#define TX_RTS_CFG 0x1344
+#define TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT FIELD32(0x000000ff)
+#define TX_RTS_CFG_RTS_THRES FIELD32(0x00ffff00)
+#define TX_RTS_CFG_RTS_FBK_EN FIELD32(0x01000000)
+
+/*
+ * TX_TIMEOUT_CFG:
+ * MPDU_LIFETIME: expiration time = 2^(9+MPDU LIFE TIME) us
+ * RX_ACK_TIMEOUT: unit:slot. Used for TX procedure
+ * TX_OP_TIMEOUT: TXOP timeout value for TXOP truncation.
+ * it is recommended that:
+ * (SLOT_TIME) > (TX_OP_TIMEOUT) > (RX_ACK_TIMEOUT)
+ */
+#define TX_TIMEOUT_CFG 0x1348
+#define TX_TIMEOUT_CFG_MPDU_LIFETIME FIELD32(0x000000f0)
+#define TX_TIMEOUT_CFG_RX_ACK_TIMEOUT FIELD32(0x0000ff00)
+#define TX_TIMEOUT_CFG_TX_OP_TIMEOUT FIELD32(0x00ff0000)
+
+/*
+ * TX_RTY_CFG:
+ * SHORT_RTY_LIMIT: short retry limit
+ * LONG_RTY_LIMIT: long retry limit
+ * LONG_RTY_THRE: Long retry threshoold
+ * NON_AGG_RTY_MODE: Non-Aggregate MPDU retry mode
+ * 0:expired by retry limit, 1: expired by mpdu life timer
+ * AGG_RTY_MODE: Aggregate MPDU retry mode
+ * 0:expired by retry limit, 1: expired by mpdu life timer
+ * TX_AUTO_FB_ENABLE: Tx retry PHY rate auto fallback enable
+ */
+#define TX_RTY_CFG 0x134c
+#define TX_RTY_CFG_SHORT_RTY_LIMIT FIELD32(0x000000ff)
+#define TX_RTY_CFG_LONG_RTY_LIMIT FIELD32(0x0000ff00)
+#define TX_RTY_CFG_LONG_RTY_THRE FIELD32(0x0fff0000)
+#define TX_RTY_CFG_NON_AGG_RTY_MODE FIELD32(0x10000000)
+#define TX_RTY_CFG_AGG_RTY_MODE FIELD32(0x20000000)
+#define TX_RTY_CFG_TX_AUTO_FB_ENABLE FIELD32(0x40000000)
+
+/*
+ * TX_LINK_CFG:
+ * REMOTE_MFB_LIFETIME: remote MFB life time. unit: 32us
+ * MFB_ENABLE: TX apply remote MFB 1:enable
+ * REMOTE_UMFS_ENABLE: remote unsolicit MFB enable
+ * 0: not apply remote remote unsolicit (MFS=7)
+ * TX_MRQ_EN: MCS request TX enable
+ * TX_RDG_EN: RDG TX enable
+ * TX_CF_ACK_EN: Piggyback CF-ACK enable
+ * REMOTE_MFB: remote MCS feedback
+ * REMOTE_MFS: remote MCS feedback sequence number
+ */
+#define TX_LINK_CFG 0x1350
+#define TX_LINK_CFG_REMOTE_MFB_LIFETIME FIELD32(0x000000ff)
+#define TX_LINK_CFG_MFB_ENABLE FIELD32(0x00000100)
+#define TX_LINK_CFG_REMOTE_UMFS_ENABLE FIELD32(0x00000200)
+#define TX_LINK_CFG_TX_MRQ_EN FIELD32(0x00000400)
+#define TX_LINK_CFG_TX_RDG_EN FIELD32(0x00000800)
+#define TX_LINK_CFG_TX_CF_ACK_EN FIELD32(0x00001000)
+#define TX_LINK_CFG_REMOTE_MFB FIELD32(0x00ff0000)
+#define TX_LINK_CFG_REMOTE_MFS FIELD32(0xff000000)
+
+/*
+ * HT_FBK_CFG0:
+ */
+#define HT_FBK_CFG0 0x1354
+#define HT_FBK_CFG0_HTMCS0FBK FIELD32(0x0000000f)
+#define HT_FBK_CFG0_HTMCS1FBK FIELD32(0x000000f0)
+#define HT_FBK_CFG0_HTMCS2FBK FIELD32(0x00000f00)
+#define HT_FBK_CFG0_HTMCS3FBK FIELD32(0x0000f000)
+#define HT_FBK_CFG0_HTMCS4FBK FIELD32(0x000f0000)
+#define HT_FBK_CFG0_HTMCS5FBK FIELD32(0x00f00000)
+#define HT_FBK_CFG0_HTMCS6FBK FIELD32(0x0f000000)
+#define HT_FBK_CFG0_HTMCS7FBK FIELD32(0xf0000000)
+
+/*
+ * HT_FBK_CFG1:
+ */
+#define HT_FBK_CFG1 0x1358
+#define HT_FBK_CFG1_HTMCS8FBK FIELD32(0x0000000f)
+#define HT_FBK_CFG1_HTMCS9FBK FIELD32(0x000000f0)
+#define HT_FBK_CFG1_HTMCS10FBK FIELD32(0x00000f00)
+#define HT_FBK_CFG1_HTMCS11FBK FIELD32(0x0000f000)
+#define HT_FBK_CFG1_HTMCS12FBK FIELD32(0x000f0000)
+#define HT_FBK_CFG1_HTMCS13FBK FIELD32(0x00f00000)
+#define HT_FBK_CFG1_HTMCS14FBK FIELD32(0x0f000000)
+#define HT_FBK_CFG1_HTMCS15FBK FIELD32(0xf0000000)
+
+/*
+ * LG_FBK_CFG0:
+ */
+#define LG_FBK_CFG0 0x135c
+#define LG_FBK_CFG0_OFDMMCS0FBK FIELD32(0x0000000f)
+#define LG_FBK_CFG0_OFDMMCS1FBK FIELD32(0x000000f0)
+#define LG_FBK_CFG0_OFDMMCS2FBK FIELD32(0x00000f00)
+#define LG_FBK_CFG0_OFDMMCS3FBK FIELD32(0x0000f000)
+#define LG_FBK_CFG0_OFDMMCS4FBK FIELD32(0x000f0000)
+#define LG_FBK_CFG0_OFDMMCS5FBK FIELD32(0x00f00000)
+#define LG_FBK_CFG0_OFDMMCS6FBK FIELD32(0x0f000000)
+#define LG_FBK_CFG0_OFDMMCS7FBK FIELD32(0xf0000000)
+
+/*
+ * LG_FBK_CFG1:
+ */
+#define LG_FBK_CFG1 0x1360
+#define LG_FBK_CFG0_CCKMCS0FBK FIELD32(0x0000000f)
+#define LG_FBK_CFG0_CCKMCS1FBK FIELD32(0x000000f0)
+#define LG_FBK_CFG0_CCKMCS2FBK FIELD32(0x00000f00)
+#define LG_FBK_CFG0_CCKMCS3FBK FIELD32(0x0000f000)
+
+/*
+ * CCK_PROT_CFG: CCK Protection
+ * PROTECT_RATE: Protection control frame rate for CCK TX(RTS/CTS/CFEnd)
+ * PROTECT_CTRL: Protection control frame type for CCK TX
+ * 0:none, 1:RTS/CTS, 2:CTS-to-self
+ * PROTECT_NAV: TXOP protection type for CCK TX
+ * 0:none, 1:ShortNAVprotect, 2:LongNAVProtect
+ * TX_OP_ALLOW_CCK: CCK TXOP allowance, 0:disallow
+ * TX_OP_ALLOW_OFDM: CCK TXOP allowance, 0:disallow
+ * TX_OP_ALLOW_MM20: CCK TXOP allowance, 0:disallow
+ * TX_OP_ALLOW_MM40: CCK TXOP allowance, 0:disallow
+ * TX_OP_ALLOW_GF20: CCK TXOP allowance, 0:disallow
+ * TX_OP_ALLOW_GF40: CCK TXOP allowance, 0:disallow
+ * RTS_TH_EN: RTS threshold enable on CCK TX
+ */
+#define CCK_PROT_CFG 0x1364
+#define CCK_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff)
+#define CCK_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000)
+#define CCK_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000)
+#define CCK_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000)
+#define CCK_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000)
+#define CCK_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000)
+#define CCK_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000)
+#define CCK_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000)
+#define CCK_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000)
+#define CCK_PROT_CFG_RTS_TH_EN FIELD32(0x04000000)
+
+/*
+ * OFDM_PROT_CFG: OFDM Protection
+ */
+#define OFDM_PROT_CFG 0x1368
+#define OFDM_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff)
+#define OFDM_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000)
+#define OFDM_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000)
+#define OFDM_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000)
+#define OFDM_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000)
+#define OFDM_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000)
+#define OFDM_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000)
+#define OFDM_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000)
+#define OFDM_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000)
+#define OFDM_PROT_CFG_RTS_TH_EN FIELD32(0x04000000)
+
+/*
+ * MM20_PROT_CFG: MM20 Protection
+ */
+#define MM20_PROT_CFG 0x136c
+#define MM20_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff)
+#define MM20_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000)
+#define MM20_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000)
+#define MM20_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000)
+#define MM20_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000)
+#define MM20_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000)
+#define MM20_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000)
+#define MM20_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000)
+#define MM20_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000)
+#define MM20_PROT_CFG_RTS_TH_EN FIELD32(0x04000000)
+
+/*
+ * MM40_PROT_CFG: MM40 Protection
+ */
+#define MM40_PROT_CFG 0x1370
+#define MM40_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff)
+#define MM40_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000)
+#define MM40_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000)
+#define MM40_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000)
+#define MM40_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000)
+#define MM40_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000)
+#define MM40_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000)
+#define MM40_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000)
+#define MM40_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000)
+#define MM40_PROT_CFG_RTS_TH_EN FIELD32(0x04000000)
+
+/*
+ * GF20_PROT_CFG: GF20 Protection
+ */
+#define GF20_PROT_CFG 0x1374
+#define GF20_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff)
+#define GF20_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000)
+#define GF20_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000)
+#define GF20_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000)
+#define GF20_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000)
+#define GF20_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000)
+#define GF20_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000)
+#define GF20_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000)
+#define GF20_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000)
+#define GF20_PROT_CFG_RTS_TH_EN FIELD32(0x04000000)
+
+/*
+ * GF40_PROT_CFG: GF40 Protection
+ */
+#define GF40_PROT_CFG 0x1378
+#define GF40_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff)
+#define GF40_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000)
+#define GF40_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000)
+#define GF40_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000)
+#define GF40_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000)
+#define GF40_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000)
+#define GF40_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000)
+#define GF40_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000)
+#define GF40_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000)
+#define GF40_PROT_CFG_RTS_TH_EN FIELD32(0x04000000)
+
+/*
+ * EXP_CTS_TIME:
+ */
+#define EXP_CTS_TIME 0x137c
+
+/*
+ * EXP_ACK_TIME:
+ */
+#define EXP_ACK_TIME 0x1380
+
+/*
+ * RX_FILTER_CFG: RX configuration register.
+ */
+#define RX_FILTER_CFG 0x1400
+#define RX_FILTER_CFG_DROP_CRC_ERROR FIELD32(0x00000001)
+#define RX_FILTER_CFG_DROP_PHY_ERROR FIELD32(0x00000002)
+#define RX_FILTER_CFG_DROP_NOT_TO_ME FIELD32(0x00000004)
+#define RX_FILTER_CFG_DROP_NOT_MY_BSSD FIELD32(0x00000008)
+#define RX_FILTER_CFG_DROP_VER_ERROR FIELD32(0x00000010)
+#define RX_FILTER_CFG_DROP_MULTICAST FIELD32(0x00000020)
+#define RX_FILTER_CFG_DROP_BROADCAST FIELD32(0x00000040)
+#define RX_FILTER_CFG_DROP_DUPLICATE FIELD32(0x00000080)
+#define RX_FILTER_CFG_DROP_CF_END_ACK FIELD32(0x00000100)
+#define RX_FILTER_CFG_DROP_CF_END FIELD32(0x00000200)
+#define RX_FILTER_CFG_DROP_ACK FIELD32(0x00000400)
+#define RX_FILTER_CFG_DROP_CTS FIELD32(0x00000800)
+#define RX_FILTER_CFG_DROP_RTS FIELD32(0x00001000)
+#define RX_FILTER_CFG_DROP_PSPOLL FIELD32(0x00002000)
+#define RX_FILTER_CFG_DROP_BA FIELD32(0x00004000)
+#define RX_FILTER_CFG_DROP_BAR FIELD32(0x00008000)
+#define RX_FILTER_CFG_DROP_CNTL FIELD32(0x00010000)
+
+/*
+ * AUTO_RSP_CFG:
+ * AUTORESPONDER: 0: disable, 1: enable
+ * BAC_ACK_POLICY: 0:long, 1:short preamble
+ * CTS_40_MMODE: Response CTS 40MHz duplicate mode
+ * CTS_40_MREF: Response CTS 40MHz duplicate mode
+ * AR_PREAMBLE: Auto responder preamble 0:long, 1:short preamble
+ * DUAL_CTS_EN: Power bit value in control frame
+ * ACK_CTS_PSM_BIT:Power bit value in control frame
+ */
+#define AUTO_RSP_CFG 0x1404
+#define AUTO_RSP_CFG_AUTORESPONDER FIELD32(0x00000001)
+#define AUTO_RSP_CFG_BAC_ACK_POLICY FIELD32(0x00000002)
+#define AUTO_RSP_CFG_CTS_40_MMODE FIELD32(0x00000004)
+#define AUTO_RSP_CFG_CTS_40_MREF FIELD32(0x00000008)
+#define AUTO_RSP_CFG_AR_PREAMBLE FIELD32(0x00000010)
+#define AUTO_RSP_CFG_DUAL_CTS_EN FIELD32(0x00000040)
+#define AUTO_RSP_CFG_ACK_CTS_PSM_BIT FIELD32(0x00000080)
+
+/*
+ * LEGACY_BASIC_RATE:
+ */
+#define LEGACY_BASIC_RATE 0x1408
+
+/*
+ * HT_BASIC_RATE:
+ */
+#define HT_BASIC_RATE 0x140c
+
+/*
+ * HT_CTRL_CFG:
+ */
+#define HT_CTRL_CFG 0x1410
+
+/*
+ * SIFS_COST_CFG:
+ */
+#define SIFS_COST_CFG 0x1414
+
+/*
+ * RX_PARSER_CFG:
+ * Set NAV for all received frames
+ */
+#define RX_PARSER_CFG 0x1418
+
+/*
+ * TX_SEC_CNT0:
+ */
+#define TX_SEC_CNT0 0x1500
+
+/*
+ * RX_SEC_CNT0:
+ */
+#define RX_SEC_CNT0 0x1504
+
+/*
+ * CCMP_FC_MUTE:
+ */
+#define CCMP_FC_MUTE 0x1508
+
+/*
+ * TXOP_HLDR_ADDR0:
+ */
+#define TXOP_HLDR_ADDR0 0x1600
+
+/*
+ * TXOP_HLDR_ADDR1:
+ */
+#define TXOP_HLDR_ADDR1 0x1604
+
+/*
+ * TXOP_HLDR_ET:
+ */
+#define TXOP_HLDR_ET 0x1608
+
+/*
+ * QOS_CFPOLL_RA_DW0:
+ */
+#define QOS_CFPOLL_RA_DW0 0x160c
+
+/*
+ * QOS_CFPOLL_RA_DW1:
+ */
+#define QOS_CFPOLL_RA_DW1 0x1610
+
+/*
+ * QOS_CFPOLL_QC:
+ */
+#define QOS_CFPOLL_QC 0x1614
+
+/*
+ * RX_STA_CNT0: RX PLCP error count & RX CRC error count
+ */
+#define RX_STA_CNT0 0x1700
+#define RX_STA_CNT0_CRC_ERR FIELD32(0x0000ffff)
+#define RX_STA_CNT0_PHY_ERR FIELD32(0xffff0000)
+
+/*
+ * RX_STA_CNT1: RX False CCA count & RX LONG frame count
+ */
+#define RX_STA_CNT1 0x1704
+#define RX_STA_CNT1_FALSE_CCA FIELD32(0x0000ffff)
+#define RX_STA_CNT1_PLCP_ERR FIELD32(0xffff0000)
+
+/*
+ * RX_STA_CNT2:
+ */
+#define RX_STA_CNT2 0x1708
+#define RX_STA_CNT2_RX_DUPLI_COUNT FIELD32(0x0000ffff)
+#define RX_STA_CNT2_RX_FIFO_OVERFLOW FIELD32(0xffff0000)
+
+/*
+ * TX_STA_CNT0: TX Beacon count
+ */
+#define TX_STA_CNT0 0x170c
+#define TX_STA_CNT0_TX_FAIL_COUNT FIELD32(0x0000ffff)
+#define TX_STA_CNT0_TX_BEACON_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_STA_CNT1: TX tx count
+ */
+#define TX_STA_CNT1 0x1710
+#define TX_STA_CNT1_TX_SUCCESS FIELD32(0x0000ffff)
+#define TX_STA_CNT1_TX_RETRANSMIT FIELD32(0xffff0000)
+
+/*
+ * TX_STA_CNT2: TX tx count
+ */
+#define TX_STA_CNT2 0x1714
+#define TX_STA_CNT2_TX_ZERO_LEN_COUNT FIELD32(0x0000ffff)
+#define TX_STA_CNT2_TX_UNDER_FLOW_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_STA_FIFO: TX Result for specific PID status fifo register
+ */
+#define TX_STA_FIFO 0x1718
+#define TX_STA_FIFO_VALID FIELD32(0x00000001)
+#define TX_STA_FIFO_PID_TYPE FIELD32(0x0000001e)
+#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)
+#define TX_STA_FIFO_WCID FIELD32(0x0000ff00)
+#define TX_STA_FIFO_MCS FIELD32(0x007f0000)
+#define TX_STA_FIFO_PHYMODE FIELD32(0xc0000000)
+
+/*
+ * TX_AGG_CNT: Debug counter
+ */
+#define TX_AGG_CNT 0x171c
+#define TX_AGG_CNT_NON_AGG_TX_COUNT FIELD32(0x0000ffff)
+#define TX_AGG_CNT_AGG_TX_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_AGG_CNT0:
+ */
+#define TX_AGG_CNT0 0x1720
+#define TX_AGG_CNT0_AGG_SIZE_1_COUNT FIELD32(0x0000ffff)
+#define TX_AGG_CNT0_AGG_SIZE_2_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_AGG_CNT1:
+ */
+#define TX_AGG_CNT1 0x1724
+#define TX_AGG_CNT1_AGG_SIZE_3_COUNT FIELD32(0x0000ffff)
+#define TX_AGG_CNT1_AGG_SIZE_4_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_AGG_CNT2:
+ */
+#define TX_AGG_CNT2 0x1728
+#define TX_AGG_CNT2_AGG_SIZE_5_COUNT FIELD32(0x0000ffff)
+#define TX_AGG_CNT2_AGG_SIZE_6_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_AGG_CNT3:
+ */
+#define TX_AGG_CNT3 0x172c
+#define TX_AGG_CNT3_AGG_SIZE_7_COUNT FIELD32(0x0000ffff)
+#define TX_AGG_CNT3_AGG_SIZE_8_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_AGG_CNT4:
+ */
+#define TX_AGG_CNT4 0x1730
+#define TX_AGG_CNT4_AGG_SIZE_9_COUNT FIELD32(0x0000ffff)
+#define TX_AGG_CNT4_AGG_SIZE_10_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_AGG_CNT5:
+ */
+#define TX_AGG_CNT5 0x1734
+#define TX_AGG_CNT5_AGG_SIZE_11_COUNT FIELD32(0x0000ffff)
+#define TX_AGG_CNT5_AGG_SIZE_12_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_AGG_CNT6:
+ */
+#define TX_AGG_CNT6 0x1738
+#define TX_AGG_CNT6_AGG_SIZE_13_COUNT FIELD32(0x0000ffff)
+#define TX_AGG_CNT6_AGG_SIZE_14_COUNT FIELD32(0xffff0000)
+
+/*
+ * TX_AGG_CNT7:
+ */
+#define TX_AGG_CNT7 0x173c
+#define TX_AGG_CNT7_AGG_SIZE_15_COUNT FIELD32(0x0000ffff)
+#define TX_AGG_CNT7_AGG_SIZE_16_COUNT FIELD32(0xffff0000)
+
+/*
+ * MPDU_DENSITY_CNT:
+ * TX_ZERO_DEL: TX zero length delimiter count
+ * RX_ZERO_DEL: RX zero length delimiter count
+ */
+#define MPDU_DENSITY_CNT 0x1740
+#define MPDU_DENSITY_CNT_TX_ZERO_DEL FIELD32(0x0000ffff)
+#define MPDU_DENSITY_CNT_RX_ZERO_DEL FIELD32(0xffff0000)
+
+/*
+ * Security key table memory.
+ * 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
+ * MAC_WCID_ATTRIBUTE_BASE: 4-byte * 256-entry
+ * SHARED_KEY_TABLE_BASE: 32 bytes * 32-entry
+ * SHARED_KEY_MODE_BASE: 4 bits * 32-entry
+ */
+#define MAC_WCID_BASE 0x1800
+#define PAIRWISE_KEY_TABLE_BASE 0x4000
+#define MAC_IVEIV_TABLE_BASE 0x6000
+#define MAC_WCID_ATTRIBUTE_BASE 0x6800
+#define SHARED_KEY_TABLE_BASE 0x6c00
+#define SHARED_KEY_MODE_BASE 0x7000
+
+#define MAC_WCID_ENTRY(__idx) \
+ ( MAC_WCID_BASE + ((__idx) * sizeof(struct mac_wcid_entry)) )
+#define PAIRWISE_KEY_ENTRY(__idx) \
+ ( PAIRWISE_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) )
+#define MAC_IVEIV_ENTRY(__idx) \
+ ( MAC_IVEIV_TABLE_BASE + ((__idx) & sizeof(struct mac_iveiv_entry)) )
+#define MAC_WCID_ATTR_ENTRY(__idx) \
+ ( MAC_WCID_ATTRIBUTE_BASE + ((__idx) * sizeof(u32)) )
+#define SHARED_KEY_ENTRY(__idx) \
+ ( SHARED_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) )
+#define SHARED_KEY_MODE_ENTRY(__idx) \
+ ( SHARED_KEY_MODE_BASE + ((__idx) * sizeof(u32)) )
+
+struct mac_wcid_entry {
+ u8 mac[6];
+ u8 reserved[2];
+} __attribute__ ((packed));
+
+struct hw_key_entry {
+ u8 key[16];
+ u8 tx_mic[8];
+ u8 rx_mic[8];
+} __attribute__ ((packed));
+
+struct mac_iveiv_entry {
+ u8 iv[8];
+} __attribute__ ((packed));
+
+/*
+ * MAC_WCID_ATTRIBUTE:
+ */
+#define MAC_WCID_ATTRIBUTE_KEYTAB FIELD32(0x00000001)
+#define MAC_WCID_ATTRIBUTE_CIPHER FIELD32(0x0000000e)
+#define MAC_WCID_ATTRIBUTE_BSS_IDX FIELD32(0x00000070)
+#define MAC_WCID_ATTRIBUTE_RX_WIUDF FIELD32(0x00000380)
+
+/*
+ * SHARED_KEY_MODE:
+ */
+#define SHARED_KEY_MODE_BSS0_KEY0 FIELD32(0x00000007)
+#define SHARED_KEY_MODE_BSS0_KEY1 FIELD32(0x00000070)
+#define SHARED_KEY_MODE_BSS0_KEY2 FIELD32(0x00000700)
+#define SHARED_KEY_MODE_BSS0_KEY3 FIELD32(0x00007000)
+#define SHARED_KEY_MODE_BSS1_KEY0 FIELD32(0x00070000)
+#define SHARED_KEY_MODE_BSS1_KEY1 FIELD32(0x00700000)
+#define SHARED_KEY_MODE_BSS1_KEY2 FIELD32(0x07000000)
+#define SHARED_KEY_MODE_BSS1_KEY3 FIELD32(0x70000000)
+
+/*
+ * HOST-MCU communication
+ */
+
+/*
+ * H2M_MAILBOX_CSR: Host-to-MCU Mailbox.
+ */
+#define H2M_MAILBOX_CSR 0x7010
+#define H2M_MAILBOX_CSR_ARG0 FIELD32(0x000000ff)
+#define H2M_MAILBOX_CSR_ARG1 FIELD32(0x0000ff00)
+#define H2M_MAILBOX_CSR_CMD_TOKEN FIELD32(0x00ff0000)
+#define H2M_MAILBOX_CSR_OWNER FIELD32(0xff000000)
+
+/*
+ * H2M_MAILBOX_CID:
+ */
+#define H2M_MAILBOX_CID 0x7014
+#define H2M_MAILBOX_CID_CMD0 FIELD32(0x000000ff)
+#define H2M_MAILBOX_CID_CMD1 FIELD32(0x0000ff00)
+#define H2M_MAILBOX_CID_CMD2 FIELD32(0x00ff0000)
+#define H2M_MAILBOX_CID_CMD3 FIELD32(0xff000000)
+
+/*
+ * H2M_MAILBOX_STATUS:
+ */
+#define H2M_MAILBOX_STATUS 0x701c
+
+/*
+ * H2M_INT_SRC:
+ */
+#define H2M_INT_SRC 0x7024
+
+/*
+ * H2M_BBP_AGENT:
+ */
+#define H2M_BBP_AGENT 0x7028
+
+/*
+ * MCU_LEDCS: LED control for MCU Mailbox.
+ */
+#define MCU_LEDCS_LED_MODE FIELD8(0x1f)
+#define MCU_LEDCS_POLARITY FIELD8(0x01)
+
+/*
+ * HW_CS_CTS_BASE:
+ * Carrier-sense CTS frame base address.
+ * It's where mac stores carrier-sense frame for carrier-sense function.
+ */
+#define HW_CS_CTS_BASE 0x7700
+
+/*
+ * HW_DFS_CTS_BASE:
+ * FS CTS frame base address. It's where mac stores CTS frame for DFS.
+ */
+#define HW_DFS_CTS_BASE 0x7780
+
+/*
+ * TXRX control registers - base address 0x3000
+ */
+
+/*
+ * TXRX_CSR1:
+ * rt2860b UNKNOWN reg use R/O Reg Addr 0x77d0 first..
+ */
+#define TXRX_CSR1 0x77d0
+
+/*
+ * HW_DEBUG_SETTING_BASE:
+ * since NULL frame won't be that long (256 byte)
+ * We steal 16 tail bytes to save debugging settings
+ */
+#define HW_DEBUG_SETTING_BASE 0x77f0
+#define HW_DEBUG_SETTING_BASE2 0x7770
+
+/*
+ * HW_BEACON_BASE
+ * In order to support maximum 8 MBSS and its maximum length
+ * is 512 bytes for each beacon
+ * Three section discontinue memory segments will be used.
+ * 1. The original region for BCN 0~3
+ * 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
+ *
+ * IMPORTANT NOTE: Not sure why legacy driver does this,
+ * but HW_BEACON_BASE7 is 0x0200 bytes below HW_BEACON_BASE6.
+ */
+#define HW_BEACON_BASE0 0x7800
+#define HW_BEACON_BASE1 0x7a00
+#define HW_BEACON_BASE2 0x7c00
+#define HW_BEACON_BASE3 0x7e00
+#define HW_BEACON_BASE4 0x7200
+#define HW_BEACON_BASE5 0x7400
+#define HW_BEACON_BASE6 0x5dc0
+#define HW_BEACON_BASE7 0x5bc0
+
+#define HW_BEACON_OFFSET(__index) \
+ ( ((__index) < 4) ? ( HW_BEACON_BASE0 + (__index * 0x0200) ) : \
+ (((__index) < 6) ? ( HW_BEACON_BASE4 + ((__index - 4) * 0x0200) ) : \
+ (HW_BEACON_BASE6 - ((__index - 6) * 0x0200))) )
+
+/*
+ * 8051 firmware image.
+ */
+#define FIRMWARE_RT2860 "rt2860.bin"
+#define FIRMWARE_IMAGE_BASE 0x2000
+
+/*
+ * BBP registers.
+ * The wordsize of the BBP is 8 bits.
+ */
+
+/*
+ * BBP 1: TX Antenna
+ */
+#define BBP1_TX_POWER FIELD8(0x07)
+#define BBP1_TX_ANTENNA FIELD8(0x18)
+
+/*
+ * BBP 3: RX Antenna
+ */
+#define BBP3_RX_ANTENNA FIELD8(0x18)
+#define BBP3_HT40_PLUS FIELD8(0x20)
+
+/*
+ * BBP 4: Bandwidth
+ */
+#define BBP4_TX_BF FIELD8(0x01)
+#define BBP4_BANDWIDTH FIELD8(0x18)
+
+/*
+ * RFCSR registers
+ * The wordsize of the RFCSR is 8 bits.
+ */
+
+/*
+ * RFCSR 6:
+ */
+#define RFCSR6_R FIELD8(0x03)
+
+/*
+ * RFCSR 7:
+ */
+#define RFCSR7_RF_TUNING FIELD8(0x01)
+
+/*
+ * RFCSR 12:
+ */
+#define RFCSR12_TX_POWER FIELD8(0x1f)
+
+/*
+ * RFCSR 22:
+ */
+#define RFCSR22_BASEBAND_LOOPBACK FIELD8(0x01)
+
+/*
+ * RFCSR 23:
+ */
+#define RFCSR23_FREQ_OFFSET FIELD8(0x7f)
+
+/*
+ * RFCSR 30:
+ */
+#define RFCSR30_RF_CALIBRATION FIELD8(0x80)
+
+/*
+ * RF registers
+ */
+
+/*
+ * RF 2
+ */
+#define RF2_ANTENNA_RX2 FIELD32(0x00000040)
+#define RF2_ANTENNA_TX1 FIELD32(0x00004000)
+#define RF2_ANTENNA_RX1 FIELD32(0x00020000)
+
+/*
+ * RF 3
+ */
+#define RF3_TXPOWER_G FIELD32(0x00003e00)
+#define RF3_TXPOWER_A_7DBM_BOOST FIELD32(0x00000200)
+#define RF3_TXPOWER_A FIELD32(0x00003c00)
+
+/*
+ * RF 4
+ */
+#define RF4_TXPOWER_G FIELD32(0x000007c0)
+#define RF4_TXPOWER_A_7DBM_BOOST FIELD32(0x00000040)
+#define RF4_TXPOWER_A FIELD32(0x00000780)
+#define RF4_FREQ_OFFSET FIELD32(0x001f8000)
+#define RF4_HT40 FIELD32(0x00200000)
+
+/*
+ * EEPROM content.
+ * The wordsize of the EEPROM is 16 bits.
+ */
+
+/*
+ * EEPROM Version
+ */
+#define EEPROM_VERSION 0x0001
+#define EEPROM_VERSION_FAE FIELD16(0x00ff)
+#define EEPROM_VERSION_VERSION FIELD16(0xff00)
+
+/*
+ * HW MAC address.
+ */
+#define EEPROM_MAC_ADDR_0 0x0002
+#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR_1 0x0003
+#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR_2 0x0004
+#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)
+
+/*
+ * EEPROM ANTENNA config
+ * RXPATH: 1: 1R, 2: 2R, 3: 3R
+ * TXPATH: 1: 1T, 2: 2T
+ */
+#define EEPROM_ANTENNA 0x001a
+#define EEPROM_ANTENNA_RXPATH FIELD16(0x000f)
+#define EEPROM_ANTENNA_TXPATH FIELD16(0x00f0)
+#define EEPROM_ANTENNA_RF_TYPE FIELD16(0x0f00)
+
+/*
+ * EEPROM NIC config
+ * CARDBUS_ACCEL: 0 - enable, 1 - disable
+ */
+#define EEPROM_NIC 0x001b
+#define EEPROM_NIC_HW_RADIO FIELD16(0x0001)
+#define EEPROM_NIC_DYNAMIC_TX_AGC FIELD16(0x0002)
+#define EEPROM_NIC_EXTERNAL_LNA_BG FIELD16(0x0004)
+#define EEPROM_NIC_EXTERNAL_LNA_A FIELD16(0x0008)
+#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0010)
+#define EEPROM_NIC_BW40M_SB_BG FIELD16(0x0020)
+#define EEPROM_NIC_BW40M_SB_A FIELD16(0x0040)
+#define EEPROM_NIC_WPS_PBC FIELD16(0x0080)
+#define EEPROM_NIC_BW40M_BG FIELD16(0x0100)
+#define EEPROM_NIC_BW40M_A FIELD16(0x0200)
+
+/*
+ * EEPROM frequency
+ */
+#define EEPROM_FREQ 0x001d
+#define EEPROM_FREQ_OFFSET FIELD16(0x00ff)
+#define EEPROM_FREQ_LED_MODE FIELD16(0x7f00)
+#define EEPROM_FREQ_LED_POLARITY FIELD16(0x1000)
+
+/*
+ * EEPROM LED
+ * POLARITY_RDY_G: Polarity RDY_G setting.
+ * POLARITY_RDY_A: Polarity RDY_A setting.
+ * POLARITY_ACT: Polarity ACT setting.
+ * POLARITY_GPIO_0: Polarity GPIO0 setting.
+ * POLARITY_GPIO_1: Polarity GPIO1 setting.
+ * POLARITY_GPIO_2: Polarity GPIO2 setting.
+ * POLARITY_GPIO_3: Polarity GPIO3 setting.
+ * POLARITY_GPIO_4: Polarity GPIO4 setting.
+ * LED_MODE: Led mode.
+ */
+#define EEPROM_LED1 0x001e
+#define EEPROM_LED2 0x001f
+#define EEPROM_LED3 0x0020
+#define EEPROM_LED_POLARITY_RDY_BG FIELD16(0x0001)
+#define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002)
+#define EEPROM_LED_POLARITY_ACT FIELD16(0x0004)
+#define EEPROM_LED_POLARITY_GPIO_0 FIELD16(0x0008)
+#define EEPROM_LED_POLARITY_GPIO_1 FIELD16(0x0010)
+#define EEPROM_LED_POLARITY_GPIO_2 FIELD16(0x0020)
+#define EEPROM_LED_POLARITY_GPIO_3 FIELD16(0x0040)
+#define EEPROM_LED_POLARITY_GPIO_4 FIELD16(0x0080)
+#define EEPROM_LED_LED_MODE FIELD16(0x1f00)
+
+/*
+ * EEPROM LNA
+ */
+#define EEPROM_LNA 0x0022
+#define EEPROM_LNA_BG FIELD16(0x00ff)
+#define EEPROM_LNA_A0 FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI BG offset
+ */
+#define EEPROM_RSSI_BG 0x0023
+#define EEPROM_RSSI_BG_OFFSET0 FIELD16(0x00ff)
+#define EEPROM_RSSI_BG_OFFSET1 FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI BG2 offset
+ */
+#define EEPROM_RSSI_BG2 0x0024
+#define EEPROM_RSSI_BG2_OFFSET2 FIELD16(0x00ff)
+#define EEPROM_RSSI_BG2_LNA_A1 FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI A offset
+ */
+#define EEPROM_RSSI_A 0x0025
+#define EEPROM_RSSI_A_OFFSET0 FIELD16(0x00ff)
+#define EEPROM_RSSI_A_OFFSET1 FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI A2 offset
+ */
+#define EEPROM_RSSI_A2 0x0026
+#define EEPROM_RSSI_A2_OFFSET2 FIELD16(0x00ff)
+#define EEPROM_RSSI_A2_LNA_A2 FIELD16(0xff00)
+
+/*
+ * EEPROM TXpower delta: 20MHZ AND 40 MHZ use different power.
+ * This is delta in 40MHZ.
+ * VALUE: Tx Power dalta value (MAX=4)
+ * TYPE: 1: Plus the delta value, 0: minus the delta value
+ * TXPOWER: Enable:
+ */
+#define EEPROM_TXPOWER_DELTA 0x0028
+#define EEPROM_TXPOWER_DELTA_VALUE FIELD16(0x003f)
+#define EEPROM_TXPOWER_DELTA_TYPE FIELD16(0x0040)
+#define EEPROM_TXPOWER_DELTA_TXPOWER FIELD16(0x0080)
+
+/*
+ * EEPROM TXPOWER 802.11BG
+ */
+#define EEPROM_TXPOWER_BG1 0x0029
+#define EEPROM_TXPOWER_BG2 0x0030
+#define EEPROM_TXPOWER_BG_SIZE 7
+#define EEPROM_TXPOWER_BG_1 FIELD16(0x00ff)
+#define EEPROM_TXPOWER_BG_2 FIELD16(0xff00)
+
+/*
+ * EEPROM TXPOWER 802.11A
+ */
+#define EEPROM_TXPOWER_A1 0x003c
+#define EEPROM_TXPOWER_A2 0x0053
+#define EEPROM_TXPOWER_A_SIZE 6
+#define EEPROM_TXPOWER_A_1 FIELD16(0x00ff)
+#define EEPROM_TXPOWER_A_2 FIELD16(0xff00)
+
+/*
+ * EEPROM TXpower byrate: 20MHZ power
+ */
+#define EEPROM_TXPOWER_BYRATE 0x006f
+
+/*
+ * EEPROM BBP.
+ */
+#define EEPROM_BBP_START 0x0078
+#define EEPROM_BBP_SIZE 16
+#define EEPROM_BBP_VALUE FIELD16(0x00ff)
+#define EEPROM_BBP_REG_ID FIELD16(0xff00)
+
+/*
+ * MCU mailbox commands.
+ */
+#define MCU_SLEEP 0x30
+#define MCU_WAKEUP 0x31
+#define MCU_RADIO_OFF 0x35
+#define MCU_CURRENT 0x36
+#define MCU_LED 0x50
+#define MCU_LED_STRENGTH 0x51
+#define MCU_LED_1 0x52
+#define MCU_LED_2 0x53
+#define MCU_LED_3 0x54
+#define MCU_RADAR 0x60
+#define MCU_BOOT_SIGNAL 0x72
+#define MCU_BBP_SIGNAL 0x80
+#define MCU_POWER_SAVE 0x83
+
+/*
+ * MCU mailbox tokens
+ */
+#define TOKEN_WAKUP 3
+
+/*
+ * DMA descriptor defines.
+ */
+#define TXD_DESC_SIZE ( 4 * sizeof(__le32) )
+#define TXWI_DESC_SIZE ( 4 * sizeof(__le32) )
+#define RXD_DESC_SIZE ( 4 * sizeof(__le32) )
+#define RXWI_DESC_SIZE ( 4 * sizeof(__le32) )
+
+/*
+ * TX descriptor format for TX, PRIO and Beacon Ring.
+ */
+
+/*
+ * Word0
+ */
+#define TXD_W0_SD_PTR0 FIELD32(0xffffffff)
+
+/*
+ * Word1
+ */
+#define TXD_W1_SD_LEN1 FIELD32(0x00003fff)
+#define TXD_W1_LAST_SEC1 FIELD32(0x00004000)
+#define TXD_W1_BURST FIELD32(0x00008000)
+#define TXD_W1_SD_LEN0 FIELD32(0x3fff0000)
+#define TXD_W1_LAST_SEC0 FIELD32(0x40000000)
+#define TXD_W1_DMA_DONE FIELD32(0x80000000)
+
+/*
+ * Word2
+ */
+#define TXD_W2_SD_PTR1 FIELD32(0xffffffff)
+
+/*
+ * Word3
+ * WIV: Wireless Info Valid. 1: Driver filled WI, 0: DMA needs to copy WI
+ * QSEL: Select on-chip FIFO ID for 2nd-stage output scheduler.
+ * 0:MGMT, 1:HCCA 2:EDCA
+ */
+#define TXD_W3_WIV FIELD32(0x01000000)
+#define TXD_W3_QSEL FIELD32(0x06000000)
+#define TXD_W3_TCO FIELD32(0x20000000)
+#define TXD_W3_UCO FIELD32(0x40000000)
+#define TXD_W3_ICO FIELD32(0x80000000)
+
+/*
+ * TX WI structure
+ */
+
+/*
+ * Word0
+ * 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
+ * STBC: 1: STBC support MCS =0-7, 2,3 : RESERVED
+ */
+#define TXWI_W0_FRAG FIELD32(0x00000001)
+#define TXWI_W0_MIMO_PS FIELD32(0x00000002)
+#define TXWI_W0_CF_ACK FIELD32(0x00000004)
+#define TXWI_W0_TS FIELD32(0x00000008)
+#define TXWI_W0_AMPDU FIELD32(0x00000010)
+#define TXWI_W0_MPDU_DENSITY FIELD32(0x000000e0)
+#define TXWI_W0_TX_OP FIELD32(0x00000300)
+#define TXWI_W0_MCS FIELD32(0x007f0000)
+#define TXWI_W0_BW FIELD32(0x00800000)
+#define TXWI_W0_SHORT_GI FIELD32(0x01000000)
+#define TXWI_W0_STBC FIELD32(0x06000000)
+#define TXWI_W0_IFS FIELD32(0x08000000)
+#define TXWI_W0_PHYMODE FIELD32(0xc0000000)
+
+/*
+ * Word1
+ */
+#define TXWI_W1_ACK FIELD32(0x00000001)
+#define TXWI_W1_NSEQ FIELD32(0x00000002)
+#define TXWI_W1_BW_WIN_SIZE FIELD32(0x000000fc)
+#define TXWI_W1_WIRELESS_CLI_ID FIELD32(0x0000ff00)
+#define TXWI_W1_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000)
+#define TXWI_W1_PACKETID FIELD32(0xf0000000)
+
+/*
+ * Word2
+ */
+#define TXWI_W2_IV FIELD32(0xffffffff)
+
+/*
+ * Word3
+ */
+#define TXWI_W3_EIV FIELD32(0xffffffff)
+
+/*
+ * RX descriptor format for RX Ring.
+ */
+
+/*
+ * Word0
+ */
+#define RXD_W0_SDP0 FIELD32(0xffffffff)
+
+/*
+ * Word1
+ */
+#define RXD_W1_SDL1 FIELD32(0x00003fff)
+#define RXD_W1_SDL0 FIELD32(0x3fff0000)
+#define RXD_W1_LS0 FIELD32(0x40000000)
+#define RXD_W1_DMA_DONE FIELD32(0x80000000)
+
+/*
+ * Word2
+ */
+#define RXD_W2_SDP1 FIELD32(0xffffffff)
+
+/*
+ * Word3
+ * AMSDU: RX with 802.3 header, not 802.11 header.
+ * DECRYPTED: This frame is being decrypted.
+ */
+#define RXD_W3_BA FIELD32(0x00000001)
+#define RXD_W3_DATA FIELD32(0x00000002)
+#define RXD_W3_NULLDATA FIELD32(0x00000004)
+#define RXD_W3_FRAG FIELD32(0x00000008)
+#define RXD_W3_UNICAST_TO_ME FIELD32(0x00000010)
+#define RXD_W3_MULTICAST FIELD32(0x00000020)
+#define RXD_W3_BROADCAST FIELD32(0x00000040)
+#define RXD_W3_MY_BSS FIELD32(0x00000080)
+#define RXD_W3_CRC_ERROR FIELD32(0x00000100)
+#define RXD_W3_CIPHER_ERROR FIELD32(0x00000600)
+#define RXD_W3_AMSDU FIELD32(0x00000800)
+#define RXD_W3_HTC FIELD32(0x00001000)
+#define RXD_W3_RSSI FIELD32(0x00002000)
+#define RXD_W3_L2PAD FIELD32(0x00004000)
+#define RXD_W3_AMPDU FIELD32(0x00008000)
+#define RXD_W3_DECRYPTED FIELD32(0x00010000)
+#define RXD_W3_PLCP_SIGNAL FIELD32(0x00020000)
+#define RXD_W3_PLCP_RSSI FIELD32(0x00040000)
+
+/*
+ * RX WI structure
+ */
+
+/*
+ * Word0
+ */
+#define RXWI_W0_WIRELESS_CLI_ID FIELD32(0x000000ff)
+#define RXWI_W0_KEY_INDEX FIELD32(0x00000300)
+#define RXWI_W0_BSSID FIELD32(0x00001c00)
+#define RXWI_W0_UDF FIELD32(0x0000e000)
+#define RXWI_W0_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000)
+#define RXWI_W0_TID FIELD32(0xf0000000)
+
+/*
+ * Word1
+ */
+#define RXWI_W1_FRAG FIELD32(0x0000000f)
+#define RXWI_W1_SEQUENCE FIELD32(0x0000fff0)
+#define RXWI_W1_MCS FIELD32(0x007f0000)
+#define RXWI_W1_BW FIELD32(0x00800000)
+#define RXWI_W1_SHORT_GI FIELD32(0x01000000)
+#define RXWI_W1_STBC FIELD32(0x06000000)
+#define RXWI_W1_PHYMODE FIELD32(0xc0000000)
+
+/*
+ * Word2
+ */
+#define RXWI_W2_RSSI0 FIELD32(0x000000ff)
+#define RXWI_W2_RSSI1 FIELD32(0x0000ff00)
+#define RXWI_W2_RSSI2 FIELD32(0x00ff0000)
+
+/*
+ * Word3
+ */
+#define RXWI_W3_SNR0 FIELD32(0x000000ff)
+#define RXWI_W3_SNR1 FIELD32(0x0000ff00)
+
+/*
+ * Macros for converting txpower from EEPROM to mac80211 value
+ * and from mac80211 value to register value.
+ */
+#define MIN_G_TXPOWER 0
+#define MIN_A_TXPOWER -7
+#define MAX_G_TXPOWER 31
+#define MAX_A_TXPOWER 15
+#define DEFAULT_TXPOWER 5
+
+#define TXPOWER_G_FROM_DEV(__txpower) \
+ ((__txpower) > MAX_G_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
+
+#define TXPOWER_G_TO_DEV(__txpower) \
+ clamp_t(char, __txpower, MIN_G_TXPOWER, MAX_G_TXPOWER)
+
+#define TXPOWER_A_FROM_DEV(__txpower) \
+ ((__txpower) > MAX_A_TXPOWER) ? DEFAULT_TXPOWER : (__txpower)
+
+#define TXPOWER_A_TO_DEV(__txpower) \
+ clamp_t(char, __txpower, MIN_A_TXPOWER, MAX_A_TXPOWER)
+
+#endif /* RT2800PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index a084077a1c61..68b43e3c5daf 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -1257,7 +1257,7 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
unsigned int i;
/*
- * Wait untill BBP and RF are ready.
+ * Wait until BBP and RF are ready.
*/
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
rt2x00usb_register_read(rt2x00dev, MAC_CSR0, &reg);
@@ -1994,7 +1994,7 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size);
rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
- (skbdesc->entry->entry_idx + 1) : 0xff);
+ txdesc->key_idx : 0xff);
rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
skb->len - txdesc->l2pad);
rt2x00_set_field32(&word, TXWI_W1_PACKETID,
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 27bc6b7fbfde..196de8ab8153 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -158,6 +158,13 @@ struct rt2x00_chip {
#define RT2561 0x0302
#define RT2661 0x0401
#define RT2571 0x1300
+#define RT2860 0x0601 /* 2.4GHz PCI/CB */
+#define RT2860D 0x0681 /* 2.4GHz, 5GHz PCI/CB */
+#define RT2890 0x0701 /* 2.4GHz PCIe */
+#define RT2890D 0x0781 /* 2.4GHz, 5GHz PCIe */
+#define RT2880 0x2880 /* WSOC */
+#define RT3052 0x3052 /* WSOC */
+#define RT3090 0x3090 /* 2.4GHz PCIe */
#define RT2870 0x1600
u16 rf;
diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.c b/drivers/net/wireless/rt2x00/rt2x00soc.c
new file mode 100644
index 000000000000..539568c48953
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00soc.c
@@ -0,0 +1,159 @@
+/*
+ Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00soc
+ Abstract: rt2x00 generic soc device routines.
+ */
+
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "rt2x00.h"
+#include "rt2x00soc.h"
+
+static void rt2x00soc_free_reg(struct rt2x00_dev *rt2x00dev)
+{
+ kfree(rt2x00dev->rf);
+ rt2x00dev->rf = NULL;
+
+ kfree(rt2x00dev->eeprom);
+ rt2x00dev->eeprom = NULL;
+}
+
+static int rt2x00soc_alloc_reg(struct rt2x00_dev *rt2x00dev)
+{
+ struct platform_device *pdev = to_platform_device(rt2x00dev->dev);
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ rt2x00dev->csr.base = (void __iomem *)KSEG1ADDR(res->start);
+ if (!rt2x00dev->csr.base)
+ goto exit;
+
+ rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
+ if (!rt2x00dev->eeprom)
+ goto exit;
+
+ rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
+ if (!rt2x00dev->rf)
+ goto exit;
+
+ return 0;
+
+exit:
+ ERROR_PROBE("Failed to allocate registers.\n");
+ rt2x00soc_free_reg(rt2x00dev);
+
+ return -ENOMEM;
+}
+
+int rt2x00soc_probe(struct platform_device *pdev,
+ const unsigned short chipset,
+ const struct rt2x00_ops *ops)
+{
+ struct ieee80211_hw *hw;
+ struct rt2x00_dev *rt2x00dev;
+ int retval;
+
+ hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
+ if (!hw) {
+ ERROR_PROBE("Failed to allocate hardware.\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, hw);
+
+ rt2x00dev = hw->priv;
+ rt2x00dev->dev = &pdev->dev;
+ rt2x00dev->ops = ops;
+ rt2x00dev->hw = hw;
+ rt2x00dev->irq = platform_get_irq(pdev, 0);
+ rt2x00dev->name = pdev->dev.driver->name;
+
+ rt2x00_set_chip_rt(rt2x00dev, chipset);
+
+ retval = rt2x00soc_alloc_reg(rt2x00dev);
+ if (retval)
+ goto exit_free_device;
+
+ retval = rt2x00lib_probe_dev(rt2x00dev);
+ if (retval)
+ goto exit_free_reg;
+
+ return 0;
+
+exit_free_reg:
+ rt2x00soc_free_reg(rt2x00dev);
+
+exit_free_device:
+ ieee80211_free_hw(hw);
+
+ return retval;
+}
+
+int rt2x00soc_remove(struct platform_device *pdev)
+{
+ struct ieee80211_hw *hw = platform_get_drvdata(pdev);
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ /*
+ * Free all allocated data.
+ */
+ rt2x00lib_remove_dev(rt2x00dev);
+ rt2x00soc_free_reg(rt2x00dev);
+ ieee80211_free_hw(hw);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00soc_remove);
+
+#ifdef CONFIG_PM
+int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct ieee80211_hw *hw = platform_get_drvdata(pdev);
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ return rt2x00lib_suspend(rt2x00dev, state);
+}
+EXPORT_SYMBOL_GPL(rt2x00soc_suspend);
+
+int rt2x00soc_resume(struct platform_device *pdev)
+{
+ struct ieee80211_hw *hw = platform_get_drvdata(pdev);
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ return rt2x00lib_resume(rt2x00dev);
+}
+EXPORT_SYMBOL_GPL(rt2x00soc_resume);
+#endif /* CONFIG_PM */
+
+/*
+ * rt2x00soc module information.
+ */
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("rt2x00 soc library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.h b/drivers/net/wireless/rt2x00/rt2x00soc.h
new file mode 100644
index 000000000000..5cf114ac2b9c
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00soc.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00soc
+ Abstract: Data structures for the rt2x00soc module.
+ */
+
+#ifndef RT2X00SOC_H
+#define RT2X00SOC_H
+
+#define KSEG1ADDR(__ptr) __ptr
+
+#define __rt2x00soc_probe(__chipset, __ops) \
+static int __rt2x00soc_probe(struct platform_device *pdev) \
+{ \
+ return rt2x00soc_probe(pdev, (__chipset), (__ops)); \
+}
+
+/*
+ * SoC driver handlers.
+ */
+int rt2x00soc_probe(struct platform_device *pdev,
+ const unsigned short chipset,
+ const struct rt2x00_ops *ops);
+int rt2x00soc_remove(struct platform_device *pdev);
+#ifdef CONFIG_PM
+int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state);
+int rt2x00soc_resume(struct platform_device *pdev);
+#else
+#define rt2x00soc_suspend NULL
+#define rt2x00soc_resume NULL
+#endif /* CONFIG_PM */
+
+#endif /* RT2X00SOC_H */
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index b20e3eac9d67..343e565ba4d0 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -51,7 +51,7 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
* These indirect registers work with busy bits,
* and we will try maximal REGISTER_BUSY_COUNT times to access
* the register while taking a REGISTER_BUSY_DELAY us delay
- * between each attampt. When the busy bit is still set at that time,
+ * between each attempt. When the busy bit is still set at that time,
* the access attempt is considered to have failed,
* and we will print an error.
*/
@@ -386,7 +386,7 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev,
* The driver does not support the IV/EIV generation
* in hardware. However it doesn't support the IV/EIV
* inside the ieee80211 frame either, but requires it
- * to be provided seperately for the descriptor.
+ * to be provided separately for the descriptor.
* rt2x00lib will cut the IV/EIV data out of all frames
* given to us by mac80211, but we must tell mac80211
* to generate the IV/EIV data.
@@ -397,7 +397,7 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev,
/*
* SEC_CSR0 contains only single-bit fields to indicate
* a particular key is valid. Because using the FIELD32()
- * defines directly will cause a lot of overhead we use
+ * defines directly will cause a lot of overhead, we use
* a calculation to determine the correct bit directly.
*/
mask = 1 << key->hw_key_idx;
@@ -425,11 +425,11 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
/*
* rt2x00lib can't determine the correct free
* key_idx for pairwise keys. We have 2 registers
- * with key valid bits. The goal is simple, read
- * the first register, if that is full move to
+ * with key valid bits. The goal is simple: read
+ * the first register. If that is full, move to
* the next register.
- * When both registers are full, we drop the key,
- * otherwise we use the first invalid entry.
+ * When both registers are full, we drop the key.
+ * Otherwise, we use the first invalid entry.
*/
rt2x00pci_register_read(rt2x00dev, SEC_CSR2, &reg);
if (reg && reg == ~0) {
@@ -464,8 +464,8 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
&addr_entry, sizeof(addr_entry));
/*
- * Enable pairwise lookup table for given BSS idx,
- * without this received frames will not be decrypted
+ * Enable pairwise lookup table for given BSS idx.
+ * Without this, received frames will not be decrypted
* by the hardware.
*/
rt2x00pci_register_read(rt2x00dev, SEC_CSR4, &reg);
@@ -487,7 +487,7 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
/*
* SEC_CSR2 and SEC_CSR3 contain only single-bit fields to indicate
* a particular key is valid. Because using the FIELD32()
- * defines directly will cause a lot of overhead we use
+ * defines directly will cause a lot of overhead, we use
* a calculation to determine the correct bit directly.
*/
if (key->hw_key_idx < 32) {
@@ -556,7 +556,7 @@ static void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev,
if (flags & CONFIG_UPDATE_TYPE) {
/*
* Clear current synchronisation setup.
- * For the Beacon base registers we only need to clear
+ * For the Beacon base registers, we only need to clear
* the first byte since that byte contains the VALID and OWNER
* bits which (when set to 0) will invalidate the entire beacon.
*/
@@ -1168,8 +1168,8 @@ static int rt61pci_check_firmware(struct rt2x00_dev *rt2x00dev,
return FW_BAD_LENGTH;
/*
- * The last 2 bytes in the firmware array are the crc checksum itself,
- * this means that we should never pass those 2 bytes to the crc
+ * The last 2 bytes in the firmware array are the crc checksum itself.
+ * This means that we should never pass those 2 bytes to the crc
* algorithm.
*/
fw_crc = (data[len - 2] << 8 | data[len - 1]);
@@ -1986,7 +1986,7 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry,
/*
* Hardware has stripped IV/EIV data from 802.11 frame during
- * decryption. It has provided the data seperately but rt2x00lib
+ * decryption. It has provided the data separately but rt2x00lib
* should decide if it should be reinserted.
*/
rxdesc->flags |= RX_FLAG_IV_STRIPPED;
@@ -2042,7 +2042,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
* During each loop we will compare the freshly read
* STA_CSR4 register value with the value read from
* the previous loop. If the 2 values are equal then
- * we should stop processing because the chance it
+ * we should stop processing because the chance is
* quite big that the device has been unplugged and
* we risk going into an endless loop.
*/
@@ -2330,7 +2330,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
__set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags);
/*
- * Detect if this device has an hardware controlled radio.
+ * Detect if this device has a hardware controlled radio.
*/
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
@@ -2355,7 +2355,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
__set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
/*
- * When working with a RF2529 chip without double antenna
+ * When working with a RF2529 chip without double antenna,
* the antenna settings should be gathered from the NIC
* eeprom word.
*/
@@ -2668,7 +2668,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
/*
* We only need to perform additional register initialization
- * for WMM queues/
+ * for WMM queues.
*/
if (queue_idx >= 4)
return 0;
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c
index 1103256ad989..48b0bfd6c55a 100644
--- a/drivers/net/wireless/wl12xx/wl1251_main.c
+++ b/drivers/net/wireless/wl12xx/wl1251_main.c
@@ -183,8 +183,11 @@ static int wl1251_chip_wakeup(struct wl1251 *wl)
wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)",
wl->chip_id);
break;
- case CHIP_ID_1251_PG10:
case CHIP_ID_1251_PG11:
+ wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG11)",
+ wl->chip_id);
+ break;
+ case CHIP_ID_1251_PG10:
default:
wl1251_error("unsupported chip id: 0x%x", wl->chip_id);
ret = -ENODEV;
@@ -1426,4 +1429,4 @@ 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_ALIAS("spi:wl12xx");
+MODULE_ALIAS("spi:wl1251");
diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c
index 17c54b59ef86..601fe0d67827 100644
--- a/drivers/net/wireless/wl12xx/wl1251_rx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_rx.c
@@ -153,7 +153,7 @@ static void wl1251_rx_body(struct wl1251 *wl,
beacon ? "beacon" : "");
memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
- ieee80211_rx(wl->hw, skb);
+ ieee80211_rx_ni(wl->hw, skb);
}
static void wl1251_rx_ack(struct wl1251 *wl)
diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c
index 14eff2b3d4c6..2cf8a2169d43 100644
--- a/drivers/net/wireless/wl12xx/wl1251_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1251_spi.c
@@ -307,7 +307,7 @@ static int __devexit wl1251_spi_remove(struct spi_device *spi)
static struct spi_driver wl1251_spi_driver = {
.driver = {
- .name = "wl12xx",
+ .name = "wl1251",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index 55818f94017b..566f1521ec22 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -32,6 +32,8 @@
#include <linux/bitops.h>
#include <net/mac80211.h>
+#include "wl1271_conf.h"
+
#define DRIVER_NAME "wl1271"
#define DRIVER_PREFIX DRIVER_NAME ": "
@@ -97,21 +99,42 @@ enum {
} while (0)
#define WL1271_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \
- CFG_BSSID_FILTER_EN)
+ CFG_BSSID_FILTER_EN | \
+ CFG_MC_FILTER_EN)
#define WL1271_DEFAULT_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \
CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \
CFG_RX_CTL_EN | CFG_RX_BCN_EN | \
CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
+#define WL1271_DEFAULT_BASIC_RATE_SET (CONF_TX_RATE_MASK_ALL)
+
#define WL1271_FW_NAME "wl1271-fw.bin"
#define WL1271_NVS_NAME "wl1271-nvs.bin"
-#define WL1271_BUSY_WORD_LEN 8
+/*
+ * Enable/disable 802.11a support for WL1273
+ */
+#undef WL1271_80211A_ENABLED
+
+/*
+ * FIXME: for the wl1271, a busy word count of 1 here will result in a more
+ * optimal SPI interface. There is some SPI bug however, causing RXS time outs
+ * with this mode occasionally on boot, so lets have three for now. A value of
+ * three should make sure, that the chipset will always be ready, though this
+ * will impact throughput and latencies slightly.
+ */
+#define WL1271_BUSY_WORD_CNT 3
+#define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32))
#define WL1271_ELP_HW_STATE_ASLEEP 0
#define WL1271_ELP_HW_STATE_IRQ 1
+#define WL1271_DEFAULT_BEACON_INT 100
+#define WL1271_DEFAULT_DTIM_PERIOD 1
+
+#define ACX_TX_DESCRIPTORS 32
+
enum wl1271_state {
WL1271_STATE_OFF,
WL1271_STATE_ON,
@@ -134,6 +157,8 @@ struct wl1271_partition {
struct wl1271_partition_set {
struct wl1271_partition mem;
struct wl1271_partition reg;
+ struct wl1271_partition mem2;
+ struct wl1271_partition mem3;
};
struct wl1271;
@@ -258,15 +283,15 @@ struct wl1271_debugfs {
/* FW status registers */
struct wl1271_fw_status {
- u32 intr;
+ __le32 intr;
u8 fw_rx_counter;
u8 drv_rx_counter;
u8 reserved;
u8 tx_results_counter;
- u32 rx_pkt_descs[NUM_RX_PKT_DESC];
- u32 tx_released_blks[NUM_TX_QUEUES];
- u32 fw_localtime;
- u32 padding[2];
+ __le32 rx_pkt_descs[NUM_RX_PKT_DESC];
+ __le32 tx_released_blks[NUM_TX_QUEUES];
+ __le32 fw_localtime;
+ __le32 padding[2];
} __attribute__ ((packed));
struct wl1271_rx_mem_pool_addr {
@@ -274,6 +299,15 @@ struct wl1271_rx_mem_pool_addr {
u32 addr_extra;
};
+struct wl1271_scan {
+ u8 state;
+ u8 ssid[IW_ESSID_MAX_SIZE+1];
+ size_t ssid_len;
+ u8 active;
+ u8 high_prio;
+ u8 probe_requests;
+};
+
struct wl1271 {
struct ieee80211_hw *hw;
bool mac80211_registered;
@@ -288,10 +322,7 @@ struct wl1271 {
enum wl1271_state state;
struct mutex mutex;
- int physical_mem_addr;
- int physical_reg_addr;
- int virtual_mem_addr;
- int virtual_reg_addr;
+ struct wl1271_partition_set part;
struct wl1271_chip chip;
@@ -308,7 +339,6 @@ struct wl1271 {
u8 bss_type;
u8 ssid[IW_ESSID_MAX_SIZE + 1];
u8 ssid_len;
- u8 listen_int;
int channel;
struct wl1271_acx_mem_map *target_mem_map;
@@ -332,10 +362,14 @@ struct wl1271 {
bool tx_queue_stopped;
struct work_struct tx_work;
- struct work_struct filter_work;
/* Pending TX frames */
- struct sk_buff *tx_frames[16];
+ struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS];
+
+ /* Security sequence number counters */
+ u8 tx_security_last_seq;
+ u16 tx_security_seq_16;
+ u32 tx_security_seq_32;
/* FW Rx counter */
u32 rx_counter;
@@ -354,10 +388,17 @@ struct wl1271 {
/* Are we currently scanning */
bool scanning;
+ struct wl1271_scan scan;
/* Our association ID */
u16 aid;
+ /* currently configured rate set */
+ u32 basic_rate_set;
+
+ /* The current band */
+ enum ieee80211_band band;
+
/* Default key (for WEP) */
u32 default_key;
@@ -368,6 +409,7 @@ struct wl1271 {
bool elp;
struct completion *elp_compl;
+ struct delayed_work elp_work;
/* we can be in psm, but not in elp, we have to differentiate */
bool psm;
@@ -383,11 +425,20 @@ struct wl1271 {
u32 buffer_32;
u32 buffer_cmd;
- u8 buffer_busyword[WL1271_BUSY_WORD_LEN];
- struct wl1271_rx_descriptor *rx_descriptor;
+ u32 buffer_busyword[WL1271_BUSY_WORD_CNT];
struct wl1271_fw_status *fw_status;
struct wl1271_tx_hw_res_if *tx_res_if;
+
+ struct ieee80211_vif *vif;
+
+ /* Used for a workaround to send disconnect before rejoining */
+ bool joined;
+
+ /* Current chipset configuration */
+ struct conf_drv_settings conf;
+
+ struct list_head list;
};
int wl1271_plt_start(struct wl1271 *wl);
@@ -404,4 +455,13 @@ int wl1271_plt_stop(struct wl1271 *wl);
/* WL1271 needs a 200ms sleep after power on */
#define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */
+static inline bool wl1271_11a_enabled(void)
+{
+#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 f622a4092615..bf5a8680a462 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.c
@@ -34,8 +34,7 @@
#include "wl1271_spi.h"
#include "wl1271_ps.h"
-int wl1271_acx_wake_up_conditions(struct wl1271 *wl, u8 wake_up_event,
- u8 listen_interval)
+int wl1271_acx_wake_up_conditions(struct wl1271 *wl)
{
struct acx_wake_up_condition *wake_up;
int ret;
@@ -48,8 +47,8 @@ int wl1271_acx_wake_up_conditions(struct wl1271 *wl, u8 wake_up_event,
goto out;
}
- wake_up->wake_up_event = wake_up_event;
- wake_up->listen_interval = listen_interval;
+ wake_up->wake_up_event = wl->conf.conn.wake_up_event;
+ wake_up->listen_interval = wl->conf.conn.listen_interval;
ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS,
wake_up, sizeof(*wake_up));
@@ -137,7 +136,12 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power)
goto out;
}
- acx->current_tx_power = power * 10;
+ /*
+ * FIXME: This is a workaround needed while we don't the correct
+ * calibration, to avoid distortions
+ */
+ /* acx->current_tx_power = power * 10; */
+ acx->current_tx_power = 70;
ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx));
if (ret < 0) {
@@ -193,7 +197,7 @@ int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map,
return 0;
}
-int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time)
+int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl)
{
struct acx_rx_msdu_lifetime *acx;
int ret;
@@ -206,7 +210,7 @@ int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time)
goto out;
}
- acx->lifetime = life_time;
+ acx->lifetime = cpu_to_le32(wl->conf.rx.rx_msdu_life_time);
ret = wl1271_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME,
acx, sizeof(*acx));
if (ret < 0) {
@@ -232,8 +236,8 @@ int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter)
goto out;
}
- rx_config->config_options = config;
- rx_config->filter_options = filter;
+ rx_config->config_options = cpu_to_le32(config);
+ rx_config->filter_options = cpu_to_le32(filter);
ret = wl1271_cmd_configure(wl, ACX_RX_CFG,
rx_config, sizeof(*rx_config));
@@ -260,7 +264,7 @@ int wl1271_acx_pd_threshold(struct wl1271 *wl)
goto out;
}
- /* FIXME: threshold value not set */
+ pd->threshold = cpu_to_le32(wl->conf.rx.packet_detection_threshold);
ret = wl1271_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd));
if (ret < 0) {
@@ -300,7 +304,8 @@ out:
return ret;
}
-int wl1271_acx_group_address_tbl(struct wl1271 *wl)
+int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
+ void *mc_list, u32 mc_list_len)
{
struct acx_dot11_grp_addr_tbl *acx;
int ret;
@@ -314,9 +319,9 @@ int wl1271_acx_group_address_tbl(struct wl1271 *wl)
}
/* MAC filtering */
- acx->enabled = 0;
- acx->num_groups = 0;
- memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN);
+ acx->enabled = enable;
+ acx->num_groups = mc_list_len;
+ memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN);
ret = wl1271_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL,
acx, sizeof(*acx));
@@ -343,8 +348,8 @@ int wl1271_acx_service_period_timeout(struct wl1271 *wl)
wl1271_debug(DEBUG_ACX, "acx service period timeout");
- rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF;
- rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF;
+ rx_timeout->ps_poll_timeout = cpu_to_le16(wl->conf.rx.ps_poll_timeout);
+ rx_timeout->upsd_timeout = cpu_to_le16(wl->conf.rx.upsd_timeout);
ret = wl1271_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT,
rx_timeout, sizeof(*rx_timeout));
@@ -372,7 +377,7 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold)
goto out;
}
- rts->threshold = rts_threshold;
+ rts->threshold = cpu_to_le16(rts_threshold);
ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts));
if (ret < 0) {
@@ -385,20 +390,29 @@ out:
return ret;
}
-int wl1271_acx_beacon_filter_opt(struct wl1271 *wl)
+int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter)
{
- struct acx_beacon_filter_option *beacon_filter;
- int ret;
+ struct acx_beacon_filter_option *beacon_filter = NULL;
+ int ret = 0;
wl1271_debug(DEBUG_ACX, "acx beacon filter opt");
+ if (enable_filter &&
+ wl->conf.conn.bcn_filt_mode == CONF_BCN_FILT_MODE_DISABLED)
+ goto out;
+
beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL);
if (!beacon_filter) {
ret = -ENOMEM;
goto out;
}
- beacon_filter->enable = 0;
+ beacon_filter->enable = enable_filter;
+
+ /*
+ * When set to zero, and the filter is enabled, beacons
+ * without the unicast TIM bit set are dropped.
+ */
beacon_filter->max_num_beacons = 0;
ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_OPT,
@@ -416,7 +430,9 @@ out:
int wl1271_acx_beacon_filter_table(struct wl1271 *wl)
{
struct acx_beacon_filter_ie_table *ie_table;
+ int i, idx = 0;
int ret;
+ bool vendor_spec = false;
wl1271_debug(DEBUG_ACX, "acx beacon filter table");
@@ -426,8 +442,32 @@ int wl1271_acx_beacon_filter_table(struct wl1271 *wl)
goto out;
}
+ /* configure default beacon pass-through rules */
ie_table->num_ie = 0;
- memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE);
+ for (i = 0; i < wl->conf.conn.bcn_filt_ie_count; i++) {
+ struct conf_bcn_filt_rule *r = &(wl->conf.conn.bcn_filt_ie[i]);
+ ie_table->table[idx++] = r->ie;
+ ie_table->table[idx++] = r->rule;
+
+ if (r->ie == WLAN_EID_VENDOR_SPECIFIC) {
+ /* only one vendor specific ie allowed */
+ if (vendor_spec)
+ continue;
+
+ /* for vendor specific rules configure the
+ additional fields */
+ memcpy(&(ie_table->table[idx]), r->oui,
+ CONF_BCN_IE_OUI_LEN);
+ idx += CONF_BCN_IE_OUI_LEN;
+ ie_table->table[idx++] = r->type;
+ memcpy(&(ie_table->table[idx]), r->version,
+ CONF_BCN_IE_VER_LEN);
+ idx += CONF_BCN_IE_VER_LEN;
+ vendor_spec = true;
+ }
+
+ ie_table->num_ie++;
+ }
ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_TABLE,
ie_table, sizeof(*ie_table));
@@ -441,6 +481,36 @@ out:
return ret;
}
+int wl1271_acx_conn_monit_params(struct wl1271 *wl)
+{
+ struct acx_conn_monit_params *acx;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx connection monitor parameters");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->synch_fail_thold = cpu_to_le32(wl->conf.conn.synch_fail_thold);
+ acx->bss_lose_timeout = cpu_to_le32(wl->conf.conn.bss_lose_timeout);
+
+ ret = wl1271_cmd_configure(wl, ACX_CONN_MONIT_PARAMS,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("failed to set connection monitor "
+ "parameters: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+
int wl1271_acx_sg_enable(struct wl1271 *wl)
{
struct acx_bt_wlan_coex *pta;
@@ -470,6 +540,7 @@ out:
int wl1271_acx_sg_cfg(struct wl1271 *wl)
{
struct acx_bt_wlan_coex_param *param;
+ struct conf_sg_settings *c = &wl->conf.sg;
int ret;
wl1271_debug(DEBUG_ACX, "acx sg cfg");
@@ -481,34 +552,19 @@ int wl1271_acx_sg_cfg(struct wl1271 *wl)
}
/* BT-WLAN coext parameters */
- param->min_rate = RATE_INDEX_24MBPS;
- param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF;
- param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF;
- param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF;
- param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF;
- param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF;
- param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF;
- param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF;
- param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF;
- param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF;
- param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF;
- param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF;
- param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF;
- param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF;
- param->antenna_type = PTA_ANTENNA_TYPE_DEF;
- param->signal_type = PTA_SIGNALING_TYPE_DEF;
- param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF;
- param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF;
- param->max_cts = PTA_MAX_NUM_CTS_DEF;
- param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF;
- param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF;
- param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF;
- param->wlan_elp_hp = PTA_ELP_HP_DEF;
- param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF;
- param->ack_mode_dual_ant = PTA_ACK_MODE_DEF;
- param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF;
- param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF;
- param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF;
+ param->per_threshold = cpu_to_le32(c->per_threshold);
+ param->max_scan_compensation_time =
+ cpu_to_le32(c->max_scan_compensation_time);
+ param->nfs_sample_interval = cpu_to_le16(c->nfs_sample_interval);
+ param->load_ratio = c->load_ratio;
+ param->auto_ps_mode = c->auto_ps_mode;
+ param->probe_req_compensation = c->probe_req_compensation;
+ param->scan_window_compensation = c->scan_window_compensation;
+ param->antenna_config = c->antenna_config;
+ param->beacon_miss_threshold = c->beacon_miss_threshold;
+ param->rate_adaptation_threshold =
+ cpu_to_le32(c->rate_adaptation_threshold);
+ param->rate_adaptation_snr = c->rate_adaptation_snr;
ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
if (ret < 0) {
@@ -534,8 +590,8 @@ int wl1271_acx_cca_threshold(struct wl1271 *wl)
goto out;
}
- detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D;
- detection->tx_energy_detection = 0;
+ detection->rx_cca_threshold = cpu_to_le16(wl->conf.rx.rx_cca_threshold);
+ detection->tx_energy_detection = wl->conf.tx.tx_energy_detection;
ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD,
detection, sizeof(*detection));
@@ -562,10 +618,10 @@ int wl1271_acx_bcn_dtim_options(struct wl1271 *wl)
goto out;
}
- bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE;
- bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE;
- bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE;
- bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF;
+ bb->beacon_rx_timeout = cpu_to_le16(wl->conf.conn.beacon_rx_timeout);
+ bb->broadcast_timeout = cpu_to_le16(wl->conf.conn.broadcast_timeout);
+ bb->rx_broadcast_in_ps = wl->conf.conn.rx_broadcast_in_ps;
+ bb->ps_poll_threshold = wl->conf.conn.ps_poll_threshold;
ret = wl1271_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb));
if (ret < 0) {
@@ -591,7 +647,7 @@ int wl1271_acx_aid(struct wl1271 *wl, u16 aid)
goto out;
}
- acx_aid->aid = aid;
+ acx_aid->aid = cpu_to_le16(aid);
ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid));
if (ret < 0) {
@@ -618,9 +674,8 @@ int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask)
}
/* high event mask is unused */
- mask->high_event_mask = 0xffffffff;
-
- mask->event_mask = event_mask;
+ mask->high_event_mask = cpu_to_le32(0xffffffff);
+ mask->event_mask = cpu_to_le32(event_mask);
ret = wl1271_cmd_configure(wl, ACX_EVENT_MBOX_MASK,
mask, sizeof(*mask));
@@ -703,9 +758,10 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
return 0;
}
-int wl1271_acx_rate_policies(struct wl1271 *wl)
+int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates)
{
struct acx_rate_policy *acx;
+ struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf;
int ret = 0;
wl1271_debug(DEBUG_ACX, "acx rate policies");
@@ -718,11 +774,11 @@ int wl1271_acx_rate_policies(struct wl1271 *wl)
}
/* configure one default (one-size-fits-all) rate class */
- acx->rate_class_cnt = 1;
- acx->rate_class[0].enabled_rates = ACX_RATE_MASK_ALL;
- acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT;
- acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT;
- acx->rate_class[0].aflags = 0;
+ acx->rate_class_cnt = cpu_to_le32(1);
+ acx->rate_class[0].enabled_rates = cpu_to_le32(enabled_rates);
+ acx->rate_class[0].short_retry_limit = c->short_retry_limit;
+ acx->rate_class[0].long_retry_limit = c->long_retry_limit;
+ acx->rate_class[0].aflags = c->aflags;
ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
if (ret < 0) {
@@ -749,22 +805,14 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl)
goto out;
}
- /*
- * FIXME: Configure each AC with appropriate values (most suitable
- * values will probably be different for each AC.
- */
- for (i = 0; i < WL1271_ACX_AC_COUNT; i++) {
- acx->ac = i;
-
- /*
- * FIXME: The following default values originate from
- * the TI reference driver. What do they mean?
- */
- acx->cw_min = 15;
- acx->cw_max = 63;
- acx->aifsn = 3;
+ for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
+ struct conf_tx_ac_category *c = &(wl->conf.tx.ac_conf[i]);
+ acx->ac = c->ac;
+ acx->cw_min = c->cw_min;
+ acx->cw_max = cpu_to_le16(c->cw_max);
+ acx->aifsn = c->aifsn;
acx->reserved = 0;
- acx->tx_op_limit = 0;
+ acx->tx_op_limit = cpu_to_le16(c->tx_op_limit);
ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx));
if (ret < 0) {
@@ -793,12 +841,15 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl)
goto out;
}
- /* FIXME: configure each TID with a different AC reference */
- for (i = 0; i < WL1271_ACX_TID_COUNT; i++) {
- acx->queue_id = i;
- acx->tsid = WL1271_ACX_AC_BE;
- acx->ps_scheme = WL1271_ACX_PS_SCHEME_LEGACY;
- acx->ack_policy = WL1271_ACX_ACK_POLICY_LEGACY;
+ for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
+ struct conf_tx_tid *c = &(wl->conf.tx.tid_conf[i]);
+ acx->queue_id = c->queue_id;
+ acx->channel_type = c->channel_type;
+ acx->tsid = c->tsid;
+ acx->ps_scheme = c->ps_scheme;
+ acx->ack_policy = c->ack_policy;
+ acx->apsd_conf[0] = cpu_to_le32(c->apsd_conf[0]);
+ acx->apsd_conf[1] = cpu_to_le32(c->apsd_conf[1]);
ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx));
if (ret < 0) {
@@ -826,7 +877,7 @@ int wl1271_acx_frag_threshold(struct wl1271 *wl)
goto out;
}
- acx->frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
+ acx->frag_threshold = cpu_to_le16(wl->conf.tx.frag_threshold);
ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("Setting of frag threshold failed: %d", ret);
@@ -852,8 +903,8 @@ int wl1271_acx_tx_config_options(struct wl1271 *wl)
goto out;
}
- acx->tx_compl_timeout = WL1271_ACX_TX_COMPL_TIMEOUT;
- acx->tx_compl_threshold = WL1271_ACX_TX_COMPL_THRESHOLD;
+ acx->tx_compl_timeout = cpu_to_le16(wl->conf.tx.tx_compl_timeout);
+ acx->tx_compl_threshold = cpu_to_le16(wl->conf.tx.tx_compl_threshold);
ret = wl1271_cmd_configure(wl, ACX_TX_CONFIG_OPT, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("Setting of tx options failed: %d", ret);
@@ -879,11 +930,11 @@ int wl1271_acx_mem_cfg(struct wl1271 *wl)
}
/* memory config */
- mem_conf->num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS);
+ mem_conf->num_stations = DEFAULT_NUM_STATIONS;
mem_conf->rx_mem_block_num = ACX_RX_MEM_BLOCKS;
mem_conf->tx_min_mem_block_num = ACX_TX_MIN_MEM_BLOCKS;
mem_conf->num_ssid_profiles = ACX_NUM_SSID_PROFILES;
- mem_conf->total_tx_descriptors = ACX_TX_DESCRIPTORS;
+ mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS);
ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
sizeof(*mem_conf));
@@ -906,7 +957,7 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl)
return ret;
wl->target_mem_map = kzalloc(sizeof(struct wl1271_acx_mem_map),
- GFP_KERNEL);
+ GFP_KERNEL);
if (!wl->target_mem_map) {
wl1271_error("couldn't allocate target memory map");
return -ENOMEM;
@@ -923,7 +974,8 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl)
}
/* initialize TX block book keeping */
- wl->tx_blocks_available = wl->target_mem_map->num_tx_mem_blocks;
+ wl->tx_blocks_available =
+ le32_to_cpu(wl->target_mem_map->num_tx_mem_blocks);
wl1271_debug(DEBUG_TX, "available tx blocks: %d",
wl->tx_blocks_available);
@@ -943,10 +995,10 @@ int wl1271_acx_init_rx_interrupt(struct wl1271 *wl)
goto out;
}
- rx_conf->threshold = WL1271_RX_INTR_THRESHOLD_DEF;
- rx_conf->timeout = WL1271_RX_INTR_TIMEOUT_DEF;
- rx_conf->mblk_threshold = USHORT_MAX; /* Disabled */
- rx_conf->queue_type = RX_QUEUE_TYPE_RX_LOW_PRIORITY;
+ rx_conf->threshold = cpu_to_le16(wl->conf.rx.irq_pkt_threshold);
+ rx_conf->timeout = cpu_to_le16(wl->conf.rx.irq_timeout);
+ rx_conf->mblk_threshold = cpu_to_le16(wl->conf.rx.irq_blk_threshold);
+ rx_conf->queue_type = wl->conf.rx.queue_type;
ret = wl1271_cmd_configure(wl, ACX_RX_CONFIG_OPT, rx_conf,
sizeof(*rx_conf));
@@ -959,3 +1011,124 @@ out:
kfree(rx_conf);
return ret;
}
+
+int wl1271_acx_smart_reflex(struct wl1271 *wl)
+{
+ struct acx_smart_reflex_state *sr_state = NULL;
+ struct acx_smart_reflex_config_params *sr_param = NULL;
+ int i, ret;
+
+ wl1271_debug(DEBUG_ACX, "acx smart reflex");
+
+ sr_param = kzalloc(sizeof(*sr_param), GFP_KERNEL);
+ if (!sr_param) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < CONF_SR_ERR_TBL_COUNT; i++) {
+ struct conf_mart_reflex_err_table *e =
+ &(wl->conf.init.sr_err_tbl[i]);
+
+ sr_param->error_table[i].len = e->len;
+ sr_param->error_table[i].upper_limit = e->upper_limit;
+ memcpy(sr_param->error_table[i].values, e->values, e->len);
+ }
+
+ ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_PARAMS,
+ sr_param, sizeof(*sr_param));
+ if (ret < 0) {
+ wl1271_warning("failed to set smart reflex params: %d", ret);
+ goto out;
+ }
+
+ sr_state = kzalloc(sizeof(*sr_state), GFP_KERNEL);
+ if (!sr_state) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* enable smart reflex */
+ sr_state->enable = wl->conf.init.sr_enable;
+
+ ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_STATE,
+ sr_state, sizeof(*sr_state));
+ if (ret < 0) {
+ wl1271_warning("failed to set smart reflex params: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(sr_state);
+ kfree(sr_param);
+ return ret;
+
+}
+
+int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable)
+{
+ struct wl1271_acx_bet_enable *acx = NULL;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_ACX, "acx bet enable");
+
+ if (enable && wl->conf.conn.bet_enable == CONF_BET_MODE_DISABLE)
+ goto out;
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE;
+ acx->max_consecutive = wl->conf.conn.bet_max_consecutive;
+
+ ret = wl1271_cmd_configure(wl, ACX_BET_ENABLE, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx bet enable failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
+ u8 version)
+{
+ struct wl1271_acx_arp_filter *acx;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx arp ip filter, enable: %d", enable);
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->version = version;
+ acx->enable = enable;
+
+ if (enable == true) {
+ if (version == ACX_IPV4_VERSION)
+ memcpy(acx->address, address, ACX_IPV4_ADDR_SIZE);
+ else if (version == ACX_IPV6_VERSION)
+ memcpy(acx->address, address, sizeof(acx->address));
+ else
+ wl1271_error("Invalid IP version");
+ }
+
+ ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("failed to set arp ip filter: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h
index 9068daaf0ddf..2ce0a8128542 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.h
@@ -61,8 +61,9 @@
WL1271_ACX_INTR_HW_AVAILABLE | \
WL1271_ACX_INTR_DATA)
-#define WL1271_INTR_MASK (WL1271_ACX_INTR_EVENT_A | \
- WL1271_ACX_INTR_EVENT_B | \
+#define WL1271_INTR_MASK (WL1271_ACX_INTR_EVENT_A | \
+ WL1271_ACX_INTR_EVENT_B | \
+ WL1271_ACX_INTR_HW_AVAILABLE | \
WL1271_ACX_INTR_DATA)
/* Target's information element */
@@ -70,11 +71,11 @@ struct acx_header {
struct wl1271_cmd_header cmd;
/* acx (or information element) header */
- u16 id;
+ __le16 id;
/* payload length (not including headers */
- u16 len;
-};
+ __le16 len;
+} __attribute__ ((packed));
struct acx_error_counter {
struct acx_header header;
@@ -82,21 +83,21 @@ struct acx_error_counter {
/* The number of PLCP errors since the last time this */
/* information element was interrogated. This field is */
/* automatically cleared when it is interrogated.*/
- u32 PLCP_error;
+ __le32 PLCP_error;
/* The number of FCS errors since the last time this */
/* information element was interrogated. This field is */
/* automatically cleared when it is interrogated.*/
- u32 FCS_error;
+ __le32 FCS_error;
/* The number of MPDUs without PLCP header errors received*/
/* since the last time this information element was interrogated. */
/* This field is automatically cleared when it is interrogated.*/
- u32 valid_frame;
+ __le32 valid_frame;
/* the number of missed sequence numbers in the squentially */
/* values of frames seq numbers */
- u32 seq_num_miss;
+ __le32 seq_num_miss;
} __attribute__ ((packed));
struct acx_revision {
@@ -125,7 +126,7 @@ struct acx_revision {
* (1 = first spin, 2 = second spin, and so on).
* bits 24 - 31: Chip ID - The WiLink chip ID.
*/
- u32 hw_version;
+ __le32 hw_version;
} __attribute__ ((packed));
enum wl1271_psm_mode {
@@ -170,7 +171,6 @@ enum {
#define DP_RX_PACKET_RING_CHUNK_NUM 2
#define DP_TX_PACKET_RING_CHUNK_NUM 2
#define DP_TX_COMPLETE_TIME_OUT 20
-#define FW_TX_CMPLT_BLOCK_SIZE 16
#define TX_MSDU_LIFETIME_MIN 0
#define TX_MSDU_LIFETIME_MAX 3000
@@ -186,7 +186,7 @@ struct acx_rx_msdu_lifetime {
* The maximum amount of time, in TU, before the
* firmware discards the MSDU.
*/
- u32 lifetime;
+ __le32 lifetime;
} __attribute__ ((packed));
/*
@@ -273,14 +273,14 @@ struct acx_rx_msdu_lifetime {
struct acx_rx_config {
struct acx_header header;
- u32 config_options;
- u32 filter_options;
+ __le32 config_options;
+ __le32 filter_options;
} __attribute__ ((packed));
struct acx_packet_detection {
struct acx_header header;
- u32 threshold;
+ __le32 threshold;
} __attribute__ ((packed));
@@ -302,8 +302,8 @@ struct acx_slot {
} __attribute__ ((packed));
-#define ADDRESS_GROUP_MAX (8)
-#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX)
+#define ACX_MC_ADDRESS_GROUP_MAX (8)
+#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ACX_MC_ADDRESS_GROUP_MAX)
struct acx_dot11_grp_addr_tbl {
struct acx_header header;
@@ -314,40 +314,17 @@ struct acx_dot11_grp_addr_tbl {
u8 mac_table[ADDRESS_GROUP_MAX_LEN];
} __attribute__ ((packed));
-
-#define RX_TIMEOUT_PS_POLL_MIN 0
-#define RX_TIMEOUT_PS_POLL_MAX (200000)
-#define RX_TIMEOUT_PS_POLL_DEF (15)
-#define RX_TIMEOUT_UPSD_MIN 0
-#define RX_TIMEOUT_UPSD_MAX (200000)
-#define RX_TIMEOUT_UPSD_DEF (15)
-
struct acx_rx_timeout {
struct acx_header header;
- /*
- * The longest time the STA will wait to receive
- * traffic from the AP after a PS-poll has been
- * transmitted.
- */
- u16 ps_poll_timeout;
-
- /*
- * The longest time the STA will wait to receive
- * traffic from the AP after a frame has been sent
- * from an UPSD enabled queue.
- */
- u16 upsd_timeout;
+ __le16 ps_poll_timeout;
+ __le16 upsd_timeout;
} __attribute__ ((packed));
-#define RTS_THRESHOLD_MIN 0
-#define RTS_THRESHOLD_MAX 4096
-#define RTS_THRESHOLD_DEF 2347
-
struct acx_rts_threshold {
struct acx_header header;
- u16 threshold;
+ __le16 threshold;
u8 pad[2];
} __attribute__ ((packed));
@@ -408,6 +385,13 @@ struct acx_beacon_filter_ie_table {
u8 pad[3];
} __attribute__ ((packed));
+struct acx_conn_monit_params {
+ struct acx_header header;
+
+ __le32 synch_fail_thold; /* number of beacons missed */
+ __le32 bss_lose_timeout; /* number of TU's from synch fail */
+} __attribute__ ((packed));
+
enum {
SG_ENABLE = 0,
SG_DISABLE,
@@ -431,6 +415,25 @@ struct acx_bt_wlan_coex {
u8 pad[3];
} __attribute__ ((packed));
+struct acx_smart_reflex_state {
+ struct acx_header header;
+
+ u8 enable;
+ u8 padding[3];
+} __attribute__ ((packed));
+
+struct smart_reflex_err_table {
+ u8 len;
+ s8 upper_limit;
+ s8 values[14];
+} __attribute__ ((packed));
+
+struct acx_smart_reflex_config_params {
+ struct acx_header header;
+
+ struct smart_reflex_err_table error_table[3];
+} __attribute__ ((packed));
+
#define PTA_ANTENNA_TYPE_DEF (0)
#define PTA_BT_HP_MAXTIME_DEF (2000)
#define PTA_WLAN_HP_MAX_TIME_DEF (5000)
@@ -463,150 +466,34 @@ struct acx_bt_wlan_coex {
struct acx_bt_wlan_coex_param {
struct acx_header header;
- /*
- * The minimum rate of a received WLAN packet in the STA,
- * during protective mode, of which a new BT-HP request
- * during this Rx will always be respected and gain the antenna.
- */
- u32 min_rate;
-
- /* Max time the BT HP will be respected. */
- u16 bt_hp_max_time;
-
- /* Max time the WLAN HP will be respected. */
- u16 wlan_hp_max_time;
-
- /*
- * The time between the last BT activity
- * and the moment when the sense mode returns
- * to SENSE_INACTIVE.
- */
- u16 sense_disable_timer;
-
- /* Time before the next BT HP instance */
- u16 rx_time_bt_hp;
- u16 tx_time_bt_hp;
-
- /* range: 10-20000 default: 1500 */
- u16 rx_time_bt_hp_fast;
- u16 tx_time_bt_hp_fast;
-
- /* range: 2000-65535 default: 8700 */
- u16 wlan_cycle_fast;
-
- /* range: 0 - 15000 (Msec) default: 1000 */
- u16 bt_anti_starvation_period;
-
- /* range 400-10000(Usec) default: 3000 */
- u16 next_bt_lp_packet;
-
- /* Deafult: worst case for BT DH5 traffic */
- u16 wake_up_beacon;
-
- /* range: 0-50000(Usec) default: 1050 */
- u16 hp_dm_max_guard_time;
-
- /*
- * This is to prevent both BT & WLAN antenna
- * starvation.
- * Range: 100-50000(Usec) default:2550
- */
- u16 next_wlan_packet;
-
- /* 0 -> shared antenna */
- u8 antenna_type;
-
- /*
- * 0 -> TI legacy
- * 1 -> Palau
- */
- u8 signal_type;
-
- /*
- * BT AFH status
- * 0 -> no AFH
- * 1 -> from dedicated GPIO
- * 2 -> AFH on (from host)
- */
- u8 afh_leverage_on;
-
- /*
- * The number of cycles during which no
- * TX will be sent after 1 cycle of RX
- * transaction in protective mode
- */
- u8 quiet_cycle_num;
-
- /*
- * The maximum number of CTSs that will
- * be sent for receiving RX packet in
- * protective mode
- */
- u8 max_cts;
-
- /*
- * The number of WLAN packets
- * transferred in common mode before
- * switching to BT.
- */
- u8 wlan_packets_num;
-
- /*
- * The number of BT packets
- * transferred in common mode before
- * switching to WLAN.
- */
- u8 bt_packets_num;
-
- /* range: 1-255 default: 5 */
- u8 missed_rx_avalanche;
-
- /* range: 0-1 default: 1 */
- u8 wlan_elp_hp;
-
- /* range: 0 - 15 default: 4 */
- u8 bt_anti_starvation_cycles;
-
- u8 ack_mode_dual_ant;
-
- /*
- * Allow PA_SD assertion/de-assertion
- * during enabled BT activity.
- */
- u8 pa_sd_enable;
-
- /*
- * Enable/Disable PTA in auto mode:
- * Support Both Active & P.S modes
- */
- u8 pta_auto_mode_enable;
-
- /* range: 0 - 20 default: 1 */
- u8 bt_hp_respected_num;
+ __le32 per_threshold;
+ __le32 max_scan_compensation_time;
+ __le16 nfs_sample_interval;
+ u8 load_ratio;
+ u8 auto_ps_mode;
+ u8 probe_req_compensation;
+ u8 scan_window_compensation;
+ u8 antenna_config;
+ u8 beacon_miss_threshold;
+ __le32 rate_adaptation_threshold;
+ s8 rate_adaptation_snr;
+ u8 padding[3];
} __attribute__ ((packed));
-#define CCA_THRSH_ENABLE_ENERGY_D 0x140A
-#define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF
-
struct acx_energy_detection {
struct acx_header header;
/* The RX Clear Channel Assessment threshold in the PHY */
- u16 rx_cca_threshold;
+ __le16 rx_cca_threshold;
u8 tx_energy_detection;
u8 pad;
} __attribute__ ((packed));
-#define BCN_RX_TIMEOUT_DEF_VALUE 10000
-#define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000
-#define RX_BROADCAST_IN_PS_DEF_VALUE 1
-#define CONSECUTIVE_PS_POLL_FAILURE_DEF 4
-
struct acx_beacon_broadcast {
struct acx_header header;
- u16 beacon_rx_timeout;
- u16 broadcast_timeout;
+ __le16 beacon_rx_timeout;
+ __le16 broadcast_timeout;
/* Enables receiving of broadcast packets in PS mode */
u8 rx_broadcast_in_ps;
@@ -619,8 +506,8 @@ struct acx_beacon_broadcast {
struct acx_event_mask {
struct acx_header header;
- u32 event_mask;
- u32 high_event_mask; /* Unused */
+ __le32 event_mask;
+ __le32 high_event_mask; /* Unused */
} __attribute__ ((packed));
#define CFG_RX_FCS BIT(2)
@@ -657,11 +544,15 @@ struct acx_event_mask {
#define SCAN_TRIGGERED BIT(2)
#define SCAN_PRIORITY_HIGH BIT(3)
+/* When set, disable HW encryption */
+#define DF_ENCRYPTION_DISABLE 0x01
+#define DF_SNIFF_MODE_ENABLE 0x80
+
struct acx_feature_config {
struct acx_header header;
- u32 options;
- u32 data_flow_options;
+ __le32 options;
+ __le32 data_flow_options;
} __attribute__ ((packed));
struct acx_current_tx_power {
@@ -671,14 +562,6 @@ struct acx_current_tx_power {
u8 padding[3];
} __attribute__ ((packed));
-enum acx_wake_up_event {
- WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/
- WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/
- WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */
- WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */
- WAKE_UP_EVENT_BITS_MASK = 0x0F
-};
-
struct acx_wake_up_condition {
struct acx_header header;
@@ -693,7 +576,7 @@ struct acx_aid {
/*
* To be set when associated with an AP.
*/
- u16 aid;
+ __le16 aid;
u8 pad[2];
} __attribute__ ((packed));
@@ -725,152 +608,152 @@ struct acx_ctsprotect {
} __attribute__ ((packed));
struct acx_tx_statistics {
- u32 internal_desc_overflow;
+ __le32 internal_desc_overflow;
} __attribute__ ((packed));
struct acx_rx_statistics {
- u32 out_of_mem;
- u32 hdr_overflow;
- u32 hw_stuck;
- u32 dropped;
- u32 fcs_err;
- u32 xfr_hint_trig;
- u32 path_reset;
- u32 reset_counter;
+ __le32 out_of_mem;
+ __le32 hdr_overflow;
+ __le32 hw_stuck;
+ __le32 dropped;
+ __le32 fcs_err;
+ __le32 xfr_hint_trig;
+ __le32 path_reset;
+ __le32 reset_counter;
} __attribute__ ((packed));
struct acx_dma_statistics {
- u32 rx_requested;
- u32 rx_errors;
- u32 tx_requested;
- u32 tx_errors;
+ __le32 rx_requested;
+ __le32 rx_errors;
+ __le32 tx_requested;
+ __le32 tx_errors;
} __attribute__ ((packed));
struct acx_isr_statistics {
/* host command complete */
- u32 cmd_cmplt;
+ __le32 cmd_cmplt;
/* fiqisr() */
- u32 fiqs;
+ __le32 fiqs;
/* (INT_STS_ND & INT_TRIG_RX_HEADER) */
- u32 rx_headers;
+ __le32 rx_headers;
/* (INT_STS_ND & INT_TRIG_RX_CMPLT) */
- u32 rx_completes;
+ __le32 rx_completes;
/* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */
- u32 rx_mem_overflow;
+ __le32 rx_mem_overflow;
/* (INT_STS_ND & INT_TRIG_S_RX_RDY) */
- u32 rx_rdys;
+ __le32 rx_rdys;
/* irqisr() */
- u32 irqs;
+ __le32 irqs;
/* (INT_STS_ND & INT_TRIG_TX_PROC) */
- u32 tx_procs;
+ __le32 tx_procs;
/* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */
- u32 decrypt_done;
+ __le32 decrypt_done;
/* (INT_STS_ND & INT_TRIG_DMA0) */
- u32 dma0_done;
+ __le32 dma0_done;
/* (INT_STS_ND & INT_TRIG_DMA1) */
- u32 dma1_done;
+ __le32 dma1_done;
/* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */
- u32 tx_exch_complete;
+ __le32 tx_exch_complete;
/* (INT_STS_ND & INT_TRIG_COMMAND) */
- u32 commands;
+ __le32 commands;
/* (INT_STS_ND & INT_TRIG_RX_PROC) */
- u32 rx_procs;
+ __le32 rx_procs;
/* (INT_STS_ND & INT_TRIG_PM_802) */
- u32 hw_pm_mode_changes;
+ __le32 hw_pm_mode_changes;
/* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */
- u32 host_acknowledges;
+ __le32 host_acknowledges;
/* (INT_STS_ND & INT_TRIG_PM_PCI) */
- u32 pci_pm;
+ __le32 pci_pm;
/* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */
- u32 wakeups;
+ __le32 wakeups;
/* (INT_STS_ND & INT_TRIG_LOW_RSSI) */
- u32 low_rssi;
+ __le32 low_rssi;
} __attribute__ ((packed));
struct acx_wep_statistics {
/* WEP address keys configured */
- u32 addr_key_count;
+ __le32 addr_key_count;
/* default keys configured */
- u32 default_key_count;
+ __le32 default_key_count;
- u32 reserved;
+ __le32 reserved;
/* number of times that WEP key not found on lookup */
- u32 key_not_found;
+ __le32 key_not_found;
/* number of times that WEP key decryption failed */
- u32 decrypt_fail;
+ __le32 decrypt_fail;
/* WEP packets decrypted */
- u32 packets;
+ __le32 packets;
/* WEP decrypt interrupts */
- u32 interrupt;
+ __le32 interrupt;
} __attribute__ ((packed));
#define ACX_MISSED_BEACONS_SPREAD 10
struct acx_pwr_statistics {
/* the amount of enters into power save mode (both PD & ELP) */
- u32 ps_enter;
+ __le32 ps_enter;
/* the amount of enters into ELP mode */
- u32 elp_enter;
+ __le32 elp_enter;
/* the amount of missing beacon interrupts to the host */
- u32 missing_bcns;
+ __le32 missing_bcns;
/* the amount of wake on host-access times */
- u32 wake_on_host;
+ __le32 wake_on_host;
/* the amount of wake on timer-expire */
- u32 wake_on_timer_exp;
+ __le32 wake_on_timer_exp;
/* the number of packets that were transmitted with PS bit set */
- u32 tx_with_ps;
+ __le32 tx_with_ps;
/* the number of packets that were transmitted with PS bit clear */
- u32 tx_without_ps;
+ __le32 tx_without_ps;
/* the number of received beacons */
- u32 rcvd_beacons;
+ __le32 rcvd_beacons;
/* the number of entering into PowerOn (power save off) */
- u32 power_save_off;
+ __le32 power_save_off;
/* the number of entries into power save mode */
- u16 enable_ps;
+ __le16 enable_ps;
/*
* the number of exits from power save, not including failed PS
* transitions
*/
- u16 disable_ps;
+ __le16 disable_ps;
/*
* the number of times the TSF counter was adjusted because
* of drift
*/
- u32 fix_tsf_ps;
+ __le32 fix_tsf_ps;
/* Gives statistics about the spread continuous missed beacons.
* The 16 LSB are dedicated for the PS mode.
@@ -881,53 +764,53 @@ struct acx_pwr_statistics {
* ...
* cont_miss_bcns_spread[9] - ten and more continuous missed beacons.
*/
- u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD];
+ __le32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD];
/* the number of beacons in awake mode */
- u32 rcvd_awake_beacons;
+ __le32 rcvd_awake_beacons;
} __attribute__ ((packed));
struct acx_mic_statistics {
- u32 rx_pkts;
- u32 calc_failure;
+ __le32 rx_pkts;
+ __le32 calc_failure;
} __attribute__ ((packed));
struct acx_aes_statistics {
- u32 encrypt_fail;
- u32 decrypt_fail;
- u32 encrypt_packets;
- u32 decrypt_packets;
- u32 encrypt_interrupt;
- u32 decrypt_interrupt;
+ __le32 encrypt_fail;
+ __le32 decrypt_fail;
+ __le32 encrypt_packets;
+ __le32 decrypt_packets;
+ __le32 encrypt_interrupt;
+ __le32 decrypt_interrupt;
} __attribute__ ((packed));
struct acx_event_statistics {
- u32 heart_beat;
- u32 calibration;
- u32 rx_mismatch;
- u32 rx_mem_empty;
- u32 rx_pool;
- u32 oom_late;
- u32 phy_transmit_error;
- u32 tx_stuck;
+ __le32 heart_beat;
+ __le32 calibration;
+ __le32 rx_mismatch;
+ __le32 rx_mem_empty;
+ __le32 rx_pool;
+ __le32 oom_late;
+ __le32 phy_transmit_error;
+ __le32 tx_stuck;
} __attribute__ ((packed));
struct acx_ps_statistics {
- u32 pspoll_timeouts;
- u32 upsd_timeouts;
- u32 upsd_max_sptime;
- u32 upsd_max_apturn;
- u32 pspoll_max_apturn;
- u32 pspoll_utilization;
- u32 upsd_utilization;
+ __le32 pspoll_timeouts;
+ __le32 upsd_timeouts;
+ __le32 upsd_max_sptime;
+ __le32 upsd_max_apturn;
+ __le32 pspoll_max_apturn;
+ __le32 pspoll_utilization;
+ __le32 upsd_utilization;
} __attribute__ ((packed));
struct acx_rxpipe_statistics {
- u32 rx_prep_beacon_drop;
- u32 descr_host_int_trig_rx_data;
- u32 beacon_buffer_thres_host_int_trig_rx_data;
- u32 missed_beacon_host_int_trig_rx_data;
- u32 tx_xfr_host_int_trig_rx_data;
+ __le32 rx_prep_beacon_drop;
+ __le32 descr_host_int_trig_rx_data;
+ __le32 beacon_buffer_thres_host_int_trig_rx_data;
+ __le32 missed_beacon_host_int_trig_rx_data;
+ __le32 tx_xfr_host_int_trig_rx_data;
} __attribute__ ((packed));
struct acx_statistics {
@@ -946,13 +829,8 @@ struct acx_statistics {
struct acx_rxpipe_statistics rxpipe;
} __attribute__ ((packed));
-#define ACX_MAX_RATE_CLASSES 8
-#define ACX_RATE_MASK_UNSPECIFIED 0
-#define ACX_RATE_MASK_ALL 0x1eff
-#define ACX_RATE_RETRY_LIMIT 10
-
struct acx_rate_class {
- u32 enabled_rates;
+ __le32 enabled_rates;
u8 short_retry_limit;
u8 long_retry_limit;
u8 aflags;
@@ -962,47 +840,20 @@ struct acx_rate_class {
struct acx_rate_policy {
struct acx_header header;
- u32 rate_class_cnt;
- struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES];
+ __le32 rate_class_cnt;
+ struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES];
} __attribute__ ((packed));
-#define WL1271_ACX_AC_COUNT 4
-
struct acx_ac_cfg {
struct acx_header header;
u8 ac;
u8 cw_min;
- u16 cw_max;
+ __le16 cw_max;
u8 aifsn;
u8 reserved;
- u16 tx_op_limit;
+ __le16 tx_op_limit;
} __attribute__ ((packed));
-enum wl1271_acx_ac {
- WL1271_ACX_AC_BE = 0,
- WL1271_ACX_AC_BK = 1,
- WL1271_ACX_AC_VI = 2,
- WL1271_ACX_AC_VO = 3,
- WL1271_ACX_AC_CTS2SELF = 4,
- WL1271_ACX_AC_ANY_TID = 0x1F,
- WL1271_ACX_AC_INVALID = 0xFF,
-};
-
-enum wl1271_acx_ps_scheme {
- WL1271_ACX_PS_SCHEME_LEGACY = 0,
- WL1271_ACX_PS_SCHEME_UPSD_TRIGGER = 1,
- WL1271_ACX_PS_SCHEME_LEGACY_PSPOLL = 2,
- WL1271_ACX_PS_SCHEME_SAPSD = 3,
-};
-
-enum wl1271_acx_ack_policy {
- WL1271_ACX_ACK_POLICY_LEGACY = 0,
- WL1271_ACX_ACK_POLICY_NO_ACK = 1,
- WL1271_ACX_ACK_POLICY_BLOCK = 2,
-};
-
-#define WL1271_ACX_TID_COUNT 7
-
struct acx_tid_config {
struct acx_header header;
u8 queue_id;
@@ -1011,22 +862,19 @@ struct acx_tid_config {
u8 ps_scheme;
u8 ack_policy;
u8 padding[3];
- u32 apsd_conf[2];
+ __le32 apsd_conf[2];
} __attribute__ ((packed));
struct acx_frag_threshold {
struct acx_header header;
- u16 frag_threshold;
+ __le16 frag_threshold;
u8 padding[2];
} __attribute__ ((packed));
-#define WL1271_ACX_TX_COMPL_TIMEOUT 5
-#define WL1271_ACX_TX_COMPL_THRESHOLD 5
-
struct acx_tx_config_options {
struct acx_header header;
- u16 tx_compl_timeout; /* msec */
- u16 tx_compl_threshold; /* number of packets */
+ __le16 tx_compl_timeout; /* msec */
+ __le16 tx_compl_threshold; /* number of packets */
} __attribute__ ((packed));
#define ACX_RX_MEM_BLOCKS 64
@@ -1041,79 +889,87 @@ struct wl1271_acx_config_memory {
u8 tx_min_mem_block_num;
u8 num_stations;
u8 num_ssid_profiles;
- u32 total_tx_descriptors;
+ __le32 total_tx_descriptors;
} __attribute__ ((packed));
struct wl1271_acx_mem_map {
struct acx_header header;
- void *code_start;
- void *code_end;
+ __le32 code_start;
+ __le32 code_end;
- void *wep_defkey_start;
- void *wep_defkey_end;
+ __le32 wep_defkey_start;
+ __le32 wep_defkey_end;
- void *sta_table_start;
- void *sta_table_end;
+ __le32 sta_table_start;
+ __le32 sta_table_end;
- void *packet_template_start;
- void *packet_template_end;
+ __le32 packet_template_start;
+ __le32 packet_template_end;
/* Address of the TX result interface (control block) */
- u32 tx_result;
- u32 tx_result_queue_start;
+ __le32 tx_result;
+ __le32 tx_result_queue_start;
- void *queue_memory_start;
- void *queue_memory_end;
+ __le32 queue_memory_start;
+ __le32 queue_memory_end;
- u32 packet_memory_pool_start;
- u32 packet_memory_pool_end;
+ __le32 packet_memory_pool_start;
+ __le32 packet_memory_pool_end;
- void *debug_buffer1_start;
- void *debug_buffer1_end;
+ __le32 debug_buffer1_start;
+ __le32 debug_buffer1_end;
- void *debug_buffer2_start;
- void *debug_buffer2_end;
+ __le32 debug_buffer2_start;
+ __le32 debug_buffer2_end;
/* Number of blocks FW allocated for TX packets */
- u32 num_tx_mem_blocks;
+ __le32 num_tx_mem_blocks;
/* Number of blocks FW allocated for RX packets */
- u32 num_rx_mem_blocks;
+ __le32 num_rx_mem_blocks;
/* the following 4 fields are valid in SLAVE mode only */
u8 *tx_cbuf;
u8 *rx_cbuf;
- void *rx_ctrl;
- void *tx_ctrl;
+ __le32 rx_ctrl;
+ __le32 tx_ctrl;
} __attribute__ ((packed));
-enum wl1271_acx_rx_queue_type {
- RX_QUEUE_TYPE_RX_LOW_PRIORITY, /* All except the high priority */
- RX_QUEUE_TYPE_RX_HIGH_PRIORITY, /* Management and voice packets */
- RX_QUEUE_TYPE_NUM,
- RX_QUEUE_TYPE_MAX = USHORT_MAX
-};
-
-#define WL1271_RX_INTR_THRESHOLD_DEF 0 /* no pacing, send interrupt on
- * every event */
-#define WL1271_RX_INTR_THRESHOLD_MIN 0
-#define WL1271_RX_INTR_THRESHOLD_MAX 15
-
-#define WL1271_RX_INTR_TIMEOUT_DEF 5
-#define WL1271_RX_INTR_TIMEOUT_MIN 1
-#define WL1271_RX_INTR_TIMEOUT_MAX 100
-
struct wl1271_acx_rx_config_opt {
struct acx_header header;
- u16 mblk_threshold;
- u16 threshold;
- u16 timeout;
+ __le16 mblk_threshold;
+ __le16 threshold;
+ __le16 timeout;
u8 queue_type;
u8 reserved;
} __attribute__ ((packed));
+
+struct wl1271_acx_bet_enable {
+ struct acx_header header;
+
+ u8 enable;
+ u8 max_consecutive;
+ u8 padding[2];
+} __attribute__ ((packed));
+
+#define ACX_IPV4_VERSION 4
+#define ACX_IPV6_VERSION 6
+#define ACX_IPV4_ADDR_SIZE 4
+struct wl1271_acx_arp_filter {
+ struct acx_header header;
+ u8 version; /* ACX_IPV4_VERSION, ACX_IPV6_VERSION */
+ u8 enable; /* 1 to enable ARP filtering, 0 to disable */
+ u8 padding[2];
+ u8 address[16]; /* The configured device IP address - all ARP
+ requests directed to this IP address will pass
+ through. For IPv4, the first four bytes are
+ used. */
+} __attribute__((packed));
+
+
enum {
ACX_WAKE_UP_CONDITIONS = 0x0002,
ACX_MEM_CFG = 0x0003,
@@ -1170,6 +1026,9 @@ enum {
ACX_PEER_HT_CAP = 0x0057,
ACX_HT_BSS_OPERATION = 0x0058,
ACX_COEX_ACTIVITY = 0x0059,
+ ACX_SET_SMART_REFLEX_DEBUG = 0x005A,
+ ACX_SET_SMART_REFLEX_STATE = 0x005B,
+ ACX_SET_SMART_REFLEX_PARAMS = 0x005F,
DOT11_RX_MSDU_LIFE_TIME = 0x1004,
DOT11_CUR_TX_PWR = 0x100D,
DOT11_RX_DOT11_MODE = 0x1012,
@@ -1182,23 +1041,24 @@ enum {
};
-int wl1271_acx_wake_up_conditions(struct wl1271 *wl, u8 wake_up_event,
- u8 listen_interval);
+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,
struct acx_header *mem_map, size_t len);
-int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time);
+int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl);
int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter);
int wl1271_acx_pd_threshold(struct wl1271 *wl);
int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time);
-int wl1271_acx_group_address_tbl(struct wl1271 *wl);
+int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
+ void *mc_list, u32 mc_list_len);
int wl1271_acx_service_period_timeout(struct wl1271 *wl);
int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold);
-int wl1271_acx_beacon_filter_opt(struct wl1271 *wl);
+int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter);
int wl1271_acx_beacon_filter_table(struct wl1271 *wl);
+int wl1271_acx_conn_monit_params(struct wl1271 *wl);
int wl1271_acx_sg_enable(struct wl1271 *wl);
int wl1271_acx_sg_cfg(struct wl1271 *wl);
int wl1271_acx_cca_threshold(struct wl1271 *wl);
@@ -1207,9 +1067,9 @@ int wl1271_acx_aid(struct wl1271 *wl, u16 aid);
int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask);
int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble);
int wl1271_acx_cts_protect(struct wl1271 *wl,
- enum acx_ctsprotect_type ctsprotect);
+ enum acx_ctsprotect_type ctsprotect);
int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats);
-int wl1271_acx_rate_policies(struct wl1271 *wl);
+int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates);
int wl1271_acx_ac_cfg(struct wl1271 *wl);
int wl1271_acx_tid_cfg(struct wl1271 *wl);
int wl1271_acx_frag_threshold(struct wl1271 *wl);
@@ -1217,5 +1077,9 @@ int wl1271_acx_tx_config_options(struct wl1271 *wl);
int wl1271_acx_mem_cfg(struct wl1271 *wl);
int wl1271_acx_init_mem_config(struct wl1271 *wl);
int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
+int wl1271_acx_smart_reflex(struct wl1271 *wl);
+int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable);
+int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
+ u8 version);
#endif /* __WL1271_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c
index 8228ef474a7e..ba4a2b4f0f56 100644
--- a/drivers/net/wireless/wl12xx/wl1271_boot.c
+++ b/drivers/net/wireless/wl12xx/wl1271_boot.c
@@ -39,6 +39,14 @@ static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
.start = REGISTERS_BASE,
.size = 0x00008800
},
+ .mem2 = {
+ .start = 0x00000000,
+ .size = 0x00000000
+ },
+ .mem3 = {
+ .start = 0x00000000,
+ .size = 0x00000000
+ },
},
[PART_WORK] = {
@@ -48,7 +56,15 @@ static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
},
.reg = {
.start = REGISTERS_BASE,
- .size = 0x0000b000
+ .size = 0x0000a000
+ },
+ .mem2 = {
+ .start = 0x003004f8,
+ .size = 0x00000004
+ },
+ .mem3 = {
+ .start = 0x00040404,
+ .size = 0x00000000
},
},
@@ -60,6 +76,14 @@ static struct wl1271_partition_set part_table[PART_TABLE_LEN] = {
.reg = {
.start = DRPW_BASE,
.size = 0x00006000
+ },
+ .mem2 = {
+ .start = 0x00000000,
+ .size = 0x00000000
+ },
+ .mem3 = {
+ .start = 0x00000000,
+ .size = 0x00000000
}
}
};
@@ -69,19 +93,19 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag)
u32 cpu_ctrl;
/* 10.5.0 run the firmware (I) */
- cpu_ctrl = wl1271_reg_read32(wl, ACX_REG_ECPU_CONTROL);
+ cpu_ctrl = wl1271_spi_read32(wl, ACX_REG_ECPU_CONTROL);
/* 10.5.1 run the firmware (II) */
cpu_ctrl |= flag;
- wl1271_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
+ wl1271_spi_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
}
static void wl1271_boot_fw_version(struct wl1271 *wl)
{
struct wl1271_static_data static_data;
- wl1271_spi_mem_read(wl, wl->cmd_box_addr,
- &static_data, sizeof(static_data));
+ wl1271_spi_read(wl, wl->cmd_box_addr,
+ &static_data, sizeof(static_data), false);
strncpy(wl->chip.fw_ver, static_data.fw_version,
sizeof(wl->chip.fw_ver));
@@ -93,8 +117,9 @@ static void wl1271_boot_fw_version(struct wl1271 *wl)
static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
size_t fw_data_len, u32 dest)
{
+ struct wl1271_partition_set partition;
int addr, chunk_num, partition_limit;
- u8 *p;
+ u8 *p, *chunk;
/* whal_FwCtrl_LoadFwImageSm() */
@@ -103,16 +128,20 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d",
fw_data_len, CHUNK_SIZE);
-
if ((fw_data_len % 4) != 0) {
wl1271_error("firmware length not multiple of four");
return -EIO;
}
- wl1271_set_partition(wl, dest,
- part_table[PART_DOWN].mem.size,
- part_table[PART_DOWN].reg.start,
- part_table[PART_DOWN].reg.size);
+ chunk = kmalloc(CHUNK_SIZE, GFP_KERNEL);
+ if (!chunk) {
+ wl1271_error("allocation for firmware upload chunk failed");
+ return -ENOMEM;
+ }
+
+ memcpy(&partition, &part_table[PART_DOWN], sizeof(partition));
+ partition.mem.start = dest;
+ wl1271_set_partition(wl, &partition);
/* 10.1 set partition limit and chunk num */
chunk_num = 0;
@@ -125,21 +154,17 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
addr = dest + chunk_num * CHUNK_SIZE;
partition_limit = chunk_num * CHUNK_SIZE +
part_table[PART_DOWN].mem.size;
-
- /* FIXME: Over 80 chars! */
- wl1271_set_partition(wl,
- addr,
- part_table[PART_DOWN].mem.size,
- part_table[PART_DOWN].reg.start,
- part_table[PART_DOWN].reg.size);
+ partition.mem.start = addr;
+ wl1271_set_partition(wl, &partition);
}
/* 10.3 upload the chunk */
addr = dest + chunk_num * CHUNK_SIZE;
p = buf + chunk_num * CHUNK_SIZE;
+ memcpy(chunk, p, CHUNK_SIZE);
wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
p, addr);
- wl1271_spi_mem_write(wl, addr, p, CHUNK_SIZE);
+ wl1271_spi_write(wl, addr, chunk, CHUNK_SIZE, false);
chunk_num++;
}
@@ -147,28 +172,31 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
/* 10.4 upload the last chunk */
addr = dest + chunk_num * CHUNK_SIZE;
p = buf + chunk_num * CHUNK_SIZE;
+ memcpy(chunk, p, fw_data_len % CHUNK_SIZE);
wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x",
fw_data_len % CHUNK_SIZE, p, addr);
- wl1271_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
+ wl1271_spi_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false);
+ kfree(chunk);
return 0;
}
static int wl1271_boot_upload_firmware(struct wl1271 *wl)
{
u32 chunks, addr, len;
+ int ret = 0;
u8 *fw;
fw = wl->fw;
- chunks = be32_to_cpup((u32 *) fw);
+ chunks = be32_to_cpup((__be32 *) fw);
fw += sizeof(u32);
wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks);
while (chunks--) {
- addr = be32_to_cpup((u32 *) fw);
+ addr = be32_to_cpup((__be32 *) fw);
fw += sizeof(u32);
- len = be32_to_cpup((u32 *) fw);
+ len = be32_to_cpup((__be32 *) fw);
fw += sizeof(u32);
if (len > 300000) {
@@ -177,11 +205,13 @@ static int wl1271_boot_upload_firmware(struct wl1271 *wl)
}
wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u",
chunks, addr, len);
- wl1271_boot_upload_firmware_chunk(wl, fw, len, addr);
+ ret = wl1271_boot_upload_firmware_chunk(wl, fw, len, addr);
+ if (ret != 0)
+ break;
fw += len;
}
- return 0;
+ return ret;
}
static int wl1271_boot_upload_nvs(struct wl1271 *wl)
@@ -235,7 +265,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
wl1271_debug(DEBUG_BOOT,
"nvs burst write 0x%x: 0x%x",
dest_addr, val);
- wl1271_reg_write32(wl, dest_addr, val);
+ wl1271_spi_write32(wl, dest_addr, val);
nvs_ptr += 4;
dest_addr += 4;
@@ -253,20 +283,18 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
/* 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].mem.start,
- part_table[PART_WORK].mem.size,
- part_table[PART_WORK].reg.start,
- part_table[PART_WORK].reg.size);
+ wl1271_set_partition(wl, &part_table[PART_WORK]);
/* Copy the NVS tables to a new block to ensure alignment */
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_spi_mem_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len);
+ wl1271_spi_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false);
kfree(nvs_aligned);
return 0;
@@ -275,9 +303,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
static void wl1271_boot_enable_interrupts(struct wl1271 *wl)
{
enable_irq(wl->irq);
- wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
+ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
- wl1271_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
+ wl1271_spi_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
}
static int wl1271_boot_soft_reset(struct wl1271 *wl)
@@ -286,12 +314,13 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl)
u32 boot_data;
/* perform soft reset */
- wl1271_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
+ wl1271_spi_write32(wl, ACX_REG_SLV_SOFT_RESET,
+ ACX_SLV_SOFT_RESET_BIT);
/* SOFT_RESET is self clearing */
timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
while (1) {
- boot_data = wl1271_reg_read32(wl, ACX_REG_SLV_SOFT_RESET);
+ boot_data = wl1271_spi_read32(wl, ACX_REG_SLV_SOFT_RESET);
wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
break;
@@ -307,10 +336,10 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl)
}
/* disable Rx/Tx */
- wl1271_reg_write32(wl, ENABLE, 0x0);
+ wl1271_spi_write32(wl, ENABLE, 0x0);
/* disable auto calibration on start*/
- wl1271_reg_write32(wl, SPARE_A2, 0xffff);
+ wl1271_spi_write32(wl, SPARE_A2, 0xffff);
return 0;
}
@@ -322,7 +351,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
- chip_id = wl1271_reg_read32(wl, CHIP_ID_B);
+ chip_id = wl1271_spi_read32(wl, CHIP_ID_B);
wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
@@ -335,7 +364,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
loop = 0;
while (loop++ < INIT_LOOP) {
udelay(INIT_LOOP_DELAY);
- interrupt = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ interrupt = wl1271_spi_read32(wl,
+ ACX_REG_INTERRUPT_NO_CLEAR);
if (interrupt == 0xffffffff) {
wl1271_error("error reading hardware complete "
@@ -344,7 +374,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
}
/* check that ACX_INTR_INIT_COMPLETE is enabled */
else if (interrupt & WL1271_ACX_INTR_INIT_COMPLETE) {
- wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
+ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK,
WL1271_ACX_INTR_INIT_COMPLETE);
break;
}
@@ -357,17 +387,13 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
}
/* get hardware config command mail box */
- wl->cmd_box_addr = wl1271_reg_read32(wl, REG_COMMAND_MAILBOX_PTR);
+ wl->cmd_box_addr = wl1271_spi_read32(wl, REG_COMMAND_MAILBOX_PTR);
/* get hardware config event mail box */
- wl->event_box_addr = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
+ wl->event_box_addr = wl1271_spi_read32(wl, REG_EVENT_MAILBOX_PTR);
/* set the working partition to its "running" mode offset */
- wl1271_set_partition(wl,
- part_table[PART_WORK].mem.start,
- part_table[PART_WORK].mem.size,
- part_table[PART_WORK].reg.start,
- part_table[PART_WORK].reg.size);
+ wl1271_set_partition(wl, &part_table[PART_WORK]);
wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
wl->cmd_box_addr, wl->event_box_addr);
@@ -379,11 +405,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
* ready to receive event from the command mailbox
*/
- /* enable gpio interrupts */
- wl1271_boot_enable_interrupts(wl);
-
- /* unmask all mbox events */
- wl->event_mask = 0xffffffff;
+ /* unmask required mbox events */
+ wl->event_mask = BSS_LOSE_EVENT_ID |
+ SCAN_COMPLETE_EVENT_ID;
ret = wl1271_event_unmask(wl);
if (ret < 0) {
@@ -399,34 +423,13 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
static int wl1271_boot_write_irq_polarity(struct wl1271 *wl)
{
- u32 polarity, status, i;
-
- wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY);
- wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_READ);
-
- /* Wait until the command is complete (ie. bit 18 is set) */
- for (i = 0; i < OCP_CMD_LOOP; i++) {
- polarity = wl1271_reg_read32(wl, OCP_DATA_READ);
- if (polarity & OCP_READY_MASK)
- break;
- }
- if (i == OCP_CMD_LOOP) {
- wl1271_error("OCP command timeout!");
- return -EIO;
- }
+ u32 polarity;
- status = polarity & OCP_STATUS_MASK;
- if (status != OCP_STATUS_OK) {
- wl1271_error("OCP command failed (%d)", status);
- return -EIO;
- }
+ polarity = wl1271_top_reg_read(wl, OCP_REG_POLARITY);
/* We use HIGH polarity, so unset the LOW bit */
polarity &= ~POLARITY_LOW;
-
- wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY);
- wl1271_reg_write32(wl, OCP_DATA_WRITE, polarity);
- wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_WRITE);
+ wl1271_top_reg_write(wl, OCP_REG_POLARITY, polarity);
return 0;
}
@@ -436,16 +439,32 @@ int wl1271_boot(struct wl1271 *wl)
int ret = 0;
u32 tmp, clk, pause;
- if (REF_CLOCK == 0 || REF_CLOCK == 2)
- /* ref clk: 19.2/38.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)
/* ref clk: 26/52 */
clk = 0x5;
- wl1271_reg_write32(wl, PLL_PARAMETERS, clk);
+ if (REF_CLOCK != 0) {
+ u16 val;
+ /* Set clock type */
+ val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE);
+ val &= FREF_CLK_TYPE_BITS;
+ val |= CLK_REQ_PRCM;
+ wl1271_top_reg_write(wl, OCP_REG_CLK_TYPE, val);
+ } else {
+ u16 val;
+ /* Set clock polarity */
+ val = wl1271_top_reg_read(wl, OCP_REG_CLK_POLARITY);
+ val &= FREF_CLK_POLARITY_BITS;
+ val |= CLK_REQ_OUTN_SEL;
+ wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val);
+ }
+
+ wl1271_spi_write32(wl, PLL_PARAMETERS, clk);
- pause = wl1271_reg_read32(wl, PLL_PARAMETERS);
+ pause = wl1271_spi_read32(wl, PLL_PARAMETERS);
wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
@@ -454,39 +473,31 @@ int wl1271_boot(struct wl1271 *wl)
* 0x3ff (magic number ). How does
* this work?! */
pause |= WU_COUNTER_PAUSE_VAL;
- wl1271_reg_write32(wl, WU_COUNTER_PAUSE, pause);
+ wl1271_spi_write32(wl, WU_COUNTER_PAUSE, pause);
/* Continue the ELP wake up sequence */
- wl1271_reg_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
+ wl1271_spi_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
udelay(500);
- wl1271_set_partition(wl,
- part_table[PART_DRPW].mem.start,
- part_table[PART_DRPW].mem.size,
- part_table[PART_DRPW].reg.start,
- part_table[PART_DRPW].reg.size);
+ wl1271_set_partition(wl, &part_table[PART_DRPW]);
/* Read-modify-write DRPW_SCRATCH_START register (see next state)
to be used by DRPw FW. The RTRIM value will be added by the FW
before taking DRPw out of reset */
wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START);
- clk = wl1271_reg_read32(wl, DRPW_SCRATCH_START);
+ clk = wl1271_spi_read32(wl, DRPW_SCRATCH_START);
wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
/* 2 */
clk |= (REF_CLOCK << 1) << 4;
- wl1271_reg_write32(wl, DRPW_SCRATCH_START, clk);
+ wl1271_spi_write32(wl, DRPW_SCRATCH_START, clk);
- wl1271_set_partition(wl,
- part_table[PART_WORK].mem.start,
- part_table[PART_WORK].mem.size,
- part_table[PART_WORK].reg.start,
- part_table[PART_WORK].reg.size);
+ wl1271_set_partition(wl, &part_table[PART_WORK]);
/* Disable interrupts */
- wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
+ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
ret = wl1271_boot_soft_reset(wl);
if (ret < 0)
@@ -501,21 +512,22 @@ int wl1271_boot(struct wl1271 *wl)
* ACX_EEPROMLESS_IND_REG */
wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG");
- wl1271_reg_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG);
+ wl1271_spi_write32(wl, ACX_EEPROMLESS_IND_REG,
+ ACX_EEPROMLESS_IND_REG);
- tmp = wl1271_reg_read32(wl, CHIP_ID_B);
+ tmp = wl1271_spi_read32(wl, CHIP_ID_B);
wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
/* 6. read the EEPROM parameters */
- tmp = wl1271_reg_read32(wl, SCR_PAD2);
+ tmp = wl1271_spi_read32(wl, SCR_PAD2);
ret = wl1271_boot_write_irq_polarity(wl);
if (ret < 0)
goto out;
/* FIXME: Need to check whether this is really what we want */
- wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
+ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
WL1271_ACX_ALL_EVENTS_VECTOR);
/* WL1271: The reference driver skips steps 7 to 10 (jumps directly
@@ -530,6 +542,9 @@ int wl1271_boot(struct wl1271 *wl)
if (ret < 0)
goto out;
+ /* Enable firmware interrupts now */
+ wl1271_boot_enable_interrupts(wl);
+
/* set the wl1271 default filters */
wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.h b/drivers/net/wireless/wl12xx/wl1271_boot.h
index b0d8fb46a439..412443ee655a 100644
--- a/drivers/net/wireless/wl12xx/wl1271_boot.h
+++ b/drivers/net/wireless/wl12xx/wl1271_boot.h
@@ -50,23 +50,17 @@ struct wl1271_static_data {
#define WU_COUNTER_PAUSE_VAL 0x3FF
#define WELP_ARM_COMMAND_VAL 0x4
-#define OCP_CMD_LOOP 32
-
-#define OCP_CMD_WRITE 0x1
-#define OCP_CMD_READ 0x2
-
-#define OCP_READY_MASK BIT(18)
-#define OCP_STATUS_MASK (BIT(16) | BIT(17))
-
-#define OCP_STATUS_NO_RESP 0x00000
-#define OCP_STATUS_OK 0x10000
-#define OCP_STATUS_REQ_FAILED 0x20000
-#define OCP_STATUS_RESP_ERROR 0x30000
-
-#define OCP_REG_POLARITY 0x30032
+#define OCP_REG_POLARITY 0x0064
+#define OCP_REG_CLK_TYPE 0x0448
+#define OCP_REG_CLK_POLARITY 0x0cb2
#define CMD_MBOX_ADDRESS 0x407B4
#define POLARITY_LOW BIT(1)
+#define FREF_CLK_TYPE_BITS 0xfffffe7f
+#define CLK_REQ_PRCM 0x100
+#define FREF_CLK_POLARITY_BITS 0xfffff8ff
+#define CLK_REQ_OUTN_SEL 0x700
+
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c
index 2a4351ff54dc..0666328ce9ab 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.c
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c
@@ -50,18 +50,18 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len)
int ret = 0;
cmd = buf;
- cmd->id = id;
+ cmd->id = cpu_to_le16(id);
cmd->status = 0;
WARN_ON(len % 4 != 0);
- wl1271_spi_mem_write(wl, wl->cmd_box_addr, buf, len);
+ wl1271_spi_write(wl, wl->cmd_box_addr, buf, len, false);
- wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
+ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
- intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
if (time_after(jiffies, timeout)) {
wl1271_error("command complete timeout");
@@ -71,17 +71,17 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len)
msleep(1);
- intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
}
- wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
+ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK,
WL1271_ACX_INTR_CMD_COMPLETE);
out:
return ret;
}
-int wl1271_cmd_cal_channel_tune(struct wl1271 *wl)
+static int wl1271_cmd_cal_channel_tune(struct wl1271 *wl)
{
struct wl1271_cmd_cal_channel_tune *cmd;
int ret = 0;
@@ -104,7 +104,7 @@ int wl1271_cmd_cal_channel_tune(struct wl1271 *wl)
return ret;
}
-int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl)
+static int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl)
{
struct wl1271_cmd_cal_update_ref_point *cmd;
int ret = 0;
@@ -129,7 +129,7 @@ int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl)
return ret;
}
-int wl1271_cmd_cal_p2g(struct wl1271 *wl)
+static int wl1271_cmd_cal_p2g(struct wl1271 *wl)
{
struct wl1271_cmd_cal_p2g *cmd;
int ret = 0;
@@ -150,7 +150,7 @@ int wl1271_cmd_cal_p2g(struct wl1271 *wl)
return ret;
}
-int wl1271_cmd_cal(struct wl1271 *wl)
+static int wl1271_cmd_cal(struct wl1271 *wl)
{
/*
* FIXME: we must make sure that we're not sleeping when calibration
@@ -175,11 +175,9 @@ int wl1271_cmd_cal(struct wl1271 *wl)
return ret;
}
-int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval,
- u16 beacon_interval, u8 wait)
+int wl1271_cmd_join(struct wl1271 *wl)
{
static bool do_cal = true;
- unsigned long timeout;
struct wl1271_cmd_join *join;
int ret, i;
u8 *bssid;
@@ -193,6 +191,18 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval,
do_cal = false;
}
+ /* FIXME: This is a workaround, because with the current stack, we
+ * cannot know when we have disassociated. So, if we have already
+ * joined, we disconnect before joining again. */
+ if (wl->joined) {
+ ret = wl1271_cmd_disconnect(wl);
+ if (ret < 0) {
+ wl1271_error("failed to disconnect before rejoining");
+ goto out;
+ }
+
+ wl->joined = false;
+ }
join = kzalloc(sizeof(*join), GFP_KERNEL);
if (!join) {
@@ -207,15 +217,34 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval,
for (i = 0; i < ETH_ALEN; i++)
bssid[i] = wl->bssid[ETH_ALEN - i - 1];
- join->rx_config_options = wl->rx_config;
- join->rx_filter_options = wl->rx_filter;
+ join->rx_config_options = cpu_to_le32(wl->rx_config);
+ join->rx_filter_options = cpu_to_le32(wl->rx_filter);
+ join->bss_type = wl->bss_type;
- join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
- RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;
+ /*
+ * FIXME: disable temporarily all filters because after commit
+ * 9cef8737 "mac80211: fix managed mode BSSID handling" broke
+ * association. The filter logic needs to be implemented properly
+ * and once that is done, this hack can be removed.
+ */
+ join->rx_config_options = cpu_to_le32(0);
+ join->rx_filter_options = cpu_to_le32(WL1271_DEFAULT_RX_FILTER);
+
+ if (wl->band == IEEE80211_BAND_2GHZ)
+ join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_1MBPS |
+ CONF_HW_BIT_RATE_2MBPS |
+ CONF_HW_BIT_RATE_5_5MBPS |
+ CONF_HW_BIT_RATE_11MBPS);
+ else {
+ join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ;
+ join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_6MBPS |
+ CONF_HW_BIT_RATE_12MBPS |
+ CONF_HW_BIT_RATE_24MBPS);
+ }
+
+ join->beacon_interval = cpu_to_le16(WL1271_DEFAULT_BEACON_INT);
+ join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD;
- join->beacon_interval = beacon_interval;
- join->dtim_interval = dtim_interval;
- join->bss_type = bss_type;
join->channel = wl->channel;
join->ssid_len = wl->ssid_len;
memcpy(join->ssid, wl->ssid, wl->ssid_len);
@@ -228,6 +257,10 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval,
join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
+ /* reset TX security counters */
+ wl->tx_security_last_seq = 0;
+ wl->tx_security_seq_16 = 0;
+ wl->tx_security_seq_32 = 0;
ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join));
if (ret < 0) {
@@ -235,14 +268,13 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval,
goto out_free;
}
- timeout = msecs_to_jiffies(JOIN_TIMEOUT);
+ wl->joined = true;
/*
* ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
* simplify locking we just sleep instead, for now
*/
- if (wait)
- msleep(10);
+ msleep(10);
out_free:
kfree(join);
@@ -274,19 +306,20 @@ int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer)
if (answer) {
struct wl1271_command *cmd_answer;
+ u16 status;
/*
* The test command got in, we can read the answer.
* The answer would be a wl1271_command, where the
* parameter array contains the actual answer.
*/
- wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
+ wl1271_spi_read(wl, wl->cmd_box_addr, buf, buf_len, false);
cmd_answer = buf;
+ status = le16_to_cpu(cmd_answer->header.status);
- if (cmd_answer->header.status != CMD_STATUS_SUCCESS)
- wl1271_error("TEST command answer error: %d",
- cmd_answer->header.status);
+ if (status != CMD_STATUS_SUCCESS)
+ wl1271_error("TEST command answer error: %d", status);
}
return 0;
@@ -307,10 +340,10 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len)
wl1271_debug(DEBUG_CMD, "cmd interrogate");
- acx->id = id;
+ acx->id = cpu_to_le16(id);
/* payload length, does not include any headers */
- acx->len = len - sizeof(*acx);
+ acx->len = cpu_to_le16(len - sizeof(*acx));
ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx));
if (ret < 0) {
@@ -319,12 +352,12 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len)
}
/* the interrogate command got in, we can read the answer */
- wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, len);
+ wl1271_spi_read(wl, wl->cmd_box_addr, buf, len, false);
acx = buf;
- if (acx->cmd.status != CMD_STATUS_SUCCESS)
+ if (le16_to_cpu(acx->cmd.status) != CMD_STATUS_SUCCESS)
wl1271_error("INTERROGATE command error: %d",
- acx->cmd.status);
+ le16_to_cpu(acx->cmd.status));
out:
return ret;
@@ -345,10 +378,10 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
wl1271_debug(DEBUG_CMD, "cmd configure");
- acx->id = id;
+ acx->id = cpu_to_le16(id);
/* payload length, does not include any headers */
- acx->len = len - sizeof(*acx);
+ acx->len = cpu_to_le16(len - sizeof(*acx));
ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len);
if (ret < 0) {
@@ -414,8 +447,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
int ret = 0;
/* FIXME: this should be in ps.c */
- ret = wl1271_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP,
- wl->listen_int);
+ ret = wl1271_acx_wake_up_conditions(wl);
if (ret < 0) {
wl1271_error("couldn't set wake up conditions");
goto out;
@@ -433,7 +465,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
ps_params->send_null_data = 1;
ps_params->retries = 5;
ps_params->hang_over_period = 128;
- ps_params->null_data_rate = 1; /* 1 Mbps */
+ ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */
ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
sizeof(*ps_params));
@@ -464,8 +496,8 @@ int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
WARN_ON(len > MAX_READ_SIZE);
len = min_t(size_t, len, MAX_READ_SIZE);
- cmd->addr = addr;
- cmd->size = len;
+ cmd->addr = cpu_to_le32(addr);
+ cmd->size = cpu_to_le32(len);
ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd));
if (ret < 0) {
@@ -474,11 +506,11 @@ int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
}
/* the read command got in, we can now read the answer */
- wl1271_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd));
+ wl1271_spi_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd), false);
- if (cmd->header.status != CMD_STATUS_SUCCESS)
+ if (le16_to_cpu(cmd->header.status) != CMD_STATUS_SUCCESS)
wl1271_error("error in read command result: %d",
- cmd->header.status);
+ le16_to_cpu(cmd->header.status));
memcpy(answer, cmd->value, len);
@@ -488,14 +520,31 @@ out:
}
int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
- u8 active_scan, u8 high_prio, u8 num_channels,
+ u8 active_scan, u8 high_prio, u8 band,
u8 probe_requests)
{
struct wl1271_cmd_trigger_scan_to *trigger = NULL;
struct wl1271_cmd_scan *params = NULL;
- int i, ret;
+ struct ieee80211_channel *channels;
+ int i, j, n_ch, ret;
u16 scan_options = 0;
+ u8 ieee_band;
+
+ if (band == WL1271_SCAN_BAND_2_4_GHZ)
+ ieee_band = IEEE80211_BAND_2GHZ;
+ else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled())
+ ieee_band = IEEE80211_BAND_2GHZ;
+ else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled())
+ ieee_band = IEEE80211_BAND_5GHZ;
+ else
+ return -EINVAL;
+
+ if (wl->hw->wiphy->bands[ieee_band]->channels == NULL)
+ return -EINVAL;
+
+ channels = wl->hw->wiphy->bands[ieee_band]->channels;
+ n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels;
if (wl->scanning)
return -EINVAL;
@@ -512,32 +561,43 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
scan_options |= WL1271_SCAN_OPT_PASSIVE;
if (high_prio)
scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH;
- params->params.scan_options = scan_options;
+ params->params.scan_options = cpu_to_le16(scan_options);
- params->params.num_channels = num_channels;
params->params.num_probe_requests = probe_requests;
- params->params.tx_rate = cpu_to_le32(RATE_MASK_2MBPS);
+ /* Let the fw autodetect suitable tx_rate for probes */
+ params->params.tx_rate = 0;
params->params.tid_trigger = 0;
params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
- for (i = 0; i < num_channels; i++) {
- params->channels[i].min_duration =
- cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION);
- params->channels[i].max_duration =
- cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION);
- memset(&params->channels[i].bssid_lsb, 0xff, 4);
- memset(&params->channels[i].bssid_msb, 0xff, 2);
- params->channels[i].early_termination = 0;
- params->channels[i].tx_power_att = WL1271_SCAN_CURRENT_TX_PWR;
- params->channels[i].channel = i + 1;
+ if (band == WL1271_SCAN_BAND_DUAL)
+ params->params.band = WL1271_SCAN_BAND_2_4_GHZ;
+ else
+ params->params.band = band;
+
+ for (i = 0, j = 0; i < n_ch && i < WL1271_SCAN_MAX_CHANNELS; i++) {
+ if (!(channels[i].flags & IEEE80211_CHAN_DISABLED)) {
+ params->channels[j].min_duration =
+ cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION);
+ params->channels[j].max_duration =
+ cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION);
+ memset(&params->channels[j].bssid_lsb, 0xff, 4);
+ memset(&params->channels[j].bssid_msb, 0xff, 2);
+ params->channels[j].early_termination = 0;
+ params->channels[j].tx_power_att =
+ WL1271_SCAN_CURRENT_TX_PWR;
+ params->channels[j].channel = channels[i].hw_value;
+ j++;
+ }
}
+ params->params.num_channels = j;
+
if (len && ssid) {
params->params.ssid_len = len;
memcpy(params->params.ssid, ssid, len);
}
- ret = wl1271_cmd_build_probe_req(wl, ssid, len);
+ ret = wl1271_cmd_build_probe_req(wl, ssid, len, ieee_band);
if (ret < 0) {
wl1271_error("PROBE request template failed");
goto out;
@@ -562,6 +622,19 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
wl->scanning = true;
+ if (wl1271_11a_enabled()) {
+ wl->scan.state = band;
+ if (band == WL1271_SCAN_BAND_DUAL) {
+ wl->scan.active = active_scan;
+ wl->scan.high_prio = high_prio;
+ wl->scan.probe_requests = probe_requests;
+ if (len && ssid) {
+ wl->scan.ssid_len = len;
+ memcpy(wl->scan.ssid, ssid, len);
+ } else
+ wl->scan.ssid_len = 0;
+ }
+ }
ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
if (ret < 0) {
@@ -569,11 +642,12 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
goto out;
}
- wl1271_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
+ wl1271_spi_read(wl, wl->cmd_box_addr, params, sizeof(*params),
+ false);
- if (params->header.status != CMD_STATUS_SUCCESS) {
+ if (le16_to_cpu(params->header.status) != CMD_STATUS_SUCCESS) {
wl1271_error("Scan command error: %d",
- params->header.status);
+ le16_to_cpu(params->header.status));
wl->scanning = false;
ret = -EIO;
goto out;
@@ -603,9 +677,9 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
cmd->len = cpu_to_le16(buf_len);
cmd->template_type = template_id;
- cmd->enabled_rates = ACX_RATE_MASK_UNSPECIFIED;
- cmd->short_retry_limit = ACX_RATE_RETRY_LIMIT;
- cmd->long_retry_limit = ACX_RATE_RETRY_LIMIT;
+ cmd->enabled_rates = cpu_to_le32(wl->conf.tx.rc_conf.enabled_rates);
+ cmd->short_retry_limit = wl->conf.tx.rc_conf.short_retry_limit;
+ cmd->long_retry_limit = wl->conf.tx.rc_conf.long_retry_limit;
if (buf)
memcpy(cmd->template_data, buf, buf_len);
@@ -623,30 +697,62 @@ out:
return ret;
}
-static int wl1271_build_basic_rates(char *rates)
+static int wl1271_build_basic_rates(char *rates, u8 band)
{
u8 index = 0;
- rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
- rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
- rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB;
- rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB;
+ if (band == IEEE80211_BAND_2GHZ) {
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB;
+ } else if (band == IEEE80211_BAND_5GHZ) {
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB;
+ } else {
+ wl1271_error("build_basic_rates invalid band: %d", band);
+ }
return index;
}
-static int wl1271_build_extended_rates(char *rates)
+static int wl1271_build_extended_rates(char *rates, u8 band)
{
u8 index = 0;
- rates[index++] = IEEE80211_OFDM_RATE_6MB;
- rates[index++] = IEEE80211_OFDM_RATE_9MB;
- rates[index++] = IEEE80211_OFDM_RATE_12MB;
- rates[index++] = IEEE80211_OFDM_RATE_18MB;
- rates[index++] = IEEE80211_OFDM_RATE_24MB;
- rates[index++] = IEEE80211_OFDM_RATE_36MB;
- rates[index++] = IEEE80211_OFDM_RATE_48MB;
- rates[index++] = IEEE80211_OFDM_RATE_54MB;
+ if (band == IEEE80211_BAND_2GHZ) {
+ rates[index++] = IEEE80211_OFDM_RATE_6MB;
+ rates[index++] = IEEE80211_OFDM_RATE_9MB;
+ rates[index++] = IEEE80211_OFDM_RATE_12MB;
+ rates[index++] = IEEE80211_OFDM_RATE_18MB;
+ rates[index++] = IEEE80211_OFDM_RATE_24MB;
+ rates[index++] = IEEE80211_OFDM_RATE_36MB;
+ rates[index++] = IEEE80211_OFDM_RATE_48MB;
+ rates[index++] = IEEE80211_OFDM_RATE_54MB;
+ } else if (band == IEEE80211_BAND_5GHZ) {
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB;
+ rates[index++] =
+ IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB;
+ } else {
+ wl1271_error("build_basic_rates invalid band: %d", band);
+ }
return index;
}
@@ -665,7 +771,8 @@ int wl1271_cmd_build_null_data(struct wl1271 *wl)
memcpy(template.header.sa, wl->mac_addr, ETH_ALEN);
template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
- IEEE80211_STYPE_NULLFUNC);
+ IEEE80211_STYPE_NULLFUNC |
+ IEEE80211_FCTL_TODS);
return wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, &template,
sizeof(template));
@@ -678,7 +785,10 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid)
memcpy(template.bssid, wl->bssid, ETH_ALEN);
memcpy(template.ta, wl->mac_addr, ETH_ALEN);
- template.aid = aid;
+
+ /* aid in PS-Poll has its two MSBs each set to 1 */
+ template.aid = cpu_to_le16(1 << 15 | 1 << 14 | aid);
+
template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
return wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, &template,
@@ -686,12 +796,14 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid)
}
-int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len)
+int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len,
+ u8 band)
{
struct wl12xx_probe_req_template template;
struct wl12xx_ie_rates *rates;
char *ptr;
u16 size;
+ int ret;
ptr = (char *)&template;
size = sizeof(struct ieee80211_header);
@@ -713,20 +825,25 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len)
/* Basic Rates */
rates = (struct wl12xx_ie_rates *)ptr;
rates->header.id = WLAN_EID_SUPP_RATES;
- rates->header.len = wl1271_build_basic_rates(rates->rates);
+ rates->header.len = wl1271_build_basic_rates(rates->rates, band);
size += sizeof(struct wl12xx_ie_header) + rates->header.len;
ptr += sizeof(struct wl12xx_ie_header) + rates->header.len;
/* Extended rates */
rates = (struct wl12xx_ie_rates *)ptr;
rates->header.id = WLAN_EID_EXT_SUPP_RATES;
- rates->header.len = wl1271_build_extended_rates(rates->rates);
+ rates->header.len = wl1271_build_extended_rates(rates->rates, band);
size += sizeof(struct wl12xx_ie_header) + rates->header.len;
wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
- return wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
- &template, size);
+ if (band == IEEE80211_BAND_2GHZ)
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
+ &template, size);
+ else
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
+ &template, size);
+ return ret;
}
int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id)
@@ -743,7 +860,7 @@ int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id)
}
cmd->id = id;
- cmd->key_action = KEY_SET_ID;
+ cmd->key_action = cpu_to_le16(KEY_SET_ID);
cmd->key_type = KEY_WEP;
ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd));
@@ -759,7 +876,8 @@ out:
}
int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
- u8 key_size, const u8 *key, const u8 *addr)
+ u8 key_size, const u8 *key, const u8 *addr,
+ u32 tx_seq_32, u16 tx_seq_16)
{
struct wl1271_cmd_set_keys *cmd;
int ret = 0;
@@ -773,16 +891,18 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
if (key_type != KEY_WEP)
memcpy(cmd->addr, addr, ETH_ALEN);
- cmd->key_action = action;
+ cmd->key_action = cpu_to_le16(action);
cmd->key_size = key_size;
cmd->key_type = key_type;
+ cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16);
+ cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32);
+
/* we have only one SSID profile */
cmd->ssid_profile = 0;
cmd->id = id;
- /* FIXME: this is from wl1251, needs to be checked */
if (key_type == KEY_TKIP) {
/*
* We get the key in the following form:
@@ -811,3 +931,34 @@ out:
return ret;
}
+
+int wl1271_cmd_disconnect(struct wl1271 *wl)
+{
+ struct wl1271_cmd_disconnect *cmd;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd disconnect");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->rx_config_options = cpu_to_le32(wl->rx_config);
+ cmd->rx_filter_options = cpu_to_le32(wl->rx_filter);
+ /* disconnect reason is not used in immediate disconnections */
+ cmd->type = DISCONNECT_IMMEDIATE;
+
+ ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1271_error("failed to send disconnect 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 951a8447a516..174b8209dbf3 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h
@@ -30,8 +30,7 @@
struct acx_header;
int wl1271_cmd_send(struct wl1271 *wl, u16 type, void *buf, size_t buf_len);
-int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval,
- u16 beacon_interval, u8 wait);
+int wl1271_cmd_join(struct wl1271 *wl);
int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
@@ -40,16 +39,19 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode);
int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
size_t len);
int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
- u8 active_scan, u8 high_prio, u8 num_channels,
+ u8 active_scan, u8 high_prio, u8 band,
u8 probe_requests);
int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
void *buf, size_t buf_len);
int wl1271_cmd_build_null_data(struct wl1271 *wl);
int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid);
-int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len);
+int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len,
+ u8 band);
int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id);
int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
- u8 key_size, const u8 *key, const u8 *addr);
+ u8 key_size, const u8 *key, const u8 *addr,
+ u32 tx_seq_32, u16 tx_seq_16);
+int wl1271_cmd_disconnect(struct wl1271 *wl);
enum wl1271_commands {
CMD_INTERROGATE = 1, /*use this to read information elements*/
@@ -118,8 +120,8 @@ enum cmd_templ {
#define WL1271_CMD_TEMPL_MAX_SIZE 252
struct wl1271_cmd_header {
- u16 id;
- u16 status;
+ __le16 id;
+ __le16 status;
/* payload */
u8 data[0];
} __attribute__ ((packed));
@@ -172,17 +174,17 @@ struct cmd_read_write_memory {
struct wl1271_cmd_header header;
/* The address of the memory to read from or write to.*/
- u32 addr;
+ __le32 addr;
/* The amount of data in bytes to read from or write to the WiLink
* device.*/
- u32 size;
+ __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];
-};
+} __attribute__ ((packed));
#define CMDMBOX_HEADER_LEN 4
#define CMDMBOX_INFO_ELEM_HEADER_LEN 4
@@ -196,22 +198,23 @@ enum {
#define WL1271_JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */
#define WL1271_JOIN_CMD_TX_SESSION_OFFSET 1
+#define WL1271_JOIN_CMD_BSS_TYPE_5GHZ 0x10
struct wl1271_cmd_join {
struct wl1271_cmd_header header;
- u32 bssid_lsb;
- u16 bssid_msb;
- u16 beacon_interval; /* in TBTTs */
- u32 rx_config_options;
- u32 rx_filter_options;
+ __le32 bssid_lsb;
+ __le16 bssid_msb;
+ __le16 beacon_interval; /* in TBTTs */
+ __le32 rx_config_options;
+ __le32 rx_filter_options;
/*
* The target uses this field to determine the rate at
* which to transmit control frame responses (such as
* ACK or CTS frames).
*/
- u32 basic_rate_set;
+ __le32 basic_rate_set;
u8 dtim_interval;
/*
* bits 0-2: This bitwise field specifies the type
@@ -240,10 +243,10 @@ struct cmd_enabledisable_path {
struct wl1271_cmd_template_set {
struct wl1271_cmd_header header;
- u16 len;
+ __le16 len;
u8 template_type;
u8 index; /* relevant only for KLV_TEMPLATE type */
- u32 enabled_rates;
+ __le32 enabled_rates;
u8 short_retry_limit;
u8 long_retry_limit;
u8 aflags;
@@ -280,18 +283,13 @@ struct wl1271_cmd_ps_params {
* to power save mode.
*/
u8 hang_over_period;
- u32 null_data_rate;
+ __le32 null_data_rate;
} __attribute__ ((packed));
/* HW encryption keys */
#define NUM_ACCESS_CATEGORIES_COPY 4
#define MAX_KEY_SIZE 32
-/* When set, disable HW encryption */
-#define DF_ENCRYPTION_DISABLE 0x01
-/* When set, disable HW decryption */
-#define DF_SNIFF_MODE_ENABLE 0x80
-
enum wl1271_cmd_key_action {
KEY_ADD_OR_REPLACE = 1,
KEY_REMOVE = 2,
@@ -316,9 +314,9 @@ struct wl1271_cmd_set_keys {
u8 addr[ETH_ALEN];
/* key_action_e */
- u16 key_action;
+ __le16 key_action;
- u16 reserved_1;
+ __le16 reserved_1;
/* key size in bytes */
u8 key_size;
@@ -334,8 +332,8 @@ struct wl1271_cmd_set_keys {
u8 id;
u8 reserved_2[6];
u8 key[MAX_KEY_SIZE];
- u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
- u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
+ __le16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
+ __le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
} __attribute__ ((packed));
@@ -347,19 +345,22 @@ struct wl1271_cmd_set_keys {
#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_BAND_DUAL 2
struct basic_scan_params {
- u32 rx_config_options;
- u32 rx_filter_options;
+ __le32 rx_config_options;
+ __le32 rx_filter_options;
/* Scan option flags (WL1271_SCAN_OPT_*) */
- u16 scan_options;
+ __le16 scan_options;
/* Number of scan channels in the list (maximum 30) */
u8 num_channels;
/* This field indicates the number of probe requests to send
per channel for an active scan */
u8 num_probe_requests;
/* Rate bit field for sending the probes */
- u32 tx_rate;
+ __le32 tx_rate;
u8 tid_trigger;
u8 ssid_len;
/* in order to align */
@@ -374,10 +375,10 @@ struct basic_scan_params {
struct basic_scan_channel_params {
/* Duration in TU to wait for frames on a channel for active scan */
- u32 min_duration;
- u32 max_duration;
- u32 bssid_lsb;
- u16 bssid_msb;
+ __le32 min_duration;
+ __le32 max_duration;
+ __le32 bssid_lsb;
+ __le16 bssid_msb;
u8 early_termination;
u8 tx_power_att;
u8 channel;
@@ -397,13 +398,13 @@ struct wl1271_cmd_scan {
struct wl1271_cmd_trigger_scan_to {
struct wl1271_cmd_header header;
- u32 timeout;
-};
+ __le32 timeout;
+} __attribute__ ((packed));
struct wl1271_cmd_test_header {
u8 id;
u8 padding[3];
-};
+} __attribute__ ((packed));
enum wl1271_channel_tune_bands {
WL1271_CHANNEL_TUNE_BAND_2_4,
@@ -425,7 +426,7 @@ struct wl1271_cmd_cal_channel_tune {
u8 band;
u8 channel;
- u16 radio_status;
+ __le16 radio_status;
} __attribute__ ((packed));
struct wl1271_cmd_cal_update_ref_point {
@@ -433,8 +434,8 @@ struct wl1271_cmd_cal_update_ref_point {
struct wl1271_cmd_test_header test;
- s32 ref_power;
- s32 ref_detector;
+ __le32 ref_power;
+ __le32 ref_detector;
u8 sub_band;
u8 padding[3];
} __attribute__ ((packed));
@@ -449,16 +450,42 @@ struct wl1271_cmd_cal_p2g {
struct wl1271_cmd_test_header test;
- u16 len;
+ __le16 len;
u8 buf[MAX_TLV_LENGTH];
u8 type;
u8 padding;
- s16 radio_status;
+ __le16 radio_status;
u8 nvs_version[MAX_NVS_VERSION_LENGTH];
u8 sub_band_mask;
u8 padding2;
} __attribute__ ((packed));
+
+/*
+ * There are three types of disconnections:
+ *
+ * DISCONNECT_IMMEDIATE: the fw doesn't send any frames
+ * DISCONNECT_DEAUTH: the fw generates a DEAUTH request with the reason
+ * we have passed
+ * DISCONNECT_DISASSOC: the fw generates a DESASSOC request with the reason
+ * we have passed
+ */
+enum wl1271_disconnect_type {
+ DISCONNECT_IMMEDIATE,
+ DISCONNECT_DEAUTH,
+ DISCONNECT_DISASSOC
+};
+
+struct wl1271_cmd_disconnect {
+ __le32 rx_config_options;
+ __le32 rx_filter_options;
+
+ __le16 reason;
+ u8 type;
+
+ u8 padding;
+} __attribute__ ((packed));
+
#endif /* __WL1271_CMD_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h
new file mode 100644
index 000000000000..061d47520a32
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1271_conf.h
@@ -0,0 +1,911 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * 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
+ * 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 __WL1271_CONF_H__
+#define __WL1271_CONF_H__
+
+enum {
+ CONF_HW_BIT_RATE_1MBPS = BIT(0),
+ CONF_HW_BIT_RATE_2MBPS = BIT(1),
+ CONF_HW_BIT_RATE_5_5MBPS = BIT(2),
+ CONF_HW_BIT_RATE_6MBPS = BIT(3),
+ CONF_HW_BIT_RATE_9MBPS = BIT(4),
+ CONF_HW_BIT_RATE_11MBPS = BIT(5),
+ CONF_HW_BIT_RATE_12MBPS = BIT(6),
+ CONF_HW_BIT_RATE_18MBPS = BIT(7),
+ CONF_HW_BIT_RATE_22MBPS = BIT(8),
+ CONF_HW_BIT_RATE_24MBPS = BIT(9),
+ CONF_HW_BIT_RATE_36MBPS = BIT(10),
+ CONF_HW_BIT_RATE_48MBPS = BIT(11),
+ CONF_HW_BIT_RATE_54MBPS = BIT(12),
+ CONF_HW_BIT_RATE_MCS_0 = BIT(13),
+ CONF_HW_BIT_RATE_MCS_1 = BIT(14),
+ CONF_HW_BIT_RATE_MCS_2 = BIT(15),
+ CONF_HW_BIT_RATE_MCS_3 = BIT(16),
+ CONF_HW_BIT_RATE_MCS_4 = BIT(17),
+ CONF_HW_BIT_RATE_MCS_5 = BIT(18),
+ CONF_HW_BIT_RATE_MCS_6 = BIT(19),
+ CONF_HW_BIT_RATE_MCS_7 = BIT(20)
+};
+
+enum {
+ CONF_HW_RATE_INDEX_1MBPS = 0,
+ CONF_HW_RATE_INDEX_2MBPS = 1,
+ CONF_HW_RATE_INDEX_5_5MBPS = 2,
+ CONF_HW_RATE_INDEX_6MBPS = 3,
+ CONF_HW_RATE_INDEX_9MBPS = 4,
+ CONF_HW_RATE_INDEX_11MBPS = 5,
+ CONF_HW_RATE_INDEX_12MBPS = 6,
+ CONF_HW_RATE_INDEX_18MBPS = 7,
+ CONF_HW_RATE_INDEX_22MBPS = 8,
+ CONF_HW_RATE_INDEX_24MBPS = 9,
+ CONF_HW_RATE_INDEX_36MBPS = 10,
+ CONF_HW_RATE_INDEX_48MBPS = 11,
+ CONF_HW_RATE_INDEX_54MBPS = 12,
+ CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_54MBPS,
+};
+
+struct conf_sg_settings {
+ /*
+ * Defines the PER threshold in PPM of the BT voice of which reaching
+ * this value will trigger raising the priority of the BT voice by
+ * the BT IP until next NFS sample interval time as defined in
+ * nfs_sample_interval.
+ *
+ * Unit: PER value in PPM (parts per million)
+ * #Error_packets / #Total_packets
+
+ * Range: u32
+ */
+ u32 per_threshold;
+
+ /*
+ * This value is an absolute time in micro-seconds to limit the
+ * maximum scan duration compensation while in SG
+ */
+ u32 max_scan_compensation_time;
+
+ /* Defines the PER threshold of the BT voice of which reaching this
+ * value will trigger raising the priority of the BT voice until next
+ * NFS sample interval time as defined in sample_interval.
+ *
+ * Unit: msec
+ * Range: 1-65000
+ */
+ u16 nfs_sample_interval;
+
+ /*
+ * Defines the load ratio for the BT.
+ * The WLAN ratio is: 100 - load_ratio
+ *
+ * Unit: Percent
+ * Range: 0-100
+ */
+ u8 load_ratio;
+
+ /*
+ * true - Co-ex is allowed to enter/exit P.S automatically and
+ * transparently to the host
+ *
+ * false - Co-ex is disallowed to enter/exit P.S and will trigger an
+ * event to the host to notify for the need to enter/exit P.S
+ * due to BT change state
+ *
+ */
+ u8 auto_ps_mode;
+
+ /*
+ * This parameter defines the compensation percentage of num of probe
+ * requests in case scan is initiated during BT voice/BT ACL
+ * guaranteed link.
+ *
+ * Unit: Percent
+ * Range: 0-255 (0 - No compensation)
+ */
+ u8 probe_req_compensation;
+
+ /*
+ * This parameter defines the compensation percentage of scan window
+ * size in case scan is initiated during BT voice/BT ACL Guaranteed
+ * link.
+ *
+ * Unit: Percent
+ * Range: 0-255 (0 - No compensation)
+ */
+ u8 scan_window_compensation;
+
+ /*
+ * Defines the antenna configuration.
+ *
+ * Range: 0 - Single Antenna; 1 - Dual Antenna
+ */
+ u8 antenna_config;
+
+ /*
+ * The percent out of the Max consecutive beacon miss roaming trigger
+ * which is the threshold for raising the priority of beacon
+ * reception.
+ *
+ * Range: 1-100
+ * N = MaxConsecutiveBeaconMiss
+ * P = coexMaxConsecutiveBeaconMissPrecent
+ * Threshold = MIN( N-1, round(N * P / 100))
+ */
+ u8 beacon_miss_threshold;
+
+ /*
+ * The RX rate threshold below which rate adaptation is assumed to be
+ * occurring at the AP which will raise priority for ACTIVE_RX and RX
+ * SP.
+ *
+ * Range: HW_BIT_RATE_*
+ */
+ u32 rate_adaptation_threshold;
+
+ /*
+ * The SNR above which the RX rate threshold indicating AP rate
+ * adaptation is valid
+ *
+ * Range: -128 - 127
+ */
+ s8 rate_adaptation_snr;
+};
+
+enum conf_rx_queue_type {
+ CONF_RX_QUEUE_TYPE_LOW_PRIORITY, /* All except the high priority */
+ CONF_RX_QUEUE_TYPE_HIGH_PRIORITY, /* Management and voice packets */
+};
+
+struct conf_rx_settings {
+ /*
+ * The maximum amount of time, in TU, before the
+ * firmware discards the MSDU.
+ *
+ * Range: 0 - 0xFFFFFFFF
+ */
+ u32 rx_msdu_life_time;
+
+ /*
+ * Packet detection threshold in the PHY.
+ *
+ * FIXME: details unknown.
+ */
+ u32 packet_detection_threshold;
+
+ /*
+ * The longest time the STA will wait to receive traffic from the AP
+ * after a PS-poll has been transmitted.
+ *
+ * Range: 0 - 200000
+ */
+ u16 ps_poll_timeout;
+ /*
+ * The longest time the STA will wait to receive traffic from the AP
+ * after a frame has been sent from an UPSD enabled queue.
+ *
+ * Range: 0 - 200000
+ */
+ u16 upsd_timeout;
+
+ /*
+ * The number of octets in an MPDU, below which an RTS/CTS
+ * handshake is not performed.
+ *
+ * Range: 0 - 4096
+ */
+ u16 rts_threshold;
+
+ /*
+ * The RX Clear Channel Assessment threshold in the PHY
+ * (the energy threshold).
+ *
+ * Range: ENABLE_ENERGY_D == 0x140A
+ * DISABLE_ENERGY_D == 0xFFEF
+ */
+ u16 rx_cca_threshold;
+
+ /*
+ * Occupied Rx mem-blocks number which requires interrupting the host
+ * (0 = no buffering, 0xffff = disabled).
+ *
+ * Range: u16
+ */
+ u16 irq_blk_threshold;
+
+ /*
+ * Rx packets number which requires interrupting the host
+ * (0 = no buffering).
+ *
+ * Range: u16
+ */
+ u16 irq_pkt_threshold;
+
+ /*
+ * Max time in msec the FW may delay RX-Complete interrupt.
+ *
+ * Range: 1 - 100
+ */
+ u16 irq_timeout;
+
+ /*
+ * The RX queue type.
+ *
+ * Range: RX_QUEUE_TYPE_RX_LOW_PRIORITY, RX_QUEUE_TYPE_RX_HIGH_PRIORITY,
+ */
+ u8 queue_type;
+};
+
+#define CONF_TX_MAX_RATE_CLASSES 8
+
+#define CONF_TX_RATE_MASK_UNSPECIFIED 0
+#define CONF_TX_RATE_MASK_ALL 0x1eff
+#define CONF_TX_RATE_RETRY_LIMIT 10
+
+struct conf_tx_rate_class {
+
+ /*
+ * The rates enabled for this rate class.
+ *
+ * Range: CONF_HW_BIT_RATE_* bit mask
+ */
+ u32 enabled_rates;
+
+ /*
+ * The dot11 short retry limit used for TX retries.
+ *
+ * Range: u8
+ */
+ u8 short_retry_limit;
+
+ /*
+ * The dot11 long retry limit used for TX retries.
+ *
+ * Range: u8
+ */
+ u8 long_retry_limit;
+
+ /*
+ * Flags controlling the attributes of TX transmission.
+ *
+ * Range: bit 0: Truncate - when set, FW attempts to send a frame stop
+ * when the total valid per-rate attempts have
+ * been exhausted; otherwise transmissions
+ * will continue at the lowest available rate
+ * until the appropriate one of the
+ * short_retry_limit, long_retry_limit,
+ * dot11_max_transmit_msdu_life_time, or
+ * max_tx_life_time, is exhausted.
+ * 1: Preamble Override - indicates if the preamble type
+ * should be used in TX.
+ * 2: Preamble Type - the type of the preamble to be used by
+ * the policy (0 - long preamble, 1 - short preamble.
+ */
+ u8 aflags;
+};
+
+#define CONF_TX_MAX_AC_COUNT 4
+
+/* Slot number setting to start transmission at PIFS interval */
+#define CONF_TX_AIFS_PIFS 1
+/* Slot number setting to start transmission at DIFS interval normal
+ * DCF access */
+#define CONF_TX_AIFS_DIFS 2
+
+
+enum conf_tx_ac {
+ CONF_TX_AC_BE = 0, /* best effort / legacy */
+ CONF_TX_AC_BK = 1, /* background */
+ CONF_TX_AC_VI = 2, /* video */
+ CONF_TX_AC_VO = 3, /* voice */
+ CONF_TX_AC_CTS2SELF = 4, /* fictious AC, follows AC_VO */
+ CONF_TX_AC_ANY_TID = 0x1f
+};
+
+struct conf_tx_ac_category {
+ /*
+ * The AC class identifier.
+ *
+ * Range: enum conf_tx_ac
+ */
+ u8 ac;
+
+ /*
+ * The contention window minimum size (in slots) for the access
+ * class.
+ *
+ * Range: u8
+ */
+ u8 cw_min;
+
+ /*
+ * The contention window maximum size (in slots) for the access
+ * class.
+ *
+ * Range: u8
+ */
+ u16 cw_max;
+
+ /*
+ * The AIF value (in slots) for the access class.
+ *
+ * Range: u8
+ */
+ u8 aifsn;
+
+ /*
+ * The TX Op Limit (in microseconds) for the access class.
+ *
+ * Range: u16
+ */
+ u16 tx_op_limit;
+};
+
+#define CONF_TX_MAX_TID_COUNT 7
+
+enum {
+ CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/
+ CONF_CHANNEL_TYPE_EDCF = 1, /* EDCA*/
+ CONF_CHANNEL_TYPE_HCCA = 2, /* HCCA*/
+};
+
+enum {
+ CONF_PS_SCHEME_LEGACY = 0,
+ CONF_PS_SCHEME_UPSD_TRIGGER = 1,
+ CONF_PS_SCHEME_LEGACY_PSPOLL = 2,
+ CONF_PS_SCHEME_SAPSD = 3,
+};
+
+enum {
+ CONF_ACK_POLICY_LEGACY = 0,
+ CONF_ACK_POLICY_NO_ACK = 1,
+ CONF_ACK_POLICY_BLOCK = 2,
+};
+
+
+struct conf_tx_tid {
+ u8 queue_id;
+ u8 channel_type;
+ u8 tsid;
+ u8 ps_scheme;
+ u8 ack_policy;
+ u32 apsd_conf[2];
+};
+
+struct conf_tx_settings {
+ /*
+ * The TX ED value for TELEC Enable/Disable.
+ *
+ * Range: 0, 1
+ */
+ u8 tx_energy_detection;
+
+ /*
+ * Configuration for rate classes for TX (currently only one
+ * rate class supported.)
+ */
+ struct conf_tx_rate_class rc_conf;
+
+ /*
+ * Configuration for access categories for TX rate control.
+ */
+ u8 ac_conf_count;
+ struct conf_tx_ac_category ac_conf[CONF_TX_MAX_AC_COUNT];
+
+ /*
+ * Configuration for TID parameters.
+ */
+ u8 tid_conf_count;
+ struct conf_tx_tid tid_conf[CONF_TX_MAX_TID_COUNT];
+
+ /*
+ * The TX fragmentation threshold.
+ *
+ * Range: u16
+ */
+ u16 frag_threshold;
+
+ /*
+ * Max time in msec the FW may delay frame TX-Complete interrupt.
+ *
+ * Range: u16
+ */
+ u16 tx_compl_timeout;
+
+ /*
+ * Completed TX packet count which requires to issue the TX-Complete
+ * interrupt.
+ *
+ * Range: u16
+ */
+ u16 tx_compl_threshold;
+
+};
+
+enum {
+ CONF_WAKE_UP_EVENT_BEACON = 0x01, /* Wake on every Beacon*/
+ CONF_WAKE_UP_EVENT_DTIM = 0x02, /* Wake on every DTIM*/
+ CONF_WAKE_UP_EVENT_N_DTIM = 0x04, /* Wake every Nth DTIM */
+ CONF_WAKE_UP_EVENT_N_BEACONS = 0x08, /* Wake every Nth beacon */
+ CONF_WAKE_UP_EVENT_BITS_MASK = 0x0F
+};
+
+#define CONF_MAX_BCN_FILT_IE_COUNT 32
+
+#define CONF_BCN_RULE_PASS_ON_CHANGE BIT(0)
+#define CONF_BCN_RULE_PASS_ON_APPEARANCE BIT(1)
+
+#define CONF_BCN_IE_OUI_LEN 3
+#define CONF_BCN_IE_VER_LEN 2
+
+struct conf_bcn_filt_rule {
+ /*
+ * IE number to which to associate a rule.
+ *
+ * Range: u8
+ */
+ u8 ie;
+
+ /*
+ * Rule to associate with the specific ie.
+ *
+ * Range: CONF_BCN_RULE_PASS_ON_*
+ */
+ u8 rule;
+
+ /*
+ * OUI for the vendor specifie IE (221)
+ */
+ u8 oui[CONF_BCN_IE_OUI_LEN];
+
+ /*
+ * Type for the vendor specifie IE (221)
+ */
+ u8 type;
+
+ /*
+ * Version for the vendor specifie IE (221)
+ */
+ u8 version[CONF_BCN_IE_VER_LEN];
+};
+
+#define CONF_MAX_RSSI_SNR_TRIGGERS 8
+
+enum {
+ CONF_TRIG_METRIC_RSSI_BEACON = 0,
+ CONF_TRIG_METRIC_RSSI_DATA,
+ CONF_TRIG_METRIC_SNR_BEACON,
+ CONF_TRIG_METRIC_SNR_DATA
+};
+
+enum {
+ CONF_TRIG_EVENT_TYPE_LEVEL = 0,
+ CONF_TRIG_EVENT_TYPE_EDGE
+};
+
+enum {
+ CONF_TRIG_EVENT_DIR_LOW = 0,
+ CONF_TRIG_EVENT_DIR_HIGH,
+ CONF_TRIG_EVENT_DIR_BIDIR
+};
+
+
+struct conf_sig_trigger {
+ /*
+ * The RSSI / SNR threshold value.
+ *
+ * FIXME: what is the range?
+ */
+ s16 threshold;
+
+ /*
+ * Minimum delay between two trigger events for this trigger in ms.
+ *
+ * Range: 0 - 60000
+ */
+ u16 pacing;
+
+ /*
+ * The measurement data source for this trigger.
+ *
+ * Range: CONF_TRIG_METRIC_*
+ */
+ u8 metric;
+
+ /*
+ * The trigger type of this trigger.
+ *
+ * Range: CONF_TRIG_EVENT_TYPE_*
+ */
+ u8 type;
+
+ /*
+ * The direction of the trigger.
+ *
+ * Range: CONF_TRIG_EVENT_DIR_*
+ */
+ u8 direction;
+
+ /*
+ * Hysteresis range of the trigger around the threshold (in dB)
+ *
+ * Range: u8
+ */
+ u8 hysteresis;
+
+ /*
+ * Index of the trigger rule.
+ *
+ * Range: 0 - CONF_MAX_RSSI_SNR_TRIGGERS-1
+ */
+ u8 index;
+
+ /*
+ * Enable / disable this rule (to use for clearing rules.)
+ *
+ * Range: 1 - Enabled, 2 - Not enabled
+ */
+ u8 enable;
+};
+
+struct conf_sig_weights {
+
+ /*
+ * RSSI from beacons average weight.
+ *
+ * Range: u8
+ */
+ u8 rssi_bcn_avg_weight;
+
+ /*
+ * RSSI from data average weight.
+ *
+ * Range: u8
+ */
+ u8 rssi_pkt_avg_weight;
+
+ /*
+ * SNR from beacons average weight.
+ *
+ * Range: u8
+ */
+ u8 snr_bcn_avg_weight;
+
+ /*
+ * SNR from data average weight.
+ *
+ * Range: u8
+ */
+ u8 snr_pkt_avg_weight;
+};
+
+enum conf_bcn_filt_mode {
+ CONF_BCN_FILT_MODE_DISABLED = 0,
+ CONF_BCN_FILT_MODE_ENABLED = 1
+};
+
+enum conf_bet_mode {
+ CONF_BET_MODE_DISABLE = 0,
+ CONF_BET_MODE_ENABLE = 1,
+};
+
+struct conf_conn_settings {
+ /*
+ * Firmware wakeup conditions configuration. The host may set only
+ * one bit.
+ *
+ * Range: CONF_WAKE_UP_EVENT_*
+ */
+ u8 wake_up_event;
+
+ /*
+ * Listen interval for beacons or Dtims.
+ *
+ * Range: 0 for beacon and Dtim wakeup
+ * 1-10 for x Dtims
+ * 1-255 for x beacons
+ */
+ u8 listen_interval;
+
+ /*
+ * Enable or disable the beacon filtering.
+ *
+ * Range: CONF_BCN_FILT_MODE_*
+ */
+ enum conf_bcn_filt_mode bcn_filt_mode;
+
+ /*
+ * Configure Beacon filter pass-thru rules.
+ */
+ u8 bcn_filt_ie_count;
+ struct conf_bcn_filt_rule bcn_filt_ie[CONF_MAX_BCN_FILT_IE_COUNT];
+
+ /*
+ * The number of consequtive beacons to lose, before the firmware
+ * becomes out of synch.
+ *
+ * Range: u32
+ */
+ u32 synch_fail_thold;
+
+ /*
+ * After out-of-synch, the number of TU's to wait without a further
+ * received beacon (or probe response) before issuing the BSS_EVENT_LOSE
+ * event.
+ *
+ * Range: u32
+ */
+ u32 bss_lose_timeout;
+
+ /*
+ * Beacon receive timeout.
+ *
+ * Range: u32
+ */
+ u32 beacon_rx_timeout;
+
+ /*
+ * Broadcast receive timeout.
+ *
+ * Range: u32
+ */
+ u32 broadcast_timeout;
+
+ /*
+ * Enable/disable reception of broadcast packets in power save mode
+ *
+ * Range: 1 - enable, 0 - disable
+ */
+ u8 rx_broadcast_in_ps;
+
+ /*
+ * Consequtive PS Poll failures before sending event to driver
+ *
+ * Range: u8
+ */
+ u8 ps_poll_threshold;
+
+ /*
+ * Configuration of signal (rssi/snr) triggers.
+ */
+ u8 sig_trigger_count;
+ struct conf_sig_trigger sig_trigger[CONF_MAX_RSSI_SNR_TRIGGERS];
+
+ /*
+ * Configuration of signal average weights.
+ */
+ struct conf_sig_weights sig_weights;
+
+ /*
+ * Specifies if beacon early termination procedure is enabled or
+ * disabled.
+ *
+ * Range: CONF_BET_MODE_*
+ */
+ u8 bet_enable;
+
+ /*
+ * Specifies the maximum number of consecutive beacons that may be
+ * early terminated. After this number is reached at least one full
+ * beacon must be correctly received in FW before beacon ET
+ * resumes.
+ *
+ * Range 0 - 255
+ */
+ u8 bet_max_consecutive;
+};
+
+#define CONF_SR_ERR_TBL_MAX_VALUES 14
+
+struct conf_mart_reflex_err_table {
+ /*
+ * Length of the error table values table.
+ *
+ * Range: 0 - CONF_SR_ERR_TBL_MAX_VALUES
+ */
+ u8 len;
+
+ /*
+ * Smart Reflex error table upper limit.
+ *
+ * Range: s8
+ */
+ s8 upper_limit;
+
+ /*
+ * Smart Reflex error table values.
+ *
+ * Range: s8
+ */
+ s8 values[CONF_SR_ERR_TBL_MAX_VALUES];
+};
+
+enum {
+ CONF_REF_CLK_19_2_E,
+ CONF_REF_CLK_26_E,
+ CONF_REF_CLK_38_4_E,
+ CONF_REF_CLK_52_E
+};
+
+enum single_dual_band_enum {
+ CONF_SINGLE_BAND,
+ CONF_DUAL_BAND
+};
+
+struct conf_general_parms {
+ /*
+ * RF Reference Clock type / speed
+ *
+ * Range: CONF_REF_CLK_*
+ */
+ u8 ref_clk;
+
+ /*
+ * Settling time of the reference clock after boot.
+ *
+ * Range: u8
+ */
+ u8 settling_time;
+
+ /*
+ * Flag defining whether clock is valid on wakeup.
+ *
+ * Range: 0 - not valid on wakeup, 1 - valid on wakeup
+ */
+ u8 clk_valid_on_wakeup;
+
+ /*
+ * DC-to-DC mode.
+ *
+ * Range: Unknown
+ */
+ u8 dc2dcmode;
+
+ /*
+ * Flag defining whether used as single or dual-band.
+ *
+ * Range: CONF_SINGLE_BAND, CONF_DUAL_BAND
+ */
+ u8 single_dual_band;
+
+ /*
+ * TX bip fem autodetect flag.
+ *
+ * Range: Unknown
+ */
+ u8 tx_bip_fem_autodetect;
+
+ /*
+ * TX bip gem manufacturer.
+ *
+ * Range: Unknown
+ */
+ u8 tx_bip_fem_manufacturer;
+
+ /*
+ * Settings flags.
+ *
+ * Range: Unknown
+ */
+ u8 settings;
+};
+
+#define CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE 15
+#define CONF_NUMBER_OF_SUB_BANDS_5 7
+#define CONF_NUMBER_OF_RATE_GROUPS 6
+#define CONF_NUMBER_OF_CHANNELS_2_4 14
+#define CONF_NUMBER_OF_CHANNELS_5 35
+
+struct conf_radio_parms {
+ /*
+ * Static radio parameters for 2.4GHz
+ *
+ * Range: unknown
+ */
+ u8 rx_trace_loss;
+ u8 tx_trace_loss;
+ s8 rx_rssi_and_proc_compens[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
+
+ /*
+ * Static radio parameters for 5GHz
+ *
+ * Range: unknown
+ */
+ u8 rx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
+ u8 tx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
+ s8 rx_rssi_and_proc_compens_5[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
+
+ /*
+ * Dynamic radio parameters for 2.4GHz
+ *
+ * Range: unknown
+ */
+ s16 tx_ref_pd_voltage;
+ s8 tx_ref_power;
+ s8 tx_offset_db;
+
+ s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS];
+ s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS];
+
+ s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4];
+ s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4];
+ s8 tx_pdv_rate_offsets[CONF_NUMBER_OF_RATE_GROUPS];
+
+ u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS];
+ u8 rx_fem_insertion_loss;
+
+ /*
+ * Dynamic radio parameters for 5GHz
+ *
+ * Range: unknown
+ */
+ s16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
+ s8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
+ s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5];
+
+ s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS];
+ s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS];
+
+ s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5];
+ s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS];
+
+ /* FIXME: this is inconsistent with the types for 2.4GHz */
+ s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS];
+ s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
+};
+
+#define CONF_SR_ERR_TBL_COUNT 3
+
+struct conf_init_settings {
+ /*
+ * Configure Smart Reflex error table values.
+ */
+ struct conf_mart_reflex_err_table sr_err_tbl[CONF_SR_ERR_TBL_COUNT];
+
+ /*
+ * Smart Reflex enable flag.
+ *
+ * Range: 1 - Smart Reflex enabled, 0 - Smart Reflex disabled
+ */
+ u8 sr_enable;
+
+ /*
+ * Configure general parameters.
+ */
+ struct conf_general_parms genparam;
+
+ /*
+ * Configure radio parameters.
+ */
+ struct conf_radio_parms radioparam;
+
+};
+
+struct conf_drv_settings {
+ struct conf_sg_settings sg;
+ struct conf_rx_settings rx;
+ struct conf_tx_settings tx;
+ struct conf_conn_settings conn;
+ struct conf_init_settings init;
+};
+
+#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c
index f3afd4a6ff33..31d396ba9188 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.c
+++ b/drivers/net/wireless/wl12xx/wl1271_event.c
@@ -26,20 +26,45 @@
#include "wl1271_spi.h"
#include "wl1271_event.h"
#include "wl1271_ps.h"
+#include "wl12xx_80211.h"
static int wl1271_event_scan_complete(struct wl1271 *wl,
struct event_mailbox *mbox)
{
+ int size = sizeof(struct wl12xx_probe_req_template);
wl1271_debug(DEBUG_EVENT, "status: 0x%x",
mbox->scheduled_scan_status);
if (wl->scanning) {
- mutex_unlock(&wl->mutex);
- ieee80211_scan_completed(wl->hw, false);
- mutex_lock(&wl->mutex);
- wl->scanning = false;
+ if (wl->scan.state == WL1271_SCAN_BAND_DUAL) {
+ wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
+ NULL, size);
+ /* 2.4 GHz band scanned, scan 5 GHz band, pretend
+ * to the wl1271_cmd_scan function that we are not
+ * scanning as it checks that.
+ */
+ wl->scanning = false;
+ wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
+ wl->scan.active,
+ wl->scan.high_prio,
+ WL1271_SCAN_BAND_5_GHZ,
+ wl->scan.probe_requests);
+ } else {
+ if (wl->scan.state == WL1271_SCAN_BAND_2_4_GHZ)
+ wl1271_cmd_template_set(wl,
+ CMD_TEMPL_CFG_PROBE_REQ_2_4,
+ NULL, size);
+ else
+ wl1271_cmd_template_set(wl,
+ CMD_TEMPL_CFG_PROBE_REQ_5,
+ NULL, size);
+
+ mutex_unlock(&wl->mutex);
+ ieee80211_scan_completed(wl->hw, false);
+ mutex_lock(&wl->mutex);
+ wl->scanning = false;
+ }
}
-
return 0;
}
@@ -57,7 +82,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
wl1271_event_mbox_dump(mbox);
- vector = mbox->events_vector & ~(mbox->events_mask);
+ vector = le32_to_cpu(mbox->events_vector);
+ vector &= ~(le32_to_cpu(mbox->events_mask));
wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector);
if (vector & SCAN_COMPLETE_EVENT_ID) {
@@ -66,14 +92,16 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
return ret;
}
- if (vector & BSS_LOSE_EVENT_ID) {
+ /*
+ * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon
+ * filtering) is enabled. Without PSM, the stack will receive all
+ * beacons and can detect beacon loss by itself.
+ */
+ if (vector & BSS_LOSE_EVENT_ID && wl->psm) {
wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
- if (wl->psm_requested && wl->psm) {
- ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
- if (ret < 0)
- return ret;
- }
+ /* indicate to the stack, that beacons have been lost */
+ ieee80211_beacon_loss(wl->vif);
}
return 0;
@@ -92,14 +120,14 @@ int wl1271_event_unmask(struct wl1271 *wl)
void wl1271_event_mbox_config(struct wl1271 *wl)
{
- wl->mbox_ptr[0] = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
+ wl->mbox_ptr[0] = wl1271_spi_read32(wl, REG_EVENT_MAILBOX_PTR);
wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
wl->mbox_ptr[0], wl->mbox_ptr[1]);
}
-int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
+int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num, bool do_ack)
{
struct event_mailbox mbox;
int ret;
@@ -110,8 +138,8 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
return -EINVAL;
/* first we read the mbox descriptor */
- wl1271_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox,
- sizeof(struct event_mailbox));
+ wl1271_spi_read(wl, wl->mbox_ptr[mbox_num], &mbox,
+ sizeof(struct event_mailbox), false);
/* process the descriptor */
ret = wl1271_event_process(wl, &mbox);
@@ -119,7 +147,9 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
return ret;
/* then we let the firmware know it can go on...*/
- wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
+ if (do_ack)
+ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG,
+ INTR_TRIG_EVENT_ACK);
return 0;
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.h b/drivers/net/wireless/wl12xx/wl1271_event.h
index 2cdce7c34bf0..3ab53d331f15 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.h
+++ b/drivers/net/wireless/wl12xx/wl1271_event.h
@@ -66,33 +66,33 @@ enum {
struct event_debug_report {
u8 debug_event_id;
u8 num_params;
- u16 pad;
- u32 report_1;
- u32 report_2;
- u32 report_3;
+ __le16 pad;
+ __le32 report_1;
+ __le32 report_2;
+ __le32 report_3;
} __attribute__ ((packed));
#define NUM_OF_RSSI_SNR_TRIGGERS 8
struct event_mailbox {
- u32 events_vector;
- u32 events_mask;
- u32 reserved_1;
- u32 reserved_2;
+ __le32 events_vector;
+ __le32 events_mask;
+ __le32 reserved_1;
+ __le32 reserved_2;
u8 dbg_event_id;
u8 num_relevant_params;
- u16 reserved_3;
- u32 event_report_p1;
- u32 event_report_p2;
- u32 event_report_p3;
+ __le16 reserved_3;
+ __le32 event_report_p1;
+ __le32 event_report_p2;
+ __le32 event_report_p3;
u8 number_of_scan_results;
u8 scan_tag;
u8 reserved_4[2];
- u32 compl_scheduled_scan_status;
+ __le32 compl_scheduled_scan_status;
- u16 scheduled_scan_attended_channels;
+ __le16 scheduled_scan_attended_channels;
u8 soft_gemini_sense_info;
u8 soft_gemini_protective_info;
s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS];
@@ -105,6 +105,6 @@ struct event_mailbox {
int wl1271_event_unmask(struct wl1271 *wl);
void wl1271_event_mbox_config(struct wl1271 *wl);
-int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
+int wl1271_event_handle(struct wl1271 *wl, u8 mbox, bool do_ack);
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c
index 490df217605a..417b4152feb1 100644
--- a/drivers/net/wireless/wl12xx/wl1271_init.c
+++ b/drivers/net/wireless/wl12xx/wl1271_init.c
@@ -59,6 +59,14 @@ static int wl1271_init_templates_config(struct wl1271 *wl)
if (ret < 0)
return ret;
+ if (wl1271_11a_enabled()) {
+ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
+ NULL,
+ sizeof(struct wl12xx_probe_req_template));
+ if (ret < 0)
+ return ret;
+ }
+
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL,
sizeof(struct wl12xx_null_data_template));
if (ret < 0)
@@ -94,7 +102,7 @@ static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter)
{
int ret;
- ret = wl1271_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF);
+ ret = wl1271_acx_rx_msdu_life_time(wl);
if (ret < 0)
return ret;
@@ -117,7 +125,7 @@ static int wl1271_init_phy_config(struct wl1271 *wl)
if (ret < 0)
return ret;
- ret = wl1271_acx_group_address_tbl(wl);
+ ret = wl1271_acx_group_address_tbl(wl, true, NULL, 0);
if (ret < 0)
return ret;
@@ -125,7 +133,7 @@ static int wl1271_init_phy_config(struct wl1271 *wl)
if (ret < 0)
return ret;
- ret = wl1271_acx_rts_threshold(wl, RTS_THRESHOLD_DEF);
+ ret = wl1271_acx_rts_threshold(wl, wl->conf.rx.rts_threshold);
if (ret < 0)
return ret;
@@ -136,7 +144,8 @@ static int wl1271_init_beacon_filter(struct wl1271 *wl)
{
int ret;
- ret = wl1271_acx_beacon_filter_opt(wl);
+ /* disable beacon filtering at this stage */
+ ret = wl1271_acx_beacon_filter_opt(wl, false);
if (ret < 0)
return ret;
@@ -187,6 +196,7 @@ static int wl1271_init_beacon_broadcast(struct wl1271 *wl)
static int wl1271_init_general_parms(struct wl1271 *wl)
{
struct wl1271_general_parms *gen_parms;
+ struct conf_general_parms *g = &wl->conf.init.genparam;
int ret;
gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
@@ -195,15 +205,14 @@ static int wl1271_init_general_parms(struct wl1271 *wl)
gen_parms->id = TEST_CMD_INI_FILE_GENERAL_PARAM;
- gen_parms->ref_clk = REF_CLK_38_4_E;
- /* FIXME: magic numbers */
- gen_parms->settling_time = 5;
- gen_parms->clk_valid_on_wakeup = 0;
- gen_parms->dc2dcmode = 0;
- gen_parms->single_dual_band = 0;
- gen_parms->tx_bip_fem_autodetect = 1;
- gen_parms->tx_bip_fem_manufacturer = 1;
- gen_parms->settings = 1;
+ gen_parms->ref_clk = g->ref_clk;
+ gen_parms->settling_time = g->settling_time;
+ gen_parms->clk_valid_on_wakeup = g->clk_valid_on_wakeup;
+ gen_parms->dc2dcmode = g->dc2dcmode;
+ gen_parms->single_dual_band = g->single_dual_band;
+ gen_parms->tx_bip_fem_autodetect = g->tx_bip_fem_autodetect;
+ gen_parms->tx_bip_fem_manufacturer = g->tx_bip_fem_manufacturer;
+ gen_parms->settings = g->settings;
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0);
if (ret < 0) {
@@ -217,32 +226,9 @@ static int wl1271_init_general_parms(struct wl1271 *wl)
static int wl1271_init_radio_parms(struct wl1271 *wl)
{
- /*
- * FIXME: All these magic numbers should be moved to some place where
- * they can be configured (separate file?)
- */
-
struct wl1271_radio_parms *radio_parms;
- int ret;
- u8 compensation[] = { 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8, 0xfc, 0x00,
- 0x08, 0x10, 0xf0, 0xf8, 0x00, 0x0a, 0x14 };
-
- u8 tx_rate_limits_normal[] = { 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 };
- u8 tx_rate_limits_degraded[] = { 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 };
-
- u8 tx_channel_limits_11b[] = { 0x22, 0x50, 0x50, 0x50,
- 0x50, 0x50, 0x50, 0x50,
- 0x50, 0x50, 0x22, 0x50,
- 0x22, 0x50 };
-
- u8 tx_channel_limits_ofdm[] = { 0x20, 0x50, 0x50, 0x50,
- 0x50, 0x50, 0x50, 0x50,
- 0x50, 0x50, 0x20, 0x50,
- 0x20, 0x50 };
-
- u8 tx_pdv_rate_offsets[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
- u8 tx_ibias[] = { 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 };
+ struct conf_radio_parms *r = &wl->conf.init.radioparam;
+ int i, ret;
radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
if (!radio_parms)
@@ -251,33 +237,59 @@ static int wl1271_init_radio_parms(struct wl1271 *wl)
radio_parms->id = TEST_CMD_INI_FILE_RADIO_PARAM;
/* Static radio parameters */
- radio_parms->rx_trace_loss = 10;
- radio_parms->tx_trace_loss = 10;
- memcpy(radio_parms->rx_rssi_and_proc_compens, compensation,
- sizeof(compensation));
-
- /* We don't set the 5GHz -- N/A */
+ radio_parms->rx_trace_loss = r->rx_trace_loss;
+ radio_parms->tx_trace_loss = r->tx_trace_loss;
+ memcpy(radio_parms->rx_rssi_and_proc_compens,
+ r->rx_rssi_and_proc_compens,
+ CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE);
+
+ memcpy(radio_parms->rx_trace_loss_5, r->rx_trace_loss_5,
+ CONF_NUMBER_OF_SUB_BANDS_5);
+ memcpy(radio_parms->tx_trace_loss_5, r->tx_trace_loss_5,
+ CONF_NUMBER_OF_SUB_BANDS_5);
+ memcpy(radio_parms->rx_rssi_and_proc_compens_5,
+ r->rx_rssi_and_proc_compens_5,
+ CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE);
/* Dynamic radio parameters */
- radio_parms->tx_ref_pd_voltage = cpu_to_le16(0x24e);
- radio_parms->tx_ref_power = 0x78;
- radio_parms->tx_offset_db = 0x0;
-
- memcpy(radio_parms->tx_rate_limits_normal, tx_rate_limits_normal,
- sizeof(tx_rate_limits_normal));
- memcpy(radio_parms->tx_rate_limits_degraded, tx_rate_limits_degraded,
- sizeof(tx_rate_limits_degraded));
-
- memcpy(radio_parms->tx_channel_limits_11b, tx_channel_limits_11b,
- sizeof(tx_channel_limits_11b));
- memcpy(radio_parms->tx_channel_limits_ofdm, tx_channel_limits_ofdm,
- sizeof(tx_channel_limits_ofdm));
- memcpy(radio_parms->tx_pdv_rate_offsets, tx_pdv_rate_offsets,
- sizeof(tx_pdv_rate_offsets));
- memcpy(radio_parms->tx_ibias, tx_ibias,
- sizeof(tx_ibias));
-
- radio_parms->rx_fem_insertion_loss = 0x14;
+ radio_parms->tx_ref_pd_voltage = cpu_to_le16(r->tx_ref_pd_voltage);
+ radio_parms->tx_ref_power = r->tx_ref_power;
+ radio_parms->tx_offset_db = r->tx_offset_db;
+
+ memcpy(radio_parms->tx_rate_limits_normal, r->tx_rate_limits_normal,
+ CONF_NUMBER_OF_RATE_GROUPS);
+ memcpy(radio_parms->tx_rate_limits_degraded, r->tx_rate_limits_degraded,
+ CONF_NUMBER_OF_RATE_GROUPS);
+
+ memcpy(radio_parms->tx_channel_limits_11b, r->tx_channel_limits_11b,
+ CONF_NUMBER_OF_CHANNELS_2_4);
+ memcpy(radio_parms->tx_channel_limits_ofdm, r->tx_channel_limits_ofdm,
+ CONF_NUMBER_OF_CHANNELS_2_4);
+ memcpy(radio_parms->tx_pdv_rate_offsets, r->tx_pdv_rate_offsets,
+ CONF_NUMBER_OF_RATE_GROUPS);
+ memcpy(radio_parms->tx_ibias, r->tx_ibias, CONF_NUMBER_OF_RATE_GROUPS);
+
+ radio_parms->rx_fem_insertion_loss = r->rx_fem_insertion_loss;
+
+ for (i = 0; i < CONF_NUMBER_OF_SUB_BANDS_5; i++)
+ radio_parms->tx_ref_pd_voltage_5[i] =
+ cpu_to_le16(r->tx_ref_pd_voltage_5[i]);
+ memcpy(radio_parms->tx_ref_power_5, r->tx_ref_power_5,
+ CONF_NUMBER_OF_SUB_BANDS_5);
+ memcpy(radio_parms->tx_offset_db_5, r->tx_offset_db_5,
+ CONF_NUMBER_OF_SUB_BANDS_5);
+ memcpy(radio_parms->tx_rate_limits_normal_5,
+ r->tx_rate_limits_normal_5, CONF_NUMBER_OF_RATE_GROUPS);
+ memcpy(radio_parms->tx_rate_limits_degraded_5,
+ r->tx_rate_limits_degraded_5, CONF_NUMBER_OF_RATE_GROUPS);
+ memcpy(radio_parms->tx_channel_limits_ofdm_5,
+ r->tx_channel_limits_ofdm_5, CONF_NUMBER_OF_CHANNELS_5);
+ memcpy(radio_parms->tx_pdv_rate_offsets_5, r->tx_pdv_rate_offsets_5,
+ CONF_NUMBER_OF_RATE_GROUPS);
+ memcpy(radio_parms->tx_ibias_5, r->tx_ibias_5,
+ CONF_NUMBER_OF_RATE_GROUPS);
+ memcpy(radio_parms->rx_fem_insertion_loss_5,
+ r->rx_fem_insertion_loss_5, CONF_NUMBER_OF_SUB_BANDS_5);
ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
if (ret < 0)
@@ -311,8 +323,8 @@ int wl1271_hw_init(struct wl1271 *wl)
/* RX config */
ret = wl1271_init_rx_config(wl,
- RX_CFG_PROMISCUOUS | RX_CFG_TSF,
- RX_FILTER_OPTION_DEF);
+ RX_CFG_PROMISCUOUS | RX_CFG_TSF,
+ RX_FILTER_OPTION_DEF);
/* RX_CONFIG_OPTION_ANY_DST_ANY_BSS,
RX_FILTER_OPTION_FILTER_ALL); */
if (ret < 0)
@@ -323,6 +335,11 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0)
goto out_free_memmap;
+ /* Initialize connection monitoring thresholds */
+ ret = wl1271_acx_conn_monit_params(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
/* Beacon filtering */
ret = wl1271_init_beacon_filter(wl);
if (ret < 0)
@@ -369,7 +386,7 @@ int wl1271_hw_init(struct wl1271 *wl)
goto out_free_memmap;
/* Configure TX rate classes */
- ret = wl1271_acx_rate_policies(wl);
+ ret = wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_ALL);
if (ret < 0)
goto out_free_memmap;
@@ -388,10 +405,16 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0)
goto out_free_memmap;
+ /* Configure smart reflex */
+ ret = wl1271_acx_smart_reflex(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
return 0;
out_free_memmap:
kfree(wl->target_mem_map);
+ wl->target_mem_map = NULL;
return ret;
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_init.h b/drivers/net/wireless/wl12xx/wl1271_init.h
index bd8ff0fa2272..6e21ceee76a6 100644
--- a/drivers/net/wireless/wl12xx/wl1271_init.h
+++ b/drivers/net/wireless/wl12xx/wl1271_init.h
@@ -48,19 +48,6 @@ struct wl1271_general_parms {
u8 settings;
} __attribute__ ((packed));
-enum ref_clk_enum {
- REF_CLK_19_2_E,
- REF_CLK_26_E,
- REF_CLK_38_4_E,
- REF_CLK_52_E
-};
-
-#define RSSI_AND_PROCESS_COMPENSATION_SIZE 15
-#define NUMBER_OF_SUB_BANDS_5 7
-#define NUMBER_OF_RATE_GROUPS 6
-#define NUMBER_OF_CHANNELS_2_4 14
-#define NUMBER_OF_CHANNELS_5 35
-
struct wl1271_radio_parms {
u8 id;
u8 padding[3];
@@ -69,45 +56,45 @@ struct wl1271_radio_parms {
/* 2.4GHz */
u8 rx_trace_loss;
u8 tx_trace_loss;
- s8 rx_rssi_and_proc_compens[RSSI_AND_PROCESS_COMPENSATION_SIZE];
+ s8 rx_rssi_and_proc_compens[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
/* 5GHz */
- u8 rx_trace_loss_5[NUMBER_OF_SUB_BANDS_5];
- u8 tx_trace_loss_5[NUMBER_OF_SUB_BANDS_5];
- s8 rx_rssi_and_proc_compens_5[RSSI_AND_PROCESS_COMPENSATION_SIZE];
+ u8 rx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
+ u8 tx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
+ s8 rx_rssi_and_proc_compens_5[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE];
/* Dynamic radio parameters */
/* 2.4GHz */
- s16 tx_ref_pd_voltage;
+ __le16 tx_ref_pd_voltage;
s8 tx_ref_power;
s8 tx_offset_db;
- s8 tx_rate_limits_normal[NUMBER_OF_RATE_GROUPS];
- s8 tx_rate_limits_degraded[NUMBER_OF_RATE_GROUPS];
+ s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS];
+ s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS];
- s8 tx_channel_limits_11b[NUMBER_OF_CHANNELS_2_4];
- s8 tx_channel_limits_ofdm[NUMBER_OF_CHANNELS_2_4];
- s8 tx_pdv_rate_offsets[NUMBER_OF_RATE_GROUPS];
+ s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4];
+ s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4];
+ s8 tx_pdv_rate_offsets[CONF_NUMBER_OF_RATE_GROUPS];
- u8 tx_ibias[NUMBER_OF_RATE_GROUPS];
+ u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS];
u8 rx_fem_insertion_loss;
u8 padding2;
/* 5GHz */
- s16 tx_ref_pd_voltage_5[NUMBER_OF_SUB_BANDS_5];
- s8 tx_ref_power_5[NUMBER_OF_SUB_BANDS_5];
- s8 tx_offset_db_5[NUMBER_OF_SUB_BANDS_5];
+ __le16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
+ s8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
+ s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5];
- s8 tx_rate_limits_normal_5[NUMBER_OF_RATE_GROUPS];
- s8 tx_rate_limits_degraded_5[NUMBER_OF_RATE_GROUPS];
+ s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS];
+ s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS];
- s8 tx_channel_limits_ofdm_5[NUMBER_OF_CHANNELS_5];
- s8 tx_pdv_rate_offsets_5[NUMBER_OF_RATE_GROUPS];
+ s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5];
+ s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS];
/* FIXME: this is inconsistent with the types for 2.4GHz */
- s8 tx_ibias_5[NUMBER_OF_RATE_GROUPS];
- s8 rx_fem_insertion_loss_5[NUMBER_OF_SUB_BANDS_5];
+ s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS];
+ s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
u8 padding3[2];
} __attribute__ ((packed));
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 27298b19d5bd..86132bb00787 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -30,7 +30,9 @@
#include <linux/spi/spi.h>
#include <linux/crc32.h>
#include <linux/etherdevice.h>
+#include <linux/vmalloc.h>
#include <linux/spi/wl12xx.h>
+#include <linux/inetdevice.h>
#include "wl1271.h"
#include "wl12xx_80211.h"
@@ -45,6 +47,308 @@
#include "wl1271_cmd.h"
#include "wl1271_boot.h"
+static struct conf_drv_settings default_conf = {
+ .sg = {
+ .per_threshold = 7500,
+ .max_scan_compensation_time = 120000,
+ .nfs_sample_interval = 400,
+ .load_ratio = 50,
+ .auto_ps_mode = 0,
+ .probe_req_compensation = 170,
+ .scan_window_compensation = 50,
+ .antenna_config = 0,
+ .beacon_miss_threshold = 60,
+ .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS,
+ .rate_adaptation_snr = 0
+ },
+ .rx = {
+ .rx_msdu_life_time = 512000,
+ .packet_detection_threshold = 0,
+ .ps_poll_timeout = 15,
+ .upsd_timeout = 15,
+ .rts_threshold = 2347,
+ .rx_cca_threshold = 0xFFEF,
+ .irq_blk_threshold = 0,
+ .irq_pkt_threshold = USHORT_MAX,
+ .irq_timeout = 5,
+ .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
+ },
+ .tx = {
+ .tx_energy_detection = 0,
+ .rc_conf = {
+ .enabled_rates = CONF_TX_RATE_MASK_UNSPECIFIED,
+ .short_retry_limit = 10,
+ .long_retry_limit = 10,
+ .aflags = 0
+ },
+ .ac_conf_count = 4,
+ .ac_conf = {
+ [0] = {
+ .ac = CONF_TX_AC_BE,
+ .cw_min = 15,
+ .cw_max = 63,
+ .aifsn = 3,
+ .tx_op_limit = 0,
+ },
+ [1] = {
+ .ac = CONF_TX_AC_BK,
+ .cw_min = 15,
+ .cw_max = 63,
+ .aifsn = 7,
+ .tx_op_limit = 0,
+ },
+ [2] = {
+ .ac = CONF_TX_AC_VI,
+ .cw_min = 15,
+ .cw_max = 63,
+ .aifsn = CONF_TX_AIFS_PIFS,
+ .tx_op_limit = 3008,
+ },
+ [3] = {
+ .ac = CONF_TX_AC_VO,
+ .cw_min = 15,
+ .cw_max = 63,
+ .aifsn = CONF_TX_AIFS_PIFS,
+ .tx_op_limit = 1504,
+ },
+ },
+ .tid_conf_count = 7,
+ .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,
+ .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,
+ .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,
+ .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,
+ .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 = 5,
+ .tx_compl_threshold = 5
+ },
+ .conn = {
+ .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
+ .listen_interval = 0,
+ .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
+ .bcn_filt_ie_count = 1,
+ .bcn_filt_ie = {
+ [0] = {
+ .ie = WLAN_EID_CHANNEL_SWITCH,
+ .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
+ }
+ },
+ .synch_fail_thold = 5,
+ .bss_lose_timeout = 100,
+ .beacon_rx_timeout = 10000,
+ .broadcast_timeout = 20000,
+ .rx_broadcast_in_ps = 1,
+ .ps_poll_threshold = 4,
+ .sig_trigger_count = 2,
+ .sig_trigger = {
+ [0] = {
+ .threshold = -75,
+ .pacing = 500,
+ .metric = CONF_TRIG_METRIC_RSSI_BEACON,
+ .type = CONF_TRIG_EVENT_TYPE_EDGE,
+ .direction = CONF_TRIG_EVENT_DIR_LOW,
+ .hysteresis = 2,
+ .index = 0,
+ .enable = 1
+ },
+ [1] = {
+ .threshold = -75,
+ .pacing = 500,
+ .metric = CONF_TRIG_METRIC_RSSI_BEACON,
+ .type = CONF_TRIG_EVENT_TYPE_EDGE,
+ .direction = CONF_TRIG_EVENT_DIR_HIGH,
+ .hysteresis = 2,
+ .index = 1,
+ .enable = 1
+ }
+ },
+ .sig_weights = {
+ .rssi_bcn_avg_weight = 10,
+ .rssi_pkt_avg_weight = 10,
+ .snr_bcn_avg_weight = 10,
+ .snr_pkt_avg_weight = 10
+ },
+ .bet_enable = CONF_BET_MODE_ENABLE,
+ .bet_max_consecutive = 100
+ },
+ .init = {
+ .sr_err_tbl = {
+ [0] = {
+ .len = 7,
+ .upper_limit = 0x03,
+ .values = {
+ 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
+ 0x00 }
+ },
+ [1] = {
+ .len = 7,
+ .upper_limit = 0x03,
+ .values = {
+ 0x18, 0x10, 0x05, 0xf6, 0xf0, 0xe8,
+ 0x00 }
+ },
+ [2] = {
+ .len = 7,
+ .upper_limit = 0x03,
+ .values = {
+ 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
+ 0x00 }
+ }
+ },
+ .sr_enable = 1,
+ .genparam = {
+ /*
+ * FIXME: The correct value CONF_REF_CLK_38_4_E
+ * causes the firmware to crash on boot.
+ * The value 5 apparently is an
+ * unnoficial XTAL configuration of the
+ * same frequency, which appears to work.
+ */
+ .ref_clk = 5,
+ .settling_time = 5,
+ .clk_valid_on_wakeup = 0,
+ .dc2dcmode = 0,
+ .single_dual_band = CONF_SINGLE_BAND,
+ .tx_bip_fem_autodetect = 0,
+ .tx_bip_fem_manufacturer = 1,
+ .settings = 1,
+ },
+ .radioparam = {
+ .rx_trace_loss = 10,
+ .tx_trace_loss = 10,
+ .rx_rssi_and_proc_compens = {
+ 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8,
+ 0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8,
+ 0x00, 0x0a, 0x14 },
+ .rx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
+ .tx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 },
+ .rx_rssi_and_proc_compens_5 = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00 },
+ .tx_ref_pd_voltage = 0x24e,
+ .tx_ref_power = 0x78,
+ .tx_offset_db = 0x0,
+ .tx_rate_limits_normal = {
+ 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 },
+ .tx_rate_limits_degraded = {
+ 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
+ .tx_channel_limits_11b = {
+ 0x22, 0x50, 0x50, 0x50, 0x50, 0x50,
+ 0x50, 0x50, 0x50, 0x50, 0x22, 0x50,
+ 0x22, 0x50 },
+ .tx_channel_limits_ofdm = {
+ 0x20, 0x50, 0x50, 0x50, 0x50, 0x50,
+ 0x50, 0x50, 0x50, 0x50, 0x20, 0x50,
+ 0x20, 0x50 },
+ .tx_pdv_rate_offsets = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .tx_ibias = {
+ 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 },
+ .rx_fem_insertion_loss = 0x14,
+ .tx_ref_pd_voltage_5 = {
+ 0x0190, 0x01a4, 0x01c3, 0x01d8,
+ 0x020a, 0x021c },
+ .tx_ref_power_5 = {
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },
+ .tx_offset_db_5 = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .tx_rate_limits_normal_5 = {
+ 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
+ .tx_rate_limits_degraded_5 = {
+ 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
+ .tx_channel_limits_ofdm_5 = {
+ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
+ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
+ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
+ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
+ 0x50, 0x50, 0x50 },
+ .tx_pdv_rate_offsets_5 = {
+ 0x01, 0x02, 0x02, 0x02, 0x02, 0x00 },
+ .tx_ibias_5 = {
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
+ .rx_fem_insertion_loss_5 = {
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }
+ }
+ }
+};
+
+static LIST_HEAD(wl_list);
+
+static void wl1271_conf_init(struct wl1271 *wl)
+{
+
+ /*
+ * This function applies the default configuration to the driver. This
+ * function is invoked upon driver load (spi probe.)
+ *
+ * The configuration is stored in a run-time structure in order to
+ * facilitate for run-time adjustment of any of the parameters. Making
+ * changes to the configuration structure will apply the new values on
+ * the next interface up (wl1271_op_start.)
+ */
+
+ /* apply driver default configuration */
+ memcpy(&wl->conf, &default_conf, sizeof(default_conf));
+
+ if (wl1271_11a_enabled())
+ wl->conf.init.genparam.single_dual_band = CONF_DUAL_BAND;
+}
+
+
static int wl1271_plt_init(struct wl1271 *wl)
{
int ret;
@@ -75,20 +379,14 @@ static void wl1271_power_on(struct wl1271 *wl)
wl->set_power(true);
}
-static void wl1271_fw_status(struct wl1271 *wl, struct wl1271_fw_status *status)
+static void wl1271_fw_status(struct wl1271 *wl,
+ struct wl1271_fw_status *status)
{
u32 total = 0;
int i;
- /*
- * FIXME: Reading the FW status directly from the registers seems to
- * be the right thing to do, but it doesn't work. And in the
- * reference driver, there is a workaround called
- * USE_SDIO_24M_WORKAROUND, which reads the status from memory
- * instead, so we do the same here.
- */
-
- wl1271_spi_mem_read(wl, STATUS_MEM_ADDRESS, status, sizeof(*status));
+ wl1271_spi_read(wl, FW_STATUS_ADDR, status,
+ sizeof(*status), false);
wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
"drv_rx_counter = %d, tx_results_counter = %d)",
@@ -99,25 +397,28 @@ static void wl1271_fw_status(struct wl1271 *wl, struct wl1271_fw_status *status)
/* update number of available TX blocks */
for (i = 0; i < NUM_TX_QUEUES; i++) {
- u32 cnt = status->tx_released_blks[i] - wl->tx_blocks_freed[i];
- wl->tx_blocks_freed[i] = status->tx_released_blks[i];
+ u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
+ wl->tx_blocks_freed[i];
+
+ wl->tx_blocks_freed[i] =
+ le32_to_cpu(status->tx_released_blks[i]);
wl->tx_blocks_available += cnt;
total += cnt;
}
/* if more blocks are available now, schedule some tx work */
if (total && !skb_queue_empty(&wl->tx_queue))
- schedule_work(&wl->tx_work);
+ ieee80211_queue_work(wl->hw, &wl->tx_work);
/* update the host-chipset time offset */
- wl->time_offset = jiffies_to_usecs(jiffies) - status->fw_localtime;
+ wl->time_offset = jiffies_to_usecs(jiffies) -
+ le32_to_cpu(status->fw_localtime);
}
-#define WL1271_IRQ_MAX_LOOPS 10
static void wl1271_irq_work(struct work_struct *work)
{
- u32 intr, ctr = WL1271_IRQ_MAX_LOOPS;
int ret;
+ u32 intr;
struct wl1271 *wl =
container_of(work, struct wl1271, irq_work);
@@ -132,9 +433,10 @@ static void wl1271_irq_work(struct work_struct *work)
if (ret < 0)
goto out;
- wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
+ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
- intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
+ wl1271_fw_status(wl, wl->fw_status);
+ intr = le32_to_cpu(wl->fw_status->intr);
if (!intr) {
wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
goto out_sleep;
@@ -142,46 +444,39 @@ static void wl1271_irq_work(struct work_struct *work)
intr &= WL1271_INTR_MASK;
- do {
- wl1271_fw_status(wl, wl->fw_status);
-
-
- if (intr & (WL1271_ACX_INTR_EVENT_A |
- WL1271_ACX_INTR_EVENT_B)) {
- wl1271_debug(DEBUG_IRQ,
- "WL1271_ACX_INTR_EVENT (0x%x)", intr);
- if (intr & WL1271_ACX_INTR_EVENT_A)
- wl1271_event_handle(wl, 0);
- else
- wl1271_event_handle(wl, 1);
- }
+ if (intr & WL1271_ACX_INTR_EVENT_A) {
+ bool do_ack = (intr & WL1271_ACX_INTR_EVENT_B) ? false : true;
+ wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
+ wl1271_event_handle(wl, 0, do_ack);
+ }
- if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
- wl1271_debug(DEBUG_IRQ,
- "WL1271_ACX_INTR_INIT_COMPLETE");
+ if (intr & WL1271_ACX_INTR_EVENT_B) {
+ wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
+ wl1271_event_handle(wl, 1, true);
+ }
- if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
- wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
+ if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
+ wl1271_debug(DEBUG_IRQ,
+ "WL1271_ACX_INTR_INIT_COMPLETE");
- if (intr & WL1271_ACX_INTR_DATA) {
- u8 tx_res_cnt = wl->fw_status->tx_results_counter -
- wl->tx_results_count;
+ if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
+ wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
- wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
+ if (intr & WL1271_ACX_INTR_DATA) {
+ u8 tx_res_cnt = wl->fw_status->tx_results_counter -
+ wl->tx_results_count;
- /* check for tx results */
- if (tx_res_cnt)
- wl1271_tx_complete(wl, tx_res_cnt);
+ wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
- wl1271_rx(wl, wl->fw_status);
- }
+ /* check for tx results */
+ if (tx_res_cnt)
+ wl1271_tx_complete(wl, tx_res_cnt);
- intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
- intr &= WL1271_INTR_MASK;
- } while (intr && --ctr);
+ wl1271_rx(wl, wl->fw_status);
+ }
out_sleep:
- wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
+ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK,
WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
wl1271_ps_elp_sleep(wl);
@@ -205,7 +500,7 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
wl->elp_compl = NULL;
}
- schedule_work(&wl->irq_work);
+ ieee80211_queue_work(wl->hw, &wl->irq_work);
spin_unlock_irqrestore(&wl->wl_lock, flags);
return IRQ_HANDLED;
@@ -231,7 +526,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
}
wl->fw_len = fw->size;
- wl->fw = kmalloc(wl->fw_len, GFP_KERNEL);
+ wl->fw = vmalloc(wl->fw_len);
if (!wl->fw) {
wl1271_error("could not allocate memory for the firmware");
@@ -292,7 +587,7 @@ static void wl1271_fw_wakeup(struct wl1271 *wl)
u32 elp_reg;
elp_reg = ELPCTRL_WAKE_UP;
- wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
+ wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
}
static int wl1271_setup(struct wl1271 *wl)
@@ -314,6 +609,7 @@ static int wl1271_setup(struct wl1271 *wl)
static int wl1271_chip_wakeup(struct wl1271 *wl)
{
+ struct wl1271_partition_set partition;
int ret = 0;
wl1271_power_on(wl);
@@ -323,11 +619,10 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
/* We don't need a real memory partition here, because we only want
* to use the registers at this point. */
- wl1271_set_partition(wl,
- 0x00000000,
- 0x00000000,
- REGISTERS_BASE,
- REGISTERS_DOWN_SIZE);
+ memset(&partition, 0, sizeof(partition));
+ partition.reg.start = REGISTERS_BASE;
+ partition.reg.size = REGISTERS_DOWN_SIZE;
+ wl1271_set_partition(wl, &partition);
/* ELP module wake up */
wl1271_fw_wakeup(wl);
@@ -335,7 +630,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
/* whal_FwCtrl_BootSm() */
/* 0. read chip id from CHIP_ID */
- wl->chip.id = wl1271_reg_read32(wl, CHIP_ID_B);
+ wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B);
/* 1. check if chip id is valid */
@@ -346,7 +641,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
ret = wl1271_setup(wl);
if (ret < 0)
- goto out;
+ goto out_power_off;
break;
case CHIP_ID_1271_PG20:
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
@@ -354,56 +649,34 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
ret = wl1271_setup(wl);
if (ret < 0)
- goto out;
+ goto out_power_off;
break;
default:
wl1271_error("unsupported chip id: 0x%x", wl->chip.id);
ret = -ENODEV;
- goto out;
+ goto out_power_off;
}
if (wl->fw == NULL) {
ret = wl1271_fetch_firmware(wl);
if (ret < 0)
- goto out;
+ goto out_power_off;
}
/* No NVS from netlink, try to get it from the filesystem */
if (wl->nvs == NULL) {
ret = wl1271_fetch_nvs(wl);
if (ret < 0)
- goto out;
+ goto out_power_off;
}
-out:
- return ret;
-}
-
-static void wl1271_filter_work(struct work_struct *work)
-{
- struct wl1271 *wl =
- container_of(work, struct wl1271, filter_work);
- int ret;
-
- mutex_lock(&wl->mutex);
-
- if (wl->state == WL1271_STATE_OFF)
- goto out;
-
- ret = wl1271_ps_elp_wakeup(wl, false);
- if (ret < 0)
- goto out;
-
- /* FIXME: replace the magic numbers with proper definitions */
- ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0);
- if (ret < 0)
- goto out_sleep;
+ goto out;
-out_sleep:
- wl1271_ps_elp_sleep(wl);
+out_power_off:
+ wl1271_power_off(wl);
out:
- mutex_unlock(&wl->mutex);
+ return ret;
}
int wl1271_plt_start(struct wl1271 *wl)
@@ -429,13 +702,26 @@ int wl1271_plt_start(struct wl1271 *wl)
ret = wl1271_boot(wl);
if (ret < 0)
- goto out;
+ goto out_power_off;
wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
ret = wl1271_plt_init(wl);
if (ret < 0)
- goto out;
+ goto out_irq_disable;
+
+ /* Make sure power saving is disabled */
+ ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
+ if (ret < 0)
+ goto out_irq_disable;
+
+ goto out;
+
+out_irq_disable:
+ wl1271_disable_interrupts(wl);
+
+out_power_off:
+ wl1271_power_off(wl);
out:
mutex_unlock(&wl->mutex);
@@ -462,6 +748,7 @@ int wl1271_plt_stop(struct wl1271 *wl)
wl1271_power_off(wl);
wl->state = WL1271_STATE_OFF;
+ wl->rx_counter = 0;
out:
mutex_unlock(&wl->mutex);
@@ -481,7 +768,7 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* before that, the tx_work will not be initialized!
*/
- schedule_work(&wl->tx_work);
+ ieee80211_queue_work(wl->hw, &wl->tx_work);
/*
* The workqueue is slow to process the tx_queue and we need stop
@@ -501,6 +788,93 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return NETDEV_TX_OK;
}
+static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
+ void *arg)
+{
+ struct net_device *dev;
+ struct wireless_dev *wdev;
+ struct wiphy *wiphy;
+ struct ieee80211_hw *hw;
+ struct wl1271 *wl;
+ struct wl1271 *wl_temp;
+ struct in_device *idev;
+ struct in_ifaddr *ifa = arg;
+ int ret = 0;
+
+ /* FIXME: this ugly function should probably be implemented in the
+ * mac80211, and here should only be a simple callback handling actual
+ * setting of the filters. Now we need to dig up references to
+ * various structures to gain access to what we need.
+ * Also, because of this, there is no "initial" setting of the filter
+ * in "op_start", because we don't want to dig up struct net_device
+ * there - the filter will be set upon first change of the interface
+ * IP address. */
+
+ dev = ifa->ifa_dev->dev;
+
+ wdev = dev->ieee80211_ptr;
+ if (wdev == NULL)
+ return -ENODEV;
+
+ wiphy = wdev->wiphy;
+ if (wiphy == NULL)
+ return -ENODEV;
+
+ hw = wiphy_priv(wiphy);
+ if (hw == NULL)
+ return -ENODEV;
+
+ /* Check that the interface is one supported by this driver. */
+ wl_temp = hw->priv;
+ list_for_each_entry(wl, &wl_list, list) {
+ if (wl == wl_temp)
+ break;
+ }
+ if (wl == NULL)
+ return -ENODEV;
+
+ /* Get the interface IP address for the device. "ifa" will become
+ NULL if:
+ - there is no IPV4 protocol address configured
+ - there are multiple (virtual) IPV4 addresses configured
+ When "ifa" is NULL, filtering will be disabled.
+ */
+ ifa = NULL;
+ idev = dev->ip_ptr;
+ if (idev)
+ ifa = idev->ifa_list;
+
+ if (ifa && ifa->ifa_next)
+ ifa = NULL;
+
+ mutex_lock(&wl->mutex);
+
+ if (wl->state == WL1271_STATE_OFF)
+ goto out;
+
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out;
+ if (ifa)
+ ret = wl1271_acx_arp_ip_filter(wl, true,
+ (u8 *)&ifa->ifa_address,
+ ACX_IPV4_VERSION);
+ else
+ ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
+ ACX_IPV4_VERSION);
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
+static struct notifier_block wl1271_dev_notifier = {
+ .notifier_call = wl1271_dev_notify,
+};
+
+
static int wl1271_op_start(struct ieee80211_hw *hw)
{
struct wl1271 *wl = hw->priv;
@@ -523,22 +897,32 @@ static int wl1271_op_start(struct ieee80211_hw *hw)
ret = wl1271_boot(wl);
if (ret < 0)
- goto out;
+ goto out_power_off;
ret = wl1271_hw_init(wl);
if (ret < 0)
- goto out;
+ goto out_irq_disable;
wl->state = WL1271_STATE_ON;
wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
-out:
- if (ret < 0)
- wl1271_power_off(wl);
+ goto out;
+
+out_irq_disable:
+ wl1271_disable_interrupts(wl);
+out_power_off:
+ wl1271_power_off(wl);
+
+out:
mutex_unlock(&wl->mutex);
+ if (!ret) {
+ list_add(&wl->list, &wl_list);
+ register_inetaddr_notifier(&wl1271_dev_notifier);
+ }
+
return ret;
}
@@ -551,6 +935,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
+ unregister_inetaddr_notifier(&wl1271_dev_notifier);
+ list_del(&wl->list);
+
mutex_lock(&wl->mutex);
WARN_ON(wl->state != WL1271_STATE_ON);
@@ -570,7 +957,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
cancel_work_sync(&wl->irq_work);
cancel_work_sync(&wl->tx_work);
- cancel_work_sync(&wl->filter_work);
mutex_lock(&wl->mutex);
@@ -581,8 +967,8 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
memset(wl->bssid, 0, ETH_ALEN);
memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
wl->ssid_len = 0;
- wl->listen_int = 1;
wl->bss_type = MAX_BSS_TYPE;
+ wl->band = IEEE80211_BAND_2GHZ;
wl->rx_counter = 0;
wl->elp = false;
@@ -592,8 +978,13 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wl->tx_blocks_available = 0;
wl->tx_results_count = 0;
wl->tx_packets_count = 0;
+ wl->tx_security_last_seq = 0;
+ wl->tx_security_seq_16 = 0;
+ wl->tx_security_seq_32 = 0;
wl->time_offset = 0;
wl->session_counter = 0;
+ wl->joined = false;
+
for (i = 0; i < NUM_TX_QUEUES; i++)
wl->tx_blocks_freed[i] = 0;
@@ -611,6 +1002,12 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
conf->type, conf->mac_addr);
mutex_lock(&wl->mutex);
+ if (wl->vif) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ wl->vif = conf->vif;
switch (conf->type) {
case NL80211_IFTYPE_STATION:
@@ -634,7 +1031,12 @@ out:
static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
+ struct wl1271 *wl = hw->priv;
+
+ mutex_lock(&wl->mutex);
wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
+ wl->vif = NULL;
+ mutex_unlock(&wl->mutex);
}
#if 0
@@ -657,7 +1059,15 @@ static int wl1271_op_config_interface(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- memcpy(wl->bssid, conf->bssid, ETH_ALEN);
+ if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
+ wl1271_debug(DEBUG_MAC80211, "bssid changed");
+
+ memcpy(wl->bssid, conf->bssid, ETH_ALEN);
+
+ ret = wl1271_cmd_join(wl);
+ if (ret < 0)
+ goto out_sleep;
+ }
ret = wl1271_cmd_build_null_data(wl);
if (ret < 0)
@@ -667,13 +1077,6 @@ static int wl1271_op_config_interface(struct ieee80211_hw *hw,
if (wl->ssid_len)
memcpy(wl->ssid, conf->ssid, wl->ssid_len);
- if (wl->bss_type != BSS_TYPE_IBSS) {
- /* FIXME: replace the magic numbers with proper definitions */
- ret = wl1271_cmd_join(wl, wl->bss_type, 5, 100, 1);
- if (ret < 0)
- goto out_sleep;
- }
-
if (conf->changed & IEEE80211_IFCC_BEACON) {
beacon = ieee80211_beacon_get(hw, vif);
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
@@ -691,12 +1094,6 @@ static int wl1271_op_config_interface(struct ieee80211_hw *hw,
if (ret < 0)
goto out_sleep;
-
- /* FIXME: replace the magic numbers with proper definitions */
- ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0);
-
- if (ret < 0)
- goto out_sleep;
}
out_sleep:
@@ -724,20 +1121,20 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
mutex_lock(&wl->mutex);
+ wl->band = conf->channel->band;
+
ret = wl1271_ps_elp_wakeup(wl, false);
if (ret < 0)
goto out;
if (channel != wl->channel) {
- u8 old_channel = wl->channel;
+ /*
+ * We assume that the stack will configure the right channel
+ * before associating, so we don't need to send a join
+ * command here. We will join the right channel when the
+ * BSSID changes
+ */
wl->channel = channel;
-
- /* FIXME: use beacon interval provided by mac80211 */
- ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0);
- if (ret < 0) {
- wl->channel = old_channel;
- goto out_sleep;
- }
}
ret = wl1271_cmd_build_null_data(wl);
@@ -782,6 +1179,45 @@ out:
return ret;
}
+struct wl1271_filter_params {
+ bool enabled;
+ int mc_list_length;
+ u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
+};
+
+static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
+ struct dev_addr_list *mc_list)
+{
+ struct wl1271_filter_params *fp;
+ int i;
+
+ fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
+ if (!fp) {
+ wl1271_error("Out of memory setting filters.");
+ return 0;
+ }
+
+ /* update multicast filtering parameters */
+ fp->enabled = true;
+ if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
+ mc_count = 0;
+ fp->enabled = false;
+ }
+
+ fp->mc_list_length = 0;
+ for (i = 0; i < mc_count; i++) {
+ if (mc_list->da_addrlen == ETH_ALEN) {
+ memcpy(fp->mc_list[fp->mc_list_length],
+ mc_list->da_addr, ETH_ALEN);
+ fp->mc_list_length++;
+ } else
+ wl1271_warning("Unknown mc address length.");
+ mc_list = mc_list->next;
+ }
+
+ return (u64)(unsigned long)fp;
+}
+
#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
FIF_ALLMULTI | \
FIF_FCSFAIL | \
@@ -791,28 +1227,53 @@ out:
static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed,
- unsigned int *total,u64 multicast)
+ unsigned int *total, u64 multicast)
{
+ struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
struct wl1271 *wl = hw->priv;
+ int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
+ mutex_lock(&wl->mutex);
+
+ if (wl->state == WL1271_STATE_OFF)
+ goto out;
+
+ ret = wl1271_ps_elp_wakeup(wl, false);
+ if (ret < 0)
+ goto out;
+
*total &= WL1271_SUPPORTED_FILTERS;
changed &= WL1271_SUPPORTED_FILTERS;
+ if (*total & FIF_ALLMULTI)
+ ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
+ else if (fp)
+ ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
+ fp->mc_list,
+ fp->mc_list_length);
+ if (ret < 0)
+ goto out_sleep;
+
+ kfree(fp);
+
+ /* FIXME: We still need to set our filters properly */
+
+ /* determine, whether supported filter values have changed */
if (changed == 0)
- return;
+ goto out_sleep;
- /* FIXME: wl->rx_config and wl->rx_filter are not protected */
- wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
- wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
+ /* apply configured filters */
+ ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
+ if (ret < 0)
+ goto out_sleep;
- /*
- * FIXME: workqueues need to be properly cancelled on stop(), for
- * now let's just disable changing the filter settings. They will
- * be updated any on config().
- */
- /* schedule_work(&wl->filter_work); */
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
}
static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
@@ -823,6 +1284,8 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct wl1271 *wl = hw->priv;
const u8 *addr;
int ret;
+ u32 tx_seq_32 = 0;
+ u16 tx_seq_16 = 0;
u8 key_type;
static const u8 bcast_addr[ETH_ALEN] =
@@ -861,11 +1324,15 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
key_type = KEY_TKIP;
key_conf->hw_key_idx = key_conf->keyidx;
+ tx_seq_32 = wl->tx_security_seq_32;
+ tx_seq_16 = wl->tx_security_seq_16;
break;
case ALG_CCMP:
key_type = KEY_AES;
key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ tx_seq_32 = wl->tx_security_seq_32;
+ tx_seq_16 = wl->tx_security_seq_16;
break;
default:
wl1271_error("Unknown key algo 0x%x", key_conf->alg);
@@ -879,7 +1346,7 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
key_conf->keyidx, key_type,
key_conf->keylen, key_conf->key,
- addr);
+ addr, tx_seq_32, tx_seq_16);
if (ret < 0) {
wl1271_error("Could not add or replace key");
goto out_sleep;
@@ -890,7 +1357,7 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
key_conf->keyidx, key_type,
key_conf->keylen, key_conf->key,
- addr);
+ addr, 0, 0);
if (ret < 0) {
wl1271_error("Could not remove key");
goto out_sleep;
@@ -921,13 +1388,13 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
struct wl1271 *wl = hw->priv;
int ret;
u8 *ssid = NULL;
- size_t ssid_len = 0;
+ size_t len = 0;
wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
if (req->n_ssids) {
ssid = req->ssids[0].ssid;
- ssid_len = req->ssids[0].ssid_len;
+ len = req->ssids[0].ssid_len;
}
mutex_lock(&wl->mutex);
@@ -936,7 +1403,12 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- ret = wl1271_cmd_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3);
+ if (wl1271_11a_enabled())
+ ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
+ WL1271_SCAN_BAND_DUAL, 3);
+ else
+ ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
+ WL1271_SCAN_BAND_2_4_GHZ, 3);
wl1271_ps_elp_sleep(wl);
@@ -969,6 +1441,22 @@ out:
return ret;
}
+static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
+{
+ struct ieee80211_supported_band *band;
+ u32 enabled_rates = 0;
+ int bit;
+
+ band = wl->hw->wiphy->bands[wl->band];
+ for (bit = 0; bit < band->n_bitrates; bit++) {
+ if (basic_rate_set & 0x1)
+ enabled_rates |= band->bitrates[bit].hw_value;
+ basic_rate_set >>= 1;
+ }
+
+ return enabled_rates;
+}
+
static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@@ -990,6 +1478,12 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
if (bss_conf->assoc) {
wl->aid = bss_conf->aid;
+ /*
+ * with wl1271, we don't need to update the
+ * beacon_int and dtim_period, because the firmware
+ * updates it by itself when the first beacon is
+ * received after a join.
+ */
ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
if (ret < 0)
goto out_sleep;
@@ -1005,8 +1499,14 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
if (ret < 0)
goto out_sleep;
}
+ } else {
+ /* use defaults when not associated */
+ wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
+ wl->aid = 0;
}
+
}
+
if (changed & BSS_CHANGED_ERP_SLOT) {
if (bss_conf->use_short_slot)
ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
@@ -1036,6 +1536,17 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
}
}
+ if (changed & BSS_CHANGED_BASIC_RATES) {
+ wl->basic_rate_set = wl1271_enabled_rates_get(
+ wl, bss_conf->basic_rates);
+
+ ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
+ if (ret < 0) {
+ wl1271_warning("Set rate policies failed %d", ret);
+ goto out_sleep;
+ }
+ }
+
out_sleep:
wl1271_ps_elp_sleep(wl);
@@ -1047,44 +1558,44 @@ out:
/* can't be const, mac80211 writes to this */
static struct ieee80211_rate wl1271_rates[] = {
{ .bitrate = 10,
- .hw_value = 0x1,
- .hw_value_short = 0x1, },
+ .hw_value = CONF_HW_BIT_RATE_1MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
{ .bitrate = 20,
- .hw_value = 0x2,
- .hw_value_short = 0x2,
+ .hw_value = CONF_HW_BIT_RATE_2MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
.flags = IEEE80211_RATE_SHORT_PREAMBLE },
{ .bitrate = 55,
- .hw_value = 0x4,
- .hw_value_short = 0x4,
+ .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
.flags = IEEE80211_RATE_SHORT_PREAMBLE },
{ .bitrate = 110,
- .hw_value = 0x20,
- .hw_value_short = 0x20,
+ .hw_value = CONF_HW_BIT_RATE_11MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
.flags = IEEE80211_RATE_SHORT_PREAMBLE },
{ .bitrate = 60,
- .hw_value = 0x8,
- .hw_value_short = 0x8, },
+ .hw_value = CONF_HW_BIT_RATE_6MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
{ .bitrate = 90,
- .hw_value = 0x10,
- .hw_value_short = 0x10, },
+ .hw_value = CONF_HW_BIT_RATE_9MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
{ .bitrate = 120,
- .hw_value = 0x40,
- .hw_value_short = 0x40, },
+ .hw_value = CONF_HW_BIT_RATE_12MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
{ .bitrate = 180,
- .hw_value = 0x80,
- .hw_value_short = 0x80, },
+ .hw_value = CONF_HW_BIT_RATE_18MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
{ .bitrate = 240,
- .hw_value = 0x200,
- .hw_value_short = 0x200, },
+ .hw_value = CONF_HW_BIT_RATE_24MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
{ .bitrate = 360,
- .hw_value = 0x400,
- .hw_value_short = 0x400, },
+ .hw_value = CONF_HW_BIT_RATE_36MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
{ .bitrate = 480,
- .hw_value = 0x800,
- .hw_value_short = 0x800, },
+ .hw_value = CONF_HW_BIT_RATE_48MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
{ .bitrate = 540,
- .hw_value = 0x1000,
- .hw_value_short = 0x1000, },
+ .hw_value = CONF_HW_BIT_RATE_54MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
};
/* can't be const, mac80211 writes to this */
@@ -1112,6 +1623,88 @@ static struct ieee80211_supported_band wl1271_band_2ghz = {
.n_bitrates = ARRAY_SIZE(wl1271_rates),
};
+/* 5 GHz data rates for WL1273 */
+static struct ieee80211_rate wl1271_rates_5ghz[] = {
+ { .bitrate = 60,
+ .hw_value = CONF_HW_BIT_RATE_6MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
+ { .bitrate = 90,
+ .hw_value = CONF_HW_BIT_RATE_9MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
+ { .bitrate = 120,
+ .hw_value = CONF_HW_BIT_RATE_12MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
+ { .bitrate = 180,
+ .hw_value = CONF_HW_BIT_RATE_18MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
+ { .bitrate = 240,
+ .hw_value = CONF_HW_BIT_RATE_24MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
+ { .bitrate = 360,
+ .hw_value = CONF_HW_BIT_RATE_36MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
+ { .bitrate = 480,
+ .hw_value = CONF_HW_BIT_RATE_48MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
+ { .bitrate = 540,
+ .hw_value = CONF_HW_BIT_RATE_54MBPS,
+ .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
+};
+
+/* 5 GHz band channels for WL1273 */
+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 = 136, .center_freq = 5680},
+ { .hw_value = 140, .center_freq = 5700},
+ { .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 = 165, .center_freq = 5825},
+};
+
+
+static struct ieee80211_supported_band wl1271_band_5ghz = {
+ .channels = wl1271_channels_5ghz,
+ .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
+ .bitrates = wl1271_rates_5ghz,
+ .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
+};
+
static const struct ieee80211_ops wl1271_ops = {
.start = wl1271_op_start,
.stop = wl1271_op_stop,
@@ -1119,6 +1712,7 @@ static const struct ieee80211_ops wl1271_ops = {
.remove_interface = wl1271_op_remove_interface,
.config = wl1271_op_config,
/* .config_interface = wl1271_op_config_interface, */
+ .prepare_multicast = wl1271_op_prepare_multicast,
.configure_filter = wl1271_op_configure_filter,
.tx = wl1271_op_tx,
.set_key = wl1271_op_set_key,
@@ -1151,24 +1745,25 @@ static int wl1271_register_hw(struct wl1271 *wl)
static int wl1271_init_ieee80211(struct wl1271 *wl)
{
- /*
- * The tx descriptor buffer and the TKIP space.
- *
- * FIXME: add correct 1271 descriptor size
- */
- wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE;
+ /* The tx descriptor buffer and the TKIP space. */
+ wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
+ sizeof(struct wl1271_tx_hw_descr);
/* unit us */
/* FIXME: find a proper value */
wl->hw->channel_change_time = 10000;
wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_NOISE_DBM;
+ IEEE80211_HW_NOISE_DBM |
+ IEEE80211_HW_BEACON_FILTER;
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
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;
+
SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
return 0;
@@ -1213,17 +1808,18 @@ static int __devinit wl1271_probe(struct spi_device *spi)
wl = hw->priv;
memset(wl, 0, sizeof(*wl));
+ INIT_LIST_HEAD(&wl->list);
+
wl->hw = hw;
dev_set_drvdata(&spi->dev, wl);
wl->spi = spi;
skb_queue_head_init(&wl->tx_queue);
- INIT_WORK(&wl->filter_work, wl1271_filter_work);
+ INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
wl->channel = WL1271_DEFAULT_CHANNEL;
wl->scanning = false;
wl->default_key = 0;
- wl->listen_int = 1;
wl->rx_counter = 0;
wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
@@ -1232,10 +1828,12 @@ static int __devinit wl1271_probe(struct spi_device *spi)
wl->psm_requested = false;
wl->tx_queue_stopped = false;
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
+ wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
+ wl->band = IEEE80211_BAND_2GHZ;
+ wl->vif = NULL;
+ wl->joined = false;
- /* We use the default power on sleep time until we know which chip
- * we're using */
- for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++)
+ for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
wl->tx_frames[i] = NULL;
spin_lock_init(&wl->wl_lock);
@@ -1250,13 +1848,6 @@ static int __devinit wl1271_probe(struct spi_device *spi)
wl->state = WL1271_STATE_OFF;
mutex_init(&wl->mutex);
- wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL);
- if (!wl->rx_descriptor) {
- wl1271_error("could not allocate memory for rx descriptor");
- ret = -ENOMEM;
- goto out_free;
- }
-
/* This is the only SPI value that we need to set here, the rest
* comes from the board-peripherals file */
spi->bits_per_word = 32;
@@ -1298,6 +1889,9 @@ static int __devinit wl1271_probe(struct spi_device *spi)
}
dev_set_drvdata(&wl1271_device.dev, wl);
+ /* Apply default driver configuration. */
+ wl1271_conf_init(wl);
+
ret = wl1271_init_ieee80211(wl);
if (ret)
goto out_platform;
@@ -1319,9 +1913,6 @@ static int __devinit wl1271_probe(struct spi_device *spi)
free_irq(wl->irq, wl);
out_free:
- kfree(wl->rx_descriptor);
- wl->rx_descriptor = NULL;
-
ieee80211_free_hw(hw);
return ret;
@@ -1337,14 +1928,11 @@ static int __devexit wl1271_remove(struct spi_device *spi)
platform_device_unregister(&wl1271_device);
free_irq(wl->irq, wl);
kfree(wl->target_mem_map);
- kfree(wl->fw);
+ vfree(wl->fw);
wl->fw = NULL;
kfree(wl->nvs);
wl->nvs = NULL;
- kfree(wl->rx_descriptor);
- wl->rx_descriptor = NULL;
-
kfree(wl->fw_status);
kfree(wl->tx_res_if);
@@ -1391,3 +1979,4 @@ module_exit(wl1271_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
+MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c
index 1dc74b0c7736..507cd91d7eed 100644
--- a/drivers/net/wireless/wl12xx/wl1271_ps.c
+++ b/drivers/net/wireless/wl12xx/wl1271_ps.c
@@ -27,25 +27,38 @@
#define WL1271_WAKEUP_TIMEOUT 500
+void wl1271_elp_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, elp_work);
+
+ wl1271_debug(DEBUG_PSM, "elp work");
+
+ mutex_lock(&wl->mutex);
+
+ if (wl->elp || !wl->psm)
+ goto out;
+
+ wl1271_debug(DEBUG_PSM, "chip to elp");
+ wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
+ wl->elp = true;
+
+out:
+ mutex_unlock(&wl->mutex);
+}
+
+#define ELP_ENTRY_DELAY 5
+
/* Routines to toggle sleep mode while in ELP */
void wl1271_ps_elp_sleep(struct wl1271 *wl)
{
- /*
- * FIXME: due to a problem in the firmware (causing a firmware
- * crash), ELP entry is prevented below. Remove the "true" to
- * re-enable ELP entry.
- */
- if (true || wl->elp || !wl->psm)
- return;
-
- /*
- * Go to ELP unless there is work already pending - pending work
- * will immediately wakeup the chipset anyway.
- */
- if (!work_pending(&wl->irq_work) && !work_pending(&wl->tx_work)) {
- wl1271_debug(DEBUG_PSM, "chip to elp");
- wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
- wl->elp = true;
+ if (wl->psm) {
+ cancel_delayed_work(&wl->elp_work);
+ ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
+ msecs_to_jiffies(ELP_ENTRY_DELAY));
}
}
@@ -73,7 +86,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake)
wl->elp_compl = &compl;
spin_unlock_irqrestore(&wl->wl_lock, flags);
- wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
+ wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
if (!pending) {
ret = wait_for_completion_timeout(
@@ -111,6 +124,17 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
switch (mode) {
case STATION_POWER_SAVE_MODE:
wl1271_debug(DEBUG_PSM, "entering psm");
+
+ /* enable beacon filtering */
+ ret = wl1271_acx_beacon_filter_opt(wl, true);
+ if (ret < 0)
+ return ret;
+
+ /* enable beacon early termination */
+ ret = wl1271_acx_bet_enable(wl, true);
+ if (ret < 0)
+ return ret;
+
ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
if (ret < 0)
return ret;
@@ -128,6 +152,16 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
if (ret < 0)
return ret;
+ /* disable beacon early termination */
+ ret = wl1271_acx_bet_enable(wl, false);
+ if (ret < 0)
+ return ret;
+
+ /* disable beacon filtering */
+ ret = wl1271_acx_beacon_filter_opt(wl, false);
+ if (ret < 0)
+ return ret;
+
ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
if (ret < 0)
return ret;
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.h b/drivers/net/wireless/wl12xx/wl1271_ps.h
index de2bd3c7dc9c..779653d0ae85 100644
--- a/drivers/net/wireless/wl12xx/wl1271_ps.h
+++ b/drivers/net/wireless/wl12xx/wl1271_ps.h
@@ -30,6 +30,6 @@
int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode);
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);
#endif /* __WL1271_PS_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_reg.h b/drivers/net/wireless/wl12xx/wl1271_reg.h
index f8ed4a4fc691..1f237389d1c7 100644
--- a/drivers/net/wireless/wl12xx/wl1271_reg.h
+++ b/drivers/net/wireless/wl12xx/wl1271_reg.h
@@ -34,7 +34,7 @@
#define REGISTERS_WORK_SIZE 0x0000b000
#define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC
-#define STATUS_MEM_ADDRESS 0x40400
+#define FW_STATUS_ADDR (0x14FC0 + 0xA000)
/* ELP register commands */
#define ELPCTRL_WAKE_UP 0x1
@@ -213,7 +213,6 @@
==============================================*/
#define ACX_REG_INTERRUPT_ACK (REGISTERS_BASE + 0x04F0)
-#define RX_DRIVER_DUMMY_WRITE_ADDRESS (REGISTERS_BASE + 0x0534)
#define RX_DRIVER_COUNTER_ADDRESS (REGISTERS_BASE + 0x0538)
/* Device Configuration registers*/
@@ -614,50 +613,6 @@ enum {
MAX_RADIO_BANDS = 0xFF
};
-enum {
- NO_RATE = 0,
- RATE_1MBPS = 0x0A,
- RATE_2MBPS = 0x14,
- RATE_5_5MBPS = 0x37,
- RATE_6MBPS = 0x0B,
- RATE_9MBPS = 0x0F,
- RATE_11MBPS = 0x6E,
- RATE_12MBPS = 0x0A,
- RATE_18MBPS = 0x0E,
- RATE_22MBPS = 0xDC,
- RATE_24MBPS = 0x09,
- RATE_36MBPS = 0x0D,
- RATE_48MBPS = 0x08,
- RATE_54MBPS = 0x0C
-};
-
-enum {
- RATE_INDEX_1MBPS = 0,
- RATE_INDEX_2MBPS = 1,
- RATE_INDEX_5_5MBPS = 2,
- RATE_INDEX_6MBPS = 3,
- RATE_INDEX_9MBPS = 4,
- RATE_INDEX_11MBPS = 5,
- RATE_INDEX_12MBPS = 6,
- RATE_INDEX_18MBPS = 7,
- RATE_INDEX_22MBPS = 8,
- RATE_INDEX_24MBPS = 9,
- RATE_INDEX_36MBPS = 10,
- RATE_INDEX_48MBPS = 11,
- RATE_INDEX_54MBPS = 12,
- RATE_INDEX_MAX = RATE_INDEX_54MBPS,
- MAX_RATE_INDEX,
- INVALID_RATE_INDEX = MAX_RATE_INDEX,
- RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF
-};
-
-enum {
- RATE_MASK_1MBPS = 0x1,
- RATE_MASK_2MBPS = 0x2,
- RATE_MASK_5_5MBPS = 0x4,
- RATE_MASK_11MBPS = 0x20,
-};
-
#define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */
#define OFDM_RATE_BIT BIT(6)
#define PBCC_RATE_BIT BIT(7)
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c
index ad8b6904c5eb..37d81ab6acc0 100644
--- a/drivers/net/wireless/wl12xx/wl1271_rx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_rx.c
@@ -30,14 +30,15 @@
static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status,
u32 drv_rx_counter)
{
- return status->rx_pkt_descs[drv_rx_counter] & RX_MEM_BLOCK_MASK;
+ return le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
+ RX_MEM_BLOCK_MASK;
}
static u32 wl1271_rx_get_buf_size(struct wl1271_fw_status *status,
u32 drv_rx_counter)
{
- return (status->rx_pkt_descs[drv_rx_counter] & RX_BUF_SIZE_MASK) >>
- RX_BUF_SIZE_SHIFT_DIV;
+ return (le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
+ RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV;
}
/* The values of this table must match the wl1271_rates[] array */
@@ -70,6 +71,36 @@ static u8 wl1271_rx_rate_to_idx[] = {
0 /* WL1271_RATE_1 */
};
+/* The values of this table must match the wl1271_rates[] array */
+static u8 wl1271_5_ghz_rx_rate_to_idx[] = {
+ /* MCS rates are used only with 11n */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS7 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS6 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS5 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS4 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS3 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS2 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS1 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS0 */
+
+ 7, /* WL1271_RATE_54 */
+ 6, /* WL1271_RATE_48 */
+ 5, /* WL1271_RATE_36 */
+ 4, /* WL1271_RATE_24 */
+
+ /* TI-specific rate */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_22 */
+
+ 3, /* WL1271_RATE_18 */
+ 2, /* WL1271_RATE_12 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_11 */
+ 1, /* WL1271_RATE_9 */
+ 0, /* WL1271_RATE_6 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_5_5 */
+ WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_2 */
+ WL1271_RX_RATE_UNSUPPORTED /* WL1271_RATE_1 */
+};
+
static void wl1271_rx_status(struct wl1271 *wl,
struct wl1271_rx_descriptor *desc,
struct ieee80211_rx_status *status,
@@ -77,12 +108,21 @@ static void wl1271_rx_status(struct wl1271 *wl,
{
memset(status, 0, sizeof(struct ieee80211_rx_status));
- if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG)
+ if ((desc->flags & WL1271_RX_DESC_BAND_MASK) ==
+ WL1271_RX_DESC_BAND_BG) {
status->band = IEEE80211_BAND_2GHZ;
- else
+ status->rate_idx = wl1271_rx_rate_to_idx[desc->rate];
+ } else if ((desc->flags & WL1271_RX_DESC_BAND_MASK) ==
+ WL1271_RX_DESC_BAND_A) {
+ status->band = IEEE80211_BAND_5GHZ;
+ status->rate_idx = wl1271_5_ghz_rx_rate_to_idx[desc->rate];
+ } else
wl1271_warning("unsupported band 0x%x",
desc->flags & WL1271_RX_DESC_BAND_MASK);
+ if (unlikely(status->rate_idx == WL1271_RX_RATE_UNSUPPORTED))
+ wl1271_warning("unsupported rate");
+
/*
* FIXME: Add mactime handling. For IBSS (ad-hoc) we need to get the
* timestamp from the beacon (acx_tsf_info). In BSS mode (infra) we
@@ -91,12 +131,6 @@ static void wl1271_rx_status(struct wl1271 *wl,
*/
status->signal = desc->rssi;
- /* FIXME: Should this be optimized? */
- status->qual = (desc->rssi - WL1271_RX_MIN_RSSI) * 100 /
- (WL1271_RX_MAX_RSSI - WL1271_RX_MIN_RSSI);
- status->qual = min(status->qual, 100);
- status->qual = max(status->qual, 0);
-
/*
* FIXME: In wl1251, the SNR should be divided by two. In wl1271 we
* need to divide by two for now, but TI has been discussing about
@@ -109,17 +143,11 @@ static void wl1271_rx_status(struct wl1271 *wl,
if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) {
status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
- if (likely(!(desc->flags & WL1271_RX_DESC_DECRYPT_FAIL)))
+ if (likely(!(desc->status & WL1271_RX_DESC_DECRYPT_FAIL)))
status->flag |= RX_FLAG_DECRYPTED;
-
- if (unlikely(desc->flags & WL1271_RX_DESC_MIC_FAIL))
+ if (unlikely(desc->status & WL1271_RX_DESC_MIC_FAIL))
status->flag |= RX_FLAG_MMIC_ERROR;
}
-
- status->rate_idx = wl1271_rx_rate_to_idx[desc->rate];
-
- if (status->rate_idx == WL1271_RX_RATE_UNSUPPORTED)
- wl1271_warning("unsupported rate");
}
static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
@@ -138,7 +166,7 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
}
buf = skb_put(skb, length);
- wl1271_spi_reg_read(wl, WL1271_SLV_MEM_DATA, buf, length, true);
+ wl1271_spi_read(wl, WL1271_SLV_MEM_DATA, buf, length, true);
/* the data read starts with the descriptor */
desc = (struct wl1271_rx_descriptor *) buf;
@@ -156,7 +184,7 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
beacon ? "beacon" : "");
memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
- ieee80211_rx(wl->hw, skb);
+ ieee80211_rx_ni(wl->hw, skb);
}
void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
@@ -176,15 +204,15 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
break;
}
- wl->rx_mem_pool_addr.addr =
- (mem_block << 8) + wl_mem_map->packet_memory_pool_start;
+ 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_spi_reg_write(wl, WL1271_SLV_REG_DATA,
- &wl->rx_mem_pool_addr,
- sizeof(wl->rx_mem_pool_addr), false);
+ wl1271_spi_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);
@@ -192,9 +220,5 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
}
- wl1271_reg_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
-
- /* This is a workaround for some problems in the chip */
- wl1271_reg_write32(wl, RX_DRIVER_DUMMY_WRITE_ADDRESS, 0x1);
-
+ wl1271_spi_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.h b/drivers/net/wireless/wl12xx/wl1271_rx.h
index d1ca60e43a25..1ae6d1783ed4 100644
--- a/drivers/net/wireless/wl12xx/wl1271_rx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_rx.h
@@ -102,14 +102,14 @@
#define RX_BUF_SIZE_SHIFT_DIV 6
struct wl1271_rx_descriptor {
- u16 length;
+ __le16 length;
u8 status;
u8 flags;
u8 rate;
u8 channel;
s8 rssi;
u8 snr;
- u32 timestamp;
+ __le32 timestamp;
u8 packet_class;
u8 process_id;
u8 pad_len;
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c
index 4a12880c16a8..02978a16e732 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.c
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.c
@@ -30,17 +30,29 @@
#include "wl12xx_80211.h"
#include "wl1271_spi.h"
-static int wl1271_translate_reg_addr(struct wl1271 *wl, int addr)
+static int wl1271_translate_addr(struct wl1271 *wl, int addr)
{
- return addr - wl->physical_reg_addr + wl->virtual_reg_addr;
-}
-
-static int wl1271_translate_mem_addr(struct wl1271 *wl, int addr)
-{
- return addr - wl->physical_mem_addr + wl->virtual_mem_addr;
+ /*
+ * To translate, first check to which window of addresses the
+ * particular address belongs. Then subtract the starting address
+ * of that window from the address. Then, add offset of the
+ * translated region.
+ *
+ * The translated regions occur next to each other in physical device
+ * memory, so just add the sizes of the preceeding address regions to
+ * get the offset to the new region.
+ *
+ * Currently, only the two first regions are addressed, and the
+ * assumption is that all addresses will fall into either of those
+ * two.
+ */
+ if ((addr >= wl->part.reg.start) &&
+ (addr < wl->part.reg.start + wl->part.reg.size))
+ return addr - wl->part.reg.start + wl->part.mem.size;
+ else
+ return addr - wl->part.mem.start;
}
-
void wl1271_spi_reset(struct wl1271 *wl)
{
u8 *cmd;
@@ -123,133 +135,137 @@ void wl1271_spi_init(struct wl1271 *wl)
/* Set the SPI partitions to access the chip addresses
*
- * There are two VIRTUAL (SPI) partitions (the memory partition and the
- * registers partition), which are mapped to two different areas of the
- * PHYSICAL (hardware) memory. This function also makes other checks to
- * ensure that the partitions are not overlapping. In the diagram below, the
- * memory partition comes before the register partition, but the opposite is
- * also supported.
+ * To simplify driver code, a fixed (virtual) memory map is defined for
+ * register and memory addresses. Because in the chipset, in different stages
+ * of operation, those addresses will move around, an address translation
+ * mechanism is required.
*
- * PHYSICAL address
+ * There are four partitions (three memory and one register partition),
+ * which are mapped to two different areas of the hardware memory.
+ *
+ * Virtual address
* space
*
* | |
- * ...+----+--> mem_start
- * VIRTUAL address ... | |
+ * ...+----+--> mem.start
+ * Physical address ... | |
* space ... | | [PART_0]
* ... | |
- * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size
+ * 00000000 <--+----+... ...+----+--> mem.start + mem.size
* | | ... | |
* |MEM | ... | |
* | | ... | |
- * part_size <--+----+... | | {unused area)
+ * mem.size <--+----+... | | {unused area)
* | | ... | |
* |REG | ... | |
- * part_size | | ... | |
- * + <--+----+... ...+----+--> reg_start
- * reg_size ... | |
- * ... | | [PART_1]
- * ... | |
- * ...+----+--> reg_start + reg_size
+ * mem.size | | ... | |
+ * + <--+----+... ...+----+--> reg.start
+ * reg.size | | ... | |
+ * |MEM2| ... | | [PART_1]
+ * | | ... | |
+ * ...+----+--> reg.start + reg.size
* | |
*
*/
int wl1271_set_partition(struct wl1271 *wl,
- u32 mem_start, u32 mem_size,
- u32 reg_start, u32 reg_size)
+ struct wl1271_partition_set *p)
{
- struct wl1271_partition *partition;
- struct spi_transfer t;
- struct spi_message m;
- size_t len, cmd_len;
- u32 *cmd;
- int addr;
-
- cmd_len = sizeof(u32) + 2 * sizeof(struct wl1271_partition);
- cmd = kzalloc(cmd_len, GFP_KERNEL);
- if (!cmd)
- return -ENOMEM;
-
- spi_message_init(&m);
- memset(&t, 0, sizeof(t));
-
- partition = (struct wl1271_partition *) (cmd + 1);
- addr = HW_ACCESS_PART0_SIZE_ADDR;
- len = 2 * sizeof(struct wl1271_partition);
-
- *cmd |= WSPI_CMD_WRITE;
- *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
- *cmd |= addr & WSPI_CMD_BYTE_ADDR;
+ /* copy partition info */
+ memcpy(&wl->part, p, sizeof(*p));
wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
- mem_start, mem_size);
+ p->mem.start, p->mem.size);
wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
- reg_start, reg_size);
-
- /* Make sure that the two partitions together don't exceed the
- * address range */
- if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) {
- wl1271_debug(DEBUG_SPI, "Total size exceeds maximum virtual"
- " address range. Truncating partition[0].");
- mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size;
- wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
- mem_start, mem_size);
- wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
- reg_start, reg_size);
- }
+ p->reg.start, p->reg.size);
+ wl1271_debug(DEBUG_SPI, "mem2_start %08X mem2_size %08X",
+ p->mem2.start, p->mem2.size);
+ wl1271_debug(DEBUG_SPI, "mem3_start %08X mem3_size %08X",
+ p->mem3.start, p->mem3.size);
+
+ /* write partition info to the chipset */
+ wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start);
+ wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size);
+ wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start);
+ wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size);
+ wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start);
+ wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size);
+ wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
- if ((mem_start < reg_start) &&
- ((mem_start + mem_size) > reg_start)) {
- /* Guarantee that the memory partition doesn't overlap the
- * registers partition */
- wl1271_debug(DEBUG_SPI, "End of partition[0] is "
- "overlapping partition[1]. Adjusted.");
- mem_size = reg_start - mem_start;
- wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
- mem_start, mem_size);
- wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
- reg_start, reg_size);
- } else if ((reg_start < mem_start) &&
- ((reg_start + reg_size) > mem_start)) {
- /* Guarantee that the register partition doesn't overlap the
- * memory partition */
- wl1271_debug(DEBUG_SPI, "End of partition[1] is"
- " overlapping partition[0]. Adjusted.");
- reg_size = mem_start - reg_start;
- wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
- mem_start, mem_size);
- wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
- reg_start, reg_size);
- }
+ return 0;
+}
- partition[0].start = mem_start;
- partition[0].size = mem_size;
- partition[1].start = reg_start;
- partition[1].size = reg_size;
+#define WL1271_BUSY_WORD_TIMEOUT 1000
- wl->physical_mem_addr = mem_start;
- wl->physical_reg_addr = reg_start;
+/* FIXME: Check busy words, removed due to SPI bug */
+#if 0
+static void wl1271_spi_read_busy(struct wl1271 *wl, void *buf, size_t len)
+{
+ struct spi_transfer t[1];
+ struct spi_message m;
+ u32 *busy_buf;
+ int num_busy_bytes = 0;
- wl->virtual_mem_addr = 0;
- wl->virtual_reg_addr = mem_size;
+ wl1271_info("spi read BUSY!");
- t.tx_buf = cmd;
- t.len = cmd_len;
- spi_message_add_tail(&t, &m);
+ /*
+ * Look for the non-busy word in the read buffer, and if found,
+ * read in the remaining data into the buffer.
+ */
+ busy_buf = (u32 *)buf;
+ for (; (u32)busy_buf < (u32)buf + len; busy_buf++) {
+ num_busy_bytes += sizeof(u32);
+ if (*busy_buf & 0x1) {
+ spi_message_init(&m);
+ memset(t, 0, sizeof(t));
+ memmove(buf, busy_buf, len - num_busy_bytes);
+ t[0].rx_buf = buf + (len - num_busy_bytes);
+ t[0].len = num_busy_bytes;
+ spi_message_add_tail(&t[0], &m);
+ spi_sync(wl->spi, &m);
+ return;
+ }
+ }
- spi_sync(wl->spi, &m);
+ /*
+ * Read further busy words from SPI until a non-busy word is
+ * encountered, then read the data itself into the buffer.
+ */
+ wl1271_info("spi read BUSY-polling needed!");
- kfree(cmd);
+ num_busy_bytes = WL1271_BUSY_WORD_TIMEOUT;
+ busy_buf = wl->buffer_busyword;
+ while (num_busy_bytes) {
+ num_busy_bytes--;
+ spi_message_init(&m);
+ memset(t, 0, sizeof(t));
+ t[0].rx_buf = busy_buf;
+ t[0].len = sizeof(u32);
+ spi_message_add_tail(&t[0], &m);
+ spi_sync(wl->spi, &m);
+
+ if (*busy_buf & 0x1) {
+ spi_message_init(&m);
+ memset(t, 0, sizeof(t));
+ t[0].rx_buf = buf;
+ t[0].len = len;
+ spi_message_add_tail(&t[0], &m);
+ spi_sync(wl->spi, &m);
+ return;
+ }
+ }
- return 0;
+ /* The SPI bus is unresponsive, the read failed. */
+ memset(buf, 0, len);
+ wl1271_error("SPI read busy-word timeout!\n");
}
+#endif
-void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf,
- size_t len, bool fixed)
+void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed)
{
struct spi_transfer t[3];
struct spi_message m;
- u8 *busy_buf;
+ u32 *busy_buf;
u32 *cmd;
cmd = &wl->buffer_cmd;
@@ -281,14 +297,16 @@ void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf,
spi_sync(wl->spi, &m);
- /* FIXME: check busy words */
+ /* FIXME: Check busy words, removed due to SPI bug */
+ /* if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1))
+ wl1271_spi_read_busy(wl, buf, len); */
wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
}
-void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf,
- size_t len, bool fixed)
+void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
+ size_t len, bool fixed)
{
struct spi_transfer t[2];
struct spi_message m;
@@ -321,62 +339,77 @@ void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf,
wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
}
-void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf,
- size_t len)
+void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, size_t len,
+ bool fixed)
{
int physical;
- physical = wl1271_translate_mem_addr(wl, addr);
+ physical = wl1271_translate_addr(wl, addr);
- wl1271_spi_read(wl, physical, buf, len, false);
+ wl1271_spi_raw_read(wl, physical, buf, len, fixed);
}
-void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf,
- size_t len)
+void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, size_t len,
+ bool fixed)
{
int physical;
- physical = wl1271_translate_mem_addr(wl, addr);
+ physical = wl1271_translate_addr(wl, addr);
- wl1271_spi_write(wl, physical, buf, len, false);
+ wl1271_spi_raw_write(wl, physical, buf, len, fixed);
}
-void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len,
- bool fixed)
+u32 wl1271_spi_read32(struct wl1271 *wl, int addr)
{
- int physical;
-
- physical = wl1271_translate_reg_addr(wl, addr);
+ return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr));
+}
- wl1271_spi_read(wl, physical, buf, len, fixed);
+void wl1271_spi_write32(struct wl1271 *wl, int addr, u32 val)
+{
+ wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val);
}
-void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len,
- bool fixed)
+void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val)
{
- int physical;
+ /* write address >> 1 + 0x30000 to OCP_POR_CTR */
+ addr = (addr >> 1) + 0x30000;
+ wl1271_spi_write32(wl, OCP_POR_CTR, addr);
- physical = wl1271_translate_reg_addr(wl, addr);
+ /* write value to OCP_POR_WDATA */
+ wl1271_spi_write32(wl, OCP_DATA_WRITE, val);
- wl1271_spi_write(wl, physical, buf, len, fixed);
+ /* write 1 to OCP_CMD */
+ wl1271_spi_write32(wl, OCP_CMD, OCP_CMD_WRITE);
}
-u32 wl1271_mem_read32(struct wl1271 *wl, int addr)
+u16 wl1271_top_reg_read(struct wl1271 *wl, int addr)
{
- return wl1271_read32(wl, wl1271_translate_mem_addr(wl, addr));
-}
+ u32 val;
+ int timeout = OCP_CMD_LOOP;
-void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val)
-{
- wl1271_write32(wl, wl1271_translate_mem_addr(wl, addr), val);
-}
+ /* write address >> 1 + 0x30000 to OCP_POR_CTR */
+ addr = (addr >> 1) + 0x30000;
+ wl1271_spi_write32(wl, OCP_POR_CTR, addr);
-u32 wl1271_reg_read32(struct wl1271 *wl, int addr)
-{
- return wl1271_read32(wl, wl1271_translate_reg_addr(wl, addr));
-}
+ /* write 2 to OCP_CMD */
+ wl1271_spi_write32(wl, OCP_CMD, OCP_CMD_READ);
-void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val)
-{
- wl1271_write32(wl, wl1271_translate_reg_addr(wl, addr), val);
+ /* poll for data ready */
+ do {
+ val = wl1271_spi_read32(wl, OCP_DATA_READ);
+ timeout--;
+ } while (!(val & OCP_READY_MASK) && timeout);
+
+ if (!timeout) {
+ wl1271_warning("Top register access timed out.");
+ return 0xffff;
+ }
+
+ /* check data status and return if OK */
+ if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK)
+ return val & 0xffff;
+ else {
+ wl1271_warning("Top register access returned error.");
+ return 0xffff;
+ }
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.h b/drivers/net/wireless/wl12xx/wl1271_spi.h
index 2c9968458646..cb7df1c56314 100644
--- a/drivers/net/wireless/wl12xx/wl1271_spi.h
+++ b/drivers/net/wireless/wl12xx/wl1271_spi.h
@@ -29,10 +29,14 @@
#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0
-#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0
-#define HW_ACCESS_PART0_START_ADDR 0x1FFC4
-#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8
-#define HW_ACCESS_PART1_START_ADDR 0x1FFCC
+#define HW_PARTITION_REGISTERS_ADDR 0x1ffc0
+#define HW_PART0_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR)
+#define HW_PART0_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 4)
+#define HW_PART1_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 8)
+#define HW_PART1_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 12)
+#define HW_PART2_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 16)
+#define HW_PART2_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 20)
+#define HW_PART3_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 24)
#define HW_ACCESS_REGISTER_SIZE 4
@@ -67,47 +71,56 @@
((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32))
#define HW_ACCESS_WSPI_INIT_CMD_MASK 0
+#define OCP_CMD_LOOP 32
+
+#define OCP_CMD_WRITE 0x1
+#define OCP_CMD_READ 0x2
+
+#define OCP_READY_MASK BIT(18)
+#define OCP_STATUS_MASK (BIT(16) | BIT(17))
+
+#define OCP_STATUS_NO_RESP 0x00000
+#define OCP_STATUS_OK 0x10000
+#define OCP_STATUS_REQ_FAILED 0x20000
+#define OCP_STATUS_RESP_ERROR 0x30000
/* Raw target IO, address is not translated */
-void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf,
+void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed);
-void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf,
+void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
size_t len, bool fixed);
-/* Memory target IO, address is tranlated to partition 0 */
-void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf, size_t len);
-void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf, size_t len);
-u32 wl1271_mem_read32(struct wl1271 *wl, int addr);
-void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val);
+/* Translated target IO */
+void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, size_t len,
+ bool fixed);
+void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, size_t len,
+ bool fixed);
+u32 wl1271_spi_read32(struct wl1271 *wl, int addr);
+void wl1271_spi_write32(struct wl1271 *wl, int addr, u32 val);
-/* Registers IO */
-void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len,
- bool fixed);
-void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len,
- bool fixed);
-u32 wl1271_reg_read32(struct wl1271 *wl, int addr);
-void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val);
+/* Top Register IO */
+void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val);
+u16 wl1271_top_reg_read(struct wl1271 *wl, int addr);
/* INIT and RESET words */
void wl1271_spi_reset(struct wl1271 *wl);
void wl1271_spi_init(struct wl1271 *wl);
int wl1271_set_partition(struct wl1271 *wl,
- u32 part_start, u32 part_size,
- u32 reg_start, u32 reg_size);
+ struct wl1271_partition_set *p);
-static inline u32 wl1271_read32(struct wl1271 *wl, int addr)
+static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr)
{
- wl1271_spi_read(wl, addr, &wl->buffer_32,
- sizeof(wl->buffer_32), false);
+ wl1271_spi_raw_read(wl, addr, &wl->buffer_32,
+ sizeof(wl->buffer_32), false);
return wl->buffer_32;
}
-static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val)
+static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val)
{
wl->buffer_32 = val;
- wl1271_spi_write(wl, addr, &wl->buffer_32,
- sizeof(wl->buffer_32), false);
+ wl1271_spi_raw_write(wl, addr, &wl->buffer_32,
+ sizeof(wl->buffer_32), false);
}
#endif /* __WL1271_SPI_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c
index ff221258b941..00af065c77c2 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.c
@@ -33,8 +33,7 @@
static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb)
{
int i;
-
- for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++)
+ for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
if (wl->tx_frames[i] == NULL) {
wl->tx_frames[i] = skb;
return i;
@@ -58,8 +57,8 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
/* approximate the number of blocks required for this packet
in the firmware */
/* FIXME: try to figure out what is done here and make it cleaner */
- total_blocks = (skb->len) >> TX_HW_BLOCK_SHIFT_DIV;
- excluded = (total_blocks << 2) + (skb->len & 0xff) + 34;
+ total_blocks = (total_len + 20) >> TX_HW_BLOCK_SHIFT_DIV;
+ excluded = (total_blocks << 2) + ((total_len + 20) & 0xff) + 34;
total_blocks += (excluded > 252) ? 2 : 1;
total_blocks += TX_HW_BLOCK_SPARE;
@@ -89,15 +88,25 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
{
struct wl1271_tx_hw_descr *desc;
int pad;
+ u16 tx_attr;
desc = (struct wl1271_tx_hw_descr *) skb->data;
+ /* relocate space for security header */
+ if (extra) {
+ void *framestart = skb->data + sizeof(*desc);
+ u16 fc = *(u16 *)(framestart + extra);
+ int hdrlen = ieee80211_hdrlen(cpu_to_le16(fc));
+ memmove(framestart, framestart + extra, hdrlen);
+ }
+
/* configure packet life time */
- desc->start_time = jiffies_to_usecs(jiffies) - wl->time_offset;
- desc->life_time = TX_HW_MGMT_PKT_LIFETIME_TU;
+ desc->start_time = cpu_to_le32(jiffies_to_usecs(jiffies) -
+ wl->time_offset);
+ desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU);
/* configure the tx attributes */
- desc->tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
+ tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
/* FIXME: do we know the packet priority? can we identify mgmt
packets, and use max prio for them at least? */
desc->tid = 0;
@@ -106,11 +115,13 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
/* align the length (and store in terms of words) */
pad = WL1271_TX_ALIGN(skb->len);
- desc->length = pad >> 2;
+ desc->length = cpu_to_le16(pad >> 2);
/* calculate number of padding bytes */
pad = pad - skb->len;
- desc->tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
+ tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
+
+ desc->tx_attr = cpu_to_le16(tx_attr);
wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad);
return 0;
@@ -147,11 +158,11 @@ static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb,
len = WL1271_TX_ALIGN(skb->len);
/* perform a fixed address block write with the packet */
- wl1271_spi_reg_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true);
+ wl1271_spi_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true);
/* write packet new counter into the write access register */
wl->tx_packets_count++;
- wl1271_reg_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
+ wl1271_spi_write32(wl, WL1271_HOST_WR_ACCESS, 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)",
@@ -254,14 +265,13 @@ out:
static void wl1271_tx_complete_packet(struct wl1271 *wl,
struct wl1271_tx_hw_res_descr *result)
{
-
struct ieee80211_tx_info *info;
struct sk_buff *skb;
- u32 header_len;
+ u16 seq;
int id = result->id;
/* check for id legality */
- if (id >= TX_HW_RESULT_QUEUE_LEN || wl->tx_frames[id] == NULL) {
+ if (id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL) {
wl1271_warning("TX result illegal id: %d", id);
return;
}
@@ -284,22 +294,32 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
/* info->status.retry_count = result->ack_failures; */
wl->stats.retry_count += result->ack_failures;
- /* get header len */
+ /* update security sequence number */
+ seq = wl->tx_security_seq_16 +
+ (result->lsb_security_sequence_number -
+ wl->tx_security_last_seq);
+ wl->tx_security_last_seq = result->lsb_security_sequence_number;
+
+ if (seq < wl->tx_security_seq_16)
+ wl->tx_security_seq_32++;
+ wl->tx_security_seq_16 = seq;
+
+ /* remove private header from packet */
+ skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
+
+ /* remove TKIP header space if present */
if (info->control.hw_key &&
- info->control.hw_key->alg == ALG_TKIP)
- header_len = WL1271_TKIP_IV_SPACE +
- sizeof(struct wl1271_tx_hw_descr);
- else
- header_len = sizeof(struct wl1271_tx_hw_descr);
+ info->control.hw_key->alg == ALG_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);
+ }
wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
" status 0x%x",
result->id, skb, result->ack_failures,
result->rate_class_index, result->status);
- /* remove private header from packet */
- skb_pull(skb, header_len);
-
/* return the packet to the stack */
ieee80211_tx_status(wl->hw, skb);
wl->tx_frames[result->id] = NULL;
@@ -315,8 +335,8 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count)
wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count);
/* read the tx results from the chipset */
- wl1271_spi_mem_read(wl, memmap->tx_result,
- wl->tx_res_if, sizeof(*wl->tx_res_if));
+ wl1271_spi_read(wl, le32_to_cpu(memmap->tx_result),
+ wl->tx_res_if, sizeof(*wl->tx_res_if), false);
/* verify that the result buffer is not getting overrun */
if (count > TX_HW_RESULT_QUEUE_LEN) {
@@ -337,10 +357,10 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count)
}
/* write host counter to chipset (to ack) */
- wl1271_mem_write32(wl, memmap->tx_result +
+ wl1271_spi_write32(wl, le32_to_cpu(memmap->tx_result) +
offsetof(struct wl1271_tx_hw_res_if,
tx_result_host_counter),
- wl->tx_res_if->tx_result_fw_counter);
+ le32_to_cpu(wl->tx_res_if->tx_result_fw_counter));
}
/* caller must hold wl->mutex */
@@ -364,7 +384,7 @@ void wl1271_tx_flush(struct wl1271 *wl)
ieee80211_tx_status(wl->hw, skb);
}
- for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++)
+ for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
if (wl->tx_frames[i] != NULL) {
skb = wl->tx_frames[i];
info = IEEE80211_SKB_CB(skb);
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h
index 4a614067ddba..416396caf0a0 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.h
@@ -58,7 +58,7 @@
struct wl1271_tx_hw_descr {
/* Length of packet in words, including descriptor+header+data */
- u16 length;
+ __le16 length;
/* Number of extra memory blocks to allocate for this packet in
addition to the number of blocks derived from the packet length */
u8 extra_mem_blocks;
@@ -67,12 +67,12 @@ struct wl1271_tx_hw_descr {
HW!! */
u8 total_mem_blocks;
/* Device time (in us) when the packet arrived to the driver */
- u32 start_time;
+ __le32 start_time;
/* Max delay in TUs until transmission. The last device time the
packet can be transmitted is: startTime+(1024*LifeTime) */
- u16 life_time;
+ __le16 life_time;
/* Bitwise fields - see TX_ATTR... definitions above. */
- u16 tx_attr;
+ __le16 tx_attr;
/* Packet identifier used also in the Tx-Result. */
u8 id;
/* The packet TID value (as User-Priority) */
@@ -100,12 +100,12 @@ struct wl1271_tx_hw_res_descr {
several possible reasons for failure. */
u8 status;
/* Total air access duration including all retrys and overheads.*/
- u16 medium_usage;
+ __le16 medium_usage;
/* The time passed from host xfer to Tx-complete.*/
- u32 fw_handling_time;
+ __le32 fw_handling_time;
/* Total media delay
(from 1st EDCA AIFS counter until TX Complete). */
- u32 medium_delay;
+ __le32 medium_delay;
/* LS-byte of last TKIP seq-num (saved per AC for recovery). */
u8 lsb_security_sequence_number;
/* Retry count - number of transmissions without successful ACK.*/
@@ -118,8 +118,8 @@ struct wl1271_tx_hw_res_descr {
} __attribute__ ((packed));
struct wl1271_tx_hw_res_if {
- u32 tx_result_fw_counter;
- u32 tx_result_host_counter;
+ __le32 tx_result_fw_counter;
+ __le32 tx_result_host_counter;
struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN];
} __attribute__ ((packed));
diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h
index 657c2dbcb7d3..055d7bc6f592 100644
--- a/drivers/net/wireless/wl12xx/wl12xx_80211.h
+++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h
@@ -122,8 +122,8 @@ struct wl12xx_null_data_template {
} __attribute__ ((packed));
struct wl12xx_ps_poll_template {
- u16 fc;
- u16 aid;
+ __le16 fc;
+ __le16 aid;
u8 bssid[ETH_ALEN];
u8 ta[ETH_ALEN];
} __attribute__ ((packed));
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 4e79a9800134..dfa1b9bc22c8 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -755,7 +755,7 @@ static int hw_reset_phy(struct zd_chip *chip)
static int zd1211_hw_init_hmac(struct zd_chip *chip)
{
static const struct zd_ioreq32 ioreqs[] = {
- { CR_ZD1211_RETRY_MAX, 0x2 },
+ { CR_ZD1211_RETRY_MAX, ZD1211_RETRY_COUNT },
{ CR_RX_THRESHOLD, 0x000c0640 },
};
@@ -767,7 +767,7 @@ static int zd1211_hw_init_hmac(struct zd_chip *chip)
static int zd1211b_hw_init_hmac(struct zd_chip *chip)
{
static const struct zd_ioreq32 ioreqs[] = {
- { CR_ZD1211B_RETRY_MAX, 0x02020202 },
+ { CR_ZD1211B_RETRY_MAX, ZD1211B_RETRY_COUNT },
{ CR_ZD1211B_CWIN_MAX_MIN_AC0, 0x007f003f },
{ CR_ZD1211B_CWIN_MAX_MIN_AC1, 0x007f003f },
{ CR_ZD1211B_CWIN_MAX_MIN_AC2, 0x003f001f },
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index 678c139a840c..9fd8f3508d66 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -642,13 +642,29 @@ enum {
#define CR_ZD1211B_TXOP CTL_REG(0x0b20)
#define CR_ZD1211B_RETRY_MAX CTL_REG(0x0b28)
+/* Value for CR_ZD1211_RETRY_MAX & CR_ZD1211B_RETRY_MAX. Vendor driver uses 2,
+ * we use 0. The first rate is tried (count+2), then all next rates are tried
+ * twice, until 1 Mbits is tried. */
+#define ZD1211_RETRY_COUNT 0
+#define ZD1211B_RETRY_COUNT \
+ (ZD1211_RETRY_COUNT << 0)| \
+ (ZD1211_RETRY_COUNT << 8)| \
+ (ZD1211_RETRY_COUNT << 16)| \
+ (ZD1211_RETRY_COUNT << 24)
+
/* Used to detect PLL lock */
#define UW2453_INTR_REG ((zd_addr_t)0x85c1)
#define CWIN_SIZE 0x007f043f
-#define HWINT_ENABLED 0x004f0000
+#define HWINT_ENABLED \
+ (INT_TX_COMPLETE_EN| \
+ INT_RX_COMPLETE_EN| \
+ INT_RETRY_FAIL_EN| \
+ INT_WAKEUP_EN| \
+ INT_CFG_NEXT_BCN_EN)
+
#define HWINT_DISABLED 0
#define E2P_PWR_INT_GUARD 8
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 6d666359a42f..8a243732c519 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -88,6 +88,34 @@ static const struct ieee80211_rate zd_rates[] = {
.flags = 0 },
};
+/*
+ * Zydas retry rates table. Each line is listed in the same order as
+ * in zd_rates[] and contains all the rate used when a packet is sent
+ * starting with a given rates. Let's consider an example :
+ *
+ * "11 Mbits : 4, 3, 2, 1, 0" means :
+ * - packet is sent using 4 different rates
+ * - 1st rate is index 3 (ie 11 Mbits)
+ * - 2nd rate is index 2 (ie 5.5 Mbits)
+ * - 3rd rate is index 1 (ie 2 Mbits)
+ * - 4th rate is index 0 (ie 1 Mbits)
+ */
+
+static const struct tx_retry_rate zd_retry_rates[] = {
+ { /* 1 Mbits */ 1, { 0 }},
+ { /* 2 Mbits */ 2, { 1, 0 }},
+ { /* 5.5 Mbits */ 3, { 2, 1, 0 }},
+ { /* 11 Mbits */ 4, { 3, 2, 1, 0 }},
+ { /* 6 Mbits */ 5, { 4, 3, 2, 1, 0 }},
+ { /* 9 Mbits */ 6, { 5, 4, 3, 2, 1, 0}},
+ { /* 12 Mbits */ 5, { 6, 3, 2, 1, 0 }},
+ { /* 18 Mbits */ 6, { 7, 6, 3, 2, 1, 0 }},
+ { /* 24 Mbits */ 6, { 8, 6, 3, 2, 1, 0 }},
+ { /* 36 Mbits */ 7, { 9, 8, 6, 3, 2, 1, 0 }},
+ { /* 48 Mbits */ 8, {10, 9, 8, 6, 3, 2, 1, 0 }},
+ { /* 54 Mbits */ 9, {11, 10, 9, 8, 6, 3, 2, 1, 0 }}
+};
+
static const struct ieee80211_channel zd_channels[] = {
{ .center_freq = 2412, .hw_value = 1 },
{ .center_freq = 2417, .hw_value = 2 },
@@ -282,7 +310,7 @@ static void zd_op_stop(struct ieee80211_hw *hw)
}
/**
- * tx_status - reports tx status of a packet if required
+ * zd_mac_tx_status - reports tx status of a packet if required
* @hw - a &struct ieee80211_hw pointer
* @skb - a sk-buffer
* @flags: extra flags to set in the TX status info
@@ -295,15 +323,49 @@ static void zd_op_stop(struct ieee80211_hw *hw)
*
* If no status information has been requested, the skb is freed.
*/
-static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
- int ackssi, bool success)
+static void zd_mac_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
+ int ackssi, struct tx_status *tx_status)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ int i;
+ int success = 1, retry = 1;
+ int first_idx;
+ const struct tx_retry_rate *retries;
ieee80211_tx_info_clear_status(info);
- if (success)
+ if (tx_status) {
+ success = !tx_status->failure;
+ retry = tx_status->retry + success;
+ }
+
+ if (success) {
+ /* success */
info->flags |= IEEE80211_TX_STAT_ACK;
+ } else {
+ /* failure */
+ info->flags &= ~IEEE80211_TX_STAT_ACK;
+ }
+
+ first_idx = info->status.rates[0].idx;
+ ZD_ASSERT(0<=first_idx && first_idx<ARRAY_SIZE(zd_retry_rates));
+ retries = &zd_retry_rates[first_idx];
+ ZD_ASSERT(0<=retry && retry<=retries->count);
+
+ info->status.rates[0].idx = retries->rate[0];
+ info->status.rates[0].count = 1; // (retry > 1 ? 2 : 1);
+
+ for (i=1; i<IEEE80211_TX_MAX_RATES-1 && i<retry; i++) {
+ info->status.rates[i].idx = retries->rate[i];
+ info->status.rates[i].count = 1; // ((i==retry-1) && success ? 1:2);
+ }
+ for (; i<IEEE80211_TX_MAX_RATES && i<retry; i++) {
+ info->status.rates[i].idx = retries->rate[retry-1];
+ info->status.rates[i].count = 1; // (success ? 1:2);
+ }
+ if (i<IEEE80211_TX_MAX_RATES)
+ info->status.rates[i].idx = -1; /* terminate */
+
info->status.ack_signal = ackssi;
ieee80211_tx_status_irqsafe(hw, skb);
}
@@ -316,16 +378,79 @@ static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
* transferred. The first frame from the tx queue, will be selected and
* reported as error to the upper layers.
*/
-void zd_mac_tx_failed(struct ieee80211_hw *hw)
+void zd_mac_tx_failed(struct urb *urb)
{
- struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue;
+ struct ieee80211_hw * hw = zd_usb_to_hw(urb->context);
+ struct zd_mac *mac = zd_hw_mac(hw);
+ struct sk_buff_head *q = &mac->ack_wait_queue;
struct sk_buff *skb;
+ struct tx_status *tx_status = (struct tx_status *)urb->transfer_buffer;
+ unsigned long flags;
+ int success = !tx_status->failure;
+ int retry = tx_status->retry + success;
+ int found = 0;
+ int i, position = 0;
- skb = skb_dequeue(q);
- if (skb == NULL)
- return;
+ q = &mac->ack_wait_queue;
+ spin_lock_irqsave(&q->lock, flags);
+
+ skb_queue_walk(q, skb) {
+ struct ieee80211_hdr *tx_hdr;
+ struct ieee80211_tx_info *info;
+ int first_idx, final_idx;
+ const struct tx_retry_rate *retries;
+ u8 final_rate;
+
+ position ++;
+
+ /* if the hardware reports a failure and we had a 802.11 ACK
+ * pending, then we skip the first skb when searching for a
+ * matching frame */
+ if (tx_status->failure && mac->ack_pending &&
+ skb_queue_is_first(q, skb)) {
+ continue;
+ }
+
+ tx_hdr = (struct ieee80211_hdr *)skb->data;
+
+ /* we skip all frames not matching the reported destination */
+ if (unlikely(memcmp(tx_hdr->addr1, tx_status->mac, ETH_ALEN))) {
+ continue;
+ }
+
+ /* we skip all frames not matching the reported final rate */
- tx_status(hw, skb, 0, 0);
+ info = IEEE80211_SKB_CB(skb);
+ first_idx = info->status.rates[0].idx;
+ ZD_ASSERT(0<=first_idx && first_idx<ARRAY_SIZE(zd_retry_rates));
+ retries = &zd_retry_rates[first_idx];
+ if (retry < 0 || retry > retries->count) {
+ continue;
+ }
+
+ ZD_ASSERT(0<=retry && retry<=retries->count);
+ final_idx = retries->rate[retry-1];
+ final_rate = zd_rates[final_idx].hw_value;
+
+ if (final_rate != tx_status->rate) {
+ continue;
+ }
+
+ found = 1;
+ break;
+ }
+
+ if (found) {
+ for (i=1; i<=position; i++) {
+ skb = __skb_dequeue(q);
+ zd_mac_tx_status(hw, skb,
+ mac->ack_pending ? mac->ack_signal : 0,
+ i == position ? tx_status : NULL);
+ mac->ack_pending = 0;
+ }
+ }
+
+ spin_unlock_irqrestore(&q->lock, flags);
}
/**
@@ -342,18 +467,27 @@ void zd_mac_tx_to_dev(struct sk_buff *skb, int error)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hw *hw = info->rate_driver_data[0];
+ struct zd_mac *mac = zd_hw_mac(hw);
+
+ ieee80211_tx_info_clear_status(info);
skb_pull(skb, sizeof(struct zd_ctrlset));
if (unlikely(error ||
(info->flags & IEEE80211_TX_CTL_NO_ACK))) {
- tx_status(hw, skb, 0, !error);
+ /*
+ * FIXME : do we need to fill in anything ?
+ */
+ ieee80211_tx_status_irqsafe(hw, skb);
} else {
- struct sk_buff_head *q =
- &zd_hw_mac(hw)->ack_wait_queue;
+ struct sk_buff_head *q = &mac->ack_wait_queue;
skb_queue_tail(q, skb);
- while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS)
- zd_mac_tx_failed(hw);
+ while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS) {
+ zd_mac_tx_status(hw, skb_dequeue(q),
+ mac->ack_pending ? mac->ack_signal : 0,
+ NULL);
+ mac->ack_pending = 0;
+ }
}
}
@@ -606,27 +740,47 @@ fail:
static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr,
struct ieee80211_rx_status *stats)
{
+ struct zd_mac *mac = zd_hw_mac(hw);
struct sk_buff *skb;
struct sk_buff_head *q;
unsigned long flags;
+ int found = 0;
+ int i, position = 0;
if (!ieee80211_is_ack(rx_hdr->frame_control))
return 0;
- q = &zd_hw_mac(hw)->ack_wait_queue;
+ q = &mac->ack_wait_queue;
spin_lock_irqsave(&q->lock, flags);
skb_queue_walk(q, skb) {
struct ieee80211_hdr *tx_hdr;
+ position ++;
+
+ if (mac->ack_pending && skb_queue_is_first(q, skb))
+ continue;
+
tx_hdr = (struct ieee80211_hdr *)skb->data;
if (likely(!memcmp(tx_hdr->addr2, rx_hdr->addr1, ETH_ALEN)))
{
- __skb_unlink(skb, q);
- tx_status(hw, skb, stats->signal, 1);
- goto out;
+ found = 1;
+ break;
}
}
-out:
+
+ if (found) {
+ for (i=1; i<position; i++) {
+ skb = __skb_dequeue(q);
+ zd_mac_tx_status(hw, skb,
+ mac->ack_pending ? mac->ack_signal : 0,
+ NULL);
+ mac->ack_pending = 0;
+ }
+
+ mac->ack_pending = 1;
+ mac->ack_signal = stats->signal;
+ }
+
spin_unlock_irqrestore(&q->lock, flags);
return 1;
}
@@ -709,6 +863,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
skb_reserve(skb, 2);
}
+ /* FIXME : could we avoid this big memcpy ? */
memcpy(skb_put(skb, length), buffer, length);
memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats));
@@ -999,7 +1154,14 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
hw->queues = 1;
hw->extra_tx_headroom = sizeof(struct zd_ctrlset);
+ /*
+ * Tell mac80211 that we support multi rate retries
+ */
+ hw->max_rates = IEEE80211_TX_MAX_RATES;
+ hw->max_rate_tries = 18; /* 9 rates * 2 retries/rate */
+
skb_queue_head_init(&mac->ack_wait_queue);
+ mac->ack_pending = 0;
zd_chip_init(&mac->chip, hw, intf);
housekeeping_init(mac);
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 7c2759118d13..630c298a730e 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -140,6 +140,21 @@ struct rx_status {
#define ZD_RX_CRC16_ERROR 0x40
#define ZD_RX_ERROR 0x80
+struct tx_retry_rate {
+ int count; /* number of valid element in rate[] array */
+ int rate[10]; /* retry rates, described by an index in zd_rates[] */
+};
+
+struct tx_status {
+ u8 type; /* must always be 0x01 : USB_INT_TYPE */
+ u8 id; /* must always be 0xa0 : USB_INT_ID_RETRY_FAILED */
+ u8 rate;
+ u8 pad;
+ u8 mac[ETH_ALEN];
+ u8 retry;
+ u8 failure;
+} __attribute__((packed));
+
enum mac_flags {
MAC_FIXED_CHANNEL = 0x01,
};
@@ -150,7 +165,7 @@ struct housekeeping {
#define ZD_MAC_STATS_BUFFER_SIZE 16
-#define ZD_MAC_MAX_ACK_WAITERS 10
+#define ZD_MAC_MAX_ACK_WAITERS 50
struct zd_mac {
struct zd_chip chip;
@@ -184,6 +199,12 @@ struct zd_mac {
/* whether to pass control frames to stack */
unsigned int pass_ctrl:1;
+
+ /* whether we have received a 802.11 ACK that is pending */
+ unsigned int ack_pending:1;
+
+ /* signal strength of the last 802.11 ACK received */
+ int ack_signal;
};
#define ZD_REGDOMAIN_FCC 0x10
@@ -279,7 +300,7 @@ int zd_mac_preinit_hw(struct ieee80211_hw *hw);
int zd_mac_init_hw(struct ieee80211_hw *hw);
int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length);
-void zd_mac_tx_failed(struct ieee80211_hw *hw);
+void zd_mac_tx_failed(struct urb *urb);
void zd_mac_tx_to_dev(struct sk_buff *skb, int error);
#ifdef DEBUG
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 23a6a6d4863b..d46f20a57b7d 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -419,7 +419,7 @@ static void int_urb_complete(struct urb *urb)
handle_regs_int(urb);
break;
case USB_INT_ID_RETRY_FAILED:
- zd_mac_tx_failed(zd_usb_to_hw(urb->context));
+ zd_mac_tx_failed(urb);
break;
default:
dev_dbg_f(urb_dev(urb), "error: urb %p unknown id %x\n", urb,
@@ -553,6 +553,8 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
if (length < sizeof(struct rx_length_info)) {
/* It's not a complete packet anyhow. */
+ printk("%s: invalid, small RX packet : %d\n",
+ __func__, length);
return;
}
length_info = (struct rx_length_info *)
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index baa051d5bfbe..a869b45d3d37 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -42,6 +42,7 @@
#include <linux/mm.h>
#include <net/ip.h>
+#include <xen/xen.h>
#include <xen/xenbus.h>
#include <xen/events.h>
#include <xen/page.h>
diff --git a/drivers/of/base.c b/drivers/of/base.c
index ddf224d456b2..e6627b2320f1 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -9,7 +9,8 @@
*
* Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net
*
- * Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell.
+ * Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell and
+ * Grant Likely.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -82,6 +83,29 @@ struct property *of_find_property(const struct device_node *np,
}
EXPORT_SYMBOL(of_find_property);
+/**
+ * of_find_all_nodes - Get next node in global list
+ * @prev: Previous node or NULL to start iteration
+ * of_node_put() will be called on it
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_all_nodes(struct device_node *prev)
+{
+ struct device_node *np;
+
+ read_lock(&devtree_lock);
+ np = prev ? prev->allnext : allnodes;
+ for (; np != NULL; np = np->allnext)
+ if (of_node_get(np))
+ break;
+ of_node_put(prev);
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_find_all_nodes);
+
/*
* Find a property with a given name for a given node
* and return the value.
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index bacaa536fd51..4b22ba568b19 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -97,6 +97,12 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
}
EXPORT_SYMBOL(of_mdiobus_register);
+/* Helper function for of_phy_find_device */
+static int of_phy_match(struct device *dev, void *phy_np)
+{
+ return dev_archdata_get_node(&dev->archdata) == phy_np;
+}
+
/**
* of_phy_find_device - Give a PHY node, find the phy_device
* @phy_np: Pointer to the phy's device tree node
@@ -106,15 +112,10 @@ EXPORT_SYMBOL(of_mdiobus_register);
struct phy_device *of_phy_find_device(struct device_node *phy_np)
{
struct device *d;
- int match(struct device *dev, void *phy_np)
- {
- return dev_archdata_get_node(&dev->archdata) == phy_np;
- }
-
if (!phy_np)
return NULL;
- d = bus_find_device(&mdio_bus_type, NULL, phy_np, match);
+ d = bus_find_device(&mdio_bus_type, NULL, phy_np, of_phy_match);
return d ? to_phy_device(d) : NULL;
}
EXPORT_SYMBOL(of_phy_find_device);
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 22b02c6df854..0d064d1e840a 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -348,6 +348,35 @@ found:
}
#endif
+#ifdef CONFIG_ACPI_NUMA
+static int __init
+dmar_parse_one_rhsa(struct acpi_dmar_header *header)
+{
+ struct acpi_dmar_rhsa *rhsa;
+ struct dmar_drhd_unit *drhd;
+
+ rhsa = (struct acpi_dmar_rhsa *)header;
+ for_each_drhd_unit(drhd) {
+ if (drhd->reg_base_addr == rhsa->base_address) {
+ int node = acpi_map_pxm_to_node(rhsa->proximity_domain);
+
+ if (!node_online(node))
+ node = -1;
+ drhd->iommu->node = node;
+ return 0;
+ }
+ }
+ WARN(1, "Your BIOS is broken; RHSA refers to non-existent DMAR unit at %llx\n"
+ "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
+ drhd->reg_base_addr,
+ dmi_get_system_info(DMI_BIOS_VENDOR),
+ dmi_get_system_info(DMI_BIOS_VERSION),
+ dmi_get_system_info(DMI_PRODUCT_VERSION));
+
+ return 0;
+}
+#endif
+
static void __init
dmar_table_print_dmar_entry(struct acpi_dmar_header *header)
{
@@ -467,7 +496,9 @@ parse_dmar_table(void)
#endif
break;
case ACPI_DMAR_HARDWARE_AFFINITY:
- /* We don't do anything with RHSA (yet?) */
+#ifdef CONFIG_ACPI_NUMA
+ ret = dmar_parse_one_rhsa(entry_header);
+#endif
break;
default:
printk(KERN_WARNING PREFIX
@@ -677,6 +708,8 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
iommu->agaw = agaw;
iommu->msagaw = msagaw;
+ iommu->node = -1;
+
/* the registers might be more than one page */
map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap),
cap_max_fault_reg_offset(iommu->cap));
@@ -1018,6 +1051,7 @@ static void __dmar_enable_qi(struct intel_iommu *iommu)
int dmar_enable_qi(struct intel_iommu *iommu)
{
struct q_inval *qi;
+ struct page *desc_page;
if (!ecap_qis(iommu->ecap))
return -ENOENT;
@@ -1034,13 +1068,16 @@ int dmar_enable_qi(struct intel_iommu *iommu)
qi = iommu->qi;
- qi->desc = (void *)(get_zeroed_page(GFP_ATOMIC));
- if (!qi->desc) {
+
+ desc_page = alloc_pages_node(iommu->node, GFP_ATOMIC | __GFP_ZERO, 0);
+ if (!desc_page) {
kfree(qi);
iommu->qi = 0;
return -ENOMEM;
}
+ qi->desc = page_address(desc_page);
+
qi->desc_status = kmalloc(QI_LENGTH * sizeof(int), GFP_ATOMIC);
if (!qi->desc_status) {
free_page((unsigned long) qi->desc);
diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile
index 3625b094bf7e..6cd9f3c9887d 100644
--- a/drivers/pci/hotplug/Makefile
+++ b/drivers/pci/hotplug/Makefile
@@ -6,18 +6,22 @@ obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o
obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o
obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o
-# pciehp should be linked before acpiphp in order to allow the native driver
-# to attempt to bind first. We can then fall back to generic support.
+# native drivers should be linked before acpiphp in order to allow the
+# native driver to attempt to bind first. We can then fall back to
+# generic support.
obj-$(CONFIG_HOTPLUG_PCI_PCIE) += pciehp.o
-obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o
-obj-$(CONFIG_HOTPLUG_PCI_ACPI_IBM) += acpiphp_ibm.o
obj-$(CONFIG_HOTPLUG_PCI_CPCI_ZT5550) += cpcihp_zt5550.o
obj-$(CONFIG_HOTPLUG_PCI_CPCI_GENERIC) += cpcihp_generic.o
obj-$(CONFIG_HOTPLUG_PCI_SHPC) += shpchp.o
obj-$(CONFIG_HOTPLUG_PCI_RPA) += rpaphp.o
obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR) += rpadlpar_io.o
obj-$(CONFIG_HOTPLUG_PCI_SGI) += sgi_hotplug.o
+obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o
+
+# acpiphp_ibm extends acpiphp, so should be linked afterwards.
+
+obj-$(CONFIG_HOTPLUG_PCI_ACPI_IBM) += acpiphp_ibm.o
# Link this last so it doesn't claim devices that have a real hotplug driver
obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakephp.o
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index 0325d989bb46..38183a534b65 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -68,26 +68,26 @@ static DEFINE_MUTEX(pci_hp_mutex);
static char *pci_bus_speed_strings[] = {
"33 MHz PCI", /* 0x00 */
"66 MHz PCI", /* 0x01 */
- "66 MHz PCIX", /* 0x02 */
- "100 MHz PCIX", /* 0x03 */
- "133 MHz PCIX", /* 0x04 */
+ "66 MHz PCI-X", /* 0x02 */
+ "100 MHz PCI-X", /* 0x03 */
+ "133 MHz PCI-X", /* 0x04 */
NULL, /* 0x05 */
NULL, /* 0x06 */
NULL, /* 0x07 */
NULL, /* 0x08 */
- "66 MHz PCIX 266", /* 0x09 */
- "100 MHz PCIX 266", /* 0x0a */
- "133 MHz PCIX 266", /* 0x0b */
+ "66 MHz PCI-X 266", /* 0x09 */
+ "100 MHz PCI-X 266", /* 0x0a */
+ "133 MHz PCI-X 266", /* 0x0b */
NULL, /* 0x0c */
NULL, /* 0x0d */
NULL, /* 0x0e */
NULL, /* 0x0f */
NULL, /* 0x10 */
- "66 MHz PCIX 533", /* 0x11 */
- "100 MHz PCIX 533", /* 0x12 */
- "133 MHz PCIX 533", /* 0x13 */
- "2.5 GT/s PCI-E", /* 0x14 */
- "5.0 GT/s PCI-E", /* 0x15 */
+ "66 MHz PCI-X 533", /* 0x11 */
+ "100 MHz PCI-X 533", /* 0x12 */
+ "133 MHz PCI-X 533", /* 0x13 */
+ "2.5 GT/s PCIe", /* 0x14 */
+ "5.0 GT/s PCIe", /* 0x15 */
};
#ifdef CONFIG_HOTPLUG_PCI_CPCI
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index b1e97e682500..c83113646223 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -277,6 +277,7 @@ static int hw_pass_through = 1;
struct dmar_domain {
int id; /* domain id */
+ int nid; /* node id */
unsigned long iommu_bmp; /* bitmap of iommus this domain uses*/
struct list_head devices; /* all devices' list */
@@ -400,15 +401,18 @@ static inline void *iommu_kmem_cache_alloc(struct kmem_cache *cachep)
}
-static inline void *alloc_pgtable_page(void)
+static inline void *alloc_pgtable_page(int node)
{
unsigned int flags;
- void *vaddr;
+ struct page *page;
+ void *vaddr = NULL;
/* trying to avoid low memory issues */
flags = current->flags & PF_MEMALLOC;
current->flags |= PF_MEMALLOC;
- vaddr = (void *)get_zeroed_page(GFP_ATOMIC);
+ page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0);
+ if (page)
+ vaddr = page_address(page);
current->flags &= (~PF_MEMALLOC | flags);
return vaddr;
}
@@ -589,7 +593,8 @@ static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
root = &iommu->root_entry[bus];
context = get_context_addr_from_root(root);
if (!context) {
- context = (struct context_entry *)alloc_pgtable_page();
+ context = (struct context_entry *)
+ alloc_pgtable_page(iommu->node);
if (!context) {
spin_unlock_irqrestore(&iommu->lock, flags);
return NULL;
@@ -732,7 +737,7 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
if (!dma_pte_present(pte)) {
uint64_t pteval;
- tmp_page = alloc_pgtable_page();
+ tmp_page = alloc_pgtable_page(domain->nid);
if (!tmp_page)
return NULL;
@@ -868,7 +873,7 @@ static int iommu_alloc_root_entry(struct intel_iommu *iommu)
struct root_entry *root;
unsigned long flags;
- root = (struct root_entry *)alloc_pgtable_page();
+ root = (struct root_entry *)alloc_pgtable_page(iommu->node);
if (!root)
return -ENOMEM;
@@ -1263,6 +1268,7 @@ static struct dmar_domain *alloc_domain(void)
if (!domain)
return NULL;
+ domain->nid = -1;
memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
domain->flags = 0;
@@ -1420,9 +1426,10 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
domain->iommu_snooping = 0;
domain->iommu_count = 1;
+ domain->nid = iommu->node;
/* always allocate the top pgd */
- domain->pgd = (struct dma_pte *)alloc_pgtable_page();
+ domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
if (!domain->pgd)
return -ENOMEM;
__iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE);
@@ -1577,6 +1584,8 @@ static int domain_context_mapping_one(struct dmar_domain *domain, int segment,
spin_lock_irqsave(&domain->iommu_lock, flags);
if (!test_and_set_bit(iommu->seq_id, &domain->iommu_bmp)) {
domain->iommu_count++;
+ if (domain->iommu_count == 1)
+ domain->nid = iommu->node;
domain_update_iommu_cap(domain);
}
spin_unlock_irqrestore(&domain->iommu_lock, flags);
@@ -3416,6 +3425,7 @@ static struct dmar_domain *iommu_alloc_vm_domain(void)
return NULL;
domain->id = vm_domid++;
+ domain->nid = -1;
memset(&domain->iommu_bmp, 0, sizeof(unsigned long));
domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
@@ -3442,9 +3452,10 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width)
domain->iommu_coherency = 0;
domain->iommu_snooping = 0;
domain->max_addr = 0;
+ domain->nid = -1;
/* always allocate the top pgd */
- domain->pgd = (struct dma_pte *)alloc_pgtable_page();
+ domain->pgd = (struct dma_pte *)alloc_pgtable_page(domain->nid);
if (!domain->pgd)
return -ENOMEM;
domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c
index 0ed78a764ded..255deaa095d7 100644
--- a/drivers/pci/intr_remapping.c
+++ b/drivers/pci/intr_remapping.c
@@ -2,6 +2,7 @@
#include <linux/dmar.h>
#include <linux/spinlock.h>
#include <linux/jiffies.h>
+#include <linux/hpet.h>
#include <linux/pci.h>
#include <linux/irq.h>
#include <asm/io_apic.h>
@@ -14,7 +15,8 @@
#include "pci.h"
static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
-static int ir_ioapic_num;
+static struct hpet_scope ir_hpet[MAX_HPET_TBS];
+static int ir_ioapic_num, ir_hpet_num;
int intr_remapping_enabled;
static int disable_intremap;
@@ -343,6 +345,16 @@ int flush_irte(int irq)
return rc;
}
+struct intel_iommu *map_hpet_to_ir(u8 hpet_id)
+{
+ int i;
+
+ for (i = 0; i < MAX_HPET_TBS; i++)
+ if (ir_hpet[i].id == hpet_id)
+ return ir_hpet[i].iommu;
+ return NULL;
+}
+
struct intel_iommu *map_ioapic_to_ir(int apic)
{
int i;
@@ -470,6 +482,36 @@ int set_ioapic_sid(struct irte *irte, int apic)
return 0;
}
+int set_hpet_sid(struct irte *irte, u8 id)
+{
+ int i;
+ u16 sid = 0;
+
+ if (!irte)
+ return -1;
+
+ for (i = 0; i < MAX_HPET_TBS; i++) {
+ if (ir_hpet[i].id == id) {
+ sid = (ir_hpet[i].bus << 8) | ir_hpet[i].devfn;
+ break;
+ }
+ }
+
+ if (sid == 0) {
+ pr_warning("Failed to set source-id of HPET block (%d)\n", id);
+ return -1;
+ }
+
+ /*
+ * Should really use SQ_ALL_16. Some platforms are broken.
+ * While we figure out the right quirks for these broken platforms, use
+ * SQ_13_IGNORE_3 for now.
+ */
+ set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_13_IGNORE_3, sid);
+
+ return 0;
+}
+
int set_msi_sid(struct irte *irte, struct pci_dev *dev)
{
struct pci_dev *bridge;
@@ -548,7 +590,8 @@ static int setup_intr_remapping(struct intel_iommu *iommu, int mode)
if (!iommu->ir_table)
return -ENOMEM;
- pages = alloc_pages(GFP_ATOMIC | __GFP_ZERO, INTR_REMAP_PAGE_ORDER);
+ pages = alloc_pages_node(iommu->node, GFP_ATOMIC | __GFP_ZERO,
+ INTR_REMAP_PAGE_ORDER);
if (!pages) {
printk(KERN_ERR "failed to allocate pages of order %d\n",
@@ -711,6 +754,34 @@ error:
return -1;
}
+static void ir_parse_one_hpet_scope(struct acpi_dmar_device_scope *scope,
+ struct intel_iommu *iommu)
+{
+ struct acpi_dmar_pci_path *path;
+ u8 bus;
+ int count;
+
+ bus = scope->bus;
+ path = (struct acpi_dmar_pci_path *)(scope + 1);
+ count = (scope->length - sizeof(struct acpi_dmar_device_scope))
+ / sizeof(struct acpi_dmar_pci_path);
+
+ while (--count > 0) {
+ /*
+ * Access PCI directly due to the PCI
+ * subsystem isn't initialized yet.
+ */
+ bus = read_pci_config_byte(bus, path->dev, path->fn,
+ PCI_SECONDARY_BUS);
+ path++;
+ }
+ ir_hpet[ir_hpet_num].bus = bus;
+ ir_hpet[ir_hpet_num].devfn = PCI_DEVFN(path->dev, path->fn);
+ ir_hpet[ir_hpet_num].iommu = iommu;
+ ir_hpet[ir_hpet_num].id = scope->enumeration_id;
+ ir_hpet_num++;
+}
+
static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope,
struct intel_iommu *iommu)
{
@@ -740,8 +811,8 @@ static void ir_parse_one_ioapic_scope(struct acpi_dmar_device_scope *scope,
ir_ioapic_num++;
}
-static int ir_parse_ioapic_scope(struct acpi_dmar_header *header,
- struct intel_iommu *iommu)
+static int ir_parse_ioapic_hpet_scope(struct acpi_dmar_header *header,
+ struct intel_iommu *iommu)
{
struct acpi_dmar_hardware_unit *drhd;
struct acpi_dmar_device_scope *scope;
@@ -765,6 +836,17 @@ static int ir_parse_ioapic_scope(struct acpi_dmar_header *header,
drhd->address);
ir_parse_one_ioapic_scope(scope, iommu);
+ } else if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_HPET) {
+ if (ir_hpet_num == MAX_HPET_TBS) {
+ printk(KERN_WARNING "Exceeded Max HPET blocks\n");
+ return -1;
+ }
+
+ printk(KERN_INFO "HPET id %d under DRHD base"
+ " 0x%Lx\n", scope->enumeration_id,
+ drhd->address);
+
+ ir_parse_one_hpet_scope(scope, iommu);
}
start += scope->length;
}
@@ -785,7 +867,7 @@ int __init parse_ioapics_under_ir(void)
struct intel_iommu *iommu = drhd->iommu;
if (ecap_ir_support(iommu->ecap)) {
- if (ir_parse_ioapic_scope(drhd->hdr, iommu))
+ if (ir_parse_ioapic_hpet_scope(drhd->hdr, iommu))
return -1;
ir_supported = 1;
diff --git a/drivers/pci/intr_remapping.h b/drivers/pci/intr_remapping.h
index 63a263c18415..5662fecfee60 100644
--- a/drivers/pci/intr_remapping.h
+++ b/drivers/pci/intr_remapping.h
@@ -7,4 +7,11 @@ struct ioapic_scope {
unsigned int devfn; /* PCI devfn number */
};
+struct hpet_scope {
+ struct intel_iommu *iommu;
+ u8 id;
+ unsigned int bus;
+ unsigned int devfn;
+};
+
#define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 4e4c295a049f..5669e54f23df 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -47,6 +47,15 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
unsigned long pci_hotplug_io_size = DEFAULT_HOTPLUG_IO_SIZE;
unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE;
+/*
+ * The default CLS is used if arch didn't set CLS explicitly and not
+ * all pci devices agree on the same value. Arch can override either
+ * the dfl or actual value as it sees fit. Don't forget this is
+ * measured in 32-bit words, not bytes.
+ */
+u8 pci_dfl_cache_line_size __devinitdata = L1_CACHE_BYTES >> 2;
+u8 pci_cache_line_size;
+
/**
* pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
* @bus: pointer to PCI bus structure to search
@@ -1379,6 +1388,7 @@ void pci_pm_init(struct pci_dev *dev)
int pm;
u16 pmc;
+ device_enable_async_suspend(&dev->dev, true);
dev->wakeup_prepared = false;
dev->pm_cap = 0;
@@ -1537,6 +1547,41 @@ void pci_enable_ari(struct pci_dev *dev)
}
/**
+ * pci_enable_acs - enable ACS if hardware support it
+ * @dev: the PCI device
+ */
+void pci_enable_acs(struct pci_dev *dev)
+{
+ int pos;
+ u16 cap;
+ u16 ctrl;
+
+ if (!dev->is_pcie)
+ return;
+
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
+ if (!pos)
+ return;
+
+ pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap);
+ pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
+
+ /* Source Validation */
+ ctrl |= (cap & PCI_ACS_SV);
+
+ /* P2P Request Redirect */
+ ctrl |= (cap & PCI_ACS_RR);
+
+ /* P2P Completion Redirect */
+ ctrl |= (cap & PCI_ACS_CR);
+
+ /* Upstream Forwarding */
+ ctrl |= (cap & PCI_ACS_UF);
+
+ pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
+}
+
+/**
* pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
* @dev: the PCI device
* @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD)
@@ -1669,9 +1714,7 @@ static int __pci_request_region(struct pci_dev *pdev, int bar, const char *res_n
return 0;
err_out:
- dev_warn(&pdev->dev, "BAR %d: can't reserve %s region %pR\n",
- bar,
- pci_resource_flags(pdev, bar) & IORESOURCE_IO ? "I/O" : "mem",
+ dev_warn(&pdev->dev, "BAR %d: can't reserve %pRt\n", bar,
&pdev->resource[bar]);
return -EBUSY;
}
@@ -1866,31 +1909,6 @@ void pci_clear_master(struct pci_dev *dev)
__pci_set_master(dev, false);
}
-#ifdef PCI_DISABLE_MWI
-int pci_set_mwi(struct pci_dev *dev)
-{
- return 0;
-}
-
-int pci_try_set_mwi(struct pci_dev *dev)
-{
- return 0;
-}
-
-void pci_clear_mwi(struct pci_dev *dev)
-{
-}
-
-#else
-
-#ifndef PCI_CACHE_LINE_BYTES
-#define PCI_CACHE_LINE_BYTES L1_CACHE_BYTES
-#endif
-
-/* This can be overridden by arch code. */
-/* Don't forget this is measured in 32-bit words, not bytes */
-u8 pci_cache_line_size = PCI_CACHE_LINE_BYTES / 4;
-
/**
* pci_set_cacheline_size - ensure the CACHE_LINE_SIZE register is programmed
* @dev: the PCI device for which MWI is to be enabled
@@ -1901,13 +1919,12 @@ u8 pci_cache_line_size = PCI_CACHE_LINE_BYTES / 4;
*
* RETURNS: An appropriate -ERRNO error value on error, or zero for success.
*/
-static int
-pci_set_cacheline_size(struct pci_dev *dev)
+int pci_set_cacheline_size(struct pci_dev *dev)
{
u8 cacheline_size;
if (!pci_cache_line_size)
- return -EINVAL; /* The system doesn't support MWI. */
+ return -EINVAL;
/* Validate current setting: the PCI_CACHE_LINE_SIZE must be
equal to or multiple of the right value. */
@@ -1928,6 +1945,24 @@ pci_set_cacheline_size(struct pci_dev *dev)
return -EINVAL;
}
+EXPORT_SYMBOL_GPL(pci_set_cacheline_size);
+
+#ifdef PCI_DISABLE_MWI
+int pci_set_mwi(struct pci_dev *dev)
+{
+ return 0;
+}
+
+int pci_try_set_mwi(struct pci_dev *dev)
+{
+ return 0;
+}
+
+void pci_clear_mwi(struct pci_dev *dev)
+{
+}
+
+#else
/**
* pci_set_mwi - enables memory-write-invalidate PCI transaction
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index d92d1954a2fb..33ed8e0aba1e 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -311,4 +311,6 @@ static inline int pci_resource_alignment(struct pci_dev *dev,
return resource_alignment(res);
}
+extern void pci_enable_acs(struct pci_dev *dev);
+
#endif /* DRIVERS_PCI_H */
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index 52f84fca9f7d..bbc58e38d3f3 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -274,6 +274,7 @@ static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev,
dev_set_name(device, "%s:pcie%02x",
pci_name(parent), get_descriptor_id(port_type, service_type));
device->parent = &parent->dev;
+ device_enable_async_suspend(device, true);
}
/**
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 8105e32117f6..bb2cc39b64ff 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -10,6 +10,8 @@
#include <linux/module.h>
#include <linux/cpumask.h>
#include <linux/pci-aspm.h>
+#include <linux/iommu.h>
+#include <xen/xen.h>
#include "pci.h"
#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */
@@ -222,6 +224,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
if (!sz64)
goto fail;
+ res->flags |= IORESOURCE_MEM_64;
+
if ((sizeof(resource_size_t) < 8) && (sz64 > 0x100000000ULL)) {
dev_err(&dev->dev, "can't handle 64-bit BAR\n");
goto fail;
@@ -234,14 +238,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
} else {
res->start = l64;
res->end = l64 + sz64;
- dev_printk(KERN_DEBUG, &dev->dev,
- "reg %x %s: %pR\n", pos,
- (res->flags & IORESOURCE_PREFETCH) ?
- "64bit mmio pref" : "64bit mmio",
- res);
+ dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pRt\n",
+ pos, res);
}
-
- res->flags |= IORESOURCE_MEM_64;
} else {
sz = pci_size(l, sz, mask);
@@ -251,11 +250,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
res->start = l;
res->end = l + sz;
- dev_printk(KERN_DEBUG, &dev->dev, "reg %x %s: %pR\n", pos,
- (res->flags & IORESOURCE_IO) ? "io port" :
- ((res->flags & IORESOURCE_PREFETCH) ?
- "32bit mmio pref" : "32bit mmio"),
- res);
+ dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pRt\n", pos, res);
}
out:
@@ -323,7 +318,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
res->start = base;
if (!res->end)
res->end = limit + 0xfff;
- dev_printk(KERN_DEBUG, &dev->dev, "bridge io port: %pR\n", res);
+ dev_printk(KERN_DEBUG, &dev->dev, "bridge window: %pRt\n", res);
}
res = child->resource[1];
@@ -335,8 +330,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
res->start = base;
res->end = limit + 0xfffff;
- dev_printk(KERN_DEBUG, &dev->dev, "bridge 32bit mmio: %pR\n",
- res);
+ dev_printk(KERN_DEBUG, &dev->dev, "bridge window: %pRt\n", res);
}
res = child->resource[2];
@@ -375,9 +369,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
res->flags |= IORESOURCE_MEM_64;
res->start = base;
res->end = limit + 0xfffff;
- dev_printk(KERN_DEBUG, &dev->dev, "bridge %sbit mmio pref: %pR\n",
- (res->flags & PCI_PREF_RANGE_TYPE_64) ? "64" : "32",
- res);
+ dev_printk(KERN_DEBUG, &dev->dev, "bridge window: %pRt\n", res);
}
}
@@ -1014,6 +1006,10 @@ static void pci_init_capabilities(struct pci_dev *dev)
/* Single Root I/O Virtualization */
pci_iov_init(dev);
+
+ /* Enable ACS P2P upstream forwarding */
+ if (iommu_found() || xen_initial_domain())
+ pci_enable_acs(dev);
}
void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index a790b1771f9f..1812ae7698de 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -1009,7 +1009,7 @@ DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX,
static void __devinit quirk_amd_ide_mode(struct pci_dev *pdev)
{
- /* set SBX00 SATA in IDE mode to AHCI mode */
+ /* set SBX00/Hudson-2 SATA in IDE mode to AHCI mode */
u8 tmp;
pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &tmp);
@@ -1028,8 +1028,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk
DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk_amd_ide_mode);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_amd_ide_mode);
DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_amd_ide_mode);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_SB900_SATA_IDE, quirk_amd_ide_mode);
-DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_SB900_SATA_IDE, quirk_amd_ide_mode);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SATA_IDE, quirk_amd_ide_mode);
+DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SATA_IDE, quirk_amd_ide_mode);
/*
* Serverworks CSB5 IDE does not fully support native mode
@@ -2595,9 +2595,37 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
static int __init pci_apply_final_quirks(void)
{
struct pci_dev *dev = NULL;
+ u8 cls = 0;
+ u8 tmp;
+
+ if (pci_cache_line_size)
+ printk(KERN_DEBUG "PCI: CLS %u bytes\n",
+ pci_cache_line_size << 2);
while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
pci_fixup_device(pci_fixup_final, dev);
+ /*
+ * If arch hasn't set it explicitly yet, use the CLS
+ * value shared by all PCI devices. If there's a
+ * mismatch, fall back to the default value.
+ */
+ if (!pci_cache_line_size) {
+ pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &tmp);
+ if (!cls)
+ cls = tmp;
+ if (!tmp || cls == tmp)
+ continue;
+
+ printk(KERN_DEBUG "PCI: CLS mismatch (%u != %u), "
+ "using %u bytes\n", cls << 2, tmp << 2,
+ pci_dfl_cache_line_size << 2);
+ pci_cache_line_size = pci_dfl_cache_line_size;
+ }
+ }
+ if (!pci_cache_line_size) {
+ printk(KERN_DEBUG "PCI: CLS %u bytes, default %u\n",
+ cls << 2, pci_dfl_cache_line_size << 2);
+ pci_cache_line_size = cls;
}
return 0;
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 0959430534b2..ceb75333862b 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -299,17 +299,8 @@ static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned lon
r = bus->resource[i];
if (r == &ioport_resource || r == &iomem_resource)
continue;
- if (r && (r->flags & type_mask) == type) {
- if (!r->parent)
- return r;
- /*
- * if there is no child under that, we should release
- * and use it. don't need to reset it, pbus_size_* will
- * set it again
- */
- if (!r->child && !release_resource(r))
- return r;
- }
+ if (r && (r->flags & type_mask) == type && !r->parent)
+ return r;
}
return NULL;
}
@@ -399,8 +390,8 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
align = pci_resource_alignment(dev, r);
order = __ffs(align) - 20;
if (order > 11) {
- dev_warn(&dev->dev, "BAR %d bad alignment %llx: "
- "%pR\n", i, (unsigned long long)align, r);
+ dev_warn(&dev->dev, "BAR %d: bad alignment %llx: "
+ "%pRt\n", i, (unsigned long long)align, r);
r->flags = 0;
continue;
}
@@ -591,10 +582,7 @@ static void pci_bus_dump_res(struct pci_bus *bus)
if (!res || !res->end)
continue;
- dev_printk(KERN_DEBUG, &bus->dev, "resource %d %s %pR\n", i,
- (res->flags & IORESOURCE_IO) ? "io: " :
- ((res->flags & IORESOURCE_PREFETCH)? "pref mem":"mem:"),
- res);
+ dev_printk(KERN_DEBUG, &bus->dev, "resource %d %pRt\n", i, res);
}
}
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index c54526b206b5..5e78f2096ce8 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -51,11 +51,9 @@ void pci_update_resource(struct pci_dev *dev, int resno)
pcibios_resource_to_bus(dev, &region, res);
- dev_dbg(&dev->dev, "BAR %d: got res %pR bus [%#llx-%#llx] "
- "flags %#lx\n", resno, res,
- (unsigned long long)region.start,
- (unsigned long long)region.end,
- (unsigned long)res->flags);
+ dev_dbg(&dev->dev, "BAR %d: got %pRf (bus addr [%#llx-%#llx])\n",
+ resno, res, (unsigned long long)region.start,
+ (unsigned long long)region.end);
new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
if (res->flags & IORESOURCE_IO)
@@ -91,9 +89,9 @@ void pci_update_resource(struct pci_dev *dev, int resno)
}
}
res->flags &= ~IORESOURCE_UNSET;
- dev_dbg(&dev->dev, "BAR %d: moved to bus [%#llx-%#llx] flags %#lx\n",
+ dev_dbg(&dev->dev, "BAR %d: moved to bus addr [%#llx-%#llx]\n",
resno, (unsigned long long)region.start,
- (unsigned long long)region.end, res->flags);
+ (unsigned long long)region.end);
}
int pci_claim_resource(struct pci_dev *dev, int resource)
@@ -110,7 +108,7 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
if (err) {
const char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge";
- dev_err(&dev->dev, "BAR %d: %s of %s %pR\n",
+ dev_err(&dev->dev, "BAR %d: %s %s %pRt\n",
resource,
root ? "address space collision on" :
"no parent found for",
@@ -181,9 +179,8 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
align = pci_resource_alignment(dev, res);
if (!align) {
- dev_info(&dev->dev, "BAR %d: can't allocate resource (bogus "
- "alignment) %pR flags %#lx\n",
- resno, res, res->flags);
+ dev_info(&dev->dev, "BAR %d: can't allocate %pRf "
+ "(bogus alignment)\n", resno, res);
return -EINVAL;
}
@@ -199,8 +196,8 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
}
if (ret)
- dev_info(&dev->dev, "BAR %d: can't allocate %s resource %pR\n",
- resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", res);
+ dev_info(&dev->dev, "BAR %d: can't allocate %pRt\n",
+ resno, res);
return ret;
}
@@ -225,9 +222,8 @@ void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
r_align = pci_resource_alignment(dev, r);
if (!r_align) {
- dev_warn(&dev->dev, "BAR %d: bogus alignment "
- "%pR flags %#lx\n",
- i, r, r->flags);
+ dev_warn(&dev->dev, "BAR %d: bogus alignment %pRf\n",
+ i, r);
continue;
}
for (list = head; ; list = list->next) {
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 17f38a781d47..5ed3b93be27e 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -192,6 +192,27 @@ config PCMCIA_AU1X00
tristate "Au1x00 pcmcia support"
depends on SOC_AU1X00 && PCMCIA
+config PCMCIA_ALCHEMY_DEVBOARD
+ tristate "Alchemy Db/Pb1xxx PCMCIA socket services"
+ depends on SOC_AU1X00 && PCMCIA
+ select 64BIT_PHYS_ADDR
+ help
+ Enable this driver of you want PCMCIA support on your Alchemy
+ Db1000, Db/Pb1100, Db/Pb1500, Db/Pb1550, Db/Pb1200 board.
+ NOT suitable for the PB1000!
+
+ This driver is also available as a module called db1xxx_ss.ko
+
+config PCMCIA_XXS1500
+ tristate "MyCable XXS1500 PCMCIA socket support"
+ depends on PCMCIA && MIPS_XXS1500
+ select 64BIT_PHYS_ADDR
+ help
+ Support for the PCMCIA/CF socket interface on MyCable XXS1500
+ systems.
+
+ This driver is also available as a module called xxs1500_ss.ko
+
config PCMCIA_BCM63XX
tristate "bcm63xx pcmcia support"
depends on BCM63XX && PCMCIA
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index a03a38acd77d..8bd8b0294185 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -34,21 +34,13 @@ obj-$(CONFIG_OMAP_CF) += omap_cf.o
obj-$(CONFIG_BFIN_CFPCMCIA) += bfin_cf_pcmcia.o
obj-$(CONFIG_AT91_CF) += at91_cf.o
obj-$(CONFIG_ELECTRA_CF) += electra_cf.o
+obj-$(CONFIG_PCMCIA_ALCHEMY_DEVBOARD) += db1xxx_ss.o
sa11xx_core-y += soc_common.o sa11xx_base.o
pxa2xx_core-y += soc_common.o pxa2xx_base.o
au1x00_ss-y += au1000_generic.o
au1x00_ss-$(CONFIG_MIPS_PB1000) += au1000_pb1x00.o
-au1x00_ss-$(CONFIG_MIPS_PB1100) += au1000_pb1x00.o
-au1x00_ss-$(CONFIG_MIPS_PB1200) += au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_PB1500) += au1000_pb1x00.o
-au1x00_ss-$(CONFIG_MIPS_DB1000) += au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_DB1100) += au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_DB1200) += au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_DB1500) += au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_DB1550) += au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_XXS1500) += au1000_xxs1500.o
sa1111_cs-y += sa1111_generic.o
sa1111_cs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o
@@ -78,3 +70,5 @@ pxa2xx-obj-$(CONFIG_MACH_E740) += pxa2xx_e740.o
pxa2xx-obj-$(CONFIG_MACH_STARGATE2) += pxa2xx_stargate2.o
obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_core.o $(pxa2xx-obj-y)
+
+obj-$(CONFIG_PCMCIA_XXS1500) += xxs1500_ss.o
diff --git a/drivers/pcmcia/au1000_db1x00.c b/drivers/pcmcia/au1000_db1x00.c
deleted file mode 100644
index c78d77fd7e3b..000000000000
--- a/drivers/pcmcia/au1000_db1x00.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- *
- * Alchemy Semi Db1x00 boards specific pcmcia routines.
- *
- * Copyright 2002 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
- *
- * Copyright 2004 Pete Popov, updated the driver to 2.6.
- * Followed the sa11xx API and largely copied many of the hardware
- * independent functions.
- *
- * ########################################################################
- *
- * This program is free software; you can distribute it and/or modify it
- * under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * ########################################################################
- *
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/init.h>
-
-#include <asm/irq.h>
-#include <asm/signal.h>
-#include <asm/mach-au1x00/au1000.h>
-
-#if defined(CONFIG_MIPS_DB1200)
- #include <db1200.h>
-#elif defined(CONFIG_MIPS_PB1200)
- #include <pb1200.h>
-#else
- #include <asm/mach-db1x00/db1x00.h>
- static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
-#endif
-
-#include "au1000_generic.h"
-
-#if 0
-#define debug(x,args...) printk(KERN_DEBUG "%s: " x, __func__ , ##args)
-#else
-#define debug(x,args...)
-#endif
-
-
-struct au1000_pcmcia_socket au1000_pcmcia_socket[PCMCIA_NUM_SOCKS];
-extern int au1x00_pcmcia_socket_probe(struct device *, struct pcmcia_low_level *, int, int);
-
-static int db1x00_pcmcia_hw_init(struct au1000_pcmcia_socket *skt)
-{
-#ifdef CONFIG_MIPS_DB1550
- skt->irq = skt->nr ? AU1000_GPIO_5 : AU1000_GPIO_3;
-#elif defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200)
- skt->irq = skt->nr ? BOARD_PC1_INT : BOARD_PC0_INT;
-#else
- skt->irq = skt->nr ? AU1000_GPIO_5 : AU1000_GPIO_2;
-#endif
- return 0;
-}
-
-static void db1x00_pcmcia_shutdown(struct au1000_pcmcia_socket *skt)
-{
- bcsr->pcmcia = 0; /* turn off power */
- au_sync_delay(2);
-}
-
-static void
-db1x00_pcmcia_socket_state(struct au1000_pcmcia_socket *skt, struct pcmcia_state *state)
-{
- u32 inserted;
- unsigned char vs;
-
- state->ready = 0;
- state->vs_Xv = 0;
- state->vs_3v = 0;
- state->detect = 0;
-
- switch (skt->nr) {
- case 0:
- vs = bcsr->status & 0x3;
-#if defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200)
- inserted = BOARD_CARD_INSERTED(0);
-#else
- inserted = !(bcsr->status & (1<<4));
-#endif
- break;
- case 1:
- vs = (bcsr->status & 0xC)>>2;
-#if defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200)
- inserted = BOARD_CARD_INSERTED(1);
-#else
- inserted = !(bcsr->status & (1<<5));
-#endif
- break;
- default:/* should never happen */
- return;
- }
-
- if (inserted)
- debug("db1x00 socket %d: inserted %d, vs %d pcmcia %x\n",
- skt->nr, inserted, vs, bcsr->pcmcia);
-
- if (inserted) {
- switch (vs) {
- case 0:
- case 2:
- state->vs_3v=1;
- break;
- case 3: /* 5V */
- break;
- default:
- /* return without setting 'detect' */
- printk(KERN_ERR "db1x00 bad VS (%d)\n",
- vs);
- }
- state->detect = 1;
- state->ready = 1;
- }
- else {
- /* if the card was previously inserted and then ejected,
- * we should turn off power to it
- */
- if ((skt->nr == 0) && (bcsr->pcmcia & BCSR_PCMCIA_PC0RST)) {
- bcsr->pcmcia &= ~(BCSR_PCMCIA_PC0RST |
- BCSR_PCMCIA_PC0DRVEN |
- BCSR_PCMCIA_PC0VPP |
- BCSR_PCMCIA_PC0VCC);
- au_sync_delay(10);
- }
- else if ((skt->nr == 1) && bcsr->pcmcia & BCSR_PCMCIA_PC1RST) {
- bcsr->pcmcia &= ~(BCSR_PCMCIA_PC1RST |
- BCSR_PCMCIA_PC1DRVEN |
- BCSR_PCMCIA_PC1VPP |
- BCSR_PCMCIA_PC1VCC);
- au_sync_delay(10);
- }
- }
-
- state->bvd1=1;
- state->bvd2=1;
- state->wrprot=0;
-}
-
-static int
-db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_state_t *state)
-{
- u16 pwr;
- int sock = skt->nr;
-
- debug("config_skt %d Vcc %dV Vpp %dV, reset %d\n",
- sock, state->Vcc, state->Vpp,
- state->flags & SS_RESET);
-
- /* pcmcia reg was set to zero at init time. Be careful when
- * initializing a socket not to wipe out the settings of the
- * other socket.
- */
- pwr = bcsr->pcmcia;
- pwr &= ~(0xf << sock*8); /* clear voltage settings */
-
- state->Vpp = 0;
- switch(state->Vcc){
- case 0: /* Vcc 0 */
- pwr |= SET_VCC_VPP(0,0,sock);
- break;
- case 50: /* Vcc 5V */
- switch(state->Vpp) {
- case 0:
- pwr |= SET_VCC_VPP(2,0,sock);
- break;
- case 50:
- pwr |= SET_VCC_VPP(2,1,sock);
- break;
- case 12:
- pwr |= SET_VCC_VPP(2,2,sock);
- break;
- case 33:
- default:
- pwr |= SET_VCC_VPP(0,0,sock);
- printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __func__,
- state->Vcc,
- state->Vpp);
- break;
- }
- break;
- case 33: /* Vcc 3.3V */
- switch(state->Vpp) {
- case 0:
- pwr |= SET_VCC_VPP(1,0,sock);
- break;
- case 12:
- pwr |= SET_VCC_VPP(1,2,sock);
- break;
- case 33:
- pwr |= SET_VCC_VPP(1,1,sock);
- break;
- case 50:
- default:
- pwr |= SET_VCC_VPP(0,0,sock);
- printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __func__,
- state->Vcc,
- state->Vpp);
- break;
- }
- break;
- default: /* what's this ? */
- pwr |= SET_VCC_VPP(0,0,sock);
- printk(KERN_ERR "%s: bad Vcc %d\n",
- __func__, state->Vcc);
- break;
- }
-
- bcsr->pcmcia = pwr;
- au_sync_delay(300);
-
- if (sock == 0) {
- if (!(state->flags & SS_RESET)) {
- pwr |= BCSR_PCMCIA_PC0DRVEN;
- bcsr->pcmcia = pwr;
- au_sync_delay(300);
- pwr |= BCSR_PCMCIA_PC0RST;
- bcsr->pcmcia = pwr;
- au_sync_delay(100);
- }
- else {
- pwr &= ~(BCSR_PCMCIA_PC0RST | BCSR_PCMCIA_PC0DRVEN);
- bcsr->pcmcia = pwr;
- au_sync_delay(100);
- }
- }
- else {
- if (!(state->flags & SS_RESET)) {
- pwr |= BCSR_PCMCIA_PC1DRVEN;
- bcsr->pcmcia = pwr;
- au_sync_delay(300);
- pwr |= BCSR_PCMCIA_PC1RST;
- bcsr->pcmcia = pwr;
- au_sync_delay(100);
- }
- else {
- pwr &= ~(BCSR_PCMCIA_PC1RST | BCSR_PCMCIA_PC1DRVEN);
- bcsr->pcmcia = pwr;
- au_sync_delay(100);
- }
- }
- return 0;
-}
-
-/*
- * Enable card status IRQs on (re-)initialisation. This can
- * be called at initialisation, power management event, or
- * pcmcia event.
- */
-void db1x00_socket_init(struct au1000_pcmcia_socket *skt)
-{
- /* nothing to do for now */
-}
-
-/*
- * Disable card status IRQs and PCMCIA bus on suspend.
- */
-void db1x00_socket_suspend(struct au1000_pcmcia_socket *skt)
-{
- /* nothing to do for now */
-}
-
-struct pcmcia_low_level db1x00_pcmcia_ops = {
- .owner = THIS_MODULE,
-
- .hw_init = db1x00_pcmcia_hw_init,
- .hw_shutdown = db1x00_pcmcia_shutdown,
-
- .socket_state = db1x00_pcmcia_socket_state,
- .configure_socket = db1x00_pcmcia_configure_socket,
-
- .socket_init = db1x00_socket_init,
- .socket_suspend = db1x00_socket_suspend
-};
-
-int au1x_board_init(struct device *dev)
-{
- int ret = -ENODEV;
- bcsr->pcmcia = 0; /* turn off power, if it's not already off */
- au_sync_delay(2);
- ret = au1x00_pcmcia_socket_probe(dev, &db1x00_pcmcia_ops, 0, 2);
- return ret;
-}
diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h
index 13a4fbc58711..aa743f6875bd 100644
--- a/drivers/pcmcia/au1000_generic.h
+++ b/drivers/pcmcia/au1000_generic.h
@@ -44,22 +44,12 @@
/* pcmcia socket 1 needs external glue logic so the memory map
* differs from board to board.
*/
-#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || \
- defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1550) || \
- defined(CONFIG_MIPS_PB1200)
+#if defined(CONFIG_MIPS_PB1000)
#define AU1X_SOCK1_IO 0xF08000000ULL
#define AU1X_SOCK1_PHYS_ATTR 0xF48000000ULL
#define AU1X_SOCK1_PHYS_MEM 0xF88000000ULL
#define AU1X_SOCK1_PSEUDO_PHYS_ATTR 0xF4800000
#define AU1X_SOCK1_PSEUDO_PHYS_MEM 0xF8800000
-#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || \
- defined(CONFIG_MIPS_DB1500) || defined(CONFIG_MIPS_DB1550) || \
- defined(CONFIG_MIPS_DB1200)
-#define AU1X_SOCK1_IO 0xF04000000ULL
-#define AU1X_SOCK1_PHYS_ATTR 0xF44000000ULL
-#define AU1X_SOCK1_PHYS_MEM 0xF84000000ULL
-#define AU1X_SOCK1_PSEUDO_PHYS_ATTR 0xF4400000
-#define AU1X_SOCK1_PSEUDO_PHYS_MEM 0xF8400000
#endif
struct pcmcia_state {
diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c
index b1984ed72d1d..5a979cb8f3e6 100644
--- a/drivers/pcmcia/au1000_pb1x00.c
+++ b/drivers/pcmcia/au1000_pb1x00.c
@@ -1,6 +1,6 @@
/*
*
- * Alchemy Semi Pb1x00 boards specific pcmcia routines.
+ * Alchemy Semi Pb1000 boards specific pcmcia routines.
*
* Copyright 2002 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
@@ -46,20 +46,11 @@
#define debug(fmt, arg...) do { } while (0)
-#ifdef CONFIG_MIPS_PB1000
#include <asm/pb1000.h>
#define PCMCIA_IRQ AU1000_GPIO_15
-#elif defined (CONFIG_MIPS_PB1500)
-#include <asm/pb1500.h>
-#define PCMCIA_IRQ AU1500_GPIO_203
-#elif defined (CONFIG_MIPS_PB1100)
-#include <asm/pb1100.h>
-#define PCMCIA_IRQ AU1000_GPIO_11
-#endif
static int pb1x00_pcmcia_init(struct pcmcia_init *init)
{
-#ifdef CONFIG_MIPS_PB1000
u16 pcr;
pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST;
@@ -74,21 +65,10 @@ static int pb1x00_pcmcia_init(struct pcmcia_init *init)
au_sync_delay(20);
return PCMCIA_NUM_SOCKS;
-
-#else /* fixme -- take care of the Pb1500 at some point */
-
- u16 pcr;
- pcr = au_readw(PCMCIA_BOARD_REG) & ~0xf; /* turn off power */
- pcr &= ~(PC_DEASSERT_RST | PC_DRV_EN);
- au_writew(pcr, PCMCIA_BOARD_REG);
- au_sync_delay(500);
- return PCMCIA_NUM_SOCKS;
-#endif
}
static int pb1x00_pcmcia_shutdown(void)
{
-#ifdef CONFIG_MIPS_PB1000
u16 pcr;
pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST;
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0);
@@ -96,14 +76,6 @@ static int pb1x00_pcmcia_shutdown(void)
au_writel(pcr, PB1000_PCR);
au_sync_delay(20);
return 0;
-#else
- u16 pcr;
- pcr = au_readw(PCMCIA_BOARD_REG) & ~0xf; /* turn off power */
- pcr &= ~(PC_DEASSERT_RST | PC_DRV_EN);
- au_writew(pcr, PCMCIA_BOARD_REG);
- au_sync_delay(2);
- return 0;
-#endif
}
static int
@@ -112,21 +84,11 @@ pb1x00_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state)
u32 inserted0, inserted1;
u16 vs0, vs1;
-#ifdef CONFIG_MIPS_PB1000
vs0 = vs1 = (u16)au_readl(PB1000_ACR1);
inserted0 = !(vs0 & (ACR1_SLOT_0_CD1 | ACR1_SLOT_0_CD2));
inserted1 = !(vs1 & (ACR1_SLOT_1_CD1 | ACR1_SLOT_1_CD2));
vs0 = (vs0 >> 4) & 0x3;
vs1 = (vs1 >> 12) & 0x3;
-#else
- vs0 = (au_readw(BOARD_STATUS_REG) >> 4) & 0x3;
-#ifdef CONFIG_MIPS_PB1500
- inserted0 = !((au_readl(GPIO2_PINSTATE) >> 1) & 0x1); /* gpio 201 */
-#else /* Pb1100 */
- inserted0 = !((au_readl(SYS_PINSTATERD) >> 9) & 0x1); /* gpio 9 */
-#endif
- inserted1 = 0;
-#endif
state->ready = 0;
state->vs_Xv = 0;
@@ -203,7 +165,6 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
if(configure->sock > PCMCIA_MAX_SOCK) return -1;
-#ifdef CONFIG_MIPS_PB1000
pcr = au_readl(PB1000_PCR);
if (configure->sock == 0) {
@@ -323,84 +284,6 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
au_writel(pcr, PB1000_PCR);
au_sync_delay(300);
-#else
-
- pcr = au_readw(PCMCIA_BOARD_REG) & ~0xf;
-
- debug("Vcc %dV Vpp %dV, pcr %x, reset %d\n",
- configure->vcc, configure->vpp, pcr, configure->reset);
-
-
- switch(configure->vcc){
- case 0: /* Vcc 0 */
- pcr |= SET_VCC_VPP(0,0);
- break;
- case 50: /* Vcc 5V */
- switch(configure->vpp) {
- case 0:
- pcr |= SET_VCC_VPP(2,0);
- break;
- case 50:
- pcr |= SET_VCC_VPP(2,1);
- break;
- case 12:
- pcr |= SET_VCC_VPP(2,2);
- break;
- case 33:
- default:
- pcr |= SET_VCC_VPP(0,0);
- printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __func__,
- configure->vcc,
- configure->vpp);
- break;
- }
- break;
- case 33: /* Vcc 3.3V */
- switch(configure->vpp) {
- case 0:
- pcr |= SET_VCC_VPP(1,0);
- break;
- case 12:
- pcr |= SET_VCC_VPP(1,2);
- break;
- case 33:
- pcr |= SET_VCC_VPP(1,1);
- break;
- case 50:
- default:
- pcr |= SET_VCC_VPP(0,0);
- printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __func__,
- configure->vcc,
- configure->vpp);
- break;
- }
- break;
- default: /* what's this ? */
- pcr |= SET_VCC_VPP(0,0);
- printk(KERN_ERR "%s: bad Vcc %d\n",
- __func__, configure->vcc);
- break;
- }
-
- au_writew(pcr, PCMCIA_BOARD_REG);
- au_sync_delay(300);
-
- if (!configure->reset) {
- pcr |= PC_DRV_EN;
- au_writew(pcr, PCMCIA_BOARD_REG);
- au_sync_delay(100);
- pcr |= PC_DEASSERT_RST;
- au_writew(pcr, PCMCIA_BOARD_REG);
- au_sync_delay(100);
- }
- else {
- pcr &= ~(PC_DEASSERT_RST | PC_DRV_EN);
- au_writew(pcr, PCMCIA_BOARD_REG);
- au_sync_delay(100);
- }
-#endif
return 0;
}
diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c
deleted file mode 100644
index b43d47b50819..000000000000
--- a/drivers/pcmcia/au1000_xxs1500.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- *
- * MyCable board specific pcmcia routines.
- *
- * Copyright 2003 MontaVista Software Inc.
- * Author: Pete Popov, MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
- *
- * ########################################################################
- *
- * This program is free software; you can distribute it and/or modify it
- * under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * ########################################################################
- *
- *
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/proc_fs.h>
-#include <linux/types.h>
-
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/ss.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/bus_ops.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#include <asm/au1000.h>
-#include <asm/au1000_pcmcia.h>
-
-#define PCMCIA_MAX_SOCK 0
-#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
-#define PCMCIA_IRQ AU1000_GPIO_4
-
-#if 0
-#define DEBUG(x, args...) printk(__func__ ": " x, ##args)
-#else
-#define DEBUG(x,args...)
-#endif
-
-static int xxs1500_pcmcia_init(struct pcmcia_init *init)
-{
- return PCMCIA_NUM_SOCKS;
-}
-
-static int xxs1500_pcmcia_shutdown(void)
-{
- /* turn off power */
- au_writel(au_readl(GPIO2_PINSTATE) | (1<<14)|(1<<30),
- GPIO2_OUTPUT);
- au_sync_delay(100);
-
- /* assert reset */
- au_writel(au_readl(GPIO2_PINSTATE) | (1<<4)|(1<<20),
- GPIO2_OUTPUT);
- au_sync_delay(100);
- return 0;
-}
-
-
-static int
-xxs1500_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state)
-{
- u32 inserted; u32 vs;
- unsigned long gpio, gpio2;
-
- if(sock > PCMCIA_MAX_SOCK) return -1;
-
- gpio = au_readl(SYS_PINSTATERD);
- gpio2 = au_readl(GPIO2_PINSTATE);
-
- vs = gpio2 & ((1<<8) | (1<<9));
- inserted = (!(gpio & 0x1) && !(gpio & 0x2));
-
- state->ready = 0;
- state->vs_Xv = 0;
- state->vs_3v = 0;
- state->detect = 0;
-
- if (inserted) {
- switch (vs) {
- case 0:
- case 1:
- case 2:
- state->vs_3v=1;
- break;
- case 3: /* 5V */
- default:
- /* return without setting 'detect' */
- printk(KERN_ERR "au1x00_cs: unsupported VS\n",
- vs);
- return;
- }
- state->detect = 1;
- }
-
- if (state->detect) {
- state->ready = 1;
- }
-
- state->bvd1= gpio2 & (1<<10);
- state->bvd2 = gpio2 & (1<<11);
- state->wrprot=0;
- return 1;
-}
-
-
-static int xxs1500_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
-{
-
- if(info->sock > PCMCIA_MAX_SOCK) return -1;
- info->irq = PCMCIA_IRQ;
- return 0;
-}
-
-
-static int
-xxs1500_pcmcia_configure_socket(const struct pcmcia_configure *configure)
-{
-
- if(configure->sock > PCMCIA_MAX_SOCK) return -1;
-
- DEBUG("Vcc %dV Vpp %dV, reset %d\n",
- configure->vcc, configure->vpp, configure->reset);
-
- switch(configure->vcc){
- case 33: /* Vcc 3.3V */
- /* turn on power */
- DEBUG("turn on power\n");
- au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<14))|(1<<30),
- GPIO2_OUTPUT);
- au_sync_delay(100);
- break;
- case 50: /* Vcc 5V */
- default: /* what's this ? */
- printk(KERN_ERR "au1x00_cs: unsupported VCC\n");
- case 0: /* Vcc 0 */
- /* turn off power */
- au_sync_delay(100);
- au_writel(au_readl(GPIO2_PINSTATE) | (1<<14)|(1<<30),
- GPIO2_OUTPUT);
- break;
- }
-
- if (!configure->reset) {
- DEBUG("deassert reset\n");
- au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<4))|(1<<20),
- GPIO2_OUTPUT);
- au_sync_delay(100);
- au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<5))|(1<<21),
- GPIO2_OUTPUT);
- }
- else {
- DEBUG("assert reset\n");
- au_writel(au_readl(GPIO2_PINSTATE) | (1<<4)|(1<<20),
- GPIO2_OUTPUT);
- }
- au_sync_delay(100);
- return 0;
-}
-
-struct pcmcia_low_level xxs1500_pcmcia_ops = {
- xxs1500_pcmcia_init,
- xxs1500_pcmcia_shutdown,
- xxs1500_pcmcia_socket_state,
- xxs1500_pcmcia_get_irq_info,
- xxs1500_pcmcia_configure_socket
-};
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index db77e1f3309a..98789c031a7c 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -184,26 +184,33 @@ fail:
=====================================================================*/
-/*
- * Since there is only one interrupt available to CardBus
- * devices, all devices downstream of this device must
- * be using this IRQ.
- */
-static void cardbus_assign_irqs(struct pci_bus *bus, int irq)
+static void cardbus_config_irq_and_cls(struct pci_bus *bus, int irq)
{
struct pci_dev *dev;
list_for_each_entry(dev, &bus->devices, bus_list) {
u8 irq_pin;
+ /*
+ * Since there is only one interrupt available to
+ * CardBus devices, all devices downstream of this
+ * device must be using this IRQ.
+ */
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin);
if (irq_pin) {
dev->irq = irq;
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
}
+ /*
+ * Some controllers transfer very slowly with 0 CLS.
+ * Configure it. This may fail as CLS configuration
+ * is mandatory only for MWI.
+ */
+ pci_set_cacheline_size(dev);
+
if (dev->subordinate)
- cardbus_assign_irqs(dev->subordinate, irq);
+ cardbus_config_irq_and_cls(dev->subordinate, irq);
}
}
@@ -228,7 +235,7 @@ int __ref cb_alloc(struct pcmcia_socket * s)
*/
pci_bus_size_bridges(bus);
pci_bus_assign_resources(bus);
- cardbus_assign_irqs(bus, s->pci_irq);
+ cardbus_config_irq_and_cls(bus, s->pci_irq);
/* socket specific tune function */
if (s->tune_bridge)
diff --git a/drivers/pcmcia/cirrus.h b/drivers/pcmcia/cirrus.h
index ecd4fc7f666f..446a4576e73e 100644
--- a/drivers/pcmcia/cirrus.h
+++ b/drivers/pcmcia/cirrus.h
@@ -30,16 +30,6 @@
#ifndef _LINUX_CIRRUS_H
#define _LINUX_CIRRUS_H
-#ifndef PCI_VENDOR_ID_CIRRUS
-#define PCI_VENDOR_ID_CIRRUS 0x1013
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_6729
-#define PCI_DEVICE_ID_CIRRUS_6729 0x1100
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_6832
-#define PCI_DEVICE_ID_CIRRUS_6832 0x1110
-#endif
-
#define PD67_MISC_CTL_1 0x16 /* Misc control 1 */
#define PD67_FIFO_CTL 0x17 /* FIFO control */
#define PD67_MISC_CTL_2 0x1E /* Misc control 2 */
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index 4a110b7b2673..24dd3c1eac0b 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -1463,7 +1463,9 @@ int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t
return -ENOMEM;
}
tuple.DesiredTuple = code;
- tuple.Attributes = TUPLE_RETURN_COMMON;
+ tuple.Attributes = 0;
+ if (function == BIND_FN_ALL)
+ tuple.Attributes = TUPLE_RETURN_COMMON;
ret = pccard_get_first_tuple(s, function, &tuple);
if (ret != 0)
goto done;
@@ -1480,6 +1482,67 @@ done:
}
EXPORT_SYMBOL(pccard_read_tuple);
+
+/**
+ * pccard_loop_tuple() - loop over tuples in the CIS
+ * @s: the struct pcmcia_socket where the card is inserted
+ * @function: the device function we loop for
+ * @code: which CIS code shall we look for?
+ * @parse: buffer where the tuple shall be parsed (or NULL, if no parse)
+ * @priv_data: private data to be passed to the loop_tuple function.
+ * @loop_tuple: function to call for each CIS entry of type @function. IT
+ * gets passed the raw tuple, the paresed tuple (if @parse is
+ * set) and @priv_data.
+ *
+ * pccard_loop_tuple() loops over all CIS entries of type @function, and
+ * calls the @loop_tuple function for each entry. If the call to @loop_tuple
+ * returns 0, the loop exits. Returns 0 on success or errorcode otherwise.
+ */
+int pccard_loop_tuple(struct pcmcia_socket *s, unsigned int function,
+ cisdata_t code, cisparse_t *parse, void *priv_data,
+ int (*loop_tuple) (tuple_t *tuple,
+ cisparse_t *parse,
+ void *priv_data))
+{
+ tuple_t tuple;
+ cisdata_t *buf;
+ int ret;
+
+ buf = kzalloc(256, GFP_KERNEL);
+ if (buf == NULL) {
+ dev_printk(KERN_WARNING, &s->dev, "no memory to read tuple\n");
+ return -ENOMEM;
+ }
+
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = 255;
+ tuple.TupleOffset = 0;
+ tuple.DesiredTuple = code;
+ tuple.Attributes = 0;
+
+ ret = pccard_get_first_tuple(s, function, &tuple);
+ while (!ret) {
+ if (pccard_get_tuple_data(s, &tuple))
+ goto next_entry;
+
+ if (parse)
+ if (pcmcia_parse_tuple(&tuple, parse))
+ goto next_entry;
+
+ ret = loop_tuple(&tuple, parse, priv_data);
+ if (!ret)
+ break;
+
+next_entry:
+ ret = pccard_get_next_tuple(s, function, &tuple);
+ }
+
+ kfree(buf);
+ return ret;
+}
+EXPORT_SYMBOL(pccard_loop_tuple);
+
+
/*======================================================================
This tries to determine if a card has a sensible CIS. It returns
@@ -1490,7 +1553,7 @@ EXPORT_SYMBOL(pccard_read_tuple);
======================================================================*/
-int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, unsigned int *info)
+int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info)
{
tuple_t *tuple;
cisparse_t *p;
@@ -1515,30 +1578,30 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, unsigned
count = reserved = 0;
tuple->DesiredTuple = RETURN_FIRST_TUPLE;
tuple->Attributes = TUPLE_RETURN_COMMON;
- ret = pccard_get_first_tuple(s, function, tuple);
+ ret = pccard_get_first_tuple(s, BIND_FN_ALL, tuple);
if (ret != 0)
goto done;
/* First tuple should be DEVICE; we should really have either that
or a CFTABLE_ENTRY of some sort */
if ((tuple->TupleCode == CISTPL_DEVICE) ||
- (pccard_read_tuple(s, function, CISTPL_CFTABLE_ENTRY, p) == 0) ||
- (pccard_read_tuple(s, function, CISTPL_CFTABLE_ENTRY_CB, p) == 0))
+ (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY, p) == 0) ||
+ (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY_CB, p) == 0))
dev_ok++;
/* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2
tuple, for card identification. Certain old D-Link and Linksys
cards have only a broken VERS_2 tuple; hence the bogus test. */
- if ((pccard_read_tuple(s, function, CISTPL_MANFID, p) == 0) ||
- (pccard_read_tuple(s, function, CISTPL_VERS_1, p) == 0) ||
- (pccard_read_tuple(s, function, CISTPL_VERS_2, p) != -ENOSPC))
+ if ((pccard_read_tuple(s, BIND_FN_ALL, CISTPL_MANFID, p) == 0) ||
+ (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_1, p) == 0) ||
+ (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_2, p) != -ENOSPC))
ident_ok++;
if (!dev_ok && !ident_ok)
goto done;
for (count = 1; count < MAX_TUPLES; count++) {
- ret = pccard_get_next_tuple(s, function, tuple);
+ ret = pccard_get_next_tuple(s, BIND_FN_ALL, tuple);
if (ret != 0)
break;
if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) ||
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index 79615e6d540b..70432cae76eb 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -197,8 +197,23 @@ int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function,
cisdata_t code, void *parse);
int pcmcia_replace_cis(struct pcmcia_socket *s,
const u8 *data, const size_t len);
-int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function,
- unsigned int *count);
+int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *count);
+
+/* loop over CIS entries */
+int pccard_loop_tuple(struct pcmcia_socket *s, unsigned int function,
+ cisdata_t code, cisparse_t *parse, void *priv_data,
+ int (*loop_tuple) (tuple_t *tuple,
+ cisparse_t *parse,
+ void *priv_data));
+
+int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function,
+ tuple_t *tuple);
+
+int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function,
+ tuple_t *tuple);
+
+int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple);
+
/* rsrc_mgr.c */
int pcmcia_validate_mem(struct pcmcia_socket *s);
diff --git a/drivers/pcmcia/db1xxx_ss.c b/drivers/pcmcia/db1xxx_ss.c
new file mode 100644
index 000000000000..b35b72b0d5b5
--- /dev/null
+++ b/drivers/pcmcia/db1xxx_ss.c
@@ -0,0 +1,630 @@
+/*
+ * PCMCIA socket code for the Alchemy Db1xxx/Pb1xxx boards.
+ *
+ * Copyright (c) 2009 Manuel Lauss <manuel.lauss@gmail.com>
+ *
+ */
+
+/* This is a fairly generic PCMCIA socket driver suitable for the
+ * following Alchemy Development boards:
+ * Db1000, Db/Pb1500, Db/Pb1100, Db/Pb1550, Db/Pb1200.
+ *
+ * The Db1000 is used as a reference: Per-socket card-, carddetect- and
+ * statuschange IRQs connected to SoC GPIOs, control and status register
+ * bits arranged in per-socket groups in an external PLD. All boards
+ * listed here use this layout, including bit positions and meanings.
+ * Of course there are exceptions in later boards:
+ *
+ * - Pb1100/Pb1500: single socket only; voltage key bits VS are
+ * at STATUS[5:4] (instead of STATUS[1:0]).
+ * - Au1200-based: additional card-eject irqs, irqs not gpios!
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/resource.h>
+#include <linux/spinlock.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-db1x00/bcsr.h>
+
+#define MEM_MAP_SIZE 0x400000
+#define IO_MAP_SIZE 0x1000
+
+struct db1x_pcmcia_sock {
+ struct pcmcia_socket socket;
+ int nr; /* socket number */
+ void *virt_io;
+
+ /* the "pseudo" addresses of the PCMCIA space. */
+ unsigned long phys_io;
+ unsigned long phys_attr;
+ unsigned long phys_mem;
+
+ /* previous flags for set_socket() */
+ unsigned int old_flags;
+
+ /* interrupt sources: linux irq numbers! */
+ int insert_irq; /* default carddetect irq */
+ int stschg_irq; /* card-status-change irq */
+ int card_irq; /* card irq */
+ int eject_irq; /* db1200/pb1200 have these */
+
+#define BOARD_TYPE_DEFAULT 0 /* most boards */
+#define BOARD_TYPE_DB1200 1 /* IRQs aren't gpios */
+#define BOARD_TYPE_PB1100 2 /* VS bits slightly different */
+ int board_type;
+};
+
+#define to_db1x_socket(x) container_of(x, struct db1x_pcmcia_sock, socket)
+
+/* DB/PB1200: check CPLD SIGSTATUS register bit 10/12 */
+static int db1200_card_inserted(struct db1x_pcmcia_sock *sock)
+{
+ unsigned short sigstat;
+
+ sigstat = bcsr_read(BCSR_SIGSTAT);
+ return sigstat & 1 << (8 + 2 * sock->nr);
+}
+
+/* carddetect gpio: low-active */
+static int db1000_card_inserted(struct db1x_pcmcia_sock *sock)
+{
+ return !gpio_get_value(irq_to_gpio(sock->insert_irq));
+}
+
+static int db1x_card_inserted(struct db1x_pcmcia_sock *sock)
+{
+ switch (sock->board_type) {
+ case BOARD_TYPE_DB1200:
+ return db1200_card_inserted(sock);
+ default:
+ return db1000_card_inserted(sock);
+ }
+}
+
+/* STSCHG tends to bounce heavily when cards are inserted/ejected.
+ * To avoid this, the interrupt is normally disabled and only enabled
+ * after reset to a card has been de-asserted.
+ */
+static inline void set_stschg(struct db1x_pcmcia_sock *sock, int en)
+{
+ if (sock->stschg_irq != -1) {
+ if (en)
+ enable_irq(sock->stschg_irq);
+ else
+ disable_irq(sock->stschg_irq);
+ }
+}
+
+static irqreturn_t db1000_pcmcia_cdirq(int irq, void *data)
+{
+ struct db1x_pcmcia_sock *sock = data;
+
+ pcmcia_parse_events(&sock->socket, SS_DETECT);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t db1000_pcmcia_stschgirq(int irq, void *data)
+{
+ struct db1x_pcmcia_sock *sock = data;
+
+ pcmcia_parse_events(&sock->socket, SS_STSCHG);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t db1200_pcmcia_cdirq(int irq, void *data)
+{
+ struct db1x_pcmcia_sock *sock = data;
+
+ /* Db/Pb1200 have separate per-socket insertion and ejection
+ * interrupts which stay asserted as long as the card is
+ * inserted/missing. The one which caused us to be called
+ * needs to be disabled and the other one enabled.
+ */
+ if (irq == sock->insert_irq) {
+ disable_irq_nosync(sock->insert_irq);
+ enable_irq(sock->eject_irq);
+ } else {
+ disable_irq_nosync(sock->eject_irq);
+ enable_irq(sock->insert_irq);
+ }
+
+ pcmcia_parse_events(&sock->socket, SS_DETECT);
+
+ return IRQ_HANDLED;
+}
+
+static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock)
+{
+ int ret;
+ unsigned long flags;
+
+ if (sock->stschg_irq != -1) {
+ ret = request_irq(sock->stschg_irq, db1000_pcmcia_stschgirq,
+ 0, "pcmcia_stschg", sock);
+ if (ret)
+ return ret;
+ }
+
+ /* Db/Pb1200 have separate per-socket insertion and ejection
+ * interrupts, which should show edge behaviour but don't.
+ * So interrupts are disabled until both insertion and
+ * ejection handler have been registered and the currently
+ * active one disabled.
+ */
+ if (sock->board_type == BOARD_TYPE_DB1200) {
+ local_irq_save(flags);
+
+ ret = request_irq(sock->insert_irq, db1200_pcmcia_cdirq,
+ IRQF_DISABLED, "pcmcia_insert", sock);
+ if (ret)
+ goto out1;
+
+ ret = request_irq(sock->eject_irq, db1200_pcmcia_cdirq,
+ IRQF_DISABLED, "pcmcia_eject", sock);
+ if (ret) {
+ free_irq(sock->insert_irq, sock);
+ local_irq_restore(flags);
+ goto out1;
+ }
+
+ /* disable the currently active one */
+ if (db1200_card_inserted(sock))
+ disable_irq_nosync(sock->insert_irq);
+ else
+ disable_irq_nosync(sock->eject_irq);
+
+ local_irq_restore(flags);
+ } else {
+ /* all other (older) Db1x00 boards use a GPIO to show
+ * card detection status: use both-edge triggers.
+ */
+ set_irq_type(sock->insert_irq, IRQ_TYPE_EDGE_BOTH);
+ ret = request_irq(sock->insert_irq, db1000_pcmcia_cdirq,
+ 0, "pcmcia_carddetect", sock);
+
+ if (ret)
+ goto out1;
+ }
+
+ return 0; /* all done */
+
+out1:
+ if (sock->stschg_irq != -1)
+ free_irq(sock->stschg_irq, sock);
+
+ return ret;
+}
+
+static void db1x_pcmcia_free_irqs(struct db1x_pcmcia_sock *sock)
+{
+ if (sock->stschg_irq != -1)
+ free_irq(sock->stschg_irq, sock);
+
+ free_irq(sock->insert_irq, sock);
+ if (sock->eject_irq != -1)
+ free_irq(sock->eject_irq, sock);
+}
+
+/*
+ * configure a PCMCIA socket on the Db1x00 series of boards (and
+ * compatibles).
+ *
+ * 2 external registers are involved:
+ * pcmcia_status (offset 0x04): bits [0:1/2:3]: read card voltage id
+ * pcmcia_control(offset 0x10):
+ * bits[0:1] set vcc for card
+ * bits[2:3] set vpp for card
+ * bit 4: enable data buffers
+ * bit 7: reset# for card
+ * add 8 for second socket.
+ */
+static int db1x_pcmcia_configure(struct pcmcia_socket *skt,
+ struct socket_state_t *state)
+{
+ struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
+ unsigned short cr_clr, cr_set;
+ unsigned int changed;
+ int v, p, ret;
+
+ /* card voltage setup */
+ cr_clr = (0xf << (sock->nr * 8)); /* clear voltage settings */
+ cr_set = 0;
+ v = p = ret = 0;
+
+ switch (state->Vcc) {
+ case 50:
+ ++v;
+ case 33:
+ ++v;
+ case 0:
+ break;
+ default:
+ printk(KERN_INFO "pcmcia%d unsupported Vcc %d\n",
+ sock->nr, state->Vcc);
+ }
+
+ switch (state->Vpp) {
+ case 12:
+ ++p;
+ case 33:
+ case 50:
+ ++p;
+ case 0:
+ break;
+ default:
+ printk(KERN_INFO "pcmcia%d unsupported Vpp %d\n",
+ sock->nr, state->Vpp);
+ }
+
+ /* sanity check: Vpp must be 0, 12, or Vcc */
+ if (((state->Vcc == 33) && (state->Vpp == 50)) ||
+ ((state->Vcc == 50) && (state->Vpp == 33))) {
+ printk(KERN_INFO "pcmcia%d bad Vcc/Vpp combo (%d %d)\n",
+ sock->nr, state->Vcc, state->Vpp);
+ v = p = 0;
+ ret = -EINVAL;
+ }
+
+ /* create new voltage code */
+ cr_set |= ((v << 2) | p) << (sock->nr * 8);
+
+ changed = state->flags ^ sock->old_flags;
+
+ if (changed & SS_RESET) {
+ if (state->flags & SS_RESET) {
+ set_stschg(sock, 0);
+ /* assert reset, disable io buffers */
+ cr_clr |= (1 << (7 + (sock->nr * 8)));
+ cr_clr |= (1 << (4 + (sock->nr * 8)));
+ } else {
+ /* de-assert reset, enable io buffers */
+ cr_set |= 1 << (7 + (sock->nr * 8));
+ cr_set |= 1 << (4 + (sock->nr * 8));
+ }
+ }
+
+ /* update PCMCIA configuration */
+ bcsr_mod(BCSR_PCMCIA, cr_clr, cr_set);
+
+ sock->old_flags = state->flags;
+
+ /* reset was taken away: give card time to initialize properly */
+ if ((changed & SS_RESET) && !(state->flags & SS_RESET)) {
+ msleep(500);
+ set_stschg(sock, 1);
+ }
+
+ return ret;
+}
+
+/* VCC bits at [3:2]/[11:10] */
+#define GET_VCC(cr, socknr) \
+ ((((cr) >> 2) >> ((socknr) * 8)) & 3)
+
+/* VS bits at [0:1]/[3:2] */
+#define GET_VS(sr, socknr) \
+ (((sr) >> (2 * (socknr))) & 3)
+
+/* reset bits at [7]/[15] */
+#define GET_RESET(cr, socknr) \
+ ((cr) & (1 << (7 + (8 * (socknr)))))
+
+static int db1x_pcmcia_get_status(struct pcmcia_socket *skt,
+ unsigned int *value)
+{
+ struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
+ unsigned short cr, sr;
+ unsigned int status;
+
+ status = db1x_card_inserted(sock) ? SS_DETECT : 0;
+
+ cr = bcsr_read(BCSR_PCMCIA);
+ sr = bcsr_read(BCSR_STATUS);
+
+ /* PB1100/PB1500: voltage key bits are at [5:4] */
+ if (sock->board_type == BOARD_TYPE_PB1100)
+ sr >>= 4;
+
+ /* determine card type */
+ switch (GET_VS(sr, sock->nr)) {
+ case 0:
+ case 2:
+ status |= SS_3VCARD; /* 3V card */
+ case 3:
+ break; /* 5V card: set nothing */
+ default:
+ status |= SS_XVCARD; /* treated as unsupported in core */
+ }
+
+ /* if Vcc is not zero, we have applied power to a card */
+ status |= GET_VCC(cr, sock->nr) ? SS_POWERON : 0;
+
+ /* reset de-asserted? then we're ready */
+ status |= (GET_RESET(cr, sock->nr)) ? SS_READY : SS_RESET;
+
+ *value = status;
+
+ return 0;
+}
+
+static int db1x_pcmcia_sock_init(struct pcmcia_socket *skt)
+{
+ return 0;
+}
+
+static int db1x_pcmcia_sock_suspend(struct pcmcia_socket *skt)
+{
+ return 0;
+}
+
+static int au1x00_pcmcia_set_io_map(struct pcmcia_socket *skt,
+ struct pccard_io_map *map)
+{
+ struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
+
+ map->start = (u32)sock->virt_io;
+ map->stop = map->start + IO_MAP_SIZE;
+
+ return 0;
+}
+
+static int au1x00_pcmcia_set_mem_map(struct pcmcia_socket *skt,
+ struct pccard_mem_map *map)
+{
+ struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
+
+ if (map->flags & MAP_ATTRIB)
+ map->static_start = sock->phys_attr + map->card_start;
+ else
+ map->static_start = sock->phys_mem + map->card_start;
+
+ return 0;
+}
+
+static struct pccard_operations db1x_pcmcia_operations = {
+ .init = db1x_pcmcia_sock_init,
+ .suspend = db1x_pcmcia_sock_suspend,
+ .get_status = db1x_pcmcia_get_status,
+ .set_socket = db1x_pcmcia_configure,
+ .set_io_map = au1x00_pcmcia_set_io_map,
+ .set_mem_map = au1x00_pcmcia_set_mem_map,
+};
+
+static int __devinit db1x_pcmcia_socket_probe(struct platform_device *pdev)
+{
+ struct db1x_pcmcia_sock *sock;
+ struct resource *r;
+ phys_t physio;
+ int ret, bid;
+
+ sock = kzalloc(sizeof(struct db1x_pcmcia_sock), GFP_KERNEL);
+ if (!sock)
+ return -ENOMEM;
+
+ sock->nr = pdev->id;
+
+ bid = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
+ switch (bid) {
+ case BCSR_WHOAMI_PB1500:
+ case BCSR_WHOAMI_PB1500R2:
+ case BCSR_WHOAMI_PB1100:
+ sock->board_type = BOARD_TYPE_PB1100;
+ break;
+ case BCSR_WHOAMI_DB1000 ... BCSR_WHOAMI_PB1550_SDR:
+ sock->board_type = BOARD_TYPE_DEFAULT;
+ break;
+ case BCSR_WHOAMI_PB1200 ... BCSR_WHOAMI_DB1200:
+ sock->board_type = BOARD_TYPE_DB1200;
+ break;
+ default:
+ printk(KERN_INFO "db1xxx-ss: unknown board %d!\n", bid);
+ ret = -ENODEV;
+ goto out0;
+ };
+
+ /*
+ * gather resources necessary and optional nice-to-haves to
+ * operate a socket:
+ * This includes IRQs for Carddetection/ejection, the card
+ * itself and optional status change detection.
+ * Also, the memory areas covered by a socket. For these
+ * we require the 32bit "pseudo" addresses (see the au1000.h
+ * header for more information).
+ */
+
+ /* card: irq assigned to the card itself. */
+ r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "card");
+ sock->card_irq = r ? r->start : 0;
+
+ /* insert: irq which triggers on card insertion/ejection */
+ r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "insert");
+ sock->insert_irq = r ? r->start : -1;
+
+ /* stschg: irq which trigger on card status change (optional) */
+ r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "stschg");
+ sock->stschg_irq = r ? r->start : -1;
+
+ /* eject: irq which triggers on ejection (DB1200/PB1200 only) */
+ r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "eject");
+ sock->eject_irq = r ? r->start : -1;
+
+ ret = -ENODEV;
+
+ /*
+ * pseudo-attr: The 32bit address of the PCMCIA attribute space
+ * for this socket (usually the 36bit address shifted 4 to the
+ * right).
+ */
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pseudo-attr");
+ if (!r) {
+ printk(KERN_ERR "pcmcia%d has no 'pseudo-attr' resource!\n",
+ sock->nr);
+ goto out0;
+ }
+ sock->phys_attr = r->start;
+
+ /*
+ * pseudo-mem: The 32bit address of the PCMCIA memory space for
+ * this socket (usually the 36bit address shifted 4 to the right)
+ */
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pseudo-mem");
+ if (!r) {
+ printk(KERN_ERR "pcmcia%d has no 'pseudo-mem' resource!\n",
+ sock->nr);
+ goto out0;
+ }
+ sock->phys_mem = r->start;
+
+ /*
+ * pseudo-io: The 32bit address of the PCMCIA IO space for this
+ * socket (usually the 36bit address shifted 4 to the right).
+ */
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pseudo-io");
+ if (!r) {
+ printk(KERN_ERR "pcmcia%d has no 'pseudo-io' resource!\n",
+ sock->nr);
+ goto out0;
+ }
+ sock->phys_io = r->start;
+
+
+ /* IO: we must remap the full 36bit address (for reference see
+ * alchemy/common/setup.c::__fixup_bigphys_addr())
+ */
+ physio = ((phys_t)sock->phys_io) << 4;
+
+ /*
+ * PCMCIA client drivers use the inb/outb macros to access
+ * the IO registers. Since mips_io_port_base is added
+ * to the access address of the mips implementation of
+ * inb/outb, we need to subtract it here because we want
+ * to access the I/O or MEM address directly, without
+ * going through this "mips_io_port_base" mechanism.
+ */
+ sock->virt_io = (void *)(ioremap(physio, IO_MAP_SIZE) -
+ mips_io_port_base);
+
+ if (!sock->virt_io) {
+ printk(KERN_ERR "pcmcia%d: cannot remap IO area\n",
+ sock->nr);
+ ret = -ENOMEM;
+ goto out0;
+ }
+
+ sock->socket.ops = &db1x_pcmcia_operations;
+ sock->socket.owner = THIS_MODULE;
+ sock->socket.pci_irq = sock->card_irq;
+ sock->socket.features = SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
+ sock->socket.map_size = MEM_MAP_SIZE;
+ sock->socket.io_offset = (unsigned long)sock->virt_io;
+ sock->socket.dev.parent = &pdev->dev;
+ sock->socket.resource_ops = &pccard_static_ops;
+
+ platform_set_drvdata(pdev, sock);
+
+ ret = db1x_pcmcia_setup_irqs(sock);
+ if (ret) {
+ printk(KERN_ERR "pcmcia%d cannot setup interrupts\n",
+ sock->nr);
+ goto out1;
+ }
+
+ set_stschg(sock, 0);
+
+ ret = pcmcia_register_socket(&sock->socket);
+ if (ret) {
+ printk(KERN_ERR "pcmcia%d failed to register\n", sock->nr);
+ goto out2;
+ }
+
+ printk(KERN_INFO "Alchemy Db/Pb1xxx pcmcia%d @ io/attr/mem %08lx"
+ "(%p) %08lx %08lx card/insert/stschg/eject irqs @ %d "
+ "%d %d %d\n", sock->nr, sock->phys_io, sock->virt_io,
+ sock->phys_attr, sock->phys_mem, sock->card_irq,
+ sock->insert_irq, sock->stschg_irq, sock->eject_irq);
+
+ return 0;
+
+out2:
+ db1x_pcmcia_free_irqs(sock);
+out1:
+ iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
+out0:
+ kfree(sock);
+ return ret;
+}
+
+static int __devexit db1x_pcmcia_socket_remove(struct platform_device *pdev)
+{
+ struct db1x_pcmcia_sock *sock = platform_get_drvdata(pdev);
+
+ db1x_pcmcia_free_irqs(sock);
+ pcmcia_unregister_socket(&sock->socket);
+ iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
+ kfree(sock);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int db1x_pcmcia_suspend(struct device *dev)
+{
+ return pcmcia_socket_dev_suspend(dev);
+}
+
+static int db1x_pcmcia_resume(struct device *dev)
+{
+ return pcmcia_socket_dev_resume(dev);
+}
+
+static struct dev_pm_ops db1x_pcmcia_pmops = {
+ .resume = db1x_pcmcia_resume,
+ .suspend = db1x_pcmcia_suspend,
+ .thaw = db1x_pcmcia_resume,
+ .freeze = db1x_pcmcia_suspend,
+};
+
+#define DB1XXX_SS_PMOPS &db1x_pcmcia_pmops
+
+#else
+
+#define DB1XXX_SS_PMOPS NULL
+
+#endif
+
+static struct platform_driver db1x_pcmcia_socket_driver = {
+ .driver = {
+ .name = "db1xxx_pcmcia",
+ .owner = THIS_MODULE,
+ .pm = DB1XXX_SS_PMOPS
+ },
+ .probe = db1x_pcmcia_socket_probe,
+ .remove = __devexit_p(db1x_pcmcia_socket_remove),
+};
+
+int __init db1x_pcmcia_socket_load(void)
+{
+ return platform_driver_register(&db1x_pcmcia_socket_driver);
+}
+
+void __exit db1x_pcmcia_socket_unload(void)
+{
+ platform_driver_unregister(&db1x_pcmcia_socket_driver);
+}
+
+module_init(db1x_pcmcia_socket_load);
+module_exit(db1x_pcmcia_socket_unload);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PCMCIA Socket Services for Alchemy Db/Pb1x00 boards");
+MODULE_AUTHOR("Manuel Lauss");
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 9f300d3cb125..f5b7079f13d3 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -547,7 +547,7 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev)
if (!vers1)
return -ENOMEM;
- if (!pccard_read_tuple(p_dev->socket, p_dev->func,
+ if (!pccard_read_tuple(p_dev->socket, BIND_FN_ALL,
CISTPL_MANFID, &manf_id)) {
p_dev->manf_id = manf_id.manf;
p_dev->card_id = manf_id.card;
@@ -581,9 +581,9 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev)
kfree(devgeo);
}
- if (!pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_VERS_1,
+ if (!pccard_read_tuple(p_dev->socket, BIND_FN_ALL, CISTPL_VERS_1,
vers1)) {
- for (i=0; i < vers1->ns; i++) {
+ for (i = 0; i < min_t(unsigned int, 4, vers1->ns); i++) {
char *tmp;
unsigned int length;
@@ -733,7 +733,7 @@ static int pcmcia_card_add(struct pcmcia_socket *s)
return -EAGAIN; /* try again, but later... */
}
- ret = pccard_validate_cis(s, BIND_FN_ALL, &no_chains);
+ ret = pccard_validate_cis(s, &no_chains);
if (ret || !no_chains) {
ds_dev_dbg(0, &s->dev, "invalid CIS or invalid resources\n");
return -ENODEV;
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index b906abe26ad0..a4aacb830b80 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -1053,8 +1053,8 @@ static int i365_set_io_map(u_short sock, struct pccard_io_map *io)
u_char map, ioctl;
debug(1, "SetIOMap(%d, %d, %#2.2x, %d ns, "
- "%#x-%#x)\n", sock, io->map, io->flags,
- io->speed, io->start, io->stop);
+ "%#llx-%#llx)\n", sock, io->map, io->flags, io->speed,
+ (unsigned long long)io->start, (unsigned long long)io->stop);
map = io->map;
if ((map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
(io->stop < io->start)) return -EINVAL;
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
index d1d89c4491ad..7dfbee1dcd76 100644
--- a/drivers/pcmcia/m32r_cfc.c
+++ b/drivers/pcmcia/m32r_cfc.c
@@ -537,8 +537,9 @@ static int _pcc_set_io_map(u_short sock, struct pccard_io_map *io)
u_char map;
debug(3, "m32r_cfc: SetIOMap(%d, %d, %#2.2x, %d ns, "
- "%#lx-%#lx)\n", sock, io->map, io->flags,
- io->speed, io->start, io->stop);
+ "%#llx-%#llx)\n", sock, io->map, io->flags,
+ io->speed, (unsigned long long)io->start,
+ (unsigned long long)io->stop);
map = io->map;
return 0;
@@ -554,8 +555,9 @@ static int _pcc_set_mem_map(u_short sock, struct pccard_mem_map *mem)
pcc_socket_t *t = &socket[sock];
debug(3, "m32r_cfc: SetMemMap(%d, %d, %#2.2x, %d ns, "
- "%#lx, %#x)\n", sock, map, mem->flags,
- mem->speed, mem->static_start, mem->card_start);
+ "%#llx, %#x)\n", sock, map, mem->flags,
+ mem->speed, (unsigned long long)mem->static_start,
+ mem->card_start);
/*
* sanity check
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
index a0655839c8d3..c6524f99ccc3 100644
--- a/drivers/pcmcia/m32r_pcc.c
+++ b/drivers/pcmcia/m32r_pcc.c
@@ -492,8 +492,9 @@ static int _pcc_set_io_map(u_short sock, struct pccard_io_map *io)
u_char map;
debug(3, "m32r-pcc: SetIOMap(%d, %d, %#2.2x, %d ns, "
- "%#x-%#x)\n", sock, io->map, io->flags,
- io->speed, io->start, io->stop);
+ "%#llx-%#llx)\n", sock, io->map, io->flags,
+ io->speed, (unsigned long long)io->start,
+ (unsigned long long)io->stop);
map = io->map;
return 0;
@@ -515,8 +516,9 @@ static int _pcc_set_mem_map(u_short sock, struct pccard_mem_map *mem)
#endif
debug(3, "m32r-pcc: SetMemMap(%d, %d, %#2.2x, %d ns, "
- "%#lx, %#x)\n", sock, map, mem->flags,
- mem->speed, mem->static_start, mem->card_start);
+ "%#llx, %#x)\n", sock, map, mem->flags,
+ mem->speed, (unsigned long long)mem->static_start,
+ mem->card_start);
/*
* sanity check
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index c69f2c4fe520..403559ba49dd 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -975,8 +975,9 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
#define M8XX_BASE (PCMCIA_IO_WIN_BASE + io->start)
dprintk("SetIOMap(%d, %d, %#2.2x, %d ns, "
- "%#4.4x-%#4.4x)\n", lsock, io->map, io->flags,
- io->speed, io->start, io->stop);
+ "%#4.4llx-%#4.4llx)\n", lsock, io->map, io->flags,
+ io->speed, (unsigned long long)io->start,
+ (unsigned long long)io->stop);
if ((io->map >= PCMCIA_IO_WIN_NO) || (io->start > 0xffff)
|| (io->stop > 0xffff) || (io->stop < io->start))
@@ -1055,8 +1056,9 @@ static int m8xx_set_mem_map(struct pcmcia_socket *sock,
pcmconf8xx_t *pcmcia = s->pcmcia;
dprintk("SetMemMap(%d, %d, %#2.2x, %d ns, "
- "%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
- mem->speed, mem->static_start, mem->card_start);
+ "%#5.5llx, %#5.5x)\n", lsock, mem->map, mem->flags,
+ mem->speed, (unsigned long long)mem->static_start,
+ mem->card_start);
if ((mem->map >= PCMCIA_MEM_WIN_NO)
// || ((mem->s) >= PCMCIA_MEM_WIN_SIZE)
@@ -1107,8 +1109,9 @@ static int m8xx_set_mem_map(struct pcmcia_socket *sock,
}
dprintk("SetMemMap(%d, %d, %#2.2x, %d ns, "
- "%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
- mem->speed, mem->static_start, mem->card_start);
+ "%#5.5llx, %#5.5x)\n", lsock, mem->map, mem->flags,
+ mem->speed, (unsigned long long)mem->static_start,
+ mem->card_start);
/* copy the struct and modify the copy */
diff --git a/drivers/pcmcia/o2micro.h b/drivers/pcmcia/o2micro.h
index 72188c462c9c..624442fc0d35 100644
--- a/drivers/pcmcia/o2micro.h
+++ b/drivers/pcmcia/o2micro.h
@@ -30,28 +30,6 @@
#ifndef _LINUX_O2MICRO_H
#define _LINUX_O2MICRO_H
-#ifndef PCI_VENDOR_ID_O2
-#define PCI_VENDOR_ID_O2 0x1217
-#endif
-#ifndef PCI_DEVICE_ID_O2_6729
-#define PCI_DEVICE_ID_O2_6729 0x6729
-#endif
-#ifndef PCI_DEVICE_ID_O2_6730
-#define PCI_DEVICE_ID_O2_6730 0x673a
-#endif
-#ifndef PCI_DEVICE_ID_O2_6832
-#define PCI_DEVICE_ID_O2_6832 0x6832
-#endif
-#ifndef PCI_DEVICE_ID_O2_6836
-#define PCI_DEVICE_ID_O2_6836 0x6836
-#endif
-#ifndef PCI_DEVICE_ID_O2_6812
-#define PCI_DEVICE_ID_O2_6812 0x6872
-#endif
-#ifndef PCI_DEVICE_ID_O2_6933
-#define PCI_DEVICE_ID_O2_6933 0x6933
-#endif
-
/* Additional PCI configuration registers */
#define O2_MUX_CONTROL 0x90 /* 32 bit */
diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c
index 68570bc3ac86..663781d20129 100644
--- a/drivers/pcmcia/omap_cf.c
+++ b/drivers/pcmcia/omap_cf.c
@@ -23,8 +23,8 @@
#include <asm/io.h>
#include <asm/sizes.h>
-#include <mach/mux.h>
-#include <mach/tc.h>
+#include <plat/mux.h>
+#include <plat/tc.h>
/* NOTE: don't expect this to support many I/O cards. The 16xx chips have
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index 32c44040c1e8..30cf71d2ee23 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -881,7 +881,7 @@ static int ds_ioctl(struct inode * inode, struct file * file,
mutex_lock(&s->skt_mutex);
pcmcia_validate_mem(s);
mutex_unlock(&s->skt_mutex);
- ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo.Chains);
+ ret = pccard_validate_cis(s, &buf->cisinfo.Chains);
break;
case DS_SUSPEND_CARD:
ret = pcmcia_suspend_card(s);
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index d919e96c0afd..0bfb05aa8f85 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -20,6 +20,7 @@
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/device.h>
+#include <linux/netdevice.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
@@ -885,13 +886,40 @@ EXPORT_SYMBOL(pcmcia_disable_device);
struct pcmcia_cfg_mem {
- tuple_t tuple;
+ struct pcmcia_device *p_dev;
+ void *priv_data;
+ int (*conf_check) (struct pcmcia_device *p_dev,
+ cistpl_cftable_entry_t *cfg,
+ cistpl_cftable_entry_t *dflt,
+ unsigned int vcc,
+ void *priv_data);
cisparse_t parse;
- u8 buf[256];
cistpl_cftable_entry_t dflt;
};
/**
+ * pcmcia_do_loop_config() - internal helper for pcmcia_loop_config()
+ *
+ * pcmcia_do_loop_config() is the internal callback for the call from
+ * pcmcia_loop_config() to pccard_loop_tuple(). Data is transferred
+ * by a struct pcmcia_cfg_mem.
+ */
+static int pcmcia_do_loop_config(tuple_t *tuple, cisparse_t *parse, void *priv)
+{
+ cistpl_cftable_entry_t *cfg = &parse->cftable_entry;
+ struct pcmcia_cfg_mem *cfg_mem = priv;
+
+ /* default values */
+ cfg_mem->p_dev->conf.ConfigIndex = cfg->index;
+ if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
+ cfg_mem->dflt = *cfg;
+
+ return cfg_mem->conf_check(cfg_mem->p_dev, cfg, &cfg_mem->dflt,
+ cfg_mem->p_dev->socket->socket.Vcc,
+ cfg_mem->priv_data);
+}
+
+/**
* pcmcia_loop_config() - loop over configuration options
* @p_dev: the struct pcmcia_device which we need to loop for.
* @conf_check: function to call for each configuration option.
@@ -913,48 +941,173 @@ int pcmcia_loop_config(struct pcmcia_device *p_dev,
void *priv_data)
{
struct pcmcia_cfg_mem *cfg_mem;
-
- tuple_t *tuple;
int ret;
- unsigned int vcc;
cfg_mem = kzalloc(sizeof(struct pcmcia_cfg_mem), GFP_KERNEL);
if (cfg_mem == NULL)
return -ENOMEM;
- /* get the current Vcc setting */
- vcc = p_dev->socket->socket.Vcc;
+ cfg_mem->p_dev = p_dev;
+ cfg_mem->conf_check = conf_check;
+ cfg_mem->priv_data = priv_data;
- tuple = &cfg_mem->tuple;
- tuple->TupleData = cfg_mem->buf;
- tuple->TupleDataMax = 255;
- tuple->TupleOffset = 0;
- tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
- tuple->Attributes = 0;
+ ret = pccard_loop_tuple(p_dev->socket, p_dev->func,
+ CISTPL_CFTABLE_ENTRY, &cfg_mem->parse,
+ cfg_mem, pcmcia_do_loop_config);
- ret = pcmcia_get_first_tuple(p_dev, tuple);
- while (!ret) {
- cistpl_cftable_entry_t *cfg = &cfg_mem->parse.cftable_entry;
+ kfree(cfg_mem);
+ return ret;
+}
+EXPORT_SYMBOL(pcmcia_loop_config);
- if (pcmcia_get_tuple_data(p_dev, tuple))
- goto next_entry;
- if (pcmcia_parse_tuple(tuple, &cfg_mem->parse))
- goto next_entry;
+struct pcmcia_loop_mem {
+ struct pcmcia_device *p_dev;
+ void *priv_data;
+ int (*loop_tuple) (struct pcmcia_device *p_dev,
+ tuple_t *tuple,
+ void *priv_data);
+};
- /* default values */
- p_dev->conf.ConfigIndex = cfg->index;
- if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
- cfg_mem->dflt = *cfg;
+/**
+ * pcmcia_do_loop_tuple() - internal helper for pcmcia_loop_config()
+ *
+ * pcmcia_do_loop_tuple() is the internal callback for the call from
+ * pcmcia_loop_tuple() to pccard_loop_tuple(). Data is transferred
+ * by a struct pcmcia_cfg_mem.
+ */
+static int pcmcia_do_loop_tuple(tuple_t *tuple, cisparse_t *parse, void *priv)
+{
+ struct pcmcia_loop_mem *loop = priv;
- ret = conf_check(p_dev, cfg, &cfg_mem->dflt, vcc, priv_data);
- if (!ret)
- break;
+ return loop->loop_tuple(loop->p_dev, tuple, loop->priv_data);
+};
+
+/**
+ * pcmcia_loop_tuple() - loop over tuples in the CIS
+ * @p_dev: the struct pcmcia_device which we need to loop for.
+ * @code: which CIS code shall we look for?
+ * @priv_data: private data to be passed to the loop_tuple function.
+ * @loop_tuple: function to call for each CIS entry of type @function. IT
+ * gets passed the raw tuple and @priv_data.
+ *
+ * pcmcia_loop_tuple() loops over all CIS entries of type @function, and
+ * calls the @loop_tuple function for each entry. If the call to @loop_tuple
+ * returns 0, the loop exits. Returns 0 on success or errorcode otherwise.
+ */
+int pcmcia_loop_tuple(struct pcmcia_device *p_dev, cisdata_t code,
+ int (*loop_tuple) (struct pcmcia_device *p_dev,
+ tuple_t *tuple,
+ void *priv_data),
+ void *priv_data)
+{
+ struct pcmcia_loop_mem loop = {
+ .p_dev = p_dev,
+ .loop_tuple = loop_tuple,
+ .priv_data = priv_data};
+
+ return pccard_loop_tuple(p_dev->socket, p_dev->func, code, NULL,
+ &loop, pcmcia_do_loop_tuple);
+};
+EXPORT_SYMBOL(pcmcia_loop_tuple);
-next_entry:
- ret = pcmcia_get_next_tuple(p_dev, tuple);
+
+struct pcmcia_loop_get {
+ size_t len;
+ cisdata_t **buf;
+};
+
+/**
+ * pcmcia_do_get_tuple() - internal helper for pcmcia_get_tuple()
+ *
+ * pcmcia_do_get_tuple() is the internal callback for the call from
+ * pcmcia_get_tuple() to pcmcia_loop_tuple(). As we're only interested in
+ * the first tuple, return 0 unconditionally. Create a memory buffer large
+ * enough to hold the content of the tuple, and fill it with the tuple data.
+ * The caller is responsible to free the buffer.
+ */
+static int pcmcia_do_get_tuple(struct pcmcia_device *p_dev, tuple_t *tuple,
+ void *priv)
+{
+ struct pcmcia_loop_get *get = priv;
+
+ *get->buf = kzalloc(tuple->TupleDataLen, GFP_KERNEL);
+ if (*get->buf) {
+ get->len = tuple->TupleDataLen;
+ memcpy(*get->buf, tuple->TupleData, tuple->TupleDataLen);
}
+ return 0;
+};
+
+/**
+ * pcmcia_get_tuple() - get first tuple from CIS
+ * @p_dev: the struct pcmcia_device which we need to loop for.
+ * @code: which CIS code shall we look for?
+ * @buf: pointer to store the buffer to.
+ *
+ * pcmcia_get_tuple() gets the content of the first CIS entry of type @code.
+ * It returns the buffer length (or zero). The caller is responsible to free
+ * the buffer passed in @buf.
+ */
+size_t pcmcia_get_tuple(struct pcmcia_device *p_dev, cisdata_t code,
+ unsigned char **buf)
+{
+ struct pcmcia_loop_get get = {
+ .len = 0,
+ .buf = buf,
+ };
+
+ *get.buf = NULL;
+ pcmcia_loop_tuple(p_dev, code, pcmcia_do_get_tuple, &get);
+
+ return get.len;
+};
+EXPORT_SYMBOL(pcmcia_get_tuple);
+
+
+/**
+ * pcmcia_do_get_mac() - internal helper for pcmcia_get_mac_from_cis()
+ *
+ * pcmcia_do_get_mac() is the internal callback for the call from
+ * pcmcia_get_mac_from_cis() to pcmcia_loop_tuple(). We check whether the
+ * tuple contains a proper LAN_NODE_ID of length 6, and copy the data
+ * to struct net_device->dev_addr[i].
+ */
+static int pcmcia_do_get_mac(struct pcmcia_device *p_dev, tuple_t *tuple,
+ void *priv)
+{
+ struct net_device *dev = priv;
+ int i;
+
+ if (tuple->TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID)
+ return -EINVAL;
+ if (tuple->TupleDataLen < ETH_ALEN + 2) {
+ dev_warn(&p_dev->dev, "Invalid CIS tuple length for "
+ "LAN_NODE_ID\n");
+ return -EINVAL;
+ }
+
+ if (tuple->TupleData[1] != ETH_ALEN) {
+ dev_warn(&p_dev->dev, "Invalid header for LAN_NODE_ID\n");
+ return -EINVAL;
+ }
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = tuple->TupleData[i+2];
+ return 0;
+};
+
+/**
+ * pcmcia_get_mac_from_cis() - read out MAC address from CISTPL_FUNCE
+ * @p_dev: the struct pcmcia_device for which we want the address.
+ * @dev: a properly prepared struct net_device to store the info to.
+ *
+ * pcmcia_get_mac_from_cis() reads out the hardware MAC address from
+ * CISTPL_FUNCE and stores it into struct net_device *dev->dev_addr which
+ * must be set up properly by the driver (see examples!).
+ */
+int pcmcia_get_mac_from_cis(struct pcmcia_device *p_dev, struct net_device *dev)
+{
+ return pcmcia_loop_tuple(p_dev, CISTPL_FUNCE, pcmcia_do_get_mac, dev);
+};
+EXPORT_SYMBOL(pcmcia_get_mac_from_cis);
- return ret;
-}
-EXPORT_SYMBOL(pcmcia_loop_config);
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index 1c39d3438f20..70a33468bcd0 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -641,6 +641,12 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev,
if ((ret = pci_enable_device(dev)))
goto err_out_free_mem;
+ if (!pci_resource_start(dev, 0)) {
+ printk(KERN_INFO "pd6729: refusing to load the driver "
+ "as the io_base is 0.\n");
+ goto err_out_free_mem;
+ }
+
printk(KERN_INFO "pd6729: Cirrus PD6729 PCI to PCMCIA Bridge "
"at 0x%llx on irq %d\n",
(unsigned long long)pci_resource_start(dev, 0), dev->irq);
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c
index e592e0e0d7ed..de0e770ce6a3 100644
--- a/drivers/pcmcia/rsrc_mgr.c
+++ b/drivers/pcmcia/rsrc_mgr.c
@@ -18,6 +18,7 @@
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
#include "cs_internal.h"
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index 9ca22c7aafb2..7039f3cf5b77 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -206,6 +206,7 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
/* First, what does a floating port look like? */
b = kzalloc(256, GFP_KERNEL);
if (!b) {
+ printk("\n");
dev_printk(KERN_ERR, &s->dev,
"do_io_probe: unable to kmalloc 256 bytes");
return;
@@ -275,7 +276,7 @@ static int readable(struct pcmcia_socket *s, struct resource *res,
s->cis_mem.res = res;
s->cis_virt = ioremap(res->start, s->map_size);
if (s->cis_virt) {
- ret = pccard_validate_cis(s, BIND_FN_ALL, count);
+ ret = pccard_validate_cis(s, count);
/* invalidate mapping and CIS cache */
iounmap(s->cis_virt);
s->cis_virt = NULL;
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index 163cf98e2386..ef7e9e58782b 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -336,8 +336,9 @@ soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *m
struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
unsigned short speed = map->speed;
- debug(skt, 2, "map %u speed %u start 0x%08x stop 0x%08x\n",
- map->map, map->speed, map->start, map->stop);
+ debug(skt, 2, "map %u speed %u start 0x%08llx stop 0x%08llx\n",
+ map->map, map->speed, (unsigned long long)map->start,
+ (unsigned long long)map->stop);
debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n",
(map->flags==0)?"<NONE>":"",
(map->flags&MAP_ACTIVE)?"ACTIVE ":"",
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index ff9a3bb3c88d..78d5aab542f7 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -300,7 +300,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj,
if (!(s->state & SOCKET_PRESENT))
return -ENODEV;
- if (pccard_validate_cis(s, BIND_FN_ALL, &chains))
+ if (pccard_validate_cis(s, &chains))
return -EIO;
if (!chains)
return -ENODATA;
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index 582413fcb62f..6918849d511e 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -732,8 +732,8 @@ static int tcic_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
u_short base, len, ioctl;
debug(1, "SetIOMap(%d, %d, %#2.2x, %d ns, "
- "%#x-%#x)\n", psock, io->map, io->flags,
- io->speed, io->start, io->stop);
+ "%#llx-%#llx)\n", psock, io->map, io->flags, io->speed,
+ (unsigned long long)io->start, (unsigned long long)io->stop);
if ((io->map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
(io->stop < io->start)) return -EINVAL;
tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
diff --git a/drivers/pcmcia/xxs1500_ss.c b/drivers/pcmcia/xxs1500_ss.c
new file mode 100644
index 000000000000..4e36930b51ce
--- /dev/null
+++ b/drivers/pcmcia/xxs1500_ss.c
@@ -0,0 +1,357 @@
+/*
+ * PCMCIA socket code for the MyCable XXS1500 system.
+ *
+ * Copyright (c) 2009 Manuel Lauss <manuel.lauss@gmail.com>
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/resource.h>
+#include <linux/spinlock.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cistpl.h>
+
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#define MEM_MAP_SIZE 0x400000
+#define IO_MAP_SIZE 0x1000
+
+
+/*
+ * 3.3V cards only; all interfacing is done via gpios:
+ *
+ * 0/1: carddetect (00 = card present, xx = huh)
+ * 4: card irq
+ * 204: reset (high-act)
+ * 205: buffer enable (low-act)
+ * 208/209: card voltage key (00,01,10,11)
+ * 210: battwarn
+ * 211: batdead
+ * 214: power (low-act)
+ */
+#define GPIO_CDA 0
+#define GPIO_CDB 1
+#define GPIO_CARDIRQ 4
+#define GPIO_RESET 204
+#define GPIO_OUTEN 205
+#define GPIO_VSL 208
+#define GPIO_VSH 209
+#define GPIO_BATTDEAD 210
+#define GPIO_BATTWARN 211
+#define GPIO_POWER 214
+
+struct xxs1500_pcmcia_sock {
+ struct pcmcia_socket socket;
+ void *virt_io;
+
+ /* the "pseudo" addresses of the PCMCIA space. */
+ unsigned long phys_io;
+ unsigned long phys_attr;
+ unsigned long phys_mem;
+
+ /* previous flags for set_socket() */
+ unsigned int old_flags;
+};
+
+#define to_xxs_socket(x) container_of(x, struct xxs1500_pcmcia_sock, socket)
+
+static irqreturn_t cdirq(int irq, void *data)
+{
+ struct xxs1500_pcmcia_sock *sock = data;
+
+ pcmcia_parse_events(&sock->socket, SS_DETECT);
+
+ return IRQ_HANDLED;
+}
+
+static int xxs1500_pcmcia_configure(struct pcmcia_socket *skt,
+ struct socket_state_t *state)
+{
+ struct xxs1500_pcmcia_sock *sock = to_xxs_socket(skt);
+ unsigned int changed;
+
+ /* power control */
+ switch (state->Vcc) {
+ case 0:
+ gpio_set_value(GPIO_POWER, 1); /* power off */
+ break;
+ case 33:
+ gpio_set_value(GPIO_POWER, 0); /* power on */
+ break;
+ case 50:
+ default:
+ return -EINVAL;
+ }
+
+ changed = state->flags ^ sock->old_flags;
+
+ if (changed & SS_RESET) {
+ if (state->flags & SS_RESET) {
+ gpio_set_value(GPIO_RESET, 1); /* assert reset */
+ gpio_set_value(GPIO_OUTEN, 1); /* buffers off */
+ } else {
+ gpio_set_value(GPIO_RESET, 0); /* deassert reset */
+ gpio_set_value(GPIO_OUTEN, 0); /* buffers on */
+ msleep(500);
+ }
+ }
+
+ sock->old_flags = state->flags;
+
+ return 0;
+}
+
+static int xxs1500_pcmcia_get_status(struct pcmcia_socket *skt,
+ unsigned int *value)
+{
+ unsigned int status;
+ int i;
+
+ status = 0;
+
+ /* check carddetects: GPIO[0:1] must both be low */
+ if (!gpio_get_value(GPIO_CDA) && !gpio_get_value(GPIO_CDB))
+ status |= SS_DETECT;
+
+ /* determine card voltage: GPIO[208:209] binary value */
+ i = (!!gpio_get_value(GPIO_VSL)) | ((!!gpio_get_value(GPIO_VSH)) << 1);
+
+ switch (i) {
+ case 0:
+ case 1:
+ case 2:
+ status |= SS_3VCARD; /* 3V card */
+ break;
+ case 3: /* 5V card, unsupported */
+ default:
+ status |= SS_XVCARD; /* treated as unsupported in core */
+ }
+
+ /* GPIO214: low active power switch */
+ status |= gpio_get_value(GPIO_POWER) ? 0 : SS_POWERON;
+
+ /* GPIO204: high-active reset line */
+ status |= gpio_get_value(GPIO_RESET) ? SS_RESET : SS_READY;
+
+ /* other stuff */
+ status |= gpio_get_value(GPIO_BATTDEAD) ? 0 : SS_BATDEAD;
+ status |= gpio_get_value(GPIO_BATTWARN) ? 0 : SS_BATWARN;
+
+ *value = status;
+
+ return 0;
+}
+
+static int xxs1500_pcmcia_sock_init(struct pcmcia_socket *skt)
+{
+ gpio_direction_input(GPIO_CDA);
+ gpio_direction_input(GPIO_CDB);
+ gpio_direction_input(GPIO_VSL);
+ gpio_direction_input(GPIO_VSH);
+ gpio_direction_input(GPIO_BATTDEAD);
+ gpio_direction_input(GPIO_BATTWARN);
+ gpio_direction_output(GPIO_RESET, 1); /* assert reset */
+ gpio_direction_output(GPIO_OUTEN, 1); /* disable buffers */
+ gpio_direction_output(GPIO_POWER, 1); /* power off */
+
+ return 0;
+}
+
+static int xxs1500_pcmcia_sock_suspend(struct pcmcia_socket *skt)
+{
+ return 0;
+}
+
+static int au1x00_pcmcia_set_io_map(struct pcmcia_socket *skt,
+ struct pccard_io_map *map)
+{
+ struct xxs1500_pcmcia_sock *sock = to_xxs_socket(skt);
+
+ map->start = (u32)sock->virt_io;
+ map->stop = map->start + IO_MAP_SIZE;
+
+ return 0;
+}
+
+static int au1x00_pcmcia_set_mem_map(struct pcmcia_socket *skt,
+ struct pccard_mem_map *map)
+{
+ struct xxs1500_pcmcia_sock *sock = to_xxs_socket(skt);
+
+ if (map->flags & MAP_ATTRIB)
+ map->static_start = sock->phys_attr + map->card_start;
+ else
+ map->static_start = sock->phys_mem + map->card_start;
+
+ return 0;
+}
+
+static struct pccard_operations xxs1500_pcmcia_operations = {
+ .init = xxs1500_pcmcia_sock_init,
+ .suspend = xxs1500_pcmcia_sock_suspend,
+ .get_status = xxs1500_pcmcia_get_status,
+ .set_socket = xxs1500_pcmcia_configure,
+ .set_io_map = au1x00_pcmcia_set_io_map,
+ .set_mem_map = au1x00_pcmcia_set_mem_map,
+};
+
+static int __devinit xxs1500_pcmcia_probe(struct platform_device *pdev)
+{
+ struct xxs1500_pcmcia_sock *sock;
+ struct resource *r;
+ phys_t physio;
+ int ret, irq;
+
+ sock = kzalloc(sizeof(struct xxs1500_pcmcia_sock), GFP_KERNEL);
+ if (!sock)
+ return -ENOMEM;
+
+ ret = -ENODEV;
+
+ /*
+ * pseudo-attr: The 32bit address of the PCMCIA attribute space
+ * for this socket (usually the 36bit address shifted 4 to the
+ * right).
+ */
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pseudo-attr");
+ if (!r) {
+ dev_err(&pdev->dev, "missing 'pseudo-attr' resource!\n");
+ goto out0;
+ }
+ sock->phys_attr = r->start;
+
+ /*
+ * pseudo-mem: The 32bit address of the PCMCIA memory space for
+ * this socket (usually the 36bit address shifted 4 to the right)
+ */
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pseudo-mem");
+ if (!r) {
+ dev_err(&pdev->dev, "missing 'pseudo-mem' resource!\n");
+ goto out0;
+ }
+ sock->phys_mem = r->start;
+
+ /*
+ * pseudo-io: The 32bit address of the PCMCIA IO space for this
+ * socket (usually the 36bit address shifted 4 to the right).
+ */
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pseudo-io");
+ if (!r) {
+ dev_err(&pdev->dev, "missing 'pseudo-io' resource!\n");
+ goto out0;
+ }
+ sock->phys_io = r->start;
+
+
+ /* for io must remap the full 36bit address (for reference see
+ * alchemy/common/setup.c::__fixup_bigphys_addr)
+ */
+ physio = ((phys_t)sock->phys_io) << 4;
+
+ /*
+ * PCMCIA client drivers use the inb/outb macros to access
+ * the IO registers. Since mips_io_port_base is added
+ * to the access address of the mips implementation of
+ * inb/outb, we need to subtract it here because we want
+ * to access the I/O or MEM address directly, without
+ * going through this "mips_io_port_base" mechanism.
+ */
+ sock->virt_io = (void *)(ioremap(physio, IO_MAP_SIZE) -
+ mips_io_port_base);
+
+ if (!sock->virt_io) {
+ dev_err(&pdev->dev, "cannot remap IO area\n");
+ ret = -ENOMEM;
+ goto out0;
+ }
+
+ sock->socket.ops = &xxs1500_pcmcia_operations;
+ sock->socket.owner = THIS_MODULE;
+ sock->socket.pci_irq = gpio_to_irq(GPIO_CARDIRQ);
+ sock->socket.features = SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
+ sock->socket.map_size = MEM_MAP_SIZE;
+ sock->socket.io_offset = (unsigned long)sock->virt_io;
+ sock->socket.dev.parent = &pdev->dev;
+ sock->socket.resource_ops = &pccard_static_ops;
+
+ platform_set_drvdata(pdev, sock);
+
+ /* setup carddetect irq: use one of the 2 GPIOs as an
+ * edge detector.
+ */
+ irq = gpio_to_irq(GPIO_CDA);
+ set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
+ ret = request_irq(irq, cdirq, 0, "pcmcia_carddetect", sock);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot setup cd irq\n");
+ goto out1;
+ }
+
+ ret = pcmcia_register_socket(&sock->socket);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register\n");
+ goto out2;
+ }
+
+ printk(KERN_INFO "MyCable XXS1500 PCMCIA socket services\n");
+
+ return 0;
+
+out2:
+ free_irq(gpio_to_irq(GPIO_CDA), sock);
+out1:
+ iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
+out0:
+ kfree(sock);
+ return ret;
+}
+
+static int __devexit xxs1500_pcmcia_remove(struct platform_device *pdev)
+{
+ struct xxs1500_pcmcia_sock *sock = platform_get_drvdata(pdev);
+
+ pcmcia_unregister_socket(&sock->socket);
+ free_irq(gpio_to_irq(GPIO_CDA), sock);
+ iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
+ kfree(sock);
+
+ return 0;
+}
+
+static struct platform_driver xxs1500_pcmcia_socket_driver = {
+ .driver = {
+ .name = "xxs1500_pcmcia",
+ .owner = THIS_MODULE,
+ },
+ .probe = xxs1500_pcmcia_probe,
+ .remove = __devexit_p(xxs1500_pcmcia_remove),
+};
+
+int __init xxs1500_pcmcia_socket_load(void)
+{
+ return platform_driver_register(&xxs1500_pcmcia_socket_driver);
+}
+
+void __exit xxs1500_pcmcia_socket_unload(void)
+{
+ platform_driver_unregister(&xxs1500_pcmcia_socket_driver);
+}
+
+module_init(xxs1500_pcmcia_socket_load);
+module_exit(xxs1500_pcmcia_socket_unload);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PCMCIA Socket Services for MyCable XXS1500 systems");
+MODULE_AUTHOR("Manuel Lauss");
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
index 9652c3fe7f5e..8390dca2b4e1 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -1,5 +1,3 @@
-# drivers/platform/Kconfig
-
if X86
source "drivers/platform/x86/Kconfig"
endif
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c
index 11003bba10d3..1a387e79f719 100644
--- a/drivers/platform/x86/compal-laptop.c
+++ b/drivers/platform/x86/compal-laptop.c
@@ -51,7 +51,6 @@
#include <linux/dmi.h>
#include <linux/backlight.h>
#include <linux/platform_device.h>
-#include <linux/autoconf.h>
#define COMPAL_DRIVER_VERSION "0.2.6"
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index d93108d148fc..9a2e9a7b0bed 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -22,7 +22,7 @@
*/
#define TPACPI_VERSION "0.23"
-#define TPACPI_SYSFS_VERSION 0x020500
+#define TPACPI_SYSFS_VERSION 0x020600
/*
* Changelog:
@@ -6083,6 +6083,12 @@ static int brightness_get(struct backlight_device *bd)
return status & TP_EC_BACKLIGHT_LVLMSK;
}
+static void tpacpi_brightness_notify_change(void)
+{
+ backlight_force_update(ibm_backlight_device,
+ BACKLIGHT_UPDATE_HOTKEY);
+}
+
static struct backlight_ops ibm_backlight_data = {
.get_brightness = brightness_get,
.update_status = brightness_update_status,
@@ -6237,6 +6243,12 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK;
backlight_update_status(ibm_backlight_device);
+ vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
+ "brightness: registering brightness hotkeys "
+ "as change notification\n");
+ tpacpi_hotkey_driver_mask_set(hotkey_driver_mask
+ | TP_ACPI_HKEY_BRGHTUP_MASK
+ | TP_ACPI_HKEY_BRGHTDWN_MASK);;
return 0;
}
@@ -6313,6 +6325,9 @@ static int brightness_write(char *buf)
* Doing it this way makes the syscall restartable in case of EINTR
*/
rc = brightness_set(level);
+ if (!rc && ibm_backlight_device)
+ backlight_force_update(ibm_backlight_device,
+ BACKLIGHT_UPDATE_SYSFS);
return (rc == -EINTR)? ERESTARTSYS : rc;
}
@@ -7712,6 +7727,13 @@ static struct ibm_struct fan_driver_data = {
*/
static void tpacpi_driver_event(const unsigned int hkey_event)
{
+ if (ibm_backlight_device) {
+ switch (hkey_event) {
+ case TP_HKEY_EV_BRGHT_UP:
+ case TP_HKEY_EV_BRGHT_DOWN:
+ tpacpi_brightness_notify_change();
+ }
+ }
}
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index 8473fe5ed7ff..3a2031b25c3c 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -285,15 +285,9 @@ static void quirk_system_pci_resources(struct pnp_dev *dev)
* the PCI region, and that might prevent a PCI
* driver from requesting its resources.
*/
- dev_warn(&dev->dev, "%s resource "
- "(0x%llx-0x%llx) overlaps %s BAR %d "
- "(0x%llx-0x%llx), disabling\n",
- pnp_resource_type_name(res),
- (unsigned long long) pnp_start,
- (unsigned long long) pnp_end,
- pci_name(pdev), i,
- (unsigned long long) pci_start,
- (unsigned long long) pci_end);
+ dev_warn(&dev->dev, "resource %pRt overlaps %s "
+ "BAR %d %pRt, disabling\n", res,
+ pci_name(pdev), i, &pdev->resource[i]);
res->flags |= IORESOURCE_DISABLED;
}
}
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index ba9765427886..18557d7bb0b9 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -517,7 +517,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 irq %d flags %#x\n", irq, flags);
+ pnp_dbg(&dev->dev, " add %pRf\n", res);
return pnp_res;
}
@@ -538,7 +538,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 dma %d flags %#x\n", dma, flags);
+ pnp_dbg(&dev->dev, " add %pRf\n", res);
return pnp_res;
}
@@ -562,8 +562,7 @@ struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev,
res->start = start;
res->end = end;
- pnp_dbg(&dev->dev, " add io %#llx-%#llx flags %#x\n",
- (unsigned long long) start, (unsigned long long) end, flags);
+ pnp_dbg(&dev->dev, " add %pRf\n", res);
return pnp_res;
}
@@ -587,8 +586,7 @@ struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
res->start = start;
res->end = end;
- pnp_dbg(&dev->dev, " add mem %#llx-%#llx flags %#x\n",
- (unsigned long long) start, (unsigned long long) end, flags);
+ pnp_dbg(&dev->dev, " add %pRf\n", res);
return pnp_res;
}
diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c
index 63087d5ce609..1f8a33b0abac 100644
--- a/drivers/pnp/support.c
+++ b/drivers/pnp/support.c
@@ -75,47 +75,14 @@ char *pnp_resource_type_name(struct resource *res)
void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc)
{
- char buf[128];
- int len;
struct pnp_resource *pnp_res;
- struct resource *res;
- if (list_empty(&dev->resources)) {
+ if (list_empty(&dev->resources))
pnp_dbg(&dev->dev, "%s: no current resources\n", desc);
- return;
- }
-
- pnp_dbg(&dev->dev, "%s: current resources:\n", desc);
- list_for_each_entry(pnp_res, &dev->resources, list) {
- res = &pnp_res->res;
- len = 0;
-
- len += scnprintf(buf + len, sizeof(buf) - len, " %-3s ",
- pnp_resource_type_name(res));
-
- if (res->flags & IORESOURCE_DISABLED) {
- pnp_dbg(&dev->dev, "%sdisabled\n", buf);
- continue;
- }
-
- switch (pnp_resource_type(res)) {
- case IORESOURCE_IO:
- case IORESOURCE_MEM:
- len += scnprintf(buf + len, sizeof(buf) - len,
- "%#llx-%#llx flags %#lx",
- (unsigned long long) res->start,
- (unsigned long long) res->end,
- res->flags);
- break;
- case IORESOURCE_IRQ:
- case IORESOURCE_DMA:
- len += scnprintf(buf + len, sizeof(buf) - len,
- "%lld flags %#lx",
- (unsigned long long) res->start,
- res->flags);
- break;
- }
- pnp_dbg(&dev->dev, "%s\n", buf);
+ else {
+ pnp_dbg(&dev->dev, "%s: current resources:\n", desc);
+ list_for_each_entry(pnp_res, &dev->resources, list)
+ pnp_dbg(&dev->dev, "%pRf\n", &pnp_res->res);
}
}
diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c
index 59b90922da8c..242d3a872011 100644
--- a/drivers/pnp/system.c
+++ b/drivers/pnp/system.c
@@ -22,11 +22,11 @@ static const struct pnp_device_id pnp_dev_table[] = {
{"", 0}
};
-static void reserve_range(struct pnp_dev *dev, resource_size_t start,
- resource_size_t end, int port)
+static void reserve_range(struct pnp_dev *dev, struct resource *r, int port)
{
char *regionid;
const char *pnpid = dev_name(&dev->dev);
+ resource_size_t start = r->start, end = r->end;
struct resource *res;
regionid = kmalloc(16, GFP_KERNEL);
@@ -48,10 +48,8 @@ static void reserve_range(struct pnp_dev *dev, resource_size_t start,
* example do reserve stuff they know about too, so we may well
* have double reservations.
*/
- dev_info(&dev->dev, "%s range 0x%llx-0x%llx %s reserved\n",
- port ? "ioport" : "iomem",
- (unsigned long long) start, (unsigned long long) end,
- res ? "has been" : "could not be");
+ dev_info(&dev->dev, "%pRt %s reserved\n", r,
+ res ? "has been" : "could not be");
}
static void reserve_resources_of_dev(struct pnp_dev *dev)
@@ -77,14 +75,14 @@ static void reserve_resources_of_dev(struct pnp_dev *dev)
if (res->end < res->start)
continue; /* invalid */
- reserve_range(dev, res->start, res->end, 1);
+ reserve_range(dev, res, 1);
}
for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) {
if (res->flags & IORESOURCE_DISABLED)
continue;
- reserve_range(dev, res->start, res->end, 0);
+ reserve_range(dev, res, 0);
}
}
diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/pcf50633-charger.c
index e8b278f71781..6a84a8eb8d7a 100644
--- a/drivers/power/pcf50633-charger.c
+++ b/drivers/power/pcf50633-charger.c
@@ -303,7 +303,6 @@ static const u8 mbc_irq_handlers[] = {
static int __devinit pcf50633_mbc_probe(struct platform_device *pdev)
{
struct pcf50633_mbc *mbc;
- struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data;
int ret;
int i;
u8 mbcs1;
@@ -313,7 +312,7 @@ static int __devinit pcf50633_mbc_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, mbc);
- mbc->pcf = pdata->pcf;
+ mbc->pcf = dev_to_pcf50633(pdev->dev.parent);
/* Set up IRQ handlers */
for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++)
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
new file mode 100644
index 000000000000..04719551381b
--- /dev/null
+++ b/drivers/regulator/88pm8607.c
@@ -0,0 +1,685 @@
+/*
+ * Regulators driver for Marvell 88PM8607
+ *
+ * Copyright (C) 2009 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/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/88pm8607.h>
+
+struct pm8607_regulator_info {
+ struct regulator_desc desc;
+ struct pm8607_chip *chip;
+ struct regulator_dev *regulator;
+
+ int min_uV;
+ int max_uV;
+ int step_uV;
+ int vol_reg;
+ int vol_shift;
+ int vol_nbits;
+ int update_reg;
+ int update_bit;
+ int enable_reg;
+ int enable_bit;
+ int slope_double;
+};
+
+static inline int check_range(struct pm8607_regulator_info *info,
+ int min_uV, int max_uV)
+{
+ if (max_uV < info->min_uV || min_uV > info->max_uV || min_uV > max_uV)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+ struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+ uint8_t chip_id = info->chip->chip_id;
+ int ret = -EINVAL;
+
+ switch (info->desc.id) {
+ case PM8607_ID_BUCK1:
+ ret = (index < 0x1d) ? (index * 25000 + 800000) :
+ ((index < 0x20) ? 1500000 :
+ ((index < 0x40) ? ((index - 0x20) * 25000) :
+ -EINVAL));
+ break;
+ case PM8607_ID_BUCK3:
+ ret = (index < 0x3d) ? (index * 25000) :
+ ((index < 0x40) ? 1500000 : -EINVAL);
+ if (ret < 0)
+ break;
+ if (info->slope_double)
+ ret <<= 1;
+ break;
+ case PM8607_ID_LDO1:
+ ret = (index == 0) ? 1800000 :
+ ((index == 1) ? 1200000 :
+ ((index == 2) ? 2800000 : -EINVAL));
+ break;
+ case PM8607_ID_LDO5:
+ ret = (index == 0) ? 2900000 :
+ ((index == 1) ? 3000000 :
+ ((index == 2) ? 3100000 : 3300000));
+ break;
+ case PM8607_ID_LDO7:
+ case PM8607_ID_LDO8:
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 8) ? (index * 50000 + 2550000) :
+ -EINVAL);
+ break;
+ case PM8607_ID_LDO12:
+ ret = (index < 2) ? (index * 100000 + 1800000) :
+ ((index < 7) ? (index * 100000 + 2500000) :
+ ((index == 7) ? 3300000 : 1200000));
+ break;
+ case PM8607_ID_LDO2:
+ case PM8607_ID_LDO3:
+ case PM8607_ID_LDO9:
+ switch (chip_id) {
+ case PM8607_CHIP_A0:
+ case PM8607_CHIP_A1:
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 8) ? (index * 50000 + 2550000) :
+ -EINVAL);
+ break;
+ case PM8607_CHIP_B0:
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 7) ? (index * 50000 + 2550000) :
+ 3300000);
+ break;
+ }
+ break;
+ case PM8607_ID_LDO4:
+ switch (chip_id) {
+ case PM8607_CHIP_A0:
+ case PM8607_CHIP_A1:
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 8) ? (index * 50000 + 2550000) :
+ -EINVAL);
+ break;
+ case PM8607_CHIP_B0:
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 6) ? (index * 50000 + 2550000) :
+ ((index == 6) ? 2900000 : 3300000));
+ break;
+ }
+ break;
+ case PM8607_ID_LDO6:
+ switch (chip_id) {
+ case PM8607_CHIP_A0:
+ case PM8607_CHIP_A1:
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 8) ? (index * 50000 + 2450000) :
+ -EINVAL);
+ break;
+ case PM8607_CHIP_B0:
+ ret = (index < 2) ? (index * 50000 + 1800000) :
+ ((index < 7) ? (index * 50000 + 2500000) :
+ 3300000);
+ break;
+ }
+ break;
+ case PM8607_ID_LDO10:
+ switch (chip_id) {
+ case PM8607_CHIP_A0:
+ case PM8607_CHIP_A1:
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 8) ? (index * 50000 + 2550000) :
+ 1200000);
+ break;
+ case PM8607_CHIP_B0:
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 7) ? (index * 50000 + 2550000) :
+ ((index == 7) ? 3300000 : 1200000));
+ break;
+ }
+ break;
+ case PM8607_ID_LDO14:
+ switch (chip_id) {
+ case PM8607_CHIP_A0:
+ case PM8607_CHIP_A1:
+ ret = (index < 3) ? (index * 50000 + 1800000) :
+ ((index < 8) ? (index * 50000 + 2550000) :
+ -EINVAL);
+ break;
+ case PM8607_CHIP_B0:
+ ret = (index < 2) ? (index * 50000 + 1800000) :
+ ((index < 7) ? (index * 50000 + 2600000) :
+ 3300000);
+ break;
+ }
+ break;
+ }
+ return ret;
+}
+
+static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+ struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+ uint8_t chip_id = info->chip->chip_id;
+ int val = -ENOENT;
+ int ret;
+
+ switch (info->desc.id) {
+ case PM8607_ID_BUCK1:
+ if (min_uV >= 800000) /* 800mV ~ 1500mV / 25mV */
+ val = (min_uV - 775001) / 25000;
+ else { /* 25mV ~ 775mV / 25mV */
+ val = (min_uV + 249999) / 25000;
+ val += 32;
+ }
+ break;
+ case PM8607_ID_BUCK3:
+ if (info->slope_double)
+ min_uV = min_uV >> 1;
+ val = (min_uV + 249999) / 25000; /* 0mV ~ 1500mV / 25mV */
+
+ break;
+ case PM8607_ID_LDO1:
+ if (min_uV > 1800000)
+ val = 2;
+ else if (min_uV > 1200000)
+ val = 0;
+ else
+ val = 1;
+ break;
+ case PM8607_ID_LDO5:
+ if (min_uV > 3100000)
+ val = 3;
+ else /* 2900mV ~ 3100mV / 100mV */
+ val = (min_uV - 2800001) / 100000;
+ break;
+ case PM8607_ID_LDO7:
+ case PM8607_ID_LDO8:
+ if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0; /* 1800mv */
+ else if (min_uV <= 1900000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 3; /* 2700mV */
+ } else { /* 2700mV ~ 2900mV / 50mV */
+ if (min_uV <= 2900000) {
+ val = (min_uV - 2650001) / 50000;
+ val += 3;
+ } else
+ val = -EINVAL;
+ }
+ break;
+ case PM8607_ID_LDO10:
+ if (min_uV > 2850000)
+ val = 7;
+ else if (min_uV <= 1200000)
+ val = 8;
+ else if (min_uV < 2700000) /* 1800mV ~ 1900mV / 50mV */
+ val = (min_uV - 1750001) / 50000;
+ else { /* 2700mV ~ 2850mV / 50mV */
+ val = (min_uV - 2650001) / 50000;
+ val += 3;
+ }
+ break;
+ case PM8607_ID_LDO12:
+ if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 100mV */
+ if (min_uV <= 1200000)
+ val = 8; /* 1200mV */
+ else if (min_uV <= 1800000)
+ val = 0; /* 1800mV */
+ else if (min_uV <= 1900000)
+ val = (min_uV - 1700001) / 100000;
+ else
+ val = 2; /* 2700mV */
+ } else { /* 2700mV ~ 3100mV / 100mV */
+ if (min_uV <= 3100000) {
+ val = (min_uV - 2600001) / 100000;
+ val += 2;
+ } else if (min_uV <= 3300000)
+ val = 7;
+ else
+ val = -EINVAL;
+ }
+ break;
+ case PM8607_ID_LDO2:
+ case PM8607_ID_LDO3:
+ case PM8607_ID_LDO9:
+ switch (chip_id) {
+ case PM8607_CHIP_A0:
+ case PM8607_CHIP_A1:
+ if (min_uV < 2700000) /* 1800mV ~ 1900mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1900000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 3; /* 2700mV */
+ else { /* 2700mV ~ 2900mV / 50mV */
+ if (min_uV <= 2900000) {
+ val = (min_uV - 2650001) / 50000;
+ val += 3;
+ } else
+ val = -EINVAL;
+ }
+ break;
+ case PM8607_CHIP_B0:
+ if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1900000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 3; /* 2700mV */
+ } else { /* 2700mV ~ 2850mV / 50mV */
+ if (min_uV <= 2850000) {
+ val = (min_uV - 2650001) / 50000;
+ val += 3;
+ } else if (min_uV <= 3300000)
+ val = 7;
+ else
+ val = -EINVAL;
+ }
+ break;
+ }
+ break;
+ case PM8607_ID_LDO4:
+ switch (chip_id) {
+ case PM8607_CHIP_A0:
+ case PM8607_CHIP_A1:
+ if (min_uV < 2700000) /* 1800mV ~ 1900mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1900000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 3; /* 2700mV */
+ else { /* 2700mV ~ 2900mV / 50mV */
+ if (min_uV <= 2900000) {
+ val = (min_uV - 2650001) / 50000;
+ val += 3;
+ } else
+ val = -EINVAL;
+ }
+ break;
+ case PM8607_CHIP_B0:
+ if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1900000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 3; /* 2700mV */
+ } else { /* 2700mV ~ 2800mV / 50mV */
+ if (min_uV <= 2850000) {
+ val = (min_uV - 2650001) / 50000;
+ val += 3;
+ } else if (min_uV <= 2900000)
+ val = 6;
+ else if (min_uV <= 3300000)
+ val = 7;
+ else
+ val = -EINVAL;
+ }
+ break;
+ }
+ break;
+ case PM8607_ID_LDO6:
+ switch (chip_id) {
+ case PM8607_CHIP_A0:
+ case PM8607_CHIP_A1:
+ if (min_uV < 2600000) { /* 1800mV ~ 1900mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1900000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 3; /* 2600mV */
+ } else { /* 2600mV ~ 2800mV / 50mV */
+ if (min_uV <= 2800000) {
+ val = (min_uV - 2550001) / 50000;
+ val += 3;
+ } else
+ val = -EINVAL;
+ }
+ break;
+ case PM8607_CHIP_B0:
+ if (min_uV < 2600000) { /* 1800mV ~ 1850mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1850000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 2; /* 2600mV */
+ } else { /* 2600mV ~ 2800mV / 50mV */
+ if (min_uV <= 2800000) {
+ val = (min_uV - 2550001) / 50000;
+ val += 2;
+ } else if (min_uV <= 3300000)
+ val = 7;
+ else
+ val = -EINVAL;
+ }
+ break;
+ }
+ break;
+ case PM8607_ID_LDO14:
+ switch (chip_id) {
+ case PM8607_CHIP_A0:
+ case PM8607_CHIP_A1:
+ if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1900000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 3; /* 2700mV */
+ } else { /* 2700mV ~ 2900mV / 50mV */
+ if (min_uV <= 2900000) {
+ val = (min_uV - 2650001) / 50000;
+ val += 3;
+ } else
+ val = -EINVAL;
+ }
+ break;
+ case PM8607_CHIP_B0:
+ if (min_uV < 2700000) { /* 1800mV ~ 1850mV / 50mV */
+ if (min_uV <= 1800000)
+ val = 0;
+ else if (min_uV <= 1850000)
+ val = (min_uV - 1750001) / 50000;
+ else
+ val = 2; /* 2700mV */
+ } else { /* 2700mV ~ 2900mV / 50mV */
+ if (min_uV <= 2900000) {
+ val = (min_uV - 2650001) / 50000;
+ val += 2;
+ } else if (min_uV <= 3300000)
+ val = 7;
+ else
+ val = -EINVAL;
+ }
+ break;
+ }
+ break;
+ }
+ if (val >= 0) {
+ ret = pm8607_list_voltage(rdev, val);
+ if (ret > max_uV) {
+ pr_err("exceed voltage range (%d %d) uV",
+ min_uV, max_uV);
+ return -EINVAL;
+ }
+ } else
+ pr_err("invalid voltage range (%d %d) uV", min_uV, max_uV);
+ return val;
+}
+
+static int pm8607_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+ struct pm8607_chip *chip = info->chip;
+ uint8_t val, mask;
+ int ret;
+
+ if (check_range(info, min_uV, max_uV)) {
+ pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ ret = choose_voltage(rdev, min_uV, max_uV);
+ if (ret < 0)
+ return -EINVAL;
+ val = (uint8_t)(ret << info->vol_shift);
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+
+ ret = pm8607_set_bits(chip, info->vol_reg, mask, val);
+ if (ret)
+ return ret;
+ switch (info->desc.id) {
+ case PM8607_ID_BUCK1:
+ case PM8607_ID_BUCK3:
+ ret = pm8607_set_bits(chip, info->update_reg,
+ 1 << info->update_bit,
+ 1 << info->update_bit);
+ break;
+ }
+ return ret;
+}
+
+static int pm8607_get_voltage(struct regulator_dev *rdev)
+{
+ struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+ struct pm8607_chip *chip = info->chip;
+ uint8_t val, mask;
+ int ret;
+
+ ret = pm8607_reg_read(chip, info->vol_reg);
+ if (ret < 0)
+ return ret;
+
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ val = ((unsigned char)ret & mask) >> info->vol_shift;
+
+ return pm8607_list_voltage(rdev, val);
+}
+
+static int pm8607_enable(struct regulator_dev *rdev)
+{
+ struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+ struct pm8607_chip *chip = info->chip;
+
+ return pm8607_set_bits(chip, info->enable_reg,
+ 1 << info->enable_bit,
+ 1 << info->enable_bit);
+}
+
+static int pm8607_disable(struct regulator_dev *rdev)
+{
+ struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+ struct pm8607_chip *chip = info->chip;
+
+ return pm8607_set_bits(chip, info->enable_reg,
+ 1 << info->enable_bit, 0);
+}
+
+static int pm8607_is_enabled(struct regulator_dev *rdev)
+{
+ struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+ struct pm8607_chip *chip = info->chip;
+ int ret;
+
+ ret = pm8607_reg_read(chip, info->enable_reg);
+ if (ret < 0)
+ return ret;
+
+ return !!((unsigned char)ret & (1 << info->enable_bit));
+}
+
+static struct regulator_ops pm8607_regulator_ops = {
+ .set_voltage = pm8607_set_voltage,
+ .get_voltage = pm8607_get_voltage,
+ .enable = pm8607_enable,
+ .disable = pm8607_disable,
+ .is_enabled = pm8607_is_enabled,
+};
+
+#define PM8607_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
+{ \
+ .desc = { \
+ .name = "BUCK" #_id, \
+ .ops = &pm8607_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = PM8607_ID_BUCK##_id, \
+ .owner = THIS_MODULE, \
+ }, \
+ .min_uV = (min) * 1000, \
+ .max_uV = (max) * 1000, \
+ .step_uV = (step) * 1000, \
+ .vol_reg = PM8607_##vreg, \
+ .vol_shift = (0), \
+ .vol_nbits = (nbits), \
+ .update_reg = PM8607_##ureg, \
+ .update_bit = (ubit), \
+ .enable_reg = PM8607_##ereg, \
+ .enable_bit = (ebit), \
+ .slope_double = (0), \
+}
+
+#define PM8607_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \
+{ \
+ .desc = { \
+ .name = "LDO" #_id, \
+ .ops = &pm8607_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = PM8607_ID_LDO##_id, \
+ .owner = THIS_MODULE, \
+ }, \
+ .min_uV = (min) * 1000, \
+ .max_uV = (max) * 1000, \
+ .step_uV = (step) * 1000, \
+ .vol_reg = PM8607_##vreg, \
+ .vol_shift = (shift), \
+ .vol_nbits = (nbits), \
+ .enable_reg = PM8607_##ereg, \
+ .enable_bit = (ebit), \
+ .slope_double = (0), \
+}
+
+static struct pm8607_regulator_info pm8607_regulator_info[] = {
+ PM8607_DVC(1, 0, 1500, 25, BUCK1, 6, GO, 0, SUPPLIES_EN11, 0),
+ PM8607_DVC(3, 0, 1500, 25, BUCK3, 6, GO, 2, SUPPLIES_EN11, 2),
+
+ PM8607_LDO(1 , 1200, 2800, 0, LDO1 , 0, 2, SUPPLIES_EN11, 3),
+ PM8607_LDO(2 , 1800, 3300, 0, LDO2 , 0, 3, SUPPLIES_EN11, 4),
+ PM8607_LDO(3 , 1800, 3300, 0, LDO3 , 0, 3, SUPPLIES_EN11, 5),
+ PM8607_LDO(4 , 1800, 3300, 0, LDO4 , 0, 3, SUPPLIES_EN11, 6),
+ PM8607_LDO(5 , 2900, 3300, 0, LDO5 , 0, 2, SUPPLIES_EN11, 7),
+ PM8607_LDO(6 , 1800, 3300, 0, LDO6 , 0, 3, SUPPLIES_EN12, 0),
+ PM8607_LDO(7 , 1800, 2900, 0, LDO7 , 0, 3, SUPPLIES_EN12, 1),
+ PM8607_LDO(8 , 1800, 2900, 0, LDO8 , 0, 3, SUPPLIES_EN12, 2),
+ PM8607_LDO(9 , 1800, 3300, 0, LDO9 , 0, 3, SUPPLIES_EN12, 3),
+ PM8607_LDO(10, 1200, 3300, 0, LDO10, 0, 4, SUPPLIES_EN11, 4),
+ PM8607_LDO(12, 1200, 3300, 0, LDO12, 0, 4, SUPPLIES_EN11, 5),
+ PM8607_LDO(14, 1800, 3300, 0, LDO14, 0, 3, SUPPLIES_EN11, 6),
+};
+
+static inline struct pm8607_regulator_info *find_regulator_info(int id)
+{
+ struct pm8607_regulator_info *info;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
+ info = &pm8607_regulator_info[i];
+ if (info->desc.id == id)
+ return info;
+ }
+ return NULL;
+}
+
+static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
+{
+ struct pm8607_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct pm8607_platform_data *pdata = chip->dev->platform_data;
+ struct pm8607_regulator_info *info = NULL;
+
+ info = find_regulator_info(pdev->id);
+ if (info == NULL) {
+ dev_err(&pdev->dev, "invalid regulator ID specified\n");
+ return -EINVAL;
+ }
+
+ info->chip = chip;
+
+ info->regulator = regulator_register(&info->desc, &pdev->dev,
+ pdata->regulator[pdev->id], info);
+ if (IS_ERR(info->regulator)) {
+ dev_err(&pdev->dev, "failed to register regulator %s\n",
+ info->desc.name);
+ return PTR_ERR(info->regulator);
+ }
+
+ /* check DVC ramp slope double */
+ if (info->desc.id == PM8607_ID_BUCK3)
+ if (info->chip->buck3_double)
+ info->slope_double = 1;
+
+ platform_set_drvdata(pdev, info);
+ return 0;
+}
+
+static int __devexit pm8607_regulator_remove(struct platform_device *pdev)
+{
+ struct pm8607_regulator_info *info = platform_get_drvdata(pdev);
+
+ regulator_unregister(info->regulator);
+ return 0;
+}
+
+#define PM8607_REGULATOR_DRIVER(_name) \
+{ \
+ .driver = { \
+ .name = "88pm8607-" #_name, \
+ .owner = THIS_MODULE, \
+ }, \
+ .probe = pm8607_regulator_probe, \
+ .remove = __devexit_p(pm8607_regulator_remove), \
+}
+
+static struct platform_driver pm8607_regulator_driver[] = {
+ PM8607_REGULATOR_DRIVER(buck1),
+ PM8607_REGULATOR_DRIVER(buck2),
+ PM8607_REGULATOR_DRIVER(buck3),
+ PM8607_REGULATOR_DRIVER(ldo1),
+ PM8607_REGULATOR_DRIVER(ldo2),
+ PM8607_REGULATOR_DRIVER(ldo3),
+ PM8607_REGULATOR_DRIVER(ldo4),
+ PM8607_REGULATOR_DRIVER(ldo5),
+ PM8607_REGULATOR_DRIVER(ldo6),
+ PM8607_REGULATOR_DRIVER(ldo7),
+ PM8607_REGULATOR_DRIVER(ldo8),
+ PM8607_REGULATOR_DRIVER(ldo9),
+ PM8607_REGULATOR_DRIVER(ldo10),
+ PM8607_REGULATOR_DRIVER(ldo12),
+ PM8607_REGULATOR_DRIVER(ldo14),
+};
+
+static int __init pm8607_regulator_init(void)
+{
+ int i, count, ret;
+
+ count = ARRAY_SIZE(pm8607_regulator_driver);
+ for (i = 0; i < count; i++) {
+ ret = platform_driver_register(&pm8607_regulator_driver[i]);
+ if (ret != 0)
+ pr_err("Failed to register regulator driver: %d\n",
+ ret);
+ }
+ return 0;
+}
+subsys_initcall(pm8607_regulator_init);
+
+static void __exit pm8607_regulator_exit(void)
+{
+ int i, count;
+
+ count = ARRAY_SIZE(pm8607_regulator_driver);
+ for (i = 0; i < count; i++)
+ platform_driver_unregister(&pm8607_regulator_driver[i]);
+}
+module_exit(pm8607_regulator_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC");
+MODULE_ALIAS("platform:88pm8607-regulator");
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index bcbb161bde0b..39cb6b58e20e 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -69,6 +69,13 @@ config REGULATOR_MAX1586
regulator via I2C bus. The provided regulator is suitable
for PXA27x chips to control VCC_CORE and VCC_USIM voltages.
+config REGULATOR_MAX8660
+ tristate "Maxim 8660/8661 voltage regulator"
+ depends on I2C
+ help
+ This driver controls a Maxim 8660/8661 voltage output
+ regulator via I2C bus.
+
config REGULATOR_TWL4030
bool "TI TWL4030/TWL5030/TPS695x0 PMIC"
depends on TWL4030_CORE
@@ -157,5 +164,11 @@ config REGULATOR_TPS6507X
three step-down converters and two general-purpose LDO voltage regulators.
It supports TI's software based Class-2 SmartReflex implementation.
+config REGULATOR_88PM8607
+ bool "Marvell 88PM8607 Power regulators"
+ depends on MFD_88PM8607=y
+ help
+ This driver supports 88PM8607 voltage regulator chips.
+
endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 4257a8683778..c1961e285773 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
+obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
obj-$(CONFIG_REGULATOR_TWL4030) += twl4030-regulator.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
@@ -25,5 +26,6 @@ obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
+obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c
index 49aeee823a25..5da127bbe1f2 100644
--- a/drivers/regulator/ab3100.c
+++ b/drivers/regulator/ab3100.c
@@ -81,7 +81,7 @@ static const u8 ab3100_reg_init_order[AB3100_NUM_REGULATORS+2] = {
#define LDO_C_VOLTAGE 2650000
#define LDO_D_VOLTAGE 2650000
-static const int const ldo_e_buck_typ_voltages[] = {
+static const int ldo_e_buck_typ_voltages[] = {
1800000,
1400000,
1300000,
@@ -91,7 +91,7 @@ static const int const ldo_e_buck_typ_voltages[] = {
900000,
};
-static const int const ldo_f_typ_voltages[] = {
+static const int ldo_f_typ_voltages[] = {
1800000,
1400000,
1300000,
@@ -102,21 +102,21 @@ static const int const ldo_f_typ_voltages[] = {
2650000,
};
-static const int const ldo_g_typ_voltages[] = {
+static const int ldo_g_typ_voltages[] = {
2850000,
2750000,
1800000,
1500000,
};
-static const int const ldo_h_typ_voltages[] = {
+static const int ldo_h_typ_voltages[] = {
2750000,
1800000,
1500000,
1200000,
};
-static const int const ldo_k_typ_voltages[] = {
+static const int ldo_k_typ_voltages[] = {
2750000,
1800000,
};
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 744ea1d0b59b..2dab0d9e11f5 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -66,6 +66,16 @@ static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
static void _notifier_call_chain(struct regulator_dev *rdev,
unsigned long event, void *data);
+static const char *rdev_get_name(struct regulator_dev *rdev)
+{
+ if (rdev->constraints && rdev->constraints->name)
+ return rdev->constraints->name;
+ else if (rdev->desc->name)
+ return rdev->desc->name;
+ else
+ return "";
+}
+
/* gets the regulator for a given consumer device */
static struct regulator *get_device_regulator(struct device *dev)
{
@@ -96,12 +106,12 @@ static int regulator_check_voltage(struct regulator_dev *rdev,
if (!rdev->constraints) {
printk(KERN_ERR "%s: no constraints for %s\n", __func__,
- rdev->desc->name);
+ rdev_get_name(rdev));
return -ENODEV;
}
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
printk(KERN_ERR "%s: operation not allowed for %s\n",
- __func__, rdev->desc->name);
+ __func__, rdev_get_name(rdev));
return -EPERM;
}
@@ -124,12 +134,12 @@ static int regulator_check_current_limit(struct regulator_dev *rdev,
if (!rdev->constraints) {
printk(KERN_ERR "%s: no constraints for %s\n", __func__,
- rdev->desc->name);
+ rdev_get_name(rdev));
return -ENODEV;
}
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) {
printk(KERN_ERR "%s: operation not allowed for %s\n",
- __func__, rdev->desc->name);
+ __func__, rdev_get_name(rdev));
return -EPERM;
}
@@ -159,17 +169,17 @@ static int regulator_check_mode(struct regulator_dev *rdev, int mode)
if (!rdev->constraints) {
printk(KERN_ERR "%s: no constraints for %s\n", __func__,
- rdev->desc->name);
+ rdev_get_name(rdev));
return -ENODEV;
}
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) {
printk(KERN_ERR "%s: operation not allowed for %s\n",
- __func__, rdev->desc->name);
+ __func__, rdev_get_name(rdev));
return -EPERM;
}
if (!(rdev->constraints->valid_modes_mask & mode)) {
printk(KERN_ERR "%s: invalid mode %x for %s\n",
- __func__, mode, rdev->desc->name);
+ __func__, mode, rdev_get_name(rdev));
return -EINVAL;
}
return 0;
@@ -180,12 +190,12 @@ static int regulator_check_drms(struct regulator_dev *rdev)
{
if (!rdev->constraints) {
printk(KERN_ERR "%s: no constraints for %s\n", __func__,
- rdev->desc->name);
+ rdev_get_name(rdev));
return -ENODEV;
}
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) {
printk(KERN_ERR "%s: operation not allowed for %s\n",
- __func__, rdev->desc->name);
+ __func__, rdev_get_name(rdev));
return -EPERM;
}
return 0;
@@ -230,16 +240,8 @@ static ssize_t regulator_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
- const char *name;
- if (rdev->constraints && rdev->constraints->name)
- name = rdev->constraints->name;
- else if (rdev->desc->name)
- name = rdev->desc->name;
- else
- name = "";
-
- return sprintf(buf, "%s\n", name);
+ return sprintf(buf, "%s\n", rdev_get_name(rdev));
}
static ssize_t regulator_print_opmode(char *buf, int mode)
@@ -579,10 +581,29 @@ static int suspend_set_state(struct regulator_dev *rdev,
struct regulator_state *rstate)
{
int ret = 0;
+ bool can_set_state;
+
+ can_set_state = rdev->desc->ops->set_suspend_enable &&
+ rdev->desc->ops->set_suspend_disable;
+
+ /* If we have no suspend mode configration don't set anything;
+ * only warn if the driver actually makes the suspend mode
+ * configurable.
+ */
+ if (!rstate->enabled && !rstate->disabled) {
+ if (can_set_state)
+ printk(KERN_WARNING "%s: No configuration for %s\n",
+ __func__, rdev_get_name(rdev));
+ return 0;
+ }
- /* enable & disable are mandatory for suspend control */
- if (!rdev->desc->ops->set_suspend_enable ||
- !rdev->desc->ops->set_suspend_disable) {
+ if (rstate->enabled && rstate->disabled) {
+ printk(KERN_ERR "%s: invalid configuration for %s\n",
+ __func__, rdev_get_name(rdev));
+ return -EINVAL;
+ }
+
+ if (!can_set_state) {
printk(KERN_ERR "%s: no way to set suspend state\n",
__func__);
return -EINVAL;
@@ -641,25 +662,43 @@ static void print_constraints(struct regulator_dev *rdev)
{
struct regulation_constraints *constraints = rdev->constraints;
char buf[80];
- int count;
+ int count = 0;
+ int ret;
- if (rdev->desc->type == REGULATOR_VOLTAGE) {
+ if (constraints->min_uV && constraints->max_uV) {
if (constraints->min_uV == constraints->max_uV)
- count = sprintf(buf, "%d mV ",
- constraints->min_uV / 1000);
+ count += sprintf(buf + count, "%d mV ",
+ constraints->min_uV / 1000);
else
- count = sprintf(buf, "%d <--> %d mV ",
- constraints->min_uV / 1000,
- constraints->max_uV / 1000);
- } else {
+ count += sprintf(buf + count, "%d <--> %d mV ",
+ constraints->min_uV / 1000,
+ constraints->max_uV / 1000);
+ }
+
+ if (!constraints->min_uV ||
+ constraints->min_uV != constraints->max_uV) {
+ ret = _regulator_get_voltage(rdev);
+ if (ret > 0)
+ count += sprintf(buf + count, "at %d mV ", ret / 1000);
+ }
+
+ if (constraints->min_uA && constraints->max_uA) {
if (constraints->min_uA == constraints->max_uA)
- count = sprintf(buf, "%d mA ",
- constraints->min_uA / 1000);
+ count += sprintf(buf + count, "%d mA ",
+ constraints->min_uA / 1000);
else
- count = sprintf(buf, "%d <--> %d mA ",
- constraints->min_uA / 1000,
- constraints->max_uA / 1000);
+ count += sprintf(buf + count, "%d <--> %d mA ",
+ constraints->min_uA / 1000,
+ constraints->max_uA / 1000);
+ }
+
+ if (!constraints->min_uA ||
+ constraints->min_uA != constraints->max_uA) {
+ ret = _regulator_get_current_limit(rdev);
+ if (ret > 0)
+ count += sprintf(buf + count, "at %d uA ", ret / 1000);
}
+
if (constraints->valid_modes_mask & REGULATOR_MODE_FAST)
count += sprintf(buf + count, "fast ");
if (constraints->valid_modes_mask & REGULATOR_MODE_NORMAL)
@@ -669,33 +708,30 @@ static void print_constraints(struct regulator_dev *rdev)
if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY)
count += sprintf(buf + count, "standby");
- printk(KERN_INFO "regulator: %s: %s\n", rdev->desc->name, buf);
+ printk(KERN_INFO "regulator: %s: %s\n", rdev_get_name(rdev), buf);
}
-/**
- * set_machine_constraints - sets regulator constraints
- * @rdev: regulator source
- * @constraints: constraints to apply
- *
- * Allows platform initialisation code to define and constrain
- * regulator circuits e.g. valid voltage/current ranges, etc. NOTE:
- * Constraints *must* be set by platform code in order for some
- * regulator operations to proceed i.e. set_voltage, set_current_limit,
- * set_mode.
- */
-static int set_machine_constraints(struct regulator_dev *rdev,
+static int machine_constraints_voltage(struct regulator_dev *rdev,
struct regulation_constraints *constraints)
{
- int ret = 0;
- const char *name;
struct regulator_ops *ops = rdev->desc->ops;
+ const char *name = rdev_get_name(rdev);
+ int ret;
- if (constraints->name)
- name = constraints->name;
- else if (rdev->desc->name)
- name = rdev->desc->name;
- else
- name = "regulator";
+ /* do we need to apply the constraint voltage */
+ if (rdev->constraints->apply_uV &&
+ rdev->constraints->min_uV == rdev->constraints->max_uV &&
+ ops->set_voltage) {
+ ret = ops->set_voltage(rdev,
+ rdev->constraints->min_uV, rdev->constraints->max_uV);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: failed to apply %duV constraint to %s\n",
+ __func__,
+ rdev->constraints->min_uV, name);
+ rdev->constraints = NULL;
+ return ret;
+ }
+ }
/* constrain machine-level voltage specs to fit
* the actual range supported by this regulator.
@@ -719,14 +755,13 @@ static int set_machine_constraints(struct regulator_dev *rdev,
/* voltage constraints are optional */
if ((cmin == 0) && (cmax == 0))
- goto out;
+ return 0;
/* else require explicit machine-level constraints */
if (cmin <= 0 || cmax <= 0 || cmax < cmin) {
pr_err("%s: %s '%s' voltage constraints\n",
__func__, "invalid", name);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
/* initial: [cmin..cmax] valid, [min_uV..max_uV] not */
@@ -748,8 +783,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
if (max_uV < min_uV) {
pr_err("%s: %s '%s' voltage constraints\n",
__func__, "unsupportable", name);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
/* use regulator's subset of machine constraints */
@@ -767,22 +801,34 @@ static int set_machine_constraints(struct regulator_dev *rdev,
}
}
+ return 0;
+}
+
+/**
+ * set_machine_constraints - sets regulator constraints
+ * @rdev: regulator source
+ * @constraints: constraints to apply
+ *
+ * Allows platform initialisation code to define and constrain
+ * regulator circuits e.g. valid voltage/current ranges, etc. NOTE:
+ * Constraints *must* be set by platform code in order for some
+ * regulator operations to proceed i.e. set_voltage, set_current_limit,
+ * set_mode.
+ */
+static int set_machine_constraints(struct regulator_dev *rdev,
+ struct regulation_constraints *constraints)
+{
+ int ret = 0;
+ const char *name;
+ struct regulator_ops *ops = rdev->desc->ops;
+
rdev->constraints = constraints;
- /* do we need to apply the constraint voltage */
- if (rdev->constraints->apply_uV &&
- rdev->constraints->min_uV == rdev->constraints->max_uV &&
- ops->set_voltage) {
- ret = ops->set_voltage(rdev,
- rdev->constraints->min_uV, rdev->constraints->max_uV);
- if (ret < 0) {
- printk(KERN_ERR "%s: failed to apply %duV constraint to %s\n",
- __func__,
- rdev->constraints->min_uV, name);
- rdev->constraints = NULL;
- goto out;
- }
- }
+ name = rdev_get_name(rdev);
+
+ ret = machine_constraints_voltage(rdev, constraints);
+ if (ret != 0)
+ goto out;
/* do we need to setup our suspend state */
if (constraints->initial_state) {
@@ -903,7 +949,7 @@ static int set_consumer_device_supply(struct regulator_dev *rdev,
dev_name(&node->regulator->dev),
node->regulator->desc->name,
supply,
- dev_name(&rdev->dev), rdev->desc->name);
+ dev_name(&rdev->dev), rdev_get_name(rdev));
return -EBUSY;
}
@@ -1212,7 +1258,7 @@ static int _regulator_enable(struct regulator_dev *rdev)
ret = _regulator_enable(rdev->supply);
if (ret < 0) {
printk(KERN_ERR "%s: failed to enable %s: %d\n",
- __func__, rdev->desc->name, ret);
+ __func__, rdev_get_name(rdev), ret);
return ret;
}
}
@@ -1238,7 +1284,7 @@ static int _regulator_enable(struct regulator_dev *rdev)
}
} else if (ret < 0) {
printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n",
- __func__, rdev->desc->name, ret);
+ __func__, rdev_get_name(rdev), ret);
return ret;
}
/* Fallthrough on positive return values - already enabled */
@@ -1279,11 +1325,12 @@ static int _regulator_disable(struct regulator_dev *rdev)
if (WARN(rdev->use_count <= 0,
"unbalanced disables for %s\n",
- rdev->desc->name))
+ rdev_get_name(rdev)))
return -EIO;
/* are we the last user and permitted to disable ? */
- if (rdev->use_count == 1 && !rdev->constraints->always_on) {
+ if (rdev->use_count == 1 &&
+ (rdev->constraints && !rdev->constraints->always_on)) {
/* we are last user */
if (_regulator_can_change_status(rdev) &&
@@ -1291,7 +1338,7 @@ static int _regulator_disable(struct regulator_dev *rdev)
ret = rdev->desc->ops->disable(rdev);
if (ret < 0) {
printk(KERN_ERR "%s: failed to disable %s\n",
- __func__, rdev->desc->name);
+ __func__, rdev_get_name(rdev));
return ret;
}
}
@@ -1348,7 +1395,7 @@ static int _regulator_force_disable(struct regulator_dev *rdev)
ret = rdev->desc->ops->disable(rdev);
if (ret < 0) {
printk(KERN_ERR "%s: failed to force disable %s\n",
- __func__, rdev->desc->name);
+ __func__, rdev_get_name(rdev));
return ret;
}
/* notify other consumers that power has been forced off */
@@ -1765,7 +1812,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
output_uV = rdev->desc->ops->get_voltage(rdev);
if (output_uV <= 0) {
printk(KERN_ERR "%s: invalid output voltage found for %s\n",
- __func__, rdev->desc->name);
+ __func__, rdev_get_name(rdev));
goto out;
}
@@ -1776,7 +1823,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
input_uV = rdev->constraints->input_uV;
if (input_uV <= 0) {
printk(KERN_ERR "%s: invalid input voltage found for %s\n",
- __func__, rdev->desc->name);
+ __func__, rdev_get_name(rdev));
goto out;
}
@@ -1790,7 +1837,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
ret = regulator_check_mode(rdev, mode);
if (ret < 0) {
printk(KERN_ERR "%s: failed to get optimum mode for %s @"
- " %d uA %d -> %d uV\n", __func__, rdev->desc->name,
+ " %d uA %d -> %d uV\n", __func__, rdev_get_name(rdev),
total_uA_load, input_uV, output_uV);
goto out;
}
@@ -1798,7 +1845,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
ret = rdev->desc->ops->set_mode(rdev, mode);
if (ret < 0) {
printk(KERN_ERR "%s: failed to set optimum mode %x for %s\n",
- __func__, mode, rdev->desc->name);
+ __func__, mode, rdev_get_name(rdev));
goto out;
}
ret = mode;
@@ -1884,9 +1931,9 @@ int regulator_bulk_get(struct device *dev, int num_consumers,
consumers[i].consumer = regulator_get(dev,
consumers[i].supply);
if (IS_ERR(consumers[i].consumer)) {
- dev_err(dev, "Failed to get supply '%s'\n",
- consumers[i].supply);
ret = PTR_ERR(consumers[i].consumer);
+ dev_err(dev, "Failed to get supply '%s': %d\n",
+ consumers[i].supply, ret);
consumers[i].consumer = NULL;
goto err;
}
@@ -1929,7 +1976,7 @@ int regulator_bulk_enable(int num_consumers,
return 0;
err:
- printk(KERN_ERR "Failed to enable %s\n", consumers[i].supply);
+ printk(KERN_ERR "Failed to enable %s: %d\n", consumers[i].supply, ret);
for (i = 0; i < num_consumers; i++)
regulator_disable(consumers[i].consumer);
@@ -1964,7 +2011,8 @@ int regulator_bulk_disable(int num_consumers,
return 0;
err:
- printk(KERN_ERR "Failed to disable %s\n", consumers[i].supply);
+ printk(KERN_ERR "Failed to disable %s: %d\n", consumers[i].supply,
+ ret);
for (i = 0; i < num_consumers; i++)
regulator_enable(consumers[i].consumer);
@@ -2315,7 +2363,7 @@ int regulator_suspend_prepare(suspend_state_t state)
if (ret < 0) {
printk(KERN_ERR "%s: failed to prepare %s\n",
- __func__, rdev->desc->name);
+ __func__, rdev_get_name(rdev));
goto out;
}
}
@@ -2428,12 +2476,7 @@ static int __init regulator_init_complete(void)
ops = rdev->desc->ops;
c = rdev->constraints;
- if (c && c->name)
- name = c->name;
- else if (rdev->desc->name)
- name = rdev->desc->name;
- else
- name = "regulator";
+ name = rdev_get_name(rdev);
if (!ops->disable || (c && c->always_on))
continue;
diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c
index aa224d936e0d..f8c4661a7a81 100644
--- a/drivers/regulator/da903x.c
+++ b/drivers/regulator/da903x.c
@@ -331,7 +331,7 @@ static int da9034_get_ldo12_voltage(struct regulator_dev *rdev)
static int da9034_list_ldo12_voltage(struct regulator_dev *rdev,
unsigned selector)
{
- if (selector > ARRAY_SIZE(da9034_ldo12_data))
+ if (selector >= ARRAY_SIZE(da9034_ldo12_data))
return -EINVAL;
return da9034_ldo12_data[selector] * 1000;
}
diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c
new file mode 100644
index 000000000000..acc2fb7b6087
--- /dev/null
+++ b/drivers/regulator/max8660.c
@@ -0,0 +1,510 @@
+/*
+ * max8660.c -- Voltage regulation for the Maxim 8660/8661
+ *
+ * based on max1586.c and wm8400-regulator.c
+ *
+ * Copyright (C) 2009 Wolfram Sang, Pengutronix e.K.
+ *
+ * This 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
+ *
+ * Some info:
+ *
+ * Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX8660-MAX8661.pdf
+ *
+ * This chip is a bit nasty because it is a write-only device. Thus, the driver
+ * uses shadow registers to keep track of its values. The main problem appears
+ * to be the initialization: When Linux boots up, we cannot know if the chip is
+ * in the default state or not, so we would have to pass such information in
+ * platform_data. As this adds a bit of complexity to the driver, this is left
+ * out for now until it is really needed.
+ *
+ * [A|S|M]DTV1 registers are currently not used, but [A|S|M]DTV2.
+ *
+ * If the driver is feature complete, it might be worth to check if one set of
+ * functions for V3-V7 is sufficient. For maximum flexibility during
+ * development, they are separated for now.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/max8660.h>
+
+#define MAX8660_DCDC_MIN_UV 725000
+#define MAX8660_DCDC_MAX_UV 1800000
+#define MAX8660_DCDC_STEP 25000
+#define MAX8660_DCDC_MAX_SEL 0x2b
+
+#define MAX8660_LDO5_MIN_UV 1700000
+#define MAX8660_LDO5_MAX_UV 2000000
+#define MAX8660_LDO5_STEP 25000
+#define MAX8660_LDO5_MAX_SEL 0x0c
+
+#define MAX8660_LDO67_MIN_UV 1800000
+#define MAX8660_LDO67_MAX_UV 3300000
+#define MAX8660_LDO67_STEP 100000
+#define MAX8660_LDO67_MAX_SEL 0x0f
+
+enum {
+ MAX8660_OVER1,
+ MAX8660_OVER2,
+ MAX8660_VCC1,
+ MAX8660_ADTV1,
+ MAX8660_ADTV2,
+ MAX8660_SDTV1,
+ MAX8660_SDTV2,
+ MAX8660_MDTV1,
+ MAX8660_MDTV2,
+ MAX8660_L12VCR,
+ MAX8660_FPWM,
+ MAX8660_N_REGS, /* not a real register */
+};
+
+struct max8660 {
+ struct i2c_client *client;
+ u8 shadow_regs[MAX8660_N_REGS]; /* as chip is write only */
+ struct regulator_dev *rdev[];
+};
+
+static int max8660_write(struct max8660 *max8660, u8 reg, u8 mask, u8 val)
+{
+ static const u8 max8660_addresses[MAX8660_N_REGS] =
+ { 0x10, 0x12, 0x20, 0x23, 0x24, 0x29, 0x2a, 0x32, 0x33, 0x39, 0x80 };
+
+ int ret;
+ u8 reg_val = (max8660->shadow_regs[reg] & mask) | val;
+ dev_vdbg(&max8660->client->dev, "Writing reg %02x with %02x\n",
+ max8660_addresses[reg], reg_val);
+
+ ret = i2c_smbus_write_byte_data(max8660->client,
+ max8660_addresses[reg], reg_val);
+ if (ret == 0)
+ max8660->shadow_regs[reg] = reg_val;
+
+ return ret;
+}
+
+
+/*
+ * DCDC functions
+ */
+
+static int max8660_dcdc_is_enabled(struct regulator_dev *rdev)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 val = max8660->shadow_regs[MAX8660_OVER1];
+ u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4;
+ return !!(val & mask);
+}
+
+static int max8660_dcdc_enable(struct regulator_dev *rdev)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 bit = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4;
+ return max8660_write(max8660, MAX8660_OVER1, 0xff, bit);
+}
+
+static int max8660_dcdc_disable(struct regulator_dev *rdev)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? ~1 : ~4;
+ return max8660_write(max8660, MAX8660_OVER1, mask, 0);
+}
+
+static int max8660_dcdc_list(struct regulator_dev *rdev, unsigned selector)
+{
+ if (selector > MAX8660_DCDC_MAX_SEL)
+ return -EINVAL;
+ return MAX8660_DCDC_MIN_UV + selector * MAX8660_DCDC_STEP;
+}
+
+static int max8660_dcdc_get(struct regulator_dev *rdev)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2;
+ u8 selector = max8660->shadow_regs[reg];
+ return MAX8660_DCDC_MIN_UV + selector * MAX8660_DCDC_STEP;
+}
+
+static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 reg, selector, bits;
+ int ret;
+
+ if (min_uV < MAX8660_DCDC_MIN_UV || min_uV > MAX8660_DCDC_MAX_UV)
+ return -EINVAL;
+ if (max_uV < MAX8660_DCDC_MIN_UV || max_uV > MAX8660_DCDC_MAX_UV)
+ return -EINVAL;
+
+ selector = (min_uV - (MAX8660_DCDC_MIN_UV - MAX8660_DCDC_STEP + 1))
+ / MAX8660_DCDC_STEP;
+
+ ret = max8660_dcdc_list(rdev, selector);
+ if (ret < 0 || ret > max_uV)
+ return -EINVAL;
+
+ reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2;
+ ret = max8660_write(max8660, reg, 0, selector);
+ if (ret)
+ return ret;
+
+ /* Select target voltage register and activate regulation */
+ bits = (rdev_get_id(rdev) == MAX8660_V3) ? 0x03 : 0x30;
+ return max8660_write(max8660, MAX8660_VCC1, 0xff, bits);
+}
+
+static struct regulator_ops max8660_dcdc_ops = {
+ .is_enabled = max8660_dcdc_is_enabled,
+ .list_voltage = max8660_dcdc_list,
+ .set_voltage = max8660_dcdc_set,
+ .get_voltage = max8660_dcdc_get,
+};
+
+
+/*
+ * LDO5 functions
+ */
+
+static int max8660_ldo5_list(struct regulator_dev *rdev, unsigned selector)
+{
+ if (selector > MAX8660_LDO5_MAX_SEL)
+ return -EINVAL;
+ return MAX8660_LDO5_MIN_UV + selector * MAX8660_LDO5_STEP;
+}
+
+static int max8660_ldo5_get(struct regulator_dev *rdev)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 selector = max8660->shadow_regs[MAX8660_MDTV2];
+
+ return MAX8660_LDO5_MIN_UV + selector * MAX8660_LDO5_STEP;
+}
+
+static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 selector;
+ int ret;
+
+ if (min_uV < MAX8660_LDO5_MIN_UV || min_uV > MAX8660_LDO5_MAX_UV)
+ return -EINVAL;
+ if (max_uV < MAX8660_LDO5_MIN_UV || max_uV > MAX8660_LDO5_MAX_UV)
+ return -EINVAL;
+
+ selector = (min_uV - (MAX8660_LDO5_MIN_UV - MAX8660_LDO5_STEP + 1))
+ / MAX8660_LDO5_STEP;
+ ret = max8660_ldo5_list(rdev, selector);
+ if (ret < 0 || ret > max_uV)
+ return -EINVAL;
+
+ ret = max8660_write(max8660, MAX8660_MDTV2, 0, selector);
+ if (ret)
+ return ret;
+
+ /* Select target voltage register and activate regulation */
+ return max8660_write(max8660, MAX8660_VCC1, 0xff, 0xc0);
+}
+
+static struct regulator_ops max8660_ldo5_ops = {
+ .list_voltage = max8660_ldo5_list,
+ .set_voltage = max8660_ldo5_set,
+ .get_voltage = max8660_ldo5_get,
+};
+
+
+/*
+ * LDO67 functions
+ */
+
+static int max8660_ldo67_is_enabled(struct regulator_dev *rdev)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 val = max8660->shadow_regs[MAX8660_OVER2];
+ u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4;
+ return !!(val & mask);
+}
+
+static int max8660_ldo67_enable(struct regulator_dev *rdev)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 bit = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4;
+ return max8660_write(max8660, MAX8660_OVER2, 0xff, bit);
+}
+
+static int max8660_ldo67_disable(struct regulator_dev *rdev)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? ~2 : ~4;
+ return max8660_write(max8660, MAX8660_OVER2, mask, 0);
+}
+
+static int max8660_ldo67_list(struct regulator_dev *rdev, unsigned selector)
+{
+ if (selector > MAX8660_LDO67_MAX_SEL)
+ return -EINVAL;
+ return MAX8660_LDO67_MIN_UV + selector * MAX8660_LDO67_STEP;
+}
+
+static int max8660_ldo67_get(struct regulator_dev *rdev)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 shift = (rdev_get_id(rdev) == MAX8660_V6) ? 0 : 4;
+ u8 selector = (max8660->shadow_regs[MAX8660_L12VCR] >> shift) & 0xf;
+
+ return MAX8660_LDO67_MIN_UV + selector * MAX8660_LDO67_STEP;
+}
+
+static int max8660_ldo67_set(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+ struct max8660 *max8660 = rdev_get_drvdata(rdev);
+ u8 selector;
+ int ret;
+
+ if (min_uV < MAX8660_LDO67_MIN_UV || min_uV > MAX8660_LDO67_MAX_UV)
+ return -EINVAL;
+ if (max_uV < MAX8660_LDO67_MIN_UV || max_uV > MAX8660_LDO67_MAX_UV)
+ return -EINVAL;
+
+ selector = (min_uV - (MAX8660_LDO67_MIN_UV - MAX8660_LDO67_STEP + 1))
+ / MAX8660_LDO67_STEP;
+
+ ret = max8660_ldo67_list(rdev, selector);
+ if (ret < 0 || ret > max_uV)
+ return -EINVAL;
+
+ if (rdev_get_id(rdev) == MAX8660_V6)
+ return max8660_write(max8660, MAX8660_L12VCR, 0xf0, selector);
+ else
+ return max8660_write(max8660, MAX8660_L12VCR, 0x0f, selector << 4);
+}
+
+static struct regulator_ops max8660_ldo67_ops = {
+ .is_enabled = max8660_ldo67_is_enabled,
+ .enable = max8660_ldo67_enable,
+ .disable = max8660_ldo67_disable,
+ .list_voltage = max8660_ldo67_list,
+ .get_voltage = max8660_ldo67_get,
+ .set_voltage = max8660_ldo67_set,
+};
+
+static struct regulator_desc max8660_reg[] = {
+ {
+ .name = "V3(DCDC)",
+ .id = MAX8660_V3,
+ .ops = &max8660_dcdc_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = MAX8660_DCDC_MAX_SEL + 1,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "V4(DCDC)",
+ .id = MAX8660_V4,
+ .ops = &max8660_dcdc_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = MAX8660_DCDC_MAX_SEL + 1,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "V5(LDO)",
+ .id = MAX8660_V5,
+ .ops = &max8660_ldo5_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = MAX8660_LDO5_MAX_SEL + 1,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "V6(LDO)",
+ .id = MAX8660_V6,
+ .ops = &max8660_ldo67_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = MAX8660_LDO67_MAX_SEL + 1,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "V7(LDO)",
+ .id = MAX8660_V7,
+ .ops = &max8660_ldo67_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = MAX8660_LDO67_MAX_SEL + 1,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int max8660_probe(struct i2c_client *client,
+ const struct i2c_device_id *i2c_id)
+{
+ struct regulator_dev **rdev;
+ struct max8660_platform_data *pdata = client->dev.platform_data;
+ struct max8660 *max8660;
+ int boot_on, i, id, ret = -EINVAL;
+
+ if (pdata->num_subdevs > MAX8660_V_END) {
+ dev_err(&client->dev, "Too much regulators found!\n");
+ goto out;
+ }
+
+ max8660 = kzalloc(sizeof(struct max8660) +
+ sizeof(struct regulator_dev *) * MAX8660_V_END,
+ GFP_KERNEL);
+ if (!max8660) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ max8660->client = client;
+ rdev = max8660->rdev;
+
+ if (pdata->en34_is_high) {
+ /* Simulate always on */
+ max8660->shadow_regs[MAX8660_OVER1] = 5;
+ } else {
+ /* Otherwise devices can be toggled via software */
+ max8660_dcdc_ops.enable = max8660_dcdc_enable;
+ max8660_dcdc_ops.disable = max8660_dcdc_disable;
+ }
+
+ /*
+ * First, set up shadow registers to prevent glitches. As some
+ * registers are shared between regulators, everything must be properly
+ * set up for all regulators in advance.
+ */
+ max8660->shadow_regs[MAX8660_ADTV1] =
+ max8660->shadow_regs[MAX8660_ADTV2] =
+ max8660->shadow_regs[MAX8660_SDTV1] =
+ max8660->shadow_regs[MAX8660_SDTV2] = 0x1b;
+ max8660->shadow_regs[MAX8660_MDTV1] =
+ max8660->shadow_regs[MAX8660_MDTV2] = 0x04;
+
+ for (i = 0; i < pdata->num_subdevs; i++) {
+
+ if (!pdata->subdevs[i].platform_data)
+ goto err_free;
+
+ boot_on = pdata->subdevs[i].platform_data->constraints.boot_on;
+
+ switch (pdata->subdevs[i].id) {
+ case MAX8660_V3:
+ if (boot_on)
+ max8660->shadow_regs[MAX8660_OVER1] |= 1;
+ break;
+
+ case MAX8660_V4:
+ if (boot_on)
+ max8660->shadow_regs[MAX8660_OVER1] |= 4;
+ break;
+
+ case MAX8660_V5:
+ break;
+
+ case MAX8660_V6:
+ if (boot_on)
+ max8660->shadow_regs[MAX8660_OVER2] |= 2;
+ break;
+
+ case MAX8660_V7:
+ if (!strcmp(i2c_id->name, "max8661")) {
+ dev_err(&client->dev, "Regulator not on this chip!\n");
+ goto err_free;
+ }
+
+ if (boot_on)
+ max8660->shadow_regs[MAX8660_OVER2] |= 4;
+ break;
+
+ default:
+ dev_err(&client->dev, "invalid regulator %s\n",
+ pdata->subdevs[i].name);
+ goto err_free;
+ }
+ }
+
+ /* Finally register devices */
+ for (i = 0; i < pdata->num_subdevs; i++) {
+
+ id = pdata->subdevs[i].id;
+
+ rdev[i] = regulator_register(&max8660_reg[id], &client->dev,
+ pdata->subdevs[i].platform_data,
+ max8660);
+ if (IS_ERR(rdev[i])) {
+ ret = PTR_ERR(rdev[i]);
+ dev_err(&client->dev, "failed to register %s\n",
+ max8660_reg[id].name);
+ goto err_unregister;
+ }
+ }
+
+ i2c_set_clientdata(client, rdev);
+ dev_info(&client->dev, "Maxim 8660/8661 regulator driver loaded\n");
+ return 0;
+
+err_unregister:
+ while (--i >= 0)
+ regulator_unregister(rdev[i]);
+err_free:
+ kfree(max8660);
+out:
+ return ret;
+}
+
+static int max8660_remove(struct i2c_client *client)
+{
+ struct regulator_dev **rdev = i2c_get_clientdata(client);
+ int i;
+
+ for (i = 0; i < MAX8660_V_END; i++)
+ if (rdev[i])
+ regulator_unregister(rdev[i]);
+ kfree(rdev);
+ i2c_set_clientdata(client, NULL);
+
+ return 0;
+}
+
+static const struct i2c_device_id max8660_id[] = {
+ { "max8660", 0 },
+ { "max8661", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max8660_id);
+
+static struct i2c_driver max8660_driver = {
+ .probe = max8660_probe,
+ .remove = max8660_remove,
+ .driver = {
+ .name = "max8660",
+ },
+ .id_table = max8660_id,
+};
+
+static int __init max8660_init(void)
+{
+ return i2c_add_driver(&max8660_driver);
+}
+subsys_initcall(max8660_init);
+
+static void __exit max8660_exit(void)
+{
+ i2c_del_driver(&max8660_driver);
+}
+module_exit(max8660_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MAXIM 8660/8661 voltage regulator driver");
+MODULE_AUTHOR("Wolfram Sang");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c
index 0803ffe6236d..c8f41dc05b76 100644
--- a/drivers/regulator/pcf50633-regulator.c
+++ b/drivers/regulator/pcf50633-regulator.c
@@ -314,13 +314,15 @@ static int __devinit pcf50633_regulator_probe(struct platform_device *pdev)
struct pcf50633 *pcf;
/* Already set by core driver */
- pcf = platform_get_drvdata(pdev);
+ pcf = dev_to_pcf50633(pdev->dev.parent);
rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
pdev->dev.platform_data, pcf);
if (IS_ERR(rdev))
return PTR_ERR(rdev);
+ platform_set_drvdata(pdev, rdev);
+
if (pcf->pdata->regulator_registered)
pcf->pdata->regulator_registered(pcf, pdev->id);
@@ -331,6 +333,7 @@ static int __devexit pcf50633_regulator_remove(struct platform_device *pdev)
{
struct regulator_dev *rdev = platform_get_drvdata(pdev);
+ platform_set_drvdata(pdev, NULL);
regulator_unregister(rdev);
return 0;
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c
index 2eefc1a0cf08..0a6577577e8d 100644
--- a/drivers/regulator/wm831x-dcdc.c
+++ b/drivers/regulator/wm831x-dcdc.c
@@ -19,6 +19,8 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/gpio.h>
#include <linux/mfd/wm831x/core.h>
#include <linux/mfd/wm831x/regulator.h>
@@ -39,6 +41,7 @@
#define WM831X_DCDC_CONTROL_2 1
#define WM831X_DCDC_ON_CONFIG 2
#define WM831X_DCDC_SLEEP_CONTROL 3
+#define WM831X_DCDC_DVS_CONTROL 4
/*
* Shared
@@ -50,6 +53,10 @@ struct wm831x_dcdc {
int base;
struct wm831x *wm831x;
struct regulator_dev *regulator;
+ int dvs_gpio;
+ int dvs_gpio_state;
+ int on_vsel;
+ int dvs_vsel;
};
static int wm831x_dcdc_is_enabled(struct regulator_dev *rdev)
@@ -240,11 +247,9 @@ static int wm831x_buckv_list_voltage(struct regulator_dev *rdev,
return -EINVAL;
}
-static int wm831x_buckv_set_voltage_int(struct regulator_dev *rdev, int reg,
- int min_uV, int max_uV)
+static int wm831x_buckv_select_min_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
{
- struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
- struct wm831x *wm831x = dcdc->wm831x;
u16 vsel;
if (min_uV < 600000)
@@ -257,39 +262,126 @@ static int wm831x_buckv_set_voltage_int(struct regulator_dev *rdev, int reg,
if (wm831x_buckv_list_voltage(rdev, vsel) > max_uV)
return -EINVAL;
- return wm831x_set_bits(wm831x, reg, WM831X_DC1_ON_VSEL_MASK, vsel);
+ return vsel;
+}
+
+static int wm831x_buckv_select_max_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ u16 vsel;
+
+ if (max_uV < 600000 || max_uV > 1800000)
+ return -EINVAL;
+
+ vsel = ((max_uV - 600000) / 12500) + 8;
+
+ if (wm831x_buckv_list_voltage(rdev, vsel) < min_uV ||
+ wm831x_buckv_list_voltage(rdev, vsel) < max_uV)
+ return -EINVAL;
+
+ return vsel;
+}
+
+static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state)
+{
+ struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+
+ if (state == dcdc->dvs_gpio_state)
+ return 0;
+
+ dcdc->dvs_gpio_state = state;
+ gpio_set_value(dcdc->dvs_gpio, state);
+
+ /* Should wait for DVS state change to be asserted if we have
+ * a GPIO for it, for now assume the device is configured
+ * for the fastest possible transition.
+ */
+
+ return 0;
}
static int wm831x_buckv_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV)
+ int min_uV, int max_uV)
{
struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
- u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
+ struct wm831x *wm831x = dcdc->wm831x;
+ int on_reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
+ int dvs_reg = dcdc->base + WM831X_DCDC_DVS_CONTROL;
+ int vsel, ret;
+
+ vsel = wm831x_buckv_select_min_voltage(rdev, min_uV, max_uV);
+ if (vsel < 0)
+ return vsel;
+
+ /* If this value is already set then do a GPIO update if we can */
+ if (dcdc->dvs_gpio && dcdc->on_vsel == vsel)
+ return wm831x_buckv_set_dvs(rdev, 0);
+
+ if (dcdc->dvs_gpio && dcdc->dvs_vsel == vsel)
+ return wm831x_buckv_set_dvs(rdev, 1);
+
+ /* Always set the ON status to the minimum voltage */
+ ret = wm831x_set_bits(wm831x, on_reg, WM831X_DC1_ON_VSEL_MASK, vsel);
+ if (ret < 0)
+ return ret;
+ dcdc->on_vsel = vsel;
+
+ if (!dcdc->dvs_gpio)
+ return ret;
+
+ /* Kick the voltage transition now */
+ ret = wm831x_buckv_set_dvs(rdev, 0);
+ if (ret < 0)
+ return ret;
+
+ /* Set the high voltage as the DVS voltage. This is optimised
+ * for CPUfreq usage, most processors will keep the maximum
+ * voltage constant and lower the minimum with the frequency. */
+ vsel = wm831x_buckv_select_max_voltage(rdev, min_uV, max_uV);
+ if (vsel < 0) {
+ /* This should never happen - at worst the same vsel
+ * should be chosen */
+ WARN_ON(vsel < 0);
+ return 0;
+ }
+
+ /* Don't bother if it's the same VSEL we're already using */
+ if (vsel == dcdc->on_vsel)
+ return 0;
- return wm831x_buckv_set_voltage_int(rdev, reg, min_uV, max_uV);
+ ret = wm831x_set_bits(wm831x, dvs_reg, WM831X_DC1_DVS_VSEL_MASK, vsel);
+ if (ret == 0)
+ dcdc->dvs_vsel = vsel;
+ else
+ dev_warn(wm831x->dev, "Failed to set DCDC DVS VSEL: %d\n",
+ ret);
+
+ return 0;
}
static int wm831x_buckv_set_suspend_voltage(struct regulator_dev *rdev,
- int uV)
+ int uV)
{
struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+ struct wm831x *wm831x = dcdc->wm831x;
u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL;
+ int vsel;
+
+ vsel = wm831x_buckv_select_min_voltage(rdev, uV, uV);
+ if (vsel < 0)
+ return vsel;
- return wm831x_buckv_set_voltage_int(rdev, reg, uV, uV);
+ return wm831x_set_bits(wm831x, reg, WM831X_DC1_SLP_VSEL_MASK, vsel);
}
static int wm831x_buckv_get_voltage(struct regulator_dev *rdev)
{
struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
- struct wm831x *wm831x = dcdc->wm831x;
- u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
- int val;
- val = wm831x_reg_read(wm831x, reg);
- if (val < 0)
- return val;
-
- return wm831x_buckv_list_voltage(rdev, val & WM831X_DC1_ON_VSEL_MASK);
+ if (dcdc->dvs_gpio && dcdc->dvs_gpio_state)
+ return wm831x_buckv_list_voltage(rdev, dcdc->dvs_vsel);
+ else
+ return wm831x_buckv_list_voltage(rdev, dcdc->on_vsel);
}
/* Current limit options */
@@ -346,6 +438,64 @@ static struct regulator_ops wm831x_buckv_ops = {
.set_suspend_mode = wm831x_dcdc_set_suspend_mode,
};
+/*
+ * Set up DVS control. We just log errors since we can still run
+ * (with reduced performance) if we fail.
+ */
+static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc,
+ struct wm831x_buckv_pdata *pdata)
+{
+ struct wm831x *wm831x = dcdc->wm831x;
+ int ret;
+ u16 ctrl;
+
+ if (!pdata || !pdata->dvs_gpio)
+ return;
+
+ switch (pdata->dvs_control_src) {
+ case 1:
+ ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT;
+ break;
+ case 2:
+ ctrl = 3 << WM831X_DC1_DVS_SRC_SHIFT;
+ break;
+ default:
+ dev_err(wm831x->dev, "Invalid DVS control source %d for %s\n",
+ pdata->dvs_control_src, dcdc->name);
+ return;
+ }
+
+ ret = wm831x_set_bits(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL,
+ WM831X_DC1_DVS_SRC_MASK, ctrl);
+ if (ret < 0) {
+ dev_err(wm831x->dev, "Failed to set %s DVS source: %d\n",
+ dcdc->name, ret);
+ return;
+ }
+
+ ret = gpio_request(pdata->dvs_gpio, "DCDC DVS");
+ if (ret < 0) {
+ dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n",
+ dcdc->name, ret);
+ return;
+ }
+
+ /* gpiolib won't let us read the GPIO status so pick the higher
+ * of the two existing voltages so we take it as platform data.
+ */
+ dcdc->dvs_gpio_state = pdata->dvs_init_state;
+
+ ret = gpio_direction_output(pdata->dvs_gpio, dcdc->dvs_gpio_state);
+ if (ret < 0) {
+ dev_err(wm831x->dev, "Failed to enable %s DVS GPIO: %d\n",
+ dcdc->name, ret);
+ gpio_free(pdata->dvs_gpio);
+ return;
+ }
+
+ dcdc->dvs_gpio = pdata->dvs_gpio;
+}
+
static __devinit int wm831x_buckv_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
@@ -384,6 +534,23 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev)
dcdc->desc.ops = &wm831x_buckv_ops;
dcdc->desc.owner = THIS_MODULE;
+ ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_ON_CONFIG);
+ if (ret < 0) {
+ dev_err(wm831x->dev, "Failed to read ON VSEL: %d\n", ret);
+ goto err;
+ }
+ dcdc->on_vsel = ret & WM831X_DC1_ON_VSEL_MASK;
+
+ ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_ON_CONFIG);
+ if (ret < 0) {
+ dev_err(wm831x->dev, "Failed to read DVS VSEL: %d\n", ret);
+ goto err;
+ }
+ dcdc->dvs_vsel = ret & WM831X_DC1_DVS_VSEL_MASK;
+
+ if (pdata->dcdc[id])
+ wm831x_buckv_dvs_init(dcdc, pdata->dcdc[id]->driver_data);
+
dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev,
pdata->dcdc[id], dcdc);
if (IS_ERR(dcdc->regulator)) {
@@ -422,6 +589,8 @@ err_uv:
err_regulator:
regulator_unregister(dcdc->regulator);
err:
+ if (dcdc->dvs_gpio)
+ gpio_free(dcdc->dvs_gpio);
kfree(dcdc);
return ret;
}
@@ -434,6 +603,8 @@ static __devexit int wm831x_buckv_remove(struct platform_device *pdev)
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "HC"), dcdc);
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc);
regulator_unregister(dcdc->regulator);
+ if (dcdc->dvs_gpio)
+ gpio_free(dcdc->dvs_gpio);
kfree(dcdc);
return 0;
diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c
index bb61aede4801..902db56ce099 100644
--- a/drivers/regulator/wm831x-ldo.c
+++ b/drivers/regulator/wm831x-ldo.c
@@ -175,18 +175,18 @@ static unsigned int wm831x_gp_ldo_get_mode(struct regulator_dev *rdev)
struct wm831x *wm831x = ldo->wm831x;
int ctrl_reg = ldo->base + WM831X_LDO_CONTROL;
int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
- unsigned int ret;
+ int ret;
ret = wm831x_reg_read(wm831x, on_reg);
if (ret < 0)
- return 0;
+ return ret;
if (!(ret & WM831X_LDO1_ON_MODE))
return REGULATOR_MODE_NORMAL;
ret = wm831x_reg_read(wm831x, ctrl_reg);
if (ret < 0)
- return 0;
+ return ret;
if (ret & WM831X_LDO1_LP_MODE)
return REGULATOR_MODE_STANDBY;
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 3c20dae43ce2..1ad63fe880f8 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -520,6 +520,15 @@ config RTC_MXC
This driver can also be built as a module, if so, the module
will be called "rtc-mxc".
+config RTC_DRV_MSM6242
+ tristate "Oki MSM6242"
+ help
+ If you say yes here you get support for the Oki MSM6242
+ timekeeping chip. It is used in some Amiga models (e.g. A2000).
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-msm6242.
+
config RTC_DRV_BQ4802
tristate "TI BQ4802"
help
@@ -529,6 +538,16 @@ config RTC_DRV_BQ4802
This driver can also be built as a module. If so, the module
will be called rtc-bq4802.
+config RTC_DRV_RP5C01
+ tristate "Ricoh RP5C01"
+ help
+ If you say yes here you get support for the Ricoh RP5C01
+ timekeeping chip. It is used in some Amiga models (e.g. A3000
+ and A4000).
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-rp5c01.
+
config RTC_DRV_V3020
tristate "EM Microelectronic V3020"
help
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index aa3fbd5517a1..af1ba7ae2857 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
obj-$(CONFIG_RTC_MXC) += rtc-mxc.o
obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
+obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o
obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o
obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o
@@ -64,6 +65,7 @@ obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o
obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
+obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index 0b6b7730c716..539676e25fd8 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -2,7 +2,7 @@
* An rtc driver for the Dallas DS1511
*
* Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
- * Copyright (C) 2007 Andrew Sharp <andy.sharp@onstor.com>
+ * Copyright (C) 2007 Andrew Sharp <andy.sharp@lsi.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
@@ -636,7 +636,7 @@ ds1511_rtc_exit(void)
module_init(ds1511_rtc_init);
module_exit(ds1511_rtc_exit);
-MODULE_AUTHOR("Andrew Sharp <andy.sharp@onstor.com>");
+MODULE_AUTHOR("Andrew Sharp <andy.sharp@lsi.com>");
MODULE_DESCRIPTION("Dallas DS1511 RTC driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-msm6242.c b/drivers/rtc/rtc-msm6242.c
new file mode 100644
index 000000000000..10b9b7fb4700
--- /dev/null
+++ b/drivers/rtc/rtc-msm6242.c
@@ -0,0 +1,268 @@
+/*
+ * Oki MSM6242 RTC Driver
+ *
+ * Copyright 2009 Geert Uytterhoeven
+ *
+ * Based on the A2000 TOD code in arch/m68k/amiga/config.c
+ * Copyright (C) 1993 Hamish Macdonald
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+
+enum {
+ MSM6242_SECOND1 = 0x0, /* 1-second digit register */
+ MSM6242_SECOND10 = 0x1, /* 10-second digit register */
+ MSM6242_MINUTE1 = 0x2, /* 1-minute digit register */
+ MSM6242_MINUTE10 = 0x3, /* 10-minute digit register */
+ MSM6242_HOUR1 = 0x4, /* 1-hour digit register */
+ MSM6242_HOUR10 = 0x5, /* PM/AM, 10-hour digit register */
+ MSM6242_DAY1 = 0x6, /* 1-day digit register */
+ MSM6242_DAY10 = 0x7, /* 10-day digit register */
+ MSM6242_MONTH1 = 0x8, /* 1-month digit register */
+ MSM6242_MONTH10 = 0x9, /* 10-month digit register */
+ MSM6242_YEAR1 = 0xa, /* 1-year digit register */
+ MSM6242_YEAR10 = 0xb, /* 10-year digit register */
+ MSM6242_WEEK = 0xc, /* Week register */
+ MSM6242_CD = 0xd, /* Control Register D */
+ MSM6242_CE = 0xe, /* Control Register E */
+ MSM6242_CF = 0xf, /* Control Register F */
+};
+
+#define MSM6242_HOUR10_AM (0 << 2)
+#define MSM6242_HOUR10_PM (1 << 2)
+#define MSM6242_HOUR10_HR_MASK (3 << 0)
+
+#define MSM6242_WEEK_SUNDAY 0
+#define MSM6242_WEEK_MONDAY 1
+#define MSM6242_WEEK_TUESDAY 2
+#define MSM6242_WEEK_WEDNESDAY 3
+#define MSM6242_WEEK_THURSDAY 4
+#define MSM6242_WEEK_FRIDAY 5
+#define MSM6242_WEEK_SATURDAY 6
+
+#define MSM6242_CD_30_S_ADJ (1 << 3) /* 30-second adjustment */
+#define MSM6242_CD_IRQ_FLAG (1 << 2)
+#define MSM6242_CD_BUSY (1 << 1)
+#define MSM6242_CD_HOLD (1 << 0)
+
+#define MSM6242_CE_T_MASK (3 << 2)
+#define MSM6242_CE_T_64HZ (0 << 2) /* period 1/64 second */
+#define MSM6242_CE_T_1HZ (1 << 2) /* period 1 second */
+#define MSM6242_CE_T_1MINUTE (2 << 2) /* period 1 minute */
+#define MSM6242_CE_T_1HOUR (3 << 2) /* period 1 hour */
+
+#define MSM6242_CE_ITRPT_STND (1 << 1)
+#define MSM6242_CE_MASK (1 << 0) /* STD.P output control */
+
+#define MSM6242_CF_TEST (1 << 3)
+#define MSM6242_CF_12H (0 << 2)
+#define MSM6242_CF_24H (1 << 2)
+#define MSM6242_CF_STOP (1 << 1)
+#define MSM6242_CF_REST (1 << 0) /* reset */
+
+
+struct msm6242_priv {
+ u32 __iomem *regs;
+ struct rtc_device *rtc;
+};
+
+static inline unsigned int msm6242_read(struct msm6242_priv *priv,
+ unsigned int reg)
+{
+ return __raw_readl(&priv->regs[reg]) & 0xf;
+}
+
+static inline void msm6242_write(struct msm6242_priv *priv, unsigned int val,
+ unsigned int reg)
+{
+ return __raw_writel(val, &priv->regs[reg]);
+}
+
+static inline void msm6242_set(struct msm6242_priv *priv, unsigned int val,
+ unsigned int reg)
+{
+ msm6242_write(priv, msm6242_read(priv, reg) | val, reg);
+}
+
+static inline void msm6242_clear(struct msm6242_priv *priv, unsigned int val,
+ unsigned int reg)
+{
+ msm6242_write(priv, msm6242_read(priv, reg) & ~val, reg);
+}
+
+static void msm6242_lock(struct msm6242_priv *priv)
+{
+ int cnt = 5;
+
+ msm6242_set(priv, MSM6242_CD_HOLD, MSM6242_CD);
+
+ while ((msm6242_read(priv, MSM6242_CD) & MSM6242_CD_BUSY) && cnt--) {
+ msm6242_clear(priv, MSM6242_CD_HOLD, MSM6242_CD);
+ udelay(70);
+ msm6242_set(priv, MSM6242_CD_HOLD, MSM6242_CD);
+ }
+
+ if (!cnt)
+ pr_warning("msm6242: timed out waiting for RTC (0x%x)\n",
+ msm6242_read(priv, MSM6242_CD));
+}
+
+static void msm6242_unlock(struct msm6242_priv *priv)
+{
+ msm6242_clear(priv, MSM6242_CD_HOLD, MSM6242_CD);
+}
+
+static int msm6242_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct msm6242_priv *priv = dev_get_drvdata(dev);
+
+ msm6242_lock(priv);
+
+ tm->tm_sec = msm6242_read(priv, MSM6242_SECOND10) * 10 +
+ msm6242_read(priv, MSM6242_SECOND1);
+ tm->tm_min = msm6242_read(priv, MSM6242_MINUTE10) * 10 +
+ msm6242_read(priv, MSM6242_MINUTE1);
+ tm->tm_hour = (msm6242_read(priv, MSM6242_HOUR10 & 3)) * 10 +
+ msm6242_read(priv, MSM6242_HOUR1);
+ tm->tm_mday = msm6242_read(priv, MSM6242_DAY10) * 10 +
+ msm6242_read(priv, MSM6242_DAY1);
+ tm->tm_wday = msm6242_read(priv, MSM6242_WEEK);
+ tm->tm_mon = msm6242_read(priv, MSM6242_MONTH10) * 10 +
+ msm6242_read(priv, MSM6242_MONTH1) - 1;
+ tm->tm_year = msm6242_read(priv, MSM6242_YEAR10) * 10 +
+ msm6242_read(priv, MSM6242_YEAR1);
+ if (tm->tm_year <= 69)
+ tm->tm_year += 100;
+
+ if (!(msm6242_read(priv, MSM6242_CF) & MSM6242_CF_24H)) {
+ unsigned int pm = msm6242_read(priv, MSM6242_HOUR10) &
+ MSM6242_HOUR10_PM;
+ if (!pm && tm->tm_hour == 12)
+ tm->tm_hour = 0;
+ else if (pm && tm->tm_hour != 12)
+ tm->tm_hour += 12;
+ }
+
+ msm6242_unlock(priv);
+
+ return rtc_valid_tm(tm);
+}
+
+static int msm6242_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct msm6242_priv *priv = dev_get_drvdata(dev);
+
+ msm6242_lock(priv);
+
+ msm6242_write(priv, tm->tm_sec / 10, MSM6242_SECOND10);
+ msm6242_write(priv, tm->tm_sec % 10, MSM6242_SECOND1);
+ msm6242_write(priv, tm->tm_min / 10, MSM6242_MINUTE10);
+ msm6242_write(priv, tm->tm_min % 10, MSM6242_MINUTE1);
+ if (msm6242_read(priv, MSM6242_CF) & MSM6242_CF_24H)
+ msm6242_write(priv, tm->tm_hour / 10, MSM6242_HOUR10);
+ else if (tm->tm_hour >= 12)
+ msm6242_write(priv, MSM6242_HOUR10_PM + (tm->tm_hour - 12) / 10,
+ MSM6242_HOUR10);
+ else
+ msm6242_write(priv, tm->tm_hour / 10, MSM6242_HOUR10);
+ msm6242_write(priv, tm->tm_hour % 10, MSM6242_HOUR1);
+ msm6242_write(priv, tm->tm_mday / 10, MSM6242_DAY10);
+ msm6242_write(priv, tm->tm_mday % 10, MSM6242_DAY1);
+ if (tm->tm_wday != -1)
+ msm6242_write(priv, tm->tm_wday, MSM6242_WEEK);
+ msm6242_write(priv, (tm->tm_mon + 1) / 10, MSM6242_MONTH10);
+ msm6242_write(priv, (tm->tm_mon + 1) % 10, MSM6242_MONTH1);
+ if (tm->tm_year >= 100)
+ tm->tm_year -= 100;
+ msm6242_write(priv, tm->tm_year / 10, MSM6242_YEAR10);
+ msm6242_write(priv, tm->tm_year % 10, MSM6242_YEAR1);
+
+ msm6242_unlock(priv);
+ return 0;
+}
+
+static const struct rtc_class_ops msm6242_rtc_ops = {
+ .read_time = msm6242_read_time,
+ .set_time = msm6242_set_time,
+};
+
+static int __init msm6242_rtc_probe(struct platform_device *dev)
+{
+ struct resource *res;
+ struct msm6242_priv *priv;
+ struct rtc_device *rtc;
+ int error;
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->regs = ioremap(res->start, resource_size(res));
+ if (!priv->regs) {
+ error = -ENOMEM;
+ goto out_free_priv;
+ }
+
+ rtc = rtc_device_register("rtc-msm6242", &dev->dev, &msm6242_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ error = PTR_ERR(rtc);
+ goto out_unmap;
+ }
+
+ priv->rtc = rtc;
+ platform_set_drvdata(dev, priv);
+ return 0;
+
+out_unmap:
+ iounmap(priv->regs);
+out_free_priv:
+ kfree(priv);
+ return error;
+}
+
+static int __exit msm6242_rtc_remove(struct platform_device *dev)
+{
+ struct msm6242_priv *priv = platform_get_drvdata(dev);
+
+ rtc_device_unregister(priv->rtc);
+ iounmap(priv->regs);
+ kfree(priv);
+ return 0;
+}
+
+static struct platform_driver msm6242_rtc_driver = {
+ .driver = {
+ .name = "rtc-msm6242",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(msm6242_rtc_remove),
+};
+
+static int __init msm6242_rtc_init(void)
+{
+ return platform_driver_probe(&msm6242_rtc_driver, msm6242_rtc_probe);
+}
+
+static void __exit msm6242_rtc_fini(void)
+{
+ platform_driver_unregister(&msm6242_rtc_driver);
+}
+
+module_init(msm6242_rtc_init);
+module_exit(msm6242_rtc_fini);
+
+MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Oki MSM6242 RTC driver");
+MODULE_ALIAS("platform:rtc-msm6242");
diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c
index f4dd87e29075..0f045d791092 100644
--- a/drivers/rtc/rtc-pcf50633.c
+++ b/drivers/rtc/rtc-pcf50633.c
@@ -276,16 +276,13 @@ static void pcf50633_rtc_irq(int irq, void *data)
static int __devinit pcf50633_rtc_probe(struct platform_device *pdev)
{
- struct pcf50633_subdev_pdata *pdata;
struct pcf50633_rtc *rtc;
-
rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return -ENOMEM;
- pdata = pdev->dev.platform_data;
- rtc->pcf = pdata->pcf;
+ rtc->pcf = dev_to_pcf50633(pdev->dev.parent);
platform_set_drvdata(pdev, rtc);
rtc->rtc_dev = rtc_device_register("pcf50633-rtc", &pdev->dev,
&pcf50633_rtc_ops, THIS_MODULE);
diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c
new file mode 100644
index 000000000000..e1313feb060f
--- /dev/null
+++ b/drivers/rtc/rtc-rp5c01.c
@@ -0,0 +1,222 @@
+/*
+ * Ricoh RP5C01 RTC Driver
+ *
+ * Copyright 2009 Geert Uytterhoeven
+ *
+ * Based on the A3000 TOD code in arch/m68k/amiga/config.c
+ * Copyright (C) 1993 Hamish Macdonald
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+
+enum {
+ RP5C01_1_SECOND = 0x0, /* MODE 00 */
+ RP5C01_10_SECOND = 0x1, /* MODE 00 */
+ RP5C01_1_MINUTE = 0x2, /* MODE 00 and MODE 01 */
+ RP5C01_10_MINUTE = 0x3, /* MODE 00 and MODE 01 */
+ RP5C01_1_HOUR = 0x4, /* MODE 00 and MODE 01 */
+ RP5C01_10_HOUR = 0x5, /* MODE 00 and MODE 01 */
+ RP5C01_DAY_OF_WEEK = 0x6, /* MODE 00 and MODE 01 */
+ RP5C01_1_DAY = 0x7, /* MODE 00 and MODE 01 */
+ RP5C01_10_DAY = 0x8, /* MODE 00 and MODE 01 */
+ RP5C01_1_MONTH = 0x9, /* MODE 00 */
+ RP5C01_10_MONTH = 0xa, /* MODE 00 */
+ RP5C01_1_YEAR = 0xb, /* MODE 00 */
+ RP5C01_10_YEAR = 0xc, /* MODE 00 */
+
+ RP5C01_12_24_SELECT = 0xa, /* MODE 01 */
+ RP5C01_LEAP_YEAR = 0xb, /* MODE 01 */
+
+ RP5C01_MODE = 0xd, /* all modes */
+ RP5C01_TEST = 0xe, /* all modes */
+ RP5C01_RESET = 0xf, /* all modes */
+};
+
+#define RP5C01_12_24_SELECT_12 (0 << 0)
+#define RP5C01_12_24_SELECT_24 (1 << 0)
+
+#define RP5C01_10_HOUR_AM (0 << 1)
+#define RP5C01_10_HOUR_PM (1 << 1)
+
+#define RP5C01_MODE_TIMER_EN (1 << 3) /* timer enable */
+#define RP5C01_MODE_ALARM_EN (1 << 2) /* alarm enable */
+
+#define RP5C01_MODE_MODE_MASK (3 << 0)
+#define RP5C01_MODE_MODE00 (0 << 0) /* time */
+#define RP5C01_MODE_MODE01 (1 << 0) /* alarm, 12h/24h, leap year */
+#define RP5C01_MODE_RAM_BLOCK10 (2 << 0) /* RAM 4 bits x 13 */
+#define RP5C01_MODE_RAM_BLOCK11 (3 << 0) /* RAM 4 bits x 13 */
+
+#define RP5C01_RESET_1HZ_PULSE (1 << 3)
+#define RP5C01_RESET_16HZ_PULSE (1 << 2)
+#define RP5C01_RESET_SECOND (1 << 1) /* reset divider stages for */
+ /* seconds or smaller units */
+#define RP5C01_RESET_ALARM (1 << 0) /* reset all alarm registers */
+
+
+struct rp5c01_priv {
+ u32 __iomem *regs;
+ struct rtc_device *rtc;
+};
+
+static inline unsigned int rp5c01_read(struct rp5c01_priv *priv,
+ unsigned int reg)
+{
+ return __raw_readl(&priv->regs[reg]) & 0xf;
+}
+
+static inline void rp5c01_write(struct rp5c01_priv *priv, unsigned int val,
+ unsigned int reg)
+{
+ return __raw_writel(val, &priv->regs[reg]);
+}
+
+static void rp5c01_lock(struct rp5c01_priv *priv)
+{
+ rp5c01_write(priv, RP5C01_MODE_MODE00, RP5C01_MODE);
+}
+
+static void rp5c01_unlock(struct rp5c01_priv *priv)
+{
+ rp5c01_write(priv, RP5C01_MODE_TIMER_EN | RP5C01_MODE_MODE01,
+ RP5C01_MODE);
+}
+
+static int rp5c01_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rp5c01_priv *priv = dev_get_drvdata(dev);
+
+ rp5c01_lock(priv);
+
+ tm->tm_sec = rp5c01_read(priv, RP5C01_10_SECOND) * 10 +
+ rp5c01_read(priv, RP5C01_1_SECOND);
+ tm->tm_min = rp5c01_read(priv, RP5C01_10_MINUTE) * 10 +
+ rp5c01_read(priv, RP5C01_1_MINUTE);
+ tm->tm_hour = rp5c01_read(priv, RP5C01_10_HOUR) * 10 +
+ rp5c01_read(priv, RP5C01_1_HOUR);
+ tm->tm_mday = rp5c01_read(priv, RP5C01_10_DAY) * 10 +
+ rp5c01_read(priv, RP5C01_1_DAY);
+ tm->tm_wday = rp5c01_read(priv, RP5C01_DAY_OF_WEEK);
+ tm->tm_mon = rp5c01_read(priv, RP5C01_10_MONTH) * 10 +
+ rp5c01_read(priv, RP5C01_1_MONTH) - 1;
+ tm->tm_year = rp5c01_read(priv, RP5C01_10_YEAR) * 10 +
+ rp5c01_read(priv, RP5C01_1_YEAR);
+ if (tm->tm_year <= 69)
+ tm->tm_year += 100;
+
+ rp5c01_unlock(priv);
+
+ return rtc_valid_tm(tm);
+}
+
+static int rp5c01_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rp5c01_priv *priv = dev_get_drvdata(dev);
+
+ rp5c01_lock(priv);
+
+ rp5c01_write(priv, tm->tm_sec / 10, RP5C01_10_SECOND);
+ rp5c01_write(priv, tm->tm_sec % 10, RP5C01_1_SECOND);
+ rp5c01_write(priv, tm->tm_min / 10, RP5C01_10_MINUTE);
+ rp5c01_write(priv, tm->tm_min % 10, RP5C01_1_MINUTE);
+ rp5c01_write(priv, tm->tm_hour / 10, RP5C01_10_HOUR);
+ rp5c01_write(priv, tm->tm_hour % 10, RP5C01_1_HOUR);
+ rp5c01_write(priv, tm->tm_mday / 10, RP5C01_10_DAY);
+ rp5c01_write(priv, tm->tm_mday % 10, RP5C01_1_DAY);
+ if (tm->tm_wday != -1)
+ rp5c01_write(priv, tm->tm_wday, RP5C01_DAY_OF_WEEK);
+ rp5c01_write(priv, (tm->tm_mon + 1) / 10, RP5C01_10_MONTH);
+ rp5c01_write(priv, (tm->tm_mon + 1) % 10, RP5C01_1_MONTH);
+ if (tm->tm_year >= 100)
+ tm->tm_year -= 100;
+ rp5c01_write(priv, tm->tm_year / 10, RP5C01_10_YEAR);
+ rp5c01_write(priv, tm->tm_year % 10, RP5C01_1_YEAR);
+
+ rp5c01_unlock(priv);
+ return 0;
+}
+
+static const struct rtc_class_ops rp5c01_rtc_ops = {
+ .read_time = rp5c01_read_time,
+ .set_time = rp5c01_set_time,
+};
+
+static int __init rp5c01_rtc_probe(struct platform_device *dev)
+{
+ struct resource *res;
+ struct rp5c01_priv *priv;
+ struct rtc_device *rtc;
+ int error;
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->regs = ioremap(res->start, resource_size(res));
+ if (!priv->regs) {
+ error = -ENOMEM;
+ goto out_free_priv;
+ }
+
+ rtc = rtc_device_register("rtc-rp5c01", &dev->dev, &rp5c01_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ error = PTR_ERR(rtc);
+ goto out_unmap;
+ }
+
+ priv->rtc = rtc;
+ platform_set_drvdata(dev, priv);
+ return 0;
+
+out_unmap:
+ iounmap(priv->regs);
+out_free_priv:
+ kfree(priv);
+ return error;
+}
+
+static int __exit rp5c01_rtc_remove(struct platform_device *dev)
+{
+ struct rp5c01_priv *priv = platform_get_drvdata(dev);
+
+ rtc_device_unregister(priv->rtc);
+ iounmap(priv->regs);
+ kfree(priv);
+ return 0;
+}
+
+static struct platform_driver rp5c01_rtc_driver = {
+ .driver = {
+ .name = "rtc-rp5c01",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(rp5c01_rtc_remove),
+};
+
+static int __init rp5c01_rtc_init(void)
+{
+ return platform_driver_probe(&rp5c01_rtc_driver, rp5c01_rtc_probe);
+}
+
+static void __exit rp5c01_rtc_fini(void)
+{
+ platform_driver_unregister(&rp5c01_rtc_driver);
+}
+
+module_init(rp5c01_rtc_init);
+module_exit(rp5c01_rtc_fini);
+
+MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Ricoh RP5C01 RTC driver");
+MODULE_ALIAS("platform:rtc-rp5c01");
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
index 7d1547b0070e..d491eb265c38 100644
--- a/drivers/rtc/rtc-stk17ta8.c
+++ b/drivers/rtc/rtc-stk17ta8.c
@@ -286,7 +286,7 @@ static struct bin_attribute stk17ta8_nvram_attr = {
.write = stk17ta8_nvram_write,
};
-static int __init stk17ta8_rtc_probe(struct platform_device *pdev)
+static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev)
{
struct rtc_device *rtc;
struct resource *res;
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index aaccc8ecfa8f..4d9f2775bad6 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -24,7 +24,6 @@
#include <asm/ccwdev.h>
#include <asm/ebcdic.h>
#include <asm/idals.h>
-#include <asm/todclk.h>
#include <asm/itcw.h>
/* This is ugly... */
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index e8ff7b0c961d..316eb1256a99 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -12,7 +12,6 @@
#include <linux/timer.h>
#include <linux/slab.h>
#include <asm/idals.h>
-#include <asm/todclk.h>
#define PRINTK_HEADER "dasd_erp(3990): "
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 4e49b4a6c880..f64d0db881b4 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -24,7 +24,6 @@
#include <asm/ebcdic.h>
#include <asm/io.h>
#include <asm/s390_ext.h>
-#include <asm/todclk.h>
#include <asm/vtoc.h>
#include <asm/diag.h>
@@ -145,6 +144,15 @@ dasd_diag_erp(struct dasd_device *device)
mdsk_term_io(device);
rc = mdsk_init_io(device, device->block->bp_block, 0, NULL);
+ if (rc == 4) {
+ if (!(device->features & DASD_FEATURE_READONLY)) {
+ dev_warn(&device->cdev->dev,
+ "The access mode of a DIAG device changed"
+ " to read-only");
+ device->features |= DASD_FEATURE_READONLY;
+ }
+ rc = 0;
+ }
if (rc)
dev_warn(&device->cdev->dev, "DIAG ERP failed with "
"rc=%d\n", rc);
@@ -433,16 +441,20 @@ dasd_diag_check_device(struct dasd_device *device)
for (sb = 512; sb < bsize; sb = sb << 1)
block->s2b_shift++;
rc = mdsk_init_io(device, block->bp_block, 0, NULL);
- if (rc) {
+ if (rc && (rc != 4)) {
dev_warn(&device->cdev->dev, "DIAG initialization "
"failed with rc=%d\n", rc);
rc = -EIO;
} else {
+ if (rc == 4)
+ device->features |= DASD_FEATURE_READONLY;
dev_info(&device->cdev->dev,
- "New DASD with %ld byte/block, total size %ld KB\n",
+ "New DASD with %ld byte/block, total size %ld KB%s\n",
(unsigned long) block->bp_block,
(unsigned long) (block->blocks <<
- block->s2b_shift) >> 1);
+ block->s2b_shift) >> 1,
+ (rc == 4) ? ", read-only device" : "");
+ rc = 0;
}
out_label:
free_page((long) label);
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 417b97cd3f94..c2aa495e6b43 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -24,7 +24,6 @@
#include <asm/idals.h>
#include <asm/ebcdic.h>
#include <asm/io.h>
-#include <asm/todclk.h>
#include <asm/uaccess.h>
#include <asm/cio.h>
#include <asm/ccwdev.h>
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index f245377e8e27..d1a07e4c0e78 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -20,7 +20,6 @@
#include <asm/idals.h>
#include <asm/ebcdic.h>
#include <asm/io.h>
-#include <asm/todclk.h>
#include <asm/ccwdev.h>
#include "dasd_int.h"
diff --git a/drivers/s390/char/sclp_async.c b/drivers/s390/char/sclp_async.c
index a4f68e5b9c96..b44462a6c6d3 100644
--- a/drivers/s390/char/sclp_async.c
+++ b/drivers/s390/char/sclp_async.c
@@ -26,7 +26,6 @@ static struct sclp_async_sccb *sccb;
static int sclp_async_send_wait(char *message);
static struct ctl_table_header *callhome_sysctl_header;
static DEFINE_SPINLOCK(sclp_async_lock);
-static char nodename[64];
#define SCLP_NORMAL_WRITE 0x00
struct async_evbuf {
@@ -52,9 +51,10 @@ static struct sclp_register sclp_async_register = {
static int call_home_on_panic(struct notifier_block *self,
unsigned long event, void *data)
{
- strncat(data, nodename, strlen(nodename));
- sclp_async_send_wait(data);
- return NOTIFY_DONE;
+ strncat(data, init_utsname()->nodename,
+ sizeof(init_utsname()->nodename));
+ sclp_async_send_wait(data);
+ return NOTIFY_DONE;
}
static struct notifier_block call_home_panic_nb = {
@@ -68,15 +68,14 @@ static int proc_handler_callhome(struct ctl_table *ctl, int write,
{
unsigned long val;
int len, rc;
- char buf[2];
+ char buf[3];
- if (!*count | (*ppos && !write)) {
+ if (!*count || (*ppos && !write)) {
*count = 0;
return 0;
}
if (!write) {
- len = sprintf(buf, "%d\n", callhome_enabled);
- buf[len] = '\0';
+ len = snprintf(buf, sizeof(buf), "%d\n", callhome_enabled);
rc = copy_to_user(buffer, buf, sizeof(buf));
if (rc != 0)
return -EFAULT;
@@ -171,39 +170,29 @@ static int __init sclp_async_init(void)
rc = sclp_register(&sclp_async_register);
if (rc)
return rc;
- callhome_sysctl_header = register_sysctl_table(kern_dir_table);
- if (!callhome_sysctl_header) {
- rc = -ENOMEM;
- goto out_sclp;
- }
- if (!(sclp_async_register.sclp_receive_mask & EVTYP_ASYNC_MASK)) {
- rc = -EOPNOTSUPP;
+ rc = -EOPNOTSUPP;
+ if (!(sclp_async_register.sclp_receive_mask & EVTYP_ASYNC_MASK))
goto out_sclp;
- }
rc = -ENOMEM;
+ callhome_sysctl_header = register_sysctl_table(kern_dir_table);
+ if (!callhome_sysctl_header)
+ goto out_sclp;
request = kzalloc(sizeof(struct sclp_req), GFP_KERNEL);
- if (!request)
- goto out_sys;
sccb = (struct sclp_async_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if (!sccb)
+ if (!request || !sccb)
goto out_mem;
- rc = atomic_notifier_chain_register(&panic_notifier_list,
- &call_home_panic_nb);
- if (rc)
- goto out_mem;
-
- strncpy(nodename, init_utsname()->nodename, 64);
- return 0;
-
+ rc = atomic_notifier_chain_register(&panic_notifier_list,
+ &call_home_panic_nb);
+ if (!rc)
+ goto out;
out_mem:
kfree(request);
free_page((unsigned long) sccb);
-out_sys:
unregister_sysctl_table(callhome_sysctl_header);
out_sclp:
sclp_unregister(&sclp_async_register);
+out:
return rc;
-
}
module_init(sclp_async_init);
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c
index c5b83874500c..db054ed1a8cc 100644
--- a/drivers/s390/net/ctcm_main.c
+++ b/drivers/s390/net/ctcm_main.c
@@ -1530,11 +1530,16 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev)
struct net_device *dev;
struct ccw_device *cdev0;
struct ccw_device *cdev1;
+ struct channel *readc;
+ struct channel *writec;
int ret;
+ int result;
priv = dev_get_drvdata(&cgdev->dev);
- if (!priv)
- return -ENODEV;
+ if (!priv) {
+ result = -ENODEV;
+ goto out_err_result;
+ }
cdev0 = cgdev->cdev[0];
cdev1 = cgdev->cdev[1];
@@ -1545,31 +1550,40 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev)
snprintf(write_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev1->dev));
ret = add_channel(cdev0, type, priv);
- if (ret)
- return ret;
+ if (ret) {
+ result = ret;
+ goto out_err_result;
+ }
ret = add_channel(cdev1, type, priv);
- if (ret)
- return ret;
+ if (ret) {
+ result = ret;
+ goto out_remove_channel1;
+ }
ret = ccw_device_set_online(cdev0);
if (ret != 0) {
- /* may be ok to fail now - can be done later */
CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE,
"%s(%s) set_online rc=%d",
CTCM_FUNTAIL, read_id, ret);
+ result = -EIO;
+ goto out_remove_channel2;
}
ret = ccw_device_set_online(cdev1);
if (ret != 0) {
- /* may be ok to fail now - can be done later */
CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE,
"%s(%s) set_online rc=%d",
CTCM_FUNTAIL, write_id, ret);
+
+ result = -EIO;
+ goto out_ccw1;
}
dev = ctcm_init_netdevice(priv);
- if (dev == NULL)
- goto out;
+ if (dev == NULL) {
+ result = -ENODEV;
+ goto out_ccw2;
+ }
for (direction = READ; direction <= WRITE; direction++) {
priv->channel[direction] =
@@ -1587,12 +1601,14 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev)
/* sysfs magic */
SET_NETDEV_DEV(dev, &cgdev->dev);
- if (register_netdev(dev))
- goto out_dev;
+ if (register_netdev(dev)) {
+ result = -ENODEV;
+ goto out_dev;
+ }
if (ctcm_add_attributes(&cgdev->dev)) {
- unregister_netdev(dev);
- goto out_dev;
+ result = -ENODEV;
+ goto out_unregister;
}
strlcpy(priv->fsm->name, dev->name, sizeof(priv->fsm->name));
@@ -1608,13 +1624,22 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev)
priv->channel[WRITE]->id, priv->protocol);
return 0;
+out_unregister:
+ unregister_netdev(dev);
out_dev:
ctcm_free_netdevice(dev);
-out:
+out_ccw2:
ccw_device_set_offline(cgdev->cdev[1]);
+out_ccw1:
ccw_device_set_offline(cgdev->cdev[0]);
-
- return -ENODEV;
+out_remove_channel2:
+ readc = channel_get(type, read_id, READ);
+ channel_remove(readc);
+out_remove_channel1:
+ writec = channel_get(type, write_id, WRITE);
+ channel_remove(writec);
+out_err_result:
+ return result;
}
/**
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index a70de9b4bf29..5e46415d3e13 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -889,7 +889,7 @@ lcs_send_lancmd(struct lcs_card *card, struct lcs_buffer *buffer,
rc = lcs_ready_buffer(&card->write, buffer);
if (rc)
return rc;
- init_timer(&timer);
+ init_timer_on_stack(&timer);
timer.function = lcs_lancmd_timeout;
timer.data = (unsigned long) reply;
timer.expires = jiffies + HZ*card->lancmd_timeout;
@@ -2130,8 +2130,12 @@ lcs_new_device(struct ccwgroup_device *ccwgdev)
card->write.ccwdev = ccwgdev->cdev[1];
recover_state = card->state;
- ccw_device_set_online(card->read.ccwdev);
- ccw_device_set_online(card->write.ccwdev);
+ rc = ccw_device_set_online(card->read.ccwdev);
+ if (rc)
+ goto out_err;
+ rc = ccw_device_set_online(card->write.ccwdev);
+ if (rc)
+ goto out_werr;
LCS_DBF_TEXT(3, setup, "lcsnewdv");
@@ -2210,8 +2214,10 @@ netdev_out:
return 0;
out:
- ccw_device_set_offline(card->read.ccwdev);
ccw_device_set_offline(card->write.ccwdev);
+out_werr:
+ ccw_device_set_offline(card->read.ccwdev);
+out_err:
return -ENODEV;
}
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 31a2b4e502ce..e8f72d715eba 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -849,7 +849,7 @@ int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *,
struct sk_buff *, struct qeth_hdr *, int, int, int);
int qeth_do_send_packet(struct qeth_card *, struct qeth_qdio_out_q *,
struct sk_buff *, struct qeth_hdr *, int);
-int qeth_core_get_stats_count(struct net_device *);
+int qeth_core_get_sset_count(struct net_device *, int);
void qeth_core_get_ethtool_stats(struct net_device *,
struct ethtool_stats *, u64 *);
void qeth_core_get_strings(struct net_device *, u32, u8 *);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index c4a42d970158..edee4dc6430c 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -4305,11 +4305,16 @@ static struct {
{"tx csum"},
};
-int qeth_core_get_stats_count(struct net_device *dev)
+int qeth_core_get_sset_count(struct net_device *dev, int stringset)
{
- return (sizeof(qeth_ethtool_stats_keys) / ETH_GSTRING_LEN);
+ switch (stringset) {
+ case ETH_SS_STATS:
+ return (sizeof(qeth_ethtool_stats_keys) / ETH_GSTRING_LEN);
+ default:
+ return -EINVAL;
+ }
}
-EXPORT_SYMBOL_GPL(qeth_core_get_stats_count);
+EXPORT_SYMBOL_GPL(qeth_core_get_sset_count);
void qeth_core_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data)
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index f4f3ca1393b2..b61d5c723c50 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -866,7 +866,7 @@ static const struct ethtool_ops qeth_l2_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_strings = qeth_core_get_strings,
.get_ethtool_stats = qeth_core_get_ethtool_stats,
- .get_stats_count = qeth_core_get_stats_count,
+ .get_sset_count = qeth_core_get_sset_count,
.get_drvinfo = qeth_core_get_drvinfo,
.get_settings = qeth_core_ethtool_get_settings,
};
@@ -874,7 +874,7 @@ static const struct ethtool_ops qeth_l2_ethtool_ops = {
static const struct ethtool_ops qeth_l2_osn_ops = {
.get_strings = qeth_core_get_strings,
.get_ethtool_stats = qeth_core_get_ethtool_stats,
- .get_stats_count = qeth_core_get_stats_count,
+ .get_sset_count = qeth_core_get_sset_count,
.get_drvinfo = qeth_core_get_drvinfo,
};
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 073b6d354915..4ca28c16ca83 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -2957,7 +2957,7 @@ static const struct ethtool_ops qeth_l3_ethtool_ops = {
.set_tso = qeth_l3_ethtool_set_tso,
.get_strings = qeth_core_get_strings,
.get_ethtool_stats = qeth_core_get_ethtool_stats,
- .get_stats_count = qeth_core_get_stats_count,
+ .get_sset_count = qeth_core_get_sset_count,
.get_drvinfo = qeth_core_get_drvinfo,
.get_settings = qeth_core_ethtool_get_settings,
};
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c
index 102000d1af6f..3012355f8304 100644
--- a/drivers/s390/net/smsgiucv.c
+++ b/drivers/s390/net/smsgiucv.c
@@ -158,7 +158,12 @@ static int smsg_pm_restore_thaw(struct device *dev)
smsg_path->flags = 0;
rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ",
NULL, NULL, NULL);
- printk(KERN_ERR "iucv_path_connect returned with rc %i\n", rc);
+#ifdef CONFIG_PM_DEBUG
+ if (rc)
+ printk(KERN_ERR
+ "iucv_path_connect returned with rc %i\n", rc);
+#endif
+ cpcmd("SET SMSG IUCV", NULL, 0, NULL);
}
return 0;
}
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 0f79f3af4f54..2889e5f2dfd3 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -128,12 +128,13 @@ out_ccwdev:
static void __init zfcp_init_device_setup(char *devstr)
{
char *token;
- char *str;
+ char *str, *str_saved;
char busid[ZFCP_BUS_ID_SIZE];
u64 wwpn, lun;
/* duplicate devstr and keep the original for sysfs presentation*/
- str = kmalloc(strlen(devstr) + 1, GFP_KERNEL);
+ str_saved = kmalloc(strlen(devstr) + 1, GFP_KERNEL);
+ str = str_saved;
if (!str)
return;
@@ -152,12 +153,12 @@ static void __init zfcp_init_device_setup(char *devstr)
if (!token || strict_strtoull(token, 0, (unsigned long long *) &lun))
goto err_out;
- kfree(str);
+ kfree(str_saved);
zfcp_init_device_configure(busid, wwpn, lun);
return;
- err_out:
- kfree(str);
+err_out:
+ kfree(str_saved);
pr_err("%s is not a valid SCSI device\n", devstr);
}
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 73d366ba31e5..f73e2180f333 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -858,10 +858,7 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
return zfcp_erp_open_ptp_port(act);
if (!port->d_id) {
- zfcp_port_get(port);
- if (!queue_work(adapter->work_queue,
- &port->gid_pn_work))
- zfcp_port_put(port);
+ zfcp_fc_trigger_did_lookup(port);
return ZFCP_ERP_EXIT;
}
return zfcp_erp_port_strategy_open_port(act);
@@ -869,12 +866,11 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
case ZFCP_ERP_STEP_PORT_OPENING:
/* D_ID might have changed during open */
if (p_status & ZFCP_STATUS_COMMON_OPEN) {
- if (port->d_id)
- return ZFCP_ERP_SUCCEEDED;
- else {
- act->step = ZFCP_ERP_STEP_PORT_CLOSING;
- return ZFCP_ERP_CONTINUES;
+ if (!port->d_id) {
+ zfcp_fc_trigger_did_lookup(port);
+ return ZFCP_ERP_EXIT;
}
+ return ZFCP_ERP_SUCCEEDED;
}
if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) {
port->d_id = 0;
@@ -889,19 +885,21 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action)
{
struct zfcp_port *port = erp_action->port;
+ int p_status = atomic_read(&port->status);
- if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC)
+ if ((p_status & ZFCP_STATUS_COMMON_NOESC) &&
+ !(p_status & ZFCP_STATUS_COMMON_OPEN))
goto close_init_done;
switch (erp_action->step) {
case ZFCP_ERP_STEP_UNINITIALIZED:
zfcp_erp_port_strategy_clearstati(port);
- if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)
+ if (p_status & ZFCP_STATUS_COMMON_OPEN)
return zfcp_erp_port_strategy_close(erp_action);
break;
case ZFCP_ERP_STEP_PORT_CLOSING:
- if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)
+ if (p_status & ZFCP_STATUS_COMMON_OPEN)
return ZFCP_ERP_FAILED;
break;
}
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 629edec70405..b3f28deb4505 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -96,6 +96,7 @@ extern int zfcp_fc_scan_ports(struct zfcp_adapter *);
extern void _zfcp_fc_scan_ports_later(struct work_struct *);
extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *);
extern void zfcp_fc_port_did_lookup(struct work_struct *);
+extern void zfcp_fc_trigger_did_lookup(struct zfcp_port *);
extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *);
extern void zfcp_fc_test_link(struct zfcp_port *);
extern void zfcp_fc_link_test_work(struct work_struct *);
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index 722f22de8753..df23bcead23d 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -361,6 +361,17 @@ out:
}
/**
+ * zfcp_fc_trigger_did_lookup - trigger the d_id lookup using a GID_PN request
+ * @port: The zfcp_port to lookup the d_id for.
+ */
+void zfcp_fc_trigger_did_lookup(struct zfcp_port *port)
+{
+ zfcp_port_get(port);
+ if (!queue_work(port->adapter->work_queue, &port->gid_pn_work))
+ zfcp_port_put(port);
+}
+
+/**
* zfcp_fc_plogi_evaluate - evaluate PLOGI playload
* @port: zfcp_port structure
* @plogi: plogi payload
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 38a7e4a6b639..4e41baa0c141 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -1079,7 +1079,7 @@ static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req,
/* common settings for ct/gs and els requests */
req->qtcb->bottom.support.service_class = FSF_CLASS_3;
req->qtcb->bottom.support.timeout = 2 * R_A_TOV;
- zfcp_fsf_start_timer(req, 2 * R_A_TOV + 10);
+ zfcp_fsf_start_timer(req, (2 * R_A_TOV + 10) * HZ);
return 0;
}
@@ -1475,9 +1475,16 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els;
if (req->qtcb->bottom.support.els1_length >=
FSF_PLOGI_MIN_LEN) {
- if (plogi->serv_param.wwpn != port->wwpn)
+ if (plogi->serv_param.wwpn != port->wwpn) {
port->d_id = 0;
- else {
+ dev_warn(&port->adapter->ccw_device->dev,
+ "A port opened with WWPN 0x%016Lx "
+ "returned data that identifies it as "
+ "WWPN 0x%016Lx\n",
+ (unsigned long long) port->wwpn,
+ (unsigned long long)
+ plogi->serv_param.wwpn);
+ } else {
port->wwnn = plogi->serv_param.wwnn;
zfcp_fc_plogi_evaluate(port, plogi);
}
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c
index 079a8cf518a3..d31000886ca8 100644
--- a/drivers/s390/scsi/zfcp_sysfs.c
+++ b/drivers/s390/scsi/zfcp_sysfs.c
@@ -224,6 +224,7 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
zfcp_erp_unit_reopen(unit, 0, "syuas_1", NULL);
zfcp_erp_wait(unit->port->adapter);
+ flush_work(&unit->scsi_work);
zfcp_unit_put(unit);
out:
mutex_unlock(&zfcp_data.config_mutex);
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index 36c21b19e5d7..b59e240f2385 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -732,7 +732,7 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
break;
case TW_IOCTL_GET_COMPATIBILITY_INFO:
tw_ioctl->driver_command.status = 0;
- /* Copy compatiblity struct into ioctl data buffer */
+ /* Copy compatibility struct into ioctl data buffer */
tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer;
memcpy(tw_compat_info, &tw_dev->tw_compat_info, sizeof(TW_Compatibility_Info));
break;
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index faa0fcfed71e..a8289926ee35 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -8,7 +8,7 @@
Copyright (C) 1999-2009 3ware Inc.
- Kernel compatiblity By: Andre Hedrick <andre@suse.com>
+ Kernel compatibility By: Andre Hedrick <andre@suse.com>
Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com>
Further tiny build fixes and trivial hoovering Alan Cox
@@ -2321,7 +2321,7 @@ static int __devinit tw_probe(struct pci_dev *pdev, const struct pci_device_id *
host->max_cmd_len = TW_MAX_CDB_LEN;
/* Luns and channels aren't supported by adapter */
- host->max_lun = 0;
+ host->max_lun = 1;
host->max_channel = 0;
/* Register the card with the kernel SCSI layer */
diff --git a/drivers/scsi/aic7xxx/aic79xx.seq b/drivers/scsi/aic7xxx/aic79xx.seq
index 58bc17591b54..3b66b5ae3d9f 100644
--- a/drivers/scsi/aic7xxx/aic79xx.seq
+++ b/drivers/scsi/aic7xxx/aic79xx.seq
@@ -1281,7 +1281,7 @@ END_CRITICAL;
* Is it a disconnect message? Set a flag in the SCB to remind us
* and await the bus going free. If this is an untagged transaction
* store the SCB id for it in our untagged target table for lookup on
- * a reselction.
+ * a reselection.
*/
mesgin_disconnect:
/*
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 75b23317bd26..1222a7ac698a 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -2335,7 +2335,7 @@ ahd_linux_queue_abort_cmd(struct scsi_cmnd *cmd)
/*
* The sequencer will never re-reference the
* in-core SCB. To make sure we are notified
- * during reslection, set the MK_MESSAGE flag in
+ * during reselection, set the MK_MESSAGE flag in
* the card's copy of the SCB.
*/
ahd_outb(ahd, SCB_CONTROL,
diff --git a/drivers/scsi/aic7xxx/aic7xxx.seq b/drivers/scsi/aic7xxx/aic7xxx.seq
index 15196390e28d..5a4cfc954a9f 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.seq
+++ b/drivers/scsi/aic7xxx/aic7xxx.seq
@@ -1693,7 +1693,7 @@ if ((ahc->flags & AHC_INITIATORROLE) != 0) {
* Is it a disconnect message? Set a flag in the SCB to remind us
* and await the bus going free. If this is an untagged transaction
* store the SCB id for it in our untagged target table for lookup on
- * a reselction.
+ * a reselection.
*/
mesgin_disconnect:
/*
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index fd2b9785ff4f..8cb05dc8e6a1 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -2290,7 +2290,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
* In the non-paging case, the sequencer will
* never re-reference the in-core SCB.
* To make sure we are notified during
- * reslection, set the MK_MESSAGE flag in
+ * reselection, set the MK_MESSAGE flag in
* the card's copy of the SCB.
*/
if ((ahc->flags & AHC_PAGESCBS) == 0) {
diff --git a/drivers/scsi/bfa/bfa_cb_ioim_macros.h b/drivers/scsi/bfa/bfa_cb_ioim_macros.h
index 0050c838c358..961fe439daad 100644
--- a/drivers/scsi/bfa/bfa_cb_ioim_macros.h
+++ b/drivers/scsi/bfa/bfa_cb_ioim_macros.h
@@ -51,7 +51,7 @@ bfad_int_to_lun(u32 luno)
lun.bfa_lun = 0;
lun.scsi_lun[0] = bfa_os_htons(luno);
- return (lun.bfa_lun);
+ return lun.bfa_lun;
}
/**
@@ -68,7 +68,7 @@ bfa_cb_ioim_get_cdb(struct bfad_ioim_s *dio)
{
struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
- return ((u8 *) cmnd->cmnd);
+ return (u8 *) cmnd->cmnd;
}
/**
@@ -97,7 +97,7 @@ bfa_cb_ioim_get_size(struct bfad_ioim_s *dio)
{
struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
- return (scsi_bufflen(cmnd));
+ return scsi_bufflen(cmnd);
}
/**
@@ -129,7 +129,7 @@ bfa_cb_ioim_get_sgaddr(struct bfad_ioim_s *dio, int sgeid)
sge = (struct scatterlist *)scsi_sglist(cmnd) + sgeid;
addr = (u64) sg_dma_address(sge);
- return (*(union bfi_addr_u *) &addr);
+ return *((union bfi_addr_u *) &addr);
}
static inline u32
@@ -197,7 +197,7 @@ bfa_cb_ioim_get_cdblen(struct bfad_ioim_s *dio)
{
struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
- return (cmnd->cmd_len);
+ return cmnd->cmd_len;
}
diff --git a/drivers/scsi/bfa/bfa_cee.c b/drivers/scsi/bfa/bfa_cee.c
index 7a959c34e789..2b917792c6bc 100644
--- a/drivers/scsi/bfa/bfa_cee.c
+++ b/drivers/scsi/bfa/bfa_cee.c
@@ -228,7 +228,7 @@ bfa_cee_reset_stats_isr(struct bfa_cee_s *cee, bfa_status_t status)
u32
bfa_cee_meminfo(void)
{
- return (bfa_cee_attr_meminfo() + bfa_cee_stats_meminfo());
+ return bfa_cee_attr_meminfo() + bfa_cee_stats_meminfo();
}
/**
diff --git a/drivers/scsi/bfa/bfa_csdebug.c b/drivers/scsi/bfa/bfa_csdebug.c
index 1b71d349451a..caeb1143a4e6 100644
--- a/drivers/scsi/bfa/bfa_csdebug.c
+++ b/drivers/scsi/bfa/bfa_csdebug.c
@@ -47,12 +47,12 @@ bfa_q_is_on_q_func(struct list_head *q, struct list_head *qe)
tqe = bfa_q_next(q);
while (tqe != q) {
if (tqe == qe)
- return (1);
+ return 1;
tqe = bfa_q_next(tqe);
if (tqe == NULL)
break;
}
- return (0);
+ return 0;
}
diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c
index 401babe3494e..790c945aeae6 100644
--- a/drivers/scsi/bfa/bfa_fcpim.c
+++ b/drivers/scsi/bfa/bfa_fcpim.c
@@ -131,7 +131,7 @@ bfa_fcpim_path_tov_get(struct bfa_s *bfa)
{
struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
- return (fcpim->path_tov / 1000);
+ return fcpim->path_tov / 1000;
}
bfa_status_t
@@ -169,7 +169,7 @@ bfa_fcpim_qdepth_get(struct bfa_s *bfa)
{
struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
- return (fcpim->q_depth);
+ return fcpim->q_depth;
}
diff --git a/drivers/scsi/bfa/bfa_fcpim_priv.h b/drivers/scsi/bfa/bfa_fcpim_priv.h
index 153206cfb37a..5cf418460f75 100644
--- a/drivers/scsi/bfa/bfa_fcpim_priv.h
+++ b/drivers/scsi/bfa/bfa_fcpim_priv.h
@@ -35,7 +35,7 @@
#define BFA_FCPIM_PATHTOV_MAX (90 * 1000) /* in millisecs */
#define bfa_fcpim_stats(__fcpim, __stats) \
- (__fcpim)->stats.__stats ++
+ ((__fcpim)->stats.__stats++)
struct bfa_fcpim_mod_s {
struct bfa_s *bfa;
@@ -143,7 +143,7 @@ struct bfa_itnim_s {
struct bfa_itnim_hal_stats_s stats;
};
-#define bfa_itnim_is_online(_itnim) (_itnim)->is_online
+#define bfa_itnim_is_online(_itnim) ((_itnim)->is_online)
#define BFA_FCPIM_MOD(_hal) (&(_hal)->modules.fcpim_mod)
#define BFA_IOIM_FROM_TAG(_fcpim, _iotag) \
(&fcpim->ioim_arr[_iotag])
diff --git a/drivers/scsi/bfa/bfa_fcport.c b/drivers/scsi/bfa/bfa_fcport.c
index 992435987deb..aef648b55dfc 100644
--- a/drivers/scsi/bfa/bfa_fcport.c
+++ b/drivers/scsi/bfa/bfa_fcport.c
@@ -388,32 +388,29 @@ bfa_pport_sm_linkup(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
bfa_pport_callback(pport, BFA_PPORT_LINKDOWN);
bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkdown");
- if (BFA_PORT_IS_DISABLED(pport->bfa)) {
+ if (BFA_PORT_IS_DISABLED(pport->bfa))
bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
- } else {
+ else
bfa_pport_aen_post(pport, BFA_PORT_AEN_DISCONNECT);
- }
break;
case BFA_PPORT_SM_STOP:
bfa_sm_set_state(pport, bfa_pport_sm_stopped);
bfa_pport_reset_linkinfo(pport);
- if (BFA_PORT_IS_DISABLED(pport->bfa)) {
+ if (BFA_PORT_IS_DISABLED(pport->bfa))
bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
- } else {
+ else
bfa_pport_aen_post(pport, BFA_PORT_AEN_DISCONNECT);
- }
break;
case BFA_PPORT_SM_HWFAIL:
bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
bfa_pport_reset_linkinfo(pport);
bfa_pport_callback(pport, BFA_PPORT_LINKDOWN);
- if (BFA_PORT_IS_DISABLED(pport->bfa)) {
+ if (BFA_PORT_IS_DISABLED(pport->bfa))
bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
- } else {
+ else
bfa_pport_aen_post(pport, BFA_PORT_AEN_DISCONNECT);
- }
break;
default:
@@ -999,10 +996,10 @@ bfa_pport_enable(struct bfa_s *bfa)
struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
if (pport->diag_busy)
- return (BFA_STATUS_DIAG_BUSY);
+ return BFA_STATUS_DIAG_BUSY;
else if (bfa_sm_cmp_state
(BFA_PORT_MOD(bfa), bfa_pport_sm_disabling_qwait))
- return (BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_ENABLE);
return BFA_STATUS_OK;
@@ -1032,7 +1029,7 @@ bfa_pport_cfg_speed(struct bfa_s *bfa, enum bfa_pport_speed speed)
pport->cfg.speed = speed;
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
/**
@@ -1068,7 +1065,7 @@ bfa_pport_cfg_topology(struct bfa_s *bfa, enum bfa_pport_topology topology)
}
pport->cfg.topology = topology;
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
/**
@@ -1094,7 +1091,7 @@ bfa_pport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa)
pport->cfg.cfg_hardalpa = BFA_TRUE;
pport->cfg.hardalpa = alpa;
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
bfa_status_t
@@ -1106,7 +1103,7 @@ bfa_pport_clr_hardalpa(struct bfa_s *bfa)
bfa_trc(bfa, pport->cfg.hardalpa);
pport->cfg.cfg_hardalpa = BFA_FALSE;
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
bfa_boolean_t
@@ -1138,16 +1135,16 @@ bfa_pport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxfrsize)
* with in range
*/
if ((maxfrsize > FC_MAX_PDUSZ) || (maxfrsize < FC_MIN_PDUSZ))
- return (BFA_STATUS_INVLD_DFSZ);
+ return BFA_STATUS_INVLD_DFSZ;
/*
* power of 2, if not the max frame size of 2112
*/
if ((maxfrsize != FC_MAX_PDUSZ) && (maxfrsize & (maxfrsize - 1)))
- return (BFA_STATUS_INVLD_DFSZ);
+ return BFA_STATUS_INVLD_DFSZ;
pport->cfg.maxfrsize = maxfrsize;
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
u16
@@ -1415,7 +1412,7 @@ bfa_pport_get_stats(struct bfa_s *bfa, union bfa_pport_stats_u *stats,
if (port->stats_busy) {
bfa_trc(bfa, port->stats_busy);
- return (BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
}
port->stats_busy = BFA_TRUE;
@@ -1427,7 +1424,7 @@ bfa_pport_get_stats(struct bfa_s *bfa, union bfa_pport_stats_u *stats,
bfa_timer_start(bfa, &port->timer, bfa_port_stats_timeout, port,
BFA_PORT_STATS_TOV);
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
bfa_status_t
@@ -1437,7 +1434,7 @@ bfa_pport_clear_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
if (port->stats_busy) {
bfa_trc(bfa, port->stats_busy);
- return (BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
}
port->stats_busy = BFA_TRUE;
@@ -1448,7 +1445,7 @@ bfa_pport_clear_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
bfa_timer_start(bfa, &port->timer, bfa_port_stats_clr_timeout, port,
BFA_PORT_STATS_TOV);
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
bfa_status_t
@@ -1515,7 +1512,7 @@ bfa_pport_get_qos_stats(struct bfa_s *bfa, union bfa_pport_stats_u *stats,
/*
* QoS stats is embedded in port stats
*/
- return (bfa_pport_get_stats(bfa, stats, cbfn, cbarg));
+ return bfa_pport_get_stats(bfa, stats, cbfn, cbarg);
}
bfa_status_t
@@ -1525,7 +1522,7 @@ bfa_pport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
if (port->stats_busy) {
bfa_trc(bfa, port->stats_busy);
- return (BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
}
port->stats_busy = BFA_TRUE;
@@ -1536,7 +1533,7 @@ bfa_pport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
bfa_timer_start(bfa, &port->timer, bfa_port_stats_clr_timeout, port,
BFA_PORT_STATS_TOV);
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
/**
@@ -1545,7 +1542,7 @@ bfa_pport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
bfa_status_t
bfa_pport_trunk_disable(struct bfa_s *bfa)
{
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
bfa_boolean_t
@@ -1562,8 +1559,8 @@ bfa_pport_is_disabled(struct bfa_s *bfa)
{
struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
- return (bfa_sm_to_state(hal_pport_sm_table, port->sm) ==
- BFA_PPORT_ST_DISABLED);
+ return bfa_sm_to_state(hal_pport_sm_table, port->sm) ==
+ BFA_PPORT_ST_DISABLED;
}
@@ -1572,7 +1569,7 @@ bfa_pport_is_ratelim(struct bfa_s *bfa)
{
struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
-return (pport->cfg.ratelimit ? BFA_TRUE : BFA_FALSE);
+ return pport->cfg.ratelimit ? BFA_TRUE : BFA_FALSE;
}
@@ -1620,7 +1617,7 @@ bfa_pport_cfg_ratelim_speed(struct bfa_s *bfa, enum bfa_pport_speed speed)
pport->cfg.trl_def_speed = speed;
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
/**
@@ -1632,7 +1629,7 @@ bfa_pport_get_ratelim_speed(struct bfa_s *bfa)
struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
bfa_trc(bfa, pport->cfg.trl_def_speed);
- return (pport->cfg.trl_def_speed);
+ return pport->cfg.trl_def_speed;
}
diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c
index 8975ed041dc0..c7ab257f10a7 100644
--- a/drivers/scsi/bfa/bfa_fcs_lport.c
+++ b/drivers/scsi/bfa/bfa_fcs_lport.c
@@ -568,11 +568,10 @@ bfa_fcs_port_offline_actions(struct bfa_fcs_port_s *port)
__port_action[port->fabric->fab_type].offline(port);
- if (bfa_fcs_fabric_is_online(port->fabric) == BFA_TRUE) {
+ if (bfa_fcs_fabric_is_online(port->fabric) == BFA_TRUE)
bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DISCONNECT);
- } else {
+ else
bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_OFFLINE);
- }
bfa_fcb_port_offline(port->fcs->bfad, port->port_cfg.roles,
port->fabric->vf_drv,
(port->vport == NULL) ? NULL : port->vport->vport_drv);
@@ -777,7 +776,7 @@ bfa_fcs_port_get_rport_by_pwwn(struct bfa_fcs_port_s *port, wwn_t pwwn)
}
bfa_trc(port->fcs, pwwn);
- return (NULL);
+ return NULL;
}
/**
@@ -796,7 +795,7 @@ bfa_fcs_port_get_rport_by_nwwn(struct bfa_fcs_port_s *port, wwn_t nwwn)
}
bfa_trc(port->fcs, nwwn);
- return (NULL);
+ return NULL;
}
/**
@@ -870,7 +869,7 @@ bfa_fcs_port_lip(struct bfa_fcs_port_s *port)
bfa_boolean_t
bfa_fcs_port_is_online(struct bfa_fcs_port_s *port)
{
- return (bfa_sm_cmp_state(port, bfa_fcs_port_sm_online));
+ return bfa_sm_cmp_state(port, bfa_fcs_port_sm_online);
}
/**
diff --git a/drivers/scsi/bfa/bfa_fcxp.c b/drivers/scsi/bfa/bfa_fcxp.c
index 4754a0e9006a..cf0ad6782686 100644
--- a/drivers/scsi/bfa/bfa_fcxp.c
+++ b/drivers/scsi/bfa/bfa_fcxp.c
@@ -199,7 +199,7 @@ bfa_fcxp_get(struct bfa_fcxp_mod_s *fm)
if (fcxp)
list_add_tail(&fcxp->qe, &fm->fcxp_active_q);
- return (fcxp);
+ return fcxp;
}
static void
@@ -503,7 +503,7 @@ bfa_fcxp_alloc(void *caller, struct bfa_s *bfa, int nreq_sgles,
fcxp = bfa_fcxp_get(BFA_FCXP_MOD(bfa));
if (fcxp == NULL)
- return (NULL);
+ return NULL;
bfa_trc(bfa, fcxp->fcxp_tag);
@@ -568,7 +568,7 @@ bfa_fcxp_alloc(void *caller, struct bfa_s *bfa, int nreq_sgles,
}
}
- return (fcxp);
+ return fcxp;
}
/**
@@ -709,7 +709,7 @@ bfa_status_t
bfa_fcxp_abort(struct bfa_fcxp_s *fcxp)
{
bfa_assert(0);
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
void
diff --git a/drivers/scsi/bfa/bfa_intr.c b/drivers/scsi/bfa/bfa_intr.c
index 0ca125712a04..b36540e4ed76 100644
--- a/drivers/scsi/bfa/bfa_intr.c
+++ b/drivers/scsi/bfa/bfa_intr.c
@@ -59,7 +59,7 @@ bfa_intx(struct bfa_s *bfa)
qintr = intr & __HFN_INT_RME_MASK;
bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, qintr);
- for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue ++) {
+ for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue++) {
if (intr & (__HFN_INT_RME_Q0 << queue))
bfa_msix_rspq(bfa, queue & (BFI_IOC_MAX_CQS - 1));
}
diff --git a/drivers/scsi/bfa/bfa_intr_priv.h b/drivers/scsi/bfa/bfa_intr_priv.h
index 8ce6e6b105c8..5fc301cf4d1b 100644
--- a/drivers/scsi/bfa/bfa_intr_priv.h
+++ b/drivers/scsi/bfa/bfa_intr_priv.h
@@ -26,9 +26,9 @@ void bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m);
void bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func);
-#define bfa_reqq_pi(__bfa, __reqq) (__bfa)->iocfc.req_cq_pi[__reqq]
+#define bfa_reqq_pi(__bfa, __reqq) ((__bfa)->iocfc.req_cq_pi[__reqq])
#define bfa_reqq_ci(__bfa, __reqq) \
- *(u32 *)((__bfa)->iocfc.req_cq_shadow_ci[__reqq].kva)
+ (*(u32 *)((__bfa)->iocfc.req_cq_shadow_ci[__reqq].kva))
#define bfa_reqq_full(__bfa, __reqq) \
(((bfa_reqq_pi(__bfa, __reqq) + 1) & \
@@ -50,14 +50,16 @@ void bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func);
} while (0)
#define bfa_rspq_pi(__bfa, __rspq) \
- *(u32 *)((__bfa)->iocfc.rsp_cq_shadow_pi[__rspq].kva)
+ (*(u32 *)((__bfa)->iocfc.rsp_cq_shadow_pi[__rspq].kva))
-#define bfa_rspq_ci(__bfa, __rspq) (__bfa)->iocfc.rsp_cq_ci[__rspq]
+#define bfa_rspq_ci(__bfa, __rspq) ((__bfa)->iocfc.rsp_cq_ci[__rspq])
#define bfa_rspq_elem(__bfa, __rspq, __ci) \
- &((struct bfi_msg_s *)((__bfa)->iocfc.rsp_cq_ba[__rspq].kva))[__ci]
+ (&((struct bfi_msg_s *)((__bfa)->iocfc.rsp_cq_ba[__rspq].kva))[__ci])
-#define CQ_INCR(__index, __size) \
- (__index)++; (__index) &= ((__size) - 1)
+#define CQ_INCR(__index, __size) do { \
+ (__index)++; \
+ (__index) &= ((__size) - 1); \
+} while (0)
/**
* Queue element to wait for room in request queue. FIFO order is
@@ -94,7 +96,7 @@ bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg),
wqe->cbarg = cbarg;
}
-#define bfa_reqq(__bfa, __reqq) &(__bfa)->reqq_waitq[__reqq]
+#define bfa_reqq(__bfa, __reqq) (&(__bfa)->reqq_waitq[__reqq])
/**
* static inline void
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c
index 149348934ce3..397d7e9eade5 100644
--- a/drivers/scsi/bfa/bfa_ioc.c
+++ b/drivers/scsi/bfa/bfa_ioc.c
@@ -51,7 +51,7 @@ BFA_TRC_FILE(HAL, IOC);
(sizeof(struct bfa_trc_mod_s) - \
BFA_TRC_MAX * sizeof(struct bfa_trc_s)))
#define BFA_DBG_FWTRC_OFF(_fn) (BFI_IOC_TRC_OFF + BFA_DBG_FWTRC_LEN * (_fn))
-#define bfa_ioc_stats(_ioc, _stats) (_ioc)->stats._stats ++
+#define bfa_ioc_stats(_ioc, _stats) ((_ioc)->stats._stats++)
#define BFA_FLASH_CHUNK_NO(off) (off / BFI_FLASH_CHUNK_SZ_WORDS)
#define BFA_FLASH_OFFSET_IN_CHUNK(off) (off % BFI_FLASH_CHUNK_SZ_WORDS)
@@ -1953,8 +1953,8 @@ bfa_ioc_error_isr(struct bfa_ioc_s *ioc)
bfa_boolean_t
bfa_ioc_is_disabled(struct bfa_ioc_s *ioc)
{
- return (bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabling)
- || bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled));
+ return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabling)
+ || bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled);
}
/**
@@ -1963,9 +1963,9 @@ bfa_ioc_is_disabled(struct bfa_ioc_s *ioc)
bfa_boolean_t
bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc)
{
- return (bfa_fsm_cmp_state(ioc, bfa_ioc_sm_reset)
+ return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_reset)
|| bfa_fsm_cmp_state(ioc, bfa_ioc_sm_fwcheck)
- || bfa_fsm_cmp_state(ioc, bfa_ioc_sm_mismatch));
+ || bfa_fsm_cmp_state(ioc, bfa_ioc_sm_mismatch);
}
#define bfa_ioc_state_disabled(__sm) \
diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h
index 58efd4b13143..7c30f05ab137 100644
--- a/drivers/scsi/bfa/bfa_ioc.h
+++ b/drivers/scsi/bfa/bfa_ioc.h
@@ -179,16 +179,16 @@ struct bfa_ioc_s {
struct bfa_ioc_mbox_mod_s mbox_mod;
};
-#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_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
+ (((__stats)->drv_stats) = (__ioc)->stats)
#define bfa_ioc_clr_stats(__ioc) \
bfa_os_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_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)
diff --git a/drivers/scsi/bfa/bfa_iocfc.c b/drivers/scsi/bfa/bfa_iocfc.c
index 12350b022d63..d7ab792a9e54 100644
--- a/drivers/scsi/bfa/bfa_iocfc.c
+++ b/drivers/scsi/bfa/bfa_iocfc.c
@@ -794,7 +794,7 @@ bfa_iocfc_get_stats(struct bfa_s *bfa, struct bfa_iocfc_stats_s *stats,
if (iocfc->stats_busy) {
bfa_trc(bfa, iocfc->stats_busy);
- return (BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
}
iocfc->stats_busy = BFA_TRUE;
@@ -804,7 +804,7 @@ bfa_iocfc_get_stats(struct bfa_s *bfa, struct bfa_iocfc_stats_s *stats,
bfa_iocfc_stats_query(bfa);
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
bfa_status_t
@@ -814,7 +814,7 @@ bfa_iocfc_clear_stats(struct bfa_s *bfa, bfa_cb_ioc_t cbfn, void *cbarg)
if (iocfc->stats_busy) {
bfa_trc(bfa, iocfc->stats_busy);
- return (BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
}
iocfc->stats_busy = BFA_TRUE;
@@ -822,7 +822,7 @@ bfa_iocfc_clear_stats(struct bfa_s *bfa, bfa_cb_ioc_t cbfn, void *cbarg)
iocfc->stats_cbarg = cbarg;
bfa_iocfc_stats_clear(bfa);
- return (BFA_STATUS_OK);
+ return BFA_STATUS_OK;
}
/**
diff --git a/drivers/scsi/bfa/bfa_iocfc.h b/drivers/scsi/bfa/bfa_iocfc.h
index 7ad177ed4cfc..ce9a830a4207 100644
--- a/drivers/scsi/bfa/bfa_iocfc.h
+++ b/drivers/scsi/bfa/bfa_iocfc.h
@@ -107,13 +107,13 @@ struct bfa_iocfc_s {
#define bfa_lpuid(__bfa) bfa_ioc_portid(&(__bfa)->ioc)
#define bfa_msix_init(__bfa, __nvecs) \
- (__bfa)->iocfc.hwif.hw_msix_init(__bfa, __nvecs)
+ ((__bfa)->iocfc.hwif.hw_msix_init(__bfa, __nvecs))
#define bfa_msix_install(__bfa) \
- (__bfa)->iocfc.hwif.hw_msix_install(__bfa)
+ ((__bfa)->iocfc.hwif.hw_msix_install(__bfa))
#define bfa_msix_uninstall(__bfa) \
- (__bfa)->iocfc.hwif.hw_msix_uninstall(__bfa)
+ ((__bfa)->iocfc.hwif.hw_msix_uninstall(__bfa))
#define bfa_isr_mode_set(__bfa, __msix) \
- (__bfa)->iocfc.hwif.hw_isr_mode_set(__bfa, __msix)
+ ((__bfa)->iocfc.hwif.hw_isr_mode_set(__bfa, __msix))
#define bfa_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec) \
(__bfa)->iocfc.hwif.hw_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec)
diff --git a/drivers/scsi/bfa/bfa_ioim.c b/drivers/scsi/bfa/bfa_ioim.c
index 7ae2552e1e14..f81d359b7089 100644
--- a/drivers/scsi/bfa/bfa_ioim.c
+++ b/drivers/scsi/bfa/bfa_ioim.c
@@ -105,13 +105,13 @@ bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
list_del(&ioim->qe);
list_add_tail(&ioim->qe,
- &ioim->fcpim->ioim_comp_q);
+ &ioim->fcpim->ioim_comp_q);
bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
__bfa_cb_ioim_pathtov, ioim);
} else {
list_del(&ioim->qe);
list_add_tail(&ioim->qe,
- &ioim->itnim->pending_q);
+ &ioim->itnim->pending_q);
}
break;
}
diff --git a/drivers/scsi/bfa/bfa_itnim.c b/drivers/scsi/bfa/bfa_itnim.c
index 4d5c61a4f85c..eabf7d38bd09 100644
--- a/drivers/scsi/bfa/bfa_itnim.c
+++ b/drivers/scsi/bfa/bfa_itnim.c
@@ -1029,7 +1029,7 @@ bfa_itnim_create(struct bfa_s *bfa, struct bfa_rport_s *rport, void *ditn)
bfa_stats(itnim, creates);
bfa_sm_send_event(itnim, BFA_ITNIM_SM_CREATE);
- return (itnim);
+ return itnim;
}
void
@@ -1061,7 +1061,7 @@ bfa_itnim_offline(struct bfa_itnim_s *itnim)
bfa_boolean_t
bfa_itnim_hold_io(struct bfa_itnim_s *itnim)
{
- return (
+ return
itnim->fcpim->path_tov && itnim->iotov_active &&
(bfa_sm_cmp_state(itnim, bfa_itnim_sm_fwcreate) ||
bfa_sm_cmp_state(itnim, bfa_itnim_sm_sler) ||
@@ -1069,7 +1069,7 @@ bfa_itnim_hold_io(struct bfa_itnim_s *itnim)
bfa_sm_cmp_state(itnim, bfa_itnim_sm_fwdelete) ||
bfa_sm_cmp_state(itnim, bfa_itnim_sm_offline) ||
bfa_sm_cmp_state(itnim, bfa_itnim_sm_iocdisable))
-);
+ ;
}
void
diff --git a/drivers/scsi/bfa/bfa_log.c b/drivers/scsi/bfa/bfa_log.c
index c2735e55cf03..e7514016c9c6 100644
--- a/drivers/scsi/bfa/bfa_log.c
+++ b/drivers/scsi/bfa/bfa_log.c
@@ -231,9 +231,9 @@ bfa_log_get_level(struct bfa_log_mod_s *log_mod, int mod_id)
return BFA_LOG_INVALID;
if (log_mod)
- return (log_mod->log_level[mod_id]);
+ return log_mod->log_level[mod_id];
else
- return (bfa_log_info[mod_id].level);
+ return bfa_log_info[mod_id].level;
}
enum bfa_log_severity
diff --git a/drivers/scsi/bfa/bfa_port_priv.h b/drivers/scsi/bfa/bfa_port_priv.h
index 4b97e2759908..51f698a06b6d 100644
--- a/drivers/scsi/bfa/bfa_port_priv.h
+++ b/drivers/scsi/bfa/bfa_port_priv.h
@@ -59,8 +59,8 @@ struct bfa_pport_s {
u8 *stats_kva;
u64 stats_pa;
union bfa_pport_stats_u *stats; /* pport stats */
- u32 mypid : 24;
- u32 rsvd_b : 8;
+ u32 mypid:24;
+ u32 rsvd_b:8;
struct bfa_timer_s timer; /* timer */
union bfa_pport_stats_u *stats_ret;
/* driver stats location */
diff --git a/drivers/scsi/bfa/bfa_rport.c b/drivers/scsi/bfa/bfa_rport.c
index 16da77a8db28..3e1990a74258 100644
--- a/drivers/scsi/bfa/bfa_rport.c
+++ b/drivers/scsi/bfa/bfa_rport.c
@@ -677,7 +677,7 @@ bfa_rport_alloc(struct bfa_rport_mod_s *mod)
if (rport)
list_add_tail(&rport->qe, &mod->rp_active_q);
- return (rport);
+ return rport;
}
static void
@@ -834,7 +834,7 @@ bfa_rport_create(struct bfa_s *bfa, void *rport_drv)
rp = bfa_rport_alloc(BFA_RPORT_MOD(bfa));
if (rp == NULL)
- return (NULL);
+ return NULL;
rp->bfa = bfa;
rp->rport_drv = rport_drv;
@@ -843,7 +843,7 @@ bfa_rport_create(struct bfa_s *bfa, void *rport_drv)
bfa_assert(bfa_sm_cmp_state(rp, bfa_rport_sm_uninit));
bfa_sm_send_event(rp, BFA_RPORT_SM_CREATE);
- return (rp);
+ return rp;
}
void
diff --git a/drivers/scsi/bfa/bfa_tskim.c b/drivers/scsi/bfa/bfa_tskim.c
index 010d40d1e5d3..ff7a4dc0bf3c 100644
--- a/drivers/scsi/bfa/bfa_tskim.c
+++ b/drivers/scsi/bfa/bfa_tskim.c
@@ -23,13 +23,14 @@ BFA_TRC_FILE(HAL, TSKIM);
/**
* task management completion handling
*/
-#define bfa_tskim_qcomp(__tskim, __cbfn) do { \
- bfa_cb_queue((__tskim)->bfa, &(__tskim)->hcb_qe, __cbfn, (__tskim)); \
+#define bfa_tskim_qcomp(__tskim, __cbfn) do { \
+ bfa_cb_queue((__tskim)->bfa, &(__tskim)->hcb_qe, \
+ __cbfn, (__tskim)); \
bfa_tskim_notify_comp(__tskim); \
} while (0)
-#define bfa_tskim_notify_comp(__tskim) do { \
- if ((__tskim)->notify) \
+#define bfa_tskim_notify_comp(__tskim) do { \
+ if ((__tskim)->notify) \
bfa_itnim_tskdone((__tskim)->itnim); \
} while (0)
diff --git a/drivers/scsi/bfa/bfa_uf.c b/drivers/scsi/bfa/bfa_uf.c
index ff5f9deb1b22..4b3c2417d180 100644
--- a/drivers/scsi/bfa/bfa_uf.c
+++ b/drivers/scsi/bfa/bfa_uf.c
@@ -185,7 +185,7 @@ bfa_uf_get(struct bfa_uf_mod_s *uf_mod)
struct bfa_uf_s *uf;
bfa_q_deq(&uf_mod->uf_free_q, &uf);
- return (uf);
+ return uf;
}
static void
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
index 6f2be5abf561..b52b773d49d9 100644
--- a/drivers/scsi/bfa/bfad.c
+++ b/drivers/scsi/bfa/bfad.c
@@ -188,8 +188,8 @@ static struct bfad_port_s *
bfad_get_drv_port(struct bfad_s *bfad, struct bfad_vf_s *vf_drv,
struct bfad_vport_s *vp_drv)
{
- return ((vp_drv) ? (&(vp_drv)->drv_port)
- : ((vf_drv) ? (&(vf_drv)->base_port) : (&(bfad)->pport)));
+ return (vp_drv) ? (&(vp_drv)->drv_port)
+ : ((vf_drv) ? (&(vf_drv)->base_port) : (&(bfad)->pport));
}
struct bfad_port_s *
@@ -716,7 +716,7 @@ bfad_drv_init(struct bfad_s *bfad)
if ((bfad->bfad_flags & BFAD_MSIX_ON)
&& bfad_install_msix_handler(bfad)) {
printk(KERN_WARNING "%s: install_msix failed, bfad%d\n",
- __FUNCTION__, bfad->inst_no);
+ __func__, bfad->inst_no);
}
bfad_init_timer(bfad);
diff --git a/drivers/scsi/bfa/bfad_fwimg.c b/drivers/scsi/bfa/bfad_fwimg.c
index b2f6949bc8d3..2c2082d6ce45 100644
--- a/drivers/scsi/bfa/bfad_fwimg.c
+++ b/drivers/scsi/bfa/bfad_fwimg.c
@@ -63,10 +63,10 @@ bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
memcpy(*bfi_image, fw->data, fw->size);
*bfi_image_size = fw->size/sizeof(u32);
- return(*bfi_image);
+ return *bfi_image;
error:
- return(NULL);
+ return NULL;
}
u32 *
@@ -76,12 +76,12 @@ bfad_get_firmware_buf(struct pci_dev *pdev)
if (bfi_image_ct_size == 0)
bfad_read_firmware(pdev, &bfi_image_ct,
&bfi_image_ct_size, BFAD_FW_FILE_CT);
- return(bfi_image_ct);
+ return bfi_image_ct;
} else {
if (bfi_image_cb_size == 0)
bfad_read_firmware(pdev, &bfi_image_cb,
&bfi_image_cb_size, BFAD_FW_FILE_CB);
- return(bfi_image_cb);
+ return bfi_image_cb;
}
}
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c
index 158c99243c08..ae3a0689a66f 100644
--- a/drivers/scsi/bfa/bfad_im.c
+++ b/drivers/scsi/bfa/bfad_im.c
@@ -1050,7 +1050,7 @@ bfad_im_itnim_work_handler(struct work_struct *work)
} else {
printk(KERN_WARNING
"%s: itnim %llx is already in online state\n",
- __FUNCTION__,
+ __func__,
bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim));
}
diff --git a/drivers/scsi/bfa/bfad_im_compat.h b/drivers/scsi/bfa/bfad_im_compat.h
index 1d3e74ec338c..b36be15044a4 100644
--- a/drivers/scsi/bfa/bfad_im_compat.h
+++ b/drivers/scsi/bfa/bfad_im_compat.h
@@ -31,7 +31,7 @@ u32 *bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
static inline u32 *
bfad_load_fwimg(struct pci_dev *pdev)
{
- return(bfad_get_firmware_buf(pdev));
+ return bfad_get_firmware_buf(pdev);
}
static inline void
diff --git a/drivers/scsi/bfa/bfad_intr.c b/drivers/scsi/bfa/bfad_intr.c
index f104e029cac9..7de8832f6fee 100644
--- a/drivers/scsi/bfa/bfad_intr.c
+++ b/drivers/scsi/bfa/bfad_intr.c
@@ -23,13 +23,12 @@ BFA_TRC_FILE(LDRV, INTR);
/**
* bfa_isr BFA driver interrupt functions
*/
-irqreturn_t bfad_intx(int irq, void *dev_id);
static int msix_disable;
module_param(msix_disable, int, S_IRUGO | S_IWUSR);
/**
* Line based interrupt handler.
*/
-irqreturn_t
+static irqreturn_t
bfad_intx(int irq, void *dev_id)
{
struct bfad_s *bfad = dev_id;
diff --git a/drivers/scsi/bfa/fabric.c b/drivers/scsi/bfa/fabric.c
index a8b14c47b009..a4b5dd449573 100644
--- a/drivers/scsi/bfa/fabric.c
+++ b/drivers/scsi/bfa/fabric.c
@@ -36,12 +36,12 @@ BFA_TRC_FILE(FCS, FABRIC);
#define BFA_FCS_FABRIC_RETRY_DELAY (2000) /* Milliseconds */
#define BFA_FCS_FABRIC_CLEANUP_DELAY (10000) /* Milliseconds */
-#define bfa_fcs_fabric_set_opertype(__fabric) do { \
- if (bfa_pport_get_topology((__fabric)->fcs->bfa) \
- == BFA_PPORT_TOPOLOGY_P2P) \
- (__fabric)->oper_type = BFA_PPORT_TYPE_NPORT; \
- else \
- (__fabric)->oper_type = BFA_PPORT_TYPE_NLPORT; \
+#define bfa_fcs_fabric_set_opertype(__fabric) do { \
+ if (bfa_pport_get_topology((__fabric)->fcs->bfa) \
+ == BFA_PPORT_TOPOLOGY_P2P) \
+ (__fabric)->oper_type = BFA_PPORT_TYPE_NPORT; \
+ else \
+ (__fabric)->oper_type = BFA_PPORT_TYPE_NLPORT; \
} while (0)
/*
@@ -887,7 +887,7 @@ bfa_fcs_fabric_modsusp(struct bfa_fcs_s *fcs)
bfa_boolean_t
bfa_fcs_fabric_is_loopback(struct bfa_fcs_fabric_s *fabric)
{
- return (bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_loopback));
+ return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_loopback);
}
enum bfa_pport_type
@@ -974,7 +974,7 @@ bfa_fcs_fabric_port_delete_comp(struct bfa_fcs_fabric_s *fabric)
int
bfa_fcs_fabric_is_online(struct bfa_fcs_fabric_s *fabric)
{
- return (bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_online));
+ return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_online);
}
@@ -1015,7 +1015,7 @@ bfa_fcs_fabric_vport_lookup(struct bfa_fcs_fabric_s *fabric, wwn_t pwwn)
u16
bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric)
{
- return (fabric->num_vports);
+ return fabric->num_vports;
}
/**
diff --git a/drivers/scsi/bfa/fcbuild.c b/drivers/scsi/bfa/fcbuild.c
index d174706b9caa..fee5456451cb 100644
--- a/drivers/scsi/bfa/fcbuild.c
+++ b/drivers/scsi/bfa/fcbuild.c
@@ -188,14 +188,14 @@ fc_els_rsp_parse(struct fchs_s *fchs, int len)
switch (els_cmd->els_code) {
case FC_ELS_LS_RJT:
if (ls_rjt->reason_code == FC_LS_RJT_RSN_LOGICAL_BUSY)
- return (FC_PARSE_BUSY);
+ return FC_PARSE_BUSY;
else
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
case FC_ELS_ACC:
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
}
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
}
static void
@@ -228,7 +228,7 @@ fc_plogi_x_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
bfa_os_memcpy(&plogi->port_name, &port_name, sizeof(wwn_t));
bfa_os_memcpy(&plogi->node_name, &node_name, sizeof(wwn_t));
- return (sizeof(struct fc_logi_s));
+ return sizeof(struct fc_logi_s);
}
u16
@@ -267,7 +267,7 @@ fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
flogi->csp.npiv_supp = 1; /* @todo. field name is not correct */
vvl_info[0] = bfa_os_htonl(FLOGI_VVL_BRCD);
- return (sizeof(struct fc_logi_s));
+ return sizeof(struct fc_logi_s);
}
u16
@@ -287,7 +287,7 @@ fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
flogi->csp.bbcred = bfa_os_htons(local_bb_credits);
- return (sizeof(struct fc_logi_s));
+ return sizeof(struct fc_logi_s);
}
u16
@@ -306,7 +306,7 @@ fc_fdisc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
flogi->port_name = port_name;
flogi->node_name = node_name;
- return (sizeof(struct fc_logi_s));
+ return sizeof(struct fc_logi_s);
}
u16
@@ -338,26 +338,26 @@ fc_plogi_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name)
case FC_ELS_LS_RJT:
ls_rjt = (struct fc_ls_rjt_s *) (fchs + 1);
if (ls_rjt->reason_code == FC_LS_RJT_RSN_LOGICAL_BUSY)
- return (FC_PARSE_BUSY);
+ return FC_PARSE_BUSY;
else
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
case FC_ELS_ACC:
plogi = (struct fc_logi_s *) (fchs + 1);
if (len < sizeof(struct fc_logi_s))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (!wwn_is_equal(plogi->port_name, port_name))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (!plogi->class3.class_valid)
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (bfa_os_ntohs(plogi->class3.rxsz) < (FC_MIN_PDUSZ))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
default:
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
}
}
@@ -372,7 +372,7 @@ fc_plogi_parse(struct fchs_s *fchs)
if ((bfa_os_ntohs(plogi->class3.rxsz) < FC_MIN_PDUSZ)
|| (bfa_os_ntohs(plogi->class3.rxsz) > FC_MAX_PDUSZ)
|| (plogi->class3.rxsz == 0))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
return FC_PARSE_OK;
}
@@ -393,7 +393,7 @@ fc_prli_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
prli->parampage.servparams.task_retry_id = 0;
prli->parampage.servparams.confirm = 1;
- return (sizeof(struct fc_prli_s));
+ return sizeof(struct fc_prli_s);
}
u16
@@ -414,41 +414,41 @@ fc_prli_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
prli->parampage.rspcode = FC_PRLI_ACC_XQTD;
- return (sizeof(struct fc_prli_s));
+ return sizeof(struct fc_prli_s);
}
enum fc_parse_status
fc_prli_rsp_parse(struct fc_prli_s *prli, int len)
{
if (len < sizeof(struct fc_prli_s))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (prli->command != FC_ELS_ACC)
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if ((prli->parampage.rspcode != FC_PRLI_ACC_XQTD)
&& (prli->parampage.rspcode != FC_PRLI_ACC_PREDEF_IMG))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (prli->parampage.servparams.target != 1)
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
}
enum fc_parse_status
fc_prli_parse(struct fc_prli_s *prli)
{
if (prli->parampage.type != FC_TYPE_FCP)
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (!prli->parampage.imagepair)
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (!prli->parampage.servparams.initiator)
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
}
u16
@@ -462,7 +462,7 @@ fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo, u32 d_id,
logo->nport_id = (s_id);
logo->orig_port_name = port_name;
- return (sizeof(struct fc_logo_s));
+ return sizeof(struct fc_logo_s);
}
static u16
@@ -484,7 +484,7 @@ fc_adisc_x_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id,
adisc->orig_node_name = node_name;
adisc->nport_id = (s_id);
- return (sizeof(struct fc_adisc_s));
+ return sizeof(struct fc_adisc_s);
}
u16
@@ -511,15 +511,15 @@ fc_adisc_rsp_parse(struct fc_adisc_s *adisc, int len, wwn_t port_name,
{
if (len < sizeof(struct fc_adisc_s))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (adisc->els_cmd.els_code != FC_ELS_ACC)
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (!wwn_is_equal(adisc->orig_port_name, port_name))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
}
enum fc_parse_status
@@ -529,14 +529,14 @@ fc_adisc_parse(struct fchs_s *fchs, void *pld, u32 host_dap,
struct fc_adisc_s *adisc = (struct fc_adisc_s *) pld;
if (adisc->els_cmd.els_code != FC_ELS_ACC)
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if ((adisc->nport_id == (host_dap))
&& wwn_is_equal(adisc->orig_port_name, port_name)
&& wwn_is_equal(adisc->orig_node_name, node_name))
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
}
enum fc_parse_status
@@ -550,13 +550,13 @@ fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name, wwn_t port_name)
if ((bfa_os_ntohs(pdisc->class3.rxsz) <
(FC_MIN_PDUSZ - sizeof(struct fchs_s)))
|| (pdisc->class3.rxsz == 0))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (!wwn_is_equal(pdisc->port_name, port_name))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
if (!wwn_is_equal(pdisc->node_name, node_name))
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
return FC_PARSE_OK;
}
@@ -570,7 +570,7 @@ fc_abts_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id)
fchs->s_id = (s_id);
fchs->ox_id = bfa_os_htons(ox_id);
- return (sizeof(struct fchs_s));
+ return sizeof(struct fchs_s);
}
enum fc_parse_status
@@ -578,9 +578,9 @@ fc_abts_rsp_parse(struct fchs_s *fchs, int len)
{
if ((fchs->cat_info == FC_CAT_BA_ACC)
|| (fchs->cat_info == FC_CAT_BA_RJT))
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
}
u16
@@ -597,7 +597,7 @@ fc_rrq_build(struct fchs_s *fchs, struct fc_rrq_s *rrq, u32 d_id,
rrq->ox_id = bfa_os_htons(rrq_oxid);
rrq->rx_id = FC_RXID_ANY;
- return (sizeof(struct fc_rrq_s));
+ return sizeof(struct fc_rrq_s);
}
u16
@@ -611,7 +611,7 @@ fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
memset(acc, 0, sizeof(struct fc_els_cmd_s));
acc->els_code = FC_ELS_ACC;
- return (sizeof(struct fc_els_cmd_s));
+ return sizeof(struct fc_els_cmd_s);
}
u16
@@ -627,7 +627,7 @@ fc_ls_rjt_build(struct fchs_s *fchs, struct fc_ls_rjt_s *ls_rjt, u32 d_id,
ls_rjt->reason_code_expl = reason_code_expl;
ls_rjt->vendor_unique = 0x00;
- return (sizeof(struct fc_ls_rjt_s));
+ return sizeof(struct fc_ls_rjt_s);
}
u16
@@ -643,7 +643,7 @@ fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc, u32 d_id,
ba_acc->ox_id = fchs->ox_id;
ba_acc->rx_id = fchs->rx_id;
- return (sizeof(struct fc_ba_acc_s));
+ return sizeof(struct fc_ba_acc_s);
}
u16
@@ -654,7 +654,7 @@ fc_ls_acc_build(struct fchs_s *fchs, struct fc_els_cmd_s *els_cmd,
memset(els_cmd, 0, sizeof(struct fc_els_cmd_s));
els_cmd->els_code = FC_ELS_ACC;
- return (sizeof(struct fc_els_cmd_s));
+ return sizeof(struct fc_els_cmd_s);
}
int
@@ -696,7 +696,7 @@ fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc,
tprlo_acc->tprlo_acc_params[page].orig_process_assc = 0;
tprlo_acc->tprlo_acc_params[page].resp_process_assc = 0;
}
- return (bfa_os_ntohs(tprlo_acc->payload_len));
+ return bfa_os_ntohs(tprlo_acc->payload_len);
}
u16
@@ -721,7 +721,7 @@ fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc,
prlo_acc->prlo_acc_params[page].resp_process_assc = 0;
}
- return (bfa_os_ntohs(prlo_acc->payload_len));
+ return bfa_os_ntohs(prlo_acc->payload_len);
}
u16
@@ -735,7 +735,7 @@ fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid, u32 d_id,
rnid->els_cmd.els_code = FC_ELS_RNID;
rnid->node_id_data_format = data_format;
- return (sizeof(struct fc_rnid_cmd_s));
+ return sizeof(struct fc_rnid_cmd_s);
}
u16
@@ -759,10 +759,10 @@ fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc,
rnid_acc->specific_id_data_length =
sizeof(struct fc_rnid_general_topology_data_s);
bfa_os_assign(rnid_acc->gen_topology_data, *gen_topo_data);
- return (sizeof(struct fc_rnid_acc_s));
+ return sizeof(struct fc_rnid_acc_s);
} else {
- return (sizeof(struct fc_rnid_acc_s) -
- sizeof(struct fc_rnid_general_topology_data_s));
+ return sizeof(struct fc_rnid_acc_s) -
+ sizeof(struct fc_rnid_general_topology_data_s);
}
}
@@ -776,7 +776,7 @@ fc_rpsc_build(struct fchs_s *fchs, struct fc_rpsc_cmd_s *rpsc, u32 d_id,
memset(rpsc, 0, sizeof(struct fc_rpsc_cmd_s));
rpsc->els_cmd.els_code = FC_ELS_RPSC;
- return (sizeof(struct fc_rpsc_cmd_s));
+ return sizeof(struct fc_rpsc_cmd_s);
}
u16
@@ -797,8 +797,8 @@ fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rpsc2,
for (i = 0; i < npids; i++)
rpsc2->pid_list[i].pid = pid_list[i];
- return (sizeof(struct fc_rpsc2_cmd_s) + ((npids - 1) *
- (sizeof(u32))));
+ return sizeof(struct fc_rpsc2_cmd_s) + ((npids - 1) *
+ (sizeof(u32)));
}
u16
@@ -819,7 +819,7 @@ fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc,
rpsc_acc->speed_info[0].port_op_speed =
bfa_os_htons(oper_speed->port_op_speed);
- return (sizeof(struct fc_rpsc_acc_s));
+ return sizeof(struct fc_rpsc_acc_s);
}
@@ -856,7 +856,7 @@ fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
pdisc->port_name = port_name;
pdisc->node_name = node_name;
- return (sizeof(struct fc_logi_s));
+ return sizeof(struct fc_logi_s);
}
u16
@@ -865,21 +865,21 @@ fc_pdisc_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name)
struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1);
if (len < sizeof(struct fc_logi_s))
- return (FC_PARSE_LEN_INVAL);
+ return FC_PARSE_LEN_INVAL;
if (pdisc->els_cmd.els_code != FC_ELS_ACC)
- return (FC_PARSE_ACC_INVAL);
+ return FC_PARSE_ACC_INVAL;
if (!wwn_is_equal(pdisc->port_name, port_name))
- return (FC_PARSE_PWWN_NOT_EQUAL);
+ return FC_PARSE_PWWN_NOT_EQUAL;
if (!pdisc->class3.class_valid)
- return (FC_PARSE_NWWN_NOT_EQUAL);
+ return FC_PARSE_NWWN_NOT_EQUAL;
if (bfa_os_ntohs(pdisc->class3.rxsz) < (FC_MIN_PDUSZ))
- return (FC_PARSE_RXSZ_INVAL);
+ return FC_PARSE_RXSZ_INVAL;
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
}
u16
@@ -903,7 +903,7 @@ fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
prlo->prlo_params[page].resp_process_assc = 0;
}
- return (bfa_os_ntohs(prlo->payload_len));
+ return bfa_os_ntohs(prlo->payload_len);
}
u16
@@ -916,7 +916,7 @@ fc_prlo_rsp_parse(struct fchs_s *fchs, int len)
len = len;
if (prlo->command != FC_ELS_ACC)
- return (FC_PARSE_FAILURE);
+ return FC_PARSE_FAILURE;
num_pages = ((bfa_os_ntohs(prlo->payload_len)) - 4) / 16;
@@ -936,7 +936,7 @@ fc_prlo_rsp_parse(struct fchs_s *fchs, int len)
if (prlo->prlo_acc_params[page].resp_process_assc != 0)
return FC_PARSE_FAILURE;
}
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
}
@@ -968,7 +968,7 @@ fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
}
}
- return (bfa_os_ntohs(tprlo->payload_len));
+ return bfa_os_ntohs(tprlo->payload_len);
}
u16
@@ -981,23 +981,23 @@ fc_tprlo_rsp_parse(struct fchs_s *fchs, int len)
len = len;
if (tprlo->command != FC_ELS_ACC)
- return (FC_PARSE_ACC_INVAL);
+ return FC_PARSE_ACC_INVAL;
num_pages = (bfa_os_ntohs(tprlo->payload_len) - 4) / 16;
for (page = 0; page < num_pages; page++) {
if (tprlo->tprlo_acc_params[page].type != FC_TYPE_FCP)
- return (FC_PARSE_NOT_FCP);
+ return FC_PARSE_NOT_FCP;
if (tprlo->tprlo_acc_params[page].opa_valid != 0)
- return (FC_PARSE_OPAFLAG_INVAL);
+ return FC_PARSE_OPAFLAG_INVAL;
if (tprlo->tprlo_acc_params[page].rpa_valid != 0)
- return (FC_PARSE_RPAFLAG_INVAL);
+ return FC_PARSE_RPAFLAG_INVAL;
if (tprlo->tprlo_acc_params[page].orig_process_assc != 0)
- return (FC_PARSE_OPA_INVAL);
+ return FC_PARSE_OPA_INVAL;
if (tprlo->tprlo_acc_params[page].resp_process_assc != 0)
- return (FC_PARSE_RPA_INVAL);
+ return FC_PARSE_RPA_INVAL;
}
- return (FC_PARSE_OK);
+ return FC_PARSE_OK;
}
enum fc_parse_status
@@ -1024,7 +1024,7 @@ fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
fchs->cat_info = FC_CAT_BA_RJT;
ba_rjt->reason_code = reason_code;
ba_rjt->reason_expl = reason_expl;
- return (sizeof(struct fc_ba_rjt_s));
+ return sizeof(struct fc_ba_rjt_s);
}
static void
@@ -1073,7 +1073,7 @@ fc_gidpn_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
bfa_os_memset(gidpn, 0, sizeof(struct fcgs_gidpn_req_s));
gidpn->port_name = port_name;
- return (sizeof(struct fcgs_gidpn_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_gidpn_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1090,7 +1090,7 @@ fc_gpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
bfa_os_memset(gpnid, 0, sizeof(fcgs_gpnid_req_t));
gpnid->dap = port_id;
- return (sizeof(fcgs_gpnid_req_t) + sizeof(struct ct_hdr_s));
+ return sizeof(fcgs_gpnid_req_t) + sizeof(struct ct_hdr_s);
}
u16
@@ -1107,7 +1107,7 @@ fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
bfa_os_memset(gnnid, 0, sizeof(fcgs_gnnid_req_t));
gnnid->dap = port_id;
- return (sizeof(fcgs_gnnid_req_t) + sizeof(struct ct_hdr_s));
+ return sizeof(fcgs_gnnid_req_t) + sizeof(struct ct_hdr_s);
}
u16
@@ -1137,7 +1137,7 @@ fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr, u8 set_br_reg,
if (set_br_reg)
scr->vu_reg_func = FC_VU_SCR_REG_FUNC_FABRIC_NAME_CHANGE;
- return (sizeof(struct fc_scr_s));
+ return sizeof(struct fc_scr_s);
}
u16
@@ -1157,7 +1157,7 @@ fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn, u32 s_id,
rscn->event[0].format = FC_RSCN_FORMAT_PORTID;
rscn->event[0].portid = s_id;
- return (sizeof(struct fc_rscn_pl_s));
+ return sizeof(struct fc_rscn_pl_s);
}
u16
@@ -1188,7 +1188,7 @@ fc_rftid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
rftid->fc4_type[index] |= bfa_os_htonl(type_value);
}
- return (sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1210,7 +1210,7 @@ fc_rftid_build_sol(struct fchs_s *fchs, void *pyld, u32 s_id,
bfa_os_memcpy((void *)rftid->fc4_type, (void *)fc4_bitmap,
(bitmap_size < 32 ? bitmap_size : 32));
- return (sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1231,7 +1231,7 @@ fc_rffid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
rffid->fc4ftr_bits = fc4_ftrs;
rffid->fc4_type = fc4_type;
- return (sizeof(struct fcgs_rffid_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_rffid_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1253,7 +1253,7 @@ fc_rspnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
rspnid->spn_len = (u8) strlen((char *)name);
strncpy((char *)rspnid->spn, (char *)name, rspnid->spn_len);
- return (sizeof(struct fcgs_rspnid_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_rspnid_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1275,7 +1275,7 @@ fc_gid_ft_build(struct fchs_s *fchs, void *pyld, u32 s_id,
gidft->domain_id = 0;
gidft->area_id = 0;
- return (sizeof(struct fcgs_gidft_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_gidft_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1294,7 +1294,7 @@ fc_rpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
rpnid->port_id = port_id;
rpnid->port_name = port_name;
- return (sizeof(struct fcgs_rpnid_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_rpnid_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1313,7 +1313,7 @@ fc_rnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
rnnid->port_id = port_id;
rnnid->node_name = node_name;
- return (sizeof(struct fcgs_rnnid_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_rnnid_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1332,7 +1332,7 @@ fc_rcsid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
rcsid->port_id = port_id;
rcsid->cos = cos;
- return (sizeof(struct fcgs_rcsid_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_rcsid_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1351,7 +1351,7 @@ fc_rptid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
rptid->port_id = port_id;
rptid->port_type = port_type;
- return (sizeof(struct fcgs_rptid_req_s) + sizeof(struct ct_hdr_s));
+ return sizeof(struct fcgs_rptid_req_s) + sizeof(struct ct_hdr_s);
}
u16
@@ -1368,7 +1368,7 @@ fc_ganxt_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id)
bfa_os_memset(ganxt, 0, sizeof(struct fcgs_ganxt_req_s));
ganxt->port_id = port_id;
- return (sizeof(struct ct_hdr_s) + sizeof(struct fcgs_ganxt_req_s));
+ return sizeof(struct ct_hdr_s) + sizeof(struct fcgs_ganxt_req_s);
}
/*
@@ -1385,7 +1385,7 @@ fc_fdmi_reqhdr_build(struct fchs_s *fchs, void *pyld, u32 s_id,
fc_gs_fchdr_build(fchs, d_id, s_id, 0);
fc_gs_fdmi_cthdr_build(cthdr, s_id, cmd_code);
- return (sizeof(struct ct_hdr_s));
+ return sizeof(struct ct_hdr_s);
}
/*
@@ -1425,7 +1425,7 @@ fc_gmal_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn)
bfa_os_memset(gmal, 0, sizeof(fcgs_gmal_req_t));
gmal->wwn = wwn;
- return (sizeof(struct ct_hdr_s) + sizeof(fcgs_gmal_req_t));
+ return sizeof(struct ct_hdr_s) + sizeof(fcgs_gmal_req_t);
}
/*
@@ -1445,5 +1445,5 @@ fc_gfn_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn)
bfa_os_memset(gfn, 0, sizeof(fcgs_gfn_req_t));
gfn->wwn = wwn;
- return (sizeof(struct ct_hdr_s) + sizeof(fcgs_gfn_req_t));
+ return sizeof(struct ct_hdr_s) + sizeof(fcgs_gfn_req_t);
}
diff --git a/drivers/scsi/bfa/fcbuild.h b/drivers/scsi/bfa/fcbuild.h
index 4d248424f7b3..8fa7f270ef7b 100644
--- a/drivers/scsi/bfa/fcbuild.h
+++ b/drivers/scsi/bfa/fcbuild.h
@@ -32,8 +32,8 @@
* Utility Macros/functions
*/
-#define fcif_sof_set(_ifhdr, _sof) (_ifhdr)->sof = FC_ ## _sof
-#define fcif_eof_set(_ifhdr, _eof) (_ifhdr)->eof = FC_ ## _eof
+#define fcif_sof_set(_ifhdr, _sof) ((_ifhdr)->sof = FC_ ## _sof)
+#define fcif_eof_set(_ifhdr, _eof) ((_ifhdr)->eof = FC_ ## _eof)
#define wwn_is_equal(_wwn1, _wwn2) \
(memcmp(&(_wwn1), &(_wwn2), sizeof(wwn_t)) == 0)
@@ -49,7 +49,7 @@
static inline u32
fc_get_ctresp_pyld_len(u32 resp_len)
{
- return (resp_len - sizeof(struct ct_hdr_s));
+ return resp_len - sizeof(struct ct_hdr_s);
}
/*
diff --git a/drivers/scsi/bfa/fcpim.c b/drivers/scsi/bfa/fcpim.c
index 8ce5d8934677..1f3c06efaa9e 100644
--- a/drivers/scsi/bfa/fcpim.c
+++ b/drivers/scsi/bfa/fcpim.c
@@ -286,11 +286,10 @@ bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_offline);
bfa_fcb_itnim_offline(itnim->itnim_drv);
bfa_itnim_offline(itnim->bfa_itnim);
- if (bfa_fcs_port_is_online(itnim->rport->port) == BFA_TRUE) {
+ if (bfa_fcs_port_is_online(itnim->rport->port) == BFA_TRUE)
bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_DISCONNECT);
- } else {
+ else
bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_OFFLINE);
- }
break;
case BFA_FCS_ITNIM_SM_DELETE:
@@ -732,7 +731,7 @@ bfa_fcs_itnim_lookup(struct bfa_fcs_port_s *port, wwn_t rpwwn)
return NULL;
bfa_assert(rport->itnim != NULL);
- return (rport->itnim);
+ return rport->itnim;
}
bfa_status_t
diff --git a/drivers/scsi/bfa/fcs.h b/drivers/scsi/bfa/fcs.h
index deee685e8478..8d08230e6295 100644
--- a/drivers/scsi/bfa/fcs.h
+++ b/drivers/scsi/bfa/fcs.h
@@ -23,7 +23,7 @@
#ifndef __FCS_H__
#define __FCS_H__
-#define __fcs_min_cfg(__fcs) (__fcs)->min_cfg
+#define __fcs_min_cfg(__fcs) ((__fcs)->min_cfg)
void bfa_fcs_modexit_comp(struct bfa_fcs_s *fcs);
diff --git a/drivers/scsi/bfa/fdmi.c b/drivers/scsi/bfa/fdmi.c
index b845eb272c78..df2a1e54e16b 100644
--- a/drivers/scsi/bfa/fdmi.c
+++ b/drivers/scsi/bfa/fdmi.c
@@ -72,9 +72,9 @@ static u16 bfa_fcs_port_fdmi_build_rpa_pyld(
struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld);
static u16 bfa_fcs_port_fdmi_build_portattr_block(
struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld);
-void bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_port_fdmi_s *fdmi,
+static void bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_port_fdmi_s *fdmi,
struct bfa_fcs_fdmi_hba_attr_s *hba_attr);
-void bfa_fcs_fdmi_get_portattr(struct bfa_fcs_port_fdmi_s *fdmi,
+static void bfa_fcs_fdmi_get_portattr(struct bfa_fcs_port_fdmi_s *fdmi,
struct bfa_fcs_fdmi_port_attr_s *port_attr);
/**
* fcs_fdmi_sm FCS FDMI state machine
@@ -1091,7 +1091,7 @@ bfa_fcs_port_fdmi_timeout(void *arg)
bfa_sm_send_event(fdmi, FDMISM_EVENT_TIMEOUT);
}
-void
+static void
bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_port_fdmi_s *fdmi,
struct bfa_fcs_fdmi_hba_attr_s *hba_attr)
{
@@ -1145,7 +1145,7 @@ bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_port_fdmi_s *fdmi,
}
-void
+static void
bfa_fcs_fdmi_get_portattr(struct bfa_fcs_port_fdmi_s *fdmi,
struct bfa_fcs_fdmi_port_attr_s *port_attr)
{
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen.h b/drivers/scsi/bfa/include/aen/bfa_aen.h
index da8cac093d3d..d9cbc2a783d4 100644
--- a/drivers/scsi/bfa/include/aen/bfa_aen.h
+++ b/drivers/scsi/bfa/include/aen/bfa_aen.h
@@ -54,7 +54,7 @@ bfa_aen_get_max_cfg_entry(void)
static inline s32
bfa_aen_get_meminfo(void)
{
- return (sizeof(struct bfa_aen_entry_s) * bfa_aen_get_max_cfg_entry());
+ return sizeof(struct bfa_aen_entry_s) * bfa_aen_get_max_cfg_entry();
}
static inline s32
diff --git a/drivers/scsi/bfa/include/bfa.h b/drivers/scsi/bfa/include/bfa.h
index 64c1412c5703..d4bc0d9fa42c 100644
--- a/drivers/scsi/bfa/include/bfa.h
+++ b/drivers/scsi/bfa/include/bfa.h
@@ -76,11 +76,11 @@ struct bfa_meminfo_s {
struct bfa_mem_elem_s meminfo[BFA_MEM_TYPE_MAX];
};
#define bfa_meminfo_kva(_m) \
- (_m)->meminfo[BFA_MEM_TYPE_KVA - 1].kva_curp
+ ((_m)->meminfo[BFA_MEM_TYPE_KVA - 1].kva_curp)
#define bfa_meminfo_dma_virt(_m) \
- (_m)->meminfo[BFA_MEM_TYPE_DMA - 1].kva_curp
+ ((_m)->meminfo[BFA_MEM_TYPE_DMA - 1].kva_curp)
#define bfa_meminfo_dma_phys(_m) \
- (_m)->meminfo[BFA_MEM_TYPE_DMA - 1].dma_curp
+ ((_m)->meminfo[BFA_MEM_TYPE_DMA - 1].dma_curp)
/**
* Generic Scatter Gather Element used by driver
@@ -100,7 +100,7 @@ struct bfa_sge_s {
/*
* bfa stats interfaces
*/
-#define bfa_stats(_mod, _stats) (_mod)->stats._stats ++
+#define bfa_stats(_mod, _stats) ((_mod)->stats._stats++)
#define bfa_ioc_get_stats(__bfa, __ioc_stats) \
bfa_ioc_fetch_stats(&(__bfa)->ioc, __ioc_stats)
@@ -136,7 +136,7 @@ void bfa_isr_enable(struct bfa_s *bfa);
void bfa_isr_disable(struct bfa_s *bfa);
void bfa_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap,
u32 *num_vecs, u32 *max_vec_bit);
-#define bfa_msix(__bfa, __vec) (__bfa)->msix.handler[__vec](__bfa, __vec)
+#define bfa_msix(__bfa, __vec) ((__bfa)->msix.handler[__vec](__bfa, __vec))
void bfa_comp_deq(struct bfa_s *bfa, struct list_head *comp_q);
void bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q);
diff --git a/drivers/scsi/bfa/include/bfa_svc.h b/drivers/scsi/bfa/include/bfa_svc.h
index 0c80b74f72ef..268d956bad89 100644
--- a/drivers/scsi/bfa/include/bfa_svc.h
+++ b/drivers/scsi/bfa/include/bfa_svc.h
@@ -34,10 +34,10 @@ struct bfa_fcxp_s;
*/
struct bfa_rport_info_s {
u16 max_frmsz; /* max rcv pdu size */
- u32 pid : 24, /* remote port ID */
- lp_tag : 8;
- u32 local_pid : 24, /* local port ID */
- cisc : 8; /* CIRO supported */
+ u32 pid:24, /* remote port ID */
+ lp_tag:8;
+ u32 local_pid:24, /* local port ID */
+ cisc:8; /* CIRO supported */
u8 fc_class; /* supported FC classes. enum fc_cos */
u8 vf_en; /* virtual fabric enable */
u16 vf_id; /* virtual fabric ID */
diff --git a/drivers/scsi/bfa/include/bfi/bfi.h b/drivers/scsi/bfa/include/bfi/bfi.h
index 6cadfe0d4ba1..7042c18e542d 100644
--- a/drivers/scsi/bfa/include/bfi/bfi.h
+++ b/drivers/scsi/bfa/include/bfi/bfi.h
@@ -93,13 +93,13 @@ union bfi_addr_u {
*/
struct bfi_sge_s {
#ifdef __BIGENDIAN
- u32 flags : 2,
- rsvd : 2,
- sg_len : 28;
+ u32 flags:2,
+ rsvd:2,
+ sg_len:28;
#else
- u32 sg_len : 28,
- rsvd : 2,
- flags : 2;
+ u32 sg_len:28,
+ rsvd:2,
+ flags:2;
#endif
union bfi_addr_u sga;
};
diff --git a/drivers/scsi/bfa/include/bfi/bfi_ioc.h b/drivers/scsi/bfa/include/bfi/bfi_ioc.h
index 026e9c06ae97..96ef05670659 100644
--- a/drivers/scsi/bfa/include/bfi/bfi_ioc.h
+++ b/drivers/scsi/bfa/include/bfi/bfi_ioc.h
@@ -142,7 +142,7 @@ enum {
BFI_ADAPTER_UNSUPP = 0x400000, /* unknown adapter type */
};
-#define BFI_ADAPTER_GETP(__prop,__adap_prop) \
+#define BFI_ADAPTER_GETP(__prop, __adap_prop) \
(((__adap_prop) & BFI_ADAPTER_ ## __prop ## _MK) >> \
BFI_ADAPTER_ ## __prop ## _SH)
#define BFI_ADAPTER_SETP(__prop, __val) \
diff --git a/drivers/scsi/bfa/include/bfi/bfi_lps.h b/drivers/scsi/bfa/include/bfi/bfi_lps.h
index 414b0e30f6ef..c59d47badb4b 100644
--- a/drivers/scsi/bfa/include/bfi/bfi_lps.h
+++ b/drivers/scsi/bfa/include/bfi/bfi_lps.h
@@ -55,8 +55,8 @@ struct bfi_lps_login_rsp_s {
u16 bb_credit;
u8 f_port;
u8 npiv_en;
- u32 lp_pid : 24;
- u32 auth_req : 8;
+ u32 lp_pid:24;
+ u32 auth_req:8;
mac_t lp_mac;
mac_t fcf_mac;
u8 ext_status;
diff --git a/drivers/scsi/bfa/include/bfi/bfi_rport.h b/drivers/scsi/bfa/include/bfi/bfi_rport.h
index 3520f55f09d7..e1cd83b56ec6 100644
--- a/drivers/scsi/bfa/include/bfi/bfi_rport.h
+++ b/drivers/scsi/bfa/include/bfi/bfi_rport.h
@@ -38,10 +38,10 @@ struct bfi_rport_create_req_s {
struct bfi_mhdr_s mh; /* common msg header */
u16 bfa_handle; /* host rport handle */
u16 max_frmsz; /* max rcv pdu size */
- u32 pid : 24, /* remote port ID */
- lp_tag : 8; /* local port tag */
- u32 local_pid : 24, /* local port ID */
- cisc : 8;
+ u32 pid:24, /* remote port ID */
+ lp_tag:8; /* local port tag */
+ u32 local_pid:24, /* local port ID */
+ cisc:8;
u8 fc_class; /* supported FC classes */
u8 vf_en; /* virtual fabric enable */
u16 vf_id; /* virtual fabric ID */
diff --git a/drivers/scsi/bfa/include/cs/bfa_checksum.h b/drivers/scsi/bfa/include/cs/bfa_checksum.h
index af8c1d533ba8..650f8d0aaff9 100644
--- a/drivers/scsi/bfa/include/cs/bfa_checksum.h
+++ b/drivers/scsi/bfa/include/cs/bfa_checksum.h
@@ -31,7 +31,7 @@ bfa_checksum_u32(u32 *buf, int sz)
for (i = 0; i < m; i++)
sum ^= buf[i];
- return (sum);
+ return sum;
}
static inline u16
@@ -43,7 +43,7 @@ bfa_checksum_u16(u16 *buf, int sz)
for (i = 0; i < m; i++)
sum ^= buf[i];
- return (sum);
+ return sum;
}
static inline u8
@@ -55,6 +55,6 @@ bfa_checksum_u8(u8 *buf, int sz)
for (i = 0; i < sz; i++)
sum ^= buf[i];
- return (sum);
+ return sum;
}
#endif
diff --git a/drivers/scsi/bfa/include/cs/bfa_sm.h b/drivers/scsi/bfa/include/cs/bfa_sm.h
index 9877066680a6..b0a92baf6657 100644
--- a/drivers/scsi/bfa/include/cs/bfa_sm.h
+++ b/drivers/scsi/bfa/include/cs/bfa_sm.h
@@ -24,8 +24,8 @@
typedef void (*bfa_sm_t)(void *sm, int 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_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))
@@ -62,7 +62,7 @@ typedef void (*bfa_fsm_t)(void *fsm, int event);
} while (0)
#define bfa_fsm_send_event(_fsm, _event) \
- (_fsm)->fsm((_fsm), (_event))
+ ((_fsm)->fsm((_fsm), (_event)))
#define bfa_fsm_cmp_state(_fsm, _state) \
((_fsm)->fsm == (bfa_fsm_t)(_state))
diff --git a/drivers/scsi/bfa/include/cs/bfa_trc.h b/drivers/scsi/bfa/include/cs/bfa_trc.h
index 3e743928c74c..310771c888e7 100644
--- a/drivers/scsi/bfa/include/cs/bfa_trc.h
+++ b/drivers/scsi/bfa/include/cs/bfa_trc.h
@@ -24,7 +24,7 @@
#endif
#ifndef BFA_TRC_TS
-#define BFA_TRC_TS(_trcm) ((_trcm)->ticks ++)
+#define BFA_TRC_TS(_trcm) ((_trcm)->ticks++)
#endif
struct bfa_trc_s {
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h
index 4ffd2242d3de..08b79d5e46f3 100644
--- a/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h
@@ -75,7 +75,7 @@ struct bfa_fcs_fabric_s {
*/
};
-#define bfa_fcs_fabric_npiv_capable(__f) (__f)->is_npiv
+#define bfa_fcs_fabric_npiv_capable(__f) ((__f)->is_npiv)
#define bfa_fcs_fabric_is_switched(__f) \
((__f)->fab_type == BFA_FCS_FABRIC_SWITCHED)
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h
index b85cba884b96..967ceb0eb074 100644
--- a/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h
@@ -125,12 +125,12 @@ union bfa_fcs_port_topo_u {
struct bfa_fcs_port_s {
struct list_head qe; /* used by port/vport */
bfa_sm_t sm; /* state machine */
- struct bfa_fcs_fabric_s *fabric; /* parent fabric */
- struct bfa_port_cfg_s port_cfg; /* port configuration */
+ struct bfa_fcs_fabric_s *fabric;/* parent fabric */
+ struct bfa_port_cfg_s port_cfg;/* port configuration */
struct bfa_timer_s link_timer; /* timer for link offline */
- u32 pid : 24; /* FC address */
- u8 lp_tag; /* lport tag */
- u16 num_rports; /* Num of r-ports */
+ u32 pid:24; /* FC address */
+ u8 lp_tag; /* lport tag */
+ u16 num_rports; /* Num of r-ports */
struct list_head rport_q; /* queue of discovered r-ports */
struct bfa_fcs_s *fcs; /* FCS instance */
union bfa_fcs_port_topo_u port_topo; /* fabric/loop/n2n details */
@@ -188,13 +188,14 @@ bfa_fcs_port_get_drvport(struct bfa_fcs_port_s *port)
}
-#define bfa_fcs_port_get_opertype(_lport) (_lport)->fabric->oper_type
+#define bfa_fcs_port_get_opertype(_lport) ((_lport)->fabric->oper_type)
-#define bfa_fcs_port_get_fabric_name(_lport) (_lport)->fabric->fabric_name
+#define bfa_fcs_port_get_fabric_name(_lport) ((_lport)->fabric->fabric_name)
-#define bfa_fcs_port_get_fabric_ipaddr(_lport) (_lport)->fabric->fabric_ip_addr
+#define bfa_fcs_port_get_fabric_ipaddr(_lport) \
+ ((_lport)->fabric->fabric_ip_addr)
/**
* bfa fcs port public functions
diff --git a/drivers/scsi/bfa/include/protocol/ct.h b/drivers/scsi/bfa/include/protocol/ct.h
index c59d6630b070..c8648bcba41a 100644
--- a/drivers/scsi/bfa/include/protocol/ct.h
+++ b/drivers/scsi/bfa/include/protocol/ct.h
@@ -193,11 +193,11 @@ struct fcgs_rftid_req_s {
#define FC_GS_FCP_FC4_FEATURE_TARGET 0x01
struct fcgs_rffid_req_s{
- u32 rsvd :8;
- u32 dap :24; /* port identifier */
- u32 rsvd1 :16;
- u32 fc4ftr_bits :8; /* fc4 feature bits */
- u32 fc4_type :8; /* corresponding FC4 Type */
+ u32 rsvd:8;
+ u32 dap:24; /* port identifier */
+ u32 rsvd1:16;
+ u32 fc4ftr_bits:8; /* fc4 feature bits */
+ u32 fc4_type:8; /* corresponding FC4 Type */
};
/**
diff --git a/drivers/scsi/bfa/include/protocol/fc.h b/drivers/scsi/bfa/include/protocol/fc.h
index 3e39ba58cfb5..14969eecf6a9 100644
--- a/drivers/scsi/bfa/include/protocol/fc.h
+++ b/drivers/scsi/bfa/include/protocol/fc.h
@@ -486,14 +486,14 @@ struct fc_rsi_s {
* see FC-PH-X table 113 & 115 for explanation also FCP table 8
*/
struct fc_prli_params_s{
- u32 reserved: 16;
+ u32 reserved:16;
#ifdef __BIGENDIAN
- u32 reserved1: 5;
- u32 rec_support : 1;
- u32 task_retry_id : 1;
- u32 retry : 1;
+ u32 reserved1:5;
+ u32 rec_support:1;
+ u32 task_retry_id:1;
+ u32 retry:1;
- u32 confirm : 1;
+ u32 confirm:1;
u32 doverlay:1;
u32 initiator:1;
u32 target:1;
@@ -502,10 +502,10 @@ struct fc_prli_params_s{
u32 rxrdisab:1;
u32 wxrdisab:1;
#else
- u32 retry : 1;
- u32 task_retry_id : 1;
- u32 rec_support : 1;
- u32 reserved1: 5;
+ u32 retry:1;
+ u32 task_retry_id:1;
+ u32 rec_support:1;
+ u32 reserved1:5;
u32 wxrdisab:1;
u32 rxrdisab:1;
@@ -514,7 +514,7 @@ struct fc_prli_params_s{
u32 target:1;
u32 initiator:1;
u32 doverlay:1;
- u32 confirm : 1;
+ u32 confirm:1;
#endif
};
diff --git a/drivers/scsi/bfa/loop.c b/drivers/scsi/bfa/loop.c
index a418dedebe9e..f7c7f4f3c640 100644
--- a/drivers/scsi/bfa/loop.c
+++ b/drivers/scsi/bfa/loop.c
@@ -58,49 +58,16 @@ static const u8 port_loop_alpa_map[] = {
/*
* Local Functions
*/
-bfa_status_t bfa_fcs_port_loop_send_plogi(struct bfa_fcs_port_s *port,
- u8 alpa);
-
-void bfa_fcs_port_loop_plogi_response(void *fcsarg,
- struct bfa_fcxp_s *fcxp,
- void *cbarg,
- bfa_status_t req_status,
- u32 rsp_len,
- u32 resid_len,
- struct fchs_s *rsp_fchs);
-
-bfa_status_t bfa_fcs_port_loop_send_adisc(struct bfa_fcs_port_s *port,
- u8 alpa);
-
-void bfa_fcs_port_loop_adisc_response(void *fcsarg,
- struct bfa_fcxp_s *fcxp,
- void *cbarg,
- bfa_status_t req_status,
- u32 rsp_len,
- u32 resid_len,
- struct fchs_s *rsp_fchs);
-
-bfa_status_t bfa_fcs_port_loop_send_plogi_acc(struct bfa_fcs_port_s *port,
- u8 alpa);
-
-void bfa_fcs_port_loop_plogi_acc_response(void *fcsarg,
- struct bfa_fcxp_s *fcxp,
- void *cbarg,
- bfa_status_t req_status,
- u32 rsp_len,
- u32 resid_len,
- struct fchs_s *rsp_fchs);
-
-bfa_status_t bfa_fcs_port_loop_send_adisc_acc(struct bfa_fcs_port_s *port,
- u8 alpa);
-
-void bfa_fcs_port_loop_adisc_acc_response(void *fcsarg,
- struct bfa_fcxp_s *fcxp,
- void *cbarg,
- bfa_status_t req_status,
- u32 rsp_len,
- u32 resid_len,
- struct fchs_s *rsp_fchs);
+static bfa_status_t bfa_fcs_port_loop_send_plogi(struct bfa_fcs_port_s *port,
+ u8 alpa);
+
+static void bfa_fcs_port_loop_plogi_response(void *fcsarg,
+ struct bfa_fcxp_s *fcxp,
+ void *cbarg,
+ bfa_status_t req_status,
+ u32 rsp_len,
+ u32 resid_len,
+ struct fchs_s *rsp_fchs);
/**
* Called by port to initializar in provate LOOP topology.
*/
@@ -179,7 +146,7 @@ bfa_fcs_port_loop_lip(struct bfa_fcs_port_s *port)
/**
* Local Functions.
*/
-bfa_status_t
+static bfa_status_t
bfa_fcs_port_loop_send_plogi(struct bfa_fcs_port_s *port, u8 alpa)
{
struct fchs_s fchs;
@@ -208,7 +175,7 @@ bfa_fcs_port_loop_send_plogi(struct bfa_fcs_port_s *port, u8 alpa)
/**
* Called by fcxp to notify the Plogi response
*/
-void
+static void
bfa_fcs_port_loop_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
void *cbarg, bfa_status_t req_status,
u32 rsp_len, u32 resid_len,
@@ -244,179 +211,3 @@ bfa_fcs_port_loop_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
bfa_assert(0);
}
}
-
-bfa_status_t
-bfa_fcs_port_loop_send_plogi_acc(struct bfa_fcs_port_s *port, u8 alpa)
-{
- struct fchs_s fchs;
- struct bfa_fcxp_s *fcxp;
- int len;
-
- bfa_trc(port->fcs, alpa);
-
- fcxp = bfa_fcxp_alloc(NULL, port->fcs->bfa, 0, 0, NULL, NULL, NULL,
- NULL);
- bfa_assert(fcxp);
-
- len = fc_plogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), alpa,
- bfa_fcs_port_get_fcid(port), 0,
- port->port_cfg.pwwn, port->port_cfg.nwwn,
- bfa_pport_get_maxfrsize(port->fcs->bfa));
-
- bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
- FC_CLASS_3, len, &fchs,
- bfa_fcs_port_loop_plogi_acc_response,
- (void *)port, FC_MAX_PDUSZ, 0); /* No response
- * expected
- */
-
- return BFA_STATUS_OK;
-}
-
-/*
- * Plogi Acc Response
- * We donot do any processing here.
- */
-void
-bfa_fcs_port_loop_plogi_acc_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
- void *cbarg, bfa_status_t req_status,
- u32 rsp_len, u32 resid_len,
- struct fchs_s *rsp_fchs)
-{
-
- struct bfa_fcs_port_s *port = (struct bfa_fcs_port_s *) cbarg;
-
- bfa_trc(port->fcs, port->pid);
-
- /*
- * Sanity Checks
- */
- if (req_status != BFA_STATUS_OK) {
- bfa_trc(port->fcs, req_status);
- return;
- }
-}
-
-bfa_status_t
-bfa_fcs_port_loop_send_adisc(struct bfa_fcs_port_s *port, u8 alpa)
-{
- struct fchs_s fchs;
- struct bfa_fcxp_s *fcxp;
- int len;
-
- bfa_trc(port->fcs, alpa);
-
- fcxp = bfa_fcxp_alloc(NULL, port->fcs->bfa, 0, 0, NULL, NULL, NULL,
- NULL);
- bfa_assert(fcxp);
-
- len = fc_adisc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), alpa,
- bfa_fcs_port_get_fcid(port), 0,
- port->port_cfg.pwwn, port->port_cfg.nwwn);
-
- bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
- FC_CLASS_3, len, &fchs,
- bfa_fcs_port_loop_adisc_response, (void *)port,
- FC_MAX_PDUSZ, FC_RA_TOV);
-
- return BFA_STATUS_OK;
-}
-
-/**
- * Called by fcxp to notify the ADISC response
- */
-void
-bfa_fcs_port_loop_adisc_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
- void *cbarg, bfa_status_t req_status,
- u32 rsp_len, u32 resid_len,
- struct fchs_s *rsp_fchs)
-{
- struct bfa_fcs_port_s *port = (struct bfa_fcs_port_s *) cbarg;
- struct bfa_fcs_rport_s *rport;
- struct fc_adisc_s *adisc_resp;
- struct fc_els_cmd_s *els_cmd;
- u32 pid = rsp_fchs->s_id;
-
- bfa_trc(port->fcs, req_status);
-
- /*
- * Sanity Checks
- */
- if (req_status != BFA_STATUS_OK) {
- /*
- * TBD : we may need to retry certain requests
- */
- bfa_fcxp_free(fcxp);
- return;
- }
-
- els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);
- adisc_resp = (struct fc_adisc_s *) els_cmd;
-
- if (els_cmd->els_code == FC_ELS_ACC) {
- } else {
- bfa_trc(port->fcs, adisc_resp->els_cmd.els_code);
-
- /*
- * TBD: we may need to check for reject codes and retry
- */
- rport = bfa_fcs_port_get_rport_by_pid(port, pid);
- if (rport) {
- list_del(&rport->qe);
- bfa_fcs_rport_delete(rport);
- }
-
- }
- return;
-}
-
-bfa_status_t
-bfa_fcs_port_loop_send_adisc_acc(struct bfa_fcs_port_s *port, u8 alpa)
-{
- struct fchs_s fchs;
- struct bfa_fcxp_s *fcxp;
- int len;
-
- bfa_trc(port->fcs, alpa);
-
- fcxp = bfa_fcxp_alloc(NULL, port->fcs->bfa, 0, 0, NULL, NULL, NULL,
- NULL);
- bfa_assert(fcxp);
-
- len = fc_adisc_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), alpa,
- bfa_fcs_port_get_fcid(port), 0,
- port->port_cfg.pwwn, port->port_cfg.nwwn);
-
- bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
- FC_CLASS_3, len, &fchs,
- bfa_fcs_port_loop_adisc_acc_response,
- (void *)port, FC_MAX_PDUSZ, 0); /* no reponse
- * expected
- */
-
- return BFA_STATUS_OK;
-}
-
-/*
- * Adisc Acc Response
- * We donot do any processing here.
- */
-void
-bfa_fcs_port_loop_adisc_acc_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
- void *cbarg, bfa_status_t req_status,
- u32 rsp_len, u32 resid_len,
- struct fchs_s *rsp_fchs)
-{
-
- struct bfa_fcs_port_s *port = (struct bfa_fcs_port_s *) cbarg;
-
- bfa_trc(port->fcs, port->pid);
-
- /*
- * Sanity Checks
- */
- if (req_status != BFA_STATUS_OK) {
- bfa_trc(port->fcs, req_status);
- return;
- }
-}
diff --git a/drivers/scsi/bfa/lport_api.c b/drivers/scsi/bfa/lport_api.c
index 8f51a83f1834..1e06792cd4c2 100644
--- a/drivers/scsi/bfa/lport_api.c
+++ b/drivers/scsi/bfa/lport_api.c
@@ -43,7 +43,7 @@ bfa_fcs_cfg_base_port(struct bfa_fcs_s *fcs, struct bfa_port_cfg_s *port_cfg)
struct bfa_fcs_port_s *
bfa_fcs_get_base_port(struct bfa_fcs_s *fcs)
{
- return (&fcs->fabric.bport);
+ return &fcs->fabric.bport;
}
wwn_t
@@ -88,11 +88,10 @@ bfa_fcs_port_get_rport(struct bfa_fcs_port_s *port, wwn_t wwn, int index,
}
bfa_trc(fcs, i);
- if (rport) {
+ if (rport)
return rport->pwwn;
- } else {
+ else
return (wwn_t) 0;
- }
}
void
@@ -198,17 +197,17 @@ bfa_fcs_lookup_port(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t lpwwn)
vf = bfa_fcs_vf_lookup(fcs, vf_id);
if (vf == NULL) {
bfa_trc(fcs, vf_id);
- return (NULL);
+ return NULL;
}
if (!lpwwn || (vf->bport.port_cfg.pwwn == lpwwn))
- return (&vf->bport);
+ return &vf->bport;
vport = bfa_fcs_fabric_vport_lookup(vf, lpwwn);
if (vport)
- return (&vport->lport);
+ return &vport->lport;
- return (NULL);
+ return NULL;
}
/*
diff --git a/drivers/scsi/bfa/ns.c b/drivers/scsi/bfa/ns.c
index 59fea99d67a4..2f8b880060bb 100644
--- a/drivers/scsi/bfa/ns.c
+++ b/drivers/scsi/bfa/ns.c
@@ -932,11 +932,10 @@ bfa_fcs_port_ns_send_rff_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
}
ns->fcxp = fcxp;
- if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) {
+ if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port))
fc4_ftrs = FC_GS_FCP_FC4_FEATURE_INITIATOR;
- } else if (BFA_FCS_VPORT_IS_TARGET_MODE(ns->port)) {
+ else if (BFA_FCS_VPORT_IS_TARGET_MODE(ns->port))
fc4_ftrs = FC_GS_FCP_FC4_FEATURE_TARGET;
- }
len = fc_rffid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
bfa_fcs_port_get_fcid(port), 0, FC_TYPE_FCP,
diff --git a/drivers/scsi/bfa/plog.c b/drivers/scsi/bfa/plog.c
index 86af818d17bb..fcb8864d3276 100644
--- a/drivers/scsi/bfa/plog.c
+++ b/drivers/scsi/bfa/plog.c
@@ -180,5 +180,5 @@ bfa_plog_disable(struct bfa_plog_s *plog)
bfa_boolean_t
bfa_plog_get_setting(struct bfa_plog_s *plog)
{
- return((bfa_boolean_t)plog->plog_enabled);
+ return (bfa_boolean_t)plog->plog_enabled;
}
diff --git a/drivers/scsi/bfa/rport_ftrs.c b/drivers/scsi/bfa/rport_ftrs.c
index 8a1f59d596c1..e1932c885ac2 100644
--- a/drivers/scsi/bfa/rport_ftrs.c
+++ b/drivers/scsi/bfa/rport_ftrs.c
@@ -79,7 +79,7 @@ bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
bfa_trc(rport->fcs, event);
switch (event) {
- case RPFSM_EVENT_RPORT_ONLINE :
+ case RPFSM_EVENT_RPORT_ONLINE:
if (!BFA_FCS_PID_IS_WKA(rport->pid)) {
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending);
rpf->rpsc_retries = 0;
@@ -87,7 +87,7 @@ bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
break;
};
- case RPFSM_EVENT_RPORT_OFFLINE :
+ case RPFSM_EVENT_RPORT_OFFLINE:
break;
default:
@@ -107,7 +107,7 @@ bfa_fcs_rpf_sm_rpsc_sending(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc);
break;
- case RPFSM_EVENT_RPORT_OFFLINE :
+ case RPFSM_EVENT_RPORT_OFFLINE:
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rpf->fcxp_wqe);
rpf->rpsc_retries = 0;
@@ -130,11 +130,10 @@ bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
case RPFSM_EVENT_RPSC_COMP:
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online);
/* Update speed info in f/w via BFA */
- if (rpf->rpsc_speed != BFA_PPORT_SPEED_UNKNOWN) {
+ if (rpf->rpsc_speed != BFA_PPORT_SPEED_UNKNOWN)
bfa_rport_speed(rport->bfa_rport, rpf->rpsc_speed);
- } else if (rpf->assigned_speed != BFA_PPORT_SPEED_UNKNOWN) {
+ else if (rpf->assigned_speed != BFA_PPORT_SPEED_UNKNOWN)
bfa_rport_speed(rport->bfa_rport, rpf->assigned_speed);
- }
break;
case RPFSM_EVENT_RPSC_FAIL:
@@ -154,7 +153,7 @@ bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
}
break;
- case RPFSM_EVENT_RPORT_OFFLINE :
+ case RPFSM_EVENT_RPORT_OFFLINE:
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
bfa_fcxp_discard(rpf->fcxp);
rpf->rpsc_retries = 0;
@@ -174,13 +173,13 @@ bfa_fcs_rpf_sm_rpsc_retry(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
bfa_trc(rport->fcs, event);
switch (event) {
- case RPFSM_EVENT_TIMEOUT :
+ case RPFSM_EVENT_TIMEOUT:
/* re-send the RPSC */
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending);
bfa_fcs_rpf_send_rpsc2(rpf, NULL);
break;
- case RPFSM_EVENT_RPORT_OFFLINE :
+ case RPFSM_EVENT_RPORT_OFFLINE:
bfa_timer_stop(&rpf->timer);
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
rpf->rpsc_retries = 0;
@@ -201,7 +200,7 @@ bfa_fcs_rpf_sm_online(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
bfa_trc(rport->fcs, event);
switch (event) {
- case RPFSM_EVENT_RPORT_OFFLINE :
+ case RPFSM_EVENT_RPORT_OFFLINE:
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
rpf->rpsc_retries = 0;
break;
@@ -221,12 +220,12 @@ bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
bfa_trc(rport->fcs, event);
switch (event) {
- case RPFSM_EVENT_RPORT_ONLINE :
+ case RPFSM_EVENT_RPORT_ONLINE:
bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending);
bfa_fcs_rpf_send_rpsc2(rpf, NULL);
break;
- case RPFSM_EVENT_RPORT_OFFLINE :
+ case RPFSM_EVENT_RPORT_OFFLINE:
break;
default:
@@ -366,10 +365,9 @@ bfa_fcs_rpf_rpsc2_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
bfa_trc(rport->fcs, ls_rjt->reason_code);
bfa_trc(rport->fcs, ls_rjt->reason_code_expl);
rport->stats.rpsc_rejects++;
- if (ls_rjt->reason_code == FC_LS_RJT_RSN_CMD_NOT_SUPP) {
+ if (ls_rjt->reason_code == FC_LS_RJT_RSN_CMD_NOT_SUPP)
bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_FAIL);
- } else {
+ else
bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR);
- }
}
}
diff --git a/drivers/scsi/bfa/vfapi.c b/drivers/scsi/bfa/vfapi.c
index 31d81fe2fc48..391a4790bebd 100644
--- a/drivers/scsi/bfa/vfapi.c
+++ b/drivers/scsi/bfa/vfapi.c
@@ -189,7 +189,7 @@ bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id)
{
bfa_trc(fcs, vf_id);
if (vf_id == FC_VF_ID_NULL)
- return (&fcs->fabric);
+ return &fcs->fabric;
/**
* @todo vf support
diff --git a/drivers/scsi/bfa/vport.c b/drivers/scsi/bfa/vport.c
index c10af06c5714..e90f1e38c32d 100644
--- a/drivers/scsi/bfa/vport.c
+++ b/drivers/scsi/bfa/vport.c
@@ -31,13 +31,13 @@
BFA_TRC_FILE(FCS, VPORT);
-#define __vport_fcs(__vp) (__vp)->lport.fcs
-#define __vport_pwwn(__vp) (__vp)->lport.port_cfg.pwwn
-#define __vport_nwwn(__vp) (__vp)->lport.port_cfg.nwwn
-#define __vport_bfa(__vp) (__vp)->lport.fcs->bfa
-#define __vport_fcid(__vp) (__vp)->lport.pid
-#define __vport_fabric(__vp) (__vp)->lport.fabric
-#define __vport_vfid(__vp) (__vp)->lport.fabric->vf_id
+#define __vport_fcs(__vp) ((__vp)->lport.fcs)
+#define __vport_pwwn(__vp) ((__vp)->lport.port_cfg.pwwn)
+#define __vport_nwwn(__vp) ((__vp)->lport.port_cfg.nwwn)
+#define __vport_bfa(__vp) ((__vp)->lport.fcs->bfa)
+#define __vport_fcid(__vp) ((__vp)->lport.pid)
+#define __vport_fabric(__vp) ((__vp)->lport.fabric)
+#define __vport_vfid(__vp) ((__vp)->lport.fabric->vf_id)
#define BFA_FCS_VPORT_MAX_RETRIES 5
/*
@@ -641,9 +641,9 @@ bfa_fcs_vport_get_max(struct bfa_fcs_s *fcs)
bfa_get_attr(fcs->bfa, &ioc_attr);
if (ioc_attr.pci_attr.device_id == BFA_PCI_DEVICE_ID_CT)
- return (BFA_FCS_MAX_VPORTS_SUPP_CT);
+ return BFA_FCS_MAX_VPORTS_SUPP_CT;
else
- return (BFA_FCS_MAX_VPORTS_SUPP_CB);
+ return BFA_FCS_MAX_VPORTS_SUPP_CB;
}
@@ -675,7 +675,7 @@ bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs,
struct bfad_vport_s *vport_drv)
{
if (vport_cfg->pwwn == 0)
- return (BFA_STATUS_INVALID_WWN);
+ return BFA_STATUS_INVALID_WWN;
if (bfa_fcs_port_get_pwwn(&fcs->fabric.bport) == vport_cfg->pwwn)
return BFA_STATUS_VPORT_WWN_BP;
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index cafb888c2376..10110be7c0ff 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -1883,7 +1883,7 @@ static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep)
bnx2i_ep = ep->dd_data;
- /* driver should not attempt connection cleanup untill TCP_CONNECT
+ /* driver should not attempt connection cleanup until TCP_CONNECT
* completes either successfully or fails. Timeout is 9-secs, so
* wait for it to complete
*/
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index 075e2397273c..6c59c02c1ed9 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -1509,7 +1509,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
* Try anyway?
*
* We could, BUT: Sometimes the TRM_S1040 misses to produce a Selection
- * Timeout, a Disconnect or a Reselction IRQ, so we would be screwed!
+ * Timeout, a Disconnect or a Reselection IRQ, so we would be screwed!
* (This is likely to be a bug in the hardware. Obviously, most people
* only have one initiator per SCSI bus.)
* Instead let this fail and have the timer make sure the command is
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index a39addc3a596..134c63ef6d38 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_sas.c
- * Version : v00.00.04.01-rc1
+ * Version : v00.00.04.12-rc1
*
* Authors:
* (email-id : megaraidlinux@lsi.com)
@@ -40,6 +40,7 @@
#include <linux/compat.h>
#include <linux/blkdev.h>
#include <linux/mutex.h>
+#include <linux/poll.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -75,6 +76,10 @@ static struct pci_device_id megasas_pci_table[] = {
/* gen2*/
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0079GEN2)},
/* gen2*/
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0073SKINNY)},
+ /* skinny*/
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0071SKINNY)},
+ /* skinny*/
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VERDE_ZCR)},
/* xscale IOP, vega */
{PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)},
@@ -89,8 +94,14 @@ static struct megasas_mgmt_info megasas_mgmt_info;
static struct fasync_struct *megasas_async_queue;
static DEFINE_MUTEX(megasas_async_queue_mutex);
+static int megasas_poll_wait_aen;
+static DECLARE_WAIT_QUEUE_HEAD(megasas_poll_wait);
+static u32 support_poll_for_event;
static u32 megasas_dbg_lvl;
+/* define lock for aen poll */
+spinlock_t poll_aen_lock;
+
static void
megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
u8 alt_status);
@@ -215,7 +226,10 @@ megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs)
* @regs : MFI register set
*/
static inline void
-megasas_fire_cmd_xscale(dma_addr_t frame_phys_addr,u32 frame_count, struct megasas_register_set __iomem *regs)
+megasas_fire_cmd_xscale(struct megasas_instance *instance,
+ dma_addr_t frame_phys_addr,
+ u32 frame_count,
+ struct megasas_register_set __iomem *regs)
{
writel((frame_phys_addr >> 3)|(frame_count),
&(regs)->inbound_queue_port);
@@ -312,7 +326,10 @@ megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs)
* @regs : MFI register set
*/
static inline void
-megasas_fire_cmd_ppc(dma_addr_t frame_phys_addr, u32 frame_count, struct megasas_register_set __iomem *regs)
+megasas_fire_cmd_ppc(struct megasas_instance *instance,
+ dma_addr_t frame_phys_addr,
+ u32 frame_count,
+ struct megasas_register_set __iomem *regs)
{
writel((frame_phys_addr | (frame_count<<1))|1,
&(regs)->inbound_queue_port);
@@ -328,6 +345,104 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
};
/**
+ * megasas_enable_intr_skinny - Enables interrupts
+ * @regs: MFI register set
+ */
+static inline void
+megasas_enable_intr_skinny(struct megasas_register_set __iomem *regs)
+{
+ writel(0xFFFFFFFF, &(regs)->outbound_intr_mask);
+
+ writel(~MFI_SKINNY_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
+
+ /* Dummy readl to force pci flush */
+ readl(&regs->outbound_intr_mask);
+}
+
+/**
+ * megasas_disable_intr_skinny - Disables interrupt
+ * @regs: MFI register set
+ */
+static inline void
+megasas_disable_intr_skinny(struct megasas_register_set __iomem *regs)
+{
+ u32 mask = 0xFFFFFFFF;
+ writel(mask, &regs->outbound_intr_mask);
+ /* Dummy readl to force pci flush */
+ readl(&regs->outbound_intr_mask);
+}
+
+/**
+ * megasas_read_fw_status_reg_skinny - returns the current FW status value
+ * @regs: MFI register set
+ */
+static u32
+megasas_read_fw_status_reg_skinny(struct megasas_register_set __iomem *regs)
+{
+ return readl(&(regs)->outbound_scratch_pad);
+}
+
+/**
+ * megasas_clear_interrupt_skinny - Check & clear interrupt
+ * @regs: MFI register set
+ */
+static int
+megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs)
+{
+ u32 status;
+ /*
+ * Check if it is our interrupt
+ */
+ status = readl(&regs->outbound_intr_status);
+
+ if (!(status & MFI_SKINNY_ENABLE_INTERRUPT_MASK)) {
+ return 1;
+ }
+
+ /*
+ * Clear the interrupt by writing back the same value
+ */
+ writel(status, &regs->outbound_intr_status);
+
+ /*
+ * dummy read to flush PCI
+ */
+ readl(&regs->outbound_intr_status);
+
+ return 0;
+}
+
+/**
+ * megasas_fire_cmd_skinny - Sends command to the FW
+ * @frame_phys_addr : Physical address of cmd
+ * @frame_count : Number of frames for the command
+ * @regs : MFI register set
+ */
+static inline void
+megasas_fire_cmd_skinny(struct megasas_instance *instance,
+ dma_addr_t frame_phys_addr,
+ u32 frame_count,
+ struct megasas_register_set __iomem *regs)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&instance->fire_lock, flags);
+ writel(0, &(regs)->inbound_high_queue_port);
+ writel((frame_phys_addr | (frame_count<<1))|1,
+ &(regs)->inbound_low_queue_port);
+ spin_unlock_irqrestore(&instance->fire_lock, flags);
+}
+
+static struct megasas_instance_template megasas_instance_template_skinny = {
+
+ .fire_cmd = megasas_fire_cmd_skinny,
+ .enable_intr = megasas_enable_intr_skinny,
+ .disable_intr = megasas_disable_intr_skinny,
+ .clear_intr = megasas_clear_intr_skinny,
+ .read_fw_status_reg = megasas_read_fw_status_reg_skinny,
+};
+
+
+/**
* The following functions are defined for gen2 (deviceid : 0x78 0x79)
* controllers
*/
@@ -404,7 +519,9 @@ megasas_clear_intr_gen2(struct megasas_register_set __iomem *regs)
* @regs : MFI register set
*/
static inline void
-megasas_fire_cmd_gen2(dma_addr_t frame_phys_addr, u32 frame_count,
+megasas_fire_cmd_gen2(struct megasas_instance *instance,
+ dma_addr_t frame_phys_addr,
+ u32 frame_count,
struct megasas_register_set __iomem *regs)
{
writel((frame_phys_addr | (frame_count<<1))|1,
@@ -446,7 +563,8 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
/*
* Issue the frame using inbound queue port
*/
- instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
+ instance->instancet->fire_cmd(instance,
+ cmd->frame_phys_addr, 0, instance->reg_set);
/*
* Wait for cmd_status to change
@@ -477,7 +595,8 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
{
cmd->cmd_status = ENODATA;
- instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
+ instance->instancet->fire_cmd(instance,
+ cmd->frame_phys_addr, 0, instance->reg_set);
wait_event_timeout(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA),
MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
@@ -522,7 +641,8 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
cmd->sync_cmd = 1;
cmd->cmd_status = 0xFF;
- instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
+ instance->instancet->fire_cmd(instance,
+ cmd->frame_phys_addr, 0, instance->reg_set);
/*
* Wait for this cmd to complete
@@ -592,6 +712,35 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
return sge_count;
}
+/**
+ * megasas_make_sgl_skinny - Prepares IEEE SGL
+ * @instance: Adapter soft state
+ * @scp: SCSI command from the mid-layer
+ * @mfi_sgl: SGL to be filled in
+ *
+ * If successful, this function returns the number of SG elements. Otherwise,
+ * it returnes -1.
+ */
+static int
+megasas_make_sgl_skinny(struct megasas_instance *instance,
+ struct scsi_cmnd *scp, union megasas_sgl *mfi_sgl)
+{
+ int i;
+ int sge_count;
+ struct scatterlist *os_sgl;
+
+ sge_count = scsi_dma_map(scp);
+
+ if (sge_count) {
+ scsi_for_each_sg(scp, os_sgl, sge_count, i) {
+ mfi_sgl->sge_skinny[i].length = sg_dma_len(os_sgl);
+ mfi_sgl->sge_skinny[i].phys_addr =
+ sg_dma_address(os_sgl);
+ }
+ }
+ return sge_count;
+}
+
/**
* megasas_get_frame_count - Computes the number of frames
* @frame_type : type of frame- io or pthru frame
@@ -600,7 +749,8 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
* Returns the number of frames required for numnber of sge's (sge_count)
*/
-static u32 megasas_get_frame_count(u8 sge_count, u8 frame_type)
+static u32 megasas_get_frame_count(struct megasas_instance *instance,
+ u8 sge_count, u8 frame_type)
{
int num_cnt;
int sge_bytes;
@@ -610,6 +760,10 @@ static u32 megasas_get_frame_count(u8 sge_count, u8 frame_type)
sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
sizeof(struct megasas_sge32);
+ if (instance->flag_ieee) {
+ sge_sz = sizeof(struct megasas_sge_skinny);
+ }
+
/*
* Main frame can contain 2 SGEs for 64-bit SGLs and
* 3 SGEs for 32-bit SGLs for ldio &
@@ -617,12 +771,16 @@ static u32 megasas_get_frame_count(u8 sge_count, u8 frame_type)
* 2 SGEs for 32-bit SGLs for pthru frame
*/
if (unlikely(frame_type == PTHRU_FRAME)) {
- if (IS_DMA64)
+ if (instance->flag_ieee == 1) {
+ num_cnt = sge_count - 1;
+ } else if (IS_DMA64)
num_cnt = sge_count - 1;
else
num_cnt = sge_count - 2;
} else {
- if (IS_DMA64)
+ if (instance->flag_ieee == 1) {
+ num_cnt = sge_count - 1;
+ } else if (IS_DMA64)
num_cnt = sge_count - 2;
else
num_cnt = sge_count - 3;
@@ -671,6 +829,10 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
else if (scp->sc_data_direction == PCI_DMA_NONE)
flags = MFI_FRAME_DIR_NONE;
+ if (instance->flag_ieee == 1) {
+ flags |= MFI_FRAME_IEEE;
+ }
+
/*
* Prepare the DCDB frame
*/
@@ -687,9 +849,24 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
/*
+ * If the command is for the tape device, set the
+ * pthru timeout to the os layer timeout value.
+ */
+ if (scp->device->type == TYPE_TAPE) {
+ if ((scp->request->timeout / HZ) > 0xFFFF)
+ pthru->timeout = 0xFFFF;
+ else
+ pthru->timeout = scp->request->timeout / HZ;
+ }
+
+ /*
* Construct SGL
*/
- if (IS_DMA64) {
+ if (instance->flag_ieee == 1) {
+ pthru->flags |= MFI_FRAME_SGL64;
+ pthru->sge_count = megasas_make_sgl_skinny(instance, scp,
+ &pthru->sgl);
+ } else if (IS_DMA64) {
pthru->flags |= MFI_FRAME_SGL64;
pthru->sge_count = megasas_make_sgl64(instance, scp,
&pthru->sgl);
@@ -708,7 +885,7 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
* Compute the total number of frames this command consumes. FW uses
* this number to pull sufficient number of frames from host memory.
*/
- cmd->frame_count = megasas_get_frame_count(pthru->sge_count,
+ cmd->frame_count = megasas_get_frame_count(instance, pthru->sge_count,
PTHRU_FRAME);
return cmd->frame_count;
@@ -739,6 +916,10 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
flags = MFI_FRAME_DIR_READ;
+ if (instance->flag_ieee == 1) {
+ flags |= MFI_FRAME_IEEE;
+ }
+
/*
* Prepare the Logical IO frame: 2nd bit is zero for all read cmds
*/
@@ -809,7 +990,11 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
/*
* Construct SGL
*/
- if (IS_DMA64) {
+ if (instance->flag_ieee) {
+ ldio->flags |= MFI_FRAME_SGL64;
+ ldio->sge_count = megasas_make_sgl_skinny(instance, scp,
+ &ldio->sgl);
+ } else if (IS_DMA64) {
ldio->flags |= MFI_FRAME_SGL64;
ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl);
} else
@@ -826,7 +1011,8 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
* Compute the total number of frames this command consumes. FW uses
* this number to pull sufficient number of frames from host memory.
*/
- cmd->frame_count = megasas_get_frame_count(ldio->sge_count, IO_FRAME);
+ cmd->frame_count = megasas_get_frame_count(instance,
+ ldio->sge_count, IO_FRAME);
return cmd->frame_count;
}
@@ -983,7 +1169,8 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
*/
atomic_inc(&instance->fw_outstanding);
- instance->instancet->fire_cmd(cmd->frame_phys_addr ,cmd->frame_count-1,instance->reg_set);
+ instance->instancet->fire_cmd(instance, cmd->frame_phys_addr,
+ cmd->frame_count-1, instance->reg_set);
/*
* Check if we have pend cmds to be completed
*/
@@ -1000,24 +1187,76 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
return 0;
}
+static struct megasas_instance *megasas_lookup_instance(u16 host_no)
+{
+ int i;
+
+ for (i = 0; i < megasas_mgmt_info.max_index; i++) {
+
+ if ((megasas_mgmt_info.instance[i]) &&
+ (megasas_mgmt_info.instance[i]->host->host_no == host_no))
+ return megasas_mgmt_info.instance[i];
+ }
+
+ return NULL;
+}
+
static int megasas_slave_configure(struct scsi_device *sdev)
{
+ u16 pd_index = 0;
+ struct megasas_instance *instance ;
+
+ instance = megasas_lookup_instance(sdev->host->host_no);
+
/*
- * Don't export physical disk devices to the disk driver.
- *
- * FIXME: Currently we don't export them to the midlayer at all.
- * That will be fixed once LSI engineers have audited the
- * firmware for possible issues.
- */
- if (sdev->channel < MEGASAS_MAX_PD_CHANNELS && sdev->type == TYPE_DISK)
+ * Don't export physical disk devices to the disk driver.
+ *
+ * FIXME: Currently we don't export them to the midlayer at all.
+ * That will be fixed once LSI engineers have audited the
+ * firmware for possible issues.
+ */
+ if (sdev->channel < MEGASAS_MAX_PD_CHANNELS &&
+ sdev->type == TYPE_DISK) {
+ pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
+ sdev->id;
+ if (instance->pd_list[pd_index].driveState ==
+ MR_PD_STATE_SYSTEM) {
+ blk_queue_rq_timeout(sdev->request_queue,
+ MEGASAS_DEFAULT_CMD_TIMEOUT * HZ);
+ return 0;
+ }
return -ENXIO;
+ }
/*
- * The RAID firmware may require extended timeouts.
- */
- if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS)
- blk_queue_rq_timeout(sdev->request_queue,
- MEGASAS_DEFAULT_CMD_TIMEOUT * HZ);
+ * The RAID firmware may require extended timeouts.
+ */
+ blk_queue_rq_timeout(sdev->request_queue,
+ MEGASAS_DEFAULT_CMD_TIMEOUT * HZ);
+ return 0;
+}
+
+static int megasas_slave_alloc(struct scsi_device *sdev)
+{
+ u16 pd_index = 0;
+ struct megasas_instance *instance ;
+ instance = megasas_lookup_instance(sdev->host->host_no);
+ if ((sdev->channel < MEGASAS_MAX_PD_CHANNELS) &&
+ (sdev->type == TYPE_DISK)) {
+ /*
+ * Open the OS scan to the SYSTEM PD
+ */
+ pd_index =
+ (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
+ sdev->id;
+ if ((instance->pd_list[pd_index].driveState ==
+ MR_PD_STATE_SYSTEM) &&
+ (instance->pd_list[pd_index].driveType ==
+ TYPE_DISK)) {
+ return 0;
+ }
+ return -ENXIO;
+ }
return 0;
}
@@ -1072,7 +1311,14 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
spin_lock_irqsave(instance->host->host_lock, flags);
instance->flag &= ~MEGASAS_FW_BUSY;
- instance->host->can_queue =
+ if ((instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ instance->host->can_queue =
+ instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
+ } else
+ instance->host->can_queue =
instance->max_fw_cmds - MEGASAS_INT_CMDS;
spin_unlock_irqrestore(instance->host->host_lock, flags);
@@ -1117,8 +1363,16 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
* Send signal to FW to stop processing any pending cmds.
* The controller will be taken offline by the OS now.
*/
- writel(MFI_STOP_ADP,
+ if ((instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ writel(MFI_STOP_ADP,
+ &instance->reg_set->reserved_0[0]);
+ } else {
+ writel(MFI_STOP_ADP,
&instance->reg_set->inbound_doorbell);
+ }
megasas_dump_pending_frames(instance);
instance->hw_crit_error = 1;
return FAILED;
@@ -1266,6 +1520,8 @@ megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev,
return 0;
}
+static void megasas_aen_polling(struct work_struct *work);
+
/**
* megasas_service_aen - Processes an event notification
* @instance: Adapter soft state
@@ -1281,16 +1537,36 @@ megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev,
static void
megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
{
+ unsigned long flags;
/*
* Don't signal app if it is just an aborted previously registered aen
*/
- if (!cmd->abort_aen)
+ if ((!cmd->abort_aen) && (instance->unload == 0)) {
+ spin_lock_irqsave(&poll_aen_lock, flags);
+ megasas_poll_wait_aen = 1;
+ spin_unlock_irqrestore(&poll_aen_lock, flags);
+ wake_up(&megasas_poll_wait);
kill_fasync(&megasas_async_queue, SIGIO, POLL_IN);
+ }
else
cmd->abort_aen = 0;
instance->aen_cmd = NULL;
megasas_return_cmd(instance, cmd);
+
+ if (instance->unload == 0) {
+ struct megasas_aen_event *ev;
+ ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+ if (!ev) {
+ printk(KERN_ERR "megasas_service_aen: out of memory\n");
+ } else {
+ ev->instance = instance;
+ instance->ev = ev;
+ INIT_WORK(&ev->hotplug_work, megasas_aen_polling);
+ schedule_delayed_work(
+ (struct delayed_work *)&ev->hotplug_work, 0);
+ }
+ }
}
/*
@@ -1302,6 +1578,7 @@ static struct scsi_host_template megasas_template = {
.name = "LSI SAS based MegaRAID driver",
.proc_name = "megaraid_sas",
.slave_configure = megasas_slave_configure,
+ .slave_alloc = megasas_slave_alloc,
.queuecommand = megasas_queue_command,
.eh_device_reset_handler = megasas_reset_device,
.eh_bus_reset_handler = megasas_reset_bus_host,
@@ -1370,6 +1647,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
{
int exception = 0;
struct megasas_header *hdr = &cmd->frame->hdr;
+ unsigned long flags;
if (cmd->scmd)
cmd->scmd->SCp.ptr = NULL;
@@ -1459,6 +1737,12 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
case MFI_CMD_SMP:
case MFI_CMD_STP:
case MFI_CMD_DCMD:
+ if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET_INFO ||
+ cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET) {
+ spin_lock_irqsave(&poll_aen_lock, flags);
+ megasas_poll_wait_aen = 0;
+ spin_unlock_irqrestore(&poll_aen_lock, flags);
+ }
/*
* See if got an event notification
@@ -1536,6 +1820,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
u8 max_wait;
u32 fw_state;
u32 cur_state;
+ u32 abs_state, curr_abs_state;
fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
@@ -1545,6 +1830,9 @@ megasas_transition_to_ready(struct megasas_instance* instance)
while (fw_state != MFI_STATE_READY) {
+ abs_state =
+ instance->instancet->read_fw_status_reg(instance->reg_set);
+
switch (fw_state) {
case MFI_STATE_FAULT:
@@ -1556,18 +1844,36 @@ megasas_transition_to_ready(struct megasas_instance* instance)
/*
* Set the CLR bit in inbound doorbell
*/
- writel(MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
- &instance->reg_set->inbound_doorbell);
+ if ((instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+
+ writel(
+ MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
+ &instance->reg_set->reserved_0[0]);
+ } else {
+ writel(
+ MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
+ &instance->reg_set->inbound_doorbell);
+ }
- max_wait = 2;
+ max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_WAIT_HANDSHAKE;
break;
case MFI_STATE_BOOT_MESSAGE_PENDING:
- writel(MFI_INIT_HOTPLUG,
- &instance->reg_set->inbound_doorbell);
+ if ((instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ writel(MFI_INIT_HOTPLUG,
+ &instance->reg_set->reserved_0[0]);
+ } else
+ writel(MFI_INIT_HOTPLUG,
+ &instance->reg_set->inbound_doorbell);
- max_wait = 10;
+ max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
break;
@@ -1576,9 +1882,17 @@ megasas_transition_to_ready(struct megasas_instance* instance)
* Bring it to READY state; assuming max wait 10 secs
*/
instance->instancet->disable_intr(instance->reg_set);
- writel(MFI_RESET_FLAGS, &instance->reg_set->inbound_doorbell);
+ if ((instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ writel(MFI_RESET_FLAGS,
+ &instance->reg_set->reserved_0[0]);
+ } else
+ writel(MFI_RESET_FLAGS,
+ &instance->reg_set->inbound_doorbell);
- max_wait = 60;
+ max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_OPERATIONAL;
break;
@@ -1586,32 +1900,32 @@ megasas_transition_to_ready(struct megasas_instance* instance)
/*
* This state should not last for more than 2 seconds
*/
- max_wait = 2;
+ max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_UNDEFINED;
break;
case MFI_STATE_BB_INIT:
- max_wait = 2;
+ max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_BB_INIT;
break;
case MFI_STATE_FW_INIT:
- max_wait = 20;
+ max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_FW_INIT;
break;
case MFI_STATE_FW_INIT_2:
- max_wait = 20;
+ max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_FW_INIT_2;
break;
case MFI_STATE_DEVICE_SCAN:
- max_wait = 20;
+ max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_DEVICE_SCAN;
break;
case MFI_STATE_FLUSH_CACHE:
- max_wait = 20;
+ max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_FLUSH_CACHE;
break;
@@ -1627,8 +1941,10 @@ megasas_transition_to_ready(struct megasas_instance* instance)
for (i = 0; i < (max_wait * 1000); i++) {
fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) &
MFI_STATE_MASK ;
+ curr_abs_state =
+ instance->instancet->read_fw_status_reg(instance->reg_set);
- if (fw_state == cur_state) {
+ if (abs_state == curr_abs_state) {
msleep(1);
} else
break;
@@ -1637,7 +1953,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
/*
* Return error if fw_state hasn't changed after max_wait
*/
- if (fw_state == cur_state) {
+ if (curr_abs_state == abs_state) {
printk(KERN_DEBUG "FW state [%d] hasn't changed "
"in %d secs\n", fw_state, max_wait);
return -ENODEV;
@@ -1715,6 +2031,10 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
sizeof(struct megasas_sge32);
+ if (instance->flag_ieee) {
+ sge_sz = sizeof(struct megasas_sge_skinny);
+ }
+
/*
* Calculated the number of 64byte frames required for SGL
*/
@@ -1777,6 +2097,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
}
cmd->frame->io.context = cmd->index;
+ cmd->frame->io.pad_0 = 0;
}
return 0;
@@ -1882,6 +2203,97 @@ static int megasas_alloc_cmds(struct megasas_instance *instance)
return 0;
}
+/*
+ * megasas_get_pd_list_info - Returns FW's pd_list structure
+ * @instance: Adapter soft state
+ * @pd_list: pd_list structure
+ *
+ * Issues an internal command (DCMD) to get the FW's controller PD
+ * list structure. This information is mainly used to find out SYSTEM
+ * supported by the FW.
+ */
+static int
+megasas_get_pd_list(struct megasas_instance *instance)
+{
+ int ret = 0, pd_index = 0;
+ struct megasas_cmd *cmd;
+ struct megasas_dcmd_frame *dcmd;
+ struct MR_PD_LIST *ci;
+ struct MR_PD_ADDRESS *pd_addr;
+ dma_addr_t ci_h = 0;
+
+ cmd = megasas_get_cmd(instance);
+
+ if (!cmd) {
+ printk(KERN_DEBUG "megasas (get_pd_list): Failed to get cmd\n");
+ return -ENOMEM;
+ }
+
+ dcmd = &cmd->frame->dcmd;
+
+ ci = pci_alloc_consistent(instance->pdev,
+ MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST), &ci_h);
+
+ if (!ci) {
+ printk(KERN_DEBUG "Failed to alloc mem for pd_list\n");
+ megasas_return_cmd(instance, cmd);
+ return -ENOMEM;
+ }
+
+ memset(ci, 0, sizeof(*ci));
+ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+ dcmd->mbox.b[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST;
+ dcmd->mbox.b[1] = 0;
+ dcmd->cmd = MFI_CMD_DCMD;
+ dcmd->cmd_status = 0xFF;
+ dcmd->sge_count = 1;
+ dcmd->flags = MFI_FRAME_DIR_READ;
+ dcmd->timeout = 0;
+ dcmd->data_xfer_len = MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST);
+ dcmd->opcode = MR_DCMD_PD_LIST_QUERY;
+ dcmd->sgl.sge32[0].phys_addr = ci_h;
+ dcmd->sgl.sge32[0].length = MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST);
+
+ if (!megasas_issue_polled(instance, cmd)) {
+ ret = 0;
+ } else {
+ ret = -1;
+ }
+
+ /*
+ * the following function will get the instance PD LIST.
+ */
+
+ pd_addr = ci->addr;
+
+ if ( ret == 0 &&
+ (ci->count <
+ (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL))) {
+
+ memset(instance->pd_list, 0,
+ MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
+
+ for (pd_index = 0; pd_index < ci->count; pd_index++) {
+
+ instance->pd_list[pd_addr->deviceId].tid =
+ pd_addr->deviceId;
+ instance->pd_list[pd_addr->deviceId].driveType =
+ pd_addr->scsiDevType;
+ instance->pd_list[pd_addr->deviceId].driveState =
+ MR_PD_STATE_SYSTEM;
+ pd_addr++;
+ }
+ }
+
+ pci_free_consistent(instance->pdev,
+ MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST),
+ ci, ci_h);
+ megasas_return_cmd(instance, cmd);
+
+ return ret;
+}
+
/**
* megasas_get_controller_info - Returns FW's controller structure
* @instance: Adapter soft state
@@ -2081,6 +2493,8 @@ static int megasas_init_mfi(struct megasas_instance *instance)
* Map the message registers
*/
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078GEN2) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0079GEN2)) {
instance->base_addr = pci_resource_start(instance->pdev, 1);
} else {
@@ -2111,6 +2525,10 @@ static int megasas_init_mfi(struct megasas_instance *instance)
case PCI_DEVICE_ID_LSI_SAS0079GEN2:
instance->instancet = &megasas_instance_template_gen2;
break;
+ case PCI_DEVICE_ID_LSI_SAS0073SKINNY:
+ case PCI_DEVICE_ID_LSI_SAS0071SKINNY:
+ instance->instancet = &megasas_instance_template_skinny;
+ break;
case PCI_DEVICE_ID_LSI_SAS1064R:
case PCI_DEVICE_ID_DELL_PERC5:
default:
@@ -2166,6 +2584,10 @@ static int megasas_init_mfi(struct megasas_instance *instance)
if (megasas_issue_init_mfi(instance))
goto fail_fw_init;
+ memset(instance->pd_list, 0 ,
+ (MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)));
+ megasas_get_pd_list(instance);
+
ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL);
/*
@@ -2409,6 +2831,11 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
dcmd->sgl.sge32[0].phys_addr = (u32) instance->evt_detail_h;
dcmd->sgl.sge32[0].length = sizeof(struct megasas_evt_detail);
+ if (instance->aen_cmd != NULL) {
+ megasas_return_cmd(instance, cmd);
+ return 0;
+ }
+
/*
* Store reference to the cmd used to register for AEN. When an
* application wants us to register for AEN, we have to abort this
@@ -2419,7 +2846,8 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
/*
* Issue the aen registration frame
*/
- instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
+ instance->instancet->fire_cmd(instance,
+ cmd->frame_phys_addr, 0, instance->reg_set);
return 0;
}
@@ -2465,7 +2893,13 @@ static int megasas_io_attach(struct megasas_instance *instance)
*/
host->irq = instance->pdev->irq;
host->unique_id = instance->unique_id;
- host->can_queue = instance->max_fw_cmds - MEGASAS_INT_CMDS;
+ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ host->can_queue =
+ instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
+ } else
+ host->can_queue =
+ instance->max_fw_cmds - MEGASAS_INT_CMDS;
host->this_id = instance->init_id;
host->sg_tablesize = instance->max_num_sge;
host->max_sectors = instance->max_sectors_per_req;
@@ -2572,6 +3006,9 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
*instance->producer = 0;
*instance->consumer = 0;
+ megasas_poll_wait_aen = 0;
+ instance->flag_ieee = 0;
+ instance->ev = NULL;
instance->evt_detail = pci_alloc_consistent(pdev,
sizeof(struct
@@ -2595,10 +3032,11 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
init_waitqueue_head(&instance->abort_cmd_wait_q);
spin_lock_init(&instance->cmd_pool_lock);
+ spin_lock_init(&instance->fire_lock);
spin_lock_init(&instance->completion_lock);
+ spin_lock_init(&poll_aen_lock);
mutex_init(&instance->aen_mutex);
- sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);
/*
* Initialize PCI related and misc parameters
@@ -2608,8 +3046,16 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
instance->unique_id = pdev->bus->number << 8 | pdev->devfn;
instance->init_id = MEGASAS_DEFAULT_INIT_ID;
+ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ instance->flag_ieee = 1;
+ sema_init(&instance->ioctl_sem, MEGASAS_SKINNY_INT_CMDS);
+ } else
+ sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);
+
megasas_dbg_lvl = 0;
instance->flag = 0;
+ instance->unload = 1;
instance->last_time = 0;
/*
@@ -2655,6 +3101,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (megasas_io_attach(instance))
goto fail_io_attach;
+ instance->unload = 0;
return 0;
fail_start_aen:
@@ -2778,12 +3225,23 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
instance = pci_get_drvdata(pdev);
host = instance->host;
+ instance->unload = 1;
if (poll_mode_io)
del_timer_sync(&instance->io_completion_timer);
megasas_flush_cache(instance);
megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
+
+ /* cancel the delayed work if this work still in queue */
+ if (instance->ev != NULL) {
+ struct megasas_aen_event *ev = instance->ev;
+ cancel_delayed_work(
+ (struct delayed_work *)&ev->hotplug_work);
+ flush_scheduled_work();
+ instance->ev = NULL;
+ }
+
tasklet_kill(&instance->isr_tasklet);
pci_set_drvdata(instance->pdev, instance);
@@ -2873,6 +3331,8 @@ megasas_resume(struct pci_dev *pdev)
megasas_start_timer(instance, &instance->io_completion_timer,
megasas_io_completion_timer,
MEGASAS_COMPLETION_TIMER_INTERVAL);
+ instance->unload = 0;
+
return 0;
fail_irq:
@@ -2913,6 +3373,7 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
struct megasas_instance *instance;
instance = pci_get_drvdata(pdev);
+ instance->unload = 1;
host = instance->host;
if (poll_mode_io)
@@ -2921,6 +3382,16 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
scsi_remove_host(instance->host);
megasas_flush_cache(instance);
megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
+
+ /* cancel the delayed work if this work still in queue*/
+ if (instance->ev != NULL) {
+ struct megasas_aen_event *ev = instance->ev;
+ cancel_delayed_work(
+ (struct delayed_work *)&ev->hotplug_work);
+ flush_scheduled_work();
+ instance->ev = NULL;
+ }
+
tasklet_kill(&instance->isr_tasklet);
/*
@@ -2969,6 +3440,7 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
static void megasas_shutdown(struct pci_dev *pdev)
{
struct megasas_instance *instance = pci_get_drvdata(pdev);
+ instance->unload = 1;
megasas_flush_cache(instance);
megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
}
@@ -3016,6 +3488,23 @@ static int megasas_mgmt_fasync(int fd, struct file *filep, int mode)
}
/**
+ * megasas_mgmt_poll - char node "poll" entry point
+ * */
+static unsigned int megasas_mgmt_poll(struct file *file, poll_table *wait)
+{
+ unsigned int mask;
+ unsigned long flags;
+ poll_wait(file, &megasas_poll_wait, wait);
+ spin_lock_irqsave(&poll_aen_lock, flags);
+ if (megasas_poll_wait_aen)
+ mask = (POLLIN | POLLRDNORM);
+ else
+ mask = 0;
+ spin_unlock_irqrestore(&poll_aen_lock, flags);
+ return mask;
+}
+
+/**
* megasas_mgmt_fw_ioctl - Issues management ioctls to FW
* @instance: Adapter soft state
* @argp: User's ioctl packet
@@ -3032,7 +3521,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
int error = 0, i;
void *sense = NULL;
dma_addr_t sense_handle;
- u32 *sense_ptr;
+ unsigned long *sense_ptr;
memset(kbuff_arr, 0, sizeof(kbuff_arr));
@@ -3056,6 +3545,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
*/
memcpy(cmd->frame, ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE);
cmd->frame->hdr.context = cmd->index;
+ cmd->frame->hdr.pad_0 = 0;
/*
* The management interface between applications and the fw uses
@@ -3109,7 +3599,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
}
sense_ptr =
- (u32 *) ((unsigned long)cmd->frame + ioc->sense_off);
+ (unsigned long *) ((unsigned long)cmd->frame + ioc->sense_off);
*sense_ptr = sense_handle;
}
@@ -3140,8 +3630,8 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
* sense_ptr points to the location that has the user
* sense buffer address
*/
- sense_ptr = (u32 *) ((unsigned long)ioc->frame.raw +
- ioc->sense_off);
+ sense_ptr = (unsigned long *) ((unsigned long)ioc->frame.raw +
+ ioc->sense_off);
if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)),
sense, ioc->sense_len)) {
@@ -3177,20 +3667,6 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
return error;
}
-static struct megasas_instance *megasas_lookup_instance(u16 host_no)
-{
- int i;
-
- for (i = 0; i < megasas_mgmt_info.max_index; i++) {
-
- if ((megasas_mgmt_info.instance[i]) &&
- (megasas_mgmt_info.instance[i]->host->host_no == host_no))
- return megasas_mgmt_info.instance[i];
- }
-
- return NULL;
-}
-
static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
{
struct megasas_iocpacket __user *user_ioc =
@@ -3214,6 +3690,17 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
goto out_kfree_ioc;
}
+ if (instance->hw_crit_error == 1) {
+ printk(KERN_DEBUG "Controller in Crit ERROR\n");
+ error = -ENODEV;
+ goto out_kfree_ioc;
+ }
+
+ if (instance->unload == 1) {
+ error = -ENODEV;
+ goto out_kfree_ioc;
+ }
+
/*
* We will allow only MEGASAS_INT_CMDS number of parallel ioctl cmds
*/
@@ -3249,6 +3736,14 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
if (!instance)
return -ENODEV;
+ if (instance->hw_crit_error == 1) {
+ error = -ENODEV;
+ }
+
+ if (instance->unload == 1) {
+ return -ENODEV;
+ }
+
mutex_lock(&instance->aen_mutex);
error = megasas_register_aen(instance, aen.seq_num,
aen.class_locale_word);
@@ -3337,6 +3832,7 @@ static const struct file_operations megasas_mgmt_fops = {
.open = megasas_mgmt_open,
.fasync = megasas_mgmt_fasync,
.unlocked_ioctl = megasas_mgmt_ioctl,
+ .poll = megasas_mgmt_poll,
#ifdef CONFIG_COMPAT
.compat_ioctl = megasas_mgmt_compat_ioctl,
#endif
@@ -3378,6 +3874,15 @@ static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date,
NULL);
static ssize_t
+megasas_sysfs_show_support_poll_for_event(struct device_driver *dd, char *buf)
+{
+ return sprintf(buf, "%u\n", support_poll_for_event);
+}
+
+static DRIVER_ATTR(support_poll_for_event, S_IRUGO,
+ megasas_sysfs_show_support_poll_for_event, NULL);
+
+static ssize_t
megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
{
return sprintf(buf, "%u\n", megasas_dbg_lvl);
@@ -3451,6 +3956,92 @@ out:
return retval;
}
+static void
+megasas_aen_polling(struct work_struct *work)
+{
+ struct megasas_aen_event *ev =
+ container_of(work, struct megasas_aen_event, hotplug_work);
+ struct megasas_instance *instance = ev->instance;
+ union megasas_evt_class_locale class_locale;
+ struct Scsi_Host *host;
+ struct scsi_device *sdev1;
+ u16 pd_index = 0;
+ int i, j, doscan = 0;
+ u32 seq_num;
+ int error;
+
+ if (!instance) {
+ printk(KERN_ERR "invalid instance!\n");
+ kfree(ev);
+ return;
+ }
+ instance->ev = NULL;
+ host = instance->host;
+ if (instance->evt_detail) {
+
+ switch (instance->evt_detail->code) {
+ case MR_EVT_PD_INSERTED:
+ case MR_EVT_PD_REMOVED:
+ case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
+ doscan = 1;
+ break;
+ default:
+ doscan = 0;
+ break;
+ }
+ } else {
+ printk(KERN_ERR "invalid evt_detail!\n");
+ kfree(ev);
+ return;
+ }
+
+ if (doscan) {
+ printk(KERN_INFO "scanning ...\n");
+ megasas_get_pd_list(instance);
+ for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
+ for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+ pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
+ sdev1 = scsi_device_lookup(host, i, j, 0);
+ if (instance->pd_list[pd_index].driveState ==
+ MR_PD_STATE_SYSTEM) {
+ if (!sdev1) {
+ scsi_add_device(host, i, j, 0);
+ }
+ if (sdev1)
+ scsi_device_put(sdev1);
+ } else {
+ if (sdev1) {
+ scsi_remove_device(sdev1);
+ scsi_device_put(sdev1);
+ }
+ }
+ }
+ }
+ }
+
+ if ( instance->aen_cmd != NULL ) {
+ kfree(ev);
+ return ;
+ }
+
+ seq_num = instance->evt_detail->seq_num + 1;
+
+ /* Register AEN with FW for latest sequence number plus 1 */
+ class_locale.members.reserved = 0;
+ class_locale.members.locale = MR_EVT_LOCALE_ALL;
+ class_locale.members.class = MR_EVT_CLASS_DEBUG;
+ mutex_lock(&instance->aen_mutex);
+ error = megasas_register_aen(instance, seq_num,
+ class_locale.word);
+ mutex_unlock(&instance->aen_mutex);
+
+ if (error)
+ printk(KERN_ERR "register aen failed error %x\n", error);
+
+ kfree(ev);
+}
+
+
static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUGO,
megasas_sysfs_show_poll_mode_io,
megasas_sysfs_set_poll_mode_io);
@@ -3468,6 +4059,8 @@ static int __init megasas_init(void)
printk(KERN_INFO "megasas: %s %s\n", MEGASAS_VERSION,
MEGASAS_EXT_VERSION);
+ support_poll_for_event = 2;
+
memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info));
/*
@@ -3500,6 +4093,12 @@ static int __init megasas_init(void)
&driver_attr_release_date);
if (rval)
goto err_dcf_rel_date;
+
+ rval = driver_create_file(&megasas_pci_driver.driver,
+ &driver_attr_support_poll_for_event);
+ if (rval)
+ goto err_dcf_support_poll_for_event;
+
rval = driver_create_file(&megasas_pci_driver.driver,
&driver_attr_dbg_lvl);
if (rval)
@@ -3516,7 +4115,12 @@ err_dcf_poll_mode_io:
&driver_attr_dbg_lvl);
err_dcf_dbg_lvl:
driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_support_poll_for_event);
+
+err_dcf_support_poll_for_event:
+ driver_remove_file(&megasas_pci_driver.driver,
&driver_attr_release_date);
+
err_dcf_rel_date:
driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
err_dcf_attr_ver:
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 0d033248fdf1..72b28e436e32 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -18,9 +18,9 @@
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "00.00.04.01"
-#define MEGASAS_RELDATE "July 24, 2008"
-#define MEGASAS_EXT_VERSION "Thu July 24 11:41:51 PST 2008"
+#define MEGASAS_VERSION "00.00.04.12-rc1"
+#define MEGASAS_RELDATE "Sep. 17, 2009"
+#define MEGASAS_EXT_VERSION "Thu Sep. 17 11:41:51 PST 2009"
/*
* Device IDs
@@ -30,6 +30,8 @@
#define PCI_DEVICE_ID_LSI_VERDE_ZCR 0x0413
#define PCI_DEVICE_ID_LSI_SAS1078GEN2 0x0078
#define PCI_DEVICE_ID_LSI_SAS0079GEN2 0x0079
+#define PCI_DEVICE_ID_LSI_SAS0073SKINNY 0x0073
+#define PCI_DEVICE_ID_LSI_SAS0071SKINNY 0x0071
/*
* =====================================
@@ -94,6 +96,7 @@
#define MFI_FRAME_DIR_WRITE 0x0008
#define MFI_FRAME_DIR_READ 0x0010
#define MFI_FRAME_DIR_BOTH 0x0018
+#define MFI_FRAME_IEEE 0x0020
/*
* Definition for cmd_status
@@ -131,6 +134,7 @@
#define MR_DCMD_CLUSTER 0x08000000
#define MR_DCMD_CLUSTER_RESET_ALL 0x08010100
#define MR_DCMD_CLUSTER_RESET_LD 0x08010200
+#define MR_DCMD_PD_LIST_QUERY 0x02010100
/*
* MFI command completion codes
@@ -251,9 +255,100 @@ enum MR_EVT_ARGS {
MR_EVT_ARGS_STR,
MR_EVT_ARGS_TIME,
MR_EVT_ARGS_ECC,
+ MR_EVT_ARGS_LD_PROP,
+ MR_EVT_ARGS_PD_SPARE,
+ MR_EVT_ARGS_PD_INDEX,
+ MR_EVT_ARGS_DIAG_PASS,
+ MR_EVT_ARGS_DIAG_FAIL,
+ MR_EVT_ARGS_PD_LBA_LBA,
+ MR_EVT_ARGS_PORT_PHY,
+ MR_EVT_ARGS_PD_MISSING,
+ MR_EVT_ARGS_PD_ADDRESS,
+ MR_EVT_ARGS_BITMAP,
+ MR_EVT_ARGS_CONNECTOR,
+ MR_EVT_ARGS_PD_PD,
+ MR_EVT_ARGS_PD_FRU,
+ MR_EVT_ARGS_PD_PATHINFO,
+ MR_EVT_ARGS_PD_POWER_STATE,
+ MR_EVT_ARGS_GENERIC,
+};
+/*
+ * define constants for device list query options
+ */
+enum MR_PD_QUERY_TYPE {
+ MR_PD_QUERY_TYPE_ALL = 0,
+ MR_PD_QUERY_TYPE_STATE = 1,
+ MR_PD_QUERY_TYPE_POWER_STATE = 2,
+ MR_PD_QUERY_TYPE_MEDIA_TYPE = 3,
+ MR_PD_QUERY_TYPE_SPEED = 4,
+ MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5,
};
+#define MR_EVT_CFG_CLEARED 0x0004
+#define MR_EVT_LD_STATE_CHANGE 0x0051
+#define MR_EVT_PD_INSERTED 0x005b
+#define MR_EVT_PD_REMOVED 0x0070
+#define MR_EVT_LD_CREATED 0x008a
+#define MR_EVT_LD_DELETED 0x008b
+#define MR_EVT_FOREIGN_CFG_IMPORTED 0x00db
+#define MR_EVT_LD_OFFLINE 0x00fc
+#define MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED 0x0152
+#define MAX_LOGICAL_DRIVES 64
+
+enum MR_PD_STATE {
+ MR_PD_STATE_UNCONFIGURED_GOOD = 0x00,
+ MR_PD_STATE_UNCONFIGURED_BAD = 0x01,
+ MR_PD_STATE_HOT_SPARE = 0x02,
+ MR_PD_STATE_OFFLINE = 0x10,
+ MR_PD_STATE_FAILED = 0x11,
+ MR_PD_STATE_REBUILD = 0x14,
+ MR_PD_STATE_ONLINE = 0x18,
+ MR_PD_STATE_COPYBACK = 0x20,
+ MR_PD_STATE_SYSTEM = 0x40,
+ };
+
+
+ /*
+ * defines the physical drive address structure
+ */
+struct MR_PD_ADDRESS {
+ u16 deviceId;
+ u16 enclDeviceId;
+
+ union {
+ struct {
+ u8 enclIndex;
+ u8 slotNumber;
+ } mrPdAddress;
+ struct {
+ u8 enclPosition;
+ u8 enclConnectorIndex;
+ } mrEnclAddress;
+ };
+ u8 scsiDevType;
+ union {
+ u8 connectedPortBitmap;
+ u8 connectedPortNumbers;
+ };
+ u64 sasAddr[2];
+} __packed;
+
+/*
+ * defines the physical drive list structure
+ */
+struct MR_PD_LIST {
+ u32 size;
+ u32 count;
+ struct MR_PD_ADDRESS addr[1];
+} __packed;
+
+struct megasas_pd_list {
+ u16 tid;
+ u8 driveType;
+ u8 driveState;
+} __packed;
+
/*
* SAS controller properties
*/
@@ -282,7 +377,7 @@ struct megasas_ctrl_prop {
u8 expose_encl_devices;
u8 reserved[38];
-} __attribute__ ((packed));
+} __packed;
/*
* SAS controller information
@@ -525,7 +620,7 @@ struct megasas_ctrl_info {
u8 pad[0x800 - 0x6a0];
-} __attribute__ ((packed));
+} __packed;
/*
* ===============================
@@ -540,6 +635,8 @@ struct megasas_ctrl_info {
#define MEGASAS_DEFAULT_INIT_ID -1
#define MEGASAS_MAX_LUN 8
#define MEGASAS_MAX_LD 64
+#define MEGASAS_MAX_PD (MEGASAS_MAX_PD_CHANNELS * \
+ MEGASAS_MAX_DEV_PER_CHANNEL)
#define MEGASAS_DBG_LVL 1
@@ -570,6 +667,7 @@ struct megasas_ctrl_info {
* is shown below
*/
#define MEGASAS_INT_CMDS 32
+#define MEGASAS_SKINNY_INT_CMDS 5
/*
* FW can accept both 32 and 64 bit SGLs. We want to allocate 32/64 bit
@@ -584,6 +682,8 @@ struct megasas_ctrl_info {
#define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000
#define MFI_REPLY_GEN2_MESSAGE_INTERRUPT 0x00000001
#define MFI_GEN2_ENABLE_INTERRUPT_MASK (0x00000001 | 0x00000004)
+#define MFI_REPLY_SKINNY_MESSAGE_INTERRUPT 0x40000000
+#define MFI_SKINNY_ENABLE_INTERRUPT_MASK (0x00000001)
/*
* register set for both 1068 and 1078 controllers
@@ -644,10 +744,17 @@ struct megasas_sge64 {
} __attribute__ ((packed));
+struct megasas_sge_skinny {
+ u64 phys_addr;
+ u32 length;
+ u32 flag;
+} __packed;
+
union megasas_sgl {
struct megasas_sge32 sge32[1];
struct megasas_sge64 sge64[1];
+ struct megasas_sge_skinny sge_skinny[1];
} __attribute__ ((packed));
@@ -1061,16 +1168,10 @@ struct megasas_evt_detail {
} __attribute__ ((packed));
- struct megasas_instance_template {
- void (*fire_cmd)(dma_addr_t ,u32 ,struct megasas_register_set __iomem *);
-
- void (*enable_intr)(struct megasas_register_set __iomem *) ;
- void (*disable_intr)(struct megasas_register_set __iomem *);
-
- int (*clear_intr)(struct megasas_register_set __iomem *);
-
- u32 (*read_fw_status_reg)(struct megasas_register_set __iomem *);
- };
+struct megasas_aen_event {
+ struct work_struct hotplug_work;
+ struct megasas_instance *instance;
+};
struct megasas_instance {
@@ -1085,17 +1186,21 @@ struct megasas_instance {
unsigned long base_addr;
struct megasas_register_set __iomem *reg_set;
+ struct megasas_pd_list pd_list[MEGASAS_MAX_PD];
s8 init_id;
u16 max_num_sge;
u16 max_fw_cmds;
u32 max_sectors_per_req;
+ struct megasas_aen_event *ev;
struct megasas_cmd **cmd_list;
struct list_head cmd_pool;
spinlock_t cmd_pool_lock;
/* used to synch producer, consumer ptrs in dpc */
spinlock_t completion_lock;
+ /* used to sync fire the cmd to fw */
+ spinlock_t fire_lock;
struct dma_pool *frame_dma_pool;
struct dma_pool *sense_dma_pool;
@@ -1120,11 +1225,25 @@ struct megasas_instance {
struct tasklet_struct isr_tasklet;
u8 flag;
+ u8 unload;
+ u8 flag_ieee;
unsigned long last_time;
struct timer_list io_completion_timer;
};
+struct megasas_instance_template {
+ void (*fire_cmd)(struct megasas_instance *, dma_addr_t, \
+ u32, struct megasas_register_set __iomem *);
+
+ void (*enable_intr)(struct megasas_register_set __iomem *) ;
+ void (*disable_intr)(struct megasas_register_set __iomem *);
+
+ int (*clear_intr)(struct megasas_register_set __iomem *);
+
+ u32 (*read_fw_status_reg)(struct megasas_register_set __iomem *);
+};
+
#define MEGASAS_IS_LOGICAL(scp) \
(scp->device->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h
index f9f6c0839276..914168105297 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2.h
@@ -8,7 +8,7 @@
* scatter/gather formats.
* Creation Date: June 21, 2006
*
- * mpi2.h Version: 02.00.12
+ * mpi2.h Version: 02.00.13
*
* Version History
* ---------------
@@ -52,6 +52,7 @@
* MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those
* bytes reserved.
* Added RAID Accelerator functionality.
+ * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
*/
@@ -77,7 +78,7 @@
#define MPI2_VERSION_02_00 (0x0200)
/* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x0C)
+#define MPI2_HEADER_VERSION_UNIT (0x0D)
#define MPI2_HEADER_VERSION_DEV (0x00)
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
index ab47c4679640..1611c57a6fdf 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
@@ -6,7 +6,7 @@
* Title: MPI Configuration messages and pages
* Creation Date: November 10, 2006
*
- * mpi2_cnfg.h Version: 02.00.11
+ * mpi2_cnfg.h Version: 02.00.12
*
* Version History
* ---------------
@@ -100,6 +100,13 @@
* Added expander reduced functionality data to SAS
* Expander Page 0.
* Added SAS PHY Page 2 and SAS PHY Page 3.
+ * 07-30-09 02.00.12 Added IO Unit Page 7.
+ * Added new device ids.
+ * Added SAS IO Unit Page 5.
+ * Added partial and slumber power management capable flags
+ * to SAS Device Page 0 Flags field.
+ * Added PhyInfo defines for power condition.
+ * Added Ethernet configuration pages.
* --------------------------------------------------------------------------
*/
@@ -182,6 +189,7 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION
#define MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG (0x16)
#define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING (0x17)
#define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18)
+#define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19)
/*****************************************************************************
@@ -268,6 +276,14 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION
#define MPI2_DPM_PGAD_START_ENTRY_MASK (0x0000FFFF)
+/* Ethernet PageAddress format */
+#define MPI2_ETHERNET_PGAD_FORM_MASK (0xF0000000)
+#define MPI2_ETHERNET_PGAD_FORM_IF_NUM (0x00000000)
+
+#define MPI2_ETHERNET_PGAD_IF_NUMBER_MASK (0x000000FF)
+
+
+
/****************************************************************************
* Configuration messages
****************************************************************************/
@@ -349,6 +365,15 @@ typedef struct _MPI2_CONFIG_REPLY
#define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064)
#define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065)
+#define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080)
+#define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081)
+#define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082)
+#define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083)
+#define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084)
+#define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085)
+#define MPI2_MFGPAGE_DEVID_SAS2208_7 (0x0086)
+#define MPI2_MFGPAGE_DEVID_SAS2208_8 (0x0087)
+
/* Manufacturing Page 0 */
@@ -787,6 +812,56 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_6 {
#define MPI2_IOUNITPAGE6_FLAGS_ENABLE_RAID_ACCELERATOR (0x0001)
+/* IO Unit Page 7 */
+
+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 {
+ MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
+ U16 Reserved1; /* 0x04 */
+ U8 PCIeWidth; /* 0x06 */
+ U8 PCIeSpeed; /* 0x07 */
+ U32 ProcessorState; /* 0x08 */
+ U32 Reserved2; /* 0x0C */
+ U16 IOCTemperature; /* 0x10 */
+ U8 IOCTemperatureUnits; /* 0x12 */
+ U8 IOCSpeed; /* 0x13 */
+ U32 Reserved3; /* 0x14 */
+} MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7,
+ Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t;
+
+#define MPI2_IOUNITPAGE7_PAGEVERSION (0x00)
+
+/* defines for IO Unit Page 7 PCIeWidth field */
+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01)
+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X2 (0x02)
+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X4 (0x04)
+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X8 (0x08)
+
+/* defines for IO Unit Page 7 PCIeSpeed field */
+#define MPI2_IOUNITPAGE7_PCIE_SPEED_2_5_GBPS (0x00)
+#define MPI2_IOUNITPAGE7_PCIE_SPEED_5_0_GBPS (0x01)
+#define MPI2_IOUNITPAGE7_PCIE_SPEED_8_0_GBPS (0x02)
+
+/* defines for IO Unit Page 7 ProcessorState field */
+#define MPI2_IOUNITPAGE7_PSTATE_MASK_SECOND (0x0000000F)
+#define MPI2_IOUNITPAGE7_PSTATE_SHIFT_SECOND (0)
+
+#define MPI2_IOUNITPAGE7_PSTATE_NOT_PRESENT (0x00)
+#define MPI2_IOUNITPAGE7_PSTATE_DISABLED (0x01)
+#define MPI2_IOUNITPAGE7_PSTATE_ENABLED (0x02)
+
+/* defines for IO Unit Page 7 IOCTemperatureUnits field */
+#define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00)
+#define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01)
+#define MPI2_IOUNITPAGE7_IOC_TEMP_CELSIUS (0x02)
+
+/* defines for IO Unit Page 7 IOCSpeed field */
+#define MPI2_IOUNITPAGE7_IOC_SPEED_FULL (0x01)
+#define MPI2_IOUNITPAGE7_IOC_SPEED_HALF (0x02)
+#define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER (0x04)
+#define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH (0x08)
+
+
+
/****************************************************************************
* IOC Config Pages
****************************************************************************/
@@ -1470,6 +1545,12 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1
/* values for PhyInfo fields */
#define MPI2_SAS_PHYINFO_PHY_VACANT (0x80000000)
+
+#define MPI2_SAS_PHYINFO_PHY_POWER_CONDITION_MASK (0x18000000)
+#define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE (0x00000000)
+#define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL (0x08000000)
+#define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER (0x10000000)
+
#define MPI2_SAS_PHYINFO_CHANGED_REQ_INSIDE_ZPSDS (0x04000000)
#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS_PERSISTENT (0x02000000)
#define MPI2_SAS_PHYINFO_REQ_INSIDE_ZPSDS (0x01000000)
@@ -1682,11 +1763,11 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1
/* values for SAS IO Unit Page 1 PortFlags */
#define MPI2_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01)
-/* values for SAS IO Unit Page 2 PhyFlags */
+/* values for SAS IO Unit Page 1 PhyFlags */
#define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE (0x10)
#define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08)
-/* values for SAS IO Unit Page 0 MaxMinLinkRate */
+/* values for SAS IO Unit Page 1 MaxMinLinkRate */
#define MPI2_SASIOUNIT1_MAX_RATE_MASK (0xF0)
#define MPI2_SASIOUNIT1_MAX_RATE_1_5 (0x80)
#define MPI2_SASIOUNIT1_MAX_RATE_3_0 (0x90)
@@ -1745,6 +1826,74 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_4
#define MPI2_SASIOUNIT4_PHY_SPINUP_GROUP_MASK (0x03)
+/* SAS IO Unit Page 5 */
+
+typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS {
+ U8 ControlFlags; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 InactivityTimerExponent; /* 0x02 */
+ U8 SATAPartialTimeout; /* 0x04 */
+ U8 Reserved2; /* 0x05 */
+ U8 SATASlumberTimeout; /* 0x06 */
+ U8 Reserved3; /* 0x07 */
+ U8 SASPartialTimeout; /* 0x08 */
+ U8 Reserved4; /* 0x09 */
+ U8 SASSlumberTimeout; /* 0x0A */
+ U8 Reserved5; /* 0x0B */
+} MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS,
+ MPI2_POINTER PTR_MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS,
+ Mpi2SasIOUnit5PhyPmSettings_t, MPI2_POINTER pMpi2SasIOUnit5PhyPmSettings_t;
+
+/* defines for ControlFlags field */
+#define MPI2_SASIOUNIT5_CONTROL_SAS_SLUMBER_ENABLE (0x08)
+#define MPI2_SASIOUNIT5_CONTROL_SAS_PARTIAL_ENABLE (0x04)
+#define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE (0x02)
+#define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE (0x01)
+
+/* defines for InactivityTimerExponent field */
+#define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER (0x7000)
+#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER (12)
+#define MPI2_SASIOUNIT5_ITE_MASK_SAS_PARTIAL (0x0700)
+#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_PARTIAL (8)
+#define MPI2_SASIOUNIT5_ITE_MASK_SATA_SLUMBER (0x0070)
+#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_SLUMBER (4)
+#define MPI2_SASIOUNIT5_ITE_MASK_SATA_PARTIAL (0x0007)
+#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_PARTIAL (0)
+
+#define MPI2_SASIOUNIT5_ITE_TEN_SECONDS (7)
+#define MPI2_SASIOUNIT5_ITE_ONE_SECOND (6)
+#define MPI2_SASIOUNIT5_ITE_HUNDRED_MILLISECONDS (5)
+#define MPI2_SASIOUNIT5_ITE_TEN_MILLISECONDS (4)
+#define MPI2_SASIOUNIT5_ITE_ONE_MILLISECOND (3)
+#define MPI2_SASIOUNIT5_ITE_HUNDRED_MICROSECONDS (2)
+#define MPI2_SASIOUNIT5_ITE_TEN_MICROSECONDS (1)
+#define MPI2_SASIOUNIT5_ITE_ONE_MICROSECOND (0)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.ExtPageLength or NumPhys at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT5_PHY_MAX
+#define MPI2_SAS_IOUNIT5_PHY_MAX (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U8 NumPhys; /* 0x08 */
+ U8 Reserved1; /* 0x09 */
+ U16 Reserved2; /* 0x0A */
+ U32 Reserved3; /* 0x0C */
+ MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS SASPhyPowerManagementSettings
+ [MPI2_SAS_IOUNIT5_PHY_MAX]; /* 0x10 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_5,
+ MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5,
+ Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t;
+
+#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x00)
+
+
+
+
/****************************************************************************
* SAS Expander Config Pages
****************************************************************************/
@@ -1927,6 +2076,8 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0
/* see mpi2_sas.h for values for SAS Device Page 0 DeviceInfo values */
/* values for SAS Device Page 0 Flags field */
+#define MPI2_SAS_DEVICE0_FLAGS_SLUMBER_PM_CAPABLE (0x1000)
+#define MPI2_SAS_DEVICE0_FLAGS_PARTIAL_PM_CAPABLE (0x0800)
#define MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY (0x0400)
#define MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200)
#define MPI2_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100)
@@ -2343,5 +2494,122 @@ typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAPPING_0
#define MPI2_DRVMAP0_MAPINFO_MISSING_MASK (0x000F)
+/****************************************************************************
+* Ethernet Config Pages
+****************************************************************************/
+
+/* Ethernet Page 0 */
+
+/* IP address (union of IPv4 and IPv6) */
+typedef union _MPI2_ETHERNET_IP_ADDR {
+ U32 IPv4Addr;
+ U32 IPv6Addr[4];
+} MPI2_ETHERNET_IP_ADDR, MPI2_POINTER PTR_MPI2_ETHERNET_IP_ADDR,
+ Mpi2EthernetIpAddr_t, MPI2_POINTER pMpi2EthernetIpAddr_t;
+
+#define MPI2_ETHERNET_HOST_NAME_LENGTH (32)
+
+typedef struct _MPI2_CONFIG_PAGE_ETHERNET_0 {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U8 NumInterfaces; /* 0x08 */
+ U8 Reserved0; /* 0x09 */
+ U16 Reserved1; /* 0x0A */
+ U32 Status; /* 0x0C */
+ U8 MediaState; /* 0x10 */
+ U8 Reserved2; /* 0x11 */
+ U16 Reserved3; /* 0x12 */
+ U8 MacAddress[6]; /* 0x14 */
+ U8 Reserved4; /* 0x1A */
+ U8 Reserved5; /* 0x1B */
+ MPI2_ETHERNET_IP_ADDR IpAddress; /* 0x1C */
+ MPI2_ETHERNET_IP_ADDR SubnetMask; /* 0x2C */
+ MPI2_ETHERNET_IP_ADDR GatewayIpAddress; /* 0x3C */
+ MPI2_ETHERNET_IP_ADDR DNS1IpAddress; /* 0x4C */
+ MPI2_ETHERNET_IP_ADDR DNS2IpAddress; /* 0x5C */
+ MPI2_ETHERNET_IP_ADDR DhcpIpAddress; /* 0x6C */
+ U8 HostName
+ [MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */
+} MPI2_CONFIG_PAGE_ETHERNET_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_0,
+ Mpi2EthernetPage0_t, MPI2_POINTER pMpi2EthernetPage0_t;
+
+#define MPI2_ETHERNETPAGE0_PAGEVERSION (0x00)
+
+/* values for Ethernet Page 0 Status field */
+#define MPI2_ETHPG0_STATUS_IPV6_CAPABLE (0x80000000)
+#define MPI2_ETHPG0_STATUS_IPV4_CAPABLE (0x40000000)
+#define MPI2_ETHPG0_STATUS_CONSOLE_CONNECTED (0x20000000)
+#define MPI2_ETHPG0_STATUS_DEFAULT_IF (0x00000100)
+#define MPI2_ETHPG0_STATUS_FW_DWNLD_ENABLED (0x00000080)
+#define MPI2_ETHPG0_STATUS_TELNET_ENABLED (0x00000040)
+#define MPI2_ETHPG0_STATUS_SSH2_ENABLED (0x00000020)
+#define MPI2_ETHPG0_STATUS_DHCP_CLIENT_ENABLED (0x00000010)
+#define MPI2_ETHPG0_STATUS_IPV6_ENABLED (0x00000008)
+#define MPI2_ETHPG0_STATUS_IPV4_ENABLED (0x00000004)
+#define MPI2_ETHPG0_STATUS_IPV6_ADDRESSES (0x00000002)
+#define MPI2_ETHPG0_STATUS_ETH_IF_ENABLED (0x00000001)
+
+/* values for Ethernet Page 0 MediaState field */
+#define MPI2_ETHPG0_MS_DUPLEX_MASK (0x80)
+#define MPI2_ETHPG0_MS_HALF_DUPLEX (0x00)
+#define MPI2_ETHPG0_MS_FULL_DUPLEX (0x80)
+
+#define MPI2_ETHPG0_MS_CONNECT_SPEED_MASK (0x07)
+#define MPI2_ETHPG0_MS_NOT_CONNECTED (0x00)
+#define MPI2_ETHPG0_MS_10MBIT (0x01)
+#define MPI2_ETHPG0_MS_100MBIT (0x02)
+#define MPI2_ETHPG0_MS_1GBIT (0x03)
+
+
+/* Ethernet Page 1 */
+
+typedef struct _MPI2_CONFIG_PAGE_ETHERNET_1 {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U32 Reserved0; /* 0x08 */
+ U32 Flags; /* 0x0C */
+ U8 MediaState; /* 0x10 */
+ U8 Reserved1; /* 0x11 */
+ U16 Reserved2; /* 0x12 */
+ U8 MacAddress[6]; /* 0x14 */
+ U8 Reserved3; /* 0x1A */
+ U8 Reserved4; /* 0x1B */
+ MPI2_ETHERNET_IP_ADDR StaticIpAddress; /* 0x1C */
+ MPI2_ETHERNET_IP_ADDR StaticSubnetMask; /* 0x2C */
+ MPI2_ETHERNET_IP_ADDR StaticGatewayIpAddress; /* 0x3C */
+ MPI2_ETHERNET_IP_ADDR StaticDNS1IpAddress; /* 0x4C */
+ MPI2_ETHERNET_IP_ADDR StaticDNS2IpAddress; /* 0x5C */
+ U32 Reserved5; /* 0x6C */
+ U32 Reserved6; /* 0x70 */
+ U32 Reserved7; /* 0x74 */
+ U32 Reserved8; /* 0x78 */
+ U8 HostName
+ [MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */
+} MPI2_CONFIG_PAGE_ETHERNET_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_1,
+ Mpi2EthernetPage1_t, MPI2_POINTER pMpi2EthernetPage1_t;
+
+#define MPI2_ETHERNETPAGE1_PAGEVERSION (0x00)
+
+/* values for Ethernet Page 1 Flags field */
+#define MPI2_ETHPG1_FLAG_SET_DEFAULT_IF (0x00000100)
+#define MPI2_ETHPG1_FLAG_ENABLE_FW_DOWNLOAD (0x00000080)
+#define MPI2_ETHPG1_FLAG_ENABLE_TELNET (0x00000040)
+#define MPI2_ETHPG1_FLAG_ENABLE_SSH2 (0x00000020)
+#define MPI2_ETHPG1_FLAG_ENABLE_DHCP_CLIENT (0x00000010)
+#define MPI2_ETHPG1_FLAG_ENABLE_IPV6 (0x00000008)
+#define MPI2_ETHPG1_FLAG_ENABLE_IPV4 (0x00000004)
+#define MPI2_ETHPG1_FLAG_USE_IPV6_ADDRESSES (0x00000002)
+#define MPI2_ETHPG1_FLAG_ENABLE_ETH_IF (0x00000001)
+
+/* values for Ethernet Page 1 MediaState field */
+#define MPI2_ETHPG1_MS_DUPLEX_MASK (0x80)
+#define MPI2_ETHPG1_MS_HALF_DUPLEX (0x00)
+#define MPI2_ETHPG1_MS_FULL_DUPLEX (0x80)
+
+#define MPI2_ETHPG1_MS_DATA_RATE_MASK (0x07)
+#define MPI2_ETHPG1_MS_DATA_RATE_AUTO (0x00)
+#define MPI2_ETHPG1_MS_DATA_RATE_10MBIT (0x01)
+#define MPI2_ETHPG1_MS_DATA_RATE_100MBIT (0x02)
+#define MPI2_ETHPG1_MS_DATA_RATE_1GBIT (0x03)
+
+
#endif
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
index c294128bdeb4..ea51ce868690 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
@@ -6,7 +6,7 @@
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: October 11, 2006
*
- * mpi2_ioc.h Version: 02.00.11
+ * mpi2_ioc.h Version: 02.00.12
*
* Version History
* ---------------
@@ -84,6 +84,9 @@
* Added two new reason codes for SAS Device Status Change
* Event.
* Added new event: SAS PHY Counter.
+ * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure.
+ * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define.
+ * Added new product id family for 2208.
* --------------------------------------------------------------------------
*/
@@ -274,6 +277,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY
#define MPI2_IOCFACTS_CAPABILITY_MULTICAST (0x00000100)
#define MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET (0x00000080)
#define MPI2_IOCFACTS_CAPABILITY_EEDP (0x00000040)
+#define MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER (0x00000020)
#define MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (0x00000010)
#define MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (0x00000008)
#define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004)
@@ -448,6 +452,7 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY
#define MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST (0x0020)
#define MPI2_EVENT_LOG_ENTRY_ADDED (0x0021)
#define MPI2_EVENT_SAS_PHY_COUNTER (0x0022)
+#define MPI2_EVENT_GPIO_INTERRUPT (0x0023)
/* Log Entry Added Event data */
@@ -469,6 +474,16 @@ typedef struct _MPI2_EVENT_DATA_LOG_ENTRY_ADDED
MPI2_POINTER PTR_MPI2_EVENT_DATA_LOG_ENTRY_ADDED,
Mpi2EventDataLogEntryAdded_t, MPI2_POINTER pMpi2EventDataLogEntryAdded_t;
+/* GPIO Interrupt Event data */
+
+typedef struct _MPI2_EVENT_DATA_GPIO_INTERRUPT {
+ U8 GPIONum; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+} MPI2_EVENT_DATA_GPIO_INTERRUPT,
+ MPI2_POINTER PTR_MPI2_EVENT_DATA_GPIO_INTERRUPT,
+ Mpi2EventDataGpioInterrupt_t, MPI2_POINTER pMpi2EventDataGpioInterrupt_t;
+
/* Hard Reset Received Event data */
typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED
@@ -1117,6 +1132,7 @@ typedef struct _MPI2_FW_IMAGE_HEADER
#define MPI2_FW_HEADER_PID_FAMILY_MASK (0x00FF)
/* SAS */
#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0010)
+#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0011)
/* use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
index 7134816d9046..5160c33d2a00 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
@@ -6,7 +6,7 @@
* Title: MPI Integrated RAID messages and structures
* Creation Date: April 26, 2007
*
- * mpi2_raid.h Version: 02.00.03
+ * mpi2_raid.h Version: 02.00.04
*
* Version History
* ---------------
@@ -20,6 +20,8 @@
* 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that
* the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT
* can be sized by the build environment.
+ * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of
+ * VolumeCreationFlags and marked the old one as obsolete.
* --------------------------------------------------------------------------
*/
@@ -217,10 +219,14 @@ typedef struct _MPI2_RAID_VOLUME_CREATION_STRUCT
/* use MPI2_RAID_VOL_TYPE_ defines from mpi2_cnfg.h for VolumeType */
/* defines for the VolumeCreationFlags field */
+#define MPI2_RAID_VOL_CREATION_DEFAULT_SETTINGS (0x80000000)
+#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x00000004)
+#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x00000002)
+#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x00000001)
+/* The following is an obsolete define.
+ * It must be shifted left 24 bits in order to set the proper bit.
+ */
#define MPI2_RAID_VOL_CREATION_USE_DEFAULT_SETTINGS (0x80)
-#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x04)
-#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x02)
-#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x01)
/* RAID Online Capacity Expansion Structure */
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
index 007e950f7bfa..73fcdbf92632 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
@@ -6,7 +6,7 @@
* Title: MPI diagnostic tool structures and definitions
* Creation Date: March 26, 2007
*
- * mpi2_tool.h Version: 02.00.03
+ * mpi2_tool.h Version: 02.00.04
*
* Version History
* ---------------
@@ -18,6 +18,10 @@
* structures and defines.
* 02-29-08 02.00.02 Modified various names to make them 32-character unique.
* 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool.
+ * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request
+ * and reply messages.
+ * Added MPI2_DIAG_BUF_TYPE_EXTENDED.
+ * Incremented MPI2_DIAG_BUF_TYPE_COUNT.
* --------------------------------------------------------------------------
*/
@@ -282,7 +286,7 @@ typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY {
typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST
{
- U8 Reserved1; /* 0x00 */
+ U8 ExtendedType; /* 0x00 */
U8 BufferType; /* 0x01 */
U8 ChainOffset; /* 0x02 */
U8 Function; /* 0x03 */
@@ -301,11 +305,15 @@ typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST
} MPI2_DIAG_BUFFER_POST_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REQUEST,
Mpi2DiagBufferPostRequest_t, MPI2_POINTER pMpi2DiagBufferPostRequest_t;
+/* values for the ExtendedType field */
+#define MPI2_DIAG_EXTENDED_TYPE_UTILIZATION (0x02)
+
/* values for the BufferType field */
#define MPI2_DIAG_BUF_TYPE_TRACE (0x00)
#define MPI2_DIAG_BUF_TYPE_SNAPSHOT (0x01)
+#define MPI2_DIAG_BUF_TYPE_EXTENDED (0x02)
/* count of the number of buffer types */
-#define MPI2_DIAG_BUF_TYPE_COUNT (0x02)
+#define MPI2_DIAG_BUF_TYPE_COUNT (0x03)
/****************************************************************************
@@ -314,7 +322,7 @@ typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST
typedef struct _MPI2_DIAG_BUFFER_POST_REPLY
{
- U8 Reserved1; /* 0x00 */
+ U8 ExtendedType; /* 0x00 */
U8 BufferType; /* 0x01 */
U8 MsgLength; /* 0x02 */
U8 Function; /* 0x03 */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 670241efa4b5..6422e258fd52 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -57,6 +57,7 @@
#include <linux/dma-mapping.h>
#include <linux/sort.h>
#include <linux/io.h>
+#include <linux/time.h>
#include "mpt2sas_base.h"
@@ -77,6 +78,44 @@ static int msix_disable = -1;
module_param(msix_disable, int, 0);
MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
+/* diag_buffer_enable is bitwise
+ * bit 0 set = TRACE
+ * bit 1 set = SNAPSHOT
+ * bit 2 set = EXTENDED
+ *
+ * Either bit can be set, or both
+ */
+static int diag_buffer_enable;
+module_param(diag_buffer_enable, int, 0);
+MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers "
+ "(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)");
+
+int mpt2sas_fwfault_debug;
+MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault "
+ "and halt firmware - (default=0)");
+
+/**
+ * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug.
+ *
+ */
+static int
+_scsih_set_fwfault_debug(const char *val, struct kernel_param *kp)
+{
+ int ret = param_set_int(val, kp);
+ struct MPT2SAS_ADAPTER *ioc;
+
+ if (ret)
+ return ret;
+
+ printk(KERN_INFO "setting logging_level(0x%08x)\n",
+ mpt2sas_fwfault_debug);
+ list_for_each_entry(ioc, &mpt2sas_ioc_list, list)
+ ioc->fwfault_debug = mpt2sas_fwfault_debug;
+ return 0;
+}
+module_param_call(mpt2sas_fwfault_debug, _scsih_set_fwfault_debug,
+ param_get_int, &mpt2sas_fwfault_debug, 0644);
+
/**
* _base_fault_reset_work - workq handling ioc fault conditions
* @work: input argument, used to derive ioc
@@ -121,7 +160,7 @@ _base_fault_reset_work(struct work_struct *work)
/**
* mpt2sas_base_start_watchdog - start the fault_reset_work_q
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
* Context: sleep.
*
* Return nothing.
@@ -155,7 +194,7 @@ mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc)
/**
* mpt2sas_base_stop_watchdog - stop the fault_reset_work_q
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
* Context: sleep.
*
* Return nothing.
@@ -177,10 +216,55 @@ mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc)
}
}
+/**
+ * mpt2sas_base_fault_info - verbose translation of firmware FAULT code
+ * @ioc: per adapter object
+ * @fault_code: fault code
+ *
+ * Return nothing.
+ */
+void
+mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code)
+{
+ printk(MPT2SAS_ERR_FMT "fault_state(0x%04x)!\n",
+ ioc->name, fault_code);
+}
+
+/**
+ * mpt2sas_halt_firmware - halt's mpt controller firmware
+ * @ioc: per adapter object
+ *
+ * For debugging timeout related issues. Writing 0xCOFFEE00
+ * to the doorbell register will halt controller firmware. With
+ * the purpose to stop both driver and firmware, the enduser can
+ * obtain a ring buffer from controller UART.
+ */
+void
+mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc)
+{
+ u32 doorbell;
+
+ if (!ioc->fwfault_debug)
+ return;
+
+ dump_stack();
+
+ doorbell = readl(&ioc->chip->Doorbell);
+ if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT)
+ mpt2sas_base_fault_info(ioc , doorbell);
+ else {
+ writel(0xC0FFEE00, &ioc->chip->Doorbell);
+ printk(MPT2SAS_ERR_FMT "Firmware is halted due to command "
+ "timeout\n", ioc->name);
+ }
+
+ panic("panic in %s\n", __func__);
+}
+
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
/**
* _base_sas_ioc_info - verbose translation of the ioc status
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @request_hdr: request mf
*
@@ -394,7 +478,7 @@ _base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply,
/**
* _base_display_event_data - verbose translation of firmware asyn events
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
*
* Return nothing.
@@ -474,7 +558,7 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc,
/**
* _base_sas_log_info - verbose translation of firmware log info
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
* @log_info: log info
*
* Return nothing.
@@ -526,22 +610,8 @@ _base_sas_log_info(struct MPT2SAS_ADAPTER *ioc , u32 log_info)
}
/**
- * mpt2sas_base_fault_info - verbose translation of firmware FAULT code
- * @ioc: pointer to scsi command object
- * @fault_code: fault code
- *
- * Return nothing.
- */
-void
-mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code)
-{
- printk(MPT2SAS_ERR_FMT "fault_state(0x%04x)!\n",
- ioc->name, fault_code);
-}
-
-/**
* _base_display_reply_info -
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
* @smid: system request message index
* @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
@@ -570,7 +640,7 @@ _base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
/**
* mpt2sas_base_done - base internal command completion routine
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
* @smid: system request message index
* @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
@@ -603,7 +673,7 @@ mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
/**
* _base_async_event - main callback handler for firmware asyn events
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
* @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
*
@@ -684,7 +754,7 @@ _base_get_cb_idx(struct MPT2SAS_ADAPTER *ioc, u16 smid)
/**
* _base_mask_interrupts - disable interrupts
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
*
* Disabling ResetIRQ, Reply and Doorbell Interrupts
*
@@ -704,7 +774,7 @@ _base_mask_interrupts(struct MPT2SAS_ADAPTER *ioc)
/**
* _base_unmask_interrupts - enable interrupts
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
*
* Enabling only Reply Interrupts
*
@@ -1258,12 +1328,13 @@ mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid)
* @ioc: per adapter object
* @smid: system request message index
*
- * Returns phys pointer to sense buffer.
+ * Returns phys pointer to the low 32bit address of the sense buffer.
*/
-dma_addr_t
+__le32
mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
{
- return ioc->sense_dma + ((smid - 1) * SCSI_SENSE_BUFFERSIZE);
+ return cpu_to_le32(ioc->sense_dma +
+ ((smid - 1) * SCSI_SENSE_BUFFERSIZE));
}
/**
@@ -1697,6 +1768,12 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc)
}
if (ioc->facts.IOCCapabilities &
+ MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) {
+ printk(KERN_INFO "%sDiag Extended Buffer", i ? "," : "");
+ i++;
+ }
+
+ if (ioc->facts.IOCCapabilities &
MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) {
printk("%sTask Set Full", i ? "," : "");
i++;
@@ -2871,6 +2948,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
Mpi2IOCInitRequest_t mpi_request;
Mpi2IOCInitReply_t mpi_reply;
int r;
+ struct timeval current_time;
+ u16 ioc_status;
dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
__func__));
@@ -2921,6 +3000,13 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
cpu_to_le32(ioc->reply_post_free_dma);
#endif
+ /* This time stamp specifies number of milliseconds
+ * since epoch ~ midnight January 1, 1970.
+ */
+ do_gettimeofday(&current_time);
+ mpi_request.TimeStamp = (current_time.tv_sec * 1000) +
+ (current_time.tv_usec >> 3);
+
if (ioc->logging_level & MPT_DEBUG_INIT) {
u32 *mfp;
int i;
@@ -2943,7 +3029,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
return r;
}
- if (mpi_reply.IOCStatus != MPI2_IOCSTATUS_SUCCESS ||
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS ||
mpi_reply.IOCLogInfo) {
printk(MPT2SAS_ERR_FMT "%s: failed\n", ioc->name, __func__);
r = -EIO;
@@ -3461,11 +3548,11 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
return r;
pci_set_drvdata(ioc->pdev, ioc->shost);
- r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
+ r = _base_get_ioc_facts(ioc, CAN_SLEEP);
if (r)
goto out_free_resources;
- r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+ r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
if (r)
goto out_free_resources;
@@ -3531,6 +3618,8 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
goto out_free_resources;
mpt2sas_base_start_watchdog(ioc);
+ if (diag_buffer_enable != 0)
+ mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable);
return 0;
out_free_resources:
@@ -3684,6 +3773,9 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
__func__));
+ if (mpt2sas_fwfault_debug)
+ mpt2sas_halt_firmware(ioc);
+
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
if (ioc->shost_recovery) {
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index 0cf6bc236e4d..bb4f14656afa 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -69,8 +69,8 @@
#define MPT2SAS_DRIVER_NAME "mpt2sas"
#define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION "02.100.03.00"
-#define MPT2SAS_MAJOR_VERSION 02
+#define MPT2SAS_DRIVER_VERSION "03.100.03.00"
+#define MPT2SAS_MAJOR_VERSION 03
#define MPT2SAS_MINOR_VERSION 100
#define MPT2SAS_BUILD_VERSION 03
#define MPT2SAS_RELEASE_VERSION 00
@@ -278,7 +278,7 @@ struct _internal_cmd {
* @sas_address: device sas address
* @device_name: retrieved from the SAS IDENTIFY frame.
* @handle: device handle
- * @parent_handle: handle to parent device
+ * @sas_address_parent: sas address of parent expander or sas host
* @enclosure_handle: enclosure handle
* @enclosure_logical_id: enclosure logical identifier
* @volume_handle: volume handle (valid when hidden raid member)
@@ -296,7 +296,7 @@ struct _sas_device {
u64 sas_address;
u64 device_name;
u16 handle;
- u16 parent_handle;
+ u64 sas_address_parent;
u16 enclosure_handle;
u64 enclosure_logical_id;
u16 volume_handle;
@@ -352,8 +352,6 @@ struct _boot_device {
/**
* struct _sas_port - wide/narrow sas port information
* @port_list: list of ports belonging to expander
- * @handle: device handle for this port
- * @sas_address: sas address of this port
* @num_phys: number of phys belonging to this port
* @remote_identify: attached device identification
* @rphy: sas transport rphy object
@@ -362,8 +360,6 @@ struct _boot_device {
*/
struct _sas_port {
struct list_head port_list;
- u16 handle;
- u64 sas_address;
u8 num_phys;
struct sas_identify remote_identify;
struct sas_rphy *rphy;
@@ -398,7 +394,7 @@ struct _sas_phy {
* @num_phys: number phys belonging to this sas_host/expander
* @sas_address: sas address of this sas_host/expander
* @handle: handle for this sas_host/expander
- * @parent_handle: parent handle
+ * @sas_address_parent: sas address of parent expander or sas host
* @enclosure_handle: handle for this a member of an enclosure
* @device_info: bitwise defining capabilities of this sas_host/expander
* @responding: used in _scsih_expander_device_mark_responding
@@ -411,7 +407,7 @@ struct _sas_node {
u8 num_phys;
u64 sas_address;
u16 handle;
- u16 parent_handle;
+ u64 sas_address_parent;
u16 enclosure_handle;
u64 enclosure_logical_id;
u8 responding;
@@ -470,6 +466,7 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
* @chip_phys: physical addrss prior to mapping
* @pio_chip: I/O mapped register space
* @logging_level: see mpt2sas_debug.h
+ * @fwfault_debug: debuging FW timeouts
* @ir_firmware: IR firmware present
* @bars: bitmask of BAR's that must be configured
* @mask_interrupts: ignore interrupt
@@ -495,12 +492,14 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
* @msix_table_backup: backup msix table
* @scsi_io_cb_idx: shost generated commands
* @tm_cb_idx: task management commands
+ * @scsih_cb_idx: scsih internal commands
* @transport_cb_idx: transport internal commands
* @ctl_cb_idx: clt internal commands
* @base_cb_idx: base internal commands
* @config_cb_idx: base internal commands
* @base_cmds:
* @transport_cmds:
+ * @scsih_cmds:
* @tm_cmds:
* @ctl_cmds:
* @config_cmds:
@@ -591,6 +590,7 @@ struct MPT2SAS_ADAPTER {
unsigned long chip_phys;
unsigned long pio_chip;
int logging_level;
+ int fwfault_debug;
u8 ir_firmware;
int bars;
u8 mask_interrupts;
@@ -626,6 +626,7 @@ struct MPT2SAS_ADAPTER {
u8 scsi_io_cb_idx;
u8 tm_cb_idx;
u8 transport_cb_idx;
+ u8 scsih_cb_idx;
u8 ctl_cb_idx;
u8 base_cb_idx;
u8 config_cb_idx;
@@ -633,6 +634,7 @@ struct MPT2SAS_ADAPTER {
u8 tm_sas_control_cb_idx;
struct _internal_cmd base_cmds;
struct _internal_cmd transport_cmds;
+ struct _internal_cmd scsih_cmds;
struct _internal_cmd tm_cmds;
struct _internal_cmd ctl_cmds;
struct _internal_cmd config_cmds;
@@ -773,7 +775,7 @@ int mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
void *mpt2sas_base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid);
void *mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid);
void mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr);
-dma_addr_t mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc,
+__le32 mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc,
u16 smid);
/* hi-priority queue */
@@ -807,6 +809,8 @@ int mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc,
Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request);
void mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type);
+void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc);
+
/* scsih shared API */
u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
u32 reply);
@@ -886,19 +890,22 @@ u8 mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
void mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,
Mpi2EventNotificationReply_t *mpi_reply);
+void mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc,
+ u8 bits_to_regsiter);
+
/* transport shared API */
u8 mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
u32 reply);
struct _sas_port *mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc,
- u16 handle, u16 parent_handle);
+ u16 handle, u64 sas_address);
void mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
- u16 parent_handle);
+ u64 sas_address_parent);
int mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
*mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev);
int mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
*mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev);
-void mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, u16 handle,
- u16 attached_handle, u8 phy_number, u8 link_rate);
+void mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
+ u64 sas_address, u16 handle, u8 phy_number, u8 link_rate);
extern struct sas_function_template mpt2sas_transport_functions;
extern struct scsi_transport_template *mpt2sas_transport_template;
extern int scsi_internal_device_block(struct scsi_device *sdev);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
index 57d724633906..84a124f8e21f 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
@@ -740,7 +740,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
Mpi2SCSIIORequest_t *scsiio_request =
(Mpi2SCSIIORequest_t *)mpi_request;
scsiio_request->SenseBufferLowAddress =
- (u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid);
+ mpt2sas_base_get_sense_buffer_dma(ioc, smid);
priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid);
memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE);
mpt2sas_base_put_smid_scsi_io(ioc, smid,
@@ -848,8 +848,9 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: "
"IOCStatus(0x%04x), IOCLogInfo(0x%08x), "
"TerminationCount(0x%08x)\n", ioc->name,
- tm_reply->IOCStatus, tm_reply->IOCLogInfo,
- tm_reply->TerminationCount);
+ le16_to_cpu(tm_reply->IOCStatus),
+ le32_to_cpu(tm_reply->IOCLogInfo),
+ le32_to_cpu(tm_reply->TerminationCount));
}
#endif
/* copy out xdata to user */
@@ -896,6 +897,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
printk(MPT2SAS_INFO_FMT "issue target reset: handle "
"= (0x%04x)\n", ioc->name,
mpi_request->FunctionDependent1);
+ mpt2sas_halt_firmware(ioc);
mutex_lock(&ioc->tm_cmds.mutex);
mpt2sas_scsih_issue_tm(ioc,
mpi_request->FunctionDependent1, 0,
@@ -1229,7 +1231,7 @@ _ctl_btdh_mapping(void __user *arg)
/**
* _ctl_diag_capability - return diag buffer capability
* @ioc: per adapter object
- * @buffer_type: specifies either TRACE or SNAPSHOT
+ * @buffer_type: specifies either TRACE, SNAPSHOT, or EXTENDED
*
* returns 1 when diag buffer support is enabled in firmware
*/
@@ -1249,24 +1251,25 @@ _ctl_diag_capability(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type)
MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER)
rc = 1;
break;
+ case MPI2_DIAG_BUF_TYPE_EXTENDED:
+ if (ioc->facts.IOCCapabilities &
+ MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER)
+ rc = 1;
}
return rc;
}
/**
- * _ctl_diag_register - application register with driver
- * @arg - user space buffer containing ioctl content
- * @state - NON_BLOCKING or BLOCKING
+ * _ctl_diag_register_2 - wrapper for registering diag buffer support
+ * @ioc: per adapter object
+ * @diag_register: the diag_register struct passed in from user space
*
- * This will allow the driver to setup any required buffers that will be
- * needed by firmware to communicate with the driver.
*/
static long
-_ctl_diag_register(void __user *arg, enum block_state state)
+_ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc,
+ struct mpt2_diag_register *diag_register)
{
- struct mpt2_diag_register karg;
- struct MPT2SAS_ADAPTER *ioc;
int rc, i;
void *request_data = NULL;
dma_addr_t request_data_dma;
@@ -1279,18 +1282,17 @@ _ctl_diag_register(void __user *arg, enum block_state state)
u16 ioc_status;
u8 issue_reset = 0;
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
- if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
-
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
__func__));
- buffer_type = karg.buffer_type;
+ if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
+ printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
+ ioc->name, __func__);
+ rc = -EAGAIN;
+ goto out;
+ }
+
+ buffer_type = diag_register->buffer_type;
if (!_ctl_diag_capability(ioc, buffer_type)) {
printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for "
"buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
@@ -1305,24 +1307,12 @@ _ctl_diag_register(void __user *arg, enum block_state state)
return -EINVAL;
}
- if (karg.requested_buffer_size % 4) {
+ if (diag_register->requested_buffer_size % 4) {
printk(MPT2SAS_ERR_FMT "%s: the requested_buffer_size "
"is not 4 byte aligned\n", ioc->name, __func__);
return -EINVAL;
}
- if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
- return -EAGAIN;
- else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
- return -ERESTARTSYS;
-
- if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx);
if (!smid) {
printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
@@ -1338,12 +1328,12 @@ _ctl_diag_register(void __user *arg, enum block_state state)
ioc->ctl_cmds.smid = smid;
request_data = ioc->diag_buffer[buffer_type];
- request_data_sz = karg.requested_buffer_size;
- ioc->unique_id[buffer_type] = karg.unique_id;
+ request_data_sz = diag_register->requested_buffer_size;
+ ioc->unique_id[buffer_type] = diag_register->unique_id;
ioc->diag_buffer_status[buffer_type] = 0;
- memcpy(ioc->product_specific[buffer_type], karg.product_specific,
- MPT2_PRODUCT_SPECIFIC_DWORDS);
- ioc->diagnostic_flags[buffer_type] = karg.diagnostic_flags;
+ memcpy(ioc->product_specific[buffer_type],
+ diag_register->product_specific, MPT2_PRODUCT_SPECIFIC_DWORDS);
+ ioc->diagnostic_flags[buffer_type] = diag_register->diagnostic_flags;
if (request_data) {
request_data_dma = ioc->diag_buffer_dma[buffer_type];
@@ -1373,8 +1363,8 @@ _ctl_diag_register(void __user *arg, enum block_state state)
}
mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST;
- mpi_request->BufferType = karg.buffer_type;
- mpi_request->Flags = cpu_to_le32(karg.diagnostic_flags);
+ mpi_request->BufferType = diag_register->buffer_type;
+ mpi_request->Flags = cpu_to_le32(diag_register->diagnostic_flags);
mpi_request->BufferAddress = cpu_to_le64(request_data_dma);
mpi_request->BufferLength = cpu_to_le32(request_data_sz);
mpi_request->VF_ID = 0; /* TODO */
@@ -1422,7 +1412,7 @@ _ctl_diag_register(void __user *arg, enum block_state state)
} else {
printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
"log_info(0x%08x)\n", ioc->name, __func__,
- ioc_status, mpi_reply->IOCLogInfo);
+ ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
rc = -EFAULT;
}
@@ -1438,6 +1428,83 @@ _ctl_diag_register(void __user *arg, enum block_state state)
request_data, request_data_dma);
ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
+ return rc;
+}
+
+/**
+ * mpt2sas_enable_diag_buffer - enabling diag_buffers support driver load time
+ * @ioc: per adapter object
+ * @bits_to_register: bitwise field where trace is bit 0, and snapshot is bit 1
+ *
+ * This is called when command line option diag_buffer_enable is enabled
+ * at driver load time.
+ */
+void
+mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc, u8 bits_to_register)
+{
+ struct mpt2_diag_register diag_register;
+
+ memset(&diag_register, 0, sizeof(struct mpt2_diag_register));
+
+ if (bits_to_register & 1) {
+ printk(MPT2SAS_INFO_FMT "registering trace buffer support\n",
+ ioc->name);
+ diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE;
+ /* register for 1MB buffers */
+ diag_register.requested_buffer_size = (1024 * 1024);
+ diag_register.unique_id = 0x7075900;
+ _ctl_diag_register_2(ioc, &diag_register);
+ }
+
+ if (bits_to_register & 2) {
+ printk(MPT2SAS_INFO_FMT "registering snapshot buffer support\n",
+ ioc->name);
+ diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_SNAPSHOT;
+ /* register for 2MB buffers */
+ diag_register.requested_buffer_size = 2 * (1024 * 1024);
+ diag_register.unique_id = 0x7075901;
+ _ctl_diag_register_2(ioc, &diag_register);
+ }
+
+ if (bits_to_register & 4) {
+ printk(MPT2SAS_INFO_FMT "registering extended buffer support\n",
+ ioc->name);
+ diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_EXTENDED;
+ /* register for 2MB buffers */
+ diag_register.requested_buffer_size = 2 * (1024 * 1024);
+ diag_register.unique_id = 0x7075901;
+ _ctl_diag_register_2(ioc, &diag_register);
+ }
+}
+
+/**
+ * _ctl_diag_register - application register with driver
+ * @arg - user space buffer containing ioctl content
+ * @state - NON_BLOCKING or BLOCKING
+ *
+ * This will allow the driver to setup any required buffers that will be
+ * needed by firmware to communicate with the driver.
+ */
+static long
+_ctl_diag_register(void __user *arg, enum block_state state)
+{
+ struct mpt2_diag_register karg;
+ struct MPT2SAS_ADAPTER *ioc;
+ long rc;
+
+ if (copy_from_user(&karg, arg, sizeof(karg))) {
+ printk(KERN_ERR "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
+ return -EFAULT;
+ }
+ if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
+ return -ENODEV;
+
+ if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
+ return -EAGAIN;
+ else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
+ return -ERESTARTSYS;
+ rc = _ctl_diag_register_2(ioc, &karg);
mutex_unlock(&ioc->ctl_cmds.mutex);
return rc;
}
@@ -1600,7 +1667,7 @@ _ctl_diag_query(void __user *arg)
/**
* _ctl_send_release - Diag Release Message
* @ioc: per adapter object
- * @buffer_type - specifies either TRACE or SNAPSHOT
+ * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED
* @issue_reset - specifies whether host reset is required.
*
*/
@@ -1690,7 +1757,7 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)
} else {
printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
"log_info(0x%08x)\n", ioc->name, __func__,
- ioc_status, mpi_reply->IOCLogInfo);
+ ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
rc = -EFAULT;
}
@@ -1951,7 +2018,7 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
} else {
printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
"log_info(0x%08x)\n", ioc->name, __func__,
- ioc_status, mpi_reply->IOCLogInfo);
+ ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
rc = -EFAULT;
}
@@ -2474,6 +2541,43 @@ _ctl_logging_level_store(struct device *cdev, struct device_attribute *attr,
static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR,
_ctl_logging_level_show, _ctl_logging_level_store);
+/* device attributes */
+/*
+ * _ctl_fwfault_debug_show - show/store fwfault_debug
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * mpt2sas_fwfault_debug is command line option
+ * A sysfs 'read/write' shost attribute.
+ */
+static ssize_t
+_ctl_fwfault_debug_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", ioc->fwfault_debug);
+}
+static ssize_t
+_ctl_fwfault_debug_store(struct device *cdev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+ int val = 0;
+
+ if (sscanf(buf, "%d", &val) != 1)
+ return -EINVAL;
+
+ ioc->fwfault_debug = val;
+ printk(MPT2SAS_INFO_FMT "fwfault_debug=%d\n", ioc->name,
+ ioc->fwfault_debug);
+ return strlen(buf);
+}
+static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR,
+ _ctl_fwfault_debug_show, _ctl_fwfault_debug_store);
+
struct device_attribute *mpt2sas_host_attrs[] = {
&dev_attr_version_fw,
&dev_attr_version_bios,
@@ -2487,13 +2591,12 @@ struct device_attribute *mpt2sas_host_attrs[] = {
&dev_attr_io_delay,
&dev_attr_device_delay,
&dev_attr_logging_level,
+ &dev_attr_fwfault_debug,
&dev_attr_fw_queue_depth,
&dev_attr_host_sas_address,
NULL,
};
-/* device attributes */
-
/**
* _ctl_device_sas_address_show - sas address
* @cdev - pointer to embedded class device
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h
index 211f296dd191..8a5eeb1a5c84 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.h
@@ -313,7 +313,7 @@ struct mpt2_ioctl_btdh_mapping {
* struct mpt2_diag_register - application register with driver
* @hdr - generic header
* @reserved -
- * @buffer_type - specifies either TRACE or SNAPSHOT
+ * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED
* @application_flags - misc flags
* @diagnostic_flags - specifies flags affecting command processing
* @product_specific - product specific information
@@ -352,7 +352,7 @@ struct mpt2_diag_unregister {
* struct mpt2_diag_query - query relevant info associated with diag buffers
* @hdr - generic header
* @reserved -
- * @buffer_type - specifies either TRACE or SNAPSHOT
+ * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED
* @application_flags - misc flags
* @diagnostic_flags - specifies flags affecting command processing
* @product_specific - product specific information
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index 86ab32d7ab15..8dc682f00fd2 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -76,6 +76,7 @@ static u8 tm_cb_idx = -1;
static u8 ctl_cb_idx = -1;
static u8 base_cb_idx = -1;
static u8 transport_cb_idx = -1;
+static u8 scsih_cb_idx = -1;
static u8 config_cb_idx = -1;
static int mpt_ids;
@@ -196,10 +197,28 @@ static struct pci_device_id scsih_pci_table[] = {
PCI_ANY_ID, PCI_ANY_ID },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3,
PCI_ANY_ID, PCI_ANY_ID },
+ /* Meteor ~ 2116 */
{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1,
PCI_ANY_ID, PCI_ANY_ID },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2,
PCI_ANY_ID, PCI_ANY_ID },
+ /* Thunderbolt ~ 2208 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_7,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_8,
+ PCI_ANY_ID, PCI_ANY_ID },
{0} /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, scsih_pci_table);
@@ -317,6 +336,47 @@ _scsih_is_boot_device(u64 sas_address, u64 device_name,
}
/**
+ * _scsih_get_sas_address - set the sas_address for given device handle
+ * @handle: device handle
+ * @sas_address: sas address
+ *
+ * Returns 0 success, non-zero when failure
+ */
+static int
+_scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle,
+ u64 *sas_address)
+{
+ Mpi2SasDevicePage0_t sas_device_pg0;
+ Mpi2ConfigReply_t mpi_reply;
+ u32 ioc_status;
+
+ if (handle <= ioc->sas_hba.num_phys) {
+ *sas_address = ioc->sas_hba.sas_address;
+ return 0;
+ } else
+ *sas_address = 0;
+
+ if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ return -ENXIO;
+ }
+
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+ MPI2_IOCSTATUS_MASK;
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)"
+ "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
+ __FILE__, __LINE__, __func__);
+ return -EIO;
+ }
+
+ *sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
+ return 0;
+}
+
+/**
* _scsih_determine_boot_device - determine boot device.
* @ioc: per adapter object
* @device: either sas_device or raid_device object
@@ -510,8 +570,6 @@ _scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
struct _sas_device *sas_device)
{
unsigned long flags;
- u16 handle, parent_handle;
- u64 sas_address;
dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
"(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
@@ -521,10 +579,8 @@ _scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
list_add_tail(&sas_device->list, &ioc->sas_device_list);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- handle = sas_device->handle;
- parent_handle = sas_device->parent_handle;
- sas_address = sas_device->sas_address;
- if (!mpt2sas_transport_port_add(ioc, handle, parent_handle))
+ if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
+ sas_device->sas_address_parent))
_scsih_sas_device_remove(ioc, sas_device);
}
@@ -553,31 +609,6 @@ _scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,
}
/**
- * mpt2sas_scsih_expander_find_by_handle - expander device search
- * @ioc: per adapter object
- * @handle: expander handle (assigned by firmware)
- * Context: Calling function should acquire ioc->sas_device_lock
- *
- * This searches for expander device based on handle, then returns the
- * sas_node object.
- */
-struct _sas_node *
-mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _sas_node *sas_expander, *r;
-
- r = NULL;
- list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
- if (sas_expander->handle != handle)
- continue;
- r = sas_expander;
- goto out;
- }
- out:
- return r;
-}
-
-/**
* _scsih_raid_device_find_by_id - raid device search
* @ioc: per adapter object
* @id: sas device target id
@@ -699,6 +730,31 @@ _scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
}
/**
+ * mpt2sas_scsih_expander_find_by_handle - expander device search
+ * @ioc: per adapter object
+ * @handle: expander handle (assigned by firmware)
+ * Context: Calling function should acquire ioc->sas_device_lock
+ *
+ * This searches for expander device based on handle, then returns the
+ * sas_node object.
+ */
+struct _sas_node *
+mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+ struct _sas_node *sas_expander, *r;
+
+ r = NULL;
+ list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
+ if (sas_expander->handle != handle)
+ continue;
+ r = sas_expander;
+ goto out;
+ }
+ out:
+ return r;
+}
+
+/**
* mpt2sas_scsih_expander_find_by_sas_address - expander device search
* @ioc: per adapter object
* @sas_address: sas address
@@ -1052,8 +1108,33 @@ _scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
struct Scsi_Host *shost = sdev->host;
int max_depth;
int tag_type;
+ struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+ struct MPT2SAS_DEVICE *sas_device_priv_data;
+ struct MPT2SAS_TARGET *sas_target_priv_data;
+ struct _sas_device *sas_device;
+ unsigned long flags;
max_depth = shost->can_queue;
+
+ /* limit max device queue for SATA to 32 */
+ sas_device_priv_data = sdev->hostdata;
+ if (!sas_device_priv_data)
+ goto not_sata;
+ sas_target_priv_data = sas_device_priv_data->sas_target;
+ if (!sas_target_priv_data)
+ goto not_sata;
+ if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))
+ goto not_sata;
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device_priv_data->sas_target->sas_address);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ if (sas_device && sas_device->device_info &
+ MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
+ max_depth = MPT2SAS_SATA_QUEUE_DEPTH;
+
+ not_sata:
+
if (!sdev->tagged_supported)
max_depth = 1;
if (qdepth > max_depth)
@@ -1874,6 +1955,8 @@ _scsih_abort(struct scsi_cmnd *scmd)
goto out;
}
+ mpt2sas_halt_firmware(ioc);
+
mutex_lock(&ioc->tm_cmds.mutex);
handle = sas_device_priv_data->sas_target->handle;
mpt2sas_scsih_issue_tm(ioc, handle, sas_device_priv_data->lun,
@@ -2297,7 +2380,6 @@ _scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
u16 handle;
u16 reason_code;
u8 phy_number;
- u8 link_rate;
for (i = 0; i < event_data->NumEntries; i++) {
handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
@@ -2308,11 +2390,6 @@ _scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
MPI2_EVENT_SAS_TOPO_RC_MASK;
if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING)
_scsih_block_io_device(ioc, handle);
- if (reason_code == MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED) {
- link_rate = event_data->PHY[i].LinkRate >> 4;
- if (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)
- _scsih_ublock_io_device(ioc, handle);
- }
}
}
@@ -2349,16 +2426,10 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- if (!sas_device) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n",
- ioc->name, __func__);
- return;
- }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
/* skip is hidden raid component */
- if (sas_device->hidden_raid_component)
+ if (sas_device && sas_device->hidden_raid_component)
return;
smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx);
@@ -2371,18 +2442,31 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
delayed_tr->state = MPT2SAS_REQ_SAS_CNTRL;
list_add_tail(&delayed_tr->list,
&ioc->delayed_tr_list);
- if (sas_device->starget)
+ if (sas_device && sas_device->starget) {
dewtprintk(ioc, starget_printk(KERN_INFO,
sas_device->starget, "DELAYED:tr:handle(0x%04x), "
- "(open)\n", sas_device->handle));
+ "(open)\n", handle));
+ } else {
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "DELAYED:tr:handle(0x%04x), (open)\n",
+ ioc->name, handle));
+ }
return;
}
- if (sas_device->starget && sas_device->starget->hostdata) {
- sas_target_priv_data = sas_device->starget->hostdata;
- sas_target_priv_data->tm_busy = 1;
- dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget,
- "tr:handle(0x%04x), (open)\n", sas_device->handle));
+ if (sas_device) {
+ sas_device->state |= MPTSAS_STATE_TR_SEND;
+ sas_device->state |= MPT2SAS_REQ_SAS_CNTRL;
+ if (sas_device->starget && sas_device->starget->hostdata) {
+ sas_target_priv_data = sas_device->starget->hostdata;
+ sas_target_priv_data->tm_busy = 1;
+ dewtprintk(ioc, starget_printk(KERN_INFO,
+ sas_device->starget, "tr:handle(0x%04x), (open)\n",
+ handle));
+ }
+ } else {
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "tr:handle(0x%04x), (open)\n", ioc->name, handle));
}
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
@@ -2390,8 +2474,6 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
mpi_request->DevHandle = cpu_to_le16(handle);
mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
- sas_device->state |= MPTSAS_STATE_TR_SEND;
- sas_device->state |= MPT2SAS_REQ_SAS_CNTRL;
mpt2sas_base_put_smid_hi_priority(ioc, smid);
}
@@ -2426,21 +2508,25 @@ _scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- if (!sas_device) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n",
- ioc->name, __func__);
- return 1;
- }
- sas_device->state |= MPTSAS_STATE_CNTRL_COMPLETE;
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (sas_device->starget)
- dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget,
+ if (sas_device) {
+ sas_device->state |= MPTSAS_STATE_CNTRL_COMPLETE;
+ if (sas_device->starget)
+ dewtprintk(ioc, starget_printk(KERN_INFO,
+ sas_device->starget,
+ "sc_complete:handle(0x%04x), "
+ "ioc_status(0x%04x), loginfo(0x%08x)\n",
+ handle, le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo)));
+ } else {
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
"sc_complete:handle(0x%04x), "
"ioc_status(0x%04x), loginfo(0x%08x)\n",
- handle, le16_to_cpu(mpi_reply->IOCStatus),
+ ioc->name, handle, le16_to_cpu(mpi_reply->IOCStatus),
le32_to_cpu(mpi_reply->IOCLogInfo)));
+ }
+
return 1;
}
@@ -2478,28 +2564,33 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
handle = le16_to_cpu(mpi_reply->DevHandle);
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- if (!sas_device) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n",
- ioc->name, __func__);
- return 1;
- }
- sas_device->state |= MPTSAS_STATE_TR_COMPLETE;
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (sas_device->starget)
- dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget,
- "tr_complete:handle(0x%04x), (%s) ioc_status(0x%04x), "
- "loginfo(0x%08x), completed(%d)\n",
- sas_device->handle, (sas_device->state &
- MPT2SAS_REQ_SAS_CNTRL) ? "open" : "active",
- le16_to_cpu(mpi_reply->IOCStatus),
+ if (sas_device) {
+ sas_device->state |= MPTSAS_STATE_TR_COMPLETE;
+ if (sas_device->starget) {
+ dewtprintk(ioc, starget_printk(KERN_INFO,
+ sas_device->starget, "tr_complete:handle(0x%04x), "
+ "(%s) ioc_status(0x%04x), loginfo(0x%08x), "
+ "completed(%d)\n", sas_device->handle,
+ (sas_device->state & MPT2SAS_REQ_SAS_CNTRL) ?
+ "open" : "active",
+ le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo),
+ le32_to_cpu(mpi_reply->TerminationCount)));
+ if (sas_device->starget->hostdata) {
+ sas_target_priv_data =
+ sas_device->starget->hostdata;
+ sas_target_priv_data->tm_busy = 0;
+ }
+ }
+ } else {
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "tr_complete:handle(0x%04x), (open) ioc_status(0x%04x), "
+ "loginfo(0x%08x), completed(%d)\n", ioc->name,
+ handle, le16_to_cpu(mpi_reply->IOCStatus),
le32_to_cpu(mpi_reply->IOCLogInfo),
le32_to_cpu(mpi_reply->TerminationCount)));
-
- if (sas_device->starget && sas_device->starget->hostdata) {
- sas_target_priv_data = sas_device->starget->hostdata;
- sas_target_priv_data->tm_busy = 0;
}
if (!list_empty(&ioc->delayed_tr_list)) {
@@ -2514,8 +2605,7 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
} else
rc = 1;
-
- if (!(sas_device->state & MPT2SAS_REQ_SAS_CNTRL))
+ if (sas_device && !(sas_device->state & MPT2SAS_REQ_SAS_CNTRL))
return rc;
if (ioc->shost_recovery) {
@@ -2531,12 +2621,14 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
return rc;
}
+ if (sas_device)
+ sas_device->state |= MPTSAS_STATE_CNTRL_SEND;
+
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl);
memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
mpi_request->DevHandle = mpi_reply->DevHandle;
- sas_device->state |= MPTSAS_STATE_CNTRL_SEND;
mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl);
return rc;
}
@@ -2678,8 +2770,6 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
else
return;
- mpi_request->EEDPBlockSize = scmd->device->sector_size;
-
switch (prot_type) {
case SCSI_PROT_DIF_TYPE1:
@@ -2687,8 +2777,7 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
* enable ref/guard checking
* auto increment ref tag
*/
- mpi_request->EEDPFlags = eedp_flags |
- MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
+ eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
mpi_request->CDB.EEDP32.PrimaryReferenceTag =
@@ -2701,11 +2790,11 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
/*
* enable guard checking
*/
- mpi_request->EEDPFlags = eedp_flags |
- MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
-
+ eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
break;
}
+ mpi_request->EEDPBlockSize = cpu_to_le32(scmd->device->sector_size);
+ mpi_request->EEDPFlags = cpu_to_le16(eedp_flags);
}
/**
@@ -2788,7 +2877,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
}
/* see if we are busy with task managment stuff */
- if (sas_target_priv_data->tm_busy)
+ if (sas_device_priv_data->block || sas_target_priv_data->tm_busy)
return SCSI_MLQUEUE_DEVICE_BUSY;
else if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
return SCSI_MLQUEUE_HOST_BUSY;
@@ -2842,7 +2931,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR;
mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
mpi_request->SenseBufferLowAddress =
- (u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid);
+ mpt2sas_base_get_sense_buffer_dma(ioc, smid);
mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;
mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI +
MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR);
@@ -3059,7 +3148,7 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
response_info = le32_to_cpu(mpi_reply->ResponseInfo);
response_bytes = (u8 *)&response_info;
- _scsih_response_code(ioc, response_bytes[3]);
+ _scsih_response_code(ioc, response_bytes[0]);
}
}
#endif
@@ -3177,7 +3266,7 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
u8 scsi_status;
u32 log_info;
struct MPT2SAS_DEVICE *sas_device_priv_data;
- u32 response_code;
+ u32 response_code = 0;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
scmd = _scsih_scsi_lookup_get(ioc, smid);
@@ -3199,16 +3288,16 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
}
/* turning off TLR */
+ scsi_state = mpi_reply->SCSIState;
+ if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
+ response_code =
+ le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF;
if (!sas_device_priv_data->tlr_snoop_check) {
sas_device_priv_data->tlr_snoop_check++;
- if (sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) {
- response_code = (le32_to_cpu(mpi_reply->ResponseInfo)
- >> 24);
- if (response_code ==
- MPI2_SCSITASKMGMT_RSP_INVALID_FRAME)
- sas_device_priv_data->flags &=
- ~MPT_DEVICE_TLR_ON;
- }
+ if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) &&
+ response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME)
+ sas_device_priv_data->flags &=
+ ~MPT_DEVICE_TLR_ON;
}
xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
@@ -3219,7 +3308,6 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
else
log_info = 0;
ioc_status &= MPI2_IOCSTATUS_MASK;
- scsi_state = mpi_reply->SCSIState;
scsi_status = mpi_reply->SCSIStatus;
if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
@@ -3255,10 +3343,9 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
if (sas_device_priv_data->block) {
- scmd->result = (DID_BUS_BUSY << 16);
- break;
+ scmd->result = DID_TRANSPORT_DISRUPTED << 16;
+ goto out;
}
-
case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
scmd->result = DID_RESET << 16;
@@ -3304,8 +3391,10 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
case MPI2_IOCSTATUS_SUCCESS:
scmd->result = (DID_OK << 16) | scsi_status;
- if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
- MPI2_SCSI_STATE_NO_SCSI_STATUS))
+ if (response_code ==
+ MPI2_SCSITASKMGMT_RSP_INVALID_FRAME ||
+ (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
+ MPI2_SCSI_STATE_NO_SCSI_STATUS)))
scmd->result = DID_SOFT_ERROR << 16;
else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
scmd->result = DID_RESET << 16;
@@ -3344,7 +3433,6 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
/**
* _scsih_sas_host_refresh - refreshing sas host object contents
* @ioc: per adapter object
- * @update: update link information
* Context: user
*
* During port enable, fw will send topology events for every device. Its
@@ -3354,13 +3442,14 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
* Return nothing.
*/
static void
-_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc, u8 update)
+_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc)
{
u16 sz;
u16 ioc_status;
int i;
Mpi2ConfigReply_t mpi_reply;
Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
+ u16 attached_handle;
dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
"updating handles for sas_host(0x%016llx)\n",
@@ -3374,27 +3463,24 @@ _scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc, u8 update)
ioc->name, __FILE__, __LINE__, __func__);
return;
}
- if (!(mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
- sas_iounit_pg0, sz))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
- goto out;
- for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
- ioc->sas_hba.phy[i].handle =
- le16_to_cpu(sas_iounit_pg0->PhyData[i].
- ControllerDevHandle);
- if (update)
- mpt2sas_transport_update_links(
- ioc,
- ioc->sas_hba.phy[i].handle,
- le16_to_cpu(sas_iounit_pg0->PhyData[i].
- AttachedDevHandle), i,
- sas_iounit_pg0->PhyData[i].
- NegotiatedLinkRate >> 4);
- }
- }
+ if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
+ sas_iounit_pg0, sz)) != 0)
+ goto out;
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
+ goto out;
+ for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
+ if (i == 0)
+ ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
+ PhyData[0].ControllerDevHandle);
+ ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
+ attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i].
+ AttachedDevHandle);
+ mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address,
+ attached_handle, i, sas_iounit_pg0->PhyData[i].
+ NegotiatedLinkRate >> 4);
+ }
out:
kfree(sas_iounit_pg0);
}
@@ -3507,19 +3593,21 @@ _scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc)
ioc->name, __FILE__, __LINE__, __func__);
goto out;
}
- ioc->sas_hba.phy[i].handle =
- le16_to_cpu(sas_iounit_pg0->PhyData[i].ControllerDevHandle);
+
+ if (i == 0)
+ ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
+ PhyData[0].ControllerDevHandle);
+ ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
ioc->sas_hba.phy[i].phy_id = i;
mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i],
phy_pg0, ioc->sas_hba.parent_dev);
}
if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
- MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.phy[0].handle))) {
+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
goto out;
}
- ioc->sas_hba.handle = le16_to_cpu(sas_device_pg0.DevHandle);
ioc->sas_hba.enclosure_handle =
le16_to_cpu(sas_device_pg0.EnclosureHandle);
ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
@@ -3562,7 +3650,7 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
Mpi2SasEnclosurePage0_t enclosure_pg0;
u32 ioc_status;
u16 parent_handle;
- __le64 sas_address;
+ __le64 sas_address, sas_address_parent = 0;
int i;
unsigned long flags;
struct _sas_port *mpt2sas_port = NULL;
@@ -3591,10 +3679,16 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
/* handle out of order topology events */
parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle);
- if (parent_handle >= ioc->sas_hba.num_phys) {
+ if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent)
+ != 0) {
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
+ return -1;
+ }
+ if (sas_address_parent != ioc->sas_hba.sas_address) {
spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
- parent_handle);
+ sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
+ sas_address_parent);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (!sas_expander) {
rc = _scsih_expander_add(ioc, parent_handle);
@@ -3622,14 +3716,12 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
sas_expander->handle = handle;
sas_expander->num_phys = expander_pg0.NumPhys;
- sas_expander->parent_handle = parent_handle;
- sas_expander->enclosure_handle =
- le16_to_cpu(expander_pg0.EnclosureHandle);
+ sas_expander->sas_address_parent = sas_address_parent;
sas_expander->sas_address = sas_address;
printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x),"
" parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name,
- handle, sas_expander->parent_handle, (unsigned long long)
+ handle, parent_handle, (unsigned long long)
sas_expander->sas_address, sas_expander->num_phys);
if (!sas_expander->num_phys)
@@ -3645,7 +3737,7 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
INIT_LIST_HEAD(&sas_expander->sas_port_list);
mpt2sas_port = mpt2sas_transport_port_add(ioc, handle,
- sas_expander->parent_handle);
+ sas_address_parent);
if (!mpt2sas_port) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
@@ -3691,20 +3783,54 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
if (mpt2sas_port)
mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
- sas_expander->parent_handle);
+ sas_address_parent);
kfree(sas_expander);
return rc;
}
/**
+ * _scsih_done - scsih callback handler.
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @msix_index: MSIX table index supplied by the OS
+ * @reply: reply message frame(lower 32bit addr)
+ *
+ * Callback handler when sending internal generated message frames.
+ * The callback index passed is `ioc->scsih_cb_idx`
+ *
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
+ */
+static u8
+_scsih_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
+{
+ MPI2DefaultReply_t *mpi_reply;
+
+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
+ if (ioc->scsih_cmds.status == MPT2_CMD_NOT_USED)
+ return 1;
+ if (ioc->scsih_cmds.smid != smid)
+ return 1;
+ ioc->scsih_cmds.status |= MPT2_CMD_COMPLETE;
+ if (mpi_reply) {
+ memcpy(ioc->scsih_cmds.reply, mpi_reply,
+ mpi_reply->MsgLength*4);
+ ioc->scsih_cmds.status |= MPT2_CMD_REPLY_VALID;
+ }
+ ioc->scsih_cmds.status &= ~MPT2_CMD_PENDING;
+ complete(&ioc->scsih_cmds.done);
+ return 1;
+}
+
+/**
* _scsih_expander_remove - removing expander object
* @ioc: per adapter object
- * @handle: expander handle
+ * @sas_address: expander sas_address
*
* Return nothing.
*/
static void
-_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
{
struct _sas_node *sas_expander;
unsigned long flags;
@@ -3713,7 +3839,8 @@ _scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u16 handle)
return;
spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, handle);
+ sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
+ sas_address);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
_scsih_expander_node_remove(ioc, sas_expander);
}
@@ -3805,8 +3932,11 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
}
sas_device->handle = handle;
- sas_device->parent_handle =
- le16_to_cpu(sas_device_pg0.ParentDevHandle);
+ if (_scsih_get_sas_address(ioc, le16_to_cpu
+ (sas_device_pg0.ParentDevHandle),
+ &sas_device->sas_address_parent) != 0)
+ printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
+ ioc->name, __FILE__, __LINE__, __func__);
sas_device->enclosure_handle =
le16_to_cpu(sas_device_pg0.EnclosureHandle);
sas_device->slot =
@@ -3836,43 +3966,39 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
/**
* _scsih_remove_device - removing sas device object
* @ioc: per adapter object
- * @handle: sas device handle
+ * @sas_device: the sas_device object
*
* Return nothing.
*/
static void
-_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device
+ *sas_device)
{
struct MPT2SAS_TARGET *sas_target_priv_data;
- struct _sas_device *sas_device;
- unsigned long flags;
Mpi2SasIoUnitControlReply_t mpi_reply;
Mpi2SasIoUnitControlRequest_t mpi_request;
- u16 device_handle;
+ u16 device_handle, handle;
- /* lookup sas_device */
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- if (!sas_device) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ if (!sas_device)
return;
- }
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle"
- "(0x%04x)\n", ioc->name, __func__, handle));
+ handle = sas_device->handle;
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle(0x%04x),"
+ " sas_addr(0x%016llx)\n", ioc->name, __func__, handle,
+ (unsigned long long) sas_device->sas_address));
if (sas_device->starget && sas_device->starget->hostdata) {
sas_target_priv_data = sas_device->starget->hostdata;
sas_target_priv_data->deleted = 1;
}
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (ioc->remove_host)
+ if (ioc->remove_host || ioc->shost_recovery || !handle)
goto out;
if ((sas_device->state & MPTSAS_STATE_TR_COMPLETE)) {
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip "
- "target_reset handle(0x%04x)\n", ioc->name, handle));
+ "target_reset handle(0x%04x)\n", ioc->name,
+ handle));
goto skip_tr;
}
@@ -3925,10 +4051,10 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
_scsih_ublock_io_device(ioc, handle);
mpt2sas_transport_port_remove(ioc, sas_device->sas_address,
- sas_device->parent_handle);
+ sas_device->sas_address_parent);
printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
- "(0x%016llx)\n", ioc->name, sas_device->handle,
+ "(0x%016llx)\n", ioc->name, handle,
(unsigned long long) sas_device->sas_address);
_scsih_sas_device_remove(ioc, sas_device);
@@ -3952,7 +4078,7 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
u16 reason_code;
u8 phy_number;
char *status_str = NULL;
- char link_rate[25];
+ u8 link_rate, prev_link_rate;
switch (event_data->ExpStatus) {
case MPI2_EVENT_SAS_TOPO_ES_ADDED:
@@ -3962,6 +4088,7 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
status_str = "remove";
break;
case MPI2_EVENT_SAS_TOPO_ES_RESPONDING:
+ case 0:
status_str = "responding";
break;
case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
@@ -3987,30 +4114,30 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
MPI2_EVENT_SAS_TOPO_RC_MASK;
switch (reason_code) {
case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
- snprintf(link_rate, 25, ": add, link(0x%02x)",
- (event_data->PHY[i].LinkRate >> 4));
- status_str = link_rate;
+ status_str = "target add";
break;
case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
- status_str = ": remove";
+ status_str = "target remove";
break;
case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
- status_str = ": remove_delay";
+ status_str = "delay target remove";
break;
case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
- snprintf(link_rate, 25, ": link(0x%02x)",
- (event_data->PHY[i].LinkRate >> 4));
- status_str = link_rate;
+ status_str = "link rate change";
break;
case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
- status_str = ": responding";
+ status_str = "target responding";
break;
default:
- status_str = ": unknown";
+ status_str = "unknown";
break;
}
- printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x)%s\n",
- phy_number, handle, status_str);
+ link_rate = event_data->PHY[i].LinkRate >> 4;
+ prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
+ printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x): %s:"
+ " link rate: new(0x%02x), old(0x%02x)\n", phy_number,
+ handle, status_str, link_rate, prev_link_rate);
+
}
}
#endif
@@ -4031,8 +4158,10 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
u16 reason_code;
u8 phy_number;
struct _sas_node *sas_expander;
+ struct _sas_device *sas_device;
+ u64 sas_address;
unsigned long flags;
- u8 link_rate_;
+ u8 link_rate, prev_link_rate;
Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data;
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
@@ -4040,10 +4169,13 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
_scsih_sas_topology_change_event_debug(ioc, event_data);
#endif
+ if (ioc->shost_recovery)
+ return;
+
if (!ioc->sas_hba.num_phys)
_scsih_sas_host_add(ioc);
else
- _scsih_sas_host_refresh(ioc, 0);
+ _scsih_sas_host_refresh(ioc);
if (fw_event->ignore) {
dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander "
@@ -4058,6 +4190,17 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
if (_scsih_expander_add(ioc, parent_handle) != 0)
return;
+ spin_lock_irqsave(&ioc->sas_node_lock, flags);
+ sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
+ parent_handle);
+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+ if (sas_expander)
+ sas_address = sas_expander->sas_address;
+ else if (parent_handle < ioc->sas_hba.num_phys)
+ sas_address = ioc->sas_hba.sas_address;
+ else
+ return;
+
/* handle siblings events */
for (i = 0; i < event_data->NumEntries; i++) {
if (fw_event->ignore) {
@@ -4077,48 +4220,47 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
if (!handle)
continue;
- link_rate_ = event_data->PHY[i].LinkRate >> 4;
+ link_rate = event_data->PHY[i].LinkRate >> 4;
+ prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
switch (reason_code) {
case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
+
+ if (link_rate == prev_link_rate)
+ break;
+
+ mpt2sas_transport_update_links(ioc, sas_address,
+ handle, phy_number, link_rate);
+
+ if (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)
+ _scsih_ublock_io_device(ioc, handle);
+ break;
case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
- if (!parent_handle) {
- if (phy_number < ioc->sas_hba.num_phys)
- mpt2sas_transport_update_links(
- ioc,
- ioc->sas_hba.phy[phy_number].handle,
- handle, phy_number, link_rate_);
- } else {
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_expander =
- mpt2sas_scsih_expander_find_by_handle(ioc,
- parent_handle);
- spin_unlock_irqrestore(&ioc->sas_node_lock,
- flags);
- if (sas_expander) {
- if (phy_number < sas_expander->num_phys)
- mpt2sas_transport_update_links(
- ioc,
- sas_expander->
- phy[phy_number].handle,
- handle, phy_number,
- link_rate_);
- }
- }
- if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED) {
- if (link_rate_ < MPI2_SAS_NEG_LINK_RATE_1_5)
- break;
- _scsih_add_device(ioc, handle, phy_number, 0);
- }
+
+ mpt2sas_transport_update_links(ioc, sas_address,
+ handle, phy_number, link_rate);
+
+ _scsih_add_device(ioc, handle, phy_number, 0);
break;
case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
- _scsih_remove_device(ioc, handle);
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = _scsih_sas_device_find_by_handle(ioc,
+ handle);
+ if (!sas_device) {
+ spin_unlock_irqrestore(&ioc->sas_device_lock,
+ flags);
+ break;
+ }
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ _scsih_remove_device(ioc, sas_device);
break;
}
}
/* handle expander removal */
- if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
- _scsih_expander_remove(ioc, parent_handle);
+ if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING &&
+ sas_expander)
+ _scsih_expander_remove(ioc, sas_address);
}
@@ -4170,6 +4312,12 @@ _scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
reason_str = "internal async notification";
break;
+ case MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY:
+ reason_str = "expander reduced functionality";
+ break;
+ case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY:
+ reason_str = "expander reduced functionality complete";
+ break;
default:
reason_str = "unknown reason";
break;
@@ -4197,11 +4345,43 @@ static void
_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
struct fw_event_work *fw_event)
{
+ struct MPT2SAS_TARGET *target_priv_data;
+ struct _sas_device *sas_device;
+ __le64 sas_address;
+ unsigned long flags;
+ Mpi2EventDataSasDeviceStatusChange_t *event_data =
+ fw_event->event_data;
+
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
_scsih_sas_device_status_change_event_debug(ioc,
- fw_event->event_data);
+ event_data);
#endif
+
+ if (!(event_data->ReasonCode ==
+ MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
+ event_data->ReasonCode ==
+ MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET))
+ return;
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_address = le64_to_cpu(event_data->SASAddress);
+ sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_address);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+ if (!sas_device || !sas_device->starget)
+ return;
+
+ target_priv_data = sas_device->starget->hostdata;
+ if (!target_priv_data)
+ return;
+
+ if (event_data->ReasonCode ==
+ MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET)
+ target_priv_data->tm_busy = 1;
+ else
+ target_priv_data->tm_busy = 0;
}
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
@@ -4281,6 +4461,7 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
#endif
+ u16 ioc_status;
dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: "
"phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
event_data->PortWidth));
@@ -4314,8 +4495,9 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
mpt2sas_scsih_issue_tm(ioc, handle, lun,
MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30);
ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
-
- if ((mpi_reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) &&
+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus)
+ & MPI2_IOCSTATUS_MASK;
+ if ((ioc_status == MPI2_IOCSTATUS_SUCCESS) &&
(mpi_reply->ResponseCode ==
MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
mpi_reply->ResponseCode ==
@@ -4570,7 +4752,7 @@ _scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (!sas_device)
return;
- _scsih_remove_device(ioc, handle);
+ _scsih_remove_device(ioc, sas_device);
}
/**
@@ -4591,6 +4773,8 @@ _scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
Mpi2ConfigReply_t mpi_reply;
Mpi2SasDevicePage0_t sas_device_pg0;
u32 ioc_status;
+ u64 sas_address;
+ u16 parent_handle;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
@@ -4615,9 +4799,10 @@ _scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
return;
}
- mpt2sas_transport_update_links(ioc,
- le16_to_cpu(sas_device_pg0.ParentDevHandle),
- handle, sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
+ parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
+ if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
+ mpt2sas_transport_update_links(ioc, sas_address, handle,
+ sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
_scsih_add_device(ioc, handle, 0, 1);
}
@@ -4857,7 +5042,7 @@ static void
_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
struct fw_event_work *fw_event)
{
- u16 handle;
+ u16 handle, parent_handle;
u32 state;
struct _sas_device *sas_device;
unsigned long flags;
@@ -4865,6 +5050,7 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
Mpi2SasDevicePage0_t sas_device_pg0;
u32 ioc_status;
Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data;
+ u64 sas_address;
if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)
return;
@@ -4906,9 +5092,10 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
return;
}
- mpt2sas_transport_update_links(ioc,
- le16_to_cpu(sas_device_pg0.ParentDevHandle),
- handle, sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
+ parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
+ if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
+ mpt2sas_transport_update_links(ioc, sas_address, handle,
+ sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
_scsih_add_device(ioc, handle, 0, 1);
@@ -4948,11 +5135,17 @@ _scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK:
reason_str = "consistency check";
break;
- default:
- reason_str = "unknown reason";
+ case MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT:
+ reason_str = "background init";
+ break;
+ case MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT:
+ reason_str = "make data consistent";
break;
}
+ if (!reason_str)
+ return;
+
printk(MPT2SAS_INFO_FMT "raid operational status: (%s)"
"\thandle(0x%04x), percent complete(%d)\n",
ioc->name, reason_str,
@@ -5252,18 +5445,23 @@ _scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
{
struct _sas_node *sas_expander;
unsigned long flags;
+ int i;
spin_lock_irqsave(&ioc->sas_node_lock, flags);
list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
- if (sas_expander->sas_address == sas_address) {
- sas_expander->responding = 1;
- if (sas_expander->handle != handle) {
- printk(KERN_INFO "old handle(0x%04x)\n",
- sas_expander->handle);
- sas_expander->handle = handle;
- }
+ if (sas_expander->sas_address != sas_address)
+ continue;
+ sas_expander->responding = 1;
+ if (sas_expander->handle == handle)
goto out;
- }
+ printk(KERN_INFO "\texpander(0x%016llx): handle changed"
+ " from(0x%04x) to (0x%04x)!!!\n",
+ (unsigned long long)sas_expander->sas_address,
+ sas_expander->handle, handle);
+ sas_expander->handle = handle;
+ for (i = 0 ; i < sas_expander->num_phys ; i++)
+ sas_expander->phy[i].handle = handle;
+ goto out;
}
out:
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
@@ -5340,7 +5538,9 @@ _scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc)
(unsigned long long)
sas_device->enclosure_logical_id,
sas_device->slot);
- _scsih_remove_device(ioc, sas_device->handle);
+ /* invalidate the device handle */
+ sas_device->handle = 0;
+ _scsih_remove_device(ioc, sas_device);
}
list_for_each_entry_safe(raid_device, raid_device_next,
@@ -5366,7 +5566,7 @@ _scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc)
sas_expander->responding = 0;
continue;
}
- _scsih_expander_remove(ioc, sas_expander->handle);
+ _scsih_expander_remove(ioc, sas_expander->sas_address);
goto retry_expander_search;
}
}
@@ -5406,7 +5606,7 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
case MPT2_IOC_DONE_RESET:
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
"MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
- _scsih_sas_host_refresh(ioc, 0);
+ _scsih_sas_host_refresh(ioc);
_scsih_search_responding_sas_devices(ioc);
_scsih_search_responding_raid_devices(ioc);
_scsih_search_responding_expanders(ioc);
@@ -5646,7 +5846,7 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (!sas_device)
continue;
- _scsih_remove_device(ioc, sas_device->handle);
+ _scsih_remove_device(ioc, sas_device);
if (ioc->shost_recovery)
return;
goto retry_device_search;
@@ -5669,7 +5869,8 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (!expander_sibling)
continue;
- _scsih_expander_remove(ioc, expander_sibling->handle);
+ _scsih_expander_remove(ioc,
+ expander_sibling->sas_address);
if (ioc->shost_recovery)
return;
goto retry_expander_search;
@@ -5677,7 +5878,7 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
}
mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
- sas_expander->parent_handle);
+ sas_expander->sas_address_parent);
printk(MPT2SAS_INFO_FMT "expander_remove: handle"
"(0x%04x), sas_addr(0x%016llx)\n", ioc->name,
@@ -5690,9 +5891,99 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
}
/**
+ * _scsih_ir_shutdown - IR shutdown notification
+ * @ioc: per adapter object
+ *
+ * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that
+ * the host system is shutting down.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc)
+{
+ Mpi2RaidActionRequest_t *mpi_request;
+ Mpi2RaidActionReply_t *mpi_reply;
+ u16 smid;
+
+ /* is IR firmware build loaded ? */
+ if (!ioc->ir_firmware)
+ return;
+
+ /* are there any volumes ? */
+ if (list_empty(&ioc->raid_device_list))
+ return;
+
+ mutex_lock(&ioc->scsih_cmds.mutex);
+
+ if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) {
+ printk(MPT2SAS_ERR_FMT "%s: scsih_cmd in use\n",
+ ioc->name, __func__);
+ goto out;
+ }
+ ioc->scsih_cmds.status = MPT2_CMD_PENDING;
+
+ smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx);
+ if (!smid) {
+ printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+ ioc->name, __func__);
+ ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
+ goto out;
+ }
+
+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+ ioc->scsih_cmds.smid = smid;
+ memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t));
+
+ mpi_request->Function = MPI2_FUNCTION_RAID_ACTION;
+ mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
+
+ printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name);
+ init_completion(&ioc->scsih_cmds.done);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
+
+ if (!(ioc->scsih_cmds.status & MPT2_CMD_COMPLETE)) {
+ printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+ ioc->name, __func__);
+ goto out;
+ }
+
+ if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) {
+ mpi_reply = ioc->scsih_cmds.reply;
+
+ printk(MPT2SAS_INFO_FMT "IR shutdown (complete): "
+ "ioc_status(0x%04x), loginfo(0x%08x)\n",
+ ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo));
+ }
+
+ out:
+ ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
+ mutex_unlock(&ioc->scsih_cmds.mutex);
+}
+
+/**
+ * _scsih_shutdown - routine call during system shutdown
+ * @pdev: PCI device struct
+ *
+ * Return nothing.
+ */
+static void
+_scsih_shutdown(struct pci_dev *pdev)
+{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+ _scsih_ir_shutdown(ioc);
+ mpt2sas_base_detach(ioc);
+}
+
+/**
* _scsih_remove - detach and remove add host
* @pdev: PCI device struct
*
+ * Routine called when unloading the driver.
* Return nothing.
*/
static void __devexit
@@ -5726,7 +6017,7 @@ _scsih_remove(struct pci_dev *pdev)
mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
mpt2sas_port->remote_identify.sas_address);
if (sas_device) {
- _scsih_remove_device(ioc, sas_device->handle);
+ _scsih_remove_device(ioc, sas_device);
goto retry_again;
}
} else {
@@ -5735,7 +6026,7 @@ _scsih_remove(struct pci_dev *pdev)
mpt2sas_port->remote_identify.sas_address);
if (expander_sibling) {
_scsih_expander_remove(ioc,
- expander_sibling->handle);
+ expander_sibling->sas_address);
goto retry_again;
}
}
@@ -5749,7 +6040,7 @@ _scsih_remove(struct pci_dev *pdev)
}
sas_remove_host(shost);
- mpt2sas_base_detach(ioc);
+ _scsih_shutdown(pdev);
list_del(&ioc->list);
scsi_remove_host(shost);
scsi_host_put(shost);
@@ -5770,7 +6061,8 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
void *device;
struct _sas_device *sas_device;
struct _raid_device *raid_device;
- u16 handle, parent_handle;
+ u16 handle;
+ u64 sas_address_parent;
u64 sas_address;
unsigned long flags;
int rc;
@@ -5799,17 +6091,17 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
} else {
sas_device = device;
handle = sas_device->handle;
- parent_handle = sas_device->parent_handle;
+ sas_address_parent = sas_device->sas_address_parent;
sas_address = sas_device->sas_address;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
list_move_tail(&sas_device->list, &ioc->sas_device_list);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
- sas_device->parent_handle)) {
+ sas_device->sas_address_parent)) {
_scsih_sas_device_remove(ioc, sas_device);
} else if (!sas_device->starget) {
mpt2sas_transport_port_remove(ioc, sas_address,
- parent_handle);
+ sas_address_parent);
_scsih_sas_device_remove(ioc, sas_device);
}
}
@@ -5849,8 +6141,6 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
{
struct _sas_device *sas_device, *next;
unsigned long flags;
- u16 handle, parent_handle;
- u64 sas_address;
/* SAS Device List */
list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
@@ -5859,14 +6149,13 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
list_move_tail(&sas_device->list, &ioc->sas_device_list);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- handle = sas_device->handle;
- parent_handle = sas_device->parent_handle;
- sas_address = sas_device->sas_address;
- if (!mpt2sas_transport_port_add(ioc, handle, parent_handle)) {
+ if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
+ sas_device->sas_address_parent)) {
_scsih_sas_device_remove(ioc, sas_device);
} else if (!sas_device->starget) {
- mpt2sas_transport_port_remove(ioc, sas_address,
- parent_handle);
+ mpt2sas_transport_port_remove(ioc,
+ sas_device->sas_address,
+ sas_device->sas_address_parent);
_scsih_sas_device_remove(ioc, sas_device);
}
}
@@ -5935,6 +6224,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->ctl_cb_idx = ctl_cb_idx;
ioc->base_cb_idx = base_cb_idx;
ioc->transport_cb_idx = transport_cb_idx;
+ ioc->scsih_cb_idx = scsih_cb_idx;
ioc->config_cb_idx = config_cb_idx;
ioc->tm_tr_cb_idx = tm_tr_cb_idx;
ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
@@ -6072,6 +6362,7 @@ static struct pci_driver scsih_driver = {
.id_table = scsih_pci_table,
.probe = _scsih_probe,
.remove = __devexit_p(_scsih_remove),
+ .shutdown = _scsih_shutdown,
#ifdef CONFIG_PM
.suspend = _scsih_suspend,
.resume = _scsih_resume,
@@ -6113,6 +6404,9 @@ _scsih_init(void)
transport_cb_idx = mpt2sas_base_register_callback_handler(
mpt2sas_transport_done);
+ /* scsih internal commands callback handler */
+ scsih_cb_idx = mpt2sas_base_register_callback_handler(_scsih_done);
+
/* configuration page API internal commands callback handler */
config_cb_idx = mpt2sas_base_register_callback_handler(
mpt2sas_config_done);
@@ -6152,6 +6446,7 @@ _scsih_exit(void)
mpt2sas_base_release_callback_handler(tm_cb_idx);
mpt2sas_base_release_callback_handler(base_cb_idx);
mpt2sas_base_release_callback_handler(transport_cb_idx);
+ mpt2sas_base_release_callback_handler(scsih_cb_idx);
mpt2sas_base_release_callback_handler(config_cb_idx);
mpt2sas_base_release_callback_handler(ctl_cb_idx);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
index eb98188c7f3f..3a82872bad44 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c
@@ -59,24 +59,23 @@
#include "mpt2sas_base.h"
/**
- * _transport_sas_node_find_by_handle - sas node search
+ * _transport_sas_node_find_by_sas_address - sas node search
* @ioc: per adapter object
- * @handle: expander or hba handle (assigned by firmware)
+ * @sas_address: sas address of expander or sas host
* Context: Calling function should acquire ioc->sas_node_lock.
*
* Search for either hba phys or expander device based on handle, then returns
* the sas_node object.
*/
static struct _sas_node *
-_transport_sas_node_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+_transport_sas_node_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
+ u64 sas_address)
{
- int i;
-
- for (i = 0; i < ioc->sas_hba.num_phys; i++)
- if (ioc->sas_hba.phy[i].handle == handle)
- return &ioc->sas_hba;
-
- return mpt2sas_scsih_expander_find_by_handle(ioc, handle);
+ if (ioc->sas_hba.sas_address == sas_address)
+ return &ioc->sas_hba;
+ else
+ return mpt2sas_scsih_expander_find_by_sas_address(ioc,
+ sas_address);
}
/**
@@ -259,8 +258,7 @@ struct rep_manu_reply{
u8 response_length;
u16 expander_change_count;
u8 reserved0[2];
- u8 sas_format:1;
- u8 reserved1:7;
+ u8 sas_format;
u8 reserved2[3];
u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
@@ -375,7 +373,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
mpi_request->VP_ID = 0;
sas_address_le = (u64 *)&mpi_request->SASAddress;
*sas_address_le = cpu_to_le64(sas_address);
- mpi_request->RequestDataLength = sizeof(struct rep_manu_request);
+ mpi_request->RequestDataLength =
+ cpu_to_le16(sizeof(struct rep_manu_request));
psge = &mpi_request->SGL;
/* WRITE sgel first */
@@ -438,8 +437,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
SAS_EXPANDER_PRODUCT_ID_LEN);
strncpy(edev->product_rev, manufacture_reply->product_rev,
SAS_EXPANDER_PRODUCT_REV_LEN);
- edev->level = manufacture_reply->sas_format;
- if (manufacture_reply->sas_format) {
+ edev->level = manufacture_reply->sas_format & 1;
+ if (edev->level) {
strncpy(edev->component_vendor_id,
manufacture_reply->component_vendor_id,
SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
@@ -469,7 +468,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
* mpt2sas_transport_port_add - insert port to the list
* @ioc: per adapter object
* @handle: handle of attached device
- * @parent_handle: parent handle(either hba or expander)
+ * @sas_address: sas address of parent expander or sas host
* Context: This function will acquire ioc->sas_node_lock.
*
* Adding new port object to the sas_node->sas_port_list.
@@ -478,7 +477,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
*/
struct _sas_port *
mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
- u16 parent_handle)
+ u64 sas_address)
{
struct _sas_phy *mpt2sas_phy, *next;
struct _sas_port *mpt2sas_port;
@@ -488,9 +487,6 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
int i;
struct sas_port *port;
- if (!parent_handle)
- return NULL;
-
mpt2sas_port = kzalloc(sizeof(struct _sas_port),
GFP_KERNEL);
if (!mpt2sas_port) {
@@ -502,17 +498,16 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
INIT_LIST_HEAD(&mpt2sas_port->port_list);
INIT_LIST_HEAD(&mpt2sas_port->phy_list);
spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle);
+ sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (!sas_node) {
- printk(MPT2SAS_ERR_FMT "%s: Could not find parent(0x%04x)!\n",
- ioc->name, __func__, parent_handle);
+ printk(MPT2SAS_ERR_FMT "%s: Could not find "
+ "parent sas_address(0x%016llx)!\n", ioc->name,
+ __func__, (unsigned long long)sas_address);
goto out_fail;
}
- mpt2sas_port->handle = parent_handle;
- mpt2sas_port->sas_address = sas_node->sas_address;
if ((_transport_set_identify(ioc, handle,
&mpt2sas_port->remote_identify))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
@@ -604,7 +599,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
* mpt2sas_transport_port_remove - remove port from the list
* @ioc: per adapter object
* @sas_address: sas address of attached device
- * @parent_handle: handle to the upstream parent(either hba or expander)
+ * @sas_address_parent: sas address of parent expander or sas host
* Context: This function will acquire ioc->sas_node_lock.
*
* Removing object and freeing associated memory from the
@@ -614,7 +609,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
*/
void
mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
- u16 parent_handle)
+ u64 sas_address_parent)
{
int i;
unsigned long flags;
@@ -624,7 +619,8 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
struct _sas_phy *mpt2sas_phy, *next_phy;
spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle);
+ sas_node = _transport_sas_node_find_by_sas_address(ioc,
+ sas_address_parent);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (!sas_node)
return;
@@ -650,8 +646,7 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
&mpt2sas_port->phy_list, port_siblings) {
if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
dev_printk(KERN_INFO, &mpt2sas_port->port->dev,
- "remove: parent_handle(0x%04x), "
- "sas_addr(0x%016llx), phy(%d)\n", parent_handle,
+ "remove: sas_addr(0x%016llx), phy(%d)\n",
(unsigned long long)
mpt2sas_port->remote_identify.sas_address,
mpt2sas_phy->phy_id);
@@ -799,8 +794,8 @@ mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
/**
* mpt2sas_transport_update_links - refreshing phy link changes
* @ioc: per adapter object
- * @handle: handle to sas_host or expander
- * @attached_handle: attached device handle
+ * @sas_address: sas address of parent expander or sas host
+ * @handle: attached device handle
* @phy_numberv: phy number
* @link_rate: new link rate
*
@@ -808,28 +803,25 @@ mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
*/
void
mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
- u16 handle, u16 attached_handle, u8 phy_number, u8 link_rate)
+ u64 sas_address, u16 handle, u8 phy_number, u8 link_rate)
{
unsigned long flags;
struct _sas_node *sas_node;
struct _sas_phy *mpt2sas_phy;
- if (ioc->shost_recovery) {
- printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
+ if (ioc->shost_recovery)
return;
- }
spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_node = _transport_sas_node_find_by_handle(ioc, handle);
+ sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (!sas_node)
return;
mpt2sas_phy = &sas_node->phy[phy_number];
- mpt2sas_phy->attached_handle = attached_handle;
- if (attached_handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5))
- _transport_set_identify(ioc, mpt2sas_phy->attached_handle,
+ mpt2sas_phy->attached_handle = handle;
+ if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5))
+ _transport_set_identify(ioc, handle,
&mpt2sas_phy->remote_identify);
else
memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct
@@ -841,13 +833,11 @@ mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
- "refresh: handle(0x%04x), sas_addr(0x%016llx),\n"
+ "refresh: parent sas_addr(0x%016llx),\n"
"\tlink_rate(0x%02x), phy(%d)\n"
"\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
- handle, (unsigned long long)
- mpt2sas_phy->identify.sas_address, link_rate,
- phy_number, attached_handle,
- (unsigned long long)
+ (unsigned long long)sas_address,
+ link_rate, phy_number, handle, (unsigned long long)
mpt2sas_phy->remote_identify.sas_address);
}
@@ -1126,7 +1116,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
if (!dma_addr_out) {
- mpt2sas_base_free_smid(ioc, le16_to_cpu(smid));
+ mpt2sas_base_free_smid(ioc, smid);
goto unmap;
}
@@ -1144,7 +1134,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio),
blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
if (!dma_addr_in) {
- mpt2sas_base_free_smid(ioc, le16_to_cpu(smid));
+ mpt2sas_base_free_smid(ioc, smid);
goto unmap;
}
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index 2be7d5b018d2..2c98a6ee973b 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -1419,7 +1419,7 @@ static irqreturn_t do_nsp32_isr(int irq, void *dev_id)
nsp32_msg(KERN_ERR, "Received unexpected BMCNTERR IRQ! ");
/*
* TODO: To be implemented improving bus master
- * transfer reliablity when BMCNTERR is occurred in
+ * transfer reliability when BMCNTERR is occurred in
* AutoSCSI phase described in specification.
*/
}
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index 7a117c18114c..60b7ca1e9bc0 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -73,7 +73,8 @@ static const char *_osd_ver_desc(struct osd_request *or)
#define ATTR_DEF_RI(id, len) ATTR_DEF(OSD_APAGE_ROOT_INFORMATION, id, len)
-static int _osd_print_system_info(struct osd_dev *od, void *caps)
+static int _osd_get_print_system_info(struct osd_dev *od,
+ void *caps, struct osd_dev_info *odi)
{
struct osd_request *or;
struct osd_attr get_attrs[] = {
@@ -137,8 +138,12 @@ static int _osd_print_system_info(struct osd_dev *od, void *caps)
OSD_INFO("PRODUCT_SERIAL_NUMBER [%s]\n",
(char *)pFirst);
- pFirst = get_attrs[a].val_ptr;
- OSD_INFO("OSD_NAME [%s]\n", (char *)pFirst);
+ odi->osdname_len = get_attrs[a].len;
+ /* Avoid NULL for memcmp optimization 0-length is good enough */
+ odi->osdname = kzalloc(odi->osdname_len + 1, GFP_KERNEL);
+ if (odi->osdname_len)
+ memcpy(odi->osdname, get_attrs[a].val_ptr, odi->osdname_len);
+ OSD_INFO("OSD_NAME [%s]\n", odi->osdname);
a++;
pFirst = get_attrs[a++].val_ptr;
@@ -171,6 +176,14 @@ static int _osd_print_system_info(struct osd_dev *od, void *caps)
sid_dump, sizeof(sid_dump), true);
OSD_INFO("OSD_SYSTEM_ID(%d)\n"
" [%s]\n", len, sid_dump);
+
+ if (unlikely(len > sizeof(odi->systemid))) {
+ OSD_ERR("OSD Target error: OSD_SYSTEM_ID too long(%d). "
+ "device idetification might not work\n", len);
+ len = sizeof(odi->systemid);
+ }
+ odi->systemid_len = len;
+ memcpy(odi->systemid, get_attrs[a].val_ptr, len);
a++;
}
out:
@@ -178,16 +191,17 @@ out:
return ret;
}
-int osd_auto_detect_ver(struct osd_dev *od, void *caps)
+int osd_auto_detect_ver(struct osd_dev *od,
+ void *caps, struct osd_dev_info *odi)
{
int ret;
/* Auto-detect the osd version */
- ret = _osd_print_system_info(od, caps);
+ ret = _osd_get_print_system_info(od, caps, odi);
if (ret) {
osd_dev_set_ver(od, OSD_VER1);
OSD_DEBUG("converting to OSD1\n");
- ret = _osd_print_system_info(od, caps);
+ ret = _osd_get_print_system_info(od, caps, odi);
}
return ret;
diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c
index 0bdef3390902..25ef993b7d8d 100644
--- a/drivers/scsi/osd/osd_uld.c
+++ b/drivers/scsi/osd/osd_uld.c
@@ -71,8 +71,7 @@
#define SCSI_OSD_MAX_MINOR 64
static const char osd_name[] = "osd";
-static const char *osd_version_string = "open-osd 0.1.0";
-const char osd_symlink[] = "scsi_osd";
+static const char *osd_version_string = "open-osd 0.2.0";
MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>");
MODULE_DESCRIPTION("open-osd Upper-Layer-Driver osd.ko");
@@ -80,18 +79,34 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV_MAJOR(SCSI_OSD_MAJOR);
MODULE_ALIAS_SCSI_DEVICE(TYPE_OSD);
+#define OSD_FMT_d "osd%d"
+
struct osd_uld_device {
int minor;
- struct kref kref;
struct cdev cdev;
struct osd_dev od;
+ struct osd_dev_info odi;
struct gendisk *disk;
struct device *class_member;
+ typeof(((struct device *)NULL)->release) save_release;
};
+struct osd_dev_handle {
+ struct osd_dev od;
+ struct file *file;
+ struct osd_uld_device *oud;
+} ;
+
+static DEFINE_IDA(osd_minor_ida);
+
static void __uld_get(struct osd_uld_device *oud);
static void __uld_put(struct osd_uld_device *oud);
+static struct class osd_uld_class = {
+ .owner = THIS_MODULE,
+ .name = "scsi_osd",
+};
+
/*
* Char Device operations
*/
@@ -177,7 +192,7 @@ static const struct file_operations osd_fops = {
struct osd_dev *osduld_path_lookup(const char *name)
{
struct osd_uld_device *oud;
- struct osd_dev *od;
+ struct osd_dev_handle *odh;
struct file *file;
int error;
@@ -186,8 +201,8 @@ struct osd_dev *osduld_path_lookup(const char *name)
return ERR_PTR(-EINVAL);
}
- od = kzalloc(sizeof(*od), GFP_KERNEL);
- if (!od)
+ odh = kzalloc(sizeof(*odh), GFP_KERNEL);
+ if (unlikely(!odh))
return ERR_PTR(-ENOMEM);
file = filp_open(name, O_RDWR, 0);
@@ -203,33 +218,134 @@ struct osd_dev *osduld_path_lookup(const char *name)
oud = file->private_data;
- *od = oud->od;
- od->file = file;
+ odh->od = oud->od;
+ odh->file = file;
+ odh->oud = oud;
- return od;
+ return &odh->od;
close_file:
fput(file);
free_od:
- kfree(od);
+ kfree(odh);
return ERR_PTR(error);
}
EXPORT_SYMBOL(osduld_path_lookup);
-void osduld_put_device(struct osd_dev *od)
+static inline bool _the_same_or_null(const u8 *a1, unsigned a1_len,
+ const u8 *a2, unsigned a2_len)
+{
+ if (!a2_len) /* User string is Empty means don't care */
+ return true;
+
+ if (a1_len != a2_len)
+ return false;
+
+ return 0 == memcmp(a1, a2, a1_len);
+}
+
+struct find_oud_t {
+ const struct osd_dev_info *odi;
+ struct device *dev;
+ struct osd_uld_device *oud;
+} ;
+
+int _mach_odi(struct device *dev, void *find_data)
+{
+ struct osd_uld_device *oud = dev_get_drvdata(dev);
+ struct find_oud_t *fot = find_data;
+ const struct osd_dev_info *odi = fot->odi;
+
+ if (_the_same_or_null(oud->odi.systemid, oud->odi.systemid_len,
+ odi->systemid, odi->systemid_len) &&
+ _the_same_or_null(oud->odi.osdname, oud->odi.osdname_len,
+ odi->osdname, odi->osdname_len)) {
+ OSD_DEBUG("found device sysid_len=%d osdname=%d\n",
+ odi->systemid_len, odi->osdname_len);
+ fot->oud = oud;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/* osduld_info_lookup - Loop through all devices, return the requested osd_dev.
+ *
+ * if @odi->systemid_len and/or @odi->osdname_len are zero, they act as a don't
+ * care. .e.g if they're both zero /dev/osd0 is returned.
+ */
+struct osd_dev *osduld_info_lookup(const struct osd_dev_info *odi)
{
+ struct find_oud_t find = {.odi = odi};
+
+ find.dev = class_find_device(&osd_uld_class, NULL, &find, _mach_odi);
+ if (likely(find.dev)) {
+ struct osd_dev_handle *odh = kzalloc(sizeof(*odh), GFP_KERNEL);
+
+ if (unlikely(!odh)) {
+ put_device(find.dev);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ odh->od = find.oud->od;
+ odh->oud = find.oud;
+ return &odh->od;
+ }
+
+ return ERR_PTR(-ENODEV);
+}
+EXPORT_SYMBOL(osduld_info_lookup);
+
+void osduld_put_device(struct osd_dev *od)
+{
if (od && !IS_ERR(od)) {
- struct osd_uld_device *oud = od->file->private_data;
+ struct osd_dev_handle *odh =
+ container_of(od, struct osd_dev_handle, od);
+ struct osd_uld_device *oud = odh->oud;
BUG_ON(od->scsi_device != oud->od.scsi_device);
- fput(od->file);
- kfree(od);
+ /* If scsi has released the device (logout), and exofs has last
+ * reference on oud it will be freed by above osd_uld_release
+ * within fput below. But this will oops in cdev_release which
+ * is called after the fops->release. __uld_get/put pair makes
+ * sure we have a cdev for the duration of fput
+ */
+ __uld_get(oud);
+ if (odh->file)
+ fput(odh->file);
+ else
+ put_device(oud->class_member);
+ __uld_put(oud);
+ kfree(odh);
}
}
EXPORT_SYMBOL(osduld_put_device);
+const struct osd_dev_info *osduld_device_info(struct osd_dev *od)
+{
+ struct osd_dev_handle *odh =
+ container_of(od, struct osd_dev_handle, od);
+ return &odh->oud->odi;
+}
+EXPORT_SYMBOL(osduld_device_info);
+
+bool osduld_device_same(struct osd_dev *od, const struct osd_dev_info *odi)
+{
+ struct osd_dev_handle *odh =
+ container_of(od, struct osd_dev_handle, od);
+ struct osd_uld_device *oud = odh->oud;
+
+ return (oud->odi.systemid_len == odi->systemid_len) &&
+ _the_same_or_null(oud->odi.systemid, oud->odi.systemid_len,
+ odi->systemid, odi->systemid_len) &&
+ (oud->odi.osdname_len == odi->osdname_len) &&
+ _the_same_or_null(oud->odi.osdname, oud->odi.osdname_len,
+ odi->osdname, odi->osdname_len);
+}
+EXPORT_SYMBOL(osduld_device_same);
+
/*
* Scsi Device operations
*/
@@ -250,14 +366,35 @@ static int __detect_osd(struct osd_uld_device *oud)
OSD_ERR("warning: scsi_test_unit_ready failed\n");
osd_sec_init_nosec_doall_caps(caps, &osd_root_object, false, true);
- if (osd_auto_detect_ver(&oud->od, caps))
+ if (osd_auto_detect_ver(&oud->od, caps, &oud->odi))
return -ENODEV;
return 0;
}
-static struct class *osd_sysfs_class;
-static DEFINE_IDA(osd_minor_ida);
+static void __remove(struct device *dev)
+{
+ struct osd_uld_device *oud = dev_get_drvdata(dev);
+ struct scsi_device *scsi_device = oud->od.scsi_device;
+
+ kfree(oud->odi.osdname);
+ oud->save_release(oud->class_member);
+
+ if (oud->cdev.owner)
+ cdev_del(&oud->cdev);
+
+ osd_dev_fini(&oud->od);
+ scsi_device_put(scsi_device);
+
+ OSD_INFO("osd_remove %s\n",
+ oud->disk ? oud->disk->disk_name : NULL);
+
+ if (oud->disk)
+ put_disk(oud->disk);
+ ida_remove(&osd_minor_ida, oud->minor);
+
+ kfree(oud);
+}
static int osd_probe(struct device *dev)
{
@@ -289,7 +426,6 @@ static int osd_probe(struct device *dev)
if (NULL == oud)
goto err_retract_minor;
- kref_init(&oud->kref);
dev_set_drvdata(dev, oud);
oud->minor = minor;
@@ -302,7 +438,7 @@ static int osd_probe(struct device *dev)
}
disk->major = SCSI_OSD_MAJOR;
disk->first_minor = oud->minor;
- sprintf(disk->disk_name, "osd%d", oud->minor);
+ sprintf(disk->disk_name, OSD_FMT_d, oud->minor);
oud->disk = disk;
/* hold one more reference to the scsi_device that will get released
@@ -327,18 +463,19 @@ static int osd_probe(struct device *dev)
OSD_ERR("cdev_add failed\n");
goto err_put_disk;
}
- kobject_get(&oud->cdev.kobj); /* 2nd ref see osd_remove() */
/* class_member */
- oud->class_member = device_create(osd_sysfs_class, dev,
- MKDEV(SCSI_OSD_MAJOR, oud->minor), "%s", disk->disk_name);
+ oud->class_member = device_create(&osd_uld_class, dev,
+ MKDEV(SCSI_OSD_MAJOR, oud->minor), oud, disk->disk_name);
if (IS_ERR(oud->class_member)) {
OSD_ERR("class_device_create failed\n");
error = PTR_ERR(oud->class_member);
goto err_put_cdev;
}
+ oud->save_release = oud->class_member->release;
+ oud->class_member->release = __remove;
- dev_set_drvdata(oud->class_member, oud);
+ __uld_get(oud);
OSD_INFO("osd_probe %s\n", disk->disk_name);
return 0;
@@ -368,51 +505,21 @@ static int osd_remove(struct device *dev)
}
if (oud->class_member)
- device_destroy(osd_sysfs_class,
+ device_destroy(&osd_uld_class,
MKDEV(SCSI_OSD_MAJOR, oud->minor));
- /* We have 2 references to the cdev. One is released here
- * and also takes down the /dev/osdX mapping. The second
- * Will be released in __remove() after all users have released
- * the osd_uld_device.
- */
- if (oud->cdev.owner)
- cdev_del(&oud->cdev);
-
__uld_put(oud);
return 0;
}
-static void __remove(struct kref *kref)
-{
- struct osd_uld_device *oud = container_of(kref,
- struct osd_uld_device, kref);
- struct scsi_device *scsi_device = oud->od.scsi_device;
-
- /* now let delete the char_dev */
- kobject_put(&oud->cdev.kobj);
-
- osd_dev_fini(&oud->od);
- scsi_device_put(scsi_device);
-
- OSD_INFO("osd_remove %s\n",
- oud->disk ? oud->disk->disk_name : NULL);
-
- if (oud->disk)
- put_disk(oud->disk);
-
- ida_remove(&osd_minor_ida, oud->minor);
- kfree(oud);
-}
-
static void __uld_get(struct osd_uld_device *oud)
{
- kref_get(&oud->kref);
+ get_device(oud->class_member);
}
static void __uld_put(struct osd_uld_device *oud)
{
- kref_put(&oud->kref, __remove);
+ put_device(oud->class_member);
}
/*
@@ -432,11 +539,10 @@ static int __init osd_uld_init(void)
{
int err;
- osd_sysfs_class = class_create(THIS_MODULE, osd_symlink);
- if (IS_ERR(osd_sysfs_class)) {
- OSD_ERR("Unable to register sysfs class => %ld\n",
- PTR_ERR(osd_sysfs_class));
- return PTR_ERR(osd_sysfs_class);
+ err = class_register(&osd_uld_class);
+ if (err) {
+ OSD_ERR("Unable to register sysfs class => %d\n", err);
+ return err;
}
err = register_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0),
@@ -459,7 +565,7 @@ static int __init osd_uld_init(void)
err_out_chrdev:
unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR);
err_out:
- class_destroy(osd_sysfs_class);
+ class_unregister(&osd_uld_class);
return err;
}
@@ -467,7 +573,7 @@ static void __exit osd_uld_exit(void)
{
scsi_unregister_driver(&osd_driver.gendrv);
unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR);
- class_destroy(osd_sysfs_class);
+ class_unregister(&osd_uld_class);
OSD_INFO("UNLOADED %s\n", osd_version_string);
}
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 5987da857103..108655230b59 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -898,7 +898,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
scsi_print_sense("", cmd);
scsi_print_command(cmd);
}
- if (blk_end_request_err(req, -EIO))
+ if (blk_end_request_err(req, error))
scsi_requeue_command(q, cmd);
else
scsi_next_command(cmd);
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index c44783801402..74598a416334 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -317,6 +317,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
out_device_destroy:
scsi_device_set_state(sdev, SDEV_DEL);
transport_destroy_device(&sdev->sdev_gendev);
+ put_device(&sdev->sdev_dev);
put_device(&sdev->sdev_gendev);
out:
if (display_failure_msg)
@@ -957,6 +958,7 @@ static inline void scsi_destroy_sdev(struct scsi_device *sdev)
if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev);
transport_destroy_device(&sdev->sdev_gendev);
+ put_device(&sdev->sdev_dev);
put_device(&sdev->sdev_gendev);
}
@@ -1468,7 +1470,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
for (i = 0; i < sizeof(struct scsi_lun); i++)
printk("%02x", data[i]);
printk(" has a LUN larger than currently supported.\n");
- } else if (lun > sdev->host->max_lun) {
+ } else if (lun >= sdev->host->max_lun) {
printk(KERN_WARNING "scsi: %s lun%d has a LUN larger"
" than allowed by the host adapter\n",
devname, lun);
@@ -1681,7 +1683,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
((id != SCAN_WILD_CARD) && (id >= shost->max_id)) ||
- ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
+ ((lun != SCAN_WILD_CARD) && (lun >= shost->max_lun)))
return -EINVAL;
mutex_lock(&shost->scan_mutex);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index fde54537d715..5c7eb63a19d1 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -864,10 +864,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
goto clean_device;
}
- /* take a reference for the sdev_dev; this is
- * released by the sdev_class .release */
- get_device(&sdev->sdev_gendev);
-
/* create queue files, which may be writable, depending on the host */
if (sdev->host->hostt->change_queue_depth)
error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_depth_rw);
@@ -917,6 +913,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
device_del(&sdev->sdev_gendev);
transport_destroy_device(&sdev->sdev_gendev);
+ put_device(&sdev->sdev_dev);
put_device(&sdev->sdev_gendev);
return error;
@@ -1065,7 +1062,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
device_initialize(&sdev->sdev_dev);
- sdev->sdev_dev.parent = &sdev->sdev_gendev;
+ sdev->sdev_dev.parent = get_device(&sdev->sdev_gendev);
sdev->sdev_dev.class = &sdev_class;
dev_set_name(&sdev->sdev_dev, "%d:%d:%d:%d",
sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index a67fed10598a..51ab0c090051 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -1992,7 +1992,7 @@ fc_user_scan(struct Scsi_Host *shost, uint channel, uint id, uint lun)
if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
((id != SCAN_WILD_CARD) && (id >= shost->max_id)) ||
- ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
+ ((lun != SCAN_WILD_CARD) && (lun >= shost->max_lun)))
return -EINVAL;
if (channel == SCAN_WILD_CARD) {
@@ -2384,6 +2384,7 @@ fc_rport_final_delete(struct work_struct *work)
struct Scsi_Host *shost = rport_to_shost(rport);
struct fc_internal *i = to_fc_internal(shost->transportt);
unsigned long flags;
+ int do_callback = 0;
/*
* if a scan is pending, flush the SCSI Host work_q so that
@@ -2422,8 +2423,15 @@ fc_rport_final_delete(struct work_struct *work)
* Avoid this call if we already called it when we preserved the
* rport for the binding.
*/
+ spin_lock_irqsave(shost->host_lock, flags);
if (!(rport->flags & FC_RPORT_DEVLOSS_CALLBK_DONE) &&
- (i->f->dev_loss_tmo_callbk))
+ (i->f->dev_loss_tmo_callbk)) {
+ rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE;
+ do_callback = 1;
+ }
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ if (do_callback)
i->f->dev_loss_tmo_callbk(rport);
fc_bsg_remove(rport->rqst_q);
@@ -2970,6 +2978,7 @@ fc_timeout_deleted_rport(struct work_struct *work)
struct fc_internal *i = to_fc_internal(shost->transportt);
struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
unsigned long flags;
+ int do_callback = 0;
spin_lock_irqsave(shost->host_lock, flags);
@@ -3035,7 +3044,6 @@ fc_timeout_deleted_rport(struct work_struct *work)
rport->roles = FC_PORT_ROLE_UNKNOWN;
rport->port_state = FC_PORTSTATE_NOTPRESENT;
rport->flags &= ~FC_RPORT_FAST_FAIL_TIMEDOUT;
- rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE;
/*
* Pre-emptively kill I/O rather than waiting for the work queue
@@ -3045,32 +3053,40 @@ fc_timeout_deleted_rport(struct work_struct *work)
spin_unlock_irqrestore(shost->host_lock, flags);
fc_terminate_rport_io(rport);
- BUG_ON(rport->port_state != FC_PORTSTATE_NOTPRESENT);
+ spin_lock_irqsave(shost->host_lock, flags);
- /* remove the identifiers that aren't used in the consisting binding */
- switch (fc_host->tgtid_bind_type) {
- case FC_TGTID_BIND_BY_WWPN:
- rport->node_name = -1;
- rport->port_id = -1;
- break;
- case FC_TGTID_BIND_BY_WWNN:
- rport->port_name = -1;
- rport->port_id = -1;
- break;
- case FC_TGTID_BIND_BY_ID:
- rport->node_name = -1;
- rport->port_name = -1;
- break;
- case FC_TGTID_BIND_NONE: /* to keep compiler happy */
- break;
+ if (rport->port_state == FC_PORTSTATE_NOTPRESENT) { /* still missing */
+
+ /* remove the identifiers that aren't used in the consisting binding */
+ switch (fc_host->tgtid_bind_type) {
+ case FC_TGTID_BIND_BY_WWPN:
+ rport->node_name = -1;
+ rport->port_id = -1;
+ break;
+ case FC_TGTID_BIND_BY_WWNN:
+ rport->port_name = -1;
+ rport->port_id = -1;
+ break;
+ case FC_TGTID_BIND_BY_ID:
+ rport->node_name = -1;
+ rport->port_name = -1;
+ break;
+ case FC_TGTID_BIND_NONE: /* to keep compiler happy */
+ break;
+ }
+
+ /*
+ * As this only occurs if the remote port (scsi target)
+ * went away and didn't come back - we'll remove
+ * all attached scsi devices.
+ */
+ rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE;
+ fc_queue_work(shost, &rport->stgt_delete_work);
+
+ do_callback = 1;
}
- /*
- * As this only occurs if the remote port (scsi target)
- * went away and didn't come back - we'll remove
- * all attached scsi devices.
- */
- fc_queue_work(shost, &rport->stgt_delete_work);
+ spin_unlock_irqrestore(shost->host_lock, flags);
/*
* Notify the driver that the rport is now dead. The LLDD will
@@ -3078,7 +3094,7 @@ fc_timeout_deleted_rport(struct work_struct *work)
*
* Note: we set the CALLBK_DONE flag above to correspond
*/
- if (i->f->dev_loss_tmo_callbk)
+ if (do_callback && i->f->dev_loss_tmo_callbk)
i->f->dev_loss_tmo_callbk(rport);
}
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index 09fa8861fc58..3058bb1aff95 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -36,11 +36,11 @@
#include <scsi/scsi_eh.h>
#define DRV_NAME "stex"
-#define ST_DRIVER_VERSION "4.6.0000.3"
+#define ST_DRIVER_VERSION "4.6.0000.4"
#define ST_VER_MAJOR 4
#define ST_VER_MINOR 6
#define ST_OEM 0
-#define ST_BUILD_VER 3
+#define ST_BUILD_VER 4
enum {
/* MU register offset */
@@ -64,24 +64,24 @@ enum {
YH2I_REQ_HI = 0xc4,
/* MU register value */
- MU_INBOUND_DOORBELL_HANDSHAKE = 1,
- MU_INBOUND_DOORBELL_REQHEADCHANGED = 2,
- MU_INBOUND_DOORBELL_STATUSTAILCHANGED = 4,
- MU_INBOUND_DOORBELL_HMUSTOPPED = 8,
- MU_INBOUND_DOORBELL_RESET = 16,
-
- MU_OUTBOUND_DOORBELL_HANDSHAKE = 1,
- MU_OUTBOUND_DOORBELL_REQUESTTAILCHANGED = 2,
- MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED = 4,
- MU_OUTBOUND_DOORBELL_BUSCHANGE = 8,
- MU_OUTBOUND_DOORBELL_HASEVENT = 16,
+ MU_INBOUND_DOORBELL_HANDSHAKE = (1 << 0),
+ MU_INBOUND_DOORBELL_REQHEADCHANGED = (1 << 1),
+ MU_INBOUND_DOORBELL_STATUSTAILCHANGED = (1 << 2),
+ MU_INBOUND_DOORBELL_HMUSTOPPED = (1 << 3),
+ MU_INBOUND_DOORBELL_RESET = (1 << 4),
+
+ MU_OUTBOUND_DOORBELL_HANDSHAKE = (1 << 0),
+ MU_OUTBOUND_DOORBELL_REQUESTTAILCHANGED = (1 << 1),
+ MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED = (1 << 2),
+ MU_OUTBOUND_DOORBELL_BUSCHANGE = (1 << 3),
+ MU_OUTBOUND_DOORBELL_HASEVENT = (1 << 4),
+ MU_OUTBOUND_DOORBELL_REQUEST_RESET = (1 << 27),
/* MU status code */
MU_STATE_STARTING = 1,
- MU_STATE_FMU_READY_FOR_HANDSHAKE = 2,
- MU_STATE_SEND_HANDSHAKE_FRAME = 3,
- MU_STATE_STARTED = 4,
- MU_STATE_RESETTING = 5,
+ MU_STATE_STARTED = 2,
+ MU_STATE_RESETTING = 3,
+ MU_STATE_FAILED = 4,
MU_MAX_DELAY = 120,
MU_HANDSHAKE_SIGNATURE = 0x55aaaa55,
@@ -111,6 +111,8 @@ enum {
SS_H2I_INT_RESET = 0x100,
+ SS_I2H_REQUEST_RESET = 0x2000,
+
SS_MU_OPERATIONAL = 0x80000000,
STEX_CDB_LENGTH = 16,
@@ -160,6 +162,7 @@ enum {
INQUIRY_EVPD = 0x01,
ST_ADDITIONAL_MEM = 0x200000,
+ ST_ADDITIONAL_MEM_MIN = 0x80000,
};
struct st_sgitem {
@@ -311,6 +314,10 @@ struct st_hba {
struct st_ccb *wait_ccb;
__le32 *scratch;
+ char work_q_name[20];
+ struct workqueue_struct *work_q;
+ struct work_struct reset_work;
+ wait_queue_head_t reset_waitq;
unsigned int mu_status;
unsigned int cardtype;
int msi_enabled;
@@ -577,6 +584,9 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
lun = cmd->device->lun;
hba = (struct st_hba *) &host->hostdata[0];
+ if (unlikely(hba->mu_status == MU_STATE_RESETTING))
+ return SCSI_MLQUEUE_HOST_BUSY;
+
switch (cmd->cmnd[0]) {
case MODE_SENSE_10:
{
@@ -841,7 +851,6 @@ static irqreturn_t stex_intr(int irq, void *__hba)
void __iomem *base = hba->mmio_base;
u32 data;
unsigned long flags;
- int handled = 0;
spin_lock_irqsave(hba->host->host_lock, flags);
@@ -852,12 +861,16 @@ static irqreturn_t stex_intr(int irq, void *__hba)
writel(data, base + ODBL);
readl(base + ODBL); /* flush */
stex_mu_intr(hba, data);
- handled = 1;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ if (unlikely(data & MU_OUTBOUND_DOORBELL_REQUEST_RESET &&
+ hba->cardtype == st_shasta))
+ queue_work(hba->work_q, &hba->reset_work);
+ return IRQ_HANDLED;
}
spin_unlock_irqrestore(hba->host->host_lock, flags);
- return IRQ_RETVAL(handled);
+ return IRQ_NONE;
}
static void stex_ss_mu_intr(struct st_hba *hba)
@@ -939,7 +952,6 @@ static irqreturn_t stex_ss_intr(int irq, void *__hba)
void __iomem *base = hba->mmio_base;
u32 data;
unsigned long flags;
- int handled = 0;
spin_lock_irqsave(hba->host->host_lock, flags);
@@ -948,12 +960,15 @@ static irqreturn_t stex_ss_intr(int irq, void *__hba)
/* clear the interrupt */
writel(data, base + YI2H_INT_C);
stex_ss_mu_intr(hba);
- handled = 1;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ if (unlikely(data & SS_I2H_REQUEST_RESET))
+ queue_work(hba->work_q, &hba->reset_work);
+ return IRQ_HANDLED;
}
spin_unlock_irqrestore(hba->host->host_lock, flags);
- return IRQ_RETVAL(handled);
+ return IRQ_NONE;
}
static int stex_common_handshake(struct st_hba *hba)
@@ -1001,7 +1016,7 @@ static int stex_common_handshake(struct st_hba *hba)
h->partner_type = HMU_PARTNER_TYPE;
if (hba->extra_offset) {
h->extra_offset = cpu_to_le32(hba->extra_offset);
- h->extra_size = cpu_to_le32(ST_ADDITIONAL_MEM);
+ h->extra_size = cpu_to_le32(hba->dma_size - hba->extra_offset);
} else
h->extra_offset = h->extra_size = 0;
@@ -1046,7 +1061,7 @@ static int stex_ss_handshake(struct st_hba *hba)
struct st_msg_header *msg_h;
struct handshake_frame *h;
__le32 *scratch;
- u32 data;
+ u32 data, scratch_size;
unsigned long before;
int ret = 0;
@@ -1074,13 +1089,16 @@ static int stex_ss_handshake(struct st_hba *hba)
stex_gettime(&h->hosttime);
h->partner_type = HMU_PARTNER_TYPE;
h->extra_offset = h->extra_size = 0;
- h->scratch_size = cpu_to_le32((hba->sts_count+1)*sizeof(u32));
+ scratch_size = (hba->sts_count+1)*sizeof(u32);
+ h->scratch_size = cpu_to_le32(scratch_size);
data = readl(base + YINT_EN);
data &= ~4;
writel(data, base + YINT_EN);
writel((hba->dma_handle >> 16) >> 16, base + YH2I_REQ_HI);
+ readl(base + YH2I_REQ_HI);
writel(hba->dma_handle, base + YH2I_REQ);
+ readl(base + YH2I_REQ); /* flush */
scratch = hba->scratch;
before = jiffies;
@@ -1096,7 +1114,7 @@ static int stex_ss_handshake(struct st_hba *hba)
msleep(1);
}
- *scratch = 0;
+ memset(scratch, 0, scratch_size);
msg_h->flag = 0;
return ret;
}
@@ -1105,19 +1123,24 @@ static int stex_handshake(struct st_hba *hba)
{
int err;
unsigned long flags;
+ unsigned int mu_status;
err = (hba->cardtype == st_yel) ?
stex_ss_handshake(hba) : stex_common_handshake(hba);
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ mu_status = hba->mu_status;
if (err == 0) {
- spin_lock_irqsave(hba->host->host_lock, flags);
hba->req_head = 0;
hba->req_tail = 0;
hba->status_head = 0;
hba->status_tail = 0;
hba->out_req_cnt = 0;
hba->mu_status = MU_STATE_STARTED;
- spin_unlock_irqrestore(hba->host->host_lock, flags);
- }
+ } else
+ hba->mu_status = MU_STATE_FAILED;
+ if (mu_status == MU_STATE_RESETTING)
+ wake_up_all(&hba->reset_waitq);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
return err;
}
@@ -1137,17 +1160,11 @@ static int stex_abort(struct scsi_cmnd *cmd)
base = hba->mmio_base;
spin_lock_irqsave(host->host_lock, flags);
- if (tag < host->can_queue && hba->ccb[tag].cmd == cmd)
+ if (tag < host->can_queue &&
+ hba->ccb[tag].req && hba->ccb[tag].cmd == cmd)
hba->wait_ccb = &hba->ccb[tag];
- else {
- for (tag = 0; tag < host->can_queue; tag++)
- if (hba->ccb[tag].cmd == cmd) {
- hba->wait_ccb = &hba->ccb[tag];
- break;
- }
- if (tag >= host->can_queue)
- goto out;
- }
+ else
+ goto out;
if (hba->cardtype == st_yel) {
data = readl(base + YI2H_INT);
@@ -1221,6 +1238,37 @@ static void stex_hard_reset(struct st_hba *hba)
hba->pdev->saved_config_space[i]);
}
+static int stex_yos_reset(struct st_hba *hba)
+{
+ void __iomem *base;
+ unsigned long flags, before;
+ int ret = 0;
+
+ base = hba->mmio_base;
+ writel(MU_INBOUND_DOORBELL_RESET, base + IDBL);
+ readl(base + IDBL); /* flush */
+ before = jiffies;
+ while (hba->out_req_cnt > 0) {
+ if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) {
+ printk(KERN_WARNING DRV_NAME
+ "(%s): reset timeout\n", pci_name(hba->pdev));
+ ret = -1;
+ break;
+ }
+ msleep(1);
+ }
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ if (ret == -1)
+ hba->mu_status = MU_STATE_FAILED;
+ else
+ hba->mu_status = MU_STATE_STARTED;
+ wake_up_all(&hba->reset_waitq);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ return ret;
+}
+
static void stex_ss_reset(struct st_hba *hba)
{
writel(SS_H2I_INT_RESET, hba->mmio_base + YH2I_INT);
@@ -1228,66 +1276,86 @@ static void stex_ss_reset(struct st_hba *hba)
ssleep(5);
}
-static int stex_reset(struct scsi_cmnd *cmd)
+static int stex_do_reset(struct st_hba *hba)
{
- struct st_hba *hba;
- void __iomem *base;
- unsigned long flags, before;
+ struct st_ccb *ccb;
+ unsigned long flags;
+ unsigned int mu_status = MU_STATE_RESETTING;
+ u16 tag;
- hba = (struct st_hba *) &cmd->device->host->hostdata[0];
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ if (hba->mu_status == MU_STATE_STARTING) {
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ printk(KERN_INFO DRV_NAME "(%s): request reset during init\n",
+ pci_name(hba->pdev));
+ return 0;
+ }
+ while (hba->mu_status == MU_STATE_RESETTING) {
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ wait_event_timeout(hba->reset_waitq,
+ hba->mu_status != MU_STATE_RESETTING,
+ MU_MAX_DELAY * HZ);
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ mu_status = hba->mu_status;
+ }
- printk(KERN_INFO DRV_NAME
- "(%s): resetting host\n", pci_name(hba->pdev));
- scsi_print_command(cmd);
+ if (mu_status != MU_STATE_RESETTING) {
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ return (mu_status == MU_STATE_STARTED) ? 0 : -1;
+ }
hba->mu_status = MU_STATE_RESETTING;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ if (hba->cardtype == st_yosemite)
+ return stex_yos_reset(hba);
if (hba->cardtype == st_shasta)
stex_hard_reset(hba);
else if (hba->cardtype == st_yel)
stex_ss_reset(hba);
- if (hba->cardtype != st_yosemite) {
- if (stex_handshake(hba)) {
- printk(KERN_WARNING DRV_NAME
- "(%s): resetting: handshake failed\n",
- pci_name(hba->pdev));
- return FAILED;
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ for (tag = 0; tag < hba->host->can_queue; tag++) {
+ ccb = &hba->ccb[tag];
+ if (ccb->req == NULL)
+ continue;
+ ccb->req = NULL;
+ if (ccb->cmd) {
+ scsi_dma_unmap(ccb->cmd);
+ ccb->cmd->result = DID_RESET << 16;
+ ccb->cmd->scsi_done(ccb->cmd);
+ ccb->cmd = NULL;
}
- return SUCCESS;
}
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
- /* st_yosemite */
- writel(MU_INBOUND_DOORBELL_RESET, hba->mmio_base + IDBL);
- readl(hba->mmio_base + IDBL); /* flush */
- before = jiffies;
- while (hba->out_req_cnt > 0) {
- if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) {
- printk(KERN_WARNING DRV_NAME
- "(%s): reset timeout\n", pci_name(hba->pdev));
- return FAILED;
- }
- msleep(1);
- }
+ if (stex_handshake(hba) == 0)
+ return 0;
- base = hba->mmio_base;
- writel(0, base + IMR0);
- readl(base + IMR0);
- writel(0, base + OMR0);
- readl(base + OMR0);
- writel(0, base + IMR1);
- readl(base + IMR1);
- writel(0, base + OMR1);
- readl(base + OMR1); /* flush */
- spin_lock_irqsave(hba->host->host_lock, flags);
- hba->req_head = 0;
- hba->req_tail = 0;
- hba->status_head = 0;
- hba->status_tail = 0;
- hba->out_req_cnt = 0;
- hba->mu_status = MU_STATE_STARTED;
- spin_unlock_irqrestore(hba->host->host_lock, flags);
- return SUCCESS;
+ printk(KERN_WARNING DRV_NAME "(%s): resetting: handshake failed\n",
+ pci_name(hba->pdev));
+ return -1;
+}
+
+static int stex_reset(struct scsi_cmnd *cmd)
+{
+ struct st_hba *hba;
+
+ hba = (struct st_hba *) &cmd->device->host->hostdata[0];
+
+ printk(KERN_INFO DRV_NAME
+ "(%s): resetting host\n", pci_name(hba->pdev));
+ scsi_print_command(cmd);
+
+ return stex_do_reset(hba) ? FAILED : SUCCESS;
+}
+
+static void stex_reset_work(struct work_struct *work)
+{
+ struct st_hba *hba = container_of(work, struct st_hba, reset_work);
+
+ stex_do_reset(hba);
}
static int stex_biosparam(struct scsi_device *sdev,
@@ -1420,8 +1488,8 @@ static int stex_set_dma_mask(struct pci_dev * pdev)
{
int ret;
- if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
- && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
+ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
+ && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
return 0;
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (!ret)
@@ -1528,10 +1596,24 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
hba->dma_mem = dma_alloc_coherent(&pdev->dev,
hba->dma_size, &hba->dma_handle, GFP_KERNEL);
if (!hba->dma_mem) {
- err = -ENOMEM;
- printk(KERN_ERR DRV_NAME "(%s): dma mem alloc failed\n",
- pci_name(pdev));
- goto out_iounmap;
+ /* Retry minimum coherent mapping for st_seq and st_vsc */
+ if (hba->cardtype == st_seq ||
+ (hba->cardtype == st_vsc && (pdev->subsystem_device & 1))) {
+ printk(KERN_WARNING DRV_NAME
+ "(%s): allocating min buffer for controller\n",
+ pci_name(pdev));
+ hba->dma_size = hba->extra_offset
+ + ST_ADDITIONAL_MEM_MIN;
+ hba->dma_mem = dma_alloc_coherent(&pdev->dev,
+ hba->dma_size, &hba->dma_handle, GFP_KERNEL);
+ }
+
+ if (!hba->dma_mem) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRV_NAME "(%s): dma mem alloc failed\n",
+ pci_name(pdev));
+ goto out_iounmap;
+ }
}
hba->ccb = kcalloc(ci->rq_count, sizeof(struct st_ccb), GFP_KERNEL);
@@ -1568,12 +1650,24 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
hba->host = host;
hba->pdev = pdev;
+ init_waitqueue_head(&hba->reset_waitq);
+
+ snprintf(hba->work_q_name, sizeof(hba->work_q_name),
+ "stex_wq_%d", host->host_no);
+ hba->work_q = create_singlethread_workqueue(hba->work_q_name);
+ if (!hba->work_q) {
+ printk(KERN_ERR DRV_NAME "(%s): create workqueue failed\n",
+ pci_name(pdev));
+ err = -ENOMEM;
+ goto out_ccb_free;
+ }
+ INIT_WORK(&hba->reset_work, stex_reset_work);
err = stex_request_irq(hba);
if (err) {
printk(KERN_ERR DRV_NAME "(%s): request irq failed\n",
pci_name(pdev));
- goto out_ccb_free;
+ goto out_free_wq;
}
err = stex_handshake(hba);
@@ -1602,6 +1696,8 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
out_free_irq:
stex_free_irq(hba);
+out_free_wq:
+ destroy_workqueue(hba->work_q);
out_ccb_free:
kfree(hba->ccb);
out_pci_free:
@@ -1669,6 +1765,8 @@ static void stex_hba_free(struct st_hba *hba)
{
stex_free_irq(hba);
+ destroy_workqueue(hba->work_q);
+
iounmap(hba->mmio_base);
pci_release_regions(hba->pdev);
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index d7bcd074d383..7ce9e9f567a3 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -705,7 +705,7 @@ mpc52xx_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
return -EINVAL;
if ((ser->irq != port->irq) ||
- (ser->io_type != SERIAL_IO_MEM) ||
+ (ser->io_type != UPIO_MEM) ||
(ser->baud_base != port->uartclk) ||
(ser->iomem_base != (void *)port->mapbase) ||
(ser->hub6 != 0))
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index ff4617e21426..7bf02cf3123f 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -426,21 +426,6 @@ static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
/*====================================================================*/
-static int
-first_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse)
-{
- int i;
- i = pcmcia_get_first_tuple(handle, tuple);
- if (i != 0)
- return i;
- i = pcmcia_get_tuple_data(handle, tuple);
- if (i != 0)
- return i;
- return pcmcia_parse_tuple(tuple, parse);
-}
-
-/*====================================================================*/
-
static int simple_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cf,
cistpl_cftable_entry_t *dflt,
@@ -665,6 +650,25 @@ static int multi_config(struct pcmcia_device *link)
return 0;
}
+static int serial_check_for_multi(struct pcmcia_device *p_dev,
+ cistpl_cftable_entry_t *cf,
+ cistpl_cftable_entry_t *dflt,
+ unsigned int vcc,
+ void *priv_data)
+{
+ struct serial_info *info = p_dev->priv;
+
+ if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
+ info->multi = cf->io.win[0].len >> 3;
+
+ if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
+ (cf->io.win[1].len == 8))
+ info->multi = 2;
+
+ return 0; /* break */
+}
+
+
/*======================================================================
serial_config() is scheduled to run after a CARD_INSERTION event
@@ -676,46 +680,14 @@ static int multi_config(struct pcmcia_device *link)
static int serial_config(struct pcmcia_device * link)
{
struct serial_info *info = link->priv;
- struct serial_cfg_mem *cfg_mem;
- tuple_t *tuple;
- u_char *buf;
- cisparse_t *parse;
- cistpl_cftable_entry_t *cf;
- int i, last_ret, last_fn;
+ int i;
DEBUG(0, "serial_config(0x%p)\n", link);
- cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
- if (!cfg_mem)
- goto failed;
-
- tuple = &cfg_mem->tuple;
- parse = &cfg_mem->parse;
- cf = &parse->cftable_entry;
- buf = cfg_mem->buf;
-
- tuple->TupleData = (cisdata_t *) buf;
- tuple->TupleOffset = 0;
- tuple->TupleDataMax = 255;
- tuple->Attributes = 0;
-
- /* Get configuration register information */
- tuple->DesiredTuple = CISTPL_CONFIG;
- last_ret = first_tuple(link, tuple, parse);
- if (last_ret != 0) {
- last_fn = ParseTuple;
- goto cs_failed;
- }
- link->conf.ConfigBase = parse->config.base;
- link->conf.Present = parse->config.rmask[0];
-
/* Is this a compliant multifunction card? */
- tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
- tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
- info->multi = (first_tuple(link, tuple, parse) == 0);
+ info->multi = (link->socket->functions > 1);
/* Is this a multiport card? */
- tuple->DesiredTuple = CISTPL_MANFID;
info->manfid = link->manf_id;
info->prodid = link->card_id;
@@ -730,20 +702,11 @@ static int serial_config(struct pcmcia_device * link)
/* Another check for dual-serial cards: look for either serial or
multifunction cards that ask for appropriate IO port ranges */
- tuple->DesiredTuple = CISTPL_FUNCID;
if ((info->multi == 0) &&
(link->has_func_id) &&
((link->func_id == CISTPL_FUNCID_MULTI) ||
- (link->func_id == CISTPL_FUNCID_SERIAL))) {
- tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
- if (first_tuple(link, tuple, parse) == 0) {
- if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
- info->multi = cf->io.win[0].len >> 3;
- if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
- (cf->io.win[1].len == 8))
- info->multi = 2;
- }
- }
+ (link->func_id == CISTPL_FUNCID_SERIAL)))
+ pcmcia_loop_config(link, serial_check_for_multi, info);
/*
* Apply any multi-port quirk.
@@ -768,14 +731,10 @@ static int serial_config(struct pcmcia_device * link)
goto failed;
link->dev_node = &info->node[0];
- kfree(cfg_mem);
return 0;
-cs_failed:
- cs_error(link, last_fn, last_ret);
failed:
serial_remove(link);
- kfree(cfg_mem);
return -ENODEV;
}
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
index 559b5fe9dc0f..94e6e46ff82c 100644
--- a/drivers/sh/intc.c
+++ b/drivers/sh/intc.c
@@ -70,9 +70,7 @@ static LIST_HEAD(intc_list);
#endif
static unsigned int intc_prio_level[NR_IRQS]; /* for now */
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
static unsigned long ack_handle[NR_IRQS];
-#endif
static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
{
@@ -250,7 +248,6 @@ static int intc_set_wake(unsigned int irq, unsigned int on)
return 0; /* allow wakeup, but setup hardware in intc_suspend() */
}
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
static void intc_mask_ack(unsigned int irq)
{
struct intc_desc_int *d = get_intc_desc(irq);
@@ -282,7 +279,6 @@ static void intc_mask_ack(unsigned int irq)
}
}
}
-#endif
static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
unsigned int nr_hp,
@@ -501,7 +497,6 @@ static unsigned int __init intc_prio_data(struct intc_desc *desc,
return 0;
}
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
static unsigned int __init intc_ack_data(struct intc_desc *desc,
struct intc_desc_int *d,
intc_enum enum_id)
@@ -533,7 +528,6 @@ static unsigned int __init intc_ack_data(struct intc_desc *desc,
return 0;
}
-#endif
static unsigned int __init intc_sense_data(struct intc_desc *desc,
struct intc_desc_int *d,
@@ -641,10 +635,8 @@ static void __init intc_register_irq(struct intc_desc *desc,
/* irq should be disabled by default */
d->chip.mask(irq);
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
if (desc->ack_regs)
ack_handle[irq] = intc_ack_data(desc, d, enum_id);
-#endif
}
static unsigned int __init save_reg(struct intc_desc_int *d,
@@ -681,10 +673,8 @@ void __init register_intc_controller(struct intc_desc *desc)
d->nr_reg = desc->mask_regs ? desc->nr_mask_regs * 2 : 0;
d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0;
d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0;
-
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
d->nr_reg += desc->ack_regs ? desc->nr_ack_regs : 0;
-#endif
+
d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT);
#ifdef CONFIG_SMP
d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT);
@@ -727,14 +717,12 @@ void __init register_intc_controller(struct intc_desc *desc)
d->chip.set_type = intc_set_sense;
d->chip.set_wake = intc_set_wake;
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
if (desc->ack_regs) {
for (i = 0; i < desc->nr_ack_regs; i++)
k += save_reg(d, k, desc->ack_regs[i].set_reg, 0);
d->chip.mask_ack = intc_mask_ack;
}
-#endif
BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c
index 93c20e135ee1..4e8f57d4131f 100644
--- a/drivers/sh/maple/maple.c
+++ b/drivers/sh/maple/maple.c
@@ -106,7 +106,7 @@ static void maple_dma_reset(void)
* max delay is 11
*/
ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(0xFFFF), MAPLE_SPEED);
- ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR);
+ ctrl_outl(virt_to_phys(maple_sendbuf), MAPLE_DMAADDR);
ctrl_outl(1, MAPLE_ENABLE);
}
@@ -258,7 +258,7 @@ static void maple_build_block(struct mapleq *mq)
maple_lastptr = maple_sendptr;
*maple_sendptr++ = (port << 16) | len | 0x80000000;
- *maple_sendptr++ = PHYSADDR(mq->recvbuf->buf);
+ *maple_sendptr++ = virt_to_phys(mq->recvbuf->buf);
*maple_sendptr++ =
mq->command | (to << 8) | (from << 16) | (len << 24);
while (len-- > 0)
diff --git a/drivers/spi/au1550_spi.c b/drivers/spi/au1550_spi.c
index 76cbc1a66598..c343f0082291 100644
--- a/drivers/spi/au1550_spi.c
+++ b/drivers/spi/au1550_spi.c
@@ -406,11 +406,13 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t)
}
/* put buffers on the ring */
- res = au1xxx_dbdma_put_dest(hw->dma_rx_ch, hw->rx, t->len);
+ res = au1xxx_dbdma_put_dest(hw->dma_rx_ch, virt_to_phys(hw->rx),
+ t->len, DDMA_FLAGS_IE);
if (!res)
dev_err(hw->dev, "rx dma put dest error\n");
- res = au1xxx_dbdma_put_source(hw->dma_tx_ch, (void *)hw->tx, t->len);
+ res = au1xxx_dbdma_put_source(hw->dma_tx_ch, virt_to_phys(hw->tx),
+ t->len, DDMA_FLAGS_IE);
if (!res)
dev_err(hw->dev, "tx dma put source error\n");
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
index ba1a872b221e..bf5f95a19413 100644
--- a/drivers/spi/omap2_mcspi.c
+++ b/drivers/spi/omap2_mcspi.c
@@ -35,8 +35,8 @@
#include <linux/spi/spi.h>
-#include <mach/dma.h>
-#include <mach/clock.h>
+#include <plat/dma.h>
+#include <plat/clock.h>
#define OMAP2_MCSPI_MAX_FREQ 48000000
diff --git a/drivers/spi/omap_uwire.c b/drivers/spi/omap_uwire.c
index e75ba9b28898..6c3a8557db27 100644
--- a/drivers/spi/omap_uwire.c
+++ b/drivers/spi/omap_uwire.c
@@ -51,8 +51,8 @@
#include <asm/io.h>
#include <asm/mach-types.h>
-#include <mach/mux.h>
-#include <mach/omap730.h> /* OMAP730_IO_CONF registers */
+#include <plat/mux.h>
+#include <plat/omap7xx.h> /* OMAP7XX_IO_CONF registers */
/* FIXME address is now a platform device resource,
@@ -504,7 +504,7 @@ static int __init uwire_probe(struct platform_device *pdev)
}
clk_enable(uwire->ck);
- if (cpu_is_omap730())
+ if (cpu_is_omap7xx())
uwire_idx_shift = 1;
else
uwire_idx_shift = 2;
@@ -573,8 +573,8 @@ static int __init omap_uwire_init(void)
}
if (machine_is_omap_perseus2()) {
/* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */
- int val = omap_readl(OMAP730_IO_CONF_9) & ~0x00EEE000;
- omap_writel(val | 0x00AAA000, OMAP730_IO_CONF_9);
+ int val = omap_readl(OMAP7XX_IO_CONF_9) & ~0x00EEE000;
+ omap_writel(val | 0x00AAA000, OMAP7XX_IO_CONF_9);
}
return platform_driver_probe(&uwire_driver, uwire_probe);
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 5d23983f02fc..d9b4100ade9c 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -42,7 +42,7 @@
* This supports acccess to SPI devices using normal userspace I/O calls.
* Note that while traditional UNIX/POSIX I/O semantics are half duplex,
* and often mask message boundaries, full SPI support requires full duplex
- * transfers. There are several kinds of of internal message boundaries to
+ * transfers. There are several kinds of internal message boundaries to
* handle chipselect management and other protocol options.
*
* SPI has a character major number assigned. We allocate minor numbers
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
index 538c570df337..f1dcd7969a5c 100644
--- a/drivers/ssb/driver_pcicore.c
+++ b/drivers/ssb/driver_pcicore.c
@@ -551,13 +551,13 @@ int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
might_sleep_if(pdev->id.coreid != SSB_DEV_PCI);
/* Enable interrupts for this device. */
- if (bus->host_pci &&
- ((pdev->id.revision >= 6) || (pdev->id.coreid == SSB_DEV_PCIE))) {
+ if ((pdev->id.revision >= 6) || (pdev->id.coreid == SSB_DEV_PCIE)) {
u32 coremask;
/* Calculate the "coremask" for the device. */
coremask = (1 << dev->core_index);
+ SSB_WARN_ON(bus->bustype != SSB_BUSTYPE_PCI);
err = pci_read_config_dword(bus->host_pci, SSB_PCI_IRQMASK, &tmp);
if (err)
goto out;
diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c
index 100e7a5c5ea1..e72f4046a5e0 100644
--- a/drivers/ssb/pcmcia.c
+++ b/drivers/ssb/pcmcia.c
@@ -617,136 +617,140 @@ static int ssb_pcmcia_sprom_check_crc(const u16 *sprom, size_t size)
} \
} while (0)
-int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
- struct ssb_init_invariants *iv)
+static int ssb_pcmcia_get_mac(struct pcmcia_device *p_dev,
+ tuple_t *tuple,
+ void *priv)
{
- tuple_t tuple;
- int res;
- unsigned char buf[32];
+ struct ssb_sprom *sprom = priv;
+
+ if (tuple->TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID)
+ return -EINVAL;
+ if (tuple->TupleDataLen != ETH_ALEN + 2)
+ return -EINVAL;
+ if (tuple->TupleData[1] != ETH_ALEN)
+ return -EINVAL;
+ memcpy(sprom->il0mac, &tuple->TupleData[2], ETH_ALEN);
+ return 0;
+};
+
+static int ssb_pcmcia_do_get_invariants(struct pcmcia_device *p_dev,
+ tuple_t *tuple,
+ void *priv)
+{
+ struct ssb_init_invariants *iv = priv;
struct ssb_sprom *sprom = &iv->sprom;
struct ssb_boardinfo *bi = &iv->boardinfo;
const char *error_description;
+ GOTO_ERROR_ON(tuple->TupleDataLen < 1, "VEN tpl < 1");
+ switch (tuple->TupleData[0]) {
+ case SSB_PCMCIA_CIS_ID:
+ GOTO_ERROR_ON((tuple->TupleDataLen != 5) &&
+ (tuple->TupleDataLen != 7),
+ "id tpl size");
+ bi->vendor = tuple->TupleData[1] |
+ ((u16)tuple->TupleData[2] << 8);
+ break;
+ case SSB_PCMCIA_CIS_BOARDREV:
+ GOTO_ERROR_ON(tuple->TupleDataLen != 2,
+ "boardrev tpl size");
+ sprom->board_rev = tuple->TupleData[1];
+ break;
+ case SSB_PCMCIA_CIS_PA:
+ GOTO_ERROR_ON((tuple->TupleDataLen != 9) &&
+ (tuple->TupleDataLen != 10),
+ "pa tpl size");
+ sprom->pa0b0 = tuple->TupleData[1] |
+ ((u16)tuple->TupleData[2] << 8);
+ sprom->pa0b1 = tuple->TupleData[3] |
+ ((u16)tuple->TupleData[4] << 8);
+ sprom->pa0b2 = tuple->TupleData[5] |
+ ((u16)tuple->TupleData[6] << 8);
+ sprom->itssi_a = tuple->TupleData[7];
+ sprom->itssi_bg = tuple->TupleData[7];
+ sprom->maxpwr_a = tuple->TupleData[8];
+ sprom->maxpwr_bg = tuple->TupleData[8];
+ break;
+ case SSB_PCMCIA_CIS_OEMNAME:
+ /* We ignore this. */
+ break;
+ case SSB_PCMCIA_CIS_CCODE:
+ GOTO_ERROR_ON(tuple->TupleDataLen != 2,
+ "ccode tpl size");
+ sprom->country_code = tuple->TupleData[1];
+ break;
+ case SSB_PCMCIA_CIS_ANTENNA:
+ GOTO_ERROR_ON(tuple->TupleDataLen != 2,
+ "ant tpl size");
+ sprom->ant_available_a = tuple->TupleData[1];
+ sprom->ant_available_bg = tuple->TupleData[1];
+ break;
+ case SSB_PCMCIA_CIS_ANTGAIN:
+ GOTO_ERROR_ON(tuple->TupleDataLen != 2,
+ "antg tpl size");
+ sprom->antenna_gain.ghz24.a0 = tuple->TupleData[1];
+ sprom->antenna_gain.ghz24.a1 = tuple->TupleData[1];
+ sprom->antenna_gain.ghz24.a2 = tuple->TupleData[1];
+ sprom->antenna_gain.ghz24.a3 = tuple->TupleData[1];
+ sprom->antenna_gain.ghz5.a0 = tuple->TupleData[1];
+ sprom->antenna_gain.ghz5.a1 = tuple->TupleData[1];
+ sprom->antenna_gain.ghz5.a2 = tuple->TupleData[1];
+ sprom->antenna_gain.ghz5.a3 = tuple->TupleData[1];
+ break;
+ case SSB_PCMCIA_CIS_BFLAGS:
+ GOTO_ERROR_ON((tuple->TupleDataLen != 3) &&
+ (tuple->TupleDataLen != 5),
+ "bfl tpl size");
+ sprom->boardflags_lo = tuple->TupleData[1] |
+ ((u16)tuple->TupleData[2] << 8);
+ break;
+ case SSB_PCMCIA_CIS_LEDS:
+ GOTO_ERROR_ON(tuple->TupleDataLen != 5,
+ "leds tpl size");
+ sprom->gpio0 = tuple->TupleData[1];
+ sprom->gpio1 = tuple->TupleData[2];
+ sprom->gpio2 = tuple->TupleData[3];
+ sprom->gpio3 = tuple->TupleData[4];
+ break;
+ }
+ return -ENOSPC; /* continue with next entry */
+
+error:
+ ssb_printk(KERN_ERR PFX
+ "PCMCIA: Failed to fetch device invariants: %s\n",
+ error_description);
+ return -ENODEV;
+}
+
+
+int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
+ struct ssb_init_invariants *iv)
+{
+ struct ssb_sprom *sprom = &iv->sprom;
+ int res;
+
memset(sprom, 0xFF, sizeof(*sprom));
sprom->revision = 1;
sprom->boardflags_lo = 0;
sprom->boardflags_hi = 0;
/* First fetch the MAC address. */
- memset(&tuple, 0, sizeof(tuple));
- tuple.DesiredTuple = CISTPL_FUNCE;
- tuple.TupleData = buf;
- tuple.TupleDataMax = sizeof(buf);
- res = pcmcia_get_first_tuple(bus->host_pcmcia, &tuple);
- GOTO_ERROR_ON(res != 0, "MAC first tpl");
- res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
- GOTO_ERROR_ON(res != 0, "MAC first tpl data");
- while (1) {
- GOTO_ERROR_ON(tuple.TupleDataLen < 1, "MAC tpl < 1");
- if (tuple.TupleData[0] == CISTPL_FUNCE_LAN_NODE_ID)
- break;
- res = pcmcia_get_next_tuple(bus->host_pcmcia, &tuple);
- GOTO_ERROR_ON(res != 0, "MAC next tpl");
- res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
- GOTO_ERROR_ON(res != 0, "MAC next tpl data");
+ res = pcmcia_loop_tuple(bus->host_pcmcia, CISTPL_FUNCE,
+ ssb_pcmcia_get_mac, sprom);
+ if (res != 0) {
+ ssb_printk(KERN_ERR PFX
+ "PCMCIA: Failed to fetch MAC address\n");
+ return -ENODEV;
}
- GOTO_ERROR_ON(tuple.TupleDataLen != ETH_ALEN + 2, "MAC tpl size");
- memcpy(sprom->il0mac, &tuple.TupleData[2], ETH_ALEN);
/* Fetch the vendor specific tuples. */
- memset(&tuple, 0, sizeof(tuple));
- tuple.DesiredTuple = SSB_PCMCIA_CIS;
- tuple.TupleData = buf;
- tuple.TupleDataMax = sizeof(buf);
- res = pcmcia_get_first_tuple(bus->host_pcmcia, &tuple);
- GOTO_ERROR_ON(res != 0, "VEN first tpl");
- res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
- GOTO_ERROR_ON(res != 0, "VEN first tpl data");
- while (1) {
- GOTO_ERROR_ON(tuple.TupleDataLen < 1, "VEN tpl < 1");
- switch (tuple.TupleData[0]) {
- case SSB_PCMCIA_CIS_ID:
- GOTO_ERROR_ON((tuple.TupleDataLen != 5) &&
- (tuple.TupleDataLen != 7),
- "id tpl size");
- bi->vendor = tuple.TupleData[1] |
- ((u16)tuple.TupleData[2] << 8);
- break;
- case SSB_PCMCIA_CIS_BOARDREV:
- GOTO_ERROR_ON(tuple.TupleDataLen != 2,
- "boardrev tpl size");
- sprom->board_rev = tuple.TupleData[1];
- break;
- case SSB_PCMCIA_CIS_PA:
- GOTO_ERROR_ON((tuple.TupleDataLen != 9) &&
- (tuple.TupleDataLen != 10),
- "pa tpl size");
- sprom->pa0b0 = tuple.TupleData[1] |
- ((u16)tuple.TupleData[2] << 8);
- sprom->pa0b1 = tuple.TupleData[3] |
- ((u16)tuple.TupleData[4] << 8);
- sprom->pa0b2 = tuple.TupleData[5] |
- ((u16)tuple.TupleData[6] << 8);
- sprom->itssi_a = tuple.TupleData[7];
- sprom->itssi_bg = tuple.TupleData[7];
- sprom->maxpwr_a = tuple.TupleData[8];
- sprom->maxpwr_bg = tuple.TupleData[8];
- break;
- case SSB_PCMCIA_CIS_OEMNAME:
- /* We ignore this. */
- break;
- case SSB_PCMCIA_CIS_CCODE:
- GOTO_ERROR_ON(tuple.TupleDataLen != 2,
- "ccode tpl size");
- sprom->country_code = tuple.TupleData[1];
- break;
- case SSB_PCMCIA_CIS_ANTENNA:
- GOTO_ERROR_ON(tuple.TupleDataLen != 2,
- "ant tpl size");
- sprom->ant_available_a = tuple.TupleData[1];
- sprom->ant_available_bg = tuple.TupleData[1];
- break;
- case SSB_PCMCIA_CIS_ANTGAIN:
- GOTO_ERROR_ON(tuple.TupleDataLen != 2,
- "antg tpl size");
- sprom->antenna_gain.ghz24.a0 = tuple.TupleData[1];
- sprom->antenna_gain.ghz24.a1 = tuple.TupleData[1];
- sprom->antenna_gain.ghz24.a2 = tuple.TupleData[1];
- sprom->antenna_gain.ghz24.a3 = tuple.TupleData[1];
- sprom->antenna_gain.ghz5.a0 = tuple.TupleData[1];
- sprom->antenna_gain.ghz5.a1 = tuple.TupleData[1];
- sprom->antenna_gain.ghz5.a2 = tuple.TupleData[1];
- sprom->antenna_gain.ghz5.a3 = tuple.TupleData[1];
- break;
- case SSB_PCMCIA_CIS_BFLAGS:
- GOTO_ERROR_ON((tuple.TupleDataLen != 3) &&
- (tuple.TupleDataLen != 5),
- "bfl tpl size");
- sprom->boardflags_lo = tuple.TupleData[1] |
- ((u16)tuple.TupleData[2] << 8);
- break;
- case SSB_PCMCIA_CIS_LEDS:
- GOTO_ERROR_ON(tuple.TupleDataLen != 5,
- "leds tpl size");
- sprom->gpio0 = tuple.TupleData[1];
- sprom->gpio1 = tuple.TupleData[2];
- sprom->gpio2 = tuple.TupleData[3];
- sprom->gpio3 = tuple.TupleData[4];
- break;
- }
- res = pcmcia_get_next_tuple(bus->host_pcmcia, &tuple);
- if (res == -ENOSPC)
- break;
- GOTO_ERROR_ON(res != 0, "VEN next tpl");
- res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple);
- GOTO_ERROR_ON(res != 0, "VEN next tpl data");
- }
+ res = pcmcia_loop_tuple(bus->host_pcmcia, SSB_PCMCIA_CIS,
+ ssb_pcmcia_do_get_invariants, sprom);
+ if ((res == 0) || (res == -ENOSPC))
+ return 0;
- return 0;
-error:
ssb_printk(KERN_ERR PFX
- "PCMCIA: Failed to fetch device invariants: %s\n",
- error_description);
+ "PCMCIA: Failed to fetch device invariants\n");
return -ENODEV;
}
diff --git a/drivers/staging/iio/ring_sw.h b/drivers/staging/iio/ring_sw.h
index f0b86f02cd80..fd677f008365 100644
--- a/drivers/staging/iio/ring_sw.h
+++ b/drivers/staging/iio/ring_sw.h
@@ -29,7 +29,6 @@
* driver requests - some may support multiple options */
-#include <linux/autoconf.h>
#include "iio.h"
#include "ring_generic.h"
diff --git a/drivers/staging/netwave/Kconfig b/drivers/staging/netwave/Kconfig
index b6f0f0a3ca58..c0c996c0550a 100644
--- a/drivers/staging/netwave/Kconfig
+++ b/drivers/staging/netwave/Kconfig
@@ -2,6 +2,7 @@ config PCMCIA_NETWAVE
tristate "Xircom Netwave AirSurfer Pcmcia wireless support"
depends on PCMCIA
select WIRELESS_EXT
+ select WEXT_PRIV
help
Say Y here if you intend to attach this type of PCMCIA (PC-card)
wireless Ethernet networking card to your computer.
diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c
index 4ce399b6d237..f98a52448eae 100644
--- a/drivers/staging/panel/panel.c
+++ b/drivers/staging/panel/panel.c
@@ -55,7 +55,7 @@
#include <linux/list.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
#include <linux/io.h>
#include <asm/uaccess.h>
diff --git a/drivers/staging/rtl8187se/Kconfig b/drivers/staging/rtl8187se/Kconfig
index 236e42725447..faf6c6087414 100644
--- a/drivers/staging/rtl8187se/Kconfig
+++ b/drivers/staging/rtl8187se/Kconfig
@@ -1,6 +1,7 @@
config RTL8187SE
tristate "RealTek RTL8187SE Wireless LAN NIC driver"
depends on PCI
- depends on WIRELESS_EXT
+ select WIRELESS_EXT
+ select WEXT_PRIV
default N
---help---
diff --git a/drivers/staging/rtl8187se/r8180.h b/drivers/staging/rtl8187se/r8180.h
index 8216d7e96d60..35ed60be891a 100644
--- a/drivers/staging/rtl8187se/r8180.h
+++ b/drivers/staging/rtl8187se/r8180.h
@@ -521,7 +521,7 @@ typedef struct r8180_priv
//u32 NumTxOkInPeriod; //YJ,del,080828
u8 TxPollingTimes;
- bool bApBufOurFrame;// TRUE if AP buffer our unicast data , we will keep eAwake untill receive data or timeout.
+ bool bApBufOurFrame;// TRUE if AP buffer our unicast data , we will keep eAwake until receive data or timeout.
u8 WaitBufDataBcnCount;
u8 WaitBufDataTimeOut;
diff --git a/drivers/staging/rtl8192e/Kconfig b/drivers/staging/rtl8192e/Kconfig
index 3100aa58c940..5c077b9fdc77 100644
--- a/drivers/staging/rtl8192e/Kconfig
+++ b/drivers/staging/rtl8192e/Kconfig
@@ -1,6 +1,7 @@
config RTL8192E
tristate "RealTek RTL8192E Wireless LAN NIC driver"
depends on PCI
- depends on WIRELESS_EXT
+ select WIRELESS_EXT
+ select WEXT_PRIV
default N
---help---
diff --git a/drivers/staging/tm6000/Kconfig b/drivers/staging/tm6000/Kconfig
new file mode 100644
index 000000000000..cb2011536363
--- /dev/null
+++ b/drivers/staging/tm6000/Kconfig
@@ -0,0 +1,32 @@
+config VIDEO_TM6000
+ tristate "TV Master TM5600/6000/6010 driver"
+ depends on VIDEO_DEV && I2C && INPUT && EXPERIMENTAL
+ select VIDEO_TUNER
+ select TUNER_XC2028
+ select VIDEOBUF_VMALLOC
+ help
+ Support for TM5600/TM6000/TM6010 USB Device
+
+ Since these cards have no MPEG decoder onboard, they transmit
+ only compressed MPEG data over the usb bus, so you need
+ an external software decoder to watch TV on your computer.
+
+ Say Y if you own such a device and want to use it.
+
+config VIDEO_TM6000_ALSA
+ tristate "TV Master TM5600/6000/6010 audio support"
+ depends on VIDEO_TM6000 && SND && EXPERIMENTAL
+ select SND_PCM
+ ---help---
+ This is a video4linux driver for direct (DMA) audio for
+ TM5600/TM6000/TM6010 USB Devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tm6000-alsa.
+
+config VIDEO_TM6000_DVB
+ bool "DVB Support for tm6000 based TV cards"
+ depends on VIDEO_TM6000 && DVB_CORE && EXPERIMENTAL
+ select DVB_ZL10353
+ ---help---
+ This adds support for DVB cards based on the tm5600/tm6000 chip.
diff --git a/drivers/staging/tm6000/Makefile b/drivers/staging/tm6000/Makefile
new file mode 100644
index 000000000000..25aefe74dddc
--- /dev/null
+++ b/drivers/staging/tm6000/Makefile
@@ -0,0 +1,15 @@
+tm6000-objs := tm6000-cards.o \
+ tm6000-core.o \
+ tm6000-i2c.o \
+ tm6000-video.o \
+ tm6000-stds.o
+
+ifeq ($(CONFIG_VIDEO_TM6000_DVB),y)
+tm6000-objs += tm6000-dvb.o \
+ hack.o
+endif
+
+obj-$(CONFIG_VIDEO_TM6000) += tm6000.o
+obj-$(CONFIG_VIDEO_TM6000_ALSA) += tm6000-alsa.o
+
+EXTRA_CFLAGS = -Idrivers/media/video
diff --git a/drivers/staging/tm6000/README b/drivers/staging/tm6000/README
new file mode 100644
index 000000000000..cff09b7b477e
--- /dev/null
+++ b/drivers/staging/tm6000/README
@@ -0,0 +1,11 @@
+Todo:
+ - checkpatch.pl cleanups
+ - sparse cleanups
+ - convert to new i2c approach
+ - better support DVB
+ - fix reading from i2c, if possible
+ - fix loosing frames
+ - fix oops?
+
+Please send patches to linux-media@vger.kernel.org
+
diff --git a/drivers/staging/tm6000/hack.c b/drivers/staging/tm6000/hack.c
new file mode 100644
index 000000000000..f181fce6716b
--- /dev/null
+++ b/drivers/staging/tm6000/hack.c
@@ -0,0 +1,252 @@
+
+
+
+
+
+
+/*
+ hack.h - hackish code that needs to be improved (or removed) at a
+ later point
+
+ Copyright (C) 2007 Michel Ludwig <michel.ludwig@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 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. 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 "hack.h"
+
+#include "tm6000.h"
+
+#include <linux/usb.h>
+
+static inline int tm6000_snd_control_msg(struct tm6000_core *dev, __u8 request, __u16 value, __u16 index, void *data, __u16 size)
+{
+ return tm6000_read_write_usb (dev, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, request, value, index, data, size);
+}
+
+static int pseudo_zl10353_pll(struct tm6000_core *tm6000_dev, struct dvb_frontend_parameters *p)
+{
+ int ret;
+ u8 *data = kzalloc(50*sizeof(u8), GFP_KERNEL);
+
+printk(KERN_ALERT "should set frequency %u\n", p->frequency);
+printk(KERN_ALERT "and bandwith %u\n", p->u.ofdm.bandwidth);
+
+ if(tm6000_dev->dvb->frontend->ops.tuner_ops.set_params) {
+ tm6000_dev->dvb->frontend->ops.tuner_ops.set_params(tm6000_dev->dvb->frontend, p);
+ }
+ else {
+ printk(KERN_ALERT "pseudo zl10353: couldn't set tuner parameters\n");
+ }
+
+ // init ZL10353
+ data[0] = 0x0b;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x501e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x80;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x551e, 0x00, data, 0x1);
+ msleep(100);
+ data[0] = 0x01;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0xea1e, 0x00, data, 0x1);
+ msleep(100);
+ data[0] = 0x00;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0xea1e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x1c;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x561e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x40;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x5e1e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x36;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x641e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x67;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x651e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0xe5;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x661e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x19;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x6c1e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0xe9;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x6d1e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x44;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x511e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x46;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x521e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x15;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x531e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x0f;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x541e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x75;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x5c1e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x01;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x701e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x00;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x701e, 0x00, data, 0x1);
+ msleep(15);
+
+ msleep(50);
+
+ switch(p->u.ofdm.bandwidth) {
+ case BANDWIDTH_8_MHZ:
+ data[0] = 0x00;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x701e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x36;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x641e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x67;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x651e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0xe5;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x661e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x19;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x6c1e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0xe9;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x6d1e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x44;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x511e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x46;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x521e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x15;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x531e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x0f;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x541e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x75;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x5c1e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x01;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x701e, 0x00, data, 0x1);
+ msleep(15);
+ break;
+
+ default:
+ printk(KERN_ALERT "tm6000: bandwidth not supported\n");
+ case BANDWIDTH_7_MHZ:
+ data[0] = 0x00;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x701e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x35;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x641e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x5a;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x651e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0xe9;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x661e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x19;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x6c1e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0xe9;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x6d1e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x44;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x511e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x46;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x521e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x15;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x531e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x0f;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x541e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x86;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x5c1e, 0x00, data, 0x1);
+ msleep(15);
+ data[0] = 0x01;
+ ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x701e, 0x00, data, 0x1);
+ msleep(15);
+ break;
+ }
+
+ kfree(data);
+
+ return 0;
+};
+
+
+
+int pseudo_zl10353_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct tm6000_core *tm6000_dev = fe->dvb->priv;
+ u32 status;
+
+ if(p != NULL) {
+// mutex_lock(&tm6000_dev->mutex);
+ pseudo_zl10353_pll(tm6000_dev, p);
+// mutex_unlock(&tm6000_dev->mutex);
+ }
+
+ if(tm6000_dev->dvb->frontend->ops.read_status) {
+ tm6000_dev->dvb->frontend->ops.read_status(tm6000_dev->dvb->frontend, &status);
+ printk(KERN_ALERT "demodulator status: FE_HAS_CARRIER %i \n", (status & FE_HAS_CARRIER));
+ printk(KERN_ALERT "demodulator status: FE_HAS_VITERBI %i \n", (status & FE_HAS_VITERBI));
+ printk(KERN_ALERT "demodulator status: FE_HAS_LOCK %i \n", (status & FE_HAS_LOCK));
+ printk(KERN_ALERT "demodulator status: FE_HAS_SYNC %i \n", (status & FE_HAS_SYNC));
+ printk(KERN_ALERT "demodulator status: FE_HAS_SIGNAL %i \n", (status & FE_HAS_SIGNAL));
+ }
+ else {
+ printk(KERN_ALERT "pseudo zl10353: couldn't read demodulator status\n");
+ }
+ return 0;
+}
+
+int pseudo_zl10353_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+
+ *status = FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK | FE_HAS_SIGNAL;
+
+ return 0;
+}
+
+struct dvb_frontend* pseudo_zl10353_attach(struct tm6000_core *dev,
+ const struct zl10353_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct tm6000_dvb *dvb = dev->dvb;
+
+ dvb->frontend = dvb_attach(zl10353_attach, config, i2c);
+ if(!dvb->frontend) {
+ printk(KERN_ERR "Error during zl10353_attach!\n");
+ return NULL;
+ }
+
+ /* override some functions with our implementations */
+ dvb->frontend->ops.set_frontend = pseudo_zl10353_set_frontend;
+ dvb->frontend->ops.read_status = pseudo_zl10353_read_status;
+ dvb->frontend->frontend_priv = dev;
+
+ return dvb->frontend;
+}
diff --git a/drivers/staging/tm6000/hack.h b/drivers/staging/tm6000/hack.h
new file mode 100644
index 000000000000..96f1b61df682
--- /dev/null
+++ b/drivers/staging/tm6000/hack.h
@@ -0,0 +1,45 @@
+/*
+ hack.h - hackish code that needs to be improved (or removed) at a
+ later point
+
+ Copyright (C) 2007 Michel Ludwig <michel.ludwig@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 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. 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.
+ */
+
+#ifndef HACK_H
+#define HACK_H
+
+#include <linux/i2c.h>
+
+#include "zl10353.h"
+#include "dvb_frontend.h"
+
+struct tm6000_core;
+
+int pseudo_zl103530_init(struct dvb_frontend *fe);
+
+int pseudo_zl10353_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
+
+int pseudo_zl10353_read_status(struct dvb_frontend *fe, fe_status_t *status);
+
+int pseudo_zl10353_read_signal_strength(struct dvb_frontend* fe, u16* strength);
+
+int pseudo_zl10353_read_snr(struct dvb_frontend *fe, u16 *snr);
+
+struct dvb_frontend* pseudo_zl10353_attach(struct tm6000_core *dev,
+ const struct zl10353_config *config,
+ struct i2c_adapter *i2c);
+
+#endif
diff --git a/drivers/staging/tm6000/tm6000-alsa.c b/drivers/staging/tm6000/tm6000-alsa.c
new file mode 100644
index 000000000000..cf24340e0874
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-alsa.c
@@ -0,0 +1,413 @@
+/*
+ *
+ * Support for audio capture for tm5600/6000
+ * (c) 2007-2008 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Based on cx88-alsa.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/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+
+#include <asm/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+
+#undef dprintk
+
+#define dprintk(level, fmt, arg...) do { \
+ if (debug >= level) \
+ printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \
+ } while (0)
+
+/****************************************************************************
+ Data type declarations - Can be moded to a header file later
+ ****************************************************************************/
+
+struct snd_tm6000_card {
+ struct snd_card *card;
+
+ spinlock_t reg_lock;
+
+ atomic_t count;
+
+ unsigned int period_size;
+ unsigned int num_periods;
+
+ struct tm6000_core *core;
+ struct tm6000_buffer *buf;
+
+ int bufsize;
+
+ struct snd_pcm_substream *substream;
+};
+
+
+/****************************************************************************
+ Module global static vars
+ ****************************************************************************/
+
+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)] = 1};
+
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable tm6000x soundcard. default enabled.");
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s).");
+
+
+/****************************************************************************
+ Module macros
+ ****************************************************************************/
+
+MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000 based TV cards");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Trident,tm5600},"
+ "{{Trident,tm6000}");
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+/****************************************************************************
+ Module specific funtions
+ ****************************************************************************/
+
+/*
+ * BOARD Specific: Sets audio DMA
+ */
+
+static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
+{
+ struct tm6000_core *core = chip->core;
+ int val;
+
+ /* Enables audio */
+ val = tm6000_get_reg(core, REQ_07_SET_GET_AVREG, 0xcc, 0x0);
+ val |= 0x20;
+ tm6000_set_reg(core, REQ_07_SET_GET_AVREG, 0xcc, val);
+
+ tm6000_set_reg(core, REQ_08_SET_GET_AVREG_BIT, 0x01, 0x80);
+
+ return 0;
+}
+
+/*
+ * BOARD Specific: Resets audio DMA
+ */
+static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip)
+{
+ struct tm6000_core *core = chip->core;
+ int val;
+ dprintk(1, "Stopping audio DMA\n");
+
+ /* Enables audio */
+ val = tm6000_get_reg(core, REQ_07_SET_GET_AVREG, 0xcc, 0x0);
+ val &= ~0x20;
+ tm6000_set_reg(core, REQ_07_SET_GET_AVREG, 0xcc, val);
+
+ tm6000_set_reg(core, REQ_08_SET_GET_AVREG_BIT, 0x01, 0);
+
+ return 0;
+}
+
+static int dsp_buffer_free(struct snd_tm6000_card *chip)
+{
+ BUG_ON(!chip->bufsize);
+
+ dprintk(2, "Freeing buffer\n");
+
+ /* FIXME: Frees buffer */
+
+ chip->bufsize = 0;
+
+ return 0;
+}
+
+/****************************************************************************
+ ALSA PCM Interface
+ ****************************************************************************/
+
+/*
+ * Digital hardware definition
+ */
+#define DEFAULT_FIFO_SIZE 4096
+
+static struct snd_pcm_hardware snd_tm6000_digital_hw = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+ .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+ .rate_min = 44100,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .period_bytes_min = DEFAULT_FIFO_SIZE/4,
+ .period_bytes_max = DEFAULT_FIFO_SIZE/4,
+ .periods_min = 1,
+ .periods_max = 1024,
+ .buffer_bytes_max = (1024*1024),
+};
+
+/*
+ * audio pcm capture open callback
+ */
+static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int err;
+
+ err = snd_pcm_hw_constraint_pow2(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (err < 0)
+ goto _error;
+
+ chip->substream = substream;
+
+ runtime->hw = snd_tm6000_digital_hw;
+
+ return 0;
+_error:
+ dprintk(1, "Error opening PCM!\n");
+ return err;
+}
+
+/*
+ * audio close callback
+ */
+static int snd_tm6000_close(struct snd_pcm_substream *substream)
+{
+ return 0;
+}
+
+/*
+ * hw_params callback
+ */
+static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+ if (substream->runtime->dma_area) {
+ dsp_buffer_free(chip);
+ substream->runtime->dma_area = NULL;
+ }
+
+ chip->period_size = params_period_bytes(hw_params);
+ chip->num_periods = params_periods(hw_params);
+ chip->bufsize = chip->period_size * params_periods(hw_params);
+
+ BUG_ON(!chip->bufsize);
+
+ dprintk(1, "Setting buffer\n");
+
+ /* FIXME: Allocate buffer for audio */
+
+
+ return 0;
+}
+
+/*
+ * hw free callback
+ */
+static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
+{
+
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+ if (substream->runtime->dma_area) {
+ dsp_buffer_free(chip);
+ substream->runtime->dma_area = NULL;
+ }
+
+ return 0;
+}
+
+/*
+ * prepare callback
+ */
+static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
+{
+ return 0;
+}
+
+
+/*
+ * trigger callback
+ */
+static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+ int err;
+
+ spin_lock(&chip->reg_lock);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ err = _tm6000_start_audio_dma(chip);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ err = _tm6000_stop_audio_dma(chip);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ spin_unlock(&chip->reg_lock);
+
+ return err;
+}
+
+/*
+ * pointer callback
+ */
+static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ u16 count;
+
+ count = atomic_read(&chip->count);
+
+ return runtime->period_size * (count & (runtime->periods-1));
+}
+
+/*
+ * operators
+ */
+static struct snd_pcm_ops snd_tm6000_pcm_ops = {
+ .open = snd_tm6000_pcm_open,
+ .close = snd_tm6000_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_tm6000_hw_params,
+ .hw_free = snd_tm6000_hw_free,
+ .prepare = snd_tm6000_prepare,
+ .trigger = snd_tm6000_card_trigger,
+ .pointer = snd_tm6000_pointer,
+};
+
+/*
+ * create a PCM device
+ */
+static int __devinit snd_tm6000_pcm(struct snd_tm6000_card *chip,
+ int device, char *name)
+{
+ int err;
+ struct snd_pcm *pcm;
+
+ err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
+ if (err < 0)
+ return err;
+ pcm->private_data = chip;
+ strcpy(pcm->name, name);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
+
+ return 0;
+}
+
+/* FIXME: Control interface - How to control volume/mute? */
+
+/****************************************************************************
+ Basic Flow for Sound Devices
+ ****************************************************************************/
+
+/*
+ * Alsa Constructor - Component probe
+ */
+
+int tm6000_audio_init(struct tm6000_core *dev, int idx)
+{
+ struct snd_card *card;
+ struct snd_tm6000_card *chip;
+ int rc, len;
+ char component[14];
+
+ if (idx >= SNDRV_CARDS)
+ return -ENODEV;
+
+ if (!enable[idx])
+ return -ENOENT;
+
+ rc = snd_card_create(index[idx], id[idx], THIS_MODULE, 0, &card);
+ if (rc < 0) {
+ snd_printk(KERN_ERR "cannot create card instance %d\n", idx);
+ return rc;
+ }
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ chip->core = dev;
+ chip->card = card;
+
+ strcpy(card->driver, "tm6000-alsa");
+ sprintf(component, "USB%04x:%04x",
+ le16_to_cpu(dev->udev->descriptor.idVendor),
+ le16_to_cpu(dev->udev->descriptor.idProduct));
+ snd_component_add(card, component);
+
+ if (dev->udev->descriptor.iManufacturer)
+ len = usb_string(dev->udev,
+ dev->udev->descriptor.iManufacturer,
+ card->longname, sizeof(card->longname));
+ else
+ len = 0;
+
+ if (len > 0)
+ strlcat(card->longname, " ", sizeof(card->longname));
+
+ strlcat(card->longname, card->shortname, sizeof(card->longname));
+
+ len = strlcat(card->longname, " at ", sizeof(card->longname));
+
+ if (len < sizeof(card->longname))
+ usb_make_path(dev->udev, card->longname + len,
+ sizeof(card->longname) - len);
+
+ strlcat(card->longname,
+ dev->udev->speed == USB_SPEED_LOW ? ", low speed" :
+ dev->udev->speed == USB_SPEED_FULL ? ", full speed" :
+ ", high speed",
+ sizeof(card->longname));
+
+ rc = snd_tm6000_pcm(chip, 0, "tm6000 Digital");
+ if (rc < 0)
+ goto error;
+
+ rc = snd_card_register(card);
+ if (rc < 0)
+ goto error;
+
+
+ return 0;
+
+error:
+ snd_card_free(card);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(tm6000_audio_init);
+
diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c
new file mode 100644
index 000000000000..fd9ee77aee52
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-cards.c
@@ -0,0 +1,630 @@
+/*
+ tm6000-cards.c - driver for TM5600/TM6000 USB video capture devices
+
+ Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.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 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. 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/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/usb.h>
+#include <linux/version.h>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include <media/tvaudio.h>
+#include <media/i2c-addr.h>
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+#include "tuner-xc2028.h"
+
+#define TM6000_BOARD_UNKNOWN 0
+#define TM5600_BOARD_GENERIC 1
+#define TM6000_BOARD_GENERIC 2
+#define TM6010_BOARD_GENERIC 3
+#define TM5600_BOARD_10MOONS_UT821 4
+#define TM5600_BOARD_10MOONS_UT330 5
+#define TM6000_BOARD_ADSTECH_DUAL_TV 6
+#define TM6000_BOARD_FREECOM_AND_SIMILAR 7
+#define TM6000_BOARD_ADSTECH_MINI_DUAL_TV 8
+#define TM6010_BOARD_HAUPPAUGE_900H 9
+
+#define TM6000_MAXBOARDS 16
+static unsigned int card[] = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(card, int, NULL, 0444);
+
+static unsigned long tm6000_devused;
+
+
+struct tm6000_board {
+ char *name;
+
+ struct tm6000_capabilities caps;
+
+ enum tm6000_devtype type; /* variant of the chipset */
+ int tuner_type; /* type of the tuner */
+ int tuner_addr; /* tuner address */
+ int demod_addr; /* demodulator address */
+ int gpio_addr_tun_reset; /* GPIO used for tuner reset */
+};
+
+struct tm6000_board tm6000_boards[] = {
+ [TM6000_BOARD_UNKNOWN] = {
+ .name = "Unknown tm6000 video grabber",
+ .caps = {
+ .has_tuner = 1,
+ },
+ .gpio_addr_tun_reset = TM6000_GPIO_1,
+ },
+ [TM5600_BOARD_GENERIC] = {
+ .name = "Generic tm5600 board",
+ .type = TM5600,
+ .tuner_type = TUNER_XC2028,
+ .tuner_addr = 0xc2 >> 1,
+ .caps = {
+ .has_tuner = 1,
+ },
+ .gpio_addr_tun_reset = TM6000_GPIO_1,
+ },
+ [TM6000_BOARD_GENERIC] = {
+ .name = "Generic tm6000 board",
+ .tuner_type = TUNER_XC2028,
+ .tuner_addr = 0xc2 >> 1,
+ .caps = {
+ .has_tuner = 1,
+ .has_dvb = 1,
+ },
+ .gpio_addr_tun_reset = TM6000_GPIO_1,
+ },
+ [TM6010_BOARD_GENERIC] = {
+ .name = "Generic tm6010 board",
+ .type = TM6010,
+ .tuner_type = TUNER_XC2028,
+ .tuner_addr = 0xc2 >> 1,
+ .caps = {
+ .has_tuner = 1,
+ .has_dvb = 1,
+ },
+ .gpio_addr_tun_reset = TM6010_GPIO_4,
+ },
+ [TM5600_BOARD_10MOONS_UT821] = {
+ .name = "10Moons UT 821",
+ .tuner_type = TUNER_XC2028,
+ .type = TM5600,
+ .tuner_addr = 0xc2 >> 1,
+ .caps = {
+ .has_tuner = 1,
+ .has_eeprom = 1,
+ },
+ .gpio_addr_tun_reset = TM6000_GPIO_1,
+ },
+ [TM5600_BOARD_10MOONS_UT330] = {
+ .name = "10Moons UT 330",
+ .tuner_type = TUNER_PHILIPS_FQ1216AME_MK4,
+ .tuner_addr = 0xc8 >> 1,
+ .caps = {
+ .has_tuner = 1,
+ .has_dvb = 0,
+ .has_zl10353 = 0,
+ .has_eeprom = 1,
+ },
+ },
+ [TM6000_BOARD_ADSTECH_DUAL_TV] = {
+ .name = "ADSTECH Dual TV USB",
+ .tuner_type = TUNER_XC2028,
+ .tuner_addr = 0xc8 >> 1,
+ .caps = {
+ .has_tuner = 1,
+ .has_tda9874 = 1,
+ .has_dvb = 1,
+ .has_zl10353 = 1,
+ .has_eeprom = 1,
+ },
+ },
+ [TM6000_BOARD_FREECOM_AND_SIMILAR] = {
+ .name = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual",
+ .tuner_type = TUNER_XC2028, /* has a XC3028 */
+ .tuner_addr = 0xc2 >> 1,
+ .demod_addr = 0x1e >> 1,
+ .caps = {
+ .has_tuner = 1,
+ .has_dvb = 1,
+ .has_zl10353 = 1,
+ .has_eeprom = 0,
+ .has_remote = 1,
+ },
+ .gpio_addr_tun_reset = TM6000_GPIO_4,
+ },
+ [TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = {
+ .name = "ADSTECH Mini Dual TV USB",
+ .tuner_type = TUNER_XC2028, /* has a XC3028 */
+ .tuner_addr = 0xc8 >> 1,
+ .demod_addr = 0x1e >> 1,
+ .caps = {
+ .has_tuner = 1,
+ .has_dvb = 1,
+ .has_zl10353 = 1,
+ .has_eeprom = 0,
+ },
+ .gpio_addr_tun_reset = TM6000_GPIO_4,
+ },
+ [TM6010_BOARD_HAUPPAUGE_900H] = {
+ .name = "Hauppauge HVR-900H",
+ .tuner_type = TUNER_XC2028, /* has a XC3028 */
+ .tuner_addr = 0xc2 >> 1,
+ .demod_addr = 0x1e >> 1,
+ .type = TM6010,
+ .caps = {
+ .has_tuner = 1,
+ .has_dvb = 1,
+ .has_zl10353 = 1,
+ .has_eeprom = 1,
+ },
+ .gpio_addr_tun_reset = TM6000_GPIO_2,
+ },
+};
+
+/* table of devices that work with this driver */
+struct usb_device_id tm6000_id_table [] = {
+ { USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_10MOONS_UT821 },
+ { USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC },
+ { USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV },
+ { USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR },
+ { USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV },
+ { USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
+ { },
+};
+
+/* Tuner callback to provide the proper gpio changes needed for xc2028 */
+
+static int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
+{
+ int rc=0;
+ struct tm6000_core *dev = ptr;
+
+ if (dev->tuner_type!=TUNER_XC2028)
+ return 0;
+
+ switch (command) {
+ case XC2028_RESET_CLK:
+ tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT,
+ 0x02, arg);
+ msleep(10);
+ rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
+ TM6000_GPIO_CLK, 0);
+ if (rc<0)
+ return rc;
+ msleep(10);
+ rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
+ TM6000_GPIO_CLK, 1);
+ break;
+ case XC2028_TUNER_RESET:
+ /* Reset codes during load firmware */
+ switch (arg) {
+ case 0:
+ tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
+ dev->tuner_reset_gpio, 0x00);
+ msleep(130);
+ tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
+ dev->tuner_reset_gpio, 0x01);
+ msleep(130);
+ break;
+ case 1:
+ tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT,
+ 0x02, 0x01);
+ msleep(10);
+ break;
+
+ case 2:
+ rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
+ TM6000_GPIO_CLK, 0);
+ if (rc<0)
+ return rc;
+ msleep(100);
+ rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN,
+ TM6000_GPIO_CLK, 1);
+ msleep(100);
+ break;
+ }
+ }
+ return (rc);
+}
+
+static void tm6000_config_tuner (struct tm6000_core *dev)
+{
+ struct tuner_setup tun_setup;
+
+ /* Load tuner module */
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ "tuner", "tuner",dev->tuner_addr, NULL);
+
+ memset(&tun_setup, 0, sizeof(tun_setup));
+ tun_setup.type = dev->tuner_type;
+ tun_setup.addr = dev->tuner_addr;
+ tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+ tun_setup.tuner_callback = tm6000_tuner_callback;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
+
+ if (dev->tuner_type == TUNER_XC2028) {
+ struct v4l2_priv_tun_config xc2028_cfg;
+ struct xc2028_ctrl ctl;
+
+ memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
+ memset (&ctl,0,sizeof(ctl));
+
+ ctl.mts = 1;
+ ctl.read_not_reliable = 1;
+ ctl.msleep = 10;
+
+ xc2028_cfg.tuner = TUNER_XC2028;
+ xc2028_cfg.priv = &ctl;
+
+ switch(dev->model) {
+ case TM6010_BOARD_HAUPPAUGE_900H:
+ ctl.fname = "xc3028L-v36.fw";
+ break;
+ default:
+ if (dev->dev_type == TM6010)
+ ctl.fname = "xc3028-v27.fw";
+ else
+ ctl.fname = "tm6000-xc3028.fw";
+ }
+
+ printk(KERN_INFO "Setting firmware parameters for xc2028\n");
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
+ &xc2028_cfg);
+ }
+}
+
+static int tm6000_init_dev(struct tm6000_core *dev)
+{
+ struct v4l2_frequency f;
+ int rc = 0;
+
+ mutex_init(&dev->lock);
+
+ mutex_lock(&dev->lock);
+
+ /* Initializa board-specific data */
+ dev->dev_type = tm6000_boards[dev->model].type;
+ dev->tuner_type = tm6000_boards[dev->model].tuner_type;
+ dev->tuner_addr = tm6000_boards[dev->model].tuner_addr;
+ dev->tuner_reset_gpio = tm6000_boards[dev->model].gpio_addr_tun_reset;
+
+ dev->demod_addr = tm6000_boards[dev->model].demod_addr;
+
+ dev->caps = tm6000_boards[dev->model].caps;
+
+ /* initialize hardware */
+ rc=tm6000_init (dev);
+ if (rc<0)
+ goto err;
+
+ rc = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
+ if (rc < 0)
+ goto err;
+
+ /* register i2c bus */
+ rc=tm6000_i2c_register(dev);
+ if (rc<0)
+ goto err;
+
+ /* register and initialize V4L2 */
+ rc=tm6000_v4l2_register(dev);
+ if (rc<0)
+ goto err;
+
+ /* Default values for STD and resolutions */
+ dev->width = 720;
+ dev->height = 480;
+ dev->norm = V4L2_STD_PAL_M;
+
+ /* Configure tuner */
+ tm6000_config_tuner (dev);
+
+ /* Set video standard */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
+
+ /* Set tuner frequency - also loads firmware on xc2028/xc3028 */
+ f.tuner = 0;
+ f.type = V4L2_TUNER_ANALOG_TV;
+ f.frequency = 3092; /* 193.25 MHz */
+ dev->freq = f.frequency;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+
+ if (dev->caps.has_tda9874)
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ "tvaudio", "tvaudio", I2C_ADDR_TDA9874, NULL);
+
+ if(dev->caps.has_dvb) {
+ dev->dvb = kzalloc(sizeof(*(dev->dvb)), GFP_KERNEL);
+ if(!dev->dvb) {
+ rc = -ENOMEM;
+ goto err2;
+ }
+#ifdef CONFIG_VIDEO_TM6000_DVB
+ rc = tm6000_dvb_register(dev);
+ if(rc < 0) {
+ kfree(dev->dvb);
+ dev->dvb = NULL;
+ goto err2;
+ }
+#endif
+ }
+
+err2:
+ v4l2_device_unregister(&dev->v4l2_dev);
+
+err:
+ mutex_unlock(&dev->lock);
+ return rc;
+}
+
+/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+
+static void get_max_endpoint ( struct usb_device *usbdev,
+ char *msgtype,
+ struct usb_host_endpoint *curr_e,
+ unsigned int *maxsize,
+ struct usb_host_endpoint **ep )
+{
+ u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize);
+ unsigned int size = tmp & 0x7ff;
+
+ if (usbdev->speed == USB_SPEED_HIGH)
+ size = size * hb_mult (tmp);
+
+ if (size>*maxsize) {
+ *ep = curr_e;
+ *maxsize = size;
+ printk("tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n",
+ msgtype, curr_e->desc.bEndpointAddress,
+ size);
+ }
+}
+
+/*
+ * tm6000_usb_probe()
+ * checks for supported devices
+ */
+static int tm6000_usb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *usbdev;
+ struct tm6000_core *dev = NULL;
+ int i,rc=0;
+ int nr=0;
+ char *speed;
+
+
+ usbdev=usb_get_dev(interface_to_usbdev(interface));
+
+ /* Selects the proper interface */
+ rc=usb_set_interface(usbdev,0,1);
+ if (rc<0)
+ goto err;
+
+ /* Check to see next free device and mark as used */
+ nr=find_first_zero_bit(&tm6000_devused,TM6000_MAXBOARDS);
+ if (nr >= TM6000_MAXBOARDS) {
+ printk ("tm6000: Supports only %i em28xx boards.\n",TM6000_MAXBOARDS);
+ usb_put_dev(usbdev);
+ return -ENOMEM;
+ }
+
+ /* Create and initialize dev struct */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ printk ("tm6000" ": out of memory!\n");
+ usb_put_dev(usbdev);
+ return -ENOMEM;
+ }
+ spin_lock_init(&dev->slock);
+
+ /* Increment usage count */
+ tm6000_devused|=1<<nr;
+ snprintf(dev->name, 29, "tm6000 #%d", nr);
+
+ dev->model=id->driver_info;
+ if ((card[nr]>=0) && (card[nr]<ARRAY_SIZE(tm6000_boards))) {
+ dev->model=card[nr];
+ }
+
+ INIT_LIST_HEAD(&dev->tm6000_corelist);
+ dev->udev= usbdev;
+ dev->devno=nr;
+
+ switch (usbdev->speed) {
+ case USB_SPEED_LOW:
+ speed = "1.5";
+ break;
+ case USB_SPEED_UNKNOWN:
+ case USB_SPEED_FULL:
+ speed = "12";
+ break;
+ case USB_SPEED_HIGH:
+ speed = "480";
+ break;
+ default:
+ speed = "unknown";
+ }
+
+
+
+ /* Get endpoints */
+ for (i = 0; i < interface->num_altsetting; i++) {
+ int ep;
+
+ for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
+ struct usb_host_endpoint *e;
+ int dir_out;
+
+ e = &interface->altsetting[i].endpoint[ep];
+
+ dir_out = ((e->desc.bEndpointAddress &
+ USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
+
+ printk("tm6000: alt %d, interface %i, class %i\n",
+ i,
+ interface->altsetting[i].desc.bInterfaceNumber,
+ interface->altsetting[i].desc.bInterfaceClass);
+
+ switch (e->desc.bmAttributes) {
+ case USB_ENDPOINT_XFER_BULK:
+ if (!dir_out) {
+ get_max_endpoint (usbdev, "Bulk IN", e,
+ &dev->max_bulk_in,
+ &dev->bulk_in);
+ } else {
+ get_max_endpoint (usbdev, "Bulk OUT", e,
+ &dev->max_bulk_out,
+ &dev->bulk_out);
+ }
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ if (!dir_out) {
+ get_max_endpoint (usbdev, "ISOC IN", e,
+ &dev->max_isoc_in,
+ &dev->isoc_in);
+ } else {
+ get_max_endpoint (usbdev, "ISOC OUT", e,
+ &dev->max_isoc_out,
+ &dev->isoc_out);
+ }
+ break;
+ }
+ }
+ }
+
+
+ printk("tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n",
+ speed,
+ le16_to_cpu(dev->udev->descriptor.idVendor),
+ le16_to_cpu(dev->udev->descriptor.idProduct),
+ interface->altsetting->desc.bInterfaceNumber);
+
+/* check if the the device has the iso in endpoint at the correct place */
+ if (!dev->isoc_in) {
+ printk("tm6000: probing error: no IN ISOC endpoint!\n");
+ rc= -ENODEV;
+
+ goto err;
+ }
+
+ /* save our data pointer in this interface device */
+ usb_set_intfdata(interface, dev);
+
+ printk("tm6000: Found %s\n", tm6000_boards[dev->model].name);
+
+ rc=tm6000_init_dev(dev);
+
+ if (rc<0)
+ goto err;
+
+ return 0;
+
+err:
+ printk("tm6000: Error %d while registering\n", rc);
+
+ tm6000_devused&=~(1<<nr);
+ usb_put_dev(usbdev);
+
+ kfree(dev);
+ return rc;
+}
+
+/*
+ * tm6000_usb_disconnect()
+ * called when the device gets diconencted
+ * video device will be unregistered on v4l2_close in case it is still open
+ */
+static void tm6000_usb_disconnect(struct usb_interface *interface)
+{
+ struct tm6000_core *dev = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+ if (!dev)
+ return;
+
+ printk("tm6000: disconnecting %s\n", dev->name);
+
+ mutex_lock(&dev->lock);
+
+#ifdef CONFIG_VIDEO_TM6000_DVB
+ if(dev->dvb) {
+ tm6000_dvb_unregister(dev);
+ kfree(dev->dvb);
+ }
+#endif
+
+ tm6000_v4l2_unregister(dev);
+
+ tm6000_i2c_unregister(dev);
+
+ v4l2_device_unregister(&dev->v4l2_dev);
+
+// wake_up_interruptible_all(&dev->open);
+
+ dev->state |= DEV_DISCONNECTED;
+
+ usb_put_dev(dev->udev);
+
+ mutex_unlock(&dev->lock);
+ kfree(dev);
+}
+
+static struct usb_driver tm6000_usb_driver = {
+ .name = "tm6000",
+ .probe = tm6000_usb_probe,
+ .disconnect = tm6000_usb_disconnect,
+ .id_table = tm6000_id_table,
+};
+
+static int __init tm6000_module_init(void)
+{
+ int result;
+
+ printk(KERN_INFO "tm6000" " v4l2 driver version %d.%d.%d loaded\n",
+ (TM6000_VERSION >> 16) & 0xff,
+ (TM6000_VERSION >> 8) & 0xff, TM6000_VERSION & 0xff);
+
+ /* register this driver with the USB subsystem */
+ result = usb_register(&tm6000_usb_driver);
+ if (result)
+ printk("tm6000"
+ " usb_register failed. Error number %d.\n", result);
+
+ return result;
+}
+
+static void __exit tm6000_module_exit(void)
+{
+ /* deregister at USB subsystem */
+ usb_deregister(&tm6000_usb_driver);
+}
+
+module_init(tm6000_module_init);
+module_exit(tm6000_module_exit);
+
+MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000 USB2 adapter");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c
new file mode 100644
index 000000000000..d41af1d6c66a
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-core.c
@@ -0,0 +1,511 @@
+/*
+ tm6000-core.c - driver for TM5600/TM6000 USB video capture devices
+
+ Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+
+ Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+ - DVB-T 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 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. 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/usb.h>
+#include <linux/i2c.h>
+#include <linux/video_decoder.h>
+#include "tm6000.h"
+#include "tm6000-regs.h"
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+
+#define USB_TIMEOUT 5*HZ /* ms */
+
+int tm6000_read_write_usb (struct tm6000_core *dev, u8 req_type, u8 req,
+ u16 value, u16 index, u8 *buf, u16 len)
+{
+ int ret, i;
+ unsigned int pipe;
+ static int ini=0, last=0, n=0;
+ u8 *data=NULL;
+
+ if (len)
+ data = kzalloc(len, GFP_KERNEL);
+
+
+ if (req_type & USB_DIR_IN)
+ pipe=usb_rcvctrlpipe(dev->udev, 0);
+ else {
+ pipe=usb_sndctrlpipe(dev->udev, 0);
+ memcpy(data, buf, len);
+ }
+
+ if (tm6000_debug & V4L2_DEBUG_I2C) {
+ if (!ini)
+ last=ini=jiffies;
+
+ printk("%06i (dev %p, pipe %08x): ", n, dev->udev, pipe);
+
+ printk( "%s: %06u ms %06u ms %02x %02x %02x %02x %02x %02x %02x %02x ",
+ (req_type & USB_DIR_IN)?" IN":"OUT",
+ jiffies_to_msecs(jiffies-last),
+ jiffies_to_msecs(jiffies-ini),
+ req_type, req,value&0xff,value>>8, index&0xff, index>>8,
+ len&0xff, len>>8);
+ last=jiffies;
+ n++;
+
+ if ( !(req_type & USB_DIR_IN) ) {
+ printk(">>> ");
+ for (i=0;i<len;i++) {
+ printk(" %02x",buf[i]);
+ }
+ printk("\n");
+ }
+ }
+
+ ret = usb_control_msg(dev->udev, pipe, req, req_type, value, index, data,
+ len, USB_TIMEOUT);
+
+ if (req_type & USB_DIR_IN)
+ memcpy(buf, data, len);
+
+ if (tm6000_debug & V4L2_DEBUG_I2C) {
+ if (ret<0) {
+ if (req_type & USB_DIR_IN)
+ printk("<<< (len=%d)\n",len);
+
+ printk("%s: Error #%d\n", __FUNCTION__, ret);
+ } else if (req_type & USB_DIR_IN) {
+ printk("<<< ");
+ for (i=0;i<len;i++) {
+ printk(" %02x",buf[i]);
+ }
+ printk("\n");
+ }
+ }
+
+ kfree(data);
+
+ msleep(5);
+
+ return ret;
+}
+
+int tm6000_set_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index)
+{
+ return
+ tm6000_read_write_usb (dev, USB_DIR_OUT | USB_TYPE_VENDOR,
+ req, value, index, NULL, 0);
+}
+
+int tm6000_get_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index)
+{
+ int rc;
+ u8 buf[1];
+
+ rc=tm6000_read_write_usb (dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+ value, index, buf, 1);
+
+ if (rc<0)
+ return rc;
+
+ return *buf;
+}
+
+int tm6000_get_reg16 (struct tm6000_core *dev, u8 req, u16 value, u16 index)
+{
+ int rc;
+ u8 buf[2];
+
+ rc=tm6000_read_write_usb (dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+ value, index, buf, 2);
+
+ if (rc<0)
+ return rc;
+
+ return buf[1]|buf[0]<<8;
+}
+
+void tm6000_set_fourcc_format(struct tm6000_core *dev)
+{
+ if (dev->dev_type == TM6010) {
+ if (dev->fourcc == V4L2_PIX_FMT_UYVY)
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xc1, 0xfc);
+ else
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xc1, 0xfd);
+ } else {
+ if (dev->fourcc == V4L2_PIX_FMT_UYVY)
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xc1, 0xd0);
+ else
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xc1, 0x90);
+ }
+}
+
+int tm6000_init_analog_mode (struct tm6000_core *dev)
+{
+ if (dev->dev_type == TM6010) {
+ int val;
+
+ /* Enable video */
+ val = tm6000_get_reg(dev, REQ_07_SET_GET_AVREG, 0xcc, 0);
+ val |= 0x60;
+ tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xcc, val);
+ tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xfe, 0xcf);
+
+ } else {
+ /* Enables soft reset */
+ tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0x3f, 0x01);
+
+ if (dev->scaler) {
+ tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xc0, 0x20);
+ } else {
+ /* Enable Hfilter and disable TS Drop err */
+ tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xc0, 0x80);
+ }
+
+ tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xc3, 0x88);
+ tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xda, 0x23);
+ tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xd1, 0xc0);
+ tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xd2, 0xd8);
+ tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xd6, 0x06);
+ tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xdf, 0x1f);
+
+ /* AP Software reset */
+ tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xff, 0x08);
+ tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xff, 0x00);
+
+ tm6000_set_fourcc_format(dev);
+
+ /* Disables soft reset */
+ tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0x3f, 0x00);
+
+ /* E3: Select input 0 - TV tuner */
+ tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xe3, 0x00);
+ tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, 0x60);
+
+ /* This controls input */
+ tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_2, 0x0);
+ tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_3, 0x01);
+ }
+ msleep(20);
+
+ /* Tuner firmware can now be loaded */
+
+ /*FIXME: Hack!!! */
+ struct v4l2_frequency f;
+ mutex_lock(&dev->lock);
+ f.frequency=dev->freq;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+ mutex_unlock(&dev->lock);
+
+ msleep(100);
+ tm6000_set_standard (dev, &dev->norm);
+ tm6000_set_audio_bitrate (dev,48000);
+
+ return 0;
+}
+
+int tm6000_init_digital_mode (struct tm6000_core *dev)
+{
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00ff, 0x08);
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00ff, 0x00);
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x003f, 0x01);
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00df, 0x08);
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e2, 0x0c);
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e8, 0xff);
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0xd8);
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c0, 0x40);
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c1, 0xd0);
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c3, 0x09);
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00da, 0x37);
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d1, 0xd8);
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d2, 0xc0);
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d6, 0x60);
+
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e2, 0x0c);
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e8, 0xff);
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0x08);
+ msleep(50);
+
+ tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
+ msleep(50);
+ tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
+ msleep(50);
+ tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
+ msleep(100);
+
+ return 0;
+}
+
+struct reg_init {
+ u8 req;
+ u8 reg;
+ u8 val;
+};
+
+/* The meaning of those initializations are unknown */
+struct reg_init tm6000_init_tab[] = {
+ /* REG VALUE */
+ { REQ_07_SET_GET_AVREG, 0xdf, 0x1f },
+ { REQ_07_SET_GET_AVREG, 0xff, 0x08 },
+ { REQ_07_SET_GET_AVREG, 0xff, 0x00 },
+ { REQ_07_SET_GET_AVREG, 0xd5, 0x4f },
+ { REQ_07_SET_GET_AVREG, 0xda, 0x23 },
+ { REQ_07_SET_GET_AVREG, 0xdb, 0x08 },
+ { REQ_07_SET_GET_AVREG, 0xe2, 0x00 },
+ { REQ_07_SET_GET_AVREG, 0xe3, 0x10 },
+ { REQ_07_SET_GET_AVREG, 0xe5, 0x00 },
+ { REQ_07_SET_GET_AVREG, 0xe8, 0x00 },
+ { REQ_07_SET_GET_AVREG, 0xeb, 0x64 }, /* 48000 bits/sample, external input */
+ { REQ_07_SET_GET_AVREG, 0xee, 0xc2 },
+ { REQ_07_SET_GET_AVREG, 0x3f, 0x01 }, /* Start of soft reset */
+ { REQ_07_SET_GET_AVREG, 0x00, 0x00 },
+ { REQ_07_SET_GET_AVREG, 0x01, 0x07 },
+ { REQ_07_SET_GET_AVREG, 0x02, 0x5f },
+ { REQ_07_SET_GET_AVREG, 0x03, 0x00 },
+ { REQ_07_SET_GET_AVREG, 0x05, 0x64 },
+ { REQ_07_SET_GET_AVREG, 0x07, 0x01 },
+ { REQ_07_SET_GET_AVREG, 0x08, 0x82 },
+ { REQ_07_SET_GET_AVREG, 0x09, 0x36 },
+ { REQ_07_SET_GET_AVREG, 0x0a, 0x50 },
+ { REQ_07_SET_GET_AVREG, 0x0c, 0x6a },
+ { REQ_07_SET_GET_AVREG, 0x11, 0xc9 },
+ { REQ_07_SET_GET_AVREG, 0x12, 0x07 },
+ { REQ_07_SET_GET_AVREG, 0x13, 0x3b },
+ { REQ_07_SET_GET_AVREG, 0x14, 0x47 },
+ { REQ_07_SET_GET_AVREG, 0x15, 0x6f },
+ { REQ_07_SET_GET_AVREG, 0x17, 0xcd },
+ { REQ_07_SET_GET_AVREG, 0x18, 0x1e },
+ { REQ_07_SET_GET_AVREG, 0x19, 0x8b },
+ { REQ_07_SET_GET_AVREG, 0x1a, 0xa2 },
+ { REQ_07_SET_GET_AVREG, 0x1b, 0xe9 },
+ { REQ_07_SET_GET_AVREG, 0x1c, 0x1c },
+ { REQ_07_SET_GET_AVREG, 0x1d, 0xcc },
+ { REQ_07_SET_GET_AVREG, 0x1e, 0xcc },
+ { REQ_07_SET_GET_AVREG, 0x1f, 0xcd },
+ { REQ_07_SET_GET_AVREG, 0x20, 0x3c },
+ { REQ_07_SET_GET_AVREG, 0x21, 0x3c },
+ { REQ_07_SET_GET_AVREG, 0x2d, 0x48 },
+ { REQ_07_SET_GET_AVREG, 0x2e, 0x88 },
+ { REQ_07_SET_GET_AVREG, 0x30, 0x22 },
+ { REQ_07_SET_GET_AVREG, 0x31, 0x61 },
+ { REQ_07_SET_GET_AVREG, 0x32, 0x74 },
+ { REQ_07_SET_GET_AVREG, 0x33, 0x1c },
+ { REQ_07_SET_GET_AVREG, 0x34, 0x74 },
+ { REQ_07_SET_GET_AVREG, 0x35, 0x1c },
+ { REQ_07_SET_GET_AVREG, 0x36, 0x7a },
+ { REQ_07_SET_GET_AVREG, 0x37, 0x26 },
+ { REQ_07_SET_GET_AVREG, 0x38, 0x40 },
+ { REQ_07_SET_GET_AVREG, 0x39, 0x0a },
+ { REQ_07_SET_GET_AVREG, 0x42, 0x55 },
+ { REQ_07_SET_GET_AVREG, 0x51, 0x11 },
+ { REQ_07_SET_GET_AVREG, 0x55, 0x01 },
+ { REQ_07_SET_GET_AVREG, 0x57, 0x02 },
+ { REQ_07_SET_GET_AVREG, 0x58, 0x35 },
+ { REQ_07_SET_GET_AVREG, 0x59, 0xa0 },
+ { REQ_07_SET_GET_AVREG, 0x80, 0x15 },
+ { REQ_07_SET_GET_AVREG, 0x82, 0x42 },
+ { REQ_07_SET_GET_AVREG, 0xc1, 0xd0 },
+ { REQ_07_SET_GET_AVREG, 0xc3, 0x88 },
+ { REQ_07_SET_GET_AVREG, 0x3f, 0x00 }, /* End of the soft reset */
+ { REQ_05_SET_GET_USBREG, 0x18, 0x00 },
+};
+
+struct reg_init tm6010_init_tab[] = {
+ { REQ_07_SET_GET_AVREG, 0xc0, 0x00 },
+ { REQ_07_SET_GET_AVREG, 0xc4, 0xa0 },
+ { REQ_07_SET_GET_AVREG, 0xc6, 0x40 },
+ { REQ_07_SET_GET_AVREG, 0xca, 0x31 },
+ { REQ_07_SET_GET_AVREG, 0xcc, 0xe1 },
+ { REQ_07_SET_GET_AVREG, 0xe0, 0x03 },
+ { REQ_07_SET_GET_AVREG, 0xfe, 0x7f },
+
+ { REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf0 },
+ { REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xf4 },
+ { REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf8 },
+ { REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x00 },
+ { REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf2 },
+ { REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xf0 },
+ { REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2 },
+ { REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x60 },
+ { REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfc },
+
+ { REQ_07_SET_GET_AVREG, 0x3f, 0x01 },
+ { REQ_07_SET_GET_AVREG, 0x00, 0x00 },
+ { REQ_07_SET_GET_AVREG, 0x01, 0x07 },
+ { REQ_07_SET_GET_AVREG, 0x02, 0x5f },
+ { REQ_07_SET_GET_AVREG, 0x03, 0x00 },
+ { REQ_07_SET_GET_AVREG, 0x05, 0x64 },
+ { REQ_07_SET_GET_AVREG, 0x07, 0x01 },
+ { REQ_07_SET_GET_AVREG, 0x08, 0x82 },
+ { REQ_07_SET_GET_AVREG, 0x09, 0x36 },
+ { REQ_07_SET_GET_AVREG, 0x0a, 0x50 },
+ { REQ_07_SET_GET_AVREG, 0x0c, 0x6a },
+ { REQ_07_SET_GET_AVREG, 0x11, 0xc9 },
+ { REQ_07_SET_GET_AVREG, 0x12, 0x07 },
+ { REQ_07_SET_GET_AVREG, 0x13, 0x3b },
+ { REQ_07_SET_GET_AVREG, 0x14, 0x47 },
+ { REQ_07_SET_GET_AVREG, 0x15, 0x6f },
+ { REQ_07_SET_GET_AVREG, 0x17, 0xcd },
+ { REQ_07_SET_GET_AVREG, 0x18, 0x1e },
+ { REQ_07_SET_GET_AVREG, 0x19, 0x8b },
+ { REQ_07_SET_GET_AVREG, 0x1a, 0xa2 },
+ { REQ_07_SET_GET_AVREG, 0x1b, 0xe9 },
+ { REQ_07_SET_GET_AVREG, 0x1c, 0x1c },
+ { REQ_07_SET_GET_AVREG, 0x1d, 0xcc },
+ { REQ_07_SET_GET_AVREG, 0x1e, 0xcc },
+ { REQ_07_SET_GET_AVREG, 0x1f, 0xcd },
+ { REQ_07_SET_GET_AVREG, 0x20, 0x3c },
+ { REQ_07_SET_GET_AVREG, 0x21, 0x3c },
+ { REQ_07_SET_GET_AVREG, 0x2d, 0x48 },
+ { REQ_07_SET_GET_AVREG, 0x2e, 0x88 },
+ { REQ_07_SET_GET_AVREG, 0x30, 0x22 },
+ { REQ_07_SET_GET_AVREG, 0x31, 0x61 },
+ { REQ_07_SET_GET_AVREG, 0x32, 0x74 },
+ { REQ_07_SET_GET_AVREG, 0x33, 0x1c },
+ { REQ_07_SET_GET_AVREG, 0x34, 0x74 },
+ { REQ_07_SET_GET_AVREG, 0x35, 0x1c },
+ { REQ_07_SET_GET_AVREG, 0x36, 0x7a },
+ { REQ_07_SET_GET_AVREG, 0x37, 0x26 },
+ { REQ_07_SET_GET_AVREG, 0x38, 0x40 },
+ { REQ_07_SET_GET_AVREG, 0x39, 0x0a },
+ { REQ_07_SET_GET_AVREG, 0x42, 0x55 },
+ { REQ_07_SET_GET_AVREG, 0x51, 0x11 },
+ { REQ_07_SET_GET_AVREG, 0x55, 0x01 },
+ { REQ_07_SET_GET_AVREG, 0x57, 0x02 },
+ { REQ_07_SET_GET_AVREG, 0x58, 0x35 },
+ { REQ_07_SET_GET_AVREG, 0x59, 0xa0 },
+ { REQ_07_SET_GET_AVREG, 0x80, 0x15 },
+ { REQ_07_SET_GET_AVREG, 0x82, 0x42 },
+ { REQ_07_SET_GET_AVREG, 0xc1, 0xd0 },
+ { REQ_07_SET_GET_AVREG, 0xc3, 0x88 },
+ { REQ_07_SET_GET_AVREG, 0x3f, 0x00 },
+
+ { REQ_05_SET_GET_USBREG, 0x18, 0x00 },
+
+ /* set remote wakeup key:any key wakeup */
+ { REQ_07_SET_GET_AVREG, 0xe5, 0xfe },
+ { REQ_07_SET_GET_AVREG, 0xda, 0xff },
+};
+
+int tm6000_init (struct tm6000_core *dev)
+{
+ int board, rc=0, i, size;
+ struct reg_init *tab;
+
+ if (dev->dev_type == TM6010) {
+ tab = tm6010_init_tab;
+ size = ARRAY_SIZE(tm6010_init_tab);
+ } else {
+ tab = tm6000_init_tab;
+ size = ARRAY_SIZE(tm6000_init_tab);
+ }
+
+ /* Load board's initialization table */
+ for (i=0; i< size; i++) {
+ rc= tm6000_set_reg (dev, tab[i].req, tab[i].reg, tab[i].val);
+ if (rc<0) {
+ printk (KERN_ERR "Error %i while setting req %d, "
+ "reg %d to value %d\n", rc,
+ tab[i].req,tab[i].reg, tab[i].val);
+ return rc;
+ }
+ }
+
+ msleep(5); /* Just to be conservative */
+
+ /* Check board version - maybe 10Moons specific */
+ board=tm6000_get_reg16 (dev, 0x40, 0, 0);
+ if (board >=0) {
+ printk (KERN_INFO "Board version = 0x%04x\n",board);
+ } else {
+ printk (KERN_ERR "Error %i while retrieving board version\n",board);
+ }
+
+ if (dev->dev_type == TM6010) {
+ /* Turn xceive 3028 on */
+ tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6010_GPIO_3, 0x01);
+ msleep(11);
+ }
+
+ /* Reset GPIO1 and GPIO4. */
+ for (i=0; i< 2; i++) {
+ rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+ dev->tuner_reset_gpio, 0x00);
+ if (rc<0) {
+ printk (KERN_ERR "Error %i doing GPIO1 reset\n",rc);
+ return rc;
+ }
+
+ msleep(10); /* Just to be conservative */
+ rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+ dev->tuner_reset_gpio, 0x01);
+ if (rc<0) {
+ printk (KERN_ERR "Error %i doing GPIO1 reset\n",rc);
+ return rc;
+ }
+
+ msleep(10);
+ rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_4, 0);
+ if (rc<0) {
+ printk (KERN_ERR "Error %i doing GPIO4 reset\n",rc);
+ return rc;
+ }
+
+ msleep(10);
+ rc=tm6000_set_reg (dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_4, 1);
+ if (rc<0) {
+ printk (KERN_ERR "Error %i doing GPIO4 reset\n",rc);
+ return rc;
+ }
+
+ if (!i) {
+ rc=tm6000_get_reg16(dev, 0x40,0,0);
+ if (rc>=0) {
+ printk ("board=%d\n", rc);
+ }
+ }
+ }
+
+ msleep(50);
+
+ return 0;
+}
+
+int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate)
+{
+ int val;
+
+ val=tm6000_get_reg (dev, REQ_07_SET_GET_AVREG, 0xeb, 0x0);
+printk("Original value=%d\n",val);
+ if (val<0)
+ return val;
+
+ val &= 0x0f; /* Preserve the audio input control bits */
+ switch (bitrate) {
+ case 44100:
+ val|=0xd0;
+ dev->audio_bitrate=bitrate;
+ break;
+ case 48000:
+ val|=0x60;
+ dev->audio_bitrate=bitrate;
+ break;
+ }
+ val=tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0xeb, val);
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate);
diff --git a/drivers/staging/tm6000/tm6000-dvb.c b/drivers/staging/tm6000/tm6000-dvb.c
new file mode 100644
index 000000000000..e900d6ddea30
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-dvb.c
@@ -0,0 +1,322 @@
+/*
+ tm6000-dvb.c - dvb-t support for TM5600/TM6000 USB video capture devices
+
+ Copyright (C) 2007 Michel Ludwig <michel.ludwig@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 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. 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/usb.h>
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+
+#include "hack.h"
+
+#include "zl10353.h"
+
+#include <media/tuner.h>
+
+#include "tuner-xc2028.h"
+
+static void tm6000_urb_received(struct urb *urb)
+{
+ int ret;
+ struct tm6000_core* dev = urb->context;
+
+ if(urb->status != 0){
+ printk(KERN_ERR "tm6000: status != 0\n");
+ }
+ else if(urb->actual_length>0){
+ dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
+ urb->actual_length);
+ }
+
+ if(dev->dvb->streams > 0) {
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if(ret < 0) {
+ printk(KERN_ERR "tm6000: error %s\n", __FUNCTION__);
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+ }
+ }
+}
+
+int tm6000_start_stream(struct tm6000_core *dev)
+{
+ int ret;
+ unsigned int pipe, maxPaketSize;
+ struct tm6000_dvb *dvb = dev->dvb;
+
+ printk(KERN_INFO "tm6000: got start stream request %s\n",__FUNCTION__);
+
+ tm6000_init_digital_mode(dev);
+
+/*
+ ret = tm6000_set_led_status(tm6000_dev, 0x1);
+ if(ret < 0) {
+ return -1;
+ }
+*/
+
+ dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if(dvb->bulk_urb == NULL) {
+ printk(KERN_ERR "tm6000: couldn't allocate urb\n");
+ return -ENOMEM;
+ }
+
+ maxPaketSize = dev->bulk_in->desc.wMaxPacketSize;
+
+ dvb->bulk_urb->transfer_buffer = kzalloc(maxPaketSize, GFP_KERNEL);
+ if(dvb->bulk_urb->transfer_buffer == NULL) {
+ usb_free_urb(dvb->bulk_urb);
+ printk(KERN_ERR "tm6000: couldn't allocate transfer buffer!\n");
+ return -ENOMEM;
+ }
+
+ pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in->desc.bEndpointAddress
+ & USB_ENDPOINT_NUMBER_MASK);
+
+ usb_fill_bulk_urb(dvb->bulk_urb, dev->udev, pipe,
+ dvb->bulk_urb->transfer_buffer,
+ maxPaketSize,
+ tm6000_urb_received, dev);
+
+ ret = usb_set_interface(dev->udev, 0, 1);
+ if(ret < 0) {
+ printk(KERN_ERR "tm6000: error %i in %s during set interface\n", ret, __FUNCTION__);
+ return ret;
+ }
+
+ ret = usb_clear_halt(dev->udev, pipe);
+ if(ret < 0) {
+ printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n",ret,__FUNCTION__);
+ return ret;
+ }
+ else {
+ printk(KERN_ERR "tm6000: pipe resetted\n");
+ }
+
+// mutex_lock(&tm6000_driver.open_close_mutex);
+ ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL);
+
+
+// mutex_unlock(&tm6000_driver.open_close_mutex);
+ if (ret) {
+ printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",ret);
+
+ kfree(dvb->bulk_urb->transfer_buffer);
+ usb_free_urb(dvb->bulk_urb);
+ return ret;
+ }
+
+ return 0;
+}
+
+void tm6000_stop_stream(struct tm6000_core *dev)
+{
+ int ret;
+ struct tm6000_dvb *dvb = dev->dvb;
+
+// tm6000_set_led_status(tm6000_dev, 0x0);
+
+ ret = usb_set_interface(dev->udev, 0, 0);
+ if(ret < 0) {
+ printk(KERN_ERR "tm6000: error %i in %s during set interface\n",ret,__FUNCTION__);
+ }
+
+ if(dvb->bulk_urb) {
+ usb_kill_urb(dvb->bulk_urb);
+ kfree(dvb->bulk_urb->transfer_buffer);
+ usb_free_urb(dvb->bulk_urb);
+ dvb->bulk_urb = NULL;
+ }
+}
+
+int tm6000_start_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct tm6000_core *dev = demux->priv;
+ struct tm6000_dvb *dvb = dev->dvb;
+ printk(KERN_INFO "tm6000: got start feed request %s\n",__FUNCTION__);
+
+ mutex_lock(&dvb->mutex);
+ if(dvb->streams == 0) {
+ dvb->streams = 1;
+// mutex_init(&tm6000_dev->streaming_mutex);
+ tm6000_start_stream(dev);
+ }
+ else {
+ ++(dvb->streams);
+ }
+ mutex_unlock(&dvb->mutex);
+
+ return 0;
+}
+
+int tm6000_stop_feed(struct dvb_demux_feed *feed) {
+ struct dvb_demux *demux = feed->demux;
+ struct tm6000_core *dev = demux->priv;
+ struct tm6000_dvb *dvb = dev->dvb;
+
+ printk(KERN_INFO "tm6000: got stop feed request %s\n",__FUNCTION__);
+
+ mutex_lock(&dvb->mutex);
+ --dvb->streams;
+
+ if(0 == dvb->streams) {
+ tm6000_stop_stream(dev);
+// mutex_destroy(&tm6000_dev->streaming_mutex);
+ }
+ mutex_unlock(&dvb->mutex);
+// mutex_destroy(&tm6000_dev->streaming_mutex);
+
+ return 0;
+}
+
+int tm6000_dvb_attach_frontend(struct tm6000_core *dev)
+{
+ struct tm6000_dvb *dvb = dev->dvb;
+
+ if(dev->caps.has_zl10353) {
+ struct zl10353_config config =
+ {.demod_address = dev->demod_addr >> 1,
+ .no_tuner = 1,
+// .input_frequency = 0x19e9,
+// .r56_agc_targets = 0x1c,
+ };
+
+ dvb->frontend = pseudo_zl10353_attach(dev, &config,
+ &dev->i2c_adap);
+ }
+ else {
+ printk(KERN_ERR "tm6000: no frontend defined for the device!\n");
+ return -1;
+ }
+
+ return (!dvb->frontend) ? -1 : 0;
+}
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+int tm6000_dvb_register(struct tm6000_core *dev)
+{
+ int ret = -1;
+ struct tm6000_dvb *dvb = dev->dvb;
+
+ mutex_init(&dvb->mutex);
+
+ dvb->streams = 0;
+
+ /* attach the frontend */
+ ret = tm6000_dvb_attach_frontend(dev);
+ if(ret < 0) {
+ printk(KERN_ERR "tm6000: couldn't attach the frontend!\n");
+ goto err;
+ }
+
+ ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T",
+ THIS_MODULE, &dev->udev->dev, adapter_nr);
+ dvb->adapter.priv = dev;
+
+ if (dvb->frontend) {
+ struct xc2028_config cfg = {
+ .i2c_adap = &dev->i2c_adap,
+ .i2c_addr = dev->tuner_addr,
+ };
+
+ ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+ if (ret < 0) {
+ printk(KERN_ERR
+ "tm6000: couldn't register frontend\n");
+ goto adapter_err;
+ }
+
+ if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) {
+ printk(KERN_ERR "tm6000: couldn't register "
+ "frontend (xc3028)\n");
+ ret = -EINVAL;
+ goto frontend_err;
+ }
+ printk(KERN_INFO "tm6000: XC2028/3028 asked to be "
+ "attached to frontend!\n");
+ } else {
+ printk(KERN_ERR "tm6000: no frontend found\n");
+ }
+
+ dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING
+ | DMX_MEMORY_BASED_FILTERING;
+ dvb->demux.priv = dev;
+ dvb->demux.filternum = 256;
+ dvb->demux.feednum = 256;
+ dvb->demux.start_feed = tm6000_start_feed;
+ dvb->demux.stop_feed = tm6000_stop_feed;
+ dvb->demux.write_to_decoder = NULL;
+ ret = dvb_dmx_init(&dvb->demux);
+ if(ret < 0) {
+ printk("tm6000: dvb_dmx_init failed (errno = %d)\n", ret);
+ goto frontend_err;
+ }
+
+ dvb->dmxdev.filternum = dev->dvb->demux.filternum;
+ dvb->dmxdev.demux = &dev->dvb->demux.dmx;
+ dvb->dmxdev.capabilities = 0;
+
+ ret = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+ if(ret < 0) {
+ printk("tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret);
+ goto dvb_dmx_err;
+ }
+
+ return 0;
+
+dvb_dmx_err:
+ dvb_dmx_release(&dvb->demux);
+frontend_err:
+ if(dvb->frontend) {
+ dvb_frontend_detach(dvb->frontend);
+ dvb_unregister_frontend(dvb->frontend);
+ }
+adapter_err:
+ dvb_unregister_adapter(&dvb->adapter);
+err:
+ return ret;
+}
+
+void tm6000_dvb_unregister(struct tm6000_core *dev)
+{
+ struct tm6000_dvb *dvb = dev->dvb;
+
+ if(dvb->bulk_urb != NULL) {
+ struct urb *bulk_urb = dvb->bulk_urb;
+
+ kfree(bulk_urb->transfer_buffer);
+ bulk_urb->transfer_buffer = NULL;
+ usb_unlink_urb(bulk_urb);
+ usb_free_urb(bulk_urb);
+ }
+
+// mutex_lock(&tm6000_driver.open_close_mutex);
+ if(dvb->frontend) {
+ dvb_frontend_detach(dvb->frontend);
+ dvb_unregister_frontend(dvb->frontend);
+ }
+
+ dvb_dmxdev_release(&dvb->dmxdev);
+ dvb_dmx_release(&dvb->demux);
+ dvb_unregister_adapter(&dvb->adapter);
+ mutex_destroy(&dvb->mutex);
+// mutex_unlock(&tm6000_driver.open_close_mutex);
+
+}
diff --git a/drivers/staging/tm6000/tm6000-i2c.c b/drivers/staging/tm6000/tm6000-i2c.c
new file mode 100644
index 000000000000..4da10f5ea024
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-i2c.c
@@ -0,0 +1,245 @@
+/*
+ tm6000-i2c.c - driver for TM5600/TM6000 USB video capture devices
+
+ Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+
+ Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+ - Fix SMBus Read Byte command
+
+ This 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. 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/usb.h>
+#include <linux/i2c.h>
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include "tuner-xc2028.h"
+
+
+/*FIXME: Hack to avoid needing to patch i2c-id.h */
+#define I2C_HW_B_TM6000 I2C_HW_B_EM28XX
+/* ----------------------------------------------------------- */
+
+static unsigned int i2c_debug = 0;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+#define i2c_dprintk(lvl,fmt, args...) if (i2c_debug>=lvl) do{ \
+ printk(KERN_DEBUG "%s at %s: " fmt, \
+ dev->name, __FUNCTION__ , ##args); } while (0)
+
+static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msgs[], int num)
+{
+ struct tm6000_core *dev = i2c_adap->algo_data;
+ int addr, rc, i, byte;
+
+ if (num <= 0)
+ return 0;
+ for (i = 0; i < num; i++) {
+ addr = (msgs[i].addr << 1) & 0xff;
+ i2c_dprintk(2,"%s %s addr=0x%x len=%d:",
+ (msgs[i].flags & I2C_M_RD) ? "read" : "write",
+ i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
+ if (msgs[i].flags & I2C_M_RD) {
+ /* read request without preceding register selection */
+ /*
+ * The TM6000 only supports a read transaction
+ * immediately after a 1 or 2 byte write to select
+ * a register. We cannot fulfil this request.
+ */
+ i2c_dprintk(2, " read without preceding write not"
+ " supported");
+ rc = -EOPNOTSUPP;
+ goto err;
+ } else if (i + 1 < num && msgs[i].len <= 2 &&
+ (msgs[i + 1].flags & I2C_M_RD) &&
+ msgs[i].addr == msgs[i + 1].addr) {
+ /* 1 or 2 byte write followed by a read */
+ if (i2c_debug >= 2)
+ for (byte = 0; byte < msgs[i].len; byte++)
+ printk(" %02x", msgs[i].buf[byte]);
+ i2c_dprintk(2, "; joined to read %s len=%d:",
+ i == num - 2 ? "stop" : "nonstop",
+ msgs[i + 1].len);
+ rc = tm6000_read_write_usb (dev,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ msgs[i].len == 1 ? REQ_16_SET_GET_I2C_WR1_RDN
+ : REQ_14_SET_GET_I2C_WR2_RDN,
+ addr | msgs[i].buf[0] << 8,
+ msgs[i].len == 1 ? 0 : msgs[i].buf[1],
+ msgs[i + 1].buf, msgs[i + 1].len);
+ i++;
+ if (i2c_debug >= 2)
+ for (byte = 0; byte < msgs[i].len; byte++)
+ printk(" %02x", msgs[i].buf[byte]);
+ } else {
+ /* write bytes */
+ if (i2c_debug >= 2)
+ for (byte = 0; byte < msgs[i].len; byte++)
+ printk(" %02x", msgs[i].buf[byte]);
+ rc = tm6000_read_write_usb(dev,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ REQ_16_SET_GET_I2C_WR1_RDN,
+ addr | msgs[i].buf[0] << 8, 0,
+ msgs[i].buf + 1, msgs[i].len - 1);
+ }
+ if (i2c_debug >= 2)
+ printk("\n");
+ if (rc < 0)
+ goto err;
+ }
+
+ return num;
+err:
+ i2c_dprintk(2," ERROR: %i\n", rc);
+ return rc;
+}
+
+static int tm6000_i2c_eeprom(struct tm6000_core *dev,
+ unsigned char *eedata, int len)
+{
+ int i, rc;
+ unsigned char *p = eedata;
+ unsigned char bytes[17];
+
+ dev->i2c_client.addr = 0xa0 >> 1;
+
+ bytes[16] = '\0';
+ for (i = 0; i < len; ) {
+ *p = i;
+ rc = tm6000_read_write_usb (dev,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ REQ_16_SET_GET_I2C_WR1_RDN, 0xa0 | i<<8, 0, p, 1);
+ if (rc < 1) {
+ if (p == eedata)
+ goto noeeprom;
+ else {
+ printk(KERN_WARNING
+ "%s: i2c eeprom read error (err=%d)\n",
+ dev->name, rc);
+ }
+ return -1;
+ }
+ p++;
+ if (0 == (i % 16))
+ printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
+ printk(" %02x", eedata[i]);
+ if ((eedata[i] >= ' ') && (eedata[i] <= 'z')) {
+ bytes[i%16] = eedata[i];
+ } else {
+ bytes[i%16]='.';
+ }
+
+ i++;
+
+ if (0 == (i % 16)) {
+ bytes[16] = '\0';
+ printk(" %s\n", bytes);
+ }
+ }
+ if (0 != (i%16)) {
+ bytes[i%16] = '\0';
+ for (i %= 16; i < 16; i++)
+ printk(" ");
+ }
+ printk(" %s\n", bytes);
+
+ return 0;
+
+noeeprom:
+ printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
+ dev->name, rc);
+ return rc;
+}
+
+/* ----------------------------------------------------------- */
+
+/*
+ * functionality()
+ */
+static u32 functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL;
+}
+
+#define mass_write(addr, reg, data...) \
+ { const static u8 _val[] = data; \
+ rc=tm6000_read_write_usb(dev,USB_DIR_OUT | USB_TYPE_VENDOR, \
+ REQ_16_SET_GET_I2C_WR1_RDN,(reg<<8)+addr, 0x00, (u8 *) _val, \
+ ARRAY_SIZE(_val)); \
+ if (rc<0) { \
+ printk(KERN_ERR "Error on line %d: %d\n",__LINE__,rc); \
+ return rc; \
+ } \
+ msleep (10); \
+ }
+
+static struct i2c_algorithm tm6000_algo = {
+ .master_xfer = tm6000_i2c_xfer,
+ .functionality = functionality,
+};
+
+static struct i2c_adapter tm6000_adap_template = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_TV_ANALOG,
+ .name = "tm6000",
+ .id = I2C_HW_B_TM6000,
+ .algo = &tm6000_algo,
+};
+
+static struct i2c_client tm6000_client_template = {
+ .name = "tm6000 internal",
+};
+
+/* ----------------------------------------------------------- */
+
+/*
+ * tm6000_i2c_register()
+ * register i2c bus
+ */
+int tm6000_i2c_register(struct tm6000_core *dev)
+{
+ unsigned char eedata[256];
+
+ dev->i2c_adap = tm6000_adap_template;
+ dev->i2c_adap.dev.parent = &dev->udev->dev;
+ strcpy(dev->i2c_adap.name, dev->name);
+ dev->i2c_adap.algo_data = dev;
+ i2c_add_adapter(&dev->i2c_adap);
+
+ dev->i2c_client = tm6000_client_template;
+ dev->i2c_client.adapter = &dev->i2c_adap;
+
+ i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
+
+ tm6000_i2c_eeprom(dev, eedata, sizeof(eedata));
+
+ return 0;
+}
+
+/*
+ * tm6000_i2c_unregister()
+ * unregister i2c_bus
+ */
+int tm6000_i2c_unregister(struct tm6000_core *dev)
+{
+ i2c_del_adapter(&dev->i2c_adap);
+ return 0;
+}
diff --git a/drivers/staging/tm6000/tm6000-regs.h b/drivers/staging/tm6000/tm6000-regs.h
new file mode 100644
index 000000000000..85acc07f62e9
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-regs.h
@@ -0,0 +1,86 @@
+/*
+ tm6000-regs.h - driver for TM5600/TM6000 USB video capture devices
+
+ Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.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 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. 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.
+ */
+
+/*
+ * Define TV Master TM5600/TM6000 Request codes
+ */
+#define REQ_00_SET_IR_VALUE 0
+#define REQ_01_SET_WAKEUP_IRCODE 1
+#define REQ_02_GET_IR_CODE 2
+#define REQ_03_SET_GET_MCU_PIN 3
+#define REQ_04_EN_DISABLE_MCU_INT 4
+#define REQ_05_SET_GET_USBREG 5
+ /* Write: RegNum, Value, 0 */
+ /* Read : RegNum, Value, 1, RegStatus */
+#define REQ_06_SET_GET_USBREG_BIT 6
+#define REQ_07_SET_GET_AVREG 7
+ /* Write: RegNum, Value, 0 */
+ /* Read : RegNum, Value, 1, RegStatus */
+#define REQ_08_SET_GET_AVREG_BIT 8
+#define REQ_09_SET_GET_TUNER_FQ 9
+#define REQ_10_SET_TUNER_SYSTEM 10
+#define REQ_11_SET_EEPROM_ADDR 11
+#define REQ_12_SET_GET_EEPROMBYTE 12
+#define REQ_13_GET_EEPROM_SEQREAD 13
+#define REQ_14_SET_GET_I2C_WR2_RDN 14
+#define REQ_15_SET_GET_I2CBYTE 15
+ /* Write: Subaddr, Slave Addr, value, 0 */
+ /* Read : Subaddr, Slave Addr, value, 1 */
+#define REQ_16_SET_GET_I2C_WR1_RDN 16
+ /* Subaddr, Slave Addr, 0, length */
+#define REQ_17_SET_GET_I2CFP 17
+ /* Write: Slave Addr, register, value */
+ /* Read : Slave Addr, register, 2, data */
+
+/*
+ * Define TV Master TM5600/TM6000 GPIO lines
+ */
+
+#define TM6000_GPIO_CLK 0x101
+#define TM6000_GPIO_DATA 0x100
+
+#define TM6000_GPIO_1 0x102
+#define TM6000_GPIO_2 0x103
+#define TM6000_GPIO_3 0x104
+#define TM6000_GPIO_4 0x300
+#define TM6000_GPIO_5 0x301
+#define TM6000_GPIO_6 0x304
+#define TM6000_GPIO_7 0x305
+
+/* tm6010 defines GPIO with different values */
+#define TM6010_GPIO_0 0x0102
+#define TM6010_GPIO_1 0x0103
+#define TM6010_GPIO_2 0x0104
+#define TM6010_GPIO_3 0x0105
+#define TM6010_GPIO_4 0x0106
+#define TM6010_GPIO_5 0x0107
+#define TM6010_GPIO_6 0x0300
+#define TM6010_GPIO_7 0x0301
+#define TM6010_GPIO_9 0x0305
+/*
+ * Define TV Master TM5600/TM6000 URB message codes and length
+ */
+
+enum {
+ TM6000_URB_MSG_VIDEO=1,
+ TM6000_URB_MSG_AUDIO,
+ TM6000_URB_MSG_VBI,
+ TM6000_URB_MSG_PTS,
+ TM6000_URB_MSG_ERR,
+};
diff --git a/drivers/staging/tm6000/tm6000-stds.c b/drivers/staging/tm6000/tm6000-stds.c
new file mode 100644
index 000000000000..c61d1a61ea3e
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-stds.c
@@ -0,0 +1,873 @@
+/*
+ tm6000-stds.c - driver for TM5600/TM6000 USB video capture devices
+
+ Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@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 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. 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 "tm6000.h"
+#include "tm6000-regs.h"
+
+struct tm6000_reg_settings {
+ unsigned char req;
+ unsigned char reg;
+ unsigned char value;
+};
+
+struct tm6000_std_tv_settings {
+ v4l2_std_id id;
+ struct tm6000_reg_settings sif[12];
+ struct tm6000_reg_settings nosif[12];
+ struct tm6000_reg_settings common[25];
+};
+
+struct tm6000_std_settings {
+ v4l2_std_id id;
+ struct tm6000_reg_settings common[37];
+};
+
+static struct tm6000_std_tv_settings tv_stds[] = {
+ {
+ .id = V4L2_STD_PAL_M,
+ .sif = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xf8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf3},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x08},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf1},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x62},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfe},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0xcb},
+ {0, 0, 0},
+ },
+ .nosif = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xf8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf3},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x0f},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf1},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x60},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfc},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0x8b},
+ {0, 0, 0},
+ },
+ .common = {
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x00, 0x04},
+ {REQ_07_SET_GET_AVREG, 0x01, 0x0e},
+ {REQ_07_SET_GET_AVREG, 0x02, 0x5f},
+ {REQ_07_SET_GET_AVREG, 0x03, 0x00},
+ {REQ_07_SET_GET_AVREG, 0x07, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x18, 0x1e},
+ {REQ_07_SET_GET_AVREG, 0x19, 0x83},
+ {REQ_07_SET_GET_AVREG, 0x1a, 0x0a},
+ {REQ_07_SET_GET_AVREG, 0x1b, 0xe0},
+ {REQ_07_SET_GET_AVREG, 0x1c, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x1d, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1e, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1f, 0xcd},
+ {REQ_07_SET_GET_AVREG, 0x2e, 0x88},
+ {REQ_07_SET_GET_AVREG, 0x30, 0x20},
+ {REQ_07_SET_GET_AVREG, 0x31, 0x61},
+ {REQ_07_SET_GET_AVREG, 0x33, 0x0c},
+ {REQ_07_SET_GET_AVREG, 0x35, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x82, 0x52},
+ {REQ_07_SET_GET_AVREG, 0x83, 0x6F},
+
+ {REQ_07_SET_GET_AVREG, 0x04, 0xdc},
+ {REQ_07_SET_GET_AVREG, 0x0d, 0x07},
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x00},
+ {0, 0, 0},
+ },
+ }, {
+ .id = V4L2_STD_PAL_Nc,
+ .sif = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xf8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf3},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x08},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf1},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x62},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfe},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0xcb},
+ {0, 0, 0},
+ },
+ .nosif = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xf8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf3},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x0f},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf1},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x60},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfc},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0x8b},
+ {0, 0, 0},
+ },
+ .common = {
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x00, 0x36},
+ {REQ_07_SET_GET_AVREG, 0x01, 0x0e},
+ {REQ_07_SET_GET_AVREG, 0x02, 0x5f},
+ {REQ_07_SET_GET_AVREG, 0x03, 0x02},
+ {REQ_07_SET_GET_AVREG, 0x07, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x18, 0x1e},
+ {REQ_07_SET_GET_AVREG, 0x19, 0x91},
+ {REQ_07_SET_GET_AVREG, 0x1a, 0x1f},
+ {REQ_07_SET_GET_AVREG, 0x1b, 0x0c},
+ {REQ_07_SET_GET_AVREG, 0x1c, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x1d, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1e, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1f, 0xcd},
+ {REQ_07_SET_GET_AVREG, 0x2e, 0x8c},
+ {REQ_07_SET_GET_AVREG, 0x30, 0x2c},
+ {REQ_07_SET_GET_AVREG, 0x31, 0xc1},
+ {REQ_07_SET_GET_AVREG, 0x33, 0x0c},
+ {REQ_07_SET_GET_AVREG, 0x35, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x82, 0x52},
+ {REQ_07_SET_GET_AVREG, 0x83, 0x6F},
+
+ {REQ_07_SET_GET_AVREG, 0x04, 0xdc},
+ {REQ_07_SET_GET_AVREG, 0x0d, 0x07},
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x00},
+ {0, 0, 0},
+ },
+ }, {
+ .id = V4L2_STD_PAL,
+ .sif = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xf8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf3},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x08},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf1},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x62},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfe},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0xcb},
+ {0, 0, 0}
+ },
+ .nosif = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xf8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf3},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x0f},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf1},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x60},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfc},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0x8b},
+ {0, 0, 0},
+ },
+ .common = {
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x00, 0x32},
+ {REQ_07_SET_GET_AVREG, 0x01, 0x0e},
+ {REQ_07_SET_GET_AVREG, 0x02, 0x5f},
+ {REQ_07_SET_GET_AVREG, 0x03, 0x02},
+ {REQ_07_SET_GET_AVREG, 0x07, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x18, 0x25},
+ {REQ_07_SET_GET_AVREG, 0x19, 0xd5},
+ {REQ_07_SET_GET_AVREG, 0x1a, 0x63},
+ {REQ_07_SET_GET_AVREG, 0x1b, 0x50},
+ {REQ_07_SET_GET_AVREG, 0x1c, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x1d, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1e, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1f, 0xcd},
+ {REQ_07_SET_GET_AVREG, 0x2e, 0x8c},
+ {REQ_07_SET_GET_AVREG, 0x30, 0x2c},
+ {REQ_07_SET_GET_AVREG, 0x31, 0xc1},
+ {REQ_07_SET_GET_AVREG, 0x33, 0x0c},
+ {REQ_07_SET_GET_AVREG, 0x35, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x82, 0x52},
+ {REQ_07_SET_GET_AVREG, 0x83, 0x6F},
+
+ {REQ_07_SET_GET_AVREG, 0x04, 0xdc},
+ {REQ_07_SET_GET_AVREG, 0x0d, 0x07},
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x00},
+ {0, 0, 0},
+ },
+ }, {
+ .id = V4L2_STD_SECAM,
+ .sif = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xf8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf3},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x08},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf1},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x62},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfe},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0xcb},
+ {0, 0, 0},
+ },
+ .nosif = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xf8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf3},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x0f},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf1},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x60},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfc},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0x8b},
+ {0, 0, 0},
+ },
+ .common = {
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x00, 0x38},
+ {REQ_07_SET_GET_AVREG, 0x01, 0x0e},
+ {REQ_07_SET_GET_AVREG, 0x02, 0x5f},
+ {REQ_07_SET_GET_AVREG, 0x03, 0x02},
+ {REQ_07_SET_GET_AVREG, 0x07, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x18, 0x24},
+ {REQ_07_SET_GET_AVREG, 0x19, 0x92},
+ {REQ_07_SET_GET_AVREG, 0x1a, 0xe8},
+ {REQ_07_SET_GET_AVREG, 0x1b, 0xed},
+ {REQ_07_SET_GET_AVREG, 0x1c, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x1d, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1e, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1f, 0xcd},
+ {REQ_07_SET_GET_AVREG, 0x2e, 0x8c},
+ {REQ_07_SET_GET_AVREG, 0x30, 0x2c},
+ {REQ_07_SET_GET_AVREG, 0x31, 0xc1},
+ {REQ_07_SET_GET_AVREG, 0x33, 0x2c},
+ {REQ_07_SET_GET_AVREG, 0x35, 0x18},
+ {REQ_07_SET_GET_AVREG, 0x82, 0x42},
+ {REQ_07_SET_GET_AVREG, 0x83, 0xFF},
+
+ {REQ_07_SET_GET_AVREG, 0x0d, 0x07},
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x00},
+ {0, 0, 0},
+ },
+ }, {
+ .id = V4L2_STD_NTSC,
+ .sif = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xf8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf3},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x08},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf1},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x62},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfe},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0xcb},
+ {0, 0, 0},
+ },
+ .nosif = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xf8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf3},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x0f},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf1},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x60},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfc},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0x8b},
+ {0, 0, 0},
+ },
+ .common = {
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x00, 0x00},
+ {REQ_07_SET_GET_AVREG, 0x01, 0x0f},
+ {REQ_07_SET_GET_AVREG, 0x02, 0x5f},
+ {REQ_07_SET_GET_AVREG, 0x03, 0x00},
+ {REQ_07_SET_GET_AVREG, 0x07, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x18, 0x1e},
+ {REQ_07_SET_GET_AVREG, 0x19, 0x8b},
+ {REQ_07_SET_GET_AVREG, 0x1a, 0xa2},
+ {REQ_07_SET_GET_AVREG, 0x1b, 0xe9},
+ {REQ_07_SET_GET_AVREG, 0x1c, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x1d, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1e, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1f, 0xcd},
+ {REQ_07_SET_GET_AVREG, 0x2e, 0x88},
+ {REQ_07_SET_GET_AVREG, 0x30, 0x22},
+ {REQ_07_SET_GET_AVREG, 0x31, 0x61},
+ {REQ_07_SET_GET_AVREG, 0x33, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x35, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x82, 0x42},
+ {REQ_07_SET_GET_AVREG, 0x83, 0x6F},
+
+ {REQ_07_SET_GET_AVREG, 0x04, 0xdd},
+ {REQ_07_SET_GET_AVREG, 0x0d, 0x07},
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x00},
+ {0, 0, 0},
+ },
+ },
+};
+
+static struct tm6000_std_settings composite_stds[] = {
+ {
+ .id = V4L2_STD_PAL_M,
+ .common = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xf4},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf3},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x0f},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf1},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x68},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfc},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0x8b},
+
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x00, 0x04},
+ {REQ_07_SET_GET_AVREG, 0x01, 0x0e},
+ {REQ_07_SET_GET_AVREG, 0x02, 0x5f},
+ {REQ_07_SET_GET_AVREG, 0x03, 0x00},
+ {REQ_07_SET_GET_AVREG, 0x07, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x18, 0x1e},
+ {REQ_07_SET_GET_AVREG, 0x19, 0x83},
+ {REQ_07_SET_GET_AVREG, 0x1a, 0x0a},
+ {REQ_07_SET_GET_AVREG, 0x1b, 0xe0},
+ {REQ_07_SET_GET_AVREG, 0x1c, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x1d, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1e, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1f, 0xcd},
+ {REQ_07_SET_GET_AVREG, 0x2e, 0x88},
+ {REQ_07_SET_GET_AVREG, 0x30, 0x20},
+ {REQ_07_SET_GET_AVREG, 0x31, 0x61},
+ {REQ_07_SET_GET_AVREG, 0x33, 0x0c},
+ {REQ_07_SET_GET_AVREG, 0x35, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x82, 0x52},
+ {REQ_07_SET_GET_AVREG, 0x83, 0x6F},
+
+ {REQ_07_SET_GET_AVREG, 0x04, 0xdc},
+ {REQ_07_SET_GET_AVREG, 0x0d, 0x07},
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x00},
+ {0, 0, 0},
+ },
+ }, {
+ .id = V4L2_STD_PAL_Nc,
+ .common = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xf4},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf3},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x0f},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf1},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x68},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfc},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0x8b},
+
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x00, 0x36},
+ {REQ_07_SET_GET_AVREG, 0x01, 0x0e},
+ {REQ_07_SET_GET_AVREG, 0x02, 0x5f},
+ {REQ_07_SET_GET_AVREG, 0x03, 0x02},
+ {REQ_07_SET_GET_AVREG, 0x07, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x18, 0x1e},
+ {REQ_07_SET_GET_AVREG, 0x19, 0x91},
+ {REQ_07_SET_GET_AVREG, 0x1a, 0x1f},
+ {REQ_07_SET_GET_AVREG, 0x1b, 0x0c},
+ {REQ_07_SET_GET_AVREG, 0x1c, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x1d, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1e, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1f, 0xcd},
+ {REQ_07_SET_GET_AVREG, 0x2e, 0x8c},
+ {REQ_07_SET_GET_AVREG, 0x30, 0x2c},
+ {REQ_07_SET_GET_AVREG, 0x31, 0xc1},
+ {REQ_07_SET_GET_AVREG, 0x33, 0x0c},
+ {REQ_07_SET_GET_AVREG, 0x35, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x82, 0x52},
+ {REQ_07_SET_GET_AVREG, 0x83, 0x6F},
+
+ {REQ_07_SET_GET_AVREG, 0x04, 0xdc},
+ {REQ_07_SET_GET_AVREG, 0x0d, 0x07},
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x00},
+ {0, 0, 0},
+ },
+ }, {
+ .id = V4L2_STD_PAL,
+ .common = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xf4},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf3},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x0f},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf1},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x68},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfc},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0x8b},
+
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x00, 0x32},
+ {REQ_07_SET_GET_AVREG, 0x01, 0x0e},
+ {REQ_07_SET_GET_AVREG, 0x02, 0x5f},
+ {REQ_07_SET_GET_AVREG, 0x03, 0x02},
+ {REQ_07_SET_GET_AVREG, 0x07, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x18, 0x25},
+ {REQ_07_SET_GET_AVREG, 0x19, 0xd5},
+ {REQ_07_SET_GET_AVREG, 0x1a, 0x63},
+ {REQ_07_SET_GET_AVREG, 0x1b, 0x50},
+ {REQ_07_SET_GET_AVREG, 0x1c, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x1d, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1e, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1f, 0xcd},
+ {REQ_07_SET_GET_AVREG, 0x2e, 0x8c},
+ {REQ_07_SET_GET_AVREG, 0x30, 0x2c},
+ {REQ_07_SET_GET_AVREG, 0x31, 0xc1},
+ {REQ_07_SET_GET_AVREG, 0x33, 0x0c},
+ {REQ_07_SET_GET_AVREG, 0x35, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x82, 0x52},
+ {REQ_07_SET_GET_AVREG, 0x83, 0x6F},
+
+ {REQ_07_SET_GET_AVREG, 0x04, 0xdc},
+ {REQ_07_SET_GET_AVREG, 0x0d, 0x07},
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x00},
+ {0, 0, 0},
+ },
+ }, {
+ .id = V4L2_STD_SECAM,
+ .common = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xf4},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf3},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x0f},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf1},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x68},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfc},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0x8b},
+
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x00, 0x38},
+ {REQ_07_SET_GET_AVREG, 0x01, 0x0e},
+ {REQ_07_SET_GET_AVREG, 0x02, 0x5f},
+ {REQ_07_SET_GET_AVREG, 0x03, 0x02},
+ {REQ_07_SET_GET_AVREG, 0x07, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x18, 0x24},
+ {REQ_07_SET_GET_AVREG, 0x19, 0x92},
+ {REQ_07_SET_GET_AVREG, 0x1a, 0xe8},
+ {REQ_07_SET_GET_AVREG, 0x1b, 0xed},
+ {REQ_07_SET_GET_AVREG, 0x1c, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x1d, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1e, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1f, 0xcd},
+ {REQ_07_SET_GET_AVREG, 0x2e, 0x8c},
+ {REQ_07_SET_GET_AVREG, 0x30, 0x2c},
+ {REQ_07_SET_GET_AVREG, 0x31, 0xc1},
+ {REQ_07_SET_GET_AVREG, 0x33, 0x2c},
+ {REQ_07_SET_GET_AVREG, 0x35, 0x18},
+ {REQ_07_SET_GET_AVREG, 0x82, 0x42},
+ {REQ_07_SET_GET_AVREG, 0x83, 0xFF},
+
+ {REQ_07_SET_GET_AVREG, 0x0d, 0x07},
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x00},
+ {0, 0, 0},
+ },
+ }, {
+ .id = V4L2_STD_NTSC,
+ .common = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xf4},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf3},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x0f},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf1},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x68},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfc},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0x8b},
+
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x00, 0x00},
+ {REQ_07_SET_GET_AVREG, 0x01, 0x0f},
+ {REQ_07_SET_GET_AVREG, 0x02, 0x5f},
+ {REQ_07_SET_GET_AVREG, 0x03, 0x00},
+ {REQ_07_SET_GET_AVREG, 0x07, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x18, 0x1e},
+ {REQ_07_SET_GET_AVREG, 0x19, 0x8b},
+ {REQ_07_SET_GET_AVREG, 0x1a, 0xa2},
+ {REQ_07_SET_GET_AVREG, 0x1b, 0xe9},
+ {REQ_07_SET_GET_AVREG, 0x1c, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x1d, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1e, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1f, 0xcd},
+ {REQ_07_SET_GET_AVREG, 0x2e, 0x88},
+ {REQ_07_SET_GET_AVREG, 0x30, 0x22},
+ {REQ_07_SET_GET_AVREG, 0x31, 0x61},
+ {REQ_07_SET_GET_AVREG, 0x33, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x35, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x82, 0x42},
+ {REQ_07_SET_GET_AVREG, 0x83, 0x6F},
+
+ {REQ_07_SET_GET_AVREG, 0x04, 0xdd},
+ {REQ_07_SET_GET_AVREG, 0x0d, 0x07},
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x00},
+ {0, 0, 0},
+ },
+ },
+};
+
+static struct tm6000_std_settings svideo_stds[] = {
+ {
+ .id = V4L2_STD_PAL_M,
+ .common = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xfc},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x00},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x68},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfc},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0x8a},
+
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x00, 0x05},
+ {REQ_07_SET_GET_AVREG, 0x01, 0x0e},
+ {REQ_07_SET_GET_AVREG, 0x02, 0x5f},
+ {REQ_07_SET_GET_AVREG, 0x03, 0x04},
+ {REQ_07_SET_GET_AVREG, 0x07, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x18, 0x1e},
+ {REQ_07_SET_GET_AVREG, 0x19, 0x83},
+ {REQ_07_SET_GET_AVREG, 0x1a, 0x0a},
+ {REQ_07_SET_GET_AVREG, 0x1b, 0xe0},
+ {REQ_07_SET_GET_AVREG, 0x1c, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x1d, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1e, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1f, 0xcd},
+ {REQ_07_SET_GET_AVREG, 0x2e, 0x88},
+ {REQ_07_SET_GET_AVREG, 0x30, 0x22},
+ {REQ_07_SET_GET_AVREG, 0x31, 0x61},
+ {REQ_07_SET_GET_AVREG, 0x33, 0x0c},
+ {REQ_07_SET_GET_AVREG, 0x35, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x82, 0x52},
+ {REQ_07_SET_GET_AVREG, 0x83, 0x6F},
+
+ {REQ_07_SET_GET_AVREG, 0x04, 0xdc},
+ {REQ_07_SET_GET_AVREG, 0x0d, 0x07},
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x00},
+ {0, 0, 0},
+ },
+ }, {
+ .id = V4L2_STD_PAL_Nc,
+ .common = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xfc},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x00},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x68},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfc},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0x8a},
+
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x00, 0x37},
+ {REQ_07_SET_GET_AVREG, 0x01, 0x0e},
+ {REQ_07_SET_GET_AVREG, 0x02, 0x5f},
+ {REQ_07_SET_GET_AVREG, 0x03, 0x04},
+ {REQ_07_SET_GET_AVREG, 0x07, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x18, 0x1e},
+ {REQ_07_SET_GET_AVREG, 0x19, 0x91},
+ {REQ_07_SET_GET_AVREG, 0x1a, 0x1f},
+ {REQ_07_SET_GET_AVREG, 0x1b, 0x0c},
+ {REQ_07_SET_GET_AVREG, 0x1c, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x1d, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1e, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1f, 0xcd},
+ {REQ_07_SET_GET_AVREG, 0x2e, 0x88},
+ {REQ_07_SET_GET_AVREG, 0x30, 0x22},
+ {REQ_07_SET_GET_AVREG, 0x31, 0xc1},
+ {REQ_07_SET_GET_AVREG, 0x33, 0x0c},
+ {REQ_07_SET_GET_AVREG, 0x35, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x82, 0x52},
+ {REQ_07_SET_GET_AVREG, 0x83, 0x6F},
+
+ {REQ_07_SET_GET_AVREG, 0x04, 0xdc},
+ {REQ_07_SET_GET_AVREG, 0x0d, 0x07},
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x00},
+ {0, 0, 0},
+ },
+ }, {
+ .id = V4L2_STD_PAL,
+ .common = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xfc},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x00},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x68},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfc},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0x8a},
+
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x00, 0x33},
+ {REQ_07_SET_GET_AVREG, 0x01, 0x0e},
+ {REQ_07_SET_GET_AVREG, 0x02, 0x5f},
+ {REQ_07_SET_GET_AVREG, 0x03, 0x04},
+ {REQ_07_SET_GET_AVREG, 0x07, 0x00},
+ {REQ_07_SET_GET_AVREG, 0x18, 0x25},
+ {REQ_07_SET_GET_AVREG, 0x19, 0xd5},
+ {REQ_07_SET_GET_AVREG, 0x1a, 0x63},
+ {REQ_07_SET_GET_AVREG, 0x1b, 0x50},
+ {REQ_07_SET_GET_AVREG, 0x1c, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x1d, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1e, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1f, 0xcd},
+ {REQ_07_SET_GET_AVREG, 0x2e, 0x8c},
+ {REQ_07_SET_GET_AVREG, 0x30, 0x2a},
+ {REQ_07_SET_GET_AVREG, 0x31, 0xc1},
+ {REQ_07_SET_GET_AVREG, 0x33, 0x0c},
+ {REQ_07_SET_GET_AVREG, 0x35, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x82, 0x52},
+ {REQ_07_SET_GET_AVREG, 0x83, 0x6F},
+
+ {REQ_07_SET_GET_AVREG, 0x04, 0xdc},
+ {REQ_07_SET_GET_AVREG, 0x0d, 0x07},
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x00},
+ {0, 0, 0},
+ },
+ }, {
+ .id = V4L2_STD_SECAM,
+ .common = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xfc},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x00},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x68},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfc},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0x8a},
+
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x00, 0x39},
+ {REQ_07_SET_GET_AVREG, 0x01, 0x0e},
+ {REQ_07_SET_GET_AVREG, 0x02, 0x5f},
+ {REQ_07_SET_GET_AVREG, 0x03, 0x03},
+ {REQ_07_SET_GET_AVREG, 0x07, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x18, 0x24},
+ {REQ_07_SET_GET_AVREG, 0x19, 0x92},
+ {REQ_07_SET_GET_AVREG, 0x1a, 0xe8},
+ {REQ_07_SET_GET_AVREG, 0x1b, 0xed},
+ {REQ_07_SET_GET_AVREG, 0x1c, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x1d, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1e, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1f, 0xcd},
+ {REQ_07_SET_GET_AVREG, 0x2e, 0x8c},
+ {REQ_07_SET_GET_AVREG, 0x30, 0x2a},
+ {REQ_07_SET_GET_AVREG, 0x31, 0xc1},
+ {REQ_07_SET_GET_AVREG, 0x33, 0x2c},
+ {REQ_07_SET_GET_AVREG, 0x35, 0x18},
+ {REQ_07_SET_GET_AVREG, 0x82, 0x42},
+ {REQ_07_SET_GET_AVREG, 0x83, 0xFF},
+
+ {REQ_07_SET_GET_AVREG, 0x0d, 0x07},
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x00},
+ {0, 0, 0},
+ },
+ }, {
+ .id = V4L2_STD_NTSC,
+ .common = {
+ {REQ_08_SET_GET_AVREG_BIT, 0xe2, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe3, 0xfc},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe4, 0xf8},
+ {REQ_08_SET_GET_AVREG_BIT, 0xe6, 0x00},
+ {REQ_08_SET_GET_AVREG_BIT, 0xea, 0xf2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xeb, 0xf0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xec, 0xc2},
+ {REQ_08_SET_GET_AVREG_BIT, 0xed, 0xe0},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf0, 0x68},
+ {REQ_08_SET_GET_AVREG_BIT, 0xf1, 0xfc},
+ {REQ_07_SET_GET_AVREG, 0xfe, 0x8a},
+
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x00, 0x01},
+ {REQ_07_SET_GET_AVREG, 0x01, 0x0f},
+ {REQ_07_SET_GET_AVREG, 0x02, 0x5f},
+ {REQ_07_SET_GET_AVREG, 0x03, 0x03},
+ {REQ_07_SET_GET_AVREG, 0x07, 0x00},
+ {REQ_07_SET_GET_AVREG, 0x17, 0x8b},
+ {REQ_07_SET_GET_AVREG, 0x18, 0x1e},
+ {REQ_07_SET_GET_AVREG, 0x19, 0x8b},
+ {REQ_07_SET_GET_AVREG, 0x1a, 0xa2},
+ {REQ_07_SET_GET_AVREG, 0x1b, 0xe9},
+ {REQ_07_SET_GET_AVREG, 0x1c, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x1d, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1e, 0xcc},
+ {REQ_07_SET_GET_AVREG, 0x1f, 0xcd},
+ {REQ_07_SET_GET_AVREG, 0x2e, 0x88},
+ {REQ_07_SET_GET_AVREG, 0x30, 0x22},
+ {REQ_07_SET_GET_AVREG, 0x31, 0x61},
+ {REQ_07_SET_GET_AVREG, 0x33, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x35, 0x1c},
+ {REQ_07_SET_GET_AVREG, 0x82, 0x42},
+ {REQ_07_SET_GET_AVREG, 0x83, 0x6F},
+
+ {REQ_07_SET_GET_AVREG, 0x04, 0xdd},
+ {REQ_07_SET_GET_AVREG, 0x0d, 0x07},
+ {REQ_07_SET_GET_AVREG, 0x3f, 0x00},
+ {0, 0, 0},
+ },
+ },
+};
+
+void tm6000_get_std_res(struct tm6000_core *dev)
+{
+ /* Currently, those are the only supported resoltions */
+ if (dev->norm & V4L2_STD_525_60) {
+ dev->height = 480;
+ } else {
+ dev->height = 576;
+ }
+ dev->width = 720;
+}
+
+static int tm6000_load_std(struct tm6000_core *dev,
+ struct tm6000_reg_settings *set, int max_size)
+{
+ int i, rc;
+
+ /* Load board's initialization table */
+ for (i = 0; max_size; i++) {
+ if (!set[i].req)
+ return 0;
+
+ if ((dev->dev_type != TM6010) &&
+ (set[i].req == REQ_08_SET_GET_AVREG_BIT))
+ continue;
+
+ rc = tm6000_set_reg(dev, set[i].req, set[i].reg, set[i].value);
+ if (rc < 0) {
+ printk(KERN_ERR "Error %i while setting "
+ "req %d, reg %d to value %d\n",
+ rc, set[i].req, set[i].reg, set[i].value);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static int tm6000_set_tv(struct tm6000_core *dev, int pos)
+{
+ int rc;
+
+ /* FIXME: This code is for tm6010 - not tested yet - doesn't work with
+ tm5600
+ */
+
+ /* FIXME: This is tuner-dependent */
+ int nosif = 0;
+
+ if (nosif) {
+ rc = tm6000_load_std(dev, tv_stds[pos].nosif,
+ sizeof(tv_stds[pos].nosif));
+ } else {
+ rc = tm6000_load_std(dev, tv_stds[pos].sif,
+ sizeof(tv_stds[pos].sif));
+ }
+ if (rc < 0)
+ return rc;
+ rc = tm6000_load_std(dev, tv_stds[pos].common,
+ sizeof(tv_stds[pos].common));
+
+ return rc;
+}
+
+int tm6000_set_standard(struct tm6000_core *dev, v4l2_std_id * norm)
+{
+ int i, rc = 0;
+
+ dev->norm = *norm;
+ tm6000_get_std_res(dev);
+
+ switch (dev->input) {
+ case TM6000_INPUT_TV:
+ for (i = 0; i < ARRAY_SIZE(tv_stds); i++) {
+ if (*norm & tv_stds[i].id) {
+ rc = tm6000_set_tv(dev, i);
+ goto ret;
+ }
+ }
+ return -EINVAL;
+ case TM6000_INPUT_SVIDEO:
+ for (i = 0; i < ARRAY_SIZE(svideo_stds); i++) {
+ if (*norm & svideo_stds[i].id) {
+ rc = tm6000_load_std(dev, svideo_stds[i].common,
+ sizeof(svideo_stds[i].
+ common));
+ goto ret;
+ }
+ }
+ return -EINVAL;
+ case TM6000_INPUT_COMPOSITE:
+ for (i = 0; i < ARRAY_SIZE(composite_stds); i++) {
+ if (*norm & composite_stds[i].id) {
+ rc = tm6000_load_std(dev,
+ composite_stds[i].common,
+ sizeof(composite_stds[i].
+ common));
+ goto ret;
+ }
+ }
+ return -EINVAL;
+ }
+
+ret:
+ if (rc < 0)
+ return rc;
+
+ msleep(40);
+
+
+ return 0;
+}
diff --git a/drivers/staging/tm6000/tm6000-usb-isoc.h b/drivers/staging/tm6000/tm6000-usb-isoc.h
new file mode 100644
index 000000000000..11297763de6f
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-usb-isoc.h
@@ -0,0 +1,53 @@
+/*
+ tm6000-buf.c - driver for TM5600/TM6000 USB video capture devices
+
+ Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.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 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. 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/videodev2.h>
+
+#define TM6000_URB_MSG_LEN 180
+
+struct usb_isoc_ctl {
+ /* max packet size of isoc transaction */
+ int max_pkt_size;
+
+ /* number of allocated urbs */
+ int num_bufs;
+
+ /* urb for isoc transfers */
+ struct urb **urb;
+
+ /* transfer buffers for isoc transfer */
+ char **transfer_buffer;
+
+ /* Last buffer command and region */
+ u8 cmd;
+ int pos, size, pktsize;
+
+ /* Last field: ODD or EVEN? */
+ int field;
+
+ /* Stores incomplete commands */
+ u32 tmp_buf;
+ int tmp_buf_len;
+
+ /* Stores already requested buffers */
+ struct tm6000_buffer *buf;
+
+ /* Stores the number of received fields */
+ int nfields;
+};
diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c
new file mode 100644
index 000000000000..fc5a9089ab68
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000-video.c
@@ -0,0 +1,1573 @@
+/*
+ tm6000-video.c - driver for TM5600/TM6000 USB video capture devices
+
+ Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+
+ Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+ - Fixed module load/unload
+
+ This 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. 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/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/random.h>
+#include <linux/version.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/highmem.h>
+#include <linux/freezer.h>
+
+#include "tm6000-regs.h"
+#include "tm6000.h"
+
+#define BUFFER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
+
+/* Limits minimum and default number of buffers */
+#define TM6000_MIN_BUF 4
+#define TM6000_DEF_BUF 8
+
+#define TM6000_MAX_ISO_PACKETS 40 /* Max number of ISO packets */
+
+/* Declare static vars that will be used as parameters */
+static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
+static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
+
+/* Debug level */
+int tm6000_debug;
+
+/* supported controls */
+static struct v4l2_queryctrl tm6000_qctrl[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 54,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = 119,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = 112,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = -128,
+ .maximum = 127,
+ .step = 0x1,
+ .default_value = 0,
+ .flags = 0,
+ }
+};
+
+static int qctl_regs[ARRAY_SIZE(tm6000_qctrl)];
+
+static struct tm6000_fmt format[] = {
+ {
+ .name = "4:2:2, packed, YVY2",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16,
+ }, {
+ .name = "4:2:2, packed, UYVY",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .depth = 16,
+ }, {
+ .name = "A/V + VBI mux packet",
+ .fourcc = V4L2_PIX_FMT_TM6000,
+ .depth = 16,
+ }
+};
+
+static LIST_HEAD(tm6000_corelist);
+
+/* ------------------------------------------------------------------
+ DMA and thread functions
+ ------------------------------------------------------------------*/
+
+#define norm_maxw(a) 720
+#define norm_maxh(a) 576
+
+#define norm_minw(a) norm_maxw(a)
+#define norm_minh(a) norm_maxh(a)
+
+/*
+ * video-buf generic routine to get the next available buffer
+ */
+static inline void get_next_buf(struct tm6000_dmaqueue *dma_q,
+ struct tm6000_buffer **buf)
+{
+ struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+ char *outp;
+
+ if (list_empty(&dma_q->active)) {
+ dprintk(dev, V4L2_DEBUG_QUEUE, "No active queue to serve\n");
+ *buf = NULL;
+ return;
+ }
+
+ *buf = list_entry(dma_q->active.next,
+ struct tm6000_buffer, vb.queue);
+
+ if (!buf)
+ return;
+
+ /* Cleans up buffer - Usefull for testing for frame/URB loss */
+ outp = videobuf_to_vmalloc(&(*buf)->vb);
+ memset(outp, 0, (*buf)->vb.size);
+
+ return;
+}
+
+/*
+ * Announces that a buffer were filled and request the next
+ */
+static inline void buffer_filled(struct tm6000_core *dev,
+ struct tm6000_dmaqueue *dma_q,
+ struct tm6000_buffer *buf)
+{
+ /* Advice that buffer was filled */
+ dprintk(dev, V4L2_DEBUG_ISOC, "[%p/%d] wakeup\n", buf, buf->vb.i);
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
+
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+}
+
+const char *tm6000_msg_type[] = {
+ "unknown(0)", /* 0 */
+ "video", /* 1 */
+ "audio", /* 2 */
+ "vbi", /* 3 */
+ "pts", /* 4 */
+ "err", /* 5 */
+ "unknown(6)", /* 6 */
+ "unknown(7)", /* 7 */
+};
+
+/*
+ * Identify the tm5600/6000 buffer header type and properly handles
+ */
+static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp,
+ u8 *out_p, struct tm6000_buffer **buf)
+{
+ struct tm6000_dmaqueue *dma_q = urb->context;
+ struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+ u8 c;
+ unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
+ int rc = 0;
+ /* FIXME: move to tm6000-isoc */
+ static int last_line = -2, start_line = -2, last_field = -2;
+
+ /* FIXME: this is the hardcoded window size
+ */
+ unsigned int linewidth = (*buf)->vb.width << 1;
+
+ if (!dev->isoc_ctl.cmd) {
+ c = (header >> 24) & 0xff;
+
+ /* split the header fields */
+ size = (((header & 0x7e) << 1) -1) *4;
+ block = (header >> 7) & 0xf;
+ field = (header >> 11) & 0x1;
+ line = (header >> 12) & 0x1ff;
+ cmd = (header >> 21) & 0x7;
+
+ /* Validates header fields */
+ if(size > TM6000_URB_MSG_LEN)
+ size = TM6000_URB_MSG_LEN;
+
+ if (cmd == TM6000_URB_MSG_VIDEO) {
+ if ((block+1)*TM6000_URB_MSG_LEN>linewidth)
+ cmd = TM6000_URB_MSG_ERR;
+
+ /* FIXME: Mounts the image as field0+field1
+ * It should, instead, check if the user selected
+ * entrelaced or non-entrelaced mode
+ */
+ pos= ((line<<1)+field)*linewidth +
+ block*TM6000_URB_MSG_LEN;
+
+ /* Don't allow to write out of the buffer */
+ if (pos+TM6000_URB_MSG_LEN > (*buf)->vb.size) {
+ dprintk(dev, V4L2_DEBUG_ISOC,
+ "ERR: size=%d, num=%d, line=%d, "
+ "field=%d\n",
+ size, block, line, field);
+
+ cmd = TM6000_URB_MSG_ERR;
+ }
+ } else {
+ pos=0;
+ }
+
+ /* Prints debug info */
+ dprintk(dev, V4L2_DEBUG_ISOC, "size=%d, num=%d, "
+ " line=%d, field=%d\n",
+ size, block, line, field);
+
+ if ((last_line!=line)&&(last_line+1!=line) &&
+ (cmd != TM6000_URB_MSG_ERR) ) {
+ if (cmd != TM6000_URB_MSG_VIDEO) {
+ dprintk(dev, V4L2_DEBUG_ISOC, "cmd=%d, "
+ "size=%d, num=%d, line=%d, field=%d\n",
+ cmd, size, block, line, field);
+ }
+ if (start_line<0)
+ start_line=last_line;
+ /* Prints debug info */
+ dprintk(dev, V4L2_DEBUG_ISOC, "lines= %d-%d, "
+ "field=%d\n",
+ start_line, last_line, field);
+
+ if ((start_line<6 && last_line>200) &&
+ (last_field != field) ) {
+
+ dev->isoc_ctl.nfields++;
+ if (dev->isoc_ctl.nfields>=2) {
+ dev->isoc_ctl.nfields=0;
+
+ /* Announces that a new buffer were filled */
+ buffer_filled (dev, dma_q, *buf);
+ dprintk(dev, V4L2_DEBUG_ISOC,
+ "new buffer filled\n");
+ get_next_buf (dma_q, buf);
+ if (!*buf)
+ return rc;
+ out_p = videobuf_to_vmalloc(&((*buf)->vb));
+ if (!out_p)
+ return rc;
+
+ pos = dev->isoc_ctl.pos = 0;
+ }
+ }
+
+ start_line=line;
+ last_field=field;
+ }
+ last_line=line;
+
+ pktsize = TM6000_URB_MSG_LEN;
+ } else {
+ /* Continue the last copy */
+ cmd = dev->isoc_ctl.cmd;
+ size= dev->isoc_ctl.size;
+ pos = dev->isoc_ctl.pos;
+ pktsize = dev->isoc_ctl.pktsize;
+ }
+
+ cpysize = (endp-(*ptr) > size) ? size : endp - *ptr;
+
+ if (cpysize) {
+ /* handles each different URB message */
+ switch(cmd) {
+ case TM6000_URB_MSG_VIDEO:
+ /* Fills video buffer */
+ memcpy(&out_p[pos], *ptr, cpysize);
+ break;
+ case TM6000_URB_MSG_PTS:
+ break;
+ case TM6000_URB_MSG_AUDIO:
+/* Need some code to process audio */
+printk ("%ld: cmd=%s, size=%d\n", jiffies,
+ tm6000_msg_type[cmd],size);
+ break;
+ default:
+ dprintk (dev, V4L2_DEBUG_ISOC, "cmd=%s, size=%d\n",
+ tm6000_msg_type[cmd],size);
+ }
+ }
+ if (cpysize<size) {
+ /* End of URB packet, but cmd processing is not
+ * complete. Preserve the state for a next packet
+ */
+ dev->isoc_ctl.pos = pos+cpysize;
+ dev->isoc_ctl.size= size-cpysize;
+ dev->isoc_ctl.cmd = cmd;
+ dev->isoc_ctl.pktsize = pktsize-cpysize;
+ (*ptr)+=cpysize;
+ } else {
+ dev->isoc_ctl.cmd = 0;
+ (*ptr)+=pktsize;
+ }
+
+ return rc;
+}
+
+static int copy_streams(u8 *data, u8 *out_p, unsigned long len,
+ struct urb *urb, struct tm6000_buffer **buf)
+{
+ struct tm6000_dmaqueue *dma_q = urb->context;
+ struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
+ u8 *ptr=data, *endp=data+len;
+ unsigned long header=0;
+ int rc=0;
+
+ for (ptr=data; ptr<endp;) {
+ if (!dev->isoc_ctl.cmd) {
+ u8 *p=(u8 *)&dev->isoc_ctl.tmp_buf;
+ /* FIXME: This seems very complex
+ * It just recovers up to 3 bytes of the header that
+ * might be at the previous packet
+ */
+ if (dev->isoc_ctl.tmp_buf_len) {
+ while (dev->isoc_ctl.tmp_buf_len) {
+ if ( *(ptr+3-dev->isoc_ctl.tmp_buf_len) == 0x47) {
+ break;
+ }
+ p++;
+ dev->isoc_ctl.tmp_buf_len--;
+ }
+ if (dev->isoc_ctl.tmp_buf_len) {
+ memcpy (&header,p,
+ dev->isoc_ctl.tmp_buf_len);
+ memcpy (((u8 *)header)+
+ dev->isoc_ctl.tmp_buf,
+ ptr,
+ 4-dev->isoc_ctl.tmp_buf_len);
+ ptr+=4-dev->isoc_ctl.tmp_buf_len;
+ goto HEADER;
+ }
+ }
+ /* Seek for sync */
+ for (;ptr<endp-3;ptr++) {
+ if (*(ptr+3)==0x47)
+ break;
+ }
+
+ if (ptr+3>=endp) {
+ dev->isoc_ctl.tmp_buf_len=endp-ptr;
+ memcpy (&dev->isoc_ctl.tmp_buf,ptr,
+ dev->isoc_ctl.tmp_buf_len);
+ dev->isoc_ctl.cmd=0;
+ return rc;
+ }
+
+ /* Get message header */
+ header=*(unsigned long *)ptr;
+ ptr+=4;
+ }
+HEADER:
+ /* Copy or continue last copy */
+ rc=copy_packet(urb,header,&ptr,endp,out_p,buf);
+ if (rc<0) {
+ buf=NULL;
+ printk(KERN_ERR "tm6000: buffer underrun at %ld\n",
+ jiffies);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+/*
+ * Identify the tm5600/6000 buffer header type and properly handles
+ */
+static int copy_multiplexed(u8 *ptr, u8 *out_p, unsigned long len,
+ struct urb *urb, struct tm6000_buffer **buf)
+{
+ struct tm6000_dmaqueue *dma_q = urb->context;
+ struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
+ unsigned int pos=dev->isoc_ctl.pos,cpysize;
+ int rc=1;
+
+ while (len>0) {
+ cpysize=min(len,(*buf)->vb.size-pos);
+//printk("Copying %d bytes (max=%lu) from %p to %p[%u]\n",cpysize,(*buf)->vb.size,ptr,out_p,pos);
+ memcpy(&out_p[pos], ptr, cpysize);
+ pos+=cpysize;
+ ptr+=cpysize;
+ len-=cpysize;
+ if (pos >= (*buf)->vb.size) {
+ pos=0;
+ /* Announces that a new buffer were filled */
+ buffer_filled (dev, dma_q, *buf);
+ dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n");
+ get_next_buf (dma_q, buf);
+ if (!*buf)
+ break;
+ out_p = videobuf_to_vmalloc(&((*buf)->vb));
+ if (!out_p)
+ return rc;
+ pos = 0;
+ }
+ }
+
+ dev->isoc_ctl.pos=pos;
+ return rc;
+}
+
+static void inline print_err_status (struct tm6000_core *dev,
+ int packet, int status)
+{
+ char *errmsg = "Unknown";
+
+ switch(status) {
+ case -ENOENT:
+ errmsg = "unlinked synchronuously";
+ break;
+ case -ECONNRESET:
+ errmsg = "unlinked asynchronuously";
+ break;
+ case -ENOSR:
+ errmsg = "Buffer error (overrun)";
+ break;
+ case -EPIPE:
+ errmsg = "Stalled (device not responding)";
+ break;
+ case -EOVERFLOW:
+ errmsg = "Babble (bad cable?)";
+ break;
+ case -EPROTO:
+ errmsg = "Bit-stuff error (bad cable?)";
+ break;
+ case -EILSEQ:
+ errmsg = "CRC/Timeout (could be anything)";
+ break;
+ case -ETIME:
+ errmsg = "Device does not respond";
+ break;
+ }
+ if (packet<0) {
+ dprintk(dev, V4L2_DEBUG_QUEUE, "URB status %d [%s].\n",
+ status, errmsg);
+ } else {
+ dprintk(dev, V4L2_DEBUG_QUEUE, "URB packet %d, status %d [%s].\n",
+ packet, status, errmsg);
+ }
+}
+
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static inline int tm6000_isoc_copy(struct urb *urb)
+{
+ struct tm6000_dmaqueue *dma_q = urb->context;
+ struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
+ struct tm6000_buffer *buf;
+ int i, len=0, rc=1;
+ int size;
+ char *outp = NULL, *p;
+ unsigned long copied;
+
+ get_next_buf(dma_q, &buf);
+ if (!buf)
+ outp = videobuf_to_vmalloc(&buf->vb);
+
+ if (!outp)
+ return 0;
+
+ size = buf->vb.size;
+
+ copied=0;
+
+ if (urb->status<0) {
+ print_err_status (dev,-1,urb->status);
+ return 0;
+ }
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int status = urb->iso_frame_desc[i].status;
+
+ if (status<0) {
+ print_err_status (dev,i,status);
+ continue;
+ }
+
+ len=urb->iso_frame_desc[i].actual_length;
+
+// if (len>=TM6000_URB_MSG_LEN) {
+ p=urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+ if (!urb->iso_frame_desc[i].status) {
+ if ((buf->fmt->fourcc)==V4L2_PIX_FMT_TM6000) {
+ rc=copy_multiplexed(p, outp, len, urb, &buf);
+ if (rc<=0)
+ return rc;
+ } else {
+ copy_streams(p, outp, len, urb, &buf);
+ }
+ }
+ copied += len;
+ if (copied>=size)
+ break;
+// }
+ }
+ return rc;
+}
+
+/* ------------------------------------------------------------------
+ URB control
+ ------------------------------------------------------------------*/
+
+/*
+ * IRQ callback, called by URB callback
+ */
+static void tm6000_irq_callback(struct urb *urb)
+{
+ struct tm6000_dmaqueue *dma_q = urb->context;
+ struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
+ int i;
+
+ if (!dev)
+ return;
+
+ spin_lock(&dev->slock);
+ tm6000_isoc_copy(urb);
+ spin_unlock(&dev->slock);
+
+ /* Reset urb buffers */
+ for (i = 0; i < urb->number_of_packets; i++) {
+ urb->iso_frame_desc[i].status = 0;
+ urb->iso_frame_desc[i].actual_length = 0;
+ }
+
+ urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (urb->status)
+ tm6000_err("urb resubmit failed (error=%i)\n",
+ urb->status);
+}
+
+/*
+ * Stop and Deallocate URBs
+ */
+static void tm6000_uninit_isoc(struct tm6000_core *dev)
+{
+ struct urb *urb;
+ int i;
+
+ dev->isoc_ctl.nfields = -1;
+ dev->isoc_ctl.buf = NULL;
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+ urb=dev->isoc_ctl.urb[i];
+ if (urb) {
+ usb_kill_urb(urb);
+ usb_unlink_urb(urb);
+ if (dev->isoc_ctl.transfer_buffer[i]) {
+ usb_buffer_free(dev->udev,
+ urb->transfer_buffer_length,
+ dev->isoc_ctl.transfer_buffer[i],
+ urb->transfer_dma);
+ }
+ usb_free_urb(urb);
+ dev->isoc_ctl.urb[i] = NULL;
+ }
+ dev->isoc_ctl.transfer_buffer[i] = NULL;
+ }
+
+ kfree (dev->isoc_ctl.urb);
+ kfree (dev->isoc_ctl.transfer_buffer);
+
+ dev->isoc_ctl.urb=NULL;
+ dev->isoc_ctl.transfer_buffer=NULL;
+ dev->isoc_ctl.num_bufs = 0;
+
+ dev->isoc_ctl.num_bufs=0;
+}
+
+/*
+ * Allocate URBs and start IRQ
+ */
+static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize)
+{
+ struct tm6000_dmaqueue *dma_q = &dev->vidq;
+ int i, j, sb_size, pipe, size, max_packets, num_bufs = 5;
+ struct urb *urb;
+
+ /* De-allocates all pending stuff */
+ tm6000_uninit_isoc(dev);
+
+ pipe = usb_rcvisocpipe(dev->udev,
+ dev->isoc_in->desc.bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK);
+
+ size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
+
+ if (size > dev->max_isoc_in)
+ size = dev->max_isoc_in;
+
+ dev->isoc_ctl.max_pkt_size = size;
+
+ max_packets = ( framesize + size - 1) / size;
+
+ if (max_packets > TM6000_MAX_ISO_PACKETS)
+ max_packets = TM6000_MAX_ISO_PACKETS;
+
+ sb_size = max_packets * size;
+
+ dev->isoc_ctl.num_bufs = num_bufs;
+
+ dev->isoc_ctl.urb = kmalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
+ if (!dev->isoc_ctl.urb) {
+ tm6000_err("cannot alloc memory for usb buffers\n");
+ return -ENOMEM;
+ }
+
+ dev->isoc_ctl.transfer_buffer = kmalloc(sizeof(void *)*num_bufs,
+ GFP_KERNEL);
+ if (!dev->isoc_ctl.urb) {
+ tm6000_err("cannot allocate memory for usbtransfer\n");
+ kfree(dev->isoc_ctl.urb);
+ return -ENOMEM;
+ }
+
+ dprintk(dev, V4L2_DEBUG_QUEUE, "Allocating %d x %d packets"
+ " (%d bytes) of %d bytes each to handle %u size\n",
+ max_packets, num_bufs, sb_size,
+ dev->max_isoc_in, size);
+
+
+ /* allocate urbs and transfer buffers */
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+ urb = usb_alloc_urb(max_packets, GFP_KERNEL);
+ if (!urb) {
+ tm6000_err("cannot alloc isoc_ctl.urb %i\n", i);
+ tm6000_uninit_isoc(dev);
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+ dev->isoc_ctl.urb[i] = urb;
+
+ dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->udev,
+ sb_size, GFP_KERNEL, &urb->transfer_dma);
+ if (!dev->isoc_ctl.transfer_buffer[i]) {
+ tm6000_err ("unable to allocate %i bytes for transfer"
+ " buffer %i%s\n",
+ sb_size, i,
+ in_interrupt()?" while in int":"");
+ tm6000_uninit_isoc(dev);
+ return -ENOMEM;
+ }
+ memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
+
+ usb_fill_bulk_urb(urb, dev->udev, pipe,
+ dev->isoc_ctl.transfer_buffer[i], sb_size,
+ tm6000_irq_callback, dma_q);
+ urb->interval = dev->isoc_in->desc.bInterval;
+ urb->number_of_packets = max_packets;
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+
+ for (j = 0; j < max_packets; j++) {
+ urb->iso_frame_desc[j].offset = size * j;
+ urb->iso_frame_desc[j].length = size;
+ }
+ }
+
+ return 0;
+}
+
+static int tm6000_start_thread( struct tm6000_core *dev)
+{
+ struct tm6000_dmaqueue *dma_q = &dev->vidq;
+ int i;
+
+ dma_q->frame=0;
+ dma_q->ini_jiffies=jiffies;
+
+ init_waitqueue_head(&dma_q->wq);
+
+ /* submit urbs and enables IRQ */
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+ int rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
+ if (rc) {
+ tm6000_err("submit of urb %i failed (error=%i)\n", i,
+ rc);
+ tm6000_uninit_isoc(dev);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------
+ Videobuf operations
+ ------------------------------------------------------------------*/
+
+static int
+buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+{
+ struct tm6000_fh *fh = vq->priv_data;
+
+ *size = fh->fmt->depth * fh->width * fh->height >> 3;
+ if (0 == *count)
+ *count = TM6000_DEF_BUF;
+
+ if (*count < TM6000_MIN_BUF) {
+ *count=TM6000_MIN_BUF;
+ }
+
+ while (*size * *count > vid_limit * 1024 * 1024)
+ (*count)--;
+
+ return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct tm6000_buffer *buf)
+{
+ struct tm6000_fh *fh = vq->priv_data;
+ struct tm6000_core *dev = fh->dev;
+ unsigned long flags;
+
+ if (in_interrupt())
+ BUG();
+
+ /* We used to wait for the buffer to finish here, but this didn't work
+ because, as we were keeping the state as VIDEOBUF_QUEUED,
+ videobuf_queue_cancel marked it as finished for us.
+ (Also, it could wedge forever if the hardware was misconfigured.)
+
+ This should be safe; by the time we get here, the buffer isn't
+ queued anymore. If we ever start marking the buffers as
+ VIDEOBUF_ACTIVE, it won't be, though.
+ */
+ spin_lock_irqsave(&dev->slock, flags);
+ if (dev->isoc_ctl.buf == buf)
+ dev->isoc_ctl.buf = NULL;
+ spin_unlock_irqrestore(&dev->slock, flags);
+
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct tm6000_fh *fh = vq->priv_data;
+ struct tm6000_buffer *buf = container_of(vb,struct tm6000_buffer,vb);
+ struct tm6000_core *dev = fh->dev;
+ int rc = 0, urb_init = 0;
+
+ BUG_ON(NULL == fh->fmt);
+
+
+ /* FIXME: It assumes depth=2 */
+ /* The only currently supported format is 16 bits/pixel */
+ buf->vb.size = fh->fmt->depth*fh->width*fh->height >> 3;
+ if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ return -EINVAL;
+
+ if (buf->fmt != fh->fmt ||
+ buf->vb.width != fh->width ||
+ buf->vb.height != fh->height ||
+ buf->vb.field != field) {
+ buf->fmt = fh->fmt;
+ buf->vb.width = fh->width;
+ buf->vb.height = fh->height;
+ buf->vb.field = field;
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+ }
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ if (0 != (rc = videobuf_iolock(vq, &buf->vb, NULL)))
+ goto fail;
+ urb_init = 1;
+ }
+
+ if (!dev->isoc_ctl.num_bufs)
+ urb_init = 1;
+
+ if (urb_init) {
+ rc = tm6000_prepare_isoc(dev, buf->vb.size);
+ if (rc < 0)
+ goto fail;
+
+ rc = tm6000_start_thread(dev);
+ if (rc < 0)
+ goto fail;
+
+ }
+
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+
+fail:
+ free_buffer(vq, buf);
+ return rc;
+}
+
+static void
+buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct tm6000_buffer *buf = container_of(vb,struct tm6000_buffer,vb);
+ struct tm6000_fh *fh = vq->priv_data;
+ struct tm6000_core *dev = fh->dev;
+ struct tm6000_dmaqueue *vidq = &dev->vidq;
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vidq->active);
+}
+
+static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct tm6000_buffer *buf = container_of(vb,struct tm6000_buffer,vb);
+
+ free_buffer(vq,buf);
+}
+
+static struct videobuf_queue_ops tm6000_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/* ------------------------------------------------------------------
+ IOCTL handling
+ ------------------------------------------------------------------*/
+
+static int res_get(struct tm6000_core *dev, struct tm6000_fh *fh)
+{
+ /* is it free? */
+ mutex_lock(&dev->lock);
+ if (dev->resources) {
+ /* no, someone else uses it */
+ mutex_unlock(&dev->lock);
+ return 0;
+ }
+ /* it's free, grab it */
+ dev->resources =1;
+ dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n");
+ mutex_unlock(&dev->lock);
+ return 1;
+}
+
+static int res_locked(struct tm6000_core *dev)
+{
+ return (dev->resources);
+}
+
+static void res_free(struct tm6000_core *dev, struct tm6000_fh *fh)
+{
+ mutex_lock(&dev->lock);
+ dev->resources = 0;
+ dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: put\n");
+ mutex_unlock(&dev->lock);
+}
+
+/* ------------------------------------------------------------------
+ IOCTL vidioc handling
+ ------------------------------------------------------------------*/
+static int vidioc_querycap (struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ // struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
+
+ strlcpy(cap->driver, "tm6000", sizeof(cap->driver));
+ strlcpy(cap->card,"Trident TVMaster TM5600/6000", sizeof(cap->card));
+ // strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info));
+ cap->version = TM6000_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_TUNER |
+ V4L2_CAP_READWRITE;
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (unlikely(f->index >= ARRAY_SIZE(format)))
+ return -EINVAL;
+
+ strlcpy(f->description,format[f->index].name,sizeof(f->description));
+ f->pixelformat = format[f->index].fourcc;
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct tm6000_fh *fh=priv;
+
+ f->fmt.pix.width = fh->width;
+ f->fmt.pix.height = fh->height;
+ f->fmt.pix.field = fh->vb_vidq.field;
+ f->fmt.pix.pixelformat = fh->fmt->fourcc;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fh->fmt->depth) >> 3;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+ return (0);
+}
+
+static struct tm6000_fmt* format_by_fourcc(unsigned int fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(format); i++)
+ if (format[i].fourcc == fourcc)
+ return format+i;
+ return NULL;
+}
+
+static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
+ struct tm6000_fmt *fmt;
+ enum v4l2_field field;
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (NULL == fmt) {
+ dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Fourcc format (0x%08x)"
+ " invalid.\n", f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ field = f->fmt.pix.field;
+
+ if (field == V4L2_FIELD_ANY) {
+// field=V4L2_FIELD_INTERLACED;
+ field=V4L2_FIELD_SEQ_TB;
+ } else if (V4L2_FIELD_INTERLACED != field) {
+ dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Field type invalid.\n");
+ return -EINVAL;
+ }
+
+ tm6000_get_std_res (dev);
+
+ f->fmt.pix.width = dev->width;
+ f->fmt.pix.height = dev->height;
+
+ f->fmt.pix.width &= ~0x01;
+
+ f->fmt.pix.field = field;
+
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fmt->depth) >> 3;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+ return 0;
+}
+
+/*FIXME: This seems to be generic enough to be at videodev2 */
+static int vidioc_s_fmt_vid_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct tm6000_fh *fh=priv;
+ struct tm6000_core *dev = fh->dev;
+ int ret = vidioc_try_fmt_vid_cap(file,fh,f);
+ if (ret < 0)
+ return (ret);
+
+ fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ fh->width = f->fmt.pix.width;
+ fh->height = f->fmt.pix.height;
+ fh->vb_vidq.field = f->fmt.pix.field;
+ fh->type = f->type;
+
+ dev->fourcc = f->fmt.pix.pixelformat;
+
+ tm6000_set_fourcc_format(dev);
+
+ return (0);
+}
+
+static int vidioc_reqbufs (struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ struct tm6000_fh *fh=priv;
+
+ return (videobuf_reqbufs(&fh->vb_vidq, p));
+}
+
+static int vidioc_querybuf (struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct tm6000_fh *fh=priv;
+
+ return (videobuf_querybuf(&fh->vb_vidq, p));
+}
+
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct tm6000_fh *fh=priv;
+
+ return (videobuf_qbuf(&fh->vb_vidq, p));
+}
+
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct tm6000_fh *fh=priv;
+
+ return (videobuf_dqbuf(&fh->vb_vidq, p,
+ file->f_flags & O_NONBLOCK));
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+ struct tm6000_fh *fh=priv;
+
+ return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8);
+}
+#endif
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct tm6000_fh *fh=priv;
+ struct tm6000_core *dev = fh->dev;
+
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (i != fh->type)
+ return -EINVAL;
+
+ if (!res_get(dev,fh))
+ return -EBUSY;
+ return (videobuf_streamon(&fh->vb_vidq));
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct tm6000_fh *fh=priv;
+ struct tm6000_core *dev = fh->dev;
+
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (i != fh->type)
+ return -EINVAL;
+
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(dev,fh);
+
+ return (0);
+}
+
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *norm)
+{
+ int rc=0;
+ struct tm6000_fh *fh=priv;
+ struct tm6000_core *dev = fh->dev;
+
+ rc=tm6000_set_standard (dev, norm);
+
+ fh->width = dev->width;
+ fh->height = dev->height;
+
+ if (rc<0)
+ return rc;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
+
+ return 0;
+}
+
+static int vidioc_enum_input (struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ switch (inp->index) {
+ case TM6000_INPUT_TV:
+ inp->type = V4L2_INPUT_TYPE_TUNER;
+ strcpy(inp->name,"Television");
+ break;
+ case TM6000_INPUT_COMPOSITE:
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ strcpy(inp->name,"Composite");
+ break;
+ case TM6000_INPUT_SVIDEO:
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ strcpy(inp->name,"S-Video");
+ break;
+ default:
+ return -EINVAL;
+ }
+ inp->std = TM6000_STD;
+
+ return 0;
+}
+
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+{
+ struct tm6000_fh *fh=priv;
+ struct tm6000_core *dev = fh->dev;
+
+ *i=dev->input;
+
+ return 0;
+}
+static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+{
+ struct tm6000_fh *fh=priv;
+ struct tm6000_core *dev = fh->dev;
+ int rc=0;
+ char buf[1];
+
+ switch (i) {
+ case TM6000_INPUT_TV:
+ dev->input=i;
+ *buf=0;
+ break;
+ case TM6000_INPUT_COMPOSITE:
+ case TM6000_INPUT_SVIDEO:
+ dev->input=i;
+ *buf=1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ rc=tm6000_read_write_usb (dev, USB_DIR_OUT | USB_TYPE_VENDOR,
+ REQ_03_SET_GET_MCU_PIN, 0x03, 1, buf, 1);
+
+ if (!rc) {
+ dev->input=i;
+ rc=vidioc_s_std (file, priv, &dev->vfd->current_norm);
+ }
+
+ return (rc);
+}
+
+ /* --- controls ---------------------------------------------- */
+static int vidioc_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
+ if (qc->id && qc->id == tm6000_qctrl[i].id) {
+ memcpy(qc, &(tm6000_qctrl[i]),
+ sizeof(*qc));
+ return (0);
+ }
+
+ return -EINVAL;
+}
+
+static int vidioc_g_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct tm6000_fh *fh=priv;
+ struct tm6000_core *dev = fh->dev;
+ int val;
+
+ /* FIXME: Probably, those won't work! Maybe we need shadow regs */
+ switch (ctrl->id) {
+ case V4L2_CID_CONTRAST:
+ val=tm6000_get_reg (dev, REQ_07_SET_GET_AVREG, 0x08, 0);
+ break;
+ case V4L2_CID_BRIGHTNESS:
+ val=tm6000_get_reg (dev, REQ_07_SET_GET_AVREG, 0x09, 0);
+ return 0;
+ case V4L2_CID_SATURATION:
+ val=tm6000_get_reg (dev, REQ_07_SET_GET_AVREG, 0x0a, 0);
+ return 0;
+ case V4L2_CID_HUE:
+ val=tm6000_get_reg (dev, REQ_07_SET_GET_AVREG, 0x0b, 0);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ if (val<0)
+ return val;
+
+ ctrl->value=val;
+
+ return 0;
+}
+static int vidioc_s_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct tm6000_fh *fh =priv;
+ struct tm6000_core *dev = fh->dev;
+ u8 val=ctrl->value;
+
+ switch (ctrl->id) {
+ case V4L2_CID_CONTRAST:
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x08, val);
+ return 0;
+ case V4L2_CID_BRIGHTNESS:
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x09, val);
+ return 0;
+ case V4L2_CID_SATURATION:
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x0a, val);
+ return 0;
+ case V4L2_CID_HUE:
+ tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x0b, val);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int vidioc_g_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct tm6000_fh *fh =priv;
+ struct tm6000_core *dev = fh->dev;
+
+ if (unlikely(UNSET == dev->tuner_type))
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
+
+ strcpy(t->name, "Television");
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM;
+ t->rangehigh = 0xffffffffUL;
+ t->rxsubchans = V4L2_TUNER_SUB_MONO;
+
+ return 0;
+}
+
+static int vidioc_s_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct tm6000_fh *fh =priv;
+ struct tm6000_core *dev = fh->dev;
+
+ if (UNSET == dev->tuner_type)
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vidioc_g_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct tm6000_fh *fh =priv;
+ struct tm6000_core *dev = fh->dev;
+
+ if (unlikely(UNSET == dev->tuner_type))
+ return -EINVAL;
+
+ f->type = V4L2_TUNER_ANALOG_TV;
+ f->frequency = dev->freq;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f);
+
+ return 0;
+}
+
+static int vidioc_s_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct tm6000_fh *fh =priv;
+ struct tm6000_core *dev = fh->dev;
+
+ if (unlikely(f->type != V4L2_TUNER_ANALOG_TV))
+ return -EINVAL;
+
+ if (unlikely(UNSET == dev->tuner_type))
+ return -EINVAL;
+ if (unlikely(f->tuner != 0))
+ return -EINVAL;
+
+// mutex_lock(&dev->lock);
+ dev->freq = f->frequency;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
+// mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------
+ File operations for the device
+ ------------------------------------------------------------------*/
+
+static int tm6000_open(struct file *file)
+{
+ int minor = video_devdata(file)->minor;
+ struct tm6000_core *h,*dev = NULL;
+ struct tm6000_fh *fh;
+ struct list_head *list;
+ enum v4l2_buf_type type = 0;
+ int i,rc;
+
+ printk(KERN_INFO "tm6000: open called (minor=%d)\n",minor);
+
+
+ dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: open called "
+ "(minor=%d)\n",minor);
+
+ list_for_each(list,&tm6000_corelist) {
+ h = list_entry(list, struct tm6000_core, tm6000_corelist);
+ if (h->vfd->minor == minor) {
+ dev = h;
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ }
+ }
+ if (NULL == dev)
+ return -ENODEV;
+
+
+ /* If more than one user, mutex should be added */
+ dev->users++;
+
+ dprintk(dev, V4L2_DEBUG_OPEN, "open minor=%d type=%s users=%d\n",
+ minor,v4l2_type_names[type],dev->users);
+
+ /* allocate + initialize per filehandle data */
+ fh = kzalloc(sizeof(*fh),GFP_KERNEL);
+ if (NULL == fh) {
+ dev->users--;
+ return -ENOMEM;
+ }
+
+ file->private_data = fh;
+ fh->dev = dev;
+
+ fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dev->fourcc = format[0].fourcc;
+
+ fh->fmt = format_by_fourcc(dev->fourcc);
+
+ tm6000_get_std_res (dev);
+
+ fh->width = dev->width;
+ fh->height = dev->height;
+
+ dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=0x%08lx, dev=0x%08lx, "
+ "dev->vidq=0x%08lx\n",
+ (unsigned long)fh,(unsigned long)dev,(unsigned long)&dev->vidq);
+ dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty "
+ "queued=%d\n",list_empty(&dev->vidq.queued));
+ dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty "
+ "active=%d\n",list_empty(&dev->vidq.active));
+
+ /* initialize hardware on analog mode */
+ if (dev->mode!=TM6000_MODE_ANALOG) {
+ rc=tm6000_init_analog_mode (dev);
+ if (rc<0)
+ return rc;
+
+ /* Put all controls at a sane state */
+ for (i = 0; i < ARRAY_SIZE(tm6000_qctrl); i++)
+ qctl_regs[i] =tm6000_qctrl[i].default_value;
+
+ dev->mode=TM6000_MODE_ANALOG;
+ }
+
+ videobuf_queue_vmalloc_init(&fh->vb_vidq, &tm6000_video_qops,
+ NULL, &dev->slock,
+ fh->type,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct tm6000_buffer),fh);
+
+ return 0;
+}
+
+static ssize_t
+tm6000_read(struct file *file, char __user *data, size_t count, loff_t *pos)
+{
+ struct tm6000_fh *fh = file->private_data;
+
+ if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (res_locked(fh->dev))
+ return -EBUSY;
+
+ return videobuf_read_stream(&fh->vb_vidq, data, count, pos, 0,
+ file->f_flags & O_NONBLOCK);
+ }
+ return 0;
+}
+
+static unsigned int
+tm6000_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct tm6000_fh *fh = file->private_data;
+ struct tm6000_buffer *buf;
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+ return POLLERR;
+
+ if (res_get(fh->dev,fh)) {
+ /* streaming capture */
+ if (list_empty(&fh->vb_vidq.stream))
+ return POLLERR;
+ buf = list_entry(fh->vb_vidq.stream.next,struct tm6000_buffer,vb.stream);
+ } else {
+ /* read() capture */
+ return videobuf_poll_stream(file, &fh->vb_vidq,
+ wait);
+ }
+ poll_wait(file, &buf->vb.done, wait);
+ if (buf->vb.state == VIDEOBUF_DONE ||
+ buf->vb.state == VIDEOBUF_ERROR)
+ return POLLIN|POLLRDNORM;
+ return 0;
+}
+
+static int tm6000_release(struct file *file)
+{
+ struct tm6000_fh *fh = file->private_data;
+ struct tm6000_core *dev = fh->dev;
+ int minor = video_devdata(file)->minor;
+
+ dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: close called (minor=%d, users=%d)\n",minor,dev->users);
+
+ dev->users--;
+
+ if (!dev->users) {
+ tm6000_uninit_isoc(dev);
+ videobuf_mmap_free(&fh->vb_vidq);
+ }
+
+ kfree (fh);
+
+ return 0;
+}
+
+static int tm6000_mmap(struct file *file, struct vm_area_struct * vma)
+{
+ struct tm6000_fh *fh = file->private_data;
+ int ret;
+
+ ret=videobuf_mmap_mapper(&fh->vb_vidq, vma);
+
+ return ret;
+}
+
+static struct v4l2_file_operations tm6000_fops = {
+ .owner = THIS_MODULE,
+ .open = tm6000_open,
+ .release = tm6000_release,
+ .ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .read = tm6000_read,
+ .poll = tm6000_poll,
+ .mmap = tm6000_mmap,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ .vidiocgmbuf = vidiocgmbuf,
+#endif
+};
+
+static struct video_device tm6000_template = {
+ .name = "tm6000",
+ .fops = &tm6000_fops,
+ .ioctl_ops = &video_ioctl_ops,
+ .minor = -1,
+ .release = video_device_release,
+ .tvnorms = TM6000_STD,
+ .current_norm = V4L2_STD_NTSC_M,
+};
+
+/* -----------------------------------------------------------------
+ Initialization and module stuff
+ ------------------------------------------------------------------*/
+
+int tm6000_v4l2_register(struct tm6000_core *dev)
+{
+ int ret = -1;
+ struct video_device *vfd;
+
+ vfd = video_device_alloc();
+ if(!vfd) {
+ return -ENOMEM;
+ }
+ dev->vfd = vfd;
+
+ list_add_tail(&dev->tm6000_corelist,&tm6000_corelist);
+
+ /* init video dma queues */
+ INIT_LIST_HEAD(&dev->vidq.active);
+ INIT_LIST_HEAD(&dev->vidq.queued);
+
+ memcpy (dev->vfd, &tm6000_template, sizeof(*(dev->vfd)));
+ dev->vfd->debug=tm6000_debug;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+
+ ret = video_register_device(dev->vfd, VFL_TYPE_GRABBER, video_nr);
+ printk(KERN_INFO "Trident TVMaster TM5600/TM6000 USB2 board (Load status: %d)\n", ret);
+ return ret;
+}
+
+int tm6000_v4l2_unregister(struct tm6000_core *dev)
+{
+ struct tm6000_core *h;
+ struct list_head *pos, *tmp;
+
+ video_unregister_device(dev->vfd);
+
+ list_for_each_safe(pos, tmp, &tm6000_corelist) {
+ h = list_entry(pos, struct tm6000_core, tm6000_corelist);
+ if (h == dev) {
+ list_del(pos);
+ }
+ }
+
+ return 0;
+}
+
+int tm6000_v4l2_exit(void)
+{
+ return 0;
+}
+
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr,"Allow changing video device number");
+
+module_param_named (debug, tm6000_debug, int, 0444);
+MODULE_PARM_DESC(debug,"activates debug info");
+
+module_param(vid_limit,int,0644);
+MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
+
diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h
new file mode 100644
index 000000000000..54dbdb91c52f
--- /dev/null
+++ b/drivers/staging/tm6000/tm6000.h
@@ -0,0 +1,279 @@
+/*
+ tm6000.h - driver for TM5600/TM6000 USB video capture devices
+
+ Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+
+ Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
+ - DVB-T 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 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. 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.
+ */
+
+// Use the tm6000-hack, instead of the proper initialization code
+//#define HACK 1
+
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/videobuf-vmalloc.h>
+#include "tm6000-usb-isoc.h"
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <media/v4l2-device.h>
+
+
+#include <linux/dvb/frontend.h>
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dmxdev.h"
+
+#define TM6000_VERSION KERNEL_VERSION(0, 0, 1)
+
+/* Inputs */
+
+enum tm6000_itype {
+ TM6000_INPUT_TV = 0,
+ TM6000_INPUT_COMPOSITE,
+ TM6000_INPUT_SVIDEO,
+};
+
+enum tm6000_devtype {
+ TM6000 = 0,
+ TM5600,
+ TM6010,
+};
+
+/* ------------------------------------------------------------------
+ Basic structures
+ ------------------------------------------------------------------*/
+
+struct tm6000_fmt {
+ char *name;
+ u32 fourcc; /* v4l2 format id */
+ int depth;
+};
+
+/* buffer for one video frame */
+struct tm6000_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+
+ struct tm6000_fmt *fmt;
+};
+
+struct tm6000_dmaqueue {
+ struct list_head active;
+ struct list_head queued;
+
+ /* thread for generating video stream*/
+ struct task_struct *kthread;
+ wait_queue_head_t wq;
+ /* Counters to control fps rate */
+ int frame;
+ int ini_jiffies;
+};
+
+/* device states */
+enum tm6000_core_state {
+ DEV_INITIALIZED = 0x01,
+ DEV_DISCONNECTED = 0x02,
+ DEV_MISCONFIGURED = 0x04,
+};
+
+/* io methods */
+enum tm6000_io_method {
+ IO_NONE,
+ IO_READ,
+ IO_MMAP,
+};
+
+enum tm6000_mode {
+ TM6000_MODE_UNKNOWN=0,
+ TM6000_MODE_ANALOG,
+ TM6000_MODE_DIGITAL,
+};
+
+struct tm6000_capabilities {
+ unsigned int has_tuner:1;
+ unsigned int has_tda9874:1;
+ unsigned int has_dvb:1;
+ unsigned int has_zl10353:1;
+ unsigned int has_eeprom:1;
+ unsigned int has_remote:1;
+};
+
+struct tm6000_dvb {
+ struct dvb_adapter adapter;
+ struct dvb_demux demux;
+ struct dvb_frontend *frontend;
+ struct dmxdev dmxdev;
+ unsigned int streams;
+ struct urb *bulk_urb;
+ struct mutex mutex;
+};
+
+struct tm6000_core {
+ /* generic device properties */
+ char name[30]; /* name (including minor) of the device */
+ int model; /* index in the device_data struct */
+ int devno; /* marks the number of this device */
+ enum tm6000_devtype dev_type; /* type of device */
+
+ v4l2_std_id norm; /* Current norm */
+ int width,height; /* Selected resolution */
+
+ enum tm6000_core_state state;
+
+ /* Device Capabilities*/
+ struct tm6000_capabilities caps;
+
+ /* Tuner configuration */
+ int tuner_type; /* type of the tuner */
+ int tuner_addr; /* tuner address */
+ int tuner_reset_gpio; /* GPIO used for tuner reset */
+
+ /* Demodulator configuration */
+ int demod_addr; /* demodulator address */
+
+ int audio_bitrate;
+ /* i2c i/o */
+ struct i2c_adapter i2c_adap;
+ struct i2c_client i2c_client;
+
+ /* video for linux */
+ struct list_head tm6000_corelist;
+ int users;
+
+ /* various device info */
+ unsigned int resources;
+ struct video_device *vfd;
+ struct tm6000_dmaqueue vidq;
+ struct v4l2_device v4l2_dev;
+
+ int input;
+ int freq;
+ unsigned int fourcc;
+
+ enum tm6000_mode mode;
+
+ /* DVB-T support */
+ struct tm6000_dvb *dvb;
+
+ /* locks */
+ struct mutex lock;
+
+ /* usb transfer */
+ struct usb_device *udev; /* the usb device */
+
+ struct usb_host_endpoint *bulk_in, *bulk_out, *isoc_in, *isoc_out;
+ unsigned int max_bulk_in, max_bulk_out;
+ unsigned int max_isoc_in, max_isoc_out;
+
+ /* scaler!=0 if scaler is active*/
+ int scaler;
+
+ /* Isoc control struct */
+ struct usb_isoc_ctl isoc_ctl;
+
+ spinlock_t slock;
+};
+
+struct tm6000_fh {
+ struct tm6000_core *dev;
+
+ /* video capture */
+ struct tm6000_fmt *fmt;
+ unsigned int width,height;
+ struct videobuf_queue vb_vidq;
+
+ enum v4l2_buf_type type;
+};
+
+#define TM6000_STD V4L2_STD_PAL|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc| \
+ V4L2_STD_PAL_M|V4L2_STD_PAL_60|V4L2_STD_NTSC_M| \
+ V4L2_STD_NTSC_M_JP|V4L2_STD_SECAM
+
+/* In tm6000-core.c */
+
+int tm6000_read_write_usb (struct tm6000_core *dev, u8 reqtype, u8 req,
+ u16 value, u16 index, u8 *buf, u16 len);
+int tm6000_get_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index);
+int tm6000_set_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index);
+int tm6000_init (struct tm6000_core *dev);
+int tm6000_init_after_firmware (struct tm6000_core *dev);
+
+int tm6000_init_analog_mode (struct tm6000_core *dev);
+int tm6000_init_digital_mode (struct tm6000_core *dev);
+int tm6000_set_audio_bitrate (struct tm6000_core *dev, int bitrate);
+
+int tm6000_dvb_register(struct tm6000_core *dev);
+void tm6000_dvb_unregister(struct tm6000_core *dev);
+
+int tm6000_v4l2_register(struct tm6000_core *dev);
+int tm6000_v4l2_unregister(struct tm6000_core *dev);
+int tm6000_v4l2_exit(void);
+void tm6000_set_fourcc_format(struct tm6000_core *dev);
+
+/* In tm6000-stds.c */
+void tm6000_get_std_res(struct tm6000_core *dev);
+int tm6000_set_standard (struct tm6000_core *dev, v4l2_std_id *norm);
+
+/* In tm6000-i2c.c */
+int tm6000_i2c_register(struct tm6000_core *dev);
+int tm6000_i2c_unregister(struct tm6000_core *dev);
+
+/* In tm6000-queue.c */
+
+int tm6000_v4l2_mmap(struct file *filp, struct vm_area_struct *vma);
+
+int tm6000_vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type i);
+int tm6000_vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type i);
+int tm6000_vidioc_reqbufs (struct file *file, void *priv,
+ struct v4l2_requestbuffers *rb);
+int tm6000_vidioc_querybuf (struct file *file, void *priv,
+ struct v4l2_buffer *b);
+int tm6000_vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *b);
+int tm6000_vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *b);
+ssize_t tm6000_v4l2_read(struct file *filp, char __user * buf, size_t count,
+ loff_t * f_pos);
+unsigned int tm6000_v4l2_poll(struct file *file,
+ struct poll_table_struct *wait);
+int tm6000_queue_init(struct tm6000_core *dev);
+
+/* In tm6000-alsa.c */
+int tm6000_audio_init(struct tm6000_core *dev, int idx);
+
+
+/* Debug stuff */
+
+extern int tm6000_debug;
+
+#define dprintk(dev, level, fmt, arg...) do {\
+ if (tm6000_debug & level) \
+ printk(KERN_INFO "(%lu) %s %s :"fmt, jiffies, \
+ dev->name, __FUNCTION__ , ##arg); } while (0)
+
+#define V4L2_DEBUG_REG 0x0004
+#define V4L2_DEBUG_I2C 0x0008
+#define V4L2_DEBUG_QUEUE 0x0010
+#define V4L2_DEBUG_ISOC 0x0020
+#define V4L2_DEBUG_RES_LOCK 0x0040 /* Resource locking */
+#define V4L2_DEBUG_OPEN 0x0080 /* video open/close debug */
+
+#define tm6000_err(fmt, arg...) do {\
+ printk(KERN_ERR "tm6000 %s :"fmt, \
+ __FUNCTION__ , ##arg); } while (0)
+
+
diff --git a/drivers/staging/vt6655/Kconfig b/drivers/staging/vt6655/Kconfig
index 9bec95adcce2..825bbc4fc3fa 100644
--- a/drivers/staging/vt6655/Kconfig
+++ b/drivers/staging/vt6655/Kconfig
@@ -1,6 +1,8 @@
config VT6655
tristate "VIA Technologies VT6655 support"
- depends on WIRELESS_EXT && PCI
+ depends on PCI
+ select WIRELESS_EXT
+ select WEXT_PRIV
---help---
This is a vendor-written driver for VIA VT6655.
diff --git a/drivers/staging/vt6656/Kconfig b/drivers/staging/vt6656/Kconfig
index 3165f2c42079..87bcd269310c 100644
--- a/drivers/staging/vt6656/Kconfig
+++ b/drivers/staging/vt6656/Kconfig
@@ -1,6 +1,8 @@
config VT6656
tristate "VIA Technologies VT6656 support"
- depends on WIRELESS_EXT && USB
+ depends on USB
+ select WIRELESS_EXT
+ select WEXT_PRIV
---help---
This is a vendor-written driver for VIA VT6656.
diff --git a/drivers/staging/wavelan/Kconfig b/drivers/staging/wavelan/Kconfig
index ff349cd1df61..786060e025c0 100644
--- a/drivers/staging/wavelan/Kconfig
+++ b/drivers/staging/wavelan/Kconfig
@@ -2,6 +2,8 @@ config WAVELAN
tristate "AT&T/Lucent old WaveLAN & DEC RoamAbout DS ISA support"
depends on ISA
select WIRELESS_EXT
+ select WEXT_SPY
+ select WEXT_PRIV
---help---
The Lucent WaveLAN (formerly NCR and AT&T; or DEC RoamAbout DS) is
a Radio LAN (wireless Ethernet-like Local Area Network) using the
@@ -25,6 +27,8 @@ config PCMCIA_WAVELAN
tristate "AT&T/Lucent old WaveLAN Pcmcia wireless support"
depends on PCMCIA
select WIRELESS_EXT
+ select WEXT_SPY
+ select WEXT_PRIV
help
Say Y here if you intend to attach an AT&T/Lucent Wavelan PCMCIA
(PC-card) wireless Ethernet networking card to your computer. This
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 33351312327f..a18e3c5dd82e 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -223,6 +223,7 @@ config USB_OTG
config USB_GADGET_PXA25X
boolean "PXA 25x or IXP 4xx"
depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
+ select USB_OTG_UTILS
help
Intel's PXA 25x series XScale ARM-5TE processors include
an integrated full speed USB 1.1 device controller. The
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 1e6aa504d58a..5e14dbaf65bc 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -1713,7 +1713,7 @@ static int do_write(struct fsg_dev *fsg)
}
if (fsg->cmnd[1] & 0x08) { // FUA
spin_lock(&curlun->filp->f_lock);
- curlun->filp->f_flags |= O_SYNC;
+ curlun->filp->f_flags |= O_DSYNC;
spin_unlock(&curlun->filp->f_lock);
}
}
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index a2db0e174f2c..b836efe9ea71 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -52,9 +52,9 @@
#include <asm/unaligned.h>
#include <asm/mach-types.h>
-#include <mach/dma.h>
-#include <mach/usb.h>
-#include <mach/control.h>
+#include <plat/dma.h>
+#include <plat/usb.h>
+#include <plat/control.h>
#include "omap_udc.h"
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index a7649b586a92..cc4cd28f1bfc 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -209,7 +209,7 @@ static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
if (error) {
ehci_halt(ehci);
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
- ehci_err(ehci, "force halt; handhake %p %08x %08x -> %d\n",
+ ehci_err(ehci, "force halt; handshake %p %08x %08x -> %d\n",
ptr, mask, done, error);
}
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 83cbecd2a1ed..5645f70b9214 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -24,10 +24,10 @@
#include <asm/io.h>
#include <asm/mach-types.h>
-#include <mach/mux.h>
+#include <plat/mux.h>
#include <mach/irqs.h>
-#include <mach/fpga.h>
-#include <mach/usb.h>
+#include <plat/fpga.h>
+#include <plat/usb.h>
/* OMAP-1510 OHCI has its own MMU for DMA */
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 34875201ee04..6761d2088db8 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -35,7 +35,7 @@
#include <asm/mach-types.h>
#include <mach/hardware.h>
-#include <mach/mux.h>
+#include <plat/mux.h>
#include "musb_core.h"
#include "omap2430.h"
diff --git a/drivers/usb/musb/omap2430.h b/drivers/usb/musb/omap2430.h
index dc7670718cd2..fbede7798aed 100644
--- a/drivers/usb/musb/omap2430.h
+++ b/drivers/usb/musb/omap2430.h
@@ -12,7 +12,7 @@
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
#include <mach/hardware.h>
-#include <mach/usb.h>
+#include <plat/usb.h>
/*
* OMAP2430-specific definitions
diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c
index 7e073a0d7ac9..e13c77052e5e 100644
--- a/drivers/usb/musb/tusb6010_omap.c
+++ b/drivers/usb/musb/tusb6010_omap.c
@@ -15,8 +15,8 @@
#include <linux/usb.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
-#include <mach/dma.h>
-#include <mach/mux.h>
+#include <plat/dma.h>
+#include <plat/mux.h>
#include "musb_core.h"
diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/otg/isp1301_omap.c
index 77a5f4188999..d54460a88173 100644
--- a/drivers/usb/otg/isp1301_omap.c
+++ b/drivers/usb/otg/isp1301_omap.c
@@ -36,8 +36,8 @@
#include <asm/irq.h>
#include <asm/mach-types.h>
-#include <mach/usb.h>
-#include <mach/mux.h>
+#include <plat/usb.h>
+#include <plat/mux.h>
#ifndef DEBUG
diff --git a/drivers/uwb/neh.c b/drivers/uwb/neh.c
index 0af8916d9bef..78510a1f410d 100644
--- a/drivers/uwb/neh.c
+++ b/drivers/uwb/neh.c
@@ -150,7 +150,7 @@ void uwb_rc_neh_put(struct uwb_rc_neh *neh)
* 0xff is invalid, so they must not be used. Initialization
* fills up those two in the bitmap so they are not allocated.
*
- * We spread the allocation around to reduce the posiblity of two
+ * We spread the allocation around to reduce the possibility of two
* consecutive opened @neh's getting the same context ID assigned (to
* avoid surprises with late events that timed out long time ago). So
* first we search from where @rc->ctx_roll is, if not found, we
diff --git a/drivers/vbus/Kconfig b/drivers/vbus/Kconfig
new file mode 100644
index 000000000000..f51cba10913e
--- /dev/null
+++ b/drivers/vbus/Kconfig
@@ -0,0 +1,25 @@
+#
+# Virtual-Bus (VBus) driver configuration
+#
+
+config VBUS_PROXY
+ bool "Virtual-Bus support"
+ select SHM_SIGNAL
+ select IOQ
+ default n
+ help
+ Adds support for a virtual-bus model drivers in a guest to connect
+ to host side virtual-bus resources. If you are using this kernel
+ in a virtualization solution which implements virtual-bus devices
+ on the backend, say Y. If unsure, say N.
+
+config VBUS_PCIBRIDGE
+ bool "PCI to Virtual-Bus bridge"
+ depends on PCI
+ depends on VBUS_PROXY
+ select IOQ
+ default n
+ help
+ Provides a way to bridge host side vbus devices via a PCI-BRIDGE
+ object. If you are running virtualization with vbus devices on the
+ host, and the vbus is exposed via PCI, say Y. Otherwise, say N.
diff --git a/drivers/vbus/Makefile b/drivers/vbus/Makefile
new file mode 100644
index 000000000000..944b7f1fec90
--- /dev/null
+++ b/drivers/vbus/Makefile
@@ -0,0 +1,6 @@
+
+vbus-proxy-objs += bus-proxy.o
+obj-$(CONFIG_VBUS_PROXY) += vbus-proxy.o
+
+vbus-pcibridge-objs += pci-bridge.o
+obj-$(CONFIG_VBUS_PCIBRIDGE) += vbus-pcibridge.o
diff --git a/drivers/vbus/bus-proxy.c b/drivers/vbus/bus-proxy.c
new file mode 100644
index 000000000000..5d349427661a
--- /dev/null
+++ b/drivers/vbus/bus-proxy.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2009 Novell. All Rights Reserved.
+ *
+ * Author:
+ * Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file 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 St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/vbus_driver.h>
+
+MODULE_AUTHOR("Gregory Haskins");
+MODULE_LICENSE("GPL");
+
+#define VBUS_PROXY_NAME "vbus-proxy"
+
+static struct vbus_device_proxy *to_dev(struct device *_dev)
+{
+ return _dev ? container_of(_dev, struct vbus_device_proxy, dev) : NULL;
+}
+
+static struct vbus_driver *to_drv(struct device_driver *_drv)
+{
+ return container_of(_drv, struct vbus_driver, drv);
+}
+
+/*
+ * This function is invoked whenever a new driver and/or device is added
+ * to check if there is a match
+ */
+static int vbus_dev_proxy_match(struct device *_dev, struct device_driver *_drv)
+{
+ struct vbus_device_proxy *dev = to_dev(_dev);
+ struct vbus_driver *drv = to_drv(_drv);
+
+ return !strcmp(dev->type, drv->type);
+}
+
+/*
+ * This function is invoked after the bus infrastructure has already made a
+ * match. The device will contain a reference to the paired driver which
+ * we will extract.
+ */
+static int vbus_dev_proxy_probe(struct device *_dev)
+{
+ int ret = 0;
+ struct vbus_device_proxy *dev = to_dev(_dev);
+ struct vbus_driver *drv = to_drv(_dev->driver);
+
+ if (drv->ops->probe)
+ ret = drv->ops->probe(dev);
+
+ return ret;
+}
+
+static struct bus_type vbus_proxy = {
+ .name = VBUS_PROXY_NAME,
+ .match = vbus_dev_proxy_match,
+};
+
+static struct device vbus_proxy_rootdev = {
+ .parent = NULL,
+ .init_name = VBUS_PROXY_NAME,
+};
+
+static int __init vbus_init(void)
+{
+ int ret;
+
+ ret = bus_register(&vbus_proxy);
+ BUG_ON(ret < 0);
+
+ ret = device_register(&vbus_proxy_rootdev);
+ BUG_ON(ret < 0);
+
+ return 0;
+}
+
+postcore_initcall(vbus_init);
+
+static void device_release(struct device *dev)
+{
+ struct vbus_device_proxy *_dev;
+
+ _dev = container_of(dev, struct vbus_device_proxy, dev);
+
+ _dev->ops->release(_dev);
+}
+
+int vbus_device_proxy_register(struct vbus_device_proxy *new)
+{
+ new->dev.parent = &vbus_proxy_rootdev;
+ new->dev.bus = &vbus_proxy;
+ new->dev.release = &device_release;
+
+ return device_register(&new->dev);
+}
+EXPORT_SYMBOL_GPL(vbus_device_proxy_register);
+
+void vbus_device_proxy_unregister(struct vbus_device_proxy *dev)
+{
+ device_unregister(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(vbus_device_proxy_unregister);
+
+static int match_device_id(struct device *_dev, void *data)
+{
+ struct vbus_device_proxy *dev = to_dev(_dev);
+ u64 id = *(u64 *)data;
+
+ return dev->id == id;
+}
+
+struct vbus_device_proxy *vbus_device_proxy_find(u64 id)
+{
+ struct device *dev;
+
+ dev = bus_find_device(&vbus_proxy, NULL, &id, &match_device_id);
+
+ return to_dev(dev);
+}
+EXPORT_SYMBOL_GPL(vbus_device_proxy_find);
+
+int vbus_driver_register(struct vbus_driver *new)
+{
+ new->drv.bus = &vbus_proxy;
+ new->drv.name = new->type;
+ new->drv.owner = new->owner;
+ new->drv.probe = vbus_dev_proxy_probe;
+
+ return driver_register(&new->drv);
+}
+EXPORT_SYMBOL_GPL(vbus_driver_register);
+
+void vbus_driver_unregister(struct vbus_driver *drv)
+{
+ driver_unregister(&drv->drv);
+}
+EXPORT_SYMBOL_GPL(vbus_driver_unregister);
+
+/*
+ *---------------------------------
+ * driver-side IOQ helper
+ *---------------------------------
+ */
+static void
+vbus_driver_ioq_release(struct ioq *ioq)
+{
+ kfree(ioq->head_desc);
+ kfree(ioq);
+}
+
+static struct ioq_ops vbus_driver_ioq_ops = {
+ .release = vbus_driver_ioq_release,
+};
+
+
+int vbus_driver_ioq_alloc(struct vbus_device_proxy *dev, const char *name,
+ int id, int prio, size_t count, struct ioq **ioq)
+{
+ struct ioq *_ioq;
+ struct ioq_ring_head *head = NULL;
+ struct shm_signal *signal = NULL;
+ size_t len = IOQ_HEAD_DESC_SIZE(count);
+ int ret = -ENOMEM;
+
+ _ioq = kzalloc(sizeof(*_ioq), GFP_KERNEL);
+ if (!_ioq)
+ goto error;
+
+ head = kzalloc(len, GFP_KERNEL | GFP_DMA);
+ if (!head)
+ goto error;
+
+ head->magic = IOQ_RING_MAGIC;
+ head->ver = IOQ_RING_VER;
+ head->count = count;
+
+ ret = dev->ops->shm(dev, name, id, prio, head, len,
+ &head->signal, &signal, 0);
+ if (ret < 0)
+ goto error;
+
+ ioq_init(_ioq,
+ &vbus_driver_ioq_ops,
+ ioq_locality_north,
+ head,
+ signal,
+ count);
+
+ *ioq = _ioq;
+
+ return 0;
+
+ error:
+ kfree(_ioq);
+ kfree(head);
+
+ if (signal)
+ shm_signal_put(signal);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(vbus_driver_ioq_alloc);
diff --git a/drivers/vbus/pci-bridge.c b/drivers/vbus/pci-bridge.c
new file mode 100644
index 000000000000..c1af37cd30d1
--- /dev/null
+++ b/drivers/vbus/pci-bridge.c
@@ -0,0 +1,1028 @@
+/*
+ * Copyright (C) 2009 Novell. All Rights Reserved.
+ *
+ * Author:
+ * Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file 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 St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/mm.h>
+#include <linux/workqueue.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/ioq.h>
+#include <linux/interrupt.h>
+#include <linux/vbus_driver.h>
+#include <linux/vbus_pci.h>
+
+MODULE_AUTHOR("Gregory Haskins");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1");
+
+#define VBUS_PCI_NAME "pci-to-vbus-bridge"
+
+struct vbus_pci {
+ spinlock_t lock;
+ struct pci_dev *dev;
+ struct ioq eventq;
+ struct vbus_pci_event *ring;
+ struct vbus_pci_regs *regs;
+ struct vbus_pci_signals *signals;
+ int irq;
+ int enabled:1;
+ struct {
+ struct dentry *fs;
+ int events;
+ int qnotify;
+ int qinject;
+ int notify;
+ int inject;
+ int bridgecalls;
+ int buscalls;
+ } stats;
+};
+
+static struct vbus_pci vbus_pci;
+
+struct vbus_pci_device {
+ char type[VBUS_MAX_DEVTYPE_LEN];
+ u64 handle;
+ struct list_head shms;
+ struct vbus_device_proxy vdev;
+ struct work_struct drop;
+};
+
+DEFINE_PER_CPU(struct vbus_pci_fastcall_desc, vbus_pci_percpu_fastcall)
+____cacheline_aligned;
+
+/*
+ * -------------------
+ * common routines
+ * -------------------
+ */
+
+static int
+vbus_pci_bridgecall(unsigned long nr, void *data, unsigned long len)
+{
+ struct vbus_pci_call_desc params = {
+ .vector = nr,
+ .len = len,
+ .datap = __pa(data),
+ };
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&vbus_pci.lock, flags);
+
+ memcpy_toio(&vbus_pci.regs->bridgecall, &params, sizeof(params));
+ ret = ioread32(&vbus_pci.regs->bridgecall);
+
+ spin_unlock_irqrestore(&vbus_pci.lock, flags);
+
+ vbus_pci.stats.bridgecalls++;
+
+ return ret;
+}
+
+static int
+vbus_pci_buscall(unsigned long nr, void *data, unsigned long len)
+{
+ struct vbus_pci_fastcall_desc *params;
+ int ret;
+
+ preempt_disable();
+
+ params = &get_cpu_var(vbus_pci_percpu_fastcall);
+
+ params->call.vector = nr;
+ params->call.len = len;
+ params->call.datap = __pa(data);
+
+ iowrite32(smp_processor_id(), &vbus_pci.signals->fastcall);
+
+ ret = params->result;
+
+ preempt_enable();
+
+ vbus_pci.stats.buscalls++;
+
+ return ret;
+}
+
+struct vbus_pci_device *
+to_dev(struct vbus_device_proxy *vdev)
+{
+ return container_of(vdev, struct vbus_pci_device, vdev);
+}
+
+static void
+_signal_init(struct shm_signal *signal, struct shm_signal_desc *desc,
+ struct shm_signal_ops *ops)
+{
+ desc->magic = SHM_SIGNAL_MAGIC;
+ desc->ver = SHM_SIGNAL_VER;
+
+ shm_signal_init(signal, shm_locality_north, ops, desc);
+}
+
+/*
+ * -------------------
+ * _signal
+ * -------------------
+ */
+
+struct _signal {
+ char name[64];
+ struct vbus_pci *pcivbus;
+ struct shm_signal signal;
+ u32 handle;
+ struct rb_node node;
+ struct list_head list;
+ int irq;
+ struct irq_desc *desc;
+};
+
+static struct _signal *
+to_signal(struct shm_signal *signal)
+{
+ return container_of(signal, struct _signal, signal);
+}
+
+static int
+_signal_inject(struct shm_signal *signal)
+{
+ struct _signal *_signal = to_signal(signal);
+
+ vbus_pci.stats.inject++;
+ iowrite32(_signal->handle, &vbus_pci.signals->shmsignal);
+
+ return 0;
+}
+
+static void
+_signal_release(struct shm_signal *signal)
+{
+ struct _signal *_signal = to_signal(signal);
+
+ kfree(_signal);
+}
+
+static struct shm_signal_ops _signal_ops = {
+ .inject = _signal_inject,
+ .release = _signal_release,
+};
+
+/*
+ * -------------------
+ * vbus_device_proxy routines
+ * -------------------
+ */
+
+static int
+vbus_pci_device_open(struct vbus_device_proxy *vdev, int version, int flags)
+{
+ struct vbus_pci_device *dev = to_dev(vdev);
+ struct vbus_pci_deviceopen params;
+ int ret;
+
+ if (dev->handle)
+ return -EINVAL;
+
+ params.devid = vdev->id;
+ params.version = version;
+
+ ret = vbus_pci_buscall(VBUS_PCI_HC_DEVOPEN,
+ &params, sizeof(params));
+ if (ret < 0)
+ return ret;
+
+ dev->handle = params.handle;
+
+ return 0;
+}
+
+static int
+vbus_pci_device_close(struct vbus_device_proxy *vdev, int flags)
+{
+ struct vbus_pci_device *dev = to_dev(vdev);
+ unsigned long iflags;
+ int ret;
+
+ if (!dev->handle)
+ return -EINVAL;
+
+ spin_lock_irqsave(&vbus_pci.lock, iflags);
+
+ while (!list_empty(&dev->shms)) {
+ struct _signal *_signal;
+
+ _signal = list_first_entry(&dev->shms, struct _signal, list);
+
+ list_del(&_signal->list);
+ free_irq(_signal->irq, _signal);
+
+ spin_unlock_irqrestore(&vbus_pci.lock, iflags);
+ shm_signal_put(&_signal->signal);
+ spin_lock_irqsave(&vbus_pci.lock, iflags);
+ }
+
+ spin_unlock_irqrestore(&vbus_pci.lock, iflags);
+
+ /*
+ * The DEVICECLOSE will implicitly close all of the shm on the
+ * host-side, so there is no need to do an explicit per-shm
+ * hypercall
+ */
+ ret = vbus_pci_buscall(VBUS_PCI_HC_DEVCLOSE,
+ &dev->handle, sizeof(dev->handle));
+
+ if (ret < 0)
+ printk(KERN_ERR "VBUS-PCI: Error closing device %s/%lld: %d\n",
+ vdev->type, vdev->id, ret);
+
+ dev->handle = 0;
+
+ return 0;
+}
+
+static void vbus_irq_chip_noop(unsigned int irq)
+{
+}
+
+static struct irq_chip vbus_irq_chip = {
+ .name = "VBUS",
+ .mask = vbus_irq_chip_noop,
+ .unmask = vbus_irq_chip_noop,
+ .eoi = vbus_irq_chip_noop,
+};
+
+irqreturn_t
+shm_signal_intr(int irq, void *dev)
+{
+ struct _signal *_signal = (struct _signal *)dev;
+
+ _shm_signal_wakeup(&_signal->signal);
+
+ return IRQ_HANDLED;
+}
+
+static int
+vbus_pci_device_shm(struct vbus_device_proxy *vdev, const char *name,
+ int id, int prio,
+ void *ptr, size_t len,
+ struct shm_signal_desc *sdesc, struct shm_signal **signal,
+ int flags)
+{
+ struct vbus_pci_device *dev = to_dev(vdev);
+ struct _signal *_signal = NULL;
+ struct vbus_pci_deviceshm params;
+ unsigned long iflags;
+ int ret;
+
+ if (!dev->handle)
+ return -EINVAL;
+
+ params.devh = dev->handle;
+ params.id = id;
+ params.flags = flags;
+ params.datap = (u64)__pa(ptr);
+ params.len = len;
+
+ if (signal) {
+ /*
+ * The signal descriptor must be embedded within the
+ * provided ptr
+ */
+ if (!sdesc
+ || (len < sizeof(*sdesc))
+ || ((void *)sdesc < ptr)
+ || ((void *)sdesc > (ptr + len - sizeof(*sdesc))))
+ return -EINVAL;
+
+ _signal = kzalloc(sizeof(*_signal), GFP_KERNEL);
+ if (!_signal)
+ return -ENOMEM;
+
+ _signal_init(&_signal->signal, sdesc, &_signal_ops);
+
+ /*
+ * take another reference for the host. This is dropped
+ * by a SHMCLOSE event
+ */
+ shm_signal_get(&_signal->signal);
+
+ params.signal.offset = (u64)sdesc - (u64)ptr;
+ params.signal.prio = prio;
+ params.signal.cookie = (u64)_signal;
+
+ } else
+ params.signal.offset = -1; /* yes, this is a u32, but its ok */
+
+ ret = vbus_pci_buscall(VBUS_PCI_HC_DEVSHM,
+ &params, sizeof(params));
+ if (ret < 0)
+ goto fail;
+
+ if (signal) {
+ int irq;
+
+ BUG_ON(ret < 0);
+
+ _signal->handle = ret;
+
+ irq = create_irq();
+ if (irq < 0) {
+ printk(KERN_ERR "Failed to create IRQ: %d\n", irq);
+ ret = -ENOSPC;
+ goto fail;
+ }
+
+ _signal->irq = irq;
+ _signal->desc = irq_to_desc(irq);
+
+ set_irq_chip_and_handler_name(irq,
+ &vbus_irq_chip,
+ handle_percpu_irq,
+ "edge");
+
+ if (!name)
+ snprintf(_signal->name, sizeof(_signal->name),
+ "dev%lld-id%d", vdev->id, id);
+ else
+ snprintf(_signal->name, sizeof(_signal->name),
+ "%s", name);
+
+ ret = request_irq(irq, shm_signal_intr, 0,
+ _signal->name, _signal);
+ if (ret) {
+ printk(KERN_ERR "Failed to request irq: %d\n", irq);
+ goto fail;
+ }
+
+ spin_lock_irqsave(&vbus_pci.lock, iflags);
+
+ list_add_tail(&_signal->list, &dev->shms);
+
+ spin_unlock_irqrestore(&vbus_pci.lock, iflags);
+
+ shm_signal_get(&_signal->signal);
+ *signal = &_signal->signal;
+ }
+
+ return 0;
+
+fail:
+ if (_signal) {
+ /*
+ * We held two references above, so we need to drop
+ * both of them
+ */
+ shm_signal_put(&_signal->signal);
+ shm_signal_put(&_signal->signal);
+ }
+
+ return ret;
+}
+
+static int
+vbus_pci_device_call(struct vbus_device_proxy *vdev, u32 func, void *data,
+ size_t len, int flags)
+{
+ struct vbus_pci_device *dev = to_dev(vdev);
+ struct vbus_pci_devicecall params = {
+ .devh = dev->handle,
+ .func = func,
+ .datap = (u64)__pa(data),
+ .len = len,
+ .flags = flags,
+ };
+
+ if (!dev->handle)
+ return -EINVAL;
+
+ return vbus_pci_buscall(VBUS_PCI_HC_DEVCALL, &params, sizeof(params));
+}
+
+static void
+vbus_pci_device_release(struct vbus_device_proxy *vdev)
+{
+ struct vbus_pci_device *_dev = to_dev(vdev);
+
+ vbus_pci_device_close(vdev, 0);
+
+ kfree(_dev);
+}
+
+struct vbus_device_proxy_ops vbus_pci_device_ops = {
+ .open = vbus_pci_device_open,
+ .close = vbus_pci_device_close,
+ .shm = vbus_pci_device_shm,
+ .call = vbus_pci_device_call,
+ .release = vbus_pci_device_release,
+};
+
+/*
+ * -------------------
+ * vbus events
+ * -------------------
+ */
+
+struct deferred_devadd_event {
+ struct work_struct work;
+ struct vbus_pci_add_event event;
+};
+
+static void deferred_devdrop(struct work_struct *work);
+
+static void
+deferred_devadd(struct work_struct *work)
+{
+ struct deferred_devadd_event *_event;
+ struct vbus_pci_device *new;
+ int ret;
+
+ _event = container_of(work, struct deferred_devadd_event, work);
+
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
+ if (!new) {
+ printk(KERN_ERR "VBUS_PCI: Out of memory on add_event\n");
+ return;
+ }
+
+ INIT_LIST_HEAD(&new->shms);
+
+ memcpy(new->type, _event->event.type, VBUS_MAX_DEVTYPE_LEN);
+ new->vdev.type = new->type;
+ new->vdev.id = _event->event.id;
+ new->vdev.ops = &vbus_pci_device_ops;
+
+ dev_set_name(&new->vdev.dev, "%lld", _event->event.id);
+
+ INIT_WORK(&new->drop, deferred_devdrop);
+
+ ret = vbus_device_proxy_register(&new->vdev);
+ if (ret < 0)
+ panic("failed to register device %lld(%s): %d\n",
+ new->vdev.id, new->type, ret);
+
+ kfree(_event);
+}
+
+static void
+deferred_devdrop(struct work_struct *work)
+{
+ struct vbus_pci_device *dev;
+
+ dev = container_of(work, struct vbus_pci_device, drop);
+ vbus_device_proxy_unregister(&dev->vdev);
+}
+
+static void
+event_devadd(struct vbus_pci_add_event *event)
+{
+ struct deferred_devadd_event *_event;
+
+ _event = kzalloc(sizeof(*_event), GFP_ATOMIC);
+ if (!_event) {
+ printk(KERN_ERR \
+ "VBUS_PCI: Out of ATOMIC memory on add_event\n");
+ return;
+ }
+
+ INIT_WORK(&_event->work, deferred_devadd);
+ memcpy(&_event->event, event, sizeof(*event));
+
+ schedule_work(&_event->work);
+}
+
+static void
+event_devdrop(struct vbus_pci_handle_event *event)
+{
+ struct vbus_device_proxy *dev = vbus_device_proxy_find(event->handle);
+
+ if (!dev) {
+ printk(KERN_WARNING "VBUS-PCI: devdrop failed: %lld\n",
+ event->handle);
+ return;
+ }
+
+ schedule_work(&to_dev(dev)->drop);
+}
+
+static void
+event_shmsignal(struct vbus_pci_handle_event *event)
+{
+ struct _signal *_signal = (struct _signal *)event->handle;
+ struct irq_desc *desc = _signal->desc;
+
+ vbus_pci.stats.notify++;
+ desc->handle_irq(_signal->irq, desc);
+}
+
+static void
+event_shmclose(struct vbus_pci_handle_event *event)
+{
+ struct _signal *_signal = (struct _signal *)event->handle;
+
+ /*
+ * This reference was taken during the DEVICESHM call
+ */
+ shm_signal_put(&_signal->signal);
+}
+
+/*
+ * -------------------
+ * eventq routines
+ * -------------------
+ */
+
+static struct ioq_notifier eventq_notifier;
+
+static int __devinit
+eventq_init(int qlen)
+{
+ struct ioq_iterator iter;
+ int ret;
+ int i;
+
+ vbus_pci.ring = kzalloc(sizeof(struct vbus_pci_event) * qlen,
+ GFP_KERNEL);
+ if (!vbus_pci.ring)
+ return -ENOMEM;
+
+ /*
+ * We want to iterate on the "valid" index. By default the iterator
+ * will not "autoupdate" which means it will not hypercall the host
+ * with our changes. This is good, because we are really just
+ * initializing stuff here anyway. Note that you can always manually
+ * signal the host with ioq_signal() if the autoupdate feature is not
+ * used.
+ */
+ ret = ioq_iter_init(&vbus_pci.eventq, &iter, ioq_idxtype_valid, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * Seek to the tail of the valid index (which should be our first
+ * item since the queue is brand-new)
+ */
+ ret = ioq_iter_seek(&iter, ioq_seek_tail, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * Now populate each descriptor with an empty vbus_event and mark it
+ * valid
+ */
+ for (i = 0; i < qlen; i++) {
+ struct vbus_pci_event *event = &vbus_pci.ring[i];
+ size_t len = sizeof(*event);
+ struct ioq_ring_desc *desc = iter.desc;
+
+ BUG_ON(iter.desc->valid);
+
+ desc->cookie = (u64)event;
+ desc->ptr = (u64)__pa(event);
+ desc->len = len; /* total length */
+ desc->valid = 1;
+
+ /*
+ * This push operation will simultaneously advance the
+ * valid-tail index and increment our position in the queue
+ * by one.
+ */
+ ret = ioq_iter_push(&iter, 0);
+ BUG_ON(ret < 0);
+ }
+
+ vbus_pci.eventq.notifier = &eventq_notifier;
+
+ /*
+ * And finally, ensure that we can receive notification
+ */
+ ioq_notify_enable(&vbus_pci.eventq, 0);
+
+ return 0;
+}
+
+/* Invoked whenever the hypervisor ioq_signal()s our eventq */
+static void
+eventq_wakeup(struct ioq_notifier *notifier)
+{
+ struct ioq_iterator iter;
+ int ret;
+
+ /* We want to iterate on the head of the in-use index */
+ ret = ioq_iter_init(&vbus_pci.eventq, &iter, ioq_idxtype_inuse, 0);
+ BUG_ON(ret < 0);
+
+ ret = ioq_iter_seek(&iter, ioq_seek_head, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * The EOM is indicated by finding a packet that is still owned by
+ * the south side.
+ *
+ * FIXME: This in theory could run indefinitely if the host keeps
+ * feeding us events since there is nothing like a NAPI budget. We
+ * might need to address that
+ */
+ while (!iter.desc->sown) {
+ struct ioq_ring_desc *desc = iter.desc;
+ struct vbus_pci_event *event;
+
+ event = (struct vbus_pci_event *)desc->cookie;
+
+ switch (event->eventid) {
+ case VBUS_PCI_EVENT_DEVADD:
+ event_devadd(&event->data.add);
+ break;
+ case VBUS_PCI_EVENT_DEVDROP:
+ event_devdrop(&event->data.handle);
+ break;
+ case VBUS_PCI_EVENT_SHMSIGNAL:
+ event_shmsignal(&event->data.handle);
+ break;
+ case VBUS_PCI_EVENT_SHMCLOSE:
+ event_shmclose(&event->data.handle);
+ break;
+ default:
+ printk(KERN_WARNING "VBUS_PCI: Unexpected event %d\n",
+ event->eventid);
+ break;
+ };
+
+ memset(event, 0, sizeof(*event));
+
+ /* Advance the in-use head */
+ ret = ioq_iter_pop(&iter, 0);
+ BUG_ON(ret < 0);
+
+ vbus_pci.stats.events++;
+ }
+
+ /* And let the south side know that we changed the queue */
+ ioq_signal(&vbus_pci.eventq, 0);
+}
+
+static struct ioq_notifier eventq_notifier = {
+ .signal = &eventq_wakeup,
+};
+
+/* Injected whenever the host issues an ioq_signal() on the eventq */
+irqreturn_t
+eventq_intr(int irq, void *dev)
+{
+ vbus_pci.stats.qnotify++;
+ _shm_signal_wakeup(vbus_pci.eventq.signal);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * -------------------
+ */
+
+static int
+eventq_signal_inject(struct shm_signal *signal)
+{
+ vbus_pci.stats.qinject++;
+
+ /* The eventq uses the special-case handle=0 */
+ iowrite32(0, &vbus_pci.signals->eventq);
+
+ return 0;
+}
+
+static void
+eventq_signal_release(struct shm_signal *signal)
+{
+ kfree(signal);
+}
+
+static struct shm_signal_ops eventq_signal_ops = {
+ .inject = eventq_signal_inject,
+ .release = eventq_signal_release,
+};
+
+/*
+ * -------------------
+ */
+
+static void
+eventq_ioq_release(struct ioq *ioq)
+{
+ /* released as part of the vbus_pci object */
+}
+
+static struct ioq_ops eventq_ioq_ops = {
+ .release = eventq_ioq_release,
+};
+
+/*
+ * -------------------
+ */
+
+static void
+vbus_pci_release(void)
+{
+#ifdef CONFIG_DEBUG_FS
+ if (vbus_pci.stats.fs)
+ debugfs_remove(vbus_pci.stats.fs);
+#endif
+
+ if (vbus_pci.irq > 0)
+ free_irq(vbus_pci.irq, NULL);
+
+ if (vbus_pci.signals)
+ pci_iounmap(vbus_pci.dev, (void *)vbus_pci.signals);
+
+ if (vbus_pci.regs)
+ pci_iounmap(vbus_pci.dev, (void *)vbus_pci.regs);
+
+ pci_release_regions(vbus_pci.dev);
+ pci_disable_device(vbus_pci.dev);
+
+ kfree(vbus_pci.eventq.head_desc);
+ kfree(vbus_pci.ring);
+
+ vbus_pci.enabled = false;
+}
+
+static int __devinit
+vbus_pci_open(void)
+{
+ struct vbus_pci_bridge_negotiate params = {
+ .magic = VBUS_PCI_ABI_MAGIC,
+ .version = VBUS_PCI_HC_VERSION,
+ .capabilities = 0,
+ };
+
+ return vbus_pci_bridgecall(VBUS_PCI_BRIDGE_NEGOTIATE,
+ &params, sizeof(params));
+}
+
+#define QLEN 1024
+
+static int __devinit
+vbus_pci_eventq_register(void)
+{
+ struct vbus_pci_busreg params = {
+ .count = 1,
+ .eventq = {
+ {
+ .count = QLEN,
+ .ring = (u64)__pa(vbus_pci.eventq.head_desc),
+ .data = (u64)__pa(vbus_pci.ring),
+ },
+ },
+ };
+
+ return vbus_pci_bridgecall(VBUS_PCI_BRIDGE_QREG,
+ &params, sizeof(params));
+}
+
+static int __devinit
+_ioq_init(size_t ringsize, struct ioq *ioq, struct ioq_ops *ops)
+{
+ struct shm_signal *signal = NULL;
+ struct ioq_ring_head *head = NULL;
+ size_t len = IOQ_HEAD_DESC_SIZE(ringsize);
+
+ head = kzalloc(len, GFP_KERNEL | GFP_DMA);
+ if (!head)
+ return -ENOMEM;
+
+ signal = kzalloc(sizeof(*signal), GFP_KERNEL);
+ if (!signal) {
+ kfree(head);
+ return -ENOMEM;
+ }
+
+ head->magic = IOQ_RING_MAGIC;
+ head->ver = IOQ_RING_VER;
+ head->count = ringsize;
+
+ _signal_init(signal, &head->signal, &eventq_signal_ops);
+
+ ioq_init(ioq, ops, ioq_locality_north, head, signal, ringsize);
+
+ return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int _debugfs_seq_show(struct seq_file *m, void *p)
+{
+#define P(F) \
+ seq_printf(m, " .%-30s: %d\n", #F, (int)vbus_pci.stats.F)
+
+ P(events);
+ P(qnotify);
+ P(qinject);
+ P(notify);
+ P(inject);
+ P(bridgecalls);
+ P(buscalls);
+
+#undef P
+
+ return 0;
+}
+
+static int _debugfs_fops_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, _debugfs_seq_show, inode->i_private);
+}
+
+static const struct file_operations stat_fops = {
+ .open = _debugfs_fops_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+#endif
+
+static int __devinit
+vbus_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int ret;
+ int cpu;
+
+ if (vbus_pci.enabled)
+ return -EEXIST; /* we only support one bridge per kernel */
+
+ if (pdev->revision != VBUS_PCI_ABI_VERSION) {
+ printk(KERN_DEBUG "VBUS_PCI: expected ABI version %d, got %d\n",
+ VBUS_PCI_ABI_VERSION,
+ pdev->revision);
+ return -ENODEV;
+ }
+
+ vbus_pci.dev = pdev;
+
+ ret = pci_enable_device(pdev);
+ if (ret < 0)
+ return ret;
+
+ ret = pci_request_regions(pdev, VBUS_PCI_NAME);
+ if (ret < 0) {
+ printk(KERN_ERR "VBUS_PCI: Could not init BARs: %d\n", ret);
+ goto out_fail;
+ }
+
+ vbus_pci.regs = pci_iomap(pdev, 0, sizeof(struct vbus_pci_regs));
+ if (!vbus_pci.regs) {
+ printk(KERN_ERR "VBUS_PCI: Could not map BARs\n");
+ goto out_fail;
+ }
+
+ vbus_pci.signals = pci_iomap(pdev, 1, sizeof(struct vbus_pci_signals));
+ if (!vbus_pci.signals) {
+ printk(KERN_ERR "VBUS_PCI: Could not map BARs\n");
+ goto out_fail;
+ }
+
+ ret = vbus_pci_open();
+ if (ret < 0) {
+ printk(KERN_DEBUG "VBUS_PCI: Could not register with host: %d\n",
+ ret);
+ goto out_fail;
+ }
+
+ /*
+ * Allocate an IOQ to use for host-2-guest event notification
+ */
+ ret = _ioq_init(QLEN, &vbus_pci.eventq, &eventq_ioq_ops);
+ if (ret < 0) {
+ printk(KERN_ERR "VBUS_PCI: Cound not init eventq: %d\n", ret);
+ goto out_fail;
+ }
+
+ ret = eventq_init(QLEN);
+ if (ret < 0) {
+ printk(KERN_ERR "VBUS_PCI: Cound not setup ring: %d\n", ret);
+ goto out_fail;
+ }
+
+ ret = pci_enable_msi(pdev);
+ if (ret < 0) {
+ printk(KERN_ERR "VBUS_PCI: Cound not enable MSI: %d\n", ret);
+ goto out_fail;
+ }
+
+ vbus_pci.irq = pdev->irq;
+
+ ret = request_irq(pdev->irq, eventq_intr, 0, "vbus", NULL);
+ if (ret < 0) {
+ printk(KERN_ERR "VBUS_PCI: Failed to register IRQ %d\n: %d",
+ pdev->irq, ret);
+ goto out_fail;
+ }
+
+ /*
+ * Add one fastcall vector per cpu so that we can do lockless
+ * hypercalls
+ */
+ for_each_possible_cpu(cpu) {
+ struct vbus_pci_fastcall_desc *desc =
+ &per_cpu(vbus_pci_percpu_fastcall, cpu);
+ struct vbus_pci_call_desc params = {
+ .vector = cpu,
+ .len = sizeof(*desc),
+ .datap = __pa(desc),
+ };
+
+ ret = vbus_pci_bridgecall(VBUS_PCI_BRIDGE_FASTCALL_ADD,
+ &params, sizeof(params));
+ if (ret < 0) {
+ printk(KERN_ERR \
+ "VBUS_PCI: Failed to register cpu:%d\n: %d",
+ cpu, ret);
+ goto out_fail;
+ }
+ }
+
+ /*
+ * Finally register our queue on the host to start receiving events
+ */
+ ret = vbus_pci_eventq_register();
+ if (ret < 0) {
+ printk(KERN_ERR "VBUS_PCI: Could not register with host: %d\n",
+ ret);
+ goto out_fail;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ vbus_pci.stats.fs = debugfs_create_file(VBUS_PCI_NAME, S_IRUGO,
+ NULL, NULL, &stat_fops);
+ if (IS_ERR(vbus_pci.stats.fs)) {
+ ret = PTR_ERR(vbus_pci.stats.fs);
+ printk(KERN_ERR "VBUS_PCI: error creating stats-fs: %d\n", ret);
+ goto out_fail;
+ }
+#endif
+
+ vbus_pci.enabled = true;
+
+ printk(KERN_INFO "Virtual-Bus: Copyright (c) 2009, " \
+ "Gregory Haskins <ghaskins@novell.com>\n");
+
+ return 0;
+
+ out_fail:
+ vbus_pci_release();
+
+ return ret;
+}
+
+static void __devexit
+vbus_pci_remove(struct pci_dev *pdev)
+{
+ vbus_pci_release();
+}
+
+static DEFINE_PCI_DEVICE_TABLE(vbus_pci_tbl) = {
+ { PCI_DEVICE(0x11da, 0x2000) },
+ { 0 },
+};
+
+MODULE_DEVICE_TABLE(pci, vbus_pci_tbl);
+
+static struct pci_driver vbus_pci_driver = {
+ .name = VBUS_PCI_NAME,
+ .id_table = vbus_pci_tbl,
+ .probe = vbus_pci_probe,
+ .remove = vbus_pci_remove,
+};
+
+int __init
+vbus_pci_init(void)
+{
+ memset(&vbus_pci, 0, sizeof(vbus_pci));
+ spin_lock_init(&vbus_pci.lock);
+
+ return pci_register_driver(&vbus_pci_driver);
+}
+
+static void __exit
+vbus_pci_exit(void)
+{
+ pci_unregister_driver(&vbus_pci_driver);
+}
+
+module_init(vbus_pci_init);
+module_exit(vbus_pci_exit);
+
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 2830ffd72976..317afab62b3c 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -959,7 +959,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
if (sinfo->atmel_lcdfb_power_control)
sinfo->atmel_lcdfb_power_control(1);
- dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %lu\n",
+ dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %d\n",
info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
return 0;
diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c
index ad05da5ba3c7..4c10edecfb66 100644
--- a/drivers/video/backlight/adp5520_bl.c
+++ b/drivers/video/backlight/adp5520_bl.c
@@ -15,7 +15,7 @@
struct adp5520_bl {
struct device *master;
- struct adp5520_backlight_platfrom_data *pdata;
+ struct adp5520_backlight_platform_data *pdata;
struct mutex lock;
unsigned long cached_daylight_max;
int id;
@@ -31,29 +31,30 @@ static int adp5520_bl_set(struct backlight_device *bl, int brightness)
if (data->pdata->en_ambl_sens) {
if ((brightness > 0) && (brightness < ADP5020_MAX_BRIGHTNESS)) {
/* Disable Ambient Light auto adjust */
- ret |= adp5520_clr_bits(master, BL_CONTROL,
- BL_AUTO_ADJ);
- ret |= adp5520_write(master, DAYLIGHT_MAX, brightness);
+ ret |= adp5520_clr_bits(master, ADP5520_BL_CONTROL,
+ ADP5520_BL_AUTO_ADJ);
+ ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX,
+ brightness);
} else {
/*
* MAX_BRIGHTNESS -> Enable Ambient Light auto adjust
* restore daylight l3 sysfs brightness
*/
- ret |= adp5520_write(master, DAYLIGHT_MAX,
+ ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX,
data->cached_daylight_max);
- ret |= adp5520_set_bits(master, BL_CONTROL,
- BL_AUTO_ADJ);
+ ret |= adp5520_set_bits(master, ADP5520_BL_CONTROL,
+ ADP5520_BL_AUTO_ADJ);
}
} else {
- ret |= adp5520_write(master, DAYLIGHT_MAX, brightness);
+ ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX, brightness);
}
if (data->current_brightness && brightness == 0)
ret |= adp5520_set_bits(master,
- MODE_STATUS, DIM_EN);
+ ADP5520_MODE_STATUS, ADP5520_DIM_EN);
else if (data->current_brightness == 0 && brightness)
ret |= adp5520_clr_bits(master,
- MODE_STATUS, DIM_EN);
+ ADP5520_MODE_STATUS, ADP5520_DIM_EN);
if (!ret)
data->current_brightness = brightness;
@@ -79,7 +80,7 @@ static int adp5520_bl_get_brightness(struct backlight_device *bl)
int error;
uint8_t reg_val;
- error = adp5520_read(data->master, BL_VALUE, &reg_val);
+ error = adp5520_read(data->master, ADP5520_BL_VALUE, &reg_val);
return error ? data->current_brightness : reg_val;
}
@@ -93,33 +94,46 @@ static int adp5520_bl_setup(struct backlight_device *bl)
{
struct adp5520_bl *data = bl_get_data(bl);
struct device *master = data->master;
- struct adp5520_backlight_platfrom_data *pdata = data->pdata;
+ struct adp5520_backlight_platform_data *pdata = data->pdata;
int ret = 0;
- ret |= adp5520_write(master, DAYLIGHT_MAX, pdata->l1_daylight_max);
- ret |= adp5520_write(master, DAYLIGHT_DIM, pdata->l1_daylight_dim);
+ ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX,
+ pdata->l1_daylight_max);
+ ret |= adp5520_write(master, ADP5520_DAYLIGHT_DIM,
+ pdata->l1_daylight_dim);
if (pdata->en_ambl_sens) {
data->cached_daylight_max = pdata->l1_daylight_max;
- ret |= adp5520_write(master, OFFICE_MAX, pdata->l2_office_max);
- ret |= adp5520_write(master, OFFICE_DIM, pdata->l2_office_dim);
- ret |= adp5520_write(master, DARK_MAX, pdata->l3_dark_max);
- ret |= adp5520_write(master, DARK_DIM, pdata->l3_dark_dim);
- ret |= adp5520_write(master, L2_TRIP, pdata->l2_trip);
- ret |= adp5520_write(master, L2_HYS, pdata->l2_hyst);
- ret |= adp5520_write(master, L3_TRIP, pdata->l3_trip);
- ret |= adp5520_write(master, L3_HYS, pdata->l3_hyst);
- ret |= adp5520_write(master, ALS_CMPR_CFG,
- ALS_CMPR_CFG_VAL(pdata->abml_filt, L3_EN));
+ ret |= adp5520_write(master, ADP5520_OFFICE_MAX,
+ pdata->l2_office_max);
+ ret |= adp5520_write(master, ADP5520_OFFICE_DIM,
+ pdata->l2_office_dim);
+ ret |= adp5520_write(master, ADP5520_DARK_MAX,
+ pdata->l3_dark_max);
+ ret |= adp5520_write(master, ADP5520_DARK_DIM,
+ pdata->l3_dark_dim);
+ ret |= adp5520_write(master, ADP5520_L2_TRIP,
+ pdata->l2_trip);
+ ret |= adp5520_write(master, ADP5520_L2_HYS,
+ pdata->l2_hyst);
+ ret |= adp5520_write(master, ADP5520_L3_TRIP,
+ pdata->l3_trip);
+ ret |= adp5520_write(master, ADP5520_L3_HYS,
+ pdata->l3_hyst);
+ ret |= adp5520_write(master, ADP5520_ALS_CMPR_CFG,
+ ALS_CMPR_CFG_VAL(pdata->abml_filt,
+ ADP5520_L3_EN));
}
- ret |= adp5520_write(master, BL_CONTROL,
- BL_CTRL_VAL(pdata->fade_led_law, pdata->en_ambl_sens));
+ ret |= adp5520_write(master, ADP5520_BL_CONTROL,
+ BL_CTRL_VAL(pdata->fade_led_law,
+ pdata->en_ambl_sens));
- ret |= adp5520_write(master, BL_FADE, FADE_VAL(pdata->fade_in,
+ ret |= adp5520_write(master, ADP5520_BL_FADE, FADE_VAL(pdata->fade_in,
pdata->fade_out));
- ret |= adp5520_set_bits(master, MODE_STATUS, BL_EN | DIM_EN);
+ ret |= adp5520_set_bits(master, ADP5520_MODE_STATUS,
+ ADP5520_BL_EN | ADP5520_DIM_EN);
return ret;
}
@@ -156,29 +170,31 @@ static ssize_t adp5520_store(struct device *dev, const char *buf,
}
static ssize_t adp5520_bl_dark_max_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+ struct device_attribute *attr, char *buf)
{
- return adp5520_show(dev, buf, DARK_MAX);
+ return adp5520_show(dev, buf, ADP5520_DARK_MAX);
}
static ssize_t adp5520_bl_dark_max_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- return adp5520_store(dev, buf, count, DARK_MAX);
+ return adp5520_store(dev, buf, count, ADP5520_DARK_MAX);
}
static DEVICE_ATTR(dark_max, 0664, adp5520_bl_dark_max_show,
adp5520_bl_dark_max_store);
static ssize_t adp5520_bl_office_max_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+ struct device_attribute *attr, char *buf)
{
- return adp5520_show(dev, buf, OFFICE_MAX);
+ return adp5520_show(dev, buf, ADP5520_OFFICE_MAX);
}
static ssize_t adp5520_bl_office_max_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- return adp5520_store(dev, buf, count, OFFICE_MAX);
+ return adp5520_store(dev, buf, count, ADP5520_OFFICE_MAX);
}
static DEVICE_ATTR(office_max, 0664, adp5520_bl_office_max_show,
adp5520_bl_office_max_store);
@@ -186,16 +202,17 @@ static DEVICE_ATTR(office_max, 0664, adp5520_bl_office_max_show,
static ssize_t adp5520_bl_daylight_max_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return adp5520_show(dev, buf, DAYLIGHT_MAX);
+ return adp5520_show(dev, buf, ADP5520_DAYLIGHT_MAX);
}
static ssize_t adp5520_bl_daylight_max_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct adp5520_bl *data = dev_get_drvdata(dev);
strict_strtoul(buf, 10, &data->cached_daylight_max);
- return adp5520_store(dev, buf, count, DAYLIGHT_MAX);
+ return adp5520_store(dev, buf, count, ADP5520_DAYLIGHT_MAX);
}
static DEVICE_ATTR(daylight_max, 0664, adp5520_bl_daylight_max_show,
adp5520_bl_daylight_max_store);
@@ -203,14 +220,14 @@ static DEVICE_ATTR(daylight_max, 0664, adp5520_bl_daylight_max_show,
static ssize_t adp5520_bl_dark_dim_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return adp5520_show(dev, buf, DARK_DIM);
+ return adp5520_show(dev, buf, ADP5520_DARK_DIM);
}
static ssize_t adp5520_bl_dark_dim_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- return adp5520_store(dev, buf, count, DARK_DIM);
+ return adp5520_store(dev, buf, count, ADP5520_DARK_DIM);
}
static DEVICE_ATTR(dark_dim, 0664, adp5520_bl_dark_dim_show,
adp5520_bl_dark_dim_store);
@@ -218,29 +235,29 @@ static DEVICE_ATTR(dark_dim, 0664, adp5520_bl_dark_dim_show,
static ssize_t adp5520_bl_office_dim_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return adp5520_show(dev, buf, OFFICE_DIM);
+ return adp5520_show(dev, buf, ADP5520_OFFICE_DIM);
}
static ssize_t adp5520_bl_office_dim_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- return adp5520_store(dev, buf, count, OFFICE_DIM);
+ return adp5520_store(dev, buf, count, ADP5520_OFFICE_DIM);
}
static DEVICE_ATTR(office_dim, 0664, adp5520_bl_office_dim_show,
adp5520_bl_office_dim_store);
static ssize_t adp5520_bl_daylight_dim_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+ struct device_attribute *attr, char *buf)
{
- return adp5520_show(dev, buf, DAYLIGHT_DIM);
+ return adp5520_show(dev, buf, ADP5520_DAYLIGHT_DIM);
}
static ssize_t adp5520_bl_daylight_dim_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- return adp5520_store(dev, buf, count, DAYLIGHT_DIM);
+ return adp5520_store(dev, buf, count, ADP5520_DAYLIGHT_DIM);
}
static DEVICE_ATTR(daylight_dim, 0664, adp5520_bl_daylight_dim_show,
adp5520_bl_daylight_dim_store);
@@ -316,7 +333,7 @@ static int __devexit adp5520_bl_remove(struct platform_device *pdev)
struct backlight_device *bl = platform_get_drvdata(pdev);
struct adp5520_bl *data = bl_get_data(bl);
- adp5520_clr_bits(data->master, MODE_STATUS, BL_EN);
+ adp5520_clr_bits(data->master, ADP5520_MODE_STATUS, ADP5520_BL_EN);
if (data->pdata->en_ambl_sens)
sysfs_remove_group(&bl->dev.kobj,
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index b6449470106c..a482dd7b0311 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -56,7 +56,7 @@ static int fb_notifier_callback(struct notifier_block *self,
static int lcd_register_fb(struct lcd_device *ld)
{
- memset(&ld->fb_notif, 0, sizeof(&ld->fb_notif));
+ memset(&ld->fb_notif, 0, sizeof(ld->fb_notif));
ld->fb_notif.notifier_call = fb_notifier_callback;
return fb_register_client(&ld->fb_notif);
}
diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c
index cbad67e89826..8693e5fcd2eb 100644
--- a/drivers/video/backlight/omap1_bl.c
+++ b/drivers/video/backlight/omap1_bl.c
@@ -26,8 +26,8 @@
#include <linux/backlight.h>
#include <mach/hardware.h>
-#include <mach/board.h>
-#include <mach/mux.h>
+#include <plat/board.h>
+#include <plat/mux.h>
#define OMAPBL_MAX_INTENSITY 0xff
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
index c27ab1ed9604..e59c08320886 100644
--- a/drivers/video/fb_defio.c
+++ b/drivers/video/fb_defio.c
@@ -71,7 +71,7 @@ int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync)
{
struct fb_info *info = file->private_data;
- /* Skip if deferred io is complied-in but disabled on this fbdev */
+ /* Skip if deferred io is compiled-in but disabled on this fbdev */
if (!info->fbdefio)
return 0;
diff --git a/drivers/video/omap/blizzard.c b/drivers/video/omap/blizzard.c
index 70dadf9d2334..f5d75f22cef9 100644
--- a/drivers/video/omap/blizzard.c
+++ b/drivers/video/omap/blizzard.c
@@ -26,9 +26,9 @@
#include <linux/delay.h>
#include <linux/clk.h>
-#include <mach/dma.h>
-#include <mach/omapfb.h>
-#include <mach/blizzard.h>
+#include <plat/dma.h>
+#include <plat/omapfb.h>
+#include <plat/blizzard.h>
#include "dispc.h"
diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c
index f16e42154229..7c833db4f9b7 100644
--- a/drivers/video/omap/dispc.c
+++ b/drivers/video/omap/dispc.c
@@ -25,9 +25,9 @@
#include <linux/clk.h>
#include <linux/io.h>
-#include <mach/sram.h>
-#include <mach/omapfb.h>
-#include <mach/board.h>
+#include <plat/sram.h>
+#include <plat/omapfb.h>
+#include <plat/board.h>
#include "dispc.h"
@@ -204,6 +204,7 @@ static u32 inline dispc_read_reg(int idx)
/* Select RFBI or bypass mode */
static void enable_rfbi_mode(int enable)
{
+ void __iomem *rfbi_control;
u32 l;
l = dispc_read_reg(DISPC_CONTROL);
@@ -216,9 +217,15 @@ static void enable_rfbi_mode(int enable)
dispc_write_reg(DISPC_CONTROL, l);
/* Set bypass mode in RFBI module */
- l = __raw_readl(OMAP2_IO_ADDRESS(RFBI_CONTROL));
+ rfbi_control = ioremap(RFBI_CONTROL, SZ_1K);
+ if (!rfbi_control) {
+ pr_err("Unable to ioremap rfbi_control\n");
+ return;
+ }
+ l = __raw_readl(rfbi_control);
l |= enable ? 0 : (1 << 1);
- __raw_writel(l, OMAP2_IO_ADDRESS(RFBI_CONTROL));
+ __raw_writel(l, rfbi_control);
+ iounmap(rfbi_control);
}
static void set_lcd_data_lines(int data_lines)
@@ -1367,6 +1374,7 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
int r;
u32 l;
struct lcd_panel *panel = fbdev->panel;
+ void __iomem *ram_fw_base;
int tmo = 10000;
int skip_init = 0;
int i;
@@ -1441,7 +1449,13 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
}
/* L3 firewall setting: enable access to OCM RAM */
- __raw_writel(0x402000b0, OMAP2_IO_ADDRESS(0x680050a0));
+ ram_fw_base = ioremap(0x68005000, SZ_1K);
+ if (!ram_fw_base) {
+ dev_err(dispc.fbdev->dev, "Cannot ioremap to enable OCM RAM\n");
+ goto fail1;
+ }
+ __raw_writel(0x402000b0, ram_fw_base + 0xa0);
+ iounmap(ram_fw_base);
if ((r = alloc_palette_ram()) < 0)
goto fail2;
diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c
index ca51583ec98a..17a975e4c9c9 100644
--- a/drivers/video/omap/hwa742.c
+++ b/drivers/video/omap/hwa742.c
@@ -26,9 +26,9 @@
#include <linux/delay.h>
#include <linux/clk.h>
-#include <mach/dma.h>
-#include <mach/omapfb.h>
-#include <mach/hwa742.h>
+#include <plat/dma.h>
+#include <plat/omapfb.h>
+#include <plat/hwa742.h>
#define HWA742_REV_CODE_REG 0x0
#define HWA742_CONFIG_REG 0x2
diff --git a/drivers/video/omap/lcd_2430sdp.c b/drivers/video/omap/lcd_2430sdp.c
index 393712b6f369..fea7feee0b77 100644
--- a/drivers/video/omap/lcd_2430sdp.c
+++ b/drivers/video/omap/lcd_2430sdp.c
@@ -27,8 +27,8 @@
#include <linux/gpio.h>
#include <linux/i2c/twl4030.h>
-#include <mach/mux.h>
-#include <mach/omapfb.h>
+#include <plat/mux.h>
+#include <plat/omapfb.h>
#include <asm/mach-types.h>
#define SDP2430_LCD_PANEL_BACKLIGHT_GPIO 91
diff --git a/drivers/video/omap/lcd_ams_delta.c b/drivers/video/omap/lcd_ams_delta.c
index 1f7439955e02..b3973ebd1b0f 100644
--- a/drivers/video/omap/lcd_ams_delta.c
+++ b/drivers/video/omap/lcd_ams_delta.c
@@ -25,9 +25,9 @@
#include <linux/io.h>
#include <linux/delay.h>
-#include <mach/board-ams-delta.h>
+#include <plat/board-ams-delta.h>
#include <mach/hardware.h>
-#include <mach/omapfb.h>
+#include <plat/omapfb.h>
#define AMS_DELTA_DEFAULT_CONTRAST 112
@@ -123,12 +123,12 @@ struct platform_driver ams_delta_panel_driver = {
},
};
-static int ams_delta_panel_drv_init(void)
+static int __init ams_delta_panel_drv_init(void)
{
return platform_driver_register(&ams_delta_panel_driver);
}
-static void ams_delta_panel_drv_cleanup(void)
+static void __exit ams_delta_panel_drv_cleanup(void)
{
platform_driver_unregister(&ams_delta_panel_driver);
}
diff --git a/drivers/video/omap/lcd_apollon.c b/drivers/video/omap/lcd_apollon.c
index 626ae3a532ff..4c5cefc5153b 100644
--- a/drivers/video/omap/lcd_apollon.c
+++ b/drivers/video/omap/lcd_apollon.c
@@ -25,8 +25,8 @@
#include <linux/platform_device.h>
#include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/omapfb.h>
+#include <plat/mux.h>
+#include <plat/omapfb.h>
/* #define USE_35INCH_LCD 1 */
diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c
index 417ae5efa8bb..240b4fb10741 100644
--- a/drivers/video/omap/lcd_h3.c
+++ b/drivers/video/omap/lcd_h3.c
@@ -24,7 +24,7 @@
#include <linux/i2c/tps65010.h>
#include <mach/gpio.h>
-#include <mach/omapfb.h>
+#include <plat/omapfb.h>
#define MODULE_NAME "omapfb-lcd_h3"
diff --git a/drivers/video/omap/lcd_h4.c b/drivers/video/omap/lcd_h4.c
index 0c398bda7601..720625da1f4e 100644
--- a/drivers/video/omap/lcd_h4.c
+++ b/drivers/video/omap/lcd_h4.c
@@ -22,7 +22,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <mach/omapfb.h>
+#include <plat/omapfb.h>
static int h4_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
{
diff --git a/drivers/video/omap/lcd_inn1510.c b/drivers/video/omap/lcd_inn1510.c
index cdbd8bb607be..aafe9b497e2d 100644
--- a/drivers/video/omap/lcd_inn1510.c
+++ b/drivers/video/omap/lcd_inn1510.c
@@ -23,8 +23,8 @@
#include <linux/platform_device.h>
#include <linux/io.h>
-#include <mach/fpga.h>
-#include <mach/omapfb.h>
+#include <plat/fpga.h>
+#include <plat/omapfb.h>
static int innovator1510_panel_init(struct lcd_panel *panel,
struct omapfb_device *fbdev)
diff --git a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c
index 268f7f808a4e..0de338264a8a 100644
--- a/drivers/video/omap/lcd_inn1610.c
+++ b/drivers/video/omap/lcd_inn1610.c
@@ -23,7 +23,7 @@
#include <linux/platform_device.h>
#include <mach/gpio.h>
-#include <mach/omapfb.h>
+#include <plat/omapfb.h>
#define MODULE_NAME "omapfb-lcd_h3"
diff --git a/drivers/video/omap/lcd_ldp.c b/drivers/video/omap/lcd_ldp.c
index dbfe8974fb94..6a260dfdadc5 100644
--- a/drivers/video/omap/lcd_ldp.c
+++ b/drivers/video/omap/lcd_ldp.c
@@ -27,8 +27,8 @@
#include <linux/i2c/twl4030.h>
#include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/omapfb.h>
+#include <plat/mux.h>
+#include <plat/omapfb.h>
#include <asm/mach-types.h>
#define LCD_PANEL_BACKLIGHT_GPIO (15 + OMAP_MAX_GPIO_LINES)
diff --git a/drivers/video/omap/lcd_mipid.c b/drivers/video/omap/lcd_mipid.c
index 918ee8934196..8f3e2b4bb4f3 100644
--- a/drivers/video/omap/lcd_mipid.c
+++ b/drivers/video/omap/lcd_mipid.c
@@ -23,8 +23,8 @@
#include <linux/workqueue.h>
#include <linux/spi/spi.h>
-#include <mach/omapfb.h>
-#include <mach/lcd_mipid.h>
+#include <plat/omapfb.h>
+#include <plat/lcd_mipid.h>
#define MIPID_MODULE_NAME "lcd_mipid"
@@ -607,7 +607,7 @@ static struct spi_driver mipid_spi_driver = {
.remove = __devexit_p(mipid_spi_remove),
};
-static int mipid_drv_init(void)
+static int __init mipid_drv_init(void)
{
spi_register_driver(&mipid_spi_driver);
@@ -615,7 +615,7 @@ static int mipid_drv_init(void)
}
module_init(mipid_drv_init);
-static void mipid_drv_cleanup(void)
+static void __exit mipid_drv_cleanup(void)
{
spi_unregister_driver(&mipid_spi_driver);
}
diff --git a/drivers/video/omap/lcd_omap2evm.c b/drivers/video/omap/lcd_omap2evm.c
index 7a2bbe2ecec3..e1a38abca3e7 100644
--- a/drivers/video/omap/lcd_omap2evm.c
+++ b/drivers/video/omap/lcd_omap2evm.c
@@ -26,8 +26,8 @@
#include <linux/gpio.h>
#include <linux/i2c/twl4030.h>
-#include <mach/mux.h>
-#include <mach/omapfb.h>
+#include <plat/mux.h>
+#include <plat/omapfb.h>
#include <asm/mach-types.h>
#define LCD_PANEL_ENABLE_GPIO 154
diff --git a/drivers/video/omap/lcd_omap3beagle.c b/drivers/video/omap/lcd_omap3beagle.c
index 4011910123bf..ccec084ed647 100644
--- a/drivers/video/omap/lcd_omap3beagle.c
+++ b/drivers/video/omap/lcd_omap3beagle.c
@@ -25,8 +25,8 @@
#include <linux/gpio.h>
#include <linux/i2c/twl4030.h>
-#include <mach/mux.h>
-#include <mach/omapfb.h>
+#include <plat/mux.h>
+#include <plat/omapfb.h>
#include <asm/mach-types.h>
#define LCD_PANEL_ENABLE_GPIO 170
diff --git a/drivers/video/omap/lcd_omap3evm.c b/drivers/video/omap/lcd_omap3evm.c
index b6a4c2c57a2f..556eb31db24c 100644
--- a/drivers/video/omap/lcd_omap3evm.c
+++ b/drivers/video/omap/lcd_omap3evm.c
@@ -25,8 +25,8 @@
#include <linux/gpio.h>
#include <linux/i2c/twl4030.h>
-#include <mach/mux.h>
-#include <mach/omapfb.h>
+#include <plat/mux.h>
+#include <plat/omapfb.h>
#include <asm/mach-types.h>
#define LCD_PANEL_ENABLE_GPIO 153
diff --git a/drivers/video/omap/lcd_osk.c b/drivers/video/omap/lcd_osk.c
index b3fa88bc6269..bb21d7dca39e 100644
--- a/drivers/video/omap/lcd_osk.c
+++ b/drivers/video/omap/lcd_osk.c
@@ -24,8 +24,8 @@
#include <linux/platform_device.h>
#include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/omapfb.h>
+#include <plat/mux.h>
+#include <plat/omapfb.h>
static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
{
diff --git a/drivers/video/omap/lcd_overo.c b/drivers/video/omap/lcd_overo.c
index 2bc5c9268e5e..b0f86e514cde 100644
--- a/drivers/video/omap/lcd_overo.c
+++ b/drivers/video/omap/lcd_overo.c
@@ -24,8 +24,8 @@
#include <linux/i2c/twl4030.h>
#include <mach/gpio.h>
-#include <mach/mux.h>
-#include <mach/omapfb.h>
+#include <plat/mux.h>
+#include <plat/omapfb.h>
#include <asm/mach-types.h>
#define LCD_ENABLE 144
diff --git a/drivers/video/omap/lcd_palmte.c b/drivers/video/omap/lcd_palmte.c
index 4bf3c79f3cc7..d30289603ce8 100644
--- a/drivers/video/omap/lcd_palmte.c
+++ b/drivers/video/omap/lcd_palmte.c
@@ -23,8 +23,8 @@
#include <linux/platform_device.h>
#include <linux/io.h>
-#include <mach/fpga.h>
-#include <mach/omapfb.h>
+#include <plat/fpga.h>
+#include <plat/omapfb.h>
static int palmte_panel_init(struct lcd_panel *panel,
struct omapfb_device *fbdev)
diff --git a/drivers/video/omap/lcd_palmtt.c b/drivers/video/omap/lcd_palmtt.c
index 48ea1f9f2cbf..557424fb6df1 100644
--- a/drivers/video/omap/lcd_palmtt.c
+++ b/drivers/video/omap/lcd_palmtt.c
@@ -30,7 +30,7 @@ GPIO13 - screen blanking
#include <linux/io.h>
#include <mach/gpio.h>
-#include <mach/omapfb.h>
+#include <plat/omapfb.h>
static int palmtt_panel_init(struct lcd_panel *panel,
struct omapfb_device *fbdev)
diff --git a/drivers/video/omap/lcd_palmz71.c b/drivers/video/omap/lcd_palmz71.c
index 0697d29b4d3b..5f4b5b2c1f41 100644
--- a/drivers/video/omap/lcd_palmz71.c
+++ b/drivers/video/omap/lcd_palmz71.c
@@ -24,7 +24,7 @@
#include <linux/platform_device.h>
#include <linux/io.h>
-#include <mach/omapfb.h>
+#include <plat/omapfb.h>
static int palmz71_panel_init(struct lcd_panel *panel,
struct omapfb_device *fbdev)
diff --git a/drivers/video/omap/lcdc.c b/drivers/video/omap/lcdc.c
index ab3949256677..5f32cafbf74c 100644
--- a/drivers/video/omap/lcdc.c
+++ b/drivers/video/omap/lcdc.c
@@ -29,8 +29,8 @@
#include <linux/vmalloc.h>
#include <linux/clk.h>
-#include <mach/dma.h>
-#include <mach/omapfb.h>
+#include <plat/dma.h>
+#include <plat/omapfb.h>
#include <asm/mach-types.h>
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c
index 0d0c8c8b9b56..f900a43db8d7 100644
--- a/drivers/video/omap/omapfb_main.c
+++ b/drivers/video/omap/omapfb_main.c
@@ -28,8 +28,8 @@
#include <linux/mm.h>
#include <linux/uaccess.h>
-#include <mach/dma.h>
-#include <mach/omapfb.h>
+#include <plat/dma.h>
+#include <plat/omapfb.h>
#include "lcdc.h"
#include "dispc.h"
diff --git a/drivers/video/omap/rfbi.c b/drivers/video/omap/rfbi.c
index ee01e84e19c1..c90fa39486b4 100644
--- a/drivers/video/omap/rfbi.c
+++ b/drivers/video/omap/rfbi.c
@@ -27,7 +27,7 @@
#include <linux/clk.h>
#include <linux/io.h>
-#include <mach/omapfb.h>
+#include <plat/omapfb.h>
#include "dispc.h"
diff --git a/drivers/video/omap/sossi.c b/drivers/video/omap/sossi.c
index a76946220249..79dc84f09713 100644
--- a/drivers/video/omap/sossi.c
+++ b/drivers/video/omap/sossi.c
@@ -24,8 +24,8 @@
#include <linux/irq.h>
#include <linux/io.h>
-#include <mach/dma.h>
-#include <mach/omapfb.h>
+#include <plat/dma.h>
+#include <plat/omapfb.h>
#include "lcdc.h"
diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c
index 54cd91610174..966b226c858c 100644
--- a/drivers/video/xen-fbfront.c
+++ b/drivers/video/xen-fbfront.c
@@ -25,7 +25,10 @@
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
+
#include <asm/xen/hypervisor.h>
+
+#include <xen/xen.h>
#include <xen/events.h>
#include <xen/page.h>
#include <xen/interface/io/fbif.h>
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 200c22f55130..9dd588042880 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -19,7 +19,6 @@
*/
//#define DEBUG
#include <linux/virtio.h>
-#include <linux/virtio_ids.h>
#include <linux/virtio_balloon.h>
#include <linux/swap.h>
#include <linux/kthread.h>
@@ -248,7 +247,7 @@ out:
return err;
}
-static void virtballoon_remove(struct virtio_device *vdev)
+static void __devexit virtballoon_remove(struct virtio_device *vdev)
{
struct virtio_balloon *vb = vdev->priv;
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c
index 4a1f1ebff7bf..28d9cf7cf72f 100644
--- a/drivers/virtio/virtio_pci.c
+++ b/drivers/virtio/virtio_pci.c
@@ -530,19 +530,22 @@ static int vp_try_to_find_vqs(struct virtio_device *vdev, unsigned nvqs,
err = PTR_ERR(vqs[i]);
goto error_find;
}
+
+ if (!vp_dev->per_vq_vectors || msix_vec == VIRTIO_MSI_NO_VECTOR)
+ continue;
+
/* allocate per-vq irq if available and necessary */
- if (vp_dev->per_vq_vectors) {
- snprintf(vp_dev->msix_names[msix_vec],
- sizeof *vp_dev->msix_names,
- "%s-%s",
- dev_name(&vp_dev->vdev.dev), names[i]);
- err = request_irq(msix_vec, vring_interrupt, 0,
- vp_dev->msix_names[msix_vec],
- vqs[i]);
- if (err) {
- vp_del_vq(vqs[i]);
- goto error_find;
- }
+ snprintf(vp_dev->msix_names[msix_vec],
+ sizeof *vp_dev->msix_names,
+ "%s-%s",
+ dev_name(&vp_dev->vdev.dev), names[i]);
+ err = request_irq(vp_dev->msix_entries[msix_vec].vector,
+ vring_interrupt, 0,
+ vp_dev->msix_names[msix_vec],
+ vqs[i]);
+ if (err) {
+ vp_del_vq(vqs[i]);
+ goto error_find;
}
}
return 0;
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index f53600580726..fbd2ecde93e4 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -285,6 +285,9 @@ static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len)
return NULL;
}
+ /* Only get used array entries after they have been exposed by host. */
+ rmb();
+
i = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].id;
*len = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].len;
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 3ed571a2ab18..429ea99eaee5 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -43,7 +43,7 @@
#include <linux/io.h>
#include <linux/uaccess.h>
#include <mach/hardware.h>
-#include <mach/prcm.h>
+#include <plat/prcm.h>
#include "omap_wdt.h"
diff --git a/drivers/watchdog/sb_wdog.c b/drivers/watchdog/sb_wdog.c
index 9748eed73196..c8eadd478175 100644
--- a/drivers/watchdog/sb_wdog.c
+++ b/drivers/watchdog/sb_wdog.c
@@ -1,7 +1,7 @@
/*
* Watchdog driver for SiByte SB1 SoCs
*
- * Copyright (C) 2007 OnStor, Inc. * Andrew Sharp <andy.sharp@onstor.com>
+ * Copyright (C) 2007 OnStor, Inc. * Andrew Sharp <andy.sharp@lsi.com>
*
* This driver is intended to make the second of two hardware watchdogs
* on the Sibyte 12XX and 11XX SoCs available to the user. There are two
@@ -326,7 +326,7 @@ static void __exit sbwdog_exit(void)
module_init(sbwdog_init);
module_exit(sbwdog_exit);
-MODULE_AUTHOR("Andrew Sharp <andy.sharp@onstor.com>");
+MODULE_AUTHOR("Andrew Sharp <andy.sharp@lsi.com>");
MODULE_DESCRIPTION("SiByte Watchdog");
module_param(timeout, ulong, 0);
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index d31505b6f7a4..826dda414166 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -52,6 +52,8 @@
#include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h>
+
+#include <xen/xen.h>
#include <xen/interface/xen.h>
#include <xen/interface/memory.h>
#include <xen/xenbus.h>
diff --git a/drivers/xen/cpu_hotplug.c b/drivers/xen/cpu_hotplug.c
index bdfd584ad853..6625ffe1a6fd 100644
--- a/drivers/xen/cpu_hotplug.c
+++ b/drivers/xen/cpu_hotplug.c
@@ -1,5 +1,6 @@
#include <linux/notifier.h>
+#include <xen/xen.h>
#include <xen/xenbus.h>
#include <asm/xen/hypervisor.h>
diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c
index 79bedba44fee..f70a4f4698c5 100644
--- a/drivers/xen/evtchn.c
+++ b/drivers/xen/evtchn.c
@@ -48,6 +48,8 @@
#include <linux/gfp.h>
#include <linux/mutex.h>
#include <linux/cpu.h>
+
+#include <xen/xen.h>
#include <xen/events.h>
#include <xen/evtchn.h>
#include <asm/xen/hypervisor.h>
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index 7d8f531fb8e8..4c6c0bd636a8 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -37,6 +37,7 @@
#include <linux/vmalloc.h>
#include <linux/uaccess.h>
+#include <xen/xen.h>
#include <xen/interface/xen.h>
#include <xen/page.h>
#include <xen/grant_table.h>
diff --git a/drivers/xen/sys-hypervisor.c b/drivers/xen/sys-hypervisor.c
index 88a60e03ccf0..ae5cb05a1a1c 100644
--- a/drivers/xen/sys-hypervisor.c
+++ b/drivers/xen/sys-hypervisor.c
@@ -14,6 +14,7 @@
#include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h>
+#include <xen/xen.h>
#include <xen/xenbus.h>
#include <xen/interface/xen.h>
#include <xen/interface/version.h>
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index d42e25d5968d..08638adec9fc 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -49,6 +49,8 @@
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/xen/hypervisor.h>
+
+#include <xen/xen.h>
#include <xen/xenbus.h>
#include <xen/events.h>
#include <xen/page.h>
diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c
index 6559e0c752ce..8924d93136f1 100644
--- a/drivers/xen/xenfs/super.c
+++ b/drivers/xen/xenfs/super.c
@@ -13,6 +13,8 @@
#include <linux/fs.h>
#include <linux/magic.h>
+#include <xen/xen.h>
+
#include "xenfs.h"
#include <asm/xen/hypervisor.h>
diff --git a/firmware/Makefile b/firmware/Makefile
index a6c7c3e47e42..45c04660a44d 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -32,7 +32,7 @@ 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.0.21.0.fw bnx2x-e1h-5.0.21.0.fw
+fw-shipped-$(CONFIG_BNX2X) += bnx2x-e1-5.2.7.0.fw bnx2x-e1h-5.2.7.0.fw
fw-shipped-$(CONFIG_BNX2) += bnx2/bnx2-mips-09-5.0.0.j3.fw \
bnx2/bnx2-rv2p-09-5.0.0.j3.fw \
bnx2/bnx2-rv2p-09ax-5.0.0.j3.fw \
diff --git a/firmware/WHENCE b/firmware/WHENCE
index c437e14f0b11..a07aede9fcc3 100644
--- a/firmware/WHENCE
+++ b/firmware/WHENCE
@@ -674,8 +674,8 @@ Found in hex form in kernel source.
Driver: bnx2x: Broadcom Everest
-File: bnx2x-e1-4.8.53.0.fw.ihex
-File: bnx2x-e1h-4.8.53.0.fw.ihex
+File: bnx2x-e1-5.2.7.0.fw.ihex
+File: bnx2x-e1h-5.2.7.0.fw.ihex
License:
Copyright (c) 2007-2009 Broadcom Corporation
diff --git a/firmware/bnx2x-e1-5.0.21.0.fw.ihex b/firmware/bnx2x-e1-5.0.21.0.fw.ihex
deleted file mode 100644
index c51afd44a23d..000000000000
--- a/firmware/bnx2x-e1-5.0.21.0.fw.ihex
+++ /dev/null
@@ -1,10184 +0,0 @@
-:10000000000028B0000000600000068800002918E9
-:100010000000161400002FA800000098000045C042
-:100020000000738800004660000000CC0000B9F0BA
-:1000300000009A4C0000BAC0000000940001551066
-:10004000000057B8000155A8000000B80001AD68D5
-:100050000000CE1C0001AE280000000400027C4815
-: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
-:100530000718040000960000081807600014022342
-:10054000071C000034B80000071C800034E90D2FA0
-:10055000071D000009DD1A6A081D14005D800225D0
-: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
-:100F1000020E005800000007020E005C0000000FE7
-:100F2000020E006000000010060E006400000004C5
-:100F3000020E00DC00000003020E01100000000F92
-:100F4000020E01140000002F020E01180000000E16
-:100F5000020E011C0000002E020E00040000000121
-:100F6000020E000800000001020E000C000000014B
-:100F7000020E001000000001020E0014000000012B
-:100F8000020E001800000001020E001C000000010B
-:100F9000020E002000000001020E002400000001EB
-:100FA000020E002800000001020E002C00000001CB
-:100FB000020E003000000001020E003400000001AB
-:100FC000020E003800000001020E003C000000018B
-:100FD000020E004000000001020E0044000000016B
-:100FE0000730040000C900000830076800130282BF
-:100FF00007340000341200000734800037B70D05B5
-:10100000073500002E7D1AF308356F405218028410
-: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
-:1012400008200780001002A9072400002CCF00000E
-:10125000072480002AE50B340824DC6062DA02AB44
-: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
-:101EB000020201F0000000FF0728040000B4000047
-:101EC00008280768001302F4072C000035D700002B
-:101ED000072C80003A590D76072D00003B741C0D2D
-:101EE000072D8000226C2AEB082DC6F0472202F64F
-: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
-:103B9000000000000001000100150005CCCCCCC1E4
-: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
-:103DE0000040CF3CCDCDCDCDFFFFFFF3310FFFFF26
-: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
-:10450000000F024000010330000800000008008096
-:1045100000028100000B8128000201E0000102007E
-:104520000007021000020280000F0000000800F0E7
-:1045300000028170000B819800020250000102709D
-:10454000000B828000080338001000000008010002
-:1045500000028180000B81A80002026000018280BD
-:10456000000E82980008038000028000000B802863
-:10457000000200E0000101000000811000000118AD
-:10458000CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC6B
-:1045900000002000CCCCCCCCCCCCCCCCCCCCCCCC6B
-:1045A000CCCCCCCC00002000CCCCCCCCCCCCCCCC5B
-:1045B000CCCCCCCCCCCCCCCC00002000000000007B
-:1045C0001F8B080000000000000BFB51CFC0F00360
-:1045D0008A7BD81818367020F843015F646260B88F
-:1045E0000CC45781588099812198918121849178B8
-:1045F000FD49A208F62B210606316106866841A016
-:10460000B9C208F1A3403556220C0C7FA1628D403F
-:10461000369B2875DC3FD0789314A6D87A09047BA2
-:1046200033167964BC054D9E4F1295BF9580FE816F
-:10463000C68F1551F9620A103A1F2AFE044D5E1CFE
-:104640002A7F19EAAFA78AD8CDBD02950700C8E92D
-:10465000674460030000000000000000000000004C
-:104660001F8B080000000000000BED7D0B7854D577
-:10467000B5F03E73CE9C9949662627214F1E6112E4
-:1046800020828638BC0228BD4E0844AC5C0DF8423E
-:104690008B3ABC43DE50B4B4B55F2610224F6FF0A6
-:1046A00047452FD8E161458B3660A4D1021D4010EB
-:1046B0007BBDB7C1528BD5FA4554500C24728BD2B6
-:1046C0005B7BFDD75A7BEFCC39930960FFF6FEF791
-:1046D000BFDF1F3FBFC33E673FD65EAFBDD6DA6BBD
-:1046E000EFB1B334A60F64EC6BFCBB81B11A1B6352
-:1046F000F0AAFBF9949DDD5FEA662C6FA36FB93BCE
-:1047000015DEB7E6EC4AF43196B577BD3211DE67B7
-:104710006D6A5266E747DB8F76C1C731F0BE75BD63
-:104720005204EFB3DE6C5266E1D361636D509F6952
-:10473000BE24864F16602C9DB141E398F80BB8B3A8
-:104740000A19EB8FFF842ECE1B89D01963392B6C8D
-:10475000E19002EF8365539997B16D0057560AB403
-:1047600053BF3A60C7BAB5DAC97627634ECDA97D83
-:104770009DCB58F60C6663F01CB894BFC7BFAFE181
-:10478000FF9C90B53C8899CA3958F6A49E8221991D
-:104790008779BE56E3C1DBA5970E8FCE533E37D542
-:1047A000F9D2DD5ACFF7F2B978D127FAC3D0FA6936
-:1047B000AC3798B1704CFDAA90AEB16BE1090868B6
-:1047C000CEEFD97E2A2B2A443ADCC726D2B346F351
-:1047D000DD8578A9396A672180BBA6F65409965908
-:1047E000ABC286E4F46C3F9CD9891E454CD14EE1A6
-:1047F0007CBDCC8BF3532B7D4F94009EE726062681
-:1048000061BFEB1283F494EF33674FC90C023CC5D0
-:104810000BF2430CE87E7EA3E27740F3D34A58B70D
-:10482000033D2A6EAF2DB811EAFD560FDE8CED2A3E
-:1048300067B41D217AB0DA3CC4539BCEF967606B34
-:10484000D1A71AD00D582C9494827461ECA4890ECF
-:10485000F87772A828ABBDE3F172CFB9D88F86BDC7
-:104860008469BEF27D4EE8E8A0C131E3B14282879F
-:1048700031E471D6AEC4A3EBC0578A8E6A05BD8FF2
-:10488000F7F79F4788CB21E00EE95BE5D1C3CB80EA
-:10489000BEC52FDB2337003DAAB6286107946DFB08
-:1048A0005D01A4CFB9ED5006BA443C3AD53F6B3810
-:1048B000A95CE3687BE47A2877BDACB2ADD8EDD0D3
-:1048C000041BCADD29013B1B0D65C0C77C172F5691
-:1048D0006D39701FF657D6EA602EE8BFEA9505B726
-:1048E0005C0FE505C06F58A5EA997ABD2F9417862D
-:1048F00095662C774E64C41FA1143DFC0C8CD7E93F
-:104900006D4BBF03E4E54C9D93F90094E59EB6F42E
-:10491000DB818FCAC3BB4AB05DF94EC58F682F7E5D
-:10492000F999235938AFE780AF808F2A7624329FD8
-:10493000C41FFC7F0AA672037C5F0CF344F95FC0BE
-:104940009A4A988AE3AFD77D9E28BECED419344EBA
-:10495000B73C3D07E340BBEA17153F4EB1DAC682CC
-:104960002857E75E71CDD8E6C6F9D5EB791E9CD7FE
-:10497000C33AD65B109EB507555679788B5E02DF39
-:10498000CB376DD1E7E723DE40EFE5235C7DAC70EC
-:104990006D540388DFC5C9CEAD2AE087B90399D32A
-:1049A000E3F0CF993A506379D17239CA37E993B0BD
-:1049B0003ECD54BF4449267EADD8A1329F859F3855
-:1049C000FD43C738FD43FB3CE16772A2F45B6C70AA
-:1049D0003D29E9B73859D053EB2A8C07CF23480F2C
-:1049E00080A709F105CFB5023EEF0456A4015DBCD6
-:1049F000016628ECF2FCD96467B3188CFD169B178E
-:104A0000D0C64359678B989F3143AB0A4C82F2570B
-:104A1000ACF44D9C0F637E5F29E0B951613370DEC9
-:104A2000871158984F63964EF86B9A5CB84D5504B1
-:104A3000CCA9589EFF93D539D4FE38B5D7A0FDF048
-:104A4000DEDB1B25E32CED8D9232D9FE3DACC79CFD
-:104A5000976EDF54729D75FC9272D9FE231ADF7D2A
-:104A600069F88D1B2758C7BFB192DAD73838BDBA5D
-:104A7000929DE1AD506E70F9031AD24D63117CAF77
-:104A8000A5E46DC57AAAE407D61650A1BD7B67F2EE
-:104A9000C8D5CCCC1713FF88E379405ACC7C91342D
-:104AA0002EC1C28FC981144B197A324E5D13D54382
-:104AB00001AF93E0D1FBEAA42F8AFA3A09DE07F7A7
-:104AC000BBA8FCE0751CDE07FBBA49CE10069605B4
-:104AD000653D78AD615A8F004E856532764109BAE1
-:104AE0009431E6F73E1BBE4F50592DCE27C1C14829
-:104AF0001F3D9C53B82D64C2CFCA01405F28A72A2E
-:104B00003AC7A3C0EBC303E667CE328DD338409FCC
-:104B1000B1359FBF9FE3C6F14AD315D4837A579E20
-:104B2000E1EE398E23779C651C6776198D931333DC
-:104B30008E23BB2C661CE78CADE2BD1867D0A5C6E2
-:104B40007938F73AEB7CB2CB699C82D8F96497C785
-:104B50008C93C0E703EFC5387EC45FAFF31934C14F
-:104B60003A9F819534CEF538CE18D37C0656C68C44
-:104B7000E3A671F03D8E0386948F6500DD1D5DF325
-:104B800089FEBF7491BDA03B82CF62BFEC5D17234D
-:104B90007DE283713350AFC0E20CF2AB292934CEF1
-:104BA0001709407FB799CE5C1FD113F4CF3C012287
-:104BB0000B0344A07FAA058FCEDD392DBB1E9FAD10
-:104BC000C599B3D02ED9E0F10F01D139D75AACCF66
-:104BD0008963DFCC6BB29F6AB7F0AFD07B13D9D0BB
-:104BE0005A18BF05958DA97C0AF41703BD7512F4F8
-:104BF000173E4F0BFBF423D06F4C37C35B4FF3389A
-:104C0000A5713C9EDAC4D7912FD61FB383B187C359
-:104C10001CCF07B8EF14D398D704C69F49CE6A04B7
-:104C20003DBA5E7184B7123D02FD6CC0E76C631F34
-:104C3000C095A80776E61F843D0A7FFD6C60CBDE39
-:104C4000B372D761ACF6B6326BC06298EF8C96F552
-:104C5000F67E503E676FBFCFEF36F533C37E12E767
-:104C6000ED84FFB09FBB83768B7DFA9D326BF9DEBE
-:104C7000187BB552C915F410E3FAC276A4D79DE9A2
-:104C80001C9E7BF139123F1B44AFFB0CDE56C25316
-:104C9000F3433B8BD07AD49EC6F2111F696417058B
-:104CA000E5BA1203DF7D7667A014E879DFF755C215
-:104CB000632CBCEDFB130336B097DA37FEBB1DED5A
-:104CC000EFCBC17FFF52EB7716E2E349BC4A3EB817
-:104CD0006B46519F8F4CF5EE0EDED4E72313BF7C5D
-:104CE000A76C9AA57C6FEDDD96FAF72F9D65F93ECE
-:104CF0002BB4D0F27DCECA4596F2BCA6EF5BEA2F6C
-:104D0000D8586FF9BE30BCCAF2BD62C77A4BB9AA97
-:104D1000F9494BFD9AD62D96EFB6FDC36E45795CE9
-:104D2000FE5B95A17D76C17DEA11B4AF2E189A1F66
-:104D3000EB5423AF811C7E529749FC7DA6CE47CF12
-:104D400073ADA39C688FD724803CC35ABF5FF943DF
-:104D500068E504D423501F74F841E5C350089CA7AC
-:104D600037141FF1BDBA516711605585A574F375ED
-:104D7000971AFDAEB5C3F751BD7F57376A71BF6B48
-:104D8000ED5ADC7E3B95AE3CB4EF42EF3818DA8149
-:104D9000BDD90FF0D70FD78BDEBE77D85859B3499E
-:104DA000EF9C526CC407772A134FA17EAED4B9BCD6
-:104DB00057EECE9A88FE60A51EC9AB755F62BC66D1
-:104DC000002603FBC9A5792D0CF78BCA2FD16F9054
-:104DD00045EE97B0E0C7A89F3B0EA8A46759E450E2
-:104DE000F66DC371FCC0297CCF5AD3687D7CBB2E85
-:104DF000D0E723F0E74ED44DA1E7EFEB4AFB7C046C
-:104E0000BAE6BDBA19547EBF2E48CFF6BA327A9EA2
-:104E1000ACABA5EF1FD52DA5F2A9BA103D3FA95BFC
-:104E200049CF33754DF4BDA36E2395CFD585E9D910
-:104E3000ED07087B94A50AFB4FD8EBB07250F9BC84
-:104E400098830AFFE67EAB3F13E5FABCFB8B3CB4CC
-:104E500073CF9F00C3248E7F289FB1FCD63BFD02F9
-:104E6000B4DECF0F03FD47F5FCEE4AE0F471D9D86C
-:104E70001406FA67D5109D69307EC22FAF217B19C9
-:104E8000DE6B8CF465D83FCD13A77F9C73C6E5E934
-:104E9000D4CD1F4FFDB910E30F770A7D987048AD50
-:104EA000E574DBE647BA99F0C7EDB297853E8FC14E
-:104EB00023D972593DF179364DE2B32D1BE3001B26
-:104EC00094D26136E083F32D0E9AD7F9BD896186BD
-:104ED0006D313832FE5278E37054EC701966FD5033
-:104EE000D59C6C58F5459661D617E78F6EF3A2DC1A
-:104EF0002FCEB4191F8D42FE0808FEE07C27FBAFC1
-:104F00006ACE31DC967EACE5F34DCA14F48340B929
-:104F100027DD1EC73F90CFC599BAF111C8F7991D7B
-:104F20008392705CF0E30C1CA7A3CE30F8B899868E
-:104F3000992F2B9726507D095F6FFDFEADE143CB86
-:104F4000E0432723D47F3DE89BFBD94CFB23C5736B
-:104F5000D85EFB17B8EE38E0FFAF291EA05159F616
-:104F60005BD3AC861CD7E2FB9D96F1A09D4FFAD097
-:104F7000B85EF54E778D9D32C505AA710CF28F9CF7
-:104F800044E720F49804FD756AEE950A8C33C5E673
-:104F9000A3EF35821FAB9CED7A105E9D6DE1F4E8C6
-:104FA0006D9C3375477D1AE88F32277864304E59EF
-:104FB000F3B049A81FCFB62C4F0F02DF56A8E71F4A
-:104FC0002C8DD37EA54DE1F084ED5DEDA6F9C838BA
-:104FD0000A63D0AF330A3F72FA295339565FCBE7E1
-:104FE000A3D82FF047F5CE6325D703FCD5AD9FEBB3
-:104FF00008C7145BF0515B5A74FE0ACE1FFA29DF12
-:10500000F1818EF3FBC41ECAFBE125F4544F38DD59
-:105010009914B793F085581BDA31B3BBE38ABEBB52
-:10502000DE05D1FCF45FEC6C35C0C1BE825AF0DD08
-:105030002EBECE65A55EC4D7EC960A8A2F7E6A93F3
-:1050400076535321F2C759669B82F33BCBDEF28E37
-:1050500032E1AFC5C6ED7EB692DB3121F80FE1013A
-:105060007BD662D72CD8682DCF67D3D3516FCCDFD6
-:1050700060676140D142B48B247FC0BCB7DBB8BD50
-:10508000BB80D536A23DA739B87F30DB605A3F8060
-:10509000ABEAE79B0BD1EEFF85CD46F49171868597
-:1050A000291CEEF2D4B01E80EF1FB68CBAF37AE45E
-:1050B0003E47B811D76596C4FCCFB09EF89CB3D2DA
-:1050C0000ADFE5E08F8597B165163864BF120E756B
-:1050D000871208C7E1BB3724DF093D92A25AEDFCD5
-:1050E0008C98F27B3611BF54998A743E6B3843B664
-:1050F00024FAEE8F607C64B7C3BF1CE8FB80ADB4BC
-:105100001DF533D80505CC54EF015B90DE77286F91
-:10511000CE47FB94699102F4EF614DD1901F74C1A9
-:105120000F6A82B700E3B11E06EB27C8A503E1832F
-:105130007E1A3D65535901C65F414EA1BF75DE928F
-:10514000A30A945DEE1686FD3932ADF16597CF5A0C
-:10515000AEC17F201D86328AE3240EB57E87058B83
-:1051600021BF79FCD6F7FFD18DA708F1AD97581A6A
-:105170009E4E774485F1D938ADC36C37573B39FC27
-:10518000E49743FD25C29EAF66BE10C58933391F23
-:105190002CB9C946F02CF1F8FC21F8AE680186F272
-:1051A00087B16AF33A56731144AE8FA9AC75E9C85A
-:1051B0009735173516067D5F600B7AD43188BF00AE
-:1051C000D9B94E40D6D700B2E69E62B17B59FF14E2
-:1051D000B1BEF637CCF2DA1FE93C264A67A917ECD4
-:1051E000422F82BEC850D3500F7695905FC2DA49E5
-:1051F0004FC87A7AB45E7F84A3B77AAE68BD9C78D4
-:10520000FD55FDFC853D21C07FF9CF1EF302F1D98C
-:10521000A75A53BA1FDE573EB3C28B7CFC8916F2E5
-:10522000E2BC3F0DAB53E2F1F39DAA22FCB1805BDF
-:10523000417F58D0E9CCF36B6E41BC7FF18CDDC06F
-:105240002A353B1C110710B1BA6521E7A71D8E0F47
-:1052500078F9E1CF919E35AD56792B7FF6B1748CFC
-:10526000770286B8DFC822643F576FFFB804ED911C
-:105270001AD6457A22B61D8E7F3185D6AF597A521D
-:10528000CFEF72FFA546F07D4DCB9ACF552F96AD4F
-:10529000F25D26FC911B554F2AC595C6B2B1483721
-:1052A000890716E6F6F0F2E79E28F800E0E8D8FE57
-:1052B0002F5EC51237E2FAE17CF39C1FBFEAEB5D7B
-:1052C000AF9F13FE7CB45D98DAF95AB9FDCEF6F2C1
-:1052D00067A53DE2457FA9728BDD0F92C92A5FD891
-:1052E000F693A790AFDF71509CA1E285C36F5F0773
-:1052F000E58A5DF6D4A97C1A6E253D4A8F1AF87F9F
-:10530000E9C828FECB5F3AACFB86F3F70FA544E96A
-:1053100050B1EB80CE86F7C45B71F301BDDD1D8714
-:105320001ECD1F94A0BDBDFCB92F7594AB4FF72BBC
-:105330002C23A767FBB22D87C99E433C11FD047D3A
-:10534000BAE9D5834E915B5E1D4DF50C5CBF7AA327
-:10535000D3D5B8F6A5111FBFF82AC6EF7FEFF0E34B
-:10536000FCCB5EFCAE17E7715AABE5FCBC79457A25
-:1053700000C62DB387D20D7AF2F7654F3F407CB659
-:10538000E0D803E9140F60812C1BADA1A12C9CDF98
-:10539000BC4D77D0FCE6B320F15BD966B5348CF117
-:1053A0002C8D4DD915471EDE14F2707AAB03D71E33
-:1053B000761A152CFA876FA9B44FC0D8228A373CC9
-:1053C00020F721D8622A5F70723A6D536D32BEE1C8
-:1053D000B4F0E9F687DB903E67060432303E097888
-:1053E00008097C29A877D4639333387D984F2B1410
-:1053F000ED402F16E37BACDF660FB80A2CEDC43A04
-:10540000C6C75F22C607B813D01E3B9D0EF64D9C43
-:10541000F97DA94ABD0CF68689BF4C72CDE57CFBAF
-:105420002A2ED752CEC3D3A6E0F73F1EE7F283ED74
-:10543000705D07B82219F4FDC0ED0AE901078BC4BD
-:1054400093E7ED7621CFD6EF727F12E0D6707D8A9A
-:10545000F209F49F42F8273B6DFE066867D2CB3510
-:10546000381ED5D3A3EF4DEBFA0221FFAFAB627F1D
-:1054700054C83FDBC4E5BE77BB37C4FD037BF827C8
-:105480004FA1BC827CE23A53F982BD14E7FDD9CE2C
-:10549000436FDF037CFD59B39453ABDE8C95D3B2DD
-:1054A000DD63583C39FDCCED6771E514DEC79553DB
-:1054B000773BF1F1DF5B6F4ABC9D8BD19B520FF6BE
-:1054C00086BF583DB856F5C5D583F0779C15F6E4F0
-:1054D0003BC96F92CFCA7F5A3590E246921F25BFD3
-:1054E00075F3A3E4B7D8795AF116FBFD15A16F2423
-:1054F0009DEDCB58C883F1D27D2AF9D79D00532367
-:10550000D0B773674E18E3CE2B5C3C7ED1697479BB
-:1055100053E0B9229997BBD2F446D40FF27D978B12
-:10552000C7B73B4BBBBCC926BFE283BDAAD707DFC9
-:10553000DBC36C4A3C7F03342FC1D1CE7AFBCEE370
-:10554000C1935577F652F4DB9B54DACF9E5B7F977D
-:1055500017F7813BF70EFA27D44FF3DE000313E071
-:10556000ED443B3009A717D0302F618EA0F7272CD0
-:10557000F4F80498DF9CBDDC5F98BB36C6BE772F7D
-:10558000D151DF807D7FD21AD7E67C532EFA29DBFA
-:1055900064FD5ECED612DDCA63F82828FCC0B19A3D
-:1055A000E0A3116C84F0C378FC42E8ABC96AFE3F0B
-:1055B000A19DD17994C715CFEF5509FFE7772A61EF
-:1055C0008CFB507C773CD2BF4B67267FB903F94DEB
-:1055D000EF5D8E3B5EFE43E10FA14AE59E770BFE39
-:1055E000199E1D7BDEC9FB05967FFEBBEC7759CF6C
-:1055F000FAC5FBFF44FBC79DFB1D0447E7FED7B37D
-:105600007F88E5571D7E84B3739983F6CF42FB3DB7
-:10561000E121F87D00D01BD7CD7D5F16B4D3BAD37E
-:1056200040749AADF1FD8EF37BFFFCBE82F9077BDF
-:105630001D3E9C47CD7E9E1752F3AA8BE22E9DFB0A
-:10564000BE2C0CBAFF76F3A9D65990F8CFC366ECFE
-:10565000467E4DE6FB0035BF18BFAD1EF7C35B0E9F
-:10566000E8B8BF52FCCBBF14A07EE9DCCDED84735B
-:10567000F6F6A7711FB44A1BBCCC8E728F365B5FE7
-:10568000B03BEDF32686F2E3E185E3A113F080F36E
-:1056900002BC94A15EEC0D1F0D1AF737FFFBE1E38E
-:1056A000F3FB70FCCABD63496EA2785102FCBD27B2
-:1056B000EC5468FEFCFDFE2F0BD0EEF9ACB99ED683
-:1056C000F1CBCD7BDBFFB8792B912B99F7C1FFE6AE
-:1056D000FC3F45E3EB52AC1CF4E4F39F3F48E51775
-:1056E0003D7E82F70AE5FFE4FF34BAEF06BA7B2F6E
-:1056F0004F77C5FEDF75DE97A3FB1B82EE1E03F31B
-:105700000A3AF7FD85E2E572FE979BB7EFFFD17984
-:105710004BFB67B5CDDF940BF5D7B2489B0FE05C30
-:1057200031747A138699C04D288D678F94DAB97FCA
-:10573000A42A3C0EC306F0B81013FE04A580F9306D
-:105740008E329FEC3ACDDD487626D3FC6D01C0C782
-:10575000EAAB67FB2957838D3C11C472FF097E8A2F
-:105760006FC6F8550D0A0B2860EF69577FFB28DAE2
-:10577000F9F6A1B688A3809E1FE0F36111C7B21BA2
-:10578000BAC59F70C7F8032E9FF5BB43F4E76423A7
-:105790009B72314FC1AD196118DF5DD444F3710FB5
-:1057A00061ACC9B40FE860A6F6D05F3E06604DF666
-:1057B000E337C55F7D37FE46B605107FC36C14D74F
-:1057C000A2A43EC2873FBC9AFC4CEE3F46F1D9D81A
-:1057D0008678D418F87F7C7EE43732E12F6AA20BFA
-:1057E0006DA82DE0B2D6137ED165E9C3E9915D299C
-:1057F000E8B3D8420F89FF3874B1D043E2F79BD2A7
-:1058000025961EB178BFDDCEE36DB174B2E477A406
-:10581000713F24027EC8EB3BB751BCE3ECF31FDCC5
-:1058200082F52B7EA13227F4736EA78745507EB593
-:10583000B08EFE54798B1A37CE2BEDF28A9F7968A1
-:10584000BCF2DD8EF054685FBEE7C302B29B967572
-:105850001DE9877181E7154EBF507B01EEDB956B2B
-:10586000DC3F88ED6F939DC7053A5E499C81F10747
-:105870006507CF572C6FBECBEE30F1DBFFB2F3BC28
-:1058800057A847F21C7A4EA1F5A6277CDC2FE878B2
-:105890004EE1F0B5DAC398F758BE638B1E44BF7271
-:1058A000C7E714C72EFED90BDE76F21755ABFFBC47
-:1058B00043257AC293E817EBC756B754919F50DD42
-:1058C0002CFCC4183FAAE267FBF6840035152F3D77
-:1058D000EBC5F8CB99B667BCE49FEEE0FEA7E6D631
-:1058E000E2FBA797F34B9B57C5F54BCFE03FC09F1B
-:1058F00038608FF1E777F4B9B2FDCB172E3C8D718C
-:10590000D28EDD9F3D8D7057FEE7BF3F8DF63DDBAC
-:10591000EF329E81F9D63CFF5B8A37C976EF0A39B0
-:105920003D378085B2A0DEB9771C943F726EDFE907
-:105930006CF4E7CEEDFA533AFAF54BF64DCEC0795A
-:105940002F79B93883C59177F944BE0C5F419C30FB
-:10595000960E875A0E911F72F68483FCBEEEF842B3
-:1059600073158FD7F8445C6167FC38ACF487AB5B88
-:105970003E2CE1F131E1175F2E8E701CE878ED15B9
-:10598000D06BA78813C5D0EB2CFE03E8F2650CBDE5
-:105990002EB0E08FB3701FB2A54FAF7184C815E071
-:1059A00049C6778FD803361DE5607762379DA622FA
-:1059B0009D5EB8908DF1F04FEC5D64F774ED731857
-:1059C000E8DF97EFFB1DC9C5B9978F51FC94893863
-:1059D000EB39D6FDC7E3628A98DF760F8F3F087CEC
-:1059E000637CC2E7A5F7220EC1F955C6277A8B4B17
-:1059F0008CD545DE93883B576D7F576731711E65A7
-:105A00001CD2E9034B7C5CCE3BB63F03F130D61C85
-:105A10005F8B1FF7917E73944E3CAE26E367E7B62B
-:105A200088B81BBCEF3F12FD411EC7A8092BBF63FE
-:105A300071E450C6D746EA317218BEB2B8DAE5E072
-:105A4000FD6BF13144E7EB83C44BC757F1F5F03FF1
-:105A5000EA5CAEA7D8825375D37EF6FD629F45E21D
-:105A60004BC2DB21F2F03A9E57291ED4D87C88F431
-:105A700069AC3C57F7720EE23E9DC75BAB5B0F14FF
-:105A8000A0DEE938F80AF15DF5CE0FF410F4736486
-:105A9000C74B3AB727399FA39E0E9BF474C78B0759
-:105AA0000A78DC8FE7DDC6F65F21FAAFD96BEDBF70
-:105AB00066E7E796FE2B42CDB4FF75B971CE6881DB
-:105AC000BB70BE67DAEC0CF5DD9966754A389E1D31
-:105AD000A8DB2DFBA08DC7745AAF46BF9540F9B91E
-:105AE0004B8E4D793709F7E940CCD0FE6DA9E77CA4
-:105AF000D5F2A3403FA44BCBB17B545C37F6201EBC
-:105B00004D7670E1F1DA620FC86BE17BA5A391AD30
-:105B100062F5C0D813360BDC304E06EAE306E80720
-:105B2000F3E9317F08F747556FC9148447356C8610
-:105B30002BEEFAC9FBB3BB4B19DAE576C39AAF9CDF
-:105B4000395DC4D122D6BCF54C9D0DC57D70664B28
-:105B5000F0E37EC0E26181118731AF7E5E26C589A8
-:105B6000B36EE3EDCE1AEE90EDDAE8BE6DE245E8F5
-:105B70001FF3606CE1F533A15DA2D6ACE03E003CC2
-:105B800019D2E5015B70AB9E86F574E603D5F8B4D7
-:105B9000AE68947F21CEBDC8FE64BDDEF683E539D4
-:105BA0002455C03F48EC070F60ED0AEE076FF2F096
-:105BB000F34803DDA974DE689BB0DB7CB8EF8AF59F
-:105BC0006AADEBF665CF23ADB496538B8B160DF40F
-:105BD00033F661E383C51AE883D4BB8A76F5337064
-:105BE0005F7A4331E6DDA73E5B34220BCA77398604
-:105BF0004FA2EFBF2E1A910DE55AE7B849F4BD4206
-:105C0000A1BCC07D7A6771283F2A9F6960DC62BEB3
-:105C100005C8ED4194DBB3A51D8DF8B5EA8E2F7450
-:105C20007E1E8695E2FC078CE3F3EFEF7E6F17CEC6
-:105C300077A0ADBD1EF9EFC7FBBE4CC67A3E66D05D
-:105C40003C0DD660E0BE3CBC1AF7F525F27F62F34E
-:105C50006024BF6F4B0CFE06E158357BE81325A886
-:105C6000532BFDC447B1FBC4CC4825BACC157441B5
-:105C7000389DA63CE4056A88F25EF04402E5F5B082
-:105C800049068EA7842AD5AFAFF9E6709DD645BEEA
-:105C900081380F663A2F7506E15D9718A467EC7995
-:105CA000A9837A6907BECF9A7F311BE721CF4115BF
-:105CB0002F70537CE0FC5E1676C49123F9DC5AC742
-:105CC000D2B4C1BD7FFF8D23F81FD87FEE2F7DBBDF
-:105CD0008F427FD7CED5FD98C276EDD2D169DA2832
-:105CE000C627847685A05F26D214E5EC41C6CFE7AF
-:105CF000389400FA8F9DDF35480FF79F3B95FC8C59
-:105D0000CEC49C66CCA3E8FC21CF0780955E417988
-:105D100018B03729827E10F0F31731FCFC8575BD71
-:105D2000B18EDBF9B5AFB59DFA33447F60F0A4A323
-:105D3000FCF0BF4E95DBDB9D753E8203CCC303B800
-:105D4000AE5EE978590E110F17F401BCF77398F0A5
-:105D50003ED0D12BFD721D9C7EF48CA5DF7C676D3F
-:105D600036CA7379697309BAA8BFD5835761BDD3A1
-:105D7000F38F34DAA15ED5CCDA3C64F69E74E5E7A5
-:105D8000B1D2F7CEAAB763BC02E9E2EB49BF6B9789
-:105D9000FAD3B43E167A8E72403FD7EEFDDC8670A1
-:105DA0004B3A3E21F2FC63DBFF834311E356D6DB23
-:105DB000314ED2AA933D1B5B6F0A1EAA1A132D17F0
-:105DC000380B69DC0C1B8F77F4ACCFD7BF68BF4EA4
-:105DD0003A97D51B1F1618BC3FC0FBB7117E89F739
-:105DE0005B1C42DFF6C4FB34AC0778A7E715E0FD87
-:105DF000CE4BE15DDACF15421F54E0FE09F0CDC76E
-:105E000081E9E98361DC12D54D7CBFF01995E40D81
-:105E1000EA4FCD4A8FEA8F85E36B0FE03C176E5651
-:105E2000883FE78AF3A59F897CFED83CA8F93342D6
-:105E3000B4AFD3231F2A1CE3CFC5E4B95747F97485
-:105E400020CF4FE3E7B5542107C50BF293D00EDA0C
-:105E50006FF7FD9AECEB3754B6350EDE89B9D2A256
-:105E6000E501B5364B7E2C9B9B6CE977D2827CDAC0
-:105E7000EF5EECF15DD29F1AB8D4BA5EE784ACE76E
-:105E80008B06ADB49E2F1AD2D4D752FFAA8DB996E5
-:105E9000EFC3C2575BBE5FB363A4A53CBCF93A4BEA
-:105EA000FD6B5B275ACA2322DFB6D41F7574BAA5CF
-:105EB0003CA6ED1E4BFDB127665BBE8F6F2FB77CF6
-:105EC000BFFE93C596F2B7BA7E60B54F6C8CF421D5
-:105ED0004B50483FBE56372E1BF3B0D9686512E2CF
-:105EE000B358E411BEB648B7195E7CE6D90CD0535E
-:105EF00007E74DA5F5FEB545E9011F3D0B03E8CFCA
-:105F00003075C2E878799A938DF1D9E67CA862A7BA
-:105F1000DDA2CF261BD6F2CB926F0672BE79354634
-:105F20009FD96B2744C022647D170ECEC0F140BEBE
-:105F3000F609BDB6EF0AF5DA4194C3D3E991462CD0
-:105F40004BF962625D2D127C04CF808EF990933CF8
-:105F5000B4FE06F0A58FDE87349093894E7FFFC391
-:105F6000381F9B3F15996FD28CD2D7786EA5587F7A
-:105F7000D950DB37597FA57C67DA44BE5A0ACF5720
-:105F80007B725E5E1233E1F55D874DD8CD4DFC69C5
-:105F90001C7575E7A9E69ADF7F92A099F2E3940554
-:105FA00053293F24B3173DA867E6DEB41DF4AF9E26
-:105FB000E5A3A77CDF38C31637EFEB9CD09BD2BE9E
-:105FC0001A16B5AFCE211DCE66BEF538E62555CFE3
-:105FD000EC22FB2AD3D6B4E808CEEB57AA8857FAAE
-:105FE000F8792A6117CFBBE9D14547701FFA5F875F
-:105FF000905E92E36CAA9B7293663A37DEBF173FBE
-:10600000699893AF0F4FD70DBD692EE5691BFC7CD6
-:10601000A8E83F3B54558276F240915FFAB82D7E56
-:106020007E4B8293CF2B03498EF01A6E928FB3F37F
-:10603000DFF36A308FA76CC10427EED35EDB56C84E
-:10604000FDBC801FCF9D6647EE7D1CEB67676A94A1
-:10605000DF1A3B7EC6CCE0CA1C985F438ACDEFA610
-:10606000729782F51D0F31D607EA37FCA74AF03444
-:106070001C1C4FF91E0E772D43FB55CEEB50CA5317
-:10608000841FB52591D63D26F6C1657CF542E6DC38
-:1060900036B42B2E6CB0D37817608E06F47FA145F2
-:1060A000A57DD6232909111B94D5951E52A9D9681F
-:1060B0006B42FDF92D9EB02F278A176DE3043AFF3E
-:1060C000E2E8CFE7DF90E20EBB7368DE29386F09A4
-:1060D000A79CF7805EFCCA1B041EB3AEEA3E97C1C4
-:1060E000908F5543A37EE725F37397E1BA71825EE3
-:1060F000D6F934664EBFF56E3C2F745C65980AE2A3
-:106100006B6FA2F9CF87F9637C3716BF677D395F64
-:10611000D85482F3068453DD5842F3A07AD0AEEA15
-:10612000C70A7B2A07F9303885E8DAD746E70063E3
-:10613000E12E71F238EB8D4E1E0FD033F36EDADEA6
-:10614000079F83492E6E76F6BACEDFE2E47A889E08
-:10615000577E9F40C4B2CEAB011BD941B17081DEE6
-:10616000BADB69B26BD4A4870AB0DFDEEDB15D079C
-:1061700074B4C7DC8CEC64A92F7BB3C7D00E437E0C
-:106180009376D802A755EFC2FCCAC5FCCAE3CD2F4F
-:106190008E9EADC17AA7EF89C4B563D2F4F87A6850
-:1061A000B3C07F8DA1338A2BF5120F7FC229EDC1B9
-:1061B000BD0774C42BCC13F19A09FE7109E9197B50
-:1061C000DCBCEFCBF919B96BF2771FC5FEC08E4569
-:1061D000EE39DFE44B4AB9841D615FFA2B97198FC2
-:1061E0008FC4F007E06DBD93DB7FF4EC81B754C042
-:1061F0009BCD82B7C79D97B4FFB8BEED2BCE0F9C49
-:10620000137802BDFB7DECFFEC6DE7EE44DFB0EAF6
-:10621000B6AF845FCBEBA70BFD0C7EEF3F7CECA30E
-:10622000FA4B709CA8FFDB5E887ECFF297AF4A42A4
-:10623000FB69D29EBB0D7C9E4F1D4CEBCFD93D8E92
-:10624000008E733685E7D39DDD33F608C6073EAB77
-:106250003B9A6BD6CF675F3C5668877ECEEE3E5644
-:10626000A851FE6ED8628F577DFD9B423C2725F3D7
-:106270009EBBE9ECE47A7D838BC71DD2D2F546CC78
-:10628000E7EE4848A6793F966E7B245E3C05D51D17
-:10629000EDAB7B74DA475C3CCCB7DC8DF1941C83AE
-:1062A000F264972B81AC79B80F32CDE9C7387D6A9B
-:1062B0002E1B9A9384A1C62073030B395E6BA2E355
-:1062C000A0096DC6013463649C452BE6FAB1EB0E60
-:1062D0009DF2BA1235DF1333A19C3943A3F549C6A9
-:1062E0005DFE9C9042F0C9B84B373C6FD869DD58D1
-:1062F0009C136C2A82768BC7A7503BEFB4B789DE1C
-:106300009D3E5BC88EF3D1BA28FEF24F7543D3068B
-:10631000031E8D2CDB4D64837C05D832E5E77B358D
-:10632000164A027B640DF0EF60E0DF963A27D56FE6
-:10633000043BCE48A17B0CA2F77098F87E779D4174
-:10634000F57E529749ED1EADF3D1B37BDD67BC1DE1
-:1063500095E3E8C3BFD7735D1DBFEF4396FF7D3460
-:10636000D85540EFD4B14055C04BAA381F2EBF3F7F
-:1063700055F7C6A049830532009F7D2B8D2DAB2F8D
-:10638000016FAA239C8C478007BA58685226E6E121
-:10639000753D52928CE717EA274D1A0678C4FDE73F
-:1063A000EBC09570AD6D084D007EA8F4D5635C2EF2
-:1063B000AB5569C6F526AB757D11C6F9A11E9DEBDF
-:1063C00093FDBA5C5C3F251E7A52C91D8EC17FBE0B
-:1063D0006FCEF62586E39DFF1CEAE27A6AB068B7C5
-:1063E00046EC7B774D73D33D0989875CC42F597B7D
-:1063F000AFA1FD37772FFBBEB1FD241EFA13C5698F
-:10640000DD4AD301DC4764F3B8BD28F9A9B7765853
-:106410005FBF82FA9D7E8DE2B660A6D2FCCE4EEBC7
-:106420004FF8C6FAE67B3C3AF5F876D46817B753CE
-:1064300057D8E3EB6F8D71FB60745B17ED37E2BDEE
-:106440004A88EFACE34D0AFAD367159E2FD117F0B7
-:10645000B11BCA59139AE8DEA56DCEE0752E80EF08
-:106460008FC689BC15008E2BFFF7D9D84EE2432D7D
-:10647000D09DA84FB2F67EC0CFE1D8DA75CC4FFBE5
-:10648000CEAA17283EA8EAA539BC5CB702E3876903
-:10649000DED22DC8272CF4C2A4D7C0E7794C9C2BA0
-:1064A000C637A8F7D6B84439F47C4300F8648D9D0C
-:1064B00097BFB3EAB9063C77BCC65EBA10CF256376
-:1064C000B901FA5F93DC9C6983B2BBFED986A30352
-:1064D000B02CEB3F4B7C76A78B9FEF61EED22CC4A8
-:1064E0007B77D980F2705359E365E6E44F39BFAA50
-:1064F000437F3AD20FF8A57A2FBF87A61B6FADEB6B
-:10650000155C4F7E5277D4D7A0093991FA03D6E5AE
-:10651000AB3219F9157A5809E72A781FC7CA74737C
-:106520003EC9AD898A585FA0BD392E1873EE8C8E96
-:10653000B2E0FADAC0F33662E9FA46425143C218D1
-:106540003C2F1A5CADA21E7CC16E50DE7BBB467A2E
-:10655000BB43E6BDD7DAC97EAB14E750EDCB82ABC7
-:1065600087A15CDCABF9310E5091D35484F64BC556
-:106570002B39FE7A16CDA3AD486E4E1FE98EE6D1BB
-:10658000CAF2721137CA48AE4D4ECEC7FD92F5D948
-:10659000B89F51CD9AEEFB01C2FBA6CA90DF3F3DEA
-:1065A000303E09EF05AA8232C6A9AA5A8EE941A84F
-:1065B0005790C0EFA3A96E01BE71F37B6202798C84
-:1065C0006DD18C04D4F33F09D45E8D26EC13AEA3B9
-:1065D000935C40D767730306D2F9A5556F3538BF72
-:1065E0000565DD18C64660F99D06E4B38A1136CA12
-:1065F0008364A1775E0B0C16FBB1507EC89531D930
-:106600001C97CE12EB78CD26379DD78275F971E4B1
-:10661000EFEA8DB610EE6FD99C6D744EE725975C4E
-:10662000FFADE79B36285C1F86E6F138E7929B5268
-:10663000BE4DE79B56E41AA14BC45BCB2E26D03946
-:1066400026592E48F051FF655A88F679CA2E7AE904
-:10665000FCD3DF6E3CA7E53C55CFF1DC048F1CAFCB
-:10666000323A1ED1F5D0C85F3D3E18E8B66497DDDA
-:10667000E630F1DD925D62FFDC15C8C07ED2748E1B
-:106680006786FE1BF01ADD41C3CB210DD681755202
-:10669000BE431D0D932620DDA2DF9955FE03E83F82
-:1066A000AF4B90E50BF1EB27C4D4CF95FDFF85EA06
-:1066B000C7C29396102D3BA1BEF617477719E15B31
-:1066C0006F8BE92F4596F51593FA47F9EAA155DE48
-:1066D000C321E0AB75C94D45A8FFBBE6311FDE7392
-:1066E00085FCEA37E9DB875C5CCF965DCCB5D03BB7
-:1066F0008AF73C0B5D4ED7655AF62517CC5C42FBFA
-:10670000A70FA1B0603F2CC4CFC16CEAC7C2A6B826
-:10671000CDFF87E3AF85E3BA5EE0F887FF62387CA0
-:1067200096F1A2700CB6C0F7D7C2B1F5CEBC6FE738
-:106730004095C794903317D7851FF1BC35357992B2
-:10674000AF1EF74B7EA451DC7D08E3F928B91A3B54
-:10675000AA8D44F9690A60DC822DE3F60ABC5F6900
-:106760001F49EB10F90B83F63A66615E456E59607E
-:10677000213E59FF7CDA8F91FB984CC4F5E4FECBA7
-:10678000108315E1BD7C6F27CCA2752AB77466050E
-:10679000C6BF55CFE8045C0F1FB38543385EE85190
-:1067A0003E5E9A2DDCEC447BC93BD8C0F52ECDCBA8
-:1067B000F51F5B9D4FEBDF565BEED58B008E154AC8
-:1067C00051C21B88E7E45C8A63E37BBC0767AB5874
-:1067D000B7D464BF81EBD456B16E2D17FA5DBE4FAE
-:1067E0004C299D8576C4F2D545939DE3510F0556FE
-:1067F000F681F566D9EAA21599E371BDF1E53A6132
-:106800007D599650B4C20993D95AEFEB6B2447CB0C
-:1068100043FE02AB35E989A21568A734B81797A3E0
-:106820009D03DF0FA35FF86C8AD43BFC7BAED4538F
-:10683000A897408FA9F5DDE510EAA5DC6EBD5344AD
-:106840007A67FBD32A95CB603CB47B601E21BCBF2A
-:10685000AB6B8846FE910B604980B26B582EED6B96
-:10686000C1BC5902C6F587F1EF725F421F62A37D7A
-:1068700009AC8F787465F1FAFA347E9E59F7B8C97D
-:106880006F93FB1CAAD8574B1079248A318DCED92F
-:106890003AD78E5C8C7E9473B075FF588FC9375190
-:1068A00063F34FDC11B2BB1A12449CB90FCBA47B2B
-:1068B0000DC47BC6FC23F1997E774311DD77E76138
-:1068C00006E63B670623CC6C2FC9A703D6519F4928
-:1068D0006E1C6E168897EF704F22B787DD1735EE66
-:1068E000272A60DFE03AEA1176B8B08FECF21EA2F8
-:1068F000987557DA4B7671DFDD929B2666E0B921F9
-:10690000D51D70A29D73C01849FB292AF3DF5A6474
-:10691000B2771A2237513C5133020CED9CFDC2CEA6
-:10692000510D3F33DB398D75E080C35AB5AD308FE3
-:10693000EE9779CA15710E42FA3E66F3A3DE38343B
-:10694000B23CA4603C71292339DD56983E11F7030F
-:10695000B668A549F7A2BC1C87F17C9C6E7CFF79C8
-:10696000B982F1EF0BCED224D407EB9299C58F2ACE
-:106970004EE4FEC89309DCEE947E4223C013013836
-:10698000B48B57D37D3B43845DAACF9C44F12D4CFF
-:10699000D3C178A583D5860C77F43E3947A6CD922E
-:1069A0009FA85D2CA0F8DF930936CBFED1C3E23E51
-:1069B000405976B25A1EE7059E8EE7BFCD12703A57
-:1069C000C01EF2917D12B33FDFD33E227B45D2A79A
-:1069D000DB4E51F8B9CDDEECA39A8B368B9E8D9EA3
-:1069E00037D7492F9F13E7F9659E865BE8B3C6CC7E
-:1069F00060D3F539D1F3FB9AC8D7582BCEEDB34C01
-:106A0000ADCB7C4E3E11E331F0BD41E46D24C69C1C
-:106A1000BB77B99790BFE01AAA59CE69395990DA75
-:106A2000397CD6F75A66EC79FE50779E16E5156AE2
-:106A3000EC49850EEF737BB79FC8933A9BF87E2194
-:106A4000CA2FD8BB3F77D23E023FC729E359DFD4D4
-:106A50003EDE8F76D518F40BA78CC07EBF23D6A35D
-:106A60002C569AC537079B19E5F524F8DB19BF1397
-:106A70008CEC2D55EAB9D00B0DE847A599ED3B9369
-:106A8000BD3670CD0B0D0DDCEFA0F27756AD263D77
-:106A9000B8C225CB2BA80CEB5504FD1EB6C7E143AD
-:106AA0007E82F601941B76671ED9CB6A2EB8B4009D
-:106AB000F724BC9F10E3F97B1C5BD19E05BFF64E0B
-:106AC00097894FCF7A4E64B3FCB8FD852CFD657F66
-:106AD000B3FE60FC16CC0392DF2779374654DECE36
-:106AE00087ED58FFB6F743D0FF632F3BE8DE107900
-:106AF0000F722CBF162672BB01F58639DF529F3903
-:106B00003780CC29E5D3919960C9D396F2AA5D1C50
-:106B10004AF229DBED4FC8E1F77369018AAB6917C7
-:106B2000F349FE9F14746DAC332E334E4A2FE38C21
-:106B3000A47E7A1FA750E80926F6B334C37CCF4B56
-:106B40006FF21ABB7F17ABDFE453EAB7DDA2FF3B5E
-:106B500012ADF1E1F28DCD4790857E600BCE481CE1
-:106B6000837959EF797129AEB4450A50DE1EE8F9F0
-:106B7000BE1A27B7C0C5F727F2762C3A88EC3A3709
-:106B800031D884F6CC7D89226E9F09EB9A8AEB1668
-:106B9000CF2B5A87DF31FE1CF43D3119F5D4B412E6
-:106BA0008A3F6F4B2C7D1DDBAD9A5E48B10209F721
-:106BB0009A3A9E0F27F5A51BF105F51D5A2DE1CD3B
-:106BC000E10E44D0BE684CFCF564F4B1548DCB4169
-:106BD000E59ABD24074ECD4F7CE574DB7CB8BE3B07
-:106BE000C1BFC375AFDE6DA378D272BCA73707CF24
-:106BF000034C35505E177B7233D825F4A376315D94
-:106C0000E85FEBBD377FFB7152A97D8FFB750E8D61
-:106C10008F607F9A9F517E0B22E143935E95EB7AC2
-:106C20006CBBD8FE253E257E1D5A90F0AAA3DD1030
-:106C300007AECDDD7119AE0F33A4FE4C7E3B2F02A3
-:106C40006FAB94762FDA27A0173727A25E1CDEF5EC
-:106C50006F8A8FF4693AB76742F23E01CBFD453245
-:106C60002EAFBAB95D23E15FFCC6634EF33E512CF3
-:106C7000BCB1EBA53BDF9A47E1EC9F10739F6F3DE2
-:106C80001F472B25BEB14F0838514EEA8D9106DAC9
-:106C90002B0D9AEF7701CAFFB093DD0C76B8657CB7
-:106CA000F95C27EEEF3D2CECA8D8EF1E71DF71ECFC
-:106CB000FB8F05FED61DB89BF4706FF4C303CF485D
-:106CC0005F4F2E33F0FC8C5DC0EBBD4CBFBDF1D1EE
-:106CD0002307785C571BE70CA38B153B9E6A2F0D8F
-:106CE000E0792F7504237B571DC0C7075A1A181760
-:106CF000F68E4E61434DEBECAAC1D3F9FDCB69068C
-:106D00009DBF533DB6D27876A6C4536BA2CDB23F99
-:106D10009F29F966C8EF693FC9C4371FA17E89E57D
-:106D20009B56E4E1340E87999EAB06E766C4A34FF9
-:106D3000542F72BEBA1C5F144EE0FC9E01CF2D3062
-:106D40008F16719F4615E20AFC9DCABBDCCC80758C
-:106D5000ED2B4FD117085F61DB419EEFDE9246CEEF
-:106D60005FE584F8F2B2C8CDE9B2C8CDE3A84927FF
-:106D7000023FC57BC35BDA127C0A7C6A4989AFA7F4
-:106D80000BDC52CE44FE84D65E80F688AC5F38D3EE
-:106D90003A9ECFCDD7BF01B25DE8D614B4CBA66280
-:106DA0001780C7417E85E771B42686F17E7AB06A86
-:106DB000B5DB00AF3B84FFB703FCC269D06F7A023A
-:106DC0000BE2BCD3FA40399FDA0776B9A3FDBDC9FF
-:106DD00051C6260F2ADD8EFD4DCEC81AB13C87B7AD
-:106DE000C77E0E27B006E7C828DE6F7500CBA5E08A
-:106DF000F750DF45F9D1F7875176A15E7A7A7B812A
-:106E000082FB92B6403AAE231F1DFB01E5C12EC0A6
-:106E10007B8C9C78A5844A7E52E18952BAB7EC53A8
-:106E2000FC9885F71D950E738FC1FC30EB3DA46C6B
-:106E30003B3F3F23F1D5931FB8FE013843CE140BDF
-:106E40009C6C1CC2EDE4ED62F1DBFD147C2CE909C5
-:106E5000E8B9C623E88972DA22EEC5ECE61B71AF09
-:106E60004287B80F6A76A2B817CAE0FE95BCE7A4BD
-:106E7000450B24A27D3EBB3B3F2140E78F2A5D812D
-:106E8000A4F148B763DC7F3A5DC4EFA73B6D0F24E4
-:106E9000A1BC9E3EA62AF594DFC1F33E655EDD6986
-:106EA000BB6FCDD5F07DCE3FAB817AFA6CF50B3A56
-:106EB0005860D4BFA29FD4AAD23E64CEA3B3D4E17B
-:106EC000507F2E380CA88F6617BB4368C7B5FCBE31
-:106ED000F67D5CCFE63CEDF02D83715EDB38EA0B8E
-:106EE0002C9F5AEBF13928DE9AABE0FDF14BD6E747
-:106EF00018B40FB9948938F3C4926258839FC7A11C
-:106F0000E5FE8593EE9317DFAB1B27C1FCAE4E6BFE
-:106F1000B1212AFFB0B6BA11CFB3ADA82FCDC43876
-:106F2000C25AF7E4468C23A4A707DA6E80753DE2C7
-:106F3000BEB104CB2D4FC9FEA63462DCE017B660AB
-:106F40008E02DF4FBB679550FEF520D9FF92C60039
-:106F5000AC09B37F7CD51727305F7B5D6309DA0509
-:106F60004057615FAF21F8E64D90E526BD7830B41B
-:106F70004F649678AA3D1A97A0786D4BB77DBEA155
-:106F800004E3107326D6166BD07FE1BAA71AF3413B
-:106F9000C58E6D2A320250BE7EDDA6125CFF5A58A5
-:106FA000A002ED921BD63D5D8271F9D43ED6FE5310
-:106FB00055119767DB1AB1BFC29981110AB4FF97C7
-:106FC000752F35A21F9286F9B930DE05CF9F1A437F
-:106FD000FDA3FAF396E83D5AAB510EAA9CED47305B
-:106FE000549BBDB44BE779DB426FF4E7FCDC5D1EDC
-:106FF000DACEF3EB653993975B96C5D7438F7AB9B1
-:10700000BFD99210FFFBAB42EF4879493AC1023B2E
-:10701000E3C8CD16B7FBFF48EE5AFF6FE9B5E4CBE6
-:10702000E8B564A9D7043EF3AD7A1A8611FAFEEAF0
-:107030005CD40F0B30D9CA642F14B64DA775E47B0E
-:107040005E6E3F331F6F9F56CCF39DBA5E49E4F7E7
-:10705000A43ADBF2CCFBA2C7053E8A1F9EFA049D30
-:10706000776FB3333AA7B2ABE89279A69518DF35BC
-:10707000F91F955A84FCFA4A8CEF8EC2FEDEA47387
-:10708000A6D80F9E43C17D0C8CCFA62D8F4F7F6954
-:107090004F555E3458A84FCF7537DA7F2A0B8DBA1B
-:1070A000FCBCA2FD59E30F3DFBD3C57E50CCFAA832
-:1070B000C787F3CF924F01DF36137FCD13FC26F73E
-:1070C00095CFED19B6D5BC8F2FCF87817EFE29FED7
-:1070D0000E4608F43CDA99855AE066AC5FD89642D1
-:1070E000FB4C923F245F48BAB6A4D452DCAEEB49C5
-:1070F00085CEEBC5C265F3703A166EE4F73366CC05
-:107100000CAAE6FBE4A53C40FF2DA2FFD1E3487E9C
-:1071100036737900B9B917E517EFDBC179F8DB0BE6
-:10712000CCBF3B21E1AF405E4C233A72FCBFECA2E6
-:10713000FDFED875328AFFBE97A16736D153DA417A
-:1071400095BDAE975E9EBF7822E2F561FC08F91FFF
-:10715000F549F387747F5C4BABCA141F9F37EAADC8
-:10716000C26E7DFCF5E1891AD963D1F5C3477699E2
-:10717000D49F11A7335ABF6BCDD793719F3955DC7C
-:10718000CF9CAAE211EC281C233C5C8F8D0BC68F90
-:107190008716B83D9C0E621E4F2E9DC83E84F97F17
-:1071A0004FACF3E3DA43F4FB4976C4E398283EA4FA
-:1071B0003EBBD5D1FEA238F762E14759063BA7DABC
-:1071C00036C8F4DDCDF5AE1C0FE06DC0FB98D3E002
-:1071D0008957FF5FF0E4887D77CE9727F7646CA12D
-:1071E000DF6D18141881FA46F217AC2762BEB6FBA1
-:1071F000A7BB39FF4F8F4387E982CFE66DE4F36F7A
-:10720000F98FE29B910F5ADE4A495E66E2F77AA156
-:107210005764BF529E643BF97D86E8EF5E8F979E70
-:10722000F5027F0847BCFC0AD90EE74BFA7A25D74E
-:10723000D730EF10D209E61DC273F8173C4A0C5E36
-:10724000C5FA20F05DA5039E018F3BECA1BE98AF6F
-:1072500095A6F27C98CBC92FCC47FC8E8087F44E44
-:107260006CFF6B057F6C11F7E81EB6813CA39CB9DF
-:1072700039BCE7F66451BF75A2DEE5F5E195C9CFEB
-:107280001691AF02F0533E66D5ABFDB658E1AF178D
-:10729000F00797E339C2D427987F3923BC45105FA4
-:1072A000295EBE9EB4E841B2DFBA9E64E4B70E0127
-:1072B0003BC207E59A52F74825272AA779CD0AD17C
-:1072C000B17003ACD38837A7C4DB1B3BCDE36EF0B2
-:1072D000782CF710540AFA0F81F5FDA700EF10E89B
-:1072E000E745829BC375F2F1E6EB313ED7BDDE0B7D
-:1072F000BEE8096744EFC7E1A4BC0AB4777CA3A346
-:107300007062FF94E7E32E5D86FD56FF66773F735C
-:10731000BF2F76F73B7BA20BF5D87AD0ABA40E82B9
-:1073200087F01CC9DCBDC906DEF700FE820DFD42F8
-:1073300039EE5C4DFEEE4F7B21DE779ED73D0EE8A9
-:107340004F93FE3BE071F3FACE8303F11E6DA6F17D
-:10735000F529ADE9F48F701FA2B775F56FC50F4021
-:10736000479A77D72E98972F8ABF96E659CB5CA875
-:107370002F4F303FEA4B39AF2133DBBD987F53238A
-:10738000F428E0C5867C90FACF3EB6DC67D2CF8287
-:107390007E43199737E99F0CC50D1228BFE32910CA
-:1073A0007A8B519CE0E4ABFB7ECAEFEDE0F4AA9946
-:1073B000C9E92BE5F52B4F30C58BF6E95D0F4DE4A0
-:1073C00097E146E89EE6CA0D7C1CA8D7CC486EDB48
-:1073D000B26762FE25F2D3989E744B2D6D76517B79
-:1073E000C1FF675F191E463E4CBBBDAB18DF033FB4
-:1073F000103C2DCD9E30FACB642F63FB7D0A5FBF1E
-:107400005890F03277A6E137F38984AF9BEE0CE811
-:107410003E3CFA7EC84CDE6F4D2BF4CBFB21F9A924
-:10742000BC9FF1FBA9057D80D5428E9151BD03E53E
-:107430008823258A47893FD9BEFA7EFEDB3D182F77
-:10744000403FAF86B553DCB4522DED8FFE1ACB70A2
-:10745000D0395BF07F49FF1C7631CD05ED5F872782
-:10746000AEEF93D545741E6AF22085E41C2449C60C
-:10747000CBE8F7C66EBD2191E7BD7DF5DDC1389F34
-:10748000B444CE77D08F53F4E3243B55E8C35F6711
-:10749000833E34F9A5871585FA39FCAD6BB62E57B6
-:1074A000A2F3C4FED06E38AC4CEB4FF6AC886B0048
-:1074B000DE2CF97851FE0D09B8DAB3F1BBD94F4291
-:1074C000BFA6DBCF62490FDF087ED5D829CD11BC1E
-:1074D00052BB3E947CE3F760DCC9E067B960FEFD17
-:1074E000918FD12FC809A95E846B8842F7471F4945
-:1074F00008E6F37B88F938E922EE952EF2B4D19EA6
-:10750000C7E7362F5F2F8627F1F5E5A1245E4EF7FA
-:10751000C68F933D21BED7887BBB5717C5CF071CAD
-:10752000E7B5C6396F15FB3EE06F8DF3A6F1FBE0C2
-:10753000799E32DF2702BB96F05BFCF04CDAF7BC99
-:10754000D0764712BF9F82CBFFC74AE0DFEE52F0F2
-:10755000594AF703867EAB52BEFF4746C08BF9619E
-:107560005509F1F3CFEF15705489F99FAEE3F74950
-:10757000CCC3FD48D017B70AFF6C41D36D2548EF47
-:1075800005E0BFE37EA4CC7B90F42DDBA45AF62368
-:10759000E6E17E649FBFC67FF0F7E23F8CB6F80F4E
-:1075A00072DC583FE2645DA665DF6476D320718F9C
-:1075B00007AF3F87F909EE392BFB59F64FD9CAB40B
-:1075C0002BBBE714FC86505CF874D2AFF2FDC93ACD
-:1075D000270B99E1F86430E58D8CF3061FF05AE033
-:1075E000486421331C6C02FF5D2F178F5B03DD4362
-:1075F000667B3A16AE55DEBFD64FCBED05CF79FF91
-:10760000257E5AE104AECFF05222CC81193BC96AE3
-:10761000376FF6F27572B337D16237CF9D69ADB768
-:1076200045D4DB22EA5DCEFF37DBCBCA20D41BBCBE
-:107630003FF97B3C3967DEA2BCD3F7BCDC0E389E39
-:1076400014D881F2B856E4E96FF9CBA1CC39685F60
-:10765000FCAB9DF2048A362F598E79D4EE66C5A014
-:10766000734AAD563EFAC7A5CD03E7023E5E1274DB
-:10767000AAF4F37954FA23FA6037E675F3F1FB378D
-:107680001F5034939EE85FC6EBEDF3DA2D71F703DC
-:107690005E7E8FC42FBD323E183E70532AD60F68CF
-:1076A000B8AEF4C5DFC10178FAD6323A07D57734DF
-:1076B000B7C7FE71F416057F974BCE73A56D5ABE02
-:1076C00001ED56A627FA514F671BC1D7719E95EF62
-:1076D000452218BE19FB5E9B86FE92DF081C457E84
-:1076E00095F3F2A9465F5C6F12DFE3F03575C721B1
-:1076F000B89E666C8DF05FB6723B56654719B773DE
-:1077000069BF367DD9505A2FE47CD25384BE4D6771
-:10771000C1DD646FB395B4DE39F9FA99BE8CFF8E82
-:107720009EA467347E326C24C64F06AD8D68B3A12B
-:10773000DDAB9B6C71EFDD3825F00EF3F800E71739
-:107740004B9F5ED71D51CFDE4B5C4AF27BE294F833
-:10775000FE1E638FD0F7A2CDA9F7905C36E8744F78
-:10776000A2C4BFDF28FD23C2D3B7798B82B83929E1
-:10777000F2194EAEFEA982F6D6771732438DC34F6B
-:10778000DDF2BA74F7C0B9267D03FD133DB6C4E43B
-:10779000A74BFFC49DC4F5F83CA3544D4AA37C619C
-:1077A0008AE32DDCCE7F8FA3577C5C21BE9432EE22
-:1077B000C754CEE0BF475AB459237A5734F0DF2379
-:1077C000ACDCB98BCEE3B187981FE5BDB2799732B7
-:1077D00017C6ADD8B94B9967C25FBFCA30E5755FB0
-:1077E000E59171EA08DD3B16CBD718DFC7F5FD88B8
-:1077F0008BCB7B47913B8471EB0E7BB012EB7564B6
-:1078000025FA717F54E2FBF55D37D2FD079EDD8ED0
-:10781000083E57DAB6663AA1DECAAB753FF291DF91
-:10782000080E45BCA468A52DD83E39D5E3C7B8B726
-:10783000CFC146D23A778578181BC30F631FE27217
-:10784000724F9257DA59946F3531C923ED0ED24FEA
-:1078500047EC7C1EBB1987779B373016E16147F9EF
-:10786000EF29F4AD8C2898A7123B6E949F02DF4A53
-:10787000FA06FC0DF6928E7ABD42E899A2CDDB9510
-:107880000F4D704F456304F973E71605E32AF09D29
-:10789000F40CD467980FD577278F2755C0F7792632
-:1078A000BD22E71147BFDC86F0B9DF6B7B8DEB971C
-:1078B000088F230B7863E9797F12B7DB4A6059A5FB
-:1078C000F77A6828FA9B477213A83F29EFB1F2793B
-:1078D000BFE0F3BE9BB62B3637C5DBC9FE92F0C9BD
-:1078E0007AC79326CE491A837868233C546DD268B0
-:1078F0003E93F5D2C18B4CF2B048F477F0AEF7E985
-:107900005EA00D3F3F46FC58D5A470BBBFE9987EF2
-:1079100007AE2BA1E754DC1FB9992FE5EC71715F1D
-:10792000D6CD2D5CFF56B5ECD2F07E49C9A739679C
-:107930000ED23D5B55CD0E86FBA5C07FDF43FCC458
-:10794000F2A9C48FD4AFBDD113F4103FA710D24514
-:107950009C3A9833DD13D5CFDBBC627FD4CDDF6F8B
-:1079600048E2E528FF04572559F4AB8BE422E7CC25
-:10797000C883980F5AE557E85C656AB1F87D321301
-:107980005CE6F331B1FA11E3E13C7ED29E3DDD7459
-:107990003EAE5BCF8BF64F20BDF9FB087FCF7271F7
-:1079A000BD96F0C7D2EF90B0C7E3F0593829CE3A70
-:1079B00026D7F59CA7776B788F92E49F9B91EE2654
-:1079C000FEF95912BF8FF767491AF5FF7811DFA743
-:1079D0007ADCCED7AFC7EB9D94BFF9FADD3C9FCCE4
-:1079E000738F1EC1E761DBEC4AFC7EB82F8763A56D
-:1079F0006D199DF703B96C4E22FEF132AE1FB93EF0
-:107A0000DCF012D767952137DD775A19BC7D2EE55A
-:107A1000D9A6BAFC743F68F035FD0E4F4FBEF2EDAB
-:107A20003E40BF8B7C7333973F4907D0A7C45F525A
-:107A30001E245EA3F8E47897F224E9B14DEE0B0022
-:107A4000BF70FB88FB23F94CA5FD9F3267E0089EC1
-:107A5000CB2C13FBA5F9E2775FE47EE96C4197023A
-:107A60005BE9AF719E3DF64BAFD0AEAE58FAAB615D
-:107A7000180F29CF3C4A4F29B7E0F759E4FB7D4165
-:107A8000F7C3E2F9B1E09B8AD1CD2497151FD592B7
-:107A90003CBBA770BDE67ECFAA8F195B27E6BB96DD
-:107AA000DA4F4E6C2EC1FDC6C93F560CF4877B835E
-:107AB00073019E5343FF68D321EF2CC4AFF87D2997
-:107AC000799EE70BA1273A76A8E2F7366BF54BD9FA
-:107AD000DF97EB8F458E2B74EF89F0A93A76168FDE
-:107AE000FF18FDBA1D49F4FB279FEDBCEDFB1FA756
-:107AF000E2EF8BDCE0473B21757929F14F579ACBB8
-:107B0000BF95C73DA7605CA7BEF99017CFFFFC6F7C
-:107B10005968C8A800800000000000001F8B080002
-:107B200000000000000BD57D097854D5D9F0B97359
-:107B3000670B994966267BC832091050499884849E
-:107B40007D9924844516270805641BF600D958DA68
-:107B500062A57F068388886D68AD225ABF01C16225
-:107B6000B53560A441020EB208553F470A165BB412
-:107B70002322B284648AADA55FF93EFEF3BEE79C82
-:107B8000CCDC9B09A85FDBE7FFC3E3733CF7DC7B3E
-:107B900096F7BCFBFB9E33975FEE5760B01362B65F
-:107BA00068084920E4CA6BF21AAF8990877FF1EA2E
-:107BB00088A185842CF74A71064248EBEEFFF89FB6
-:107BC000D478422A76D658245AAF7FF94D7D80BEAC
-:107BD000A7F16E67CF77C75AE0BDCB2F6C1941FA7A
-:107BE000D2F6C67A6CBFF2C276ACBFF58B570FFDEA
-:107BF000177DAFD215E380F7AEBC76580FCF2BDDE3
-:107C00005A67232D89FBA87EAA99969E976492486D
-:107C1000C878C2FE9EDA73586FCFA5F5463A2AFDA2
-:107C20009E4CD77B7B65D1EF1AF7681798E00D2F34
-:107C3000214574DC5FCC1DEC867A335D444AE8F95B
-:107C4000463DF1186DB4EC4648142DAF169B3C52DE
-:107C50002C5D5789692394577F15351DD65BAD0F71
-:107C6000E458613E7D8913EADD011E4530CE0A5D90
-:107C7000B509BFC77E3ED41102652EF1908B7DE819
-:107C8000FA09D979AB3F8CF76B841F7D6F50540193
-:107C900021D3667D2AC17CA2FBD6EA96E33C5F66CF
-:107CA000ED74D5E1ED0356D3F1E8B8B7E06F64A801
-:107CB0002CB298F07D0A102C539BCAD3ECB0FE78FE
-:107CC0008303D62FD6975AE1AE37D3E7F7AE763B8C
-:107CD00064BA8F6F5C3A35BA3BADFFA28FD45F8632
-:107CE000D76569AE8BF65FED31E138556B4AC867F1
-:107CF00074BE636017E9F78916123F84AEA74C4B38
-:107D0000E24D5012725A5700FDEFC276BB8138091E
-:107D1000C503FB9BD376ADA39F3CA573A714413F3E
-:107D20001BFD7A3B943BD9FCE9F7165301F6671922
-:107D300002DF1BC94AF8AE7DDD84F84D12F6EBD7A1
-:107D4000D942F3262498313597F55708701AEB99E4
-:107D50000EEF13BB1ED777055EC17DF4E4CDCE8553
-:107D6000F209365F0D7103BE24EA69897075679563
-:107D700053BC596429765B8A42656237D6AE86EB7E
-:107D80004E68A7F0BC6071624976C71132B8F37BC8
-:107D9000A214F07F6B5A9B3E40C77DF2C0A788B704
-:107DA000D580B730BEFB821ED621F076217C42F70B
-:107DB000E1A9FD9F22DE2E6C96103ED5CDC5FA05B9
-:107DC000B4BC5AE7249F69699DE3DF53526031E0F8
-:107DD000B5677F94651785539BC0CF864F2FCAF434
-:107DE0007976738A5D82E7FB199E1ED3683C00A7F3
-:107DF000633BEED95E2F85CF731DC247AA2048276B
-:107E0000D5B5C46BA0EDC53F5F7D6A1CAD5755105D
-:107E100007D079B50A8FB29E3FBF01F0C55A490A13
-:107E2000A3ECB0CE4F4677A7FD57579222A0D3D4EC
-:107E300051CEFD5027CD12E905F50AD74218FFDED5
-:107E4000F8A50E99F66F1DE56A82F1EE8D1FEE9092
-:107E5000697F4FA5376E30D2764F19B1EC0238E802
-:107E60001A4AB4B4FE5499DD422149E1B63319DA15
-:107E7000491FBD6317E0B17B6125F4579D3CD301D9
-:107E800078D289FEF7AFEB03F3ADB6777344D1F741
-:107E9000C7374B8857C4632230FF6A0A5FA88FF741
-:107EA0000EF5C27CAE71F80938B6E9FC73607E6DE0
-:107EB000AF1B8887B68F1FC5F0D53AAA11F9C7DB6B
-:107EC000FBC79C90F2427869DE67F041DDA6B548B9
-:107ED0000EE04BE47E03CC67019F4F838ECC75D1BF
-:107EE000EFAC63593F3D364BC82F7E0DF49400A58F
-:107EF00086977A8EE70DACB478F25C141FAEF1FD74
-:107F00004734A1FD2EE7F852B5D087F454F90AEBB7
-:107F10002FDEE0CC5F1586BFF1A504E978771499D0
-:107F20005B4E9FEFB6B2528DAFA7395D673DBF1272
-:107F3000F77D01DD77D8D7D4CDF439C08DE205C007
-:107F40008DEE23E2C1BDF14B70DF166C961EC07D35
-:107F5000F40C20504F8863EB54F77F96F3C5DD5146
-:107F6000AE4289F6174C303B7648301FA7260AEA06
-:107F7000F956C70E02DFBB76C2780949518EFA3036
-:107F80007E4588AB5043C7B9946866FBED7D5F3B87
-:107F90003917E8D18EED0932F111E43F24DB951B4E
-:107FA000FAAEAC07EBAF8CF737A1C19347B2193CDF
-:107FB000102E1C1EDE75DDA687F3D34F383CBC7730
-:107FC00091E9C0378EE989C908FD5BE838B4BFC4C0
-:107FD0001D435FD884F3ABC77D7BDB62C1B22CCE7F
-:107FE00055580B2CB8876B35C045AC530D8F451CCD
-:107FF0001E6F4D9B93AF013C9E627200DD3D794048
-:108000009A8F78ED3152A204BC677448E87E005D17
-:1080100010B716F7A3BAD6E58D8CF7E54867D5F10A
-:10802000518E2809F1DE89F2CF63F232BC67F22F5C
-:108030007A2C9357C027CB733BF303C16740BE0133
-:108040003E0BBAA81E11C881FDFDBA7CA54DC7E83C
-:10805000BC8DC201E848D08DF90D462F9BD6D98B37
-:10806000A17D13A5FBF0FD3EAEF720FD1ECFEEE691
-:10807000807E619E2E7388BF67585C362B8577B5EE
-:10808000C6B7419B15E2C7D56F3C96E38E807F82D1
-:108090001F1BB58CCF19BDD15ED62F1BCF48C16D2C
-:1080A0002EC0D203F2287A0D838FBA9F5E56215FCD
-:1080B0008D960B548E4FA29B14DB8390B11A772FB1
-:1080C0002BEDA7CA18384E779664AC09EA611E8971
-:1080D00020BB807E76447B816F252612F7DE08FD6B
-:1080E0002659191F10FBD26063749418C3DE2FB693
-:1080F00032FE50686578792F2FC5FC05FEDB35EE22
-:108100004F89DCB51C13DFD17961BB980FFD7E234D
-:1081100061F217E79BF870CE8E4D61FB11A2A3BBF5
-:108120000A609F7A6CF669E79B42E30879AADE7FD2
-:10813000983FD00FACA7BC6FD7EF351C66F4A8C62C
-:10814000C772CE1763AD84BDA7F3FD15E96A8599A3
-:10815000EC80F96D25CE383AAF9A43BD193D38838E
-:1081600039D0FF119BFB15D88F81A3389ED3E7939D
-:10817000E9F3E55AE231D03D59BE5BE70D1819CD60
-:10818000DCA2FF95D858FFED66A347A6787EC6E629
-:1081900076037E794A88C30772E907947F00FD1150
-:1081A0005F11F0971A1288013857CBFE1C42F77FF7
-:1081B000B0C9BD08C63BAFF167C073420288AFE7E4
-:1081C000A262F208EDAF49EF4BFF3ECCFBA44C7628
-:1081D000D07EAE13E77858C775BFC6E6A1EBF8B8F6
-:1081E000F977BF3A40BF9A7DE0DAEC87004A9BA25C
-:1081F000E73C4BCB59468D51DB3F048F73E6C8FCFF
-:10820000F5871C7F12EA99DE155C67F0027CD4EFDB
-:108210004DB0B1FDAFB9914A3C71E1CF191FADD15D
-:1082200006F5A042D6DCC8201E3AEEC71A52D11875
-:1082300041CF0C5819FF6AA2A81FA9FD738E67BB16
-:108240007524672BCC673BE583003FAD1DF945C521
-:108250004FB31C9B68B5293B781CF488E0CF24E41D
-:10826000FFE7748CEFD0BF29C60121F909EA09E8BC
-:108270008715168F4F43F946C56AB34FCEC3E7DA69
-:1082800061B0771E8B16F8E07C2E1717D4BEFD77F1
-:108290002986B66B897118FDEE0BD3C218100B8BB3
-:1082A000BFBB2A1194EFA4590D489F848CB2803E25
-:1082B0002E3927C8B7A26FA7CF69516F477CA1FBA2
-:1082C000EBB2B95E80FD9E15CBE03D6B55B4D71384
-:1082D000C6FFA671F8A8F16C37E0289DEF2712932E
-:1082E0002BEA715EB595DC07789714E3FA35F6BF93
-:1082F000EA9A829FB54981179F057C5C6176EC62A2
-:10830000DD66B8C2E8E51D31EE0D0DEE5F7BBE3FC8
-:10831000674D16E07D30E3F714CECB5B0C168F1D56
-:10832000DAF58AFD3F5F47195F4EA83EFF52CFD175
-:10833000C404F0776C007C58B0319A78FA84D60186
-:108340000A37E077F50D82FDCC6F79FB2CF0F36AEC
-:108350006D00F167BED184FB537D438BF3201B7509
-:10836000AD01F13D95BFFD629C2791BE1E1D66BD0E
-:10837000780F7D98449FE3FADDEFC3BA9F8E8E217C
-:108380004E462FDEDE74FED78DF6581B85578D9E28
-:10839000E2473FECC6650CD3AF489A59B9FF2D2789
-:1083A000FF0EF3596874EB41DE2F9A5EAB07BA9C5F
-:1083B00015EB2BB2F40DDFF761F2AD7BBEFEBE37DD
-:1083C000713EF4B19ED245043AFC9CC37F02E02486
-:1083D0005DDFC7A98C7E3ECE20157BA1BC9B96F4A9
-:1083E000BB8FB379BD80D5D5FD44D9183D7F9CC7DF
-:1083F000E4956725931FEAF7FEC1C773D99C5F0216
-:108400003CC573A78D3D7FD5E6FC0A9E537EF85F81
-:108410001C5F7D56DADFAC370D88AF647D3007F620
-:10842000B1635D397CBE8991E7956163FC98F62B59
-:10843000D98AF03D27EAED87A2BC60879009943F76
-:10844000033F5E994E801FD371A36CAC5F9F15DF15
-:1084500033E03AC846CAA729DEB617D9715F361588
-:1084600053FC043E71D060013E21F049E0911A7F37
-:10847000126D42FE31397C1FC86119E570A28DC9A9
-:10848000613DD039ED51CFF4C19EB8DF8867F2D796
-:10849000DFEF3D46B68F94DEED3694FBBEDC707A9E
-:1084A0001370167CF2E36E4ABCD8CDF9601F0EB78C
-:1084B0000E38DBD87BF13D98DC13F6C120BEAE57F9
-:1084C000383F17A5906303C72AF59257B85EF08A24
-:1084D0003546EC4B21AC5FC8BF4EFBFD1CDB6FFA91
-:1084E000DE6058CF2C43704E1C955FDFA17A91BEA1
-:1084F00000BF6B82EF3AF9294631B95BB3D24C40E9
-:108500002F28B55918FC0B8319D01FE913443E34AA
-:108510009F507E23DD79FFC02790426964690C93E8
-:108520003B924C07049AE943ECD01F85F7245B513A
-:1085300008DEEAF1CE4113D503A7DB242DEE573E2A
-:10854000C987FD9AF3C197E6D9B4CB6B16A347430D
-:10855000E5C87735EE59D04FEB832751EF3FA7F7AA
-:10856000E5349822B4EB7DCF3F2D85DAE7BE247B3E
-:10857000F494CF34F95B7F368DE2E57CBFEC80214B
-:10858000E7AFFDEB7B03419FF6EB1C60D7527D62AA
-:10859000B316E65DCBF4CF731AE5FE5FFD1EDB5F1D
-:1085A000517F90E30BD5B3B46440885F093D6129E6
-:1085B000F1F5027D620171EAA13CBF62C90442E1AA
-:1085C000B7C8B41AF9D8E595E3507F5E4C3CD8BEE5
-:1085D00060A3EE7CB87C59D4A0AC2FD9AAAC2FF5FF
-:1085E0002AEB42FF4A288DAC57BCC8F9D0552A2E39
-:1085F0006EA7576CE1785BFAE884A791FEFD3A62BA
-:10860000A0EFAD3E589C4422F42BCA9A1BD9C41B40
-:10861000268742FA470EF1F687FE6EA23FF079AE4A
-:108620009F407F60EFAE8E7226815D72B524F2BCF2
-:10863000B7F179D7DCE8A6E8FFF94E7A4E0C8E53F5
-:1086400073C38865E77998F0FBAB8B238FB3BB438B
-:108650009FB228E469E8FB7826FFB83D2FF0A1E639
-:1086600046323E1775A16787BE4BC3FEA860B35C58
-:108670008C0EF1235D37360F81FF9F49C49882FE2F
-:10868000B12DDC2E71E4819EFB19E851407F63EC33
-:108690008702748A0B1E1A9CA3CD0ED1877A1D14F3
-:1086A0008FAE04C2E4FB219B391EE5B28338605CC7
-:1086B00081DF731E2C8B75D3F9FE696D6992BB6FD8
-:1086C00038DFF4E0F8D57AA1BF9914F298A8E4F560
-:1086D00082E693A89F2D34BA7280C97C7EF041C493
-:1086E000EFC5C4950878DD7EB07786FB7F21A7C5EE
-:1086F0007CEEF7CCD3317D9C122DA5B7C97C3EF71B
-:10870000B730FD506374EA701C27B15B12D1E46688
-:10871000F3A5CC524BEBC33BE60FCE434286F1F9B7
-:108720004BF03D85EF705E92F9EE6498B701C6A5F7
-:10873000E345116F3294F5831D7628474A2E2D9B11
-:1087400007DBE7D1A4360DDED71803325B279D4146
-:10875000227CDF012FAC9B797DFD94EB7316C173F6
-:108760009319F9869ECFE316F03F23F21323ACDB77
-:1087700060F25D86759979E92961FAB6279B38EA36
-:10878000E96BDD482381714DA66B1E58AC855824DA
-:10879000A84759AEFBC0EEB866317934FD902FCAB8
-:1087A00071147EADD2BB8B615F281F667EA8AEDAE6
-:1087B000B53EB477045FB3F1F9D573BE9642181C89
-:1087C000E289EBB093F2859F98174F2031208EDD20
-:1087D00038FE3331634FC07C01F028AFC76ACF87C2
-:1087E000CB8B049756C1B792A62BEB296E65DD485B
-:1087F000CE59007F259F2BF9561CDA717DC02FA31F
-:10880000E3FC624A37362F813FD9711A853EE1E297
-:10881000767DB54D4FD01F986834927EA85F64C7AF
-:1088200031FDE213BAD3D4FE0B221FCE1FE9ECF5C3
-:10883000330AE70D1FC88E87E93E6D30DBD76941EB
-:108840006F9B21313D5DDBE8033FCFF63956C726EC
-:10885000688F72FEF8BFA1FD039980DE5403FE7598
-:10886000A4774B317CB73DC382EFC59706D12F1A51
-:108870007C8CA05ED4094F6FD2F95378BF00750A83
-:10888000DF9A8596E5AFD0F7535CD10E29AC7D27F2
-:10889000B4D3794A1C2FE0F9C80160C7B2BF1E2DBE
-:1088A000F97E27F8299C32CAB59A96FC23263A8F7E
-:1088B0001EEE7C07A06DCF161E47893778591C81A4
-:1088C000522D9DC754239B474D4BF17D45B4BDA709
-:1088D000BF3F817842F409FBCC4A68D250FB19BEF5
-:1088E0002B8946FFD569EE47229C1F0C54D1DBD063
-:1088F00010FE637BBEA853F1EF1CC0DC13588F67DA
-:1089000074E020E28FD1E71012FA83EF4B43FD2190
-:108910003F1A156A0ED11B5D5A81D1515F49DF3B69
-:10892000563E06F1B006EC27BA1F03B5BEC340DFC2
-:10893000437999CF4B32BF01E1B9699D5306B8170E
-:1089400011B7BC85D60719FD71400FC38C8175091D
-:10895000B4BFC1D3E72543FD20285945A86779C096
-:108960003F6F3569BCEB7013F31D4037D3A6333F1F
-:10897000EBD4E9462FF8EDA76A098B6F69DD59DF63
-:10898000A1EDDF99C5FCBB509F15E63F11F18CD3DB
-:10899000D41ED913C19E3C18C7E493F8BE66BD5ED1
-:1089A0001137DA1F67C2F6FF881BBD360EF1DF9D57
-:1089B00005F4F7701CD7ABFA903EC057C2E87E03AF
-:1089C000BCD75AFC4E577C41D9CEF9C254E74F75FB
-:1089D000A88F73FE20F8B00BE8907EE7979C3A8052
-:1089E000E747250CFEA78A97227F9846DCF89C2251
-:1089F00088CE15EE371A1BA6C7D071A6BA947ACDC9
-:108A0000B4E96A3D87E1AB1877865BD93E59E8A99E
-:108A100063957AEAACEFDFB4A2FC4D7AB1EA562650
-:108A2000C649D0DEAFA1FBC4E2245A163759AFF7CE
-:108A300082BE53D3BCE25802D0D15AC2E9688FB487
-:108A400010E3387BA44561FA43F74AAF047CBF3793
-:108A50005D931FF73588F1A1D33AEF61889B9C5E47
-:108A60004A574CE77944CFE28F47A38807FCCF02EF
-:108A70003FCD9399FF94A231C641D22CD10ED0CBD9
-:108A8000376A0AD0DFBA31C6EC08F76F6E5AE72EA4
-:108A90000BF7B3DA0DA4C0C2F126921D7B8CF3C391
-:108AA000A724E6EFF6CC30A2DD96D0C3A5882F240C
-:108AB000C8E42CF80DD7C6D951DE3EC5FD1A109F6B
-:108AC000EB4F4BAF4405627CD8F732598F7E461589
-:108AD000FF498873A07F3F213617FDF4D35BF277FF
-:108AE00022BF3145397A49A1FEA7BBB76B1781FE7A
-:108AF000D4B25DBBD014C2BBB3025FA34934E06BF8
-:108B000087DF6EAF01FD76DFD5B8CE015E56EA7D18
-:108B1000794489CFF8BC2B39B684E38BAEC4356376
-:108B2000119D4FFB7B7AE6C75A4B905E5FDB6F452A
-:108B3000BFA376324179B2BE98203EB46F97504FB2
-:108B4000FEC25A81FAFB7AA901E5449B6D34EEDF3F
-:108B500032D351B44F2B9ED39D0FD7BB96ED54D635
-:108B600097133FDAC795AF74C267E45F823F563709
-:108B700029BF233D95FC319FF3FD0297E3FE329818
-:108B8000FA74470F661F139F81AEA3E85D3DF7F7A8
-:108B9000CE627293BC2881BED56EBE24333A67FC88
-:108BA000B888F7A79643455C9F1A41F916D89142B9
-:108BB0003FA2EF63FDA8A6454ED684E655C8BF1375
-:108BC0007A99E0DB625F8A07812D4C48463CD76F7B
-:108BD000B24936EC2BED1FE9818EEBD1DBB07F0F74
-:108BE000D85F43F97874DF3D20673D1AA317F0681A
-:108BF00083548B7CDA4838BF96DCF5F0F16F3C1E6D
-:108C0000E4DB8349EDFD13B2805FFBA3011E141F5B
-:108C1000B2E3C3F0A49EF832F6480A7CC1F656EBE4
-:108C20003B11F145C817DF474CBF184F570CFD9457
-:108C300041E08696472566CF8D313DA985EFDFD18E
-:108C40008C437C184BBC5A985F9945B9CF63929579
-:108C5000F571F64E7820C3B84E0ECFF17D94ED4EEF
-:108C6000C1D78892AF65919BB8CFE4B1E3DF05FB34
-:108C70003E7A0DE9037A07D51091DED4FC6054BC2E
-:108C800049A11F85C53D46C527748E7BB4733FEE51
-:108C9000101258FC8AD4195FDA8EAD9193C3F04A52
-:108CA000E0F11B3C4F427A93C7570B995F2F24E7A3
-:108CB00019BE0CE0B521806FF4FD45024F32492604
-:108CC000E0C9F0E6289F4CE19ACFFB1902785310D7
-:108CD00092E73E8DC9AECF06FC706C94E5CE7A7BF0
-:108CE000A2CD8E78D25F23E4BB238EA07C6FACD75D
-:108CF000C2FCF70FECEE3629F06229E28544F1025E
-:108D0000E9AA935C54B6ABF046ECDF09AE2F8F2195
-:108D10009E9E301E656347415FF66531BC29234E38
-:108D2000C493B7B3C7F1F8B35B8BFD10A53C2C35EA
-:108D30002AF1408D5774444DF8B86A3CEB0A6F3203
-:108D4000016F843C8CBB33DE3CDE35DE3C7E3BBCBD
-:108D500051E38BE0277BA22CA5A097D65448C88767
-:108D6000FBBFD7B31EEABDABB2308F658FD5817A1A
-:108D70006B4D2D6B2FF43B65C873E9B19AB767B99A
-:108D80004AA15EB386C51B8A4EB33C989E6B597B45
-:108D9000FEC3B547CC20DF3DECFB372E6F906368F8
-:108DA000BB7703FFBEB8A114EA351BD9F75F40BCFF
-:108DB00088EEEF80B3DE7A787ED7E62C07333F99D2
-:108DC0003E3B92E3E91E69EF11FCAE817DB7E4B84A
-:108DD000B11B413D98E9AD23F83A473EC7D619FF8C
-:108DE000D9BD63ED147F17053DA8375DD4540E40FF
-:108DF0007ED3859D592C35A44149F106F98CD34881
-:108E0000F13A9BC51377D021DE8E677AA088C341E3
-:108E10005E40781EC0DBF14CDE8BF7126D84C58D91
-:108E2000B799D1AF2BE284BEA7890474066BE4F234
-:108E30003F62DC704C8F5A8C178EC914F1C2807659
-:108E40003E1D37FFD697A323F951FE938F7B89E709
-:108E50003988E715DE2C0DE0C51E4092540052F50E
-:108E60006F416FDA037E5426343C6410EC2BAB9FC9
-:108E70008B5FB6692335D297686AB51E103219D454
-:108E8000FEA25D4FF2135F6C4CE7F98FD1121FC841
-:108E900027A265F35F5C4FE5A014E24B5305DB1995
-:108EA000D60BE9740ADFA7CBF15CDFE84FFA03BF0A
-:108EB00099CAF7ED3BC65A1D93970D3A15FD5F43CE
-:108EC000FA7FA64BBD59D9AEE20F157CDCC55C5FBD
-:108ED0005E4A82A8175C94BC585E7A86E9CBCB4D7B
-:108EE000A751AF68DFC6F4C44A1240BD43EDF75B3B
-:108EF000BE5B59AF6A54D66B9A95F5F65C0F8ED36C
-:108F0000FE4CD500F0BF556C7D0FFDBB15824F7830
-:108F1000957C822A488C4F3C7D37FA6D3446CA27AF
-:108F20000A015CDD306FA43F71C6013F00217B8BDD
-:108F3000D61F834F52685DE38A49403FD6D8B80BAD
-:108F4000627C19E3B2EF39EDA17DE9B00B557C22CB
-:108F50005FF8637ADAD05F25F8463E617242AD175A
-:108F6000F54950DA3942AFC807BD82E2855F63F246
-:108F70006A34E17A8417E98FDA8BE3A3B201655C86
-:108F800032D4FBCF2834F27D27AA7DED9B707B7B0A
-:108F900049D9AEDA7761AF0CE0FB3E83B8BBC33E84
-:108FA0004C21AE6320174E7D54A1B0933EFAC368A6
-:108FB000E147417BE99BDB494EF9DBD8491DFB1DAD
-:108FC00045F5465A964E1ED7EB6710DF6E8AC2BC37
-:108FD000CD1A89ED6FE28CD319E17EC3537524411C
-:108FE0001B46EFF5E30C4688EFD5EB981D3179FC75
-:108FF000C703E687F18B178CC52E80D706C9FFBD46
-:109000003F825D7152269817D39280FB7DBD813ED1
-:10901000A77876FDB97B1C1EFAF8AA8EC50BBF9007
-:109020006A17432A9398C7E235BF8DD252F9752546
-:10903000FA10C683CFE8DDB301EF96BDB30FFD9103
-:1090400095A077F708F5DBB5DFD1837689FE2D266D
-:109050000783523707E625104F4E789C685622E367
-:10906000AF676CAEA5307F21E784DFFFDC8A31B1CA
-:10907000200AFE429CB1109F94284CBADB3A8F071D
-:10908000F900EBC3FCCCE7A294F105517E2F81F9E6
-:10909000BFF7012DD1F1D2ACCEEFC3FA2E717BEF29
-:1090A000128F535D8A6171AB871318FFDDC7BFDB79
-:1090B000CACB4B3CAE75C9A6B413C57BDBF877179A
-:1090C000EA8CC6F561FB687FDA50EBC53C289EF759
-:1090D000B19A30BB68BF75FBA6B0F8C1AE84E27D23
-:1090E00030AF841E4E7D0AC06F3F93BB1047867819
-:1090F000EF308BBB01E0556D274E8897127B407F88
-:109100003FC40DC1CE447D81E1497B142BC5BC76A3
-:109110002594EF4338AF0820DFEAA897337EB82BB9
-:10912000C185E3B64F15EDBCFE04AB13EE2F10FE68
-:10913000EBAEE258EAB815CC18F5EA28C6B7D4F178
-:10914000EAD9826FF178F52CCE8766B7307FF81CAC
-:1091500023D9D09DB6CF6D4962F6618C274711AFF8
-:10916000F6447FA33C05819FEDE9FE8E38EBB6B057
-:10917000386B158FD35589F53529D77724A1CB388E
-:10918000EB9184087156753C7F1FC8F39E2178AE21
-:10919000B4B0F597C995A57AE00F0B09E67FAF3C0F
-:1091A000B9A0DE48EB2B1F034F1FF221D44FAB3881
-:1091B000BCBA9A5F824B43EC0ABF7037620FB3832D
-:1091C00053DC36451D35DEB0FCC9EE15A98AEFD358
-:1091D0006BB315EF67AEB95BD19EE52950D47B6CBC
-:1091E0001CA278BF574389A2DE7BEBBD8AF7F34907
-:1091F000762CFA8F4EC8E01B217779272BDAEFD92E
-:10920000FD80E2FB2F48ED53C3E87B4D518CFF13EB
-:109210008FD3DF7740285F38B771BEE2FB7AA97140
-:10922000808FBEBFD0CFFCEBFD9A9729FABB1A33D3
-:109230009AD90D3C4E584BFF31FE6D9751FF699600
-:10924000C836A973DCB0A265CB86EE2452FC90C967
-:10925000F56554AE83DEA4D62B0C893C8E944A521D
-:109260006F85D155080F4CA8775D7F4E46FF593E5C
-:10927000C9797A18C24747BCF6CEFB759D30BFCE80
-:10928000F557CC0EF08F2D39B900F1CF90ACC483D7
-:1092900028BB120FA2FB28F1C0EC50EE7BEC20E5BE
-:1092A000BEABE16C752AF140C051C0396EAC122FD3
-:1092B000047C07D17F00DF02123C8EF9D15EC9E148
-:1092C0002311E2B2CDDB711D77D2D3F255F0EC7FE2
-:1092D000D4596F4238B17C29A11719B85EA2F69310
-:1092E00077F85712B9DEC3FB117EED0D9207F59C9E
-:1092F0008EF8D5205F862F0BF49D5AC2FC23AEB2A8
-:10930000C4C87E347CDE951F4DC051E831CB418FFF
-:10931000A1E32C226EE44B17B81EB3C4F424C6019B
-:10932000AFFE81C1B78278915F7FE3B836D50B4934
-:10933000987F510D47A945F299810E38DF4E252DB2
-:10934000826FBB31DF81A29D7180229EA0D43B89B8
-:10935000530AE74F420F15E309780ABE25C633903A
-:109360005A3919E840C5C7481F753C43E9E7107EE4
-:10937000111C2C2C6E31B0231EC1ECC2909F8BF9B6
-:1093800035E4CCAC7A02FAB645F831FC33E1B9F0F9
-:1093900063A8EDF93BC541EFF7488167B33AC73F92
-:1093A000453C952EF3B33FD28F8749F674186FF280
-:1093B0001BBD138826921FCE71F600ED47D604E33D
-:1093C000C2FD63C25FFDB614C0797F87381F21617B
-:1093D000FA4235691C3D330BFC9D546EC540C9FCF7
-:1093E0003CA459AD8FB2F8A186AE04F07B39098B4D
-:1093F0000F6685DAB12E77AE8BFC943BC9F75E49D8
-:1094000016712E2587B533FE26ECB5AEEC2311BFC1
-:109410003FA6A7302908E5A33426723F561EC9830C
-:10942000FE295D352526803D4EE9500AA7BB8EFCFE
-:10943000156CEF4477AAF58BF8BD6C2E443FCB82B8
-:10944000F0F57E0D78083DE2065D1BACF7478976A6
-:109450002CABBA9DFBD009CD857E451E628D9EE565
-:10946000FD9246A5FE7C3651C459999D71273875E9
-:10947000BD0F3C9F8BEFC3D7D587443E9780DF2736
-:10948000820F86E07D5E01CF0E7BAD03DEE723C158
-:109490005BC0E35A91FF45D827D97C3A11E09C1470
-:1094A000E3FA02F862FAD9C04549139A5799DC8A5F
-:1094B000799CD79B65B48FAA87B37C9EEAFD18245C
-:1094C000276D2D068C0356341F41FDACB58E32D26C
-:1094D0009E5DC3A963BD2A787765AF88F5DC52AD80
-:1094E0005FE487407C3FA9E8B67050B67338887C4B
-:1094F0009632B96F6C20CC2EF1F17D8FD2BAA29248
-:10950000E8F885BF4B8B01F894C92DC753010EAB0A
-:10951000253C6734D2403CE0DF4FE1E7CD06056AE9
-:109520001D160A8FE434139E1BEAFD5DD905F1CBAD
-:109530008F57AFB2C1B9A82B7574686A77F49634A7
-:109540002EC437B2F7931F14425C6D16E617CF3660
-:10955000B0787FD6F7A27D3D289F78534F8C406F1F
-:10956000BAEC5A3C5711B4CA686FC4CB6414E09784
-:1095700080737C345B87785EFCF39D12E42189E77D
-:1095800023EB83FD57D2F273D8F784D03A4796067F
-:10959000FBD79A427016F97D441BCC981C461F4796
-:1095A000383CAA13F41B401EB619B91DC8ED416220
-:1095B000D1221F59CDE3EBE77A11E2C77E7C66C862
-:1095C000A7AA8E72C60E04FF16E40FD0E22F16670C
-:1095D000AC15D76F47BD7935D7AFDA787EF6EA712B
-:1095E0002549604F25D447CE631A9DC4F4FC4A1E1A
-:1095F000F716CF2BB53ECC47AA847CE1B0FCA86F10
-:109600009A2F2CF2C4BB8483554BB4140ED512711F
-:10961000DDEEBD03FF2347B477AB9234B7CD635B78
-:10962000C8D727F2D3AA213F8D3E5ABDBF388944FF
-:10963000E8AF43DEDC18A2C80B13F9CDD53746607E
-:109640005E58E9A3AD78BE0FFAB19B4279695DC15E
-:10965000F948229B4735E48BF50F7FCEF847A8FFEA
-:1096600078DC875F0200C1CFD12CA31FF697273487
-:1096700063774498EF16BEFEBB13B4481FF7F88813
-:10968000737B84F1C57BE2FC07C0B93CB7F3FC9A5D
-:109690004A027360FE90771A69BCF549CCCE16F386
-:1096A0006EB20516733CC7F3171D758B721F5FE012
-:1096B000FBD8746F2003CF118D8B9C072FF6FBA670
-:1096C000D9FD26F0DBCA69F465F0B36B6B254B1846
-:1096D0007D75B5DF21386B14F97F9DE1ACC7FD15B1
-:1096E000FD097BE4F25619E3FB974F717A244E9300
-:1096F00044E96A1E975797098B135C6E90D00E99B8
-:10970000EF26640DE52BF3762EC738CDE25DFD37ED
-:10971000809882E76B29FF98974CC8085ACE5FAFB4
-:109720008CD32EDCDCC9FF46C2E522553BD1AE5EB0
-:10973000FCA4F2BB0AB2F9CFA0F754A8F49ADEDC7D
-:10974000BFB52F89DA09A0D70D200380AFAFDCF5B4
-:10975000A51E526DBBC2F32B949E7B6A81FF59B04C
-:109760003C91E43C08FCFDF7496E1F94ED1F303836
-:109770005CAFBCCEF8FD73F128670CC094E9FF1A0A
-:1097800066B278EBA3944D409CCD60607A8DD0E7B3
-:109790006479951C43DB077FBEDA06FEBFF897C7E6
-:1097A0008C057D3FE1E56827C06B53B1331FECFFAB
-:1097B0004DE526CC5B301A589CD7FBCBC16F81DBC3
-:1097C000BF67E39612B03F2D2D877DE01FD9A8F922
-:1097D000339E1BD93882E5B575E44FB694EF81F915
-:1097E000644C61F262539633DF12D62FE1FA593599
-:1097F0008759FBC1DE3F86F3EACF9E40F598AE2F36
-:109800001BFD707713B69F227F0AC60ED7435BA954
-:10981000DC81243C51BFBB51F2E9E87AAA9AF66098
-:10982000BCA2F2615FE24C902F2F6931DE23E61774
-:10983000FF664A09C475845C992959989F91EBD9B0
-:109840003388F86371A1E91C0F6670FD7A66348372
-:10985000EF7CE2C880EF1E309218F04FCF2C6D2CB9
-:1098600042B9B35C6705792EE21B5DEB0191FD44C3
-:10987000D52F9AD9F9572998039D5CA1760761FEE7
-:10988000A28879BFE6644E67395CDFEB499C104FD4
-:10989000AB3ED47B3BF8030CDD58DC95F21BE3A018
-:1098A00002D4778D60C72C3D10E5637E6A2F3FE7B9
-:1098B000EACC87FC8F9AC9690598877096F20D33B8
-:1098C0009C1F0C64209D527E22519996936C9EA001
-:1098D00085737EA9549FA2F5295B53276829BE573B
-:1098E0006707166B687D6D72216BBF3B7011EA1BB9
-:1098F0009247B2F682C06299D6B7274F647530ECB2
-:109900002862FD3A79CA040FEDFF8A95CB694700BA
-:10991000CFFD56BFD15B13EEA7DC06C90B143E5733
-:10992000B8BFF54A16993B19E0DD2780E7CAC47B2A
-:10993000FF87BF27F27DC53AC577243972FF45FC02
-:10994000BBA5FCBCEEC868B2318AC5A53C3114FE8B
-:10995000475B7A635C2D35D9C6FAB7D07E0A43FDE2
-:1099600008388AFEC4B8CB409E029FD5317FA968D3
-:109970002F4966FC9B8EB31EC7E9E964E75027A711
-:10998000E5C3BED1FDD2F2FDD232BB733B9B1FEDCE
-:10999000D79A877CBD3FF8BB8FDEA4EF6785E6AD25
-:1099A000C68FFB387E2CAD67F1C4A0B507E2D1C8E5
-:1099B00068A6E79142E53AB62733BEBF2DD9CAF073
-:1099C000A2633F92241CA79EC3318DC23DF79BAF7B
-:1099D0007B1E9FCF3F7BDD61FBE584FCBEA3CD7783
-:1099E000ED085F8FC8CF16FD5C59A7FA6E10CB93B8
-:1099F000AAB6F5C0EF1E8D22467C4E76747C9795F4
-:109A0000C7F44BD03BC57D0CC433029D04959C6BC1
-:109A100074DCAFD0C8F3053BD637A190AFCFC2D727
-:109A2000673186DDABD0418FA7831953CC9DF1B749
-:109A300003EE1DFDF52DE0FD29E83A527F401F5D44
-:109A4000EDC74FFFD97828E6A98267079C55F31325
-:109A5000F0047AC6EFFA2AF151CC7343C73EAAE864
-:109A60003AEB5B8E57CCBEAB7A90E7FDDA95F85CAB
-:109A7000D594A58178B9F86E2CF8D81342FEB67D3E
-:109A8000C9DC6E4B23695DE4BBBD919C10D14F874F
-:109A9000CFD5765BBB95E539ABFD06ED090E3F9C56
-:109AA000C3F35C63E7CF87AAF40D88BFEC3585BEAE
-:109AB0000BC91365DD90C2F85B673F5010CFCB1622
-:109AC0001A4A5EB33B28BA242F43FE5D185BB22AC4
-:109AD0008BD63F4AAE447E5DD8BDE4CB2CCABFFFD7
-:109AE000985CC5EAF7947C990DF5AD55ECFD91CEE7
-:109AF000D780BF134FD584512921FDE15CB29DE988
-:109B00001FA51A027864905738404E0A7876551689
-:109B10001A34B511CFB576E0018B4F0CE2F2799093
-:109B2000B0CB035A855DDE1EC3CE13B7833CA5EBD5
-:109B30000D26BBAF00FC6BA25BE764D1AE1E8EFEB0
-:109B4000440FFA90E4A4FA06F839EC16320BF2E767
-:109B50005A37B9403F22CB1C462DC293FB9DE8DA11
-:109B60006ED17E0E1C7AE9A1EE6C1817CC6330A77B
-:109B7000FF9A437FFF0AE2A235574C0E50FF06B70B
-:109B80003CB30AF4ABC12DEFFC9DC95B762E43CCF0
-:109B90007B30F80FE9F341CD069CFFE096BB16C180
-:109BA000FB437FD7D203F063F8395F3DB083F68380
-:109BB000BFE9AE388F41BE90BECD798C0E787C4E19
-:109BC00095A75884872905E17113F3A2DA124E6D27
-:109BD00008A09EA63CF742F5728CAF5E27DD1C10F4
-:109BE0002710E7B4D5FECAB3E5747DF4F9F0209DE3
-:109BF0004198BE3CF206B5EBC3F4EC626255D44B1F
-:109C00008D298AF7CB2C598AF631C97729DAC7D939
-:109C1000F315F5F17D062BDE9FE82856D4EF1B34B3
-:109C20004EF17EB9B35C51CFF7352ADEEF7FA259F2
-:109C3000D97EDA8EFBD0FF9CAB14F47887DF5D0F02
-:109C4000E5C0D686D2583BE9E4A72D0C78EBE1F9C4
-:109C5000D09BB5453E12E1BCCA3237FAF73B9D575F
-:109C60002966E7D7DB34ECBC86F0CB0E36B98B61C6
-:109C70009FDE9628D829B047188371B05F65739F1F
-:109C8000C0FCA8EB41827EAC267DE0474341CECFAD
-:109C90009651EF6DE279354DD37331DFFDAC14D8B9
-:109CA00007F179CF6C761E6038D57071DD10D394D2
-:109CB000609FDC8A751793A5AA7D5AA1A897591EA3
-:109CC00054BC3F26799DA27D9CFD31D53E6D51D47B
-:109CD000273A9E51EDD376D53EBDA4681F7E215014
-:109CE0000F6434B2D5239BE9FC879C6D28857D19D0
-:109CF0007ACE331BE8A5D0E7AE07765874B4F608E1
-:109D0000943E6A4F817FEAADBA642C8FD6D9D1BF19
-:109D100074BCAE0F9627EA1CF8FCB77583B07CB70D
-:109D2000CE89E57FD68DC5D25FE7C2B2B1AE11DF75
-:109D3000DF5BD78C2585603AC88BF8B88E7B13D251
-:109D4000C18E6FD304AA2182FAFD670E225F6CEBED
-:109D5000166883FAC3A465C2285A9F0FC614E85731
-:109D600050D2FDF4A43AFF2B05F22952D8739197F3
-:109D7000D0A871E6837EFDF833C7366BD3097964CA
-:109D80009D2BD962657523ADE366431F9E639B9D42
-:109D90006984FC0A44C610AC4F807A7B146BDFF0F8
-:109DA000CCB1091E9C1F8B1F4F09C58F1F4F8910F7
-:109DB0003FFED525BB19FC28A76EF636C3BA4E71F7
-:109DC000BF9193E4EBE6D1B2589BAF03B97856A5A7
-:109DD0004788B24653FC24E069A3C63115F380EFEF
-:109DE000D511C83B9F2C317BB4430F4C65F2A87D45
-:109DF000A201ED9DD31AE722CC6F9282CF03BC5E05
-:109E000049F910E1D76E0E66001C7E997286D51353
-:109E100082CF4B8EB0BA8EADF38594D35DAD7337E0
-:109E2000CCA7D33A53D87D31C4E74C07F92BEAA726
-:109E3000CB9D5520274E173B7BC17C4EB90C483F2C
-:109E40001E97D90BF99544EB2C9A1AE64FE99DAA77
-:109E5000C3EFA6E8199D9107E488E7C4CB52999E09
-:109E600085FB06F6DC8C68D4C34F6B229FF39ECD36
-:109E7000E173B55B64FFCA1CDE5E72BF19FB6B5FEA
-:109E80001D85F1DB76576FD483DA6B2994287DB476
-:109E90005FAABDF63AB61B44680BE39433399FFAC8
-:109EA00055CBAABF9EA1EF7FB23ADA813CDC723774
-:109EB000CAA707F8CBB3E38CA8B7CC9E9C5E02720E
-:109EC00069268F77CD316B1331ECA5B5EAE10AA095
-:109ED00085A6FC0D20FE17C797EBADB45E91B66268
-:109EE0000394CB7A6ED1C391CFCABE7B3680FA5829
-:109EF0004549AB08EDA5C07B75745E73D7C876661F
-:109F00003F897386CBBF517E85C0C3D33C4F86C289
-:109F100017EDC2B9A992C22E999BCAF4866B295C2F
-:109F20006FCB25B9B794719C3F033DB4CE7E2FA76C
-:109F30000B7FBBB29DEB6D1FEAD9B8EA7B26C4B894
-:109F40006E3E8FD37AE294408F7BC08CF89137FDC0
-:109F5000CB878BE8FAF35A2C1A8CC30B3EEE67F7CB
-:109F60007D155D70239F1BD81A78F10C413C6F065C
-:109F70003AB9939CBADFB30EE5C3E0BF50F9037C56
-:109F8000F1A6FB9333D81A1FF1FCA5AFAE82F3C73D
-:109F90005AE46B47EBD660FD789D07CB13751B39F0
-:109FA0007F6CC0F677EBB672FEE8E5FC71373E6F6A
-:109FB000A99B8EE5A13A37964931AEC454A00BA3B4
-:109FC0001BF3318F3D632032C4195A0C88A79402C9
-:109FD0009E7F361EF25F0C163867A7CE8351F3DBE7
-:109FE0008EFD6FEA748F45766A5158DE0BE86799EB
-:109FF0005DE3CF296237033F19B22D6522F08F53FD
-:10A0000076BB19F4D6A1A9A9ACEEB49B75B43E6C8D
-:10A010001BAFBBED6603AD0F4FED3E11F4DE531EDB
-:10A02000BB398AD6476CEBCEDABD0483D4A5DBEC12
-:10A030001381FF1413E928D043A9316B14A4C896E7
-:10A04000598A8F021D8C499E370AE8606F8A1DF17C
-:10A05000619C7DDD51A88FEFB35D0B476B9CA6FC27
-:10A06000F5F05D497CB916BE1B95B6623D7C37BAEA
-:10A07000E7166DF87763FBEE590FF5098EED5AD0B0
-:10A0800007F7A6B0F8A7E847D445BBE0AF224FAB2F
-:10A090005F8B0BF9785EB30BF978873F624AF9233F
-:10A0A000E0A7AB69962C12CC638AD4117C875CB88C
-:10A0B000EA9B945A289F9DBCED1EF33A4A5F3550A7
-:10A0C0001F82F527D645E6BBD35223F0DDDF733A76
-:10A0D00005B909F9CFBFD7B37B387EC3D757D33281
-:10A0E000CF3C0FED19B719E4EBC11426270F73F914
-:10A0F000F8675E7EC59FD7689CF360FF2B5279DCC2
-:10A10000B6335D57C23C28DDAACE0574D1CEE9BA7C
-:10A110003A95CB077EDF411561E787EE94AFB53402
-:10A12000DC7ECB82BC9CC6E39027AACE7F10F98D43
-:10A13000EABC5FCA17F15E17D2ACCC1BEDB03FBAD8
-:10A1400031BE07C715C1E87834B54B7EF6F81DD689
-:10A15000FD78A4752F252C9F59BD0EE24E40DA12D2
-:10A16000F9CD9DD71388BC9E4EEB6850DCBF20FC18
-:10A17000EC540F7A16E65336D74CC07F13CE27CE59
-:10A18000DC864FA8F9CE3F8B9FDD86DF34C23CD5FD
-:10A19000FC469C6F5697429F837351906F07F7B4AC
-:10A1A000809FFEA144F701C0DBF692E0571AB0CFC2
-:10A1B000E20388676956F721782EE959DC5DE4B13E
-:10A1C0005ED2787E0D7AD16FB72D423ED406C28121
-:10A1D000D2E35BB40EFED36116D7519817E9C3F0F2
-:10A1E000A7ABFCCC77B81ED2B9647425F214DBB7E8
-:10A1F000FF3D03FD5877C0F7AEE050260F0B40FE41
-:10A20000FFF541D1A8F2B44AC42715409E7522EA51
-:10A2100011ADE97A2D94FF6C3BB1353D07FB57DB5F
-:10A220008BAD29838C6CDCD163A16CD6BBB7CE031C
-:10A230003B69B001EDA4F7797EDFA4F337E3415E1B
-:10A240004D927D897952673BB3F5E4AC127B5E6732
-:10A250007B93AE6F14ACEF4E76A7CBE8B70118D561
-:10A26000F667E59AAF08E4430F5D7393C07D6377AB
-:10A27000B647890C6CA2E0ACE3089445179C98861D
-:10A2800033E052ED112807FF8599E777CA271A7244
-:10A29000A3F1083B0EDE5779BFC2A07798BDCACBA9
-:10A2A0004EF7B02DF328F3D48A7D45983F210762FD
-:10A2B000A0BC2605D0EF256BD8BD0BE2BE056AC752
-:10A2C000A6764F00BB97E54B8D843C233AB9B21F6D
-:10A2D0007C34E721A4FB28D47F3AECD8D735981FEB
-:10A2E000D0A475C60E073B764D2FC73A5AFF933F51
-:10A2F000E16707685963F98A84DFCF56B9E6BAA2E5
-:10A30000DEBA2E74BF0FE44157FE8F8C72A7929075
-:10A310008DB05F95E42DFDCA3039481AFFDC01F796
-:10A320007E94CF9503E0D0AED24E72D2F7CAB9BDBB
-:10A33000413C8FB03AB7B308F97CA293F65B9EC05C
-:10A34000DF2733587BBA687F80D57B89FEF64FC400
-:10A350007A8AA8F3FEEE12F52DAC9E25BEDFCBEA7D
-:10A36000B962FCF7D97866F67E69F7EF4D02FD43D6
-:10A37000F0F771DD95F7F2507E3FB1FBEDF34994B4
-:10A38000ED5C1E887B78CA7E302EFA3DA0E7460938
-:10A3900073DF2AD7EAD0BF7DD5D698177E1E59E441
-:10A3A0009FB84ACD4ED0F7AAF6F5DE21F37C1CD03B
-:10A3B000377EC4E3CA65B209E311D737333EDF9570
-:10A3C000BEB678CD1B8AFDECD4CEEF49C6401D1D2C
-:10A3D000EFDA134998DF4E7AFA310EBEBCBB24E2A5
-:10A3E000ED789E55E47BC5F7204EB04FE37F13C553
-:10A3F000EEA1BCE047FEBBF837CCDF5BF5CC119497
-:10A4000073F3653BE2F1F12CF70A804F9B99DD373E
-:10A41000B878CD21A4D7B5995C4FB004FB86C3F3BF
-:10A42000C1CEF0FFE11DE0FFC37F27FCD57E667142
-:10A430001E7AD937CC4B6B33B338A883EFD3798DE1
-:10A440007D0087D7D340E7D716F973AC32240DFBD4
-:10A450001359BED1BB4560075DAF35E3FD44B3562C
-:10A460007D9C177E1E45946AFDFF73A0A38410BCDB
-:10A470007675E7FA5E08BE2FDD01BE2FFD3BE19B3E
-:10A48000A40DE81D10373DCBEE0B1BE03FAF0FCF07
-:10A490007339D99DC9DDD866162752E76B9DEC6EDE
-:10A4A0006678C5E3315593DF1D06F118410F23A3EC
-:10A4B0004923F8D7295E3B385E3B00AF05FE86E2B4
-:10A4C00032F4BB08F415C25FC2EC620E277F67BC92
-:10A4D0003D7D07B89EFE77C2B589EABF18C77C3DAF
-:10A4E0000AFD276A38FF8DD3BB80B731EDF6703691
-:10A4F000A6FD6BE06C4CB32BF2D204BCBB924FEACE
-:10A50000FD11F38E40A745DF864E1F4DE77C4A1BA9
-:10A51000C03C51F5BEC7A675DAF7B8B4DBEFBBB2E5
-:10A52000FD5FBCEF6AB8A9CB4A1EDF543FCF4FD3C3
-:10A53000FC4BE1F8FF9BFF7C76ED6145FBDC3527AA
-:10A5400015EDF33C1F28EAC302FE524073E10F1FD2
-:10A55000712988FAE5B7F5AB77E54F9FF4DA120D6C
-:10A56000C4DB06F9993FBF2DDDBD01F0EB7D8DB752
-:10A57000DE4CE13AF05C23BBA7AB2207F38756F130
-:10A58000397E39EC6F9F3C44F1E64B62407FA7EF88
-:10A59000F05D5A7B6E673C28BEA121CEB03CB46210
-:10A5A000A355EB447F0D7146C29BC7D318DE61FEF5
-:10A5B0000FA5F7E946A28BA7743E7DBA84F94ED366
-:10A5C00009CB87A6A5CF4DDB2769890FEE352E373E
-:10A5D000697D068CF329CF2F1BF8BDC7243E4E7131
-:10A5E0008E5976CA98973675108B0F3E606AC47381
-:10A5F000A4334E3C7CED21DA4ED67B8A58BEB5386A
-:10A600007FF607CD3789FB3D9E46989F5DE27164DA
-:10A610004987F761A9BF9BCBD73B495E2743BE4B18
-:10A62000F003827AB7A03BBABE13860276BE027EE2
-:10A6300077A29CE87CBDF17CF3965278BFF2B41D02
-:10A64000E15233685D1EEC63CD28E953435EC8AE2A
-:10A65000A959F317ECA74C7EA51EDEBF7E96B9C2A2
-:10A6600007B6523BC51EEEAF0CCC01BABC93FD231E
-:10A67000E67DAECE87F8F449DD092CDF1FF14E11DF
-:10A68000E819813A7F44BFE4B7F50F08BF80F013A3
-:10A69000083E20EEE17B3D8DF305A3D41DEF4FD3A3
-:10A6A000B252F0CB039DF9EB9B77E0AF6FFE3BF925
-:10A6B000EBD7C5F3CA642617D5F8ADC66B81CF704A
-:10A6C0005F37FCDEC00354DF03B93A9378722B295D
-:10A6D0009F9DBEA4413754FAF678BDCC74218344C3
-:10A6E0003867F2CDF9B91DF74D2E95D13E10F90915
-:10A6F000621FAEA775D233BF4A4BB8EDBE29DBFF50
-:10A70000ED7AFC8539DF4EAE11853E604DEFB4EE3B
-:10A7100084F4DBAF5BD9FE2F5E77D8F99739B22688
-:10A7200074DE03F287218FB1DDCBCE33566435E082
-:10A730003DF164503006F4C6A50765C443A2756AAE
-:10A7400053C2EE976A25BE0F011F970C5B82E7E0AC
-:10A750003ADD0B656AC27371EAFBA144BE7035EF46
-:10A76000477D4F5435CF13AE56E5ED0C49E7E7086A
-:10A770000B4801CBAF50EAA5EAB2AD8E28FC926D32
-:10A7800037EBD00F5092BEF7479EB4D03E8CEDBC55
-:10A790006F13EEB06F13FE9DFBA6C657D9BC13CF47
-:10A7A000437D537C2576E73C98B7E0C3B320878B85
-:10A7B0008E3BEB80C10BF7F98B7BADDB2576FF4C35
-:10A7C000FBA704FD4677BA1779F069379EE71CF8B6
-:10A7D000AE536679042CDF40E829426F19DA1A94E7
-:10A7E000D9FDF5FC1C14CF0BFABAFCCBE1B7A09E47
-:10A7F00023FC6FFF2CBFB590737B8C8C3E847FB0A5
-:10A8000030E0423DAE4DE72B827BE83DFBA322EAE0
-:10A81000013F4967FBD4D5BDAD4931EE9FA4433B11
-:10A82000E7EFE2FED63299DDD37CDD2FA3FF6EF594
-:10A830000F7FF7EB67ED77B6EB6B2CD723DA45A2EA
-:10A84000ACD1B0731205A576CCDB037B09FC77C2D3
-:10A850009FA77EFF5066C9CE74F42F0DC3FB34AFA3
-:10A860006F65F3E96A5F6AD60471FC2EDBF9F8358F
-:10A87000078B2CE1F7607C9E2E097CB65C3486F653
-:10A88000F5EBEEFFF0E074857EF3FFBADD3049A60C
-:10A89000AA23958FB99297E9A784E9A9B3881FCB1A
-:10A8A000392488A59BB07CFAF9C481E542E2C2D282
-:10A8B00095E9FE281DF35B8289980FB9EF1F7D0192
-:10A8C0006FAE8D18DA00B973FF2A3DAD3DDF8EE320
-:10A8D000B7BFFE8F0CC86BB913FDF78B71B6A647D7
-:10A8E0008827FF67B18CF11392BC12E9A19CDF921B
-:10A8F0004046B1B8D88F12B3D83DF51DFC2F69BBC7
-:10A90000E07F106FCDFD54C3F243964A787F6B739E
-:10A910004083A495BB28CB0BF7F13437B1F6DC2A82
-:10A92000AB57A2F5DCC151AC7D85D50BE71E669314
-:10A9300000D2E35C38F520C33918C6DFC43DE554C6
-:10A9400063CF063D6B518B91E5EF93404FE0E37988
-:10A950005DD8376333985DDC2F9BF1ED7E254A3F50
-:10A96000444C06E3035599254B3368B92AC3190BA8
-:10A97000653F9B7FD34F0BD12F8FBFA3F2C5E0075D
-:10A98000317E28BE7B32B3241EDE7B5562F9E69E03
-:10A9900083FCF706483031FCFE505766696A061D95
-:10A9A0003F2B83303AEA02AEF07B73AE08F69CC8C8
-:10A9B00067EC073615FAC7D93D54AF4AAC5EF0BC18
-:10A9C000EDBEF57DD187EF01BDF6C94CF73D387F6F
-:10A9D0003D212698FFCF0DDE1DA87FD666803F72F1
-:10A9E000C9F3060DE8051F51B10AE74AFE5867C4CE
-:10A9F000F2636AE742F9276AE742F929B573A1FCD5
-:10AA00008CDAB9502EBAE12084F28FF7329CA3324F
-:10AA10008A42F136F57C877378768C7F508FE357C6
-:10AA200065BA11BE1DFBBD9F78211EF2AA35986A3A
-:10AA3000BB0DBE75CD673CDCDE8B9C9FD59FEF7B4D
-:10AA40005E9316E5785E73206671D87B9333F4D8F5
-:10AA50009EFBFA053C1FDA66E980AF53A24B9EA429
-:10AA600061F5C9CFF741F856653A97C23E52FAFEF2
-:10AA70000E9479CDBFFB099CE7A1FD631E41BB1479
-:10AA80007C0AF57CD53AD47010EB7AD5EADF04DF86
-:10AA9000BFFA7A36AC84F21BC2E806F0488AB4DE0C
-:10AAA0007508D7FB0CC14238A772DF2D3962DE7002
-:10AAB000556631C25927F04DC089EFD7B7A5EB8E47
-:10AAC0007836C75322EED700DE690739743306F4AF
-:10AAD000BA721EAF6F6EEAF93EACCF734226BDEC80
-:10AAE00088BF0ABA7B8EEF8F28730FEA5DB04FAF35
-:10AAF0001EBCD813EE5BA5FBD213EE5FDD9CD14BE1
-:10AB000091DF943BF8EFDB7E1A8FEFE3EF7CCE20F2
-:10AB1000DBCB209F64A6F1F03158D26CCBA76590B7
-:10AB20004F3237593A0EE53C7BD668C82311F9EE0F
-:10AB30000BFA141F07529AE028477DAC18984B98DF
-:10AB40003C283546F3CB9F85FC8953D4C7247757DF
-:10AB5000BC3FCEDE43D13EBECF3D8A7631EE0447C8
-:10AB60007FC57BFD6CC16CB0BFE83AD87DD7BB64B4
-:10AB7000CCBBCB7DFDF4BDF7D0FAA417A7E2FD7ED8
-:10AB8000AFF2F6497B4BF1F703DB293CF55491BA60
-:10AB900034E8B1A77E0A9DA9F4FBCA832F1C77DA9B
-:10ABA0006FA3DFDF41AF17FC75798BB108F8EBD7E6
-:10ABB000D5F3D5FBB23F839F0BE47A7F57F8D241A0
-:10ABC0000F929DE10BBF674B8D2F9059CAF08F9567
-:10ABD000934EB17360DF948F7D0E7C2CEC1C664726
-:10ABE000A9F2B7F5D33BDE5F05FEF7F76482E7EA2B
-:10ABF000F8F9BCC5F0FF7208CFC9C2ED8FC07D5215
-:10AC0000F4B907F44F3807EAA4FDFF3983EB4D95FB
-:10AC1000871F49290CB593D59F2ADE276BA50D8A7E
-:10AC2000FAFA2C657D73F186F0EFBBE2878BB7CE25
-:10AC3000D3BBF1FCA614F1F75AC57CCADE8AC2FC6C
-:10AC4000BC899077421F55177EA085F8EAC42EE490
-:10AC5000A7E03B3364521BA9FD6606F3DF4F782B58
-:10AC60000AF359BE69BF1F515862BEE06F98FCFCE1
-:10AC700028D6AF0DDF774326EBFF5AD1961F7E050E
-:10AC800071CFFD04F337AF5919DFCF6BFA42A3A19F
-:10AC900065BF6E0C5FF22C010DC893F68A680FE455
-:10ACA000E7D72C35635E67BFECE087C67C42623332
-:10ACB00037FFD848F7ED0F7098314C9EB6838D431F
-:10ACC000EBC9FFF138F2FBF16F45F934DF623DC9A2
-:10ACD000548742795DC2E87B0EE00D972BE03BAFD5
-:10ACE000798474C819E007B07EA84FCAFCF1FB4F05
-:10ACF000D2716B4E32FA864C39B5DD3E33CC6E27BD
-:10AD0000CF31BA34D27FA0CF2D3BDAA0077BEECE75
-:10AD1000F4DD8879335F97AE0B3295F67B043A3ECB
-:10AD2000359EEE4BCD7E76BFC4F5965E78AEB52BE4
-:10AD3000F95DB35583F427EA6D2DF258C057F5F944
-:10AD400070014F62C951DCE3B472F8DF26839C5C6A
-:10AD50007950CB923DBA1A67A386D8C3C679F590CD
-:10AD6000A182FD0E259B7FBB90CF07FF6A2BEECB08
-:10AD7000CA7511E41C95CBBA7890CBE5ECF715CEEB
-:10AD80001C4C2A01F89F9188CF8EE7AE589EF1FDAA
-:10AD9000AC3B786EC2FB4392FB68C3EF371476E49A
-:10ADA000D483537B811EF961D3FC337467C8A2CC72
-:10ADB0001E38DE34E241BDF78CD5950EFE86493C47
-:10ADC000DE7FC61A6C057E7C6678B404F17BDAFF00
-:10ADD0007A12765FDF199D2B9DDD0321F28AEFFE4B
-:10ADE00056F7B695C96B8BC743BC7A16B1801D79EF
-:10ADF0009FCCF45AF226A34BC1EF6A24BF0DE6E9BB
-:10AE0000CA9CFCFD4CFA5DD29A1FA15DD901372D79
-:10AE1000FF9DA6AFA9D776D8AFBB25763F8983E93A
-:10AE2000FBD5C3AEFE6C1A9C73A376B644E733BF62
-:10AE3000F930DEC3A3B6AB3BEC9BFFA57FB4B37D7B
-:10AE4000E4DA925914F27BABEDA40EBD5CE877BB5B
-:10AE5000589EFB91E14FB72DA7F5D5BBA2118E9758
-:10AE60009F3778807F5FDE61407BE7B22D786E157B
-:10AE7000D4F7E63A3C385A0E9EEF12F8BD4463FF11
-:10AE80003DC81DF25B1DDEB7F1C5CF0DF87B1E4B33
-:10AE90005FB86B07D84F5FA4DB5F7E05FC7B2F2775
-:10AEA000E07D0024997D3F91D323D0979DEE87FCD0
-:10AEB0000B33EA0D4B5F4B41FE25F6EFD2CFA3F0EB
-:10AEC0001CFCE513F7C7821FAC55B387FD8EA46C3D
-:10AED000F2001F5EBE230AF53EA277BF06EB2FFDF0
-:10AEE000C5C469FD61FCDF2510584F7BCB6BE87F43
-:10AEF0000CED6F64B97EBDA507E3031D7296E5CD29
-:10AF0000CE0DDDCBBC1FF0A78A887B1059DE6C818B
-:10AF10002CB1DF957C22F239F0DF66F238A9F09788
-:10AF2000C4116332D0A19BB07B1F9FE88DF7EA9ECE
-:10AF3000CFE4E79749909F7714F876AEFA00FA4B82
-:10AF40000C2C5FAF8B7B2D3FCC64E782171BFFA2DD
-:10AF5000F09B54AFB9A1ACF765BFB35C506FEFBFC6
-:10AF60008296AB389CFF91E4FA08D6B7AC71CBBEA1
-:10AF700077112ECF7DEF0F30EE0913FA69C8BB0CA5
-:10AF80007E6AFB65B131C8E30EDB1571F58BCFFC32
-:10AF90001EF3472EBE7E0FFEBED87CD97F11EEC7B2
-:10AFA0006A33FB3F7988967B4F9CC27D51CFB75364
-:10AFB0001C5E627CA512D6D11FF2575CED9948B792
-:10AFC0008CDECF6FCA45F8093F6DFBE5C8F6959852
-:10AFD000A7E85FCC4FF42FDEFBEF4CA6DF5FD3FB7F
-:10AFE000F3402EEF843844983E7F2DC69F073F756F
-:10AFF000BB339DE5735FB3D17A18DEFC5F8A9C0C8E
-:10B00000C3008000000000001F8B0800000000004B
-:10B01000000BAD580D6C14D7119EB77BB777C67770
-:10B02000F6818D7FE21FF6CEC4187CF816FFD5B1ED
-:10B030004D39FC832842CDF193D44A216C9A4028A3
-:10B04000C4F864438B92AAAC7B95F911515C358AA4
-:10B05000A04DAB83081455541817228A30BD04152F
-:10B06000701BD1438914925A68EB36D46D0CE7D229
-:10B07000A42D6A2477E6ED1E77EB9FB4897A966F4C
-:10B080003CEFCD9B37F3CDBC99F7DC01F8A906E87E
-:10B0900070823D37176907532238D401A0C13C4E56
-:10B0A000632ACE3F5770016C35240C21671EC063A4
-:10B0B000607E72736C500FB091FE9671BCE1B7F771
-:10B0C0005916C01330608732809B42EF1E49041826
-:10B0D0001FF8A15D7591509BE7760500D33E1026C1
-:10B0E0002B0126E9B3623A05B001C9D16752A46FBA
-:10B0F0000D603E7EB7404518F5DCF1B834210050B4
-:10B100002A331B972B811292C37925568B74D0A1B9
-:10B1100044D09E3D42C827E3BAE7A4581588A975D4
-:10B120007B04958F8FB3B7B7818FB68B5585DC00C5
-:10B1300089B912B06CA4F3957810F1D03E01E50402
-:10B14000EA49D8A16310F7AD6D15C283DC0FDBA807
-:10B150008EFB0AC0B87DB59538EE07584EE34ED346
-:10B160006E2F8E07ACF2297FACFC0559E0FED5E6C8
-:10B1700008E101FF743C36D07C1D40046222E18A64
-:10B180009F8D4EC4BDC9C41D202802C66597C9EF56
-:10B1900072BA626215DA9DE5D444F4A7E922C605C5
-:10B1A000F9265BEC4DA22C08B017E30BE7EDE30F9B
-:10B1B000EC201C0A2A6DA4A7D10C2F435D9B50AE36
-:10B1C0008F8581F675423FA787589CDBF16598E033
-:10B1D00034081E1B51849FD3360871BA0AC29CAE34
-:10B1E000867E4ED7C000A76B21CE292C8945C04B47
-:10B1F0003B7DC7733B13C9579E152691D67E0DC262
-:10B2000003AEE938EC31719A1D078D513E7E5E1C0C
-:10B2100056815AC0F54DC5A3B882E7F7543C1C943B
-:10B220008F18B70C8816105D0EBA487405252EEAE3
-:10B230005909B28DF8560872BEFD7FC4A141576D01
-:10B24000AA7F063C5A67CE8BEF9A7921128675A9A0
-:10B25000389D9165CE27E305686768E9F43826C70D
-:10B260006B335BFE2E7B008E46DB42B642E46B5AAC
-:10B270007ACA90FF99BCD1E09B5A7EE143FE54F418
-:10B2800031830FB4D4D81580DEDEC7436D8F00A89C
-:10B2900019595510A0C2512E50FEECF618F8ABBD4E
-:10B2A0007B140F9E23B5C4A5907F4E076286F88954
-:10B2B000652234206D93D49765B4B37475BCCF40C8
-:10B2C000B825BF03CFEF78DC0E8770FD7EC990777D
-:10B2D000E03A6775CA2F1CD732901F1CACEC61BED8
-:10B2E000D9F747FDC748BFDAFBB00664C739A67C6B
-:10B2F000D63E3FCE574F923C38CB81E25EE434F4E9
-:10B300008C0F5656525CCE1048349FEBAD21DCFEBC
-:10B31000921F3A43F209B7915F672807E7CF4EDFE4
-:10B320009783A7497EEA78E2433400D7BF25ABE78D
-:10B3300068BE2BF3D372AA4B7797BDD3A77B537903
-:10B34000CA70FF4DE87724085189D79166CF6DAC5C
-:10B35000A3803199C47826B6A21EC4A136A446ECB7
-:10B3600038FCA54D13F558A4486F8CEA5D97A49757
-:10B370002EC3752F6FB8251979566CE499598786B5
-:10B380002E0DBF5064B021483B575D97EEFFE3F7A9
-:10B39000885FD73D9742E2A9F374B407B248C86505
-:10B3A000A91BC973D678DE1113B3885FBC95E496E8
-:10B3B000BF3352467EAD18D1236ED233F45E916115
-:10B3C00087D91782FF645FA42FB48B549C01BACF36
-:10B3D000895107E2D5CDC297DDC4FF9C291ADAFF57
-:10B3E0006727E64736C9075D85E8D776D3AFCEE154
-:10B3F000137D6EA4DB5F7D7A2D54D171B0F3FA2DED
-:10B40000E30F9DFF9DAFDB53F59C7F6320D0CF2ED4
-:10B41000487E6212E541E78055AE0B0EFF8DEA4E85
-:10B42000577A9D47BB2664772EC7DBEC57402D0427
-:10B43000F53D6BAE253F5C64F790147530A43FE991
-:10B44000513CC49BE7072E7E0FD2E5E1D51C1EFBC5
-:10B45000E479FAE601B43D278557E0A42348B8070C
-:10B460004EE607C9BF80045B421CEF28CFE300E62D
-:10B4700006C37C3A3D77C227E03EA7872A14ACA0DA
-:10B4800070615F10FEB830655FB7799EDAC553AD65
-:10B4900012E6C1BD67C0834712BA875F8B3891EF50
-:10B4A0003E082401F7E80BF5DC1B13A2A4A771B832
-:10B4B000A680E27DD63C9F8E0201E4349C32E439C2
-:10B4C0002057A4F824BE0E333E9915F32CF36EE5F5
-:10B4D00021CBFAEC069F75BD168CFBEBA91E1BEB6E
-:10B4E000E7069758E4F767ADBA4679B93CBE6D2DCB
-:10B4F000E192B3BADA325F0F4E7E7FA82B762951E4
-:10B500005C0F1F1BFDBC017F783F80B048FE35E912
-:10B51000003FC278348EDB2C71CFD0311F512EE327
-:10B52000DDB4B8E3AF43B6F2CBBC661E1443717A08
-:10B530001EA470763DC091E7C1300A11CE6E298AF3
-:10B54000578E6938D5C3C26C9AAFBB264294E3DEEE
-:10B55000A3C4707C7EC88A777E8715EF42D58A6F38
-:10B56000D1762BBE25612BBE0BF65AF1F46A56FC40
-:10B57000CA0E345AE41FEE6FB1F08B8EACB1C82FF7
-:10B580008EAEB7F095AF3F61915F3AF00DCB7CE0A6
-:10B59000FC0ECB7C32AFA6C67D59ACDB223735EE34
-:10B5A00035D79EB7E84DC659C39FFF679C774D8935
-:10B5B000F3F3681B9DBBEB596387E9187E35D3A86D
-:10B5C0004BED62733C48F16EB62B14D3DFC939AD35
-:10B5D0006E3AEF661F0A997D08D43E1EF7909927B0
-:10B5E0004A5CB94C75B4FA66A8350BF95A3D7C999A
-:10B5F000CA71FD587F6BB6CCD344F6A03C33717949
-:10B60000B48181CD725E90CF4BE1B641EB15B35161
-:10B61000B8E9D36884974B4A2ADC7FBD39CF1A8CAE
-:10B62000BABE2E9801B6343C969BE3007E6E5FB3A3
-:10B6300031051BCCF700DECB41A27BB9E08C46BCC8
-:10B6400033DD27952322BF27A9FCDE7495A976A2B6
-:10B650001B9DF152EA5FC7F2D4235EACF377054538
-:10B66000E6F72CA647C8A90439C69BCE8D50D04F0B
-:10B67000F777FCF321ACBBC2F590E6E7E67B74B448
-:10B680005F35ED39E1558F919E51E6E9ABC1B5D7F4
-:10B690001B3F2AA5FEE3101109AC8381ACE06B349B
-:10B6A000AFED6F9ECBFB6A3EFA87755417647E7FC1
-:10B6B000D09E67FC3DF011297B24ED9C1EB0F3BEAB
-:10B6C00003E6FB68B38957F27DB4C9DC7F14556C7F
-:10B6D000C73ABDF9FC558ECBCE8271B0E5F07CE364
-:10B6E000F7A4A78B5DD587C8A7608DB27E298D276B
-:10B6F000DF4B45E2E7E98BEDA23F5B9FE1BE98A4FB
-:10B700003B0BC6F87BEEC1FA53461F995DBFC6FBE3
-:10B710006CCA6F43FFE8C14CDE5F460F96B4104D14
-:10B72000E9BFCBF56F0EDFB0E4C996BDEF5BF2EF7A
-:10B7300029ED0F96793D77C25E84FEEB6F14AEFA69
-:10B740003AE277E79CA39EDE8D18B79BDEBA947E23
-:10B75000FDC5456DB4DF7FF7F3AF1CDF917D71B0A0
-:10B760002D4CF9796BDF4DCEEBFB744EA7FA997C2B
-:10B770006726A9F41654D8303E136C8E72DC3B7DDC
-:10B780009F2D3EE35D32B232AF85FAEC48896433D7
-:10B7900068B9C11736380D7ED56AA209BBEB00BD6A
-:10B7A0003347180419E6C32616FAE953E8F70B796C
-:10B7B000EA27947F5D3B26AA6C781EBA02FA930CA6
-:10B7C000E3593C57FD17F9CFF07A57388FDB594EC4
-:10B7D000F78E3141AB62580BAA7D85EB6C1897B19F
-:10B7E00039DA5DEAC44B8EE71ABC649C8F46DF24CD
-:10B7F0003F0FCD1E55F0A19E0F9918E3F9FC4B1693
-:10B800003DC1F34D97D6BBF979EAA07717BD77E92B
-:10B81000BD91C83068868F71FFE64CA10B7D463D17
-:10B820006B3469BB78B89CD1FDE08803E83CE03E0E
-:10B830004181F61972444F209F87B6D33DE5D792D8
-:10B84000719FAFFE95234675639BF3631EA7129FFE
-:10B8500097EBC92DC3CA85EB725F724423649F1EA8
-:10B860002F5D87F6F5DBF1FE42EFE977711ECFDD44
-:10B870009D17171D3F94168F12330EF00C80319FC9
-:10B880007F8CE63B87476F511DB9E255BDE4FFA8A9
-:10B8900020D7531DE9CC7A53A2FA53E393F93AB473
-:10B8A00097FB8FF5E0FB8CE3ECF4FC09F3750B16CA
-:10B8B0009B6C7ABF09EA625ADFE9D425D28719C1A5
-:10B8C000EF7FB3F97F676BFC153FD2BB6EA594F693
-:10B8D00049EE8B76D4909EA4DF493B527A3E3BAF33
-:10B8E000B739272CE7F7F6D1FDE5744E105F95ECDC
-:10B8F000AF16D996F533AC7FDC8CDBBFF3432B7DE1
-:10B900004877847FF0C6DB726A3EC1FABFF501C595
-:10B910006BD8C5EBDC6CEBA7FAD9796998E3817E2B
-:10B920003E49FEA5F9F928ED93F4F3CED07BAFF8AC
-:10B93000E52FEE5FA2242E91DEC4B1FBA532AEEF5F
-:10B94000BC78F526E54FA7F9CE87B3D6F7BB630ED3
-:10B95000BE13E7A5D573AA710BF8344BBF3F3992DC
-:10B96000EB8B6DD6F578511670BFB3E6FBE13C9DCD
-:10B97000DB19DE9967E3026F95670BF07E467D0069
-:10B98000FB2ED5FD64DFDD7D43E0F9B8DB0B7C9E4B
-:10B99000ECA2FC67FA15DE0792FF478830EC6F983F
-:10B9A00007DD92FA6DCA0F507B785F1017B814CA82
-:10B9B000E3C1DFAC31DF4B469FA933FB4A1DE921D0
-:10B9C000FBFDD9BCDFD49AFBD63BF11EE3A392ADBD
-:10B9D00099FF2F31FFAF70F00A7F67FD0774153EA6
-:10B9E000C90014000000000000000000000000007A
-:10B9F0001F8B080000000000000BFB51CFC0F003BC
-:10BA00008AB7C9333098293130242A33309C01E277
-:10BA10002479841CADB02A0765FA5F303230BC024D
-:10BA2000E23740FC8E9174FD3F8510EC87BC0C0C16
-:10BA3000BF80FC8D405A4C8081E12690FD1B88BF61
-:10BA400003F9E27C0C0CCA406C06E4BB00E93C2024
-:10BA5000F607E23F407E1B1F6EF3FF0AE1B7FFAA25
-:10BA6000002A9F571095FF911FBFFE0E41FCF2BCAC
-:10BA700004ECC7864FA8911F1F3CEAB44F33D4C4CF
-:10BA8000371950F9A7651818EECA323028C843F89C
-:10BA9000D790E48D8062676420ECAD620C0C7BE58E
-:10BAA00018182E336037771B507E1F50DE0E6A0E3B
-:10BAB00000B5BC7B1E680300000000000000000011
-:10BAC0001F8B080000000000000BE57D0B7854D5AB
-:10BAD000B5F03E73CE9957662693848484F09824FB
-:10BAE000803C020E010248A893071425C008A868EC
-:10BAF000110651088F3C44ED976BDBCBF04AD1D255
-:10BB000036D6B6D25ED401E15EA45803448D1A60E5
-:10BB1000806051C106EB03ABD600B6080219A0EA5B
-:10BB200048F1F75F6BED7D92732633407BFBDFBFFF
-:10BB3000DFFF8FB5DB7DCEDEFBECBDDE6BEDB577D9
-:10BB40005496CE581FC6BEC1DF8D8C3D2031868FE6
-:10BB5000B4127EFFEB9B0CC6A65AE1BF64C6C6CBEF
-:10BB60000EC6463036C5C142166833A5081E766338
-:10BB7000ECCD4D5248C63ED02E58C8D822C67F5371
-:10BB800015D6245DCFD885D13BEB867918937C3EC2
-:10BB9000565B00A5C7CD666159B4F72BC9C558F2ED
-:10BBA00068136303789F6FE0DF149F9DC6D2EA6934
-:10BBB00013530DF5747F0F43FBEE33730DEFB30298
-:10BBC000830CEFB32B0A0CF55E353718DAF7A92D85
-:10BBD00031D47382371BDAE7AD9966A8F7ABBFD3D0
-:10BBE000D0FEBA75771BDE0F0C2D32BC1FBC65A9C9
-:10BBF000A13EA4E12143FBEB9B5618DE0F0B3F62F5
-:10BC0000783FFCE0CF0CF591ADBF36B41F7574A33F
-:10BC1000E1FD98B6AD86F7633FDD61A88F8BBC6C04
-:10BC2000687F63749FA15ECCDE30B42FB5FEC15037
-:10BC30001FEFFEC0D0FEDB99270CEF6FF27C667819
-:10BC4000AFD1C1A401170DCF277BFF66E8A7303F16
-:10BC5000009B3133ABA1D2CAEAA9B4B3062A1DAC0A
-:10BC600095CAEFF60EDC49F4F964B08E01DDAD0C37
-:10BC700046FE9406E59BA3F39203F9389A8F31A010
-:10BC8000DB297C6836C5EA08CB4067162B0BDA80C7
-:10BC9000145C51A0B734A0BB28A3D21D057A1B0E9B
-:10BCA0007417B552991A4DA5E769513795DDA23D34
-:10BCB000E8797A3493CA8C682E95DDA31E2A33A3C3
-:10BCC00083A8CC8A0EA0B247B480FA6547BD54F66B
-:10BCD0008CDE40CF7B454753D93B5A42CFFB447D56
-:10BCE000547AA2375399139D48656E741AB5CB8B5D
-:10BCF000FAA9EC1BBD939EF78BCEA4B27FF46E2AFB
-:10BD0000AF8B06A81C105D44E5C068059583A24B67
-:10BD1000A9DFE0680D95F9D187E8F990682D954382
-:10BD2000A32BA8BC3E1AA4D21B7D84DA0D8BAEA136
-:10BD3000B220FA337A3E3C5A4FE588E8AFE9F9C8B9
-:10BD4000E83A2A0BA31BA91C150D51393ABA95CA1A
-:10BD500031D12D54DE10DD41FDC6461BA82C8ABE14
-:10BD60004CCFC7459BA8FC16D25B1AD25D984A5FA0
-:10BD7000F4757A5E1C3D486549F42D7A5E1A6DA50E
-:10BD8000B22CFA477A3E3E7A94CA09D1E3547E3BFC
-:10BD9000DA46E5C4E8692A6F8A7E4AE5CDD10BD43C
-:10BDA0006F5234426579F4123D9F1C8D52A9C93BF4
-:10BDB000365A3DD3A6D15F2EFEFF2CF75F06835C7B
-:10BDC0006201D337503207D0C198CEF6B125483B37
-:10BDD00092932AD05512D0770AC8429487536AA406
-:10BDE000D0B773803EBAB5B5605D1D6DF158A07EC9
-:10BDF000178BA848BF1FB13627CAD3BD634EF66C58
-:10BE0000037A7D333DDC0B881B7F246F559C531ECA
-:10BE1000CADB334A1B3C9FD26D5F7AC081FD8137FC
-:10BE20000A90BCE1FB48DF408E38CE5D0A0BBA6059
-:10BE3000AA47708431D42E6C81FAAC72E62B80F65E
-:10BE400075632C3343F09DBA027F851FCA1FE7F844
-:10BE50006762F93A320FCC7FBF288F3013953FEEDF
-:10BE6000EDA672D67DFD383F950110B3AE0E87F476
-:10BE70000CDE8F3922BDFD43AEBD9FC2A0DFC8CE10
-:10BE8000F6CF30FF3BF83C58C206D4383ADBC1F35A
-:10BE9000A3D82ECEF30FE23D6F308120007D154CEC
-:10BEA000358736A37E629EE45B705E564FF2346740
-:10BEB000E2793DBC2C335FE9AB9F6788E6F7B0C4FD
-:10BEC0006636D0F8BECC6943687CC27730D51ADAC2
-:10BED0009C43A830D0CB5F119ED02FDFEE6FA7F52B
-:10BEE000413FBF13E1E3BE26B840BF2F089E0AF4CE
-:10BEF0001B72EDFD1297F54CCCC343E389E7D516D1
-:10BF00001694004E91CDCED0C61C5C9387E4678515
-:10BF10005B08D06E000CD0EB15290842C65A762774
-:10BF2000854DD0BE68B37323DA01ED25C18CA90815
-:10BF3000878D2ADB0C4D56ECFED1BBFF01F5A20D1F
-:10BF40002AB3407DE1C59F1732A0A3EB24897F3F30
-:10BF5000E8DBDB17C60F30EDE79370FC058C8FDF55
-:10BF60002E09B86E4E26BC7D5AB6A96E2C946DBBB8
-:10BF70002ACB19C8F19300D62CA0EF8576A660399C
-:10BF8000AB66BB99E834A87ED2A6E917E267A5B3F1
-:10BF90002E77AD2FC0BAC6FFB0EE8521B5B30EFF28
-:10BFA0002EDE62ACEBE0457650E4BC12DA487495C4
-:10BFB000CDE1A3C1CB97CDE127E055765E099ABAD2
-:10BFC00011BC42280792250FC1A1E2BC1296619CC8
-:10BFD0000A8023B260C5AE8733104E8BB7D8DC9F82
-:10BFE000E8BE5BD99062A8573765B93FD1E9D10B5C
-:10BFF000079F76E1FA97669ADC9F807C3BB3CC97EB
-:10C00000F609A0ECDCB289546AF451D990E37618B1
-:10C01000C631D62FD44B131B487F7A92670C494CFC
-:10C02000674B33CDEE4F80554F6FE1FAF6F432ABEC
-:10C030001BBF736699DBCDBF9B49A506AF25B576BF
-:10C040006AAFCD2FD1B8FFECF931D6C84E58519E0A
-:10C05000C3BBBCC4ED13F293F25733F149B3FA05F5
-:10C06000D28D15FEFDC6447444756DDCEA06396850
-:10C07000B91E9F6F337C0FFA79FEA2D32F89F95630
-:10C08000617FD1D1E5FD3800F1A995F01C801193B5
-:10C0900061BC76C5B106EDA8C9827EAAB11DC88370
-:10C0A0004A6B9B39008FCE36727C24FACEE9655BF1
-:10C0B000B251AE5558EBCD28AC2A1A0696213F9DB9
-:10C0C0006D5C9981FA65B17CE1BBFE38FD7FACF116
-:10C0D0006D488D18F56548CC13C635F0197374ACEE
-:10C0E0001BEA674CF02947D7711F97B8DEA9DA76AB
-:10C0F00064C258987F55D37933CE63B214785C4AC2
-:10C10000EF5CBF84EB8771166D39467CFEA91AEC93
-:10C11000FFBD9C2BC0B3CB3C1D997F49D2CD2F08CE
-:10C120008624F0EBDDA305BF32CFED1F007F9E7AA2
-:10C1300043658FC03CD8656805EF7B8BB7F730BF90
-:10C140000BE17577E362923FA750FEA01E66F5856E
-:10C15000481F67996922AEEF2C7BCB355C07BF7D0A
-:10C160009259C0074C59900716FA14C12D0BF5804F
-:10C17000A5A2AE551E8ACF95A0904BD237244F4230
-:10C1800012E9890AFE3CC8ACCB691D6BB83C0AC2F7
-:10C190003F58BFB7DE289F16AC33D6E7B369190AFC
-:10C1A000C897F93F576144906F7AF907F07B46E2F0
-:10C1B0007A7701ABA973C3FC9F30039E60FE77BB07
-:10C1C00099920DEBAB7CF189C2B9507F4DE27AECCC
-:10C1D000F432987E7F182795AF7F516DC8ECCBEF76
-:10C1E000BABE138DC36F1BCB683C9293C1459AFEB8
-:10C1F000651EA590A42518B989D79FDD28FB6C2E54
-:10C200006C07CF75F279DE1AE3FAAEB6FED8F532D6
-:10C21000F633A2B7455B6E614867DA7A347C69EB26
-:10C2200051B748BE501C3E6813F4AAC9B588809F18
-:10C2300066777C1E53BF1453FF26A6AED1B72AF8EB
-:10C240001BE8FE736924F2736402A79336AED744E9
-:10C250003B7367BB4B576A6711FC02EDBEB9523B9B
-:10C260005BE7788A29BD6BBBCA179F7D2108F4BDA7
-:10C27000E8B95FB818D0E329A53EC30BCF976C5E31
-:10C28000ED42387DAA045D4837A742F2C478F01A1F
-:10C290006392347BC32101DEAB34FA2F5A3E05F59D
-:10C2A000FB179B55F7238097EA2D96B005F05DD5D7
-:10C2B000B8B09C0DA5FA315EFFE179A48FEA26F5AE
-:10C2C000B81EAF8BFEEB17191E27E121DB84363039
-:10C2D0000B673328AB36FD7902DAD1D52C42F41C3A
-:10C2E000DB0FBF8FAE1DC8EBB9E6E4AEEF35BFB1D3
-:10C2F0009A3F62D58D3F3A8F7E6335538EEBE9A826
-:10C30000026919ECBC41266737F417D828360AE5CC
-:10C310008A0607164A27B9BCF299C7871E83799CFB
-:10C32000D9F4864BD2C1072C2482CB8586791FA7EE
-:10C330005D412F9C03FA64FDF5FD42D4CFD3041375
-:10C34000E80ED5665E2E51C3AEB100CF251B542F2B
-:10C3500050265BF2ECD3FFF96BE03BF6BEC5DB0F7A
-:10C36000E0BDF8D903EFDE00F5C5DBD56EE57C193D
-:10C370000E29A3131FD5F02FC66534F82FDA79C024
-:10C38000EC19C29F7F3FB5130F8BB7EF35B3215D1B
-:10C39000E156DAB0D7DCE688838F866313D09E59E6
-:10C3A000F9CC9766C4F7A9DD12EB9ED3B57FC5869D
-:10C3B0000364BF209C087F023F1DF8EA82A7F09427
-:10C3C0009747503B37CAEB447872A2AE1E4974FCC3
-:10C3D000DB97E1FB157FB47871FD15BFBDDF85EB01
-:10C3E00038A9D4707A7E6275860FBE5BA10633DCF5
-:10C3F00054F2E7154F3E4874B6E0C8836497017D58
-:10C400006499486704B3707DF7AEBF95D6379F0532
-:10C4100088DE2A9E90FD2194030A9BB83D0E3F3C86
-:10C4200027F8E1E4469094B0BE93281FD1CE7D4B0F
-:10C4300016F2F13EB2231F146B054B86EA9F5B395F
-:10C440009EEA4C262D2E6735D0E9A61F921C3DDDB5
-:10C45000CBD7DD9D4F70D0E426C953F9C8F8EE1C48
-:10C460003F5CFE523FA0BB527C8EED5B559F6DA89A
-:10C47000A19F9097FCFB0F88EFC3BCED687F9CCC1D
-:10C48000E07A22767D7F3469F211F4AB8EBE747C43
-:10C49000CDF97CD3C39CAF353E0FDD3211DFFFF504
-:10C4A0006DCE3FD80FF50FCC2BDC9DDEEF9D21919B
-:10C4B0001CB0B0703C7EDEA40A7E36BE07094DF685
-:10C4C0001BCC5B9192F57402E3A712FCC92E99FF75
-:10C4D00073E8A7B3A7ABF17BD4CEDCF93CA7936F8D
-:10C4E0001708FEDF8AFC9FD4C9FF6C7DFA35F96717
-:10C4F0004BD4D07FFE1AF915F833E8417E55FDB8CC
-:10C50000EECFB6ED7FF74EA0EBCF1A343E35CACD55
-:10C51000583EADD8F12043FA8CE5D3CF7AD6B0B8E7
-:10C520007C0ACFE3F269CFB6FF11B9A9C1ED480C7F
-:10C53000DC400E3EF5B22731FC62E560B5C9135709
-:10C540000EC2EF6D56D895EE347AD3E86CD16F2ACF
-:10C55000FBA0BCE9A0478DDE3AE851A3B7D8751A15
-:10C56000E116FB7E3DCA1B9D7DA0AE604127E039F0
-:10C57000B24B263FB1DD1371A5C27757DBD81CB48F
-:10C58000B3DBDDA29EC2EB9174731DCA05ED79C4C5
-:10C59000C6E30DEDFE882B45673F1F6B965D1E7849
-:10C5A000DF166213E3D9D52071E9FB6D2CD1FBE5D1
-:10C5B00004BFF1B2A377ED08F4AB642FDA6EF72C69
-:10C5C000BFDD85218BF6E6BCA933E1F9BDAFC91407
-:10C5D000D368B7BB86E2BCC06F57B200BEF3049EFF
-:10C5E0003F65C15F16C1BAE63573BBF89EB54678A4
-:10C5F000CC773C60463903F667271DE8E845DB2722
-:10C60000A8586F7CBF88AD257C2D8AA19F80F077CC
-:10C61000B264413FC3D830E16F9870BCA5424E8DE3
-:10C6200097F3A7CE04B8B71F949905EA179A6556F1
-:10C6300087EBDC268518F271309DE8B00AE403D35D
-:10C64000F9856790CECC89F9F7CCF31F157E0F9A48
-:10C650002C79E183A1FF01E59917DEEFFF0AD65F90
-:10C660007CAFF707AC6BFBD2DD5FCD46F9DEBEDBFE
-:10C67000C2284EB2FB77BDBF87F5972D5E8A73AC9B
-:10C68000B0F0F8D46E67A81FBEEF05F8467DB9EB91
-:10C69000CBA16DA46F56119ECA64EE475C68FEDBA9
-:10C6A0009FA46E58C2AA508FEE4E22FBBAFA655B69
-:10C6B000089DCEF65D5F16061CFFBCF554995980A7
-:10C6C000E8CFC966EE407A4D01C4C1F7AB5F19F3FC
-:10C6D000F472F87E65E35EF33C785FBAE7EBA1287D
-:10C6E00057DA7770FBE09CDAF624F3323655FEC554
-:10C6F0007215F0750E6DB51E2097E4778B838E78DA
-:10C7000070E170680738E0BA002E15280F13C16376
-:10C71000FEBF2C3CCECFC6EF2F691EC5E41C3D5C8E
-:10C72000241F7FEE0C59255A3F7FBEFBCBA12877F3
-:10C730003F6B584EFAFB6AEB5E8DEB4EFF7F69DD77
-:10C7400052F85AD6BDE95F76DD9CFE07C95C1FC56D
-:10C75000F241573A7FF1BB54FFADD34BF3BD46FED8
-:10C760006FF9975DFF3F88F71D12EDC75D0DEF274D
-:10C77000FE65D77D35BCBF26F0EE7463BCB77DD7B0
-:10C78000D7BD996EFD575BB749F957956F575EB79F
-:10C7900066F7B49A6ADC23607EEFB3FA5B73A0FCA1
-:10C7A000BDEF623774478107FCF1FC860285FB0D03
-:10C7B000168C3361C35B252D5ED46AD8C7ED594111
-:10C7C00076C614DF8FC93E604A4D6B31B46F2D9928
-:10C7D000E77D845A141C0D607DC6385137FA536FBB
-:10C7E0004ACC27811D3BA564D241B4EFA6FA64B2BE
-:10C7F000FFA024BBEF9DDE13F8F3D1463FE28E1875
-:10C800003FE0F699C6F7B78AF16E634BDD23005E11
-:10C81000B7F554DC2100D11DC5352AAEE78EBB2407
-:10C8200056AF8B57DE1A339E4B61224EF28FC1EF0B
-:10C830009E0EF82D2578B062D9BB995D03FC188750
-:10C8400077EB8C61218CC330C5CBE1775BA597E298
-:10C85000A0C2CF54457FD5B1A615F9566546FF5203
-:10C86000F31313C19909BF93C6C9ED84BBEA93C9F9
-:10C87000EFD48D47F0D0F0F1F7E241C3DF7F171F0F
-:10C8800085888F38FB670BADD65B71FFC23A4022BB
-:10C89000BF7DEA5A99F260ACF912C1D13F5AA5FDA9
-:10C8A0009D3F9BFC856838970F1F55F5101FD68B51
-:10C8B000F05928E0389FD590DDC92E7FF34D11EE59
-:10C8C0001B1184E0BD8FB1C9E087CC2F92C276588E
-:10C8D000FF028505930B30AE29B1E3FAB866C8585C
-:10C8E000C7DFB7323AC7B95AFB44F2E19F5D7E0C0D
-:10C8F000F2E8785FF057B054E8F38ADE4F9CD3CC6F
-:10C90000E158BD440AE5121D8555BF6E5FE77D41C4
-:10C91000D71F7F7F38C9B9E29F0E4926FFD53788D8
-:10C92000ECFD6A61EF5F087A92315E73A1392F19CD
-:10C93000E331170E96BAF472512B8F083FF20FCBEA
-:10C94000AC54B69749F532FA5B2C3285F470998D68
-:10C95000A1DC89EDF792A2C55D6ACC1497879F5C34
-:10C960008878E4BF05D035395587B7B5934F29434B
-:10C97000BBE2017FC775FB24FF5DF8A2DF8A703D33
-:10C98000626B9BE08FB3DE3704FCCAF77D65C63867
-:10C99000C1B4E61C15E132AD4C36E4DDEC57843F02
-:10C9A000359C0DC77995EFBBC93506F17250F6DAA3
-:10C9B00000BED5CDE7CD8138FB6DB1F0C4F1312E8D
-:10C9C0007C42F5CE47789EF8B18D05811F0E8BFD18
-:10C9D0001F78E543F90543F9303EF6B6C2F7150670
-:10C9E000AA3C2E3EBDBC584D87EFE637BA87A18AD8
-:10C9F000E921DA0F543DF43E5BF4D3DAF558C2DB9B
-:10CA00001D33BBABE2AD7FB299AF7F01F37E77B44C
-:10CA1000F4AF87B7E29F3AC325A8DFCB2492235D0A
-:10CA2000E99A117F5C98288550FFA21F4BF5728907
-:10CA3000F4FF612DFF601AD7971ADDC7C25952392A
-:10CA40009CB5EFE7A89C9ECD2A878F06670DBEB1E7
-:10CA5000F3D5DA83BCBA511F5F99DA34ECB7689F1B
-:10CA600054354B6E0CFD55296D66E4C3EAA6475557
-:10CA7000DC2FB8C3C3C7658A7FA87EBF76A0AAD0C3
-:10CA80007CF6178C25FBF1E25A6E1FFBEE39EF4264
-:10CA90003BE8B0C9FBFBB1C88F6FCA944F90088EBA
-:10CAA0001F2CDB32A34CD18F9B43F39CBEA458C5F3
-:10CAB00070D07796EC55BBEBE869A09A4AEFB5E7E2
-:10CAC0003D96780AF0397C8FE611FC8985611E4716
-:10CAD0007E436B4912BCFF4E4D0AA7C38A86BD66D2
-:10CAE000AAE7507BED7BDA7762F969467992A13E3D
-:10CAF000AFB4AD27C2A5DC127EC01B874E5B546D60
-:10CB00009FE4EFD4133EA0DBA1FF3FE889F3137C41
-:10CB100071E0F698DA453F748FA71F962EF7744799
-:10CB2000F82FDD95D71D9963E96BE333E2E9877749
-:10CB300096F1FDC0F7409E61D93E03F4C3F53AFD7E
-:10CB400030C346F411DBEF07EA35EA070D5FFFC398
-:10CB500072E61DD40F71F8BA5E35EA87DB9AE79268
-:10CB60007EB86D86CC3CBA78DC0F55B1CF95503F7E
-:10CB70001467DC4175D59B14876EDE117E09C215E2
-:10CB80004BFC0EEA893D42EEC7EA8B44F27C9A598F
-:10CB900012FBD55791E7FF97E0ACC9F3A5E0BFA022
-:10CBA0001DD8950E19C9EBA577803C97901EB93C0E
-:10CBB0005F7A97884BC6C8573FCAD7117AF9CAFB24
-:10CBC0005705B83EA86ECA797C16BCBFB35EF55A4D
-:10CBD000A1FD9D9DF2B6502F6FF708790B70EEED19
-:10CBE0008E83DF99B39298C728AFFAA29C3A31ECB2
-:10CBF00077F93B91EE0FCBB48FF867A1C70F0DFB10
-:10CC0000DD088C9F77332B443F7F16F2EBDCB2D0EC
-:10CC10008C32E0E3D27BB83D5CB94D263854357296
-:10CC20003BAFAAAF3DE481FA8482AF683F70F12E3A
-:10CC3000BE1F08802A2FD6E171F1E1B6BA6C7CBF25
-:10CC400041A2FDCCF9DEC514C767EB789CD80AFF7A
-:10CC5000F0BC0E1FC5912B05BC16366FA078F3C231
-:10CC600090310E5DD9F7E653E80F68F277F19698A8
-:10CC7000F7DE8769BFA212E3CD3A3F4416F6C3BD83
-:10CC800072387F27E676FE9EFB55B1F8D7DA75AC91
-:10CC9000BFE2BFB9FE23B0FE11FFFCF55FEBBA5552
-:10CCA000B3E0F7023602F9E3CF261FF17BF07558A7
-:10CCB0003F7CE79E47FB75D7E719A509BE3C6C0A88
-:10CCC000D46561BB2A89DA2D58BFFD4006D467358B
-:10CCD000B06118A65FB0CEA8173BF470A387F4EC40
-:10CCE000AC9AEDD2DDF9086F56837436AFC012C02E
-:10CCF000FDD423B608C92F8DEEC699393D8F15DFB7
-:10CD00003DD12352467E4493E426BE08DBB85F0142
-:10CD1000F0B7417DFF982F270878533CA6BA89E3E6
-:10CD2000A71AF0817C35A159D4B7703BEC3BA06FBA
-:10CD3000683FAC79AF8AFD2AA07D1AC99B41867DE8
-:10CD40002EDC9F2BCED0E16DD7314EB79B252F8B9C
-:10CD500083B701F04F5CBCFD93E85583C738B3B08F
-:10CD6000E705FE8ED85ACB87D33E94E4DD888D9BB1
-:10CD700053681FE593FA3CC2E32441BFB1748DF6BA
-:10CD8000BD47174FBA05270EF2954DB4519E1B7D36
-:10CD90003797DB3F7A7912EB3757B356B263264B9E
-:10CDA000818F145D5EDB6D22FF44DBA7D5B57B5C14
-:10CDB000BD423B96E936A19CBC5FCBB7C4FCE10CFD
-:10CDC000CA5BA2DFFE5E85EFCD82F55E5C237B71E0
-:10CDD000FFE77693E7DD22E4DF4754867479F1902C
-:10CDE000EAE3766712C9DDB9874FA8180A990B30B4
-:10CDF000417CCFFD0197AF27703078F647D05B3E7E
-:10CE0000DCAB670D23317F788677EF780FE0E5D6CE
-:10CE1000114756E33EDCF452F7BBEF227C1F961914
-:10CE2000C2F7F89A52F24FEEBF4F22BA3E0A70C4D0
-:10CE3000FEB7CEC879F75DF8EE5D6BD2695F6D968F
-:10CE4000EFC078A4B379539D0EDC5F9B344066013C
-:10CE50001D1CEF62ADAB515ECFAAB9EF569C6F05BA
-:10CE6000E8018CB356341F19DF1DEBEB25AF07C665
-:10CE7000AF0E06CCDD0185ADEBCE9B31DE311FDA86
-:10CE8000217AAAD7F376D59B24AF0DE9B1F9519257
-:10CE90003BF33749CC8DEDC1DEB3F271435618B781
-:10CEA000753DF487FA02EC8FE36E4AB90DF7D1AA0B
-:10CEB0000FC9BCFFE8E5AFA25C9A0FFDE0356BDD62
-:10CEC000741F8DB770BDC43261BC8AD1393F198DD2
-:10CED000E31D52BDF8FEBDBDBF32E3BC67C3F7B270
-:10CEE00060FC7972DB786CCFBE27B93753BC89E719
-:10CEF000C9B60B3E606F6771FE92445DD8819A3E61
-:10CF0000FC833997E8697EEDF23A5C575B303D0768
-:10CF10005DA0EAA6F366B4EB3E013807C06E3B2184
-:10CF2000F2D8F6074F98DB74722A62CEA3FEF7346C
-:10CF300015137FDFCBFCB4DF1D58CEF5F0B1D5B6AD
-:10CF40009084F687EA263DB97FF575BFC4F59F7BCF
-:10CF500056A5FDD173BDDA281E7B72BDCA8230C7CB
-:10CF600095EB65921B27B7F13890FC844AF5050FC5
-:10CF70009AA9BE7FFDF409280F4F02FC910E4B9F2A
-:10CF8000186FC6FA0290EB9638F263BE67119717D6
-:10CF900031F261C13A23FF7791170F4CE0F23D4621
-:10CFA0001E54F6ACA3385FAC9CA8660E4D3E1460D0
-:10CFB000BD359C45F45B75486568CF5529EED9EBC6
-:10CFC000906E66D970A718F8227C00E5DAC590E467
-:10CFD00009C2FBEFCC796924C2EF2F086FE48BB54F
-:10CFE00069B49F3A3F3497E0AAE5132E5867A467C7
-:10CFF0002D7FE98E80CC7C7A3D5091C47CBA76EF4F
-:10D00000FD00E812BE37A7490AD924AC1F7BF5C141
-:10D01000115477231D56D50A7DBAD64974FBDEBF5D
-:10D020009D5F8D7439FBFB12CD9F050375A857AA30
-:10D03000D6491E8C632EF83EEFBF00FA23BDBCF725
-:10D040002B4E3F40C71EA4F3AAF58FBE4AED3749C9
-:10D050001E1CFFBD0D7349FF56046546EF371D23A7
-:10D06000FB18F400E501ED0FCA1948E755AB2C6E2B
-:10D07000C4A3462F1AFD1D53C53901AB77E874E8E8
-:10D08000B7C1ECA175C7D29D3C3387E8AB7A9B4A08
-:10D09000F4511DE4F474EC5999E870FFEADB897EE1
-:10D0A000CE6D9612D05FA9390BE92FC4DF77D0DFA0
-:10D0B0003392A03F4ED7271FE0F4588AEF91FE9E8F
-:10D0C00017F629630EBDDDA1D19F464F57A3BB2E96
-:10D0D0007A2901BD816D7C1BCEEBFED5369A77692E
-:10D0E000DD4BB7D512DFA8B43F5F5AF76F19C8A759
-:10D0F000F3159E87A1C1B152E1793A5DE6F1F3E5FE
-:10D10000E6AC6B994FCC3CF676EAC502D48B9857C7
-:10D110001286EFFC6EDBD394BF7676EB31CA4B5CA4
-:10D12000FC0AE01DDA9FDBE66461B2A743245F16C8
-:10D1300035CA9417CA9470E174DDF9112DDF62F1DC
-:10D14000734E82EFA21D965039F45FF4C289A1B4E8
-:10D150001FBE22F22AF24F70ABC4E3F2C1B6A1D3D4
-:10D1600031AF52E1791FB17A778C85C76BCEBC9411
-:10D170003413ED1F69CB5EDA4F5AD470BB6AD1C548
-:10D1800027BD1695BE0BED689F260878C77D449C89
-:10D19000DF2D43F4F35BCEC77B86F3CDA22695EC5F
-:10D1A000A2455B36505CAF7ACB79CA7B2D7DEE59B8
-:10D1B00017C2A1BA4936E6436D91C316CAD7928FFA
-:10D1C00059B87C32E4255535F27319550D22EF27F5
-:10D1D000262F66F173BB5E08026816EFFC2F17F26C
-:10D1E000D1E9D6CD2E84278C47F944534727C83739
-:10D1F000BA5A9E51C3C371F38C4EE37F0081CCB603
-:10D2000018F333D9162EA700EB85FE38F14CCD5E0E
-:10D2100059FCECE74F62DEEB991D9F3D89F35EF20E
-:10D22000BF2E3E89791B6CB7CD8DF643F5D6772896
-:10D230007F50EB576B11FECF33FF457997E7DEB791
-:10D2400090FD776ED7C9DE681F9CDBFE5506E6535E
-:10D250003EB06B3CC51F1E78BEB43B8BE3DF6A2536
-:10D26000D265E81AF23E63F1B0BF510E3B609E6793
-:10D270008F5A88BF3BF2C51A2A79FE9D47E4896D13
-:10D280008B9F57ABE53755354E9F3A0EE55B23D75D
-:10D29000E31DF94E57CB0F7B1BF079FD35E06D9BFD
-:10D2A000C8FF8BC1DB59FC0FC0CF2F2CC6FCB0CF01
-:10D2B0001BEF7DEAD7F8AE31FE79328D8FAF062FA6
-:10D2C0002D6F779EC517B220DFECF80DE5E121BE8A
-:10D2D000CA3DA8E73FEF8D71CB4FD508C50323BBEF
-:10D2E0002C6ECCDB5AB4EB3DE28F73CF1FA1BC5840
-:10D2F00026F267CFB18E1FCF77143189EA4D4E9E4B
-:10D300005726E08E79671E173D17F9659C6EB5BCF0
-:10D31000B344F966EF5872C5B90B9E1757E96935E2
-:10D3200023FCF57968D268C4D33143FE9EB6EED8AB
-:10D33000F1DC088751FABCC944F97CC21EEFC01366
-:10D3400097C3E736883CCA8EFC48C67A1660BE0F83
-:10D35000D777D521E93D16871FB5BCC9D6587E0CB5
-:10D360005D5BBEE4D5E7FB8FC163BF85C79F34B863
-:10D370009CB91C5F1E7F26F81BFC92D316DDB99466
-:10D3800039C22FD1F2C8B4F9D63570BD7B660BB760
-:10D390000B63F9B94AC4DB63BFF395F84E55D3DE8E
-:10D3A000A12877CEEC7B49D01BA7E7AA6DC7CC415B
-:10D3B000219F437AF98CE3C59127B2958F077E6C44
-:10D3C000DCF1AAB79D8F3BDE69C5773BCEFF742B9E
-:10D3D000B7334E37C8134371C63F2BF44FC7BA9DBE
-:10D3E00066F2AB64979DE4CF03CED14793BB6169EE
-:10D3F000A6FC8595CB45BEC30FBC9908E795CE9B8F
-:10D4000019CE6735C247E767AAEE00433B47CDF424
-:10D410008F40FF499BAFF6DEDCCDC4427AFC2BC1C6
-:10D420009E18779D92FBA582FAA57599F15C47AB92
-:10D43000E23E9006E3B596495EB467BBD29971FCB3
-:10D440005B7CB2211E86B1675CD705AF89F0E934F9
-:10D4500085DDD084396DAD99E4C8799847C9A09429
-:10D460006EDADF7E64D9965E78CECAC5BC12BE770E
-:10D470007A3BCEB7D078C92C36CF9ABDDDB790892C
-:10D4800023C0F8DEBD17E312F6016C009EDF713396
-:10D49000BB17EF57784C9C7B5CEB0C90BE4DC837AC
-:10D4A0005E7EEE458B13258F560CE762527CC67A62
-:10D4B0005ACC39484D5ED3113A80FF0471EF43CA0C
-:10D4C00078BE7E8C57F5CBE89C6F4A3AF386F1FD27
-:10D4D0006407E5333B1C7C7EDA7C613E240F004C04
-:10D4E0007C3EF96D41B4C3615E317CCCE8DC13CC89
-:10D4F000EF78CCFC0C76DC1D56A11F14A6A01C7185
-:10D50000585B9980F305639E699061DE4172075C08
-:10D51000E13D8C93234DB560DE821BBDE03CFA5E9D
-:10D520004CBF9E6EFD79B1EB85DE28CA64F974AEFE
-:10D53000B0B91BC9ADDCDA127602EA523DA78FBE44
-:10D540006B19D17DDF88C8635965277B4CBB774059
-:10D550005258502DE8A43780C80A3C17AAAC019A4B
-:10D56000817ECD9112D3BD00D4067C05E3DF6BF53F
-:10D570003D68857675B704324DC37039C5AB5A8A9C
-:10D58000E814EF408C309996FB5A0EF62251C3D81E
-:10D590000DF8DED782B45AAFD54120E27D0BF5F607
-:10D5A0008EBACF0A72B23E97D757AEF1AD5A03E3A7
-:10D5B000C94EFF4A2BF2B1D53D88F62FC2D776EE81
-:10D5C0005D9BE7804DE1523B4CE2E6080014F0DF42
-:10D5D0000F7990ECE4563312C96687560F931DED10
-:10D5E0006F3C427E7965C3117A6FC23A947DD2C294
-:10D5F000A5D9B0CE8DD65BCA3207C2788D73334DB4
-:10D6000020A27F63BDA54549D7C3E156031C9415ED
-:10D61000D35B0E8ED3C3617A0BEAEB6B85C36FD6F7
-:10D620004C5FB5A6E7B5AF3BCBE6DF8A7899546C83
-:10D63000223935EAA883FC35F8D9283E25C6D99089
-:10D64000E0DCA3668F6BED343A4A442779CC3D8801
-:10D65000EB1723BDD4637E37C6EF02016FD9F04EBE
-:10D660003A65EEC0703C9F9E65BB3B6CD5C5F52608
-:10D67000152F9573613E943303CFD36B83B6FE4071
-:10D68000A7E93E13E52367D90207705DAE99913093
-:10D69000E6EA8C6281FBA5BC4E7AD7BE53B78BFB02
-:10D6A000A975734DA115240FDA245C7727DEDB62A0
-:10D6B000F01EE1786F3A4678AF6A3EC6F1DEB4BC40
-:10D6C000C42EF637D00FAC67916188CF0FD6549631
-:10D6D0002940D77D922275480F2A5B5C566E23B88D
-:10D6E000BF8FEBE90277313F0DFE89F0567F30F7AF
-:10D6F00047F9E8271D32D17E8606AF8E76369E77B3
-:10D70000B7C71EF80B7EA77A74DBAB28DE771C7CCC
-:10D710008BF6D55D87A6EDC5FEAE1980094FE7777C
-:10D72000EB0FAD2841FAAF8F50580DE44C248876AA
-:10D7300047627870BEE88047E331828F09EBF07C66
-:10D74000AB389752D424F950EFF64902BB04CAAF64
-:10D75000ACDC2F74DA645A8FD3C6F57BFAA17D3224
-:10D76000FA1945AB4CD43E1DCB7CFDFA57897E8A15
-:10D7700021CF4CC3A74647403849B7C09CC72407B0
-:10D78000CCB6917ABA494DCA85F7A35AEEBE1FF5B9
-:10D790009BD6EF27CB98F71EDDF972A09F13067A70
-:10D7A0001BA2DA106E5A7BA44B7F9C7B17A05F37BD
-:10D7B0005B3AFF0EC655B7B72C95E99CE235E2B54A
-:10D7C000D0C26A70FE8549AC6607F42F4C8612EB16
-:10D7D00069A2DE5DD4B345D9473C1FCCEB791F7AF3
-:10D7E0004D9203E3343C6E38D426F67315F720E4EB
-:10D7F000A3A1361E1F2FCAB493FCD7F8550170E2BF
-:10D800007EA322F61D7323B926C4A3C6BF4AC4143F
-:10D8100076821ECC553C26DC7F7E7D19C041492C8A
-:10D820005F6E1EC8CF8FC53E1F6B3319CE83FB3A88
-:10D83000CF778E453C555ADB7E320DDE560DBC4807
-:10D84000FB3F2B92AAC65EE91C78EC3C5EBFFCBB9A
-:10D8500024A4AFE6A825EE799107C4FA0F2E9B49C0
-:10D86000FD1ED6CE8308BBE55B249AA0ECCBE34734
-:10D870008596A0928AFA2F89C73B0A93B87E64DD09
-:10D8800073E89E8C42EC8BC2FABA4194B752981658
-:10D890002AA7FAE03CC6F33E75F98516D6615F11FA
-:10D8A000CA73119F819578AE86C93934FE8DCC68D4
-:10D8B0004F1566D7ECA7F7961CDA8762516EDF68C2
-:10D8C000F6D078B1BF52D8A7BE8CE699CCC72966EE
-:10D8D000C6F3C385D70515BCE782E5E5D0BC4AADE4
-:10D8E00031EF07F3FB45B4758CEF6247D57BF19EB2
-:10D8F000914903E67ACBC4F38BF06F1F0B9B734BFC
-:10D900007EA77CBFC97387B7CC607FD47B910FDFC4
-:10D91000F85A9E136F1FFCB0E0FB83CBFC5EDC6FFC
-:10D920007CCE06F800BFBBC423AD727AAE0EBF58E2
-:10D93000BCC5C2EF5BCDF3C97E8B855BF187DEB2E0
-:10D94000544F5738C5C2653CAB1F40F7D70838C79E
-:10D95000C2E5752BA787D7F32D21F42F5E5700CE94
-:10D9600080AFD73D12F91B85E27E0D20724E2F1A33
-:10D97000FD24E5707A4936C23D16BEB1F0D4E4C04C
-:10D98000AB082FCA2FF1958FCFE85C7F61F79A968D
-:10D99000141DBD68EB2FCC1674BAA73F9F8726379E
-:10D9A000AE137244C80FCD5E1E2FC6037B99ECE107
-:10D9B000D27427C5654B2BF938A5FD1C1B31BF81DF
-:10D9C000856FA47CD942267E516EDF823DCAE9B3C1
-:10D9D00079C229F4AFFB5802AB9C18879052685F5C
-:10D9E00009E07E3C06EEC78D7037DAC9B170780E5B
-:10D9F000FF634C577869F4D6621376750FD613ED32
-:10DA0000DEA12F8D4846F9CD9A53E3FAE9A38EFAA9
-:10DA10003BC611744B7429B140C77337D041D380D2
-:10DA2000D58FA13933D65A2F23FD8D65BE34BCCF97
-:10DA3000049364719EDABC864BFE77509E8D699B81
-:10DA400098A6BFDF44FBBE06E77102CEE358702FF5
-:10DA5000C651C631E5AFFA788336DE9F6C22DE9080
-:10DA6000CDB2713D45B83990DE399EB6BE3E792CB7
-:10DA70004CF7DF48563AA707FF0B9A533BBFA7E581
-:10DA80003F4F724EFBD44672B886F13C9F3021B1B5
-:10DA900048BC2F12F78CB18892E85E29F64D52E708
-:10DAA000FCBEB0490ADD9321E677768B3588F946CE
-:10DAB0000F49814BF89D33D2A1A1C4AF4AB83FDDD5
-:10DAC0003311F3FE62534B15BE8776F3A99D58D7E9
-:10DAD0006299C77923BB2C749F4F42FBD30AAA4B90
-:10DAE00027078AEC5C8E8CC7785F1EC90B05CBDDDF
-:10DAF000E779DE7871538182DF397081E759973099
-:10DB00009F827ED78D51A3BF76553A75C7C66FC425
-:10DB1000BD444AA437C255B3CBF2ED81EE76C0D7EF
-:10DB20002A21DF9ACF4FF020BE360E1879F37468A1
-:10DB3000923B70F834342B4CD65615F5DD5D82AE31
-:10DB400046235D4964F56874E5B1A31DBD2686AE24
-:10DB5000DCA9063F6E160BD381C7A21AF592C11F2E
-:10DB6000147648AC7DDE6997D7C7F5E7580B38A81F
-:10DB7000403FB3057C57A5988328B794FB78BECF68
-:10DB80005D8CF5C63CA0BB6A5483FF393B4521FC44
-:10DB9000CD5E6EA33C4FBC376A2ED403F09CCE35CD
-:10DBA0000CE0F74875E0B356D71FE9C09141743BCC
-:10DBB0005BEC87FF49E27EF8EC944FD2C9690FAA6B
-:10DBC00017F4F419FBFD84E3C6F45B25F178CE2A43
-:10DBD000D597E9D5D91B13EDDC7EBAE02E5B67BA89
-:10DBE000C2FD06016B8F7C45771F505B8A7566BC52
-:10DBF0007B24B4F1347BAF28C0FDF044E3F68D9470
-:10DC0000911D66FA795846FBBA6F84913D5C14F118
-:10DC100099E619EC72EE8F76B1CBF13E03A82F692D
-:10DC2000DCCBEDF286E564DF2F01FB1EE5F906DCB7
-:10DC3000F3ECC1F884F2C95EEFF02B31BFA5A84127
-:10DC4000EAF03B15C07B5E3D6FBFEA9171EAC30A03
-:10DC5000FA85814CD58BE18192D556F073EA7298A2
-:10DC60008D819FB3C25E327E2DFAA5A93E89A55053
-:10DC70007DB523EBDAFDD855F6E2D5E8C726F227C5
-:10DC8000ABED1E825F227F5276FA57D975710090F4
-:10DC90008B71ED8F49CE9235D84E93170F9BC27979
-:10DCA0003FED46F941945F7173EDDD64EF4FAEAD2A
-:10DCB000F0E2956EEDFB2EF7C7FC8A2281EF5FD86C
-:10DCC000B93D599DC4ED48490AFC02F9B375C0D36A
-:10DCD0006B0B803F6635F1BC0DDB75977BD37D40C8
-:10DCE000239FFE79018CFF5144A1F842B393C79B57
-:10DCF0003F6212D9AB45472CFE46C0C365905076B3
-:10DD00009DDF729995519DF5CC309C0FFE88EDCD2D
-:10DD1000FB297C2758C3F3942ED4E42423DE9B559F
-:10DD200063FC77AB9DE7B76D15F4370BEF8D1C8E59
-:10DD3000EDC2D9787FCB2C25AC527E46D4CCEF39BE
-:10DD40008479E07C9A6DC67176DAB9DFB5D3CEED11
-:10DD5000F859E2DEC9665BEC380A1F5FDC33170B4B
-:10DD6000F7347BE98BB89ECBCCD744780279857A9F
-:10DD7000A16844CB51B417AEAE7F7C12EA9FEACBC8
-:10DD800052B80FC6A71B55F2DFCF8873E2671BF7A7
-:10DD900067DC0D65E5F63FB8D0DF7B4DE0E9ACD23E
-:10DDA0004AF7BC2C795EA67B0AE0BB19DFA1FEF323
-:10DDB0000AF9392B7E4E48D3CB055FEFCFF6F3E05F
-:10DDC000209DFBD1ECCE71D66008E7D7BC5C26B9AC
-:10DDD000017ADB70EFCF8DE2DE9F587BF463BB16D8
-:10DDE00067CEA0BC9F07DCFC3B89F8BF289ACA42DB
-:10DDF0003AF950A484659C7F5134838500BE670F37
-:10DE0000E63E568EF4CA546F3F1C56612D640F8B4C
-:10DE1000FD1BF8B5E0FD74BB45654FE3C5E96389BB
-:10DE2000F9DCAB06439B6F8503DDC83EC610686115
-:10DE3000A7DD7763D418578DB5934B9A87AD42937E
-:10DE4000F20C3E40FA8BF07B91BAD8CF910971ED7C
-:10DE500066C61E2538143C9F3709EF7B2978CDE430
-:10DE6000C6EFEE41BEC6787EE345BA8FA48A856FC1
-:10DE7000C3F7558DB23BCCAE14CF5AF5C68D308F5B
-:10DE80003D11C583FCBF27D2621D4A7513C5318A77
-:10DE90000E170D46BE6D8E2814FF2F3ADF92342FD9
-:10DEA000BFD37E69BE6CA2E77B2EEFA3E7DAB8CDC5
-:10DEB00091D4C1A88FB79BB83FDDF2EAA52494A7FF
-:10DEC0007B2E5F48E3F70F2DD7EE058AB59B092E11
-:10DED000A54EB923CEACB7D3995CF436E62B8D4F63
-:10DEE00056994C78E0FE6617FBE343B6CAC9BADA26
-:10DEF000212568D7C871EC914E781BECE7FE49C22A
-:10DF00007EECC50AF03EB7A6CB698BE95C677392DD
-:10DF10007B05C59DB8FDD0DE72FA6793F0F92199B3
-:10DF20009FEBBF2C133FEDDBBDB84F9B430FEF3A88
-:10DF3000C2DF1759E7CFBD02EDBF3860A77839536C
-:10DF4000BC83E3C5453AE3C4E11E7C7F2BD883DF65
-:10DF50003FC3E300DFEA8C0314258DE4F737A15AB1
-:10DF6000EABFFE9819E3287BECFE6F2511DF34240D
-:10DF7000A19CA8B073B9146425D96024B1E70F9AA5
-:10DF80004A904E462CF710BEB7AA604A215F6CE655
-:10DF90007EFB563C070AE32C6CA837E7E8F0BB5041
-:10DFA000EC377DAA067BA7EA9EFF3E89FBA59F1E54
-:10DFB00058F414E523BC6F61FDE2D89FA1242E071D
-:10DFC000779A8393B661BBE3263AE7D1F2EACBAF07
-:10DFD000F600FC2E3CEA1986F27F599287E0D57450
-:10DFE000686B5D0F68D7F4216A4930B937CD954D1C
-:10DFF000F0DD579887C7F3DE36D17C3BE29F6007A0
-:10E00000E27A7F20E6F3CA419361FFEA153BD76BC2
-:10E0100095492ABD9F97C4E3693B0E96A461FEE92A
-:10E020001E7B603EC2B3FA93B63A97A733FEA7D9D8
-:10E030008163DEDE316908FCE798332637A2CFF32F
-:10E04000F64619D7EBF994B114A96B7C0AC6AB411B
-:10E050003C68E3BD72868F07F3D887FC1659CEDC87
-:10E060009497C9FC3FCA87FA2BAD4A2AE62D6D1555
-:10E07000FBAA1A1EB4F568F3F03430DF0607B18648
-:10E080006FC795E2CC223F72B8909B5FDB7DC124C5
-:10E090001E07247BFBD30376B2BB768A7835CB9CF4
-:10E0A000DB07E1A7E169BD2863E793E8FB8F2771F0
-:10E0B000BDA1955B554F90E8E179AE6FB73AC3D6F5
-:10E0C0003C947F2FE551DD130C260DC53CA8A67EA0
-:10E0D0005EDCEFC3FCCF24DD3EEB3841E79E868853
-:10E0E00039478787C4728DC3BD837E9406A2ABA6D1
-:10E0F000A38CF86DD196FB787C11E481B8CF89F6BA
-:10E100008F912FC43E7296C44B17F2C998E60D2B1F
-:10E11000B33D74BE80F66D353878902FA0DC2DF0BD
-:10E120008270C1F72F89756BEF5F14F01B2FE72703
-:10E13000EBF31163CB3DCB3229A6A8D55F12F35F79
-:10E14000C81E253B74E1E57AB24F3D35BC5CF80052
-:10E150002FFBAF9F6BC6F8EFC275F1EFAD1B95C4F7
-:10E16000ED97B3820F98C9DE03F3393AF46312D7FF
-:10E17000AFA71A1FDB9F4DFA24F02AD2C70D4D8F8F
-:10E18000FE12C1A4D1FFA94D2AF5D7E488D6FF0D10
-:10E1900031FEF36F73FE19B3492DC17B8CC6049910
-:10E1A0001BE3E4AF6CDA2CA35C7F05F92387CB0D6E
-:10E1B000D4C79F1E7824E921A483632686F1F89DA5
-:10E1C0006656B15D87DF960D2F1AE4C1A22DCB27CD
-:10E1D000E138A3DA522594FF9A1CD0F0BDD3ECBDF0
-:10E1E00089E4C994187952C6FB47053C1F13F2E431
-:10E1F000B189204FE051CAA61409C7D9698E7FAFF3
-:10E20000D5671ADF097A1CDB29773FE372B7CD9512
-:10E2100007E3544DBE40F1D78EEF08BA7BAC4CA358
-:10E22000BB1C09E108F6BCA92FAE1BE083F40FF676
-:10E23000FC9C69F9C4A50715DAF711FB48226F8227
-:10E24000384CC7BF9A9CFBDA1EF81BF2496159CDC6
-:10E250004AF433D2CA8344D7A7A4409F54D057A7C7
-:10E2600090AFE3C885E3623D5FA8813EEE38EF3BA7
-:10E27000F988F5403EA8600113AE83AD97DCFAF350
-:10E280000F9EF59CDE521C92217F5CAB6BF0BA9125
-:10E2900075DC3398E248273D65C6BCCAFE21AEA7AF
-:10E2A000985442F4C84C37F7407E3BA532A29F53A6
-:10E2B0002017116E0BED463F445B574F07E7AB2F1E
-:10E2C00052F83AFE28F88E7CDC91D48EDB59C526B4
-:10E2D000DA8745FA207A9B924A7E0A38460AF17913
-:10E2E000C73E435896B83C90711E6EF4DF280EB4BA
-:10E2F00081E7856DDB40749332D14DE7191E53BC25
-:10E30000B6145D1CB765F3E3E437223DE11C12D17E
-:10E310006305D2238B438721A043E8973AB186F067
-:10E3200008F81DE5807153CA0232D24D2C7EB5FD2E
-:10E33000430D1E3B63F61BBFE7E07C3951949E04FE
-:10E3400079279D7AC2286F015FDFE6F8EAA46FC4DF
-:10E350009BC66FC31D57A6F39083DF075EF7D13CC2
-:10E36000CAF7D0F699B47D63EDFB77087A49B44FCC
-:10E3700094650BCC7418F6A396D27E97C627DADF85
-:10E38000A558BA99E7BD6DC73708F7167B487F5E79
-:10E39000CFAD301FE2B3C29143DFD3F0EBA935B369
-:10E3A000BEE02F7C9133B7055F7DBB35583E04D668
-:10E3B000B1DD1C9C3199EC6EEF4D38FE4DE526F732
-:10E3C0002312E60BB8258C771089235F1CE2DF61EE
-:10E3D0001EAF61DE4B05DC353C697048A4AF12E12D
-:10E3E0002724E0932EDEC7F275B983F373BEE35A98
-:10E3F000F93A2823DDBB586005DE3FCD8AB81CEA18
-:10E40000E0EB2246FB886BC578DA73AD1E87AFD789
-:10E410003A46EAF87A749B91AFC1C215FA94F82B88
-:10E420007D93CAF368059F7D61E3F3FD9583DB630C
-:10E43000E9A83F007FE941BE9FBA54D0195010E5CA
-:10E44000E5D56FB230C483C6F7AE19AC44C57D596B
-:10E45000D437D86A46E0E838DC8FCD347B707FF85B
-:10E46000941A213C9D0207B59EF0E9A73C935307FF
-:10E470006EE0F2607287FEF1E17E4FF08F3DF97E33
-:10E480008EDC4C74BD743C23FDD1B27914D141456E
-:10E4900079AE8474B6684B8A84EF53CBDC26592757
-:10E4A0001747D59A58DFE144B7CF3974727154B029
-:10E4B0004646B8F4490B64AA29603738E64CD0C701
-:10E4C0007F5E81BA3EFE03F5BABF27FEB37BED5DEA
-:10E4D0007518FF694FF235233EB26CFEDDF8FDC2C0
-:10E4E000EC1A99E9E4C5D5ECA66A113FFA70F5EB90
-:10E4F0009BE7C2BA673D1C598D6FE7607C7500E6EB
-:10E5000005F0F86A75F3118ABB360B7E1E2EF90FE3
-:10E51000E377EFAAB9C918678D5CDB77BB09BE65E5
-:10E520001F32827F377F8D8CF1084D2E7C807F8F4C
-:10E5300081FB8D12EEAB69FC807205ED4F2DBF01A2
-:10E54000E35ECED44EB98CF5649D5E5D5B6E8A7BD6
-:10E550005FED6987C3A0B73439C89AFFF6C243DAC2
-:10E56000BD995C2E9E76E8F4FE63E5C7E93C311365
-:10E57000F7D0DD2F7CC8A756787F7F5DB7CE73ECD0
-:10E58000C32CE620E64F82DBEB71EBF261A5662936
-:10E59000ECC43CCB4BE8B900FE2E99A87CEADFFD29
-:10E5A0001373D08F6F3279C112C03C09A2636F1F01
-:10E5B00046E71E1AC43E6CF17E874F1D81F7E65B6D
-:10E5C00049FEB5EFB50791AFDB9D268A1FB7ECB2C8
-:10E5D000105C2FF6B50BBF3A64F0BFB5FD0D9BA5DF
-:10E5E000EDAD22E8BFD1C6C7DDF8707FBA4F23D1A9
-:10E5F0007E77516D2EC5F3B4F8626EC463E2496153
-:10E600007C7C25C2685DDAFEF73ACCBF189138FFF2
-:10E61000A297D3ACF94B194EA4C3996DAFE2DC625B
-:10E62000FDAF8C43C7F7E23819B53C2CB0EED052A1
-:10E6300009D7B76E567CFF4BA39F7522CEA5CB732F
-:10E64000C873EAF5CADCD4A45C9DDCD4FAFD52E4BC
-:10E65000398C6AB97B27DA77C0D7694E1D5F4F1AAC
-:10E66000B2DA166FBFDD5FFB10C53F13D1BDDFC44B
-:10E67000EF5B8A7D3EDE29EC1825D283ECC03D5F3E
-:10E68000D83D71F21FFCBB4CF47741B4784CD7EF06
-:10E69000FF3BCDFF4667C7BE5E8F6BD9D78B9D779B
-:10E6A000ABCA7AC5D327B17993DAF7E2F4BF4B7FCF
-:10E6B000EF81DFCC02DB1D5DFB69F6AE5FE2F74E5A
-:10E6C000B18F18E9558D4E00EE7720BE861E9E371D
-:10E6D0001C43A9CC5A23A31CB8D8D4928D71AA4448
-:10E6E0007EA1361FF8F58B1767F1E3BD4A71D67727
-:10E6F000BFC0835FE5F6A7547CE03B382FFF79B3BA
-:10E70000A43F8731C72919F8498B83369F7F773813
-:10E71000C947359C1D0F7EB1FB96733068C5F51C4B
-:10E720008783804B5D312BB174A33801DBE841FF57
-:10E730008FCB494F2D23FEBE5EF2D1BA5738B95D5B
-:10E74000B38EB5525EE3C5433C0F79E87D1EFAFBFC
-:10E750005CA00F8248B7A35860A74997D7A5D143BB
-:10E76000DDB3609F18E2559C7F34BFB59788FBF4FA
-:10E77000C47B4274EDBACF0452D5C9FBAC80952955
-:10E78000BAF85A7685DB50EF559369689F190C4BA0
-:10E79000C85799B51EC3F34E39C5D7DB2BC836A071
-:10E7A000DE5FC7DA687DBDC57CAE9702441F170FD8
-:10E7B0009D48C5386448E003D6FB24ADB736705198
-:10E7C0004F1FDA7AAFB6AE0F97C17C80EFFF847E21
-:10E7D0003994773D704CEA4E707753DAEF1CD1AF25
-:10E7E000D7F78F90FFD8ABA695ECF7D9B57B25D49A
-:10E7F0005B2037A8DFBA65562A7FBDCC4D3254C3A3
-:10E800006F4F68877947DA7DF089F4D22EE735EBD0
-:10E81000A55DCE387AC9648DBC86FBDB95CDB20789
-:10E82000E960E5F753297FE2A9067E2E717F33CF99
-:10E83000E77BAA8EE76D6BDF3DF77C32EDEF9C1333
-:10E84000FB7CCC7729631AED7B5FCAC0F3451F3B85
-:10E85000026FE8E5E053CD9FDB505F0CD6F26463B6
-:10E86000F40B0A5E3CAF42671F25B47B86AD917105
-:10E870001DB70586634A1BF0F73B9C3EB91EFACDD7
-:10E88000B61293FE9E8E8B4D7F9DBDCFD3B96FA4E4
-:10E89000ED2B69EFB57D27490A7CAC97EBB1FB4ABC
-:10E8A000B1FB21B2CB4A79D65ED9EE958D7A95E847
-:10E8B0006E653FAE3757EEB513DC56F673D0FE2DBE
-:10E8C000CCF70CCEB705F4169EC3BB78D441EDB49B
-:10E8D000F9C37C871ED2CDB7DA1499BD4F8A3BDFCE
-:10E8E000CFF570EC3A5F633EB2363FD9A9D0BCDBBE
-:10E8F00099DD8B786B30F3FBDB826FDA291EDAEE61
-:10E90000BB64C37B83DBD9251BC6694F3B02920BDB
-:10E91000BE23F78AB8D00FD9DF7C7120D27FA27DC9
-:10E92000BE41CE1215DBC33AAD588E72072E6E6310
-:10E930009CCF0257E837C959E2708DFCBBD69FEED9
-:10E94000BA22BE8CEBAFC6BF83A2B3A324216F63F0
-:10E95000E94D6ADEFB15C6F581BF285F34D89B857B
-:10E9600056029CEA8608BA9BC1C4DF4132D2C3C7B3
-:10E970000E7F3F5CAFC6975780CF409CF75B0EFF82
-:10E98000606C8FF3C0F33C207786B8B89EDA894775
-:10E990009635FBA94F1E97639114467926B1FBB3B8
-:10E9A000939CD34660BFDC011E13DEE3FE77D0FBF1
-:10E9B000B82BC32F4C792ADA79E24ADC27C4737C5E
-:10E9C0008DEA19E3DF4B32C2E1B4C3FF6D1C375847
-:10E9D000D249572B3D5784C72484C35B8EC0142C67
-:10E9E0009D2AD00B0265F45CFAFB555936DF2ADC10
-:10E9F000BFDCBA9CC3A1FD590E87ED2D26A2E30D05
-:10EA00006C10F1DF20D385D9383EC8979938CE886D
-:10EA1000D67A13E6F3F50B794C748F536B83C97474
-:10EA200065BA9D25E8768EC0C3FD8887C1DB785C1A
-:10EA3000E50A743B4FD0EDB5C27D89EB8A7CDB855E
-:10EA4000AE6AF47475ADF9439238071B3B1E636DD3
-:10EA500014BFDFFB9285E477D50E7EEEB76AF749E7
-:10EA60003A2F5AF5B28588B2EC651B3FBFD2C8DF9A
-:10EA70009F2B8EBFBFFC6F2EEE5F5536DCE7D5EBCC
-:10EA80006BCD0EF8A9EF82BBAFDCB94F9736999FDB
-:10EA9000075969D3F241F97E9D4BD0595A2FBF0FC8
-:10EAA000F54EDA781E177239E6D37E5DD7731F9C58
-:10EAB0006FD3453FB7DB43F640EC399074BC179CED
-:10EAC000EFBB12BDC826BB17F72DD326C6B4734CB7
-:10EAD000A4FCB9F498FDBC904BD8C166964972D499
-:10EAE00016FFBC9792ACD97376935E9EA09CA7FB51
-:10EAF0007A9C565AF7D27496568EF101A742E73D9A
-:10EB000063C7D1CA149FC9709E286DA2DD705F468D
-:10EB1000BA3FD550EF3EB387A17D5620D7F03EBB1C
-:10EB20006290E17DAF9A0243BD4FED0D86F639400C
-:10EB300070FA7ADE9A9B0DEDFBD54F33D4AF5B773D
-:10EB4000A7A1FDC0D0DD86F783B72C32BC1FD2B0A1
-:10EB5000D450BFBEE921437B39817DADC159D6EC8C
-:10EB60006BE788009D1F735A25BD1D72D8C5EDF057
-:10EB7000629795E0BF5AE8E3D5E2BCD96AA18F5B02
-:10EB8000D20BAFB8BFF28FFA63675DC6B8578988FA
-:10EB90007B9DDB673621DD57ED07BAA0BFCB15386B
-:10EBA000EBE2F6D794B9B47A7E8EB235413EC79780
-:10EBB0002ECDCF03BF248E7F674AF6C4F5AF40AE9B
-:10EBC0005D72E9FD205623A31CD0E452751223BBCD
-:10EBD000ADDD15ED8F7C04724A4A4E47F9F458CDED
-:10EBE0003E944FCD16924FAF0F38417EF5CDB5F321
-:10EBF000092E875D3C5E2B9BBD1E7ECED4A8770F71
-:10EC0000A9AD94A77D68A4CCF07E948BDE51749E50
-:10EC100039113CDF44BF1964D77E940D23AFEE77E2
-:10EC20001E5A5641F9CC89C63B34CC4671CFF29876
-:10EC30007B7007093A2A4B16F0B470FFF1EC0B4ECB
-:10EC4000CA2F3E5BF00EFDFDA2B38D7F181EA4BF40
-:10EC5000D7D57A3FEEBF07FFEAA0B84CF9B0778668
-:10EC60002F27BBD6C7FD37F177C1C6BD78D8857EC3
-:10EC700077F9F6FDDD823AFCC5FA6D65627D4C6977
-:10EC8000EB4F79A1AF9CA2BF1B53FED2816E3C2EED
-:10EC900064CC5B89F5D7CB6BAB086F5ABD326A3554
-:10ECA000E4AF542AFCDC6F65D441F92BAE64A33F7A
-:10ECB0009F105ED708CFD8E71A3C0F0D3BC5CFAFEA
-:10ECC000DBE2D36F4DB2313E1C7BAE2051FEFAED3C
-:10ECD000A2DF45EF183A075F6E0EF7BD96F8820681
-:10ECE000A7D72F2FA0F30A2F2438AFE04FE671F7F4
-:10ECF0001706DC4B79C763AC35A5A8BFC788F86594
-:10ED00009CBCE37B9247623EF33F27EFB852C38F30
-:10ED1000C8EB1D837C9CCEBAE41D5FED3CC824BCCF
-:10ED20008F3B0E7FDDD401BFF767E0BD4EF73FA1FB
-:10ED3000521ED002984310E3261B548A9F1EBE6CBD
-:10ED40006118CF3EB95E7D1AF3552A9ED8DFF331A4
-:10ED50008C5F0FB3501EDD820DFC3E1036CC16C208
-:10ED60003C8D8A0D0F66607EE467C0B74B605E0B1A
-:10ED70009E48A73C9EC32D8F64209E4E097EAEF810
-:10ED8000FA87B721FCB79BDD838741B9649B64C8D0
-:10ED9000035FB4C966A86B79401AFE98D4991FEE38
-:10EDA0000139FA78B2F17CCBF0CE7D85C793853CF2
-:10EDB0009D0EF3AD1A79D18C78DCFFAA9DE6BDC714
-:10EDC000C1EF570B0FFBF28DEBA15EFAB5A2DDABE5
-:10EDD00063C82B62B80981F79C88FCBFD297948ED8
-:10EDE000FC7CE13738C6EBF2A0C3CB6A886F4A7F60
-:10EDF000C5FDE2521BCFD74D986FC4BAE4330F4024
-:10EE000079DE25CFA8F33C84C12ED1E8A63159E4A0
-:10EE10001B09BEDEFF2ACF2B9A7F48D89357919BC0
-:10EE20006FE2BC15C4D7EBB370DFF1B080C6E1CBA5
-:10EE30002757D13D44A3258CB0B19397E3F38D5967
-:10EE4000939F98BF3FA0133F93BD0B3BEAC89653D7
-:10EE500047DF67385770EDF2E6CAF2A436999FBFD4
-:10EE60008B95EFB174FF7F4ABE970F3BD01BCFC984
-:10EE700043F99F745E7E3B978FB17C1E2BCF6F8AC8
-:10EE800091839D72DC6490E337097DDE29CFCD2428
-:10EE9000CFC13CE3F7B7142AA19512F93D5FA0BE9C
-:10EEA000CE7778D28AA1CB2A776E52E0CA7EE82547
-:10EEB000E493765BE06B2CFBFC6610FD5DCFC1DB61
-:10EEC000EA4DC8BFED09EC8FFF0D39A0FC7700803B
-:10EED000000000001F8B080000000000000BCD7D2B
-:10EEE000097C94D5B5F8FDE69B2DC94C3299EC2BE5
-:10EEF00013761570801010A27E4900A3101C5001DB
-:10EF000035E82490842D24205AFA6A5F262460C4B0
-:10EF10006843B58A8A7650F051450D8235B651273F
-:10EF20008014AC4BACB6A5AD621044362582FAA76E
-:10EF30007D2AEF9C73EFCDCC3799B0F4F97EBF7F7B
-:10EF4000FAB397FBDDFDECE7DC6566451B181BC3D8
-:10EF5000D8B32636BBD506A902E930C6CEE2DFD546
-:10EF60008CC5380A66452731B6DF0A29D463CCEA56
-:10EF7000383494B15C6660712A63258A37C601E52E
-:10EF8000D5D6AE07CAA074C96FBE354311DB10EDEC
-:10EF90004D352632E64B37BB37E504FB93699203C8
-:10EFA0002A41BBFE2B0AD9C104C62C56E68B1AC5D2
-:10EFB0009862643ED3281CC7B5D200ED8D4D8CAD50
-:10EFC00081F6B17646F36443530D2C99B13BAC8C7A
-:10EFD000FE7C850C27C37C3BA2FD0D0A63DF332D2D
-:10EFE00003E7F303D3321D50FF23A665615E8EDB7A
-:10EFF00028D6693430EF565BEF79CD74287C1CE657
-:10F0000019EC81312B0A9937141E322D7018A95E24
-:10F01000C1C337677741F9671DB76433E86FD7AF6E
-:10F02000C6C67545A82FD3B575B5EE89D0F4FE3A9E
-:10F030002FA5F18C69389F5FD4CDA7BC13F25BA1DB
-:10F040007D85D933383EA49F818E788297A3E04F87
-:10F050009E01009743CDAA437141CA0CC5D8FEA0BA
-:10F060003FAE78BB6897A86BC7E7A9328DB101B0F6
-:10F070006E9BF15F5D02766719AE9751BF7DAD73F0
-:10F08000A683D38799B9ADD8DEBCE33A2BE25755B6
-:10F090003407E6253D5C0123203DDC839FAE606C98
-:10F0A000B4E2F538A89D9620CBCFE6E0F8C594975A
-:10F0B000E3B34C58715ADFF0628A7613E2EF08D35B
-:10F0C00066627FAD66769903D6DB1ACDE6479A6F06
-:10F0D000A9C05FBA43D00BB3390E5F26C683F99D32
-:10F0E0008CD16EC77ED2A23C65D86F5E46AD6A8277
-:10F0F00026B3A21DA2BEA67886537925D663A99A07
-:10F100005202F0CEFB04E810B2DBF6142A2E183FB0
-:10F11000B173A2E282F11305FE7ACD5FC0ED25C680
-:10F120008A23CD7356349FE75201FFFD560FF1D766
-:10F13000EA1C6F6A2DF4E76A659A1FDAB5E2944219
-:10F14000E0F396C34CF5374477F954A4FB5B987B06
-:10F1500013D0414ABE4F31429A31B5A50030CE1A84
-:10F160001C4EEADF59EC4D55A05E7AAAD9AD2A179C
-:10F17000CE6FC35A35D50BE3E77A0D348F759DBE3C
-:10F18000A8C130AFE44E6F8119D2A2F864EA3F857E
-:10F19000D5D6233EA03D43BE1CEDE0FFCCF516AA1C
-:10F1A000AE10B8E4CDAB6D30C3F7EFA3BD6B43F940
-:10F1B0003163B18FC639AA78FB39819E8EBE193D65
-:10F1C000DB8FFD059C4447B2DE5388D724A487C259
-:10F1D00074960AFD6F34D1BC7237FEEA36E4FFDC68
-:10F1E0008DD718951039F38AC344F58FBEB9B01F77
-:10F1F000AEDFF7370B1B14410EBD28E8E5618187B0
-:10F200006DE6C874F59C1C5FD0FB04A648F9F79C1A
-:10F21000907FB103607D4BAA4F91FC6B76B8A8FE3E
-:10F22000E3C6D6DDE900D7C7E731B70F3E2DDCBC1A
-:10F2300041C1F56E33B75EBB05E7B5C4C0107FBBF7
-:10F2400076FF6E773AE4E7CF738DB4B842DABFFD4C
-:10F25000EC6AFCFEF87C3612E19AE65FAB18003EE1
-:10F26000DF46B5D0BABFDD6461F530B5C7373E9231
-:10F270006CC77A5E8303EBF5E22340B32115D3809C
-:10F28000C9308EE311E595C49F843BAE1FE5E2AE25
-:10F290004DAFD0BCE57C8050CC08F7A27817C16B8D
-:10F2A000E1E6ADD722F1A72F762A6A4E705EE7938A
-:10F2B000FB1F0ABEB8503A7C339EF331C8790DC7A4
-:10F2C000F3E51949CE7F62F3FE1DE13ECCE64A2804
-:10F2D0008029353AFAC77861FC7E03D8ED9E08FC98
-:10F2E00078A9BD703FD63F19E53D807CDDEFB94B75
-:10F2F00027B258C62EDBD262407C9C54B85EE8CD63
-:10F30000A7423F0ABD28F5A42C3F29E8E20EA12719
-:10F3100023E8C79391F4A38BB9EE1B06F8626F1B29
-:10F32000887FC3C75D2AE87282E62D427E9E1DE378
-:10F330003D83F3BE629C7FA70AF5C716FB7622BF0A
-:10F34000E72AB53BED0017762D9703095DAC0396D0
-:10F35000C5E2F77569B1909F8B7200C61F7F44EBC1
-:10F36000C0F1E23C4CC1F6CF229DC33A5A9CECF668
-:10F37000E911E8FD36B12EC343DD66D46789ED0A95
-:10F38000F15B6FF8707904F232261EE697D70FE42E
-:10F39000694E6F791A017FCE786877C996C00EAC36
-:10F3A000352A7E600C343B17FE92E3097F5A0A8EA1
-:10F3B00023F175E959F576CFB0DEF8CA8EE7F3BFD1
-:10F3C000D3AE6561BBCF843EE80B8FC3E339FE8AC1
-:10F3D000E2B99DF3AC5DD48BD2D72B8BE778A988AB
-:10F3E000D7CB83107C0F8F8F806F29C7B7ED7949FA
-:10F3F00045BCE54D6C69403C005E47E37AC6E7D703
-:10F4000036E0F784A95C1E86E355CAC370FC86E328
-:10F4100095B17A9A1FE0E3AAF808FA4BF613AEC743
-:10F4200042E404AD6B9DA04F1FD227E3FA68832D01
-:10F43000B80EC93FB709784CF07A8BCC9C4E4B7014
-:10F44000DC2B66FB779A904EE7FB769A43E97401D2
-:10F45000A3FEE43C32BA7CB49EB47DDE024CC71FEE
-:10F4600009740C837A29B5B01E165C4F56E7870ADB
-:10F47000CAABACDA4E85A1FCDCB383E69DD9B98B6F
-:10F48000A7A88787F5D6B78CAD1474C8FB79339ECF
-:10F49000CBD5D55FCC4D45BA595DC0F5ED2ABB56ED
-:10F4A0008EF3BEC3A1CD45FCADB36BF3303F2B9AB9
-:10F4B000EB85E1F15A257ECFEA43DF2F117000B8CA
-:10F4C0005763BBC4E5CCA7C03AC6EEB3F9415500BB
-:10F4D000E9C3BC614189B53EC50C704DD4981BE5AC
-:10F4E00074BF046FBD09EA755FC1DC4F413EAED405
-:10F4F0005180F072CE7777203C577FA1927DBB7A06
-:10F5000029F3AFA47E18FF3F6F7F3FCA57E4DF5057
-:10F510007EF18979F8E2391F80BDF3F378CE9F75CB
-:10F52000C49FC2DE917CD997FD12C2D7AB2F92AF98
-:10F53000EFBF48BE5E2BF8FA97949E87AF1F0DF27F
-:10F54000F53A9CD7F9F87AB3E0E737057FF7C5D7E6
-:10F550007F10707B27BE4F3F67338ED75B8E73BAA9
-:10F56000937CF1D29E5131E5D0EF4E31CF10F9DDD1
-:10F570008AEB3B9FFCFE37F8FCF7D8EFF9EC54D947
-:10F58000AFC4F7F9F864B8D343F092F668ACDD4144
-:10F59000EB917C0FFCB247F0CB5EC12F6F613A2B31
-:10F5A0009ADB07E1FCD5A3EF3AB93C014F2606E907
-:10F5B000478E7FA437BCFE12095E594CC0AB98CB76
-:10F5C000914CE65363B1DFA90ECA3B4E38EAD155E0
-:10F5D0008C3DD4ED43B87D1BCFFDCC5C857922D921
-:10F5E00075C7049F247616927C01781EC27125BDD2
-:10F5F0002732C714F473A29C5C6E8C1EA7ED44B92D
-:10F60000E4D03C2ADA1BB94ECE0F124ED0FE8B4806
-:10F61000F8D88EF818D6DB6F08C7C3A762BE514E64
-:10F620000E8FF0FEA5FCC1FE8753FF2E03F62FDBE5
-:10F63000FF109443DF237EC62EAF55715D894C8B3E
-:10F6400041F923E524CB84F6B9BDDB9BC4B8D0DEF9
-:10F65000E484746C2DB41F166C9FC5020AC2C339B2
-:10F660001FE41443FBDD4DF66C9BD5637312BD3074
-:10F670002EAF0A0C240FA6D934E2A748FADF7991FD
-:10F68000FADF29F4BFF342F4BF33A8FFB19D723E05
-:10F69000FD2FEA8F709E5B4EB87BF022E304BDF530
-:10F6A000BF3382FEDF6FD5A8DF087C3412D713E3A7
-:10F6B000D046610A7C34DA9914D43BD06E0C7E6F4C
-:10F6C00013ED9BA71A86927DCDA2DD91FC9942A7EE
-:10F6D0004D37AF2B859FC2DAFFFBB7FF91C7580D9F
-:10F6E00016F179163A43FC9607A77E9AEC253F8ED1
-:10F6F000E9E22BBF5EE97E6F088EF7AECA90BF7E4F
-:10F70000FD9F5D6684776B74EC0816171CB7E65F87
-:10F71000405860CF9FFC97815289C725EDCA680683
-:10F720000C59B0F33B8A939CECF817C5492EB5975A
-:10F73000CFC075ED7A8DC74B4EBF7DD0897424C77D
-:10F740005F26FCC849EAB0D600D0D3A9CD6637FA07
-:10F75000212A733D920FF3A9D963627E9283CC8AEA
-:10F76000F54D7CBACCB47975A71A8B79A34FC439FF
-:10F7700094B3A4EF5C714897A63D2AF9152C919794
-:10F78000D7326BFDD9FE2057C719982B242E12AF04
-:10F79000453357489C22A1D8A9CB338CA7C0B88B3E
-:10F7A000189F6792275DD73E65767F5DFD34EFA594
-:10F7B000BAF28CF9A374F9ACDAF1BAFAFDC03F0AD7
-:10F7C000CDE7F8AED3D51FD03443971FD4728BAE9C
-:10F7D000FEE7ACF6E17C5CB74FEB1C08F39C27E638
-:10F7E00039645DB9AEDDA586D63CE068362FB070D1
-:10F7F0002A1B01FCE85FA8EBE7F8B3C57B14F8CE41
-:10F800005A4C8738BC6A19C28BD60FF0AC6C53D8EF
-:10F8100063D0BE6A1D2F97EDE6B7AF5D9D01E9028B
-:10F82000BFFE3B637E33CAFD459BF5DF1F74DA13D1
-:10F83000294E93CED2CFAA91E8C046E39D5AAFFAA3
-:10F840002D803FD537248C0EF4F860FF4BBA700939
-:10F85000BAB0A4EAE922CAA5A78BAABDDBF202AC22
-:10F86000379C63863A23C251C2D9EED6D38B842FFC
-:10F87000E8C9FF13F8BE81F08D09C2372DCABB035A
-:10F88000F9EF74DB7295E1785EEF686CD797FC9DB9
-:10F89000622FDC8DF2E274DBD7B7ED80F5D5C47052
-:10F8A000FE3FB9E3BBC128DF64BDEB5694BB278E96
-:10F8B00006E02ADEF7B07FF9BD73E8D3CDA3603D43
-:10F8C000A56D2AF1F149A3AD49B99C96E97200DC16
-:10F8D000941EBC713C4ABC29ED3BFFA900DE2C30D4
-:10F8E0004313C61BC7B9AD384F8CF421BD286087C0
-:10F8F0009E8D217DF231CECF57A8318AF7FC89B990
-:10F900001BA056833DEFB2F3C4050E38495F7A1B46
-:10F9100051BE8EEDF49EDE82DD1B3B1D18FF9DE285
-:10F92000F5D27A2EC70982FDC41C00277BB03DB4F6
-:10F930003B8EE34E2970C6A0BDB575D732F2DF58B5
-:10F940007B22D9834832A1764EB89F25ED46B0D3AD
-:10F950004FF17978BE7686DAE9C26E93F6765FFD6E
-:10F96000807E1D8AF6415FA9B2431D6A04B8742BDC
-:10F97000D1EEA722E80D4B82DE9FBD3218DFB22404
-:10F9800084E88925779EDE8DFA03E01D9D00F3B49F
-:10F99000DB417F2B17A4BF63B1FE2331B144D7DD18
-:10F9A0007B55FF106870CAEA8A7302BCF2519F5CF3
-:10F9B0004E712096E10CB6ABB5A60F33823EC93F1F
-:10F9C00035348E9D23AE9E8FF54607F3ED514C677F
-:10F9D00017AC1EC5E7E512EB3C10C5EDACB1225FDC
-:10F9E00013168FAA69E2F1D70D6660B5907EC62620
-:10F9F000D879BCC75A3016D7B341C4A157E7286499
-:10FA000027AC5614B21B76DA0AA9FC90B3200FE19A
-:10FA100077B918672C8C81FAB9A5BF988FB0C764E5
-:10FA2000FFDDA27EB7B390D2B1090E8117C7A588BA
-:10FA3000FF0AAB46FD9A5535229CF313B8FD5313CC
-:10FA4000CDA49F46FC3449F0D76421478BEC204776
-:10FA5000B91F387512945F25F94FCDFFD00CA43B28
-:10FA600029CEC4305E7C959057EC8CF15394270ED0
-:10FA7000F81FCA276DA863178CC40A98E9D35039B8
-:10FA800053C83AD3913E8AACFAEF93B64F3E8AF20E
-:10FA90006F123306BFE77078C738837C7063428F7C
-:10FAA0001EC84439D516DDF5CB29E81FBFA3BA9F80
-:10FAB00062BDD75B91C0EDB066B4A36D042A0DE3BF
-:10FAC00097D9621FA5777D0E9F0D7DC4792BAC055C
-:10FAD0007311BEAADD538129B0C3A5C8EF6D666F4F
-:10FAE00003FA1DDD2F339AC7503FDB81F9E13E1742
-:10FAF0002E17F0EF8B1981743DD2407EBC6B5DCB2D
-:10FB0000CE282877AD579C0AE44D46E6B38F0ACA43
-:10FB100093C6841C9A6C7357F90E3B9427AD9FAE25
-:10FB2000F487F9B4B096A258B4B7D6B38871C13A85
-:10FB30004147530A76507C3DA91BE834021DD42569
-:10FB400018A41DFF9FB88EB1DDDED14AFFA03C2274
-:10FB5000518B7ED32E833F529C769AADA811DB0D3C
-:10FB6000F7B38871BF9A683E8F26AB670DD2E9F074
-:10FB7000ED01F287AAA45C9F676046A0AB1B841CC2
-:10FB8000BF617DC73FC98EF8EEEC5955DAA18CFAFA
-:10FB9000672897AA6EB4FB317E5FD59EE3A379797F
-:10FBA00014F720486ADADFF760BE2A37D78171661A
-:10FBB000EDEF4C393C944C58C6E59F911D967A96D2
-:10FBC000EC06748A189B21E8B906FDD124D21FCD1A
-:10FBD0003100FFAAF5F53BD2A0BF3F3F0D7D40D1DC
-:10FBE0003ED5BBEF67D0EF4DA0C4568CC2D4C84AF7
-:10FBF000290E9D4AFDDC28FAF1FD0BC6B506C7BDEE
-:10FC0000A97D2FAD679F89F9AC40BFA6423EB4E9FC
-:10FC10003FE2FC0D2808999FE86CA6B56512EAD76B
-:10FC200093E6EE116EB47F5FFB6B960FE0FFF1CFB2
-:10FC30004FDBD12EFEC4D86DC7EF47EEFEC0AE013C
-:10FC4000FC3EBE5B2D4678DF26F48D847787C07B33
-:10FC500042A2A70DF1727BDDF779DE10BCB3154926
-:10FC6000C43F0BFC30C310BB63D1E618B4847AF2F6
-:10FC7000D5AD09BABCD41FD516561B290EF48DE09C
-:10FC800097055B3698335C38BEF72D1CFF8891D3FF
-:10FC9000CF91ED76BF2F27389FF22D23CD68977C2B
-:10FCA000D26E6101D483C64E13B37139A3003D787F
-:10FCB00005DEC3E7B9FBF518EAAFE2575C2E95C144
-:10FCC000582B00AEDEF605247FC2D751F1B16B721E
-:10FCD0000AC0BBE25E85E1BE0AD6BF1BF0E65D71DD
-:10FCE000CF5768E785AFB3CCA79747739BF47929C3
-:10FCF00027AB04BEE7317713DACF152DFA7A55ED2D
-:10FD0000F751FF556172EC7882B0AFF2D8D8B3608A
-:10FD1000A734D8FAC779CFA1AF4ED4815C1FCCD815
-:10FD2000B13A2BA547EA18A56D092E82F7E2F6F73E
-:10FD3000EF42BA59D2B6D58CFD34FA2739C64315ED
-:10FD40004BFBCD0CBF5B705F159ACEC17D559827DC
-:10FD5000DA3A88FFD18AE77BE44793236C9F55AC5E
-:10FD6000AF54C09FD9B85D518AEB1981DF8D5F8791
-:10FD7000AEE7D49ED1561CD79C28E4F15858977A08
-:10FD8000E1EB92EB91EB93E5D52AD05984F692BE44
-:10FD9000DB04BDCDDB387D753A80A2E1B5CFB3BBC6
-:10FDA000B85F4AF6BC51E0C7685B43F6BC9181BDC1
-:10FDB000CED729EC79F621F2ADA4B3703AAA423835
-:10FDC000500087B7B30A3BBF877EDAEF2778483CFD
-:10FDD000037FA48A7DB354DC37033A3A144647BA0A
-:10FDE0007C458B3EFFA5A92B1BF91BE8E550287C21
-:10FDF000BF0C3B6721D3A4C4FE0487792E6DB203E8
-:10FE0000CA2B986735DF5F6D21B81C31B6ECFE193F
-:10FE1000F2DD464EF79F08BCFF32D1332111F59534
-:10FE2000511B81F2BD70659A9A08F5CA9A1507F2BE
-:10FE3000D3DCC69193910F47318DFA9B9310D94E25
-:10FE40009B93C8E15F5E6B6266B0EFCB610C946B15
-:10FE5000E5DB55E273A0235B09E061BEC043F5BD5D
-:10FE60005BCD6990CEAFADE276829FF30BC095EC8F
-:10FE70008485CD1D66A457F04722F29BD403D5ADEF
-:10FE8000FAF21AD64C78A8413E93740CE3CF4E1484
-:10FE90007CE6666EA447EF5D76AB1277FEF5B2DEC8
-:10FEA00071058A3B9CDA3388ECCA532E570AD6F385
-:10FEB00002CE3BD15E367AC7E2778013E9A3EEFA31
-:10FEC000183FDACD07CE803F88369CC33B16EDA4A1
-:10FED000AEBF67B1354A903EE57A6AACCD449F35F6
-:10FEE0004CEF6F96816383FB9B659B12FC3E85FA0A
-:10FEF0001FD18676C52613D90D3EB62C95019D7966
-:10FF00005699481E96B7C593BF5BDEC8F701CAB7BE
-:10FF1000C4FB55EED77F38302F8887038D45E634F4
-:10FF2000C2538E9BE2C36D261D7D4BFC84FB8B0B65
-:10FF30009B3A76A7BA7AFB8B11F073A80FFC1C0AC8
-:10FF4000C54F73187ED8DD095CCE2C7D739015E605
-:10FF500077AA36CAAD46B037A41E6299408079C1EF
-:10FF6000F853713AC70733BA93119FA79BC710BEC6
-:10FF7000C2F154FCC35CC207FBBB9DA13D3307FC2F
-:10FF80009019F0FD7685F3C79C866B8B515F6F4AA5
-:10FF9000E472E63D904F9A99B1F7413E69209F3E49
-:10FFA00000B985F93FD7A552FEAF752E4AFF5637E7
-:10FFB00094D24362BF54F20D108019EDC2E704BF22
-:10FFC0003C9728E381CB53D17428FEE1833106347A
-:10FFD000DD7D33AF9B94C5D8F59A5EDFCDBE51AFC2
-:10FFE000CFBA4C8EC9A9E8B7DEAB90DD57EE99A029
-:10FFF000ABCF8C2EF3740C6C0F1D1DFC4EF69CCBFE
-:020000021000EC
-:100000003C03F8FDE6A909BAFA339B3274F99D89DD
-:100010002E5AF7F4E201BAEFB7945EA6CB979D0192
-:10002000208C466A76121E965B9930169D3C2EE80F
-:10003000E075BFAE1D9BF21398EFD76F9BA83C1CD9
-:100040001F12AFF3D6199817A636771DAC0DFA3DDF
-:10005000D402788276C7F7D9C9BF58BD65F4BBE32F
-:10006000207F608B89E202071A131E40FBE8C096CE
-:10007000A45806A977B52AEC08879985C8ABA2C60B
-:10008000FADB502E95F92D6EB21776F99E947917FA
-:10009000FAA33849E4970F553FC6B7007F3C2EF0CE
-:1000A000AC85ECDD2360B7E1D6F8118535628A8A2C
-:1000B000250ECABFE94CF2233F17FFA06AA9484F9B
-:1000C000CF46517D8A5040F9B1F7073DB586E8CB60
-:1000D000D51A20BEB5903F30B78BAF8F29A3321011
-:1000E000FF47E299160F93A85EF6D7FD46C0D3826C
-:1000F000C19D2302D0AE342790340BDA9DD868A27C
-:10010000F320D8AF03F2D5CF59367039A2A54C1FD2
-:100110001E0A4FFF085CF71C83E7FF2502FE8E5581
-:10012000FA47903CBB3B89F82A1CEE87CC5E82AF35
-:100130000FF94009CAC7209FF17D1E106A69286720
-:10014000E69ADCC9A89F0E359BC8EE04FD113B9DC5
-:10015000E22B2F111D1F32BA26E3BA0F35E530947A
-:100160005772DCF26695FC02A43FAABF56F5828D59
-:10017000C0A49EF235295E96D29B6EEE583A3605A3
-:10018000D7136EDFCAF44BE0556F88BDB0F035D59C
-:1001900043E78172BB8C370E0F5D4723E7B754DE10
-:1001A000FF7221D717F7FFC37E9B01E5FA80388CD9
-:1001B000931FFD50253A3BDABF252F1548FF846178
-:1001C00047DE4F207FBCC477D808F9272DDE814950
-:1001D000B0A44586E66CF48F4EB61F7C6002B43B3B
-:1001E000F6BCC98DC32E7C76413F8AE708FBBAB7BF
-:1001F000DC0AA473FB404B53009E8B5CADA4B75D3F
-:100200005B14C6D7EFE7E705841E773CA4A02DC595
-:100210000E8EB1AFC178C75C608F50BBFBA089DB8D
-:100220000579495C9E48FDBE5CE4E71A385DB3D7AA
-:1002300015FF2661EF84EA0129972725F5A7FA3DE6
-:100240007A99B592BCAAC4731DB0BEC59B2D7E7FA2
-:100250000EB571209F2FE0E861F5492E7EBEC7FCE8
-:10026000FCC3C84355AC93E67DCCE4AFECCCC1F6FF
-:100270001B1A9DD4DEE4A6B8ABD027566020944765
-:100280005582EFAA5B147F80F886EBC50AD13F4305
-:100290003D1322BF7AEB15BD3EA9107AB48285C505
-:1002A0006D5BF4FACD1363A7752D8471515F06E77A
-:1002B00005F631C0ACD2EBDF3D8DE6ADB8FD11E601
-:1002C00051C5BA03789EAE7A8BE20EB0DEF30A5FB8
-:1002D000C785CEB3D23D7D627C6EC8B861F396F01F
-:1002E000A6C06F081E24DC2B7D1C9E95ED0AE1EB59
-:1002F000336197C11FC59B25DEAB98671A9E37A84F
-:100300007A08E4654E900E7AF4FE56BF19EDDEE3EE
-:10031000AC25D60674BF78DDD6995760BBF5EF9350
-:100320007F51EA0C0C32C4837FE7EB58539CD5DB3A
-:100330004E08B70F7E2CF8E0EC8D79A21DC0A362A9
-:10034000A3AA458DD0D5A3F6D23E98EFF399319E5E
-:10035000395FC409CF37CF1AAC37EA42E61BD99EC2
-:10036000F9DFCEFB8524E13FF5B2870645F4A37A99
-:10037000ECA0F3E8DF8F4C812CD4BFDD5946D23F8F
-:100380005F1BDD7F2D48447D3C88FC82BEE46BA56D
-:10039000D0C315A897213DBC6E5B2CFAED9F3DB4F0
-:1003A0008DF6FFCCCF57C4A25D7C78DDDC077CC026
-:1003B0005287B7CC253D5CF598D4C35E73A87E2FD9
-:1003C0005A57F6EB9F237D6E8E725BA0B8729757DB
-:1003D000D8DD20EF500EAEE3F28E3DC4E56115EAA4
-:1003E000AB61A4AF8660BDBB2ABD4390CE43BE9334
-:1003F0001EBB6BAE772CB5678E00FA5D203903A863
-:10040000AFA43E957AD668F07E9484FCA3BEFDE747
-:100410009FC2FABF784925F7AE5ADD90EDC0FD8244
-:100420003EE4F6BF0F6F430FBC732E00DEE5086F8E
-:10043000B27F38BC3F6DE2703ED8CCE1BE7ACB8053
-:1004400058F46F3F6D1A4076CFA75B0611BCE7AD3D
-:10045000017893DDEBD2DB3D4D006FB4F311DE305C
-:100460006EF92E9780B79BC3BB49E89D669ECEEB85
-:1004700005571F9D1BBDEB698B1BF5F991A8401219
-:10048000FA2347B6AA0CF7E57BEC2261BF48387F18
-:10049000C35A9E443BAA973DB3D6C21CD0DF829775
-:1004A000ED7E06F9634A410A22E044CB1F6271BC2B
-:1004B000E0F83D768C23794C881D7381F859C23C55
-:1004C000747E7D49FB1FF6A11DAF68DCAF5F62B58E
-:1004D00005906FC1DF39112ACF1517CA348C93B834
-:1004E000AD56A4834CE6D2EF1B7919EE1B7D3BE899
-:1004F000ABDB96113F770F0EDDD7A9890E9830BE82
-:10050000D4BD55217C572F2F882D60B82F554BF324
-:10051000189ECCF5B1A2691437B400DD44C378EE5F
-:100520006417FFEE72F038E27A18D71E9C6FF8F766
-:1005300069487AA8CF6D06D2E7E1EBBF2D99FB2B76
-:10054000D5AA81FC8EC566EE7FC8F30F578AF22BC1
-:100550009379BCB72899EF179C8C62A4374EAE8D67
-:10056000F1D7D3FA26523CB3277E22E1E6307ED97A
-:1005700023AF90AF44FC603FB68179CEB388782E2C
-:10058000A8586C7FAB687F6BCB3BB42F079ECB1317
-:10059000A877E7ACB0B8D17EF5BD6621BABB279A83
-:1005A000EFA3B0C43823F2D12D42CEDEDA729F071A
-:1005B000CF3DCC6989D13085717C4CC44F73711F9C
-:1005C00036DD4CF1D3526BD7F3E866DF9E7AF04EFE
-:1005D0002B2CADDEC0ED967A27A3F3239783D98E1B
-:1005E000F15828DA7E36E15CF4A38F0F2FC638ED80
-:1005F00078C6096B1CC155975F6CE6E5CB93474DF8
-:10060000792893B13F31D770C4F762840DD2435932
-:100610001CC501AEC778B1135323D1D90C23F319EC
-:1006200078DA84A135193F9E26D67DD33816888383
-:10063000F506F6EAE3D7B30286C010C0C3F5C6409C
-:1006400007D2B5C1EA32A13FE0295646A19FBC7846
-:10065000E585CDF79EE42B69BE8B0D063ECF9F2A24
-:10066000FEA7004EB70293237DDE6664BBD4511C07
-:100670007F487F354E978FEA2DE5F42DE3E6124F44
-:1006800023A1FB50F8DE2AE607FD34C5627B73E444
-:10069000F8D183C9D20FE6F6E622C1AF8B24BD6D37
-:1006A000D1F3E936E4173C9F83762DC0ED5691F6E1
-:1006B00045EFAD82DE5B05BD3F29F2173A5EB58599
-:1006C0000568DDAF59088F72DCEB45FA4232B79B03
-:1006D000E53C243D3311873280E4403A3AD4D2409D
-:1006E00076D3FCB038300B8D57A991F23DF2C7702C
-:1006F000165373F73C9C8F7255941BE9FA5673EBB3
-:10070000A05A5BEF7A721FB794759AF8BD1B11CF90
-:1007100012FA6A926AA37341A54AB41BEDDF9305EE
-:10072000769F210EE32D26426D29D003CAE78FA2C2
-:10073000F8BEFD9CB8BBA6A15D581A6B36627A3B29
-:10074000EBB4E7E404ED92D5052AEEC1C1C0D55360
-:1007500034C837A03CE1F9FBB44C8A0E89FCB23FA7
-:1007600062F98DDF01FE297FC7140DE4C5C9374545
-:10077000395B4EED4FAE1274EC5B3105F7394EFE2E
-:100780004A96FF9C97DF2BCBEB79F9FDB27F915F07
-:100790001B565E1F56FE28CF773D5C3FC587701203
-:1007A000FB31A5E31592272E4167A52B0304DF52E9
-:1007B000C30E9E16B28021F7FCF56C291E5732ED50
-:1007C0000B1EB2A3DE4E48D35CC950CF96E43D8EDB
-:1007D000DF174E577C6694931FFA070BB91EF15C26
-:1007E000AD4BD06D542AEF4FC21BFAF91AFBBBD8A0
-:1007F0007ED6E1BC9274FD7CFFEFF4332FB5573FFA
-:10080000E6947FA39FBD61EB92765159BA9683FD22
-:10081000B14389BAF3658BFED31D877615C3F365A3
-:1008200000FA452B5BB34743FF8B5E7835BB32C480
-:10083000EF5E72C6C034B09F6ACE304A8F77FCCD6F
-:10084000EC82F92CD9DE619E0CF56A202D0A99D72D
-:1008500062794E9275196784E8F5C12906219FD601
-:10086000D27C17BD70D488F85C64683DFC18C67BE8
-:10087000C62B11F75D6345BBFD7DDCE71A96C2E52B
-:100880009E2753BB2C05CF45A0CC407DDC10799F23
-:10089000FE4ED15F6934976F73F3EC5617C079CC75
-:1008A000877C9FB9727DCE288CE35E9E543806FB10
-:1008B000EB3B2EDACDE3A2ED3C2E5AEAEC5C0EC205
-:1008C0009BD5A66CB8CF7A2563531E917C062C0B62
-:1008D0006D8B2D32DF3665623EC5B9287FC3235B41
-:1008E000EF43BED913CDCF4DCC193B3C1AE542574F
-:1008F0004E8CC101F2625C62592DE26FCED82B277B
-:10090000E3F7028B7D70198FAB135D8C4BF44CC1F8
-:1009100072AC8F710DAF99C7B9BC6FA914E7F28E95
-:1009200088F146DA47BE56C0A136859F73DD03685D
-:1009300046BB43CE438E0F86CAF24EE8EFD0CAB410
-:10094000916B5CB8DF515043F424C6FF65A2B73405
-:10095000747C58EE08FC7EA1F3B83985D36F0DE2A4
-:100960000DF198AF322DC45F9C31314697BF716A4B
-:1009700002D342E3AD3766E8F2B34B07E8EADF3271
-:10098000EF325D7989A533B7F622ECDF1ABB3D1A49
-:10099000EDB08FDBBFF9CBAD68D76D54DD0AAC6726
-:1009A000C16B9BFE32016A9DC2E397FCFE14C5BD7C
-:1009B0008EE17936E43DA3660CDDAFF98275D2B9DC
-:1009C000C090FD00DDBECB22C72E3AAFFA63EDD753
-:1009D0003C9022FCDF516C14EABF53B57FA638DB94
-:1009E000121B5FCF17AF1E30E339063C177016E8B5
-:1009F000FB1A6CA8229FFB280E5DD476C08CFE915A
-:100A00003B85CBE525994B8D6091B11A48516F4CD0
-:100A100006F91407F4D1D9C1866FC7731339763A32
-:100A2000075E7D66060869A423DFB0A5506F5153A9
-:100A300031E5979C89A67EDF533B27D379E4571491
-:100A4000DA2F28C998B312ED51AC7F078C57F2E228
-:100A500035C5089F25DBF9BDA712F54FB9D8CFE200
-:100A600096626A5FA2B23D0AD807538AB89E2D41AA
-:100A7000DD0E7935CFBE06F5AB6A0E0C7E1CE5891E
-:100A8000D94EF224EECC2D347ECD192BB5FFAD908E
-:100A900017A62E3EAF49673CF45DE2BD3D85EF03EE
-:100AA000CABC2969A311EF1598BA18D5BFEECCA519
-:100AB00094CA75BE35F4E9449463A6A4AF276700D1
-:100AC0007DBC95A838C8DC0893B7A76BC7C6B1082A
-:100AD000F2A8679C33FCFCAEE50C3FCFDB9EA6FD85
-:100AE00009F96ADADD5D46DCBF6136AB03E1356DDD
-:100AF000DC485765081FA93B6E36235E4C0FBD6F5F
-:100B0000467D6C81B428A4BC5A9E3B0F93C7FB045E
-:100B1000DFC97B0752BF30DF6CB2476F13FEB7E40B
-:100B20009337457DD9BE13691CF1F8B285FCA73F08
-:100B3000A7798FA3BCEC2C60B35F22F9D8998DFB09
-:100B4000263FD6FC01CF5685ECFB2E3ACF3E6D9C5E
-:100B5000CB80FB01DD3DEBE0FC7ABE757C2CEABF6F
-:100B6000A7B215D8EF7B575FDDA9417F1D3F1B3D25
-:100B70001AE5BE1C5749E5F77098A3FB3BF4E76AFA
-:100B80005E8F71215F97A073941BB463E13BC3F840
-:100B90005FCDEB96A71428AF89057F16C62F7A2361
-:100BA0002A8074DCF1469411F5437DA657491D83D4
-:100BB000DF874C44FF4D6BB71819D9379A01BFF73F
-:100BC00035DFF3C9A7703A937CE96DE2FC5226E861
-:100BD000B45CF09F57F0D1E9DA14E2C3D377C3A431
-:100BE000719FF36E65F876B4075C76F72057902F07
-:100BF0004BD0EF81EF2597C593FF17C277C4878B42
-:100C0000CF38A8BFEA332EC1E74ECA4B7E2B17FC64
-:100C1000621176C43C41DF49E9DE91A930FF9206BA
-:100C2000E07718C7BB322D17F928482F6607D21571
-:100C3000D04B6A6508DF3474DCCCD0FEB0247A88EF
-:100C40005EE6411A6A7F54F4D81F8EC9C930EF6935
-:100C50008D39BA7B1679A91747F70352C5BEBC2D4B
-:100C60003008ED55536D941BEF839D4AE4FB33CB65
-:100C7000EEE5F05B66F214A1FDB0EC51C50D9821D4
-:100C8000BB02E551DEBE5A7368BCF1E63323980B14
-:100C9000E070C39981945E9EE49D88F82F3B3353A6
-:100CA000C06BC4BFB50F3846E3F12593DFE2DE80A9
-:100CB000FB6C515E15F17B248B391E0C892F613C36
-:100CC0000CE362727F50C69B2CB89F1AA227BF31DB
-:100CD000B664A3BFD32BEE54A0DF475BDCF1A73C87
-:100CE00003941FCBD128FE34C7E0BD0DF1BA708646
-:100CF000FF0513E417DDBF2D16E3DD129EADC6C060
-:100D000020D493AD00478C83B536ABC57E6ECFC47F
-:100D1000F0FD2F4ED7928EC3E97BE199FE444FA799
-:100D20006B2DA4774E03BDB210BD23F58D94EF5209
-:100D3000EF487AAE3672B9556D8BA37315417D338A
-:100D4000DD83715C36949F7F0BEA9BA71E188FF49E
-:100D50007F3291CE3587D3FF2B75A974CE46EA91A9
-:100D6000707D23E5B994EF525FDD95E65D8B702AC7
-:100D70007CEEBFB7FD1D3E5D67E47AEB3AA39DE8CC
-:100D8000E7C2E5E60121370FE8E4E6923EE4FEC360
-:100D90001749FF8DA23ED8AF6417A25C0FEDEFCFCD
-:100DA0006985BF41FA7D2195EBD51F6BDE7DC9FBBF
-:100DB0001752A51F7161F2FE7151FF7CF2BE43C84C
-:100DC000FB70F9CEA03F94EF275FBB84F6A7F73303
-:100DD000D007A8F7DA635C9B84FC27FD101DE73F72
-:100DE00097FCF764CEEDE843FEEFF8DFC87F498F4C
-:100DF000925F247F487E08E71FC90F53EE03FF0F61
-:100E0000F1F41EBF5F546DF46DA1FD4357CC48E46F
-:100E1000CB1EBB6DBB427CD64B2F08BE09F2895E50
-:100E20004F48BE907C22F9A35AF04345183FEC543A
-:100E30005B1F1C0FED6E4EF39E0EE58BC52F85EBF1
-:100E4000853EE90A2386AC22B196215D55431A4AB4
-:100E500057963EF8E14C0F3D5D183F1CBE407A8A24
-:100E6000493353BDFF437A8A494B8A484FB6B41F72
-:100E7000D19E385DFBD75C17CCE7742EC8D99C2077
-:100E8000BD4DF923E3F6C2006EF7EF89E6EBDC63B4
-:100E9000CEA278CE94B3FC5CABA44B8967690754AF
-:100EA00088784271BAC78DF395FEC285E2D992D88F
-:100EB00069463FA402D250FDDF97BD3B26EDE2F02C
-:100EC0003C20EDC2ECC4C902CF3FA29D383D125E6A
-:100ED00099C3A98B4380FEBB81ECB780918EC8F487
-:100EE000E957ACE37096F95501A3D4B709A86F810F
-:100EF0005E66E078FF2EBD941431110F7C79AA96BE
-:100F00000F78FF85C8B357A7227E668E93E5BF6D25
-:100F1000D606A2DC61328E4E7191F75491F7BDF284
-:100F2000F644A83FE541168CB343F9A4FCB89E38BB
-:100F30008AC282F5973EBAFDED66C2333FF7C2BC66
-:100F40005D46BECF24F2B990B787E4C785E5D7F3F5
-:100F5000FAB1C62EC6CF29FA39BFAAB8F5C6E9C775
-:100F600013628F002627E3798269DB1507C6416E7D
-:100F7000C93F49FBB1C1F5BF41EB5FD2AE88FCCEA2
-:100F8000B771BDB76CE7F9471EFD43B36FA0E82FFB
-:100F900099E264F4676A55343CFFB0789CE2EF9FB5
-:100FA000D31BCE8FA4E9FD1BFC33EADB333C7F77F8
-:100FB00031ED11CFD4BE3FB50F582E62FC59F991D7
-:100FC000EF3DFC97AC27E209D43FC0F286D6C8EFCC
-:100FD00097BC28F8B113F74D085E1F3523FC3ACDB6
-:100FE000129EFF68C67837DD9F81FCAB8FFE63AA37
-:100FF0006F189FBE16B6FE73CDFFF108EB77E9DBE5
-:1010000007CE05BF0DBDDA0BFA99AFA7A738A367C6
-:10101000D769E8270EFC7FB48B9778A29AD1FE0F90
-:10102000D2C761A28F4E19CFEF45FF9F4F9D682316
-:10103000FB47D43FDA8C7ACC63E8A9CFF941D217C9
-:101040005E05C2B3738CB7FFE0D123CD081FC00F7C
-:101050009553DE780E7E680DCBE787F18FA07FE297
-:101060005F94F3009F4111E4CC29019F2FC4B9EA9A
-:10107000CE426E2776F6E7A9339DDB85FF12F83660
-:10108000A4F3FA9DD1217008C133FC05D00F095992
-:1010900037C1E9E644B9EEA892A9B0AE4E272FB702
-:1010A000A59BEEF7E507F3E1FDC5A64795205C8219
-:1010B000FD5BDE41B974B3809B33DDFA8E8FCB4389
-:1010C00005F9B29A0804E862BBE253D14F40BA88EE
-:1010D000B0EEBFF7A62B5F587BCD748EF65DBDDBFF
-:1010E0006B61ED9929F762DA0BBC4D0DC36B71187A
-:1010F0005E2786E54B65DEAF937F522E96B7AD5DDA
-:10110000959C88714985EE8A06E939A504E97991AB
-:1011100043D26F2AC13548CF69EF20FDCE6895F2E2
-:1011200030FD7E0DF0361DE5E1F860FE0694179463
-:10113000CF28D1E242F5452695CF6A92F5B3EE2746
-:1011400079DA28FBCBA6BCC423F3F52B21BCE60A35
-:101150007DE173BD83E50BDB79FB498FE5BC734E05
-:101160007E680983CBFAB0BC2FACFE43E7D12F8D4C
-:1011700061EDEF0E2B6F0ECBAF0BCB37E9DB97CDCD
-:1011800053880FCB801E1011E7E3CB9BD27BECD4AE
-:101190001E7DAAD8C86ED3F1D594069EBFFDB111AD
-:1011A000254DB6907CBABB24942FE4BD604B22231E
-:1011B000BE30F5212F4BD2F5FE59CF7A8686EB5BF8
-:1011C0005EFE09FE338DF6777476C14E559FEF5063
-:1011D000E5BCAF7A67B92D641F945D5982F195BE65
-:1011E000F75B26944CCC0CB14B7CE34BB49075CAA6
-:1011F000FA93BF3FABE27877A68F2FD988FB39856A
-:10120000621FD2C953D06B2AEACD1A118F998CE78D
-:1012100063B15E7460D0B2503B84B50EC67576FC87
-:101220008CDF1BF035007E30BEC6DC668CA774C434
-:10123000C5AD7806EAEFFC99BA02F5E8FE15097427
-:101240002EE94FE9DCFFDC19D72FB902F21D31B7C7
-:101250009BF1BD928E7B2651BA43D5567703AF3DA5
-:10126000F8D8B525B64BB03C8EE0F38BF44925F5A4
-:1012700040D7BFC44B3BD0DEEB7424E3BD06B6C6FB
-:1012800044FB7A8CB99F24BAB9DF3212FDE7B2FA77
-:10129000CB68DFAAFC57D327D3BD855526DACF808C
-:1012A0003F3A7FE25D3389CE3DCD6B14A9EF1A4AF8
-:1012B000DFF8E1E906BC1FD9FD8442F725AEFCBA90
-:1012C000F58F23F0DC63D30037A2E675B0EBF13C79
-:1012D000D2A7EB86D03D898351B574EE13EA33ACC7
-:1012E0005FF59DEBDD69B9585F75E0D18AC3F01DEC
-:1012F000EDE1C3F7AA4FE1FDC3B2587B349E973EA0
-:10130000FCBDEB5DB46BA1DCB112BE1F5EB5201954
-:10131000EDACC38A2B16DF1279F1B15925A9697892
-:101320002FDF22F039CB5E067C5E66E8A117D21F64
-:1013300095F13CFF62FAAC924D30FFC38F0EA17362
-:101340005F8333B4D674C0D3E90C6D2BA607C57D7B
-:10135000E5377EE0FB85BF3F519E8CF4F47B41C7AF
-:10136000AF9F294F2E0FB1772ABF3012DEDF30BB7F
-:1013700096E33CDF88CE52E87C366B4DC078F73C74
-:10138000E17F00FDAED816C1EE79385D253C75DCF5
-:1013900097948F780DD27125C94BF21B20FFF6630D
-:1013A000E5A4D70E5956B08368378AF38B6C67145F
-:1013B000BFEFB825CA1F9583F14F6D32B663A9AD53
-:1013C0008367D843F84ED4FFD8C7CFE77E0CF5D15A
-:1013D0007FFBD8F70F7BE83E84AC5F156BF7A1313C
-:1013E000F1B9DD6E443CEC37D61DC6737D954F9840
-:1013F00048EE573E91747737CA1BA0178C8F85AF84
-:101400002B35C344F0EA930F7D77944CD4F90777DA
-:101410009C930F0F3FB6AC64A3AD6F3EAC127ECA77
-:10142000E4274C744EBD6A8CDD88FB8F854FBCB9B8
-:1014300089EEAD2E8D1A85F713AA9EB010BEBAECB8
-:10144000769F03F74763EDC67848BF167648125E6D
-:10145000AEC4B88CCA8CD65194D2BD04B9AF7774DF
-:10146000C5830FE331CA63CC3F732CC0EF14220C49
-:10147000E0724ADECB0ADBE7ABDEBBCD5CC0CEB1AF
-:10148000CF779EFD3D205F7A47E242F7F96232C492
-:10149000BD9F9E7D3E13BD0B5125F6F98AD6F3F311
-:1014A0005B552BF8FB1D45093CDE7BA8CE878FC41E
-:1014B000E27A7D0EBC9FFB10D72F554CF15BE19F6C
-:1014C000D7AC5F6AA4FB8FE91C3E65E21DA7835180
-:1014D000EE6CF4D32B9F8822B8563DB9E02F8F4293
-:1014E000BBAEFA92C450BF3847D003F4CFF09EAEE3
-:1014F000ECE7F3FA9F6723DD17FD1AFC5BBCEF17DF
-:10150000CF5EB83907F194968DFB91B25ED5CA9F34
-:101510000DE6F5C03F063FB8EC5E95BFBFF6B2855D
-:10152000F41DF0782A0BB9CF3CAF71AFD93C2C78C1
-:10153000FFEB53C8E395FB907B60668497BC978470
-:101540007FA979C2DE7691FCA077784B0D0ADD5F2A
-:1015500002C945F77EAECFE0F6EBC40C7EDEA92CC7
-:10156000DB4DF75FAA1FB0B857E6F07E7AEE55E381
-:101570003927436725ED3FFED64271919AC6282D43
-:101580002A969F8B7869189D8B369A71DFC4C5E5C2
-:10159000C4F582FE6A5CD3AF417A81F27D463C8716
-:1015A00065E7F2B03A1EE0CEF5B06680714EE2BF5C
-:1015B00006F07ED346848CAF88EFD08F2B36D8EFE1
-:1015C0001E036BC2B80BD6BF6404C23161E66C9CCB
-:1015D000DFF32AF1312CFE817168DF3DAF8E46BF0B
-:1015E000B6ECDE9D93D7617EEB48BCB1C0CA5EF815
-:1015F00080F4C52281FF2E711EAC1CF278DF7F7E45
-:101600000697935E95C77BE60B78493A90E5D5F748
-:10161000F2F350D5AB2C64BF54D7FF95FAADB67733
-:1016200026A3DCAD7ED944F79817897997D767E56B
-:10163000EF03BA2A37C5D17BCB8B7D2566CC2F6EC5
-:1016400051281F6C97948D747ABCF19558A49F8390
-:10165000518141A887BA9746B9F11C9E8CB71D6F7E
-:101660001CF414C665E6393AED781F69DEF2014EC6
-:1016700094DBFB1D013396EF6FCD31605E7338F262
-:1016800031AF192FA7FC7171EE84FE905E148EE7C6
-:10169000C55B769AFBC3782D822EBE78FE83C1A8E7
-:1016A000A7AAB33B07A33E013A189C81707E56213E
-:1016B0003DBC640B3FA72EE96009D201F0DD424139
-:1016C000074BB6BFF213E4872588FF51BDE908E850
-:1016D00074177D7F69C364C6DBEF423A91FA0BF25F
-:1016E0008D2627C6DF441EC6C1FC5A014F289FC85D
-:1016F000CB7DC3F839B72E3AB75723EE2BF6C8A7E0
-:101700003EF0FC82C06379BD85E4ED0B02CF5DF74E
-:10171000BE1C8B78FCE2F99DBB719FA4FA25C5C164
-:10172000F7ABC2F842C0A506E1104BEB20BBA20606
-:10173000D71D1B84430FFD0B7EAC617C9D72DD3594
-:10174000460107592EDABF88EB4C42F80AB86D1FE4
-:10175000C2F94FF01BF233BDCF23D6E775EADFDDC8
-:10176000FE3083EB83D744BA18E802EF6731BC9EA2
-:1017700028E504147DB17503C57D24BEE4BC0F07C4
-:10178000F58816EF0CE2B1CBC0EF2F86EBCB7704D8
-:10179000FC0EAC4AC96E03B81DDF4CCF5412BD1A03
-:1017A00043C6937423C72B7A6EFA75B85EE83F8000
-:1017B000FDCB71F7FB628CD8CF7EC6F903E913E548
-:1017C000A7E4CBA28639D78DC473BFBE2FEC0386A6
-:1017D000E17A39DD1ECEE0E77F34B413A0BDD6A692
-:1017E00050DCF980F0E70FAC7A25B63C044E874414
-:1017F0003B4967F887F12839DF3D4E1EC70D9FB77B
-:10180000944372DE45F7CCBA0EBFCBF94B7A95F410
-:1018100029E128E954DE7F0BA757A235A93F559D42
-:10182000BC27FD784DE65766AFADF7F7F0BCB48343
-:101830000E8AF3DBDD498CC7EB1B537785DEF7811E
-:101840003F5BA8DE09D127CDC6107D22F57F4DA2D2
-:101850007614F1559CC9CF951C63ADE602E877F18B
-:1018600091CEC9F84EA2B43BAFFC3AA0C6611C6A47
-:101870003B3F7F26E1BDF8C42EA2FB6A712FA9EC85
-:10188000DE0F4AC6227DFFC644FB3165AB26D1FD83
-:10189000E3059BE6E621FDE07D0694E747378E19D8
-:1018A000CD9FF37224CFC47B0D1B1F9C790B7C9FB3
-:1018B000D7A6BA49AE433FC8AF65778E66482F07B3
-:1018C000A3BA4AC6A3BDFE53D581F6FA844D63EE92
-:1018D000C6FA13ECFDE2713DDAC604CA6BC638D213
-:1018E0000BD2CE95E7F21A4C9C1E466572FEB9A447
-:1018F0002755C479BC86C1B87FDEBD218ADE412A66
-:10190000358B7B9CAFA5903F5163C62B85742F947C
-:10191000ECB0F966664DE3E79DAD69F07DAFA9F3E4
-:101920004ED41F7BEFB48FA473F5EA7779E5DC7EA4
-:10193000E6FB8509FA7787E43C468AF1C3FB93ED21
-:10194000F788F3C607C5FC8F36FE6626EABFA39B61
-:10195000073971DD9FBF1645E7F03F0F7BB7F06297
-:10196000EF6901DD86DD835AC9E545A6FE9C96A494
-:10197000F3F3DE53FA28316C3FE0DCE78B4ED431D1
-:10198000BA4F6D015F98EC9998EFB7E1B9BECA16EE
-:101990008B03EFB31C42BAA7F33C2ABF776BE57CFD
-:1019A0007068EB483FFA8D951FF1FB45BBD6DE43CF
-:1019B000E70A2AC0AEC4A3543D76F2436B67221BEC
-:1019C0009C727B57E33B2FA736F37310BDDE2DD8F7
-:1019D000BB6D77E8BB05176B1F5FA85D2CE30A356D
-:1019E00099FA7BF112AED23F7A03F03F6E54104E5B
-:1019F0005FD6CD27BBF8449D97D293CA8107262096
-:101A0000DDDAE3E8BCFEEFDB1E54F19D95EAED2341
-:101A1000BF43FF76BC2DCE81FCFA65DD0ADAEF3CD0
-:101A200051574B69F05D573FA5576EEFA0765FB6F3
-:101A30008D6EC77BAEAFDBE284BC0FDFD7E178EC05
-:101A4000EBFEAE5CD7B19F727CCA791FDB3C3716C8
-:101A5000D7D5F17842FB1588C7983807DA7755E271
-:101A60009CC7E175DC7E3E628D7B662A9E0F597FA6
-:101A70004332BE8353D171E34CFC5EF99AE240BB22
-:101A8000DFFDDAF4588CA37D66EC8AC57B4D9FADF3
-:101A900093F7A1FCF41EE9F86246FB4EE30346E629
-:101AA000CAE15BCC4827579C30D2BDD3E3B81F8531
-:101AB000718FEFA229EEC1C43E53C5AB3C5ED2E3A9
-:101AC000C70A3F6E8258F75B994EB97F40DF8BC6DD
-:101AD000F1EF9FAFDF360DFB3BBAD1E4C0797FB9A0
-:101AE00091BFCFB010FC2FBC9A726433F76F16B65B
-:101AF0002AE40F1FDD0CFA19D655BDD4A4F1FB9AC8
-:101B00007AFA2B82723CD728E96FA1E627BA0E7FBA
-:101B10003F239EB5D2BDAE1F8B1E03997A3FAD8782
-:101B20000EFBC2BF8013F22DD2A1C4F3C2757CDFBD
-:101B3000DCD93AB200E949E25DCA05795FA1C1CCBE
-:101B4000F87BA58668FA3D80E936974981F5DF90F4
-:101B5000D83511C5E7B02C6E7FA845060DEFA1B1B1
-:101B6000064BC4F7A8FE26E4E89C2C46E93799DC2E
-:101B70005E90F7B1640A0BC9423D3D3DC6F98D0B3D
-:101B8000AA1C5EBF749A11E63F7D82F3CE016EC03F
-:101B9000DBFA9F4C3302DD4E1FED7CB93FE4BB33D3
-:101BA000EFE2F9CB9D634C90AFAF5F316D22D4B7BC
-:101BB0006769873243C691FDC2F7CFF1BB3FC17B56
-:101BC0000CD31A33BF1F7552E91EB1222758FF7D6F
-:101BD00085EDFFBD12CC779918BD03F34DA69C7F10
-:101BE000E4744C96763A734CEFEFE58CADA2F3714A
-:101BF0003E7EBF05FE3CD664BC7FC4E9A95CDE77AF
-:101C000069D2DF77616E7EFF4ADE4392F78C2E0940
-:101C1000DE9F5A7F31F7A74E9A60BD71BDEFB329A1
-:101C2000ED7FA0F7B01A7CAC2B8AF0A0BFBF521D8D
-:101C3000C3DFF75BF6F217BB90AC16487B05956DDA
-:101C40005EF0FE3E4BE5FBFE770A3AFCBC8E0D1CB7
-:101C500008AC7C7D6767AC0B267B625A6030F2B7BC
-:101C6000CBE2CDC8423F7E7D43E6B244BCF769710A
-:101C70004F85FA47FCFC5EE562616FB28D4982CF09
-:101C8000D5C0D5506F4FCE25F47EC3A02CEE479C17
-:101C9000C80964E37B3ABE1CEEDF403D3ABF56BC48
-:101CA000F29A24AC7762EB3D032B006F167CBFCD1C
-:101CB0004929C3FB4FD742DFE39CF4AE1B53699F16
-:101CC000D64FFD61BD58D4EBAEB9A93C8ECEEFCD59
-:101CD000493C49F8F7C20B4C01ED5183959970FED0
-:101CE00097B0F50EE453891FF9FEE9B29779FC64C9
-:101CF00099D2D59880F9E7153AFFF6B995DFEBE967
-:101D0000ADE7369911D4F3D7CFD5BDCF23DF19FD79
-:101D1000B1E34053B3847C19C94686BEE35A25DA41
-:101D20004E524B5DF8DEDBB2242BBDDBB1EC8901FA
-:101D3000A44FD8DB77B0D07A6C7D02D1C7EA1C956E
-:101D4000E0BCA08DD1BB3B256DE9745E716A9B93AD
-:101D5000D2D833A9F4FDE8337FCCE5F287E3A1E4E0
-:101D6000BF520AE97CD07F0DA194F5F5AEB0CD4A03
-:101D7000F76897EDE57A69D94D2AC52799B81FEE1E
-:101D800011D3F1D89A289EE36191DF8FF5C8F763EC
-:101D900035D339DF8F95F0B508FC84BF277BD3DEC0
-:101DA000D1A9F41EAB784F76B6A8D729EE6D85BFC2
-:101DB0002B7B4FEC647A5776B65615F15D59A32FFD
-:101DC000CA8DF6AD29D3C6DF6BF086BF33DB65C4A1
-:101DD00075CFCCE7EFCCDE343BE45D04F8CF94FF65
-:101DE00015C969537EAFF7814C48DF168FBE7EB3AD
-:101DF000C4FF25EC9273BEE39B69A677DE8CF89E48
-:101E000033E4678A777CD18E43FBFC94C6DF95B3BD
-:101E10008877A63B596E2AF2FDC5BED3FCFFDBBB1B
-:101E2000CCE1EF2F87BFB77CD9E665BAFCF0D6FFCF
-:101E3000D0D5BFBC6DA5AE7C64608DAE7CF49E5FDA
-:101E4000EAF2633A1FD3D51FBBEF295DF9155DCFC9
-:101E5000EACA271C794997BFB2FB77BAFA579FD9CC
-:101E6000A1CB17B03FEAEA17593FD0E52739FEA1C9
-:101E7000AB7F4DEA415DF9B5AEE3BAF229434FEBD2
-:101E8000D763F4FE0DE57C89FBBF75EDA631D72F36
-:101E9000F0FDE75989067AAFE31F59C27F1174F745
-:101EA00057A9B707B26C945F93D4FC00D15D9BC275
-:101EB000DF1F0ED363C6E31E0DE371EC157EFF2B0F
-:101EC0000EEC3E63C878F19A151CC2603EA1D8A101
-:101ED000CB27795275F55366BB74E569DEA1BAF27A
-:101EE0008CF96E5D3EAB769CAE7EBF159A2E9FE35D
-:101EF0002BD6D51FD0E4D1E507B5CCD6D51FB2CEB1
-:101F0000AB2BBFC43F5F577ED9E65A5D7E78EB0AA4
-:101F10005DFDCBDB7CBAF29181265DF9E83D2DBAFF
-:101F2000FC98CE75BAFA63F7F975E557746DD695D6
-:101F30004F38D2AACB5FD9DDA6AB7FF599802E5F53
-:101F4000C0F6EAEA1759DFD7E52739FEA6AB7F4D81
-:101F5000EA015DF9B5AEA3BA7269B74C19FA95FEFC
-:101F6000BBB0634ADCFFD4B5F7158A77A55F52DCB6
-:101F70000D2E584F767FAEEF418046E1BB883E0F75
-:101F8000C57D9C78B00FE514DEBB76F27331A514E5
-:101F90003F4A243B8754910BCFE9801D108BDE55BF
-:101FA0004E0EDAC931417B2CF36CC839B9F3D963D1
-:101FB000D764339AC75DD9DEFCEC24F43FB64EA655
-:101FC00077C1996F35CE43BE73F76ED87BC832BDEB
-:101FD000D67A841943ECBFBD512D99A3CEE1BF5FE2
-:101FE0006B3DC1F09DE59E7E45BC4281F52D0BE920
-:101FF000FF01F0178C03196BA903BEC17DE13A07FD
-:10200000E51FAA4BA5FCC3752E4AD7D50DA5F4B183
-:102010003A3795AFAF1B47F927EB34CAFBEB8A2958
-:102020007DAACE43DF37D6CDA6FC33E01763BA19BD
-:10203000FC644C9F057F17CBB780FF8BF917EA7CB8
-:1020400094B6D635D1F797EA5A28BFBD6E1DE57F05
-:102050005BE7A7B4AD6E33A5BFAB6BA5F2F6BA369E
-:10206000CABF5E17A07CA06E0FE577D475527E576D
-:10207000DD3ECAEFAEEBA2744FDD114ADFAAEBA63C
-:10208000F2B7EBCE50FE9888B72ECF5674F7956412
-:102090005EBEC720EDBF6968BF23718C337DA9B3D5
-:1020A000DFC3ECE8707CC87182EF270C7EAA21C4E4
-:1020B0007FF26573FF4ABEC710FE8E0213F6A97C3D
-:1020C000F754BED75029E65525F8610CD2E750A247
-:1020D000CFB72FC65F90FEA02DC9DB42F49965F003
-:1020E000913F6CE3F7892F4FF23E983D06F70B2B9B
-:1020F00076D3780E37ED1B96580249B372E99D707E
-:102100008ACBF5355E8D38F7DD67F9EB4733D19E25
-:102110002EFE41A577B6DE35D967A3FFFF8CC0C37D
-:1021200033D9065DBA2DC9BB09E7F3ADBDF6360359
-:10213000CCFFDBAB963E73474ED04FBE1E5D4DF0DD
-:102140006FA6339789CE1532EDCD1CB49BC0B0C2BB
-:10215000FC2CE6A3745CA2F705ECE76630B831EF1F
-:102160001D6FC98EB4AEF079BD2AF0F56AB64197FD
-:102170001E48F2B621FCBEB56B34AF77AFB86630FF
-:10218000AE4BCEABBF7877641AEB7E12E7F7ED6B00
-:102190005F1D560604E12FFD71BAD78F726CA9221C
-:1021A000DEB5EBF58E009597DEA9907D3607FC191C
-:1021B000DC1F92EF069CAA35D13BF2F8CE00EE9FD1
-:1021C0009DAAFDCC86E40CF518EE6F34E0011D28C5
-:1021D0006FF829BF4F5F8AEF628CC2770BACBCDF10
-:1021E000BB15A2BBA4E41C7EFF19EC3DF29F12BB01
-:1021F000E99E1ED0C99F116E0BAF50E9DEF9BB06F8
-:10220000FF6085F6932BCC0ACCAF2A11E8A37FDFC1
-:1022100074B044DC1790DF81BE3E41B87DF9EAD846
-:10222000A1147F7FFD0A17C2ABC1C0EF0FF9DE52C8
-:10223000F9EF2E0911AD4E184E71466674BB315E32
-:102240005422EE9B74A86C45A4F7C4957E9C8EDE48
-:102250004DE5EFE73584EDB3FC53D0D53F05BD9593
-:10226000ECD84BEF082DD9C3DF3B64B95DC342DF27
-:102270009DE959CF8AB72E1918B28E9AB603FC7C05
-:1022800005EB1A167A9E3C5D8C2FE94835DBBD1BA9
-:102290006CA1F3EBA16BD60FE9271EE87A00D1F50C
-:1022A00061DC579C6671C5CD82B40B4084EFFB782E
-:1022B0007FEDA0F341F29CD03CE6A1B40AC800E94E
-:1022C000D8E35B4BEFB92EC45F62C5F778C6CDCDBE
-:1022D000C67C0DEB9E980A70BBA9A9FE4D7C0EEF43
-:1022E0008696B59330BE3AC35FF626A6D3372A87C3
-:1022F000D14F05BE88EF87F110A576151EC9BC65C4
-:102300004BC12ADC7A99A6727CB03F727C00DD68F2
-:10231000AAB3F73A810FD2F83A345A871A5BACE382
-:1023200083D2954C531283E7DD7BF862DCA24F70B9
-:102330004B8D19BB69DFBCE6758B13F1BC9071BD89
-:102340001D8C67487DCD88CE17B16837D63B26E80F
-:10235000FA581623BA3EA630BAA72EED4896ED4D90
-:102360001D3520A8778F19FC79B103482FBB71BDAB
-:10237000BB536F70611C6C51A295DE3F3D16EFCFD1
-:102380000E7BE783DE239271AC074C3CAE143E2FEC
-:1023900065DC6EFE7B1866E6C3FD09FCFDE33CE4EC
-:1023A000677C3747A177A0BB90EF4D851E57A4FEF1
-:1023B0001B45BF7BBEE7FEAE0FD683F71B7B8DE3CD
-:1023C00010E344F371A4FEE8F9BDE564A61B6F7A3F
-:1023D0003FCECFEFDA359A7FBD219EE44D9AD5EB03
-:1023E000417CC9B88EF403F7E47C3E90FCF5EF1A0B
-:1023F00032D13EA77708D0FEBE8ACBA5774D2E7A84
-:1024000077F7DD821C8ADF4B797BFD381EFFBA5ED1
-:10241000C6BBF2C3E25D61F116961F39FEC598DBBB
-:1024200084E35EC23E92F0A138CB8E7C23E15DFE58
-:10243000BED20EE17F9E2A4ECC453AFF5D3F5577D6
-:10244000AE40A66B447CB439ECBDEB35B9CB1C78FF
-:102450001EC0F23CDFEFBDBF307A7EE839F42707BB
-:10246000F1F329EEC1059B114EC36CFE4252CB9A8B
-:10247000D185F356C43A2E73009C0D686F7A449C44
-:10248000D36DE5F1A589A497257E2F542F3F6BF4DA
-:10249000AF8CC67526F2DF19B0AFB392DC545BB5D2
-:1024A000001E89FE72D08C5548B7CCE8198AE374B7
-:1024B000E445331BD4FFB6C34CF1A7D70DE5BFC627
-:1024C000F3EADD7FB3303CDFD06ACF30A271DBFAB4
-:1024D0003DFF5DAB56FB84C9FCDD491683EF638E7F
-:1024E00074B0A75F44E4887B61AD0ADBC31F69D584
-:1024F00062F07DB756033B7D35CCEB25DBA8072F7B
-:102500002712F3A8B8CE67077AD7E13CF2582DE539
-:10251000EF377BE66F8071EF775A892E0A077A1EB4
-:10252000E7F364ABA6C2FCAE2A52E8F7D65689DFC1
-:1025300077B0BBA375EFEC7ACE0C263DF14C3FAEE5
-:10254000571B53B54EBCD0D127DC1CC66EDDFB58E3
-:102550002C93E272128EA1F872E4E9F0E53585E27F
-:10256000ABE7776B24BEF8EFD65C28BEEAFA319A67
-:10257000AFA4475FA16BEDC45CAEBF1AA89623174A
-:10258000FBDF119D312CF47701243D4AFA8C4097F2
-:102590004B77A2DCCD323830FE79CFD468D263924B
-:1025A0004E257D7E9CD343A743FA631CDEE69984C7
-:1025B000B2229C4E31BE154A8FA57DD22D7384F276
-:1025C000E534B013E29C68D71CD9D81A428FA5B560
-:1025D0005F19B99C387B75745E301E372D5F619F23
-:1025E00086E215FEFB74A8581FD93546F2A724FCD5
-:1025F0002E14CEA61BEB87A29DB61AEF0D02BC9A35
-:1026000014B79602FD196B0FDC81DF57897BBBBEC7
-:1026100061666E3F09FE90FD7D39A8F038D2A37D3A
-:10262000EC89984AA8F76DB2C185C059E52A7F9117
-:10263000F86D5F0CBD37119BD039FF69E29F210C0B
-:10264000F7F3BE5DE0ED87FBEAF7029E3EA5FB399E
-:10265000FE14FEEE61570A7F5FD625DEA1F7A6F2D3
-:10266000EF4C94FB297F474E7FE15768A27E17D538
-:10267000BFD7DC628DC67172AC8EA742E8FC6A11CE
-:102680001FFF1FC180237D00800000001F8B0800FA
-:1026900000000000000BED7D0D7854D5B5E83E3309
-:1026A000677E330927C9240CF98133C92484640265
-:1026B000930410446512020D083AFCD520890C8A57
-:1026C000DEA82493426CA3D77733908001EC2DA22F
-:1026D000B568793AD042F1AF3728A5A18D74127E42
-:1026E0002E5A2A83D5165BB581FAACB60582785B83
-:1026F000BC9796BBD6DAE764E64C2680F6BEBEEF02
-:10270000DDF7E65EBBB3CFDE67FFACBDFED7DA8791
-:102710001C59C7580663EC52BB3C3F99B11C59A0E9
-:10272000FAE36D5B7D1FB818DBD016A2327D6E8890
-:10273000F94B19B31605E520F433AF65FE2E1B6384
-:1027400097F1373D5A3EE014199B04ED7D4F311946
-:10275000FAA5BB3C821FFAD9E7C278458C7E97E187
-:10276000BF5B180B8E28877E3B98974D646C9D6CE1
-:102770000D0585A1E3DD925175544C19FA7CB0FD2D
-:1027800006819D3647C7C5DF69751E3D8CFF57BD65
-:10279000BFCB8D35878E6532D6827D65C6AAF3E0C4
-:1027A0000F9CB7D5B8DD04F34E965369DF9FDAABC3
-:1027B0004630F7F0F33DD3060B2F642CD466A67297
-:1027C000479BC48246C6BEDBE6A0FAAE3699CADD98
-:1027D0006D45543EDFE6A1F617DBA650FDFB6D5EAE
-:1027E000AA77B5D550FDE5361FD5F7B6D5527D5F32
-:1027F0009B9FCAEEB6062A7FD4D64CED3D6DAD54F4
-:102800009F6E62CDB49FA2A063019C47E78346AF51
-:102810000CF06954CEF1A0372FDD6367CC52A4636E
-:1028200026E86639B685E17E2C0E9D3704E7B0DEDA
-:10283000B185DD05A5617272A73002F6FF92AD5336
-:102840009800EDE2E34C86E7CF08C106E6616C91A3
-:102850003CD6278E62CCE5F84A551AD46F974B3791
-:102860009B9D8C15CAF36BD7C4D4E5E4F2FBF64804
-:10287000D1FA18F776D10AEDCB421336DB05BE0E3E
-:1028800096C5D8BD72B96F0DE051388F0511EE03B2
-:102890004E636807B4AFC0F31271FD12ADFF66D688
-:1028A000EED0C1FAC7C8C6722650FF30B35F7BFFB7
-:1028B0004659A6E7F1EF5DA99F6EE235F563FA2B65
-:1028C0008C87EDC215C6310B0BCD1158FB2603FCCE
-:1028D0000F3C0F66D8423B015E9D06B6CC0770EFF9
-:1028E000B4F0F28893D3DFB3CEAAF14EA0A3F14E99
-:1028F0007EAE9D96A05485F397EA3C3B109D5B9D70
-:102900003FCF83F9BEFABAC836CA51FCEC403C80CE
-:10291000F70AC6247B711EF68FE65001CCF3A53171
-:102920002F75A441BDE03B1E8F1EFA6F621E2BE285
-:1029300049F0511DDB09F51726E6A7CD87EE259353
-:102940007E90E6077C398D7C00C609315683F8B647
-:1029500066DD3D63FAA1FCD309FF1809D6F9B83248
-:10296000CF7643A499CE73928DE1BE19DB9CA473FC
-:10297000407F071CD2758CE946F1D268906EC77E05
-:10298000C675461684F518FF729DD907E3B55F3406
-:10299000D5201F612C92A49B02CF2D7E29159E6FFE
-:1029A0000EEA882FB4CBB69000E36EB2951F95A1C6
-:1029B0001E94749E0284A35B4770ECB07D39A4879B
-:1029C000F144614D03CB87F54A2F9B9DF03CE4D643
-:1029D0004948E721EF821AAC07FDA2A74056180428
-:1029E000B6FBD3421B715C36F0D309D85EC73C08F6
-:1029F000877599FFDE9704F5F6C59247CF7BCBE24A
-:102A000064C646E15F3065BBA17F6D12AE6309EF1E
-:102A10000F7F79E6031DA698F8F97DA377B6945742
-:102A20008ACFC5603FE74BC2652044D1E0317BA02F
-:102A30007DBCADBCC60BA5985C6E96619F1D52B95E
-:102A40007939ED9FD918CC93CE387F6A97743521A8
-:102A5000A5FD2EA477911D724D2652A2F60EDB968F
-:102A60005E84877837634E19D707F3A97C0FE0613E
-:102A7000CEBFE1A80CFBE8BC278DF6210A1EAAB345
-:102A8000BB455A77966C0DB3F1708EC6794719F035
-:102A90008F2CF3FD73B13EAA41FCA03F864F8FF40B
-:102AA0006BEB19B5DA7A3A83BA393AEF6F14F91148
-:102AB0000FB778788C923A4EE0FA47F9457A18BF0A
-:102AC000FEA7A427522B19AED346EBCCB4DD59098F
-:102AD0001082A17D6B10FFFED6758E9716989D30E3
-:102AE000FF78BB0EC1C926B081B538EE2605DF3BA5
-:102AF0009DFC3CA374A557E97224D2E598561D0BA2
-:102B0000C6C81D67D0CA8231F3E577A669EA059B7E
-:102B1000B334FDC76ECDD3B48F0B156BDA4B7697FC
-:102B20006BEAA55DD76BFA4FE8AED2D4CBC2733453
-:102B3000FD2B8E2ED0D427456ED7F4BFEEE49D9AA0
-:102B4000F6A9FDF769DAA77DB44A53BF71E0214DBC
-:102B50007F20E386AE04723255E1571D0E6FC49B91
-:102B6000409EAB2593C481C1F300DE69720066C745
-:102B7000CC97ECB1021247EBA099481F2629759219
-:102B8000EBEDF25AC4E71423E1B388F21CEAAB1E62
-:102B900034864C88FF377964E42F2627E763FB0AE5
-:102BA000BDA39DB0AECA1433C905D1C6FB89B659C1
-:102BB000A4A78CDE0A7CA902EA121B6C4F42FEDC41
-:102BC00016F4B95CD1755BA4CD0CE9B732A586F5D6
-:102BD000DBA2EF8B9297F993713E99EB3F5290FAFB
-:102BE0005964783F665F07743A66433EDE0B7202B3
-:102BF000C6EF4ACE1691FEBAFE525C4D65F2B4594C
-:102C000088EF6512FBCEBF40FF2E811D65A02775A2
-:102C1000E9D885E9B0EF976DE58F83B806D6E8D39C
-:102C200023BF9BCC9AA91CAD63562CB70BFDAB19E7
-:102C3000F473379FA81A09FD9E77F9BDB8EFAF83EB
-:102C40000E81FBFAFA78AE67ADCB9C23A35ED6E982
-:102C5000EC3A9A87EBC900B9828420FA3CA857A8BD
-:102C6000FBBD4F394F31AFB31FE5DFAA54B38CFA28
-:102C70009268DEECFB00E0F58CA1FFB976A877083E
-:102C8000D2CA2EE48B0FDA3C3B19EA8F1C6E72B26B
-:102C9000AE622D8CDBB5C62BA6427BD706E6E9409B
-:102CA000FAB057AE4D85E70539CB7569480FAE359B
-:102CB0006BB1AC73E611FCC6B9B7EBD2A1BD6462CF
-:102CC000652D43D92BC17CE9C3E3933E652BC3FD3E
-:102CD0003097F821E2954E063E034BAF4C83F386C6
-:102CE000792D78DE02950407CB455BC8827517877E
-:102CF0008BC52B8492A06E777905AF1BDFDB4AE78B
-:102D00006B096BF5D82A97FF3EA47FFB5CEDB98A6F
-:102D1000E627687D9B749C2E3A53E563289F3B9D74
-:102D2000AEB47639BA4E95AF3CA0E86BEA7395AF76
-:102D3000FC0ECF2023AADF009E6FD5E5A37EB699B7
-:102D4000217FB23CBC99215E5BA4A0CC500FFFA7B1
-:102D500020E1B9AADFAE5668A63AAFD68CF2FA8265
-:102D6000BD9CF4594BEB2E3AAF78B859FA75CC7B31
-:102D700005B8A6143E4DF21D18B05C00F0E9CBB4C6
-:102D8000356C4FA0F78F50F4850D40C61192573E19
-:102D900033F26B831EF455926FB06190071724468F
-:102DA000F28B7539A9BE3A95D7D5715667948FBC09
-:102DB00092FE6DD96A66FE987D6C8079102EEB2E9E
-:102DC000CDAF41B8329188836DFA8B7BFB46A02F43
-:102DD000D5AE19A1E82B39383794A38D8CEC028F2E
-:102DE0007D6E0DD29DEF621E09DF83CE346AF7043B
-:102DF00099BE99D66D50E592EEF2045AAB6C54E54B
-:102E000030A9B65C6EC1FFF75E1690EFC7C8315EA1
-:102E1000905C57E576C1666DFBD8ADDAFAB8D09014
-:102E2000F7DF42B9BF98FF0D7241DBFEB422BF1736
-:102E3000A3FC86922D3290DC33C38A2E73B91B9586
-:102E400083C01772BBC295C846735A62E421A37D42
-:102E500068E463954B26FCF31D150D788EBE8B60E0
-:102E60007C540CE5CBA34D1CDE7DC6E4D05A78EF34
-:102E700051B08BFCD0753DD8437E20B5AF8B9E5FA3
-:102E8000D6A19D7554EF018C1D3CA7F873F5E4A9FC
-:102E90007AAFEF2DA403C6FA2B7CC97C3E7FCC7C95
-:102EA0007DD694F10CEC965D85FE5F61BF4F6AECB8
-:102EB00013913F98729801E913E767CAFCCC88FA2E
-:102EC000333FEF4D9E379B0FC23A1E396942759CC6
-:102ED000CDD41F3BDA06F555B922F133E9BA95CFC7
-:102EE0005A810F54FD1ADAE19D47647924E9E947D4
-:102EF0000D0CF5F42A058FAB14FBEB9902038DFB47
-:102F000089225FCE3A55BD276845FD172C022BEA72
-:102F1000B325BB81176BCF3389B77B49DF2DED8A92
-:102F20006FF732A4E362055FA06EAB847A9952EF2B
-:102F30006242BA04E738A1B6BF0F4D09F76B87ADFF
-:102F400088877B2C5C7F7B5EC1874C2678C2B0FE75
-:102F5000CCDD364F08FA25EBD99E08ECC373483C0C
-:102F60001D7BEEE37BB475378BA93B711DDAFAA3A9
-:102F700072B3807079B40E7474D8B2352FD9FE61F3
-:102F800009439817227ECDD4DBCAD09E5A55696377
-:102F90000857D3A9B1DF8A20FF38A1672817A424D6
-:102FA000F9B16A785FFA69BA678D1C3DFFE7DB907B
-:102FB0007533F6E4650FEB009EFCF52A6B03EABF60
-:102FC0002FC279A21CF93ED8D9D8DE05E78AF59739
-:102FD000C1CEC6722FD8D9F87C1FD8D958EF063B7E
-:102FE0001BCB1F819D8DCF7BC0CEC6BAA7B072749C
-:102FF0001E9C4FBDCD375340B87A455902BA12A234
-:1030000070661F1661BD5FB80C045227B17E13C0F5
-:10301000F5F81899CED7C47C0CE52BF37BCC8897B8
-:10302000571FC7AB8EE337241A670A8C4376825941
-:1030300042BF481EBC31029E9F79F057BB505ECC08
-:1030400013FC1E5C6FE3A4D346AE3F0F18B1FF36EE
-:103050000BE03FF0A11C850E8255004F94BBAFEBF7
-:103060003DEDD0EBA619A7566780FD5D95E79C2F37
-:103070004E85FAFDA72A4643BD73C7A6F968CFDF80
-:10308000F4BD53AF64030F3E9B378FB73F7EEA42D8
-:103090000EB48F605F9B5F0DED29E95C3E6D1358A8
-:1030A0006DAC7E776B1EC7F340EB169273C0DF19D1
-:1030B000C2A13DD347F2F19C7D206539F40F640C29
-:1030C00064DE7905FE1D687D92E4507BCAEF49FFFE
-:1030D000681F94171E9217EABCAABCF844C13D555C
-:1030E0005EACB2F0EA603F7F3E3D7F5CF1EBB050FA
-:1030F00001D5D32DBCFECF55F271B47B003E64E701
-:103100001E4C29FEC60D6857D6881E13D41FB795CE
-:103110005B50DEFCA3C27F60DC20DAF1C199E6D00F
-:103120004E3C54BB4CF498A68E6F77A1D2C5D29476
-:10313000751CBADE1A463BBFBDDABC03F5C92DB615
-:103140003C1AAF7D8A3188FE15B5BEF6FAEBCDA8E4
-:103150004FA4A6A439B1AEF2A78D80F758C24F8F05
-:10316000E35629DBAD32DBC27AE4E766C31F63F5C1
-:10317000641B8B10FE7874609000BD19F3395E55A6
-:10318000304F2D3E370ACD4144C66DB876DC47B28C
-:1031900091FC0C8C65F375ABFBF066F37DA9FB48E5
-:1031A0003606957D909EB4C5A60BA3BEB705F685E1
-:1031B000E305F264824FFCBEE0E7C371674C51D671
-:1031C0002DDDB017D73153E7EDC0F70E7F566707F7
-:1031D000F462B358B388CFF3C1A2FDD04CA2B3E3DD
-:1031E000F215F40E14E41FC6C8AD9B7E2BD07ED81A
-:1031F000FD463A97CD057CDF4F1B434E46066E6871
-:10320000D482E4E1F1F78521F8EB65484FED695E82
-:103210008EBFD240CA1AC4DFD481CCB5B4AF70C25D
-:10322000F388C7E3F8F3D907FF2972408FF0BDDABE
-:1032300079AAE7A8E241BCFC32E64BEAF93A689F7A
-:10324000DE224E07AA1EC5C0CE491E0ABFF5309E1B
-:103250005C18AD1B1D3ED28F0D764F11FA6FDBFF50
-:10326000AA6F48E4BFFD5081D39A142BE9CDED2914
-:103270005C6FEE4D99A3B177AAC1FE11003FF4E94E
-:10328000AC0BE9483FE276F27FE947A28684EB8AFD
-:10329000D34747CCE5FAA804FA688279D552447D31
-:1032A00034819E3AA88FA6CDE1FA688A91F4D16D57
-:1032B000C9C6DAED09F8CD813CAE5FF7E23E12D81F
-:1032C0007B60E7911F52B5F38C929FEC35759F0799
-:1032D000147C57FB9BA466867E31BDD123A3BEA977
-:1032E000B772FDD104DB2C8A91DFEAFCFBF30CF40E
-:1032F000FEB70BB91EAF3373FDE4A6E3427322B8E9
-:10330000FF5981FB7078F737E00DF185729BD18B07
-:10331000FA41B9CD5185FAC170EF81A919FC282D68
-:10332000CA573C7F9DAC27F9237A1C88675D86FECF
-:10333000578EA31D77D846F246D59BC14EF57AE04D
-:10334000E53DFF0114A81B6A9F82DD24E5C3787D5B
-:10335000AB3227F2F140BF2B1DAA4FC6FB0106E995
-:103360003C659793BF171A85EF09ABA68C447C8AFE
-:10337000A773B5CC75BC9EBB02D6953BEA2895EAEF
-:10338000F3FFC9F4E4578BEF3F365F853F97C7E300
-:1033900060B2117A92C36371DD675ADECCF4C05219
-:1033A0009AC4F3248F3F699E32E21199F3D9DD2844
-:1033B0005FBE22129FCDB9B737352DE67C9F6EEBED
-:1033C000CE155D182F88E456BBC80EF0265AEF4282
-:1033D00075FEF018E2CB06E5FC657B64F65880B715
-:1033E0006CD379D0150D425743FF95626AB504F34B
-:1033F000E7B6318F0DEA4E26911F2BF7B29EF02CC7
-:10340000F7E012C2DF31F60121E88E990759704CBE
-:103410003CE4D3E66AA2CBDC9183F61BC50D3EB536
-:1034200087E7235D7FFA045F51EE77B4ED205BC937
-:10343000CF7C4F8B358426E09887251DD6739F154A
-:10344000588E13D771D0F908FA697E98447E1AFD18
-:103450005617F9599E15FCD3F2812ECE84E4AFA203
-:103460007D4B3FE8D7F835EB8E8D24BF22B3497EE4
-:103470003DA0633B13F8916ECFE7F6DCD27C4E5F44
-:10348000B98E3772575460798CCEFB5AE9A813F97C
-:10349000358CF3C888CD14E70A56B122B4FB3A0D37
-:1034A000805709E8F45FF3957899CA8715F859D0E1
-:1034B0004A817DE80545BFDBFDFCF3CF67A2BC6612
-:1034C000A8DC0DD29B3A4E525117352679BC0CFD23
-:1034D0000D82E4E5FC550A3A8218D7F98B3E215E4D
-:1034E0003FA99CDF1AE77A07F6AF76791C4807BD3B
-:1034F000CEC98E3B017E369B919962F8AF8A2787B1
-:10350000922793FEA18EB32A39EF8A76B611F8B0CE
-:103510007C05F96C447F37EA317D53CD32AC77BD01
-:10352000AD3C827AD67A9BBD9CFCE636E017317EB4
-:10353000249BED08E1A1CDC3FD6B36E4BBE8475207
-:10354000F6DFEB3C42FB57FBAD52F88FCD13E67133
-:1035500047B062B09F45F405D1BEB0D819D99316D3
-:1035600033A7A724380E730C1F51E7BD3F9FDB69BB
-:10357000EB73CA2395B43E113D016CBDA3DC4172CF
-:1035800010E18C7AE8A8413D94FC25CF297056C7FC
-:1035900069EFE5FBF4B53ABCD5E9687FFA9E45BE14
-:1035A000B0DE76A73988F22079E215C77B255FD097
-:1035B000F87BA2E3B5CE50C67B0EC7D327974B3816
-:1035C0009E01F94402FC0B2BEBFAA2FE3080A844CA
-:1035D000F61AE37A1560BC2391FEA09666C5AF3556
-:1035E000F43DCE279D8ADD027CF218AEBF31E7F4B0
-:1035F000914AEAC5ED95B4D9629108E7F5099CA016
-:103600005E88DAEFF17A4CA57E80E4992A8754B976
-:10361000F434EA31C6283DA97E97EC061FC96BC178
-:10362000EE23BC01BD4646BAD163BC3701DC24178A
-:10363000879B903245467AA9BED49F4D723EF9A32E
-:103640006C16E33F53F9E1A1CF7659B0FDD386AABA
-:103650002BEA2B6A3C78B83870CA43BFFF4AACBE2D
-:10366000325C5CF86AF1E0BE1423F9DD9E11B47C93
-:10367000C9EAE2FCC8E052FD27FEBFE0393C23F86E
-:103680003CA42F2A7E947D857EE642BF57A79105F4
-:10369000E13C0F7C36D981F871ADF055FDE6598AD1
-:1036A0001E9565DB25209D66358404F47B673774A1
-:1036B00009DE2BF47B07E93923DADFA08C3F5D1CA0
-:1036C000D0A3BC9AAED071F6459115C5E87F6FE5E1
-:1036D000733DCAA0E8ED297DCF5970BC3E9DAFB3C4
-:1036E00010E5438A4EDE1943EF867BCBCD5531F092
-:1036F00069C7784E82F32B770DEA5B6417A9F2D67F
-:10370000A0CA09BBA8911381248EB7AABE13B89E84
-:10371000DB4182E02F41B89EBBFEF7B7E016CF0930
-:103720006183DD79F578C6A05EA30B2D57ED17A454
-:10373000972E83DCDD4FFA558A07FD00AA5E55F609
-:103740003D211FFB79042FD1C924E6A7F23AC6F523
-:1037500040D0AF6E7091BE075B89397786AE88CC5A
-:10376000ABEFAF00FDE018271023E44FFDFA2581F1
-:10377000F87B3CDCDA06E13618CFD3F845B315798F
-:1037800097ADB4CBE81775627C4AEBB7AC38AAADFD
-:103790004F8A68EBD79D8CF38306BD6FBB3279FCF3
-:1037A0001F07DD06F4867C628512B7CC09862A25C0
-:1037B000586F2EEBA2F86076439A06DE37E995BC87
-:1037C00009E61598BA4EF8658BF33EC6F75B5C8345
-:1037D000FE3BD2BFEE51DAFFA17AC5573BD096DE51
-:1037E0006C20FFA819264778FDC3EC0533F1BC8790
-:1037F000F8579BB57ED5ECD87680C33DDB0C9A7626
-:103800009FB78CEC82858ADF7670BFB88E0CBEDFE6
-:10381000ECF2A1F35F7D5EF82F6DE8FCEAB84F0390
-:103820001F42FECA2EC1B94E46B831F440B05C31D9
-:103830002C609C3AAB9979514FCE6E61DE44FEFE0E
-:103840005D0ABCE2E1CC82D3097E33946759363DF0
-:10385000D9ED592D3AD20FB3804F207FB86525900E
-:1038600011D4B357CAA45FDEDAA063281FD8A536E7
-:10387000CDFBB05CF27FAAE7FE348E87FA65230B9E
-:10388000E9703FCDC54467B4AEBC283E00BC4E7362
-:103890007899095EB74E3168FC9CB9E8D78C818B6A
-:1038A0008A07D971CFBFE492347401726E978BF09E
-:1038B00084CBBF02947FB0A433534FEEEA82F5DD90
-:1038C000B496D17E0752AD219E0F31183FD05F1EB6
-:1038D0000B7CCB3CA308FD2C9B24AB0EF3160EA453
-:1038E000F67F9BA532D60D6A71750E633FB10E94BB
-:1038F00008503FE46AD8D27923B45B065E40E7AF54
-:10390000CD16585013534F49695F5083873685C988
-:1039100022C0C78A33C03EADD29CDD7A98DFEAB6BA
-:103920009153D2CA06E994F6D371BDFC28E67D74A2
-:1039300014E8487F62B1EDB08FB20249A1036F1164
-:10394000F18F1A1EC78F1D5FB45F61FC3930FEC452
-:10395000CF31BE99AF3F131F81DCC9C4F5A3DF1A75
-:10396000C7C7F345E751ECFCCA78220B6EC7780B4A
-:10397000CC6713F87C12E69564326D1EC1E07C12B0
-:10398000CC57FA77D84FEDD0F3305CE93C6EFF7C32
-:10399000E7D1A1F3D27A83E36D64173168D64D463F
-:1039A000FB83CF6711D921B19CC3B5637214AEA05C
-:1039B00007D2B8D07DCD6505CE0684B36424380F18
-:1039C00007B73E89E7356D90ACA135CEFF03E7E53B
-:1039D000E0E7153B1FEA93D73CDFED309FFDDAE7C8
-:1039E00043F822FD0CC217CE646DE6B5C317561519
-:1039F000BC16F8F6C1B8BA18B846F3879E92D02E16
-:103A0000B0187C660FF0DF9B0A5249DEBAED0BCC92
-:103A1000944F90B1C08C797AEBDCB61ACCE75BE7B7
-:103A20005A6436C4C8E975EE3A6A87FE94F7E40E24
-:103A30005BD16DC14A5984FC021B6EA8762C47FCF1
-:103A400069E679546A5E912A0F9912AFA47DC18B01
-:103A5000236EDC3BD007FD37344FA4BCB111A9FF66
-:103A60004EF9529B1A3C1E6CFFB685C71D9F54E24F
-:103A70004E88A8E4571B7FFD7730FE5A5EB04AA0FF
-:103A800078E3CA2BC71BCBCF47AA30EF8A2DE77943
-:103A9000558E3A314E1E6AE97613C295E73F85048A
-:103AA0000E5FCD782D05193C1EEDDAC1D0EE7B05F9
-:103AB000C6D26BE94B877948F1F4281ABD5225EA42
-:103AC000EBAB74B48E6C0CED83882B2F9DEB580EF2
-:103AD000CF73EE163D023C1FE97E98F29140DB2742
-:103AE0007DC3ED3E5685F521FB5CA1DD47FCBEE2C2
-:103AF000D70D828BD6AD9E57F9794F12DA57E5056F
-:103B00000B285F8C7E2ABDEBE3F6938E76B1CE6BED
-:103B1000198F7641CCBE98A69F62BFFDD7D6EF44E1
-:103B20006442BD303E1EF64F3E5AA78979CC467A94
-:103B3000AF8EEC4835CE9685B483E73E9AF1384592
-:103B4000FCFB93F9FBCCC1E36E262B98A4407FC20B
-:103B50007D56F2679A4C5087F3118CCC3C0A9E3FFD
-:103B6000ADF803D7084CC47A74BE30C3F9DA05DF68
-:103B7000668F134B6E4719527D946F8861DB587BBB
-:103B8000B40FF338A07DD5BDCE91E8CF1B01041151
-:103B9000417B5A8953A9FE9394FCFEA528BF5F2C54
-:103BA000F8688119E5333A9CAE676CFFCED35B822F
-:103BB0003951BA345DCC62728C5D63129B299FC30C
-:103BC0007471B4C6CF1256EC31B5EEB58BD5385FF3
-:103BD00004ED05CC5F625207BE5709409163FDA614
-:103BE000171D9A71A2E3E768E60D835D1D1B171888
-:103BF0007EFC242617C58E9F37CCF88571E34B09D0
-:103C0000C78F8E9BAE19779DC8F945D06E0D25F2F2
-:103C1000F39D2DA87A1B4979B87CB33305DC0F08D6
-:103C2000FC58A4389482378F389A29FF4C6FE5F1FD
-:103C30005283123F3998DCC0F32472B4F967554CB3
-:103C400012B17D5DCAACA302B457D9B47AFAF44B71
-:103C5000A7F5C877A68B5A3DDDCB9A093F6F62DA8C
-:103C6000E7861C2D1FD8A8D0872E796284F2D43223
-:103C70006C9477309C5FE1DD3646F95386245F33E0
-:103C8000CA3863E1A5B4750EA88FE0F8652F4C5DC6
-:103C9000887EA277153C5E07748F70AC5B3572BB73
-:103CA0003E66DC3A63B800E5489D8EE7EBD30FE64D
-:103CB0007F37238BFCACF1F352C66F8CDFABBE5960
-:103CC000F0B962F6F1AE421783F3ADCEDE8E7AEC38
-:103CD000E07CA6F0249A6F30EF47992FF38BCDF755
-:103CE0009E42CFEA7CF55FD5EEAFDE18A1FDD5EBA5
-:103CF0009892E7CFE77B0FF7E7FC02F329F95B83A4
-:103D0000F37D4DBBBF7A5384F6573F684F2AF36566
-:103D10007EB1F94CC6668ACF3C26F0739DBB6BD44E
-:103D2000E3E8A7BF3077958CF8A6DA67B7E00B8099
-:103D300067B728F94DB7E618496F50C7DDDD3685FE
-:103D4000798DDC9F8365D10D02E5FB8F9B22783155
-:103D50003EB60DE8DE5B88FE2A89DA436D0E2A77CF
-:103D6000B4C9547E17EC412FF9AD3C54FF1F85DCDC
-:103D7000CE7F6C94B46405EA0B95569EEF7CC334F9
-:103D8000D044A3F61618607D16CC2BFC322BDB0832
-:103D9000B5C2AD1C1EF6EACC109E93B5EC50A40D36
-:103DA000EAA6A97A19F3B84D4EE64BE48F692DE4E3
-:103DB0007E9E47D4FCF81B051E7F077DA412F6BF2C
-:103DC0004C0135D3CF1550AFBAF56BA9A48FD42DC4
-:103DD000EA4F96601D7708656FBB001EBF51F491D6
-:103DE00065A3391DC7DB9376942C13317F4F1F0ACF
-:103DF000C19F0B9317923DBA70316369F0FEADF825
-:103E00001EC895E38A3EF346BF89A1BD16ACE67194
-:103E1000E73B1ED6DA918F59C212EA718F95D919F4
-:103E20009E475D8BB6FD11258EB030CEAEBC352ED3
-:103E3000AF06B44C9E1F827B9ECAD80385DABC9A1B
-:103E40008A4299F3B91C3B2555A7CD768DC078A43D
-:103E5000C998F81E8E3ADE33AA5CB67B090E6A1E3C
-:103E60001AD3BF5846EF2BF3A9EF3D2DBC38EA4AD1
-:103E7000FE4ED0DB3EEC2FE2F219F5EB8D71EBBC80
-:103E80003037EF1BD52C11DE0E88E85750D7FFBF17
-:103E90000B5FABD1A70178747CC6A713290EC37240
-:103EA00068DFB7A8F8A3E4572D1CAC8B4C8CC9AFC6
-:103EB000638E01379EF75B3726793612FE29FA4367
-:103EC000F81DDDE5A4CF3FDEE03A1CDE5CEE8FABF3
-:103ED00096283F48196F3838C7E73FA87E1BFAC5B8
-:103EE000E41FB66FE7F98F59F6AA8FF19E143E3F93
-:103EF000ADC12BED7DA8F6DEE704B42FBE8DF7BB78
-:103F0000C4E87CE8BF0D92FEAABDA715BF2EF5FE42
-:103F10008DBA9E76232B227B5407FC01E69B67EB30
-:103F2000170519FDF10322C5CBC7723F11E608F34F
-:103F30007B2F5CCFD367EB783EC71899EB7DAE81C2
-:103F4000D1B1F1A28F0AB95C9F97F4668B0CF2EFA6
-:103F5000FDC2C042CC579A37E2CD1627D44F153652
-:103F60002FC47CA679D96F7EEA049DEDB7855FE109
-:103F7000F592373FCD83FAFF2A5CC5EBD31801E5F4
-:103F80007785AB17225FFDA85052FC97911C9C6F60
-:103F90009EC0F1E58B967A932E613CFF7CA1EA4F9F
-:103FA00064069CC7D7F3AF27911FF954FFAB571B8B
-:103FB0008764D89489F786949F3D85F49939F837BA
-:103FC000C0F36631DC8BEFEBCC6182EB58CCA329DC
-:103FD000221478E2F215F225E2F14800746D457D75
-:103FE0005996581DE8C7EDADCC6FC98FC173E65522
-:103FF000F09CE7F5A8EB51E71FB22E3852312D7631
-:104000005DDB681C755DE7CA4C41BC5FA6C655D533
-:10401000759D13069E4167C49C929D8BF15CCF25D4
-:104020000F8C16A0FEFCD8B7E99CCF650C3C23781A
-:1040300062EA067E8E23C73E4A7A4F8BE01D391610
-:10404000F9A5D146F7D83A153D6F53863FC8B87EDB
-:104050004FF98FC15C7E3FA07AA2E08D8DFB3BC7FC
-:10406000F2B8494829679A36379F007C0CEC15D87E
-:104070001AE81FB874C188F6F8BC9E5346B4BB9BBF
-:10408000F69E32A25DDD847518A7699B91F8553CB8
-:10409000BC778ED56BE2EBAA3D7138B7709D1DD60B
-:1040A000D3B442F060CAECAAFDA933B1BE6A39EEBE
-:1040B00092B1DB6FD83313D1A5DED7BB0ECB65AC85
-:1040C000FF30DE9F5BE2D7EAF94B1BB47A797DB310
-:1040D000569F5EB6194E07E4D7B2D66CCD7B0C3531
-:1040E0006458CF12E53C97381E8DE8C7633DE65E05
-:1040F0008E40644DFE9DA57C07506AFD16F37A0440
-:10410000A2E3A65A33F95F0FE7F27CFAC04A3DE515
-:104110000905101DB0DE2C28FE2C2FF147557ECF4F
-:10412000EC3E7F241BDF5F692038B0A037827EFD24
-:104130005A059F96D5D67C8C78562BDFC7E5F89824
-:104140005D06F2AFF8B93E2E2BFEEFBAEEC7AAD34A
-:1041500050FF6C11C8BFB1B441ABAFD7E31FA8BFCC
-:10416000B50AA1B013E1A46D5FD6AAADDF355691B3
-:104170006325AC04E9A461AC2012DD28F53FE6FE1E
-:10418000E28D304CF490E0BB7F2C1CD04A63783C2D
-:10419000CAB587043FD5D57678DEC4E50E97F73AE1
-:1041A000A028E2BB06EE5708360A848F4B87C8FF6B
-:1041B00018FD403FB4FECC582EDFDA2DBE16B29764
-:1041C0005E1524D447AA45AF98E68EDAB3F1F8F825
-:1041D000AC82DF6FB07E37AEAB10810EF02F5C3853
-:1041E0002284FEB0C29F2CA77CC7C20AC1A3237A37
-:1041F000D6B1D6722C45E20FA86F5AA02CD477D531
-:1042000012BF9E6094783EA183C5F201EF734CC04B
-:10421000BC3E5C3ACE7B73CED1CFF01C6FD9FAE8AE
-:1042200079E477AE7C6FF963B0BE4D163EFFA6FD14
-:1042300002E9AF4DEE23C41747029AE0BC4D0E854C
-:104240003F76037F54F70FE73D12F9155E1099EBA7
-:10425000A67947A9F10135DF365CA5BB0CE73752DB
-:10426000997767A94CFBCEBCAF4BC07DE7B2E01A93
-:10427000F413FDF3584670544BD58FBF381AC776E8
-:10428000E279363AFA8DA47F2B71EC04FD4A12F6DE
-:10429000F3328D1F61A6FE520AC69B57BD9A7FC599
-:1042A0007C0BBD59A7A1578364D5D0F5CD455A3AAB
-:1042B0009FE7D1D2F7AD53F235EDF3BD259AF685E0
-:1042C00035159AFA62DF344DFFDB6A6768ED7DC70A
-:1042D0001C4D7F8BBC40534F2ABA5DD33FD973A787
-:1042E00096DFD8BB28AFC0680EF6FB010E9D80ABF1
-:1042F00053D2A2FCBA24C58C49C7CC5A61B161D94A
-:1043000059660AE3B97566F138ABE9B5071C6184F3
-:10431000FA8817CD9550BE2084AA305E6456ECBC56
-:10432000E28799869F8F2DE178AE96EF8FF57F5CBF
-:1043300004A57BB79CCDF3A723C5783E66742022E5
-:104340001EEF3393DE31214EFFFD5E69E56F51AE06
-:10435000B81FF6CE26BF543793F0FEEC0E23CF7372
-:104360000AEEE3F9B4EEEE7E9D3786DE02455CDEB2
-:104370007FD35745794B4D3D20CD10BFB79E36A218
-:10438000DFAEA9A73705E5C678DF6923EAD7D1E70D
-:104390008A3C1107AC18BFFC97AEC4F969638A8CDC
-:1043A00034FE1185DFD63FC0F92D20DC5CB48F547C
-:1043B000FE59BF87EFAF7EB191E85BE5A3C03F3503
-:1043C000F1B078BEBCF486D03AA45DE0A31AFB65D8
-:1043D000D9A2591FA33DC45898F418E0A3DAF69C5B
-:1043E000F544DFCBE2EC9BE422E0A7A8479430F74A
-:1043F00065A097933E5DC27DB94BF8F7024EFA6710
-:1044000010BCBF097043BBF19B43E0C4E17735F8B2
-:10441000BCA4F813D5738AEF5756C2F9E84BC3F022
-:10442000CB078A78FB0E21528ECC2CE0B3129E2E45
-:10443000359B1763FEC191DC3FADC77842FD0F0489
-:10444000B465D9AF7B5FCBC47C04E39EC399982746
-:1044500011E83A9CC9004E2B0DF21AD48B010F3C87
-:104460006BE05C9ABAC3B4FEC6AE8A5E7CDED82D21
-:1044700078901506F69E9F45FB64FDEB518FDF316A
-:10448000CCBAA615717D785691CCF398FD3027CA29
-:10449000D9BD26B263EBF7001FC275ED17E85EC603
-:1044A0008E0DE6DA44FAC9648437C0E9D00623C326
-:1044B00038CA4A781FF77124F788D18C78B347201F
-:1044C0009B30D0756231FAE3032D0686715B757DF2
-:1044D000677223EFE3FEDF596160788FB07D058F4F
-:1044E000C7BED3A2A771F4771BA8BEE45E9E377C3B
-:1044F00070C56FD767C3B8EFAC1428DF7EC6DDFF89
-:104500007604EB4BEEE57A503CFE0EE26B1C7E2E01
-:10451000F16BF16E089E367C313CBD338AA7E351C6
-:10452000CEC2B9CF1C89F8F320A37B8CB5970E1AA5
-:1045300046C27AF3D64B1E0CED96EA43EB32912F2E
-:104540001CE4ED652BB70B9CBFC874BF3DBBD3C843
-:10455000D06E7C4039AF0794F392D98080F96E4CCD
-:104560008CE4E1FA9C4A7ED7CB0656BB07FD482275
-:10457000E72FA53F746C8FF523B914BEA2F2BD12CC
-:10458000B0F7F7901FBA2B0BEF9DBF64E0FEB1D1DF
-:10459000CA7805F903B3E643F9CD22CE07DB94755B
-:1045A000A875AF82FFCCBE83E03BCFCCE13EA73500
-:1045B0005C87FBB847F4AF2B82F6B9A37FB1925169
-:1045C0007EE4EB6E3FF9B98A49AE0594F33838F5CD
-:1045D00077DB56631EDE382B9DE3FCBEA72278AE48
-:1045E0004D2E91F20F2D051347FAAFE047085C946A
-:1045F00035F7F89A7ACECFF226A0EB69CA7A4B95B6
-:10460000FB7AAC87FB0F801F8B53CAA3FDD4FDAB95
-:104610007E0F4BC177E99C567F8595F17BFC8FD14E
-:10462000FE97AE3C21E03D95DB0C5E830DE0FC8BFC
-:10463000116C31DAC1AFB731BAB7760CEFAF012BDD
-:1046400079A34DA27A44B9C7F6669B4CE56D46DF67
-:104650006E84CFE243CD0508AF83B94FFAF0BB0CAF
-:10466000E78E29FA2C93F8BD4605F72EF4E8991940
-:10467000DA2FEC1542E43451D67FC7C52CE6077E0D
-:10468000F22BE5BE5C63EBCF89CF791ACECF423BEC
-:10469000A36CE5A9F5580FB4FEDB2CD41BDE07395B
-:1046A00081F815E8169803C6A9BB9846EF37769FA0
-:1046B00030A23DFF926E6016C23F7840A07B5681CB
-:1046C000E6F3C43FB729FE958F8A781C31D053A6F4
-:1046D000A3F3F41673FB4439FFDEE27F4F41FE651E
-:1046E0006E958F4FC3733CAAA773DC583590222573
-:1046F000389793302EE68FFC4AC9D38B6FAF3506BF
-:10470000C92F5BABE06D7CFB070A3E02840D4A9E1D
-:104710001213603D750A7ED5E3F761D250CF17C200
-:1047200056A0DBFA9E19E4DFA86FBEF2F75E86C3DF
-:10473000B76B2D9B18F76FA875B4BF62F3B8D0FEA6
-:10474000D2DE4B0FD23E4CB9AE91FE2BE87781FE04
-:104750002C8A9F3475328A97345E2CA6F2ECFE4781
-:10476000E81E94D93AF024CA0556A823BDBE31A844
-:10477000D56F8E17733A385ECCE9F95211D8276697
-:1047800036689F801D7219F112EC90943EA6B14FCD
-:10479000E29F937D6256FC86A02EF95F4EB0EEB785
-:1047A0008AABC4711948579B09BF19E037E255FC21
-:1047B0003E478CE3EB52E97949DFC746D47703DD06
-:1047C00089E9F937C5952370DC0DC3E4E5BD5DCCFF
-:1047D000F95DE35646F00A6C4D23389D615B7D55CB
-:1047E000809767601D784FFD9CCF97940AEF9FF3E9
-:1047F000FB92303EA7D27FD3562BBDB7C1B5201D4B
-:10480000BFABE11AC7BFEB73B67B8619E17CC75615
-:104810004E77EA7CEF8797A423FD4C320C18D13FEA
-:1048200099D3732A05F5BA49FB17A623FD0DB74E98
-:10483000BB721E8DAD598BE91E10FCF440F7F72BAF
-:10484000722CB0366C44F8DFDFCA087F7BF7FDBA04
-:1048500009E9F76C4F928472F2CCAB4941E4F7E777
-:104860000E98423A186AA5F23DA43386FE5B487F53
-:10487000DCAFA77C85C0813F3C89F418D867A27B58
-:1048800035F7F73C721EE5DCCA9ED91F8B58BEF87F
-:10489000F7A587C6D6D18B63F38EFFD0B63B0BF955
-:1048A000E75991F389FBBB5F217DF6FE4B17C66389
-:1048B000FEE09957FF6332F2B3C04F2E4C463E16CE
-:1048C000F8F185C9D81EF861527322FD646609FFAC
-:1048D000CE862A1F9D6F891A3FCB39053F9C1D9BB1
-:1048E0006BF0BB05934E2CA23880DA3EA940E7C39B
-:1048F000FE93DEAE4EBF3BE6BD8E8848F912134FE5
-:104900005427AD88C1CB0F8A0DAA9FEEDAFC234A4B
-:104910001E82EA1FD91011F93DBB067D08F37B9773
-:104920004678FC3DDE6FC298EFE6523CEF7B333CAD
-:10493000F8BD1EBCA78E7191730F1684E89E7AD0C5
-:104940007CD815A3072D89E8C226F483F498C2A861
-:104950000F2D8988A74C317E91F7A597D7A11ABF53
-:10496000C4AFF563C4FB41E0972CC6C44FEA5BC2F9
-:1049700006554ECD83F97FB18E4918B719E21FA9AC
-:10498000FD12F961E2FD2472E40933BE27BBF8F79A
-:1049900075543D13CF6B6F027AB72974A2D2514779
-:1049A0004447E7D011A932BBA03428ED7B416C0607
-:1049B000312FA867E14EB4D33B2EDD9684F0EA7820
-:1049C0006B01C3EF479C93AACC05F8DEA52F99177E
-:1049D000BBA3F831847F8CE37265501F1846CE1D4F
-:1049E00051F8D6DF4BDEF58DFBEF21EFC0AE7E6DCB
-:1049F0001CB7AB9772BF07B7ABE3E584CA7FD5712D
-:104A00003F53E03D94FF7E4CFA0BD8BFC47F3F1B61
-:104A100027F3EF34F4CC4F27BBF8AD45E9B26DE88E
-:104A2000F8F9A24797E61E3ABEAAAF0582DEC36632
-:104A3000B463BC3CFF34B048A0EF48057C02E9D920
-:104A4000813A4308DBD5F54416F1B8E0628F40DFC8
-:104A50000551F53F553F1C6C9F08EDCEA8BEA8EA56
-:104A600085111FF78B2EF21AA8FD36A37F60DC2478
-:104A7000DC9F859E4F9ACAC7053E7018FD9FB77D83
-:104A800059A0EF76A9FAA28A9FF1FAE4273DF957D7
-:104A9000FC1EDD36052F55FA1A1D4717AA9C7229F0
-:104AA000F06942399D8E72FA3363BF6D78BD1BE4A5
-:104AB000B4584CEF31C2DB896F8BBE4476F7B7C672
-:104AC000717E6C2F56CE2D72A812D79BCB229417D5
-:104AD000359CFCFCB498D3C370EDAE715CCFB91AB1
-:104AE0001D4F2FFEFBD2F1B4E2FF1E743CA8FF194C
-:104AF00013EFF3ADE2CA6A3C7FABBE99EE4DB19FB6
-:104B00001AC86F1DDFEF3305FE20CF34787C38D70D
-:104B1000A843BB27D0C0EDFECE54F938D927AFF15A
-:104B20007BF8F72BF94AF75D94A8ECC40F8561FB7D
-:104B3000034EF2DBDCB7FB84C10BEF2F6D11CAD043
-:104B40001FB4B441BB9FCE0CEFEC583F78E7A82EC2
-:104B50008A2B0477E6CB387E3D6E16FD219D5921C8
-:104B60008C3D36A11F67023E8FB98701F3342ACFEF
-:104B7000A729FE1D16A707FCB8F71DF2F7605C0811
-:104B8000E9D7D823505E48E028F77734F570BEF0B7
-:104B9000518340FCE423253F23D06A21FFB6AA4776
-:104BA0007CACF4BBF74181F4BD217A85571B776952
-:104BB000FCEEDBC417E3F588B4BD7C1C8CB7A05FAA
-:104BC000E670EE6401EB8D60178E447D51966FCDDB
-:104BD000E6EB6321E22F5E8D1FE593A3BF253B72B9
-:104BE000E97E81A593DE11177FE99C13177F397247
-:104BF000381BC751F40C09FE0FFD87F17A4653F7B5
-:104C00000903DA05578BB36C2ED6FA05C788DCCFBB
-:104C10003AA64790D09F344681D3751BAC04A75960
-:104C2000EFAD48473A57CFE7EC7C7E5E67DFF9B4DB
-:104C300012DF9BFC9E2821BFFDF13B2D3FCFE67587
-:104C4000D92CE37B2D4968879C7D6F5512C2F1C733
-:104C500050E2F7927E78524CE83FFC6BF1A0DF788F
-:104C60006731CAB78715BFB108F22D39EA7F897F4E
-:104C70002FA784F3A94EFC8E11E2DF7E1EDFEE1C0F
-:104C8000E59F43F5A7F2781EB1C8F1F5959E54094A
-:104C9000F5BD12D82CC661BF6F651D185FE9CCF059
-:104CA000BF4EF4F1948EF017DEE7DFA1D82393BC5A
-:104CB000C3D014C63FC683AC31535EA39DE220EA45
-:104CC000776246811DAA7C576111C65D4B9438C836
-:104CD000782B1371FC4D06FFC6711877E9153D6BF3
-:104CE000F01DD1938EDF458A8FC7A8F161352EA3C1
-:104CF000C689878BCB0838CF788E67B1DF3D51E30B
-:104D00002FECCB3C7FB37D4A33DD8BDD8E3112E25D
-:104D10009F43E2297F463B353E9E22A2FCA1388D6F
-:104D2000369EB6B1E865C2B7CF1B479B5E3CDCFC44
-:104D300032B7E7E2E69F98FA4926D92F7FF9730A3E
-:104D4000C9B39E0B2477CE0D9894FB9DFDDC4FDDFF
-:104D500063207BFD1CD8411931F26CF9380E87BEF7
-:104D60009E19848F7B23D549D8BF53D17336BCB5E8
-:104D70006821EAD3C188C8F3B119B76BF646C449B4
-:104D80005C3F180227A93841DCC96C4D9C071456BA
-:104D9000FC056165DF33DEE1F64AA085C70F248597
-:104DA000DE023546E22747723305D58F3C32517C0F
-:104DB00061FF00F1D9FA7B797CF79AE30BDDBD0640
-:104DC0009697C06F5B338BF8CDB5FA6B195AC193C8
-:104DD000A3FC39AB44E127A58AFFB698E7F3A735D2
-:104DE0009755E2F7EFC2C39EB77F634982F34ED077
-:104DF0006FABFBDAE281BFBEC6B8616AD1B5F51B05
-:104E000093881E12F49B7E8DE37DF31AFBB55DE360
-:104E1000BC0BC725EAF7FF68FC333EBE191F0F8D98
-:104E20008F739A5EBB3B886D8F088F0E8411BA29F1
-:104E3000FB6A05205531F5BB66E46B73A7F278C0B9
-:104E4000866A7368BB108D8BAAF00A9672BD4B728E
-:104E50009F0FE27712477B23D5E940C7E7A632B21E
-:104E60001BCE5994EF2389D2A8F9747E127D1FA717
-:104E7000D39238BE3451196F383EF2BDD2CAF548CC
-:104E80002FD230DFAFC82DE17680D4CDC85FC344C8
-:104E900079D4029A571E45DFDF3BC49FA78419E5EA
-:104EA000F741BB7301E9CFB213D7B745897BA5CDD5
-:104EB0002974A29F2E0DE42DC6451EC3F808F9F5EE
-:104EC00025EAA7CE97ECE6F36D313001E358C171C6
-:104ED0003CAF82757C5F13D73866087FB05CA0B8A2
-:104EE000C6765CFFCF7461F70E273F1784AF7BAFA8
-:104EF00044F19637A67EAF88EECB2B718ED512EF9C
-:104F00007210ED0C58C7EA572B087F97F64DFD65D8
-:104F10001DEA832E91E03C440F57ECAB938A7DA8A9
-:104F2000DA57FD6827C6D81B3F50F4860474F58312
-:104F3000447C698BC0EDDFE0CFB8FD5B61F4E4C772
-:104F4000E653F52A7192E561EE8755EDDAF1DE90D0
-:104F50002E13E050F1A03E6C02395DB1BED488FC46
-:104F6000BA627DAE95FC4A2BF6E85478273AF79F53
-:104F70002AEBDC707480E212AFC4C52793DD466A69
-:104F80007F48C19F643C5B28571788ED287E47DC2B
-:104F900020E913F9C5EB41EFC7F52DEFE4EB55E33D
-:104FA00020F5617906CE73EAF0C07A2CCB1B9C33D6
-:104FB000C86FB8F2FC7A949B814B178E4C273F80C8
-:104FC000514E745F604B29F71FBE828A08C26BB6D0
-:104FD0004879BB15B3453AEFB47A0BD9E16906A617
-:104FE000C7EFB0A6CDE772ACBCC63E03EB6C512A4E
-:104FF000C9E1F2A372EADDEEA89D9F36BB2503E16D
-:1050000074B5F890EA2FB8CDE8FD6349C6E78F0F75
-:10501000351E7B8BF2CCEEE8D7C687D478CF70F103
-:1050200021353E1BA8F954134F0E8803B3D0AF525D
-:10503000F1EA298A0F07BA05C9E18CC68D027BCF38
-:105040001B09BE4ABC08FA1BF1BD0A38F65169F8C3
-:105050001D021E3FDA87F9B846FCBE9E4479B73F71
-:10506000C27CDC42FCBE1ECFC73D80F9B846BCFF07
-:10507000C1F371FB94FCDE40CF798A37A5B987E490
-:1050800053513CE221C197E19EA48957503D3E5EB9
-:10509000A1B7723B3470D440DF3F0F1C33139FAD78
-:1050A000EC593E06F531F5BBE44D182F88F12F9DE4
-:1050B000F57A2C78BFE7ACCF63C1384145EFC746DE
-:1050C00099F84E381B53989AC48811ED7D8403E5F6
-:1050D000F9F5545A10AE57F5EB77FF7FBFFEE7F1B5
-:1050E000EB7F2B4A97C43FCA7D3ABA575E7ED46B9A
-:1050F000B93B863F6CF071FFF006571ED1DF13BE3F
-:10510000BCD415B17EFC1A6EBFA5CD7659629FBF87
-:105110005BCAFDF86942E2FB0577B987E5B777B965
-:1051200013EA3B89E3011B6A381F51FDFD43E3038A
-:105130009ED75C317EFEB33F33D3BFAFD0BBDF44DD
-:10514000F2FC4FAF9A76A0DE5D5EB3624C32D4CBF8
-:105150004F9A9893CB234D5C61698DCE6B4949146E
-:1051600047F066D3F743E3E305353AE2EF83F18294
-:105170001AF114D515FDFC8EF3BF4BC64F94BE2219
-:10518000843AD1BE78A551F0F4B2A1F10318389B4E
-:105190004D815DD4703BC1536B26BBE06A7185BA0B
-:1051A000BD27D6A19FA08C6DEEC4EF5196B97412A5
-:1051B00088A20471059EDF59AEE811F1FE01C40F0B
-:1051C00094FBF17EC1AD6E6E9F6F55E47E5E0997D4
-:1051D00033EA38EA7BF1E77EC6AD8D3FC4B7BFA79F
-:1051E000B477D4946FC0730BCED531E4FF1D355521
-:1051F0006657CC782FB879DECC168C53D863E3147D
-:105200003C1E111F9F50F95345EF67B3F0DC9FE838
-:10521000E1FEA38083FB332B0E54D23D93E83A3951
-:105220007E3EE118BC6798CAF8BE9899FBB9C8AF32
-:10523000503EF7D33EFCF707982F95FE3D83C031D3
-:1052400057BB0DF9C85C719220937F7BD0DF8DFE38
-:10525000A885C71BE6603E70C5E2B213782E8BEBC3
-:105260000C9477B4F0782D7D675C9557158BB7AFAC
-:10527000B5627B91E0B1C8D85E5385ED37BF184663
-:10528000CF1E9B87BB077A891C83DE79E4DFFE296A
-:10529000DA4515F315BF771D97AB8B7BE61BF847F7
-:1052A000AFB472EE60EE9FC86EBED05341FEEC7498
-:1052B0008CB7BAA372A6E255903FC951F9F3B7CAA9
-:1052C0009D336E9EE73F01E40FAE276D3E8F0BC608
-:1052D0009FFF0B0A3E0D274F86E39F283F745338EC
-:1052E000BD088EA8DC95D19EBE2E2A7FA56EA88F04
-:1052F0001C1EFFF215BC4E1D46FF1A5D2A28DF1B3F
-:105300001B265FA3FBEFE3F7CE2A55F9E7FFE57E07
-:105310006FC5BE51FDDFAA3DD4A2C0592D1F50F468
-:10532000D9BF395F198562C27CE5B4C4F9CA777404
-:1053300009F41D16255FF9B09155EEB1639E9E727A
-:105340002F21E423FDE6F0D3BF5AFF9C1DEF250873
-:10535000128A9DC6AE13249F1B419F213DA8E70FD3
-:10536000DC2FD5C5F34B1BBBB5F71FD4725B29BF30
-:10537000AF500DFB213FB292C7376B2FA7EB80D701
-:1053800018929DE817FAAA18EB170AC8910C353F36
-:1053900030C4E552C23CBE263640F97E4D0D820730
-:1053A000E5C117F61379797EDFB5FA89EA4BB57E48
-:1053B000E6B525DC2F54EB1704D447CD3ADF4ACAB3
-:1053C000EF3D204889F244572BF87EB3E2A7DD6514
-:1053D000E478B0EB7A81F26AF15E0C9EEFAE033CAA
-:1053E0007F7E5739CF9F57FDB26A5EFCB8A85F96A3
-:1053F000EEC3A8F9F46A7EBC7A3F74FE566B18F5CA
-:105400008B4D862E07D2A19A57E42AE572CEAA7C4C
-:10541000773C7E9DCB4A2B5DA518A72BD50DE7E7E2
-:105420006A2B4DA0DFBCAEC8CF75A5C3EAE59DA52C
-:105430005ABD9CEAF17AF97F955F76CCF07EE15F08
-:10544000975C9BDFEA96C47ADC907E95A509C66BD3
-:10545000B724FE8EE8EF54FE1BF7EF8FB021F77BE9
-:10546000B87CEB14E45F4EA3389781E25C2A7FE9B5
-:105470004CE6E3EF53F88A5A9E50C61FEE7B93EF3B
-:105480002AFD5A04EF0F70DD25BBB57EB2D22EADDA
-:105490009F6C42779AA65E16CED2F4AF389AA7696F
-:1054A0009F1429D6B45F77B25C539FDA7FBDA6FF05
-:1054B000B48FAA34F51B07B47EB2E91717C4DD3BDD
-:1054C000E2F85D091811FBDE0CF35D9A7ED90DDA66
-:1054D0007DE5366BF735A655BB2F755C6750BBBFB6
-:1054E000FC4EEDFED2D07FEFFEE2FEFBDBDD32CDE7
-:1054F000D3D7934FDF03DC52E3A2EF5EABF7FFFE9F
-:105500001307AFFB52406F000000000000000000D6
-:105510001F8B080000000000000B53E16760F8518A
-:105520000FC15BF918182EF021F8F4C01CCC0C0C3C
-:105530009C40ACC8C8C02001C4FC40CC06C49E0C32
-:105540000C0CFF81F81B10BF05E22740EC0CC407D0
-:1055500058B09BE3C6CAC0E001C4DC40B378988968
-:10556000B7DF8917C17ECCC3C0700E889FF1D037DA
-:105570000C061B5E27403FBB7E43ED3A2932F0FE0E
-:1055800006612131609A1447F0A78AA3CA0B8B21C8
-:10559000D8C9D294D9950FD40F00F19321F080038C
-:1055A00000000000000000001F8B08000000000049
-:1055B000000BED7D0B7C94C5B5F87CBBDFBE92DDA6
-:1055C000CD26E44900370960501E4B80C84BDDF002
-:1055D0003252C40411828A2CAF10027914A9A5FF9B
-:1055E000DABB0B2804AADE5851A37F6A17041B2DCF
-:1055F000DA80D11B6DE02EA208D56A684551AB0D4B
-:10560000888808498C8F6AB57ACF3933DF66E7CB53
-:105610002E89B6FE6FFFBF7BC3AF1DE79B99336733
-:10562000CE3973E6CC9999B32696C20C9733F60D12
-:10563000FE416A3331C6C674A5ED4AC77035A7ABC3
-:10564000FC36BF9779CD8CD5F9AD946EF1A733EFC9
-:1056500060F8EE331406ED8CDDEB7751FE17FE4259
-:105660004A6BFD4554EF4E7F09E56FF7FB28DDECF3
-:105670002FA3EF35FE6ACA6FF0AFA17493BA280D5D
-:105680005082BFA2C2AC64C6AA9EC9C9DB0CB92DA8
-:10569000B3C627A8A321FF8A9119B300BE4FA5FE68
-:1056A00098EADE347074573D0DCF4DEAA47E08A70A
-:1056B0007609C78B59992D46BD2C1CE79D4B043CA0
-:1056C0007B6B4D4E72D47A8311DEED25006F28146A
-:1056D000B842D69CE8F02E46789B4B545E2F395842
-:1056E000931D1D9E07EBD5DC20E0A507AC31EA8DAC
-:1056F000C17A1B6E10F8F5F3D56445EF773CD6639D
-:105700002EF56FAD56467FDF64E3FFDB5DA72E16F7
-:1057100079236693181BD7D54E9F321660384E9565
-:10572000F90A890FEECCAFBFC967EC268409ED03F7
-:105730009358C808FD079258707D96547F26D56F00
-:10574000EDFBF537A952FD80214A7D136B50B0FC6B
-:10575000E72847C0F7FBFCB9946E14F273DF5003DF
-:1057600063D82EDD1C1C04EDEEF17B485EEEF68F57
-:10577000A5F2BB841CFEBB90B3A090B30751CE2012
-:10578000DD8A7266C6FE7CADA500A77D6F3CDBECB2
-:1057900026F95A4C78AA8CE06FD83B64FB66807F70
-:1057A000DF0DAB4E6F03FAB7350FF318A1DE3D43A3
-:1057B00035F9625E96DC55EF9ED9279C8B8612BD2B
-:1057C000CB10CEDD1EC13F15061651EFEE19E17A62
-:1057D0001558EF2E4F185E28B2DFBBA684EBAD2222
-:1057E0003E2BACA4C1DE9D2F3B9842F3110485E80B
-:1057F0006B42FAC2BC7C76C0754A2BB44F49CE4B83
-:1058000063D0EE7E9C8F669C776EA28BD61EE9ECF1
-:1058100083EF1916568DF081B2FB8D80AF69B63BD0
-:1058200011E972FBB5454C19C6585F519E1A2852B2
-:10583000B200AE7D4E9182DF4DB3A11CBEBB447958
-:10584000F21A5E7E3B963BBACA13B11CBE27554383
-:1058500039E4ED7379F91D7EE0C4E0AE7A9B80CF28
-:105860003EE2773AFF0E6C45FA9846F354C3FB09C3
-:105870001412A0DF414CC774E1BF69D0BD190BED14
-:105880005DF8DA06D7535EC36FD3E038CA6BF8D839
-:105890002EEC97B110D2BE4BFA326FAE980FAC3BE4
-:1058A0009D13BDD95279A6EA4950814E992F1959B5
-:1058B00000589009E289F0F4ED8A9881F0EC71FECD
-:1058C00025F76EFE9986CA74D0D2A3821E1A1D36A1
-:1058D000F697E9601920D361E300990E960BCE4F3D
-:1058E000871DCC4D748E450FADDFCD43E47EE32E96
-:1058F00092FBDD7C91DC6FDCC5FF9C7E6BB2E47EAD
-:10590000ADD972BF35D972BFD69C7FAC5FA67A6025
-:1059100032A0BED2FE2E94F4DBD5CC7716DBA39E4C
-:10592000C3F9A4E93953B28FF9EC5DFC84758AB1EF
-:10593000FC48388325BD0A703EC57A00C77B7E3897
-:105940002E1D9C417A385F0B7C58A49EEE06870D75
-:10595000D48FC3A4F076214344FF4CF5B1224764B1
-:105960003B8FAEFF1C7DFF4E458CC370DEFEDD3AE3
-:10597000BA66EBF14913F830C3F9E8C15C3A38591B
-:105980007A386E814F48392F1CB77E1C178AFE0368
-:105990008AB47E013D8675B56B07FC689DCAB30469
-:1059A00077827E08EDFBF214AE03E71AAF755BA0B9
-:1059B000FEFE9196D0E5507E2E5810B440F9E427B3
-:1059C0008F3AD18EA978D2A862B9619F8DD697B649
-:1059D0001D0A9557595AEE9C00E51D4F1AD976EAD3
-:1059E0002ED380E33B25740A0BF17CA98D672BB67F
-:1059F000EDBF11DB973559980DE0553CBD6CE604C1
-:105A0000C82F3B646258A562E75A735FC82F0F2AFC
-:105A10000D98077C699D0AE4D9823BA1FEBA7D5F9F
-:105A2000B621FEE71A4D83109F33B04EB8619D78C2
-:105A3000C9D1923A1BE8531EDC3D0DDB97EF523C77
-:105A4000A0E100FF9D073310FF47148F0558B8A24F
-:105A50003E9EB923E6CBA946238D77D53625C800CF
-:105A6000DE32563B0DE95981C4413C3C96A04DE9DC
-:105A70009A6F67FC75D49F96AF7804FA83F6958F7A
-:105A80002B1E1C72A581F9701EB73D6D2B79C88E37
-:105A9000E35D6B1EECC0716E3463BD65C1854FD98B
-:105AA000DC88E736F334C477EB3673E950A4235B24
-:105AB000503414F1FBBF327E75462F8E77D548CB1C
-:105AC0007623E0C1ECA181B31CDDF5EC1958AFDC05
-:105AD00011EB673903BD4FEB77D05C3CACEBFB9728
-:105AE0008644D21F2BEA8DCC6DEDEA47938FC0110F
-:105AF000211F7B1D446F8D9FAB5C7C0A68FC5C950D
-:105B000028F8AB76E4CF1AD61D9F3B912F644FBB8C
-:105B100028FD05AC9B986E81751EE9772FD84F6ED6
-:105B2000B2CB3DF4FD01B09330DD0A7612A60F82B0
-:105B30009DE4167612D6DB0E7612A63BC04EC2EF5F
-:105B40000F833D8E693DD8E3F8FD51B0C731DDE5E7
-:105B50000FD0F7C7FD359436F86B29DD837C83B40D
-:105B6000D11FA47A4FF9EB296DF237D0F767FC4DBE
-:105B700094DE2EE8E89CC80A701D757A990BC99EC0
-:105B800034C35B60827C5211CFA7DE102830433EC5
-:105B9000D50779A04BDF95A1020BE4FB56F3F20188
-:105BA000B7B04956C80F08F0F2ECDBBD936C90CF4C
-:105BB000AEE5E583B70626C5417E7090975FB42BAE
-:105BC00034291EF21735F0F2E1CD6CB21DF2C34359
-:105BD0003C9FF79277B203F2792D3C9FFFE7C064B8
-:105BE00027E4F35B79FBF16783467794F5778FC9F8
-:105BF000BD1855CE01E56DAF9A0179B3FB265489E6
-:105C0000479553946F3479A9FC7DA5DDABC23ADF8B
-:105C100068F652F917CAE7947FCAE4A3F278835270
-:105C20004079B38FCAFB1BE228DF640A50F90843AE
-:105C30001F9E3707A8BCC0D0AF00E13F630A52F9EE
-:105C40003586413C6F0E52F92FD4E10553A0FEE397
-:105C500006DF5ED477EB155F19DA874C6D48477D18
-:105C6000A5D9953B717068676698691EECF943FE8B
-:105C700043340FF02F19F3A50FA35D0A700E121C09
-:105C800013C031F60C27EFE5B1129CBC97CB34382A
-:105C9000AF101C5BEFE0EC7979BC8CCFCBE51A9CA4
-:105CA0006304C7D1BB71E5BD3251C6E795951A9C17
-:105CB000E30427B177F8341E95E9D378344C9F3349
-:105CC000B83EAC4FE91D3EA35F93E933FAB5307D92
-:105CD0003E267C327A07A7F135993E8DAF85E9F3F0
-:105CE00015C1E9DFBB718D7E5DA6CFE8D7C3F43166
-:105CF00019104E56EFE03CF5B64C9FA7DE0ED3C709
-:105D00006940FA0CEADDB8F2DF91E993FF4E983E64
-:105D10006984CF90DEC179EA1D993E4FBD13A68FED
-:105D20009BF019D6BB71E5FF45A64FFE5FC2F41983
-:105D3000427046F60E9FA6F764FA34BD17A64F1EB2
-:105D4000C119D33B7CC69E92E933F654983E1308A2
-:105D5000CEB8DEC1693A25D3A7E954983E5388CE20
-:105D600097F66E5C63DF97E933F6FD307DAE22383F
-:105D700005BE7AC287011C476C38CF9C93E9F3CCEF
-:105D8000B9307DE6109CA90027A76738E3DB64FAE9
-:105D90008C6F0BD36701C1B9B277709E6993E9F339
-:105DA0004C5B983E6544E7AB7A37AEF1ED327DC689
-:105DB000B773FA54593C931D68DF2532CF76687269
-:105DC000C9C986034EC89BECCC83605F52423B102E
-:105DD0003EAC956417AA1ECD4EF130B4436738DD52
-:105DE0001EF4FB18357B84B5D07EC1BE2B51F20763
-:105DF0007D6998740BE2EB00AB2DD22E49181B275E
-:105E0000D94389DE2429DFA7B0AF543FA5285B2AF8
-:105E10004F2BB9482ACFF0E549F9CCB2F152FDFE3B
-:105E2000D593A4FC056BA64BF5B302B3A47C4ECD71
-:105E30007552FD41B58BA4F20BEBCAA5F221C155F9
-:105E400052FEE2FAFF23D51FD6B04E2A1FD1B45915
-:105E50002A1F19FA85941F75E801A9FE9896ED523C
-:105E6000F925C71E95CAC7B5EE91F2134E3FA3B3ED
-:105E700003E5FDFFFA02C6EDC10C33D983218799F2
-:105E8000F2E67D36B2FFF7631EF869EE3B83F2E679
-:105E90006717BB93713F8D0060BD2FE85B7621FAD9
-:105EA0007B6E1EEFBBD005DF6F36FB46B8A2F82332
-:105EB0003CAA6F9F81FC452D0A4BC7D46DC034CEE0
-:105EC00028F6EB162E5F1BB3F21F0A44C8694D7FFC
-:105ED000987F903F6C3093FDAAC9F7C6FEA5E90BE9
-:105EE00023FAD9D0DF5CB27D28FFBED88EFD15BD68
-:105EF00088F3ACCADC3118F1D2F763C91E2BF56305
-:105F00001D5046FDBC86FD44F8BD2C03CA74FD58E7
-:105F10004BB68BEFA29F6338AE58FD6CCC1E2F8F13
-:105F2000674039F5F3AEAE9F8D03CA75FDC4F1F13C
-:105F3000C077D1CF7BE71D4FCE44793C17ACA47E10
-:105F40003A7474B35CB052D78F9DFAC1EF8BC99F7E
-:105F50000BBB8034E0B3A5A394E4E03F6D2C00724A
-:105F600061CE2CFF35E6D95B363608FB7143BF5056
-:105F70008FE572FFD1D386241ACF6771C0FF083B2B
-:105F8000B56B3F1BA07DF15281220B0246B0BFAD25
-:105F900014B2B96457F1809BDC90361D187837F63F
-:105FA000B3C5E11904F9B6A6C9E6C551E46969ADFE
-:105FB000E9546BA45F44DBDF4C62B9D5D0FF2E9B64
-:105FC0004BCA6BE94AC5C5843F82F22760DFC260D5
-:105FD0003FF067D8173020D5BB26BE4F7B07F6377A
-:105FE000986F85FD0D9633B696DA9D107EDA13B75D
-:105FF0002B41A4F7673FF9A189F47880BD9A9E8A66
-:106000007E37FEB7604D3CFAF8C3F82D0CF491F2E0
-:10601000A02E330DE9B42FA4FD6FC7D396E076A46C
-:106020006B4D26D054D4CB66EC75D8E4662451363B
-:10603000D33096B1D9D5C553D3681629FD57019EE3
-:10604000B31A479AA0056B33B5DEE8B177C1655E38
-:10605000D309A48F15FE219C6B0A211FD1FFB545E2
-:10606000727E2E53BBF2C0EFC1C66CC137D1AFDB1D
-:106070006B42BE16A5727CE6629A87C5DCDF51E2F0
-:10608000E26D357CAA169B5888F6A7811486FEE837
-:106090004032D5BB4EDB67EAF02B3159BD4540D7C6
-:1060A000928546A2AB1EDF37F7C57B0DC321ADB984
-:1060B000DB84AECD9EF09FE793CB5919EF4FA3AB96
-:1060C000262FA7047F4F20FF217D1FF90F789F14F3
-:1060D000FCEF9263CEFF2A8B6F26F2BFE37E232371
-:1060E0007E09BECF117C5F5A2BF37D0EFAC9A1FE4B
-:1060F0009CD559C1F558BFAE8FC45F18B84C87DA2C
-:10610000BBA6825AED86FFDB420EAEABD9FD3CB298
-:10611000F7FA32DDF8041F6E147C98AFA3C71CC1D8
-:10612000B7F9826FCB58E0B60CF21F054DE8179B0C
-:1061300057A630D417553FD5F8D62AF1CDA7F14D43
-:1061400087EF8D826F37FE84F34D8F77ABE05B6B0B
-:10615000DDC72696DD1D6F3D9E0BD6E8C615D0F334
-:10616000AD569C3BB8CC68EF147B0BFA9C8CA87F97
-:106170004DE1957D4E46E8856B8B8AA5FCDC9279D6
-:1061800052FD79BE8552F9F565CBA5F2F9D53F945C
-:10619000F20BD6FC44AABF30B0562A5F5CB3492A42
-:1061A0005F5A7B97945F5677BF547F79709B54BE3C
-:1061B000A2FE11A9BCA261B794AF6A7A5AAA6FD89D
-:1061C00037E46A94AF978E1A19FACB3EF5BC4FFEAE
-:1061D000BA4F3D260FD6A944991B87F2EC26793E8B
-:1061E000E5CFA5F4B4DF43F27EC63F96D2B6A60350
-:1061F00076F43F56C581DE4F043BDCF8E6DA9A7E42
-:10620000B8DE40FBF18C351B5BD706207F000FA367
-:1062100060DECCA833B3D02806D2DD372CCF1DC624
-:1062200088F2D61ECAEB5416EAD3BD7C466BF4EF57
-:10623000ED4AC7E00CF413BE61613B23FC75DDCF72
-:106240002B5826DA15B1CACF1A5859E479D6492302
-:106250003F27711A279D3442BAD2CCE7FFCA3D19B5
-:10626000939813F3A1C1D551FC2EE1FE1A00993485
-:10627000E4738E34EF97D55DDC35CF19F6934D720C
-:10628000BB3C384AFABEA27E82D42E57F1BD6B8445
-:106290007A67F71B69BD66A10303AE1986F8794FCB
-:1062A000E277D6944276578BDFDBE7E440C6FEE820
-:1062B0002FA4F4557F11A5AFF94B283DE6F751FA0D
-:1062C000A6BF8CD23FFBAB297DC7BF86D2567F804D
-:1062D000D213FE1A4A4FFA6B293DE5AFA3F4B43F3F
-:1062E00048E9197F3DA567FD0D94B6F99B28D5F4C3
-:1062F000674FF2775AACAF6750FEA2C899F956B60D
-:10630000AE6662979CC5A9967528671A7D67D459B1
-:10631000843CA44AF29088EB30C9590FE5752621D8
-:1063200087B1DA472F4779EBFB3DC81B63EB480E7B
-:10633000660AB9FBAEF2C6D01B9F82F294A99327DE
-:10634000590E3539D2F440AE52345C1DD325573343
-:106350008DDC4ED2E4EAE7682746B1B76E5015B13E
-:10636000FE71FB88F9320C68BFAD127E7FE64EA746
-:106370007CA7E87B3D806BC17A6A3017D791CEDC71
-:10638000BF0D46FF78E7310B433F7CACF1E9E525D3
-:1063900036DDBDB47F280DC2A236AA7BB92D8ED3BF
-:1063A000D56660852C0FCF67F38FF9809F71FF79D9
-:1063B000711EEE6BE1BBCAC8AE0A7A8AA3F8DB197C
-:1063C000CA785ACFF4D5EA9F7AE0CB7C3C379F2934
-:1063D000E679DC01233FD70E3DE4B926E27C06F6E0
-:1063E000DBE9E877EE18647691FD10EA2BD331D81B
-:1063F00057A2E381419F0DC6F38D4D208738BF3AE8
-:10640000070E4E60E7918F9EF47C4FF45C14ECDB3A
-:106410004B7A9A199E1B013DB7E3FD97DED2B32755
-:106420003DD9937E3CB199D3D929ECD358746E9F52
-:1064300004F32E8A1CDFA3AAB21CB381FCBC43A3C5
-:106440003FEE4B23E87FA9DD4DF59FDBF7D6805665
-:10645000E8A7B3F1C204C6CF73C8AEEB7852D8ED4B
-:10646000EE4C998FAD7D09AE06E7B9275F1F80FB23
-:10647000E4DB3003F3ECC9F8A25FA9295DF07A7B75
-:106480000E1F6B5CBBBFE5FC6C4FD5E667CB009481
-:10649000A7CF841E8839BE9EE414C70770AE52F899
-:1064A000F836188B7E877A263CBED129BD1A5F55F7
-:1064B00082992923003F87D9CC1218DBA1FA0EAAB2
-:1064C000B48FF3B406D04FB12FDEB31E5852E53C63
-:1064D000F372C88DED647FC68A7A9B4BB69F125DBE
-:1064E000B2FD94E18AB49F3A0F3DE4F4017EABD251
-:1064F0000DAE93A3709DF38A758EAFAB1A7E150D0A
-:10650000592EBB0447CE77D62A850D244FEE84D969
-:1065100051CECBB47455BAD97512D6AB33F539090F
-:10652000D8EF19BFD5C5D757978BF79BEE8A5C5F1D
-:1065300057AE89A3FA1A7EB1E0FEB3F163AC91BD08
-:106540006BC57511CA7262D78FC94FF513339D4B56
-:10655000379B3E43FBDD96ABD9EF2AE535B8550DA9
-:10656000C68065047EDF25F507EDDCDA1933B68BCE
-:106570002D372A3BA5F113F86FC58377DAB75A890F
-:10658000CF3E809800F0DA557B0DCAD50995CFE74C
-:106590002A21A715D656B3CF4DE46E41795E3496C5
-:1065A000691366EE5BA0A73F78D144F7B4D85700D3
-:1065B0003DBFEBAAC01256E444A7E7A2C61533704C
-:1065C000DDFEC0A0ED876BF371DCE798A110F5D27A
-:1065D00039F647E7A888F93AC4C4FD31AC86EF73B1
-:1065E00002F00FC7B7B456DEF72CAB93F3A56C5689
-:1065F0002AEADBD22D261604DC97E3BE491B37E8D6
-:10660000DF0C13F76B2C63D51B709F7EAF89FB7B70
-:1066100016B9989A097855FCC72FF3D1EFE3317179
-:10662000BB433B4F5E9EC4F12E9F1D347BA1FEBB3E
-:106630008DA3E680C685F6C10D64FF1433CF4ED618
-:106640009DEE8B6B64FC7AC25F8FAF6607753BD79C
-:10665000167824D72BDE60143D77994911FB3F3E15
-:106660003F669B647FCE3C93ECF7D1E4C024E4E02A
-:1066700084EABBDA3486F31DF9A8A81D665F443DA1
-:106680007357BDD9E7AB67C17A46AA37CF9482F575
-:106690003AA6D1FE98813C0DEDAA67EB827723875D
-:1066A00027D7ABF88FC79E0A80BC94FFF61E2783BE
-:1066B00075F303B536D503DF57EEBCCDE985F4B4E9
-:1066C0001A70223F3F081A0BA3D1634B981E5EBB82
-:1066D00082FE34219FAC26407E8ACF769A5CE4E726
-:1066E000AFB7842C20A7958DCB67B0E1943FCEF354
-:1066F0001B3F3262BE49E657F9AFEF4975F37B366F
-:10670000DC9FC44264E756EE786F1AAE1755AC832F
-:10671000E44CDF0EFBFF3C89E6F5427342F772C0A2
-:1067200093FC095562965535FEFC23A313F3B27C06
-:1067300094097B15E984FBFCDB4C8EE453F190BD9E
-:10674000845D82F35CA3070B72BB75FD23F70D3FDD
-:106750000EF89CDDF1A253191AA91FB89C75362CAE
-:10676000FE95D5105B8FB4811C46DA470098DAB9E4
-:106770009B84BDDDCCD395A69013EFB3ACDC66F261
-:106780008004B2958F1919DE03606F5882E8175D97
-:10679000F1D8F3AF8D07BAAFD86D4A9EC187635762
-:1067A00052BBF85205FF5B93D7C587F2279E37BBD4
-:1067B00087F1EFB72475F163C5EEFD6636AC3BFD9E
-:1067C0002637EC37B7DAA3F0A5E1F8345C67D73F9A
-:1067D000F25733FA133FD8A7B0B4ACEEEDCBB63DC9
-:1067E0004FEB1DD289F828F814E65B377E85663EAC
-:1067F000339AEAB9500FC6E2D732A177419E1F7F84
-:1068000006EFFFBC69F1E0F8CB1EBFC989E3785FF2
-:10681000ADE672FDCBDB52717E979902A92E4AF943
-:10682000F7B2077F44F2B6ECC88F52C95E60DE0C47
-:1068300003E9E240068E6FE9D66B697CA5CC47720E
-:1068400057F64B6311DE47FC546585BBA3CC8B38F0
-:10685000B342F8BCBF1D0C1918DFFBB8BF447DF66E
-:106860004723DD8B62EC87746FEC4762ACB0F2516A
-:10687000FE532BE7D371A12771224BF2BA63630B4E
-:10688000F2E74C7F6F1A9E73001D02825ECA3700CA
-:10689000D778646A1AE70F73ABF9A21DE8F7C9F855
-:1068A0001DEBB798BCB6E1523BA10F79FFAB45FF9A
-:1068B00080771CAE57EFA746B7F7C688F1C15F0BCC
-:1068C0008B90AF88F9CDE7FB8E4D7C7E6BF33D5806
-:1068D0005C88E59FBCCAE70FB6C3F501F00AA55175
-:1068E000F9FED90AE903D857479BD73B4C625ECBE8
-:1068F000E56029D27A0F78AB4A42A49C00FC24A21E
-:106900003FED834BB740BB08FBAB0AFBA37AE6AE77
-:10691000EF11EBC332A1074C6698FF1777CD7FB616
-:1069200095CFFB9EECC995A6E0C30FE07C7DC3E24A
-:1069300009B871BE9A8A70DC1FEE3AF0DA7520D77A
-:106940001F3668F354D69FFA795AB6670C8B364FC8
-:106950003FB4C3FE2ADA3C85EF51E7A9BD95E4F8C0
-:10696000FBD69F1ADD869A65BD897AF019776CFA95
-:10697000E9F5E0EF4D6EA2A35E0FC2DFAB2CBFBB0B
-:10698000DC69F2A6C959F96F2A2E407D1396474D4E
-:10699000DEC2F2A8C99B7E9C32DDF4E57F15FAE6E3
-:1069A0007A6BE13568175B3B18ED570A661B83B8B5
-:1069B0004FB67EC268BE4FBA219EF2738DAD4FA016
-:1069C000CDF756C5DC61B88E5FCF02267E6E5E6B5A
-:1069D000223BF5AB6FBE9908E3B94ED0F57A20F3B0
-:1069E00055C087125509C5019EF354164848427F89
-:1069F000B1C24E44E0717D999CC7BFCB52BBE0F45D
-:106A000054FFDBDAD5DF353DE2E767577FC294F606
-:106A100017603847C85171333FA7A81AAD04B3694E
-:106A2000FEB5AA4511FB84C7CCDCCE3832E59A31DD
-:106A300048BF82B9C31248BE6B87D03EB04AE8ADAA
-:106A4000CE803B01F57967730EEDFB3A0F2D76F89A
-:106A5000A2E8AF0342CE9E17E72CED76A5D608F24A
-:106A6000DECE3AC86E09D86D51FD6E756683B0777B
-:106A700004DFE0CF08FD9708399C074D13F222F898
-:106A800036FBAA0F5467773EE0DF89887DC33F4A13
-:106A90005F946BA4EF015BEBB4A228FE994785BE1F
-:106AA000BEECD92FCCB8CE4D692E50918E53EC460A
-:106AB000C9DFB15D9BAF43D950C4EBB26797DF31FB
-:106AC00006E4B8EA90D16383F155357F64F645D981
-:106AD000BFE9E989F0D17E6C3573FBF8A8A9682974
-:106AE000D2F5E8B5FC3CF74F664F45343C675B395F
-:106AF0009EF358D1A7A3957F3DFA16CC7584260145
-:106B00003D3AEDFC7E7277F9E3F3BED3A504D72AB4
-:106B10002887469E4FE6F77FA731DF1D13159AEFB2
-:106B20009747EAAF82A6E2C7F03E4B65B3E2324038
-:106B300079A5DA6A4639AE6ADAADA25DFE03377F1F
-:106B400067C1D4EA61B323FC5BAD66EE4F3AF0B7A0
-:106B5000EBE6237D3F9E6D61889777E8474E5CEFBB
-:106B60003F6E1E45F320D6B8FEE0F75C3305FDF11D
-:106B700066AECFF4F2302D395ECA5F3B99F5C37330
-:106B8000DECB2CAD3779A2F06F9D85CFD35EEB378E
-:106B9000EBFF30FD3611F41B976B53A47E9B6EE127
-:106BA000721FA1DFD2A2E9B7556BDD692817ABF6DA
-:106BB000E6A4215F571D5E9A124DBFBD20F6B58732
-:106BC000C53DE9F67EA0DF4644E8B77EA0DFA2F827
-:106BD000C1475B34BBB307FD66FDEF997F2FA07EF5
-:106BE0008B32DE2B84DC69FAADB0792DE9B7C27E39
-:106BF00046E93ED2651661C7C5D46F0BEFB996F270
-:106C0000264F7C14F941BAA27E3B2CF41CF6837A01
-:106C1000EE67966FA7E7E65939BE3DEAB9FF263A17
-:106C20006B7A6E557F85EC97EE72C8F5DCAA2CAEB8
-:106C3000E756EDE57A6ED520AEE7F4FA6D5237FDF2
-:106C4000C6DB57E6427BDA2766DD7703DEE72B31CA
-:106C500079AC507F865B7B5F503D2652DFFDCC12C6
-:106C600043DF7940DFD97BD677AFA0BE53498F0D84
-:106C7000C479A4978FE903E3A5FB6A47BF38F59B66
-:106C8000DFE27CF98391EE03BD6EE0FBA17D5F9CAA
-:106C90001A85F3EE65C407E6CB4E217F6DFEB1A4E5
-:106CA0004F270FE5F3BDE2501CAD13958D0A1FEF82
-:106CB0002D4AD08DEBC0DF3EA77DF2FCBD7C9F3C12
-:106CC000D7C2E9C17E6CE4EF2280040B23E4A1E487
-:106CD000F372F2F395A8CC8AF6EB8243D33F40BB24
-:106CE00075C1E73564EF2EC0EF78BF6277EB864C55
-:106CF000E877FE7285F61B4CDC87D0EE4B5CDFBC80
-:106D00009FEEAFE8EF4168FA7C7EB5FC7D81CEAEA8
-:106D10003F20C609F62CD185BD628CEA9F3BA0A717
-:106D200087878FBF6235B78FC3F400FAB895EEF44A
-:106D3000008ECE5898DA35FEF94FC2B892BBC6A580
-:106D4000D1433F3E6D7FB240CC8D58E3D5E8D76D3F
-:106D5000BC1A3D75E37EDE22ECA28BD9309C67AF76
-:106D60001B7C778C41B9F83D8C1FF099336F505ADA
-:106D7000A41E7E51E8F3AB7CC7A7A4BA915EFCFDCC
-:106D8000DD7565BB9F4F85715CEDCDCAC3AB08D780
-:106D9000FECDEC433FC2015B07E9354DAE2EB47228
-:106DA00039FFBB8073B4AF6B0AAD1F4D8A8BE64BC6
-:106DB00048A7B7C4BDB02AA027CEC7AA26B1DE8097
-:106DC000BCE17C9BA6AD3F487FF8CFAB9A39FDABC9
-:106DD000AA15A2FF4CD67110E95B99AC7842006A03
-:106DE0005AD3EEDBF01ED50B36F88EF3B64CF16CB1
-:106DF000E7E4B067A446954B359A5CB2EA21E457C4
-:106E0000D0D6C105582F09DF8BBC9E82F689DEDE05
-:106E1000B8CCD27214F1B8ECC726B68D75B73F3432
-:106E20007EE7C2BF6FA2DDE7E9417E0709FBF205FD
-:106E3000A4B71DE9DA6146B9AF0AF175432BAF5229
-:106E4000DD53883E1ABD9B605D18CDE98DEFBEF421
-:106E5000F4BC5ACBA33C63FD66C584EDAF043EF49D
-:106E600081A2C9862F0E6AF28BEFC4F474C1FD7F34
-:106E700046C47C47BD1479EE58D97484E8327D3518
-:106E800098551174477D753EFA749B0F4DFBA3DE38
-:106E900083FAB6F3E142AB3C1FF6D93A5E1C81FEA1
-:106EA000ADBD0AE903D69C28EDEFAFB0F27DD3016A
-:106EB0009B8FE4B6E3B089EE7BEBF5C658417FDCEF
-:106EC0004F44BE839B8C03C1F35D978DBDABE191B5
-:106ED000CDE527525FBF60F3119F62C19F26E0C7D7
-:106EE000B297C2F8627F789EE296FBD3AF179A9F63
-:106EF000A7A7715D23D6FBEF3AAEF0F9246B3133CF
-:106F0000EECFDF6D8E38679A23FCFC9A1F2CA2DE31
-:106F10004CCB98D8F5D0DF128271BFB0EB21F2EBE9
-:106F20009E7BF4F84C94DB15BF33322BF0B96D9790
-:106F30008385F83D0A33AEABE58DC6A8E7228CAD5C
-:106F400027FC56FCD6417AA57C8F253803DA973F7B
-:106F5000F5EE70F44FB5ADE3FA25F0A8908F40EB55
-:106F6000703C2F2F57F979B11EDE8F85BC9C7D3A7E
-:106F7000BE04F5A352CFDF759637CC355922F6E51E
-:106F80009578E0C6EBD13DE4C0230AF9C1BBE3B775
-:106F900096D77B84EBBDF2265310DF8796D76FA37D
-:106FA000FD6C55FD4766B4E326FFF631B223AA9A7D
-:106FB0008CB29FB0DE18B2901FD3781C53BDBFAE09
-:106FC000B2B182E6636583F087E9FC452B7EBBF7AF
-:106FD000A9009066C513BF76A29E39D3B2D3497E6D
-:106FE000B87AEE6753ED6A743F5C4FFEB7864D5139
-:106FF000FD6F67F03F60FE6DB5CAFE3756DFA757DD
-:10700000E7E02B1EFBF4413C173ABBE7C30711EF47
-:10701000955F7FFCE04FD13ED96773E17A57F5E881
-:1070200051F2AB6BED9E12F3AAED915F3FFC00CCE9
-:10703000BFB6372C74FFAA6DEFFB03DC30CEB6DD94
-:107040005FA4A2FF72F5DEA9B46F59FDE4E4B4F3C6
-:10705000DD2341B90CF6E23C44CF87038D4686EF31
-:1070600020CF1DB3909D11F6A3365470BFB45BF8CA
-:107070004F77453F77D2FC7E958DD75C7D29AE7BDF
-:107080008D268F9BBE0B3F604F7ED357819F237A07
-:10709000C1B75DC22FAEE3DB39FC0FE0CF9FACB2CE
-:1070A000BFF9D3C6A5BF7A00CB1AFBC4F49B867A7E
-:1070B000412FED5C6B9BD5FB8E15E7C39EDF907F68
-:1070C0001AF90536376B7BECD301E86F386DEAB8F7
-:1070D00091EE5FECB5D03DA1F2BDAFD3FC687BF281
-:1070E000089D173171AED4C6C27FFC1C40EC65AA66
-:1070F0007638B8BF55D01DFDB16E277D177E572E4F
-:10710000B79A3F36961FB68F4DDC0317E76C153BD9
-:10711000DE32339D5F5B198B7C3A2E9D0B6AE3D682
-:10712000C373211D2E893C4F88E5E7167A34CC279E
-:107130007E8ED0B64D9C2F84CF0D18EB9787F7DF4E
-:10714000F979775550799D45998FDA7982D3A69B45
-:107150008FC1DE9D23F48CEF77A38762E3FB568D0E
-:107160002E67BF8AAE8F87D814F1FEC0976B8B58FD
-:10717000771688F5A412E8C5DF93717CCF8AFDDD10
-:10718000D9478D41DC076F6838407A553FAF2B599E
-:10719000F4F821E36D5C9F5436ED1F8EFAE7ECB3F3
-:1071A0004F93DC55EE3A6E0E009C83F54F985B874B
-:1071B00076C939EAEB6084BE3EFBF8FEE1FC9C83B5
-:1071C000EF23F5F0AF10F0AB9A65F855BB3E92E0B7
-:1071D000AF0834985DF69EFB39A37AE7E278CFB426
-:1071E00098282ECA99066361B47825433190544A91
-:1071F000179D3638F8FB38639299ECC8D58EB1C725
-:1072000012923135BB711FBD7E2DBF0FB9FE679E37
-:1072100074E4CBFAC439740E54ABA3A32BD95580B4
-:10722000FB6BD794A2D128567A3D90E8354878AFC9
-:107230007614A6E17BEE5B853DC2540FBDDF333A89
-:10724000A715E2388C2E83CB16751DE5F04CF6227F
-:107250008A176172C9EFE9BEF7F80FEE7E72FC87FC
-:1072600040BF7F34FE03A33818FFEFE33F04B09F15
-:107270007F81F80F21F2DB68F11F92BFE7F80F6BF7
-:10728000991CFF41F0331CFF41F0F37FE33FFCFF0B
-:1072900015FFC118F7F729189F418BFF9012679EC1
-:1072A0001A19FFE1C2B884A991F11FC6C5A54F8D77
-:1072B0008CFFF083B8ACA991F11FE6C75D3435327D
-:1072C000FE4355DCA8A991F11FD6C64DA4BC16FFFC
-:1072D000E1EEB8A953E5F80F33A74E817C5B9CEF34
-:1072E000EFB85EC58AFFF01E4E96313DC77F00386D
-:1072F000E6B831B1E33FE8E1C48AFF007012084EFE
-:107300008CF80FDDF08911FF01E0A4139C18F11F28
-:10731000BAE11323FE03C0C9223831E23FE8E1C4D9
-:107320008AFF00702E8A4B891DFF410F2756FC07EC
-:1073300080338AF08911FFA11B3E31E23F009C8916
-:10734000042746FC876EF8C488FF0070A6D2B86296
-:10735000C47FD0C38915FF01E0CC247C62C47FD0F8
-:10736000C38915FF01E0CC257C62C47FE8864F8C81
-:10737000F80F00C747F8C488FFD00D9F18F11F0011
-:10738000CE72821323FE831E4EACF80F006715C128
-:107390008911FF410F2756FC0780F353821323FE08
-:1073A00043377C62C47F0038B7129C18F11FBAE1E2
-:1073B0001323FE03C0B983E0C488FFA087132BFE0C
-:1073C00003C0B997E0C488FFA087132BFE03C0F960
-:1073D00015C18911FFA11B3E31E23F009C7A92C387
-:1073E00018F11FBAE1F35DE33FD84203951C8AFF11
-:1073F000407122C3F11F92BF75FC8766C4F77FE31B
-:107400003FFCCF8CFF70B3DDF7751CF941BF5BFC0F
-:10741000075BFCB78BFF70B3BD283E1EF797DF32CA
-:10742000FE436AFCB78BFF00FDA4C78F89DD4FAC1C
-:10743000F80F39BA7E7A8AFF00FD0C3AEF7862C401
-:107440007FF0E8E8F67DC57FF822EEFCF11FFEE54F
-:10745000E22CC03605CF7F8A4914D9BF4CDC856B3E
-:10746000E3FFC97117C858F8578ABBA0BDDF6F305A
-:10747000E17AF5A6E0FB6B422EDE12F1178EC58C89
-:10748000BF10BC8AFCA2CBE5F80BD3051FE7F9645B
-:107490007998CEF879C3F429593C5E66992EFE425C
-:1074A000AE7C7E3DC377640A80635779E4711C111A
-:1074B000F230B3E4A3E7903D578F8D1E7F6196E0D5
-:1074C00047B18E2ED305DF8A457A3D3E4901799E2C
-:1074D00051764445BACE74B7AAE4D7FE81C63FB709
-:1074E000C4BFD902AE1EDF59827FB3AEE4FCD3E342
-:1074F000FD2AF2CF0969D928E29F1E6F3D9E7AFED0
-:10750000B3487E47C4CD286072DC85C95639EEC2C7
-:1075100054971C77E18A7439EEC2956E39EEC20F2A
-:1075200072E5B80B5779E4B80B578F95E32E147BAF
-:10753000D7EAE23E6CD2C57DB84B17F7E17E5DDC41
-:10754000876DBAB80F8FE8E23EECD6C57D785A1742
-:10755000F761BF945F5C7358AABFB4F688945F5616
-:10756000F786547F79F0B854BEA2FE03A9BCA2E10D
-:1075700023295FD5F48554BFB7711F5E15EF815F76
-:1075800013EF818F89F7C06FC688FBF0D79F7F719B
-:107590005BE47BFC2F7FFECD6DF81EDF20DEC1C6D5
-:1075A0008AFB102E8F11F7A1ABFDB78FFB9092FCD9
-:1075B000CF7F879F63E7E79B13E227E5D853BEFBA6
-:1075C0003BFC6B8BE4F7CC734BE4F7CC3976AECF56
-:1075D000E7F9E477CDD797C9EF9ACB6CBE6CC4437B
-:1075E0001FF76142BC37C78EFA52BCCF0FE1FB5484
-:1075F000581B9FC5F7A9903E87711F203D88711FBA
-:10760000203D84711F20FD3DC67D80F4258CFB004C
-:10761000E9CB18F741C5B811011137A246C48DA8AE
-:10762000157123EA44DC88A0881B512FE246348878
-:10763000B8114D226E4488E09CF01FA2F4A4BF85CF
-:10764000D253FE63949EF6B7527AC67F9AD2B3FEA7
-:107650000E4ADBFC9F53DADBB8119A5CFE19ED068B
-:1076600033F6CFE55893D319F6811B22E5B4C87ED3
-:10767000D10694D358F122E6224D5362C78B089766
-:10768000C78817D1D53E76BC88B4D1DF5FBC887F70
-:107690008BE7F2FA8FC68B985F2DC73358B0E6FCA4
-:1076A000F122CA6C45AB512E3579FCB7787E5ED598
-:1076B00053BC886D7645ACD74017B4BB802EB45E02
-:1076C000F7F0DEFE39C7C3B9B89FE8CCBDE8BC719E
-:1076D0000EF472119BDE3CAEC175DF739C889EE890
-:1076E000AAD57FB39CC72FF8B7F8F3C72FE81627A2
-:1076F000A2A7F802833E233DD9DB38113DAD0B3DF7
-:10770000D173D6F71C27A227BDDA933EFDE3744E52
-:10771000E709F1E78FC7118E0B676D39488D5D5E04
-:107720009ADAAA78075E30DB45FE93F65DE2DE98D2
-:1077300097B95DA9FC9D3ADA9BED7B1286337ABF3F
-:10774000EE625EE04FBCF8AEECDABF1FCFD36F75D0
-:10775000326F6212C583771B73701F36D28AFE9414
-:107760008AC68F5EFE1DC0B5351BE93E593BE0D091
-:1077700042769F3711F916CF6EA77D3A9E717DD361
-:1077800027F23DB3EEF71BB04AC4F9CD54A39DF6E2
-:107790004D9D5BF93D4F23BBE8BE89C9749F9A0597
-:1077A000DDC43FB25357083C3B31C5FA3E2BD98F5D
-:1077B000CB0E3F911F62FCBC32D26FD0A750F6D3E4
-:1077C000D4D99CC3F15D250B785BD0FE5E22E0A589
-:1077D00014C9FE9B0F17151EC273FA25BE52BA8735
-:1077E000905622FB739878378EDBB1F07D39C0A7B5
-:1077F000B449610F28DDDF919735DFB501F739CB4B
-:10780000837AFB9BE5A29C95B3380FEE7B57D4CBD4
-:10781000E50E87B8CF6167F65ED1AD75F07D134791
-:107820009F976E9E10D6DFE5A0FBB0CB0E2F3623C0
-:10783000B32CE932DD6C6E996EF1B9327DF4F473DC
-:107840007864FAE8E9973056F67F69F4D3EE1BAA1C
-:107850004CDC170DF27BA4DDDEE1376D233CF5F443
-:10786000D3D36B9443DC93E8A257913595543EE112
-:1078700099A18648BEF5F321D31E52F0BFFB27071E
-:10788000D7522B8F4345BD95CE413365096F178F76
-:10789000F301E3CA320FCD07DCD1A37F379EFD5938
-:1078A000C8FDBBEC1B486F2A7EEEF82228DD8AF269
-:1078B0003682FFFE02F9ABB4DF4D601E17EEA31A4D
-:1078C000FC56F71215CF05997BC9403C0F74517ACD
-:1078D000A778F7DB3E94D1BEBF21F4492A9EA3DDF1
-:1078E00099D73113FD0F554B5911AE5F3F72F277A7
-:1078F000179B443AC2C9FD339B8B0CCC3B1A7F8744
-:10790000C71854D0EFEAF21EBE1CEDD166939BDE81
-:1079100011BB3A5EBE9ECA47D1FBE80C43ED48C49A
-:1079200007EAD3FBDAF6E6779D8B23F4705BD3DDB1
-:1079300043F07EF1FD86E8EF7A4B1DDAFB367EBF21
-:107940006344579C8152C7188A47706736F453596D
-:10795000DC497CD4E47282A0FF73A5D309BF279BC6
-:107960001537FAEBA6196FF8C130C06FDC5195EBF3
-:107970002F71AF7BB4A8FF34F3A423BEE32E650AB6
-:10798000CE9F716F304F00495C5D4AF7E97EE79CFE
-:107990007608F935A519E409F5C859BB07AFCA8FB0
-:1079A0006991EFCB254EF11DC0FB85971C63A4CFD9
-:1079B0002E39A6EAEFC71871BF3FAE55FE3E41B75C
-:1079C000FF5CA7C99D93A5A2DC6DF9CA4878B5777D
-:1079D00030CF3A80DBBEA42F9DDBB67FC2C84E6C91
-:1079E000FFCA5818ED7EC9DD0EEEF7BADFCC487F2E
-:1079F000DF5F6AA7770ECF96965F80F6C5673FF187
-:107A00005D10CD4F1961A725F0F7E7DE043616E5C6
-:107A1000F05685D3BB36A328CABAA5C99D26879A36
-:107A2000FC6594C6F9A2DDD74C7672FB685269AE4C
-:107A30006246F9D9A730A46BDB3AC0EB3CEB768009
-:107A4000ADCB447CAA9A3EA67B58D66625EAEFF2D7
-:107A50003CE170F2FB80EB026BF1FEC5CD3089504A
-:107A60004F65986BB3A2C10FB02D64973EE070F3E1
-:107A7000770356114748ADCDC0FB086D4D93AFDC81
-:107A800000783E00F301F97BBFC94378072A18A3A9
-:107A9000FBA4C25FD76F26DBB639C2FEDDEB283808
-:107AA0008C727BD8C1EDC63E3E8F82787BFEFE573E
-:107AB00027C26FFFDC42FCEB2BEC4DADDD4907A785
-:107AC0004F89D37B00DBB3B264523E1E9FD3BDA46B
-:107AD0000FFACD81DE51EC2B6D5D4FF2313A9F48AC
-:107AE000B21B82A49CBC5EB74BBAEF1DA079A3CD9C
-:107AF00003165218BED7D7F49BD2AC841C20F7A330
-:107B0000ADF610DE3F4B2A837127633C0F2B87D7DE
-:107B1000A29E95FD5A208FF968DC337AEF8F8E5440
-:107B200084AFE93D4D5FDE9AC8F5D1AD77A9140F5A
-:107B300074ABDA6A437F6A96D73D0943D324A96EB2
-:107B4000BA97D2BF8CCFC3F89C5F2686ED0098E42D
-:107B500023BF362E88F69E2903E52905E9E5FBD0EB
-:107B600001E9F0431DCFA2B9E0B1B13EFCFE94D0D3
-:107B700013C2AE9926D6BB71EF19F83BCAD0E52CDB
-:107B8000F27D915E4F80DCFF097FBFE7FEF7548AEC
-:107B9000131AD60FA5D3687D62C6A10750CE26BCA6
-:107BA000C8F87194D00F2EF887F4B9E425DF7A4431
-:107BB000E3BBEA053DBF59C81ACEE34FB38D3A0483
-:107BC000F32D729D758AF55EE8919B8A07AEC7F921
-:107BD000A5C9D105B7788CBE083AEADB87FD948A3F
-:107BE00035FCDD9D837AE42523DE0F6B2F007E03B9
-:107BF0005D9EC4F902F44EFC247825F27D4BF3150A
-:107C00003694EF5B43935C33A04DA2B5889897C838
-:107C1000BCE4CFC903EA609C88F52414B05F578B9D
-:107C2000B29C29788FAB50F2F768BF8B070325BE53
-:107C300084F900721C798F55934FBD3C6AF2BB1ECC
-:107C40003758787E871E73488D4A0331C8C2B6BA4A
-:107C500050CF6AF6E5FAB03D9748FB8CD5C22E5A54
-:107C60006F9F662535B03F99D6F3D5B83EC1F8571A
-:107C7000A7309A07DA38F4F258F5B9810523F607E8
-:107C8000556A07DDE3ABFADCCC827D70DCBE493897
-:107C90006E8D2E23055DF474C8768AFDA6A0476C10
-:107CA0003CF35D787F36D1EA651B09CF4974CFB9C3
-:107CB000219467C5F5F6361D9EBDC06F4E34FC5449
-:107CC0007B0CFC44FCB609CCF7BB5690D7FC9BEA76
-:107CD00032F87AC15E4D8FE09F7EDE8C6DAA3E60E9
-:107CE0008E982F9A5F573F4F4634B36B90EEE34226
-:107CF0002AC3F3D79EE6CB2762BC55F19C5EED7399
-:107D00003A06A37CEE507DD54EB22F5A0D18F7B728
-:107D1000FD6946F3D9B3FFA493E21BB5F4EE7EBA36
-:107D2000664769F693BE9E663F697A57BB1FBEDD04
-:107D3000E9F363FF4A13C8278C7FBD8BEF8BF63ABC
-:107D40007CEBF07B3C8C018F92586E288BBF7F952B
-:107D5000E53F96BCC7EBE4B901E844BF9305FA7F61
-:107D600090D21D0FADFF29CE447EDE02B319F5502F
-:107D7000BF7CC63BAB64747FB2DF70E6C3F5A95F1E
-:107D80001EBFF71714EBF636A16FB574AFA3E87EEC
-:107D9000C4DFA4B28025EFBBE38DA8E27DECED4EFD
-:107DA000EF7D287FD6422F8D23D3C53C687F66AAFE
-:107DB0000D0ABE9B4C5AE956F83D6CD6F58E09E08B
-:107DC00065CE7017A09C64E23E1AEB37478FA3F58F
-:107DD00084D324D9991E168E53F504F60B76E6410A
-:107DE00033E0DD678616F74A3BB7F12848A736C768
-:107DF0001C42BAED5385DBE3899C5EFAFD00121E3E
-:107E0000F15345FE3633536D49ACEB77380D56B21E
-:107E1000E3E399A701F5D2CBCE6C712EEAA9C1FCA0
-:107E2000BFAB1DD6C4A15D727CE7C4591E15AA382C
-:107E30002FED1C8E7B2690E7C3886FDBC4CEC1B7C5
-:107E400012313A0670B9F11AA5B8381AFD9B4C12D6
-:107E5000FD6DB8CF8ED4830E33ED23DB94380FCE77
-:107E6000B3B6E50AC753B18AB841AABCFF17FA48AE
-:107E7000D3AF9DCE2CC23F9E05681FC0AC1E2BDD2C
-:107E80006317F8635C45F2EBEC8D0F6EC7F3285D6A
-:107E90001C457D9CC5C98BED74EF62CB5E1BED4B21
-:107EA0003B8BF8F97C67B385F46FAC799A86CAE0AE
-:107EB0003CF102816E1D48B734537522EABDB4F916
-:107EC0007CFEEBE9D18E03C5FDCE1F4CC168EFD51A
-:107ED000B5343DBD6F31DA65E919E9946ADFEBEC41
-:107EE0006AD47BD8C604458AD337047A14FB1C6352
-:107EF000027C3FE7FBE36B5ED675AFBD2E8ED3AF42
-:107F0000D3373EE161942B1038FA3D01ED5C53EC20
-:107F1000E7B5F8495A3F5BFCD6620CF959B768BA25
-:107F20000DD78114E6BD721E4ECA2D26B693DAE532
-:107F30004AF75DEFF58F2CC6F7C99909FC1EED27AE
-:107F40005BA6D27BE654B6CE3618E8505A64F0A051
-:107F50003FE0DCA2379D06909F45992DF928A7099F
-:107F6000265F66C218725DD17E6359893918027A1C
-:107F700025D78142203A06AE243A2E3444F50F67C5
-:107F800027F07DE75B623D494F1F50BC645464BEDF
-:107F90001FD1559323983F194B4677C5C3047E5E86
-:107FA0009410651EB49B5813BE97D0F451B2103391
-:107FB0004D1F6A729C8CF303EDB822D04FD2791F0B
-:107FC000544DEDFA3D43A5F9852FD08E755E3A8963
-:107FD000F40DCCDB1A92F35CAE3F6DA8CF22FC56B9
-:107FE000ED7B5FEF8FEF98DEFED9C70E7CD7F217DF
-:107FF000B5C381FAEBF42D7F72601CB0B76FE1FB63
-:10800000E41B75F6FF55423E8209455390AE0BFCCA
-:108010007FCF8FB4D7D81AEE7F5E1E94DFAFE2FD1C
-:10802000EF483F604583FE3E4080C72913BFCFA97C
-:10803000E7C33AC187E5BBB69933DDD8BF6F0EF60B
-:108040007F5AEC6F4E373AE83D8586CFA25D23CD4F
-:1080500068F3FFA5D922DEE9B598B85EF6CEC0F781
-:10806000393E41373D9E07F7C513BCA5F7F0F7AB86
-:108070000BA1AF35A0177DCD3C8E927E1C4BDF76D9
-:108080004F433FFAD24D0AEDE3B0FE2DB04EF8D685
-:108090006CA4773CFA712E0CC8FE1C7DBC466D3F6B
-:1080A000B04CF07F09FE1A6F4E94388ECDFC3DDD4A
-:1080B000329D7DD17928271EC7BF2641D8D9F9EC3A
-:1080C000128CDBB9E7507642B478185A7A569CF78E
-:1080D000E3BD7E4C4FFB19A55312DC3C5E57F39178
-:1080E0009B51AE2A9B76537CC47DC1F7FA8C872ABC
-:1080F00005CD5F1851A80A843D365FD8637B189779
-:108100001BB0A337A3FC5FFEB9CE8E16E3BC419330
-:10811000FB4349243737E0B886E377F59368E3BA41
-:108120003B417EFFD5DB7169E3D1C6A7955788F740
-:10813000E7FA769A9C4F1172B76447F186BE408A7F
-:10814000F57BDF1F20E2C8519C2D4D8EF472B24C9E
-:10815000F02D2C0FCD77D0B834BE81BCA78B7749DA
-:10816000E9E8CFE8492EF4FC6F33B50EC0F9AAE771
-:108170007F5B8C739FED09FC5C6389DB3B0DFD2B02
-:10818000601E6E7045D80FA7D5DA833FC579B483DA
-:10819000CB71E4BA48C6D28B265A675739DC698955
-:1081A00076C1B771F87ED112C07A5A3FA7FC35B3B9
-:1081B00006D27963EDAC8103E9DD06A55A79E9FDC4
-:1081C0001F3BD13E6DCF65E45F6873C8F81EC1C523
-:1081D000660CA69CFE2BD596AFDF421DB4A385E2AC
-:1081E000B79EFA4AF827BEB214461BE7D9046E07B9
-:1081F0006AF74F6E14F3E8C666FEDE6ED1D66233C0
-:10820000F901D6C8F7355E525CD332A1A9AF61A49B
-:1082100019F9ACE7C752CF15F40EBC1B5FD8EDC4FB
-:10822000D7A5FA776DE21ED302211F335D6E61A7D9
-:10823000F9E81DF1923A23D9F7CBDCD5B4BF59A1A7
-:10824000467F8F35C66538EF78F4E358D8A890DEBE
-:10825000D3E3BF6CC7DA0D7D198E9F8FAFFB384219
-:10826000FD48CF8871B2D6CBF9BB4CB16EFF174732
-:1082700094BC5700800000001F8B08000000000025
-:10828000000BB57C0D7854D5B5E83E73CEFC243395
-:108290004926FF21413C21111212E2908400017114
-:1082A000F24BC408030182607540518490207A5BD0
-:1082B000EFABB79990682DFA7AA358CB6DEDFD0618
-:1082C0002BAD0A4880A08126E9041403040D820A1C
-:1082D00096D68014B1053280B5587D8FB7D6DAFBBB
-:1082E00064664E92426F5F87D69D7DCE3EFBACBDED
-:1082F000FED7DA6B9F65ECD94B720E630FB7CB8C50
-:10830000E53356FBACEC65A98C2D63CAE9BE0C467F
-:10831000BF6BA9F85F67E59204C6EEC53F5568DB01
-:1083200057553278AE5CAE9985CFF56F90995982EA
-:10833000EB1EEF53C971D036498E4618C71E379EC3
-:10834000EEB33066817FD746D33C8C25E0FCFCD76A
-:1083500023B1A75260FEB38AFFBD0878EE2CC0E1BE
-:1083600081799678F873F47EF8FF32C78C2F2478E1
-:10837000DFFDEDF229730E5E5D6D32C0F8A52F4969
-:108380006C1D8CBFFF69DD78B12EFD3A1EDAF0A3BB
-:10839000B9E91981710F7B9F0BE9C3DA5456C0D834
-:1083A0007D023EF6EA7F05EE73F84DAE08C632ED6B
-:1083B000117167B3A05BC0265D4B63ACCE1A99C345
-:1083C000A2A03533C2233B64F46E02B8D644C08207
-:1083D00001CE355BA3BD1EC4E3EA68C646C0B8F64D
-:1083E0008D26B70DE6C4DFED8C9DAB6F9E9B9E0E78
-:1083F000EBAF7F7A6EBAC2D82CBB9DB189408FB6E5
-:10840000E7685CB7E29A6487FE2A4BDF8FEF5683FA
-:10841000F03899D363995C696286C07CFA7659B367
-:10842000F1CBBEA0751621FC56F86312C02FFF3D9C
-:10843000F8D5C4685B006EFDBC7FAADF1002F74A66
-:1084400085395B6C81F568E326DA0DB41EFDF37A9D
-:108450007A30E6A5717ABAAC443A04D117E15400F7
-:10846000AF3D1D56EF5A89F888E0F6748411DC1789
-:1084700093D6CD3D93C7D8617C00E0AE1DF132F5B7
-:108480005F515C6E7B3C5EF48F728DC76762199B97
-:10849000323CDE6046C6607C2ECE0FE3768539F333
-:1084A000988CD75DB1C807D31BFAAA2C40AA3AFB17
-:1084B000A40A05DE33FDB9BEAA30E83F629FCCFBBB
-:1084C0009BFA8E5A1C8C35B02915A5F0FC63700FF1
-:1084D000E7BB5E9B6F762D66C0573580534B0CB45F
-:1084E000C7C6BC8DF256D35B59214542CB984FCAC3
-:1084F000057E7046FAAC39D4678530AE33CAFD1FAD
-:10850000B8BE55579B2EC938EE98C2E5A53B8EF0F4
-:10851000A000EC61F05C53B853B503BE9A622C8E98
-:10852000C654BAEE098BC1BE535583AE6BF4C0E797
-:10853000108E2603734643DB75604C545FF6F0786B
-:10854000EBAA57AB14A0FFBEFA0C6AF5F78B4CF6FA
-:1085500074073C5F6460EE16DBE0FBAF22BF109D4A
-:10856000D414A4736DB789E41C7F12F0FD2AA1878F
-:108570006A81405100CFAA63CC171E89E3CABF505D
-:10858000B06D95D8E910BE6281BE3C3CDC37DAD6CE
-:10859000E27C4A309F703C152BA9554AD07B4B6D2D
-:1085A00099217D39D19081EB6172B86313E0574E08
-:1085B00031ACDE01EB976F8616F0A1D81DF2126880
-:1085C0009B4BA6CB4BA16D34B2852DD81AD8F26047
-:1085D0003C750879D2DA4B76D76F90EE17DEEF2D27
-:1085E000B0929E1A6927F916EB6D941C3ED4439EF7
-:1085F0002EE6D804D79A6417E37CDCC2908F7F2FD5
-:10860000E671980D3B55E0D7F7EC0F12FF3AA20C3C
-:108610008FA642FFA3E615150AF0AF23C5702515F6
-:1086200078F478F34ADECF325C190DFD4F9A6B78FF
-:108630007F2A4C99CCD8C9E655159E6C9C97EB3196
-:10864000B6C59985EF510C12C9A9B2D7E46D843F24
-:108650009B22393F3519812F6370BC4AE39F6A28FA
-:10866000DE6C05FE578A9DEA6A1BC735F2C3FFB46C
-:10867000D5F0285B0DAB118FD822BECF88756B74F7
-:1086800060ADCEAC39A8175A9C59732310AFEECF0A
-:1086900011AF793DBDD3510FB77EF049813B9BD3DC
-:1086A0000BE7C9EB612C12D673E1AD9B36CA528041
-:1086B0003E97EC45E7515F4BA0A61F877549AA9DE1
-:1086C000DD0372D7E864AA09D695C85EB2A3FD306F
-:1086D000207D4005B532AE5F3AA35C5FE2736CA4C7
-:1086E0008FEC4CB5DDF515BE5FD3CFAC3766483D9A
-:1086F000ACD757A69CC765067C1093D2767C29EA36
-:10870000F3DF9A1DB7A8088F933D0E706C33308548
-:10871000C5107B642870DFCAC21DEB50DE1D2CC95A
-:1087200003F2856823E0E01707F6D02864485B076A
-:108730003C5FCAA09D8470DD4AEB92919F263097E2
-:108740008C7AAB8079ADD8F677BC9584F87A3E8C7C
-:10875000DDE782D6F22A737A83F4467EB444F89F2A
-:108760001563A436DCD83217F934FC12B3A31FD03A
-:10877000FF0B9382F38360DC89D71DFB0D0CE1FCBA
-:10878000B5D16B8F82BE3F53515F6681F9FA059D6B
-:10879000B5799F37A999D1D0AF8A91082FBF2EE222
-:1087A000F6D8FF85C9FB722AE2C7B2DA1B2457E369
-:1087B000A3F9B8BAB8E2B1D1F07C4B4738C3F74F50
-:1087C000EA0C3720FE376FC90D433ED886B881F5D5
-:1087D000C798ED8FE07C315700DE54BAEE24BC2AF6
-:1087E000EA8428C06BE14C9BBA0EF0FEEBB0969980
-:1087F000C8F7FEAD06F632BC629BC93107FBDB2E23
-:10880000AB76D4B3BF4E6D09A7F56C35D07AB6857B
-:10881000FBC7AD01B8D7652815089F62650AEA5FF6
-:10882000C550AC3E02D7A74573FDA8E9E39A689509
-:10883000FACF4BF0FE5C1C5744725326DB48DEFA3D
-:10884000FDCC6B86F7C4CFEB95911EE173809590BC
-:10885000DF159FCC703E17121A5A9BD1AB929E75B2
-:10886000DA9600DDA70B3D3BFD644D258BC48EE3FE
-:10887000D854986F9FCDC8705DB7B13ED902FDDB6B
-:10888000AE32870FF9E7AA427E981DFE05FB7B6595
-:10889000629E5F494C898271455FAA0AF257110BAB
-:1088A000F5DBCA36947F81F6ADC4A2BB8EFE5C2494
-:1088B000B64AE03ACCB3285AF861A3D8A86BA4CF43
-:1088C00060D6046147555C7FF67FE1BAFA2B4C0E07
-:1088D0005CFF769BF3E3A9A8077B8D6C131B5E8E70
-:1088E0007E550F1A7D0C08C7D570E68D253EB42144
-:1088F000FDC76D68F684C17AC7A5F3F991DF506FA3
-:108900008CFD455C2CEAED8868AE4FB456E32FE44D
-:10891000237B14E723FBAD01F9FB5E742A8DD3E4BE
-:1089200009F90BE7D963F42E760D6117812FBF8704
-:108930007CB9DDC62A90CF9F19615988F2A4BD6722
-:10894000B7E07B7DFB54C39A2E23AEFB2FA0FF0123
-:10895000EED2E4ABA660FBDD15C7E12D93BF25BFCA
-:10896000FA62BB44FE7C423BD7D7C17C316268BE11
-:108970007801F17A3DBED0C7011A5FECB81E5F7472
-:10898000FF637CF18B68E1DF0ECB17DF46E2FA1F55
-:10899000EB2849647FC78F69137C30DCFD2956AE14
-:1089A000D7F4D7DB053E779B9AEFCC41B9BFCBE03C
-:1089B00040B906AAA7CC05FBB23B9C3FC794D5693A
-:1089C000D8DFAE703DB2BDDD4C7A64BBCDED267B09
-:1089D0009D6461E82730C5DDF77DD47FC916755DDC
-:1089E00010DF3E2EF4408BD137E573F47F0F70FA21
-:1089F0004EBE2B5736C1B8110F70B9CE3F67DA287B
-:108A0000C33CD53145BE6818DF17CDED62DD1918BE
-:108A1000057C597BC644FAEDADCE23E54E1BF937F4
-:108A20004EE4AF497B8E941767E378CE47DDA2D53D
-:108A3000FA53704D3164768E25017E5DC24E4C61D5
-:108A40005C0FB9903F72027DE634523CA6F141358D
-:108A500063596827E6F639CA908DAA2A42E95BED88
-:108A60009B4971DFFCE3CEB20858D77C97EEBEA0DD
-:108A70007FB58EFEE007FF01E564D5E6DE4E1BF212
-:108A8000ADCAED698B697516F77B56A7A1FFAFC913
-:108A900011FD004F2DBFCF78795D901D5763F83AD7
-:108AA0009F752874DFD367F2DE0297FE37E3CFB5F8
-:108AB000087BF3AD90E3DCC7DE588CFC9BB7DCB9D8
-:108AC0000FF1BF284EA6EBFFC97C9634A48F43213B
-:108AD000FFABC5A8967C2E05C631C5956183FB7B8F
-:108AE000E2C3F3F0FDD531EE6B4827A6F8BBF1B930
-:108AF0004985B9792857B6094DB1687F34B801AEB8
-:108B00008A4DB6001C1A5CE785FEA98E59720DF1DC
-:108B100080CFA15E693B75D682CF6B746FE9B8C414
-:108B2000E91D447FA47780FED27DD8D7F06011ADD7
-:108B3000D6FFE7E9EF1B89F41896FE18F747FE8F7A
-:108B4000E83F2A6608FA833F958ED7357FAAC50489
-:108B50007E7576A0AFD1BDDA5E44E31C265819FAC3
-:108B60004F9D1057A21CBAA3D1B9613BEDFC5DFD2E
-:108B7000BF3F3B0A5C4036292686CB93C93F06FDA2
-:108B80008D093E89FCBE0920F0F7909F3592F49D37
-:108B900043E0879D95A4B319DC05BF9682FE9F2F05
-:108BA00016E56082B9D287FCBEC33A3D05FDB75CCD
-:108BB000EBB434E4A737331E3B8426E7CDE4E53B32
-:108BC0005F51037E8EA6D7F68969B5F797C770FA0D
-:108BD000DF0E6A16FD3D740D83E1D0F4379205E196
-:108BE000907CD5866B56D2C7ED7D80AFDB110EC071
-:108BF0006B97C45A517F17199C7125E88FC5FB14D8
-:108C0000EED77D3D4A05BEA96C7FF738C25B69B1DE
-:108C1000F930DFC21CC6F37D41F912BD9FABF925C7
-:108C20009ADFAFF92D5A7C89FE0DDECFC7EB00BF6E
-:108C3000DD0C00A2FDF159BC0DF0FEE72FAB994E03
-:108C400021AF0AACA352AC6336EB25B8D8B7D7AE88
-:108C50004D03FACC12F8A8EC86B83007EF3376173C
-:108C6000E0E12E85C78B7739203E0CE2A3D99343F0
-:108C7000FBF89B9E1098E77AE3F5FA7FAAC817FCE9
-:108C8000B371A6D676831D3A0D0C70B09EC734859D
-:108C9000A3658F82F1803BD380FC5827EC1A84C9EE
-:108CA00043DB2321AF8586BE1C07E0B76BCF37645B
-:108CB000FFF6EEF9E623F4E7A67CA130333C5FF83B
-:108CC000457E14EA07E60A9DB7EE8FAD56C6AF1390
-:108CD000FFD48AB5EFAFC78C18C267A1F637E79FFC
-:108CE0005F8FF37D7946E1BC2DDE5F6E72A7DB6D91
-:108CF000D8F2787FBFC4FD1DEDFE7E23C00DD737AF
-:108D0000C568717FAF42F919F89983E87C17C6FBF3
-:108D1000B901BADE75AEE20B2567307DF0F7FF23AF
-:108D2000DED7E2FCB744FCC0F69D30A900D78CD654
-:108D30004714F4A36724C9CC19F4DE3B542B730603
-:108D4000C5FB6FC4E8FC907DAFAD9F0576A4AE4730
-:108D50007684A1BCB66F3F9483FD5ED9611D828F7E
-:108D6000F4F89DD1FE8882FC9F10CBE5E67AEF2FC8
-:108D70001C077C722BD29D911F77B1402239D2D330
-:108D800077EF9E9FC7F6650F8FEFE1E8AFA7C36F40
-:108D9000CE1747215EAE470F3DDF76C23A3DB03E6B
-:108DA0001FACD303FED6DE7A3BF5DFAE4FA2BEC6C4
-:108DB000AF751DBF8C457F4DE3D3B258CE37537688
-:108DC000AF8F65B600BD347C5D1474AB668EF9B3AD
-:108DD000E0CF5D922382F48487F5261504EC55F5E7
-:108DE000B172F233347B552D671B51FF6AF60AD3FB
-:108DF000C2A8CFF4F6697E7A9111D5AADE2EC102FF
-:108E00008DC8BFD50B43AF57F4342B11D433109D0D
-:108E10002449E043F8D51A3C1F3217C1ABA7A70677
-:108E20009F1E2ECD9FAE1674837596E1D2E7AA459C
-:108E3000B48E417655ACF746EDA9393634CEBA72C8
-:108E4000AEF4FD9C21F87538BED5DFD7F44039BEAD
-:108E500020975A0FFA1109B10944AFF2AB26E60484
-:108E60007BC14686B1CF82F3EFAF6492BD7B54D80D
-:108E7000DFE1F8A6F6AA81B96303FC636C7BCE8AB6
-:108E8000FCB35B69B662DEF136DB9CC628C053E9F1
-:108E90001F8BE7A15F57D76760989A2A6BBFB40F03
-:108EA000E3F6BAE3CC81FAB0B8BDAB04F9ED6DA539
-:108EB00057A638FA4BC69E0BF20FDBDA1BADE83F24
-:108EC000B5C5C914A7EF8FE6FCA8DD6F89E5FCD70F
-:108ED00076E6F22CE710F73F13F74B4FE51AD1482F
-:108EE000F6C74750BEA1FC6903ADBF54B25755A2A7
-:108EF000FF718791FC7A885BFEF07DCC37B599B71E
-:108F000063AABEACED878FD881102DFFE7B306337F
-:108F1000E60FE6488E97615CB9EAEFC27EF9BC5471
-:108F2000DA8799F47F65F25FFD774B94F72807762F
-:108F3000C17EF93DA95ECC3FEC9178DFD3C1F3FE51
-:108F4000CCEE899D05EFF9A03276C23AE229AD7FD9
-:108F50004BEE3A261838289E7A6C17DF3F7AAC4CD5
-:108F6000A2FDA3327B0AF304F155F9D340CF3CE0D4
-:108F7000C7F6C462E4DFAA0A997983F87ABECBCA3D
-:108F8000BC41E3F7877178FC92D98BF9124D5E678B
-:108F90000AFEAE5E181B327E0EE37EE242D66C44C1
-:108FA000F9AE13F0D415013CF0FC4C11A7DEED4EE8
-:108FB00009796F256641606856DC68B28FB3BFECF3
-:108FC00023B33A473E796C31BC876570F9D0E4AC85
-:108FD0004CAE69223E48921C181FCF97C0AB9451EB
-:108FE000DF85CAD1ECC9A1FD394EBD7E089577BD9C
-:108FF0001ED7E47C7E876CC4387A7E91E46043E8B7
-:1090000003BD3FADD703930C8E7730AE9E7BD54921
-:10901000FC35480F9CACF887F4C05B205B93415E45
-:109020007FA4E9839BD84DA80FCAE42DEB913FFAAA
-:10903000C1AE9987E00FCD2E68F17639C827F203CB
-:109040003BCFF725CAAE829CC606E2ED01FD007E4D
-:109050008363087FE657B16921FB4903FA22C86F91
-:109060003016FCF37E4319F88BA65C846F24F3E47E
-:10907000919EA2FC1EB43ECAB3255DA23C4A1DC40B
-:10908000F114CFB35F125CA8D7A49800DFEBFD0901
-:109090002D4F3B42E409F4FC3090B79B67F4229FCC
-:1090A00069FC506EE772513E4FA6FCB99E3FB4F783
-:1090B0005D8F2F7C12F085F477F842C8D38DF2C50E
-:1090C000218D1FD259FA8DF083C6071A5FE8EDC5CE
-:1090D000415DDE65387B71F23AF6E29D0C23E9656D
-:1090E000BD9DD0ECC28138AE7FC7C7F27D8A999909
-:1090F000F36DE8578C407D80FE9EB0370379A30D59
-:109100009C0FDEE95BAA486837500FA406E15DE4D6
-:109110004D35BEAB7D9A51FEB052E89F8B1D3C9FF2
-:1091200056572A7B2DF06749FB73EB79DF48F9B678
-:1091300022A54BB1C0BCB31D9203F3354E917F9B6A
-:1091400075D5E455293F3FF47E7A95E01B8C73700A
-:10915000FC6CA7E4851074901EAABACAEDBE5E1F0F
-:109160005589FDF22ADD7EB9294ED0F56676F3BF2A
-:10917000D2EEC7C72570B919868EDAF31A1D35FAF3
-:109180004DC0B1283FFBBE36A911DC3F46FACDB831
-:10919000AAD03CA3E242FD962FCFE7FE27C574621A
-:1091A0007C5DFB25937BFCF0F05FCF2FBD59F3C3B3
-:1091B000855FAEBD7726C8780A3A863AFBA1BDE73F
-:1091C000BAF6423CAFA7D3E4B8D07842A387A6470B
-:1091D00007E15BE8D9E1E8753D3DABE9B37FB59EBA
-:1091E000D5E6D7EC80F65EBDFE1D2E3ED3F4E953E6
-:1091F0001B0D9417B94DC4C1B7893CEB8342CE9780
-:109200000B7DDBFF178B01FDAC6D9DDC1F7198EDB5
-:1092100087D06F08E4F3385D9F8C601EDC2F674AAF
-:10922000AF85F62F8B81A4B87F99CCF72FB7283E56
-:1092300017E96987C21A405EFE2AF2164FEEF52C36
-:10924000463DFDE4E93106DA47577CBD18174FCAA1
-:1092500055683F28DAAC52BEF76287D98ECFF5EF5A
-:10926000FE5E9711E7F90B7360A8F6768779603F89
-:1092700006F54299DC23635EBEDF0FBE388C9FB6D5
-:10928000D05782F1CE6DACB711E3EA42A4E310F4FB
-:109290007B55675FF479FB920EEE279544F0BA9FF9
-:1092A000E980467CEFF43613F985D7CBDB177DC90F
-:1092B000C85F1A94AF6FE37A0606119FDC68DEBEC2
-:1092C000107D3DE0E39FE8F40E1B267FBFCDC4F781
-:1092D00073FC478C0CFD5E762E6EC8BCCBF5F2F8A5
-:1092E000BB3BC39D6A24EEBB71FF7C7767B253CD55
-:1092F000197E7C4E9FBF18F395DBB6CC55284E14D3
-:10930000F9CF41FB223AFCED90589315F369ED8EAD
-:10931000528C3F86DBE728F63B69DE1BC51B63CD1D
-:109320009CCEA27EE9762163DBCE863B91BFB79DC2
-:109330004D76223CBB057F6AFCBEFBCCE570DACFE4
-:10934000343955DC07F6475B1C2F13BF723E6F198B
-:1093500031C68BFBADDB853C6C0BF71FCC8A0BDE7B
-:10936000CFE0FB179DF59EAA33E9B4DF2D61BE5116
-:10937000DB27F680BC505D4E0C237E32B21686EFA2
-:109380006D74B29F633B7D9A1A85F8BE1CA7ED47AA
-:10939000AA519467F8F64A816BFC60BCEFA877513C
-:1093A0003D496BFDC22A05607CB3DE4D6D5BFD72ED
-:1093B0006AF7D4AFA6FB6B0F453E8E76BFCEB9A041
-:1093C0004A09D21B9FC5F3FC526ED6E912E473F62C
-:1093D0000D6318EF4C7FA24F463D71FB555847482F
-:1093E000DD887219F14CF9CBB4403F555A12867C96
-:1093F00079FB55E8078D97E2A3391D9A94A65B0A7D
-:10940000485A881FC2E29D17E3E0FA0FED2E7F5CF9
-:109410003CF241F5BE0B8CFA97F1FA0EE96EF902B7
-:109420008CCBF31551DE380FF3C6B934ED62C4DFCF
-:10943000C42E13ED7B6BF9DB5C31AFF3ABD03C7228
-:109440009EC8DBBEC9FA289F9C6F81C0CA8070711C
-:10945000FA39A5F94912E6FBE24D0EAC579898E6A9
-:10946000CAC37C6B573CA3FC695757C24815F0E050
-:1094700054785ED7A9E575D9DFCFEB767F1AE9215D
-:109480007D057E0AEAA7EEA3910E1FEDFF59C8FFE6
-:10949000DB810F627D4338AF1760F3E6511EFD7626
-:1094A0000B5F07D89FF878CAFBF9F61D86E77E7B2D
-:1094B00099F17DC4DE93B43F5D62C84CEC0338F78C
-:1094C0004963A3B07DF1D3C86C6A8F469E47FC7494
-:1094D0001AAC2ABEF7C37A56857567CEF76DB49F6E
-:1094E00031FD7D9B82EDE1FA3EAA477BBFFE1CB5B4
-:1094F00047EAFDD41EADBF4AED3B701DF9E7103CB5
-:109500008F6DEEE2087A6EC7A20813C2DB19C9B6E6
-:1095100068EFC17A335FB8AF1593F9EFC57FBECE60
-:109520007213D83BB37BBC3481B113F19FCF54A0ED
-:109530007F68C6A87FFF0BDCFFDD4F2EACB3005C5D
-:10954000F38EDA5A7BA0FFE94F2EAEB3A19E3D14F5
-:109550000ECA0EF546FF4190749687363D99710507
-:109560003B19FAB1A2EFE99F590A245F50D297C57F
-:1095700080B5A6FCC43FD302785C6075FF1BF64D36
-:109580009E976696DE847DE6C17A2EBF64A4F89E1F
-:109590008D94E2B07E6599DD7D2C3EC87E3BA53F73
-:1095A000D2FE51815362D1714457DACF62F653B182
-:1095B000C1F2B6CC5E760CE971473CDFBF9A384DFC
-:1095C0007206D749E8C74D3CA396229D0ACE95372F
-:1095D000613BBB229AFAAE85939A509E4B6DC33D78
-:1095E0005F42CF2F8837127F162B52487D887E5CD2
-:1095F0001E3013FAC7FE03E194179878CCDD887506
-:10960000A36549A9B9B2D0798CFAD11B711F6D62DB
-:10961000E587A5B1283F36C981E6A180F535C5C6E5
-:1096200061FD231644E1BA9E2BC1FA9D89AAE4404C
-:10963000B41539BB5AF1F9224784A308FDF1636AD6
-:10964000299A9CA3CA84C3F9306E46BAECB0C044D0
-:10965000477D774CBD00FDA28C28CAE31629ABAF2D
-:109660001CA67E84A341C5756CFC792DCD63267B39
-:10967000BE6356C97F20FF14BBA228E7576A3B355B
-:1096800037B82E0CD64D7017D9656F9884FCFD83C2
-:10969000523BF4778C9218CACF515FE69FE97E77F0
-:1096A000B81A0680EE30D94B71BE1D26C9BE96FA97
-:1096B000AE121CEF196354314F541EF745C8FC33EA
-:1096C0004AA5296710FEECA80978AD62E4A590FBD5
-:1096D0003D8BAC64272ADFCF267FA867510AD98B40
-:1096E000CAF7A71563DB63E07E7AE5FB951574DFA7
-:1096F000C0E3DFCAC5DF718A3EC5BB958B5751BF3A
-:109700004B4AFC777CDF95ECA85CCCA3CD4CFF7A70
-:10971000AE12ECFFADCE24F9CF1579BC2243E6FAA8
-:109720006900FFA307F83E4465B6145237372BFF94
-:1097300054483DA86BDA1721FDB9A59742EA43E7E3
-:10974000557E1DD25F304FAA0A1E5F7A209FEC6BB8
-:10975000BEA85FD2F24B458285DEA9CFA82A05B903
-:109760003C00ED03A01F8A7A45DE55E1717506FCC9
-:10977000433D586AD3E577994AFBD915DD7CDFBABA
-:109780003CCE783AD83E54C84F707F41B7FEDC03D8
-:1097900046B293B9D132E5AB34F82A46863EAFF9EA
-:1097A0005F1502CE1D0677530CE5C79CBDE87F68A8
-:1097B000F06BEFD7E0AE90EF29A5EDBFEBC0AF8720
-:1097C000170025FF4D0FC78178118780BF41FE59D3
-:1097D00037AF4B835FDC50765BF3CF2B414F4507B0
-:1097E000EB299B1487F576C3E9296DDEE1FC306D2A
-:1097F000DE6576173DEFDCFAD9D14239A89F7A2A87
-:109800003626B8FFDA67EB43EEC79FAA8A0EEE6FE3
-:10981000FAAC0AEF4F57D4461BF0E34126393CC857
-:109820009F3DAA82FBCF25C79C4DD8969D74639916
-:10983000299B71C6D384EDD4F3DE1E33ACEB8E0CC2
-:1098400059C5B85DF33FF4F09A13781C72F0AA6A18
-:10985000C5FDD31D1ED58AFEFB8E27542BFA1F3B58
-:109860009CAC02E331679A6135FAF3CE2C5E6778DF
-:1098700055E8E16FE2F9F35A7B5A717F837A11EB75
-:10988000C2D127A8FDDA4F75E007D1AFCA1EEC5749
-:109890001D54BC367CDFC127BCB6E07DC21BF5ABD6
-:1098A000FE8C363A1EF96C4E887C9658EEAE0A96BF
-:1098B000EF32FB9290FB9FC6A904FF8CA48743C69E
-:1098C000DDA13E12D2077F3103FD914613A33A5921
-:1098D0008F81D7C9EAF1F8A8C0A3C36647378619B4
-:1098E000E354AA6BD38F739470FCE9AFA727F0B849
-:1098F0006823C80CB6F72470F8F475B1FA3EC47C3E
-:109900000B713E983909F9DC61355C0157973913C1
-:1099100092EEA47AD93CC3A369D0AF4EC8E2FDA9A8
-:10992000869D581F7B774236EFDF6AC833821FF06F
-:109930002B36FE4EAC07AF0D13759D0F24D27E98CB
-:1099400016DF2886532F2EC638738F9161FEFE19BD
-:1099500013D8BDDCC0BEB9D5CCE352AB89D76D3FBF
-:10996000957AF429D41B6A987B7A02F951C52AE2C8
-:10997000EFBCDD42759D8FED2E4B44FADF93C0F3B3
-:109980005C593BA726A17EF917BC7F56C2C4E1DF14
-:109990008F75BE38CFF91D59E47F67DD0CE895025D
-:1099A000F887F098AE87419840E725983309F36C23
-:1099B0008DD1269AE79E04CE7F37DA0EAAFB8D3230
-:1099C000ACDE0EEDFD82FE0FE07B095FFE51737091
-:1099D00063CEEE1F35773CEF237D6539D78F7EACA4
-:1099E000FF3B11B4AFC246FA69FFE5E37BB21CE866
-:1099F0009F7E12CEF1B7D03BBAB14FC5FA0DEF4DF5
-:109A0000582F9191E8AE453C2C327B6F21FEB1ADD1
-:109A10008EC0F96FB41E78F07B218004FA544FE1B8
-:109A2000F4D1DE0B38B5A03DF8589C03D1E080F7A7
-:109A3000FF00F9408367000E5D5DB89667AEFBA33B
-:109A400081F20C7512E83DE8EF3CC91C1E98E7A2B4
-:109A5000E6AF8BBC266E45E17BA61C5E5A62833660
-:109A6000BF6D258F737B95903CD7A4E38A7EBF831F
-:109A7000ECD654ED795D9E71AA886BA7EAE2DA17FD
-:109A800013849D4966C9C1798035226EB8DC333AAA
-:109A90000AFD4CD45132E0D5A4CA6C724C40CE5B66
-:109AA00021EE674171BFC667E38FD9EF47B8C71F83
-:109AB00063F7915DD7E61DC82F70BC5C3ECEF132D6
-:109AC000A12FE3A7D3A06FEC3632AF1A584F21076E
-:109AD000955DC6FFE078BBC98B75CB05077E99E71E
-:109AE000834BE624035383F010A6863335482F5A60
-:109AF000336242FAB2866F61CFF3C4FC118EE490F8
-:109B000079F6C49477A37DCFB32D27FB1E357974E6
-:109B1000C83CAC4709B1F3B028DABF9C0840FD0C43
-:109B2000F05A704C09B1E793E23CB86236F9A4A24E
-:109B3000B3FFCD32CA41E199D0EB0786A3CB70F8D1
-:109B400063393F45FFEE1FC55FB433147FB115A1E4
-:109B5000F88B7785E22F7161289E46B843F192B267
-:109B60007C5CC8FD9B56E786F46F7EBC30647C2A23
-:109B700018A4E07EDAD33343C6DFD23C37A43F7665
-:109B8000C3A290F199DEA521F7B35E5D7143F41E87
-:109B9000DFB226649C9EDEB7B6FDAF9079357A7B46
-:109BA000E0DFBF82DEE6C4507AA70AFD1AEDE4F5D5
-:109BB00065FD46DBD312E8234C13A15E8B6E7FF765
-:109BC0006BCC43788A55AA9FF3CC64B40FFD82EC2A
-:109BD00092500FA5C0148634AA5FA7FABB1F1B0CB6
-:109BE00021FBE28989DCBE2726F27CCDCF4DFCDC4F
-:109BF000520AF88F64870C2C102F031E22315EA6A8
-:109C000078FAC7CF60BCDC14DD97A1427C6CC6FE3D
-:109C10004D017DB9C8AC36F6013E26C85C1F829E58
-:109C20004C4B84F93F919E30723FC263443F22C542
-:109C3000C23C91B9643F287F1CCDE224ACC78F0A97
-:109C4000E869F51A106BDF8A2C3A07F51E4282FE8E
-:109C5000AF2586ECE8DD9A7E5A9E49FAE9B22DD40A
-:109C60000FBBFC401A5D3F71AF99F6FB4F883A4439
-:109C70006DFDE784DEFA53BD85DAF3F5F6103DB6E7
-:109C80007CE3FA08F41F4F64707F51BB5E82789BBF
-:109C900088AD2CEC9AC58EF9AC7BC0384701BE5715
-:109CA00075F7452E62E43716E3BA6B375EB9F74DA8
-:109CB000E8D719FC09DC3E7878BDCCC78CFCCFEA2C
-:109CC0006F5888FF343791C7E973C5FC0BA0B10307
-:109CD0009E1600FEA3B17D775A39F2275CA7F3697F
-:109CE000B3BB19D59FCC71A7D23EE351E6F87017EC
-:109CF00080F89D4495E09CC75CB45FFFD1BDAB226A
-:109D000070DCC07CDA3CC028E86F7C1CED3126603A
-:109D1000DC7F1BAF6F80F759F0BAEB9E9427D10E12
-:109D200069EFFB88B92F7C88FBDDCC41F36AF33304
-:109D30001613A29F762C5FF9692CBC6FCD0103E549
-:109D400013D6749829EEEA5FF1D7AD2FC2FDFB520E
-:109D5000FA6E42BBFCC98A6FC6203FDCBD01F4101D
-:109D6000ACB130CAFD7062509C72E2812B11781F39
-:109D7000ECEBA617D1386E36537DEF272B368F09C3
-:109D8000F6471F4D2CAAC5E7D8E41B3B6F58F27A63
-:109D90006622D563097E7A58F0D39AD7C6921FB54A
-:109DA0002662809F787F13AFEFD0D6F1A1E0C71570
-:109DB000AF7F5D107CCE7407F0913A86EF6BA920DF
-:109DC000533B7B2EE7E0FD57147713C2D779F57428
-:109DD00024F677BEF737829FCDBB317851063D051B
-:109DE00081FD65EDDCE5C2F6D83CA43BC85933CE15
-:109DF000BFE837AF5DF81DE2A763F3A6EFE3981B5A
-:109E00003C7FC9847D71083C807DA1F8A09F85F3CB
-:109E1000731D428F2AB8839E86E7991C2AF1B3935B
-:109E20001DC27D97C62E03C3BA9548DCB409CAB3D8
-:109E300045CA06CD08392D49A09F855E7925F1E4F4
-:109E40009D4DE4E787FA3DF96FAF08F1775CF08F3D
-:109E5000FC9D97DC8D9807BAAEDFE3332C3145DDEE
-:109E6000B8FF0381B0532A105B38F06B4B14FB2210
-:109E7000420F77A21C61FD3FCE85F97A5F383F67BC
-:109E80000CA602F5F80F604DF8B02945B4D2C50C08
-:109E90000BE8C5BD897F78E669D0939674BE5EEC09
-:109EA00037E2DFDD9CDF06FCABB7C7919E62DFC205
-:109EB000DB100F225FA1A7533EC8078B0D9233F131
-:109EC000BC6FFFDF22314FBB35467D1FE9E03F20ED
-:109ED000D33E4D98D2678A1E222E7B13F59E89FBB6
-:109EE0004D546FDEC6F38116D5C9300E08B3DB279B
-:109EF000049FB36B17FA6ED5FE4F4699800E170C70
-:109F00003D91D9307FCDAE1D91E8C6DF6B747F8A5D
-:109F10007CB7F2C40705763ACFB671149D03F08D75
-:109F2000A6BA83F10AF328B983E1A8DB904BC6B83F
-:109F3000760325E3D9F8F6BC87501FD5F9F83A71B6
-:109F40006E2CFCCB6C63D4BFD8D61883F3D5FDB68A
-:109F50002319E567733C8F135FBF3A8E3FAF30051F
-:109F6000C77F99182DF8D96BC03863B3884F2E5E20
-:109F700035D038EDFDE3DB8A643BF043B6AF792F93
-:109F8000C543ED6615E91AF60AE378680F2339AF81
-:109F9000EB9CC1309FDF1FCD1C12DCDF1AEEFF03EC
-:109FA0009D33EB30AB981F0DB337B318987FABD808
-:109FB0000FCD048EC2F34ADA75ED7D61ED3FC558D1
-:109FC00002F981F2B4614A33BBCD168CE708C27343
-:109FD0003CF2533CBEC767C0FC88FF16C65E26B87D
-:109FE0000270327AAF066726F9735B4DFEB3787E56
-:109FF00005E0B223FD33198793B58F5531BE0FB3FA
-:10A000003B691D6176D5E19106C35597C3BC68BF16
-:10A010007FBC960DC82BCA6F5D78A06F0119D83A26
-:10A020009A09F9B63F5B3A2DB80F8A6472E0F9716C
-:10A030001B629E6D1A49718347C63816DA88185C10
-:10A04000A7CACF3B636A2897E301F7C5AD167E7FA9
-:10A05000603CF0B70DFB363ECE1165B7CE94484E4E
-:10A0600028AF572BE4FD31C977F67690D3BFF8F6C9
-:10A07000E6A8004BCDBB7B884F571ADA5F1C0FF761
-:10A08000375ADCF94980CFB74E1AE81CE99F5E0BBE
-:10A09000F35662FCB87B63827308F9D0CFFFC3E349
-:10A0A0006B9F4F41FAEF9654CC9BF61BFDA310DE3D
-:10A0B000DAF6CF4D548FD0768AEA938E24B99DF884
-:10A0C0009EC96D0DB46F3C8535D3BE7196387FDD6A
-:10A0D00092C4F5C7E563635E6E08C2FF8349DC0F77
-:10A0E000637EF7CD2837ED423E3BD12F817697F046
-:10A0F0008F7675DD9DA606E5FD1AD8DE14C4F75AE5
-:10A10000F636B5DAF57E2F3FCF98F591E53E67102C
-:10A11000FFB993B89FE716EFF327B91724A1DC76B0
-:10A120009D3645AA785EA56514DA9116F09FEC433A
-:10A13000E065406E757254A7F84D38BEEE1C3F774F
-:10A140000A746EC2FAFFCD1FB58D5B02D77701AEE0
-:10A15000B1DED373C24C758FBB8CAE141CDFF0E143
-:10A160005739A8B72A1069F0BFAF3A56DE8C78038A
-:10A17000BE2F0E47F9DACE488F69F2998DF209CFDA
-:10A180006723DFE7633F93F4F056532F3FF7B98B14
-:10A190009FFB04BE273900BEB7A39F906D0739A06F
-:10A1A000E7C7927C6FED35D0F9540FE8F15BA85FFB
-:10A1B0005C85FDADBDA576926FCCC3E7A29CFAF697
-:10A1C000D23C2D108320E924E60AF61FDB132389F5
-:10A1D0008F35FD783091EBFF960C350AEBFFADB271
-:10A1E0001C2217417690F7859DECDD50FCEC0BD3DB
-:10A1F000D0DE09BB20FC27769CEBF94785AD5AF3EE
-:10A200004EE1EC2DB0CE3587E5817A6EF4577D8234
-:10A210004FF60AFF15ED849AC7EB67F0FAC40DBC40
-:10A22000CEB5C0B9BA04CB38265734EFC3B6D0D5B3
-:10A230005282678EA72DECDDC7CF1EF3F3E3AD7B13
-:10A24000EFC8C27DEAFE136686FB24AD7FF3FFE113
-:10A2500075C0C3773B01FF43D825580EF11F58EA5C
-:10A26000149634F87EBFA4E98FF995286F175BE543
-:10A27000401FEC612D3038F67F9D54F5AC07004B44
-:10A280001BE17C1D59A230D94D6DFF91BF25A02D3A
-:10A29000D8758CFB4DAD266716F24FEBE8D0F3FA7C
-:10A2A0005AFB62123FE79C6F6643E6250F09BB37F6
-:10A2B000C6C39E413EAA6D95ED5EA0FB8556D96949
-:10A2C00002FFE6ACD39D806765CE31CF82A968E7F7
-:10A2D00045DCA87D4F6519FA2760A71E7C61501EDA
-:10A2E000DF807CF450BBC47E066B5EFED2D0FB0ADE
-:10A2F00035629E87DB36EE4F013AAE7825745C8D71
-:10A30000A813ABD1F92F8792447C98C6D2D02F01E5
-:10A31000FE21BD605458B719F8F5C1647707C61B14
-:10A320009BC5770C407F921C7608BEDC2AEA04FCB1
-:10A330005B25DAD7CB7CD52B1BE0F942C52BA39D3F
-:10A3400062D0E23EC164A7BB1CF10BEB3E86FB353D
-:10A35000CB851E5CAEF9655EBE9F01E696FCB22918
-:10A36000CCDB1889EB7E5572F854FC8EC8A03A5CA1
-:10A370005A779D5877CD8623FB318C5BD5123AAE48
-:10A380004EACBB4EB76E6D5FFBCF49BA73C837B8E2
-:10A390006FF16723F7133E10F368F7CD23B83EAC97
-:10A3A00005F0906E355ED9EBE57E9D0DBFC373BFA2
-:10A3B00080F77E41EF3AE633A5C0B8552FF075B26D
-:10A3C0006743EB3F1F6C7DC484F1959E2F966F31E0
-:10A3D000923F0A8833A1BFA8E78B1562DD2B74EB8F
-:10A3E000AE754B3AB8B89F3C18AE960548D7555B4A
-:10A3F0008C0CEB11F5702D6B59528E7C36985F39B1
-:10A400005D5688F90270AEA6737C370AE7A8118200
-:10A410002FC7B17144978AD81BA28BDE8FDDBE7F18
-:10A420009C15E5FB72F7688ADF35BAEB9F2F177E24
-:10A43000F08C0D8CDA0B6D25D6F118A7F4181C9250
-:10A440004AF156E478C0475E87CC2AA1DFDF9EB68A
-:10A45000DE0378CF3D9C5F85F17CDE61039D77DB79
-:10A46000D99D4FFBC07907D263D3281FEDA0EFCD54
-:10A47000C03C643FFB7B72D7E3B980FE9ED27C9CDC
-:10A4800057827168E773851D68E8C9B5069FEF2E8E
-:10A4900018C1E3F5A7923EFB31FAE133B61BE97C24
-:10A4A000C30CA3FF3DAC9FDAD9ADD0BE75CDE1A5FD
-:10A4B0006BC390AEAF49B46FBDBF774DDC62E4AB08
-:10A4C00076A31DF7A1FBDBFF6D2FDEF76C91E87B18
-:10A4D00012751D65595BA19FBB31CF117CDE2B37F7
-:10A4E0005A25F8D8082BC5C3336E32925D3C9F6C59
-:10A4F000FD25FA372B9C1B498ECFEFD969A2FAB9FB
-:10A50000AD1243D3BF3F69DF1B888FF36F1E31A1AC
-:10A51000935DD27AC4D4F777ECFD052F04FE1407BF
-:10A52000379B304E59B551EBF799904E2EE1FFD441
-:10A53000BE728AFA2BDA24D2332B5E92E93CFBBE40
-:10A540008EB74CC8C7B55B2496981A747F8314F2F3
-:10A550001D84A58CF3C152A1675632EF53C9306EEA
-:10A560006533AF23604F87D6E5AEDC3287BEDBB400
-:10A57000AC79687DF3B0E0EB87301EBC15BF831467
-:10A580003AEE61EDBB5C3A7E7E5CE3E74C9689FC7B
-:10A59000FC55911A950DD7BF3AB2E2E6A1CEB1F7BC
-:10A5A000083BACD9C1CB3E03D911FDB88B6D570820
-:10A5B000DEBA9ECB26B483E5ED9708EF95ED5D54AA
-:10A5C000C7711773D7209EEE6AB7DA518E2BFBB88E
-:10A5D0005E9AD96EF67A25BCDFD284F4ECEFE4758E
-:10A5E0008B9E3D12F92F9ABE7A48E0EF2181BF87FA
-:10A5F0004041A7E4A21FCBE3DE873336EE8F81FB19
-:10A60000B5E27ACD817D91E8EFCD6497EE457AC0D1
-:10A610007B18BE87BD148AE73B1987E3CE2DBCDECD
-:10A62000596FAFFA4764CDA6FC23C49D084FCD9661
-:10A63000503CD7EAE2ED7523B87DDEA4C373A59F35
-:10A6400059B3110E5576786974AF82EFEDCE91282B
-:10A65000BFDAADA6450DB5FFA8B5EF09BF59EBCFE1
-:10A6600016E7AB5BECCDB6E038D894CCEDFF8A2989
-:10A67000B207E934103FA4EFCB510D81F801E28617
-:10A68000DF8C88E771041674BC3B5266717181F8E7
-:10A69000E18749EB2B73A15FB785CBF9C5C9301FA3
-:10A6A0007EDF4B61E45FD66D31D339C03AA03BC544
-:10A6B00009EDFC1C83AB5D2A437A83FFFDEE88899C
-:10A6C00078AE8619E360DD73DA389FCF29BD447C0C
-:10A6D00072209DAFF7B2A2260EE58F6B7E389EC327
-:10A6E0005283CF3F805CE2F8DA765E0FD4BAF7EBA4
-:10A6F00051A9A8D73AFE3A6A09B45746F0F56B7EDD
-:10A700009E1FFCBCD1DCCF3986FEE7839ADCD8F9EA
-:10A710003EDA83C2CE30A989F8BBD6D8F2760CFADD
-:10A720004D5BF9BE3DDB6DC46F9CB1860F5E6F8AD9
-:10A7300081755F7C5DA27A347CFE09E0B38B4B5B54
-:10A740004EA31FFDD5560BF98F0F828F383D77B082
-:10A750003C6A72AB7D77AA81AD257F722D6BA276A4
-:10A7600095E0E38B6D8D26CA9B79839E1F3DD8EFC4
-:10A7700058A5E33B537228BF357C104EFE5FFF01A6
-:10A78000D98EFB2780A7FF4E0EC687F02F5AF7867B
-:10A79000113DFB8FD8C85EFC49F0D97991376E988E
-:10A7A0002CD3FA0D53789BD5F9D668A41FE21BEB86
-:10A7B000DE3777BE358E9FA7F612DE57BE8A49F187
-:10A7C00020385BAC94DBD3FA0D1F2CA2EFF0D4ED54
-:10A7D00019806B8C292E00D770FC2F493C1E344801
-:10A7E000A1F160DD6ED9155CEF05EBB90FF54F9265
-:10A7F0009003A6F813D02F1999AC92FD6A68E7F47C
-:10A800003474F016DEBF80E73B8CF4FE41F78B3DDD
-:10A810003578FFAB542BDF4FBEEAA9C4FE7747CB98
-:10A82000544FF9DD0F568C0DD69B0CE1047AD619E6
-:10A83000FD0914371E31107C75472E27A4DB501FED
-:10A840006D2CB567A3DEE1FA6EFF68EB72E4630F6F
-:10A85000BE373130CF6BC2DE325C6F127A152FF00B
-:10A8600079C57AD7B2B9223EE67C942DFC3D882B7F
-:10A8700026264F1C1C57DCA83F09F6E0E86209EBCE
-:10A8800089140FC6B53B8F737DD0D0F1D0A7C8E730
-:10A89000759F98A9BEEABB9D0F8DA53A5BB7FB5685
-:10A8A000F42BBEEA7CF856CAF3496B092E0FC29707
-:10A8B00084FECB8709580FBAAAE3C304B2AFBB2604
-:10A8C000AEF744A09F927B275E07BF81F80FFC176D
-:10A8D000E2BF9D3DF99ABF62C579571D505C889FC4
-:10A8E0005507F20F55A21F71B8381FD5B874389F9D
-:10A8F000FC953CF4576C01FF455B4F6532AF77E93F
-:10A90000EF0AA33C81C44673FE61E921FC53D3FAEC
-:10A910000ED9F59A3639A46E507BCE9DACF07D7E73
-:10A920008D7F5A2427F1C776DED6B4EDA4F5AD3479
-:10A93000B610BD1BB618F9FDADBCD5EAAA3D2CC6B4
-:10A9400083F8388497800E334D5EFA6EC5C154EE9D
-:10A95000BFEBE9F15932CF631C3CE1BE19F9E56068
-:10A96000917BAC7D08FBE061C53C3E9504BE5BF984
-:10A970007925FDB853C93C8E8F8C0D3D3F3A605F01
-:10A980009239FFCC340DFD3DBD9F69F2C4D833062A
-:10A99000E08BA39546FB3AE1B78F08FA5E42D55D9E
-:10A9A00046F20F8E32FB3B5867384BD3AF93B95DFD
-:10A9B000D5F2DDAE0D2ADFD7197CAE91F4E47C6DC3
-:10A9C0003EFD7969E1D7CCD7F935EB35FD37868D7A
-:10A9D00041FDD722CEB9ADC90CF306E7A3F4ED7E55
-:10A9E000B18F81E775B06DC8FC98F23607BB4EBCDD
-:10A9F00041756627C2D8689E97A3FCF5AA61F2D775
-:10AA00000D03F2382F84BF347A5C10DF55D1D3E3C5
-:10AA10000D81776D9F2D5CECB39D56DC6F24535DEB
-:10AA2000D67913FF8E9A9FE2AB864CEE1F5D28937A
-:10AA3000685F1CE01C650ED2EB1746F0B8EABB0B52
-:10AA400024CA9B76E1788C9F5A24AAAB5EE5EB354D
-:10AA5000211F8D695DF224C9AB871D6341DFA99871
-:10AA60006DE17671806EDABA07EC568C87EBE138CF
-:10AA70006A713CDAC159C2EEE9CF218D65BDE51896
-:10AA800057563B2507EEDBEBE93D77E18477E2FFA4
-:10AA9000013A9F4B761F21FDD67B7901E63F0F6679
-:10AAA0007E3E0AED65ED307CFB3BC1B7DAF7591C01
-:10AAB00063D546FC3EC98F12DD9F207EFB0DDF462D
-:10AAC0008E63F87CDF7FAF91902E8CE8319C9C9C4C
-:10AAD00012F39D4A16DF258CE3FB24CBB18FF26A7B
-:10AAE000F48EA4FC42F68DED4B35EC7E3707F5D69F
-:10AAF000C5AE0339A6203A9E5F03F28EF6A3635FCC
-:10AB0000826A0BE63303F1972469FCA608BB18CAD6
-:10AB100077E791EFB2B1FD30321DF5EEF6A391B7B4
-:10AB2000E07CBB783BC09FED328D837867CCFC889E
-:10AB300060F89E24F82EB4F07918EB1B53353EF8DC
-:10AB40007EE3707C6B4CE1F584217CABADB705BF37
-:10AB50008783FE7DA799BE8783F9E6E820B9484D33
-:10AB6000E1F230497CFF660AF3D0F7002789EFE075
-:10AB70004C51984F89C17D2E9FCCF765F97986029B
-:10AB8000C1BF93145F17D6394C11FB3285AC97C601
-:10AB90004D677E6A9DCC4EE7148A9983DAC916DF29
-:10ABA0009D9876C96E69A1FA3F5F82127DD622CE4A
-:10ABB000430C41B7C0FA15FAEE0DF1A58CE761869A
-:10ABC000FE6E4A650A9773FA3807D2F702A3FC149F
-:10ABD0007EDF0C5F325561155877749BC22CE10003
-:10ABE000EFF6B70D24BF9D7DAA17EB401DB1E2B96A
-:10ABF0002F18D5BB4E7272F944D3827512DA7AF5EA
-:10AC0000782884F9303F364981C892F0E8A3F7DD0F
-:10AC1000CEF8398D22A6D207566EC78F27935EF7DE
-:10AC2000539C54027112EA7583C543F828C3E4CAE1
-:10AC300044BEBF1109F314364BEC38EE57A4F1F5BE
-:10AC40006AF3170223E0B9BD32B15E4C811E8FE179
-:10AC5000FB1E9154385C6AE7DF094AA0EF04DD2847
-:10AC60005EFB13F8772123EFF75FFC7E7E60FFC762
-:10AC700081DF0D8A0C7C8FD281E74C307FE753CE89
-:10AC800007FBCD77A72CAD4E9918A897636EA6A2A7
-:10AC90005FA1AF9743F49D0B3ADFACD57BBCEA9D37
-:10ACA000ABE2B9B98571163A4F9B6B199587762B34
-:10ACB00023D15D9D42751F5B6EA14914EF4457443B
-:10ACC00080CFADCC3919F11CA8D7E3DF4F1A38CFAC
-:10ACD00094C0E8FC9FD5CCEB199F01B9C0EF178158
-:10ACE00054A958D7C29E28A1FAC7A7A22D0E3C8707
-:10ACF000604678AD01781B2DA2EE475777D96833AF
-:10AD0000D0F7381B59389DE79E15E6FE1EAEFFB101
-:10AD100088623A2F9DB56D5A12F983B0DE69DA7AEE
-:10AD20000D83EB10B1FE0F9FD3D7FF69EBC2E3EBAE
-:10AD3000F85EBBC097B64EBB76DEC7A9849CF7D140
-:10AD4000D6FF4C385FA71177E2D3E85915F5837E1B
-:10AD50007D1A3FFC3FDDFB356D605C0000000000AC
-:10AD600000000000000000001F8B08000000000031
-:10AD7000000BBB26CBC0F0A31E815964181826F126
-:10AD8000A18AD112CFE066607804C42C3C0C0C85FB
-:10AD9000407B23807424101F01E2A340ACC2CBC0CF
-:10ADA000100BC471403C07C89F0BC4A5409C05759F
-:10ADB000632B0B03433B107702713710EB303330BA
-:10ADC000E832136F7FB10803C31309045F5112689F
-:10ADD000A734FDFC3FD8F00C7DFADAC76DC0C0B0D7
-:10ADE000D402C11703B29759A0AA596E81DF8C15FE
-:10ADF00068F22BD1F8ABF0E8DFA787CAD7D340734E
-:10AE00009F160383155298E86BE0770B3ACE04EA5D
-:10AE1000CD0262009F3090CD68030000000000006A
-:10AE200000000000000000001F8B08000000000070
-:10AE3000000BE57D0B7854D5B5F03E731EF3C8CCFE
-:10AE40006412420810C2092FA30D382121058AED92
-:10AE50001020A2458D8F2A54D4098F24E435011F78
-:10AE6000176BDB0C04232068B058A2463B4150F01E
-:10AE7000061D6890200107B01A7A7D04AFF5D1F65F
-:10AE80007A8352400824E20BBD6DFDF75A7B9FCCBC
-:10AE900039273340FFF6FF6FFFFBC7AF3DEC73F67A
-:10AEA00063EDF5DA6BADBDF61E990C24D20F08F9EF
-:10AEB00016FEE873A644087DD5F774BE4254924846
-:10AEC000487D0E2DA710923E8A84884048410D2D62
-:10AED000E711F2D06D2464CD2464FFEB16FCBECAEA
-:10AEE000CFCAB45DD87239FD3E9ABD7F2C8BB6A314
-:10AEF000EF1F3B2762BBE02C12DA4CCB4984F636BD
-:10AF000092D021FCF82CF036D8C7D2FA4DB7598828
-:10AF10005525E4513A0C9944888BF8EC84365D351C
-:10AF20008AF5F7C82CCB33A2001F2369F36979F5A2
-:10AF3000F492FCD5B4B446667035CE29792648FB28
-:10AF4000F75846E23C68BDC79CB4DEC3EF9792D584
-:10AF5000B4DD86B916A1249BD66B566687B2A3F3DF
-:10AF6000D79E7389C4DB05AD9689F0F4F1674481FF
-:10AF7000E72FA658709CB5350C1FB49E624923A4D8
-:10AF8000B5F380CD4FFB5B5BD97AB8907E7F709430
-:10AF9000C54B31481EEC3C60BF848E1FCCB3784754
-:10AFA000D3DAE95244F038A3E34D2214F009B49EF9
-:10AFB00077874D75F6AF4FFB9D0AF35E43F12E6622
-:10AFC00046DB8D073869BBB59464613AEE2F65EFB7
-:10AFD0002118F797D7240B4112AD77150009F5E634
-:10AFE0005A4884D62352AF8DD071564F79DB369AAA
-:10AFF000D65F5D64814990B55EEDBBD74EA0BF19A9
-:10B00000630E8D02BA5E45BFC33CB21F990DF37E3D
-:10B0100078BA4200FFBF14683D8AE2C662E5870045
-:10B020009FAB8678E03D7DFA62E1B54DB0211C64AE
-:10B03000CD0642F20980807FAB7DA1952380BFF2CF
-:10B040008817CAE95EDADED9BF7D976045BA34CA8F
-:10B05000C1C180BF78F41BC5F1B93A6B891DE841C5
-:10B0600048435AD15842D6039E6050C9AF5EEF8A1A
-:10B07000D65F2930FCAC93894FA0F34BC85342CB29
-:10B08000289E2DD99E39305FA75F2157D2F22A2101
-:10B09000385804BA8C55C86615F9C23E9A96D75EE0
-:10B0A0009AEC05FEAB17C269127CBF867EA75D1EB7
-:10B0B000281A3F07F8B3C9AB203F53FE3904F85EA6
-:10B0C000EB4F26AB55FCDE89ED9DA33C56C40485B1
-:10B0D00087E26500E525C06BCE75F5578D04FA4C07
-:10B0E000B0788042AB85A9EA7C909F249B07C697E5
-:10B0F00027DC80F49307260B4447EF9F03BD299E6E
-:10B100006AD5A29FC3BC9EC8FB286934ADBF26E7A1
-:10B11000C546A0D393F7D8907E4F4EE85C0C72F5ED
-:10B12000D8B9DCF7FD28978A7733EDE7A99C6399B6
-:10B13000840EF8C8CC8F92007FC34635DC49DCF41E
-:10B1400039ABB7968CA3F09186A20599C827C28D1A
-:10B1500014AFC3962A44B5315A7E4BE03BF185B318
-:10B1600059D949E7338CD3B9B5F36D5B31F43797CF
-:10B1700044C6B8F1BD2D3539AA6786E591482AED58
-:10B18000FFB185AFA29C3F7959AA97C9791AF24BB2
-:10B1900006EF271DEA53FD926623C104FA1CD6D19F
-:10B1A0007B03C0352CEBD85C8073FF1BAF0A40B724
-:10B1B000A7C6A5AAA08F92FC9DA48BD27D58F6BBF2
-:10B1C000F7413D97339456948DF5FF82ED4CF03F57
-:10B1D000A9FA3601DEB6093587803EC11C8B97D1AE
-:10B1E0009BE9C13577A586408F0C73FCF17A710419
-:10B1F000F20121A9143E0F4139A91722B691D0EED0
-:10B200005ED66E38090980E76159C1C5A21BEAFB09
-:10B21000852257FF715B4123827C504E077EDDAE55
-:10B2200090F2A21872F03297E77A81CC467E26D24D
-:10B230005F816F862731BED1CA4F013C74DCEDAF10
-:10B2400024FF309BC2F3ABA52372440ACF43D02E18
-:10B2500086DCACE572E0E8204181E275FF6F7F6B30
-:10B2600007BC6DB79032A83F352B6CEBE274057AC2
-:10B270002C24ACFFA6EC8D36D4174216F2DDC28921
-:10B280008ACF3E0EE46FB9E0A7EDD33C4C2FBBBC98
-:10B290004A08F4B22B2D2858283C6A36F16CCC644D
-:10B2A000DD0529FEE6C13F80D125567FCDDAA4D049
-:10B2B0006AFA7D5E361534C01BC595858EBB80B09D
-:10B2C00079CEF3D62F06FA115264017CAEF630FA2D
-:10B2D00034C138742A4DE9AC9FB57793D072E0231E
-:10B2E0000F6B3F0A9A50BA8DCA7BF15F04DA6F3A4E
-:10B2F0006F07720FED12D242360B6DA7D65808C2F7
-:10B3000027450E0940F7B1A92AC0D394E6FDF759A5
-:10B3100000FF6CC9BB917E1E0570D07E9A6A2C3EE0
-:10B32000D417794A33E8E9D53EA6E7357C65F27152
-:10B33000D3BD1181CE9D64523D8978F245EC1E2823
-:10B3400067337832F3D8BCFAE01FAB8496D3C6E9F2
-:10B35000B608817A1A1E4A787F257C1ECEB4D04A60
-:10B3600009E0CE6370D37519E149CF569A410ED2E8
-:10B37000D3587F2AC58F867780CBA1C19547EB83B1
-:10B380001EF62ACDC00A0E0E5F49368367FFEB6FAB
-:10B390007708AC3F942B0787D7C1E74F00DE54AE48
-:10B3A000D7697F2D72441069FDD004A26E64A3A9F1
-:10B3B000527EF4FB2335140FB4E0E4E390F5569489
-:10B3C00007FA2AF82DE583F90DB49C15958FD12B3A
-:10B3D000AD067971F27993062647946D22D02E93AB
-:10B3E000B0B205CA741E25594639235E5D99C2E183
-:10B3F000027EA7FA67D92485F1CFA5CC8E214457C8
-:10B400000FF87C82FAF41AFCAEE0BA9EF153C50044
-:10B41000DFB09AD40211F449C7E3375880AFEE2267
-:10B42000163111F959E8D35F74BC1D4B227698A4EC
-:10B43000A3A32819F09651935CA0001E3BFC5876FC
-:10B4400074D4F8F0094BD378428610DD3899A05FA8
-:10B450003D152D14AFA4460983BE9EA087937ECFD1
-:10B4600078A5E17AA0D7038B5F1D0CF29B6A6A3F37
-:10B47000CE3202E574D82BB4168E7FEC67507F1560
-:10B48000D7270E80783C3E5F81E73027D5B3544FF5
-:10B490006750042BE3A3FA62F5A5EFE6F89D9C7FC5
-:10B4A00092F11981A759AFE8EA5FCAEB0785F3D695
-:10B4B0003B86F53478CCDFCF0816D4532EB0332931
-:10B4C0007E1F269E39B82E7B2DB82E26F0F761EF11
-:10B4D0008102A4679878854CD0B77FB5EAF9E02758
-:10B4E000F012F4AD14463951321C681F52394E80A7
-:10B4F00075AF49AA2983F7E1740701BD7060C6AB37
-:10B5000002E033BDCD3F1CE450B3730BBCE1347893
-:10B51000FFE021FF25289F71EC46CD4E34CF67E830
-:10B5200015CB511F0CF7F776C07AEFAC94BC5702DD
-:10B530007FF9295C4ED4932AF92E85DF1B5C067AAD
-:10B5400056F5D3F220FAACE4CF32F67D556D59EEC4
-:10B550005129DAEFAA51D41EA57A717DE77ADB353D
-:10B560006067D45854E0DBB5DEB76D3E27940B0618
-:10B57000009E5B8B34BB2F22C078E9EFF8D0CE9BC6
-:10B58000E0513CA0B4C65A23833DBAF5A269C6BBBC
-:10B59000E3010E721325E2E0F874A4F3453E8BB785
-:10B5A0009E002C16DD3AB23F6B07AE2F6F904B9189
-:10B5B0002EDABAA2AD23D823D52FF3B91C3DA88625
-:10B5C0006D02EA2B2ABB943EF3B91E7172BD49F598
-:10B5D00030D3737C3D59BB3815D7134D7F826D0D29
-:10B5E0004A623ED7B76B739E49BA86C2E4043D0BEC
-:10B5F0007A298D14C0FA3B1AF40CE8272928C07860
-:10B600004D133C6435AE63467D3ABA86E9C107D333
-:10B6100008F2135D879A61BD6B4A0FA7413F4D3514
-:10B620000704BF6EFDD4D63B574D27013D382F8F01
-:10B63000AD73F3B2D978BF07044D60F0825E35AFC9
-:10B640007BBF98B203956502B7B7CCF8172CCC0E28
-:10B650007C78D6DB88C7B50B1EC12769D880FDA5CD
-:10B66000D9180D56651DC0F76BFC96996077AF979A
-:10B670003A578EA2F0AF9F394F09D2EF6BBCCCEF97
-:10B680005A3D65DE33B0AE592D0A83ABA60CEDD51D
-:10B69000040ED706E81BFD4405FDA2BB6FDBB872A4
-:10B6A00004ED278DFA31820A9542362BFDEE049A7D
-:10B6B00082FEF64718FC5E524062C0FF1F8283F98B
-:10B6C000A1FECE8ED1484F8B07E04DF0F6DAC04F89
-:10B6D00054A91FA6AA00AF6A1F8BF05A3CCBD468AE
-:10B6E000FBDF717FE17658F8C1BE9FF3EE4C90AF5F
-:10B6F00075B731BFCC0CFFDD53431D161C87A05B13
-:10B70000E78A83D7B9A0C140FF784308972B8BC144
-:10B71000755460F47AB8B3E02AF4938AE87BDAD1FE
-:10B72000239D23EC20DFFDECCC840F73D0DE31AD04
-:10B7300033172A0F33E9FBB1D6F0D5C86FDB2CA83D
-:10B74000A708617A4E2016F5DB91B08830B890F5E5
-:10B75000A8FE5E2147E62CA0F557EC7412C097C6F0
-:10B760000FE9BCCFD535940F62CCBB4310E3D19D1C
-:10B77000D9199CEE9D30DEC00BD39F4AB31DECB6A9
-:10B7800070A87E4839F81F35CCDF0D470EA0FE4962
-:10B790009F7E33FA295B9A53E72C00BECAF27901E7
-:10B7A0001D1A3C609FC4F213AFB6D8CEEBBFC7D30F
-:10B7B000C38D952BD0EF6DEC8C3DFF2916E66F877E
-:10B7C000A99EF466C71F3FDFC2ECE8240BE7BB1954
-:10B7D000AFA6E9D7336D5DD5D6D96112098ABAF51E
-:10B7E000F0268E3FF3BA49A406DB18C6E7E83F36D9
-:10B7F0002E6071880D532C185FD1F89CD64B03BC7A
-:10B80000D279A03D47F93004F6DCC3A401E526480F
-:10B81000DB6F26FDE1BE8D582E6A7E93F9FCFAC6D9
-:10B82000E3FEF5ED5C5FADCBB9C70E5DD1F1D28023
-:10B830003F026EA627AB5CCC8E9DB6538EFC80C2B9
-:10B8400051D52CA09D65D9674738CF6CA265DA75B4
-:10B85000C4A560FDD31E1B9603D6CE87BE47CBBDC5
-:10B860003B4582766496C302FC7A8CF32BC9A365B0
-:10B87000B087EDAC58D5BCFF76E8AFACCD4AECB4A0
-:10B88000FFAADDA5D77E8F964B3B640255AA362FC3
-:10B890005386D0F2A2901086724F015DA8002FC986
-:10B8A0004A08FCF61E7767EA8FE8BC4FD6DA884A6A
-:10B8B00041A97375A6DE44F1511EDA5E08EDCA5B3C
-:10B8C00004D088741E9B5F1D0CF3DA2A78C1BFAFC9
-:10B8D000D89260B0078FD1A9FC807E5F42E70972E1
-:10B8E000594A1A0A619DABDABC4E5175F18793B57E
-:10B8F0001E1C472B576DA5E3D076D5CF0B5E986203
-:10B90000B585F8410F9DD96D9FFDB413E6B74C196D
-:10B91000E382793DA040BDD250F18B7615E06B56A5
-:10B920000AE9F7F2A66605E25B012BB903FCDC8AA3
-:10B930002D038C70358A28AF4B926C1B419F13A747
-:10B940002FED86B1FDE97CB296EAD831D17239E8A3
-:10B9500043E4C39072BDAEFE703109F9B5628B68E5
-:10B96000B4B3F9FA1F3CCCE81FDCEBC2B89F46BF6A
-:10B9700025DC5FD6E8B72489D353EACD8F05CF43C2
-:10B98000400F0A4F03E08B3ED770F8DC53C8548851
-:10B99000BBB87DC423C4E06BF3B34126C5C0BAFF76
-:10B9A000BAFCFAA9D260741F1643E4C9B362CED4BC
-:10B9B000E9B4FC3B4BD1660BEA0FAF0A72A4F9D98C
-:10B9C0004F59985CD60F56107F0D33F29F66F109E0
-:10B9D00082EB5EC38C9267C02EA0EDB759500E6902
-:10B9E000FBB1F1DB7B0A271ADA7B0ACBB4F63BB159
-:10B9F000BDEDFCED1B0A271BC72F2CD7DAEF45F84E
-:10BA00009DE787DF73E514E3F8575662FB8095D115
-:10BA1000AB37C98676CD0ABBD727313B2A02EFA5C3
-:10BA2000E4311BA19EA8F103E9F481FDED6C491AF4
-:10BA3000BF9AE8F9A2E00D80C345A545CF17891349
-:10BA40001D067E4CF2251BCAB427CFB1EFF0320C95
-:10BA5000E2B6213CCA1005F5C5D4213684F79E7D97
-:10BA6000762CDF3399C17BCF1027CA19AE2D948E67
-:10BA7000F728FECBF5762BAC4C104A7A53F47F04B2
-:10BA8000F88DBE572DF0DE21921AD4CF5682FAE8F7
-:10BA900081CCFCA7833AFCAC1C46E94BCBA7C1FE8A
-:10BAA0001918C5EB03C34AD28A75E3D40F53666FE6
-:10BAB000CC66EFE73B61BCA21EC04340E91D0376A4
-:10BAC000A5791CEB888986716C196538CE37A6710B
-:10BAD000AC1965A6716CB337F2F77C9C3FC3BCE22E
-:10BAE0008DF3C088C9C6F96494E33856D1349F8C6D
-:10BAF00072D3380E361FFA9E8F6317CF379F91533C
-:10BB00008CF3195E89E3A4888A216E651D5E691A2B
-:10BB1000C789E3C07B1887A433FF46B1F69620FDA2
-:10BB20005FB613B0A715ABFF59E897FCC14E509F05
-:10BB3000A874DC41A0579271BFE03F2CC9389F2FF9
-:10BB40001D94FE4E3D9D839A5D80F6CE420E2209E5
-:10BB5000D5A37F5ECD797441CBF519CBE0D9362DD5
-:10BB6000AD18FCECF52E2FC44FCFB44D53E6C7B043
-:10BB70000B1636C8C7BA0CFCCBF55E01C9AA013F4B
-:10BB80008BDB015AF918D55F84EAAD8FA8FE82E7F6
-:10BB90007199EA69FAFE28D56F44D1C3BB0CDB1D4D
-:10BBA00093181E8F35B175E4CB7587658CF305C985
-:10BBB0003B59741E37F3692C6C4860BE028723C062
-:10BBC000E9D1BBDB1ADA88F4F00D05BB87340EA08F
-:10BBD000B8E2F54600BEA8B824637128D8473F5E96
-:10BBE000B9FD3750ED5DA178D8123ADFD9ADEBE45D
-:10BBF000A1B47C46EEBADDEBD4F5335BFE08E66D0E
-:10BC0000A3FF413F73FCB4AC1BFFD63263F936226D
-:10BC100045CB946E33C4119C1E7C5C352403BD6EF1
-:10BC20004E65F0DC06CFF1F0D983F4BADDC3DA6AF1
-:10BC3000F004EE934904D7A3AE81CCB81D88F5FC7F
-:10BC4000DABA6282EF76D9E62BA2F4BCFD5E11F17E
-:10BC50006886B76B5F82CF42FDAAAEC6CF64F02F75
-:10BC60002F04FF1D4B8DDF49908DA7E155E3835BCA
-:10BC7000664F1D7054576F8EFFAA014775FC726B9B
-:10BC8000D9F586F26D35730CF5EF585A6CF85E1CD9
-:10BC90005C64F83E7FE562437961C3BD86FAA58D99
-:10BCA000CB0CDF17855619BE576C59672857851F6F
-:10BCB00033D40FB4351BBE5BF65D7A1DC863DDEF70
-:10BCC0004402F6D917CE630F817DF5855342BFAA92
-:10BCD0001A788DCAE189DA34E4EF93B52A3ECFB4FD
-:10BCE000E5E2FE58C041E599AEF51BEA0E2D5B3941
-:10BCF00005F408AD4F75F813756F2D0B52DF7D23DA
-:10BD000004A929DF8B8D0A890C003F26B98FAF7BF0
-:10BD100045DDF7AE0B7C6FA40B566EFFEF6257EC60
-:10BD2000F73D42EF18B0EF821F5871FF269EFD408D
-:10BD3000FF869218FE83F6EC86F8864EEFBC2C3216
-:10BD4000BBFA72B1E065913E2B1526EF953B0617C5
-:10BD500040BCA052898CA9896167F78D17A6C00CD9
-:10BD6000827E98BC2C0A0D8DCA2FD26FA441EEAFF3
-:10BD7000B1F8F7817EEEDE2FB2FD81C8C10CD8A7E5
-:10BD8000B95CF4BD0CEF49DB405C1FDFADF50D384D
-:10BD90003A8A90F76B67E2F3F7B54503207EF4C764
-:10BDA000DAD958FEB0D68FCFAEDA327C7E545B83C0
-:10BDB000DF8FD62EC5F2B1DA203E4FD4AEC4E7C92C
-:10BDC000DA06FCDE5DDB88E533B5217C6A72A0D93A
-:10BDD000A32485DB7FDC5EA72B0796CFF23988F49E
-:10BDE000DF9D28D7DE3490EBB3CE2FC7809D7BF646
-:10BDF0007D2B06D1E3E1C9CC6FF1E9E7C3F5BE24A1
-:10BE000044E99FDBFFBBDDC1E863B79099E09FADDC
-:10BE10001AAD1088AB3B5EFE0EDACBF4BD44505F2A
-:10BE200086BCFA7DC4BEFE61CE832E4C27ADFEB12A
-:10BE3000C7FF2B7F5E36D087D1D77150AC61747B42
-:10BE4000DA0B74D3E18FD9653BB93E37E151E27229
-:10BE500067C6E7E9811A3E3B3320DE522516592496
-:10BE6000FAEE6CAB15E775B63D81ED637B522E2A79
-:10BE70009E57B1C5EED1EB87AA7092C7A82F067B5B
-:10BE8000F4FAE26CC7D36E90FB256916CFD15CE063
-:10BE90000F1FE70FC6775AFF55E14C8FD3D08FB1F4
-:10BEA0007CB64198C9F615D5C49B62F807DA734988
-:10BEB0009AE2394AF5C2C92D2313615CEAC7796059
-:10BEC0009CEE5A8F878D9BE6D1F365E55207D6D756
-:10BED000E08BD7EF3F1A3ED8F1FBD8C6624D10A7D2
-:10BEE00089573F2E3DA4CF15F00F48BBFC25AC3B36
-:10BEF0008E2C6DDD91B0ACF51B088B41EBE5F0BEEF
-:10BF0000C5301E6DA76A3E34B48B4F77891CD3E8C9
-:10BF100049F5E4953C3F843233D2D94F7B4CA4FDA4
-:10BF2000F548CE9510E7CD9454D477011888F25394
-:10BF300095AD4BF1AB88EE4E8C7B4ED4E45EBDE507
-:10BF40000F94E53EF93719E319E4CFB477FA5DE6CB
-:10BF50005F179022373819F35A2B66819EFCC4A2D2
-:10BF6000D9030DF930EFD3C482FBF9A7C9DBEE5C2E
-:10BF70009D5D5626F1F8E44AB63E07E97F303F6AF8
-:10BF8000A719D6EBD24663B984DC900AF250B25EB0
-:10BF9000861D5BB208D67BDDBEC96CC983F32E2536
-:10BFA00035F560A7AC96D93EEA3C0F918652B8AA07
-:10BFB000763D990FF66C4062FA5EF39F172533B811
-:10BFC000CB53428A8F7EFFB835F7E6EF11681FAA80
-:10BFD00007BD1674116FAC78CCFC9546F82E04BFE3
-:10BFE000195E42961BE0D0FAD5E010B70831F33461
-:10BFF0007E26093CAEC3E463AD64B45F1FE178D034
-:10C00000CA1B4CE526537D8D4F64CE279992FF11B4
-:10C01000D03F55B6DE42B4D308E58FEC683D255AD3
-:10C020006FC3F9EA59A19E88F59AA409F1EBD9A347
-:10C03000FD35C7EAAF6AD7B61783949FCA5F78D435
-:10C040000D41DF4FA48654887F556EBEDF0D783AD0
-:10C050002105DD40EF4F4262CCB8E07B7DF8F2393C
-:10C0600005F02390B529DE9F7BF05AD0D75F6E96FE
-:10C07000312F26B0C51AB1523EAE6E5D340BE2F7D9
-:10C08000B47C84951FF814F60D036D467A963FFB39
-:10C09000682AC489282699BD4D226877546FFA53BF
-:10C0A00021E8F100E9453E34B783F1CF25A3DC1741
-:10C0B0002B89FDBF6BF90A012E6781D6073F85BC2E
-:10C0C0008480897FCAFAD6932E05E2081D922B053B
-:10C0D000FDF2EF92EF821ED0F04142CC9EA8DBBA77
-:10C0E00061DC110A4FF7A67F730B06BF9BF1E1D904
-:10C0F000F0FC5FBDA4C6D73367B83F146D17C27696
-:10C100006A1BB37F483B7B56CA1137D89B95CDB28B
-:10C11000977228A9DCF6F4338F839FF68115FDB45E
-:10C120008A6DBF7977322D576C975366B1E93885A0
-:10C13000D4285D02F47F4BC747E950FEEBDF28EAC5
-:10C1400058F6FEA7C9517A546CDFAF90B1FDF137B4
-:10C150002DBC5FE972C6A04BF84821D82B755BBF98
-:10C1600052C0EFFA649F400665F66F5FD6FC1B5C19
-:10C170000F014F48474EA73EBAF5A357E4DA97F2AE
-:10C18000B09E07F4643C7A3DC7F572D52E174982FC
-:10C19000F8E7EFADA15940C7E7EF74C33C8E4B35CC
-:10C1A0008CAF9FBC3F15F6FFCAE460AA079FEC7DE9
-:10C1B000D9537723BF950A35A96C1FD33798C7CBBE
-:10C1C00007C3FC1636FD08E75742FCC877654F8A5F
-:10C1D00045101FFE422233B7C7908B6B64B6FF74C5
-:10C1E0007CA31592FCC871B0F3C1BE7E5BC4382B32
-:10C1F000218B711FEC6E2D8E4B9660F90BBE2F3587
-:10C200004AB668FEA1CDC0AF9B1EE804FA9C1CE6AE
-:10C210001B0470523C0439BE04D8EF170FCF18C46A
-:10C22000E8C3F20DB01DD5FFD3E03DD4EF94719F6C
-:10C2300050D78EEB4B36FE5D7C7C0AB703D6B3E35A
-:10C24000A96CBFD23CBFA57C7EF4AF93E8F84B2726
-:10C25000DF4CDE37AD62F2ADC97BE8FA99F0FDF351
-:10C260007798FC403B583F285C9141F87DFF4D0298
-:10C27000EA032B89C492EB4D32976BE3F700955399
-:10C28000880B50B825C86788F209ED3F19F18F7EF9
-:10C2900049C97ADA4E679F05603CACA744DFEBD60C
-:10C2A0008F52AE0766CA46F9274D032FCA5EAC947B
-:10C2B00049104CCBCA0FACE877576E938B60DEA762
-:10C2C0005A0EBEFB63CAD7A7C29A9C1AF5A7594E4D
-:10C2D000CB766C16803FCD727AAA8CAED6B1E49440
-:10C2E000BE8F29A7655DFF57F4A786B780096F54F5
-:10C2F0000F0E4FB2C4C79F590FBA6435A61EA47F54
-:10C30000EF90FCFE7CA7F19BC667D4421B0EFABBE4
-:10C310008F1F357EEBE3478DDFCCF334E2CDFC7D20
-:10C3200032186A14AEA2DD32FA2595ED6CFF86B69E
-:10C330007B75681EE2C787CB17697875688ABE1C53
-:10C340003295C3A6FA3E53B9C854DF6F2AD718EA0C
-:10C3500057B61D54589251C450CFBAF471F2710CB3
-:10C36000FB5E5B6702AD9F2A41E087F45E05F49CAB
-:10C37000BC9C9A66103FDB2BA2BFD5A3F6BA93E90B
-:10C38000FBFBEDCC8FEDF1F072122BF70E54EA416E
-:10C39000CF69EF7BED2CCED953D4EB4ED2F9F747D2
-:10C3A000DA4537EC077785583E6A7F78EA506EBAEF
-:10C3B00048BCEF2C2E384374662C05FFAD41F48247
-:10C3C0006BB860D92D6ED877EB691F79DD6CFA7E7A
-:10C3D000E12111CC67D2E3708F03B848D0270DCE8E
-:10C3E000E7F913F4EF0409FE720AE44DB433FB7A63
-:10C3F000C11A933DECBC4BC1FCB2F5BAB8968EFFA6
-:10C40000CB793F654DC6EFE5640DF25FB9491EFC7F
-:10C41000DC1F38ACC9430EC961FBDB84F9B15CEFAA
-:10C42000CE10B3AF9B4DF1DED32162DEECD9769115
-:10C43000D4C33C5B04DCE724C1812857D5A417F59D
-:10C440009D86976E901B25BE3EEADEF91FF9F70127
-:10C450007FBCF887714FD067F78B1F8CD903E55DE0
-:10C46000EF65FC81F4AF3F6DDFD7B88FD8B3CF8ACB
-:10C4700071AE9E7DAF65DC07E597AC18E7EA596EB3
-:10C48000C57D94E03E5768347C1FC6FC81BABD5F11
-:10C490008D6379922B904E7F96993F72B6FDBF3E89
-:10C4A00084FC91B3ED74566017EC4B40B909BC6441
-:10C4B00047FFBB67EF57F97EE73F6E3ED50AF12392
-:10C4C000FFB9C8EC1DC0AF492C1E1CD833E969C8A0
-:10C4D0006FAE6ADDAF409C7DDACB7F19077AB26719
-:10C4E00007B377CEC85D4FC17E9855F974B94CF14A
-:10C4F0007C06846708214F2BE3A705B363E185E140
-:10C50000A187E201E645F15206FA3D1E3E32947FD4
-:10C51000567C7C7A3BD363DFC53CFB285E041F7BE3
-:10C52000EF0AD9049C3F7BBFEFAB71A0674E8597A4
-:10C53000A13D72A1795FA1B07D96FF39F316221754
-:10C5400033EFB9FFB4F466FCFF11ACAF03FBCB4192
-:10C550007F3EDF750F969F777911DE8B94FF9FFEEC
-:10C560004FA3FB0E4A77F785E9FEC43FEDBC2F448D
-:10C57000F7439CEE2E0FEC2FF7ECFD0BC64DB5F9F3
-:10C580005F68DE2FFD3F3A6FCD5E7FCDA2BE934345
-:10C59000EB1F220DEF8C11207FF1E0613802562055
-:10C5A00090A258F6C84985C53F0A049627489204C8
-:10C5B000EEDF31BF6828B71386DE558276C6D0F429
-:10C5C000B5681F10495D0FFB71AF65CCF7B27CB049
-:10C5D000F1780EE535CF15BC6CF40F9F10880FF283
-:10C5E000868766FCB003ECD5F47411ED59FA443B30
-:10C5F000F615F74CF6BE5231F84557115D99CEABA2
-:10C6000030C5E8FF4CE7FDCD2023DEC9A1F0CFB057
-:10C61000C99E1045D15553FD12CCE7AAC10269D07D
-:10C62000ED074D37F949AF825FAB8B97FDADF84B06
-:10C63000B7323FB24018B1BE08F0374CC478E005BD
-:10C64000F14758FED76B9E1C96D72A7919FE92ABFC
-:10C65000BC184FE57E338405C05E919CF59D20B7E4
-:10C6600012A17E2F831FFD65CDEF8D8767C2FD6808
-:10C67000890FA9E15D4A17315F55D71FE243A3C770
-:10C68000DF4A078D7E7F2F3DCE98E891FEB94702A5
-:10C69000F99CC6EDFFE99F778A584EF74AB81FC547
-:10C6A000EDFFA9CE2409ECFF2BA4C322C865A9ADD8
-:10C6B000ED6A88D3DBBC02F2F525DD16F46F6C79E8
-:10C6C00002E23DAB51C2F2618B670218DAD77E6F8E
-:10C6D000D7A97B09C4877D0A1ADEA488C5E7FFFCB9
-:10C6E000EDB753B4F31AF89D906BA8FFB5A0894439
-:10C6F0001C144F0B25124C4C86F8AE403E32C477CA
-:10C700008D65F8FB7E6AB49F0BD58FA747FED1CF0E
-:10C710005D546F7D449963373C715F85B284CE3F31
-:10C72000FE6E3BC357E075121A8171059F58A4DB5A
-:10C73000377BD0CAF4C7AE3FEEC885B8D8D49EECDC
-:10C7400044A64F47A15F10E07EC159A22642FEC118
-:10C75000D9F69189B82FD821BAFC31E2325BB9FF02
-:10C76000FCAF904F419F3D9B48039CC3E821BD18FF
-:10C770008F0D6EB2C5DCDFBDC7AAC59B38DDE89F53
-:10C78000A89D3752315F2498A8A75BF7AC4FA471DE
-:10C79000FDE9007F1FE9F64BFE5EFC82BF0EF8DD6F
-:10C7A0006AEF2A8C751E6C25C7DFB507BEC638E652
-:10C7B00065EDCD16E0DFCB36590CFB8D412BF7BB79
-:10C7C000C693F100D7B507ECAE3CA04B87E885FCDB
-:10C7D000C140FBA78A3FC6BE95199FD03FC4C5F78D
-:10C7E00059599C7F8F1C9E0F78DD73DA86F939BB0F
-:10C7F00095868A58705E62677A6E2109DF392EF35A
-:10C800009F0FBF537B9C9102F03337111EC730F34B
-:10C810001F413E3EBB85E0F950F04B412F9C6D61BE
-:10C82000E780294AD6823F4DE5FD07FAB8CC256D51
-:10C83000DBFF15EC80EA76C103A9B3D5529702F16C
-:10C84000D6405B9208EB6E8EAAE5557AC6DEA493BD
-:10C850008B7D56966F7C70F29E5B61DCCFBA1502C1
-:10C86000F688EF955E37ACDB9FB5E726C6CA9BD747
-:10C870009EBFAE25574F97A01F827837F343768B24
-:10C88000C350FE9EE81F02F275ADB5EB2E6F0CFA99
-:10C89000F96D8CCF2E5ABF85FE3FD36FEF68FACD6E
-:10C8A0002F16E9E428CBD64FBF0D8AA5DF9608EAFC
-:10C8B00020C0FB92BD2307015D971C9207C6D26F73
-:10C8C000DB6AD97EDE0B3C1FB6A795EAB7CB75FABB
-:10C8D000ADD5867971E676C9360B5F172FA0DF429A
-:10C8E000FF3DF2B70DF45B8CF98EB631BDA1E9B70F
-:10C8F00071ED4750BF8D6BB518F246D36D17D26FEF
-:10C90000C2C09BC01EEE90BD0931F8671BB7BF5F68
-:10C91000E07978300EE8B95B6D6C7FF362F55CB658
-:10C920009DD1FB827AEEBF09CF9A9E5BB2533BE763
-:10C9300068E643A6E796ECA67A4E007E647A6EC956
-:10C940005E768F8359BF65F5D36F04EB574758FB6D
-:10C95000405BE686B9B4BFF13ED96BA3F5C747F596
-:10C96000DD04BDBEBBD5C6EE5DE8A7EF3A2E4EDFB7
-:10C97000EDE4FA8EEAB111A05FCDFCE16D37E61D62
-:10C98000EF9974BCE5D7202F6F88B86F78989F4BCC
-:10C990007B73D2F13CE0AF161BD3BF759CFFCED4A6
-:10C9A00006B1FF69AFB0F95539593E72752BB30F17
-:10C9B000AB5B84904AFF5938F96B05E05FB45720B0
-:10C9C0008368F97A2BAB4F9ED5F6BDC8AC1C1D3FD2
-:10C9D0002C98588171FB0512B1415CBEC259F8090F
-:10C9E000D8BF1513591CBF82BF5F74A8AB1EE2D914
-:10C9F0008B1E1370DF93F07C002DBFB1B47D19C680
-:10CA00006BCD79019A3E5F1432BEAF30E53336F319
-:10CA1000795E2F76215EC85B62CCBC8466333E3A79
-:10CA2000383E3689B86EF6E183E247CDEC8F0F4A87
-:10CA3000D15939A9D1F92F7A83CE2B2F3A2F0D1F37
-:10CA4000E6F96971E70ADE2EDE7C35FCF59BAF86E0
-:10CA50004FD3BC9F06BD010A2187E4425E0CE5036B
-:10CA6000D41BC1DF8A787EBF68EAE8417A3DBC9575
-:10CA7000EBF3DC86A9D30613C017A901BE29695CB4
-:10CA8000FCEA603AEF09EFABE36179FCDE64AB1FCF
-:10CA9000F647B7DA7B51AF697CF50DE7AB77391E06
-:10CAA000F70CA9C173AA8136C1037645206247FC01
-:10CAB0000528FEE0FC4A809F5F0C50FE02793AF8A0
-:10CAC000D8970C5F7B0515E2E385DAFA03F8A7F542
-:10CAD00073DB19FE032101F19F477A717FA4BA51DC
-:10CAE000F04668FDEAB6C598F7A0E95BFAE7D4D34B
-:10CAF00043C78F522C7EC44ABAF5AF82D7BBD6DA71
-:10CB0000F02EF0E7B5CFCAA459C79F59F4BF6F63A1
-:10CB1000D049C3E785F8F21CC7D336C0A313F0D5BC
-:10CB2000CBECA7C8D7788E46FB1E9082063C4E7B86
-:10CB3000FCDC79F13441C313F029E8A9F66211CA8B
-:10CB4000256D021990D97F9EB03FA997DB457B8F59
-:10CB5000B0FE9F14F0DE1233DF6AF3EEC7B771F850
-:10CB600015CEA5815F74B17CFB8D896FDFB4F7BEF4
-:10CB70009E0B7CBB5760F183F624C3FEE2103B5B47
-:10CB8000FFB7DA297FC3BED621D9BB51ED2FDF090C
-:10CB90007CFD02BB5F7F2EE9529808E43D6EB161D7
-:10CBA0001E19C23182D9957ABDBACD4E06DE9417D0
-:10CBB000BFFFC1BCFF78768D561E0BE341BE571BED
-:10CBC0001D2F2B3A9E59AF6B7EFE85E635E6EF9C16
-:10CBD000575F1E26E9C47DA74CC9FFB0559707775C
-:10CBE00033CF33A210A07DA5AB976D3B4F3D92E6AE
-:10CBF000C1F34F777A343E63F9EE453C8F7D86383A
-:10CC0000E53D583F3FF3B17DBE3C0BF9DD14D0CF7D
-:10CC100005329EE3FBEC7519E3B59F4D67799CD710
-:10CC2000BD71508238CD75A09C283EAE9B20A0BF20
-:10CC300002C7B060DF6C17B56F7C63703EB9708E51
-:10CC40002B6753C334387F3C7E4BA80E9EDE69BDF4
-:10CC5000296F021EA78A04F0D8E91B300DEE4FBAE7
-:10CC6000F34F04EF0FA1EB2CB61FDF410642BDC905
-:10CC7000BE81E80E4C6A5D3F0DE2A3D71F743AE116
-:10CC80007E96AC260BF519A2F89B4C4275B0DF3EA0
-:10CC9000E9A8EF4680B78CDA0B10772E6B6FAE7376
-:10CCA00043B949F0AAB4FF40D05FE8A6F3D8D6F85C
-:10CCB00069E177401E693DE826D0C4EA0536C1C562
-:10CCC00043F07E1DE6D9946C12F0E0D7B690406C2C
-:10CCD000ACDF908DF6BBAD89B6CF837582B6877E0B
-:10CCE000377DFACE8D20EFAF8BAC7D0BDBA72EA16D
-:10CCF000ED54E0DB4D8BB1BF454D0249A3FD95B529
-:10CD0000B075A0EC75D90BDF5BF73F86EBD82C3AFA
-:10CD1000DEE04CD0FB91E95026B98207CFA1548EBA
-:10CD200041BAF5703927534633FD21F032F71B34F1
-:10CD3000BBE95D3BCBF72DF12E5306D07EDE9C3850
-:10CD40003013D202026D9FE2FEF3518A673FEDF28B
-:10CD500030CFDB3838F163A54BB70E7D6667F75BE4
-:10CD60002D689B8AF90C0B4911E6335C3B89D96B22
-:10CD70006F5D610FC115076FC9BDE9F0FEE0155683
-:10CD8000B47FCF6C93918FCE0CEBC2F8F4F12619DF
-:10CD9000CF0DD735B1FBB98EB7B0755C7C92EDEB9A
-:10CDA00097BA142C1F6CBAB110D6B7E39BD879C7C9
-:10CDB000694FCE50A05CDA2C78D9FD454C3F6AFE15
-:10CDC0005B8987E52368FAAF8ACFBB5FDEA249DFC4
-:10CDD0005569EB8D49DF55C1BEB21B9EC6F701E216
-:10CDE000647A10EC7EA07BE46BE4DFEAD765027620
-:10CDF000BFF0717721E663ED15309E3FA95DF0C16C
-:10CE0000BE7ED9FBD610DAABA1E23B7E027AFC03F0
-:10CE10002B1154C86BA778A7FA61A2B5F78FBFA0F2
-:10CE2000EF3F396C834C18CA27C588672DFF336FD5
-:10CE300033CB63C93BBC3E15CE5B92E90350DF9612
-:10CE4000368AC4AFD31B9F08BE1B7FCCF432DE4FA3
-:10CE5000A1D12F4F692881756CA483E92575B30C86
-:10CE60003922E4108F93507B1ACFDF2EDABD2E5576
-:10CE7000A1F5EA79FEC7A2BDEB5245FABE0ED62F48
-:10CE80005A7F91C2FA5FB44FF034EBFAD7DA6BFDF8
-:10CE900069FD28BB8DFD8CDCCBCB17D98F0687367F
-:10CEA0007E3C7B7CE2BF9F5B0FF7C54C7C4BC4A4F0
-:10CEB000E3891FCF1AA9DFEFD09E5AFC35FF1D0B67
-:10CEC000F1E9F036F18F0EE2D3F145EB042ADF945D
-:10CED0006ED7B4092100A575C211A52A0FCB1E90EB
-:10CEE000E76A1EA7AD9ECEF6AD5A730EAF00F99E4F
-:10CEF0009527201F90A05F19908276900AF1F1D2B9
-:10CF00003CD6BE94B607B96B7D8CC921D5072AE8FB
-:10CF10008BEAA67585587F93A042FFADCDC5B8DEDC
-:10CF2000974D14097EDF7404ED8FB2B6232920AF2C
-:10CF3000543ED7C3FA5B3DC58AF7796972A7C9F138
-:10CF40005B32BFAFC9E6190B79FDF7015031E457E9
-:10CF50007C9D303FB54546390B4C6472F9D636118D
-:10CF6000E5F9E015B7A01C9ED92CC491E3690A9C91
-:10CF70004B3E1E62DFFBE478ABC0E598E987E34EE9
-:10CF800026D7D3E03BC8F14E81FB83CC1E34CBB116
-:10CF900026971792DF8A2D26798E23B79D52D74D7B
-:10CFA00030EE9D57D811EE69DFDFFDEE9DA87F645E
-:10CFB000CCFB98F6FD7B5341DF95482C5F49C3635A
-:10CFC00095C4F2D9FAC1B17E9932F8A2E031C2F12A
-:10CFD00084DD15D51F22F039BB872BB849463E3773
-:10CFE000CBE1DF2B3FFF28793EC4F9478347DCCBF9
-:10CFF000DA43FE5884E2E9B596A7314FF5F473475A
-:10D00000AE053C57ECA17C4BE77BA6C5C5EF7B0981
-:10D01000E13A53DE2A621E389122F937BAF472C916
-:10D02000F2902A5E70217F94EF60F9A4E52F7E3C98
-:10D030000EF34496F7627E55F0396E6F06BBC6015B
-:10D040005F974B2C1FCA2CE7373998FDD9BD3B6140
-:10D0500036CC43D8C2CEE997876F91810FB57A3F1E
-:10D0600074C85A3DDCBF0C52BE85FD75804F7FEE03
-:10D070005CCB83EADECAE4BEBC4D467FA97C4B3361
-:10D08000C6B1035B3EC53CF7692F6CC3F841A04DA8
-:10D0900034E63D6E112356CCCB148F58D93A65C86F
-:10D0A0003FAC6EADC2FDB6EA30CFEF33E5BF55BC45
-:10D0B000B0F7C520454DC5AF9F75831E38D9B9D986
-:10D0C0000DF8A4FD61DEE0F73F970C7951F1F37B99
-:10D0D0007DC67CC2F0AA98F98427E11F94C1EF7540
-:10D0E000707ED5F230B70CE079DA91FCA218F1FB32
-:10D0F000BE733BDBBE780AF2DCBB779C7A0AE0AEFB
-:10D10000FCEB674F413E13D967C77529F0DCEF3060
-:10D110004F586BF70B07F7F3B73E8BF9D5673EB067
-:10D12000A29F7366EFF10CC85F3BB3FDEB5488C759
-:10D13000DDB57706C62BEFDA396D1089A1DFB5278B
-:10D14000F065E822F2BBCD7438D87A10F3AE4EBF4A
-:10D150006F457DD697171AAE6279B62ACF076D89CB
-:10D160009D47AFE53156B7DE78DD15A09F5B993D51
-:10D17000D797D778A13CD077283D2FBF08BAB5F014
-:10D180003C5F13DD4EC33F287DC226BA7DD1BAF085
-:10D19000578FC3B7D60171F3402317812F2D4FFF4F
-:10D1A000E70EDF1E079CFBDB91104C63F40ACD12E7
-:10D1B000C0DEFB2203CE359C907B31DFA377AFD559
-:10D1C00003F98CE57BDF43F938B3F330C65509CF5B
-:10D1D000933F43FAFE585EB3C0E7B7C9C5F247397B
-:10D1E000DE21BF5475E37B9E47CAF856CB2F8D973F
-:10D1F00057DAEB18C1E2D0FCDC4015F593F8BD59C5
-:10D200007DF9A6C244A0D311439EAE366F737F1E34
-:10D21000AE37A3F9D1B1F376B57CC1289DD83AA237
-:10D22000E53F9F69E679D3F47DFA78C88363EB75AF
-:10D230002024BC4762C8A3961F7DCA61CA8B0E5DBD
-:10D240005C5EF485E0FDDFC5C7870E16AFD6F0D271
-:10D25000FDE7D8FA5849607627F54FE504DC1760FA
-:10D26000FEE91DDC3FD5F0A5C15B1F667643F716CE
-:10D27000E61F98E5B93ACE7D49297C9CEAB6FDE3E4
-:10D2800040EF741FD8CDF98DF17375CB1196774BA4
-:10D29000F57348AF9FF9FD12E6FE32787F81F6D82C
-:10D2A000FD055A3E8DD9DF49C9770BC07FB293D9AE
-:10D2B0004927C3E2CC58F7DBD8126443FE40BD8B4C
-:10D2C000DD9721BA1D681FDDE59AF87E620A3C15DC
-:10D2D000CCEBA95BC6F3807EE6C57B45EB5C5713C0
-:10D2E00080E77EC08F2ECE207BFC04EC3439AD2845
-:10D2F0004F54A3F0F6D123C542427AFA4B9174D031
-:10D30000E71FE61C97A1BFFF34C547FE5322F583F4
-:10D31000285CFF1914BCCBD4F876B556F6FF54340C
-:10D32000C433AAADBD1F827D4E5EB6E37EB8B8CFD2
-:10D330001EC4F8D853EC5E8D833BBF7A06EFE5F947
-:10D34000959570BB50007D50CAE314C7777EF5D425
-:10D350007F811D098DE9F8A54FD1FA603FB724A060
-:10D36000BDDFB323711CC4014A5FBEEF5AD017A5BD
-:10D37000A0FBC0CE7C6150A88EF6776C202B1FDB03
-:10D38000360CCF0554EC70613EE1C19DBBAA41DF74
-:10D390009F79218180BE3F2D77FD15CA813D89A4EB
-:10D3A0005945BB4FD5AFAB8B88A4EAEDB90A281B12
-:10D3B000F25B08E6B760FC8DF273455B229EFFD0FE
-:10D3C000D5E3F21C1CC2EF891A027247ED46D598CC
-:10D3D000F7CCBE2F4860FA2B60EDBD87DD87C0EA31
-:10D3E0000794DE12566E18C2E4B613EB2FD6F895EA
-:10D3F0007FEFDF2FAB1F4860F180683FAC7DB595B4
-:10D40000DDAF61A6EF4F13047E1EF72F97C4BA7FDE
-:10D410002206FCEC5E2E8104E1FE55B2DD8EF7F1B2
-:10D42000542A913190AFFEA2C2F63F2ADD9131908D
-:10D43000AFBE87EBBF4A072DD3F743381C501FCA36
-:10D44000C4D6F53CDEEBB4CB8EF7E155BDECF2A1D2
-:10D450009FF0E257C79EC8837CB504CC93AE7AF99F
-:10D460005F90FE55D6C8EDC0FFBDDBAD783F69F7D4
-:10D47000F64319603774CB918CE4F3ECEB5485AD33
-:10D48000867D6A6D1E276B974E8673BCDA39C3F2B0
-:10D4900038FAE28D0496D7D19CE0FB15D373C6FB16
-:10D4A000654ED6CE36DC9B586E8BADC75A402FE802
-:10D4B000E27862F45C610BF47B9A74D50FA124A925
-:10D4C000127A717FBC7C4B663AF8BB07EC97E0BEE2
-:10D4D000D50159457F109E7A7D7CA2D69B2BE179A0
-:10D4E000FAAC5C89C2D1D3FC69C91002F981F6D9C2
-:10D4F000B1F4D3DE8404E4A7729B35E6F9CDDF7284
-:10D500007EDB06F236818DE7CD8E8E7B400E2900C4
-:10D51000C714A78AF329A77E00BB276A4EAEFEDC9C
-:10D52000F622A901EB51F9427C2C22EB953C677F56
-:10D53000BDB268695EAE948B0AEB9B3E7E13A3740A
-:10D5400022C114B493244E43B27EB021DF5F928B8C
-:10D550006C802F851479241148DD8072EA20617C6B
-:10D560003AA919C2D6A11A02F1F1137C7FD62AA9D1
-:10D570000FE37D331D22EAF30BE1EDBD0437C26DED
-:10D58000956A8817ED8D591EB0C784A09F7C4BF912
-:10D59000A1AE76662E3B174E7C90EFE6260C3EB78A
-:10D5A000E7D5AFC13EA07CC6EEB1FA3E09D5D1F1B8
-:10D5B000E09831C6FF0AD87DF6E6F1FECCE940825C
-:10D5C000FB0DF79DC35FAF767F1EF8EB897F9D084B
-:10D5D000FB314E0F8980BD94E024918471704F9E81
-:10D5E00074522FBF6EC2CA23283B835EF34C317E38
-:10D5F00037F335F14A9FF7E94511DB7F6E6AFFF992
-:10D60000F9DA6BF808D8367A8FE646F1E2E073086B
-:10D610001678CF75013EC6B9BD754047A5F7C3FB67
-:10D62000001FE39CCC1F4C69247A7F2DD7C9F4D509
-:10D630000A7EFF34FD2B72EAFA231E1BC647577180
-:10D64000BCF7D5D7E226FDEADB25C06BBFFAF6783A
-:10D65000F51DB1EBBBE2C193101B9EA438FD07631F
-:10D66000D7AF7EF9BD37232ABC647A0382F3FCDC92
-:10D6700072AE13FCABC40F538B1957B0FD0013DD12
-:10D680001CC07F941F1CA374EFE1FFB275F41B1143
-:10D6900083FE24827C57CCE1A165E7600ADF8F39E5
-:10D6A000B8D337B1FDCAB977B138D18F6DA5E8EFDE
-:10D6B0001EE1F701CD6D647EF5DCA56C1F9194B180
-:10D6C000733E1EFA1F8C771B7442E97D5B83108AC0
-:10D6D00064C2BD3526FBB5EF7E9C450AD42F36C506
-:10D6E0005D347ED2CE23CDE7F67526E7CF85A4D76D
-:10D6F00005726F3EF7FE0AD76B9ADE0FAE235970A4
-:10D700006E5FB438BCB03F2AF273A6C4CDEEF323EB
-:10D71000BE61EC7E392D8F2B4B4D84F58D84F97BCA
-:10D72000BECFB2E42A7590FE9C9674CE81F783D466
-:10D73000C9DE34D083F2396AD751574D393782A8C0
-:10D74000BA7364D49E43E1963DECBE44C953444A47
-:10D75000C10EE4F7039094ABFBECAEB7281E96AC79
-:10D7600053F1DCEA4227B3337FE12ABAD33901EC23
-:10D77000CB895E76CFAD918EC19D6C7E7530BFCC6E
-:10D78000FE70D7295E2FDA9D57538B01E3385EFC7C
-:10D790007D07D1AABEA7823CFE9BCC7EAFA01F1EF8
-:10D7A00018FDCEA624E3BDEC0BDCAB3F043E5DC30D
-:10D7B000EF235C599B85CFD5B5696877D6D77AF1C9
-:10D7C000A9E1C5E66DC07BDF6CA3587F368F9FD97A
-:10D7D00015D496817C0AC9531381B22DBD8680BDB4
-:10D7E0006BEFC34F03E247E92BFBB16CF5B0DF8D64
-:10D7F000901B67219E697B524ABF2F71F91F073921
-:10D80000B1AB9719EE91B3A68D37DD3768C29BC6D1
-:10D810001FDB18FED60A8C3FCCF85B2B77AAB0AF83
-:10D82000BCF6AABE7B67107FD4BC67F8FB2DDB6714
-:10D830008B8B3F4F32DAAF0BF2EB6FAFA3AF1EE42F
-:10D84000FB8B0FD44E447CADE2F748DE5FEBC3A701
-:10D8500008F8A3F3B3660709DC8FCE7E1B823E9DDA
-:10D86000453EB87F167817F0273A193EAD6935B8AE
-:10D87000BF6673327C89CE20E24576327C894EC603
-:10D880006F0A2F4B80BF5C6C8FEF29FE0E007FD993
-:10D89000D2271BF0A5A4145C1CFE1EA3F8A370A441
-:10D8A00070F932E3214561F7536A7215CF8E7B948C
-:10D8B000CE1FD6ED0DB5049F03E3F88B235C6CDD22
-:10D8C0004CB1D4EC97011FC984AF2741929E4F58A9
-:10D8D000EA21FCA505890A6581C1411A8619EE95E0
-:10D8E000143D92E95E367503F0C1FA43B205EEA32A
-:10D8F00013975E6D380F2ACEF625A9884F3FDED3E9
-:10D90000FC60AD8AF45B0774847B40B9FF753FA768
-:10D91000E703FC1ECA555C3ED672797998CB491D47
-:10D92000BF3779CD4C9667959263E1F79545883E70
-:10D930008F29C91B260A850B6D6A159F78CF22791E
-:10D94000DF1A1A4DDB2564131FF049D2FBF786D886
-:10D950007D8D4583C10E4AD2EE5F9CA226CDC18348
-:10D96000B01189F91D5415A21FD36989754F559DB2
-:10D97000F7800DE2A1F1E049F0FA32EFA7E3253498
-:10D98000BAD07E1FE02F9AB390969D8D0918FF4B59
-:10D99000E0BFCFE2A47097EAE81DEF1EEA8DAEABC0
-:10D9A000125D949E1E80913E1F691C89BFCBF2A818
-:10D9B0005C84BFE3F2285F4FB57BCEB576DF70FDA8
-:10D9C000E8CEBBCCE0B7AE977DD8CE33C528FFEB11
-:10D9D000B9BE4D9E6EE4734DDF1EEDD3B7FE110050
-:10D9E0004FEAB9E9A8C7526E88AD77EB6405EF2D11
-:10D9F000AF1BCBE43C58ACB0FB4BFBEB018C539F13
-:10DA0000F58FD9087A54E3ABE584E99D20717871EC
-:10DA10001DE2F7DB6876F04AB80790EB57788AA3E7
-:10DA2000D8EF0FA4CE65F7F9AEE1F7583D44F98A77
-:10DA3000E0BDA75E7C5EED62FB13CB6DE3F13EB50E
-:10DA40003AA705F584F48135042687B47F9207E26E
-:10DA50000592ECEDF441BCCF2585E1DEDC3A671E92
-:10DA6000DEFB2E24E57980FE5FBA160C3F5F3E1D7B
-:10DA70009D28DE97E94929221F65E36E009E47969F
-:10DA80003D3710881B6E48A9B103DE26B9585CBF2C
-:10DA9000B1381FF148F17B9D6B60B49F41B3AFEE8D
-:10DAA000BB070BBADD10E75CF3AD2E662F91F420B7
-:10DAB00019A593F346ED774ED420C9D2C9FBF2D114
-:10DAC0008504F687FACB791C3DB699E9B115426C0D
-:10DAD0003DA6D9999A1E934DFA417BD60F9F69387E
-:10DAE000A7A5A4788177E119B478C1BE7BB1FED631
-:10DAF00024C4430DE081A45DDDE7BFFE6004D88F40
-:10DB0000F931F9CDACBF16F4ADE7BE54A0D3095935
-:10DB10001D3407F8E950ECF57CEA23973E0C7CB005
-:10DB2000E0B7A2A0DF4F293DB712D7D3927313F10C
-:10DB300059D63813F99E40145CE7871D6FBADB0D88
-:10DB4000701D6FE479004D7208F2338E37DE8DF769
-:10DB500095409EB7A8DBDF27792ADA97DA3D63C7BD
-:10DB60004377BAF5FBBB25BFB0FBC06E8DC75F2501
-:10DB70004DB1FD7A5843217E4A01CC027B98DA37B9
-:10DB8000BD11B07F365ABD41122D071FB1C7CC4F12
-:10DB90005CE29AF128E07D89CBF724C83971B27B29
-:10DBA00041E3F3391BF7186C02C37ED3E33C4F53B8
-:10DBB000F2BBF5F7BBF5DDC7C9E324C416E7BB43E9
-:10DBC000FB7D8338DFDD2C9F8378627FD7FC8484E4
-:10DBD000A89FD006F3A86A3C55FF01E289FB091C07
-:10DBE000EE133283FBC43356F63B3726BE38C1F3FF
-:10DBF0004716090CAF1A7F9FE8B377FC780F8D9911
-:10DC0000FF848D976E9844FBFDAC43C6385C25E5D8
-:10DC10001FE01B61E324CC5F171E99F430E4257DDF
-:10DC2000FEBA88DFCBCFD9F07BF7CFBC1BE6429C96
-:10DC3000E70D19EFEBFEBC6346228BF318E3D00B24
-:10DC4000DD6C9D3FC9E5BEE4DC6AE4CF3EFE68586A
-:10DC5000A8805C959C7B08ED99922D02DE13498289
-:10DC6000BDAF4E95381F4E86F6A70B9703BEA7345F
-:10DC7000E0FE46E966AB77B5D09FCE275DAAE15EB0
-:10DC8000F5D2AE35D82FA1F6548A6EBFFB04CF0370
-:10DC90002E3DC7EE07249E204903BEE77A27CABF60
-:10DCA000C67B5FBBEDB1E3ECDF707BA6E4DC648395
-:10DCB000DF109DDFF7997CF2F5BCB46B2283AB6F6C
-:10DCC0003E1B26C59A4F741E53B07D7752ECF1333C
-:10DCD000399E8FD596C1C90D52A6B07A250D772BE6
-:10DCE000A04F4A9A929205DDBC4A1B2B0C7918A5CD
-:10DCF0004DC5CA3C5DBF513A385E9B3A2A4A87CC33
-:10DD000087E42B973B61BD2F72B961BC8D8BF27F8D
-:10DD1000A2427F4CFF7C223764D4A07EB9D31DEB96
-:10DD20005C43A65B35C4954A1B397DA89D9CA7A37F
-:10DD30008F461773FB63CDA5F93F8178F263EC56EC
-:10DD400090F87AC744B7CCD8789BDC87B72CCC073F
-:10DD5000BA30DEBE63C8FBE987374E5F0D2FDA7B32
-:10DD60006A1FE502BE2643C06920F4C3E87F217C18
-:10DD700045C7E5F49F1A7B1EFEBE792C25416A3FFC
-:10DD80002CB8E03CEE2341DB79E6A1D19F5C66A094
-:10DD9000BFFFA1D157821C6AF45E70E031E4DF0559
-:10DDA000541E615FFE78C3DD86F5210A5F1CBA8FC1
-:10DDB0000A92ECFCFF7374FF440E6640DE57701D40
-:10DDC0005B474E6C7C30438FE725AEA90B812E64F8
-:10DDD000D3C08B5A3F8205DE0E15D72519E361BBF0
-:10DDE0005DFE809BBE2FE37EF58AA4C231B1D67D55
-:10DDF000EA174E81F8735DEDCC29106F93B9DD08F9
-:10DE0000BFAC05F6265C811EEB7EAD064ED7FB6BE4
-:10DE10006B307E4D6C41E2D19FF725CC2EFA86B057
-:10DE2000788BD64E91FD1E887F2AFC3CB22CF95788
-:10DE300066E6411C232527A8C3DF436E66D7AD499C
-:10DE40003BE0817C522BED1FE231B674E9AC719F4F
-:10DE5000929573844932CC474E09138C6766D3F789
-:10DE60003A7C2B2914CEF3F89B92CD8DFB451261A1
-:10DE7000769A367FFA06D7B307F8BAB41CE2B82907
-:10DE8000608759D01F5ACFE394BFAC2DE2789070D1
-:10DE90001DB326B1FA4A2283DB0E716B11D6D50869
-:10DEA000965D70C38E885793E1EF8F2611157FA77B
-:10DEB0006F0089D4E33D2653BBEE81F7BE04FF1605
-:10DEC000E0832F07777E28401CBAC87F09ACBF8D3E
-:10DED000623047A5F57F25F6E6403DF87DAFF79324
-:10DEE000D97338E42DFB75FB52EC5E4E551FD733CA
-:10DEF00097872F954CFB357FBE44FFBD39C1B70BCB
-:10DF0000E048F958C07D983A3BBBD7A7CE7573223D
-:10DF1000ACDF8739BD90FEC03F1DCC8E392BA9895F
-:10DF2000C918DFCCCA7DC530BED75096B8FFB689B8
-:10DF3000F2A3A4BB977594E4B300BF8C6EA0EFF579
-:10DF4000F48B11574B76E2F5B731F76134F8E8B846
-:10DF500004F0279E2B64EBAB890FF6080CFEA08B18
-:10DF6000FB5B2428023DE768F7054B2B5859FBBDA6
-:10DF700008A02285E3036D7F81AC6065BE4F1998D0
-:10DF8000C7F621CDF0CC697FA013E2FA73DA07CF90
-:10DF900087FDA939CE317F82E71EB9F74002D881CB
-:10DFA000770B78FEE3C7BF7B454EA0CF9DEF6CC4D7
-:10DFB000F3C6A7B9DCDD4E7AF11E763FF1F07DF2B3
-:10DFC00010BE9F073F3087E5B00C7EFADC48E8477B
-:10DFD000D7D0D26DAF84AE01B3EDF68EDEDF801AFE
-:10DFE000F0873D85B807A0B56BF3BECACAAC5D1417
-:10DFF0000F366E8FDA705ED179DB100F1FF4E58D6E
-:10E0000007911E7D78E2F72A6978E99B77E2CD5780
-:10E01000439C379E3E9BE3CCFA13DBFC607099F186
-:10E02000F4397CA276E4E76E9F3D91EAB78FDD3E3E
-:10E03000073C2B6DBD19D20894173794AB45FFF000
-:10E04000548A87D3C3FC970C047C740EB8283DFA1D
-:10E05000A19DE901929781F3D1EE7D3F78EF711791
-:10E06000D89DF53BDFCB806795D8B5F6168C6F8AC7
-:10E07000E80F9D6DBDE4BCE7C33E84B8135DFF4669
-:10E08000276A7CC8E677073F5F73476B029EAFB98C
-:10E0900063A968B8B7F98EA52CEF8E489DE36E3260
-:10E0A000D8EB2BE2F6037100733FF39716908F07BE
-:10E0B000C03EAB672AC6059E62FC357FBA4F847CA2
-:10E0C000E4C92B058CB74C3AAAB675D1F2FC5012B4
-:10E0D000FEDED1FC7B97E4C23D04D59D2CBE3748C3
-:10E0E0005C9CF333889F1C60EB389417837C3B7DEA
-:10E0F000AA5317EFEF966B72E0DEBDE06D4E1FF096
-:10E100004FF14DBE0FF0F712791C425B5777351671
-:10E11000631E6BF15C7522D0BD386CC7DF1F2CB657
-:10E1200011C941F558B1446CF01CA410C90E4F0739
-:10E13000B1C1337F39BB27BBA4F17AB40FDC138B99
-:10E1400014B8FFB6B8FDD92FA07DA914D9CFCEB58C
-:10E1500030FC14B71FFA1AF867A1AF08F30EBFB36B
-:10E160004531F87F63C3C6F2E56DC6724EC458CE22
-:10E17000ED3096B7C21D673A3BE2C05E2BAE131579
-:10E18000A7D839BD9704589B201E6C45799A56D163
-:10E190009E0FFBD1A79E7759E0FB9EBF30BFB7779C
-:10E1A000AB1DEF7BDBFF7B0771405EE10BF68DF073
-:10E1B000FD94239C0F71385A9FFDCE5651780CF870
-:10E1C0006F2F5EA6F9E9A17130AF17FFCAF2647A2A
-:10E1D000B75AF1F7534EED7EF679D8173BB575284F
-:10E1E000DA592F09410BF41B5CC5E86FE6D38A2D81
-:10E1F00046BFF89E44A66F7A0486EF4B1A8DF3BE95
-:10E2000034642CFF3C91F953F388EE7D26ECDFABB0
-:10E21000F569B0AE3E1DFBBEE1FBB95C3CF79CA2CC
-:10E22000F1ADC8EF6723AAEEFCD29EE8FEDD5D43A8
-:10E2300021AF02703122FABEC234AED67F5122DB4A
-:10E24000874FE1FB33BD6F88889F93A6DF2DECB32A
-:10E25000EB6A6B064FD7AD43258DFB538BC13F6AED
-:10E26000DA9F3A4FB7BE546E3D987A2BE62549F8AF
-:10E27000BB4C95739E7968720ABC17C3002F7C87CC
-:10E28000B85777F8376EA847EDDDF1A20EEFA58DF0
-:10E29000770F9EAE93D3BF952F3579AAE4F6C9AE1A
-:10E2A000899D8590275ED1C87EBFA922FCA31BE172
-:10E2B000F71749133B679A2F912291CA4FE5F61F32
-:10E2C000FD107E8F2BF0E4042FC043BBB809DE574E
-:10E2D000B47C8AE709569B7E47407BEEE3F4A5F5C4
-:10E2E00023165A7FF5CDCE32D04FB4DF57A07C2015
-:10E2F0006B23DE6FE23EC1E2B4F4FDFBF09328270E
-:10E300000A826FDE4A9B9E22E177AFC984791BF9AE
-:10E310008CF2AD007657EF66017FD7965A5AF937DF
-:10E320008049ED5B8679B7F4FB1DB1CE3B2F0A190E
-:10E33000FB31D3FFF79C7FE95F969E8FCCF506CC2F
-:10E340000AE2B9C4CAA554DFE9ECFCCAA30D789F60
-:10E35000A3791C0CC2E9F20D60BD5451BEEDDC6E18
-:10E3600020822D9FE7CD8E6465BCB710F895324AA8
-:10E37000C56564BA0AF8BE81CC84E74B42E42151FA
-:10E38000647A02E340DB12504F747BBA9E7902F844
-:10E39000AB652CC69F86F0F39EDD6A04EF79ECE155
-:10E3A000F1C96E0F2B97B7DB310FE6D46905F5E89D
-:10E3B000B2F04137D0A3FB79BB057E97F4D4F601C8
-:10E3C000059027D91D66F7FF9E0C0FC0DF7F8DB724
-:10E3D0006E99F581B64E1E817FC27A9AE8FB06D609
-:10E3E0005BB282E5910E1A509313EBF724B47629B1
-:10E3F0004A4D0EF829FF0BC935400200800000008D
-:10E400001F8B080000000000000BDD7D0D7854D547
-:10E4100099F0B973EFFC65669299C9249984FC4C14
-:10E42000420801024E42884851272160C054078AA1
-:10E430001A7F8AC37F80FC89B61B956E26266242AE
-:10E4400051C31A1110704051BA6A1B5CD46883CF53
-:10E450008068B1D57EB176BBFEECB223B088562081
-:10E46000A2A5B4DB96EF7DDF73EECCDC49A2747716
-:10E47000BFEEF37CE943AFE79E73CFCFFBBEE7FD72
-:10E480003F6786BE6BF5EECE67F017CC575C8C9D70
-:10E490000BB8BD1BA0BC58825757306671FA8DF679
-:10E4A00034C66CE58CF9E09FF388BC5B86FAE3B276
-:10E4B000F7FBF6B18C2D637E03C36779C0C00AE019
-:10E4C0009B4E689CC9D852858515273C17FA3E900B
-:10E4D000A6509931F87EE97629D401DF2FDB6864F4
-:10E4E000CCC4E8EF22FC5BD10BE5E25879150B199F
-:10E4F000980CFFB13DAE1DF4BF4A091F9492195B01
-:10E500006D62610BF4BBFA29ED776B5898E6D3F096
-:10E51000DC45637CFFB03EC6606ABF63EABA7C1E1E
-:10E52000FB34C65C0628C3BA87DED187100EFF21F4
-:10E53000FB695D6B5880FAB9A5B58A1D4F65ACF9CA
-:10E54000EED6CC65F03CDB7A4FE6B2A9508FF38073
-:10E55000F1AD8C7FCF605D7B00666BAA593807E612
-:10E56000B71CD69B5406E501293C19CB26164C2E28
-:10E57000E3EF53CAF87A7D71F3AB673D345EFD7605
-:10E58000ED7BF6EB548267031BA47AF6545C3DC026
-:10E59000A341C0A1E139781F078719CF4941DB6545
-:10E5A000580A75A4C3FC9A4E31B6014A4DFB2F1A86
-:10E5B00035FDB31EC6000E19498C99015F8F4AAC18
-:10E5C000AEAF84BE9B307F32B4C1BFABB1DC4EED89
-:10E5D0008E0AF83D7AC38ACC00B47BD801E52C01C1
-:10E5E000E0E930860E07A772D804E3244D8D96A982
-:10E5F000BEE23E5E9E6F2FAED992CDD8667D20D30F
-:10E600000E405C2AFBDFD401FC9E71066E40BC2CE0
-:10E61000D5F972155C2FF315F9611EAC95C3E1B104
-:10E62000B296092D25B179C5E6C7F1BB59EA0BEBC6
-:10E6300080CE82AF48DE3D1EA4DB217DC01A6BD7A1
-:10E640006C97681D2987226F8E41BCBF28B1DDD031
-:10E650006EABF4F19B63E0BBAD733DAC03CA6EC01F
-:10E66000935C86EF59A7047029DF3FFF8E3710CFE8
-:10E67000E549DE71F068DC5F29375A69FDB7FB6157
-:10E680003E1996965D3AA8CFB8BDB80CE91BD67D69
-:10E69000FB02787F97DD43E3655A39DEDDF705F34A
-:10E6A000D796E0F8FE3BDE80F18626277971FC0CD8
-:10E6B0008095CD49CF2E33B663ED12B67B3499F7F2
-:10E6C0009FA6936F9F8FE5325E76AE937CBB89F8F1
-:10E6D00036D1BA338CAC06E789EF4325B4657CFBB1
-:10E6E000A83EC4F13BABA514FBCB18CB9F2E4338FF
-:10E6F0001BFB795BC5F740A68EA5E37CE1BF613EBD
-:10E7000077EDABCC70C2F76F7F6E527429F0743323
-:10E710003688ED94B095E1B3B098B73789F6A5B3D4
-:10E72000327033B872B5EDCEEA7D2953012EC17730
-:10E730006586F8F8CAEA4B7140BB6F19F83A12F1D6
-:10E74000B813F103EB69BE00334F8DC35BDD790372
-:10E75000F6D77C4161A1A9B1F79FB79958A828566F
-:10E760006EA83F3407DB35B2C1F548578D7D1616CC
-:10E770008AA3F76F258D3CAE4ADFCD17742C984ADB
-:10E78000E49BEDB7217C86D62FC7F91F90D81E8653
-:10E79000F506168C1BBFF982535B8ECE339DFA892A
-:10E7A000B563DA76FDBFA7766C7A2419C739638F13
-:10E7B000243BC5FAF0BB2C99B5205ECE8674413D52
-:10E7C000ECE3331E5E7F96B19A3E6BACBDDADF9907
-:10E7D0003A030B13DC87A85F844B1078DBB6812FDC
-:10E7E0000C1E28370C1C24B8A8F4100F9F601CDFE7
-:10E7F00048EF180CEB604FFFDABEAAABC40CA83888
-:10E80000A4EEDF355DBE99502FEB34FBD9521EDDEF
-:10E81000DFC4561ED5C9821F347455CF8C2FF3F632
-:10E82000B1EF1B6BAA61FF9797F0EF8FDA9B8EDC3D
-:10E83000A7C4F811AC2317E1122D9B12CA56284F1A
-:10E840008E2BDB13EA5D09F5EE8472366FFFB92D6E
-:10E850009C2B7B19FBD4BEB64601FEF279667891FB
-:10E8600004E58D1D77D554039F6B2C1FF4C9C83F59
-:10E870000724AFC462F06BF2325F08E067F5460C24
-:10E880004B4B100E836FE2FE6FE897EC12D0B9B5D8
-:10E890006F5F98CAF89D27EEBB3E89BE6BE8FB9878
-:10E8A000BE1BB5FF621DEDE30DC5C7A81D00C07EF0
-:10E8B00002F0741393580A80345F09FC11F9646301
-:10E8C000DF275CEEB221035F1FE78367327DAF1362
-:10E8D0001F3C20D971DF45E90EFBB5C6E85D6DFF31
-:10E8E000D1E4817FC66E2C777DD1AE40FB7F6BFC7F
-:10E8F000641A03547D844DAE40BE1A9A80F2781B90
-:10E900000B4C4039F4DDC6710775D0EEA83EB283DA
-:10E9100001BC8A1D1B6A146877D416C99180874C84
-:10E92000DCD4CBCB69911D08CFE0A64709BE477365
-:10E9300022393A284F718479795C6407966FDCF448
-:10E940002C2F4F8EE4C8F07D41F0B99A6A28EFB1C0
-:10E950008FBC5FF31C9C8FABF33B31D697E54843EC
-:10E96000B2E37262871E2006FC70D1EACF9EDF03FD
-:10E970007058748F85F8D49ECFBF33CF4FEB0FFA0A
-:10E98000950AE0879CF4B91C237EAC901E9089B256
-:10E99000CB19C3872D77D0437C7E62CB3E94F71989
-:10E9A0008B4A88CF5F48F1B53BA6C59EBF4BE7CFEA
-:10E9B00076879DF36559E7A3F6F7DA48EF79D8CC67
-:10E9C000D703FB86F06B15F82817EB2977E8E89951
-:10E9D0006B9F4DFD7C28F9B69A647CB2A019F1B901
-:10E9E0002A89F48C5B77015F00BEDC2BE6DDBB6916
-:10E9F000422808FDDF2A313FF28D5E872F13F9C3CD
-:10EA00004B7F916FC7F5F69642199E3F15FCBE7776
-:10EA1000BE2FD31127177B77F17A95EFF4E6F3EF4A
-:10EA2000557993D1C1C7C97878C26E5C8745613E7C
-:10EA30002C2FAF2BDADD4E727B01CD97F97C99122A
-:10EA4000ACF7C4AA021DEA912A7E9442DF75587F72
-:10EA50000BF66F8DE1491DBF1DD79D867A00C87DDD
-:10EA6000586F9B33D08EF8043D600AE981420F68ED
-:10EA7000C7F5C6C197299169F8FEFF2338DD89EBF8
-:10EA8000FEEFC269047E11C4711B5B815FE8E2F88E
-:10EA90008580DF6629ACCFE0FCC28B720EDF2F00D1
-:10EAA000FE788B3DF000F6AF8EBFE8DE46D2FBD499
-:10EAB0007959FEEEE59A9BD8F07D96A8971DFDD07A
-:10EAC000B491811C3B6AE823BE78741EF3B623FF21
-:10EAD000D0B17A84A3AA5756DCB3E66D06FAEC9758
-:10EAE0000E99F0DC2DF932715DDD805713CAE1F922
-:10EAF00086D09EFC985CEC7584B6AE40BCDE50E2DD
-:10EB00000D7A483ED27E0BB65AA85DAF23C214AC34
-:10EB1000BFC2638799209E091F43371B42BB25C490
-:10EB200037A797DE5513434189F01EA4EF6FE6F433
-:10EB3000D33B9F917EDF7BB39BE8C6CC42669CCFE4
-:10EB4000687490DEC1888E98E29B32DF1683C32FF3
-:10EB5000C5BEB694475EFC17D423379A498F4499B3
-:10EB6000897617EBC9A0F9023E5F22FA50EDA5475E
-:10EB700032431BC83EF356203E1EB0F916D3FC7F2D
-:10EB800060F1E0FCB79B5997A90CCD0FD649FC4E1C
-:10EB9000CC87F53CC6503FBB5DE867FF5E7FCE8605
-:10EBA0007AC01B0EAE5F21A19880FF2D61BC7EC98B
-:10EBB0003ACBC768CF2C5927878D60AFB0AED9BE8E
-:10EBC000489C9D411405FD0504BF645B866C483775
-:10EBD00001FC2E19FBFFA3CD63C5327C3F05D10E8E
-:10EBE000DF17C7BE7F5FECDB45329F3F6BB378100A
-:10EBF000BE897CFD7D757E3D8FF9E2C753C749EC28
-:10EC000017ECB80F903E01EEE114D4E77F20135EBD
-:10EC100013E7EB320C3D6886FA456DB2E33E806740
-:10EC2000A0D546EB55E77B7BC6D095645F25F47F86
-:10EC3000D2D254A1E0FA85FDC1D669ED2FC60CB140
-:10EC400032D0C572364476CCB0F7C26E4DB4FB18E4
-:10EC5000FB8B31BE9DBA5F98474A98BFA02B8FA40B
-:10EC600020DE0212C79BC130B408F94EE2BC5578D1
-:10EC70001A9D3A01774E1789F0363AB9DC4984B7C4
-:10EC8000CB10C9C17E03AD46825362FFAA5C7CCC27
-:10EC90000CFB07E86E8B2411BD6EB9DB42728E99B6
-:10ECA000389E9B572779907EB719869EA67DF5AA38
-:10ECB0009121DECF9A875E227E55C8FD0A677F29A3
-:10ECC000EFC27667D238DD9F79454FFB8D4F06F452
-:10ECD000A15FCABBA95EE2FD9E69B77870BF36230B
-:10ECE000A461FCE6E07FB63180EF711DB7939BFB1A
-:10ECF000B5F6F019F8575F16E31B67191F27D8CF31
-:10ED0000F904AC74158D736B12DB00FD36E9241F1A
-:10ED1000EA4F4DAB27863A383D99703F3588293503
-:10ED2000E9C02E2C8BEDFF26DDB122B4AB1A4C1BB3
-:10ED300007E564AA3F8CF618437B0ABE5B8D1FE58E
-:10ED40000F877FD3C6DFFE19E7DDB45F4B170D31A8
-:10ED5000FA912E4AF87D1C3DE5C7E884F46FE41F64
-:10ED6000D52C344EE27E1A2C5B6A0643E8A769165E
-:10ED7000FE8BB4439139483FB6F23EB6049ECDA710
-:10ED8000B8FE316360D7EB68073B6A06737099CDB4
-:10ED9000AD6BA79E981AC3AF3ACF2B0636C968DF72
-:10EDA000A97A4B9C7D3961C1E4F8E77DF41DDAABAB
-:10EDB000385E045FE1BE51B8BCDB2CE41DC845E2FF
-:10EDC000CBCB7BC6935C44B985FC4DB57791DF21F5
-:10EDD0007F79C659759B13D6E94DADBAC9398D8F68
-:10EDE000437A3E1A49570C8767A2DC51DBA1DDDB71
-:10EDF000621DBD5DD40FB43585F30F45A2F28A5F65
-:10EE0000E8776DA0F929442F6B77E4133F56FD3561
-:10EE10000DC24FB542F8775608FFCECA2D46E68997
-:10EE2000F76785B4E506C10F1A5984FBB9F6427D30
-:10EE3000BC5FA79A856D588FFE1D7CF669BF6F6613
-:10EE4000A1590AE2B7FFA231FE3DEBE5EBBD5DE063
-:10EE50007DAB99FB7566ACDB257367155F6F4A99CF
-:10EE60002FFF7E94236FE9C9FFF01F024F2A5C2C0D
-:10EE7000CEAAC508EF24B4D7B0DDFD4682CB0990F9
-:10EE8000D7FB84DF6301DAA16D81CCC242048F3DE0
-:10EE900077816D387C37BC6AAE477AE97172BD45BF
-:10EEA0007D3FC7A9A732F98310EEED16D2BB01CC86
-:10EEB00053908E2A0A5439CAA6A01FEA633DE8631C
-:10EEC000506EBAD11AC0FE22A837407987E05F3B66
-:10EED0009C06EA4F2D47ED3C412F300EF5877E19F9
-:10EEE0007F1C1D3C156DBF49E8939C2F6C5E9544BB
-:10EEF000FC2846B73A46745BE237A03FE955C14764
-:10EF00005E0580929DD567E67C44E1FCE9D553130C
-:10EF100089EF1DF96C35F195737549CC28517B9FAC
-:10EF200084F52F1A43F7417999F0B3BE2A713D3128
-:10EF300078C046FD3418025BD1EFD0F0C2382F60A4
-:10EF40008CBD6408FDE869AC7FCD4C7EAD86643E27
-:10EF5000CF8657C7109FFCA93EF4EC8FC94F6124A0
-:10EF6000FDAD21C99342F53F4F6558DF65098471B6
-:10EF70001F6519B95ED960081739008EC7425C3F1A
-:10EF80003E868C06FB1FB091DE03D3CCC4F18F7795
-:10EF900067783778627039FEE024A2FFCD7A8EB7A9
-:10EFA000E02BDCEF794CEF9F9309E5632F967AC154
-:10EFB000B26467FD86B001E6D8FC30D7E796EA3C3C
-:10EFC0003B5B9137BD66F16AECD18756D6627DF323
-:10EFD000EA75D7211F1C6D3F233F8FF7E79E6143E2
-:10EFE000B9648FD617F48561DC330313BC243E99D2
-:10EFF0001B900D7462E76D4FE801DE485F07F44433
-:10F00000BF97DA3FAE17ED43942F384E33F0DFA8A9
-:10F010009F99F86F5C591EA9CCF1D9FC6A86D0DFA4
-:10F02000B4F5B7A604CEE1FE6AFA87DF1F6D25F8B6
-:10F030000E11FF633DDC7F7E42EF5B8474EAA80E15
-:10F040001B96C4C9EDA4542ECF971A859EC7C286BD
-:10F05000F87DA7D6575469E95C7D9A5339BDDB0624
-:10F06000391F1F5EAF13FBE13B46945BDCB503F633
-:10F07000F629EEEF484AF550FD8C5361C35228E75C
-:10F08000AD0B1B568827EE0B8077D804EB3EB1D52D
-:10F09000C6F7338001FB59319D91BEB242063DB5A2
-:10F0A0000CDF7BFA238097932F3A387DFD09A0026D
-:10F0B000F05ECC443B23E8B5C0B75EEE94C2A8F73F
-:10F0C0002FDE62DC6DCEC77DEC936D88CF1D12F113
-:10F0D000ADC59D95455BA1BC7AFF64C27FF2744EBD
-:10F0E00097AB430E927F33041F5C6A0C1948CF7EA6
-:10F0F00096FBF1A07FD2971BE0A3CCB2E17040FE5B
-:10F10000ADA18790360E31A34FF0D3BD71F1878248
-:10F1100038BEDE97F03DE8795AFA08AA7287F339CB
-:10F12000E6C9403EA7F2618BD33F2D95F050988100
-:10F13000F8057C723EB94F22B836B2162E3704BF9E
-:10F140008F8E2BE4C54939C8E59271133DE7A5E6DA
-:10F1500013DE56A3BC21BF3AB7FF46A38379A93A71
-:10F1600061278C4C07D70A3A6838C5C257C2780D58
-:10F17000EB58B8710A7FDAA6901CE4F2D024E21DA5
-:10F18000261E0FF926B998280787C9BD047997610B
-:10F1900010F24DE039DEDF8DF27EC6BA908C7ECF64
-:10F1A0005CBBAF32635A4C7F697EDF64F25C86657C
-:10F1B0003F2BB0A2FFA6F25937FA7FC15EC77D652B
-:10F1C00001B8EC42F9A2EAB76EBE5EB781D3AF5E7A
-:10F1D000F1B3522BE26590ECD9A13466477A54E141
-:10F1E000B9C306DF95E1777CBF45BF37B1CEA4B880
-:10F1F000EFAB5E35135F3DFF8A2D6424BD2390E79E
-:10F2000080FED23F32921E7AE6551BC9CF3342FEB2
-:10F21000B954BF005B4FF85927F01A645563D0BF4B
-:10F22000CAA479639005AA7A58A363347FB7A8CF9C
-:10F230001FBC91D39591ECC9F38EC8F7B10CF36163
-:10F24000A85FDF25F0DCBC7F56E9BDF0BED96FF5C5
-:10F2500072E8074A915E8DF25D37A2DF658EBC6E63
-:10F26000E86E5847638ED56E844FAAF3FEF53737A4
-:10F2700043F9D3FD7A66443CEF9955C70A46E7BF88
-:10F28000AB42FA6391B8FDB266AFB6DCD8A72D37B2
-:10F2900033E558248E1F3F9E6A739D9C44BCC37BFC
-:10F2A00011E8DB686C39B50BE66BFCA991E4514BB6
-:10F2B0006A20949A867AF9D09B086763DEE753D078
-:10F2C0008F5195F7278AFB9CFF01F3E2BCCF9B2B64
-:10F2D000497E9FDF6AF604E3F857B3A0FFDEDC5AED
-:10F2E000AAEFDD66F448BCBE765A05EA833436FEE2
-:10F2F000997400FFE62D733F25BB09B57628F7A268
-:10F300007E89DFBD2085DA517FDCC2E5DE69D01F52
-:10F310004D309F9308678C7BC803734CF09FBDCE24
-:10F320009A09C85F943F2B7EC4FF03D8559CBE7BCF
-:10F3300020CAA7B99FE75AF4F38C253FCF01E41BFD
-:10F340008DA688A112FAB9FACF5F115F5ED9BA848F
-:10F35000F4FA989E6B243EB2F2EE00BD7F7DEB3551
-:10F36000B4AE93B06E84CFC91DDC9E5B996D0DE188
-:10F37000FCAE7670FD77257C2749C3E19208874F64
-:10F38000B65FE3467C7FC2F878C13EAE277C621F41
-:10F390004C26FEE36949463DAF79CB359F22DF5AC3
-:10F3A000B943F6A21C67076CE41759B963F684E504
-:10F3B00056ECE7CBD44A84DBCED97699DECBFE106F
-:10F3C000F7AF0C5E0DEF959D977B709F1CDE61E49F
-:10F3D000F373989EC6F95FFD6799E85ED1B100EAC4
-:10F3E000ABBD06DF04DC6F9EED7BE6205C3F999FA2
-:10F3F000A5A3F6CF4BCC8E7070B4A6E3FB9592E23A
-:10F40000C7FD55BF65556DBC3ED2952A137E2AF3C4
-:10F41000D6A547AC44EF37A29C6BDCA127BDEEF02C
-:10F42000820F7F73B32B46EF2BE59E1B67C4E91B4E
-:10F43000CDDBBF2DE8012436C069A58093316F5D17
-:10F44000118EFB4DF4BFF2BE96221EAFF9FA7D106D
-:10F45000DDDFDBF97EF833C8FB8BE8EFCB766AF4AF
-:10F46000FBD1EC20D51F6DF232DF1E2BC5157D6858
-:10F47000E716B814AA2F400202FA52FEB076EF3B0C
-:10F4800030FFFDA9018B0BCA79CC578A78F50CD9CE
-:10F49000AB409DC42591FEC3B61BB93EA970BFDC2D
-:10F4A000E634F6F486B879E68AFE607FBAB09F3318
-:10F4B0001FFCE94D845F53EEE75378BCED2B8A5F68
-:10F4C0005907785CD3EAF533A48BE681F96C594986
-:10F4D0008C1F367B39BF1EC6575C7ACEBF5C43D4C7
-:10F4E0004F4D1AE767AA3F785B6B12F9FDB6B94238
-:10F4F000666EDF0619F2F3EBCA651E8F117A895F1B
-:10F50000F8D14CBED719C66B9857F68E83F2A0EF90
-:10F5100078672A94DF299FED95A16CF53DD9558038
-:10F52000EBF6EA45FD58F227BE3DB392F493EB7C2F
-:10F53000328DCBEA93C95E1FF4BDE75A06E35ECF76
-:10F540007CA927608C1A10D688C7411C1BF0655413
-:10F5500002D35D7176D3B7BD73534FC4CB4B1F97A6
-:10F56000FF688FF789B8C24870F0A6565E85F0BD77
-:10F57000FA2A8E87CF9EE7F6C76766EEE756DB7DF1
-:10F5800066E372C6EF52FD847DB9C8E7A3E5DB8A66
-:10F5900035716297A12F17F7D96F256D3FABBB74FB
-:10F5A00014BF5DD5C5285EFBD98F5ECE457EFBE9D5
-:10F5B0009E977397C4CD2FF13BF5798B3A9EF04B14
-:10F5C000A97E4A97885B2FF11AB93F70143FA5DADC
-:10F5D0009E6DE1F6D859E0EE4877EA7767EB937CC9
-:10F5E000A8579E6526E2674B0684DFD3E72B74A1FC
-:10F5F000FDA07E9FD0FF23827EA47E89EC734BC941
-:10F6000010F1D75526FF9B633C98B7E223FCCC450D
-:10F610003C4A48AF3E03AE5B11769E51F1DF8178E4
-:10F6200058DEA3C5638E4BC433EC2EC2BBA1C9AA5E
-:10F63000A07C48EF10FCFA7B3AB25F0C596E2BF2BB
-:10F64000A5AB8B923A312EEF4A4A9E827EF59CAC56
-:10F65000626A1FACE2741D4C67E4B7CA642D12F1F4
-:10F660005B3BF783674F6776CC03F9A98BEB0D6E95
-:10F67000E6DD22933ED827513C40AC5FE5EB482FB6
-:10F68000C8E73E934C442FD28044FA9DACEB5B8498
-:10F69000FD8E463F5B5CAA5DCDE9275AFE1BD1CFAC
-:10F6A0006E75BC61F413A038DE12B76964FA117E7E
-:10F6B000D74B6E3F5A1CF17B26D50F2DE17A6B4557
-:10F6C0007FB5266B589E42FCE1F3787FEA76D03313
-:10F6D000D11E51E38E633A167BB89E3E1841BBDCC7
-:10F6E00072B989E4DC0F7583F9A8CF27C62101B36D
-:10F6F0000EE4F7C863C8AFD85AE53F911A27EF0F59
-:10F7000070BBA1E96E1FBD9F35C0E57B73A181F47D
-:10F71000CEE67E2988786EF21B42A67C8ABB2C2618
-:10F72000B9FDA0D9C3E3289E768AA3FCC0C3E32C0D
-:10F73000513F6A64E7BD486FF556F23B24C6635EED
-:10F74000FA8BCCC71FC768FCDE521EFFE99DEB2178
-:10F75000BF46629C8D7569F7AF1A67396B03C0C0ED
-:10F76000784B369A090F593287334B3171F9329CF5
-:10F770000F90BF367DBA408C888744F73590249629
-:10F78000B344BD1ABFB195F8F351C35D94BAFFAD50
-:10F79000A4697F4DBEC33D3FC47C8651F31D82C624
-:10F7A0005AAC37A1F62CEA71DA206FD5B2CFECC192
-:10F7B000F84EAC5E01BDD1D42F89F15EBE7636889D
-:10F7C000E0B3923A7EE7069F95E2C99AF1E2E7A795
-:10F7D00024F4AF87FEAD1ED13EF8E3B9B30B296E1A
-:10F7E00029EAA50D3E98DFC37A6D7F0452F13D16DC
-:10F7F000D4F10E67D4FC70E3CC98DC073DC09A3698
-:10F800002D26FF1FF8B0B6E73218CB62FFD2807208
-:10F810005595E3CD2E9EFF90B85FD3D338BF07FD3B
-:10F82000353D8DE40ED76B6B45FC12F4D939B8B574
-:10F830009AD7F919C62F415FC84A237DE1F3930790
-:10F84000117F0B3E237DBEF982C2FD2EA077A07EE4
-:10F850006E1274CEFAF5246F553A582DF84FAF0357
-:10F86000E43DD2EB01695A90E8A225F706C0C1DF5A
-:10F87000A7F90A711EAADD9538DF2BD3B87DDC5CB1
-:10F880005CB5B508FB7F4A6228EF37141F4B47BDB4
-:10F89000A479E0E3F4E571DFADEA7F94E0B06AAF0C
-:10F8A0007EC4F55F99C6E39D4DAFBC48FEC1CF4213
-:10F8B00012EDE57A25D43D03CAF5F53AD4D058794E
-:10F8C00068F1CDE4EFAF33B071B0BEB1288F701ED8
-:10F8D0007BBF139C81F619FC93E0D536FF0A927B1F
-:10F8E000DBEA4C568C3B34172FB983E0604FF22192
-:10F8F0001C36145765E2384DF3E7D8294E00FA1547
-:10F90000D637DD7D0BF94DD4796DE8D7D7A0DE551C
-:10F91000017AD63FC1BC739CF36ABCB0FFC6C8FB7A
-:10F920004AEFB462DC7864FEFB5E3AC767A7E40F77
-:10F930005E5F4E7E4216EFF7CBEBE7FADC0D690611
-:10F940008D5FF8863485E0303338380B69EF352524
-:10F950006241BDB799F9BE40FB92F9AD9E3D842747
-:10F96000CE475C6D1EF21F995C911F5E86F53315C4
-:10F97000B21F98127904C73DD3EDF26E60827EB15A
-:10F980007C774908F9E8EB69812588DF0AA13F9E69
-:10F9900079E59A52F4B3A9FA51F72E7308E384DD9E
-:10F9A00036CF3FD4201FFC83C2E3E2A6A1C1598811
-:10F9B0008F3F3AA9DF6E73A81BF11FDCA4A7FA578B
-:10F9C0006C8146A4CB53F36B8A282FC71A2CC238FC
-:10F9D000B0DED5C3504F007381FC0926979F61BCF0
-:10F9E000745670B122219F4FD03B6689FC52629EB3
-:10F9F000F0BE4AB0B1714005274DB4053A2FA6C6F6
-:10FA0000F490237F5AA8E04B553FD199783CABBA8C
-:10FA10002E89C948F7EB87DED4A1FFDA3548FA6BA7
-:10FA2000639F44E33416BF40F9626B445E52343F37
-:10FA3000488950BED4FA348BD0033BB91ECD06C9D9
-:10FA40005E66CF717C3216A13CAA981DD14EEDD4D2
-:10FA5000FE0CC2EFDE28FC2E20C1A87E539AAA5FBE
-:10FA6000DEA7F5D78B71374B833E19E15A2A69FC23
-:10FA7000C5EA73AFF83EE5D0D01CDCBF43AFA87930
-:10FA80009C3C4F73EBB4895E549D86E571F67F31E3
-:10FA900007E906146DDAAF4DFD9796C7F9BCD86734
-:10FAA000FFE3799C5EC9B71B9E2FA739B4799C5E92
-:10FAB0000E3F35CE9698BF792633ACF07CACC8CEDD
-:10FAC0003D489FFD46CAF3AAEDFFD9FB281F6B4DA9
-:10FAD000AC0FE390897A469BFD3B61A4FBB3A74F33
-:10FAE000EEBC9F611EEF4B5ECAE748D01F12ED844B
-:10FAF000DDD82473747DEF37517C727D2F5AFE1F41
-:10FB0000D7F7B83E1FDCC3F307547EDE2CECB3B34B
-:10FB1000F5E79251CE1C4B53F5CF843C87A7449E0A
-:10FB2000C3C0C8790E8AC817027D3D4874B28FC71A
-:10FB3000758E3C6D21FE71CEAEEC467DE9B46DE86C
-:10FB4000FB082C45E8499D078C1EE417C0EF887F11
-:10FB500007F7E9799C06E33618C7796D8288E38850
-:10FB600078D1AB16D25B1A923D29F8BD1AA7F9A934
-:10FB700090370D493C3ED36509FC3E6D84B8CD2ECF
-:10FB8000A17FED82AEECD8DFFB4611C7060681F6F9
-:10FB9000CE83393CEE20E2366745DCE678B12E6C48
-:10FBA000E07E08F25379BA149609F59EF7CD210F3D
-:10FBB000F767997420F797AA719BD7B89F6AA988AD
-:10FBC000CF1C5F3087F28796637EBC8C7E0CEE671D
-:10FBD0008EE6EB33BB0ED7B306D8C5366431418011
-:10FBE000FAE5F05AD249A84F783AA14CCAB2AFA769
-:10FBF00006C65DD2A9237B646997D65F7E7EC31D4E
-:10FC00003528BF1FE8E4F1C7609744F27B29F3B9B8
-:10FC100051DF50E9615C7A2AD159B053E7C371AE24
-:10FC20004CE7FE04007D88D6279E9D7AE16717F396
-:10FC30006867BA303E75127F3E60576A4694CBA221
-:10FC4000BF4E7D8BA912F5D81C1DF979CF1B7C7591
-:10FC5000E427751611DE3A6D2D5D35BC9EF6CA7926
-:10FC6000F3909FEAAF54B8A2C73C4EE49363D245E9
-:10FC7000FC2661BDCB7BB4E5C4F8C3AA90B6BC94A6
-:10FC800005C667E23985BDDAF763D239FF3FBF2188
-:10FC90005FF8F9BDE4E7EFD47B7E958F7CAA5B210A
-:10FCA0003ED99ECDE1A5CBE1CF0247751DE9070EF8
-:10FCB000D02B68BE7CFE0557BA2494979D0E4E97B4
-:10FCC000FFDD7927CE77767A11D71350B9C37DD46B
-:10FCD0002D8538BCF8BC2FD55FB1225D6B6F46CB4C
-:10FCE000FFF3F626A7C76E59EC373BF19F2522DEBE
-:10FCF000785CF23E1DC6F756D00B60DE4BBBE5329A
-:10FD0000D44F667DC74AEB687ACD1C32427DE3BA98
-:10FD1000482EEEA3A6AA4851CB0870C5D92A2ADFDF
-:10FD200082764B5C601FE0BEEDD2C6A186C7157D12
-:10FD3000F7A6A7A11D727CDFCF10DFFBCC2497E0D4
-:10FD4000BF0E1AD1DFF14A3EE94B5352021DE9289A
-:10FD5000CF93C23B9FC947FD84EB478D03C65DA887
-:10FD6000FF2DE9D49EAB611BB5712ED6E5247F062D
-:10FD7000EBD5BEC7F32B9AEF86C5BDB89CDF6C08E8
-:10FD80004C40BDEEEAAB787CFDF42A1D43FC2E9579
-:10FD9000BD2B908F9C366BF5EED3368EAFDDE9AA86
-:10FDA0009CF116219EA3E56178F616219E97EA58EC
-:10FDB00020BE9F46C4F354CC4EE7783EFDE2E545B5
-:10FDC00088E7CFF75D5E8478DEACEFF1E1BE79C6FF
-:10FDD00019781AE17362B69FF42635AFF252E9B191
-:10FDE0003F811EFBFFDFD1635D7CBE5FA21C3C1C1C
-:10FDF0008597560EBA0C9E6CE4874B4CC6AF958720
-:10FE0000F837A23FCD64247FC46B7FFAF221946F50
-:10FE1000C10199F40FB5BFD794C058F417BCF6BE12
-:10FE2000DB1B9446EFBF45E8556E130BA2DF43D5AD
-:10FE3000F755BD31911FBF2FE0782ADD578B7AB679
-:10FE4000EA9FAD177D9A425F72FDF42989FCAF26C7
-:10FE50004F1FCFAF3FB0D88EFED95321EE8F6D7AB2
-:10FE6000B194FCB5AB42AF8731FF890D4876B41B26
-:10FE7000563DF57132C6B3C10EFD243D2EBE325B38
-:10FE8000D8A1A742C79331EE0DE3D7A05CB6B886E0
-:10FE90000C48BF4D609F4113D6A40CD1B9A22617C0
-:10FEA00023795FDEAFB5D7D4F8E436BF81F8DDB68D
-:10FEB000012984F659BA21909F8DF28965DB4F5A4A
-:10FEC00062FBE577E93E17C62D637161DFEF715E76
-:10FED000AA5F27B23585E830A2673ED203B6DA04BE
-:10FEE0005FE2F19ADF6D778478FE126FFFBB503EC0
-:10FEF000955579BD429CD35B21CEE921FF0E27F0B9
-:10FF0000EFF87234DEAC9E47037E1E1E29FE1D975D
-:10FF1000B714FF7D131B12F979178D9A7EA3F93A56
-:10FF20002DA51E98F79ADBAC740EB119E8BAB52C62
-:10FF300046870D62292A1D3609BF6E73FD31B20353
-:10FF40009AF1FC05EA555E4E870D601F617E67E2FF
-:10FF5000BE657DDA7CC6D1F6716986761F47CB7F98
-:10FF6000233FE6CC0CEDFE55D7AFFAC1A3EB1C90B6
-:10FF7000F8FE4A5857A25D99E8BF56EDC24BE56BB3
-:10FF8000DF89CE87C3235AFE1BF3B5DB3346E36B11
-:10FF9000DAF8C05FCDD712E30485DCFF8D71028CE7
-:10FFA000DBFE77E3049F7A7AD2753C4F5F133FED17
-:10FFB000925AAE338DC5B8228F2F37DA8C14874D05
-:10FFC0008CAB367BE68838E2E06FAE40B9B95FCFE4
-:10FFD000509ED75B5752BCB2597ECE80470E87C524
-:10FFE000139583A4B7FFB571F5F5193617F1230FF3
-:10FFF000CBC7B87A625ED1EBD62F530371F8AD2A26
-:020000022000DC
-:1000000001857F043A362941167F5EAD3783EBC107
-:10001000AF8BFC17B781E7B13F6C033B0BD6E7D63C
-:10002000F1FC9CBF4FF36FCE48433ECEE1F7C42BAB
-:1000300037313C77F484BE8FF844B0D1EA457EA7CF
-:10004000FA55A2E309FBF352E9FAC709FBFCC77FA3
-:10005000E37DDEAFD2F35F1BEFDA026BD5D03FA3B7
-:10006000B8D6DB18AFC91F4EA7A3F5331ABDFE22C1
-:10007000C3FF6606ED33DF14CABBBD447E62291F91
-:100080003A8EFE1BB6DFE8417BC224CE65B08D9967
-:10009000224FD25B319FF285F9B906F5FCC7687A29
-:1000A000DFC7D1FDCEF5BE8F47E53BFF35BDAFCDF8
-:1000B000E93F8E72F644A5AF08E5E20336983FDAD1
-:1000C000733F328E78CE423D0F00F4C4CF9B3CCFBD
-:1000D000E3DC8974F587047EF987FF257EA977FF25
-:1000E0008DF865FD1F93D1AF397A3F419EF75B359F
-:1000F000E8137129867121751DCD833CBF2C5DE409
-:100100004DA9EFBF127AECED6E5F861B9E9F7F605C
-:1001100032B114507190C650DFF25BC9DFDFD4C733
-:10012000F3409AD6318AEBAAE7289BFAE733D4EB5F
-:10013000F6A706F2F1FB073EB406E514F4832F6040
-:10014000A8CF9DF980975B5203E3B0BE795D44135D
-:1001500057A8B8F8E57AF457C07CC9FE7719B5E717
-:1001600029E6BB393F539FD7097847D7E5E2F364C7
-:100170007D7208F5408B6790FC444DFBB9725621A7
-:10018000FBC81FCFD638E97C44D3FECA523A6FDE93
-:10019000672E453DB6E2A35A3BFA1F3EBFD24579D2
-:1001A00004B9726415EA51AFA70566E27C6DE5A15A
-:1001B000B9A887E6811E8A7AEDE7FBE69606E2FC9F
-:1001C000D99BD19F0DFD6EB669FDD5CCC4F3C0EBB4
-:1001D00077F33CDF576C8139D8DF66339F6F7093BC
-:1001E000C86B167EECC4FDAFEEFBE839C75B4D145F
-:1001F0007756F9C2663D0BA05C53F94989C8830361
-:1002000078F03CBC81F93C9F4394AD2E6D3EE2A951
-:10021000F4D925389F12378F0B2C370D49E8575FDB
-:100220002EE2ECD7887C09353FCAA8F8BF8BEDD900
-:10023000BA9A587CBD00BFB78B73BF3C0FC67281A2
-:10024000EBC7057603D18D0DF617F93F806E103F91
-:1002500033870667E179A2C2DEF04C84E76B17743E
-:10026000040F65FEDB141F4941B4413F633746BAB2
-:10027000C7A39FC4FEEB2B112F9E1E7B15826E7FA2
-:10028000AABFD14DFEEC9662B41BABFE59CFF3FC76
-:100290000E58C8FEEFCD6DA03CBF331F1A473C1768
-:1002A000A23E83EC3ECAEB2BE87F8FFCF4B6FDD276
-:1002B00088F99A5D6E2B8F1F0507297F8CCD74F10D
-:1002C000F384073EA2B8AED2AD9087A253EFD3E13C
-:1002D00039A8603B23FFE4B85EBB0EF19227F247DA
-:1002E000CEBEF69F53026487A87EF910CFF7D147A0
-:1002F000D6A35DA5B447AE821DCC1AF73B744D253D
-:10030000D8DF5013CF5BB730A493BCFEB1F77D0BA1
-:10031000CA795D762621FF79754D1EF943619DE30B
-:100320004658E71D6E9E9FA31CB0E8506E299B188F
-:10033000E5172A8EF42A9AF7A350867ED608BA517A
-:10034000E38D305D37CAA3DBDD811D88EFE8399886
-:10035000D6247E0E469CBBB4B57EF83C9E2FD96950
-:10036000E0E70C0FBD366901F9E5BA1509F170DE59
-:10037000B138CF0EEFF78A7D6B530699DD1A0FFF68
-:1003800043944F597080E79D297A4E274AB76B17DF
-:10039000FAFD2EA404286FF4CACEB04CF12AFB89D2
-:1003A000476A3C7176CB162E479AF6727B39D14E4E
-:1003B000F926F971D0ADD54BA2E5BF915EF27682F8
-:1003C000DCF8ABED0FA6B5DB12F593443B6D985E00
-:1003D0009DD0DF687A8A9AB751151B87E8E1759B33
-:1003E000AA070535792D555671AECDA4ED7FAF8B9B
-:1003F000F30935CF25BDC3D38E79E3433F60E4478E
-:1004000053F36D8255DC2E08EA4C74DECDCD7A288C
-:10041000CF660C0B4B12E9F7113AD79981F936F0F8
-:10042000DD07EE027E3E8579BB64E2871E09E76D3B
-:10043000C63C0DCACB0C6D5D81E3DC60A571CC9828
-:10044000A7311543EDBEADC83F67D5F3384316C895
-:100450005BA4DBAC424E87E63A9EAFA1E663A8F907
-:10046000132A1CAA047CB3C6AFC847FDBF5B0AFCB5
-:10047000483D4F1B7F4E3A7A3E7A55019D27899E13
-:100480008F2B64A2FED2CE4927C253CDDFA8B2077C
-:10049000EC9969C3CFCBAAF41187379AD7B6035C1E
-:1004A0005FAFAA37D0FCCFAE9A477EC2B3AB740C15
-:1004B000F74DD58091D35BC278DBA2F76084CC7412
-:1004C000DF85C0FB37E9AB80CF62F4C31E6AAB990E
-:1004D0007A02607BB8CD4FCFB366A94FBE8CCE2BCE
-:1004E0002E42CEF465E6B65ABCA7E0AC6D2817EFF5
-:1004F00039F832EBFE6F53396DE8289693B39EFFBF
-:1005000036DE7B7076DCD04EBCF7A0705B25AF4743
-:100510001ACC62ECB2CC8A6F0769DDDCAF342B7683
-:100520003EBB1CE1D3C822EB07C97FC3F3F3319F65
-:100530000FF1E0B61A489F718B3C4A562DF22A31D2
-:10054000C202E58ECC528A475B9967FF20D667F3DB
-:100550007340504FF4DB318EFB7D4D02AF2C5BF5C9
-:10056000134582C89F3AF21DF47D948FEE3786B80A
-:10057000BF8A8FFFEE8B93297EA4E6873266CF5920
-:100580003899F2493465F57E03A6D873505FE8D0F8
-:100590000BBD5494535302F333E3F4A27767FF5D2A
-:1005A00009EE83D32FDD5B887CE91A03E8ED23F0A5
-:1005B000A17FCDE27CE8ACDEDA25819EF65E72E0BA
-:1005C00016ECE77DCBA2390E58575D6AA5C181F3C1
-:1005D0000DFE4846BE9826F0ED58C8E7E7A8F64B52
-:1005E000CBA1DF0E33EC5FF83E2DA0F8288F3EB094
-:1005F00050BA01E6DD21717E0B1FA5905D52EC49DA
-:10060000C1FCE406711E5216FBFE8ABE4D32EAD3CF
-:10061000BF6AEB9FA114C6E53B88F8F17BF9ECF6C5
-:10062000F923F82D5B3339DF5E207B26231DAD9740
-:10063000FADFAECDC4F79C1E6727B796635EF1352F
-:10064000969672943FC3DEA7C0FB92B8B291B76B87
-:10065000300DE5E2F9649F25B02E13E33E8B3FA6F3
-:10066000B8E4F7B3DE3D8A7905EFEA7B6625A37C23
-:10067000C917E7FA855FF0CDF1AA5FD0C4CB93B874
-:100680005F309AAF3599E78BD52EE4E7106B453E86
-:10069000C21C3B3FB733A73CDFDB0153BC8E0D29A7
-:1006A000C8F7E6BCEF4F46BB9D2D0C94FB278FAEE1
-:1006B000CF30B7DE13BF5FE77AE2CAF0EFDA626DE0
-:1006C000F9DB5E6DF9FAE97F1E1F5FDE65F16DC52E
-:1006D00075FF54E2F98DC12B989DD6E99282A877D7
-:1006E0004C7A394B9CDFE47978FF28ECA297A7334A
-:1006F000AA4FDF6BDA8DF9EDAA1F5916F593DCCC02
-:1007000094E7E4F705A0BC1A92443E9F8B6225EC67
-:10071000A53BEC1C7ED0D600FDBCB4D843FB23DD4A
-:10072000AA6357E11E2A37911E5231C6948474730E
-:1007300048D09D7A1E57A5C30A85F9313F01865ED0
-:1007400088CF77F5F683E83F0E7ECA18C757A542D3
-:10075000F985622CC6DAA9FC98A0EF43624EC11F4E
-:1007600028B49FDFB019089FF2CFE55D282730F647
-:10077000827EE1731B27D2FCD4FD03BBBAD0954E19
-:100780002E6BD1AFA2C349140B7D42A56FD480B0AC
-:10079000DD18FCCF7CA273E23743D3F8FD09EFE507
-:1007A000737E32B4C929CE7BF178588E29DAAF0F27
-:1007B000FBCD8C8EC3CF13A58B32548575B0EE4F15
-:1007C00032F369D34A033FFB03C965AB3780E318B3
-:1007D000924D740E46DD37F6CEDFBE5D7B05AEB3BF
-:1007E000E87BB4CE79363BAEB318C8BACE494F5F7A
-:1007F0002AF5C7F78F9CE4F5E03EF94ECD2B3394F4
-:1008000038BA81EF1BF9F716EDF76EF8DE19F77DB0
-:10081000327C5F32FCFBA76CA6B06E0AF653E1890E
-:10082000103F0FD362E68975C9E9FCBB7922DFB3BB
-:100830003019DAA3BC29D6E663B0E95E13BFAF4333
-:100840009B7F718DB42E13F7D55C53E34004FAFB04
-:1008500099C0DB35BAC057783FDDCF16151DC6FDF0
-:1008600056630A29680F5DCBC2EB1199672B034FC2
-:1008700038C6123FF80BEE8B263930DE09E5D3FA85
-:100880009EC23BF269BF5CCC9C367CBE2A5DA8F35D
-:1008900045FA403A8BD247C2BCA378BAAE8F12D584
-:1008A0007680DE834F550F024B9AE7137B7262EB23
-:1008B00002229A636A29443DE467ED41E21BD7387E
-:1008C0001EA1BCA5336302AE2CC07FDD655FD0BD29
-:1008D00026CCBD783CEAF730DFB4ACB4FFBDF9AA52
-:1008E000FADEB07CDA4F0D9A7CDAD1F6953A6E33A7
-:1008F000E3F7D3CC1AD845F9B1CD0BAD5E3CE7D0C8
-:100900008CF99DE5143F223D0ECF01D33D2792493E
-:10091000E85D979A77CBF7616FA387F4B7281F1725
-:1009200079E3BDA57CDEBD7778D47B4EB87EB798E1
-:10093000F17B52D47B4E96DBA95ECD2FEFDDC5FD5A
-:1009400078BD2F8EA7F350A0BF91BEC052747C7E9D
-:10095000F9DAFB55F04F4A8FE5436FD6737D739BF1
-:10096000CE5B8170DE86719EAF89EFDE94A5F59B2C
-:10097000A8E544BFDE33CEC02D59E80F28F1E54A83
-:10098000403F4B0DDC6F07F4B51DCF4ED4B096A79A
-:10099000F0FEC0B9ACE5D7BAB1445F01A2AF495F80
-:1009A000F07B0563F4B598D3579098924A5F51BA9B
-:1009B0002A4ECC9F0AACC6F6BD8EBE8F9A504F1DF4
-:1009C00030125ED43CB8C47D1C379F137A3E1F970B
-:1009D0002CD37CD68E349F4BA1F378FACA609C9EB0
-:1009E00047A3F70C85056D65317ADF6509B4E3B877
-:1009F00051BA5FCFED9161F396AD441F37DE2CF312
-:100A0000FC700B9757188FC884F1E78BF16FECE6F9
-:100A10007474A3CD4074377FA091F28558358F2B25
-:100A200078E17FDC0EF4117CEBC4770B5DA57A24B2
-:100A3000D985B5DAF8439D558D6FF8F5B81F6F5C11
-:100A4000A83F162FEFEBD8C62F30AFAD0EE314EA58
-:100A50007730EEE359D1F37FE3314E7158D8E9672F
-:100A600081BE91FEDF485BB9FD0EA0DBF18F97944C
-:100A7000A13F6776FAAAA73641F9996D13A9FC46FA
-:100A8000FAAD77BD8BF53B8BA85C8D97B8A0BDD137
-:100A9000C8BF2FAEB8795E3E8C7BD82CFAC57D8559
-:100AA000765F52A0773EB4734F2928C37CC36AC1D6
-:100AB0001FCEDEC1F3DDAFBDCCC65338577AC86F49
-:100AC000549D24EABFCBFB7DBBF45FCA30EFB4BAC0
-:100AD00080DFE3F276D94F2762F9B0F4C5A291E244
-:100AE000DF938AA5F004804FB593B7AF2DFB511665
-:100AF000DAF1D555BC3CC95BD93D16EB75E7168DCF
-:100B000074EEF317623F45CF35897DFAB2EF633A51
-:100B1000C7E437495E5CA27FFAC7FC5E22AB64473C
-:100B2000FFA3DF97AFA09F74968FE7255699DA331E
-:100B3000D1FEBD2E6028C7FC52BBA9F430EA1929AA
-:100B4000D32BA7217E6799981EE512D0F9FF213A91
-:100B5000BFFC8BDC64242EAB96CE553A9AAFD2778D
-:100B6000B5968E617FFE7356DA37F3D7D1E818C693
-:100B7000FF77E41375DFD2CA95687F09FB2DB1FFBB
-:100B8000D1F800FEC5F3B9D83CFA685F6563D6D7E3
-:100B900058DC773DEABE1BC27518748374AE234FD0
-:100BA000F24EA4038DA3C87F757E39C0DB58D9F0FF
-:100BB00079E19FA2EA65FCCF85766EB6A887EF7CC7
-:100BC000CC199B178CCFC6A0DC5FCFE7B3436AE19B
-:100BD0007C43E8C5AA7DDCA4AEB75FBBDE8A247E79
-:100BE0009ED98DFE0BFCCE553AF1EBE6DD2CE4E60A
-:100BF0004293FF4123ACE106C752A2879B58F045C0
-:100C0000D44F8C2901E79834B4BB820722F9E4CF92
-:100C1000A5BC00C077EA9838FD449D57223C9A460F
-:100C2000E18789F34E84430C3F83A45FA9E7A3A225
-:100C3000EB4A588F2AFF5D06AD1FC829FC364EE1EE
-:100C4000A7410A413958CB92286F61965722395EE5
-:100C5000CB4CC43F6B6BB8DC745AB99C57E5EB685E
-:100C6000747DF5559CCFD4363071EE8ACF3F91AE6E
-:100C70003258E47BF8AC3579B62EC3FD8AFA80276A
-:100C8000B6DF6BADDCAF3B778CF01BB2C834B46F12
-:100C9000A3E5617EC4C834E41B89F745D55EE07ED8
-:100CA00044A7B897B5D6FBF134B4D79D359169C840
-:100CB0007F1E74F8E621DED4FBDC12F9CE8D63745E
-:100CC000AA1FF192E82D110F6ADC2835C55F87E372
-:100CD0009C96062BB0F29134E1D767817CA44787BC
-:100CE0003DBF12FD01C0DF2E5E44A30AAB005ED300
-:100CF0009D8100D2DB4DCC3F1BCFE2396B027AEEF7
-:100D0000E766B4FEB562FDB385DC3BB75D263F7D8B
-:100D1000B5AFF83174A5371FD1B310ED3B1FC9B182
-:100D20003562FEE718C7D3392B977F2BDFFAA70A66
-:100D3000A05C367E8B2E768F01FC9B104AD2DC6342
-:100D40003069AF53539EDC97A5697F597F81A6BE5A
-:100D5000343C51533FF54899A63C6D7086A6FDE59D
-:100D6000EF5769CA5744E669DA7FEBD4024DF9CAF6
-:100D7000A15B34ED8F0BFB94057D83C5E978CFB77C
-:100D8000A0CB0B4B34DFFD3679CE11A4CB651B799C
-:100D90009E70254046739F430F97EF2DF03F8E576F
-:100DA000BF82F05A017A2FE607AFDCA295FFF50368
-:100DB0009BD6234F4BCC5F58CD5AAAF06AB8C4FCDF
-:100DC000856AFB621DD2E1E363449EC2E5EC727169
-:100DD000FFCAD7E2B58815FE97F06A746BF16AF620
-:100DE00068F16A29D6E2D5E6D5E23565BA16AF0EC6
-:100DF0009F16AFA9355ABCA6F9B578CDA8D3E23570
-:100E000033A0C5EB987A2D5E735AB478CD6BD5E2DA
-:100E10002F3FB85A8BAF047CABFC6F6CD75A4DBBDD
-:100E200028DEFDF5947732AEE71E4DBF2ADE83F053
-:100E30003F8EF716CA0BFF6BF10EDC86FCA089789B
-:100E4000FF2001DF20373E44BE00F2FEDFF05937BD
-:100E50005EE8D5FE91E5BDCA7FE2E56BBCFD381AC0
-:100E60005F1A264F843D39AA3C49B0273FC0EC1891
-:100E7000D2533692BFE566419F5FE2AB2BD09FF91C
-:100E80006392931FC044A6C3BC3EC079C3381F24DD
-:100E90004D227BFF5616D6D3FDBB98F1079DDE8E03
-:100EA00009C032DE9BE3A1E7522147970B7F80CF39
-:100EB00012B83886FB01F2D271DCEC417E0FF2DB16
-:100EC000A997741FC031F4872B8C9D407F383CCF8D
-:100ED00098393D9C54F9838F795C71705B324B2A51
-:100EE00026BD514EA2BC9C253749244796FC9E3F07
-:100EF000D3B3B9FE99F8EC6855E1C6ED9299D91EC5
-:100F0000E2EBD9AC4FC83B16B08EA57EB8FFFA49CC
-:100F10007E0FE8F31253A63BE93812E131C3C4E770
-:100F2000F5BC9E99107ECFB28007E1F243055813BD
-:100F3000CF879F88F4B0E4F7EF16A03F49EEB05F8B
-:100F400087F73C4FC0F1601EB36F6B91D0BF9AE141
-:100F50006E91D07F33ECFDFE7B243CC7172D33DE32
-:100F60000EFF100EAA9FAC58C7E3C54377703DFF34
-:100F7000A9EF32F2FF74B4062B83182792C120C365
-:100F80007C123D3FF73B339BFBBF32D920DD2FCA9C
-:100F9000DE14FA99B897BD44E4979F11F19615BBFA
-:100FA0004C0CF3154AF61D74627C6505E07210E581
-:100FB0009912A07B2C4AB6BEE1E4F77DEB1D785E6A
-:100FC0004C95A3A3E35B6127E3F2B4018F23DE1703
-:100FD000795B0E97E31D6D3533313EA2CEE7FE36C9
-:100FE000DF4CA40F59F1529E17DE6FE388FBDEE061
-:100FF00082FAB8FDAB586B3465BDD54F9746AC6FE0
-:101000006B213AD38B7B781EC85E6B8FBFBFFFD638
-:101010006CA1479882CC9ECE840A8B4FE524F28740
-:101020003F326E0F1ADDD04F3C5FBB2B97C5FB776D
-:10103000BBDAFC34DFF55220809D180B59D89C8C0C
-:10104000F90378C611DE6FBDE608E6B3186C6BBD18
-:1010500061CFE87033BA95F3F17CA9215BCB97FEA1
-:10106000A1ED14C1A9A3AD8EC63B83BA1CFA773299
-:10107000B97FA7A36D31BDD7D578889E5EDF3AFED4
-:10108000A007EA8FC23FBC8FC6E8E2F362E5B9244D
-:101090009F16093A40DF510ED0CFD1563DD1D99D90
-:1010A00039D6106EC23BDF197710EFD334008CE4D1
-:1010B000BF62DED171049C0C822F013DF971BF1912
-:1010C000B214F2C33AED0B084FFFD5FE54F81ACC18
-:1010D0008CEE7B31E458C97F72A9F3DC922DEC7C55
-:1010E00055CE97E7121FBD53C0E5F5AD3CFFE7E8CD
-:1010F0005D8CF4EE3BEFE67EB03BC18EC77DC95AF6
-:10110000E1AF2246372ABF4EC31B37E0654F1B3085
-:101110009A22C61E6A33E1092766417FD5D8181E78
-:101120007B7C8A03DDE29BAA5DF3F1F9D0F4133DE9
-:10113000C8561E9EF9D5203ED1D78CE3DB5B5808FC
-:10114000F54C8A89C2F88E7A28C3F8C9A23E39C004
-:10115000CB29A23EA58E97737C2F48D538B18478D1
-:10116000448ED539B710F9DE32C6CFB78AF3ED3BDE
-:1011700004DF1D6375CEAFC6FADB18E5BDABF58F96
-:101180008BFA4CEBB1AEB1C897176ABFDF2AE0907B
-:10119000613DD6338BE216DA7A35CE90663D7784A0
-:1011A000BE2FD1D63F2ABEB759CF0DCEC2FA42EDDF
-:1011B000F80F8A7A8B95F343E6E7F794AAF53F1484
-:1011C000F5662B3FE7053C5953DF2DC6EF9042846F
-:1011D0001FBA8B15F74F1AF75BEE6C6357E2FEE907
-:1011E000691BA27DF450DB05C2D339CCF39916DB21
-:1011F00057F65636E2B9EB73829F247B223EDF0816
-:10120000FC4EAD77DAF9B972D96D203A325A05BF82
-:1012100010FB30CA2FA4162F272EEE4FFE267A86FB
-:101220000D761EF58B5CF8437ACEBE4BC702717CFF
-:101230002BAB218905E2DABB973935E5F4DBB23413
-:10124000ED5D0B0B34F5D6F2899A7AE6CBA1FDB2AF
-:1012500056D055524999A65E3DEFCE7A7234FAB314
-:10126000BE7086A6DDB9620FFD8EC7C9B9EAEF7DF3
-:10127000784DC817D6DA0A3250EE3CDB361D956C35
-:10128000F63CEC273CA2F49C83E7F93E87F151A899
-:10129000FFC7361FBDDF03F5A0B9B02761BF79A036
-:1012A000FDAE363B959F6873D373479B879E8FB780
-:1012B0001553FDD6362F951F83FEF1F928F483EFE1
-:1012C0001F69ABA1F2A6363F951F6EABA3F2836DEB
-:1012D000017AFEB0AD9EDE77B7B550F981B6567A89
-:1012E000DEDF16A467475B17D5170BF9F69C382F7E
-:1012F000F85C253FFF9B88C7C939C28F26E2F8B644
-:10130000581C7F720EC6F1FB229A7BD671DDD49FEA
-:1013100099AF3FB1BF2AD1DF4436D86EE1FB98E2E6
-:101320007FE3FABDF75980DEC7B4703CE4F70F5194
-:101330007D663DC74595982F73055976053FEE8923
-:10134000EDCE488355161E0F257F0073C33A2BC47C
-:101350003D344476211DCE4B99CEE5A68AD7E8BA16
-:101360001D7C9EB8FE91E6FB6D315FB9BC8FDF330B
-:1013700051D31346B24FF2B5D03D13A63A7F187F32
-:1013800047C2E50FD0B9F78917E68071037CE6C242
-:1013900055CC03CFEC06ADDD93B5AC4C635FC817FD
-:1013A0001E629EA9D06F89D63E492A5CABF9CE94C5
-:1013B0007D8FA6DEE0BA4F53BF644DFE7A37C2730D
-:1013C0000CA3388971633BC3D0DEF2DE4D34AF7BB2
-:1013D000C53ACE481E3A371BDCA7C6C9B97EFE8C7B
-:1013E000902BCCB491F6C378072F16A50475281757
-:1013F0003EFFA714E2474F3FA10BA11F74020BE968
-:1014000070FF4F02750FEB27E34DB5325D5D226330
-:10141000B99479642C4F6543649F807E7E27D20BFC
-:10142000E8E74F98314E97137886E70F85496E1697
-:10143000097C16A9F6C81625D13F7A770EF93FB474
-:10144000E7863A859EDEEEA8C8C0F8E49951F2BB63
-:101450006CEE1933F0F7AC6C99D3E9A9BE7FD0A339
-:101460001BF13CECC61CD58FC4E97E0210B9A0FB71
-:101470008D388FD3E5BF4A4773AFA97088E8FF8CDA
-:10148000E4732F46B8BE25733A1CC8A4752902AE72
-:10149000CABE4AF762809FF2CE586F90C5C679BA2D
-:1014A000CD37435162E522919FB8B76DFE8CEAB803
-:1014B000F7FD027FC56CB006E5537189CE1BA29E75
-:1014C000DD1AFE652EECF1E1796EA58C7991BD4DAA
-:1014D000603DF7A1AC56FE2253BE8972E80AE601D0
-:1014E000BBC06A0D33CCCFE98FEE6FA6F99DA3AFD9
-:1014F000ECD529742F5F5694EFA14CC4DF351A4404
-:10150000FAF9AA57CFD775485B5F6CE579342B8A17
-:101510000D218F84E1ED1EBA7F4ED9293154FD95FE
-:10152000BFCC2238B0972C447F962D53E8EAEAEBE3
-:10153000944008E9E374D8F3926EACA04568D738BC
-:10154000C9B01BF5B1F108175C506131C175B958CC
-:10155000EFDEB6C504A77704BE3A7312E6C3BC3EFD
-:10156000BC9F7145AFEAFFD0AEF3C1F2AAEBF13EEA
-:10157000BB8E4159E84A5A786ED00F4EC1DF883B86
-:101580001D8179C934CF7710FFF2960AFA9D231096
-:1015900020B4BEC627C0DECF277E5443727B9A8E0E
-:1015A000F24413E9EAD7828F2DCEE1FE3C9BFBAAE1
-:1015B00019F87B6BB1F24CA2CF6775DCCF1AD471EE
-:1015C000FB52CDA300C5C183765D41AEEA67EC64F2
-:1015D000F3505E3B74947F27EF4AA27380B243A11D
-:1015E0007CDF4E6BB57D35F6635728BE31479E399B
-:1015F000887AB3D1A19B8A7AF7E1DDF70C629E87E6
-:101600009CA330F41775DA15AE7764EB282F4A7176
-:10161000549B301E52643D5189F03CB8EBFBE4DF33
-:1016200090BF277235843F492F50D6C95AA8FF6012
-:10163000B622EECDF0D596A60B57BE07ED9F9A4F7A
-:10164000D18F72D87ECE8CFA8AC7BA82FC6969B90A
-:10165000DC2ED463DC0BCA4FAC3BE740BEF5D6AE04
-:10166000F5CE7CD49F430AE920C57FEEC8A2F3DD06
-:10167000BB0C74FE5C856B5E50D1C4CF725AB565ED
-:1016800063421C4D9F70FE2709C7A7FD5EC7C2714C
-:10169000EBD1BBB9BDC65C56B277D27225EEE7116D
-:1016A000656B2EBF7770AF3E98E505F81CDAB52262
-:1016B0000FD775FE9500E5DB8EA6EF7F94E311F85A
-:1016C0000B9A75748F69D88CF9B74FB5B134D4EFD4
-:1016D0004C2185F29FF7087E5668E5F4FFFB5C4ECF
-:1016E000E789CFC21EBEEF94E7924216C49BBDAFFE
-:1016F0002C087432E9F5B9CC03F2AFD0EE23FF61C8
-:1017000061AB210DE3F8737E62253A39674D223FC4
-:10171000A1D29AE4C5F71DBB2B8AE3CF3585DAEC5D
-:1017200069981FB3BBCD94867C2A340A7F1DEBD009
-:1017300051DEB047C7F3DABE25E6F5AD5C0BBF4717
-:101740003997F3992795E0029CE793804FCC573E59
-:10175000B891EBC36BDB4D348FB56F8D25BD6A340B
-:10176000B83DDDE64EC37BD8776FD465A1FFA8B244
-:10177000BB7003DE47B0D6C6EF6395532692BF9386
-:10178000FD42CF507FEF489EE15D1AC7DFE5949997
-:10179000C54857B21CCC42BF887F67D5F598B708BB
-:1017A000F8DB86E5BADC89D7635EE35E5B300BF37A
-:1017B0001C03B95378392DB80DF31CEB73CB783972
-:1017C000279885BFE7D4925BC1BF1F17DC86E5D69B
-:1017D000DC19BC1E7D4FC03B83B9575D1F84F13AB5
-:1017E0000CDE7A64C83F86F997C0FCFBC4F33E0167
-:1017F00017B5FE057C0F70DE2F9E89F52F89EFFA55
-:1018000047A97F55D40F8CD2FF6BE2BBF028DF1FB6
-:1018100012DF1D1EE5FB37C5774746A9FFB9A87F34
-:101820007B94FE7F29BE1B1CE5FB5F89EF7E3DCAD2
-:10183000F7BF11DFBD3F4AFD87A2FE5F13FA3F2AC3
-:10184000DA47C4FB02DBC60FC3407705C047902FC1
-:1018500015DB363A719FEFEE2A27FAEFA8E0F11D6B
-:1018600095DE0BF07794A0FECB5C7E3FE89782FF7D
-:101870006E17FD031D3E8C74B7F61D99F25D3A7428
-:10188000DE5321E4A31B74A40FAC7D8BDBE76BBBA1
-:101890009550FC3988ED09F35F2FE6D729E6DB9BED
-:1018A000CBF3A98D6E775A6DBC1FC9AE2D637A1428
-:1018B000F25DE0DF943F5BDC5DD5550CE5314E1DFC
-:1018C00069204AA3298CF72228362117ECE53DC56B
-:1018D000383FAB42E7C1158712DE8BDFBBCB49BF78
-:1018E00053E7D76955E85E2CD9C6E5C09C9FCCB4B8
-:1018F000A39ED5C902833EFCDEAD90FE7EB0ABCC8C
-:101900008E7CCF605B66C7FDBBD6C3F77F75537116
-:1019100012F26BF9411DF1EFC376BEDF77BA75E4C1
-:10192000B700B942E74A805F7B51468C67E1763A5F
-:10193000A7F0D04B8BB95F8FD94A2BE8DC861A0F02
-:10194000969438FDFF04C207CF4B0839A2A07C81D2
-:10195000E793E5E2BC4190FB9FF214E61E13776E1D
-:10196000F244AECCCF63280823E84BAEA5FB8172CE
-:10197000D7291AFF7BF65DDAB221416E280972651C
-:101980006C17F0C938B9931FB46BCAEFE50ABF9959
-:101990009779517F9DF3938DC40FCFA17C9346E738
-:1019A0007B51FE2BF8F193E2BE9B2783FCBCEEC17A
-:1019B0008D653F477CAFEDD6D1FDCE97CA47B7E7DF
-:1019C0003282C3B800C81DD467149685F6D237C1D9
-:1019D000619CDEEFA4FB0BBE011EE31E2D7722BF30
-:1019E0001D175048EE0C931BDF00AFE725EFFB01FE
-:1019F000C4A32389EBD576BEEECE7417BFF7479C00
-:101A0000039485BE76BFF0832B29733CF8531C9D4D
-:101A10008E162AAF97BC19D742FB07A4801DCB476F
-:101A20009C495CEEE424111DEE455D86EE2FCCF45E
-:101A3000A37FA42F6450EF030CE3FFEDC33C19F523
-:101A4000BE4137E967A2FCE0F5D5D85EB14F4295BB
-:101A5000B328AFE761FD95D0DEC0A2EDF15CD3B352
-:101A60008775A2BFCD0FA3BEBA2F8969EE5BDC8755
-:101A70007E742A6F7D18EF4F84F1AE95C1069BFEF0
-:101A8000C4130F5BAF88CD676AE8A987DB295F9530
-:101A9000DB250EC6EFC33EED8924E37601FBC4933C
-:101AA0008776F9AE13E99ADF3F13ED5344FBA68125
-:101AB000A1A6E73CD4BE88DAF70F2597D0FE1AAA74
-:101AC000886F9F2CECFDB8F6255FD7BE589DCF736D
-:101AD000BFBAB184B72FC3F6673C9174CA3D499829
-:101AE0004FEAF0FEA77F5DFF1345FBD3E15F51FB9B
-:101AF000332C923E399FBEBB3A0FE8F8ECDBBFAA0D
-:101B000010EB4E473D19B8A20FDF277B98B877AD91
-:101B100085F4E73E538F1DF535B3BEC78F7CB710F4
-:101B2000EF4F9A1E7BCECA2BE47A55C2FB3E134B75
-:101B3000AD457A6CD591FDD2671A2C2B417DFA65A3
-:101B40002B6B87317479EBBCC807FB236BBD25D0A9
-:101B50006E67F64CB22BF6195AFAE89CED622B9D93
-:101B600003DD69EFB1E3FE313B7AEC184790EFE615
-:101B7000FA93B2C41A780AE929BCB67879DCFE9DDA
-:101B8000EAE1BF23D3FD867523DA01DD7A6FCF78D2
-:101B9000D4B36D0AE5812B4B06E6D1B9BD1FEB1816
-:101BA000F177585715943B1B75742F7C9B67C9328E
-:101BB000842B53FCFE2AF82E374D91F01CC4FD8A6D
-:101BC000DF84F10BA3D0DB767AF9EFAEAAE36EC81F
-:101BD000E3F269431EBF1FAA7BF173C56FC2773B57
-:101BE0005BD7F6E178E6092686F95E3BB34F76E3EC
-:101BF000B9CDC7DD60F1021CAC0D3AFA5D94C76B3C
-:101C0000A14D0AFA330C1A7FC5F3521FB50F36EAFD
-:101C1000C84EB0961834FE8DD4069D0FFD8E3B3C09
-:101C2000817B71DE53DF51AEC5F1DCE3143BCAA703
-:101C300007DDBF36E9609EC9E5DA7EED33B5FD38D4
-:101C4000ABB5F5AE5A6D7DFA426DBDFB364382BF32
-:101C5000465BBE888208E1083CC00A72288957B1F9
-:101C600024EB79FA5DAEEEC0F69EF1B01EA32558C6
-:101C7000FA26CC37696212D9FB0FBC91849B0FF80E
-:101C80000F23BEF3C06446F9A78772BEEF46799A68
-:101C9000089F9DD9065AAFB510E0998FF6FA29FA38
-:101CA000FD2C2B8B6B978FF0F16DCF9BC6CBEE0A83
-:101CB000F4CF31E283CFABFEE31BF8B9A69DADDCD8
-:101CC0002FFD601DCFCFA31554E0FEE6ED93F1F795
-:101CD000BCA6A0DFBEEB0ECC3B4C846B06E6E3C893
-:101CE00031FA58AF9E23C1538C159C2DE3BE3BEEB9
-:101CF000E174F2933C2EFFF7897B0FA2ED711FA6D2
-:101D0000336ECA427FAFE6A9FE079E97BF598DC7C3
-:101D100088325E1788E57D879DD7E27EDABCD05990
-:101D200086FBE901A197A5641B7C1360BE8F1C3163
-:101D300004A5CBA0ACB0C37A90E7FB9C7C5CC35BF2
-:101D400049413CD7F488BB9CCE497D24E6F542A5A9
-:101D5000F7BD5ADA8F0AE5393DE2F29ACBB8BE8177
-:101D6000774A33FA4954502D0ED696919DFA88CF72
-:101D70006BC6FDFA48B6D78C79C2E64CC58EFBD847
-:101D8000E956E8BEAA474C013BEA2D4E1080F83BCD
-:101D90006D869C9EB9743E0860A8ABE0210126F2D6
-:101DA000E9309F2D55C06BA77B991DCF91BB0AF7DA
-:101DB000FF1DFAD553B1BF64FE1DC2C921E0743CBA
-:101DC000CFC3F38345FFA9CB5EA0F6F8D75911D74F
-:101DD0009F97D397612E0BD1EF8D89F1D57EA2FD10
-:101DE000331FF9EDD7FF9CC3AD3D87DFD36358C3E5
-:101DF000C80E7BA132B0F720C2273389ECEC2C77D8
-:101E00005615D247D6916D0BF03CC0FA9F73F96915
-:101E100058CEE34D590A335D85EB4E0BD8118E89B0
-:101E2000FB30F370CF7C2436152F89FB3253615D74
-:101E3000B273F8FECC74BBAA8AA68CB04F13F641DD
-:101E4000E691A1EF61FF89FB7587E56829C2E5FF8F
-:101E5000029F8BFAF4008000000000001F8B080036
-:101E600000000000000BD57D0B7C94C5D5F73C7BB2
-:101E7000CB26D9249B04424248D8CD8D402E6CC23B
-:101E8000C588A84B48102DE2227235E2131220407B
-:101E90000201F46B6CA9590C372DD6F0360A5AD4CE
-:101EA0008D058A8A362820566C978B8AD56A5AF512
-:101EB0002D554B13A18A728BA17D3FDAFAB6DFFC58
-:101EC000CFCC24FB2C89D27E6F7FBFEF4B7F7598E0
-:101ED000E79967E6CC3967CE9CDBCC3266632E3B54
-:101EE000A3BF7F98F1DFAFAFAFD53AEE1F369A317F
-:101EF0007F8AC5B3C3C5585AE87B37FEFBF708D4C1
-:101F0000356672FD2393B151AE78C606E279BDCB3A
-:101F100057C0D81E9B73A26300635D2B98E729FE10
-:101F20007DE94B9BE6BEC5EBFF95E67046F056A9F2
-:101F3000C79ADBF3F97376401F86F6DB2CFA93D150
-:101F4000FCFDB6E383985F632C229AD5B7393854E9
-:101F500026A6A3FC07FEAEC738561A6794CBC4D892
-:101F600018C678170153F2BF5EB60D1992E7F4F068
-:101F7000FE0229ED76DE6F9BC59967E1F59CA1CD48
-:101F80000F59AFC53C388CE368DA5E56C2D8B34708
-:101F9000F9B883517DE4A1320B7F1FD5F3DE8FF7B3
-:101FA0007B4C26597FF4A1B2218C0D39DAB6C6E1FB
-:101FB000E4F31FDAFA909DE32DF257E2FD045EF799
-:101FC00067012FB5433BF8FC0EA72FA1F937FD2E73
-:101FD0008245F0760566CF56D4D947916C07AFEFAE
-:101FE000DA377EB68BB76B8A19EBD2F3192B73698C
-:101FF00034FF525986CFCB6CF3E81EC7E5CFC74BF1
-:10200000BC31E639DECAE95BF0631B7B80BFCC05DF
-:10201000DCA0576B64E029D0B7790B63498C553B42
-:1020200005CDABF73F907E88972FC74CBBCDC5F150
-:10203000541D53960478522F31A62772BA35DA9977
-:10204000CE71953AE0058D71F8860C383A8139C029
-:1020500037ED6B9C28EBA398AEF807F4BF6461FAE8
-:1020600028F4E7A5FEF0674F02178ABFB5093A5B6F
-:10207000C3E1F1735CEF00773AA33AB542FE8FE417
-:10208000326F47AEEC27037CCA66B7F1F12A8107AD
-:10209000DE8F8DD3C45ACC4B872518D147FB8512D0
-:1020A0005F66BB23681EC94BE7EBC7A95F87E56C7A
-:1020B00087BDB79D3D60217CB05A16C8D6084FFE3B
-:1020C00008D4E312A8CEBC5ED78024F03F23E4A658
-:1020D0005AD8D1083E2E712F5F3F292C48E5E31CCA
-:1020E0003D8E4C344A8BFF349AE111031F3FC5D813
-:1020F000E450BE56E5C57413CD23ABC134F014C70C
-:102100004FDE914882C3B2910522F96059A007A71A
-:102110005BD62616B0B8D1CE36F05422BE73D17736
-:102120002EE634311AAF6D04D6D5D6D71D9B581C78
-:10213000D1F74E1F1F6F6B14AB01BED4788CAD214D
-:102140007C6C768971B7353A898EEAFD90DAC36185
-:10215000744C30D051B54BBD3498E8D9DB6F80FA60
-:102160004D6DD84BFC907A295DF289EB1BFACFE8D4
-:10217000A7FF64FABEFFFE87D0F88F07DF8F9FCAE4
-:1021800051F1A3AEBDF13E5E465A9B7D9E3EF09C52
-:102190007A57883CE3FF1F7980D7737BEB0A2F9136
-:1021A00056EF80691CFF91779B3CADBCBFAB8E1B8B
-:1021B000DB4D767F108FF5D8DB3E38603ADAD78971
-:1021C000F6D79C36B6F74DD817D65EC077FD256397
-:1021D000BB70FA84C3CBE11A382304AE89F608C376
-:1021E000F7B32B2F836BE0AC10B86E4836B6D7D759
-:1021F000F40DD7B77223BE162ED5EE96922B6B1721
-:102200003E8FE99323FAC1BB683F6BF695F57B7B64
-:10221000CDD7B7BBB3217C1CBFDCAFF8DAE2EB381B
-:1022200011FFE04B20B1C1E48D8C65CCC9BA18D642
-:10223000D1C9A12E6A97C09CB49EF9C2D7B0AEDEB8
-:10224000C33F53F856E0F69D738D01FEBD150FF3A5
-:10225000A66572BF6253788F57A3735FC1AD0597B0
-:10226000F31F63F7115CAF68BACE689FB57B76F059
-:10227000F59D97CAEC2909FC757220E3D618C6BEF5
-:10228000EA91D75CD470384748DC3D37B86D653C7F
-:10229000ADF34002E0F967C7B5BBBD66F798DEF65F
-:1022A000E1ED7ADB0B3CD96C6D2B0067579DC38346
-:1022B000FDE17DBCE2DFFD786644D0CCF175C1EA7A
-:1022C000D8A87139733C7ADEEB03391EDE8BD5E377
-:1022D000D1FFEC5937AE475D3B9CE85AC9E1BB5092
-:1022E000D9311678F546EB03DDBCDF5ABB3E3489A5
-:1022F0004FF15C9A3E2C0EF8F525125EF93F0A7CF0
-:102300007DC22FE029D304FE13E3F474F453666A0C
-:102310007FC2876796F6B1F88E3907127CE76C5C4E
-:10232000DEF5B1FE151E4A653F87AC9EAFBAF8FCDC
-:102330000E6D8EF3347178AB1367CD5BCE5F2D30AD
-:10234000F992826603DCF904B7A372680AE0B64A20
-:10235000B8ED0325DEBD595F077713C6C3BEF63D52
-:102360002DB0C32D6889FA4BFEF8C003BC1E61BABC
-:10237000F83EE4475781C9C3F708B68DEB1776BE20
-:10238000AFBC2BF1FD38577FEC09F47C239E274727
-:1023900089EF931F31059AF8F7BED297894E3F5EB9
-:1023A000E6F098F95895CC6503DF5631AF0DF0FF94
-:1023B00071C2DF5EEDE0F3BBC9AD97833E77269A2D
-:1023C000D2DF2738F4BC699CDFD87881FF6FE20741
-:1023D000C63699D858C66E95FAC10289C7E9CC6B42
-:1023E000C53833986EC5B8BF396FF332CE1FBFE121
-:1023F000B8621CDE59CC4FCFE7B00095B7B320B51B
-:10240000BF837550FDD7D185690D1CBE695B86659C
-:10241000633D86E0FD76C92F770E10FCF2D920E0EF
-:10242000BD65E015F1EF344DE06FB05BAF76D37A68
-:10243000750DF00026E7C421BE9890F5533650F094
-:102440009FC599FD75EBA7BD3BB6908D2479E048FB
-:10245000E178B84192F206EFD229982F2408D6EB02
-:102460002D72BD969B1D6C00A74BBBCB1C88E0B0AA
-:102470004C9EB02219F37D630DFBD5284EBF372645
-:10248000985913B5F4D27753657F53874CFA1CFAE9
-:10249000C9DB2C386034FFAEFC927E348EE367AA31
-:1024A00079F75AAE71B3C943AC9F7484C8B51B07A2
-:1024B000ECB130AEBFDC94657C3E259FD743E4EEA3
-:1024C0005466E97DCFE97F08F881DC61CD66F0EFE5
-:1024D0004677CC804FF37875041B21EC034E8D902A
-:1024E000F974DBFF6EBBC0BF7BC5AD3F04BAAC8CDB
-:1024F0003F3F8FF40E8B98CFB277CCA4577ED2C8D3
-:10250000C079EC14D70FBD398C7DCAF50BD44F3789
-:102510002653F905D707509E6DCCA5F7E71B3D5410
-:10252000FFC4EDDB8A7EE76FFCD2827D6943A4C2E3
-:10253000B7806395E4BB0D6963B7FC95E375C3DBB6
-:102540007C6170786ADA9A2771358BAD4AFBE43E7C
-:10255000E8CFAB9ED63C68B7F4A0D7E6E0F02C38C5
-:10256000AAAF079917BDDD311562A20EFA2BD71B52
-:10257000EEB7FA7662BC311F9C4AD27903EFC1CE26
-:10258000D71379FBCF1A4B08AECF1BBD04D799C622
-:10259000C954FECDEDDB8DF65EF6A50DED6FDEDDEB
-:1025A0006949E5EDCBBD9A17EBF13A2F0B04383CA6
-:1025B0005BAD42BE6FE5F21DEB7342C1AD8FDF052F
-:1025C00071E1D6F7830F6724549527F2E7534B2A1E
-:1025D0002D6837EB2B2ED3DCBD7CF8CDEB50E0A380
-:1025E0004ED2E5DCCF35C2D3B9FD79B75CC3FBFB76
-:1025F000F931333373B8BA2F9908AEEEE35101289D
-:10260000ADAADDCA7D66D22757A6D902C0DFCA7D32
-:102610007983A04F9DE1746339BDE39D79EEDB2E94
-:102620003D448E9E4968FBAF0F21A77E2FE414D74F
-:10263000373F7D0C726CC8600FE87EDECAF57220F1
-:102640009AD547631F5B6693EB8BCB19D4CF44318C
-:10265000D247C73E9F5A8AF582F15CB65E3994F341
-:10266000FC968CEFBA7AC7DBD5B6E0C3C778FD5CC1
-:10267000C0E4B7F27DE61C6B3BFF33C8D1ED0E0F13
-:10268000EC830D1A8707FBE88EC154CFD52C510D72
-:10269000C4CF015AAFB99ACBD2C0E54FED0B8F0E24
-:1026A000063FBDC27150C2DFBFB2399AE4D32B5688
-:1026B000CF8906F4F7B8E8EF273FB8E79303281F60
-:1026C000AC2BBE879717DD09D44FF57F2C1E81EF09
-:1026D000F93ECD52787FCFBEA40523F9FA2C683994
-:1026E000745F0A876FE4B64ED3605E166DD79A505A
-:1026F000E6A5DD74CCCCDFFFC5ED1276EB6EB73905
-:1027000015CB6A70E0C3EB69FF36EEEBF92D5F96EF
-:10271000C2BC54FBFB08ADED8B56D8C3E9C78B7523
-:10272000C25F33C1B1EFE0F4F76E679807D71C00C2
-:1027300077A5CD43FB49C0DF0A3A9FD3733D0F60B5
-:102740004DFBFC8F82BEE7F4240FF697FD267FEC4D
-:1027500038B43F61A179BEB4FDD7B1565E8FDB6B53
-:102760006591FC7D5D51D724B4AF4B73911D9EF6EE
-:10277000C40D93819F657BF7B5523FB5768F867503
-:10278000B6EFE2EBA9B0876E649E6CF0DD5E51FFA0
-:102790007E99D7037EAB69FDB3A8B7FBA8EE33FBE8
-:1027A000DD16B4AF127ACE16B98FB18E429277C4CD
-:1027B000CAAE5E7A7D9FBFC6FBAD6E7F4ABDA37772
-:1027C000FFE3FBD6900CFE3EC526BF774E4FF7FDCC
-:1027D00013FB964DEE43AABF2D36E68FE4FDA4F120
-:1027E000E71AF6559BD86F7770F9027E51FB2D1FC3
-:1027F000371FE3F2EFBD9093A97C732DE2F349DD1F
-:102800001211A03DFD0AC7577AD2F22821CF94FEBB
-:10281000313BB1E9D50E8ED73FC5EA2519BCDD02A3
-:10282000B95F338B2719F33B19EBBD3A83F6BFAE83
-:1028300074CC81EF87D7A2BECCCCF5A7CC10FDC954
-:102840007E65FB61449C7722BEBFD2F6E3A3FA9675
-:10285000BFE3BB4B48FEBE2AE5EFAA3F9B5811AF32
-:10286000AF7A3882E409ED697DE0E555BEDE752E6C
-:102870005F7E01BF012FAFFD538799EC8FA3A6DACE
-:10288000D7F97E4A4367E03F5D4D71A3A9EE0599F4
-:10289000AFFB93A94FFB50959C4E95A093F72BA3AC
-:1028A000BFE1FAAF9C36EADF917045F335F7335F4D
-:1028B00073AC98EF41CC97D36ED597C5242F0F5E9C
-:1028C000E13CD322BC2B015FF83C38DC0DA047383B
-:1028D000DC3DFCDD756570DFAD31BF09EBEC4B5BBA
-:1028E00000EBEC200713EBF6E0E2FC00D6F37E9B56
-:1028F000A8FB636DA47F1E8C617EC88F83D3920278
-:102900007EECE7680FF9309089F791F2FB3949F4D2
-:10291000FDE008CEFFBCCE6E8F92FDD7BF5580F78D
-:102920006B523D1C02AEDF063666907E6B26BFE121
-:102930007129AF5BE283B79BF9F3962F7318C63901
-:10294000CE82A9CBD1AE268AE4504BBC372581E399
-:1029500071FFDFCDB42FB414F1BA83E434F9775AA0
-:10296000A67953E2797DAEA44B4B6B60C723E86F29
-:102970005AAEC7CFC7196C66F5D4CE2DFAF9D02A56
-:10298000BEFB9DA40B5FC7B4CE8F66CCDF03FCEB10
-:1029900053A32DF08B708CA7681CFEC7AAB319C96E
-:1029A0004BE9F79A2D6930B7970FBCF6B1D06BC5DC
-:1029B000DF9C053B22218F67D444925FEA78CD7D6E
-:1029C000312E3EDE0CDD1C8C80FE775BB9C1EF74CE
-:1029D00034C34BE372C342DA09C12AE0F1E75D7602
-:1029E00006B9DC1F3DEBDA26249E0AE1871A9B908C
-:1029F0001FA7A53EF4728CFE0BF0CDF20337269E86
-:102A00000AD1F7AA1794E7407F56E37D13DF34819C
-:102A10004E2369BDFA4DE08FB648A2FFE45BED445A
-:102A2000EF6E87E929F825EF94F2AA0986307FDE58
-:102A3000B42F22701F7FB63C223813F28AD3FFE9ED
-:102A40009DA0EBAB9144FF5A9BE0A7DA9FE5117F75
-:102A5000EDB779DDEBD0FFCF2388EEB5B1AE387A94
-:102A6000FFCB4426F98FF486DAA8604E3CC7E7C650
-:102A700068FD43E08DF31DF9836B6DE2F909C957D9
-:102A800027781F80C35F1F43FCC8645DFF6E22D997
-:102A9000535C1F25FED51FCAA3BA6EF3A62CC0FA3D
-:102AA00058194DF09D90FEB413B5F1C4DF150F2DEC
-:102AB0007D9B717A9EF0EDBC3F87B73B71D0EAC138
-:102AC000BEF471833968E3743DBFFAE4D8ADBCDE6F
-:102AD00071DF47E97A881FADE2BEBA29F8AE62C954
-:102AE000EAA9D82FFBC377456D0497B9BD74B266C8
-:102AF0007AFF04FAB933F5FF8D792ECFEF5808B974
-:102B000077DED6FE04EC830FE3F4BFE2FD85973F4A
-:102B1000DB49F2D0D29503FD7C9985F301F852EEA2
-:102B20009FCB255F063275963986F047FA78747E1A
-:102B3000BB907BABAF4CCE7F7170C77E8D8FB334B3
-:102B4000EAE0322ACD8142F473460BC66A99C01F6F
-:102B5000D7E3787F679DC158D0419776D3D25DC6C1
-:102B600079E10F7E95A5F807FF6E699B99FC2A1CF9
-:102B7000421BE05F0A4FAF219E20E40AEFE7295A8B
-:102B8000878E8FE77D97E37FC9D3C38BA14F2E8DAF
-:102B90003FF0836BA81DFF4EF1B9F9F2BA9ACFE569
-:102BA000F088F99D957C7E96493938DBD66387435A
-:102BB0000F3AFFDC2003DF9C7F7A38D5BFD0BAB450
-:102BC000280ED779298F98A76DEC341810DEB6B18E
-:102BD000D0671F91CF9726B68D85FC51F288D9DB3F
-:102BE0000AC9AECE6D2B843DA9E419F3B5E5D0F347
-:102BF000405B0EBEDF6F127E0AFAC3BC9F4D6D258F
-:102C00003CD8C57A5CF26C1EE1458D134EBFF0F9DD
-:102C10005E9F29FCDC1CDE3B7DBCFDB0AD36C3FBFA
-:102C2000E10163FD06D97E68185D069BBB0E454039
-:102C3000DEFF98D17A0D1F77AAFCEE99677AE860DB
-:102C400096F6227329FABB84BE6D05BE7FD783EF4B
-:102C5000BB52B93C5D8A3966F4CE7F7F919E0AB93A
-:102C60007FDE24FCD4FBE3793D1F7A8EC0A7AA2B1C
-:102C70003C86F3D17DBF5B988A78CA3D9926A954DA
-:102C80007A0681DF9A202FB9BC68B20A7C7CD158C1
-:102C900033EA9405F6687D4AB5A5773E0BB716D999
-:102CA000B15E166D2BB2CF0FB1779A768D3AE6E210
-:102CB0007439BBCB426E83264BE007D0A39B769939
-:102CC000DBFC8CDEDBBDBCFD59C7E177D06EE1B625
-:102CD000F862E8BDEAFB455BEF4EA90EC177DE2E38
-:102CE00023FE0BDA8C75F8A343EB4DD005C7FCF33C
-:102CF000DF15058DF551C78CF5CFDEBF6B26D8F8F3
-:102D0000A512C1EFA7033101C4A96A3E9A740CFB56
-:102D1000DAE9FD2FC5823E4B7F5FFD3AEC96455BBD
-:102D20008D7CC6E9A641AFF7EFD4883F1607C2D71E
-:102D30009D5CEF97ADC735CAAF991BCA27E1F43C3C
-:102D4000C3DA667A393FD536AC1C857848CD14CEC7
-:102D5000B81C9EABDB36DB1037081FAFBF75CF1C2E
-:102D60005E17FC559525E2DDB8865276124EDF4D92
-:102D7000BF9E84F556F97D8DF6FFCA17871D85FC29
-:102D8000EEDC33E7262A674E263C28FFD9A2835A79
-:102D90003086D79D25AE031DFCBB05018DF687F956
-:102DA0006B237AE510FF7FF5A630385A42DE73F8C0
-:102DB000171D38F4178DF75FB3CDF8DD628E2FC87D
-:102DC000FD25DBFF1111FA5CD97DE30EB69A31EFD8
-:102DD000050A7EFF750CF31221482E3AA4BE720A32
-:102DE000152EEFA3137C8732F9FCC7B588EFB8C066
-:102DF000AAC47CEB1C3617E65B6767C1680EC7B1D7
-:102E0000189BD7C99F5FDC1A43FEA985115C2F2C44
-:102E1000A6924516E33B0FEDD39FBE6B267DA50E14
-:102E200063A39F2735B27FEAE06C44FDC7A2BE983A
-:102E300005691EE0176FE8FC02C63A6B167653ADC3
-:102E4000257808F858C23A84DDC3E9E80D89C7D56A
-:102E5000F2791E4F803E64FC7E396BA3F6CB0FFCEB
-:102E60002322F479889F94EC3965579A6DCC0BFD39
-:102E7000D87C6F14EDF75C1047813FD769DE47EDD2
-:102E80006694625EFECD42FF99DB2AF60BAE9FE6AA
-:102E9000003F2D9B877BA0A7CCE57A7624F488C5DC
-:102EA00051D4AE259E917FA5654E8ED0B3FFFE62B4
-:102EB00010E3743DAC917FA4A548F4DBF2E0707A96
-:102EC0000F79A8D13811A4B7B44C53EFD3484FFAB7
-:102ED00010A0A540CF95CF07BAE8F960B33707FA3D
-:102EE0003AFB6124D9FB4AAFFD4982FE0FECFB6A35
-:102EF000BE4A0F663557A6FFED90FB5DD76611FF02
-:102F00003DA5F95E3785E8A5CE2C21E7C7967A77EF
-:102F1000CA761407A8364D7BE07A0E4FF523265764
-:102F200093BB17EFCCEBCDC1FC4F6D8E2C069F8D64
-:102F30002D15FE9E1345426E478F66DE002F5364AB
-:102F4000BF29592643991CC5F98FF773AA5CF887E6
-:102F50006346FBC8CFC6753692DFE1F3C896FD54D1
-:102F6000DB7CBFBCB60F787AF8A04CE819A756688E
-:102F70004F09B8385D797DEC7F44927FEE94DC5741
-:102F800014FE39DF8CA17D5AC549259F6C06FDB121
-:102F90009F2D1676502F9F18F960AE26F0CA1E148A
-:102FA000FA694BBCA82B3EE0F60EFB2BF8A49C1153
-:102FB000DEFBB37BD43C5B5AC57B4EEF6BB3C65C88
-:102FC0006EF7287A334B600CECC6FEE83DBF247EDA
-:102FD000AC66A2B8B51F716BEC758497FB2D81FBB5
-:102FE000381C432C02FF6916C15F5C2AFBA38AA927
-:102FF000BDD7C6EB953F5CC4BCBC7D652A237F1062
-:103000006FCFE2D09E7763867F8497F8AE324EF41E
-:103010005B3988919D407F5C5E65A1CCA07EBDA69A
-:1030200004F17D6C317DEF3789EFBD165E0ECD1456
-:10303000FA7CD7BA88C05390CF1BD272C007534ACC
-:103040008D7CD026F94695A9D92E95E7908CF53D33
-:103050007FED70DA2F9A227D75FB40B7E784FE5F23
-:10306000B9FE8E9BC700BEE7133D00EF8BA97B28FE
-:10307000DE307FED9CBB3F80DDB02B929E9764EBF2
-:103080004BB3A01F6BAE79FBF883F9338ED892F95E
-:10309000F77ADBB4733FE3E554FF9E77A00F4CBD96
-:1030A000CD4CEDA732E11F656BC53837FBBFB424AB
-:1030B000F3FE6E1EAF51CE4067A4337D05F2162499
-:1030C000FDBE0DFE851D16C966BFE0005C6939199D
-:1030D000FCF9CDD030FB885FED93FCDE3441DB069C
-:1030E000BD66E844B1BE547BF4837E5FC9127AD0DA
-:1030F0007DB254758E576A5FBD31A2333316A53544
-:10310000380CFB5D4EE97AF0D5940C36692BF07ED5
-:103110008F19B90A1CDEAE4A5AF731392EF0A9CE02
-:103120005890F22302C389AF3B2774756EE0F5CE49
-:10313000D6611EF2F9483B7A01EC2B17DE0B39A65B
-:10314000E4CB0967470CF1ABB4ABAB246BFCB161CA
-:10315000E22357F1F6550E5B27F683050F4F8F4597
-:103160009E49558B59E4736C32DAD5DCFE0D00DED6
-:10317000703B39DC1E06CF808FAA3769C487439B1A
-:103180003CB61492639A13F3AB7604B320DFAB3DE5
-:10319000911EBC3FDBE84D3C958578C4642AD95725
-:1031A0001CEF63E18F6594C4F162B6FE1CF8A1B216
-:1031B000B992ECC5E87C9DE4D3D92CC17753E04F9C
-:1031C00084BCB174A4601DCE53CF139C390EE2E7CA
-:1031D00048063C745A9D3980AB735DA409FBE694A4
-:1031E000FB045FF37566B7F0EFEFB7B028ACF7EF0D
-:1031F000E27B3E5EC51A8BAF95D787D8992526010D
-:103200007C55447C9D394CBF0FF09CFE1E2BC1FEAB
-:103210005FB56933C1A3F88259DACB12A1DFED7033
-:10322000173FC07AF9287358E951E0AF871F6ED372
-:10323000880F78792893F8E1D637891F4A83592B6C
-:10324000F311C7AA655EC411929907FE806ED64538
-:10325000FA4437D72720CF943C517283F3811779F2
-:103260003D8ABE4A7EEC6CE42071BCEE6AB453F930
-:103270004CA39359B80CD8DD984CF5E71B5D54B6B8
-:1032800035E6D2F3171A3D54DFDB5842F5FD8D5E6B
-:10329000AA1F689C4CE5CF1A7DF49CE385E49092CC
-:1032A0002B4A1E297E5272299C8FE671F45E574C80
-:1032B000DF93DC53F20EF33015F7CA2345DF0CCD54
-:1032C000E74F76438E75CC81BC28379F7DEE25F87D
-:1032D000496A1C9E0817F022E45EB7C34E723EDDB9
-:1032E000C60EC05E6F5AE1EDDC10B2AFDE5EA331F8
-:1032F0004B089FDE511FC92C217C7C6743BCA15E1B
-:10330000D1F0DE6B8378FF5ABCFEDFA0CB897B3F18
-:103310007DFCB7FCF993F77E910D7A7338766CC11A
-:10332000B8ABA37AE048407DAD95F487A151C20EB9
-:10333000C21FE8329F89F5F9E4BD7FA5F5DDD910FC
-:10334000E132F376F31B22085F1F824E1CAF1F4B46
-:103350003A55AE3BF9DC4B58E7AB6D24E7E6AF9549
-:10336000EB7223C76788BEF6490A23BD4CF3328649
-:1033700038CC27DFB305F99ECF3ED1EC010DBA0F53
-:1033800037922AF8737DE31B947FA5351C237D5863
-:10339000475E16FC047EAB211F4B6B90795A1D4390
-:1033A0000C7954D1A3BD36C807F034E8363FF73066
-:1033B000C3BA66CD9A135B40B57C5EBD51237DA335
-:1033C000475FC836131D2BB32C54FE026B9CECC513
-:1033D00066DA9F14BF7279E10D605D3417D91686E5
-:1033E000C8E1F9F27955AE894AF5BC32CB46FDFC0D
-:1033F000028B91F7FB406E866D01C939970D7240C3
-:10340000B59F9F5BBC3E6334FA99308085ACC7A200
-:103410006C0B7D5F89442FEC5F76E1FFAFED671F9A
-:10342000507AC969FCF36A829FECAD25CF3FFB3C23
-:10343000E2634B3E8A203A2D1929FD11F981B1D35F
-:10344000499FF13A343ECF6592FE65CFFE3EB6838A
-:10345000BF5FBE57F82F79D98972D9EA1AF26B2D5E
-:10346000F3F0F59100B96A8C231F7DFEA3D80EB24C
-:103470002BFCA9C82FE4DB422A4B46BCE8E424F825
-:10348000C597B3AEF5C8EB0AFF6EB9F655ACF0EFD1
-:103490008B38B98A5F96BFFAE7248263DFC524C8F8
-:1034A000B5E5AFAE4BD2FB98F7F2B0F8B58A9B2BDF
-:1034B0003FD872B6E94BC4DDC2DB5565C70C00FFCF
-:1034C000B0ABD855E4A7B030CA6358691778E80E96
-:1034D00064C7B13EC6EB19772B17ECDC0EEDB6B81E
-:1034E000E23C1CCE0BFDE4F1EDCA16FBF93919479D
-:1034F000BDB0DB4C7AE185DD31C4FFCB76FFF0F562
-:103500006B787DD9760DC3B23AD64E785AB6D7CC01
-:10351000ECA1F60DFC3689FDC3B9F4D9987AF0D345
-:10352000E236CDBB231F717957DCC01078D6497EB7
-:103530005A1AD13696E820E1FFAED48F54BBC507A6
-:103540007F6803BD78BBF3A4B7FC341ABA36FFEB2F
-:103550007A07709ED9368AE2BA8BDBF62CA37D7F80
-:1035600077B41353FCC26AF4476D96E36DCE167AB6
-:10357000C619E9FF3DF3BC99E40FE0C43AFC4213DD
-:103580007E5EF5DD16F9DD1689B7EB10541CD3DB32
-:103590007E715B676C166FFFD981F7A86C95ED178C
-:1035A0003BDA0BB15F7EB6377A7280CA1F4D7A85DF
-:1035B0008F77AE6DC2002D645D3D9F6DA5FECE6D13
-:1035C000334F06BE5840E519B5D17CCEEC4ED5C878
-:1035D000AE05BE397ECEEC7D31D644EBD66FA0A3CE
-:1035E000C92EFCA96E8B4BEA977627F48CB95CAB9D
-:1035F0008BE3F2AE6EAFC807087FAEDAD37A4B0129
-:10360000BF77D904FFCBF8BD8C2F214F84E2F13175
-:10361000B600F6D779235DB36E873C7BCB2AE831C1
-:10362000C4B50576D5BC7713C95FB1D2EA1A84FA5E
-:103630009FDEB692FF7CDE28B9CE933BC6C03FD951
-:10364000E916FB7AED46BE42F8940773FAFBF9FCE3
-:103650006A0326CAA77C3F3B83E6F7588DC96BA354
-:10366000384730077ECA1336E637434F7E2192F43F
-:10367000BBDA0CE1777F0CFCCECBDA84604E22F40F
-:103680001D49C7DA5BF9FB107AD63E15CC81DE7294
-:10369000D626FC7878EF44592CDA3549BE413FE80C
-:1036A000B7D3ED3C4FFAE5BE18063DDFF4528CF07F
-:1036B00027FC2492E20EAADF53D942BF6F92712EEB
-:1036C000FF0E011FE082DEBCD8D69C03BD528DBB2D
-:1036D00038B699C63B2BC75B1CD52CE207322F0CA2
-:1036E000ED697C2BF3C21EEF7A3A82F4D32F52DAC3
-:1036F000F763FC2F9E1E4E71F04E7760E1017ACF8A
-:10370000F5364E8725CF440401EFE74FC7509CF3B1
-:1037100073ABD0833E8F49223DE858CC23F3D05F72
-:10372000F7F6080DFE94CF35664BC6FB1D03295EE8
-:10373000B5A4B181E2044BF872473C9A97931157B4
-:10374000FE7CC770F2B37CFEA699E28BFCF9463C86
-:10375000D759F3BCEF60DDED8A263FDB17CFFC6D58
-:103760007868FC41954BB61BFD498AFEEABD35479A
-:10377000D80DD61C81C7C81CB1CFD445B73D9241E6
-:10378000F314EB95D381EC2DBE3E92E09F3ED1F633
-:103790007292E6009E83393F02DE7709BBE68BDD3D
-:1037A000568A8B2C7929C64BFE9B0D5799B05F2CFE
-:1037B000310BFD77096737510AFFD092D81CF20F01
-:1037C000717C93FDD8B5C32CC711E37EBE334DF891
-:1037D000DF83B2BEBF20003E9F92C0EEBC95F49B3B
-:1037E0006D85C0EBC5EDD126F0051FC78BB8FD92E6
-:1037F000EF7C57E0336E21E9E30C79D063112F178A
-:10380000F2B26EC33571C88761EF9A1944DF458BF8
-:103810006710E46138BE66E74879B9FF711BE2675B
-:10382000B57CBD203F68A98C9B2E7D46237D6EE92B
-:10383000FA6BB6901C7CC7CAB2391C67DB7E181BBA
-:103840004A8FD21CA157F47EEFA1F64B797BF1FD94
-:103850005BB104CF4EAB07F084D3F18ABF7FC67C47
-:1038600045DFF7F0471BDFD70B2F9FF745D6FEBF8D
-:103870003E821CD91DE9F1D3D3368A3B9FB1B62DC8
-:10388000C4BCCF3C1749F2E54CBC58EF9F7179E8B6
-:10389000B7018E6F3D44FE8DDF4C6710DD8B02C695
-:1038A0007ED5B837E488731B75899E38C433EA38EF
-:1038B0001DD01FA7CB2DF4FDBB56FA3E7C1E393917
-:1038C000426EF7ACCFE7A2895FCE0C16F438F3FC5A
-:1038D00030DA573AE3059F7378D361A79C8917259F
-:1038E0008332C2F96089B443CF4C6823BBFB8CB6EA
-:1038F00087CA4EABF86E49838CDB72BE4B06DF8005
-:103900002711B7B26F6A871E01FFF4D8622A8311AC
-:103910000997FB99C19FD8879E94EB0B6A0DE43AF7
-:10392000C537483F69B3411EEB528FABDD7D79BC93
-:103930008CE2A0BB358AFBDCABFAE1500F50FE7184
-:10394000CE8F4BFD9A17F9464BD7AE580C7E5F5A77
-:10395000BFF976F0BB9AC7520B9B0CFBAA533313EB
-:103960003C9D917CDD000FA1E365F4E2F7FE1CAD08
-:10397000270FDA99447A2629D70FE688FD0AF566DB
-:10398000DE5FED5A6D138DE356F6A4989FC2134780
-:103990008B0D7E326EE78BF7FDCC5FC1193E7F0544
-:1039A0004F6B8ED01B3ADDAE87C683DEBF3293FFEE
-:1039B000F4E257A3E212BE462F83C5D6E32FE6F00A
-:1039C0003FCFF76AC0BF42CAB7A5F047733873B696
-:1039D00019E31FB9DB8DF511BB8DF5FCBDC67AE18E
-:1039E0004163DD73D4587F04E30EECC513EC5CE453
-:1039F000B5C1CE45093BD79523EC5CD461E7A284E1
-:103A00009D8BE7B07351879D8B3AEC5CD461E7A244
-:103A1000849D8BE77F9078AA957E47D081F2AB5E3C
-:103A20008E5471705A2F17E62491FC54F1CC0B8BF5
-:103A3000F3A9DEE3CF9966277F8ECAD3B93D4E7FC7
-:103A40003387E286EDEB5340374B07F97197FF4C14
-:103A5000F8716B8B231DF02F74ACFB6C3DD4A7C2A7
-:103A600038FD1DB4BF60EDDA29F2958224373AD6CD
-:103A7000B8DEBD5ED08FFC1C2AEFA612FB5D42FFB4
-:103A8000740C8FA3B04DC6B849781C253C7E12CE6D
-:103A9000072A6EF2A4B52B05F2FEE4D3F64D80FFA3
-:103AA000A4F48FB1D94ED2BF945EDDA37F3DA83D73
-:103AB000857DFB428EC8FBEB3EC6F5ED3EF65B55C1
-:103AC000565D2A26BDB1A7BE493351DE48722CEDA2
-:103AD00043AB244CE95A57E706C8BB1813EDE3176C
-:103AE0001D26B20B2EBE6F263D6218F4F390F90C22
-:103AF0000F4419F82B6F574258FC6FB0A1FDC80353
-:103B00001961F1BF11C6B8D46D6B0EC1BE9EBE69FE
-:103B100094A15DB5EF9A303C4AB8A55EDAB47A6BF1
-:103B20003AE4CFAA986E827FD5BE48CAABADE6F024
-:103B30007A11974385A3A0C6EE9D0AFCD5B459E33C
-:103B4000B1CF57C9FD873518F7E31A0BF33B137A4A
-:103B5000F9AEC6C9BCF1FCFB7345CD3B4D9C6EE78D
-:103B60004CDB1E19EF425CA935DDC9F9EA2EAD2DFB
-:103B7000E96ADEDFDF2C7ADA304E8F746BF00715DE
-:103B800090977B32D91ADEEEE4A6176349EF967C54
-:103B9000966E754681DEADCD66B20BE0973227F4A6
-:103BA000F2436B73625496A3779EBDF4FF8AE6C717
-:103BB000E9E2C139C56EC7E121ABA0C7B589F9D625
-:103BC0004CD0FCA427CBF9AC94FB0ACB12FDDC252E
-:103BD000EBA7A4BDA0E67776F8A14217E2988D077F
-:103BE000D2CD90E3A6DD3B717EE0DE28BD64D840F7
-:103BF000E44B66FF763C1F77C907225FF78F2D13D2
-:103C000063AF86FEF99CD53385D73734FFD806BB22
-:103C10007889256083DD59F374ABCDCBCB1B76B5AA
-:103C2000D2F385BB2AC9DE5EC4EAC98E3CADF26F11
-:103C3000253E6A4AB56D4E0EF793C384DCA88912FF
-:103C4000791BE5E6F1AF212FFDE22EAD08F3BDCDE6
-:103C5000B7C756C99FDF3A4C9E3B095B1FDD6F4FCC
-:103C60002F1F087F529B887BF6B71E660473693D41
-:103C70004CBFE4A2F2B64B23C88EFD80F90A484E31
-:103C8000E487D9B36F8B3CE4EE83621DD4D8820302
-:103C9000A6639DFCDC4AEBA48ECBAF9262D8C98CA4
-:103CA0008DE3A56FBCD9C0AFCBCBA20DFC3C9B254F
-:103CB00018E2C833716833A47EDB944C43FB59B7D8
-:103CC000E585F17F71EF7B9223E30C792675ABFDDF
-:103CD0002E8DF2594A8DCF79B99AF8EC26C3F77533
-:103CE000ECD6DE76B083B7FF9AF0CC58BB0DF65613
-:103CF0008D49E4D5CCD63BE5F30E7ACE27625887C2
-:103D000043333DBF15FBA295FCF2CA2F3D1BFFCEEE
-:103D1000EC6B5FE48496E3223F14FE05437E2107AB
-:103D200080EC4F26E85027FD3D75B9C2DF53E76FA1
-:103D3000B721FF96E3DF92CA51B2AC59237F1E6FC1
-:103D40006F4F4D10F5D578BED778DE00FD5DC2FB14
-:103D500063E64AAC97F0F7CBF8BCA1672C839F06CB
-:103D60007E26D5BFEC57F1E7A2AD46BFD132F8733E
-:103D700042E8F8C93017F1F3925D7B5E1FCCF13257
-:103D8000DD175F84F553DB36CD5A997F399F29F9CA
-:103D90007EB1C64471EEEEB78F109F75D758889FDD
-:103DA000BF091FCBBCC29F19CE7F0BF97C10975D5A
-:103DB000B857F30434D10E78190CBE0CC34B6A1FEC
-:103DC000F85278EAC15BD8FB45F8C768E40D688112
-:103DD000A0BB2FBC483CAAFEC3F0C44A8C7858A8AC
-:103DE000BBDE85BC5978CCCC025730EF45981FC656
-:103DF000E7F3C3F8B75E127E1215379879C942F51A
-:103E00001E3EF189FCE9DBA618D7650FDFF8C43A3E
-:103E100099712989BEFB9FE69F6FE21B0577787E2B
-:103E2000B23ADF737A983CFF32868DA1F57F8579AF
-:103E3000C36ABF57781E7A6F09E513753B32487F16
-:103E4000E8D96F9CC6F72B6332288F5897FE392527
-:103E50007775D94E8D53C9DFBB46818F8724C1EF5B
-:103E6000BA7E6D667A47885EA2AFB392DF347D4D2D
-:103E700022959591CE24EC17956BCC3EEC839FDC7C
-:103E80003F28A9047EF875D6015378D79FDC333AD2
-:103E90009D15A05E4EE5C9CD11B343FDD9AA8CCFC7
-:103EA00015FB46DDBDC769FF3A677A3B7636D6D942
-:103EB000BA7DB148A959BAEEBDB14EAE7AB45A74C2
-:103EC000672EC5495B773A8137676B21FCD174F661
-:103ED0007260AF9EB0645DF920F8BF6AFF7EE409AE
-:103EE000ECEFFA1A6B12F4CCCFDFE7FB9F46FB171F
-:103EF000E907A7917F3C0071AB683ADF765A635EB1
-:103F0000C46F169B0F153A0DFBE9C19980E3E528B4
-:103F1000DD953B06E3077626637C8F9FF225F5351A
-:103F2000D9717DF94B54B97CABD0DF762A7FADF4E3
-:103F3000EB426F471D7A3B8242D0DB5187DE8E1207
-:103F40007A3B9E97C25F8FB86A535711EC4E7F2918
-:103F5000CBADA7FDD5910BBD7C9516E581BC59A5D0
-:103F60007906C10FC6B6A7887D358CBEAABCB68BB4
-:103F7000EB5621FC7EFD253B0BCD1F9BC0E20DF5D2
-:103F800089F61443FB72A7DBF0FE86E4E186F7377F
-:103F9000BA8A0CF56FE55E6D687FB36782A17E4BD0
-:103FA000C98D86F6D3BCD30CF5E993E718DACFF0C8
-:103FB000551ADECF9ABDD8F07E8EBEC250BFBDE688
-:103FC0001E43FB3BEAD718DE7B99D382FDED20EC44
-:103FD000298EF79FC39EE2E5AA5F653B42E93A7EE0
-:103FE000A2A9BE2F7FFCA25CA1CFDC3FDC3B1FFC63
-:103FF0009126CF81A4C9F31C77E7BA44DE00CEED49
-:10400000933DDB9E02BE096F17FE7E7CF4E18B2E92
-:104010004EC3F6DC5B6EB370F930FEAAC3A33279EF
-:10402000DDFC74D36D162E57C65F73F8C50C5E8F1A
-:104030007EFA55511F79F822DEAF7E7A83A84F674A
-:10404000A45A243E3DEE363F9FC7F8EB33367984C1
-:104050003FA4CF7C4B55020FC85B041E5006397F2E
-:10406000A23CCCF913E551CE9FD5598CBDCEF913A6
-:10407000E5316E57E2F92FB95D89F26D6E57A27C7A
-:1040800087DB9528DBB95D89F2378DB3A97CBF51F9
-:10409000A7EFFEB3B186CAE38DF5F4FCC3C6062ACA
-:1040A0003F6EF4D3F3CDB9CA4F11243F8B8A272D2D
-:1040B000431C0F7EB803D6B3A17156150F54F1BF40
-:1040C000A67AD6118D75DA6189FFD4DE1BD7EB5F36
-:1040D000CE5AD8A721FA566BB4775B2EF92F8638C3
-:1040E00029AE239F976AD3D38A79F9854B7F0AEF4C
-:1040F000671457AD8B73E31C48BD15FCF281A9EF23
-:1041000073C1774B3EA91AEEFD09BE53716C15477A
-:10411000EEC94F0989739B42F262E82F24BF45C55F
-:104120009B553ECD7576919FA7E2C92A6F46F557FC
-:104130007E8991BCBB76A385F493180B0BA27F9567
-:104140001F73ADBDAD08F902D7D63A280F6D107FA9
-:104150006E2BA6765E332FB7FF99B72FEC8D5F0FCE
-:1041600092F0F3F7047FF9259DFCAED7CAF83DBE67
-:10417000B78BF77E7C8FDC29E819BC24BFDAE3C853
-:10418000732AEE8DA7A37DB4681F447F59FFC5C76E
-:104190008BED5D3F69096D45C8A74A5BE6A07CAA27
-:1041A0006D1382747E4B77EBEF019FBE08E7EFA3A0
-:1041B00069FD64A6C14F304DEABD5F4387E358AF48
-:1041C0000A3F0ACF8A2E0ABF21794784D7FEE81416
-:1041D0004E9F70BA287A945FEAC533F074391D7A1D
-:1041E000E9047FECFF2B74186D69A3F37F11B5769A
-:1041F0000FE0FA26BADCD9C526E13C7172867E371B
-:10420000E85379C9F53AEA556CC2246C4DEABDFB16
-:104210001BDE4FFE86F70BFB79FF56A4CA47F03A28
-:104220008A385D264AF9B1AA5CE077B2DB4CF89D8A
-:1042300098BF88F451E6107A9D8BFF0FF264D25735
-:10424000BEB5E86FD200A37EA8E2C137C9FE2687BB
-:10425000C5816F927AE34D617AE1B0E1323EEC665E
-:104260006E61F78973EE65729F4E9574CEE4C6FC5D
-:1042700078D091E91608ADA338E75E8873E07EAA8E
-:10428000DFC802547E8B0569DFBA990B38D46F61A1
-:104290008CF2198F444FAD58CEFB9B386A62169E44
-:1042A000879CEB2B193E86CEF5FDC11972AEEF70DF
-:1042B000998BF486C3F64CD263B00EAC217EB43732
-:1042C000B9DC472AC311BE2FA07C8DEF0B599CC9C6
-:1042D000DFE0FB02EA37E5AE61F86E92CB986FA2A1
-:1042E000BEFF96B3945946F52F77BF55F8F210F8F4
-:1042F00057DE8A1F5606BFF35BF1579561BE6FC547
-:104300000F328932C24665C14B597DE9598A0F7B0C
-:10431000C79BC42C8997E357E1331C8F0ABFFF0268
-:104320003EE7F785CFBBA53EDA6D7F2F363903F127
-:104330002FB1FEEB5E2A1804F83F0768C84BB60B96
-:10434000BC84FB773E6B6443805FB63D8E9EDF2D61
-:1043500079E8DA8671D4FEBA86129ADF3551FAAA64
-:10436000E13877521CCCE19A03FB6C5B139DBF3D97
-:10437000F7BCD903FDBBD6ECDAE4C15A7F4B9C975E
-:10438000635F1D4947BC8D6DEF3B6FB7D6AEF0E65E
-:1043900027F88B32BC778BFD4F9C2356FBEF9008A0
-:1043A00091EFAACEB3F6B71F8F8D12726548849035
-:1043B000838A4EFC3BAAA7F27EC672B991FA5014CA
-:1043C000E9DF2509DE07804F56C60CFAABB2ABBB5E
-:1043D0000798296EBD12F1CB01B06BECE4CFB98E1A
-:1043E000E5DC023DB80CF626C743F99B55744F81B6
-:1043F0003A9711916C32DE6FE38A32DCD7129D9BC3
-:1044000060A8C778061BDAC7956418DEC77B471813
-:10441000DE274E2E36D407FAC619DA0F9A5D6AA83F
-:10442000A7E83719DAA7D6DC6AA82BF9922A1EB1B9
-:10443000B4FAB986EF8736CC37B477FB9718EF9F7D
-:10444000F17BDB73932097C45FE6C69586F73F8ABE
-:1044500015E70E263B16D27D12D9CDDF318E6FFEC9
-:10446000CA0CFCA6C669E2BE0097907F7EFE3FD0D4
-:10447000B53CD9280F273A8DF630D7D734ECBFA9F1
-:10448000F516C3F337864BBBB7901592FCFB27E9B3
-:104490001C8E97EE32E609A23DF4155EBF4E1FF169
-:1044A00010FC0E6503AC9E0013FEEED079C1DF1D3B
-:1044B0008A07F8BB43EBF0771BEF6D32D21DFEEE9F
-:1044C000D0F7A38E19E93EA6DD48F7AB8E1BE9AE07
-:1044D000F8319C3E577718F9219C3ED79C0EE30F8C
-:1044E000498FD9FC7FFF10E798895E931C1A7BCC1B
-:1044F000FDAFD3E76F61F4E9A187C34EFAE275C15E
-:10450000BC38D4CBB1CEA037C8F9DC9057EFC88007
-:104510009CB4E9D611037BF9A72945F04FF7B117F1
-:104520002321F7224618FB3F9FAA47A1FDECC48B2D
-:10453000E936F04397B8AF6FBE949F2A9F90DBBBDC
-:10454000E23CDD77CC14DF3F616AA6FB920E3BF5BF
-:10455000047C7F677EBD86F84132F3ED59C8C79B66
-:10456000F78B088A27CC1B2ACE75B2FC0ECAB3572C
-:10457000726E5EAAC863193C42C6273D229F256D14
-:1045800084D00B633C4ECA7BADCC17E708B859907A
-:104590003EAF00F8783B12F71676B708FF7D8755D7
-:1045A0009C2FF5733E455C0C7A22F4B834A947354C
-:1045B000FDCE6E07FCC3B632C3BE383C6037E45D47
-:1045C000E6ED721AEA056DC986F6230FB80CEF8B7B
-:1045D00082B986F7A38E790CF531ED2586F6571D45
-:1045E000F71AEA57774C36B4BFE6B4CF504F655D43
-:1045F0008F02BF4335618FCE1821F278F81AA57863
-:10460000D2BC0DF1E2FCA0B453951EACF27175C999
-:10461000D7E1FAF4509B4EF9BD4D29CC43E700ECAD
-:10462000D23E61463D5B97F9B44A1F657E633EAD5D
-:10463000CAA3EDD1C7A5FEADF4E1903C5A6F681E48
-:10464000ED3C79CE377CDFAB1C21CFF385C13FD465
-:1046500026E6DB748F8DCE2D28B8C2E1392BF33BD3
-:1046600077D8FB3E3FB27C84B0637F96E95B3482AF
-:10467000974F403C65F6359EA7C3CFF9ABE97B3633
-:10468000CF7DAE6F1E6FDE48319F0A93E9CE69F988
-:1046900094B734FB8590F11B257F57E76B7DCE6F78
-:1046A0005E9CC82B62713617F8B7FFF1043E936D1C
-:1046B0006C2D9D739179E7776C6A7B102EF20A5B03
-:1046C000B355DC5F16B0821FA69472FDA988DBC9C2
-:1046D000DBFFEB870EAEE73CD160213FC4FA67CA2F
-:1046E0006770CDABE71CC1506E5F803FA0ABC02EA2
-:1046F000F94B9EC89BFDC9084665B9F9AB9EFC6F96
-:10470000F2A73326F70761B7F4C16FC4876A1EFFAB
-:10471000EE3CF0703C29BB90C9BCBB2C0997C25F32
-:104720008F1D2FF1A7F2F15D2BACBEA71C94D73FD4
-:1047300019F94C8A7E31F9822F7F27F181769047D3
-:10474000FDB52B37E7C7C15FDBCD5C71CEAFF1475D
-:10475000FEBBF0A2F0DFDFF99EFEE4C36572A19F0D
-:10476000F33EFDF127FDFD13E77E42E483C82F9160
-:10477000F4086499289EBB21C6B88EED79625F78F3
-:104780004EED177E6E4F1AE504837FB9699D59CAB5
-:1047900009B16F63FFC4F305EBACA4CFB006918FF2
-:1047A0005C23653163BEA471A3118FB5D27D56D74A
-:1047B0007919E93BF31DB6402B6F5FE90FDFB7BDF9
-:1047C000F43DC56B5CB8B7C4B31EFEF7AA8DC676C0
-:1047D0008B1CE25EAF056176E92269972E0AB34B26
-:1047E000FF3A42DAA51EE621BD4CC69F159C3D7CD2
-:1047F00015C8A4BC60D8A966E12FA17C2585271720
-:10480000E20B21F768727C46E562DF5E6BE9338F6D
-:10481000AC079FFDC4C9CF224EEEC2FAEFA6F33F0C
-:10482000DD7B23451C4DC52F64FBB3FE8BF41EEDD1
-:10483000D1DBB9A2F642C4917AE21D6171936E8711
-:1048400029B604FDED16F72FA83C80257F0D143AFC
-:1048500043E29C7A87C99077115EEA6BF6515E401D
-:10486000AB45CFCC433EB2C563C77D91F73B0E2726
-:10487000E1BCF614E9AF0987B747AF1AAF8938A191
-:104880005FE8B9DD9335D273B95C6458472A9E3D21
-:104890008D0507A054F1037D6309E159C50F2A83F3
-:1048A0002504E78CA645565CD9D7F1E8EAF22857EB
-:1048B0006F5CA1234DE4A3F4175F987EC943FDDD2F
-:1048C00076691CF5539AE716E7F5D73EB8027C34B3
-:1048D0006217B3629E1D61F9D8AA7C214FC89F77E9
-:1048E000F394DC96792E6B34A1C76B4CE5BD90DC5C
-:1048F00056F58BCDB25E2EEAABD6897A87BCC768F7
-:10490000A7F437609E28311FD8C5BBA53F02F340EE
-:104910008979E039E414EA9053A8434EA10E398511
-:1049200012720ACFE7335F7A9159C441CA42D60D59
-:10493000E22065217A10E220A175C44142DB230EFA
-:1049400012FA1E7190D0F7888384D61107096D8FF3
-:104950003848689D95DCD85B875CF34E33D4A773E9
-:104960007DBF2C64DD220E12DA3FE22086FEF415B4
-:1049700086EF6F670D86EF1107096D7F6783668885
-:1049800093DC29CFA5576D4D20FEB8C9ED6BCCE364
-:10499000F4FD43F4DFEFB6C20E341F5C4CF6595DF4
-:1049A0009447D0B979B2A0BB89093A77CD213AAF03
-:1049B000B6897AB9C88BED2BDE509625E20D281109
-:1049C0006F408978034AC41B701F36E20D28116FAF
-:1049D000C073C41B5022DE8012F106948837A044B5
-:1049E000BC0125E20DF80EF106948837E039E20D9E
-:1049F00028116FC0F313887B64F5C205BD3DCB6001
-:104A00003F723E34D88F4E431D7A7B687BE8EDA120
-:104A1000EFA1B787BE87DE1E5A87DE1EDA1E7A7BBD
-:104A200068FDD00817AD33E8EFA1DF417F0FAD1768
-:104A300034FB5F838FE9E66DE78FA2EC88D19ED0CF
-:104A4000B82808E67D3C0371A48E482D3D9E2F7941
-:104A5000EB9ACE1965BCAECBFCB242D645F73BEB28
-:104A6000F2DE1A3DC8281FB6E02FC9422EC83824EE
-:104A7000FD71BA17ED65640794CAF383EA7B0F737F
-:104A80009A51AAF6BDF5BEDB858FAFDA91BC0C81D9
-:104A9000831B8845C883285AED28461EF74E932667
-:104AA000F220EF1379A8E17CF527B96FEF34ED39E7
-:104AB0001C85BC964A8DEE8BCFB1B063B8C7BBA046
-:104AC000B9BE18FAC2C7793DF7CB8F435E8C825BC3
-:104AD000F901B99CA07355E3BB98AD3A1FF7893132
-:104AE000DB02C8779BD013F01DECC73CBFE67D2AE4
-:104AF00084BF3FCD137ABFEE5F31AE9A3FCFDB5D0F
-:104B00003F0EE7B5A64489EF7EF2642CE171EA5AC4
-:104B1000ED299C8B1BBF9B7971FEF282843B6FB7A2
-:104B2000D3564DE33AE99C578FBDB22D9DCEA55586
-:104B3000B28EB264F2E56B748FB9C21B9FDF51CCA9
-:104B40008F8BF86356D247C5799128795E449D13BF
-:104B5000715B7C7B608FA8F322D78E8E2F47BE16A9
-:104B60003B28EEDDBB7974E5BA81BC7F3D20EEDDEC
-:104B7000BBF64FF5AF517DBBB8778FD8602C8D4316
-:104B8000FBDA30BF46F73D4CF5B79A06B8707E7435
-:104B90008D3509ED77330FD49F614C9C8354F0E53C
-:104BA000B37613EE1DE75BCC91C4103EE29C7A1BFA
-:104BB000E85EE4B1D27D10D32C4E2BE446F83E7E65
-:104BC000793E5D989E10960FD1B4FA78BA3903FEFB
-:104BD00024932708B9B52F9AF405A5EF54CA3CA829
-:104BE0008B6B5FA3FBAC2BF708FD40E77200F24F25
-:104BF000E547D46506D24DD01706B7162698C5FEF0
-:104C00009FCFF178C6FFE2CC1217CE31BE46F9FA3B
-:104C100095EBC6C489F33A22FE502DF1542DF35F73
-:104C200058BE33097AA7BAC7B4DC3C3E8ECEBB353A
-:104C30000B7D4EF9772A7F35EA75D0B9F271791F6D
-:104C4000C8C64A3A07149E87A2F44375DFC9E2B585
-:104C500056CA6F591CA6072E957AE0D2303DF09ABD
-:104C60007CE99F517AA0BA9F4EB6A9FCD59119A4B0
-:104C7000A7D48BFBF82AD608BD85ED11F7D857AC21
-:104C80009968C2BD1515FBBC1EAD0FFE7857EA2F03
-:104C900053306822F27C065339F3523295B32EE535
-:104CA000921CC0590CD0BFE36546FAF47B525F9961
-:104CB000813C3F9C8FF347C87C3E46FA5211739665
-:104CC000436E8CF06A47E0BE9E62D5D7218F704A52
-:104CD0002BA3F3303743AFE12F6643CF19053E775F
-:104CE00097D3B980C91A9DAFB879F40AC9D79CCFB8
-:104CF00019F8DC2FF9D647F59EFD40F2B7EEEFB478
-:104D0000D0BDAC7ECD867BD97469CF2AFE0DE7F38A
-:104D100079F2F7269843F8997AFC50001697ABF889
-:104D2000C7CE84BE380FBEC1C1929076D875E2FD61
-:104D3000DDBBC7CE5C8B1CEBFF4BFF4485FA1D0629
-:104D4000AE67419EDE7157916D7E885C292D2C6D7A
-:104D50002918D84BF7F93DE7C6F20741FF5F797F85
-:104D6000F6A0AF3BBF58C5F18CF5312FAEE36EDC3A
-:104D70008CFB703EF39625E33E66A62E9109225FDA
-:104D80006DAEAC1FDE7DE77F6E74107EA8BE39BFAE
-:104D90007CA69FD68B9057B7435E9921A7F487F2E4
-:104DA000911F64EF98047A44E777C9F3F0F21C6B23
-:104DB000983FE270BEA043B85FA22A5FC8716671D7
-:104DC000A5DF4EE7545DE4D753F07F62359E1B5458
-:104DD000E5CFA47DFDEFCAB7FF7392FE2CE6F788FE
-:104DE000499CDF1E6C6E66D23F247E2743AE1F2691
-:104DF000EF33E8A53F971AA0FFFD9A3394FEFA46D9
-:104E00004D9C9BEEC78FC372BB1EDD013F5EA3F8B6
-:104E10007D8E2773041F3DF91D1BE9DF15B6F6D7FC
-:104E2000704F93C2E3470DFF61A5FBFE58301BF79F
-:104E30004FCDAD8FA4FB5E4B0B7D8720F7A2F33DDA
-:104E4000448F9602C1671D4EDF513CAFDB74E80909
-:104E50009C1F5F7ED04DE71A2B0F14ADC7BD16A562
-:104E600085FA9B986FA5C369C3FEBD6C6D3CED6769
-:104E7000F306C9F385AC8BE2540AFF9DF9621FDD8E
-:104E800052C8E43DA732BF9E0BCA69867632AF385E
-:104E90006C9D28FF60B89F21FC3E81FED68FF227D3
-:104EA000C07F600BF12F2AFF8435F79339D83F2B51
-:104EB0006CC6F370AA4C289076AEB40317F4EC5F7E
-:104EC000F99306415FDEACD1EFD6543B5CB3AEE65E
-:104ED000F5EA6356640AB229092E718FC4FDE21EF9
-:104EE00089F97CBD42DE54C8BCA1EAAD25B4DEAA76
-:104EF00003BC4CEC7F5DDEBEF948DACBE09FA097A7
-:104F0000CE89573BBDB68490755FD5AC19CE99ABB1
-:104F1000BAA9C02CD611AE302F86BC70DB70974B6F
-:104F200005572B9087965020F8437DC7DB511EC351
-:104F3000940CF6BAB8C787C3ED16E31587F43FBFE4
-:104F4000D9785E9EB7277DC8511023CEA73BF9BC08
-:104F5000E1FF703A094E8E07C253D783BC3F178DCD
-:104F600043F4A80A06ACB0B72B903FC1EB739D0188
-:104F70002BC699BF56DC5BA16F12E3E81BE36D05FE
-:104F8000D0972C4E5B1AF027EFB5E7F0911CACE6FA
-:104F900078C1F91F750E301C3F9512DEEAE678A342
-:104FA0001ED6BCD90A7ACCE9E7FCFC7505826FE70E
-:104FB000AF9D40E79FAB2D5ECAAFD7257EFFB822DD
-:104FC000F201C407E6B46CB1BA79BDB040C899EB40
-:104FD0000A047F4DC90866D3FD342B223D80738EB1
-:104FE000B399E6D783DF87393E34DC83E223FC7252
-:104FF000BEF0238FACBAC548CF5E7862C43D462D63
-:1050000095B4DE165A749B33148EAD87B271AE67B9
-:105010000E5FDFB8778739753A6FF3E9C3B3D269AA
-:105020009E1C4EE035C6E39A84FB66389F101F2B0A
-:105030007E51E783D578330BC479C799057DFBD7BB
-:105040007BD7A597F49B264E5FF8BDFB5B97361C7C
-:1050500034E2E3DAAAC53D60E1EB54AD4FB52ED59D
-:105060003A55EBF709AB2F98ACF5CA19BEDFD6BF9E
-:10507000D0079E5A0A841C992BE9CAF17A34F45C51
-:10508000D1F7E47AAEC830AE77F447F7064ABA579C
-:105090009406B3710E50B557E3562488EFC0F7E07D
-:1050A000B7A5723CB45F49ED4D067951D5232F76F3
-:1050B000AF4B82BCD8A391BEBBF2C12369DF861E71
-:1050C000FB9CD063CFD4EE589602BF8125901E7A08
-:1050D0003F537550C887055CFF81BC5828F7E9929B
-:1050E0006CFD3B0521EBB7FA87CFE5E842BE042112
-:1050F0005F3E7EEE950FC6B97AF74F05FFFC8DBF78
-:10510000B6563A42F1A5C9FB28BAE9DC5795C3E681
-:10511000429E6DD5DA4A92B72C99DB135A489E54B9
-:10512000181F54AED5E8DEACAA86B101F3FFA05C2F
-:10513000AEDA348DEEE6517452F76FA8FD54C1FF1C
-:10514000B8847FAEE4E380946B736BDCB685B4EE19
-:10515000DDB62AF0BF7C3FA7DAF8BC874E3D71EC84
-:10516000FCF5C9F21C0BD9259BACC2BFB73B86F43A
-:10517000D5332B5F7A67266FF7C523ADE9D04F147F
-:105180001C8BA41F6F81F4C72D947A2BA7D34F0BD0
-:1051900042F25B163D29E854F5FCAF7E8FFBA12A55
-:1051A00032A43C7B509C2F9FDFB687E83667E366CE
-:1051B000AB9BB7FB4581DB20A7ABEA8B9CF04FCFC5
-:1051C000DDD86A851CF8859437E1FC5E21F3521521
-:1051D0005EB1EF6821F10BD51EF26F0F1FE7AE1520
-:1051E00091B1C87351E39C967C5C551F9F80F1AAD6
-:1051F000EA2B7F00BB47C9FBF075773252AC87F9C9
-:10520000BC3FACCB93133C74CEB642FEBE5478FB8D
-:105210003F48BAFDC82AEE114C8D6E7B9AF2169665
-:105220004779201FB2B23A021817FC0CB86D2671EC
-:10523000EF60566DC7978083ABC5949F8212F71DB0
-:10524000414D4EE2F5A74CE23C50865994D642C1FE
-:105250000F704DE13D1BD041F79F85E4671AF8D5EB
-:10526000C6B66FC4FD2BB6018C7EEF45F1A7EA47A9
-:10527000F1A7E2DFFEE6F7DF5738BF936EE987C894
-:10528000F5A4E31CC5BC8786D1FDFCDF344F9BBC75
-:1052900007AF67BE11E2770B2E9B6F968C8FF73BA3
-:1052A000DF96F2A43EE61B3E4FB54E54EE754F5CC2
-:1052B000A159C4154E6A7CFFE2DF9D5C1149795FFC
-:1052C0006A5ECAEF7DA5F9F2EEC2049937DC1103DC
-:1052D0003DB242FE1E040B8A3A9E4F0B79AEF67D1C
-:1052E000756F9892CFA7EAE5BEC83A1EC47A660DDC
-:1052F00099744FC689E69331B8BFE3E404019FFA7D
-:10530000EE2EAB38F7CA626C2EDC9FC8ED2BFADDAF
-:1053100087056B07911D79474326C9853BFCF1C280
-:10532000EF20F5FB85520E46DF55B9FE2AB4DFEAC1
-:10533000766A7C9C050ECFA75BE9FB3C0FF4C1E8C5
-:105340009669B60CD27B851DA0E2407769CC47E711
-:10535000992027B1BE4C87B2B0EF2CDA2AEC802915
-:1053600026B611F1C2A14DBE492990138F8A7B2325
-:10537000D936E3BD4A2F66FBC617026F61F791DD90
-:10538000656DF30E821CE7FA06FC4C0B1C3ED2DB6B
-:105390005F9172F2444B27DD4FAEF07AD939159BFD
-:1053A0003897DA156322FFDB959E57A996F124C53D
-:1053B000372A1EF518FE7335F064A27DADDC5C4122
-:1053C000F7FAAC6F994865F5E6F247FC05380FEB44
-:1053D0004B1A47705BC93F565D37519C1F7D2A228F
-:1053E0001EF64DBAD59F1EAA9756B76EA0732AA770
-:1053F0005B23E99C4A99735A59FC00BA6F97CE7D9A
-:10540000A976B585623F5F5237D170CE6401EF1344
-:1054100079B07F6E8BA6BC52757EE4DE287D51E1AB
-:1054200040718EE46A97383F9242ED5D7DFAC35534
-:10543000F969A3388F10722E66EA1CFE7D6DDD8B34
-:10544000B1E867E9C3EF8DE59881FF6915FAEF3997
-:1054500017B3559C8BB90BF612F4C804DFCC39C0D6
-:10546000FF9B66C27F7FE3D5E0474942EC883B0261
-:1054700071A4B7EA4166433C597732D28B4F9B59AE
-:1054800003F400A5BFA8E71B245E4EC735A7833FE2
-:1054900016EFDC928EFDE5F31851AFD839EB9790FB
-:1054A00057FAF608A19F5B18E9C3557EA15FB39A2E
-:1054B00004752F66E43CCE479B0BA3C53D3DF2FC33
-:1054C0008C824BDDB7FAB945DC17837331E0F78F77
-:1054D0002CC105A0EF475C7F851D5B2BE5D847CD30
-:1054E00066FADD113F5F28D0433E6A7E3106E773DE
-:1054F00095BE566EFED88BFB6856EE13E75471AF1F
-:1055000039DD5929FD20CBA41F64E5CBD649F8DD50
-:1055100011AE7FD1935A4BD0D617FD9648FDAAA75E
-:10552000BE770FD96DB5BB85FE50DBD649FA83D265
-:1055300047D4B9B8A5BB3B499F50DF2DDB2BF052B8
-:10554000B7573CAF44DEBAFCBD502D0BF6B446F560
-:105550007776CF9DB5C6509F43F577F2A5BFDED2D3
-:1055600045FAE003B9BF213BBC6EADEC97D7AD2146
-:10557000E3ED07138D11CF331DF8DE65D01BEAF67E
-:10558000C6D3F7C1BAA88DD8E7BDCB1C16944D750C
-:105590000EDAF7B7D59B722DA3015C94077ADC4134
-:1055A00099BF3570E97F46C27F90C2BA8EE0DED7E0
-:1055B000C34EFD4DC819F57B96EADCCB85573F1BE2
-:1055C00085FEAF1BDA7111773C58B585B3109FF893
-:1055D00075A19C477EC728F0F5C0C3423E3F6E656B
-:1055E0001BE9FE608B8FC16F1F947145FF5F4CE21A
-:1055F000F725B4E08F43F52BEB48B19FFA22447CAA
-:10560000B1C8AD7F08386ED1AC0545B0A95DE66C78
-:10561000F4AF7E4745E9A9A5523EA749FBCA3638F3
-:10562000D9013ED6BC5E3A87785FFEE12AECCBDF3B
-:10563000EFB2D3EFABAA3CBFD2AE28D25BD3064FBA
-:10564000A6FD4C7359584531FC2AA620F255BFCF10
-:10565000EC222FC01EA6D79A22291F593BF8C65FFD
-:1056600020CF53CD5F1EC1EF94A47E5BA3FB2FE739
-:10567000757FFA387E63A682058AE81EBC78FD2213
-:105680004877A27B72A7CE49F67D679BDD23F6099A
-:10569000160AFFC17BFE129B60EA85EB42D7A77416
-:1056A000AFE0852E3BF96B4B0FCAFBF6C2E0B99019
-:1056B000ECA2BC68DE8EF4CC0B0E13DD33567AF010
-:1056C00008DD9B57AAEED5B31BEFD563AEB478F8CF
-:1056D00093C987CA9582A42641B7EBE28C7662D241
-:1056E00048A127268DD4E43DA5027FDDF6F36FE9BE
-:1056F0005AEF3A5CAEE2F7EAF7A66A22E8F7A6BAF2
-:105700000F667EEDFD09EF417FE07AC1F732BCE91B
-:1057100023C7F4EE9F33245ED43E6C96FDCF90F801
-:1057200099E130097C84FDDE86E20F457F05AF3AC2
-:1057300077A4E8C6BED3FE1ACE05717A153CC4889C
-:105740004EB918FFC45FDE5E8763FE83CDDE4EDD9B
-:10575000FD6FA15310F7E05C319DDAC3E9148C1C96
-:10576000063DE161F1FB5BE1798D2C97D13A9F67B2
-:105770008E223FA02EEF05E7EBFB35AC6FB5AE8771
-:105780004EEE28C0FE78829BDE80ABC3D446CF1796
-:105790008DCCA0753884B5A7C8FC9B31D0CB9AE4DA
-:1057A000FDC73DBF63B8D841F78D5C08A8FB8F03E8
-:1057B0008F2EE4E3B6CCC827BFFE0526D77B4DCF9E
-:1057C0003DD9E2FEE39E7BB2CD7EF293CC89223FAF
-:1057D0004FCF3DD9D9E2BEEB573496837B68FDD3DA
-:1057E000EC941F1F7E4F36DF679E463CE3B19A283C
-:1057F0008A43A9FB914B9D7AE5C88197DF8FFC888E
-:10580000E69BB300FD1538A8BF8E3951CFEF146861
-:105810000EC28F73A22186EE85567CA9FCD743FD6C
-:105820009D8F024FEA5CE71F247F29BCAB736D0A92
-:10583000FF8ACFD47DECDA6AC16F3D79B2CB18F91B
-:1058400047867010A229EFD1E3029E1F8CD71B0060
-:1058500077D30A2E37C82F2EF2374F988CBFDBAB89
-:10586000CA26B92E99CCFF9F27F7A9792ADFBFC195
-:1058700098EF1F7E7F66629C6F1DC63BA7BD3716E3
-:105880000FDFFE6F739FF9233F90727974B4FE208F
-:10589000DAAB730F4A2F7CBBE8B334FA9D91AF8E1D
-:1058A000D0EF29CE75FA9AB18E22B3441CE00F29AD
-:1058B0001D744EE30F73FE9A467EE4D5E2DECF2BD5
-:1058C00085F3F273B4820F562D107986A9AC9EF839
-:1058D00036B9F77C6624E0F8FFED1C6DEF39D7C9C7
-:1058E000A34E51BE858F7EA7229C1EE3230EBFE8E8
-:1058F000E216CA1B233F9945E74EE30EAF72F3FA57
-:105900003B3FFD54D4530F5F74E35CEA4F3F9B452C
-:10591000E74CF30E5FC439D4DFFCF4B4787F0DA3F9
-:1059200038D6FB3FFD7C16CE9DDADDFA07A0EBCC26
-:105930004BF5AF615BFD60CDAD0BDC748E725A5AD6
-:10594000AE3847F916E8392369FEBA38ADF71C6559
-:10595000F748DF07787EE14BC1E76EC4C006FEEB77
-:10596000A53A47AAE46C7FF250ADB77FD73958B556
-:105970007ED94ECF462B98D0FF2F9F4FED12FB992B
-:10598000F17CEA6BAFFED685BCC3F1A3EDC4CFE3D7
-:105990001DED2EF80550875CDCFEA538CF87769686
-:1059A000D07603C439BEF1384F01FF41B73867F8EC
-:1059B000DAAB6FA440DE8FAFB7519ECF16F9BB00B4
-:1059C00031A643668CF37F00B1492F16008000009A
-:1059D000000000001F8B080000000000000BB53C19
-:1059E0000B5894D795F79F7F9E30C08008288A3F38
-:1059F000820413A433BC345BDB8E0A14A54D31DD65
-:105A0000A41A098E9120AF01D4B671B7C9C7188CFA
-:105A1000519B74756312638C1950D434B83B463073
-:105A2000A0D84C4CA4C63C96B05BE2B7DBF86162F0
-:105A30008CAF0C48926EFCD6D63DE7DCFB330F20D2
-:105A400026ED2E7EEDCDB9EF7BDEE7DCFB4FC430DB
-:105A5000634D1263530C8C19B3188BD733668A616C
-:105A6000EC591DC050EE1D665E4D246353631A56FB
-:105A7000B31C28CBCCD6A664067F6EC672194B9C8D
-:105A8000E09D6484FAC4B57AAA8FD0F4290D66C665
-:105A90007C8DDE45E75319CB0F8BCC64DF8152CF71
-:105AA000D2B5D08F69C2ACADB05E817CA32711E0C6
-:105AB000355D920D9666F986925D2C85B13A2D0082
-:105AC000B1F83F93BB15D7D1F656ED877E7D71892E
-:105AD000D62D004E4938C252B3617C7D51069BCE13
-:105AE000D8098B638A7522B4B3AD128E0FCFE0E371
-:105AF0007F5A14DE22C3F8C1E3B7E53AA0EE6E8305
-:105B0000D2C1AC8CA578A29768EF04384AC9952C0D
-:105B1000005B63976827011CAF7448D06E74452FF3
-:105B2000C99F84E7335ACEA733F63326B12899B1FB
-:105B300064AD231DD771167DA6671A6C1FD297CC52
-:105B4000622CC36A213C4C3C0178827D0E2D8C7006
-:105B5000B7C0F95886928BED49BAA1480BE063F0C3
-:105B600086B6C86DA671917F0FF537F1EF078CED02
-:105B7000EE96A95E85D5D267854960BDFA54F313C8
-:105B800088BFBA04A391CAEE6B850CE7D196A4DE58
-:105B90000DF3D8F56C7949C6E8F103560DED2B7974
-:105BA00023107432AECBEC4C81FF0B632AEC627392
-:105BB000186BFE2554FC1D6F879330FD0C8D806D96
-:105BC0003BF25383FADBB1BFBF9DD98DCC3FFE7E44
-:105BD000EB8C1D1BB4623DA4730573CF802324B2EC
-:105BE000068901FE129897E8B3DB1643FBA23FA09B
-:105BF000D30BB1A6E62DD02F55662E531695CC02A9
-:105C0000656238AC07ED89AF99DCC8577B4DD00E83
-:105C1000435335BCDCABE1FDF561CC857C3A1560C6
-:105C200006E5319BA3CE3691E6F1D23CF2211BF280
-:105C3000E324E6A1F5E3998BF6A3F69BC27A4D081F
-:105C400033ED501AD26BAEAC19139F3ADBBCF5485A
-:105C50007F5FA39D7DA20DA05378E4BA40FAD5E101
-:105C60007873E0B8F9344E1DEF5CA7619F4CC0C358
-:105C70007B897F9CA91ABB3B03C7B137A52CACEF2E
-:105C8000D59744F8C7F5371AD9274087FF68645479
-:105C90009E69B4D0FAFFD99840E51F1B15AA3FDBD7
-:105CA000984EE540A395EA3F6A9C43E5BDCB22723E
-:105CB00090FFEB3BE7B14F8C1CED37E17F4E8FCE71
-:105CC000311000F7CF1B9B8FF60B3EEA4F1EBBDD5A
-:105CD0008BEDB8CFEF737A0E3EC8DC2DC9C4971B8D
-:105CE0002C31A3E90FE733E1F90623D8120FE0E9DD
-:105CF000588E44F30F4EE270B35547F3D9356C0715
-:105D00008E3F96A3E7F34FD75462BB3D86CFDB9F10
-:105D10000630ECA768CEBC17114FF638A8CFF2C3F7
-:105D2000FDB7F376FB645EAFEE576DAFB359685EB7
-:105D300095EE833A583F83F89DE657FB7F96C7E57B
-:105D400030B4BF3B5553E41E031F1A1BEF4F7201C3
-:105D5000F870A11C2407C8459D4272A1F2A1CA7F18
-:105D6000BB6D1C8FA906C1E7E12007312407342E43
-:105D7000311EE44022BCD8199C67AF24E425541E90
-:105D8000A0443DAECA832A072ABF27829C4931FE20
-:105D9000737C2F845FD5F29495D3A5372EE21744F8
-:105DA000D76E9D055421F40742C6207C4F8E1DC638
-:105DB000153C6E6E184B7FDDB4FE8D7850F5C13802
-:105DC0007818757E3D2FBFEDF949BFA1DE46BE1D97
-:105DD000435F7D6655F515E75B9DCDFEA915F95529
-:105DE0003269A528284D9C6F42CF7F2C87CB8DCA66
-:105DF0003FBB6D8CDB4B3C67CA687DA79E67E49C0C
-:105E0000AB18E9BDD4305E1F4A5FF55C017AEFCF75
-:105E1000B82F159F8C796C1698674AADD9BA25D9D9
-:105E2000CFBFBE89D72BD07E6DB62AB49FE735325F
-:105E3000D15FB52723F592BC7C7146909D6116A079
-:105E4000E3D07103C9B757C32A5F8171ADB8D49D40
-:105E5000FE73CF16F41B5E3243B30EF6E5FB93D907
-:105E60008576CB3779E8AC04E37D3B74CC45FE8383
-:105E7000FD47521C630F824D41BB7415F41C4B63EC
-:105E80004C7EEECBB312ECBBE239991900753E5053
-:105E9000DB328CAB7F3AC26DE4E3188371B5625C90
-:105EA000D38ECFEF45FEBA00FC6980F64F4C75D318
-:105EB0005926630B9ED3111E2B22F46EAC7F63C751
-:105EC00053A796017CA15D52D0DF2894CDD45EFD0E
-:105ED00092ECC6756ACD859724F0737CEDCDCF84A6
-:105EE00041BDF3808E99605C61BB64F5C2FCAB3C44
-:105EF00011881956B15DF7D140BA5F6FFE50D8B125
-:105F0000CABD921B388655EE0A6EAFDE1B0CD73227
-:105F1000AD1F86F9B36C11B117EE006026B3DD44F6
-:105F2000BA6D8F416335A2B743F90ACD36E9C7355B
-:105F30005C1F33F645DCDDC097F2F12F933E3273E0
-:105F400078B180CF01FCD9971CFF2ADEEA84CEFF0E
-:105F50006C12CBF1C039EB8E9B2C2E38585D974CD0
-:105F6000E7F079A208CFF5610377919C1E952DE8A3
-:105F7000876DEE945DD8EEEC36EDD1C039EB3A2466
-:105F8000A645B8D3E0E678BA5681EDAB3A4D160592
-:105F9000DB8F1A980CE37D403713D271EA00D11FD2
-:105FA000E9EA92680B3F92F2FCF497915EB17E7A37
-:105FB00035EDE0FBB97080D3A7507E584BF46A965C
-:105FC000587C009D7FAF7979845ED86FC1737FE87C
-:105FD000413A57C0FE0C0AD25D263A5F00FAE0BC97
-:105FE000FAE39F240D98FDF49681DEBF52C743FF6C
-:105FF00055B7A07725736D447FEEDBD2395CC83F7F
-:10600000F8BD179E47BF37426F453E8C15FEF1C461
-:106010009AFE93B1B06059CC15E76AA89F91F00A37
-:106020004B053F418A763C6483716717BEFB18922B
-:10603000A36FD1CB36E48B26DD40EBB350E18A0E63
-:10604000B7A20C0E262FDEF52AAC931F733DE91084
-:10605000CACBEF0C1664A726218FF86704FA3B1908
-:10606000C737D0F11C9EDFD96DF01A008FACBDC0D0
-:106070003EE20F4C477BECD1A39E2AD00F95AD4654
-:106080007F1CE6C37524602394EB9AEEDF9F91603A
-:106090009CA4C4B252848D66AF8CF3B4E9AE8E9CDE
-:1060A0001BE6912CEF52BF5DB6E9B48F94F8EF294F
-:1060B000A87F9A96324758CAD7E979467AFE059D55
-:1060C000D0EFE3F97FE3E87BD5EF63AE29D117602A
-:1060D0004EC405971FAE7756CD61E24FC885802B21
-:1060E000D7BB228DD079D51DD6043CFFA7C86791B8
-:1060F000C87FEF6827C0BE6A5B25A25B1DF20F9CBC
-:10610000EB24DA37A81FF4083DF2526FFE84582CB6
-:10611000252B482AABEA96AD5E68AFEAE4FC348AE8
-:106120006F84FEA86EE3FA63141FB5011CE0A7D5C7
-:10613000215FA930D0FBA85F7FCCBA09FB7D713607
-:1061400013F4E67AA240CE881A007E19664A942596
-:1061500023C06E49DCDF52F5CA6D3B40D507AC3B2E
-:10616000D36D64DA8075EF3860098267791282FA3C
-:106170007FA753096AB779D383DAB34F5983E0DC39
-:10618000DE3941FD679FB107C1770E1405F5FFEEBB
-:10619000C59220783803CE3396DF21CA1F264841A6
-:1061A000FD172AA6A0F98BD3A383E061B3C08FF0BB
-:1061B0000355FFF4A28DFB41A1A58ADF1F5B83D7A6
-:1061C00051E3E29FCC095E6FB13D78BD6F4A977D88
-:1061D000E0F76BC1AF3F00F611CBDF82FFAF05BF29
-:1061E000BE0DFC7F84FF05FC7F2C3DE0FF63FD2B93
-:1061F000E0FF23DC0EFE3FC247205E41B8B3B1880A
-:10620000CAA38D25547F2BFCF588754F89754F8B5C
-:1062100075FF5A3CA9A5B36886E62B90D3793197D0
-:10622000F4A887ED6B060A310F30F496CC5A504033
-:106230001CEE538DB1688F2630F45B58C9D0DB1A41
-:10624000843B522C5B14B443FFFE1EB6FBDA65059B
-:10625000F5F989CE8F23719EAB5F811C66E3B88F01
-:1062600023313EAEBDCE08DE02ED0AC00B0F8162C7
-:10627000207F06F41AF64F5561B79E4159D27648F1
-:106280008FF4A8397088DADFF2E882DB0F3407B5C3
-:106290005BB03F94355A37C5F7973BD5F9BCD4BFAF
-:1062A0003655B2A35F7CF9C0BFC75560BFB6F7E3F0
-:1062B000567E0DBE3F3BF27206EA7527D861AFD914
-:1062C0003F8FB34B2760BEEFDAD44385316808DADD
-:1062D0002436038AAB6C2B5B07FAAEA6B3B516F572
-:1062E000504DFA321D4B267D24F20DA06DD15FC2B8
-:1062F000E01EF077D5F379E44A98F735CFC9BBECC7
-:1063000048BFEE372271DDC17639289E5994C5FD0C
-:10631000D645597AA2E3D5F637221568DFEC7983A2
-:10632000E35BEBA5739F10F0209484E74E99CE5D5C
-:10633000F59586F0AFCE774F964CF32DEC9C1181FE
-:10634000E7EAF3F0F596672934FFC2D415E5B8FF04
-:10635000D3094B7365F2F34031A35EBDBDB815F3AD
-:1063600003351ED93E56BCB55ACCDBA3E37CF856A8
-:10637000EAE19EC9C01FA78B26D848E78B7E5559F6
-:10638000DC1F2FD43B52D12EF4999508E4E3478BC0
-:10639000522290AE27B0C4FAA23D7A0794D5ED7C84
-:1063A000BD3E4B6F24F25B5F7BB68C7E8B3ADF4A3F
-:1063B000B1EE085F8FD0CD4574AA74379B711E3F34
-:1063C000FD78FDF22C9E2F3AED7EFF5EF453FAD25B
-:1063D000C3AD48971E3DA3F8B606E88AF6A0AF3BCA
-:1063E000B119F1A0AEB73C4BC4C9E91AA2ABAF5387
-:1063F00027FA2D6B6541FD78FC7C756FF07E2CEEE5
-:1064000073BF598676E905F0ABA1BA56D71087E776
-:10641000FF7457F0FE2A059E6B75DEB8B8007EAD9E
-:10642000ED1A911733F177972A1F0AD153A5635FAD
-:106430003AF7DBFA120C6E8C176B0FB5125F8FCE2A
-:10644000EFF426A39F9FF89091F286B78A67553F95
-:106450002020EE6118C7E98A527235D3FDF67ED04E
-:10646000667F3E6B22C6432514EFF5B1A10A34FEC8
-:106470004EF483A350EFFEF1195C77B81DFC3D5834
-:10648000D769EC5C741EFCAC612B080AEC7B789736
-:10649000CE2DE21333FAA715C23FFD5471E4C96053
-:1064A0005F9DEB3574BEDA8C30EED70A3DF9D9A189
-:1064B000E49F20BFD69E922D46F443216E21B88DD5
-:1064C000FB05759EE47F9A8BFE769B8EFC00D5EFD4
-:1064D000700ABFE382F0672FAC1FD293BF7A5C6271
-:1064E0004FC13E2A3BB7F52442BB336311F9AB4E93
-:1064F000B98DF28FAB7604FB0555EE60B8E64030FF
-:10650000EC0CF11BD4B8ED44D688FF3013E38F02B6
-:10651000796E3CCAC107829E6A3CB27696351EE50A
-:106520007DB35659A4E603104FF5C70F57E17EDD42
-:10653000B561568A0BD61D257C0E7EC1E38EC10443
-:10654000C6FD23C6F13AD8C9F9BB5E27F13803D896
-:1065500095E6334AEEF5D034E81A8E24BDC45811BE
-:10656000CAC39AA53C8EB463CE15CA17845E0AB519
-:1065700097DFD70EC8D101FAE17C16F737F3F5CCD7
-:1065800081766A6D8495ECD63423F7B70B1EF6D866
-:10659000900FA6417C6C08C8674F330F49D86FEF46
-:1065A0002310E266FAE3FBC55A8B2E3AC0EE31B6F1
-:1065B0009EFAABF38326E1E36F35BF05E637FBE7D1
-:1065C000077C4721BE3FCFB1923D4E5ACC582FC9D0
-:1065D0006303C9A37A9EABC067988FC59C09D2ADEF
-:1065E00076D7EB940776B25E8A470A23F93E0A71A2
-:1065F0003F0887F19265737CD9B3B9FE589B1D6C37
-:1066000097BBB2ED5236943BB21DBA6CD26716E21C
-:10661000CBB58257C04F891F1843EFAE7997C75546
-:106620009F831CA09CDFDF2029A9417E10E7EF7A21
-:106630005EC5AE304FFF5CC483CBDE9B1E877114FA
-:1066400097ABE5EB4C4A6A009FD6239F035E2A2D49
-:10665000553F42BFDBB12E4EC17C7F3DF2FD7444FD
-:1066600023E7EB58F887F1C5283EF704C3F0B70BD2
-:10667000F9AB8E19AC6847EA3B43DBAD5ACCEBA4CF
-:1066800064831C84FBE52049F065B34372A3DE6F8D
-:10669000BEA1E579AC5289F256F74025F225FD619D
-:1066A000BFCA796E9CFF1E00311E62DB63496EA873
-:1066B00011F4C8DF8BF3DEA3F5BE8E727C52E7497E
-:1066C000C67CCA49A7D18AF32F65E070807E296510
-:1066D000BD54F687D775786972D7548C9B3F701874
-:1066E000288FD3BCA12502F56926DB60B9908EC640
-:1066F0009D1DB8993DBE5F018CC42EA874A1BCD06D
-:1067000056118772BAEEC8B6CFCBCE1D7F7CCD1F97
-:106710003AEEC290A2E617ADFA78CE36BDE9797EA0
-:10672000FAD5334F3AEE57A5D708FD60CF53000F87
-:106730004BD8501EC6352ADD8CF06F2CBAA9F84C08
-:10674000D20DFD1451067689F44B283D55FCD6B187
-:10675000061DCF7335BCB714FADFB741A3A07F384D
-:106760008ABEB7A083D7C49BBC1112C59BE3D14599
-:10677000A5874A9F33D17CDC99FB65CAD3FD5FD3E3
-:10678000A52BDBF1D0D7C963A8FC8D276FCBD785AC
-:10679000C86588FCA9F472AC8B243953E958AB3036
-:1067A0008A5B6BBB23AC6EE6A79F19FE21FDF09EB2
-:1067B00082F231ED12DB297D13391CA07B8D50FA5A
-:1067C000006FD851AF3F951D6C8754BA8DA77F5489
-:1067D000FDF521F39EB448743FC0E5F3970637DE1C
-:1067E0002FAAF703EA3DC061A1F742CB0FC1EFC06A
-:1067F0007B972DE97D13D15FEBD7ABF3F0FBC70F90
-:10680000D7F74E5D0DE33F9CC7CB7EF4D302607B90
-:1068100018CFC37D38C9E042BC7D28CD9C8F76FC63
-:1068200043E9A1BB381CAF57105E1A3FDF0270BFAF
-:106830004ECDDB3D2AF4B09BEF63E9EC7CEA27B157
-:1068400037111F8AC44A681D498A2982FD7CF88B4A
-:1068500019594DCC7FFE966CEECFBA55FDAEE6B120
-:10686000FF41A23CF672300116CCB7CF7FB6683A32
-:10687000D49FFDC7141BDDFFAD095E1FED6832E537
-:1068800007B7D13CDFFF6A48B722C3BFAF11FB9700
-:106890007F8DD797CFA078A252D0D01E3393C7B1A7
-:1068A000EE9428B447AA7D1A3E75D81C98BFBC0444
-:1068B000F68BE903E0994F2605DAB7D7F7FD3A0DD5
-:1068C000E7A9D4BB32AD184F363F9F847E40E5BE6A
-:1068D000C7D3C82FDDB7390DE38BCA965FA7D90997
-:1068E0000E77507CA3E5E7BE72F0CE3D5B02FCE084
-:1068F000EA5C99F65F6A7CBD00FDD345777CF618AB
-:10690000E6C367FCA34479B1FB59EF636837CBD288
-:10691000B91CB1ED46D2EB301FDD3BB6CEFCF15ECB
-:10692000D4E7A7D33FD69543BFEBD95AC24F1973CB
-:106930003F118FF9B04D12E5C3FCFDA7D23DE68AA9
-:106940000D923E2116ED61B44D56705C34EDE3813D
-:106950004DB61EAC2F7B98D72F32B8DBFB709E67ED
-:10696000F5D65605272A995E12702F7C3D9BC75D90
-:10697000CB9F90C81F57D799F14C5C73E039AF0B90
-:10698000FAB31BFF46FAED27822E3F7AF8FD371344
-:1069900014BC4F72DC443DF2DED31752517FE5C781
-:1069A0005CCA403E9FA177ECACC273B718287F98B1
-:1069B000939928C743FFAC9FCF7B0ACBE50FAFD895
-:1069C000598579D01D468AA3D4FDAD91140DC69B7F
-:1069D0006F34FFEC01C4DBC5A78DE447AF69BE2D62
-:1069E0009E8D21A76AB91FE8AFA431F652A391CAC0
-:1069F000971B2D4C81231E6C4C20F85F1B152AD948
-:106A000012CE5F6B44BC3ADE7CD910EF2BA0AF7284
-:106A100036C17CE06FDA4CF6C93980AF19B73B5B01
-:106A2000368B73CD80F13657F202C443CEE6D53DA6
-:106A3000E88AEA73787CF476DFA624F2A31F3EB7D7
-:106A4000BB0ADA17E794A4E078E3AE6B14E7BFD192
-:106A5000F57819E5F55B0CFC7CE2DC179F4E8BDFCB
-:106A60008979D7B774147FD7EF3AB77B33942B9FCC
-:106A700058AD0FE4F76F7ADE64B19F5BC9D57878C3
-:106A8000F8F672F5EB24929F1690AB8CBF5EAEEADF
-:106A90001F5E4FF87B28A764510EECFFA2CE9584B1
-:106AA000F27471E6F788CF5DC725C2BFAAC7D5F1DA
-:106AB00045E2BC351ACF13E40F0A3DFE25447E881B
-:106AC000DFD7BB3E4D437FF8CBCEA55F7BEE238D5A
-:106AD00078838E792D2395A1ED797A478A15CE9703
-:106AE000A7E17EF028FF55DCCFA9F7EDF88779E123
-:106AF0005A613F9DB0B1A818B47F92372C13EF397B
-:106B00007E78498BF117C4751F05FB97ECA3003BFA
-:106B10003EDE7E6F55D6E13C5ABFDE9D7D46C3BC4E
-:106B20000176FBCE8130E60D587724EE30224F43BC
-:106B30001CDA3589F402D20DEF657C5D335B10BE43
-:106B4000A4E774F41D81F88AE755989CE73FE7A510
-:106B5000AE2B99A86743CF5B77F40AF1476DE7E363
-:106B6000D7243AFFC24BDACC5B9FFFF57D573291B9
-:106B70007E977403791847F9F403994887BA635CE0
-:106B80009F7F5B3CA8F5559BF43CBF2759281E2CE2
-:106B900090AF521CEF3BC5E3F8BAAE3DA44F87BBA4
-:106BA000793EA55ED35B188FF98786733DA8CF86A3
-:106BB00013787C05F3DB116F7353841DD40E252DE0
-:106BC00006BDF6CA083FF0B8EE22CAAF1EE7F1D400
-:106BD000D27BA4CC70867EC5659467A82F5B97BCDA
-:106BE00011F9FCA27B226682D8DB99FF5347F9B7E3
-:106BF000D7C22D32F9AD501B40BF9173B865FE70FE
-:106C000086A9717A38B307F4ABD72B3FA1F8F834D3
-:106C1000BF27ABBF9DCB133BCAE5C9B9E1757D4228
-:106C2000C07CBB519E68DFDC7F5CF4DAFF905C7651
-:106C3000DBECDD2897E1A80B71BE8428B724897EA0
-:106C400079FE7B4073B788C78B646AAFEF94D92411
-:106C50001C931041F7F5456CAB16FDDD45CC339721
-:106C6000BF9319F8CD77A1BDF835391BDF6381FFDC
-:106C70004CF7C785618ED435E81F692481574FCE04
-:106C8000E2407B26DE79CC9525B2634393C2C94F9F
-:106C900059B8C4598AFB1DD10F5ADE0FE6213F8B2C
-:106CA000B98732F13E93798732F19E53ED77EF6BDE
-:106CB000E10D64179927E7DE8075C272B9DDFC1C0F
-:106CC000EF9F419FD48BFBCF02F9C6331847AD39F4
-:106CD000CEEF09FB35C91FE07B2D17E019E97A05D6
-:106CE000E86A47FBE360763BCACFAC896E949FFAB3
-:106CF0008312C3776B755D8616CCEBD4E906E29000
-:106D00009F3777FE418FFC5CDFF1BE5E9985E379AA
-:106D10001E08FC750DE2B75ED82F67E76D1F60DEB9
-:106D2000CD798A5B51A7F67D8AEB6BDA0F51FC5E59
-:106D3000CBBC14BFD7B605F3CB7002CFB387CA471D
-:106D400058AE42FA528517EEE07271AFCC1A28DEC7
-:106D50001779D38509F1E48FF8C7093F51BEF218BE
-:106D6000FA2F83D325AB04530D86B936A05FE44ACE
-:106D7000E3FECCE0EF5ECEA920BDE2CEF929BE8BCA
-:106D800011FEEEC24DDBB472C07E1676F33CE160BC
-:106D900018AB3C42F4764C413A446695987373497B
-:106DA000AE32E99D8F86E73543CFF1A4C8679EC612
-:106DB0003C4F867FDFC589895C8F3137F14F8F86E5
-:106DC000AFAFBE7B51C7AFC89582E2A53512CF4F9A
-:106DD0008DA757F01EA55CDCA3948B7B9472718FFA
-:106DE000522EEE51CAC53D4AB9B8472917F728E5D2
-:106DF000E21EA55CDCA3948B7B14AC3F8D5BA5F7F6
-:106E000070CFEF44FBD9833236D90FF7C784C093D4
-:106E100083FBF7C748C1F06489FAE7E43EBFD39526
-:106E200081794C8B906F2502FDAF8B269E5FEA8A9D
-:106E300070FC1DE2B97C61D33EFE1ED14EEF59F2CB
-:106E4000639696A27C0DC71A18EAA1865CC7BC5C43
-:106E5000A0FBA9530B52B7917E3459F19EBBFFBEE4
-:106E60003BA2282FF796CC6458725E7AF6861C8077
-:106E7000E79925E25BD013DF2951E3499867413751
-:106E8000BFCF28906BCB71FE35934CD9A87787B2D2
-:106E90001CC5B901FC583879552AFA413D3AE50339
-:106EA000CCA7BADED5318CA3D4FC9BDAAF276BDE3E
-:106EB000521CB7303D654316EA1B102ED46F763D49
-:106EC0006BC37DD935E15213E92B458BF2BF54F0EA
-:106ED000EF7C85FBC35EBDA28DC1B83D6C5EAC4B43
-:106EE000E1F755E5E2BEAA5CDC57217DDEC1BC19A5
-:106EF00094EF413D96BD508F65E87BAE67724A5670
-:106F0000E652BC3D9414F81E6C11CA15D73349C81B
-:106F1000CF3B05DF26083DD3935D524DFCCE3C347C
-:106F20004F8DC8BF5DD105DFE3A9E3FCE319957779
-:106F30007F87EB6716A5E7EF5DA73017BEA7BDFB00
-:106F4000D549944FF2B9352E5D14C020E3A8BFD8BF
-:106F5000AB3CBE65095C5EEE3E1C4FFD9A441ED400
-:106F600019D39B16837657C8950A1FF90B7FE7E361
-:106F7000CC0218CA63123F9FF3EEDEB468807D92A4
-:106F80004983F971670B6FEF1372E79C2EE613E7E5
-:106F900061464F12D263F0F8AB490F00BCC5ECADAF
-:106FA000E0FADE9B467A9A79D3F0BDD015C9731604
-:106FB000DFDBAE3A92B50CDFD75ED17976235C7316
-:106FC0002487C3D2A1B396C0F6899E247C8FBBEAE6
-:106FD00048F6327C9F7B65E2A1DDD1D60058F7CA26
-:106FE000596CD73F9AB32C1FE06283FB5423F2CD38
-:106FF000BF72FE321DECB880F8A9E9E2FEFAFC830C
-:107000001D575F417BDC1141F7F507729389DE4D17
-:107010005DFB9F407EF31DD2911C6C69FBC3EE5F4C
-:10702000513F03A5518A0D9E1C4CB934E4FDC77D28
-:10703000B86E71B8E70B84D7E7FD80F6513C81CB81
-:10704000F3C6BCF9CB503E7D1D077F89F2571C0566
-:107050008E2CEEE76513D1A7FAF0CC7CCC03F82296
-:107060007ACB70FEBADF1AACC8A7D587E3E7635EB8
-:10707000A02397E7A7AB6EDF9A84F65573F4A57D3E
-:10708000BFC23CE56F4D743F531FC3FDBB6AB939A6
-:107090006F35D16FCF3E7C37E27BC944F7A45530C2
-:1070A00007AE57B56F06E5D58FFDF9E332A44381EE
-:1070B000BC6B1FD67FB1D7A4413CF4E9ED51DF434F
-:1070C00039ECD3519C5925E0AAFE097C3FE10385A8
-:1070D00044BFD8AD49685FAB27FCC35DB8EF6279A8
-:1070E000EB6E8C73D87E03DD155C7A09F006E32E17
-:1070F000B5EAE895AAEFA5082DF2CB15696BD94E34
-:107100009CBF95F7BB62DA4AF874B5DEC6703DE8FD
-:10711000C7505F5D91B605D55F6ADD9F8971E8E56F
-:10712000DF16533CAAF2F9489CB1D710640F4913FB
-:10713000C489F71264665DCC0C76B64A80978F3CA2
-:10714000E7DBC9FCE32FB7E9BC7AC05195816DC07C
-:10715000F7C1AA3C5427FEB008CF57AD694E437F14
-:10716000A52A7BA00CE5E292891913A0DFDBC25EA1
-:1071700055B7AF5F8C7EEF78FBF98BB03F5F0A3974
-:10718000FCB2D3E40EBC1F0C2DFFD8C8947702DEEE
-:107190000DDFDF6020DF5D9DEF6DBDA716E3B3BAA5
-:1071A00018AE3FCE42FF36D0633784DE5BBE2EB8CA
-:1071B000FFB5DC18FE2E553F9086764F9DDF97ABCE
-:1071C000EAB58134D457A1E38A65A16F5E9648DFA2
-:1071D00054B74BE764C053B5D1E5C6F73BD5184C5F
-:1071E000F2736A6F4A7C5C429EC03B8C7D3C2F9957
-:1071F000CE5DDD66B29B605C4DD84024FA43B5118C
-:107200000391E8E7F88ECAAC45902B364ED067BAAA
-:10721000205940DEB1CAA3B39B32C7A033FA4DF860
-:107220003E07FF1BD6DF95379DD6ABEC0CA7F59834
-:1072300065200FF9B47257F0383C972540FE7C9DCD
-:107240007BE202E3F164B1EF41E91CC9C9E09F3F71
-:107250004A42BA576BD806BC47BC2CF1EF1E00A6B9
-:10726000EF1E2E8BFBC8EA3F99C3905F2E7F594BD0
-:1072700072EB930648AFBD7BA484F4814F37407A0C
-:10728000ED44DEBDA4C77CD10365A8A7DE3D52C195
-:10729000DB270D9429D0DE8630B64F6564EFFF2BD7
-:1072A000CF49FAA358E6EF1BD81E9D85E78136F536
-:1072B00037525CA15302E3EE3FE6A9F7367AFFB9F5
-:1072C00065BFDCF89872B01DE5B0D24CF91CF09F98
-:1072D000DA5E413F6F699C15F3E295388EF3813E8B
-:1072E000F0FE2F36E67A05D2675994A3202F17EFC8
-:1072F0001907287E00AE263FBDEE77068A23077564
-:1073000043FB504F65463916E6017FD5EA7B37A22D
-:107310004B7F5537D083F77E8B64AE8FD87ECE57A8
-:10732000BE8C3DFC3B09717FB854E01FEC166B46E8
-:10733000BE90387DDFE83CFC0EEA155F6F0AE9E39A
-:1073400050B9B9D4F95424EA873360C75D0171FE9E
-:107350009915FBE99E7E09BECB80F2810DC1FC3000
-:107360007CE3A714EFB12702EA910FB707C3A17C12
-:1073700084FCE80DD23B2E92A76773B91F5633BF2A
-:10738000B70EF13002DF0DB01C009F088143FAB345
-:1073900012EE273C8BFF8D789CEAEDA7F8FC207F4E
-:1073A00017DB04F68BE08E70BA37D61C04FB14CBC7
-:1073B000ED13DA859AC85ECA4BF93A0C743FF2684D
-:1073C000D7A7F49E11F890F22F355DAFC661DC7E31
-:1073D00000E3845CB28371F44EA5A32B0EE30DB5DC
-:1073E000BE56E34913EFF1C94F57EB9DB2370DF786
-:1073F0005F23F56662FB01B1EF5A0DC032C262DF56
-:10740000129777D625933E0FA5DB0EC1AFA017329A
-:10741000E99DC5519E1750F54095D02727B03E8372
-:10742000CBBD45BD5792F0BD5CF898FA213E4FE8C0
-:1074300037D640799BED797CDFEA789A97E795A873
-:10744000BDEED895CCE919384E19790739A2875283
-:10745000FC7A05E53F81E4FF515D1C9CAB7AB76483
-:107460006D423D55BABE10BAB355DAD585942F1387
-:10747000EF3F43F715CA4756D80BE9494D74416CA5
-:10748000C07C97215C4FC8223D43EFE81F8C7DB242
-:1074900010F3133F2BDD46FC3C626F02E51CCFB3BB
-:1074A0008BEB71149B9B9AD17CBCAAA17963FC18CD
-:1074B000FB08DD6795A3B9304E195DAFEEF7B24911
-:1074C000DDDF7CDDC4403C2C595F3811CA55C6BF96
-:1074D000160FFCBC97BB0C5EB4AB55A5AB37468D05
-:1074E000C137A3ECC1AE00FB351DE9EBA67B8DF1E6
-:1074F000F61F5AD64ADE7ECC133190AB56922F90AF
-:107500009700BB30272F24DF50B9621AC69DCCB13B
-:10751000621ADA1990AB32EB1871257E59A2A1B725
-:107520001B2E2A43F7733E8FE749E7E47179E9B6EA
-:10753000D97DA837C7FBDEE2BFC53EC6FBDE2251C0
-:1075400033FC1ECA5B625C8482F740050BC279BFC4
-:10755000E3260BE66D068F5FA7BCEEE063E625FC35
-:10756000BEC0CC26417B4FC2AC96403BB275365F65
-:10757000273C87FB2DF5E9BAAFCF0B65448CE4853A
-:10758000C86FC808A77B125FE7E764B706BB732D17
-:10759000789FE1EB85E810E4A9FECFFF1D87F6D5C3
-:1075A000D7FD09BD07F3DDF894DE896D16EFF44EC3
-:1075B000748A7756BD4A047D1757F47121F6DB2291
-:1075C0004A7F7E80E789D5528DFF03E2DFC9B3C7CA
-:1075D0008E7F631CE6C0BC80123F561E25302F9064
-:1075E000AAE579012C312F909ACAF30208635E0054
-:1075F0004BCC0B603DE60510C6BC00C29817401886
-:10760000F30258625E00EBBF10DF3F0C8262E2F9CA
-:107610004A33E9F5B5F8BE1DF0B7F638BF775ADB47
-:107620002AD3FD2D7EFF80F66DD4BB9976F16EC610
-:10763000B38DEEF1EA3B642B92A85E377412F338F7
-:10764000F58724EB7AD42B8D4B68FDCDDDB91F94E3
-:10765000627DABCEAA51888F381D9B257AA75FDD4E
-:10766000DD4A79A7FCF8E37AAA6F9318E649EF356B
-:10767000F038D729436D16DD83921FEC34F452FCA9
-:1076800051734052CA03DF69CCB9467A40BD4FAE50
-:10769000E04DCCE93129E563BC031979772EDE4D45
-:1076A00057E03D33BE17976FD0BB7E2704A41390DD
-:1076B0000F77F0F7CF16F847F21EF2AEA9BAFBD05B
-:1076C000467C0F157ADF3CF23D5DC8BD73D96C7105
-:1076D000AF6CE3DF57143D5D7EB003D61BDE6A203E
-:1076E0007FA321D7F120F2D1499D9DF223278F9BC3
-:1076F000282E3ABFEDB6A0FCC85096A37A36E59B7B
-:10770000A650BE628D4E227BBCA028251EF1B8E09B
-:10771000948EEC4E4F56492DF65B334BA17C548131
-:1077200081FD82E611EFA5547A1434496E0DC02B09
-:107730009895DED92F073461BE725067DE84EF9AC8
-:107740009633FECE41E59B35DB24E21B4C10203EF8
-:10775000CB043E9777FFFE3ABE635869E07E6BA28A
-:1077600086DF5F276EE1EF191E640E3DDAD955C83A
-:107770005D32D9C7DF0D40BD237C4A12F7CB957827
-:107780009C7FC5691DBDB72D88FF719A83EC743E3F
-:10779000BD6390BCCBE49B778C2F3FA1EF184EEAE2
-:1077A000B85E013C523CD4837C4979190795A71BEC
-:1077B0002BA9AC13DF438C7EFF3F7416E3C4C4F8DF
-:1077C000082BEAB971BF770BFBFAEFBD768AF76B2E
-:1077D000899ABE6C05F1F127B315F1A1BE13ECB681
-:1077E0009534239DEC91CC65A1EFC14003025E0B63
-:1077F000F12012E6B53D76FCEE68E8B864A177C9E1
-:10780000A3F4E3B6C7F09D487DAA649114CC7F6FC2
-:107810002D88837D174E4FA67DD777F2FC286128EF
-:107820000EF3E79C5E91598EC3B373FDF5C5426EAE
-:107830007CD09FF3C977DDC86FDF206FBA17FBBB21
-:107840009889BEA7A63FD84FF11D53297FAAF2CD34
-:10785000705B7C0BF2CDEF67F338B2B4F47D1DDAC8
-:10786000FF9E6CC709DC4759F9B5C7E2E87C63E7BE
-:10787000AFD477EAA1F9AB40FDF9FFF13EFD9DC61B
-:10788000062ADF6B5C47656FA38BDA03F4FF7F8EFC
-:10789000A3FF43F39FE7B05F68FE93199528B29F5B
-:1078A00020DF3CDF1C92EF2C9AF0C026C0DF82ED77
-:1078B0007A2B56A9F94F7C3FBCD64CFAE0F2EC315A
-:1078C000F39E2ADECC94271D66A62CC4FFFCF4147C
-:1078D000AD06DABF107450F38E281F783E940F2C3B
-:1078E000513EB45ABF7CBCA00711CEE176DE45768E
-:1078F000DE4474DDB81EF407C02B9925487F5C0D6B
-:10790000D11F1070DC47DF55751B18E609D5779439
-:10791000F3A1F82A6B0C7DE2E1FA646A98E725FA94
-:10792000DEBF2E8CDEE79E14EFE14E6EE6EFE1CA7D
-:107930005909AD3B865E89447AAC9C3074F679E88F
-:10794000BFF2D766F257364EAAC8FB5BF4CAE06CAA
-:107950008E8F67F17705B45FF7BB024F48781FBA87
-:10796000E67E66433AABBF2B102FEEB3BFC5EF0ADE
-:10797000DC3667E237FF5D81CC39F1A581BF2B9002
-:10798000D93989C3EAEF0AB0F8D2717E57207B4E0D
-:10799000EEE8DF15983D87C739E3FDAE00F8937335
-:1079A000707F3A9BFD4E2C13C53E43BFA73D2DEE85
-:1079B000EF7A348E522C0B235D5AAAD7B873B07C61
-:1079C0005BE3F939D6033FE7E33E0A9FB2DD9E0E43
-:1079D00070A2C1437AB227CB5E80F583367B21AE9D
-:1079E000139A3747DA627C0FFB5984EDA1EFAE544E
-:1079F0007AAE98C3F9FE0151CE6D1AFB7BF207E611
-:107A0000F0EFD56EB56FD8EF7DB82F75FF6CEB8AB0
-:107A10001C92A72CFB32B1DF522C993926E8FBD4FB
-:107A2000D17CE612FBE2FC05FAACF83CF707A94C66
-:107A3000D3BAA3D17F9CFC883B1AF73BB979C884A1
-:107A4000DF41BCE81A32A17D7FF1E12113D6BF6886
-:107A5000E7EF9543E77F710EFF4E206DEE108D9F8F
-:107A600006FFDD4BFEF95034FA4F6995E737D27DBA
-:107A7000CB8199645FA609FB32ED91E99D03C06F4C
-:107A8000D39E8BA2FB6C961F4BEDD5462EA7D58FB0
-:107A9000941FE950E8BBADE2F301FECE4C37EC3B5E
-:107AA000C8FFD20EF3779700239E0EE808469E4546
-:107AB000FFCAC9F8BBCBC9426FA09F560A7AC15909
-:107AC000F9E675BAF7C7F1381FDED122FF75EA86ED
-:107AD000C5F769168C43572D59DF4371E18E917AB2
-:107AE00011671EDA887133F86F41F5D5E5AFF7A05D
-:107AF000BDA939105CEF6CB846F12BF86F41F5F772
-:107B0000FFFC9C9EFF7E41703DD07707F29B4ADFD1
-:107B1000933ACF4C8CF34E3AC3ACFCFDBE877EAF9C
-:107B2000A4457CFFBCE79FE7E7F0F7A29CDE30DED0
-:107B3000FDCDF8A389FABBE6B37494875B95AA5E82
-:107B40001AF9FD133D73517E6F5104E99D7A115767
-:107B5000D5955BC8CE27D619497F15C8615684478D
-:107B60007EFFA448167ACA43F2DF775734E5F1E87E
-:107B70000008C7CCA27B9FB8260E0F4D34907E28FC
-:107B8000D094D4EE87F24D4DF077EC2FA07E90513B
-:107B90007E793EB55EEFE1DF896B955C8C739B244B
-:107BA000FB73F8DD639324F2885566BA2F18C4FC82
-:107BB000229C677BB4FBB90A5867FB3D19E41F0F91
-:107BC00032AE4F5D4BF8BDD5F6E892D2D5D8BEF4B3
-:107BD000766A3FF297942773D07FAA0AB3A2FFB4C4
-:107BE000DDC6FDEBED8BD3A9FD98A4ACC773BB1E1E
-:107BF00061B4CEF6C5FCDCDB9F9C2ABEBF709B50F7
-:107C00009EB737DB27E17DD47C8BE30CD26BB2B817
-:107C10008FDB9E0CF5503E23952C7D10E799C5F720
-:107C20005B6753885E2797DEFEE43E85CC8817EFBE
-:107C300085EA1745501CFCBF93011353F046000022
-:107C4000000000000000000005001500000000001A
-:00000001FF
diff --git a/firmware/bnx2x-e1-5.2.7.0.fw.ihex b/firmware/bnx2x-e1-5.2.7.0.fw.ihex
new file mode 100644
index 000000000000..a99c41c993b9
--- /dev/null
+++ b/firmware/bnx2x-e1-5.2.7.0.fw.ihex
@@ -0,0 +1,10178 @@
+:10000000000028B0000000600000068800002918E9
+:100010000000161400002FA800000098000045C042
+:10002000000073C400004660000000CC0000BA2845
+:10003000000099A00000BAF800000094000154A04C
+:10004000000057BC00015538000000B80001ACF8B2
+:100050000000CE2C0001ADB80000000400027BE8D7
+: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
+:100530000718040000960000081807600014022342
+:10054000071C000034C50000071C800034DB0D329E
+:10055000071D00000A1D1A69081D14405D78022558
+: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
+:100FE0000730040000CA00000830076800130282BE
+:100FF00007340000336100000734800037270CD924
+:10100000073500002F111AA30835708051F00284B3
+: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
+:101EC00008280768001302F4072C000035D300002F
+:101ED000072C80003A3E0D75072D00003B541C0571
+:101EE000072D800022BC2ADB082DC770471202F69E
+: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
+:103B9000000000000001000100070205CCCCCCC1F0
+: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
+:1045F000FD19A208F63B210606296106860841A09E
+:1046000079C208F1D3403576220C0C8C22107E2B17
+:1046100090E612A58EFB071AEF94C214DB26816088
+:10462000EFC2228F8C77A3C98B4AA2F2F710D03F3A
+:10463000D0F895222A5F5601429741C55FA3C9CBA6
+:1046400041E56F41FDF54611BBB9B7A1F2009CB43D
+:10465000B6A260030000000000000000000000009F
+:104660001F8B080000000000000BED7D0B7854D577
+:10467000B5F03E73CE9C9949662627214F1E6112E4
+:1046800020028638BC0228F73A212140A575A055A2
+:10469000D1A21D3040C85B8A5E5ADB2F130831025D
+:1046A000DAE08F8A16EDF0AAA8A80123450B7478EA
+:1046B0008A5E6F6FB06A69B5DE888A8A3C22AD4A2D
+:1046C000EF6D7FFFB5D6DE3B73CE6402D8AFF7FE49
+:1046D000F7BFDF1F3FBFC33E7B9FBDD75EAFBDD6D9
+:1046E000DA6BEFB1DB1C4CBF96B1AFF00F9EF53625
+:1046F000C65846ECF9A89D7D2FE866AC60BD6F8575
+:104700003B1DDEEFCEDB91EC632C67CF5A650ABC14
+:10471000CFD9D0A6CC2F8C7D1F7041E57878BF7B98
+:10472000AD5202EF735E6B53E6E1D361639DD09EA1
+:1047300069BE14864F16602C93B1211399F80BB8FB
+:10474000738A191B88FF842ECE1BC98C8D632C6F36
+:10475000A52D1256E07DA87226F332B619E0CA499B
+:1047600083EFD4BFECB763DB06ED44979331A7E644
+:10477000D4BECA672C770EB331780E5EC6DFE3DF96
+:1047800057F07F5ED85A1EC24CE53C2C7BD24FC2FC
+:1047900090CCC33C5FA989E0EDD683A362F394CFAC
+:1047A0000D8DBE4CB7D6FBBD7C2EB9E363FD1EF864
+:1047B000FA716C3794B1485CFBDAB0AEB1ABE0098A
+:1047C00008682FECFDFD4C56528C74B88D4DA167D6
+:1047D000BDE6BB09F1527FD4CEC200777DC3C9725A
+:1047E0002CB3DD0A1B96D7FBFB51CC4EF428618A13
+:1047F0007612E7EB655E9C9F5AE37BB81CF0DC9079
+:104800001C28C37E1F490ED153BECF9E3F3D3B04A3
+:10481000F0942E2A0C33A0FBF9F58ADF019F7FA4C8
+:1048200044743BD0A3FA3B0D45D3A0DD9B7AE83A14
+:10483000FC6E911A6DB1C3F8B5731B0A8002AC53BC
+:10484000E7FC337877C9271AD06D3063E19434A43C
+:104850000B63274C74C0BF13C34559ED1B8F977A68
+:1048600056603F1AF612A1F9CAF779E1A34386C64A
+:104870008DC78A091E867032D6A524A2EBE0174B9D
+:104880008E6A457D8FF79F3F8F309743C01DD2B70B
+:10489000D6A34796037E4B5FB047AF057AD46E54DC
+:1048A000220E28DBF6B902489FB35BA00C74897A0C
+:1048B000746A7FC67052B9DED179FF3550EE7E4101
+:1048C000659BB0DBE1493694BB930276360ECA8015
+:1048D0008F852E5EACDDB8FF36ECAF72B783B99032
+:1048E0009E2F2EFAD635505E04FC864D6AB736E907
+:1048F000FDA1BC38A2B463F9DC1446FC114ED323ED
+:104900005B61BC73DECECC1B405E4E353A990F40E6
+:1049100059E1E9CCFC0EF051556447397E57B55D3D
+:10492000F123DA4B5FD87A2407E7F524F015F0512C
+:10493000F5B664E693F883FF4FC254AE85FA25308E
+:104940004F94FF45ACAD9CA938FE5ADDE789E1EBF9
+:1049500054A341E3F4C8D393300E7C57F7ACE2C7BD
+:1049600029D6D95808E5EAEC8BAE399BDD38BF264D
+:10497000BDC083F3BA47C7768B22F376A1CAAA8A51
+:104980006CD4CBA1BE6AC3467D6121E20DF45E21E9
+:10499000C2D5CF0AD77A3580F85D92EADCA4027ED0
+:1049A000983B903D3B01FF9C6A043556102B57A164
+:1049B0007C933E89E8B34CEDCB9554E2D7EA6D2A5F
+:1049C000F359F889D33F7C8CD33FBCD713D99A17BE
+:1049D000A3DF1283EB4949BF25A9829E5A77712232
+:1049E00078EE477A003C6D882F78AE11F07927B3C6
+:1049F000120DE8E20D30436197E6CF363B9BC7606E
+:104A0000ECD7D982803609CA3ABB83F91933B4DAB4
+:104A1000401994FFC282AFE17C18F3FB8280E71655
+:104A200085CDC1791F4660613E2D393AE1AF6D6A8F
+:104A3000F166551130A76379E1CF57E5D1F76FD013
+:104A4000F71A7C3FAAEFEF8DF28996EF8DF24AF9C3
+:104A5000FD3BD88E392FFE7D5BF9D5D6F1CBABE48B
+:104A6000F71FD0F8EE8BC36F4C9B6C1D7F5A0D7DEA
+:104A70005FEFE0F4EA4E75463641B9D9E50F684874
+:104A8000378D45F1BD9656B009DBA9921F58674096
+:104A900085EFDDDB53C7AC6266BE98F2271CCF03FF
+:104AA000D262E68B948949167E4C0DA459CAD093E4
+:104AB00071F2CA981E0A789D048FDE5F277D51D25D
+:104AC000DF49F0DEB5CF45E5BBAEE6F0DED5DF4D24
+:104AD000728630B01C28EBA1AB0CD37A04702A2C60
+:104AE0009BB1CF95904B196F7EEFB3E1FB249535C9
+:104AF000E07C921C8CF4D13D79C59BC326FCB40E9E
+:104B000002FA42395DD1391E055EEF19B4307B9E41
+:104B1000699C9641FA9C4D85FCFDED6E1C2F98A971
+:104B2000A01ED4BB0B0C77EF711CF9132DE3387367
+:104B30002B699CBCB8711CB99571E338E76C12EF16
+:104B4000C538432E36CE3DF9575BE7935B45E314FA
+:104B5000C5CF27B72A6E9C243E1F782FC6F123FEAF
+:104B6000FA9CCF90C9D6F90CAEA171AEC171C69BAB
+:104B7000E633B8266E1C378D83EF711C30A47C2C75
+:104B80000BE8EEE85E48F4FF958BEC05DD117A0248
+:104B9000FB656FBB18E9131F8C9B857A0516679020
+:104BA0005F4D49A371BE4802FABBCD74E6FA889EF8
+:104BB000A07F16081059042002FD532778B462FB29
+:104BC000ACDC267CEE2ECD9E8776C93A8F7F188886
+:104BD000CED9DDA5FAED09EC9B056DF6935D16FEC9
+:104BE000157A6F0A1BDE00E377A0B231954F82FE83
+:104BF00062A0B74E80FEC2E747C23EFD00F41BD361
+:104C0000CDF036D13C4E6A1C8F2737F075E48BB55A
+:104C1000C7EC60ECE1306F1402DC378A692C680362
+:104C2000E3CF2467F5821EDD2F3A229B881E810187
+:104C300036E073B6BE1FE04AB4033BF30FC21E85D5
+:104C4000BF0136B0656F69DD71189BBDA5CC1BB483
+:104C500004E63BA763AD7D0094CFDABB6EF3BB4D9A
+:104C6000FDCCB19FC0793BE13FECE7E690DD629F70
+:104C70007EB7D25ABE35CE5EAD51F2053DC4B8BE48
+:104C8000881DE975632687E7567C8EC16A83E875BF
+:104C90009BC1BF95F0D4DF6D67515A8FBA3258214E
+:104CA000E22383ECA2905C57E2E0BBCDEE0C0481E2
+:104CB0009EB7FD40253CC6C3DBB52F3960037BA9F9
+:104CC0006BFD1FED687F5F0AFEEF2DB3D6B3301F7B
+:104CD0004FE255F2C14D734AFA7D606A77736846B8
+:104CE000BF0F4CFCF2DDCA5996F2AD0D375BDA7F8F
+:104CF0006FD93C4BFDBCF0624BFDEDAD7758CA0B54
+:104D0000DA7E6069BF687D93A57E71E45E4B7DF5B8
+:104D1000B6B596726DFB2396F6F5BB375AEA6DFB76
+:104D2000465C8FF2B8E24D95A17DF6B9FBE4FD68D3
+:104D30005F7D6E687E6C5387BC0672F8716336F1D6
+:104D4000F7A9461F3DCFEE1EEB447BBC3E09E4199C
+:104D5000D6FA7DCA1FC2AD93518F407BD0E1079434
+:104D6000F7C361709E5E517CC4F7EA7A9D45815518
+:104D70001596D6C3D7DD6AAC5EEB82FAB17DD7ABB0
+:104D8000EBB584F55A9796B0DF734A7701DA77E18D
+:104D9000DF3918DA817DD90FF03700D78BBEEA4FA3
+:104DA000DB5865BB49EF9C546CC407372A534EA2AD
+:104DB0007EAED1B9BCD7ECCC9982FE608D1E2D6839
+:104DC000705F64BC7600260BFBC9A7792D8E0C881A
+:104DD000C92FD16F8845EE97B2D087A89F4FEF5764
+:104DE00049CFB2E8C1DC6F8FC2F10327F13DDB9DF3
+:104DF00041EBE35B8D817E1F803F77BC713A3D7F45
+:104E0000DF18ECF701E89A771AE750F9DDC6103D94
+:104E1000BB1A2BE979A2B181EA3F685C46E5938D24
+:104E2000617A7EDCD84ACF538D6D547FBA713D953F
+:104E3000CF3646E8D9E307087B94A50BFB4FD8EBA8
+:104E4000B07250F9BC98830AFFE67EAB3F1BE5FACF
+:104E5000BCFB8B02B473CF1F07C324817F289FF153
+:104E6000FCD637FD02B4DE2F8C00FDC7F6AE7725E9
+:104E700071FAB86C6C3A03FD73EF309D69307ED2E5
+:104E8000AFAE247B19DE6B8CF465C43FCB93A07F5F
+:104E90009C73D6A5E9D4C31F8FFE4731C61F6E147D
+:104EA000FA30E9A0DAC0E9B6D98F7433E18FDB6557
+:104EB0002F087D1E8747B2E5727AE3F34C86C467FC
+:104EC000672EC601D629C11136E083F31D0E9AD78D
+:104ED000F93DC91186DF627064D2C5F0C6E1A8DE73
+:104EE000E632CCFAA1B63DD5B0EA8B1CC3AC2FCECE
+:104EF0001FDDEC45B95F926D333E188BFC1110FC41
+:104F0000C1F94EF65FDB9E67B82DFD58CBE7DB9409
+:104F1000E9E80781724FF94E02FF403E9764EBC605
+:104F20000720DFA7B60D49C171C18F33709CD38DA7
+:104F300086C1C7CD36CC7C59B32C89DA4BF8FAEA56
+:104F4000F7EF0D1F5A06EF3B19A1FEAB215FDFCF34
+:104F500066DA9F289EC3F6D8BFC075C701FF7F459C
+:104F6000F1008DCAB2DFFA7635ECB80ADF6FB78C84
+:104F700007DFF9A40F8DEB55DF74D7D849535CA038
+:104F80000EC720FFC849740E418F29D0DF39CDDD0F
+:104F9000AAC038D36D3EAAAF17FC58EBECD243F051
+:104FA000EA4C07A7475FE39C6A3CEAD3407F543A48
+:104FB000C12383712ADB4794A17E3CD3B122330401
+:104FC0007C5BAD9EBF2B98E0FB569BC2E189D8BBB2
+:104FD000BB4CF3917114C6A05F670C7EE4F493A6FA
+:104FE00072BCBE96CF07B05FE08FBAEDC7CAAF0103
+:104FF000F8EB767FA6231CD36DA1076C19B1F92BB2
+:10500000387FE8A76ADB7B3ACEEF637BB8E0EE8BB4
+:10501000E8A9DE70BAB3296E27E10BB34EB463E69C
+:10502000F7C4157D37BD0DA2F9C93FDBD92A8083AE
+:10503000FD055A41BD5DD456B0A017F135BFA39A06
+:10504000E28B9FD8A4DDD4568CFC7186D9A6E3FCF4
+:10505000CEB0D7BD634DF8EBB071BB9FB5723B26A8
+:105060000CFF213C60CF5AEC9A45EBADE5856C76A0
+:1050700026EA8D85EBEC2C02285A8C7691E40F9869
+:10508000F7161BB77717B18616B4E73407F70FE6A4
+:105090001B4C1B0070D5FEE2B162B4FB7F69B311FB
+:1050A0007D649C61711A87BB2A3DA207A0FEFD8E1C
+:1050B000B1375E83DCE788B4E0BACC52987F2BEB43
+:1050C0008DCFDB5BADF05D0AFE7878195B6E8143B6
+:1050D000F62BE150B729814802BE7B45F29DD023D3
+:1050E00069AAD5CECF8A2BBF6313F14B95A948E7A8
+:1050F0003386336C4BA17A7F14E3233B1DFE1540AE
+:10510000DF3B6DC12ED4CF6017143153BB3B6D21F3
+:105110007A7F5A796D21DAA74C8B16A17F0F6B8AA3
+:1051200086FCA00B7E5093BC45188FF530583F414C
+:105130002E1D081FF4D3E2A99CC98A30FE0A720A08
+:10514000FDDDE72D3FAA40D9E5EE60D89F23DB1AAD
+:105150005F76F9ACE57AFC07D26138A3384EF2707D
+:105160006B3D2C580CF9CDE3B7BEFFF71E3C4589CB
+:105170006FBDC4D2F074BAA32A8CCF266AA7CD76AD
+:10518000739D93C34F7E39B45F2AECF93AE60B5313
+:105190009C389BF3C1D219368267A9C7E70F43BD7C
+:1051A000A20518CA1FC6AACDEB58FD0510B97EA6E8
+:1051B000B2D6AD235FD65FD05804F47D912DE45173
+:1051C000C723FE0264E73A01595F01C89A7BBAC55A
+:1051D000EE6503D3C4FA3AD030CBEB40A4F3F81811
+:1051E0009DA55EB00BBD08FA224BCD403DD85D4E6B
+:1051F0007E09EB223D21DBE9B17603118EBEDAB9DF
+:1052000062EDF212F557FB8B67768501FF55CF3DB6
+:10521000E805E2B34FB4B64C3FBCAFD9BAD28B7CF1
+:10522000FCB116F6E2BC3F89A8D313F1F38DAA2294
+:10523000FCB1805B417F58D0E9D453ABBF8578FF88
+:1052400062ABDDC026F5DB1C510710B1AE6331E760
+:10525000A76D8EF778F99ECF909EF5BBADF256F50F
+:10526000C4839918EF040C71BF9145C97EAEDBF27F
+:105270006139DA23F5AC9BF444FC7738FE85345A67
+:10528000BFE6E929BDEBE5FE4BBDE0FBFA8ED59FFD
+:10529000A95E2C5BE5BB52F823D3544F3AC5952643
+:1052A000B0094837890716E1F6F08A271F2E7A0FD2
+:1052B000E038BDE59FBD8A256EC4F5C3F9F6DB7FF6
+:1052C000F692AF6FBD7E56F8F3B1EF22F49D6F37C3
+:1052D000B7DFD91EFEACB147BDE82FD56CB4FB419A
+:1052E0003259CD339B7FFE28F2F5EF1C1467A87E60
+:1052F000E6F05B5743B97A873D7D269F865BC98C74
+:10530000D1A31EFE5F362686FFAAE70FEBBE51FC37
+:10531000FD8FD26274A8DEB15F67A37AE3ADB47D7E
+:10532000BFDEE54E408FF6F7CAD1DE5EF1E4973A74
+:10533000CAD527FB149695D7FBFBCA8D87C99E4318
+:105340003C11FD047D7AE8D58B4ED16FBD348EDAE9
+:1053500019B87EF545A791B8F665101F3FFB12C638
+:10536000EF7FEFF0E3FC2B9FFDBE17E7F191D6C076
+:10537000F9F9B195990118B7D21ECE34E8C9DF57B3
+:105380003E7E27F1D9A2637766523C8005726CB4E9
+:10539000868673707E0B36DC40F35BC842C46F9523
+:1053A0008FA9C108C6B334367D470279784DC8C38A
+:1053B000479B1CB8F6B08F50C1A27FF8BA4AFB04D5
+:1053C0008CDD41F1863BE53E045B42E5CF9D9C4E82
+:1053D0009B559B8C6F382D7CBAE59E4EA4CFA9417E
+:1053E000812C8C4F021EC2025F0AEA1DF5D8D42C14
+:1053F0004E1FE6D38AC577A0174BF13DB6EFB40731
+:105400005C4596EFC43AC6C75F2AC607B893D01E5C
+:10541000FB2813EC9B04F3FB52957A19EC0D137FD8
+:1054200099E49ACBF9967BB95C4B398FCC9A8EF57F
+:105430007F7A83CB0F7E87EB3AC015CDA2FAFDDFD2
+:1054400051480F385834913C6FB10B79B6D6CBFD2B
+:1054500049805BC3F529C627D07F1AE19FECB4854C
+:10546000EBE03B935EAEC7F1A89D1E7B6F5AD7174A
+:1054700009F97F5915FBA342FED9062EF77DDBBD46
+:1054800061EE1FD8233F7F14E515E413D7999A677F
+:10549000EC419CF7A7DB0FBE750BF0F5A7ED524E64
+:1054A000AD7A335E4E2B778E6789E4F453B79F2530
+:1054B0009453789F504EDD5DC4C7FFD97A53E2ED17
+:1054C0006C9CDE947AB02FFCC5EBC135AA2FA11ECF
+:1054D00084BF3758716FBE93FC26F9ACEAE9DAC194
+:1054E000143792FC28F9AD871F25BFC5CFD38AB7E3
+:1054F000F8FA1785BE9174B62F67610FC64BF7AAED
+:10550000E45F9F03985A80BEE7B6E74530EEBCD211
+:10551000C5E317E78C6E6F1A3C57A6F2727786DEEA
+:1055200082FA41BEEF76F1F8F6B960B737D5E457A5
+:10553000BCB747F5FAA0BE2BC2A627F23740F3123C
+:105540001C5DACAF7A1E0F9EAABA7397A1DFDEA6D0
+:10555000D27E7645D34D5EDC073EB767C84F503FDD
+:105560002D78050C4C80F71CDA812938BD808679AE
+:1055700009B70B7A7FCCC20F4D86F9DDBE87FB0BD6
+:10558000156BE2EC7BF7521DF50DD8F727AC716D6A
+:10559000CE3755A29FCA0DD6FA2AB686E85615C749
+:1055A0004721E1074ED0041F8D66A3851FC6E31770
+:1055B000425F4D550B7F8276C6B9A33CAE787E8F95
+:1055C0004AF83FBF5D8960DC87E2BB9390FEDD3A1D
+:1055D00033F9CBA791DFF4BEE5F8F40B7F28BE1BAF
+:1055E0009AD4EC7ABBE8A7F03CBDEB7705BFC4F2D8
+:1055F0002F7E9BFB36EBDDBE74DF9F69FFF8DC3E40
+:1056000007C1716EDFCBB97763F925871FE13CB71E
+:10561000DC41FB67E17D9EC830AC1F04F4C67573A6
+:10562000EF97455DB4EE34139DE66B7CBFE3FC9EC3
+:10563000FF7857C1FC833D0E1FCEA37E1FCF0BA961
+:105640007FC9457197737BBF2C0EB9FF7EF3A9D339
+:105650005988F8CFC3E6EC447E4DE5FB00F5BF9CCE
+:10566000B4B909F7C33BF6EBB8BF52FAABBF16A10A
+:105670007E39B793DB0967ED5D8FE33E68AD367425
+:10568000B91DE51E6DB6FE6077DA174C091726C204
+:105690000BC7C339C003CE0BF052897AB12F7C34CB
+:1056A0006BDCDFFCEF878FCF6EC3F16BF64C20B95C
+:1056B00089E14509F0F79E8853A1F9F3F7FBBE2C69
+:1056C00042BBE7D3F6265AC72F35EFCDFFE3E6AD51
+:1056D000442F67DE07FE9BF3FF748DAF4BF172D052
+:1056E0009BCF7F7117959FF5F809DECB94FF13FFD1
+:1056F000D3E8BE13E8EEBD34DD15FB7FD7795F8AB2
+:10570000EEAF08BA7B0CCC2B38B7F7AF142F97F35A
+:10571000BFD4BC7DFF8FCE5BDA3FAB6CFEB67C683E
+:10572000BF86453B7D00E7CAE1B3DB30CC046E4267
+:1057300030913D12B473FF4855781C860DE27121FB
+:1057400026FC094A01F3611C6521D9759ABB85ECD9
+:105750004CA6F93B03808F5523E7FB2957838D39EE
+:105760001EC2F2C0C97E8A6FC6F955CD0A0B2860E9
+:10577000EF6923BF7114ED7CFB705BD45144CFF70C
+:10578000F0798F8863D90DDDE24FB8E3FC0197CF44
+:105790005AEF10FD39D998B67CCC53706B4604C6CD
+:1057A0007797B4D17CDCC3186B33ED033A98E97B6F
+:1057B000E8AF1003B026FBF1EBE2AFA9077F633A35
+:1057C0000388BF11368A6B51521FE1C31F59457EB2
+:1057D00026F71F63F86CE9443C6A0CFC3F3E3FF23D
+:1057E0001B99F01735D18536DC167059DB09BFE8F7
+:1057F00092F4E1F4C8AD11F45962A187C47F02BAF2
+:1058000058E821F1FB75E9124F8F78BC7FC7CEE3D2
+:105810006DF174B2E47764703F240A7EC8CBDB3745
+:1058200053BCE3CC53EF7D0BDB57FF52654EE8E7EB
+:10583000EC760F8BA2FC6A111DFDA9AA0E35619CA6
+:1058400057DAE5D5CF7968BCAA9D8EC84CF8BE6AF8
+:10585000D7FB4564372DEF3E3200E3024F299C7E93
+:10586000E1AE22DCB7ABD2B87F10DFDF063B8F0B97
+:105870009C7E31790EC61F946D3C5FB1AAFD26BB9C
+:10588000C3C46FFFCBCEF35EA11DC973F84985D6A3
+:105890009BDEF071BFE0F4930A876FB73D82798F8A
+:1058A00055DB36EA21F42BB77D4671ECD2E79EF149
+:1058B0007691BFA85AFDE76D2AD1139E44BF783F69
+:1058C000B6AEA396FC84BA76E127C6F951D5CFEDE2
+:1058D000DD1506D4543FFF8417E32FA73AB77AC9E2
+:1058E0003FDDC6FD4FCDAD25F64F2FE597B6DF9BCB
+:1058F000D02F3D85FF007F62BF3DCE9FDFD6EFF208
+:10590000F62F9FF9FC718C939EDEF9E9E30877CDC1
+:10591000FFFEE3E368DFB37D2E632BCCB7FEA93730
+:1059200029DE24BF7B5BC8E9D9412C9C03EDCEFE68
+:10593000CE41F92367F77E948BFEDCD91D7FCE44E0
+:10594000BF7EE9DEA95938EFA52F9466B104F22E87
+:105950009FC89791CB8813C6D3E160C741F243CE6D
+:105960001C7790DFD7135F68AFE5F11A9F882B6C27
+:105970004F1C8795FE705DC7FBE53C3E26FCE24B65
+:10598000C511DE003A5E7519F4DA2EE24471F43A7C
+:1059900083FF00BA7C1947AFCF59E86739B80FD9F0
+:1059A000D1AFCF3842F432F024E3BB47EC019B8EF9
+:1059B00072B033B9874E33914ECF7C9E8BF1F08F0E
+:1059C000EDDD64F774EF7518E8DF57EDFD2DC9C5FF
+:1059D000D9178E51FC948938EB59D6F3C7E3628A04
+:1059E00098DF160F8F3F087C637CC2E7A5F7220E75
+:1059F000C1F955C627FA8A4B4CD045DE93883BD770
+:105A00006E795B6771711E6522D2E93D4B7C5CCE7D
+:105A10003BBE3F03F130C11C5F4B1CF7917E738C82
+:105A20004E3CAE26E36767378AB81BBC1F3806FDBD
+:105A3000411EC7A88F28BF6509E450C6D7C6E871C4
+:105A40007218B9BCB8DAA5E0FD5BF1314CE7EB8325
+:105A5000C4CBE9BF24D6C3DFD4B95C4FB78566EAAF
+:105A6000A6FDECEF897D16892F09EF69918777FAFA
+:105A70002995E2412DED07499FC6CB735D1FE720B5
+:105A80006ED379BCB56EF7FE22D43BA70FBC487C21
+:105A900057B7FD3D3D0CFD1CD9F6BCCEED49CEE718
+:105AA000A8A723263D7DFAD9FD453CEEC7F36EE35A
+:105AB000FBAF16FDD7EFB1F65FBFFD334BFFD5E16E
+:105AC00076DAFFBAD438A7B4C04D38DF539D768656
+:105AD000FAEE54BB3A3D92C80ED4ED967DD0966353
+:105AE0003AAD57E35E4FA2FCDCA5C7A6BF9D82FB83
+:105AF00074206668FF763471BEEAF8716000D2A542
+:105B0000E3D82D2AAE1BBB108F263BB8F88D8652EA
+:105B10000FC86BF13BC171C856F17A60C2719B0529
+:105B20006E18270BF57133F483F9F4983F84FBA3C7
+:105B3000AAB77C3AC2A31A36C39570FDE4FDD9DD3D
+:105B4000418676B9DDB0E62B67CF1671B4A8356F04
+:105B50003D5B67C3711F9CD992FCB81FB064446061
+:105B6000F461CCAB5F904D71E29C6FF3EFCE18EE19
+:105B7000B0EDAAD8BE6DF205E81FF3606C91B57365
+:105B8000E1BB64AD5DC17D007832A4CB9DB6D0266B
+:105B90003D03DBE9CC07AAF1715DD128FF429C7B74
+:105BA00091FDC9767DED07CB7348AA807F88D80F19
+:105BB0001EC4BA14DC0FDEE0E1E79106BBD3E9BCFA
+:105BC000D16661B7F970DF15DB3558D7ED4B9E47CD
+:105BD0006AB596D34B4BEE18EC073F58BFAB540356
+:105BE0007D907E53C98E0106EE4BAF2BC5BCFBF4F6
+:105BF000274A46E740798EA3A88CEAFFB564742E45
+:105C000094BFDF3AA98CEAAB15CA0BDCAB77978659
+:105C1000DD31F9CC00E316F32D406E0FA0DC9E09B8
+:105C20009E6EC1DADA1BBED0F9791816C4F90F9A44
+:105C3000C8E73FD0FDCE0E9CEF605B5713F2DFCF7D
+:105C4000F67E998AED7CCCA0791AACD9C07D7978A2
+:105C500035F1AB8BE4FFC4E7C1487E7F2E39F41BDE
+:105C600084E3DEF9C31F2E479D5AE3273E8ADF27D0
+:105C700066463AD1A542D005E1749AF2902BF12400
+:105C800002E99B3203C751C235EA57577E7D784EF1
+:105C90004A7E11E7C04CE7A43E41381F490ED1337C
+:105CA000FE9CD4013DF829F253CEC20BB908BF3C8B
+:105CB000FF54BAC84D7181F37B58C491407EE473A0
+:105CC0005323CBD086F65DFFA623F4671C37FF571E
+:105CD000BE9D47A1BFAB2A743FA6AE5DB56C5C8686
+:105CE0003696F109A13D21E8968DB444F9BA8BF1BD
+:105CF00073390E25807EE3B9EF1BA47F0756CC24B1
+:105D0000FFE25C725E3BE64F9CBB9BE701C00AAFC3
+:105D1000A01C0CDA931245FF07F8F88B383EFEC240
+:105D2000BACE58C73DF7956F7717F56788FEC0D094
+:105D3000C944B9E17FE7546E679F6BF4111C60168C
+:105D4000EEC7F5F472C7CB7658CFE901DEFB3B4CCA
+:105D500078CF75F449BF3C07A71F3DE3E9B7D0D919
+:105D6000908B725C156C2F47D7F4A385771523535E
+:105D7000BFA987AEC0F635733A8FF09CA18602DCCE
+:105D800067EB4D5F7E1E2B73CFBC263BC62B903E30
+:105D9000BEDE74BC6A993F43EB67A1EB5884FFAA4F
+:105DA0003D9FD9107E49CF87459E7FFCF7FFE85085
+:105DB000C4B8354D768C93ECD6C99E8D6F371D0FC8
+:105DC000558D8F958B9CC5346E968DC73B7AB7E702
+:105DD000EB5FAC5F279DCBEA8B1F8B0CDE1FE0FFD8
+:105DE0001B66FC7FAB6FFCCFC276807F7A7E0DFC9A
+:105DF000DF84EDFBC2BFB4A3AB855EA8C67D14E013
+:105E0000A30F03B33387C2F8E5AA9BE460F156956C
+:105E1000E40FDACFCCC98CE991C5931AF6E37C176D
+:105E20003FA610BF568873A69F8ABCFEF87CA88543
+:105E300073C2B4BFD32B2F2A12E7D7C5E5BBD7C790
+:105E4000F87630CF53E3E7B6542117A58B0A53D029
+:105E50001EDA67F7FD2BD9D9AFA86C5302FC6F444B
+:105E60002633D1755083CD9227CB2A522DFD962D06
+:105E70002AA47DEF251EDF45FDAAC1CBACEB765EE3
+:105E8000D87ACE6848ABF59CD1B0B6FE96F657AC42
+:105E9000CFB7D48F888CB4D45FB96D8CA53CAAFDE4
+:105EA0006A4BFBAB764FB1944747BF61693FF6E859
+:105EB0006C4B797CE72D96F6138ECFB7D44FEAAAB8
+:105EC000B2D45FF3F1124BF91FBA7F68B5536C8CF3
+:105ED000F4234B52485F1E6A9C988BF9D86C9C52F5
+:105EE00086F82C15F98487EED06D86179F0536034A
+:105EF000F4D681053369DD3F744766C047CFE200C1
+:105F0000FA354C9D3C2E51BEE6546352AE392FAA51
+:105F1000D469B7E8B7A986B5BCCB21F6FD0673BE38
+:105F2000F9659C7CD91B2647C13264FD170FCDC291
+:105F3000F140CEF6093DB7EFB2F45C6643319641CD
+:105F4000CE0E25923326D6D912C14FF00CE8981FF9
+:105F500059E6A1F538802F7DF43EAC81BC4C71FA36
+:105F6000071EC679D9FCE9C88465738287787F6289
+:105F70005D66C36D5F675D96729E6D13F96B693CDC
+:105F80007FED91050529CC84DF3F386CC28E6EE32E
+:105F90004FE3A8AB276F35DFFCFEE324CD942FA79A
+:105FA0002C9A49F922D97DE8453D3B7FC616D0C7DA
+:105FB0007A8E8F9EF27DCB1C5BC23CB06EA147A552
+:105FC000BD3522666F75233DCE64BFFE10E629D530
+:105FD000CDED267B2BDBD676C7119CD7ABAA885F8D
+:105FE000FAF8F92A61272F98F1C01D47705FFA5F10
+:105FF00086917E92E36C689C3E43339D231FD88735
+:10600000DF74A593C3F378E3F0191594B76DF0F33B
+:10601000A2A2FFDC706D39DACD8345BEE943B6C478
+:10602000F92E6ED14F16921CE135DC24276716BE7F
+:10603000E3D5601E8FC2EAE5C47DDBAB3A8BB91DA8
+:1060400016F0E339D4DCE8AD0F61FBDC6C8DF25D5A
+:10605000E3C7CF9A1B6ACD83F935A7D9FC6E2A779F
+:106060002BD8DEF123C6FA41FBE6FFAD123CCD078B
+:106070002651FE87C3DDC0703F55CEEB60DAA384A6
+:106080001FB52399D64126F6C565BCF5F3EC8A4EBB
+:10609000B4373E5F67A7F13E87391AD0FFE71D2A64
+:1060A000EDBB1E494B8ADAA0ACB67A68FDCE45DB63
+:1060B00013DA2FECF0447C7931BC68EB27D37918E4
+:1060C000C7403EFFE63477C49D47F34EC7794B384F
+:1060D000E5BC07F5E1679608B873AEE839A7C1904B
+:1060E0008F5543A37E17A4F2739891C689825ED61A
+:1060F000F9B464CFBEFE663C3FF486CA3035C4D7DF
+:10610000D546F35F08F3C7786F3C7ECFF8F2BEB098
+:10611000A9046709C2A9AE2FA779503BF8AEF6676C
+:106120000A7B340FF930349DE8DADF46E7027BD989
+:10613000074E2E5F339C3C2F57CF2E98B1A51F3EA4
+:1061400087925C7CD3D9E7BA1F74727D44CFAF715C
+:10615000BF00ADFF521FA9019BB073B95EEAB19FAA
+:10616000F4D0779D19B1B29AF2A322ECB76FFB6C11
+:10617000C77E1DED333723FB59EACDBEEC33B4CBDC
+:1061800090DFA45DB6386E9E30BF1A31BF9A44F3DB
+:10619000EBA56F6F699076CD12E745ECCA0C3DB167
+:1061A0003E7A52D0A1DED019C59B688D02BDB3D80E
+:1061B00046E78D99167199CF976F704ABB6ECF7E67
+:1061C0001DF10CF3463C6783FF5C4E7AC79E302F6F
+:1061D000FC52FE48FEEAC29D47B13FB07311FAF38C
+:1061E0006DBE94B48BD817F665AFBACC787DC02954
+:1061F000F2B963787C50E0F1C184784C073CDA2C2A
+:10620000F6E1AE021FE1F1A7CE8BD88767BEFD6E27
+:1062100031AE476705BEEA7AFC5CAE9FFBC32285C0
+:10622000F1AA5ACC5F76F232EE07ADC0263998DF7C
+:106230001C7C02FBAFDF6D3D77F863278F9331370E
+:106240003F372BFBCB14FA1EFCEA7FFCD0477AFFCA
+:106250009F703E31FFBAAB18FDAB152F5C91827673
+:1062600059D9AE9B0D7C9E4F1F4AEBD9995D8E008C
+:10627000C279268DE7EB9DD935E108C61F3E6D3CFE
+:106280009A6FD6F7679E3D566C877ECEEC3C56AC37
+:10629000517E70C46217D67EF59B623C8725F3AAB7
+:1062A0007BF8C5C9D789752E1ED7C8C8D45B305FA7
+:1062B000FC42522AE1EBC14CDBFD89E235A83E6984
+:1062C000DFDEA3D33EE59211BE156E8CD7E41994A0
+:1062D00087BB4209E42CC07D96594E3FEE03A4E7EC
+:1062E000B3E1792988C21073033E1D87DAE8B869E3
+:1062F00052A7B11FCD2319C7D14AB9BEEDBE41A7E0
+:10630000BCB164CDF7F05C2867CFD168BD93711D37
+:1063100047323F972CE33A3DF0BC62A77568495E6F
+:10632000A8AD04BE5B32298DBEF3CE7A8BF8E59C16
+:10633000CF16B6E37CB46E8AEFFCA47178C650C069
+:10634000A391639B4136CD5F005BA6FC7FAFC6C2C5
+:106350002960DFAC06FE1F0AFCDFD1E8A4F62D6041
+:106360001F1A69744F42EC9E0F93DCEC6C34A8DD6D
+:10637000CF1BB3E9BB071A7DF4ECB12318FF8ECA1B
+:1063800009F4EB7FD6F3BE467E9F882CFF711CD8A4
+:106390006940EFF4094055C04BBA387F2EEB1F6DB2
+:1063A0007C6548D950810CC067FF1A63E3AA8BC093
+:1063B0009BEE88A4E211E32B5D2C5C3611F3FCBA52
+:1063C000EF2F4FC5F311F794958D003CE2FEF6D503
+:1063D000402AD703CD783E35A7C6D78471BF9CDD50
+:1063E0004A3BAE5F39BBD796E03E02B4A37383B29B
+:1063F000DF0C17D773C9071F51F247E1E602DF9799
+:10640000677B932389CE978E73713DE777F1FDC14A
+:10641000D5625FBD7B969BF462F24117F14BCE9E35
+:106420002B697FCFDDC7BE727C3FC907FF4C71600F
+:10643000B7D2B61FF729D9026E7F4A7EEAEB3B6CD2
+:10644000AF5F46FB737E8DE2C260F6D2FCCECC1A03
+:1064500048F8C6F6663D7E4E4F6C9705049E56DAA8
+:1064600013C7E935C6C719D7D94DFB99786F13E221
+:106470003BE78D3605FDF5330ACFC7E80FF8D8099D
+:10648000E59CC96D74AFD373CE50B90BBEFB93714D
+:10649000BC602580E32AFC7D2E7E27F1A116E94E03
+:1064A000D427397BDEE3E77C6C5D3AE6BF2DBAF793
+:1064B000798A3FAA7A308F9757AEC4F8648637B886
+:1064C00011F984859F2F3B047CF2A038B78C6F5064
+:1064D000EFAD768972B8BD39007CB2DACECB8BEEE7
+:1064E0007D8EF866B53DB818CF3D63B919FA5F9D4A
+:1064F000DA9E6D83B2BBE999E6A383B02CDB3FD370
+:106500001C9E0C76A84BEAE7600EE2BDA76C4079B2
+:1065100094A9ACF13273F2A79C5FEDC13F1F190043
+:10652000FC52B787DF73D383B7DD6B155C8F7EDEDC
+:1065300078D4D7AC093991FA03D6F92BB219F929D5
+:106540007A4489E42B78DF476BA6395FE5BBC98ABB
+:10655000885BC0F7E6F863DCB9363A2A83EB73331D
+:10656000CF0B89A7EB9B49256D4919781E35B44A95
+:10657000453DF88CDDA0BCFA2E8DF4F6699957DF05
+:1065800060277BB0469C73B52F0FAD1A817271AB3B
+:10659000E6C7F842755E5B09DA43D52FE6F99B58EA
+:1065A0002C4FB73AB53D738C3B96A72BCB2B445C55
+:1065B0002A2BB52135B510F763D6E6E27E491D6B6F
+:1065C000BBED8708EF6B2A437EFF64FFA414BC7702
+:1065D000A816CA1807ABED38A687A0DDD549FCBEC2
+:1065E0009BBA0EE01B37BF872650C0D846CD484225
+:1065F0003DFFF340C348348937BB7E5DE6FA07C6EA
+:106600009EC80F1848E75FDD7BBCD98965DD18C1DE
+:106610004663F9DF9A91CFAA47DB28CF9285FFED39
+:106620005060A8D8EF8572AB6BD05473DC3B479CAD
+:1066300033ACDFE0A6F360B02E6F42FEAE5B6F0BB3
+:10664000E3FE99CDD949E7807EE562823ED6F353D9
+:10665000EB14AE0FC30B783C75E98CB46FD0F9A97D
+:1066600095F946F82271DDCA0B49744E4A96AF4E31
+:10667000F251FF955A98F6912A2F78E97CD5DF6F71
+:106680003CA7E5BC56EFF1DC048F1CAF26361ED1CB
+:10669000F5E098571F1A0A745BBAC36E7398F86EC8
+:1066A000E90EB13FEF0A64613F193AC733437F10E7
+:1066B000788DEEB8E1E5B0960DFA5FCA77F87C7395
+:1066C000D964A45BAC9E59E53F80FEF87D49B2FCDD
+:1066D0001FCD650313B44F8A6B9F2FFB575762FF83
+:1066E000F1F06424C5CA4E68AFFDD5D15346F8D643
+:1066F000DAE2FA4B9365F74A1C5FF255EBBDE98786
+:10670000C3C057F7A5B695A0FEEF5EC07C788F1684
+:10671000F2ABDFA46F5B5D5CAE2B2FE45BE81DC3C7
+:106720007B81852E1F35665BF63D17CD5D4AFBB339
+:10673000AD2E412F16E6E76C360C6011533CE8FF96
+:10674000C3F1B7C271751F70FCE37F311C3ECB787B
+:106750003138865AE0FB5BE1D87463C137F2A0C9D7
+:10676000834AD8998FEBC28F795E9C9A5AE66BC2A6
+:106770007D991F6B14D71FC678BE4BBEC68E6A6349
+:10678000507EDA02180761CBB9BD02EF5BED63689A
+:106790001D227F61C81EC73CCCDBC8AF0C2CC627AE
+:1067A0001B5848FB3E729F948938A1DCE71966B0FC
+:1067B00012BCF7EF44D23C5AA7F28373AB31AEAEB2
+:1067C0007AC625E17AF8A02D12C6F1C20FF0F13297
+:1067D0006C917627DA4BDEA106AE77195EAEFFD854
+:1067E000AA425AFF36D9F247DE0170AC544A925E93
+:1067F000413CA7E6537C1CDFE33D3B9BC4BAA5A606
+:10680000FA0D5CA73689756B85D0EFF27D725A70F0
+:106810001EDA113F59356DAA7312EAA1406B3F5839
+:106820006FEE5F356D65F6245C6F7CF94E585FEE58
+:106830004F9AB6D20993D9D4E4EB6FA4C6CAC3FE6B
+:106840000AAB35E989692B03A0779ADD4BAAD0CE34
+:1068500081FAC3E8273E9126F50EAFCF977A0AF565
+:1068600012E831B5A9A71C46BD94DFA377A691DE37
+:10687000D9F2B84AE5A5301EDA31308F30DE0FD6B6
+:106880003D4C23FFC805B02441D935229FF6CF6087
+:10689000DE2C09FDFF11BC5EEE77E8C36CB4DF812E
+:1068A000ED118FAE1CDE5E9FC5CF4BEB1E37F96D31
+:1068B00072FF4415FB7749224F453166911FEC5C0E
+:1068C000336609FA51CEA1D6FD693D2E9F458DCF85
+:1068D0006F7147C9EE6A4B12F1EB7E2C9BEE4D10A7
+:1068E000EFC1521E83CFCC9B9B4BE83E3D0F333014
+:1068F0009F3A3B1465667B493E1DB08EFA4C72E3AD
+:1069000070B340A27C8A85C9DC1E765FD0B89FA890
+:10691000807D83EBA847D8E1C23EB2CB7B8EE2D626
+:106920005D692FD9C57D7A4B674CC9C27349AA3BB3
+:10693000E0443B67BF3186F66954E6BFBEC464EFEE
+:10694000344767507C5233020CED9C57859DA31A47
+:106950007E66B6735A1AC10187B56A737101DD5F2D
+:10696000F3A82BEA1C82F47DD0E647BD71704C552C
+:1069700058C1F8E4324672BAB938730AEE336CD4AF
+:106980008229B7A2BCBC01E3F938DDF83EF70A055D
+:10699000E3E99F3B8329A80FEE4B65163FEAFA64B3
+:1069A000EE8F6C4DE2FA47FA092D004F14E0D02E1D
+:1069B0008CA4FB7C460BBB549F5B46F1324C03C25C
+:1069C000F8A78335840D77ECBE3A47B6CD92FFA881
+:1069D0005D28A278E2D6243E8E1CF71E71DFA02C23
+:1069E0003B59038F1B038F27F2DF6A059C0EB0878C
+:1069F0007C649FC4EDFFF7B68FC85E91F4E9B15394
+:106A0000147E2EB42FFBA8FE82CDA26763E7D97552
+:106A1000D2CB67C57D01320FC42DF4594B76A8ED5A
+:106A20009ABCD8FD009AC8075923EE0560D95AB719
+:106A3000F91C7E32C663A0BE59E48524C79DEB775E
+:106A4000B99792BFE01AAE59CE81395988BE73F812
+:106A5000ACEFB5ECF8FB02C23D796094B7A8B14742
+:106A600014BA1C80DBBB03441ED699E47729DE08E8
+:106A7000F6EE4127ED4BF073A2321EF675EDE357AB
+:106A8000D1AE22BF70FA68EC7711AE4718CF66C15D
+:106A90001CBEE9D8CE286F28C9DFC5F89D63646F96
+:106AA000A952CF859F6F463F2AC36CDF99ECB52B67
+:106AB000573FDFDC5C487E079517DDDB467A70A523
+:106AC0004B96575319D6AB28FA3D6C97C387FC04F5
+:106AD000DF07506ED88D05642FABF9E0D202DC657C
+:106AE00078FF21EE0FEC726C427B16FCDAF92E5324
+:106AF0009CEC8CE7782E2B4CD85FD8D25FEED7EB8E
+:106B00000FC6EFC03C23595FE65D1F55F9773EFC89
+:106B10008E0DEC7C370CFD3FF88283EE2591F72C2F
+:106B2000C7F3EB9464EEBFA3DE30E773EA732B0286
+:106B3000C89C523E1DD949963C7029AFDA85E124A4
+:106B40009FF2BB5793F8FEB1A60528AEA65D282498
+:106B5000F9DF2AE8DAD2685C629CB43EC61943FDCC
+:106B6000F43D4EB1D0134CEC8F6986F91E99BEE40A
+:106B7000357E3F305EBFC9A7D46FFB44FFF392ADB3
+:106B8000F1E5AAF5ED4790857E680B55248FC7BCCB
+:106B9000AF77BCB814D7D8A245286F77F67E5F8749
+:106BA00093FBBE8813146CBBE300B26B4372684363
+:106BB0001294AB92C53E4036AC6B2AAE5B3C6FE99B
+:106BC00011ACC7FC8690EFE1A9A8A7669553FCFA23
+:106BD000B9E4E06FF0BB7B671753AC40C2BDBA911C
+:106BE000E7DB497DE9467C417B87D6C0E39EEE40EA
+:106BF00014ED8B0792DF9CAA211F6A5C0E96AD3EB6
+:106C0000B012E3224ECD4F7CE574DB7CB8BE3BC1B5
+:106C1000BFC375AFC96DA378D20ABC07380FCF1BAD
+:106C2000CC34505E9778F2B3D845F4A3762153E87C
+:106C30005FEBBD3A7FFF71D2E9FB5EF7F71C9C1456
+:106C4000C5FE343FA3FC1944C2FB26BD2AD7F5F884
+:106C5000EFE2FB97F894F8756821C2AB8E76430299
+:106C6000B89E4CB6EEDB6649FD99FA564114DED665
+:106C70002A5D5EB44F402F3E897C5237AAFBD78AEB
+:106C80008FF46926B767C2F2BE02CBFD48322EAF41
+:106C9000BAB95D23E15FF2CA834EF3BE533CBCF147
+:106CA000EBA5BBD09A9FE11C9814775F70131F4728
+:106CB0000B12DFD827079C28274DC61803ED9566D1
+:106CC000CDF7DB00E595D8C96E063BDC32BE7CDE35
+:106CD00027EE073E26ECA8F87A8FB84F39FEFD67FD
+:106CE000C27EB86FFFCDA487FBA21F1EA846FA7A0A
+:106CF000F29981E773EC025EEF25FAED8B8FEEDF00
+:106D0000CFE3BADA4467045DACF8F1547B3080E736
+:106D1000C9D4D18CEC5D75101F1F6869605CD83BCD
+:106D20002E8D0D37ADB3F70E9DCDEF77CE30E87CCD
+:106D30009FEAB10513D999124F8792E53D159C6FD3
+:106D4000B225DF0CFB3DDD836EE29BEE447C7328B5
+:106D500099EB2B84C34CCF7B87E66725A24F4C2F42
+:106D600072BEBA145F7488FB126B1137E0DFD488EF
+:106D7000F3F6A7C53D41F393C57D4106B78BE5FD0D
+:106D8000171D5A2019EDAAF93DFBD4013A9752E399
+:106D90000AA44C42BE3CC6EDDE8F4AF8BD651FD941
+:106DA000032988E78F8EA94A13EDF3F3BC40996756
+:106DB000F591DDB77A24D4DFFE5335D044D5567B28
+:106DC000EE340B8CFD17B46F77ABB47F94F7C03CF7
+:106DD0007514B4AF00430FF9687EA93B8CEB6FC705
+:106DE000EF1BDE453D74FBE30EDF7218E7D0FAB10E
+:106DF0005F60F9E41A8FCF4171B27C05EF155FBA7D
+:106E000036CFA0FDA3654CD81943CB4B8732F6147F
+:106E1000FE53C69D9D74CFB8A80FB694C1FC4666BC
+:106E200074D8DC0053C41D6CC1734E2B9B82D9E80F
+:106E3000FF5DBFA6A005E38F999981CE6B411FAF7F
+:106E40005833BC1CFDC18E47457FE1112DE8EFFD95
+:106E5000D216CA53A0FEA93553CA292F7788ECFF52
+:106E600046AA9FFFB32BBE386E204E2BCB31665601
+:106E70003C57C2535B5E0ABA7DC164595EA2633956
+:106E80003D9959E260F6983F4971B68E1EFFF1AE0A
+:106E9000728C83DD3EA5A15483FEF33C3F6A290436
+:106EA000D198D0566204F0CA5CCF03E5C919786B5B
+:106EB0005EA01AD793919E75E5389FF47ED6FED3D7
+:106EC00055114F65EB5BB0BF1EF8C2DB5A30BE2ACE
+:106ED000DBBF7EDF5B2DE18131BEFF56EC7EA56F0F
+:106EE000BA33E8DEBA231862CB5DD6ADF37C5E918F
+:106EF0007F33B0AB88E71589F2F02E9E772DCBD982
+:106F0000BCDCB13CF13AFF132F97B78EA4C4F53F18
+:106F100076737D0170939E4F39CE02DB13C8518585
+:106F2000DB4DED0E839DE74C8BC9D3F50EC6266273
+:106F30007E9393C329FB89FFFE6E310E0B5F9F8604
+:106F40007C3C53F0F910BFC2F394762747F0F71852
+:106F5000C0CBD2BE0DF3D926E211DB5CEC7BB36073
+:106F6000E8CC2416C27B7332FA41B990BE0FEC70A4
+:106F7000C7FA7B8D8B309B3A24B805FB9B9A9533DF
+:106F80007A455EAC1F80BBD939C602B736310DEBEE
+:106F9000C3FD314ED283CF423E0FE013C2170CF334
+:106FA00034FE7E4047E7C87CD4BF2331E9C6A4E75E
+:106FB0008B3B67D3799AA55EB13FE2E3DF6794F23A
+:106FC000BC97EE1793F9FD99CECE02F37ED6C36E31
+:106FD000916770CFCC87E91C74A79DD1F9851D25D9
+:106FE00017CD3BACC1B89CC96EACD1A2E48FD560C3
+:106FF0005C6E2CF6F71A9D3FC47E7C22FE8C71B528
+:107000008C1589E92FD7C19A0B060BF7EBAD2F63CF
+:10701000FDA7B3F0D84BCF2BD69FD56FECDD9F2EBD
+:10702000E2F802EF9AC0BB9E18CE7D924F01DF3688
+:10703000137F2D10FC26F703CFEE1AB1C9BCFF2A2F
+:10704000CF0D817E7E1A7F1F21DC9944FE4AB11646
+:10705000B80EDB1777A6D1FE80E40FC91792AE1DDC
+:10706000690D146FE97E44A1735CF1701D9670ADDB
+:10707000E7F7F665CD0DA9E67BC6A53C40FF1DA24E
+:10708000FF7113497E1EE3F20072732BCA2FDEC319
+:1070900082F3F07715997F8F40C25F84BC389EE8F9
+:1070A000C8F1FF824BE4AF70BCF5C67FFF4BD03315
+:1070B00097E859DC7980E659D387DC5679BD3C8F57
+:1070C000ED78D4EB83766304FF77B4BF4FF78A750E
+:1070D000EC5699E2E3F346BD55DCA38FC7BF3C05F0
+:1070E000F471564F19F4A50FE9D0A33FA34E67AC36
+:1070F000FD77BDE3A735A3BE14F7F6A6AB7834370A
+:1071000006C79FDCDCBE9A184A1CC76AF07A2C7A44
+:10711000EC916553D8FB30FFABDD3CFF6A625798BA
+:107120007E5747CA75BC9EEAE7E174343CFF97F48A
+:1071300094EB127ACA25F5147F7F186DDE31B8BE44
+:10714000761529603757D80299E87F7D70EC8774EF
+:107150003E6591C8CF1985F939B86E1E0FD2BAF2C3
+:107160000956F23C9D819E0CCCD7B6E6E9B02DFCC9
+:107170005C6B3C5FC5F8282CEC370187580FAE7765
+:10718000743DCBE3195679966580B3CE36C454EF7F
+:10719000E6EB96A403D0BB99EE3916727C6257D603
+:1071A00046D4B7AF7B789E4DFA90C0689CBF944B95
+:1071B0005857059FD8BE37DBCDF5C6EC04FC3BD94C
+:1071C000C3F5EC82F59C6F3AFEBDF43AC47BC7EB85
+:1071D00069A9CB4D7AA24CC8B1EC57EA21F99DAC14
+:1071E0009F22FA9BE6E17251E6E67C877024CA276B
+:1071F0002833ADAFC43FAD9C7F60BE61337FBF2EEF
+:10720000FA8DE153ACAB02CFB53AE017F0B7CD1E23
+:10721000EE8FF949C59D36EAAF62B787F2322BDAB5
+:10722000391E2BDAF6DBAA4DF889EF6FA987CBD18F
+:1072300046710FED611BF01BE2DDCDE13BBB2B87FF
+:10724000F4E7220FB71B2EBD6E5C9E9ED928F2314B
+:1072500080BE94BF58FBD2808D563DCDFB4BEF17BF
+:107260005A81E7F0D21F667ECC29033C45F1DCFF52
+:10727000171EA177F4808EE76DBB1F61B41F3F6CB2
+:107280006E60B40FCAF541F71805FA2B68E37AB8B7
+:10729000781DD83128774EB92EBCB2DD3CDEDD1E1C
+:1072A0008FE51C61C57A8EBF6160FF3C8D4FE8E7BA
+:1072B00059B2E3393C271E6ABF06E34EF2FB564142
+:1072C000FF4BC1578CF08D8BC187FD53FE8A3BB8B5
+:1072D0001CFBADFBCDCE01E67E1FECE977FE14175B
+:1072E000EAF9B5B0EE9074860EE2B98B8A3DA90634
+:1072F000DE9300F26C437F478E5BA1C9DFCBE92AA6
+:10730000C67BC20B7AC69174FDDD33E6F96FF6B821
+:10731000FFAEF4EDD043349FEE1D00AF2F86978E65
+:10732000F679CB5DB84E1C677E5C2724BCC3E6763D
+:1073300079315FA45EAC1F305F1BFA2FE93FF5B1D6
+:107340001588B7CE29744F423C5F4B3A0D675C7E7F
+:10735000A49F361C03FC50DEE32912FA87919F7B21
+:10736000E2A5BD4FF37B2D385DEAE7723A767942AC
+:107370005F7832627208FA9CEE2FAE58D7A38FDA8C
+:10738000F9FBCEDCB980CF5F7BA49C5BE9921E6CDD
+:1073900077D125B382AFCFBC382AB28AD399C6EF52
+:1073A00068F7441405CFD13634A1BF2DF504C2636C
+:1073B000CE5792F0F4D091011D47C5DE0F9BCBFB59
+:1073C000AB0779473EAA511B941C85F400C557B3FF
+:1073D000500F4039AB9DB7637BF8FD0D124F353729
+:1073E00041A7E077FE9BA790E621F19535376AAB80
+:1073F00029C47CE503833F30D1F9A8D82F40BCCC09
+:10740000267F83EBEB1A353810FD5696E5A073A85E
+:10741000B00E917E39EC629A0BFA7B199EB82E4D14
+:1074200055EFA0734253872824C7A00164BC877E10
+:107430008FEBFA6B9379DED65FBE3F14E79991CC60
+:10744000F910FA718A7E9CB40E8AF5E05F73C1AEC2
+:1074500053627AF9B0A2503F87FFE1CA4D2B9418CE
+:107460005F627F683F1D56660DA4F5B22343240773
+:107470007559F2C97AAF675DB9586FF617D1BF8BEE
+:10748000F99BCA3DD380A7264C6F8FE295D34D61FF
+:1074900075DA3FC1B853C1DF74A1FEF472BE3E9CE1
+:1074A0001756BD08D73085EE573E92142AE4F7F4FC
+:1074B000F2713245DC2653E42BA3BD80CF8897EBD5
+:1074C000FF9129FCF903F1CCF4268EF3AC13F5F50A
+:1074D000E25EEB552589F3D9067A154BBCE57AB106
+:1074E0006F81F7FF7AB9DF29F26CF93E07D8F7848C
+:1074F000DFD27BE6D2BEDDE79D37A4F0FB1BB83EB2
+:10750000F85009FCFA26059F41BA3F2FFCA64AF91C
+:10751000EF1F18012FE637D52625CEC32E11F3AB6A
+:1075200015F3FFA891DFB7B000F7D3407F8CF5F2D9
+:10753000792C6AFB7639D27BD13A85F6D3E4BEBD8D
+:10754000A46FE506D5124F5F80FB69FDFE163FCAAA
+:10755000DF871F35CEE247C971E3FDA9138DD996A8
+:10756000B8FFFCB621E29E0BDEFE76E627B86F6F11
+:107570001D60D9FF63AD1997770F28F84FE184F0AC
+:10758000E9A46FE5FB138D4E1636C3F1F150CA7BAB
+:1075900018E80DDD8CF48DC191CCC26638D864FE3C
+:1075A000BB572E1E77053B9CFB2FF0DCE8263B9D4E
+:1075B000EEA9ED898381FE3052501F95CCF38E8F5A
+:1075C000F90D52BE6A2627F61FC6093F779C9BFB22
+:1075D000C729C7A53F9DE443BD28EDF1F8EF1A7A0E
+:1075E000F8D66A4F5E2AFE00FC1B36FB47F1FDB65B
+:1075F000887EBF3EBFE4F7C12F05FF257E77F1E40B
+:1076000010C5F7F0F221CC45995066F5831EF5F2CE
+:10761000F5FC516F327D2FEDEA8AB9D6768F63BBC8
+:10762000F1F84CBEAC788ED97E5786A0FEE3FDC93A
+:10763000DFDDC93BF53AE57FFE0EFD44E8EF584A31
+:10764000602BF2C71A912FBFF1AF07B36F477BE8EA
+:107650005FECB45F5FF2D8D21598CFEC6E570C3A5E
+:107660007FB4DB2A0FDF5CD63EB802F0D12EE8549F
+:10767000E3E7F3A8F147F5A16ECCAFE6E30F6CDFCB
+:10768000AF68267E1B58C9DBBDE4B55BE233FBB0B7
+:107690000CFDECF11AD26FD93F231DDB0734B40384
+:1076A000FAE3EFDD003CFD1B18D9D1FDC729D4FF5B
+:1076B00037C76D54F0F7B7E43C5B6DB30A0DF8AE15
+:1076C0003533D98FEBCD00237408E5ABE69D681404
+:1076D00097C709EF746AE85F8D320287F1BD9C9706
+:1076E0004F35FAA3DD9EFC0E87AFAD27AEC4D71B86
+:1076F000C6560B3B7413B7C7547694717B9CD6F572
+:10770000CCE5C369DD93F3C94C13EB46260B61FE50
+:1077100031B46F253BC5C9D7FDCCE5FCF7F2243D5C
+:10772000637EE68831E8670E5913D5E6C3772F6D7F
+:10773000B025BC5FE37D817798C7BBE6795C4A5F83
+:10774000C976F63EE28C92DF93A727F6DF19BB9F3E
+:10775000EA4B1E4BBF85E4B259A7FB1025FE471923
+:10776000C1CF109EFEED1B15C4CD0991577062D597
+:10777000D30ADA91DF5FCC0C35013FF5C8EBB29D3F
+:10778000832B4C7A13FA277A6C8CCB1397F116570C
+:107790000AF77FE61B4196329EF276C97F5EBC8572
+:1077A000FFEE469FF8B84C7C2995DC2EAF99C37F3D
+:1077B00077B4E4318DE85DDDCC7F77B066FB0E3ABF
+:1077C00067C77EC4FC28EF35ED3B940A18B77AFBF7
+:1077D0000E6581097F036A22945F7D8547EE3B44F5
+:1077E000C96E8EE76B8C17A09D72C4C5E5FD7489C8
+:1077F0003B8CFB10A7EDA11A6C773A27D98FFB942D
+:1078000012DF2FEF9846F71D78763AA2F86CB56D27
+:10781000CA7642BBD691BA1FF96894111A86784984
+:10782000D3821DF87D6ABAC78FFB183E071B43EB56
+:10783000F565E261421C3F4CF81197939B52BC42A4
+:107840002E18E53D5D9BE291F613E9A723763E8F66
+:107850009D8CC31BF106C6A5201F1EE5BF9BD0BF94
+:1078600026AA60BE48FCB8317E0A5C8DF05F3E9C63
+:10787000ED3AEAF56AA1674A1EDBA2BC6F827B067D
+:107880001A55C89FDB372A1827837AD233D09E61D6
+:107890005E52FFEDDC2FAD86FA0526BD22E7914052
+:1078A000BF04713EEE773A0F71FD12E5FB0202DE76
+:1078B000787ACE4DF1D1F8E5601ED07B3D3C1CFDC1
+:1078C000E223F949D49F94F778F99C2BF8BCFF8602
+:1078D0002D8ACD4DFB2764474AF864BB6329534288
+:1078E00088AF09D33B090FB51B349ACF543D38F408
+:1078F0000E933CD4A5703BEEC04DEFD2FD3FEB7E26
+:10790000718CF8B116FC69F227DA8EE937E0BA1209
+:107910007E52C5FDAEEBB849C21E12F7625DD7C1FB
+:10792000F56F6DC70E0DEF91947C9A77EA00DDA795
+:1079300055DBEE60E84701FF2D45FCC4F3A9C48F79
+:10794000D4AF7DD113F410F793C2BA88E785F2D093
+:10795000CF91FA3922EC51E6E6EFD78A79C5F827BC
+:10796000D49262D1AF2E928BBC53630E605E66AD33
+:107970005FA1F392E9A5E277C84C7099FDBE78FD4E
+:107980008871C320F7E373679BCEA9F5E879F1FD11
+:107990003AA4377F1FE5EF593EAED712FE78FA457D
+:1079A00053B85E4FC0678FE13CE2D731B9AEE73DD7
+:1079B000BE53C3FB9224FF5C877437F1CFF6147E6D
+:1079C000EFEEF6148DFA7FA884EF3B3E64E7EBD729
+:1079D000434D4ECAA37CF9669ED7E5B9458FE2F3C5
+:1079E000B06D7E0DD61FEECFE168B52DA773772061
+:1079F00097CF205D0FDCE4655C3F727DB8EE79AE19
+:107A0000CF6AC26EF2736B42DFA9A07CD774979FD6
+:107A1000EE010D1DD26FF0F4E62BDFCEFDF4FBC7B7
+:107A2000D7B573F99374007D4AFC25E541E23586AC
+:107A30004F8E77294F921E11B9CF03FCC2ED23EE72
+:107A400057158A739195CEC011BB0FFD161E7F2D61
+:107A500014E72365FC75BEA04B912DF81ACEB357E1
+:107A6000FCF532FD83EA65AF8EC0DF0FABCA3E4A3C
+:107A70004F29B7E0BF5AE4FB6D41F703C25F3C21D9
+:107A8000F444F5B87692CBEA0F1A489EDDD3B95E7E
+:107A900073BF63D5C78CDD27E6BB86BE9B9ADC5ED1
+:107AA0008EFBC7537FA618E8D7F705E7223C2F8641
+:107AB0007EDE8683DE79885FF13B52F25CCD1F85E6
+:107AC000DE39BD4D15BFABD9A05FCCFEBE547F2CB7
+:107AD000FA8642F79A08DFF0F4F6D2491FA27FBA7D
+:107AE0002D857EE7E4D3EDDFFEC187E9F83B22D7A1
+:107AF000FAD14E485F1124FEE9CE70F937F178ECE7
+:107B0000748C5735B51FF4E2399C4F9EBE6A0CEA5F
+:107B1000ED2483CBFDA9E7D5658897FF0324F17B8E
+:107B20003E008000000000001F8B080000000000E5
+:107B3000000BD57D097854D5D9F0B973670B9949F5
+:107B400066924C36B24C02045412262161916D9219
+:107B50001016599CB014906D640901421220ED87F3
+:107B6000D57E190CA5C823355A1770EB049762B55A
+:107B70003568B441830E0808553F47848A15EC8860
+:107B80001441423245DBE25F5AFFF3BEE79CCCDC96
+:107B90003B1350BFDAE7FFC3E3733CF7DC7B96F798
+:107BA000BCFBFB9E3377FEEAF9B1A38A0959ED9538
+:107BB000120D8490CE5DBFFC577A1221D54FD65955
+:107BC000245A6F7AF6757DC04488C6DBC29EEF8A60
+:107BD000B7C07BE79FB8772C194CDB5B9BB0FDF3FC
+:107BE000275AB0BEFF57CFBFF67FE87B35AE3807C8
+:107BF000BCF7F98BFBF4F0BCC6AD75B6D292B80FEA
+:107C0000E8679B69E9794626C9844C21ECEFC1DD20
+:107C1000FBF4F67C5A6FA5A3D2EFC95CBD77400E8A
+:107C2000FDAE75B776A909DEF0125242C7FDD5E266
+:107C3000916EA8B7DB08490B3DDFA2271E63022D1A
+:107C4000FB101243CB0BA5268F144FD75566DA02D3
+:107C5000E585DFC4CCF5D2EF6AF5813C2BCC6730EB
+:107C600071423DD5A2C1EF6B5AD7EA6A4DF83DF695
+:107C7000F3071D2150E6130F393B88AE9F9027BFB5
+:107C80001E0AE3FD96101BBE3722A68890390B3ED4
+:107C900091603EB183EB75AB719ECFB276BAEAF0DC
+:107CA000F6610D743C3AEED7F0372E5416594C3825
+:107CB0003E05087E97DE56996187F527191CB07E30
+:107CC000B1BEF46A7793993EBFA9C1ED90ED84BC33
+:107CD00072EEE884BEB4FEAB41D250195E97A5C5E2
+:107CE0002EDA7FADC784E3ACD950463EA5F31D0F15
+:107CF000BB48BF4FB690A41BE97A2AB424C9042517
+:107D000021C77445D0FF53D86E371027A178607F04
+:107D10007DCE531BE9270FEADC6925D0CF16BFDEE5
+:107D20000EE5936CFEF47B8BA908FBB3DC08DF1B2C
+:107D3000C93AF8AE7BE3D4A4AD12F6EBD72584E6BE
+:107D40004D48306B763EEBAF18E034C93317DE2771
+:107D5000763DAEEF737805F7D153B0301FCA6D6C26
+:107D6000BE1AE2067C49D6D312E1EACEA9A478B3C2
+:107D7000C452BAD052122A93FBB076355C5B78FBC2
+:107D800027162796645722212323DF13A580FFFEA1
+:107D9000395DFA001DF7FE573F41BCAD05BC85F1CA
+:107DA000DD67F4B00E81B7CBE013BA0F0FEEF90424
+:107DB000F17659BB84F0A96D2FD52FA5E58546270F
+:107DC000F9544BEB1CFF1E94025580D79E3D319613
+:107DD000A7289CBA047E367F7256A6CF73DBD3ECFD
+:107DE000123CDFC3F0F4A046E301381DDC79434BBD
+:107DF00093143ECF8D081FA99A209DD4D613AF812E
+:107E0000B6973ED6707432ADAFA9260E039D57AD1E
+:107E10000A8F721E3FBD19F0C55A438A63ECB0CE7B
+:107E20008F27F4A5FDD7D69012A0D3F4F1CE3D5004
+:107E300027ED121900F56AD73218FFA6A4950E99FE
+:107E4000F66F1DEF6A83F16E4A1AE390697F0F6641
+:107E5000B66E36D2764F05B13C0570D0359769695C
+:107E6000FDC10ABB854292C2EDC954682783F48ED6
+:107E7000A7008FDDCB6AA0BFDAD4F90EC09308FA51
+:107E8000DFB37110CCB7D6DEC71143DF9FD22E21EE
+:107E90005E118F89C0FC6B297CA13EC53BCA0BF3E8
+:107EA000B9C8E127E0D8A5F32F82F975BD64201E7B
+:107EB000DA3E653CC357EBF856E41F6FEE997858ED
+:107EC0002A08E1A5F965830FEA095A8BE400BE444C
+:107ED000661A603E4BF97C9A7564B18B7E679DC4CF
+:107EE000FAE977B784FCE259A0271B941A5EEA39B5
+:107EF0009E37B3D2E22970517CB8C8F71FD184F6FF
+:107F0000BB9AE3CB9A653EA4A79AE7587F490667D8
+:107F1000E1FA30FC4D2A2748C7BB62C8E24AFA7C26
+:107F20009795956A7C7D8FD375CEE3EB70DF97D202
+:107F30007D877D4DBF9B3E07B851BC00B8D17D44C5
+:107F40003CB8296905EEDBD2BBA55B701F3DC308B9
+:107F5000D46D896C9DEAFE8FF3F5ED8A71154BB4F3
+:107F6000BFA0CDECD829C17C9C9A18A8175A1D3BFC
+:107F7000097CEF7A12C6B3A5C4389AC2F81521AEAF
+:107F8000620D1DE75CB299EDB7F75DED8C7CA04703
+:107F90003BB6DB64E223C87F48AE2B3FF45D453F30
+:107FA000D65F05EF6F6AB3A780E43278205C383C77
+:107FB000BC1BFBCC0DE7A71F717878AF2373816FD3
+:107FC0001CD4139311FAB7D071687FC93B473DB1F8
+:107FD00015E7D784EB3A60B1605991E82AAEA7FD66
+:107FE000D9FAB91A002E629D6A782CE1F0D83F6761
+:107FF00051A106F07896C9017477FFABD212C46B19
+:108000008F911225E03DA34342F703E882B8B5B84B
+:108010001FB5F52E6F74BCAF443AAB4D8A71C4489E
+:1080200088F74E947F1E9397E13D937FB19398BC60
+:10803000023E59991FC90F049F01F906F82CE8A2C6
+:10804000766C200FF6F79BF2952E1DA3F32E0A07F0
+:10805000A0234137E65718BD6CDD682F85F6AD9437
+:10806000EEC3F7FB90DE83F47B28B78F03FA8579A4
+:10807000BACC21FEDED7E28AB752F8D56A7C9BB52E
+:1080800039217E5CFBCA5D79EE28F827F8B151CB27
+:10809000F89CD11BEB65FDB2F18C14DCE6222C3D83
+:1080A000208F623730F8A8FBC9B50AF96AB49CA1E1
+:1080B000727C3ADDA4F87E844CD2B873613E6B8C3E
+:1080C0008143746749D686A01EE6910CB20BE8671F
+:1080D00067AC17F856723271BF10A5DF242BE3038B
+:1080E000625F9A13181D25C7B1F7C75A995E516888
+:1080F00065783991BF2FE62FF0DFAE717F42E4DE65
+:10810000E598F88ECE0BDBC57CE8F75B0893BF38AB
+:10811000DFE43BF3766E0DDB8F101D5D5704FBD45F
+:10812000EF6E9F768929348E90A7EAFD87F903FDCB
+:10813000C07A2A07F7FE5EF33E468F6A7C9CCEF536
+:10814000299395B0F774BEBF225DAD35939D30BFC6
+:10815000EDC49948E755F7DA40460FCE601EF4FFAC
+:108160006682FB19D88FE1E3399ED3E733E8F3D574
+:108170005AE231D03D59BD4BE70D1819CD7C4DFF6A
+:108180001B97C0FAEF361B3D32C5F30F13DC0BAD66
+:10819000B4EE29230E1FC8A51F53FE01F4477C250A
+:1081A000C05FEA48200EE05C2BFBF308DDFF2BB13B
+:1081B000EE25F0FE698D3F0B9E1312407C3D191396
+:1081C0005740687F6D7A5FE67FC1BC8FC86427ED3A
+:1081D000E712714E81755CF26B123C741DA7DADFF9
+:1081E000FFCDABF4AB85AF5E5C783B40696BECA236
+:1081F0004768B9C0A8316A8786E071D21C9DBFFE6E
+:1082000098E385AD89E95DC18D062FC047FDDEE4A9
+:1082100004F65EDDE574E2490C7FCEF8689D36A871
+:108220000715B2EE7216F1D0714F6948756B143DA7
+:10823000F39495F1AF368AFAD1DA4F733CDBA5237C
+:1082400079DB613E2D940F02FCB476E417D5BFC8EC
+:10825000716CA5D5B6DCE021D023820F48C8FF4F52
+:10826000EA18DFA17FB38CC342F213D413D00FAB53
+:108270002D1E9F86F28DEA06B34F2EC0E7DAD1B0ED
+:10828000771E8B16F8E0122E1797D6BFF995144774
+:10829000DBB5C4389A7EF79969591C8885AA1FAE48
+:1082A0004F06E53B654133D22768B4A08F4BCEA97A
+:1082B000F2D7B157D3E7B4A8B723BED0FD9D96E05F
+:1082C000F2C27E2F8867F05EB03ED6EB09E37FB343
+:1082D00038BDAAF16C17E0289DEFC712932BEA7105
+:1082E0005E4C289B0AFDFEC3EC7A16F077C1FA8B30
+:1082F0000A7ED625059E7E04F071ADD9F114EB36C9
+:10830000CB15462F87C5B89735B87FDD85FEBC0DE8
+:108310003980F7C1AC0F289C5777182C1E3BB4EB63
+:1083200015FB7FBA9132BEBC30F974AEFF04620215
+:10833000F83B36033E2CDD124B3C8342EB00851BA1
+:10834000F0BBF632C17E9674BC7902F879AD368006
+:10835000F8B3C468C2FDA9BDACC579902DBACE8072
+:10836000F89ECADFC438E721589FE767A3AD676F5F
+:10837000A00F53E8735CBFFB6D78FE506C1C71322C
+:108380007AF10EA4F3BF64B4C7275078D5E9297EEB
+:108390000CC16E5CC630FD8A649895FBDF71E42BDE
+:1083A00098CF32A35B0FF27EF9DC7A3DD0E582787C
+:1083B0005F896570F8BE8F96BFBEE19BEFFB6ECE06
+:1083C000874EE9295D44A1C3D39C2E26034ED2F2E9
+:1083D000543AA39F5359A4FA0528AFA725FDEE549C
+:1083E0002EAF17B1BABA1F7D02A39F53054C5E7919
+:1083F000D631F9A17EEF32DFEF6909CE20C04D3CC6
+:108400001F93C09EBF98E0FC02F089F2C3BF737C4B
+:10841000F559697F0B5E3720BE924DC13CD8C79E8F
+:1084200075E5F1F926479F57DF04B63EDAEFBF60E6
+:108430003CFA9E13F5F6D762BC608790A9943F037F
+:108440003F5E9749801FD371F50936ECD767C5F7B2
+:108450000CB80EB285F2698AB7DD2576DC97ADA53A
+:10846000143F814FEC3558804F087C127814813FBF
+:108470009C8F09397C33C86119E570624209CA6171
+:108480003DD039ED51CFF4C1FEB8DF8867F237DF58
+:10849000EFBD46B68F94DE3313703C5F7E38BD0966
+:1084A000380B3E79AA8F122F9EE27C70007FAF07B7
+:1084B000CE09ECBDA47E4CEE09FBA084EFFB335645
+:1084C0006529E4D8F0494ABDE4198E6FCF58E3C45A
+:1084D000BE1402BC85FC8BD8EF47D97ED3F786C18A
+:1084E0007A1618828B12A9FCFA01D58BF445F8DDB7
+:1084F0006EF82EC24F319EC9DDBA7566027A81339D
+:10850000C1C2E05F1CCC82FEC8A020F2A12584F28B
+:108510001BE9DAFB073E81344A23D3E298DC9164FD
+:108520003A20D0CC206287FE28BCA784C35B3DDE06
+:108530004968A27AE0EC04497B16F6A89014C27E42
+:108540002D7AEF0BF342DAE5458BD1A3A172E487D4
+:108550001AF73CE8A7F3B623A8F79FD4FBF29A4D8D
+:1085600051DAF5BEC71F9242ED8B9F913D7ACA67E3
+:10857000DAFC9D0FCCA178B9C42F3B60C82577FCED
+:10858000F59DE1A04FFB750EB06BA93E71B796CE7D
+:10859000FBA486ED27A957FA051A38BD50BD4A4BF2
+:1085A0008685F893D00B5612DF00D01F9612A71EB7
+:1085B000CAD36B574C25145ECB4D0DC8B7CEAF9BBD
+:1085C0008CFA7215F160FBD22DBAD3E1F26479B363
+:1085D000B2BE62BBB2BED2ABAC5FF811C3B748BC8F
+:1085E000677A98AD3CBA7EF118A7B70BFAE8EDDBD5
+:1085F00038DE96FF6CEA4348FF7E1D31503C69D857
+:108600005B9A42A2BC2FCABACBB9C41B268742FAD6
+:10861000471EF10E85FEAEA03F10FA013BB721C602
+:108620009902F6C885B2E8F37880CFA3EE729F5E18
+:10863000FA8DC37E2FE45E7D9D75978DF85EE4F71D
+:1086400026EC97EA5951BFFFAD805342F4F65FF72D
+:10865000CC2F15E562E83BBB4AFFCA40B95A77D92F
+:10866000A290D3A1F6242657B99F80EEAB07F562FE
+:10867000AEF7518168391B1BE263BA3E6C3E826ED5
+:108680003E9588310DFD6AF7723BC25100FAF1A7A1
+:10869000A07F01DD4EB4BF16A0535D7AFBC83C6DD0
+:1086A0006E88AED4EBA1F8F879204C2FD89F604E9D
+:1086B000C2711DC401E30A7A58745B45BC9BEEDBB2
+:1086C0009FEE284F710F0EC73B0F8E5FAB177A9F3F
+:1086D0004921C7894ACE2F6D3F827ADD32A32B0F05
+:1086E00098D39FF7DE867452455CC9401FDD7B0737
+:1086F00066B9FF17F25DCC67A6E7561DD3E3295094
+:1087000029DDCEE0F399D9C1F44A8DD1A9C3719C7A
+:10871000C46E4946539DCD9732592DAD8FE9993F8F
+:10872000381D0919CDE72FC1F714BE63784996B8F3
+:108730005361DE0618978E1743BCA950368D74D846
+:10874000A11C27B9B46C1E5EDCE709A43E03DED78A
+:108750001803325B279D41327CDF032FAC9B797D70
+:10876000D3AC4B8B96C3739319F98F9ECF434EA412
+:108770007C7310F22523ACDB60F29D87759979E953
+:1087800029637ABA2797389AE86B7D482B81714D17
+:10879000A68B1E58AC855824A8C7582EF9C05EB9C0
+:1087A0006831793443909F1A12819F4A6F57C1BE36
+:1087B00050FECDFC57BDB56B7D682709FE98C0E71C
+:1087C000D7C4F9631A61704822AE7D4E8AD7F799F3
+:1087D000ABA6923810E36E1C7F47DCA4C3305F0069
+:1087E0003CCAF949DAD3E172C6E6D22AF85FCA5C1C
+:1087F000653DCDADAC1BC9490BE8A392CF95FA7589
+:1088000022DA7F83C09FA3E3FC66561F362F813F89
+:1088100079899CBF733DC4C5FD01B5097A827EC4C8
+:1088200064A3910C41BD242F91F9073EA63B4DED69
+:10883000C620F2F3C271CE010F50386F7E4F76DC46
+:1088400049F769B3D9BE510BFADE3C89E9F7DA562C
+:108850001FF8875A16591D5BA13DC679CF3FA1FD70
+:108860003D9980BE55077EF94478D1520ADFB56440
+:1088700059F0BDA4F220FA53837711D4A722F0F463
+:108880000A9D3F85F713880CB49F6596D5CFD1F725
+:10889000D35CB10E29ACFD4968A7F394385EC0F3F0
+:1088A00071C3C0FE657FFD3A0AFD4EF06F386594D6
+:1088B00087751D856F98E83CFAB90B1D80B6FD3BA6
+:1088C00078FC25C9E065F1074AB5741EB38D6C1EAE
+:1088D000751DA53797D0F6FEFEA104E210B187ED15
+:1088E000F36BA04943ED6EF8AE2C16FD5EC7B8FFE2
+:1088F00089707E305C456FA342F88FED85A24ED51E
+:1089000006E730E6D6C07A12A30307117F8C3E6FCC
+:1089100024A13FF8BE3CD41FF2A3F1A1E610BDD1C3
+:10892000A515191D4D35F4BD839513110FEBC0EE40
+:10893000A2FB315CEBDB07F43D8A9785BC244B9AA4
+:10894000119E5B37FAF6EB72C0D5E292A13ECC7273
+:108950005713F43746F2619935F7DE2640AB7DA018
+:108960009C217EB92B801E3757100BE85F4D231CCE
+:108970000E0B6D9A3397F96767CF357AC1DF3F5B8E
+:108980004B585C4CEBCEF901A5AB1F2C607E61A867
+:108990002F08F3BB8838C8316AC7EC8EA20FEC4BA6
+:1089A00064724A7C5FB749AF8837ED4D3461FB1381
+:1089B00089133C89A8A7B97380FE3627727D6C1095
+:1089C00019047C258CEEB722DD97BED51B5F50B60F
+:1089D00073BE30DBF90B1DEAF19C3F083EEC023A16
+:1089E000A4DFF925A70EE0F7611983FFD1D295C85E
+:1089F0001FE610373EA708A27385FB9B2685E94337
+:108A0000749CD92EA57E3467AEB22EF0558C3BCF28
+:108A1000AD6C9F21F4DB494AFD76C17F5DB1A21C9C
+:108A20004C797ACDD7D9185F413F411DDD27165FBC
+:108A3000D1B278CB26BD17F4A4BAF6B5076D40477E
+:108A400077104E47BBA56518FFD92D2D0FD323FAFC
+:108A5000D67825E0FB03E99AFCB8AF418C2B1DD3F7
+:108A600079F741BCE5D84ABA623ACF37F42C6E792F
+:108A7000208678C06F2DF0D33C83F95D291A63FC02
+:108A800024C312EB007CDAA229423FED9638B323CF
+:108A9000DC2FBA7523C5BB30FFACDDC0428CC77A72
+:108AA000B17F8F24323BE74189F9C93DF38C68EFF0
+:108AB000D9FAB91471099B4C4E80BFD19368473CD9
+:108AC0007A90FB4320AE3794965E89E9333DDFCB45
+:108AD0006413FA2755FCC796E8C0B8802D3E1FFDE9
+:108AE000FB733B0A9F447E638A710C9042FDCF75F5
+:108AF000B7689783FFA0A345BBCC14C2BB93025FAA
+:108B000063492CE06B8FBFEF0503FAFB7EA871056C
+:108B1000002F6BF4BE02A2C4E7C0D5E4D80A8E2FA2
+:108B2000BA32D7BCE5743EDDEFE899FFEB0E82F474
+:108B3000FAE21E2BFA2BB53308CA934DA504F1A116
+:108B4000BB4542FDED336B35DA019BA46694135DA2
+:108B5000091370FF56990EA05D5BFDA8EE74B8DE98
+:108B6000B5EA49657D35F1A35D5DF35C043E23FF05
+:108B700012FCB1B64DF91DE9AFE48F859CEF17B932
+:108B80001C332B60EA731DFD985D4D7C06BA8E92F6
+:108B9000B7F5DC4FBC80C94DF2B404FA56B7F99C66
+:108BA000CCE89CF1E312DE9F5A0E95707D6A2CE5AD
+:108BB0005B607F0AFD88BE8FF5039A0E3955139AC4
+:108BC0005731FF4EE865826F8B7D291D41C8088AA9
+:108BD000F7B9497C5F73492EEC2BED1FE901504238
+:108BE0009F80FD7BC06E1BC5C7A3FBEE0139EBD197
+:108BF00018BD80479BA57AE4D346C2F9B5E446BECA
+:108C0000FC3B8F4706B88E24F533A7D2F7461BFDF1
+:108C1000B1000F8A0F7949B6109E34115FD66E49A4
+:108C2000812FD8DE697D2B2ABE08F9E2FB90E91777
+:108C300053E88AA19F0A08F8D0F280C4ECC289A642
+:108C4000FBB5F0FD5B9AC9880F9388570BF3ABB067
+:108C500028F77962AAB23ED91E8107328CEBE4F084
+:108C60009C3248D9EE147C8D28F95A0EB982FB4CFF
+:108C7000EE3AF443F00BC46E208340EFA01A22D2E8
+:108C80009B9A1F4C4AEA355E3229294ABCA49BFBB9
+:108C90007F6F2481AAE7A4487CE93AB8414E0DC30E
+:108CA0002B81C7AFF0FC0AE9751E972D66FEC090B8
+:108CB0009C67F8328CD76E047CA3EFAF1478924D8A
+:108CC000B2014FC6B4C7F8640AD742DECF8D8037F1
+:108CD000452179EED398ECFA5CC00FC716598ED4B3
+:108CE000DB9313EC882743354EC49312E24884FD8E
+:108CF00019616C6DD2C2FCF70CEFEB3629F0620DF6
+:108D0000E28544F102E92A422E2ADB557823F6EF68
+:108D100030D79727124F7F188FB2B103A02FFB7265
+:108D200018DE541027E2C99BB99379DCDAADC57E11
+:108D300088521E961B9578A0C62B3AA2267C5C35DD
+:108D40009EF58637D98037421E265E1B6FEE49326C
+:108D500029F4EA30BCB927A9A477BC51E38BE027FA
+:108D6000BB632CE5A097D6554BC88787BED3BF09F8
+:108D7000EA03D7E460FECB6EAB03F5D6BA7AD65ED3
+:108D8000EC77CA901FD3AF81B7E7B8CAA15EB781AD
+:108D9000C5294A8EB1FC99FE77B0F6C23BEBDF30B5
+:108DA000837CF7B0EF5F39BF598EA3EDDECDFCFBBE
+:108DB000D2E672A8D76D61DF7F067126BABFC34EB7
+:108DC000789BE0F97577E73898F9C9F4D9711C4FA9
+:108DD000774B2FBC81DF35B3EF561C32F621A80745
+:108DE00033BD752C5FE7B847D93A933EBD69929D74
+:108DF000E2EFF2A007F5A6B39A9A61C86F7AB13391
+:108E00004BA5E60C2829DE209F711A295EE7B238AF
+:108E1000E44E3AC45B49CC9F21E277904F109E3FCD
+:108E2000F0561293F7E2BDE404C2E2CD0F9BD11FCE
+:108E30002CE28BBE87880474066BE4F23F6ABC7137
+:108E400062BF7A8C334ECC1671C68076091DB7F09E
+:108E5000EB2F2644F3A71C4D627AEA399E1F219E10
+:108E6000577B73348017BB0149D20148F5BF07BD5A
+:108E700009FDAF4C6878C808D857560F24D56CDD6B
+:108E8000428DF4159A7AAD07844C16B5BF68D7D3D6
+:108E9000FDC4171F1739FF895AE203F944B46CFE69
+:108EA000554D540E4A21BE345BB09DD103904E67A0
+:108EB000F17DBA28F8CD503214F8CD6CBE6F3F303A
+:108EC000D6EB98BC6CD6A9E8FF2F48FF3B7AD59B20
+:108ED00095ED2AFE50CDC7ADE2FAF24A1244BDE04C
+:108EE000ACE4C5F2DC0EA62FAF361D43BDA2FB617C
+:108EF000A627D69000EA1D6AFFE1EA5DCAFA9A56F3
+:108F000065BDAE5D59EFCEF7E038DD3BD60C03FF13
+:108F10005DF5F677D02F5C2DF88457C927A882C459
+:108F2000F8C443D7A3DF4663A47CA218C0D507F3D7
+:108F30004D86126722F00310B25FD3FA5DF0491A32
+:108F4000AD6B5C093694339312CF88F1658CE7BE24
+:108F5000E3B487F6A5C72E54F18942E18FE99F80DB
+:108F6000FE2AC1370AB95E4226A9EDC6FB91FE86EC
+:108F7000F25ABE8DFB53B8DD23F40CFA3DEA197E9C
+:108F80008DC9ABD184EB155EA4C72223951348424B
+:108F90000E23B3579A896A7F0B6D57B79B94EDAA3E
+:108FA000FD1776CB30BEFFF388BB2FECC72CE23A1F
+:108FB00008F2E1E887D50A7BE9C33F4E10FE14B4FE
+:108FC0009BBEBDBDE4FB4EF652CFBEC750FD919691
+:108FD000E533260F7800E2E36D3198F75927B17D2C
+:108FE0004E9E772C2BDC7F78B491D8B46174DF343B
+:108FF000D96084F860938ED91333A69C1AB6248C5A
+:109000006F3C6F2C9D0DF0DA2CF97FF411D81747C7
+:10901000648279351D36DCF74BCDF439C5B74B8FFB
+:10902000DEE0F0D0C717742CDEF899545F05A95024
+:10903000621E551B7E1FA3A5726C85EC7D2D00F171
+:1090400055C9FB720D6D3BAE772F85FE576B7C7A51
+:10905000E6B7F3639C54F4DFBB1FD2837C4CBF9F05
+:10906000C9C5A0D4C7C1FCB89EBCF078D39264E651
+:109070006FFA30C15507E308B927E20927D74E8CAC
+:1090800007D1F02571C6439C53D242CC2E723CC806
+:109090002BD814E6573E19133D2E70878DF1579843
+:1090A0003EF0F734ABF32736E0B7DCFE3BC7E35DB9
+:1090B000E7E258FC6B8B8DC9810EFEDDE3BC3CC73B
+:1090C000E363E7129476A378CFCBBF3BD368346ECB
+:1090D0000ADB4FFB43867A2FE653F1FC9106C2EC84
+:1090E000A43DD696AD61F1D0676DA51D000F5B3F25
+:1090F000A73E0DE0B787C961884743DC78A4C5FD6A
+:1091000020B4D7DA8913E2AEC41ED0CF84F823D8B6
+:109110009DA83F307CE98E61A598D7B3B6CA0E589A
+:109120006FF7DA00EE674FBD92F1C7676D2E1CB77F
+:109130007BB668E7F56D01BEFFCC7F20FCD9BDC5CD
+:10914000C3D4F12F2A38989E1DC3F8983AEEBD502B
+:10915000F0311EF75EC0F9D0C20EE61F5F64249B9B
+:10916000FBD2F6C51D29CC5E8CF3E429E2DE9ED845
+:109170006F95EF20F0B33BD3DF13AF7D382C5EBB90
+:1091800086C7FBD688F5B529D777C4D66BBCF688D9
+:109190002D4ABC569D17F032C8F7FE2178AEB3B009
+:1091A000F557C835E57AE013CB08E691AF3BB2B48A
+:1091B000C948EBEBEE02CF1FFC317D750D87576F71
+:1091C000F3B3B934C4AEF013F721F630BB38CD9DFC
+:1091D000A0A8A3061C9687D9B73A5DF17D667DAE3F
+:1091E000E2FDEC0DD72BDA733C458A7ABF2D372A86
+:1091F000DE1FD05CA6A80FDC7E93E2FD42D22F1EBC
+:10920000E3B18765F09590EBBC3314ED37ECBA45CC
+:10921000F1FD67A4FEC1D1F4BDB618260788C7E9E1
+:109220001F3C2C94779CDFBA44F17D93D43ACC4711
+:10923000DF5FE667FEF621EDAB14FD5D889BC0ECB9
+:10924000081E7FACA7FF181FB7CBA80FB54BE46172
+:1092500029321E59DD71EFE6BE2452AFA07F28E708
+:109260005751390F7A945ACF30279B93101FD24908
+:10927000FAD7617415C20313EA61971E95D19F5600
+:1092800048063E341AE1A3235E7BE47E5D22CCCF08
+:1092900073E939B303FC652B8E2C45FC33A42AF10A
+:1092A00020C6AEC483D8414A3C303B94FB1E3F42AB
+:1092B000B9EF6A385B9D4A3C107014704E9CA4C490
+:1092C0000B01DF11F41FC0B788040F619EB5577200
+:1092D000F84894786F7B0BAEE35A7ADB70153C87C5
+:1092E0001E703699104E2CEF4AE84906EE9F56FB49
+:1092F000CD85FE313199EB3DBC1FE1E7DE2C795085
+:10930000CFE989678DF065F97240DFA927CC5FE26C
+:109310009A926C8BEA57C3E7BDF9D5041C853EB31E
+:109320001AF4193ACE72E246BE7486EB332B4CF730
+:10933000635CF0C21F197CAB8917F9F5B78D978371
+:109340009E48C2FC8D6A384A1D92CF0C74C0F976D3
+:109350003AE9107CDB8D791314ED8CC314F105A56B
+:109360001E4A9C52387F127AA9184FC053F02D31F3
+:109370009E81D4CBA940072A3E4606A9F554A5DF15
+:1093800043F84970B0B038C6F09EF804B313437E7A
+:109390002FE6E790B3739A08E8DF16E1D7F0CF879E
+:1093A000E7C2AFA1B6EFAF15179DE991028FE44474
+:1093B000C643457C952EF3D38FE8C7A3257B268C27
+:1093C00037E3958136A289E697739C7895F6236BEF
+:1093D0008289E1FE32E1BF7E530AE0BC7F409C3FC0
+:1093E0002561FA422D699D303F07FC9F546EC541AF
+:1093F000C9FC3EA45DAD97B278A286AE04F07B3581
+:10940000098B17E684DAB12E47D6459ECBB5E4FB2F
+:109410000D2916EEEF60F93984F33761BFF5662F39
+:109420008978FE413D85495128AFE5E5646E6716B0
+:109430009002E89FD2D52BC9689F533A94C2E9AEF7
+:10944000270F06DB23E84EB57E11CF97CDC5E87711
+:10945000591ABEDE6F000FA147FC8BAE0DF6E7FE7A
+:10946000643BD6D7F439F907273417FB15F98C7507
+:109470007A963F4C5A95FAF3C7C91AAE4F38E56F42
+:1094800002A7DEF781E785F17DF8A6FA90C80B13F5
+:10949000F03B23F86008DEE7147CACC76EEB81F785
+:1094A000B9687C4EC0E36289FF69D827D97C2C1942
+:1094B000E0FC0FB3EB22BC9F79227056D284E655B4
+:1094C0002177623EE8A57619EDA4DA312C4FA87613
+:1094D0000F06CD49578701E382D5ED6FA07ED6D91F
+:1094E000481969FFDEE1D4B35E15BC7BB357C47A7B
+:1094F00074294A7C13F922749D312951F3017AE0D1
+:10950000A06CE77010794A15F2E0F840985D728817
+:10951000EF7B8CD6159F42C72F7E3F230EE0532151
+:10952000771C4A07383448785E699C8178C0DF9F91
+:10953000C6CFAD8D08D43B2C141EA919263C7F3410
+:10954000F087B20BE299A71AD627C0F9AACF1BE978
+:10955000D0D4EE1828695C886FE4858F7F5C0C712D
+:10956000B60598A7BCD0C0E2FF393F8AF5F5A37CC9
+:10957000E2753D3102BDE972EBF17C46D02AA3BD14
+:10958000912493F1805F02CE49B16C1DE279E963C9
+:109590004F4A90CF249E8F6B0A0E5D07F94CB0EFB7
+:1095A00025A1758E2B0F0EAD3785E02CF204893680
+:1095B0009835238C3E8E7078D4DAF49B411E761950
+:1095C000B91DC8ED4162D1221F69E0F1F69303A8ED
+:1095D000458AFDF8CC9097551BE38C1F0EFE2EC8D4
+:1095E00027A0C5971667BC15D76F47BDB981EB5744
+:1095F0005D3CCFBB6172590AD853BDE53F4D4D610B
+:109600007A7E0D8F838BE7355A1FE62DD540DE71AC
+:1096100058DED3B7CD3B16F9E6BDC2C1AA255A0A1A
+:10962000875A89B8AEF6DEABFF92A3DABBEB5334B0
+:1096300057CD835B952229F2DC6A21CF8D3E6AD813
+:10964000539A42A2F4D7236F2EDFA8C8271379D2EA
+:10965000B597C7623E59F9CF3AF19C20F46337853C
+:10966000F2DC7A83F3916406E75AC80F1B1AFE9C5A
+:10967000E151A8FF24DC875F0300C1DFD12EA35F87
+:10968000F6D7873593764699EF76BEFEEB6D5AA4F2
+:109690008F1B7CC4D912657CF19E38470270AECC1A
+:1096A0008F9C5F5B596011CC1FF257A38DB795E378
+:1096B0008B98775B42A08AE3399EE3E8A95B94FB31
+:1096C000F80CDFC7B69B0259781E6972F47C7AB138
+:1096D000DFC3B4F512C02360761F44BD730EAD0C1A
+:1096E0008173003E0DCBA36274D6DBBE87E0AD5123
+:1096F000E41546C25B8FFB2CFA1376C9F9ED32C62E
+:10970000FDCF1FE574499C2689D2D7AD5C6E9D279D
+:109710002C7E70BE59427B64899B900D94BFDCFA0D
+:10972000E46A8CDF543D357433882B787E07E5235B
+:10973000B7A6123296964B3629E3B7CBEE8E88D772
+:109740009070F948D54FB4AFABEE577E574DEEFE53
+:109750000BE83FD52AFD6620F777ED4DE1F6C230E4
+:10976000320CF8FBBAA7BED043EA6E6FF8FE39A5FB
+:10977000EBFE5AE083162CDF4D711E003EFF718A0E
+:10978000FB4DE0DBDDEF31385CAAB9C4F8FEA3493C
+:10979000286F0CC09CE9FF1AE6B338ECCF28BB80D9
+:1097A000F89BC1C0F41BA1D7C9F27A398EB68FFCE1
+:1097B000734302EC5FD2B3132781DE6F7B36D60989
+:1097C000F0DA5AEA2C043FC0D64A13E633180D2CBF
+:1097D000FEEBFDF5C8FD100EE8DF7A6F19D8A196F3
+:1097E0008E7D3EF0936CD1FC05CFA16C19CBF2DDE0
+:1097F000C438751D95BB613E59B398DCD89AE32CEB
+:10980000B484F54BB89E56CB61D6BD77E03D70FE73
+:10981000FD91C3A826D3F5E5A23FEE7AC2F653E444
+:1098200055C1D8E1FA6827953F909C27EAD7B74AF7
+:109830003E1D5DCF9AB6DD18C7A8B9D3973C1FE48B
+:10984000CC335A8C0389F925BD9E5606F11E215F43
+:10985000E64B1694FF42DF9E47C41F8B17CDE57879
+:10986000308FEBD9F363197C971047167C778B9177
+:10987000C4819F7A7E796B09CA9FD53A2BE835223D
+:10988000EED1BB3E10DD5F54FBB4999DA795827964
+:10989000D0C9E7D4FE20CC6F14F57C52522AE3AF36
+:1098A000B5795CEFEB4F9C1067AB7D6D600BF805F5
+:1098B0000C7D583C96F21DE38822D47B8D60CFACA2
+:1098C0007C35C6C7FCD65E7E6ED6590879217533C5
+:1098D000328A303FE104E51F66388F18C8423AA546
+:1098E0007C45A2B22D7FBB65AA16CE0DA653BD8ABC
+:1098F000D6E7A7664DD5527CAFCD0D546968BD69DA
+:10990000FB7056BF3E7016EADBB697B17A51A04A9B
+:10991000A6F55DDB5DEC7B30F02862BDB47DCE54F6
+:109920000FE813562EAF1D013C475CFBCA404DB8F3
+:10993000BFB22595F1A5CFB9DFF5F31CB27806C00B
+:109940007B5000CFA989F77E9A2AF45C96E72BD644
+:1099500029BE23A9D1FB1F9DCAFCC42BF9F9DF71D5
+:10996000B1644B0C8B5779E228FC0F740CC4785B04
+:109970004E6A028717EDA738D48F80A3E84F8CBBBF
+:109980000AE42AF05B1DF39B8AF6C9A98C3FD271C9
+:1099900036E1388319FC6B676414C2BED1FDD2F284
+:1099A000FDD232FBB385CD8FF66B2D40FE3E14FC0D
+:1099B000DE07AED0F77342F356E3C70F387EAC6CC8
+:1099C0006271C6A0B51FE2D1B858A6EF9162E53A20
+:1099D0007671F8B5A45A997DD5B31F29128ED3C4D8
+:1099E000E19841E19EFFEDD75DFD3DAD3B6CBF9C35
+:1099F000709EFF40FB753BC3D723F2B6453F9F6F78
+:109A0000547D3782E54FD526F4C3EF7E16438CF89C
+:109A10009CECECF92EA780E999A07F8AFB1D886752
+:109A20002C3A0B6A38D7E8B9AFA195E711F677B2AF
+:109A3000F3CA33A616F3F559F8FA2CC6B07B1A7A96
+:109A4000E8F158306B9639127F7BE0DED3DFE022FD
+:109A5000DE9F82AEA3F507F4D1DB7E3CCCF1E3DFE1
+:109A6000B61F629E2A78F6C059353F014FA067FCA9
+:109A70006EB0121FC53CB7A58ABC61155DE77CC7F7
+:109A8000F14AD9776B6EE3F9C076253EAF69CBD149
+:109A9000401C5D7C37097CEDB690DF6D6F2AB7DF27
+:109AA0003248462F7970FB52A3FBEBF0B9DA7EEB1C
+:109AB000B6B2FC67B5FFA0DBE6F0C3B93ECF457692
+:109AC0009E7D944ADF8038CC0BA6D0772179A2AC5A
+:109AD000C7A531F845FA838278FEB6D850F6A2DDE4
+:109AE00041C847DBD7207F2E8E2F5B9F43EB81ED54
+:109AF00075ACDEB7EC8B1CCABF4F6FAF67F51BCAE6
+:109B0000BEC8857AEA5A561FE77C51C608C2DAA950
+:109B1000E3D342FAC3A7A976A67F946B08E09141EC
+:109B20005EEB003929E0D95B596CD0D447D34F3B69
+:109B30007BE899C5294670F93C42D8E701ADC23EA1
+:109B4000EF8E63E793BB419ED2F5FE3DD5FD975462
+:109B5000D053623B17E5D0AEEE8CFD580FFA90E47F
+:109B6000A4FA06F83BEC16B200F2EA3AB7BA403F64
+:109B700022AB1C462DC293FB9FE8DABEA6FDBCFAC1
+:109B8000DA33B7F765C3B8601E2339FDD7BDF6D504
+:109B9000DF204E5AF7B9C901EEBD911D3BD6837E39
+:109BA00035B2E3ADAF98BC65E735C4BC47821F91C1
+:109BB0003E1FD16EC0F98FECB86E39BC3FEAFD8E06
+:109BC0007E801F634EFA9A801D74EFFD5D5FC5397C
+:109BD0000DF299F45DCE69F4C0E3CF54798A4778E9
+:109BE00024A6D9001E57305FAACB76747300F534D3
+:109BF000E57918AA97639CF512E9E380788138F734
+:109C0000ADF65B9EA8A4EBA3CFC704E90CC2F4E5B4
+:109C10007197A97D1FA6679712ABA25E6E4C53BCCD
+:109C20005F61C951B44F4CBD4ED13ED95EA8A84F1B
+:109C3000193452F1FE3447A9A27EF388C98AF72B62
+:109C40009D958A7AA1AF55F1FED0C3EDCAF6637631
+:109C5000DC87A1275DE5A0C73BFCEE262887773689
+:109C600097C7DB4984BFB638E06D82E7A3AED497CF
+:109C7000F84894732CABDCE8E78F38C752CACEC3E0
+:109C80007769D8390EE19FBD12EB9E9486FE590A82
+:109C9000760AECB1C66022EC57C5E26D983775299B
+:109CA00048D09FD5A60FFC7C14C8F98532EABD6D5B
+:109CB0003CDFA66D6EBE177C7A27A4C0CB10AFF731
+:109CC0002C64E704C6500D17D70DB14D09F6C9AD88
+:109CD00058772959A9DAA7B58A7A85E536C5FB13DD
+:109CE00053372ADA27DBEF52EDD3BD8AFA34C70E99
+:109CF000D53EB5A8F6E91945FB9833812620A37116
+:109D00009D1ED94CE77FE389E672D89751273D0B1A
+:109D1000815E8A7DEE2660872507EADF80D247EDE7
+:109D200029F053ED6F4CC5F240A31DFD4C871A0777
+:109D30006179B8D181CF7FDF3802CBB71B9D58FE48
+:109D40004FE3242CFD8D2E2C5B1B5BF1FD171ADBE2
+:109D5000B1A410CC04799194D8730F4326D8F35D45
+:109D60009A402D4452FF3B6D1FF2C5AE3E812EA896
+:109D7000DFE9791DF9E24A30A628BDB54049F7F37D
+:109D800067E94E299D96DBD2D873919FD0AA7116B0
+:109D9000827E7D5FDA91BBB59954AFDDE84AB55854
+:109DA00059DD48EBB8D998A775E46EE768427E03A1
+:109DB0002203832647A642BD3B86B56F4B3B82FA02
+:109DC000B58823CF0AC591EF03BA57C7917F73CEE9
+:109DD0006E067FCAD12B03CDB0AEA3DC7FE4248511
+:109DE000BA5B6959AA2DD4815C3CA1D2234459A7FE
+:109DF000297D04FA6DD53866637EF04D3A02F9E8A4
+:109E00003324668FF6E881E94C1E754F33A0BD738D
+:109E10004CE35C8E794F52F07180D78B3B3E44F817
+:109E2000759B83590087DD3B4EB0BA2DF8B8E40826
+:109E3000ABEBD83A7FBDE383A91E53D4753E9F1682
+:109E4000255EDE96C6CFC7FA9C99207F45FD58A5B2
+:109E5000730DC88963A5CE01309FA32E03D28FC78F
+:109E600065F642DE25D13A4B6687F9550AD275B8B8
+:109E70008E597A4667E41639EAB9F3A9E94CCFC29C
+:109E80007D037B6E5E2CEAE1C734D1CF8D2FE3F0EA
+:109E9000B9D027BA7F65793A93836533CDD85F7798
+:109EA000430CC671BB5D03510FEAAEA750A2F4D1BB
+:109EB0007DAEFEE24BD86E10212E8C57CEE77CEAA9
+:109EC000371DEBFF7A9CBEFF7143AC0379B8E57A8E
+:109ED000944FB7F09717261A516F593823B30CE4F3
+:109EE000D27C1EF75A64D62663F84B6BD5C39542D5
+:109EF000CB4C859B41FC572555EAADB45E9DB176B0
+:109F00003394ABFADFAB87A39A3583776F06F5718D
+:109F10000D25AD12B49702EF34D2792DDE20DB99F6
+:109F2000FD24CE1FAEFE567916020F8FF17C190A62
+:109F30005FB40BABD225855D52C5E1F5651AD7DB61
+:109F4000F249FED7CA78CE65C093CE85EFE4F5E23C
+:109F50007757B673BDED0F7A36AEFADE0A31EE0AE8
+:109F6000BEEFC7F4C429811E778B19F1A360EE17E9
+:109F70007796D0F517745834188F177CDCCFEE0F16
+:109F80002B39E3463E37BC33F0F4718278DE0E7431
+:109F9000722D3935D3B311E5C3C82FA9FC01BE78A2
+:109FA000C5FDF1716C4D8A7A2ED3D758CDF9633D3A
+:109FB000F2B5038D1BB07EA8D183E5E1C62D9C3F91
+:109FC0003663FBDB8DDB397FF472FEB80B9F773491
+:109FD000CEC5F2B5463796FF30BB32D3812E8C6E9C
+:109FE000CCD33CB8C3406488377418104F29053C63
+:109FF000FE4812E4C1182C70FE4E9D0FA3E6B73D3B
+:10A00000FBDF16712FC675304E4FFE0BE867D9BDCA
+:10A01000E3CF516237033F294DCF9C06FCE3A8DD17
+:10A020006E06BDB5EC615AA7DF1E75DACD3A5A2F20
+:10A030004FCF6275B7DD6CA0F5F10FF3BAC76E8E26
+:10A04000A1F58AF46CF6BD9760B0FAA6F4FED38051
+:10A05000CF9612E900D043B931673CA4CE56584A96
+:10A060000F001D4C4CBD753CD0C19E343BBBEFC2B4
+:10A07000BEF100D4A70C6AD1C2911BA7A970137CB2
+:10A08000579654A985EFC667ACDD04DF4DE87FAF76
+:10A0900036FCBB4983776F82FA54478B16F4C13D77
+:10A0A000692C0E2AFA1175D12EF8ABC8D71AD2E155
+:10A0B000423E5ED0EE423E2EE05236ABF2A7E0A723
+:10A0C000AB6B972C12CC6396D41384879CB8DA2B95
+:10A0D000945A289F9D973EC4BC917E5707F51BB1AB
+:10A0E000BE6D6374BEBB283D8A7CF980D329C84D00
+:10A0F000C88BFE40CFEEF5780DD687FEC35BCDB79B
+:10A10000627F6E33C8D703694C4E1EE6E5655EFE7E
+:10A110009397751A6735C8CFBA741E4F8CA4EBF5A8
+:10A12000E98C6E55E7057A69E774FDC3741E5FE636
+:10A13000F727AC21EC5CD1B5F2B65686DB6F3990CF
+:10A140009FD37A08F246D579103570DEA85F643E59
+:10A1500030E58B2CFFB15D9947DA637FF4617C0FAA
+:10A160008E3182D1F1F3DED77DDF35D67D5FB475D8
+:10A17000AF242CCF59BD0EE2B6216D89BCE7C8F5DE
+:10A1800004A2AF27621DFC9E3E55BE35D58376C224
+:10A190007C2A169B09F86FC2F9C4F1ABF00935DFD0
+:10A1A000F977F1B3ABF09BDFC13CD5FC469C7B5605
+:10A1B00097429F83F352907707F7BE809F7E63B2EA
+:10A1C0007B3FD0477759F06F1AB0CF92028867690A
+:10A1D00056F741E85FD2B3F8BBC8673DA7F1FC165C
+:10A1E000F4A2F7D25722DFE902E140E9F108AD839A
+:10A1F000DE33D2E27A0BFA238318FEF496A7799421
+:10A20000CBC5C89228F215BB5BBECA423FD635F01B
+:10A21000BD373854C8A303702EE0D2885854793A19
+:10A2200025E2938A20EF3A19F588CE4CBD16CA7FF5
+:10A23000B79DD8999987FDABEDC5CEB4114636EEE2
+:10A24000844950B6EBDDDB6F053B69A401EDA477D3
+:10A25000799EDFF4D35792405E4D977DC90552A495
+:10A260009DD979644199BD20D2DEA4EB1B0FEBBBD5
+:10A2700096DDE932FA13008C6AFBB366C3DF08E4AB
+:10A28000478FDA7085C0FD65D7B647890C6CA2E8A8
+:10A2900084E30D284BCE38311D67D8B9FA37A01C9E
+:10A2A000F92533CFAF955774E3E5D637D831F1C1EF
+:10A2B000CA7B1746BCC5EC555E46DCEBB6CAA3CCE0
+:10A2C000572BF595601E851C8883F2A21440BF971A
+:10A2D000AC61F731887B18A81D9BD3D706762FCBAE
+:10A2E0009B1A07F9467472153FFE70D1ED48F7319D
+:10A2F000A8FFF4D8B12F69304FA04DEB8C1F037627
+:10A30000EC86018E8DB4FE27BFED8157695967F940
+:10A310001B09BFEFAD66C32545BD7363E8BE20C80A
+:10A3200087AEF9978C72A786902DB05F3564BF7E9B
+:10A330005D981C24AD7FE981FB10CAE72A017028D3
+:10A34000078DD39DF4BB4A6E6F107217AB733B8BB6
+:10A3500078CE4DC3BA8DBFEF59C0DA3345FBC2E9A1
+:10A360004E3A4EE500D1DFDE69584F1375DEDF75DA
+:10A37000A2FE007B3F477CFF12ABE78BF1DF67E378
+:10A3800099D9FB373D72DB74E00382BFBBFA2AEF39
+:10A39000F9A1FC7E565FDB55F34A94ED5C1E887B89
+:10A3A0007D2A7E3C39F61DA0E7560973E06AEED09F
+:10A3B000A17FFB42426B41F839659187E22A373B26
+:10A3C00041DF5BF3F2C09D32CFCB017DE37E9E8FF8
+:10A3D0005F219B301E71E96EC6E77BD3D7AA36BCDE
+:10A3E000A2D8CF88767EEF3206EAE87817B7A56064
+:10A3F0009E3BE9EFC778F8BABE92B8BF11CFB98AD1
+:10A40000BCAFA47EC409F669D2EF62D8BD9667FCE2
+:10A41000C87FAB7EC7FCBD6B76BC81726E896C4712
+:10A420003C7E27C7BD01E0D36566F717566D780DF2
+:10A43000E9B5299BEB0996E0E070787AFA72B91CCD
+:10A4400082FFA6BE255785BFB2FD7B86BFDACF2C23
+:10A45000CE49AFFA96F9695D66160775F07D3AAD9B
+:10A46000B10FE3F07A1CD67371B93FCF2A43F2B033
+:10A470003F99E51DBD5D0276D0A57A33DE77B460E5
+:10A48000FDA982F0F329A254EBFF9D4047B610BC12
+:10A490009E8BC4EFD66BE077EB7F12BF53B401BD48
+:10A4A00003E2A627D8FD63C3FCA7F5E1F92EFEBEA3
+:10A4B0004CEEC6B7B338913A6FCBDFD7CCF4241E3D
+:10A4C0008F5933E3EDD1108F11F4302E96B4827F83
+:10A4D0009DE2B583E3B503F05AE06F282E43BF8BAE
+:10A4E000425F21FC25388E80D3079170FDE81A78F1
+:10A4F000FBD17F126FDBA8FE8B71CC9762D07FA25D
+:10A5000086F3BF385C05BCE333AE0EE7F88CEF078B
+:10A51000CEF11976A5FF81C3BB37F9A4DE1F31EF59
+:10A5200028745AF25DE8F4E7999C4F6903982FAAC2
+:10A53000DEF7E48C887D4FCFB8FABE2BDBBFE77D1A
+:10A5400057C34D5DD6F0F8A6FAF9888C5EF9DDBFE9
+:10A55000058EFFBFF9CF17D6EF53B42FDE7044D16D
+:10A560007EABE73D457D74C05F0E682EFCE163CF96
+:10A570000551BFFCAE7EF5DEFCE9D35F5CA18178BE
+:10A58000DB083FF3E7FF35D3BD2D83C2F95D8DB7FF
+:10A59000C94CE13AFC642BBBBFAB3A0FF387D6F34F
+:10A5A000397E31FAEF1FDF4EF1E60B62407FA76F75
+:10A5B000DF755A7B7E241E945ED61067581E5AA9FA
+:10A5C000D1AA75A2BF8638A3E1CD7D1C6F30FF876D
+:10A5D000D2FB5C23D125513A9F3B57C27CA7B9845B
+:10A5E000E545D3D2E7A6EDD3B5C407F724579AB40F
+:10A5F0003E03C6F994E79A0DFC1E659294A838DFD5
+:10A600002C3B65CC4B9B3D82C5076F31B5E2B9D27F
+:10A610007987EFBC783B6D279B3C252CEF5A9C43F8
+:10A62000FBA3E6DBC4FDEECB6074DE2DF138B2A4F3
+:10A63000C37BB222E44106F38F4E9737CA90EF12E4
+:10A640007C8FA0DE2DE88EAEEFB0A1889DB380DFB9
+:10A65000B1A8243ADF403CF77C6F39BC5F73CC8EE5
+:10A6600070A91BB1B100F6B16EBCF489A12064D70A
+:10A67000D46DF812FBA9909F6B82F72F9D60AEF00E
+:10A68000E19DD44EB187FB2B038B802EAF65FF88F5
+:10A69000799F6CF4213E7DDC7818CB77C7BE5502DC
+:10A6A0007A46A0D11FD52FF95DFD03C22F20FC04EF
+:10A6B000820F88FBF93A32385F304A7DF15E352DE2
+:10A6C0002B05BFDC1FC95F0F655C5D5F51B67FCF97
+:10A6D000FCF59BE2794D2A938B6AFC56E3B5C06783
+:10A6E000B8FF1B7EBFE016AAEF815C9D4F3CF93599
+:10A6F00094CFCE5DD1AC1B257D77BC5E653A93458A
+:10A70000A29C37F9F6FCDC8EEB97CB65B40F447E48
+:10A7100082D887AF3222F4F87F5E432EFEF33F29C2
+:10A720001723E5DA9945DF4DAE11853E909A1981E0
+:10A73000AF199957C75765FBF7BCEEB073308B6400
+:10A740004DE8DC07E40F831ED7ED65E71AAB739A7B
+:10A75000F1DE79322218077AE3CABD32E221D13A1A
+:10A76000B56961F74E7512DF1F001F578C5E81E7D8
+:10A77000E122EE8B32B5E1F938F5BD51225FB89692
+:10A78000F7A3BE3FAA96E709D7AAF2764A33797EA5
+:10A7900070112962F9154ABD545D763512855FB294
+:10A7A000EB4A23FA01263FF6D2CF3DA343FB707359
+:10A7B0006604BECECCBC3ABE2ADBFFC3F82A9B9F00
+:10A7C000C47351DF165F0D766735CC5BF0E1059001
+:10A7D000C345C75DF0AAC10BBF0F20EEC9EE96D8E6
+:10A7E000BD34DD9F10F41B5DEB9EE591C7DC78AEB8
+:10A7F00073F8DB4E99E511B07C03A1A708BD655441
+:10A80000675066F7E1F3F3503C2FE89BF22F87DFA8
+:10A81000827A8EF0BFFDBBFCD642CEED35DA919E3A
+:10A82000857FB038E0423DAE4BE72B817BED3D7B31
+:10A8300062A2EA013B323557BDCFF51F66F70E80A5
+:10A84000FB4CCEDFC5BDAE1532BBF7F9925F46FFBC
+:10A850005DC34FDEFFED23F66BDBF575964B51EDD7
+:10A860002251D669D87989A2723BE6ED81BD04FEFA
+:10A870003BE1CF53BF7F30BBEC59985F853C1AEF6B
+:10A88000D9BCB49DCDA7B77DA9DB10C4F17B6DE722
+:10A89000E3D7ED2DB184DF8BD199D9639F59CE1ABF
+:10A8A00043FBFA4DF77F4C70AE42BFF97FDD6E98E7
+:10A8B0002E53D591CAC77CC9CBF453C2F4D405C476
+:10A8C0008FE52212C4D24D583EFD12E2C0721971BA
+:10A8D000613927DB1DC8C4FC966032E643BEFC8F9D
+:10A8E000C1803717C78E6A86DCB9EF4B4FEB2EB4A9
+:10A8F000E3F8DD2FFD230BF25AAE794F7E9CF38BEC
+:10A90000CC28F1E4FF2995317E428AD721BFAFE4FC
+:10A91000B72590F12C2E767F720EE24388FFA5B406
+:10A9200008FE07F1D6FC4F342C3F64A584F7BAB675
+:10A930000734485AF9CB73BC704F4F7B1B6BCF5F0A
+:10A9400063F54AB49E3F3286B5AFB57AE1DCC342C7
+:10A9500012407A5C0CA71E643807C3F89BB8079DA9
+:10A960006AECB9A0672DEF30B2FC7D12E80F7CBC19
+:10A97000A017FBE6E62CA6EF0FC9657C7B4899D2B1
+:10A980000F61E3ED0DD965F559B4FC719633398B40
+:10A990002E7548827FEB2F8AD12F8FBFCBF2D9C87B
+:10A9A000DB307E28BE7B24BBAC2FBCFFBCC4F2CD09
+:10A9B0003D7BF9EF17906072F8BDA273B2CB73A024
+:10A9C000BF415984DF531F1DAEF0FB75AE28F69CC6
+:10A9D000C8671C023615FAC3D9FD54CF4BAC3E32C2
+:10A9E0002BF9E64D26F4E17B40AF7D24DB5D84F35B
+:10A9F000D7136282F93F66F0EE44FDB33E0BFC9143
+:10AA00002B1E3768402FF8908A553857F251A31102
+:10AA1000CB53D4CE85F24FD4CE85F2136AE742F9F8
+:10AA200029B573A15C7ED9419186906359CE29598D
+:10AA3000B650BC4D3DDFF1598CAFF68CBF578FE35C
+:10AA40003764BB11BE3DFBBD8778211EF2BC359833
+:10AA50009E70157CEB9DCF30B888F89FBAFD463EBE
+:10AA60008F82362DCAF182F6405C55D87BF3B2D87E
+:10AA7000EFA9E5BF7406CF8976597AE0EB94E892A6
+:10AA8000A76B587D5ED660846F43B6B31ED64DE982
+:10AA90007B219405EDEFDF07E77968FF9847D02D1C
+:10AAA000051F443D5FB50E351CC4BA9EB7FAB7C248
+:10AAB000F7CFBF940B2BA1FC8630BA013C92A2AD1C
+:10AAC0007723CEF76643B018CEA9DCFCB51C356FF2
+:10AAD000B821BB14E16C12F826E0C4F7EBBBD275C9
+:10AAE0004F3C9BE32911F76C00EFB4831CBA1207AB
+:10AAF0007A5D258FD7B7B7F57F17D6E7392C930145
+:10AB000076C45F05DD3DC1F74794F97BF52ED8A7E4
+:10AB1000E7F79EED0FF7B0D27DE90FF7B2FE226B9B
+:10AB200000B68BEFF2477EF5F02F92F07DFCDDD082
+:10AB300079A4A502F249E61BF71D84252DB47C52A9
+:10AB400001F9248B53A54350DE6ACF990079242262
+:10AB5000DF7DE9A0D243404A531D95A88F9502732B
+:10AB6000099307E5C6587E29B4903F898AFAC4D470
+:10AB7000BE8AF727DBFB29DAA70CBA41D12EC69D86
+:10AB8000EA18AA786F48423017EC2FBA0E760FF603
+:10AB90005332E6DDE5BF74ECA61B687DFAD3B3F152
+:10ABA000DEBFE779FBF417CAF1F708BB293CF5547F
+:10ABB000913A37E2AE077F019DA9F4FB9ABD4F1C85
+:10ABC00072DAAFA2DF5F43AF17FC757587B104F887
+:10ABD000EB37D5F3D5FBE2CB52EAFDBDE14B0F3DA0
+:10ABE0004876862FFCDE2D35BE107227C73F564EA5
+:10ABF0003FCACE817D5B3EF667E06361E7307B4A0A
+:10AC000095BF6D88DEF1EE7AF0BFBF23133C57C7C6
+:10AC1000CFE755C1FFCB213C27CB5A7E0AF74AD15B
+:10AC2000E71ED03FE11CA893F67F398BEB4D35FB37
+:10AC30007E9A561C6A270D9F28DE2777489B15F5BC
+:10AC40004D39CAFADDA59BC3BFEF8D1F566DBF55A9
+:10AC5000EFC6F39B52D4DF7F15F3A9D81F83F97990
+:10AC6000D320EF843EAA2D7E4F0BF1D569BDC84F8E
+:10AC7000C177E6C9A43E5ABB9CCDFA9DBA3F06F304
+:10AC800059BE6DBF1F525862BEE0EF98FCFC30DE2B
+:10AC9000AF0DDFF7B86C89DF7B70EF4FFE0671CF29
+:10ACA0003D04F3372F5A19DF2F68FB4CA301F9D766
+:10ACB00087E14B8125A00179D25D1DEB81FCFCBAB7
+:10ACC0009566CCEB1C921BFC83B190A2FA2FEFB9D6
+:10ACD000C748F7ED8F7098314C9E76838D43EBD942
+:10ACE000D9F720BF9FB23FC6A7F90EEBC9A63A1409
+:10ACF000EA1B658CBE1701DE70B902BEF3BA9F92E3
+:10AD00001E3903FC00D60FF5D9BFBCEFDDFB41FFB8
+:10AD10003EC2E81B32E5D476FBFC30BB9D3CCAE862
+:10AD2000D248FF813EB7EA40B31EECB96BD3772B14
+:10AD3000E6CD7C53BA1E99CD7FB7A3773A3E3A85CC
+:10AD4000EE4BDD1E76CFC4A58E0178AEB537F95D2A
+:10AD5000B75D83F427EA5D1DF224C057F539710110
+:10AD60004F62C953DCE7B46ECCDF67809C5CB75799
+:10AD7000CB923D7A1B678B86D8C3C679FE354335A7
+:10AD8000FB5D4B36FF6E219FF7FE35A174302B37EC
+:10AD9000469173542EEB92402E57B2DF5D38BE378A
+:10ADA000A50CE07F5C223E3B9EBB6279C63359779F
+:10ADB000F0DC84F788A40ED286DF7728ECC8D97B34
+:10ADC000670F003DF20F6D4B8E3B813D64F7C3F181
+:10ADD000E6100FEABDC7ADAE4CF0374CE7F1FEE32D
+:10ADE000D66027F0E3E363622588DFD3FE3791B0B6
+:10ADF0007BFB8EEB5C99EC3E0891577CFD77BABFEC
+:10AE0000AD42BEA3740AC4AB17100BD89137CB4C1C
+:10AE1000AF25AF33BA14FCAE4EF227C03CE764CF87
+:10AE2000F8EF6C3AEF940D3F47BBB2076E5AFEBB8A
+:10AE30004FDF50AFEDB15F7749EC9E1207D3F76B50
+:10AE4000475F78600E9C73A376B644E7B3A47D1F7A
+:10AE5000DEC7A3B6AB7BEC9BFFA57F34D23E726D01
+:10AE600087F509BFB7DA4EEAD1CB857EF714CB73ED
+:10AE70007F63CC435DAB69BDE1A95884E3F9C70D9D
+:10AE80001EE0DFE7771AD0DE399F103CB91EEA2FAB
+:10AE9000E43B3C385A1E9EEF12F8BD4263FF00E4CB
+:10AEA0000EF9BD0EEFDDF8EC3103FECEC7CA27AEBA
+:10AEB000DB09F6D36799F6679F03FFDEB336BC0F55
+:10AEC00080A4B2EFA7717A04FAB2D3FD907F6546F1
+:10AED000BD61E58B69C8BFC4FE9D7B2C06CFC19FB9
+:10AEE0003F3C331EFC609D9ADDEC7729659307F8A3
+:10AEF000F0EA9D31A8F711BDFB15587FF9AFA6CD3B
+:10AF0000190AE3BF6F23B09EEE8E17D1FF18DADF68
+:10AF1000E872FD52473FC6077AE42CCB9B5D1CBA12
+:10AF2000AFD907FDAF21E23E4496375B244BEC7767
+:10AF30002AB7453F07FE5E36B3D76A84BF2491180F
+:10AF400053810EDD84DDFFB86D20DEB77B3E3B41D3
+:10AF5000D0313FEF28F0ED64EDABE82F31B07CBD90
+:10AF60005EEEB73C95CDCE055719BF54F84D6A3704
+:10AF70005C56D607B3DF6D2E6AB20F5D4BCBF51C66
+:10AF8000CE9A5457209B7EBFAAF5DE97DF46B83C89
+:10AF9000FAA33FC2B8874DE8A7216F33F8A9ED9710
+:10AFA0002A6390C71D5A147AEFD91D1F60FEC8D9B5
+:10AFB000976EC0DF2B5B22FBCFC23D595D66FFC79A
+:10AFC000B7D3F285C347715FD4F38D88C34B8CAF81
+:10AFD000D4C03A8642FE8AEB6FD948B78CDE4F6FF9
+:10AFE000CD47F8093F6DF7F9E8F69598A7E85FCCEB
+:10AFF0004FF42FDED3DA997EFF7F0189AF015A002B
+:10B00000800000001F8B080000000000000BAD58FE
+:10B01000096C14E7157EFFCCEEEC18AFD7EB031FDD
+:10B02000F1C1EC1A8C898D3DF8AAB1A12C36A60489
+:10B03000A17639225CCA3169C25188E3950D154A5F
+:10B040009118675B2E11C555AB88B469BBA1224529
+:10B050002D515C07901B61BA0435E0364D17052968
+:10B0600034B5E8D46DA8D5D8D8A569232424F7BD74
+:10B070007F66588F316D137557F6F3FB8FF7BFF767
+:10B08000BDEBFF3D26252A332B007E56A400D401BC
+:10B090004CD26719C0982F5199E1A5713F1F1FCB62
+:10B0A000441ED701E800B301DAE8CF6AA432B8B38E
+:10B0B000B391B631350A7C5C874C4EE31ACE3F9D86
+:10B0C000F726B86A683184E51C80C7C1FA6467B99D
+:10B0D000A01E6003FD8D473FDEF09BBBCC07B0098F
+:10B0E0007ADD50027043E8DE278900A3BDDF716B73
+:10B0F0005E5AB4C27FAB0C80E91F0893E5493DA7B7
+:10B10000530017D03AFA4C8A497DF566288BA09CEB
+:10B1100031BF5717AA00E629CC754BC6E92228A2F1
+:10B120007538AFC66B91F679D428EAB34F082F5023
+:10B13000D0EEA7A5782588C97DFB048D8F8FB277C7
+:10B140007640908E8B5786D300C6332460E94867DB
+:10B15000AB8910E2A1FF13D4532867DC0D6D7D7815
+:10B160006E6D8B10E9E376B8860DD44F00C6F5AB53
+:10B170002DC771C475298DCB96DE011CAF72AE4F01
+:10B18000DAE3E42F2902B7AF364B88F4563C88C780
+:10B19000269A477DA310170957FC6C9011F7260BD0
+:10B1A00077809008E897672CFE19D91B172B516FF1
+:10B1B0009FAC8B684FD305F40BF24DAEF825A22C53
+:10B1C00004B01FFD0BFDEED1FB7A100E79E52E9237
+:10B1D000D368B997A1ACCDB8EE108B009D2B430F6F
+:10B1E000A7C75882EBF17998E034047E1751849F09
+:10B1F000D31510E6742544385D053D9CAE865E4E41
+:10B20000D740825378341E85009D74C07F2B15C9AA
+:10B21000633B8549A4B51B21D2EB7D108703164EF5
+:10B220000FC74167148F9F168795A0E57179D3F1F9
+:10B23000282CE3F13D1D0F0FC523FA2D056279443B
+:10B24000978221125D46818B729683E222BE05426F
+:10B250009C6FFD1F71683034975631031E2D33C724
+:10B26000C5B72C3C66118675493FF52B661DB0FDB0
+:10B2700005A86778E1837EB4C76B539BFFA1608903
+:10B280008829ABC2AEC5C8D734779520FFF3D8461E
+:10B29000936F6A7E2388FC1BCA97C3AE7C8AEBE659
+:10B2A0001AB70AD0CD36855720AFA5F82AA18A0A49
+:10B2B00047A940F1B3D76FE2AF75EF53FD98475AF6
+:10B2C000915725FB640F6286F889252234202D5E74
+:10B2D000157FCB8DEB5648DAF7291FDBE5B84F41D8
+:10B2E000DCF776B7E602DA7B5832D77B709F5C9D3D
+:10B2F000B40BC7F514E4FBFACABB58F0E1E7A3DCD2
+:10B30000D32457EB9EA703E9718EA9A6279B73DB75
+:10B31000B04E8C26DC704C499E7332577B4D413CBD
+:10B32000412E05F27B816CCA19ED2B2F27BFF42B20
+:10B33000661D85EC400DE136911BEEA7F5E36966CD
+:10B340007CF5530CCE7E383594D0796586F1F10FBB
+:10B350005101DC3FA8681768BE23F55E29D5A5DB3F
+:10B360008BDE3B64049271CAF0FCCD687734043103
+:10B3700089D79125FE5B5847017D3089FE1CDF8E01
+:10B38000721087DAB01675E3F0E7364FD463912276
+:10B39000B957B85CC9285E84FBBEBBFEA664C6591B
+:10B3A000A11967561D1AB838F88D02930DC394BCC5
+:10B3B000EAB878F75F7F40FC3AEE78555A9ECCA702
+:10B3C00097BAC0478BBC8EBA61E75963BF272EFA84
+:10B3D000885FB09DD62D7D6FA884EC5A366444D327
+:10B3E00048CEC0FB05A61E565F087DC23E4B5F6877
+:10B3F00015A93803749E13631EC4AB93452EA71181
+:10B40000FF1A5375D4FFAF32C6473AAD0F79F3D167
+:10B41000AE5D965DED83A70EA521DDF5F2936BA0E1
+:10B4200092D2C1CDEBB7825FCAFF3DA7DDC97ACE0C
+:10B430007FA323D0CE0EB03F7189E2A0BDD7B9AEB5
+:10B44000038EFF9DEA4EC7D43A8F7A7DA2A465731E
+:10B450007F59FD0AA885A0BC9DD65EB2C34B7A0F6A
+:10B4600048310F43FA832ED54FBC953F70E3391E08
+:10B4700097F67A78398BFBDECEA7AF1D41DDB3920C
+:10B480007855BDEA0911EE55AFE686C8BE2A09B661
+:10B490008539DE311EC755181B0CE3E9F58C89A0F0
+:10B4A00080E7BC3E50A6620585370F86E0CF7393D8
+:10B4B000FA755AF9D42A9E6991300EEE3C057E4CFD
+:10B4C00049E81CFC715446BEF328D00AB843BF506B
+:10B4D000CE9D112146721A076BF2C8DF67ADFCF4EE
+:10B4E000E409A04CC1294599054A5992B7F1F5588C
+:10B4F000FE492DCB74CCA7A98F38F6A737049DFB46
+:10B50000F550A2A29EEAB1B93F23F4A863FD61DF22
+:10B51000CAAB14974B133BD6102E59ABAA1DF3F5AB
+:10B5200020F3FB435DA1578DE17EF8D8ECE70DF8E1
+:10B53000E5FD002222D9D764007C0FFDD138EA72E4
+:10B54000F83DC5C078C47529D7A7F81D7F3C8A93FC
+:10B550006F08601C50221542E1D43848E2ECBD8FE0
+:10B56000238F83415C4438A74931BC723C80533DF2
+:10B57000CC4DA7F9BAAB22C438EE5D6A1CC7678709
+:10B580009D78E7B639F1CED79CF816EC72E25B14E1
+:10B5900071E23B67BF13CF80EEC4AFE448A363FD05
+:10B5A000BC9E66073FFFC46AC7FA05B1750EBEFCB4
+:10B5B000F426C7FA85BD5F75CC57F5EF76CCDB7105
+:10B5C00035DDEF8BE29D8E75D3FD5E73F559875C9B
+:10B5D000DBCF3A7EFF9F7EDE37CDCFDDA81BD5AB1C
+:10B5E000777D23C7290DBF986AD6A5567149224495
+:10B5F000FE5EE256C9A7BF53B25AD228DFAD3E1451
+:10B60000B6FA101C3864F2569CA809F532D5D1EA76
+:10B610001BE1161FF2B546E43295E3FA919E96744B
+:10B62000858789E2C73861162E5F6A60E072E40B95
+:10B63000F23949DCD6EBDD623A2E6EBA178BF27224
+:10B64000494185E7ADB3E6598359D7D78652C0350E
+:10B65000058FA5D63850D346794BCC29586FBD07F6
+:10B66000F05E0E12DDCB0539160DCC749F544F8859
+:10B67000FC9EA4F17BD315A6B9896E9013C5D4BFE7
+:10B680007E92A3FD2880F5EAB6A02AFC9EC58C28F0
+:10B6900019354E8651D3D1AF87435EBABFE3DF8FF2
+:10B6A00060DD7DEE5A58AFE0EAFB0DD45FB3F439AC
+:10B6B00013D04E0710FF61E63F54837BDF6DFCA87B
+:10B6C00098FA8F474424B00E66F9423FA579FDF001
+:10B6D000920C5EA773D13EACA386A0F0FB83FE2C38
+:10B6E000E3EF818F48D8E229797AC4CDFB0E58EF79
+:10B6F000A32D165EF6FB68B375FE308AD885757A81
+:10B700004BFF158ECB9EBC517065F178E3F7A427F3
+:10B710000BBDD5C7C8A6508DBA6E218DDBEFA50233
+:10B72000F1D3F4C556B122DD98E1BE68D33D79234B
+:10B73000FC3D777FFF19B38F3C5CBECEE33669B723
+:10B74000297FF8682AEF2FC3478B9A8926E5DFE621
+:10B75000F2B744AE39E264DBFEDF3BE2EF09FD4FB6
+:10B760008E79237BC25D80F61BE7F3577E05F11BC4
+:10B770003BE7A9A77723FAED8FE4175BBEF1FCFC4A
+:10B780001574DE7FB7F36F1CDFA1830970CD4DDA2E
+:10B7900079F3E00DCE1B070D4EA7DB69BF336D2A91
+:10B7A000BD05652EF4CF049BA59E0C3C78CECEA0A3
+:10B7B000F93E1B5A9ED34C7D76A8487299B4D4E4C6
+:10B7C000F31B64935FB98AE8B8DB7B84DE99430C92
+:10B7D000420CE361330BFFF009B4BB3B47BB477638
+:10B7E00076EC9EA874613E7454195B19FA333F439A
+:10B7F0009BA47186D7BBFC4CAE6729DD3B4604BDDC
+:10B8000092612D587CB2702DDDD34766E9B7A9133C
+:10B810002F0AE6ADA57BFA8864E6C7F293C25A1DEB
+:10B82000ED58ECD7528228E74326C6793CFF82C503
+:10B830004EF17833A475693C9FDAE8DD45EF5D7A17
+:10B840006F8CA798D41F64DCBE0CA2B393B49C6A1F
+:10B85000258E2FB768AB78BC94D1FDE08407281FF4
+:10B86000F09C9040E70C7862A790CF41DDE99EF212
+:10B870002BC9BCCF57FFD213A7BAB143FE98FB69BF
+:10B880006E30C0E5649760E5C27DD92F786251D2F1
+:10B89000CF4814AF45FD7ADC787FA1F7F4759CC7DB
+:10B8A000BC1B7B7EFEC96353FC313768BE87E02931
+:10B8B00000733EF7159A6F1F1CBE4975E4B701ADC2
+:10B8C0008CEC1F16947AAA23EDBE4B12D59FC6A00E
+:10B8D000C2F7A1BEDC7EAC07DF641C67D9FF178C02
+:10B8E000D76D586CD2E9FD26682AED6F970D89E473
+:10B8F0006144F0FBDFC3EC1FDB9E78B102E9ED345D
+:10B90000B598CEB1CF453D1A498E6DB7AD4752CEF1
+:10B910007F8EEB1DF284237F6FBD74B894F264C8F0
+:10B920006DDEEF10678DECA816D9B675C87FC1C261
+:10B93000C55EBFD5F2A790177E2C887477E4DBE74D
+:10B94000DF5192F3E3ACE7EB1F90DF06BDBCDE4DA9
+:10B950003FDFDE3FDDDEF68B831C17B4772BD93952
+:10B96000C5DE8D748E6DEFD8C0FB2F56289FDDCEBF
+:10B97000F1A2844472C75FB95BACE0FEF60B576E70
+:10B98000501CB55BEF7D38EB7CC77B66E17B317388
+:10B990004A5DA75A37874FB3A9F7288FBDBFD0E5B7
+:10B9A000DC8F176601CF3B6BBD23FA297F67786F69
+:10B9B0009E4D08BC659ECDC37B1AF503ECBF54FFBA
+:10B9C000EDFEBBF79AC0E3726F00F83CE94579C021
+:10B9D0008CB7793FB0FF9F1065D8E7301E3A25ED50
+:10B9E00020C509685DBC3F8873BC2AC573DFAF57AB
+:10B9F0005BEF26B3DFD459FDA58EE490FE15E9BCBC
+:10BA0000EFD45AE7D6CB789F0952E9D6ADFF9B58C1
+:10BA1000FF5F38FA367F6FFD1B3AD0569240140014
+:10BA200000000000000000001F8B08000000000064
+:10BA3000000BFB51CFC0F0038AEFCA3330C42B3167
+:10BA400030742B33307C03E20E79841CADB02A07AE
+:10BA500065FA5F303230BC02E23740FC8E9174FDF3
+:10BA60006AC208F6525E06067520BF02482B0A30ED
+:10BA700030B001D91A40BC0BC8BF05C4CF80D84133
+:10BA80008881819D8F81C110888580581328EF0996
+:10BA9000A43FF161375F4B18BFFD8F0550F9A282BB
+:10BAA000A8FC3FFCF8F5B709E2971717223D4CDEDA
+:10BAB000AB911F1FC6EAB44F33D4C4371950F91FD6
+:10BAC00065181898E51818DCE421FC6B48F2114061
+:10BAD000B14F3210F66D3160DC01D55D66C06EEE9F
+:10BAE0001DA0FC13A07C0AD41C0004EB50106803BA
+:10BAF00000000000000000001F8B08000000000094
+:10BB0000000BE57D09785445B670DDBEF7F696DE8C
+:10BB10004216C2163A2C0A08D86C21084A67C3A0FC
+:10BB2000019A454407B5598410C822E27C3CC77984
+:10BB3000345B061DE64D147518079C06C380F35050
+:10BB400003460D1A980682A3CF2DB8208E336F9A24
+:10BB50007D3190002EAD83E3AB73AA2A7D6FA79B46
+:10BB6000E08CFFFBE7FBFF2016756B3F75B63AE7ED
+:10BB70005445359808194BC877F043D32512212432
+:10BB80002D9AD29FBF7F974EC82433FD974C48A172
+:10BB90006C23643821136D2468A275268EA11F536F
+:10BBA0000979B7460ACAD086D60B6413524AD8CF51
+:10BBB0002485D44BD7137231E7C5AA216E4224AF36
+:10BBC000972C1D4A53B78BCC8474CCDEAF2507214C
+:10BBD000CE1C0321FD589BEFE8DF64AF15FB12F983
+:10BBE00094A24EBA7C9AAFABAE7EE719BD74E55D08
+:10BBF000FC0374E5DD4A86EAF23D2A6FD0D5EFB941
+:10BC0000344F97CF0ADCA2ABDF7BCD145DBE6FF55E
+:10BC10009DBAFAD7AE9FAD2BEF1F2CD5955FB76DB0
+:10BC2000B12E3FA8F6415DFDEBEB57E8CA87841EB5
+:10BC3000D1950F7BE3315D7E44D353BAFA230F6F66
+:10BC4000D6958F0AFF5E573EFAF44E5DFEC6D65774
+:10BC500075F5C746F6E9F2B9E42D5DFD7CF307BA48
+:10BC60007CA1EB535DFD9B338EE9CAC7BB3FD395E7
+:10BC70000B3CB8B5DF25DDF7099EBFE9DA29C447DB
+:10BC8000814D889154626A26D5985A492DA636D29C
+:10BC900084E9864CFF9D64046DF074A08A50BC5BFF
+:10BCA0001968FDEF149ABE9BD3DBE91F08BD790923
+:10BCB000A1783B91754D269A6D2199E299C94C0264
+:10BCC000168A0A8E08C5B7148A771182A92B42F109
+:10BCD0006D18C5BB8819D34E914EF83D25E2C2348C
+:10BCE00035D215BFA74532304D8FF4C2B473C48D21
+:10BCF00069466400A65D22FD30ED1A198AEDBA4549
+:10BD00003C98768FDC80DF7B447230CD8CE4E1F7A9
+:10BD10009E112FA6EEC82D9866458A30ED159982A2
+:10BD2000F57A477C98F689DC89DFFB4666607A4DB8
+:10BD30006436A6D746FC98F68B9462DA3F5282E9C5
+:10BD400080C8626C775DA412D3819107F1FBA0C813
+:10BD5000524C074756607A7D2480A927F208D61BEB
+:10BD6000125983E9D0C863F87D58A41AD3E191A78A
+:10BD7000F0FB88C87A4CB3239B311D1909629A13D2
+:10BD8000F93DA6A322DB30BD21B213DB8D8ED46238
+:10BD90003A26F22A7EBF31528FE94D806F29807793
+:10BDA000214CBD91FFC2EFB9913730CD8BBC8FDFF5
+:10BDB000F3234D981644FE84DF0B2387311D17397A
+:10BDC0008AE9CD9130A64591B3988E8F9CC6F496A2
+:10BDD000C8456C776BA415D3E2C837F87D4224823E
+:10BDE000A9E07724476D0E0BFCEB05FF9FE93A793C
+:10BDF0001DE54BC46FF88EA6C446F16054B47E6C4A
+:10BE00004AB91DF24995E25512C5EF64CA0B811F6C
+:10BE10004EAC9482376751FC480D37425ECD31B944
+:10BE20004D347F176955017FFF42C276E0A77B47FB
+:10BE30009DEA1EA6F8FA6E5AA807456EF8417EAB39
+:10BE4000C29C7A03BF6D56C2F4FBC4D47D697E1BCD
+:10BE5000B4A7B43114D09B8E0FF84DD111FAB94B61
+:10BE60002101079DEA41E86114D60B99687E66318D
+:10BE7000F10EA5F5AB46996604E93855437D253E9C
+:10BE80009AFE22CB3703D2FF02E2A1F3DFCFD383A6
+:10BE9000C480E98B9914EF297DCDBCAF2FA3A702F5
+:10BEA0000AC42E1DC36174BA8BC90D5B6BA66FD01B
+:10BEB000D5B753081B4FD47F96F83E82EF813CD212
+:10BEC000AFD216AD47BF1F867A71BE7F1AEF7BBD1A
+:10BED0008132020AFF402763700BC827E2764E8644
+:10BEE0007999DDCE29F6C4F3FAD932D740A58F76F9
+:10BEF0009E419CDFCF2432A396F1978C2983B07F9B
+:10BF0000948701AB05FB9739FC45BBCF019EB4DD9F
+:10BF1000FB165F0B93A7EEEE08179BEBAAE042DB44
+:10BF20007D897051683BFBD5B74B9C56333813AFB6
+:10BF30001BE7C1BF57984840A2EB68DD620F6ECE89
+:10BF4000021C7623FF2C7171069A4A8141E57A49D9
+:10BF5000322C8190C63D492103AD9FB7C5BE19F46F
+:10BF60008096BCC0933E80F366956CA15556ECF963
+:10BF7000F9A1DFD07CDE2695500D832C487A229BD8
+:10BF800050B85D2B496CFC80776F1FDABF9F881F0C
+:10BF9000AF04FDCF27ACFF1689D151608B13E17A36
+:10BFA000BAA0A66A344DC3BBCB8A09E5E3A72858DB
+:10BFB000BB50FC5E60250AA494831B113E01F578FA
+:10BFC00058C817A467259A97DBE7E7435ED03F5D23
+:10BFD000F782A01ACDD3BF0BB7E9F31A78E1BEB749
+:10BFE0005AD4E066C4AB6E0C3E025EDE6E0C7E1C64
+:10BFF0005E0516356048457805810F382537C2A1A2
+:10C00000C4A28664DA4F0985239060C9EE87D30104
+:10C010004E0BB7595CC735E396D526EBF215F55DA7
+:10C020005CC73572F4E21BCF38804E1767185CC7C7
+:10C03000297F6B5EE64D394EB7ECFCB2224C057E93
+:10C0400094D566B96CBA7EF4F98BD55211C36FB72B
+:10C0500073DAA0C478B638C3E83A4E49F5EC362610
+:10C060006FCF2E33BB609CE6652E171B3703530141
+:10C07000AF454BAD585FCC2F51BF3FF4FC08A9230F
+:10C08000C7CCC0CF6959EFC4F513D293F2B911E907
+:10C09000A441FD12F0C64CFF7E67403CC2BCE8B72D
+:10C0A000A2560E98AE87EFDB75E3D176EE931AF9C0
+:10C0B00092986E1572528397F7430748A766DC671C
+:10C0C0003FEDD149FB6B516C6B408F9AC0F1A702D9
+:10C0D000EA517E50660E1BFDF4D3B93AB61F89C6ED
+:10C0E00039BB6C5B37E06B25E66A2330AB92DAFE36
+:10C0F00005404FE7EA56A6837C59285FFCB12F4ED6
+:10C10000FB5F08BA0DAAAD7A7919E4F3A4FDEAE859
+:10C110008CD8DAD64DF3CD063A94AD7DBFBF929858
+:10C12000DC29DF7E70DC683AFFF2FA0B4698C70420
+:10C13000C9FF2B292DBA7E09D64FFB29DD76C4080D
+:10C14000EB3BAD06AEF949D615E0D96E9EB68C93A1
+:10C15000499AF905A82249E975760EA757E2BEFD6E
+:10C16000534A9F67DE52C923741EE432AD45CB3378
+:10C1700079E95CE27300BC66D72D44FE7306F80FC4
+:10C18000C861529D0DF8718E188A607DE7C8FB8EDC
+:10C19000611AF8ED938C1C3E5495A5FCC084432194
+:10C1A000DCBA00BF32955435C983E1BB12E07C494B
+:10C1B000FA0EF94950427E56C2BE07887939AE63FD
+:10C1C0000DE34701FA07F2F756EBF9D3FCF5FAFC59
+:10C1D0003C32255DA1FC65DEE32AED91F2372DFFAF
+:10C1E000A3F07B566272773EA9AC72D1F96F34D25C
+:10C1F0007DA2F39FED224A37BABEB2573666CFA270
+:10C20000F9372526C7CE2EA3D3BF86F6D389ADBF77
+:10C210007469D0E81DD87E7DC7EA864D1F4DB03FBA
+:10C22000261F4B85FC256E251BB925557213AFBF04
+:10C230005B9DECB538A01EFDAEE1CF73D6E8D7D735
+:10C24000D1FA63D74BC863886FA5DB2613C033B11F
+:10C250001EB15F623DEA36C91B8C4307618EAF8217
+:10C26000AFB572F809BDE38B98FC3731F9EF62F294
+:10C2700002BF554EDF14EFBF9046003DB78E637886
+:10C280001236B2F30CAB678CD6FBE64AF54C9C5EDB
+:10C2900068BDEFAE54CF12ED4F31A4B5AF57F6CA1B
+:10C2A000732F07287E97BEF08483507C3CA354A74D
+:10C2B0007BE8F7455B563B004EA7958003F0E64CC4
+:10C2C000502E8A07AF510649E81B3689EE7BB9C06C
+:10C2D000FF31CB27827CFF728BEA7A84EE4BC53626
+:10C2E00053C844F7BBBC6E4131198CF9232CFFB302
+:10C2F0000B801F15F5EA51EDBE966E7D22DD6DC7F0
+:10C300007DE866001D9884BA119A96D79C18077A22
+:10C31000740569457C8E6D07E3C3D18EF2EB5946F7
+:10C3200067FB72716EAC609F4845DDCF2FC0B9B11D
+:10C33000822847B5785402B84CF5BC01067B2A9C8C
+:10C3400017C8483212F88A800309A6215F5EF9EC0B
+:10C35000AF061FA1F368AE79CB2169E04335248491
+:10C36000CBC5DA397F4DB9825C384FF1935CA36D50
+:10C3700017C476EE7A3A81CE34DBC0D2456AC83132
+:10C380009AC273D126D54331932C7AEE99DF3D457D
+:10C39000E98E7C62F2F4A5F05EF8DC814337D0FCD4
+:10C3A000C21D6A6A315B864D4A8FEE4705FD0B76EA
+:10C3B0001901FFD2170F18DD83D8F7873A45F761C7
+:10C3C000E18EBD4632A83DDCF26BF71AC3B638FBEE
+:10C3D000517B641CE8332B9FFDCA08FB7D668F44AC
+:10C3E0003A67B56F5FB2E900EA2F0027DC3FBE3F36
+:10C3F0006DFBD56E9F42135F1D8EF55CC0AF13EDD4
+:10C40000931D64F508C4E3E75FA5E397FCC9E481E5
+:10C41000F5973C7FBF03D6714AA964F8BC7175BA21
+:10C42000978E5BA206D25D98B2EF254F3F8078369B
+:10C43000FFE003A89751FCE862409911E802EBBBCA
+:10C4400077C36DB8BE79C48FF856B251F605810F27
+:10C4500028A468471C7A7881D3C3A9CD9453D2F518
+:10C460009D02FE087AEEFB32E78FF7A11EF9005F0E
+:10C470002BD56430FF8599ED5395C120EC72661D74
+:10C480009ED6FC0CF9E8D91EDECEAE810807C13776
+:10C49000919FCA070B3BB3FD61FC17DB51BCCB87F7
+:10C4A000EF50BF49F55A06EBDA717EC9C65FC2C7C5
+:10C4B000A7F3B682FE712A9DC989D8F5FDC920F877
+:10C4C0002395AF1AFCD2D035A3F39A87195D0B3AA6
+:10C4D0000F4E2E82F2CF3F64F403ED40FED07985FB
+:10C4E0003A63F9DE6912F2011309C5A3E71A95D37D
+:10C4F000B3BE9C7268D4DFE8BC15C9A9C513DA7F46
+:10C5000027843FEA25F31EA7ED34FA74058C87F5DE
+:10C510008CD1EF5951BA9DCFE9FFF740FF4951FA4D
+:10C52000271BD2AEEA7CB6480DFEEE29A0574A9FE3
+:10C530000137D0ABEA83757FB67DFFA13B295E7FD3
+:10C54000562BE854CF3763E9B464E70304F033961D
+:10C550004E3FEB5E49E2D229FD1E974EBB87FF5747
+:10C56000F8A680DBC118B8513EF8DB57DD89E1172A
+:10C57000CB072B0CEEB87C90FE7C48B2DBE39DC071
+:10C58000378167A5FF59D613F84D1B3E0A7C6BC354
+:10C5900047816FB1EBD4C32DB67C03F01B8D7EA019
+:10C5A000AE20013BDDE7D6DD329E135BDCAD8E4E67
+:10C5B00074DCD516720FE8D92D2E9E4F66F9D6344D
+:10C5C0006315F005F1BDD54266007EB6F85A1DC967
+:10C5D0001AFDF94883EC70D3F2709014C5D3AB29DF
+:10C5E000C7C5F1C32451F972845FA16CCB5C3A1CBE
+:10C5F000CE55B20774B7B9CB6F7780C9A2A5A1F7A2
+:10C60000A419F4FBBD6FCA68D368B13A06C3BCE88D
+:10C61000B95DE942E13B87EFF3691278720C5DD7AF
+:10C620009C06A617CF5DAB87C73CDB1223F019AA87
+:10C630007F46F140832FC24F50B2415F5E4AD6E23F
+:10C640007E95C6E08F9F9F77BAC81C7F869021FC9D
+:10C65000BC6180FE16733E55280F9C3483C2BDE535
+:10C660000D999868FE62834CAA609DDBA520013A73
+:10C670000EA4211E9653FE4034E7C266C0336362A7
+:10C68000FA6D7EE92FD93FA15516BDFCE9E0DFD058
+:10C69000B4F9E54FAE790DF2AF7C9CF929695F3FA3
+:10C6A0007FCFD777037F6FD963226827D9F3C7CCB1
+:10C6B0009F40FE559307ED1C2B4C5ED48FF7D8831B
+:10C6C0007DA1BC07B32FADDCFDD5E030CA9B55B8CA
+:10C6D0004F05323B475C6CF8DB7F4BA990D255810C
+:10C6E0001CDD9384FA75C5AB96201C3A5B767F956A
+:10C6F000EDB7FD70EB2937123FE29F9DCCD809F8CA
+:10C700009ACCEC6915AF8D7A66391DBFAC6EAF71EE
+:10C710000E2DCFFFC3B78381AFB4EC64FAC1793576
+:10C72000FC34F11032497E62B94AF7EB3CE86A5DAD
+:10C73000295F920FE5066CF1E0C2E0D042E100EB28
+:10C74000A27029017E98081EF3FE65E171E16E1862
+:10C750007F51C348226769E12279D9777BD02CE1E8
+:10C76000FAD9F73D5F0D06BEFB59ED7294DF1DADA2
+:10C770007B35AC3BEDFFA5754BA1AB5977CDBFEC3D
+:10C78000BA19FE0F90993C8AA583F678FECA8F31BC
+:10C79000FFBCDD83F3BD4AFA6FFC975DFF3FB8EF46
+:10C7A0003B25F4C775B4EFC7FE65D7DDD1BEBFC961
+:10C7B000F7DDEE027B6FCBEE6F338966FD1DADDBDF
+:10C7C000A0FCABF2B72BAF5BE83D4D864AD7703A81
+:10C7D000BF4F48F56D59347DCF7B29158EA3940644
+:10C7E0007CF1CE0D4315766E30819D092ADE260937
+:10C7F0007B5193CE8FDBBD04F58C89DE5FA07E403C
+:10C8000094CAA65C5ABF296F8EE711AC31F4B01FF1
+:10C81000F2D36EE479FD79EA5D897825AAC74ECC1A
+:10C82000BBF50DD0EF267965D4FF688A7ADF47998A
+:10C83000E3D8F71CFD39E28E9873C0ED33F4E5B709
+:10C84000F1FEA693C5AEE1145ED3BB2BAE2005D19D
+:10C850001DB9952AACE78EBB2452ADB157DE16D375
+:10C860009F4321DC4EF28FC16F6E1BFC16233C48A8
+:10C87000AEECD942AE027E84C1BB69DA9020D861A9
+:10C8800088E261F09B5EE6413B283F67AABCBD6A37
+:10C890005BD30474AB12FDF9529C1313C199F0736E
+:10C8A00027F6D32B0A77D52BE3B953D31FC243EC1A
+:10C8B000C7F7DD07B17FFFEC7E64C37EC4F19F2D17
+:10C8C000309B6F03FF85B99F84E7F6496B658C83C6
+:10C8D000310F94108EBE1C15FD3B270CBE6C509C76
+:10C8E0008B878D2C7F9075EB01F82CE0709C472A8C
+:10C8F00051EF2497BFFB6E0CF88D1042B4DC4BC88F
+:10C90000047A0E9937460A59E9FAE72B24E01C0A03
+:10C91000764D891CD5DA3583FA3CFCDC941EEDA7F4
+:10C92000A3FA89F8C30F9DFE95F2A3A37DE87905CC
+:10C9300052058757B4E7C47B1A181C2B1649C15EF1
+:10C94000884721D5A7F1EB7CC2F1FAAF0F0D433E2A
+:10C9500097FBCB414E3CBF7A07A0BE5FC1F5FD8B74
+:10C9600001B713EC35171B7A3BC11E73F18D7C8721
+:10C97000962F8AF4203F477EB0CC8C694B81542D92
+:10C98000C3798BB44E44395C6021C07762DBED52D1
+:10C9900084DDA592F919E98F9C0DFBC87EE6D3A62C
+:10C9A000CE4E9A7D5B3BE18C32B8FD3EC0CF518DBF
+:10C9B0009FE49F852F9C5B01AE072DE171BE38EB94
+:10C9C0007D8BC3AF78DFD746B0134C69C852012EB8
+:10C9D000530A645DDCCD7E859FA786916130AFE20E
+:10C9E0007DE31DA3605FDE903D160ADF8A860B465D
+:10C9F0007F1C7F5B2C3CA17FB00B1F533DF3009E3F
+:10CA0000C77E6121014A0FEF70FF0F2DF202FFA2D6
+:10CA10005D79C13EF6A1C2FC0AFD5566179F5A9C7E
+:10CA2000ABA6D17107D6B9868088E9CAEBF757DD86
+:10CA300058DE8DB713F5BA2E62F58E185DE5F1D686
+:10CA40003FC1C8D63F9F787E9C23FDEBED5BEE2F68
+:10CA5000EDA13C90EF0512F291F6784D903E2E1626
+:10CA6000494190BF708EC57CB184F2FF1D032B0F2E
+:10CA70004C61F252E07D2C9C2595C1598C9FA532CA
+:10CA80007C36AA0C3E02CE02BEB1F315F529BF1AC0
+:10CA9000ABB5AF4CAA1FF23CE827E50D920B4C7FDB
+:10CAA000E54AD808745851FFA80AFE823BDCAC5F07
+:10CAB000A2F8066BFDB5FD5505E7B37FE868D41F06
+:10CAC0002FAD65FAB177EE0507E841EF183CEF8D21
+:10CAD000067A7C57C678824470FC74D9B669058A98
+:10CAE000B6DF2C9CE7D445B92A98837EB468AFDAC8
+:10CAF00059834FFDD54E582EBE775DE41E0ADFE9FF
+:10CB000078388FC07F98C816DAC5C0DAA6BC245A18
+:10CB1000FEA3CA64868725B57B8D98CFC2FA623C96
+:10CB2000314E2C3D4D2B4ED2E5E7E487BB035C8AAA
+:10CB30004DA1259E3878DAA80A3FC9F794135E8A7A
+:10CB4000B783FF7F901317C679E3C06D9DDA4E3E21
+:10CB5000748E271F162F777706F82FDEDDBB331074
+:10CB6000C7E2370BD3E3C9878F96317FE0C7949F25
+:10CB700041DA328DCA87EB35F2619A05F123B6DDD1
+:10CB80004FD5AB940F62BFFE97F9CC47201FE2D080
+:10CB900075B5AA970FD31B66A17C983E4D266E8D66
+:10CBA0003DEE672AF77325940FB9E977605EF524A7
+:10CBB000C5C19B8FF8B904E00A298C0372E20F9C6F
+:10CBC000EFC7CA8B44FC7C8A51E2FEEA0EF8F9FFFB
+:10CBD00025380B7EBE989E5F400F6C8F8704F9F559
+:10CBE000E23B283F97001F193F5F7C17B74BC6F009
+:10CBF000571FF0D7E15AFECADA97FB993CA8A8CF95
+:10CC0000FAD54C5A7E67B5EA31D3FA7746F96DB654
+:10CC100096DFFE81F35B0AE74C579CFD9D3133891B
+:10CC2000B8F5FCAA0FF0A96343FE38F045C0FB77C6
+:10CC300064F4239EE072FCED217F1C0EF6F354A3F6
+:10CC400082F87382F3AFF3CB82D30A281DE7CF6556
+:10CC5000FA70D97619E1505EC7F4BCF23ED6A09BBB
+:10CC6000E6C70DFD1AFD810B77337F20055471AEA9
+:10CC7000661F17BE13AEEA06E59B24F467CEF32CBD
+:10CC8000443B3E59CFECC466FA87C57578D18E5CBB
+:10CC9000C6E1B5A06113DA9B1704F576E8B23EB79A
+:10CCA0009C81F380E0BF0BB7C5947B1E467F45197E
+:10CCB000D89B35E71099EB0FF7CAA1812F426CE79B
+:10CCC0007BEC5C15BBFFA25EDBFA4BFEC9F51FA433
+:10CCD000EB1FFEC3AFFF6AD7AD1A39BD0F25C38165
+:10CCE0003E4E18BC48EF81FFA2EBA7E3CC7DB46FAA
+:10CCF000676D9C510AA7CB770CFEAA2E50AF5CC281
+:10CD00007AF337EC38904EF3336BC91030D3CF5FE2
+:10CD1000AF978B6D72B8CE8D727666E50E69F64070
+:10CD20008037A9043C9B33D4E4077FEA414B2BF2C4
+:10CD30002F8177371A193E8FE6E31EEBDA5A80E728
+:10CD4000887AC9857411B2B0730585BF85E6F78FFF
+:10CD5000FA6A1C8737DA632AEAD9FE54D0FD00BA92
+:10CD60001AD7C0F3DB981EF6232A6FD01FD6B05710
+:10CD7000857625B47E0AF29B013A3F17F8E772D315
+:10CD800035FBB6FB08C3DB2D9287C4D9B77EF44FC1
+:10CD9000DC7DFB81F055C0E34623D7E7F9FE1DB4E7
+:10CDA00034150F433F94E4D90C951B92D18F72BC7C
+:10CDB000BA37EEE3AD1C7F63F11AF47BB7C69E343D
+:10CDC00019260EF19645168C73C3717B31FD47CB46
+:10CDD0004F62CFCD15A409F5980992FF2F8A26AE90
+:10CDE0006D3A8F3F117E5A4DBD5FA957A847325CFF
+:10CDF00006E093F78B784B881F4EC7B825FCD9DF28
+:10CE000023FBE39974BD97D6C81EF0FFDC6E701F3C
+:10CE10001A03F4FB884A002F2FBDAD7A99DE99845E
+:10CE20007C77D63BC7543085CCA23081FD9EF5532C
+:10CE3000C65F8F4167F4DB9FA8DCF282AF9ED48E81
+:10CE400080F8E1699EBD856EBA2FB70D3FB81AFC18
+:10CE50007053F35D870E017C1F9609C0F7E89A7C3A
+:10CE60003C9FDC7F9F84787D98C211DADF362DEB02
+:10CE7000D0213AEE5D6BD2D0AF36D37BA010F06CF0
+:10CE8000CE24BB0DFC6BB7F693895F03C7BB48D3B9
+:10CE90006AE0D7332BEFBB0DE65B42E500D8594B78
+:10CEA0001A0E167686FC06C9E3A6FD5704FCC6CE0C
+:10CEB000740B9BD65F3082BD631EAD07DB53B1811F
+:10CEC000D5ABA8913C16C0C7864791EFCCAB9188F3
+:10CED0000BEA537DCFCCFA0D9A69BF4D1B687B9A44
+:10CEE0009F0FEDA1DF9AE4E9E047AB785B66ED7355
+:10CEF00096BF0E7C691E6D478B4953CD7DD8DF826E
+:10CF00000D12C9A0FD95E464FD470EF4F7B6EA8161
+:10CF1000F28FF7FEDA08F3BE9B8ED785F63F470EF9
+:10CF200017427DF213C9B505ED4D2C4EB685D301E0
+:10CF3000F9B00BA32F89E7B91E28E4E107C65E8884
+:10CF40004FF3962EAF8275850369597004AAA8BF66
+:10CF50006004BDEE3885B39FEA6DC7781CDBFEC068
+:10CF6000316358C3A75A8DBDB1FDDCFA5CA4EF7BD9
+:10CF7000890FFDDDFEE54C0E1F596D094AA07FA803
+:10CF80002E9493FB575FFB24ACFFFC732AFA47CF28
+:10CF9000F708A33DF6D4069504E81C576E90916FF0
+:10CFA0009CDACEEC40F24615F3F31F30627EFF862A
+:10CFB000A9E3801F9EA2F0073CCCDF586884FC7C6C
+:10CFC000CAD74D71F8C73C7729E31731FC61FE7A67
+:10CFD0003DFDB7E3174BC631FE1EC30FCABA57A1BA
+:10CFE0009D2F964F54109BE00F4321DF14EA82F8E7
+:10CFF0005BFEB64A409F2B575C77AF07BC9969012F
+:10D000004F31A58BD001E06B9782923B40CB7F7470
+:10D01000CFAE1100BF93006FA08BB529E84F9D17CD
+:10D020009C857015F184F3D7EBF159C42FDDE1979E
+:10D0300089572B074A92885753EFE39F52BCA4E3CA
+:10D04000DD532F052D12E48FBCFEC070CCBB000F4A
+:10D05000CB977279BAD68E78FBF1BF5D580D78798F
+:10D06000F74312CE9F04FC552057CAD74B6EB063CE
+:10D07000CE7F88B59F4FDB03BE7CFC6B863F148F51
+:10D08000DD80E7E51B1E7D1DEBD7486EE8FFE34D15
+:10D09000B350FE96046482E53547503FA67200E324
+:10D0A00080F607E474C0F3F2552617ECA3C017818D
+:10D0B0007F4754E6B72766CFE0A9B4DD26A31BD788
+:10D0C0001D8B77F28C2CC4AF8AED2AE2474580E1B4
+:10D0D000D391E764C4C3FDAB6F47FC39BF454A80B9
+:10D0E0007FF9C62E807F4156DE867FCF4A1CFF180F
+:10D0F0005E9F5AC2F0311FCA01FF5EE2FA29213653
+:10D10000ADDE21F04FE0534778D74E2E25C037AA29
+:10D110001B4F8779DDBFDA82F3CEAFDA357D29D2B6
+:10D120008D8AFEF9FCAA7F4B073A9DA7B0380C0107
+:10D13000C73285C5E9B49BC7E3CB8D5DAE663E3192
+:10D14000F3D81B958B43412E425C49888EF3C7ED83
+:10D15000CF60FCDAB9DF1FC1B8C485AFD17DA7F5B8
+:10D16000CF6FB79310EAD341E42FA57532C685126D
+:10D1700025943D55737F44C45B2C7CC18EF02DDD1E
+:10D18000690A16D3F6A52F1F1B8CFEF015ADAF0351
+:10D19000FD047E2F31BB7C203C782AC4552A2CEE1E
+:10D1A0002356EE8E32317B4DF3AEA419A0FF48DB3F
+:10D1B000F6A23FA9B4F676D5A4B14F7A4C2A8E4B8D
+:10D1C000EBB17B2E74DFC18F08F39B3C483BBFE57E
+:10D1D000ACBF6719DD94D6ABA817956EDB8476BD1E
+:10D1E0008A6D1730EE35FF85E71C00878A7A591F54
+:10D1F0000FB54D0E99305E4B3E6262FC4917975455
+:10D200005EC7EE6594D7F2B89F98B898852FEC7EEC
+:10D21000394041B3F0C5AD0EA0A3B34D5B1C004F28
+:10D22000DA1FC6134DCA49106FD4519C51EDC3711A
+:10D23000E38CCEC23F2882DC6DD2C767926D8C4FE3
+:10D24000D15DCFF6C5B1670A7D65E1735F3C0D71B5
+:10D25000AFCD3B3F7B1AE6BDE8EF979E86B80DB297
+:10D26000C7E202FDA1E2F71F61FCA068B7D4C4CFFA
+:10D270003FCF6EC5B8CBF39F9850FF3BBFFB542602
+:10D28000E807E7777C9D0EF1944B7617A2FD61C904
+:10D290004BF99D499CF3AD48012F835711F719BBFA
+:10D2A0000FFBEBE4908DCEF3DC6113D2775BBC58BF
+:10D2B0006D198BBF73F338B1EDF1E36A457C537997
+:10D2C000DDD44937027FAB6372BC2DDEA9A3F8B071
+:10D2D0000FE97E5E7F15FBB69DC7FFC5ECDB39F815
+:10D2E00007DD9F274CFAF8B02FEAEEFDED535056BC
+:10D2F00017FF3E99A0E38EE025E276E798BC411344
+:10D30000D0CDCEFFC4383CD8AF6237C8F92F32C178
+:10D310006E795A6D457B60EB6E930BE2B64A777F70
+:10D320008CF471FEA58318174B78FCEC79D2F6C308
+:10D33000E21DB94DA2A2C6CEE2CA38DC21EECCED88
+:10D34000C0EF3CBE8CE1AD883B4B146FF691A91742
+:10D35000BF77C1E2E2CADC4D4680BF360E4DCA81BE
+:10D360007D3AA28BDF13EB8EEDCF057018A98D9B54
+:10D370004C14CFC7F5F1B67D627CF8FC261E47D968
+:10D38000161F4948F7A110EFC3E45D4550FA98C451
+:10D39000A1471137D9144B8FC1AB8B97EC78BEFFE7
+:10D3A000183CF69B98FD49C0A5F9727C7EFC19A734
+:10D3B0006F7A2E396BD2DC4BB9879F4B441C9998FE
+:10D3C0006F552D93BBCDDB985E184BCFE5DCDE1E91
+:10D3D0003BCED77C9CF2FABD8381EF34EFDBC5F105
+:10D3E0008DE173F9F623C600E7CF412D7F86FEE27B
+:10D3F000F013D9CCFAA3E7D8B8FD556CBF10B7BF6E
+:10D40000B38AF77698FFD926A6679CAD958B827173
+:10D41000FA3FC7E54FDBBAED463C57C90E2BF29FEA
+:10D4200025F69CC3CE54488D18BFB072398F77F85B
+:10D43000A92703E0BCD27E0B81F9AC06F868CE992F
+:10D44000AACB4F40CF51337CC3E1FC24E62BCA8DDD
+:10D45000A90612D4EEBF12C0FB91137B7DA5807C80
+:10D46000695AA6BFD7D1A4B80EA4D0FE9A0A240F39
+:10D47000E8B3EDF14CDFFF64AFACB38781ED19D6B3
+:10D4800075D163C0FDB41B422E5A85D82D4D197835
+:10D49000907313B7928E21DDE8DF7E64D9B61E70DB
+:10D4A000CFCA413C1294DB3D6DF75BB03F27898DBD
+:10D4B000B3261FF6C926FC0A3094BBF6825DC2DA99
+:10D4C0008FF483FB3B2E62F5C0FB0AEBF8BDC7B5BA
+:10D4D000763FCADB8474E361F75E849DC899A3E854
+:10D4E000EEC5247BF5F994987B90825FE3153A0AA8
+:10D4F000FF71FCDD87E442B67EB057F54D8FCE3725
+:10D50000398D7842503EC186F1CC361B9B9F982FB7
+:10D510009D0FF2030A26369F81E100E8E1745E3137
+:10D52000744CF0DE139DDFD198F9E9F4B83BCC5C84
+:10D530003E2844013E623337110EE78BFA38D300A0
+:10D5400081B803671B5C6939ED274B9A6482B80583
+:10D55000179C827BE37831EDBABBB4F7C5EAE11FD3
+:10D56000A3D05FD468043FBF5982E333E90CB80607
+:10D5700040509A8C008C5FD9443E84FAA2AFEE20D2
+:10D580009E3FCB6A0F62B901F2344D497217741B8A
+:10D5900042C8C36B0A0A32FA43BD5919060FE61B8B
+:10D5A00015A0A3C9FE0CC310987EC1AAC631846C15
+:10D5B000259503C0A2645EE56D7CA307E01541A735
+:10D5C0001D09781B0137B78A3C6580F0BEC2566BD7
+:10D5D0005BDE6BA67C716BAFB67C00F23500FC1B8A
+:10D5E000603C6FE32A88F331FB5699E9B893371A08
+:10D5F00090EEC6466C78FE20E14EC89F09A9B4FAA9
+:10D60000E2DC976EB3F3F07A1DF1F1AD3C1E79B216
+:10D61000DFEF81ABDE23B93C26AEF030B88FDD62A0
+:10D620009EFDA4594B871B2FCABDE8FC9E84BDA755
+:10D63000ED9D45AE5BFAD1F939371858FCACD9FFEE
+:10D640001BA8DFF721BF01AA8C25E1FB25E0C37FE2
+:10D650004EC5F98871AA76B37355D56A437005E251
+:10D66000AF5B02F916DDBF70CCFEB5B2FDAB3F82F9
+:10D67000FB57DE7084ED5FFDA6BD466E8F8773CBD2
+:10D6800056E2D901A6A71D6B661428745F524CADF3
+:10D6900055B0AF2A995E50DC1FE1FA425CB8F2F94E
+:10D6A0007504D7ADA737FF7C30E8F5CD064F5F1284
+:10D6B0008597A877C8CCE2C4A659FD0D304EC5E3C6
+:10D6C000E12A38FFBE7AFA7DF403F76DBE181A4CD2
+:10D6D000E7DB770C37A7F071B7366F467FE656C0A9
+:10D6E0006337B8EEFD2B404E268607C3EF3678D45D
+:10D6F0001D41F818204FBFEFE4F728F2EA252FC8A4
+:10D7000089141395A3347DCFCCCE31C7CC324F9939
+:10D710009DD1D9DC4B01BD386F9A01CF534E9E4647
+:10D72000D7CFE3FFCC8A4EBE88FD147844487512EB
+:10D730009C730A9CFE3FEBF1E6B1A45EB47CECF175
+:10D74000A3F7835D4FB4DBB28C78E66AEE4353FCFB
+:10D75000D9A56B57F88015ECA1A23EE065BC730219
+:10D760006D7716DAC138B08E5DC72FCA00EFABDD1A
+:10D77000D7D8EF4DCBE8787D12D38F2F97DD2B8A4A
+:10D78000FDFE77B3F03B327DC41BBDF7F777C08752
+:10D790003273D8318DEE6F79EE2523C06145D2F911
+:10D7A000D1F1FC9E89E6D174F95A1BC8E97D115369
+:10D7B000DC7B04FD2D4CBF7877D90C0FF8E11F16E8
+:10D7C000F704B83C2BE07CB7A04F6931635A9AB894
+:10D7D00031305870B959085FE8FC8A727628203FCA
+:10D7E0000B89465E32F93801F49187F36482716ADD
+:10D7F0002E5527DF6E057BB903DE05A96C84E16F2A
+:10D80000CED0DF039D34E68802EF158CCFA1E2581D
+:10D8100082F769F4E5B7C6DC139DEC9DE529E0E5E8
+:10D8200097F0FF415CE7A49C3B3C055A39A154F7B3
+:10D83000837D3EF8AD1C576F7CA00D3E3E84EB2BE4
+:10D84000160A9FEB619DB35631305D191EB1708C85
+:10D85000854BC19FE7317B610C3C6EBE5CDD98124D
+:10D86000070EEDD75DDD0FE4A6805F2C1C9AA02E7D
+:10D87000EA4DA620E8814D4A18E1D844E118E07E3F
+:10D88000ABC274CD3E8BF970FDE156FE3D169EB1E4
+:10D8900070A4FA05EA0FE307D9D10EF636C00BE300
+:10D8A00000AA3F34D1EF6FF651C923C0FB42633168
+:10D8B000CEF02682B022AF489505E8977131FF0A75
+:10D8C00095E70C1FFECCEC57C51136FF716E162F75
+:10D8D00043E17134061E4763F040776E899DE72B64
+:10D8E000F08F5171F083E3C1220B3FDF641237DC0C
+:10D8F000FFCFFE64B893F185F8F2716CC4D7D60FF0
+:10D90000D33BD8FB1C12F1B77D77D17E425E15E385
+:10D910003FF3CD2EA48F7CE24D81F72020C810E686
+:10D9200029E6354CF2FDD49206EF378D4FD1BE0F6C
+:10D9300021C617FB92CFE1974F027BE11C9A4F94CF
+:10D94000CFB5EB16FD5559B89ED593F4443F391821
+:10D95000434744FB13EB4B4921217C3F4432E33DD9
+:10D9600027FA5FC0D8293A9E881FB5DBA7545B58B9
+:10D970009C0461711221DCCF3C5E9EC7DF6922E608
+:10D9800084EFF290EF92A2F37BDA2229F86E029FE5
+:10D99000DFB937CC0188D77850F26F86719AA5B776
+:10D9A0000703BCA83E760DDED38F29BF74B8B11C27
+:10D9B000CA69BD79588FAF6BA1CCEC64F4FC8FEFD2
+:10D9C000A1B4E7E3CC9E46C94D211AFACCB332FA92
+:10D9D000BE95B8BBE37B69C4AF40DA6861F7D06E2F
+:10D9E0003EFC18EEDF5BD69BDF007A2B224105DF81
+:10D9F000F971E9F1B0433CED177BFEE5EFBA28ADD4
+:10DA00009900D77D966BFB801C13FAC2FB16DF1FB3
+:10DA100060BDFB2C8C3F1FF58E7817E4C2ECDC61F7
+:10DA20008786D3D460F6E1BB0BF7025E5178E6003F
+:10DA30005ED1B6FBA0EB2E88576F5846C0FDFB1891
+:10DA4000BC32337BDA6CCAB6601D796BD46FB4F329
+:10DA50006A8317978B1DE987A4912AF4E9F0DE0207
+:10DA6000C3CF7D165300F4B6BC87597CC41CE27F3B
+:10DA7000BA5AC2770074FAFA5C0BB37BCFFDB505D6
+:10DA8000E99C36DE50097E2E0B7FCFA11F7B77A746
+:10DA90006DBC6A4D7BD877733AE2E15CEE3F3C2E79
+:10DAA000B173CB5C4B21BBF7BB5EBDA8C5C7D8F13A
+:10DAB00013F61BD36E9FC4EC24FB5437C6838976C0
+:10DAC000E72D4C8E5F34F7DD60B8C27DF079E64E0D
+:10DAD00003959468FEA4C532239E5E20FA6B3B97A3
+:10DAE0008BF30431AF6EEC1E3D4FAC5EA11ED09F98
+:10DAF00027D403FFCC79C2F5887A60156DFF848145
+:10DB0000F9DF88E2EB3F59A30775B1327DF080CD94
+:10DB1000DBC54AD327B8DE48359CFE5A7BB5A897AB
+:10DB2000BE348F1C1B167DB74D52E80CF1DD0DFF86
+:10DB3000729043CA0C827281F29F7BE2C50BD9EDD1
+:10DB4000793D601C41970F1BDC35D52C8E01FDC043
+:10DB5000BEA5B351CF9BBAB404D396A397AF01FA35
+:10DB6000CCE3701E60E5F69324463792E41F60858F
+:10DB7000F87CAF6C073FEBC27A99FBF1D87B575327
+:10DB800027C869F0FD9859C5F3E13E3BDBEF63849C
+:10DB9000BD5B9377D0E4ABA3E965923BC1AAD13BCF
+:10DBA0002F9302CC938C74F46B8B7B8CC748169BA1
+:10DBB000EF1AE637B8B8260BE39BF7A97A3BD5589E
+:10DBC0002BD393C75AD9BECFE6EFDB019EC13B13DF
+:10DBD000B31537DA0D67478CEC7D353A0FC4438BAC
+:10DBE000BE9F22DE4F515B3F04EBEFB3C4F6A3B000
+:10DBF000FE393EC7C2FD354B7E31ACE732F14EB047
+:10DC0000221EBA15804FDEF0C6C3C0F73AE6F30114
+:10DC100009F87CC56529D413EC68752A9EDB9AB98E
+:10DC2000DE7FAE6E7FFA6C9A96EDF8C001E7C3BB5B
+:10DC3000F93E9D539AF03D8A452FC9789F9AA26F6D
+:10DC4000FA8FB0FD9C6C761F84DD6710F2EF866F53
+:10DC50007B77F7613D763F41E85DF9E64010E6B736
+:10DC60006FB98CF62A2A1F75EF9314D6B17B0BB1CE
+:10DC7000FAD812ABCAE338D93E2E71B17112D17302
+:10DC80005EC44A821A7ACE53DC0ACC3F2FE220418E
+:10DC90000AF773A737AF9B48F13C90A1E2F98F4A8E
+:10DCA0009B46D407A3FEF1467847AB91AFE740DD32
+:10DCB000D469F0EECAEBA472D5205AA720EC4F65C8
+:10DCC000C44D4F6FD9517DACD0A5D70363F5C4A225
+:10DCD000864757C11B2DCDF001C6379B30BEB89D7E
+:10DCE000FE68BE39AEDE48C8A3883F37BCF4CCAD71
+:10DCF000F02EC50D670C2E98DF34AB9BD153DD257C
+:10DD00007C37A19C84A64379799DEC0AD1560748BB
+:10DD1000DD75202F857C1770095DDE6FF6801CB0E5
+:10DD2000C8AE15B04EF36D3688BF18DD323015E43D
+:10DD3000DC3EB38AF6C93C4B5FDB1C0D3EEF4B6506
+:10DD4000EF091C48EDADFF6E5E771DC8BB5D3C9EC4
+:10DD5000ADF1E49DB630D69B9A8AFA9A90EF317A6B
+:10DD6000ACB0838DEF2BB7D9C1B4FA2F91373C6E8D
+:10DD7000A1E5B75EABE27DB88230F3A7B693EF972B
+:10DD8000FDABF83945F7BD88EB0DEDE47D14CE3AD7
+:10DD9000FDF4552BD7CFDC6410E89BA1CBEB16E24A
+:10DDA0003DDA8624D70AB433307DA6E578E9BA098E
+:10DDB000F0FD6D99D94D2ECB4847FBF62CEC19D6CA
+:10DDC000D02F9514B86F5F0EB970FE35BA2F5F9ED5
+:10DDD000B07A028877B5D7C5F79705399C425D9927
+:10DDE000FD3DD095BD8FC1CEA33745CFA34DC00F0C
+:10DDF000E07D19101B191B8E18E1DC7C8EAAE888C7
+:10DE00005F74D1805F3779C3B24B339FE356662F7F
+:10DE10009866F51E023E122079DDA872424AACDEF9
+:10DE20005C880F6F9D4C5C9BE97A769FCE93549AE9
+:10DE30001FB325CB23D1FC4E5038816FBE24072160
+:10DE4000CE6427DC67A3FD2E68AA3666D171037500
+:10DE500032DAFB1770BBF969359099ACC18F5F2638
+:10DE6000B1714FABFEDF423FA73F31A11DFCF4096A
+:10DE70006B5C797B7B12E397AF71793624C98DF99E
+:10DE800050F3ABAF77A5F30A455C4300EEA5DB2E5C
+:10DE9000C8F09ED28D5C2F2B7EBC6915D86B266E88
+:10DEA000685580EFF882AE4210B553B6795490436E
+:10DEB000D3B6FB54D8DEE97595189F34A3BEFA009B
+:10DEC000E4EF0CD562FEBA24FFDF00AE37AD69DDAA
+:10DED0000FE8D2A79A28F8BECFE74CDF4AE3F3E871
+:10DEE00015F1EC732236E71A00BFDBC67FA84901A3
+:10DEF000957EE22A363EED4F4D82FE2A5BF341AE1F
+:10DF0000652E65FD6592BDCB9DEE68BF632F3749D9
+:10DF10005A3B42DE4F16211E3DFDE0A29E60670F78
+:10DF2000FCC944FA66719A4885EFDDF9FDB270FFCD
+:10DF3000293ABF74C8C4F08698592AF0C96B66782C
+:10DF4000E4B2825EF0E3272BAD4017A93EB7511B28
+:10DF50007798B7AE78C09B80A71613DAE3BE1CC2D1
+:10DF6000F4F62F1FB505F9F97400E0AD9053B363D3
+:10DF7000FC2E513A67784FBB08C23C444AA4152E88
+:10DF8000A2CD935006CCAB4712E3633546F74C184D
+:10DF9000AFC66A72C178B3CD7D8DC097DAEC9A3C7A
+:10DFA0002E6D34D72B779FDE9702FBFAE590E5992B
+:10DFB000A02F870CBF413ED4115E3D66F566273128
+:10DFC0007D0EF57B517FD749EB409083AF097DCB28
+:10DFD00033AB27AC57B49B9AC4F4A89DDC3F27E829
+:10DFE00020B58978370D445079776AE0313189C995
+:10DFF0005191EE54DD0146472C9E73A73D64EE0D12
+:10E00000F4BAAB37E6537DC4E681F895FABE1EF04C
+:10E01000D3503A9F98A489DBBB91D37F6A532BD20C
+:10E02000DDD59E034670F886945A4E3F04F910D011
+:10E030000FE3CFA16EFC1D1EF4FB015FE0FBD34597
+:10E04000CAC03870DC67B1EE544EF7F773BA0638C1
+:10E05000407939CF8BF2451C5E85F240A7366EAC15
+:10E060009DDC5E9A41403F2C5CDA15D3724E670B03
+:10E07000CC8FA29D7441EAA3681F4DF55663BAA0E8
+:10E08000A01ABF676C9885F8B1607DFCF7C5DEE229
+:10E090007AEFB9D306F68E94C1DA15F04F9437595A
+:10E0A00055CE0FFD0F023E9CA95BF7E46077D4DEEE
+:10E0B0007BA686C9C112AB5EAF5BC6F161F7E7FB19
+:10E0C00052005FBEB4544FBC13E8648BEC5A0EFB95
+:10E0D000585328B9E3E09F16CE00D78A9A2FD0AFC5
+:10E0E0005A4EC2E8573DC3F53137F79F0A3F6BB030
+:10E0F00086F1D7D32AE3EFA7A51409E803F83BF08C
+:10E10000D9D3271EC97C10F048B2A35E037C738765
+:10E11000063F166EDF54D595FEF3A6CBECDE4E48D7
+:10E1200021362D7F167822F86DECBC37F17D1578FD
+:10E13000383A2A87362571BB686FDA6FF9A317D191
+:10E140002EFA32DFBF1AC037A0E73502DF8618D8B3
+:10E150007B697A3A1EF903F1EF5D8F3D95897687E9
+:10E160001C4AB7F0BE1AD0751CBCD8C3F1F231AB53
+:10E170007F17CC3F96DF9F91FCBF4DE91D6DBFEB34
+:10E18000E42D03666BFA59CFE1F1A5EAEFE98A03C2
+:10E19000AF285C4957D8E712BA330007B241726919
+:10E1A000E3DD533730FBFE7B9C3F88EF222FE03DC1
+:10E1B00036FAAEDC7B494CEE1B4124670499DC2720
+:10E1C000865BBA821C5F60F5DE827696470D04DFBF
+:10E1D0005195F210DF536B9E38F9ED70482DBDD08C
+:10E1E0005F42DC06F0832E78D88DE7BD15BFB320E3
+:10E1F0009E9D4862F1112B6A54C4B7336A35C6E15B
+:10E200009D3951DA13FC2D814F981C4A044F813FF0
+:10E210003B39BF1178D76B2DC3BB1AC56B05BC1337
+:10E220007254E0E7992D370F057A13EDA378E31ABE
+:10E2300022F06616FDDE6B4D5886FDA1FBD60A70F6
+:10E24000E8BDB615F957A27D137E34B17F82AF0FBA
+:10E25000B319747E03838DCD3F3581DF3F2AD7F418
+:10E260007C98EE87641BA1C77FB85A29E8A9B90337
+:10E270003AB8C7C6DE77AEFACB1CF4DF0B3F8CF0A2
+:10E280008F8AF1536C0C1F12F9515ACCFE4EB618FE
+:10E290003F9F1BF93AF39B88DF33B0780B8B63DA2F
+:10E2A0000545C02F8E5B83DAFBB9D72AC4AB0CA51A
+:10E2B000D861CBC2795D0BAC82E653971A491F7ABD
+:10E2C0007EFA72D4DE4607AD3FA1355C7C3D5DDA57
+:10E2D0002E6378DA24B0EB126F29E8136883073CC9
+:10E2E0006F66FD1257AD6E9E03389CC5BE887527BC
+:10E2F000925B89F6E31E1BF77BF1F2583A37F2F294
+:10E30000D39C8E3AA6D38013E8F42612580EF1154A
+:10E31000F4A08D71696D744A0FDED07F01EF577CD8
+:10E3200017F938745A604BD3D06924CCE894D3A33E
+:10E33000B346F5C6D34FA6D8983C72D614E6823CB5
+:10E3400071FA30AC9CFE30BA5E40E91AE83500F450
+:10E35000D919E0C9E8AC97B71AE3197BD530BDFAF3
+:10E36000CB64B6DE05377AF7C27BC80BA85E2FD127
+:10E37000AAD59CAE13C33DE494987C72023FB96960
+:10E380004C381FE4AD1BEC169DF1575BE0A68C1DCD
+:10E39000438221BAEFEECB84F189134FDDFD20F0EB
+:10E3A00087476D78AF49C89FB424FF3CC0CB44F485
+:10E3B0004CF1D20B76A7C55FDBD8F92F81DF7BEC60
+:10E3C0005203E99382785EA1C5F3B1BE5619E09A73
+:10E3D00092E4CF5093E9F836EF38730FBABE2CAA07
+:10E3E000DFD2FC4F697E2D5DC7D64E61C2F355B6B4
+:10E3F00051FFB83D2EB0F6A6D7C1BFBF25C9FBEF70
+:10E40000308F16B32F00FB7C53B75619E395AED26D
+:10E410006F5F017638BA9EA3B70DF8DD2CFA75F65A
+:10E420001DBE2A2815F6E291DC5E5CD13004EDC8F1
+:10E430001ABBF12F6D57B01B7734AE83D33DC56F38
+:10E440003CC739725A65E08B82AF6CB475E2F81C38
+:10E450002670AE10F4057C09F45A113F00F6433BD8
+:10E46000FA2382887F90770E8DF29BB5D586B8F11E
+:10E470004DDB6DB6B87C9434FCEDE507C53B8A8C6A
+:10E48000AF6EB769F48A9AEAA3E94C4F65EF92DD63
+:10E49000CFCFF2EB5678DEEB931ABDD73CCA640CB3
+:10E4A000C07B8AF460E67669E223A506296487B812
+:10E4B000BB6F6811E0D137064CD7FDBBAF280BEC22
+:10E4C00025870D9E1504E310103E393D09BEB35358
+:10E4D000CFED9CB9C76C5EF0EFB74866E49F2D475F
+:10E4E000AC01909F2D7603DAC71B779B902E2EF5FB
+:10E4F000B1723B465067EF10FE9A4B6FCF4901BE99
+:10E50000FF24F75B3E79C735687F14765945A13003
+:10E51000EF04662976EF326F6957B49B0A3B6DBAF8
+:10E520007996C4828458FF8A99AD2B5DF14B60FFC8
+:10E53000DED4417CC35F6D46A1EF1E06F8563C1445
+:10E5400036C27955E8BB421EF76CEEB517E21C7A6D
+:10E550001631B3D8A6668301D6B789A25172567B0D
+:10E56000BC12F8B3A97D1CC1099B865F4E5ECDE24B
+:10E5700008DAF2BCDD6F791CC1D8E3475FC4F7F25B
+:10E58000CCFE8F74ED0AD3ACF1DEE19EBEF4416C9B
+:10E590009F08EFA71BD8FB3BB1DF4D76CEB795CADE
+:10E5A0006E78FFE9AF3F4E72C7B1C74CFFCB6CFC32
+:10E5B0003D11B1F6B3E8F8FFEE29A0FB26D9DBFC4C
+:10E5C0009499E037EBC84F193BEF43AABF473CF99A
+:10E5D000141B4727C66BDF9E9DBFDAEA19897F8728
+:10E5E0008DF53B54D36F8E9DE93DD32582F1EDE44B
+:10E5F0005B82725AE009857B373B2DCF7EE7D830AE
+:10E600002BFA715A65E003970EF7E98EFEF304E7E3
+:10E610004D311F42FC7DE3C5694C877776E2AC6FD4
+:10E62000849DC9E7E92AF3374877F4C5F3FF748B73
+:10E6300049D2C6E567D9251D3D097BF33ECB48BCD1
+:10E64000BF0876F978F08BF5C366818F348DC1C52C
+:10E6500013079F84DF4FC0B92AD79BAB30BB18DEAE
+:10E66000434BF532FE995A44D07F3652F2223C6E2B
+:10E67000B6337D69138F7FBBF4368B57CDCE75E3F0
+:10E68000EF71A272A2D03E02E3A95E3468E2A9044F
+:10E690009E543D47E5B1CE6EC8E84A9C9B93391F16
+:10E6A00076C17B129A7AEE87800744E540F755667B
+:10E6B0005D3E73898B281A3991ECCDD0E5BBFB5CAC
+:10E6C00056382F752F72EBDA09BC13F17CF8930AD8
+:10E6D000EB76A1DDA9139FCF48C98F78037C0DECA1
+:10E6E000C1F7F27DA2EB9D037834B6287C498B37C5
+:10E6F00062BD1DADEBE83237F2C2E3CBE87C295FA7
+:10E7000098B3366B7906C2DD45E01C71729919BF6A
+:10E71000DFCBDB273F3E0BEFC926AF72A33D36D9D7
+:10E720005BF93ADCE349AE74E3BD81B9D59204E705
+:10E7300074CA67B0DDC6652E4CC57EBB68B9648BF4
+:10E74000BE239E487EADB2DB74FADE15E4D72AFB09
+:10E7500088F6F2CB60F6BC097EFDB206D90D78B121
+:10E76000B2B813C6F7AEAB65F7D9F637B0B8BA751D
+:10E77000D3991C11E39E7FC989F2E2BCF87D29DEA2
+:10E780006FD2A7A0BFFF9B74E0B39B6CFEC7EC1ACF
+:10E790007EB9AE618485BFAFAC933FF4C705F71B6C
+:10E7A000D0C726819E34648DD21BE9FE29684FE6CE
+:10E7B0008587597A039EFA3F8077482F1DFE3C13C8
+:10E7C000F64FF8EB843F4F8C23FC7D92E47F463B71
+:10E7D0007E7B7F9EDE0F253BCC18879B23B3385C66
+:10E7E0008D9C25B08F2B411FA478B6F28815E1B11E
+:10E7F000F25B466F749E2FC0388DF66CC41F214F9C
+:10E80000E93C07BF4BA2F3AC30B4666ADF21D5CC3C
+:10E81000B3FECAF38C8953E5F392ED0ACEB785585F
+:10E820003D30AF7AA3E7B01FE4EC792BDAED5ABCA8
+:10E830003758E03DD916728305DE99DD6EF337C295
+:10E84000FECB3D5A1DA067EF6F18D61FE69BC8AFE1
+:10E85000DA6CCB7B03E645D7F716F20957F8D2F30B
+:10E86000EEE8FAAEE08F7D0FDA7D8FF51FFE3EEB0E
+:10E87000AF80DF8FC10CDDA84F499CEFC6E295D475
+:10E88000B0F76B880FA2F4837199814C125C49E157
+:10E89000543588E117994BF8EFC7D1E3C1269BEFB8
+:10E8A00034AC57D0DD15E0D30CF37EDCE63B0FF53E
+:10E8B000611E70CF83F299562EAF5E341AA27A543D
+:10E8C0004A0AE357ADC904E36762FDDD76FB94AF06
+:10E8D000A05D7A3FBFE41AF8BDF09C38AE08BF10C7
+:10E8E000C63D887BA665E09785F8AD3AB559FF7BB4
+:10E8F00074F470D86EF359A1DF401E7B2F0EF06ABE
+:10E9000025B9223C1C0E84873FD941E1615729BEBD
+:10E910000050726665009C5BCC2C1E60E772068717
+:10E920009677181C761D37201E3F410620DD0D35D9
+:10E930005CBC1BFAA7FCA31BF433A6B55682F36F8D
+:10E94000E712B701F86CB7568F6CB832DEF6743048
+:10E95000BCEDE560FB703FECC3B0B7995DE60A78AB
+:10E960007B0D8CF73DE07EBD63C4D5F3178A57C39A
+:10E970001C1ABCBADAB82889DF8F8CED8F9E87D03D
+:10E980004FB0779709F951F94E761FB47CCF293CE7
+:10E990007797BF6A42A42C78D5C2EE35D4B1F2F392
+:10E9A000B9F1FDF9631CEC9C55567B9F472F77030B
+:10E9B000F8FD97DE8BAE3E72D43F9A3281DD13585C
+:10E9C0006911F1A0CC4FEAE07896D2C3E705B9927D
+:10E9D0005248F0BE80C3C6E206DBDF0760749BC608
+:10E9E000DBB95C6E09E01D7B3F200DDE8B667E6E21
+:10E9F000C417D960F580DC4F298AA9672B423F6A8A
+:10EA00005ACC7D82390EEE4735920CE023B596F84C
+:10EA1000F7805A1D42AFB3E2B94EE1F36AB41BD995
+:10EA20003B2E7633AE7B71324929C6BC82F23CB6AE
+:10EA30001F91267B0DBA7B26294556DD3B0A69BE10
+:10EA40004EBA7CE7195D75F5BBF87BE9CABB950C3E
+:10EA5000D095F7A81CAACBF75C7A83AE7E16453812
+:10EA60006DBEF79A5B74F5FB564FD1E5AF5D7FA79E
+:10EA7000AE7EFFE06C5DF975DB4A75E5836A17EBE6
+:10EA8000F2D7D73FA8AB2F27D0B35F72B0F38E2C4D
+:10EA9000F46CFB703FDE2BB29B2593E63C57CDF721
+:10EAA00023D7519401FEC755F6711970DE6C4CCE18
+:10EAB0007686E3F42BD27FF41CF6BC436F3FCBE3A6
+:10EAC000F6B3F3FB281781DF57B19FE201FE7E26E4
+:10EAD000FFF30E6E0F98E586FAFCDD0AC583EB980E
+:10EAE000EE30A35D2CB6FF6A873BEEF94936785CC1
+:10EAF000C552627809BCEC085E2FF3F9FFB3F03A17
+:10EB00001413F723CE6FB1EDCE390C5CBFF637018D
+:10EB10007F6B3BA79156D987E7B4CFCF0708F05357
+:10EB2000827A4B223D408C2F49BE4FA09F587EEAEF
+:10EB30005B3A8F9D330D5EBC8F95E8FC76CE117BE2
+:10EB40007E2B9C81FB916CD4C1E9D3363AF7EACE97
+:10EB50006FAB92B3F1FCB64AF5665CCDF9ED5307A5
+:10EB600032270A77373BC78AFD347ADCEC1EA75E72
+:10EB70007F69AF6F53F947D7B90EF43809F4B2146F
+:10EB8000A67FEF64F7FDC5B857A16F13E755E8DB23
+:10EB900026E259A3C8B85F4627AC7F5EF87E8BFC9F
+:10EBA0000FE9D74EE7F7907FEFAB1E8CEF7F7F82A8
+:10EBB0004CE0DD954B4523F19E74227CFC90DB5F9D
+:10EBC000DE7532F87664BF787F59C915EF57BC3FC0
+:10EBD0009EC5514E89795F778493D1CB2427C7078F
+:10EBE00013B3439C7BD98EF1F0E76EF9087F2FD2E7
+:10EBF000B9BA61C303F87BC03C4B206E2660B3A357
+:10EC00007D6FCAF811C397DB3578C47FDF58FE2BC0
+:10EC1000EF38C07E336547EFB4802D31FE4CE2EB18
+:10EC2000234AF81A8C977EED0CFE3E9A29BBFAA671
+:10EC300031FBA23ECE2CD6EE33656939E29BC897F4
+:10EC40004508C695B5E515769FB82CA2601C5A17E5
+:10EC5000279783DC2E94105E5709CFD8EF029EEFE2
+:10EC60008F3FC3EEC55BE2EB1B3F71EAFD16B1F7C8
+:10EC70005212DDB798CDF7E952D128BC5F3FC5E805
+:10EC8000EE7B35762A01A7A6CBA792802FEC81FBDD
+:10EC90002E71FAFF9193F1B33DDE13296096CE35C4
+:10ECA000B7E603FEE7723B789C78FC0AA0BBB19103
+:10ECB000A21F241E7FA993DBED78BC7B81D3CDFD01
+:10ECC00092FA78FC8EEE134D36C6976FD3A2F0FB06
+:10ECD00008E8F5FE8D2AC6EDCDA7730880FD6D937B
+:10ECE0008AF6B70F2E9B08F8414E6D509F8138B3BE
+:10ECF000928DBD373E4EF325E34DE8B799BF89BDF0
+:10ED00003342C65B82E07F2DD9F4403ABC1BFE192A
+:10ED1000A5DB4554699ABFF1098C7BF9E0F823180B
+:10ED20005F7D06E8997E2FF9F667D301FEBB8CD58F
+:10ED3000D70DA1E9A2ED92EE7E44698D459717F1BA
+:10ED40007B62FF8814BD37E1A6726433DF2F21AFE9
+:10ED50008745FD5D9B9DCCDE8171F0E513D8FDA854
+:10ED6000FD27D9F9FD401F16DF171A7F7BF110BA76
+:10ED70008EF169EC7D96D8784002CE31783F85C718
+:10ED8000EB8EFF4469BBC7C2CABDB642CDFD80D77A
+:10ED90009755E2BE8CFF35B39B8CCF6271ED09E3D2
+:10EDA0000433DAC5F9F703B9D92E3E307A7FE76824
+:10EDB0003CBCF9430C5DEF3FC9E201E7BDCDDEC7C6
+:10EDC000EA886F7EC8E7FDC1F101773D4FE1F1416F
+:10EDD00011E3E21F5CBE7935BE3FE39308C4659E34
+:10EDE000BA1CFF9E58B253E84DFEB6FB34B03F53F9
+:10EDF0008B16B4E5812C6FF3DDA7BB6F73F5FCE6D2
+:10EE0000CAFC64A593F91162F97B2CDEFF9FE2EF47
+:10EE100053C61FC884FBF734FD1DDEC3DFC1F86392
+:10EE20002C9DC7F27331AFD8F996450CBAB8E16999
+:10EE3000C0074668F9B911F93C55EFD9BB30D94A3A
+:10EE400070A5847A80E4A270186E0BA6E4D221FE2D
+:10EE500007B1ADBCC8008000000000001F8B080097
+:10EE600000000000000BDD7D797C54D5F5F87DF3C2
+:10EE7000DE2C496692C96412929084093B15718018
+:10EE8000B008A82F04421482032AA2069D84256C90
+:10EE90002191AAC54A9B810444441AEA8614ED4094
+:10EEA00041F95AF41B116B6C834E04115C6345C528
+:10EEB0007E15C3229B2811AC1FEAC6F79C73EFCDC9
+:10EEC000CC9B4C58FCFAFBE7173FEDE5BEBB9FFD22
+:10EED0009CBB4CAD737D82BF2F632929EC369F9D6F
+:10EEE000B1B3F87755383D611F69760E62ECD138C1
+:10EEF000BFCD990AF5DECC1CC912191BF856BDE22C
+:10EF000087FA271536B93E46BB1FE34C8C41BB2D13
+:10EF1000665EBE05EBF50D97A739F37F8C83FEB6D1
+:10EF2000DA20857A8CD99C877A3396C74C2C496530
+:10EF3000AC58F1A7E17815B69695A5503A6FF7B79A
+:10EF40001628620F5BFCE95A1E63814C8B77636E57
+:10EF5000FB713D4EA804EDD2168C6407073266B5EE
+:10EF6000B140DC00C6148D05CC03701CFF2213B425
+:10EF7000D72633B65C61AC19E686F559EF74134BAE
+:10EF800063ECD736467F81910C27C30207E28335B5
+:10EF900030CE8F4CEF8970F889E9BD705E9F30BD2F
+:10EFA00037A672DC5AB14ECDC4FCCFC58047A953F9
+:10EFB000E1E3305F4F9F83B1E923993F121E321D79
+:10EFC000E7D4A85EFE2337E5B440F9E7FB6FCE61D6
+:10EFD00090EE787848524B8CFA32FD437595771451
+:10EFE00034BDBFDA4F6912633ACEE781EA99DE5148
+:10EFF000DD1973421EE735DDE2EB991CD1CF65CEFA
+:10F0000064C253E2E55B9ABBBA193BB442752A1E4F
+:10F010004899A908DB1F0C26156DEDCBDBB90DED6A
+:10F02000F83C55A633D60DD66DD7BE6B11B03BCB91
+:10F0300070BD8CFAED689DA5024F16E6B5617BCBDD
+:10F04000816B6CAC2BF4A7E84ECC4B7AB81C4640D5
+:10F050007AB8173F5D0E74A7F86F71523B3D459625
+:10F060009FCDC5F18B282FC767592EC6323A861718
+:10F0700053743FF67394E9A598365802973861BDEA
+:10F080000DF16C662C7A2E17F8EB21D6C598DD7938
+:10F09000F812311ECC6F63823E1BFB3969F3CDC57C
+:10F0A000F4CACEAD352AD24D9C53D46F61887728EF
+:10F0B000BF1DCB597A0BBB16E07D254C763964FF1A
+:10F0C00071F400F3009C125B0F310F8C9F88F88B5A
+:10F0D00001376B32E7ABBF3356149BEF142A5F281E
+:10F0E000E6B901F8C5E40EF3CB53D0EEB9BEC8774C
+:10F0F0007EC177FA350CCA37FCD1A52C87F2AEBA9F
+:10F10000C784F4E16E667A10E121E02EFBDFEBB4F8
+:10F11000101C900F9573F0E1AA8BE4C30D7F1C6760
+:10F120008AC379FE96797B78B0DCB3D806F927E6F6
+:10F130003BBDCB21DF6D05101AD4CF5E10BF5E85BD
+:10F14000FA6B9D7C9D5D1E628BE3A076EEDA560D18
+:10F15000E5C3B885CD9A0DEAE7D6B668289F5EFA72
+:10F16000ED9A1CA4AB639F5FA33AB0FFAF65FF00AD
+:10F1700020E0F7E14E8E4336B4B40BE267B393C39D
+:10F1800057AEE38FF1FEA7089F55AD0556A896B37D
+:10F190008069282F8F29FE3FA774C37EE32707FBD2
+:10F1A000227A39BDBD74F8789F32C8BF24F95D1941
+:10F1B00099C9D2191BB1C14CF01CB1E1E15B11DE60
+:10F1C00023368CD114A8F2841652345C6795AE05B0
+:10F1D00020FFA6D34CE31FFB7C761705E7FBB19518
+:10F1E000F58801DF9D62FD9B9D5C7EFDC3129B6ED9
+:10F1F0005F6D933B9C9F863345CAD757857C4DEC0A
+:10F2000006F09877F72992AF7F717AA8DF27B4FAD2
+:10F210009D99342FE60DC0A7D99BDE23792FC79186
+:10F22000F5E66C5EB714EB65DDE1ECAF7AB05D4BF3
+:10F230001CD2CFB7711C5FDFDE1D1F5CA410FDF771
+:10F24000F75D1A830F59C86A4A270CD878AADB4C95
+:10F250004301AFADADF928F7A0CBC5C89785C91E4E
+:10F26000035ED6B53AE3915FCEA70F0E087C5E2809
+:10F270001D6E4FE67C03F25F473C05066BC11AF832
+:10F28000BECEEE3F8AF23FCF1E4CC9872AB5E7D7E4
+:10F290009B2710BEA0374FFE2CBD29F4A5D49F6D2F
+:10F2A000E5029F35427FC6D09B3FC6D29B6E16BCFF
+:10F2B000BF1FAC879D307937B2F6E32E14FD9E8CCC
+:10F2C000D7D564187F84C27C386EE289034C89905C
+:10F2D00043F3045F6F1174F0948BDD3621C63A66F8
+:10F2E00009FA3495B45A5AB09F4685E8BFFD7AB9F9
+:10F2F0003C01B998928C7CD605E4A6D25E6EC6C05D
+:10F300004726CEB3F35BFA76249261C91B1200FD47
+:10F31000E7C2474E32E143EF82A984FF80B3EA6D32
+:10F32000BEBEEDE1DF3399CF7F9843EF81F54F0B00
+:10F330003EEB082F8392393E0A93B93DB3C521EACB
+:10F34000C519EBDD96CCE13C35D9C89711F81B9473
+:10F350001C037F520E9F8CF70DC575FFFDE89604C8
+:10F36000A4238927297FA2F115E6B345B41E807333
+:10F370003EB68FD63FB27DB41E0AB70FD07CD721E0
+:10F380001D21BF211D79B89E58D7373C3F49E7253D
+:10F39000627D67E3F5625C4FF43C9D274CCAB9E699
+:10F3A00099DCEA5690FF937527A5FF386A52705E84
+:10F3B000CE564DC17939857E8CD683202E04DDF062
+:10F3C0007EB6A3DC80F1977E39351DF1BC34DF9F1A
+:10F3D0005E05F5AF71E8FE64E223BD14E131C5A11D
+:10F3E0009761FA631CC7F3A0647D1AE693851D1527
+:10F3F0003DCFB9627D00CF39D84FE22816407D78E5
+:10F40000D5197B10442C8000E60DFA2151778E44EB
+:10F410003D96B89679914E53125A9BAC906F7D9859
+:10F4200079D743BE67C063B2A27EBB435F8CE9D28B
+:10F430002F55B23B97E6B3E062EA87DBA1ACB66B2F
+:10F4400090F437F05B24BDFE5ECCE3F7C99C2FC17E
+:10F450000EB92799E3F977984A3B44F2514776452C
+:10F46000041FD652BB0BE7C3FB71FD17C1877F4852
+:10F47000267F42AFA3799E870F1F0DF3E12358FF2C
+:10F480007C7CF8A4E0C3ED22ED880F5F13707B3322
+:10F49000B943FFE3C9587CE816F420E91DF910F5DB
+:10F4A0007DA39827C8CFBFC6A2F70BE0CBADB1F8BC
+:10F4B000329A1FDBFABB40FAEFC8FE1BE23AB7FDF7
+:10F4C000D76CE77897FC0CFCB253F0CBEB825F76FD
+:10F4D000717EE17A399ABFDAF44D2B97138CD525DA
+:10F4E00020FDC879EE97FC13AFBF17C967D24F91C3
+:10F4F000F093F5FF23E8FBA848135B0F30940B0053
+:10F50000B77F45EA8DA704BF048632E217F0B746FD
+:10F51000A25DF9D209B0232167777179306275F362
+:10F52000766475A6D5254C74740CA72B5D1E01CF8F
+:10F53000D87082F1BF8885B746C49BBDBD3D1F8D85
+:10F54000AFBD623D761787C7CF9D87841FCEE3325C
+:10F550009A87C7B43C42CF2B2E45D21973417AD536
+:10F56000A85695D1BC4209E042B5C9539605EDF3C2
+:10F57000DAB7B785DBDB5C30CFAB7468DF37DC1E16
+:10F58000C62779D7ED0E90676427EB26D44F4B73CF
+:10F59000393D44D3FD06B41FFA46E0AB2E93F0B5D7
+:10F5A000D2E64FC3F96DD03C26B4EB362C732A015A
+:10F5B000C263553CD28FCDAE135FC7904359AE8B1B
+:10F5C000B3073C2E2E87725D1720877A0BFC801CB8
+:10F5D000EA85F5EDE791434304BC86BACE6D0F0C86
+:10F5E00013FD5E29EAC790434370BC6839B4D5C6A1
+:10F5F000E110834F8763FD34A73E02F1047C7A85D6
+:10F600002B42AF41BBAB30BF52B45F5167EA4DF6FE
+:10F61000338BF7C6F233C6B9EC063BE50AE13FB0DF
+:10F62000C6EFFFF6DBC18C5562119FE738314FF210
+:10F630002736D41D4843FCC39F21AEF2E062EFBBE6
+:10F64000DD116FEFA80CEDD0077FDF62417837C482
+:10F6500027F6639785C7ADFC0E083205F0F29D8949
+:10F660005289C7798D8B0632F023F20FFE90837694
+:10F67000E5C9FDDF517CE484BDAC04C7DFB18DC7B3
+:10F68000494EBF353505ED7339FE7CC417CC6BB4DC
+:10F69000DAB73E04EB3DB5CBE2457DAB32CFA323D9
+:10F6A000603E95BBCC2C48728AD9B0BE994F9799D1
+:10F6B000772D6D561331AF05447C43394BFE8C27B3
+:10F6C00009E9D6BC4B65C887CCCDCB03CCB6E82CBA
+:10F6D000F89B49434DCC13110F49D6E39927223E9D
+:10F6E0009152E432E4537D9986FA9D2677359467EA
+:10F6F000F87F6528EF3C7380219F5D35CC50BF0BB0
+:10F70000F83B91F9DCC03586FADD964D34E47BD4C4
+:10F71000DD6CA8DF6B7599A1BC4F70B6A1BC7CF7FE
+:10F72000F316F4AB2FD934DFF0FDD2FADF1ADA0189
+:10F73000409ABB039D4C631CFE97352C36D49FD654
+:10F74000327B1CD26DFFD07263BB3AF3210ECF0027
+:10F7500043781E617E0BD299C65A777606B8CF0BD6
+:10F760002ADE10549BD590DB0DF9E18B378A762980
+:10F77000FD605EAB793BD9CFACA0313F47DD4CFC9F
+:10F78000138DE74AD635C9938774A0B2A012C6FB81
+:10F790009C4DC6F60CE35DD06E8E584F345D1C61F7
+:10F7A000558F8C40FA08E8CDDDD3C2EB36B3FAC1F1
+:10F7B00021FC2EE8C429E844AE5FCE5FAEDB09FF32
+:10F7C0006139287C0BD2D98C0685AD51DAAF6F66D2
+:10F7D000E3AAA59D63AC93B1A005FDEDE8F9875CB4
+:10F7E0000E37C5AD72580EC6AD583BFEB0933C3EC9
+:10F7F000B5560D5A81AED540EF28FE30AE3F1A8E79
+:10F8000017CB2F1E01076BBA915FE23CF1D1F436A2
+:10F8100038C4DAC335A1B7918F241C255C1DDECC1A
+:10F820009874E581FF387C75F64BC2F704C2372126
+:10F830000CDF9336FF4994C3A7F77EA312DDF95B73
+:10F8400006A21EEB482F391C234FA31C83FA3958FC
+:10F85000BF3201E46212F473E0879EC86FB29E6FFC
+:10F8600041997714C84545F1FFE08A888B34EBAAAB
+:10F87000230FF035A741F5A21E3EA9D9972997D1AC
+:10F88000323DCE3454D2126F1C8F126F4AE3F6FF12
+:10F8900028002F68E3B760FCB5C86BC3798227479F
+:10F8A000714E05DC9BB309A467E353283EA2338A5B
+:10F8B000FF9D62DE1AE8AFC6F1B74BCE130F494C7D
+:10F8C00021FFC29F118FF6436BCBE967B17BADD9A6
+:10F8D00089E34CF0FB693D43708260573327C029B0
+:10F8E000225E04EDD2B1FD84C7FF9880F6F04B870D
+:10F8F0004EA9A45F3E71933D2CED83F6F67580F41E
+:10F9000097B4D7C13FEA92C2ED985CECAFCD3F12FD
+:10F9100076B5F4733AEA07EC8EDE68CF74942AAFBA
+:10F92000AAA44F5B9578EFFA18FA342F4589A94FAE
+:10F93000417FE6A5A446C4E3EE3CBD13E51DC07BB4
+:10F94000087E7738C0AE512EC8AE198EF51F4D48CF
+:10F9500024BA6EDDAD067B418353364F920BE03601
+:10F9600052E85945031DE20AB7ABB2B9FA6A03B1CE
+:10F97000BC4F128BE1A7C87424D64B89882FC619B7
+:10F98000FDD1A503F8BC8A53B83D739FB09F4AC50B
+:10F99000BA2B310E97128EC3554EE671E687A3E25D
+:10F9A00097A5290EAABFC43EB214D7B3345721BBC2
+:10F9B00069A9A218F6919253F2A9FC16D17F29F4F5
+:10F9C0008DE33DD595CFCB1DE5BF678BFAD929BC1B
+:10F9D0005FE0A43E886F8BAAC684E78C143E7F69E3
+:10F9E0003F49BE192BF8A650C8CBAB7B80BC24E6A0
+:10F9F000D2C78D86F251A29CA96BF758A17C6C2FBF
+:10FA000033433A1B857209E5BCD37CA0A57758CE59
+:10FA100017F6AEDA81E2614C3A7C8F902745CCD75D
+:10FA200019E9E06A8FF1FBD83D85C7905FC7328D39
+:10FA3000FAA1EFB91CAE09AE30BDFF3EA54D1E794F
+:10FA4000CE025F87E2FD0F1663FCE16DD5BB9EB56C
+:10FA50005FEFFD026F2B849F82FB48E87FB844DA9A
+:10FA6000BE3E87CF6B76DFFD044F0DE0097C1BB2F5
+:10FA7000B4D424E1381F301A2773A6DE84F9413E3E
+:10FA80000FC338F1D25C66F7227DF637511CC4ED06
+:10FA9000778EB240DEBD963C1566D658C031202C1C
+:10FAA000179E4EC925F8AF60354D49503F69EDD7D7
+:10FAB000AC2BF90FCE514E9443D358CCB8E646B197
+:10FAC0009E098F77D5D00F4BB2297A30C63A368A45
+:10FAD00075805CD880F2E12ADBFE814AD7B05C41B8
+:10FAE0005796FEEF9029B85169DFDE662F781AD756
+:10FAF0003F6826EB20CEC9E731DDE6ABA77A7B3C39
+:10FB0000B43F512EE5F33413D3806E6E126473D379
+:10FB1000DAA6FF903DF0C3D9B3AAB4B319F5CF70FC
+:10FB2000BFA07CAE2388FB07E58DB9018A0FCD54B9
+:10FB3000685FA3B2F13D1FE6CBF3F29C24D7121409
+:10FB4000E5706F32D11997631A3B2CE945158B820A
+:10FB5000FE270BBD20FD79D0032B1200FEE56BD7ED
+:10FB600035654095FF01858F78DBABFAF7DE03FD45
+:10FB7000DE00CA69C1004C35564271F474EAE77A76
+:10FB8000D14FE03BA61CB685C7BDA17137AD67AFAD
+:10FB900099056C404CE6917C68F36F93687F15F48F
+:10FBA000298D3BC956371AF5DC494B6B3F2FFAD7E5
+:10FBB000DB3ECA0E003D7DFABBD30E0678F84C6BD7
+:10FBC00075E0F7A30BDF77E800BF4F17AA4588CF92
+:10FBD0005B85DE90F03E22F07EB9DBB70FE17D5B06
+:10FBE000F58F83FD91719205A924EF670561861158
+:10FBF000F6C39C4D0968D1B4E52BEA530C79A907EB
+:10FC00002AACAC2A565CB0B39BFBF3B336AFB374EB
+:10FC1000F6E0F8FE561CFF28C85BC4CBD1AD8E20A1
+:10FC2000FAB3723E659BFB5BD0BEF8ACD1CA42E82A
+:10FC3000AF68CD6666E77244017AF00BBC47CF73BC
+:10FC4000E7CB09D4DFF487B9DC2985B116005CFD68
+:10FC50008DB348BE44AF63FAA79EC24E00EFE9F7EA
+:10FC60008126F7F0FA0B016FFE05F77E8DF65AF448
+:10FC70003A4B034679337599312FE560B9C037B0F7
+:10FC8000DF32B47BA7D719EB9537DE4FFD97A39CE6
+:10FC900092DF61FDC96E61870E6643502ED5D8BBD9
+:10FCA00026F9CFA1774E548381DA93B1E3D5364A52
+:10FCB0008F56334AF7A5707A9DDBF8DE5D4837F33F
+:10FCC0001A9EB3603FB5C1D1CE6150C5DA081C851C
+:10FCD000F625EE1743D329B85F0CF3ACC18964E075
+:10FCE0007EB2AF9B1BDA9B9D51FBC7627D2502FE56
+:10FCF000CCEE22FA2AC1F5F4C3EFDA3791EB39B52D
+:10FD00006BA00DC7EDEB16F27608AC4BBDF075C9D4
+:10FD1000F5C8F5C9F20A15E82C467B49DFFB84DCFF
+:10FD20009AB661C2D24C0045CDB623E41733619731
+:10FD30006B023F9A7D39D9E51A03BB9BAF53D8E5D7
+:10FD40006C0FF2ADA4B3683A2A473820133B793BD5
+:10FD50009BB0D7DBE8A7F1018287C433F0473ADFD5
+:10FD6000C70BA5E33E1ED0D1A1283A32E4A7D7198C
+:10FD7000F35F995B7290BF815E0E45C2F7ABA8F34B
+:10FD800023321DEEEE4AFC36CDA3173AA17C3AF39E
+:10FD90002D75D2FAEB082E47B5BA9DF720DF6DE03E
+:10FDA00074FF99C07B83DB57EA267DA5F7437D3539
+:10FDB000727186EA867AA52B1427F2D3D4DAFE85EF
+:10FDC000C88703984EFD4DE9C0DEAA7173F89755B8
+:10FDD0009999059465198C8172AD6CAB1AE4712BFD
+:10FDE000DD5E0C789829F05071DF73960C486756E9
+:10FDF00095733B20C8F905E04A76C0EC154DE457F1
+:10FE0000835F1193DFA41EA8A8379657B215848785
+:10FE1000CA287BE0F792CFBCCC8BF4E8BFCB615310
+:10FE200092CEBF5ED63E6E42719553BB7A907D787E
+:10FE3000CAE3E984F5FC89FC0C8DA2F987E07780A0
+:10FE400013E9A3D6450941B47FF79F01BF0E6D3278
+:10FE5000A77F8805E0D2F2AF6CDA6795F429D75313
+:10FE6000695B41F459C98C7E63293828180F2DDD50
+:10FE70009812C4FD71E8BF5F03DA151BCD64370427
+:10FE8000D8FC740674E65B62267958D6904C7E6B7B
+:10FE9000592DDF4729DB9C1C54B93FBE07E31012E4
+:10FEA0000FFB6B0B2C1984A75C2FEA35D66036D07C
+:10FEB000B7C44FB4DF377B59D3CE744FC7718108B5
+:10FEC000FC1CEA003F8722F1B3250A3F6C610A97C8
+:10FED00033B7BFD603F78D4E55C579D5187E84D478
+:10FEE000432C0B08707038BE569429CE3469DE342A
+:10FEF000C4E7E91583085FD1782AFA692AE183FD0E
+:10FF0000CBC130EE3AA51BBB6D227CBF4DE1FC316D
+:10FF1000A5E6EA22D4D76FBAB99C7917E4936E614B
+:10FF2000EC3D904F3AC8A7F7416E61FE83EA74CA70
+:10FF30007F54EDA1F4E3EADE941E12F6BCE41B202C
+:10FF4000000BDA51EF09FDF89E5BFA4177A4A3E9B3
+:10FF500050F4D3FB834C406BA98159D78CCE66EC0F
+:10FF60005ADDA8EF265F6FD4672D6667613ADA7DA8
+:10FF7000F729B4BF50E61B6EA8CF348F6502FAAFE5
+:10FF8000BD0786BF933DE7B14C047EBF695C8AA183
+:10FF9000FEA4659D0DF9636E0FB71B8BBA19BEDF0A
+:10FFA0005C7289215F7A06803010A9D94578B8C380
+:10FFB000C6847FEDE2714F71BEE49BAA219D7E0352
+:10FFC000F3FDE62D339547E343E275DA6A13F3C395
+:10FFD000D4A6AE86B541BF87EA004FD0EE8BBD0EEA
+:10FFE0008674BC74F3C07786427EFF6633C52FF7F4
+:10FFF000D7A6AC44FB68FFE6D4448C8BFA97AAC220
+:020000021000EC
+:100000008E705A5884BC2AA85D44E74E4A83562F06
+:10001000D90B3B024FC8BC4741BE679C5FF6A84165
+:100020008C5301FEB87FFFB495E2F247C16E738234
+:100030005E38AAB05A4C51B12441F9BF9B5383C8D2
+:10004000CF453FA97A3AD2D3D37162DF45A1FE8E64
+:10005000BFD763FD72A22F4F7D88F8D64AFEC0D469
+:1000600016BE3EA60CE88CF83F9ACCF4649844C5C2
+:10007000FC8FF66980A7593D9BFB85A05D496E28E2
+:10008000F5466877628399CEA160BF4EC857FCD50C
+:10009000BA8ECB11BDD3844B23E119EC87EB9E6262
+:1000A000F265A7027D1D9F11EC47F26C612AF155A4
+:1000B00034DC0F59FC04DF00F28112968F613EE3BD
+:1000C000FB6920D43250CE4C357BD3503F1D5A6152
+:1000D00026BB13F447228E0F9C4C747C48F314E229
+:1000E000BA0F2DCB6528AFE4B8652B54F23B90FED8
+:1000F000A8FE2AD50F3602937A2AB04CF1B34EED02
+:10010000E9E6D7B70FE984EB89B66F65FA15F0AA6F
+:100110003FC25E98BD4DF5A1FFC1F25AB4EB2F8DE1
+:100120005C472DDF5F48E7FDDF21E4FADCAEAFEF8F
+:10013000B39B50AE774B42BFE2D81E95E8EC58D740
+:10014000BAC1E9DDF0B8C8AB837F03F92F8A038712
+:1001500035C83F61F55F930AFDCC31ADC841FFE87A
+:1001600064E3C195C3A1DDF167CC5E1C76F6D3B321
+:10017000BA50DC5DD8D7EDE55628539CF3C9500042
+:100180009E733CF5A4B73D9B61105A7F90FB49429A
+:100190008F3B1F52D096620707399663DC622AB004
+:1001A00047A4DD7DD0CCED8292542EA7A47E5F23A0
+:1001B000F2534D9CAED9CB0AF96DF067D003522EA5
+:1001C000CF49ED4AF5DBF432AB27793503CFB1C027
+:1001D000FAE66EB20683B9D4C6897C3E8BA3873D0E
+:1001E00095EA213936DBF2CC23C843E5AC99E67DAC
+:1001F000DC1C9CD19C8BEDD7D5BAA8BDD94BF15353
+:10020000A14F6CC040288FCA05DF55D429C110F119
+:100210000DD78BD345FF0CF54C84FC6AAF578CFA95
+:1002200064BAD0A3D35954FCB5CEA8DF7C09DCA9AD
+:100230009D0DE3A2BE0CCF0BEC6380D90C7F70E761
+:10024000789AB7E20DC69847396B0DA938EFCD3CC7
+:100250000E1F3DAFE8755CE83C6778278C4ACE8B73
+:1002600018376ADE12DE14C08DC08384FB8C0087D1
+:10027000E78C4685F0F5B9B0CBE08FE2C612EFE52A
+:10028000CC371ECFD7953F04F232374C076D7AFF3B
+:10029000B920ED377CC1EA12ED40F773573F37E9DB
+:1002A000726CB7F63DF22F4A5CA11EA664C65202DC
+:1002B0007B96175D11639F21CA3EF8A5E083B3D7F3
+:1002C000068B76008FE91B543DAE9FA11EB597F6B5
+:1002D000C1CC40C08271C99922DE77BE795662BD19
+:1002E000011732DFD8F6CCFF75DE7B5285FFD4CE06
+:1002F0001EEA11D38F6AB383CEA37F3F3187B251F9
+:10030000FFB6666BA47FBED1BC1FE5BB511FF720B3
+:10031000BFA023F93A43E8E1E9A897213DBCFAF9E7
+:1003200044F4DB3F7FE879DADFB43C333D11EDE2A2
+:10033000C3ABA7AE0C004B1DDE3C95F470F91AA9B7
+:1003400087FD9648FD5EB0BAF4CFBF43FADC144790
+:10035000F1F9193BFCC2EE0679877270359777EC9C
+:10036000212E0FCB515FF5257DD50BEBDD35C3DF9E
+:100370000BE93CE23BE9B1BBA6FA87507BE60CA156
+:10038000DF05923384FA4AEA53A9673593DF9486EE
+:100390007A407DEB83BB61FD5F6E51C9BDAB50D729
+:1003A000E53831EEDF81DCFEF9F036B5C13BF7020E
+:1003B000E05D86F026FB87C3FBC0320EE7832B3857
+:1003C000DC976EEE9688FEED8165DDC8EE39B0B93A
+:1003D00007C17BDA728037D9BD1EA3DDB30CE08D77
+:1003E000763EC21BC62DDBE111F0F672782F137A30
+:1003F00067054FA7B5836BE056942777FDC5EA459F
+:100400007D7E342E948AFEC8D1E75486E70EDAEC5E
+:100410002261BF4838FF9BD53D8176543B7B669572
+:100420009561BC72D60B8E2083FC7125BF1322E030
+:1004300044DDEB89385E78FC363B66705AA41D7348
+:1004400081F899C77C742E7F5EE3EB7BD18E577465
+:10045000EED7CFB3D943C8B7E0EF9C8894E78A07BB
+:10046000651AC649BC361BD24116F3F8C8AE91FBDB
+:100470003F7E86FB3FDFF6F8FAD6F9C4CFAD3D23C9
+:10048000F7492AE343668C2FB53EA710BE2BEEC872
+:100490004FCC67B8BF5445F3B82E8DEB6345D729D1
+:1004A0006E6805BA8987F126A579F8778F93C71109
+:1004B000D7C2B88EF07CA3BF8F47D2437D6E8F1D0D
+:1004C00087AD15E354A826F23BE65AB8FF21CF7753
+:1004D0004C15E553D3B8DF3E2B8D9F9F3889F17DB6
+:1004E000E8F7E4AA04715E7914C533DBE227126EE3
+:1004F0004EEDAB3679857C25E207FBB00DCC739AC7
+:1005000055C47341C562FB5B44FB5BEADEA6FD3567
+:10051000F05C1E47BD3B6581D58BF66B609B95E813
+:10052000EEDE78BE1FC2DC491AF2D1CD42CEDE52D9
+:1005300077BF0FF731A7D425E898C2380126E2A784
+:1005400079B89F9A69A1F86989ADE51974B36F4BC1
+:100550003F78A70D96B6C8C4ED96452E46E7632EA4
+:1005600003B31DE3B17874E46CCAB9E8C7181F9EE1
+:100570008B71DA618C13D65082AB210FF0A5FC9AF7
+:10058000B4D1631FCA62EC9FCC7329E27B2EC206F2
+:10059000E9A13489E200D762BCD885A946743651F6
+:1005A0006301134F9761684DC68FC78B75DF309419
+:1005B000859260BDA1DDCC10BFBE31640AF5023C5E
+:1005C0005CAB859A90AE4D368F19FD015F9132007C
+:1005D000FDE4B98B2F6CBECFA4F968BE734DFC50FF
+:1005E0005FEBDD4A703DC0E9166072A4CF5B35B6A3
+:1005F000431DC0F187F457E9F204A8DEED9CBE6507
+:10060000DC5CE2A93F741F09DF5BC4FCA09F658925
+:10061000D8DE123B7EF4529AF483B9BD3947F0EB31
+:100620001C496F9B8D7CFA31F20BD457D0AE05B8C4
+:10063000DD22D28EE8FD43D1FF8769DCEFDE7191C8
+:10064000E355585988D6BDCD4A7894E35E2BD23D08
+:10065000693CFE26E721E999893894092407D2D11B
+:10066000A1BA1AB29B6646C5815964BC4A8D956F82
+:10067000933FA6B3985A5AA7E17C942BE3BC48D782
+:10068000B758EA7B54D9DBD793FBB125ACD9CCEF73
+:1006900013897896D057A3557B6FF4774A94782FB7
+:1006A000DABF27F31D015312C65BCC84DA12A00710
+:1006B00094CF9FC4F1FDF72949778D47BBB024D172
+:1006C000A2617A1B6B76E4E686ED92A5F930D94CEF
+:1006D000A4B2C0581DF235284F78FE7E3D8BA24350
+:1006E00022BFE44DDCB7B8FE07C03FE5978ED54189
+:1006F0005E9C7C4D94B37BA9FDC925828E03F78F48
+:10070000C5FA271F96E575BCFC3E59FE10CF3F2069
+:10071000FB17F95551E58BA2CA1FE379CBA30F8DC7
+:100720000DA03D2BF6634A8629244F0A059D952C82
+:100730000E117C4B4CAFF274240BE17D89F3D51B79
+:10074000D0C957887A4B751C72A0DEBE3C432F443B
+:10075000BB6340AA3FB913A4B32728010BCAC93D04
+:10076000C19E42AEC73C675D28E8F6B274DE9F8446
+:1007700037F493D929F5E2FB7919E735C8D04FB79B
+:100780009FD3CFF2F6F3E9FB73FA3919D58FB48B07
+:10079000EECDD4C7209CD821B7E1FCDC9CDF7B9355
+:1007A000D0AE62787E0E403F67717DCE40E87FCE4E
+:1007B000B32FE5CC88F0BBE79D31311DECA7CA33E0
+:1007C0008CD22F9A3EB678603EF3B636590AA15EB7
+:1007D00025A40511F39A2BCF8FB2166D62845E1F8C
+:1007E000D7C924CE25AEA2F9CE79F618ED5BCE316D
+:1007F000D51F5E83F19E613CFE16BDBE3CD16E1FCF
+:10080000EE23C7B0DB2776E27AF8AE2C7D02AE731A
+:1008100020CA0C480B6A62EFC3FF49F45712CFE5B8
+:10082000DBD4C10E9BE732DC47F5D7E0BDAE196BD8
+:100830007307601CF786D491B710DC3A8C8BB6F244
+:10084000B868238F8B96B89AEF00E1CD1EE9B4F516
+:100850007E1BF871631F957C062C0B6D8BAC32FFF1
+:10086000E6D8515914E7A2FCDD8FEEB83F00FDEC4D
+:100870008AE7E70CA60CB9341EE5424B6E82C90923
+:10088000F2E25677E923388F2943AE28C4EFF956B0
+:1008900047CF521E5727BAB8D5EDBB1DE905EB630C
+:1008A0005CC36FE1712EFF1B2AC5B9FCFD12FCB1C0
+:1008B000F6A92B3B71BA79A49393D25D8066B43BC1
+:1008C000E43CE4F860A8DCD10CFD1D5A9CD11FEF7C
+:1008D000CF35B8F31F26B888F11BDCFEC59897E327
+:1008E000C372FBE1F70B9D47B5C0C7C3026FBE11D2
+:1008F0002AD323FCC589A3120CF9EBC7A5303D32DE
+:10090000DE7A7D67437E72493743FD9BA75D62288F
+:100910002FB636E7555D84FD5BE970C4A31DF6690B
+:10092000E3BF3FBC05EDBA0DAA5781F5CCDAB6F1AD
+:10093000C3E150EB141E2FA5A0A787E25EC7F15CB0
+:100940001AF29EA66B91FB355FB2663ACF17B11FC4
+:1009500060D87799E3DC41E7097FA9FD9AAD9DC492
+:100960007EC0003C8A8CFAE8038AB3CDB3F3F57CF1
+:10097000F9D27E0BDD0340FD01F43D061BAAC8E75A
+:10098000018A431734ECA7FB56933A71B93C2FEB1D
+:10099000760D2C32560929CAFD42904F49401FCD91
+:1009A0004DECD2AD780E37D741E7262ACE4C642CD9
+:1009B00005E928D0F776A837675911E5E79D89A79B
+:1009C0007EDF559B0BE9BCF58B0AED1714779EB2C1
+:1009D00018ED51ACFF6B18AFF8BFC714217CE66D62
+:1009E000E5E72B8AD57FE6613F73EB8AA87DB1CA24
+:1009F0007629601F8C2DE07AB618753BE4D5C18E40
+:100A0000E5A85F554BA8E79F509E581C244F92CEF7
+:100A1000DC4CE3579EB151FB4F84BC30B7F0798D6D
+:100A20003EE3A3EF12EF073A7535DC0F34A76ED023
+:100A3000CAEC589F51FD6BCEFC8A52B9CE377AFF73
+:100A4000C58D72CC9CFA4D219E277DC3AD38C9DC83
+:100A50008892B7A7AB8624B118F2A86D9C33FC7CB2
+:100A6000B2F50C3FAF7C20433F837C3D7E618B869B
+:100A7000FB37CC6E7322BCC60FEDEF9911C147EA6C
+:100A8000AB3759102FE687DEB3A07EB7425A10511C
+:100A90005E21CFE347C9E39FDAE4F1224AA57E61F4
+:100AA000E937913D7AABBCCF2AF8E40B212F64FBE8
+:100AB00066A471C4E30B56F29FBECFF027A7433F55
+:100AC000CDF96CF216928FCD39B86FF24BCD1FF085
+:100AD0006C53C8BE6FA1F3FAE3877A4CB81F9096A7
+:100AE0002ED7C1F9F57CEB50D3F93ADE55D902EC9B
+:100AF000F7DDABAE6AD6A1BFA67B060E44B92FC701
+:100B0000ED956EE1FD3A5B7F407FAEF2E5040FF2BA
+:100B100075313A4779613B16BE338CFF55BE6C5D2B
+:100B20008FE7682A13C19F85F10B5E890B211D3762
+:100B3000BD12A7A17E782ACBDF0BE153F04AAF515B
+:100B4000E8BFE98D568DE2079DF4DEE9833A9EEF1A
+:100B5000F9E453349D49BEF42FE3FC522AE8B44C27
+:100B6000F09F5FF0D1E9AA4EC487A717C2A4719F76
+:100B700073A172E956B4073C0E3AFF23F9B218FD8F
+:100B80001EF85E7C4932F97F117C477C38F78C93E4
+:100B9000FAAB38E3117CEEA2BCE4B732C12F566148
+:100BA000474C13F43D3CD37F633ACCBFB806F81DE5
+:100BB000C6F12FCEC8433E0AD38BC5897405F49283
+:100BC0003E23826F6A9A6E62687F58DD3EA2976903
+:100BD0009046DA1FD3DBEC0F67611ACC7B7C6DAEDD
+:100BE000E1FE4989C0FF85D2FDD582BECAECA11EB7
+:100BF00068AF9AABE2BC789FEE949BEFCFCCBF8FEF
+:100C0000C36FBED95780F6C3FCC7142F6086EC0AA9
+:100C1000944783F7565922E38D379DE9C73C0087F7
+:100C2000EBCE74A7F48654FF6C8443E99949025EC5
+:100C3000FD7ED63EE0209DC797CC41AB771DEEB33D
+:100C4000C5F955C4EFD16CE67C3022BE84F1308CFE
+:100C50008BC9FD41196FB2E27E6A849EFCB756973C
+:100C600083FE4EBBB853BE711F6D6ED33F079BA072
+:100C7000FC78AE4EF1A729267F2DD2F3EC89C1670F
+:100C8000CD909FF3C0F38918EF96F0ACD7423D505A
+:100C90004FD6031C310E56BF422D0A727B2681EFC0
+:100CA0007F71BA96741C4DDFB3CF74257A3A5D65B7
+:100CB00025BD731AE89545E81DA96FA47C977A476E
+:100CC000D27385C6E556853D89CE5584F5CD041F82
+:100CD000C671596FC5DB8345EA9BF52B8721FD9FC4
+:100CE000747BF1AC4F34FDBF589D4EE76CA41E8958
+:100CF000D637529E4BF92EF5D5DA0CFF8B88F7913B
+:100D00007FFDFEF97FC1A76B34AEB7AED11C443F67
+:100D1000172E37F70BB9B9DF2037E77520F71BD34C
+:100D20002F4EEE3F2DF805EC57B20B51AE47F6F7BC
+:100D30007DC6C87711DF7BD2793CE0979A7747F27E
+:100D40007E4F1BFF5E98BC6F12EB3D9FBC3F22E4C1
+:100D50007DB47CC70B6D28DF4F6EEB43FBD3FB18D4
+:100D6000E803D47B8D099E8D42FE937E884F0A9EB8
+:100D70004BFEDF9535F54807F2FFE8FF45FE4B7A5D
+:100D800094FC22F943F24334FF487E187B3FF87FFE
+:100D900088A777F9FDA90A2DB099F60F3D09FD91B5
+:100DA0002FDBECB6AD0AF1593BBD20F826CC274627
+:100DB0003D21F942F289E48F0AC10FD3A3F861BB48
+:100DC0005AFFE03068579DE1CFC81814E68BB95B35
+:100DD000A2F542877485114336DD5DC590AE2A20A9
+:100DE0008DA42B6B07FC90937171FC60CFB8307AA7
+:100DF000EA9FF1FF9C9EFA67C4A6A70119BFA03D18
+:100E000071BAEAA33CBCCF743A0FE46C6E98DEC6AC
+:100E1000BEC9B8BDD08DDBFDE037D2BC7759B22951
+:100E20009E33F62C3FD72AE952E259DA01D3453CEA
+:100E3000615EA66F52466AD85FB8503C5BDDCD1646
+:100E4000F443A6431AA9FF3BB2776FC9B848BD9FC8
+:100E5000716176E2DC0C7EDFFD17B4137F83F088CE
+:100E6000C62B73BA0C7108D07FD791FD16D2E888D3
+:100E70004C877EC56A0E67995F12D2A4BE4D417D34
+:100E80000BF4B200C7FBB9F4525CC0443C70D738D5
+:100E90007D04E0FD0F22CFDE1A877C3869A82CDFA5
+:100EA000BD42D750EE301947A7B8C8BBAAC807DE65
+:100EB000786B14AC7FEC832C1C6787F2D12392DA19
+:100EC000E2280A0BD77FF4B1D7DF5A4178E6E75E14
+:100ED00098BF45E3FB4C229F077947447E68547EC8
+:100EE0002DAF9FA8B5307E4E31C8F955C5AD374EF0
+:100EF0003FBE087B04305988E709C66F559C180728
+:100F0000B979C449DA8F0DAFFF9FE3303E3BAF5153
+:100F100011F90FDFC2F5DEBC95E7B73DF6AF15015D
+:100F20004DF497467132FA33D72B3A9E7F983B5453
+:100F30000976CD6D0FE76D1946FF06FF34637B869A
+:100F4000E7EF2EA63DE299DA77A5F621EB458C7FF7
+:100F5000E388D8F712DE96FC25E209D43FC0F2BA46
+:100F6000FAD8F7243E10F59B71DF84E0757205D244
+:100F70004FB345C2F3AB1508CFD18CE73F7BECAB49
+:100F80007181BE7CFA7AD4FACF35FFA60CA3BD805E
+:100F90007F1E63FBD0B9E0F77ABBF6827E661AE962
+:100FA0002949F3ED380DFD2481FF8F76F13C5FDC9C
+:100FB0000AB4FFC3F4F11FA28F6619CF6F47FFDF9A
+:100FC0008D1B6527FB47D4FF6105CA379FA9AD3E3E
+:100FD000E707495FD0BE377F9F8DDAFFE7B1EF5754
+:100FE000207C003F544E79ED1CFC501F951F11C50D
+:100FF0003F82FE897F51CE037C7AC49033E9999C6D
+:101000003EBE14E7AA9B47723BB159DC9B1A9AC9B2
+:10101000ED424F2687636F51BF393E020E1178862D
+:10102000BF10FA2111EB2638DDE496EBCE2A1ED74D
+:101030001DDABB78F980CCF4070259E17C747F7922
+:101040009959C5185F0DF79FF936C2F52601B7A16A
+:10105000999DDF0E7079A8205F561081005D6C5558
+:10106000022AFA09481731D6CD32DBF15520AABD44
+:101070006E3E477B4BFBF67A547B66CEBB98F602FE
+:101080006FE3A2F05A1485D75151F912990F1AE45F
+:101090009F948B650DAB96A4B9312EA9D09DCF300E
+:1010A0003DFFAA18E9798E53D2EF2504D7303DF7DA
+:1010B0007D1BE5FFC47A290F2F7D4007BC4D407989
+:1010C000382C9CBF0EE505E5FB15EB4991FAE2B221
+:1010D00007507EDEB84CD6F752FD9B6B657FFDA9AD
+:1010E0005CE291050614135EF384BE080C7C1BCBF6
+:1010F0006737F2F673D6E4BD1DE87E0E7EA88B82BC
+:10110000CBDAA87C20AAFE43E7D12FB551ED1746D4
+:1011100095AF88CAAF8ECA2F33B62F9DA6101F96E3
+:10112000023D2022CEC797F764B6D9A96DFA54B113
+:1011300093DD66E0ABB1353CBF644D7EF1B2BE11CC
+:10114000F9CC82E248BE90F77BAD6E467C61EE4002
+:101150005EFE3AB30379D93B5ADFF2F2CFF09F1922
+:10116000B4BF63B00BB6ABC67C932AE73DE1ED3B61
+:10117000EC11FBA0CC578CFE41C7FB2DE38B474500
+:10118000DA2581E262A44BB94E59BFF0C7B32A8E6B
+:10119000F7A7CCE2E20DB89F3352EC43BA780A7A53
+:1011A0004D45BD5929E23185783E16EBC5877ACC8D
+:1011B0008FB443587D4F5C67D33DFCDE40A006F002
+:1011C00083F135E6B5603CA5292969C193507FFBC1
+:1011D0003DEA02D4A3FB16A4D0B9A43399DC5FD8AE
+:1011E0009ED4256D3AE49B126EB3E0FDE4A67B47E6
+:1011F00053FAAAAA2F6D055E7B694D49B1BD0F96C2
+:1012000027117C5EC89C5CBC08E8BC012FED407BCC
+:10121000BFCB9986F71AD87233E3EFE5789F20BAEF
+:1012200079C0DA1FFDE7D24597D0BE55D9C3130A5E
+:10123000E9DEC21233ED67C01F9D3FF12F1F4DE75E
+:101240009EA6D58A343086D2577EFA4B4D22EEDFE9
+:101250003FAED07D892BBEA97F13DFE5295FD6CDB8
+:101260008BA87919EC7A3C8F7460752FBA2771308E
+:10127000AE8ACE7D427D86F5CB7FF0BC333E0FEB50
+:10128000AB4E3C5A7118BEA33D7CF83E75BD82F34F
+:101290004A74C4E379E9C33F7ADE41BB16CA9D8B29
+:1012A000E1FBE125B3D2D0CE3AAC78121558FF0756
+:1012B0006B6617A767E0FD7AABC0E76C4729ACBF48
+:1012C000D4D4462FA43F6624F3FC0799B38B37C2CE
+:1012D000FC0F3FD68BCE7D8DEBAC7F980970CAC8D2
+:1012E000D23FC2F4A0B877FCCA4F7CBFF01F27CA18
+:1012F000D2305EB75FF0CFCB67CAD2CA22EC9D195D
+:101300005F6A84F7572C9E3B709EAFC4672B743E78
+:101310009BD5A760BC7B9AF03F807E173C1FC3EE35
+:1013200069CC54A9DFA6FB5347205EC3747C37C940
+:101330004FF21B207F6ACD9DA4D70E5917B083288A
+:10134000B7C4F94586AF0D21FF6D8E0BC6E562FC73
+:10135000532FD4C98FA9EF39D111C177A2FEA701AC
+:101360007E3EF753A88FFEDBA781FF7144EE43C892
+:10137000FAE5898E001A13471C0E0DF1B04FAB3EF3
+:101380008CE7FA663C6E26B93FE3F1D485AD286F51
+:10139000805E303E16BDAE2B3B9B793CA2233E0CBB
+:1013A0002C35F2215B7A4E3EB4FF69C939F9B05C45
+:1013B000F829858F9BE99C7AF9208786FB8F231F6C
+:1013C0007F6D23DD5BBD3D6E00DE4F287FDC4AF87C
+:1013D0006A7138024EDC1F4D7468C9906676E6F873
+:1013E0001DDE99F34D81CA34DB004AE95E82DCD709
+:1013F0003BB6E0C147F018E571169C3404E0770A6B
+:101400001106703925EF6545EDF355EC7EDE92CF80
+:10141000CEB1CF779EFD3DBCF18C7C78A1FB7CFDED
+:101420003B8B73AE6DFB7CE69EB88F582EF6F90AA7
+:10143000D6F2F35BE50BF83B1C05293CDE7BA83AB2
+:10144000808FDFE27A034EBC9FFB10D72FE54C095B
+:10145000DAE09F63D6DE4EEF933E2DE44A29BEA329
+:10146000D517F9C59B837EFA8CC7E308AEE54FCC50
+:10147000FAF03168D7B2A8D81DE9178FE96C9670D9
+:1014800065784F57F67364D1EF7290EE0BFE0CFE49
+:101490002DDEF74B66CFDE948B78CAC8C1FD485964
+:1014A000AF7CF13D3D793DF08FC10F2EBD4FE5F78B
+:1014B000A65FB092BE031E4F6711F799A7D5EEB68F
+:1014C00058FA86EF7F1D803C5EA98FB80766417889
+:1014D000C97B49F8973E58D8DB1E921FF4BE70892D
+:1014E00049A1FB4B20B9E8DECF9D9DF97EE1ECCE12
+:1014F000DC8E2DCDF1D2FD978A9556EFE25CDE4F62
+:10150000DBBD6A3CE7646A9E41FB8F7FB3525CA4FB
+:10151000B2364E8F4BE4E722B6F4A573D19A05F7A5
+:101520004D3C5C4EDC29E8AFD233610CD20B94EF1A
+:10153000D5F01C9683CBC38A64F1FE1BB437C13847
+:1015400027F15FDD78BF19FD22C657C477E8C7933E
+:1015500018EE7797892DC3B80BD6EFD30FE19832E9
+:101560006932CEEF1995F81816BF7228DA77CFA82E
+:1015700003D1AF2DBD6F7BE16ACC3FD71F6F2CB07D
+:10158000D267DF277D3147E0BF459C072B833CBEF8
+:10159000AFB6B233D7F77E95C77B560A38493A9033
+:1015A000E515F7F1F350154BAC64BF542CFA88FAEB
+:1015B000AD7034A7A1DCAD78C14CF7985789799705
+:1015C0002DCA1EB117E8AACC9C44EF48CF0D145B7E
+:1015D000303FB74EA17CB85D6A0ED2E917B52F2611
+:1015E00022FD1C8C0BF5403DD47A7B9C17CFE1C9C2
+:1015F00078DB17B53DD6635C669AB3D981F791A6BF
+:10160000DDD1CD85727B9F3364C1F27DF5B926CCE7
+:10161000EB4EE708CCEBDA6594FF429C3BA13FA47C
+:101620001785E379EEE6ED96AE30DEDF047D7CF9DA
+:10163000CCFB3D514F55E434F7447D0274D0B333B5
+:10164000C2F96985F4F0BCCDFC9CBAA48379480743
+:10165000C077B3051DCCDBFAE26F901FE621FE07D1
+:10166000B4A723A0D31DF47DCBBA42C6DBEF403A2A
+:1016700091FA0BF2B56617C6DF441EC6C1FC8B0893
+:10168000CF542A1FC5CB037DF939B7163AB757296E
+:10169000EE2BB6C9A70EF0BC47E0B16C9195E4ED16
+:1016A0001E81E796FB5E48443C7EF9CCF69DB84F20
+:1016B00052B105B4B427065F08B854221C12691D44
+:1016C000645754E2BA13C37068A37FC18F958CAF7F
+:1016D00053AEBB52137090E5A2FD07826EE6320155
+:1016E000B7ADBD38FF097E437EA67776C4FAFC2EDF
+:1016F000E37BE2DF89F51D147A612ED005DECF622F
+:10170000783D51CA0928FAF2B97514F791F892F3A5
+:10171000B66779A4BCD3935D613CB69862BFA77CE1
+:101720005AC06FFF924E390D00B72FC0BFA273038E
+:1017300040AF5AC478926EE478057F9D700DAE1765
+:10174000FA0F61FF72DC7D81040DFBD9C7387F2061
+:101750007DA2FC947C595033E59AFE78EE37F0A5D3
+:10176000A35B5F5C2F1FDF9EC5CF2DEB6827407BFF
+:10177000BD41A1B8F37EE1CFEF5FF2626259049CF4
+:10178000E2B338BD4B3AC33F8C47C9F9EE72F1382A
+:101790006EF4BCA51C92F32EB8F7C66BF0BB9CBFD1
+:1017A000A457499F128E924EE5FDB7687A255A9349
+:1017B000FA5335C87BD28F63B2BEB6F8EDEDBF47A2
+:1017C000E7A51D74509CDF6E4D653C5E5F9BBE239C
+:1017D000F2BE0FFCD923F54E843E59A145E813A96A
+:1017E000FF2BDD3ABDAF322F8B9F2B39CEEA2DF97F
+:1017F000D0EFDCA3CD85899EB0DD79C5372115DF1B
+:101800003599BB959F3F93F09E7B6207D17D85B84C
+:1018100097547ADFFBC54390BEFFCB4CFB31A54B01
+:1018200046D3FDE3591BA70E46FAC1FB0C28CF8F08
+:101830006D1834903FCBE54C9B84F71A363C38E961
+:1018400066F83EAD41F5925C877E905F4BEF1CC819
+:10185000905E0EC6B5140F437BFD6ED589F6FAF087
+:101860008D831662FDE18E2EC9B81E7D430AE57593
+:101870002D89F482B473E5B9BC1A33A787C9599C82
+:101880008FAE6D4B399D15D4D4F4C4FDF3D675716C
+:10189000F49E518945DCE3DCD689FC894A0B5E293C
+:1018A000A47BA16487CDB4305B063FEF6CCB80EFA7
+:1018B000BBCDCD77A2FED87DA7A33F9DAB577F18A8
+:1018C0005CC6ED67BE5F98627C3F48CEE346317EE2
+:1018D000747FB2FD2E71DEF8A098FFB1DAFF9A8412
+:1018E000FAEFD8A61E2E5CF7916D71740EFF48D4E6
+:1018F000BB8C177B4F0BE836EA1ED4627E6F20CB81
+:1019000068BF493A3FEF3DA54FDC51FB01E73E5F21
+:1019100074A29AD17DEA4BC1A7C0F6A3127E7C1EA9
+:10192000CFF5CDA8B33AF13ECB21A47B3ACFA3F2B9
+:101930007BB736CE07879EEB1F44BF71C627FC7E60
+:10194000D18E55F7D2B982E96057E251AA363BF9F8
+:10195000A15593900D4E79FD4B33A0DDA94DFC1C94
+:1019600044BB770B763FBF33F2DD828BB58F2FD42C
+:101970002E96718587B38CF7C0245CA57FF40AE0AE
+:101980007FE880309CBEAA9E4976F1896A3FA527F0
+:1019900095FD2B8723DD3A92E8BCFE3F1A1E54F1D9
+:1019A0009D958AADFD7F40FF76983DC989FCFA552B
+:1019B000F502DAEF3C515D4569F8FDDC20A5576C76
+:1019C0006DA2765F350C6CC47BAE2FDB9384BC8F2D
+:1019D000DED7E178ECE8FEAE5CD7F1BB393EE5BC82
+:1019E0008F6F9A9A88EB6AFA534AE3E588C7842492
+:1019F00027DA77E5E29CC7E1D5DC7E3E6A4B7A7256
+:101A00001C9E0F597B5D1ABE8333BDE9FA49F87DF0
+:101A1000C636C58976BF77DB8444F4433FD75A1274
+:101A2000F15ED3E7ABE57DA820BDD33AAC88D1BE4B
+:101A3000D3B090C63CB97C8B19E9E4F2131ADD3BB4
+:101A4000FD02F7A330EEF1433CC53D98D8679AFEFE
+:101A5000128F97B4F9B1C28F1B2ED6DD8ABFB39116
+:101A60001AFE5E30947F3FB2F6F9F1D8DFB10D6611
+:101A700027CEFBAB0DFC7D86D9E07FE1D594A39BFF
+:101A8000B87F33BB5E217FF8D826D0CFB0AE8ADBDB
+:101A9000CD3ABFAF69A4BF0228C7738D92FE66EB33
+:101AA00041A2EBE8F73392593DDDEBFAA5E8F1707E
+:101AB00096F13C661B1D76847F0127E45BA4438975
+:101AC000E7D9ABF9BEB9ABBE7F3ED293C47BF4BBC2
+:101AD00072351646F71202A6787AFF7782DD6356D2
+:101AE00060FDD7B95B46A1F89C98CDF5B85A60D295
+:101AF000F11E1AABE1F7F3DBC98F2C6E0FD56433FF
+:101B0000EABF73363F2F2CEF63C91416924DEFEFE7
+:101B100025B8FEED812AF6C76BC76B30FF09C35DA0
+:101B20007776F3028A1E5F3E5E03BA9D30D0F5429F
+:101B300057C8A765DFC7F397B9069921BF68D1FDDC
+:101B4000E347E1EFB264EBF1D911E3C87EE1BB23D7
+:101B50001BE6B133C5EFC4B4D2C2EF479D545AFB64
+:101B60002DC80DD77F4F61FBFEA184F32D6646EF94
+:101B7000C074C6F90FEA38BD255BCFE0E31ABF9702
+:101B800031B684CEC705F8FD16F8F3D9D2F0FE11B0
+:101B9000A7A73279DF6599F1BE0BF3F2FB57F21E6E
+:101BA00092BC67D4277C7F6AEDC5DC9F3A6986F5D5
+:101BB00026B5BFCFA634BE4EEF61D504584B1CE10D
+:101BC000C1787FA52281BFD337FF852F772059CDDC
+:101BD00092F60A2ADBC1E1FBFB2C9DEFFBDF29E833
+:101BE000F04835EBDE1D58F9DAE6E6440F4CF6C452
+:101BF000F8504FE46F8FD59F8FF03FB2B6266BBE83
+:101C00001BEF7D5ABDE3A0FED120BF573957D89BAB
+:101C10006C43AAE073357415D4DB95DB87DE6F184F
+:101C20009BCDF5F289DC500EBEA713C8E5FE0DD49E
+:101C3000A3F36B458BC7A462BD13CFDDDB7D3AE018
+:101C4000CD8AEFB7B9286578FFE96A3BBE854CEFCE
+:101C5000BA3195F66983FC9D31A897887ADD3335D2
+:101C60009DC7D1F9BD39892709FF76788129A03D23
+:101C70006AB23133CEBF0F5BEB447D21F123DF31FC
+:101C80009DFF028F9FCC575A6A5330FF8C42E7DF8B
+:101C90008ED8F8BD9EF67A6EA305413D73ED54C310
+:101CA000FB3CF2BDD05F3A0E343F5BC897FEAC7F81
+:101CB000E47BACE5A2ED68B5C483EF49CE4FB5D166
+:101CC000BB1DF31FEF46FA041C6116598FAD4D2161
+:101CD000FA589AAB129C6735307A77A7B82193CE21
+:101CE0002B8E6B70519A78269DBE1F7BF2CD3C2EB9
+:101CF0007F381E8A9FEA44EF47173FD56B24FFD1F8
+:101D00008176EFFFF07793ED36BA473B7F37D74BBD
+:101D1000F36F50293EC9C4FD709F988ECFBE8CE2F0
+:101D2000393E16FB1D589F7C0756379FF31D5809F7
+:101D30005FABC04FF4BBB037EC1E988E7EAA7C1709
+:101D400056BE63D72CEE6D45BF0F7B6F6221BD0F72
+:101D50003B59E77A24FA7D582D10E745FBD69C6560
+:101D6000E7EF35F8A3DF8B6DD170DD9346F0F762B6
+:101D70006F981CF12E02FCCF3CE26B92D3E611ED82
+:101D8000DE0732237D5B7DC6FA5B24FEFBB03EE7B7
+:101D90007C8F37CB42EFBC69F85E35E42789F77852
+:101DA000D18E43FBFC94CEDF95B3C6F37537B3BC3D
+:101DB00074E4FBFFDFDFA13EDFFBD3D1EF4D47BF74
+:101DC000333D70D71F0DF941CD6B0CF587EC5D6F7E
+:101DD00028BFBCE56943F9F0A35B0CF92B5AFF6EF1
+:101DE000A87FD599570DF97CF6A6A17E81ED7D439C
+:101DF0007EB4F37F0CF5C7A41F34945FEDF9C25095
+:101E00003EB6F769E37A34FF59D487C5DEEF0DEDAE
+:101E1000C633CF1FF01DE71BDD267AAF43C911F68D
+:101E2000B5A0BB1FB384DEEECE72507E8D564784C4
+:101E300088EE1A14E2F7683DA67DE1D3311EC75E35
+:101E4000E4F7BF92C0EED322C64BD66DE01086F306
+:101E500029454E433ED5976EA8DF69B2C7509EE133
+:101E6000EF6D28EF3CD36BC867570D35D4EFB24008
+:101E700037E473034586FADD96F90CF91E75930D68
+:101E8000F57BADF61BCAFB04671ACA2FD95465C887
+:101E90005F5ABFC050FFB28680A1BC7F6899A17C09
+:101EA000E0AE3A437E50F36A43FD217B8386F2CB5A
+:101EB0005B3619CA871FAD37E4AF686D30D4BFEA0F
+:101EC0004CC890CF67BB0DF50B6CEF19F2A39D1FAB
+:101ED0001BEA8F49DF6F28BFDA73CC502EED96B125
+:101EE000BDBF367E17764CB1F73F86F68191E27D15
+:101EF000E82D0ABD0F7D5B4E57F9AE684B1CBE8BBB
+:101F000018F051DCC78507FB504EE1BD6B173F173A
+:101F10005342F12337D939A48A3C784E07EC8044E8
+:101F2000F4AE7273D14E4E08DB63596723CEC99D60
+:101F3000CF1EABC86144E76B73FC6539A9E87F3CF1
+:101F40005748EF7BB3C0529C877CE7EE9DA8778D06
+:101F5000657AB5ED288B7CFF78775C5DD68073F869
+:101F6000EF57DB4E307C57B9AD5F11AF50607DF35A
+:101F700023FA5F09FE82D69DB1BA6AE01BB091FEDA
+:101F800058EDA4FC43D5E9947FA4DA43E9EAEADEFC
+:101F900094AEA9F652F9DAEAA1947FA25AA77CB0CE
+:101FA000BA88D2F5D53EFABEA17A32E59F04BF18B1
+:101FB000D34DE02763FA34F8BB58BE19FC5FCC3F21
+:101FC0005B1DA0B4BE7A197DDF525D47F9ADD5AB7C
+:101FD00029FFB7EA20A50DD59B28FD7B753D9537D8
+:101FE000563750FEE5EA10E543D5BB28FF6A753346
+:101FF000E57754EFA5FCCEEA164A77551FA5F48D78
+:10200000EA562A7FABFA0CE56B4DFCF740D6E41894
+:10201000F721645EBEC720EDBFF168BF23710C35A8
+:102020007F65B0DFA3ECE8687C1C1771DDF0FB096D
+:102030003DD7D744F84F4F8AF1E47B0CD1EF2830DD
+:10204000619FCA774FE57B0D33C4BCCA053F0C4284
+:10205000FAEC4DF4F9D6C5F80BD21F1C90EAFF1B21
+:10206000D167B62940FEB09DDF27BE21D5FF52CEF5
+:1020700020DC2F9CBE93C6737A69DFB0D81A4ABDA4
+:10208000318FDEFBA6B85C47E3558A73DF1D96BF30
+:102090007C2C0BEDE9A29F547A67EB1DB3837EDFA6
+:1020A000F02D0197B7724C86F4E354FF9B38CF6F45
+:1020B0001D55B79A60FEDF5E79FB93BFCE0DFBC95D
+:1020C000D7A2AB09FECD04E631D3B942A6BF968BA9
+:1020D0007613185698BF910528BDD5EDDF83FDDC3A
+:1020E000040637E6FDC3AC39B1D6153DAFCF72B8A3
+:1020F0003FFC598EC9905AD3FCFB104EDF3A749ABC
+:10210000D73B978FE989EB92F32A12EF8E8C67AD5C
+:102110004FE0FCBEDDF6F561A55B18FED21FA77B84
+:10212000FD28C76E57C4BB76EDDE11A0F2923B15B9
+:10213000B2CFA6803F83FB43F2DD805355667A0F12
+:102140001EDF19C0FDB353559FDB919CA11EC3FD3B
+:102150008D1A3CA003E53577F3FBF425F82EC60075
+:102160007CB7C0C6FB5DA810DD0D4FCBE5F79FC166
+:10217000DE23FFC9DD4AF7F4804EBE273AB95CA5DD
+:102180007BE7EF98823D15DA4F9E6E51607EE56EDB
+:10219000AFE17703A2E9609EB82F20BF037D99BB12
+:1021A000C0385FBD34A437C5DF5FBEDC83F0AA3121
+:1021B000F1FB43813754F17B4E5C44ABC32FA53810
+:1021C00023D3BC5E8C17158BFB264D2A5B10EBBD11
+:1021D000F05E5D38BEDE49E7EFE7D544EDB374E964
+:1021E000C2E9AA4B174E6FC5AFEEA67784E6EDE2C3
+:1021F000EF1DB2BC96BEB1DEE7AF5CF0469FEE11BC
+:10220000EBA86CD8CFCF57B096BE91E7C975D1AFC8
+:10221000A423D5E2F0AFB347CE8FD30FD0754F8450
+:10222000C3B7C940D7DD88AE0FE3BEE278AB27E97C
+:1022300046057F25807D85EFFBF8FFECA4F341F296
+:102240009CD034E6A3B41CC800E9D8175845EFB9B0
+:10225000CE66F5F47DDED0A9F47BA495AC75543A36
+:10226000C0ED86658B5EC3E7F0AEAB5B351AE3ABC2
+:102270001383A5AF613A61837218FD54E08B215D31
+:10228000301EA2542DC12399376FCE5F825B66E367
+:10229000558E0FF626C707D08DAEBADAAF13F8E029
+:1022A0002A6CFF6DB24EEB50138B0C7C50B298E948
+:1022B0008A3B7CDEBD8D2F86CEF90CB7D498D64AEA
+:1022C000FBE6952F5B5D88E7D98CEBED703C43EA2C
+:1022D0006B46743E87C57BB1DE7141D7C7B319D158
+:1022E000F57185D13D756947B21C7FFA806E61BD7D
+:1022F0007BDC141C9CD88DF4F2249CEFCEF4EB3CD8
+:1023000018079BE3B6D1FBA7C793833951EF7CD065
+:102310007B44328EB5D2CCE34AD1F35286EEE4BF91
+:102320006B616101DC9FC0DF751E8CFC8CEFE628C1
+:10233000F40E740BF2BD79A4CF13ABFF5AD1EFAEFC
+:102340001FB9BF1B80F5E0FDC676E338C538F17CC8
+:102350001CA93FDA7E473A8D19C6FB4D975CC2CF68
+:102360003B0E9DE6BFC8944CF226C3E6BF0BE94E78
+:10237000C675A41FB82BF74877F2D77FA8C942FBD0
+:102380009CDE2140FBFB4A2E97DE317BE8DDDD77CA
+:10239000F273297E2FE5EDB54379FCEB5A19EF1A5C
+:1023A0001115EF8A8AB7B011B1E35F8C79CD386E21
+:1023B0001FF689840FC5595E1DA1197E3FEA55E1BC
+:1023C0007F9E2A72E7219DEFEFA2D23A1353F8BB0A
+:1023D00021AD0E95E86C7BC06BC7DFA3582EE2A43D
+:1023E0002BA2DEBD5E9E37DF89E702AC0EFE9EE5C6
+:1023F0000323E367469E477FAD073FB77463CFFC77
+:1024000077915EFADA8323493DEB9A07E7AF88F5C7
+:102410005CE204789BD0EEF48978A7FC5D9351A42C
+:102420009F259E2F543F3FAD0517C7E37ADD8CF8FB
+:10243000CEB1DA46F253ADD74378343AB5E7C4CDDE
+:10244000843FCDD71BC7691A1CCFEC50FFDB260B8E
+:10245000C5A15E3695FD19CFADB77E6C6578CEA16E
+:10246000DED1594323B7FEC75F8DA2D431BC90BFE4
+:102470003FC912F09DCCFE4EF697FF462489FB61C2
+:10248000F50ADBC51F6BD513F09DB77A133B7D159D
+:10249000CC6B8B7DC0839711A9F9545CE77BDDFD84
+:1024A000AFE03C06B32ACA3F60F1CD5C07E33EE0F3
+:1024B000B2117DCCEAEE7B95CF932D1907F3BBB219
+:1024C00040A1DFAD5B227E97CDE18D37BCB7EB3B02
+:1024D000D393F4C5DB423ED7A6EBCD78B1A343B886
+:1024E00039B556C33B592C8BE273128E91F8720E9C
+:1024F00036E0CB6F8EC4D750C0D7A591F8D2958B5C
+:10250000C1D7935D18CD57D26560A467D5A83CAEFE
+:10251000C76AA896338FCEB7B6A34FCFE67AC86FF7
+:10252000D72E217849FA94F41A834E6FDF8EF23851
+:10253000DBE4C4FDDD7BC7C5937E93742BE9D5D264
+:10254000959FAF02BAF57585748ADD371A654834F0
+:10255000DD62DC2B923E4B3AA463E68CE4D7F1605B
+:102560003F24B9D0DE39BAA13E823E4BAABED6B8CE
+:10257000FC387B55FCE0709CEE7F012DB720EB0012
+:10258000800000001F8B080000000000000BED7DA4
+:102590000D7854D5B5E83E33672633934972924C93
+:1025A00092811038934C424826302480FC552721D4
+:1025B000D0F0EBF05783243A58B4412193026DA335
+:1025C000D77B33908001EC2DA2F5A1F2EC808A68D4
+:1025D000B506A51ADB889320DC685107B52DB6DA5D
+:1025E00006DBCF9FB64A10AF175B5AEE5A6BEF93DC
+:1025F000CC994C10ED7D7DDFD7F7A27C3BFBEC7DC9
+:10260000F6CFDAEB7FAD7DB268A6C4DEB130FAB9A1
+:1026100000FFFCF0EF9D62F81D7F5CF85456DED59C
+:10262000DA8DE2F915434BE8C7DE2D1EEC675AB68A
+:10263000A9981918DBDAE264CCCC58BBE4F5E5C004
+:102640007872D3A90DF87C8B0C1D1D8C853CE6F0AF
+:1026500043388FEC2FF6A70C8E975554E550B318DE
+:102660004BB9EC4FC93740BF4FB30D2A93E03DF54E
+:10267000BA276C93E0BD93C90CDF4BCD8C363C0080
+:10268000EDFD6F8E65FB60984FD704C62876C6B601
+:10269000B5C03EDCB89A708E612A967D39062796C1
+:1026A000AA939701277FCE447B98EA7B5CF98C4DF7
+:1026B000C6BA4FF4EFA3FEDBCC3B2D369CC7655169
+:1026C000F64983EBBCC2C89A3A60BED92A6C0AD6D6
+:1026D000CBCEB7AA8B53B02E51FDCE96DDFEDFBB1D
+:1026E000713D612A33178459A08C315B71480D41CB
+:1026F0003FCB6616C0F7E3E179BF4BA675587AEE7B
+:10270000612AF4CB747BA500F4732C80F13438C3B8
+:10271000BF45008AB472E8B78FF9D824848F2D1C86
+:1027200092868EB728ABAA574E1DFEFC16C5E10156
+:102730001378A09DA7E56FC64087076B4E03CB6655
+:102740006C23F65519ABCE875F70DE66F3DE2498F6
+:10275000F75A359DF6FD89A32A8D79869FEF7E383D
+:102760009F501140BDC542E5BE168585004F1E0431
+:102770007CC1FAFE1695CA032DC5543EDAE2A5F6D1
+:10278000C75AA652FD472D3EAA77B4D450FDC916AC
+:102790003FD50FB5D452FDE99600959D2D0D54FE01
+:1027A000A4A589DABB5A9AA97E45129C1BEEA738CC
+:1027B000E45C02E7D17EB3D9A7027CEEC67304B80D
+:1027C0001FF1E5677AE1BCADC5069604DDACC777BD
+:1027D00031DC8FD569F085E11CB63A77B1AF43693A
+:1027E0009A92D22EA5C1FE1FB7B74B13A05DBE9320
+:1027F000A9F0FC7E29D4C0BC8CFD6B78865F9EC698
+:1028000098DBF9CDAA0CA8B7862B775A006F8BD42A
+:10281000C5B59B62EA6A4AF98D0795C1FA18CF5E81
+:10282000D906EDED6AF54E87C4D7C14632B62B3CCA
+:10283000C7BF09F02892CF4208F77E97398CF8B8C5
+:102840001ACF4BC6F52BB4FEF9ACD56980F58F5184
+:10285000CDE54837D03FC21C97DEFF6E55A5E7F1A6
+:10286000EF5DAC9F61D225F563C68B8C87EDD245B9
+:10287000C6B1484B2D5158FB0E93E01F5976E21F0D
+:10288000ED2676AD1FE0DE6EE5E5699744F3F5BA17
+:10289000AAAE724179958B9F6BBB35A454E1FC6560
+:1028A000062FF20BD6EC7A3D1FE6FBF64B32DBAE81
+:1028B0000EE2E7E3829E0BC7A4F8701EF62F967017
+:1028C00021CCF3D5318FB76540BDF001AFD708FDFE
+:1028D0007730AF0DF12474BB813D04F51F4E2AC83B
+:1028E000580CDD4B27FF382300F8922CD61166AC2C
+:1028F00006F16DD3961BC6F441F9E909CEA7BAC417
+:102900003C7B4DD1263ACFC97686FB666C6732F2A6
+:102910009D4D4E38A4CB18338CE0A5D9A45C8DFD19
+:10292000CC5BCC2C04EB31FFF5328B1FC66B3D9793
+:1029300054837C84B16832F231B335A0A4C3F39DD3
+:102940002103F18556D51E9660DC1DF6F25E15F961
+:10295000A762F016221C3D0682639BFD6B6123F289
+:10296000676953032B80F52A4F5A5CF03CEC312801
+:1029700048E761DF921AAC8702B2B750150C02DB50
+:102980000319E1ED382EEBFFD9046CAF635E84C30D
+:1029900096EC3FF72443BD75B9E235F2DEAA3C85DB
+:1029A000B111F81B4CD96AEADB9C8CEB58C1FBC314
+:1029B0006FDEC54087A949FCFCBED73D57C92F2310
+:1029C000B912EAE37C49BA0084289BBC162FB48F65
+:1029D000B797D7F8A09453CA2D2AECB34D29B7ACBA
+:1029E000A2FD333B83793219E74FAD8AA1262CDA59
+:1029F000BFEE2131F5827B0A9112B5B7D9777523E5
+:102A00003CE4EB1973A9B83E984FE37B000F4BC130
+:102A1000CC5E15F6D17E4306ED4396BC5467D7CB0A
+:102A2000B4EE91AA2DC2C6039F372FEC65C03F4676
+:102A30005A6E5A80F5110DF2EFFB62F8744E405F4A
+:102A4000CFAAD5D73319D42D31F30ABC89875B3C83
+:102A50003C46286D2770FD2302323D8C5FFF3DCA46
+:102A60005DE9950CD769A77566DBAFAB040801CAB1
+:102A7000F93721FEFDBDEB1CAF2CB1B860FEF10EA5
+:102A80000382934D60FD9B71DC1D02DFDB5DFC3C2E
+:102A900007E9CAA8D1A50FE9724CB3818562E48E1B
+:102AA0002B6463A198F90ADA3374F5C29D2375FD8E
+:102AB000C7EECED7B58F0B97E8DA4B0F94EBEA65EC
+:102AC0001DD375FD277456E9EA1323F374FD2B7AA1
+:102AD00097E8EA93A357EBFA5F76F23A5DFBB4BE50
+:102AE0001B75ED33DE5FAFAB7FA5FF165D7F20E387
+:102AF000868E047272BA8BF38536A72FEA4B20CFED
+:102B000007F42E45EE1F380FE09D494EC0EC98F9B2
+:102B100052BC3640A6C13A63A3947793459DE47AAC
+:102B2000ABBA19F139D54CF82CA33C87FAFA9BCDF6
+:102B3000E124C4C3CBBD2AF217AF8BEB336F17F977
+:102B4000BE8AE756996A21B920DB793FD93E87F4DE
+:102B500094D1BB812F55A0D6C806DA93913FB78494
+:102B6000FC6EF7E0BAADCA4E86F45B995AC3FAEC34
+:102B700083EFCB8A8F0552703E95E6B32821EA6732
+:102B800055E1FD987D1D3618981DF97837C809184C
+:102B9000BF23255746FAEBF86B4935952933E620D4
+:102BA000BE4F54D8034F40FF0E89F532D0933A0CF4
+:102BB000EC2CE86CEC497BF99D20AE8135FA8DC890
+:102BC000EFA6B0262A471B980DCBBD52DF0606FDA7
+:102BD0003C4D27AA72A0DF0977600DEEFBBBA04336
+:102BE000E0BEBE3B9EEB595BB2E7A9A897B5BB3AE6
+:102BF0007AF3713D592057901064BF17F50A6DBFE5
+:102C0000778AF394F3DBFB50FEAD4FB7A8A82FC92A
+:102C1000969DFEDF03BCEE37F53DD20AF5364959E5
+:102C2000DB817CF166BBF72186FA23879B9A62A839
+:102C3000D80CE3766CF2C9E9D0DEB18D79DB903E39
+:102C40001C959BD3E179E1A855860CA407F7A6CD86
+:102C5000586E413D16E61BE7D96BC884F6D24995FC
+:102C6000B50C65AF02F3650E8F4FC6D4DD0CF7C30C
+:102C7000DCF2BB8857A8755F80A55766C079C3BCD6
+:102C8000563C6F894A8283F59C3D6CC5BA9BC3C58F
+:102C9000EA93C2C95077B87D92CF83EFEDA6F3B522
+:102CA00046F47AEC1A77E04E84A76381FE5C65CB2C
+:102CB0005DB4BE1D064E17EDE9EA7194CFED2E7797
+:102CC00046AB3AB84E8DAFDC2FE4A7F65CE32B0A97
+:102CD000DA145983FA0DE0F96E4301EA673B19F201
+:102CE00027EBAD3B19E2B55509A90CF5F07F0B11A7
+:102CF0009E6BFAED064133D5F9B51694D7671DE5FD
+:102D0000A4CF5A9BF7D379C5C3CDDA6760BE8BC019
+:102D100035B5E85E92EFC080D542804F4FB6BD61B9
+:102D20006F02BD7FAAB01BB6011947495EF92DC8D5
+:102D3000AF4DC2CE004C30A07C3BAB30925FACC3F9
+:102D400045F50DE9BCAE8DB321AB3CE762FAB77532
+:102D5000B7850562F6B10DE641B86C39BFB806E13A
+:102D6000CA64220EB6E3AF9EBDDB1196C2AE992AAD
+:102D7000E03D1BE706B88E3633B20BBC8E053548F6
+:102D800077FE73F9247CFFE4CAA07EDE103336D1CF
+:102D9000BA4D9A5C325C98406B55CD9A1C26D596FC
+:102DA000CB2DF8BFFB82847C3F468EF182E4BA26AD
+:102DB000B70B77EADBC7EED6D7C78587BCFF06CA55
+:102DC000FDE5FC77900BFAF67B85FC5E8EF21B4AE4
+:102DD000B6CC4472CF022BBAC0E5EEA01C04BE9064
+:102DE000D711A944363A6A638C3C64B40F9D7C5C6D
+:102DF000E3E67CCCDF2B9BF01CFDE7C0F8A818CAEB
+:102E00009747277178F79853C29BE1BDDBC12E0A23
+:102E10001471FB3900A4F65DD9FBCB3AB4B37A8DBB
+:102E20005EC0D881738A3FD715F91C7F7A5DFEBFDB
+:102E3000BA487FE8AB40BB1AE70BC4CCD7634B1D45
+:102E4000CFC06E79B92860CC877E1FD73826217F06
+:102E5000481AC54C489F383F2B1AB4DFAF12F4B460
+:102E6000C3FB5AD31158C76D2793501D67B38DC745
+:102E70007B5BA0BE3E4F267EA65CB6F60768275752
+:102E8000FD1ADAE19DDB543587F4F45E13D9EB5576
+:102E9000028FAB84FD75B4D044E3E68A75E78812EF
+:102EA000DEB071FB3B62437DB6F400F062FD792633
+:102EB000F3761FE9BB651DF1ED3E86745C22F005DB
+:102EC000EAF64AA84F14F50E26652A708E136AFB9F
+:102ED0007AD094F0BC78D4867878D0CAF5B7470514
+:102EE0003E6433C91B81F5671FB07BC3D02FC5C8B3
+:102EF0000E46611FDE17E47762CF7D7C97BEEE61E0
+:102F0000317517AE435FBF5D6D92102EB7D7818EBE
+:102F10000E5BAEC84F71BC5BCA10E645885FB38DCF
+:102F2000F689684FADAFB433846BD2A9B1FF2B8A59
+:102F3000FCE38491A15C5092D53BAAE17DE56799C1
+:102F4000DE4DEAE0F93FDA82AC1BF8DE052F6B03B9
+:102F50009EFCDD2A5B03EABF8FC179A21CF911D860
+:102F6000D9D8DE01E78AF527C1CEC6F210D8D9F844
+:102F7000FC69B0B3B1DE097636963F013B1B9F7703
+:102F8000819D8DF5AB8A2ABF8AF8526FF7CF9610D4
+:102F9000AE3E595580AEA44138931F48627DD2059C
+:102FA00020903A85F525015CCF8DE17490841E2632
+:102FB000E0C32CE0B5205E7EFE383E6D9C8029D1BA
+:102FC0003853611CB2132C0AFA45F2E18D3478FEB5
+:102FD000E1CDBFDA8FF262A11458910FFDD74D7E7B
+:102FE000C7CCF5E77E33F6DF6305FC073E344AD0F5
+:102FF00041A80AE08972F725A3B7157A5D3EEBD4A4
+:10300000862CB0BF6FDA377931DAEF97DF74AA62B6
+:1030100034D40FEE0B2F964119BFFCE1534FE5025C
+:103020000FCE796015AFDF79EAEC28684F0BED58C9
+:103030005C3D0DFD525C3EED91586DAC7ED72CF0A1
+:103040003BD8BC8BE41CF077867068CDF6937C3C53
+:10305000EDE84F5D05FD8359FDD9D75D847F079B62
+:10306000EF2639D49AFA07D23F5A07E48597E485C8
+:1030700036AF262F3E16B8A7C98BF5565E1DE8174A
+:1030800028A0E7770ABF0E0B17523DD3CAEBFF5EAD
+:10309000A5BE8A760FC087ECDC23A925DF9B897645
+:1030A000658DEC4D82FA9DF6722BCA9B07F3B9DD54
+:1030B00002E386D08E0FCDB6841FC24375A8448F1D
+:1030C00019DAF80E372A5D2C43ACE385E9B608DA45
+:1030D000F9ADD5967DA84FEEB2E7D378AD53CD21AB
+:1030E000F4AF68F5CDD3A75B509F484FCD70615DBD
+:1030F000E34FDB01EFB1841F238E5B25B65B65B127
+:10310000478CC8CF2DA63FC5EAC9761625FCF11A13
+:10311000C020413E50C0F1AA82796BF1B9596A0AC8
+:103120002132EEC1B5E33E52849F92E5F2756BFB0E
+:10313000F0E5F27D69FB483187C43E484FDA6537D8
+:103140004450DFDB05FBC2F176E7AB049FF87D312D
+:1031500074BDC2B8B3A68A752B330FE13A661B7CE7
+:103160006DF8DED1CFEA1C805E6C0E6B92F17901B6
+:1031700058B4E89705946EBB7011BD23DE2F7BF920
+:10318000EF24DA0FBBC94CE7F24C215FCFBDE6B0AC
+:103190008B91811B1EB1246578FC7D6308FEFA18B3
+:1031A000D2536B868FE3AFD29FBA09F137BD3F7B15
+:1031B00033ED2B92F03CE2F138FE7C7E0BFF841C59
+:1031C00030227C3FEF3CB573D4F0205E7E4D28501A
+:1031D000B4F375D23E7DC59C0E343D8A819D9332F9
+:1031E000147E5B613CB568B06E76FA493F3639BCF7
+:1031F000C5E8BF6DFD9BB12191FF36AD80D3C1A65F
+:10320000541BE9CDADA95C6FEE4E9DA7B377AAC163
+:10321000FE91003F8C99AC03E9C8987635F9BF8CD4
+:1032200039A821E1BAE2F4D1B4055C1F55401F4D25
+:1032300030AF56CAA88F26D05307F4D18C795C1FC3
+:103240004D35933EBA27C55CBB3701BF792F9FEB45
+:103250007BDDB88F04F61ED879E487D4EC3CB3123A
+:10326000207B4DDBE77BF99CAEB4FE494A1343BF9C
+:1032700098D1EC5551DF34DAB8FE9804DB2C8E91EE
+:10328000DFDAFCEFE49B088E3D45FCFC0C16AE9F9C
+:103290005CFEAAD49408EE6A81A63F24C6BBBF0395
+:1032A0006F882F94DBCD3ED40FCAEDCE2AD40F8683
+:1032B0007B0F4CCDD0FB19837CC5FBB72946923FD1
+:1032C000B2D78978D661EA7BEA55B4E38EDA49DE73
+:1032D00074A48CAA8AD59FC15E0D15C32007FF0276
+:1032E0009468186AA782FD34BD00C6ED599F3D89D8
+:1032F0008F0B7A5ED950BD32DE1F3040EFA9FB5DE7
+:10330000FCBDF0087C4F5A3F3507F12A9EDEB532EE
+:10331000CFF952DE6A5857DE885E2AB5E7FF9B195F
+:10332000C9BF16DF7FF1C03970B93C0E264B33920E
+:103330003C5E8CEBFE70E36BD95E584AA37C86E45E
+:10334000F2C74D53D36E5339BF3D8072E69B32F1C5
+:10335000DB516BBAD33362CEF9DE96CE3CD98D7198
+:1033600083685EB59BEC015FA2F5FEABA03F16192A
+:1033700043FCD924F0407544E78E05B8AB7683173B
+:103380005DD2207C757CA0524EAF5660FEBC16E626
+:10339000B543DDC514F267E55D3012BEE51D594148
+:1033A000783CC6D12F853C31F3202B8E898B7CD283
+:1033B000544DF499973360C751FCE013476431D200
+:1033C000F72777F115E53DA06F07194BFEE61B3691
+:1033D000DAC2680A8EB95531603DEF07121BE5C2AB
+:1033E000751C71DD86FE9A6792C95F63DCED267FEE
+:1033F000CB0FA4C0F505B08E0FC3EAB7D1CEA51F81
+:10340000E8B7EE3BB67DDB498E45E7921CFB968123
+:103410003D94C09FD456C0FDE35B04BEE7395FC94D
+:103420005B5D81E5713AEF4BA5A783C8B7619CDB73
+:10343000D27652BC2B54C58AD1FE6B37015E25A0D3
+:10344000D73305226EA6F163013F2B5A2BB00FA391
+:1034500024F4BC038F3EFA6836CA6D864ADE00DD6E
+:1034600069E32417775063B2D7C7D0EF20293ECE47
+:103470006795903384F19DBF1A13E27544E3D3AE90
+:10348000AD4EEC5FEDF63A910EBA5D539CD701FC60
+:10349000EC76334B8AE1C31A9EBC903285F4106DF2
+:1034A0009CF529F917B5B7CDC08FD58BC86933FA0C
+:1034B000BD519FE999665161BD5BEDE551D4B7B649
+:1034C000DA1DE5E43FB703DF88F127D9EDC7080F20
+:1034D000ED5EEE67B323FF457F92D87FB7EB18ED23
+:1034E0005FEBB7A780D3BDDD1BE1F147B066B09FAE
+:1034F00055F687D0CEB03A18D995560BA7A76438A1
+:103500000E4B0C1FD1E6FD7E01B7D7B68E2A8F5623
+:10351000D2FA64F408B0ADCE7227C9438433EAA36B
+:103520002306F451F29BBC2EF881364E6B37DFA791
+:10353000BFD9E9ABCE443BD4FF22F285ADF6EB2CEC
+:1035400021940B29932E3ADEDBE2DC868ED73C4BAE
+:103550008CF73AD28331A55CC1F14CC82712E0DF69
+:103560001FC4BABEAC5F0C20AA90DDC6B87E051899
+:10357000EF4CA44768A545F8B786BEC7F9A44BD859
+:103580002FC0273FC5F5AF1BF5CEB14AEAC5ED9672
+:103590008CB972B10CE7F5319CA0511AB4E3E3F594
+:1035A000994A633FC9354D1E69F2E95ED467CC8301
+:1035B000F4A4F95F721BFC24B725879FF006F41B67
+:1035C00015E9C68871DF04709BEEE6709352A7AAD6
+:1035D000482FD5E7FB72F1BDC329EFE7B2183F9A38
+:1035E000C60F5FF86CBF15DB3F69A8BAA8DEA2C59D
+:1035F00085878B07A7DEF2876FC6EA2DC3C5873F95
+:103600002F2EDC936A26FFDBFD929E2F4D72733EB8
+:1036100038C1ADC50F0363DD59D8CFEF25BD51F8D3
+:1036200053DE2E0A94B8D1FFD56E662138CFC39FE2
+:103630004D71227E5C2A7C35FFF948A14F8DB4EF95
+:1036400097904E47368425F47FE7367448BE8BF456
+:10365000330ABF92D6DF24C6BF42EE37A2BCBA42BD
+:10366000D071EE399915C7E8817F2BE0FA9449E8CB
+:10367000EFA93D8F5871BC1E83BFBD08E543AA4129
+:103680007D2886DE4D6BCA2D5531F069C5B84E8256
+:10369000F3AB730FE85D641F69F2D6A4C90987AC68
+:1036A0009313C1648EB79ABE139CCEED21490A2CA8
+:1036B00047B89E9EFE8745C8B24E4B1D668C7F7FE5
+:1036C0005E5C6340AF31845769760CD28B57567E6F
+:1036D000DA07EF4F7CB892E861320B507919E37A40
+:1036E0001FE8515FC7F92A70C931E7CBD0F590FDCB
+:1036F000F9FBB812FDDE59E89F8B92FFF4BBE7257A
+:10370000E2E3F1F0D93F009F81F89DCE0F9A2BE4C0
+:103710005AAE6857D10FEAC27894DE4F59D1ABAF99
+:103720004F8EEAEB979D8CF37B867C3F7767F3782F
+:103730003F0EBA07E80AF9C16A11A71C150A572AF1
+:10374000B0DE3CD641F1C0DC860C1D5C2F378A3CD4
+:1037500009E69398B64EF8C995177E80EFDFE7D655
+:10376000F49F10E9593788F66F54AFFE761BDACE16
+:103770003B4DE40FB5C0E408AF6FCC5D321BCF7595
+:10378000883FB549EF47CD8D6D0738DCB0C7A46BD6
+:10379000F7FB26921DB054F86907F68BEBC8E2FBE5
+:1037A000CD2D1F3AFFE7CF0BFF3286CEAF8D7B2F9B
+:1037B000F01BE4A3EC3C9CEB14841B438F03CB93E2
+:1037C0002312C6A54736311FEAC3B91B992F917F33
+:1037D000FF6501AF7838B3D01504BF59E2D948BBB3
+:1037E00091ECF4911B0DA4078E047E807C60D15A6D
+:1037F0002017A8E7AE55498FBCB2C1C0500EB0F338
+:103800002DBAF761B9E4EFD4CEFD5E1C0FF5C87593
+:103810002C6CC0FD3495103DD1BAF207F101E0F5F2
+:103820000E879785E3F75493CEAF99877ECC18B86F
+:103830006878901BF7BCD1CDE32E1A5D803C7BD914
+:103840004D78C2E55C21CA3958D287D34EEEEF805D
+:10385000F55DBE99D17EFBD36D619EFF30102F3098
+:103860005E180BFCC932AB18FD2A3B149B01F31404
+:103870000EA7F7DDC7D219FB2DA8BFD533197BDE04
+:10388000D65F2A41FD8F0FFECBAE763894C3D6FEAD
+:103890001FA2B3D77EFBE6253531F5D47FBF9BEA67
+:1038A0006C2A5365808F0D67807DDA9479078C30A0
+:1038B000BFCD632727A48D0DD029EDA76DBA7A3B24
+:1038C000E679B4151A484F62B1EDB08FDA4245D0AF
+:1038D000B78FF2D8580D8FDBC78E2F3B2E32FE3CB0
+:1038E000187FD21718DFC2D79F8D8F40BE64E3FACE
+:1038F000D14F8DE3E3F9A2B328767E319ECC427B93
+:1039000031BE02F3D9253E9F827924D94C9F3730AE
+:10391000309F02F395FD03F6533BF43C4C173B8F6D
+:10392000ABBFD879B4197CB4DED0783BD93F0C9AC0
+:103930000D53D0CEE0F35965F6825CCEE1DA366500
+:1039400010AEA0EFD1B8D07DD305016713C25931B5
+:10395000139C87835B8FC2F398B629B6F026D7FFF6
+:1039600085F372F2F38A9D0FF5C64B9EEF6A98CFEE
+:1039700071E9F3217C917E06E00B67B239FBD2E15D
+:103980000BAB0A5D0A7C7B605C430C5C07F385EE45
+:103990005150FFB79AFC162FF0DFEB0B791EA2C730
+:1039A000B1C442F903594B2C9897B7C563AFC1FC1A
+:1039B000BD2DEE6516538C9CDEE2A9A376E84F7907
+:1039C0004E9E880DDD13AC8C45C9FEDF36B3DAB9E7
+:1039D0000AF1A789E74D6979449A3C64223E49FB84
+:1039E0008217D3BE72A8BF07FA6F6B9A44796269D7
+:1039F000E97FA6FCA81D0D5E2FB6DF67E571C6BB8B
+:103A0000459C091195FC68E3A73F80F1D6F2C2F509
+:103A100012C517D75E3CBE587E265A8579566C155E
+:103A2000CFA372D6C971F2504FB73B10AE3CDF291D
+:103A30002C71F8EAC6BBAF308BC79FDDFB18DA7775
+:103A40004FC158463D7D1930EF289E1E65B34FA9E2
+:103A500044BD7CBD81D6918BA17C1071E5650B9C2A
+:103A6000ABE0F9A8EB65AF04CF733CB752FE116829
+:103A7000F5A46F783CC7ABB03E649FABF5FB88DF25
+:103A800057FCBA417091BCD1CEABFC8C3719EDA874
+:103A9000F2C225941F463F1ABD1BE3F69389F6AF89
+:103AA000C16705396673C7EC8BE9FA093BED7FB650
+:103AB000BE0D9109E5627CFCEBDFFCB4CE24E6B5DB
+:103AC00098E9BD3AB217B5B8DA48A41D3CF7D18CD5
+:103AD000C725E2DF9FC2DF674E1E674BB281E9094F
+:103AE000F427DD6823FF655212D4E17C2433B38CC4
+:103AF00080E7F70ABFDF2689C9581F9C2FC270BE16
+:103B000056C9BFD3EBC292DB4BA6743FE517629850
+:103B100036D6EEECC1BC0D685FBFC695837EBB3464
+:103B2000208828DACD222EA5F949520BFA56A2FC9C
+:103B30007EFDA1BF2CB1A07C46C7D274D0BE0B3F86
+:103B4000DD159A39489749E7463235C67E49929B3A
+:103B5000287F23E9DC689D3F2522EC2EADEE73C85B
+:103B6000D538DF7FA15D00F85CC994367CAF128048
+:103B7000A2C6FA47CF3975E30C8E3F4A376F04EC83
+:103B8000E7D838C0F0E32733B53876FCFC61C62FA0
+:103B90008A1B5F4938FEE0B899BA71B7C89C5F8448
+:103BA0001CB670227F5E5651D57924E5E1F2CB1C1C
+:103BB00045DCCE057E2C53DC49E0CD6DCE26CA37E0
+:103BC00033DA787CD424E22547521A785EC4287D03
+:103BD000BE591553646CDF923AA75782F62ABB5E32
+:103BE0004FBFE2FC3B46E43B57C87A3DDDC79A082D
+:103BF0003F2F67FAE7A6517A3E7010E903FDFE29D0
+:103C000093A294979665A73C83E1FC076FB530CAF1
+:103C1000973225FB9B50C695ED4FCBDCE2847A1A98
+:103C2000C7AF19FBDD4BD11FF496C0E32D40F70859
+:103C3000C7BAF5397B8D31E3D69923852847EA0C3D
+:103C40003C3F9F7E60FEB7B246923F357E5ECAF033
+:103C50008DF147D537497E77CC3EDE12743130DFA7
+:103C600086DCBDA8C70ECC9714994CF30DE4F988F7
+:103C7000F9B2BFDC7C6F0B7AD6E6ABFFB67E7FF580
+:103C8000E628EDAFDEC0445E3F9FEF6DDC9FEB4B5F
+:103C9000CC27F2B506E6FB8E7E7FF54951DA5FFD53
+:103CA000803D29E6CBFE72F325999B281E7387C4BD
+:103CB000CF754351D99DE88F3FBB60BD8AF8A6D927
+:103CC000678BF005C0B345229FE9CA5166D21BB489
+:103CD000710FB44C653E33F7DB60593C53A2FCFED8
+:103CE0007153251FC6C3F600DDFB8AD02FA5507B7C
+:103CF000B8C549E5BE1695CA07C11EF4917FCACB67
+:103D0000EB45DCCEBF6384B26235EA0B95369EDFAD
+:103D10003C730668A283F61618603D56CC23FC1A45
+:103D20009BB81D6A45BB393C1CD5D9613C27DBC417
+:103D300017A22D504F9A6654316F3BC9C5FC89FCC0
+:103D40002E3F28E2FED8DBB47CF8AF483CDE0EFA0A
+:103D50004825ECFF5A016A665C20A15E75E577D2C2
+:103D6000491FA95BD697A2C03AAE9126FEDC0DF0A2
+:103D7000F8ADD047AE1DCDE938DE9E74A0649984BD
+:103D8000F97AC670187E5D9AB294ECD1A5CB19CBA6
+:103D900080F7AFC4F740AEBC2AF49957FA9218DA0C
+:103DA0006BA16A1E67BEE656BD1D798735A2A01EAF
+:103DB00077C74407C3F3A8DBA86FBF4DC40B96C6F3
+:103DC000D99557C6E5D180964978823C814D83F3D9
+:103DD0002A4A71507EABC8A3B9BA48E57C6E948379
+:103DE00092A833E6BAD330FE98644E7CEF461BEFC0
+:103DF000A8E03BCCE12338687967CCF8D8447A5FF7
+:103E0000CCA7BD77AFF4D8888BF935416F7BB7AFBE
+:103E100098CB67D4AF0FC6ADF3EC82FCEF55B3443B
+:103E200078DB2FA35F415BFFFF297CBD097D1AB0C2
+:103E3000EF57677D3289E22D6C14ED7B91863F222E
+:103E40009F6AE9405D66724C3E1D73F67BF0BCDFF5
+:103E5000F84AB2773BE19FD01F226F1A2E247FF1E0
+:103E6000F106D6E1F4E5717F5CB542F94062BCE150
+:103E7000E01C9FEFA0F96DE82726DFB0752FCF7704
+:103E80001CE9A8FA00EF45E1F3777478A5BFFFD4E9
+:103E9000DAFD8884F6C57D789F4B1E9C0FFDB4210A
+:103EA000D25FF5F7B2E2D7A5DDB7D1D6D36A66C542
+:103EB000648F1A803FC07C0BED7DB2A4A2DFBD5F92
+:103EC00046FC2A19CBFD449813CCEFB9703DCF982E
+:103ED0006BE0F91B6354AEF7B9FB47C7C685D2C682
+:103EE000F278DAC2E4D736AA20FF4C0F6F5E8AF967
+:103EF0004B0BD35EDBE882BAE5E1565ECF7DED1376
+:103F000017E86CB687DB78BDF4B54FF2A16E7F7809
+:103F1000CB52CC675A38831150521FDE4AF2326DB1
+:103F2000AC664F4747E17C0B254E1F5FB634261920
+:103F300012C6EF9D63353F2933E13CFEAEFF388961
+:103F4000FCC8AFF95F7DFA7823C3A66CBC27247E3A
+:103F50001CA9A4CFCCC3DF019EF3E54837BE6FB0E8
+:103F60004408AE63316FA69850E0AE0B17C98F8836
+:103F7000C72309D0B519F565556175A01FB736B3CC
+:103F800080B52006CF994FE039CFE3D1D6A3CD3FFE
+:103F9000645D70A47246ECBAF6D038DABA4E4F4C73
+:103FA0000AE17D322D7EAAADEBB4D47F3F3A23BE29
+:103FB000F9C3CEE5786EA753FA474B503FF1F0FBBB
+:103FC000748EA7B3FAEF97BC3175133FC7CB1FFEB2
+:103FD000C152948F1B25DFE563317FCE6CA77B6BCD
+:103FE000ED42CFDB91150831AEDF53BE63288FDF82
+:103FF00007A89E24F962E3FB3502BFFE632CD71F9E
+:104000006727ED6C3A01F8183C24B14DD03F78FE9B
+:10401000AC19EDF1855DA7CC6877371E3A6546BBD4
+:10402000BA11EB304EE31E33F1AB78781F1F6BD41F
+:10403000C5D1357BE2685ED11607ACA771B5E4C582
+:1040400014D9F5CFA6CFC6FAFA55B84BE0EF330F27
+:10405000CE4674A9F7776FC1F25AD67714E3052BD1
+:10406000027A3D7F65835E2FAF6FD2EBD3D7EE84AC
+:10407000D301F9756D73AEEE3D861A32AC678538A3
+:10408000CF15CEDBA3C6F1588FB987231159937F83
+:104090006725DF01947ABFC5C22E89E8B8B1D64240
+:1040A000FED7A3793C7F3EB8D6487941414407AC5E
+:1040B0003749C29FE523FEA8C9EFD99D678EE5E287
+:1040C000FB6B4D040716F245D1AF5F2BF0E9DADA4E
+:1040D0009A0F10CF6AD51BB91C1FB3DF44FE9500A1
+:1040E000D7C755E1FFAEEBBCA33A03F5CF8D12F96C
+:1040F000375636E8F5F57AFC05F5B766291C7121C7
+:104100009CF4EDD736EBEBDBC70A3956CA4A914E21
+:10411000BE375692896E44FD4F79BF78250213DD74
+:1041200022F97721DEAD3547C6A35CBB450A505D59
+:104130006B87E78D5CEE70796F008A22BE6BE27E42
+:1041400085D03A89F071E510F91FA31F1887D68F23
+:104150000A7ED26AF56F247BE93949417DA45AF67B
+:10416000C9199E417B361E1F8F093C7F85F57970EA
+:104170005D450874807FD1D2B430FAC38A9E5F4512
+:10418000F98D451592D740F46C60CDE558CAC41F2F
+:1041900050DFB4425964ECA8257E3DC1ACF0FC412F
+:1041A000278BE503BE479884797CB8749C77FEA87A
+:1041B000DECFF01C17EDBEFD0CF23B7781AFFC0E9D
+:1041C00058DF0E2B9F7FC7B312E9AF8D9E63C417D4
+:1041D00073004D70DE46A7E08F9DC01FB5FDC3790B
+:1041E000E720BFC20B210B3C34EF082D3EA0E5D7E2
+:1041F00046AA0C1780EFE488798F97A9B4EFEC1BDF
+:104200003B24DC771E0B6D423FD18FC7327AAE95CF
+:104210009A1F7FF960BCBA06CF739DB3CF4CFAB733
+:10422000885727E8B764ECE404FD7C4CE747986DB9
+:104230003C9F8A71E5F5CF155C34AFC26831E8E880
+:10424000D5A4D874743DBF584FE70BBD7AFABE723F
+:104250006A81AE7DB1AF54D7BEB4A642575FEE9F20
+:10426000A1EB7F55ED2CBDBDEF9CA7EB6F5597E8FB
+:10427000EAC9C557EBFAA778AFD3F31B4707E50F99
+:10428000982DA1BE808AF7E6199B9A31C8AF4B538F
+:10429000A13394B60AAB1DCBF68949113CB7F69110
+:1042A0003C9E9AF4E2B79C11847ADA63964A287F9E
+:1042B0002885AB305E6411765EC9AD4CC7CF1795CB
+:1042C000723CD74A5371401907E7E339A0E6F27C04
+:1042D000E968099E8F051D8888C74F5B48EF9810D5
+:1042E000A7FFBE5256692B467FEBADBEB9E497EAF5
+:1042F000640ADE97DD67E6F94CA1A779FEACA7B3A7
+:10430000CFE08BA1B7BB8B397D7EDF5F45F9498D4F
+:104310005D20CD10BF77BF6346BF5D6357772ACA64
+:104320008DF1FE77CCA85F0F3E17F244EEB761FC2B
+:10433000F2898EC47968738ACD34FE31C16FEBBFC8
+:10434000C5F92D20DC02B48F34FE597F90EFAF7E8B
+:10435000B999E85BE3A3C03F75F1B078BEBC726663
+:10436000780BD22EF0519DFD72EDB2391FA03DC4E5
+:104370005884F418E0A3FAF6515B89BEAF8DB36F91
+:1043800026150FF053CF05A097937E43C27D2D2DA8
+:1043900095695F2703B308DEDF07B8A1DDF8FD21CB
+:1043A00070E2F0FB3CF83C2EFC89DA39C5F7AB2D06
+:1043B000E5FAE8E3C3F0CB3DE21CF749D17264664D
+:1043C00041BF8DF074A5C5B21CF30C8EE57DBA1506
+:1043D000E309F53F96D09665BFEE7E311BF30ECC18
+:1043E000078F66633E44B0E368360338AD35A99B5A
+:1043F000502F063CF06E827369EC8CD0FAD775545E
+:1044000074E3F3759D92175961F0D09939B44FD682
+:10441000B715F5F87DC3ACEBBA62AEA7AC2B56A9C5
+:104420000C06604E94B38792C88EAD3F087C08D7C7
+:10443000F5AC44F730F66DB3D426D24FEA4BF9F71A
+:10444000185ED866661847590BEFE33E8EE51D33BC
+:104450005B106F0E4A6413063B4E2C477F7C70A3A3
+:104460008961DC565BDF8779D1DFE0FEDF5C6D625E
+:10447000786FB075358FC7BEB9D148E318AF3751E3
+:104480007DC51A9E277C64F5EFB6E6C2B86FAE957F
+:1044900028BF7ED6F5FF790CEB2BD6703D281E7F0A
+:1044A00007F0350E3F5704F47837044F1BBE1C9EAF
+:1044B0006E1BC4D3F12867E1DC67E720FEDCCCE8A3
+:1044C000DE62EDF923A61C586FFE56C58BA1DD32C6
+:1044D00063784B36F28523BC7DE2DABD12E72F2AE2
+:1044E000DD67CF6D3733CA532CE67C680F9E5716B5
+:1044F0006EAD5FC2BC362647F3717D2E91C7F5A421
+:1045000089D51E443F92CCF94BD933CEBDB17EA4A0
+:10451000F9021F35BE570AF6FE41F243778CC47B81
+:10452000E68F9BB87F6CB418AFB0A07FCE6228BB7B
+:1045300004BEEC17EBD0EADF10F8CF3AF6911C5D21
+:1045400068E1709FD71CA9C37DDC20071E43FEB71E
+:1045500060F42FD6A25C6BCF7FC913203F5709C9E7
+:10456000B5A0388F23D3DEDBB301F3EDC6D9E81C49
+:1045700017F7DC13C5736D74CB9467682D9C941387
+:10458000B8881F21784ED5DDDB6BEC3A33C79780B6
+:10459000AEAF13EB2D13F7F35817F71F003F96A795
+:1045A000960FF6D3F6AFF93DAC850FD2396DF826EC
+:1045B0009BC8EFEDDF417058B9F68484F752AE32F4
+:1045C000F94C7680F32FD2D872B4835F6A61744F4E
+:1045D000ED38DE570356F24A8B42F5A8B8B7F65AC3
+:1045E0008B4AE55566FFAB089FE52F341522BC8E3C
+:1045F000E4DDEDC7EF309C3E2EF459A6F07B8C0233
+:10460000F7CE76199905DACF1E92C2E43411EBBFCA
+:10461000E6DC4816007EF22B713F6E5DF3EBC4E7DB
+:10462000BC0D67E6A09D3171EDA9AD580F36FFE7CF
+:104630001CD41B7E037202F12BD82931278C5377AF
+:104640002E83DE5FD779C28CF6FCE386FE3908FF45
+:10465000D06189EE55059BCE10FFDC23FC2B69E36E
+:10466000781C31D835D140E7E92BE1F68938FFEEE7
+:10467000923FA722FFB234ABAFCEC073EC35D23934
+:104680006EAFEA4F55129CCB491817F3477E25F2BF
+:10469000F186F0597388FCB2B5026FE3DB93C7195A
+:1046A000343BDC24F2949804EBA913F8558FDF8394
+:1046B000C9403D5F8AD8806EEBBB66917FA3BEE99F
+:1046C000E2DF77190EDF2EB56C64DCBFA1D5D1FE19
+:1046D0008ACDD742FB4B7F0F3DC4EF71E5B9730222
+:1046E00017D1EF827D23297ED2D8CE285EB2EE5C30
+:1046F00009951F3D7B1BDD7BB2D8FAEF46B9C08A16
+:104700000CA4D7AF0BE9F59B4F4B381D7C5AC2E97F
+:10471000B8601CD8271636609F801D5284FA0ED8C8
+:1047200021A93D4C679FC43F27FBC422FC86A02ED5
+:10473000059E4CB0EEBF9454958ECB42BADA49F840
+:10474000CD00BF11AFE2F739651C5F9746CF2B7ADA
+:104750003E30A3BE1BEC4C4CCFE6D2CA2938EEB695
+:1047600061F2EFCE8B7DAEDBCD085EC1DD1904A713
+:104770000FD96E7F15E0E587B00EBC977EDAEF4F5C
+:104780004E87F74F07FCC9189FD3E8BF71B78DDE7E
+:10479000DBE65E9289DFD1982FF0FEA3CE59168416
+:1047A000F335BB39DD69F3FD26B22213E967B2A9FF
+:1047B000DF8CFEC9515DA75251AF9BFCECD24CA4DB
+:1047C000BFE1D639A384F3E575CD2397D3BD1FF898
+:1047D0003102DDDF24E4587073C48CF0BFA9991155
+:1047E000FE763FFDEB46A4DF8FBA921594931F3EF1
+:1047F000971C427E7FFA7052D80043AD15DF3FFA16
+:10480000D0D4B788F4C7678D94AF103CFCC7BB9178
+:104810001E834F27D13D9A9BBA6E3B83726E6DD734
+:10482000DC0F642C1FFBC7D2C3BAE6D1CB63F38B7A
+:10483000FFD8726024F2CF8F64CE276EEA7C8AF4B0
+:10484000D99BCE9F1D8FF9831F3EF79729C8CF8232
+:10485000CF9F9D827C2CF8D3B353B03DF84C72535C
+:1048600022FD646D29F79F68F2D1F586ACF3B3643D
+:104870000B79E06ADB5983DF29987C6219C501B4A2
+:10488000F6C985063FF69FFCF3EACCEB63DE6B8B43
+:10489000CA942F31E94475F2EA18BC4C2E35697E72
+:1048A000BA4BF38F883C04CD3FB22D2AF37B750DB4
+:1048B000C630E6F1AE8CF2F87BBCDF8431FFFC320F
+:1048C0003CEF35595EFC3E0FDE4BC7B8C8E99B0B89
+:1048D000C3742F3D6439EA8ED18356440D9124F47C
+:1048E00083742545501F5A11954F25C5F8457EA361
+:1048F0003CB905D5F81501BD1F23DE0F023F297213
+:104900004CFCA47E63C4A4C9A98530FF2FB6300532
+:10491000E33643FC23B55F253F4CBC9F448DDE65E9
+:10492000C1F75437FF9E8EA667E2791D4A40EF1506
+:10493000829E353A6A8B1AE81CDAA2551637941E05
+:10494000414787406C86302FA86BE94368A7B79D25
+:10495000BF2A19E1D5F6C61286DF8B38AD54590A45
+:10496000F1BDF35FB52CF70CE2C710FE318EF3C733
+:10497000017D601839F7A1E05BFF2879F7C13F8915
+:10498000BC03BBBA1FF937D8D52BB9DF83DBD5F110
+:104990007242E3BFDAB8AA38E7A1FCF703D25FC0DE
+:1049A000FE25FEAB96A8D46F54D7E24CB28BDF58ED
+:1049B00096A9DA878E5F207B0D199EA1E36BFA5AC8
+:1049C00030E43B6A413BC6C7F34F83CB24FA6E54B5
+:1049D000D02F919E1DAC3385B15D5B4F74198F0B49
+:1049E0002EF74AF41D104DFFD3F4C381F649D0EEE3
+:1049F0001AD41735BD30EAE77ED1653E13B55F6541
+:104A00000EE4944CC6FD59E9F9E4697C5CE0034787
+:104A1000D1FF79D5D724FA4E97A62F6AF819AF4F50
+:104A20007EDC5570D1EFCFED1178A9D1D7E838BA37
+:104A3000D0E4D47C81EF8D28A733514E7F66EEB34E
+:104A40000FAF77839C2E2DA1F718BD3FE9E7B23F4A
+:104A500091DD7D588C3B433BB7E80B95B8DE3C16A7
+:104A6000A5BCA8E1E467AEF0D30CD73EFF12E9F88D
+:104A700086927F2C1D5F57F2CF41C703FA9F39F111
+:104A80003EFF52527913E2AFCDD844F7A3D8CF4CB2
+:104A9000E4B78EEFA76AF6A4CC74787C34CF6C4070
+:104AA000BB27D8C0EDFEF674F555B24F5EE4F7EEC5
+:104AB0006F12F94A379E53A86CC70F8361FBB75C2E
+:104AC000E4B7B9F1C009930FDE5FB9519A88FEA02F
+:104AD000950DFAFDB467F9E6C6FAC1DB4774505C80
+:104AE00021F450818AE3D7E366D11FD23E328CB1E4
+:104AF000C746F4E34CC0E731F72D609E75E2F90C30
+:104B0000E1DF61717AC04FBBDF247F0FC685907EE5
+:104B1000CD5D12E585047BB9BFA3B18BF385F71B8F
+:104B200024E227EF8BFC8C60B395FCDB9A1EF181AD
+:104B3000E8B7E66689F4BD217A854F1F7759F7E01B
+:104B4000CF892FC6EB111987F838186F41BFCCD128
+:104B5000BC2912D6D7815D88DF250DAAEA95B97CDC
+:104B60007D2C4CFCC5A7F3A37CDCFB3BB223573E5A
+:104B70002BB14CD23BE2E22FEDF3E2E22FC78EE6FF
+:104B8000E23842CF50E03FF41FC6EB198D9D274C11
+:104B900068177C5E9CE59912BD5F708CCCFDAC63A0
+:104BA000BA2405FD4963049C2EDB662338CD797B4E
+:104BB0007526D2B9763E1F2DE6E7F5D19B9F54E2CC
+:104BC0007B53DE9615E4B73F7D73E3EBB9BCAE5A79
+:104BD000547C6F6332DA211FBDBD3E19E1F85328C2
+:104BE000F1FB48CF9C9413FA0F0B4B39BF01F976B8
+:104BF000BC84FCBFC26F2C837C4B19F4BFC4BF378D
+:104C00004BBCD78EDF2D42FC7B96C7B7DB4704E653
+:104C100051FD9E7C9E472C737C7DAA2B5D417DAF10
+:104C200014368B71D81FD9581BC657DAB3022F110F
+:104C30007DDC6320FC85F7F977270EAA24EFF08A44
+:104C40001DC63FC683ACB1505EA383FC37DA7761E3
+:104C500046801D2ABEA3B00CE3AEA5220E32DEC6EE
+:104C6000641C7F8729B07D1CC65DBA65EF267C4732
+:104C7000F666E27790E2E3315A7C588BCB6871E2BA
+:104C8000E1E23212CE339EE359EC774EB4F80BFBDF
+:104C90001ACFDF6C9DDA44F75F7B31469238EE32F3
+:104CA0007A5C82784AE938ADBF3E9EB6BDF849C20B
+:104CB000B72F1A47BBA164B8F9556E77C6CD3F2907
+:104CC000FDE36CB25FFEFA5FA924CFBACE92DC3965
+:104CD000DD9F24EE71F6713F759789ECF5D360077F
+:104CE00065C5C8B3F6717CDC9EAE59848F87A2D5AA
+:104CF000C9D8FF09F17CDB1BCB96A23E1D8ACA3CBA
+:104D00001F9B71BBE650549ECCF5832170BAAC2436
+:104D1000417CCA624B9C07F49EF017BC27F63DEB22
+:104D20004D6EAF0437F2F88122E82D5863267E726B
+:104D30002C2F5BD2FCC83989E20BCFF6139FAD5FF5
+:104D4000C3E3BB971C5FE8EC36B1FC047EDB9A3909
+:104D5000C46F2ED55FCBD00A9E32C89F2B4BC5F7B0
+:104D600086CAB8FFF6C5127E5F27A36962257EEF6B
+:104D7000EEBD61CF3B70B0F4D2E27CCF7B2EAD9F15
+:104D8000A138513C7068BFA997D86FCE25F6BBA15A
+:104D9000F8D2D6D77589E3EDBFC4F16E1997A8DFB5
+:104DA000FFA3F1CFF8F8667C3C343ECE99F4E2F5EF
+:104DB000216CBB4DBABD3F82D04D7DBA5602529593
+:104DC000D31FB4205F5B308DC703B6555BC27BA594
+:104DD000C1B8A806AF87CBB8DEA578CE84F0BB8873
+:104DE000A37DD1EA4CA0E3D3D318D90DA7ADE27BC4
+:104DF00048B23262319D9F42DFC369B7268E2FAD24
+:104E000014E30DC7475E29AB7CBC7432DD1F4AF842
+:104E10009D8AEA526E67289D8CFC354C56472CA122
+:104E200079D5112867D25EE0CF53238CF2FBA0DD49
+:104E3000B584F467D585EBDB25E25E19F38A5CE87F
+:104E4000A7CB00798B71913B303E427E7D85FA691C
+:104E5000F34DF2F0F97699988471ACD0389E57C131
+:104E6000D42788EF68718DE3A6C8EF574914D7E8B7
+:104E7000C5F5BF6C8878F6B9F8B9207C3D87148AEF
+:104E8000B7BC32EDE162BA172FE21C1B14DEE50855
+:104E9000DA19B08E0DCF5510FEAEEC99F6CB3AD4A0
+:104EA00007DD32C179881E2EECAB93C23ED4ECAB49
+:104EB0003EB41363EC8DB784DE9080AEDE2A4D40A5
+:104EC000A7BB246EFF865EE6F66F85D95B109B4F0D
+:104ED000F5BE80FFAA08F7C36A76ED785FD8900D1B
+:104EE00070A8B8D9184902395DB1B5CC8CFCBA624A
+:104EF0006B9E8DFC4AAB0F1A3478273AF78FC53A70
+:104F0000B7F5F6535CE2A9F87BE61E33B5EF15F86A
+:104F10003309CF16CA0D85722B8ADFB4998A319175
+:104F20005FBC1EF47E5CDFAA76BE5E2D0E521F5162
+:104F300067E13CA78EF66FC5B2BCC1358BFC866BB2
+:104F4000CF6C45B9193C7FF6D815E40730AB89EE34
+:104F50000B3C5B6624383C858A08C26BAE4C79BB3F
+:104F60001573653AEF8C7A2BD9E1192666C4EFAE3A
+:104F7000662CE672ACBCC6310BEB6C593AC9E1F257
+:104F80005E35FD7ACFA09D9F31776316C2E9F3E2CB
+:104F9000439ABFE02AB32FD333F98BC787D61D7F3F
+:104FA00083F2CCAEE9D3C787B478CF70F1212D3E20
+:104FB0001BACF944174F0ECAFD73D0AF52F1DC2978
+:104FC0008A0F073B25C5E91A8C1B050F9D31137C01
+:104FD00045BC08FA9BF1BD0A38F61119F8BD011E4F
+:104FE0003F7A1AF371CDF83D3D85F26E7F82F9B8B4
+:104FF00045F83D3D9E8F7B18F371CD78FF83E7E345
+:10500000F688FCDE60D7198A374DF30CC9A7A27861
+:10501000C42D927FA6479F4F45F5F87885D1C6ED00
+:10502000D060AF89BE771E3C6E213E5BD9B56A0C5D
+:10503000EA63DA77C81B315E10E35FFAC8E7B5E2CE
+:10504000FD9E8FFC5E2BC6092ABA3F30ABC4772287
+:10505000B998C2D42847CD68EF231C28CFAFABD274
+:105060008A70FD5CBF7EE7FFF7EB7F11BFFEE13288
+:10507000EED7D7F847B9DF40F7CACB7B7DD6EB63D5
+:10508000F8C3363FF70F6F73E713FDDDE5CF4F5FD2
+:105090001DEBC7AFE1F65BC65CB735F6B9713CFFF7
+:1050A0001E448694F87EC1768F61383D707B62FD28
+:1050B0002E713C605B0DE7239ABF7F687CC0FBA22A
+:1050C0003BC6CFFFD1CB16FA7B0ADDCF26913CFF42
+:1050D000F4B9A47DA87797D7AC1E9302F5F2934953
+:1050E000CCC5E5912EAEB0B2C6E0B3A6268A23F8B1
+:1050F00072E97BA1F1F1821A03F1F78178418D7C8D
+:105100008AEA423FBFE6CC7B29F8E9EBA7A4703BD3
+:10511000DA174FAD93BCDD6C68FC0006CE655361B9
+:105120001735DC4EF0D65AC82EF8BCB842DDA113B4
+:105130005BD04F3091ED6CC7EF4F4E741B14104590
+:1051400009E20A3CBFB35CE811F1FE01C40F94FB15
+:10515000F17EC1E7C5F93D2FE4FE5CD4F9B306C783
+:10516000D1DE8B3F77479974513FA32CE4565B4DBA
+:10517000F9363CB7D0020343FEDF56536571C78C46
+:10518000F79A87E7CDECC2388523364EC1E311F19B
+:10519000F1098D3F55747F3607CFFDAE2EEE3F0AE5
+:1051A0003AB93FB3E27025DD33195C27DFDF5DCE0E
+:1051B000817B86E98CEF8B59B89F8BFC0AE50B3E0F
+:1051C000E9C1BF37C0FCE9F4F70B82C7DDAD76E477
+:1051D000230BE4C9924AFEED017F37FAA396BEDAAB
+:1051E000300FF3812B964F3C81E7B2BCCE44794718
+:1051F0004B5FADA5EF8A6BF2AA62F9DECDF8F768D6
+:1052000096174B5EAB8AED3555D83EFFB1087AF65E
+:10521000D8425C1DD04BF438F4CE27FFF6C7483790
+:10522000158B85DFBB8ECBD5E55D8B4DFCE3567AC8
+:10523000397724EF53B29BCF7655903F3B13E3ADC4
+:105240009E413953F11CC89F9441F9F3F7CA1D4799
+:1052500019CFF39F00F207D793B198C705E3CFFFAB
+:10526000350F3FFFE1E4C970FC13E507FF7B3BA16D
+:105270005CC939287755B4A72F1B94BF4A27D4732C
+:1052800086C7BF7902AFD387D1BF660BFC1C365FE0
+:10529000A3F31FE3F7AE2CFB27F17B0BFB46F37F59
+:1052A0006BF6D07D02CE5AB947F08DBF3B5F1985B2
+:1052B00062C27CE58CC4F9CAD77448F41D1691AF5C
+:1052C0007CD4CC2A0F3A304F4FDC4B08FB49BF3916
+:1052D0007AEFAFB63EE2C07B09928262675DC70992
+:1052E00092CFEB409F213DA8EB8FDC2FD5C1F34B34
+:1052F000D775EAEF3F68E5112197AB613FE44716A8
+:10530000797C730E71BA0EFACC61D5857EA16FCB14
+:10531000B17EA1A01ACDD2F203C35C2E25CCE36BE3
+:1053200064FD94EFD7D82079511E7C693F918FE7B7
+:10533000F75DAA9FA8AD4CF885849FF99152CE0FD6
+:105340006A039284FAA8C5E05F4BF9BD8725255111
+:105350009EE8BD02DFE70B3FED7E33C783FDD3251B
+:10536000CAABC57B3178BEFB0FF3FCF9FDE53C7F92
+:105370005EF3CB6A79F1E306FDB2741F46CBA7D783
+:10538000F2E3B5FBA18B77DB22A85FEC3075389197
+:105390000EB5BCA2F9A88B601C467C673C7E9D5B69
+:1053A000CB2AE79751BF61F59BFD6509F49B33421A
+:1053B0007E3E56A6CF238AD1CB9F289BACD3CBA9C8
+:1053C0001EAF97FF4FF965E70CEF17365CA2FFEDB4
+:1053D0005B97D8AFA12C817DDD6A4DFCBDD0D4F1A7
+:1053E00082FFC6FDBD1136E47E0F976FED92FACBBA
+:1053F0001914E732519C4BE32FED297CFCB7055F74
+:10540000D1CA7382DF0CF75D49E378DE6FA3E47BDA
+:105410000BCFB1F480DE4F56D6A1F7934DE8CCD038
+:10542000D5274646EAFA57F4E6EBDA27474B74ED00
+:10543000979D2CD7D5A7F54DD7F59FF17E95AEFE5C
+:10544000957EBD9FEC8A734BE2EE1D71FCAE048C21
+:10545000887D6F96E5EBBA7EB90DFA7DE535E9F703
+:1054600035A659BF2F6D5C5748BFBF8276FDFE320F
+:10547000D07FEFF9F2FEFB4D1E55F8EF0BE8BB7F36
+:10548000BB6ADCF49D6BEDFE9FD6EFBF0137C3FC1A
+:10549000BB80700000000000000000000000000061
+:1054A0001F8B080000000000000B53E16760F851FB
+:1054B0000FC15BF918182EF021F8F4C01CCC0C0CAD
+:1054C0009C40ACC8C8C02001C4FC40CC06C49E0CA3
+:1054D0000C0CFF81F81B10BF05E22740EC0CC40741
+:1054E00058B09BE3C6CAC0E001C4DC40B3789889D9
+:1054F000B7DF8917C17ECCC3C0700E889FF1D0374B
+:105500000C061B5E27403FBB7E43ED3A2932F0FE7E
+:1055100006612131609A1447F0A78AA3CA0B8B2138
+:10552000D8C9D294D9950FD40F00F19321F08003FC
+:1055300000000000000000001F8B080000000000B9
+:10554000000BED7D0B7C94C5B5F87CBBDFBE92DD16
+:10555000CD26E44900370960501E4B80C84BDDF072
+:105560003252C40411828A2CAF10027914A9A5FF0B
+:10557000DABB0B2804AADE5851A37F6A17041B2D3F
+:10558000DA80D11B6DE02EA208D56A684551AB0DBB
+:10559000888808498C8F6AB57ACF3933DF66E7CBC4
+:1055A0002E89B6FE6FFFBF7BC3AF1DE79B993367A4
+:1055B000CE3973E6CC9999B3268385192E60EC1BFE
+:1055C000FCBB9C319B893136A62B6D573A86AB3993
+:1055D0005DE5B7F9BDCC6B66ACCE6FA5748B3F9D16
+:1055E0007907C3779FA1306867EC5EBF8BF2BFF08D
+:1055F00017525AEB2FA27A77FA4B287FBBDF47E985
+:10560000667F197DAFF157537E837F0DA59BD445EF
+:10561000692C05FA66458559C98C553D9393B71990
+:10562000725B668D4F504743FE15233366017C9FA6
+:105630004AFD31D5BD69E0E8AE7A1A9E9BD449FD9A
+:10564000104EED128E17B3325B8C7A5938CE3B97E1
+:105650000878F6D69A9CE4A8F50623BCDB4B00DE5E
+:1056600050287085AC39D1E15D8CF03697A8BC5ECE
+:1056700072B0263B3A3C0FD6ABB941C04B0F5863D2
+:10568000D41B83F536DC20F0EBE7ABC98ADEEF787C
+:10569000ACC75CEADF5AAD8CFEBEC9C6FFB7BB4ED5
+:1056A0005D2CF246CC263136AEAB9D3E652CC070EB
+:1056B0009C2AF315121FDC995F7F93CFD84D0813F6
+:1056C000DA0726B19011FA0F24B1E0FA2CA9FE4CAA
+:1056D000AADFDAF7EB6F52A5FA014394FA26D6A0B7
+:1056E00060F9CF518E80EFF7F97329DD28E4E7BE2A
+:1056F000A106C6B05DBA393808DADDE3F790BCDC44
+:10570000ED1F4BE5770939FC7721674121670FA22F
+:105710009C41BA15E5CC8CFDF95A4B014EFBDE7865
+:10572000B6D94DF2B598F05419C1DFB077C8F6CDAF
+:1057300000FFBE1B569DDE06F46F6B1EE63142BDB8
+:105740007B866AF2C5BC2CB9ABDE3DB34F38170D72
+:10575000257A97219CBB3D827F2A0C2CA2DEDD336B
+:10576000C2F52AB0DE5D9E30BC5064BF774D09D7CC
+:105770005B457C56584983BD3B5F763085E6230800
+:105780000AD1D784F48579F9EC80EB9456689F921E
+:105790009C97C6A0DDFD381FCD38EFDC4417AD3D2A
+:1057A000D2D907DF332CAC1AE10365F71B015FD3B5
+:1057B0006C7722D2E5F66B8B98328CB1BEA23C3569
+:1057C00050A464015CFB9C2205BF9B6643397C7737
+:1057D00089F2E435BCFC762C7774952762397C4FCE
+:1057E000AA8672C8DBE7F2F23BFCC089C15DF536E0
+:1057F000019F7DC4EF74FE1DD88AF4318DE6A98621
+:10580000F713282440BF83988EE9C27FD3A07B334F
+:1058100016DABBF0B50DAEA7BC86DFA6C17194D772
+:10582000F0B15DD82F6321A47D97F465DE5C311F54
+:1058300058773A277AB3A5F24CD593A0029D325FF0
+:1058400032B200B02013C413E1E9DB153103E1D912
+:10585000E3FC4BEEDDFC330D95E9A0A547053D3497
+:105860003A6CEC2FD3C13240A6C3C601321D2C17AF
+:105870009C9F0E3B989BE81C8B1E5ABF9B87C8FDC4
+:10588000C65D24F7BBF922B9DFB88BFF39FDD664BA
+:10589000C9FD5AB3E57E6BB2E57EAD39FF58BF4C0A
+:1058A000F5C064407DA5FD5D28E9B7AB99EF2CB646
+:1058B000473D87F349D373A6641FF3D9BBF809EBBF
+:1058C0001463F99170064B7A15E07C8AF5008EF727
+:1058D000FC705C3A3883F470BE16F8B0483DDD0DBC
+:1058E0000E1BA81F8749E1ED428688FE99EA6345B1
+:1058F0008EC8761E5DFF39FAFE9D8A1887E1BCFDD1
+:10590000BB7574CDD6E39326F06186F3D183B97469
+:1059100070B2F470DC029F90725E386EFD382E1407
+:10592000FD071469FD027A0CEB6AD70EF8D13A959F
+:105930006709EE04FD10DAF7E5295C07CE355EEB6A
+:10594000B640FDFD232DA1CBA1FC5CB0206881F207
+:10595000C94F1E75A21D53F1A451C572C33E1BADA4
+:105960002F6D3B142AAFB2B4DC3901CA3B9E34B26E
+:10597000EDD45DA601C7774AE81416E2F9521BCFB1
+:10598000566CDB7F23B62F6BB2301BC0AB787AD955
+:10599000CC09905F76C8C4B04AC5CEB5E6BE905F6C
+:1059A0001E541A300FF8D23A15C8B3057742FD7568
+:1059B000FBBE6C43FCCF359A06213E67609D70C3E9
+:1059C0003AF192A3257536D0A73CB87B1AB62FDFE3
+:1059D000A57840C301FE3B0F6620FE8F281E0BB04A
+:1059E00070457D3C7347CC97538D461AEFAA6D4A9C
+:1059F0009001BC65AC761AD2B302898378782C41C9
+:105A00009BD235DFCEF8EBA83F2D5FF108F407ED10
+:105A10002B1F573C38E44A03F3E13C6E7BDA56F225
+:105A2000901DC7BBD63CD881E3DC68C67ACB820B1D
+:105A30009FB2B911CF6DE66988EFD66DE6D2A14865
+:105A400047B6A06828E2F77F65FCEA8C5E1CEFAAE7
+:105A50009196ED46C083D943036739BAEBD933B089
+:105A60005EB923D6CF72067A9FD6EFA0B97858D701
+:105A7000F72F0D89A43F56D41B99DBDAD58F261F4B
+:105A80008123423EF63A88DE1A3F57B9F814D0F81F
+:105A9000B92A51F057EDC89F35AC3B3E77225FC81D
+:105AA0009E7651FA0B583731DD02EB3CD2EF5EB0F7
+:105AB0009FDC64977BE8FB03602761BA15EC244CFC
+:105AC0001F043BC92DEC24ACB71DEC244C77809D02
+:105AD00084DF1F067B1CD37AB0C7F1FBA3608F6302
+:105AE000BACB1FA0EF8FFB6B286DF0D752BA07F926
+:105AF0000669A33F48F59EF2D753DAE46FA0EFCFD3
+:105B0000F89B28BD5DD0D1399115E03AEAF43217FF
+:105B1000923D6986B7C004F9A4229E4FBD21506012
+:105B2000867CAA0FF24097BE2B430516C8F7ADE658
+:105B3000E5036E6193AC901F10E0E5D9B77B27D9E0
+:105B4000209F5DCBCB076F0D4C8A83FCE0202FBFDD
+:105B5000685768523CE42F6AE0E5C39BD9643BE494
+:105B60008787783EEF25EF6407E4F35A783EFFCF4E
+:105B700081C94EC8E7B7F2F6E3CF068DEE28EBEF0A
+:105B80001E937B31AA9C03CADB5E3503F266F74D98
+:105B9000A8128F2AA728DF68F252F9FB4ABB578563
+:105BA00075BED1ECA5F22F94CF29FF94C947E5F13A
+:105BB00006A580F2661F95F737C451BEC914A0F23E
+:105BC00011863E3C6F0E507981A15F01C27FC614E1
+:105BD000A4F26B0C8378DE1CA4F25FA8C30BA64072
+:105BE000FDC70DBEBDA8EFD62BBE32B40F99DA901B
+:105BF0008EFA4AB32B77E2E0D0CECC30D33CD8F348
+:105C000087FC87681EE05F32E64B1F46BB14E01C32
+:105C10002438268063EC194EDECB632538792F9724
+:105C200069705E2138B6DEC1D9F3F278199F97CB3F
+:105C30003538C7088EA377E3CA7B65A28CCF2B2BA0
+:105C40003538C7094E62EFF0693C2AD3A7F168984E
+:105C50003E67707D589FD23B7C46BF26D367F46B6E
+:105C600061FA7C4CF864F40E4EE36B327D1A5F0BE4
+:105C7000D3E72B82D3BF77E31AFDBA4C9FD1AF870E
+:105C8000E96332209CACDEC179EA6D993E4FBD1DBF
+:105C9000A68FD380F419D4BB71E5BF23D327FF9D12
+:105CA000307DD2089F21BD83F3D43B327D9E7A277D
+:105CB0004C1F37E133AC77E3CAFF8B4C9FFCBF84AA
+:105CC000E93384E08CEC1D3E4DEFC9F4697A2F4C2A
+:105CD0009F3C8233A677F88C3D25D367ECA9307DB5
+:105CE00026109C71BD83D3744AA64FD3A9307DA6DC
+:105CF000109D2FEDDDB8C6BE2FD367ECFB61FA5CBB
+:105D000045700A7CF5840F03388ED8709E3927D3EE
+:105D1000E7997361FACC213853014E4ECF70C6B764
+:105D2000C9F419DF16A6CF02827365EFE03CD326D3
+:105D3000D3E799B6307DCA88CE57F56E5CE3DB6554
+:105D4000FA8C6FE7F4A9B278263BD0BE4B649EED87
+:105D5000D0E492930D079C9037D99907C1BEA484D3
+:105D600076207C582BC92E543D9A9DE2616887CEDF
+:105D700070BA3DE8F7316AF6086BA1FD827D57A243
+:105D8000E40FFAD230E916C4D701565BA45D923015
+:105D9000364EB28712BD4952BE4F615FA97E4A514D
+:105DA000B6549E567291549EE1CB93F29965E3A549
+:105DB000FAFDAB2749F90BD64C97EA67056649F916
+:105DC0009C9AEBA4FA836A1749E517D6954BE543ED
+:105DD00082ABA4FCC5F5FF47AA3FAC619D543EA22F
+:105DE00069B3543E32F40B293FEAD00352FD312D02
+:105DF000DBA5F24B8E3D2A958F6BDD23E5279C7E3C
+:105E0000466707CAFBFFF5058CDB831966B20743BB
+:105E10000E33E5CDFB6C64FFEFC73CF0D3DC7706B7
+:105E2000E5CDCF2E7627E37E1A01C07A5FD0B7EC9E
+:105E300042F4F7DC3CDE77A10BBEDF6CF68D7045DB
+:105E4000F1477854DF3E03F98B5A14968EA9DB8014
+:105E5000699C51ECD72D5CBE3666E53F148890D323
+:105E60009AFE30FF207FD86026FB5593EF8DFD4BC7
+:105E7000D31746F4B3A1BFB964FB50FE7DB11DFB3F
+:105E80002B7A11E75995B96330E2A5EFC7923D56D9
+:105E9000EAC73AA08CFA790DFB89F07B590694E9A0
+:105EA000FAB1966C17DF453FC7705CB1FAD9983DDF
+:105EB0005E1ECF8072EAE75D5D3F1B0794EBFA89B7
+:105EC000E3E381EFA29FF7CE3B9E9C89F2782E58A8
+:105ED00049FD74E8E866B960A5AE1F3BF583DF179E
+:105EE000933F17760169C0674B4729C9C17FDA58CC
+:105EF00000E4C29C59FE6BCCB3B76C6C10F6E38621
+:105F00007EA11ECBE5FEA3A70D49349ECFE280FF04
+:105F100011766AD77E3640FBE2A5024516048C60F6
+:105F20007F5B296473C9AEE20137B9216D3A30F065
+:105F30006EEC678BC33308F26D4D93CD8BA3C8D342
+:105F4000D25AD3A9D648BF88B6BF99C472ABA1FFB5
+:105F50005D369794D7D2958A8B097F04E54FC0BEF2
+:105F600085C17EE0CFB02F6040AA774D7C9FF60EB2
+:105F7000EC6F30DF0AFB1B2C676C2DB53B21FCB4AA
+:105F8000276E578248EFCF7EF24313E9F1007B354D
+:105F90003D15FD6EFC6FC19A78F4F187F15B18E84E
+:105FA00023E5415D661AD2695F48FBDF8EA72DC1EC
+:105FB000ED48D79A4CA0A9A897CDD8EBB0C9CD4849
+:105FC000A26CA6612C63B3AB8BA7A6D12C52FAAFFF
+:105FD000023C67358E34410BD6666ABDD163EF82D1
+:105FE000CBBCA613481F2BFC4338D714423EA2FF5C
+:105FF0006B8BE4FC5CA676E581DF838DD9826FA292
+:106000005FB7D7847C2D4AE5F8CCC5340F8BB9BF78
+:10601000A3C4C5DB6AF8542D36B110ED4F03290C2B
+:10602000FDD18164AA779DB6CFD4E15762B27A8B55
+:1060300080AE250B8D44573DBE6FEE8BF71A86431D
+:106040005A73B7095D9B3DE13FCF2797B332DE9F7F
+:1060500046574D5E4E09FE9E40FE43FA3EF21FF04B
+:106060003E29F8DF25C79CFF5516DF4CE47FC7FDAE
+:106070004646FC127C9F23F8BEB456E6FB1CF49304
+:1060800043FD39ABB382EBB17E5D1F89BF307099A0
+:106090000EB5774D05B5DA0DFFB7851C5C57B3FB20
+:1060A0007964EFF565BAF1093EDC28F8305F478F77
+:1060B00039826FF305DF96B1C06D19E43F0A9AD0BB
+:1060C0002F36AF4C61A82FAA7EAAF1AD55E29B4FA7
+:1060D000E39B0EDF1B05DF6EFC09E79B1EEF56C13D
+:1060E000B7D6BA8F4D2CBB3BDE7A3C17ACD18D2B8B
+:1060F000A0E75BAD38777099D1DE29F616F439192F
+:1061000051FF9AC22BFB9C8CD00BD716154BF9B9BB
+:1061100025F3A4FAF37C0BA5F2EBCB964BE5F3AB9E
+:106120007F28E517ACF989547F6160AD54BEB8662D
+:106130009354BEB4F62E29BFACEE7EA9FEF2E03633
+:10614000A97C45FD23527945C36E295FD5F4B4542B
+:10615000DFB06FC8D5285F2F1D3532F4977DEA79FF
+:106160009FFC759F7A4C1EAC538932370EE5D94D92
+:10617000F27CCA9F4BE969BF87E4FD8C7F2CA56D3B
+:106180004D07ECE87FAC8A03BD9F0876B8F1CDB52A
+:1061900035FD70BD81F6E3196B36B6AE0D40FE00DD
+:1061A0001E46C1BC99516766A1510CA4BB6F589E95
+:1061B0003B8C11E5AD3D94D7A92CD4A77BF98CD6A7
+:1061C000E8DFDB958EC119E8277CC3C27646F8EB81
+:1061D000BA9F57B04CB42B62959F35B0B2C8F3ACA0
+:1061E00093467E4EE2344E3A698474A599CFFF956A
+:1061F0007B32263127E64383ABA3F85DC2FD350031
+:106200003269C8E71C69DE2FABBBB86B9E33EC2745
+:106210009BE476797094F47D45FD04A95DAEE27B44
+:10622000D708F5CEEE37D27ACD4207065C330CF1B3
+:10623000F39EC4EFAC2985ECAE16BFB7CFC9818CF5
+:10624000FDD15F48E9ABFE224A5FF397507ACCEF6D
+:10625000A3F44D7F19A57FF65753FA8E7F0DA5AD98
+:10626000FE00A527FC35949EF4D7527ACA5F47E911
+:10627000697F90D233FE7A4ACFFA1B286DF33751EB
+:10628000AAE9CF9EE4EFB4585FCFA0FC459133F369
+:10629000AD6C5DCDC42E398B532DEB50CE34FACE80
+:1062A000A8B308794895E42111D76192B31ECAEBCF
+:1062B0004C420E63B58F5E8EF2D6F77B9037C6D612
+:1062C000911CCC1472F75DE58DA1373E05E529538D
+:1062D000274FB21C6A72A4E9815CA568B83AA64B44
+:1062E000AE661AB99DA4C9D5CFD14E8C626FDDA020
+:1062F0002A62FDE3F611F36518D07E5B25FCFECC27
+:106300009D4EF94ED1F77A00D782F5D4602EAE2398
+:106310009DB97F1B8CFEF1CE6316867EF858E3D3C1
+:10632000CB4B6CBA7B69FF501A84456D54F7725B96
+:106330001CA7ABCDC00A591E9ECFE61FF3013FE359
+:10634000FEF3E23CDCD7C27795915D15F41447F17A
+:10635000B73394F1B49EE9ABD53FF5C097F9786EA9
+:106360003E53CCF3B803467EAE1D7AC8734DC4F9D4
+:106370000CECB7D3D1EFDC31C8EC22FB21D457A60B
+:1063800063B0AF44C703833E1B8CE71B9B400E7179
+:106390007E750E1C9CC0CE231F3DE9F99EE8B928EE
+:1063A000D8B797F434333C37027A6EC7FB2FBDA5BC
+:1063B000674F7AB227FD786233A7B353D8A7B1E805
+:1063C000DC3E09E65D1439BE475565396603F97947
+:1063D00087467FDC9746D0FF52BB9BEA3FB7EFADC5
+:1063E00001ADD04F67E385098C9FE7905DD7F1A49D
+:1063F000B0DBDD99321F5BFB125C0DCE734FBE3EEE
+:1064000000F7C9B76106E6D993F145BF5253BAE028
+:10641000F5F61C3ED6B8767FCBF9D99EAACDCF969D
+:1064200001284F9F093D10737C3DC9298E0FE05C08
+:10643000A5F0F16D3016FD0EF54C787CA3537A353E
+:10644000BEAA04335346007E0EB3992530B643F5F9
+:106450001D54691FE7690DA09F625FBC673DB0A432
+:10646000CA79E6E5901BDBC9FE8C15F536976C3FC3
+:1064700025BA64FB29C315693F751E7AC8E903FC78
+:1064800056A51B5C2747E13AE715EB1C5F5735FC27
+:106490002A1AB25C76098E9CEFAC550A1B489EDC2A
+:1064A00009B3A39C9769E9AA74B3EB24AC5767EAD4
+:1064B0007312B0DF337EAB8BAFAF2E17EF37DD1526
+:1064C000B9BEAE5C1347F535FC62C1FD67E3C75842
+:1064D000237BD78AEB2294E5C4AE1F939FEA2766FD
+:1064E0003A976E367D86F6BB2D57B3DF55CA6B7073
+:1064F000AB1A8C01CB08FCBE4BEA0FDAB9B5336698
+:106500006C175B6E54764AE327F0DF8A07EFB46FAF
+:10651000B5129F7D003101E0B5ABF61A94AB132A9A
+:106520009FCF55424E2BACAD669F9BC8DD82F2BC1F
+:10653000682CD326CCDCB7404F7FF0A289EE69B13E
+:10654000AF007A7ED7558125ACC8894ECF458D2BBB
+:1065500066E0BAFD8141DB0FD7E6E3B8CF314321D6
+:10656000EAA573EC8FCE5111F3758889FB63580D42
+:10657000DFE704E01F8E6F69ADBCEF595627E74B8C
+:10658000D9AC54D4B7A55B4C2C08B82FC77D933633
+:106590006ED0BF1926EED758C6AA37E03EFD5E136F
+:1065A000F7F72C72313513F0AAF88F5FE6A3DFC737
+:1065B00063E27687769EBC3C89E35D3E3B68F642AB
+:1065C000FD771B47CD018D0BED831BC8FE29669E11
+:1065D0009DAC3BDD17D7C8F8F584BF1E5FCD0EEA32
+:1065E00076AE2DF048AE57BCC1287AEE329322F633
+:1065F0007F7C7ECC36C9FE9C7926D9EFA3C9814920
+:10660000C8C109D577B5690CE73BF251513BCCBE07
+:10661000887AE6AE7AB3CF57CF82F58C546F9E2935
+:1066200005EB754CA3FD3103791ADA55CFD605EF8A
+:10663000460E4FAE57F11F8F3D15007929FFED3DF6
+:106640004E06EBE6076A6DAA07BEAFDC799BD30B5B
+:10665000E96935E0447E7E10341646A3C796303D86
+:10666000BC7605FD69423E594D80FC149FED34B95E
+:10667000C8CF5F6F0959404E2B1B97CF60C3297F4E
+:106680009CE7377E64C47C93CCAFF25FDF93EAE68D
+:10669000F76CB83F8985C8CEADDCF1DE345C2FAA3B
+:1066A0005807C999BE1DF6FF7912CDEB85E684EE39
+:1066B000E58027F913AAC42CAB6AFCF9474627E604
+:1066C00065F92813F62AD209F7F9B7991CC9A7E288
+:1066D000217B09BB04E7B9460F16E476EBFA47EED7
+:1066E0001B7E1CF039BBE345A73234523F7039EBB7
+:1066F0006C58FC2BAB21B61E6903398CB48F00306B
+:10670000B57337097BBB99A72B4D2127DE6759B994
+:10671000CDE40109642B1F3332BC07C0DEB004D1C5
+:106720002FBAE2B1E75F1B0F745FB1DB943C830FBC
+:10673000C7AEA476F1A50AFEB726AF8B0FE54F3C96
+:106740006F760FE3DF6F49EAE2C78ADDFBCD6C5855
+:1067500077FA4D6ED86F6EB547E14BC3F169B8CE8D
+:10676000AE7FE4AF66F4277EB04F616959DDDB97F9
+:106770006D7B9ED63BA413F151F029CCB76EFC0A79
+:10678000CD7C6634D573A11E8CC5AF6542EF823CCB
+:106790003FFE0CDEFF79D3E2C1F1973D7E9313C734
+:1067A000F1BE5ACDE5FA97B7A5E2FC2E3305525D4E
+:1067B00094F2EF650FFE88E46DD9911FA592BDC0DC
+:1067C000BC1906D2C5810C1CDFD2ADD7D2F84A99CC
+:1067D0008FE4AEEC97C622BC8FF8A9CA0A77479916
+:1067E00017716685F0797F3B183230BEF7717F896B
+:1067F000FAEC8F46BA17C5D80FE9DED88FC45861B6
+:10680000E5A3FCA756CEA7E3424FE24496E475C742
+:10681000C616E4CF99FEDE343CE7003A0404BD948A
+:106820006F00AEF1C8D434CE1FE656F3453BD0EF2F
+:1068300093F13BD66F31796DC3A576421FF2FE57B7
+:106840008BFE01EF385CAFDE4F8D6EEF8D11E38371
+:10685000BF1616215F11F39BCFF71D9BF8FCD6E600
+:106860007BB0B810CB3F7995CF1F6C87EB03E01559
+:106870004AA3F2FDB315D207B0AF8E36AF7798C4F6
+:10688000BC96CBC152A4F51EF0569584483901F848
+:1068900049447FDA07976E817611F65715F647F56A
+:1068A000CC5DDF23D68765420F98CC30FF2FEE9A60
+:1068B000FF6C2B9FF73DD9932B4DC1871FC0F9FA71
+:1068C00086C51370E37C3515E1B83FDC75E0B5EBA8
+:1068D00040AE3F6CD0E6A9AC3FF5F3B46CCF1816D0
+:1068E0006D9E7E6887FD55B4790ADFA3CE537B2B5E
+:1068F000C9F1F7AD3F35BA0D35CB7A13F5E033EE7C
+:10690000D8F4D3EBC1DF9BDC4447BD1E84BF57598D
+:106910007E77B9D3E44D93B3F2DF545C80FA262C32
+:106920008F9ABC85E5519337FD3865BAE9CBFF2ACC
+:10693000F4CDF5D6C26BD02EB67630DAAF14CC36A5
+:1069400006719F6CFD84D17C9F74433CE5E71A5B24
+:106950009F409BEFAD8AB9C3701DBF9E054CFCDC08
+:10696000BCD64476EA57DF7C3311C6739DA0EBF5A5
+:1069700040E6AB800F25AA128A033CE7A92C909031
+:1069800084FE62859D88C0E3FA32398F7F97A576B1
+:10699000C1E9A9FEB7B5ABBF6B7AC4CFCFAEFE8459
+:1069A00029ED2FC0708E90A3E2667E4E51355A09B4
+:1069B00066D3FC6B558B22F6098F99B99D7164CA19
+:1069C0003563907E05738725907CD70EA17D6095F9
+:1069D000D05B9D017702EAF3CEE61CDAF7751E5A0A
+:1069E000ECF045D15F07849C3D2FCE59DAED4AADDE
+:1069F00011E4BD9D7590DD12B0DBA2FADDEACC0694
+:106A000061EF08BEC19F11FA2F1172380F9A26E468
+:106A100045F06DF6551FA8CEEE7CC0BF1311FB8666
+:106A20007F94BE28D748DF03B6D6694551FC338F23
+:106A30000A7D7DD9B35F98719D9BD25CA0221DA772
+:106A4000D88D92BF63BB365F87B2A188D765CF2E42
+:106A5000BF630CC871D521A3C706E3AB6AFEC8ECBF
+:106A60008BB27FD3D313E1A3FDD86AE6F6F151537D
+:106A7000D152A4EBD16BF979EE9FCC9E8A6878CE87
+:106A8000B6723CE7B1A24F472BFF7AF42D98EB0882
+:106A90004D027A74DAF9FDE4EEF2C7E77DA74B09FF
+:106AA000AE55500E8D3C9FCCEFFF4E63BE3B262A69
+:106AB00034DF2F8FD45F054DC58FE17D96CA66C543
+:106AC0006580F24AB5D58C725CD5B45B45BBFC07DA
+:106AD0006EFECE82A9D5C36647F8B75ACDDC9F7447
+:106AE000E06FD7CD47FA7E3CDBC2102FEFD08F9CF2
+:106AF000B8DE7FDC3C8AE641AC71FDC1EFB9660AC5
+:106B0000FAE3CD5C9FE9E5615A72BC94BF7632EB43
+:106B100087E7BC97595A6FF244E1DF3A0B9FA7BD54
+:106B2000D66FD6FF61FA6D22E8372ED7A648FD361C
+:106B3000DDC2E53E42BFA545D36FABD6BAD3502EDA
+:106B400056EDCD4943BEAE3ABC34259A7E7B41EC2E
+:106B50006B0F8B7BD2EDFD40BF8D88D06FFD40BFAA
+:106B600045F1838FB66876670FFACDFADF33FF5EA3
+:106B700040FD1665BC5708B9D3F45B61F35AD26F78
+:106B800085FD8CD27DA4CB2CC28E8BA9DF16DE7343
+:106B90002DE54D9EF828F2837445FD7658E839ECD2
+:106BA00007F5DCCF2CDF4ECFCDB3727C7BD473FFE7
+:106BB0004D74D6F4DCAAFE0AD92FDDE590EBB95569
+:106BC000595CCFADDACBF5DCAA415CCFE9F5DBA4AB
+:106BD0006EFA8DB7AFCC85F6B44FCCBAEF06BCCF0A
+:106BE0005762F258A1FE0CB7F6BEA07A4CA4BEFBC9
+:106BF000992586BEF380BEB3F7ACEF5E417DA792C8
+:106C00001E1B88F3482F1FD307C64BF7D58E7E7106
+:106C1000EA37BFC5F9F20723DD077ADDC0F743FB8A
+:106C2000BE38350AE7DDCB880FCC979D42FEDAFCF3
+:106C300063499F4E1ECAE77BC5A1385A272A1B15F8
+:106C40003EDE5B94A01BD781BF7D4EFBE4F97BF950
+:106C50003E79AE85D383FDD8C8DF4500091646C806
+:106C600043C9E7E5E4E72B519915EDD70587A67FE2
+:106C70008076EB82CF6BC8DE5D80DFF17EC5EED61D
+:106C80000D99D0EFFCE50AED3798B80FA1DD97B864
+:106C9000BE793FDD5FD1DF83D0F4F9FC6AF9FB02F6
+:106CA0009D5D7F408C13EC59A20B7BC518D53F77B7
+:106CB000404F0F0F1F7FC56A6E1F87E901F4712BCC
+:106CC000DDE9011C9DB130B56BFCF39F8471257724
+:106CD0008D4BA3877E7CDAFE6481981BB1C6ABD155
+:106CE000AFDB78357AEAC6FDBC45D84517B36138C5
+:106CF000CF5E37F8EE188372F17B183FE03367DE22
+:106D0000A0B4483DFCA2D0E757F98E4F497523BD8A
+:106D1000F8FBBBEBCA763F9F0AE3B8DA9B9587572F
+:106D200011AEFD9BD9877E8403B60ED26B9A5C5D53
+:106D300068E572FE7701E7685FD7145A3F9A141727
+:106D4000CD97904E6F897B6155404F9C8F554D621A
+:106D5000BD0179C3F9364D5B7F90FEF09F573573C7
+:106D6000FA57552B44FF99ACE320D2B73259F1843E
+:106D700000D4B4A6DDB7E13DAA176CF01DE76D990C
+:106D8000E2D9CEC961CF488D2A976A34B964D54318
+:106D9000C8AFA0AD830BB05E12BE17793D05ED13F1
+:106DA000BDBD7199A5E528E271D98F4D6C1BEB6EC5
+:106DB0007F68FCCE857FDF44BBCFD383FC0E12F609
+:106DC000E50B486F3BD2B5C38C725F15E2EB86567C
+:106DD0005EA5BAA7107D347A37C1BA309AD31BDFCB
+:106DE0007DE9E979B5964779C6FACD8A09DB5F096D
+:106DF0007CE80345930D5F1CD4E417DF89E9E98241
+:106E0000FBFF8C88F98E7A29F2DCB1B2E908D165F2
+:106E1000FA6A30AB22E88EFAEA7CF4E9361F9AF679
+:106E200047BD07F56DE7C38556793EECB375BC38B1
+:106E300002FD5B7B15D207AC3951DADF5F61E5FB00
+:106E4000A603361FC96DC76113DDF7D6EB8DB1827E
+:106E5000FEB89F887C0737190782E7BB2E1B7B573C
+:106E6000C3239BCB4FA4BE7EC1E6233EC5823F4DCC
+:106E7000C08F652F85F1C5FEF03CC52DF7A75F2FAC
+:106E8000343F4F4FE3BA46ACF7DF755CE1F349D6C8
+:106E90006266DC9FBFDB1C71CE3447F8F9353F5882
+:106EA00044BD999631B1EBA1BF2504E37E61D74380
+:106EB000E4D73DF7E8F19928B72B7E676456E07375
+:106EC000DB2E070BF17B14665C57CB1B8D51CF4536
+:106ED000185B4FF8ADF8AD83F44AF91E4B7006B459
+:106EE0002F7FEADDE1E89F6A5BC7F54BE051211F88
+:106EF00081D6E1785E5EAEF2F3623DBC1F0B79395C
+:106F0000FB747C09EA47A59EBFEB2C6F986BB244DB
+:106F1000ECCB2BF1C08DD7A37BC8814714F28377CC
+:106F2000C76F2DAFF708D77BE54DA620BE0F2DAF5D
+:106F3000DF46FBD9AAFA8FCC68C74DFEED636447E4
+:106F4000543519653F61BD3164213FA6F138A67AF9
+:106F50007F5D656305CDC7CA06E10FD3F98B56FC8B
+:106F600076EF530120CD8A277EED443D73A665A7B9
+:106F700093FC70F5DCCFA6DAD5E87EB89EFC6F0DE9
+:106F80009BA2FADFCEE07FC0FCDB6A95FD6FACBE52
+:106F90004FAFCEC1573CF6E983782E7476CF870F7A
+:106FA00022DE2BBFFEF8C19FA27DB2CFE6C2F5AEB6
+:106FB000EAD1A3E457D7DA3D25E655DB23BF7EF8B7
+:106FC00001987F6D6F58E8FE55DBDEF707B8619CCE
+:106FD0006DBBBF4845FFE5EABD5369DFB2FAC9C9D9
+:106FE00069E7BB47827219ECC579889E0F071A8D35
+:106FF0000CDF419E3B66213B23EC476DA8E07E6998
+:10700000B7F09FEE8A7EEEA4F9FD2A1BAFB9FA52C3
+:107010005CF71A4D1E377D177EC09EFCA6AF023F5F
+:1070200047F4826FBB845F5CC7B773F81FC09F3F94
+:1070300059657FF3A78D4B7FF5009635F689E937C3
+:107040000DF5825EDAB9D636ABF71D2BCE873DBF84
+:1070500021FF34F20B6C6ED6F6D8A703D0DF70DABE
+:10706000D47123DDBFD86BA17B42E57B5FA7F9D14B
+:10707000F6E4113A2F62E25CA98D85FFF83980D8D9
+:10708000CB54ED70707FABA03BFA63DD4EFA2EFC63
+:10709000AE5C6E357F6C2C3F6C1F9BB8072ECED933
+:1070A0002A76BC65663ABFB63216F9745C3A17D4D4
+:1070B000C6AD87E7423A5C12799E10CBCF2DF468BB
+:1070C000984FFC1CA16D9B385F089F1B30D62F0F7B
+:1070D000EFBFF3F3EEAAA0F23A8B321FB5F304A789
+:1070E0004D371F83BD3B47E819DFEF460FC5C6F795
+:1070F000AD1A5DCE7E155D1F0FB129E2FD812FD740
+:1071000016B1EE2C10EB4925D08BBF27E3F89E1566
+:10711000FBBBB38F1A83B80FDED07080F4AA7E5EFB
+:1071200057B2E8F143C6DBB83EA96CDA3F1CF5CF95
+:10713000D9679F26B9ABDC75DC1C003807EB9F30A4
+:10714000B70EED9273D4D7C1087D7DF6F1FDC3F97A
+:107150003907DF47EAE15F21E05735CBF0AB767DB9
+:1071600024C15F116830BBEC3DF77346F5CEC5F125
+:107170009E6931515C94330DC6C268F14A86622023
+:10718000A9942E3A6D70F0F771C62433D991AB1DD6
+:10719000638F2524636A76E33E7AFD5A7E1F72FD73
+:1071A000CF3CE9C897F58973E81CA856474757B202
+:1071B000AB00F7D7AE2945A351ACF47A20D16B9040
+:1071C000F05EED284CC3F7DCB70A7B84A91E7ABFBA
+:1071D00067744E2BC471185D06972DEA3ACAE1997F
+:1071E000EC45142FC2E492DFD37DEFF11FDCFDE408
+:1071F000F80F817EFF68FC07467130FEDFC77F080D
+:10720000603FFF02F11F42E4B7D1E23F247FCFF19C
+:107210001FD63239FE83E06738FE83E0E7FFC67F82
+:10722000F8FF2BFE8331EEEF53303E8316FF21250E
+:10723000CE3C3532FEC38571095323E33F8C8B4B23
+:107240009F1A19FFE10771595323E33FCC8FBB68A5
+:107250006A64FC87AAB8515323E33FAC8D9B4879FD
+:107260002DFEC3DD7153A7CAF11F664E9D02F9B60C
+:1072700038DFDF71BD8A15FFE13D9C2C637A8EFFFC
+:107280000070CC716362C77FD0C38915FF01E02411
+:10729000109C18F11FBAE11323FE03C049273831AF
+:1072A000E23F74C32746FC078093457062C47FD0D9
+:1072B000C38915FF01E05C1497123BFE831E4EACA0
+:1072C000F80F006714E11323FE43377C62C47F008C
+:1072D0003813094E8CF80FDDF08911FF01E04CA541
+:1072E00071C588FFA087132BFE03C09949F8C48895
+:1072F000FFA087132BFE03C0994BF8C488FFD00D65
+:107300009F18F11F008E8FF08911FFA11B3E31E203
+:107310003F009CE5042746FC073D9C58F11F00CE2A
+:107320002A821323FE831E4EACF80F00E7A7042722
+:1073300046FC876EF8C488FF00706E253831E23F46
+:1073400074C32746FC07807307C18911FF410F27CB
+:1073500056FC0780732FC18911FF410F2756FC0788
+:1073600080F32B821323FE43377C62C47F0038F501
+:10737000248731E23F74C3E7BBC67FB085062A3954
+:1073800014FF81E24486E33F247FEBF80FCD88EFC2
+:10739000FFC67FF89F19FFE166BBEFEB38F2837EF3
+:1073A000B7F80FB6F86F17FFE1667B517C3CEE2F04
+:1073B000BF65FC87D4F86F17FF01FA498F1F13BB15
+:1073C0009F58F11F7274FDF414FF01FA1974DEF175
+:1073D000C488FFE0D1D1EDFB8AFFF045DCF9E33F43
+:1073E000FCCBC559806D0A9EFF149328B27F99B8D3
+:1073F0000BD7C6FF93E32E90B1F0AF1477417BBF5C
+:10740000DF60C2F5EA4DC1F7D7845CBC25E22F1CD2
+:107410008B197F217815F94597CBF117A60B3ECE36
+:10742000F3C9F2309DF1F386E953B278BCCC325DFA
+:10743000FC855CF9FC7A86EFC81400C7AEF2C8E39D
+:107440003822E46166C947CF217BAE1E1B3DFEC2D8
+:107450002CC18F621D5DA60BBE158BF47A7C920247
+:10746000F23CA3EC888A749DE96E55C9AFFD038D8B
+:107470007F6E897FB3055C3DBEB304FF665DC9F9CD
+:10748000A7C7FB55E49F13D2B251C43F3DDE7A3CFF
+:10749000F5FC6791FC8E889B51C0E4B80B93AD72EC
+:1074A000DC85A92E39EEC215E972DC852BDD72DC94
+:1074B000851FE4CA7117AEF2C87117AE1E2BC75DE7
+:1074C00028F6AED5C57DD8A48BFB70972EEEC3FDF4
+:1074D000BAB80FDB74711F1ED1C57DD8AD8BFBF020
+:1074E000B42EEEC37E29BFB8E6B0547F69ED1129F2
+:1074F000BFACEE0DA9FEF2E071A97C45FD07527903
+:1075000045C34752BEAAE90BA97E6FE33EBC2ADE03
+:1075100003BF26DE031F13EF81DF8C11F7E1AF3FBE
+:10752000FFE2B6C8F7F85FFEFC9BDBF03DBE41BC56
+:10753000838D15F7215C1E23EE4357FB6F1FF72148
+:1075400025F99FFF0E3FC7CECF3727C44FCAB1A73B
+:107550007CF777F8D716C9EF99E796C8EF9973ECDF
+:107560005C9FCFF3C9EF9AAF2F93DF3597D97CD9C2
+:1075700088873EEEC384786F8E1DF5A5789F1FC265
+:10758000F7A9B0363E8BEF53217D0EE33E407A10D3
+:10759000E33E407A08E33E40FA7B8CFB00E94B185F
+:1075A000F701D29731EE838A712302226E448D88CF
+:1075B0001B512BE246D489B811411137A25EC48D0C
+:1075C000681071239A44DC8810C139E13F44E949CD
+:1075D0007F0BA5A7FCC7283DED6FA5F48CFF34A554
+:1075E00067FD1D94B6F93FA7B4B7712334B9FC33D6
+:1075F000DA0D66EC9FCBB126A733EC033744CA699A
+:1076000091FDA20D28A7B1E245CC459AA6C48E17DC
+:10761000112E8F112FA2AB7DEC781169A3BFBF781B
+:1076200011FF16CFE5F51F8D1731BF5A8E67B06079
+:10763000CDF9E34594D98A56A35C6AF2F86FF1FC60
+:10764000BCAAA77811DBEC8A58AF812E6877015D60
+:1076500068BDEEE1BDFD738E8773713FD1997BD11B
+:1076600079E31CE8E52236BD795C83EBBEE738118F
+:107670003DD155ABFF66398F5FF06FF1E78F5FD07B
+:107680002D4E444FF105067D467AB2B771227A5AE3
+:10769000177AA2E7ACEF394E444F7AB5277DFAC787
+:1076A000E99CCE13E2CF1F8F231C17CEDA72901AFB
+:1076B000BBBC34B555F10EBC60B68BFC27EDBBC42A
+:1076C000BD312F73BB52F93B75B437DBF7240C6720
+:1076D000F47EDDC5BCC09F78F15DD9B57F3F9EA724
+:1076E000DFEA64DEC4248A07EF36E6E03E6CA415C8
+:1076F000FD29158D1FBDFC3B806B6B36D27DB276AC
+:10770000C0A185EC3E6F22F22D9EDD4EFB743CE362
+:10771000FAA64FE47B66DDEF37609588F39BA946B8
+:107720003BED9B3AB7F27B9E4676F17D1347D37DC6
+:107730006A167413FFC84E5D21F0ECC414EBFBAC69
+:10774000643F2E3BFC447E88F1F3CA48BF419F4210
+:10775000D94F5367730EC777952CE06D41FB7B893A
+:1077600080975224FB6F3E5C547808CFE997F84A23
+:10777000E91E425A89ECCF61E2DD386EC7C2F7E5F7
+:10778000009FD226853DA0747F475ED67CD706DC5D
+:10779000E72C0FEAED6F968B7256CEE23CB8EF5DA8
+:1077A000512F973B1CE23E879DD97B45B7D60BEF07
+:1077B0009B987C5EBA7942587F9783EEC32E3BBC80
+:1077C000D88CCCB2A4CB74B3B965BAC5E7CAF4D12E
+:1077D000D3CFE191E9A3A75FC258D9FFA5D14FBB91
+:1077E0006FA832715F34C8EF91767B87DFB48DF07C
+:1077F000D4D34F4FAF510E714FA28B5E45D654522A
+:10780000F98467861A22F9D6CF874C7B48C1FFEEF0
+:107810009F1C5C4BAD3C0E15F5563A07CD9425BC2C
+:107820005D3CCE078C2BCB3C341F70478FFEDD7840
+:10783000F66721F7EFB26F20BDA9F8B9E38BA0740A
+:107840002BCADB08FEFB0BE4AFD27E3781795CB834
+:107850008F6AF05BDD4B543C1764EE2503F13CD09E
+:1078600045E99DE2DD6FFB5046FBFE86D027A978F7
+:107870008E76675EC74CF43F542D6545B87EFDC8D3
+:10788000C9DF5D6C12E90827F7CF6C2E3230EF6844
+:10789000FC1D1E635041BFABCB7BF872B4479B4DC0
+:1078A0006E7A47ECEA78F97A2A1F45EFA3330CB5D4
+:1078B00023111FA84FEF6BDB9BDF752E8ED0C36D9E
+:1078C0004D770FC1FBC5F71BA2BFEB2D7568EFDB32
+:1078D000F8FD8E115D71064A1D63281EC19DD9D029
+:1078E0004F657127F15193CB0982FECF954E27FC4E
+:1078F0009E6C56DCE8AF9B66BCE107C300BF7147D6
+:1079000055AEBFC4BDEED1A2FED3CC938EF88EBBD4
+:107910009429387FC6BDC13C0124717529DDA7FBC0
+:107920009D73DA21E4D7946690279C0F67ED1EBC07
+:107930002A3FA645BE2F9738C57700EF175E728C99
+:10794000913EBBE498AABF1F63C4FDFEB856F9FB85
+:1079500004DDFE739D26774E968A72B7E52B23E1F0
+:10796000D5DEC13CEB006EFB92BE746EDBFE0923DC
+:107970003BB1FD2B6361B4FB25773BB8DFEB7E3376
+:1079800023FD7D7FA99DDE393C5B5A7E01DA179F7E
+:10799000FDC47741343F65849D96C0DF9F7B13D83B
+:1079A0005894C35B154EEFDA8CA228EB9626779A93
+:1079B0001C6AF297511AE78B765F33D9C9EDA34958
+:1079C000A5B98A19E5679FC290AE6DEB00AFF3AC25
+:1079D000DB01B62E13F1A96AFA98EE61599B95A8BE
+:1079E000BFCBF384C3C9EF03AE0BACC5FB1737C3E2
+:1079F00024423D9561AECD8A063FC0B6905DFA80C7
+:107A0000C3CDDF0D58451C21B53603EF23B4354DEA
+:107A1000BE7203E0F900CC07E4EFFD260FE11DA8DC
+:107A2000608CEE930A7F5DBF996CDBE608FB77AF55
+:107A3000A3E030CAED6107B71BFBF83C0AE2EDF9A1
+:107A4000FB5F9D08BFFD730BF1AFAFB037B5762775
+:107A50001D9C3E254EEF016CCFCA9249F9787C4EB1
+:107A6000F7923EE837077A47B1AFB4753DC9C7E82A
+:107A70007C22C96E089272F27ADD2EE9BE7780E62A
+:107A80008D360F584861F85E5FD36F4AB31272802B
+:107A9000DC8FB6DA4378FF2CA90CC69D8CF13CAC88
+:107AA0001C5E8B7A56F66B813CE6A371CFE8BD3F36
+:107AB0003A5211BEA6F7347D796B22D747B7DEA5BF
+:107AC000523CD0AD6AAB0DFDA9595EF7240C4D9325
+:107AD000A4BAE95E4AFF323E0FE3737E9918B603FB
+:107AE00060928FFCDAB820DA7BA60C94A714A497D6
+:107AF000EF4307A4C30F753C8BE682C7C6FAF0FBC1
+:107B000053424F08BB669A58EFC6BD67E0EF284363
+:107B100097B3C8F7457A3D0172FF27FCFD9EFBDF56
+:107B200053294E68583F944EA3F58919871E403952
+:107B30009BF022E3C751423FB8E01FD2E792977C07
+:107B4000EB118DEFAA17F4FC66216B388F3FCD3611
+:107B5000EA10CCB7C875D629D67BA1476E2A1EB8C5
+:107B60001EE797264717DCE231FA22E8A86F1FF6D6
+:107B7000532AD6F077770EEA91978C783FACBD0008
+:107B8000F80D747912E70BD03BF193E095C8F72D0F
+:107B9000CD57D850BE6F0D4D72CD803689D622623A
+:107BA0005E22F3923F270FA8837122D69350C07EA6
+:107BB0005D2DCA72A6E03DAE42C9DFA3FD2E1E0CAC
+:107BC00094F812E603C871E43D564D3EF5F2A8C99B
+:107BD000EF7ADC60E1F91D7ACC21352A0DC4200B47
+:107BE000DBEA423DABD997EBC3F65C22ED33560B93
+:107BF000BB68BD7D9A95D4C0FE645ACF57E3FA04A2
+:107C0000E35F9DC2681E68E3D0CB63D5E706168CA0
+:107C1000D81F54A91D748FAFEA73330BF6C171FBE3
+:107C200026E1B835BA8C1474D1D321DB29F69B82B6
+:107C30001EB1F1CC77E1FDD944AB976D243C27D13F
+:107C40003DE786509E15D7DBDB7478F602BF39D14D
+:107C5000F053ED31F013F1DB2630DFEF5A415EF3E4
+:107C60006FAACBE0EB057B353D827FFA7933B6A96D
+:107C7000FA803962BE687E5DFD3C19D1CCAE41BA56
+:107C80008F0BA90CCF5F7B9A2F9F88F156C5737A13
+:107C9000B5CFE9188CF2B943F5553BC9BE683560DC
+:107CA000DCDFF6A719CD67CFFE934E8A6FD4D2BB27
+:107CB000FBE99A1DA5D94FFA7A9AFDA4E95DED7EFC
+:107CC000F876A7CF8FFD2B4D209F30FEF52EBE2FCF
+:107CD000DAEBF0ADC3EFF130063C4A62B9A12CFEFD
+:107CE000FE5596FF58F21EAF93E706A013FD4E1601
+:107CF000E8FF414A773CB4FEA73813F9790BCC660C
+:107D0000D443FDF219EFAC92D1FDC97EC3990FD7D0
+:107D1000A77E79FCDE5F50ACDBDB84BED5D2BD8EA6
+:107D2000A2FB117F93CA0296BCEF8E37A28AF7B1ED
+:107D3000B73BBDF7A1FC590BBD348E4C17F3A0FD2A
+:107D400099A93628F86E3269A55BE1F7B059D73B9F
+:107D500026809739C35D80729289FB68ACDF1C3D39
+:107D60008ED6134E9364677A58384ED513D82FD8D1
+:107D70009907CD80779F195ADC2BEDDCC6A3209D97
+:107D8000DA1C7308E9B64F156E8F27727AE9F7038C
+:107D90004878C44F15F9DBCC4CB525B1AEDFE134E2
+:107DA00058C98E8F679E06D44B2F3BB3C5B9A8A781
+:107DB00006F3FFAE7658138776C9F19D13677954A1
+:107DC000A8E2BCB47338EE99409E0F23BE6D133BFE
+:107DD00007DF4AC4E818C0E5C66B94E2E268F46FB6
+:107DE0003249F4B7E13E3B520F3ACCB48F6C53E2C8
+:107DF0003C38CFDA962B1C4FC52AE206A9F2FE5F6B
+:107E0000E8234DBF763AB308FF7816A07D00B37A19
+:107E1000AC748F5DE08F7115C9AFB3373EB81DCF1D
+:107E2000A3747114F57116272FB6D3BD8B2D7B6DFE
+:107E3000B42FED2CE2E7F39DCD16D2BFB1E6691A5F
+:107E40002A83F3C40B04BA7520DDD24CD589A8F778
+:107E5000D2E6F3F9AFA7473B0E14F73B7F3005A3FB
+:107E6000BD57D7D2F4F4BEC56897A567A453AA7DC1
+:107E7000AFB3AB51EF611B1314294EDF10E851EC87
+:107E8000738C09F0FD9CEF8FAF7959D7BDF6BA38E6
+:107E90004EBF4EDFF8848751AE40E0E8F704B4737C
+:107EA0004DB19FD7E22769FD6CF15B8B31E467DD53
+:107EB000A2E9365C075298F7CA793829B798D84EA4
+:107EC0006A972BDD77BDD73FB218DF276726F07B97
+:107ED000B49F6C994AEF9953D93ADB60A0436991FA
+:107EE000C183FE80738BDE741A407E1665B6E4A3F0
+:107EF0009C26987C990963C87545FB8D6525E660CD
+:107F000008E8955C070A81E818B892E8B8D010D55F
+:107F10003F9C9DC0F79D6F89F5243D7D40F19251B6
+:107F200091F97E44574D8E60FE642C19DD150F13B8
+:107F3000F87951429479D06E624DF85E42D347C9C8
+:107F400042CC347DA8C97132CE0FB4E38A403F4998
+:107F5000E77D5035B5EBF70C95E617BE403BD6797B
+:107F6000E924D237306F6B48CE73B9FEB4A13E8B93
+:107F7000F05BB5EF7DBD3FBE637AFB671F3BF05DF5
+:107F8000CB5FD40E07EAAFD3B7FCC98171C0DEBEA8
+:107F900085EF936FD4D9FF5709F90826144D41BADC
+:107FA0002EF0FF3D3FD25E636BB8FF7979507EBF04
+:107FB0008AF7BF23FD80150DFAFB00011EA74CFCBC
+:107FC0003EA79E0FEB041F96EFDA66CE7463FFBEEA
+:107FD00039D8FF69B1BF39DDE8A0F7141A3E8B76B6
+:107FE0008D34A3CDFF97668B78A7D762E27AD93B11
+:107FF00003DFE7F804DDF4781EDC174FF096DEC3EC
+:10800000DFAF2E84BED6805EF435F3384AFA712C89
+:108010007DDB3D0DFDE84B3729B48FC3FAB7C03A7D
+:10802000E15BB391DEF1E8C7B93020FB73F4F11ADC
+:10803000B5FDC032C1FF25F86BBC3951E23836F3CB
+:10804000F774CB74F645E7A19C781CFF9A0461672E
+:10805000E7B34B306EE79E43D909D1E26168E95935
+:1080600071DE8FF7FA313DED67944E4970F3785D1C
+:10807000CD476E46B9AA6CDA4DF111F705DFEB3347
+:108080001EAA14347F6144A12A10F6D87C618FEDBA
+:10809000615C6EC08EDE8CF27FF9E73A3B5A8CF35E
+:1080A000064DEE0F2591DCDC80E31A8EDFD54FA262
+:1080B0008DEBEE04F9FD576FC7A58D471B9F565EEC
+:1080C00021DE9FEBDB69723E45C8DD921DC51BFAC0
+:1080D0000229D6EF7D7F8088234771B63439D2CB11
+:1080E000C932C1B7B03C34DF41E3D2F806F29E2E6C
+:1080F000DE25A5A33FA327B9D0F3BFCDD43A00E72F
+:10810000AB9EFF6D31CE7DB627F0738D256EEF34BB
+:10811000F4AF8079B8C115613F9C566B0FFE14E730
+:10812000D10E2EC791EB22194B2F9A689D5DE570F9
+:10813000A725DA05DFC6E1FB454B00EB69FD9CF2A4
+:10814000D7CC1A48E78DB5B3060EA4771B946AE521
+:10815000A5F77FEC44FBB43D97917FA1CD21E37B54
+:1081600004179B319872FAAF545BBE7E0B75D08EAC
+:10817000168ADF7AEA2BE19FF8CA52186D9C6713C2
+:10818000B81DA8DD3FB951CCA31B9BF97BBB455B58
+:108190008BCDE4075823DFD77849714DCB84A6BE39
+:1081A000869166E4B39E1F4B3D57D03BF06E7C61D9
+:1081B000B7135F97EADFB5897B4C0B847CCC74B92D
+:1081C000859DE6A377C44BEA8C64DF2F7357D3FEFB
+:1081D00066851AFD3DD61897E1BCE3D18F6361A394
+:1081E000427A4F8FFFB21D6B37F465387E3EBEEE8C
+:1081F000E308F5233D23C6C95A2FE7EF32C5BAFD80
+:108200005FB8D1C6A4008000000000001F8B0800EA
+:1082100000000000000BB57C0D7854D5B5E83E7326
+:10822000CEFC24334926FF21413C21111212E29059
+:1082300084000171F24BC4080301826075405184CF
+:1082400090207A5BEFABB79990682DFA7AA358CB60
+:108250006DEDFD062BAD0A4880A08126E9041403CC
+:10826000040D820A96D68014B1053280B5587D8FF0
+:10827000B7D6DAFB64664E92426F5F87D69D7DCE9D
+:108280003EFBACBDFED7DA6B9F65ECD94B720E633B
+:108290000FB7CB8CE53356FBACEC65A98C2D63CACC
+:1082A000E9BE0C46BF6BA9F85F67E59204C6EEC550
+:1082B0003F5568DB57553278AE5CAE9985CFF56F88
+:1082C00090995982EB1EEF53C971D036498E4618EA
+:1082D000C71E379EEEB33066817FD746D33C8C25D0
+:1082E000E0FCFCD723B1A75260FEB38AFFBD08783B
+:1082F000EE2CC0E181799678F873F47EF8FF32C7EE
+:108300008C2F2478DFFDEDF229730E5E5D6D32C097
+:10831000F8A52F496C1D8CBFFF69DD78B12EFD3AA1
+:108320001EDAF0A3B9E91981710F7B9F0BE9C3DA5B
+:108330005456C0D87D023EF6EA7F05EE73F84DAE86
+:1083400008C632ED117167B3A05BC0265D4B63AC0C
+:10835000CE1A99C3A2A03533C2233B64F46E02B88F
+:10836000D644C08201CE355BA3BD1EC4E3EA68C615
+:1083700046C0B8F68D26B70DE6C4DFED8C9DAB6F19
+:108380009E9B9E0EEBAF7F7A6EBAC2D82CBB9DB17E
+:1083900089408FB6E7685CB7E29A6487FE2A4BDFB4
+:1083A0008FEF5683F03899D363995C696286C07CFD
+:1083B000FA7659B3F1CBBEA0751621FC56F86312BC
+:1083C000C02FFF3DF8D5C4685B006EFDBC7FAADFFF
+:1083D0001002F74A85395B6C81F568E326DA0DB443
+:1083E0001EFDF37A7A30E6A5717ABAAC443A04D12C
+:1083F00017E15400AF3D1D56EF5A89F888E0F67436
+:108400008411DC1793D6CD3D93C7D8617C00E0AED4
+:108410001DF132F55F515C6E7B3C5EF48F728DC74F
+:108420006762199B323CDE6046C6607C2ECE0FE34D
+:10843000768539F3988CD75DB1C807D31BFAAA2C7F
+:1084400040AA3AFBA40A05DE33FDB9BEAA30E83FD4
+:10845000629FCCFB9BFA8E5A1C8C35B02915A5F077
+:10846000FC63700FE7BB5E9B6F762D66C05735804F
+:10847000534B0CB4C7C6BC8DF256D35B5921454251
+:10848000CB984FCA057E7046FAAC39D4678530AEBA
+:1084900033CAFD1FB8BE55579B2EC938EE98C2E5AA
+:1084A000A53B8EF0A000EC61F05C53B853B503BE61
+:1084B0009A622C8EC654BAEE098BC1BE535583AE58
+:1084C0006BF4C0E7108E2603734643DB75604C5493
+:1084D0005FF6F078EBAA57AB14A0FFBEFA0C6AF572
+:1084E000F78B4CF674073C5F6460EE16DBE0FBAF85
+:1084F00022BF109DD414A4736DB789E41C7F12F0C1
+:10850000FD2AA1876A81405100CFAA63CC171E893A
+:10851000E3CABF50B06D95D8E910BE6281BE3C3C45
+:10852000DC37DAD6E27C4A309F703C152BA9554ADD
+:10853000D07B4B6D99217D39D19081EB6172B8630D
+:1085400013E0574E31ACDE01EB976F8616F0A1D8E1
+:108550001DF212689B4BA6CB4BA16D34B2852DD872
+:108560001AD8F2603C750879D2DA4B76D76F90EE64
+:1085700017DEEF2DB0929E1A6927F916EB6D941C49
+:108580003ED4439E2EE6D804D79A6417E37CDCC21F
+:10859000908F7F2FE671980D3B55E0D7F7EC0F12C7
+:1085A000FF3AA20C8FA642FFA3E615150AF0AF23EF
+:1085B000C570251578F478F34ADECF325C190DFDCD
+:1085C0004F9A6B787F2A4C99CCD8C9E655159E6C8A
+:1085D0009C97EB31B6C59985EF510C12C9A9B2D75A
+:1085E000E46D843F9B22393F3519812F6370BC4A6B
+:1085F000E39F6A28DE6C05FE578A9DEA6A1BC73531
+:10860000F2C3FFB4D5F0285B0DAB118FD822BECFDB
+:1086100088756B7460ADCEAC39A8175A9C5973231A
+:1086200010AFEECF11AF793DBDD3510FB77EF049FA
+:10863000813B9BD30BE7C9EB612C12D673E1AD9B59
+:1086400036CA52803E97EC45E7515F4BA0A61F8784
+:108650007549AA9DDD0372D7E864AA09D695C85E5C
+:10866000B2A3FD30207D4005B532AE5F3AA35C5F1A
+:10867000E2736CA48FEC4CB5DDF515BE5FD3CFACC7
+:108680003766483DACD757A69CC765067C1093D289
+:10869000767C29EAF3DF9A1DB7A8088F933D0E7008
+:1086A0006C333085C5107B642870DFCAC21DEB5067
+:1086B000DE1D2CC903F2856823E0E01707F6D028F9
+:1086C00064485B073C5FCAA09D8470DD4AEB9291D1
+:1086D0009F2630978C7AAB8079ADD8F677BC95849D
+:1086E000F87A3E8CDDE782D6F22A737A83F4467EEE
+:1086F000B444F89F1563A436DCD83217F934FC1261
+:10870000B3A31FD0FF0B9382F38360DC89D71DFBDB
+:108710000D0CE1FCB5D16B8F82BE3F53515F66817A
+:10872000F9FA059DB5799F37A999D1D0AF8A9108FB
+:108730002FBF2EE2F6D8FF85C9FB722AE2C7B2DA54
+:108740001B2457E3A3F9B8BAB8E2B1D1F07C4B4788
+:1087500038C3F74FEA0C3720FE376FC90D433ED8B8
+:1087600086B881F5C798ED8FE07C315700DE54BAAA
+:10877000EE24BC2AEA8428C06BE14C9BBA0EF0FEC2
+:10878000EBB09699C8F7FEAD06F632BC629BC931D4
+:1087900007FBDB2EAB76D4B3BF4E6D09A7F56C3566
+:1087A000D07AB685FBC7AD01B8D7652815089F629A
+:1087B000650AEA5FC550AC3E02D7A74573FDA8E93C
+:1087C000E39A6895FACF4BF0FE5C1C57447253262F
+:1087D000DB48DEFAFDCC6B86F7C4CFEB95911EE14A
+:1087E00073809590DF159FCC703E17121A5A9BD15B
+:1087F000AB929E75DA9600DDA70B3D3BFD644D25DF
+:108800008BC48EE3D854986F9FCDC8705DB7B13ECE
+:10881000D902FDDBAE32870FF9E7AA427E981DFE32
+:1088200005FB7B65629E5F494C898271455FAA0AA0
+:10883000F257110BF5DBCA36947F81F6ADC4A2BBAB
+:108840008EFE5C24B64AE03ACCB3285AF861A3D82D
+:10885000A86BA4CF60D6046147555C7FF67FE1BA70
+:10886000FA2B4C0E5CFF769BF3E3A9A8077B8D6C7B
+:10887000131B5E8E7E550F1A7D0C08C7D570E68DD2
+:10888000253EB421FDC76D68F684C17AC7A5F3F90A
+:1088900091DF506F8CFD455C2CEAED8868AE4FB4DB
+:1088A00056E32FE4237B14E723FBAD01F9FB5E7451
+:1088B0002A8DD3E409F90BE7D963F42E760D6117FD
+:1088C000812FBF877CB9DDC62A90CF9F1961598857
+:1088D000F2A4BD67B7E07B7DFB54C39A2E23AEFBA9
+:1088E0002FA0FF01EED2E4ABA660FBDD15C7E12DA2
+:1088F00093BF25BFFA62BB44FE7C423BD7D7C17C05
+:10890000316268BE7801F17A3DBED0C7011A5FECD2
+:10891000B81E5F74FF637CF18B68E1DF0ECB17DF5D
+:1089200046E2FA1FEB2849647FC78F69137C30DC6D
+:10893000FD2956AED7F4D7DB053E779B9AEFCC41A5
+:10894000B9BFCBE040B906AAA7CC05FBB23B9C3F20
+:10895000C794D569D8DFAE703DB2BDDD4C7A64BB3B
+:10896000CDED267B9D6461E82730C5DDF77DD47FA2
+:10897000C916755D10DF3E2EF4408BD137E573F4D8
+:108980007F0F70FA4EBE2B5736C1B8110F70B9CE9B
+:108990003F67DA28C33CD53145BE6818DF17CDEDF7
+:1089A00062DD1918057C597BC644FAEDADCE23E58E
+:1089B0004E1BF9374EE4AF497B8E941767E378CEB0
+:1089C00047DDA2D5FA53704D3164768E25017E5D68
+:1089D000C24E4C615C0FB9903F72027DE634523C4E
+:1089E000A6F1413563596827E6F639CA908DAA2A5F
+:1089F00042E95BED9B4971DFFCE3CEB20858D77CBE
+:108A000097EEBEA07FB58EFEE007FF01E564D5E6D8
+:108A1000DE4E1BF2ADCAED698B697516F77B56A762
+:108A2000A1FFAFC911FD004F2DBFCF78795D901D1B
+:108A30005763F83A9F752874DFD367F2DE0297FE1A
+:108A400037E3CFB5087BF3AD90E3DCC7DE588CFC91
+:108A50009BB7DCB90FF1BF284EA6EBFFC97C96345B
+:108A6000A48F4321FFABC5A8967C2E05C631C595C2
+:108A70006183FB7BE2C3F3F0FDD531EE6B4827A6A3
+:108A8000F8BBF1B94985B9792857B6094DB1687F66
+:108A900034B801AE8A4DB6001C1A5CE785FEA98E7B
+:108AA00059720DF180CFA15E693B75D682CF6B7490
+:108AB0006FE9B8C4E91D447FA47780FED27DD8D782
+:108AC000F06011ADD6FFE7E9EF1B89F41896FE18A8
+:108AD000F747FE8FE83F2A6608FA833F958ED73521
+:108AE0007FAAC5047E7576A0AFD1BDDA5E44E31CD3
+:108AF000265819FA4F9D1057A21CBAA3D1B9613B51
+:108B0000EDFC5DFDBF3F3B0A5C4036292686CB93DA
+:108B1000C93F06FD8D093E89FCBE0920F0F7909FF4
+:108B20003592F49D43E0879D95A4B319DC05BF966B
+:108B300082FE9F2F16E56082B9D287FCBEC33A3D04
+:108B400005FDB75CEBB434E4A737331E3B8426E75E
+:108B5000CDE4E53B5F51037E8EA6D7F68969B5F774
+:108B600097C770FADF0E6A16FD3D740D83E1D0F4ED
+:108B7000379205E1907CD5866B56D2C7ED7D80AFEC
+:108B8000DB110EC06B97C45A517F17199C7125E8F1
+:108B90008FC5FB14EED77D3D4A05BEA96C7FF73823
+:108BA000C25B69B1F930DFC21CC6F37D41F912BD69
+:108BB0009FABF9259ADFAFF92D5A7C89FE0DDECFE8
+:108BC000C7EB00BFDD0C00A2FDF159BC0DF0FEE7C4
+:108BD0002FAB994E21AF0AACA352AC6336EB25B84C
+:108BE000D8B7D7AE4D03FACC12F8A8EC86B8300748
+:108BF000EF337617E0E12E85C78B7739203E0CE204
+:108C0000A3D99343FBF89B9E1098E77AE3F5FA7F8C
+:108C1000AAC817FCB371A6D676831D3A0D0C70B0A6
+:108C20009EC73485A3658F82F1803BD380FC582793
+:108C3000EC1A84C943DB2321AF8586BE1C07E0B74D
+:108C40006BCF3764FFF6EEF9E623F4E7A67CA1309C
+:108C5000333C5FF8457E14EA07E60A9DB7EE8FAD18
+:108C600056C6AF13FFD48AB5EFAFC78C18C267A141
+:108C7000F637E79F5F8FF37D7946E1BC2DDE5F6EAF
+:108C800072A7DB6DD8F2787FBFC4FD1DEDFE7E2399
+:108C9000C00DD737C568717FAF42F919F89983E8DD
+:108CA0007C17C6FBB901BADE75AEE20B2567307DD5
+:108CB000F0F7FF23DED7E2FCB744FCC0F69D30A9F5
+:108CC00000D78CD64714F4A36724C9CC19F4DE3B33
+:108CD000542B7306C5FB6FC4E8FC907DAFAD9F05B8
+:108CE00076A4AE477684A1BCB66F3F9483FD5ED96F
+:108CF000611D828FF4F89DD1FE8882FC9F10CBE528
+:108D0000E67AEF2F1C077C722BD29D911F77B14022
+:108D10002239D2D377EF9E9FC7F6650F8FEFE1E838
+:108D2000AFA7C36FCE1747215EAE470F3DDF76C2B8
+:108D30003A3DB03E1FACD303FED6DE7A3BF5DFAE44
+:108D40004FA2BEC6AF751DBF8C457F4DE3D3B25851
+:108D5000CE375376AF8F65B600BD347C5D1474ABEF
+:108D6000668EF9B3E0CF5D922382F48487F52615F1
+:108D700004EC55F5B172F233347B552D671B51FF6E
+:108D80006AF60AD3C2A8CFF4F6697E7A9111D5AA01
+:108D9000DE2EC1028DC8BFD50B43AF57F4342B1163
+:108DA000D433109D2449E043F8D51A3C1F3217C133
+:108DB000ABA7A7069F1E2ECD9FAE1674837596E1B6
+:108DC000D2E7AA45B48E417655ACF746EDA93936BF
+:108DD00034CEBA72AEF4FD9C21F87538BED5DFD71B
+:108DE000F44039BE20975A0FFA1109B10944AFF285
+:108DF000AB26E6047BC14686B1CF82F3EFAF649227
+:108E0000BD7B54D8DFE1F8A6F6AA81B96303FC6301
+:108E10006C7BCE8AFCB35B69B662DEF136DB9CC646
+:108E200028C053E91F8BE7A15F57D76760989A2A3C
+:108E30006BBFB40FE3F6BAE3CC81FAB0B8BDAB04B4
+:108E4000F9ED6DA557A638FA4BC69E0BF20FDBDA8B
+:108E50001BADE83FB5C5C914A7EF8FE6FCA8DD6FD1
+:108E600089E5FCD776E6F22CE710F73F13F74B4F76
+:108E7000E51AD148F6C74750BEA1FC6903ADBF54FF
+:108E8000B25755A2FF718791FC7A885BFEF07DCCCA
+:108E900037B599B763AABEACED878FD881102DFF87
+:108EA000E7B30633E60FE6488E97615CB9EAEFC296
+:108EB0007EF9BC54DA8799F47F65F25FFD774B94B5
+:108EC000F7280776C17EF93DA95ECC3FEC9178DFAB
+:108ED000D3C1F3FECCEE899D05EFF9A03276C23AFC
+:108EE000E229AD7F4BEE3A261838289E7A6C17DFC0
+:108EF0003F7AAC4CA2FDA3327B0AF304F155F9D3BF
+:108F000040CF3CE0C7F6C462E4DFAA0A997983F84F
+:108F10007ABECBCABC41E3F7877178FC92D98BF952
+:108F2000124D5E670AFEAE5E181B327E0EE37EE2D5
+:108F300042D66C44F9AE13F0D415013CF0FC4C1150
+:108F4000A7DEED4E09796F256641606856DC68B290
+:108F50008FB3BFEC23B33A473E796C31BC87657061
+:108F6000F9D0E4AC4CAE69223E48921C181FCF9752
+:108F7000C0AB9451DF85CAD1ECC9A1FD394EBD7E8D
+:108F8000089577BD1ED7E47C7E876CC4387A7E91C5
+:108F9000E46043E803BD3FADD703930C8E7730AE5A
+:108FA0009E7BD549FC35480F9CACF887F4C05B200C
+:108FB0005B93415E7FA4E9839BD84DA80FCAE42D43
+:108FC000EB913FFAC1AE9987E00FCD2E68F176396B
+:108FD000C827F2033BCFF725CAAE829CC606E2ED56
+:108FE00001FD007E8363087FE657B16921FB4903D9
+:108FF000FA22C86F3016FCF37E4319F88BA65C8406
+:109000006F24F3E4919EA2FC1EB43ECAB3255DA278
+:109010003C4A1DC4F114CFB35F125CA8D7A49800DA
+:10902000DFEBFD092D4F3B42E409F4FC3090B79B88
+:1090300067F4229F69FC506EE772513E4FA6FCB95F
+:109040009E3FB4F75D8F2F7C12F085F477F842C80D
+:10905000D38DF2C5218D1FD259FA8DF083C6071A20
+:109060005FE8EDC5415DDE65387B71F23AF6E29D61
+:109070000C23E965BD9DD0ECC28138AE7FC7C7F235
+:109080007D8A9999F36DE8578C407D80FE9EB037BC
+:109090000379A30D9C0FDEE95BAA486837500FA443
+:1090A00006E15DE44D35BEAB7D9A51FEB052E89FBE
+:1090B0008B1D3C9F56572A7B2DF06749FB73EB793C
+:1090C000DF48F9B622A54BB1C0BCB31D9203F335FE
+:1090D0004E917F9B75D5E455293F3FF47E7A95E00C
+:1090E0001B8C7370FC6CA7E4851074901EAABACA1E
+:1090F000EDBE5E1F5589FDF22ADD7EB9294ED0F501
+:109100006676F3BFD2EEC7C72570B919868EDAF33B
+:109110001A1D35FA4DC0B1283FFBBE36A911DC3F00
+:1091200046FACDB8AAD03CA3E242FD962FCFE7FE87
+:1091300027C574627C5DFB25937BFCF0F05FCF2F2D
+:10914000BD59F3C3855FAEBD7726C8780A3A863A23
+:10915000FBA1BDE7BAF6423CAFA7D3E4B8D0784252
+:10916000A387A64707E15BE8D9E1E8753D3DABE998
+:10917000B37FB59ED5E6D7EC80F65EBDFE1D2E3ED4
+:10918000D3F4E9531B0D9417B94DC4C1B7893CEB17
+:109190008342CE970B7DDBFF178B01FDAC6D9DDC11
+:1091A0001F7198ED87D06F08E4F3385D9F8C601EC7
+:1091B000DC2F674AAF85F62F8B81A4B87F99CCF757
+:1091C0002FB7283E17E96987C21A405EFE2AF216B9
+:1091D0004FEEF52C463DFDE4E93106DA47577CBDFC
+:1091E00018174FCA55683F28DAAC52BEF76287D9C4
+:1091F0008ECFF5EFFE5E9711E7F90B7360A8F67658
+:109200008779603F06F54299DC23635EBEDF0FBEBF
+:10921000388C9FB6D05782F1CE6DACB711E3EA42DD
+:10922000A4E310F47B55675FF479FB920EEE27956B
+:1092300044F0BA9FE980467CEFF43613F985D7CB2A
+:10924000DB177DC9C85F1A94AF6FE37A0606119FDA
+:10925000DC68DEBE107D3DE0E39FE8F40E1B267F58
+:10926000BFCDC4F773FC478C0CFD5E762E6EC8BC78
+:10927000CBF5F2F8BB3BC39D6A24EEBB71FF7C7754
+:1092800067B253CD197E7C4E9FBF18F395DBB6CCE9
+:1092900055284E14F9CF41FB223AFCED9058931516
+:1092A000F369ED8E528C3F86DBE728F63B69DE1BC7
+:1092B000C51B63CD9CCEA27EE9762163DBCE863BC7
+:1092C00091BFB79D4D76223CBB057F6AFCBEFBCCAF
+:1092D000E570DACF343955DC07F6475B1C2F13BF36
+:1092E000723E6F1931C68BFBADDB853C6C0BF71FF3
+:1092F000CC8A0BDECFE0FB179DF59EAA33E9B4DFE5
+:109300002D61BE51DB27F680BC505D4E0C237E32B2
+:10931000B21686EF6D74B29F633B7D9A1A85F8BED4
+:109320001CA7ED47AA519467F8F64A816BFC60BC14
+:10933000EFA877513D496BFDC22A05607CB3DE4D35
+:109340006D5BFD726AF7D4AFA6FB6B0F453E8E7660
+:10935000BFCEB9A04A09D21B9FC5F3FC526ED6E915
+:1093600012E473F60D6318EF4C7FA24F463D71FB7C
+:1093700055584748DD887219F14CF9CBB4403F5538
+:109380005A12867C79FB55E8078D97E2A3391D9A1E
+:1093900094A65B0A485A881FC2E29D17E3E0FA0FC1
+:1093A000ED2E7F5C3CF241F5BE0B8CFA97F1FA0E84
+:1093B000E96EF9028CCBF31551DE380FF3C6B934E0
+:1093C000ED62C4DFC42E13ED7B6BF9DB5C31AFF3D0
+:1093D000ABD03C729EC8DBBEC9FA289F9C6F81C08F
+:1093E000CA807071FA39A5F94912E6FBE24D0EAC5C
+:1093F000579898E6CAC37C6B573CA3FC695757C281
+:109400004815F0E054785ED7A9E575D9DFCFEB7643
+:109410007F1AE9217D057E0AEAA7EEA3910E1FEDD2
+:10942000FF59C8FFDB810F627D4338AF1760F3E659
+:10943000511EFD760B5F07D89FF878CAFBF9F61D21
+:1094400086E77E7B99F17DC4DE93B43F5D62C84CB4
+:10945000EC0338F74963A3B07DF1D3C86C6A8F463B
+:109460009E47FC741AAC2ABEF7C37A56857567CE40
+:10947000F76DB49F31FD7D9B82EDE1FA3EAA477BFB
+:10948000BFFE1CB547EAFDD41EADBF4AED3B701DC3
+:10949000F9E7103C8F6DEEE2087A6EC7A20813C29E
+:1094A000DB19C9B668EFC17A335FB8AF1593F9EF2E
+:1094B000C57FBECE7213D83BB37BBC3481B113F1F0
+:1094C0009FCF54A07F68C6A87FFF0BDCFFDD4F2E27
+:1094D000ACB3005CF38EDA5A7BA0FFE94F2EAEB33B
+:1094E000A19E3D140ECA0EF546FF41907496873634
+:1094F0003D9971053B19FAB1A2EFE99F590A245F22
+:1095000050D297C580B5A6FCC43FD302785C607585
+:10951000FF1BF64D9E976696DE847DE6C17A2EBFD0
+:1095200064A4F89E8D94E2B07E6599DD7D2C3EC8E2
+:109530007E3BA53FD2FE51815362D1714457DACFB1
+:1095400062F653B1C1F2B6CC5E760CE971473CDFEE
+:10955000BF9A384D7206D749E8C74D3CA396229D65
+:109560000ACE9537613BBB229AFAAE85939A509EFC
+:109570004B6DC33D5F42CF2F8837127F162B524869
+:109580007D887E5C1E3013FAC7FE03E1941798783D
+:10959000CCDD8875A36549A9B9B2D0798CFAD11B05
+:1095A000711F6D62E587A5B1283F36C981E6A180AC
+:1095B000F535C5C661FD231644E1BA9E2BC1FA9D5F
+:1095C00089AAE440B41539BB5AF1F9224784A308AB
+:1095D000FDF1636A299A9CA3CA84C3F9306E46BA26
+:1095E000ECB0C044477D774CBD00FDA28C28CAE397
+:1095F0001629ABAF1CA67E84A341C5756CFC792DE2
+:10960000CD63267BBE6356C97F20FF14BBA228E72B
+:10961000576A3B3537B82E0CD64D7017D9656F9801
+:1096200084FCFD83523BF4778C9218CACF515FE6DD
+:109630009FE97E77B81A0680EE30D94B71BE1D26A1
+:10964000C9BE96FAAE121CEF196354314F541EF77F
+:1096500045C8FC334AA5296710FEECA80978AD621D
+:10966000E4A590FB3D8BAC64272ADFCF267FA8675B
+:10967000510AD98BCAF7A71563DB63E07E7AE5FB55
+:10968000951574DFC0E3DFCAC5DF718A3EC5BB959F
+:109690008B5751BF4B4AFC777CDF95ECA85CCCA381
+:1096A000CD4CFF7AAE12ECFFADCE24F9CF1579BCCC
+:1096B0002243E6FA6900FFA307F83E4465B6145258
+:1096C00037372BFF54483DA86BDA1721FDB9A59712
+:1096D00042EA43E7557E1DD25F304FAA0A1E5F7AE9
+:1096E000209FEC6BBEA85FD2F24B458285DEA9CFEE
+:1096F000A82A05B93C00ED03A01F8A7A45DE55E192
+:10970000717506FC433D586AD3E577994AFBD91534
+:10971000DD7CDFBA3CCE783AD83E54C84F707F41EA
+:10972000B7FEDC0346B293B9D132E5AB34F82A4632
+:10973000863EAFF95F1502CE1D0677530CE5C79C38
+:10974000BDE87F68F06BEFD7E0AE90EF29A5EDBFE5
+:10975000EBC0AF87170025FF4D0FC78178118780B9
+:10976000BF41FE5937AF4B835FDC50765BF3CF2BA5
+:10977000414F4507EB299B1487F576C3E9296DDE38
+:10978000E1FC306DDE6576173DEFDCFAD9D1423968
+:10979000A89F7A2A3626B8FFDA67EB43EEC79FAA5E
+:1097A0008A0EEE6FFAAC0AEF4F57D4461BF0E34136
+:1097B00026393CC89F3DAA82FBCF25C79C4DD89631
+:1097C0009D746399299B71C6D384EDD4F3DE1E3357
+:1097D000ACEB8E0C59C5B85DF33FF4F09A13781CCE
+:1097E00072F0AA6AC5FDD31D1ED58AFEFB8E2754D2
+:1097F0002BFA1F3B9CAC02E331679A6135FAF3CE3A
+:109800002C5E677855E8E16FE2F9F35A7B5A717F75
+:10981000837A11EBC2D127A8FDDA4F75E007D1AFEB
+:10982000CA1EEC571D54BC367CDFC127BCB6E07D98
+:10983000C21BF5ABFE8C363A1EF96C4E887C9658EE
+:10984000EEAE0A96EF32FB9290FB9FC6A904FF8C06
+:10985000A48743C6DDA13E12D2077F3103FD9146A6
+:1098600013A33A598F81D7C9EAF1F8A8C0A3C366F8
+:1098700047378619E354AA6BD38F739470FCE9AF12
+:10988000A727F0B86823C80CB6F72470F8F475B1B0
+:10989000FA3EC47C0B713E983909F9DC61355C01F4
+:1098A0005797391392EEA47AD93CC3A369D0AF4E2F
+:1098B000C8E2FDA9869D581F7B774236EFDF6AC854
+:1098C00033821FF02B36FE4EAC07AF0D13759D0F84
+:1098D00024D27E9816DF2886532F2EC638738F9198
+:1098E00061FEFE1913D8BDDCC0BEB9D5CCE352ABC6
+:1098F00089D76D3F957AF429D41B6A987B7A02F94F
+:1099000051C52AE2EFBCDD42759D8FED2E4B44FA26
+:10991000DF93C0F35C593BA726A17EF917BC7F56A5
+:10992000C2C4E1DF8F75BE38CFF91D59E47F67DD12
+:109930000CE89502F887F098AE87419840E72598A3
+:109940003309F36C8DD1269AE79E04CE7F37DA0E69
+:10995000AAFB8D32ACDE0EEDFD82FE0FE07B095FCF
+:10996000FE51737063CEEE1F35773CEF237D653972
+:10997000D78F7EACFF3B11B4AFC246FA69FFE5E377
+:109980007BB21CE89F7E12CEF1B7D03BBAB14FC577
+:10999000FA0DEF4D582F9191E8AE453C2C327B6F7C
+:1099A00021FEB1AD8EC0F96FB41E78F07B2180042A
+:1099B000FA544FE1F4D1DE0B38B5A03DF8589C03C2
+:1099C000D1E080F7FF00F9408367000E5D5DB89637
+:1099D00067AEFBA381F20C7512E83DE8EF3CC91CB1
+:1099E0001E98E7A2E6AF8BBC266E45E17BA61C5E07
+:1099F0005A628336BF6D258F737B95903CD7A4E365
+:109A00008A7EBF83ECD654ED795D9E71AA886BA7E0
+:109A1000EAE2DA1713849D4966C9C1798035226E5E
+:109A2000B8DC333A0AFD4CD45132E0D5A4CA6C728A
+:109A30004C40CE5B21EE674171BFC667E38FD9EF23
+:109A400047B8C71F63F7915DD7E61DC82F70BC5C90
+:109A50003ECEF132A12FE3A7D3A06FEC3632AF1A7E
+:109A6000584F2107955DC6FFE078BBC98B75CB05C4
+:109A7000077E99E7834BE624035383F010A68633D1
+:109A800035482F5A336242FAB2866F61CFF3C4FC75
+:109A9000118EE49079F6C49477A37DCFB32D27FB84
+:109AA0001E357974C83CAC4709B1F3B028DABF9CC5
+:109AB0000840FD0CF05A704C09B1E793E23CB862E3
+:109AC00036F9A4A2B3FFCD32CA41E199D0EB0786A3
+:109AD000A3CB70F863393F45FFEE1FC55FB4331465
+:109AE0007FB115A1F88B7785E22F7161289E46B86A
+:109AF00043F192B27C5CC8FD9B56E786F46F7EBC56
+:109B000030647C2A18A4E07EDAD33343C6DFD23C2B
+:109B100037A43F76C3A290F199DEA521F7B35E5D2D
+:109B20007143F41EDFB226649C9EDEB7B6FDAF9093
+:109B300079357A7BE0DFBF82DEE6C4507AA70AFD82
+:109B40001AEDE4F565FD46DBD312E8234C13A15E64
+:109B50008B6E7FF76BCC43788A55AA9FF3CC64B4A5
+:109B60000FFD82EC92500FA5C0148634AA5FA7FAAD
+:109B7000BB1F1B0C21FBE28989DCBE2726F27CCDB2
+:109B8000CF4DFCDC520AF88F64870C2C102F031E7B
+:109B900022315EA678FAC7CF60BCDC14DD97A14203
+:109BA0007C6CC6FE4D017DB9C8AC36F6013E26C8B8
+:109BB0005C1F829E4C4B84F93F919E30723FC26382
+:109BC000443F22C5C23C91B9643F287F1CCDE224AA
+:109BD000ACC78F0AE869F51A106BDF8A2C3A07F5D3
+:109BE0001E4282FEAF2586ECE8DD9A7E5A9E49FA37
+:109BF000E9B22DD40FBBFC401A5D3F71AF99F6FB63
+:109C00004F883A446DFDE784DEFA53BD85DAF3F5FB
+:109C1000F6103DB67CE3FA08F41F4F64707F51BB29
+:109C20005E82789B88AD2CEC9AC58EF9AC7BC038EF
+:109C30004701BE5775F7452E62E43716E3BA6B3716
+:109C40005EB9F74DE8D719FC09DC3E7878BDCCC782
+:109C50008CFCCFEA6F5888FF343791C7E973C5FC95
+:109C60000BA0B1039E1600FEA3B17D775A39F227EF
+:109C70005CA7F369B3BB19D59FCC71A7D23EE35162
+:109C8000E6F8701780F89D4495E09CC75CB45FFFD0
+:109C9000D1BDAB2270DCC07CDA3CC028E86F7C1CF4
+:109CA000ED312660DC7F1BAF6F80F759F0BAEB9E79
+:109CB0009427D10E69EFFB88B92F7C88FBDDCC415E
+:109CC000F36AF3331613A29F762C5FF9692CBC6FED
+:109CD000CD0103E513D6749829EEEA5FF1D7AD2FD5
+:109CE000C2FDFB52FA6E42BBFCC98A6FC6203FDC44
+:109CF000BD01F410ACB130CAFD7062509C72E281BB
+:109D00002B11781FECEBA617D1386E36537DEF2759
+:109D10002B368F09F6471F4D2CAAC5E7D8E41B3B0D
+:109D20006F58F27A6622D563097E7A58F0D39AD7B3
+:109D3000C6921FB52662809F787F13AFEFD0D6F111
+:109D4000A1E0C715AF7F5D107CCE7407F0913A8615
+:109D5000EF6BA920533B7B2EE7E0FD57147713C22E
+:109D6000D779F57424F677BEF737829FCDBB31786B
+:109D700051063D0581FD65EDDCE5C2F6D83CA43B0E
+:109D8000C85933CEBFE837AF5DF81DE2A763F3A62D
+:109D9000EFE3981B3C7FC9847D71083C807DA1F86E
+:109DA000A09F85F3731D428F2AB8839E86E7991C76
+:109DB0002AF1B3931DC27D97C62E03C3BA9548DC22
+:109DC000B409CAB345CA06CD08392D49A09F855E9E
+:109DD0007925F1E49D4DE4E787FA3DF96FAF08F18D
+:109DE000775CF08FFC9D97DC8D9807BAAEDFE3338C
+:109DF0002C3145DDB8FF0381B0532A105B38F06B7E
+:109E00004B14FB22420F77A21C61FD3FCE85F97AED
+:109E10005F383F670CA602F5F80F604DF8B0294592
+:109E2000B4D2C50C0BE8C5BD897F78E669D093969E
+:109E300074BE5EEC37E2DFDD9CDF06FCABB7C7919A
+:109E40009E62DFC2DB100F225FA1A7533EC8078BC3
+:109E50000D9233F1BC6FFFDF22314FBB35467D1FC2
+:109E6000E9E03F20D33E4D98D2678A1E222E7B1315
+:109E7000F59E89FB4D546FDEC6F38116D5C9300EB1
+:109E800008B3DB27049FB36B17FA6ED5FE4F4699D4
+:109E9000800E170C3D91D9307FCDAE1D91E8C6DF05
+:109EA0006B747F8A7CB7F2C40705763ACFB671141B
+:109EB0009D03F08DA6BA83F10AF328B983E1A8DBEC
+:109EC000904BC6B8760325E3D9F8F6BC87501FD56A
+:109ED000F9F83A716E2CFCCB6C63D4BFD8D61883DA
+:109EE000F3D5FDB62319E567733C8F135FBF3A8E38
+:109EF0003FAF3005C77F99182DF8D96BC03863B3D1
+:109F0000884F2E5E35D038EDFDE3DB8A643BF043AD
+:109F1000B6AF792FC543ED6615E91AF60AE37868FE
+:109F20000F2339AFEB9CC1309FDF1FCD1C12DCDF4C
+:109F30001AEEFF039D33EB30AB981F0DB337B31808
+:109F4000987FABD80FCD048EC2F34ADA75ED7D61F0
+:109F5000ED3FC55802F981F2B4614A33BBCD168C8E
+:109F6000E708C2733CF2533CBEC767C0FC88FF16CB
+:109F7000C65E26B80270327AAF066726F9735B4D6B
+:109F8000FEB3787E05E0B223FD33198793B58F5574
+:109F900031BE0FB33B691D6176D5E19106C355977C
+:109FA000C3BC68BF7FBC960DC82BCA6F5D78A06F1D
+:109FB0000119D83A9A09F9B63F5B3A2DB80F8A646D
+:109FC00072E0F9711B629E6D1A49718347C638169B
+:109FD000DA88185CA7CACF3B636A2897E301F7C504
+:109FE000AD167E7F603CF0B70DFB363ECE1165B7F7
+:109FF000CE94484E28AF572BE4FD31C977F67690C2
+:10A00000D3BFF8F6E6A8004BCDBB7B884F571ADAD2
+:10A010005F1C0FF7375ADCF94980CFB74E1AE81C9E
+:10A02000E99F5E0BF35662FCB87B63827308F9D03C
+:10A03000CFFFC3E36B9F4F41FAEF9654CC9BF61BC7
+:10A04000FDA310DEDAF6CF4D548FD0768AEA938ED8
+:10A0500024B99DF89EC96D0DB46F3C8535D3BE7192
+:10A0600096387FDD92C4F5C7E563635E6E08C2FF74
+:10A070008349DC0F637EF7CD2837ED423E3BD12F7D
+:10A08000817697F08F7675DD9DA606E5FD1AD8DE00
+:10A0900014C4F75AF636B5DAF57E2F3FCF98F5910E
+:10A0A000E53E6710FFB993B89FE716EFF327B9179E
+:10A0B00024A1DC769D3645AA785EA56514DA911652
+:10A0C000F09FEC43E065406E757254A7F84D38BEC2
+:10A0D000EE1C3F770A746EC2FAFFCD1FB58D5B028E
+:10A0E000D77701AEB1DED373C24C758FBB8CAE1483
+:10A0F0001CDFF0E15739A8B72A1069F0BFAF3A5614
+:10A10000DE8C7803BE2F0E47F9DACE488F69F299BC
+:10A110008DF209CF6723DFE7633F93F4F056532FA7
+:10A120003FF7B98B9FFB04BE273900BEB7A39F90B2
+:10A130006D0739A0E7C7927C6FED35D0F9540FE871
+:10A14000F15BA85F5C85FDADBDA576926FCCC3E7E2
+:10A15000A29CFAF6D23C2D108320E924E60AF61FD1
+:10A16000DB1323898F35FD783091EBFF960C350A90
+:10A17000EBFFADB21C2217417690F7859DECDD50C8
+:10A18000FCEC0BD3D0DE09BB20FC27769CEBF94717
+:10A1900085AD5AF34EE1EC2DB0CE3587E5817A6E70
+:10A1A000F4577D824FF60AFF15ED849AC7EB67F0EE
+:10A1B000FAC40DBCCEB5C0B9BA04CB38265734EFBB
+:10A1C000C3B6D0D55282678EA72DECDDC7CF1EF364
+:10A1D000F3E3AD7BEFC8C27DEAFE136686FB24ADD8
+:10A1E0007FF3FFE175C0C3773B01FF43D825580ECD
+:10A1F000F11F58EA149634F87EBFA4E98FF9952828
+:10A200006F175BE5401FEC612D3038F67F9D54F5EC
+:10A21000AC07004B1BE17C1D59A230D94D6DFF915D
+:10A22000BF25A02DD8758CFB4DAD266716F24FEBE0
+:10A23000E8D0F3FA5AFB62123FE79C6F6643E625CB
+:10A240000F09BB37C6C39E413EAA6D95ED5EA0FBCC
+:10A250008556D96902FFE6ACD39D806765CE31CFC4
+:10A2600082A968E745DCA87D4F6519FA2760A71E1B
+:10A270007C61501EDF807CF450BBC47E066B5EFEAA
+:10A28000D2D0FB0A35629E87DB36EE4F013AAE78BC
+:10A2900025745C8DA813ABD1F92F8792447C98C6A6
+:10A2A000D2D02F01FE21BD605458B719F8F5C16412
+:10A2B0007707C61B9BC5770C407F921C7608BEDCD7
+:10A2C0002AEA04FC5B25DAD7CB7CD52B1BE0F942CC
+:10A2D000C52BA39D62D0E23EC164A7BB1CF10BEB72
+:10A2E0003E86FB35CB851E5CAEF9655EBE9F01E602
+:10A2F00096FCB229CCDB1889EB7E5572F854FC8EA3
+:10A30000C8A03A5C5A779D5877CD8623FB318C5B89
+:10A31000D5123AAE4EACBB4EB76E6D5FFBCF49BAAD
+:10A3200073C837B86FF16723F7133E10F368F7CDA2
+:10A3300023B83EAC05F0906E355ED9EBE57E9D0D01
+:10A34000BFC373BF80F77E41EF3AE633A5C0B8556F
+:10A350002FF075B26743EB3F1F6C7DC484F1959E6F
+:10A360002F966F31923F0A8833A1BFA8E78B156201
+:10A37000DD2B74EBAE754B3AB8B89F3C18AE960522
+:10A3800048D7555B8C0CEB11F5702D6B59528E7CB8
+:10A3900036985F395D5688F90270AEA6737C370A2D
+:10A3A000E7A811822FC7B17144978AD81BA28BDE10
+:10A3B0008FDDBE7F9C15E5FB72F7688ADF35BAEB4F
+:10A3C0009F2F177EF08C0D8CDA0B6D25D6F118A718
+:10A3D000F4181C924AF156E478C0475E87CC2AA153
+:10A3E000DFDF9EB6DE0378CF3D9C5F85F17CDE61CA
+:10A3F000039D77DBD99D4FFBC07907D263D3281F1C
+:10A40000EDA0EFCDC03C643FFB7B72D7E3B980FE8B
+:10A410009ED27C9C57827168E773851D68E8C9B538
+:10A42000069FEF2E18C1E3F5A7923EFB31FAE13308
+:10A43000B61BE97CC30CA3FF3DAC9FDAD9ADD0BEFF
+:10A4400075CDE1A56BC390AEAF49B46FBDBF774D7D
+:10A45000DC62E4AB76A31DF7A1FBDBFF6D2FDEF71B
+:10A460006C91E87B12751D65595BA19FBB31CF11C3
+:10A470007CDE2B375A25F8D8082BC5C3336E3292B1
+:10A480005D3C9F6CFD25FA372B9C1B498ECFEFD985
+:10A4900069A2FAB9AD1243D3BF3F69DF1B888FF3BE
+:10A4A0006F1E31A1935DD27AC4D4F777ECFD052FEE
+:10A4B00004FE1407379B304E59B551EBF799904E77
+:10A4C0002EE1FFD4BE728AFA2BDA24D2332B5E92AD
+:10A4D000E93CFBBE8EB74CC8C7B55B2496981A748E
+:10A4E0007F8314F21D84A58CF3C152A1675632EF0D
+:10A4F00053C9306E6533AF23604F87D6E5AEDC328B
+:10A5000087BEDBB4AC79687DF3B0E0EB87301EBC6E
+:10A5100015BF83143AEE61EDBB5C3A7E7E5CE3E7E7
+:10A520004C9689FCFC55911A950DD7BF3AB2E2E6DC
+:10A53000A1CEB1F7083BACD9C1CB3E03D911FDB8D0
+:10A540008B6D5708DEBA9ECB26B483E5ED9708EFF6
+:10A5500095ED5D54C7711773D7209EEE6AB7DA5137
+:10A560008E2BFBB85E9AD96EF67A25BCDFD284F4C6
+:10A57000ECEFE4758B9E3D12F92F9ABE7A48E0EF1E
+:10A580002181BF874041A7E4A21FCBE3DE8733369A
+:10A59000EE8F81FBB5E27ACD817D91E8EFCD6497B6
+:10A5A000EE457AC07B18BE87BD148AE73B1987E366
+:10A5B000CE2DBCDE596FAFFA4764CDA6FC23C49DF7
+:10A5C000084FCD96503CD7EAE2ED7523B87DDEA466
+:10A5D000C373A59F59B3110E5576786974AF82EF96
+:10A5E000EDCE9128BFDAADA6450DB5FFA8B5EF09B0
+:10A5F000BF59EBCF16E7AB5BECCDB6E038D894CCC7
+:10A60000EDFF8A29B207E934103FA4EFCB510D8149
+:10A61000F801E286DF8C88E771041674BC3B526651
+:10A62000717181F8E18749EB2B73A15FB785CBF995
+:10A63000C5C9301F7EDF4B61E45FD66D31D339C0B1
+:10A640003AA03BC509EDFC1C83AB5D2A437A83FF2E
+:10A65000FDEE888978AE8619E360DD73DA389FCF26
+:10A6600029BD447C72209DAFF7B2A2260EE58F6B08
+:10A670007E389EC35283CF3F805CE2F8DA765E0F6D
+:10A68000D4BAF7EB51A9A8D73AFE3A6A09B45746AB
+:10A69000F0F56B7E9E1FFCBCD1DCCF3986FEE783D4
+:10A6A0009ADCD8F93EDA83C2CE30A989F8BBD6D875
+:10A6B000F2760CFA4D5BF9BE3DDB6DC46F9CB18642
+:10A6C0000F5E6F8A81755F7C5DA27A347CFE09E043
+:10A6D000B38B4B5B4EA31FFDD5560BF98F0F828FAB
+:10A6E000383D77B03C6A72AB7D77AA81AD257F7229
+:10A6F0002D6BA27695E0E38B6D8D26CA9B79839EA8
+:10A700001F3DD8EF58A5E33B537228BF357C104E50
+:10A71000FE5FFF01D98EFB2780A7FF4E0EC687F094
+:10A720002F5AF786113DFB8FD8C85EFC49F0D979C6
+:10A7300091376E982CD3FA0D53789BD5F9D668A42F
+:10A740001FE21BEBDE3777BE358E9FA7F612DE5772
+:10A75000BE8A49F120385BAC94DBD3FA0D1F2CA2E2
+:10A76000EFF0D4ED19806B8C292E00D770FC2F49A7
+:10A770003C1E3448A1F160DD6ED9155CEF05EBB9E4
+:10A780000FF54F929003A6F813D02F1999AC92FDB4
+:10A790006A68E7F43474F016DEBF80E73B8CF4FEA1
+:10A7A00041F78B3D3578FFAB542BDF4FBEEAA9C490
+:10A7B000FE7747CB544FF9DD0F568C0DD69B0CE13D
+:10A7C000047AD619FD0914371E31107C75472E27DF
+:10A7D000A4DB501F6D2CB567A3DEE1FA6EFF68EBBA
+:10A7E00072E4630FBE373130CF6BC2DE325C6F1262
+:10A7F0007A152FF079C57AD7B2B9223EE67C942D2E
+:10A80000FC3D882B26264F1C1C57DCA83F09F6E090
+:10A81000E86209EB89140FC6B53B8F737DD0D0F188
+:10A82000D0A7C8E7759F98A9BEEABB9D0F8DA53A32
+:10A830005BB7FB56F42BBEEA7CF856CAF3496B09AA
+:10A840002E0FC29784FECB8709580FBAAAE3C30420
+:10A85000B2AFBB26AEF744A09F927B275E07BF81B5
+:10A86000F80FFC17E2BF9D3DF99ABF62C579571DED
+:10A87000505C889F5507F20F55A21F71B8381FD53D
+:10A88000B874389FFC953CF4576C01FF455B4F65ED
+:10A8900032AF77E9EF0AA33C81C44673FE61E92138
+:10A8A000FC53D3FA0ED9F59A3639A46E507BCE9D5F
+:10A8B000ACF07D7E8D7F5A2427F1C776DED6B4EDCD
+:10A8C000A4F5AD34B610BD1BB618F9FDADBCD5EA84
+:10A8D000AA3D2CC683F8388497800E334D5EFA6EFD
+:10A8E000C5C154EEBFEBE9F15932CF631C3CE1BE68
+:10A8F00019F9E560917BAC7D08FBE061C53C3E95B4
+:10A9000004BE5BF97925FDB853C93C8E8F8C0D3D93
+:10A910003F3A605F9239FFCC340DFD3DBD9F69F237
+:10A92000C4D83306E08BA39546FB3AE1B78F08FA0B
+:10A930005E42D55D46F20F8E32FB3B5867384BD3F3
+:10A94000AF93B95DD5F2DDAE0D2ADFD7197CAE919C
+:10A95000F4E47C6D3EFD7969E1D7CCD7F935EB3570
+:10A96000FD37868D41FDD722CEB9ADC90CF306E780
+:10A97000A3F4ED7EB18F81E775B06DC8FC98F23617
+:10A9800007BB4EBC41756627C2D8689E97A3FCF5ED
+:10A99000AA61F2D70D03F2382F84BF347A5C10DF3E
+:10A9A00055D1D3E30D81776D9F2D5CECB39D56DCC3
+:10A9B0006F24535DD67913FF8E9A9FE2AB864CEEDF
+:10A9C0001F5D2893685F1CE01C650ED2EB1746F0F4
+:10A9D000B8EABB0B24CA9B76E1788C9F5A24AAABB9
+:10A9E0005EE5EB35211F8D695DF224C9AB871D63E0
+:10A9F00041DFA9986DE17671806EDABA07EC568C6A
+:10AA000087EBE1386A713CDAC159C2EEE9CF218D9A
+:10AA100065BDE51857563B2507EEDBEBE93D77E1D1
+:10AA20008477E2FF013A9F4B761F21FDD67B7901A7
+:10AA3000E63F0F667E3E0AED65ED307CFB3BC1B71D
+:10AA4000DAF7591C63D546FC3EC98F12DD9F207E84
+:10AA5000FB0DDF468E63F87CDF7FAF91902E8CE894
+:10AA6000319C9C9C12F39D4A16DF258CE3FB24CB82
+:10AA7000B18FF26AF48EA4FC42F68DED4B35EC7E7C
+:10AA80003707F5D6C5AE0339A6203A9E5F03F28E8E
+:10AA9000F6A3635F826A0BE63303F1972469FCA691
+:10AAA00008BB18CA77E791EFB2B1FD30321DF5EE61
+:10AAB000F6A391B7E07CBB783BC09FED328D8378E5
+:10AAC00067CCFC8860F89E24F82EB4F07918EB1B54
+:10AAD00053353EF87EE3707C6B4CE1F584217CAB12
+:10AAE000ADB705BF8783FE7DA799BE8783F9E6E8EA
+:10AAF00020B9484DE1F230497CFF660AF3D0F700F7
+:10AB00002789EFE04C51984F89C17D2E9FCCF76586
+:10AB1000F9798602C1BF93145F17D6394C11FB3205
+:10AB200085AC97C64D677E6A9DCC4EE7148A9983A3
+:10AB3000DAC916DF9D9876C96E69A1FA3F5F821265
+:10AB40007DD622CE430C41B7C0FA15FAEE0DF1A521
+:10AB50008CE76186FE6E4A650A9773FA3807D2F76A
+:10AB600002A3FC147EDF0C5F325561155877749B8D
+:10AB7000C22CE100EFF6B70D24BF9D7DAA17EB4074
+:10AB80001DB1E2B92F18D5BB4E7272F944D382754C
+:10AB900012DA7AF5782884F9303F364981C892F084
+:10ABA000E8A3F7DDCEF8398D22A6D207566EC78FFF
+:10ABB00027935EF7539C54027112EA7583C543F8DC
+:10ABC00028C3E4CA44BEBF1109F314364BEC38EE77
+:10ABD00057A4F1F56AF3170223E0B9BD32B15E4C18
+:10ABE000811E8FE1FB1E9154385C6AE7DF094AA0A1
+:10ABF000EF04DD285EFB13F8772123EFF75FFC7E7F
+:10AC00007E60FFC781DF0D8A0C7C8FD281E74C30DC
+:10AC10007FE753CE07FBCD77A72CAD4E9918A897A9
+:10AC2000636EA6A25FA1AF9743F49D0B3ADFACD54C
+:10AC30007BBCEA9DABE2B9B98571163A4F9B6B19A3
+:10AC40009587762B23D15D9D42751F5B6EA14914BC
+:10AC5000EF44574480CFADCC3919F11CA8D7E3DFBE
+:10AC60004F1A38CF94C0E8FC9FD5CCEB199F01B99F
+:10AC7000C0EF178154A958D7C29E28A1FAC7A7A22E
+:10AC80002D0E3C87604678AD01781B2DA2EE47570C
+:10AC900077D96833D0F7381B59389DE79E15E6FE03
+:10ACA0001EAEFFB188623A2F9DB56D5A12F983B07E
+:10ACB000DE69DA7A0D83EB10B1FE0F9FD3D7FF69FF
+:10ACC000EBC2E3EBF85EBBC097B64EBB76DEC7A91E
+:10ACD000849CF7D1D6FF4C385FA71177E2D3E859AF
+:10ACE00015F5837E7D1A3FFC3FDDFB356D605C0012
+:10ACF00000000000000000001F8B080000000000A2
+:10AD0000000B7B2ACBC0F0A31E818565181826F1A5
+:10AD1000A18AD112CFE066607804C42C3C0C0C856B
+:10AD2000407B23807424101F01E2A340ACC2CBC03F
+:10AD3000100BC471403C07C89F0BC4A5409C05750F
+:10AD4000632B0B03433B107702713710EB3033302A
+:10AD5000E832136F7FBE0803C31309045F51126802
+:10AD6000A734FDFC3FD8F00A7DFADA276DC0C0B0E9
+:10AD7000D502C15703B2B759A0AAD96E81DF8C1D85
+:10AD800068F23BD1F8BBF0E83FAB87CAB7D540E5E6
+:10AD90004B693130782285899D067EB7A0E30AA0F1
+:10ADA000DE4A200600FB72DB43680300000000005F
+:10ADB00000000000000000001F8B080000000000E1
+:10ADC000000BE57D0B7854D5B5F03E731EF3C8CC6F
+:10ADD000641242483084092FA30D3821210D14DB61
+:10ADE0008140448A1AD42A54D4098F24E435011F9F
+:10ADF000176BDB0C04232060B058A2463B4150F097
+:10AE0000061D6890200107B034F4A206AFF5D1F614
+:10AE10007A8352400824E20BBDB6FE7BADBD4FE6FF
+:10AE20009C9319A07FFBFFB7FFFDE3D71EF639FB0C
+:10AE3000B1F67AEDB5D65E7B8F6C3213692821DFCF
+:10AE4000C2DF0F089926114206469EF6D7889BC49A
+:10AE500013529F4DCB4984A48D2041221032B986D4
+:10AE6000967309597B27099A3308D97FC484DF5721
+:10AE7000FA5899B60B99AEA1DF47B2F74F64D27674
+:10AE8000F4FD1317446C179841829B693981D0DE19
+:10AE900086133A840F9F933D0DD6D1B47ED39D2661
+:10AEA000627613F2381D868C27C441BC56429BAE95
+:10AEB0001CC1FA7B6C86E93951808FE19479B4BC6E
+:10AEC0006A4A49DE2A5A5A2D33B81A67973C17A0A6
+:10AED000FDBB4CC3711EB4DE13765AEFD1F74AC9DD
+:10AEE0002ADA6EC31C93509245EB352BB3825991ED
+:10AEF000F9ABCF3944E2ED0266533E3CBDFC195636
+:10AF0000E0F98B89261C674D0DC307ADA798520841
+:10AF100069ED3C60F1D1FED654B61E2DA4DF1F1999
+:10AF200061F2500C92473A0F58AFA4E307724D9E5E
+:10AF300091B4769A14165CF6C878E309057C1CADCA
+:10AF4000E7D96171DBFBD7A7FD4E8279AFA67817F1
+:10AF50003322EDC6029CB4DD1A4AB2101DF797B237
+:10AF6000E7308CFBCB1B12850089D4BB1E80847A12
+:10AF7000734C244CEB11A9D742E838AB26BE6519B7
+:10AF800049EBAF2A32C124C81A8FFADD6325D0DF1E
+:10AF9000D4518747005DAFA7DF611E598FCD8279FD
+:10AFA0003F3A452180FF5F0AB41E457163B1F24309
+:10AFB00080CF51435CF09E3EBDD1F0DA2658100E92
+:10AFC000B27A0321790440C0BF55DEE08A61C05FD8
+:10AFD000B9C403E5340F6D6FEFDFBE4B30235D1A4C
+:10AFE000E5402AE02F16FD46707CAECA5C6C057AFF
+:10AFF00010D29052349A90F580271854F2B9673ADB
+:10B0000022F557080C3FEB64E215E8FCE27295E08C
+:10B01000528A6753966B36CCD7EE53C875B4BC5280
+:10B0200008A48A4097D10AD9EC46BEB08EA4E53573
+:10B0300057257A80FFEA85508A04DF6FA0DF699781
+:10B04000078AC6CE06FE6CF228C8CF947F0E03BED8
+:10B05000D7F812C92A377EEFC4F6F6112E33628272
+:10B06000C243F13280F212E035FBA6FAEB87037D92
+:10B07000C6995C40A155C224F73C909F048B0BC637
+:10B0800097C7DD8CF49307260A4443EF9F03BD293D
+:10B090009ED6BA8B7E0ECFA7723F4C1849EBAFCE2F
+:10B0A0007EB911E8F4F4FD16A4DFD3E33A17815C0E
+:10B0B0003D7121E73D1FCAA5E2D94CFB7926FB442F
+:10B0C00006A1033E36EDC304C0DF90110DF7102733
+:10B0D0007DCEE8AD2563287CA4A1687E06F2897048
+:10B0E0000BC5EB90250A715B182DBF25F09D7843A9
+:10B0F00059AC6CA7F319C2E9DCDAF996A518FA9BEA
+:10B1000043C2A39CF8DE929C18D13343724938990C
+:10B11000F6FFC4824328E74F5F9DEC61729E82FC7C
+:10B1200092CEFB4983FA54BFA45848208E3E8774C0
+:10B13000F4DE0C700DC93C3107E0DCFFFA2101E8B8
+:10B14000F6CC986437E8A3045F27E9A2741F92F550
+:10B15000CE8350CF610FA6146561FDBF603B03FC39
+:10B160002D6EEF26C0DB36A1E630D027906DF23091
+:10B170007A333DB8FADEE420E89121B63FCD14875A
+:10B18000211F10924CE1731194937A216C190EEDEA
+:10B190001E60ED8692A000781E921958243AA1BE36
+:10B1A0004F2872F41FB7153422C807E574E0D7EDB5
+:10B1B0000A292F8A2207AF7279AE17C82CE46722BA
+:10B1C000FD15F8666802E31BB5FC0CC043C7DDFE45
+:10B1D0005AE20FB3283CBF5A322C5BA4F0AC857600
+:10B1E00051E4660D97035B07090814AFFB7FF73B3B
+:10B1F0002BE06DBB899441FD4999214B17A72BD0BA
+:10B20000630161FD37656DB4A0BE103291EF16E4A5
+:10B210002B5EEB1890BF65828FB64F7131BDECF09D
+:10B220002841D0CB8E948060A2F0B8B3886B6306BF
+:10B23000EB2E40F13717FE018C2EB1FAABD7240468
+:10B2400057D1EF73B3A8A001DE28AE4C74DCF984AB
+:10B25000CD73AEA77E11D08F902213E073958BD162
+:10B26000A709C6A153694A63FDACB98F0497011FB2
+:10B27000B958FB11D084D26D44EECBFF22D07ED3DF
+:10B28000783B907B68179712B498683B778D89203C
+:10B290007C52F8B000741F9DEC06789A523CFF3E39
+:10B2A00003E09F257936D2CF23000EDA4F538DC9A4
+:10B2B0008BFA225769063DBDCACBF4BC8AAF0C3E5F
+:10B2C0006E9A272CD0B9930CAA27114FDEB0D50562
+:10B2D000E52C064F462E9B571FFCA395E032DA382B
+:10B2E000CD1226504FC54309EFAF84CFC39E125CE9
+:10B2F0002101DCB90C6EBA2E233C69594A33C8418E
+:10B300005A0AEBCF4DF1A3E21DE0B2A970E5D2FAE3
+:10B31000A0873D4A33B0828DC35792C5E0D97FE400
+:10B32000AD0E81F5877265E3F0DAF8FC09C09BCCBD
+:10B33000F53AEDAF450E0B22AD1F1C47DC1BD9685B
+:10B340006E292FF2FDB11A8A075AB0F371C87A3309
+:10B35000CA037D15F896F2C1BC065ACE8CC8C7C880
+:10B3600015669DBCD8F9BC49039323CA366168971A
+:10B370004158D904653A8F924CBD9C118FA64CE17F
+:10B380007000BF53FDB374BCC2F8E72A66C710A2B1
+:10B39000A9077C3ECEFDEC6AFCAEE0BA9EFE5345AA
+:10B3A00007DF909AE4C922E8938E276F36015FDDAC
+:10B3B0004B4C623CF2B3D0A7BFE8783B1687AD3068
+:10B3C000495B475122E02DBD2671B20278ECF06155
+:10B3D000D9D651E3C5272C4D6309194C34E3648059
+:10B3E0007E7555B450BC921A2504FA7A9C164EFA12
+:10B3F0003DFDB5869940AF87171D4A05F94D36B416
+:10B400001F631A86723AE4355A0BC73FF133A8BF5F
+:10B4100092EB131B403C169FAFC173889DEA59AA5B
+:10B42000A7D3298295B1117DB1EAAA77B27D76CEF4
+:10B430003F89F80CC3D3A85734F5AFE2F503C245F2
+:10B44000EB9DC07A2A3CC6EFE70413EA2907D89996
+:10B4500014BF8F12D76C5C973D265C17E3F8FB9006
+:10B46000E7C064A4678878840CD0B77F356BF9E0B7
+:10B4700027F012F4AD14423951D26D681F52398E43
+:10B480008375AF49AA2983F7A1341B01BD7060EA17
+:10B490002101F099D6E61B0A72A8DAB9933DA114EE
+:10B4A00078FFC861DF95289F31EC46D54E34CEE752
+:10B4B0008A6B97A13E18EAEBED80F5DE5E2979AE46
+:10B4C00003FEF251B8ECA827DDE4BB147E4F6029DF
+:10B4D000E859B78F9607D167257F96B1EF2B6BCBD5
+:10B4E000728E4B917E578EA0F628D58BEB3BD75BA7
+:10B4F0006E003BA3C6E406BE5DE379CBE2B54379BB
+:10B50000F200C0736B916AF78505182FED6D2FDA85
+:10B5100079E35C8A0B94D6687338D5A5592F9AA61F
+:10B52000BE3316E020B75222A6C6A6239D2FF2599D
+:10B53000ACF504603169D691FD993B707D799D5CD5
+:10B54000857451D715751DC11EA97E99C7E5E811EF
+:10B5500077C822A0BEA2B24BE9338FEB113BD79B39
+:10B56000540F333DC7D793358B92713D51F527D892
+:10B57000D6A024E6717DBB26FBB9841B284C76D06F
+:10B58000B3A09752C864587F47829E01FD240504EA
+:10B5900018AF699C8BACC2754CAF4F47D6303DF8A5
+:10B5A000480A417EA2EB5033AC774D69A114E8A75D
+:10B5B000A9E680E0D3AC9FEA7AE7A8E924A007E7F0
+:10B5C000E6B2756E6E161BEF0F80A0710C5ED0ABED
+:10B5D000C675EF171377A0B28CE3F69611FF828938
+:10B5E000D9818FCE780BF1B866FE63F8240D1BB0BD
+:10B5F000BF140BA3C1CACC03F87EB5CF340DECEE5B
+:10B60000F552E78A1114FEF5D3E62A01FA7DB587D3
+:10B61000F95DAB26CE7D0ED635B3496170D594A1C8
+:10B62000BD1AC7E1DA007DA39FA8A05F74DF9D1B50
+:10B63000570CA3FDA4503F467043A5A0C54CBFDBEB
+:10B6400081A6A0BF7D6106BF874C2651E0FF0FC1D8
+:10B65000C6FC505F67C748A4A7C905F0C6797A2D14
+:10B66000E027BAA91FE67603BC6EEB6884D7E45ADC
+:10B67000EA8EB4FF3DF717EE82851FECFBD9EF4C45
+:10B6800003F95A7727F3CB8CF0DF3729D861C271E1
+:10B6900008BA758E18789D031A0CF48F27887039B4
+:10B6A00032195CC70546AF473B275F8F7E52117D3D
+:10B6B0004F3B7AAC739815E4DB68EF3D1DF74136DC
+:10B6C000DA3B8675E652E521067D3FDA1C9A8EFC50
+:10B6D000B6CD847A8A10A6E70462727F3B1C1611ED
+:10B6E0000617B21ED5DFCBE5F0ECF9B4FEF29D767D
+:10B6F00002F852F9218DF7B9AA86F24194797708B8
+:10B70000622CBA333B83D3BD13C61B7869FA5369E5
+:10B71000B682DD160AD60F2E07FFA386F9BBA1F06D
+:10B7200001D43F69536E433F654B73F2ECF9C05748
+:10B73000995E0FA0438507EC93687EE27493E5A2BF
+:10B74000FE7B2C3DDC58B91CFDDEC6CEE8F39F68BD
+:10B7500062FE7688EA494F56ECF1F34CCC8E4E30BF
+:10B7600071BE9B7A2845BB9EA9EBAABACE0E914822
+:10B7700040D4AC87B772FC19D74D22355846313EBC
+:10B7800047FFB1713E8B436C9868C2F88ACAE7B430
+:10B790005E0AE095CE03ED39CA8741B0E71E250D5C
+:10B7A000283701DA7E33E90FF79DC47459F39BC043
+:10B7B000E7D7371EF7AFEFE2FA6A5DF6FD56E88A83
+:10B7C0008E9702FCE177323D59E560766CC14E39C7
+:10B7D000FC030A4755B3807696699F15E13CB7890B
+:10B7E0009669D7618782F5CFBA2C58F69B3BD77EF6
+:10B7F0008F967B778A04EDC84C9B09F8F504E757D0
+:10B80000924BCB600F5B59B1AA79FF5DD05F599B1A
+:10B81000995869FF55BB4B6FFC1E2D9776C804AA3B
+:10B82000546D5EAA0CA6E585412104E59EC974A16C
+:10B8300002BC242A41F0DB7B9C9DC93FA2F33E5D04
+:10B840006B216E0A4A9DA333F9568A8FF2E0F642C5
+:10B850006857DE228046A4F3D87C2815E6B555F05B
+:10B86000807F5FB1254E670F9EA053F901FDBE9802
+:10B87000CE13E4B2943414C23A57B5799DE2D6C4DB
+:10B880001F4ED7BA701CB55CB5958E43DB55BF28EB
+:10B8900078608AD526E2033D746EB775D6B3769884
+:10B8A000DF52659403E6F5B002F54A83C52F5BDDF0
+:10B8B000005FB35248BF9737352B10DFF29BC9DDCD
+:10B8C000E0E7566C19A087AB5144795D9C60D908BC
+:10B8D000FA9CD8BD29378FEE4FE7D3B554C78E8A6F
+:10B8E00094CB411F221F0695999AFA43C504E4D7C9
+:10B8F0008A2DA2DECEE6EB7FE028A37F60AF03E3D4
+:10B900007E2AFD16737F59A5DFE2044E4FA9372F1B
+:10B910001A3C6B811E149E06C0177DAEE6F03927D7
+:10B9200092491077717A894B88C2D7C667834C8A4F
+:10B930008175FF75D9CC49522ABA0F8B20F2E45A8F
+:10B940003E7BD2145AFEBDA968B309F587C70D72B4
+:10B95000A4FAD9CF98985CD6A72A88BF86A979CFB0
+:10B96000B2F804C175AF616AC9736017D0F6DB4CD9
+:10B970002887B4FDE8D8ED5D85F9BAF6AEC232B5D8
+:10B98000FD4E6C6FB978FB86C209FAF10BCBD5F688
+:10B990007B117EFBC5E1775D37513FFE7595D8DEA3
+:10B9A0006F66F4EA4DB0A05DB3DCEAF14ACC8E0AD2
+:10B9B000C37B2971D446A827AAFC403ABD607FDB2F
+:10B9C0005B12C6AE225ABE98FC3AC0E1A0D2A2E5F4
+:10B9D0008BF87C9B8E1F13BC89BA32EDC975E23B94
+:10B9E000BC0C83382D088F3258417D3169B005E198
+:10B9F000BD7F9F15CBF74F60F0DE3FD88E72866B10
+:10BA00000BA5E3FD8AEF1AADDD0A2B138492DE103D
+:10BA10007D1F027E23EFDD26786F13490DEA673321
+:10BA2000417DF47046DEB3010D7E560CA1F4A5E510
+:10BA3000B360FF0C8CE0F5E1212529C59A71EA87F6
+:10BA400028B33666B1F7F3EC305E510FE0C1AFF4C6
+:10BA50008E02BBD2388E7958BE6E1C4B7A198EF38B
+:10BA6000B5611C737A99611CCBAC8DFC3D1FE71B43
+:10BA70009857AC711E1E36413F9FF4721CC72C1A9A
+:10BA8000E6935E6E18C7C6E643DFF371ACE2C5E627
+:10BA9000337CA27E3E432B719C2451D1C5ADCC4357
+:10BAA0002B0DE3D8711C780FE39034E6DF28E6DE37
+:10BAB00012A4FFAB5602F6B462F63D0FFD923F5A58
+:10BAC00009EA13371D7710E89544DC2FF80F53224D
+:10BAD000CEE70B1BA5BF5D4BE7806A17A0BDB38007
+:10BAE000834882F5E89F57731E9DDF32337D293CE2
+:10BAF000DB0A528AC1CF5EEFF040FCF45C5B81321E
+:10BB00002F8A5DB0A0413ED1A5E35FAEF72693CC6E
+:10BB10001AF0B3B81DA0964F50FD45A8DEFA90EA82
+:10BB20002F789E94A99EA6EF8F53FD46142DBC4BF3
+:10BB3000B1DD0989E1F144135B47BE587754C6383B
+:10BB40005F80BC9D49E7711B9FC6828638E62B70DB
+:10BB500038FC9C1EBDBBCDC18D480FEF1560F79022
+:10BB6000C6011457BCDE30C0171597442C5E01F691
+:10BB7000D18F576CFF0D547B47281EB298CE775655
+:10BB8000EB3AF90A5A3E2777DDE5B16BFA99257F42
+:10BB900008F3B6D0FFA09FD93E5AD68C7F4799BEF6
+:10BBA0007C279122654AB7A9E2304E0F3EAE3B2872
+:10BBB00003BD6E4B66F0DC09CFB1F0D985F4BACB8A
+:10BBC000C5DAAAF0F81F944918D7A3AE81CCB81DE6
+:10BBD00088F57CEABA6280EF2ED9E22DA2F4BCEBA4
+:10BBE0000111F16884B76B5F9CD744FDAAAEC64FC4
+:10BBF00065F02F2F05FFDD4BF4DF49808DA7E2555F
+:10BC0000E583DB674D1A705C536FB6EFFA01C735F9
+:10BC1000FC7247D94C5DF9CE9AD9BAFA772F29D65A
+:10BC20007D2F0E2CD47D9FB76291AEBCA0E1015D4B
+:10BC3000FDD2C6A5BAEF0B832B75DF2BB6ACD3951F
+:10BC4000AB424FE8EAFBDB9A75DF4DFBAEBA09E485
+:10BC5000B1EEF72201FBEC73FB89B5605F7D6E9757
+:10BC6000D0AFAA065EA37278AA3605F9FB74AD1BA5
+:10BC70009FE7DA72707FCC6FA3F24CD7FA0D75870D
+:10BC800097AE98087A84D6A73AFCA9BA379706A83F
+:10BC9000EFBE1182D494EFC546858407801F93D8E8
+:10BCA000C7D7BDA2E67BD725BE37D2052BA7FF7726
+:10BCB000B12BFAFB1EA17714D87781F7CDB87F138B
+:10BCC000CB7EA07F579028FE83FAEC86F88646EF5D
+:10BCD000BC2A32BBFA1A71F2AB227D562A4CDE2BFB
+:10BCE00077A44E867841A5121E5513C5CEEE1B2FA4
+:10BCF00044811904FD30795918BC2222BF48BFE1A4
+:10BD00003AB9BFC1E4DB07FAB97BBFC8F607C2077F
+:10BD1000D3619FE61AD1FB2ABC276D03717D7CA7F6
+:10BD2000D63BE0F80842DEAB9D86CF3FD4160D80AF
+:10BD3000F8D19F6A6761F9835A1F3EBB6ACBF0F95D
+:10BD4000616D0D7E3F5EBB04CB276A03F83C55BB9B
+:10BD5000029FA76B1BF07B776D2396CFD506F1A9C9
+:10BD6000CA816A8F92246EFF717B9DAE1C583ECFB4
+:10BD7000E720D27F77A25C7B5240AECFDBBF1805B5
+:10BD800076EEF9F7CC18448F852723BFC5A69F17F9
+:10BD9000D7FB9220A57F4EFFEF561BA38FD544A65D
+:10BDA000817FB672A44220AE6E7BF53B682FD3F73D
+:10BDB00012417D19F468F711FBFA87390FBA349DE7
+:10BDC000D4FA279EFCAFBCB959401F465FDB41B196
+:10BDD00086D1ED590FD04D833F6697EDE4FADC80B4
+:10BDE0004789CB9D119F6707AAF8EC4C87784B9544
+:10BDF000586492E8BBF3AD669CD7F9F638B68FED80
+:10BE00004ABAAC785EC516AB4BAB1FAA42092EBD31
+:10BE1000BE487569F5C5F98E679D20F78B534CAE0A
+:10BE2000E339C01F5ECE1F8CEFD4FEAB42192EBB90
+:10BE3000AE1F7DF97C83308DED2BBAE36F8DE21F51
+:10BE4000A8CFC5298AEB38D50BA7B70C8F8771A966
+:10BE50001FE78271BA6B5D2E366E8A4BCB97954B7E
+:10BE60006C585F852F56BFFF68F860C7EF230B8BB8
+:10BE700035419C2656FD98F4903E53C03F20EDF28C
+:10BE800017B0EED832D57547C2B2DAAF3F2406CC30
+:10BE9000D7C0FB16DD78B49D5BF5A1A15D6CBA4BF4
+:10BEA000E4844A4FAA27AFE3F921949991CE3EDA70
+:10BEB000633CEDAF47B2AF80386F86E4467DE787DD
+:10BEC00081283F5559BA149F1BD1DD8971CF7C550C
+:10BED000EEDDB7FF91B2DCC7FF26633C837C437B7A
+:10BEE000A7DF65FE753E2972829331B7B56206E819
+:10BEF000C98F4DAA3DD09007F33E4B4CB89F7F961B
+:10BF0000BCE5CCD1D86565128F4FAE60EB7380FE77
+:10BF100007F3A3769A6EBD2E6DD4974BC8CDC9207A
+:10BF20000F25EB65D8B1250B61BDD7EC9BCC925C9E
+:10BF300038EF5252530F76CA2A99EDA3CE7511E904
+:10BF40000A0A57D5AEA7F3C09EF54B4CDFABFEF304
+:10BF5000C2440677795250F1D2EF1FB5E6DCF63DC8
+:10BF600002ED83F5A0D7020EE289168F99B7420F32
+:10BF7000DFA5E037C24BC8321D1C6ABF2A1CE2167F
+:10BF8000216A9EC6CF2481C775987CAC91F4F6EBEC
+:10BF9000631C0F6A7983A1DC64A8AFF289CCF92411
+:10BFA00043F23D06FAA7CAD25B88761AA1FC911526
+:10BFB000A9A744EA6DB8583D33D413B15E93342E2B
+:10BFC000763D6BA4BFE668FD55EDDAF67280F2535C
+:10BFD000F94B8F3B21E8FBB1D4900CF1AFCACD0FE8
+:10BFE00039014FA7A48013E8FD71508C1A177CB754
+:10BFF0000F5F5EBB007E04B236C5FB0B8FDC08FA18
+:10C00000FA8BCD32E6C5F8B798C366CAC7D5AD0B73
+:10C010006740FC9E968FB1F2C39FC0BEA1BF4D4F3B
+:10C02000CFF2E71F4F863811C524B3B74918ED8EFC
+:10C03000EA4D7F2E043DEE27BDC887C67630FE85CB
+:10C040004494FB6225BEFF77355FC1CFE5CCDFFAB4
+:10C05000C8279097E037F04F59DF7AD2A5401CA14E
+:10C06000437224A15FFE5DF25DD0032A3E4890D961
+:10C0700013755B378C3946E1E9DEF46F4E41E777A3
+:10C08000333E3C1F9AF7AB57DCB1F5CC39EE0F4588
+:10C09000DA05B19DBB8DD93FA49D3D2BE5B013ECD6
+:10C0A000CDCA66D9433994546E7BF6B927C14F7B0C
+:10C0B000DF8C7E5AC5B6DFBC3381962BB6CB4933B5
+:10C0C000D874EC4272842E7EFABF2563237428FF55
+:10C0D000F56F14F768F6FEA789117A546CDFAF90FC
+:10C0E000D1FDF15710DAAF74D9A3D02574AC10ECA0
+:10C0F00095BAAD5F2AE0777DBC4F208332FAB72F27
+:10C100006BFE0DAE878027A423A7531FDDFAD12B2A
+:10C110007CE32BB958CF057A3216BD5EE07AB96A56
+:10C1200097832440FCF30FE6E00CA0E38BF7386123
+:10C130001E27A51AC6D74F3F940CFB7F657220D9E6
+:10C14000854FF6BEEC99FB90DF4A859A64B68FE97D
+:10C150004DE5F1F25498DF82A61FE1FC4A880FF901
+:10C16000AEEC69B108E2C39F4B64DAF628727183C2
+:10C17000CCF69F4E6E3443921F3909763ED8D76F66
+:10C18000891867256411EE83DDA7C671C9622C7F0B
+:10C19000CEF7A546C826D53FB4E8F875D3C39D4071
+:10C1A0009FD343BC83004E8A8700C79700FBFDE204
+:10C1B000D1A983187D58BE01B6A3FABF00DE43FDA6
+:10C1C0004E19F70935EDB8BE64E3DFCBC7A770DBC6
+:10C1D000603D3B99CCF62B8DF35BC2E747FF3A8974
+:10C1E00086BF34F2CDE47DD34A26DFAABC07674E72
+:10C1F00083EF9FBDCDE407DAC1FA41E10A0FC2EF38
+:10C20000FB6F15501F9849389A5C6F92B95CEBBF71
+:10C21000FBA99C425C80C22D413E43844F68FF894C
+:10C22000887FF44B4AD6D3761AFBCC0FE3613D25C9
+:10C23000F25EB37E94723D304DD6CB3F691A785989
+:10C24000F662A54C02605A56BE6F46BFBB729B5C3D
+:10C2500004F33ED372F09D1F53BE3E1352E554AF1C
+:10C260003F8D725AB663B300FC6994D3336574B5DD
+:10C270008E26A7F47D54392DEBFABFA23F55BCF9A9
+:10C280000D78A37A7068822936FE8C7AD021BBA300
+:10C29000EA41FAF736C9EBCF772ABFA97C462DB41D
+:10C2A000A1A0BFFBF851E5B73E7E54F9CD384F3D14
+:10C2B000DE8CDF2780A146E12ADA2DA35F52D9CE9A
+:10C2C000F66F68BB4357E4227EBCB87C9186435727
+:10C2D0002469CB41433964A8EF35948B0CF57D86F6
+:10C2E000728DAE7E65DB418525198575F5CC4B9E3B
+:10C2F000241F45B1EFD575C6DFFA8912007E48EBE1
+:10C300005540CFC9CBA86906F1B3BD22FA5B3DEE1B
+:10C310005E67227DFF9095F9B13D2E5E4E60E5DEB1
+:10C32000814A3DE839F57DAF95C5397B8A7A9D090B
+:10C330001AFFFE58BBE884FDE0AE20CB47ED0F4F5F
+:10C340001DCA4D1789F59DC505A78AF6F425E0BFDE
+:10C3500035881E700DE72FBDDD09FB6E3DEDC36F07
+:10C360009A45DF2F382C82F94C7A6CCE31001709B0
+:10C3700078A5D43C9E3F41FF4E91C02F2742DE441A
+:10C380003BB3AFE7AF36D8C3F67B15CC2F5BAF8995
+:10C390006B69F8BF9CF753D6A4FF5E4E5623FF95FA
+:10C3A0001BE4C1C7FD81A3AA3C64936CB6BF4D9842
+:10C3B0001FCBF5EE5431EBA65914EF3D1D22E6CD0F
+:10C3C0009E6F17493DCCB345C07D4E1218887255FB
+:10C3D0004D7A51DFA978E906B95162EBA3EE9DFFD2
+:10C3E00091F720F0C7CB7F1CF3147D76BFFCFEA82D
+:10C3F0003D50DEF56EFA1F49FFFA05FBBEC27DC453
+:10C400009E7D668C73F5ECFB6DFA83507EC58C7156
+:10C41000AE9E6566DC4709EC730447C2F721CC1F6A
+:10C42000A8DBFBE5189627B91CE9F48DCCFC91F349
+:10C43000EDFFF501E48F9C6FA7B302BB605F1CCAE0
+:10C440008DFF152BFADF3D7BBFCCF3D9FF71F3A92C
+:10C4500056880FF9CF4166ED007E4D60F160FF9E7A
+:10C46000F1CF427E7355EB7E05E2EC05AFFE650C25
+:10C47000E8C99E1DCCDE3927773D03FB6166E59355
+:10C480006532C5F339109EC1843CAB8C2D086445E0
+:10C49000C30BC3430FC503CC8BE2A50CF47B2C7CF0
+:10C4A000A42BFFACF8F8E42EA6C7BE8B79F611BC1E
+:10C4B000085EF6DE11B408387FF67EDF976340CF62
+:10C4C0009C092D457BE452F3BE5661FB2CFF73E6BD
+:10C4D0002D842F67DE73FE69E9CDF8FF43585F07AF
+:10C4E000F69783FE7CBEEB7E2CBFE8F020BC97293C
+:10C4F000FF3FFD9F46F71D94EECE4BD3FDA97FDA9B
+:10C50000795F8AEE8739DD1D2ED85FEED9FB178C57
+:10C510009BAAF3BFD4BC5FF97F74DEAABD3EDD5495
+:10C52000736426AD7F8484D71751385F4B9BFAF62E
+:10C530004CFAF5B731EC91D30A8B7FFC96B03CC135
+:10C54000408AC0F23CB85F5440D8BA5E90598A76AF
+:10C550004641E623681F10A9E64836C5C7F4F4052E
+:10C560001E960F3616CFA15C977AAD07E38106FFC2
+:10C57000F0A040BC900F5D70F5F51DE0AF4C499305
+:10C58000C3E631F83C06CF43CE69ECBD5DEF17CD75
+:10C5900000BF46E3E75DEFD67F2FE4FD4D238B8F91
+:10C5A000CCA4E34F4B135D416837A94182F9CCA07D
+:10C5B000C2DDA0D90F2A34F47708FC5A4DBCEC6FC9
+:10C5C000C55F9A99F991BFA5E36703FED2648C0712
+:10C5D0005E127F84E57F5D979A8DE75188E441FC88
+:10C5E0004D1F5CC5F1C9FC6689B797ECF59D20B776
+:10C5F00012A17E2FB3CBD05F56FDDE587826DC8F9C
+:10C6000096F8902ADEA53419F35535FD213E547A6B
+:10C61000FCAD7450E9F7F7D2E39C811E699FB92401
+:10C6200090CF026EFF4FF9AC53C4729A47C2FD28F7
+:10C630006EFF4FB2274860FF5F2B1D15412E4B2D1B
+:10C640006DD3214E6FF108C8D757769BD0BFB1E4A8
+:10C650000A88F7CC4609CB474DAE716068DFF8BD5C
+:10C660005D671E20101FF62A68789322169FFFE64A
+:10C67000DB6F27AAE735F03B213750FCCE6F2261F4
+:10C680001B9DE7028904E21321BE2B900F75F15D1B
+:10C690007D19FEBE9F1CE9E752F563E9917FF473B3
+:10C6A00017D55B1F52E6D80D4FDC57A12CA1F18F97
+:10C6B000BFDBCEF0E53F4282C3502F78C522CDBE0E
+:10C6C000D92366A63F76FD69470EC4C526F564C525
+:10C6D000337D3A02FD023FF70BCE13773CE41F9CFB
+:10C6E0006F1F1E8FFB821DA2C317252EB395FBCF94
+:10C6F000FF0AF914F4D9B38934C0398C1ED28BF1F6
+:10C70000D8C0264BD4FDDDFBCD6ABC89D38DFE8914
+:10C71000EA792337E68B04E2B574EB9EF1B134A6D7
+:10C720003F1DE0EF43CD7EC9DF8B5FF0D701BF5BDC
+:10C73000AD5D85D1CE83ADE0F8BBF1C05718C7BC65
+:10C74000BABDD904FC7BF526936EBF3160E67ED777
+:10C75000583216E0BAF180D5910B74E9103D903F44
+:10C76000E86FFF44F145D9B732E213FA87B8F83ED3
+:10C77000338BF3EF9143F300AF7BCE5A303F67B773
+:10C78000D250110DCE2BAD4CCF2D20A17BC664FC19
+:10C79000F3E177528F3D3C19FCCC4D84C7318CFCC2
+:10C7A00047908FCF6F21783E14FC52D00BE75BD8B7
+:10C7B00039608A9235E04F5379FF81362E7365DBFD
+:10C7C000F67F053BA0BA5D7041EA6CB5D4A540BCCC
+:10C7D000D5DF9620C2BA9BED56F32A5DA36FD5C86C
+:10C7E000C53E33CB373E3861CF1D30EEA7DD0A01A1
+:10C7F0007BC4FB5AAF13D6ED4FDB73E2A3E5CDABA1
+:10C80000CF5FD792E95324E88720DE8DFC90D56274
+:10C81000D395BF27FA06837CDD68EEBAD713857EF1
+:10C820003E0BE3B3CBD66FC1FFCFF4DBDBAA7EF3C5
+:10C8300089451A39CAB4F4D36F83A2E9B7C5827B9C
+:10C8400010E07DF1DEE18380AE8B0FCB03A3E9B76F
+:10C850006DB56C3FEF259E0FDBD34AF5DB351AFD36
+:10C86000D66AC1BC3863BB448B89AF8B97D06FC18C
+:10C87000FF1EF9DB06FA2DCA7C475A98DE50F5DB1D
+:10C8800098F663A8DFC6B49A7479A369964BE93722
+:10C8900061E0AD600F77C89EB828FCB38DDBDF2F59
+:10C8A000F13C3C1807F4DC1D16B6BF79B97A2ECBE3
+:10C8B000CAE87D493DF7DF846755CF2DDEA99E7319
+:10C8C00034F221D3738B77533D27003F323DB77845
+:10C8D0002FBBC7C1A8DF32FBE93782F5ABC3ACBDC4
+:10C8E000BF2D63C31CDADF58AFECB1D0FA6323FA73
+:10C8F0006E9C56DFDD6161F72EF4D3771D97A7EFAD
+:10C9000076727D47F5D830D0AF46FEF0B4EBF38EAB
+:10C91000F78C3FD9F26B9097D745DC373CCACFA54F
+:10C92000BD31FE642EF0578B85E9DF3ACE7FE76A92
+:10C9300003D87FC16B6C7E5576968F5CDDCAECC3E5
+:10C94000EA1621E8A6FF2C9CF09502F02FDC2B9034
+:10C9500041B43CD3CCEA93E7D57D2F32235BC30FA0
+:10C96000F3F32B306E3F5F221688CB57D80B3F86F0
+:10C97000787C453E8BE357F0F70B0F77D5433C7B34
+:10C98000E11302EE7B129E0FA0E63796B62FC57814
+:10C99000AD312F40D5E70B83FAF715867CC6663E8E
+:10C9A000CF996217E285BC2946CD4B6836E2A38356
+:10C9B000E3639388EB661F3E287EDC19FDF1412975
+:10C9C0003A233B3932FF85AFD379E546E6A5E2C38A
+:10C9D000383F35EE5CC1DBC59AAF8ABF7EF355F1B7
+:10C9E0006998F7B3A037402164931CC88BA17C8061
+:10C9F0007A23F03B11CFEF174D1A3948AB87B77246
+:10CA00007D9ED330A9209500BE480DF04D49E3A28C
+:10CA100043A974DEE3DE738F85E5F17B13CC3ED84A
+:10CA20001FDD6AED45BDA6F2D5D79CAFDEE178DC0F
+:10CA300033B806CFA9FADB0417D815FEB015F1E715
+:10CA4000A7F883F32B7E7E7ED14FF90BE4E9E01348
+:10CA50005F307CED15DC101F2F54D71FC03FAD9FFA
+:10CA6000D3CEF0EF0F0A88FF5CD28BFB23D58D82EB
+:10CA7000274CEB57B72DC2BC0755DFD23FBB961EE4
+:10CA80001A7E94A2F12356D2AC7F15BCDE8DE686C9
+:10CA900077803F6F7C5E26CD1AFECCA4FF7D1B8580
+:10CAA0004E2A3E2FC59717389EB6011EED80AF5E09
+:10CAB000663F85BFC27334EA77BF14D0E1B1E0C9E5
+:10CAC0000B17C5D338154FC0A7A0A7DA8B452897F9
+:10CAD000B409644046FF79C2FEA4566E17EE3DC607
+:10CAE000FA7F5AC07B4B8C7CABCEBB1FDFC6E057B6
+:10CAF0003897067ED1E5F2EDD706BE7DC3DA7B24FA
+:10CB000007F876AFC0E207ED09BAFDC5C156B6FE1B
+:10CB10006FB552FE867DADC3B267A3BBBF7CC7F1C4
+:10CB2000F50BEC7EEDB9A4AB602290F7B8C5827925
+:10CB30006408C73066576AF5EA362B19786B6EECD5
+:10CB4000FE5379FFB1EC1AB53C1AC6837CAF363A76
+:10CB50005E66643CA35E57FDFC4BCD6BD4DF39AF02
+:10CB6000BE3C4CD289FB4E1992EF51B3260FEE36E4
+:10CB70009E67442140FB4A532FCB72917A24C5858E
+:10CB8000E79FEE71A97CC6F2DD8B781EFB5471E243
+:10CB9000BBB07E7EEA65FB7CB926F2FB89A09F27AD
+:10CBA000CB788EEFD32332C66B3F9DC2F2386F7ABB
+:10CBB000FDA004719A9B4039517CDC344E407F05C6
+:10CBC0008E61C1BED92E6ADF7847E17C72E01C57C6
+:10CBD000F6A68602387F3C764BB00E9E9E82DEA47F
+:10CBE00037008F93440278ECF40E2880FB93EEF923
+:10CBF00033C1FB43E83A8BEDC7769081506F827763
+:10CC000020BA03E35BD717407C74E641BB1DEE6797
+:10CC1000C96C32519F2182BF09245807FBEDE38F75
+:10CC20007B6F0178CBA8BD0071E7B2F6E63A279496
+:10CC30009B048F9BF6EF0FF80A9D741EDB1A3F29A9
+:10CC4000FC0EC823AD07DDF89B583DFF26B87808D9
+:10CC5000DEAFC33C9B924D021EFCDA16148885F5AC
+:10CC60001BB4D07EB735D1F6B9B04ED0F6D0EFA612
+:10CC70004FDEBE05E4FD88C8DAB7B07DEA12DACE31
+:10CC80000D7CBB6911F6B7B0492029B4BFB216B606
+:10CC90000E941D913DF0BD75FF13B88ECDA0E3A598
+:10CCA0006680DE0F4F8132C9115C18EFAC1C8574B1
+:10CCB000EBE1724E268E64FA43E065EE37A876D338
+:10CCC0003B5696EF5BE259AA0CA0FDBC913F3003A6
+:10CCD000D202FC6D9FE0FEF3718A671FEDF228CF50
+:10CCE000DB3898FF91D2A559873EB5B2FBADE6B7C8
+:10CCF0004DC27C8605A408F3196E1CCFECB537AF86
+:10CD0000B506E18A8337E5DE34787FF05A33DABF3F
+:10CD1000E7B6C9C847E78674617CFA64938CE786F6
+:10CD2000EB9AD8FD5C275BD83A2E3ECDF6F54B1D2D
+:10CD30000A960F36DD5208EBDBC94DECBC63C1D35C
+:10CD400053152897360B1E767F11D38FAAFF56E214
+:10CD500062F908AAFEABE2F3EE97B768D07755EA1E
+:10CD60007A63D07755B0AFEC84A7FEBD9FD8991EEB
+:10CD700004BB1FE81EFE0AF9B7FA884CC0EE173E46
+:10CD8000EA2EC47CACBD02C6F3C7B70B5ED8D72F62
+:10CD90007BCF1C447B35587CF74F408FBF6F26827A
+:10CDA0001BF2DA29DEA97EC837F7FEE917F4FDC7C2
+:10CDB000472D900943F9A418F1ACE67FE66E667939
+:10CDC0002CB947D727C3794B326500EADBD24691AD
+:10CDD000F8347AE363C17BCB8F995EC6FB2954FAA2
+:10CDE000E52A0D25B08E0DB731BDE4DE2C438E084B
+:10CDF00039CCE324D49EC6F3B70B77AF4B5668BD4E
+:10CE00007A9EFFB170EFBA6491BEAF83F58BD65FA7
+:10CE1000A8B0FE17EE135CCD9AFED5F66A7F6A3F86
+:10CE2000CA6E7D3FC3F7F2F265F6A3C2A18E1FCB97
+:10CE30001ECFFFF70BEBE1BE98FC37454C3ACEFF17
+:10CE400068C670ED7E87FA54E3AF796F9B8857838D
+:10CE5000B7FC3FD98857C317ADE3A87C53BADDD0E0
+:10CE600026040194D671C794AA5C2CBB409EAB7972
+:10CE70009CB67A0ADBB76ACD3EBA1CE47B46AE802C
+:10CE80007C40023E654012DA416ED85F28CD65EDE8
+:10CE90004B697B90BBD627981C527DE0067D51DD07
+:10CEA000B4AE10EB6F12DCD07F6B7331AEF765F967
+:10CEB00022C1EF9B8EA1FD51D6762C09E495CAE7DD
+:10CEC0007A587FAB279AF13E2F55EE54397E53E6C0
+:10CED000F735595CA321AFFF41002A8AFC8A470835
+:10CEE000F3535B6494337F3E93CB37B78928CF07E6
+:10CEF000AFBD1DE5F0DC6621861C1728702EF96495
+:10CF0000907DEF93E3AD029763A61F4EDA995C170D
+:10CF1000C07790E39D02F707993D689463552E2FE3
+:10CF200025BF155B0CF21C436E3BA5AE5B61DC7B41
+:10CF3000AEB522DC05DFDFFDCE3DA87F64CCFB284B
+:10CF4000F8FE03C9A0EF4A2496AFA4E2B14A62F901
+:10CF50006CFDE058BF5449BD2C78F4703C657544B5
+:10CF6000F487087CCEEEE10A6C9291CF8D72F8F7CF
+:10CF7000CACF3F4A9E0F73FE51E111F7B2F6903FC0
+:10CF800016A678FA6DCBB398A77AF6856337029E1A
+:10CF90002BF650BEA5F33DD7E2E0F7BD04719D2905
+:10CFA0006F15310F9C48E1BC5B1C5AB96479481578
+:10CFB0002F39903FCA77B07CD2F2973F1A837922FB
+:10CFC000CB7A31BF2AF002B737035D6380AFCB2540
+:10CFD000960F6594F35B6DCCFEECDE1D370BE621FE
+:10CFE0006C61E7F4CB43B7CBC0876ABD1FDA64B589
+:10CFF0001EEE5F0628DFC2FE3AC0A73D77AEE641CF
+:10D00000756F65725FDE26A3BF54BEA519E3D8FE17
+:10D010002D9F609E7BC14BDB307EE06F13F5798FD7
+:10D020005B44DCC7A24FDCAF32E61F56B756E17E49
+:10D030005B7588E7F719F2DF2A5EDAFB7280A2A639
+:10D04000E2D7CF3B410F9CEEDCEC047CD2FE306F8C
+:10D05000F0FB9F49BABCA8D8F9BD5E7D3E6168650A
+:10D06000D47CC2D3F00FCAE00FD838BFAA79985B3E
+:10D0700006F03CED705E5194F87DDFB99D6D9F3FE9
+:10D080000379EEDD3BCE3C037057FEF5D367209F5E
+:10D0900089ECB3E2BAE47FE1F79827ACB6FB858D63
+:10D0A000FBF95B9FC7FCEA73EF9BD1CF39B7F764FD
+:10D0B0003AE4AF9DDBFE5532C4E3EEDD3B15E3956C
+:10D0C000F7EE2C1844A2E877F5097C19BC8CFC6EAD
+:10D0D000231D0EB61EC4BCABB3EF99519FF5E58579
+:10D0E00086AA589EAD9BE783B644CFA357F318ABEF
+:10D0F0005B6FB9E95AD0CFADCC9EEBCB6BBC541E65
+:10D10000E8DB949ED75C06DD5A789EAF816E67E1BE
+:10D110001F943E2103DD3E6F5DF0AB27E15BEB80AA
+:10D120009879A0E1CBC0979AA7FF739B778F0DCE1C
+:10D13000FDED880BA4307A05670860EF7D9E0EE751
+:10D140001A4EC9BD98EFD1BBD7EC827CC6F2BDEFB9
+:10D15000A27C9CDB7914E3AA84E7C99F237D7F2C02
+:10D16000AF59E0F3DBE460F9A31CEF905FEA76E2ED
+:10D170007B9E47CAF856CD2F8D9557DA6B1BC6E2BA
+:10D18000D0FCDC4015F593F8BD597DF9A6423ED0A0
+:10D19000E9982E4F579DB7B13F17D79B91FCE8E810
+:10D1A00079BB6ABE60844E6C1D51F39FCF35F3BCD2
+:10D1B00069FA3E6D2CE4C1B1F5DA1F14DE2551E4A5
+:10D1C00051CD8F3E6333E445072F2F2FFA52F0FEE7
+:10D1D000EFE2E3031B8B57AB78E9FE26BA3E56E23B
+:10D1E00098DD49FD53390EF705987F7A37F74F558B
+:10D1F0007CA9F0D68798DDD0BD85F9074679AE8E3B
+:10D20000715F52121FA7BA6DFF18D03BDD0776730E
+:10D210007E63FC5CDD728CE5DD52FD1CD4EA677E2A
+:10D22000BF84B1BF74DE9FBF3D7A7FFE964FA2F6EA
+:10D23000775AF2DE0EF09FEE6476D2E990382DDA5E
+:10D24000FD36963859973F50EF60F765884E1BDAE8
+:10D2500047F73AF2DF8B4F82A782793D754B791EF3
+:10D26000D0CF3C78AF689D633A01781E02FC68E23B
+:10D270000CB2CB47C04E93538A72457704DE3E7A98
+:10D28000249948504B7F299C06FAFC83EC9332F496
+:10D29000F79F86F8C87F4AA47E1085EB3F0382671C
+:10D2A000A93BB65DAD967D3F1575F18C6A73EF07AE
+:10D2B000609F9357ADB81F2EEEB306303EF60CBB01
+:10D2C00057E3E0CE2F9FC37B797E6526DC2E14408A
+:10D2D0001F94F238C5C99D5F3EF35F604742633AD1
+:10D2E0007EE933B43ED8CF2D7168EFF7EC881F0389
+:10D2F0007180D2571FBC11F44529E83EB0335F1A44
+:10D3000014ACA3FD9D18C8CA27B60DC17301153B07
+:10D310001C984F7870E7AE6AD0F7E75E8A23A0EFDB
+:10D32000CFCA5D7F85B27F4F3C6976A3DDE7D6AE7D
+:10D33000AB0B89E4D6DA731550D6E5B710CC6FC1C4
+:10D34000F81BE5E78AB6783CFFA1A9C7E539309814
+:10D35000DF133518E48EDA8D6E7DDE33FB3E3F8EB3
+:10D36000E92FBFB9F77E761F02ABEF577A4B58B95A
+:10D37000613093DB4EACBF48E557FEBD7FBFACBE0E
+:10D380003F8EC50322FDB0F6D56676BF8691BE3FBF
+:10D390008D13F879DCBF5C19EDFE8928F0B37BB9F9
+:10D3A000041280FB57C9762BE669552AE15190AFEC
+:10D3B000FEB2C2F63F2A9DE15190AFBE87EBBF4A55
+:10D3C0001B2DD3F783391C501FCAC4D2F522DEEBC4
+:10D3D000B4CB8AF7E155BDEAF0A29FF0F297279E01
+:10D3E000CA857CB538CC93AE7AF55F90FE55E6F0F1
+:10D3F0005DC0FFBDDBCD783F69F7F6C3E9603774E8
+:10D40000CBE1F4C48BECEB5485CCBA7D6A751EA7D6
+:10D410006B974C8073BCEA39C3F218FAE2F5389680
+:10D42000D7D11CE7FD15D373FAFB654ED7CED2DDFD
+:10D430009B586E89AEC75A402F68E27862E45C61FF
+:10D440000BF47B9674D50FA624A9127A717FBC7C4D
+:10D450004B461AF8BB07AC57E2BED501D98DFE206A
+:10D460003CB5FAF854AD2747C2F3F499391285A3B5
+:10D47000A7F99392C104F203ADB3A2E9A7BD7171FC
+:10D48000C84FE51673D4F39BBFE3FCB60DE46D1CE7
+:10D490001BCF931519F7801C54008E897637CEA7C1
+:10D4A0009CFA01EC9EA8D939DA73DB0BA506AC47D0
+:10D4B000E50BF1B190AC5772EDFDF5CAC225B93953
+:10D4C000520E2AACAFFBF84D8CD0890492D04E920C
+:10D4D000380DC9FA545DBEBF241759005F0A29727E
+:10D4E000492290BA01E5D44642F8B4533384AD439F
+:10D4F0003504E2E3A7F8FEAC59723F8AF7CD748891
+:10D50000A8CF2F85B777E39C08B759AA211EB43757
+:10D5100066B8C01E13023EF22DE587BADA6939EC0F
+:10D520005C38F142BE1BA6BE51F89CAE435F817DC4
+:10D5300040F98CDD63F57D12ACA3E3C131638CFF50
+:10D540004D66F7D91BC7FB86D38104F6EBEE3B870C
+:10D55000BF5EF5FE3CF0D7E3FF9A0FFB317617096B
+:10D5600083BD146727E1B831704F9E745A2BBF4EAC
+:10D57000C2CAC3283B835E734DD47F37F235F1486E
+:10D580009FF5E94511DB7F6668FFD9C5DAABF8F096
+:10D590005B367A8EE744F062E373084CF65CE8028F
+:10D5A0007C8C717AEA808E4AEF070F023EC6D899CA
+:10D5B0003F98D448B4FE5A8E9DE9ABE5FCFE69FA6B
+:10D5C0005764D7F4475C168C8FAEE478EFABAFC6E8
+:10D5D0004DFAD5B74A80D77EF5ADB1EADBA2D77751
+:10D5E000C482272E3A3C0931FA0F44AF5FFDEABBF3
+:10D5F0006F84DDF092E90D08CEF373CB3976F0AF8E
+:10D60000E23F482E665CC1F6030C74B301FF517E05
+:10D61000B08DD0BC87FFCBD2D06F5814FA9330F2C4
+:10D620005D31878796EDA914BE1F7370A76C62FBEE
+:10D630009573EE6571A21F5B587EE9317E1FD09C09
+:10D6400046E657CF59C2F61149193BE7E3A2FFC19D
+:10D650007877422794DE773608C17006DC5B63B0CA
+:10D660005FFBEEC759A840FD6243DC45E527F53C6A
+:10D67000D23C6E5F6770FE5C407A1D20F7C673EF88
+:10D68000AF71BDA6EAFDC03A9209E7F64593CD0316
+:10D69000FBA3223F674A9CEC3E3FE21DC2EE97533C
+:10D6A000F3B832DDF1B0BE91107FCFF759165FEFBE
+:10D6B0001EA43DA7255DB0E1FD2075B22705F4A0AD
+:10D6C0007C81DA75D455532E0C236ECD39326ACF56
+:10D6D000A170CB2E765FA2E42A22A56007F2FB019F
+:10D6E00048D2F43EBBEB4D8A87C5EBDC786E758182
+:10D6F0009DD999BF7014DD631F07F665BE87DD7382
+:10D70000ABA76360279B5F1DCC2FA33FDC758AC747
+:10D710008376E7746A31601CC783BFEF209ADDEF20
+:10D72000BA411EFF4D66BF57D00F0F8C7EE7931294
+:10D73000F15EF6F9CE551F009FAEE6F711AEA8CD0B
+:10D74000C4E7AADA14B43BEB6B3DF854F162F13450
+:10D75000E0BD6F9611AC3F8BCBC7EC0A6ACB403E65
+:10D7600085E4AA0943D9925643C0DEB5F6E1A70184
+:10D77000F1A3F4957D5836BBD8EF46C88D3310CF52
+:10D78000B43D29A5DF173B7C4F829C58DD57EBEE5B
+:10D790009133A78C35DC3768C09BCA1FDB18FED6D7
+:10D7A000088C3F8CF85B2377BA615F79CDF57DF704
+:10D7B000CE20FEA879CFF0F73BB6CF16137FAE444C
+:10D7C000B45FE7E7D5DF55475F3DC2F7171FAECD22
+:10D7D000477CADE4F7483E54EBC5A708F8A3F33304
+:10D7E000670508DC8FCE7E1B823EED455EB87F1656
+:10D7F0007817F027DA193ECD2935B8BF66B1337CEA
+:10D8000089F600E245B6337C8976C66F0A2F4B80D5
+:10D81000BF1C6C8FEF29FE0E007F59D226E8F0A5C1
+:10D82000244DBE3CFC3D41F147E148E2F265C44372
+:10D8300092C2EEA754E52A961DF7389D3FACDB1B3C
+:10D840006A093E07C6F0178739D8BA9964AAD92F52
+:10D85000033E12095F4F02242D8FB0D443F84B09C9
+:10D860001037940506076918A2BB57527449867B86
+:10D87000D9DC1B800FD61F964D902F2F2E99AE3BD3
+:10D880000F2ACEF226B8119F3EBCA7F9915A37D283
+:10D890006F1DD011EE01E5FED7439C9E0FF37B2850
+:10D8A0005772F958C3E5E5512E2775FCDEE4D5D350
+:10D8B000589E5552B689DF571626DA3CA6044F8883
+:10D8C00028142EB4A9DDF8C47B16C97BE6E048DA3B
+:10D8D0002E2E8B78814F12DE7B20C8EE6B2C4A05F2
+:10D8E0003B2841BD7F71A23B61361E840D4BCCEFBE
+:10D8F000A0AA10FD984E53B47BAAEA3C072C100F47
+:10D900008D054F9CC79BF1101D2FAED181F6FB00FA
+:10D910005FD1EC05B46C6F8CC3F85F1CFF7D163BC8
+:10D9200085BB5443EF58F7506F745C1FEFA0F4743D
+:10D93000018CF4F958E370FC5D96C7E522FC1D9755
+:10D94000C7F97AAADE73AEB6FB9AEB4767EED53A13
+:10D95000BF75BDECC576AE897AF95FCFF56DE2147F
+:10D960003D9FABFAF6789FBEF50D0378922F4C41A0
+:10D970003D96747374BD5B272B786F79DD6826E75D
+:10D980008162859D6BE9AF07304E7DDE376A23E803
+:10D990005195AF9611A67702C4E6C17588DF6FA3D3
+:10D9A000DAC12BE01E40AE5FE1298E60BF3F903CA4
+:10D9B00087DDE7BB9ADF63B596F215C17B4F3DF873
+:10D9C0009CEE60FB13CB2C63F13EB53ABB09F584AA
+:10D9D000F4BE39082687B47FBC0BE20592ECE9F46B
+:10D9E00042BCCF2185E0DEDC3A7B2EDEFB2E24E438
+:10D9F000BA80FE5F38E60FBD583E1D9D28DE97E9D0
+:10DA00004A2A221F66E16E009E5F915D3713881BD4
+:10DA10006E48AAB102DEC63B585CBFB1380FF14870
+:10DA2000F17B936360A49F41B3A6F7DD8305DD6EB0
+:10DA300088710EE60E07B397485A808CD0C879A338
+:10DA4000FA3B27EE00C9D4C8FBB2918504F687FAE9
+:10DA5000CB790C3DB699E9B1E542743DA6DA99AAB5
+:10DA60001E930DFA417DD60F9DA63BA7A524798074
+:10DA700077E1193079C0BE7BB9FE8E04C4430DE056
+:10DA800081A44CEFF35F7F300CECC7BCA8FC66D4DC
+:10DA90005FF3FBD6736F32D0E994EC1E341BF8E9C8
+:10DAA00070F4F57CD263573D0A7C30FF77A2A0DD8D
+:10DAB0004F29BDB002D7D3920BF9F82C6B9C867C12
+:10DAC0004F200AAEF1C34E36DDE704B84E36F23CC5
+:10DAD00080263908F919271BEFC3FB4A20CF5BD4F6
+:10DAE000ECEF935C37DA97EA3D632783F738B5FBB1
+:10DAF000BB25BFB07AC16E8DC55F254DD1FD7A586B
+:10DB000043217E4A01CC047B98DA37BD61B07F3671
+:10DB10009A3D011229071EB346CD4F5CEC98FA38A6
+:10DB2000E07DB1C3FB34C839B1B37B4163F3391B2A
+:10DB3000F7046C02C37ED3933C4F53F239B5F7BB65
+:10DB4000F5DDC7C9E324C412E3BB4DFD7D8318DFB7
+:10DB50009D2C9F83B8A27F57FD84B8889FD006F381
+:10DB6000A86A3C53FF3EE289FB091CEE533283FB5B
+:10DB7000D47366F63B3706BE38C5F347160A0CAFBA
+:10DB80002A7F9FEAB3777C780F8D91FF848D576D44
+:10DB9000184FFBFDB443C6385C25E51FE01B61E36D
+:10DBA00078CC5F171E1BFF28E4257D7644C4EFE583
+:10DBB000172CF8BDFB679E0D7320CEF3BA8CF7755A
+:10DBC0007FD631359EC579F471E8054EB6CE9FE615
+:10DBD000725F726115F2671F7F342C5040AE4A2E7F
+:10DBE000AC457BA6648B80F7449240EFA14912E7D5
+:10DBF000C309D0FE6CE132C0F7C406DCDF28DD6C5F
+:10DC0000F6AC12FAD3F9B4C3ADBB57BDB46B35F65D
+:10DC10004BA83D95A4D9EF3EC5F3804B2FB0FB0137
+:10DC2000892B405280EFB9DE89F0AFFEDED76E6BF4
+:10DC3000F438FBD7DC9E29B93041E73744E6F77D5D
+:10DC4000269F7C3D2FEDCA6770F5CD67C3F868F35A
+:10DC500089CC6322B6EF4E883E7E06C7F389DA325E
+:10DC600038B941CA1456AFA4E13E05F449495342BC
+:10DC7000A2A099576963852E0FA3B4A95899ABE95F
+:10DC8000374207DB6F278D88D02163AD7CDD323BC7
+:10DC9000ACF7450E278CB77161DE4FDCD01FD33F48
+:10DCA0001FCB0DE935A85FEE71463BD790E174EBD1
+:10DCB000E24AA58D9C3ED44ECED5D047A58BB1FD72
+:10DCC00089E6D2BC9F403CF909762B486CBD63A025
+:10DCD0005B4674BC4DE8C35B26E6035D1A6FDFD17B
+:10DCE000E5FDF4C31BA7AF8A17F53DB58F72005F42
+:10DCF0001320E03410FA61F4BF14BE22E372FA4F2D
+:10DD00008A3E0F5FDF3C969000B51FE65F721E0FE4
+:10DD10009280E522F350E94FAED6D1DFB776E475B5
+:10DD200020872ABDE71F7802F9773E9547D8973FAD
+:10DD3000D9709F6E7D88C01783EE2302242BEFFFDE
+:10DD40001CDD3F9603E990F71558C7D691531B1F6A
+:10DD500049D7E279B163D202A00BD934F0B2D68FA1
+:10DD6000C0644F871BD72519E361BB1D3EBF93BE1F
+:10DD70002FE37EF5F284C251D1D67DEA174E84F8A6
+:10DD8000735DEDB489106F93B9DD08BFAC05F6265D
+:10DD90005C811EED7EAD064ED7876A6B307E4D2CC2
+:10DDA00001E2D29EF725CC2EFA9AB0788BDA4E910A
+:10DDB0007D2E887F2A0229427B4EF2ADC8C8853865
+:10DDC0004652764083BFB54E66D7AD4E39E0827C71
+:10DDD0005233ED1FE2319634E9BC7E9F9295B385B4
+:10DDE000F132CC474E0A118C6766D1F71A7C2B4969
+:10DDF00014CE8BF89B92C589FB451261769A3A7FC7
+:10DE0000FA06D7B387F9BAB40CE2B849608799D05B
+:10DE10001F5ACFE394BFAC2DE27890701D3327B02A
+:10DE2000FA4A3C83DB0A716B11D6D530961D70C35C
+:10DE30008E885793E1EF8F261037FE4EDF0012AE2B
+:10DE4000C77B4C2675DD0FEFBD71BE2DC0075FA4EB
+:10DE5000767E20401CBAC87725ACBF8D6220DB4D92
+:10DE6000EBFF4AECCD867AF0FB5EEF25B2E750C8B7
+:10DE70005BF669F6A5D8BD9C6E6D5CCF581EBA44A2
+:10DE800032ECD77C73A5F67B739C7717C091F49125
+:10DE900080FB30755676AF4F9DE3B67858BF8F72D2
+:10DEA0007A21FD817F3A981D735E72C727627C33A9
+:10DEB00033E735DDF81E5D59E2FEDB26CA8F92E6B8
+:10DEC0005ED61192D704FC32B281BED7D22F4A5C03
+:10DED0002DD18ED7DF46DD8751E1A3E312C09F78B5
+:10DEE000A190ADAF063ED82330F8030EEE6F9180BF
+:10DEF00008F49CADDE172C2D6765F5F722808A1497
+:10DF00008EF7D5FD05B29C95F93EA57F2EDB8734B3
+:10DF1000C233BBFDE14E88EBCF6E4F9D07FB53B381
+:10DF2000EDA3FE0CCF3D72EF8138B003EF13F0FC90
+:10DF3000C78F7FFF9A1C479F3BDFDE88E78DCF723C
+:10DF4000B9BB8BF4E23DEC3EE2E2FBE4417C3F17DF
+:10DF50007E600ECB2119FCF439E1E08F6EA0A53B69
+:10DF60005F0BDE0066DB5D1DBDBF0135E00BB90A4E
+:10DF7000710F406DD7E639C4CAAC5D040F166E8FC1
+:10DF80005A705E91795B100FEFF7E58D07901E7D5B
+:10DF900078E2F72AA978E99B77FC6DD321CE1B4B59
+:10DFA0009FCDB667FE996D7E30B88C78FA0C3E51E5
+:10DFB0003BF233A7D71A4FF5DB474EAF0D9E959630
+:10DFC000DE746918CA8B13CAD5A26F6832C5C3D96B
+:10DFD00021BE2B07023E3A075C961EFDC0CAF40024
+:10DFE000C94DC7F9A8F7BE1F7CE0A403ECCEFA9D8B
+:10DFF000EFA6C3B34AEC5A733BC63745F487CEB796
+:10E000005E79D1F3611F40DC89AE7F23E3553E6426
+:10E01000F3BB9B9FAFB9BB350ECFD7DCBD44D4DD7E
+:10E02000DB7CF712967747A4CE31B7EAECF5E53101
+:10E03000FB813880B19F794B26938F06C03EAB6B36
+:10E0400012C6059E61FC356F8A57847CE4092B0457
+:10E050008CB78C3FEE6EEBA2E579C104FCBDA379D1
+:10E060000F2CCE817B08AA3B597C6F90B828FB67A8
+:10E07000103F39C0D671282F02F9B67BDD764DBC32
+:10E08000BF5BAEC9867BF70277DABDC03FC5B77A02
+:10E09000DFC7FB1C781C425D57773516631E6BF19A
+:10E0A0001C773ED0BD3864C5DF1F2CB610C946F5BD
+:10E0B00058B1442CF01CA410C90A4F1BB1C0336FD7
+:10E0C00019BB27BBA47126DA07CEFC2205EEBF2DB3
+:10E0D0006E7FFE73685F2A85F7B3732D0C3FC5ED25
+:10E0E00087BF02FE59E02DC2BCC3EF6C5174FEDF46
+:10E0F000E890BE7C4D9BBE9C1DD697733AF4E5AD6F
+:10E1000070C799C68E38B0D78CEB44C519764EEFE0
+:10E110001501D62688079B519E0A2ADAF3603FFA3A
+:10E12000CC8B0E137CDFF317E6F7F66EB5E27D6F4E
+:10E13000FBFF602336C82B7CC9BA11BE9FB185F2A4
+:10E14000200E47EBB3DFD92A0A8D02FFEDE5AB5570
+:10E150003F3D3806E6F5F25F599E4CEF5633FE7EA2
+:10E16000CA99DDCFBF08FB6267B65E8176D62B42C7
+:10E17000C004FD065632FA1BF9B4628BDE2FBE3F97
+:10E180009EE99B1E81E1FBCA46FDBCAF0AEACB3F7C
+:10E190008F67FED45CA2799F01FBF7EEFA14585703
+:10E1A0009F8D7EDFF0435C2E5E784151F956E4F797
+:10E1B000B311B7E6FCD29EC8FEDDBD57405E05E058
+:10E1C0006258E47D85615CB5FFA278B60F9FC4F705
+:10E1D000677A5F17113FA70DBF5BD867D7D5D6A465
+:10E1E0004ED1AC43258DFB938BC13F6ADA9F3C57E0
+:10E1F000B3BE546E3D987C07E62549F8BB4C95B3F9
+:10E200009F5B3B2109DE8B218017BE43DCAB3BF4D7
+:10E210001B27D4A3F6EE585183F7D2C6FB52A7684A
+:10E22000E4F46FE54B559E2AB97DB22BBFB310F2D3
+:10E23000C42B1AD9EF3755847E740BFCFE22696219
+:10E24000E74CF324522452F9A9DCFEA31FC2EF715C
+:10E25000F99F1EE701786817B7C2FB8A964FF03C1A
+:10E26000C12AC3EF08A8CF7D9CBEB47ED844EBAFD3
+:10E27000BACD5E06FA89F6FB1A940F646EC4FB4DA4
+:10E280009CA7589C96BE7F0F7E12E5D4E4C01B77F6
+:10E29000D0A66748E89D1B3260DE7A3EA37C2B80C7
+:10E2A000DDD5BB59C0DFB5A59656DECD60527B9754
+:10E2B00062DE2DFD7E77B4F3CE0B83FA7E8CF4FF05
+:10E2C00003E75FFA97A9E52363BD013302782EB116
+:10E2D0007209D5771A3BBFF27803DEE7681C078323
+:10E2E000709A7C03582FDD28DF56F5FE21C192C7B6
+:10E2F000F36687B332DE5B08FC4A19A5E26A32C5D1
+:10E300000DF8BE994C83E72B4278AD28323D8171E0
+:10E31000A06D71A827BA5D5DCF3D05FCD5321AE32B
+:10E320004F83F979CF6E7718EF79ECE1F1C96E1769
+:10E330002B97B75B310FE6CC5905F5E8D2D04127D2
+:10E34000D0A3FB45AB097E97F4CCF60193214FB2E5
+:10E350003BC4EEFF3D1D1A80BFFF1A6BDD32EA039E
+:10E36000759D3C06FF84F534DEFB35ACB76439CBD4
+:10E37000231D34A0263BDAEF49A8ED92949A6CF065
+:10E3800053FE17A753B28F00800000001F8B0800B8
+:10E3900000000000000BDD7D0B7854D5B5F03E7316
+:10E3A000CEBC92996466324926218F09841020E000
+:10E3B00024860814EB24040C187542D1A2B63880C8
+:10E3C0004080BC44DB46A55F2624424251428D0872
+:10E3D000087140B1F48A6DB0A8C106EF80F86AB543
+:10E3E00037DADE5EB5FDB92370295A1E23F452DBFD
+:10E3F000DBD67FADB5F799993349AABDF7B6FFF7DC
+:10E40000FDE9478FFBECC7597BADB5D75A7BADB55E
+:10E41000F744BE6EF1EC2D60F01728509C8C5DF235
+:10E42000BB3C9BA0BC4482573318333A7C465B3AD2
+:10E4300063D672C6BCF0CFF186BC5786FA53B2E7FA
+:10E440009BB6718CDDC57C0686CF72BF818D853E03
+:10E450009DD0388BB1650A0B290E782EF4BE2F4D56
+:10E46000A53263D07FD92E29D801FDEFDA6C64CCB8
+:10E47000C4E8EF33F8B7A217CAC5B1F22A16343090
+:10E4800019FE63575C3B187F95123A2AA530B6DA1D
+:10E49000C442C930EEEAA7B4FDD6B010C1D370E0D3
+:10E4A0003363FCF8303FC600B4FF64EABCBC6EDBEB
+:10E4B00034C69C0628C3BC236FEB838887FF907DFE
+:10E4C00034AF35CC4FE3DCDE5AC54EA531D67C5F88
+:10E4D0006BD65DF0BCD87A7FD65D57433DC201DF75
+:10E4E000B730DE9FC1BCF601CED654B3502EC0B7B4
+:10E4F0001CE69B5406E541293405CB26164829E342
+:10E50000EF53CBF87CBD71F0D5B31EFA5EFD2EED56
+:10E510007BF68B34C267031BA27AF6545C3DE0A302
+:10E5200041E0A1E100BC8FC3C3CC0352C07A159671
+:10E53000821D19005FD359C63641A9E9D06746CD7F
+:10E54000F8AC8731C04366126366A0D7A3125BD4D0
+:10E550005F42FD26D64D8136F8771D96DBA9DD0991
+:10E5600081BF476F5991E587765BEC50CE16089EC8
+:10E570000EDFD0E1C7A91C32C17792AE8E96A9BE3C
+:10E58000623D2FD7D98A6BB6E730B64DEFCFB201D7
+:10E590001297C9BED77480BF271DFE5B90DF96E936
+:10E5A000BC790ACE97798B7C00076BE57878ACACA8
+:10E5B00065624B490CAE187C9CBEDBA4FE900EF845
+:10E5C0002C7058F2EC7323DF46F47E4BAC5DB34DF8
+:10E5D000A279A41E0BBF3606E9FEBCC4F642BB1DE1
+:10E5E000D287AF8D817E3BE6B95907945D4027B94C
+:10E5F0000CDFB34E09F0527EA8EEEE5791CEE549FE
+:10E600009EF1F0683C5429375A68FE77FA009ECC98
+:10E61000E4963D3AA8CFBCB3B80CF91BE67DE702FF
+:10E62000787FAFCD4DDFCBB270BABBD6070AD69696
+:10E63000E0F77D77BF0ADF8B4C49F2E0F7330157F3
+:10E6400056073DBBCCD88EB54BD8EED1143E7EBA22
+:10E650004EBEB30ECB65BCEC582779F712F36DA50F
+:10E6600079671A590DC289EF8325B464BC07A93EA6
+:10E67000C8E93BBBA514C7CB1CC79F4E432807C79F
+:10E68000794BA5F760968E6520BCF0DF00CFBD0703
+:10E690002B331DD0FFAD732645970A4F176343D820
+:10E6A0004E0959183E0B8B797B93685F3A3B1317E1
+:10E6B00083334FDBEEA2DE9B7A35E025F08ECC90E3
+:10E6C0001EBFB37853EDD0EE4B063E8F443AF62191
+:10E6D0007D603ECD9F02E46971745B74C580E33553
+:10E6E0007FAAB0E0D5B1F7E7DA4C2C58142B37D419
+:10E6F0001F9B8BED1AD9D006E4ABC6FE64168CE3E3
+:10E70000F72F258DFC5D95BF9B3FD5B1401AB16FAA
+:10E710008ECF8AF8896C588EF01F91D83E86F50608
+:10E720001688FB7EF3A70E6D390A67068D136BC73B
+:10E73000B4ED067E4FEDD8F4700A7EE7822D9CE2A0
+:10E7400010F3C37ED9326B41BA5C0CEA027A58C727
+:10E7500017DCBCFE226335FD96587B75BC0B8B0C19
+:10E760002C44788FD0B8889700C8B69D839F18DC5A
+:10E77000506E183C4A7851F9211E3F8138B991D129
+:10E780003114D2C19AFE856D5557891948714C5D77
+:10E79000BF6BBABCB3A05ED669D6737279747D9331
+:10E7A000587954270B79D0D0553D2BBECCDBC7FA16
+:10E7B00037D654C3FA2F2FE1FD4FD89ADE58AFC495
+:10E7C000E411CC230FF1122D9B12CA16284F892B6E
+:10E7D000DB12EA9D09F5AE84720E6F7FCE1ACA93E2
+:10E7E0003D8C7D645B5BA3807C3997155A2C417905
+:10E7F00073C7BD35D520E71ACB87BC32CACF41C914
+:10E8000023B118FE9A3CCC1B04FC593C61C3B212E4
+:10E81000C4C3D06BB8FE1B06249B047C6EE93F1872
+:10E82000A232F673C7F5EB97A85F43FF87D46FD486
+:10E83000F18B75B48E37159FA4768000DB69A0D369
+:10E840005799C45201A5058AFF8FA8BF1AFB7FC341
+:10E85000F52E8B18F8FCB81CBC90E57D85E4E01122
+:10E86000C986EB2ECA7738AE25C6EF6AFB5F4D1915
+:10E87000FC571C26F9DE4FDA1568FF7F1A7F338DAF
+:10E8800001A97E854D66A05C0D4E447DBC93F927A1
+:10E89000A21EFA7AE3F8A33A6877421FDECD005F42
+:10E8A000C5F64D350AB43B610DE74A2043266DEDB0
+:10E8B000E5E5F4F06EC46760EBA384DF13B9E15CB7
+:10E8C0001D94A7DA43BC3C3EBC1BCBB76E7D86973C
+:10E8D000A7847365E83F3670A0A61ACAFB6C23AF05
+:10E8E000D77C3B97E32A7C97C779B3EDE9C8765C80
+:10E8F0004FECD603C6401E2E5EFDF1B3FB000F8B1E
+:10E90000EF4F2639B5EFDC57E6FB68FE019F520159
+:10E91000F290B33ED763248F15B203B250773962B9
+:10E92000F4B0E60DB949CE4F6A3988FA3E737109E1
+:10E93000C9F94F53BDEDF669B1E72719F00438DA8C
+:10E94000ED362E97659D97DA3F6025BB678B99CF93
+:10E9500007D60DD1D722E8512EE6536ED7D133CF4B
+:10E960003687C6FB40F2EE30C9F8640133D27355E6
+:10E9700012D91977EC01B90072B957C0DDBB7562C5
+:10E980003000E3DF21311FCA8D5EBB370BE5C30BBF
+:10E990007F91EFC4F9F69642199E3F16F2BEB7CEAC
+:10E9A0009B658FD38BBD7B78BD2A777A0B787F559B
+:10E9B000DF6476F0EF646E99B817E791AC302F966C
+:10E9C000972F2ADADB4E7A7B01CD9B79BD5912CC89
+:10E9D000F7F4AAB13AB42355FAA4157A6FC2F9DC58
+:10E9E0008EE35B627452BFDF8EF346BD2F83DE87FA
+:10E9F000F93EE0F0D3FCC10E984A76A0B003DA717C
+:10EA0000BED362F8654A781ABEFFFF084FF760FD73
+:10EA1000FF144F23C88B00B66B6C0579A18B93173D
+:10EA2000027FDBA4903E93CB0B0FEA397CBF00E45E
+:10EA3000E3ED36FF468447FDFEE2071AC9EE53E1D7
+:10EA40004AFED68B355F65C3D759A25D76E203D304
+:10EA500066067AEC84A19FE4E289F9CCD38EF24376
+:10EA6000C7EA118FAA5D5971FF9AB718D8B397ED0D
+:10EA700032D1B95BF266E1BCBA81AE26D4C37586E9
+:10EA8000E0BE82985EECB50777AC40BADE52E20990
+:10EA9000B8493FD27A0BB42653BB5E7B9829583FC6
+:10EAA000C36D034890CE448FC86D86E05E09E9CD02
+:10EAB000F9A577D5A4604022BA07A8FF6D9C7F7A9C
+:10EAC000EB18D9F7BDB7B9886FCC2C68467846E308
+:10EAD000838C0E467CC414EFD43A6B0C0F3F13EBBF
+:10EAE0003AB93CFCFCBFA11DB9D94C7624EA4CDCF8
+:10EAF00077B19E4C8217E8F902F187BA5F7A242B2E
+:10EB0000B889F6679E0AA4C746AB7709C1FFED64D2
+:10EB100037C2BFCBCCBA4C65B8FD609D24EF043C36
+:10EB2000ACE73186F6D99DC23EFBF7FA4B56B403EB
+:10EB30005EB573FB0A19C504F26F29E3F54BD725BF
+:10EB40007F88FB99A5EBE49011F62BAC6B8E371CFC
+:10EB5000B7CF208E82F1FC425EB2ED112BF28D1FF9
+:10EB6000FBA5E0F87FB4BA2D5886FE5391ECD0BFD8
+:10EB700038D6FF3DB16E17CB1C7ED696EC46FC26F0
+:10EB8000CAF5F754F87A1EF3C67F4FFD4EE2B8B0CF
+:10EB90008F7B1FF105780FA5A23DFF6D99E89A08BC
+:10EBA000AFD31079C80CF58BDB64FB7AC0A7BFD557
+:10EBB0004AF355E1BD3333722DEDAF12C63F93DCFE
+:10EBC00054A1E0FCC5FE83ADD3EEBF1833C4CAC068
+:10EBD00017CB5984F631C3DE8B7D6BE2BE8FB1BF9C
+:10EBE00018E3DBA9EB85B9A504F8055FB92505E9AC
+:10EBF000E69738DDA2F44E805BC5A7EC18199F4E4E
+:10EC0000433817E595BFD5487848ECAFEABDC7CC87
+:10EC1000B03E80AFB64B12F1E3F6FB92498F311351
+:10EC2000A763F3EA2437F2E74E43E4695A372F1912
+:10EC300019D2F5A239F202C9A342EE37B8F83379F6
+:10EC40000FB6BB90CEF9FAC2613DAD270E0CD83B92
+:10EC50003F93F752BDC4C7BDD09EECC6F5D88C9883
+:10EC600084EF3707FEAB8D01FE4EE9F83EB87940E0
+:10EC7000BBDFBD00FFEACB6272E122E3DF090C706B
+:10EC80003900335D45DFB923896D82719B7492171A
+:10EC9000EDA3A6D593821D9C5F4CB85E1A04484D27
+:10ECA0003AD8F795C5D67793EE6411EE9B1A4C9B34
+:10ECB00087E414AA3F8EFB2D86FB25E8B71A3B1587
+:10ECC0000CE7E7A6CDBFFD33C2DD74484BF78618CD
+:10ECD0007F489F49D83F8E5F0A627C40F635CA87DD
+:10ECE0006A161C2F713F0C96936B8682E887691613
+:10ECF000FE89F463E1B9C81FD6F27EB6149ECD67D3
+:10ED0000B97D317370CF2BB8CFB5D70CE5E2349B0A
+:10ED10005BD75E7DFAEA187D5538670C6E9571FFFA
+:10ED2000A6DA2571FBC7890BA6C43FD7533FDC8FFA
+:10ED3000E2F7C2F80AD785C2F5D936A1CF40EF91E4
+:10ED4000DC5DDE3381F41EEA25945FEA7E16E51968
+:10ED5000CA8F271D558B1C30CF92B4AAAF38A6F1AD
+:10ED6000EF901D8F9BA019C3F199A857D476B8AF27
+:10ED70006DB18CDE2EEAE7D991CAE583225179C5BF
+:10ED80004FF57B36117C0AF1CBDADD05246F557F18
+:10ED90004C83F043AD10FE9B15C27FB372BB91B99B
+:10EDA000E3FD55416DB941ACF74616E67EACFD502A
+:10EDB0001FEFB7A966212BD6A3FF069FFDDAFECD74
+:10EDC0002C385B41FA0E7C668C7FCF7AF97CEF148D
+:10EDD00074DF61E67E9B99EBF6C8DC19C5E79B5AA8
+:10EDE000E62D7810F5C49B7AF22FFC87A0938A1742
+:10EDF000A3A3EAEB88EF24DC8F61BB078D8497D354
+:10EE0000A08F0F0ABFC602DC67B6F9B30A0B113D2B
+:10EE1000B6BC05D6E1F8DDF492B91EF965B343A797
+:10EE2000E1A72A879ECAE4EF41BCB727935D0D682E
+:10EE30009E8A7C543156D5936C2AFA993ED483BD70
+:10EE400005E5A65B2D7E1C2F8C7601947708F9B51D
+:10EE5000C361A0F1D472741F27F805BE43E3A1DF9C
+:10EE6000C517C707C168FBADC25EE47261DBAA24A7
+:10EE7000924731BED531E2DB129F01FD452F0939A2
+:10EE8000F2122094F651FD662E47142E9F5E3A3BF7
+:10EE900089E4DE1B1FAF26B972695112334AD4DEF2
+:10EEA0002B61FDF3C6E07A28DF25FCA82F49DC0E94
+:10EEB0000C1CB1D2380D06FF0EF42B343C37DE03A8
+:10EEC00014632F1882DF7F1AEB5F3693DFAA218548
+:10EED000C3D9F0D21892933FD6079FF901F9218C3C
+:10EEE000649F3524B953A9FE27690CEBBB92FD83BF
+:10EEF00048CF6C23B71B1B0CA1223BE0F16490DBD5
+:10EF0000BF2751D0E0F88356B26B00CC2CFCFEA991
+:10EF1000EE4CCF26770C2FA71E9A4CFCBF4DCFE9A5
+:10EF20001638CCFD9A27F5BEB959503EF97CA90791
+:10EF3000768EECA2CF1032008CCD5BB8BDB64CE71C
+:10EF4000EE6B45D9F472B247B3DF7C78652DD637C6
+:10EF5000AF5E7713CAC1D1D633CAF3787FED0516F9
+:10EF6000C9A3FD66FDD8FE107CF7C2E0440FA94797
+:10EF7000E60262039FD878DBD37AC037F2D7113D1F
+:10EF8000F1EF171D1FE78BFB3FD42FF89D6690BF55
+:10EF9000513F32C9DFB8B23C5299D3B3F9A54C61A5
+:10EFA0009F69EBEF48F55F40B9D6F4DDDF9F682538
+:10EFB000FC4648FEB11EEE1F3FADF72E463EB5574C
+:10EFC000870C4BE3F6B78634BE8E9619855E6721B3
+:10EFD00043FCBA53EB2BAAB47CAE3EF5697C1F69A7
+:10EFE0001DE2727C78BD4EAC9BAF18516F71D70D8E
+:10EFF000ECA7CF727F8621CD4DF533CF860CCBA009
+:10F000009CBF2E6458219EB82E00DF2113CCFBF448
+:10F010000E2B5FCF80061C67C57446F6C80A19EC34
+:10F02000D0327CEF1E08035DCE3C6FE7FCF527C0B5
+:10F030000AE07B0913ED8C60B782DC7AB1530AA138
+:10F040005DBF64BB71AFB900D7B157B6223D774BF6
+:10F0500024B796745616ED80F2EA435388FE29D3FE
+:10F06000395FAE0EDA49FFCD147270993168203BDA
+:10F07000FA19EEA783F1C91E6E804E5965C3F1805F
+:10F08000F25BC30F416D9C6166BF90A7FBE3E20B8F
+:10F0900063E3E47A7F427FB0E3B4FC1150F50E974E
+:10F0A00073CC9D89724E95C34687AF348DE452610F
+:10F0B00026D217E8C9E5E44189F0DAC85AB8DE106B
+:10F0C000F23EFA5DA12FCEC801AE978C5BE93937CD
+:10F0D000AD80E8B61AF50DF9CDF9FE6E343E989B79
+:10F0E000A6137271643EB85EF041C35916BA16BEDB
+:10F0F000D7B08E851AA7F2A7752AE941AE0F4D2227
+:10F100009E61E2F18ECFD38B897A7098DE4BD077F7
+:10F110009906A1DF049DE3FDD9A8EF67AE0BCAE80D
+:10F12000D7CCB379AFCD4C8FD92FCDEF994CEEAB77
+:10F13000B0EC63632DE89FA97CC685FE5DD88FE3A4
+:10F14000BA4A06BCEC81F7BB55FBD6C5E7EB32707B
+:10F15000FED52B3E566A41BA0CD17E3592CE6CC894
+:10F160008F2A3E775BA15F19F6E3EB2DDADFC43A15
+:10F1700093E2FA57BD6426B97AE5B0356824BBC37B
+:10F180009F6F87F1327E65243BF4C24B56D29F17A6
+:10F1900084FE73AAFB7EB681E8D38A744D476EAABB
+:10F1A0001A83FE5326CD1F832250B5C31AEDA3F94F
+:10F1B000B3457DC1D0AD9CAF8CB45FBC620F7F13F3
+:10F1C000CB000F43FBBA05E98CFEF643B34B1F801F
+:10F1D000F7CD3E8B8763DF5F8AFC6A94EFBD15FD38
+:10F1E0002A73E57591FB601E8DB9169B11BA54E721
+:10F1F000FFFA97B741F9A3437A66443AEF9BBD887B
+:10F200008D1D5DFEAE0AEA4F86E3D6CB9AFDDA721B
+:10F2100063BFB6DCCC9493E13879FC589AD5796613
+:10F2200032C90ECF67C0DF4663CBD93D00AFF1C70F
+:10F2300046D2470D69FE5D69E837D5455E433C1B04
+:10F24000F3CF4D453F4555FE9F28AE73E5DBCC839C
+:10F25000705F315792FEBEB2C3EC0EC4C9AF66C137
+:10F26000FFBD79B554DFBBD3E896787DEDB40AB421
+:10F2700007E9DBF867D201FE9BB7CFFB88F64D6844
+:10F28000B543B917ED4BECF79C146C47FB713BD7BA
+:10F290007BE7C17E34A1FE14EBA9591E9C6B82FF53
+:10F2A000EC75D44C44F9A2FC59F121FD37E25071C0
+:10F2B000F6EEE1E8FAE47E9C1BD08F338EFC3887B3
+:10F2C000516E349AC2864A18E7BA3FFF8EE4F2CAFA
+:10F2D000D6A564D7C7EC5C23C99195F7F9E9FD2B56
+:10F2E0003BAEA7799D8179237ECEECE6FBB99539BB
+:10F2F0009620C2779D9DDBBF2BA19F240DC74B227B
+:10F300001E7EB3EB7A17D2FB378C7F2FD0CFED84E4
+:10F31000DFD8865248FEB85B52D0CE6BDE7EFD470A
+:10F3200028B756EE963DA8C7D9112BF93D56EE9E4B
+:10F330003371B905C7B99C568978EB9B6393E9BDD6
+:10F34000EC0B72FFC9D075F05EE9BBC68DEBE4F83B
+:10F350006E2387CF6E7A1AE1BFEECF32F1BDA26382
+:10F360007EB4577B0DDE89B8DEDCBBF6CD45BCFE36
+:10F37000A62E5B47ED9F95980DF1606FCDC0F72BE2
+:10F3800025C587EBAB7EFBAADA787BA4334D267CC0
+:10F3900057E6AFCB085B88DF6F453DD7B85B4F764C
+:10F3A000DDF1051FFCF236678CDF57CA3DB7CE8C06
+:10F3B000B3379A77DD28F8013436E069A5C0933178
+:10F3C0007F5D117EF7F3F87FE5FA96221E8FF9EB49
+:10F3D000EB20BABE77F1F5F007D0F7B45FCF7168D4
+:10F3E000ECFBD1F641AABFD9E461DE7D168A1B7A17
+:10F3F000719F9BE754A83ECFC9ED6CE50F6BF7BF3B
+:10F400000DF0F7A7F98D4E789FCFBCA5485777C46C
+:10F410005605E6244E89EC1FB6CBC8ED4985FBDDC9
+:10F42000B6A5B3A737C5C1998DE3A5D3FAB43961A1
+:10F43000DC0BEFFFE935C45F53DEB9A93C9EF63B18
+:10F440008A4F590679DCD2E2F131E48BE6C13A7693
+:10F4500057494C1E367BB8BC4E9CD77227DF6734A9
+:10F460003B23344E753A5F67AABF77676B12F9F595
+:10F47000763A8366BEBF0D3094E73795CB3CDE22EB
+:10F48000EC129FF09399BCAF308CC7308FEC190F02
+:10F49000E521EFA9CE3428BF5D3EC72343D9E27DE5
+:10F4A000B26B2CCEDBA317F5E3C85FF8D6AC4AB23B
+:10F4B0004F6EF2CAF45D569F42FBF521EFCF9D7768
+:10F4C000C1776F66DEB4D3F08D1A50D648C721FCE1
+:10F4D00036DA018ABFDC19E75FBDD1332FED74BC8A
+:10F4E000BEF472FD8FFBF17E113718090F25699567
+:10F4F0003311BFD77D99D3E1E367F9FEE36333F7B7
+:10F5000063ABED3EB6723D53EB94841DD89F87727A
+:10F510003E5AFE5AB1260EEC34F4E7E13AFBADA4B4
+:10F520001D6775978EE2B3ABBA18C5633FFEFE8BBD
+:10F5300079286F3FDAF762DED238F812FBA9CF5B89
+:10F540009D5ABF94EA87748AB8F4528F91FBFB46A8
+:10F55000F143AAEDD976BE1FBB08D21DF94EED7757
+:10F56000B13EC98B76E545662279B67450F835BD53
+:10F57000DE4227EE1FD4FE09E36F41FE01B8A4016D
+:10F5800089F6E7C9251192AFAB4CBED7C6B8312F6B
+:10F59000C54BF499877494905FBD069CB722F679A9
+:10F5A00046C5D788F45CDEA3A56396D326E2944EC5
+:10F5B000A2BBA1C9A2A07EC8E810F2FA1B3ADABF2A
+:10F5C00018B25D16944BD715257562DCDD9994321F
+:10F5D00015FDE6B9D9C5D43E50C5F93A90C1C86FFA
+:10F5E00095C55A2492B736EEE7CE99CE6C98E7F1DE
+:10F5F000A293DB832EE6D92E933DD82F91BF5FCC0B
+:10F600005F95EBC82F28E73E964CC42FD2A044F656
+:10F610009DACEB5F8CE38EC63FBD09FCD3FB0FE6D0
+:10F620009F3EF57BC3F8C74F71BAA52ED3C8FC2304
+:10F63000FCAA5FB8FD6871C26F98543FB384F3AD04
+:10F6400015E3D59A2C21792AC98773F1FED45D6020
+:10F6500067E27E448D2B8EE958E2E676FA5018F781
+:10F66000E5C9D79848CF7D47375480F67C629C1116
+:10F67000286B47798F3286FC8AAD55BED36971FA03
+:10F68000FE08DF3734DDE7A5F7B307B97E6F2E3408
+:10F6900090DDD93C200590CE4D3E43D0544071952D
+:10F6A00025A4B71F32BB799CC4DD4E71926FBB7924
+:10F6B0001C25EA470DF73D80FC566F21BF4362BC15
+:10F6C000E585BFC8FCFBE3197DBFB794C7777AE730
+:10F6D000B9C9AF911847635DDAF5ABC6512E5A012F
+:10F6E00031F0BDA59BCD44876C99E399A59AB87E6E
+:10F6F000192E07C85F9B315D1046C43BA2EB1A244C
+:10F700000396B345BD1A9FB196F80AD0C2BD3DED30
+:10F71000B93793D2FF967C86D6EFFCD57C8680B134
+:10F7200016F3194C683D8B7A041BF4AD5AF69ADD3A
+:10F7300018BF89D52B60379A0624F1BDE76F98531F
+:10F74000087890D4EFAFDFE4B550BC58F3BD78F83B
+:10F750009484F1F530BEC52DDA070ECC9BA3505C26
+:10F7600052D47FD68DF91B5BF4DAF108A5A23F16BF
+:10F77000D4EF1DCF9CFB9DCD3931BD0F7680297D07
+:10F780005A4CFF6FFCA0B6E72AF856B2EDB201F56D
+:10F79000AAAAC79B9D3CBF2171BD3AD2F97A05FB4D
+:10F7A000D5914E7283DBB5B5223E09F6EC5C5C5A0E
+:10F7B000CDEB7C0CE393602F64A4631EC3FBE7CE08
+:10F7C0001C45FA2DF898ECF9E64F15EE7701BB03CE
+:10F7D000ED7393E07336A0277DABF2C16A217F7A87
+:10F7E000EDA0EF915F8F48D302C4172D79B7000DBC
+:10F7F000EE4FF7BA697CB1EF4A8477463AF7933413
+:10F800001757ED28C2F19F9218EAFB4DC52733D058
+:10F810002E691EFC3063795CBF55038F121E56EDB6
+:10F82000D78F38FF19E9DCBE6C3AFC3CF9073F0E74
+:10F830004AB496EB9560F74C28D7D7EBD04263E5F6
+:10F84000C125B791BF7F91818D87F9E50B7DD4BC30
+:10F85000FF2B8199B83F837F12BCDAE95B417A6F55
+:10F86000E7229305E30ECDC54BEF263CD892BC882A
+:10F87000874DC55559F89DA6BAB9368A13807D853E
+:10F88000F54DF7DD4E7E1315AE4D03FA1AB4BB2AC3
+:10F89000C0CEFA11C09DEB985FE381F537463E5824
+:10F8A0007A8F05E3C223CBDF7FC9E0F4EC947C813F
+:10F8B0009BCBC94FC8E2FD7EF903DC9EAB4B37689A
+:10F8C000FCC275E9DCCE9C15189A8DBCF7B2124EBD
+:10F8D00046BBB799793FC1FD25F359DCFB884E5CE7
+:10F8E0008E38DBDCE43F3239C3DFB90AEB6729B479
+:10F8F0007F604AF811FCEE856EA7671313FC8BE559
+:10F90000FB4A822847FF39DDBF18F9AC42D88F1770
+:10F910000E5F5F8A7E36D53EEADE630E621CB0DB88
+:10F92000EAFE6E0DCAC13F283CEE6D8A0CCD467AC8
+:10F93000FCD141E3769B83DD48FFC0563DD51FB621
+:10F94000FA5721DF9CADAB29A2BC1B4BA008E3BC3E
+:10F950007A670F433B01B60BE44F30397D0CE3A1CE
+:10F96000B3034B1409E57C82DD315BE48F92F084B4
+:10F97000F755428C8D072E3863A225D0F9595ACC01
+:10F980000E79E34F0B157CA9DA273A138F67552FB1
+:10F990004A6232F2FD86C86B3AF45F3B87C87E6DDF
+:10F9A000EC97E83B8DC5CF513ED81A917714CDFF27
+:10F9B00051C2940FB53E3D59E8F14ECEEF6C88F63A
+:10F9C000CBEC00A7276361CA938AED23DAA99D3A9D
+:10F9D0009E41F8DD1B85DF053418D53F94AEDA076C
+:10F9E000EBC553CDEBE2DFDD260D7965C46BA9A431
+:10F9F000F117ABCFA7D2B97D987A2C3217D76FE425
+:10FA0000B09AA7C9F330774C9BE441D369589EE67E
+:10FA1000C02773916FC0D0A6F5DA34F0C5F234BFB9
+:10FA20002FF60DFFEB799A1EC9BB179E3F4AB7739D
+:10FA3000BF959AA7E9E1F853E36C89F99917B242A7
+:10FA40000ACFB70AF7ED43FE1C30521E57EDC0EB4C
+:10FA5000EFA17EAC35B17E8C4326DA196DB6AF0CC2
+:10FA600022DF5F3C7FA6EF418679BA2F78285F239B
+:10FA7000C17E48DC27ECC52659A3DB7BEF46E9C9EC
+:10FA8000EDBD68F97FDDDEE3F67C601FCF0F50E54A
+:10FA900079B3D89F5DACBF94827AE644149E843CCF
+:10FAA00086A7441EC3E0C8790C8AC807027B3D4084
+:10FAB0007C7290C775DE783A99E4C7259BB217ED42
+:10FAC000A5F3D6C83711598AB0933A8F18DD282F7D
+:10FAD00040DE91FC0E1CD4F3380DC66D308EF3F26F
+:10FAE0004411C711F1A29792C96E694871A7627F4C
+:10FAF000354EF363A16F1A92787CA62BD97F397D9E
+:10FB000084B8CD1E617FED81A16C38DE7B4611C7C4
+:10FB1000060181FB9D877279DC41C46D2E8AB8CDC8
+:10FB2000A9625DC8C0FD10E4A77277292C0BEADD3D
+:10FB3000EF99836EEECF32E940EF2F53E3362F7308
+:10FB40003FD532119F39B5602EE5072DC7FC7719D7
+:10FB5000FD18DCCF1CCDC767361DCE670D888B9D89
+:10FB600028620280F56BE0B5A493D09E707742992D
+:10FB70008C656F4F0D7C7769A78EF623CBBAB4FEE8
+:10FB8000F22B9BEEAE41FDBDB193C71F035D12E9A1
+:10FB9000EF65CCEB427B43E587828C34A273A053A4
+:10FBA000E7C5EFCCC8E0FE04407D90E6279E9D7A35
+:10FBB000E1671770B4335D089F3A893F37DA949A4A
+:10FBC00011F5B218AF53DF62AA443B3657477EDEC9
+:10FBD0002B06EF22F2933A8A886E9DD696AE1A5E75
+:10FBE0004F6BE58A39E2A3FA6B156EE831B703E58E
+:10FBF00064668688DF24CC77798FB69C187F581589
+:10FC0000D4969731FF842C3C87B05FFB3E3383CB87
+:10FC1000A92B9B0A849FDF437EFE4EBDFBDD029431
+:10FC200053DD0AC9C9F61C8E2F5D2E7F8EB5572F66
+:10FC300022FBC00E7605C1CBE11F7BAD53427DD9BF
+:10FC400069E77CF93F853B11DECA8C226E27A071E3
+:10FC500087EBA85B0A727C71B8BFA8BF626986F0A7
+:10FC60001708F9132DFFEFEF37393F76CB62BDD977
+:10FC700048FE2C15F1C65392E7E910BEB7805D002F
+:10FC8000702FEB96CBD03E99FD150BCDA3E9657394
+:10FC9000D008F58DEBC279B88E9AAAC2452D23E023
+:10FCA00015A15554B905ED963A617F80EBB64B1B13
+:10FCB000871A1E57F47E2B231DF721A70EBE8EF444
+:10FCC0003E6826BD04FF75D488FE8EC305642F4DA3
+:10FCD0004DF5B765A03E4F0AF57DAF00ED136E1FE1
+:10FCE000350E1AF7A0FDB7B4537B6E866DD6C6B934
+:10FCF000589783FC19AC57FB1ECFA768FA0D8B7B76
+:10FD0000713DBFCDE09F8876DD755FE6F1F5F3AB21
+:10FD1000740CE9BB4CF6AC403972DEACB5BBCF5BC2
+:10FD200039BDFAA274F614219DFB46A5B3A708E9D4
+:10FD3000BC4CC7FCF1E334229DAFC6EC734EE7F335
+:10FD4000CF5F5384743E77F09A22A4F3367D8F17E9
+:10FD5000D7CD930EFF5EC4CFE9393EB29BD4BCC968
+:10FD60002FCA8F8732B4FA305AFE3BF93F46D3830D
+:10FD7000A1281C5A3DE834B873501E2E3519FFAA2D
+:10FD80003EC4BF11FD692623F9235EFED3E58751EA
+:10FD9000BF050665B23FD4F15E56FCE3D05FF0F2DA
+:10FDA0007B2E4F401A7DFC066157B94C2C807E0F8C
+:10FDB000D5DE57EDC64479FC0B319FD319DE1AB45A
+:10FDC000B355FF6CBD18D314BCCCEDD3A724F2BF40
+:10FDD0009ADCFD3C7FFEC8121BFA67CF06B93FB61E
+:10FDE000E9F952F2D7AE0ABE12C2FC273628D97002
+:10FDF000DFB0EAA90F53309E0DFBD0531971F19576
+:10FE000039621F7A36782A05E3DEF0FD6AFC7EB29D
+:10FE1000336240FE6D82FD1934614D4A84CE0D354A
+:10FE20003919E9FBF201ED7E4D8D4FEEF41948DEF4
+:10FE3000ED1C9482B83FCB30F80B72503FB11CDB05
+:10FE400099E4D87AF924C36BCB9C161F17F65ECEC3
+:10FE500088CB570AEF48253E0CEB9997EC801D564E
+:10FE6000219778BCE63F77D9833C7F89B7FFCF6085
+:10FE70000195557DBD429CC35B21CEE1A1FC0E25C1
+:10FE8000C8EFF87234DEAC9E3703791E1A29FE1DC6
+:10FE900097B714DFBF8945447EDE6746CDB8D17C75
+:10FEA0009D965237C0BDE66B163A67D80C7CDD5A7A
+:10FEB00016E3C3063115950F9B845FB7B9FE24ED99
+:10FEC000039AF17C05DA551ECE870DB03FC2FCCDFA
+:10FED000C475CBFAB5F98CA3ADE329995ABD122D9F
+:10FEE000FF83FC98D333B5EB579DBFEA078FCE73E2
+:10FEF00050E2EB2B615E89FBCA44FFB5BA2FFCA22E
+:10FF000072EDE64CAD5C8B96FFC172ED8ECCD1E408
+:10FF10009A363EF037CBB5C4384121F77F639C0059
+:10FF2000E3B6FFD338C147EE9E0C1DCFC3D7C44FF5
+:10FF3000BBA4969B4CE330AEC8E3CB8D5623C56182
+:10FF400013E3AACDEEB9228E38F4CB19A8370FE906
+:10FF500019EAF37ACB4A8A5736CB070C78A4705843
+:10FF60003C51394A76FBDF1A575F9F198DAB1760FA
+:10FF70005CFD15CBE5347F1C3DAB4AC0C02F193D5D
+:10FF8000DF68B3A053B2C88B302901668FEB3F5AAC
+:10FF9000BFDE4C6E27BF22F2635C069EC7BEC50A59
+:10FFA000FB3098BF4BC7F377EE4FF76D43F968729C
+:10FFB00073FC3E71F8AB0CCF1D3DA1EF27391268E1
+:10FFC000B478501EAA7E17757C45F80FBE28DFFF57
+:10FFD0002081EF7FF077E6FB447C0CA872E76F8D01
+:10FFE000876D07DC68D607A3B8D75B18CF2918CE72
+:10FFF000C7A38D331A3FFF34D3F75A26C947EF54AE
+:020000022000DC
+:10000000CACBFD82F226B93C720AFD3BEC90D18D41
+:10001000FB0D933897C13667893C4A4F451DE51360
+:10002000F3730DEAF98FD1ECC20FA3729ADB851F2F
+:100030008E2AA7FF7B76E1030EDF299CE7E94A6F52
+:1000400011EACD8D56801FF77BDF378E78CE423D8B
+:100050000F00FCC4CF9B3CCBE3E0897CF58704FD1B
+:10006000F287BFB37E194D9EEA5D2A1C7F67795ADD
+:10007000FFC714F47B8E3E4E80E0A8A81AF28AB81F
+:1000800015C3B8913A8FE6219E7F9621F2AAD4F744
+:10009000116117DEE9F266BAA0FFB9F74D26960A9C
+:1000A0002610F218DA633E0BC5039AFA799E48D3FC
+:1000B0003A46715FF51C65D3401D43BBAF3FCD5F32
+:1000C0008079601B3FB004E454F4932F6068EF5DC7
+:1000D000789F971BD2FCE3294F6C5D581377A8F8E3
+:1000E000ECF206F46700BCE41F708AFC4C15BE3AC3
+:1000F000179767EAF32681EFE8BC9C1C4ED62F07C2
+:10010000D14E4C760F911FA9E91037DE2A642FF9E2
+:10011000EBD91A079D9F683A54594AE7CDFBCDA504
+:1001200068E756FCAAD686FE8973D73A29CF204FB6
+:100130000EAF423BEB9FD3FDB3105E6B79701EDABE
+:10014000A9F960A7A2DD7BEEE0BC527F9CBF7B1BC0
+:10015000FABB61DC6D56AD3F9B99789E78FD5E9E43
+:10016000077CD8EA9F8BF8DD66E6F006B68ABC67A6
+:10017000E1E74E5CFFEABA8F9E73BCC344716955D8
+:100180002E6CD3333FEA3D559E94883C39C007CF4F
+:10019000D31BACE3F91EA26C716AF3154F67CC292F
+:1001A00041784AD0D13B0DEF518848E8775F2EE285
+:1001B000F0D78B7C0A357FCAA8F8BE8EEDD9BA9AE3
+:1001C00058FC7D2CF617F177912793FC29B79FC730
+:1001D000DA0CC43756585FE41F01BE41FACC8A0CD2
+:1001E000CDC6F34485BDA15988CF973FD5113E9424
+:1001F000BAB7287E928A648371C66D0E774F403FEE
+:100200008AED17D7225DDC3DB62A445D7F9AAF9117
+:10021000E0505A8A715F59F5AF7A9E07782499FCAD
+:1002200003BD790D940778E103E388E746D467803E
+:10023000ADA7BCBFB1033F273FBEF59034623E6718
+:1002400097CBC2CF0D078628BF8CCD72123E942368
+:10025000BFA2B8AFD2AD9007A353EFD5E139A84004
+:100260003B23FFE5F85E9B0EE9922FF24B2EBEFC7E
+:100270005F53FDB44F51FDF6419E0FA40F6FC07D3B
+:1002800097D21EFE32AC60D678C8AE6B2AC1F1227E
+:100290004D3CAF3D99219FE40F8C5BFF2528E7770C
+:1002A000D99884F2E7A535F9E42F85798E1F619EF0
+:1002B00077BB78FE8E722459877A4BD9CA28FF50B3
+:1002C000B1675411DC8F4219C65923F8468D470295
+:1002D000B82ED44777BAFCBB11CFD17332AD49FCED
+:1002E0009C8C3877696DFDE0593C7FD267E0E70C64
+:1002F0008FBD3C7901F9EDBA1509E970C5BE24DF5F
+:1003000006EFF78B756B558698CD128FFF63946F50
+:1003100039F608CF4B53F49C4F946EE71EF40B7ED6
+:100320009AEAA7BCD26B3B4332C5B36CA71FA97135
+:10033000C7ED6BB6733DD2B49FEFA713F7319FA7FC
+:100340003F8EBAB47649B4FC0FB24BDE4AD01B7F65
+:10035000F3FE8469F77589F649E23E6E98DD9D30BB
+:10036000DE68768A9AD75115FB0EF1C32B56D50E4F
+:100370000A68F25EAA2CE2DC9B493BFE53224F47FF
+:10038000CD83C9E870B7635E79E4DB8CFC6C6A3EB0
+:100390004EA08AEF1B023A139D8773B11ECAC31980
+:1003A000C3429244F67F98CE7566623E0EF47BDFC0
+:1003B0003596E0DECD3C5D32C943B784709B318F0A
+:1003C00083F236833B56E0776EB1D077CC98C77115
+:1003D0003586E2BD3B507ECEAEE771886CD0B7C8A3
+:1003E000B7D9859C0FCD8B783E879AAFA1E657A8E9
+:1003F00078A812F8CD9EB0A200F707DD92FFFBEAC5
+:1004000079DAF873D2D1F3D1ABC6D27993E8F9B9DE
+:100410004226EABFD839E9447CAAF91D5536BF2DDA
+:100420002B7DF87959953FE2E84670ED3CC2EDF539
+:10043000AA7A03C17F71D57CF2235E5CA563B86E96
+:10044000AA068D9CDF12BEB7337A0F46D04CF75DFB
+:1004500008BA7F9EBD0AF42C463FEDB1B69AAB4F69
+:10046000036E8FB7F9E879D12CF5CB57D179C6C592
+:1004700028992E67EDACC57B0A2E5A237978CFC117
+:10048000E5EC076FA4727AE4049653761EBA11EF76
+:100490003DB8383ED287F71E14EEACE4F5C883D9D8
+:1004A0008C5D9555716380E6CDFD4EB363E7B3CBAC
+:1004B000113F8D2CBC6188FC3B3C7F1FF3FD900EEF
+:1004C0002E8B81EC1997C8B364D522EF12233050DC
+:1004D000EEC82AA578B585B90F0D617D0E3F2704BA
+:1004E000F5C4BF1DE3B95FD824E8CA72543F52383F
+:1004F00080F2A9A3C04EFDA372F49031C8FD59FC4F
+:10050000FBEF3C3F85E24B6AFE2863B6DC8553284F
+:10051000DF445356EF37608A2D17ED850EBDB04B83
+:1005200045392DD55F97156717BD33E75B25B80EA5
+:10053000CEBFF04021CAA5EB0D60B78F20877E9D0E
+:10054000CDE5D045BDA54B023BEDE729FEDB719C17
+:10055000F79217CFB5C3BC16A5551AEC086FE0FB90
+:1005600032CAC574416FFB420E9FBDDA272D8771D9
+:100570003BCCB07EA17FBA5FF1529EBD7FA1740BD0
+:10058000C0DD2171790B9D52695F52EC4EC5FCE5CF
+:1005900006715E5216EB7E46FF5619EDE977DB06D3
+:1005A000662A8531F87E2EE2CB3F2F6077D68DB05C
+:1005B000DF6DCDE2727B81EC9E827CB4411A78AB18
+:1005C000360BDFBBE9FD9C94D672CC3BBE3EB9A591
+:1005D0001CF5CFB0F7A9F0BE24AE6CE4ED1A4C9137
+:1005E0003C3C9FEC4DF6AFCBC2B8D0920F296EF9D0
+:1005F000CDEC774E60DEC13BFA9ED929A85F0AC4D4
+:10060000B97EE1377C6D82EA3734F1F264EE378CE3
+:10061000E6734DE1F964B50BF939C55A91AF30D79E
+:10062000C6CFF5CC2D2FF074008837B18882726F59
+:10063000EE7BBE14DCB7B385FE72DF94D1ED19E614
+:10064000D2BBE3D7EB3C775C19FEDD50AC2DDFE885
+:10065000D1966F9EFEE709F1E53DC9DE1D38EF1F1B
+:100660004B3CFF313083D9689E4E298076C7E41712
+:10067000B3C5F94E9EA7F74F625FF4E27446F519D1
+:10068000FB4D7B31FF5DF533CBA27EB28B99F21D22
+:10069000FCBE00D4571149E4FB392996C25EB8DB91
+:1006A000C6F1076D0D30CE0B4BDCB43E322C3AF662
+:1006B000655C43E526B2432AC69892906F8E09BEC8
+:1006C00053CFEBAA7C58A1301FE62FC0A717E2F347
+:1006D0001DBDED28FA97031F31C6E955A950FEA1AB
+:1006E000F81663ED547E4CF0F7310153E0DB0AADB0
+:1006F000E757AD06A2A7FC13790FEA098CCDA0DF5E
+:10070000F8D2E649049FBA7E6055173A33C8A52D42
+:10071000C655740844B1B02754FE460B08DB8DC1A2
+:10072000FF2C203E27791399C6EF4FF879019727C0
+:1007300091AD0E711E8CC7CB724DD171BD386E5606
+:10074000F43BFCBC51862843554807F3FE4D560147
+:1007500097CB83AFFF81F4B2C5E3C7EF18524C7457
+:100760004E465D37B6CEDFBE553B03E759F40D9AD2
+:10077000E77CAB0DE7590C6CBDC8414F6F1A8DC7B4
+:10078000D78F9CE471E33AF94ACDE1994A1CDF40E6
+:10079000FF46DE3F59DBDF05FD1D71FD53A07FC91C
+:1007A000F0FE4F594D21DD541CA7C21D26791EA213
+:1007B000C9CC17F3923378BFF9221FB43005DAA3FE
+:1007C000BE29D6E66BB0E91E13BFAF439B9F71BD38
+:1007D000B42E0BD7D53C53E36018C67B5DD0ED7AC1
+:1007E0009DFF77783FDDEB8B8B8EE37AAB31051580
+:1007F000DC0FDDC0421B9098172BFD4FD8C7913CF2
+:10080000F80BAE8B26D93FC101E5F3FA9EC2BB0BB4
+:1008100068BD7C96356D38BC2A5FA8F0227F209F8A
+:1008200045F92301EE289D6EEAA744B6DD60F7E0A6
+:1008300053B583186BE1F9C6EEDCD8BC8089E69A23
+:100840005A0AD10E79BD3D4072E37AFB2394D7F466
+:10085000E7317E6736C0B5E8AA4FE85E13E65A3244
+:1008600001ED7B80373D3BFDFF1DBCAABD372CDF72
+:10087000F6238326DF76B475A57EB799F1FB69660A
+:100880000FEEA1FCD9E685160F9E8368C6FCCF72D9
+:100890008A2F911D87E784E99E13C924ECAE2F9A15
+:1008A00097CBD7616FA39BECB7A81C1779E5BDA5C3
+:1008B0001CEEDEBBDDEA3D27DCBE5BC2F83D29EA6B
+:1008C0003D27CB6D54AFE69FF7EEE17EBCDEE72718
+:1008D000D07929B0DFC85E60A93A0E5F81F67E1537
+:1008E000FC933262F9D2DBF4DCDEDCA9F354209E07
+:1008F00077621CE8AFC47FBF9AADF59BA8E544BF03
+:10090000DE930EFFEDC817CB4BBC7912F0CF32034C
+:10091000F7DB017FEDC2B31535ACE529BC3F701E96
+:100920006BF9856E1CF1979FF86BF227FC5EC1187E
+:100930007F2DE1FC1520A1A4F25794AF8A13F3ABED
+:10094000FCABB17DAFBDFF574D68A70E1A892E6A6B
+:100950009E5CE23A8E83E7B49EC3E394658267EDC2
+:1009600048F07C113E8FE7AF4CC6F979347ECF5406
+:1009700058C05A16E3F73DC9FE76843FCAF71BF804
+:100980007E6418DCB285F8E3D6DB649E3F9ECCF52E
+:1009900015C62BB2E0FB75E2FBB776733EBAD56A9B
+:1009A00020BEAB1B6CA47C2256CDE30E1EF81FDFCD
+:1009B000077A09BF8B44BF85CE523DB2ECC25A6D57
+:1009C0007C6291458D7FF8F4B81E6F5DA83F19AF2A
+:1009D000EF17B1CD9F60DEDB228C63A8FDE0BB8FFB
+:1009E0006747E31813308E715CECD32F027F23FF2F
+:1009F000BF9ABE72D7DDC0B7131E2F29437FCE9C8E
+:100A00008C554F6D85F2F7764EA2F2AB1977DCFB71
+:100A10000ED6F71551B91A2F71C1FD4623EF5F5C51
+:100A200071DBFC02F8EE71B31817D715EEFB92FCE0
+:100A3000BD75D0CE35756C19E623560BF970F16E85
+:100A40009E0F7FC355569EE2B9D24D7EA3EA245134
+:100A5000FF753EEE5BA5FF568679A9D563238BE92A
+:100A60003EC6B21F4FC2F271E993C523C54D26178A
+:100A70004BA189809F6A076F5F5BF6FD6CDCC757EF
+:100A800057F1F2644F65F738ACD75D5A3CD2B9D014
+:100A90009F8AF5143DF724D6E98BDE0FE99C93CFAE
+:100AA0002479708ABEE91FF27B892C920DFD8F3E5E
+:100AB0006F81827ED2D95E9EB758656ACFC2FDEF44
+:100AC0004D7E4339E69FDA4CA5C7D1CE489D5E39AD
+:100AD0000DE93BDBC4F4A89780CFFF85F8FC9A4F63
+:100AE000F25290B92C5A3E57F9A84EE5EF6A2D1FE5
+:100AF000C3FAFCD7ECF4CF97AFA3F1317CFFDFB1A1
+:100B0000FFA22F69F54A74BC84F59638FE6872001E
+:100B1000FFE2E55C0C8E7E5A57399815360ED75D8C
+:100B20008FBAEE220887413744E73EF225CF243AB8
+:100B3000F0388AFE57E1CB05D9C6CA86C3857F8ABD
+:100B40006A9771086CB60CFC2EAF877E5EE688C192
+:100B500005DF676350EF6FE0F0EC965AB8DC107673
+:100B6000B1BA3F6E52E73BA09D6F45123FEFEC429A
+:100B7000FF05F673964EFA6B70370BBDB9D0E47B68
+:100B8000C80873B8C5BE8CF8E1AB2CF03CDA27C6B8
+:100B900054BF634C3AEEBB0247C205E4CFA5BC018B
+:100BA000A077DA9838FB44852B111F4DA3C8C344A6
+:100BB000B813F110A3CF10D957EAF9A9E8BC12E68F
+:100BC000D361E5EB3532CDA8DE5F528CEBE26D6987
+:100BD0009227DE9E7E3B416F27C2A5DA11AA5E55A1
+:100BE000E1417F11FF7EA41DCF90DD38662CD99D99
+:100BF0002ADF640AB80C3A69C438EA8D6374AA7FA4
+:100C00004E43C7C4734E2ABED4BCA0443CA9793D10
+:100C1000C3E23509F1C8D1DA49603F8F710CC79F33
+:100C20001AEF7144FD5C029FA512C93F87F073CD96
+:100C3000F6F0F309B5ADFC9C7C6D0D4C0070FFB671
+:100C4000F01FA8787EC8EEBF8DF347781AEED3BFA9
+:100C50003BEF698A73A8F7C825E267F928F8198D70
+:100C6000CF47833F2DD5B712BF7B5E1AAAC0CA2DCE
+:100C7000E9E2FE41E62FC07560B71554A21F02E4F9
+:100C8000EA679FE1660EAB80AEE50E7F33F2F9575F
+:100C9000996F0ED2D751E3D773FF3A23FFED5AB1C4
+:100CA000DF9A23F4EDA55D32C507AABD131F9B850E
+:100CB00076E21B7A16A4F5EE25FDB946C07F099FA2
+:100CC000D8DEC2F5EECA377F54012B864DD8AE8BE5
+:100CD000DDAF00FF26069334F72B4CDEEFD094A750
+:100CE000F4676BDA5F353056535F1A9AA4A9BFFADE
+:100CF0008D324D79DAD04C4DFB6BDEABD2946784EC
+:100D0000E76BDA7FE9EC024DF9DAC8ED9AF6A7C491
+:100D1000BE9805BC43C51978BF389FEF759F2ED587
+:100D2000F4FB6DCADC37900FEFDACCF3972B01336D
+:100D30009A7B267AB85DD102FFE374F52988AF1556
+:100D4000606F63DEF2CAED5ABBA37E70EB0694A51A
+:100D5000897915AB594B155E49979857516D5BA230
+:100D600043BEFBA731C2EEB8865D23EE85F9AB74B6
+:100D70002D62E3FF5B7435BAB47435BBB5744D2E88
+:100D8000D6D2D5EAD1D23575BA96AE76AF96AE69DF
+:100D9000355ABAA6FBB474CD5CA4A56B965F4BD74D
+:100DA00031F55ABAE6B668E99ADFAAA55F4160B59F
+:100DB000965E09F456E5E5B8AEB59A7651BAFBEA07
+:100DC000291F667CCFFD9A7155BA07E07F9CEE2DF6
+:100DD00094AFFEB7D29DB120F95F13E97E3681DE74
+:100DE000A0AF3E42B90076C6397C2E9A20EC79DF5E
+:100DF000C876862A7FE2F57AFCBE7534B9344C8F0A
+:100E0000897DECA87A2C611FFB3E66F1907DB49938
+:100E1000FC3CB709FEBC8CAF66A01FF507A49FDFA2
+:100E20000740A6035CEF23DCF09DF79326939FE138
+:100E30000E16D2D3BDBF98890883DE8989C932DEF8
+:100E4000E7E3A6E732A1BF970B3F8437D99F92C350
+:100E5000FD0FF919F8DD9C217EFFF25B695FE89ECA
+:100E60008293E887079D721AFDF0F0BC60E6FC7083
+:100E700046950F5EE676C6E16DE96C89F4323A7C00
+:100E8000703FBBF4AB12C51996FE9E3FC7E770BB1F
+:100E900037F1D9D1AAE28DEF876EC87193FECD618B
+:100EA000FDC27E637ECB381A87FBCD9FE4F78F3E71
+:100EB0002B3165BA838E49111D334D1CAE67F5CCBD
+:100EC00084F87B86F9DD8897EF28209A789EFE24A7
+:100ED000E487A5BF7F672CFAB164D97513DE2F3D77
+:100EE0001DBF0770CCF95A8B847EDD4C578B847EF6
+:100EF000A361EF0FDD2FE1F9C26899F176F88778E9
+:100F000050FD73C53A1EA78EDCCDF7174F7D9D911E
+:100F1000DFA9A3355019C0F8940C0607E6B1E8F92B
+:100F200079E41B72B8DF2D8B0DD1BDA6EC356117AE
+:100F30008AFBE04B44DEFB0511E759B1C7C4304FD3
+:100F4000A2E4E05107C67556002D87509F297EBA4E
+:100F50005FA364C7AB0E7ECFB8DE8EE7D8543D3AB0
+:100F60003ABD1576262E7F1CE8D832921E5F93CBB1
+:100F7000E3B31D6D35B3302EA3C2F3609B7716F239
+:100F800087AC7818C693F0DE9DF8FC338313EAE350
+:100F9000D6AF62A9D194F5161F5D66B1A1AD85F8F3
+:100FA0004C2FEE07DA98B3D616FFBB01AB7374E291
+:100FB0001EF200433B9B8B7A7C2A67503EFC91F1EA
+:100FC0007DA8D105E3C4CBB57BF358BC5FB9ABCDED
+:100FD00047F06E90FC7E1CC458C842E614CC5BC03F
+:100FE000B397F07EC7F56F601E8DC1BAD613728FAE
+:100FF0008E37A34BB9122F971EC801B9941C934B7F
+:10100000DF6D3B4B78EA685B44DF037C318C9F05E6
+:10101000B2B87DDAD1B684DEEBC0CE427E7A65C747
+:1010200084A36EA83F01FFF09E1CA393C3C5CAF31F
+:10103000483F2D167C803EAB5CE09F13AD7AE2B357
+:101040007B722D415C84F7BC3DFE28DEF369005EB7
+:1010500092FF06B8A3DF11783208B904FCE4C3F5A7
+:1010600066C856C8FFEBB02D203AFD77C753F16B29
+:101070003033BA87C6906B21BFCD1785F37B390912
+:101080007ABE3C8FE4E83D022FAFECE0794727EED3
+:101090006564BFDE731FF7BFDDD3C828FF9BB5C2F1
+:1010A0005F458C6F54799D8E3781C0CB9E3610344E
+:1010B000458C3DDC66C293572C19FD64E36274ECE9
+:1010C000F12A7674C76FAD76D6E1F3E1E9A77B50DC
+:1010D000AC6C99F5BB217CA28F1BBF6F6B6141B4D7
+:1010E0003329160BDFB7D74319BE9F22EA53FCBC46
+:1010F0009C2AEA5317F172AEF739A91A014B88837B
+:10110000E45A1CF30A51EEDDC5F8B95B71EE7EB707
+:1011100090BB632C8EBA6AACFF1AA37C7CB5FE71BF
+:10112000519F6539D9350EE5F2426DFF1D020F99C9
+:1011300096933DB3295EA2AD57E31BE9964B6F50E2
+:10114000FF126DFDA3A2BFD572696836D6176ABFBC
+:10115000FF90A84FB67079C87CFCFE54B5FE3BA248
+:10116000DE8CF5F87D8FB6BE5B7CBF430A127DE84E
+:101170008E585C3FE9DC5FDAD7C6AEC5F5D3D3162F
+:10118000A175F470DBA7442709992C3DB6AE6CAD70
+:101190006CC4F3E092906729EEB0D73B82BC53EB6E
+:1011A0001D367EDE5D7619888F8C16212FC43A8C11
+:1011B000CA0BA9C5C3998BFBB13F8F9F61815D416C
+:1011C000FB220FFE909F73EED5317F9CDCCA6E48E8
+:1011D00062FEB8F6AEBB1C9A72C6D7B235ED9D0B57
+:1011E000C76AEA2DE59334F5CC9B4BEB65ADE0ABDC
+:1011F000A492324DBD7A0E9FF5E46AEC677DE14C16
+:101200004DBB4BC56EFAFD9033F3D4DF19F1985006
+:101210002EACB58ECD44BDF34CDB7434B2D9B3B033
+:101220009EF0E8D4013BCF2F3E807159B4D7DBBC90
+:10123000F47E1FD483E5C29E84F5E686F67BDA6CE5
+:10124000547EA2CD45CFDD6D6E7A3EDE564CF53B29
+:10125000DA3C547E0CC6C7E7A3300EBE7FA4AD8631
+:10126000CA5BDB7C54DED2B688CA0FB5F9E9F99DBA
+:10127000B67A7ADFDDD642E58D6DADF47CB02D40D7
+:10128000CF8EB62EAABF46D0FB8038C778A0929FDB
+:101290004B4EA4E3AC5C49732F9835963F302B1727
+:1012A000F307FAC39AFBDD71DE349E99CF3F71BC20
+:1012B0003A1C0FBE3B890DB527F3754C71C7F1037E
+:1012C0009EF5C9C0EF635A381D0A0622549F55CFB8
+:1012D000695127E065CE00CBA9E0C750B1DD0569B3
+:1012E000A82A99C76129BF8CB9609E15E27E1C624D
+:1012F000BBA00EE152A673BDA9D2353A6F3B87134E
+:10130000E73F12BC5F13F397CBFBF9FD17353D2187
+:1013100064FB246F0BDD7F615AE40BE1EF57387DEE
+:101320007E3A8F3FE9D3B9B0B90139F3E997991BF8
+:101330009E390DDA7D4FF65D659AFD85FCE9C3CCDB
+:101340007D358C5BA2DD9F2415AED5F433E5DCAF93
+:10135000A93738D76BEA97AE29D8E0427C8E611462
+:101360009F316E6E6718525CDEBB95E0DA24F07E2A
+:101370004172D379DEC041353ECFEDF3EF09BDC2F6
+:101380004C9B693D4CB0F362516A40877AE1DC8F37
+:1013900052491E3DFD842E88FED7892CA8C3F53FF7
+:1013A00019CC3DAC9F8237E8CA74A58A8CE552E619
+:1013B00096B17C358BD0FE04ECF3F5B9DC3E7FC2F0
+:1013C0008CF1C15CFFF778DE5288F46691A06791DA
+:1013D000BA1FD9AE24FA65BB72890FB5E7993A8571
+:1013E0009DDE6EAFC8C4B8E88551F2CAACAE993381
+:1013F000F177B4AC59D3E9A9BE7FC8AD1BF19CEE1F
+:10140000E3025F2ADF4F0426177CFF38CEE37CF926
+:10141000BB19B8DD6B2A8C10FF5F90BCAE2588D756
+:101420003765CE878359342F45E0553958E95A023C
+:10143000F853DE1EE709B0D8779E6EF3CE54945869
+:10144000B948E445EE6FAB9B591DF7FE75014F316E
+:101450001BAA41FD545CA2F304696497467E990B74
+:101460007BBC78CE5C29631E146F1359CF7AD4D518
+:10147000CA5F64CA73518ECD606ED817582C21860E
+:101480007941AF47E7C934BFAFF43B5B752ADD173D
+:10149000981D957BA813F1F79486907F7ED7ABE7D4
+:1014A000F33AA6AD2FB6F0FC9D15C586A05BC2B081
+:1014B0007A0FDD8BA7F4490C4D7FE52FB3090FECB4
+:1014C0008564E2BFE4ED53E94AED9B14FF0F91BE42
+:1014D000E743EE1774E3042F42BBC6C986BD688F8D
+:1014E0004D40BCE0840A8B09AFCBC57CF7B72D21FA
+:1014F0003CFD5ACCA33337011EE6F1E2BD912B7AB5
+:1015000055FF87769E0F9557DD8CF7EC750CC9C299
+:1015100056D2E273937E682AFE36DDF930C0251379
+:101520009CBF46FACBDB2BE8F7954081D0FC1A9F95
+:1015300080FD7E01C9A31AD2DBD374949F9AC85749
+:10154000A7841C6BC9E5797F56D79767E2EFBCC5C6
+:10155000CAB3883F9FD1B162CA2FD1F1FDA59ABF0E
+:101560000186831BF775A579BAE83D1AF3515FDB55
+:101570007594F727EF49A2F389B25DA13CE34E4B86
+:10158000B56D358E635328AE32579E358476B3D110
+:10159000AEBB1AEDEEE37BEF1FC2FC12395761E8D8
+:1015A0002FEAB429DCEEC8D1513E9662AF36611CF9
+:1015B000A6C872BA12F17974CF37C9BF217F43E44C
+:1015C00088087F925E90AC93B5D0F8811C45DCE72B
+:1015D000E1AD2DCD10210437EE7F6A3E423FCA7146
+:1015E000DB2533DA2B6ECB0AF2A715E615D07CF497
+:1015F000186F83F213EB2ED9516EBDB96783A30028
+:10160000EDE7A0423648F19F3BB2E9DCF91E039DAD
+:101610008B57F19A1F503471BBDC566DD99810BFAF
+:10162000D3279C4BCACA2B107A6E110BC5CD47EF3E
+:10163000E2FB35E6B4D07EA7304F629FE962E53128
+:10164000A2BC5F1FC8F6007E8EED59918FF3BA726F
+:10165000D84F79BEA3D9FB1FE7BAD5DF4332EBE8F9
+:101660007ED59019F37E9F6A63E968DF99820AE567
+:101670005DEF13F2ACD0C2F9DF90CFF93CF159D84D
+:10168000C3D79D722029988C74B3F59705804F2697
+:10169000BF328FB941FF15DABCE43F2C6C35A4632F
+:1016A000FEC0DC1F5A884F2E5992C84FA8B4267925
+:1016B000F07DC7DE8A62771CDCC1365B3AE6E5EC7A
+:1016C0006D33A5A39C0A8E225FC7D97594AFECD663
+:1016D000F17CBAF9791CAEF979FCBE9779A2FCA429
+:1016E000125880703E09F4C43CE9A39BB93DBCB6D6
+:1016F000DD4470AC7D731CD955A3E1EDE936573A52
+:10170000DE0FBF77B32E1BFD4795DD859BF09E84D2
+:10171000B5567E4FAC9C3AE9314C45673FD533B462
+:10172000DF3B52667A96C5C97739755631F2952CEA
+:1017300007B2D12F7267DEFC9B315F12E8B713CB83
+:101740002BFB4A79D91AC8C6FCCAE6BE69BC9C1EE6
+:10175000D889F995DFEA9BC1CBB9816CFC1DA9B68C
+:10176000BE6B79797C60279637F655F232FA9E4047
+:10177000766EE99B7333CAD90E83A71E05F20F005C
+:10178000FE1280BF5F3CB70ABCA8F5CFE17BC0F377
+:1017900021F14CAC7F41F41B18A5FE25513F38CAFE
+:1017A000F82F8B7EA151FA1F13FD8E8FD2FF35D1FA
+:1017B000EF8D51EA7F22EADF1A65FC9F897E43A301
+:1017C000F47F57F4FBC528FD7F29FABD374AFD0792
+:1017D000A2FED709E39F10EDC3E2FD58EBE60F42EE
+:1017E000C07763418EA05C2AB66E76E03ADFDB55A7
+:1017F0004EFCDF51C1E33B2ABF8FC5DF6F827A5DAC
+:101800003EBF4F4A97CFE33CCF88F1810FB720DF2F
+:10181000AD7D5BA63C9B0E9DE76C10E5E8261DD9CF
+:10182000036BDFE4FBF3B5DD4A30FEFCC53309F0A2
+:101830006F10F0750A789FCCE3F139A3CB955E1B4E
+:10184000EF47B269CB9896857217E437E5ED1677C6
+:1018500057751597638C4C471688D2680AE17D0D41
+:101860008A55E8055B794F31C26751E89CBA6257E7
+:1018700042FBB1BFAB9CEC3B15BE4E8B42F775C92A
+:1018800056AE07E6FE70960DEDAC4EE61FF2627F97
+:101890009742F6FBD1AE321BCA3D83F52E1BAEDF5D
+:1018A00076379F5775537112CA6BF9211DC9EFE343
+:1018B00036BEDEFB5C3AF25B805EA1F32C20AF3DCE
+:1018C000A82326B0503B9D8F78F88525DCAFC7ACA8
+:1018D000A515745E448D434B4A9CFD7F59E0275FFC
+:1018E000E81105F50B3C9F2C17E71C02DCFF046494
+:1018F000738D893BAF79394FE6E740D438A25C4B12
+:10190000F716E5AD5334FEF79C7BB5654382DE5098
+:1019100012F4CAB82E9093717AA72060D3944FE640
+:1019200009BF8E8779D07E9DFBC3CD240F2FA17E6A
+:101930009346977B51F92BE4F193E21E9E2703FC1B
+:101940001CF1D1CD653F417AAFEDD6D1BDD35F5407
+:101950008E3E93C7B87FDA0F7A07ED198565E37E6F
+:10196000E9F3F0305EEF73D0BD0A9F838FF18F965D
+:101970003B50DE8EF72BA47786E98DCFC1D7B3928B
+:10198000E73D3FD2D19EC4ED6A1B9F77678693DF08
+:101990004724CE1FCAC25E7B50F8C195D4B96EFCF5
+:1019A00089904E7B0B9537489ECC1BA0FD46C96F96
+:1019B000C3F21B8E24AE777293880FF7A32D43F7E3
+:1019C0001C16F8D03FD21F34A8F71486F0FF0E6221
+:1019D0007E8E7A0FA28BEC33710F63EFCDD5D85E7C
+:1019E000B14D469373DA138F6DD1830D7AD0C0A2B7
+:1019F000EDF13CD533C775E29EC4DD5BD05E3D980A
+:101A0000C434F7401E443F3A8D17DC82F73EC2F7DC
+:101A10006E90610F767DFEF7B658B262F054B90F42
+:101A20006C69A73C59BE2FB1337E4FF779773805E3
+:101A3000970BEC4FAECAC77DF99ED3199ADF5D13A1
+:101A4000ED5345FBA6C148D30137B59F960FEBA0D8
+:101A50007120925242EB2B5211DF3E45ECF7E3DA54
+:101A60007F89C61FA57DB10ACF81776F2DE1ED2B50
+:101A700071FC0BEE7006E5BC24C093367CFCEBFFDA
+:101A80001A3C9344FBF3A177A9FD0516CE9852406A
+:101A9000FD6EC27E17DF7AB742CC3B03ED64908ABD
+:101AA00037E37B34B7F8EFB1B490FDDC6FEAB1A156
+:101AB000BD66D6F7F850EE16E2BD4ED363CF05F9FA
+:101AC00085DCAE4A78DF6F6269B5C88FAD3ADABFA0
+:101AD000F49B86CA4AD09E7ED102320FF5C23A0FDD
+:101AE000CAC181F05A4F09B4EBCB9945FB8A838672
+:101AF000967E3ADFBBC442E74FFB6C3D365C3F66E7
+:101B00007B8F0DE308F27DDC7E52965AFC4F213F1D
+:101B100085D6162F8F5BBF556E3DC1DFFDAA65339D
+:101B2000EE03BAF59E9E0968675B15CA3F57960E8D
+:101B3000CEA7F3823FD03192EF30AF2A287736EA32
+:101B4000E8BEFA87DD4BEF413C30C5E7AB827E79DA
+:101B5000E98A84E72F1E547C268C5F1885DDD6E742
+:101B6000E1BFF7AA7E7787B02F77E4F37BABBA9714
+:101B70001C287E0DFAF5B5AEEDC7EF99279A18E649
+:101B800099F5E59CE9C6F3A28FBB60C70B78B0342A
+:101B9000E8E8F75A1EAF8536A9E8CF3068FC15CFC4
+:101BA0004AFDD43ED0A8A37D82A5C4A0F16FA43580
+:101BB000E8BCE8773CE0F66F427EBBFA6DE506FCD8
+:101BC0009E6BBC6243FDF490EB17261DC09952AE8C
+:101BD0001DD7364B3B8EA35A5BEFACD5D6672CD4C2
+:101BE000D6BBBE6648F0D768CB29C8478847900166
+:101BF00016D04349BC8A2559AED0EF8575FB77F5E1
+:101C00004C8036C6E440E96B006FD2A424DAEF6F53
+:101C10007C3509171FC81F467267E3144679AFC7A2
+:101C200072BFE9427D9A889FBE1C03CDD75208F847
+:101C30002CC0FDFA59FA5D2F0B8B6B5780F8F13EE3
+:101C400093CFF7EFCC5581FE394672F059D57F7CA2
+:101C50000B3F4FD5D7CAFDD20F2DE2798134830ACD
+:101C60005CDFBC7D0AFECED854F4DB77DD8DF98EC7
+:101C70008978CDC4FC3239C61F1BD4F32B787AB2D5
+:101C8000828B655C7797DCFCFECD9705DF1C14F733
+:101C90002D44DB23FE3218DFCAC2786FE6ABFE07A5
+:101CA0007E1E609B1A8F1165BCC610CB078F3B6EE2
+:101CB000C0F5B46DA1A30CD7D3466197A5E618BCB7
+:101CC0001301DE47DE3004A4ABA0ACB0E37AD0E76A
+:101CD000071DFCBB86379302789EEA1157399DCFCA
+:101CE000FA389FFBF39EABF4FCBC96D6A342E7DF29
+:101CF0001E717ACC65DCDEC0BBAE19A51681697198
+:101D0000B4B68CF6A98F783D665CAF8FE478CC983A
+:101D10009F6CCE526CB88E1D2E85EED17AC4E4B77E
+:101D2000A1DDE2000588BF1F67C8ED9947E7920073
+:101D300087BA0A1E1260228F0FF3E8D204BEFA5C43
+:101D400077D9F0FCBAB3F0D0B7D0AF9E86E3A5F058
+:101D50007E8827BBC0D3A57C37CF4B16E3A7DDF524
+:101D60001CB5C7BFCE8AB8F13C9CBF0CF358907E1F
+:101D7000074D7C5F1D273A3EF392DF7EC34F38DE6E
+:101D8000DA73F9FD4186358CF661CF55FAF71F45B8
+:101D9000FC6425D13E3BDB955D85FC91FDC6CE05FF
+:101DA000780E61C34FB8FE342CE7F1A66C8599BE5E
+:101DB0008CF34EF7DB108F89EB30EB784F1D32DB65
+:101DC000FF054658D4C60080000000001F8B0800A5
+:101DD00000000000000BD57D0B7C94C5D5F73C7B43
+:101DE000CB26D9249B0B212124ECE646201736E193
+:101DF0002222EA7209A222DDC81D233E210102240B
+:101E00001040FB46CB6B161214156BA8A86851370F
+:101E10000A142B6AA88058D177B968A95A4DABBE6D
+:101E2000A55A692254416E31B4EF4B5B3FFBCDFFA5
+:101E3000CC4CB2CF9228EDFBF6F7FBBEF86B87795E
+:101E4000E676E69C3367CE9C7366765702BBCDE799
+:101E5000602C61A28DB9EC8CFEFECEFF976A61EB1F
+:101E6000CD098C254DE1DFF342BEA7248DCF2D6235
+:101E70002C79BAB17E0A0BC9BB79BD239D77B058C6
+:101E8000C6065419EB3D197DAC9899900BF96EFE7E
+:101E9000EE7C93D67EDFE0118CF9532D9E6D2EC61D
+:101EA000D2C3C663EC9B08E4356672FD3D8BB1F18D
+:101EB000AE78C6FAE17B9DCB57C8D82E9B738223A0
+:101EC00089B1CE15CCF30C6F3FFE950D73DFE1F9B0
+:101ED000FF4A77382378ADB423CD6D05FC3BDBA7F3
+:101EE0000F46FD2D16FDE9685EBEE5687FE6D71852
+:101EF0008B886675AD1C4F3613D391FE1D7FD7625C
+:101F00001C2B8D33DEC527359231DE45C094F2CFD0
+:101F1000A7AD0307E63B3DE8CFDD66E7FDB65A9C7B
+:101F2000F9169E1FF9F4630F59D3310F0EE3189A77
+:101F3000B6978D66ECF9C37CDC013CE77FF2A189A2
+:101F4000165E1ED55DEE47F92E9349E4FD81872686
+:101F50008E656CE0E1D6350E2763654FEF78C8CE0D
+:101F6000F116F92B51EEE379BF0578A919D4CEE724
+:101F700077306309CDBFF177112C82D72B347B36B4
+:101F800023CF3E8964DB787EC79EB1B35DBC5E63C0
+:101F9000CC28975EC0D8349746F32F43DAEFD27936
+:101FA000996D1EDDE3B8F4FB8D126F8C798EB670DF
+:101FB000FA163E6B63F7F3C23CC00D7AB544069E39
+:101FC000017D9B1FE34CC7589553D0BC6AEFFD19A8
+:101FD0000778FA6A4C59A58BB7AF8A99980C78D2D2
+:101FE0002E32A62772BA35D899CE719596F4338DD4
+:101FF00071F806261D1EC71CE09BB6354EA4755110
+:102000004C0FE1CBB48B16A60F477F5EEA0F7FF62D
+:102010006470A1F86B4AD0D91A0E8F9FE37A1BB86F
+:10202000D319D5A11581F1277ADBD5FAC8049FB25F
+:10203000D9AD05E03A81071BC7A9B584A70E4B307F
+:10204000A297FA77C87A66BB23681EC653E75B4738
+:10205000A95F87E54CBBBDA79E3D60217CB01A16E9
+:10206000C8D1084FFE08E4E31228CFBC5E575232B5
+:10207000F89F1172D32CEC70041F97B897AF9F5440
+:1020800016A4F4498E1E47162AA5C77F1ECDF089D7
+:10209000818F9F616C72285FABD434C844F065D7E0
+:1020A0009BFA9DE0F8C93F14497058D6B340241FED
+:1020B0002C1BF4E074CBDEC0021637EAD9FA9D4837
+:1020C000443B97E403A789D178AD43B1AE36BFE571
+:1020D000D8C0E288BE24773647B16AE04B8DC7D8B6
+:1020E0001AE28780E48B2D0D4EA2A32A1F5873306D
+:1020F0008C8E09063AAA7A691707103D7BFA0D50B3
+:102100007F69F5BB891FD22E66483E717D47FF99D6
+:102110007DF49F42EDFBEE7F208DFF64F0C3F8A9B4
+:102120001C153FEEDC1DEFE369A4B5D9E7E905CF47
+:1021300069B71BE5E4B07D46B9ABF01269F52695A9
+:1021400071FC47DE61F2B4F0FEAE386AAC37D9FDFF
+:10215000513CD6634FFD60D234D4AF15F5AF3A6928
+:10216000ACEF1BB727ACBE80EFDA8BC67AE1F4097F
+:102170008797C3D56F46085C13EC1186F6B32B2EF8
+:1021800081ABDFAC10B8AE4B31D6D7D7F40ED78DBC
+:102190007911DF0A97AAF7BDD197572F7C1ED32656
+:1021A00047F48177517FD6ECCBEBF796EA6FAF77A8
+:1021B0005B7DF8387EB95FF1B5C5D77122FEC19756
+:1021C0004062BDC91BC9F75127EB6458475D725D7A
+:1021D000253027AD67BEF035ACAB0FF0CF54C686C7
+:1021E000B87D5F437E4DB07BCB1FE15527CAFD8A8A
+:1021F0004DE13D5E89CE7D8537175ECA7F8CAD256A
+:10220000B85ED3749DD13E6BF76CE3EB3B3F8DD949
+:1022100053B91EC052029937C73016ED56F29A8B49
+:102220001A0EE75089BB1706B4AE8CA7751E48007E
+:102230003CFFE8B8FDDDDE0477BF9EFAE1F57AEAFF
+:102240000B3CD96CAD2B006767ADC383FDE1431434
+:10225000F176CFCE8C089A39BECE5B1DEB352E675A
+:102260008E46CF7BAB1FC7C307B1BA0BFDCF9E75A0
+:10227000FD3DC86B07135D2B397CE72BDA4701AFB7
+:10228000DE683DDBCDE1A8B1EB8392F914CFA6EB7C
+:1022900083E3805F5F22E195FFA3D0D72BFC029EF2
+:1022A000899AC07F629C5E8871269ADA9EF2E19BD1
+:1022B000A56D14DA31673F82EFAC8DCBBB5ED6BF24
+:1022C000C2C378D9CF01ABE7EB4E3EBF031BE33C63
+:1022D0008D1CDEAAC459F396F3A205265F72D06C5A
+:1022E00080FB2A8C57E3A818940AB8AD126E7B3F86
+:1022F00089776FF6B7C1DD88F1B0AFFDBB16D8E6C0
+:1023000016B444FE157F7CE07E9E8F305DF810F29F
+:10231000A3B3D0E4E17B04DBC2F50B3BDF57DE97D0
+:10232000F87E92AB3FF604FABE1EDF53A244FB9444
+:10233000474D8146DEDE37FE55A2D3B3CB1C1E339C
+:102340001FAB82B96CE0DB4AE6B501FE3F8EFBDBDA
+:10235000EBED7C7E73DCFA74CCE3B64453C68704A1
+:10236000879E5FC6F98D8D15F8FF2E7E606C838980
+:102370008D62EC66A91F2C90789CC6BC568C33836A
+:10238000E9568CFB9B73362FF4D2DF4007E5F0CE85
+:10239000627EFA3E870528BD8505A9FEADAC9DF29B
+:1023A000BF8E2E4AAFE7F0953D363807EB3104EF8C
+:1023B0004B24BFDC9624F8E58BFEC0FBA67E97C5B8
+:1023C000BF659AC0DF10B7BECA4DEBD595E4014C8E
+:1023D000CE09037D3121EB67623FC17F1667CEB71F
+:1023E000AD9FB6AED822368CE4812395E3E13A491D
+:1023F000CAEBBC4BA760BE902058AFDF93EBB5D4BF
+:10240000EC60499C2E6D2E732082C33279DC8A14D5
+:10241000CCF7176BD8AF8673FAFD629C9935524D95
+:102420002FB59B2AFB9B3A70D229E827EFB260D2E6
+:1024300008DEAEF4A27E388EE367AA796713D7B8B8
+:10244000D9E481D6CFDA43E4DAF549BB2C8CEB2F03
+:1024500037641BBF4F29E0F910B93B95597ACA3947
+:10246000FD0F003F903BACD90CFE7DCC1D93047D4D
+:10247000850D6543C5F9805323643E5DF66F6CE7B7
+:1024800079BBB7DDFA53E0A395F1E7E691DE611180
+:10249000F359F69E99F4CACF1A18388F9DE0FAA125
+:1024A0003797B1CFB97E81FCC986144ABFE4FA00E0
+:1024B000D2330D79547EAEC143F9AFDCBE9F804E5E
+:1024C000F3D77F65C1BE746FA4C2B7806395E4BBC8
+:1024D0007BD3473DF6578ED77BDFE50B83C353DDB8
+:1024E000DA3C0960AF4AFF6C2DF4E755CF691ED482
+:1024F0005BBADF6B737078161CD6EF019917BDDBE2
+:102500003E1562A216FA2BD71BEEB3FAF660BC9109
+:102510001F9D48D67905EFFE8EB71279FD2F1A461A
+:10252000135CA71ABC04D7E986C9944665FA5E43D2
+:102530007D2FFBCA86FA37EDECB0A4F1FAA55ECD8B
+:102540008BF5788D9705021C9ECD5621DF3773F9E8
+:102550008EF539AEF0E6276F6790BFFA9B683F2390
+:10256000A1B234917F9F3ABAC2827AB3BEE632CD2D
+:10257000DDC387DFBD0E053E6A255DCEBEA1119E7F
+:10258000CEEECDFFDE55BCBF378E989999C3D57579
+:10259000D14470751D8D0A406955F556EE31933E54
+:1025A000B932DD1600FE56EEC9EF0F7DEA34A71BE7
+:1025B000CBED19EFF40BFFE6D243E4E8E984D6FF54
+:1025C000FA1872EA5321A7B8BEF9F913906303070A
+:1025D0007840F77356AE9703D1AC2E1AFBD8329BD6
+:1025E0005C5F5CCE207F3A4A9C8347BD98361EEBE9
+:1025F00005E3B96C3D7228F7C5C7327FE0EA196F71
+:1026000047EB828F9FE0F9B30193DFCAF799B3AC30
+:10261000F5DCCF2147B73A3C381FDCAB7178B08F7F
+:102620006E1B40F93CCD12554FFC1CA0F59AA7B982
+:102630002CF55CFED4FCECF101E0A7D7380E46F394
+:10264000F2D73646937C7ACDEA39568FFE9E14FD3A
+:10265000FDE487777EB60FE983B5257702C999092E
+:1026600084EFAA1F2D1E8AF67C9F66A9BCBFE75F78
+:10267000D182917C7D166E3AB03695C3376C4B870C
+:1026800069004F8BB76A8D48F3D36F3862E6E5F681
+:102690004C17C1317CA7DB9C86653520F0F1B5B4C1
+:1026A0007F1BF7F5824D5F8DC7F152EDEF43B5D635
+:1026B0002F5B701ECE385AA213FE9AA99F3DFBA72E
+:1026C0007D700BC33CB8E600B82B6C1EDA4F02FEDF
+:1026D00016D0F9AC9EE7B91F6BDAE77F1CF43DAB6F
+:1026E000277BB0BFEC35F963C7A0FE310BCDF39566
+:1026F000ADBF8EB5F27CDC6E2B8BE4E5B5C59D934A
+:1027000050BF36DD45E7F0F4A7AE9B0CFC2CDBBDDB
+:10271000A785FAA9B17B34ACB33D17DE4AC379E88B
+:102720007AE6C901DFED16F907267A3DE0B7EA96A9
+:102730003F8B7C9B8FF23EB3DF6D41FD4AA1E73CAE
+:1027400026F731D65E44F28E58D9D543AF0778319B
+:10275000CA37BBFDA9758E9EFD8FEF5BF999BC3C16
+:10276000D526DB3BA765F8FE817DCB26F721D5DF9B
+:102770006336E68FE4FDA4F3EF1AF6559BD86FB7E6
+:1027800071F9027E51FB2D1FF7AA4CD1DE0B39994E
+:10279000C637D7623E9FB4C72202B4A75FE6F84AA5
+:1027A0004F5A1E25E499D23F662736BEDECEF1FA97
+:1027B000A758FD3ACC6F81DCAF99C59382F91D8F84
+:1027C000F54EC6F835F6CE0CCC81EF8753905F6698
+:1027D000E6FA535688FE64BFBCFD3022CE7B33DA66
+:1027E0005F6EFDB151BDCBDFB15DA349FEBE2EE5ED
+:1027F000EFAA3F9B5831CFAF7A2482E409ED69BD3F
+:10280000E0E575BEDE752E5FFE0376039E5EFDA7D6
+:1028100076339D3F0E9B6ADEE2FB290D9D89FFEB1F
+:102820006C8C1B41792FC87CCD9F4CBD9E0F55CA27
+:10283000E954877979BF36DA1BAEFDDA69A3FE1D4C
+:102840000997355F731FF335C78AF9EEC77C39EDF9
+:10285000567D5542F272FF65CE333DC2BB06F40D84
+:102860009F0787FB5E7C0F87BB9BBF3B2F0FEE3B19
+:1028700034E637619D7D650B609DEDE76062DDEEBE
+:102880005F5C10C07ADE6B13797FAC8DF4CFFD31C5
+:10289000CC0FF9B1BF2C39E077430E32A19FF6631C
+:1028A000A23C52B69F934CED074470FEE779764BFD
+:1028B00094ECBFEE9D4294AF49F37008B87E1B586C
+:1028C0009F49FAAD99EC8647A5BCDE141FBCC5CC68
+:1028D000BF6FFA2A97619CA32C98B61CF5AAA3484F
+:1028E0000E6D8AF7A626703CEEFDC64CFBC2A662B2
+:1028F0009E77909C26FBCEA6326F6A3CCFCF957414
+:10290000D9D412D8F628FA2BCBF3F8F93803CCAC8B
+:102910008EEAB9453F1F5B45BBDF49BAF0754CEB0A
+:10292000FC83CCF941E0599F1A6D815D84633C556D
+:10293000E3F03F5195C3485E4ABBD76C4983B93D2C
+:102940007CE0B58F825E2BFEE62CD81609793CA37D
+:102950003A92EC5247ABD7C6B8F87833747330026A
+:10296000FADFF45283DDE9834C2F8DCB0F16F29CF6
+:1029700010AC041EDFE8B433C8E5BEE859DB3A2EDC
+:10298000F144083F54DB84FC3829F5A15763F4F780
+:10299000C0EFCBF75D9F782244DFAB5A509A4B765D
+:1029A000DFAACB3BDF35824EC368BDFA4DE08FD640
+:1029B00048A2FFE49BED44EF2E87E919D8256F93D9
+:1029C000F2AA110761FEBD714F44602DFFB63C2293
+:1029D0003813F28AD3FFB9EDA0EBEB9144FF1A9BB9
+:1029E000E0A79A9FE7137FEDB579DDEBD0FF1B11D0
+:1029F00044F79A58571C95BF9DC824FF91DE501389
+:102A000015CC8DE7F85C1FAD9F02DE38DF913DB835
+:102A1000C626BE1F937C758CF70138FC7531C48FB8
+:102A20004CE6F51F24D2798AEBA3C4BFFA43F9948C
+:102A3000D76DDED405581F2BA309BE63D29E76AC9A
+:102A4000269EF8BBFCA1A5EF324ECF63BEEDF7E5A5
+:102A5000F27AC7F65B3DD8977E5F6F0EDA385DCFAE
+:102A6000AD3E3E6A33CFB7AFFD24430FB1A395AF60
+:102A7000AD9D8276E54B564FC57ED917BECB6B22F6
+:102A8000B8CCEDA1535296D79CC5F1EFC9D26D5980
+:102A90007C9ECB0BDA1742EE9DB3B53D85F3C1C7E3
+:102AA000717A24BE9F7FF58BED240F2D9DB9D0CF79
+:102AB0009759381F802FE5FEB95CF2E54B597A1C17
+:102AC000EA73FC913E1E5DD026E4DEEACB93F35F11
+:102AD000EEDFB657E3E32C8DDABF8C5273A008FD0E
+:102AE0009CD682B15A16F0C7F538DEDF196730166A
+:102AF00074D0E5B969E90EE3BCF007BBCA52FC83A8
+:102B0000B75BDA6A26BB0ADFDF6D807F292CBD0642
+:102B10007F82902BBC9F67681D3A7E3FEF071CFFAA
+:102B20004B9E1B52027D7269FCBE1F5E45F5783BD1
+:102B3000C5E7E64BF36A3E97C223E67746F2F919FA
+:102B400026E5E06C5BF7391C7AD0B917FA1BF8E67A
+:102B5000DC734328FFA5D6A94571B8CE4979C43C9A
+:102B6000ADA3CA7080F0B68E823EFBA8FCBE34B125
+:102B70007514E48F9247CCDE5A44E7EABCD6229C17
+:102B800027953C63BED65CFA1E68CD45FBBD266129
+:102B9000A7A03FCCFBF9B416C2835DACC725CFE735
+:102BA000135ED438E1F40B9FEFD42CE11FE0F0DE8C
+:102BB000E6E3F5076FB619CA87048CF999B2FEA04F
+:102BC00030BA0C30771E8880BC7F96D17A0D1FF703
+:102BD000D62C614FFFE94FBBE96096E745E652F41A
+:102BE00077097DDB0A7CFFAE1BDFB7A77179BA14CA
+:102BF00073CCEC99FFDE623D0D72FF9C49D8A9F7BA
+:102C0000C6F37C01F41C814F9557780CE7A3B5BF40
+:102C10005B98067FCAFAAC6E3F477FF05B23E425E2
+:102C200097178D56818F2F1BAA879FB0E03C5A972C
+:102C30005A65E999CFC2CDC576AC97455B8AEDF36D
+:102C400043CE3B8D3B861F7171BA9CD96121B34144
+:102C5000A325F043E8D18D3BCCAD7E46E5762FAF82
+:102C60007FC671F03DD45BB825BE047AAF6ABF68F9
+:102C7000F31DA95521F8CEDF61C47F61AB310F7B15
+:102C80007468FE47D00547FEE3ED8A83C6FCF02357
+:102C9000C6FC171FDE3E136CFCCA68C1EF27033168
+:102CA00001F8A9AA3F997404FBDAC9BDAFC4823EFA
+:102CB0004B3FAD7A0BE796459B8D7CC6E9A641AFAD
+:102CC000F76FD7883F1607C2D79D5CEF97ACC73523
+:102CD000CAAE9917CA27E1F43CCD5A677A393FD575
+:102CE000D4AF1C0E7F48F514CEB81C9E2B5B37DA90
+:102CF000E037081FAFAF75CF1C5E17EC5515A34525
+:102D0000D998FAF1EC388CBE1B7E3D09EBADE2019F
+:102D10008DF6FF8A97071F86FCEED835E7064A67CF
+:102D20004E263C28FBD9A2FD5A3086E79DA35DFBC9
+:102D3000DA79BB05018DF687F94D113D7288FFAF39
+:102D40006A43181C9B42CA39FC8BF61DF88BC6FBE4
+:102D5000AFDE626CB798E30B727FC9D6BF47847E43
+:102D600057E7BE31FB5BCC98F70205BFFF1A8679A7
+:102D7000091724171D525F39810C97F71109BE36C8
+:102D8000EC2F633689765C605560BEB50E9B0BF305
+:102D9000ADB5B3603487E3488CCDEBE4DF2F6C8EA8
+:102DA00021FBD4C208AE179650CA224BD0CE43FBAB
+:102DB000F4E7EF9B495FA9C5D8E8E7698DCE3FB539
+:102DC000303622FFACC82F66419A07F8C51B3ABFC0
+:102DD0008031CF9AC5B9A9C6123C007C2C61EDE2C6
+:102DE000DCC3E9E80DF1C7D5F0791E4D803E646C77
+:102DF000BF9CB552FDE5FBFE1E11FA3DC44E4AE7ED
+:102E00003975AE34DB9817FAB1F9EE28DAEFB9204C
+:102E10008E027FAED3BC8FDBCD48C5BCFC1B85FECC
+:102E200033B745EC175C3FCD057E366D1CE2819EC5
+:102E30003297EBD991D023164751BD4DF18CEC2B35
+:102E40009BE6E40A3DFB9B978318A7F3118DEC23C7
+:102E50009B8A45BF9B1E1C42E590871A8D13417AC1
+:102E6000CBA632559E4E7AD2C7002D157AAEFCDE27
+:102E7000CF45DF0798BDB9D0D7D9C39174DE577A53
+:102E8000EDB3097A6C76BF9EF92A3D98555F9EFE98
+:102E9000B74DEE779D1B85FFF784E67BCB14A29799
+:102EA0000ECA16FBC3A8F1DEEDB21EF901AA4C65ED
+:102EB000F75FCBE1A97AD4E46A74F7E09D79BDB9F4
+:102EC00098FF898D9125E0B351E385BDE758B19016
+:102ED000DBD1239837C0D3BC6CB17FE4659B0C6910
+:102EE0004A14E73FDECF8952611F8E19E1233B1B55
+:102EF000D7D9487E87CF638484AFCAE67BFBEA5E7E
+:102F0000E0E9E6838942CF38B1427B46C0C5E9CAD1
+:102F1000F3A37E1449F6B913725F51F8E77C33923C
+:102F2000F66929AF364A3ED908FA633F5B2CCE4199
+:102F30003D7C62E483B99AC02B7B50E8A79BE245B5
+:102F40005EF1013FEFB0BF824F4A19E1BDAF738F11
+:102F50009AE7A61651CEE93D05F40E3FF7287A33DD
+:102F60004B6024CE8D7DD17BFEE8F8519A89FCD64A
+:102F70007EF8ADB1D7115EEEB304D67238065A04AE
+:102F8000FED32D82BFB854F64795507DAF8DE72B09
+:102F90001E5EC4BCBC7E451A237B10AFCFE2509F9F
+:102FA00077833816EC1568571127FAADE8CFE89CFF
+:102FB000407F5C5E6523CDA47EBDA604D13EB68471
+:102FC000DAFB4DA2BDD7C2D34159429FEF5C171126
+:102FD0007806F2F9DEF45CF0C194F1463EF88F6CAD
+:102FE000B1DFAB74688E4B1A953C2958DFF39B8692
+:102FF000D07ED118E9ABDD03BABD20F4FF8A7B6E29
+:10300000BD6924E07B31D103F0BE9CBA8BFC0DF38B
+:103010009BE6DCF111CE0D3B22E9FB7539FA5DD957
+:1030200023A107BAE6EDE11FE6CF38644BE1EDF5E9
+:10303000D6B2B33FE7E954FFAEF7A00F4C9D6EA6A2
+:10304000FA5399B08FB22631CE4DFEAF2C29BCBFBA
+:103050009BC66A1433D011E9CC58C1E1AF90F4BBE0
+:1030600047F26F63249BFD3307E04ACFCDE4DF6F67
+:103070008286D98BFFEAB0AA3F4EDB02BD66D00440
+:10308000B1BE547DF4837EDF96EB69A3C48BCA7313
+:10309000BC52FDAAF5111D59B148ADC1C13CEDCCE2
+:1030A0001DFF08F86A4A269BB41978BFD38C5805CF
+:1030B0000E6F6705ADFB985C17F854672C48F1114B
+:1030C0008121C4D71DE33A3BEEE5F98E96C11EB2CD
+:1030D000F9C873F4029CAF5C2817724CC99763CE91
+:1030E000F618E25779AEAE94ACF1C7FA098F5EC11B
+:1030F000EB573A6C1DD80F163C322D167126959B56
+:10310000CC229E6383F15CCDCFBF2F812EE1E7E41B
+:10311000F0F33078067C54B541233E1CD4E8B1A5C9
+:10312000921CD39C985F9523980DF95EE589F4A0D5
+:10313000FC4C8337F14436FC119329655F73BC8FD7
+:10314000823D965110C7C11C7D3FF054D15C41E7D0
+:10315000C5E8029DE4D3DFB25D84E729B02742DEF3
+:1031600058DA53B10E6BD5F70467AE83F839920184
+:103170000F1D56672EE0EA581769C2BE3965ADE0EB
+:103180006BBECEEC16DEFE3E0B8BC27ABF5FB62F57
+:103190005F63F1B5F0FC403BB3C42480AF8A89AFD4
+:1031A0004B06EB1B818793FFCE4663FFAFDCB091EC
+:1031B000E0517CC12C6D1313A1DF6D7397DCCF7AC6
+:1031C000F8A864F0F80FD0AE9B1FA66BC4073C3D77
+:1031D0009045FC70F351944F191FCC5E59003F5637
+:1031E0000DF3C28F90C23CB00774B14ED227BAB86B
+:1031F0003E0179A6E489921B9C0FBC88EB51F455E3
+:10320000F2637B030789E37547839DD29F36389924
+:1032100085CB809D0D29947FB1C145696B431E7D8F
+:10322000FF598387F2BB1B46537E6F8397F2FB1ACD
+:103230002653FAF3061F7DE7782139A4E48A9247E2
+:103240008A9F945C0AE7A3791CBDD794507B927B3C
+:103250004ADE611EA6921E79A4E89BA9F9FC296E9C
+:10326000C8B1F6399017A5E6332FBC023B49B5C368
+:1032700013E1025E84DCEB72D849CE67D8D83E9C5D
+:10328000D71B57783BEE0DD9576FA9D69825844F99
+:103290006FAD8B6496103EBEAD3EDE902FAFFFE06B
+:1032A000CDFEBC7F2D5E77E470388EDDFDF993BFD7
+:1032B000E5DF9FBEFBCB1CD09BC3B1ED318CBB3A8D
+:1032C000AA1B8E04E49BACA43F0C8A12E720FC816D
+:1032D0002EF399589F4FDFFD575ADF1DF5112E33FE
+:1032E000AF37BF3E82F0F531E8C4F1FA7B49A78AD7
+:1032F00075C75F7805EB7CB58DE4DCFC26B92ED76D
+:10330000737C86E86B9FA532D2CB342F63F0C37CED
+:10331000F6EFB620DFF3D9679A3DA041F7E187A425
+:1033200072FE5D5FFF0B8ABFD2EA8F903EAC232E08
+:103330000B7602BFD5108FA5D5CB38ADF681863878
+:10334000AAE8115E1BE403781A749B9F7790615D75
+:10335000B366CD892DA04A7EAF5AAF91BED1AD2FB5
+:10336000E498898E75D9164ADFC31AA7FDA299F68B
+:1033700027C5AF5C5E78035817CDC5B68521727836
+:10338000BEFC5E9967A2547DAFCBB6513FEF41388A
+:10339000F07EEFCFCBB42D2039E7B2410EA8FAF37F
+:1033A000F34AEEC91C817EC625B190F5E8CDB15037
+:1033B000FB3A047AE17C6417F6FF9A3EF601A59782
+:1033C0009CC43FAF24F8E9BCB5E4C5E75F847F6CDB
+:1033D000C9271144A725C3A43DA220306A1AE933A6
+:1033E0005E87C6E7B94CD27FE2F39FC6B6F3F2E53B
+:1033F000BB85FD92A71D4897ADAE26BBD6320F5FA9
+:103400001F0990AB463FF2E1173F896DA773853FD7
+:103410000DF1857C5B486329F0171D9F04BBF87292
+:10342000D6790FE2BAC2DB2DD7BE8E15F67DE12725
+:1034300057FECBD2D7FF9C4C70ECB9900CB9B6FCC0
+:10344000F575C97A2FF35E1EE6BF567E7365075B7E
+:10345000CE367C05BF5B78BD9539D2AF7D05BB828A
+:10346000EC141646710C2BED020F5D819C38D6CB07
+:1034700078DDE36EE6829D9F43BB2CAE380F87F369
+:103480007C1F717CAFE488FDF9ACF4A39EDF692654
+:10349000BDF0FCCE18E2FF653B1F7EEB2A9E5FB6B7
+:1034A00055C3B0AC96B5119E96ED36337BE8F90660
+:1034B000769BC4BEE15CFA7C4C1DF86971ABE6DD1D
+:1034C0005600BFBC2BAE5FA8BE28F9696944EB2843
+:1034D000A28384FF7EA91FA97A8BF73F6C03BD7876
+:1034E000BD73A4B7BC140D5D9BFF75BE07384F6F4D
+:1034F000194E7EDDC5ADBB96D1BEBF33DA89297EBC
+:103500006935DAA30239623D057284BE715ADA7FE9
+:103510004FBF6826F90338B10EBFD4849D57B5DB81
+:103520002EDB6D9778BB2947AC47557F716B476C95
+:1035300036AFFFC5BE0F286D95F35AEC682BC27EDF
+:10354000F9C5EEE8C9014A7F3CE9353EDED9D671BE
+:10355000495AC8BA7A3D47C40D9FDD629E0C7CB1C2
+:10356000808A336AA5F99CDE99A6D1B916F8E6F8E7
+:1035700039BDFBE55813AD5BBF6827E968B20B7B2B
+:10358000AADBE292F60BBB137AC65CAED5C57179A5
+:1035900057BB5BC403847F57F569BDA582DF3B6DD4
+:1035A00082FFA5FF5EFA97102742FEF8185B00FB2A
+:1035B000EBBC61AE59B7409EBD6315F418E87A0CB8
+:1035C000E7AA79EF2792BD62A5D5D51FF93FBD6B5C
+:1035D00025FBF9BCE1729DA7B48F847DB2C32DF6A3
+:1035E000F59AF57C85F0290FE0F4F7F3F9D5044C52
+:1035F000144F793C2793E07AA2DAE4B5919F23989F
+:103600000B3BE5311BF39BA127FF2C92F4BB9A4C9B
+:1036100061777F02FCCED39A84606E22EC5D928E3D
+:103620003537F3F2107AD63C13CC85DE72C626EC21
+:10363000782877222D11F51A25DFA01FF4DBE1761B
+:103640009E23FD724F0C839E6F7A2546D8137E12FF
+:10365000497E07D5EF05C9578DD2CFE5DF26E003B8
+:103660005CD09B17DB9A73A157AA7117C736D37822
+:1036700067E4788BA39A85FF40C685A13E8D6F6570
+:103680005E9CC73B9F8B20FDF4CBD4B6BD18FFCB0F
+:10369000E786901FBCC31D58B88FCAB9DEC6E9B013
+:1036A000E4A71141C07BEAB918F2739EB20A3DE863
+:1036B000544C32E94147621E9D87FEBAB64668B057
+:1036C000A79CD2982D05E5DBFA91BF6A49433DF9E5
+:1036D0000996F0E50E7F344F27C3AF7C6ADB10B24A
+:1036E000B39CFAA599FC8BFCFB7A7CD759F3BCBB45
+:1036F000B0EE7644939DEDCB9FFE6D48A8FF41A5AB
+:103700004BB61AED498AFEAA3C2957ACAFA45C819E
+:10371000C7945CB1CFD446B73E9A49F314EB95D326
+:1037200081CE5B7C7D24C33E7DACF5D564CD013C70
+:1037300007737F0CBCEF10E79A2F775AC92FB2E4BA
+:1037400095182FD96FEEBDC284FD628959E8BF4B31
+:1037500038BB8954D88796C4E6927D88E39BCE8F88
+:103760009DDBCC721C31EEA9EDE9C2FE1E94F9BDC1
+:103770008501F0F9940476DBCDA4DF6C29025E2F7D
+:103780006C8D36812FF8385EF8ED97DCF50381CF2C
+:10379000B885A48F33C4418F82BF5CC8CBDA7BAFBE
+:1037A0008A433C0C7BDFCC20FA2E583CFD210FC312
+:1037B000F1B52857CACBBD4FDAE03FABE1EB05F1DD
+:1037C000414BA5DF74E94F35D2E796DE73D563240C
+:1037D00007DFB3B21C0EC799D6876343E95126FBB6
+:1037E000E969EFA1FA4B797DD1FE9D588267BBD57F
+:1037F0000378C2E978D9ED7F6ABEACF6DDFCD1CAA8
+:10380000F7F5A24BE77D81B57DFF13C8919D911E11
+:103810003F7D6D25BFF3696BEB42CCFBF40B91242C
+:103820005F4EC78BF5FE0597877E1BE0B8F121B28E
+:103830006FFC661A83E85E1430F6ABC69D992BE4E4
+:103840006F6DA2270EFE8C5A4E07F4C7E9F23D6A4F
+:10385000FFBE95DA87CF63A46CD7BD3E5F88267E16
+:10386000393D40D0E3F48B83695FE988177CCEE172
+:10387000CDC039E574BC487153067CB0449E434FBB
+:103880008F6BA573F7696D17A51D56D16E49BDF4F1
+:10389000DB72BE4B01DF8027E1B7B26F68831E0188
+:1038A000FBF4A8124A83110997DA99C19FD8875E61
+:1038B000CC15F62CA83590EBE4DF20FDA4D50679D5
+:1038C000AC4B3DAE66E7A5FE32F283EED4C8EFF313
+:1038D000A05CA7803A49D9C7393F2EF56B5EC41B5F
+:1038E0002D6D5AB118FCBEB46EE32DE077358FA56F
+:1038F000163619E7AB0ECD4CF07444F275033C84D8
+:103900008E97D983DFCD0A5E809C4C7A2629D75BBF
+:1039100072C57E857C33EFAFA649DB40E3B8D5792D
+:1039200052CC4FE189A3C5063B193FE78BF23EE637
+:10393000AFE00C9FBF82A73557D8273ADCAE87C6C9
+:1039400082DEBF3293FDF4C2D7C3E312BE452FC35C
+:1039500089ADDB5ECCE17F9DEFD5E8C70FF986F539
+:103960000C7B348733778BD1FF91B7D5981FBAD3AF
+:10397000982FD86DCC17ED37E63D878DF96D725CC9
+:1039800085279C7311D786732E529C735DB9E29C78
+:103990008B3CCEB94871CEC5779C7391C7391779E6
+:1039A0009C7391C7391729CEB9F87E4ECAEF1A69B0
+:1039B00077041D28BEEAD548E507A7F5727E4E328A
+:1039C000C94FE5CF3CBFB880F2DDF69C323BD973DE
+:1039D000549CCE2D71FAD15CF21BB6DD930ABA5914
+:1039E000DAC98EBBFCE7C28E5B5312E9807DA17DF4
+:1039F000DD17F7407D2A8AD33FCDA5B8A6CEED22AC
+:103A00005E294872A37D8DEBFD6B05FDC8CEA1E25A
+:103A10006E2AB0DF25F44DC7703F0ADB60F49B844B
+:103A2000FB51C2FD27E17CA0FC264F5B3B5321EFFD
+:103A30008F3F67DF00F88F4BFB189BED24FD4BE9B0
+:103A4000D5DDFAD783DA33D8B7BFC94DA0F65D47C5
+:103A5000B8BEDDCB7EABD2CA8B25A43776E73768FC
+:103A6000268A1B4989A57D6895842943EBECB81704
+:103A7000F22EC644FBF8058789CE05173E34931E07
+:103A80003118FA79C87C8604A20CFC95BF2321CC9E
+:103A9000FF37C0507FD8BECC30FFDF50A35F6AFA3B
+:103AA0009A03385F4FDB30DC50AFCA7755181E25BC
+:103AB000DC522F6D5CBD3903F267554C17C1BF6AEC
+:103AC0004F24C5D5567178BDF0CB21C351506DF749
+:103AD0004E05FEAA5BADF1D8E72BE5FEC3EA8DFBF0
+:103AE00071B585F99D093D7C57ED64DE78DEFE6C8D
+:103AF00071F37613A7DB59D39647C7BAE0576AC963
+:103B00007072BEBA5D6B4DBE92F7F7378B5E309820
+:103B1000F35B8635F8C372C8CB5D596C0DAF777C0B
+:103B2000C3CBB1A4774B3ECBB03AA340EF966633FC
+:103B30009D0B60973227F4F0434B736254B6A36732
+:103B40009E3DF4FF9AE6C7E9E2C13DC52EC7C1819B
+:103B5000ABA0C7B58AF9568FD3FCA427CBF9AC9498
+:103B6000FB0ACB16FDDC2EF327E47941CDEFCC9098
+:103B700003452EF8311BF6659821C74D3BB7E3FE90
+:103B8000C0DD51FA758347225E32E7B763F9B84B5F
+:103B90003E12F1BA7FDC3421F64AE89F2F583D539C
+:103BA00078FEDEE6676D38172FB1046C3877563F24
+:103BB000D762F3F2F4BA1D2DF47DE18E0A3A6F2F2D
+:103BC0006275748E3CA9E26F253EAAC76B5B9C1C94
+:103BD000EE17070BB9511D25E2364ACD63DF445C71
+:103BE000FA851D5A31E63BDDB7CB5601FBB3AC1766
+:103BF000BE3EBADE9D56DA0FF6A456E1F7EC6B3DF9
+:103C0000CC08E6D17A9876D145E9F48B43E91CFBE0
+:103C100011F315929C28083BCFBE2BE290BBF68B8C
+:103C200075506D0B264DC33A79C34AEBA496CBAFC2
+:103C3000D1253827333686A7BEB16603BF2E9F181D
+:103C40006DE0E7D92CC1E0479E894B9B21F9E953F0
+:103C5000B20CF5674DCF0FE3FF929E729223630C77
+:103C60007126B5ABFD2E8DE259C61BBFF37435F13D
+:103C7000D90D86F6B5ECE69E7A38076FFD35E199E9
+:103C8000B1361BCE5BD5261157335BEF90DFDBE9F6
+:103C90003B9F88611D0ECAF2FC56EC8B56B2CB2BB3
+:103CA000BBF46CFC3BABB77D91135A8E8BF850D8AC
+:103CB000170CF1851C003A7F3241875A69EFA9CD74
+:103CC00013F69E5A7F9B0DF1B71CFF96348E9265BA
+:103CD000CD1AD9F3787D7B5A82C8AFC6F7DDC6FB13
+:103CE00006E8EF22CA8F982BB05EC2CB97F17943DA
+:103CF000CF58063B0DEC4CAA7FD9AFE2CF459B8D48
+:103D000076A365B0E784D0F1ABC12EE2D3253B7634
+:103D1000BD3580E3659A2FBE18EBA7A6B5CC5A51E6
+:103D200070299F29F97EA1DA447EEEAE770F119FAC
+:103D300075555B889FBF0B1FCBBCC29E19CE7F0BF6
+:103D4000F97CE0975DB85BF30434510F781900BE3D
+:103D50000CC34B5A2FF85278EAC65B58F922FC6321
+:103D600004E206B440D0DD1B5E241E55FF6178627C
+:103D7000A38D7858A8BBDE87BC5978C4CC02973194
+:103D8000EF45981FC6E7F3C3F8375F147612E5379F
+:103D90009879D142F96E3EF189F8E9E9538CEBB29A
+:103DA0009B6F7C629DCCB8984CEDFEB7F9E7BBF8F1
+:103DB00046C11D1E9FACEEF7FCF76069271CC94683
+:103DC000D2FABFCCB861B5DF2B3C0FBA7B34C51338
+:103DD000753932497FE8DE6F9CC6F29531991447F8
+:103DE000AC4BFB9C92BBBAACA7C6A9E0E5AEE1E048
+:103DF000E381C9B0BBDED39495D11EA297E8EBACAA
+:103E00006437CD5893486945A43319FB45C51AB3A7
+:103E10000FFBE067F7F54F1E0D3BFC3A6BD214DE4B
+:103E2000F567778EC86085C897527A7C63C4EC507A
+:103E30007BB64A5D79623FA8BDFB28ED5F674DEF19
+:103E4000C6CEC63A5BB7271621354BD77D30CAC9D7
+:103E5000558F168B3E280F71845ACB7627F0E66C6F
+:103E600029823D7A1868D7AF474F58B2AEB43FECBD
+:103E70005F35DF1C7A0AFBBBBEC69A0C3DF3D487C4
+:103E80007CFFD368FF22FDE024E28F93E0B78AA68F
+:103E9000FB6D2735E685FF66B1F94091D3B09FEE03
+:103EA0009F09385E8DD287E5919F36B03D05E37B53
+:103EB000FC142FA9AFC989EBCD5EA2D2E59B85FE8C
+:103EC000B65DD96BA55D177A3BF2D0DBE11482DEDB
+:103ED0008E3CF476A4D0DBF1BD4CDAEB07357616D8
+:103EE000E3DCE91FCFF2EA687F75E4412F5FA54567
+:103EF00079206F56699EFEB083B1ADA9625F0DA3B4
+:103F0000AF4AAFEEE4BA5508BF5F7BD1CE42E3C7FC
+:103F1000C6B178437E823DD550BFD4E936945F97D1
+:103F200032C4507EBDABD890BF31EF4A43FD9B3CBD
+:103F3000E30CF9EF8DBEDE50BFCC5B66C84F9B3CF7
+:103F4000C7507F86AFC2503E6BF66243F91C7D8539
+:103F5000217F4BF59D86FAB7D6AD31947B99D382FC
+:103F6000FD6D3FCE531CEF6FE03CC5D355BFCA710A
+:103F700084D275EC04535D6FF6F8EF4BFEDD3CC464
+:103F8000BB02FC992EEF81A4CBFB1C4D792EE2CF16
+:103F900034DCDBA7F36C5B2AF826BC5E78F9D8E842
+:103FA00083175C9C867FD83173BA85CB87B1571C49
+:103FB0001C9EC5F309431E986EE17265EC55075FC0
+:103FC000CEE4F90143DE14E5C30E5E40F903431E5F
+:103FD00012F9698C548BCC21E3A7FBF93CC65E9B9C
+:103FE000B9C123EC21BDC65BAA147840DC22F08065
+:103FF00034C8F913E941CE9F480F73FEACCA66EC92
+:104000002DCE9F488FF07325BEBFCDCF9548DFE5FD
+:10401000E74AA4EFF17325D2367EAE44FA9B86D9E7
+:10402000947ED8A053BBFF6CA8A6F468431D7DFF07
+:10403000B8A19ED2DF37F8E97B204FD90F826467A1
+:1040400051FEA465F0E3C10EB7CF7A26D4CFAAFC07
+:1040500081CAFFD758C7DAA3B14EDB2DF19FDB7BB6
+:10406000FC7A7DCB590BFB3C44DF6A89F63E9F47C7
+:104070007692814E92D7F2FB786D5A7A094FFFE221
+:10408000D27781DE334A2AD7C5B9710FA4CE0A7E12
+:10409000F9C8D4FBBDE0A63C617F5839C4BB97F892
+:1040A00044FAB1951FB93B3E25C4CF6D0A898BA157
+:1040B000BF90F816E56F56F134D7D8457C9EF227AD
+:1040C000ABB819D55FE94546F2EEEAF516D24F6274
+:1040D0002C2C88FE557CCCD5F6D662C40B5C5DE3F7
+:1040E000A038B4FEFCBBAD84EA79CD3CDDFA675E56
+:1040F000BFA8C77FDD5FC2CFCB09FED28B3AD95DA7
+:10410000AF96FE7BB4B78B723FDA23760A7A064FFE
+:10411000C9AEF624E29C4A7AFCE9A81F2DEA07D131
+:104120005FF67FF1F1627BD64F7A426B31E2A9D222
+:104130009739289E6ACBB820DDDF5AEED63F039D23
+:104140007C11CE4FA369FD64A5C34E5026F5DE6FEA
+:10415000A1C31768A7F0A3F0ACE8A2F01B12774444
+:1041600078ED8B4EE1F409A78BA247E9C51E3C030D
+:104170004F97D2A1874EB0C7FEBF4287119656BA5D
+:10418000FF175163F700AEEFA2CB6D9D6C12EE13DB
+:104190000FCED49B80E78A8BAEB790AF64E32661E5
+:1041A0006B52E59EEF289F85F27E7D97DFD147F920
+:1041B0003B912A1EC1EB28E6749920E5C7AA5281DB
+:1041C000DFC96E33E17742C122D2479943E8752EA9
+:1041D000FE1FE4C9A4AF7D4DE86F5292513F54FEDB
+:1041E000E01B647F93C3FCC03748BDF18630BD70CF
+:1041F000D410A9F7B9995B9CFBC43DF789729F4E17
+:104200009374CEE287F9B1A023D32D105A8771CFD2
+:10421000BD08F7C0FD94BF9E0528BD910569DFBAB2
+:10422000890B38E4BFC718C5331E8A9E5ABE9CF757
+:104230003761F8846C7C0FB9D777DD907E74AFEF6F
+:104240000FCE907B7D0727BA486F3868CF223D0696
+:10425000EBC01A6247FB2597FB086538C4F705A435
+:104260006FF27D219B33F92FF8BE80FC0D796B181E
+:10427000DA4D7219E34D54FB1B9DE3996578DF72AB
+:10428000F7C6A25707C2BEF24EFCE089B03BBF138F
+:104290007FC544CCF79DF8FE269146D8282D7C2575
+:1042A000BB373D4BF161CF78939825F152FC2A7CC6
+:1042B00086E351E1F79FC0E78ADEF0D9041CC0AE67
+:1042C00067FF20362513FE2FB1FE6B5F29EC0FF838
+:1042D0004F0134C425DB055EC2ED3B5F34B081C0C5
+:1042E0002FDB1A47DFEF903C7475FD18AA7F4DFD58
+:1042F000689ADF5551FADA217C9C3325C15CAE39CE
+:10430000B02FB634D2FDDBB32F9A3DD0BF6BCCAE0D
+:104310000D1EACF577C47D39F6F5A10CF8DBD8D6C7
+:10432000DEE3766BEC0A6F7EC2A737D3DB24F63F61
+:10433000718F58EDBF032344BCABBACFDAD77E3CB4
+:104340002A4AC8958111420E2A3AF176944FE3FD2C
+:104350008CE27223EDA128D2BF4724781F073ED5F7
+:10436000391AF14DD8A7AE09E6C7213F19E7499E92
+:104370007F5BDE4F7B7B685D5226C7F7219BFE2C5F
+:10438000DA31F3D766ACEBC61C8DEEB9771DC94A9E
+:1043900002BEB7A97557C48A42DF1B50FA71F7787D
+:1043A0004966F28BAF847F3409E7263BD98BAE6137
+:1043B000B9E4379D28C72FFD6525BD83A0EE7D4458
+:1043C000A4988CEFE7B8A20CEFC144E72518F231AE
+:1043D0009E0186FA71A3330DE5F1DEA186F2C4C910
+:1043E00025867C3FDF1843FDFEB3C71BDF75D36F07
+:1043F00030D44FABBED99057F22B4D7C62E9757328
+:104400000DED07D5CF37D477FB9718DFB7F17BDBFE
+:10441000F29221F7C45FD6FA9586F21FC78A7B0D08
+:10442000931D0BE9BD8A9CE6BB8CE34B3AA5C509FD
+:104430003A319790AF7EFE1FF8A634C5286F273813
+:104440008DE76DAE0F6AD8DFD3EA2C86EF9FFD0FA4
+:10445000E91C8E972EBE3505511FFA10CF5FA30FB2
+:104460007D08768D8949564F80097B7AE8BC604F7C
+:104470000FC503ECE9A179D8D38DEF4219E90E7B82
+:104480007A68F9F02346BA8F6C33D2FD8AA346BA14
+:104490002B7E0CA7CF95ED467E08A7CF5527C3F8F6
+:1044A00043D26336FFEFEFE29E34D16B9243634F0A
+:1044B000B8FF79FA240FE5F4C9EFA1CFFF49D35330
+:1044C00087F6C3FDF40B1936D0AB53BCD7B742CA3D
+:1044D0004F154FC8CFBBE23EDD5D66F2EF1F3335AF
+:1044E000D37B49079DBA1BED6F2BA8D3E03F4861F2
+:1044F000BE5D0B397CF3FE2382FC09F306897B9DAC
+:10450000ACA09DE2EC959C9B9726E258860C95E723
+:104510000B8F886729182AF4C2188F93E25E2B0A42
+:10452000C43D027E2CC8985708FE793712EF1676E4
+:104530006D12F6FB76ABB85FEAE77C04BF18F44473
+:10454000E871E9528F6AFC9DDD0EF8076F66867D83
+:104550007148C06E88BBCCDFE134E40B5B530CF5D3
+:1045600087ED7319CA8B837986F2E1473C86FCC8D4
+:10457000B6D186FA571CF51AF257B64F36D4BFEAB1
+:10458000A4CF904F639D8F03BF8334711EAD1A2A51
+:10459000E278F81A227FD2BC7BE3C5FD41794E5503
+:1045A0007AB08AC7D525DF85EBD3836C3AC5F73659
+:1045B000A6320FDD03B0CBF30933EAD9BA8CA75585
+:1045C000FA28F31BE369551C6DB73E2EF56FA50F56
+:1045D00087C4D17A43E368E7C97BBEE1FB5E9DA453
+:1045E0007B38FC836C62BE8D77DAE8DE82822B1C1E
+:1045F0009EBFC9F8CE6DF6DEEF8FDC3D54F8DB7F51
+:1046000099E5FB3EF8F529888FACDEC6F3B4FB399B
+:104610007F35FEBBCDB3D6F5DDE3CD1B26E6536E6D
+:1046200032DD565640714BB37F1632FE0FE5B8AB04
+:104630000AB45EE7372F4EC415B1389B0BFCDBF78D
+:1046400078029F2936D644F75C64DCF9AD1B5A1F0B
+:104650008489BCDCD66C15EF9705ACE08729E3B9FB
+:10466000FE540CBBD5370F3BB89EF154BD85EC1002
+:104670008F0CBD69863FBBE71EC1207EBE007F4018
+:1046800057C1B9C45E20E266F70E15EBBFD4FC75C6
+:1046900077FC37D9D31993F25B9C5B7AE137E2431D
+:1046A000358F7F751C78389ED4B990C97D275BC241
+:1046B000A5F0D77D8E97F853F1F8AE1556DF330E7F
+:1046C0008AEB9F8C782645BF8105822F4F0E15F40B
+:1046D000463DC8A3BEEA959A0BE260AFED62AE38E4
+:1046E000E7B7D823FF557851F8EFEB7E4F5FF2E143
+:1046F00012B9D0C77D9FBEF893FEFE817B3F21F2A9
+:1047000041C497487A04B24DE4CFBD37C6B88EFB9A
+:10471000E70BFCEE57FB859F9F278D7282C1BEDCA5
+:10472000B8CE2CE584D857A16FE0FB827556D237FE
+:1047300058BD8847AE96B298315FF29811F0C75ACB
+:10474000E93DAB6BBC8CF491F90E5BA085D7AFF063
+:1047500087EFAB5E6A4FFE1A17DE2DF1DC03FB7BA1
+:10476000E57A63BD450EF1AED782B073E922792EAA
+:104770005D14762E8DCC97FBB28779486F92FE67D9
+:104780000567375F05B2282E18E754B3B09750BCC1
+:1047900052B71D1FFE85907734393EA3F2B06F37B4
+:1047A000597A8D23EBC6671F7EF233F093BBB0FEC0
+:1047B000BBE8FE4FD7EE48E14753FE0B59FF8CFF95
+:1047C0000295A33E7A3B5BDC56043F52B7BF23CC35
+:1047D0006FD2E530C58E467F3BC5FB0B2A0E60C904
+:1047E0005F0345CE103FA7DE6E32C45D84A7FA9A00
+:1047F0003D1417D062D14BF2F93C4E5B3C76BC17AE
+:10480000799FE36032EE6B4F91F69A7078BBF5D0EA
+:10481000B19AF013FA851EDA3559233D94CB4586BB
+:1048200075A4FCD9652C988454F90FF4F5A309CF2D
+:10483000CA7F50111C4D70CE685C64C5937DED8FAE
+:10484000AF2E8D72F5F815DAD3453C4A5FFE8569C7
+:10485000173DD4DFF48B63A89FB27CB7B8C7D5F4FB
+:10486000E00AF0D1D01DCC8A79B687C563ABF4409D
+:10487000BEB07F1FCB57725BC6B9ACD1849EAD3141
+:1048800015F742725BE52F34CB7CA9C8AF5A27F2EB
+:10489000EDF21DA3EDD2DE807922C57C702EDE29DB
+:1048A000ED11980752CC03DF21A790879C421E721E
+:1048B0000A79C829A49053F83E9FF9328ACDC20FD5
+:1048C000323164DDC00F3231440F821F24340F3F78
+:1048D00048687DF84142CBE107092D871F24340F3A
+:1048E0003F48687DF84142F36CF4F53D79C8356F77
+:1048F00099213F8DEBE31343D62DFC20A1FDC30F7F
+:1049000062E84F5F61687F0BAB37B4871F24B4FE4A
+:104910006DF59AC14F729BBC975EB93981F8638E71
+:10492000DBF7C37C4EDF3F447F738715E734F3FE2C
+:10493000C5747EAA8DF2083A374F1674373141E7B5
+:10494000CE3944E7D536912F1571B1BDF91B2666D6
+:104950000B7F0352F81B90C2DF8014FE06BC870D4C
+:104960007F0352F81BF01DFE06A4F0372085BF011F
+:1049700029FC0D48E16F400A7F03DAC1DF8014FE95
+:10498000067C87BF0129FC0DF87E0C7E8FEC1EB8DB
+:10499000A0B7671BCE779C0F0DE73BA7210FBD3D4E
+:1049A000B43EF4F6D072E8EDA1E5D0DB43F3D0DB02
+:1049B00043EB436F0FCDB70D75D1BA84FE1EDA0EEF
+:1049C000FA7B68BEB0D9FF266C4C376D3977186911
+:1049D0007B8CF694C645C1FBCF1F9F01BF517BA4C2
+:1049E0009611CF97BC553B356322D7CF74195F56CC
+:1049F000C43AE97D675DBE5BA30719C5C316FE25F2
+:104A000045C805756F087F9CEEC5BB199D03CAE4B8
+:104A10007EAADA7B98D34C724BD6EFC9F75E2F7C17
+:104A20007C558FE465081CFC80588C3888E2D58E54
+:104A300012C4716F3769220E72AD88430DE72B7374
+:104A400081904BDB4DBB0E4621AEA542A3F7E2732E
+:104A50002DEC08DEF12E6CAE2B81BE703A3F5ECE9F
+:104A6000AB6E0CE26214DCCA0EC8E504DDAB1ADBE7
+:104A7000C96C5505784F8CD91640BEDB849E807674
+:104A8000383FE6FB35EF3321FCFDE77CB1BFE9FEA3
+:104A90001563AAF8F7FC9D7563705F6B4A9468F71D
+:104AA00093A763098F539BB467702F6EEC4EE6C5D6
+:104AB000FDCB6FA43CCDDFE9B455D1B84EBAE7A524
+:104AC000FAADD89241F7D22A58FBC414B2E56BF480
+:104AD0008EB9C21B9FDF61CC8F8BF82356D247C59E
+:104AE0007D9128795F44DD13715B7CC1A1237BEE4E
+:104AF0008B5C3D22BE14F15A6CBF7877EFA611157E
+:104B0000EBFAF1FEF5807877EFEA3FD5BD49F9ADD4
+:104B1000E2DD3D628351340EED6B83FD1ABDF7304B
+:104B2000D5DF624A72E1FEE81A6B32EAEF641EA832
+:104B30003F8399B807A9E02B606D26BC3BCEB798A0
+:104B40004389217CC425C074D0BDD863A5F720CA91
+:104B50002C4E2BE446F83E7E693C5D989E10160F65
+:104B6000D1B8FA68863913F61E932708B9B5279A83
+:104B7000F405A5EF54C838A80B4D6FD27BD615BBF2
+:104B8000847EA0733900F9A7E2236AB3021926E8EC
+:104B90000B035A8A12CC62FF2FC07D24FFCB334710
+:104BA000BB708FF14D8AD7AF5837324EDCD711FE2C
+:104BB000872A89A72A19FFC20A9CC9D03BD53BA6E0
+:104BC000A5E6B17174DFAD59E873CAFE52F1ABE1ED
+:104BD0006F81CE154FCAF740D657D03DA0F038149C
+:104BE000A51FAAF74E16375929BE6571981EB854ED
+:104BF000EA814BC3F4C01B0AC2F440F53E9DAC539E
+:104C0000F1AB4333484FA913EFF195AF117A0BDBAA
+:104C100025DEB12F5F33C184772BCAF7783D5A2F39
+:104C2000FCF1BED45FA660D044C4F90CA074E6C504
+:104C3000144A675DCC233980BB18A07FFBAB8CF492
+:104C4000E90FA4BE3203717EB81FE78F90F17C8C10
+:104C5000F4A562E62C85DC18EAD50EC17C3DC5AA18
+:104C6000AF431CE1941646F7616E825EC30B664348
+:104C7000CF190E3E7797D2BD80C91ADDAFB869C48F
+:104C80000AC9D79CCF19F8DC2FF9D647F9EEFD40B9
+:104C9000F2B7EEEFB0D0BBAC7ECD8677D974799EFB
+:104CA00055FC1BCEE7F3E4EF4D3087B03375DBA145
+:104CB000002C3DAE72CD4CE88BF360BB1B2009C9C4
+:104CC00051145320CA9B0AAE99D984C3CDFFD03E5C
+:104CD00051AE7E8781EB5990A7B7DE5E6C9B1F2299
+:104CE00057CA8AC63F5BD8AF87EEF3BBEF8D15F48A
+:104CF00087FEBFF2BE9CFEDF767FB192E319EB63C5
+:104D00005E5CFB1D7819776B01F34E1C8DF798D50F
+:104D10003C5910F16A7365FED7058BFE737D01E186
+:104D200087F2819D5366FA69BD0879750BE4951980
+:104D3000724A7FAA00F73BECED93408FE8824E79F0
+:104D40001F5EEE4761F6885F17083A84DB252A0B61
+:104D5000841C671657C62D744FD545763D05FF67F1
+:104D600056E3BD4195FE52ED230DFF9A78FBAF92BD
+:104D7000F59F437E3C6A12F7B707989B99B40F8959
+:104D8000DFC990EB87C9F70C7AE8CFA506E87F9FCB
+:104D9000E60CA5BFBE5E13F7A6FBB0E3B0BCCEC762
+:104DA000B7C18ED7207E9FE3E95CC1474FDF652303
+:104DB000FDBBDCD6F626DE695278FCA4FE4756F130
+:104DC0003B2FC11CBC3F35B72E92DE7B2D2BF2B59D
+:104DD000812ED1051EA2C7B38829E5F5DB9DBE0F44
+:104DE000309FDA0D079EC2FDF1E5FBDD74AFB162C5
+:104DF0005FF13D78D7A2AC483F8AF20A87D386FD9F
+:104E00007B59533CED67F3FACBFB85AC93FC540A1A
+:104E1000FF9D05C28EB5BD48F47F5E9E432028CB22
+:104E20000CF5645C71D83A51F6C1703B43F87B02D3
+:104E30007DAD1F654F80FDC016625F54F6096BDEC5
+:104E40006773B07F96DB8CF7E154EA2E94E75C79C8
+:104E50000E5CD0BD7F154CEA0F7D79A346BF5B5336
+:104E6000E570CDBA92E7AB8E581129C8A624B8C414
+:104E70003B12F7897724E6F3F50A79532EE386AAE5
+:104E8000368FA6F55615E06962DFEBF2968D87D274
+:104E90005F05FF04BD744FBCCAE9B52584ACFBCAED
+:104EA00066CD70CF5CE5E30B853DAE1C4F98974017
+:104EB0005EB86D78CBA59CAB1588437317BA0C7E92
+:104EC000575E8FE218A664B2B7C43B3E1C6EB7189B
+:104ED000AF24A4FFF9CDC6FBF2BCBE7897A2308602
+:104EE000FAAB70F279C3FEE174129C1C0F84A7CE5A
+:104EF00007797F2E1A87E851190C5871DE2E47FC6E
+:104F000004CFCF7506AC18677E9378B742DF20C612
+:104F1000D1D7C7DB0AA12F599CB674E04FBE6BCF27
+:104F2000E1233958C5F182FB3FEA1E60387E2A240E
+:104F3000BC55CDF1463DAC79A315F498D3C7FDF926
+:104F40009B24DDE7378DA3FBCF55162FC5D7EB127A
+:104F5000BF7F5C11793FFC0373363D6675F3FCD56A
+:104F600085827F6F92789D9219CCA1F76956447A19
+:104F700000E71C6733CDAF1BBF8F707C687807C517
+:104F800047F8E57CE1471C59D526233D7BE011F825
+:104F9000ADDA5441EB6DA145B73943E1D87C200728
+:104FA000F77AE6F0F58D77779853A7FB369F3F3277
+:104FB0002B83E6C9E1045E633CAE49786F86F30952
+:104FC000F1B1E217753F588DB7A050DC135C50D893
+:104FD000BB7DBD675D7A49BF69E4F485DDBBAF7514
+:104FE00069C345233EAEAD4ABC0316BE4ED5FA5446
+:104FF000EB52AD53B57E9FB2FA82295A8F9CE1FBEA
+:105000006DDDCF7AC1D3B312DEB992AE1CAF874348
+:10501000EF156D2814F2A83CD3B8DED11FFABD4BB2
+:10502000958F0FE6E01EA0AAAFC62D97BFD305BE91
+:1050300007BFDD25E98EFA2BA9BEF17E4465B7BC1A
+:10504000D8B92E19F2629746FAEECA070FA5FF1BD0
+:10505000F4D817841E7BBA66DBB254D80D2C818C31
+:10506000D0F799AA82423E2CE0FA0FE4C542B94F2C
+:105070005F97A3DF573832A4DEC32FE4EA42BE04B1
+:10508000215F7EFFC26B1F8D71F5EC9F0AFEF9EB6D
+:105090007F6DAD7084E24BF0F9FD795D74EFABD2BA
+:1050A000617321CEB6B2A982E42D4BE1E7092D242C
+:1050B0004E2A8C0F2A9A347A37ABB27E54C0FCBF8A
+:1050C00028972B3794D1DB3C8A4EEAFD0DB59F2AF9
+:1050D000F8774AF8E74A3E7E49AEBFB9D56EDB4263
+:1050E0005AF76E5B25F85F96CFA9327EEFA653B7CD
+:1050F0009FB9E09E14798F85CE251BACC2BEB73315
+:1051000086F4D5D32B5F796F26AFF7E5A32D19D0A1
+:105110004F141C8BA41D6F81B4C72D947A2BA7D379
+:105120001B85217276D1D3824E952FFEEA53BC0F98
+:10513000559E29E5D983E27EF9FCD65D44B739EB6B
+:10514000375ADDBCDE7B856E839CAEAC2B76C23ECF
+:105150003D777D8B1572E0BD4281B7707E2F9771D0
+:10516000A90AAFD877B410FF85AA0FF9B78B8F7350
+:10517000FB8AC858C465A871FE5BF271655D7C024C
+:10518000C6ABACABF821CE3D4ADE87AFBBE3916244
+:105190003DCCE7FD615D1E1FE7A17BB6E5F2F7A5FB
+:1051A000C2EB9F9374FBB155BC239816DDFA1CC566
+:1051B000152C8FF2403E6467B707302EF81970DB6C
+:1051C0004CE2DDC1EC9AF6AF0007578B293E05296A
+:1051D000DE3B829A9CCCF3CF98C47D20C496204DB0
+:1051E0002A12FC00D314CA59523BBD7F16129F6984
+:1051F000E0571BDBBA1EEFAFD89218FDDE8BE24FF3
+:10520000D58FE24FC5BF7DCDCF517479F33BEE967C
+:1052100076883C4F06EE51CC7B6830BDCFFF5DF306
+:10522000B4C977F0BAE71B217EB7E092F9668B73B9
+:105230004BDFF3DD549ADCCB7CC3E7A9D6898ABD6A
+:10524000EEF62B340BBFC2718DEF5FBCDDF1159113
+:1052500014F7A5E6A5ECDE971B2FEF294A9076847C
+:10526000F618E891E5F2F7205850E4F1BD2CE4BBC4
+:10527000DAF7D5BB614A3E9FA893FB226B7F10EB08
+:1052800099D567D13B19C79A8FC7E0FD8EE3E30438
+:105290007CAADDED5671EF95C5D85C783F919FAF44
+:1052A000E8771F1634F5A773E4ADF55924176EF5AA
+:1052B000C70BBB83D4EF174A39187D7BC53D57A078
+:1052C000FE66B753E3E32C70783EDF4CEDF33DD040
+:1052D00007A33795D93249EF15E700E507BA5D63B3
+:1052E0003EBACF043989F5653A908D7D67D16671F4
+:1052F0000E986262EBE12F1CD4E89B940A39F1B856
+:105300007837926D31BEAB7430C7776311F016F603
+:105310001ED9EDD6566F7FC871AE6FC0CEB4C0E156
+:1053200023BDFD6D29278F6DEAA0F7C9155E2FB942
+:10533000A76213F7523B634C647FBBDCFB2A55D258
+:105340009FA4F846F9A39EC0FF5D093C99685F2BB6
+:105350003597D3BB3EF76C9A4069D5C6D247FD85D9
+:10536000B80FEB4B1E43705BC93E56553B41DC1FEB
+:105370007D26221EE79B0CAB3F23542FAD6AB997C5
+:10538000EEA99C6C89A47B2A139D6513E393E8BD69
+:105390005DBAF7A5EAFD40AECB25B5130CF74C1668
+:1053A000F03E1107FBE7D6688A2B55F747EE8ED201
+:1053B000BF5FD44FDC23B9D225EE8FA4527D57AF07
+:1053C000F670957EDE20EE2384DC8B993A87B7AFAA
+:1053D000A97D3916FD2C7DE483511C33B03FAD050A
+:1053E000DDBAEFC56C16F7621A715E821E99E09BFA
+:1053F0003907F8FFA599F0DFD778D5F85192907367
+:10540000C4AD8138D25BF520B3C19FAC3B19E9C56F
+:1054100027CDAC1E7A80D25FD4F747255E4EC635C5
+:1054200067803F166F7F2C03FBCBA918912FDF3EBF
+:10543000EB6DC82B7D6B84D0CF2D8CF4E14ABFD0AF
+:10544000AF5975827A1733721EFCB145D1E21D1E29
+:10545000797F46C1A5DE5B3D6511EFC5E05E0CF8C6
+:10546000FD134B7001E8FB09D75F718EFD819463DA
+:105470009F349BE97747FC7CA1400FF9A4F9E5181C
+:10548000DCCF55FA5AA9F9F75EBC47B3728FB8A7BB
+:105490008A77CDE9CD4A69075926ED202B5FB54EB5
+:1054A000C2EF8E70FD8BBED45882B6DEE8B744EAF8
+:1054B00057DDF9DDBBE8DC56B353E80F35AD1DA46D
+:1054C0003F287D44DD8B5BBAB383F409D56ED96E7A
+:1054D0008197DADDE27B05E2D6E5EF856AD9384FC0
+:1054E0006B94FFB460FEAC3596D07C05E53F2D5043
+:1054F000F6914ED207EFCFFB0D9DC36B9B64BF3C73
+:105500006F0D19EF4D30693FF13DCB81F662DF57EA
+:10551000E5B5BBE3A97DB0366A3DF679EF32870584
+:105520006963AD83F6FD2D75A63CCB080017E581B8
+:105530001EB75FC66FF55BFA9F91B01FA4B2CE4352
+:1055400078F7F5A0533F0A7E55BF67A9EEBD9C7F53
+:10555000FD8BE1E8FF9A41ED17F0C683754DED2C08
+:10556000F827DA8BE43C0ADA8783AFFB1D14F2F9E3
+:10557000492B5B4FEF075B7C0C76FBA0F42BFAFF0B
+:105580006212BF2FA1059F0DD5AF9286093DDC1792
+:1055900021FC8B5EB77E0A707C4FB31616E34CED90
+:1055A00032E7A07FF53B2A4A4F1D2FE573BA3C5FD7
+:1055B000D906A438C0C79AD74BF710D7161CACC46D
+:1055C000BEFC40A79D7E5F55C5E18DEF8C22BD35A9
+:1055D0007DC064DACF34978595F3FA070B4C41DC34
+:1055E000DB7A80D9455C803D4CAF3545523CB2B644
+:1055F000FF177F813C4F337F7508BF5392F66F1AB8
+:10560000BD7F39AFEBF327F11B33E52C504CEFE0B6
+:10561000C5EBA66190C35D933B744EB2079CAD761B
+:105620008FD8275828FCFBEFFC4B6C82A907AEF300
+:105630009D9FD3BB82E73BED64AF1DBF5FBEB71735
+:1056400006CFF91417C545F37AA4679E7798E89DAD
+:10565000B1F1FB0FD1BB79E3D5BB7A76E3BB7ACC52
+:10566000951E0F7B32D950B95290DC28E8764D9CBC
+:10567000F19C98334C9CB7728609F9A1F0D7653F2D
+:10568000F78EAEF5ACC3E5CA7FAF7E6FAA3A827ED5
+:105690006FAA6B7FD6B7BE9FF001F407AE176CC838
+:1056A000F4160EEBD7B37FCE907851FBB059F63F8E
+:1056B00043E26786C324F011F67B1B8A3F14FD1575
+:1056C000BCEADE91A21BBBABED4DDC0BE2F42A7C05
+:1056D00088119DAE203AFDE5DD75B8E63FC0ECEDE2
+:1056E000D0DDFF123A05F10ECE65D3A92D9C4EC137
+:1056F000C8C1D0131E11BFBF151ED7C8F218ADF315
+:1057000079E628B203EAF25D70BEBEDFC4FA56EB5A
+:105710007AD0E4F642EC8FC7F8D11B70B59B5AE9FA
+:10572000FBF7878978C281AC2D55C6DF8C845ED6A5
+:1057300028DF3FEEFE1DC3C50E7A6FE47C40BD7FBF
+:105740001C787C211F77D38C02B2EB9F6772BD5708
+:1057500077BF932DDE3FEE7E27DBEC273BC99C28ED
+:10576000B2F374BF939D23DEBB7E4D63B97887D6B9
+:105770005F66A7F8F8F077B2F93EF31CFC194F54B6
+:1057800047911F4ABD8F3CDEA9D7818EE1EF233FB1
+:10579000AAF9E62C407F850EEAAF7D4ED48BDB055F
+:1057A0009A83B0E31CAB8FA177A1155F2AFBF5208C
+:1057B0007FC7E3C093BAD7F907C95F0AEFEA5E9BD8
+:1057C000C2BFE233BF95D1FD4FD001EFCAAAF7D9CE
+:1057D000B5D5526EA8FB846F785C481F8CD7D70371
+:1057E000EEC6155C6E905DBCFD0ECCF7C93B63BC8C
+:1057F00080EB98C9F8FBBD2A7D7898C9F03BA1F3EE
+:10580000E47E354FC5FDD71BE3FEC3DFD14C8CF3DF
+:105810003D328CB73FAB7D300A1FDFFD3FE65EE3D4
+:10582000489E92EB7F44B4FE24EAABFB0F4A3F7CD8
+:10583000B7F88B74FABD91AF0FD1EF2ACE75FA028B
+:10584000A817992DFC017F486DA7FB1A7F98F3D705
+:1058500074B227AF16EF7F5E2E9C97DEA715FCB0C3
+:105860006A8188374C6375C4BF293DF7342301C76B
+:10587000FF6FF7697BEEBB4E1E7E82E22E7CF47BCF
+:1058800015E1F4181B71F065173FA9FC76D897B3A2
+:10589000E83E69DCC1556E9E3FF6D239914F3B78A8
+:1058A000C1CD69D3FED27991CF3F7801F7513F7BCB
+:1058B000A953E4AF62E4CF3AF1D257B370FFB4BF5B
+:1058C0005BFF23E835F362DD9BD85E3F5A73F3023A
+:1058D00037DDA72C4BCF13F7293F41F98CE4F9EBC7
+:1058E000E2B49EFB94268FEF8FE0DBF35F09FE7638
+:1058F0007358C127FF6CAAEE932A79DB975C54EBAF
+:10590000EE5F751F56AD63B6DDB3DE0A26F4FFD336
+:10591000F7549987CFEBFF021C7874630080000076
+:10592000000000001F8B080000000000000BB57C89
+:105930000B7854D5B5F03E73E6994C9249C80B02EA
+:10594000E104420C18D299BCC05BEA1D2089015ABF
+:105950001B6CB52018068D90D76442A82DB5D80CC5
+:105960000611A8DE0B5754B06827400035E8A001A7
+:105970002718EA00922252BF98FB37F2FD5FE10B35
+:105980003E90979310B557EF55B96BADBD4FE641BB
+:1059900022DAFE7FF8DAEDDAEFBDD77BAD7D86B196
+:1059A000B196F3D18CFEAEC98C1D3FFC9EA249641A
+:1059B0006C4681D16A90A034772BC6020EBB01DE03
+:1059C0007595F935B1BC9F36B45FA2D766C17E75B7
+:1059D00066EA973908FD72B1DF9F476BB1BE416F30
+:1059E000356430F6B48EB94D098CC5688EC8B84E92
+:1059F000CC2063CDD07FAC8131631E63297AC6B0E1
+:105A00001DFA312394BB06F97AE3121A56309867CF
+:105A10005C85D9DA9C81BBF53056C858DA28FF6816
+:105A2000DC5FDA4A3DD5C7687A940633638126FF86
+:105A3000DC0F33192B8E8ACD653F8052CFB2711F98
+:105A40004C13656D85F54AE4AFBAD2006EEC906CEC
+:105A5000B0342B36946F671319ABD7029088FF339D
+:105A6000795A711D6D77F51EE8D7939C66DD08E0C5
+:105A7000D8D4832C331FC6BBCA72D804C68E5A1C16
+:105A800039D62468679B241C1F9DC3C7FFAC2C7AA2
+:105A9000870CE3FB0FDF54E880BA3B0CCA01666554
+:105AA0002CDF3B7A81F61680E39442C902B075EC94
+:105AB00002ED688053940312B41BDDA31714DF8238
+:105AC000E7335A3ECC66EC174C627180970CAD639D
+:105AD000BA15CEEB2CFB44CF34D83EA02F9F0AF74B
+:105AE0006A854960FDA4A3704FB0CF8139319E1DF6
+:105AF000703E96A314627BBA6E20D602F7D1FF9552
+:105B0000B6CC63A671B13F87FA6BF8F7AF8C3DD77F
+:105B10002953BD0AABE5375689EED795697E0CEF60
+:105B2000AF3ED568A4B2F36A29C379B4E59977C0CA
+:105B30003C763D5B529E73FDF801AB86F695B10E47
+:105B4000103A86C8CBCE14F8BF28A6C26E369DB1D7
+:105B5000965F41C5BFF0763809D34FD208F896ADAD
+:105B6000C5DAB0FE76EC1F6C6776230B8E775AA7EA
+:105B70006E5D9B29D6433C2F639E49708434D620AA
+:105B800031B8BF54E627FCBC644BA073D11FE0E9D9
+:105B9000D94453CB46A45719E8328F4A6681322D37
+:105BA0001AD683F6B4374C1EA4AB5D264EB7991AAD
+:105BB0005EEED2F0FEFA28E6463A1D073083F26D1B
+:105BC0009BE377B6249AC74FF3C8FB6D488FA39920
+:105BD00097D64F616EDA8FDA6F2CEB3621CCB40397
+:105BE00059844F5933EC7D26D9666E463A0B34D929
+:105BF000D947DA607D203A765528FEEA71BC3974BF
+:105C0000DC2C1AA78E77AED2B08F46E1E1FD443F7F
+:105C1000CE4C8DDD9383E3D89B521ED677EBCB63BE
+:105C200082E37A9B8CEC23B8D7FFD3C4A83CDD6415
+:105C3000A1F5FF6F532A957F6B52A8FE6C533695E2
+:105C40007D4D56AA7FBF693A95772D8A2940FA770C
+:105C5000F966B28F8C42CEC0FF9C5E9DA32F04EEEE
+:105C60009D393C1DBD26E8A83763F8F66E6C077CAD
+:105C7000F6DECAF1D97F3FF3ECC820BA5C6B49B8B5
+:105C80001EFF30C284E7EB8F610BBC704F6F17486B
+:105C9000347FFF680EEFB7EA683EBB866DC5F16FD3
+:105CA00017E8F9FC133455D86E4FE0F3F666010C93
+:105CB000FB59307DE6CBC897F664A8CF0BC2BD5325
+:105CC00078BB7D0CAF57F7ABB6FFCE66E17428F01A
+:105CD000DEAF83F57388DE697EB5FFD7459C0F2361
+:105CE000FB7B3235659E61EE23C1C6FB135FC07D31
+:105CF000B8910F3242F8A25E21BE50E950A5BF977D
+:105D00006CFC9E330D82CE4127D0FDA16E40F99AE6
+:105D1000027C20D1BDD8199C679724F825921FA03A
+:105D20004439AEF283CA072ABDA7019F4909C1734E
+:105D3000FC28825ED5F2B495E3A53B39E601C26B3F
+:105D4000A7CE02A210FA03221310BEB3C00EE34A7C
+:105D50001E35370C27BFE2FED97B50E5C108F7702E
+:105D6000DDF9F5BCFCBEE727F986721BE9761879E8
+:105D7000F5B53581F6A3D26D92CDFE5F483FFD9219
+:105D8000492BC54169E2741379FEB70BF83954FA0F
+:105D900079C9C6B8BEC4734EBC5EDEA9E7193AE73E
+:105DA0007246722F338AD747E2573D5788DC8BB152
+:105DB0001506EF93316E0F8C057B606346907E0372
+:105DC000495F2E43FDB5CDAAD0FEFEA09109FFAAE2
+:105DD0003E19AA97E425F373C2F40CB3001E070E14
+:105DE0001B88BFFD1A56F50A8C6B2555113CF76DC3
+:105DF000362E0F06174CD2AC827D05FE6E76A3DEE2
+:105E00000A8C19382BC1F8C0563040C87EB0FF58F4
+:105E10004A66EC7ED029A897AE809C63598CC9DB7A
+:105E20003E3F2BC1BE976D9319DA350110DB328CE2
+:105E3000733D19E331F2718CC1B83A31AE79EBA7F9
+:105E400077217D9D07FA44FBE62353FD040676CFB8
+:105E5000EC6D3ABAC765317A0FD61FDBFAC48945B3
+:105E6000009F6F9714B4374A6533B5D73C2F7B70CA
+:105E70009D3A73E94509EC9C407BCB535150EFDCD4
+:105E8000AB63261857DA2E59FD30FF726F0CDE0C0B
+:105E90005BB645F77E5F76506EDE26F458D52EC988
+:105EA0000314C3AAB687B7D7EC0A87EB983608C3A2
+:105EB000FCB36C318964FF4D6636B4FFD896045448
+:105EC0005643723B92AE506D237EEC8D5C1E33F6D2
+:105ED00059F21D4097F2E1CFD3DF377378BE80CF00
+:105EE00001FCC9E7FCFED57BAB1732FF93D1ACC0F8
+:105EF0000BE7AC3F6CB2B8E160F51D329D23E08D3D
+:105F0000A37B7645F5DD4E7C7A48B6A01DB6C12749
+:105F1000BBB1DDD969DAA98173D61F9018DA9F4E1B
+:105F20009FC1C3EFE9EA326C5FEE3359146C3F64F2
+:105F300060328C0F00DE4C88C7717D847FC42BDA01
+:105F4000A7F0F763A928887F19F19518C457F3566D
+:105F5000BE9FF37B397E4AE5D55AC2578BC4524265
+:105F6000F0FC67CD8B43F8C27EB3B7FDB50BF1BC37
+:105F70000CF6675010EF32E1F93CE007E7D51FFE61
+:105F800028BDCF1CC4B70CF8FEAD3A1EFA2FBF01D6
+:105F9000BEAB987B1DDA73DF17CF69C8FF4964F782
+:105FA0009EFF03DABD31608F23E908FB38A9B6F7FD
+:105FB00078222C589170D9B902EA27A5BEC232C105
+:105FC0004E90E21D8F225F9F9DF39747101D3D73FA
+:105FD0005FB4215D34EBFA5A9F860A777CB4157959
+:105FE000B03F63FEF6D7609DE2842FD3F723BFFC5A
+:105FF000C96041727A42F023FE1901FF4EC6EF1BC1
+:10600000F0780ECFEFEC34F80D708FACBDC43E6469
+:106010000F4C407DECD5A39C2AD10F54AC407B1C87
+:10602000E6C375242023E4EBDACE3F9F96609CA460
+:1060300024B2C5081BCD7E19E769D35D193A37CC68
+:106040002359FE42FDDA6C13E8FC13537EA4A0FC36
+:10605000695EC81C5113BF4DCE3392F3CF0A7F65E2
+:1060600044FB6F0479AFDA7DCC3D361EF90BEF822D
+:10607000F30F973BCBA733F127F842C0556BDCB148
+:1060800046E8BCFC666B2A9EFF63A4B358A4BF53CA
+:10609000DA51B0AFBA5689F0568FF483FE15EA375D
+:1060A000A8EFF70A39F27C77F1A8442C252B702A47
+:1060B000ABEE94AD7E68AFF6717ABA8E6E84FCA8B2
+:1060C00069E3F2E33A3A6A0338C44EAB47BA526125
+:1060D000C0F7C9A0FC987A0DF6FBF23426F4955B64
+:1060E000D05B4E5C1FD0CB2053E22C39217A4BE29F
+:1060F000F6962A576EDA0AA23E64DDC91E23D386BD
+:10610000AC7BF35E4B183CD59B1AD6FF073E25AC03
+:10611000DDE6CF0E6BCF3F610D830BBBA787F59FED
+:1061200076DA1E06DFD25716D6FF8717CAC3E0C13C
+:106130001C38CF3076C7901E4A95C2FACF514C61B9
+:10614000F3CFCB8E0F8307CDE27E841DA8DAA75F45
+:10615000D8B81D1459AAF7FB136BF83AAA5FFCD301
+:10616000E9E1EBCDB787AFF75DF1B21BEC7E2DD83F
+:10617000F57B413F62F902D8FF5AB0EBDBC0FE4726
+:10618000F825B0FFB1F482FD8FF5AF80FD8F703B35
+:10619000D8FF081F047F05615F531995879ACAA924
+:1061A000FE46F7D725D63D21D63D29D6FD47EF49F6
+:1061B0002D9D6593345F009FCE4CB8A847396C6F16
+:1061C000EC2BC538C0C05B32DB810CE2F09C684A26
+:1061D000447D348AA1DDC2CA07DEC63845FD818907
+:1061E000968D0AEAA1FF7C07DB03EDB282F2FCA8E0
+:1061F000EF83589CE7CA17C087F938EE8358F48FAD
+:10620000EBBE64046F847605E039FB4130903D03BA
+:10621000720DFB67AAB047CFA02C6FDBAF477CD4D1
+:10622000EEDD4FED6F7975E1ED7B5BC2DA2DD81FA6
+:10623000CA5AAD87FCFB4B3E753E3FF5AFCB94ECA5
+:1062400068175FDAFB9FC9CBB05FDBBBC9F77DCBBB
+:106250007D7F72F0C51C94EB4ED0C37E73701E67B9
+:10626000874EC07CDF7599FB4B135011B4496C12FB
+:106270001457D826B60AE45DADAFB50EE5506DF6FD
+:10628000221DCB207924E20D206DD15E42E71EEE67
+:10629000EF8AF7D3D8FB60DE37BCC76FB723FE3A6F
+:1062A0008FC5E2BAFDED72983F73771EB75BEFCEF4
+:1062B000D313DEAEB41F8B55A07D83F718BF6FAD2F
+:1062C0009FCE7D54C0FD50D23DFB643A77F5171A3E
+:1062D000BA7F75BEFBF3649A678E6F520C9EABC794
+:1062E000CBD773E529B4CE9CCCA595B8FF93A90B69
+:1062F0000B65B2F34030A35C9D32AF15E303B55E8E
+:10630000D93E9CBFB546CCDBA5E374F856E6AB5D41
+:1063100063803E4E968DB291CC17FD7E93C7EDF112
+:1063200052BD2313F5428F5989413A7EB86C620CF5
+:10633000E2F52896585FB653EF80B2A69DAFD763BB
+:10634000E98E457AEB69CF97D16E51E75B89EB1601
+:1063500086D0F510DEDC84A72A4F8B19E709E28F7F
+:10636000D7BBF2B81D7ED2F3EE5D68A7F464475B3D
+:10637000112F5D7A46FE6D2DE015F5414F675A0BE2
+:10638000DE83BA9E4BE0A33F5B43780DF874A2DF37
+:10639000A25616D64FC7F1B52B7C3F16CFB97F5BFF
+:1063A000847AE959B0ABA1BA4ED7908CE7FF787BDD
+:1063B000F8FEAAC43DD7E9FCC9C921F45AD731C4B3
+:1063C0002F66A2EF0E953F14C2A78AC79E6C6EB7C8
+:1063D000F5A41A3CE82FD6ED6F25BABE3EBED39D7C
+:1063E00081767EDAAF8D1437BC913FABDA01217E26
+:1063F0000F433F4E5736B1503321A8EFAFD9EC2FA2
+:10640000E615A23F544EFE5E0F1B5886CADF897602
+:10641000701CCADDBF3D85EB0EB683BD07EB3A8D20
+:10642000BEB91F829D35680546817D0F6ED7798480
+:106430007F6246FB7499B04F3F561C4532E857E7E0
+:106440001A0D9DAF2E278ADBB5424E7EB23FE3A7E1
+:1064500048AF7527648B11ED50F05B086EE3764111
+:10646000BD37E3DF67A0BDDDA6233B40B53B9CC243
+:10647000EE382FECD9F36B06F464AF1E96D813B048
+:106480008F2ADFE6AE346877E6CC257BD529B75175
+:10649000FC71F9D670BBA0DA130ED7EE0D879D11F3
+:1064A0007683EAB7F5E40DD90F93D1FF289167A45D
+:1064B000201F7C2CF0A9FA232BA75A5390DF3768B2
+:1064C00095B96A3C00EFC975F8D56ADCAFA72ECA4A
+:1064D0004A7EC1AA43749FFD9F71BFA33F9571FB84
+:1064E00088F17BEDF771FA76E924EE6700B9D27C8A
+:1064F00046C9B3069AFADD83B12497182B437E6808
+:106500005CC8FD483BC65CA1DC9727E24511FAF266
+:10651000566D9F1C1F221F3ECB9B40FB2FD633077F
+:10652000EAA9953156D25BE38DDCDE2E59EDB5211B
+:106530001D8C07FFD81012CF1E6F1E90B0DFAE87E4
+:1065400078FC5CF5EFE76B2DBAF810BD0792276C6D
+:106550007E90247CFC8DE6B7C0FCE6E0FC70DF7129
+:1065600078DF9F1658491FA7CF67AC9BF8B181F819
+:10657000513DCF15A0B362A0338C9920DEEAB61F3F
+:10658000A138B09375933F521ACBF7518AFB41382B
+:106590008A97967C2E37CAF3F9BD350B58955B6FF9
+:1065A000E5DBE3F3A1DC9BEF48CAA77A0BD1E54A10
+:1065B000412B60A7A4F40D23771BFFC2FDAA4F81D6
+:1065C0000F90CFEF699094CC303B88D3B78B57B105
+:1065D000CBCCDB3B03EFC16DEFCE4E463F8AF3D50C
+:1065E0009255262533844E5D48E7702F5596EA1F55
+:1065F000A3DDED5895AC60BCDF85743F01AF91D34E
+:106600007522FC43FFE23A3AF786C3F0B71DE9ABC7
+:106610009E19ACA8475CBEC876AB16E33AF9F9C040
+:10662000073707F9205DD0658B43F2A0DC6FF94A8C
+:10663000CBE3588B258A5BDD09954897F487FDAA43
+:10664000667A70FE3B01447F886D4924BEA1469066
+:10665000233F17E7BD53EB3F827C7C5CE7CDC078DE
+:10666000CA7127CFEB2C646070807C59CCBAA9EC3E
+:106670008DAE3FE0A7C9DDE3D06F7ECF61A0384E7D
+:10668000CBDA1D31284F73D95ACBF96C54EE6CEF2D
+:10669000B5FC91ED0A2024765EC50BC5853611FE4A
+:1066A00055BCEECDB7CF47FC8F34BEF6AF076E4773
+:1066B00097A2F681567D0A279BEEECA220FE5CCCC9
+:1066C0009B8DFB55F135843FD8F358B887056CA0F6
+:1066D00008FD1A156F46F8371CDED4FB4CD70DFCAD
+:1066E0000CAF0CF412C997487CAAF75BCF1A743C24
+:1066F000CED5F0CE42E87FF75A8D82F6E175F8BD2F
+:10670000011EFC26DEE48F91C8DF1C092F2A3E54AF
+:10671000FC9C8EE7E34EDF23539CEEFF355EDECA22
+:10672000773CFA6DFC18C97F23F1DB9255117C1977
+:10673000C17F2ABE1CAB6289CF543CD6298CFCD6C3
+:10674000BACE18AB8705F167867F883FCC53503CA3
+:10675000A65D62CF48DF850FFB28AF11891FA00D12
+:106760003BCAF59D11FCA7E26D24F9A3CAAF33CC57
+:106770007FDC22517E80F3E7AF0C1ECC2FAAF901FB
+:10678000350F704CC8BFC8F20CD81D9877D998DD6A
+:106790009384F65AAF5E9D87E71FCFACE91EB70220
+:1067A000C69F99C9CB5EB4D342607B148FC39D1939
+:1067B0006D70E3BD9D9126CF423D7E46FAF5ED1CFE
+:1067C0004ED12B082F4C996501B857A7C6ED1E1660
+:1067D00072D843E59985D38AA99FC4DEC4FB5024AF
+:1067E000564EEB48524219ECE7CC0393F29A59F01B
+:1067F000FCAFE4737BD62BE4F9501CFB3712C5B118
+:1068000097800AB060BC7DD6D36513A0FEEC8313DD
+:106810006D94FF6B0C5F1FF56806C50737D37CB717
+:106820007E31A05B9A13DCD790FE2BBECAEB2B27E0
+:10683000913F512570684F98CCFD58CFC438D4474C
+:10684000AA7E1A3CF1AA39347E7911F417D387C095
+:10685000931F4F0FD56F4776FF3E0BE7A9D2BB734F
+:10686000AD507FA1E50FE9680754ED7E348BECD283
+:10687000DD1BB2D0BFA8DAF1FB2C3BC1D10EF26F09
+:10688000B4FCDC97F7DDB27363881DFC6021F70B65
+:10689000161B8F94A07D3AF7E64F1EC178F8A40727
+:1068A000258A8BDDC3BA1F41BD5991CDF9886D3161
+:1068B000925C87F928EFD83AF927BB509E9FCCFE0F
+:1068C000405709FD4C055ABA8F0AE6792C05E36159
+:1068D000EB258A8705FB8FA33CE6D2B5923E3511A6
+:1068E000F561BC4D56705C3CEDE3DEF5B62EACAF09
+:1068F00058CDEBE71A3CED3D38CFD37A6BAB821322
+:10690000954F280FC90B9B0AB8DFB5E43189EC71AC
+:10691000759D494F25B7849ED35420F4F98C6EE2BF
+:10692000FF9F0ABCFC78F5BB6FA62A984F72C4156E
+:1069300040FB3B4F9ECF44F9559C703107E97C9258
+:10694000DEF14C359E7B8781E28705B969720AF4D6
+:10695000CFFBE5CC27B05CB27AE933D51807DD6A06
+:10696000243F4ADD5FA3A468D0DF3CD6F28B7BF1E5
+:10697000DE2E3C69243BBAB1E5A614360C9FAAE58D
+:106980001EC0BF92C5D8F34D462A5F6CB230058E4B
+:10699000B8AF2995E0979B142AD9024E5F8DC25F4C
+:1069A0001D69BE7CF0F715905705EB613EB0376D61
+:1069B00026FB143CE7A429CE1D1BC4B926C1789B35
+:1069C0003B6336DE43C186155D688A2617F0FCE21C
+:1069D000DB3DEBD3C98E5E7DEEB96A685F5A509E8F
+:1069E0005F00F76DDC7E95FCFC631D8F56505C7F6D
+:1069F00087819F4F9CFBC2935929CF60DCF52D1DE9
+:106A0000F9DFAEEDE79EDB00E57D8FADD087D2FBF1
+:106A1000773DAF4DECE7467C35D23D7C7FBEFA7DBD
+:106A20003AF1CF0EE0AB9C7F9CAF5CABD7D0FD3D85
+:106A30005A507E37DEFB059D3B1DF9E9C2E41F116C
+:106A40009DBB0F4B74FFAA1C57C72F10E7ADD5781D
+:106A50001F237B50C8F1CFC1F3C3FB3DD2F17116A8
+:106A6000DAC39FFB167EEBB90F3661061DE35A466B
+:106A70002A23DB8BF48E8956385F9186DBC191ED3A
+:106A80000F17A871719E6FC73F8C0BD709FDE98462
+:106A90008DC525A0FE93FC51B998E7B8EDA216FD6F
+:106AA0002FF0EBDE0FB72FD9FB217A7CA4FDDEA8F7
+:106AB000ACC779B441B93BEDB486F943F4F62D7D0A
+:106AC00051CC1FB2EE90DF01757ACCB3748C26B92D
+:106AD0008078C3BC4CA063F20E842FEA391E0307F2
+:106AE000C1BFE27115261705CF79B1E3722ECAD95D
+:106AF000C8F3D61FBA4CF451E77BF4AA44E79F735E
+:106B0000519B7BE3F31FD97D3917F17751D7578418
+:106B10007E5440DF978B78A87F9DCBF3EF7B0F6A85
+:106B20007DF57A3D8FEF4916F2074BE42BE4C7075A
+:106B30004E703FBEBE6327C9D3C14E1E4F7169BAA6
+:106B40004B5330FED070AE0BE5D9602AF7AF607EB4
+:106B50003BDEDB8C89420F6A07D2E7835C3B2AF27B
+:106B6000B5AA5F7701F9578FF378EBE83D526E34A1
+:106B700043BBE212F233D457ACCA5887747EC19338
+:106B8000849120F676EEFFD453FCED8D688B4C7625
+:106B90002BD486E06FE81C1E993F9C61AA9F1ECDF6
+:106BA000EC21FD5C7AE5A7E41F9FE47932D714CE8F
+:106BB0004FEC10E727E7DA23FAD490F95E52E58725
+:106BC000B01FE7BEF13FC497A76CF65328CFA25180
+:106BD00016E27CA9711E4912FD8A82794073A7F0E2
+:106BE000C7CB646A77F964361AC7A4C650BEBE8C98
+:106BF0006DD2A2BD3B977967F077327DFFF643688F
+:106C00009FF7869C8FEFB1C07EA6FC71699423B379
+:106C100011ED238D24EED55B303F549F15727B6BB5
+:106C2000862C911E1B181D4D76CA9C05CEC5B85FDB
+:106C3000B55F9996EB339887EC2CE619C8C57C268E
+:106C4000F30FE4629E53ED77D71BD10DA41799B7CC
+:106C5000E0AE9075C61472BDF929E69F419EB84416
+:106C6000FEB344FEEA29F4A31A0FF33C61AF26E316
+:106C70003D7CAFE5867B46BC5E06BCDA51FF3898AA
+:106C8000DD8EFC3335C983FCE3DA27317CB756DF70
+:106C900061D881719D7A5D5F32D2F306DF5FF5487E
+:106CA000CFAE03EFEA95A9389EC781C05ED7E0FD5D
+:106CB000BA84FE72FA6E7A0FE36ECE135C8B3AB52D
+:106CC000EF925F5FDBBE9FFCF73AE627FFBDAE2D7C
+:106CD0009C5E0653799C3D923FC6142A617C3167C5
+:106CE0002BE78BBB64D680728E89B8E99CD414B232
+:106CF0004782E3849D285F7E04ED97FE09925582CA
+:106D0000A9FAA3DC6BD12E7267717BA6FF4F2F16F9
+:106D10002C23B9E229F819BE8B11F6EE9CF59BB530
+:106D200072C87EE674F238617F14AB3A48F8768C0C
+:106D3000453CA4E7958F2DE4EF6472E99D8F86C7EB
+:106D40003523CFF1AC88E39CC4384F4E70DFF3D2CB
+:106D5000D2B81C631EA29F2E0D5F5F7DF7A28E5FCF
+:106D600021E869C81F92787C6A24B98279944A9193
+:106D700047A91479944A9147A91479944A9147A94B
+:106D80001479944A9147A91479944A9147A914799E
+:106D900014AC3F895BA5F7703B9F417AE8421E1B0C
+:106DA00013847B1322E031E1FD7B13A470788C44C3
+:106DB000FD8B0B773EE3CEC138A645C8252506EDF1
+:106DC000AF0B261E5FEA8871CC2D84FACA39CDBB81
+:106DD000F97B443BBD67294E58B818F96B30D1C0D8
+:106DE000500EB90B1DF3111F274ECCCEDC4CF2D147
+:106DF00064C53C77EFDD37C7515CEE2D99C9B0E42F
+:106E0000CCECFCB50500CF344B44B720277E50AE08
+:106E1000FA9330CFEC4E9ECF2891EB2A71FEC6D16B
+:106E2000A67C8A6BE53B161586C40F4AC72CCF4457
+:106E30003BA84BA7BC87F154F75F740CFD2835FEC7
+:106E4000A6F6EBCD9B598DFB9A933D716D1ECA1B27
+:106E5000602E946F763D6BC37DD935D15233C92BEB
+:106E6000458BFC5F2DF03D4BE1F6B05FAF6813D072
+:106E70006F8F9A99E85678BEAA52E4AB2A45BE0AAB
+:106E8000F1730AE36650BE03F55876433D9691EFE1
+:106E9000B9761794AF24BA6503E9A1EFC1E6225F82
+:106EA0007139938EF4FC8288C367178A7769F9E594
+:106EB0000FF2715E9AA756C4DF2EEBC2F378EAB8E0
+:106EC000E07846E51D3FE0F299C5E9F97BD7B1CC02
+:106ED0008DEF69EF786D34C593021E8D5B17073017
+:106EE000F038CA2FF61AF76F592AE7973B5E4DA183
+:106EF0007ECD220EEA4CE8CE4A40BD2BF84A850FE3
+:106F00007EC3DFF938F30086F275899FCF79477722
+:106F1000563CC001C9A4C1F8B873076FEF117CE7F4
+:106F20009C20E613E761466F3AE2A3FFF06BE9F7B6
+:106F300002BCD1EC5FC6E5BD3F8BE434F367E17B77
+:106F4000A1CB92F72CBEB7FDF5C17F5984EF6B2F13
+:106F5000EBBCCF21FCDB8333382CED3F6B096D4F4D
+:106F6000F2A6E37BDC5F1FFCE1227C9F7B3969FF9B
+:106F700073F1D61058F7CA596CD73F3C635131F4BE
+:106F80009F67F09C6842BA7999D39769DF81F3785B
+:106F90003FB51DDC5E9FB5EFC09557501F1F88A100
+:106FA0007CBDAF3083EEBBB963CF63486F81FD3AE0
+:106FB000E2838D6D7F7DEEB7D4CF40619479066F0B
+:106FC00001865CDC457FBB1BF7352FDAFB19C29BC2
+:106FD0008B6EA37DCE1BC5F9F9A9A2B98B903F0397
+:106FE00007F6FD0AF96F5E1C18B2B89F174D849F13
+:106FF0009A572717631C2010D35D81F3D7BF60B069
+:10700000229DD6BC9A320BE302C70B797CBA7ACAAE
+:10701000A674D4AF9A43CFEFFE2DC6295F30517EC0
+:10702000C695C0EDBB1AB9A56805E16FE76E7C3760
+:107030001278DE4479D26A9803D7ABDE3D89E2EA62
+:10704000AF7FFD4105E2A144DEBE1BEB3FDB65D215
+:10705000E03DF4E8ED713F423EECD1919F592DE0C7
+:10706000EADE517C3FD17DA584BFC44DE9A85F6BAA
+:1070700046FDE676DCF73C79D373E8E7B03D06CA17
+:10708000155C7C1EEE0DC65D6CD5D12BD5C0F331E1
+:107090005AA497CBD2A68A6770FE56DEEFB2691368
+:1070A000DDA7BBF52686EB413F86F2EAB2B439ACE8
+:1070B000FE62EB9E5CF4432FBD308FFC5195CE55A4
+:1070C0007EA9D96508D387240992C57B0952B36E7E
+:1070D00066063D5B2DC04B07B7059E61C1F197DA8F
+:1070E000747E3DDC51B581ADC5F7C12A3FD4A4DD26
+:1070F0005686E7ABD1B464A1BD529DDF57817C7148
+:10710000D1C48CA9F88E4EE8AB9AF635F3D1EE1DBA
+:10711000693FB1E25DDFE7820F3FF7993CA1F9C11A
+:10712000C8F26F4D4C3915F26EF89E0603D9EEEA9F
+:107130007C6FEBBD75E89FD52770F97116FAB781A2
+:107140001C331771B9B76455787FA988BF4BACD78A
+:10715000F765A1DE53E7FFA650956B7D5928AF2256
+:10716000C7CD9385BC7951227953D32E9D93E19E4F
+:107170006A8C6E0FBEDFA94167929F537B4DE2E39D
+:10718000528BC4BDC3D8A78B3268DD9A3693DD0419
+:10719000E36AA3FA62D11EAA8BE98B453B277048AC
+:1071A000663B04BA1293057E26089485C41DABBDC8
+:1071B0003ABB2977183CA3DD84EF73F0BF61FDB6BD
+:1071C00022CE2755BE685A8F59FA8A904EABB687A1
+:1071D0008FC3735942F82FE0DB991CEA8FDBC4BEE2
+:1071E000FBA573C427FD5FBF9F8E78AFD1B0B59864
+:1071F00047BC24F1EF1E00A6EF1E2E897C64CDDF74
+:10720000CD51482F973EAF23BE0D487D24D7CE1CCD
+:107210005C407229A0EB23B9D6535441F22110DF10
+:10722000578172EACCC17ADE3EBAAF4281F64E8413
+:10723000B17D1C237D7FB9E801921FF364FEBE81FE
+:10724000EDD459781C687D6F13F9153A25D4EFBE3B
+:1072500052A4E66DF4C173CB41BE0930655F3BF2C9
+:10726000619599E239603FB5BD8276DEC2642BC676
+:10727000C5AB701CA7037D68FE2F31E1CB65889FED
+:1072800045718E3B8B308F9DD347FE035035D9E936
+:10729000F57F32901FD9AF1BD88D722A37CEB1B08F
+:1072A00008F651A7EF5E87A1A72BBABE2ECCFBCD67
+:1072B00095B93C627B385D057276F2EF2444FEB0EE
+:1072C000BA88CB5FD05BAC05E942E2F83DE67BF5DE
+:1072D00014CA9540F74492C7917C73D1F7442CCAE5
+:1072E00087D3A0C7DD217EFEE9A57B284FBF00DF45
+:1072F000654079EFDA707A18FCEA67E4EFB1C742CB
+:10730000EA910EB784C3917484F4E80F933B6EA2A4
+:107310009B3D82AF6A6775D7E33D0CC177002C8730
+:10732000C04723E088FEAC9CDB097BF0BF61DEBA7E
+:1073300071FE5EF2CFF7F177B1CDA0BF083E104DE0
+:107340007963CD3ED04F895C3FA15EA88DEDA6B894
+:1073500054E08081F2230F777C4CEF19810E29FED7
+:1073600052DBF15A32FAED3EF41392480F26D33B2A
+:1073700095031DC9E86FA8F5751A6F96788F4F763B
+:10738000BA5AEF94FD59B8FF5AA93B17DB7D851611
+:10739000D11F60196146E7A89338BFB30E99E4790D
+:1073A00024DEF60A7A05B9904BEF2C0EF1B8802A4C
+:1073B00007AA853C398AF5399CEF2D6A5E49C2F7E8
+:1073C00072D1C3CA879B8A547BB881E236BB8A14C8
+:1073D0007EAF623CCDCBE34AD45EFFFAE5DC0939EF
+:1073E000384E11E342E4D0C4A05C41FE4F25FE7F3D
+:1073F00058970CE7AA794EB236A39C5ABCA614BA89
+:10740000B3E5DA15A5142F13EF3F23F7154947F617
+:10741000228EDF1A4D7C4962C87C97C05D4FCD2318
+:107420003943EFE8EF4F7CBC14E313BF58BC99E835
+:107430007948DF84F2399E673B97E3C836D734D763
+:10744000D3F1F286967529C3EC23729FD58E96D21E
+:1074500064E5FA7A75BF974CEAFE66E99242EF61FD
+:10746000C19AD22428971BFFD17BE0E7BDD461F0FD
+:10747000A35EAD5EBC625DDC3074739D3ED81EA21F
+:10748000BF26207E3D94D71869FF91659DE4EFC526
+:10749000381103BE6A25FE027E09D10B6542BF0E7C
+:1074A000C51BAA968E47BF9339968E473D037C55E0
+:1074B000611DC6AFC42F4B34F476C34D65E47E3EE8
+:1074C0002BE271D2B222CE2FA76CF66F50BE8EF493
+:1074D000BD85619AF4ADDF5BA46906DF417E4B4B4D
+:1074E0008E51300F54323B9AF73B6CB260DCA6FFF2
+:1074F000F09714D7ED7FC4BC80E70BCC6C34B47725
+:10750000A54EDD11AA473CD3385F461770BBC59521
+:10751000ADFBF6B8504ECC505C88EC869C68CA93A4
+:10752000047C9F92DEEAEF2CB4603E23D00DDE2176
+:10753000F093EBEBFF4A46FD1AE8FC88DE8305BEBC
+:10754000FA98DE896D10EFF48EFAC43BAB6E258697
+:10755000BE8B2BFBA014FB6D1465303EC0E35A6A52
+:10756000A9FAFF21FEEF946985C3FABF090E73687B
+:107570005C4049192E8E121A17C8D4F2B80096181A
+:1075800017C8CCE4710184312E8025C605B01EE3F6
+:107590000208635C00618C0B208C71012C312E8001
+:1075A000F59F89EF1FFA4130F178A599E4FA4A7CFA
+:1075B000DF0EF7B7F230CF3BAD6C95297F8BDF3F05
+:1075C000A07EBBEEDD4CBB7837E3DD4C793CD701C8
+:1075D000D98A2872E9068E631CC7B55FB2AE41B97D
+:1075E000D2B480D6DFD059F8DE62AC6FD559350AF7
+:1075F000D111C7638B44EFF46B3A5B29EE549C7254
+:10760000584FF56D12C338E95D06EEE73A65A8CD2F
+:10761000A33C28D9C14E4337F91FB57B25A532F4C9
+:107620009DC6F4AB2407D47CF232DEC49C5E935238
+:1076300039CC3B90A177E7E2DDF432CC33E37B71C8
+:10764000F92B7AD7EF04877414D2E156FEFED902E3
+:10765000FF88DF23DE35D574EE5F87EFA122F3CDFF
+:1076600043DFD345E49DEBA789BCB28D7F5F51F624
+:1076700064E5BE03B0DEE02603D91BEE42C703D3A8
+:107680009230EF6FA7F8C8F1C326F28B3EDC7C5333
+:10769000587C84E53B1E9C46F9F9B114AF68D44987
+:1076A000A48F67974D4CC17B9C7D42477AA737AF2B
+:1076B0007C35F66B9CAA503CAAC4C01EA079C47B42
+:1076C00029151F25CD924703F05266A577F64BE0AA
+:1076D0009A305ED9AF33AFC7774D4B187FE7A0D252
+:1076E0004DE36689E8060304789F15E23E9774FE31
+:1076F000F94B7CC7709F81DBAD691A9EBF4EDBC81A
+:10770000DF33DCCF1C7AD4B3CB91BA64D28F7FEA5B
+:10771000837A47F4D8746E972B2938FFD2933A7A3C
+:107720006F5B92F2932C07E9E9627AC720F917C9D7
+:10773000D76E1E997F22DF311CD771B902F748FE40
+:107740005017D225C5651C549E6CAAA2F277E27B25
+:1077500088EBDFFF0F9C453F312D25C68A726EC432
+:10776000EFDDA2BEFD7BAF17C4FBB5344D4FBE822B
+:10777000F7F177B315EF437D2778CA56BE1FF16442
+:107780008F656E0B7D0F061210EEB5140F22615C33
+:10779000DB6BC7EF8E060E4B167A977C9D7CDCFC6C
+:1077A00008BE1371654A1649C1F8F7A69264D877E6
+:1077B000E9840CDAB7CBC7E3A37443C9183FE7F8F1
+:1077C0004ACF731C9B5618AC9F27F82600FD399DA5
+:1077D000FCD083F4F61DE2A6BBB0BF9B99E87B6AA0
+:1077E000FA83FDCCBB791CC54F55BA196C4BD981B6
+:1077F00074F39E90FB8B17BFAB43FDDF9BEFE8C19B
+:107800007D54545E7D2499CE377CFC4A7DA71E1999
+:10781000BF0A959FFF3FDEA79F6A6AA0F29DA6550B
+:10782000547637B9A93D44FE5F1A41FE47C63FAFC3
+:10783000227F47C63F99518923FD09FCCDE3CD1135
+:10784000F1CEB251F7AE87FB9BBD456FC52A35FE21
+:1078500089EF87579A491EFCF7B461E39EEABD9908
+:10786000294E3AC84C7978FFB3B2276A35D0AE9D1D
+:10787000CEF1A7C61D913FF07CC81F58227F68B586
+:1078800041FE78560F2C5CC0F5BC9BF4BC89F0BA65
+:107890006E0DC80F80EF639630F97125427E80C36C
+:1078A00071377D57D56960182754DF51CE82E28B3E
+:1078B000BC61E48997CB937151DEE7E97BFFFA283D
+:1078C0007A9F7B5CBC873BBE81BF87AB64E5B4EE2F
+:1078D00030722516F171DFA881B37F80FEF7FDDEDF
+:1078E0004CF6CABAD1CB8AFE19B9724D7CD7F234A4
+:1078F000FEAE80F6DB7E57E03109F3A18DF7301B39
+:10790000E259FD5D811491CFFE1EBF2B306D7AE1EF
+:1079100077FF5D815BA78F5F1CFABB02B7FA323835
+:10792000ACFEAE001BBF7884DF15983D3DE9FADF61
+:1079300015B86D3AF71747FA5D01B027CB705C9226
+:10794000CD3E07CB34B1CFC8EF694F8AFC5D97C6F7
+:10795000B118CBD258B796EA359E02FA0E5EE3FD17
+:1079600025F981F98E9FE3794B9FB04DC90638CD3B
+:10797000E02539D99B67BF13EBAFD9EC77E13A919A
+:107980007173C42DFAF7B09FBBB13DF2DD958ACF7C
+:1079900015D3B9DC6814E58CE6E1BF276F9CCEF304
+:1079A000F237DA37ECB706D71BDAFFA6A505B81F02
+:1079B000D86F2DD6C37EEBB064E684B0EF53AFA78B
+:1079C0003337D155E3744E5F20CFE67DC8ED412AB1
+:1079D000B3B49E78B41FC73CE489C7FD8E691930E3
+:1079E000E177107F740F9850BFFF71F58009EBFFAE
+:1079F00068E7EF9523E77F793AF703B2660CD0F892
+:107A0000F168E3937D3E108FF65356D587EB28DF60
+:107A1000B27732E997F142BF8C7F6882AF0FE86D91
+:107A2000FCB638CA67B3E2446AAF31723EAD79A89A
+:107A3000F2E00185BEDB9AF76188BD33D903FB0E06
+:107A4000B3BFB483FCDD25C0784F7B750423CDA282
+:107A50007DE564FCDDE5182137D04E5B0C72C15921
+:107A6000F5E69794F7C7F1381FE66891FE7CBA41B6
+:107A7000F17D9A05FDD0E50BD674915FB875A85ECF
+:107A8000F899FBD7A1DF0CF65B587D4DE5912ED41C
+:107A900037B57BC3EB9D0D57C97F05FB2DACFE9E13
+:107AA0005F9ED3F3DF2F08AF07FCEE45BA54F17B9E
+:107AB0005CE79D8C7EDE71679495BFDFF7D2EF9512
+:107AC000EC10DF3FEFFC8F599C6E04BE61BC377435
+:107AD000FCC8F4D14CFDDDB35836F2C38D4A552EA7
+:107AE0000DFDFE899EB929BE373786E48E4BF855C9
+:107AF000F59516D2F369F546925F25729415E1A1CA
+:107B0000DF3F2993859CF212FFF7DC1E4F713C3A50
+:107B100000C2095329EF93DCCCE1812403C9871209
+:107B20004D79DD1E28DFD4847FC7FE2CCA0719F9E2
+:107B3000977F87E9D27BF977E25AA510FDDC66C909
+:107B4000BE0DBF7B6C96441CB1DA4CF9827E8C2F43
+:107B5000C279B6C47BB62D8375B6DC9943F6713F06
+:107B6000E3F2D4BD80E7ADB6C4972F5E81ED0BA7DD
+:107B700050FBC16F263E5E80F653759415EDA72D20
+:107B8000366E5F6F999F4DEDAF4BCA1A3CB7FB2124
+:107B900046EB6C99CFCFBDE5F171E2FB0B8F09F994
+:107BA000794B8B7D34E6A366591C17105F63443E06
+:107BB0006E4B06D443F99454BEF07E9C672ADFEFE7
+:107BC000EF6C0AC98FE30BA73CBE5B2135E2C7BC53
+:107BD000906B6E0CF9C1FF0BB81F749470470000D6
+:107BE0000000000000000000050207000000000087
+:00000001FF
diff --git a/firmware/bnx2x-e1h-5.0.21.0.fw.ihex b/firmware/bnx2x-e1h-5.0.21.0.fw.ihex
deleted file mode 100644
index e78c86378f89..000000000000
--- a/firmware/bnx2x-e1h-5.0.21.0.fw.ihex
+++ /dev/null
@@ -1,12855 +0,0 @@
-:1000000000003BB8000000600000068800003C20B3
-:100010000000192C000042B0000000AC00005BE0C2
-:1000200000008DC400005C90000000E40000EA586D
-:100030000000E4140000EB40000000940001CF58E1
-:10004000000058E80001CFF0000000C4000228E0E2
-:100050000000F978000229A800000004000323280A
-: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
-:10061000081807C800070223071C00002C2D000043
-:10062000071C800038A20B0C071D000028EF1935AD
-:10063000081D681052FE022501180000000000008D
-: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
-:1013F000020E00540000000C020E0058000000070E
-: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
-:1015B0000730040000E10000083007D8000502BD34
-:1015C000073400002ECA000007348000311A0BB324
-:1015D00007350000368B17FA0735800039C6259D80
-:1015E0000736000013D5340F0836307039F202BFC9
-: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
-:1017D000063240000000000204324008000102C24C
-:1017E0000632400C00000003063240D80000000220
-:1017F00006326B680000000204326B70000202C304
-:1018000006326B1000000002043274C0000202C5F0
-:101810000632DA40000000020632E0000000080054
-:10182000023308000100000004330C00001002C75E
-:10183000023308000000000004330C40001002D7FF
-:1018400006322450000000B406322AD00000000204
-:1018500006321000000001A002323DB80000000076
-:101860000632500000000020063251000000002027
-:101870000632520000000020063253000000002013
-:1018800006325400000000200632550000000020FF
-:1018900006325600000000200632570000000020EB
-:1018A00006325800000000200632590000000020D7
-:1018B00006325A000000002006325B0000000020C3
-:1018C00006325C000000002006325D0000000020AF
-:1018D00006325E000000002006325F00000000209B
-:1018E00006326B780000005206326E080000000CD1
-:1018F0000632DA880000000206322720000000B419
-:1019000006322AD80000000206321680000001A02C
-:1019100002323DBC00000000063250800000002072
-:101920000632518000000020063252800000002064
-:101930000632538000000020063254800000002050
-:10194000063255800000002006325680000000203C
-:101950000632578000000020063258800000002028
-:10196000063259800000002006325A800000002014
-:1019700006325B800000002006325C800000002000
-:1019800006325D800000002006325E8000000020EC
-:1019900006325F800000002006326CC0000000525A
-:1019A00006326E380000000C0632DA9000000002A9
-:1019B00002322A3000000000063240180000000207
-:1019C0000632D0000000000602322A340000000077
-:1019D00006324028000000020632D018000000063F
-:1019E00002322A38000000000632403800000002AF
-:1019F0000632D0300000000602322A3C000000000F
-:101A000006324048000000020632D04800000006BE
-:101A100002322A4000000000063240580000000256
-:101A20000632D0600000000602322A4400000000A6
-:101A300006324068000000020632D078000000063E
-:101A400002322A48000000000632407800000002FE
-:101A50000632D0900000000602322A4C000000003E
-:101A600006324088000000020632D0A800000006BE
-:101A7000072004000093000008200780001002E700
-:101A8000072400002ADF0000072480002E050AB882
-:101A90000824E4A061D202E9012000000000000057
-:101AA00001200004000000000120000800000000E8
-:101AB0000120000C000000000120001000000000C8
-:101AC000012000140000000002200020000000019E
-:101AD0000220002400000002022000280000000371
-:101AE0000220002C00000000022000300000000452
-:101AF0000220003400000001022000380000000035
-:101B00000220003C00000001022000400000000410
-:101B100002200044000000000220004800000001F4
-:101B20000220004C000000030220005000000000D2
-:101B300002200054000000010220005800000004B0
-:101B40000220005C00000000022000600000000194
-:101B50000220006400000003022000680000000072
-:101B60000220006C00000001022000700000000450
-:101B70000220007400000000022000780000000431
-:101B80000220007C0000000306200080000000020C
-:101B9000022000A400003FFF022000A8000003FF75
-:101BA0000220022400000000022002340000000095
-:101BB0000220024C00000000022002E40000FFFFAF
-:101BC000062020000000080002238BC00000000156
-:101BD0000223800000000010022380400000001259
-:101BE0000223808000000030022380C00000000E2D
-:101BF000022383C0000001F40223148000000001CE
-:101C00000A23148000000000062210000000004299
-:101C100006227020000000C80622700000000002AA
-:101C2000022211E80000000006223000000000C07F
-:101C3000062240700000008006225280000000044E
-:101C40000622670000000100062290000000040048
-:101C500004226B08002002EB02230800013FFFFF73
-:101C600004230C000010030B0223080000000000F6
-:101C700004230C400010031B06228100000000A07A
-:101C8000062286000000004006228C000000003C76
-:101C90000622B0000000020006228800000000803A
-:101CA00006228DE00000003C0622404000000006B5
-:101CB00006228380000000A006228700000000406A
-:101CC00006228CF00000003C0622B8000000020052
-:101CD00006228A000000008006228ED00000003C10
-:101CE000062240580000000606228000000000087E
-:101CF000022211480000000006223300000000020A
-:101D0000062260400000003006228020000000080B
-:101D10000222114C000000000622330800000002DD
-:101D2000062261000000003006228040000000080A
-:101D300002221150000000000622331000000002B1
-:101D4000062261C00000003006228060000000080A
-:101D50000222115400000000062233180000000285
-:101D60000622628000000030062280800000000809
-:101D70000222115800000000062233200000000259
-:101D80000622634000000030062280A00000000808
-:101D90000222115C0000000006223328000000022D
-:101DA0000622640000000030062280C00000000807
-:101DB0000222116000000000062233300000000201
-:101DC000062264C000000030062280E00000000807
-:101DD00002221164000000000622333800000002D5
-:101DE0000622658000000030021610000000002866
-:101DF00002170008000000020217002C0000000378
-:101E00000217003C00000004021700440000000814
-:101E100002170048000000020217004C000000906A
-:101E2000021700500000009002170054008000903C
-:101E30000217005808140000021700600000008A12
-:101E40000217006400000080021700680000008193
-:101E50000217006C000000800217007000000006EE
-:101E600002170078000007D00217007C0000076C02
-:101E700002170038007C1004021700040000000F55
-:101E80000616402400000002021640700000001CEC
-:101E90000216420800000001021642100000000174
-:101EA0000216422000000001021642280000000134
-:101EB0000216423000000001021642380000000104
-:101EC00002164260000000020C16401C0003D09075
-:101ED0000A16401C0000009C0B16401C000009C4A0
-:101EE0000216403000000008021640340000000CCA
-:101EF0000216403800000010021640440000002086
-:101F00000216400000000001021640D80000000147
-:101F100002164008000000010216400C00000001FB
-:101F200002164010000000010216424000000000AE
-:101F3000021642480000000006164270000000022F
-:101F40000216425000000000021642580000000035
-:101F500006164280000000020216600800000424F9
-:101F60000216600C00000410021660100000041439
-:101F70000216601C0000FFFF021660200000FFFF39
-:101F8000021660240000FFFF021660280000FFFF19
-:101F900002166038000000200216603C000000209D
-:101FA0000216604000000034021660440000003554
-:101FB00002166048000000230216604C0000002456
-:101FC0000216605000000025021660540000002632
-:101FD00002166058000000270216605C000000290D
-:101FE000021660600000002A021660640000002BE8
-:101FF000021660680000002C0216606C0000002DC4
-:102000000616607000000052021661B80000000160
-:10201000061661BC0000001F0216623807FFFFFFB2
-:102020000216623C0000003F0216624007FFFFFFFD
-:10203000021662440000000F011662480000000012
-:102040000116624C00000000011662500000000002
-:1020500001166254000000000116625800000000E2
-:102060000116625C000000000116626000000000C2
-:1020700001166264000000000116626800000000A2
-:102080000116626C00000000011662700000000082
-:102090000116627400000000011662780000000062
-:1020A0000116627C000000000C166000000003E8CE
-:1020B0000A166000000000010B1660000000000A14
-:1020C0000216804000000006021680440000000551
-:1020D000021680480000000A0216804C000000052D
-:1020E0000216805400000002021680CC000000049A
-:1020F000021680D000000004021680D40000000404
-:10210000021680D800000004021680DC00000004E3
-:10211000021680E000000004021680E400000004C3
-:10212000021680E800000004021688040000000483
-:10213000021680300000007C021680340000003D52
-:10214000021680380000003F0216803C0000009C10
-:10215000021680F000000007061680F4000000055B
-:102160000216880C0101010102168108000000001E
-:102170000216810C00000004021681100000000409
-:1021800002168114000000020216881008012004C3
-:1021900002168118000000050216811C00000005CF
-:1021A00002168120000000050216812400000005AF
-:1021B0000216882C20081001021681280000000851
-:1021C0000216812C00000006021681300000000774
-:1021D000021681340000000002168830010101203F
-:1021E000061681380000000402168834010101013E
-:1021F00002168148000000000216814C0000000415
-:1022000002168150000000040216815400000002F2
-:1022100002168838080120040216815800000005C3
-:102220000216815C000000050216816000000005B6
-:1022300002168164000000050216883C2008100187
-:1022400002168168000000080216816C000000067A
-:102250000216817000000007021681740000000160
-:102260000216884001010120021681780000000159
-:102270000216817C0000000102168180000000012E
-:102280000216818400000001021688440101010148
-:1022900002168188000000010216818C00000004F3
-:1022A00002168190000000040216819400000002D2
-:1022B00002168848080120040216819800000005D3
-:1022C0000216819C00000005021681A00000000596
-:1022D000021681A4000000050216881420081001CF
-:1022E000021681A800000008021681AC000000065A
-:1022F000021681B000000007021681B40000000140
-:102300000216881801010120021681B800000001A0
-:10231000021681BC00000001021681C0000000010D
-:10232000021681C4000000010216881C010101018F
-:10233000021681C800000001021681CC00000004D2
-:10234000021681D000000004021681D400000002B1
-:102350000216882008012004021681D8000000051A
-:10236000021681DC00000005021681E00000000575
-:10237000021681E4000000050216882420081001DE
-:10238000021681E800000008021681EC0000000639
-:10239000021681F0000000070216E40C00000000A5
-:1023A00002168828010101200616E410000000042E
-:1023B0000216E000010101010216E4200000000005
-:1023C0000216E424000000040216E42800000004C1
-:1023D0000216E42C000000020216E00408012004AA
-:1023E0000216E430000000050216E4340000000587
-:1023F0000216E438000000050216E43C0000000567
-:102400000216E008200810010216E440000000084F
-:102410000216E444000000060216E448000000072B
-:102420000216E44C000000000216E00C010101203D
-:102430000616E450000000040216E010010101013C
-:102440000216E460000000000216E46400000004CC
-:102450000216E468000000040216E46C00000002AA
-:102460000216E014080120040216E47000000005C2
-:102470000216E474000000050216E478000000056E
-:102480000216E47C000000050216E0182008100186
-:102490000216E480000000080216E4840000000632
-:1024A0000216E488000000070216E48C0000000118
-:1024B0000216E01C010101200216E4900000000158
-:1024C0000216E494000000010216E49800000001E6
-:1024D0000216E49C000000010216E0200101010147
-:1024E0000216E4A0000000010216E4A400000004AB
-:1024F0000216E4A8000000040216E4AC000000028A
-:102500000216E024080120040216E4B000000005D1
-:102510000216E4B4000000050216E4B8000000054D
-:102520000216E4BC000000050216E0282008100195
-:102530000216E4C0000000080216E4C40000000611
-:102540000216E4C8000000070216E4CC00000001F7
-:102550000216E02C010101200216E4D00000000167
-:102560000216E4D4000000010216E4D800000001C5
-:102570000216E4DC000000010216E0300101010156
-:102580000216E4E0000000010216E4E4000000048A
-:102590000216E4E8000000040216E4EC0000000269
-:1025A0000216E034080120040216E4F000000005E1
-:1025B0000216E4F4000000050216E4F8000000052D
-:1025C0000216E4FC000000050216E03820081001A5
-:1025D0000216E500000000080216E50400000006EF
-:1025E0000216E508000000070216E03C0101012088
-:1025F00002168240003F003F0216824400000000A5
-:102600000216E524003F003F0216E5280000000006
-:1026100002168248000000000216824C003F003F74
-:102620000216E52C000000000216E530003F003FD6
-:1026300002168250010001000216825401000100BE
-:102640000216E534010001000216E5380100010020
-:1026500006168258000000020216E53C0000000049
-:102660000216E540000000000216826000C000C0B3
-:102670000216826400C000C00216E54400C000C01B
-:102680000216E54800C000C0021682681E001E0047
-:102690000216826C1E001E000216E54C1E001E0073
-:1026A0000216E5501E001E00021682704000400017
-:1026B00002168274400040000216E55440004000BB
-:1026C0000216E55840004000021682788000800023
-:1026D0000216827C800080000216E55C800080008B
-:1026E0000216E56080008000021682802000200033
-:1026F00002168284200020000216E56420002000DB
-:102700000216E568200020000616828800000002FC
-:102710000216E56C000000000216E57000000000E3
-:102720000216829000000000021682940000000051
-:102730000216E574000000000216E57800000000B3
-:1027400002168298000000000216829C0000000021
-:102750000216E57C000000000216E5800000000083
-:10276000021682A000000000021682A400000001F0
-:10277000061682A80000000A021681F400000C0868
-:10278000021681F800000040021681FC00000100E2
-:1027900002168200000000200216820400000017CA
-:1027A00002168208000000800216820C000002005F
-:1027B00002168210000000000216821801FF01FFBD
-:1027C0000216821401FF01FF0216E51001FF01FF4E
-:1027D0000216E50C01FF01FF0216823C0000001307
-:1027E000021680900000013F021680600000014048
-:1027F0000216806400000140061680680000000296
-:1028000002168070000000C00616807400000007E9
-:102810000216809C00000048021680A000000048BC
-:10282000061680A400000002021680AC00000048DA
-:10283000061680B0000000070216823800008000F3
-:1028400002168234000025E40216809400007FFF07
-:1028500002168220000F000F0216821C000F000FCC
-:102860000216E518000F000F0216E514000F000F06
-:10287000021682280000000002168224FFFFFFFFDC
-:102880000216E520000000000216E51CFFFFFFFF16
-:102890000216E6BC000000000216E6C000000002BE
-:1028A0000216E6C4000000010216E6C8000000039C
-:1028B0000216E6CC000000040216E6D00000000676
-:1028C0000216E6D4000000050216E6D80000000754
-:1028D000021680EC000000FF02140000000000015E
-:1028E0000214000C0000000102140040000000016E
-:1028F0000214004400007FFF0214000C00000000DE
-:1029000002140000000000000214006C000000002F
-:102910000214000400000001021400300000000155
-:1029200002140004000000000214005C000000001B
-:10293000021400080000000102140034000000012D
-:1029400002140008000000000214006000000000F3
-:102950000202005800000032020200A0031500200D
-:10296000020200A403150020020200A801000030AA
-:10297000020200AC08100000020200B000000033A8
-:10298000020200B400000030020200B80000003172
-:10299000020200BC00000003020200C000000006AA
-:1029A000020200C400000003020200C8000000038D
-:1029B000020200CC00000002020200D00000000071
-:1029C000020200D400000002020200DC000000004D
-:1029D000020200E000000006020200E40000000421
-:1029E000020200E800000002020200EC0000000207
-:1029F000020200F000000001020200FC00000006DC
-:102A00000202012000000000020201340000000266
-:102A1000020201B0000000010202020C00000001ED
-:102A2000020202140000000102020218000000026B
-:102A300002020404000000010202040C0000004035
-:102A400002020410000000400202041C0000000406
-:102A50000202042000000020020204240000000200
-:102A600002020428000000200602050000000012F7
-:102A700004020480001F032B020200600000000F0C
-:102A80000202006400000007020200680000000B60
-:102A90000202006C0000000E020200700000000E36
-:102AA0000602007400000003020200F400000004AB
-:102AB0000202000400000001020200080000000100
-:102AC0000202000C000000010202001000000001E0
-:102AD00002020014000000010202001800000001C0
-:102AE0000202001C000000010202002000000001A0
-:102AF0000202002400000001020200280000000180
-:102B00000202002C0000000102020030000000015F
-:102B1000020200340000000102020038000000013F
-:102B20000202003C0000000102020040000000011F
-:102B300002020044000000010202004800000001FF
-:102B40000202004C000000010202005000000001DF
-:102B500002020108000000C8020201180000000281
-:102B6000020201C400000000020201CC00000000CB
-:102B7000020201D400000002020201DC0000000297
-:102B8000020201E4000000FF020201EC000000FF6D
-:102B900002020100000000000202010C000000C857
-:102BA0000202011C00000002020201C80000000035
-:102BB000020201D000000000020201D80000000261
-:102BC000020201E000000002020201E8000000FF32
-:102BD000020201F0000000FF0202010400000000F8
-:102BE00002020108000000C80202011800000002F1
-:102BF000020201C400000000020201CC000000003B
-:102C0000020201D400000002020201DC0000000206
-:102C1000020201E4000000FF020201EC000000FFDC
-:102C200002020100000000000202010C000000C8C6
-:102C30000202011C00000002020201C800000000A4
-:102C4000020201D000000000020201D800000002D0
-:102C5000020201E000000002020201E8000000FFA1
-:102C6000020201F0000000FF020201040000000067
-:102C700002020108000000C8020201180000000260
-:102C8000020201C400000000020201CC00000000AA
-:102C9000020201D400000002020201DC0000000276
-:102CA000020201E4000000FF020201EC000000FF4C
-:102CB00002020100000000000202010C000000C836
-:102CC0000202011C00000002020201C80000000014
-:102CD000020201D000000000020201D80000000240
-:102CE000020201E000000002020201E8000000FF11
-:102CF000020201F0000000FF0202010400000000D7
-:102D000002020108000000C80202011800000002CF
-:102D1000020201C400000000020201CC0000000019
-:102D2000020201D400000002020201DC00000002E5
-:102D3000020201E4000000FF020201EC000000FFBB
-:102D400002020100000000000202010C000000C8A5
-:102D50000202011C00000002020201C80000000083
-:102D6000020201D000000000020201D800000002AF
-:102D7000020201E000000002020201E8000000FF80
-:102D8000020201F0000000FF020201040000000046
-:102D90000728040000C00000082807A8000B034A09
-:102DA000072C000032FD0000072C8000357E0CC08F
-:102DB000072D00003AE41A20072D800039CF28DAC9
-:102DC000072E00001C3C374E082E3710391E034CCE
-:102DD000012800000000000001280004000000009D
-:102DE00001280008000000000128000C000000007D
-:102DF000012800100000000001280014000000005D
-:102E00000228002000000001022800240000000227
-:102E100002280028000000030228002C0000000007
-:102E200002280030000000040228003400000001E5
-:102E300002280038000000000228003C00000001C9
-:102E400002280040000000040228004400000000A6
-:102E500002280048000000010228004C0000000386
-:102E60000228005000000000022800540000000169
-:102E700002280058000000040228005C0000000046
-:102E80000228006000000001022800640000000326
-:102E900002280068000000000228006C0000000109
-:102EA00002280070000000040228007400000000E6
-:102EB00002280078000000040228007C00000003C3
-:102EC0000628008000000002022800A400003FFF46
-:102ED000022800A8000003FF0228022400000000CE
-:102EE00002280234000000000228024C000000000A
-:102EF000022802E40000FFFF06282000000008006E
-:102F0000022B8BC000000001022B8000000000009B
-:102F1000022B804000000018022B80800000000C73
-:102F2000022B80C0000000660C2B83000007A1204C
-:102F30000A2B8300000001380B2B8300000013884C
-:102F4000022B83C0000001F40C2B8340000001F42D
-:102F50000A2B8340000000000B2B8340000000057B
-:102F60000A2B83800004C4B40C2B83801DCD650024
-:102F70000A2B1480000000000B2B8380004C4B4078
-:102F8000022B148000000001062A29C8000000045A
-:102F9000042A29D80002034E062A20800000004897
-:102FA000062A9020000000C8062A900000000002B7
-:102FB000062A21A800000086062A20000000002022
-:102FC000022A23C800000000042A23D00002035074
-:102FD000042A249800040352022A2C500000000006
-:102FE000022A2C1000000000042A2C0800020356BC
-:102FF000042A300000020358062A300800000100AD
-:10300000062A404000000010042A40000010035A25
-:10301000062A6AC000000002062A6B0000000004B5
-:10302000042A84080002036A022B08000000000042
-:10303000042B0C000010036C022B080001000000A0
-:10304000042B0C400008037C022B08000200000047
-:10305000042B0C6000080384062AC000000000D87E
-:10306000062A24A800000014062A2548000000248F
-:10307000062A266800000024062A2788000000246B
-:10308000062A28A800000024062AA0000000002824
-:10309000062AA1400000000C042A29E00002038C4B
-:1030A000062A502000000002062A503000000002CC
-:1030B000062A500000000002062A501000000002FC
-:1030C000022A520800000001042A6AC80002038E86
-:1030D000062A6B1000000042062A6D200000000442
-:1030E000062ABCD000000002062AC360000000D8F7
-:1030F000062A24F800000014062A25D8000000241F
-:10310000062A26F800000024062A281800000024B9
-:10311000062A293800000024062AA0A00000002862
-:10312000062AA1700000000C042A29E8000203907E
-:10313000062A502800000002062A5038000000022B
-:10314000062A500800000002062A5018000000025B
-:10315000022A520C00000001042A6AD000020392E5
-:10316000062A6C1800000042062A6D300000000498
-:10317000062ABCD800000002022AC6C000000000D7
-:10318000042A29F000100394062A50480000000E7B
-:10319000062AB00000000006022AC6C40000000093
-:1031A000042A2A30001003A4062A50800000000ED2
-:1031B000062AB01800000006022AC6C80000000057
-:1031C000042A2A70001003B4062A50B80000000E2A
-:1031D000062AB03000000006022AC6CC000000001B
-:1031E000042A2AB0001003C4062A50F00000000E82
-:1031F000062AB04800000006022AC6D000000000DF
-:10320000042A2AF0001003D4062A51280000000ED8
-:10321000062AB06000000006022AC6D400000000A2
-:10322000042A2B30001003E4062A51600000000E2F
-:10323000062AB07800000006022AC6D80000000066
-:10324000042A2B70001003F4062A51980000000E87
-:10325000062AB09000000006022AC6DC000000002A
-:10326000042A2BB000100404062A51D00000000EDE
-:10327000062AB0A800000006021010080000000195
-:103280000210105000000001021010000003D000D6
-:10329000021010040000003D091018000200041480
-:1032A0000910110000280614061011A000000018D3
-:1032B00006102400000000E00210201C00000000A6
-:1032C0000210202000000001021020C000000002B7
-:1032D000021020040000000102102008000000017C
-:1032E00009103C000005063C0910380000050641A5
-:1032F000091038200005064606104C0000000100A9
-:1033000002104028000000100210404400003FFF5F
-:103310000210405800280000021040840084924AA5
-:1033200002104058000000000210800000001080D1
-:10333000021080AC00000000021080380000001075
-:103340000210810000000000061081200000000231
-:1033500002108008000002B502108010000000007A
-:10336000061082000000004A021081080001FFFFE1
-:1033700006108140000000020210800000001A8048
-:103380000610900000000024061091200000004A62
-:10339000061093700000004A061095C00000004A15
-:1033A0000210800400001080021080B000000001B4
-:1033B0000210803C00000010021081040000000098
-:1033C00006108128000000020210800C000002B5E7
-:1033D0000210801400000000061084000000004A63
-:1033E0000210810C0001FFFF06108148000000025E
-:1033F0000210800400001A80061090900000002443
-:10340000061092480000004A061094980000004AF6
-:10341000061096E80000004A0210800000001080AC
-:10342000021080AC00000002021080380000001082
-:103430000210810000000000061081200000000240
-:1034400002108008000002B5021080100000000089
-:10345000061082000000004A021081080001FFFFF0
-:1034600006108140000000020210800000001A8057
-:103470000610900000000024061091200000004A71
-:10348000061093700000004A061095C00000004A24
-:103490000210800400001080021080B000000003C1
-:1034A0000210803C000000100210810400000000A7
-:1034B00006108128000000020210800C000002B5F6
-:1034C0000210801400000000061084000000004A72
-:1034D0000210810C0001FFFF06108148000000026D
-:1034E0000210800400001A80061090900000002452
-:1034F000061092480000004A061094980000004A06
-:10350000061096E80000004A0210800000001080BB
-:10351000021080AC0000000402108038000000108F
-:10352000021081000000000006108120000000024F
-:1035300002108008000002B5021080100000000098
-:10354000061082000000004A021081080001FFFFFF
-:1035500006108140000000020210800000001A8066
-:103560000610900000000024061091200000004A80
-:10357000061093700000004A061095C00000004A33
-:103580000210800400001080021080B000000005CE
-:103590000210803C000000100210810400000000B6
-:1035A00006108128000000020210800C000002B505
-:1035B0000210801400000000061084000000004A81
-:1035C0000210810C0001FFFF06108148000000027C
-:1035D0000210800400001A80061090900000002461
-:1035E000061092480000004A061094980000004A15
-:1035F000061096E80000004A0210800000001080CB
-:10360000021080AC0000000602108038000000109C
-:10361000021081000000000006108120000000025E
-:1036200002108008000002B50210801000000000A7
-:10363000061082000000004A021081080001FFFF0E
-:1036400006108140000000020210800000001A8075
-:103650000610900000000024061091200000004A8F
-:10366000061093700000004A061095C00000004A42
-:103670000210800400001080021080B000000007DB
-:103680000210803C000000100210810400000000C5
-:1036900006108128000000020210800C000002B514
-:1036A0000210801400000000061084000000004A90
-:1036B0000210810C0001FFFF06108148000000028B
-:1036C0000210800400001A80061090900000002470
-:1036D000061092480000004A061094980000004A24
-:1036E000061096E80000004A021205B00000000132
-:1036F0000212049000E383400212051400003C1003
-:103700000212066C000000010212067000000000A8
-:1037100002120494FFFFFFFF02120498FFFFFFFF55
-:103720000212049CFFFFFFFF021204A0FFFFFFFF35
-:10373000021204A4FFFFFFFF021204A8FFFFFFFF15
-:10374000021204ACFFFFFFFF021204B0FFFFFFFFF5
-:10375000021204BCFFFFFFFF021204C0FFFFFFFFC5
-:10376000021204C4FFFFFFFF021204C8FFFFFFFFA5
-:10377000021204CCFFFFFFFF021204D0FFFFFFFF85
-:10378000021204D8FFFFFFFF021204DCFFFFFFFF5D
-:10379000021204E0FFFFFFFF021204E4FFFFFFFF3D
-:1037A000021204E8FFFFFFFF021204ECFFFFFFFF1D
-:1037B000021204F0FFFFFFFF021204F4FFFFFFFFFD
-:1037C000021204F8FFFFFFFF021204FCFFFFFFFFDD
-:1037D00002120500FFFFFFFF02120504FFFFFFFFBB
-:1037E00002120508FFFFFFFF0212050CFFFFFFFF9B
-:1037F00002120510FFFFFFFF021204D4FF80200019
-:10380000021204B4F0005000021204B8F0001000DC
-:1038100002120390000000080212039C000000083E
-:10382000021203A000000008021203A4000000021C
-:10383000021203BC00000004021203C000000005D5
-:10384000021203C400000004021203D000000000B2
-:103850000212036C00000001021203680000003F26
-:10386000021201BC00000040021201C00000180852
-:10387000021201C400000803021201C8000008037C
-:10388000021201CC00000040021201D0000000032F
-:10389000021201D400000803021201D8000008033C
-:1038A000021201DC00000803021201E00001000323
-:1038B000021201E400000803021201E800000803FC
-:1038C000021201EC00000003021201F000000003EC
-:1038D000021201F400000003021201F800000003CC
-:1038E000021201FC000000030212020000000003AB
-:1038F000021202040000000302120208000000038A
-:103900000212020C00000003021202100000000369
-:103910000212021400000003021202180000000349
-:103920000212021C00000003021202200000000329
-:1039300002120224000000030212022800002403E5
-:103940000212022C0000002F0212023000000009B7
-:103950000212023400000019021202380000018431
-:103960000212023C00000183021202400000030622
-:103970000212024400000019021202480000000670
-:103980000212024C0000030602120250000003065D
-:1039900002120254000003060212025800000C86B4
-:1039A0000212025C0000030602120260000003061D
-:1039B0000212026400000006021202680000000603
-:1039C0000212026C000000060212027000000006E3
-:1039D00002120274000000060212027800000006C3
-:1039E0000212027C000000060212028000000006A3
-:1039F0000212028400000006021202880000000683
-:103A00000212028C00000006021202900000000662
-:103A10000212029400000006021202980000000642
-:103A20000212029C00000006021202A0000003061F
-:103A3000021202A400000013021202A800000006F5
-:103A4000021202B000001004021202B400001004BE
-:103A50000212032400106440021203280010644084
-:103A6000021205B400000001021201B000000001C2
-:103A70000600A000000000160200A0EC5554000053
-:103A80000200A0F0555555550200A0F40000555510
-:103A90000200A0F8F00000000200A0FC5554000055
-:103AA0000200A100555555550200A10400005555CE
-:103AB0000200A108F00000000200A18C5554000093
-:103AC0000200A190555555550200A194000055558E
-:103AD0000200A198F00000000200A19C000000007C
-:103AE0000200A1A0000100000200A1A400005014E7
-:103AF0000200A1A8000000000200A45C00000C006D
-:103B00000200A61C000000030200A06CFF5C000085
-:103B10000200A070FFF55FFF0200A0740000FFFF2D
-:103B20000200A078F00003E00200A07C000000008A
-:103B30000200A0800000A0000600A0840000000594
-:103B40000200A0980FE000000600A09C0000000703
-:103B50000200A0B8000004000600A0BC00000003A2
-:103B60000200A0C8000010000600A0CC0000000366
-:103B70000200A0D8000040000600A0DC0000000306
-:103B80000200A0E8000100000600A22C00000004D2
-:103B90000200A10CFF5C00000200A110FFF55FFF16
-:103BA0000200A1140000FFFF0200A118F00003E0D2
-:103BB0000200A11C000000000200A1200000A000E3
-:103BC0000600A124000000050200A1380FE000005B
-:103BD0000600A13C000000070200A15800000800F8
-:103BE0000600A15C000000030200A16800002000A4
-:103BF0000600A16C000000030200A1780000800014
-:103C00000600A17C000000030200A1880002000061
-:103C10000600A23C000000040000000000000000BC
-:103C20000000003100000000000000000000000063
-:103C30000000000000000000000000000000000084
-:103C40000000000000000000000000000031003211
-:103C50000000000000000000000000000000000064
-:103C60000000000000000000000000000000000054
-:103C700000000000000000000032005600000000BC
-:103C80000000000000000000000000000000000034
-:103C90000000000000000000000000000000000024
-:103CA000000000000056008C000000000000000032
-:103CB000008C009000900094009400980098009C64
-:103CC000009C00A000A000A400A400A800A800ACD4
-:103CD00000AC00B100B100B300B300B500000000BB
-:103CE00000000000000000000000000000000000D4
-:103CF00000000000000000000000000000B501020C
-:103D00000102010A010A01120112011B011B012417
-:103D10000124012D012D01360136013F013F0148EB
-:103D2000014801510151015A00000000000000004B
-:103D30000000000000000000000000000000000083
-:103D40000000000000000000000000000000000073
-:103D50000000000000000000000000000000000063
-:103D60000000000000000000000000000000000053
-:103D70000000000000000000000000000000000043
-:103D80000000000000000000000000000000000033
-:103D90000000000000000000000000000000000023
-:103DA0000000000000000000000000000000000013
-:103DB0000000000000000000000000000000000003
-:103DC00000000000000000000000000000000000F3
-:103DD0000000000000000000015A015F0000000028
-:103DE00000000000015F016001600161016101628A
-:103DF000016201630163016401640165016501669B
-:103E000001660167000000000000000000000000E3
-:103E100000000000000000000000000000000000A2
-:103E20000000000000000000000000000000000092
-:103E30000167016C016C01790179018600000000C5
-:103E40000000000000000000000000000000000072
-:103E50000000000000000000000000000000000062
-:103E60000000000000000000000000000000000052
-:103E70000000000000000000000000000000000042
-:103E80000000000000000000018601870000000023
-:103E90000000000000000000000000000000000022
-:103EA0000000000000000000000000000000000012
-:103EB00000000000018701BE0000000000000000BB
-:103EC00000000000000000000000000000000000F2
-:103ED00000000000000000000000000000000000E2
-:103EE00001BE01E900000000000000000000000029
-:103EF00000000000000000000000000000000000C2
-:103F000000000000000000000000000001E9021AAB
-:103F10000000000000000000021A02210221022815
-:103F20000228022F022F02360236023D023D0244D1
-:103F30000244024B024B02520252028A000000006D
-:103F400000000000028A028E028E02920292029605
-:103F50000296029A029A029E029E02A202A202A661
-:103F600002A602AA02AA02FC02FC03130313032AFC
-:103F7000032A032D032D03300330033303330336A9
-:103F8000033603390339033C033C033F033F034239
-:103F9000034203830383038A038A039103910395F6
-:103FA000039503990399039D039D03A103A103A511
-:103FB00003A503A903A903AD03AD03B103B103B284
-:103FC00000000000000000000000000000000000F1
-:103FD00000000000000000000000000000000000E1
-:103FE000000000000000000003B203C40000000055
-:103FF00000000000000000000000000000000000C1
-:1040000000000000000000000000000000000000B0
-:104010000000000003C403D903D903DC03DC03DF81
-:104020000000000000000000000000000000000090
-:104030000000000000000000000000000000000080
-:1040400003DF040C0000000000000000000000007E
-:104050000000000000000000000000000000000060
-:10406000000000000000000000000000040C050F2C
-:104070000000000000000000000000000000000040
-:104080000000000000000000000000000000000030
-:104090000000000000000000050F05160516051AB7
-:1040A000051A051E000000000000000000000000CE
-:1040B0000000000000000000000000000000000000
-:1040C00000000000051E055E00000000000000006A
-:1040D000055E056705670570057005790579058238
-:1040E0000582058B058B05940594059D059D05A608
-:1040F00005A605FF05FF0611061106230623062760
-:104100000627062B062B062F062F06330633063707
-:104110000637063B063B063F063F06430643064A74
-:10412000000000000000000000000000000000008F
-:10413000000000000000000000000000000000007F
-:104140000000000000000000064A065000000000C9
-:10415000000000000000000000000000000000005F
-:10416000000000000000000000000000000000004F
-:104170000000000006500653000000000000000090
-:10418000000000000000000000000000000000002F
-:10419000000000000000000000000000000000001F
-:1041A0000653065900000000000000000000000057
-:1041B00000000000000000000000000000000000FF
-:1041C00000000000000000000000000000000000EF
-:1041D0000000000000000000065906680668067727
-:1041E0000677068606860695069506A406A406B3F7
-:1041F00006B306C206C206D106D10742000000007F
-:1042000000000000000000000000000000000000AE
-:10421000000000000000000000000000000000009E
-:104220000000000007420755075507660766077735
-:10423000000000000000000000000000000000007E
-:10424000000000000000000000000000000000006E
-:10425000000000000000000000000000000000005E
-:10426000000000000000000000000000000000004E
-:10427000000000000000000000000000000000003E
-:10428000000000000000000000000000000000002E
-:10429000000000000000000000000000000000001E
-:1042A000000000000000000000000000000000000E
-:1042B00000010000000204C00003098000040E4059
-:1042C00000051300000617C000071C8000082140ED
-:1042D00000092600000A2AC0000B2F80000C344081
-:1042E000000D3900000E3DC0000F42800010474015
-:1042F00000114C00001250C00013558000145A40A9
-:1043000000155F00001663C00017688000186D403C
-:1043100000197200001A76C0001B7B80001C8040D0
-:10432000001D8500001E89C0001F8E800020934064
-:10433000000020000000400000006000000080003D
-:104340000000A0000000C0000000E000000100002C
-:104350000001200000014000000160000001800019
-:104360000001A0000001C0000001E0000002000008
-:1043700000022000000240000002600000028000F5
-:104380000002A0000002C0000002E00000030000E4
-:1043900000032000000340000003600000038000D1
-:1043A0000003A0000003C0000003E00000040000C0
-:1043B00000042000000440000004600000048000AD
-:1043C0000004A0000004C0000004E000000500009C
-:1043D0000005200000054000000560000005800089
-:1043E0000005A0000005C0000005E0000006000078
-:1043F0000006200000064000000660000006800065
-:104400000006A0000006C0000006E0000007000053
-:104410000007200000074000000760000007800040
-:104420000007A0000007C0000007E000000800002F
-:10443000000820000008400000086000000880001C
-:104440000008A0000008C0000008E000000900000B
-:1044500000092000000940000009600000098000F8
-:104460000009A0000009C0000009E000000A0000E7
-:10447000000A2000000A4000000A6000000A8000D4
-:10448000000AA000000AC000000AE000000B0000C3
-:10449000000B2000000B4000000B6000000B8000B0
-:1044A000000BA000000BC000000BE000000C00009F
-:1044B000000C2000000C4000000C6000000C80008C
-:1044C000000CA000000CC000000CE000000D00007B
-:1044D000000D2000000D4000000D6000000D800068
-:1044E000000DA000000DC000000DE000000E000057
-:1044F000000E2000000E4000000E6000000E800044
-:10450000000EA000000EC000000EE000000F000032
-:10451000000F2000000F4000000F6000000F80001F
-:10452000000FA000000FC000000FE000001000000E
-:1045300000102000001040000010600000108000FB
-:104540000010A0000010C0000010E00000110000EA
-:1045500000112000001140000011600000118000D7
-:104560000011A0000011C0000011E00000120000C6
-:1045700000122000001240000012600000128000B3
-:104580000012A0000012C0000012E00000130000A2
-:10459000001320000013400000136000001380008F
-:1045A0000013A0000013C0000013E000001400007E
-:1045B000001420000014400000146000001480006B
-:1045C0000014A0000014C0000014E000001500005A
-:1045D0000015200000154000001560000015800047
-:1045E0000015A0000015C0000015E0000016000036
-:1045F0000016200000164000001660000016800023
-:104600000016A0000016C0000016E0000017000011
-:1046100000172000001740000017600000178000FE
-:104620000017A0000017C0000017E00000180000ED
-:1046300000182000001840000018600000188000DA
-:104640000018A0000018C0000018E00000190000C9
-:1046500000192000001940000019600000198000B6
-:104660000019A0000019C0000019E000001A0000A5
-:10467000001A2000001A4000001A6000001A800092
-:10468000001AA000001AC000001AE000001B000081
-:10469000001B2000001B4000001B6000001B80006E
-:1046A000001BA000001BC000001BE000001C00005D
-:1046B000001C2000001C4000001C6000001C80004A
-:1046C000001CA000001CC000001CE000001D000039
-:1046D000001D2000001D4000001D6000001D800026
-:1046E000001DA000001DC000001DE000001E000015
-:1046F000001E2000001E4000001E6000001E800002
-:10470000001EA000001EC000001EE000001F0000F0
-:10471000001F2000001F4000001F6000001F8000DD
-:10472000001FA000001FC000001FE00000200000CC
-:1047300000202000002040000020600000208000B9
-:104740000020A0000020C0000020E00000210000A8
-:104750000021200000214000002160000021800095
-:104760000021A0000021C0000021E0000022000084
-:104770000022200000224000002260000022800071
-:104780000022A0000022C0000022E0000023000060
-:10479000002320000023400000236000002380004D
-:1047A0000023A0000023C0000023E000002400003C
-:1047B0000024200000244000002460000024800029
-:1047C0000024A0000024C0000024E0000025000018
-:1047D0000025200000254000002560000025800005
-:1047E0000025A0000025C0000025E00000260000F4
-:1047F00000262000002640000026600000268000E1
-:104800000026A0000026C0000026E00000270000CF
-:1048100000272000002740000027600000278000BC
-:104820000027A0000027C0000027E00000280000AB
-:104830000028200000284000002860000028800098
-:104840000028A0000028C0000028E0000029000087
-:104850000029200000294000002960000029800074
-:104860000029A0000029C0000029E000002A000063
-:10487000002A2000002A4000002A6000002A800050
-:10488000002AA000002AC000002AE000002B00003F
-:10489000002B2000002B4000002B6000002B80002C
-:1048A000002BA000002BC000002BE000002C00001B
-:1048B000002C2000002C4000002C6000002C800008
-:1048C000002CA000002CC000002CE000002D0000F7
-:1048D000002D2000002D4000002D6000002D8000E4
-:1048E000002DA000002DC000002DE000002E0000D3
-:1048F000002E2000002E4000002E6000002E8000C0
-:10490000002EA000002EC000002EE000002F0000AE
-:10491000002F2000002F4000002F6000002F80009B
-:10492000002FA000002FC000002FE000003000008A
-:104930000030200000304000003060000030800077
-:104940000030A0000030C0000030E0000031000066
-:104950000031200000314000003160000031800053
-:104960000031A0000031C0000031E0000032000042
-:10497000003220000032400000326000003280002F
-:104980000032A0000032C0000032E000003300001E
-:10499000003320000033400000336000003380000B
-:1049A0000033A0000033C0000033E00000340000FA
-:1049B00000342000003440000034600000348000E7
-:1049C0000034A0000034C0000034E00000350000D6
-:1049D00000352000003540000035600000358000C3
-:1049E0000035A0000035C0000035E00000360000B2
-:1049F000003620000036400000366000003680009F
-:104A00000036A0000036C0000036E000003700008D
-:104A1000003720000037400000376000003780007A
-:104A20000037A0000037C0000037E0000038000069
-:104A30000038200000384000003860000038800056
-:104A40000038A0000038C0000038E0000039000045
-:104A50000039200000394000003960000039800032
-:104A60000039A0000039C0000039E000003A000021
-:104A7000003A2000003A4000003A6000003A80000E
-:104A8000003AA000003AC000003AE000003B0000FD
-:104A9000003B2000003B4000003B6000003B8000EA
-:104AA000003BA000003BC000003BE000003C0000D9
-:104AB000003C2000003C4000003C6000003C8000C6
-:104AC000003CA000003CC000003CE000003D0000B5
-:104AD000003D2000003D4000003D6000003D8000A2
-:104AE000003DA000003DC000003DE000003E000091
-:104AF000003E2000003E4000003E6000003E80007E
-:104B0000003EA000003EC000003EE000003F00006C
-:104B1000003F2000003F4000003F6000003F800059
-:104B2000003FA000003FC000003FE000003FE00168
-:104B300000000000000001FF0000020000007FF8FC
-:104B400000007FF800000CDF0000150000000001ED
-:104B50000000000100000001FFFFFFFFFFFFFFFF5B
-:104B6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF55
-:104B7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45
-:104B8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF35
-:104B9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25
-:104BA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF15
-:104BB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF05
-:104BC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5
-:104BD000FFFFFFFFFFFFFFFFFFFFFFFF00000000E1
-:104BE000FFFFFFFF00000000FFFFFFFFFFFFFFFFD1
-:104BF00000000000FFFFFFFF00000000FFFFFFFFBD
-:104C0000FFFFFFFF00000000FFFFFFFF00000000AC
-:104C1000FFFFFFFF0000000300BEBC20FFFFFFFFFF
-:104C200000000000FFFFFFFF00000000FFFFFFFF8C
-:104C30000000000300BEBC20FFFFFFFF00000000DB
-:104C4000FFFFFFFF00000000FFFFFFFF0000000369
-:104C500000BEBC20FFFFFFFF00000000FFFFFFFFC2
-:104C600000000000FFFFFFFF0000000300BEBC20AB
-:104C7000FFFFFFFF00000000FFFFFFFF000000003C
-:104C8000FFFFFFFF0000000300BEBC20FFFFFFFF8F
-:104C900000000000FFFFFFFF00000000FFFFFFFF1C
-:104CA0000000000300BEBC2000002000000040C047
-:104CB00000006180000082400000A3000000C3C02B
-:104CC0000000E4800001054000012600000146C00C
-:104CD00000016780000188400001A9000001C9C0EF
-:104CE0000001EA8000020B4000022C0000024CC0D0
-:104CF00000026D8000028E400002AF000002CFC0B3
-:104D00000002F0800003114000033200000352C093
-:104D100000037380000394400003B5000003D5C076
-:104D20000003F6800004174000043800000458C057
-:104D30000004798000049A40000080000001038094
-:104D40000001870000020A8000028E00000311802B
-:104D5000000395000004188000049C0000051F80DB
-:104D60000005A300000626800006AA0000072D808B
-:104D70000007B100000834800008B80000093B803B
-:104D80000009BF00000A4280000AC600000B4980EB
-:104D9000000BCD00000C5080000CD400000D57809B
-:104DA000000DDB0000007FF800007FF80000193CD8
-:104DB000000015000000190000000028001000008D
-:104DC0000000000000000000FFFFFFFF40000000A7
-:104DD00040000000400000004000000040000000D3
-:104DE00040000000400000004000000040000000C3
-:104DF00040000000400000004000000040000000B3
-:104E000040000000400000004000000040000000A2
-:104E10004000000040000000400000004000000092
-:104E20004000000040000000400000004000000082
-:104E30004000000040000000400000004000000072
-:104E400040000000400000004000000000007FF82B
-:104E500000007FF8000005C700001500FFFFFFFFFE
-:104E6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52
-:104E7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42
-:104E8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF32
-:104E9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22
-:104EA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12
-:104EB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02
-:104EC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2
-:104ED000FFFFFFFFFFFFFFFFFFFFFFFF400000009E
-:104EE00040000000400000004000000040000000C2
-:104EF00040000000400000004000000040000000B2
-:104F000040000000400000004000000040000000A1
-:104F10004000000040000000400000004000000091
-:104F20004000000040000000400000004000000081
-:104F30004000000040000000400000004000000071
-:104F40004000000040000000400000004000000061
-:104F50004000000040000000400000000000100081
-:104F6000000020800000310000004180000052005D
-:104F70000000628000007300000083800000940045
-:104F80000000A4800000B5000000C5800000D6002D
-:104F90000000E6800000F700000107800001180013
-:104FA00000012880000139000001498000015A00F9
-:104FB00000016A8000017B0000018B8000019C00E1
-:104FC0000001AC800001BD000001CD800001DE00C9
-:104FD0000001EE800001FF0000007FF800007FF874
-:104FE0000000112E0000350010000000000028AD68
-:104FF000000000000001000100150005CCCCCCC56C
-:10500000FFFFFFFFFFFFFFFF7058103C0000000094
-:105010000000000000000001CCCC0201CCCCCCCCC4
-:10502000CCCC0201CCCCCCCCCCCC0201CCCCCCCCEA
-:10503000CCCC0201CCCCCCCCCCCC0201CCCCCCCCDA
-:10504000CCCC0201CCCCCCCCCCCC0201CCCCCCCCCA
-:10505000CCCC0201CCCCCCCC00000000FFFFFFFF89
-:105060004000000040000000400000004000000040
-:105070004000000040000000400000004000000030
-:105080004000000040000000400000004000000020
-:105090004000000040000000400000004000000010
-:1050A0004000000040000000400000004000000000
-:1050B00040000000400000004000000040000000F0
-:1050C00040000000400000004000000040000000E0
-:1050D00040000000400000004000000040000000D0
-:1050E000000E0232011600D6001000000000000081
-:1050F00000720236012300F30010000000000000DF
-:105100000000FFFF000000000000FFFF00000000A3
-:105110000000FFFF000000000000FFFF0000000093
-:105120000000FFFF000000000000FFFF0000000083
-:105130000000FFFF000000000000FFFF0000000073
-:105140000000FFFF000000000000FFFF0000000063
-:105150000000FFFF000000000000FFFF0000000053
-:105160000000FFFF000000000000FFFF0000000043
-:105170000000FFFF000000000000FFFF0000000033
-:105180000000FFFF000000000000FFFF0000000023
-:105190000000FFFF000000000000FFFF0000000013
-:1051A0000000FFFF000000000000FFFF0000000003
-:1051B0000000FFFF000000000000FFFF00000000F3
-:1051C0000000FFFF000000000000FFFF00000000E3
-:1051D0000000FFFF000000000000FFFF00000000D3
-:1051E0000000FFFF000000000000FFFF00000000C3
-:1051F0000000FFFF000000000000FFFF00000000B3
-:105200000000FFFF000000000000FFFF00000000A2
-:105210000000FFFF000000000000FFFF0000000092
-:105220000000FFFF000000000000FFFF0000000082
-:105230000000FFFF000000000000FFFF0000000072
-:105240000000FFFF000000000000FFFF0000000062
-:105250000000FFFF000000000000FFFF0000000052
-:105260000000FFFF000000000000FFFF0000000042
-:105270000000FFFF000000000000FFFF0000000032
-:105280000000FFFF000000000000FFFF0000000022
-:105290000000FFFF000000000000FFFF0000000012
-:1052A0000000FFFF000000000000FFFF0000000002
-:1052B0000000FFFF000000000000FFFF00000000F2
-:1052C0000000FFFF000000000000FFFF00000000E2
-:1052D0000000FFFF000000000000FFFF00000000D2
-:1052E0000000FFFF000000000000FFFF00000000C2
-:1052F0000000FFFF000000000000FFFF00000000B2
-:10530000FFFFFFF3318FFFFF0C30C30CC30C30C322
-:10531000CF3CF300F3CF3CF30000CF3CCDCDCDCD5F
-:10532000FFFFFFF130EFFFFF0C30C30CC30C30C3A5
-:10533000CF3CF300F3CF3CF30001CF3CCDCDCDCD3E
-:10534000FFFFFFF6305FFFFF0C30C30CC30C30C310
-:10535000CF3CF300F3CF3CF30002CF3CCDCDCDCD1D
-:10536000FFFFF4061CBFFFFF0C30C305C30C30C3A6
-:10537000CF300014F3CF3CF30004CF3CCDCDCDCDE6
-:10538000FFFFFFF2304FFFFF0C30C30CC30C30C3E4
-:10539000CF3CF300F3CF3CF30008CF3CCDCDCDCDD7
-:1053A000FFFFFFFA302FFFFF0C30C30CC30C30C3DC
-:1053B000CF3CF300F3CF3CF30010CF3CCDCDCDCDAF
-:1053C000FFFFFFF731EFFFFF0C30C30CC30C30C3FE
-:1053D000CF3CF300F3CF3CF30020CF3CCDCDCDCD7F
-:1053E000FFFFFFF5302FFFFF0C30C30CC30C30C3A1
-:1053F000CF3CF300F3CF3CF30040CF3CCDCDCDCD3F
-:10540000FFFFFFF3310FFFFF0C30C30CC30C30C3A1
-:10541000CF3CF300F3CF3CF30000CF3CCDCDCDCD5E
-:10542000FFFFFFF1310FFFFF0C30C30CC30C30C383
-:10543000CF3CF300F3CF3CF30001CF3CCDCDCDCD3D
-:10544000FFFFFFF6305FFFFF0C30C30CC30C30C30F
-:10545000CF3CF300F3CF3CF30002CF3CCDCDCDCD1C
-:10546000FFFFF4061CBFFFFF0C30C305C30C30C3A5
-:10547000CF300014F3CF3CF30004CF3CCDCDCDCDE5
-:10548000FFFFFFF2304FFFFF0C30C30CC30C30C3E3
-:10549000CF3CF300F3CF3CF30008CF3CCDCDCDCDD6
-:1054A000FFFFFFFA302FFFFF0C30C30CC30C30C3DB
-:1054B000CF3CF300F3CF3CF30010CF3CCDCDCDCDAE
-:1054C000FFFFFFF730EFFFFF0C30C30CC30C30C3FE
-:1054D000CF3CF300F3CF3CF30020CF3CCDCDCDCD7E
-:1054E000FFFFFFF5304FFFFF0C30C30CC30C30C380
-:1054F000CF3CF300F3CF3CF30040CF3CCDCDCDCD3E
-:10550000FFFFFFF331EFFFFF0C30C30CC30C30C3C0
-:10551000CF3CF300F3CF3CF30000CF3CCDCDCDCD5D
-:10552000FFFFFFF1310FFFFF0C30C30CC30C30C382
-:10553000CF3CF300F3CF3CF30001CF3CCDCDCDCD3C
-:10554000FFFFFFF6305FFFFF0C30C30CC30C30C30E
-:10555000CF3CF300F3CF3CF30002CF3CCDCDCDCD1B
-:10556000FFFFF4061CBFFFFF0C30C305C30C30C3A4
-:10557000CF300014F3CF3CF30004CF3CCDCDCDCDE4
-:10558000FFFFFFF2304FFFFF0C30C30CC30C30C3E2
-:10559000CF3CF300F3CF3CF30008CF3CCDCDCDCDD5
-:1055A000FFFFFFFA302FFFFF0C30C30CC30C30C3DA
-:1055B000CF3CF300F3CF3CF30010CF3CCDCDCDCDAD
-:1055C000FFFFFF97056FFFFF0C30C30CC30C30C308
-:1055D000CF3CC000F3CF3CF30020CF3CCDCDCDCDB0
-:1055E000FFFFFFF5310FFFFF0C30C30CC30C30C3BE
-:1055F000CF3CF300F3CF3CF30040CF3CCDCDCDCD3D
-:10560000FFFFFFF3320FFFFF0C30C30CC30C30C39E
-:10561000CF3CF300F3CF3CF30000CF3CCDCDCDCD5C
-:10562000FFFFFFF1310FFFFF0C30C30CC30C30C381
-:10563000CF3CF300F3CF3CF30001CF3CCDCDCDCD3B
-:10564000FFFFFFF6305FFFFF0C30C30CC30C30C30D
-:10565000CF3CF300F3CF3CF30002CF3CCDCDCDCD1A
-:10566000FFFFF4061CBFFFFF0C30C305C30C30C3A3
-:10567000CF300014F3CF3CF30004CF3CCDCDCDCDE3
-:10568000FFFFFFF2304FFFFF0C30C30CC30C30C3E1
-:10569000CF3CF300F3CF3CF30008CF3CCDCDCDCDD4
-:1056A000FFFFFF8A042FFFFF0C30C30CC30C30C375
-:1056B000CF3CC000F3CF3CF30010CF3CCDCDCDCDDF
-:1056C000FFFFFF9705CFFFFF0C30C30CC30C30C3A7
-:1056D000CF3CC000F3CF3CF30020CF3CCDCDCDCDAF
-:1056E000FFFFFFF5310FFFFF0C30C30CC30C30C3BD
-:1056F000CF3CF300F3CF3CF30040CF3CCDCDCDCD3C
-:10570000FFFFFFF3316FFFFF0C30C30CC30C30C33E
-:10571000CF3CF300F3CF3CF30000CF3CCDCDCDCD5B
-:10572000FFFFFFF1302FFFFF0C30C30CC30C30C361
-:10573000CF3CF300F3CF3CF30001CF3CCDCDCDCD3A
-:10574000FFFFFFF6305FFFFF0C30C30CC30C30C30C
-:10575000CF3CF300F3CF3CF30002CF3CCDCDCDCD19
-:10576000FFFFFFF630BFFFFF0C30C30CC30C30C38C
-:10577000CF3CF314F3CF3CF30004CF3CCDCDCDCDE3
-:10578000FFFFFFF2304FFFFF0C30C30CC30C30C3E0
-:10579000CF3CF300F3CF3CF30008CF3CCDCDCDCDD3
-:1057A000FFFFFFFA302FFFFF0C30C30CC30C30C3D8
-:1057B000CF3CF300F3CF3CF30010CF3CCDCDCDCDAB
-:1057C000FFFFFFF731CFFFFF0C30C30CC30C30C31A
-:1057D000CF3CF300F3CF3CF30020CF3CCDCDCDCD7B
-:1057E000FFFFFFF0307FFFFF0C30C30CC30C30C352
-:1057F000CF3CF300F3CF3CF30040CF3CCDCDCDCD3B
-:10580000FFFFFFFF30CFFFFF0C30C30CC30C30C3D2
-:10581000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD8E
-:10582000FFFFFFFF30CFFFFF0C30C30CC30C30C3B2
-:10583000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD6D
-:10584000FFFFFFFF30CFFFFF0C30C30CC30C30C392
-:10585000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD4C
-:10586000FFFFFFFF30CFFFFF0C30C30CC30C30C372
-:10587000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD2A
-:10588000FFFFFFFF30CFFFFF0C30C30CC30C30C352
-:10589000CF3CF3CCF3CF3CF30008CF3CCDCDCDCD06
-:1058A000FFFFFFFF30CFFFFF0C30C30CC30C30C332
-:1058B000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDDE
-:1058C000FFFFFFFF30CFFFFF0C30C30CC30C30C312
-:1058D000CF3CF3CCF3CF3CF30020CF3CCDCDCDCDAE
-:1058E000FFFFFFFF30CFFFFF0C30C30CC30C30C3F2
-:1058F000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD6E
-:10590000FFFFFFFF30CFFFFF0C30C30CC30C30C3D1
-:10591000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD8D
-:10592000FFFFFFFF30CFFFFF0C30C30CC30C30C3B1
-:10593000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD6C
-:10594000FFFFFFFF30CFFFFF0C30C30CC30C30C391
-:10595000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD4B
-:10596000FFFFFFFF30CFFFFF0C30C30CC30C30C371
-:10597000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD29
-:10598000FFFFFFFF30CFFFFF0C30C30CC30C30C351
-:10599000CF3CF3CCF3CF3CF30008CF3CCDCDCDCD05
-:1059A000FFFFFFFF30CFFFFF0C30C30CC30C30C331
-:1059B000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDDD
-:1059C000FFFFFFFF30CFFFFF0C30C30CC30C30C311
-:1059D000CF3CF3CCF3CF3CF30020CF3CCDCDCDCDAD
-:1059E000FFFFFFFF30CFFFFF0C30C30CC30C30C3F1
-:1059F000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD6D
-:105A0000FFFFFFFF30CFFFFF0C30C30CC30C30C3D0
-:105A1000CF3CF3CCF3CF3CF30000CF3CCDCDCDCD8C
-:105A2000FFFFFFFF30CFFFFF0C30C30CC30C30C3B0
-:105A3000CF3CF3CCF3CF3CF30001CF3CCDCDCDCD6B
-:105A4000FFFFFFFF30CFFFFF0C30C30CC30C30C390
-:105A5000CF3CF3CCF3CF3CF30002CF3CCDCDCDCD4A
-:105A6000FFFFFFFF30CFFFFF0C30C30CC30C30C370
-:105A7000CF3CF3CCF3CF3CF30004CF3CCDCDCDCD28
-:105A8000FFFFFFFF30CFFFFF0C30C30CC30C30C350
-:105A9000CF3CF3CCF3CF3CF30008CF3CCDCDCDCD04
-:105AA000FFFFFFFF30CFFFFF0C30C30CC30C30C330
-:105AB000CF3CF3CCF3CF3CF30010CF3CCDCDCDCDDC
-:105AC000FFFFFFFF30CFFFFF0C30C30CC30C30C310
-:105AD000CF3CF3CCF3CF3CF30020CF3CCDCDCDCDAC
-:105AE000FFFFFFFF30CFFFFF0C30C30CC30C30C3F0
-:105AF000CF3CF3CCF3CF3CF30040CF3CCDCDCDCD6C
-:105B0000000C0000000700C000028130000B81582B
-:105B10000002021000010230000F024000010330B9
-:105B2000000800000008008000028100000B8128AE
-:105B3000000201E0000102000007021000020280E2
-:105B4000000F0000000800F000028170000B819837
-:105B50000002025000010270000B8280000803382E
-:105B6000001000000008010000028180000B81A8E5
-:105B70000002026000018280000E8298000803800B
-:105B8000000B0000000100B0000280C0000580E8AA
-:105B90000002014000010160000E0170000382500C
-:105BA000CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC35
-:105BB00000002000CCCCCCCCCCCCCCCCCCCCCCCC35
-:105BC000CCCCCCCC00002000CCCCCCCCCCCCCCCC25
-:105BD000CCCCCCCCCCCCCCCC040020000000000041
-:105BE0001F8B080000000000000BFB51CFC0F0032A
-:105BF0008A59051918F484117C7A607E4ECAF43BE8
-:105C0000F232303803B12B103700F1616E06862373
-:105C1000DCC4EB3F2B8F6007CA3230D402F17E69BF
-:105C200006062B3984B8A10203C312203F0D2AF6C1
-:105C30001A4817CA53E6EEC182555431C51495115E
-:105C40006C552CF2C8580D4DBE411995AF4E40FF12
-:105C500040E3641D54FE042D08FD5E1B42A7A0C94D
-:105C60004F84CABB42FD95AA83DD5C3722FD9DC6E9
-:105C700082CA4F40E3B730A2F2CD38D0DC0F550FC7
-:105C80000000174B67C80300000000000000000080
-:105C90001F8B080000000000000BED7D0D7854D52F
-:105CA000B5E83E3F73E6CCE4CCE4242461C2EF24A3
-:105CB000841034E21022064BEB097F869A7A07AAF9
-:105CC000985AC5012306082452F5E1D37E9948026B
-:105CD000011106B53414D4E14F692FB6918B965A51
-:105CE0008A033E2DB6BEEF059FB57AB57DD152FC35
-:105CF000294ACABB52FBAEAD6FAFB5F74ECE39CC19
-:105D000090E04FDBFBDEA59FDDD9E7EC9FB5D7DF49
-:105D10005E6BEDB5CF78483E29B89C904FE01F2DC3
-:105D2000FF9741087DD4577A7412CFBA98909C3C63
-:105D30002BDE534EC8D03C2B452AE973530B7BA571
-:105D4000FE7EA23C9C332B04EDDAF2AD10A163B4CD
-:105D5000E5CC2331182BD640480121AA4EF09F688C
-:105D6000EF31E7EAA41C1FFDF513F15E21A4DD2C41
-:105D7000CE867EEEF10949127289BD2E1322C6A489
-:105D8000FD7C02DE12FA208F107F959CBCA288C297
-:105D90005D924C41DD0833B80F17BD523386AE63B8
-:105DA0005DB51CF186A1F7AD844C2664058C45EBEE
-:105DB000EB2676D78CC983F76A04DECE54F6B66A32
-:105DC000B4BD5142B07D70623CA5613FCB28A4FDBB
-:105DD00072180824A76C512D091262CED0FAE1C2C4
-:105DE000FFB770FD066FA79738DF1B64FD1F95098D
-:105DF00050EB25D18BE8F8535DEFCB66BD0DE31A70
-:105E0000843E2FE3CFE9BAEE873F0A09F91209E48D
-:105E10009DC8A27F5F4A2E053C909A5C42A69C8D4D
-:105E2000BF7EBCC591BE8430BA68A4EF1FD241E7E3
-:105E300074B862464FA744D7ED8BC8C44B1FCD52F0
-:105E40005ED48B012F4715C4C3BA3A86E77533E495
-:105E5000645CC275D616D2FEA309C363CEF862890C
-:105E60001413B2B185D6C79D8DE7EC928405F4F783
-:105E7000951009F82A9B3E1B42D7953D35857C330A
-:105E8000BA8AE193DCCDF011A7FFFBA4B81F9FD91C
-:105E9000029F1127BEB2393E736A6CF882E755142F
-:105EA0008F13E0BD138F49F883E2AB5EE0319F8C26
-:105EB000453CC67311BF03E1F10A8A832C0ABFFF78
-:105EC000556FD25BD48F57C11702AF26C7EB8699A7
-:105ED000BD3A30C3468BF1392129490EE178925CF5
-:105EE00085EBC3B203F0E6C5FEF85EA7301B7C9ECF
-:105EF000309DC75F9640FCEB141D4324E053435292
-:105F000081AF814FD3CCBB4E4FEA126DBF69AA4C13
-:105F1000805EEB2C998469FD74999A5400EEB8D593
-:105F20001DB2F1A901F8A7F8BA8FE3471B213BF096
-:105F3000A9E6F95D7CEE5CC7A6BEF5597C5D6C1DDB
-:105F4000A43BD901709C99299375D2C0E30E842794
-:105F500031EE80F0F598BE1298F70525B28EF2DA90
-:105F6000BA70B243A6F8DA3883E1E36CFA7EC6F978
-:105F70007A7BF5924ADB7C915EDD2CFF02E62139CB
-:105F8000CE7555993E33ADFE3CBF7988B960743407
-:105F900090991E9F1BFC610ABF0D4F7AD894607CBC
-:105FA0007DFC3D3AA8784276E8A017DDF39C05AF6A
-:105FB0006B5EF73C6A49B3A562CDA987343341D8FB
-:105FC0003C16DBA7087BAE821EA1FAC71F71EA113F
-:105FD000B7FED64638EB6A15D3D72AB13D2F02ED6E
-:105FE0004EF5CB85A45F4F570E4EBF10AB01E17548
-:105FF000EB93315CAEA7EFEDA95329FD4BB6093DFC
-:106000007DF72FCA687D37E8695ADFDD0973D1B2A1
-:10601000CBA9A727F0C1CABFF3920C7A7A47063DF5
-:106020005D9CB0A6819E2E49D08D808E53BC9EE98A
-:10603000E9E28E6619E83481EB097280E149A7FF35
-:10604000B3EBE9623ECF986D4E3C15733D5DBEDF0C
-:10605000F59CEBE962979EDE087F507C154A1C8F09
-:10606000634929E271EA20F73B8E47F77E570C73AC
-:106070008FA1787C90ED7739790C8FED1D3201FD81
-:10608000707A9B8CFA715C51548676424F72D0487C
-:10609000195FFF4EAEAF059C636698D5A04C4B8848
-:1060A000590DF4D1D693482A0C7ABA310EF36C4AC2
-:1060B000303D5D922072CC6607691C9E4DA1DCD9F3
-:1060C00020D7A7136A0496B98B8465BDA81FAF7D3E
-:1060D0007607C7E3D7A095431E9C74CCE17875E39F
-:1060E000675CD2C9DF250FBAE8B1DE59CF71D1E5BF
-:1060F0004AC9657F0C921E5E95C4BDB9504FA25D22
-:10610000A7D3B5E6D3BAF22FCF5AC0D746277BA67E
-:1061100075C8C922CAB7813656F774A8C96A5ABF6A
-:10612000218FF1F5D83849825DA784A204ECCFB164
-:1061300079547FD8F0E9E1F81474833F011F63B804
-:106140007D913D33D707FCBD298FE37B06C33755CF
-:10615000803ED07F02DF1E8E6FA3B21BC023B3C36D
-:106160004E7C4F3AEAD437D7D60D71D4AF890E3F63
-:10617000277D3C9C8E1E4E27C14767E13FEEB20F44
-:106180002B9D758F8B3E2D924BEF0C923EDA115268
-:10619000067C3B4EF64776149DDD2E21C948373AE2
-:1061A00079F2389D7F0135E3B2E9F8CB48CF28403A
-:1061B000D001238CE32C977B0AA07E8AF46E1E39D3
-:1061C000A67FFC512A392051234EA2E85D49411A8D
-:1061D000A693545610C18EEA05B874C48B44FFBB15
-:1061E0001EF94495015FC34DF69CC4B355A887883A
-:1061F000F817463A79F99F852B9FFFB344F128F1B0
-:1062000052013A8E01FCC4506FEA2481753FE9C205
-:10621000D220DD5806A9A686D224A604652E896060
-:10622000492E483E9142FD79B789FCEEFB1DF924C9
-:10623000AB7F3DF7C29F14AFC348F47109FC273A06
-:106240009EAEF4F3A18FF321B5D3906F7593F1ADAA
-:106250005E42F7D372947BF45FDC785ECBF5F28616
-:10626000161DCBF52D262E7268281997297D7CB531
-:106270004C8FE4847A3AC06FF137AB912B68DD6FB5
-:10628000F4BE7A13D87BB76B917B68FDF0CCE74303
-:1062900050EFB8DD60F6611BB353FD1C7B1D637BC3
-:1062A0007B5651B836DCAE47F823873EDA30BEF76E
-:1062B0009D9DA0B76EF34700BF9B4247C2AB405EB7
-:1062C0009A3594176A7B22FDD657FCA208EDB58F4C
-:1062D00029FC943E2842B4BFFE116D3589B61BD10E
-:1062E000DB82767D7377B59287EFE38170FF7A3B2F
-:1062F0008A87E1FEDF71642D09D3973995710BF020
-:10630000E52BA3A62CE5435FA529C50D90CAD8EBC4
-:1063100012E53FFF8C18B128FE0221B3157845E73E
-:1063200074236A2204F2EBC667C7C87868219D37D8
-:106330003E5E8BEC46B632A57969DAF5E17FE61D63
-:10634000D75969ECA96C5942FE3F327E11FABD5E05
-:10635000120B65814E2AD3C86E0AE7BAF18B46C785
-:10636000D2D87B3639E3F64AFA32533F4D21CD5D20
-:106370003678C6CA32F29F24EB4C6E43948FA85CE9
-:10638000E5988C9FB419C44AA681E3720EBFAEC6CD
-:106390008989F6B529819DF545E1EB5D89C1B9563D
-:1063A00022755D69DE6F0778F2413EEE4EC1FE98C0
-:1063B0003D93F135FDCFEAA2F0E7A8AC14ED6B38C0
-:1063C000FC7B78BFF3D043050F027F940FCEFEF223
-:1063D000C2BC69E09DF829E6DD48E79565139F0B8F
-:1063E000BCBBE9294A49F6E1FACE8CDF1C02FB343A
-:1063F000139CE1DB50B79370332D87D2B29697266A
-:106400002BDDF39DEF785F96D93ADCE3925DCC9E6D
-:10641000F2F3FDEBF094572C85D26D749CF0B88AA2
-:10642000537F8C2E93D15FDDB4876EF845A03F5823
-:10643000FD915D24A950549EBEFB1E19E01A49ED42
-:106440007C683F84C464C05B11094B500A3DB88628
-:10645000EBC10F49F43A391FF47417DA45B595B713
-:106460004E4B1737AAE7F2713EFBD45768B9408FFD
-:106470002E82F18DC8318BEEE4447B31BD5CD1EDD1
-:106480002A34D7260F44117CC1E4A99DF33BC8CD23
-:106490001C5A9F777D7A3837CDD48631BBC52C44C2
-:1064A0007F47350BE7DAE471532B952BFA3E09E36E
-:1064B000D9E4E0BB7C7DAD5C1ECE871F6B6869466E
-:1064C0002C4BA1AF6A92891940B7ABA5D86A998EB7
-:1064D00053D11C7956A575634FB7E567CFD7C2F383
-:1064E0007925CDEDC01286D54D40DF3E72F70A0BFF
-:1064F000E8787A045D7A1A3B4194AA253BEC147D36
-:1065000084DF690F0D521E2F8824A601BC65E1634C
-:10651000D5B961A0536C1BD069C4D1C86158A251D0
-:10652000772C956FA357D8646523004DE1D7E2948B
-:106530006E488F6808E8B198447742FF406594C57B
-:106540002B07094726FE0F8798DE0A737E6F8F5050
-:106550007E97FAE5C1CFE5A19DBF3F5D49D0BF68F9
-:10656000CFAB30D3ED1782DF05FF0B7DE86E77F8F8
-:1065700053F0F9785A961213FD9A0F49EC39C0037B
-:106580005D3DCA9F16EA42FF4EC8556DE4D88C2186
-:106590001047AD0C5728B6FDFA7DCE770B74EB97FC
-:1065A000D07FDEF50BDAF3291EC6DD4D22A066AFE3
-:1065B000BD7E01B1F3FBAFFBDA475F42F9BABB1B0B
-:1065C000DDD281FA75F3F55D2D455FB3F3211DE74B
-:1065D000751CA7A43B2EDBF44E0EC7B332B38F3F1E
-:1065E0004D10CD9ADB122AD0A7A236A248B6755C10
-:1065F0005BE7B4E729BFBF03E3BAF9741E69F690FD
-:10660000F3D83F4649B15E80B7B6A4BB0DE0D34294
-:1066100051F4F728DCA7E1F91700F727E782FB1D03
-:10662000887580DE8C545B43C2089FAA5C027E544E
-:10663000AA2D3F0C783FA602DE299E35C586E7C10C
-:10664000CAF9FD7CBF1848DEDBE00FB49763790A16
-:106650006D3F4467724A7A8E11E67739E397C26ECE
-:106660000E8608C659736A7B08F86B171F55D0DE73
-:106670001D5A4B24B0C3845D3BC475DEB001EC668B
-:106680002A3FF7B58450882E367A8FC239C08642A9
-:1066900099D9C753CE0C83FE3FAAEE09813F6856B5
-:1066A0009D59775318ECED30B65FDB12E1FB4F15C7
-:1066B0009689DAB7F6ECA4F36F08F9D15EBEB7A5F8
-:1066C0004CC46B11EE2122DE5BCBEC7B11171670F4
-:1066D000D1FE3A0FB63ADA93900D6FC5B6FE61A6B9
-:1066E0006F06EA9F55E9C47B5F7F6B70FD21DE6F0B
-:1066F000EF5F6DF51C85F89CC9E3FE42EF05791B41
-:10670000B34A46FF59E0D95BE68CCB25F8FC99F8F3
-:10671000C53D1F09FB1DEB27F106846F05978B4CC8
-:10672000E3B473FD28EA1E92DE6E5BA6F07D929FB5
-:106730004B997CAE1F594E7C5C2CE87790E3CF647C
-:10674000F22EFC1A8C0728F6F9D83AB08E719A38D6
-:10675000D3C72EF8457F8DF7CF0487E61EEF381D8F
-:1067600067B26D1C179C99E0739F9391779CE364CB
-:10677000D65FAE7E27074787B3FA119BDC633DD710
-:10678000551FE66A5FEC7A7F81EB7D85AB7E99AB26
-:10679000FD3457FDABAEF6735DF5EB5CED17BADE7D
-:1067A0002F71BD5FE1AAFF5767FBF2C59F0EBFFFC8
-:1067B0009FE149C8D5D978493ACE79DD72554C5216
-:1067C000A352B4DC91F3E22278D5A348EA099847B2
-:1067D000C4B7486A82DD8FFDBD11FB1DEC633B3EF3
-:1067E000B6FC512A57BB122F05617F13CF4F4A6F5A
-:1067F00004C787A97DA8A596B3785002E5C64FD4F3
-:10680000B77ACA804A12C6D174A31E51AE97D0E798
-:10681000367DE52551A4B336C2F99C24981C9640D8
-:10682000808A8E17DFA4A1BD171F499263419EF392
-:10683000D8F8D8BEB81FDE492AD34FA168A21A647F
-:1068400078585DD76128DD780A4D8F4F7C9EEA65C8
-:10685000F200F3CB77CD74FAD5D7F171E6ABE7ED63
-:10686000A7BE3249E91F7FD7B78D482B6DB20B8089
-:10687000A0F5F8B7F524C4374641BC8E1D2260BC94
-:106880006E24E1FF785C6E04FC4DFB8D348E62FC5F
-:106890002DDC601E019DF775B514E17A44EA1D0FE9
-:1068A000F3C9592727B2F3BDBF7E82F1788EAFD0EE
-:1068B000BD937BE2104FD9A845C6229E238867EA84
-:1068C0008FB7792B804D187E57C1EECB9EAB815C84
-:1068D0003877E1F400FD4B4B1FF013EC8B2485F56A
-:1068E00000E9C17A36B773CBD4225C7F0EF7330947
-:1068F0008948607F84AE4CEF9747A5EA32F592FE57
-:10690000B8A51466F14969FDF37F9620AE5546C2DD
-:10691000CC7EE171C2B58AF409C45FCDC1D98BA127
-:106920006F3AE94AD46632C7E65F5EAF0A3F8FE14D
-:106930006B4C88AD3FB4516B06BF66D76C271F8880
-:10694000F6EAF9F3C1E60963BE383EC855C764E00C
-:1069500083EB4D88574B718AB7ACC1E3CD54AC6F14
-:10696000AAB84E82E3FE40B26EB0D75562DDA8E60B
-:10697000F7D77FAD4417C2FBF83452D66CF48F437F
-:106980009FDF0CEDD23C6F48D77E1C8FDBD2FD1908
-:10699000F7F152AE03866E3365B0278B3A57F8EDA8
-:1069A000792EA57CBF7EAC739F0FD6BBB5F1DCF60C
-:1069B000D17D2DC8FC19DB05A5EE28D0835CA29201
-:1069C000DD69CEB17FCAF9BBAFBDCB3E9CD116AF5E
-:1069D00086FEB97532817834DDE7D1BE2BE27EEDDB
-:1069E000E6A97149A372F8C0168276726EDB429FE7
-:1069F0007D3D857C3D9B6B0BFC60B76CAF5FF855B4
-:106A0000F413A8FDAFA0DF1B5B07E317D6B0F37E3E
-:106A1000377CF7F2F525EA199EDCEFB334124B27E9
-:106A2000873F55F9F9834ADDC782FE73947B0FDFF8
-:106A3000F98BF174BED22A39E20BF7C339AECF6EAF
-:106A4000EA417C655DA69AEB400F776A0E7B73FB8B
-:106A5000B6FBB7D4C3B91F7D0EEAE0D12F370F8B39
-:106A600052B81EFBDAA2171603DFB7CB04F49180ED
-:106A7000C32877DABB47FAE4CC392F1DB71AF15295
-:106A80007F6EFFE9D3E2630B97F34C7CE2DE57DDC8
-:106A90007C703EFBC355CA675FDF7E90433A6E0150
-:106AA000F7FB86D685A51EA35F8E849F22E629E08C
-:106AB0007C965B7BBF0FF86C4B5D05CACFE9DA852E
-:106AC00012E8934DD0328D9E10F3658227CB93C090
-:106AD0007C892DF5F74BE9F0561863F122F7F36A3C
-:106AE0000FA3F37A352141FF4CED467BB8BEE67229
-:106AF00055C8D7159A9A8A02BE0A222AB987E2EBAC
-:106B000081DA85D5A5C077540E21BE32A386A0BDFB
-:106B10005068B1732293E2EB69BAEF6DAE2791141E
-:106B20006DB7D9D2F01CC62D876E7EDC5C7F6EFD02
-:106B3000422C5B7BCAFF1E8FC1CE734B4809D853D2
-:106B40000F0CE0BF0D16BFA17A99C54B67540CA07E
-:106B5000CF5BCF378E39EFCBC08F33069907E0D2AA
-:106B600017E4D92DB34BF3201E42F50549871FA723
-:106B70007E18081F6EFC5F0CF8BCF08BC3A7FB7D72
-:106B80009E87C70107898FF575C5FF03522633B568
-:106B900077AF47F41379615F21BD0AC8BF051C3A7E
-:106BA00006BC8A0896334814CB636A2CEAA1ED67C9
-:106BB0009166ACD79004968B5593D199E7C188F331
-:106BC0006E753AE3FB719792249C3B93A973F9612C
-:106BD000B06A9DD00986523F49E35711720F8E3734
-:106BE000DCB51F8B38C5D0C6446D051D77782DCB1D
-:106BF000FB1C5EB5CFB18F05B9FC88F1B6560D6EA2
-:106C00007F7ED4B53F3FAAF6E8409F47ABEE69854B
-:106C1000ED46CD7D2794AEFFB84E275E377CDCE590
-:106C20008BA681676BFD011FE48D6DAD4A9F17EB4D
-:106C30008623D3FB7119CE99BEE265E74C5B73F4F2
-:106C40006FB0649D958EBC04A21845F679B77E4C52
-:106C500072A2E7D4274E79D9E8E1F921011200FEAA
-:106C6000CF840F517ED178786C5AF392689AFEA542
-:106C70005E2637ED39240EE7D28FBDA632FEE37AC9
-:106C800078F237C249B017DA414950FDFB5835E375
-:106C9000CFC939FCFD4361CCAF1ADE49E21ADDCF22
-:106CA00086BF5AFF400E6D775F3DF5206DCFEFAB8D
-:106CB0007CA903CE899F7A59C6B8EE645FB71EA13E
-:106CC000F054F17D706BFD4B989F1CDFA646C6A269
-:106CD0007E97883419BD79A48780F7198FCAE85642
-:106CE00079BF2F0CFB57B8478F50FCDC3EE5253DA4
-:106CF0004CCBFB46A47458E7FAAAFB91CFF7D51703
-:106D00007FBD14D1EACC3B99A54CEDB6E87CEBEB0A
-:106D1000D9B95D4E4F4AF7429CB54E255750F8827F
-:106D2000065BEF7DED24798F047030FA4A640EFA29
-:106D3000C585AEBCAE0257DE9B5939EB5DC86731E5
-:106D4000E19C1F16A1343E7011E8DB2699B95BAEB9
-:106D5000FC68A3D27A17F2036629077D907FB5A558
-:106D60004D3571FF738DEB5E874962872D09C789A9
-:106D7000831FB8E541B64F9A138D483C0C5D39DC52
-:106D800026857B089DB2CD09B7C0AB7B1E77DEF5AB
-:106D9000BB829F8793B1A08744BC59C0EFE6DBBCA0
-:106DA0008AE4FE97281C5B5F3670BFDE5AF5D23747
-:106DB0009B609F2FF362DEC457CFEC69FC112D7FDF
-:106DC000F9C70325505E59B8ABB289B60BF07C0900
-:106DD00011CF2B8091D17EE57A8DF30329DFDEE69A
-:106DE000C9C347984771DF111FD2ABB04D4EFA802F
-:106DF0003E6A8A007FE55D9640BBE9BEEBBA31E9A9
-:106E00002250D725C56D721610F643634C82F3FBF2
-:106E10002BEA12B3810F0D9E47684412681FCD54B0
-:106E20005ED431CECEE966723884DCB9E9525A9F1D
-:106E3000D2212F65789B1A0170873736CB202FA57A
-:106E4000552C6FB9B4B34BE279C2984F3F8E237182
-:106E50005CB481E5156E63F817F9DFC14627DD4C98
-:106E60009EA749FD0C19FCEEA24ED7FB680DE66308
-:106E7000BAE95AACF1BCA8529E47C8F1309CDBB3CA
-:106E8000EB1BF9F99CA127CF65CFEEE3E7734761D0
-:106E9000FDE3CE7E3F2983DEBD0AF42ED5378A9CE2
-:106EA000EA40FFED3219FD37371C1B1A99BEDBA5EE
-:106EB000C90EFBFDB3CE7F03D7FB8ADCD301EBFC0D
-:106EC0005BCFDFD8B7FEBFCFFC77FD9DE75FF777DD
-:106ED000C6FF96BFF3FAF7FC8DD75F532639FCB394
-:106EE0001D909842C7FBB157C4D39C7A5B91D3FBEA
-:106EF000D96F69B2239F58E4294EAFB31668783E24
-:106F00002E137BFE8B186FA6F24607E8D32D5C9FED
-:106F1000523D4A205F207B8AC89761FAAF86EBBF5B
-:106F20001AAEFFF665D0AB15902B96877605DE0777
-:106F3000994412E8C7048FAA9867BC8FD0ED05F476
-:106F40005AD89B362FBB80C3EDD6A7055C9F56BC95
-:106F5000E87ACEF5A87B7F2FEA8B9B128C9BFE777D
-:106F60008DEF8F2EBD2AF0B0A58AD9C97973D3DBF6
-:106F700081EB5D74342A9B31FFC04D8FB734E67FBF
-:106F80000B7A2CD0ADD7B5FCCCF4EEE1F4BE9CD39B
-:106F9000FB571AF33F44BE48267A5779D93C9706E7
-:106FA0008E875A6135D16AA483C2E9A490F5DD18B1
-:106FB000F725B713BB5FB9E1636A7F507A6C358CF4
-:106FC000C83DB47E691E9145D2FDC793FBF3893D50
-:106FD000DD2C7EAAE4692E3FCB6DFFEA9837BED543
-:106FE0009293F122B023766C5D0E76C4CBFE08C47A
-:106FF0000BB6E674BE887E5C62920A70087B91F0E4
-:10700000B82C981204ED26F7B993D3DEDFFA715746
-:107010000AEC2EB348C2785F47F8FEBCB4F7F15CC7
-:1070200076BEE10D38E206E48AC1D9EBAB38BDA9E2
-:107030009F98EFB5C5295705664D62E7E6334C3892
-:10704000DF91AC5932C4D1338D0311DE13B6F3A6F0
-:10705000C5AA3512C693C06F2CEBF71B0919C1E204
-:10706000F262FD83BD3FD0B8989D7B73BCE65DD6D0
-:10707000F5B9F88FC2DF17ED0C6AAFA5BBBFE3F619
-:10708000C36B3CD614EF258387FF116038DAFE8589
-:1070900072A5265DDCA087EBD7C0D1AED973E9FA23
-:1070A0002A5FE4717D6AB6D9CFD3EECB53D3F6FF16
-:1070B0003997935FC1E548D4EBA978BE84F92404DD
-:1070C000D625E4D13DFF443EEFC4CF38FFCB5CAEC4
-:1070D0002772B9262482E73099E6ADE67A43949F79
-:1070E00076DE1EBEEE6ACDE471DF73CF3B87AF73F1
-:1070F000CE675CEF493EEF9C41AE77019F6FC16761
-:107100009CF7233EEF8241CE7B2BC7EFAD9F11CF83
-:10711000AA2EF1710687E7563E5FEB679CD7E4F332
-:10712000B60E72DE4D1CBF9B3E239E47F07937B9E9
-:10713000F09C497E777CC6F9CA74263FBBB8FCBA7E
-:10714000F59A983F502847A1FFD6101DC7A6A7AEB5
-:10715000F4B2F94549529FA0DF3A9C9FE74E597E11
-:10716000C7C27479E1A2BD7B3FCE34CF37799C464C
-:1071700094629E203F079D72199D27CDFA44FB899A
-:107180007058909F79FC251C9E25E7B90ED1BE5AF8
-:10719000637A36D3F8777238EE74C13FD0F8A2FD27
-:1071A0009C01E0EFE070749C27FCA2FD8201C6FF09
-:1071B0002E87E3BBE709BF687FEB00F87994C3F142
-:1071C000E879C22FDAB70E30FE931C8E27CF137EDC
-:1071D000D17ED300F87996C3F1EC79C22FDAEFEAC9
-:1071E0009377A7FC19E2FB06115206F7BC47117F03
-:1071F00004BF6F10E9398CDF3758A985F1FE799704
-:10720000FB5E94ED3E1515F1C37796C6A1FDC38BC9
-:10721000599EF2C31309FA110FE7B3BCFCBE7816EE
-:10722000B7071F9E28633CE9E190338FD9E0FED970
-:10723000C3111E2719C1F2988D72719F964E57C0C7
-:107240004DC430E4D3B0FB55C2DE13F7AC56A97C75
-:107250007E8B245B69FF87CB597DEB0C92948B6C02
-:10726000F7AFCA52780F080C5B88C3F6DF1FB3C8AC
-:10727000CA0A5B1EC6CA14E619A83C5F8422843879
-:10728000F2315CF7B6C4B9E135116B26A8B9A24A50
-:10729000768E571475FA0F8D70998BB6FF2DD79394
-:1072A0006665FA7B357B75169715F99A57F3F50BDA
-:1072B000BC55707A6E98F3C7EEE9749D2F4CF5605B
-:1072C000FEE80B47391EA72A49766E4E3CE9EEE3ED
-:1072D000648AB3199DCD477C143FD7BC482240C671
-:1072E000C036AB3D8C71B58F91FF30AE46E7BD66C1
-:1072F0005B4205FE9BDD199E0EF1C0AB5F0CAF82B9
-:10730000EF0A8CEB24110BD0FBF1B7709CDC36122A
-:10731000493252B59A2CDEE78CCF897BBF3C3E07C1
-:10732000616ABB7F399BAFBBA2CD6C8723BB8A1937
-:107330005E87FD3A9BFB99FF64791D7EE66C7E7F3C
-:107340007AB6CBCFECD49DF13AA3333A13E2DCCA40
-:10735000D5C72C1DE08F4A265C4BB921BA498573ED
-:10736000E4D9DB9AD9BDDA0CE75AD90FCD0DD8EDA7
-:1073700077718EFDAB6DE7B6D7459C41C41D5EE1CC
-:10738000F7F15EE679C57DF9289C3F72AF961C7CCB
-:10739000D2A9333DD2097C92FF9F7CF279F3C96F69
-:1073A0007467FCA113DE51792C8DA43F9F6FD0B57B
-:1073B000FF94D72F800E415F7A3A90C66C471EB17A
-:1073C000C8A772E36D0DC79BA8EB19EEBD8CF0F159
-:1073D0007DD6EDD7BF11AB867589380D2177B9CE33
-:1073E00035A746CE159750C4B98FFC8602EB29F31A
-:1073F00071FDA31215C777AD03E5BE00F20D390C80
-:10740000AEF1DA415F78FBD7E529895A12DE1725FC
-:1074100078CE07F9EAFBCA617F341DEBB67C6CBFFE
-:1074200059C7EF0BAD2B5393592CAFCAF9DDA2927C
-:107430001D7A3ABB4294702FD59EE7E186572B897F
-:10744000C5EDF0681C1EF7387333C2D3E0887F9D0A
-:107450002F3CDEF1847403DFAA948B917FBFE51883
-:107460004F2E4B929E7471283E0EDC55C375B9E8C1
-:1074700092697E7D8433FF49CB73DE4F518D5C571B
-:107480007E948BBFFAE242839B4F7CCF6735E783C4
-:10749000367E1FC5DDDFA72648240DDE7D61771E01
-:1074A0004612E9E00D39BF3BE0315D70BBC65F0FAE
-:1074B000CFD2E4DFB8EF57AE5593686FC5299890E7
-:1074C000E7D9CEF9523593782FEB3B3E29EDFA49B7
-:1074D00024FD7EAB96A487DF7D2F48CBCB75D221D0
-:1074E000C3FDDBB542EECD5D16F00992260CFFE739
-:1074F00096F3839173EDE759426F49BF513EA14B1B
-:10750000DAED737D2F6190F4553F1A029756FBEB2D
-:1075100054AF42BC96CA08E6F1BADB1F13F87B638E
-:1075200007C22FF474D636914FFBE9D601B906ECA9
-:107530007CDCD93FA31C723DA770BE7E6E80F567D0
-:10754000A2AFBFC49D4F3838FAFA40EE61DF532D29
-:107550007E88EE94FB4CF31193ADF77CE5FED3C22D
-:1075600039A42646409F69A11889D17DBE309490E8
-:1075700020CE6048BD71F0C7A84C8581CE1BE1527A
-:107580005DBEB3DD34DACF5324C73DD9207F91C32C
-:10759000D03E1E225DD07E7D9E5AB3A3BCBF9D21EE
-:1075A0009128F0BB91AF46E1B9182F7BAA733C6AD2
-:1075B0002628F67B58EEEF2D78A630FF54A376E808
-:1075C000F674FAC4CFECD0AC677D78AF2F1035924B
-:1075D000C092859549CCE32C6C2011F0E74A3BBB67
-:1075E000498C0EBA96C3515899C0FC80C26D093CB3
-:1075F000B7CFF39266D8970B1B13D202DB3C657EA4
-:10760000C6DFD3E6EAB84F7CAB9ADDDBEB0E2D4C40
-:1076100054C37C55ECDC2B90A79261141F8157BD9D
-:10762000CCFFACEC816F49B07C11FAFE9D16525133
-:107630003F9690F75A742C4FB698589A1FFFCF1068
-:10764000E4B7B45F32390CF90867020DA361DFF8C3
-:10765000A02584EFEFFB76240C7944CA91D7F03B48
-:1076600012FDFC1E574815E4BFF658403FDBFA7781
-:10767000F86CE7FC7DEBA2EB5D40E7B957926F84B5
-:10768000F9A0BE10F95457B4028EEF30C333D89727
-:107690009E76127DA21CBE6792946E2DB73DF75167
-:1076A000BB0DF6D74B4CA47B3F3E93AD1CDF13C103
-:1076B000DF2D7C91E3756ED539CF4DD6B7A4BA676F
-:1076C0008CEDAF1B19EEBBCDF54CBBDC4FE7990938
-:1076D00097D8299F4F9F5B3614F0F5A0C7798F5C30
-:1076E000948A392952026DE38532CA21FFDECA8AA3
-:1076F000F1E1A139B6F16772F895233F41FC669537
-:1077000027C477776A0B6D79FF23620DEC3B7ECD42
-:10771000EC7E8C38871C7D7D4F2B1C498C5EE9BC30
-:1077200037338BDFF32C6A9731EFB5680AEA505292
-:10773000D44A30BF6AA712A900FE7E88BC9C632988
-:10774000B02B1332928A6A51DC39CECE45B5CF4385
-:107750001C40DC1B5DD5C6C61B158E1C0D43FCA44E
-:107760005C467B793489E830FE68432670AF680C4C
-:10777000B18D43EB239B9DE3BAE12D0AC8F8DD02EE
-:1077800001CF28B25FB7F2707C92A4FD4750376FEB
-:10779000781AF8DCF38C11ED2EAAA8489134F392F4
-:1077A000DE5638173A6BFE01C66DF1F7E5DF05418D
-:1077B0009F6F93D8FAE32F2891DD40D75BF760BC29
-:1077C00066C48A4EDCD73BFDCCBE5B4DED01C303E6
-:1077D000760A2DC766E643C5A488CBC6FD232DFFD8
-:1077E0003DE6AFDEE88778987FDA46E043BF1ABE11
-:1077F00016E8E13FEA21708EE9B712287FA484D908
-:1078000019F796176783BCF99BB5B4FE5A9BDF83C3
-:10781000F06DF34B2AE48352DEC275A98DE1EFCE01
-:10782000A2D5FF966F3D02F3BC9F1FC3523C0F2DA4
-:10783000AC0B037F4EBFA51CE35FA73B258C7FBD30
-:107840002D253548D15E7A75F3842B283EE6E4C4B5
-:107850001E857E8D75DDCFB333DAE652F0EB6A21FB
-:10786000CF2F1FA68B337F70C45B1115EE838D5015
-:10787000539E207CCFE7C8ABAC8C5703BFEB7003A3
-:1078800086D2335862BD0B7E5380DF3F52486F5C17
-:1078900002FF682A216FD9E8063E9DBD0E67BAF641
-:1078A0007A26FC0F54D6D3BE6F8D855D3E62496843
-:1078B0001724D97710CCC8048053091D2D28B1EDA9
-:1078C000735EBE3EEFF485FC7B4916F76F22C4EE73
-:1078D000DF7AF9BA4087BF65EBEF0939EB8AF9F92E
-:1078E000AE43D8DDD2337F3901745CF5A407E39E43
-:1078F000D39FF4A42EA7F565DB25DC67E4434CAFEA
-:107900007FB04B42B94F0534D403EF9B3AD69BBCB2
-:10791000DD1BBE44EBBD4F2A6407A2A50EBF2F7529
-:1079200042ECA707587D117790966D3F3C1FC66BC0
-:1079300038E025B04F2CFBC92D577D89D66FA17C2F
-:107940000C4D96ED6ED586D1FAE2A4D405F553D34D
-:1079500008F2593C574B425ECBA96077C13506EE21
-:1079600063243C0ECEB7BB0BAEA6FCB824F9C42CE6
-:10797000E8B764AF049154BA8EDDCF1752B8967D44
-:107980005FC2FD71E99E2C12B6E1F3045DCAE5F415
-:10799000FD0ABA4ED087B790C42CA0D7B2DD9B3475
-:1079A000FB3EF75E4B19A67E88FAB2EFD37968BF2B
-:1079B000E53F9422B0C4E590EF00FBE54F7C753BBA
-:1079C0000D585FAB561A8075ADD1A0DD2DC9054F9E
-:1079D000F9C200DF766D167DBF64DB766D5139E04C
-:1079E0008DDC08FBEAD23D1792B08DAE273A15F434
-:1079F0001756E4E83BF07BA286159A9B261EF25EA2
-:107A00000B71C0B584EB0DEAF769736CED9FCACAC0
-:107A1000413E5DBA4771CC23E81F3F46D83DB49F35
-:107A200005F01E9AA09FD8AF04FD56880FE5A9BDAA
-:107A300093D3C103DFD5027812D4BF81F2FE961032
-:107A4000960FB684914E9B018FE3585E0A3CA77255
-:107A50008BDFF30B5AF0A129B88F625543FE656E98
-:107A600094D50BAE8F49E173D8E9A2DCEC892D00E7
-:107A700023676AD6F766AAD41FDBACC56E8590B5BE
-:107A8000A9EE983983EE798D59D1C959B673BFD50E
-:107A9000FC3B3217678571FDAB0B35C4F7E61B263F
-:107AA000EFE4F127DC2737DFB0E851888FD3FE5FA2
-:107AB000C902FF829FFF65EA5F30BFCAD1BF607E07
-:107AC00083E83F0BFBEBE7EEBF79FE65CEF9E72FCE
-:107AD00011FDAF42F88D73C35F70E354E7FC373696
-:107AE00062FF262FA36F6F8E8E79D66DBE48CA03B4
-:107AF0007456097E875ACD2DDD01EDC4BE432D4B52
-:107B00000BF2B68DBD3915EB889D8FA6CD073802D7
-:107B100054BAEC7C945DE577C8558E95EBA80FA917
-:107B200019E6689F1F2D76BC1F5A77818B2F0DBCDD
-:107B3000B78875000A0C730AA7364C437D543D8CF8
-:107B4000D9C1771CF261FD8ECBD8FAEE1866A01C65
-:107B500003CCE097DFA1C52EB67F2796AE4B82C33C
-:107B60009C9B8DD89DB08EFEE761199EFB79BE93DC
-:107B7000DF4B50DFAD299ABC336EC367C748CA0FCD
-:107B8000B4DE96A531BC733AAC19B92864B7D7579F
-:107B90008FD4EAC0DF80E73719305F7435CCD7A4C3
-:107BA000F59682DDE19EC75B5CE598471FD580F3C3
-:107BB0006CCA62F154318F7754836B1EBD6E077FA0
-:107BC000CEE77900F82CD33C6B8A2F73AE67D412C2
-:107BD0009CE761D73C6B462D71CDE367EBA1CFF9F4
-:107BE0003CC973CDE31D33D5B99ED18D38CF3FBB92
-:107BF000D733BAD1358F81F3C07398871ABE61F835
-:107C00003E96E6ED5D84F47FC687768EE68D3D86F2
-:107C100076CEEB3EB473682B0BBFA355C6FCDBDB03
-:107C2000B272913E67FC94FE869DCE719E7710479E
-:107C3000BFF8660E22495288A87E5BCE79B07EEFEF
-:107C40009C51AD501E981E5A00FEE883018CE37DC6
-:107C50007060BA76531A7D7473C273A2C7C6CF7DA3
-:107C60007A95C7634359EC1C52D44FF0F8CF5B10A0
-:107C700027A2E5DB1E82FED0711E2FEA87B715FB17
-:107C80009DE0E77A27B6B17DEACCA663ECBB3971FB
-:107C9000F272F964F81E0DFB777322CBE18F377116
-:107CA0007AF4FEC49BDC81F4B086E3777F3B8738AF
-:107CB000E285BF39F4B5E759DE1D190EDFCBBBAE47
-:107CC000E389E7A0D92BD282912BE87AEBF66FF209
-:107CD0000CA7F50F3C3DF323866D9C3A0FDEBB17D6
-:107CE0007EC837621E87FDFCCD0667FD06973DFD09
-:107CF0004656B1389F65F386931EA0D73C3863A5DE
-:107D000024BC014A4CBE33915EF34DD657C0D374A8
-:107D10009787A470BFEBC9C738673C1FE33431B104
-:107D20006FB9E09BEFD1AD28A5E7FC3B15C4A31BC1
-:107D3000DE9E4359964CFD9C9ECEFFED81FB3B039E
-:107D4000C17FE34AE77B12F738BE4320F8E0DABA96
-:107D5000EA9DC76DFCF18DD8EC9DC71D789AE3A80C
-:107D6000DFD0FC0D47FB1B572E70BC5F105FEC781B
-:107D70007F53C7AD8EFACD893B1DED6FE96C75BCA5
-:107D80005F9C5CEB78BF74CF26477D59D71647FBC5
-:107D9000A603DB1DEFE543E3FF09FDC05F2978CFB4
-:107DA000F943E3C406B0DF3E34D977FEDFE1E7777D
-:107DB000EFF1EFFD2C07DE9B02F2334907BFA1C9AB
-:107DC0004FE599DA12138CFCD51D53418F10FCA49A
-:107DD0004685317C759C3ABB53F8BD44A55323A915
-:107DE0002170BCD21F87ED55FADFAB3DF4FDA4CC6A
-:107DF000EF954E35ED7BB5474D3BEE29A9B714EC19
-:107E0000C7F86BDEB4F7BFFBE5920C87FD22D3FB0E
-:107E1000933269B0FB6FF30C161F7A3E6BDA3C03AA
-:107E2000FC218DC97BE3BEC269E037346AA9D274F4
-:107E3000E7367DF37549F89DC079069397C549E704
-:107E4000F76F97EE19E390FB57FDB16B0CDAEEE498
-:107E500061857D2F2FF5ECA8AF5F04F35BF3E0396C
-:107E600039908FFBE32B2DD6CEE3D40F78B5A50642
-:107E7000CB7F6D89EE3C4E1DB5375AEAB0FEDB96DE
-:107E800018963D2D0D58BED5D28CEF8FB7ACC4FAE5
-:107E900089963896EFB47460F95E4B02DF9F6CE907
-:107EA000C4FA072D492C851C087B9744B93D290E3F
-:107EB0004C08AB9FE66B500A441C3382DF8F3A6D4F
-:107EC0009C29053BFAF4AB5ECCBBCD842737DF653C
-:107ED000A69F85FBFDA2A433CE2C4A9F9FD1C72726
-:107EE000931AC891583B56C3389AFF990BD11EA7D5
-:107EF000CF55C2BEB71CB17F4FA26F7C481E1E3A41
-:107F0000309D44FB13DFFBF7C90BCB813EC58827AF
-:107F1000FFB34A33A3DBCEC8D72F1A187F68F315F7
-:107F20009E8D47E999DF8C82F8D4FBF9029FDDA38F
-:107F300020B8A51AD12DC087A7F77B715DA70F6662
-:107F4000B17C1408AA0D22FF75E91E5FD2AE1F9600
-:107F500075E5249DFAA23069D717A78FEE0C82DC55
-:107F6000AF0829C9E393803F2CCE1F8CEFC4F8CB18
-:107F7000BA8A9286631C67FD7442AAE9C2B858386F
-:107F8000FBEA34FE87285784349CE7BD3D6330FF0D
-:107F900080FA89C9E32CDE9964F3869276BE6C5C24
-:107FA00099953C3EA41FBE4CE37EDEF011B29FFCCF
-:107FB0004ECF7C0F77A092A8FFA6E1F72D0F7ACEC7
-:107FC000C0BEE3A5FF7D82F9422AD6C5B84D5D4A01
-:107FD000DC0BF778C95EC77CB45F58F8E8F6EFE6CB
-:107FE0009C4D77673EF86F819770DF66F7CA6370C4
-:107FF000AF9C8E774A353AA48BFBEF953771BE5C08
-:10800000A6F76831FAE8FDFD63CE990FF25ECB5119
-:10801000531D0B790409FC604443D7F819A01FDFF6
-:10802000DFBFAA00E2694B95D377A4BB2FFB91C1B8
-:10803000E26C24E9E9EDB1AD47C46708A1E3EAFDCC
-:10804000F003A79FB0D5DDFA5A947280C5DD97EF93
-:108050003D36EB4B14FEE507FEA8011C078C981C6F
-:10806000B0AD5FE2F7EA97EC795383F5BDE389970A
-:10807000DE750E3D75369C46C8711E1A27DD20C779
-:108080000BD96F30003F5DFB3A15CD777FE921F0CA
-:10809000BB0EE2BC42DC7BA827D120E06BE1FEA551
-:1080A000181F7EF7A92BB93D97980CFCF13E916BF8
-:1080B000607DEF939782936CF82B09303F86743084
-:1080C0003B46DC0BA4F6ACC3AEB9A5D3595F44E67E
-:1080D0001680DE58F4A007BEA14A1613DBF797E816
-:1080E000BAF302CCDEBD8534AF067B4EF532FF60BD
-:1080F000A149D4E1549F2EFBF14393C1EEBF30C0A0
-:10810000CE1D451C63712EB3F796E42535384FF824
-:10811000DDFE49F3BE04DCE74DAE867D9964A73FE2
-:10812000FFBBA9C309DF40F0BBE115F7DDCF8AA78C
-:108130007038943D52DAFCB42901CE775C8FDC13A1
-:1081400070DAF96B5CF5DA008FB32A44013ABF6F3D
-:10815000EA71391BDFE3FDDAF83E6F645518BEA7FC
-:10816000158D027F51BB6002B1B5FBBD11C3E7277E
-:10817000A51717E1FD72353501F3F174A2DA7F8F8F
-:1081800041F10727908B214EDA8C4EFD2A5F700754
-:10819000D45707D83DA8269053B83F1D9C7514E2CC
-:1081A000FA3A49A4AC2238FF76C6BF7D61673D0B21
-:1081B000E409F4093C007A4408C68BB2CA9CED027B
-:1081C00011677D491F9E528AFDDE47503752F87B6A
-:1081D0004D55EA49BBDDBC5C67F013F89E2A6D7F04
-:1081E0001BB7E79793701CF316438C0F6E9BCDF271
-:1081F000266E0B84F15EB2A45A783F620D74B5ED21
-:10820000634D1F492469D3EB4D6AAF067CD9F491C5
-:108210008ACF1F3662DF06BC6AC4423B57A7488339
-:10822000F36BD5A871D8BD6404FF2EA02B7F617DB0
-:10823000C074F87B422F78B85EA4FA624D201FF418
-:1082400060EF2C76AEDEA3B1F31DD64EEB6FB71EFA
-:10825000E0C8D4CED7DF6E53BA76CB7EFCF853712C
-:108260002AEF4B7EF49D201CA6BDAB260A20FFA161
-:1082700071777B10F8F81D351E8475BF9B4C9FF7F6
-:10828000FE73AEEF20DF09EEC92FE7747AEF07F730
-:108290005E05783FB3DB83F7EC9BF678535E4AC408
-:1082A000E5FB17337EDAE37D93D5D7E0EF2E341D5F
-:1082B00070CADB92C7BE5310C6C3BD38F31B490A50
-:1082C000EDE7E5BB7E3F0BEC9126D28B7AC2DD0F4A
-:1082D000E6FF2817F7AF0570DFDFFD5EE45B357161
-:1082E000BE6FDA7F2FE65535ED9F8D79544D2E39CF
-:1082F0006FE07EC88180F37736043E4892D9C5ABE3
-:10830000BEFFDD096F52784EEEFA655072C48F9849
-:108310009E38DD75D3234F8733EBF70FB85FDFDF70
-:108320002F89FDC207981D4F0EB2B2D1930A82DF8A
-:10833000D4B8DD13A11A84343EBEF3D1EF017FBF60
-:10834000E6C578C3D2C79F7BE5325A5FFA8427AF70
-:10835000962DC3803C604117B8DB0EF9BA820E4BF4
-:10836000FEE5392D7C117B7E776E3F3D963E715840
-:1083700023179D8DBFE95D8735FC4E909B2E5D6F69
-:10838000CE02BB7BD5F7FFA4817CBD7B4822438B0B
-:10839000CEEEDFB0FD39B4EB004F48474EA73EBAF2
-:1083A0009D45AFD4554F57623B13F6B181E8F53D7B
-:1083B000E0997CE4EB1F3E0DE705FFEA8D001E1AF5
-:1083C0007EF8AD20ACE76DB599F1F743ED05708E01
-:1083D000DEE089179858B2E70D0FDF8E7C77CBB1BE
-:1083E000DB0B581E9455C87F17A010E380DBAEC18D
-:1083F000752E2231E4BF868794289C937DA8929A9B
-:1084000027D2C8C7E541A6C7DEDEE1C58FDEBD0DB8
-:108410000A17FCC5979424BB6FCBF2126F17E71EA7
-:10842000F0DD465AFF5067F4CA0FCAE27B56BA83A2
-:108430006F77ADE9063ABD37D21A0AF14A8A873812
-:10844000C79B047A4839367328A31309AB93793F45
-:10845000AA27A7C37368DFEDB17C131CFDF8BEC665
-:10846000E6BF8DCF4FE1F6837DF67601B577D2ACCE
-:108470006F6950C83FB53F6C7C66937326F7BBD6D7
-:10848000323917729F9C5303EFFFED652647D00FDB
-:10849000F6790A576A28BE3F7CB5847AC14B52E907
-:1084A000E47B9787CBB7F33DF5CAD1BE157C42E19B
-:1084B0005761DFEAE71776CE4BE980F6DBA2076962
-:1084C0007FBB7D0EF3623BADFFB96DBFBF85EB8314
-:1084D000CB82AEDFDDD9963FA8EFE4357A928F7E6E
-:1084E0000FE497CA2BEC3F8D8F7B304FE40F7B9FBF
-:1084F0007DE53ACAE77FE81272EBD4A76EB96DD872
-:1085000077094927B77F302224ADDCD2E769E5D669
-:10851000E8417EFE5BE95381BF8541679E93D08F22
-:1085200099F0E8D68F7F0D84D9EF22B8F423FDF7B8
-:1085300032997C361F0AFE137CB7E49F97E1EF83E4
-:10854000F4F1A7E0BF3EFE14FCE75EAF137FEEF749
-:108550001782A122E2C5B4F4DC43E20188A7FE4CF5
-:10856000C178EA290AD36A4AE7537B8BF01E71BBB4
-:108570008FF9E7A7CCDE606E397EFF06EBBDF9DA36
-:108580006AD017E279AF8FC5BF4F457B83F63C9029
-:10859000370F2A4138EFEA49929A74FE08D5C80885
-:1085A000470FC9F49EC58B4F81FD07F3F94725811D
-:1085B0006E331563D44AF0F313ECBE7C7DEBB5410A
-:1085C000C853387570CC46D05F37BFA010FEBB854E
-:1085D0002AE49BDCC4E9FF0E896F9E4AD779D34118
-:1085E000E657D4AF4FCF2F4B78FB45C66D1AE82521
-:1085F000EA17BC658F872FE1BFC7D4B0CDF5FCE08B
-:1086000095C8574B5C7C15E37EE3E382AF269289E5
-:10861000DC6F93EDF96C3395F28D60979C3ACAE26A
-:1086200090A70F2A488FD37B2596FF04F1E029C03D
-:108630000FBD9A3D8FED24F05F9AEF1BF4BD7FF2E2
-:108640003793EFA24D1A9F7A7DC2565A9E7CEAB5A7
-:10865000D29F42FDC7BF1EF53A39BBFDF4437FC62A
-:10866000F3EC5387BC08C7A9433F1F7517D49FF687
-:10867000E2776A4EDDE365F99F8702C9B1F07E2497
-:10868000CB175AF5B33F4D60DF7F6943BABD1A641B
-:10869000FED8E983FFFE5BC81F3E7DD01B86753484
-:1086A0001DCAC2F3ADA6A77D18A739F5B33F4DB6D5
-:1086B000E7337DD6F52CE7DF413C15207590A77C8C
-:1086C0002A879D1B34FD74CA4EB847B46CFF610DF8
-:1086D000CE63A63FF39709A0774EED63F6C4079EDD
-:1086E0009E87E19CF577C11BD77820BE0BFBF53048
-:1086F000425AB29357C48D747861783845F100EBD3
-:10870000A27869007D99091FFFE71F161F7F9C0F44
-:10871000F3371EBC14E5A61F2F92C59E079270B5B5
-:1087200089AE9F3D3FF4A709601FFDA1AB15F7F986
-:1087300081D65D98FDFFDABAA5D460D65DF50FBB92
-:108740006EC6FF87826196F7E79283B3F9FCC7771D
-:1087500060FD878108C23B48F9AFFB875DFFA7A496
-:10876000FB3E4AF7E0C074FF2FD9EC5CF81F6FDDC9
-:1087700003D1FD054EF780097908A77EF6178CAF67
-:108780008BF50FB4EECDFF41D72DECA175722451BE
-:108790005C0479D8A9EEB004BFC3333701612985E1
-:1087A000E75DBBE17A3E9BF9178AC4E23664248B0D
-:1087B0001F11EE6FF4FD5EACC1EE57A9C66AF63D1F
-:1087C000323582DFD55B77C1C208E676908A57637F
-:1087D000501F31157FE7D6ED77B549C492A8FDA7A4
-:1087E0005EF0D5A360FF7BCAE4947702966F42B92E
-:1087F00086C7BD3CA6E6F0370C979FE00B3BDF7BBE
-:10880000F9783AA948C0EF77EB866A26E9FC463545
-:10881000FBFD68C8ED4CD8CE0DBDC4D69F8EB70306
-:108820007E93C5664F9E2FFEFE94CDFC4F45AAE871
-:1088300086BC58325E66DF3527EC5EF1BA1191E4F2
-:108840003AF443997FD98FCFD5DD80479550FF907B
-:10885000AD0FFD4AC2FD49950FA196C996CFD98E9D
-:10886000FB4B03D287D1635423A7CF0A073D04FEF5
-:10887000D3D0C5410F81DFF3A58B9B1E6EBCFF22B9
-:108880009BC5E7DC7472E483E433BF24450DE49FA9
-:10889000EFDD897191F77FF0E655D07EE94F150243
-:1088A000BF8BF6C1DE004981FCAA490DFCAC25FB5B
-:1088B000158C0BFF5F8242FCFF008000000000006F
-:1088C0001F8B080000000000000BED7D7B7C54D561
-:1088D000B5F03E73CE4C6692493249662633793103
-:1088E00049208246980408A82813020842AF038A48
-:1088F000606FD49167304F90B6B4D51F0389313C77
-:108900006C83220F4B7540545AA90D182928DA415F
-:108910001E62AD5FA3D25B6CB137E203150829ADCF
-:10892000FDE8BDF672D75A7BEFCC399389686F7F2B
-:10893000F7FBE7CB3F27FB9C7DF65E7BBDD7DAEBF1
-:10894000ECB97409FEC63376495C196B66CCC55820
-:10895000EDCF5319733276CF9EA4C8F442B8EEFD22
-:108960006038BB9AB19E55BD4773E17EF8A78AFF78
-:1089700029EC1EEE1E7E0BDCBF476377054B63E3DD
-:10898000C86BA6C3C4D868C6CEEE4F9913B133A640
-:10899000EC3C78278DDB31DB9CA4C4FAD91C669AA9
-:1089A00017FA05F079F8274A6488D27F3CC656F258
-:1089B000F17EA270F8F6992336846FE7364B08E013
-:1089C00068DCF9274B00E0A8FAF9CFD2BA61BEC63D
-:1089D0007D2A8B0E65F47789E173359A349CAEEF6E
-:1089E000E395B1805DA960AC01FFF5C1B5B37E3AF6
-:1089F0004B836BC7DA3FA969F8BEF954B735F67EE9
-:108A0000EDCF5FDE1B06D4D43EFF4C9A0FAE9F75B0
-:108A10003D95C64A69BCBB2DE98C6976CDD01FC790
-:108A2000BD98D97F1C98973137DCE7B75863C76A80
-:108A30003E5FE7374E33848FC138126E58DF67F8D8
-:108A40008F97B1B18E54E7C757C1FF63D8984B2AAF
-:108A50005C776631764D7F3CC5F015E6F4FCD9E7CE
-:108A60008F87013F67F79C791CE1AFFBAF3F3FFE6B
-:108A70007DC01F7BC5E6780AD6DDF8D3DFA6217D51
-:108A8000E57B331D0ABDD793CFC25EE8D7F36E52A4
-:108A9000240CB77A5E3E5DE083F5F6ECFE9BDB07C7
-:108AA000FD97BD3C291BD7BFEC85AA6C661F188EAD
-:108AB0009E158C4592F47045888EBE7D30683634A4
-:108AC0000F886B1C3D0E751E2A4038CF9D48F2273B
-:108AD000219EE0DEF272A40FD069386FDF07F86DD7
-:108AE000D8F5E09FD4E189F01CCE357990AE1F4CCB
-:108AF0004638198BE6320FE2B7B7D561EFDFBF8F8B
-:108B00005EC7819E23BE02DD76ADE6F37600DDD240
-:108B1000FAD3ED1CFE03F46944BAA5C4E8F6390B98
-:108B20003DE12D86766716D13511BEA25F015F3516
-:108B30000A1FFF7A47E07B0E949F3D297DF49A8EB1
-:108B4000F4FAD9E7050CE8FD89B9F74E368AB1DEAB
-:108B500097931CDBE1FE3D2FFF8EE4A4E785B72C45
-:108B60004847F8B32BB0AE1ED6F7D785EB6C50C490
-:108B70003A77A44693D262786F88CC98E24BA3FBF5
-:108B8000EFD3FD08E75FC45F2ED22772F0562501B0
-:108B90003D3A1C45B40E1671D1BAEB77FCC1827C0C
-:108BA00023E984F451C622BDDE9F8CF7259DE4BAEB
-:108BB000E3C773201EC6E8E8B683CB617FBAF65AD6
-:108BC0005871227A01BCF81EC20BED9E6D499A9233
-:108BD000CEEFE7C13A7ACC6C4E07C211517E97882E
-:108BE000BE8CADA2F53C1B2F97627D9793CBCBC17A
-:108BF000FD8FE2E5C70E078D2FF173F68BC4FAF9EE
-:108C000028CA39C0BFCF1E3A82FCC39835F2218CE6
-:108C1000731753587A710C6F12DEB31A23BD7BF6AB
-:108C2000A76A240CEB6FED38447A365EBE615D8135
-:108C30008E04F3FD4ECCD7B0EFE070D443675FDD18
-:108C40004FFCD7B0EB7D4B18C639BAF3794B776937
-:108C50008CDF517F4774FAFBEC73078793BEC5F135
-:108C600013E89B0FC5F88D078CE337EEFA9361FC90
-:108C7000DA7087C561BFFC3C9F6981D9B8DECFBA85
-:108C8000CC0CF5DF671DEA944882795F17F64BE25A
-:108C9000A9F52D0BD9B1516F274792004FCBDE9A22
-:108CA000F28774275E2D3E402DEB5CC9F9AAF3FED6
-:108CB000402ED2A5F3AD6FAA684FF6221EAF888D65
-:108CC0005B71BCA92A15E4B6E2647014B255BC3ECF
-:108CD0001873C264801BE6C946FDDC02E3F8601C21
-:108CE000A6F93D4118574D9B3C05E1511D26872DA6
-:108CF000A15DE5E399ED411602B8CC60B77D3A7EFF
-:108D0000F2CC4C1BCED271795E13EA85A5C05EA869
-:108D10009F3D16365403F89829D9FF148CBB74581C
-:108D2000A0EC08B4972EF0F8C3F0DC7B0B7FEF9C2F
-:108D3000C31E368DC0764104E528E5A2CA7CA0FAA0
-:108D4000CE2ABF5EC84025A408BECAED48213B9389
-:108D5000A2F93655433BA546F30346D947F6507E64
-:108D6000860BDFB3D07BDE0C45FB18D79DC6D250F7
-:108D7000DEE4F8B29F1C9769D1E1B87E66651A03FC
-:108D8000BB92C738DCAA584F31EB5290BF9B67A407
-:108D90006DC7F6D6D41AB2FF05ACF76000E8F664EA
-:108DA000DAE463A8C7E05F13F6CB6F32DAF741CBA2
-:108DB0008DEDC2B01627BF3E5310F8AFB8CD78DFA7
-:108DC0005955B964901FE46C7DE7140DF4B77376C0
-:108DD000E5EE5CC0E9B4356FF3F63395655E681F68
-:108DE0005F5F3755033DE2FC4D655901B4CF3FFC51
-:108DF0009DA9F4BC1690742DA8FEF5574F0D97C68B
-:108E0000E4D60560A6AB24CF37201ECE05CFB6E250
-:108E1000D3FA597FB5C023FC0B221EF2C7723CE483
-:108E2000D94FEE66D07F90A97B25F2E5132FFFDFA7
-:108E30000CECE7630E5AAF83B5383EB6E2E2D9D800
-:108E40004B23BF4C9F69EC63C9876A4C0E5477E88B
-:108E5000E60CE0ABD6B943374D465D5BE727FE82B3
-:108E6000991D640F657F8793E8335FD007E1B402F3
-:108E70009F2DE05DD822356C61346EBB2548F66AC3
-:108E8000A203E753C275EAA5ABBE3E5CF3907F90A8
-:108E90001EA92C15EF6B753E82EFB02BB090F0E65B
-:108EA0000AD155DEF7CC9DE30B019E6FC808D6E0D2
-:108EB0007ABC0B2F16E03AA667301AAF6A913D8054
-:108EC000F6F5C201508309E44B5EB7AF607E6DC812
-:108ED000C0CF8399A16FE3BC45BFF4ED3906E38DA4
-:108EE000986FF1DB608A11CB47F9B52CC61784FE69
-:108EF00087A09F07698AF2F76D1641F93B9FA4048A
-:108F000002D03E7FAF83F473DEFCE9C7D0AE9D4F45
-:108F100029EC88E2FDEFFB482EC11350502EF20FD2
-:108F2000A4476D69C4D77F8DE3EBBF1AF9D838EF3A
-:108F3000F94BBE7DDD349E438C078E113CCF17F478
-:108F40003AAF72FFFCFC0A1FC1016EE441B4BB5F83
-:108F500075BE4733843D15F4B9DF16D8887801FC17
-:108F60006FD6E37FEBC0747C42D0F18944745C68B7
-:108F70006D2A40FD704FB06332686E362323B40310
-:108F8000C73DBDF068AB19D6535FDD54824CDF9FFF
-:108F9000BE0AE973F781BB579AA1DD88F4F1F5A702
-:108FA000E388E565442F1D5D3B108E1107FE64428A
-:108FB000B8253D3729DC0EC4BFFF528622E6AD5BE3
-:108FC00069063C5ED86721FF37BEDF910C1FF59321
-:108FD000EDE1D60ABF06729A6D62A144E31EE9373D
-:108FE000AED59F9400FEBEF11C7C3CC0FB6B7ABCEE
-:108FF000BF21F56F7FBCFF1FEC0778A7EB57C0FBC5
-:109000003B5F8677E96FD70ABD50CBD6919FF95168
-:1090100060A67B30CC3B59B513FF2F7E4A25B98320
-:10902000FED3BDEE981E597C4DD3415CE7E21F2B69
-:10903000C4A7F3435CBF9F5938FD28EAF505ED4608
-:10904000BF69E11CD03300DFA2CDC6FB8B23717159
-:1090500020D3E973E08733317E1DC4F58C87ECA4FF
-:109060002AE4A16A51693AFA49AF987DBF213FFCD1
-:1090700075956D4F80F7FCCC42B2C37DED264086DE
-:10908000CEBEB3F93613EA4939EEC445A5D9E8CFC7
-:109090002C4DF57D69FC3568B9D19E178693994FA3
-:1090A000376E715BA6A13DA43DC7D0FF8ACD458632
-:1090B000E7C322571A9E5FB5B3DCD0BEBAE35A436A
-:1090C000FF11FB2618DA65D19B0CFD471E9B6968D2
-:1090D0008FEEFAA6A1FF9813730DCFAFE9BEC7F0CC
-:1090E000FCBA4F961ADAD7F77ECFE8BF9818E94551
-:1090F00096AC909E3CBCE2938A0F910147291311D4
-:109100009F556379DFC34B2C26471A5E4B4C0EE00C
-:109110008F57174C27FB7F78893BE0A36B4500E313
-:109120001EA68E1B154AE0DF4E727C5AF1A16EDE40
-:109130002AABD9A0D726398CEDF24C11170EE27C60
-:109140003326D328576AD3F4A8059A398B0767E3E7
-:109150007C205FD76672BD46D7AF205FE3B1DFE901
-:10916000B4682BB6A57C31615F2B051FC135602922
-:1091700047864A253B1CC09B3EBA1FD6203E9960BD
-:10918000F5E71DC1F598FC4E64BE89738287CD9CBE
-:1091900003B91D66434D5FC70E4BF9F6987C61B26B
-:1091A0005F998CF2495B1694A4331D5EE764F2FC70
-:1091B00011D87D7E75EC1CA949FC15E9EF4F19AD5E
-:1091C0000D8DDD57164DCF4679F30CA0072D9EE28D
-:1091D000613B40FF5ABC857495F75BE798A6441243
-:1091E000D0B536531170703F6B58CCCFAA257A7822
-:1091F000DEDE3804F0D550DD4B7E96C7D4BEE428C1
-:10920000AEEB572ACF93812785FA6081F09B174CEC
-:109210007D78C951D04B0BDE1C427A49CEB37545DF
-:109220007498DE3FC81B208E7A3A93EBF1C757043F
-:1092300086CD1F4270915E907E7941B87E32C637EE
-:10924000835813C5891B4DAC26D1380F8A71B29152
-:10925000E408AFC34EF2716EE1C9340DD6919C1A89
-:109260007A10D737774457058F0303FE99E07F15AF
-:1092700044EFD888FD0B3C1A8B28FDE7CFAE0EB526
-:1092800015C2FA5A324D7E3BB57B15EC9F741F63B5
-:1092900059D0BFE5BF5482A7E5D56B18C66749F61C
-:1092A00026867EAC5CD7A1CCC7083F6A670AD93D49
-:1092B000862E28E0EF5B82F69F7BE677A17FF1F9AF
-:1092C0000633CDF739ACD101E37FDEA946D0593F53
-:1092D0009A991C35415B6D4B257B5D803E27F45F81
-:1092E000D8991AF115C6F0A26D1EC7A260DF92F2DE
-:1092F000F8FA5B32ED117B21ADFB8799A36370CA4D
-:1093000075E70F1077BE22E06681A1063A7B210641
-:10931000EBC2B93570F6611C758399E2C205197606
-:109320008233B2223C6CBEB9FFFA5A3D336FBE1D88
-:10933000E0693EAE3215C6F175B7133E16023E2205
-:10934000BEFEF83EE72BFCAB4925B85F417AA99BEE
-:1093500027D3BA18FAF1F05EFD130A7BAC10F9328C
-:109360003485E89C63624F1526F00F50DE5C883F21
-:109370009E3FB0784AB89C78060FDB01E3FD2A7364
-:10938000407FEBCD4C6EF7E91AAF97C0FE85118E8A
-:109390000B9B15A2E76925623103CA6A6F8D1AEC2F
-:1093A000BE1A50C9DF88870BF4D8894C9D9FA3A6AD
-:1093B000DF371CC71DD83FDB7DD082FE9983917FAC
-:1093C00026F5E740FE19FA65C87FD22FFB384E0F0D
-:1093D000C3FA3E15EBFB34D1FA12E8DD1ED2BBDF37
-:1093E0008C26F46B5C96C47A29378BEBBB46878559
-:1093F000511E6A80BCBA2B4BFA71DCAF1848CF5DA6
-:109400002EDE285A5B4AFAF642972F3D13AECE0F56
-:1094100094A644E3A8CB9F1D8974596CAB4CCA0237
-:10942000F8EC5946FC6C59DDCF4EA567717CD1B57F
-:109430001FBEEC802F93015FCEAC2FF503B9DECDBC
-:10944000C1BC14CCD723F003FAF722E9DF5B7A6EB4
-:10945000C358B1FE962F449CCBFBBB859E8638F843
-:10946000868F7CD4FFCF48BF583CDC5D817150F3C0
-:109470000B57A4A31F3571EFED0EBC5E700E26BC1A
-:109480009CDB9B14C079CE6582FEB4637BCC51CC4F
-:10949000139C59712C538FD773CFBD55618671CEF4
-:1094A000ED79AB42C37C83C8A7C8E7F597DEA9086E
-:1094B000C2FBE1096C68935D475F2BD7EF1B6C3CE7
-:1094C0001FE1725B5AD908F06B5D19F4FEA36ED3ED
-:1094D0000FF0BE6A7DA7E04394E7B8FCCB06B3AFBC
-:1094E000D90E7C0E31961FF3F84B8705BC0B30FF6D
-:1094F00032C34379936685EBBDF0021E1F3A8BD8C9
-:10950000D04218CF6C52557CAFD7CBFCDBA14BD2ED
-:10951000E1F628AAA9E4AE8E00823F2A3993F07EB4
-:10952000DD598782FEBECCD768557CBCDE5996C813
-:10953000765D9EC63347233B96A27530D4ABB35CB1
-:10954000FC7D99AFA99A39275889703D60A27803AC
-:1095500014A582FA2B57ACA3D0BB67B5F4453437BA
-:10956000B215C3E40C5B0BFC3B18F09CE6330530F2
-:109570003F9A96173D61063F2CB785B1533A7F2F2E
-:1095800005990FD7F3A61AD90EF29FFAC578EB1CEE
-:10959000F0675292B9FCA4055B9760DE1AEFFF6B8F
-:1095A00039D285BF4FF451318DC4C2E90072EA58F7
-:1095B000E3B8927E9D2BACFEC1C0A87B5638E8FA7A
-:1095C000F40A0FC1F5F00A1F5D7FB86228DD1F485D
-:1095D000CE2E777D6805CCABE327E718C00AACD761
-:1095E000A93292C7874657A4CF4DA007E4F5B1151D
-:1095F000C7DC13870804023D72EA1CDBD614129DF7
-:1096000051686075AFAD0E8C63EC0173600903D6D1
-:109610007A20EB8B8998575AAB98288FD49A75701B
-:1096200075380FAF3E4EB743EF32CC477A47B52B74
-:1096300028AFDEBA76E283515D5D2C24EE07A0ED03
-:109640003DCEEF3F60E3785EC7D81484D7AEB0203C
-:109650005E7B6CDC9E7C6CE37AED53712DCC0A3D15
-:109660009C05F7FFE23851F20080672BFD7D01EE8B
-:1096700047A41CFA1BE56BD5E1162BCA87F7C0FB84
-:10968000B44FA19ABA2D0C4CE8F38FBC4BF92FD5EF
-:10969000122CE4ED9FAFC175B8D282DBD0C562E178
-:1096A00077A71EF680DC203F5C4BD808A31CAFB523
-:1096B0008976F8DF080F6BCDBCFDFC23BF5D1DA6CE
-:1096C000767031E205DB2D88978C0E8F09DAF695DE
-:1096D000EFAC3E763DB665FF77A8FF7359DC3E32AE
-:1096E0007BD08BFAA3AFED80F6D5BAB6C6DBCCCA79
-:1096F000AF727DF587FE763417F8B5E180D281A090
-:10970000790FAC57709DDE7DEB09DFF407F281CB5A
-:10971000A03CA6354C79AFA7571C73B4009DB5CCBF
-:109720003637E2FD0A4F281048A0AF7FEE92FE2A9E
-:10973000F4D7E7BF22E6DE6E9DFFEC655C6E580B4A
-:10974000E88704FE4091ABF23D27AC6383125AA335
-:10975000A29EF999D9817A8475713D74568CC5227F
-:1097600039E48FD4D978D3BC2AB46618EA893B345B
-:109770003FC6B9B585ED95688F6BF717FA57B218E4
-:10978000BFD46674B8CB917F328CED669117C9CE89
-:1097900068CAC828C5FD82F50598CF6F60ED777E51
-:1097A0000FE1FDB5CAD0AFFEF4E035E9D741BB1EED
-:1097B000DA68E7EB3BDFB2207F3EE8E4FAB3A113BF
-:1097C000F807C65907F21500C7639BE64846FDF443
-:1097D00074A0E94A74C97A1FF9CB541B3875CF14A9
-:1097E000051C446FE7A5D5566C5B1CC35819B62DF4
-:1097F0006B90DF6ACB4C5C8E98E557014DEC4F4285
-:10980000FBB78F54DD14B6C7EC8D57D8A7C6ADF69D
-:10981000B089DBA7F368D71A369BC2A8BF4CD62EF7
-:109820000BD2D78E7BAF441F07E16D99D4E771FA55
-:109830007AD9D4CC9BB0BDEC812247F84BF28A3563
-:1098400017535844E7CF3CE8E4725CA385699FA3B3
-:10985000E6621A3DFFE7CD676391915F369F9D9E5B
-:10986000CBF9EA62F3115D0F95FF6AE360A0DBB20A
-:10987000DD6653928EEF96ED16FBC9B640368EE349
-:10988000B2308177F0CF01BF5A615F3BAC819C3F22
-:10989000D427E7DE3513C721DD62CFD958831E08F0
-:1098A000607CF850B2D4038589FB27C7F52F92ED71
-:1098B0002BA97F3C3CAEE458DB0AFDB5BF27F5B5CC
-:1098C00011BEF5A6B8F132E5FCE56B26E6C5F8EA6F
-:1098D000B759D7FD2A3C189E67B457627D45EF0201
-:1098E000E643BB8CFCEAD7E9FDDF0ABFAFE662B115
-:1098F00081DE31BC9718EE9F5EE131ECCB2DAA5E84
-:1099000046FB87BF157ABE8685290EAAD99ACB2237
-:10991000BABCC4FF87E31F85E3BA01E0B8E17F1951
-:109920008E42837CC6E0186CB8FF8FC2B1FDB69240
-:109930009B0AA1CBA34AD85A8476E17E13E539D499
-:109940008C89BE95B82F70BF467E1EBA24589F5191
-:10995000A4B1635A39CA4F7B00E372B68AE77BE051
-:109960007E9BB99CEC10F9C1C50792EE463FADA8AD
-:1099700026B018AF2CAF94F61DE4BE1D13792BB999
-:10998000CF30C4C12A3570DE46B8EE263B5514AC44
-:10999000AE45674E4D1D958CF6F15153248CF385E1
-:1099A0001FE6F3B94C910E2BEADEB4C10EB477AECC
-:1099B00034AEFFD89A52B27FDB4D45572E01381E88
-:1099C000502A935F473C6714519E16EF2F85FBDBAF
-:1099D00085DD5233FC0EB453DB85DD6A16FA5DDE9D
-:1099E0004FC90CDE8DFEC44967C34DD66B500F05C1
-:1099F000DAB2C0DEFCC1D9B0C6730DDA1B5F9115B7
-:109A0000ECCB1F36D4AF417BB37DA52FC791116B33
-:109A10000FF93B586BD213F56BD05F69B12FBD07BF
-:109A2000FD1D78FE2B2BACF3994CA177C4F3A23E1D
-:109A30003D057A09F498BAB2AF1D46BD54D4A77754
-:109A4000EA49EFEC785CA5F641980FFD3E5847587F
-:109A5000C5F50ED1C8AFB7012CC9D0B60D2BA2FDEC
-:109A60001B58374B46FF7A187F2EF3EE962126CAF5
-:109A7000BB637FC4A3CDCBFB5B66303FEE3759524F
-:109A8000ED1487C83CBE2AF68F92451D85E298C129
-:109A90002EC1FBD675E54B311EB30E36EE935AE25E
-:109AA000EA2DD4F8FA0B7B94FCAFF79C22FF9EC5FD
-:109AB0003C978A63F719F397E3D57D7B4B25C2BBAF
-:109AC00034953954CC8384A2B40F196FD7AC604756
-:109AD0007D3AF9B0DA5920D17EFF8B2EEED7DA2FFE
-:109AE0006A14DF6C50C0BF413B9ACAF94CFA476612
-:109AF00087E45BA3DD95FE923983AF65D9D409D99C
-:109B0000187FABF68015FD9C838E728AEB55E6BFFD
-:109B1000B952E7EFB444A752BE4C7304C80FCFC686
-:109B20003811F33D0E3FD3FB39AD2B20B0BC82B1D1
-:109B3000272B4A26A03C3C668B5A8B91BE8F9A28D5
-:109B4000DE3B547E4F58C17CD9724672FA64857BE5
-:109B500002E6BBB769C1F43B505E8EC37C3E4E3714
-:109B6000BECFDAAC607EF7736B301DF5C143C8F72A
-:109B70003ABC3CE9E27EFD0527F73B1F3073B9682C
-:109B80000578A2008776F12ACA473DE0E2FAC95279
-:109B90003D91F23516C007E6E3925853D841EBE504
-:109BA000F9B5248FC950B7A75D1C4EEF5F709A0CB2
-:109BB00071751BACD3A7D35F3616A6FC1AE2F8A9C1
-:109BC00004FECB4141372BF8433EF24FE2F6A1FBB6
-:109BD000FB47E4AF48FAF4F9290AF8275F128F35FA
-:109BE00042BCACD7F78D5A2FE9DF468887F17E8FCC
-:109BF000C34AFEA1AC4BB00B7DD6EA09B55F877CAA
-:109C00009E9C361CF3001AEB20A4ACC3BA04D48784
-:109C10001EADB78FFF41E69B6D69DBB15F8BA8532B
-:109C200048F11BE52799B54703289F437572C31078
-:109C3000DF611A37C967BCCF5888619CA179E2EB14
-:109C400018C27DF54A546FA7B12DB8AF2CFDDE5C6C
-:109C5000512F742EE58F1528C7E0F78ECEA2BC4D8C
-:109C60002FC52D325FF375FDE46C1C03E3D1E57F56
-:109C7000AEF810E56CC6E442BC9FA2713E01575C91
-:109C80004B2AC7F06AF2E20C58FF37B238FF39D5D9
-:109C900076AAEB785ED8B1BF38E678298E027C527E
-:109CA0003D4CB2BF9BE245E1A7A97DFAF1DDD501AC
-:109CB000A3DF19D6FB792B1E7D77754B29C52BD4D5
-:109CC0007EFE9117D7603CF8804DB65FA036D8B9BC
-:109CD00028C64B6C6F920FF910DE0FA0BCB1DB4AA7
-:109CE000C8CF568B580EE263629A95F4A6BA3769CC
-:109CF0003BFAC110173F97A5CB739E4B3D5180FE99
-:109D00007082F1C286F10ABEDE78307F27D6CBC8DA
-:109D1000E713D3364755FE9E0FDF63795D7F0CC393
-:109D2000F88FBE90C4D6000A1F331BE55D5E378AEC
-:109D30003813F58DBE5ED1523D3F804C2DE53AC9BA
-:109D400093CCA23A7E9272AE5D1CC6A23A39C97615
-:109D50001512BD342D407924ED62293DBFE0E47C2D
-:109D6000D0BAC27199793207986724E98F81E7A93F
-:109D700010FA85897CA346752F522F0C24E7F1FB3E
-:109D80005AF17A515EA55E4CC1B1E1FA82CB984797
-:109D9000BF6773C75164A1CFECA17DAED158BF742A
-:109DA000320D4D789D293A1CF9F8A3FEF71B70710E
-:109DB00051CC33C0FD929D4B5E45763DEC0A7D8AC9
-:109DC0007ED02B2E919FF5803D54D1DE81BD28E5BC
-:109DD000F96B27E66343BE4D9318CAD36D948F5534
-:109DE000DD419F0BF13BB382720E12EEB52B781D55
-:109DF00099D4B3762D44F8B26A617E7584C08633F7
-:109E0000F6B1EBD24D189B691A97A35F3F7A96FC87
-:109E10000A9B1620BEB2394C3EF40B6C1017A2DE22
-:109E20005DE930F1FD168F95F2F5AD0A4488A03753
-:109E30009666147DE93EB6E5A29BEC2D40E2D1EB9F
-:109E4000ED7FFE3C4E611F8CF3680EEE37B043DCB5
-:109E50000E23123ED0E963E90FC4BF173FBEC4A76B
-:109E6000C4AF15F15A4AF630A1BFF1776137A5FEAC
-:109E7000CC96FAD675A2240A77EB95EE34F46B40B3
-:109E80008FFE1DF9A4E1EADE34938FF4AF9BFB4112
-:109E900061F13EB3EBF95AE6A9E5BA24FC4B5F5FEA
-:109EA00060D5EF97C4C31B6F67EDA5C6FA029BCFC1
-:109EB000585F20EBF6552D487C631E17B0A29CAC72
-:109EC00074943BD0CF69D17CBF0B505D8499FC6DFD
-:109ED000F0DF0DF3CBEB4320FF08C710B7C950F7F5
-:109EE00022AFA9B80F92E0BD496E8EBF870EDE4E3D
-:109EF0007A58F3F37DA178FA31D64EFC925AC21CFF
-:109F0000943F15F0A65D66DC81F8E807076DE4274D
-:109F10006B63AD11ACBB8C9F4F3507030AEADD3292
-:109F2000467EB29ACFE7578730AAD34E1B95C98693
-:109F3000EAF0D8EA9949CF97BA1C0CE9ADA69A8203
-:109F400089F845E2C9E33619F6AD3D926FBCBFA76B
-:109F5000FD151DDF4C74BBFAF38DC7CDF521C2A1F1
-:109F6000A76FABA7283B117D627A91F3D5E5F8A2E4
-:109F7000621CF03BDA79B86E8375746A6CCAEE5273
-:109F8000848B515D7BDD6C3B73805DBBC353799BE0
-:109F90001BC6ABE87A95D78B77BA2868AC13EFC7A6
-:109FA000CFFFB69BEBDBB7DD5C3FA69F083C3B1EBB
-:109FB000F0DCD995EC53E0516766623DFD03B76272
-:109FC000AC37D0BA87A3FF22FB57541BE70B0BFA21
-:109FD000DF2FDF0BDF9C89FEDC74C665A3D8AFF0F2
-:109FE000FA867D29912168575954BB05F0BA53C4AC
-:109FF0008D3B219E9C01E3BA935908D7EDCA827626
-:10A0000029BD1FD86D8F8DF76B8E3236A938B803F6
-:10A01000C79B94ED2D6B2EE4EFE3384792598BB537
-:10A020003C86F79B9380E532F17938674969ECFE0D
-:10A030001150EED8CFEDEE1EAE80FCCF3705DC68B8
-:10A04000473E7CEB7B5427BA88059EFC10E87335AD
-:10A05000DCC4F8AAE244D0827AE1537C08F87EDCC2
-:10A060001E5C8D7CB2A07DEA93FA3A17B6837F8797
-:10A0700022F1D59F1FB8FE0138C3D64C039C6C2C2F
-:10A08000C26DE5EFC5E3575EEF127C2CE909E8B934
-:10A090002A55D0730DA07E6E0AF7973B2D9C4E7DFE
-:10A0A000FCE3B2B4E23ECA592B7FCE0243B97F6FC4
-:10A0B000E5F4999B521041BFBA530BA4A07F3FB760
-:10A0C0006FBF3E40DFF5D4D902E9D720FDDEE2F1D3
-:10A0D000D7E94A7B9B02E39C3607D2516E4FBFA55E
-:10A0E0002A2BA9FE81D747CABAB3D366DFDA2BE1A0
-:10A0F000F9BC1FA98195F4D818579C6581916F62AE
-:10A100009CB54FA57DBBC287EF56AF86FEF321E01D
-:10A1100040BD34B7CA1E467FAEF3F74D7F44BB3611
-:10A12000EFF124DF2A98E7F0E6917FC5F6C7EB52FE
-:10A130007D4994AF2D52BC98475D5FE8A0FDB7E51F
-:10A140004CF8ADF74EAB1ACCD84FF15FB90F026B9C
-:10A15000FE98C9E74FAC9D08EBBCD2D569B2034C61
-:10A1600037643FB1D60AF47E6065D0837988731B6B
-:10A17000BFB516F3106E77A06BBC1FE0DBF49D69D2
-:10A18000D8EE7C4C8C175EBE16F30E2F9942850AD2
-:10A190003C9FB269FD34AA532E96E33FB53600F6D4
-:10A1A0007FEE1357FCF5048CDF90FD8B69E81F00F0
-:10A1B0007D053C0708BE05E364FB604A15F80ECE3A
-:10A1C0001466C8C79A63790DCAF7764A3F9D1D99F0
-:10A1D00086F9D879139AAA34187F53F61B6B4B87EC
-:10A1E0003136A6BDD21180F6D6EC37A7A5009F74F4
-:10A1F000B2402DE64D22D9BF9966BD1EC6CF328E24
-:10A20000EF54455E3FFCCE5A1CAFA23A5086FE4C3E
-:10A21000A9E7C3B55678DF8575AC30DF6D9B87AD98
-:10A2200043BF5EEAD17F117A14F4E61994877A6B02
-:10A23000F7514CF5162CEFB5F0FA66A13FF2385FF6
-:10A24000F7B58776F37A74D9F6F076E7AAC4FAE818
-:10A250002F1ECEF79DC9899FE76673FD23E526FD76
-:10A26000040BEC4A203FA66CFBFF48FEBCD9FF8FD5
-:10A27000F45BC665F45B86D46F029FA5467D0DD363
-:10A2800008BD7F6511EA89636E9FC15E5774CD2456
-:10A290007BF2AE47E8151F7FDF55C5EB817AF7A744
-:10A2A00050BE8B59BB4A904EF2BDD102EF550F4EB6
-:10A2B000DF84FDEABACC8CBEF3D85DF9A57E651DBE
-:10A2C000E6877571489D16A5BC401DE68747E27874
-:10A2D000BFB6A03F84E3E0771CB80F82F95D5773E7
-:10A2E00062FA4BBFAAEE62060B8FEC6F7F63E33B13
-:10A2F000E9F9E5D6151BCF98BFE83F9E45EC27C589
-:10A30000D9494B6238AB259F02BE4D3AFE5A20F820
-:10A310000DB427F9933D7B876D5F53A89F977F5FAF
-:10A3200005FAF9D9F1A82F41DFA3BF59A105A6610C
-:10A33000FF8AAE4CDAA792FC21F942D2B533B38939
-:10A34000F27EBD5B14F2A7E2E19A27E1DAAC703F3E
-:10A35000A43AA4DEAD834FCA038CDF29C61F35960D
-:10A36000E4E7C7DC9F06B9B903E517F7BD711DFE29
-:10A37000EEE133AFEE0FFFAF851F0574E4F87FC148
-:10A3800046750AF1F63286FFDCCBD0B3809E4B7F58
-:10A39000A86E40BB9946EF659F88A6F9A05F97E03D
-:10A3A000FFCE8E0FD2AE43B9D8A732C5C7D78D7AAC
-:10A3B000AB42EAE3F088372668E497C5EC878FFC68
-:10A3C00033A93FA3566BAC7F70E388692DA8BF9378
-:10A3D000B8BC3A55B036E531381ECEE67A6C6C28FA
-:10A3E000717CF303772A3D97F8DEB2BC8A7D00EBDF
-:10A3F0003B21ECFDD8EEB082745920F0D8E7CF08AD
-:10A400007D767352F773E2FB10033FCA36F83B0DBB
-:10A41000A662DD733BD7BB723E80B78561C90A5C1B
-:10A4200015B8DEE62914E370BE3CB5377B1BEA0F96
-:10A430006771A00CF58DE42FB02762BDA6BB66DA6C
-:10A4400039FFCF4C4087E785FE5CB099AFBFF33F43
-:10A45000AAA6211F74BE9D99B14AC7EFA7841F29E0
-:10A46000C795F224DF93CFF78BF15EC94E237C9C16
-:10A4700012F8433812D58BC9F770BDA4AFDBB8BE54
-:10A48000867587914EB0EEB0528EEB560C76A2CF09
-:10A490003E087CD75B00CF80C79DE6700ED631B9F1
-:10A4A000703EFBE5E517D643CF7BF7A792DE891F09
-:10A4B000FF5C368FE7B699789DD51113C833CA99DA
-:10A4C0009DC3DBB3D74BE3760B3EBABC3EFC6AF2CE
-:10A4D000B3CDC2EB62017EAA4FAC7F31779B11FEF8
-:10A4E0009502FE50337E87E7DCC4FCCD8CF0164528
-:10A4F0007CDDEBF171FD640991FFD6BB8551FC3A1F
-:10A5000004FC081FB41B83F672A53026A7251D0A7C
-:10A51000D1B16203D869C49B55E2EDF55DFA793F8C
-:10A52000CF4E357C4F5827E83F04ECFBB300EF10CB
-:10A5300018E739829BC3756A63C77598A7EBB3F7B1
-:10A540009E34C10FF170462DB91C4EAACB407FC777
-:10A55000372A06278E8FF3307B70158EDBF0CE9E68
-:10A560005CFDB8E91ECE6F4E75EE041BEAB1F5A096
-:10A5700057491D840EE17716F30F6438D6308A1BD5
-:10A580004C181FCA79E78B7C2DC865C50C585A49F1
-:10A59000DF3CA03F75FAAFC863E7FDAD5501AA7770
-:10A5A000D3B87D72B59FBE1FF73106B2ABFF2C7ECC
-:10A5B000003AD2BA7B77C3BA7C31FC7576DCBDCA6F
-:10A5C00086FAF204F3A3BE94EB1A52DD9D86753C25
-:10A5D0008D428F025E4CC807CE1FF958B34FA79F1C
-:10A5E00005FD86322E6F323E198A1B2CD0BED63323
-:10A5F0005CEA1BCA179C7AF1E567D7505CC1E9D5C4
-:10A6000058CDE92BE5F50E4FE85E0FCAC1ECFB68AB
-:10A610007F07FA55A0BEABDBC0E7817E1D8CE4B698
-:10A62000ABA01AF0F72F9ED4847473063B6CF4BE73
-:10A63000E0FF73FBAF8E201FBA6EEDADC2FBC00F03
-:10A64000044F67476A04E366F297F1FD97156EBF02
-:10A650005888F032BFDAE1D7F38984AF8FEE0CE887
-:10A660007E75ECFE906A3E6EE33E18978F43F25380
-:10A670007717A37CB3A40F801CC6FCBED43B2EFC72
-:10A680002C3E338647893FF97E03BECF78DE00E358
-:10A69000BD46D64DF9D33A359887F11ACB4EA2EF85
-:10A6A00054210E26FD73C4C6341BBCFF1A5CD1BEF8
-:10A6B0004F5297D0F742938A159273D010326F168B
-:10A6C000453FF2E6F129A41FD817F70EC6F5B85298
-:10A6D00038DFC13856318E95FC54A10F7F5300FAF4
-:10A6E0005089E9F1238A42E31CB9FEAAED549B2963
-:10A6F000D689E3A1DF7044999147FEACC86F00DEB4
-:10A7000086EBFDB318FF86055CDD05F85C1F27614D
-:10A710005CD3176785C7AFBB11E2AC31533AA226B1
-:10A72000074AC384E9DF817927419C6583F5DF8F80
-:10A730007C8CFABE30ACA6215C4360DD70EB6872A5
-:10A74000A8B4C91E9BC72DF25F6E51B78CFE3C5E4C
-:10A75000CD5E6E57D67BB9DDE81657703B12E6CB5F
-:10A76000FE533CFF773BD7E36B2A13D7376FF118C3
-:10A77000F39D378BFD2288B7B620FF40BC25EA77D2
-:10A78000F9FE12F8B584DFAA07AB69DFF4F3AE591E
-:10A79000E9FCBC072EFF0B44FDEC5DF7CFFA21F27C
-:10A7A000DD8758570F74FC48ECEF7DE808A4619DE5
-:10A7B000597D72E23AEA5F7AF83AEB051E4EAFE055
-:10A7C000E7332CC07D4DF083777BB8FD5AD47ECB28
-:10A7D00064A4FB2288E3715F53D64F483AD76C5587
-:10A7E0000DFB130B705F33EB1F8923CA06882346CA
-:10A7F00019E208396F7C3C716A85C7B08F32B7BDEA
-:10A80000589C8FC1FBCF637E827B5E5BAE611F96DF
-:10A81000B5B9BED2B906183F8413C26731DC3FB563
-:10A82000C20A02AE83E393C1547FB2C513FA9DC737
-:10A8300000470A0B1BF2C9E31CB4DF6FE3796CA07D
-:10A840007F58EF57C7C375C6F38FC66BC503E0B912
-:10A85000E47F255EAB18C7F51A6B57A89666CCC483
-:10A8600038FF59D8CB4B9E14431E607EB5B19FEA8A
-:10A87000E5F1BFEA4D31F8CD03E501F47EB3528C2A
-:10A88000FA838FD720EC56E1676F531DEB782FF7D3
-:10A8900033C6E60492BD705D27EAD8D7D9F877FEB3
-:10A8A000DBFE7EC8330FFD8D37CD5477C0F671FEC9
-:10A8B000A9FCF1B2663C37C0DEA138F4DFB57E6397
-:10A8C000B912980FF2E0167AA2CECFD753E78F5A7B
-:10A8D00006DBB1AE99C391D77150D1747A23AF869C
-:10A8E000F7F379CD86FA80C15E7E2E439157E60D4F
-:10A8F0002307A73AB17F40433B93D3A1901DCA6978
-:10A9000062F43D4ECE28EE9F7D63D436655E696C61
-:10A91000BD6DA619A50E78AFCD9DE247BDBD2A2716
-:10A9200074A517E13B198D623A67CCC92E0DE3A7D8
-:10A930000D3981AB100F729D3ED59183F627E5242A
-:10A9400087AFBD2F2FC1F536636B055CDB797CA823
-:10A95000B2638CFBBDB48FEB5E3594EC875C8F3BB0
-:10A9600053E85F370BED21FF9BB591FDB3727BEA96
-:10A970005E55427EB2A46B2C9F32AC1CF329C5EB12
-:10A98000A2DA5C78EFC5ADA684E7584C15788775D8
-:10A990004CD4AFE372F22EFB9907C85349BE4F99CE
-:10A9A0009238FE8308909E57FED8F94D92CF160B31
-:10A9B000C3FCA6C4FF869CE06C8427A7639B82B877
-:10A9C0003925EA234E25F3FCEDA935CF2AE887DDAA
-:10A9D000BB9839543630DC75CBD5C07CBD3CB758FC
-:10A9E000882E320E88C1C3E396262FD7EBAFE7043B
-:10A9F0001721BD1BF6ADA7FCDEE21DEF5BBE74FFA9
-:10AA0000E32BE24DA9E1F14DDD1C2BD55155FE584C
-:10AA100023BAD7B65868BFB26ED76EFA8E8DDDC72F
-:10AA2000FC28FF751DBB95F9306FEDAEDDCA021D28
-:10AA30001E73EB2254377E45AACC5F472DA8CFE387
-:10AA4000F91BF3FF68F78FDAB8FC9FADB487319F2D
-:10AA50007DD61CAAC37E67BD297EDC3F95787F6DBD
-:10AA6000F78D747E40EA9EA4285EDB4CDB3D56E801
-:10AA7000D776A5C58FFCB42127B40EE992A9053B72
-:10AA8000F1FD0C67AA1FF3E1BE24564E76EF2BE2D0
-:10AA9000614C1C5F8CB98FCBCB2B42BFC01FD571D3
-:10AAA0003DEDE5712E6E07A0BE3A6AE6EBD8C338DD
-:10AAB000BC666FE047C4B7C73269DE9CBAA882752E
-:10AAC0001FF1F3C6F82AB0CDEBFA3A70765850CFA2
-:10AAD000D70A7D53F9E31DCA073AB83BBC2AC19790
-:10AAE000B36B9B82F916784EFA06FA33ACB3CAD927
-:10AAF000C5F34CB5F07C814EBFC87524D033BFC0C0
-:10AB0000F5D84F761DE67A26CAF3CB02DE787A1E98
-:10AB1000F2FA68FEC96066E9BE253C14E3D0A3459D
-:10AB2000C9349E94FB78393DE4E5FE58CED61D8AA3
-:10AB3000C94E7978F2CB247CB2DFD89C09AF213C96
-:10AB400063A674111EEAB76AB49E4996E0E0253AFE
-:10AB500079F8AD909B5767FF91CEDBD9F08BB78822
-:10AB60001FEBDB151E0FB4BF6599857626FC131508
-:10AB7000F74DA671D3CE368AF3A8A675723D5CDF79
-:10AB8000B95B9B678FF169E167AFD23956F51D4913
-:10AB90000CF75381FFFE80F48BE753891FA96707E9
-:10ABA000A227E823FEFD43D822F2D7A1C299A931FA
-:10ABB0003D6D167861767EFFA258578C7F42E77014
-:10ABC000FE989EB5915C147E56FE2AD699D6FB154A
-:10ABD0003ABFC359C5F1A9876B46C27D32AE273152
-:10ABE0004FCEF32ADD053375DF93F5E97BF1FE7F68
-:10ABF00022BDB9DD88F2FBAC08EDB7843F9E7E57DD
-:10AC0000E4703F36019F693909EC99B4F3858FEF01
-:10AC1000D1F07B20C93FD390EE3AFEC9CAB1D0B87B
-:10AC200059391AC1B3B192EF5F6D34733BB671A558
-:10AC300095EA425FBB9DD7A9A57ED312C5EB11D380
-:10AC4000DC3A7C7E2487C3D1665A45DFC7815C3AF3
-:10AC5000734623FFA431AE1FB93EDCF03CD76775C5
-:10AC6000617B04CFABA90BDD3A9FEA109C363FD63F
-:10AC7000EFB2D061CBACD4FE7CE5DB73D082F04F79
-:10AC8000EBE0F227E900FA94F84BCA83C46B0C9FFF
-:10AC900011833C497A98FBFC895021F797789C52A4
-:10ACA000CA54DA17AAB1068EE2778C35623F15EFE7
-:10ACB000639DABDC4F9D2BE8F2B83D3812D7D96FBE
-:10ACC0003FF52BFAD9B5CBDFA0B8E61ECFEB7495D4
-:10ACD000720BF1A041BE2708BA0FCBE1F67D6A0ED8
-:10ACE000E79BDA511D2497B51F36913CDBA770BD59
-:10ACF000663F69D4C78C3D24D6BB8EDE9B94D2318F
-:10AD000019F721273DA138304E1E08CE45F81D18F1
-:10AD1000C64B5B0FA5DD8DF8FD02BC75DD7742DF0C
-:10AD2000CC11E743EE048413BF3759BECC1FBFDC00
-:10AD3000782C7A5CA1F342042ECFEEAABAE623DC8B
-:10AD400037D899EEC7EFF3CFECBAE5BB1F01DC674C
-:10AD5000778CF7A39FE06C0E12FFF4BA6CFEED3C0B
-:10AD60001F3A05F33D2B3B0EA5E177459F3E3BA2E5
-:10AD70001CF5F61201E767CFABCB112FAB9EF9F9AB
-:10AD80000DF8BC36A264A1FF7A76E713FF9503E3C2
-:10AD9000D4EC68C413C858F3B3BFA4B8C014D9C660
-:10ADA000EFEF4C273FF7D327D7DF80F86EEE68A68A
-:10ADB000E79F3DB98DDAAF3EF3F357FE03F31FC1B2
-:10ADC00034FA3EFAB3E70F125DEA421AD5C50FC452
-:10ADD000D71B771FE4FA12ED3CCAC11CAEC7245F33
-:10ADE0004BFEFDF499BBAED1DB0D79BF4DE441DAEA
-:10ADF00092B91D3923E4B67682BD0DAF677E66A396
-:10AE0000733B1B2CDD25181FD79572BE5891C3F5D7
-:10AE1000605DC71273839DDEA771FE0DE41DAF5701
-:10AE2000037F62FD19F4DA7189EAA89EA3FED06F50
-:10AE30002CE6496657BFCFBF2B2D6D32D7129CCF62
-:10AE4000F2E7B06AFDF38A6589F735B6E4D80DF903
-:10AE5000D19CCE19793ED20349FE213AFF37A7266D
-:10AE6000D48C7502372D0BF9F13BFA173F797B3201
-:10AE7000E6D39E19AA8C24FAAB0AB773613BCD5373
-:10AE80008FFB0E107F3C2BE4C4ED60CE6B613D93D5
-:10AE900034E6B4E395B1E366D20B4FD1F8E0E79026
-:10AEA000FFE6FBE5ECA7D0EFD9680E7947E3386DF4
-:10AEB000C23EEEE0F0C3FB0E7B398DE7B896FBEBAC
-:10AEC0004BF1BDF32BA73BD1BF8771BBCCBA780C3C
-:10AED00038B200ED238E370AF134253C87EC94CF4D
-:10AEE00042EB93E781C2FA297F2AE5333E4F83FA8A
-:10AEF00009F3ADAFE7541ECE71C5AEEE01F21CD61C
-:10AF00005CFE7C4A6E80AE5FF57CD15767F7703B84
-:10AF1000FFD2FBC4B70DC8B7387FE843839D97F5D0
-:10AF2000111BF7BF4F7C3B7F1FD7C70DFB2A2D1886
-:10AF30006F9D5911601F80A3DB20F86FA3D2BD90D5
-:10AF4000BE4FDB6FA3EF0E7B247FB6BFFF31EA9FBE
-:10AF5000A27D5EAAE7E9D9CFF9F488C944798023B4
-:10AF6000DBAFDAD6ACF4B7ABE06F939C343431E1AD
-:10AF70006F2F7B1BFDB3FA1A5E07DF10C747858F63
-:10AF80009F6A457EC900EF18EB32C09F994CDF6D78
-:10AF9000D6B1D128A7391303FB7369FF9BC7E739E3
-:10AFA00035A04FA07D9373B11F4B073226825F8C73
-:10AFB000FCE7BCDE8FF9A68DF91DADE83F87273190
-:10AFC0003A7775A3B97D02C6C11B27F91C8049C019
-:10AFD000DB0EF2AFD9508BB067F3C92F6FF0FCAB2B
-:10AFE0009FF2C1F1F2BF7F25F9770DBE643F9E83CA
-:10AFF0003B6D9FB294FB337686F037007EB13D2DDA
-:10B00000725D04E13927F027F1D863EEA2F3787B73
-:10B010005E48A2F30DA74DE4FC9A31B183F4C76BEF
-:10B02000FB6F247B2DF932756F12D9ED4CCDA1F851
-:10B03000295F744B12C2334FC0D32EEA8433841D70
-:10B04000295EC7FDB8CC5C2E4F99B92671B518EBB7
-:10B05000AC1C61CA3B9C13F42736D19DFB543F3F87
-:10B060004AF254B78B8FE74C0A94DDABE35FE95F9C
-:10B07000C97A03AC1B989180BFC7E6723B58F8F8B9
-:10B0800052A2FBBC1A713EC43AEE5730E00BC41B0F
-:10B09000D091F8E026E722A2DBBC75CA37898EE1A1
-:10B0A0000ACA1B4AFF2C7EFC71627D3B6DC1515860
-:10B0B00067D8EB4AF5E37ED7CE8C8089F2EE65192E
-:10B0C00094077165717FD125FCC598DC07479960AD
-:10B0D0009E4FDCA99CDE91DF6898179E92EB4BE8AF
-:10B0E000E7F58FF3F978D3DBC3C331EE91F5611245
-:10B0F0001F9195C973F4FA7482A04B64189B837AEC
-:10B1000003E2093BE5AF1D300FE613B65FF724CF2E
-:10B1100027F073A1AFCAE5DF354FCA0A8EA2FDBF83
-:10B12000E2E0326E3FF93AE3F1F1BAB09BAFCEBE46
-:10B13000B30CE3D8865BED7E94BB0D2F297389AFEA
-:10B14000C3563C3C08F89ECB21384C540FC5421ADC
-:10B15000D1A3A1291849CCF73348CE1AC0EFC33880
-:10B16000601AF2B993F83EC2F99EDB3F996F403DF9
-:10B17000A9F7B7A53E907A06ED1BF2B3948B861B18
-:10B18000BA4B90BE5F55AFF498B99CF7001E508E35
-:10B19000A4DCA4BEC8E565CD4A5F253E5F0372AF5F
-:10B1A000A7777C7C867062BC22F5FBAA9CE0B77313
-:10B1B000114E53B495BE7D15FAB8E1C5D52589BEAB
-:10B1C0005F92FAD82ACED3B4465222FA7D06DCB377
-:10B1D0004F2DA76B18ED51CAF2C4F998D5B9D2BE5C
-:10B1E000F6AB775A9DEBEA5FEFE446DB85F2B33DC1
-:10B1F00085BEA393F9A9F871BF2FF84DD245C62992
-:10B20000B85F80FD9F12F2B359C8E973E2AA8B7F41
-:10B2100088FF7DA6D0FBB8DF3F901D93EFFDB3F212
-:10B2200065721E694FE3E92FF73B703D334A07EE25
-:10B23000D77E50C48171FCF882F0A7EECD65746DA5
-:10B2400037473F27B95A92CA689F6D330B64E17E36
-:10B25000D92B57707908F496E0F857E68732F24612
-:10B26000C7F2C2781FE3935A8D85719FAC76A739D8
-:10B27000A2FF8E67277E4809FDCFA75AC32AF0F99F
-:10B28000B8FCD061A4677802FF5E2FFC3D1BEDFF88
-:10B2900080233D1AF54B23EB4E433C37A85D2598A0
-:10B2A000C7DCE20EBD8EFD4F99BA0A78BD05DF9F5F
-:10B2B0003A29F2BE2745DEB7D312CDFF8E3376CEC4
-:10B2C000DD05C6EB752E749932310E7C6FDF3B3F86
-:10B2D0007B09DEBEE3A573777C1FB1B526E5CE1FE3
-:10B2E000C1B5DAAA06F5E7FF9C4C4DAC674F093EA5
-:10B2F000EAABA759999430EFBF278FF34163DCFE87
-:10B30000EF9E3C1FBFDFF75D16DFFF7D6F8073B2DE
-:10B3100026E771FA748A3A9FF8E7D3C43C3BCDAC78
-:10B320006433C2B32D95F6D799C6CF37AB79A4D085
-:10B330008FFB929D45FCFCFCDE4715B20327CD5CDC
-:10B34000FFC0DFADD68A981D453705FDC41A4738C2
-:10B350006A02FD51B32C358AE767C27D6D1CCA5A5B
-:10B36000D841F5A673857D9CD7F4DADF30EF51A381
-:10B3700031EB3878EFB47D7E1A9A8785DFBA178F64
-:10B38000C061D9D5EDA22E519CD71698AE5E4AF970
-:10B3900032BFCEF85DCBDEBCA015F9AC3A9DE3BB65
-:10B3A000FA5E7E4EAFECFF9290DB7EFC86BC0AF02C
-:10B3B000FE51E1F6257E1E77FE84E751BF2DF7048E
-:10B3C000B368FC7BCF19F45A8FD2FDF48F902F977E
-:10B3D000A48A73D45881BE5ECA9FC7ED4B2DEE3749
-:10B3E000816A3C5FD655B2BC10F9BFB7E077987759
-:10B3F0003B904475B1B5B8EFA4AB671B68DF69E05B
-:10B40000FD269F05F9BCE1A2427C32F7C06B2750B4
-:10B41000AF3768DDC43F73AD76A24FC3458D9EB391
-:10B4200036F359FD777AED9EC0705C5FF8C17119F3
-:10B43000B46F950DF709CF43E99C8FA5A21ED99D46
-:10B440001F1A8DFD36A5A4DD85F1E1052B3F97A9D7
-:10B45000D1C2EB8E99F8FE59F209CB4B35F2C1817E
-:10B46000D7FF8670CDB786E81CCB05739AE8DCDC85
-:10B47000EAF4E86847A99EFEE3BED6B9B95EA137F3
-:10B48000DEB3F0FA9CFEFCCFE9B0278FEBAFF7728A
-:10B49000B81CBD57C06AF6E0F54AB8C27BEF158903
-:10B4A00076396FC78FD328E4E8BDE1DC7E8597A6A7
-:10B4B000243C97E46E218F7BF302B723BEE4FDA703
-:10B4C000051CEEFC40759E8BF46348F06D3403C69A
-:10B4D000ABFE25FF1D03D6D24B75257DEB2A11F05F
-:10B4E000BA13C3D5121B77118E07FD02E4C7BF62E2
-:10B4F000A3EFEFD874D0D7A89F97E633D4CF306F9F
-:10B50000631E1F379A41FD92681DAC0DF436F0EFB3
-:10B51000F9D13EA2CB9A4AE0D351E25C7E5F8CAF78
-:10B52000243FC5F3D17D79CA40FBE2F7E17CF1FB12
-:10B53000E28C0D267A13BF7D8DEFD8466471BC80F6
-:10B54000DCB7E691FD8D5EAD973B8967A92FDF4B98
-:10B5500036F245AA80F307A25F1F9EC5395ACE6214
-:10B560006E0765BCF0B8E89F21E82FAFD2AEC5EFFB
-:10B570000F64887133F2D2245D1E13F4CE4848EF75
-:10B58000AD9CDED0EF09EC579DD47B6716D8B3DBBA
-:10B59000C04FC2732FE13D2FDEEF97B798C8ED7013
-:10B5A000E3D254867EC24FF244DE6F542FDFBF1BBE
-:10B5B000DA4BFA682E03BDA35C9E7E9823F0823E90
-:10B5C0007C43D40F2958CF93496AC087E301BE3B1F
-:10B5D000F35C317CC7CF77121F815FF84A9EF8BEBB
-:10B5E000AF8C9521BDEE7CEBCFA977F8F01C74FEF3
-:10B5F0005DF147F6D0AB38CED9EFBE4E71C0494BA6
-:10B60000B4A4DD9EE0B925FAF82625F6FCAE9FA885
-:10B6100061FCDD8BCEAEB38FCE06BE9CDBA5FA718E
-:10B62000CAB9F77DFEE618F4AFBBCCB40F05FEC572
-:10B630003A3C179435717FF4A4C948FF33DF36D6FE
-:10B6400075740B7995DF3B4B7D25FD86C5CCCFF519
-:10B6500054323F87FDD49245F4BDF37C163C8AE713
-:10B66000B07FBA742AF9D38B58887E8F605E9BF1C5
-:10B670003CDEF8737CE3CFEFC5043FE22FFE1CDF16
-:10B68000BE7C7B55623F23359FF3E1198BA82F18B1
-:10B69000C0CFB828F857D61734CAFA8297BFBCBEB5
-:10B6A000A031AEBE20E68FC8FA822F284F68CEF7B1
-:10B6B000D1F8389EBECEE0CC84C4702BF9D2EF49CD
-:10B6C000318C2FC789CD9346CF1BF13C9F84DFABD4
-:10B6D000DBE9FE998589E749CFE7EB6E8CAB67889C
-:10B6E000BDCFEB18649C2FF9A2F1A297ECB16CF7D7
-:10B6F000FD0E43DF7B79F43CFEFB7C99A79772F04B
-:10B7000081C2AC5ECA9BAD177AD13F1CFDDF0FD062
-:10B71000AF4239BCD1F74A378038EFFBD794684540
-:10B720003139895F07F0D367FAEFE087E48B7379EB
-:10B73000FDCC4FDF490A3EBFF3BB93D2719FF5DFCB
-:10B74000EFAB327CFFD6F77DBC45FA7376835D663E
-:10B7500071767BDEBED7C95F9B6F0DD277781FBD38
-:10B76000FC5DB2D70B59D08DFC7DFEE52B0A42FF64
-:10B77000037B2DE1B9257CB799FBE94EF233660ACC
-:10B78000786E39C0FD45933560A67902CCE77053D9
-:10B7900028CEE105A589E7F05DDF077F299DDF3130
-:10B7A0004EC0AFE0FB80DFEBC595CD0D79106E7913
-:10B7B000AE00709307AFCDD7F87D781DAF0435A6E6
-:10B7C000FBDE74326BCAC3FE266BB72ACE3BA3F3F3
-:10B7D000E39362F8A276AA68B7DC7AE1CE0578DF57
-:10B7E000CECF27B6083816E68BEFA8ADCC8AEB4E45
-:10B7F000B2473FA57D40710D4FE0FE77B888D7ED89
-:10B8000026E3790A30AFDD7E2E8C8B7530079D13D1
-:10B8100060735C88621CA2FB1D897BF25DBADF91BC
-:10B8200060519E9F1AE879DCEF4C640AF89A857E95
-:10B83000F3E27987C574AE03E9B7875317D239E4C9
-:10B840002EFB32DA9FDE923685F62FDD8878AC53F8
-:10B850009FA23B97019EBB82C6F318B2E718DBDEBE
-:10B8600090B16D6527A93E4A89063D97B262E74EC1
-:10B870009A85BEB83599C3756B328FD756E71BBF13
-:10B88000130DCADF7FC9E4E736F4B8AD56ACB7C0D4
-:10B89000F83F9FC7FF7F044A435CC87F1FA66C7CAC
-:10B8A00060C8A3A3F0774F54FF2AA0536BAA6FA5DB
-:10B8B00086FEDBEDE277C2B40EAA63D8766706D5C2
-:10B8C00089B6DA1C9598F70CE7F37C4FA3A8F70725
-:10B8D0008AD4EE82F7B6CDCCA57ECEAA5ECA97F604
-:10B8E000AE66E41FF5E3D32F80FF01DF4F621BCF6D
-:10B8F0009398EFEFC2EF88BD0195EA74E5F31DF868
-:10B900001CE054045FE0FDF115B1DF712A3E507672
-:10B9100008CFC36421C5CFD38F3EE2F759C22F6F42
-:10B920003C5079F36880ABB86B24B1F1E00362BF9F
-:10B93000C59924F68DF9F9BDF1FD07637F68A71C51
-:10B94000F3FD6B1D3E32419C8DEF4D48A1751F17D5
-:10B95000F92626F4C39838F9BB2E260FF4BC4CB454
-:10B960001B457D1D9E6111A8E0E90CEAE7E4F2E1C8
-:10B9700067F28FCBEDB52CF687E354C5C6253D3570
-:10B9800031F6382687B0C472ABBFB90EFA1D99C123
-:10B99000F7D7C768D18328EFD7896B99B8B2B9EDCB
-:10B9A00084DF352B032AA3128890BA1EDA63AD5DBB
-:10B9B00059C8DFE3ACDD2B5D30CE3573EEF660BBEE
-:10B9C000A4A098F80DFC2F3A7728C36E8AF0EF28D0
-:10B9D000CBFC2847B3E7F07CECAC3956AA3B9EA5DC
-:10B9E000F1F3A198162ABC0D9EDF56CDF3C0D8AE58
-:10B9F000D6E559E4BEC7718853762788374B0AB815
-:10BA00005D94EF378AFA1FF9BC080F8AC63C59C10A
-:10BA1000E48FF2C99EF0FDDD3352CF0C6543E37E27
-:10BA20006FE67C3EEE5F56BE31909E303E177A62E6
-:10BA300056E01133F9E9425F48BD1C14754D5DE2D3
-:10BA40005C97772770BCBF5DB998F4C5ADAC89F43D
-:10BA5000F96D2C6C467CF7E9FF293ABF06E699158B
-:10BA600034FA39B3E7C4FB3D9C5FE5BCB7878CCFA4
-:10BA7000674AFF758AD17FADFECE17196417B39F51
-:10BA8000AEBF342856BFD41857BFD420EA971AF750
-:10BA90002D39E2D2D52F351EE0F54B0DFB2E57BFC9
-:10BAA000D44BFB48C7CD9183B8BF727C318804C0AA
-:10BAB0007948D4BB1CC67A97F2185FA6CEE47956B3
-:10BAC000605FDA2FC973A4F8D15F6F3395535EB608
-:10BAD0002D2DD5AFCF83AE59199AA4CFC7CA7AA559
-:10BAE000E303C4B7C30BB8FFBA51E179F1F0ED56E7
-:10BAF0008AE75CC541C33E844B652730BFF811FA25
-:10BB000059A3A93FE53D701F6F245C230AAFB3EF33
-:10BB10007B1FBF3BC27C649C3E7265F9691FC09568
-:10BB20007E35E5F3E71C28DB41FAC66EF3E3EF222E
-:10BB3000CAF1E784B6695847D478609B36DF1EE3C4
-:10BB4000BBCA02C1AF292C05F9B52FBFB72789F2AF
-:10BB50007B1FD983930AE0FD3A4B743833F233DD0F
-:10BB60001FC8AE2D12FC629E10BC7D01C073FE4D3D
-:10BB70000BCF73DDC7485E9FDF9F41F9496D2623D8
-:10BB8000FBD252C9F8EFC06CE3DF0B9CCEE0E718A4
-:10BB9000B5CC6064077B322713FD16B3C8513CA7B0
-:10BBA000A866ABD9701ED13D3B8CED3AD641F6A6C6
-:10BBB0006E573F7E26BD25F5633DF3A966DC07E899
-:10BBC00034BECF061BF56399B00723674D6CC67A68
-:10BBD0008D91A6A04AF6F73E7FEE4C8A9FABB91D29
-:10BBE000654FD3F957E7533F51B99C737D3C3AA653
-:10BBF000350D7669B4F0AF6ED0F8EF2A487F69B49E
-:10BC0000F89D85C3A6032AFD768F806794784FFA46
-:10BC100069525FF7D1732CE852E0FB07255D8B5822
-:10BC200011D215C627795030C0C9A4F1E9F71AAE70
-:10BC300013F301DDF9F977266B04F9A85569223D64
-:10BC40006D65425F2BA1667CF917E130E9ED6B5819
-:10BC5000D32DF87B9FE3AC5D29E497DA436B0B5C53
-:10BC6000313E6966D182DD8A815FE8F9D98C37126D
-:10BC7000F28BB42BD177B9BF318D811F08F3067ECB
-:10BC8000CFFDA0C30A8FF3C01F3C8C71DE1BA6A999
-:10BC9000C40F536119D86F92C348E71B3DC6F654D1
-:10BCA0005F3F3E50F5BF5F0112A7213CD3861AFBD0
-:10BCB00005A47E6346FD56C8BEE075E5AB8F7E0BDE
-:10BCC000E3FF94E56C28FA31E039FA13FD1EE973BD
-:10BCD0000503EE933C5790609FE4BCC8F75ECBBA77
-:10BCE00017EE52FAF34DCF91E5AA47C75F929F5FD7
-:10BCF000147515CA2FC57EEC289EF78BD979CE37DF
-:10BD000015A2752DF25D267E7F22F845FCBEC8F592
-:10BD1000FB6C51FCFD9C3231CEB5C83FE531BB1EFA
-:10BD200035D97D9622E4137F9BAAF6F7E7DD993E8D
-:10BD3000E297912669E7FD598CEC7C47B386F0EFDA
-:10BD40001F931BB21BF8E31DAE4F803F282FD5CFAA
-:10BD50003E1A9FC7F18FA4E331E147DFC87C144747
-:10BD60004C117E74B490F34F95FD560DDF7FAD8876
-:10BD7000E70926E206227DEF69B48B5556231FC4DE
-:10BD8000F317CC68D2CF1BCF6F03F1CD20E41B6932
-:10BD900017B32ECF379F0B3F2301DF7C5E307A60D5
-:10BDA000BE89E717A95776DB1C5578A670638D42CC
-:10BDB000FA78E49B839BB17D457D21D5BDECCEF027
-:10BDC0001FA2E74DFCF9A8AE808A7531C5CBC4F33C
-:10BDD000C26015B61B97F37D89D1C779DDCCE0FB36
-:10BDE000F8F3B2554D87F0BBB8C6307FFFC54F5B47
-:10BDF000E97BA148AB78BFB2BD0ADB8D6DFCFDD3FA
-:10BE0000B8BF3402EBDD22CD787FD8BA423F0F4B6A
-:10BE1000B95F3B5EF0E96E65CF217AAF9DBFB7E8B1
-:10BE2000A835997E6750F8AD3788758EDFCAD7E997
-:10BE3000FCE026FADDD105BD61F29F3E36D5559076
-:10BE4000DE1920FEAC54DAF3F07A23EA1315E90781
-:10BE50007C5DC4F71FB7C314658378FE42EEDB61D7
-:10BE60001D81BE6EA06C10B7FBB29F3B937FD7C500
-:10BE70001E4BA5BCAFDC578C6E620ACA19AE51F8D6
-:10BE80000109F7196F2C6EA2FDC51B07C9FDC56E10
-:10BE90000DCF752FBBF4E7C989F22B63C5BC9F8812
-:10BEA000BA0879BF265248BF23B61B9984BEC77E05
-:10BEB000F237D416E79433F11DD8EE42DE9E3CE80B
-:10BEC000891FB6E5017E4D4D1A9EEBC60A14FA0E87
-:10BED000EE5FBA58343DAD3FFC376A2C6AE1DFB102
-:10BEE00011FC0B9B2DDBF9F7885C2FCD926A67DC88
-:10BEF0001092D35B059D6E1924F29223D948D43752
-:10BF0000B304DD6EB382DF4A7AADDD1C27FFB307D1
-:10BF1000A1FDD832A0FF6C7C1EA71F6AC4BC0B8594
-:10BF2000DFBC187FAF54C5F3E6B9FFFCC916EE3786
-:10BF3000DFC33A288F78FE31EE2FD6C3F2905FFA36
-:10BF4000FDAED74E63BBBE23FE7764F9EF10F6FB60
-:10BF50009DD6529E9F3DBFA5BE02F373359BDFA4C5
-:10BF60003C708DD41711A3BE000783EB8B4D575245
-:10BF70005EC764E5BFA33912F405D6978CC4BA51E5
-:10BF8000187FB838876735BEC2CFDFF9EE20B237E9
-:10BF900053A8AE94C653693FF7CD802F461F69372B
-:10BFA000E2F54599CCD70CCEA47C96D41F658CDBEA
-:10BFB0008B78FFE811494F11F7483FA30CFD0CE0C7
-:10BFC0008F2E933D6232E9FD8A08C921C48DD36C5E
-:10BFD00045C83ADC9F1A79FB28ABA03F8BA3EF261C
-:10BFE000A2EFC0F193F1791CFD65FC5221E87F3B83
-:10BFF0000B505CB457D0FFED77F9EFBDCDB22F23D6
-:10C00000FE7BF7F7DCDF94F1D3D78F9B02EA3F1278
-:10C0100037F5D1DB067E640AFE1EC6D4218FE27E90
-:10C0200078A78DFFAEB5C2E9EBBEFD78813EAFF8D3
-:10C0300036FE7E8BEE77259AA72659711FB0D9CC94
-:10C04000E38A99D3DEAB98ABD31B8559952F0D1A94
-:10C050008DF4E8FAF61F30CE785D9CE37AC045F4A3
-:10C06000BED0C5EF5FD87A953F0CB7CF98C579465B
-:10C070004AD3422C8192702C14BFF7F259CA2BB4C8
-:10C080007F3C2323740CE970CF1B7B295F59C7BA0F
-:10C09000F8EF028B7107CE4B86497F595EE5F6B00B
-:10C0A0005749F6F3EF86C325FAFDA4633EAE67C792
-:10C0B000E5078FE33CD2DEC5D7159C5C72237DD7A4
-:10C0C000F9171648C7FD4C45E3BFDF1C3F2FD611BB
-:10C0D000B4E8F2D9276D89BF333D3588E7038A106C
-:10C0E000475807911BF800F1F78988033F11FB5A65
-:10C0F0009FA4F17DAE9EBEFEFCAAF9847E16FB6075
-:10C100009F641AE347D9CF22AE1FAEB0065B74F42A
-:10C11000F46D4A6A8A501D95A81B59C678BCB43F75
-:10C12000C3700E4186AFB2C887FB14C5010BFEBEBB
-:10C1300077EF7E6E8771FF19F7872339A12F10EEF5
-:10C14000061F0BE0FE2AF3755B6EC17D46F17DEBA9
-:10C1500079C12FE76DFC2AE1FA6FC3AFB72E0080DB
-:10C16000000000001F8B080000000000000BD57DC0
-:10C17000097854D5D9F0B9732733133213261B84A9
-:10C180002D4E16B2906DB261D8270920B860C25208
-:10C1900051B661DFB209D88FB6F6CF601090475B19
-:10C1A000A8B6C5CFE51910A8562C1183460D1A94D0
-:10C1B00022585B4704454B75A4CA222189602DF69D
-:10C1C000A3E57FDFF79C93997B3361FBD5E7FFC83D
-:10C1D000F37072EE3DF72CEF79F7F3BE27518E8A9C
-:10C1E00024471C63ED77FB4D4C652C4AD62BA09E53
-:10C1F0008CF5F2244711D4A7C8F7A2FE10AFC33FB5
-:10C2000003EBC5D81CFCCD01A5C5DAA2E6C0EFEB57
-:10C21000C25AFDE9F49E5D4A624C51998745432517
-:10C220009D39CA6DF874B8FD442614E1F01EFAA9D0
-:10C230003159D729B9D4BCDC02FDCD10FDB1FE3691
-:10C2400023F63F9D77C566341FFC5689646CA6852E
-:10C25000ADE907EF6735F736C10CD8A2484FAA3DC4
-:10C260000B5B8CB69F8071154F847A2902FAC67FCA
-:10C27000A3BA968C19D909393F5A8787315CF700E0
-:10C280001FAD6B7D4947C27F1732D6B1C76CDF0245
-:10C29000E35435BF7554817555C9F5356AD797EBA9
-:10C2A00050E87BC62CDECF2D8CDDCE14D613FA6978
-:10C2B000B2BA73115E55163FCD137A349567C368D1
-:10C2C0006B8747D1FA7BC3F7309F17EB5CECEF61CC
-:10C2D00001782EB3F3F58F512BCB4CB18C9D9BC7BE
-:10C2E000EC6678B4ECE0DC7A0BD4973DC0EC7C745F
-:10C2F00097810D86FE05BCBA9B5F5CB981392CA283
-:10C300008EC34EEDC11CE9817A1F77B4A60EFD32B3
-:10C310009CC752D16FBF457D35DF0FA84DD2B4BF4A
-:10C3200061E520CDFB444FBEA69EBC6EA8A6FDC015
-:10C330000DA59A7ADAA69B35EDF358524F06F0AF69
-:10C3400039A0322F8036C33B51F33EF3E9BB34DFD3
-:10C350009F64B5BF190EED1AC3237318E0517D78A1
-:10C36000E4162C99C7E5CB02F8CC13EBC86E98A362
-:10C37000E9E74CE4D803B8AFF37C0B6E658057B99E
-:10C380004D4B34FD2E552BF9BE6D083BEE87EF6A01
-:10C39000E107E199CF3AF6F783F9557B15670BBCB6
-:10C3A0005EB889BF97DF2D6EDA4CDF2DF66A9F2FBE
-:10C3B0007D5A5BF794B2F45A2B63CB1DB658C287F3
-:10C3C000BEACEFA520BA0AE0013482F1CE3DAE7AD0
-:10C3D000CD89089FD4DF0E27F88431AFA3EB7E9D73
-:10C3E00063CCD982ED77D89C1EA82F3C3897E663A2
-:10C3F0008ED7E241B8438B0711E95A3CB039B5FBFF
-:10C40000DEB358BBEF7AF846B9065D16BE31E3B429
-:10C410007821E15A0C3FDF255C9FD0C1B3609FAB10
-:10C42000DE4A7062932D83117E7CBE6656AE229FDB
-:10C4300063B1C067E0B99377C1CEDAAD1E03E0CF38
-:10C44000730EC578C212E827CFD8B217D7B346F11A
-:10C4500030FC2E9C79E3915FD417B724B4C0BEE4BE
-:10C460005B6A71E7D817D6F2E791EE2B4D2D39F8BC
-:10C470005EF6F785D54DCF5B95771630582F33B6DE
-:10C48000E4103FB4301A5FC271700F8EC74B593938
-:10C49000F1E117053E7FFED12282E30256BBDF05A4
-:10C4A000E39DF998C37731F350BBF91BB470E802F0
-:10C4B0003F1DDC006D1C386E8D58F712C6BC86E43B
-:10C4C000AEF0549A95165B0E82A159F26DF7A50253
-:10C4D0008E7608CFA1ACF31FF16F095F68A004F35B
-:10C4E000271CCFDE2B309E84A7E45B721C33AB5538
-:10C4F000E3910E747C8CA56BF709368E617DB0A834
-:10C50000BD023CD4122D06EB85FDE0E419BB518C35
-:10C51000C3E6B8E3114E16B681F66FBDE25CA7C262
-:10C5200038EA0D89F50CE0596077A9B85F45CC373A
-:10C530000D9F175B1AEA8DD0D50DECA2FD04C81330
-:10C54000D67B7BD5A598C03A14B92E8FC28C501FCC
-:10C5500021EA933C8AFFB1445CCF5BDFE2B823441D
-:10C5600039094BD83F58E6DFFF0A1F0F571C0370ED
-:10C57000BC89AFA4C521DEAC516A996E7E475F8548
-:10C580007E5443470CB61BC3DC462E77BD3849F6B4
-:10C5900096E2A779FF88B9EEC752CAB76AD6307655
-:10C5A0001AD4AB1B416E456219DEA242C99A74F0DF
-:10C5B00064C6E35837C04A10BF97625DEE7B62E005
-:10C5C0003DD5D5AEF555B0863ED15796EF1B13ED50
-:10C5D000345F907FA9FC3DE76F8B04BC1649B9E539
-:10C5E000D5CEEF18FED287B13F9A0026F9484716FC
-:10C5F0008FA127A805894097D82E87E560FF40576F
-:10C600008E44E8BF5734D0A1124C77BCBD7CDF8587
-:10C61000EE74EB67B5B0B94300DEB642931B58EE3B
-:10C62000DCE0F55E053CA41E310FDB42F92F878369
-:10C63000D65DD5E3D8072E7C5DE84B40F92FF7A9EE
-:10C64000C6C4DC0DA8B734C4D1B8F2F9E84483D02D
-:10C6500027001FAF024EDDEF430AE943721FAE56BB
-:10C660001FCA451C2F0AC0EFE6AEF09E90181704B3
-:10C670004F06F0CCD6C05BFB5EC05BC2E36C916F33
-:10C680003BEE936A3BDC0BE1BC32BE7C12EECF800A
-:10C69000A3FE138A2130AF316AEBF6C7508E35A95D
-:10C6A0004EA4E5EA119CCF55BFAC12E9B7359BBD4E
-:10C6B0000AF4B3A8E94DD2CF5AEB809186750FA743
-:10C6C000CEF5EAE0DD151E7C1FE57A96EAD63FF34B
-:10C6D000BDF3B6190E5A67CD15E050130A0E677EEA
-:10C6E000CC669567E1FAB27AFAB302E366E1BE037B
-:10C6F0001C7E1E597E0FC2A3F0FDFE91089F316A79
-:10C70000F3FEBE0887158AD30CE38E32334F38EC24
-:10C71000739F9565ECEFB057C5FE5AA71DE011DF7A
-:10C72000DFEA54011E69F7A8E55EE8F76F2B96472C
-:10C73000CF85F2CB3A187A203C570CE5846F6CD742
-:10C74000273F85FED26CD39DEBA136C30CF38171DC
-:10C75000127F1CD1920C7CE27513B320BD8525D5C8
-:10C760001E1A0FFD7644A94ED4836355361AF14B39
-:10C77000C2393682AF433E2F7962ABE2B7069E8F55
-:10C78000AAEF285806654522DF77B9CE51651D0509
-:10C79000A8F74838C726F3F6CCD8913031883E72D6
-:10C7A000053C8EA15E07F0AC8E33AD4139D866E111
-:10C7B00075E64A27FD778585D3C7B1F0042FCAC730
-:10C7C00063B0561FF5D76263D620BE18EEEA792310
-:10C7D000AC9BBDA7B26D507C6D77F58C2278D87973
-:10C7E0003F42DF6A636C1CC269C5F8D2DED150C615
-:10C7F000D573F8E8F1A43191EBFD951780F00A02AA
-:10C80000CF2B8D2D26BB159F9B34CF8F03DC3CE6B1
-:10C81000407DCEA994B18CF88C730DB69FBB2E824F
-:10C820007982F4AB46318FEEE0521D656446804755
-:10C83000B5C2CA2FD7EED5FFA8045FFDFCFF2AF8CA
-:10C840004C5C59E8F51D12EB2B5B7BEB6F51FFAC99
-:10C85000F68531333C5AF172496F16A2BF4E385FEC
-:10C8600018C6BC314175A39FE0517D61243D2F5B0B
-:10C87000DB6A42BCC77E1CF07C45B8ABB7F33270B4
-:10C88000CEC579E07A2F44314F4CF0738E5781FE3C
-:10C8900063E9FDEF118080B79E26D5BB0D3EFDFDFF
-:10C8A00001C3B82DA1E62BD63F28CE48F492D9C2B9
-:10C8B0005C9B438C2FDBF58A067E6DE570AEC8EE7F
-:10C8C0003ABFC652FF4C9CFF8DA3992BD478E74406
-:10C8D0003B39EFC668FF0281F7A915B6A0BA5DBB68
-:10C8E0008F3DC5F88D37FB13B0FFB6F16C6A4388F6
-:10C8F000FEE57ECF88776722DFA9BC031A037E0C92
-:10C9000036D62AF6207AEB6EBF037006BBABE07218
-:10C910007036D17BD9DFE943821E99CBAA001DCDA9
-:10C9200016F26AF6D6A5B702CFECB45F4E6F02FBE3
-:10C93000058638CD6ADFB4617D8342F6C91C37C8ED
-:10C9400000E0370BB615AC41B1353B9EB191D1FC3F
-:10C95000F9BD58AE0E0BC859FADFC582E5A21C7F9F
-:10C96000DE835ABD75117BF02BD47B4E1FE27C0118
-:10C97000D453B2BF173CA2ED6FD1D65B4EE23C1749
-:10C98000E9F49F3454F040FF484B12F6C460361867
-:10C99000F9FFB26DE74D918EEEF1FF4BA0F394815C
-:10C9A000C827ED540E4D72E524A17FE13D3ECFF145
-:10C9B00049EEFC24F4A3BCC7E775AEF21C970F8FB9
-:10C9C000C7925C322313875FCDD32CDE7A98C75A87
-:10C9D0006023E1001FB399EB4152FF53D5E56A2470
-:10C9E000BC1FF2C58A6837F2E1676F1A87FDC53D43
-:10C9F0001BE1C2F5AC2F71E5A1BF607D85D5590F54
-:10CA00005D5AE07B941BDEDF0F79A32F6A070D1BB5
-:10CA10004BFB21BA35EF6D417FCA3AC357FBFB414F
-:10CA2000FB752399B39E05C6A969AE781EE79330BE
-:10CA300099CB97F589AE3C7B50BF4CE873D5027615
-:10CA4000ED7BD27E390CF6F7B103A44EC3FAC09E3B
-:10CA500087F90D627C9FD9458013E0098E1DACB724
-:10CA6000B6829C626981FAA006A5250CD653D5F83A
-:10CA7000BC01E560E57D2DBDA6A13C7AC6E8DC12CF
-:10CA800034BFD8D7FB943A220372689A62273D419B
-:10CA9000EAE57732F92F8BF066AAC09B3B853E3ED4
-:10CAA0002D82C3770E7326E077775958A401486921
-:10CAB0005A594311C9A9A5615128FF712DA1F65BEF
-:10CAC00096DDF995AAB7DB3C0AEC7B9BD2918A9D57
-:10CAD0007C89BE1EEE5FF26E49ECDA4F5D92A0C318
-:10CAE00054A11FA630970DD65DFD5ADAE6F5F0CABF
-:10CAF000DC03F6319FF891A5389FF4630BDA3D8B88
-:10CB00005F0D6F512203706176579E01BEAB99D8BD
-:10CB10003F7F3DEAA44781AF0081B585F913888E38
-:10CB200081DF2820F336258DAD3002DE55F705FD77
-:10CB30000BEAFBB74CAA3002DE5727F91718A0DE24
-:10CB40009654C5EB83FC27B07E216925AFE7FB1720
-:10CB5000A8508F495EC3EB6808026239921FAAF0A1
-:10CB600040FF5F4609B9EEF4CF44FCA97E25CDB065
-:10CB70003E68BDD664CEAFBE0CE7EDBE4C64B326B6
-:10CB800022BCD3FDA9384FD9AE2349EAC31BA8BDA7
-:10CB90005CA7FC8EC587EEFF7749BCFFC565421FC9
-:10CBA0008960EB106EB04D9E4880FFBEE6B42DD874
-:10CBB000FEC1A468DEBF1DFA290CF423E128FB9313
-:10CBC000E32E41798B7C380CF870101F6D4CE2F22B
-:10CBD00012C6594DE3A400FCB1BF89FDF370DF60BC
-:10CBE000BF8C62BF8CDC4EDD4CEDB1DFA81CE2FBDC
-:10CBF000054658C7BE8BD03E31306F3D7EEC15F8F0
-:10CC0000B1B81E1821E967C98447A322B85EC80AD3
-:10CC1000B5EB8849E6F0B32647F17576EE476F85A8
-:10CC2000C6A91770EC0F70CFBEF675BF2FE6F35D87
-:10CC3000AF3B68BF5C2ABE6FCAD812BC1EB02C3591
-:10CC4000FD7CB94AF75D311020AE333A99BE5B1BCB
-:10CC5000CE2CF49C6DE9FC2E3187EBA3A8A75609D6
-:10CC60007D9A79469253A152708DAA753E9303DF47
-:10CC700037282EAF35787DB7168AF5D9C5FAEC7C02
-:10CC80007D5E0D9EB2C31D09936D5DF1B713EE9DE0
-:10CC9000FD65E58BFE34741DAA3FA48FEEF6232CB0
-:10CCA000F93BDE0F394F1D3C3BE1AC9B9F8427D203
-:10CCB000337D97A5C54739CF0B823EBBD075E27552
-:10CCC0008E57C2BFABFA09EC23EA270E2D3E57352B
-:10CCD000261AE66405BE6BC2BD2C0AF8E7D293851E
-:10CCE0009DD79FF547FEED29E57E54CF2EB3B3DEE9
-:10CCF000417EBDACE4B8907E3D7AAEB7F3DAA34C8A
-:10CD00004C21BD48EB67688F73FA5CA89F9E65CE87
-:10CD10006DD0EF309DDED10EFBB9CB1AF82E204F2F
-:10CD2000B4F59F083AE8EA37EA48C0F9159A4B5F2C
-:10CD30007038191B9BFC14F1F7C29EA5CB13A17E82
-:10CD40004BF236E2D785FD4ACFA36BE6B6E4EDBCE5
-:10CD50009E597A3E09EB4F6DE7ED47B95E40FECE36
-:10CD60003CDB2B460F09E80F13921D5CFF28333084
-:10CD7000C423B37AB713E5A484677765A1D9501BA0
-:10CD80004A6FBDA3939EF97946B190CFC5D28EF775
-:10CD90001B35767C7BA4C5A3025CDB519EC27AE77F
-:10CDA00024BBA723FC6B225A67A20A7C5FC42726F8
-:10CDB000D4871417E81BE81771D8D97498A7D2BA8A
-:10CDC000BE9CF4C0254E8B91E029FC54B0F64BD0AC
-:10CDD000CFABAF3DF3B37E7C98729CC71041FF355B
-:10CDE000AF7DFBCD5F518E7E6975A21B7048F3A3AA
-:10CDF000CB51BF1AD2FCA76FB9BCB5D239959CF7FD
-:10CE000010F437C2F3E22633CD7F4873C67C6C3F03
-:10CE1000ECFDE664C48F11C75AEA911DB4EF79A9FD
-:10CE20009F3BF8DC8A9D542E655EBB7ED1098F2F17
-:10CE30004C0CF54B80C7FFE1F0B8B800FD8A6D716E
-:10CE400087D6F8494FEBCFFD98E27BD0CBD391CE7C
-:10CE5000CFB11E4E3C5768B7F17EF4FECDA315B09E
-:10CE60003E783EA2036610A4378FBA60010612A86E
-:10CE700097B0284DBDCCD247D37E8C3D51F3FEA652
-:10CE8000F80CCDFBF18E3C4DFD96F4219AF6B739A6
-:10CE90004B34F5DB8BC76BDA57B82A34F5BC9606F2
-:10CEA0004DFB82034DDAF7871DB40F05C7CACB507F
-:10CEB0009F77FADCF558DED8BAA1ACA78375F1EB01
-:10CEC00016FABDF5F87CD8C5DAA216D6D5BFCB9632
-:10CED000B8E93CC08CFBA2069D0F94F8881EDB0CC1
-:10CEE0004E47B01FF7D15EEE17709FDE5200EC0088
-:10CEF000EC91968E18DCAF31B31E5223715F3A1855
-:10CF0000F9BD1A4DFE5F0C43393F4325BDB7D1C86B
-:10CF1000487F6C9C9AED45DFDF51C5FFE25F914F82
-:10CF2000CD88207E3202345C5A379E812AB84F6EFB
-:10CF3000CDBA4BD862DD3EDDADA98FB1FF44D3FE43
-:10CF4000A6F8559AF7E31D0FE8F669A3A67E9BF3B2
-:10CF500051DD3E6DD6EDD3339AF7233EF7D7231933
-:10CF60008D6AF5A83698FFD0A31BCA705F861DF3A3
-:10CF7000CC407A296C71D7130BD957FB26962D60BC
-:10CF800057A13FEB8DBA782AF7D539C81FB5BF2E08
-:10CF90009DCA03754E7AFE765D3195EFD4B9A8FC33
-:10CFA0004BDD382A7D75E55436D43550FB5D754D23
-:10CFB00054020407A0BC888D11F207EA68E7B7198C
-:10CFC000FCD578E27AFAA96F884FB6F5F0B761FD23
-:10CFD0003EF68F8AD1503F9CC288BF59A14FA4C74B
-:10CFE0007329AECA14A85F48E6CFDBC3ACEB500E82
-:10CFF00034185C79A85FFFFBA9FF6C340E60ECFE6F
-:10D0000055E5F1F6285EB7409D361B0D33CF7F36D0
-:10D01000BA8633F61C8A8CA154AFC07A7B387F7FE6
-:10D02000E1A9FF907E2DCF9B2707CE9BFF9D1CE2A1
-:10D03000BCF9B9530E1BFA590E5D4CB3E1BA0E0997
-:10D04000BF928BE585CD86B2C498178672F1A84E43
-:10D050008F90E5A7D612534A1CCEDF3905F508CFCD
-:10D06000CD616C1BF08B890AB7473BF5C0142ECFFE
-:10D07000DB6F3393BD73D8E09A8F780E7CFA4984C6
-:10D0800057424ACF892857DA6D1D090887FE299132
-:10D09000BC1ED7F1A4E20CAA87F175C6A5D82676E6
-:10D0A000B3CEBE381FFD3A6F4811E70C2DAE0128F4
-:10D0B0007F65FD7085AB0AE5C4E112D7409CCFA126
-:10D0C0007233D18FA7DCE61D884CCEE82A9A12E491
-:10D0D0006F7934258CBE9B6CE274C6EE52BDDB4288
-:10D0E000D8692FA5707D9FF60DEDB93B23480F3F02
-:10D0F0006C608B768580E3BB295CCE9DE911DAFFFD
-:10D10000E213F02B9D64A3FEDA5784D3796F7B7909
-:10D110001AE941EDB50025A08FF653B56777D37BAB
-:10D12000B33C0AA373CD69824F3DD7BCFC1F47A017
-:10D13000FD272B229CC4C3ED83483EDD251ACF88F2
-:10D14000B190DE3263E28052944BD3C4F9D84C9B49
-:10D15000B1171D9319A34C76E8679E356F0D8AFFB2
-:10D1600005B115A628A82FEA7FF71A2C97A46C34CE
-:10D1700045435999F5FC1A541FAB80B48AC85EF236
-:10D18000FFB90EE6356BA5EAE0F693906BAEA5D736
-:10D19000148F21F110E188780AF025BBF03D016F72
-:10D1A000F9DD7B029EB352C4396D36CBBEA43DF788
-:10D1B000998B78D23AE3CFA9DDF8E7B5EF85DEF6B3
-:10D1C00081898FBBF4E9306FB03F498E7B48CCE357
-:10D1D000B089B914D4E3EEB2117EE44C3D7F5F1107
-:10D1E000AC3FA7D96EA0737BC9C77D8CFCF6459F69
-:10D1F000BB89CFDDD8EADF7E84119E37219D5C4953
-:10D200004E4DF2AC22F930E46B903FC8172FBA3F75
-:10D2100039427C7091E083B5C4BFF6D5ADA4FAFE67
-:10D220003A0F9507EAD6093EB881DEBF53B749F0F9
-:10D2300041AFE0834FD3F3E6BAA954BE56E7167C5C
-:10D24000909FAB4E14F8B432DEBD0EF9993CBF9CF2
-:10D250006C718721BCFEF8A899A9782ED16C263C68
-:10D26000050A78F2B1588C9731DBD73BBAC6CDE8C6
-:10D27000F96DE7FEEBCE7937C4BB1EC1F13AE3642A
-:10D28000503FBBA17BFC39C41C36E4273BB64E247F
-:10D29000FE71C8E1B0A1DEFA5CCAA489C8AF0FB9BB
-:10D2A0001CB630A8FF61EB24FEDEEDB099A1BE33C1
-:10D2B00065327FEF71D8C2A1DEB055D4BD8C0EB5FA
-:10D2C000776FBD93F84F0953F6213D9459124703E8
-:10D2D000BB06F958B20FE9E0A6F8D9A3910E525255
-:10D2E0001C840FE31DABF661FD96F4CDC618077ADA
-:10D2F00043F356E377A5B11546FC6E74FFBB57E3C5
-:10D30000776353361A83BF1B97F5FC6AACDFEADC00
-:10D310006C447D3005F9565CA01F5997EF257F4579
-:10D320003B01F134B7B99CF8784E5339F171099744
-:10D33000D2C915F7A39FAEA649B12B388FC94AE7CA
-:10D3400061BD023A44F545A016E0B3FBB6CE8B5E54
-:10D3500005DFD5607D28D57FB52A34DF3D981242A0
-:10D36000BE7C28E814E566057CF721D0CF2EA8679F
-:10D37000E0FAC87F38DB369BFA73DB50BEE6A67056
-:10D38000395920E4E65C512E12CF3FB5BADE47BAD8
-:10D39000FC3845D8635DE9FA1341B70BF83CBAD0C5
-:10D3A000B5F6BDA06BBF940F851D0958AF621BC8B1
-:10D3B0004F78A5F8AEC5C1F65B22C6493450FC854E
-:10D3C0003E4EA292F9787F0DBA380BE637D1796CD0
-:10D3D00053D073E247C2FEE8C1F9DE5464D6809FA1
-:10D3E000DF76CFCFFE8DF0BFCCBAB5EFC5BA17331D
-:10D3F0002FC5B5E9D7C1DC71445B4BAD87693FBB35
-:10D40000AEC71F7A3D5DD6C1ED7719C722FDF2A0E8
-:10D4100007D90616211FB431F4DF04F3892397E1FD
-:10D42000137A7EF45DF1B9CBF09BA48121F88D8C49
-:10D43000CFD297529F83BA07E3F33CAF85939FFE09
-:10D44000A4C39D8DFDB497767C6340FB2CD64F78AA
-:10D45000E6E9E776E273C5C4CFE9E1492AEEDB29C4
-:10D4600083E70FA8170DDFF624F19D36140E408FC9
-:10D47000855047BEE3ED5B3E18BF63E91C7FDA15BC
-:10D480002E1725DD833E48E588815C1E752D395DAC
-:10D49000C9B8C6F6CDDF26901FEB0AF8DE1D1CC604
-:10D4A000A8C3FD1EE4F7C511A4F2B42AAC4501FDE2
-:10D4B000AFB5A417E911AD034C462CBF6B3BB1755A
-:10D4C000402AF5AFB7175BFB145BF8B863C761D9A7
-:10D4D00064726F9A8D76D21033D949EF8A78C00979
-:10D4E000113C7EEA5D3C1F8676138E5F8C45F9A564
-:10D4F000B7375B0F4E2F75E474B53B619DA3719DEB
-:10D50000959F19EEC767D76A8756AEFC86196340A8
-:10D510006EAFBCC88C055763973215D945FE51E7ED
-:10D520009B58167DEE8BCE71A0FD29F507619F5E9D
-:10D53000210EA9B883EB0BA32EB2746321FA997A5A
-:10D54000D0F98D52FC276EB78A529E8B0CE7536040
-:10D55000330D56AF29491387146F8472BAEA1F8CB2
-:10D56000F536E6A37312BD3DFB96F043815DFB0BE0
-:10D57000C4DB35223E09762406F177CC4F3F9AF979
-:10D5800033E203E1A40F75DAB5BB0D145FD0687404
-:10D59000F51C8176EDCA81CE5550FFD417F7EB57B5
-:10D5A000A1ACB17F437093F45BB9F23CC153D65B3D
-:10D5B00085DF774318C81F282BFFA3921CAA646C31
-:10D5C0001DED1B7BC3B42C482EB286AF3AE19F0BF6
-:10D5D0007CAF02014876D6C8492E685721EC0FE689
-:10D5E000799DD785DD0516C52417F45B1127DAB3BD
-:10D5F00087F9FB01F2FD23FCFD40D9DFF989F4BE78
-:10D600008FAC8BFE3264FD4FBC9E28C76BE5F56C7A
-:10D61000590FE7FDD978FB9706364CF26405F8FD03
-:10D620009E81423EE6B13C1197B377E0E5E351B409
-:10D63000EF857C98F58CEA31E5E2FE8C8FF833D2E9
-:10D64000778342B17395F78691BFFB4C7443CEF25A
-:10D65000207B45C6AF9497D95CA8FF55BD98B645C9
-:10D6600015F13CA87FFCCBC1ED9831AA95CE27CE11
-:10D670003DC8F97E77FADB8295AF6AF6B3CB7B556E
-:10D68000E1F6381EDCC178671FEABD99EC8B141FE8
-:10D690009D9B7F2AF85D2FE0ADC5D18178B1D8641C
-:10D6A000E6427B35F625E0CFB8C79FFB881F2F7871
-:10D6B00089FB7FAB1E7D93E4DE1CD541FEDCB159B6
-:10D6C000EE2F106FDB6C3EF22B2E58F91ACDEB9B30
-:10D6D0000CA137D83BB282E179B62BFCBFBA02FC71
-:10D6E000BFFA21E1AFF73B2FB1EEA3F52EB9C6B8D3
-:10D6F000B6361B3F17758A7D3A6E700C16F08A4855
-:10D7000045FFF97C5F6A948A41C7BE5E3C5EE99D35
-:10D7100022B48BCED5DA18EEFBF4E57FCB7187F01F
-:10D72000FBEAED811938665C005E7D52851E14802F
-:10D73000EF001CEF32F0D5BEFF9EE1DBDBE83739AE
-:10D74000F11CF528A37E06FB8E9B82E36246A47241
-:10D75000BCECD9C4CF8DF4F15E23526DDCEF2DCE3D
-:10D7600067AA26BE331CCF67243D8C8A600DE86F04
-:10D7700007BC760ABC76225E4BFC0D9CD3C0772199
-:10D78000E82B80BF5AB88E4EED82B7E3AE00D7715A
-:10D790003F245C1B411FA673CDDDE1E44FD1C3796B
-:10D7A000A980AB84F7BD5780F3BDDF139CEF4D75A7
-:10D7B00068FC1112DEDDC927FDFEC87987A0D3A25F
-:10D7C000EBA1D34B69DC4E64463FC599EAF7BDBE79
-:10D7D0002B3DADBDC2BEAFFD21F75D0F377D592991
-:10D7E000CE3BF5CFB7A576CBEFBE1338FE6FF3A7D0
-:10D7F000CFA8DDAB793F6BE541CDFBD99EF734F582
-:10D80000E17E5F19A2B9F48F8F3CD5F126D6AFD750
-:10D81000CFDE9D7F7DC20B0B0D78FE56ECE3FEFD47
-:10D8200005E9EE7FA5029CDF3578EB6D00D71B8FF5
-:10D8300035A8741EE6CDA373C0E5628EE787FFF3BB
-:10D84000939F01DE9C6766F27FB6ECCD303AB2BBA7
-:10D85000E241C90595B982F4C4124B9411F5A9129D
-:10D86000D09443E1CD258137140F04F43ED5C2C2D4
-:10D870006281CEA74E5528FE692AE3F1D450B6B88E
-:10D88000E1FD04236B3143BDC26A6C31D3B91FCFB4
-:10D890007798C2A7C9CC46E6C1F72C3686ECE0C91A
-:10D8A000F810E6ABBA548A679B52CCCF0BEFB23676
-:10D8B00084A13CBDF3C07D677F06EFD96A4F118F0D
-:10D8C000D796F96B1F1BAEE51CF0522AA7F37645DD
-:10D8D0009C2B2B614E8C6FD57FF77E2AF7974E508D
-:10D8E00057A918FFD2F11E23BD5BD21DACEF8039C2
-:10D8F0009FE7670CC575B2B096B448D49F37966160
-:10D90000FBCAC30E824B4DF1AA1CDCC79AD1CA6771
-:10D91000E69C807D53B3F26BD2D3C7A83BEAB1FD3E
-:10D92000B9A3DC357E63AB47457B25E0BFF4CF442C
-:10D93000BABC921D24E77DACAE85F0E993BA0354DE
-:10D94000BE3BF24F45A867F8EB7C21FD97D7EB2F44
-:10D95000907E02E937907CE0D37BCB7A235E66A48D
-:10D96000093DD0A2F443BEC08CBC94FC3237AD8BD1
-:10D970005C2D48BBBC3EA87DFF3DF3D7ABC5F3CAC9
-:10D98000782E17F5F8ADC76B89CFF0599102E3DE19
-:10D9900005FA1ECAD569CC935D097C76EAC20D6191
-:10D9A000C394EBC7EB25D6CF1358883C956BE7E7BC
-:10D9B0000EDA47B54C25FB40C62BC87D5890D6459E
-:10D9C0002E2EB9C2BE2DF921F7ADAB5CFB7CE6F57E
-:10D9D000C935A6C9EBB8BF2BBE3E9076797D40FB1A
-:10D9E000FE7B5E7750FECC4CD510C817C178628C98
-:10D9F0006B6CF7F27CC845891B222938B3B8231217
-:10DA0000F5C6C57B54C243667419FB00BE2E14F8DC
-:10DA1000DACA5A3E407C5C387C21E5D12D7A3C74D0
-:10DA20005C71B568BFC4DA68C2752ED9AA6D572D6E
-:10DA3000E28A2B7768FDA2D5C36F3A89FD56EBE2E7
-:10DA40007976A689F8E17C96CFE32EB4FAA9BE6C6C
-:10DA5000AB631A7F65DBC53AF207BCF4BBD6873DE2
-:10DA6000FD83ECFFAE78BBF70AFBB7F787DC3F3DE1
-:10DA7000DEAAB6AD945775AD78FBD341AE0F70DE1C
-:10DA8000921F4F47DE04E34E7FD5ECF5E0F9689135
-:10DA900083FB37156F3D9EB7B57FCBC87F3447F802
-:10DAA00039BBCB4B97F106430E7BEB79BC814BC561
-:10DAB0003CD1C107CACBF0B8A2E09D5AD247BA3DCB
-:10DAC000B792F955227EE86AF99AF4EB0D3E554B70
-:10DAD0007A96D367277D68E8858637513E7E57FE64
-:10DAE0006E290F736338DC0AFDE5A4E7B585B5142C
-:10DAF0007D887AC2CBE121F5841EE95C4F98E499D8
-:10DB00001DC6F30DBB9C07F648C7F340C1FF0D16B9
-:10DB10005718C2698CDAFAEB3B107F7C2AF9F7566A
-:10DB2000FCFCFD3F3CE6B8B2DD5F633F4F7A4377D4
-:10DB3000FA7F8D81E75DE4973928CE0FED29F4EF68
-:10DB4000497F9FBE7DF1A0D2FEE971E4AFF6B970C6
-:10DB50003E9BF87CBADB9F9A955F69FC8BDD8D5FFD
-:10DB6000B3A7C83E27880E66A42B12CFED272C81C1
-:10DB7000FDBD5A3C18D13155A3FFFCFF6E574C50E8
-:10DB800041B504F999AD78B9FECAB81E3B9DF9A814
-:10DB90009CC93AA874331E7F3F8739A99C27F29805
-:10DBA000DFCE7057A4533C4C472F8A9F7CF17FB245
-:10DBB000106FCE8E1CB60163EDBE2F3DAE3DCF4142
-:10DBC000E3B7EFFE9F048C83B9125FD810EF9A97EA
-:10DBD0001EE23CE82F252A9DB7B0538F919CA810D8
-:10DBE000B730B0D1FC1CED5F8E44A29B005FECBD52
-:10DBF00059F2453C9FCDFECCC0E349162BDE81D0C7
-:10DC0000B4C96F20D2CA9E9FE855B1DEC8DF6757FE
-:10DC1000457915A8670F09E7EFEF8EF2A21F7D0681
-:10DC2000F3133DCE628CF8DD6CC6F9DE5CE6E2F9FA
-:10DC30000EAC2309F5B0F9CD161EEFCFFC29C8DFD5
-:10DC400073BAB17F5A049DE726717E9E5BAAF55395
-:10DC5000AC49E77CFC6446E967484F67D25D6BB12D
-:10DC6000CC8DF6AD7FB890FCF60CED8793437E42E9
-:10DC7000E78DF2BBC841A50F62BB9D0A8F4FF7EC41
-:10DC800031537C047CD1AB3C28AEFFED8CB25F619C
-:10DC9000BB4711F645DDC315BED3E4CD06E8C9C3C5
-:10DCA000E78F3617F9DFE141318D4BF5DF3F3D61FD
-:10DCB000F26A2BF9F83DA8F7460E723F85FB9A6B86
-:10DCC00062CC8AF37FC2ECDD42FA696D02FA2B174F
-:10DCD0003E6936A0DEF011885BCC43F96B9D85CAA6
-:10DCE000BF811D8CE5A7600763F919D8C158FE1DD7
-:10DCF000EC602CE75FC80361C1D8D80C5733C7EF7D
-:10DD0000D0F959BB053C3BC7DF63A2F14F66B809A8
-:10DD1000BE9DFBFD32F3E2A1CECEA88EBED197C14F
-:10DD2000B7EEF98C47D883A1E3B99E15F3C86934DF
-:10DD3000927CCF69F2472E086AF776BA89DE67EFE0
-:10DD4000FE9CF24FDBEC9DF07529B0E409065E7F86
-:10DD5000FBE979935767E1FC5D9FE1BA81BEFF82E1
-:10DD6000654ED3FBBFC2FC1FE89FE20EDA958EDF43
-:10DD7000901DA05B871E0E725D3BA37CEBF1FB9DAB
-:10DD8000BB937025C06F18A71BC42325D47A57D125
-:10DD90007C6F377714625ECBED97D49071C62733D2
-:10DDA0004A08CE3F97F826E124F6EB7AE9BAF3FC6D
-:10DDB0005BE02993F77720EF74A01CBA1889FA5E0C
-:10DDC0008538DF6F6A4C7917D7E739A0B2810EC268
-:10DDD0005F0DDDC566F0FD9165F61E5339EED3CEBD
-:10DDE0003D2752E659695F52E6437B63C6408DFF8B
-:10DDF000317BC8B7FFFD702CB5B7E35077B2CD6368
-:10DE000030FE649A65EF1F714933EC9F8DC1F89322
-:10DE100059F1CA7E2C673B12C762DC898C8F9F9BAD
-:10DE20005EB21F49E9566705E96925C85C82E4418D
-:10DE30009925020F053BEB63EC319AFA4DF1FD3465
-:10DE4000EDC73B9235EF6F49CFD4BC97E3DEEA2CA8
-:10DE5000D0B4CB8DEE4842FB0CD641F4C0B6A91429
-:10DE6000A797BDFBF0CD99509FB07D8A13D5929DA9
-:10DE7000E2FD845D655EDC8F7680A70914A853C53A
-:10DE80000FFCE661EC4CA7FF57EE796ABFCB710D32
-:10DE9000FA7F377ABFE4B34B9B2D45C867AFD60EE8
-:10DEA000D0EF4F7E86D62EE80E6F3AE9427170BCF5
-:10DEB00039A8B26D21F0062352391EF272C2219E9A
-:10DEC0003F76ADFCEC0BE4673101FAE82C757EB9C6
-:10DED0005C93F3DDE5E8A7FFB3CA281F4FE4F52DF7
-:10DEE000C0DFD500BEB3799BEFEF134BCF3DA8E762
-:10DEF000627EA90BFA5F9221F4A7CABDF7F7290C3D
-:10DF0000BC672B3ED3B467F72A6B34F5D589DAFAB0
-:10DF100083256B82BFEF8E2F2ED834DBE4A6FC4F17
-:10DF2000C5E50DC11FE47CC6BC114E717DB761BC57
-:10DF30000A3CAA2E7CCF88E7B0B775234725FFB9E6
-:10DF40005365B5A1DEDF93C1FDFCB7BE114E713044
-:10DF5000D7DAEF47004B8A337C89CBD18F7AFA8CA2
-:10DF6000C1FBEE11FD9F2DDAF8F36FF07CF46546EE
-:10DF7000719F67A338FFCF693C6930A01CECC1F1E9
-:10DF800025C7EE37A05C695F14E1C1B8FE9AC536BB
-:10DF90008A07CD4DEAF8C0025BBFEE99038F5800A7
-:10DFA000DF3EC624C820B9DA8E4611D437661C205D
-:10DFB000B97ACB1BE12D86EB58CF463C97403958B8
-:10DFC000CAE97C26E28D902FE863AFB99F75CA1B22
-:10DFD000E40BB87EAC1F78E64F871F8179D71CE42D
-:10DFE000748E11767AFB7E5A907DCF1EE77469811C
-:10DFF0001F1EA7A4A3EF7D1B4CD6CBD27903C5DD92
-:10E000005C2D7DEF407A8EB82C3D1FBA05F6A7E651
-:10E01000657E9FC5B9E6819417DB9D3CAFD9A412FC
-:10E020001DCA7A5BB33A0EF1569F7F2EE1CA5C4E51
-:10E03000A24F796FD4B211FF9C887273D91E230F3F
-:10E0400012E96E9C752A73048DB3F335F322CA73FB
-:10E0500013F36F97F27ACF3FA24BB278B92A84DCE0
-:10E0600003391D168B72BA4221BBF2C89EDEA50889
-:10E07000A7230A6B7150DE168F539EC4BBC3E756AD
-:10E08000BAAF243E9DE293A57D29EDCA297BA60C5B
-:10E0900044BDF283C6394760E7D8A719C984E7773A
-:10E0A000300FE9C147A2CA07A05F6282880F381209
-:10E0B000D5D18A7CF9C8880805CFFBA1FFD5D8BF88
-:10E0C0005CD791B0F201FCDE0919973CE8BAEE8901
-:10E0D0001BA3DE5B720B9E6F4F6776B42B6F57B935
-:10E0E0009ECB5EE7F429F95E8DE28BC679BE9D3149
-:10E0F000F1AB0C3C2F5EF90BE157157033F238C4CD
-:10E10000ABD5733BEDD9A7157E1F8A93EBFFD5C323
-:10E11000CFFCFA0ECC9303BB5B81F9CC69DA4BF7E9
-:10E12000FEE8EDEC4E7BE7FFD19FDAD55E2A8F1833
-:10E130005414F093EBEDA64E3D5DEA7BDB789CFC3E
-:10E140009B237EDBB614EA2BB645101C4F3F69F6C5
-:10E15000201F3FBDC54CF6CFE9E88E63CBB1BE2B87
-:10E16000DBE9A1D19C9A7BD1161A1C1FA2FC616F1E
-:10E1700087D17D1E279F30B7E0F9EEE2A732B6A027
-:10E180003D757280E3D91DE80F7C368EEE19606E06
-:10E19000FEFD6D821E91BE1CA07AA8BFB3911EB178
-:10E1A000F8853EC4C7E4FE9D7A229CF2E84F1F9892
-:10E1B000D413FD65AD86E7298F87A9560FF2E3A535
-:10E1C0005BC2490F5C697767E3FACB7E77DB1D059D
-:10E1D00038FEFB710CD7D3DEFC02F92B03FB1B5A74
-:10E1E000BE9F6B4EE67CA053DEF2B8DB5918779BDE
-:10E1F0004C71B70583E2305E55DEBBC8E36EF35564
-:10E20000C54579070F85CE231F3D489CAB4AFF4982
-:10E210000CB3C4231DBA19ADB7FDA1B42D68EF4CE2
-:10E220001F24F29F5987C89794F876ACFA55F29F4D
-:10E230009879BC5F78E873ECF2413CAF7881E56B8C
-:10E240008DFFA67AE5B71ABF4A751623B99B5FEF13
-:10E2500028B81BCAE502CE5549E593107E4B1A3605
-:10E26000BEF80EC1E5F11F7F8CE31EB092DF86BDC4
-:10E27000C3E1A7B7671658BE12F4B459A3079F7835
-:10E28000F4438A3739B13B3307F76D8EEA3B81F7A8
-:10E2900071B5D97C9FFC0CCA5D070ED1BEE8E7DBE7
-:10E2A000E5DC5EE17CA512D71183F12EE58B07D169
-:10E2B000B930A7F7E3EBB3097ED29FDB7E3AB4BD5A
-:10E2C00025E729FB97F393FDCB76FF25F6EBACC949
-:10E2D0009783F2B97FBA4393877D36D2971365C58A
-:10E2E000E7FC1CEA6C34D483F0E6FB3ADFB94BF868
-:10E2F000798E1A56DD6302FC6B6D7838CC1DCC47E5
-:10E30000AFF15C47CE57C695CA3CDA4D83843F7B5C
-:10E31000001BD04DFEEDE38827955DF36FE979771B
-:10E32000F9B79DF9B6FFE0F9B632BFB6B0CC501BD5
-:10E330009C672BF96161263CCFC2737FAD7C2FCCEB
-:10E34000D5B6EF8E3F0ECEE47E95C298D0F9AE7F63
-:10E350001EC4DFD7B3167EFFA0908BC304DCE5BDDF
-:10E360005F524FA9167C5BE6790E6BE6719BC34446
-:10E37000DE0E7001CA73ED72BF5B7C26C955793F12
-:10E380009F027D4D8F0E952FECA3798C641D54BA9E
-:10E3900098DD8825809FCAD1AC9CCAB1AC96CA7161
-:10E3A0006C039537B3062A6F653E2AD9A01611EF84
-:10E3B000792FCF331DBFD080F2B5F08ED07A71FBAC
-:10E3C00015E1E0A1FB03AF150E6319BFE7AF0B3CEE
-:10E3D000FAA7137EEBE1A1CFD71CC1FC7471C92849
-:10E3E00044DC64B4831D14DF5AC65C541F739570FB
-:10E3F00028F6BB8D3CBF57078FB2D0787141C06300
-:10E4000015CACEA2C03E65673AE8B9DC2F30C4E237
-:10E4100091FFEBF7513E2F8C283DEFB0E37D30AB01
-:10E42000A6501E7741E9F264A8A766FE6A0AE5795C
-:10E430000F2B7D01F3BCD39F7D98BFCF2D2D08738B
-:10E44000C2B8AB1E9982F98C6E1137ED16F1D2CCA1
-:10E450009DA7B91FCBBDEA1EBA6FCC3DC0EAC475FB
-:10E46000CABC7035999FAFEEB1BB7B66C27C13C648
-:10E47000F9D6704897F69E0A74DCEA0B6318EFBF72
-:10E48000D6C4DBCBFB6CE4FAE43D37BB76652E5794
-:10E4900092AE3C0F1867008EE35E3590F2E3DCBB72
-:10E4A00015E7E5C60B4F722765A2DE8549F14017D7
-:10E4B000FD841C6EDD959989FB949D29E27E621393
-:10E4C0000B108ED392CAB3B17F99179D2DF6A5BBC1
-:10E4D000724AA62B13DBEB9FCBBCEC9199EE3C1C54
-:10E4E000BF26E222E59BB5E5BDBFC69FD8354FBD2F
-:10E4F000DEC5BC26E22BDAFCF4F6F926BACFA9B0C9
-:10E50000DC5D8F21CA374EEF188CFA31F43B1CC703
-:10E51000AD31F913F2548C42E6F9EFFA7CEF3DAFDE
-:10E520001DD4E4B74B3AEBCC6F3FC7F3DB03F4F5F4
-:10E53000E8721694DF2EE946D2DD50CC6F8FC47A94
-:10E54000C67C6C37E2FD6394DF3EEA985FE4B77FF8
-:10E55000A8CD6F77FDF3BAF2DB4F8AFBDE4E5AF897
-:10E560007D49F23EA965BBF9F9EF3285DF27B5ECAD
-:10E57000397E9F94B40B1789F5551DDCB606CFF98B
-:10E58000163D3E97EEA362E21E5407FC04DB85F2C3
-:10E590005E527D1E4C0DDA83A437B790DEA5CF877F
-:10E5A000A979BC8CECC11A9D1E5D9D29EC4121CF3F
-:10E5B00098D0FF168A6F711D56B2CF4CA4772E7B70
-:10E5C00062B9D38E7541576CC70E3A7793EDD9E394
-:10E5D00031840B92CE16AF53487F95F0CBDD6E762B
-:10E5E000D13DC6DB7B93DE0AFAB6C863F6727B1BAD
-:10E5F0007005E3E177467524A19EBC734FBA1338CA
-:10E600002C7BA5DBFBA777E8EE9F7E4A73FFF439EE
-:10E61000FC0FF5B453062FF63398A5FF12EF252E05
-:10E620003A65747A1D81FB98AF74EFB084BF59ECE2
-:10E63000D7B5DE43ACBFEF59E63FE8EF235E2BEEE4
-:10E64000231ED1CD7DC466B55925FDE16BA3E65EE1
-:10E65000E21BC53A8B1DCC8BF7FC0E6D356AF6BFFD
-:10E66000D8BF81A13E147ED8A8F123981DDA7A8301
-:10E67000C40771BF4857785B3BE1692678A6D03D57
-:10E68000CF45BA7B9E259C3AEF79EE6F25BC1F7A69
-:10E69000F00515F9C1B5DEF7FD43DFEF7DA5FBBC45
-:10E6A000F5F774EBEFE5EEEE9E6FB9EF792DCB3415
-:10E6B000EDF5FB5E70E0A7DA7BA8C57E7BE0E7BBEB
-:10E6C000DCEFB64CE1DF15FBFD355E800674F89794
-:10E6D000C8530F22594E88E07CADD3AE1F1E46763C
-:10E6E000D6BB8E98321BD2BF9053E5424E8115C7E0
-:10E6F000EB025F9C3E1E47907F94DF5F51E8E7F19D
-:10E7000004834F85CE0FBABD58D19CEF76BDB79824
-:10E71000E7190FBBC8E3F4F4E7FE326FA8C215AEE9
-:10E72000BDBFA19B3C22E9C7013D9E99508F37F0A8
-:10E73000FBEC42DC73BC494D0ECE2372937F67B273
-:10E74000C59780F86C4B74C7671505F28D46615EFE
-:10E750009142F6A0104A513FC238CF764CB2ED8BB1
-:10E76000F9A3913FC23C1998BEDD3F989BBBF86F5F
-:10E7700060963B310BE4C971C5BEA600BEFDCBD08F
-:10E780003309289FCC78AE9D4FE7BEC9F85E7F3F26
-:10E79000BFDFE020FDC2F35385EC8733D8D990204A
-:10E7A0007A5D1726F21A757FBF40D853F2EF171C17
-:10E7B000872E1601DF9ED1C4F3A897C6B70A3B8CFB
-:10E7C000DFDF3AB7BF95EE7F62AE0227B7C3A57D04
-:10E7D000D54FBD16B979A5F8A2A5F1A735762EDBE0
-:10E7E000117355E7898175F3FE8F3F1041F2E6F80A
-:10E7F0000303C8CF17E8BF8DECFE19B5DA38E3592B
-:10E800002B3FD2E0DF6CCF679AF7FED88EB07EB098
-:10E810007EFF8B7DC64E03F89DDD6D1E8C7406FB5E
-:10E8200036352BC80EF63F94369AEB01575AE71946
-:10E830009AC73111272AD7F949DD51AAFBEBFCBA57
-:10E84000781E8FC62E95A5E90D46F7E474283D9CE9
-:10E85000A1FC2C9F6671BDFD98C8833C26F2208FD9
-:10E8600089BCC563224FF198C85394F9A3C714E635
-:10E87000C2788AE94AF993B315CA1FBD07F1AF669A
-:10E8800049470EE6DBD5E4FA672A2AE58FAEC4F5E0
-:10E8900087C81FCDC1BCF75D5977FE08F5F8533D19
-:10E8A0003C742FC9EF774CE67513A78F57B246110A
-:10E8B0003D78FBBAEFC37EBE50D416C2E797153A37
-:10E8C0004F652EBF69E265F24B1FC8E2E70BEB759F
-:10E8D000E5D62CCECF5E11E518F5C154CAFBD9643C
-:10E8E000A6BC1F18C765083AFFD7E767E5BF6E6E7D
-:10E8F00041BE21FD304F6425F273CF64EE5F89FD88
-:10E90000A599E76DF97D0998E785F13E786F063B9B
-:10E91000CC5C3C0F8CDFDF27F7E109B10F74917EEF
-:10E9200061204FACEAE0F14F908F8CCD726FC6F54D
-:10E93000CBFCA5AAC8BD1437F1429683BE83F9D299
-:10E94000FA811FAC5608CE5DFC70CFE0FEE8F3DF25
-:10E95000BB5BFFD9F9BEDF642506F2A782F2A65E93
-:10E96000C079C875CB7904FAB93C5E4B7F52C0DFE1
-:10E97000B53615E944DE4F9BAF2AB32686F8FE0371
-:10E98000B16F5549E57B711D4B6AB9BFADD31E57B9
-:10E9900036FCF863DCAF8356E273DD7DAF5F67D58D
-:10E9A0006B07091EB0CE99B8BEA075BE9B15E417C3
-:10E9B0003CBBE7C3DF20A8AF777DD79AC76CEEC119
-:10E9C000EF43ECEA8F860D0DD2A3CCF2FBFEDA7B8F
-:10E9D000C6CCF8F71060BC46617F340AFBA3294C13
-:10E9E000FCBD1A9D3DDAE8E3F13C8DF1268AD76142
-:10E9F000E2EF2B48F9BBE23D1EDFB32291D17B9CB5
-:10EA00001FD281E2DF4FF2A0F3BE2805E41CE0C371
-:10EA100019BBFB02C28FB997937C506FB03A119F1C
-:10EA200077BD7DB3B0ABB8BC2912F2A508FBC175A8
-:10EA300064F524B95328C61D6CA925BD7608F308D2
-:10EA40003F8BF0473CB05F638FFD5F0DF62D3910B3
-:10EA500068000000000000001F8B0800000000009C
-:10EA6000000BFB51CFC0F0038AD7983330385A31AE
-:10EA700030E45933305C07E2307384DC4B71049B23
-:10EA80009AF8A73C65FA374832306C02E22D40BC58
-:10EA90004D9274FDB7B410ECBDAA0C0CB781FC6E9E
-:10EAA00020FD5D9D816117907D07882F83F840CC04
-:10EAB000ACC6C0200EE4AB00693F20D607E2BB40E5
-:10EAC0007E9A1A6EF3EF69E1B77F9B062AFF1D1A43
-:10EAD000FF923A7EFD999AF8E5DF1190C7861FDB19
-:10EAE000911F1FEAF6B44927B4C207D0D2F54E13DE
-:10EAF00006860BA60C0C22D0B4BF17495E0D28B6B3
-:10EB0000CB04C29EAB074C7B66403E8E7C310F2807
-:10EB1000BF11286F648EDF7E056654BE002FA69A53
-:10EB20006F4C08F6042154B9C3C298EAB9441918C5
-:10EB30000065838486D80300000000000000000008
-:10EB40001F8B080000000000000BE57D0D7854D5F8
-:10EB5000B5F63E73CE9C99644E269310C240024E89
-:10EB60007ED0A8098E1030261372263F242401C3BC
-:10EB70004F695A699DA045DA8222DA5E6F2F5F19CC
-:10EB80007E1A2245C516ADDADEDE812A4FDBEB7335
-:10EB90009F60A9E586442610100D3F11ADDE7EB6BC
-:10EBA000DF8DDA8BA10D38C160E9F760F9F65A7B89
-:10EBB000EFCC9C939904D4EFDEEF071F9F9373CEA5
-:10EBC0003E7BAFBDF65A6BBF6BEDB5F758C944E25B
-:10EBD000AA20E40AFCA357DF6442E8A391AB785E65
-:10EBE000692741C72D84A4D9F7F6CEC820649E2694
-:10EBF0007B6B3D844CB2B7F4906242CA89CD63CB43
-:10EC000021A45BFA4DEF0C7A7F34C5EAB511F8F711
-:10EC1000002173085967A77FD2F2472FD22BFDFE40
-:10EC2000E85F2D2122115223371209BEB74BBCBC1D
-:10EC3000AE2DC824A49AB07F732F926A5A8C54BB0D
-:10EC4000EF6D243308A972D15276F6EE0A2B4F08E5
-:10EC50002D5F4658FDBADDF8BE8C6C1F929D701773
-:10EC6000919B8A687D9755E37B77ED07C409E56240
-:10EC70009E433FE00FCA83EB494AC61907FDFB36A6
-:10EC800072DB15995E950984DC1EE58BF94A481004
-:10EC9000F9D6C1BF5748D30CB827E4456C3F5DF0A7
-:10ECA000B1AE9FB869BF334A88B7967670529DDE81
-:10ECB0000D7C29AB563D367ADF5D336772BF46C89F
-:10ECC0000FCFB5679142FA796835F23183F3B1FB22
-:10ECD000DC4BEFDC47BFF7D511AF8DDE1FB07A27D5
-:10ECE00037158EA6C757979E44683D4F341D7260F6
-:10ECF0003D84FCED4A26AF278F90CEA6DCD4409C05
-:10ED0000EFC4F5F10D2E426CD1FB1D3AA96BD7462D
-:10ED1000977B0906733654BF1CE92CE3BCFCA14465
-:10ED20009ADBB1DD661CA7039CFE1EFD90A3BF10FD
-:10ED3000DE871D16DA8FE090853C4FABE81CAC4CAB
-:10ED4000067A37E996303CEF1C5443C00FE26ECF91
-:10ED50005A54349AFE03432B6662BF02AB0DEDFE9C
-:10ED60006090F65783FEBDE89847EBB9306871C9EB
-:10ED7000745C9FE0CF0F04DA1D2EF86E201DC7F3E0
-:10ED8000F10DF4EF1B12F3E3F1B9DFC80D6850CEBB
-:10ED90006EE4C7E085637974DC3A772A5EE8D77859
-:10EDA000FCFC016F47DCA77BC3552E5AAF2FE295C1
-:10EDB000408FD207099990037AD179D809E3DB48CB
-:10EDC000502F7C4D9549D3593FBCB207DE1F974168
-:10EDD0003E7CAE30F663841EA0EF06A0D38DD7A78D
-:10EDE000797B4FC13862FF36255D4FE9BD50A26087
-:10EDF0003DBBF54D7E05EBBB1C96411E573379CAD2
-:10EE0000F004365A81FFF7106FD003F512ECF74F7C
-:10EE100079FF7FC2EB13ED740EA6FB15A0AF9978B6
-:10EE2000414D6AE4F5DDF0BD6F15A37FDAC36B25B4
-:10EE3000E0DF75EBFBF11AE274EE80EF6981ECB56F
-:10EE40001109F836F5A1305E776EFC7D37D097BAA0
-:10EE50008524812D78A2DA9206DF3D316F4A12BCFB
-:10EE6000773651C5A7F6C0E7753DD043FBB3B35A1B
-:10EE7000413A770E52FED372CEA0CB0B7AED0C7ACC
-:10EE8000F8D5EB85F207393F0EF076BB381DCEA0E2
-:10EE9000CECBAD2D8472CE6010AF21DE4FE2598310
-:10EEA00072B78ECBDD416BE026E07BC6207113AAE2
-:10EEB000CF07CED74F867645FDE6F27B9EFD9FB30A
-:10EEC000E0FDC441F2AE75065CC32DD0DE0DD00F5F
-:10EED00027DCF7B54868A742A847FA650B2105511A
-:10EEE0003B9571A969FE1D1EB8AB413D1276A06C21
-:10EEF00050B548A9B17A568D7AB093EB41F56018B8
-:10EF0000E584EAD9610BE553F01CD5332A5F079AF3
-:10EF10002C38DECF4554B4C3A4209CB52865B41E5C
-:10EF2000750EAD9C09FC16FA34DA7EFCBFA15F3B7E
-:10EF3000693F0271EC9A684FE89BF9FDB8FAE60A5E
-:10EF4000A2BE75527D0B023F9B2C49F9A07F6D1626
-:10EF5000D41377757B37D397D5A86F19F7307A26F6
-:10EF60002D0FA11E8CA7773B3D2EBF02F537333DF9
-:10EF7000ED1C7C6FA30DC66339E176E27237DCFBD2
-:10EF80001E667A6DD633B31EA6FAFA503F73B644A6
-:10EF9000085C3D9B1B51AE692B49A87F09F4B01357
-:10EFA000F4B0F8FF1F3DAC82799CEA5D9A766B8FD6
-:10EFB0008BF67B7E84303CA43DD103F3784DB68D37
-:10EFC000CDE353DFBEF37E7A7FCCEA40FE1F9B4841
-:10EFD0001F16C3BD8C7AD79DB3357B1D7D3F3F4344
-:10EFE000C2F784AC42FDAE1578091E51FDF1F74B16
-:10EFF000644E3A947B7F4715FDFED501E28557AFFD
-:10F0000066CB58DFE141C2F498EB672DEFEF61FE6C
-:10F01000FEC2251202FDAC0048429F7F7C3632CDF5
-:10F020004E5F7D68B95C4472E97C2CF8C571460D71
-:10F03000D7FF5733641DECC6E1F529219283F5858E
-:10F0400041DE5E7DD81692697B17F2F35E0813C02D
-:10F050007F91EBD7D1F73DAE8F5262F57380CBEF46
-:10F060009FB8FC0E723CB1E3E6A64512E5EFABF9A2
-:10F0700079A85F17F23F9A4628ABEFCFFBCB19B8C0
-:10F080001212B6025E32D723BE7FD51DF8B244718C
-:10F09000D540E87D278CE7B97D1FCD802B714F408F
-:10F0A000DC351E3EF3091C16E9DB0C388454533959
-:10F0B000991395934991BEC3C037DF30C363A46EE3
-:10F0C0000D8E4BB98BF1A5FBE25B59F05D07E75B59
-:10F0D000D7505F16DAC73A633D5DD6FEE54DAC7E8C
-:10F0E000FCDEE762E32AE87999F7EB6949220C270D
-:10F0F000B2F1F3F1EFE72A7D136EA174CC3D267BCC
-:10F1000037D2477307FAAB491C3BB45B4A4379AD2E
-:10F11000B86494D7AE8B4765E00BA557067ACB232E
-:10F120007D32B3E34CCE7C5CCECA23A70DF65DB432
-:10F13000DF1539DD00ED5F1860F62A115F85FC1CD4
-:10F14000E2E3FCB2D0571272DC42E5E508A57FDBB2
-:10F1500018DFD7B86403DD42FFAAEC0E035EAFB838
-:10F16000946EC2FF467A4B9530F2AB14F8E549CC69
-:10F17000AFF5523AD65F36F0E9F865B62BA2DE2E2F
-:10F18000E063E168BA0808B5A05BFE3F9FAF9DF061
-:10F1900007F35F8E829E92FEBD72530ACC271ADA65
-:10F1A00093B26A89E172DECF46F896365527F4CAE3
-:10F1B00023A19F57EF9342B58037BC3F433FF142B5
-:10F1C000B1CD03766892E709A53F46DEEAF9F72359
-:10F1D0007CDCA0633FBB67BF9D05E5BAA66FCC860C
-:10F1E0007198EF79DBB18EF2FF28D79B8E0D7558A1
-:10F1F000AEEC1279F45618977CA66773795F7A386B
-:10F20000DF0E71BB7190CF9B6F6D08E0F5CD0DAB3C
-:10F21000F07A7AC35ABCBE7AE9450DC6AFB7200F63
-:10F22000E7AF3AA55D89E757950E1AE5E6650FC584
-:10F230003BB47CC3E08AEDB7D27E1FBF6441FB7C48
-:10F24000BC206F4CBC22EC8728F78AFB6755C0B7FF
-:10F25000C6014A6ECEE8F266792D23523BE0BF32FA
-:10F26000EFEB0AA1F67241F12E2D16C71C38975903
-:10F2700004F51E90FEB0649627311D65BE3EECE796
-:10F2800082F0EF144F4AE2722794BEC659E8A732C3
-:10F29000FD2AF3BE5BADD3F66A0B7735A25C0C2B6F
-:10F2A00016908BC6C2BD7C7C5D381E0BC47C562C70
-:10F2B000D785809EC10B48676FA13C11E8DB669142
-:10F2C000512E17786C886713B63FAC9030E89712D0
-:10F2D000C6713A4EEB01B93841ED1E7BDEC7EE69CF
-:10F2E000BDF0BE3BC7A679819F6E118F5865908F88
-:10F2F000C6FC59C7BD94EE5EB78CF8B2F752A59222
-:10F3000046EF4FC0FCEA89CA671997CF1330EE2049
-:10F31000C72119E73F8197457D5D97721F2DA6EDA7
-:10F320009D0859E37EDF546DD4C73BDC0EC37D7569
-:10F33000F604C3FD89C1996F36417B947EC0732466
-:10F34000B8DA407F17D87B68CF25E1FC7FF472F5EF
-:10F35000E0FD502E64A4CB4C47EFA5DC2797D27A72
-:10F360008FEF93514EABDD46BAAA2EBE791CE23820
-:10F370000DD4BE00DF5ED6151DFA7D625F4A68239C
-:10F3800095CB970B5F77006EA0FFB405B49D2AC2A2
-:10F39000C6B732C358CFF1C1F7BE0F76EA825D46D9
-:10F3A0003B57F9D7435B005E9D2A7EB007F87C800F
-:10F3B00048C8A7F273BB65A86F59C8F8FDD2E546E7
-:10F3C000FEAC593AC164FF8DF1A52A0F8B13CDF520
-:10F3D0000E617DA510FFA1F7959A312E34178C414F
-:10F3E0004CBDE5A6B850A987C5854A212E24CAE59B
-:10F3F0009051769FDE63FBE679DDACDF09F5DF42F5
-:10F4000056413C8544168F835B36F1F88AD1DE1273
-:10F4100065A704F250CADBEFB0B63B802EDFADCC5F
-:10F420007E91487ADC7895D98E10F220CA95E02337
-:10F43000710549C61CE83F2F63B67F9C2F6D743859
-:10F44000AEE03C10E4F8C51357DFCDDF67737D9F56
-:10F450003740ED66068C97EC02BB71FC12D1401F61
-:10F460004F5179672DF75F8995DB868176944B5AEA
-:10F470001E469096F7A2FE364D66FADB9D53ABA46E
-:10F4800031FB1957DFCD7A3040824F15D3713D9E45
-:10F490009FF7E452FA5DEF3E61072C3AEAD53E86CB
-:10F4A0007B4F0CAE4379BD40E515D83E5AEF4F6B0C
-:10F4B000B1F3FE7F96BE9BF57C44FF47E93BB35B0F
-:10F4C000C7872DD89FAA8B0AD6D37099E03C6ED6F9
-:10F4D000FF13DC7F7B597F53F3C27C58F83EFAC799
-:10F4E000E453EB3BF3430E0C106CBFFCDC7B32EDC2
-:10F4F000F9E7A6EF42CF85DE5EB3BEFF27E9B9F993
-:10F50000F9B72D1CF727D0D3A8FE07B1DCE61452BB
-:10F510000071B60E29D9BB2907F49DC57DCCE5271E
-:10F52000C8221E6B0FFE91F6AB850A4B2A65F51AB1
-:10F53000D23F0DE461E2640FD6779FA53F13EE3F03
-:10F540002491CC9B65C0CF643FCCBF924EC8C3947E
-:10F5500024C9E322CB6712F2B81CB0CBB43E6920B9
-:10F56000FC5789F2993C443C80076F90020E786EFC
-:10F57000A37CD26879A29C469C48FD37E4D742AE72
-:10F58000740BED5A18E3F025D6C17EC1779C3F96E7
-:10F59000BBCEDC4CEB2561E9CACDD17EEEB186B2A3
-:10F5A000BC1AF433F4E3FB206EF58CEA7D3E0EDFEB
-:10F5B0002D9FB29F607E909F16C6CFA025D9FB7C61
-:10F5C0001CBC35FFDAEB7F2B995ECB808FB78CE6C6
-:10F5D000A33448F9077C50FE7605FCC43237932FDC
-:10F5E000F9435587380D91EDA1E971E858C3E978E1
-:10F5F0005CD66FA3C886C855EDC89F0330FE1AF0CD
-:10F600002F837C3B46BEE6C92AD2253790B538BF4A
-:10F6100090B005ECC878E361558822C338F65D41A7
-:10F62000BBDBCAE9B3D1E7DACCC4E3253778236181
-:10F630003A4EE443364E07E61BE5723DA7FF414EC6
-:10F64000179827A8BF14EAA7FC92FFACAE8D374FDE
-:10F650006C17FCE7FC32973FF025D67F517EABCC90
-:10F66000F42978EDE3B66C525EE27113F22E0D1EB2
-:10F670004D347E6B4371F47B8E6CE1FD0D4A57A3D4
-:10F680000FF3B85CCA5574DCA07F35463E6EE6FDCC
-:10F690005ACEEBBD4BD2FF1EE4E106A9E91FE04ABA
-:10F6A000AAFB50FF40C6A1DCCD44FF6FFCFD06D095
-:10F6B0005352677C4F9F6FC2EF9AFB707D4A3C3F6D
-:10F6C0002CE95B64F6BE15BFD38DEFA91CB6C173E0
-:10F6D0002A2F449E09CF193FA99C103BBD6FDD75B1
-:10F6E000F79781AFF4FBC7B07E72DAF0BD150C441A
-:10F6F0003ABB4A33D9F559903BEE9F6E6ED691AF27
-:10F700002A59CBFD67369FCDE5F399FDAF6C1EBC42
-:10F71000E05231AEA524E9A130BDA6BBC23AC40374
-:10F720002790BE20F863CB96CA063BDF6C9A5FBE7B
-:10F730007C8F71FE5DBE3ACB70FFD587F20CF781EE
-:10F74000F5371BEA5BB16596E1FE9EED6586FB959C
-:10F750003BAB0CDFAFFA4983E1FD379E5B62B85FDC
-:10F76000FDC29D71D737C57CF788E5DDD54DB45F07
-:10F770009BE1550C5E54A2EB971686C78CDF51F1C6
-:10F78000F32873A01CC15084594E15D3FA67FF8823
-:10F79000FEAC33CCB7878239190015F41C4543FC05
-:10F7A0001FD4FBF233A378A0CAB3B231DEFC2BE83E
-:10F7B0005178393FE9AF8271D315633985AFD76A84
-:10F7C000DE08C661CCEBB58A671ECEEF667ADF91A4
-:10F7D0005332C02ED1BA3DB84EAB5DDD7C3A6EFFE0
-:10F7E000A825BCAAFEF1F6FCD0CFBCC4FD9A5B1CD8
-:10F7F0009181BCABED57944E23EE11EBE40B5851C5
-:10F80000529AF31CFA630B803E989F8B19DEB1D39A
-:10F81000FFD83CCBF8DFC0CB373DE4B2023E6EAA46
-:10F8200036D2D9C07114D54305EC446981E93DD085
-:10F830003903CA19F1520F97474DE1EBE573C81C24
-:10F840001C07AEB78B84DED6B0380771C55F47AFF3
-:10F85000BF440BCDC2F651FEC4F3D70AF292E1BB0E
-:10F86000056DC463A3F8E491D91B5D9580F375AB76
-:10F87000B78E96AEF2F278932E239EBDAE80DD3722
-:10F8800056B3F8537DA00FE3808DF78436C275CA56
-:10F89000AAB0827498F8FAAC279486D880F3378B94
-:10F8A000F32B4BF095F351D8F129AB8DE3D8586C7D
-:10F8B000E4D742CE4F339F17723E2E34F1B10BFE88
-:10F8C000A07C999D808F0B381EB5CFE6FEDD707A47
-:10F8D0005CBFF1591E1F13F2A398E635613F46E65F
-:10F8E000372EBF8F831D079CE7E23885CF7B89F4D5
-:10F8F000C89FDFB2C30FF1D60CAB61FD621EEF6B88
-:10F90000693E5BEF28CD9011F797BADF30C4994B71
-:10F9100047E2A3BA5633272A9F5D03CCFF68759F41
-:10F9200096619C1AF219CEDFC2F923E27F07F8BA7A
-:10F930009199AEA3D382D9808F8E5D0C66AF2B8652
-:10F94000F88F8472D279EB03D92C5F80C773797BEF
-:10F95000AF0C05D17F3B3630F6FAA2C0F966B92963
-:10F96000F586709DB174A05D86FED645E81C44BB4B
-:10F970003E2FFC0BD95384716905E86974AF503090
-:10F980005EE66E5120BE5CE7DE5505FCF091D06668
-:10F9900027C4D53C92370C7C2C64FABB8AFE17AB8B
-:10F9A000BF82DEDAC18002FA5EEB31FA353E2E6F9D
-:10F9B000356ED3F3FC5A94379F49DE3609399B4E96
-:10F9C000A6C7CA99885BAB43B95C5FE3CB5927E70D
-:10F9D000C7BFF338EB1F787CFA1DBEAEF7BB0D1E18
-:10F9E000BCBEB2A1009F1FD9E0C5FBB73794E0FDB4
-:10F9F0006F21CE4BEFDFE071DCD73734E1FDA90D8D
-:10FA0000CD78DFCBE3B4428EB7F2F5941AB913E3A5
-:10FA10008B0DDE80DD15234F0D9C6E147DC021857E
-:10FA2000F1E3AFB669FB1590AFD3237A42D05E2CD9
-:10FA30006ECCD9BD8DF2C5F65D12005C693BF4AFAA
-:10FA4000CAF554FE1BEA72AC2BA1BD60BB320BE4BD
-:10FA500031FCAF4A1E3C6FBCD57A779CF6453B899A
-:10FA6000DA37DBB72575463FB854C4D1070241E801
-:10FA7000E7A4814018E82B75AB9E7871E1EEC92BA5
-:10FA8000DD204FAD67036E90A7D6C97B64E6AFB3A8
-:10FA900078B8CAE554942F75EF36E8A1CAE9EEA00C
-:10FAA000CF81DE8E71F4E000E79B28E753C2B24BB2
-:10FAB0004BDC3F9F295EBE458AEFB7265B19AE75CA
-:10FAC000F2F5556A3315D0331051A07F12151BD0B3
-:10FAD0002F4D63710B8737C0EDB2711E4F2B696AD2
-:10FAE00002BBA465106F2D9837ADDF0D722397CC44
-:10FAF0003B0BF32C298CB1DBE0F798FDFFD87B1989
-:10FB0000A7AE604A3A5CCDE5187F352E426DB7321C
-:10FB1000FA1EE3710EC15F8DF3B7D473ECDFC0AE94
-:10FB20003EE665F198C732D8BAEC85921588CB4A83
-:10FB3000B95F60233BB07C3269C7EB66AE67174A9A
-:10FB40004E13D07B59A1B83903E8B18782F47BA763
-:10FB5000C9BE2B9A91DF12E5C972C0D7038AC1DFF3
-:10FB6000904A989DB783BF0E7E0CC72F513F2F4000
-:10FB7000AE00F3AF124F6DB11AFD31711D502C283C
-:10FB80000F2EAB299FEEFF7AFE1DFD5CF927FCC40A
-:10FB9000119C77F8EB04D663443EA128FF8A29DE46
-:10FBA000A466B3751873BD775819DF2BAC1C1F0BF7
-:10FBB0003CE133B79314047EAAD49F4A9246D7936C
-:10FBC000A83D3230739CB8F5466CFF94E262FE04A7
-:10FBD000CF07A26EB964F04FECBA3B76BD7FE47BF1
-:10FBE000B7C5A0A7A3E966FCF9BCE95D401D52B802
-:10FBF0002E1476B884E1C9451E8A27E99F8B3426E6
-:10FC0000A727FD526813CAA96EF0B7EA4A6ACFA2C5
-:10FC10005DA2FE883A87E3744A7F1BD44BEB797D63
-:10FC2000B2F86EC49E58AEDC32BA9EA66A867B4895
-:10FC3000F097F363E3074D545C0A6642BDEC7B5AD0
-:10FC4000B4FB4A3C3AB8DD6A2A7960A1E6847B5D60
-:10FC50007A1AF05E610C3E00BEE6DB8C7C36D9BFC2
-:10FC6000EA5176CF686FE751F9DD4FDBA993D736BC
-:10FC700042C8BBF68915FB5E4572841FE2895BEFC3
-:10FC800071F8E376407F46BC42BC2C8FA32AE8691A
-:10FC900044BE6748249403F41BE998976DF2C3327D
-:10FCA000CCFDD881E37848A1F3081DAF43741C77DD
-:10FCB000A07F1CDF9F127E5E45CE30FA53C2DF2349
-:10FCC000DCDF73D1FF62F158392FEF7FC8A300FE4C
-:10FCD000F5DB4D71E691FC6382FE540531D25BCEBB
-:10FCE000FDBE7293DF27F4FD25612F855FCBEDE12B
-:10FCF0001DC29F2A1F7B7DB9C7944F574D096FBF07
-:10FD0000063D204015AC3791113E19E4AB3BE7FAB4
-:10FD1000F630E5EB1DDE24B6DE42E954843D473E75
-:10FD2000319CBD9097BFC3A3A2FCFB34B67ED138F3
-:10FD30004EDCC257C2D60D4ED925361F04C99B24AE
-:10FD4000263FBCCAC3ECB566928B6C4F5335AC03EF
-:10FD5000698AE40D91D1F25ACDFD39F87E3D6545B1
-:10FD6000753EF5C967C6CB2FEF83D02A29A7343C4F
-:10FD70009B93787C756FA40A86E76AC7979870F69C
-:10FD8000A9C87B98D775A150C2759FEE9C8FD13FB3
-:10FD900010EB3B51FE1DC57C145FC947E8AF8CE4F6
-:10FDA0006DF1FA168AFA4A0EE37ACDF75C87314F85
-:10FDB000E424ACE3D2EF4F2A110DFC90F9025F511D
-:10FDC0008E86053F73204F82D517E67ED529FB1B13
-:10FDD0000EB09B22EFA4CB27D7C58B7356C82CCE71
-:10FDE0002CAE37A96CDE99A3323C27EEC5F88EC83D
-:10FDF000937CBC98F9E1DF318CBBB97E28DF8CF1B4
-:10FE0000C170E158FE68A389CFD3543EEF71BCD1D5
-:10FE100019191BD78A7E9AF960EEA7F93BA7CAE2A7
-:10FE200065F758F59BD5D9D176C47C672EBFC81E1F
-:10FE30003F2FC75F628C4F9AF372EEB1064A55CAE4
-:10FE4000CF2A45DA92EA41BB86FA74E8B28638E6F0
-:10FE500042E4D01618D623C32C3E5A4EE4908DCDE2
-:10FE60000B8DB06E27F446C8BF998EF1DA2F1FEEC6
-:10FE7000477FDC7F29520DF27787AF1BEDEA026ADC
-:10FE80005727C4B1ABF3E4C12D13407FBD6C7FC7CE
-:10FE9000A9DFF755E3BD26613EAC5E9EA74C003955
-:10FEA00070C58F57CDE572327A3D4FD8559702B85D
-:10FEB000C11C6F9BCBF56EAE491E02EA080EBAED6F
-:10FEC0004ADEF8E394481E2E442E3C182F8E2AAEAC
-:10FED0005509C6F73E62E26FA731FE6CAE47C48398
-:10FEE00088DC990DFA2CFC5F73B93695AD7B1C2923
-:10FEF000BA97C4E655097BA096B46B1017EF2D197D
-:10FF00007BBE30E70FFA89314FACCA6E5C8F7D4AF9
-:10FF1000D11F01798CE2A416E6AF96B4A0BFBAB0A7
-:10FF200090EF0B2ABA17FD53E157B7DEBE17F3B9AE
-:10FF300044BE96F04FCD74F74E7E11F379C6A35BA5
-:10FF4000F8F1C76D325B87A07EBB07FD768AFBE2C6
-:10FF50007CF78A8DF1EB578ABE0BF4758B5577B71A
-:10FF6000C03A6391CDFB7C9C7118B031FDEE4DB071
-:10FF7000DEFA0758F8988DFD403E98E71BE1C78AE6
-:10FF80007D4A93DC4C6F1BB81F5B56D882FA98E60B
-:10FF9000A67E2BF0CDCBFC563268F453176A7D5900
-:10FFA00030FEE6F94E1EE67EED55FAAD5B93981CE9
-:10FFB000055CC4EEA6EF93140A4DE9FCF7A45C7946
-:10FFC00018F8B1358DA03F70324D0DED8E136F785E
-:10FFD0009BCB5B8DBCDA206FE51C97A8D5FD1AC4BE
-:10FFE000034E0EB3385EA271DB66C2E9B905C46F79
-:10FFF00073C235E2077ED07BDD86D708E6677FBF18
-:020000021000EC
-:1000000068656EBCFA76B72971E7A53FF3715B2C82
-:10001000F2B5EB583CF2BE4215E3C293EADE3D8AEC
-:1000200072DAC8E574810DFBDD5BA4E0B8F4DE9EF6
-:10003000D30EEB9ABD4576CC47E92EFACDEF215F82
-:10004000BBBC4432E49708F92D075C0DF5DB59BCC5
-:10005000F33E37B3C3BD1AC72F3C6F640D1FD39354
-:10006000FBDE77C6E68D2C1172DFC8E3E426FC4484
-:10007000CD48DC751C91477CBE91C585EF13FDDD35
-:10008000BF770BE85D03979BEE8B2BDDA89FFB5999
-:100090007E5E6B510BC68BBA27BFA5C2FD1AF7193E
-:1000A00015EECDB8428CEB7D25BF62F9917C5CD713
-:1000B000403C9ECAFBCB99375B3DF47E71F8762BB2
-:1000C000C43B457C76D43A145F4FA965DD27B56EF5
-:1000D00086AF8F663A487206F04B0E49C0B7701271
-:1000E0004986FC33B7359444EF1B94FE69805B1C52
-:1000F00026BC78FED77BB341BF8FCCF8408176AF6A
-:100100002B79B715FA31A5642FC6FBB3F6EFED498D
-:10011000A7F52C2C205EDD339A9E1A3E3FDD97C159
-:10012000F285EEF38682B0EFECDC65B69FA2F2D7E3
-:100130006F54C1B4367A5D46278043C4BA8EE2E676
-:10014000EB227C7D825CBE22C58E5B8312B083FD78
-:100150006D2D79C309F42EE67CCBDD27B7807C5763
-:10016000FF7AD657404EC8ED36D774DAE039D76FEC
-:100170009DD76BECFDBDACDEB9015ABEA1706FF628
-:10018000CAA2D1F665447F0AFFB22140E93939FF9E
-:1001900037D980DBDEA076D703ED72BB65F697CC4E
-:1001A000F3AA392FC6DCEF4C65519D6D368CF78F65
-:1001B000DD39317246EDC00AA07FCDD376CCE34A5B
-:1001C000DBFFBA2A837DA3F8BD568ACAD11A2E470F
-:1001D0000D1AB37FAD4524B44902F93BD358067AD2
-:1001E000F72ACB379CB4FF5D963F6A9A1F7AF9BC19
-:1001F00021E6E3DEC9EFA1FE9CDFC7F52568916229
-:10020000E3495A4964298C8BE04FA7C9DEF8ECF129
-:10021000E326EFD8185E2DD7D87B8DDA6F58D73606
-:10022000BFAFE4FE54155C63E685076D0CF78AEBFF
-:1002300035E4213CF55DAAFFDDDB0FB9EF463BA5B8
-:10024000216E5FB37F6F01ACD964EEDB5BCDED0552
-:10025000FA6532EFE724E2413BB550B3B3F50393BF
-:100260009C5B4B7685013E8B791A1C7225336A475D
-:10027000E4D838441C3F8C04F537F363F2BEE8FC45
-:100280004EC0AE54B959FCD52C276925D4EEE020D8
-:1002900050EEC5ACFB9AE5B6410BB8613D9BEACF89
-:1002A00059B6FE49E72B884FC88D5E1C4F2E9F160E
-:1002B000FA1FCC7F0EAF513EAD05AA01AF98E9F809
-:1002C000A9CD88FFC5FC9CE6EE47FA166AEDD9D0A9
-:1002D000FE24773FFA5BD4BE67C355C899B0D723D5
-:1002E000F257745B3DD877906B58223F59322B19E7
-:1002F000EC60839BE114628AA7F7BAC7F6377A4CA1
-:10030000F278D2C5FCAB861292EC4A057D6771A7E4
-:10031000DE47D3773962E272FF640D74D862E2EB94
-:10032000CEC22FD6BB9C606758FE5629355FD6BC1F
-:10033000683C53C44DC57A9F88938E8A671676634E
-:100340007E9755E45DF0F5BF51793F09D61DC5553F
-:10035000C4336D9BDA152F5F2F413CD6C8E370C3C1
-:1003600033C78987B2F803C567BFB54D1C1F9FED22
-:10037000E17EE600180F7A5D6573E155837C144ACF
-:100380006A6F527CDC7690FB6DD7A29FC764F88EB3
-:10039000B5F327937C89E7513CCCF46052C9DE9ECB
-:1003A000583C5CDE467943C7496D23D3486A62B93D
-:1003B0005B3862F77E6590AF117C3C0E2E16F275AD
-:1003C00051D6FF669B98B85C03A723D1FBD6225B6E
-:1003D00033E45BD17264522ABBDE40AF3D33F66634
-:1003E0005BE8F3D7007FC5D0D1FBCC7EECC71F54B0
-:1003F000B6CFA6F7E2CA5CC007A7143DD53EF1EA26
-:10040000E5C7AC4FF6D9BA6723D5BFAE6C3BCECFAC
-:100410005D6E86435E879231F2B44E0D5C679F8DB0
-:10042000104427E9DCC8093907A3597D75FBC4EEE0
-:1004300072F43FD414333F6C875793619D8FC9CDBD
-:10044000236A3FE6E3DC456BB7D1760E6B72E60AB2
-:100450007A3FD3CEE4F170D01A37FF79A69DE1E759
-:10046000756AD34CA093B4AF453D6B91E426D07F21
-:10047000E2BDBAF8DCE68EF879A555D1FAE762FD5F
-:10048000FB68FD801BBC3CFE4E5C9971E3EDBCDF5C
-:100490006142EA405F1E4B33FA9B3E3B9BF7E646C8
-:1004A000EBAF8FAD1FF3B366E3F30538CE2FB0E7A4
-:1004B0000576A617FE3C96D726F828EA5D1AAD6F9A
-:1004C00029D6B79F7D976FE7EB069C6E81F3CDF938
-:1004D0004F35496C3CA2FBFA08DACD528AC3F17C55
-:1004E0008548E830DCFB09DF9729319CDE95C2F6B0
-:1004F00031755987F09C85EE4F3E7E07F66B2A8A50
-:1005000011DFDBB8EC2897F7C850AE34FB8223F636
-:10051000DC8172FEBE7BD8B8AEAA73BC7390F07C4F
-:100520000D5E9F3F419C4BE0F80E5E3EBA0ECCF64E
-:10053000294E1A60FB122B5CFC9C88B46FA35F2DC4
-:10054000F47CEB276B199E9FCAF7AF65EF9163E9C7
-:1005500051383DA5CAFBDFDC0BFD8F1017C659C310
-:10056000BF73E4D07EEBC7646F129436F9193E8EE8
-:100570006BCB396E4D84EF8F4A81E7C22CBE69C0C8
-:10058000F94733FF59061C5A1A66EB4C151CD7570E
-:1005900028A12C981F6AB3593CAAE3625F16E2F9BE
-:1005A0008F3371BEB84ED985FD9EA20C619EC43CAE
-:1005B00013FECF1A20E837F8A9DFA0C7C12D357286
-:1005C0007635ECCF2DF5B0FDB5A55E56BE8BB61FCA
-:1005D000A4E52B2FFEA007E0FA687C6FC429E59EF6
-:1005E000A12A342326DC7FCD783A9BC5A52A4C7EF0
-:1005F000829007CA0FDC37DFA13C68073EE4665BE8
-:10060000987F30D5B21CF846ACCC3FD8EAFA961D9C
-:10061000FD03FA1EFC830AEE1F545C8E64817F602A
-:10062000EE8F90AFDCCB1FA37FD03DF431F239FCCD
-:10063000C99E2CB0CB228F5CE07A513E53F11F0152
-:100640003D2E37E17C9BC0F9C36B09E0FC0AC588ED
-:10065000F36D5CCE2A38CEEF80F52E90D7B399C7D4
-:1006600073683F0E0A9C3FEC32E0FC52CE8783A0B9
-:100670008F3138FFE059B6AFB22B3BD780F347FC40
-:10068000C84F89F37D49CCEE081C5FCBF18278FF1F
-:1006900021B7E3667C6F7E7FADF89E70FC1EC5C5FA
-:1006A00046B9EDDE9E8BEB2AA52E3BCA6DF9406064
-:1006B000F801FA2A7378ED1F9F007EBB1D5EF8CC0F
-:1006C000C6C765DCFC4F13DE9F44228753416FF29F
-:1006D00059BE515AB60BF5A482EA496D3C7D30E310
-:1006E000FF6C366E554A8BC88B1B13E757682EC4B8
-:1006F000D98A527B5538DFAC5775F9B631FDD2AC8B
-:1007000024230EF30BBBA93C1044BBA93C1006FDEF
-:10071000F15F66F933DD9F7CDB1D7B9EC3566EFF68
-:10072000853D17FA78F0938F791E8D49AE958F1C11
-:10073000B1FB8A0F66331CF2332582FA7BF0F2CCD0
-:10074000E4D8389519E71FE438BF82E3FC8ACB4C24
-:100750004F0E8EC6F9B725C5E036E7E56588F3AFDD
-:10076000369F40F8AFB526FFF55DBBD17F4D24D74E
-:10077000FFC1E7F3283F8736239E5586D87CCAF908
-:10078000A9703C6B031C790BCEA3B83F5EE8F1283F
-:10079000BE5A3F32CC937E8EEF0E2A578D679B93C5
-:1007A00066272E57310E9EDDFA89DA8CFCE778B683
-:1007B00042E0D9BF45B262F12CD1180E3BF8CC25EE
-:1007C000ECC7C1348663CD382C31EE60F77E4DE244
-:1007D000EB30463C21EAE94821D9189F93DE46BE1A
-:1007E0007559FF12178F08FC61C61DC4843746EA8D
-:1007F000059C027860F88203F6C1761C93F9BEBAB4
-:10080000CF8A4322722CEE10DF75A5E8E8CF0B5C8F
-:10081000B2F593338833B60E113C3941E0128A3772
-:100820000E833FA7D3F93BC913A55FE01381374679
-:10083000FAA1B0BCD12E17B7FF09E2A09F373E1135
-:10084000B8C4CC9F8356865B3A2EBEF599F08A19C0
-:100850009F98E99DB76B474F2A2D373F7F08ED5092
-:1008600087B70FF799770DE766001FC6C72D7E5C27
-:10087000871F895372FC71ADB825115E4984330E10
-:10088000028ED1A238C68C5FCCFCCCCD262D10F7C1
-:1008900017B82691DE42B97B9D51BC93A81CB5DBED
-:1008A000888312D6733972AD38E84CD298388810E4
-:1008B00026372C3F28113ED9EA7569B1F9AA623E64
-:1008C000E9CEBEF00EEE2B1F50F17C84EEB3CC7E51
-:1008D00026C247874C7A7710EC85169DAF12F265D9
-:1008E000809DF3217054A272578B9FC43CE24B62EF
-:1008F000F344A2F5C9AC6486B31EC965FEB2F97DA6
-:1009000034DFC488A3484611CAF3FD7CDF65225C4E
-:100910004548C4C9E254417CBE8CFB9B181B9CC358
-:10092000F30D28A94DF9241FE685263B1BAF93B391
-:1009300025F40316C1732A4FFE6AB63E74BA88D9ED
-:10094000EB937E1BDAEFE3E7593E62770A8BB39EA7
-:10095000BC35C9BB9B92701EEAA5F3F0E9A4BE6248
-:1009600098F767887EA6B37E2E708457E3FAF8ACBA
-:100970009B2DC19CD1FAFD4832A7235DC375B606F5
-:100980008E3F619D306BE6E8FD04CF24E7209F2079
-:100990004F3E8B96DB62E9FB7E2E7D946461EBAA71
-:1009A00066BEFE99D3038CB1C5F0A131DFAE2751ED
-:1009B000F94FBA89AD4F7555DB301F270996D269BB
-:1009C000BDDB0A7253E2C991E897F9F94F9399FF99
-:1009D0007D7A6A04E7B1533CBF778D22050973B075
-:1009E000B09FCA8429BBB6D1A25F4E66E7D59CFAF8
-:1009F000F5EB18273A91C6F9A04B98C770126C21F5
-:100A0000C4FB5C5A08F665D2EFADCBC6C8FBE8F371
-:100A1000D716B0F53242245847833F7247F37B49DB
-:100A20009D8CFD5EE2DAFE00E8E3E9BA371C70FE59
-:100A3000E4C2610B01BD5BE22ABD179E77A7303986
-:100A4000063E036E5A52FDC56FC2F3C646E3781CDC
-:100A500049CE65E7C8286C3C60FCB2668E6E97CEC6
-:100A60007E01353386FFBEDFFC9D1433AF88BC1595
-:100A70007B823CBE44FD9662EDAF1C8D3B4E2AD975
-:100A8000B503F6C73415B3732F1A3C2408EBBC0D1D
-:100A90005E12CEE1F285F9343DF96C5F10D7AFB448
-:100AA000925D6DB910A71C56D8FAB3693E29A363AD
-:100AB000959D0E7173363E2767CBE8D79595305CD0
-:100AC0005FC6717D83DE82EB7A8D8FF66CCF85F702
-:100AD00072768DDFC3D74763F847F6B338DC2293CD
-:100AE0009CA798E2FC655E537E20CFEBEB2A78CE84
-:100AF00005F2F3483A979F9912EAD1EB92E7D1DCDD
-:100B000098F9A83E59E41F118F35463E46E4818F7F
-:100B1000AF99EF89F869E693592ECCFC3E9962E2D1
-:100B20005702FE27E2775989FFBF94BFE7AC362B07
-:100B3000C86DB7F5836CEE0F1139C69E98F9764EE5
-:100B4000F3A4809D383DCCE69B13533D5FC173B049
-:100B5000A81EE3399E5C1FA2E340F5C119ABCF6F1D
-:100B60004F037DA67266857A1A75494F02FDDBB781
-:100B7000F501EC37E8A933AA4766FE8FD23FFABFEA
-:100B800022E8CD1BAD47E6BCB14FAB7FDF017B0E4A
-:100B9000F182640FF24FD8D346E2FA4AEC3E56B1E6
-:100BA0009EDE9DD3DA04FBCF1B062C78DE4FC7F008
-:100BB0008BCA0AD8D75A27E1B4A6913EA4576B63D3
-:100BC0007911D73FFB3081BCF547A7122FD82BAD49
-:100BD0008DE549D0F798272170BD38BF91BED75910
-:100BE0005E88F19CA514AF31CF67F16025AE2FF47C
-:100BF000F0738F46FC0B22E4D2B8BFA5159E4C8E35
-:100C0000EE876ABB18C2F84C4782FD2EE26AF617DF
-:100C1000CCD723877EF1CDBD905F91AFBA005294BF
-:100C20000F87ED50DFF70B0FD5613E5B9DE48275BA
-:100C3000B7231FB76F86F38E1617BE1737BFE7C0EF
-:100C4000B9A7BCD08F03D61DDE74B00F9BD8BC955E
-:100C50007443E1D41563E0A3409DBF2E6746E27C58
-:100C600092D50E1EF7EFFEFAEE47607D7B50F582BF
-:100C7000FF52CFFD8E066547F30A3A9E3DF325EFFE
-:100C800046FABCE7C627D61E8238EB5915384E7A8D
-:100C90002FEEC9063FE3B567ECE87F1EF978CF4F2A
-:100CA000309F64509D03FD1DA17FBAC6DE9F7FE982
-:100CB00018D899C5058B8BA19D2485EC0079BA6E57
-:100CC000B8FD1D3817A161409D0DF66771DD2EFB43
-:100CD000D7804F75BFB24F07FF63D85303E3999D89
-:100CE0001CD01D541EB30A73BE9701ED7889574777
-:100CF000BEF611E0ABC84310B85EF8931DF3735213
-:100D0000480C5F4F0FE7A6603CB28EE72BCC979B59
-:100D1000C03F3EED9A9E8271C83A96A760E6D762C0
-:100D2000C0E9A9405FCED49571E6EFDCBABF6C088C
-:100D300040DCF7465B733C7E0738BF93FEBC7237DE
-:100D4000F437E9C77617C0EBA4047998790E1E8FA3
-:100D5000735F5D7C44E019CA57BB3526EE47F1FE50
-:100D6000D71C3171976B6DFF4EC8D99E0D718AC02B
-:100D7000FD504F198F8F94F3F84822BA4AC7895B08
-:100D80005039423E2D86B8C52DEC7A03BDF6D4E726
-:100D90004C35C42D88EE063B7B1AD6E1008F298B9B
-:100DA0003638601DEE1C8B5F2492DFC5F97BEE3C6C
-:100DB0001463EF7AAD7A36F8B93D37BE8D7ED2FF37
-:100DC0002EF91D91B3BA5FB5C1F959DB0A174F046B
-:100DD000FB1723C7CF00FDD72AC766FE75CCCF4BC4
-:100DE000215A549E851C8F964B09FD5121DF89C6DF
-:100DF00003CA813F2AE43C51B9D3F36F882BFFD15A
-:100E00007A86C6D4832F38187E0938D8FC524E749F
-:100E100017D8E17959EFA0DFFA0AB7C7237292D247
-:100E200077E7FDD4EE049FB7E37A79D74515CF591C
-:100E3000EF7A6ED5CF60DEE819AE749DC179DCEF34
-:100E40005A42E9BA11FC87421C9F1E25264EF827FC
-:100E500087F01F8C79BDFFE2FA63BA9FCDB39A9FEA
-:100E6000F2FB163E4FDC94F35C32CCE7B7F07D1317
-:100E7000333AD5B8F3328710A430E3750B40FFC284
-:100E80007DC672DAC83EF4760BAC03DEF482E93D2F
-:100E9000DF3F6DCE83FCBDC3B4CFC934DFDA2F8E04
-:100EA000EDF7FE12E6270A255EE079BEFFC2CF0D00
-:100EB0006CE7E706BE08FB59E9751FEC67A5CF5F35
-:100EC00082FDACF47E3FDFCF4AB2AFEE7C7871AEEC
-:100ED00093CAF9D036396488878A7DDE1D706E1218
-:100EE000E001B7CACE9B7351B405F9281C2F5A1CD8
-:100EF0003EBB4AC755FD13C17C946F9DED4379D825
-:100F0000CEE759338E11E73A9AE952A37C54204E2A
-:100F1000D53535D0DC54C8070CE466F6A45DDB6239
-:100F2000F0B4A631B968E57E5BF022093D2F45CBD0
-:100F30009FB848F66C6371B6A00CB803FEA2225CA1
-:100F40003F4010C7D5176F45FF0B7020E0323C675C
-:100F50002C17F6A5BE8478AE7E78CEBD0CB7E8A37C
-:100F600070DC08DF64E413C3E7C5AFE3F9CCF50335
-:100F7000F1E52D9AC7D4DC931FB3FFA07138D0C818
-:100F8000F1912BF67C04D52457E67AD28A251C975A
-:100F900005053CDEC3D73FC4786E5EDB87F91EBD16
-:100FA000C5360FC417CC38D18CF3D562B65F4CB9B7
-:100FB0009DED5BADBF48303F1E0526337A0E9BCAC0
-:100FC000F3793B5C012FC4311BBC26DCCBCF912ACB
-:100FD0002F30E27933DE57075413DE0FB2F9701366
-:100FE0001BCF93E709FA51CFEF64F181036E0F93A2
-:100FF0003F1242BFA7C26DB9759B07D6A9D83ECC98
-:10100000D26182F192D2010FEEABAE1824E1EB6710
-:10101000E079C36D789E90897F1510EA4D877A3C00
-:101020003D13219EA7902D708E4CA6BD45073D50C7
-:10103000DD6B71DF0DE4314C6072648FE5AF9A7C3B
-:101040007C33A840058FAB89DFA79864DF8B7210D3
-:10105000337E63AE87A95CEEC4FA969FD7EF1F6418
-:10106000796D663948B30F613CBE7258C3F39ECDAB
-:10107000E36E1ED74A2DF2FEE3B03FE362B2771370
-:101080008CB39D8DB3184755EE94611F0751D878E6
-:1010900089F52F73FCB5CCB43FCE4C97381761BDA2
-:1010A00066DA2FC6717C25A7AE2D69AFE17CDA4ADE
-:1010B0006E6746E66D7B1E5FC762E7991E181C7B54
-:1010C0001DEB808B9DEF475C8BC7B17B9B98FFCD61
-:1010D000CF11282B21C98073CA060993AF472D2150
-:1010E000474E6CF99061FFB87370593D9EC7E87226
-:1010F00055439CAD8CB0F54A7D80E0FAA54EF6CA0A
-:1011000081987E89751095C7C55489F54BF0C94CF7
-:10111000DF5DC3467FE82B41E3BE873B1F36EED33E
-:10112000F8D2DA2CC3FBDA557986F7359E9B0DF79A
-:101130005F741BCF09FA42C0784ED092E62A43F979
-:10114000454DC67382EEA8339E13D4A0DF69D25FEB
-:10115000DD20DF5D52DF0FA1FF16C7EFF3C68A0760
-:10116000978FB76E1C64E706A11F1867BF8B795F66
-:10117000DB079AC00B463DE809FAD9B93A039E9DB0
-:101180007E7A7F8878157470F9F941358495AB7152
-:10119000B3F596EA8CF8FEBCB083E6F50A71FE5F03
-:1011A000D9601FCA41B9E9BCBF52F7BCB8E779BEE4
-:1011B000A771BC20CEBF4870CEC5A8F9FB6AFBC79B
-:1011C000D799C6ED1F6FB794F41D76E624EEDFD5F0
-:1011D000F66B248F0BCE1DA4FCE8834793D97B8D3F
-:1011E000EADB96B4023CE722C35E29A54C8CC63BE1
-:1011F000893EEBAAF2CEBA791C9FE84BAEEADCD26C
-:101200000CBB87E9BFCEF0D116490FC13979E6751D
-:101210005395CFA79322ECBC0B1F3FEF22690BD154
-:101220000B298B829504D7F183B9F6D06609F2C6F3
-:10123000D97ED2D61B2D38FFB40EE93BE0772DDAEC
-:101240006E54703F638DAC6179359BCD4F3EC8B114
-:10125000877C89D7F466C3391DEE4D2ED013F52750
-:10126000EC7DA2FE744E569BE3F90BC5294CEE4F64
-:10127000294D8529281FBA9BAD4784F0DC33917F27
-:101280009B28EF96024717DA6D22F0011BBFEFC1D2
-:101290007A4A1CFDF5A730BFD8572885AC9047BACD
-:1012A0009484AC63F8959D6E4BDC78C64D29DC5F69
-:1012B000BE7C05CFB353C5F97A59EC7CBD6ED3B96A
-:1012C0009537F17E1E4AB1E3B53B670FDBA76A3A5B
-:1012D0001FBDDEB392C4E25971CE8F1A790FE34C71
-:1012E00027C7395F44AC3F6DE7FB97AB2E5A9AE2B4
-:1012F000D1FF618A82743CAF59E3F6EF5B9CDECE8E
-:10130000695E3C57B5F5490B9EA3EF73B74EC1FD1F
-:10131000DD295F232CDEC5E8AFE77AEA73873693D1
-:10132000145CA77E1A7E27442DB1412C8F9CBCB142
-:1013300005CF85DD0E797339D1FEA58875EB9D87C4
-:10134000EAF28AD9F9F310EFA91D6079E50B4B7623
-:10135000F13C927EDCAF68FE9D92D2BA800EF3F231
-:10136000C2C6F066C43F5E8F1F7FB7847837E2EF56
-:10137000A88CDA57A921EEEA1C6672DFF9736F3781
-:10138000FE0E885BE046BDB126337A3E58F9D0A107
-:101390002DB004633E1FCC7CBE90F0CB5413AE1432
-:1013A000FE5803091D56A4D171E644FED863291CDA
-:1013B0008FDC48FD313AFE77D9583EAD6FBD5402FF
-:1013C0004E63D27A6932D8AF1FF1717AB33C80E7AD
-:1013D000B4B426D8677769A45C18F73375E604DCE3
-:1013E000DE31CADF9422B37D7997D9F91EAA9DE533
-:1013F000718D5C79FE8B90EB594E1B962F7132BD2F
-:10140000A8B8F242D658F367A92F40A03FD4BEC473
-:10141000CD0F7B3185ED4754C3EC9C0AB5EDBDEA99
-:1014200078FA2CF4709DDAB40FECC716696D2809B0
-:10143000EDC0D59F5F798BFCD9EDCD654D3F9C42CA
-:10144000FBFF9AF5471ED08FCD01E3EF4B89EB6B85
-:101450005AC08EFC771F7280BF793E39701CE886B7
-:101460007837EC23EC8CBC68477B6AE2BBB99EB54D
-:101470004EC677D5C3DE937FD33D8B63E224754E92
-:1014800089CF1FFA5B40D74CABFE36B4F34865FCFE
-:1014900075C84CA5F21D785FA935FD01AE9D91DDA3
-:1014A000183F4E4ED6FF077C5FAEE8FF0ECFFFC958
-:1014B000AAF7333B5DED3A5310DDD790689C61E1AC
-:1014C000E24C412CBF3E1B9F33EC4D436C9CF5809E
-:1014D000768DE3ECA4D72FC1DC429FF797C75F6FEF
-:1014E000FF119727AA6798AF20F6BDF8DC448F3725
-:1014F0007F89F274FC6527E6B5079B20AFF3E414FF
-:101500000BD91D63E7C47905AD11E6175E7848DA9B
-:10151000CDFC4282F73FFF7ACE6E58DF5D3A8DEB0D
-:1015200031DF7771F743C6FDD0A2DD39A97CFCC756
-:10153000D1CF365E6E732AD3CF1FA4B278D855EBC5
-:101540006706AB47E8A9AAB0EB5D2E265FEFA7B20E
-:10155000AB2D4D12F9EBD3810F540FFB53AE6D7CC5
-:101560009E5A92F7D9E543E883EA35E6E76DE3FA58
-:1015700022EC15A5B3D4C9EC4520F9DAE8CC2CFD52
-:101580001CE458EC3F901D92211EBEC0C9E3955C3F
-:101590007F4F29FA42A093EAEF1D285F89F57789EA
-:1015A00093E9EF179C46FD5DE664FAFB4527D3DF20
-:1015B00066E767D0DF0FB8FEF8791C9F1C37DA1D8D
-:1015C0008A8BEF81FAEB1589EFE7267F9462FC8F17
-:1015D000FA8100D1D964F95C2C6EA0F855C7FD1BC7
-:1015E0006F1AEB7B8B8F17B563F743BD6F41FBB46D
-:1015F0003F9BFF3BE31FF0F1C5387A29F828DB5AFF
-:10160000DCB0FF35D13CB7C0C9E619BF8DEDAF20C6
-:10161000C768FB4586FE7C17F837D29F20F5ECE2C1
-:10162000F72718B73F7DC6FA62FAF308D42BFA53AE
-:1016300071E5F898FAE813FAE80ACB306FFB94F8F2
-:10164000F342AF93CDDB1F3AF427A17EB37C89EB45
-:101650003F727D48B40FE69452F98FC0EF5285D99E
-:1016600041A285FBE598FE9516B4887E072CB171E2
-:10167000B681F876F217CE11FBF00B94BF9D6CDFAC
-:101680000E95EB5FC2FD5D135CCB709FD747CC6EB0
-:10169000BEF5C97A6B1A6DA739E389EFC1F51D67ED
-:1016A0001AD2DB3294EB8461E82F67FB1F5B27B310
-:1016B00073D35A25E3F969EFF0F66EE2F6E91AF40E
-:1016C000FBAD5CF9D3EBC767B50B943F2784FD4CAA
-:1016D000CABB36BB34FB73687FE93482F8B87597B0
-:1016E0008AE76C09BDB90BC6969D77A0431EC55706
-:1016F000E9BD85DE0F81D30DF62A9B10F74C2C1720
-:1017000054F13C04FD3F983DD2CFC095DAA10FB80B
-:101710001D1A802BB543673F8B1D3AEC6476A88D6C
-:10172000CA501FC8A11262F9BDDC9FAAE77D2D2D0A
-:10173000386C88DB097FAA7360B71684BCC102B617
-:101740001F3551BB61F037207125C1EF5689ABFFC2
-:10175000C91576700236535C077154F13B7A9DD0FF
-:10176000BE06ED59F0777E5E2332AEC39BEB6B9DD8
-:10177000CAE7FD142ECF9357A27F65FE1DBD2A77C1
-:1017800068FB4C5A8FEFD8DD6C9FD5E5BBC9B22200
-:10179000C0270102E76DAAF40AF99B82EE69A9D776
-:1017A00093D8DF235689A4CC2B8CDA91AA08095749
-:1017B0001423BEC1FD5C508F87D7132882F93E4D9C
-:1017C00081F5BED712FC1ED39372607A6A4CFD7EFF
-:1017D00062C42B74FCAF4F9D8DE37F0394A3E35F42
-:1017E00090CAE6A11BE1F95927B37F4FCA4D85F096
-:1017F0003C90C196A069F9225E7E46EAE720279BCD
-:1018000009FBFD5D90DFD8F5EADDDC3E744C0C94FD
-:10181000433BD53F5FD433857EB2BABD05CF39AEE9
-:10182000B82EF2D129C8BFCD52713DB0F551E33C7D
-:10183000F21CFFFE40AA88DF5D1B8EA0F6AF3E15AE
-:10184000E963F62FE866BF33DA3239F731061FA9AC
-:101850008399193DBFB6DAB508CFE7FAC60B39331D
-:10186000E1BC2B95DBE779EE6E75058C6BA43F6EC2
-:10187000BEE95746EC20B5DE86792AFE392FF7A758
-:10188000325C4BF5F8AB7CFCEE023A5F9CA8075249
-:1018900067FFD7D9476187020AB337D46F0A82DF5F
-:1018A000B4ECD2DA23304D3593276A607D83CAE5E4
-:1018B000DF019D5FB6EF3DC27E7A303805DAA5F2D2
-:1018C000F8702AB3477F9FCAECD17752993DFA87C7
-:1018D000CF2267F7A69231F1A7C0E1027F533BBF49
-:1018E0002D95E14F8FF3F3993776F2FA02CE6B9C88
-:1018F00037BEF439B44FF1C6CF505F391F12E1DB68
-:101900005F70B9FA65AA88FBE9BF04FE2FB4EBFF4C
-:101910009C1A8B370A8FFD11F2E4A278A35BE6785C
-:1019200043898D67FB28FEE27975F758E644F54454
-:101930008DC4C721F353477048078EF7768643E678
-:101940008FD0ED1D08811E4EE1FAFE3B668F5BD401
-:10195000FE7BF01CDC7446B794CEC6F128EFC7BB03
-:10196000524ADCF8E6B1687BC7B0BDF5AC3DD97131
-:101970002BFBDD0F6157AC12B623E2C3F3D3D9774B
-:10198000A29D79FC2A70AAB99DDF46DBF92DB6F33A
-:1019900090D807ACBF05F7BE285FC3B17C05FB62DA
-:1019A0009913C34F8EEB12E1B818FEBD8776A08D58
-:1019B000B533C2BF407C3BBBCC250B3919481D4316
-:1019C0003ECE71F9381F958FF35C3E3E4C457CC28C
-:1019D000C6E1AE09C6FDE5C35CAF1EE17C12E3655E
-:1019E000A6BF95BF1FE187E7D873B1B8D65790B6A9
-:1019F000AC19E2966DB2D7E2192D6FF45F3EE0DDCF
-:101A0000FF05CC52B1EF0080000000001F8B0800E2
-:101A100000000000000BE57D0B6014D5B9F0999D26
-:101A2000D9D94DB29B4CDE1B48C226800D1A7009D5
-:101A30002106083A79F20A10111014617985F04AEA
-:101A40002262EBF36731213CD5E8556B5BB40B8226
-:101A5000628B3660AA8801372088EFD02A68F5B6F5
-:101A600041ACA0225950EBDADAF29FEF3B67B23378
-:101A70009B5DC0DAF67AFF3FDEDEC339739EDFFB83
-:101A8000FBCE37B34584FDC927BD923B9790B17E0D
-:101A9000A27A6D849C83BFAB82A555110849266448
-:101AA000995C655586D20165F5CEAA8184B4977498
-:101AB0002EA90AD3FFB604DA9FF69B9EBEA92CD9A5
-:101AC00049FB7B687B0A21C31DF4DF2221D7D5B4F3
-:101AD0008B6EDDB8E99F7E3C4F0D33CF4F124CB873
-:101AE0006EC30CD721673E9DC661726D253DFB35E7
-:101AF000C7CBB8DEA86CAF1447FBBD7986289B69BD
-:101B0000BFEB260BAA979EAB829FCB96C0CE91A52A
-:101B100048D85FE5FB1C2577CE0B778E7CFE7CB426
-:101B200093A82D749ED10A517786E95708FB8479D2
-:101B3000A2C3CF338DCF3386B079429FCFE0FB1A5B
-:101B400055127EFC083EFF34C78EF20402FBD964B6
-:101B500006F8E599D5610A1DB736021E52A4929186
-:101B600080AF280A3A731E2133E958139D6016E0AE
-:101B70009C960F8AEE5278EEA6E070E40125787A02
-:101B8000015E4B6C6A19B44747ABE530FF4849AD7D
-:101B900080F297667514E29FF80829206402A79FD7
-:101BA00009569B4F8CA5FF28349FEAB4B2B673D96F
-:101BB000F0FF67281F5F4688407CC2B9CBA0EE15B6
-:101BC00061FEE1CE43EF0AB4FF706DDC4929645C2D
-:101BD000BAF2710CAF8BB82F84CF6EF34F9D365392
-:101BE000CF736AE56E9BDB0A70381DED9E09FB6CB6
-:101BF000706CB63929BC5F75B7585DB4FD641C4183
-:101C00003876C5A86E7CBE9BD4B4D0763146A86F1A
-:101C1000D1C16FBEC2E05DAD30BCBD25A9D570FE9F
-:101C2000095675018C9B9C49F144E79D95D8B95C98
-:101C30000FF77A8EA7859C6E67CAAC5FE83EABF95A
-:101C4000F32249F0C4C09E6C873E12813F48F75F83
-:101C50003F13AD8F857F51FE293AA94C9D96447163
-:101C6000B6467499685DCE11C2F2E99D7CBF944F6F
-:101C7000EF84FD1227E5533BA50F393C7D7CC5FB66
-:101C80009747A0CB3C7E9E32781E66FCA59CAECBCF
-:101C900092DA4542C717717E0BED373741C47E0D8E
-:101CA0002E323ADC3C0F04E5CB03485F0ADB779E1B
-:101CB000B9EA21A8CF500E97C7D3E6E2BB93A6920C
-:101CC0002480878958B2104E5642E1247138D16D74
-:101CD00012A82FB3B2BA14BD84C4D132D3E15D3F90
-:101CE00008E0D768763969FDC3931F8A84D2D9D6B4
-:101CF00007CE0A84CA8BDD7E4212B3601E19668449
-:101D00003FD339A1E77CF49953D2D6A3A0B9F224EA
-:101D1000512D947EAF2CF44F22B186F1E41C9DCF5F
-:101D2000E6EFF008803F2BF1C45C8E64FC76BF14B4
-:101D30009C15E74BA5EBC279E42F8917CEA33ADCBB
-:101D400095641021F1FECE5FD461BBCD350ACF453D
-:101D50006CC06FC1732E43FED3F625DB3A1FBB97D1
-:101D6000F66FFB2ADA75179CDB5FF109DB0FF1D800
-:101D700081AFC54A17C877422CB83F13FD0FF86CE6
-:101D80006480EE3787EF1716C9D7ED9FF43CCF83F9
-:101D900062D521C0C72C2B5163F3503EBC02F5BE67
-:101DA00066DA81C2B14911BC1EDAAFE981796BB242
-:101DB000405E6F905CFD09D039D925503A1F41D75C
-:101DC000BD85CA1DB990D8145A971DECFC4D7727D4
-:101DD0006D8A11E0B94465212DFDBE6F040A875854
-:101DE0004775A542CF21F3F102051C8C179C0A9977
-:101DF000910774DB2112940F0E8487C63FEA8F8807
-:101E0000F0B115550D01FA2A9388C74AFB0B0E361F
-:101E1000EF95C42F92BE8007AA086859425C58DE2D
-:101E20002BBA3F06BEB1CA14AF74FF5693D5BB524E
-:101E300000FC55BD3E1AE15EA67C9C13946791E4BC
-:101E40001040EE630DAEE2F7977BE5CBC3F3D5DF31
-:101E5000827CF3372697995E9E9CCDE4CE017BE78A
-:101E60000C3DDFAF5298DC59C5C71189F1D9325901
-:101E700035C59F87CFD7F2719782F2017D4CC2F3AF
-:101E8000714B3C930793EFF236F5A2F09B9020B88C
-:101E9000400F976F9F2DF57606FBA5727DA7A4A82E
-:101EA000F1F130DF6ED7496F12681F19F57BD37BD4
-:101EB000641ACC3F9BCBCF009FF72FF16C1FE9BC7E
-:101EC0007E4CB04F0B0797CCF86EB864C2B9889BB4
-:101ED000C1458C19ECF7D175486FBE8E59C075DAC3
-:101EE000B3997CCCE6FBD2D6E9C3E51F95FB97C03E
-:101EF0003E27677AD3A1DFAB66B6BFD0750706D79A
-:101F00001D88EB2E61EB8E05390FFCEF3CF412C8F7
-:101F1000F9224EA763FD6E02760FF0B0A92028EFDC
-:101F200065A74FACA7ED4511E4FCF0E03AC3719D05
-:101F30007A86C73D29EA08D827B50B8AA0BD3D5B44
-:101F40004179F9662F13D94CF972765AF63D20364D
-:101F5000B57976F273B6673539E6507CC97EE2B260
-:101F6000209DD7A0DC2BE2F2A561B79BC0734F2F59
-:101F70002A3375E365FF1C2BB1E151FE714EEB4F27
-:101F8000F9A8C99F1DE70E8317AD5CBF828922E2C5
-:101F90005C8AE396F171A1FD6C0FEE8B81F93740FD
-:101FA000FF1F113291EB1B7A60DCDF58CE3B0DFE38
-:101FB000CD319DB4DFEE9CB986FDE073CA474D3943
-:101FC0008FC580BDD49641F500C8A9574494934D60
-:101FD0007686C7A6B46AA2B7474B1D3EF16398E761
-:101FE000DBB9642AC55F91C34D2EA1F05DC7F751DF
-:101FF000E4AAF60849D8FE6C149D6779FC250847C9
-:1020000039C74D2A72012E5E524DC7CB8A4F74D10B
-:102010007AA99FF8AECA87FE54CE0B6C3EA75D3FEF
-:102020000F698179E45C460FB2BF8500FC769F3C66
-:102030003F1C63724C06F9ADF125B5EB56001D94BB
-:10204000295797C5D3F9176DCFCA13E9FC158E76BA
-:10205000794E2ECA6D0FD0C7CE647565FCFFA03DCA
-:10206000378D78CD80F751994C0F4CA815BC9B2922
-:102070007C9A42EC849FC6333E2C0CCABB9FE1BEC7
-:102080000B353B41FD39D4CF63073F0AF0388F1D34
-:10209000BC059E87B183B7423B85D7E3F1CC0E7E6A
-:1020A00002D6A176F0B6EF03B7090A93A3D40EDDEA
-:1020B00001F3C6837103F6D11F983D1ABAFFDBF80E
-:1020C000F9D7D0B376005D4A5E89D139E3D3E19C7C
-:1020D0004FC79EA4FC92DB93FEDB28FD7B28FD9D71
-:1020E000A576939815999E7C17C997C50F32BE6F38
-:1020F00070EC43BE7B91F3451B5FBF2D47AC047C66
-:10210000BE4A4445147ACED794E176805C0FE53F11
-:10211000F55B233D973ABC1BF2806F0ECD75C1B6BF
-:1021200042F951A665F5C0E0BE8F031F0ED5C92741
-:102130002248C88F17E04398C73D10EC8C7849CDF2
-:10214000053E62EB7A0E89A82722F111A59B5380E8
-:10215000BF6EB800B075FBA774F3393CA77C76FA64
-:10216000FBD0CB1A4E1FD40FF91AE6EB1FCFE8674E
-:102170007604FFE21FF1DD7EC03FA03F99C1F4501D
-:1021800066BC938D234932E81755CCC804F942E761
-:102190003525D0F6B7B87F1469DEA8846EFE8B4A69
-:1021A00080F3DCC2E63D0446F6D09EF38E4AA0F6EC
-:1021B000479879D2B81CBF2E82BF90C5FD1292DB22
-:1021C0006D9FA4C07A599C6F7627AB8E041DDF14D7
-:1021D00071BBE565C1A89773BAFD7DC63F4909ACDF
-:1021E0003F99D73D6F56820E9E9A1D309BCB076D4F
-:1021F0009EFE9CFF9C090A1B5FC3C6C7439D8EAB16
-:10220000E0FE13854B2ECC47ACECF985FCA27B1489
-:1022100019C7CFE5FB12E2154DBF215C4747F2BB62
-:1022200082727038E2C1C5FA5FAA100DEF23711FE8
-:10223000956C1F850AC37B68FC20127E34F8276BDF
-:10224000E7CD61F3134F37DC46EBE92512DCDE8A7C
-:1022500063F6C5280E27D2C8E7099107774B1D56AC
-:1022600025CC39AF8D771AF8D9EE32CA8748F19468
-:10227000BC207C66221CF2D9BE23C5570AF87947D8
-:1022800070FB968E9B8F70B5B1FDDEA374B7D7E05F
-:102290007CE96CBEFA20BC1763BB83F58FE4F7D7EB
-:1022A000F37D5527748F5B86EB24B171A1F104ADEA
-:1022B0005CC2F7B73038EE565CAF1F1B971CDCC70B
-:1022C0001DD83E9AB57FDFF85B32DFEF4F82EBAE71
-:1022D000C1FDAAECFC81B86EB8ACC7F622B66E247C
-:1022E000F9118863E768E270BE12FC623A477C80AD
-:1022F000E44849E03545BB46D12EA901D507FAA3EC
-:10230000E44BD90972BA5CB479042A8F25A715FD6C
-:10231000E42889A8E0D7B67FF56347672ED67DA06D
-:10232000D75747155BC1EF5C9325B9401F16DF27D0
-:1023300031FFFA9409E57D85B804E7D9A76876EE00
-:102340008D063FDAA9382BA3601F56913899FF5F9D
-:10235000399E3EBF8ACBEB7DD64413CC372283C552
-:102360000BAE7256A3BF4EBE657EB44AFF63F25BEE
-:1023700045BD2CF371527A3D11B034FADB32D9707D
-:10238000461C847A01EDA8117EA3FF2D3B2B4EC085
-:10239000FC32D18DA3EB3E9F604F427BAA1FE97FA9
-:1023A0008EF28F25472016EA5F944BEE3D808731F1
-:1023B000CE6AA5849EC792EEB6821CEE67F6F586BD
-:1023C000784263BAECF2001B3E5066CD027FAB99B7
-:1023D000FAE7080735E1EA81413C598A540274481A
-:1023E0007182FCD55DDA589990C8F0F8498205CB26
-:1023F000125ED79E87E27D486234E37F62F57C946B
-:102400000372422071940E9792CE4CA0C7E43426FA
-:102410009F6A4D9D2950EF22FE94245A36344BA3D7
-:10242000C3F93F1B79FC6CAD29BCBDF44BF3980F8D
-:10243000000E12C40D2EC7B880DBD237183FD0EC87
-:10244000552D8E10C96EBD57ACFA18E61114DF3742
-:10245000D0BFA7FDEBC17D48E94C4E6BA5B68F9967
-:10246000898C7F1C895684CFDE3B4AC91C27E2E950
-:102470002CF029C5D3A12B002A59F314C0D32B5912
-:102480000FF583B89435EB8124E0CFD184D9A7E54B
-:10249000748C83960FD9DCDF24E8E4E1987EB3D115
-:1024A0006E2ACAAC477B6A7504BFF4C77C1F12A7AB
-:1024B00093129BDB943814E25FCBAC305E52AAA23D
-:1024C000A1DC1B988425B57BA544DA7F753AAB5F08
-:1024D000080FEF72F91069FFA3402F40BC26BDFB27
-:1024E0001C09303F7DEE91F382E7D0ED2F25DCFE15
-:1024F000CC894C1F69FB92FA71BACC31D2DD784E8F
-:102500008F39899ABF78D17477E462E82EF4BC637E
-:10251000B2968F1E4082FBD7CEAB9D9F9ED705E71C
-:102520002D97D8F9B72A6E15A6A0701E0CED3DCEDA
-:10253000650DAFF733124DDFF53C0F25F4BDF8F311
-:102540007C8779A7267E07381D18A93A409E342635
-:1025500053FAA4786A1458A9F58FE6786AE174FAF8
-:102560005DE444FFEF70BE6287F012E8C3ABDCC7E6
-:102570004A6199B2A2C1A076801FE701BD95E4DE51
-:1025800027CDA1F5A63BE6A2FC3C30B21EF7BDDA92
-:102590006EDCAF5626707C1465AAC87F8D9CFFCA7E
-:1025A00009F323B57E6DFC5CA1FC113A5F285F3F07
-:1025B00064536F06FA484864FA32E8FF75887AFF78
-:1025C000AF84EBAF91D69B0CF18F91DCFF5BFD6587
-:1025D000B6CD430F7A96EAB57F89FFF70D7D027E6F
-:1025E000527A8955EFFF355A4BB17D75863AFAF22A
-:1025F00024D0C7A2EB2E82F0437FD02388CAD630E6
-:10260000FEE0EA0CD977157D6E51C8E3B0BF52AA3F
-:102610002F21FE62515472C9C09E7EE13E6B29811A
-:10262000B8C959853C0BFED885CEF378A2D12F943A
-:10263000C02FE4F3A35FA8D4934E8CF79412B06B31
-:10264000A0DD3910E48E4ADC76D023D42FD4C9A77C
-:10265000B3D69B90DF43D7A372EB69A0A34685F165
-:1026600071A83F28723ED7E46C283D943B18DD44A6
-:10267000D1AD9B99DC782E31B9275D7C77F934AFE9
-:102680000C5C806BC9CA03E0AA4D09F825707996E5
-:10269000273AB15F956D47233CD7E60FC50F3DB98B
-:1026A0000AF174B06758FC86DA6BD48E32537B6DB6
-:1026B0009D105C7F358777247CAC067D1D868FDE80
-:1026C000EE966BA171A29B8CF72F8A872415B0B868
-:1026D0003E09037F91DB496B28BFC0FDCD6AB3CBB8
-:1026E000A1009D6614BDEB067F3E43C6FB0822D5C4
-:1026F0003BAEB6F73CE71A889F85D9DF17890908F2
-:10270000576BBAC9609F1172A7C17E8C746EC2F7F5
-:1027100065E6E712009E397A78869CBB4CC17383CC
-:10272000590FF3C69A5CC447F9223693B85060C576
-:102730009A300EABF1B9C2F95C930736858DAB4C7C
-:10274000EACBEEF7449B5FA4E75F9F44ED693A4F05
-:1027500083BA0FF5AA363E8E9FDF3692C51B6D7683
-:102760009FA28481C3BD9CCF239DB35995E2CBE842
-:10277000FEEE5598FD2D8D345579311EC5E2B50A12
-:10278000879D589C6F05BB7D54523C8B7BA93B15A4
-:102790007DDC4AE4FB89B1D3FD9C474EAE0DD94F99
-:1027A000544E6719EC5FCA529578DDFE4B9234BDEA
-:1027B000D281FC1D69BEBBB99C8FEAE7C2F8ADD5DA
-:1027C000E6F2C1BD56945A5D0062313AC745E6EA69
-:1027D000DAA3D58221161D1D3667C861EF236EE787
-:1027E000EBDB25B50AC6D91589C03D999DDBCB9198
-:1027F000E68DB48F0BAD372D89E9D31EEB39C3DBE2
-:10280000157D9218FF49237756819C260325D23FD8
-:102810008C9E484862F22556EE7482BF4EE9D11D67
-:102820006E3E9224737EFE37F187667717B71ECA15
-:10283000A6FB6DB0492E01E457E1C90EA70E3E5428
-:10284000AFCF4AD2C97DD1E646F9263AD9BDFB6859
-:102850000BF3B70F8C34DE93CDE7F8FA80C33192D7
-:102860005C28E2F0F8779DF3BBE2AF2489C97D0DC7
-:102870002ECD001702FC757F6343187949E1D39090
-:1028800094FCDDE1B396C3E5E90BC067D07F183E49
-:1028900017E2EB209F79C9F130706CB0CB69730DF2
-:1028A000FCDF8C7648B87ED5BAF346E2438D3E20F5
-:1028B0007703E1D0AC1AE2027292A783F995371B35
-:1028C000F59CB8C4C5E533F996C22D9EF78FB711B4
-:1028D0005F4C6C707EB9CC184F684BE27181281246
-:1028E00005F039EB9A24409E82C53463B0920D4BBB
-:1028F000340BA02752609E4184DCC7E567A81E4CBC
-:1029000056999FDC9BD40B4CAFA4E3FE92F83E4259
-:10291000F5601AF56B201E0347047FBA37AD5BC123
-:1029200006212ADE830B1E13FACB0EE21560FE741D
-:10293000D289651F4845A0F367910EA11FC5DF7DB1
-:10294000E5D583417EBF13728E0BD9A35AA9D91F37
-:102950006BFF43F0FEF47F2FBC5796EAE02D267FF5
-:102960003F78CFE77227349E5704F1BC2C88E7F9F3
-:10297000F6039FCADF32FBA3FDEF32C6F71AB35846
-:102980003CAF5CAC7C18EF419D32BA1F524EE77AE7
-:10299000C873D2EC4ED4797D83713FEB99FB2588C7
-:1029A000A310E924C209EF869C28CF329351DE3070
-:1029B0003BE22ABE7F396B9E15EEBD83FE934F64CA
-:1029C000F606B397644E07458E12F45F1ABF3DBFFB
-:1029D000DD71B17ED25EE900DE5F6BFE51837F0E5A
-:1029E000FA4BA1E37C92EF7D38BFCF2F3B21DFA4D0
-:1029F0008DDF8BB59D396888D386FA419A5D751550
-:102A0000DF7FA9DF7DE872B8DF52E61016DF647061
-:102A100090F93A8D8EB3780FFEE2B726F4B7CE72F6
-:102A20007FAB08FC2C3BF377AAED3DCF392139BCB5
-:102A3000FF04E320AFAE54F18960CF69FE13B43BCD
-:102A4000ED3DFDA7D116FF6BB0BF09AF89981712F6
-:102A500009BEA17E53A8FE999ECCF4CE4DC9DCAE32
-:102A60000B81A716EF0BBD976ED2F84FF2087AFED6
-:102A70000F5D5FDE3706F74F145D3C363B184F1491
-:102A8000540FB9252F183F0C13375C0A74A8C50DD5
-:102A9000353DA6D1B185F6B5E23D73F878625BD6D7
-:102AA000C1BECC2F7C2911F8B35C6171236D7FD43A
-:102AB0002FBC2D59878F223FD3DB96FF53DFB9926E
-:102AC000C297241017F30FEA9D565AAF5048E23AC6
-:102AD000E4331BE669152509C877922F0AEB15A781
-:102AE0005CDE285AB7EC7B45149360BD39244A0854
-:102AF000D28F96D7D1E8FF703DE0EFEC29C9753E43
-:102B0000BFBB028268063F293A884F946F0986FA54
-:102B10004392FBA164B4177B05C789900F966DC8DB
-:102B20003F7B46527F0A709D6A551FC6FE3F3CBCE4
-:102B30006F4FC678F1C17F0AEFC175983E009B8D3B
-:102B4000A4E9D6B3D1C661B08E93DD176A71E9E509
-:102B500004EF63B601CE20CEF239F1429CE505F3D5
-:102B6000CB22E8A3263ECF70D2EC94FBB2FD42BF4D
-:102B700027B73A36015DFC2E390BD77FC1E6DE3030
-:102B800098B61FDA220D86B84D83F3192BE4CFEEE9
-:102B9000DBDA94DEA9E3BF434FBAFB84F30FB592AF
-:102BA000FEC5990AF15CB1AC54459303DB45A8F727
-:102BB000B0CFB6B42AB0CE935BADD3C2C535C41482
-:102BC000C6EFC3B730BB76748EC905E2AD8878A472
-:102BD00004B88F7111978F36C40CDCD9813670968A
-:102BE00088F71AB4BE3F96D66386AAE81F0C18B8B9
-:102BF00013C70FF8BCC4C5F2283DB63C5A5F9F53BB
-:102C000032741DADA747BB3F06FAA27AA659427D92
-:102C1000DA1203790031032725AFA3B51881548553
-:102C2000B373FF9ACCECEF27CD1A5C25CC83DCB7CD
-:102C30005546FE3A9426E2FD1385DB12A8FF252DAA
-:102C400086504A2465AAA70CE0584E5A1AC09F2AFB
-:102C5000735EFD522CF927E097BF5301FE5F1FC141
-:102C60000EFF1DDF1F0A114A3F07B7345E47C2E45B
-:102C7000516B74F85C8C2AA5D0FE6BF9BD2E714C9B
-:102C800042FA898CEFBB98BFD9E26B88A6701CBE54
-:102C9000BDB9977EFE2310744DEE896FC87F2697CD
-:102CA00043FEAD1BF3691B4E9A107EAFE60A5E81B0
-:102CB000C2E7608E486D36BAAB7E566F7F5ADFC072
-:102CC000E9B872FBE1C65EC0C22949B8EEAB398FE4
-:102CD00059597EEBC5C7AF87503E5804F953141FAE
-:102CE000A39468AF93E26B314C41EB2315ABD7470C
-:102CF000D76BB77794C6D1255E48165C9B815E7210
-:102D00008802F2035D1013439442EB2032909E92AE
-:102D100008E673AD2FC8DD0C71B175E9CE16C83762
-:102D2000DC33D08AF966A1F9C47B84FA97E2212EBC
-:102D3000152FA0BC3E98F33BBCA73B986E2140AF3B
-:102D400098F04B9F3726303E8DC937DA9FE52959D9
-:102D5000DCCF261E4B41705F31FDAC6A1425A49771
-:102D6000E3D9F843FD042FD0DB2127970FF4BC5B98
-:102D7000C120929AA5A90323E3F595FEA39C9A5D31
-:102D80002C68E734F53CC70B82774D369C63003DD9
-:102D900007ADDB73045CDFAEACBB916059B800EEED
-:102DA0003143F7BF2285F9473225BB1C906F2D6B4D
-:102DB000C6E8F363E4C21B27D862318F09EDCAD499
-:102DC0001C01CF33E624BBCFED919FAD10B76CC093
-:102DD0000FB53A5282F3C57CF9EC4F20FF775CA126
-:102DE000E08B82FDF0FC66FA7FEDA05FE47EB359D4
-:102DF000FE75CE263CCFD842B30BEE72C6DABCCD00
-:102E000025B4FECA2712C6B3C7F51B85F9D5A1EBB9
-:102E1000AF53886F3485EF2BB912C23BEA92C7706B
-:102E20009E37734D286FC6413E36E42FEBF3AA510F
-:102E30001F1AF3B9C7891FA8C5D0EC62FC4A244FFA
-:102E40002F90EF131C46F8D94F1AEF8B2BF32D86DA
-:102E5000FAB85C39440F7B10DE2F6730BA7879807E
-:102E6000E0DD9C15A4B3B12713BC4067F02716180A
-:102E7000E06838678C5F56017E87063CF15F704FD3
-:102E800012E35C7D23DE8373F86B7412C3F16E4F23
-:102E90007FEE27A0A734F887D2C1C5E3FFEAAA6274
-:102EA000C07FBE767F1F82FF107C630C523B47DFE2
-:102EB0009E78C7F5B37AE25BA3831EE7BEBB754D70
-:102EC00036C5EBAB76FA00F0BC49F6DE2504F174AA
-:102ED00041BCF62B46BA59A734DB40EE475D72DCA5
-:102EE00006FE814617446CCBD7DBFBFF2A7C976C30
-:102EF000109833E912BC10D77B0B1E0D0BAEF352AA
-:102F00004A77BECC4B20F74915CBE36850F3D87B0A
-:102F100057F94C9F86CA873FA4B0F73ADACD2FA75E
-:102F20009F2F4FB5D2E626703FD600F976F47CF29B
-:102F300086D9F046039127CF46794936082C0FA150
-:102F4000E8F728DFE739BCAB8430EBA12583FB74BD
-:102F500032BBBF2811FB93695A5E52D507B8FFC92F
-:102F6000AC7EB1FB7AE35FB4AFA3945688CEFF9CEE
-:102F7000C8E3F29ADD3DC1C6F20E271489888F3767
-:102F8000B7085ECC8FA4FD3C944E1671B29DC8ED7F
-:102F9000C0B385CF340D76823DA81AEC4EA1A81D92
-:102FA000EDBEB842A33F18AF461BF09F383AC15060
-:102FB0004FAEEA65E89F3A2DDB1857705F6A78DEFE
-:102FC000BB26CF50CFA81F6EE8DFE79612433DCB5C
-:102FD00033D6D0BFEF9A49867AFFE6EB0CFD7FF43B
-:102FE000F01CC3F301DE4586E7976D5B66A80F6CA6
-:102FF000B9CDD0FFF25D77199E0FF6AD333C1F724D
-:10300000E87E437D68C7CF0DFDAF7877B3E1F9B0B7
-:10301000CE5F199E8F38B9D3501FE9DF6DE87F5519
-:10302000609FA15E4C5E33F42FB5FEDE502F57DE5D
-:1030300037F41FE5386E783EC6F999E1B94607E3E3
-:1030400072BE30B48F77FD2DE43D9D2A16E780785F
-:10305000405F78D48C65346961F73AA403CB850569
-:10306000EEE254E08F473D4D9090D4E0F1FF11AE79
-:10307000A6DF2CEC1BC7EC2795E8E5A7969F4AFD39
-:10308000164F142585D800A5DB2194EE0202964A3E
-:10309000804AD64488F74461991048C4F6C4403C3D
-:1030A000964981DED89E1C48C33225D017CBD44028
-:1030B00016968EC06558A6050660D92B3004C7F554
-:1030C0000E0CC6323D3002DB3302C3B0CC0C94622E
-:1030D0007B9F403196CEC0382CB30263B0CC0E5CDF
-:1030E00083FDFA06AEC6B25FE07A6CEF1F988EE5FC
-:1030F0002581B958FE28301BCB9CC0622C070416D2
-:10310000627969E0261C7759E0462C7303B763FBAC
-:10311000C0C0AD580E0A34607979602596AEC07A89
-:10312000EC3738B016CBBCC07F61FB90C07D58E651
-:10313000077E81ED43033FC3B220F0189657043653
-:10314000615918F83596C3024F62393CF00C8E1B5A
-:1031500011D8816551E0056C1F19781ECB2B03FB3C
-:10316000B1FDAA403B966AE0356C2F0EBC826549E2
-:10317000E0F7D85E1A388C6559E07D6C2F0FBC875C
-:103180006545E03896A302C7B01C1DF80CCB318111
-:103190004FB01C1BF802C78D0B9CC1B232F0376CCC
-:1031A0001F1FF806CB6E7917315FD96D427F96FBF2
-:1031B000A991FD050FCA49337F2F0E72AB31FFBFB6
-:1031C0005EF062BC30A9F325A89B0B2D182FBC81A3
-:1031D000F8F13D81FF269D7690A7EDC34EA443BC38
-:1031E000E9CD645F863EDFC1CCE300E5E22909FC5E
-:1031F000D50949FB92419FDE409B21CF88A8E7304B
-:103200000F7202CF83BC41A20E16DDEA61986118ED
-:10321000F6F359687D462551F368FFA661168CEBDD
-:1032200037E5513F88967767B17CD91DA94C5FFE81
-:103230008A97BB52991DEB2960F7FB336EECCFF8F0
-:10324000A92CF1027E1383C3DF07F23C5B9B3F1383
-:10325000F3632F72DC67297C1CEFDF9C5AD5960A3A
-:10326000FB282139F5B6603FDAFE6284F67DE1DAAB
-:10327000F799183E3C4744EE2754C54D3A8F9FF0CE
-:10328000E68A8E4B5FEA1FACBF15C10F256425EEA1
-:103290003776DF2795D7527D38B1507451C9413EFA
-:1032A00058B16BE447FDD9BA909FE92911317E31BD
-:1032B000A3E8F081445A9FB13C1EF3EEBBF7556280
-:1032C000C6E7131C472E7D891EFD86FAE7477E64FC
-:1032D000888BBAD1EEBA89D32851CD7FEDD49E2305
-:1032E000BDB2B8EF4DB0B813E49F19E7ED50CDDE95
-:1032F000F3E5C710D5425403DD3378AD87FD83EF86
-:103300004FAC26583796F7A17045BDEF8995BD0D96
-:103310000238EFCE38A0BB985C3F395F7C19E029BA
-:1033200061A242A70DEC9848F04C7030FA8B2B52FA
-:103330001D1E8A9FC6BF8B78CFB53FBE4001FABF26
-:10334000C7D62F15F823D9C1E2278DEDEF617C2B6D
-:103350002EDF4F3C36767FEEB4401CDF8AE5AA159F
-:103360002E2C1B571462B92EFD7E2BC44BC464094E
-:1033700032814954C63C8C0769EB9BE3E7588B5D6F
-:10338000946C1D722584904488330C87F736E5CA07
-:1033900095FD08F92695E57DBFE9F8C806FCF04DD6
-:1033A000AA13EBA289DD1BC7E4FB54C84B88712923
-:1033B000259233D88E7F49D8BE19FC913749E786CC
-:1033C0006B008E2A7B1FA381BF6FDA50DC9FC35531
-:1033D0001B1782F7103C8BB20BEFADC568DA3F3795
-:1033E000325E0738E2719F405F12A52F3FDF3751F1
-:1033F000634C309F86DFB3921FF3A91A84F079974C
-:1034000043387E1A155539DF3D0A51A4BFEAE5A9B4
-:103410002D7757083DDB50BE621DF2B9B8BCDA9F6C
-:10342000AA0E73D0F9C75CC9F3EBD313500ED0F6D4
-:1034300001C3219FCE44153AC02D41467EA140884C
-:10344000833C5F6275C64D3A4F1EC4DA150E553285
-:10345000C3FD80330EE0B5969F0FDE50D6CB817F43
-:1034600057BFA0BCF022DD86F66FD1E4408215E59F
-:1034700093C8E1A18D5BE860F2D8945D35D33194B7
-:103480008D033EA27537C08B58697D20D6E7E07367
-:10349000A5BB3E0FEB0ED61F13692E420ED3718BC8
-:1034A000719CD43DCF52ACDBBAD7ADC37593BAEBA8
-:1034B00037623D9DF5BFD875B4B2FBFCBF6372F2B5
-:1034C0004B498D4BA0F43CF696B955A00AC6DFB225
-:1034D000B0AA8CEAEF3FAE785705B9F40195278D75
-:1034E000B41C3B607F22F839E387EE8F71EAE8F580
-:1034F000061ED76CBBC53C1AF45DD1AD62D51684EF
-:10350000F74AC3BDCF1A8799C79BD83E664884DC6B
-:103510009100F2F7F0A58D06BF93F3A1C2DABAF7D6
-:103520007B9B80FBFDA09EC9DB0F960B286FBBF930
-:10353000349E703FDE970C709AB95C27B74918B873
-:10354000D45B88DB20D723C18790BFD2FA97B67EA1
-:103550001897A5969AB52A8C3ED3E014090F3744E4
-:1035600088FF6A70D2E0ADB5FFE98E210AB3ABBD2A
-:103570000638CEBA7328C62B6FE0F17A126FE5FCDD
-:10358000C9FACDA0EBECCC457A7202BD433D6C9EEE
-:103590000D5F7706FDD71D79178507CC97FFA0FE35
-:1035A00080DDADBBFF0C857B443A8C00EF3A0BC14C
-:1035B000F72AFC5BED2C9E94340DE7ADE1EB92A471
-:1035C00019B88F1ABECE4B7B637C26B887DA6ADFC8
-:1035D0000CFE705789276522E06BB319F3DAEEDA37
-:1035E000BBFEC82FE03E789319EF4E167EF14001E6
-:1035F000DCCB76713D4615413B7C47C14DB43F5510
-:1036000080F91710367F97760FB2350EE17AB26CDB
-:103610004BD3085A76EE595A09F197137BC71F040A
-:10362000FF79613491D2C0DEABDF21233C3CE68FD1
-:103630008C768214AC8B3DEB0BA0AE8B232DF49AD1
-:103640008375FABFC5DB8C753DBC4C7A7839CB8C61
-:10365000F072961BE025BC68F7893A78959D792928
-:1036600011F4FB518713E7AB39D39802F0A9D9B312
-:1036700016CBC5DBA23C1FE9D65DDA126FA8D7EDE9
-:103680004AF3E8F5CBD9438FC5C2F9973944CF4700
-:10369000547E9C5AA136001D9F5E31BA414FCF4BDC
-:1036A0005BB23C36C33CC6FAD96601ED14D0339305
-:1036B000CF632F2E73C8B8CEA7DB98DFF9E90AAB2A
-:1036C00007D639B542F1B0751D1E664F31782DB958
-:1036D00025C6F3D190E0FE22CDFBAFDE1F21ADE485
-:1036E000B895E0BB3BE7CEA3BF23F28BF4A58CF2E9
-:1036F000BDCDFC17A01B2BFDDF398CA74A58D7E6A0
-:10370000AD6B113D90574CC876C37A749CF3639DA2
-:103710005D10593F18BF373102626228A7D97D88F2
-:103720001BEE43E87C5D926D0DC413B4FB903A58D8
-:1037300088F65D6AED94DDB4E9F3D6BEE77DDF9CE3
-:10374000E2290BF4738DB55906A55BD332A00CF8B2
-:10375000E9F3D68614B067178B677F1CEEBDAF29DF
-:10376000699C6FBD66BFD16FF46AFBCC920C7C463E
-:103770006CDDE7A6F55311DEF399C5E7ADDD7EB844
-:103780006204DD7FEDAE3332EC2339CD3D2B2D3994
-:10379000787E81DF072DDA760CF9FCA4D973C9EDA8
-:1037A000E7B3F37BECD3E630E41F7A4807F0E79CFD
-:1037B00042A231ECB5EF5379F3C96B6602F788E4A6
-:1037C0005BDA8B3ECFE44FE791AA5880D79CD6C5F1
-:1037D000287F3E7976DC419687D45C00F4F139315C
-:1037E000E1FBEE9F93DFC50ED1C16F5D9A9647C98D
-:1037F000BE73A3E5B9D00DA6619E7A4D5307BC3FB9
-:1038000066219287CB25817DB7C62BA0FD52C3DAF6
-:103810003DC4BA12CFB186C9230FFD0FEAF39B8DC9
-:10382000F269C1C3C67A3599940279DED50F982121
-:1038300093882CD4CB3F0ABF1BD398FFB980D437D1
-:10384000815DF788CCF2BBE72844EA4DF5D1D2E799
-:103850001E29984DEBF7A5317BEC53EE6FC07B8CA6
-:1038600069F4F9A25BBCB29ADBF37CC75B874C1DA1
-:1038700041703EE63F2DD2EC57E284787E6FF857D8
-:1038800076E4F3F76E15F1FEA937B4EBE4F3DC351B
-:10389000C6F35DE8FCA1E725E47E3CC7A26D57A313
-:1038A000FFA69D47C397761EF3B6F0EFFB6E4B1352
-:1038B0000C76DC2E0E3FCDFFDE1352DF97C6EC7A7E
-:1038C000ADFE72485DA36F33E76F4AF77B80EE97DA
-:1038D0005AFD158C4E3A65FDBDA81CECB72F6D68DE
-:1038E000E47E16CE2FB4DFCBE7EB17159CEFF57017
-:1038F000EB2E7DEEA967C12F5DF49B0763E152E8D3
-:1039000013A93905DEB758B275552CC0E9A4E4896E
-:1039100005BAF9C42B8E0E072F532F0D5EAA4DA0AA
-:1039200078AFD5E8BF68E504D0EF7FD96A56C03FCD
-:10393000ACDB66F1C177986A5B17E2BD0DAD1F6322
-:10394000F5D5F87E65DD2EF3877ABC2E7AE2C114B8
-:10395000CCF3209EDEEC5EDDD71B3E2154BBE5CFD1
-:1039600015E02FD7113FD273E838583F9080F27A94
-:10397000B61CD7F3B9163FAD634DA4AE75FD1988DB
-:103980009FD6B58E39017C5F47A40FF5F4540334FC
-:103990004DFD962FD278FEDD15E40A902F1A3C8853
-:1039A0003719E573C3933F1D748CEEE7D496D76245
-:1039B00005BDDFCAEFDDCFB6CCFD53E279F4C369B4
-:1039C0004AA7FAF73234B9EBDC4537904AAB6DAC15
-:1039D0005C62F6C58EA0705DB2C98CEF892E79EA63
-:1039E000B1C77F0EF944EF59F01E64F153078E0CF6
-:1039F000A7F5C53BCC4995EC1836B817D6F0524719
-:103A0000FF07F7141A1E163D734086F768A01DFCC9
-:103A1000040D1F8B77B4CB64604FF895B6B4CB9D83
-:103A2000B6307869395681EF1B3DF9B50C78FF64E3
-:103A3000AF4052B37A8EAFD97400ED188013E29183
-:103A4000E3A91B6F3DF0E59BB03B1FFB2920B72F7F
-:103A500084AF77B85EA574FDF46EBA8F9A3F585C58
-:103A600000879AA76F8A85F39C90EA197D3FB22A56
-:103A700005F2DD6ACC9E14054BD65EF3E8CD48779F
-:103A80000B0EDF9CC2F20FD5349EE79106E79CBF78
-:103A9000710A9EB39AB891FE6A1E11AB201FE62BE5
-:103AA000898CDE11863F6EE3FC716233452E3DE763
-:103AB0000990973ABF477BBFF9E6EE7808BB8FFCC9
-:103AC0008ADF4756F53219F44B37DD6E598D72F5A2
-:103AD000D30C3515EE29291C34398AF2553C5C9EED
-:103AE000CAF0C4E4318EA3F4570AEDD0BFC38CF7FB
-:103AF000C3BA715C7EB2F597F3F5E9BEA3C11E3976
-:103B00009112FEBDA0C77B09DAFE3A888ECE747C86
-:103B1000CEF87ECB5AC6E71ADF7BAF1E0DCFBF7C37
-:103B20009BF1118C037D44F7E54BC5E7ED930594BC
-:103B30000B16E20BC7DF5BCC9CBF8DCFA9C58EF601
-:103B40009C462774FF127C972C482F749D04C40355
-:103B5000DA2BD50FD0F13A3BBB0ED6C57E72B03D05
-:103B60002BC8C70BB83CB8B91795079705E501D91D
-:103B7000987C51F1812566EFE33F07FEA5FCEA71D1
-:103B800002FF9AF1FD9BCFB6EF3F721DA5F3CF5A0E
-:103B900034BE35CAD350BEADD97933C60943F9F620
-:103BA000B3F47A12966FD3F9FB73A17C9BDEF91FF5
-:103BB00095A71AFC1E09811F958FBFDCED8C0CC7E1
-:103BC00050F938AC9733AC7CA47F6F93829E74A875
-:103BD000D19F46778B7EBDB40FC8A16EFAD4E8AFF3
-:103BE0009B3E35FA0B3DAF117EA1CFAB21E9496772
-:103BF0003F98EF221E3BC5B77F8F88DF4DEA72FAF0
-:103C000063210EB42A8ACC023BBC4BE1F57856F70F
-:103C100027CB4D2027B4767F148BAB7555F963E322
-:103C200075F6F5B1363116E2BC9DDEF0DF79C3CC16
-:103C300044BA7E6784EFC0697189AEE8D841B85E46
-:103C400074A617F0552EDA326F81FCD16611BFE7EA
-:103C5000336FE5B5B19027D2D5D677E234DA3EFF9F
-:103C600015FE393F8F2AA55138CFE5783F493C0FE3
-:103C700015D1F3CD6D63F6F3BC0DE1E944BB3FAF65
-:103C8000B62D97411E51BBF5437DFC6811FFDE4206
-:103C9000CDC690F6B671484F8B42E8C9CDFDA3134F
-:103CA000BDB87E1E4C0673FFC4A4CF0B2917732723
-:103CB000C23B1E5D8744CCBB3EDB26922638E776AE
-:103CC000C14B80BF3DC94897B5547EE8E3C0A7808B
-:103CD000EECEF33EDDA9DFFE77C1EDB4CB9267DF18
-:103CE0001FF40B5A9E7AF6BD4B5E80FA734733DFA2
-:103CF000273DFB97EEFD6626C8FFAEBD1682719587
-:103D0000BD2F67DE0EF5DD16CC3FEABACBC2E2C1AD
-:103D10007BED984FD795C1DE8B69D8F3F520CCDFCA
-:103D2000268D88B784DECCEF38DBF6B73FE27BB672
-:103D30006DF454A06FF7C6A03D5EB73BCA0B4E6A48
-:103D4000D79EAF0BF4F718DFF73CB5328BE377D98A
-:103D5000C934887F75C5B33C9BBA17863DB692AE11
-:103D6000BFB4B55D86F7774A5FFCFB2090375D3BBB
-:103D7000991D71DADCF928711192D1FB8EBBCD143B
-:103D80005FA7C1B6A3BCF27CEF3DE3E19EA3275C35
-:103D9000181CBA281CE05C142E35202723C123BF31
-:103DA00037FB4ECF0F0F1E6766C2FA4BDAAEC07BF1
-:103DB00088205C0495B5DBBD5601CFCFDAF77E3D98
-:103DC00008E4F1672D2B51BF5FE8DCD7FC60E9E028
-:103DD0009F3DB7E0BB98732FFBC19E9BD17F00F442
-:103DE00053724F3EE849E7CFFD18EB4FDB5DB8DF7C
-:103DF0008BE4FFFBFF5FA3F79D02E6B15C08EF3B9E
-:103E0000FED7E2FD158E77BB02F9125D7BFE9E495F
-:103E100074E7BFD0B93B7EB0F83EFFB9353BA8C3CD
-:103E200054AFE4D3FDBD479AA764D1F22DF58B249E
-:103E3000705B2D91EE6BD2995F611158FE3799221C
-:103E400068F1A50E43FE537A0DDA1B13D4BBD97764
-:103E50009AA4FA0EC83FED2899EB5A873DF2F0BBC1
-:103E6000021D9347F2BAD1DF7A5320AA40EDDB0955
-:103E700025E30E81BD375115D11EA425DA81EF64EB
-:103E800056B0F642A39F313DC43FB8769AF1F9147B
-:103E90003EDF54B24CC9A7F09A9A2E295E0AA2E9D5
-:103EA000C5F56638CFF41B04D2AC8B6F4E0999EF81
-:103EB0000308A0E9ECC8EF0ABFBC74E6775A846532
-:103EC000080F522CF2F78D2E003FC2E0DD31793021
-:103ED000CB33965C0C7E5397BA306ECAFD50331FBD
-:103EE0006FB6ADE900BE3513A3FFA9F99191E04C7F
-:103EF000B85F8AF36407E16E5645F44B75F3213CD5
-:103F0000347C7C573C68F8FBBEF890D289E15E5562
-:103F10002B175A672F867B082BE4BDD379276E6059
-:103F2000EF91587305846355A119DFE3FAB3A9AA89
-:103F3000000CE7CA2157D4DEC6A675017C1672387C
-:103F400056937AB43BC9B7E7CE1515E0AD1FDAAD8D
-:103F50000B5542C653BFA4BA48F045D3F32F9088FF
-:103F6000272E0FE2A002F9501F07F51AEBF0776534
-:103F70004A709E0BF58F241FFED5E59FA83CFA9052
-:103F800022FD1894983F4324BDFF38AB8DC1B16E1C
-:103F900089E0CD463AF299F5F7C04F70BAFED31DCD
-:103FA0004350CE15DF3B308EF9B5F998D753C7EDA6
-:103FB000FDB31E671CC473CEB6F58D8378CDD9438F
-:103FC000A5B1E1F2790E73BFF2F72BAC58769509E3
-:103FD000CD621CBE7F3201F570591401B9133A6EDF
-:103FE00075BA1697A997318E4F583E7E353FC70256
-:103FF0003A342E4187B70DE33F9106F5C403FC7DAB
-:10400000A8BB57F9BEF0053F16E07A38AAB322DC08
-:10401000770A7FC6E56AE5BE6F64881F4C6ACBC22B
-:10402000EF4C4E2A33BE0F785F3AF7CF879021B01E
-:10403000AFCA7D636287015E0E89AE280ADFBAB619
-:1040400033B23BCCFD5C283C617E88231F37BBAA82
-:10405000019EC7EF8EC2EF00BCC1EF8B72F9F72152
-:10406000E11342103FDB9CCEEE21BE4E6771F46B34
-:104070002A8BCDC974DDDC566530E497F5E2FDBFCF
-:104080004E77E2F3DE7C9CD6AFD712D6EF98ACD455
-:10409000863B7F4626A39F05C4F5E342E18787B7A9
-:1040A000E27BED3E783FEE6C99C0DF9F09A56B8205
-:1040B000FC7176B4E005FD0B7E2CD62B05D4FF6F8A
-:1040C0006879159398BED4E83E14CE6F71FAD5D6B0
-:1040D000EFE2707F9BD38706670DBEA1FBD5FA5335
-:1040E0007975953EDE3271D7E0A7C13EA96D1314F4
-:1040F000139DAA56EA94810FEB76DD6786FB85E96E
-:10410000FC775A885435487FBFFB75BA84F3EDCFEE
-:104110001B81F6E3171B987DACCE3B130B76D01BAF
-:1041200026D75B23801FDF140DDF370F2DDF5FA144
-:104130002C2A33EBE7CD627ED29262338487AE5F66
-:10414000D26E4ED5D1D3D7908F3534D8DE6B89134C
-:10415000F318E97AB80FCF3D1602F94BB92D1D259A
-:1041600031F4F9F5F5F18C0E6B5ADA65ACB3EF0D5D
-:104170006BEB69EB84F2D3E4CA18437D6E69673A4E
-:10418000C0A5D2E25BEE0A43A7F76774C755BF9B91
-:104190009E5029DD0EFAFF414F9CA908F73DD4D966
-:1041A0001C6E3AFD901A4E3F2C5BE94C05F82FDB54
-:1041B000D337159863D92BE529E1F4C33B2BD8FD00
-:1041C000E1519E7FD93599EA87CB75FA617214D295
-:1041D00047E8B87119DA77552EA01F347CFD87E5C2
-:1041E000CC3BA01FC2F0F5CC0CA37E98DA361BF5B1
-:1041F000C3D4C92271EAE27153322EA41F8A53A696
-:1042000063DDEC8A094337EF70BF04E00A25AC0395
-:104210007AE2EE0C26F743F54524799E7DB1F2FC57
-:104220007F08CE9A3C5F3685BDCFDF930E09CAEB7F
-:1042300065D305FC1D93657B983C5F76038F4B86A9
-:10424000C8D72A90AFF97AF9CAC6D7BA993EA8DB7F
-:1042500095F5D319F4F975CD669795F6BF2E286FAD
-:104260000BF4F2F6EE0C498373A61206BFD366C4B4
-:1042700010A7515EF50339757CF0CBB9CF00DDBFD7
-:10428000C1DE37FB33D7E3AF0F7E391FE2E91FF101
-:10429000795B33185E4EAF208BCA281C4AE7317B0E
-:1042A00078E97611E150DBCAECBCDA6D02BED75B6F
-:1042B00091F70DDE1B2EDEC3EE0DE1BBBEC53A3C11
-:1042C0002E7EA3B3A9373CDF24E0BD67B56B317BFD
-:1042D000FFEF611627B6D2FF205F626D74EC668235
-:1042E000793A2AC69B9772B8555AFC07617CE51348
-:1042F000826B13CA35637C7A69BFB19F807FB078C7
-:104300005B48BB6B2DDE672C85B8B3CE1FF93DE74C
-:1043100093F9A22FF719C80F7C4B0CFBBB675ABF50
-:104320006E38D47C4F381CA670C8FFE7E150D776B2
-:104330001FE6DF7CDFF3BF93C1E3ED79241FF8E5CF
-:10434000CF2615F9DFF3AA88EF17CFBBAF7FAA3EC0
-:104350004FE93887C31B2677531AF4AB65EF212F3B
-:10436000D8B8E300BC223EA3850C86B0FD82878DC1
-:104370007AB25B2FB73A51EFCEA8DF21C077FDE7C5
-:104380008B047F0F6C6E9EC50DF7AF87A3FC28CF03
-:10439000343AB467B2DF8F8BC964EB1EEFE52F436D
-:1043A000BF6297A0209FC07735A04EF100DFD5D81F
-:1043B0003FECEB0A0E778CCFD4ED6278AAA378019C
-:1043C0003EABA0F62EE891EBA9DEC1FBB2B6763388
-:1043D000F4AFA1FD1251EEB8D0DFD5F413DCDF1538
-:1043E000A7E8F0B6E718A3DFAD828B84C15B0EFDB2
-:1043F000EF7C788B842FCD7EB858BC69F0B0671AFB
-:10440000F17738AAA37208DE53B1DF03226DF17889
-:10441000AFF251735FC4636F2E6743E91BEC7DA756
-:104420002EBE74356C1C3F601F857972B86E36B332
-:1044300087F4F225D48FAE231D68D724A7B97F9DBA
-:10444000AECB8B9BCAF357BAEF7583FDE6679CA78B
-:104450001F7194E0FD8F96570BBF2085F960BCBE9D
-:104460003FA3E0E80C7ADE2FD688F89EF2B526E767
-:104470009122E0E375660274F9C5EB6695D9A13126
-:10448000288767BF71DC0CA191D9905F40FBCDBE3E
-:1044900093C9DBE330196DFB03D5632A7CBF84B479
-:1044A0000C85FCFDC9AEF672C8DF9E927F7815DCE4
-:1044B000D35D53AA1C3902F05D2B1280EF876B4A43
-:1044C000D15FB9E94601E9FADD15F89B5864CAE401
-:1044D000AC2347E8BA37AC49C67BB619EA8172A06B
-:1044E000B7B913ED36B8A71B972306F37B09BC0FAA
-:1044F000D5B10AE4F78CFA1BA7C07E6BA85E80B822
-:104500006B4DDBE1F254A86F14F0F7D4EA3C6E195E
-:104510005E85EA78F88C0CF18F6ADA0FD053B79188
-:10452000F5ABDB22E07B3ED5543EC0F9AAB70804C8
-:104530005E28E9A0F69F95CDEB850F34756CA4E35A
-:10454000697D018C8779B7C4E3EFDED5BDCEDE137C
-:10455000AA2E5C7910E453351D471F938E2D37E248
-:104560007C0B370A0452836B0AB3EE2984F95E3759
-:10457000E3F7418EB6FF4C867DCFA4EBA5D1F9E7DA
-:104580008A9DE5986F7DBBA0E07B4D65B7211F74C8
-:10459000713E2049B7B2FB6681D7B95DA8E9C7C7AC
-:1045A00032B391BEAB6F59D904E7EAF42467814B6B
-:1045B00054B7EB8C0C76DE472BE00334146F3C0FC2
-:1045C0006EBFE7B8DCA99353BECCBE488FF3761517
-:1045D000239FCF2755782FEE5EC9F4F2B155515E77
-:1045E00001EC11B3827A73FFAA1F3D04E73FFD94EB
-:1045F00019EF4B4F6774627CF6C446337E3FA4616B
-:10460000A38872E4C4761617121F99529106F0A37C
-:104610007200E86EFFC65219E4E109AF80E34B1F58
-:10462000B93985C57D8DF2A3DAB908E5C523514CAA
-:104630003E2C7838FCFD6A4479B1BC82C9F7107908
-:10464000B034BD09E37EA172A28ED834F99007F58B
-:104650000E5F1AD26FEDEB6602F65DADA4CC7C184E
-:10466000E8664614DC2453BEF01D00F9F685577049
-:104670007AE8F3EB673D3F14E0F731C01BF8624383
-:1046800022DEAF567B67235CB57CC4050F1BE9595E
-:10469000CB7B9AEE1683EFFBD0FF5D5F1343545D37
-:1046A000BFA37752BAA4EBCDDA2578E13B4847EFB8
-:1046B0003C76F0E67CAC2B4087B5B770BDBAC18EB6
-:1046C000747BF4D633AB802E67DE21E0FE89C7DD34
-:1046D000047AA5F661C10971CD0577B0F10BE878D0
-:1046E000A097A33F63F443E9D809745EBBF1BE838E
-:1046F000D87F8BE084F98F6E9A8D7AB8C623127CAE
-:10470000BEE518DACB541F60DED07E8F9802745E4F
-:10471000DB685100AF1ABD68F4778C7F879A585DCB
-:1047200083AEA1E36ECC7486A53B715A16D257DDD9
-:104730007633D24B9D87D1D3B1A744A4C3FDABAE92
-:10474000AD00FA39BD5588407F94BEF283F4253E12
-:1047500062C6F10B9E64F185FD1B195D9F6865F6CD
-:1047600069E923FDD1AF59F08699B0F803B1E9EDBD
-:104770008F0BD16128DDF5D04B9C0E23D19DDBDC66
-:104780003215F20F663F4DF7EF0CC2ABB4E9568C11
-:104790000394364DC7F36AFC532DB1BC8D79CD2BF4
-:1047A000593EA3C4F27BBEF3BE42F6715F503FE6B2
-:1047B000817E84FC131FDDC7CBDB1F433BE0F35F2F
-:1047C0001DC3FCC6C52F50FCD3FEA7B7DB890FED78
-:1047D0006C2FCA9945AD22E69712C957708DEE7DB0
-:1047E0000D2D2F63F16FEC08F7453B2DDE4A3A7E25
-:1047F000D1B3C707E13DF95DCC4EF5FC8A7D6F86EC
-:10480000783A075D03F99912CB0F09D5BFD17D58CE
-:104810001CE7D4F331F85D26615B3BDE332D6AB9CA
-:10482000D66CD1C52D853E66AD1FDEDF7828FEE152
-:104830007E11F6A7FF5D092D2FE4D4938C7F16ED32
-:1048400032A37DB468DB268CF7D56D3B83F9B3A525
-:10485000BF792A16E050B74B34E64F6D137D16CC66
-:10486000F3128F59D8F7390C794CB5ADECFD8EDACF
-:10487000169E2714923FB3F8377B9EF550D02C7EBE
-:10488000E68958E0A74F3BB6C6023CE97C987F34E6
-:10489000B130427ED285F2925AD6F2BCA4F1F87BB6
-:1048A0001DA179499FC23FA81E77F531E679926D27
-:1048B0004C6E51EC17847B1F49B35F163FF5D5A3AF
-:1048C00090477B6AE7678FC2FE97FCE38B4721AF77
-:1048D00083EC8D52C09EA8FBD53B987FA88D1BDB37
-:1048E00087FB474F3E81F99BA7DFB3A05D787ACF66
-:1048F000894CB0174EEFF82605F23297EF29C7F82A
-:10490000C4F2DF96E27BA291FC4DA04FEF45E48F0D
-:1049100086E2637FABE8B3D17D7EFEAE05F9BF3B97
-:10492000CFAC6529CBDF73F2FCB2EDE1F374B57C5B
-:10493000A8DAD66B268E0479D7CAF47A777ED48526
-:10494000F2CADEA678BDFC22F0B79DE70FB68C0F49
-:104950009B57F639FC83E2A9A68F31AFECABD6F9B1
-:10496000BFFC393C6B0DFFBEB6C6D717829B9607BE
-:104970003CB48F7A531FE08F9DBFC63C3EC05BA501
-:1049800013F4FF579910DF3C69F663DCD0BFC7A270
-:1049900040BED7A23D47915F4EFFF630E6D9129E4A
-:1049A0008F7B9A74FFB1BC491EBBA8DB6267F968B4
-:1049B0001CFE90AFE68CC5769E97C6E858CB578B09
-:1049C00094A7F6649F6C665FF3FCE4A5CE0E59B124
-:1049D00005F105F8110A015FC70CF97FDAB943E761
-:1049E00053000E57E8F32F23E503723BBD07BE9833
-:1049F0005C3EBD89E76376E75912929E07F9414C08
-:104A00001FD67985A3E1F0ABE55F6E09C1AF76BE35
-:104A1000487CA1F1E785F7FDCFC1E5A13EEC7D0023
-:104A20000D3EA7BE0D2FA75FE4FC4EFD96BD7D7425
-:104A3000EFBDCCE27E8B9677A6EDB7A985E9E5536D
-:104A4000DB98DD18CADFB5117E57EB0DBE4EEDAE1B
-:104A5000F64120874EED7B9ED39D97BF87734CF622
-:104A600070B9EDD5CBED08BF6376B40FF317A9BFCE
-:104A70001B76BEBAED67C2CEF7A9A45E0BFBFFB4EE
-:104A800083D9219FB688617F0FA1BD8FF17DD52687
-:104A9000BB8C7E97181B8DF268B9BDF05DF8BEDB4C
-:104AA00072BB8CF90E0D2B797EC49D2EFC3D8F06BA
-:104AB000FB58FC1D8855001F9D1F6A56DCF8FB1330
-:104AC0006647553EF857A1EF77CA4926E2D5E35F1E
-:104AD000F2A4E3F7BBB2BF9640EF74AC30BE37D25E
-:104AE00021290712E97C1D65820BECDD9E74669C12
-:104AF000FF6A5534C4CF20560DE73AEB62DF45B369
-:104B00009B7C0AED42EC511D0E74F49CEC77ABE1FA
-:104B1000E7BAE03E7CDD0A6B3F788FEBFF022FB6F1
-:104B2000D5840080000000001F8B080000000000FA
-:104B3000000BB57D097C54D5B9F8B973EF4C26CB81
-:104B400024936560202C37FB1E261012D058261B9C
-:104B50000609382255D480376C610B89686D6CFD6D
-:104B600097613145E5B5A12E50A5CF01C1C7A3F886
-:104B70001A166BAC510708142DDAD0E293FA571BC2
-:104B8000942A28981194F25A2CFFF37DE79CCCDCF0
-:104B90009B0984BEFEA3FEAEE7DEB37EFBF79DEF6E
-:104BA0009C89252E89C884D85C8AB7279BE0DF15AD
-:104BB000FA5F1CA1652B2FA7E0E3787A092131EC7D
-:104BC00015FD6EDF6F920889CA26D94A3121761207
-:104BD000E59269F98958F761299690F536AD96D036
-:104BE000E715F89BD4FF495CCA2918CF4AFFB99250
-:104BF0004AFB9B40CBD6E0F8F16E7D3991849471ED
-:104C00003E6E4286C07BFAA7123259A633A3F388C0
-:104C1000AF36F92224FC5E9B312438DF780771F926
-:104C2000E1FBB4189797D68F8961F313F3A5F3F9D5
-:104C300018E6A3D27F703EF93D5E13C1797D1C3A20
-:104C40000FFA27796C38BF8F0DF3FB38747E05AAF5
-:104C50002DE9D3685A50887285C237C6DA4D389C20
-:104C6000CF87C299102F514A009E02AEF43BED2728
-:104C7000457A52B922015CED1249C3F10CED46D8D8
-:104C8000B17F28D37EC7C09A271252E694DCA7C60C
-:104C9000D1FFEF4C22641821A92D95E4135A96DA1E
-:104CA00008C2277D3DF145D0F9A5074C58266BA3D6
-:104CB0007C19B46D84957823C7D27A0AF19AC742D9
-:104CC000AF3E42C62370579B6857CA3A421EA3EDB7
-:104CD0003A0315A60514A8EDF089F63F51754F511A
-:104CE00069BDD6DB34A7A9089693D7D65546081DCB
-:104CF0002E477211625A95DB7D6424214950FF06CC
-:104D0000F89EDBED8EC1EFAC4C889FD075B545F5B4
-:104D100095DD56272DA7B2F29DBEDCB675B4BF0F48
-:104D2000D23D77AA0EFACE6ACF05F8137F02AE778E
-:104D300040FAA270258EE03CB3B7F92BA3E8246EAD
-:104D400009508052FC67D03EBAF3013FDD16209235
-:104D5000ED31A2ECB710FAF4EC3B66E9A1CFC6F650
-:104D600063F8DD0465FA1C9DE8AF4CA6EB7C50BDF2
-:104D7000D1E3CCA1FDEDAB779AEC84AC546FEC564B
-:104D80001CA17098A48383B2FA26031C6EBA2E3835
-:104D9000ACF4DD847018ECBACFA99E1F015EA69614
-:104DA0009B8844072D3D11E393181F477A0A82FD23
-:104DB0006C319145ED31E1FA59C5F0CFEB093A1A62
-:104DC000884ED2883D17E8D4482F747D35ED148E77
-:104DD00053B57A4F5562904E895D1B37A300E63973
-:104DE000F74998A718776AF90A3995CEE7498A23CF
-:104DF000E8D7D1E28DCCA474EA709B5CC0E7E7549D
-:104E0000EDE7503F7656C06FA6554A8976BF941697
-:104E1000EC5FD07DEB6B32D2776BBDC9B71AE54141
-:104E20008F04EB0EE2BDC780F700C37BC749C4FB0C
-:104E3000F2CE930CEF1DAB2AA28AA12CD923545891
-:104E40004FA008F0F92BDF9D1E85E2737474A01546
-:104E5000E8C14CBEEBA9CD41B8BF0874DA0FEE7CB7
-:104E60005E02FE03E1ADED48EAE3F9B4AAF7A8C992
-:104E700095A106E125EA1D572D586F63AAF61B1868
-:104E8000A76942CF61BA52B2E7C81F62353ADFD88C
-:104E9000A333F643FBD89914136A70DCB6A3AB2B8B
-:104EA00080FEDB80FE51CE04BCF698ABC183F14599
-:104EB0001F3CF69D44F898A04CDFEFB430BA29EBC4
-:104EC00090DC3EE08B6872AF873EDF564D38BF9373
-:104ED000AACC9F12C3E3D103B24ADB97AD35617D03
-:104EE000073CF343D7BF16EB9D54152E77183C04AF
-:104EF0005E051D51C289BE8DCE797896F63EAC3FD7
-:104F0000483709D1A9F47B69D7DCFB496AB0DD4F8A
-:104F10005612CF7C73B01EA59F9775F456608E0411
-:104F2000B8F5D10FA54B902F46FCD076A7193F2599
-:104F300044ABB4FEEEAE15B2963F78BC9644906694
-:104F4000987F493469DE43DB97C4D127941379797C
-:104F5000282F27F3E768FE3E8F95D33E7099245A99
-:104F6000DE0270073CA498189C147B2EF0912985D2
-:104F7000C1B9CC198DF25FF0AB42C11997006A88B4
-:104F800078E1991A4835011E05FF2A0193DF46F59D
-:104F90005FAAA29A5CF4FD5B2B354F55C6C0F2E5C3
-:104FA000961CD9E30B232FE25218DEA980F69ECA85
-:104FB00006ED2C91382081615A5C0A9D57A3B5E714
-:104FC0002733E8D7E539172C809FD5D1CB6FD4F2A2
-:104FD000071EC7388FB72EFF361AE8ABF352444D81
-:104FE00038795503EBA7E31F59390BDB3D1A155BE5
-:104FF000C8952ADA2DDF41D1449FE94B6A4921E067
-:10500000C3AB2480FE8B965CDB09E285E9C3A12952
-:10501000BEED29801F5F2D96F3D2C87609F0A4ADAE
-:10502000B141594EC1FA1472C23E92AE4460DFAA39
-:1050300042ED0D44792AE0B3F9A00D847D04ADAFB3
-:10504000C27BBD3D45E7B7958C017CB7552540BD7A
-:1050500038DEEF2566E708BBA83AFD963312CC7719
-:10506000B45701B94AD252703EE5C4ACB38F4AB2CC
-:1050700028C8617E59B93EF85E69357CE77454DD15
-:10508000CF8E6A73CDA0F43E359BD23F7F7F81FEE9
-:10509000373A82DC7B5B7E50BE4F51EFF254E9EC35
-:1050A0008F3617F0E1EFBE9591EF8DF8D8CAE9F190
-:1050B000C84A8FA78AF2DFAF22293EE87A2B5469CB
-:1050C000AD4DBD36FC8C7833C2EF3B9D0BD17E33AA
-:1050D000C2ABFC03575582DA1F3E467808F8D3F579
-:1050E000AD07B85567CBA8AF04BCFBC389D1C3EFEC
-:1050F00072683D89D10FC38744905E04FDC4A52129
-:10510000FC4B80F6E07B740A968DF035C293CA01A1
-:1051100037D6E7F83B0C70CB80AFEEDAEA214138A6
-:1051200050BAEA8A0FA12B01877E72238B9739DE52
-:1051300085BD5CCDFBA1F632DAC3950E9B0BC05F3B
-:10514000D9C8E65B9911B3D59B82F8DA8AFCE3A74C
-:105150001829C17FD9DF2566E752BB94D167E7E400
-:1051600033603F8F8ED0D6027F04A478B29520FCA6
-:105170003F36C05F57AE36D8CB4678FC0AFE676232
-:105180007FB809BAFB790AB5AFF36871381901F62F
-:105190006FE12BC57120C7496702CA63233D969E04
-:1051A000F0F4F5C3E917E953225ADF7B3BB5233A04
-:1051B000B21F7902CC9A1BAD6D32D0E18DC4BDE631
-:1051C0009415D62FE33CC5BCFEEEF4EC4CA1F26680
-:1051D000624FCD9A53A17CC1C717F0BE89C3FB268D
-:1051E000E2DD2FC7C253F9BACF8E0FE96F6F0AF70E
-:1051F00017924932ACC79EA232F9CEFB13EB1B9D2E
-:1052000046FC12C2D9EADB2AC1FC89D792101CCF16
-:10521000CCD1949131E3B51494C7CD04ED656A5EA9
-:105220000212CBF8F7326B8C1FE64302CAD93E3C20
-:1052300020DFD5D901AE142EE44A74707EBF4B91A5
-:10524000944FB383F33BB7C3EA95819F8769BF87C8
-:1052500071CE4A470B916F157F26E841E3F70B1D8E
-:105260005DCBE13BADB710EBF1752D05A791D25D9C
-:10527000E0B508DFD694ABD8A156AAC242E44159A2
-:10528000149327D5242083DDD919C9F8F9F5AF1671
-:10529000213FB8897D6D1EEDEFD0F9C947809F2B66
-:1052A000A978817A932EE9FDB66BD1691509CC8175
-:1052B00076D576B3C10FF4A2BE59CBE59AB0D34CE4
-:1052C000A9DAB9147C3FCA077AA6F3ABC92AE06D04
-:1052D0006BF6F85B6EA7555273C6CD00F7CC64ED44
-:1052E0003683FE9BCDE96B02D097845690A0AF8B9E
-:1052F000D04FDA3A037DD913747EDD2DC48FEB2FA6
-:10530000CB36FF4D373F6E9718EDF5A09DDE16D6D4
-:10531000BF235D0AC9A6709EC3E1BC36DEE205B9B3
-:10532000A6DC27F9480ACC978C5A45E739BBD9AC9B
-:10533000F347E7C42B88C739AB227D84F9DFCE7AE7
-:105340005AD6E8FBC7A098ED7686DA55A425A43D89
-:10535000D0438C8AF43BC7CEDE7D44FB189600FD1B
-:105360009E72A013EF359F0FA553E3F803F66B6809
-:10537000B75622B3C07E5A6B763B5D21F6C7A85460
-:1053800066BF9CB7576D32A50E6C9768D664B7920E
-:10539000182CF7C45B67F9C2D831A23F4127651AC0
-:1053A000F3CB07EA373D50857699E949BF0CF6768D
-:1053B0007A80A07D5C16709BE6E9EC74E69FF6B3FC
-:1053C000D3DBF7A39DBE6CDF7E66A7B7AF427B7FC2
-:1053D00019B5F741BE53BB1164259B503EDAEF7DF2
-:1053E0007E26E52D52D62EF5F9A10A45455A1BAB6E
-:1053F0007FF7D6ECF847D3C14FD49C66EAF7DC9D23
-:105400005AB0C14AFD9ED6141249A8DF332BB5E02D
-:10541000B6F513283525B825128FE50D311307EFA2
-:10542000D7DE9D9ABF01FCDA81FCCBEA54F5AAFED7
-:10543000E507E99EBB5343E202543E86B54732324C
-:105440002AE6403D2137CAA2187F3E6AF2A7FD1422
-:10545000FCADB76402FAF4969679E8074C6B59EC08
-:10546000A9A2F3E93D70399398405E32BC37A63269
-:10547000BBA6299AD9974DD1B41F2A6FDE746A8DC5
-:10548000D07F77F6F3EBC7527EA9EB905DE02F4615
-:10549000665D1E05FC3F6DFCF34F8EA5E37C185046
-:1054A00030FED069A37448DF7F4824B467CB8E45B3
-:1054B00078F651BC7CDF59DE961AE29F7CDF598575
-:1054C00065524B1D2BCA1F2BAC8C2F3F24FBD37E68
-:1054D0004AC7F1364B68079C6F4E89033AE834D3CC
-:1054E000F587D0E3EA5405E96F35A7C7BA4B320612
-:1054F000CD3ACDFEE4665ABF4EF19BC10FACBB6402
-:10550000C1F7300F984F67A4BE9FC7793F8FF7F55B
-:1055100043E1300EEA19FB51D87B89ADCF8887D3A0
-:1055200029953F85F57CDFE96E43BC51F905FAA268
-:10553000ACB8EB04D811D7D64B6E09F452D365C979
-:105540003F9AC2F3EC3E33FAF767C13FA4E39DDB19
-:105550007770C85CFA6CDCFDC758F007B7707C9DAB
-:1055600053BA63617ECB5EA2FE0BDA43FE21F76085
-:10557000FB79258FB161ACA1FA7AECB707933D2C8A
-:1055800078A8427C4ED8A53759BD3E985FE72A19C6
-:10559000E508D5E7226E2A81FC9EB44F7647C6F611
-:1055A000B7575F4E350B796B023DF6809D8D33907A
-:1055B0003C28BB94487C21F2A24CF1CB30FFB24B8B
-:1055C00043F0FDB923A94FD402DD12B30BCD4485BE
-:1055D00074A1BD2C11F1D7954ED7F33A2FBCB1EF82
-:1055E000C2ED37223352BD48EB7CC7AF25A1FD0C7D
-:1055F00021D292A05D38E9923EEE6AB4A3859EADB9
-:10560000E82C5A9B4C00EEEAED37021D1E51907FAC
-:105610008C76767560F200F6F406A4A33DFBD2A268
-:10562000212EB091F379D3BE0B93413E2D27FE3B43
-:105630006E4C82B8836CF793ABC5BBD6FE6E121D61
-:10564000FF8D80A2823C7823D0652DC4B209E31C73
-:10565000656F97E501FF7606941AF05BCBBEEA8A88
-:105660009E971FB46B3A2F9BF0FD1B970FE07BD1E9
-:105670006F6720210FF4F36E13F3B7BB0EFF2D1AE3
-:10568000E4EB1B97CF27A2DF2FEC92FE7635FA01D1
-:105690009536B92F0E1D6ABF13B9ECB815FC8D38BD
-:1056A0003391110FCC1FED67977C40D6DA487FFB12
-:1056B00044C01FC812F8A69F5D1D84B7CEBEBE921F
-:1056C000CAEDE59164EC15B0732F272E057DDDDB67
-:1056D000196D5F8DF1296657F4767DFEB3A9F0FE52
-:1056E000A88CF1B6DECB32F2D581D7978EEE890940
-:1056F000857B2BE2EFE2B0AFBE7C95D6BF78280A5F
-:10570000E3EA4471E5858B9F04E3C9FEE126273C6B
-:10571000BDC34D1390ED305EF09D60BCC09186F12D
-:1057200082C0645057999B4F5A20DEB231D5333432
-:105730000DDBB747C3BA174531F9E42515C9D4784D
-:10574000222F1D315500BD14AF5211EF3BCDD4C4F3
-:1057500002FED8CEFCFB9D54DE825FB4B8BDCD9274
-:105760001282E7C51441B0BED366EFA88490F73B20
-:10577000D2583CE1F4A125CF019CBC7F8A2019615D
-:10578000ECD387D2983CDC6BF14EDD05F53E36114B
-:1057900018AFEBF06F0E0FA7785E7C422D023D3004
-:1057A0002B4DC57A1D4777B60EA7F53A3E00ED4959
-:1057B0004DF26DF5B2898EFB2A5159DCEFB809E73D
-:1057C000DB172725EE4458EF1D694C8EBD7A84D136
-:1057D000AB18FFD528A6EF26A731F95296C6E26E80
-:1057E0007B8E5424CE45BED22601DC9A4EF5B4C63B
-:1057F000AAC138A1B00F271EDF33B580FEEFC4B3B6
-:10580000263BA04F3DBE5586F5AAA7098997FAC742
-:10581000B1687F53D21CC1FE5E3DCBFAA3F33800C2
-:105820007C175845EC5B91EA3C8FE7D3F2ABDD4A3D
-:10583000C2632AE203F581C083588F9887DA4EDC71
-:105840005B629045DC7BAE168FA67E27F0DB382EA0
-:105850003FDF4D75DF95C6ECAC514077A70F45A1F2
-:105860003DB697C7B589B37E34C04FE0E97BFC698C
-:105870009CCF40E337733A10CF9D66D58BF4F0127E
-:10588000D3BB3B6D7E6B1AC8BF57D2B0AC7ABDD1CB
-:1058900085F47B5347864B56919E9B19DD323ABF68
-:1058A00089D3B9DA1EB0A484E06160F9C6E0DE47AE
-:1058B0003F4A3BD255C70982FCB664C77D2C0E49CE
-:1058C000FCC98C9FBCC9C05FC0178CCFFCC324F639
-:1058D0008C053E99D8B9654D326DD700749F1F84F1
-:1058E000830A7C017C26D6696376F2CF78597C6F77
-:1058F0004B6371C76A393FAEE72AF1BB37563A8925
-:105900001212BFFB199FFF62B201EDD3C597DBD026
-:105910006E559BD973F103EC99B9B9DE02FA60F1C7
-:1059200026C91DCEAEB673FC9DE37C404C51C389A5
-:1059300033F8DDC1F9E0CCBE270EC23A29BD3E07DF
-:10594000F0BFA163C3D3002641FF67B699B1BD90F4
-:1059500023A2FD36DEFF4BC719FF4CDC66AEB89BB9
-:10596000C27BA297D8219EFEEAB6ED32C8F75781D6
-:105970003F5298DC00BD7CFAD063D13F003A3869D1
-:105980002210B7DF6B218B7687E0B76BCBCB3A79F0
-:10599000B064C7AAA9D04F694F82047A40C8018178
-:1059A000EFBD16D7149427D30DF2A48AB53F06F0A5
-:1059B000A4EB7A82CB93276AA83CA1AFE2B7C54B90
-:1059C000D0CF5E1E2736C2AF8BE353D0E38D41B9F3
-:1059D000DBC5E46E4F2C74BD7CDA798CD3F68DC3B5
-:1059E000E9EE892A41772912C091DAF9A67458376D
-:1059F000850FD03FB5F3EF9D918F5C7A44C1FD21B7
-:105A0000BEDF44560BFB47C7BF42CEBD9BAA1D87D6
-:105A1000F14BAA9AD780FF9158EB45BA3E2369A370
-:105A200013A8BE3A037C1D462EBCCAE5C845B33652
-:105A3000DA1EE67B908FC870E083454433C13AC8D4
-:105A400066C90E7015DFD5CD8CDE3EE7F011EF3F55
-:105A500037C06B12C02B0DE1F539D753162B9D6F54
-:105A6000A68FE9292255203D12D32DC381DFCE9880
-:105A700009D2CF192A17016E8BA3F4FE8958D737A4
-:105A80009CAF2EC6B375ECE5E3FE097C9EF1580F82
-:105A9000ED0A6FB909F76B813E90DEA627A0DD45C0
-:105AA0001D2605F9BC6F3FC22F4B4C1EC8300F3B63
-:105AB000F8751827DA82FD2EDDB505E926BEC65E2B
-:105AC00004FB474F28AEC8F890786FD7F68DE84FA3
-:105AD000023D015F0E448F8B801E49183AF4513A03
-:105AE000A4ED126A9A118F14BFF674DA6F7C9526B2
-:105AF00003DD18F12BF619053CF61AF62567A633D7
-:105B0000F8A4A433FE54B9FC1A584FE8E52DC59704
-:105B10009AEED0D337E04DF05B4C3A934F03D1F976
-:105B200043E976ECB7F5C3794E9017623F4AEC2F04
-:105B30008BF1C7A6337A1C683FE99CAA15A51BF612
-:105B40003BD5FC209F5473FB71C5F608DCA7DF0D25
-:105B50005F00EE5D51B82FD1270715E2067C96A7AE
-:105B6000A7E07802BF6A8B85A4D3712FA6D477C52E
-:105B7000D04F37777B6B0BE83A765BBC33A7A1DD60
-:105B8000ED9A02FD4FA935D9218E1DEFB64B1007B6
-:105B9000411207BE38CAC621AA4B37EFA91CEE0234
-:105BA0004F020E03E9AB81F0F310878F837F37F24A
-:105BB0007506FF6E4E67F47F6DBEF6CA40F7B144BE
-:105BC0005B2DC3FCCB981CEAE3EB3282FB8D0BD23E
-:105BD000F57C2DCA61F87A417A285F4FE8D1F33518
-:105BE000B570B93E45FE726C33BB993FC9F8EC62A3
-:105BF000249BEF8A74A6871CA03F28FE1C5EB6EF8C
-:105C00003A95D319A5A03900EFB66D11B89F20F8C9
-:105C10003E7626A930C3FE2DE81BA835533B7113F1
-:105C2000ECDB3A2D2AEC239F3107104F67A8A3DA4B
-:105C300086F8F4603ECA994337307930AD4FFFB8EB
-:105C40004D507E7F04EE2754CB9D48D72BAA09EAFE
-:105C50008FAEEDA548078B6A5325A0B3253BE225FF
-:105C6000F89E506537C92172B1B445467AA274BB1B
-:105C70002E3D047EA5DE6619E0323A51739AE3A9FF
-:105C80009EDD367546685CE8495A5EEF0CC685684D
-:105C9000F96731C3061F17DA987ECBCFD68DA04A9D
-:105CA00024CDFD148C7B4EF56C04BC94243763BC6E
-:105CB00073B079104D3CAEF4C1236F6DAFA7EBAE5E
-:105CC0007B34F0087CBD17E2AED9903FC0E2AE4D08
-:105CD0009DC7301EDBC9F9F9EF4ECF0B30EEECE675
-:105CE00029FAF86B6070E32671BE251F10847F923D
-:105CF000A75986B884900BFBD21384FF28C1FE9B62
-:105D0000E007902B607F8A3C088887D9128272193D
-:105D1000CA71217A757D2DB583C2F0D9C1F498B0CE
-:105D2000729074FEFDD73FA0FE7E137C6272F1601C
-:105D30007A88DE7FA2F6E3211A8B7B60BCE97EEED7
-:105D4000433EB7DAF5FB2C9043EFC828FF8B222C9B
-:105D50005E09F687DC44B50FE1FD019B744A7E1BAA
-:105D6000F53F9BFE261137C4CFFE26E3F3B91F791A
-:105D70006A52C09FEF30B9A82500F91448C7AED1C8
-:105D8000C467A5F4D7CEF76BCB0FC6B8CDF47DAF03
-:105D90006445F9D7BB3FCA0B7CDD6B33615CB9EB63
-:105DA000B50884EB85F428EE5FFB747EB8D8FF88D5
-:105DB0008CE8F943196DBF3592F5BB3592C5E9B64C
-:105DC0003E9A1907F6E740FBE3652D6918E713F1E2
-:105DD000C7D4806A6249646C1C2540707D62BF7CB8
-:105DE00013E46B140F9CAFF1D7F4BE7C8D00D0533D
-:105DF000D3AC9EC33047A31F36E4E8C7FBA19F2165
-:105E00002D2C4CB0E9E80A09D6B9A92EBC1F26E80A
-:105E100068138F7B85E4457CABD32FF509D1A9218D
-:105E2000F253B47B9AE7459476CDDD0B761EE5EF11
-:105E300073A1FC3DB5E091C870FBF39E961F625CB8
-:105E40007420FAF79888162EEE373A83CB5B25300C
-:105E50001CEDC1372E46A961F2253CAF991C0017F5
-:105E6000119FE93FFE8F70FC61197DFB7FC307B373
-:105E7000FF679C77B7998C0CA757049E8DE38569C3
-:105E80003FDB15D2DE6321DAEE98FEED84DDEB9187
-:105E9000F8FEEE8704F5ABA0130AF77119F47BE165
-:105EA000DBF3C64541C2A1B559067970A1A32B19F0
-:105EB000E25603F987623EF42F235CBC858EE70926
-:105EC000878769194CBF7ACCCC0E95CA0FDD03F3D6
-:105ED000F27C65912242E86C22AF67DCC7ECFCEAF9
-:105EE000BFC7A19C34FB93C3C1CFB8BF3911829304
-:105EF0004CDFB171395C5ACB49454412C60BC856C8
-:105F000015FC40262FD516827C3E4672E3BAEB2064
-:105F1000E8E2003AEFC63CC80B4765AC57789FEA09
-:105F200003BF89EA85BB017EA544DB6B4A0BC24BEC
-:105F3000D043EB8BD44ED1C5AD18FF08FF75248F2D
-:105F4000FF5055E30EC5DFD059945443E4FE30CDE5
-:105F50004A9490385BF222BBAE3CB2D9A9ABEFF4C5
-:105F6000FA25E02B678BAA7B1F94576CBD23BD6479
-:105F70000BE8FF4DA407D7378ACF678CA4217D5C3F
-:105F800038FA4902C4257FC0F987AEB705D7DBA22E
-:105F90005D08A50FB1DE6BADEB8395743E94EF3FCA
-:105FA00002FF9C3E673F70521A8A70B7833AA07A0C
-:105FB00091B51BF9F031F423473677A31D3FA76550
-:105FC000BF04FA8BCA0D6CB769A5159FCFACB4A3FB
-:105FD0009F2FF03B82D6833C256F05C9867D81814A
-:105FE000F4D3C68C41EBA78D1961F493C91A7813C9
-:105FF000F6C11B3B6515E860CDC30998FFF25CBB99
-:1060000084FB2E073B59FEDF73AD51A847C4B85F30
-:10601000BE1487FB3F5FF27D40D2158FF4DD14CFB5
-:1060200071B2361EF7C97BF93E6447BAF61F1921D3
-:10603000F2E0B9CE6F22417FE4893C5B83DE01410F
-:106040002CD1F6E013011DB7A614AD93615D7768FE
-:10605000E32265E4F7DD8C5E997EFAE5AE0A9316DD
-:10606000829F0B1D5FCF39A0F6DF5F12FB50627F6E
-:10607000EA4DA7F66A4688BC36EE3B19F74BE45862
-:106080002BE669BBE42897ACD7B748876B32983EBC
-:106090005DB33F0AE1B8262306F77BE97C8FC03861
-:1060A0005D360B1946DF5F381183F5C4FCE97C0BC4
-:1060B0008F86996F932930E780A49BEFB1ABCF57C0
-:1060C0009FCF2CE6D7871F1E2F906D0AAEA3974453
-:1060D000B900AFED16D7090DF4EF3B512C7F8AE3E1
-:1060E0006F39E7CD5E8A2F89E2ABB7E34224D0F166
-:1060F000C174ED24CC431E198805FFE560E7851CBB
-:10610000E09781F60D958C8ABF00BE20FF0FF166E7
-:10611000D72EEC228C2FB5ABB4CBC8A8380BF5AF7B
-:10612000033EDF5C0F7C9A949875A1F697C4E5B3A3
-:10613000911EA5CEFDFF03FB01941F311FD53B8AA5
-:10614000F8D650B8B51670BA9C4954169FD1D34BA7
-:1061500047BAC79CE908F2F155E01309F57E99EEBC
-:10616000898627CC23792CCA291B94A95EDB6B492D
-:106170000DDA5BA3D398DC0BC413CC5F31EEF7666A
-:1061800064CC48CAA4704BCD564DF6FCEBE2879127
-:106190009957859F1FE9A291C3A911F619295CC8D7
-:1061A0003EF3595DBE80010E07D33D590C0E413AB6
-:1061B0005BA35E151E790C1E5A21ACC366A6F402C1
-:1061C000409950EFC4BC18D57D37EC7FEE5CC5E03C
-:1061D000D0FB2283C3EE2E13D2F516928BFC996B63
-:1061E0003A3F07FAA7F26702F453DCDD66827CC20D
-:1061F0000C9F6A82B8724E77BBC97475BA2DCB44B6
-:106200007DA14DCA64F6C5FD8087BC5D2C1E73154B
-:10621000BAADCC1C7F5D70AFCD1C3F783944E9CA64
-:10622000134A5783CD4BA2F4419213FAF747480F14
-:10623000C6FDF7BF1281F27EF91E09E5D3F2D73F02
-:106240009B03F05DFE9B0824CAAADF44E2F7F3FB40
-:10625000D8F72FCBC3EF4FDF9599807AB6B1FD3ECB
-:106260004FA87E1776C34FDDE7EDE972709F2F715F
-:106270001A3B6FB22652E49BB2FDBE584E6789238B
-:106280003D6ED05389D52C9E141BB310F7FBFA9F9B
-:106290002B617CEBE0EDEC7615ED07E33913398AE1
-:1062A000E5E539C8FAAF004E8935FAEF8E981ACC79
-:1062B000C77318F6FF04BCBD99DC6EB61027CA5927
-:1062C000C33EBF78FE2593DBEB6BE34DA1F204F4F4
-:1062D00000C07585CD8AEB5EE12089B51057B029E5
-:1062E0002E1CCBD08F78C6BB4D440D3D2F5313458C
-:1062F000D410BBC8E149D09587CE1AAEAB3F4C4B0A
-:10630000D57D4F5E94ABFB3EB279ACAE3CBAE506B0
-:106310005DFD140A80D072DABA5B74F533DA66E890
-:10632000CA599BEED6D5CFF1CDD57DCFDBB144F7A1
-:10633000BDA07D85AE3CA6E307BAFAF200F6B880B0
-:10634000B32CEC715BB1067425DBAC52A8DDF222F4
-:10635000AF571E6B45F83FC2F5F523360BEAEB4706
-:10636000B8BEEE72945C755FE69FF5DFDE16F4C092
-:10637000EDB50A1E2FFBF280C504F4B8FC20A58BF6
-:106380003168AFBD9DC9ECB5E9F5B8FA8005E45EAA
-:10639000F700F920EF65723F43A17E4C187FF09320
-:1063A0004C5517B713FE03956BEF73FDC2FC26D255
-:1063B0002C831C1072A9299AA09DD7146DC73C9FED
-:1063C000DED84B99C04F545E7D0CEDBAB39F683E4A
-:1063D0000072AA3302E5D45BD99FA03F7E4BCB422B
-:1063E0006CFF62A69DE1C5E252ED28A7F4FAF7A87A
-:1063F000B9BB16F07074BC4C56811DE42A1D4AAE20
-:1064000002F777C0DFA676F2B62C82FD5ECB5F3D49
-:10641000BA7211E64D0FD4DFD1A2488C9BD6025D33
-:10642000858C1B9DC5E099C19FD41045BFF3DCAF9F
-:106430006D3E2FF84B63DF8D2536C893F9E3382F77
-:10644000E823D27D3FECDF7BBF8EC1B84E6DD1BB60
-:10645000E35661BEA89BF97D13D89A6F7AF9ED587F
-:10646000F0D76B771F4CF286E0D1E8EF65F0F511BD
-:10647000A52713F34E5F3D3344A5CFDA570E25B160
-:10648000B8923EFFC5E8E7D7B62CD7D167E3A54859
-:106490005D1E4CA3D26D017C345E8AC1F7BD99FAB2
-:1064A00038C080F01A243C8DEF053C8F169D1905ED
-:1064B00071FA2F23C3D3F16DBC9E281BCF2F0C94F0
-:1064C000273F81B7BBE09A3814E24CB5167FFA60DB
-:1064D000E212024E6F5D6EC07311BF1EE05C44514C
-:1064E00016DB37F975F602CC6B9E686DAE04FD3D88
-:1064F00091C73FC3E4355767819D7BE25F93D73CEB
-:106500003D8BE387E70D0FCF52C3E6355FEBDCC968
-:10651000540B954B61F82BB70F7E7F9A398ED2F1D1
-:10652000FDBF30DB615E0DA0F320DEB2C58CF1D77C
-:10653000B72F471088877FB6D9FC3CE4BB2CFAC53F
-:10654000C1114F40FCBB2802F3F11AB69859BCB6F2
-:1065500028D2072187455BBE3704F22EBFA07CBB43
-:106560008CCEABE1170ECC077ABBEBB12180A73301
-:106570009C9F177DFBE33B00FEBB2DF6BC22FA5C23
-:10658000B64BD2E5992FD916A92B8B7C22813F22BD
-:1065900005F3CF552A4F5BB2F4E768C605F7255AD5
-:1065A000B2B85CBD9DCE77F9F80B16C0E3C1C351FC
-:1065B00038EF376264F473FD457FFDDD185AAEFC99
-:1065C00056C1BC7E637E12218874B290E71156BE1C
-:1065D000A2F49D0380B27F6533F2096D17531D92BB
-:1065E0006F5DF973E64F5746B23CE001F3960CF944
-:1065F0004AE29C45BF3CA5E0390B9D9D22E8E6A9F7
-:106600002C3D5F1F3CCCF292161EE576E535E4E6A4
-:106610003BB08E0CC0D75B75B06FF93687C6DB9781
-:106620003F5B3B8C963F9B2041648E7C76393CDF00
-:106630007C26F4129C0FC80EE2679A6B715F19D822
-:10664000F2D609F7E9CE2D0C5EDE5C5D9EDC956529
-:10665000C1F18DF2DD48F7FFBFE47B6DD1A1515E42
-:106660001B3E5F80E7D9DD4C3E1AF9DC28CF730D65
-:10667000723028C7659D1CCFE5722028CF2DF89D6C
-:106680009A69B81E6F89E25B23A1FFF31ED07D7E5D
-:106690008C9A584E9BACB5A7466B57F747FF2FD443
-:1066A000EF4AD13ECAA27C34FA97B955608CE7ED27
-:1066B0006A3301FFF60E608714A41AF282787C48D0
-:1066C0007C3F9B555E00F9AA7B54F614FC594C990B
-:1066D00090EF2F9FCD62FBCB3F01BB67F97F5E44FC
-:1066E000FEDC12A5391558CF708B2B74FF563C2F4A
-:1066F000727E1FF87CAD3EDFF9743A6178CFCED65A
-:10670000EDCF807F8FF90107A2106ECF3ADD9701A0
-:106710000EED4EF7B730AF32A7FB1F59217859CB9A
-:10672000D7A998F4716BF12CCD16F4EF413DBEA0C2
-:1067300022BCFC4DCD6679C1E54FDF350AECCEBFFA
-:10674000ECBF7B14C8C7AEA74AAF6A876EE0FCF9FE
-:106750006F5CEEC7F3B8E34F816F683901E296B41E
-:10676000FD028B27333EA41F73763CDBEF2EFF83A5
-:10677000278DC2E5D47A19E5F7A9181667FC2446D7
-:10678000A9D9C6DB25E9DAB179CA40F7948F951803
-:1067900045775EA21468DA31F03A4BB3991EB51012
-:1067A0009715DA5B0EDC6205FCCA92DBCEF2D219D9
-:1067B0003D4CA423003DFC98CBB1BF3BB5A26C6C13
-:1067C000C7F4ED44AE6F9518837E1D115E9E89E778
-:1067D0004B4E7709F473A7D35D9AED80B817C903C0
-:1067E000BE698F0A9FE77313C7DFDF853D4662D01E
-:1067F0006FC6F164DC577567635CCB5301FDC1BEA6
-:10680000AA59023EB0F3FA6E89C52B3C37C377E232
-:10681000744BD328BC4BFE4CF03CC7DE231512EC66
-:10682000FF2675574920C79238FE8CF3E8E170DBEC
-:10683000C3F325FAF31DF32B6670F8EF513DC85FE3
-:10684000AD299A13FC55C8CB03BC1AF32C7E99CD05
-:10685000F6D5B644F5E0FEA0F76E82F97743CBBCDF
-:1068600012E40F25D7B695538C93F9D9CC9F4FA836
-:10687000D19CE0870F775AF09E8AC1F25B7EBB1BEA
-:10688000E325C51A3BAFBCA9DB1B9949E735A45BDF
-:106890002BB7D0677ACE105CDF50D2BC8AF909AA38
-:1068A0002EBFA958ABC07D7231EF92F9CD6B2C2A67
-:1068B000E6C3ACC80EF16B929779C3E63B19F7B902
-:1068C000D708BEE4F908C53CFFA078DB53984F50C9
-:1068D000BCED66450A91339BB2CDB8FE3387968CEA
-:1068E00086F50F94C7DA96CDF0F0FD6C265F06CAE8
-:1068F0001F5BDF2717FAE58FADCF7684E4D7349E90
-:1069000047F9D798CDE4FCB3905743E1FAEC7C917A
-:1069100057B34582F5EEB5B44FD905F35A6EC23C74
-:10692000A6BEBCA2F92CCFADAF3DE417D1F7CF2E58
-:1069300062F945C37C1B705FE26224CBA3B8B83D0B
-:1069400082C0B9A467B76D1C02E7109FD54C6807D9
-:106950001AE70F0782785EA419F225018F20AF0491
-:10696000FEFAF28F78FE5ED7F69771DE623E9450A3
-:106970002C00F7F41C36AF253B764F01E21FBE2CEE
-:106980004182B89D98D7B5E4FE4B9C2F064B872FCC
-:10699000E430FE08A31F5FCDBE3EFDF806E089EAA5
-:1069A000C703D0EEBAF523D78B424F8AEFDD9C2E7A
-:1069B00066660FA81FBBB3C3E84715F29E31EFC848
-:1069C000E4DA1E065F3378BF37BAB54AE0E7A2348F
-:1069D000ED4FD0CFC409BE8310072DADF11E047E4C
-:1069E0002F96F879EB294C0E24F690FD10838B3FFF
-:1069F000D1E3863CE5AA6C966F71C36937EEB3C7E5
-:106A0000798804EDC53D066D09ECBCB371FC499C69
-:106A10002F4C4F06301F2EA9337C5E6A412AB3D714
-:106A2000A8BC3C0B702D194DE5694A7F791A067F89
-:106A300017A07ECE2EFF01A835363E3D1ACCAAAB5C
-:106A4000E0EFAF0C7FEE4BF014F8CABD22EBE2781A
-:106A5000025F57F8FC6FCD70FF03C639CCF97B207D
-:106A60003CC6E650FC8D07FA66781479C03B0D767B
-:106A70006A450EC3CBE41C7D5C2804DFB139E3FB1F
-:106A8000E35BC8F1BD47F6C880B792AAB635800768
-:106A90008AD7A41CDACF0D65FAFC4F235E853C34FF
-:106AA000E2D78857910748F1313A278CFE12FD183A
-:106AB000F558889CE0FBCE6A5F7E07D8CF224F5CFA
-:106AC000AC43F0CF240E8F1B35ADD2C2E8B410C654
-:106AD0009D38CB77D00C74BAC87BD0124AA78B09EB
-:106AE000DBAFE2F348EEF1E27A869DD0CAE179C3EA
-:106AF000693FDEE331B499AE8704D733B2FB38E6A1
-:106B000063C2BE2CC49BF61E3980F31ED1DDC59E28
-:106B10003C8FC8A86F83F9B7AC9F17B8FC6A3DC714
-:106B2000F2F85ACB99BEBD37C35D99837CECAE8237
-:106B3000F9AFC8705743B92095D14D6C8EFB6628CC
-:106B40008F1C40DFDF9AD3B74F3D1DEA253D40BC87
-:106B5000E21E1488C327412410B6F09BBD9285C263
-:106B600035C94DD0EF1C9DA8AD82BCB7C044E282B0
-:106B70007C80B83A7B39C02B61916B3FC0B3F51C68
-:106B8000BFCFE53E82E7BDFAF2ABB454CCA700FE1E
-:106B90000DE5977A3E8FFA1CC607D4DE9993C3E6BB
-:106BA000A5C1BC84BD23F87220FB2584AF1BA0FDCA
-:106BB00075F0F5F29CEBE3EB15398CAFEF8776D7E8
-:106BC000E2EB1FE4F4F1F543D0EE5A7CFD28E7EB4D
-:106BD00017AEC1D73B78BFFFC5EB87E1EB47C3F1E9
-:106BE000B5CAE94EF0C59E2363A3215F601BEF2F5A
-:106BF000447E6F80F6D792DFFF049F6F867EAF657D
-:106C0000A78A7E05BEAFC527B1B91E8483B0474FA2
-:106C1000A733BC0BBEA7FCF29F007FCA2F3B39BF36
-:106C2000FC92F18B8AF58CFCD5A7EFBA4DFC1E11B6
-:106C30007B7468DCFBCD9C7EFAEEE59C30FA6E241A
-:106C4000E1F0AA61726404F1CAB1D06FAD1DCBF658
-:106C5000B37674F3634F05BC00B7F77298BD513C2F
-:106C6000403CE1779C4F92BA2B50BE50781ECA0927
-:106C7000D16349C43E15FC9CCF73D8BAC64D701F72
-:106C800004B964777B309FDB91CBE022E044DBBF2B
-:106C9000134EEEEE037CE4F7F71B8C7838C8E7FB65
-:106CA00039A71F63FF42FE40FF05D8BF6A82FE4539
-:106CB000FB3F07E5D047B08ED2079A65585712714F
-:106CC0004783FC1172928CA0ED8BFBB7FF34D8FE8A
-:106CD00053584769336D9F1F6C3F92F8315F2761AE
-:106CE00011955304EC7717DAB3EB55CFB91C9C27F9
-:106CF00061F2AADC84F2202BDD8D7C174EFF43FD70
-:106D0000EBD1FFB01ED0FF83911357383D81FE8732
-:106D1000713ECEBA86FECF65EB8ECBBDBA9C88CFD6
-:106D200065FD3A7207D6FFB961E4C41ED58DFC1427
-:106D3000868F12721D10677127423BCA4749501651
-:106D40007A87B61B02EFD7AB0C8EEB6B4DD9685F21
-:106D5000932857387F262D3766B0F945697C9ED732
-:106D600095FFFADC8F7A2C006F91A722C635E6BD1D
-:106D70000A3C2EEF94C6415CAEFCE0658C93F4EEC9
-:106D8000FF1BC649948CB9E360FCAED758BC44E401
-:106D90009588F157703FB25ACE6F8738EDF91D16BE
-:106DA0008C7FCA44DD5846E7D374C44C7C2807D98D
-:106DB000F965B14F6BDED1DA0D71793309B9670727
-:106DC000F59D1A0774693EC2EEBB2149EC7B33B1D5
-:106DD000AE62F730EAF769E3DDFA7DDAC41AFD3E08
-:106DE000AD88232E256C9E0E8F7EDF76E82CFDBEAF
-:106DF000ED304DBF6F9BBC68AC611F57BF6F3BBA96
-:106E0000A5C2B08FABDFB74D5B37C3B08FABDFB779
-:106E1000FD8C343F5D46D79D2BEEFBF1BABBE15CA8
-:106E2000F47C3EDFAC4DFA7DDD2F76D6E07D21F39C
-:106E3000797C3BC7A7DFE75D2A2F433A266DEC9CA0
-:106E40007333FD07E0A690C0E164C83FF0492E3FD0
-:106E5000FDDCB0497F0E7A71C7166CB7D8A77FBF2B
-:106E60007487BEFC402EBF0786C7BDFBD3410CCB49
-:106E700063D8CCE2FDB237CB40077A7CFC6FE942A5
-:106E8000E57411E1D4D345A4AAA78B8637F796C041
-:106E9000BA8DF08DCED6D38B11BE36979E5E045C34
-:106EA000A99EE4F9386E5CEFC20E893C23F587EBAE
-:106EB000A2CE0DAD700EDD0857427CB8EF6C84AFEA
-:106EC000CF00DF73AAF63CF0DF858E07F0BE1FA26D
-:106ED00069E3A0DD55F263FE83D51F747E4C3BD47D
-:106EE0000FFAC9FAFC985EC8E31A430691C775F019
-:106EF0007F20AF2382CED00CF1C6092E6BF8BC2DBB
-:106F0000EDF55CD4336E82F19E3F10D71A5A6B8D2B
-:106F1000AD24EF1A718103B9684769789F466937D4
-:106F2000CB73234AB71DE2BFE1EE6F349C6B3A0A84
-:106F3000EDFFD9FBF184DD48EDF43FE632BDFB2ED9
-:106F40003CFBEC746EB7097B7BA07EFAF25C0678A2
-:106F50004A0764CCB30A4851AE70F70D9DCE95C276
-:106F6000EA0DAA274EE73A42E25BDFBB7018F4074E
-:106F700085F717F0DE66A3FA5B1A94FEEE05386D0E
-:106F80008C8E45BA0EBC29FBB26883F356350ECE03
-:106F90009F1BEF2711794FCD70FF08D52765E7B309
-:106FA000E3AE96675066B89FC6788F47EB589E67EA
-:106FB00092C7D6F96B7E8FA0334FD29D9711F1A85F
-:106FC000A6752CFE0AF70E7686F4E3CC6387566E20
-:106FD00056CB9D790E8877B178616B8A847642AB07
-:106FE00024A1DDB039BDC29947FB3F945B3E14EA52
-:106FF000D9F9B84E88458FC7F33E381FD5705EEC7F
-:1070000018AF7F2CB7029FCE3CE16FD97301FF13FD
-:107010005537F66B91C3EFAB8FCC63F64F35F0B4B9
-:1070200023C84FD7734F8325A9FF3D0DC6FBCFDC87
-:10703000D9F62E5007C67DCF17AF754FC3BEF0F7F8
-:107040003400DCA31382FC5092A7BFE7AC23AA074D
-:10705000F741036FCBAEADA4FFBA6FE6785CCFCF3C
-:10706000853878FEF728BE9FD2BF3E83D39601E2D3
-:10707000BD13D5F26A80F307E99E9B010FE29E9D46
-:107080000E8BB606FC8FC04B04E791ED2307A05C86
-:10709000E055318FBC35C51B8DF7011499D09F5732
-:1070A00037B51D8C4CC273B609921A942766857841
-:1070B0006D94CE16C2655D60DFF5CC3D60A3DF1D2B
-:1070C0009B6F93E0FE9636D256190B76D766123632
-:1070D0003E58CFE9696AF9018CB33B02ECBC5FFF13
-:1070E0007A26E1276AB08ED280364E4A0DCA251420
-:1070F000B9E03F75997CE1E2B559E9950BA15D8155
-:107100008F848DFF55F37B66EA54CF32ACB7CF8FB7
-:107110007E518390EFF34D04EE37BC9DCBF3DB370C
-:10712000B3BC5C72F9CA15B924787E8AF64F403E2A
-:1071300035CCB4E1BDB10D9D2978FF16F14878CF6B
-:107140004B53E7310F941B8A8BED106F76BF4F24A2
-:10715000B8970DCFECA11C54C8A742DFA2FD9084C4
-:10716000FBFD33385D8BFB94A81E591F4DE1DEB04B
-:1071700079D501C8EB7EF779DA07FD7442D64EFC6B
-:1071800090F6FB5DAAC45AC6C2532175188F766269
-:107190003F33793FDEBFD171ADC171BFDBF926AEA0
-:1071A000E7849978AD947ECD156C68F30FE230DFFB
-:1071B00058E4AFDC616DAB063DDB6B0914C2F9A985
-:1071C000DED7DE1B09FBD41FFE9F0B36B08FFFAC52
-:1071D000046CF0FEF4C37FB4C1FDC81F3E2CE3BEB7
-:1071E000DE1CAE7704BC9FE7747E31CFF30CD0E792
-:1071F000BD2BBF2D09CDA3272D0EE49FC53E1953EE
-:107200001E04DF2DDD110D16515FB9B13D5157162A
-:107210007AA411EE6B0D43472738BF2CDEB5C502AB
-:10722000F70B5CCCD376C1F8A715463FA7F7D97CFE
-:10723000707FA298CFDC5D4516B04FFEDC1941FC93
-:10724000A00F956E333B4FE6AE95283D681CEFC608
-:10725000791E7E3D1AFB5BF014934FF574AC160A51
-:1072600057AD7331CA21E33A167CA84E86731C0BC6
-:107270001E9508ECAF40FD8729DEB4961F639EA8DB
-:10728000719DF55EE37D766E948F0D1CBFF3D6E99C
-:10729000BF37743E8EFDCC27EA7AB0A717B419BF6A
-:1072A0004FF90CEC9F06833C7B278FDB5B25A414F6
-:1072B000EE9D39604D8BBBDABDAF6757DA91383F31
-:1072C0005F69C5E7E995049FCFE4A908F7659DC705
-:1072D0001E04FA59DEB1DB02FD1CF48D4F82E3A3DC
-:1072E000533BA72860774DE5FBACB3F9B94E74AAC0
-:1072F000D979CE1EC053558CE13C275F771DC7035B
-:10730000B126229DD5C17A0BE1BDF275E87ACE1F78
-:10731000498BC17D3AB1AE52BA2E79F0EB12EB1126
-:10732000EB13DF1B65763FB0B19DA0F36738DDCD71
-:10733000DF765BEB700A8A35AF7D36AA87F9A968DC
-:10734000DF5772BC555A1F47FBBE92E8EFA5A27FDC
-:10735000C7817F05BD35109702CC6BA42B816712C6
-:1073600063F6F2FBF9D1FEEFA3A7CE7F43B8087C0A
-:10737000537E71F2FD3427ECA751BAD2D9DB948E3B
-:1073800074E5056DFAF297E69E51C0EF0D86FBA1FC
-:10739000BE34E45F88E7A5BC540607D53D19CE0787
-:1073A0002C209E56B6EFCACE1F9D56DA0EFF10F85F
-:1073B000701BE3833F73FCB7E47B46E783FE52DC3C
-:1073C0008520EF2B560F939368BDFAF5921DF86B4D
-:1073D000DEDAA2C9C09763891BFB9B9D18DE7EABDA
-:1073E000C8677A646EB39958A8DD3F978E01726EB4
-:1073F000EE3E19F91EF2A6A60D817B26183E1A1F35
-:10740000DD6D19469F8B9A1B98FDE0637C23EEABE4
-:1074100015F427E4FF92F5FBF1DE0DEAB7E8F8ABCF
-:1074200009F2BD0B818F0DEF9B6F463C3411F6FBCB
-:1074300005027E37E573BBC1455C409FDA83362B7E
-:107440009C17B9D6BA49FFB803C625CE1FC940BBA1
-:10745000F3BCAA0E857A1A1DB31BEC48452B85F7A1
-:10746000145EA8A702ABA2F11ECF939764A2427E3E
-:107470009B5D2B053BAAE7FD9178CE5DD0AB586FA5
-:1074800093753DD26B13D1FBA3F5D4F181FDCFFAF7
-:10749000ED8998D744FB2FEC007B63BB19ED092FD6
-:1074A00059E184F3F69E47CC2827E776C4A33F3CF6
-:1074B000772DDB2798BB2B1ECF07527F14EF1116B9
-:1074C000F838B9B6D2320CF19582F7F3900E3D9DA3
-:1074D0000B3CF5F7270D785AB7FFB053EDEF5F86F9
-:1074E000E0E9D400783A158AA715F95C8E703C91D2
-:1074F00087B9FCB9EF5006DC5F75BE3912CF83182F
-:10750000E950E82932FF06CCBF1271AA9AE10C2F8C
-:107510004471619EE285F5E3116F467CD5FC631EE4
-:10752000E285BC6FC3FB8B67A7B17B5BEE9518BF91
-:10753000CC5E33A506F4F9E3F9CCAEF93D955BEEEC
-:107540002C6A8F53B9E5A672EB8F549E41F9DD95F5
-:107550004E2CBFB752C5E79F5666E3F314DF5715AD
-:107560007C4409C10276E3867C26C736E48BB8E109
-:10757000034E302D6AFEF1C7F1F03B0A0EEF943B4B
-:10758000AA471272AB5BAF0F67CDD4EBBB1EB37DC6
-:10759000B213FCDB47D93D4C733D37EAEA1345B5DE
-:1075A000C07968923D2EF81EF94DB5C07DE977D5BA
-:1075B00026EAEADFB12E5957FECF7C15D77D5B4D09
-:1075C0009AEEFDDD7579BA723DDC9B0874AE4E40D3
-:1075D000BE7980E75552079DE1859F23FCBAB974B7
-:1075E000E8F7E97CBF3E6AC6EF467C08BCCEDF24E4
-:1075F000138DF6376F13955F748AA7DA289E68BBE0
-:107600002F4ED8D00F69DD35EE9D09B47C729719E5
-:10761000E30727D726FE04ECA793BB1CB1843EB535
-:107620005699DB1976BC4F49F45BB976159E87A94C
-:10763000F745B8D09EE8F2FEBB28ABE0B7C2248184
-:107640006F8ECB3EBF84F863F1839D11680F9FA6B8
-:10765000761D5C3D7B5A226BE10907E6E3E8F76F94
-:10766000BA1D3EE0EB9A7FC86E27D0D3CE48767F16
-:107670000838C3F4FBE7C732B63E86F4A5B6FB91E3
-:107680007F23D05F98D7C3D647A4B1C980FFD3F179
-:10769000C41D4F27D1B8E2BD8F148AA7C599DD85D7
-:1076A0007EDAAE2EC5EFB893B63BBBCDCCEE97A33A
-:1076B000FDDA69B9F197115B983C710FBDAD2014EB
-:1076C0009EBE425877D670CF87F9B07FB0D057882A
-:1076D00072ED6107F29511EEA72C1AC2D70B7C2030
-:1076E00005E56490CFD87E10156EC340DECC33BB69
-:1076F0008680BE3AB5DE8C7629D527B1B7611C6687
-:107700000FD2F129459D0CEB3EB52E8580DC12E3AE
-:10771000CE5D2FF37B42285D42FD0DB2466D072200
-:10772000F496779DA491A1FDE9E6FEFB4A312FDC9A
-:1077300068FF8AE7979457B5103B62C96BEC7E7E71
-:1077400052DCA3CC2C085D07FB7D05A24DD0E56B78
-:107750002E4BFDED473126B46BE2209E7EE6B88CC1
-:10776000747626B5ADC44949FFACE940C9F769F95B
-:107770008B69DE4F155ABE6FB416554097B4D4B41A
-:107780007E14F84FBD9D9FFC04EEDDFBFC45331CD1
-:1077900087274B762E1E8D711F6E7FF7975BE2FE5B
-:1077A0003FF730B83F65A9DA8E7A5C854372B87EC0
-:1077B0001FCE53E875FB9312D858E493F1B6C7C0B7
-:1077C0009F9E67389FF28999D909230A989C12FADB
-:1077D000FE1E5E9E6762744D5E97300F9CF07BE5E7
-:1077E000853E10F25AC8FDFC02665F08790D997655
-:1077F00020B716C2ED2D749DCB7644F87C29D8D6DF
-:107800000E705CCCD0441617A8D86E89E5C5A78148
-:10781000971A4837CEFF73B36F61770AB4DFB23679
-:1078200001DB9B5D18A7E5FA05AEB506B9D4C0F932
-:10783000AFB14DF2F9917F989E5CC0FB27A06742E3
-:10784000E4583FFD62D02B0BB85E5D400C71DE3614
-:10785000BDBEF344DB705D4BE8B8A03F83F3A2F6F6
-:107860003385DD42CD77783ACE5B72F9C2CCA38105
-:1078700004FC907FD7B88BC5BD8DF332AE63B0F3F7
-:107880005CE8BAAD2ABE38645CC3BC05BC31501C90
-:10789000820701F7855E06CF859D12E2EB2FDC5E45
-:1078A000A37F189F36E2BF8178A6439E42C39354BC
-:1078B0007EA604E941D0C1E2DD3E0BD8CB5F90B695
-:1078C000D818CA07CB36EDBE63A20AFEF331F443E3
-:1078D000EA12FC19A6784212BD2F3D5D73D3B5E3C1
-:1078E000FCFF2A38C12AE07E5A6C47E1B2609BEC6B
-:1078F0008E2CD4D5E379DA5E84D722AFD70271D04B
-:10790000453CAE78AD793629EC3CEFB5E7CBE0F8F5
-:10791000AF9EF7D3057A3B36681F6584F5B7FAEC5E
-:10792000A26BE8E30FCCFE91A08F032315D4475F31
-:107930002BAEF7CA93403F67A0DF3090BC5DC8F51F
-:10794000F202D0D3F4F9E9A6BD786EEC2F4FEEC564
-:107950007D43CB8B0B62C15EFE74D3BC9F40DEFCCB
-:10796000A7BBE6A15E6E7846E865CD12AAEF2B377D
-:10797000D53FF77F804E7744E20985855D1AB7C70A
-:10798000A9FC03B9B889C93FF224938F0DB1ECDE8D
-:107990006FAABFB2A0DE830BB52CA0F790F7A8D7D3
-:1079A0001E9CA795627B62F7B37B21ED7ED05F4280
-:1079B000BF0ABD7B7498D655007A413EFAEE4374F7
-:1079C000FDE7F6C818D36994B78C82DF4318488E58
-:1079D000FFF3F036F5C13B6510F09E0BF0467B8857
-:1079E000C1FBE3750CCE9FAC67706FDD95160B7E07
-:1079F000F0C7EBD2D00EFA785706C27BFE6314DED6
-:107A00006807AB7A3B681D8537D8FF006F3AEEDC1C
-:107A10002E95C3DBC5E0BD8EEBA1F5EC39BF1F5C35
-:107A2000BD986FFAE0F3112ED0EFA723FD0EF053AF
-:107A30004EEF9609ECE7F7D949DC9E1170FE86B44B
-:107A4000FD3BD855FDEC9B0D11C44EFB5BFC920D2C
-:107A5000CFD57C2E950F05049C6DFB6D2C8C171CCF
-:107A6000BFCFAEB954106AD70C123FCB8907F3DEF3
-:107A70009777FEF604D8F570BD0AF8FDCBC539F846
-:107A80000EFD397849059906210A97D50A7430C246
-:107A9000784F8086BF0F7131E3AB392B909F0399EC
-:107AA000A1FB414D517E33C4A302BB25C477E30340
-:107AB000E5B1E504F6B39A711E8E42A69F25B71B69
-:107AC000E38C11946EA2E878CE4215E72BA97616C6
-:107AD00077DC4CC7B505E76B7C3F1D0411E8F71850
-:107AE00013EA77E3FA27F3711A6513FA21CB2CCC4A
-:107AF0001F11791319FC7B4621F3EBF30AD93E439E
-:107B00006F2441FDD1BB21DAB70AD75785F14F85E4
-:107B100030FA5604DCECCA97BA7BCA797C017EBF86
-:107B2000008CEAF9113CFE4B552DB4BF87B7BFA7B7
-:107B3000ED6DDCCFA39ECC2F40FFCE6E8970813DD2
-:107B4000EB85FBAD28DDFD388AEDBF90A43805F844
-:107B5000EA6E2E67EF697BDC03FA68765BB41B9EE6
-:107B6000741C2FE1F1D662D8BF1D6EC1786B9DB534
-:107B7000E74530AFEF757EF23D2B5DDA2A13B35F38
-:107B8000562510CC3B1943CD7888DFD24FFBAE246D
-:107B90005E8D7EF4F1E46510D765F7B579519EC826
-:107BA000265D7919FF5D81BAC2CC3B9F1C41C81F7D
-:107BB000885A00F85E06B0017AA88FC3F8C0AD10ED
-:107BC0005F4E80A782743643215E137BAE8BC173F8
-:107BD000FE2CDE3C9DAFFBBB13883F8EAED7FFA6CD
-:107BE0003EDE7DA7DFE4CFA278B855F1EF07BA36C5
-:107BF000595533F8079E1A692CF8CDCB560F6EBE37
-:107C00004D854538DF6526139BE74312DECB700FA9
-:107C10006572A0CF390AE992C732FC01FD3525B063
-:107C20007B8003F731FA16717681A722DA7D287CF2
-:107C3000EFE1F3A3FDAC8B85F696F0F1A51F160AD4
-:107C4000BF98D99D4B39BF2E15F4B64BCFA7CF02A5
-:107C5000BF001F819D4BE1760F7F0E44EF9B38BD27
-:107C60006FE2F4DECACB831DAF3182F8437FAF45AC
-:107C70008C7B2B7F3E5D988AFD8979087A263C3E75
-:107C800065A29203E8E854DB1AB49B1619E2C524F6
-:107C9000348E25872BF7C91FD315785A02F3613E1E
-:107CA000D277225D40D7F758DA33D8BD12FA7A621C
-:107CB000FFB70E6EEEC2F33A44F77B0AD5720CE6BC
-:107CC00013D549EC5E99DE729BD744EDC50FF8BD24
-:107CD0000EE79BD9F9D0BA87F8EFA0C43D381DEC68
-:107CE000C3BA588B02CF0FF8FD72F7926E5B4A4A07
-:107CF000D03E692D97F9EF6ECCBDD39D0FF74410A0
-:107D000051DEE81E8151255E6E780FF63B665EA659
-:107D10007480E54577BAA9DCE83DC4BF7B6919F0FA
-:107D2000F888A0E746ECAFF729F1FD3E567E547C7B
-:107D30007F9095FF4DF4CFCB1B0CDF5719BEFF9CF6
-:107D400095DF2C7CF04E2FD8B57C1FA7EE0609E5F9
-:107D50008A95D35BDD6A3FC2B9CE74803D2B881F04
-:107D6000CED75EABDE37851E6BA103EE37386503D9
-:107D7000FDFDADCB8DE5F3F9DAF1425A7FC96D9285
-:107D8000D702F2F2B82F93CBF7B079B9564EBF179E
-:107D9000C6D0FEC607E14DFBF9F09FE96775FF7E8F
-:107DA0003E85795D6F3FD35D6C7D21FDF4FE33FD33
-:107DB000EC75E9E723ECA3A963DD5163403E54DD94
-:107DC000A88BFB2DFD912B0EEC2BF20EFB1D93A52A
-:107DD000ABDB478DA3FD2FFDAF57462D0CF1C797A9
-:107DE0005F92891BEE47B824E1F38BFD7FB2C0F9A7
-:107DF000FCE5FBF65B26E7C3EF2FECB75486CC6BB4
-:107E000099C8B3243DCA8C10FD1E37C6C4E506FBD5
-:107E10001D87A5FF7546017C2E35B57FFA0CC48100
-:107E20006E90C2EED7FE95AFEFA301CE8339C63078
-:107E3000F95756EC4E82755E041944EB57AE09BFF4
-:107E4000CF3F670C8B27D6F17B95E795D8AC2A8579
-:107E5000F3F8E36C7F7AE1E694B110E77514548C83
-:107E60001A03F31D305E1A60F1D24E162FAD4BE8A7
-:107E70007E00EE31BDEB574F6D847B4DA76E147CB9
-:107E800042F0F7726A2204DFEDBAB3AA0CE35F583E
-:107E90002E1BF3C246E09B23FC5EF1D9A5055120C1
-:107EA0001F7A52A24D762A4746E4D7DF05F3985D44
-:107EB0007AD364785F1E61CBAC677177A48B11F9BC
-:107EC0009E62F80EF521DEA15958FC4B7B4BC6F89B
-:107ED000975618AD85DB7F1ECBE170D718764FF132
-:107EE00011139DE7D8E03CC4F8D46079A09BF677E5
-:107EF0006AF5B022B897BF25BF7C16D2131FBF25E5
-:107F00005FAB86B2189F2EB710DE0F761E159C2E23
-:107F1000668D6178F394517A0BF11B675445EBCA77
-:107F2000336B13893B340E3B3359579E5597A6ABA1
-:107F30007FF7FC3CDDF76911DDC5CDD7610737D987
-:107F40006C51608F7DD8F9CD7FDF03F6DD36D92502
-:107F5000D1F52C7E6DFB7FC3EFA39C871F5C60E790
-:107F6000AF301EF6F911F67B7FD4AE5342F775CED3
-:107F7000916ECC2B0CD92F08BB9F2AF60B96DABB3F
-:107F800030FFEF7FBBAFD33286EF178C2563411FE5
-:107F90009E6F7E17E370CB63D8BACEBDC2EF2107C8
-:107FA0003D42E9FC666808F7855D5A85BFEF53C915
-:107FB0007FBF75D81895F90523EE53E0DC77137D64
-:107FC00082FC9F4CE5541CA593EEFDA4601FE45D6C
-:107FD000A4D8309FBCF1D2ED18E73E12E5CDBF8F9B
-:107FE000D65BBA6E0A96975F8AC67E7F2F774FC69A
-:107FF000BCE697D9EF214E4B9EBD1AE60FF5EFA7D1
-:10800000E34DFBD5CD3500A7E5FBD8F9A969F21FF3
-:108010008AA19F656D53B0FD34991C91A8BD10775E
-:10802000E91EEC771AE87A5A964B6C8F81FE952DF3
-:10803000FECC6741AE586C28579A2E4562BBA99575
-:108040004C4FFBC6303BC6DCC3E6557DE936FC2E03
-:10805000F0FFC29854DD3D3266C73605CE27987BC7
-:1080600024AC7FCBA53C7C8A75BE95FD3CDE576277
-:10807000767C3D19F23ADF4A92EC687E18E4EE8590
-:10808000E6D23812462EF58D7389E501475C627998
-:10809000C12F14B93B81BFA73FDCA3C0FE0E89B13D
-:1080A000DA015ED32714A90B43F8493E709705F017
-:1080B000627EF29805F47E047D56867C6F14F9EB9F
-:1080C00006B97C80CB01717E41E819A276E87E5F1B
-:1080D0004DF0CBAF38BF8AF6DD40EB80C79722D09A
-:1080E0009F7AA3487B17E6DB5DCE7E278328DDA33E
-:1080F000605FE55F357F8A67AB84F67E0FE6C54F2C
-:108100009FA09A60BFE0FDBE7530BEBDD63A7ECB63
-:10811000EBFF5E262DD0EFEF274DEA76D3FEF6FF7C
-:1081200070DC3890FF62DC2FC6B073C3C41EB80C7D
-:10813000FE5DD3EBD12AF0F73470968A83762D7DDD
-:108140008FF7E535BD1EB155A2DF9B62A97F4BC7F6
-:10815000AF7C23D20F74BCFF8D48057FA7A858FBC6
-:1081600002E465E51B5955E0CFB93B231482768EB6
-:10817000FB2CCAD501E67B2D3965A433C197DA3AC9
-:10818000C62FF59C4EE772FED3381F5D681E8A7CB1
-:1081900078E1613A69D80F7D582AD80776816AC399
-:1081A000FB89055F4E033F88BEFF7F46E48E2C00AF
-:1081B000800000001F8B080000000000000BC57D40
-:1081C0000B7854D5B5F03E73CEBC9299C9E44942C0
-:1081D0001E9C400841024C26218410601202A2021B
-:1081E0000E501530C88008110909515BACF6CF84D8
-:1081F0002410452D56DB068B74C04751696F406CC7
-:10820000D31661786863F5D368EF6DF1D6DAF8B804
-:10821000888A3582F5A3B728FF5A6BEF9D993349B9
-:1082200010EDBDFF1FE53B5967EFB31F6BADBD5EA2
-:108230007BED9D79E312432D0A63EBCE253296CC7C
-:10824000D83C95752B498CD59DCB65AC98B1F5E79D
-:1082500092E97DFD393B3D579E1B47EFADE754E664
-:108260000378D53985F900BE6AA633684A60EC42C6
-:108270005120D3930AEDB45C3E87B9180B6CCA2821
-:108280000938189B7F57AF664B618C392CEEC7A11C
-:10829000BFF96545E9ABE1FD05FC99C158CB9125D6
-:1082A0004C7742BB297E8B0FDEAF82E7CCA8F29BD6
-:1082B00018F37502CC987B765A097CDF9A6BBA87E3
-:1082C00045CA758F89B14958DE4CCFF9B2BEDEC5BB
-:1082D000581A6337B819FFD90883CB60CC29EAAFA5
-:1082E0007484479BA03D7383DDB309C67526459F03
-:1082F000CD006EBC1B004041A3D93FD309E36EDC27
-:10830000AE7882F0F98DA54E1B8379969E68B004F5
-:108310000A23FD2F393781E9808745E7F2E8993A4A
-:108320003E3001F1B0E2DCB584AF95508E4FA69798
-:1083300099703CB7D9F0771C10C0A58CDD2AC6F720
-:1083400059C3E461DF81FE3F7BD94CE5937CC11BBF
-:10835000703CE690D5B30BC673CA1E50198CE75417
-:1083600036733F08433C65664137D0EBC60E950532
-:10837000A1FD55F00CC0F35422F3257A119F30CFA4
-:1083800002DEF605F8F7776D5B0E1B05F46DFCD386
-:108390005BDA48C66ECEEF991086766B2AC3A9D7F2
-:1083A00041BBA71F337B82D0EFBA23AF979AA0FCC3
-:1083B000C35CDF30A632366678600ECE67EDC2D081
-:1083C0002FCC00DF72DF33AE297A049F9D5A78B438
-:1083D00006DF77021E8330AECE7BD53921A2178B04
-:1083E0005F301E1F803DA83A7B81124C00FCB1EA31
-:1083F000A97CDE363EB6B5E746117ECE3658C71F9D
-:108400008076CEEA4E0FBEAF3BB788DEDFD27E0568
-:108410003DCDBD5708BE8CE7FC9AB96C13F2599D4F
-:108420000695E1BB3A47422808F399F76FC07F8071
-:10843000F2F50716F82B91EF0A14CF6878ACDB76CB
-:1084400085E0F3DDF797035EE77D92E26981F7BF90
-:108450006A4A076445F87FD6B905542FE1DCF5D4A4
-:108460009FE47FABE07733F27F14DFC3778CC17773
-:1084700081A2C09D88A7AAA7FFF9CC7FC2AB2BB56C
-:1084800070FE4F52F0E924FE89AC039BFBF15C5A6D
-:1084900007FAEA283E528F2EB1E8802FF3436FD3BC
-:1084A0003AB0C2736654F97AE4EB42C44CAFB6D02A
-:1084B00019791FFC9AFCBF5ED49F6365CBFDD89EE3
-:1084C000D69313DDDEE1A2AA073D50DEE151787BB1
-:1084D000FF43E3063CD910BF307E1FD26B7E996EFE
-:1084E000BA2717FB91E3E77CF255E36F13F55F556D
-:1084F000D9466CF7D519337A7CD0DE913B8B8B55FE
-:108500003DD2EFD31E0BB5370F6887EBA8EF396B61
-:1085100068772E8A11C614A8FFC9736343F7C01485
-:10852000DF627DE7713CC183F13ACEAFFE503CD5AE
-:10853000AF8F4B0829505EEFEACBF7C378661EB6C3
-:108540008791AF8E1CB66B0CFAAD28B9F169C4D314
-:10855000CCC363AA15E043DF41ABC6A0DEDF27F83A
-:10856000F6221F0C357E39BED8A79CBFE42BB95E1E
-:10857000E4FA90EB2176FDC8F570D5564FC277909E
-:108580004E8098C771FD68C1BD388F3A3DBE08D78F
-:10859000A55C47EB0F28B4CE40E87A46EB917524F2
-:1085A000D74D649D98080FF3849E186A9DD48975F1
-:1085B00071935817723D1C533B1F2C87EF661605AD
-:1085C000FE827892EB62DDFE58BD30245F31E4AB71
-:1085D0009B521A18F2551D3CA3F9CA3AC47A78077F
-:1085E000F923F5D2D743CF25F2D3DF919F26FDAFF4
-:1085F000F2D3DF916F06E1A7CFFF157E8AE597B32F
-:108600000D7F2AD1613C674B40CEE646F8EDAA9734
-:10861000D8F803F09E8D727A907FBAE3F83CBB2DB8
-:10862000D9A116AC778135201EA5FEBF09E99E1C95
-:10863000E153AF3730BC685284FEDD71C1C20D8595
-:10864000974E676B4A8FC55788F4EE31E8FFBA2121
-:10865000E83CA2E8EBD1D929EA7F159D3D455C6E47
-:108660003037D0B184E8A7235D63E98E7445BAD76B
-:108670001FB2EEBE185DD79704A6160D2227988F5D
-:10868000DB0311BA581721DF9C0D83425386A6AB3A
-:10869000B983E35DC26D614DEADB64D4B7C02F15C9
-:1086A000D8DF37E5977933E1D7E1083EB5D89705AC
-:1086B00074FFBE80D92F16237DAE2D93E54F77F83A
-:1086C000F250EEC0EFE5D4838FD908BF1C0EEE3D0B
-:1086D000510DF5AF7AB0BF3C88E5B32A12447BCC8C
-:1086E000A7B048FDEBF73D79E25E9AC736AE0F02C0
-:1086F000BD9A7F7C145C02B0330A2E8B8177F0FA2E
-:108700002EAD97B9A99D105FAFD0BEE2E5FCE38F17
-:10871000B2478092B313D19E3CA0B8EF01FA2FADBF
-:10872000F8C482F48ACCFF00CD7FFD4145C05D27AF
-:1087300070BE4B0F70B879DFC18EA026DA033CAF54
-:10874000136836772A3E15DA5D57A68446E60EC4CE
-:1087500073739151DFE18F66FC9E5952BEDEF7B80C
-:10876000BEE9FB91F47DD8FA35FABFAE82F9428EAC
-:1087700081F51E90EBEB3CC0B27DC0E522985FA86E
-:108780007060FDEDA2DD1E9349E0EBB50EC45F8F76
-:1087900045E2B3A7C35701F4671C7E745FCFE26064
-:1087A000211FBE2F66FE171B7F5BFFBA8FCC5F3782
-:1087B0007E1FBE18FEB60EC09FE09F5A233F25685D
-:1087C000FEE367A19D8414C58D76F17ABFFD5EB48A
-:1087D000FF23FCF167E28F1E3BEBE76723FFBFB986
-:1087E00018F97F3D93F5DFEAC0F5E337F5D7E7EBFE
-:1087F00041F2177C5F00FC8426327EFFDCBEBF7432
-:10880000041D441F2A2738EF22EBA13306AE8859F6
-:108810003F82FF69FDA29C07FC8C1E44CEBC29F060
-:10882000FBB1C216A39CECA9E27662CF48FE3C5F86
-:10883000C4EDC2F7041E4F8BFA3D715178C88AD03F
-:10884000197EC2E88744CD9BF0B42445CEFBCBC54E
-:108850007361DE3D49BCFCF3A2FFEE086645E0D83B
-:10886000F6CE157D497C1369FFFC09C4EB1281B774
-:10887000F3455F9C107CA5E0BAAC230601BE38A08E
-:108880000455F413902F0699F7F1817C158CF9DECD
-:1088900067BEC8F7BF1FB82E7D31DF3373C9D7F964
-:1088A0005ED06D6E0C5DE7C4D0B53A06AE9170C86F
-:1088B00020FFA45C5CD9F5405B1ACCE3963D0AAA84
-:1088C00099287E762CC1F5798B5BF2AFF30DB4BBA2
-:1088D00022FCEC227861A7948709DB511E2E407997
-:1088E000581E8117A1BC20D8BDC437315A5F24520D
-:1088F000F975EDB27E12C14B5B657BC9DB7D5A8495
-:108900008E2C98B204FB5B5222F44530F50DACBFBF
-:10891000F620FF7EE2FEB4372EBA1EB6C5E06547EC
-:108920000C1C8CA9FFD057E897D698EFEF8A29BF87
-:108930003706EE8881DB8DDFAF58A5D03A5C01FCAD
-:108940008084F8AA7539C3DB6FA7F6EB53C541766F
-:108950009B615D5DD5C2E12BF68F5AD2EE8882BD58
-:10896000A397041D91756166FCC79AC2685D9887DC
-:10897000909793BDB1EB42CCA72056DFF2F2BFE255
-:10898000AF19680733835D704C35C2475439EEE246
-:10899000376E2BC49712F62EC1F8CA553F36CE0B50
-:1089A000FC55017B96545744D925C1894B70FDCBAA
-:1089B00079CAFAB3BFB8A0627FCBBD13973C06E576
-:1089C0003555E1D10D30CE9A24FE04BDA6A2DEAC11
-:1089D00017F198D9CFA97ED46B3571E1D18D85512E
-:1089E000F3649DF938CF2377AA449F600BD007F03A
-:1089F000B492814300AED99184848D4F40FD63775A
-:108A0000AA1B518FBEB531390DFD9B835EEE2F1C25
-:108A10004B18917613C047E2975B74A87764CB2C10
-:108A20007A1E557D9BFB60AD7D6FFFF4258EB1589E
-:108A30009E40F8B9C35BBEA419F8FA2EAF4EF80CED
-:108A400024B9D3BAD07EBEC7CC1ED769FE3B896F8E
-:108A5000EEB316A1FFBCA2795C1ADA932B7FB86043
-:108A60007606D45BD966F628548F4DC07107EE990F
-:108A700065C1F255ADE219BC9C9E87BF7CB4C505AB
-:108A8000F5FB1E513CBBA1FEB4CF3A5F9A00F09AB1
-:108A9000F6511E24CDA17326E6867EDEE918135218
-:108AA000811FDFB537BC309FD767587FCD79FD95E3
-:108AB000F925585F756F82FA27E13DDAC327EF5633
-:108AC000772B382E97334E81299DFC427F05ED5A36
-:108AD00028776F82F727DB6E4E433BEBA4A2BB14D3
-:108AE00098FFF6FD7397A403BFACE9B00A7ACECD28
-:108AF0005801F35F61EAE717D21FAB1339BCDD3BC6
-:108B000077C9E330FE93DBC7B810CF89C5BE87BDF8
-:108B100080E7B78A7D3FF1A6E238B99E3AFCA5BA54
-:108B20001CEDF1DF9E5E9986FCF4B8583F87CEAD10
-:108B30004C5B1965EFACFE5823BA1FB6E8B7E138B5
-:108B40000FC7652BE82F03DD9317C0FA5D25FC0FD7
-:108B5000E0DF8DCF0C62F704BD2AB57B646B6A85BC
-:108B60006EE0E3EBDF40BE24BF01E05FEEBF6E3B93
-:108B7000EAB5F7AC1BD9BBB8F8EE828229F03C66A7
-:108B8000A7F89579AF3D64CFC5F8A76F36CA3D9673
-:108B9000DE99BFD019B5EE44FDBF049D54FF2F50A0
-:108BA0001FFDB7BF04FFEC648E8176FC1A973388F3
-:108BB000C6C4FB4EA78674784B6B3A79077CB7FA2C
-:108BC0001133C9FDD58FA4DED587F206F805E3631E
-:108BD000B1F3528BCD34AF21D761B0D6B80E592D39
-:108BE000C9EBA1D661CFFE35175D876B849F32FB41
-:108BF00011B31FD7D19A494E8D81FEA87AE4F9C7E7
-:108C000091DFD76CB07BAD30F0358F58895EBD4EAB
-:108C100067D00DE50197534B84E75B82BEAC98AFFC
-:108C20009B992AD36C5E7AB6629CF40C8C2719E06F
-:108C30000F363EF8A3C950ED4316BA7632E0EF0C7A
-:108C4000120CF072E6804AF143A6F9B479201F6B4A
-:108C500019970B752F3E63A9C4D935AC998B7EDD6E
-:108C6000CD21F33BBDC267BB20A689F2B49EBF02F3
-:108C7000BD6A2CAF67F77EAA4E2036B6E07AACEB21
-:108C80008C296FB8FC7D8CBFD433ED9D5E19AF8508
-:108C9000717CEE75A69C8C4771C8BC802176A6C1FC
-:108CA0009CCF608A6B1CB0AE60BE33772834EE3543
-:108CB0001BD59015EACF4CE671DFF79A80FE63680A
-:108CC000DE4137C06B1EE27A660D534236F8F5F28C
-:108CD0001D1B345C0FEB857C59A1303FF2F7BB764E
-:108CE0004F0EFAEBAB1FB1137ED7ECBCF98FDBE173
-:108CF000BBDEE67929D1FEB143F005B4CF6C4991D2
-:108D000076DE6FFE5E0EF2FFCC9F829F0BF35D93CB
-:108D1000C87EB12417E99591A33B22F5D66CBA33EE
-:108D20009FD7033F19E6BDE26E95E6C19EB592DE80
-:108D300083B59E4E7259E07355EB8B164B21CAE9F1
-:108D40007B7B54A8FF0EC0AA83F0151478B420BE14
-:108D500096E3B719FC9BF4526177EB24470238BFC6
-:108D60001A93B27C21C9F53E0BAEEBF26285C63395
-:108D7000B198DBB32B723C37501CF97EAB07E5147E
-:108D8000FEA8721CE057D5997A56633C97FDD24AEB
-:108D9000F191FA56BBCFEE22BFC3B71FC7A731CDA3
-:108DA00002F858A77379512EF8B05E5F7039F20D52
-:108DB000949FD0707FC5C9E5625D22E09DEB639F03
-:108DC00009FAF9047F1BC5DBCD9810D5BF22DE431D
-:108DD0003BBA2BD26EB789B5639C05EB8F9D80782B
-:108DE0004CBE76318EEFE72AAD6798FCFD6568E7EB
-:108DF000FD5C2D46FF76C5DDC7667720BCAFC88D0C
-:108E00004DAEF8C51F486FDC22E8DF8BF63EEA1155
-:108E100080F7C1735131D7FB0195C77D16097C4995
-:108E20003E90E575779B79FCBDCD4A764C5DF39F0E
-:108E3000A8DD3A674F1ACADFBA67CDA528A7AF15D4
-:108E4000E35ED99C5D7102F86AA539C1ADC0AB750E
-:108E5000C1791684D76D53088E7C979A837CFA511A
-:108E6000EBAF5CC83FEFDAC3A3511FF56DB07B7663
-:108E7000E30444DCEDA3D6D1BB313EB3CADDE354F9
-:108E8000A07CD56DA392507EBFE50E5BB0FCADCE4D
-:108E90005C13C23EB7BB02619F3691E08F40947570
-:108EA0000AFF13F96DBDC2E9BC6EEF31CB48E8EFA4
-:108EB0004E31DF8F7FFE877CD45775393DF9A85737
-:108EC000800FF23311CF4F29A48FD7EF557DF609CC
-:108ED000113E588F7C00EB6EADE083F5077EF51DEB
-:108EE0005C0FEB91FEDE817C047C7A9CDEEFDF354B
-:108EF0009BF1EF8F239F483D0670AB19E369160184
-:108F0000433F08DF85F89C44E5D5BC3C5848F294C3
-:108F1000F55AD0EEACEF32077BA3F67F86A2F3764C
-:108F200041C795CD5692BBDBC5BC7BEF7ED6857421
-:108F3000FCF8E7C75EC0FD92BAFDA0ADF541D6854D
-:108F4000C04B3DE2C145F320FBA21EE7ED8AE0A144
-:108F50009FFFC57AAC677C9E72DEF59AC0832C17A2
-:108F6000DF3F2CF8661D13783B3086AF3FB1DE70D3
-:108F70003DA35C95F30B24F1EF259F1E2EE67A614D
-:108F80008F78AE03BEF01412FFF82C524E40D1C7BA
-:108F9000FB7651FC47D24B8EFBB5883EF12526452A
-:108FA000E8D86B62B59D83C44DBA04FEDE6E1B9695
-:108FB000D30578FB08FC2CB4A7905FB5A8FE24DF8E
-:108FC000C8FE663EBDE04A9C2FB41FC6F665BF6F63
-:108FD00005E3356CE72DC6D707F227CA4FB92E67D0
-:108FE000B62CBBB2C885F53E768E423B46C8B3D799
-:108FF0008ADDF4BD0FED05F8DED7A550FCF96DE173
-:10900000D7BFDDF62BD7CA283CBD2AC62DF90C7F69
-:10901000302E25C7DB9DC4E3B9B1E39672488E7B41
-:10902000E696EBAEC4F772FC925F257F4A3C4A3E5F
-:109030006577A5925D13CBAFC46B52AFAA06794F8B
-:10904000FAF1F2AC4F2D01C7C0F7B1B0B487DEC55D
-:10905000380DCA8F27D510C98FD6F4E379517A1EFF
-:109060007E1CD17AA779C3E5EE4ADC7FDDAB78D0F0
-:10907000E489D22FF76A51FA45DA0525252309EF4D
-:10908000F529BE0F908EEB4EF5CC76E9113B74DAE4
-:1090900067613501E3520772BDD1FA74DDE9E3C4BB
-:1090A000FF75AC6733FA512BEEFEC3BCC9C8E74F5E
-:1090B0009A697F6645DB2C0BDAF5373F7E6329F230
-:1090C000D13BEDA348AE7FF0D8A462E22BE64EBBC5
-:1090D00016F87FD5630F5EBB14DEAFEA523D24DF86
-:1090E000A11D5CB72B6E2F66C837EFDA7BE795A31F
-:1090F000FD7E87EA46FB7DEAE393EEC2FA539D23A9
-:1091000012711EBEC79209F66909A41FA4DDFB9661
-:1091100090932D66CE1739257C1DA59670B9915A6E
-:10912000C2F966664B4B3EEEA7F7ED02F98CFBCA1F
-:1091300016BD338CFD3D378CFC8B7A7087D281EE67
-:10914000A7146E97D55A982DC34BEF6D19F0FE45B5
-:1091500073CFEDA8475EBCDD59D48C0350CF97AEDA
-:10916000E4F634DF3F4CE6FD4BBCC9716497707E7A
-:109170008F6D4F7EDF8D7E04CA5331FE0F5A9FBC28
-:1091800016F5E0077B4627E1BCDF7FCEDE8EF6D406
-:10919000FB662E1765FB60E7BD176DA7815D6780D5
-:1091A000C18E33C0C0BFEF19EDC24D34AE8925600A
-:1091B000C78D63FD769CE4F79A0DA313A2F30862B2
-:1091C000ED779617BB6F3339810D226FE4F374137B
-:1091D000200A18F52CEE1142BFD5F15F3CD383F67F
-:1091E000FE36ABDB0AF37C0FF91FF7A59E5543B89B
-:1091F0000F83B639AE87F7F61585D08F5CFD6660B4
-:1092000036B67FFC812D94677013D897C39428BB22
-:10921000F9A107AE45F63FE3096CCE80EFCEECE155
-:10922000791150EC88B1975FC8D0FF757BF952ED8A
-:1092300064196FA82911F6B2877910CF12BFD26FC7
-:109240003A0C7C50E68DE0EB6F4DB564279F6E0ABB
-:10925000D0F313E5EDFBA722FF3A133CBBE1B3DFEC
-:10926000763DA866229D0F149D47BFB7DC91E0C6EE
-:1092700075FBB7A68DB4F978BAA9819E92CE32DE7D
-:1092800036EDC011FAEE6F5DC507A7C277871C09DE
-:109290005CFE0FD8EFE1F48CCD03B975C3E461F83F
-:1092A0005ECEEBC33B385DE5B83FDC73A30BE775DF
-:1092B000E427C907A7203DE313DC68EFAD11F91FD0
-:1092C000273BB83D7DCA96F0C45CCC1BD9B1288D34
-:1092D000819CBDE9C8B7AEC5F7AB9F53DCE8077802
-:1092E0009E5BE042FFF4BFB45E971B9FF05D18C722
-:1092F000A385549447E57318ED47958735A6E7D2C3
-:10930000562FF1CB94D35A08F3463EC27D2A8C8760
-:109310009C8FA3780813FB4F37FD9AC751FAFD5B6A
-:10932000E1DF4D15F3EE2A4992FB0AF47E66197FC0
-:10933000FFFE8E67E6637B1F3C6676E3B8FFF69818
-:1093400099DA5F0B7E9909C67B6A0FF777D6762A82
-:10935000E4277FB007F435CCAB6E83D9674918C8D2
-:109360008733A1BCD711E1C3B5BE10F13713FC6838
-:1093700083FF2E8C1CC88F89AC7333E2E35FE5CB8F
-:109380005FC4ACFB7E7E1C8A0F04BE701D233F4A67
-:109390007AAFEDE0FBEA499D4595C85792FE524EE3
-:1093A00004AB5801EAD5160B2BC03C9CA029CE83F8
-:1093B000EB7B8143372B80874529BDD5284E33274A
-:1093C0007139ADCE34F94CA85F5AAC240762E5C8B8
-:1093D000EF845C9F8F3C0DFFDE2DE1768499359004
-:1093E0001F229FA077B2517F2F884FFABB0E55FEE8
-:1093F000FD40ED520DC6BF606AD2EDA33C8CBD7935
-:1094000060FD520DF8774171D2B323017EABA48E7B
-:10941000C313932699016E6EAE5F5A0DF5FF59E2A4
-:109420007BBD24AA1FD92EBCFF8F1280378D0B9CC9
-:10943000C067BDC54172FA13A56FC2C6DC48FDD72F
-:1094400014F6D66F9508DC6B663968DFBD5B22C702
-:109450003FF8336F92EFED9241DEAF64AC0DE32A3B
-:109460002B83BF3BA1703FCC6F037A5D2DF86AA5BB
-:10947000CD11267FBEDD7CBA9FDEC8479E040DE974
-:109480003A5FF0D1D55AF8087E3F96B5BA4FDAC8A0
-:1094900084DA71217968F90D0B8F9D94ED01BF7C01
-:1094A0006286F9025F2BC09E1B61C92880E41A9076
-:1094B0005FCAC1DFFD03DB6D09B25E3BD1A1C68D82
-:1094C0007CA6B080E9023CEBE25D13306E52179F40
-:1094D0001342BE6F7CF6E3E3C85E374BFB25504674
-:1094E000FC7E9B9BCF8705CA891F6F17FCF87E13F4
-:1094F0006BC883A577754F8F4B87419F9E1FCEC743
-:10950000F5FE694E206E12FAF93B5AB21A817F3E7F
-:10951000DE6FF5CC85FAA742CF501C6E9DB047D9BF
-:1095200063A962DDABE11950AF3B77EC6ED42F2914
-:1095300093385F9DCE0DE7DC89722397FB3F508FF8
-:10954000F2DCE66CBA3C15EB9DDEB725EF26A09F5A
-:1095500055634167123D990BE67D05B45D06B01970
-:109560006095F67343442FACE7427DAFDF98CEE3BE
-:10957000EDCC8F7245D24BD261007D600868AF9A06
-:109580006CCC8CE31FCB76B8517F483ABD6F033C5F
-:1095900062FCCC067884F53D0B830E25884F1E6F48
-:1095A00069547A5B9311FEB942797303F5E0E316CF
-:1095B0004479ED8E1B49FE48B9A3C37F83C99DAF93
-:1095C0001D37DA317350B9336D92D08345ACE80260
-:1095D000371089BE6BC4B7B3D41A5DC371A7DA3C28
-:1095E000184F6B7C6414E91BD6FA07165D8FED48A3
-:1095F000267ED99CAB12DE6FEE5228BF715E5726D5
-:10960000D3A1686E57323D5DE732E8FD074FBC5489
-:10961000C2E512A7CBBC9F0DABA2BCA29F8DA1A798
-:109620001C47A3E0BB596A616718ED08078C03E08B
-:10963000C617B9DE6ABC46A5B82643119D86C4E4A8
-:109640003F7E473BC57FFCACDFBE572E509C564F3C
-:1096500040BAF8BB5586FC03DE4690E3D9D68C7839
-:10966000B6A69B983E88FD611574B2EB714C8FF2E3
-:109670003BB4E0D8EF57603CF65B664F08CA5BEC42
-:10968000AEDDB89E58D0D783FEC262F15D8F9DF3E8
-:10969000477C4192E1FB2DAED9DDC86F8B7D5CEF3D
-:1096A000383DC30DFD5BD57566643216E0F6A2E465
-:1096B00007E24BE8F76ABF42FAF59AC5501ED5AEED
-:1096C000B9E25392E3E60AA39D69F51BEB7D6F9225
-:1096D000D03B63D9D868FA47F0EEF0A19D7EC6E78B
-:1096E000243E06EDFEE30A80AFED36339CAF358EA7
-:1096F000CFEB0C620AE3A23E3584F1922D88077805
-:109700009F5066C467A2CF88BFE439467CA4FA8D17
-:10971000F31FB678A4A13C237099A13CB3D66B800B
-:10972000B31BCA0DF5476CAC32C0B9C12B0DF54760
-:10973000B52F34C0A3B72D35D41FD3B1D2503E3688
-:10974000B4D6503E6E4FA3011EDFF95D43FD895D27
-:109750009B0CE545E17B0CE5C5DD3F30C0937A1EEF
-:1097600036D49F7C62B7A17C4AEF5386F2A9A7F654
-:109770001BE0697DBF31D49F71EEA801AE642F1943
-:10978000EACFB4FDC100CF72FFD950FFF2F4770DDC
-:10979000E557E81F19CAAF2A386BE4D7382EFFE621
-:1097A00079FE69F84EC90ABC3C096D04F5B4867CA3
-:1097B000DBB24C61C9184FEF5E644339F08A9443C1
-:1097C000820F9F47FD8CF5F3580ECAB3596A4518AE
-:1097D000D7ED992E85D67FACBED33EF2FB309EC727
-:1097E0007EA57830CE96006A4B8BEA3FD16703475F
-:1097F000320227CF711BE0547FBAA1FEB0C5BAA1D7
-:109800003C23506028CFACF518E0EC863243FD11C4
-:109810001B7D06383738C7507F54BBDF008FDEB65C
-:10982000D8507F4C47C0503E36546B281FB7A7C155
-:10983000008FEFDC68A83FB12B68282F0AB71BCA3E
-:109840008BBBB719E0493D1D86FA934F840CE55355
-:109850007AF718CAA79EEA34C0D3FABA0CF5679C07
-:109860000B1BE04AF6A2A1FE4CDB6B067896FB0DC3
-:1098700043FDCBD3DF36945FA17F602897F6CD55AB
-:10988000059F1ADF0B7B679EE71F86EF83553E8699
-:10989000FC11DCAF785A74C60A4B47927D0172BD49
-:1098A000D7AEA27DE4A7B851122608025F26801029
-:1098B00043BE4257A186E24F2914F725D5A463BEC3
-:1098C0000FD8090024997273D19E8E8FD86D5917C5
-:1098D0008A2FDD6E2B2F65C4E73797062696A6A242
-:1098E000BFB26F36DAED37B3E0661C07E8BD845EC1
-:1098F0005C1F76633C433EAFB0015EA2FA7BD1BEF3
-:109900002DCB7B11BFFF0ADB69AADFDFAE8873288E
-:1099100030BFC6A8F6EF07BF4203BB6E5B13AC1B9C
-:1099200070187FD0E426F8A1A674827FD4A4D3B3A4
-:10993000A3A9809E0F3779A87C475319C13B9B7C14
-:1099400004879AE6D07377939FDE3FD6B498E027DA
-:10995000C08FC6E71EF0ABF1F914F8C758BE17FC6C
-:1099600065847FD114A46767533BBDDFDFB48DE00E
-:10997000034D1D04FFB22944CFAEA63DF4FC4D5368
-:1099800027951F6CEA22F8505398E0705337C1476F
-:109990009B7A083EDE7482E0179A7AE9D9DD748AF0
-:1099A0009EBF6FEAA3F2979BCE11FCA188D7AE2988
-:1099B000E5F12289170933564DFC20EDC3F968E71C
-:1099C00023739499FF66B0F363ECED587AC87ECCAC
-:1099D00055181384E7F0FCDD2D517ED6ADA2BF2DC6
-:1099E000712C68077E6F3671BFB63989519E351369
-:1099F000F6EB1AC1972C85DBADABC5B8D688F53030
-:109A000009F9B380F8F3E5AFE35748BFF14C61A023
-:109A100085F833DB1424FFD911CA47FB39757C6004
-:109A200073E924DC6FBCE905EACFEDA17DC779D6E7
-:109A300070EA75181F7951A578DE50FDD58BFCF1C1
-:109A400021CB0F7D9085F6F69C2FD500E2E915B36A
-:109A50007331C60BB69772FF747BA9C9F0FCC9F8C5
-:109A600040078EE77367C30D2618FFE7D3373C71B5
-:109A70006B6EC49FBE1A5D52F0831630DD4CF989BF
-:109A8000CCF77C2E34750D1858085FC782F4CC2AA9
-:109A90000CECC2F92E01431CE140B93567B079C521
-:109AA0008E6BAF18D75E311EF97C717CE0696CEF6C
-:109AB00073A78FC6F5CA94CBF3715E725C71137491
-:109AC000719EA16F278EEFF3E73E3DA98C8AE05F80
-:109AD000FAED9B2B455EC90685C7E5A4BD26F2526B
-:109AE000A4DF5173BB12427B7D19F83BB8BFF4A6CB
-:109AF000B03FDFB473FD7CA6C15C80767D8D12E73C
-:109B0000C17DB8330DFFE540771AEA33DC2769C120
-:109B10009C03286FB943A17CEE1A68C704EDD4609A
-:109B20002010BFBB4B21FEFB627C2E8DAF06CC3FCD
-:109B3000F2B352FA7270BF14F8E545A4C3DA296A89
-:109B4000D002F6F02BA650BE42FBD237591418E7CC
-:109B50009A14E0939143F3C37A71FE40BE073EFB33
-:109B600003B6F7B75F4F2EA038FEA1293AE2ADC584
-:109B7000C4CF23057FAF7A78BE0B17D5EAD4F11492
-:109B8000A7649AC78371A679E2FCCA11956DDC3788
-:109B9000881CFDBBA0DB2BE9E639216AD7B85FF34F
-:109BA000B1A0E3C7A2DEBCA32F66E3F9ABF5DD6687
-:109BB000B24758496FA1DF39C87C366EFD765E1416
-:109BC0007FD777BDCDF335586F61747EBA6B326F36
-:109BD00057F2936A71067639A2C7D7CFDF9F117FFC
-:109BE00027027F8F22FE3E89F6F67CAB9E701D3CDD
-:109BF0007B01456178067EEAA67C239977B48AF9D1
-:109C0000E9B906D801F9D91F7CC082F85FCB3AE9DF
-:109C1000FDFAB21B7310AE677DD5E9E84FB4373F4C
-:109C20009F0EA35CB4ED8159189F5D185AF13C3E1C
-:109C3000173CA69C44FF15D6877932C64F9486B64A
-:109C4000E1D0DFD2BD956D99F07EBECAE9C15EE27A
-:109C5000F400BEF1A94903E709EBC13999E6E1A394
-:109C600079A8AE3986F550B389F9949448FE7CFF03
-:109C7000FA28BBE5AF99E80F697DB4FF5E7FC89A0B
-:109C800084745ECBB8FE8EC43FA4DE66C4E7B7B072
-:109C9000380FD6FB50F0F587D98CF8FA43051C3CF9
-:109CA0006FC49E64398174EFA888FEFDD0142A75B4
-:109CB0008D22FD9C87F37D217D918E71B35B526C6B
-:109CC0001E15CB1343397C1FB55FCEB30BF191B892
-:109CD000D7FD661E878A1D9752F6C23FD07EB05AC6
-:109CE0005810F737607DB3525CD7C32DB4AE5A100D
-:109CF000B5183FABF2EB83B5DF2ADAEDFE82FBC18C
-:109D000041980F9E971CD08F5BF413C7FB917A0488
-:109D1000FB233992C60CFDCDC22417A0CB2B4E1FBE
-:109D20008DBFD9944872E7E311816AA4978CFF48EC
-:109D3000FFB03BF7FD3CF2E3CFB764A19D0EFCCB37
-:109D4000F312A773F9F48A590F22FC4A652EC5FF56
-:109D5000A5DCBDBA8CC7CBAE96F1B18A98F8584C49
-:109D60005C86550C1E2F63CC63C67EC7B237257E3A
-:109D7000281E73B44223BA0781EE186F3E2AFCD422
-:109D8000CA78EE9F774E4E267E4ABA226FD07D1556
-:109D9000F9BC47C457EF053B8845C5D5EF2969B4E1
-:109DA000619EC1964285F6BBEEAB8AAB8DCE73DF6A
-:109DB0003BCDCCF753A757EE44BC153A4255A4AE61
-:109DC0007D9A8EF350C4BCC6B901EF266CDA2FE23F
-:109DD000A41E1B8F4B5593BE96F4BE547DFD941666
-:109DE000DA1487F34E61B4FE9C1D7692A36AA72F06
-:109DF0008C29D75F4E5B7827D151F317603F474AD4
-:109E0000E39803EA7F7EC442FEFD21D3CA9F623EEF
-:109E10007CDF1B5686FB9E9DCE4C0DF545E71797C4
-:109E200055D3D3397536E371CE7813088822377B42
-:109E3000F4DF9058E2DC59A7C2BA19C5DB7CF126E1
-:109E4000F0C13A4DECEC0C18D77E87F7C189C4728B
-:109E50007E15E7D95511B81FD753296B20F83E8BD3
-:109E6000BF7617F47B5F928DF8C45FE17F808F939C
-:109E7000B5CD85F14D9FA9303CC7DB6601B95C8843
-:109E8000719238BE27C5B87DEF3F974FFDEF98CC54
-:109E9000F7F95AD37D3D78606448BCB9B5BEFEB8C9
-:109EA00008F15B16C5F3241EA3E9E52E35D02B601F
-:109EB0008EA65719D06B7C34BD7CCAD7A1D7ED983C
-:109EC0005C3669207F06ABF407AA4BB85EC314B9B1
-:109ED0004A6B7621DAEB47E2320BA3F7F5245F4AAF
-:109EE0003E1D843F371C43F990A5B9317E6A9D170A
-:109EF00047FB2D925F259FFE754A3FBF7ACBE1B9A4
-:109F0000CCE19F853224965F311E16CD973543F202
-:109F10002F7347AFD7F9603F2424A1DD73EAB1CE98
-:109F200028BEAC69F854E3F2E3C28CB8D248FC6EA8
-:109F30007E85C2DE89A62FFC7BA740CC8FEC1E8DD0
-:109F4000FC2D89C74BC5B7F95BCD0568C76DC6F356
-:109F50008980AF76C5E31B8671AD86B76FC5F76D97
-:109F6000E27C70B0D0C2ED2BB14E647B5F4EAB7A19
-:109F700007F9D639F974FC6AA8F7799A4947E4B425
-:109F8000E92BFF8DD6DD897886DFB9927B6A1FA524
-:109F9000753486E1FEE0E7370746E07EFDDD40A749
-:109FA0007728993A34CC447B59BDC3701D0172D3D4
-:109FB000F93390CEDF33511E22F83B53460ABFC31C
-:109FC00027EAF752FDBB2DDB6C71D84FAECDBD3B00
-:109FD0008ADF6788F83A1E23E7FB672D3ADA657A4D
-:109FE00019D7BF0F36ED99F6DE681C4FE7B4F7605E
-:109FF0003CC973432C007C1C5710D43105C4F6E5D2
-:10A000004C05CF2FB0CB5827F20DBE6F1E1F69DF56
-:10A010005CC6D7990DED15A09F6D53504F8A927F66
-:10A02000369312182CDFE58E291AFF6E13A372DB0C
-:10A03000D1ED749E3F39CFA360DEB36DD33686FB7E
-:10A0400031F6307F9F92E7535645B59B3217C61DB8
-:10A05000C517F3F12401C81BDB6E60CC12A4431CAE
-:10A06000C51F63FB9D9F5AD5ADB986E693587E63A5
-:10A0700082DF24DFC879D2C994A873F9D523B93D0A
-:10A08000DCB6D1B20BEDEDF2B244C2EF672955094F
-:10A09000EC227A6527F041D08AFEB18D9EBBC1BF0C
-:10A0A0000E8E41FF389DE027C0BFC6E71EF0AFF11E
-:10A0B000F914F8D758BE17FC6B847F01FE35C29D9A
-:10A0C000E05F23BC1FFC6B840F807F8DF02FC1BF2E
-:10A0D000C66717F8D7F8FC0DF8D7587E10FC6B84CC
-:10A0E0006758813F703E05C1F48540D7F63B2C3E52
-:10A0F000CC17DC20E87ACC3732D903F4B71798288C
-:10A10000F66D7FF9070CE7634F37D1F9AFCDE93F23
-:10A110006037A2DF5AEA24BBA9EDE7DC1EB16B0F62
-:10A1200032943B3B95602DF330B6B86C6C0DEEF37A
-:10A13000E5A56FA84A02F886B2893B6CB03EF2F5FD
-:10A14000058B9BA360DDE95DBBCF1D814714EED27B
-:10A15000C03361377615EDC0A33F380ECC13AE2B5C
-:10A160002BA96906160A8F646457F4E55A283F67DD
-:10A1700015D26B348E9FC70DAF622DE9B86F39428F
-:10A1800007EF47A1FA619672E9F53794E9F43EF6D4
-:10A19000BB8BD533955C523DA65EA43D2C572ED289
-:10A1A0008E4D5964EB81B16F350B3995EA2039D565
-:10A1B0008E711CC07BBB9D3FBBA7F0B8C1AE2955BB
-:10A1C000DE29F0F44EE1746DB707DD55D8FF781342
-:10A1D000E52DB08DB97F1809FD7DFBF71AC3BC4F83
-:10A1E000C99FED820F468F70D2F97B76A78DF6ED71
-:10A1F0002F1FF1F3D62480473FEAF1607EC356E675
-:10A2000089433E09DE6BA2FCC6A74B46252D80EA9A
-:10A21000E3263D9B8472FDA49037219117D4DCB6D0
-:10A220007A04EAB1CF5FE3F2F0C7423EED32F73491
-:10A23000103D2739C8EE606C1BD917CDE9406CD0B2
-:10A2400091A60CFEB498DD4BB19E050C01CCBFB6B7
-:10A250007C31D9867E5DCB39EB1C9E1FDB43768734
-:10A26000C51E7027C2FB6D4113C98516DD41F96C0F
-:10A270005B1DDE6E3CCF1C749B28EF756BA189F0D3
-:10A28000D8EAB83684F6BCA634D7A21E0BB9F7DBE1
-:10A2900072E17DA8D044798C21DFC2390807031A06
-:10A2A000E559D10F960792E81CF756D6F7D2442C01
-:10A2B000AFE176575BDA7F1F8DC738F7356E0FDF5A
-:10A2C00056613AE681514A9809FDEBDE4DF1388E30
-:10A2D000254CF8AD41F2535D564EBFEF1FB9C23D5C
-:10A2E00092EC8AA8FD2B2BC6E43C360F944F707875
-:10A2F000E7A01FA939BD36CCEF6B757B6D2B68FECF
-:10A300003C2F8DF22FA0DD16B789FC592CBFB190E0
-:10A31000D4E1F1BC529172AFE3BC7F7004F1A1DDD6
-:10A32000C458AE8EE3D382D1FB83B65115DD3ACC4F
-:10A33000A37D7512CD43533C04B39B341AF7703D93
-:10A340008ECE2F3F6899D78DF6E170DB2DB48F95B7
-:10A3500051AB19F69986058C70EA62239CCCB4C87F
-:10A360003E15F4FBAEE09B58BCC5E223C3DDFA1AF0
-:10A370008E3F2340876B078C7FBBFBA1C44A86E3DB
-:10A3800074D038D31C2B2BD17E4A65FE66E4BF7F88
-:10A39000759C13DC0B6DB9D0FF84141399471359C6
-:10A3A000DF266C77ABE0F7F65C4ECFC8BA5239BF08
-:10A3B0004FA9CA9C928AFB042670CC22EDE706C105
-:10A3C0004133EC132419E0D1DB861BEA8FE91869CD
-:10A3D000281F1BBACC503E6E8FD7008FEF2C37D47E
-:10A3E0009FD85565808BC2571AEA17772F34C093D0
-:10A3F0007A961AEA4F3EB1D2503EA577ADA17CEADB
-:10A40000A946033CADEFBB86FAD29E8FD58FA953E8
-:10A41000BE991D6F4D1F6EB8C726D64F88B5F36D18
-:10A420005FB6E89B909F5D16E2670DF539EE2BDF76
-:10A43000C1FD21DB748F8EF2255EC8D357A6FB4683
-:10A4400022DD2A5D36D20B9A83D7D31CB3C95EC9ED
-:10A45000E9B0D0FD3A9A9BF597C7A37C6E0A4ECB24
-:10A460001B1D19B7DDBD8DEEA9A874CD61987724A9
-:10A47000BFD7DC3E1670627F3AB793DC41AA67D73C
-:10A48000E1FBA8791C32999803E538F86D181F197B
-:10A49000CA4F93FE99F4CB86F2C7A41F96636271EC
-:10A4A000F8DCA5F4DE8A7E7A61C36B55C318F96BBC
-:10A4B000D5A847EEC3F3D9E8A74DE076565BDA9509
-:10A4C0003AC66DDA733BBB47E278524D141705BBB1
-:10A4D000D9B330CA5E5C2FE8A98D6CEF45FDD798E3
-:10A4E00068D3D15ED26CBBA6BD07F8DA69EE7D12E7
-:10A4F000E310AD8A7B5D27CAC53B1C94EFF1A0C079
-:10A500009BEE34156F82763B9B7D1A9EC3EFBC9BFE
-:10A51000795A717DA4546E4A84F7A3B3569830DCFF
-:10A520003326AF79133E03C25E1E5BB8CB940CE5B5
-:10A53000E34A2A17637C4B75437F178937ABAE0E0E
-:10A5400086F36179DA49E42BB4EE2FC0D02B936CFB
-:10A55000B4FF68477A2BF4243CD8CF39427684F391
-:10A56000385EEC3E2514AF70BB15F3E52A933A88AC
-:10A57000BED29E453B17DBF75704D6231FA5CC352B
-:10A58000D255B33D46F8D86AE2EBA23D517F19F5AA
-:10A59000737B6E5E12EE5BF5CB112157EE10FA5312
-:10A5A000BE9772E523F41D5223F60DF07907C6D944
-:10A5B000ECDA363A7F69BF6B1B43BEB6E36975B20E
-:10A5C000F783BA9FF487DF906F563D72B10DF5F5B2
-:10A5D000D9142FD9B3F68DBFA4F1C5E2CDDECBF3EC
-:10A5E000CE86C2AB2BFF61D2EF2080753CB77334AF
-:10A5F000CD511B1DDF94CF6421F7CD323F083C09BC
-:10A60000D4676765FE912F9E8F2F91C3C7F297D2B3
-:10A61000F86E4DF50EBB98BD6D077F331045F7BB47
-:10A6200035BF0DF1D0767EC11C9AB7468B816DFD8A
-:10A63000A27017C58D85BF942CF0AB233E018F39D6
-:10A64000167E5EC0933297EE2D93718FE7A724514B
-:10A65000B927C8541EAFEBCF4F375D984863D52D4F
-:10A6600052EF9229CBF514FC7F04F35246B56BC62A
-:10A670007C76A1C7A59E1EBDCD583EA6C3088F0DF2
-:10A680000DF8FEDF51CF5FC37F073D602C7F58E898
-:10A69000EB6B505FE3BED5B7785E880D467481EBF7
-:10A6A000D988DE033990DD19AE44B199759B66C82F
-:10A6B00027191EA30FFD153AE1CBDFAD9951CFCA83
-:10A6C000B84CAC1C56EE3CBD01D74B657CBC8EF241
-:10A6D00013E318012BF7CB03E0A7DCA779FE548323
-:10A6E0007E55B74AF952924EB1749D5A2EED5CFFD9
-:10A6F0001FA7907FDC5B8CFE3AF61788EA4FC6579F
-:10A700000E4D0FBC89F5649CE5CC1CED79458FC4DA
-:10A7100051645CC03B85AF9FAD9ED71B8EC1388E08
-:10A720009DB0520C6496FA727713E643656B24BFB2
-:10A73000DC93D7FD14FDEFAA3F4339CCE398AE0F6D
-:10A7400023BBBCDB4C71802AC1C755C2DF92F19696
-:10A75000CF843EE99B22ED9C601CF7EBC37168BF80
-:10A760008EDB03B2D748CF785ECEE36AE33B63CBA0
-:10A770007D94A77499E017CC2FAB4CC3B42E0E7701
-:10A780003225D90D749CB8B8F728BA0E852F3E1F14
-:10A79000877CB8CFCEEDB5A7043FA431C58379F847
-:10A7A000697B1C9E10D473AA6C5F0FCCC3735C339F
-:10A7B000E4934D3868840B59149C8BE330C2F7EA5C
-:10A7C0000DB8C5CCEEAD019B1CA6EC28177947F956
-:10A7D0002C1FF96B96EA2842FFA9B1D2C110AFD65F
-:10A7E000B7C7FCB807E5C56BFC7E2A77BCFE4035D1
-:10A7F0007CEF7E29D9D3AC47E8FF14F8D1A81F7E9F
-:10A8000074C1C35ACD51712DA0671EED23BBA9BCE5
-:10A8100013E88AF07EF0ABF3681FB980DEFF12FC0C
-:10A820006A84BBC0AFC6E76FC0AFC6F707C1AF460B
-:10A83000D837BD722CC6C3DE847AC8177145076C41
-:10A84000A3309EED50E97C4D2C3F6E6978D7711D89
-:10A85000C8AAA91DD97353911F6E53E91CF2D8DF02
-:10A8600064CF45BF353AAE161D578CC4D57A15193D
-:10A8700057B3027D5E98ACF3BC45195F0BF0F8DA74
-:10A8800057B7E393ED50BC72403BFD714B5BF0BD9D
-:10A89000023C9AA5B00478FFF11DFFF904EA99D4AF
-:10A8A0008CC0549C77DDA4772CDCEEE6E7A6B2C41E
-:10A8B0003ADA61E779A35922DF27365E397DE6DB94
-:10A8C000B7A602CAE6978F5986FEFFF45BDE2ECE4E
-:10A8D00001F887E53F588679BDD37FF6F633998036
-:10A8E000A77FFE66112F7FF0EDB3591ECCBBF8DEBB
-:10A8F00032CCF3752573FDB6439C3F92F8BD5EAC38
-:10A90000F7FA8D8F921E073B83213E5AD2FCA45F3B
-:10A910003F49E973AD80FAF5A97D692B2FA20FEAB3
-:10A92000373E41DFEF503CA74238EE29369E5F2A82
-:10A93000F4CD19C1BB52DF34DA3928C7C3583ABD48
-:10A940007F50C481982F93BE4BB673F898AB9CF49C
-:10A95000D2FD55FAAB3ADF9F24FFF898EBB2EF63D4
-:10A96000FE5CCB1C8DF60D1F7478EDA8B7368B7985
-:10A9700041FB41CA539965A3FD1C96B298D67592C6
-:10A98000EC27A586F20E92C4788E97C785313ED00B
-:10A99000526DDB8D72F4078E91D45E4B99258871D0
-:10A9A00019096F2A87F1003E135D49B9D49F90734E
-:10A9B000326ECC70F70CDAAD12D3AE92F90C36F3DE
-:10A9C000E968FBDAC17A887F3C265D45FB3079AACD
-:10A9D0004EF2AB987916E37B8BD2104466C479981B
-:10A9E000A2E7A1571BE7A1CF32CC4369B485D12E92
-:10A9F0006C9905F380FAC79DA534DE58BAC9F97C75
-:10AA0000B79CF373EC3C99D83792E704AADC15079E
-:10AA1000705CB34CBE561CD7F3FFA849C10B23672B
-:10AA2000B3060DDF8F8AE4EDB47E9DBC88E9EF2A82
-:10AA30007C9FEB160BCD6FE7348E87872DA15C3A98
-:10AA4000C0A18532707F77283EEE2AE7723FC2C7E9
-:10AA50003E86EBAB25C9C7F9D8DDE76A463E4EEC2A
-:10AA60004BDB44F30A0F4A9F587E8EA5D731BC13A7
-:10AA700081F4625045FC7F157D255D63F7BD24BFE1
-:10AA8000244F754B7AA7D33CC33986FD4068411FDC
-:10AA90006C1F7C33B4A747ED9F59D2FD64679B536D
-:10AAA0003C05186F6EF9521DF47CE45981A7665776
-:10AAB0001CD9DF2D2E6E7F1F715D69F09BAAC18F9F
-:10AAC000C2FD62359975E2BA521396521C4D1D862D
-:10AAD0009617B185D1AE4D98CBED5AB7F7A2E7A442
-:10AAE000B45ED5707FDA00BB36E94A6ED7BA2C6403
-:10AAF000D7EE705A16EF1A44EEBC54CEFD9F2338A1
-:10AB00008F41FC46F017299E29FD458B3B407E9FD7
-:10AB10009CE74B82DF657DABBB81617C4DB5787472
-:10AB2000B46355718E15F3970BA2EC02D9FF0BE5B8
-:10AB3000FC1CFE33D339FD641EFBF4579586C1F02F
-:10AB4000AE4D9576C9E07CF72FF00DC909AFC3E291
-:10AB500043BBC3EB48A77CEFA1BEC3ADEA53491189
-:10AB600039E3F9B254257DA479287FBFD3DCFBCC2F
-:10AB7000ABE80F3EEF20BD23ED71305629FF18FCE6
-:10AB80005E9F071AD9F74F5889A688BF0BFE57F664
-:10AB9000D4A8FDC7A38D2769FF27D64E8D8D27F436
-:10ABA000AF73D713B97C1CA10C5CB74A63D930E4EE
-:10ABB000A7D8752E9FD9E9C597AD8271656714D165
-:10ABC00053BE7F84A97306BB1FADA41FFF5C3F8FDC
-:10ABD00085CE1254D2CB2553818E1FDFF67A9A4749
-:10ABE000C773B49F927E3ED35096B005F9BC2089BE
-:10ABF000E46A96381F26C79375F391C42407E6E9E3
-:10AC0000F58DC5FCB65093FFB26A33F917BEC1C6C5
-:10AC10001B98CAF5110B8F60D1F7FFE8293D578CBF
-:10AC2000017CEB0E9347A775E526BD27D77FA59638
-:10AC300058ED06FECE6E621E878E5723BB291E96E8
-:10AC40007D41253ECB3EC6EF6F1E91D2A7E0BD5B96
-:10AC5000FDFD883C26B9AFF2594335ADCBEC618C94
-:10AC6000F550DCD24FFB0F9FA58417E0BAFEEC2114
-:10AC70003EA2EC478DE5A06B295EBDFAB6B8900EFA
-:10AC80004D8FB80BC687E3F9A9C2B272711CC772A7
-:10AC9000B760BCE757F114EF513BF2285EB32623AF
-:10ACA0003007F9E1E390FE6DD3283159A857F79D9D
-:10ACB00038BA2F6087D27305E54BDC6E628F0F12B6
-:10ACC0008F5A3395FB89B582CFB3D34B39BDD34B64
-:10ACD0002E5B957CE9EBE887425E6F4D08D1FE9CC8
-:10ACE000CCFBBAD73C385FBD3ED524E89463C8039B
-:10ACF000B3A1F703FCA22AC2DEDBF3D4534FA53184
-:10AD00007E847024DF878CDE2F8ECB0B51619CC735
-:10AD100047724771FBB87C7537A40781BFB77CA128
-:10AD20000EDAFFA3827ECDD9DF4EC7FAD5BA879E51
-:10AD300047B24B4FAC00FC391C16668D92BF924F48
-:10AD400062F57BA373E445FD770BC861FD22F10535
-:10AD50008BC8EFDA7C748A0DEF07DDECF0F6A0DD2E
-:10AD6000B5D991E2A5F8BB03E445543CCAE178812A
-:10AD7000F8D0E1E1713A07CA5D8C47E1FC0B71FC48
-:10AD80002FD0FC65BD26217F1C9E30ED93DA3DDB84
-:10AD9000A89E4DF3D3F9385B0AA3BC059B9BDF2B20
-:10ADA0001A976762B641E4F0C6A9DCFFDB5CE8ED08
-:10ADB000A9A2F169786C8A6D4EF7A6931E443CC334
-:10ADC000F7C79CA509D1F87956C88396237C7EFEE7
-:10ADD0008D19EEEA62F467FD7B511E6C76ACB4E12E
-:10ADE0007D5DAAB3E4A2ED1C12F48AB4B33DAD3A82
-:10ADF00099DA7916F95F757ADDD88E59DC8F3A4089
-:10AE00008F89717CD3381A6090F274082F4498B0FF
-:10AE1000812EB14F07C6C39207FB8ECBC55CE1B74D
-:10AE2000805CFC138EBFAEF09D17F81AE3FE4AD289
-:10AE3000153C0FE80C7036DE4B159B67116BBF4855
-:10AE4000BD23F510B4A3623B0FA3FD3226B28E647E
-:10AE50001C27B3D6CFD74B8A9FF805EC191DD78B8B
-:10AE60002AF2F806E8810A8E3FC555A6A3BEA83E81
-:10AE7000DF9B89DF1D729ECAE4F6AB717FF9F83F54
-:10AE80009EB063F967B55517B553E47EF250FBC821
-:10AE9000AEEF7EB821DA4E196A5FF9ABF6938FBA3E
-:10AEA0002C14B7DBA918CFBF0FABE0F22F49CC6F42
-:10AEB000D79480BD2215EBF93DFC40338FCBBC32DB
-:10AEC0003DE0A8C0385ABB850591EFFE519A1E8817
-:10AED0006AE752F12CE3EFC3851D35DCF18482EB88
-:10AEE00074786D48C1F879666DA7E2BB48BDFF1262
-:10AEF000EB59D6378BF667687D2AEAAB196EAE1729
-:10AF000033CF69AC204AEEF44EE5769459D8EDAED5
-:10AF1000A34FDAB1BDA3267F7B3EEA0797497F3C6A
-:10AF20006ABD9B6FF6DAAAA2E6D782FB4283D0D134
-:10AF30005721F56098F4B7D4B766A9275234839E99
-:10AF4000A88FE77C2CED9DFA72EE07D5C7737FFCC6
-:10AF5000C5F4C014C4F327E51FCE1FA5E339D8B04C
-:10AF60003925F7ABF747FAED1B536885F46390FF7B
-:10AF70003BCD7A572FD9592E3A3F21EDAAA29F29CE
-:10AF8000A3B09E47F191FD37096F1A5171AB96DB63
-:10AF90008360675D5991CAAFE48FE6031673AFE033
-:10AFA00050F3F4E27DA6A9180FECA178ED7DE795AA
-:10AFB00041CF41DC5721EDA5FEFD4143DC3553E88F
-:10AFC000BD4C51AE63DC3517F7BB8C71D1E26E23FB
-:10AFD0003CA9C7084F3E1113670DFAFE03CFF96174
-:10AFE0003E0136BA03D61FCA8F55621F342B18AAEA
-:10AFF000C4F3E1D9AC93F61B336B930CF89EAE8A85
-:10B000003C0CBCDE588E137E32B5791FE0F79BFAFC
-:10B01000E7156486BCFEEA55DFC6AB30D9367EBE86
-:10B02000CF069D23BED65CB17016D27B40FCB6C164
-:10B0300018B7CD8C2E073CACDE613C27E8F71591A4
-:10B040007FB0E85BC6F382321F1DE79BE91DD8FF86
-:10B0500057F70BFF9206F62FDB7D18E412C95D71DE
-:10B060008F703616613B5A58C17DEFE10D8CEE139F
-:10B07000CEBC8DF906DB3F3820F0158B67169C415E
-:10B08000F89B29DE0D77F03CD5E1B799C84E1C0E30
-:10B09000F282FECEC03AF03500CE5CA7939D797562
-:10B0A000AD89A1DE60E79B0CDFC37029BE2AE9FEF3
-:10B0B000B083E7E166D7B19009E7D37019AD331AD1
-:10B0C000D7C8083F00BE0CF7095C5D663CA79B1D16
-:10B0D000733E57F24166CCFB6B2ADC867501FAEFB2
-:10B0E0004005C90FAE1747A35E84217D3CE5C4131C
-:10B0F000986F377D13E3F7D924C6F1FB6C22FB135D
-:10B10000EA05E0D7A3B6990568C76C75C799300FF3
-:10B11000E25062EF4F5822F88D152C589D85F71C90
-:10B12000F68D53007EBDA27E67FB3428B7F73D8DB8
-:10B13000C16587E3DB37CCC98EC02ED73D04B3325F
-:10B14000A6E37D4098738AEB2ECE7DE51EBCE73AE0
-:10B15000AED041C1CA3866BC77A7B55CBF17F3480B
-:10B160005A479BC4F9E8A87298C78C696E99FF4644
-:10B17000F9786C0ECF0B886E1FF3B2876CFF4A68AC
-:10B18000BFE46BB46FE3E34FC357A07FD270FC18EA
-:10B1900017C7F691BE18448AEE5FB4A7B1E02EDC63
-:10B1A000CF81FE1C0AEFCF8D792A69CC9897D0DF2A
-:10B1B0009F1BFA1BFFFF603E8B07D2C37C317A2CAA
-:10B1C000FD7AF46835F968BCC1090EF28FF0FE2AE9
-:10B1D000BCA7CE2EFAB38BFBBA10AFADA511BC82C3
-:10B1E0007D48ED42F5E60B02CF987798E6B6109EC3
-:10B1F00087C2DB5137CF93BADB1D176ACEFDFF4004
-:10B20000AF744EAFE8FED0CEBCE4FE96427F2997E5
-:10B21000DE1FE217D74F3F7E81269BD22E1DBF3007
-:10B22000AAE0A5E0F728B46B8AC26B241F69BB1B98
-:10B23000FD05BBD96FC3FCCCB9D312697C85290B42
-:10B240006D949F90BA90F28DDB0A1DF4F705DAF247
-:10B25000BE653347E9E9B6C21A2A87FA94475518FA
-:10B260008EC3F0051BCF7A283E707745753AFA8B6E
-:10B27000C1069E9725F394A43E64623F94E6051FA1
-:10B28000264C3BD07714EADFDD504279680989FF0C
-:10B290004DF9575B6B3D1E2CFF899DEF6BFE48EC13
-:10B2A0006B21A3527C6D42F9A3B8BFEB1DDDA8D082
-:10B2B0007EE6BA8BEF677A3FEDA9C23C2EB682E7F5
-:10B2C00069A5D76831FAD0B86EB7225E793E554885
-:10B2D000E1F835B4B7695A2AE1EDEEBCDD0CFFDECA
-:10B2E000D033D0966A5C5F26CC6B8A5D8F9AC54757
-:10B2F000F78BB146138D2313530540C579C7CF4D46
-:10B300005F01EFB36ED2E81EDF618577517E13587F
-:10B31000FF646F1416BE5C85F08079AE32CE237662
-:10B320005EB1E396F71B4B7A793FF5C4A3DFE51DC9
-:10B33000BD90F2CFE847AE7735663E6027DB534CD1
-:10B34000740F5C5C5ED4BC98A19EF0EBFE67E106D6
-:10B35000D055B48E62F7C9FE0F3F2F64651E9B85E2
-:10B36000BE93E76BF8FEDB705C3B48F71CC6F3C08E
-:10B3700063BF2FE5DFB374BE1F678D63363C5FA3E9
-:10B38000AC8DA3B8A6D50A309EBF11F78C3D2CE238
-:10B3900070CD0AD332BCD1FD85298F5EB55D95870E
-:10B3A000FEC451DB22379D6B13FE9539D14F798C4A
-:10B3B000AC20C9E0A71E15E7D31A6FCE1D8671BD5C
-:10B3C0000428EB417F5BF3D890DE329EE21AD57BF6
-:10B3D0003DEAF1DF3EF7C90D36D4DBE81C9733D6E2
-:10B3E0003DEDC39D78BFB05C9FD673FC9E8E7E58AA
-:10B3F0006BA03C11EBB91CC3FBB0F0CFFAFD961467
-:10B40000AD9AEE9F127E432573B7E27795801CC3F9
-:10B41000BD00E2DE8F81ED6719DE87C1EF8EDE278A
-:10B4200018BAFD78C3FD0256F083066F3F3FA67D34
-:10B43000F7A0ED47DA4D36B4DBA671B9114C890B94
-:10B440000D16F7FB725AD57BB8A487CA63FB629AC4
-:10B45000C8BFB78144C37D29C13F5BD21B28AF4D14
-:10B460008DE3FBA8661023C84FC79CB53C1F23CBB8
-:10B4700098D726EF1569C3FB42A0BCCA61B4D72B8D
-:10B4800059DFB1890AFAAF467B7D3A4A52DCAF6296
-:10B49000B1767C03ED9B9AB38C72A143AC1793B346
-:10B4A000A487F2E0521D94E73054DCE1CD2646F942
-:10B4B00059E6787F03EABCB4E9DA88B632801338FB
-:10B4C0009FE54DCF588E71DE37053FB7811CA0F345
-:10B4D000A38DC376A951EDD658C2A351AFD498F825
-:10B4E000B900FA81FEDF4C1D4EF1D7D87EE5BD31A3
-:10B4F000125ED6A04CCB8B9ADF9B627DF4F7776B04
-:10B50000E62EB46BFBFBB38627517FFD7946A2BFC5
-:10B51000B46FD6DF5FC4FA96FD2DFBB6717ECB2CDF
-:10B520003D34BF65E2BE52D9DF5F707EB9DFA03F18
-:10B53000911FD6DFDF778CF35B66EDA1F92DEBF77A
-:10B540002F457F69DFAC3F99FF60B536D4223F0DB0
-:10B55000950721F31F2677641AF21F5830736E6522
-:10B560001E630F289C2F561D1AFD53E48BB3731BCB
-:10B570003D64A7087F8FCE0BA9745E88F4E8D55987
-:10B58000DC0E91EDEF692A63BE313C4E84CF820A16
-:10B5900085CE238C2D537CB8EFB603E407DE7FB74E
-:10B5A00013D63996879AD2E9B9BB49A7E763E05F1A
-:10B5B000FA282EE621F887D379DCE5810CF792553D
-:10B5C000687F54C6F17CEC8AA960D946FC37582FB5
-:10B5D00047ED98F7782D2BC27368F91D1C9F29D56C
-:10B5E0006974DF7D5CD1F19E2680B794A93AE69913
-:10B5F0006FD1078FF36C9BCEE3BF5B441E6510CF0A
-:10B60000499252017F12E6BF5C908AA973E9FCCD92
-:10B61000D5DF4924FBA6E65BBD4E378CE306A5E8E3
-:10B620003FF2001F7F15F6CDF29C2B491EC4FAA7EE
-:10B6300029A8A94A30BF500D85E0D745CE45E4DFA3
-:10B640002EBA86B124F8FE6AFC0EF4D4ABC23E7A60
-:10B65000A5D7CAD0FF0B56F3FDEC1BEE32FAA50FAF
-:10B66000D8C36EB40B1F284A61488F9ADB8CE55B08
-:10B670002C7CBD2D8AF153AF8EC90392F71F6EC18A
-:10B680005FA7003EA78B7B5F441ED055D375AEAF3E
-:10B69000B39228E95B9ECFB45AD9A0FB94B2BDBD4A
-:10B6A00028B750CEA6F8080F326F8EA97B8BF07B9F
-:10B6B000D99FFCEE61656FC6C5E2A960079EEC2DBF
-:10B6C000E0FA1EEDF5DDD38DF94A67E78EFC7E3595
-:10B6D0001B8C6FFB348C53C8F1FF6FF16BCD743E44
-:10B6E000DF57677E56C2CFDD65B1E8F376321F6C57
-:10B6F000513FACD17DC2321F90A5F71522BDFF7D11
-:10B700005ABCE71EE23F618F84DF305D88FFFAEDAF
-:10B71000F58F23DD976D38BF2ADA1B0ACF43DD375B
-:10B72000413F51F9922DCD9E743A5F97CAF7DF865B
-:10B73000A7547D80E7B9B0FC1D037F19CF6DB51C00
-:10B74000795241BFE52778DECD1CE917E3C36D0EC2
-:10B750006C37C4E34AE127292E9C551B565A0B230C
-:10B76000E78362E562D63AE3F9B3D87B14E7397A26
-:10B770003545C77D803E3AD7983343ECDB208EB108
-:10B780005E2AB727D54C13CF1F19A173FB32AF2FF9
-:10B79000277A1F449DC1ED8679F1AFDFA683E8FDCE
-:10B7A000C7A1BB96639ED4BC84D76FCB05F8FCA120
-:10B7B000EF2DC73CAA7999AF7F960BF2F6CB43FFEA
-:10B7C00087978F7BFDB39168231E6EE2E5531921A5
-:10B7D000C97438B89CF68766C87B137BE8BC762AA8
-:10B7E0001EAC98F4CD9FAAD534E8BA74CC90714BB6
-:10B7F00046E7B3FD077F7702E5945FC6797DC67D96
-:10B800004F26EE4DBC4AB2578A8BECA52BF177C080
-:10B81000E755E2BE1D932D4C781D13B9CFE4A1AFBF
-:10B8200073DF4EE47C3CBF3FA865230B18EF45F463
-:10B8300009FEE77944723CB2FF01E3C27B0193A2A7
-:10B84000C7B583DA91E3FAA4C81A542646F671E51F
-:10B85000B83E51FA7662D0A3EED82F5720DD3E7164
-:10B86000F6E5E0DF37393EE31DA2E327A97D3B156E
-:10B870004F146CE674F41EDE4EF6544586CF3B231F
-:10B8800015EF0FE0F716B40B3B726B6A20887E3D14
-:10B89000F01BE57106B3F9B986EA12E3DF61AB107C
-:10B8A000FCF59B197CFF7896755BC36B25788FBA86
-:10B8B000C29AA17EFDF9B316F4FBE71DE47FA775DC
-:10B8C000FD81B72DF47719108676D6EFB00CFA7794
-:10B8D000E00ECF5025DD0DFECAF3D9F96D29309E5B
-:10B8E000F5ABF8FDD88DBF4E9C8570E30A9C25FE14
-:10B8F0003DBD7DB3F0B365FE236DF85CCE7A9FC786
-:10B90000737F4B02463FE2FA5AA3DDBFACC168AF7A
-:10B910002FDF06D401BDB67C6366CC3D7EFC7EC0C5
-:10B9200025829E4BD2EFEDC17B0796B098FB018339
-:10B930003C8E743D9F013C8DF19179F8F7A4701E07
-:10B94000EB548AF33E9FBD59C3F370F50DFC5EB214
-:10B95000595D9F5AA81CEAE17E53DA707E0F9E94CF
-:10B960009F52BF5FFFDC2E33C60B62EF095CBE78CF
-:10B970000EDD07BE585FCBF5FB883FCE4A82F7B19C
-:10B98000F7FFD57471FD5EB35109E17DBBD7D71ABE
-:10B99000FD8165ACA70DFD99650DC6F7CB371AE1A2
-:10B9A000EFCD107A6D1C1B87EB63D30C45A373D5C9
-:10B9B000023E9DFDC757C2D07F5586BF6D06F0C9B8
-:10B9C0003A4B7802EAB9AA8C00C1B21CDEAFE77A22
-:10B9D00088EB7F13AC2492BF661EB708D6F17BD9E3
-:10B9E000AE1F600F44D90BEA40B84BCA4FBBFF36BD
-:10B9F000F2C39E53E8EF82576B3E2D29CA4F8EE566
-:10BA0000C35F0BBE7E85F516E2B8F291E9802EF990
-:10BA10008BF8DF7DCE3FBC82F22CF38B158F89D65D
-:10BA2000B1896DC4FBC4405EA05C40FB13EFC9C884
-:10BA3000573B17939C9E6871F3FB76D259F4FAF743
-:10BA40003DC914C4170E1DFBBD2AAB9BEEDB98DF6E
-:10BA500071EFA728E7F246F9BC0FC0F8B68AFBB42D
-:10BA6000B7FE5A217B767DE10B240F87015B60BF17
-:10BA7000EBD3855CEC32DE83310CE5141E68995BF8
-:10BA800048FD66C8FD0799E71BAEA27BA586897EA7
-:10BA90007F3F4BA779A7ADED5470DED92CD88C71C0
-:10BAA000A83D280B53234FB94F704D64FFBC02E9EA
-:10BAB0005997DE4BF7C2C8FDF341EACD46B933A032
-:10BAC0009E8F19F28066A9E75DB8BFDDF8DCA88B10
-:10BAD000E675A836E3FD9066B7F17EC8AB0A8CEB3D
-:10BAE0007B9EC7B8AEAF2E1B65285FE01B67285F43
-:10BAF00034A7D8005FE39F6AA87FDDE299C6384289
-:10BB0000BAF17E48BB6EBC1F32BEC0783FA4D3637F
-:10BB1000BC1F92A574525E9AC516EC0DE878BF0062
-:10BB2000BF8756CAE9712E1B5D2A17576C77E0B3A1
-:10BB3000BDC81A46BAB50FE7FBB9D6176F4F0F232A
-:10BB4000D613F6DA2AE1F9B412AAC2FD289BF01B3B
-:10BB50002FBB8B19E4F89533B91C974FE60BC457EC
-:10BB6000625C768F9EC9F3B67B2EBB587EC5A53E20
-:10BB7000FF2FC2784B6B0080000000001F8B080075
-:10BB800000000000000BED5A7D505457963FB7FB64
-:10BB900075D30D880D281F41F4A1A0262069418C82
-:10BBA0004E6636AFBB81693F3269FC986010D3ECBA
-:10BBB000E816138126D14C91AADDA255863466FE83
-:10BBC00048AC4CC6A452B5AD153399A9711713569C
-:10BBD000DB4DEB362AAEC99AB1DD31194D2A2974F5
-:10BBE000DD4CAC8C0A31E3985D77DD73EE7D8FEE32
-:10BBF000D73C12B23595AA9D5A28EA72DFBB9FE75F
-:10BC0000FBFCCEB3A503C022FC3B680BEF2B01B8B5
-:10BC100097E1FF4B01EED0CF0300A7EB5C16A50622
-:10BC2000A0E2AF9565300DDF45C05186E3F65A417D
-:10BC3000A17EF0A095CFAB880C9B94CCC4BCE7143C
-:10BC40005C683AC04F7DEE65B47E47943900C77595
-:10BC5000ECBE64952BA83F98A5605BE9BB6485CCDE
-:10BC6000E4E717ADF4BC431A497760FBF7FD666F54
-:10BC7000B822B1AED6BA142B5FFF6431B6788EE627
-:10BC800027CDE1343A3B282B5D8B011AE95F199FE0
-:10BC90001F18899971FFE676E60CE2A346F9B19583
-:10BCA0009085FFF82D97866D0036FCBD331BCF596C
-:10BCB00098B517EEE5F301F2001E05F1F3C892986E
-:10BCC000054C004DAD623CFDDCC1BF47D7D45F6180
-:10BCD00095B86E67CAF319BDA3E62C9A2F5D1A9E1C
-:10BCE000AF3E27BA2A53A67D5C8E9D72A8B8330753
-:10BCF000E0BCCF6478AF873C12BFD779BF87D3FB56
-:10BD0000A7483733233AA6D249D0EFABE8B31FCFC9
-:10BD10009ECCA7D4716B3C824FFB1934F6678E7FA3
-:10BD2000FF33958F7B59BC0ACC00011F0ACC54A469
-:10BD300087AD65F3E56AA2FFCD5E46F4FF070669AD
-:10BD4000B8FE07836FE5C95300AC0786F28671BD64
-:10BD500040FF501E2C0068B3C8DBA4695C0E9CDB5E
-:10BD6000902F1D91183F7F7B7FF5203D6F8F30A76F
-:10BD70001D8F1A1818ADE7F784E15E4726ED6B7C3E
-:10BD8000AE66C5C4CFD5AAC8BC0DF871CF69343F23
-:10BD90002D1C66C4F7612B978BC30C9EC5FEDE3E3F
-:10BDA0005B63D8609D75446F94EF137D5690504E41
-:10BDB000DA703EDDE364F149AB8DE4E600DE8BD161
-:10BDC0003DCEAECDA0F5B75A406689F35D2D8E7F8E
-:10BDD00044F7BFB0D102417CBE63A399D3FBC256E6
-:10BDE000335FC7BCE9DF7B8BB0BF0EE52F0D8F7AC9
-:10BDF0007CE38D9345B8EE8556ECE37D3D9B2C5C52
-:10BE0000FFD63DCEF8F854F9D5E4F525553ED7F9DF
-:10BE1000F5F2962AAFE3E4B4F5EBC9690FC96906F8
-:10BE200097D3CA3B66CEF7BA7C929FA7C0B98FF46E
-:10BE3000E7F6714B3E9E7776AFC3B91DFB0BCCE1A5
-:10BE40001FE7915D382EDE2F6CDBC3485FF0F08F6B
-:10BE5000D0BD8A4256D8C9488E04BF7EA6F24B8612
-:10BE6000119641FA2AC567FB503E706B85F8FCBA03
-:10BE7000051A0F54D073615F161C2AD8B333496E6C
-:10BE8000EB5579B499C0DF8FE3CAADE03F9049E349
-:10BE9000FBEF6AC075F6E37C7A3E535DAF6CCE482B
-:10BEA0007D03B687687FE4F31EF51C5AFF0724FF65
-:10BEB000D8C2CB260648F7076D82EECBBB62EBE912
-:10BEC0001E8B66F87F4EF66FE5CCF7DA00ED44681E
-:10BED000F6DB157E3A1F384D44F7804AF7E34B7F77
-:10BEE000F7F216BCAFFDEE74CED786632FC689CFAE
-:10BEF0001DA51210DFED658BF2FD06F2A7B5815B83
-:10BF000025E0CF4DF43BA2A3F58A815E6F50F57515
-:10BF10008155DC1FA248A4426E8FA525558971DA90
-:10BF2000FD01B6F3FBD9CB5EE17CDAF2382C34F3B9
-:10BF3000133FC7D7696A3BCB5A709D872D8A25135B
-:10BF4000E9FCDED4C6CD97CB00DEEE461389173967
-:10BF5000DD6D03FF3C805F773B783FDE5DC0FBFF1C
-:10BF6000DA2DF376DE4CDFDB0AAEB3F6446719D187
-:10BF7000EB78F10B3E37EE73FDB485D301C0CDE90C
-:10BF8000B44595BD1B5133D8F0FD8D01160696388A
-:10BF9000FF865B45E0477BF23EED8713DBBB7EC34C
-:10BFA000ED9CB375B45ECE24B9BAD84BFD40D71F13
-:10BFB000EA01DB8FD04F907C05220C0A709DF5B70B
-:10BFC00072F9FCF6C859AB4C72601AA927FA078FB0
-:10BFD0003220B90C748E72FBF932DE4BC173A7BBF1
-:10BFE000B2395D02D18526C1CF4526E2FF132AFF73
-:10BFF00007EFF98F2CB25FB62EF9CCFDC4C753669C
-:10C00000CEC79DEE912C87015FCEE3BA9026CE4F2E
-:10C010006DEAFB466BB0CC89F31A55B94D7D6F754F
-:10C0200009B9440A5B7C5304AD18D26DBD2A5FCDBB
-:10C030007895A939D88FB0583AEA6D73D47345A270
-:10C04000B693C1259D3D00B8A4E9B37962799B6C94
-:10C05000DB41EB9525D94B3F2E3A3FB15F536B0641
-:10C0600039D1A4FD83FC1E69C5A5F97E837B8EC9E9
-:10C07000FB7011C8C8AF8E100319E5BEFD56396FAD
-:10C08000AF1D7E5A263DB1A58FBC407E01E69A1CAD
-:10C09000FB90BFED415092FDDCA85BE8EDA85BE8AA
-:10C0A000F14C17933EB671BB554EF77617FA4B5CC1
-:10C0B000788EDF17BF97750C1FB759639560FCBC6E
-:10C0C00003D01FDB489F70DF72E4CFEB06E7BEE9C9
-:10C0D00076CFA57933E1592EDF80F24D72957ACF74
-:10C0E000852E712E4D9FD71DBB621D26B98D18EB75
-:10C0F00033F3B816D2BA7D005E233FF747F59EEDC5
-:10C10000BB19A75760772EA7D355D8ED73A35C5EF4
-:10C11000C573EC45B9BCEEF36564E3FCEB7E5F46AA
-:10C120004E6642FF3B7667F0797DA5AB725BB05FF0
-:10C130004F728FFB5D8B786C44E70DBB85DE69FB2E
-:10C140007D145B974BFA536319B13AF1FD8CE8C546
-:10C150002C8AEB6A0EAFCE25FD9BE89C8BDDC22EB0
-:10C16000B5776DD97C3957C88319F569B3EAC70229
-:10C17000DB6356A2FFE62EE0F23B78F0830ED2DFBF
-:10C180006BD10C07F9BDAB47328264EFAF1F4D0B8B
-:10C19000A32586369277B467572DC3DFE3F1E361B9
-:10C1A000B32388E302473F7D81F4317010B511D786
-:10C1B000DD1C7D7A94FC5B5B74D91589DA5F7DB3F5
-:10C1C000FAD0DEF5237E5FADFF69B74D26FB794DD2
-:10C1D00012766273E40D1ECF6EBE7DA3D25741F777
-:10C1E000FCCFC564CF02FF746331D9B1C09B371651
-:10C1F000D3FBC0A18C4EA3F8A4D563E6FCD7FC63A7
-:10C20000C93949491E97ADFAAF929E67BDB3917E79
-:10C210003567D738CD72E27D4D99C947E36BDEAD06
-:10C22000CDDD9434AF272E79E9F9A2B3B5191B936C
-:10C23000E4D2EAB1A87608B51AEDCF3A9586EB0AB2
-:10C240007E123757525F0AAA7104BBC3E36D902573
-:10C25000E47313FD87AAD81797783C136C3587CB06
-:10C26000F07D53DCA4D82BE93DCE4B8A33007C2BE8
-:10C270001610BF7F38DDB953E6FE1EBAA9FF545928
-:10C2800098FC3D046D43A54971D0BAB829968672D1
-:10C29000D3184D8B513CB42E2E5DE47D353EFAC84B
-:10C2A000F1FA8F67038F8F2E27C739180F5DD6C716
-:10C2B0004B3085CEABC54BEF515C85F16CF3D69816
-:10C2C00085FC15C649BAF18F367EF70AA338A94B0B
-:10C2D000FFBC242E991EC47B96A0B92332F4C59FBF
-:10C2E000B7917E687126F16BC040DF2B553DD1F4CC
-:10C2F000A8276EE27CE889BB6DA5D8CE53DF0F3846
-:10C300004C10C4F57BA2ABF7318ACB6E3F9C41F455
-:10C31000EA39B70AB693BE3BDCB6329A77FBBBB6B6
-:10C32000B51509F918673F5CAA7D1C8B078CFDDCED
-:10C33000272E35AEFA86FCDDE53F177FA7F83F25AF
-:10C34000FB5DF19ADC44F121DEE71E8A6753FD8430
-:10C35000667FB5758B543E8FB7BF5778FC82F92F37
-:10C36000B7BF456E998F9B116DC8E579F1B935B9A5
-:10C3700072E6F8F5E7484E534EC5F8F5B5782D103E
-:10C3800054866C94C72866AE9F81352CCCA8EF6389
-:10C390003CCE0EACB784E9BD769EF81AC6C7AD7523
-:10C3A000B2B09D25E23F2D3E1C7BBF08DF9724E203
-:10C3B000452D2E8CFB18CF83D62816FE7EDE4C7FB3
-:10C3C0008EBB86EE67E7CF6B968A75D10E0C517ED9
-:10C3D000F4F0F719703BA0C68B9A7CA6C6939F45D4
-:10C3E000E74C852F892B5E56E552D3AF99297AA168
-:10C3F000F9A97AD54F77909FAE263FFD8595F460D9
-:10C40000A2B81BFDF45C379F077CFEA277259F51E5
-:10C41000DE7D585D77B1C6B7F809179DB718E2DB26
-:10C42000285F9CC87FE6794C3ABB90FABE7E927A30
-:10C43000DCA2C60BDF941E37ABF1D7FF753D1E8B18
-:10C44000FFACC6F7BCE976FD15C96FBAB933EE2269
-:10C45000BDFB17D43B79FCB8222D9F9440C79FA108
-:10C4600062AB89F29E40ABC00142D9F2199E9FBCDB
-:10C4700065065A67F3AD421EA73D762B9BB7A142D6
-:10C48000107EF4C9128EDB3CF6DA598B82F39BB630
-:10C49000B285840735B5EAEF139AAE709C2D788487
-:10C4A000F1783954D87F92F42AB86F8E4CEB37D399
-:10C4B00065090F69CD0EEF20FC82709C7BE9797ACB
-:10C4C000820EB84FBBFAFC7E15DF819438E0CDC1F7
-:10C4D0000B1CEF090C3020FDB546D17E903D39256F
-:10C4E000F08E8EA8B00B9F74D9B93DF94412F708AD
-:10C4F00074B1F036968823AE449FCB233D1B174F73
-:10C5000028184FE425E289F657DEE5F630357EC877
-:10C510001910FB04DACC61C263868A1733EAB76369
-:10C520003E984F71A22C3F5424CE05616E57141DC6
-:10C530004EB2F72EE1F73F3BF56F3C8F6C3ACC20C3
-:10C5400097C71D4ABC342F11773C1A5ACEFDBF162F
-:10C55000673C3AEBE45011ADA7C6190EFC25FC3040
-:10C5600035CEE8889CB5505E302E9E4889235E7794
-:10C57000EB71C15992C05967459983F0A4592A3D7E
-:10C58000EFEB4BE77171FD871B7349CF35FE5C6B99
-:10C5900010FCBA76E17317CD5BFCA1E4207BFBE6CF
-:10C5A00085ADBF29127DD926D3BCAD1994875CFB1C
-:10C5B000F0890CA2E79BD802EAEBA1F392217E2836
-:10C5C000ABF608FDDB3FBB39FE2B17715C4742FF22
-:10C5D000362581BFA4CE7BC023EC4108D30C8E3B13
-:10C5E0001E062EBFA142FF72DE7F7136ECE3B88FCC
-:10C5F00090D737A2D90E8AF7CAF1B25D6827FE2E0E
-:10C600001D7AEC5524CFFEB7B97EBC68E2F28BF3FD
-:10C61000838CFA0764EEEF8864EB717CA515CF522A
-:10C62000056233D4B77B54BE15621E4AF9209E665C
-:10C63000CD1DA453F98C535F101F2BD341A2F59F3E
-:10C64000B1F877DE8D539E19949CDB688EE4CC6D37
-:10C65000C07B3D63174B3D7318E515CF85D2CDCF19
-:10C66000D55171F23CCD67B203D6E3FC8E82CC1873
-:10C67000E16710B1FC7E4C2E510E18ED5329E4ED0C
-:10C68000E3F9141B2AEC0E9A9AB7EB646117BEEF1C
-:10C6900003CA83762CE904CA3B4FD6811A07D98294
-:10C6A0009771FC5A9C31159F4F2FF417525CD15E45
-:10C6B000306C1571C58895E28AB92E6DBCC0ED4C01
-:10C6C000389EECE5CEF9AF73796BA2E749FA0CC955
-:10C6D000F89E797CBFC53DD1FEB2C8E752F65F94A3
-:10C6E000FD591ECF5FFEEB8F59DC9F456F70BF7306
-:10C6F0007D240DE21CB71B163875D4C2F3F5EB98F8
-:10C70000074D4FF2673B5C820EC7A21E2E8F03F1CE
-:10C71000DA0C1AFF4B97D8AFEFDC9AD50F929CC476
-:10C720002567193FA5C86B06E2528D880FC6D1A9AF
-:10C73000CA6D704E5BBAB0E7A9F279C92DE4FA125E
-:10C74000DD1BCFE1B920F295C056513F70A8FA1613
-:10C75000E864DCAE9C2CCE631A8E9C6F545F383C30
-:10C76000C2ED6CF30F9933284F5C5FD8A5E619A989
-:10C7700076A8237240F02D15B7F5D673BB3359DC7C
-:10C7800016281B5E9CB0D3DFF1A8766581C0714F7F
-:10C79000B81DFCBE399D0B5DF990B8BF013DF77B1C
-:10C7A0006AC6D3D3605CB4D680EE06E3FEF0C0E484
-:10C7B000D6AB5626B79E6B92E35A94C9ED7B68922E
-:10C7C000EBED99E47A4F1AE92DB25DC4030E2137DF
-:10C7D00075E6DB5924FF4F1C9993FF65F1AC190DE9
-:10C7E000AD9CC47F8B231DE424BFBF627EAEAEFF31
-:10C7F000A0B34837FEA1257374EF1B9472DDFBD5FF
-:10C80000DE6A5D7FADEF7EDDF8871B3DBA7E5AC1E3
-:10C8100072DD78BBBC4AD7CF98FF886E7C087566FE
-:10C8200009DACF346B6688A1FC4F71FEA56E7C7A65
-:10C83000B53D93F422B4302D46F29EF6D6A620BD27
-:10C840007B9AFD642446D4CD3AD8C85065A5EC57F0
-:10C850006CA4272B978ABA405FAD2DBC87E29CBBA6
-:10C86000B22A69BE46AF7D7522FE72548C06739162
-:10C87000CE3395786D2EEAF3F5A5C0F387EB7651AC
-:10C880001F00C951D8C0F9E7285C85763F6437AEF0
-:10C890003335D6A979F104F6E4749DEB17A42F0E75
-:10C8A0008ACB0DF8A8A878BD23021CB701492E5CDD
-:10C8B000C5F7950BC9DF4C3D219E67C540D9C3CF55
-:10C8C0002597ACE271B45C42E7DBA5D6BF7296CF88
-:10C8D0002D21BC2E07FD2ED5479EA33A09CF031C60
-:10C8E0007C9CB69FB356ECB7CB028CEA59C1BB19FE
-:10C8F0008F53C1315557DF386D895D6E61BCBE7194
-:10C9000082CEFF8E2956B1B744F085E85B31E0E076
-:10C9100075975F2FFDF97C3FDF47D43BB638C49055
-:10C92000E3946FE039B61CA9E6F2DB746CE96FD7CB
-:10C93000535C582A713A8F8BC7D53CEBBC9A276A57
-:10C9400079D630E58B4979C7798F6922BB74DE636C
-:10C95000A057BB98C88383EF883CB8DAEA9CD39988
-:10C96000C4A7CB6A3CDE121378AC96DF562A61531B
-:10C970001ED2A1FA29732C0DFD7575EF022BD9ED8E
-:10C98000EADEE2748E2F6D3C60D2E86DC4F76BEA8C
-:10C9900039FB4E8DF0FAC41B29754A67AD95BFFF70
-:10C9A0005B551E9DB5C0DB2D65D20E72C353BFED26
-:10C9B000301BE1E3CD18FFD3F95A42E2BC5A3DA443
-:10C9C00039267B689F8B4323BDD456B59678387E35
-:10C9D000D836DA4BFE3370FBC6C907381E6095297E
-:10C9E000BE4A5DF7509D99CBC51B149010BD96496A
-:10C9F000611A57BD4CE2FCCE69B6F37C3CC702E637
-:10CA00004CEA37087F56E59DE6A13EACC9E6FEB884
-:10CA1000EA949CBDA92291EFE72CDB3A9DE8F455FE
-:10CA200075220D37983753994A7EE3EBD689DA4F52
-:10CA30009FB3D2BD370CEBEB445ADD67A23A915657
-:10CA4000A70D783FD7D59503D2483DE12BD5472E8A
-:10CA5000F23A7120C21C052589FA516060D4CAE9F6
-:10CA6000ABD68D70BC95E60D748BFAD141DC9FDAA4
-:10CA700008DE57C173FC23DE97DA28DE979E1FED90
-:10CA80009ECFDB58B793B7C7BA97F0B61AC5A63092
-:10CA900087EA4EA3BCEE5453ABAF5B68750977A130
-:10CAA0006F496D8DAE6EC1FBA9750B73BAC8470394
-:10CAB000A72CCEBDF83C70DAC6EDAC2BDA328BE297
-:10CAC000B29B67FDB31CBC0E90CBF3CA31F9559CE9
-:10CAD000F66CCA077C4E3BD50BAA07AF58656E773C
-:10CAE00062455040F853DC4A793FD141E1F19CCB9B
-:10CAF0004E74FD4A7C3FF2FFF8FED7C1F7A37502E2
-:10CB0000DFD7EC4795CFA4ECA1F69462DF94641FC5
-:10CB1000FA7C0227EE2B9DCDF5EF79DFECEC8DC989
-:10CB200078BE57E47139CB4AEDC9CF59BD45C47DB4
-:10CB30000C7C4676ACB776427BDB6B1CDF19D705E5
-:10CB4000FABCC28E68B8FFF83A81F3ADD224BCFFBC
-:10CB5000DA3B28A798B70E1E4EE3FEFCE691B4BD63
-:10CB6000147F577937CE9A82FDAAF3695022FC913F
-:10CB7000AEBED0E43529F62CA37A82526442B91DA8
-:10CB80005737F09AB87D1FAB1B78A58BBCAFC6E9B1
-:10CB90001B467F37A58411FDC321CA33DE6867CEEB
-:10CBA00041185F47C0858B6009DEC27B8ED7959D9B
-:10CBB0009DCC29CB5F5D5FC85371868E48B699E4E2
-:10CBC000BCF904402E33AA337879BC5F05CF866A5E
-:10CBD000E97BAC529383FC592A5E407242FE3F15BA
-:10CBE000278CAA7C8CD60A7F53E711FEA64A8D4B70
-:10CBF000B479A9FCCF56FDD344B82353E39F1E6FED
-:10CC0000551FF12FB8D204E4077ABC6E5B69D27A63
-:10CC1000676AC5774BBBA86E312DB96E21EA13A99F
-:10CC2000F50ACD4E550F7E514FFC7F3E2AF0A440B1
-:10CC300081C037AB8FBA4E91DE27CE29EEF73CF29A
-:10CC400038CEE3286736887B814DE05E1C67A85AA2
-:10CC5000F9F9B10CA29F0FFD15D9A5D3A53B32C997
-:10CC60009EAC946A98CCF1EE31FC9BF0A9D5675A42
-:10CC70009703F9FFB50BCF12DDD7AEB7F0EF9034C5
-:10CC80007FB5FA4C63BD78BF677B3ABD9FCF9C767A
-:10CC9000999E7BDDF47CC5AF6284F4C183747BD440
-:10CCA0009BF8E9CB12E9CBBC99FEEBA43FD50D2A4A
-:10CCB0000EBE5EF8D7B5D1060B648EF777C78B6FC3
-:10CCC000F23CFA46B49AE3DBB9547FAD48F88BEAFC
-:10CCD00023E887A6FCE9FC50769DC807EF453F4452
-:10CCE000E7C9691075C254FE9F51E3C989FCCA4463
-:10CCF0007694FC886989D01B5690F0BF32E5D7F74F
-:10CD000025FCB02382FDFC2FC1BD55B9CE9E200E5F
-:10CD100073ABF23BE1F71B916F0607FF8BBA3F8FB6
-:10CD20007A9696E76878B89617BDA8D2596B5F5285
-:10CD3000DB54BC4CC3C9F21580AE2FC1C9F2094700
-:10CD4000CB21B35DC171BB42F50C63B8592CC774DC
-:10CD5000A71CC7A9B89D869FE56DE86714671443B3
-:10CD6000701BD997212BB80E4CA3EFF6186C23FD3E
-:10CD70000E37F03867E8A5F77B7F41DF1B0E3007E1
-:10CD8000B99FF6FEB3DC4FB7635CC3E3A1E8A7022B
-:10CD9000A7EA17DF9BB647986284830EAAFEB956AE
-:10CDA000016E37DAD5EFFAEA07845E2770A21F49D1
-:10CDB000C93851408E4FD7BE170C0BFF64F85D5F2A
-:10CDC000078CF0EF013B5A993386CF5371A354BCC3
-:10CDD000E859F53BC0097123E5EB7DEFB7BD6EEC7B
-:10CDE0007B3F8E3FEFF308BBD0E8678CD6B7997CCA
-:10CDF0006DFCBBDFA3CC61F4FDE86E55EE57A8F8DF
-:10CE0000EDAB56210FAF7E8B85299E5B0102A77D7E
-:10CE1000F5680BC76F5FAD624E13DD53C56B97AB03
-:10CE2000F4B83B81D73E4F78EDF7D09D104EBB4212
-:10CE3000E53F40989FAB61777A8CE28D672CFD05CA
-:10CE4000A48FDAF7465E15474D4F834E23FDECA9BC
-:10CE50007379EB6A68DC84F1CE2B7506F8CE558FBA
-:10CE600058F7977518A7CF07A3387D7FDD745D9CB1
-:10CE7000CEFBA971FA9F0AAFF5D03D8DCFFFDF93AE
-:10CE8000C4ED1EAF9DDCB84D7506F1DF0E153F49B0
-:10CE9000A56F66BD66876738B83C8D9D1F443D57BA
-:10CEA000C5BD86543F1762F26FEFE7F52F0BAF7FDA
-:10CEB0006976263445ACFF816A5FB4F6A6DA862C23
-:10CEC000C6380DAB177EEADB85CAFBC4C7F2D7F4C0
-:10CED000B8D9827E3D6E766F2447D75F18BB4B373B
-:10CEE000BEFAD46CDDFB9AF83DBAF7F79DAFD2F5E8
-:10CEF000970E7F4B37FEFE4FDCBAFE7746F4B8D96B
-:10CF000003B7F4B89926DF2E9488E4791EDB0F74FA
-:10CF1000E38A5AF5F72AEED4DF6B5697FE5EDABA4B
-:10CF20002541FDFDE684F4F7CB215CBFE27F8FEB6A
-:10CF3000FF4DADCCE97F2C3AC74EF376794BED141B
-:10CF4000C74C2F14F2AA8DFB1FAC27E8D970300014
-:10CF500000000000000000001F8B0800000000001F
-:10CF6000000BE3146060F8510FC1D3F9191836F3C0
-:10CF700023F8F4C0C79819188E83302303C33E20CA
-:10CF8000DE0AC46B80F83D0303C352203D078827A7
-:10CF900003711710BF048AD5B1623787858D8181EF
-:10CFA0000D884F02CD3AC54CBCFD8A7C08F6215E47
-:10CFB0000686B5407C9497BE6130D8F00C41FAD912
-:10CFC000F50C6AD76ED181F73708B38A3330304A0F
-:10CFD00020F8FD12A8F26CE20876960C65769501B1
-:10CFE000F50300295128158003000000000000000F
-:10CFF0001F8B080000000000000BED7D09785445F0
-:10D00000B670DDEE7B7B49BA3B9D90952574802000
-:10D010002A4BCB1201113B2189010306440928D276
-:10D020006C2184249D01661E3EFDFF6E0842C4D122
-:10D03000898A1AFC195F83E004079DE0A0139DC054
-:10D04000348B8833E804C70597795F401E2042126D
-:10D05000A338E8F3C9AB73AA6EBAEB763769B7FFAA
-:10D06000F97FFF840F8ABA55F7D4A9B3D5A95375B0
-:10D070004F14924292FA1372097E6E20E455851085
-:10D08000FAA8BBEC903A87CB0383ED6BBD2EE2325E
-:10D0900012F280D784E57A6F3A715D419F8FD61581
-:10D0A000F92D84DCEFB5E3F3C7BD25583EEA2DC565
-:10D0B000F211AF1BFB3DE42DC7F257DE1A2CEFF542
-:10D0C00016617B9D7715D66F5416A4C1B884B84CF1
-:10D0D00059C984785E1E387203ADADCF1C9F208F76
-:10D0E000A6F5BFEA893E8BBE375A2EF20FA50D7208
-:10D0F0004951D6E8603F15CF1B95BCBE00E7F1B1A2
-:10D100003AD6CF54F35A76E47E59640CC573AC8C8E
-:10D11000F8134BC9E4ECE488FD0603BC4786B279FA
-:10D1200012BBF3B54191E15D0DF01E1ACAF14BB689
-:10D130004F1E14199E13FAFDCAC9E1A5771E1E18C9
-:10D14000B9DF18E857E7E4F0FAFA4C03228F3B1EE8
-:10D15000FAC5C0278A1321BE16A33F3BEBFBF38B16
-:10D16000B8E85F8A4FC75EF3D60D12F26F1AD06926
-:10D17000AD7DF9992D749CF696614EBD8390CF5C80
-:10D18000CE04BB2526BEDD02F388816FA5304E0C90
-:10D190007C9B1B23DF1640BF18F8B604FAC5C0B746
-:10D1A000CA18F9F6B39F08DFEE053CBE07DF36C4A8
-:10D1B000A86FBF8A916F1B63E4DBA618F5EDC91851
-:10D1C000F9F65428DFD4E76AB9834868176F544AE0
-:10D1D00076403F4F669B6D40D64F827F7BBEA7DE79
-:10D1E000ED8F917FAFC6C8BF23409F18F8773446B4
-:10D1F000FEBD1323FF3E8851EFDA709DB1C85FB5C5
-:10D200000D21F8736900FC6BB19FBA9AD7F580774E
-:10D21000122119E172A09694A3280F3271B7B37549
-:10D22000ABE09B4B3984AC30D1FFD2F77D7924A0A1
-:10D23000A7E3FB6CC45F2B09FD3F073C09C9FFE670
-:10D2400052AAD0DFA78BD89FE8A0FD61902BCAFF20
-:10D25000CDDE2158D67339DA5CA44379F0251B5012
-:10D26000BE9EF03AB1BDC13B16CBC7B85C6EE4724E
-:10D27000F400C8DD152087A55CAE98DC1152E228C9
-:10D28000A774EDD8134F363850AECC12E02933795D
-:10D29000BB77CF955B3750F89B6B74576E0B91B390
-:10D2A000278A54F9A292991CECF744F909DB82A170
-:10D2B000486F1BC06928D6A9FD7CA1FD1ADCDDFDE5
-:10D2C0007A41BFC78AB97CC924103AEE63A5DDFD57
-:10D2D000D2254A977B2552DA6409E7CB1489E929DC
-:10D2E0005514E487CCE9BB3FEF2C69A3EFDBEC23BB
-:10D2F000D3082D9F04FD44FD7360A9BE5F4FE9EC88
-:10D30000A6F4C834929A26C097B44A0AC5571EEBB1
-:10D310004804397A689C8B485642FA433B1DBFCF7C
-:10D32000E8369245CBC4F16D441A06FD683BADA7C3
-:10D33000F0F68CA1B49DC27908DAADC1F654DE9E38
-:10D34000E6E0EF5FC7DA1FF6121C5FED771FE5B36B
-:10D350009BE2B78EE28BCF8B890BE8285376FA439A
-:10D36000E63F5BD2E3BC2B79A9E27F5FF6A98CF99B
-:10D370004383F89A075FCC981F82DF7D83E7605D67
-:10D38000C5C77C4525D6FBAFEA4D3D31AE0F249C89
-:10D39000CEA9330708ED0ED9897E9AE3889EF82836
-:10D3A000BF1C543C23F1E70B2ACE3FA8FEB9183D21
-:10D3B000B4ED776BE8B02E43A483A1B7488775BD61
-:10D3C000453A18FA5C9E0E532407C28F460F75DC4F
-:10D3D0000D578AE3C65D258EBBE12A71DCB8AB7FB1
-:10D3E0009871D7F713C735668AE3AECF14C735F601
-:10D3F000FF7EE312D9491F3273411CF0CF3CC1BEFE
-:10D400005D20EE8741BFC1CEE99383764EB697107B
-:10D41000B725C84F22D3977342E1DC29D8550AE7D4
-:10D42000FF7038AECBC3B16BE0CCD5C2D9C6E190AA
-:10D43000503B1D0687DCA19DC76FF97B015DC8F8D5
-:10D44000747D2525D6D0F79C9AF16FD78EBF1BEC43
-:10D4500018CC4377D9F11D1ABACED1E2B387C321D4
-:10D46000BACBD183D83570666BE11CE27002D2650D
-:10D47000E1946AE7F1BACA574958BF283D8605DFEB
-:10D48000EBC8EB3C857ED08B8A633B6D97FE640DC9
-:10D49000DC40FB1FD922F98DB41ED81B8FEBC7F9D6
-:10D4A0006DD3B1BEEF1A23AE13E79D93FD466A4FCD
-:10D4B00026BDF0B60DEC4BD50B7A19EABABD1FDBD1
-:10D4C000DA285E1E63EB83D7D1E79D2FE8C9569417
-:10D4D000C6421DD0FD14974DB28AD5CBCCAC5AB5FF
-:10D4E00065DF9D00B7BCD948CC144ED54B4BA65D2B
-:10D4F00047EB4B0E2B04BA546D5F6DE84DEB4BFDC3
-:10D500005213D43BF24839E8D39ABDFFD90EEBD180
-:10D51000F9DD4A368C7F96AE130E6A8F8F585B53B7
-:10D5200067523C2AFCBB0AE1BD8A9D92935A388A15
-:10D53000EFF6431980EF0EC969A4F45ED6184F1CAC
-:10D54000AABDA37F4FEDD6E3FC97D3F9130A6F0969
-:10D55000A92F047A560171607CA7D16F9682FA7662
-:10D56000D67B18C753EB553BE878F4FDEAE7242750
-:10D570004CB55A47DC8067FB4BE6D2A72C30CFD5A1
-:10D5800086C15698DF7A03F45BE29FFFA2D9017847
-:10D590006E311402BE9BB718CA8602FDC8BC92A1A8
-:10D5A00080DF5F44FC1AF42E98EFF26B8C5BF5C0C1
-:10D5B0004F4B60D00C6BB89D3D4BD72B47C8FA59E9
-:10D5C0004198DD27B2DF307D58F0F94BFA4494835F
-:10D5D000658D7AE208B51B5C3E7C4709F363F6581B
-:10D5E000FDDBB3827C5C6EE7F2CAF9B83C91F3557F
-:10D5F000EECC99312C1C9F07812F46E61F41F93054
-:10D600005D371DE8FF38907E8F51FFC981FE911371
-:10D610009F3F41FD242837533F09CA27A99F04A5EE
-:10D620009FFA49D06F2BF593A0DC46FD2478FE3499
-:10D63000F5CFA16CA4FE393C7F86FAE550EEF4FAF2
-:10D64000F0F973DE3A2C9BBCF5583EEF6DC072B713
-:10D65000D78FFD5EF43662D9EC6DC2E72F7B9BB1AC
-:10D660006CF106B0DC0B7CA665C0DB8AE57EEF3191
-:10D670002C0F7ADBF0BD43DE3358FE92D3DD3681CA
-:10D68000E4CA545E6C2E6207362515BB72C15F4931
-:10D690002A61F5D43B7CB9065A4F75D33AA563EF9E
-:10D6A000CA40AE91D67BD7B0F6CC7B489E89D633A4
-:10D6B0007DAC7DC02F5D79665A1F50CFDA076FF6BB
-:10D6C000E5C5D1FA603F6BBF6A67202F9ED6AF6A6F
-:10D6D00062EDC35BC8240BAD0F0FB0FAC823AE498F
-:10D6E000565A1FD9CAEA391FFA26D9683DA78DBDF7
-:10D6F0003FFE5C605202AD8FEF64ED13BF26F976FA
-:10D700005A9F4824ACE75972F313693DCFCEEA859E
-:10D710007DE7CB8E08EBFB5EA56D2198B49FEB7285
-:10D720007265EA27EC35B4AD0093BB5E7743AE3C3F
-:10D730008ED24F218BA07D93AE88D50D6425B4FF8A
-:10D7400056371DEBFB1507B6EFD1CD61758303DBB3
-:10D75000FFAA5B88F5838A0BDB8FEB2A59DDE0C2D9
-:10D76000F6CF743FC7F10E296E6C57F4FF9BD50DB1
-:10D770006E6C7F585E9F9B4FFB57EADD1E1D95EB3D
-:10D780005AC95D4E0682BC36A5833D5CC7FDD6599D
-:10D790003A07CAFDBA0C03EAD9DEFFCA790AF50CCA
-:10D7A0007E92A15EF634F8BD14CE2A84A35038FAD6
-:10D7B0009EE14CFC66AC0067E237E52A9CD508C7C1
-:10D7C0001C1B9CBDDF8C17F1F9A64285B34147EDC8
-:10D7D0007DAD35B6794DBC3441C4E752A50AE71199
-:10D7E000C42731367C02CAB5029C80B24485B31985
-:10D7F000E1A4C4868FCB304E80E3322C55E16C47D8
-:10D800003819B1C10918AE13F1312C53E13C87F43A
-:10D81000E917DBBC5CC6EB457C8C552A9C3F203E5F
-:10D8200059B1C1D96F15E9B3DFDA4D9F00C2C98E76
-:10D830006D5E7936913E79B66EFABC8670AE8C0D0F
-:10D84000CE7E9B489FFDB66EFABC897086C536AF0A
-:10D85000BC04913E7909DDF4F900E15C131B3E073D
-:10D860005344FA1C4CE9A6CF49843326367CF25344
-:10D8700045FAE4A776D3E73CC219171B9C83A9227B
-:10D880007D0EA676D3E70B84737D6CF3CA4F13E944
-:10D89000939FD64D9F4B0827D7DD88F8100AC71AEB
-:10D8A0001DCEA17E227D0EF5EBA68F490F700A28B2
-:10D8B0009C813DC329CC14E95398D94D9F443DE840
-:10D8C000C5E4D8E01CCA14E97328B39B3EBD119F80
-:10D8D000A9B1CDABB0BF489FC2FE8C3E1E63E7240A
-:10D8E0003BF88D89C4B995BE3229F9670761DD51CE
-:10D8F0002CC409608F48816D009FAEADE897CA4E79
-:10D90000D50F7212F0738B6D0E27C403F4AABF43B8
-:10D910005A713F62D99928C49B5ED2E70D077CAD4E
-:10D92000D42B0CF57B12C6C609FE56A22B49A8F7CC
-:10D930002AEA2DF44F291920B4A7955E25B467B8BB
-:10D94000470AF53EE5E385FEFD6AF2847AFF55530A
-:10D9500084FE59BE19427D60DD1CA17F76FD02A1C7
-:10D96000FD8A860AA1FD4AFF72A17E75E3BF0AFD0A
-:10D970008735AD11DA47346F10DAAF093C2CD44744
-:10D980001D7E42E83FA675ABD07EEDB16784F6718F
-:10D990006DCF0BF5EBCEBC2CF4BFBE73BF50BFE117
-:10D9A000E29F85FEB9E46F427D92E903A17F81FD8C
-:10D9B00023A1FDC6F44F347EAC18BFA8CD25CC9F63
-:10D9C000CD30A03F1BB01AB06ED86B66FB1BA827EA
-:10D9D000431CA218EB86FD0B1DC9100F0000D49F3D
-:10D9E000C8ED5D7E05C4AB7E31DE7D05C4717F610F
-:10D9F000708FB047F083DA65F73D7A8C27B64A24FA
-:10DA00001D4A870ECA383D8F271899FCAECFCA79B8
-:10DA1000CA17A20775FDA87F41EBEBF5148F3141C2
-:10DA2000FD59DFAF2C7D7EC838EBFA194AB70E6579
-:10DA3000CF175A60BC92FB603C8FA17330E0A51DEC
-:10DA4000C73860AC308E29B31CC7D908E3A404C71B
-:10DA50003166966BC631956EE5CFF9388F81DE441D
-:10DA60001B67FD80F1E27C322B709C2D9A71D6678A
-:10DA70005668C68963F3A1CFF9384F5D6E1CE3C0C9
-:10DA800009E27CFA57E238CF69E7D3BF52338E05FB
-:10DA9000C781E7300EE94B77316994CFC6CE329417
-:10DAA000833F99314E66E853F11BA8930FCC241B9A
-:10DAB000C671D071693F3224890A3521FFA24F42D5
-:10DAC000FE7C1147F91F124F0BEEC77DB8AF5FCC3C
-:10DAD00051247E8A11DD275573D95CB4737AE60A26
-:10DAE000072D9B0F0C7A04C6D9687566D37A7BF331
-:10DAF00024C3C208F2B4B85E39D51622E7DDFBB301
-:10DB00003C32A4868EBF22CE8EF8A875B54CD28941
-:10DB1000CF4FD07D17A1FB930FE93E85D0FDCA47BB
-:10DB20000ADB67FE3BDD9F41BD8DEECFA09D90D50A
-:10DB3000F8DE091E673EF14BC90FF4FEE2AE9F29E5
-:10DB4000B84EF8C85BE9A9104D603FF356C553269F
-:10DB500004F19BEFEB25D4A939EEA34BC77D2DC66D
-:10DB60000F3A5F32FAB7025DEBFA509AF27E030881
-:10DB70007977EFD443920DAB7D746309995933BD26
-:10DB8000200DB548EAB79CE23963F7350A7D83B4C6
-:10DB90002B6D773A2D41B8C4A59C00FA98E81F80F8
-:10DBA000734B11AD878C7F6B89589F45E4609DF264
-:10DBB000FBA47E0061F17F3EAEC3A5005F4BE81C75
-:10DBC0003328AB674139129A59BCA6D4CEDE55F141
-:10DBD000F12C544800F7D7BE148863135F32F69BCC
-:10DBE000A3EE9335F8952A265709A56BE97C3DD21B
-:10DBF000558BEFFB7BE35DBAE1B4AC7B4481D06C29
-:10DC00004FF8CF768BEDA49C8DA7D2559597539C5A
-:10DC1000BF2780FFB43C0DFCA7789FE4FC0FCA31FE
-:10DC2000E3BFC7E89E06FCEFDCA427C82FCEF7DBD6
-:10DC300038DF17D78B7CBF0DCEE368FFDB5666B1AC
-:10DC40007853432F81BF74E2221DEA1F2AA0663554
-:10DC50000CFFBF73399853B7EB1560EFEDE59AF9F8
-:10DC6000713EDCC9F93057438FDB38DFE672BE2DD9
-:10DC700021BE7B33307EE15720AE37BB5C22602F64
-:10DC80003C77AB7C6B13F8E656F9A6C1F74ECEB7DE
-:10DC90003BEF627CD3E2DDC6F9D6D6F0994206842A
-:10DCA000E3ADC573DE2ACDBC7C5ABED573B9B41BB7
-:10DCB000C09F9AEECA5D7132A4FF2D4593579C0C0C
-:10DCC000B10BB7964C17EAB34A670BFD67BBE70B7E
-:10DCD000EDB7972F15DAE7D6FC4CA8CF5B7597D038
-:10DCE0007FBE6FB5D0BEB0EE3EA17D71FD43427DDB
-:10DCF00049C326A1FF52FF16A17D59E30EA1BDAA7B
-:10DD0000699750F734BF24F4D7EDBDF26690AF2386
-:10DD10006FEB09C4FB2E384F639CF1825371429F15
-:10DD2000935E07CAF129EF102CCF789D28E767BDD5
-:10DD300063B1AC06991C0776F68005E2A79E386AA7
-:10DD4000F713E93A2E8F5B533701D61BDA3E9E90CC
-:10DD50007F956F58E3EB4BB500E2DE94FEC50D06F0
-:10DD6000121845A874F7EE96E74E7D487B5B0FEDE1
-:10DD70000D3209F40A6F2F6E8BFCBC43EA1C9C0128
-:10DD800071D9F78C647B48BC31FCBC85F401BF229F
-:10DD90005AFB391D290F3DEFD92AB3739E23FABCD4
-:10DDA000AD32C5ABD2C0F4BFF2F98C3C62837A606D
-:10DDB000708DE532E3355164D280CF0305BD5FD26B
-:10DDC000707550CF098CC3ECE952FF28E1F9B2C657
-:10DDD000EB84F7DE90DC5B008F73FBF4B85E93C0DE
-:10DDE00081CC5B86017EAEAD32ACA3CD29E877B5A0
-:10DDF0007A5D2B4E2A84BCE92DC2F22D6F0996EF75
-:10DE0000784BB13CE67563F9BEB71CCB0FBD3558F6
-:10DE1000FEBB7715966D5E1F9627BC75589EF4D68F
-:10DE20006379CADB80E519AF1FCBB3DE462CCF790F
-:10DE30009BB06CF73663A9DACF9EE4EF0C5F5FCF3F
-:10DE4000821C1AC3E5ECE0DA796BEAFA06E5ECB07D
-:10DE50005C8672A6D2B7B8C1C8E521559087BFC20B
-:10DE60003A9C02F2D2437B83C2E530DAFB91DB417C
-:10DE7000DE7AFF08F246C81A94030BC8DDF7903724
-:10DE800002A70829204F7D34F224CAA12A47AA9E5E
-:10DE9000BF21959C03F952E5CA22337F4895ABFB1D
-:10DEA000C14F8CE06FF55624BEFE31FF88047275B9
-:10DEB00040B2E5FCBC82F85C58EFE263D75270AD2B
-:10DEC000D04FF60F8175A46BC8578321BEDF758CC8
-:10DED0000A4156F4F969E5253ADD5DB87F28F35328
-:10DEE000E6F70A6F37C731BA9A75A4888C84F3E5D0
-:10DEF0009C636ECACFB83F5D3D12F6CDF4B94C922B
-:10DF0000008EDF393DC27901194490CE3DD157EDE5
-:10DF10007FEA89FFCC81737F0BE8399D7BDC017D33
-:10DF20000DD3DFA79CB7849C2F798CCE7488837720
-:10DF3000661BECCC7F9824D2914CC2F303958E07DC
-:10DF4000B2BF180CE733F7513904FDEA1A343881AF
-:10DF50005C463E7AB2F73DD17301CC37267A1A0877
-:10DF60009C73517A6E85FB8EB1D2B3273BD9937DDA
-:10DF70003CB181D1F908F74FA3D1593D0FD3E271DC
-:10DF80008B22733E7039267768E85F2AD0BFAFD501
-:10DF900081FD0FEEFD2013CEF1BA765F91408686AB
-:10DFA000BE5FC0CE7BBADFCF17F440FAD3DF336158
-:10DFB0007F7CF08577B15C4B981E6EB494CC55C6CF
-:10DFC00004E1C57A8F20DABC3C8A24CEAB07FDEC95
-:10DFD0004855F5B33513E46937B70361F3EB413EB8
-:10DFE000D5F91D80F951385341A6E93CF2E592BBC1
-:10DFF00084F98D4EC179F7343F4F82814823287EC2
-:10E0000056838124507954DC6B15DCD739DB7C10C6
-:10E01000A7D81BEFACA52CF1D8CEBE1170C07B6287
-:10E020003C6359A3B946F49F126B44FF29A326D43D
-:10E030007FEA3AFC94CD4DF15B9EAEAF39D90BD659
-:10E0400039175FE7D8BAAAE257D594556311E0882B
-:10E05000F5AE7AA988DDC37124CC8C70DEA796CB8F
-:10E06000D30D38CED9C6810930EE59AFA986ADAFF0
-:10E07000F61A366E7A4DE8FA5AB92ABEE6E4A820B6
-:10E080007ED1E0FED0F85189201F99605DA46D0318
-:10E09000A3F78FCA4FF973039EABB7285F80FF6E5B
-:10E0A0001EA2FAEF32D655B89E26BDCF38029EEF9B
-:10E0B00014C6A3EF39D4B371782FBADCC8E494CA7C
-:10E0C0004F3D9C7711BE3F30219FDD14620285D702
-:10E0D000215BEA40AEFC0AD3670F97D32A539BC15A
-:10E0E000ED4072B7825C2F18ABCAB963D607D44E25
-:10E0F0007FFC1705EF9991AF29F49CE0558745A463
-:10E10000C40641D505BB9715C3BAFDF18B37F17D28
-:10E110007A7D0ECCFB3CD115815D3A4FDEB48D0A81
-:10E12000D1D7D30A8B63913AB6CFF1D13F30BFC577
-:10E13000F5E2BE674983582F233352C1DE966D54F2
-:10E14000889FE2BE14F64DEABCA9FD7D57B123724B
-:10E150004B48CD3AD8A73FA6B078CF023B91FB50B1
-:10E160007B5DF5875FE740DCA75D61FEAE7A1EBE92
-:10E170003489ED072B66FA0D2EDAFFA3DDA36EA31B
-:10E180001697BEEF5F87FECF74E2DC4EC2E9BEB0E9
-:10E190004EC4AF27FCB5F8AA7E50D8B93CC723B906
-:10E1A000518A785FEA6B6EE754FD4832D885B84FE4
-:10E1B0009AA6AECA81C2E5C0AFB8AD8614C677E0F4
-:10E1C000A324771ADC21FD0CC17E498631D1FB19CD
-:10E1D000A19F1EFBA5B17E9D85B83F26549E860655
-:10E1E000FB9983F0FAB271C57E557F78F6451F958D
-:10E1F000978ADF3D6A2374DDFC58AE4F75D2E795F0
-:10E20000DBEFB5B9687946F6D9809F1FFBF511EFB2
-:10E21000FBDE6250E9E1B248104FE3F249EA7C18B4
-:10E22000A7F862BB62C773844663C048E5B37AF758
-:10E23000D262321CEBC7597DFDA77AA8378BFCAAA6
-:10E24000F8CDA3A90E764F88C5934800FDDCEA6D92
-:10E25000FF5108EB858774A29C69DF83F12F26A10B
-:10E260005ECF372484B7E3C5E054789FFD7876DF2E
-:10E27000FFA9DE06E5E4D3A0471E8D9C9473BF156D
-:10E28000E805FBFD7C833519EDFDB5E45AD07795A3
-:10E290002EC4CFFCD7DA1D8F0F3F4EF13AB7ED2FCA
-:10E2A000366968A89D60F2D6D5B4F0DF4CBAE8F6BE
-:10E2B000A49DCA63A89F4401E37B8E66EE77B7B046
-:10E2C000B25209D8E03E4EE516C5492591543EAB01
-:10E2D00027703F81BC67F4437C74D9B3AFBC339ED5
-:10E2E000D27FD92E25B9984DC722A506F9E3A17F83
-:10E2F000578D0CF2A3E2F7AF181CC3D8F37B9282C0
-:10E300007C59B66B9F810C0BA7E3A4A67D86364B88
-:10E3100004FE341D2F84F5B676C73F0C1057FC78E9
-:10E32000AF44D2B2C2DF2FDFF20AAE7B4027E42730
-:10E33000E75737FFC2F81698F6F268EC67077BD804
-:10E3400013DFB2613F9782F2FDDCCB708FE97DA3D2
-:10E3500013E850FEDC0A1BCCE7B45CC3E4FCD7F73F
-:10E36000A682BE972BBE543B96EC79F9933F47F9B2
-:10E370005B72F4E7A9E83F1057860E6DB32F03E6F2
-:10E38000B978F3AD38CF32E246392CFFB5BE04EE92
-:10E39000995E9049D1AE087AF21703DBBF9CDE4A42
-:10E3A000994BE7791AF003FBF6A6DEBF1DE3E63FC3
-:10E3B000C37B703FE773A62B21D62F9818BFB618E2
-:10E3C000746A3CD424C8EFB6F5ADC0A7B3FD5C6950
-:10E3D00070EE41E9E0E374932E51B8FAA305698C1D
-:10E3E0004FC421E7F0F7A8BD9F04CFA17FABE23275
-:10E3F0000F17DEE3F6918DBF928F4FF18E83F5EB11
-:10E40000746A64FFEF1F7C7EF4A79584C85988BEA8
-:10E4100033FDDF761FD37755FFFDD38BA0FDF3B718
-:10E42000981EC17BB05E50BC0269D8BE6FA684F650
-:10E4300081EEB323E9F93685EBB9D84E7738B8FECB
-:10E44000AB7242F197A5845079A1E324211F707F1C
-:10E450005CB691BE1FE29779605CEC67083E0F598D
-:10E46000379670BB7048630FC8E69498FCE84AC5BD
-:10E47000FFF413A0BFEF199D3E07E8AF5202F3FF70
-:10E4800064E78177E65039FFA449D55BD1AE6AF5E0
-:10E49000B6FCF9312492DE7E62A1FBAE487A4B9F36
-:10E4A00047D45B4B1BCAF3FF2DBBAAD2AF5D433FE2
-:10E4B000B08F2F3BA2D3516B1F37181C11ED23FDDA
-:10E4C000798BE484CBA12A7FAADC55FCB6AA3FD87D
-:10E4D000A16EF954E5AF5B3E55F9D3CE57A49FB674
-:10E4E000FD0FA0DF14AFDB4D9BA681FF6CEA241863
-:10E4F00087CF9DA9C77B9AA6CF09BBA771473CD6FA
-:10E5000067E9DB7E0F3EE10755B386C13A7F3BF1F9
-:10E5100029ECDCBE5E413FF6EB4B9726D0F9CCE10F
-:10E52000F4BD9D927B2AE547A92C05E2289EB365A0
-:10E53000E24B488278B2444E84E0717BB958879FA1
-:10E5400089A941383DF5FFB67EF7772D8F52BE9EE3
-:10E55000C826E46F50E2FE833AD621F234BD859D91
-:10E560006378464BFE01A8876D7249C83EC263645A
-:10E57000F6E768FE2D63807EB9B3862530391F8C9F
-:10E58000FB450FB7635D3E4702D8F7AE9681B82FC3
-:10E59000EC3ABCD0EA8E60CF0E70397B859FC37495
-:10E5A00058A47A3D95FB0ED2897E8DCF628E189746
-:10E5B0009B6354ED34E71BFDD1D3F14BB91CCEA6C0
-:10E5C000AF268C0CE1DBCCA91FCBB6703EC0CF8947
-:10E5D000907DC5F7A52FC835D0F780B9ADB02442DE
-:10E5E000FCA692D36FE2FE2F0DB0EEE5B7E4CA4071
-:10E5F000C77C8B5E88872C32727D1D4A86025E1333
-:10E60000F72F7D600C9563CF61BDD34CE7E769F9C7
-:10E61000D4E08EB0BFD3D213E0837FB9D5C8FCE578
-:10E62000B79592C540D7B76F65E7BD7F3338AB224A
-:10E63000E1996E66FEE66C527261B4F4D3A36FEE9C
-:10E640002C6B208FD2A3CBC2EE6B87CB1FD3FB2EBC
-:10E65000BBE45F2D811CEA593D99DD6F2E24EE0746
-:10E660002648A8EF3784DAAFDCE6E9CFC27D9AEA24
-:10E6700016C9AEA3EDD5729B01E4D8D3BC4B06BF3F
-:10E68000FD260771E1FE5AAE19363324FE45973D4B
-:10E69000A4D781AFE6CC05FA7E36D348002FD7D079
-:10E6A0004F6DB0FE7FD6320AF520DABC5EF7926974
-:10E6B000F90AC061F64C2B0F85C9F142FDD649A479
-:10E6C0002F9C034F34B6AD7046E05FBE89C959CC6C
-:10E6D000F6CDF4FF997D9B40ED1B936B25D4BE597D
-:10E6E0004C61F62D2D927D5BBEDA910672B17CCF26
-:10E6F00040FC7E6BF96B8B5322D9B757F9BEF735C7
-:10E700007E0FBCA32FB56F2342EC5B5F6ADF22C490
-:10E71000C9BF88D5BE99FE67F4EF55B06F11E66B9F
-:10E720003689F6ADA86535DAB7A2BE7AE1BE1231F8
-:10E7300051FB167F39FB36FFD15BB1AE38E323C8FE
-:10E740000FD015ECDB6BDCCEC13860E76E30B1F872
-:10E7500066AC76AE5FAC76EE7F88CEAA9D5BDE4F70
-:10E7600042FF255C0E999D5B9EC5ECDCF23DCCCE54
-:10E770002DCF66764E6BDFF2C2EC1B7BBF7A087D35
-:10E780001FF78F598FDF01F7094B15A789F62F76F1
-:10E79000A8DF4FD48C09B577379864A47398BD73FC
-:10E7A0007E8ADFC1F464EFFE0AF62E1BEDD820D07E
-:10E7B00023AD7C4C19142FDC677BFBCB53BFFD1DB5
-:10E7C000E8CBEB7ABC2FF4AE8EED8FF67E796A142F
-:10E7D000E8DD4326667F9798183FDBBD3EB4A793DC
-:10E7E00086327DAFBA87D1AF7AB7C4E6BB52EF7736
-:10E7F000C03AF0D545DC3FCFDDC3F6CFB38CAD29B1
-:10E80000F1702FE95F14C2BEFB20C5F343E4A1F40D
-:10E810006205C6019F8FB36D85FD65A94C4CE0C7AD
-:10E82000CE3B3CE563F05FE75DAC43BF771E3C87C2
-:10E8300073127E4F42BD4731A779D72B7D48F8FD33
-:10E84000888946C687892B24FF962CB88F20B6CF9F
-:10E85000D3F8F5EBF83CA93F8B74217FD5478CDFCB
-:10E86000ADD3D2C3C9E65FB5522FD2A3468A480FB3
-:10E87000CAD1E2F9A9C1F9CF7DA16D5D1F685F2AF8
-:10E88000E17E4AA587769E2A7DD4FDCA3CAE239EB2
-:10E89000965D0AF04B3B7F957E61F356E9A9997F1F
-:10E8A0009D6A3FAE26C340DFDED5B91F1803F2F1E3
-:10E8B000674A078AD76DB3B3D342EDF183DC2E4D9F
-:10E8C000751FCF4F7500DDD8778973CA77BD924A1F
-:10E8D000E773B32B6B247C3F7CEB570637C4170ED2
-:10E8E000983BD1BEA9F2F50997F70087F3766F7BC5
-:10E8F0003EAE23CD921DF526A0B15FFCFE98E71E2B
-:10E90000A65707A47FACEB331AE90ACB002954D7EA
-:10E9100021E003FDEFD416C6070FF081FE771AE958
-:10E920003C0474AE4E969C01E8DFBCEB5E909B57B6
-:10E93000CDF439E86FB9E464DF97114B46EA65E539
-:10E94000538E249F189CC809AE8BF3A05F52B8DF8A
-:10E9500031D1D8FA36E03191EAC31612EE87A87C9D
-:10E960001F42FF5C8A74EFA70739FE98CBE7AB40E4
-:10E970006F0BD0B5D300FE8C27C0D60FB5DD233B7F
-:10E98000F2913E2ABD9BE9FA309AD15B17819E37FE
-:10E99000AB754E4F4F8BA4C0FB93E9FEB59704A710
-:10E9A0005B5F1E52E518BE87D3D203E20119217ABC
-:10E9B0000FF629F47CB2BAF928D265CA4AEA5E8514
-:10E9C000D01DECD6E5E8134D2FAA9B7F18BDF84467
-:10E9D000A3177BCD9D7F1901F1AF3D12DA07D292CB
-:10E9E00028ECF7E3CDCCCF386076A3FC76BEA6E06A
-:10E9F000FD73AD1DF99ACB3DEC2F42BFFB9B041379
-:10EA0000013B6737938F543C0630390AB5DFAF9A24
-:10EA1000DDC8AF68F0E3F83A1CCD7F52EB37C2781F
-:10EA2000701FD1218E17E65FF0F84F4FF34AE3E3F2
-:10EA30007ED779759F6792560361F1FF15C6907373
-:10EA4000A9DBF8B940779C2CD8CF6EBA4C3F88BF71
-:10EA500004E8BC5FDDF914C67FCF3F737C1AC8EFB2
-:10EA6000B23FEA8989F2B97DA79504D8BD0B03AC02
-:10EA7000B315BBF511CF5108A965DF39FECE8AF673
-:10EA8000A5E279A3BF98BE5FF1E247C3216ED5BE70
-:10EA900086D919DF335C3E7C6DC3E17CBD4266E7FD
-:10EAA000C25A78D7717939F7527C29D849A9917D12
-:10EAB000BF5AD1344B3186ECD3479A151C97F6C315
-:10EAC0007BCBBE1D12C6CBC3F15BCDE0ED60F6AFD4
-:10EAD000A259F1C377B0158D5B707FEB69FCD40050
-:10EAE0007EDDA4DF3DCBBEAF6DD68BF1C3467DC0CE
-:10EAF00088714EFD71E370A6B792108FAA42BDAC2B
-:10EB00006EE271324DFC68D9EFF6BCE8A3A459F669
-:10EB1000FBDFD8C0DE9C6DDD6EC3F85C238BBFC904
-:10EB20001639727CAEA7B85CD37D3C2E37F534190C
-:10EB30001E1E973B0BFFA17A38DFCCF5558D6B3647
-:10EB4000F68AE9FC7CD9B3179E84F3A473CF7FF2D5
-:10EB500024E05FF9CD674FDE0DE7127BCD7658FFDD
-:10EB60003CCFBC8DF177F5BDBBB99CB7EFF8CDD3E9
-:10EB70004F503D6C7FCF88F7B6DAF79CCE84EF1903
-:10EB8000DB777D990AF1CD957B0A703FB3F2854919
-:10EB90006997BB7F02F2E98FE1FC44CB8F03BBF5A1
-:10EBA00004BEE73C7FCC88FE47779CB5A98AC5AFF9
-:10EBB0001D3CBEBA33F279951A0FACDE7DCBCDD7B2
-:10EBC000C33AB85B713AF0398F0FF614577D8BF268
-:10EBD00075440CFCDBC9E3E74D5323C655CFC37F17
-:10EBE000289F3699C5B8EA85DD8BFFED0968DBDD26
-:10EBF0002B6A5C351003DDD4F3B032B36B9B19F490
-:10EC0000E3F9DF621C1BF8467D72D2FEEC854C886E
-:10EC1000479C513AEFC47BCA7B8C78CFA862CFBBAC
-:10EC2000A82FED2F1CC57326C2CFA3DA49F70F3BDF
-:10EC300037E07B1DCF362B8BC772FA43BCD661C33E
-:10EC4000E73C2ECBE4588DD7468BD3BE6F66F7A139
-:10EC5000D4F3B9AA6D1F188826FE2D8D057E1D17C9
-:10EC6000CE15D5796BE1D9810ED7869E3F448B872F
-:10EC700073BB1AC62F76EED0BE859F47749F3310A4
-:10EC8000D277249C8FB373738F5F7A37127FD5F35B
-:10EC900087B7B5FAE98FEDDCA167BCBF1B5D5E35B8
-:10ECA000B3FDAD4A9F735F47B6D39D5CDFE93AD3AE
-:10ECB00061C67363B6CECCE3EB4C35A51BFBEE8D82
-:10ECC000E17B8EEF03CF3DA3F7C37E795DD301B423
-:10ECD000B75A3DAF262CFEA51D4F8A63FE4175F342
-:10ECE000BEE1608FCEED7F09E5AF7AE771838FC219
-:10ECF00039D4F87B43DBD0A0BC831DF787D8F173F0
-:10ED0000CFED1BCECE4522E769B171F89E1611BE3C
-:10ED100067E7A702FC65BE2683DDD2F3386765D7B7
-:10ED20002C98EFD95685C07DF6B34DFA227F8471B9
-:10ED30003F83756C4C904EEBACEC3B3E7D9201FDFD
-:10ED4000CC95D6B1C7E0FBF195568303F6DBB5ABA6
-:10ED5000D9BDCADAFFE54C07BED426DE86E746F504
-:10ED60001A3ADA93EDB9B00FB7E7978C06B1D2DA59
-:10ED70008344974EC07BA5B528CD6181BC5ECC4F46
-:10ED800021B213BF33D4DB0A8B601E7ABBCE6E8EEA
-:10ED9000B8BE32788A85E5CD50ECE2777FDF210F6F
-:10EDA00006817C1CDF3A0F46A7260F46F98DFFAF80
-:10EDB000E5C1F0C1383F813C18018CEFA879309251
-:10EDC0007FE43C18105F1A1D9207A353930783F347
-:10EDD000F19F7930FE9907034A350FC63B1BCA0ADB
-:10EDE000204F859A07E3CC064F01E4A550F3607CE1
-:10EDF000B56115ABF33C1896FB571784E6C1C8BC48
-:10EE00007F03B6AB79309CF73F52109A0723EFFE91
-:10EE1000CD05A1793066DEBFBD20340F46D9FDCFC8
-:10EE200015087930D6FEA100F260BC1EEF6E8D4B46
-:10EE3000899E07A339CE11531E0C0AE73D84132582
-:10EE40000F86164EB43C1814CE89B831D1F36084C5
-:10EE5000E113250F0685F309C2899207230C9F2829
-:10EE60007930289CCF715E51F26068E144CB8341D8
-:10EE7000E1FC17C2899207430B275A1E0C0AC710E0
-:10EE80009F123D0F46183E51F26050380908274A3C
-:10EE90001E8C307CA2E4C1A070D2114E943C185A52
-:10EEA00038D1F26050385908274A1E0C2D9C6879D9
-:10EEB00030289CABE2C744CF8311864F943C181492
-:10EEC000CE28C4274A1E8C307CA2E4C1A070262024
-:10EED0009C287930B470A2E5C1A0700A705E51F22E
-:10EEE0006068E144CB8341E14C437CA2E4C108C3A8
-:10EEF000274A1E0C0A6716E213250F46183E51F2E8
-:10EF00006050386EC4274A1E0C2D9C687930289CAE
-:10EF1000A508274A1E0C2D9C687930289CE50827F7
-:10EF20004A1E8C307CA2E4C1A070EE463851F260DB
-:10EF300084E1F35DF360980383A481980703F37180
-:10EF400076E7C148FED679307E05F8FE330FC63F1E
-:10EF5000F360FC1879306EB5BAFF1E8FFBC6EF96D2
-:10EF600007E34CBC266F440F79306EB5969C05794B
-:10EF7000FEB679302EC47FBB3C18749C7F5C6E9CBF
-:10EF800068793074966F9707838E235BC65C663E04
-:10EF900051F2602458C4FC213F561E8C63F149385D
-:10EFA0009F6879307E72F926E8360BF669D35114E2
-:10EFB000C94F26FFC4680B8F1BFE50F92760D2395A
-:10EFC0003FA5FC136A1E832605D6C3F739DFDFE1B0
-:10EFD00072F101CF43712C6A1E0AFF548CEF2E157B
-:10EFE000F3504CE17C9CED16E5610A61E72853F291
-:10EFF000B3FCB5B05F2FD7E4A118229ED317BB8F07
-:10F00000E6537064AA539CC7512E0FD34A3F3D0864
-:10F01000ECB9796CE43C1433383FA66BE83285F3E5
-:10F020006D3A2F6F874F73A83C17971F9581AED30A
-:10F030001C6D32C6E96F52F9E710F83793C3D5E279
-:10F040003B83F36FC664C63F2DDE6F01FF28DE6F82
-:10F05000958F42FE69F1D6E2A9E53F09E57748FEC2
-:10F06000905C22E69F986412F34F14D8C5FC1337C6
-:10F07000A68BF927263BC4FC13370D11F34F4C75B3
-:10F080008AF9276E1E2BE69F98EE5AADC97F719FB5
-:10F0900026FFC5439AFC179B34F92FB668F25FEC44
-:10F0A000D0E4BFD8A5C97FF19226FFC53EA1BEB06E
-:10F0B000EE35A1FFE2FAA3427D49C37B42FFA5FEE4
-:10F0C000E342FBB2C68F85F6AAA64F85BAA7F94BD5
-:10F0D000A17F4FF907DEE2DF43BFC3BF873EC6BF54
-:10F0E000877EBF87FC17EF5896AE0BCD7FF1BEC56C
-:10F0F000B30EF2121CB738785E81C8F92DBADBA3C3
-:10F10000E4BF08BEFFEDF35FA424FFF0F9087456D6
-:10F11000F63D606F4B9ECE9AF2DDF311DC5A227EF3
-:10F12000D73DAB54FCAE5B6765DF6BCF768BDF778B
-:10F13000DF5E2E7EDF3D22CE2D011EDAFC17BD2DB7
-:10F140002E9D15EC25CF531080EF74B321DE56842D
-:10F15000E541C87F910DF1B6522C0F43FE0B5AFECC
-:10F1600019F25FD0F208E4BFA0E51B90FF221BF26A
-:10F1700067F878FE8C3A9E3FA39EE7CF68E0F933AC
-:10F18000FC3C7F4623CF9FD1C4F36734F3FC1901C5
-:10F190008473C27B18CB93DE562C4F798F6179C66E
-:10F1A000DB86E559EF192CCF793BB16CF75EC432A1
-:10F1B000D6FC19AA5C7E087EC315303E9367554E77
-:10F1C000AF7EE09175A1F933463CB009E5345ADED3
-:10F1D0008C1CF8A62F257ADE8CEEF628793382EF88
-:10F1E00047CF9B9136FAC7CB9B31D7F2C3E4CD987A
-:10F1F0005B23E67598B7EAF2793346C495DC82F270
-:10F20000C7E571AE25B6BC193EABC4BFCBA7740130
-:10F21000BF8BD205D7EB1EF20E1CB43E3D04F61395
-:10F220005D43AEBA6CBE07AD5C44A737CBEF30E7A9
-:10F2300047CE97D1135DD5FEEF57B03C0E732DDF4F
-:10F24000325F460FF9160E667F817632D67C193D05
-:10F25000AD0F3DD173C68F9C2FA327BBDA933D7DA5
-:10F26000730AA373EF1EE8AC7E2F5D696A3D842F9D
-:10F27000DB5DA8DA32FF1E3E77A61DE3331D3BF9A6
-:10F28000BD381771D853D9F7FAE06F763C9F309CA0
-:10F29000E077FC76E2A2FC89E7CFA59DFBF6C1BD35
-:10F2A00080B536E24A4C02678F38F403611F768DD1
-:10F2B00009E23555BB3F7DE38F14AEB9458FF7E5C5
-:10F2C0003A280EADE8F7B912816FF1E497B84F878D
-:10F2D00033BA4BBD42BFEBD6FC1E0EE8921A3C7F00
-:10F2E0002AD05B70DFD4B599DD67D593AB1E9F90B4
-:10F2F0008CF7C689DF81FC433F7519C7B38B106754
-:10F3000000FAEFB4E2FDD525AF2D34C0A070DE1AAF
-:10F310001A37E85524C6811ACCB6E1706F2F5DBD4F
-:10F32000BFE773B5821FBE88C34D2911E3449F2CEC
-:10F33000283A0CFEF3227719DEAB482B15E34684FE
-:10F340007F470FDB32F03365C2EF75FAD97DCFB05E
-:10F35000EFEA9BB7209E4BFD9AFB4B8D625DA5DBD0
-:10F36000392BBF9762219698E8D636F8F109A3BFEA
-:10F370003DDD8CE922DDCC0E916EF14344BA68E9A3
-:10F3800066758A74D1D22D61AC185F53E9A6DEA7E9
-:10F39000FCA1E89664E3F73C82F42A31A5A2C947B0
-:10F3A0003C33E400CAB7561FFA5802F01B7E48BF30
-:10F3B00064FF6A7CCB6995C16EA533D0445AC4DE24
-:10F3C0008B077D80FCBDC489FAA0FE3E8A78F221BD
-:10F3D00097FB8FC8255AAE987EF0F802DABA19E486
-:10F3E0006D04FB3D1A18AF4A22B89F5388D30EFB19
-:10F3F000A826AFC9B94881734DE25C940DE79976B0
-:10F400002C1FE4DF3B770C25B8EF6F0A7C9E0AF7D0
-:10F41000061E1CD9390DE20F9EC5A404D6AF5909AA
-:10F420006C7D5DC64B5B028BCF6C28D111D768F821
-:10F430007D4A7ABF44C76BB7BB5EBB01FCD1167671
-:10F440003F80D83BDFB81DDB47E1F7E119BAFA6B23
-:10F45000001FDA1FBF2BEE68F9C8B630C40EB737ED
-:10F460003F7225DC6BDDA48BFC3D73818DFFFE1D9F
-:10F470007E3F654430DF42816D0CE6657870001D8B
-:10F48000A77A7A17F25195CBEB38FD0F964D41FCD8
-:10F490005E68911C10AF2BD4DF71D3308ADFB8B710
-:10F4A000657EAF97DD5F1FCDFBD79AA9FEA2FDAAAF
-:10F4B000FF1BFC9E95974ECA980F71744D19DE1371
-:10F4C000FCA3ADF030F02BC7D5340AE429BF2511D9
-:10F4D000CF713D1F12277E9AD52ADE07CCE1F7B601
-:10F4E00073DA881F84E2DA6362FBB836B17E9D6608
-:10F4F000FF39DFC6F5D4465241EE367EAD9760FD4A
-:10F50000E8E824CE3514DF8E45BD71FC8ECF09FAB4
-:10F51000891D5FEB8B22DD8F596E63FCDB642068F5
-:10F52000BF379559F0DEF9FEB28AFEE05F7C719735
-:10F53000BB7FA43865889F96C0BEBB772590B1205D
-:10F54000876B2546EFFA8C9208EB962A77AA1CAABD
-:10F55000F2975116E78E740FF5339B8472965736E7
-:10F56000443280FCEC9530FCD5BE86E2759975DBA3
-:10F5700047D6F4017C3CCD9FE17D32538BE48A7405
-:10F580004FE7619B8DDD6F5CE35B0DF7467E419538
-:10F5900008EC5486A13E2B127C1FD9887EE95D368B
-:10F5A000077BCFC4F320C9F519709FA2BD79D2E4BF
-:10F5B0007514CF27A83EC07AB5497122DEBE2A4213
-:10F5C000F09E2C8FD7F59D46B66C08F17F37DB7225
-:10F5D0001B6D145EA38D7D6FD9CBED94006FE77F1B
-:10F5E000FDC306F03B2E1A917FBDB9BFA9BE77803F
-:10F5F000D3675C826B2BBC4FE0979F51E3E374DBD6
-:10F600009C8B46415C9ED23BC40E06F9E663F951E1
-:10F61000DC04CF3F922C3A9443E27239ECC27D76FF
-:10F620001FEA8DAA07242011C853A0DA37A9450A7A
-:10F6300058A9DC8F365902708F2EA99CCE3B19F247
-:10F640009A9818BC56F99C18D7A2F29803CE3DC1DF
-:10F65000ABF3104805F8AADD53EDE5DA44668FD622
-:10F660003E24635ED4CD729B19E2A9592E471EA495
-:10F67000884C921D78AFA65F3971520C49FCC05F6F
-:10F680002776FB0154C9AFF9463F2FD2775B176D40
-:10F69000CCDF1E97E0FE33D06BF8E1CEFDE02E38D4
-:10F6A000CDA417BBFFC5ED04F76B0AF97A37EE3F1F
-:10F6B00074EC7BD1C00D24F43B2AAD9DD86466EB7D
-:10F6C000FCB8EBD9BA37EEBC05D7BD6E3B515688B6
-:10F6D000EBD4C8965107E09EC5C80F997E126E1FE5
-:10F6E000ECF40FD029E7B04F0FF4F9B67641CB6FA9
-:10F6F000123075D787EAE01C86EA5BC8FB6735766F
-:10F7000064C5F441B5185EE672D4FF1EA7DE1D4243
-:10F7100047EDFBDD714AC9D4FDDC3110ECC8113D69
-:10F72000DC0BE9C8A5F3A3F3DFC8F525F173FF648B
-:10F7300098D7C6961BCD20DF6B0379F662FA4EA2EE
-:10F74000A9049997485C18CF19493D32C88F518B4D
-:10F750004241FD41A58424A4C03DB42221DE432CB6
-:10F76000493CFF4B00F9D22DA7548E43EFE5AAF296
-:10F77000A99547557E6BE1A005CE0721624E4BBD92
-:10F78000D484878146B2D90EEBBBEA5FD6727FAED6
-:10F79000D69CE9C7EF977C19E81FADE4FE51ADA5F3
-:10F7A000D084E6605F32AEEB2B217E42E9B0328539
-:10F7B000D979753E5AB9F45CD4137FC83EC123771A
-:10F7C000E27D44CF45033E5FA7B807C0FC55FA5C15
-:10F7D000C3E9A3A58794C0F79D9C2E3DE39B638757
-:10F7E0007BC1892617598FF8E6E13DEEA6C0481384
-:10F7F000ACBFF76AF08D01CF6B13C684E3295BA21F
-:10F80000E099CCF0BC8EB8FFD846E53767455D6D12
-:10F810003CEA15792B3D275CAFB47AA4EA8D1AE750
-:10F82000BDB6B2FE005EBBED416F3CF18C2E4EA525
-:10F8300004EF5739F7C4A31DD1EAD3E77CFE9E78C5
-:10F8400046BF058A7B06CCCFA3EBCC043919EE204A
-:10F85000BD8A2992C39BF5A8E7A435B67BF8AA7F99
-:10F86000A5FA55DA7EAA5FA5DA63F51EFCDA04F77D
-:10F870007C9003A999CA2DC5A7D6CEF64B9B6DEEF9
-:10F880004580573CC53D0EF68D430259ECFB5F5158
-:10F890002FA2E941BC46CE9B0232AE0B3EBA2E648B
-:10F8A0004BE178A8E30F4A48647CA45A0EEB7DDF55
-:10F8B0001CC206AB269837A7EF70E28675ABEF48FF
-:10F8C000769F714D02B3BFB5096CDD52CBCDB692B8
-:10F8D000BB51BF65E2338EFCEE7803AA70DF7C6D0E
-:10F8E00082EB2EA087A9C885F3E863274EF04BFB77
-:10F8F000C84D127C379A54E990D83D7312FC7E8B28
-:10F90000C2EB53ECC8057DED03FB6BE8DF1239CF8A
-:10F91000D8A309EAFD5EE67F3A49771EAF47139800
-:10F92000FF7908529FF42A56F382A9E7394E09E875
-:10F93000D46EBD0D916EBF20313F3D91D14BBB4F79
-:10F9400000C287FEFEBD7B0D44362791E0EF59D5FE
-:10F9500099D0BF8F27CE26B057BB1206F0734C67E5
-:10F960001DD47F25779A128706E55D95E30727CC9E
-:10F9700070422A52DBF55DC3614F45E57A27D0BF5F
-:10F980007D42D760CC41493A3399FCB8F442BE205D
-:10F99000950FCD8AC00733ECC343EDA4D53004FCEA
-:10F9A000D17629CE09F72CDA974A0C5FC9C4F3291E
-:10F9B000C9C23CD3E3997FDDC1EDD53B0959282766
-:10F9C000AA3DA6F3AB83523B0F8F11EF7490CE3D4F
-:10F9D000F1FEAD706EA5C93FA9CD4F3969A105EF04
-:10F9E0007F6CDC63C6FD6B57093BC7EF6A31A27DB4
-:10F9F0008EA6B7696DE688711CB5A4F47B0BE897F9
-:10FA0000A6D424823D4C9B7BD2067CD7D2A543F260
-:10FA10005D7308F645AF2B11BFBB55CBF4F49B12B9
-:10FA200017D1FEE91993B1549F3758E488F7CD4FA9
-:10FA300073BD52E5F14A3A22DF0F9D06793CEF7E15
-:10FA4000F31D1709DEDF6F8863746C886374EC72D2
-:10FA50008F4F781AE4CD9781FAB0583D07E5FB7FC8
-:10FA600035CF943ADE46AF2951A62AD0B0608A1924
-:10FA7000D68914E29A3C1B9475A342E03BA2C7BC12
-:10FA80003B12F3318E6D12EFF9DAD9BDE1CF3716A3
-:10FA9000E077DEA9648D7930A5475989CE09F183D5
-:10FAA000F30BDEB7E9A83C2DE8D39A03F2FBBAE2E8
-:10FAB00026F63118EAC2FDC99252833F40F996DC1E
-:10FAC000400D05A5CB7F03F4A15473008000000016
-:10FAD0001F8B080000000000000BB57D0B7854D58B
-:10FAE000B5F03E73CE3C92992433794E1EC009E1A5
-:10FAF0009D108724BC1F4E9E448830BC0485EA803C
-:10FB000028CF2488D6DFB6DECBC444F4A2B745E9BB
-:10FB1000AFF4D6DB7FB0A2A8200182069AA41340DE
-:10FB2000E4113408A8A8AD5129620BC908EAC5D66A
-:10FB30007BFDD75A7B9FCCCC4922D8DE4E3EBFED11
-:10FB40003E8FBDD75EEFB5F6DA872EC977134B64CB
-:10FB5000CCB7D8C0B64A8C7D87BF1B43ADD96E6089
-:10FB60002C89B196383BB54EE70CC7D284F07E8520
-:10FB700063693E63D5D6D85C16876D7F3F8B85F170
-:10FB80008A58EAD202685BACAE5A95B12546AFDD21
-:10FB90000ECF774EBA3CA48EE12FD8DF3392B12E30
-:10FBA000236B94E2B01F606C0C4350F8CFED56ED20
-:10FBB000D097F0FFE1FD448B2D20C3B8CCA35CECC3
-:10FBC000B0F047BE1B281E4D66CC285E939ADEF827
-:10FBD00046CA652C7672116370DFCA5C8FB22CB88E
-:10FBE000318CA99E18C6A2D833F6F3D98C19F07DB2
-:10FBF000584757F3BBFD7C00C71FFEE54A0C83FB4B
-:10FC00001F29C118570E63171E3C15E3B6C1F5072F
-:10FC1000E5723FF46F4740C687F0926F870BA319D8
-:10FC20007BC4EE1981EBBA63DD7F8FF1DA42F7D93D
-:10FC300003703195B1157E19E7E6F0C27FABB65976
-:10FC400019B384FA95F509117DC018E1B5D2CCD667
-:10FC5000D4DB7AD26305D203E65DB17D8B295DC525
-:10FC6000F9BD93ECD0BFA0C0AB80EF0B0D317E5F30
-:10FC700066089E25DB4799D2E1D6474D661680750A
-:10FC800030A5DDC86C84B50A09F0E61578D3C379D0
-:10FC9000B8C54AE3DDF57F65BF1996BA18E67A2044
-:10FCA0001E9E6F5A51C1727BAEE3AE3FA8652940DC
-:10FCB000BCBBFE4D623E953FFF601E3CFFC0235F14
-:10FCC00020DDF4EB5CEC337ED211B16E376300CFF4
-:10FCD0003241EF3B1F8DBCBFACE9311A6729F39A63
-:10FCE000909E776DD4DFBFE933E4BB654C095D07B7
-:10FCF0003C5C3E9265453CDC618F493C0F20038FA4
-:10FD00008DFD0EDEDF7D64609C37A7277EB5F6E2B1
-:10FD10003AE06F33637F5E67A1F6C23A46ED08BBF7
-:10FD20004AF459DD74F27EE4AFAAC65D261CA7C56D
-:10FD3000FFA78409F04861D3373232572173DF7B44
-:10FD40000EF0F92326B3EF007FBB19E79FF546CFEE
-:10FD50003D48AF1BAF96D37DFDFA1769FC7F249E0B
-:10FD6000F86711AE3B17AF2B5FF6B6AE9FE2BA80D5
-:10FD70009FD95858977CFDEBD2D6A3AD4FBB5F29D6
-:10FD800003DFF5F2BEC6EF23843E58FADCACF5691A
-:10FD9000808ADAE6CFFA77103FB1D328BF1A3F2D19
-:10FDA0001374D2F38D46C76EFE68FA775A9F463FAA
-:10FDB000E07FA7C1896DC06918D7934FF47CA1E794
-:10FDC000834E63477F945F3D1F744A6C416FEBFA2B
-:10FDD00037FB405AD752D55D6687FB7731CF7A3BE8
-:10FDE000AD67235DBFA06C3CFC3394ABE7385F7715
-:10FDF000EB3933973776DCE847BDB936464D71D8D5
-:10FE000004FD80CE9DBBCC3E7C4E9BE7FC3AB77B8D
-:10FE10009011F15E4EED9FD779DC830687EEDFFD12
-:10FE2000AB2BB12ABCDF358C95A3DC77C644C2BBB3
-:10FE3000CF2E133CFB900EC87F4AFBFF7C803AE933
-:10FE4000B9F631A847CF7FFB5FB11E78BEEB5B737D
-:10FE5000796FEB3C2DE807EAE5B413F8EC762167FF
-:10FE6000B73755125D963C33CB84FCCC1EE0F8B41A
-:10FE7000C01FEAD7B6A8D867711D8B1B24D2237A7E
-:10FE80007ADCE59AFA39EADB3BFD85F47E0FFAB0BD
-:10FE9000C789BE77213D8685E831D6A1727854F8AE
-:10FEA00003BEB943F0CD79658DC9007AE4FC338097
-:10FEB0006F007995C2DCBDE9C1FE0ECE877DAD47EE
-:10FEC000BF8EBEE05FF65CCDFA3486EB1F654AEB71
-:10FED00045EF68EBBF8BB96249EF88F5B28E1B49DD
-:10FEE0005EAB2D7C5E6D9D2B9AEE9C817C51B5198D
-:10FEF000E895D973DDA87717F7026F997CD16881EF
-:10FF0000F7BA1E905CA86FFBA283A627EE12F85AE0
-:10FF1000B96DF10C349A8B613E3913F5D1176FC668
-:10FF200024A25C415FFA1E7A35C91F9B711D8CE3C8
-:10FF30007B09E07B8374FDF45BB6B9D03D28ECB956
-:10FF400015FE9BDC83C2F5998EAE6CDBACD0F364FE
-:10FF5000B7DD26B4C7F10EA1BF845EEE5BBE60E1E3
-:10FF600000E7DA1D0EB26F6C8D83F46375D3165300
-:10FF7000B8DDD5E44B93B7B10E3BF15955E313F41B
-:10FF80001CE85FD501FD4A4BC7CF6F55C3F0394E12
-:10FF9000D051AE30A1FEEE4B7F82BEF9B2236C9DF4
-:10FFA000231CC2AE08FD7B2DFDA0C1AD1F57D3079A
-:10FFB0001ADC1ADF6BEBD1F37D5FF0E9E9C2989FA1
-:10FFC000FB0B3AFAAC427A84F5115E05F0DBD66C95
-:10FFD000F53F04F0B6491C7E5F7314C1DFE92C764F
-:10FFE0009F033FAF2A7521B527F0C554F4EB3CD3EE
-:10FFF000109F9A3FC70A1222FC247DABF93779C2C1
-:020000022000DC
-:100000009FDA1BE5CE0713093F4F02F2C3949A8E85
-:10001000391620D9AD8EEDE50A8C3FE5898E395130
-:10002000D05FE8D8C1FB5B3B4E595C8CD5B057CA5A
-:100030004BA07F3BA013C7BB565B60F62C44F95D19
-:100040000D7E9205ECD1EAD3430EA1DCAD6EAF2854
-:1000500097C0EEAC068323813DAA74C706ACB9D421
-:100060006713E0B9E7EDDE65C42F57EBC86EAD3E10
-:10007000AD70B9399248EB5700F62878AF2E1AFCCC
-:1000800055C0575DBCC5559B49D77D51F1D877AB5D
-:100090006AD8758D1EF81EC25167606E07B4AD47F1
-:1000A00087C4757C8FDD6E5DC72A14E08383EB2CDB
-:1000B000D4EAEF179AEC83D0EE151A98B7377DF98A
-:1000C000A483FB8DC0E4E948E7AA23269277FCA12C
-:1000D0001F5829F4511510280EE0A93CCD02D1B1CA
-:1000E000F85CD9E70AB60D12FB24C25F61A1BEDC41
-:1000F00037DCD7DB56E17883C3F984E3A948912A3A
-:1001000094B0794B6C51117D39C5300CD7C3E4687C
-:10011000D756C0AF9C6E58B31BD62F0F8016F0A1D8
-:10012000D85DF2626837164F9197405B6BE476B505
-:10013000D6C09687E3E905811FADFDC0E1D98A7479
-:10014000BFF456FB182BE9AB0C3BC9B9586FADE4B3
-:100150000A50DCD4CA5C5BE15A9DEC619C8FEB19C0
-:10016000F2F11B621C97D9B047057E6D747C40FC90
-:10017000EB8A33DC9B09FDC0131FF17EBAE14A26EE
-:10018000F0F781273ACA15900757B6E1CA40E81F31
-:100190007AE2637E7F220C0906EAF0139F94FB6CDF
-:1001A000382ED7676CBB3B1BE7510C12C9A972C034
-:1001B000E4AF85FFAD8BE5FC54073C82FCF786B0CD
-:1001C000B3EB6B8A5EB602FF2B456E750D8CE3C7F1
-:1001D0008069F4DFDF6A7894AD068A53B0457CBF4E
-:1001E00029D6ADD18135B8B367A15EA87767CF8E28
-:1001F00041BC7A4F225EF3DBDAA7A03E6E78FBFDAE
-:1002000031E8AF22BD709CFC3688DD603D975EEB27
-:10021000B7450E8B473F7014BEE3003996DCDC9F78
-:1002200094543B5B047257EB66AA09D695A28BEBFC
-:100230001A18D72FCFDB3D7FC4F7584680EC4DA16D
-:10024000C3FB31CEAF8F57597B7CAF7A59AFB74CD8
-:10025000B90FC8E8E7C4A737BEB704F5FBEFCDAECA
-:10026000C12AC2E5660F003C3B0D4C61F1C426C3B8
-:1002700094028C3FA35D1B50EE5DCCE90339C33083
-:100280008D80845FE298B0B855AC07DE2F61D08EC8
-:1002900045F86EA0F5C9C857A3984746FD3586F9BD
-:1002A000ADD87635BFE644BC3D19C5EE40BFCFB2F0
-:1002B0008DB9FD61FA63403CF7F726251809EE6811
-:1002C00063FD6CE4D7E82F981DFDAAAEFF342938F2
-:1002D0003E08C874BCEE3A6C6008E70B46BF3D0EA2
-:1002E000FAC1E18AFA2C0B8DD725E8AD8DFBA44924
-:1002F0001DEE407D93C0FB2F1472FB1CFCDCE47FE1
-:100300003613F16359E30F932F673CF75BBD494503
-:10031000F1F1D0D63747339C7F6C4BB401E9F0F252
-:10032000F6BC28E4879D881B587FBCD97E0F8E17AA
-:100330007F05E0CDA4EB6EC2ABA28E8A03BC4E98C3
-:1003400066533700DE5F88AA9F86FC1FDC6160CFA2
-:10035000C2143B4DAE59D8DF7959B5A3BE7D21B348
-:100360003E9AD6B3C340EBD9191D1CB116E0DE305E
-:100370004C2947F8142B53500F2B8622F51EB83EFC
-:10038000349EDB574D2F2F88E7F2F3A404F3E7E107
-:100390007385243FA5B28DE4AE2BC8FC669827690F
-:1003A0006EBB8CF4889E05AC847CAF046406FD496A
-:1003B0001E46498D4936A35F257DEBB62D06BA4F03
-:1003C00011FA76CA87AB2B78DCE33A3D11C63B685D
-:1003D00033325CD764D621A33F38F92A7305907F66
-:1003E000AEF278C60E7FE83F3DAFF3074BC578EE1F
-:1003F000A0BD042F17B2483FAE7473D9E712CDA346
-:100400002A68A78B2DBAFBE8E7C5621B193795C58B
-:100410000BFFA63FEBFF1DE937E05E98EF3E3B9FE9
-:10042000AF54CEF915AEAFABDCE4423CECB2B9DF71
-:100430009D887AB1DDC8B6B2BEE5E979883FFDE0B6
-:10044000730CBB6A65FE7CE2471BAE67C4E68DBEDB
-:100450002858F788417C7CE43BD42343FF333101A7
-:10046000F5F855A15FB456E333E4277B1CE727FB7F
-:100470000D2139BC333E939ED3E40AF90CC7D96FE2
-:10048000F42FF4F46227813FEF44FEDC65631447E8
-:100490003D966A598072A5CDF3BCE0637DBBBE6614
-:1004A0006DAB11D7FD15D80380BB24EDAA29DC9EC6
-:1004B000EF49E27C552A7F4BFE766793C4D0CF4F3D
-:1004C0006EE2FA3B9C3F527BE78F5F225EAFC51F17
-:1004D0005ABCB0FB87F2C791BF8F3F365C933FBEDB
-:1004E0008D453CDCD75C9CC2BEC7BF6914FCD0D72D
-:1004F000FDF156AEE7F4D75F1178DD67DA383D17C6
-:10050000F5C0CD0617CA39503F7D36AC635F347FE6
-:100510008F296BB2B0BF4BE17A65579399F4CA2E1D
-:100520009BD74B76DC6961E83F30C5DBF133D4877C
-:100530006916754318FF2E8DE7FC566F0C8CFF0C67
-:10054000FDE2A39CCEE36ECE934DF05CEA522EE723
-:1005500005174C5B300E2B4D28DC817C7402751620
-:10056000B4D5E7E029407CD53913E9BBD75A4E967C
-:10057000617E11FC1E37F2D9D8FD27CB8A72F07943
-:10058000AE4FF78A56EB8FC735C5B3EE78D723EC5D
-:10059000C678C6F59207F92437D4676E23C56B1A5F
-:1005A0003FD447033F805CCC67AA3116869C73CE4C
-:1005B000F330984336A73C92CEF303D3283E9C7B7E
-:1005C000BAFD55D0CC6C9E47775FF0C17C1D1F8073
-:1005D0009D3D1E8FFED2F180C980F399D664737F52
-:1005E000684D16F293264FF4033CD5FF61D8B31B38
-:1005F000C2EC7B6C0297A3C75D0ADDF77598FC839C
-:10060000E1D2BF33FE5EBDB03F9FA33C63FC70DF11
-:100610002B0BD18EE62F771F44FC4F4F92E9FA2F18
-:1006200058C09285F47129E497D51BD5E2CFA4D0A8
-:10063000734CF10CB3C1FDFD49D1F9387F6982F7E4
-:1006400022D28929C123F8DED80979F9285FB65169
-:100650007509688F34B801AEF2ADB6101C1A5C672C
-:10066000055F94262CBE88EBC7F750BF347E7CDE36
-:1006700082EF6B74AF6FFE82D33B8CFE48EF10FDB0
-:10068000A53BB0AFE1E12BA157B4FE3F4A7F2D7FE0
-:10069000704DFA637E20F6EFA2BF352129447FF02A
-:1006A000B3E2B1AFF7B3EA4DE077E7F4BC5EE82818
-:1006B000A4E75D265821FA552D1077A23C7A1DB487
-:1006C0002FB0C7CEE7EAFAC3F9FEE022B2C109F1C2
-:1006D00084F76A537008FA21A30212F985A340F047
-:1006E0001791FF95417ACF25F0C4CE4BD2F961DC4A
-:1006F00045FF2E1DFDC34002FA51A3CC1501E4F7BE
-:10070000DDD629E9E8D7E5592765215FBD3AECBE7A
-:10071000E368825E4D5BBEE73935E4FF68FAEDA021
-:1007200018569BBF2081EBA11B41DDA21F882E63C1
-:10073000381C9A3E47F2201C5260BEE13B2BE9E593
-:10074000A60EA0C78D0807E0A155620DA8CF0B0D1E
-:10075000EEC462F4D392020AF7F7BEE98FF9C18AB8
-:10076000A637DE43782B703F04E35097F162773E63
-:1007700062604F3F58F357B4B840F367B4F813FDC5
-:100780001EBC3F405CB79B0140B447018BBF06E6EF
-:100790007FF2B23ADC2DE4568175548875CC64ED55
-:1007A0000417FBF6BBEF26017D66087C541C81B85C
-:1007B0003117EF337633E0E16685C79337BB207E90
-:1007C0000CE3A399E322FBF89B921C1AE75ACFEBA8
-:1007D000EDC044DDFECC3FDA1E017BF409B8CEC784
-:1007E000D6F1B874C240D9A7A0E11C9769407EAC8D
-:1007F00016F60DC2E85EEDD24BC22F9E60E8C875BA
-:10080000017E5BF7FF8DECE081FD7F7B07FDBCF196
-:100810009F2BCC0CEF4FF8BC200EF5041BA7125FEA
-:1008200069E356FFA9C1CAF875E2FF2AB1F6C30011
-:100830008F7B28C267A1F677179FDC84E37D794E12
-:10084000E1BC2DE62F337907611EBBCCC4F30187D1
-:1008500025EEFF68F70F1B016EB8BE2941CB0BB424
-:1008600093DDC79F398CCE37633E202F44D79B2F13
-:10087000947FAEE4F6A40FFEFE37F2015A1E60AB81
-:10088000C01F3B78D6A4025C531BEE51D0BF9EEA3A
-:1008900094993B6CDE9B542B7387E5039E49D0F9FA
-:1008A00023075FDC3403EC49759BEC8A42796DDAEF
-:1008B000753C17FBEDB2CBDA0B1FE9F13BB5E91E36
-:1008C00005F9DF98A8927C5F6BFE0923804F6E408C
-:1008D000BA33F2EB3AC74824477AFA1ED8FFEB84C2
-:1008E0008E9CBEF1DD17FDF574F8DDC522DAEFB997
-:1008F000163DF47CDB02EBF4C1FA02B04E1FF85D4A
-:1009000007D6D9A97F689D93FA1ABF5637FF3601DB
-:10091000FD368D4F4B1338DF8CDFB72981D942F478
-:10092000D2F0F5A1B0577BA3347FC3356F065C3A94
-:1009300005768718D4C7DA9D6342F66BFEE932F27A
-:100940003734FB355F5E544A6A53D82F4C23A35E7D
-:10095000D3DBA9B9EA6223EBCD3E2D88EC97B76DC6
-:100960005462A867203A4992C087F0B33538CE3038
-:100970000FC1A9A7A706971E1E6D7D9A7F3D5FD068
-:100980006FCEA04C23C2DFC3AE8A75E2409887B811
-:100990005EBBFAB58E9FAF5C28792BB717BEED8B87
-:1009A0007FF5F7357D508613E451EB43BFC298982D
-:1009B0004C742BBB6A626EB01B2C238A7D1A66575F
-:1009C00058C550E29F7B851DEE8B7FAAAECACC9B9B
-:1009D0001FE22363E31356E4A37DCA462BE62727D1
-:1009E000DB66D5C6019E4AFE543417FDBCEA0E03F1
-:1009F000C3145669D3170731AEAF7E8FB9502F1687
-:100A000035B51623DF1D52DA658AB3BF64EC893031
-:100A10007FB1B1A9D68AFE5463A24C71FC6107E78D
-:100A20004BEDFE9644AE3F1ACF5D9EE1EEE5FE191A
-:100A300071BFE4E33CE2A3B24741AE310E4D8AA15F
-:100A4000BC4489649F53817EC84D46F2F3218EF9E0
-:100A500023EE035E6A34EFC2D47E69E323F7D881C4
-:100A600010F5FFFD698D19F30BB324D7B3F05C9932
-:100A70001A6CC57ED9DC4CAA7B18FB3F32F9B3C196
-:100A80005B25CA8B9401BB60BF6C51A61FF313FB9F
-:100A900025DEF735F37D0266F725CC8079DEAE489A
-:100AA00018B581784AEB0FCEDBC0042387C557F712
-:100AB000ED9549CFDC572AF971BFA9D49ECE7C6150
-:100AC0007C55F6A889D635BB29A508F9784EB9CC4E
-:100AD000FC61FC1D107EE13C0FC4E161EF1D8EE264
-:100AE00070051703DC52486EA7093E9FC5B89F38B2
-:100AF0007F4142C47BF0C62D688F6E6D8238157AB7
-:100B0000D344FC7AAB373D625E0FE37ECD09162CF1
-:100B10008983F1FB250D24FE9B11B48F0EA8A877C5
-:100B2000CE24A25E63C3B89C6872572AAFAE237E00
-:100B300070F27DB2791248938CFA2F529E668E8B9A
-:100B4000ECCF72F7A83788907FBD5ED7E47E5EB3A6
-:100B50004CFB72F30A2517EB453FE8FDECB1D17D64
-:100B6000E8856FD587E37AD30B1F96FF5D7AE13571
-:100B7000082BC681FCFE3451E8877EAC1FEA875201
-:100B800079FB26E4972EB077E65EF845B3175A3C1A
-:100B90005E06F24AF27E91EF67945E4D65BEFC50B0
-:100BA0003CDEAD2FC09F70F5E2E73C9D984572D4C6
-:100BB000AD5F34FD11E64F18C7FCE3FE4429F89100
-:100BC000A63C842F83E02B633C1F5886854398976F
-:100BD000737E41F9966A88F329DE67BF25B850CF46
-:100BE00049F12139D0FB195A5ED72AF2087ABEE8BA
-:100BF000CEF3CD35521D8CC61765762E1F657365F5
-:100C0000CABBEBF9449B4FCF1F015D5EE69AFC2106
-:100C1000E4EC87F24773A2D8571DC4065D0F5F68E6
-:100C2000FCA0F187DE8E1CD3E567FAB2236FA21D0C
-:100C300019DDB71D797D9891F4B5DE7E68F6E2770F
-:100C4000495C2F6724F27D8E69C3E7D9D0EFB026C7
-:100C5000F13A0DCD0E75E79736737E78BD63892224
-:100C6000A13D41BD9019867F916FD5F8AFEA5189BA
-:100C7000F28D15422F7536F3FC5B7589ECB7C0FF1A
-:100C800016373DB189F78D949F2B545A150B8C3B29
-:100C9000D325B930AFE316F9BA196E89E7EB5C9149
-:100CA000FBF42D3AFACE117C349305EBD01FD7EB31
-:100CB000A53957B95FA0D74F73C4BEFB1CDDBEFB7F
-:100CC000554DDE07B001FF4C7FC09CF4FDFE80F661
-:100CD000BE46478D7E2AEEC5A11C1DFCC6A4C6706B
-:100CE000FF19E937F5AA42E3D893045F0A7FE6CB00
-:100CF0008B79BFA0984F3C5FDDF485C93BB26FF89C
-:100D0000AFE5B7C6A29F3E3AE4B76BF34E53184B1C
-:100D100047C74C674F6689EB3FD47E0CD7AD43A3E2
-:100D200083A6477BE059E8D9BEE8742D3DABE9B313
-:100D30007FB69ED5C6D7EC8036AF5EFFF615B76995
-:100D4000FA74FD1603E54B268BF878B2C8C3CE4F74
-:100D5000E2F1C1AD493CEEECFACA62407BB9B38521
-:100D6000FB272EB3FD38FA05A17C1FA7E7C331CCC2
-:100D700087FBEC4C69B7D0BE67119012F73DD3F8F2
-:100D8000BEE77625E0213DED52580DC8C9397C0FEC
-:100D9000E679F8806F21EAE9873F1962A0FD77259F
-:100DA000D08EFEC9D83C85F68F1C6695F2C19DCDCC
-:100DB000663BBED7B5EFFFB41A719CAF980B43B832
-:100DC00043CDE6EEFD1BD407A5729B8CF9FBAE204C
-:100DD000C8083C3F6941A018E3A0C9ACBD16E57B3B
-:100DE00002D2B117FAFD2A498BB37BCFEF173773C5
-:100DF0003FAE3846263F6E8AAFBD18F7ADA62892A3
-:100E0000AB169FD5E5F75FD1C51FA1FCBEAAF0FACE
-:100E1000435DFEBE91EB99EBCDEB4F40DD067CBC14
-:100E20005EE373A16F581FF9FD9D26BEEF133C6969
-:100E300064E807B30B89BDE663AE95E7DFD712ED33
-:100E40005663719F8EFBEBFB5AD2DC6A6EDFCFE7F5
-:100E500076048BD03CEEDC3E5BA1FA35911FEDB100
-:100E60007FD2C7FE88BBD17E08D5695FFB21C55FF5
-:100E7000AA94F6B95EBC69750B4CD43FDDC8B49F2B
-:100E80009BE474E7F96837F2F9CEF3696E84EB7985
-:100E9000C1A71ADFEF3B77399AF6414D6E15F78FF0
-:100EA000830E8BEB59E25BCEEFF5A943FCB84FFB09
-:100EB0001B21173BA383C7B213C3F73DF83E47CBB3
-:100EC000BA47679F33D27EB984F9486D7FD90772DC
-:100ED00043753DF18CE20F23AB67386FAD9BFD1A74
-:100EE000DB2993D438C4FBE5446D1F538DA33CC468
-:100EF000B757A8CE508FFFDDEB9807EB511AD659A4
-:100F00003C0AC8FFABEBECD46F5CE7A476FF3A95E4
-:100F1000DA878EC73E8076BFDA6DF22861FAE39DEC
-:100F200064EE77E5657F524CC5DF7F6354873EE50D
-:100F3000C10E19F5C58D57611D117527CA65C437D6
-:100F4000E537B342FD4C69710CF66FBC0AFDB0E7A2
-:100F5000AF2439B83DAA53EA462793B4105FFC2D5D
-:100F6000C9DD9104D7EF71783EC176B734FFE02533
-:100F700046FD73BC7FAB7C099ECB0F14525E391FBC
-:100F8000F3CA7934EC42C4DFE85613ED976BF9DD10
-:100F90003C4DFEBE8ECC33E78BBCEEABAC83F2CDCA
-:100FA000051608B40C0817A79F5B9AE794301F98A2
-:100FB000647261BDC3E82C4F3EE6635B9318C5477E
-:100FC000ADADC9196A0E720FCFFBBAB5BC2FFBFECF
-:100FD000BCEF918F627DA4B7AE9A687FFAC8A9581A
-:100FE0005780F60B2DE4FF69F5C82DD1BCCE806586
-:100FF0002CA03CD38DA29ED162F69A93495F050E38
-:101000009E80F77E7F99F17DC7F60F695FBBD83070
-:101010003C05EB7E0F4A43E3B07DEAA3D81C6A4F40
-:10102000C55E44FCB418AC2ACE7B669D5A82756DB1
-:1010300027D6B112AC637B6B9D85DA93EBECD49E23
-:101040005AE7A4F675B88EFC731C9E477E71BF6587
-:10105000A37D92296FD9146CF316C650BBFBB6184A
-:1010600013C2DB12CBB66BF360BD5A203AD080C9F5
-:10107000FED6A7BC8F59FA81DD337B474AA3186B94
-:101080007BCA3B5D990CE34EEDFF93AFE0FE9BC93D
-:10109000CB1EB3005C734FD91ADAA0FF76F2F2C709
-:1010A0006CA86F8F4783D2C3F5AE38EE1E0474432D
-:1010B000A590C605978D837E82D65F31BD6412638D
-:1010C000B71477643360ADECE495D32D80C75BAC87
-:1010D000DE1F63DFE44B9A5ED20FFBCC87F56041E5
-:1010E000C948713FCB9012B1FE65A6C3FB4672584A
-:1010F000FD9E5BFA13ED338D714BCC41871F8CB491
-:10110000EFC5EC1F2784CBDB4C47E91B488F89C90F
-:10111000BC0E78F424C91D5E5FA17F6EF439B5045E
-:10112000E934E642591DB633CB1DD4F72C185B8742
-:10113000F25C62EBEBFD627ABF3C99D78D142952C9
-:10114000445D89FEB97C6026F48F8347A3294F3024
-:10115000FAB4B716EB4F4B9D9979B2A6FAA8EFD81F
-:1011600082FB6DA32BCE9424A0FCD824179A89313E
-:10117000ACA32E01EE17DAB1A00AD7F54431D6FFA1
-:101180008C562517A2ADD0DDDA80EF17BA625C85E8
-:10119000E88F9F564BD0F49C52469D2880E7A60EC0
-:1011A000925D1618E854E0A68997A05F382C8EF25D
-:1011B000BC85CA9A2B27A81FE3AA51711D5B7E5DCF
-:1011C00045E398C9AEEF9E51FC2FC83F459E38CAF3
-:1011D00009023E4AC2EBCA60DD0477A15DF64749C9
-:1011E000C8DFFF5A6287FEEEFE1296CBC37CC3FFB8
-:1011F00042F78F44AB5100E86E93BD04C7DB6D929C
-:10120000EC0F51DF538CCFFB861855CC1F9525462C
-:10121000458C3FB5441A7F0EE1CF891B85D7CA3371
-:101220001C11F7DB6EB3929DA8782B87FCA2B6DB6E
-:10123000D2C95E54BC35A908DB3603F7D32BDEAA2E
-:1012400028A7FB061E07572CFC915BF429EEAD582E
-:101250005849FD5629E52738DF959CB83CCCAF4D61
-:101260001B945AA244F8810349FEF3447EAFD03068
-:101270007CD32480FFDEA37C9FA2222733E2F919CE
-:1012800005524978FDA8675254447F7689A324BC4F
-:101290000E756E456A44FF96B99911FD92A30564D7
-:1012A000BF410F5494801E380AED5260C1025107AD
-:1012B000A5E59F0A054B15B68BBCACC2E3EB61F00C
-:1012C000877AB0C41669A77747733B5FCED6D0063E
-:1012D00049F911BEBF5D9668FC24DC4E94CB1536EF
-:1012E0005E97158987BCA346B2977931921FE3FABE
-:1012F00092A34BEBD0F4966744BEAFF961E5023E92
-:101300006D5EE673B7A33FA2C1ADCDAFC15F2E2F17
-:101310002AA17CF735D6A18797C17A503FE8E168CA
-:101320004A16FE1AF81FE4AF897324F04BECCD7E09
-:101330006BFE7A05E82B47B8BEB2498958B7D797F4
-:10134000BED2C6EDCB2FD3C69DE9F0D0FBEE1D9FDC
-:101350009E9A2087F5333F4E880FEFBFF8E9A688A5
-:10136000FB491FCF7184F7B77E3A07EF4F51D45A2C
-:101370001BF0E53126B97CC8076DAA1203F4283E9C
-:10138000EDAEC3B6F4432F96ABB2A9E77C75D84E49
-:10139000BCE86F33C3BA6E1A26AB18BF6B7E881ECB
-:1013A000DEBF26F3BCC3B1ABAA15F75977FB542BAC
-:1013B000FAF3BB1F54ADE887EC76F37319EE2C03F8
-:1013C0009D8F7167F37AC5BF24F3BA834EF1BED601
-:1013D000FA8DDE4E841BEBCCD137A8FA264875E592
-:1013E000C7D0BFCAE9E95F1D53FC369CEFD8837EA6
-:1013F0005BF87EE2F5FA577F041E43380A99E40948
-:10140000D723C596284FB8DC96DA1D11FD93C20F7D
-:1014100099EA4C8D78EF263533E239F01B87A15FCE
-:10142000526B62546FEB33F07A5B3D1E57A4F0F8B9
-:10143000CE65B3A33B83FB66726FE7915CC5865EA6
-:10144000CFB7A5A4707FF03F5218C1352B85C3A735
-:10145000AFAFD5F76BF17C0FE293B99CC8E72EAB29
-:10146000E10AB8BCACE0E927A6535D6DBEE1DE2C15
-:10147000E8573CBD753AAFAB35ECC13ADB194F3F8D
-:10148000CFEFDF60C837823FB0CDF7C274AC2BAF6F
-:101490008AE2F5095551A23EB46E7444DCA3183EAD
-:1014A0007E6A21C69FFB8D0CF3FC8F99C00EE685EA
-:1014B000F6D9AD661EAF5A4DBC0E7C7DE6A9F5A8E7
-:1014C0003F3E8BF2E6A5509EB148453C5EB45BA81A
-:1014D0003EF4BE7DA529C807B35278DE2B7BCF44EE
-:1014E000279D2FFBE7C151FC7D7060FD308E73712D
-:1014F0007736F9E5D903189D27D1E801E1335D8FEF
-:1015000082F081CE6330B713F36FB50E138D332B9A
-:1015100085F3E3F5B63DEA89E30C6B7641BB2085A4
-:10152000C7CDB7E2BC046FB0FF2CDCD0B307FBCF54
-:101530001EC9FB486F59CE0BA27F1BFC510CEDC39B
-:10154000BC1FCDF1C63282B46FF3EEA26CD706BADF
-:10155000CEF1B8C03FB0B643C5FA0F7F3FACB71865
-:10156000E8F42E457CDC66F60F26BEB2AD89C17963
-:10157000AEB7DEB8EFF921E0047B327F3CA79736A7
-:101580003FE0D882747C579C3BD1E001387E8C7060
-:10159000687075C3A3AB3FEF147E7B278E971BCA81
-:1015A0005357FFC940798A6A09F424F4F77CC85C70
-:1015B0003E95E8437950DCD2C2F9C69F58526C83FD
-:1015C000B6A071158F8FDB9588BC9866CF268AE709
-:1015D000C7BEA744D8A38922FE1DAFCB4F4E6C9C3B
-:1015E0004EE7F826EAE2E25FA488BC651A4B0BCF0F
-:1015F00023AC15F1C6E5B68171E89F2A10E7CA80D1
-:101600006F932AB371F121BDD0B08E459C53D4F8AD
-:1016100070E469FB9D38DFC8D3EC0EF207B471BBF0
-:10162000F3131C2F97DFE37819D531ECE949D03754
-:101630001E3132BF1A5AE7040E2A833087E2A4CB48
-:10164000176C645FC61C9D43F5DE66A781A961EB3C
-:101650008F52A3991AA62FADC3E223FAB2A04F5D11
-:1016600054A41F902FE68971A5458CB73FBEEC08A6
-:10167000FA05F9B6E5E417C48D1B18311E6B532229
-:10168000FC833CE67163DCE802FAE27ED998D34A37
-:10169000841F302EB091CEA18EFB30F2FA8473916C
-:1016A000FD037DD1A52FFCB1DCA7D12FFCA1F873E0
-:1016B000B823F197501E89BF244F24FE521644E2EE
-:1016C00027D51B898FF4E52322EEF75B9317D11FF3
-:1016D000F0C08488E733C18085F7B31E9D16F1FC06
-:1016E000E08DB323FA4337DF16F1FC70FF9288FBDD
-:1016F000D9DB56FE207A8FAC5F1BF1BC9EDE3734FF
-:10170000FE34627C8DDE3EF8FBDFA437730AFF50A7
-:10171000D03B51D859879BD7AD75196D8FE2797C35
-:101720003C3682FACE81E7E963D1FEAB5497E79B62
-:10173000C6685FFB97B24742BD940EA8356451BDA1
-:101740003CD5F5FDDC6088D867B73BB93F6477725C
-:101750003DFE6B133F2F950EFE26D929030BC5D9ED
-:1017600016AC77648299AC8F639C5DE7E818A63A63
-:10177000306F07FDC921BDAAE9D1DBCC6A6D07E84E
-:10178000975132D793A03FFB39619EF7A5078DDCB7
-:10179000FFF019D1FF48B7305F6C1ED919CA433B1F
-:1017A00058A284E700E2427A5CFD0E8875706536C7
-:1017B0009DC37A134140BF5975D17ED3AD9A9E5ACD
-:1017C0003E9CF4D4655BA4FF767969165D3F7BBBD4
-:1017D00099EA07CE8A3A470D0FFAF3D6DA396CED5B
-:1017E000FEF22D9B62D0EF3C2BCEFF6AD7270BFC7D
-:1017F0004D76CAC2FE59D6603E6C1118F138C07BD6
-:10180000E5918ED8DB18F99B9370DD555BAEDCFE5D
-:101810002AF4AB0DC1646E377CF4DEFC77F9B9EEC7
-:10182000F97F8BFCAE408593C7F91562FC5BA0B1D4
-:10183000039E6E013A38B07D635219F2275CA7F31C
-:1018400071338F3023CAF32C6F26D54D9C62AE3393
-:101850007B01C4F94E95E09CCB3C46CC5BBD737BD1
-:10186000650C3ED73D9E360E300CFA25EF3A7CC60D
-:1018700064CC1B4CE67513309F05AF7B16A53F8CDF
-:1018800076499BEF1DE6BD7406E83B9BB9685C6D2D
-:101890007C86E9F9303DB57BF9AA8F1260BEB54769
-:1018A0000D948F58DB6CA678AD6BE57FED780AEE72
-:1018B000DF91DED10FEDF6FB2BFF3604F9E1D6CD3B
-:1018C000325381DEAADD7BA7336C5FE5ECD22B318E
-:1018D000781FECEED6A7D058BE6CA63AE2F757BEFA
-:1018E0003C24DC8FAD74162EC7F7D8B8EB3BEF580D
-:1018F000FCD2F014AAF712FCB442F0D3DA178792A4
-:10190000BFB536A69B9F787F2BAF1BD1D67146F013
-:10191000E3CA97BE89F8CEC46EE023D5CCF7C5D410
-:10192000A160EFDB2EE7D2771F8CDE7F75C2BC2D66
-:10193000573F89C5FE9E37FF4AF0B3B9D7072FCA74
-:10194000A26F4C687F5A3BEFB9A029211FE90E72A4
-:10195000B601C7BFED772F5EFA00F1D3FCF2D69F38
-:10196000E133D779FE7397967714F6C625F001F622
-:1019700086E28B2E16CDCF9308FF46C11DF92CFAB7
-:101980009E874A7CED66C7711FA7B6D5407526B104
-:10199000B8091496AF8B950D9A51725B9CA0AF85D8
-:1019A0009EF97FCEDB2AEAA83E20D21F2A38B43225
-:1019B000C20FF2C05FAF7ED033DE5ACC2FE9FDA15B
-:1019C000F101C36253DCF7F84587A6F5EA174140F9
-:1019D000ED96C688AD21F835E8F4F37E2157F53849
-:1019E00016E6FF03D1FCFC33980EF47B7F9ACAF510
-:1019F000B72D83F1F36952E7300BE8CB16E7A2C7A6
-:101A00001F856B96417CDDD8AFA53335F9C47FDDEA
-:101A10007ED7A111A4B7D8B7301BE243E43DF474DC
-:101A20002BC0F3ECF9617227DE0F1CFE6B2CE67DF8
-:101A300077C4AB6F213D824765DAFF89523A4C8EFD
-:101A40005EE2BB57510F029FCAA9DC1E581A797E6D
-:101A5000D1A2BA19C60F5176FBA8F0737F8D4E1E26
-:101A60004F561E7EBFBF09E871C9D0169B03E3AF76
-:101A7000DEBB3B16DDFF0C93F703E4C35567DF1EA7
-:101A800063A7FCCD96FE180FD607F87730462ACC10
-:101A9000A7E4F584A37A332C2601CFE927503BB283
-:101AA000297F19F2597580AF13C7C642BEE18D1266
-:101AB000F53B1B6BE371BCEADF37A7A13CBD9CC4BF
-:101AC000E3CD97AE66F3F715A6E0F341A74310D335
-:101AD0006FC0F8E46511D7745E95E9396DFE918D9C
-:101AE00085B21DF82127B0F100C5514D6615E91AE0
-:101AF000F51CE378688A22B9AF6E99CAD0EE7739BF
-:101B0000984B82FB3BA2837FA4F36ECD6615F3ADA9
-:101B100051F68D2C1EC6DF21F659870347E179293E
-:101B2000EDBA365F54D3D31873203F50DE374AD90D
-:101B3000C826DBC2F11C437876A4723EDA111D3050
-:101B4000609E253898B16709AE109C8CE6D5E01CE4
-:101B5000EEC7F3843B4CC1F3786E06E0B223FD87F9
-:101B6000330E276B1AAA629E20CAEEA67544D95579
-:101B7000974FEA0957752EF3A35DFFF943AC5B6EEF
-:101B8000518EABA3437D0BC8C08E814CC8F9CF1FCB
-:101B90002FC908EF836219177A7FC8AF363E5E37C8
-:101BA00089E2099F8CF12FB431F1B84E95D6A76028
-:101BB0008A298FE301F7DBAD167EBFFB79E06F1B4F
-:101BC000F66DFC39579CDD3A4D2239E1F5B8421FDC
-:101BD000DC2705CEDF08A4FD2A702057055856BF24
-:101BE000B19FF87495A1E9A99170FFEE28AF2B156C
-:101BF000E67BED43039D6BFDF38B51FE0AC0C7B03E
-:101C00007D5B92DDBDC8877EFC47DE7BE8C974A49E
-:101C1000FF3E49C53C6C973148DF37A96AFACC448E
-:101C2000F50D8D1F53DDD39BA9DE4938CFB8C61AF9
-:101C3000DA8F1ECF36D27E74B6380F5EEFE4FAE349
-:101C4000F2E921CFD684E17F492A972F16F40E407E
-:101C5000B96912F2D9827E0AB47B85BFB4B7F5D6D2
-:101C60002C352C7F58C30EA423BE1F6287A8D5AE87
-:101C700077F9F9B9CAEC772C77B8C3F86F9190F778
-:101C800045A9224F96EA9D8DF0AE6AFDC414ABE2E1
-:101C90003999FAFE6857EAC19FB2F782976EB9D5B3
-:101CA000C951B51234E1F3D517F8F957A0731D9E49
-:101CB0003778F99DC6118BE1FA5EC035D695FACE1C
-:101CC0009AA9BE72AFD1938ECFD79CF93A17F55629
-:101CD000090201F07CDDBC6A00E20DF8BE281AE5BD
-:101CE0006B17233DA6C9670ECA27BC9F837C5F8004
-:101CF000FDE1A4877798DAF9F9D3BDFCFC29F03D22
-:101D0000C901F0BD1DFD861C3BC801BD3F94E47BAD
-:101D100047BB81CEC9FA408F0FA67ED11CECEF687D
-:101D20002FB1937C635E3F0FE5347080C6A987D8DE
-:101D3000044927314FB83FD9E88C25BA69FAF1B088
-:101D400093093BA1C6E17903AB2C47C845983DE414
-:101D50007D612F4FFC2AF0F82FD176B8855D10FEFB
-:101D600014F3E6939EBF57D8AAB5AF4F98B91DD6C6
-:101D7000B9F684DC5D3F8EFE6B40F0C901E1CFA275
-:101D80009D5013783D0E5E1FBD99D7D58E71AF293A
-:101D9000C6B3CFE3CA371EC47682A7BE18CF3E4F64
-:101DA0005AD07E909F81E6E7D91B0EDC948DFBDE36
-:101DB0005D67CD0CF75D1AFE1AFCE34B8087FB5B79
-:101DC00000FFBDD825580EF11F58EC74E6EC79BF22
-:101DD0004BD2F4C7A90AE4C7CE0639D40740AA807B
-:101DE000C1B1FFDBD4938FFBA09F95E67E3E15FD2E
-:101DF000ED742FB55D27FF9A8CB660EF69EE47351D
-:101E000098DCD9C83F0D0323BF1FA0B54FA61A8980
-:101E10000E057D7CBFEB482ACF6F0EF1B1C7908FC6
-:101E2000AA1A64BB1FE87EA941769BC01F3AEFF651
-:101E300026E3D99C0BCC77CB44B4F3228ED4BEF7E7
-:101E40007217FA2960A7EEFE65EFFB0FAB99F65B00
-:101E50006340BE5AD624B1FF001C2C7F26F2F9D570
-:101E6000DAF76A1AB71CC6EF88AD7C4E771FFD15EE
-:101E7000FA0E46A41F732455F827592C0BFD13E0C6
-:101E800023D20F46851D3103DFAE48F7EE437BFCBE
-:101E9000B2F8BE02E85192C77D4E615744FD4170D1
-:101EA00007AF2B1EBECD2F1BE0FD098A5F467BC509
-:101EB000A0C57D87716E6F197D87C9E73E8DFB3E9A
-:101EC000CB853E5CAEF9697EBE3F026637C24FAB42
-:101ED00016AB1FCFFCB5B1B8FE6D12C5CBABB64586
-:101EE000EEA7548BF5AFDE7CF2309ABCCA7ADD7D6A
-:101EF000B1FE6ADDFAB57DF3CF5323EBBFAE773F7A
-:101F0000E42F46EE37BC2DC6D1EE9BD2B87EAC8214
-:101F10006520DD56FB65BF9FFB7936FC5ED09D6278
-:101F20005D770AFAD33AE1B9CA6D923F803CFE78F8
-:101F3000649DE95DF58BCB90AE7A3E5929D6BD7C88
-:101F4000BB91FC55FCFE0FCA9D9E3F568AF5AFD44F
-:101F5000ADBFCA2BE9E0E37E744FF8EA6F413A5710
-:101F60006E37B2DEE0D3E8B552E3EB3EE0D5E0D425
-:101F7000E0FEA1F0F64F13F9AD116C04D1A93CE1DC
-:101F8000BAE8A4F773771D1E41DF5BBB7C6420C5F4
-:101F9000FB1A1FE8DF2F137EF2D4CDDC6FBCD458C0
-:101FA0006C1D89F14C9BC125A9149FC58E04BCE40E
-:101FB00037CBAC02FA5D4D599BF0FB8379270AE6DB
-:101FC00060FC9F7FC240E7EFF61C29A07DE7FCA3E1
-:101FD0008312B228CFEDA2EFE3C038645FBBDAF220
-:101FE00036E1F984AEB692021C5782E7D00FC813CF
-:101FF00076A2A62DCF1A7EFE7C4C1A8FEFD73B3FE0
-:10200000FD39FAE9537719E99CC55463F04DACDB0F
-:10201000DA7344A17DF2D527963C1485F47D51A254
-:102020007DF2C3ED6B1317229F3519EDB8EFDDD5A7
-:10203000F4E30378DFB75DA2EF5E54379766EF8075
-:102040007EDE967C57F8F9B33C874AF0B1542BC535
-:10205000CF53FB19C96E5E4CB3FE16FD9F95EE2D56
-:1020600024DF17F7EF3151DDDE0E89A1293BEC3C6F
-:10207000F80AE2E3E2AB274DE88417379C34757C1D
-:102080008F3F70C92FB300C5CD1B4D18C7546ED1FB
-:10209000FA1D26A49347F84755CF7D4CFD95E8CF10
-:1020A000C37C2B9F91A97EF760F36B26E4E7AAED32
-:1020B000124BC90CBBBF598AF85EC312C6F96089BE
-:1020C000D03FAB987F7D1A3CB76A23AF5B608F46E9
-:1020D000D6016BFCBD42F0F7AAEDB3E8FB533DBE61
-:1020E0005B8871E30DF81CE7EF659B23EFAF107C75
-:1020F000BD42C7D73F4913FA67381B8E7CFD75A1D7
-:102100001A9703D7BF3EB972406FE7ECDB84BDD6A8
-:10211000ECE5E58081EC8DFEB9CEC62B046775DB5E
-:102120006513FAA7654D5F10FE2B9A5AA97EE466E7
-:10213000E65D8DF8BAB9C96A47B9AEE8E07A685A7F
-:1021400093D9EF97F07E3DD53977B5F0BA49DF7E68
-:1021500089FC1C4D8F69DF775C26F0B80C14787A07
-:102160001EFABB3C6EAE1271F28A615B0EE33E7BDF
-:1021700095B8BFFAE8C158F40FA7B12F6E47FAC05F
-:102180007C0CE763CF44E27DBAD08BD3B773BDA894
-:10219000B76B5DA9D933298F09712AC2B57A7B241F
-:1021A000BEAB74F1F963693C3FF6820EDF15416600
-:1021B000CD413854D9E5A7A7DB159CF7482ED85B4D
-:1021C000B4936AD6F77E87F14DE1676BFD99E21C07
-:1021D00078BD7DA32D3C6E8E4AE7FEC2CAF1B20FD8
-:1021E000E9D51D6F0C3A98AB1A42F106C419CD69B6
-:1021F000493CEEC082923732649698188A371E7135
-:102200006EAAC8837EF5762EF79DE3603C3C7FADD9
-:1022100030F247ABB79BE99C6235D09FE28A267EBD
-:102220009EC2D3249522DDC15F3F9A86FBB19852AE
-:102230008575CF6AE47C3FABE40BE297A383F87A21
-:102240002F2B6A4A6FFEBBE6B7E3F93035CC7FAF80
-:102250000239C5E7AB9A783D52C3816FFA67A29EF7
-:102260006BFEAFFE8BA1FD5AD845CD2F0C825F3897
-:1022700090FB45F4BDC9BB857C2DB3F37DBABB850E
-:10228000FD61521DF17995B1FE503CFA593B78BD84
-:1022900000DB871F8503FDF8F64B75F1B0EECE9796
-:1022A00024AA87C3F7F17B949D4BEA3F41BFFBEB28
-:1022B0001D16F237EF06BF654A5E4FB9D4E45BFBEB
-:1022C0006E560D7B88FCCF87581DB595829F3B1BB2
-:1022D0006BE9FBA09ABF42EF0FECE98F540ABEAF47
-:1022E000D4F15F547A24DFD5BC1D4D7E63D751D91C
-:1022F0008EFB3180AFDFA485E345F8210D07A2886E
-:10230000AE5D276D6447FE2CF8EDA2C83FD78C93D5
-:10231000090F86F1BCCD6E796D20D211F18EF5F7E3
-:102320002FB7BC36829FFBF613FE576D9323BE0F6B
-:102330005B591FF9FDD79AB76FA3EF0855EFEF86EA
-:102340006B88293104575F7220493C8E3448917163
-:1023500064F53ED9135E7706EBB903F551BA9007E1
-:10236000A6049331FF35009D0680AFA689D3D5D052
-:10237000CC5B98FF169E2731D2FC3DEE17F956E351
-:10238000FDAF33AD7CFFFAAAAF02FBF70F94A9AE05
-:10239000F3FEB7570E0DD7A30CE104BA561B83C941
-:1023A000146F9E34107CD5272F270FB2A15EDA520E
-:1023B00082DF0F9D2EF4DFE181D6E5C8CF3E9C374A
-:1023C0002534CECB69BC7E8FE17A9DE86DFC928F7F
-:1023D0002BD6FB109B2DE26ACE4F39697CBD108F46
-:1023E0008C4BEF251EB95EBF13ECC3A98512D63303
-:1023F000293E8C87F7BCC7F5424DF3B28F90DFAB17
-:10240000DF37539DD7FD2DCB8652BDAFD77B03FA67
-:102410001B5FB7ACB881F283D24304970FE173A27C
-:102420005F732619EB522B9BCF2493DDDD3B7A9310
-:102430002F06FD97BCE9781DFC09E23FF06B88FF91
-:10244000F6B415687E8C15C7AD3CAA78103F954749
-:102450000B8E57A07F71A2A800D5B974A280FC98FA
-:102460007CF4636C21BFA65B4FA6733FA6AB358A95
-:10247000F20B121BC8F9870D8AE09FD50DAF93BDF3
-:102480005FDD2847D42F6AEFDD99AED038CB34FE1C
-:10249000A997DCC41FBB78BBBA710FAD6F95B19E15
-:1024A000E85DB3DDC8EFEFE0ADF67D581F8BF72197
-:1024B0003E8EE325A0C334933F03F3D3C732B99FC5
-:1024C000AFA7C7E7E93CFF71ECAC7700F2CBB142B4
-:1024D000EF507B2F76C2C78A785C2B097C37F0736C
-:1024E00053FAE73E4B97C4774222CFB76AEDA974FF
-:1024F000AE3FA7997AFF2EE06FD2B57309EC314356
-:102500000146C546FB06E1D7A7867DD761CECD46FD
-:10251000F2174E31FBEB58EF3843D3B3E3B87DD518
-:10252000E7CBE789F73C9B55BE5FA43B3F334F3B6E
-:10253000DFA43BEF364FF83BF374FECED3E9C28FF6
-:102540001FC286A01EAC17E7EFD60E8FF287E7B347
-:10255000F4ED61B12F82E787B0AD19FE2EE57D8ED7
-:10256000B59E7D85EADDCE46B1813CAF47F9EFCA25
-:102570003EF2DF35DD72393782CF34BA5C12DF8349
-:10258000D1D365B7A6AFC4BE5DB4D8B7F31BBDBB8E
-:10259000519E2B2D174DBCEE3068427D56339CFB6F
-:1025A0004D974A25DA6F0738FB9BC3F4FBA5541EF1
-:1025B0007FDD7F8B4479D7567C1EE3AC7A89EABCF9
-:1025C0002B03ED26E4A7210D8B1F26B9F5B1D32CE3
-:1025D000ECBB1A332DDC4E76D34F5B77B71D8BF7F0
-:1025E000717D9C482D3E8F767186B083FA7351437E
-:1025F000597B593AC033DF2DB9B01EA02F3ACF5EB8
-:1026000030EA7544C3F5D2BB33DDFB4E3ACA79FBE1
-:10261000E55B308F7A6CF867FDD18E56F5C1C71F28
-:102620000B3CEBBF2BE31AAAD6E2F7556A9DDE0EF0
-:10263000D29F866F6347301CA7E3376B25A4132313
-:10264000FEEF4B7E3E13E37E96CEBF770FB8A77D9D
-:102650009755E9BC4EEB98D19F41798A9CEBDBF70B
-:10266000AAD9F7462EEAB3CED6A3B9A630BA5E5C95
-:102670000B7A00ED4AF3C164D516CE7706E23749EE
-:10268000D2F84F11F632920F2F221FE6607B26768A
-:1026900010EAE35DA76207E3787B79DBCDAF4DFC01
-:1026A0007BF6101F0D9917130EDFC304DFA57A3ECA
-:1026B0000E631D43E68C0CBF5FDB171F5B33888FF7
-:1026C0003B22F8585B6F3D7ECF07E38016337DCF0A
-:1026D00007F3D78E3039199AC1F5CF58F1FD9EF125
-:1026E000CC47DF391C2BBEE3335E6101251EF7CDDD
-:1026F0000232DFF7E5E72DC6087E1EAB045AB18E25
-:1027000062BCD8E799C0DAE9B9292C48AD9BD9E970
-:102710001C451173513BCE12988EEE544E7D3DD523
-:1027200025069215C7798B38AFD10BDD42EB57E800
-:10273000BB3DC49F329ED7E9FDBB2FB333B8DCD37A
-:10274000C74590BE9718E5B9F07B6D38C9448595AB
-:10275000637DD3648559A201DE5D870C24CF2D1DD6
-:10276000AA1FEB535D09E2BDCF19D5E18E757379D0
-:10277000459383F518DA7AF5789800E3619E6DAC9D
-:10278000029128E13140F3DDC8F8399242A652FDAA
-:10279000736946A6D0F7418AA38A218E427D6FB025
-:1027A000F8081FD33354BA8FFB25B130CE848D1275
-:1027B0007B0FF73FB2F87AB5F1270023E0F9C2E9C1
-:1027C00019DC9E614AF5BD78BE8F124B05CD25768A
-:1027D000FE9DA364FACED1F5E2B52B997FEF32F6D8
-:1027E000CE60E7CF0A42FB492EFCEE516CE83B9BE2
-:1027F0002EEDDF830844FE7B1077642CF911F2A3E1
-:1028000056AFC7BCFCDF7DD0D7EB85D5E7B10B61F8
-:10281000E7B0B5BA926DFED92A9EF35B9068A173BA
-:10282000BF7996FEF968C7063ABD34FEFBD2F6C101
-:102830003498E21FED8909F1BB95B9C721BE4375F4
-:1028400083FC3B50DDE7AE92199D57B49A797DE544
-:1028500063201FF81D26902E15EB68D883C5548F72
-:10286000B9DE6171E1790933C26D0DC15D6B11DFB4
-:1028700005B5F07D717D3D68ADCD40DF1DAD65D105
-:10288000740E3D29DABB2E03E0BA2FA688CE7767F7
-:10289000EF9CE444BF317CFD93B4F51B7AD647C26C
-:1028A0007A1FC9E8A51E515BA7F6EF76D805FEB4DE
-:1028B00075DBB5734A6E25E29C92868FC7A2F9BA82
-:1028C0008DB8F39F45EFAAA837F4EBFDFFDC29BCD8
-:1028D00016A06400000000000000000000000000DE
-:1028E0001F8B080000000000000BD3D76660F85172
-:1028F0008FC02E9A0C0C5DD2A862B4C41D120C0CB1
-:102900009780F80B106702EDF5926460F006E26DB7
-:1029100040BC1D88C5A518180280381088FB80FCB3
-:102920007E204E07E224A81BB30519187281381FB8
-:10293000880B815848808141588078FBCB15191845
-:102940005EAB22F85A6A0C0CC91AF4F3FF60C38E0E
-:10295000B6F4B5EF14D0BEE56E08BE0490BDC20D4E
-:1029600055CD4A37FC66AC42935F8DC65F83477F87
-:10297000A20D2A7F99292A7F9D3903C3432435CB91
-:102980004DF1BB051D0B02FD2784274C9730A2F2A9
-:102990002732A1F2F9A17C00BA0B8074A8030000D1
-:1029A00000000000000000001F8B08000000000075
-:1029B000000BED7D0D7854D599F0B93F73672699DA
-:1029C00099DC24433260126E7ED0A001879860B0FB
-:1029D000586E20E147A30E082CB440262888166DB7
-:1029E000C49FC6DD500609BF0921E14F70D11D10FB
-:1029F0005DEA63FBC5565B75BB7682D646AB356830
-:102A0000D787767765A015BFBA761BD96D976EBB51
-:102A1000F57BDFF79CCBCCBD9900FEECB7BBDFF3B9
-:102A2000C5C7E770EE3D3FEF79CFFB7FDE73C7C5CB
-:102A300046B1E058C63EC6BF698C4DCC658CD5A664
-:102A4000CA160F8B65E73096DB213156C3D8CA769C
-:102A5000253E0BFE59D8D1F20AD697B7B90D772982
-:102A600063FD0FB8FD35503FBD5D09BBA16BA3E20F
-:102A7000A3FAB22E57D86DC0F3AD1FBD9C8FEF37B0
-:102A80004A610675C6EE666C32636B3CF04FA82F48
-:102A9000AB4876E0FB77B748E118BE66A66F12BC7C
-:102AA000BF95F1F7CD0F281A93A1BEEFB626369148
-:102AB000B15B7A60160F35641FF3F68C153016E1A2
-:102AC0008F58CB16785F997A1F615D1F29D0AF3977
-:102AD000E678BE6FD6FB2C80EFB5D47358CF31FCAF
-:102AE000C714C62E65FEE0E96CF87798853F56A0BE
-:102AF0006CC8676C740A5FCE9231807E1463731960
-:102B000073B17218A7F632172B83F559786CE378F6
-:102B10005CD624111E97F918D5DF9D2BC51F2CA557
-:102B20007E6C7A3594F0BC200FCA20330BA18C78D0
-:102B300058221BE09FDB76D97BB8FE0D38D5686A3A
-:102B40009F08C0FB052CEA6200DF9FB118958B59E6
-:102B50009CCA2FB304C1B1940D95A850BF4B496CCA
-:102B600062304F38149D8EFBFBBBFA63EF4AF0FED8
-:102B7000FE6AA9760A94CC9747EBBED0FAACF95519
-:102B800016B90EC7614C7645FC8C8DB7D67998C5C1
-:102B90002A828CE93D3E4E2F87593F83FAF8064141
-:102BA0002F8DEFCB215877CFF32C8CF5106CE614DA
-:102BB000A887BAB2E21BA0DEF378AC1EF172AC05B6
-:102BC000300FFD8F35BAA56815942EDD158132A41E
-:102BD00032A6009EEA1BD64B0AB49B1BE5E38C375A
-:102BE00035995D09F5C3314915CFB1BFAEC7241D75
-:102BF000EAE3A1FEA084EF751783711A1A725DC90A
-:102C00002AC477CF181DCA8AC35A4206FCD69B3AFB
-:102C10003D676C11D1D578416B734DDE6FEEE13CB1
-:102C20003FA3F7EC4F1F5BEF01BF9714F17D3B769D
-:102C3000B82C07E165517BFF2295C53C79293CEF13
-:102C40005C072FDC29FCEE3A5CB615F176AC4F0D33
-:102C50000B52B68D0FE3F636C0FB335572583190E8
-:102C6000CF8A38FC15BA5FF7A5C6D9B90EDA5F96D8
-:102C700082A35199DA4FF83019F1E3DC1A685F95B5
-:102C80006AFF04B60738F6203CD46FCD512FCE131F
-:102C90006134CF48F4F0C23A9DFA0D8A755CF3BFF7
-:102CA000C3B44F731B5A243EAF80AFC10E9F555A19
-:102CB000F08D34FE31019735BE35DF13EB425436CB
-:102CC0002A558FDC8BEB3AA2F175CD371EDF8DF8DC
-:102CD0003BE209C7A0FEE4757F33E65E18E28AE9AD
-:102CE000CF5FFE0CC3F9963F7C3BAEEBB92C5AD7B5
-:102CF000531F9E79ED46367CDEB7041E7E7A6EFE4B
-:102D000010D5ADF9E79AD21809E8ACD294122EA0EA
-:102D10009763F55F79F85E03EBFD26CA934AF39853
-:102D20002941391186A1FD66EA9F3E06795609DDE3
-:102D3000911F2735482DD8EE891B1FFAD27DF0E868
-:102D4000A72E0EF7157FC9E1BEECFAB54F22BC974E
-:102D5000DDB8F6E7CF40FD0A1482C07797DEB47F76
-:102D6000CDDFC13FBFB1F02F97EF61241762D900CB
-:102D700047AE2931DCDF65DF77DBE4CAB1E7FD244C
-:102D8000570ACDD218F2DFB23E89E4737FA39B05C8
-:102D9000F1FDCFDC7137F2D7039249ED9F75C75132
-:102DA0003E1C733186F278D9716F1CF985AD5A4695
-:102DB000F23A62C96B337FE9BD30DEBB0D963CE76A
-:102DC000744AEF617DEF9ABFD87E35F43F63BAC293
-:102DD00028362D79E1C4F3BB02BF91FA72A2836554
-:102DE0006AD215CE400FCD6D8A4D6ED7379C24BA6E
-:102DF0005A06254BE3D3B982CF9635FC42F0A74E55
-:102E000072C909CF1BB585C599E8EE94802729E8DA
-:102E1000ED5DDCEFCB103EE88574D3A5C495343965
-:102E20000D7FAEC804AAC790A56FD96287D392DB85
-:102E30002DB16C9BBE02F9FB2F28379BDBF26DCFC7
-:102E4000E7E6B0DAA99F4E0EFF81E4705222784087
-:102E5000FFD2FE47E2521CE5A2B53F7788FD8954B8
-:102E6000305ACFAF0E48F118ECEFAF8E88F5ED93E6
-:102E7000E28A44F46A9EF6E0B83067796AFF6F1719
-:102E8000FB9FDA3F8E1F0B5F293D97BB290920B4BA
-:102E9000F8222528AF2DFEB1F0DBBFE74725B87F2C
-:102EA000856DA5DD7508E70185F8F7C3FA93C5B808
-:102EB0006FEFBA00AFD03F72F8B100F3A5E06F1129
-:102EC00072F0830EA017782E219C9569700AB85D68
-:102ED000588776B737487DC8A7BF14F35AFD7EB42C
-:102EE00065C64CC4CF1D3D1243FCDC7EA477D99F40
-:102EF000C3FA57C7B3C338C5AF1A8B0397003C2B2F
-:102F00007AECFB796ACBCD01A49B0FFBF20B709C92
-:102F1000DBA72634847375E255CD003A9B65F66ACB
-:102F2000C90C74F561DF8600B6FF50EDB9F11A9C4B
-:102F3000679F125E0FE3AF3E523AD3E4744AF4BB8C
-:102F40005AE0F7A4DA33730CC0D7F28D729207EF10
-:102F5000F529B3E319E4E7D72585E860759B5BC6DF
-:102F6000758E442F1F76B85802E7511384CF91DA3B
-:102F70007DD0D742EFFB1F28BC01EDB7DBDB5D2422
-:102F80002F6E6F73133DAD6E90E24C4AF1DB0A0178
-:102F9000EFEADD0ABD3F694A243FACFDBA5DD0DBF4
-:102FA000C9C357BD82FAFE0CC81F94BB3336FE500E
-:102FB000BB04F0B0620B97472777E72EBD07E58883
-:102FC000D0977788716F8B2B36FE58D99E6DDB8F2B
-:102FD0006857BEAD7EFA48FE8D7548D75D0AE9CFC9
-:102FE0005B363EA685483ED9ED4DE4B0490529FB48
-:102FF000F2041B5A708D94A2278B7E6E6D037B3377
-:1030000030DCDE6C3922913D7AD176661BD899137B
-:1030100087DB99961C89A07D569E922396DCB84B3F
-:10302000898E0D021CBF76452FCB2F27B9F1805416
-:103030008B74A2FF16ED4A16536A51BE5DACBCA05C
-:10304000C55A7C047FEF75005D65A0D719485730DD
-:10305000CFCC9EFE8CF43C433268BC14DDDC1220E5
-:10306000BEC541018E668FD985705E02137BABA908
-:10307000644A1E2F55A86F4698811E4EAD95E28773
-:103080004A793B1FCA5380EB1A78DEDC75797C9B4A
-:10309000847621FCA1FE6CE37637B433FD79F4DC51
-:1030A00094A02C6A2F7D19F7E71210005A356F8F04
-:1030B000F3809D452881F6097735758D05A02C860E
-:1030C0007E32EF4FEFB15D80E4789CD68BE3E3383E
-:1030D000154A7C0DCA198B8E9709B90372B5520532
-:1030E000FA6A665961D49BCD6DE5E7B55F6E08DB82
-:1030F000E5C74D75763D30D7B4CBFF9B675F626BFC
-:10310000BF20526E7BFF678BAEB0BD5F1CBDCA5641
-:10311000FFF2AA2FD8DA2F6D9D61F7937E9A4BEBC1
-:103120005923F87224B85F17F2F2270EFBD42A9BBA
-:10313000AE4FD4BC0DFBC4D6B9C38F4371620E5BD6
-:10314000D49726577CB244F8FC0DB009F70FFEF473
-:1031500031E131C4E76DFA0B776B26BAD3443F34C3
-:1031600097D05E72B63FB118E649EBF76F924474A0
-:1031700078AE1FF3F4FC12406E014ECE01D4DFC9CD
-:103180009225B86FEE5C83DEDF25270BB0FE1B3681
-:10319000B4371FF7D7972C46FE6956D973520EF6EF
-:1031A0000B7BDC301F5843AC0DE8A3A5ED47C7D11E
-:1031B0008E938C205B82758F2F81FCCD3A5C1F260D
-:1031C0002DBC031FF686A21F4A0087D4DEFF7B09B1
-:1031D000DF7F9F19A88759B22817FD479C2A9D0FAA
-:1031E0009B66B056C4D789463BDEBC621D3F9764E0
-:1031F0006AF71C337F8B7C7452D2F9FA04BCDB244F
-:10320000F32CCE67C1FD6EAEAEB14F07B722D72209
-:10321000DC3F22B837B4B264B63232DC5730D32D3B
-:103220008F1A0ECF596666657A3E0BD835D3F3CB2D
-:10323000DDAC12EDD5135256787D299643FFF83553
-:10324000E0ABD8377CE1C78DE1743155CEA5F99B51
-:1032500085BD5BD82E25B2D13E651EB25F59CF43E6
-:10326000A607E59A10712D6DD2495C3FEB68349347
-:103270009ED47A9921B1F476E7F6BDCD4DED2D7946
-:1032800063C92D0B9F965CB1E4978557E7F823C976
-:10329000191C4FCD43F8A393E4743AD1011F1310C6
-:1032A0001EB31AF7CFDA377023639EEA91F7CD92F7
-:1032B00053D08EA1FF3FD27E019EC8AE738519E127
-:1032C000E9DDE0D0D2A760DD036D5C5FBF5BC4C801
-:1032D0003E3CD376D5400EE2C7E3A940FC14F2A9E8
-:1032E000586170681DCA579F9AE847B80A85FEF270
-:1032F00032AEBF0A99B1E36AF4EFDB4F2EC176D646
-:10330000FEE48AFD6986FD417FA4D937548C76920C
-:103310001BF51AB47383DC45B95CD8FEFE7FA05E52
-:103320002C74E8458484A5C39155B5E36A237DFCDC
-:103330008F36A27D698D4B1DD2F73FA89D44FC16A8
-:10334000B66FBE5B09D8C6973E463C08B98D66D7B6
-:10335000B9794AD15E9513EE408A2E9C7059FD468C
-:10336000A213963E4FB9AD4EF684B3EE0E6B36F90E
-:10337000FCEE1FCB735A7DE7A137E7784EFA76F261
-:1033800081C0C3A7A0D34D9C4EB95CB0F8F63F8B6B
-:103390004EA3D6BEC672EF3882FAB54B0BCF32D0F1
-:1033A0004E18FA21B713DCC621A4B398945509EF3F
-:1033B000A31D2AD98D965DD1BFF6AFB794C1F31383
-:1033C000B532F91127D673BADFF300B7472DBD1D0B
-:1033D000157A1BED02C42BD80D036E5E7A701CFFAC
-:1033E000FA9B4B2580DB630CF5BBB17D9B41F66AF4
-:1033F0004E5D5C6F84325E71C833CE48C9A5642CC3
-:103400003F6F39ECD7B7728D6511B2AFA3A3E7FA5E
-:1034100053EF7F2C73FD34AD84E5CD86F1925BE5EF
-:10342000F083D03FE9B2EB31AB5CA3707D99F4B28D
-:1034300012F483476A37A4587A55D7685FE60F1CA1
-:10344000C77D1A691F6007748A639EA3438E7798AD
-:1034500087C64FFAED7AE8A4D04316FC9F40AF2E02
-:103460002C06FAD82B6586FB23315EF4390000F672
-:103470003BAA3233533BE7BAFF41F44BC82ACDB7DE
-:10348000A362E76CDCEF584C09A7EF8755FE85C2B5
-:10349000F567CEDC86DC4668C7D6676E9727DA3DCF
-:1034A000765FD622F4AF00752AC66B42317DDE6CA2
-:1034B0008C474ECD9B843EF68F51FFC0BCBB23672B
-:1034C000F416DF27C247414819191F6FCA32DF4778
-:1034D00007DFEE01770DE56752F250FCA525E6CE39
-:1034E000C8C7969C72CA23A79E934C93B5550F9755
-:1034F0002BD6B89F549F817CC85246A5ECF673FA30
-:10350000EC62E97104395022B3685F06FFF46A8502
-:10351000E3A93FC6E314AA2993DE9AA9343109F03E
-:10352000B421C8481EE4E15E23DF36B038A080E550
-:10353000B3F0800FE549506609F25B9D7EA0D98407
-:103540007E609083C6F45165FD85F03C387F259DF3
-:1035500033B00897B73AFCC7F9C8247DE116788DD7
-:10356000C626519C33AFC92EC7DDE807827CD41B29
-:103570001CCFE7CFA4F306374B7B0EEBB84AF1071D
-:103580004F8369CFAA590DF267F5FEAB762D86F110
-:103590006B1EB9F96D2C271FBC27FF4B50D63DBEC3
-:1035A000EB662C4B5E8B8ECD144FB54AE01426D7BC
-:1035B000017C3E66B873466E67AC57226857C33EBF
-:1035C00076203D2463E55948DFAB14CEFFFD0BB4F4
-:1035D00000C667D42D5CAEAAF3017944FFDC4F6FBF
-:1035E0004EF9D3E457A8C24F52DA158A2324F53294
-:1035F0008AB71CDA226B58829C8DE13CD6FCBD2236
-:103600004EDD29E2AD4EF87A4B868A510E9E58FF68
-:1036100011D9878A9E159E0DF375F95909C121E2CA
-:1036200005CD62FF926BEB3DE9F12245F8391D476C
-:10363000E70C184807034AD86B10DF68386E74CB64
-:103640007486F197597A98A13DD129FC1EC567323D
-:10365000DCD76C9DCD44BF165E6921EC5FC5C20905
-:10366000ECDFDE8FB885F59AB7231FFCE05A6E8732
-:103670009C28B5CB6D20A12ED85336AB68BD8AB43B
-:10368000D9149C7415D2FCEF9502215739BDBE5157
-:103690003BE5B16D4007CFB9CD7B94519F808F1C26
-:1036A00072FD07C026B86F8F4A76796E95079D7CAC
-:1036B000D426915DA89A7C9D33950F1B514F6E04C3
-:1036C000BBB1D018CE2F1B5F6764376E04FE8B959D
-:1036D00066E29F6A0965C4C5F24F5E7BAE84718C59
-:1036E000CFCA3F7FA988733AC13F406709B4631EC0
-:1036F000958CCE29B0BEEFEC6BFCF11478FDEC811B
-:1037000015D9D740F9BDF8C6EBAF81F96F7F7C4F73
-:1037100036EEF3A3AF023F9DC78FB7F8A9196DD856
-:10372000F3C4D98CB5767E32D657103FBDA570FD57
-:10373000D5BFE0776F5CFDFFF9E97CFCF4B602F4DD
-:1037400039ED4F678BA3E7916FCD454C437B0BDA87
-:103750009848E7D1A0BDF4A95984EF752E2EC7FC77
-:103760002E2FB73B42FCBD73BCBF513F79FC60417B
-:10377000F967E7D3753EF3A3CF83DF41EE90BC3901
-:1037800031CECEF79D2E4E77BF727DE2F5BDF3852B
-:10379000CF617D60D7937D779DCA0CF40326BEE090
-:1037A0002161F1EAB88D479025A6C1F3501E7FEF45
-:1037B000CE237919473B6648A9A4FE26E3767C53BD
-:1037C000CDE623FC5C62B06211F8CB73E05F688FDA
-:1037D0005CE7E37E058CC34230FE6A6FB4581D453A
-:1037E000E3917FF9EAF3FB82285F5EF79825F89C66
-:1037F00025D55C3C1FB0EC8E91F95D65A7D3FCAC80
-:10380000A73546709CBA54A378258AB100D4B796E0
-:103810005E4A714A168E1D97B03E4A6728C795606A
-:103820006431D9216D6E6316D4B78201150B12DD98
-:1038300092DC54DA7B430194036097E07B3536D702
-:10384000A3A1FF324AC6203473B77D447EF7896254
-:103850002E6F3BA6303AA71978E0DF96CA68EFB41E
-:10386000BBE9DC02EC46E2D7A8901BC9E0F4500BA0
-:10387000FA19455A5882FAA6D82F8E7F8DCB13D3CA
-:1038800033393D3EC2E31D2D21EEEF3AEDBECD5F53
-:10389000BFEC4D03C7FBE16B5D9743F9FA933F7FA4
-:1038A000FD7278F7C6B75EABC1B8B7BB4EB3C51DE6
-:1038B000DDCC7813ED2DF099121ACAE7D8C925B8D6
-:1038C0009929BF4E8A217EA235FE38AE17791BF1A9
-:1038D000939CA2F0F345F80B017C01015F77F05453
-:1038E00015CD137BFF3F32C97BFA9B2CF408B4DB68
-:1038F0009C777F1CE5486ABE49249FA2209FD08FF9
-:103900008CFA7A96ACA1F9FCE107B1CF1F61572779
-:10391000A7CE0B0F6D99D782789EBBC0A3239DB90C
-:10392000639BEF463A77AEF38CEFC14B3134679B24
-:103930001FF8C45DA1995EB27FD961DA0FD1C4824C
-:103940005B0705827107E8BF6C05CBD0DF80FEB84E
-:103950004E9067686F5BFD808C4D5CEF19DFF44B18
-:1039600029DE2FE21556BF9B62129D13DC540E6CAC
-:10397000503E1C4F1B7CF24FBE86E72E3145573818
-:103980001D842AD2F0867FF6B819A78BCBF6D9F51D
-:103990002ECCBFB014DFC714A21727BF8C8FDBDB80
-:1039A0006FF09DFF5C7FF87E723C4F14FC66F5B7AC
-:1039B000E02378A54CF175FBB9CC4D75F6FADC61C6
-:1039C000F8383F5CD355FBB94D83CF3EDECCA0FD2C
-:1039D000FDEC227B7D03C66F3EC9BA1D7CF7F4184F
-:1039E000F33BEA67F0EB2DB9FBBE27F2B7348E1A32
-:1039F00066384EFF82BDF3E7011D14EADCEE289C19
-:103A0000BFB021B706E51413792699ED8F42A1EFD7
-:103A100095F697941CF4474DDE3EB9E4AD1939781C
-:103A20005E5CC7E83C3DAADE13CB3152F648BF5A74
-:103A30009E8578FEFCED91BBBDE97937297BE48159
-:103A4000578D9A0CF6887A8F64C238B396803D52AF
-:103A5000956E8FB44A2883B297803D427647F43DF5
-:103A6000C4D74876C98F2DFBDE9FD9AEFE83CAF539
-:103A70002CE8997FFA2C7A669CD7FC17F573B0076F
-:103A8000A695182B2319E8F00395C73B2CFDD918F0
-:103A90004C2878760E7A5375C1F36BEB922FA138D0
-:103AA000EED0770671DDB01E97ABF6D3AFE78CCAC8
-:103AB000E199A8F23C9891FA7D6B047FC5AB7985BA
-:103AC000DD62DFEFFE05EFE832FA2FE0C7A0FF92DC
-:103AD000F4956DC3B8E099984AF13A75FECADD7362
-:103AE000919EC0CEE6F47C7EFBFADA21D9C6C7D31C
-:103AF000CE66D9F8BE9ED9CFE96678ECE7748DBA68
-:103B0000FD9C6E56C87E4E37C7B09FD35D5F693F40
-:103B1000A773DAF73347BBFE7BDAF7A14646FC749E
-:103B200001FB1EF8E926A4A791F8E9BA7CE3FE4858
-:103B300086FDAED6B89DBADA1B59807437CDE076D3
-:103B40005D34B69EF201F3A2206F4A296E48712FB0
-:103B50002BAE65C5BDACBC402B9EE58C5F59712F6B
-:103B60002B8E25C578DCAAD9135D81F036B79F94DA
-:103B7000518EE8CFC13CC808D639DEB0F81C970793
-:103B80002DED99E372CEF8DB88ED3E255F7D0EFAD0
-:103B9000613DAED7D20FC0E70F7E163E07B9B50D17
-:103BA000C7FB17E4F751244FBA69FF2A00D768A76B
-:103BB000C33E6818A75F707A3FC6E3D4E36EE2DBCA
-:103BC0008BF57F31D141864D8B820F8EF1AC68AC85
-:103BD00094F48BC537169F38FDE361FCF15FCD3F50
-:103BE00017E91F03FF7CCF751E7D04FCF13CE27BCF
-:103BF0005A25C7AF931F2CFA07924848D5B8DFD192
-:103C000004B6B7E89DBD183611CE89C2AF39315A16
-:103C100023FFE2C4F3FFCECF619FF784C78935E26B
-:103C2000FB89DD05F16DA5293EB3F8A9DD13FDB1D2
-:103C30002B2D0FC4CA773CEC315FC7E721B52F812C
-:103C4000FE4A68360B6F3088CF8EF1E79C4F7D615E
-:103C500046F1D3CFEC97ED75C5F17CA8451A5ACA49
-:103C6000C86F651AF2AD2AE4C98B59D19388CFE6A3
-:103C7000E991124E4F43E37C00D72F3A14F2D73E1E
-:103C80002B3F358F84FF73F8880EB96A87E707A446
-:103C9000CB2D946FA19016DF20659057025F7116AF
-:103CA0001E83EB83FDFC77C4635E15936839828FB6
-:103CB0009B3DE61F5C9FCDFE50B4DA141F03DE3C33
-:103CC0001ACAC56AC05BF970BC9D74F1F53BE92F57
-:103CD000A42665A4FF10C8D10D52DA39A9C08BB54E
-:103CE0009E91E4B345A769E70D212D7DBDFF8FCAE5
-:103CF000654B5E5EEE894EC67D709B1121FF4CDAEE
-:103D00005FA79C196E07C974CE7806EC1EEC76B1DD
-:103D1000F275DA592F1E96B0A967152AAF3D4B8769
-:103D200027EC8B67B3A934CFE653597F3697CAE99E
-:103D3000672FA172C6D9D154369C0560C0C4693CB6
-:103D40005B4AE5CCB3575039EBEC782A679FBD8AC4
-:103D5000DACD393B89CAEBCE7E81CAEBCF4EA1D2F8
-:103D600069FF18EB5592DF96FCB2E4BB537E5BF221
-:103D7000EFFF9AFC8E355C94FD03FAEFABDA79E441
-:103D8000F748F202F8FA3E2D5D4EA4F4F3FDDA672F
-:103D9000E0EBE3824F817FDFC3388C07BC388A5366
-:103DA00085799C2A606806E669ECC326B0A5FED238
-:103DB000C8498C1B342FF0E831807BA05423F9B420
-:103DC0002DA8D1B9DB66491FCDE5413281F4B73367
-:103DD000A4D178DBFEA878317FE1A55105019CA72D
-:103DE000DB2FEBD8FE5BB9C97DB7E039FE14163E78
-:103DF00004E3ADD8B3C793EE87EF47E300E00BC40D
-:103E00009E660CF87AE3A8DF2DC5F97C5319C563CB
-:103E1000A03433E58B7DD32DCEA7D5A110E269ABBD
-:103E20004F267DD0AD7B441E6A72A005FDDC3A9919
-:103E30006D8379378C7E670B82AD8E2BDB5106F557
-:103E40009D75655EDCA4A75FF92044F604BC435071
-:103E5000A04C88D2CC81FDE9F4868DF39DB729C6AC
-:103E6000D03A2456ECEFAE1EB9DD26FF4008E9A398
-:103E700063D2E4CA5B60FEDE4905A371FEED3547FF
-:103E80006DF850747B3C45C18023FAE175498AABDB
-:103E90006D908D1D65B0BE80C8B706302B23697943
-:103EA00007161C4A18D6C1E14A287C3DAC009EE7A3
-:103EB000D6256249BE5E13E3AE3E5F3284FEA25257
-:103EC000779AE26D9DFEE422AA3BE0B0C6FFAD66A4
-:103ED000E50570BEF109BE699EF4ED4594475EA507
-:103EE000D1BE75BB8616603DB6D6C51ECF10BFD9F4
-:103EF00020F8795BE5F9E332AACF0E47B7D7EE2F6A
-:103F00005AF0BC2F4A271CCDAEA15199F6EFD3CE63
-:103F10007FA1757FDEF3758E903F70B9DBBE0F0118
-:103F200021CF9BA77C3B84E7E2163C9D12EC43CD5E
-:103F3000E7BF0FCD53B8BCFEBCD7FB3F6DDCDF6BDA
-:103F40003CAE027C3ABB1CE38C632687305EEBB34D
-:103F5000E2D1E138E52705301E4DBD0CD243AACE93
-:103F6000C7505496403E94B33F4CE03E29D59AA1A9
-:103F7000909CCDBCEF4A7813E5B539F9D3829BFE0E
-:103F8000260BD381CE0FBD567CDA5027F3FB1218D7
-:103F9000FF5598753ECBE3D3567FB542A6783405DE
-:103FA000B2D3C651410FE3398E8271EABCE1F37F8F
-:103FB00037458FF6F98B787C5C51B91FF89EC4F1B8
-:103FC000117B55A17CCFAEE7B97C63C719C9EFAEB1
-:103FD0005A83CE5576C0FFE83FC46A7D71A45BC5A5
-:103FE000918F77A6727A08E5A81517A7F9F8F90056
-:103FF000C5B9314F91E2E606ABC0F7DD02346B1C68
-:10400000D58ACB57AE9984EDFC06F33C07EBF3D78A
-:10401000B1C425006FD0DDBAF5F2D20CF1F0CA358B
-:10402000DF7812E6DDFDD4F45F3D09F55D72F8D569
-:104030003A6897FFE53AC2AB331EBEAD523675946F
-:104040000F3EDF21DC57B0A1892E6EED9162F83C66
-:10405000DBE73BC8F7BB35A4205E404F225EBCCEF9
-:10406000BCC8747C97211C3B07E6C1BFBD5BE72D34
-:10407000C379116ECCAF5CD15BAFA19E092EB19F0D
-:104080005FF89BEC756F951DCEAD62FF2E44FFCEA1
-:104090003CC41E73DE22A4DB33418DA1BCD9B8F62B
-:1040A000EA1B49EE6F57D8B8D20CF4EB5857A7E685
-:1040B00022FDDF6DD4EFAD40BDD1A0515E4F77DC66
-:1040C0001BC714EFED75A973139BFD6E68FC1CAB49
-:1040D000464EB833D9F1E27C2C209E31C73958F7CF
-:1040E0006C99EC9AEE1E3E8F355E77DD5B1E941365
-:1040F000238DFBF418F3881BEDA968DE45DDBBB802
-:104100006FA38BD3F5142D2E95A23DAA2F5C04F539
-:10411000CDE364B28798F0FFBAAFE5E7890F6B860D
-:10412000ED7EC5A6292BC96EB8C9AD0BFE02BB70CA
-:1041300042EABEC501AFF9821B9EABCFC148600FFA
-:10414000BC971BBE11E9A231F811D951B716C93A73
-:10415000D2D78A3D8DB4AECDBACC1268F7AAAD6481
-:10416000A436B15613CF03305113E96E0EBC91E95A
-:104170005E44F25027C039675CE1A46D507317B5F7
-:10418000521E4BA321911F761D6006E5414B7144E1
-:1041900095AAB0DFFC77D0EE9B132C95D1DFBF4EF4
-:1041A000650D5A9A7D0E76F13177DABA4E8CDB13B3
-:1041B00094AB707E9807E75FE4A1FB046EB48FAF09
-:1041C0004CD9C71311916976F2AFD1A8C478465182
-:1041D000E2F794E7FDFDA48CF3B21758F536E993A6
-:1041E000FBD5E05FFE12F733CE8C7E4C35FCAC7114
-:1041F00089AF6B629FC4BD95C39EC86F707C2B1E38
-:104200003051E3F79B37B7B0702C2DAEB2F9F93FC0
-:104210003F8EF6AA157F39977727E0B4E0DE24B108
-:104220002CD2F39EE81FDCE97E314B96CD9DF0F950
-:10423000C19D215FCE570BFC3456F04F5E6D851744
-:10424000E5E658CCF7C17D68E7F2C484FFD2F37D80
-:1042500014C17CC1706BBF6C0C974B8AB837057466
-:104260002DA11DEBCC075230EF67E270B97140D041
-:10427000FF251E91FF33994DE67EB8FDFCCABF9421
-:10428000EB7DD69A97F11EEAF785DE7F51F8950906
-:1042900071AFF1A8B8B7F8F23A83FCBC57D65552C3
-:1042A00039B02E4CCF5F5B574765EA7E159F375F6D
-:1042B000D8612A06D5F09CDFC7E206C0EB1FB566C1
-:1042C000A014F9BC8EDFEFEE6E3AB5A59CEC467EED
-:1042D0006EB1B9A83A5188FE0BC09A0F7597AFCF4F
-:1042E000C3EF79998395055CCD21DEFFABCF2B9C85
-:1042F00074A15BFBEFD86F1F6B6528EF02A67DBF33
-:10430000B3C34EFF86EFBFABE8E2F6BD17FF01FB7C
-:10431000F8256BDFAF6657F3EF335C9C3C463EAA53
-:104320001472600CF0D301F0E7DD0ACF57CFE779C4
-:10433000AE6688F39BA9F27A6CBC68EFE224C406EF
-:10434000F2785E7B313F4FA07E98578EEF312CF98B
-:10435000028F6FB11C91FF3E568CB35A8C3BB19AC1
-:10436000EEEDF2F37FD6A763E96349AAE7021F6087
-:104370001964AD1222730C1B247FBB581AA2BA21F8
-:10438000E959582F93C265DC0F8F93FE2C57CC6FE1
-:104390005710F223328F172517933D097A19E562DA
-:1043A0005C8D2C42F9B2A14D0B0326CEE5C9E1FD8F
-:1043B000392C37F4D50CE0F9472C2693FC519E6339
-:1043C00059FA9564EF91FEDAB03EEF6036E56B2462
-:1043D00029CF7DBFA7D4A6A726FA165EA7C37E6DF8
-:1043E00014F9742EE8CF32E49F5AF974306E49A65E
-:1043F000F756B9D1AF2DCAE4F73FEC91443C2339CD
-:104400009AE280625FE353E58CF719F779B85DF3C0
-:104410006869667B9AB10769BCFD1EDD316EB285A5
-:10442000EECFE83CBE91E53229BF66631BBFA76FA4
-:10443000E16F34D8B5680F6FEC9B3F1BF93B56A971
-:1044400052BE39ACDF87F87389BCE48DE38307B3D0
-:10445000795CA214E5743FE2AF360D7FC1954D88BB
-:10446000BF8E57797E2FE8731FCB906F68E1CFE541
-:10447000635FCCF4DE2A3B46698B32DD1B3EEAB13A
-:10448000ECF46429A7138EBFAC6BD548A6F609815E
-:10449000EF9232163D1FFEFA3DBA6D5CEBDC571908
-:1044A00021DE25F91214E79AA8713B63C3628ED707
-:1044B0000DCF5F733C9A760EF14B1C724A2A1E6C2C
-:1044C000C58D2DBDD9EE89FEA367544A5FB2EF3387
-:1044D00092BBEC05CF41DCB70CE710A73CB519CE79
-:1044E000217A2EEEFB2E6305DF1EDA72741ECEF3E8
-:1044F00057758CECABC0337CDE5C9DC5E552FC4E41
-:104500008129619CE59A885E8FF69BAB9D99983FC7
-:104510003356C46D0ADBFB14A48B20EC65A184F731
-:104520009A9231FC9EC9D8DD8CFC44B570E6AAF5A0
-:104530008610A569F9510A1BEAA7F5B56BC6E3A574
-:1045400004D64F513F8C11EF03ED337F8572734CCE
-:10455000244A79B8D02FE647FB42E0B1C0CBF976C8
-:1045600079435892A07D3098A4F8A453AE8F01FCF3
-:104570005C9266BF05449DADE2725A86FF50CFE75C
-:1045800047EC727B9CE35E74C091F792EB15F9EEF9
-:1045900096DC2EE29B3A411D9433F9E529FDEA8031
-:1045A0000F655875AA7FC0AA7F46F88010889E2D97
-:1045B00078F02A25CADD3D2EFD2B4FA17EAED7789F
-:1045C0001E99B82F972DF0EE438719DA0D4C79C557
-:1045D000C47DDD11E6DFA53933751EF9A1D975D685
-:1045E0007D3A7E5F19CA18C6E9B2C5FCD6BDBA6C61
-:1045F00066BC590EF4906D26E95E9D6E7D57C164D0
-:1046000009CCC3D17D32E5D1E9BE08C9A79E051EFC
-:104610001DBFF3A1897B7A2E717F3CDB3C4DF7EB0C
-:10462000B287AD8FDFAFB3E0CECEAA7AB3DCB0CD28
-:10463000B31EE3DBB0F6D119EFD7D5713F29DBE428
-:104640007188B4F1E97EDD8EA965B6FB75340FFA89
-:104650007182FEAC7B764EB8CEF5ABC96CA74D0827
-:10466000DBED880BDDAF7385ECED775C203FEB1362
-:10467000DFAF137818D6CE610FBA2C3B7494CC7090
-:10468000FFCE34C8F41D91DC8F92911912C52548D4
-:10469000DF5B765E1E1FEABF9D9D9767E5F53BECED
-:1046A0003CCB7ECB9D6DC7B7D3EE735745A8CFC526
-:1046B000DA79BBF01F402F0F791D765E5366FA70D2
-:1046C000CA8B7C36B8FB4A18E768ED8F14CC57DBF1
-:1046D00095CBBF7FC486F9076FCDA07DF1F1EF1DAB
-:1046E000ED9AD2AFE2F76F7EB794919D64C511DC6D
-:1046F00002E65D45F27A0ABB773D44F8090A3C348C
-:10470000E107C86A0857F171C467A617F316F29B50
-:1047100018352AAC08D3BEE3670964BAB4155351FF
-:104720008FD72356D2F034C363FF4E40A39EEFD8F9
-:1047300047FB3E9F3B077F907F4F618E61DF77CBCA
-:104740004F427316E7BBBED24E0727A4C8A0025D36
-:104750009ECE2A15F6CFA08EFAB27BAD8BECC68723
-:1047600096946DBD12FDD5A0ACF3E3C8A171681F8E
-:10477000351F35BD68E76D8F4CF78E83F70F7528B1
-:1047800061340F9F5AB2E655ACC776BBC80E7AAA01
-:104790006F5EC18A34BEDBBC7BC1C2C5F8BEC345F7
-:1047A000FA7DC59EFB064A83D8DF559BFEBDA996C0
-:1047B0008DF7E9E8B7BD51EBCD68C75C9DC5ED92BB
-:1047C0008D5A92E24F1BE7690C5DAE8D25F5A3571C
-:1047D000A0FD708D96F13EF95D596E7E9FCFD52A72
-:1047E000A17C2F8C66BE1760B51B5BF35B3AC708D4
-:1047F000CE9619FA71AEEBE7C9587F08F655975275
-:10480000F49427E86963D1BD5B2B707D0399EF1D9C
-:104810005AE5DAAC719C4E23763E7715368DC67517
-:10482000BBDC91817A24AE4259C7B888CBDD1AB976
-:1048300019EDD1AB5D48E16C73C70F1B16E1BE8467
-:10484000255D8279826A6415D159308BA13E685802
-:10485000126945BC1482FEC3D05E61D12FE99CA2CF
-:10486000B04E635EA87B96F4245CF0DE5311BD0A63
-:10487000F1FED25AFE9D97C2A08FEE051546F8397B
-:104880005C61BB9BA1C9B0115C6017F90712C589B7
-:104890009C7C64ADAB792997E3BBD7FE7654A6EF39
-:1048A000CD546495115EBD867DDD1ED4BB30CE54E3
-:1048B000737009E1BBC6CDE2C4BF6EA2EF5DB52E39
-:1048C000826BD794935F41B87EF7FB2CDAEF6B993C
-:1048D00029215CF943FC9CD59A27BF6950E1F1700E
-:1048E000CE874EBEB3F8C109DFCED9F3E83C6E33B4
-:1048F0001B9C8FF88E9D95898E3617ADF1A6C74506
-:104900005B05FDC13E907C89E98CF65BF957B61ECC
-:10491000F361377E315289FCF1B697DF5BBD6FA939
-:1049200046EB7868AE46F1C687FCAD44F7A736BAC9
-:10493000C287101C555F88FBB9BBB8228CF1B6BF8B
-:10494000C3C3E734FF60F7A82F55223EBFF8872C7A
-:104950003ECE14D51AE76744EFB55E827386D2FE69
-:10496000B31568872E912753EEF4AA2524BF5C4225
-:104970008EBFBC24AF1EFD94C00DCB1997873C4E53
-:1049800011585BCDEF3338E47EA24EDD3D8376894E
-:10499000C77FEA85BC1B7BC3F47A5C67BDD00BA6DE
-:1049A0009AF9BB8CB9A27DE150044DB261F19F5CD4
-:1049B000A13FC6EE763C177A2177581C7CB0E266A0
-:1049C000903F5FCA1276E408719F5D4BE6113F9CF1
-:1049D000017EA0B874C949A2FF18C809B49BDF9032
-:1049E00092A11569E761D677E67E22E24111B39480
-:1049F000F284DF12F1A09F8AEFCEBD23E241C745CA
-:104A00003CE8E7221EF40F180FC2EF87792FA77D2D
-:104A10001B57F7513FC67176D62CF01830CE547D17
-:104A2000F02504F28BE6A04FE4DF13BC414B0FCD21
-:104A30003D7F9C2A8170B9312EC5E17C597C8FEE77
-:104A40001501D78080EB350197A507516E209DB1E8
-:104A5000B1AA9E491E06D55609CF7B515EF407497F
-:104A60005EF03CF1E01AC998305C4EC078A3D3EDFB
-:104A7000748BFE4E8DF2111D3BC77F348BDF3B7C68
-:104A800069EDACFD2C98268F220B5721DDE5C3FE86
-:104A9000A03C8A3671391EC57B176972D58AA7C1B9
-:104AA0008E8449EFDCC0F134927CB9905C2974C8E3
-:104AB00095DD2857A0BE1BE54A305DAEB4F6E3BADB
-:104AC000832857584A0F05239F4CAEFCCC5B668B5E
-:104AD0009358F2E56A6063B213C3A04FFD9F5E9FD7
-:104AE000BE2DE4C485F4AA95FF113019E9F53D986F
-:104AF0001782FECC7846F770147390F28972DB5DF2
-:104B00000CF341B66297D1E8CF2CA47C901DF33D05
-:104B10003AD2C5C3522284F8DC27F578F9BEE8FD05
-:104B2000682F6C9BC0E3243BFE788F17EDEC976EEB
-:104B30002F08E0394E6FAE9507A22FBE15EAA71ACF
-:104B400019D1C98A3D2B6C790F3FCFCA237CE4C6AB
-:104B500040FE003E1EBE9DEB1FDDE079205066CC7E
-:104B60000371FB443C488D85903EB649510FC561A9
-:104B70001A65D253BD619EBFD20B7E399E0FF636A9
-:104B8000EC9C83FA79C3AD32A37CF1CA9E7B50CEF4
-:104B9000744C5868205FBA4697BD89E6F8069FECCA
-:104BA0004DCF23C5E304AD9A9F1B8AD2CC01903729
-:104BB0007B4DE37CF74755E1F7617FF779F2E03B06
-:104BC0007343A3314ED0DBB83084F3F68E8A84F27F
-:104BD000283F650CD9031B476D5A8CF1A78EE51A47
-:104BE0004BB79386CD17B4DBD7569C516DE0F923B4
-:104BF0001D32F72F73C5F934F05525E22D7D9D0840
-:104C0000A76AF2FC115CAFC2D74BDF37CD6D00FF56
-:104C1000B08AAF1FFD57DDA78F46F9A136F0FC9192
-:104C2000CD7E7D31FA8D4E38ACF1AFCD966CFE91D4
-:104C30006EE52DD4AFE1E788453C6FA1D775FEBC8A
-:104C4000850E210F2DBF71247CB81CE7D4BD5E7B7F
-:104C50001CD082E74A513AE118295FE0D3CE7FA108
-:104C6000757FDEF38D9447B0265BB2DDAFC8B5F239
-:104C7000591AD784504E58F06CBE40FEC8A785AB79
-:104C8000B991B7FFBCD7FB3F6DDCFA6CAE1F814F0B
-:104C900007F01E65C7C499219443A978CCD0403948
-:104CA000DA73E23EA3953FE2D2F93F55957FE74E96
-:104CB000CE2EA2EF2CABD379FE08FD65C803D9C474
-:104CC000D86CF4775411BF71F2E985E077E68DDC9A
-:104CD000EC137E63D4319FC813618EBC1335C4F3CB
-:104CE0004BAC7C922E09D6174CE5838C38AF036F02
-:104CF000E385DC7FCFD17FD8BAC3FC7EA5957F3218
-:104D00002C8F64AABC1FB760581E89C847E9C935F3
-:104D1000E23C4F9CE795A0DAC478DEB03C92A9D380
-:104D200043F84DC96925A2DF0D8CBEBFDBE3E5F575
-:104D3000DE392C8EDF3BEBC53AF2532DA3BC9661D6
-:104D4000F92553D7109E341659C6CF77F879BF8509
-:104D500007677EC905E9ED027924419FF53D8A0880
-:104D6000CDD3E30FFFA48EE093E93CBEE04BC7C375
-:104D7000E9E35FE2E372B247E4E1F5E4DAF3F1EE8E
-:104D800013FB5221DA39F7572FE274DD55AF53DCAC
-:104D9000DDDDC0E395C3BE035163F7079CF1BC138F
-:104DA000425E5F68FDCEB8DEB611EE9B2DF0F13CA1
-:104DB000AE87961CA2BCD833AB40CF02BE1EC67CC9
-:104DC000969A8BCF67793D8BE7B3F41AF50B2F4595
-:104DD0003D16D518CAD35ECC6781F71B1A46C86743
-:104DE00011F1442B3E3A523E4BEEB9F3787B3E4BE9
-:104DF000EFAD3C9FA5B787CF638DD7DB504D76D6FF
-:104E000048E33E3DC6947DB8FF1517777E3AAD2442
-:104E1000F26798BFD253AAE90F1A482F9C9EBB1A7B
-:104E200035A2EF2E17F76363A3B9DFCCD4786821DE
-:104E3000B4D9E24F2CA278B2C8CBE815F7E7FF3E11
-:104E4000CBB0D9C79D8DDF0DA15D0F74F8B2CEF93F
-:104E500084C6C9574BD7830DC8DC7A8B893EE540A1
-:104E6000368F23B842C706EAD2E8748BD077881F02
-:104E700019F0932B9DC357542EA0E83EFDAD11F4BD
-:104E8000F946369FDFA243A64E0AF3F33F568172DE
-:104E9000C4F25F87B5F3F076C3E48F438EF4607E8F
-:104EA0001B562C797283254FEC7469C90FE6903339
-:104EB000E7E4C91C6EA79F9327203FF053674E3944
-:104EC000D4EBE5FAC282C78D8219E4C87BAEB02D5F
-:104ED0004EE3943B17E2A3CF5BEEBC949D2FEC0F07
-:104EE0002E7782481BC837D9D63922BFF77066EAB9
-:104EF00083240F3D2A5FB727C2E87702B08EF2DC29
-:104F000083E72819E57AB544F106712E922FBE3F4A
-:104F1000F8B02B4CF9690F033FA39F37C170DA67D4
-:104F2000E73F57709E273DBCF66BDC3F037CA3DF59
-:104F300075B172C892131F66F3759FA32F93C3694F
-:104F4000D1571A3DD3F7052CFAB5C6B5E898218399
-:104F5000169C875E055D63389AE2D431298E711004
-:104F60002B8FCC1AEF0D1FB74746BA5F65B5FB8E86
-:104F7000E5779D8B07EB019DF2C97AE8BE39EBE23C
-:104F8000F43787ED56D754513E81CA289F2052826C
-:104F9000FECC619FDD2FB6F2C1A69584432827364B
-:104FA000083BDDCA23B3F2D20EFB72AD73665B7EA3
-:104FB000DA8611EE67BF790E3F17FFFD13FC6EDB3B
-:104FC0006AAFF938CA45C09729BEE7447968D6B8B0
-:104FD000DF15787ADD633EE9FB0CF7275FCCB2E79B
-:104FE0005D75FA0C475C80E375A21EABA7FB785198
-:104FF0007EAFCA79AE3ED2FD57E7BDBD73F75FC540
-:10500000F97BB327FA32C1FF22CF7FD3C3D1839D6F
-:10501000ECF35BCF01AFF9131CBF53F0F7B420BF23
-:10502000B7F3BE27FA363EBF8E71BFDAB2730E6396
-:105030003BE8EF7F19A436D0CBA65A4EAF45958CEE
-:10504000BE3F3EBD95D7772CE5DF35ED7F9DDFFB7D
-:10505000D816E5DF33857E7D32E065C778AE0FF781
-:1050600057F17EFBF17E13F26905B7BBF2307AAFE0
-:10507000A0B88E5239BDA6C73B01DE1F582A535C2B
-:10508000748FE08B003329CEB1AD92CFB3AB427EAB
-:10509000427C8F66D12D50EF9CBD7232DE2FD92E0F
-:1050A000E229FB16AF7C02F3FA3E08940BBA4BD010
-:1050B000BDD79EE3B7517CE4A12579D24A58E3BE1F
-:1050C0008399F35BAAFCAAE817738B789228131ACA
-:1050D000965B4D91B7DACAC4F7D8631AC69F9E197A
-:1050E000E479ABDDAB9F393613F571A54C79665D7C
-:1050F0008347BD97E1BAEB785E4F919A90D2FD1746
-:10510000AFDFC5EDB49AA31EA36A78FB67068F12C2
-:10511000DD6D07BC2B69FE9F2CE0EC467F02FAEDAB
-:1051200075F50CCC84767BC7E5493123D56EB49FE9
-:10513000F35FF712597C879ED1771C3ACD531E94AA
-:105140009B9D78FE01EDBB6BACBCD41EBA97B577C6
-:10515000CEE4399827BEED061E2CED0A1F223FB97A
-:105160006736B7CBF64AD00EF6655F8B763DDD63CA
-:105170006AE571222833C6897A311118F12ACEEDF9
-:1051800028F505E6ED6CE81BC0798AEAF8F72D8A68
-:105190006A32F77F21E0A6FEFB5C318A7F8EB47F06
-:1051A000FFEAE3F8ECACE2E7058CC5292EB55BF825
-:1051B0005D4C8D1AE9DF096D0970FCEC743113E365
-:1051C00065BE3A8DF4BA1C36C80EF583FD88F1B879
-:1051D0006D526C31E687C42669EC71C288E91D877F
-:1051E000F1BB097961A4BF4D522284DF558E8DE356
-:1051F000F1EDA3919D74EFEA00D8D1140E6609D2A7
-:1052000053DDD13CBA0F7534523D48FD7D15BADBF4
-:10521000D22898374F1F8A646CD2659BB6A25DD3A3
-:105220003945D6316FB353AA8FE278B15C0FC5917F
-:105230005D53E6D1FEB946E549E9FAE8463FD70BAA
-:105240002727446EF4C3BA42534EE562DC727BED0D
-:105250002BFB70FF1EB9DF4374F448EDE0DD38CF5F
-:10526000FEB3571D8F125FF2F3BA476B4F97A2DD63
-:10527000B3ABE9542EE2AF18E373A00F8B2B781C6D
-:105280000D3520D9676A0FBB19F058DCA631234DC4
-:105290001F7B193FCFC33FDF64927BF4F7CCE0293B
-:1052A0004F0B8EB784252E0DD0730FC6B32C3953F8
-:1052B0005CC71205200FF7AF78278679728F4C2CC8
-:1052C000A07B9445E23D494E18AF448CD7FFC62BD6
-:1052D000EBB1DDA3D50506CA8BE281A179A8248AAA
-:1052E000AB4E539C2D64DDFF881AFB6F25FA94E9C1
-:1052F0003B95C5E177FE02D711F0F5919E83F61438
-:105300003773AEE3E309E67D88BF6F4AADAF8E0B1E
-:10531000A6FC31FA437EBC97DFCB2ECEFA87B94A82
-:105320005ABE6D89880B6C920667935DFA00B7C30D
-:10533000C7B238C9B9E2AAD8DD3CDF364AF9B6CEE1
-:1053400079B7FBCFE95789EE51E737897B25FC77A1
-:105350006C4AC4EFD838E93E14CAAFEAB82A55DF20
-:10536000173D45F4FFB466DC95E97B0FFB845CD800
-:1053700024FC316BFCB1B97C7CABFEA8CEE9F1E931
-:1053800097F3AEAF82F5FC555BD9248C7FEE18C144
-:105390008F5B19E0F4973D00160EE881FED75EF3AF
-:1053A000623ECBD3325B8572AABE2AE14956093CE4
-:1053B000C2F8E48BC1F807C2DFF6A05CFA6AA092DB
-:1053C000E05A3195C70D3AAB1EA473A090CEF50EEE
-:1053D000F227CA775F282661DC7B790DD30F8978A5
-:1053E0004B0CF04F77E76596CAEBDF9E4B7E0EF0D5
-:1053F0000ABF5783B94993C5EF4F94E339D1A6BB90
-:1054000045FEAC8CF8EE14F300DFD23C078AC438BA
-:10541000F771FB1FFD0BEC5F2EE629AFFBEED750BB
-:105420008F17E99C2E52F0F57908BE5699117C6AC7
-:10543000E255F443B74F2A30906E0E84C26F374165
-:105440007DF92295E2F1E5351C8E03AD32FD1E900B
-:10545000BF4E3B48F7C74CD01769F832C4BC45353E
-:105460000909CFB58C56BE2E68E745B96884011E80
-:10547000A81B625DE7E09FA411FC459E41CC2D3A3C
-:10548000878795381ED0EFCA3ADECF1FEADB8272DB
-:105490006C791D871BF43BC15314D60EA2BE2F0A94
-:1054A000F1F196037E0E4929B8B22DB8EA64CABF5D
-:1054B0002AAAD10EA21F9C2DE05B19E6F0F4BF7E54
-:1054C0006A40E2E319385EB680375BAC9F12760B18
-:1054D000847E80F19E7225EAF15ECEA929CC38C483
-:1054E00067A37896F57E572BE001F0E317F3B0DD64
-:1054F0006EE2275862EC6399FF7E889116B7A8D8B0
-:10550000ADD9EA7EB17FAC8B3F273F8E5422AFCB23
-:10551000C2AF5B5965EFC76AD2EA6578BF8CD3FB2F
-:10552000FA6BF979C78109DC3E42BFE31C7F239DFA
-:105530004F311EEB0AE27B8DF45D49BB7DDCE2D688
-:1055400082E9281F8A071E9E27C37A8AEE65B292D7
-:1055500043F42C9D937F30DFB7D724E8FE6CF640F0
-:10556000240FE55D496BDE74FCFE5BF64094EAD9DE
-:1055700003AD26CF3F0317260FF3F5D2E6294539B1
-:10558000CDF3E958ABD68772AD361D4E785FF27217
-:10559000CF5CECBFF9EE574623FF1638FA7B72B8A2
-:1055A000FF50FC32B40AE0FCA7D7627B2BBE938D80
-:1055B00010E751F93296C53E90C7509688FC3B4B98
-:1055C0005E744E786752D427E887F2F15822DDCE18
-:1055D0007796D07EBC681F93CEDBEE34B51B29DEF8
-:1055E0003410E0F1A680B0577B98B19FF47B0DCFCB
-:1055F000F7F0E173D01F7D3547A7D37EF6B130D2E7
-:105600007371DB9FDCE9F2FAE640A9B8079D20BA86
-:10561000D74AB2E87C0FF898BE6F7A406DA573D672
-:10562000BE227EAE7974CE2B12E2B3E8399EA76D0E
-:10563000D9CBD36B12217CDEF56AF432E2CF11ECC8
-:105640004FCBDE74AEE792FA07491E8C8D322F9E47
-:10565000AFF957AB94C75A1205B8AA502E00491794
-:1056600002FC35B1F548374694D78DD5A25C05E5E7
-:10567000D560DFAE1B28FFA52B35EED60AB06BD167
-:105680007E1ADCEDB901ED9556B0460CB4174F7992
-:10569000F07B2ADDADD3F311CFCF442CFB3221E1D7
-:1056A000F8453F35C95EACD5351DE33013DC89D1F3
-:1056B000E9E77407E6BC534DDF139B7F71F9642360
-:1056C000E91384454ED323FD554749BF3CE11F4FA5
-:1056D0007AC8D22B961EA11141BEDC22F8A8CB4875
-:1056E00078249257C0BB00E72D2847808EFD455C8B
-:1056F0009E831CE672CED2277773BD6FC9CF0A3165
-:10570000CE2D286FA15F77ED13B937A05C1172D64B
-:105710001F3266E2F95C8590AF4C8D4938DF8129F4
-:10572000FC7B9501873CAD68E5E3748518D113E8EF
-:10573000A1834837078A12744FFC40EB5129FD9E24
-:10574000A9A5EF02AD4986FB3FAE8ECBC17142AE3B
-:105750007EC76F70FAF470B97A4EEF0979BBD53C09
-:10576000CAC4776133E661FDBDD0E73D1587C82F18
-:10577000D876EB29C2A7150F0D89786877D55BF429
-:105780007E7B94DF03D8654E9F43F047966B947FF2
-:105790005A73744E19FA1B4DCB35B4EB4E060AAC56
-:1057A000F32FEF42B4275B5791FDEB13FBF85098B2
-:1057B00009BF53233FEBBEA5DF1EC0FE21F08B24A3
-:1057C000031BF579DC48E7F83D05C47774903AFB94
-:1057D0006A0CFA0E84731DDF0BF0EFD2FAA3C981B5
-:1057E00071B4AF325DE9F1D530F23B97835F87C387
-:1057F000EE56C3DE09F07E7793ACAF67A9FEFF2BB0
-:10580000C0F3D126FAF93D859D8B4F6FC138DFCEAD
-:10581000A5E23B670EF8EF6BECF328340FC60428C3
-:105820008F39E3F7F6ABFC59FCFB0B357D0368CFF2
-:1058300007AA385C2F060C8EF7418EC79E884C7CD9
-:10584000B46BB0DA8BFACE69373E92FDEE249ED768
-:1058500062D73717AA173BE4FE0477DF7524EFBE43
-:105860002993BC628CCB3B89C906FEAE464B80D3E4
-:10587000539590D71DAEC47ECC2BE878D6C7D61BE7
-:1058800029BA28126376B6CA197F3FED5040E1FB72
-:105890003F7CDFB9FD20F6FD4981870BED3F86593E
-:1058A000D09EEE8B6F1A7307CAF156EE3FF725DED6
-:1058B000A2BCA3A2D90BC9EF3972F052F2078AAA8F
-:1058C0004CDBEF6B668FE0B756E478CE1B0F1849C0
-:1058D0001EEF5BDD417EF6BEC1CCF7620A72785ED8
-:1058E0005A1FC84BFCBEC948F3EB399CFFFE292068
-:1058F000E86ECE3BF4BD8C343DFBB2D0B3A46F8BCD
-:10590000551653D2F21C2608FC39F52753E39E4B5B
-:105910006B88CE097FFBC4F9C543A64C78B7E81C59
-:10592000CF0F10AFB00E53D0219D6FF4B0B807F970
-:1059300026D6C4F33C9C704FF0CB17B5BE600EF773
-:1059400043CECD27FCF5897E0EF7CEDAFBE99E2308
-:10595000CC1742FA907EF01FA7E93ED4B32EFA3D51
-:10596000DB19CFBA1218D3BAF320FFBD45F9452F82
-:10597000C1F9CF87F9F7D5137E6E8FFD5AE7BF5770
-:10598000F455F760F717A03EF4ACC2C89E8C83E2D2
-:10599000027A3D2DE8953DC7EB2BBDBC7AE7C1FEF1
-:1059A0006538DEAAE7781EE69DCFDF76E317A07E96
-:1059B000DB808BEE0CDCF9F87A6D0CD46F8F4B7DAD
-:1059C00058FFCD7446BFF719CBD328CEF59BC060E6
-:1059D000C102C0F707EB3CCCB80CE3A48305F3018C
-:1059E0000F77C49F9E89FDEE784A0A23DBCE78F6B6
-:1059F000F15746035C777E43A2FCAFAF1CC9B6D912
-:105A000085A76129D3E0FD9A83FC77236F633D333B
-:105A1000111F773EDE4BBF7F68E1F3837595CC485D
-:105A2000FBDDB03BBFF134FD9EE15DDF92E8F71591
-:105A3000EF92F93DA27F7EDEBBE8311FAE6FBD76EF
-:105A4000A91FD7B559C376B7C55BBE8B294D77C49F
-:105A50000F6A33E1FD1D070E6A2BD12F73B366D495
-:105A60003F5F3972854DEE9CDEA7907FB026D7430D
-:105A7000F7EB99CF0CCD9B307C9F3F58C76C70DD06
-:105A800061C509D4B83637ADBD4BE7FEEF578E2858
-:105A9000B6792C3B20768CEB85D8DFFA297E6EED2B
-:105AA000DF1AE1775BFBB7C60AC4AB439333C1D3BC
-:105AB0008DFB01F0F4ACD3A9DCB92E44E5EE7506FC
-:105AC000EDD35EC423945D02EEC054568FDFE70F22
-:105AD000983CED38AFC9ACC7BB6579115E2F581241
-:105AE000253F64243BC62AF7BAA22DE84376EEE8A8
-:105AF0009FA582DDB3578BDE8D912FBDE3D5590D68
-:105B000050FF9B9CC8C61C92376103F9CEF2CFBFF1
-:105B10009EC3E5EEA6D11AE17BEFD2C98F2996FF8D
-:105B20008571BFA52B9F407B02FA6FCF21BE0DD39D
-:105B300077BA46EA5FB0ACCED6BF60D92AABFF1EBB
-:105B4000EAEF397FFFBDCBAEB1CFBFEC0EABFF2389
-:105B500004BFEFFCF017344FB5CFDFBC9AFA7FD506
-:105B6000CDF77728D743F9F41DDE70C245FE33A385
-:105B7000EF73A879971EA2EF279D8B330D9AA86724
-:105B80007D4FE556A31C4BD1D1F46FE23AFCC05DCA
-:105B9000E97494539765E3AB5C33CF56CF9F3DC612
-:105BA000D67E54A4CCF6BE70D1E50EBAF4E99407C3
-:105BB000CBB83E3531CE09706A63F8F79AEAC778F8
-:105BC000687DF7BFE8A5FAFDD7F0F5DD3FC6477C55
-:105BD0004CBA0BF6FD7E2D7A65BA7D0CEB9230E463
-:105BE000F58C1E1DC8A94D7F6EC8F83C4BE1BF6304
-:105BF00097E5E6FA7273E9E4C76269F8DC520CF4DF
-:105C000000F5B773345B9C6773F1CA504BDA3C9B69
-:105C10008AB54587AAF8F35BD08ED7237F87F37DBB
-:105C2000551BBA14ED57E73CEEB23ADB3C9E925559
-:105C3000344FD2318FBB6495631ECFA243E2B99833
-:105C4000E714D2C948F36C2EBBC6BE9E923B689E39
-:105C50005FE33CB569EB29B9C3314F165F0F3C17C1
-:105C6000F3FCE6BCEB299F6A5FCFD8D534CFBF3BAE
-:105C7000E6718F5DED98C747F3E0739C8715713F20
-:105C80004A730FADA4FDFF8197611C487347FF9ACB
-:105C90002EA9FCBD97E2C2D0CAC476FF07FE2263DC
-:105CA00096008000000000001F8B0800000000002C
-:105CB000000BE57D09785445B670DDBE4B7727DDD6
-:105CC0009DCEBE10C20D288B86D88190015CA6594E
-:105CD000E4A122065770810E4BF6A4A3E23C1C758A
-:105CE000D2104554D446518306A6C1A0E0800626B2
-:105CF0006880800DA883332E719EE3320B368804B2
-:105D000021260DA2E29BC5BFCEA9BAE97B3B1D604F
-:105D1000DECCFFBF79EF8FDF4C51B7EAD6AD3AFB4F
-:105D20003975AA9A0C4F22641C21FB12683986909F
-:105D30006FE33C17396D84FC007F3F26F4CF474862
-:105D40002A2FD3085940F85F60A9408A08A9B5B046
-:105D5000EAFC4D33721643D93629A3A490FE63A5FD
-:105D6000DD75BE4A4877DB24655E5E643CAD5CE071
-:105D7000978F8486B3777F2091EFF82692E175F4B0
-:105D8000FB65094E9C8F563F524FEB66420ED51372
-:105D90002C3B6532A7983E3F5C4F27304C3FDFC518
-:105DA000F8DE1189FE3385964D42C027D075ADF8D7
-:105DB000402643F0331F0EA7EBB8912F63813F9E1F
-:105DC000104B641E5E3371C37BE1EDE6C03A019E69
-:105DD000BA07983268D1984C8836DFC184FC69F7DD
-:105DE000D56F090EAC0E308D25E4E6655BDE846E62
-:105DF0001F092503EFA0EB9DD9BA421E40EBDD72CF
-:105E000068B6CBA61B67A67C08D66DA1FFC138B3C8
-:105E10003CB4AEFBFE2DE5C6FA6D448AD47309B9D5
-:105E2000D03998E3837F570DC880AF1BE99A322998
-:105E30000A6F837214343B115FB39DEC5D6D3EDEDF
-:105E40007B641284F948A15492072DA9D8CF03FD91
-:105E5000D4BEF39B2D5BDCC5149FB3EF16118ED11E
-:105E6000F30DED8E779BF269D9F8B54C069F7DFE58
-:105E7000731619DB898F7D4F83AB460737CD9CF0B6
-:105E8000E4611D7DCCF25CF1E461039C6618EAB725
-:105E9000D5CD32F49FB3A8C4D05EE2AB30B4CF5BB3
-:105EA00076BBA1BEC07FB7A17F59E362437B45E0CB
-:105EB00021437BD58615867A4DCB2A437F6FDB5AEB
-:105EC00043BB69F7886B088563C3EF4462A670FC27
-:105ED000C676E4B18B53A0945C00F7A3F51948D7BC
-:105EE000C7EA552C6B81F6C601FF8CB678289EBC9C
-:105EF00071E1529248C87DFE4B962DBB84D615DACF
-:105F00003E9E52BB7FE2325F3621CB9C2AD2BDD867
-:105F1000A8902025558124F5D27558D4B587CED2C6
-:105F2000DE2891E0E8BEED6228F6F31E213C348BBA
-:105F3000AEC3F7A999AC17FAF279842FC90092D1B0
-:105F40007F7B978994B7E8E4CE7AA709E793EA9C28
-:105F5000B8DE49E9A15A61FC5EBD35732271403D4E
-:105F600038B4CE7686EFB5D0C9A4C3388C5F2A0288
-:105F70000322FC8BF81B62E0FB61099E6627FD5E35
-:105F8000D71E7126CC8304F7E55C3712BEEF5E0F97
-:105F9000CF491B1D2493F277BDFBC9C3E713F24918
-:105FA000FD542C7F5F5FFCE46199903FD6CFC4FA2B
-:105FB000817A0F96A1FA722C0FD5D761FBE1FA45D1
-:105FC000583F52EFC3F268FD322C8FD5FBB1BDAB09
-:105FD000BE11EBDDF5012C353EA0F2684E31F069C3
-:105FE00071B109F8F40E2BE17FAC7E92AF41A4FFB2
-:105FF000EE40BE7665005F9FB47D3B348BD2DBC93B
-:106000004F2831E5F60FA768BAEB1F7F6E13E0AF9C
-:1060100034408927B96FBB358EE1C76A2253099591
-:106020003F0F9DAF10897E3FEEF50BD789B9F85C25
-:1060300002D2A18AC335C31E63FCF308E2EB6C787D
-:10604000D2FA1F79F6CF4573F3003F83914EE2F603
-:1060500089750C6FCFBB006F67839FC4F92B1A8EB5
-:10606000C2EB7FCA09D1FE5FA56AF0ECC821B4BCBF
-:10607000CE597C14E8E064AB19D775B23D3E406060
-:106080000C670AD245FF7063F3A8DA60F5EBE543CD
-:106090004D4BA2DF282F32FD7A797172FFF30EE0AB
-:1060A000FB3B3244FFE1D1401F6E4E1F8CEEB4F13A
-:1060B0006B5A72FD36C338C6FA49BF30B505E5BC28
-:1060C0009A70FDC8FEE779478682DF39B6614802DB
-:1060D0007CF758BDC50FDFE9AA77FAD97733FC7A88
-:1060E000BAAC5E14EF3F9C1C995F7FE3FEB3E747B9
-:1060F000482BF9DC4210F43F0CE9BF7FBFF8904E0B
-:1061000029C5401FEDF2B7A077E2866B7A47C2BA85
-:1061100036AEB745F4992F82E79B0CDFA3EFA94772
-:10612000343C0D3E13DE2572445B27959323A9EC86
-:10613000063AA5C48C78F6D01113E8783D926D9993
-:1061400040BF634E54B1DD0B1FA2F4546309291EF6
-:1061500015C1DD0176D6DCB11ADFAB37FD8192DCEB
-:1061600097BF91C9C3D0FE173A3A6D9779EB7C522D
-:10617000EC20F47B735BABA6819CFCF2D5ABB89DA5
-:10618000E22F82757F454C53814FBE22BF758CD65E
-:10619000D965D3131536BF654C3FFBE87FB03E6A27
-:1061A000A719F47559A3B15E4AAE4D037E285D2947
-:1061B00093009D7B05E87B6DDD94EF2F4B64765C4F
-:1061C00019A95B0A76CAC3329909F89EEB24D2005A
-:1061D0002A276A5E5B5D5442EB37249A90AE8E515B
-:1061E000FB4EA572A82289D931952901C54DDB3F07
-:1061F0006F1D7DE3C504DE0F2C05B9E6B313D77A16
-:10620000D217EEF39619E777B6F947CF979025386E
-:106210005F6D1EDAB8DA3CC40D823B10C39E9D97B9
-:106220002844EC645ADE9968B45F17415D67DFDE8D
-:1062300017555F1255D7E844E674624EF42C4A4C69
-:1062400005BA084F413B8D50FAC88BF45322FDEE3E
-:106250003B533F33F413B1DF9233F5B346C67B3083
-:1062600056BF9AD736BFEAA3F454F9CA530E42E593
-:10627000F997923FCD459F57AF7FC001703A2AF9F9
-:106280001C80EF2F03E2D458F0DADD0B2FB74D005E
-:106290003F02499BC2FDA547A6839DF4ED7AD9290B
-:1062A000D22EDE0DE6A099D26F6D6BC534928FF5BC
-:1062B00083ACFEE00911EA6D467C56BEF8549A6A3A
-:1062C000473C307B9B04D1EEA86DFE620AC8712F5B
-:1062D00009231D46BF07DF3F9D847C5FA224F46D28
-:1062E000A7F3443BD9CBF9CCDBFAC809D101E515BA
-:1062F0009DC067DE283A2AEFD52F21A598CEE795D5
-:10630000447BCA910B69F547E447200F34B89000ED
-:10631000B32B1A363E937F90CEABABF9370E214F9D
-:106320002F47183D9E6C99F7F31D6AFFF2A69BFB61
-:106330004591F702F89EDAC6EC20D2CECA6A39E857
-:1063400000BBB37AADECA2944AAA373FFFC2B3E0D8
-:10635000AF7D6A467FAD6AF39B1F8DA7F5AA2D72AC
-:10636000CA34B61C9B9016C18F97FE6FD1A8083E09
-:106370002A7FF9A6A28E64CFEF4D8AE0A56ACB1ED4
-:10638000858CEC0BC7492D7B94902D067E5A0E4EC2
-:1063900001BBA561E3770AF85F5FEE16487A6EDF0E
-:1063A000F7CBD7BE897A11E084F8E4F8EAC55F1F1D
-:1063B000BC05A7EF28C47E4E909767C39B9FCBE98F
-:1063C0009AD7EC2491CEA3FCF7E6C034C0E7CB7794
-:1063D0003A603D9D521DA3F3D50FA4B9E9F7CB65F3
-:1063E0005F9A134BF6BC7CCD5D487F65425D9A1386
-:1063F000F9C99D6942D9EDCB84752E68BA01D75988
-:106400004A3C4887E5ABC5E2002DBF91C8D42D3189
-:10641000F8A42889F149E73A8A5CBACE4EB0FBC1AC
-:10642000DEFEAD18588FFEE9ED04E4FF5D7CCD542F
-:106430005362FD1B0BC3972DC9A4F98B1603FD36C0
-:106440003FD801783A36D09D0EF3A470F071B809A8
-:106450003FD071C50F2E4F677822AA54C4DFA3FA2C
-:1064600060123C87FE1DB2DB9A6F788FCB4FF6FD32
-:1064700085FCFB74DE71A0DF3AD3A87D1F637D73BA
-:10648000617DA817A99ED3D1998EDF19FF373FC42C
-:10649000F85DE3FFC08CA9D07EEA43C647F01EE852
-:1064A000133AAF603AB6EFB95E40F96026C1587C46
-:1064B000DE2C733E37B67B29BF429C40A3133A7F44
-:1064C0004948D0D30BFD4E12E201FD95D295F47DE3
-:1064D000BD7D03DFC57E4AE4B94EAF9471B95090DB
-:1064E00044E5417C441E90A6D473B223AB65E2031D
-:1064F00093B3FA5333FAE3D59BE56258FFF14DFBB2
-:106500003EBA99D2F9F1168D6F8D72359A6FCBB76D
-:10651000AE17804EA3F9F67839D5E2B1F8963E8FE2
-:10652000C9B7E5A1FFA7725583DFAC24A33CA5F250
-:1065300071109810FDC1315A3E7E03F6566A5FF91C
-:1065400048FF3E24457DE950A33F8DEEA80537085E
-:10655000E47A2F7D6AF4D74B9F1AFD45AFD708BF69
-:10656000E8F6C1E023513A29DE4E2D3A8ACFEA7689
-:106570002160463EF7BD35A010E1E446F546FC6FCC
-:106580000D48D1D70351F596A8FEEEA87A71547F35
-:106590004F54BDCED0BFBA6D9F4210FF41433FF371
-:1065A000A2E7C8E731FC414DFF785B4F283EA08B46
-:1065B000ECB002724F5E424D3788AFED1231BED65D
-:1065C000A3861D49F4F90356E6A7F538793D91D520
-:1065D000C3A9CA52907BDAF3B095A07FDE531C7634
-:1065E00024EAFCFF83EDA243A5EDA10099AA8F2325
-:1065F00044E6D380F80E91FEDA59DCB027CE918FB5
-:10660000DF8BCB0900FD5D2EDA721681BFE7175DC7
-:10661000947CC8FCC5373908A5B39EF621D7CCA415
-:10662000CF17BC2D82B94DD1E3963229DDCCE3746E
-:106630007C94F89EBE84AE6F5E3BB3C3E72F8F4D54
-:10664000F795BC7FA96DA102F295DAD187F471D1DB
-:106650004AB21CE9AEBC29EA79FB55C81F9551FC2A
-:10666000E1E1FEC32E8D3F0A4801CA174298FFCBD5
-:10667000E5F2E562DE3533291E7AF68BC4AC823F43
-:106680002B92A5B0CE4D4200E205C4978A7C564BB2
-:10669000C2280F353875011F0DEB5F4E756DFB532A
-:1066A000D13D402FAFFE21FF395A76BDFAE9D09D8A
-:1066B000507FEDE39C3F90BEFD27EDFE7E36E8B3B4
-:1066C0009EDD668C8BF5ECFE55CE3D50DF61C6B885
-:1066D00058CF12B31BF8C0B7DB1E381FDA0732FFE2
-:1066E000A161D777F921D4AFF723DE8E2631FFE5FC
-:1066F00064FB9F0F082950D25581FDB03B1EF9C89D
-:10670000BBC38AFE7ACFAEEF8A3CB67FDE7A6A15CB
-:10671000E2417AB493995B817E1359FCD8BB73DC58
-:10672000F38BE9F76B5AF728F368FBA4D7FF9A0FAE
-:10673000F2B3672BB38BBAE5D01AE222E4EBA4B232
-:10674000876488F301336511F278F2862B7C79B186
-:10675000E0C2E0D043E100EBA2702907B9DF1F3CA3
-:10676000E29215A4F77F3D789C98CDE4DA8F08C4B7
-:1067700085227011DCECB93D601170FDECF9EEEF93
-:10678000F241EE1C6F598CF6CAD9D63D22F95F95BD
-:106790000EFEABEB1682E7B2EEA9FFB2F866F4FF8D
-:1067A0005E928AF38CE683BE74FEDA4FB0FEB2DDF1
-:1067B00085F33D47FE2FFFDF86F7AD14EF8EB3E381
-:1067C000FDC1FFB1787F9BE3DDEE34833CDBF55701
-:1067D0008CB36AEB3FDBBA5FF81FBA6ECD8EFF95C4
-:1067E00049FDB080F67F9BF83F1C4AE7D994BDEF86
-:1067F0008302DA3A5120C5B1EC938F92991F385138
-:1068000030A1FF471205EEFF31BF6900B723062C08
-:106810002C457B6340F6A3683710495D09FB77BFC1
-:10682000CA99E77A187B8CFAC40375E7A5BC6EF4A5
-:106830001F9F13885BA036E8809CABF683FD9A9D72
-:106840002DA27D4B4BB46BDF704C65CFAB1583DF56
-:106850007405D1D5E9BAA6A418FDA2C97CBCCBC9E0
-:10686000E00F0BE8FC2FB7C8CE0005D115133C1282
-:10687000ACE78A4C81F875FB4793A3FCA7ADD4C65F
-:10688000D4C7D7FE5EF85952989F395118BCB21838
-:10689000E03750C4F8E159E107C61EC2AB20F03022
-:1068A000D845928BC12FA9C685F157EE57C37633D1
-:1068B000D82B926D6907F0AD44A85FCCE68FFEB48B
-:1068C000E617F70767C2FD6C897F5283BB942DBA28
-:1068D000ADC6F1101E1A3EFE5E3C68F8FB47F1F1B2
-:1068E0007BC0C798083EB24F3925E0CF49DC1F98DE
-:1068F0007CAA43C47AB64BC2FD17EE0F4CB0254AB2
-:10690000E00F5C2A7D20025F9659B657C23E82C5D1
-:1069100025205D0FEB32A1BF63291410EEC31B25A8
-:10692000AC7F60728E01437BFAC5AF1DBF9B403CBC
-:10693000D9AD30C3BB98C5F3FFF2C30F9714415CC8
-:1069400085FD95D1FF5D4DFDB1F94D241847E1B4AA
-:1069500040223E487158401775C8100F36D6E1EFF7
-:10696000B2B4C83867EBDF9F1CF96797AF51B975B0
-:10697000E87C42B643C982FD92DE6FFE513B8397AD
-:10698000F71D12188CF106B758ACDB67FBF714261D
-:106990003F5EFBE3D6D1103F9BD09397C0E469A143
-:1069A00009E8D2CBFD8293444D807C8593ED431260
-:1069B000701F71BF68F7C488DB6CE4FEF42FEA3106
-:1069C000A84C7A9A895F04BF8984317EEB6BB6C488
-:1069D000DC0F9E9B62E274C3F146FFC422D8B7600D
-:1069E000DF5F405F4DD0E3AD6BDA97527E5F3CC016
-:1069F000DF21DDFECA3F0A5FF0DF01BE1BADA1292A
-:106A0000C531E4C7420EBFE97BBFC778E705ED6B30
-:106A10004D40BF17349B0CFB93D529DCEF1A45463C
-:106A2000C1BCA6EFB5DA0B012FFB459795AECFDBC6
-:106A30007E42F1C4D8E78A86278C0F71F49752D82A
-:106A4000BEC04EB9651EC075E75716E2A3F8DDAEAD
-:106A5000F8AB62CD33258DC9B905A4E5CEFCDC7F4A
-:106A60003DF84EE8B10527829FD94C785C239AFE09
-:106A700008D2F1C90D2400FA14FC52900B273711EB
-:106A8000D4E714248F825F4DF9FDC7FA38CDB0B634
-:106A90002DBF003BA0B65D709A687BAD1452201EDE
-:106AA000EB6D4B1441EF16A8C48DFBC39273E4F554
-:106AB0003ABE78294542F8EE1BBFF316F8EED75DD3
-:106AC0000A017BC4FD46D8017AFBEBF6D1C807FD6D
-:106AD000ADEB97F5A472B20CE33079184D0F799BAA
-:106AE000E20CF58B454F16F0D7747368A12B06FEA8
-:106AF000A6A5323A3B67F916F8FF4CBE7DA8C93708
-:106B00008F58ACE3A3945446F73AF9961E4BBEDD7A
-:106B100021A8E900F73B760D4907BCDEF1B69C1AC7
-:106B20004BBE6DAE67FB7FAF507E84B2A795CAB7F0
-:106B30008B74F2AD95CAB7DCBEEFFDED5CE55BE0B2
-:106B4000BF87FF36837C8BB1DE440E3F4DBEE5B779
-:106B50001F44F996DF6A22AACE7EB0A49E4DBE09DC
-:106B6000A9D7833DBC5F76C5C7A09FCDDCFE7E85DF
-:106B7000E7EDC17740CEFD5B2ADB2F3D5739979972
-:106B8000C6F8E4AC72EEBF09CE9A9CBB631B95734A
-:106B9000B9B1E890C9B93BB6533927003D323977CE
-:106BA000C72EC2E26F51F26D781FF946B07F6D902B
-:106BB000BDEF6DCB7DE6563ADE28B7ECB2D0FEA332
-:106BC00022F26E8C5EDEFD5BAA8470EE23EFF69FF0
-:106BD0009BBCDBC6E51D95638341BE46D387AB3DB9
-:106BE000CE50DF39AE73D32F815FDE15717FF10395
-:106BF00013DB077A6F5C6721D0D72A3E1F2FA7BF10
-:106C0000EE7A1F8E3FE90DB6BE9A4D2CFE5DDBCAB3
-:106C1000ECC3DA6631A0D27F4E19FFBD02F3AFD8C4
-:106C20002590745A9F61F63F6D0319FCA24CB85F22
-:106C300034AD40470FF3C756611CBFC1EA5847281F
-:106C40001FCF978805E2F555B6295F821D5C359602
-:106C5000C5F7ABF873C2F306B43CC8D2B6DBDF1A93
-:106C600040FAE60F4C37333C4E7F5E08ACCD85FCD6
-:106C700025637B5554FEE3637C9D33C410C285BC01
-:106C80002FC6CC63782C1A1EFB393CE8FA0DF008AD
-:106C90000831E141313AAD202DB2FE8A77434B21D4
-:106CA0009E5FB14AC07D5F0D1ED1EBD4E0A3C5A7A6
-:106CB000ABF8FBDEF6DB71DF3F7AFD1AFCFAAC5B6A
-:106CC0008367D4FAFDA97CDFAB808C867C1A4A0FDF
-:106CD000283F7CBFA670A0DF299E707EBA5E1E3F53
-:106CE000CDE130DA3F61522601B8913AA09FD2C679
-:106CF000DBDFCAA4EB1FF3893A0AD4E4C5E3CD1E57
-:106D0000D847DD680DA37CD3E8AB53A3773ECECE46
-:106D1000ACBA89E8AFB7094EB02FBC412BC2D14BFA
-:106D2000E9CC4ABBEC5BF5ED140E47A719F98AEBE9
-:106D30001D0A7713F8539A1EA27007BE19DD7E0252
-:106D4000F7730B4918F74B6A1B055790AEA3B68D26
-:106D5000C14B93B7F4CFA6C7470C7A9462D1238175
-:106D6000207151440F56F17ED3CDFE8F601F663ADD
-:106D7000A5F7B52482C7E1F43FC063349E34789E02
-:106D80008D3EBFE0F6C76680A30DE0156676549091
-:106D9000EA057BA4DD2BF90C709CF4EC69465FBB23
-:106DA0000415F6137AE104F44ADBC7B4337A05B864
-:106DB000A900F7F61211EAA514BEC9B97DD709FBDF
-:106DC000977AFEADD875908DBF5A709118F4ABAD1F
-:106DD000BB3FFAFD47E9B6338A6EDFB386DF190D94
-:106DE00074BB4B607184F644C3BEA3398DEDBB6F99
-:106DF000B452FA86FDAEB765D73AB52F9F9FE6F03D
-:106E000004FB5FD5C5A546C002602F708305F3CF94
-:106E1000701E83997DA997AF9BAD24F5FAC2FEC77A
-:106E200057B83FD09F7DA3D547C2F740EEB5D1EF0D
-:106E30000D8F7C2F5ABE6BFEFED9D6959CF68FAD7A
-:106E4000AB377F9374E0FE9339D1734F0AC67F58F6
-:106E50007ED28D3C3F89CE00ED2C5DBF8CD431FDC0
-:106E6000F7231916D4C377F2BCF8CB451BF1D175C3
-:106E70007CED96914EA996FEDD25209727523D4246
-:106E80008BAFDF19F3F1ADD82EE27ED435EF26D7E4
-:106E9000C03EDD35208CE8F36B0A04D4BF1FC06010
-:106EA000E3C08EB510B79993306D1FFBA3C4C0C368
-:106EB000B4BDA0D93F49A5FC346A43A0014AD7A478
-:106EC00070CA7B00BF092201F875B8932781FEBA0A
-:106ED000F30B5220AAA867719C51FB492AF41BEFBF
-:106EE0004E4577605CEBCA49101F9DB1CF66033AEF
-:106EF0001FDE64221E1DFD8E278106D8871F77D8CE
-:106F00007D1DF05F39B51720EE5CDEBEB6C101F520
-:106F100026C1A5D2F1BD3ECF14079DD7E6C61353B7
-:106F20002E043EA4FD60186F13EBE76D165C902AEB
-:106F30005BDABE02F3714A9B05E284FE018158D8F8
-:106F4000B8010B1D7773137D9FD6CBE07D18B7F981
-:106F5000C487D7019FBF23B2F737B17DEB52FA9EAA
-:106F60000AF4DA7C3B8E57D124900C3A5EF926263F
-:106F7000FFCBDF915DD0DEBA6715EAB169F47B998A
-:106F8000B920EF8393A14E460B4EB0B749F6CDC85A
-:106F9000D73D9CAF49D74C2637045EE77E836637E2
-:106FA000ED4D63F9C1A5AEC54A321DE7BDB1A9B922
-:106FB0009026E06D3B81FBD187299C3D14CE1FF0CC
-:106FC0007C8E7D633F57423AFDF359DA10A4C3F932
-:106FD0006D1330CF610129C63C87E9E398BDF6FE09
-:106FE000A5D68040E7F5BE1CCE86E7FB2E35A3FD77
-:106FF000DBBD59C6FDE2EE81218C4F7736C904F224
-:10700000351A9A44948B9D9B981E1757DF30251391
-:10701000E0B75E7081DCDCD7344901BDD61910F0D1
-:10702000FD49ABEF4A637E0C93879ADF56EAAC309A
-:10703000E88F68F9A6C9BF1A0E87683957A3E9997E
-:1070400028395703FBCD0E288DCFBDC4C6E41FD809
-:10705000FD80F7E0F748BFB5EFC804EC7EE1F3AE82
-:107060002998B7057A93B68F6B17DCB0CF5FFE898E
-:107070003980F66AA064CE4F417E7F6A26820A7903
-:10708000F014EE542E8C3587FFF8247DFEE50716AC
-:10709000C890A174528270D6F2450BD7B3FC96C249
-:1070A0000F56A695021C2627A39C2D6B14894727F3
-:1070B0002FBE14DCD7DDCCE4B173BD4E1E152AFE05
-:1070C00052D05FCE742607D5F532E48C906D5C3ECD
-:1070D000517BDA0D7643C5F615690AEDB794E7835F
-:1070E00054EC5A914645036900BD45FB57286CFC9A
-:1070F0008ADD8273AD6E7CED7D6D3C6D1C65BB7170
-:107100009C21BB78FD1CC7D1E6A17DBF3F7B7CECF9
-:107110007F9C5E29D0F1C6BE2F6292F2D8CFA70D18
-:10712000D1EF7768A5167F2DFAD044DC3AB88DFDF3
-:10713000631C71EBE8A2750CE56F8AB7ABDB983D79
-:10714000D43AE6A05253887527F0732D8FD3D64ECC
-:1071500066FB56AD051FDC0FFC3DAD50403A203EAE
-:107160008F929C8276900AF1F1B242F67E197D1FD1
-:10717000F8AE7515E3432A0F549017B54D2BA66052
-:10718000FF664185F15BD796A09E2F1F2B126C6F77
-:107190003E88764779DBC114E057CA9F2B41EFD672
-:1071A0005E6276027F687CA7F1F1FB32CB0F21167D
-:1071B000E74838075096A6C6E45FF11DC2FCD44DDF
-:1071C00032F29D772CE3CBF7378BC8CFFB2EBD690E
-:1071D0000AF061F77AA11F3EA67C5A18E153713577
-:1071E000CBD729DBC8FC957D4D4C3E74B6323B7144
-:1071F000D26AF96AA897BD2B1316F762F6E0B9F2C6
-:10720000731F3B65436C7EEE8F7FA7CB2D1FDD493F
-:10721000E777CDCB74FE6A045E932EBBDB8171FAF7
-:10722000CB66E17A3539542AB17CA6F9FEC52CDF4C
-:107230005762796F7FF7BCA2E6F1609A3D2247441E
-:10724000A0F7449627DD2C23BD47F3E33FCA47FF51
-:107250002CBEDEC6E9489B8FB88BBD0F7965410A0D
-:10726000C75F6D7A1EF35ABF7AE9E074C073D54EDA
-:107270004ABF74BDDD9BEC2408724B0AA0BEA96C0A
-:1072800015317F9C48C1A2EBEC7AFE64F94955AFF9
-:10729000D8916E2AB7B2BCD3CA573FCFC77C9125CD
-:1072A00061CCBBF2BDC4ED4D5F281FE8BB526279D3
-:1072B00052D1FC3E219DD99F5DDBE367C23A840D2C
-:1072C0007B70BFB5B2E52619E8AF577EA4CB5A3F15
-:1072D000DCC7F451FA857D7698DF8C91FAF92D465A
-:1072E0003C756D64FC5FD92607AC30BF0D6B319ED9
-:1072F000EDDD7002F3E327BDB219E308DE36D19865
-:1073000017B9410C9A317F533C6846BFC6989F58C5
-:10731000DB5A83FB6EB52D3CFF2F2A2FAEEA955D1D
-:10732000AFFA2868AA7EF9A203E4C1B18EF50E80F7
-:10733000271D0FF30A2F3B2519F2A3FACF07761B5F
-:10734000F30D5B1EE2F986577792FCBEF986C7E023
-:107350001FA06FD2A3F2353724F3FCEE6051718C7D
-:10736000787EEFB99FCDDFAC813CF9AEADC7D7C019
-:10737000FCABFFF6F51AC86F22BBADA8A7BC2FFD6A
-:107380000EF38AB5F716A7337AEBDEF822E66577B7
-:107390007F6A467FA77B57670EE4B7756FF93E0D8E
-:1073A000E2730B775D8EF1CB85DB26A59318F25E39
-:1073B0002B813E03E790171E8D8F7DADFB300FEBC9
-:1073C000AB4FCC28DF7AF3475B6A585EAECAF34610
-:1073D00037C5CEC3D7F21C6B5BAFBBE65290D7ADBF
-:1073E000CCBEEBCD7B3C5BBEE88714AF179D03FEA4
-:1073F00036F1BCE096AB63E68B7E05FFA078FA79A8
-:10740000BA315FF49BD6053F7F16DA5A93FBCD174E
-:107410000D9E03DCB43CFFEA74F74BE9C0475BE325
-:107420007D190C6F816902D881DFE4C0F988A372ED
-:1074300018F340C2BBCC4EC87BACDCF531F24BF745
-:10744000B60F30DE4A789E7D37E9FD63F9D0025FE2
-:1074500067B39DE59972F8431EAAEAC0E73CDF9442
-:10746000D1B19687DA5FFE69289D9F1FE6E70E6A15
-:10747000A8DFC4F2D42379A9C258C0D741435EAF74
-:10748000B6EEE8F19C5C8E46F2AA63E7F96A79846D
-:107490007DF1C5F48A9637DDBD96E75BD3E7D9A3C6
-:1074A000204F8EE9736F40F838167EB5BCEA3F4432
-:1074B000E1575B5F7F7CA1F1E7D9E6FD5F85CBBB40
-:1074C000E92C9EADC1A7EB2FB1E5F4B79CDFA9DF96
-:1074D000FA4DBACEBF9DC3FD560D6EDA7C97B6301D
-:1074E000BBA26B03F31FA2F99BAEC71D2BCF5ECAD5
-:1074F00060F66F6DDB9E7C90435D7BB773BA6374FF
-:107500005DBBE920CBD3A5723BA097DB84C591A3DB
-:10751000C773F0F1BCEDB1C7F36E3A1173BC63925F
-:10752000FB2698FFB10E66471D6B11A706628C7F84
-:107530009AEBA5DE75DB15CC97121D71684F2DB443
-:107540008FFD2421054A05F37E1A16F33CA1FB5C4E
-:107550001900E706FB9504E6F300C047177F909DEE
-:107560001E02769C9C515C28AA91F96AED4A8A8990
-:1075700004F4F89782D920DF0F1474CA30DE675103
-:107580007193CF24B2349DCEEB339FE05AACF66FAB
-:10759000776B75CFBDA221CE516B0E1F00FB9DBC3A
-:1075A0006EC5B8B5B8DBEAC3B8D91A2BAE73DFB66F
-:1075B000EF5E007875FFDC4CD83E02250C2A17CA16
-:1075C00078FCA273DB776BFE0C7626BC4CBF5FB6F3
-:1075D00086F607FB7A533CFA033D5B13F2D19E7C9F
-:1075E000FD9EE92037CA4087819DF74A7AA0818EA7
-:1075F000772495D58F6C1E88E709AAB6DA31DF703B
-:10760000DFB6D76A41FE77BF120FDBD1E42B39F426
-:1076100037A87B772690B52ADA81AA5EDF56104913
-:10762000D5DB79555037E4BF10F4D3311E47E9B9A3
-:10763000AA2D01CF8FE8FA717EF665B1F332C12C25
-:10764000E03B6A4F1ABEA3B55F9F31989FEF0DFFD5
-:1076500084DDAFC0FA7B957029ABFBB318DF766091
-:10766000FF128D5E797BDF7159FF3919830DFDB4EF
-:10767000F76BCDA42E161F546708FC7CEF5F87C5FF
-:10768000BACF22C6FCF1F95D02F199C00ED8620DA5
-:10769000405CA35A090E85FCF65715B63F52ED081B
-:1076A0000E85FCF69D5CFE55C7D13A7D9EC5E7016F
-:1076B000FDA14E2CA19701DF35AF5909E427D5BCB8
-:1076C0006E77039E6B5EFDEEC8738590CF168F714B
-:1076D000AB9AD7FF1DF15F630ECE06FA0F6F3193A1
-:1076E00075B47FD796B773C08EE89283394967D84F
-:1076F000F7A969311BF6B1B5751CAB0F9C07E7D72D
-:10770000B5738B95FDC88B5D19CC1E5D91E17E3CF8
-:1077100003F9DAE644790DE389304EDB10FDB9E672
-:107720004A35B61C6BCA900DE768C5C839C526181E
-:10773000F72B125A9A455152238471FFBC72C389A8
-:1077400091E00F7FF6B30B715FEB33253C12E4F64B
-:107750006739E1917A797CB4DEA24A32C625B0EC71
-:10776000597BA2348B40FEA075662CF9B439231ED8
-:10777000E751796F7CCCF3A03B38BDAD061A4C6560
-:10778000DF853884F6DDCF948002F3C8CB54B1BDD9
-:10779000323BA0C0F3AA0DDB8718EE9D90FCD88F7A
-:1077A000F217C2A382AC540A6D7DE54AC5229B2A1A
-:1077B000E1F968E93F7BE94D8CE009839C90A7C61D
-:1077C00071483513C641B5F300925C6C017829A469
-:1077D000D82989806A3FF2691C69C1D246CD11A6B9
-:1077E00087EA08E4151DE5FBB766497D1CE4877947
-:1077F000BF88F2FC6C70FB558603E76D96EA880B38
-:10780000ED8E694EB0AB059F87FC40E9A1A17EC318
-:1078100090C36CFFDF0DF9700EC2E6E770BEF53D58
-:10782000D80794CED0CFF65D46020DF47B92C2EA23
-:10783000642209C4DA8FEFE27820BE3D287F6C24F1
-:10784000F217A6F5789450F4BB097F1B0B7EAECDE2
-:1078500049826037C5DB48309E96B63CE9989E7FEA
-:107860001D84D507537206B9E6BCC4D81E4DD7C4D3
-:10787000259DEA958B22BE7F2AEAFD53677A5F83B6
-:1078800087D73224979D7F677089E36BF04D749D95
-:107890000E013CF21DAE06C0A3123E700FC023DFE6
-:1078A000C6FCC49446A2F7E38664327975BFC0F47F
-:1078B00025FD2BB6E9C6234E0BC64F1FE270EFED38
-:1078C000AFC555FAF4B74A00D73EFDADFDF58F8B35
-:1078D000DDDFDEDF7CE263CF27B19FF17DB1FBD737
-:1078E000BEFEF17B41151E32B9211193760E7A4806
-:1078F00026F85B0907D24A1855B07D8228BCC5011D
-:10790000FD517A883B4FF71CFE2F4F87BFC131F0E6
-:107910004F824877257C3EB46ECBA4F3BB994F775A
-:107920007233DBC7BC75218B23DD7C2F3B2F74F0BA
-:1079300067ECDCFEAD8DCCDFBE7511DB3723E5ECEB
-:107940001C9093FE07DFBB0D06A1F8BECD2F04826D
-:10795000B9700F4E94FDDA7BDFCE5D12F42F898A69
-:10796000C768F4A49D5B9AC7EDEB5C4E9F0B48D8AB
-:107970000E7C1F7D8EBE3583E5A55177CC0DEBBB0C
-:1079800085AF4FD303BE156438DC0B209AE25CB0A0
-:107990003F22F273ABC4A1B0BCE5EB930CF2E7E479
-:1079A000703501F41D79833FE7F711DD71859AAEDB
-:1079B0003FE7259D8EC7FB471A645706C845F9F473
-:1079C0005544A57CA19C1E4254DD39346ADF21B3A5
-:1079D000CB4E82711CC9594CCAC02E4CE4749672AD
-:1079E00065AF1DF63E85CB1D2B543C077B5326D33C
-:1079F0002F0F67152F00BA101D635D1E5B5FBCFA69
-:107A0000B6B1F535C0FA72FBCEBB4171B9D00EBD2F
-:107A1000925A1018EF7159603EA259FD5805FEFCAC
-:107A20008D4CC0FFEF0B0786CF93294901C87F9982
-:107A3000EF78F800D0EDF27A27EEA32DAB1F8EE59C
-:107A4000C3F51968872EAD7761A9C1C5E2F2BB45C0
-:107A50000A67CB796C3C8BD3C3EC0CAA8720FF421E
-:107A600072D605A16EC9AE2360FF5A7BE1E347F8E9
-:107A700028BD750FD6CD50A7A5DC380DE14BDF270B
-:107A8000651047CDF22C07F858D50B88AAA30B73C5
-:107A9000C62843BD0FDC34FAD8CCE0F7A8C0E823F1
-:107AA0001A7E8FCA1D2AEC3F3F7A45EFBD36083F4C
-:107AB0006AEE33F8FD9AEDCFF50B3F6712DAB3F3B8
-:107AC0008B96CE6EA08F1EE1FB900FD68F45783D32
-:107AD00004795DC3C03F70632902FC281D99F37CC3
-:107AE00044A4EF9B553667B3ADD86D2A64B40BF050
-:107AF000136D0C9EE68C3ADC8FB3D818BC449B0FF8
-:107B0000E122DB18BC441BA33785D72580DF687CC6
-:107B10001F9F53F8B5668E013C8C37C04B4999784E
-:107B20006EF05B45E147E791C2F92B1A0E29704EC2
-:107B3000212FC257FDD9754FD1F5831E7F86C2070D
-:107B4000CAD47EFCC7D42C2647534C757B6480472F
-:107B500012E1FAC547B28B084B5584BF0C1F51A1E7
-:107B60002EB0799066235E45A71475EF9BFA0CD072
-:107B7000C1CAB76513EC938A8BAE329C271567BADE
-:107B8000135584A74700FDFC48BD8AF85B01781CAB
-:107B900006FA91F9630F707C3E087C82F865FCF16F
-:107BA00028E797C7399F34B8D8F989E553595E5605
-:107BB0004A8189DF871624FABCA744570B51E8BCD9
-:107BC000D0C656B10CA29DF18939703E7D2F3E8FF3
-:107BD000B8814E123FB93B806B25C599601725725D
-:107BE000FB975CA226CEC283B44189F9215414A22A
-:107BF0005FD3618A750F56836BAF05E2A6FDCD6733
-:107C0000CF8C57912E4B2FC2F46092EC299EB580F9
-:107C1000D66D8DF1181F8C77798A1E003E6FB423C4
-:107C20009DDAE8FCCB74788FEF07AFCF665D61CA51
-:107C3000A2742882D146F1FB44E3102BC0F929B984
-:107C40003813E4EB535CCF521CA8FA7DA82E2E27E4
-:107C50001D851718FCD995B21BDF735E6294032B48
-:107C6000B9DC4D9A6CA4774DEE7ED42B773DA930CC
-:107C70009FB4D393911F53AE8D2D7F1B64C507F71F
-:107C80000A348C64FCEE2B51D0FE8B210F30AE7D7C
-:107C9000D233741DC8538DBE9610267F7C24CE85AA
-:107CA000FA88DFA3A3D9C7CBE0BE412E67A114CFCA
-:107CB00053906ED26E35617EDE727E5FD66394BE67
-:107CC000A0F453FA82F2D22CB69FB1C4320AEF6DFF
-:107CD0006BB099505E489F9A0336B057F78C734249
-:107CE0001C41925D1D6E8807DAA5967504FA155A37
-:107CF000E03E0921B1D00974F0AD7DFEA033E5E18D
-:107D000051740A4047CE946272280F770FF05CB32B
-:107D1000ECBC96405CF199943A2BC02D2F8BF95D09
-:107D20008D254508470ADF8959A99171D2675ED927
-:107D30007BDF160CFB4C3FE7A3A767713B3ADB47A1
-:107D4000CED3F17BA3C0ED30D54786EBF87EC9F9E1
-:107D50005308EC2BF5E5F77EE4D97A26CFEE1762CF
-:107D6000CB33CDFED4E4991C2527B472E9A0A986B3
-:107D7000F35D4A8A0B68174A9F89A248F25DF4E8CE
-:107D80002D890887790007927165AF5FFBE3C160B9
-:107D90005716C5A4B7683936BF57AFBBD3004F4796
-:107DA00065357D16D0D3DBFDE9757729D2A17F80BB
-:107DB0000A7A69CF1357615CE7F0137615E450D95E
-:107DC000E987503F949E1E876579E315A8CF8527E4
-:107DD000AF2E027AE86CBA3CFF5388F3F8EDA8B7EF
-:107DE0003B1B270DC5FD487FBC0AF91D9D8DB4BD09
-:107DF00030D20EF9E2A22E5F8040F45D77FE9B1434
-:107E0000AA68976AF79E51BFCE311EE242AB453C4D
-:107E1000D754FAA4DD0DF6677FF457DA143B1E0041
-:107E2000BA16E2AEF483C3C18EDEE3181F0ED27120
-:107E3000E7AF63FB080D8AFB4810ECA627ACB80F30
-:107E4000D99014FB5E900559972F0739B020CBFDD0
-:107E500014E2C9C6EE29ED9F1FD8F78FC02633EC78
-:107E6000633DCBEF47913C8E19867D36B68F758486
-:107E7000C75988A59FF638DEAEF6D3EE60F922C466
-:107E800019BB5DF333E2237E460BACA3A6F1F8D217
-:107E90004F115EDCCFE0F33E2AB3791F7DC11C5841
-:107EA0001283FE8FF2FC940A81C157E383A3BDF6CF
-:107EB0009107EFC389A65361DD8867C6D171BFDE24
-:107EC0002FA3DEA8A6F48574B56E1CE6C70B4F8CF5
-:107ED0007B1CF2864FBD23627BE5692BB677DDE71D
-:107EE0007A06F29EC2EFCA04E4D3A9FD9727B03800
-:107EF00091318E7DDB0026170E71F9507AFA11A4AC
-:107F0000DF5E3AF12F5080FF4A4F3FC6E87B838007
-:107F1000F756125FF5BB13CEE3F4391EDEAFB87A25
-:107F200009C0FB123FEE9394AD37BBC01E88C6F369
-:107F3000A12CD510F7280B2DC77109B5BF5274FBC2
-:107F4000E947799E71D969765F2171FA4806F00395
-:107F5000974F113A36DE43DB658D1DA73FC9ED9F74
-:107F6000D2D3171BFC8CC8FA2EC3E7A55CFF9785FC
-:107F7000C6613DB29E67C6C55A4F641D9760FFAE8D
-:107F8000C4D8DFCFE4703E525F4EDC54BE952BACBC
-:107F90005FA9FF2E05E44E69536292A05B575963B7
-:107FA0009521CFA3ACA94499AB1B378287A5EF4E8F
-:107FB000902278C87C6EF1D54B6C601714CB03808F
-:107FC0009FD65514FD5485F1987CFA52F6E780BC93
-:107FD000EE6CBCD311EBDC44E68028FC3472FC5020
-:107FE000BBBA50871F0D2FD1EF1F595B56F4538832
-:107FF00047AF62B790F42F7FA2F0961B1B6EA37A57
-:10800000E1361CF38DCE0EB70B0D79457DE0C6F140
-:10801000ABC1457B4EEDA80B078C81EF11767EA797
-:1080200091E1FF6CF08A7C97E37F42EC75CCEC5DCC
-:10803000C722E2A38C3AFFACEBB887F82C675887CD
-:10804000867FF28201FF339F5B8B7CA8E17BFEDEA3
-:108050005548BFF3293FC27E7FA7FF2E47ACFCA245
-:1080600099FDE1FD3C1FC92BFABF87F72F655F0E15
-:10807000E495F95658D11F39BAEE911C3D9C17640E
-:108080004DB80DF0429A53CF497FF826BAF6837F58
-:10809000E97B42C678DA962C4F19BC5FCEFDF0FB27
-:1080A00013A70C8D651F3C50BF7F04C4E91AEA3B3F
-:1080B000B094B97D49C0BECC457BC91DEB7EAF6590
-:1080C00003985C79A0BE83C53D2D3EE2D49F272650
-:1080D000CC7EFA4FC2E235DA7B8AEC7142FC54E185
-:1080E000E79D65C9B32CB710E21E29053E1DFC961D
-:1080F0000E60E7919667EC75C2B962331D1FE239D5
-:10810000966CE9A4719F93D50B844F45C86F965325
-:108110005A08C643F3E8731DBC95940E437C3A1A83
-:108120000E92C581FB4D1261F69CB67EFA04F5D223
-:10813000835C2FADE471CDA7EB5B30EEBF24DE8115
-:10814000FA6FE92013F3A72C12DE57634E64FD95F6
-:1081500004366F2BC4BD45D0AB41ACDBE1461F11EB
-:10816000AF4613A09E485401EAC924B814EF4999B8
-:1081700010FA093C7765780280C76F333B0E081010
-:10818000C72EF60C03FDDB28FA0A54DAFFE762B8C3
-:1081900000FAE5D0A64F92583908F2A13DBA7D2DDC
-:1081A000764FA8AA8F0B46D7072D92A2F67BFE32F8
-:1081B0004CDFBE22C3FD0ACCA3C1CAEE194AF95C4A
-:1081C000C0FD9C062BBB6FA8C17E6302E8F15F0F68
-:1081D00060763BD201D0D17E66CF9C94D4842416A5
-:1081E0002755DF30C4F92DEA1BBAEF48DCDF6BA658
-:1081F0007429E9F655CE93DC26A09BF3FDF4B97EF5
-:108200009E31E2714936BC9637E67E8E363FC8DB3A
-:1082100007388AA7A7A0BF164D0F3B7BE3CC3E11C2
-:10822000F0394BBBBF58BA9FD51389F687FED7A745
-:10823000BDF6E8FDACCEF739BD73D93E66434902C1
-:10824000E6C769F398D5FE6007D8A9B3DA33E7C16A
-:10825000FED62CDBD02FA0DC2987F7C6831D7897AC
-:1082600080E74A6EFEDD1B723C2DB77DB80ECF3322
-:108270007FC1E5E96C12C67BE13DC4C9F7D903F8BB
-:108280007C2E71F17A8B0C7EFDADC1C00D57D3DA17
-:108290006D6F04AE06B36DF6FEF09B20063C2DCE4E
-:1082A00029B887A0BDD7E67A8BD5D97BBDEB972CB3
-:1082B000B89EC87A2DB87E6D7D74A608FF5EF8F072
-:1082C000FB9A34788873E9BA29BDCC4AB8F14A726E
-:1082D00006BB7C966DF8176CD384CD271A3EA7A0F9
-:1082E00089DA8F5D03DC249BE2EF0F03DC0294D577
-:1082F00096708E3418F944867AADE81904A9CF5FD8
-:108300000DF40C4B053874249F93FC3C6065FC7F96
-:1083100000E819F2BC4EA7E0BAB47BE8F7DDDD69EE
-:1083200007BB73E9B68FF19EE51A31F4E84D180FDB
-:1083300015D16F3AD93AEC8CE7CF0E409C8AEABF50
-:1083400081D9DA394BB6CE3912E39339ADF1988F32
-:108350003F679168B8477ACE2296CF47A48EFCEB50
-:108360000DF6FAFDFD8E03F182E871E62D9A443E8A
-:108370001F0DFBB4CE09183F58C3E86BDE64B70885
-:10838000F9CEE39709B8DF3AEEB0DA16A2F57981B3
-:108390004417B0E7BCBBFF6308DC7350DBC1E2816C
-:1083A000E9E2ED05F7419C652FD3E350BF1DE8C41A
-:1083B000E6566DBAFD822EB9AE00EEFBF3DD6673B4
-:1083C00003FF975CEFFE14EFF3E5F10A4DAFBED665
-:1083D000588279B225B7AA6301FF252D5637961624
-:1083E00022C551395622110B94E90A91AC50C6119D
-:1083F0000B94454BD8BDDDA58D33D03E708C2D56EA
-:10840000E03EDE92F617BF81F7CBA4E01E763F0573
-:10841000834F49FBDBDF035E17B88B319FF1C20D41
-:108420008AC10F1CD962AC5FD466AC17048DF5D13C
-:10843000FB8DF5F5D904E968AEE5BA3C80D7DE5D81
-:1084400066AA8B20FFCF8CF92E8704861FDF462B70
-:10845000CAC34955ED45E0071F7FD96E023F7AE751
-:108460005F7F89FBE1E1CDF104F2ACF6FC3E8EC406
-:1084700041BEE22BD675D05E457107F1CBAA57AC51
-:108480006BC10F7FF502CD8F0FE4C37A5EFD1BCB6E
-:10849000AF096F3407607FFCF8F6175F86FDB4E321
-:1084A0001B07A07D7548F099E2E0FB5FB2F8678892
-:1084B000DF1717E2F7C5556D30FAC5776433391306
-:1084C0005A7271422CBB492B876724E74DA673EB88
-:1084D00079C83C07E240C31A8D70D1FA8D08189F05
-:1084E000DFC3C71F4F94089DE6429E40A0C101FA1A
-:1084F000F7F9D8F7242FE1FCF3D24BBDEF89FC9EAE
-:1085000038A2EACE4D45E437593800F23700FE83F1
-:1085100023CFAB886E3E3AFB642A1FFF6B0BCB6701
-:108520004EE1F7F71FABDF8F7ABFD7EEAB77BB27F4
-:10853000EBEAA58D7BD24AC07F6ADA93365707AF44
-:10854000EA8DFBD26EC1BC270922B8A47AD60B8F64
-:1085500041BCA27AA3D802F38476805B57CB9B0EF2
-:10856000E847EDE151100789D8A397BB27EBF8F84E
-:10857000EFA55B8DDFAAB9FDF2DAD88E2990A75E50
-:10858000D528B8A05B55CB0DD75D0DF06E62E75CCA
-:108590008B24522C52FEAADE72C35523216F66F53E
-:1085A0001817CC870E713D3CAFDA7402CF333C1CF8
-:1085B000F5BB075AB9239BD985B47FD044FB3F7CD8
-:1085C000A3AD1CE4171DF70DA8EF1DBE0EEF5771EC
-:1085D0001C65FB0FF4F927266AB71C9DE87BEF1694
-:1085E000FAEA71D2F2D1D510576A34D223A56F01BD
-:1085F000ECB2F07AC1B50E9F2E29BA164C6EF76216
-:10860000CCF7A5ED73629DB7AE0818C789C6FB47C6
-:108610007CBEF46FB89E7EA2FB254FF3613E79F5D8
-:10862000222A0F757182EAC37EBC5F32FA3B444F47
-:10863000D7CC9E202AC8C3CD2C6F86FE0996229ED9
-:10864000A73B84D5F15E45A0534A28551790C92A07
-:10865000C0FB5A3215CAF12057E03EFDB12DF9D0CA
-:108660007F87107AE1391CCF8E72BCCB19C47B2670
-:10867000B3F839D32E95D57B789C536BAF6CB7622A
-:108680009ECDF1AF1494B38B5BF6611E7DD7CB56B4
-:108690009389CA83E35B9227423E66570BBBA7F8D8
-:1086A000584BF244E50C7A3B5A6E68FAF420FC937E
-:1086B000EADD3F67BBBFCD063D753FCB574D4FAEA3
-:1086C0002B88F5FB17DA7B294A5D01F831E1DB6C79
-:1086D000AE7508275FAE8471F00C17E40995086C3D
-:1086E000DCB841C5E240DADF4EFB423C3A69BF8864
-:1086F000BFD7F0B9E8FA897308DE278F76D0FC423D
-:108700000FDE4F49EE677995F324129428BDCD030F
-:108710007D948F7594CBF39A04CC2B9BBFDCB81E51
-:10872000B82757AF472B4880DD6FA18F230E867C7B
-:1087300017AA6FE05E4B0BCBBFA86C36BE574582C5
-:10874000389FEA4D3F9863C1EB1BA2ADCB9D0DEB6B
-:1087500012AEB5E0BCEE7C2A81EDF728C40DFA34E8
-:10876000FC941DE57B15F1E0783773BDEEBDBBC40D
-:108770003D1FE4F0A279EEF9C970DE96E93F74F985
-:1087800090BFD9BD5B5593497020BB7783805EADA8
-:108790006A178223A16E213EC728F61CEE1F807542
-:1087A000EBCFD794133F7EAFBCC9F89C7CC8F05A7E
-:1087B000CDCF3192665DFB60B0CF183CAA37990DE2
-:1087C000719DF19B049F1DCFBB061AD2E8FC6A8FF6
-:1087D000525941204FF507B3617CC8E719837A9F4E
-:1087E0005829DE9EEA95EB8111B1F2FC0F70383EFC
-:1087F00075436926F0EBE360B76671408F45B9C5F4
-:10880000E3072468A1DF891BDD5BC7F6A225AC3E28
-:108810007DF50BD31B2FA17E9EECC17DA17962F16A
-:108820005B701EECC5419E6B013FF34CEE1C09F9D9
-:10883000D63D14E3A18B181C9E195537A22E861D18
-:10884000A8E1F969A12508FBB2BEEDCCFEB21786FE
-:1088500065BD7EAD1EC8E451C2DE109E9B086F133D
-:10886000F09CE52AE1209E475C75854AC0BFCFA0F9
-:10887000780279BC4A20F7C37D5C85AD336E7F13E7
-:10888000F05C18E7829FBBA8699D20D6D870FDCC0C
-:108890004E8BAF5B0BFB39E973868F023AA7EB9ED9
-:1088A000732D7D7EFB4015BF97696378CF58E2CB6F
-:1088B00085DF814AD85B7CFB9BC08723E3F09C6CFF
-:1088C0003A85953D09CB65607F6590C502F47BCA0A
-:1088D000C1C64F35897366407D14AB27DD2BB8D7F1
-:1088E00021F1ADC0F1D3CD642ACC139E831D6981E3
-:1088F000B802B607187E27D515C078E9435899A263
-:1089000004B3619C777AF1ED41BF6221D7630BB765
-:108910004C48073FEF9D2EEA7053B9F54E86660F1F
-:10892000056DF8FB50E70D67FDB95FB8B0809D3766
-:1089300048C931F6EB91DD09A3418E7EC0ECF853B6
-:108940003637C6A72F5662C7B39E1BC8EC16EF6911
-:108950008104747AC03BF35BB42BBDA725C3F3AE8F
-:108960007A8B21CFB9BA7C2F9EBBAF211D98875D32
-:10897000D3126FC8DBBD382EF67735FAF69E16890E
-:108980002FE67715E3F3D3C9C4971CAB5F9AF1398F
-:108990005D87A1DEF65DEF3AE039191B72803F3842
-:1089A0008DDBB53D01934FBE2882976E67C8A077D7
-:1089B000BA5556EFE1FB715ABB367EF74C859F2BBB
-:1089C00062F72A037C7CC30879B6FD04C6A3ABDB3F
-:1089D000F74C61BFEFC5E8420F279F4E7EA4357468
-:1089E000044D94B77F3BF0E86379232889EDD5F8EF
-:1089F000F8D8636ECAB769A2C9C0D7F185BD7C8EAD
-:108A0000E2E52993C8E5C2F1C7265FA2AFB3FE91A4
-:108A1000F7BBA64FA6B67D611E7BFF8F03BF7A6FA3
-:108A2000C97911B944D791536CD7D52D51751BAD68
-:108A30008FD4D59D51ED2951ED1951F56CD6BFCB91
-:108A40001ECC115D84740E3C315D1A07FBD8C1D970
-:108A500070A3C0F286AFA74FA6F59AC20ECC9FA90D
-:108A60006D175CB8ADAFE5C7BB989D657385F0F732
-:108A7000ECE20B3BDE023950DD2638054AEFB696B4
-:108A80002D9857530DEFA9BAF75A98DF59DD721098
-:108A9000DFEB77FCE126E4E787871FC27EDAFED1B1
-:108AA0004DA4F7F73A4E0F043CB674323D1CB57F27
-:108AB000D49DE9DE87F230EAFCAB17C6B545E85E27
-:108AC000EBFF8791EDBF8361E2179E582CD1FE7FAB
-:108AD000AAE91C03F612DC710972FF69213002F465
-:108AE000F3B3C43302F4D16D35E7EF31D17E07E43F
-:108AF000D06AB8AA61688EF51A89CAE903F6D0402F
-:108B000081CA92E16B92AF01781E480DE10D0D3FD5
-:108B10005B93C2DA078606C2BE6B5ECE8F59FDFC40
-:108B2000D06AA85FBFE602561F191A28D2F707FBC2
-:108B30002EBC06E0BFDE199B6F07E63079AECD6F25
-:108B400066813B2307ECCD6AA62FE0F8A585CAC550
-:108B5000D995C736AFA77098FDD3789457EBBBAEC5
-:108B6000BBB218D7EF2B863C3776C53BD767289723
-:108B700025B4033241872545F061CFE95051DE5FCE
-:108B800050B705F47EFAEC3C94F7A7B2DDF53963F3
-:108B900022E59F87B0B23E879DF748174D986F90AA
-:108BA0007E8F1DEDA0C7F97E12E51BC4AF8DE36378
-:108BB000540E937FA372989F9435F0F27A58CFCDDC
-:108BC000DC3E5DF95060A395C2FFF740242918DF11
-:108BD000467BF796B5546E24403E853B13E4C12D89
-:108BE00010FFCD8BD435FB7D6501ADDB227EDACA6B
-:108BF00019EE4C7D1ED0CAB5AC5D93372B73D9FBF3
-:108C00009ADE496F60F0497F7CC43A5847BC44F013
-:108C1000FCC5829943D72D46FD7D2DAE9BB8DD99CD
-:108C2000E07F1FAE186C02BB52C3CFA202F7345CC8
-:108C30008FC8F2D5353C69DFAFE7EB9E2752FD4F79
-:108C4000D7593FC883EBA7F6403E4B2E60F6403D18
-:108C500004625323F02552680C3CFF5F04A7DBA19C
-:108C6000FD1F85530C79F133E857B388CA0B934E37
-:108C70005E70F83D2D04E5F442DDFD25F439F88100
-:108C8000370DF43C90A3DBC7997D4F0DDA7FDABC3A
-:108C9000E2FFFDB5A93791BE7C166D9F1DF8BD653D
-:108CA00039C6019516948B07AE24AEC5203FF8BE99
-:108CB000AC665F16FDB4EA1DF0A34EE688F89E553B
-:108CC000C3AB50BCA594C2E921AA56E13CBA6F06D9
-:108CD000CBEFD1F4E64A7EEFEECABB2FC43CBF1EF9
-:108CE00012C2DF65F38D2528FF7ADB670DC5768A12
-:108CF0006F9F15F8BD220E7F77606501C173362B1B
-:108D0000675D80ED3BB5B8D22C0B7E67E50C464F16
-:108D10002B2B581E26E811805B7FF490D6C0E21BF7
-:108D20004472E7EBF301DEE5F88B2F0C6DFB18ECDA
-:108D3000CAE556B42B4177E2FE883F1DBF47F1BA22
-:108D40000DE599E6473D99C9EE9B252EF4CF1FB45A
-:108D5000BB4B505EDD17AFC2FC9BAC64996514B889
-:108D600023E47E947B7C3EC4FF0CE679CCE1F6DA0A
-:108D700067E527ED600FBCC1E50D100CF8CB73095A
-:108D80006B9F7B6FFC41F06FE6DECBEE9B25CB2E1D
-:108D9000771BF73BE85CD3203ECEFF1AC376808377
-:108DA00007DE73C0F8FF6987FB4C3CF7B2F3BDC424
-:108DB00047DFD7E5437F0CFC0B717691CD9FD4C77D
-:108DC000ABB1EE05FD98CB773A7FB7FE7BDA77A2A1
-:108DD000C7A5FEDD2740A714EE41380716BE4FE4B5
-:108DE000BFD76A9C6F8A127ED44ADB67D78B894BC8
-:108DF000283C3D8BECB85E6DBE73D2C397B2DF8565
-:108E0000358E7F24BEB608E2E19A3F42EE35FA6322
-:108E10001097E8AD8B98278D7E4D9FE7DC9F8DF6F0
-:108E20000309F99B59DFAFF79C862A44CD9FD39560
-:108E30002A4880370FCF5F5094F06CBC572A6ADE07
-:108E40001A3C9541260E774617D1F05606717A885E
-:108E500082778A121A08E37A1699114ED1E36BFAD7
-:108E6000F1192BF1811FD9280848AF8D77C7A3BE10
-:108E7000231686676F659C0AF4FBAC12C63C27DF9D
-:108E80000EF6FBA03DD6F0AB28B7CE63F1869EF779
-:108E9000C4B5D0AF3B95D17DF77699F31B61F74C04
-:108EA000BC27AEC376818DDBBD381EF3A7E07CA85E
-:108EB00002E7367D7FAE87F88BE6E77FFE2ABB6F41
-:108EC000017ED747EF27C3B9DAF25111F981F7C70D
-:108ED00000BFB7C5F33892A702BF774B1C813C8D0A
-:108EE0005A938079BFB59517E03913C2EF79AEE692
-:108EF00053AB35517F7154440ED49A0E0D057FABA0
-:108F0000DAB21CEF7FA6ED6F809F063FC3DBFB3B11
-:108F10001FB97DF150BBFCF85FF1DC7BAB913EAA41
-:108F2000237484E7E72AF574951BA117B4C7418E13
-:108F30004C26786EDFCEEBF1533B0210C7F1F2B84E
-:108F400046EA5E76AFADBDB085405CD57B94D92353
-:108F5000E3DBD7EE03FF38716A077864B43F8BCB4D
-:108F6000459F2F1AD7BE4204BF4FB363747EE78874
-:108F70006B47EA4B761E17FC58F85E081E01FF4847
-:108F80004CFF3DCDF51FD59328AF17F887A19E0460
-:108F90003D06724EF38341EE819C7971D0C45B072C
-:108FA000A5C27D86136F1AC4F66946A0DDEF3BB7F4
-:108FB000FD28AD1FF8C3678E9731B8855725303926
-:108FC000023F100A71E4DFC86B1FC6F949ECBEC648
-:108FD000D5B92897B5384E358F6395F2B84F298F9C
-:108FE000FB40DC559F170B714D7DBD9ACB851AF860
-:108FF000BD29BC4FC01CC98B8578CF6412B4433BDC
-:10900000C47D1CECFC9DFE7D2F094C9290CE7F30E0
-:109010001BEECD5AC9D63B87E37D9595C57BC6DF50
-:10902000BB5664412CB6DE8451EEDC070A23F77789
-:109030007DC1F1A4C1256ED0C412807B9CC8EE3FD7
-:109040000F3FC07E0FFB30D5DF5B783CE45A1B9EA0
-:109050003F769F07790B9233E7DA18BFEBFAF00EF1
-:109060002BDEE3EFE7F2487B3E6510CBF7C5381106
-:10907000C07D713CDAE114CCF940474583357D4A27
-:10908000F2213E7590E77FD6DE68F3C078211E3767
-:109090005F3D88E98DD583D8EF3F68F55EBF8FD3FC
-:1090A0008BB6CF05F11A7D7CBBB9B73F8BAF68FAA1
-:1090B000F7E98AB8B5ECBE778D6E4D78BE323EAF1B
-:1090C000588138D30E2E474AB83FBF033670419EB1
-:1090D000B4F0B8B4E49C0DBF1BB4E3681EE653A61D
-:1090E000284CBEECB8398E407EDFFE632F3DF21E69
-:1090F0006D3F7954C1FBF2E6F378EC0EB8171EE42D
-:10910000E53633C619AB15664F56EF1EC9EC18C5C8
-:10911000B30AF2BE7D5B658C7B553B021B5FC0F6DC
-:109120004C17C52C9C176576F0F678F67E5CE01738
-:109130002F835FBA3BDDE5A3FD176578F6021F6557
-:1091400099D504A2EDBB0A91F3A48702CC6E3E042C
-:109150008207BED36EE7BF33E0CE5C40C7F9FCA107
-:10916000745C0F95B7685F7DFE9819F7D59EEEFD8C
-:109170002E8B8F1E928BF13E9943DB0A5CD4F32435
-:109180003DC54A10E2DFDEC799BD37CFA4AE01F876
-:1091900090DDF12E83BFFA5819BB5FA2F2DEE967BA
-:1091A000DAE706F9AE8FFF7693700EFAABE5835BD4
-:1091B00020DFB4BB7D848B6D6765E0264A2DDF7FA1
-:1091C0003E2C33F88677C948CFE73A3ED045EFEFDB
-:1091D000E089047FDF4DBFDF16BD4FD1B7CEF0E889
-:1091E000DD91CEED3A63FB75D99E53C06FB54F7CD0
-:1091F0007760910ADF0BA33C247E166F3F2CBB6780
-:1092000003DD264E0E1AF2B86C2AF70FCCDCFE23D3
-:109210004145CF875A7BD14412735FE7FF002E3F51
-:10922000E0290080000000001F8B08000000000003
-:10923000000BC57D0B7854D5B5F03E73CEBC92992A
-:1092400064663209931739790792C01043448B3A08
-:10925000090103469D002A5A8BC31B943C046D638D
-:109260004B9B814408881A2E01010127084AAFD878
-:10927000062F20D64807448AADDE3F3EDA8B7A2F90
-:109280005F508A6805225A7EDAABF55F6BED7D92FE
-:10929000394322D8DBDB3F7CB0D967BFD65E6BEDAC
-:1092A000B5D65E7BED9D5855622C91317B37F385A9
-:1092B0008A18FB067F6EE84F635503953336C5CC9D
-:1092C0009218BB96F19F8CD350DFC6984D55191B51
-:1092D0000DDF4F874DB3209FB1246C9A2BD200A491
-:1092E000278D2C6C298574A33DB42D135BFA18F6D9
-:1092F00033770CFC179ACE95598BA504BFABFB7B3B
-:10930000DC8C9DDAEBF4AE82EFECAB6F6456C6D822
-:109310000C26EA9959ABC5C5D88B2D52D802F566F3
-:109320006C306FB3427F65CB7CB21DF2BD5B24EF26
-:1093300036A837A3A53C6F23E4EFDD53EC95A16974
-:109340001C8E83F990332443FD6B1BC7B18FAE6233
-:109350006C96396452E03B7B4E623B18F5DF82FD30
-:109360002F8446C92597E261DE063363163EF76F08
-:10937000F09F50443E0BFAEDEC9019CC97ED84EF42
-:1093800005FDDF172AE183521C63B59D51EDD9DF3E
-:10939000CC7DF5105016243CBB4DEC1EBF8D263DF8
-:1093A000A4A698B13FE27F93198BC9F05FAD121D5F
-:1093B00072864CB6C3BC2BF8BC7A774B84D75AD68E
-:1093C0006062D84F7B0263D7448C6B61E158484F91
-:1093D000C9412A9F6B5E4369B59A4974BB97F5985A
-:1093E0005836F6DB6BF2170FCE07D597E1839B0556
-:1093F0001F2C3CCDC2D7C1780B97B070ED089EDA18
-:10940000219DABB0601CE0752EE0205EA431251CD0
-:10941000AF6A413F5E1684F479C4A71A8167C463BA
-:109420006479FDFE6FCC91F92126C6ACAE7E3A037D
-:10943000A108AE21E31A4635009CD72E09C90CE6D7
-:109440009792EEBB3107BEC796F2F9D61FB358D438
-:109450009198F7B32CA8F7655AF90BB930DF7A85E4
-:10946000F93AA13C16F0D201DFB7585910FB7F2A18
-:1094700097CFD763E2FC6B54FC6C940DE9D21D3698
-:10948000205D129903F951C3E7163BB42BC1761244
-:10949000B5EB6B6F612D3111ED2B7E65650CD6CB75
-:1094A0008597EC213354654A20C309FD257D60660C
-:1094B000AB207FF657F6F9D8DF59239BD609F5DDA7
-:1094C000326BE8247E594EF4F919D23511B9A9222C
-:1094D0009521EF4B93529907CB97D178B54EE0AFDA
-:1094E00001E8DB579ED97D3BE72BB3BA0DC6BBE045
-:1094F000ECF921E6011E1684FC0F91CE88973DE31E
-:1095000046FD04BED7FB6D5E8EFDC028E457B3FC5C
-:10951000C0ED16E0AF09F292DE87601EB5E936872E
-:10952000199A5466FCE71FEE84FC277B8CCC8C7464
-:10953000DE316E1ACBBA140E2D5D10327ED813B107
-:109540005EEEDBA9CFD776EAF3F54CF9B047E3033B
-:1095500040C116D5EE3E5548B2C3FB0DF0B7D9DC7D
-:1095600070BA03E035BF6CF62E85CF8BD4C0365C65
-:109570004F7586DE23886773C667230280978A8CBF
-:10958000AF8EA422FE7FCABC08F7056BF90CA2C7F8
-:1095900046AB1A8C905FF582FFDB87565379FB262A
-:1095A000B32AF1F2EAD120B7E6D312A62A1603E0D5
-:1095B000BF7EC3C44FA411546E417AB4039F52BB03
-:1095C00017A4D05268377FC3BC6A06E56758C864E1
-:1095D00001783ED1F02C774DB0C07FDB5D55C35094
-:1095E000BE285F2B7EA4FF0AECEA9A7E7CFDBA6F50
-:1095F0007D5ADA4E025E6E62128BC7793B03BFC69C
-:1096000079D65A7A4CE5D0CF0D5F7F4972795EE307
-:10961000ABD927AF4279E39B41F486F9A11C99F7B6
-:10962000D041FA2E4DB6107CA7D26D21337C7F75C8
-:10963000A399E79D26CA9FDA22517E5EA714B264E1
-:1096400062FD8B09E528BFB7181D6676299EA2F139
-:10965000F2F1E6FF886300F2C78C55E1FA628E866C
-:1096600038BF1DCB1AE2261723BE6EFC04E5D7BC1B
-:109670002DB2378C72FA15BB3797617EFCB0393644
-:109680006CFF454239E26FEB78874CDF653FCA21BA
-:10969000A6F8BA6F80EFCAD6AB555C2F87B770B803
-:1096A000E7392DCF209D6FF85A26FE570C2CB0DBE2
-:1096B0008674F00DC375A76EDE3101F1FB714D8A22
-:1096C00081EA3F2F3107E2C3D99884DFE7498A1F37
-:1096D000D7D9FC0D0BAA595C3FDE57A932AD9BF2DE
-:1096E0008C25493D36E2FBDB51DFD56E013EC7F1EB
-:1096F00027BFFF873BDDFD7C2F4DDE70CBB5D8FF4C
-:10970000B346E22FAD9FFACD370BFE602C0C789A52
-:1097100027F064CE589287E35F6E3DCC5BD690E72E
-:10972000B05D7E5DF4ADF7CD7C7D489912C955964C
-:10973000E6223D33D87AD4F493ADC040F2DEE26540
-:10974000BE1D900E31339F04F22B2F53213CE46554
-:109750009AA89EF297453BDF04F8F7A981F84CF8E8
-:109760009EC17CA350CFA8BD8E8A78E8CD860C52CE
-:109770008A7098433B48CE411EF0B43E913DB32AD7
-:1097800002CE2CEC6F34AD574F26F47BF6BDAF8E76
-:10979000201EEB867E3602F576FDC52F4D2AD0D3EE
-:1097A000D625919CB579FD0CF9A3BEAB86CD2EEAEA
-:1097B000978FF55E2EBFA3E7559B69E4EBCCDD4B9D
-:1097C000FDDC9CC5D75DBB93AFCF4D8D3121947B24
-:1097D0009BDC212B021D5B1A6428DF6F2995BD08D5
-:1097E000B666A7F82D9C5E16DFAB4C467EF5CA5ECA
-:1097F00014F1DDBE8F5A1220FF66E978AF0C799B19
-:10980000EFE9D62C9CB7D728CAB38338EF37C69672
-:1098100093BD728B4FA671D9FCB810AA8A6EDF3B3C
-:10982000EED930EEADCCB7F624D0B10A9437D2B130
-:109830001BC7067A9D7104C6225EB4F9DCEC9DB8A4
-:10984000F664A49DE1E3F6007CE27AAC74603C949B
-:10985000A8E51548A71BAEE774F8F4797368198C6E
-:10986000FFA915F44C84BEF8D4CEF5CED44CAEC7C7
-:1098700018EB1C8A72BF2FAF0C33E0BA7FC0C1F166
-:10988000E136750EC5F5F62749DFCFBDAD320B8148
-:109890009C59D02AB11080F8E9CF5F1C8AF2F79367
-:1098A0001D2F0E9D19015F743B2D9DAE8DD7F68443
-:1098B000CF02E3CD64DA78E1341C6FA6D77C02E5F1
-:1098C000076B1DEFEB89B01F484246D4671B7C2411
-:1098D000BFCFC16A44BED3DA9D9B1FE3433BF31C59
-:1098E000B38424186A66971C36637F3E5F8E1BE83C
-:1098F0005DA7B58FEA7F03F20FC025ED97C276A86A
-:109900001F5BD44BF27681C57F24158A16201DA1DA
-:10991000FE44A4A384FCEA33E1BC1589CBF3330EE7
-:10992000FF834887396D7A3A66663AB87C77B8899A
-:10993000EEA63A9B82FA22A999713BF0414308F5C1
-:10994000B53B266E04033BC694E2B1A19CBA212F1D
-:10995000A6C5108FDF8786B07E7A4A01B50B567098
-:10996000FE0E26B150B3845D364864073A7A9802F9
-:10997000DFD3C630C72A944599DC4EF430EF069900
-:10998000ECC44E09ED440D0F9A7C47BE41B9F7A9CE
-:109990006421BE91BA24B2FB6443E774EC77303E95
-:1099A000DA12C5475BFEC97CF4ECA07C1450898FA9
-:1099B0003C9681F908F64DDFA93E0BFA15C0D71089
-:1099C00081AFC7857CE97DD04274831F09E75B2D99
-:1099D000FAABB6D8C2F20892139FF5C96FE86733A5
-:1099E000D89FB84F4946FB19D2D4E6192AB7DFBB36
-:1099F0007B24E82FF66A0BE9BD470CDD9968E70F79
-:109A000019DEB01BF963C8F4A29266B24FD29C284B
-:109A1000F751D6E0FCEB1AC7F9B91D00FD221FD59E
-:109A200098683F51F750B99FDB0155B43EEA575B48
-:109A300055D467E3BA3297227FD42F01FB08E5EFB4
-:109A4000FE8E8D73215F37D5E6453BC56A995284FA
-:109A5000ED58AB7E9DAD943AC92E0E4E645E94DBFC
-:109A6000E74286A07124CAD99EAD3F413DBEA0C841
-:109A70001B5471BD09BECC61A417DA9DBE6417E00A
-:109A800075DFDF64DA17B58F823CA42F0B7AB6D767
-:109A9000F8929D909FB9DA4A786FEFE0E5E7EC80A5
-:109AA00020E83F45E6FDB1780BD73397CA030BE2B8
-:109AB0003D690CD37E36603E45CBB73D41768CB6D2
-:109AC000DEDB33393CF6227F265ABE017574770CF3
-:109AD000F04F926CD0364541B4BB63714C9EF7E1B8
-:109AE00070EB0C00480A66BF5E53393632CFEBF795
-:109AF000B77F6472651AE9D7BE72041BF4AE96F79D
-:109B000059018E15F6FE7205EC49CB7E49B4BF763D
-:109B1000F2F81C98BF24C60F9AD6F800DEC7AD4CE9
-:109B2000375E247C4A54FF4615F7F5A27E70A47F69
-:109B30003C545857A2B56F6EF301FC8F1BF5FD1115
-:109B40004A457BCC68E3FD2EE7776B568FEDD7FF58
-:109B5000600F38B346F7DB012BDEAF6E1B0963C520
-:109B60003ABE30A17ED5F479BD5B223B237ABDA6F7
-:109B700066717F05D8B5A95911F66E35DABB32D9B1
-:109B8000B9137069D52FF133B42FC16EC8C0F1CEAF
-:109B9000BEF7D9A983F0BD7DF2A764E7D75F54C8AB
-:109BA000FEA807FB03ED764B17B767D97E23E95D67
-:109BB0008DEEF70AF9D3EE04BD8F7CFA8A341AF9D8
-:109BC00094B186A1B7010D9AB37CC3100E6D3F16F8
-:109BD0000D6F4516B7CBEB0B2A36E661FFDB25860A
-:109BE0007A7F55C18749689FD4779D489A13D16E73
-:109BF000C1FE758487053B8D03CEBF228BDB9B7531
-:109C00002FEDF5E17AFF3424D15A9EAF8456A25D40
-:109C1000397FBE012D35561A9A7127AE7B36CDC4D9
-:109C200072617E05C2AEA9DF3925782DEEDBE0AF8B
-:109C3000049F36F9E7D2FADE34CD62639908E7CCA7
-:109C4000FB090F8E181FE261554145328E53573381
-:109C5000C181FE937AB0B3B0BCEEA1BBC89FD267FE
-:109C600007EF3756A1FD5506F6D6BF01DCE9AE4930
-:109C7000555E588FA9F2EE518B21BF7E10F9FB5E25
-:109C800036A7678BE40FDE8AEBFE2589ED50FBCB10
-:109C900033F673BBEEAE2C6E076ADFEFCA52A8DD57
-:109CA000D860F738E4BD034A4F2CDABFF5CCF7395A
-:109CB000EE3B99DFA6EE203A71B9E36E52C9AF646C
-:109CC00071F73C3212CBC72AB49F604ACF5A1CF7B7
-:109CD000EC4AB7771513FC8BF9878A4228478F66C1
-:109CE00005E621FF94093BF2EC4B378E9A59D46F6D
-:109CF00027ADECB08696011E56DAD57FA942F9F65B
-:109D00001785E41BB3F4768F437AFCD545FDAEB4DA
-:109D1000865622FD836B8C54BE3B25B008F9E67451
-:109D20004D551EEE83992D985703FC6474B731B4DA
-:109D30001760FB407E068BDBCF54C88F0BCE5024C0
-:109D400094F351F6C738F4F3D0BE010687EF1542FD
-:109D50006CE502179CB2D01268F926A1DF1E39FA11
-:109D6000D554053F6A768AC11258804D2BA7C5305D
-:109D700019F97E79EF1103CC27D6DD4D766C6DA7EE
-:109D800044E3D416BC6042BFC97D9D7C5DD68B7D0B
-:109D900000E06F28DA038F64C58AFD670BF55BCF9F
-:109DA000BA691FCD76717A3206F5EC91FB89A5541C
-:109DB0004FEBCFB48CFBBD6A853F067AA4F2F56207
-:109DC000BD6BFE095898C23EE0E3AE97BA7D32E221
-:109DD0007594E48DE41B2D7D3E8BEBF7F843BD13AA
-:109DE00070FDF6027FA15F66A35473FF6B30BF8DD9
-:109DF000A3877BD184F2003BC925F81D5811F05E82
-:109E0000BAFFF309C8376070D37AADDB5F2ED7DABB
-:109E1000486FD3FE71486C4307960FB9A780F46A68
-:109E2000CC55EC9EC9F0FD05B1CE926DDCCFE55965
-:109E300016CC5C5484E3FBEF7F0DC72F8E213FE5EA
-:109E400010A08DDD45692BFA853C6CA984F5D6C53B
-:109E5000F1FE130DF23D3545247729EFF24ABE6D30
-:109E600090766539A97FD87755219CF89DF663C017
-:109E700019B89F453F17F633249BA76793C30A0A77
-:109E8000884DAC67EB0EE4CFFD6607E2A97AFF6F61
-:109E90008EA1BEACB6B04E19ED95283B6349FA943D
-:109EA000D7903FCF9D39B5F561F8B6EEB67DDE00AF
-:109EB000D1456F3F44EF17B66195E4C1EDBD0FFA90
-:109EC000E8C9EDBDBEFC3FDCDEE3767D7047ACBA91
-:109ED00023429ED78B7DDAB9F9E7E350CF7CDC07CC
-:109EE0000FE8E9B27E7B65E6F6D813B8AEFAECFE71
-:109EF00028BBE1E833B141A4FFF94E2BF9E914B4D2
-:109F00007B009E33F6DE1F2272DC26BF4FC2FDC3EC
-:109F10006EA37719F4577FEFA7BF30C0BA533AC08A
-:109F2000EE89477B5F8D2739FBBACC76A05DA6F81A
-:109F30001CE8F7D0E0579C133CA8B75BC4FC179A09
-:109F4000C279640799D87CCAC785F3D0EE7959E8FD
-:109F50009D85319087EF8D9EC0D748B714339757B2
-:109F6000D80EBF77087BAB0350E240BC1C837D77E3
-:109F7000A6D0DFB8FF79343DB48AFC3816A2E74793
-:109F800007CCDBD0CFF35181216CE27E09F263A9CB
-:109F9000AD0A4B86FAEA316B48E5FE2E8B01F4FFE1
-:109FA000ACC7EF7B03F715B30E703FD6AC7B97DCE5
-:109FB00082FB8F8F264F30A1BC99C302E4779EC7E6
-:109FC000B81F7A010B717F35731870BCFB406C6C45
-:109FD00042511304EC5F0D9F2583847685DA027964
-:109FE000329A7D6D5530EECC1603ED4B66B5EAFD29
-:109FF000E91756DD5F857A7C458B81DB8FAD12E9F1
-:10A00000F159CCE741BB43C36B617602C983608BD6
-:10A01000C187E38CCBE67A054814A2F989B4C52838
-:10A02000FCF0028EA5CC10C6D420F1748543A91A89
-:10A03000483F6BFDB5181B2CE80FEB4D37901FF810
-:10A0400082C9378DFCA8AE3C867EC4167B436B1557
-:10A050002FA73573C1DAEBA7F2EB146EF031D5857B
-:10A06000F23233DB40FD45CF774E9B3E1F7D3EB144
-:10A0700020A4CFCF6281FCE46CF41BE9BF67667358
-:10A080003D706155A63807F0D239408B517D3B13A6
-:10A09000E5D54A85E4E5D2348E2F433A4FB39C95FB
-:10A0A000D3887F9D605F10BC1CFEACEBDC12EACD58
-:10A0B0001627E7CBFF29DCD1F0DE949DC7F18B4654
-:10A0C0001E8CD7B2520A717C71B8AFD47FB1305BAD
-:10A0D000BFEFECCBFFE3F79D9C1F57CA62BD394829
-:10A0E0000ECD74F0397D24799F09E3771BD80700E2
-:10A0F000F7AC957209DA29E3A6D8681E7507ACE4B7
-:10A100006FAD5DD23314D7515D454F5EC3007845C6
-:10A1100068154D7E41BD996ED827E0BA6DD59F5325
-:10A1200081A66591E74E53D27C4BB313713FF2D1B8
-:10A13000EEDF20BD775B493FC1FF0E9A517EBD9493
-:10A140004976535E5A606536EAF598F0D66733D1A2
-:10A150004EE176526D97B903EDC0992D11E75EF887
-:10A16000CF6AFD39186B75917F83B5EBBFCFDF1CCC
-:10A17000D5EE927331AEEFD79B02C3D0BEBBE17A6E
-:10A180005F32CAD5330B0C0CE93B4BF6CE45397226
-:10A19000C6AAB7BFCFD839BD76666BF2DD9B877490
-:10A1A000EECB5F42676F1ED27996810522FBA945EF
-:10A1B0003A037D170A3A9FD97B751ED2F9B3DD5752
-:10A1C000E7219DD71BDB7CB86E9ECD08EC423C9E00
-:10A1D0001CEF27FB09E455DE77E1C70351FC78E06B
-:10A1E0007F8F1FA9DD60FAF0B77D70E8F5A1DBA4D1
-:10A1F000A6A13C9C69317FAB5EC49F01FD6B163309
-:10A20000F9250E7CF5C563CFA01DD225931DA2F5BF
-:10A2100077400964A35FE1C0318F37280DDEFF83EB
-:10A22000C26EF5585810FD1F9ADDAFD98FD1F2F8E4
-:10A23000B898CFD96C5F0DED1785BF76BEE8D31205
-:10A24000FA82DBA9DB25F2C75AD44E1FDABD75AFFF
-:10A25000CC70A0BFF67488FB67EBF68E22FFED8210
-:10A26000D0ABE154B40BBB2407EE1F166C3F118733
-:10A27000E7DDB01F3D934D78E3FBD1F1623F7A3AC1
-:10A28000F4511C9E8BC3F837E33E22D6DD6B42FEB1
-:10A29000AD837D1A5461754AEF11ECAFCECDBC4150
-:10A2A0001415FBF5FB36EDFC7293DF44F26E539709
-:10A2B00014C27D5A9229909986FA89A5394EC5F61D
-:10A2C000AF97FFCEF6A5E0B966FFB9B1EF6B84CBCF
-:10A2D0008DE74DD0BE67633CF1618F91F9C80ED810
-:10A2E000681772492139F5E7CD4EDAF7D00FD4FF60
-:10A2F000732893F29ABE9EABB0B002789F3BD5F71D
-:10A300001ED20DE577384A7E47E6FBCEA35937D7F4
-:10A310002F20CFC3039D8F8B736A3CDF8D6C5FC78B
-:10A320007AA91D9EF3EAFAD5F601AC61940A70DFB2
-:10A3300077B7CD8BF64B3DF07563493F1F2E145315
-:10A34000D1F8B04EF879EBE77F48FB81FAFD920334
-:10A35000FDBB0BBD9C0F17C23EC93CE2D275CB3A88
-:10A36000810F23E01E6C1D5F9DA35FC77DF97F9267
-:10A370003FB322476FCF6AF3D7FCE27DF3EC92F84C
-:10A38000FA8A9A57F4FE32DA9FADED0FAF54AEDD84
-:10A39000D9070FC7475FFE9F2CD7E644E165B0F3AE
-:10A3A00082EF2CD7A2CF0D72B81F1CCF0DF05CF737
-:10A3B0007F7A6EF089DA9664203DE8D39DA7A29D4E
-:10A3C0008EE3B46E91C93E9820F373E85ABB99FCB2
-:10A3D000B4D1E7ADF5EA0471BED8FD876B507FEECE
-:10A3E0003132D4EBF36DF3E83CB35EDE6572A80363
-:10A3F0009C332A07C97EFFAEE7EF8FE6F49DBF6767
-:10A40000E2F97B59855E3EBF6AFB22211041E78A53
-:10A410002230FC07E0678B1264AE88EF4FE6707B5A
-:10A42000F8551127E331B1568CBF78DC1EEBC37DA4
-:10A4300087C7C0E3789AB3FC5B500E5A548EC7A707
-:10A440005EBA8319607E4F193B495E046B6D5E9462
-:10A450007B9A9F45EBDF2EFC0557CADF7BA3D6FB1B
-:10A46000DE7FF27AFFB536DE773D07DB00B8D1AD8F
-:10A470000346E75D6FE0F94DE6A5FC3A583F83F1EE
-:10A48000EDDB39FE377368BDF946D0B9FE15CA95C4
-:10A49000D8D2DE8FD09FC3F69855DC57A05F83F4E7
-:10A4A000E1EA64AEA7146F19E219ECB9328C833A71
-:10A4B0008EFFBD6670FBEF74DFBAE7F6DFE941E5BA
-:10A4C000CFDF67FF3565F83FC5799E2CF7E5A17EA4
-:10A4D0005C6107F8715FF7731E3FB3D9CAF973B3B4
-:10A4E000C4F992352668FE119A57F0797EFE1DCD8B
-:10A4F000572C57CF577DF97FB2DCB4F5C1F1BF2C93
-:10A5000037E7FF350EFD9C83F71324BA9555741376
-:10A51000DE7A5F91D8B608FF737D378F434B17F013
-:10A520006ADFFF2AECBFB9B9BEA118CFF5D97B16F7
-:10A530000B8B075307790CED2EBF8DFCFF759D3CEF
-:10A540004EA46E09A3F3DE3AF46F16A1DFAF86A125
-:10A550007DB74F0D1460FB15EFDB82723CFAC52707
-:10A5600033B2EBDEE3F9456AA088E2C596F4E8CEA3
-:10A5700019CABEF96239FA2D005EF203B8D12F1361
-:10A5800041A769B9FC7C404B6F8B821FFDF4C4FF6F
-:10A590009D7208EDC158B59BFCFE757BB89156269F
-:10A5A000FBC83FCFEE7331E4A3BA3DE5A35EA3FA47
-:10A5B000D65168CF967D50ED403FC467D7B929BECC
-:10A5C00060A8DCB300EDA9A359817108AFBD343494
-:10A5D00011EDD10CB047D1BEFD6CF7C45108B726C0
-:10A5E000FFD6A37F1BFA5D6FD7FBAF99C597F930F4
-:10A5F000FAB7B70DA1FDE1EE94C0CDB9B84FB37273
-:10A6000078836BAC7CBD0ABF76F4FAD7D6FD10D93F
-:10A6100040E30CF9BE85CEA135B9B0DEC80296EC98
-:10A620007E7972958897037CF078BDAE1A1EE7217B
-:10A63000F236B73E6EF16CF6F8AB707E57E5F2B8C5
-:10A640009439965E09FDEC73C4F9FB8D228E428B22
-:10A65000A33AE3F0CFC6FA6C4955FFB97B16B6773B
-:10A6600070FE17F131B117B99D9CE53011DFD85B51
-:10A67000193F3702BE41FA8CEDED1E170FF3C96981
-:10A680000F8F457C1EB868207C28356FD079493CF7
-:10A69000920DFAC95EDDB3321FFD258E77AF43BA46
-:10A6A000A86D8E0A44DD3ED5FF00C1A13414E0FE42
-:10A6B000B1E2F7461E0FF84A2CE9F9F6A10B291E64
-:10A6C000F0ECFBC0AF9997EA032D0DB26514FF972C
-:10A6D000B5FF1DF2DBDBF74803C6753E9E6BE3E773
-:10A6E00049C16E8A336363DD840FE5950F82685F2D
-:10A6F000282B15F254B4187D062BD27529233F7BE5
-:10A700006EBBC38074C9107125E70EFCF78800ED9D
-:10A7100047343F7D8852C5D8B31CF757CAD29EEB49
-:10A720006105B3DA3D4E431DFA358DBD75E41779E9
-:10A730002596FC9F19FBB3977D0FF219AD0E26A14C
-:10A74000FCF9D57D19C8D7419867EE00F36CCCE5CC
-:10A75000713BCA2BB106D45BCA1A4671888A33A9E9
-:10A7600082E05E0779E86791E01BEDFC11C0F5A07F
-:10A770003E9A9B1BD88E788E15728035C690BFD0BE
-:10A78000AE70BF86BDF1FDE797427EABF0B71E3AD3
-:10A79000503899FC732B1509E970C13923C301DFC7
-:10A7A0007F99CBED11BBD2CD1CB648FC1FA2B8CB14
-:10A7B000AC57785C9A62E47CA2AC7477A0FFEFCBD4
-:10A7C000B400C5975ED71296E9FCCA71726D951AEE
-:10A7D000B17FD9C0F548DD4EBE6F8EDEAF5C4E7FD7
-:10A7E0001CCDD5DBDD7DF97F925DF24EDFF87FE792
-:10A7F0003E84E9F76FD1F649F47EED12FB3AAABF29
-:10A80000C1EC142D8EA3A27F1CE28757ED9A1D1474
-:10A81000D4C5B954D8F8B8CCA2EFFFF94C2E27B460
-:10A82000B897A4667529C697F7FE94913F4D8BCBD8
-:10A83000D1E27082157C9F103480DCCBC4F39F364C
-:10A840008ABF49656149227BBF8761FB2118870365
-:10A85000ED7B72B3A8FF2DCCDB2A935C542584DFFB
-:10A860008AF11B09087768E35C1CEF361B8D67C50E
-:10A87000F88D04DA27D03A4EF1F3B8CD71F379BCF4
-:10A88000670AE85FCCA7E470BEB44E33511CA7162C
-:10A8900097A1C56F6878A910F84EC99F9B89FB01E5
-:10A8A0002DCE637D4CE8E75619E33B84DC5F6020E6
-:10A8B000B9AFC5CFB5E7AA21E4F77318E769BBF2D2
-:10A8C000788E68FC6A711D37A40792F346535C07C3
-:10A8D000E9512D1E43E397083A06AD30FEA657B85E
-:10A8E000FD5E31DF44F09F5B3089FC87E716181866
-:10A8F000AEA38A2E33E7BFA8F1364D33B130F6ABA5
-:10A9000084AC283F353EB89CFD0A742D40FFECA175
-:10A91000A69DD92761CD1F6EEAA4F49C55EA944701
-:10A9200062DA3B1D25D58867874E51AEC13895DE6A
-:10A93000A112B04EC9CE9CA9944FEC3D8EF949F9B5
-:10A94000374F55404F9CCBEDDD2A619C49FE89294C
-:10A9500094479E4C616CCC33BF9F12A479737FD314
-:10A9600038E16F323B03D7E525E27D809EE5DDE4EB
-:10A97000D7E171FD18F787F4F0D84C64DF7844BC58
-:10A9800025AB14F19778F202F9E6E451745E6D6339
-:10A99000EA9E6E2C4F33737DCF383F37E7727F309E
-:10A9A000A948949D699AFFA82788F2AA39D349ED4E
-:10A9B000FBE4EA1E7388FBB1F8F86FED2DA6732651
-:10A9C0002D8E943147FAD4628A37D1E51FB7F273DE
-:10A9D0004FA638D2D17E68360A3B55E463D202775F
-:10A9E000E545D8496F8DFF5111AE8733FB7E9283C9
-:10A9F00072EA4613D8F103C8A5D4022E97CE196D7A
-:10AA0000AD12D86D6FA4066621BE8EC54E9FE08440
-:10AA1000794D4B28373911DEE0CF6594938982DE7A
-:10AA2000CEA91C3E67A55F9A03FD365B613D43FBE3
-:10AA3000C480E2237B3D3055BA0DE06E9684FDCE96
-:10AA4000D478B2DB0BD4783CD75BD8F80EC555CBA5
-:10AA5000420EC8420EBCDDD493A3E482CAED5C234F
-:10AA6000A3BDFD8E385F7E2793DD5333803F737D1A
-:10AA70001EB70F27CB6A31F291FBE1B1EF54035FB0
-:10AA8000C8266F88E8976E5791DF0FDACB3C3DD030
-:10AA90008F94F1D3528C4B6E4EFF6929C695C82E08
-:10AAA000AFC71F915F9FC7F9B812EB21DE621B4A47
-:10AAB000518FFDC3FA8B87FE8AFEFEFEFAFA3173D0
-:10AAC000B8165A7A872AB03EBD9EC026A4DB8519E7
-:10AAD00027E8BCF587296F1DC7F888B78C6DE3E2BE
-:10AAE000500E654A826FB9BD76245FF36BF2B8F6FB
-:10AAF0002385DCAF097288C74F16F37B34D5531911
-:10AB0000ADE76A115731C1C1EF254D28CDF436C3E9
-:10AB1000D46E61BD0ACAE909C7FC71483F36355099
-:10AB2000EA2F1EDC0E631EA31A295726AA1179F8F4
-:10AB30007B53813E7FB3579FBF75CCD7F991F935D1
-:10AB40001EDF8B38EF97251EA719BC8639689E6ECD
-:10AB50002988F652E18B291DC27F4BF184FF2AF62A
-:10AB6000732F8E61549EB4D3B20DEF17687E705967
-:10AB700094177A9825C345F8203DDB2B89B84437D4
-:10AB80009DF5B07DF73B38FEA0AE09FAD93743A555
-:10AB9000759C6433B0EB71AD975AC87ED2D645B37D
-:10ABA00015F81BF058966A89417E6F367A37605FD8
-:10ABB000728C5945BD5A1E67A1BEE59F29A4979680
-:10ABC0005ACD14DA7AE8D118CA9729CC8FF1180037
-:10ABD000E2544CDF327A430D385FA887F36D76324A
-:10ABE0009257729989F434F44B743DB4C6106234B0
-:10ABF000FF7285E22D05CCDABA8391E8FB13625D22
-:10AC0000CB06162639966221397618FAC77E0FBD13
-:10AC10002E77901FAD40BD1BCBCF5BF2E9FE4D7D83
-:10AC2000DFBD22C580C015083BCAD9C5EF7F69EBDF
-:10AC300059932FD1EB19A4608E3B89711055FC07F5
-:10AC4000A691847A9F913DAF9D0FA65BB472C58794
-:10AC5000E324F7D5E7F7AF92443E353F93D61B5434
-:10AC6000091B4AD0FEF8CD5F906F35F9B075C5CF9E
-:10AC7000483E5C8AFF8207293FC9EEE0F8CF4FC308
-:10AC80007528C7E4A7A1BE6B767A557F44BE0096AF
-:10AC9000D13417E207EA417E4AD5891C25C2FF97C5
-:10ACA0009AAF92B0847ABE0480E390554DC3F53AD2
-:10ACB000C0B8B57CDCD87FECB81E1817EA1DB2C34B
-:10ACC000B8506FBBD51C36C40D34FE1815C7BBDC9D
-:10ACD000B8804E42EA248167E08B20FAA50ED90D98
-:10ACE000C49F93447CEEA1443E1E2BD0C7CFE4C446
-:10ACF000C0F8E46FD5C7CBDC286D6E41BDFC843550
-:10AD00006E1BF2E36F049F1C89FD590EDA55BF9943
-:10AD10009E7718E5CA84F8A52DC824935827C91B27
-:10AD20004DEE5D483E518679907FD7E603DD7F98F2
-:10AD3000F5D674ECFCB0F3891CD47F201FBE979F1E
-:10AD40007829FC1A3F6A70231FE23AE8E3C328F827
-:10AD5000353E62B7745280E116B04B31D5EC54C623
-:10AD60001A781CB89ADE3F3F60E20996063E8FA52E
-:10AD70004182FB46E75A8A371B312CE047B8A68D43
-:10AD8000FC7CA882953D33F2711F06F0D6FCFF844F
-:10AD900037DA2EBF5C3CB40657F43AD6C69726EF96
-:10ADA000A478E8FAA9368A8F1E27E24AEBE71B2827
-:10ADB0004E08F66F64F7D7314B08E5F0B5C28ED672
-:10ADC000E2F47F2571FF6770AF59DD11618F5F1A63
-:10ADD00027AD521C7670098FA7EEB3B76BB9BDDDF6
-:10ADE000A7D7C4BD80F6515C96B7DFAF52BCC4CBC9
-:10ADF00012AF1F9CC1B8BD5E23CAE738443C05CCE6
-:10AE000025A93F5EBDBD8311FFB7DBB3A83C45E676
-:10AE1000FA877D8FEB9FF64C6E4FB6DF9947E5B012
-:10AE20002F1886789F2583FDCCCFE7F9FE20978FDA
-:10AE300017EDA75D9FCFEDB23E3B47E4A3FDB2CF38
-:10AE400066043622DFCF29F20D9580AF6699B8DF10
-:10AE500015F86E33DE89A9620DDB956CBC5FD1F00D
-:10AE6000AE219BF8EE29E2BB42E0BB6C1DDF85F210
-:10AE70004773F98BC254E3BB3E7E2B888E870BFC55
-:10AE80001CFB6977767E5087FB8A2E33D1418B6B12
-:10AE90008C5EE711F09C347278DCB24CF0EC1E084A
-:10AEA0009E2BE1FF487E1BC2389F0FB60E86282CD2
-:10AEB000682FE95F076B3C81308EDBB71E96F37D10
-:10AEC000E42570CB36E28BDBEF9439BFC6727D8E02
-:10AED000E749C9307E8D18FFF695FE4A27D6AB911B
-:10AEE000080F355DB514F7C52AF9B99017FE203C57
-:10AEF000CD42CE69E757D344FB298E1A23FAE3A645
-:10AF000056EBCF91A6D9F839D5ED538D1F46DA3DD2
-:10AF1000D3D8EACF314E711A9E3369F5818FDECFD7
-:10AF2000B7BBE9FC5B65F978CE7458F859CE015F80
-:10AF300023DFBF96386FF3FDC077F94F1695A03F1A
-:10AF40006E7CD282ED6B20FFECA6E1947F2DE9FBB5
-:10AF50000FBC85E55BF3285F6990884FCFD5F2F68B
-:10AF60000565774ECA8C43F92FFAC5F584FBF59831
-:10AF7000407B0DD4F38CC82AC1F8D14AE137387729
-:10AF80003FA3F29B46DA7948EE3C95FC7E9531A2D0
-:10AF9000FC07BCDF3746FD4709C6115766F54E472B
-:10AFA000FE7EA3E4E5E1983F2C7D3E7DA03886C27D
-:10AFB00002293C0CF052E9E2F5AB4B7E9E827E9872
-:10AFC000CA0A9E2FF496AFCCC672C3F9E903DDEF2F
-:10AFD0008D11FB9EBEFB6A625DBFE83B41F7D3FC6F
-:10AFE00016C98B53F48F39417E0766931CE83AF3F8
-:10AFF000FB3215F4738FF3F138D30ACBD264945F2C
-:10B00000B7044CA5182FECB08C3A8C7104F163CACC
-:10B0100047235DC75918D115F83CAE00D6D7B4AB5D
-:10B020003F1F1A87CC65D3F3B9C647351A7F57EA55
-:10B03000F918D6A71BDB5F4EDE0EC6C730FED00266
-:10B040005C67DFD3EB9BBEFEA2D65B74FF83C901B6
-:10B05000FC89948BFD7074D2BA4AC3E8BD6C5C77EE
-:10B060006DDABA1B89F33019BAE99E4E86E41D4E9B
-:10B070001756C7782DA48FA2E0D6E04B07D9C64A51
-:10B080002E850B7F14CD5EE43F6EF44BA48972686D
-:10B09000E763AE7EB860FC1B100F6C3987678BD4FA
-:10B0A000C0E586D81F68FE8C3A6DBEFBF5F32D8B8C
-:10B0B000E1F7D63DE877C276EE51C3BF0DEE7AA137
-:10B0C0004FA75AFC8F9A610EB73967113FDC011AFE
-:10B0D000CD09F3FF5B6AA006F1D12C055FE9C92415
-:10B0E0007F3CC57700BD271744D8011A5CD1F8A86A
-:10B0F0001B441E46C31D8D877EFA742763AADD7725
-:10B10000EB9B57D47CA2ED02B749EFCF7309BF9BED
-:10B11000ABDFCF5680E5D52CC64B7E36AF44FBA8BF
-:10B120006AD0F32847ABAB18F9475C3603F9D9343A
-:10B130007D3F187FDF703D9737D50B99B84FC7E734
-:10B1400011CD5F4358CF83F49E8345DD381BD7ED87
-:10B150007C9B2E0EBEDAC6FDF32B0B24E197EF1974
-:10B160008D7E89BEFC25FEE09ED1283FA6CBFA73DA
-:10B17000AAEA8BDC1FECBA28515AED3D311AFD2C9E
-:10B18000AEAA9ED128871E19EA5B85743D6EE0FE4B
-:10B19000F24BFC160506CD1F7C457C174D0FEDFCD0
-:10B1A0002F26CDBF01C73923759761E1862C713EEB
-:10B1B000C30299C8974E476639FA7140CE7DF30DA8
-:10B1C0006E1EB108F035262310C2767730FF78BCAA
-:10B1D0006BE9AA0A18F97905A3F92F12F31F2FF4C6
-:10B1E000DFF9CD3CAEA2D257F0041E89D41F35B290
-:10B1F00010AD3F1FE9B1FB04FCE741D585B1FE2E40
-:10B200003BE9C179AFCFA27889FC0D86FE772BE0B0
-:10B21000EFB0508CEEDD8AC29D2E5DBEB83345572F
-:10B220007FE4FE2C5DF9A8F0705DF955474B74F989
-:10B23000D1DDD7EAEA5F7DAC4297BFA66792AEFE4A
-:10B24000F74E4FD6E5AFEBBD4B57FFA3BE7DBCD04D
-:10B25000DF415F7701CC7BB6C69F1767EADAFF292B
-:10B260006EC251E4CFD9AB79FC77396048F78E478D
-:10B270001BD7F30DF007E93B9EF552DC5D5D48F20C
-:10B280008619C691E9ED8005FB3B088F97BBF79EB9
-:10B29000EF9E6140D3F78302116F7235BB9AC78D61
-:10B2A0007E3B5DF358CEDF4557B3474F57ABAAA758
-:10B2B0006B6C819EAE76AF9EAEF163F47475FAF45A
-:10B2C000744DA8D2D335D1AFA7EB90697ABA2607CF
-:10B2D000F4744D9DAFA76B7A839EAE198D7ABA65D3
-:10B2E00006EFD5950F466F4D1E66B72ED2D5EFA34C
-:10B2F000BB7F3EC511E5B6FD58D7BF46F720FC41E0
-:10B30000BAE73311EFF83FA47BF2303DBD417FA493
-:10B310000C1B4D7A3F1DD369F9C2BEF60FACF73551
-:10B32000F913A96723F79783C9A54BF48AD86F0E41
-:10B33000AA57A2F69BEF31D07B34C86AF21FDD29F1
-:10B34000F8F3500CC7FB1758740DD4833A6300AE62
-:10B35000F7106E18E7BD9842F20BDCC53A8DD8FFA6
-:10B36000DDAC9BD2E9AC97D20073901E9DC9BC9412
-:10B37000CE667E93F013DC302C11FD073D65A88767
-:10B380002FCC78EB389D2FBD917045EF3D7C88E741
-:10B3900018B98C9D12F2E0249E6740FEAC55F8D39C
-:10B3A0007C4C7547E0ED94F0FBCD1C27913E647218
-:10B3B0000CC559CDBC43227D32F3FFF2F48E61DC23
-:10B3C0001E8D4E9B1B35FCF17DCADA612AC9F7340C
-:10B3D000D629F41E0BD8B2A91F7EFEF0B489F693CD
-:10B3E0001E0B87EF798929635C74ED8CE8EAB170F4
-:10B3F000789E37320BE2F339165091188F2820A22D
-:10B40000F87D87E1C81F33FFEF5B59E82F8B59B5F3
-:10B410007B6AE535783E125C4AFEEA1F30BDBFFA12
-:10B42000EE0689FCD53F003821F538BC1ED4975A6A
-:10B430003E88F0C23C2AB11E7C1FE26990D03FF4E6
-:10B440000FEB6FCF8F79BDBFB3BFBE7E18870B7F69
-:10B45000907E9AFFB1C0C0E3157AEFE7FB94ED3F11
-:10B4600060DC8FD6182C0FE2F9A40C1B4A8C6732D3
-:10B47000F27BE86B8765F2FB6EAC9BF6F9EC8866B5
-:10B480005F0648FE16897B0E67C5F9DEDC0E0BC32E
-:10B490007899A2DD075D789E371778B01BF5B0125A
-:10B4A000A077568A36BEE6E2FE37A313EF2F6AFA7C
-:10B4B0007F703E55D8A988FB02C0770D03D91F7B4A
-:10B4C00086F373FAE6A6EE61781EA7C1F370D35136
-:10B4D000CACB8A97E20CF11D2667447B931BCA23D3
-:10B4E000E49D6283F61172C868F3D36326CB9BBADE
-:10B4F000E99CCF28DE8B5A91B6C81188D8C7BD30D9
-:10B500008C8FCF2C41E64862C204C754398572ED56
-:10B51000AF8CEF67CD1EE827527E5E4C64917EFAB9
-:10B52000D6A66304EF722910C04ECC392C6C05FAF4
-:10B530009815BC730BDF37DE7814E3A94CF645DEB3
-:10B54000B03A38DECC1EE542A43C7D7598D8470B56
-:10B5500079FA2F4DBD85384E73538F862F86E7A617
-:10B56000C1647E8FBEB9E913FA6EA85289DF5EDD31
-:10B57000987F5085F2E3F017DFB531BB395CECA260
-:10B580009BF4EA74C107E8134B07FE39DE68243EDA
-:10B590005B9C6E237FFDE237730FFA603D9B60BAC0
-:10B5A000F27780BB7F1C8E279390A7C04F7E940FAD
-:10B5B000A61485FCF62EC764A2D3DFDB9F865F93BB
-:10B5C00095D17B44A6741BD905570AE7B9287D0598
-:10B5D0007821F9BF58E0457B5FE9F8038CF60B8BC7
-:10B5E0001FE2FEBBC5B58CE2FD5923FC94F5F38D3B
-:10B5F000A66712F12518F8D8D6042B0EBA78ACC974
-:10B60000C202F96087607C7C763F1DDB7C8A138FE9
-:10B61000FAD754BA6B307D6CCCC936147F8F8FFD4E
-:10B62000B21B53F4D5E3F88E061642FB98CEE061C8
-:10B630007CE77CC8C3F871A23C2EC0F3F1A23C7E2B
-:10B640001ACFA7FB5E902A11B0A873A5749B6B62FA
-:10B650000ECAE9D98CDFB716EF2D6C11FA22D5E6A8
-:10B66000AAA9C4F2BB19DDBFD0CA9F14E5C9B60FA1
-:10B670005BB3518F4CD5B7DF28F030C4F661DB38AF
-:10B680003A7FD2976BE73B89B6F347A97D91BE7CA1
-:10B690009D686FB79DEF1E87E539FAF11F15E5B17B
-:10B6A000362E0F999FF1770144F923A2DC8AE53801
-:10B6B000BE9797CBDAFB17A2DE4A0107C6B691FF09
-:10B6C0007318F77F6E6DB214115D9A2E127D1E6B8A
-:10B6D00062949F34DCC5EF6557717CBBDC9C1F1CFA
-:10B6E0008D6CC0F700260DE7FBAA38B5C7E71B40F5
-:10B6F000EE69E52E077FEF40F698889FCC3621371C
-:10B70000C47AEC931B5283973319F7975F8EAF611E
-:10B71000A15D40FB6828FC205FA73D60608108793F
-:10B7200099B230860522EA7B66BB74F9A4BB5374D8
-:10B73000F5DD53B374E5B6D2E1BA7236D545EB66A2
-:10B7400091E0AF98A2125DB9F60E03DB2EEA89F5FF
-:10B750006BCCB95657EF7C811A8F3C7E6A22E81F6A
-:10B760008A2BF05A503E2CB2670D41FDF35CD31882
-:10B7700042CEF3B0AEC06865BB9C3CDE7C179EE356
-:10B7800041F9BF36F9E8FB0E2857217D1AD69D0AEC
-:10B79000F53B9A1C947FAAC943E9962695D2279B2C
-:10B7A0000AA87C639397F24F40FF98AE837EF0FB2C
-:10B7B000DAA62ACAAF69F253FEF1A669947FB429CA
-:10B7C00040E9234DF3E9FBCAA606CAAF686AA4F4B0
-:10B7D000E1A620A5CD4DAD541E14F4DE25EEAFEE4E
-:10B7E0002AE7F7D2A3E9F8F07049F75E9CBD3F7EE7
-:10B7F000E4E1E1183FD2D94376B8163F82F3A6FEC2
-:10B80000AC7CFED1FD6D1ACEFD09C359F7D258BEEE
-:10B810009EE99C3677BF77592CF07D6A03A743E6F3
-:10B82000FE5E2A4F9ECF69B149E865E60EB2B4329A
-:10B830003AADA77A67A5EE8A587EBE4DFE0CE6812A
-:10B84000799689779288ED4206844B19C3F5A7460D
-:10B85000D7BE793B399C38FF81E0DD21E0954B3B39
-:10B86000F9FB27556D6164FB185F03BD7F6299E6A4
-:10B870000F2B90BAFD017A8F61F8C509B0390379B1
-:10B8800073F17AA6429AB650BF6F4B995DA2DB174F
-:10B89000C9171F632AC8015B917E7F1593B348D7F0
-:10B8A000CE92F6635DB9C9BD4C573EF3BECCE51EE2
-:10B8B000C4672A3FE731AF5ECA9201AE39ED6B082B
-:10B8C000AE77041DCF4A2ADDE30EEED6E21EF8FE67
-:10B8D000E259A15F986535D963F94E9ECD8B0F1A59
-:10B8E000503F7CF66FF124979E79CA10427F2E88D4
-:10B8F0002703AEFF4230FBB0BC98F5501E435630D4
-:10B900003F8AA932E6AF62BDB4BF82FDC5EF866350
-:10B91000FCA81C78CA0AF933E9816779FC5A98F4C3
-:10B92000679EA0679EB69FDAA044FB79DF1A4E7C23
-:10B93000A8BFC7D622F6172D56EE7F5BEA2C1B82D6
-:10B9400076EBD941E20DED9E578FCC067CDB930F51
-:10B9500052AA7D7F54350C784FFB8F51FC3F0C98D9
-:10B960005DF0FF1F119E33A56F27A11BAA2EA7977D
-:10B97000D6C159C9E79981F87D5DE6FC083B2E9C4C
-:10B980009F22F0ABEC2EF7CC003C2A6F667B83AC99
-:10B990007F9C679A8E65633C8096CF13F1B23B9B88
-:10B9A00092732A23BE3B0B393C05ACBB0AF55541CB
-:10B9B00091C11BC28E7D0E9D1FC39AD3E6C377072C
-:10B9C0009412E64531378CB52D43DDADFC4DA6789C
-:10B9D00027E5D0354C85FD8CCD1666181FA6F5CB16
-:10B9E000843FE4012137BF7454C6D37B92297DF292
-:10B9F0000F7524FBD2E6EB463EFAB2DDC8E7754888
-:10BA00005F5E60E3715C730B4C2155C2F7CBDAE8E3
-:10BA1000BD4465ABC4D232118E718407B62F96F83F
-:10BA20003076C3081684F552EA0CFC05F9E44C584C
-:10BA3000DD67C8163C09F56A0B4DDBD03ECB47BC31
-:10BA4000D8102F77E654E2D0390584DF3962DE79E9
-:10BA5000857CBDB6A447C1C3BC3E7C57746EBBE6B3
-:10BA6000C7D1CFF3D1D28A5BF1FDC5E66E99ABB5F4
-:10BA7000287CAE32768F98015D9FE901B8648233ED
-:10BA8000AF10E5C2863216243DCEE757FB94C4368C
-:10BA900065925CAA223D3EDAC022CF31B5B4B8909F
-:10BAA000CBDF9786F3F7DAEC9E23C48FFDF9C3470B
-:10BAB00066033E9E33B0023ABF35F0FDB116372320
-:10BAC000A31F00D29F146AFED2163609F5B6D340E2
-:10BAD00071A072470CDD4F959D0AC59FB7D82A1DEE
-:10BAE000F7623F0E85CE6B26C863BBD18E363B0D09
-:10BAF00057A11D7E78DB8FBB317E474E5718FABDAC
-:10BB00005A1C0AB743D20C1497A7382B2D78BE9332
-:10BB1000673B598EF83CD8F1437A8F417E50C4CEB2
-:10BB200008BF985190AC853550FFC13445BCEBE25D
-:10BB3000AB1E95248E2654DC0F557D82FBEDC38E03
-:10BB4000F356DC17A8B6B9E40FAC2BE4FB44239EF4
-:10BB5000E341FEA925E79D28BF5EEF58EECA447B6E
-:10BB60003AA4902D52F075730ABD3BD061A27711B3
-:10BB700034BC660415DD79607AA33E6F8E3A1734C3
-:10BB800046DD479B85E3939F781A0B47CCC7E8E1D6
-:10BB9000FB37E6B6D1FEA7AE50BC8729F273300F53
-:10BBA000A4D8690CA678013F873AE666E0BC2EBCB3
-:10BBB00014A0F8EFC1ECFFD242558C17B41AE8FD7F
-:10BBC000DDB015E3C1B737312FDA79969042F1F83D
-:10BBD0003B843CCBB171FEF717713E8F4E73DAF8A0
-:10BBE000BA5376C58462916E8ECE9220ACF3C25762
-:10BBF000273215F4608EC367407F7C4EA3C98BF655
-:10BC0000E7845FDA884FCEDB783C95D2F8888ADF0C
-:10BC10009BB7951544DEB30B3539BC289FB6355913
-:10BC2000BC18A31E1A44BE663B0D14C7AE1A785C3E
-:10BC300065BB588FED85B194AE1572E6692538194C
-:10BC4000E17C1AE889F1F3075773FB78D1520BC1F5
-:10BC5000B1E8F56CB2AF06C3DB334D1E6F0EC2B355
-:10BC6000DA9082FEAAF29539ABF09D8C4576FE8E75
-:10BC7000B01C3F9CFCB6EC774686F67C73DCB5DEE8
-:10BC80005911F25D8E1F5B807C25CBC114F4E7FC5B
-:10BC9000BCF0DC6D18570BF4DB84F9DDCFFDE13629
-:10BCA0008CA3DD690FA6609CED4BCFBDCFCB13837A
-:10BCB0009B30CEF6E073C779797A30C500F9D79F0B
-:10BCC000FB9097E7063761FEADE74EF1723C030348
-:10BCD000D9F9DE739FDE16447F8BC93B1F05F22F17
-:10BCE00000FE2258629D22FD40E0452B7F01BFC32C
-:10BCF000066C8F48A3CBF78976FB0729FF9528EFC1
-:10BD00001AA4FF03A25D7890F68744BBC383B43FB7
-:10BD100022DA1D1DA4FCB7A2FC8D41FAFF77D1AE3B
-:10BD20007B90F66F8B76EF0ED2FE0FA2DDB141CA8B
-:10BD3000DF17E5FF19D5FF7151BF477CCFB2AF7E4A
-:10BD40001FFDF7592047502E15D857BB709D6F6BBC
-:10BD50002D25FE6F2EE3E7541ABF67498CDEF7AD41
-:10BD60002EE2EF8A551771F9FB67D13FF0E1E3C886
-:10BD7000778BDE9429AEA7D9E03D1D4239BACA407F
-:10BD8000F6C0A2D7F97E7DD14A2514792FE7CF518D
-:10BD9000F02F47F880715B3085F576A690C7F59B4C
-:10BDA0003D1E6F75843C333AF47990170CE52EC82C
-:10BDB0006F8ADF2E5859D15A00F95497812C10A55B
-:10BDC000D612C6F73A14BBD00B8ED2B60284CFA6D9
-:10BDD000D03B059A9C67368FCEAFD16253E8DD36F3
-:10BDE000D9CECB27FC72AC03EDAC1616E8F6617B1E
-:10BDF0008F4276FCC1D61207CA3D937DB603D7EFBA
-:10BE0000BBC57C5E9575053128AFE5470D24BF0F96
-:10BE10003BF87ADFEAE1F14EA057E89E13C86B2F9A
-:10BE2000EA887C165E8A7273E763FB66703F1FB315
-:10BE30008F2AA37B44DAF9B6A444EC03AE2BE2F8D4
-:10BE4000C9107A4441FD02E9D3A5E2FE4B90FBA361
-:10BE50003214E6498DB8C77B5D91CCEF1F2988234A
-:10BE6000E84BAEA6F7AB862E5174E708690FE8F3EE
-:10BE7000A628BDA144E995EC569093BAF313872EFA
-:10BE80005F5424FC3C5EE6453B76C22F57933C3C16
-:10BE90008FFA4D1A5CEEF5C95F218F9F4604A01CF6
-:10BEA0000DF27BE4075797FC16E9BD68A581DE8D8E
-:10BEB000BE5239FA678405F0901B90482FC0845217
-:10BEC00070DF74393CE41AFD2E7A57E332F8C85D0E
-:10BED00057EA42799B1B50A8FF4BF4C665F0F5BCAE
-:10BEE000E43D16403A3A63845D0D0C807E3B574C2E
-:10BEF00007C6179B843F458B17568628FC5D7C71CF
-:10BF00005F55167CFC30F3A9AE6C7C17A881FCFB56
-:10BF10008B773FE041BB7D8521E0C0FC51D7A45E1B
-:10BF20001C67116CFA117F3BB10F7A1FF3B7B7FB97
-:10BF300000FECE90497BBF328CFFECC63820ED7DF1
-:10BF40004C0FD96BA2FEB5B75702DE3B1547219ABD
-:10BF5000A04B775DB7DE781DD437B1BEFA78EFEE2F
-:10BF6000B9C306F17EE6B8F595209776C730DDFBBC
-:10BF7000A0BBD1CF4EFD4D588FEF81C27837C9B0ED
-:10BF8000375B5B74F37A5B723F3CEB8AA7AC5F8AEA
-:10BF90000E3BB14F7132FEAEFB19B5270E970FEC79
-:10BFA000577E5204F4ADED389914B95FD7EAC78BC8
-:10BFB000FA755DBD75BB54AABF94EAEFEF8D2B22D5
-:10BFC0007CF79645D68F137E8088FA2BBEAD7E8196
-:10BFD00006CFAEB76F2FE2F51FC5FA67D59E248A4C
-:10BFE000AD898227E1D2FED77E5BFFC345FD33E1F9
-:10BFF000B7A9FE59D693549C49ED3661BB736FBC0B
-:10C000005D26E69D84E738EFDA7C4F16815C6AC0D6
-:10C010003ED07E561A54FCDE696973A0FD6635B6C3
-:10C02000F9510EE7E03B5F63FAD3ADA83C465FFAF7
-:10C030003D9A9F3B2D2CA11AF9B5D140FB9BFD3DAC
-:10C040008647902FB7A68D75E0FE79B7A9BBA408E7
-:10C05000EDD7BD36B25F0D199F59D16F6ECEE7EBAC
-:10C06000DFEA6CF01641DE9A5E44EF74CA0F2DEAE7
-:10C07000A4F7C27FCADFD1527E660A6C477E0C2FBE
-:10C080002A9813B1BED7151B09BE95AFD956E3FE4A
-:10C0900060A5D1DB968F76B85DA1F84BE567FB26EE
-:10C0A000917DF80B0323F90FF3AC807E5B6628F4D7
-:10C0B000FB0E4E14CF3C5844F8F0FB2BA0DED044CE
-:10C0C00045C27B3A0F2B7E0B9E7798855DB7D5CB0B
-:10C0D000EF6969E37E2CECCF8F8BF8BBEE5BD32E40
-:10C0E000BC37CF8DEF3098E87EA56DA1216C8AC357
-:10C0F000FB66DB4ECF437AC6F6ACC4FBC631298A59
-:10C1000003E7F7643594D1B95C277D0FD61A68DF51
-:10C1100090B0D0E043FF634C8E49E7EFB0C1389157
-:10C12000FE906F8A03C710EEABDE546E423C7BEE8E
-:10C1300037D03BA48F7ADEB51800CEB8527D7BC7CE
-:10C14000587D7B57A5BEDC5DAD2F4F9AAA2FF7DC3B
-:10C150006D8AF2EBE8F33334BE029960033D15C3F8
-:10C160008B588CED4213EE7B56BC16C3883E4BD6E3
-:10C17000B7E5E3FA8CED257CC50C8F21BFC08A643E
-:10C1800013C9F515C5DCAF7F28DD7413E5615EC802
-:10C190001F5BD38ED07EE412BCD84E7F8DFDDB5862
-:10C1A000C477B4338A7D7F291ACDF39E32F4E3310C
-:10C1B0009287CF4B3EEF41C4F75BDC5FB1B591FB9B
-:10C1C000B11F9DCAE311690665B8DE79FD38CBEA77
-:10C1D0006EDC97C5D95AEFC738CB68BC2689F38681
-:10C1E000AD78CB16F92EC0DF675EAEDD77C2EF65A6
-:10C1F000747B81DE1F1B3F82F38B53D809F19E8431
-:10C20000A296887B1349C26FF2F8D89956D41FBB07
-:10C21000C57B1E7DFDA934280F3D45BF72B124F6B4
-:10C2200053BCFD7AED9C47E4139D3CBFFBB0EB266D
-:10C230005C5FEBA7BA4A70BFBF42D877F16926DFCF
-:10C240003098D7DAA3A6A03412F20A3B6C04BB6084
-:10C25000B78B8F6B7A3D2688F7F3D67A4AE9BEDF33
-:10C260007562BC17CABDEFE07AEF857584715F6BAC
-:10C27000DD5E6B8938370D027C685AE03EE56075FB
-:10C2800009ED77D7FABC56D49B6BD3BC568C97B6C6
-:10C29000262B0E8C077579147A8F6DAD25E040FB47
-:10C2A000C7058AD484E749E96D13E99E1BE0DA509B
-:10C2B000C68F1A988833C438BF0481CFAD9ED90E7B
-:10C2C0007C1FC19DB3E747E8A74FC0FEE2783BC49F
-:10C2D0009353E0697CB14A70BB45FF09B35FA0FA94
-:10C2E000F8D35216D19FA0A369220BE13E4D1B5FEC
-:10C2F000EBA7AF7FE6A37380E5BFE5785B9ACEDF5F
-:10C30000A132DDC7683FF742796027F2596F720C9E
-:10C31000C9BB144F4A05F251CAD14D93F1FEC3F285
-:10C32000DFC6F071E6707E4F5198E57A9C7762C067
-:10C3300081788C5EAFC987DB6A902935BA44AFDF5C
-:10C340006485B5CAAE4BD771B2C75D91376280F5CF
-:10C350001CB55E928FF63E88FD47AFEB2DB1C74707
-:10C36000713D12F15DBE7CBE45EA5949723859A152
-:10C3700075961E351EBE6787798919548C4F5E5796
-:10C38000ECD4DEAD5211AFBB4D8E71367EDE4EFC6D
-:10C3900055F1E2EABB7E07F90BF87B73A056EAD1B0
-:10C3A000B66ED28BFB03F9587FB312780AFDE99B76
-:10C3B0008F0DA17722CDB1FC9D4F53D4BB259ABEE2
-:10C3C0005857CCF7316AD4FB96DF35ED4C4B2B74C4
-:10C3D00000CFAC7BFEB77FB024FEE3ED9FB4C39DDE
-:10C3E0004B6DB0A6B7ECBA653DC6475ADFE4E59B96
-:10C3F000211F54102F0BC9EF7268E8BD34FFE6F718
-:10C40000CCE4CF2A96BD1B30CF3EB0923F6EE7DE24
-:10C41000B1D3709D34DBCB54B4F79F11F267BB5896
-:10C42000CFD1F3924DDE00DA03D1DFB7168B73095B
-:10C43000E63DD601F42D7EDA44EF25F5C547745864
-:10C44000F9EF331376E86C21CF66EF5B35F420C348
-:10C45000F7306AF615C3B8B3ED9549084FEA458938
-:10C460000540FE6D16E7B3A9EE1724943369EEC3B9
-:10C47000E528EFD359F752941BE90DFAF3B2D48BA8
-:10C480000AB5DB9DE2A3FEF007EF399B9858D3AEC7
-:10C49000005B8A723E859FB7981C31FC7EBAA7521A
-:10C4A000779F597B47F655810F13E0D45802A94D69
-:10C4B000E1F7E7A3EA1F15F892D16F8FCE7FC791FE
-:10C4C00063D4AF4DF92CF25D16DC9792D05AC8CFE9
-:10C4D0003F014F41DC87B278173F2FF5F9D4C8B838
-:10C4E000D65490BBE6128C3F09529C48B2B89FA02C
-:10C4F000C5F500069CE877D3E23EB631BD3DA2A566
-:10C50000DAFE3CA751A67D47E1AB56BE3F686521E8
-:10C51000AB84FE3046722767353F9FD6FC62D5B8A4
-:10C5200098683D380C3CFEA793E29935BB0AE84B6E
-:10C53000726765D47B4FDA7BD55F88F5B4B9C941A2
-:10C5400074D4CAD302D174D49F736AF5522FA6B2A1
-:10C55000404264BF21EA37B5710FF143EAC5A154E7
-:10C56000BEB949BD4CFF5983F49F4CFC3278FF693A
-:10C5700054BE25FCAEF31640C593BD7B9C7E15E5ED
-:10C580004A78A277003CA73EA0979323F7EBE5AE4D
-:10C590008697CD8ACF5D03F8DEFC80C1DBC130FE1B
-:10C5A000545FAF2AF3F74EFE7EB4563FEC9E82F501
-:10C5B00017F2FADF3BADAFEF2FDF1B5D9FE0BBE172
-:10C5C00062947D18459F687801AEC4DB22E01A674B
-:10C5D000D1FFFEB869332E812BF18E08B86EF4E8D6
-:10C5E000EB07960E0CD74D05E66F854BAB77EB98B6
-:10C5F0002BAB173D8F2955E641F0CEEBDF31EDCA6D
-:10C60000FAFDFEFC6FAF774F63F43841EDFC4867ED
-:10C610008F243472FBDDC17A29CE44B33B5CCC213C
-:10C62000E2BFB8DDF00EFE17F6B34B46F86F1D31D2
-:10C630001AF1EFBB7B9D8AF754B8BE62D5FC7D48EA
-:10C64000D8971447BE7FDD0FD732EAF7658C772283
-:10C650003D6BF1A2DD5998CA2CC9687C794259F822
-:10C660000ED8F4119ABCE6F1E5C305EE9E4FE95CE5
-:10C67000E4A4751E72213CDF75DC7B47F8E68C482C
-:10C68000ECAF3F98BF45C393C9D449BF3FA1B7D6CC
-:10C69000E645FDF02E1641BBA76F3787D1AED6E237
-:10C6A000508FC54E3F92A8D2FB038BB1FF69774CE8
-:10C6B0005C8E79E95082BAC886F7977AB47B9E3F40
-:10C6C00042BC2DB40432920C74BE9A8FFB61E64FCB
-:10C6D000109782FDC503C56968F0544A1CFF316993
-:10C6E0008120F65369E8DEEAC76F4A37DF673B12FD
-:10C6F000F9FB47F8CECD00EB5FC34385E8E7A0D157
-:10C70000FB552FCCEFE09A78BA0F3F3BE18EE9F86A
-:10C7100036CA1C833F090FD023E07E8CE0B6CDC81B
-:10C720004846B88D026E4BA2C0BB2FE7DBE0EE8B14
-:10C7300097F9A9A4BD534EF917834EBA776E367C8C
-:10C74000F1EE14D4C3C5062FDA9D9BC1BEC077D6C7
-:10C75000FE8FC0F7163C6371D1777A7FCD23EE5FF1
-:10C7600079D61BE8BD157FC54B44A7A7EB6C5EDCF3
-:10C77000B7CF602ABD6F3A4BDC47F963F97FBFD270
-:10C7800003F3DB3522F02CD2E79E04C3D077098E69
-:10C790004021BD6735F6CAE267B573F8C9C23E9855
-:10C7A00023F03885F9286EF7361630E2B86F9F35DA
-:10C7B000F9D02E7D5BC423DFC182F4FD4E16A2F4B6
-:10C7C000FB2C4CF57F802FB742FEADD811E98D00D0
-:10C7D0005FCD13F9B9B81E23F0FE8AE0977BDC9C8D
-:10C7E0005F3E1E82786F4FBC22FEAD9138FE968C64
-:10C7F000081CC1798FB3A86E2FC2E41897867E9467
-:10C80000BEF55399C8F94F71E47EDBFAE93EAFDD1E
-:10C81000BBF7D992CBF0DD2DFE73A3EF3E8A17C78D
-:10C82000B87C37D0A15BE5F70D416CD88340A7AA4F
-:10C830007299E2F6567C2EEE49A31303EAFD669444
-:10C840004CEF8469E792B788FE6E49E3F706ABCBFD
-:10C85000A7B4C4035E267CD5531A86B42A4D7F8FB5
-:10C8600070A2BB839E0E9F94A3FF7E136BA303E273
-:10C87000EA227D9CF92D51FECF833836F0D527234F
-:10C8800044BCE470363CF2BEC1ADA2EDF9EA2F4CD7
-:10C89000E760FCF491815EC4E3A29BFF389DF675CE
-:10C8A0000A7BF32A985FDDBFCB644F7ED80433C97F
-:10C8B000C7B86A0BF381C17F0AEC0ACC9F6EF250B5
-:10C8C000FA29D801987ED65440E5679BBC941F3F57
-:10C8D000D2FF17A4F3CCD6CF15D4472BB4786C0174
-:10C8E000871657B842C44F2CB62F3A86F10B8B29C6
-:10C8F000E09DC1626F9B80E0DFBBBFF308A6F05DE7
-:10C90000C67DC8E23512F975E61C0E2C4732CF7B86
-:10C91000A3E7161413A37F7F3209F7E9B568C702AE
-:10C92000EB2F76F92C23617C5FD789230950FFE335
-:10C93000A63104DF274D3E82EF4F4D55944E1FE93F
-:10C940008FA37AEC737A6FE9E65D2714FC3D68E308
-:10C950007D12F9EFAFF7B15008F0BAC1C8E5FB0698
-:10C9600090EFB83ECB8B276F7900E11B11F08C0460
-:10C97000FCDDE69A353E01BEDF32668682F5EEF8D2
-:10C980000A7450663F1F5E8EAFCF1C90083F670E43
-:10C9900038091F1A9E6A05BDCEEC2BBC15DF1F3B64
-:10C9A0007054A6F8D3F3170D04DFF96331149F1AFE
-:10C9B000DD7ED1DEEC21688FFD09E887071F8BF64D
-:10C9C00016923FFE4FCFFF488D8CFBFD93ABF3C219
-:10C9D000FB28A7FE8BCB29B0374F6D423996964284
-:10C9E000EFE8F4C5ABB18658D4637526B1BE40CE2E
-:10C9F00060FE4F317C1F5CF68BD40A5C2F381EC65C
-:10CA00007B99C5EF9B80FE8EFF18FADBB7C943EF19
-:10CA1000EE7CB6FB892C1C7F67E79CF73741FF67EC
-:10CA200042FCF74D9C619D677F85F274BB8DFC963F
-:10CA30002B24800BF5E98E14CA17484A4C2339334E
-:10CA400042B46E0B2455C177C816BEB03105F90B40
-:10CA5000EF8B635CFDCB6B62494EBD6CF41E6FC403
-:10CA6000FEB6F0FE9E7DECA10FF763FA686DC94338
-:10CA700090DE3ED245789FFD2F0B86637BD0D7F4A6
-:10CA80007B959F7B510AA31FA4B8FDE0328C631AEB
-:10CA9000B9F9842105D251DBA5664C0BD3271D457E
-:10CAA000FFC1DD235582E3AA5D9932C6A60F4F0967
-:10CAB000BD7F038F1BD1E9F7A2F6CF2B709BA9E9AD
-:10CAC000F9E152E7A71DB82F1E7AAC84DFEFE2EF41
-:10CAD00044EFED9AF2CEF719CE032C08847B8689B9
-:10CAE000E22E5828D881743E1328F0D2FB26FEE0AF
-:10CAF00046E4AF3381247A4F7A9F211887BF2F29CC
-:10CB0000789CFF5E9F17B7BF1587F114F17B8C0CE3
-:10CB10007FFF74EDA8DE09141F92AED27E3C7DEB40
-:10CB20008D55889FBA3D7B3BA89F85162FFA63E7FA
-:10CB3000EFFD82EEBDB0893C0EF5CC1E9E7FA4D2E7
-:10CB400047EF8ACFEFF833CF77FB29EF97839974BC
-:10CB50007F6216B7779E10FA8CF58C6091EF1269A0
-:10CB6000F47A048AB17C43663019DF9FD2F420E85E
-:10CB7000AF265C7FE876A4F68E29FCBEFA15EA2F74
-:10CB800093D0475A7F4F98F87BB92846F0F7CF6C7F
-:10CB90003671BDBB03E40DF28BA67761DCC7715C17
-:10CBA00093B82F930A4A7614CC27F5093397DF57A9
-:10CBB000387EF4BD52CD0E9996D04CF7473F4B0DC1
-:10CBC0003C89F241BB47CA142FBDEFF741AA6FF36E
-:10CBD000C8D1FCDD0C9C03E8C510D6AB93C18ECA4E
-:10CBE0008EB0A32C57A617FF96EA7B06DB5F69FD84
-:10CBF00068393C56C0BFD86E203C2C5E67267FD873
-:10CC00005871BF74ECF963B1284F16FFB984E44A38
-:10CC1000336303E2E795261EE7FD6BF423407ADDDC
-:10CC2000973D32ED470E1B161E01FD4A2090FFB0C6
-:10CC3000B739BE94F23E24F7F55F1A06DC2F6A2955
-:10CC4000D0EB359C9FEF2BBDFFE186AF1CF4FB2999
-:10CC500099CD7545F3EE7F67473F7FEDBD2B985F1C
-:10CC60000FEAF7C59F1B887F177F5E4272B3EB0AFE
-:10CC7000E76B75FBFE03E91A3D1F80FFBF0682BF0D
-:10CC80008FDF7BAF0CFE072546BFD707D415F9B75A
-:10CC9000BBC47B025D0B8AE85D8B7DF82E08CACD94
-:10CCA000C9FCDE5117F60DF5BB121DF4EEC6CB46DE
-:10CCB0009E0FDE29DA8B771ABBEE4CE1EF66981BEC
-:10CCC0007E578CFD37F3F8B82E63887E1F6CD74FE4
-:10CCD00013E83E81163F7E4CC8ED6629FC7D7A0F35
-:10CCE000E47313E3EFEA8553EB4BF11D90E154FF3E
-:10CCF00098F8FDC957FAAEDE5D823EED1DA11DEB31
-:10CD0000018EFF07358A15A9008000000000000091
-:10CD10001F8B080000000000000BED7D0B7894D500
-:10CD2000B5E8FEE79F99CC24936412421E8484C91F
-:10CD3000831024E0E40501421820A1A8680308023A
-:10CD4000C638212184BC0848CF492D3583090F15E9
-:10CD50006B38468D8A3A58A0A0600705440D9E01A5
-:10CD6000D4521F35D5EAB1DA6202880F1E0941FD9F
-:10CD7000B0D7DBDEB5D6DE3B33FF2451DB73FDEEEF
-:10CD800077BEEFA65FDDEC7FBFD75A7BEDB5D763EB
-:10CD90004FDBBC74BBCBC6D80895357832186B4BCB
-:10CDA00072C44542FAA1812DC6FC9F19FCC531F61B
-:10CDB0009881B9CC918C5D655F166D1FCE98F38616
-:10CDC000103D0BC742479C92C3D82315A3D9DD0A57
-:10CDD000645B1F622C9AB1C526467F4B83C326B085
-:10CDE000ABE99F0ED344C616F2CF6CC9F29D66A77D
-:10CDF00005F255E66E6502631F54DD196A83F1166C
-:10CE00003A556F501854B8B1C8D195CEEBFE2319DE
-:10CE1000C775D0B8AC6218639321D57BCB198CFB56
-:10CE200072AF89DD9D0475F06FBA2F65CCC518D43B
-:10CE3000FFCCCCC7AFF3CCB8FF8CEC0FFE5F65B472
-:10CE40006C56C2B13CD1CD60FCFD239CA3EDB98CE6
-:10CE5000AD3A7CCDFD674CBE7A15CB8BD298CE37E0
-:10CE60006EE03881E335BB752E038C37CAB420E3FE
-:10CE70000C346986021DCCD3E531BB7726E1BC7B3F
-:10CE8000FFBC02F2CD8BAFB2DF0DD939F34D0E25C9
-:10CE90008AB1BE0341EE2005BF073B705DCD47421E
-:10CEA000DD3AC8DFAA70F8372B8CBEBBF61BDC3B23
-:10CEB000E15BADD1BD6717B4AB7D79AC1D4666872C
-:10CEC0008CF01F2C7F31849787399236E460790C7F
-:10CED000E1F725832D9CCA7FAF322A0FF6A64500C5
-:10CEE000BC1B639DB310AE238200FF16EC977F3FFF
-:10CEF00089EB00F89C846E11BFAE8650EA9789BC1E
-:10CF0000F317C3DC77D37A1C71CB317FDB385A8FB0
-:10CF100013E701F362F50AADF7A4D57D571A949F84
-:10CF2000EC184EF38812F470B2F8EBB72641BD93BB
-:10CF300087553BF6F99746D56B0CC3728E0F65BECD
-:10CF400029AD1DDA9D7E31D41E04E525F7D5BC89B7
-:10CF5000DF4BEEAC9B4B69F5BA1B18D4EFBAF3A3C9
-:10CF60004467C6407C94D4422B3F3CAEB23B4A114E
-:10CF7000BFF7D89D65B8DE55195D950CE8EAA2B1FA
-:10CF8000F371A632F6FE4867057EEF79E1D35DF8CE
-:10CF90001DF094563C1E96A1073A41FAED9A407452
-:10CFA000BD4AD0EFB04C6735F607702C65298C85EB
-:10CFB00064741A711E6CDDF01F44275F74EC3CA48E
-:10CFC000C03835C11DF594AAEE09D8CF39C51BA6C6
-:10CFD000A4101C9DB8FFCE5BBD61880FA70EF28028
-:10CFE0009F9ADDDA75E19F1EE65583FF8076351E38
-:10CFF000D561C6FDC3DC469C7F0D33FAEA27F17D7F
-:10D00000887400FD3C49FBD5F297D25F001EAAF759
-:10D010008CCDBA1BF0531371F85753A91EB493FB70
-:10D02000451D9897EB19381FBEBEF3621F9C872FD2
-:10D0300006A49FBD419CFE19A78F8B7BE204FD7067
-:10D04000BABDB8678C1BE7132DF6CD45C5A50BC639
-:10D0500076BF64F69D302F66F74C9C371E67EF99BC
-:10D06000383F94B10715CE9F6A86792622BF92FC7D
-:10D070008B993C13E641394BF74C980FF55F12F54D
-:10D0800058B1278DBEBB3D69D8FE908E55213CE539
-:10D090007CAA9F8EDF4EF030F1FD5AFDF438828F6E
-:10D0A0001CA719F94838A6409F6103D7FD5BBBC296
-:10D0B000F77FE8C418E46B43E13F3D765806B2922F
-:10D0C0008B4B8CB73AA0DF31ED464D3FB2DE58B7FF
-:10D0D000F6FB61D1FFA8007C8E507B8F06C17CD906
-:10D0E000AF014E6CE078FF89ED804E9F7AAA1F7FDA
-:10D0F0002AC72763364937368213C7D39F8D124F0D
-:10D100006BE3815FD7204C927DF03A94E98C8F8459
-:10D11000F422E661FE8722200F69BD80BFCC4BB8A8
-:10D1200007D2DF9D7FAE8CEF82F6E7ED3A9A57206B
-:10D130005CD703FCB0BCD9C06E2D86F65F349D4829
-:10D140003963F0ADE76C93C301474D7FBEB23DD369
-:10D1500084FB6EC5B64CD3323FB837EFCE3E610389
-:10D16000BC9EDFADC79158B3DEFDAB2951F85DF52C
-:10D17000B818959B1C380FCBB13F60BDCA6D1159D3
-:10D18000AACDD77E457B91A3C20FFEE3766BF1312A
-:10D19000DEA3CD5F7D589BFF1AB95AEE3FDF2ED339
-:10D1A000ABCD679FD0E63FFDD3DA45B80D9ECFE308
-:10D1B000FBE63377A8DB0470ADFA68F6093C473F1D
-:10D1C0003BF47C18E2ABE6AF15AFC5335C87964EF7
-:10D1D000018F8A1ED6EBDAA510BDAC7407EE5FC1D5
-:10D1E0003706ECEBF5B41EDC59FE741388DF73CC04
-:10D1F000B3C801F455DBF86ECA996C98D75C20640B
-:10D2000098CF64CF5623B30C1C6F28FEC12C0E1B85
-:10D2100003FA2BCBE365531A67B1D3D01FDBF2C7F8
-:10D22000D9B85FCBEE5148DE287B6ECC2B4837DD7A
-:10D23000FB975C4BE9A239048772E630223F5CD150
-:10D24000A17843216FCDB31DEE8276CBDD8A1DE739
-:10D25000BDAC25C8C7CFE0FF155B02E6D1E6570E8F
-:10D26000F35F71F8E8370AF45FB54DDB6E25C00B4C
-:10D27000CF8FEA1DFF08F2FF0E8210C16B4AC776FE
-:10D2800015D7BD5CCC5F9E7FCC55C0707D537813A5
-:10D290007606FF03E746F028676E66AEEF1C9CD269
-:10D2A000C6DB03E32BC375D7598C365C779D897930
-:10D2B00043603E27428D0E2B7CBFDC1E4AF2436545
-:10D2C000107399B22865E62C6C670FC77667DF5636
-:10D2D000494EAA03DE43FD3CA1B89BB11F55E1F9BD
-:10D2E0005FF3FC4AE6A5F520DD38FCD7E9D6E65920
-:10D2F000EB30924B6AF5DEA308976AD645F066805C
-:10D300004F878423C0AD16D6F94124CA5FDAF6AB45
-:10D310009887EAAF3AFC8F20FFEF20673213D4DF03
-:10D32000160C29CDDF4D70548DCCA18379AA7704DA
-:10D33000BB5D24871407239D1AF0BC00B8B6DDE559
-:10D3400048C3796F501C6956E4635BCD76E4634B48
-:10D35000B7F373A82D02E45768DFB6F22A6ABF1448
-:10D36000E529945396707ED716E1F122DF6F7B207A
-:10D3700089CB537F57092EBDF79ADD4F42FDB64C3E
-:10D380002EF7B46D1D43ED915F923C756F286F3F92
-:10D390008FC3B56DB8D5ED82FC873845804FDB76FD
-:10D3A000479A89DA819C96E43BA7A43CFD9B51CE29
-:10D3B000DB10DF72BD52FE66553F4CDEDC29CECF5E
-:10D3C000DEAD304FE8FF8C52FC9ACE4F1E6EC9E4A2
-:10D3D000FC7FE24CC72E51CF8EF52A74F3EE9E0EE1
-:10D3E000F3AD7850676B4EF2C19D391C6908E73385
-:10D3F0005BCD5948671367021F06FA3B99C9F97953
-:10D40000480E73B821BD57F47B6FA64E93C6060332
-:10D41000FD413F678ABC06C46F684EB111CF4338E7
-:10D42000C3899F07AEE361D14F85B1F8F56983CC1D
-:10D43000A79F0E0AB9DC7266B5F2249F17C7F3C422
-:10D44000FF30DB9B69DD7C7E12EE4037B974DE0B6A
-:10D45000BE15D14F27EE3D6640ED56294F23FE15F0
-:10D460000D9D103CDBEE1D4F785C2AF0CCEE350BA9
-:10D470003A61EC6F585E64A372A013824F5B26E0A2
-:10D48000CDE23BF7DAE639E222FCCE23A0032A07FD
-:10D490007CEFCF1C3EF0BE25F1CDF4EEDCE2D0A156
-:10D4A000F1BD2C2F62A202A08ED7335710C005CF3A
-:10D4B0003C82CB5D7AF79D309F917A0EFF043DA7A9
-:10D4C0002FE0CEAEE02CAAEF3042BEECFE15CC0130
-:10D4D000F5CBE2995DE1F55938D6876E5448F1CC29
-:10D4E000C07665E1BCDFB218E6BE53C8FDC8AF52D6
-:10D4F000314DA67E1DBA48DE3E2C8BDABB74BCBD16
-:10D50000430FE9A814BE5F7A3704D1FE29DB94905B
-:10D5100086743077A6960E52B338DDC8B435CB2664
-:10D52000CE197B2CEEEF652D63E9DC683617D71D2D
-:10D53000447CED0B2179B06CE32DD7E7E2FC9E191A
-:10D5400086120EFBE286FD1391DE96B52CF9D97B8F
-:10D55000781FD96DA6EFFBB29C1FE3FEFA42B1958E
-:10D560001E840FCB161E37C6427BA767DE851721A8
-:10D57000BDC1B5FF0F2817DC70A34AF56F609EAFE1
-:10D580003F44BED0C2C7B9DE75491F0BFD5D9FAFDA
-:10D59000302CEF365B1357C3FCCB04FECE09FA6D7B
-:10D5A00036B3C5CF5A705E0969C9F0FD7A94540745
-:10D5B0009103C76609397186B20DE59E51B3F8FE35
-:10D5C00092F5B11FECF76A8407D4FB5AEC2B99074C
-:10D5D000B852FD8ACD41DD2961981ABC63205D9463
-:10D5E00033F36FB8CEB9C96C36DE9B7A7FAEB22703
-:10D5F00069BEBD65B4EF43D36CB8EF9D8C7989EFFC
-:10D60000B9C712DD77CFE8EDDE04F9EEED63ECCDBE
-:10D61000C4D7F9FD7DB995D1F9DE3D83F335C95FF6
-:10D620004E5ABB42895EC57DBE5C90C6278DB31E37
-:10D630009C04F5CB2DC66E3C0F963FB020CC06F374
-:10D640002C6F83FB3C9C636C8BF63E0FF7EDA8AC14
-:10D65000DC81F7F2C0FB37D20CD251C51685E870D9
-:10D6600054B3DD18477C4CB1E2FA2A2CDE543CFF5F
-:10D670002AEC663B969F6F72DC7F06E4C38B4D738A
-:10D680002865DF02DC619E5721F260DFA7673B93CC
-:10D69000B2008E65AD65749F0CC970127F720ABAB4
-:10D6A0009B0B605690DFE8BBE2701FBE9329BE471C
-:10D6B0005AD32C44CF668670E83658D3705EDD1B93
-:10D6C000CC3A3C37E7DEC9E91AF699490FEDEFD2BB
-:10D6D000B360DCEF3DD81EC62B59AF2FDE0EF9919B
-:10D6E00026A60F8D44BACA24BA6ECF717E8DFCE097
-:10D6F000B35FB23C940BCAB76CA5F948BA60FACED6
-:10D70000C26128E7ED4CCAC2FBB5A4A3F69C997987
-:10D7100008BF7E7AB851213A80F4680AD1C3FC6907
-:10D72000583E77A637750DCCAB48AD650ED433C4E3
-:10D73000327B10CCBF8FF5923CD107F2049E6792EA
-:10D740009F48BE0174E03045FBF0BBAB09A6023C2C
-:10D7500079779389D2A79AAC4C0FF0DDDB144BF9A3
-:10D76000679A6C947A9AD2E9FBB34D76CA1F68CA5D
-:10D77000A3FCA12607E50F37CDA1F4C5A662FA2EBA
-:10D78000F912C085F890E42B921F497A927C299077
-:10D790008E4A01BC0559D49EF89EE477B80E5D967A
-:10D7A0008F1F49FC262BC5AED824E4635D4B905FE8
-:10D7B00014A9E7F73D0FF0EDABB2D8836C0817CE94
-:10D7C000F7FA2C263AE7138DEC30DEFF9B573BBA75
-:10D7D00037F99DAB3757294CEF47B7B7349899DEE7
-:10D7E0008F6E6F6D8CD0E44B1ADF7D3506FAFF47E4
-:10D7F000827335D2DFC93BCE3EF65FF0FD893BBE7A
-:10D80000188DF88679EC7C08C75D17DC3F8F48CC13
-:10D81000B718E89C1915CCEF49A382F93D09FF1010
-:10D820003FCB18DFA74FDCF137DAE7DD8D41361546
-:10D83000E50FC417C0F72F025FCB1A83088E651B54
-:10D840004EEF7B1EF7FB3A23F1BB652D627F6E0620
-:10D85000B8FAC96DA7E218C9678A83B14680DFA903
-:10D860005F1ABD70F6B3538AC9AD4043052E4D25EE
-:10D8700008D7CDBFFB00E56DA5F104C9C74E93C520
-:10D88000ABE2FC5C86F3FEFD298DAF513DD635320F
-:10D89000E26C086D4586700CC97118914F206D239C
-:10D8A000FE96A51F63B8BF59AB621D0DEBAA10DF32
-:10D8B0002B362B247748F83F92A5D2BE7A2F534FB0
-:10D8C0006936EED9E1C4C0E89C92740B7CC3E1C612
-:10D8D000FDD19A69ACF4E3C7CBC4F7F2741DA5F28D
-:10D8E000FB7BB02D914EB2114990DE9D9E6C5C4E3B
-:10D8F000FCCE66447E20EB2F4BCFDA989C83FDCC88
-:10D9000088627EFB7257969EDABD9769E5F331C156
-:10D910003906ED6A87380FA47CF219FE7332CD9F69
-:10D92000EE5FD5CF3CFDCC8BA897F82888F0547DCE
-:10D93000B5D06F64B8272E20B9C66151609DF5023D
-:10D94000FF854FFF35AC0BCA571DE0FA5348BB317A
-:10D95000AD5F5745FAB27AB88F1644227F359CEAFC
-:10D96000F2A3CB579EF928AC8BEE17AE785D2CA6B0
-:10D97000DE780669FD81D3B319F6C77A375A2D03CD
-:10D98000DBAD52BEA57BA65C47D191AFA2697CE519
-:10D990004A34D53FB2217A303DC82AA63FD5BF7F51
-:10D9A00049CFE0D0E8D556B12D975498EFAA7573BA
-:10D9B0003E453A0FACFF41566814D20F9BC42691E6
-:10D9C0001E43CF7488EF35260E873EF7E870F61DAC
-:10D9D000FA9755EDD00844AD3EBD2DDC0EF3ED6158
-:10D9E0006CCE607849C8E6E7F405D8470CEE523DA6
-:10D9F0007B55BA2FF4EC0D25FAAFDF7BFF6B53217B
-:10DA00005FBF43C161591DEB2438D51F5099C9FF31
-:10DA10003C43FDCEB0A1E759F3746803D2D34A8FDB
-:10DA2000E2D809F3E933D9C287FBCDE76F829E6A5A
-:10DA3000823C1309AE62FEBD829FC97A2B3BEE3752
-:10DA400022BEA0DE45925F7E1BC2486FC67AFF8071
-:10DA5000F33CB72DDB8EFABD959EFDF574FEEF0D00
-:10DA6000B18E86757C21F4FCB21F6336DF4FC66C25
-:10DA70002E6F9C13FADC73CFA8C487709EB80FBFBB
-:10DA80004039D76F9E16D1CE22E0F61CEEC75C5F00
-:10DA9000FD959EEEB054A8FFE9E177298DCEE6EB27
-:10DAA0005A69E99C80E7E6A70742E6B8297D74F643
-:10DAB0004B30DE05CF8C28C56F5FA5641B383EB6A2
-:10DAC000A973105ECC3D4CC8F91E5ACFB9BDF10AFE
-:10DAD000DD6F11DE20E79F3BF05C988EF6AD4B8347
-:10DAE000479D89EB6983226C42CE34B5A2BCB11448
-:10DAF000A4BB70E07775072ED1F91BF85DD6A7FDA2
-:10DB00001687F7EF5ED26BC09F0EE9B7CECA715E83
-:10DB1000A466C4E03E28BDDA76D3CDC8C7DE307037
-:10DB20003C8CB43D84F7AAD2B78791DE628DC116D2
-:10DB300083F92FDF848B20CCBB345BECEFD8AE5C59
-:10DB4000D4737627F173BD76335C54603D2300EFC8
-:10DB50002E5872AD5B654EC8ABE23E734D7632AD6A
-:10DB6000EF912A9DC34876166F1AEA3D4F1A994BDA
-:10DB70004579F95933B7072473BDFE2348EF90D692
-:10DB8000467AD386A1FE4BE0B1763E94FBE1B3F634
-:10DB9000496F1ACA2FE78D5CCF87E5564CB378BD25
-:10DBA000664137D80FF6DB9D64BD4872E6C15086EA
-:10DBB000F2BEEEF950AE57F88DF9C920BF737389E4
-:10DBC000A02B90995CB87ED74E3E3F9C17CACF2BB6
-:10DBD0008DAD69285FCA715786B5D278E7C5782BB5
-:10DBE000835BB97DC2C8F591589FC63730B2A3F4A4
-:10DBF000EE092239F58BB8CE4338FE177BC6323C8E
-:10DC0000C7BB93DC9587A91CE437C047F553415E39
-:10DC10009CEFE77B42DD0CEA7F6EE0F2D0E7A1D11A
-:10DC2000240F9D087DB094EC323B8214D4AB7CAEC3
-:10DC300030632C96EFE4768CEAA646B23F54C37666
-:10DC4000675994CE6191583E96F42D9FFF1EF6A918
-:10DC500042DF37E377276B2DBD1DF7DDEE10D2BB1A
-:10DC60007DF1D4FF1A3B98DDA27A8756BF24E940A4
-:10DC700096DF9ECDEF1BB767F37BC11DD9FC9CA936
-:10DC80000BF13C984CEBE4FB15F040F72ED81FD17C
-:10DC9000A8EF3EE979215AB1209CBD698F22DC773B
-:10DCA000F3FBCD177B0D6477A97E3ED4417A9C4D62
-:10DCB0009374785E54AB5C0EAED601F82055EED866
-:10DCC0009D867276F31E7316C203E04DF7C8DE9D83
-:10DCD000AA18878FFBF9AE04AED7F78AFCA1F1A48E
-:10DCE000D79F1BC96E9D4F72CEB60908D7CB3B425A
-:10DCF000744817308E4301F854DFFE0B0ECFF04A04
-:10DD000092CB61FF11BFAC15FCB26ED3D4F0A9B8B1
-:10DD10009FDE5619CA0597F5F618E48781F07A4B0D
-:10DD2000F0959A438F19D16E570BFBC609FBA64697
-:10DD3000D8C76A9E5248AEABD938F521E2837F300E
-:10DD4000B0D1308FF39EFBC3FCF1F1BCE067BEF6AF
-:10DD500076AA5F03F579FB37C2683EBB0C769C4F11
-:10DD6000201E7F70FBA7D41FD4BE9F3E3C70AE4FD9
-:10DD700018B8EECBACF3DF3E427EB2D74CFA2BC0E4
-:10DD80007B22CA1DE70C9E4A5CF7B97D66E233E749
-:10DD900022F87EFF14F8A16B0CCEE3BAFB48BFF16A
-:10DDA000CE0286E7C10AB7B65F396E87E0BF75C39A
-:10DDB000ECE1A827AB033C607F80979F52FBB70D37
-:10DDC000D43E701D8F8A76FDFB735F08D1CBB911ED
-:10DDD0001C1FE79E1943E74A7704A773986F22DE5A
-:10DDE00057CE45F094A1300274502DEEA3E766782B
-:10DDF000E8FE7D4ED94F69B781B7AB6E147663A04C
-:10DE0000BB58A41BA449B48799B674A23C81FAEA12
-:10DE10008959947A832207EA9D913EF11C8ACAE1CE
-:10DE2000FB8BE178D1C2FE41728AC7887CD929E494
-:10DE3000B8DABD03ED7088DFDABD0AD9912E8B7395
-:10DE400010671D25F5E5408F352EC561C6F9B4ACC8
-:10DE50005E4976A486AD3723BDCB75D4E8D91CBC0A
-:10DE60000F752B2ACDA7DB0CFB06E1E03F9E9FDC64
-:10DE7000F577C10FF0CF1A4D722609D7BA1C1BA730
-:10DE80001FC8B6427FB52DCA161A2749DE2BF9FAEC
-:10DE9000249C002C46D497C17D9F970FB17E39CF2B
-:10DEA000C0F5CBF944E770FEDE9D64BB2F1FF1FD8A
-:10DEB000966AC77BFAE56FB3C323BF432EC39B5B50
-:10DEC000BFDE18E69F823405EB3A8BFC0DF733EA90
-:10DED000A5619E69DBB4F690F41DDAFC557BB5F9BB
-:10DEE0008C03DAFC840E6DDEFE8A361F22C6957026
-:10DEF000C27BAF6D0CBFF7628AF75E5B10BFF76243
-:10DF00001EEFBD98E2BD17BFE3BD17F378EFC53C28
-:10DF1000DE7B318FF75E4CF1DE8BDF6F1470AA155C
-:10DF20007A47C403DA65D80B666967A7FDD2B324C4
-:10DF30009AF8A7B493F6ACCCA07CBF5E679E89F438
-:10DF40003AA4BB01B964C1486741CE70B49F766EF4
-:10DF50008C43BCE9BB489FBBEA45AECFADCD325B3D
-:10DF600050CFD0B5E1D38D283EA58D74CECA81F5B2
-:10DF7000F6187A77111DE8BDC437BAD6DBDE9ECE1F
-:10DF8000F147FA0E6689A4FB49199E779143E33164
-:10DF9000D0AEC2B668ED28817695407B4A201D48F8
-:10DFA0003BCA1386DE38E4F7A7F798B6E0FC4F0BC0
-:10DFB0003D195B6C22F94BCAD545AA85E0B4E65EF3
-:10DFC000E5493CA72A7222A97DDF0990B707396F7E
-:10DFD000655A7E259BE4EAFEFC164547761AA78320
-:10DFE000CEA1DBC49C1295DEEE4D4823A13A3AC780
-:10DFF0002F5B74742FB8FC2795E48831ED3ACD7A05
-:10E00000C6BA8335F4356E7764803D7084A6FED53C
-:10E01000879303EC815769ED5437AE3F8AF7EB05E0
-:10E020005BB235F52A8AA706C051CC5BC8A5CDEBFB
-:10E03000DA1391FFDC16DA47F3BFEDA099FC2E2A24
-:10E04000E07C71C0BAAB3003FCB1CAE4B801E1575F
-:10E05000E53144A05EAB5C9C3FAC517B1E57E99917
-:10E06000CB1AE9A3BB2A2B734440FB0B99ADBB74BD
-:10E0700080B70BBA6D0FE6DBD0BEB43DD10A74B5E4
-:10E0800056F1444F86FE4E4738FF03E933D1E0FD99
-:10E090005509F2CBFD296C3DD43BBDE5B93092BBAF
-:10E0A000059D251AACC188EFEDAD2ADD0B503F85EB
-:10E0B000FA20490FDB5B8705A75A7CEBF4E1FF5B95
-:10E0C0005A1FE085FC46FA2CC746DE86729C87AF55
-:10E0D000B76A86E2223959AC678D3857580BEF671B
-:10E0E000ADC89F11F705B9BEF3638F4EB0A15DB304
-:10E0F000E970A28A7C5CB777571CCA1731CE7DB80D
-:10E100007FAAB68FFEAF7C18B7FA3D95A11DF99393
-:10E11000B659619351FEDC67B0CF85FCA6D65F1B74
-:10E12000F15E50AD771BF1DE59B567BB11EDFF3FD6
-:10E13000D9BD9DBE57EE2EA3FBF60AD640F7C8CF39
-:10E140000CFC9C96F0A89AA96CB3C2BC87E772B984
-:10E15000AF2A98FB8314A9F9AF46E17A772B99B8D7
-:10E16000DE1B8BF71BCBE0FBEF047F09DC1F7D6F11
-:10E170002E281A8E7A250FB7830EB51F167AC7D2AE
-:10E180007E58702589D21BAF8CA37BD57BAC783CA5
-:10E19000F1898C80FBEC9B2AD79B75F07D5065F450
-:10E1A000462DC07DF2B281F6491DF0AFBC2CBC27D4
-:10E1B000333605D2E27C5543AFAB0A4334F4BC9806
-:10E1C000456AECCA8BD8084DFEC6B9299AFA37DDE4
-:10E1D000382E80FEB37CE5C447A668FC57EAD6B962
-:10E1E0006C0AE9D1666ABF43BA8EE8EC5A4DFB3A35
-:10E1F00036DF570FEFC13BFE487066ACD388F7ADF2
-:10E200002A1DF7D759ECEC16DFBBE83B2C44B30FC3
-:10E2100047A5D8FF8B9F8B06D2CF4BFDF462FC77CE
-:10E22000CA60E722205A8C1BAE72FD82532B777492
-:10E23000D2FD93713CD4097D4F5D3AD7F7D4B93AFA
-:10E240008D0D1682BF3E1E4052DFAA903E0FEA9B04
-:10E25000E223797E1D7E3F60F0E95918EFEF0A96C0
-:10E260009F50CB70BF0496D7C3BA51CEA8477D0D3F
-:10E27000E999E67C4A7A26398EE85FD2E98A76AD5A
-:10E28000FEA81EF53A7EF85C9A6B237AADDEBDFFE0
-:10E29000B511009F05C51199B88F6A3DF30C65193A
-:10E2A00003E94DF2F9CB553AB27BF7BD799CE8AD65
-:10E2B000AF4A4F74FD7D70A97770BD66201D56C2B0
-:10E2C000BA4C307EE501C5EE56783D84CF08A4CF28
-:10E2D00000F8C40F023709AF7EF80594AFC07FE4A1
-:10E2E000A03F81E2F6260D06970078CA7102E0C5CC
-:10E2F000F2B4F0A874DADE46FE53794265EE1FB040
-:10E30000FE15B84E9C07AC13E731FF0AD79B487B3C
-:10E31000C2A22B7ACAF7D34D31C02B0BF79D769F43
-:10E32000F6D35131DF370BAF4453BB1F8B9EBE8FEB
-:10E330008EE4FC25DFF6EDA33B896F3A7343A3CE51
-:10E3400002AB807FE7125F10FC7568B9D4C5F9A8ED
-:10E35000537BCE8CBA238FFC8EFA2CC92457F49FA2
-:10E3600043566DF99AD0E4182C770ABD9DE4C74E48
-:10E37000514F8E5306E5B66148D723A3511FBBB159
-:10E380002525B1CB4F5E716E3044A3BE3071FD3098
-:10E390004ACBCCD6683C47CAD6ABC5783E9EBA2B92
-:10E3A000263A0FF5F31B0C5173A1EB533FCF496491
-:10E3B000E3315F44E9E9AD418BFDF5DC32BD4B9CB7
-:10E3C0002775777C40E7DA05DD9B618B71DF6D385F
-:10E3D0001886AE37351BDE9D6805916453847373D0
-:10E3E0002ED951B7EFB222DCACDB27A09EBA1DEFCD
-:10E3F0001EC37DF243F586A218D48BD5FEFDF8E34B
-:10E4000078EE3BD71BA251FEFCFC4F702E2A74AE57
-:10E4100091DCF09999D17DE9B39D216EB4DF7FA69F
-:10E420003007DA7756AA47275835E76CC7229CC7CA
-:10E43000EE18673B1FDFBD2B16C7B7BBC83FD3B96C
-:10E440007E74F8607A1499AE6AE772DD2EA9C7155A
-:10E45000FA5E94E7318FF23C1BC3E579CCA33C8F85
-:10E4600029CAF3F8FD90D0E38F6AEECDC4FBA86B08
-:10E47000264B6FA073D7928EF2FA6D4AB01DF9CF7A
-:10E480006D8A3D06F563EC4F11FCBC0DC0AF4CA787
-:10E49000F582CCE547F7D3AF9898BF9FD90C16A16A
-:10E4A000C9CF32C569EA17599334E53F891DAB29B5
-:10E4B000BFC696A9C95F973E5953FF7AFB0C4DFE24
-:10E4C000A779D768EACF73CCD3E417CC59A2A9BFF8
-:10E4D000B0B84C537ED3E2959AF225CED59AFCCDB6
-:10E4E000553FD7D4BFA561BDA6DCC1AC7A3CF73A95
-:10E4F000F09E05707F19EF5990DEF6D6688B3F5E6F
-:10E50000F367E91A06D3D37F2CE8376392E343A479
-:10E510008F041DA743481D28425C10E74A3CF32A9C
-:10E52000FC9EDB19877413582FB03C3FE4D8651B61
-:10E53000E0F0A6892137EB813FE44F3A969D02F93E
-:10E54000270ECDE3F9A9C79E4B86FC6F26DEC7F3E5
-:10E55000571FBB8CE5A39E5F74B31EF84EFE0246A8
-:10E5600022C77387BE5EEA8275E44F4FDE62E77AA8
-:10E570009241FD34FBF52C0007F46F443860EA0546
-:10E58000FAC4F418D027A6AF007D5618187B0DE802
-:10E5900013D31370DFC4EFAFC37D13D337E1BE894C
-:10E5A000E91FE0BE896927DC37317DA76931A57F86
-:10E5B0006A7252BBF79BAA28FDA0A981BE7FD8D45E
-:10E5C00048E95F9A5CF4DD3C51EA2FBCA47F917668
-:10E5D000A67AB4EFA17EEEB0E1BCBF1D56DA09A564
-:10E5E0005DB0B9817585E03EEDD2479C35F9EC7D93
-:10E5F00043F3593D3BEB27876D8D75444D24BDC6D4
-:10E60000482BD97BC4F799CA820434FDCD9DE01C08
-:10E6100081E50BB3CA378403FF98FE6D8301E9E5FA
-:10E620003DE1A71AD8FF855C2E0F1B2639464D8485
-:10E63000B4C0C4FDF00A4CDCCFAE40DFD58CFCA8E2
-:10E64000F92B66433F9AA3A146E24FCD77E9DDA8B7
-:10E65000A754BE64949F16C528DFFC5527F9E5151D
-:10E6600058EDB174DE887CBFFD1CFFFCFC65A43D49
-:10E670005BFAC9147ED9350BE5806916A32D28C035
-:10E68000FE8E76EBA3A1EFCBF9301C4FDAC9777C75
-:10E69000C5BCBA093E7B7881A93309F504D3D69A63
-:10E6A000ECFEFE3FD2EEAD7CD9A9E27922FD7CE4FE
-:10E6B0003872BEA17AE82FCBE7C75360F564A25F3A
-:10E6C00043739D85FA8B81EFC62CAAE750A99D273D
-:10E6D00013F5C0D36A2D76D46F4B7B7B8C5837D41F
-:10E6E000A375167EE9247F8369C2DF00FB31F172D6
-:10E6F00017F6332DCA1BA7C7F53718EDA80F7D4CA9
-:10E7000081F6593EFB3FD60FF1DBBF384FEC37F5B2
-:10E710006B982FCAED0E07C17781BCBFD9445E9CB0
-:10E72000CFCC3493F457AAC81F9BE07422DE8B83AE
-:10E73000AC7F0DA17D9E92807A8E79426EFF0E7A1B
-:10E74000598E74F6DFA71707C7F74846FAB440BAE0
-:10E75000917891781E8A8E24DEFDFCB508CFFDFEEF
-:10E7600057A29F40FA1A8AAE243D159838DE11AFA1
-:10E77000E84723E948F9D2B39DD6516BA2734ED234
-:10E7800051201D0CA4234E97CD3F33517F03E9C880
-:10E79000877F84C7BF4E479D2A9EBBFF2CFDDCDAD6
-:10E7A000CB668743D12FAE765EC8457FA02BB6D708
-:10E7B000305FCE66CC469292E52D439407D297AC5B
-:10E7C000FF34D6CF1D58DFF965AF21DC8F2EA78926
-:10E7D00033F0F521FA7F43F8C5BF6196FE1E0E4B5C
-:10E7E00026D0C12CC1876F2BE2F4352749257BC683
-:10E7F000AC8C1524DF330B978F6DF03FD2B709FB3C
-:10E80000FAB5A2DDEC6F8B5B709CD9515AF9FB5ABB
-:10E810002177CF09B0B75F9BF11392C3AF0D90B3CF
-:10E820007F3F51C8D1492C89DFAFB790FC5B28F6F8
-:10E8300063BCC0778A4D65F900F722E6D4E321F086
-:10E84000CA45A303FBFB097351FE1AE6A6F43AE698
-:10E850002539E07A383030FF53D87A983F1E72431A
-:10E86000C92AE86F56F6AC54FC5E6BEA4D34EAD028
-:10E870003BD0F921EEE77AD5F931CA9917129C639A
-:10E88000F07E7CACD04672D831530AC985B89F0C53
-:10E890007EFACADFC3399A0AE7DC713867317D1521
-:10E8A000CED95438EF7E07E72CE6AF4D5FCFB0DD11
-:10E8B0006C9BD6BF47B6BFCE3A8BE9870D7D8E5D88
-:10E8C00037E18591A8C77A23624C21E2ED8D884912
-:10E8D00085B8DE372262743C0D32523AFEF9D4C15B
-:10E8E000E45649AFBEF166D37881F095F00C84A36D
-:10E8F00084EFBF004FFDA4DC81F0BC806730EA4F9D
-:10E900004DEF86C526A39D51C4D385703E58F7FCB4
-:10E91000F8185C47AD89C3655AE3544A0B1A27338C
-:10E920007D36D9995C08DFCF7109A8700ED0B3315C
-:10E93000FD4CCAFF4CD0567A8C331AE7713ECB9B04
-:10E94000061219FB745B7318FA675E7846B5E3BD6F
-:10E95000A656B56DB1A39EFC0D95C7057D7B3C11F8
-:10E96000ED9B6CC7E0FED2B526093F17C1B5ED6A35
-:10E9700007ED3786D6D9689F5C333288FB199379C7
-:10E98000216B6839676230E7332383387F94F882DC
-:10E9900076FCDC857E26025F8BBF2F98EE3579A34F
-:10E9A0001CE3713DAC9069EE05527FD117A5D2F9F9
-:10E9B00050C0D21EC2FB7BE10903DDDFFB0A192F29
-:10E9C0008FE5F6CABE139755DCEF45A10A1B96E406
-:10E9D0008B9B098AD5319B9F3C6DB605339B1FDD10
-:10E9E00086A4476AF2A1F6119AFAE179C99AF20867
-:10E9F000C7559AF26173B234F9E1C55334F5631621
-:10EA0000CFD4E4E39CD76AEAC757CDD7E4253F8A41
-:10EA1000E79F5842C3524DFB518DCB34F5935CD5E3
-:10EA20009A723538EC498A3B75393AD3A3915FF134
-:10EA3000BF94CD6B34F51E0DE37120732C9573716B
-:10EA40001F8E6EBD5D3B2FF54D85E23A6D9C0FBA72
-:10EA5000E07F88DFA2582D5F9C65D5EA1BE21BF49E
-:10EA60009A7CF524E18F34814D203EF87D78765EE6
-:10EA7000A5C173203C00EF762FD68773D505F9A288
-:10EA8000DF97EBF1DC47BB82FFFCD1AEE0BF5EB4A9
-:10EA90002BF8E7D1AEE05F1FED0AFEE56857F02FD7
-:10EAA000CF3EA1C5736EA716CF933ED0E259D2DFF9
-:10EAB00050F898DCA5A583407C4CFD2C802E041ECC
-:10EAC00016C3FF06C3035D1180FE673530D29B7D00
-:10EAD0001F5E1E9B24CE278117C003C5F5F58D0C44
-:10EAE000253C3C26E65FE01D4771B145A8374BF257
-:10EAF000ADE73171EEFE769873F724D8DFBFB365CA
-:10EB0000C5223F9ACEB85D7376ADCEEE85EE9F0AF4
-:10EB1000C0FF84B1CE7D587FF1B0CB8946A4875E1B
-:10EB2000E718BC4F7E28F424817E9C2E1007280E07
-:10EB3000E17695E26F4EEA5A15E4CBDE04E721E474
-:10EB40001BB76634109DC6B2E2FD9530BFD2FF0CF4
-:10EB5000223B4EE9281EAFCB32BA28CE41F2BBD2BF
-:10EB600078EE47F4F2246117B6737FA2A393B83C02
-:10EB70001B6AB792DF7159068FE3806B5762E978A1
-:10EB800084CF9BE631089F366E37E9C278E1285F73
-:10EB9000BC30CA9B28DF2508F9AAF9CF2613AE633B
-:10EBA0004C3BD39C9363DD268DDFEBB8DD564D7E69
-:10EBB000BC275653FFEAC3364D79A6375D539E7D79
-:10EBC000C2AEC9E776E669EA4FFAC0A1C94FEE9A2C
-:10EBD000A3A93FF5B3624D3E9EF53E8CF01DA5F016
-:10EBE000FBFE3793B8FF14EC55B2E3956E8AE071E3
-:10EBF000A0420F20E569E90FED14F41D28A78F321C
-:10EC00007239B5398EF17B9849DCB798565E770A30
-:10EC10007F6629A73297D69F59FA31F7CBF5426E16
-:10EC200097F2B19F1FB3C3DF8FB954C46F079E7FA4
-:10EC3000863CAE1F099CFF28235F6FF3CF8D1437EE
-:10EC400022E715381F6716A7DB9DA6C1E37786E587
-:10EC5000713DC1F8CCE2903C481F37D8DDA447197C
-:10EC6000309EBDCB85F7CA5F1AED77DABE7FBCD286
-:10EC7000ABF97A4A74BA5BE76590BFD8E267FDC624
-:10EC80004F11E3064D51065D5F6938F7E762E146D3
-:10EC90001BD2EFD0E37178C61A590BC51909BFFF13
-:10ECA0005BB678EE1D034525C65603292F98DB80F9
-:10ECB000F4307726C853998C1DDAFFEC2316906741
-:10ECC0001E6FD4939EE7AAC33125AE545F1CC7289C
-:10ECD000B86F207DA0CC82F7944727737FE5EBF2D5
-:10ECE000F8FA8AD46FFBFDEFC97EC198382718F96E
-:10ECF000C30C426F4487721D3F963FBEA4DB403871
-:10ED0000C9FB2513FE8EA9625E127E723F48F8C9C8
-:10ED10007808DB6A43F193168AAB98837E64127F8E
-:10ED2000BF9DCCF9D12F053CB01EF2A3A1EA15A9D5
-:10ED300019E1A80FEF63B670EB77E87B7FC4380565
-:10ED400082FF50F15543F187017C618878ABA1E8DF
-:10ED500093FEFE89B82B3FFEC0FD7A043EDCA93A43
-:10ED6000B2A36F0AD5EEE3A7047F9827F6139CE3BE
-:10ED7000964C2D9F60A8BF6FDEA00A3EC1CF6F9456
-:10ED80006BF0FBF20D063A4F192B7E10E3883E69BB
-:10ED900033907F6B81C336DBCEEDF324DF90DD0B48
-:10EDA000A656E6D29EDB20473C89F789E9CCBE1106
-:10EDB000ED19E59BB5E52B2CB33F47B96179C0BD93
-:10EDC0007485B8AFAE08B8976ECB13E7B19DD9493B
-:10EDD0001E1376FE2A51A79F8EDC29E142EF42FBEB
-:10EDE0001352F20B9370B1A1BD26DB9707F805A76C
-:10EDF000E339DDA21FD45FAF1F7E43F8239C477F1A
-:10EE0000041BEEF73E8AB7EA3B60E6764A690F12CA
-:10EE1000F5CFBB2E5339D6C7DE2E64764E4079A788
-:10EE2000DF7E146087EAB3E8C2F2B0BFBD06EA4FE6
-:10EE3000FA5B54FFCD3DC1EA674F7676A91AFF967B
-:10EE4000C0D4B9FE20F95F6C8A70BE8A7CFC9CDE5F
-:10EE50006E42FCDD6539168D71F27385DE2670BE5B
-:10EE6000FDF26DBEC2EDB02E1E37DB3747213F00ED
-:10EE7000E0830CF78DF41B98C7BC51984A7B8C73C8
-:10EE8000F36482B3B4C7947927D33C1736AF300408
-:10EE90004395AE87D71505DB7C769AAE04EEF73343
-:10EEA00094BD66C1954CEAEFC62B53A99F337949AF
-:10EEB0005CEE6AB97735D2D155BB9901D7D915E047
-:10EEC000F72ED31B27F3FDB01A633172FDFC89D6F0
-:10EED0002B44E76B1426FD8B884FCBFCE556912F16
-:10EEE000E2F9DB36F07C9781BF33B34BE81B709DB2
-:10EEF00098E27AF05EBC57E823701D98E23AF03B46
-:10EF0000F225CC235FC23CF225CC235FC214F91258
-:10EF10007E5FC68A1333556E572AF4DB3768572A4B
-:10EF2000F4937BD0AEE49F47BB927F7DB42BF997DF
-:10EF3000A35DC9BF1CED4AFE79B42BF9D747BB923C
-:10EF40007F9EE55DE3CB231F73CCD3E417809C5FEA
-:10EF5000E8B76FD1AEE4DF3FDA9534FD39576BDAAD
-:10EF6000DFCC1A35EDD1AEE45FFFD646456377BA04
-:10EF700055BC0750DE3E8CE863EF84E2A4C980DF15
-:10EF80008F43FEFE3303DE37D48E9548B76BEA829B
-:10EF9000ED1CCFAD7338DE758CE3B97709E1799D4F
-:10EFA00091E78BB8FFF160F69B4203B7DF608AF60A
-:10EFB0001B4CD17E8329DA6F0A4773FB0DA668BF0D
-:10EFC000C1EF68BFC114ED3798A2FD0653B4DF60EE
-:10EFD0008AF61B4CD17E83EDD07E8329DA6FF03B1D
-:10EFE000DA6F3045FB0D7E3F897624BF7733504E74
-:10EFF0004FD5DC1F810E35F747AB268F72BA7F7D68
-:10F0000094D3FDCB514EF72F4739DD3F8F72BA7F36
-:10F010007D94D3FDF3CBF36CB4BF505EF76F87F2F2
-:10F02000BA7F7E7CABEB55D41D5DBFEDE22B9876AD
-:10F03000852A8F2BC00A964DDE578276B62EB39264
-:10F0400018019CD2B0FED99242D8B34EE1C73781A5
-:10F05000F5EA10DF646707BC39BD8CFC8EC77F13EF
-:10F0600047E5D2AE4B7F80F7CC038CE4FE43225EB3
-:10F0700053B6B733AB8AA9ACEFCB0F5E2F707C5978
-:10F080008FF8A5DF3CE06298897E2699EB2C59E841
-:10F090002FBF4BA7707FD33BB9BF6F205D3D28E4E6
-:10F0A000A05DBAFDC782D17FA84CB1631C439A9E74
-:10F0B0009D3064219C1AB2503EB8637284F0076E92
-:10F0C0009882FE4772DE520F087C82E2D7F27B996B
-:10F0D000B102C699F625332E47FE6EE47201B6C31F
-:10F0E000FBE23897E278D28FBE374FE6E79BD3B585
-:10F0F0007A4A057C1FB7B7610AC6C5CD0DE6ED7E1D
-:10F10000F34418C1F18616E5498C3FCCDFCB1C18BF
-:10F11000EFBA55F0D3717BADC60A1AD74AF174B273
-:10F12000DFB26D8914FF57C6BA0A31BE82E5280CDA
-:10F13000EDA3126EB0BE57707D69B0550C247FF2FE
-:10F14000B89C60119723E37182228A17E6E5FAE200
-:10F1500072A6E54414A15F1CEB60760C03BE3EA7CB
-:10F160006CC370E8DFE976D8D1AF68DA970DAF529B
-:10F170007E4731E5890C26D23874AE8D7129F4BEF4
-:10F18000C60DAEEDBA281BC6EBAE374463FDBDCC51
-:10F190008EE20E1C3514772AE797C13A756605F1A1
-:10F1A000CE8E0FF3A323E0003722DE33ED067A7F05
-:10F1B000639EDE6A40BE11788E0FF45B0C901302E2
-:10F1C000FC4B9AD77D90A826A37F89CEEE45BE75CD
-:10F1D0003084E40529EF94097FB3CB2DAF0EBF092E
-:10F1E000CACBF673F9C0D9AE10FF93FE267529EE8F
-:10F1F000441DCA0B23B64F8854F9F98F7CF19CEB60
-:10F20000B945B845CB36BC4A7111651B72C3795CF0
-:10F2100014B7435408385508BF2296618D4639F318
-:10F2200014F01DC718F24B0CA7B8C2562ECF49BD1B
-:10F230008E9407E5FB31656F65BF86782F7B4CBCEC
-:10F24000CBB2B98CE2AF02FD7C6A84BCB7B2C540D8
-:10F25000FE432B03E4C11AE12F5413200F9E9C2C74
-:10F26000F440521E14F717E9CF5BF6D6F18524AFB0
-:10F270003418C82E57B29ECB2F6C3F73633C43C9E2
-:10F28000FA593A7C37A4E4A0C3AE0C42276F0B397D
-:10F29000666E9799E03AFF4A3CA58BAEC4517AD38B
-:10F2A00015EE4789B12F48075D2F3092A3DF157205
-:10F2B000CB42F4ABC478445790F09F642437653256
-:10F2C0006B11F28FAB1CCA7114FBE61A9C1BD06F3A
-:10F2D00073EE7646F147D7A37C03FD2F467907F5F9
-:10F2E000EE39494514873147A17896EB73560BFAEE
-:10F2F000067A6748EF2E41BFC594EF3F17049D3B48
-:10F300005DDD7A84FBF52EC588EFF039C53D56D218
-:10F310007120BD978608FD9385EB97FAF54F385914
-:10F320007AD4C6740BFAB796A26E7004E388079875
-:10F330008766F0F2D829A65B5AF052F3DFD44B94DB
-:10F34000E8743CDE09E42DE4ABB7ACCD342EF3E336
-:10F350002F9F4C9D39696AAE0FEFCB02E2F4D6DCE9
-:10F36000353AE6BBE245CB01CEB84F4AC3BB7E0679
-:10F3700014CAF2A6304721889E4B985C27F3A25FFF
-:10F38000E052915F3E25F3AF9B33083E94CF793135
-:10F39000FA1617F155CEB76E46BEA522BF72664D5E
-:10F3A000217ED5351BF11192D12BDE21E0F10E81AA
-:10F3B0007A88E553381E02F511E5199C9F33BD2D5F
-:10F3C000F1668A0BB6913E4FCEFF94411BA729D31D
-:10F3D0005BA670BEFC63C537FCAF14E70DB8BE0773
-:10F3E000753C6E7E84DACA845E88F6BFE41F4CBC2E
-:10F3F00023E1C33FC869644757ACFEF8776E56787F
-:10F400009CFA10FA1B96DEFBF04ED4DF351919C6B4
-:10F41000B93E91C6E9E889DB8D248797183B5FC523
-:10F4200077B2241C3F6AFC0F03E9FF997734BEFFD3
-:10F43000B5B4C16C47FEFCC9D4E28A29C3111F765A
-:10F44000C2C724D866D8FFC984E215F8BD6ECBD1F7
-:10F45000C7316E7F554712C591961DCEDC88EF8966
-:10F460007C32D5598BEB2DB3588D788ED7B744D0DD
-:10F47000B9561A23E23A592FD9A924FC5BA6F0F316
-:10F48000744A3EEFBF47DC479061CED3D4137EDC95
-:10F4900001FB44EA0503F50B81EF380CB57FA41E90
-:10F4A00001F506463FBDA2D44B18D24F2DC173B40F
-:10F4B000C4A88D3F94E941A97713F7C1E5FDE7584A
-:10F4C000C6EC18949BB72A563CC72A2CB69B2643F9
-:10F4D000BEE284013D30D9DC481B7FBFE32EFE7EB7
-:10F4E000C732D8AFC86F4A843F5645FB64DA6F1500
-:10F4F0006E48B387DE97376F3D9EF002D28FD741BB
-:10F5000071F915568731D26FDF97B72A9AB87E996D
-:10F51000DF3945A5799780988EF0BB656D9211DF34
-:10F52000D02901F102FDFB0E4EB169E2AAA11EF93C
-:10F5300035CC4D66AFF1F79360DE497CBC2CBFFE45
-:10F5400097B56ADF2780FA2417FD764A28E1AFCC09
-:10F550000AEB4EC2D44AF30438109C7AEF85FE6C55
-:10F56000340EE1A3DCEB36E0BDBB04FD2920BFD4A3
-:10F57000EA36E038CB5AF87B21CE2D7C1CE7E60832
-:10F58000E378949BF4566302C20F2FCB51343FE2D1
-:10F59000831500178CB792719781F02913F3AD682A
-:10F5A0008DD0CA63AD5B0D888F2543BC57D02DE845
-:10F5B0007659CB0C8A37AFD03B289EC129E0FBC9D6
-:10F5C0006AF3DD681758D2F6902109F27F14F4DB54
-:10F5D0002DF6DDDC64EF687A1768B5D98EF35C62CE
-:10F5E0006DA5F5F5C3F701808782EFCF14137C81F9
-:10F5F0002E5CE89F57D1A6C5A76F3E1CBE156D6552
-:10F60000B4DF2AF54EA3D57F1EED4747A31FCA12CC
-:10F61000D8DFF8DE11B33A29BEE9EC033725D23A38
-:10F62000619EE40765B7CDC6777E804E888E25BD86
-:10F63000C8B86C39DE3753785CE637DFBB2F1D2442
-:10F64000D734037E51DF3DD4BE346260178C6BAC7F
-:10F65000E0EFAF05EE53B93FFBED07629FCAFDFB3C
-:10F66000B8A1D81BABF8F80C9CB70DCF0E02A74978
-:10F6700053F97C970ABC025C5FF18FE3B24DE578E9
-:10F680002D49D6EE77EC0FFB0D93E533BDA331EE9C
-:10F6900052D697E39644F27648F7486F61623CACE5
-:10F6A000BF86EA6BE351CAFBF9C5DE0DD1C82FF660
-:10F6B0002B24F7AEB9F778C2BFA33CBB8FCBB3E71F
-:10F6C0006A77D6C7A1DCA87727FABF8B55E1E5FC9E
-:10F6D0006139C83FC82F2AC539BD2FCB9930D5CF46
-:10F6E0007FA2E2FE7D694ECE5FBCC85FFEB2EFA591
-:10F6F000F7A6D87CE7A79CFFB2CD7F349459FCE1F4
-:10F70000C5D777777A1FC5D9955B8C36F45F2E6F96
-:10F7100029237ECB62E15EA1F8F01D4807652D0A22
-:10F72000BD2F56DE38D1ADFE5FE4CBE55BE6D19B65
-:10F7300048124FF2BD13799ECAF93BC4FC970A3AAE
-:10F740009E3595EFBFA55549C64ADAF749C672A45A
-:10F750007F51BEA442FBBD1F4FFD76EC8C8DB83FA0
-:10F76000306E88EE275B0C5CCFB73794E4D5736BB3
-:10F770009EFFC322A8F7C583DB13513E91F35821A6
-:10F78000F479CB855EAE52C8AD80A7F953FDF8EC95
-:10F790008A27389ECA9F79EBAFF82E5749B2E067A7
-:10F7A000F7F278FE659EFD84B7259BB71A92105F2D
-:10F7B000F848AD5FFBF206B8E8023C976EDE6E409B
-:10F7C0003EB04CAE3780DE4B84BFAF842B9E3B8A6D
-:10F7D0009FDD42D647FEB71FC659BBDA1C86FA69C1
-:10F7E00039CE3D53B9DC54DE101189E3953794FDD1
-:10F7F0000AEF1D92DF07EEBBD366BE1F96417FB8AE
-:10F800002F4FCFB0535C33DAB5063B57EF9CCACFCE
-:10F81000D5470DFCFDC6F810CF1E8443FCAA603B03
-:10F82000F287D4D42EB21B233DE3BC8D3AFEDE63B7
-:10F830006A6DD7259C0788D4E49F8229BE33852230
-:10F840007634E49FD4F1F8AB6495A7BB057CA0DCCB
-:10F850008BE52CAA8BDE9DEB7F3729805E8D6CC7F4
-:10F86000667CEFC618C5ECCD361F7DCA7E247D4A66
-:10F87000FA1D6A7DEE1FB8BED349421F916E4FC478
-:10F880003895D2FBC6D8513FF37DEB348AF707FB9E
-:10F89000D70BC49A1739C87A53F9BD65E8F5B61580
-:10F8A000450FB2DEC075CA7D227DDAFBED0BADDC03
-:10F8B000BE705A81F30BDA9D5E6D26FF2FB92EA91B
-:10F8C000FFFEA17108AF4C8D147A9DAE5094234B6E
-:10F8D00082C5FEF7F23C7E9FE7F75D9EFBF2BD36E8
-:10F8E000C99FCF3488739175DD8BFB9935A6D0FB0A
-:10F8F00024275B4F87E27B29A767F0F9C9766B0D58
-:10F900003CCE98851A6DF8FE21DCAF4E36A2DDA7FD
-:10F910002586EE91B734A6105FB8C515C1F50F4224
-:10F92000BEAF147C30646DD9467CE77B797B925501
-:10F930008171965BEC67DBA9FD383BCA83216DF3CF
-:10F940008CC924F7F27B80B413AD555831C58D2195
-:10F950009FC4FDA53B9A8AE7CE8A767E0F98AB635B
-:10F960009BD14E38AAB978761CF28987158A3367FD
-:10F97000DBB4EF58A567177F4CF7BF8077E0D61A46
-:10F980003C8E18E4E3206FA0BE69B9A598E4F65256
-:10F99000412727DBBAE93D7A09D701F13F461E0727
-:10F9A000DC1BAA233DDC0F8D03AA1076254937D234
-:10F9B0002EF508FE6732C249A573AD482DA1F79414
-:10F9C00036B6CDA2B4626BD183AEF1187F5C1C3D1C
-:10F9D00085E66D203D5945DD2C1EAFFB645004DEED
-:10F9E0006F120DAE447FB9B462FB268AFFF96CBB7F
-:10F9F00099E27F0AADF30A23A2E8BD638AAF93F5CB
-:10FA0000C2F3F979515D374B13BFB31CFAC4773693
-:10FA1000BFF284901F9A8CCBA98D7106E7E7F2F8AC
-:10FA20009CC9361E971347F56D83EAC5657AB6897A
-:10FA3000C779F8C51BDDB004DAD7D63D1786FDD4EB
-:10FA40003CF0EE44AB8EF450D1F9C3FDE28DDA798F
-:10FA5000BC518CB82FCD8D2C5EB404E1FF7B95E0BA
-:10FA60003FD4785587158D1DEF167738C9AD4E2FC9
-:10FA700033A21DD9696524177FA6B2469403A4FC5E
-:10FA800022BF5F95CFF9D567E1AD89481F2B773D40
-:10FA90009488E7CBE7A13C5FB2EBA6D7915F3977BB
-:10FAA0000471F95CCF481E2E7771F99A5545CAF753
-:10FAB00048CDA5404739F921FCDDA3766DBCB97C62
-:10FAC000E7F6733D7F9F07E38D90DE3FD27B972360
-:10FAD0007E3F02F915EFB1E1F99C3E3F6A5567930D
-:10FAE000DF106C1494433E6A7D2E14E3A1A5BC562E
-:10FAF000A4FEC581EFFFAC39C8E382F17D7A7A2B91
-:10FB000054E841EA851E64CD0B86D9F151247FD19A
-:10FB1000975ABDD73818FEAA857CD59F3FB09FEE77
-:10FB20006DB57BB9FC50EBE926F941CA2332EEB042
-:10FB3000666F37C913B25DFD010E97BA03FC7B599E
-:10FB4000BA4EEA511C4A2ADEA715CAAF9E9251BA94
-:10FB50005E931F57BA5E8FA9D0DBEB7B491EBC3B7F
-:10FB6000FD1DBA87D7B5887E216FF01B6F0912D1B2
-:10FB700070FE3DC582ED6D1AFFDABA0311D4DE5B6B
-:10FB800017BC19CF7947BD458F69739D85CEFD6D33
-:10FB90000DBA74F4537728C17694E33A84FFD6F013
-:10FBA0009AF7CDA83F8863BDC7F1BD5D6F82B316DC
-:10FBB000F7430CBEEEA2FAE2897A8E7C9A8DFD178D
-:10FBC0008CEABA8C6F6A18D64F2A453BC5DA7CB1ED
-:10FBD0008E8CAE6CA4EBE1C7387F7ECCC036D3BB35
-:10FBE000CDFA6286FA7BAFB02FBABED1D1FBB31D7E
-:10FBF0008AF7D7FEF2D51EB16F8B83B89DF1FE094F
-:10FC0000CE5FE23C7EAA18C667927FA33A1AFBEF4A
-:10FC100011764829A7CE14FC3941DCAF8C23622D24
-:10FC200048C7D2AF4F713828DEF3CE8C63E5783EFB
-:10FC3000DFD36BA2788199BDC124B7268C9843E7A6
-:10FC4000997CB75DB1E95909D43F96A1F3625CDCB8
-:10FC50003DCCC4FD024C01F2ADCE4CFEC94AC7EF0B
-:10FC6000BE41BE1EAF5E3A1E8EFEB2FFAED0FBA3FB
-:10FC7000A57D671F7B9BE17DD89D49F1D009CE878B
-:10FC8000108527FBE6743B0175F7583D263B3F2F57
-:10FC900098FF3A3A7EFE4D58A4CE37BF9EDEB3F4AD
-:10FCA000AE634FAF89F4B6333BC43B8701F3E989B8
-:10FCB000B5919F34D42379B3C7A2A3F7DD66761C30
-:10FCC000A7F70A67CAF70C4DDAF70C992D2102F550
-:10FCD000CAA44B05E120BA99E3AF205C7B5FECC876
-:10FCE000E7F26287E02381EFDDCBB81579AEBC6C1B
-:10FCF000D9750BD74BF17DBA4ADAF9AF24933CD1D1
-:10FD0000D791F29DEF58BC8B7205C80BA7AE76BC9D
-:10FD1000923FDC77AE2E147092E7B38C5B5828E0EC
-:10FD2000B5D0A2E3F009F8DD1549378174E1C33B92
-:10FD30008FF792F864B777BE8AF15880C7F1F73130
-:10FD4000C2DFDB488F27BF7973033EBB3042757437
-:10FD50003B937E14FCD1FBDD3F187F9D81F8F39A25
-:10FD6000C7A01CF1808EE408E9EFE814EFB54BBFA3
-:10FD70004796CE881F94AAC1A42F748A77DA810F80
-:10FD8000BC8A7C40EEFF5173BAC6E3397A12AEE802
-:10FD900038BF2E9D87BE874FE3FE862359679CF0B0
-:10FDA000CFC945F94DF5BD4F4D74DFACB81FAE441A
-:10FDB000FFCB8516F273EF7107BC4F2DDE31EF617B
-:10FDC000823F2C96EF98C37E86766D4B7879FF3B09
-:10FDD000E6A319DDA3DA32591ACA5F6DE2777F868E
-:10FDE0007CC77C6524E94D1F79C43D16CF03F97E9D
-:10FDF000F5F404A779DAF081EF573FA8142FC1DF9B
-:10FE000081718DE7F3ED5A12FCCC2E0E6E2FEA7B3A
-:10FE10004E3686D2BBDD924EA59E7B94ABFB6184B1
-:10FE2000938CABFD58D09B84BF8C2B8C0AC083A4D1
-:10FE3000BBFEDF8B59C7E9AFDF9FB69E913E6524BD
-:10FE40004C2584FC23ED3684EB3D89CE249C7FF346
-:10FE50006A8033E9D1B99FE749F17B1681FB2963B9
-:10FE60009A4EDA89295EA0549C6BA5323EA0511BA4
-:10FE70001F10F8BE69F0C8E209D3609D1794772778
-:10FE8000E2C737FFB73AA8DFC9A4699C8FA7C63A73
-:10FE9000274EA3F36DA6468E7C33F3D304FA7D99E7
-:10FEA0006F8F8FC473EFA684E2C9D8AF3995DB0D8D
-:10FEB0003E8EEBA2F88E8F97FC2D81F4CEEBF8BB33
-:10FEC000AC3F749E03E399391DDCB69CFB23C6B39B
-:10FED00006A2DF585F9CAC19E7F13F2D9ED9176F42
-:10FEE000BC9B7E57E4E5264FCA99D103F1911F745C
-:10FEF000EC391BDC681A8E1C2AA5F8DEF063B725E6
-:10FF000041BEF1C84B3C1F7FEC7212E0E6F6231DA8
-:10FF10003C3FEED8658C075E77E44829C5FFA2DD3B
-:10FF2000600463771C79B9D405F8A89EE06C427C24
-:10FF30002DBAD2F02A1EC3EFAD9FBF3C89E259E72C
-:10FF400025A4F378D6B558BE307AD98670C517CFB8
-:10FF5000BA6D1AB4037AE8B9C4E9BFE712A7F7206B
-:10FF6000E403C3FFF554C6F54AFE3B149F94FBEF30
-:10FF7000C78A4B96FB98EDB26F362031BAFEE57812
-:10FF8000E14768DF04C40BF7187A1F277BD2256688
-:10FF9000C338C4A3A1EFDBF09C68CEE5F18C4A6FB7
-:10FFA000A70DFD30F27378BEF952A70DF93BE6516B
-:10FFB000AFD513C1E31C653C6CF3256F1CEE937C3D
-:10FFC0008C5B84FA85BDBDA5C86FF2D18F3709FB64
-:10FFD0007FEDB8188F617F3B2EF178C31E73A7CDDC
-:10FFE0002AC6C17E60DC24E48BF96B4DE46FD47CBF
-:10FFF000A96135F55362E91F570918D7F4DDE3CE3F
-:020000023000CC
-:1000000052FCC64DEDE3719D38AE4D33AE97E281A3
-:10001000A13F8A3BED89B0C7E27D5FE60BB11CF2E0
-:100020000F89DFA7C8B77955E4FF323E2AC628DE1C
-:10003000E116F715A847F1983BFAF83A2F3679AB55
-:10004000713F150A7E5D68E4E725D305DBD10FBB60
-:1000500048FDF6B578BC97BCC0EF258541C5DB707F
-:100060003FD6EB39BF6151F277D23A57FE06EABD6F
-:10007000131D4FBF2B3632F6104BC57BF1AA391931
-:10008000785E80BCFD11E2FB1DD6AAF0DFDFE2ED59
-:1000900017CC0921FF939E23637271FFCC0FB21D11
-:1000A00064B06F4F4DBB44FB747EB82D176F3AA7F9
-:1000B0008E5CE6F918DB41B4EB9AD8A5D242BAA718
-:1000C000713BED4D3E3BEDA7B82FEBE65C3072B9CE
-:1000D000AC97DE673E378D9F5F20B793DCD17B8D79
-:1000E000786F33C3968BE58986DE30845BCFB77A31
-:1000F000FE5E2DEB0DBBD1CF2EFB78077FC7369070
-:10010000AEF715F0736055AA85DE39AB8F359928A7
-:10011000EDB8349B7E07465F9C8AF7028771707D3D
-:10012000E313055CDE4CDA68F4D9DDE1FC700433DE
-:100130009977B13CC6B6FF5B70FFBD0B8F18E368C3
-:10014000710F73599F284CD5D47760FDFE72C69FFE
-:100150006793ED47BEAC7F02EDF8341EE2B992FB27
-:100160004D049E17A5D32335FE568F4599C9DF2A26
-:1001700055157A3CA86B257D20B7DBC6FFA799E211
-:10018000E77698391DA6EA78BA4327E27C859E4F28
-:10019000DE5F7E31DD397E7A2EF5E3A57ED4FD99D2
-:1001A000284FC4310F8D2FE532590FE42F33311909
-:1001B000F13B6FF9AA6E5078BE5230C351908B74E8
-:1001C000ED629FF89D131743C21AFDF157AF6AF510
-:1001D0009DAF14CCA476B27D5DE32CF609C5217ADF
-:1001E000897EEA5275745FAD57D92BF47B03AC93CB
-:1001F000EC98B2DDFBC0273FA1F71A1C947E00FCEF
-:10020000F213F2F35B4CE95F9A9CF4FD645315A57D
-:100210005D4D0DF4FD545323A58B6E0ECD41FA5F59
-:1002200075783DFBC4EF7CACF3189CFE7E35EFCFB8
-:10023000189C8E2A051DBD9F3478795301978BDE5B
-:100240002FE0F8EC59CEE54BA0CB166BE4D0F24290
-:100250004F28F747786926A7F39E389E7716F077E0
-:10026000421D3AD68EED5F9AC9DF617F3F5947EF55
-:1002700039382279BFEFA7E9484EBB76F68C528415
-:1002800093231ABE67F9F2EF5FC5CB1D23F87739C8
-:100290005F593E7E7ABFFE208DDF8BB9DD1DE89D64
-:1002A000FAEFC76F219F5F607DE9471F088FA36248
-:1002B000DFD2BE40B91DF74192DFBEA8B7D1BE90D4
-:1002C0007428E9AF743A87736A90A07338BB087ECC
-:1002D0007886E1BD38C64C72AC03ED16B09E1D2287
-:1002E000CE7DC07E107600B91FE43E90F41E0FFB59
-:1002F0008CDB39F83AA6A983EBE73715F07B6A6700
-:1003000074E8CF08AF1D062B9E37D3546E6FE8E913
-:10031000589883FEE0459B2C0D83F1AF9745FB7FFA
-:10032000190E921F0C018701EB370A7DFD3FB97E44
-:10033000E26FC8B797737FCC407ADD5B20F915A7D1
-:10034000DB570A1CBB907E7A14B31EEF273DE6C133
-:10035000FDC75F9AC9F785A49FD2E94CBC3F03EB68
-:100360004C19C8EFE47AFAD7B98211DF4B1571C680
-:1003700081F895EBF2E37B1D057E7A27C6405E810E
-:100380007E46D65AE87E2AE9F7E2F06F2AF1FC9A17
-:100390005360E3F6179D2ADE81E5E749FF7745A51F
-:1003A000782BBF7386A1DCD27B84DBE1BC704F422B
-:1003B0003B16EA9EFDE3ADBF16FCA26F71AE0EF5D3
-:1003C0000317BFB6B8F0DCBA38A2F724CA2517DB8A
-:1003D000F93BE7D0E35C05FD4530EEC786BFD7C2E9
-:1003E000ED1FEAC35F9D4479A8F26195E4978B788D
-:1003F0005D8676AB1EE0BF6F27FD066B45BBE6F65C
-:10040000CB8BE877CD803E51FEF9C45C9F8C72F1B6
-:10041000AC871F3881EFAE571E5450CDCC8EA3BE93
-:100420001DF26777ABFCF75545BCC96CE1D75FBDE2
-:1004300093FBF5D7629C09CA2F07B63F88BF3B598B
-:10044000B7DBC0CCF07D36BE8F06E3ACF084C205CE
-:1004500012FA6DD3C6A5FE84B936A21EB96A9BF600
-:100460007BF50E6DBE36C05FF15281F04B1CCB3276
-:10047000C92FB18DEB8925DF1E28EFBA387F5C23A9
-:10048000FD74BFA477BDD5235F259EB2F0FC3C91DF
-:10049000EF86FC85AF38FC25DCEA05CFBF10C772BC
-:1004A0003CB0BEFA23662BDEFFEB5FE0FA818B9E49
-:1004B0007082F3AAE02EB227B017552BCA61771DC0
-:1004C00056499F50D761FE35FE1E6DFD4185DEA960
-:1004D000AD3B1CE4E6F0B95489E52B0E9BAD362C00
-:1004E0007F3188A1DEF922E00DFD612F267411FE17
-:1004F00011AFA88F80BFB9F8BB1512FFEAC3DC8E1D
-:100500005CB947E0A7FD363DE1D5ADB098A4817850
-:100510009278FE9DEEE97E3C61BB590FBFF79AC011
-:100520003BC3389BE3EDE5F47B1812DFC6239F2421
-:10053000A2DC2BF1AC029E7F21DBDBC43B78DF81A8
-:10054000E72AC4B3E59FC7F3EB054CC6FB9D7D14BA
-:10055000E5DE5023D9CFA53E43EA2F86D7BCFF6AFC
-:10056000140C3C3AF63992734B23CFD5AD66A43FB9
-:100570009B341DF59FD7BC853FE7CBDEB9F6E94C30
-:10058000A48F664317FD5E8C2B82BF27DF93346FE9
-:10059000DBF3305E61E43789FB71DFBC1C4466939A
-:1005A0005982AFE29FC9FF3DC00E33E9D9EA3A82D2
-:1005B000B85EED80D66ED613C77F9FAFC8D85BBA42
-:1005C0001AE572E80FC791F7C19A0EF1BB2FE2FE50
-:1005D0005623F50C7B03DE85B2BE45F54AA627D32C
-:1005E0003C5262A6D9900F352F61CEE094EFE2F72E
-:1005F0005C7F237F276F48397008BE2FE53FE6D226
-:10060000EA3924FF59217E57B27F7F887CD57A57FB
-:10061000984925BAA378F1DAC7F8EF2A7E8A7417C9
-:10062000E6A3A77A1197F6EABFBDAEC7DF67EAD99E
-:10063000C1FD2280433E88FEF9E73D3C0EAE3AA75D
-:100640007BA2D786BFCFC1F9D0CABD8ADB9634085A
-:100650001D31F746FE9E7D003DEDFDEEF70E6F9FCE
-:100660002EE2DDC6B2F1FF00786EC7F8A35C1FBFB3
-:10067000088C9BEC3FBF027EBFE37F5A1C775F066E
-:10068000ACE73BEC8C3F89D5BEDF728D4DFBFB4C5C
-:10069000D7A56B7F9FA9CF22E023E44129A7EE9E37
-:1006A000CEE599C054C2F77ABB761C792FFE699EBD
-:1006B00076BC790EED783F142F3F563CEBF7C1EF37
-:1006C0003531EE0931EEEB62DC7F154E321D6ABC2E
-:1006D000FF9FFEBF49FF0F426139640080000000A8
-:1006E0001F8B080000000000000BB55B0B7C94D54D
-:1006F00095BFDF7CF3CC7308210904C22424216058
-:10070000880324542B96C9D300D6065C2D68840137
-:1007100052C83B80B5D2167F190411105BA8D1A234
-:10072000224E82E1A1619D08C144431D14B288D6C6
-:100730008D748BFDFD56DCF828F23213A374E55757
-:100740002D7BFEE77E1F990CA1DAEE6EF2D3937338
-:100750005FDFB9E77DCFBDD414E718BE9A22446E9F
-:10076000CC59734F8410AE953D4589D942F4BDA94B
-:100770008A268710C2ED3D561F2B446DC770B129E4
-:1007800099F092BEB70CC0DBC6D93751FFC6F63F11
-:10079000BC83FEDE03AAC342FDAFB77F1C85752E66
-:1007A0007C152EC470CCFB384A105E7D49617C13E9
-:1007B000F53B089FD9AA0A7F26AD67F499D17F211E
-:1007C00055C7BD6641B0A4A5D5DC43B06A4F2BF731
-:1007D000BFE9330DEEDFD338A8DF8EF104AB8CDE3A
-:1007E000283BC173EDFA7A7E1E5F9DAAB8BC68DF14
-:1007F000F387B8A518D7F26EDC128297F133E36A5B
-:10080000F8D9C11732DD34AFA683D6891858A7A608
-:10081000C3A4E192EEEAD4D6A218E2976851441A32
-:10082000810B628B5845FCAC6A6FAE16D45E957135
-:10083000B749105F023EB518DFA71F8388A37976FA
-:10084000FA8BF877C1F745D4125AF735DFD1DB5C64
-:1008500004039D6F44E1BB8103343E73809EE92E07
-:10086000E25F0EA059881134EFC01B510EEADFE899
-:100870007B43F2DBE8E77DBFAEE10182CCE7769512
-:10088000F75DF195CAFCD7D7BBC5A5F23A33DBD3E8
-:1008900022B1AF133EF9BD392E876C4F5D5406FA75
-:1008A0008F27CCCF5193996E17F0C0C4D9CD9B88B8
-:1008B000942A1FAD9B7935DF9668EB7699C43C1F6F
-:1008C000E496BABF6B14E9C7F1E2E193A9E7CAB8AD
-:1008D000BB5D061E576476A72EA77127221C917652
-:1008E0005AEFC1E2719190EBEB80682FDE697613CD
-:1008F000AC3C20BF77C2DE1D057D3B7160AAEA518A
-:1009000006D6BB43FBAE101E860372F3B09CCABD75
-:100910008D115867407EB27D8ECBCEE38F7BDFBDDD
-:10092000F36EDADF898C7027E4D26516E53ED613C4
-:10093000FA08BED799D8083EE8DF9B0379D0BC40BF
-:100940008681E5DADB6ED2C6DDDD2C068D33B1DCC7
-:100950002E3C37981EBBF7C35FDD4DE3AB9F51853F
-:10096000859AAB4DCBE3B0FF4FB70FA6AF5CE373F7
-:10097000B5C91F1717A4AFD51D57EC2582F5BB438A
-:10098000B70F07CB5397E3890C55D29560F10A2234
-:10099000B9BAB599F59ACCCD639BC250D8092686D1
-:1009A00077272BB4FFC4FBADCEB544FF738AD66F57
-:1009B000201843B841E266825682CF98643BCC1639
-:1009C000F3C7903815C24DC5E3720C29B48EDA3ADC
-:1009D00019727D7186EB5117EDFF97334A26CD20B2
-:1009E0007842F42D15F4CD9A8B111E112D44A1FAE5
-:1009F000FE13F86EFF019380FFA8B176547E427A11
-:100A0000DAEF244321BAFBB79BBC1ED63F57843292
-:100A10004D88A53748BBF9D4E19EA68EA3F16B0C97
-:100A2000BCBFEA16D56BA371BDF5C40262F967AD10
-:100A3000C93F82BE561F53ED56DA77BE2FF9D7D382
-:100A400081B7989C169A5FEBA346C26BF7285E8726
-:100A50005C5FC02E6B6E605D17A76DB529228BE0C1
-:100A60009A3E33C69D3EA488C768DC2361514DA0E1
-:100A7000BB2673D659258AA0BA797D22ADB76C9B67
-:100A8000E9A31EAB9C7B99FEABEBDCCA7A5BE11D54
-:100A9000DC5EB567305E238C0338ADDF8C3F6E14AF
-:100AA000A2CD15197BFA3AFA7B82987059059FA658
-:100AB000C7C31E8E43AEC447D140CC1E29C4BD93CC
-:100AC0009CF1B0FB8D46C72CF021D069B2835F75D5
-:100AD00087F657806E6F7598D3405BAD5DF52AF34E
-:100AE00035F025F1FD7A820982F71F1092BF8176D9
-:100AF000A9E77526C56BC57CE221AF6755BC6BA81D
-:100B00002BE0E98F62FF244431EC62E5FC1C03FC1E
-:100B10001CCC581029BFD6ED41B11995684069FF2A
-:100B20003F30F6A8C382FCC47FB95298FE02B3706E
-:100B3000FBA8FDDE486734F47EAC352A0B748DB516
-:100B40002679C1F7B1C6BE35F8FE23A314C783B416
-:100B5000F4E1AC57262BC06B239CD0132561911177
-:100B6000FC7864D42223F47DACDD97519239801750
-:100B7000A01FF620BCFCBDA208B711DF796EA4E26D
-:100B800037D0FA011BD1073B31DA4DA02F6092B864
-:100B9000106B06D1471E89F1FF77FAEC445FC40061
-:100BA0007D24EF68CCFF229BF84330698E10DDEC8A
-:100BB0001796B35FD0F97981F4BD806495A648BDDE
-:100BC000A9DE7EB808FD35A27B3DE61545C97D143A
-:100BD000613FC0C3245473A5BC7235785FAE8C2FBF
-:100BE000BAFFECC8751973096ECB2D310316AA999B
-:100BF000F13D43F8FB958A95F5E40BB23FF8E37BB2
-:100C0000962BF6D48C01FDD6EDAA4E365DB19FAA87
-:100C1000DFEF348B147CCED59D41FDE542DAF5C281
-:100C200055367B6AB01DC1CE881FE5F68A5B05D9B3
-:100C30009B7B559C3D752AB5AB17CC02BAA7D957FB
-:100C40002CFD5E4E19C2BE7C2176D93E18F7DBA47E
-:100C50009EFB2315EF5AA23F3577B0DD256976D08C
-:100C6000E856787F8D5F1B19F7942A5EF0FC0E6AB8
-:100C70005C15A36D0EE3CA73BD888F77105A8AF690
-:100C80008658B653EE24FFF52FDA3EEF30FA0FC345
-:100C90007F1C35F992EDD475B4C6EAC4FAF3052584
-:100CA0003AE4D74A4537C393E1B56D7E5EDC33063F
-:100CB000FAF59EDBE2441ED6B8AE29127E3C4BAC60
-:100CC000B39FCE405221F65C9E7AED7C8614479C01
-:100CD000D6E582404C790AE4ADCB755BAE2B2F375D
-:100CE000E7DAF3ABFED876DBF7E0BFEE6B36C74B47
-:100CF00035E9CE983620375DAE75C2C374EBF2BAD3
-:100D0000223FA27D34F8A15E98C37EE65955705EFD
-:100D1000A1C9CF4ABF43C94FE7EF0C4D0ECB3AA450
-:100D20003F0A95ABCEEF1FD382F83EC5D1ED2C0F15
-:100D30006161FF172AF76F930B6598A5E8CA8FB515
-:100D400008C833D120FD63E252D213A2FB6EE13E0C
-:100D5000D443F0CEF0B74DAC879A7CEE817C68E846
-:100D60007BC2FBC38CE4FF3BF974E496DC1F6C8709
-:100D7000A176772D3BAB7638FF5D8F7BE469C8BEEB
-:100D800042EC33C4FE7479B95745B19D5D91A3DA45
-:100D900022ED55935704FD0E696FF883BE57D3AE0D
-:100DA00078FDC9DFC1FE14229CE4F65888DDE9F223
-:100DB000B996DFD1FDD429E13F6AA7FD9F4C917917
-:100DC00080E767166F33F0744339FCDEC98912EE91
-:100DD000D7FC5B283C45798E42716C53C6891188DB
-:100DE000D727CDFA3A366F33D17F6A4DF79815344D
-:100DF000FF54AE8427911706E1AE30B1107EFDD4CA
-:100E0000488B077C3AA54CC8437C38A5DC7F9BC443
-:100E1000E3CD0EE0F3E3F3EC849F34C9F17A5CD1C7
-:100E2000FDFFA9F9DF2BE0718A38027E381451C228
-:100E3000DF51949862A2E7D47D6953D68A81FD3749
-:100E4000E51A789E57F3DF4407F3BDEFE78AB789C9
-:100E50009A1622A410FDC979BF2D4EA1F60F7E313E
-:100E60006E32E4EB5A39F8FB88D7C9D703DFCAEBF7
-:100E7000FCE0AB3ED3A2A0B874254E167C2EDBCB93
-:100E8000720CB097724D86AE9809D1904FBF775CC7
-:100E900034E28E1E87FA8FED8F7007C9ED2CC529BD
-:100EA000313E089FF06852701C3BBCEB9174AC5310
-:100EB0006EF66439A9FD4CE3D349C837CA773D9C27
-:100EC000CE79F0AE8DE938CF94373D92EE623CDCBE
-:100ED000CDE729A3DCF7F97D37EEDC14947757E5ED
-:100EE000AB4C7FA9F57021E2EDACEB3E7BC84EE345
-:100EF000D27EA1D8A15EF788EE87101F17203FC6CB
-:100F0000F9ADC1CAFE9CD67341FECD137EF81CEC30
-:100F1000F878C6C7A6321A7729D7C8FC5920BC9BD7
-:100F2000E3A95F6C50ECCD2278FC98468C5FB44E00
-:100F30003127C00F2C1F36597560DE30A663F1864D
-:100F4000C95D685FB05AB6CFB2780F9CC03ABF3562
-:100F50003B9B1DEC6F524A260DD07F29D7CCF31650
-:100F60006E5638FFD7BF93F6445C63F03E2F69F2AC
-:100F7000175F5B14C8E5479A5C6E5DFDEE91045AFD
-:100F8000D71EEBBE0CBFF1CEE3A753FDD45E1073AA
-:100F900036137A9E66763F55817D37599CD84776C1
-:100FA00056A21A4FE3A7FC34F731C085AB173D5565
-:100FB000017FBBCDCAE7369DBE958AD3007FFC4634
-:100FC000E38F17836F671EB772DEBEB2717CBC18E9
-:100FD000C24E75B89BE4EFA083CEDE7A2BC317EA2E
-:100FE000EDC241FAB0AF3E81F117EB1D0CC53CA933
-:100FF0005F2BB5F3F1B5D69BFA55B870503E9BBD4B
-:10100000C1261CE4A792E25CA3F2689F69136B9A65
-:10101000366AFB4AA3F9933DC9F9E043F6C6155D6C
-:101020004879CD79F23CF6D6890D4970CACB567F06
-:10103000B8A382FAE7E4958CCBA376EBF6CFB9AEF2
-:10104000F046C7C30BC0EFF2268BDC9FB6EF338FA1
-:10105000A7C73F45EB7BDE34F179BF6EFB873B369C
-:10106000125CB279853958DFBFEB7E93357ABECDFD
-:10107000AEAEC5877FDCAE1E4962FB6922BBCAFCEF
-:10108000E7EDAA6EF51AE6DFFD7925B3C0F7332642
-:101090004F12ECE9CC849B59CF3D8714E6BFEEC7D5
-:1010A000F5F9C5DA7EAB0CBECDD39307FCF84591BC
-:1010B000CDFC3DDCF1693AF2DE8BEDF3FFEEBE0FC5
-:1010C000D2BEFDB4EF76E2AF7FFCD5FDD3CCEE719E
-:1010D0004EDADF3483CC77AFCA5BF30C5ABDA0DBAA
-:1010E0005C122979AEA02EA3C54F8A639E68A2A781
-:1010F000BA53F18765219EDD72D688F31E9D1B3F92
-:101100000ACE23E8E7A3A0B87D2D7ABF0DD6629D55
-:10111000B401BFFBBD3F19843F284EDFD81326FC26
-:1011200041DFBD723EA13633C9A9B76324FB05C8B0
-:10113000CD887A5CC78426E067CD528EBD07296FC3
-:1011400092751CA14E1BD8E7D98EF359F0B3A1FBC1
-:10115000AD7DE53CEB4775FBC39F2BBCFF99678DCD
-:1011600059DFBEFFC3BBCE67417E674D3DD370DE06
-:10117000EA35F764410EB5AF4A7FFE8FF2416FAF9B
-:10118000D8401B213BAF55ACAC2785EA05AE1BF41C
-:101190001E937583DA8E9DEC4FFB3B65FDA6CED08A
-:1011A0005D148F7AC7F20FBBE0CFFA13E4398AD609
-:1011B00077816FD3C76971D0D8973487FCDA4B57E2
-:1011C000F4419EFFCEC07EC7631D5F35FC80C80A18
-:1011D00017C82BCEC19EA97DC1AAE4F5D0F333DE9A
-:1011E0001153E01FDFCAFA6B2DD7FB5E0BB7AB9C28
-:1011F000F7506B90FCAEECC3AB0AD7A07A40B87046
-:10120000058DAB333B7EC4F9F1715520AFAB9B2804
-:10121000ED49BC22EDA966DD617342D07A3B604F97
-:101220004CB7CC1767BDF657B6CBD5335C9DB0CB6A
-:1012300070F842AC9710ED55146D1CC9BF56A32130
-:10124000A2533BF717ABDC5FD7AE8A91989310E9B6
-:101250004DA37D148B2D46E4D3B3846F3AEA36C296
-:10126000D8F3AB9BA87FF66BEAD44D82CF4F0B4BE4
-:10127000F85CE94E5D89FCC8A0687CF565CF098EF5
-:101280006779324E4D57158E637D23C3394F993997
-:10129000AFA614F4EAE3B286C971B40EE759C2DB13
-:1012A000973507F6E9EFCB9A1B3930EECED7C297C8
-:1012B000735C14BEEC3B83BE13962FEBA35F501CF4
-:1012C000819ED45D94F58E42F5EB27909FAF3C4410
-:1012D000FA82FCD090FC9E017E9CF80CB99E27B946
-:1012E000BA107FDCC2E582FD4C1AE185FDD4ED53D6
-:1012F000841175A20E4B13EA48B5A69E38E8F3C6D2
-:10130000F63F9AA1CF756DEF9A1D93305FD69DC8B9
-:1013100020D98FD769F1ABA67DFC7BA8F3D51C93B0
-:1013200051B4C6F82E9FDFAB0EB4F239BD5AF8F9AE
-:101330009C5EDD32585FFA131C5C1709B58FB07CD8
-:10134000C720BB98B94DDAC59DAA580E3F27B43ABD
-:10135000EDCC8478CE4706E6C97CD7A59E7F08F9F8
-:101360004B2045712AB45420CCB30E7991275DE609
-:101370003381DFBD90BD94FD8A37FB76DA5740CBD1
-:1013800077676ED86A5483E899D929EB92813051F6
-:101390007E90E5ED1E0D39085749447E0EDB55164B
-:1013A000FC6AC020EBA8A1FBA8D7EA45C7514FCAE9
-:1013B0001CA07B7662A2F463C2CBFAD36590DF7780
-:1013C00019A87FCAC0FCC5F972FEC07948D6C1AE63
-:1013D000E55776917CCA483E7B48CE80CF533C2E61
-:1013E000233FD342F118F8BF523C06F4D56770FB97
-:1013F0004BF54EC60FD4DFC0F8C17A17E3EDF5C543
-:101400000C5FA92FE1F6E320F5FBF8DFD38DD08741
-:101410002ED8D8A801FC644C083E6AF0F89331CA73
-:10142000607C94C2E3B3F39F6EF464A26E6AD7EC5F
-:10143000DB1189FCEB8C4DD6A1CED8641DAA759426
-:10144000FBA67CEA2F9BB976973C87BAD231AE20B7
-:10145000663E9F5FFBE9FC0A7FB422DF9D07B91C53
-:101460003B969FBA95FDA48DEBA027EFBA2E9AEB81
-:10147000806FD2799C3E9D9B31755D36E1B9110A32
-:10148000EB2FF98BEB4BF47325AD93DF29EF510A6A
-:10149000D5EA32ACBF72A46D2AFCEF172EF7ADA0CF
-:1014A00043E777D1A865A9C887BA4C8EF750C7F52E
-:1014B000FCDE24709ED2EB7DFAB80E57EE5D9837B5
-:1014C0003363DCBA29F03B6464F0732EB368015DCA
-:1014D0002E43B8B296FD96C3083F7097A6C7790E03
-:1014E0009917FBCD0E630CEA3761B9B11E9AD7A5E7
-:1014F000C9F99826E7E39A9CDF469D8CE03BD40E21
-:10150000D84DED809374FE1AFB986F4FE49594B11B
-:10151000FE8ABE24E07A5D7016EC4BFA9B24E8F557
-:10152000664D7F13347FD3955B5225E7F9789D2A6A
-:10153000ADDE765EBB07D1F7ABCF1B982F18CEBDC3
-:101540005E78ACF0F32FCB73A7184DF908E1735F09
-:101550008E673FA45A6FCFFC84EC7CEE54790E105A
-:10156000FB2D725C82230776B256ABB7F67A0D1E5E
-:1015700013EAD331DDE93188BF9A7DE9F8C1BFA90B
-:10158000ECAF6BA6104EF05545EEAF666E77FA30B5
-:10159000CC576C06AE6F37C9FE139AFDD5A468EB25
-:1015A00069FB11565F12E41138F472D262C23745FA
-:1015B000F8974ABFEF4F677F2DFCE973E11715DFFE
-:1015C00007C2497965C1D4C5C691E0876F07F0EAC3
-:1015D000829CC5C61BD1DFFA813DB87F842F49B1FB
-:1015E00003CF96FD235A770C7306E1A6973E40BFC2
-:1015F000D990B3B880F0D916EFB17AE8CD8B52BF4D
-:101600006CFBDA4E836F551D326FCFDBD776E12549
-:10161000C4E5B64827DCFBDEFC64E6F7DA8EDD9B2A
-:10162000A16FBDADF23E6053CB1F77FC92C75970DE
-:101630004D42EBFAB2057D67C591FF5804BA668743
-:10164000FBBE04FEE091194CE7ECE1D2AE1F3E92E6
-:10165000B71876DADBB6EF67B0BFD9D194D0829EE7
-:10166000176C5C87A8DC3FA10076DA1BD9BD00EBC4
-:10167000D73E6F71424F2BF7C7E7A13E70305FD660
-:10168000C32B266E49429C35BCB277D72F71BFFA67
-:10169000BC8DEF85EA62649E57A9364E5BC1F2DBD2
-:1016A000B9EB69D0BDD7C6F7B315A855115EB12BFC
-:1016B0008DEBF8AF7EF3F102C8A150DDBE0BED5FFC
-:1016C0003E6733800F27CCAEE89B6187274C7CDEDA
-:1016D000ACD0F08A93C3253DE13D452CBFD82D49C0
-:1016E00088B395C37F7E1BE89EAD6ED981F38ED8FB
-:1016F0006DE1BB89B37B896F34EF6CB3690AA4DCFD
-:10170000BB37D2087D39AF6C59F014D66F96E3CE53
-:10171000DBB6303F3DCDE305BE47E304FCD679653B
-:10172000EBA0F6B3CDBBB3701E3DF7FC6C3E97EA61
-:10173000FAABDB4BE573964171913D01F9A34AED9C
-:101740006F61F788088AB7151A7AEEE093BD4F8962
-:1017500081F9E75A4C7E33F1A8C222D6596306ECD0
-:10176000A132F19662ECAFD2D0988EBCA5626ACF5E
-:1017700002D8C5599BB026D0B8B7B4B8557960CD5A
-:101780001CE4BFD7A2E7B2E68F2E26C8F875B1DDFC
-:10179000E60DBE970C85EFD70BFBDB6903F83DCB5D
-:1017A0002D9CC3EBEBBD65F655E39C561B23FDC793
-:1017B0000734BE85FCD8375ABC5BB86AF0F8FEFC2B
-:1017C00018FE7EADB9271DF14F5F3F90AFFBB59E70
-:1017D00074F8ABD079B3918EC08FBCA0B01FA93C78
-:1017E000A07CA8129F2AAD1EAF0ABE08B3BE4FE36D
-:1017F0006545CE4B98A6F19DE66E2848E6EF56B6B5
-:10180000D85C369A5715D61385BCA83AB2270AF980
-:101810004EEF2BAA68D2C4151BA7C92745135950F0
-:10182000BDB1C26772D9B2869033F2271AB70C7F66
-:10183000D3F79F2948E1FD94B787F3F784BD671A72
-:10184000F4B47CFBE079D8973DC8FE7ADB77C60517
-:101850009FCB5334BA03CA876C27816F3E4A82DC20
-:101860002B0D621DEE2FCFD11CDC6B122EAC12E7BC
-:101870007BCFCABF4484415FCE5DAC66BBED557A79
-:10188000D8AFBD533087FD52AFA987FDDA1B47EEB5
-:1018900064FFD03BAC6701FCD43B05CB64FFC89E22
-:1018A000050EEADFA7E36304C7FDF78FD4B0FF9806
-:1018B000ADCA771562A7C92EEB411B4ED6F3F9C20C
-:1018C000E4083E7F9F2AD0EA3D03F2E173976E372A
-:1018D000BDC2B1EF00ECB03C82EB3A9447B5BC849A
-:1018E0007C6F7E9C13EF35CA314FEA8139F8BE31E7
-:1018F00036E6D252C8E7F6D1EEA2821CDC6FF6F0D3
-:101900003982B49AE34DEDEF2C7C9E0C98FA76C1A7
-:101910004FA58F76CF2A203AAACDDDEBB389A40B51
-:10192000A69E2E94C867A9D21F89DD52AF7A33775D
-:10193000CA7B1AEDBEF22E8DFF820E318DD00B4583
-:10194000CAF78DF6FD6FC3AFF4768F637F1C6A37DD
-:1019500067DB1F8B827FF813C5714FD079FF4F8BE8
-:1019600076F33DEB3CBC0721B878DD607DE8FFFAFB
-:10197000763EF789CD41EDD0C386C178A81E411FC0
-:10198000FD83FC8E87F9BE4DB3ABAABCEE5AF0E1E5
-:101990000A3E977035087F3D040F192F4A649EB0A8
-:1019A0000DF19FF8513DC67F92CFE9FB4C027E7C42
-:1019B0002DC52FC6DBC2BD38AF18F6517C8A95F114
-:1019C0000971A12AAA9BEB53BD6D16BEEF7DB0E352
-:1019D000D324EC9FF490EB30551D2FC7E1FCBE578C
-:1019E0003B2F501C8CE3F7316D1D713877E8EDD536
-:1019F000065F3AE8A28C88F375BDBD46F5A783FE65
-:101A00002AA53B0BFD7B41378F275C052E781FD520
-:101A10008AB477D1A1B23F0F95DB939ABE925FC88B
-:101A2000E2F71DAFC8FA80EE072A347FF23ADA33C4
-:101A3000A5DDDBF57B259A5A017B1FC23F2414E804
-:101A400079F172AEDF3C5EE090B8369FD795F52510
-:101A5000EEAF7DF57C564A26E669E382FDD0B801FB
-:101A6000BF02FB4F60FB7FD01447FBAADCA138D735
-:101A7000C24F95AE29A2E16299714511D7CD8487F5
-:101A8000CF6DA17485EAD1E402C9A74AC3B0C2D818
-:101A9000A0F5CE914F4F98C27EC60FBFF393D847A3
-:101AA0008B50A7F871A97C377025DE04DB39F6B3BB
-:101AB0005DFA7198CD65C3D57ABC6C79E3FAF821EB
-:101AC000E808A5B3C2DD5814E7B8BA5DA7F79C4D86
-:101AD000A72FCF3422980FF3D6148D20B8CCFACF8D
-:101AE000F241EEF75C87C58FB85A51BA627DF410A7
-:101AF0007A73553CD81E14BF52205F2FDF6F5C8B6A
-:101B0000FE5058ADF84FA25E24C8AE9AD9BEC85E4A
-:101B100082E2C28D05217587F2456391570BF7A2CA
-:101B2000B1883364570B9C439C2FC9418E32F09B84
-:101B3000110FC3507AFE5C20DF25DD5820ED7CF5C7
-:101B40000C57007EF366D5C07978E87A5F15C87CBB
-:101B5000A23B2EF23EFD3D07847DB32AF99668E84C
-:101B60007F07F6961817E9C07D50617EB81C77C8CC
-:101B70006647FD2670E812D777030F45CC93F7062A
-:101B8000116224F577254C6A0A8E23BF2994FB0D38
-:101B9000CF96794B5D86E9EFD7873223AFD487386C
-:101BA0006FC80CE7FB92DEF62F386E053A73ECB87F
-:101BB000D7E8EDA6D321D953DD37FF1D87F8DADB4F
-:101BC000F9677E87D6FBF5A7FC3E6DA3F63EF0F5E0
-:101BD00076ED7D57B72312ED81E28F8B306E930641
-:101BE00007EA04B25EAC43FDFCABD70382CEC1A3CF
-:101BF0000B873E07C7B82382EB048EF8A1EA2AC1FF
-:101C00007582D434592700449D20D524EB04C0515B
-:101C10002700449D00EDA81300479D0038EA04C04A
-:101C2000512700449D00ED5FCE93EF6502A4C4B23E
-:101C30007E19C1FEFDDE66D58BFCFCDE43F21EEA9A
-:101C4000DE4685DF695DA0EF23CE5DF55EE780F6B9
-:101C50005EC7B795EFF5EADA5427445567EA3B8A41
-:101C6000BA4E5DABE25C03FF523F8FBFBFB133E7BB
-:101C7000BD52B4379B9C0607E474310EF5AACACE58
-:101C800066AE3F15C41F32B37C5B14817AE99D16A2
-:101C900079CEAD51A9750ADF87721E5C63E9E6F360
-:101CA00047D51EC55E167C9F7BC3E7EC07D6DAA23C
-:101CB0009A40678DCF662F1BE2FD07DF0B3BC49573
-:101CC000FBE6A57288A88928E2FBE6A5B867262866
-:101CD000D4AF8D7C7F4C07D3E1D047BCABCA805BCF
-:101CE000B74BBB0F794F55D9D9BA3E515C7D0F8D9B
-:101CF000CA00E41F7AFFEC2E8C8C3D1D0E47212676
-:101D0000236F2A7EBC6C5F1B7DAF7F8B85F38E15A6
-:101D1000F9EE65D0A3A32617D7498E1EB2F1F9E8D4
-:101D200093ADE307D549BE70B9AB0BF97E7E34D7CE
-:101D30002D569A148ECBF9C5E3E2F9DDC03113C7F5
-:101D40009F0E57492DC6AD9CE4E0FA54A145DCC76F
-:101D5000EB68EFB408B23D15AE55BC06C21709A733
-:101D600019F6B390D8C6FA628AD880F7540B857CEE
-:101D7000DFA0EBCDCAAD0AE7055C2888C3BDA4E4AB
-:101D8000EFC2CE7FBB84F70B4B2C327F4D34C8FBA8
-:101D9000ECC44DF27DCB4F84DB8C78BB8CE22220EF
-:101DA000C5C9DFF550BB3B7C7492CCCF1DF1587F89
-:101DB000D17113BFF72D8CFF61BA9BE37501BF632F
-:101DC00050FC77AB97AFBBB6FD84BE63386A92FE1A
-:101DD00085F8C8E7A22EE825D767DC0C8FD79733A4
-:101DE0009C3443FAC72BEF12494676D01FDEF70129
-:101DF000CE8B89F1914EF83BDDEEAF7A9F1826A18C
-:101E0000FE3E710C4111F43E71B3CBC1FE2ED17078
-:101E100062AA03FCF84B8413FCD0DF29AE9E51B2BA
-:101E200013727245090FBE8B7B942DC4D7226C446C
-:101E3000419DDBE75251B73EA4D8F95DF4557E725F
-:101E4000EB4378C75397AAD81507EAE15B0AE38802
-:101E5000EEA29464A6BBAE5DD64B994371A8A76B66
-:101E6000F6E072B7158E18689FADD9452F8D977A19
-:101E7000729317FAF61DEAA8CF61BC47D89CCDDA59
-:101E8000790D729F7DDD18AEA7EA7AD3DF12DF04E9
-:101E9000BD79B350C699D2D2774DC803BA72DD4727
-:101EA000B0FF05659F3F14C7FB1BBA8E457E94EFBC
-:101EB0002543EB58BA5FDEA5D5C1E13F8D5A9DD5CC
-:101EC000A8D5598D5A9DD5A8D5598D5A9DD5A8D537
-:101ED000598D5A9DD5A8D5598D5A9DD5C8F5BBE5C4
-:101EE0000CDFA95FC5B0BBDEC3FD41FEFFFD6BF893
-:101EF000FFD03AE8C718175A0715564734C751B2EA
-:101F00006F597F0EA97B160F5FBC81F897DF607653
-:101F1000A249AF83E2FDF2BD11EC0F2E140E59FF62
-:101F2000D4F916C1F5D27E619B02FEE7658C331AA7
-:101F3000A8FF2F9A1CF4FA23EC03FB837D00C23E1A
-:101F40008C6903F6F18C994C385BC67B0FC77B1B01
-:101F5000CB75FD1AF21F842F11F641FEE34288FF74
-:101F6000A083C75DA06369A77CD7A4BFDFCC23F0A3
-:101F7000D59421FC894FFA933161BEBDF8CE98DA31
-:101F8000307E1F7C547B8F7574A37C1757264AF8CC
-:101F9000BB43F89528C863C9F0BE0F9EA6F14B1E3F
-:101FA00089E0BC65FDC8A5D3FE377EE5F342C98F45
-:101FB000DFD6FB2B3F215A0AC2A4FE15984506EE38
-:101FC0006B84218CEDA050DDACE07E74E53D623287
-:101FD000E45C6029D90E3AE3B5FB6D11ABD55B8D9E
-:101FE000DD15BB093F1197E8C4BDD6E8848302EF35
-:101FF0009F0AEB8A33E117FD63DC138A72F07E7966
-:102000008B82F9E19972FFB717873741AF0287C614
-:10201000E740DE732D8E36D4019C45094B70CE9F70
-:102020001BEDC8411DC0D9354AE2F18E36C5895431
-:1020300036614901BF3FB36EF9C48A776B8A88A6BF
-:102040007D5986B973F09D9AE2CFE4B959F4711CB9
-:10205000BBB1489EBF46BC2EFCB8B7EA9B19C9F776
-:102060006722D391837ECA2BBF5F44FA77E407AE21
-:102070009B0013353AE3718BA842AADD36C0E3DA40
-:102080007D5E97C15D0A5814E53172BBC19B0DF8A6
-:1020900096C1F753B4933E17619DA2C7264FCC203B
-:1020A0003CD1E2633FD9E172DD02FA5E9CE12A068F
-:1020B0000CAD9F43B638E7133DB7A23FF41D962EF3
-:1020C000CF254552EFCB8AA4FF98BE56DEC786CAFD
-:1020D000BDACC8A0F9B7BF4F37D15B8AEFE9F48B2D
-:1020E0002D8BB2410FD17B0FF641F42E001411312C
-:1020F0005CEFB8B69E79F87B654552BFC89F557DA9
-:1021000022FD19C374A37718F2C7510F788781DEB7
-:10211000518D7D36FC3B8C673D7D36C4F76757F7A4
-:10212000D9D0FEAC4BBE930E5DBFB148BE9F489F59
-:10213000DEC7F3C7D2B7BA394FEF1B863C2ABDFCC6
-:1021400093F5F2DE2583E3CB582DBE8C7D20A5BD13
-:1021500087F46DEC93D17CBF2D0A62B9BFD22AED12
-:10216000B4F281B2836D04C76F237A83F2AF095E44
-:10217000A27B505E64EC97EF2D09079FF6981887B5
-:10218000CE22BFAA11F2BDE528CD6F206F2B25BF4F
-:1021900050537EE412BF03C07CAC8F3B5BE85FBB57
-:1021A00049E214AE711E5D366F4D179F0FB75D6922
-:1021B000D7CE9BADEB717EA6FC6D507B65D9E12E31
-:1021C000C49BAA3D83DB6B967FCEE758CADF06B57A
-:1021D000DFF3D30FF99D4D5DFBE07692EF5390BF97
-:1021E0002EDFA326DF049CF78ED68439E5BF1FF0CF
-:1021F000AD80BD375547F0FBD99DBFC963BDD1E563
-:102200004DF39BBE9B7EACE5F19E3C91017BF83685
-:10221000D80BFF9436C83F79B8CE372B92FD4E9D30
-:1022200076BEAA2DB3739C4FACB5B2FF2A54C39CA3
-:10223000C06B8DD2CF886255F3533EB6FF13B70DF6
-:10224000E37A1E6F0078CC247E771CB756E27D239C
-:102250002CEC1F0A0D25D5BB091E312C673F908041
-:10226000179724F767E01F54D8AFBC7FA833FB143F
-:1022700079BFEFC8C17957BF6F6AD8E86D3D80F369
-:10228000B2E27D7229EA8A7744F0FD4100F546DA30
-:102290004FC330E9471BE6A7731C088892D215C8C4
-:1022A00043E68571FDB16198E351DC2736544CE477
-:1022B0003CFAE0DF64DCED9B6375228F6A98EC5892
-:1022C00083F72A0D0F38B8FF5545AEE77954F2A7CA
-:1022D000618EDC7F43450C9F7B74393434BA46E20F
-:1022E0007E6AC618F77F426EA3B4FBB986646A277C
-:1022F000F8845232FF27586792A477D20C07CBEDAF
-:10230000E8FC898FEE727038F1E39EA86E56E4A067
-:1023100073F1FF008751D9F610370000000000006C
-:102320000000000000000000050015000000000093
-:00000001FF
diff --git a/firmware/bnx2x-e1h-5.2.7.0.fw.ihex b/firmware/bnx2x-e1h-5.2.7.0.fw.ihex
new file mode 100644
index 000000000000..280bbcf4f2a1
--- /dev/null
+++ b/firmware/bnx2x-e1h-5.2.7.0.fw.ihex
@@ -0,0 +1,12847 @@
+:1000000000003BE8000000600000068800003C5053
+:1000100000001968000042E0000000AC00005C50E5
+:1000200000008DE400005D00000000EC0000EAE844
+:100030000000E3000000EBD8000000940001CEE0D7
+:10004000000058E80001CF78000000C400022868D2
+:100050000000F9700002293000000004000322A80B
+: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
+:10061000081807C800070223071C00002C2100004F
+:10062000071C800038930B09071D0000292B192E89
+:10063000081D685052F60225011800000000000055
+: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
+:1015B0000730040000E80000083007D8000502BD2D
+:1015C000073400002EAA000007348000312D0BAB39
+:1015D00007350000358217F707358000396D25582B
+:1015E00007360000142D33B40836321039BE02BF5E
+: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
+:102D9000072C000032FC0000072C800035790CC0A5
+:102DA000072D00003AC11A1F072D800039EF28D0E7
+:102DB000072E00001C3E374C082E3710391E034BDF
+: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
+:104DD000000DDB0000007FF800007FF80000193EA6
+: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
+:105020000001000100070205CCCCCCC5FFFFFFFF4B
+: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
+:105C8000DCC4EBBF2C8F6087CA32303402F11E694E
+:105C900006063B3984B8B90203C30A203F0B2AF633
+:105CA0001E4897CA53E6EEC182B55531C5349411EA
+:105CB0006C1D2CF2C858174DBE5D1995AF4740FFBB
+:105CC00040E32C1D54FE742D08FD4D1B4267A3C9F3
+:105CD000CF80CAFB40FD95A383DD5C5F22FD9DCA9A
+:105CE00082CA8F47E3B731A2F2CD3850F94950F557
+:105CF00000CDA28F7AC80300000000000000000061
+:105D00001F8B080000000000000BED7D0D7854D5BE
+:105D1000B5E83A73CEFC25672693908409093009CB
+:105D200021441B700C3F0D16EB097F8636D70E14ED
+:105D3000696C150744881048A4D6874FFD3291003E
+:105D4000E17F504B43413CFC29BD97B691A2A596FB
+:105D5000D2019F165BDFF782CF7AB5B5BD23A5F8D8
+:105D6000539498774BEDBBDEFAF65A7B9FCC3927DC
+:105D7000332448BDED7BEFC6AF3DEC73F6CFFADBC5
+:105D80006BAFB5F6DA7B9C0E37148E04F818FF6EF5
+:105D900000F81715000A524FA70762D9D700E4E6AA
+:105DA0006BB16415C0D07C2D0113D8FB802BE49619
+:105DB00052ED8CE789DC9941ACD75EA00581F5D125
+:105DC0009E3B0FA2D857B411A01040F100FD19F569
+:105DD0009D81391EA8A2577FF9D8F82E03AC0994EB
+:105DE000E5603B7BFF003AC04473D90160F4C9DA37
+:105DF000790D78CBD98B7C80AC090EFDC652067725
+:105E0000B99EC0727688C1CDCA274A5FF08C62788D
+:105E10006CB8DE117653EBBB012601ACC4BE42EC7C
+:105E2000FDD884F8AE84B13C433ED4E662E5EC7222
+:105E3000A0FABEB1B1848BDA696A116B1700DE2E4D
+:105E400050B9B81EC601E468AE145CBC1EE19F2DBB
+:105E5000EA79CAADDFB361D307B21F4B4988F8585E
+:105E6000FF35EC7BA5E97BE5CCB7B0DF6C30B563E3
+:105E7000786CC37F14017C0E7CF9E7B0F3CFC26766
+:105E8000910E303D0F60727FFAA5E81623FE027076
+:105E9000BE78A1EF8FF8E0117CB8717AB2C1C1F081
+:105EA00056A73800F19E297FE4296374DC7C4A26DA
+:105EB0003A6C6E60FFC7BE6FAE73E8B152C2B3BE3C
+:105EC00088B51F29F0CC9BF8B2842C5AD7CACAEEE9
+:105ED000FE747687131ACA891A8E513F6EF66E08C1
+:105EE000932B77490FC9CDC81A464FA4CB031CEF9B
+:105EF00018FBEFE3B2143DDD063DA758E9E916F4BF
+:105F0000CCBBC74A47770DA3A31FBF5BE9A8E33FFC
+:105F100018BD1619742C80D144C7581ED177B0749F
+:105F2000CCB5D13160D031966C5050FE908E0CDEE5
+:105F3000AD9A03B259B9F735B72E23DD625A77907F
+:105F4000D5574563B586CBD16601D77AA4DF18FA59
+:105F5000E4700419BFAABA343E6F121296B3AB7440
+:105F600092772F23CB905294575552183D37563283
+:105F7000790D119C92A3A63F5CEC8FDA6F64F0A8B8
+:105F80002678367ABA3C122B6F63F0C624AC76388A
+:105F9000807269E0ED0E392CF45682593679E7703B
+:105FA0001AF06DD3F87C36C141EFA1BBAB436270F0
+:105FB0005E9CE1800DD2C0FD6EEDEBC7DABFBDDFA8
+:105FC00001E14B06BCE50CBF8B2FCAE10D8C3E1BDB
+:105FD000435D1D28E75BA7737CFBF3F90AC7EBE978
+:105FE000F1944F308D17EEF104D2EAB72B1C0772F3
+:105FF000AD78D504BC81AA2B1F07020B4622FF33C4
+:10600000F1E3AF067F88C16FA293B73C2061FFDE4A
+:10601000B10F7B80E6FD610FC2611FA71FBCB67187
+:10602000EDE32895314DA1924D1F057400937EA19B
+:106030003A217C727D921DB6EA196FA54DBF84ACE2
+:106040006545E81BC5A66F3EB0EBEB0983D4335A18
+:1060500023C11B12708198CFA3C47C9E762819F4AB
+:1060600030FA95EF32F4F5033FAF64F27040E8EB9D
+:10607000039D407AF64017D3D734AFB9BE1EC7414F
+:1060800083AA6FBEEC40FCF7F6E91B2B7DCAE2DA6F
+:1060900054D43BE5F1B003FB29DBC4F54D59478BE4
+:1060A00003F9344EE82D38CAE9E061FF99F5759996
+:1060B0001867D42E2B1DCB90BEAC5DD511DBFB1A1F
+:1060C000BEEE958189AE6CBCADF80F46AF6112A3F0
+:1060D000E367D8BF474305D171CA20D73D4147BBCD
+:1060E000BE2EC3B147313A3ECAF435C36F6480D384
+:1060F000B1BDC3010ED48FBB1CA41FC794461C584E
+:10610000CFD0DB0234A814F8EF13EB9D01E7A8070A
+:106110007A6A51B99743CF0937EB27771384132154
+:10612000D4D325B538CEE371AEA7CBE3E0889AECA3
+:10613000A15C01CFE3D37B5F1CC3EAF5C69530A217
+:10614000B91F420E4F698AAEC67A3B52C8E93F601A
+:106150002D931CDAF93852C8A59D3E6374ABFC96AA
+:106160003F6AE3C7266B79A44DAEEB0D7E18723DF6
+:10617000487EB81588B9F3B0AC937DE761342A60E6
+:1061800065F907CF6928D76A277F97DBE1D04B995C
+:10619000DCFADA7959E950F45A36EE6D6880B1F2DA
+:1061A000E818E86897CAD33548327A8F0E244066DB
+:1061B000EF474E87B06C9A2F869D69F06F94A0DFF1
+:1061C00028616FE43CD8EB45397F3CC0E88E7C7F8A
+:1061D0004011ED7BBC91B129BADBF5C3571AAC7401
+:1061E000BF39926DA1D7ACD0104B79FCA96197E46F
+:1061F00093A13F0C3932E8D68F0F312BDF7CD3AD22
+:10620000DFEDFAA74DB2E99F41F2C975122AD18E8E
+:1062100019E3C80AEF2DED5FEF61C921EC218F7EF4
+:10622000968DB70024C861FD2F87E408A4F7513587
+:1062300044DF5738928558BE003DDB878F4AF53FD3
+:106240004281A3520E53DA8CBCAB1848C33C90C8B1
+:1062500026BB18229E422201D14562FFBB95E44530
+:106260007120BD8A03FC3DC472142C07C1F80B5980
+:10627000ECC4A2552FFC5962F353124F19F9C8C64A
+:10628000774294E4C103712A6741173D55E8A6A7F8
+:106290001F7AE819808084CF3C08D313AED69F4A7A
+:1062A000901E7D2040F4F4FE0E3ECE4EE1B346F04B
+:1062B0006D1844BE2F4D443E24C023A7E4D02BE6E6
+:1062C00037B3D7482F7B2A99FC96A27FC0D6D52A10
+:1062D0009AFFDC9F99DE134379CE51615884BDDF6C
+:1062E000D81A20FDBCB9D543CF0EA16F4AAE796153
+:1062F000C71DEC9F8F8CAD79732F7B9E68DBAEA1A1
+:106300005DD33196EB97A1D3BBEB46A19D58AF70FF
+:10631000BBB09DDBAD39825A1DA393FA6A567FCB81
+:10632000DD9EB0797D31F4D096EB9307F7B1EF7A2B
+:106330004B167DD7A70B7BEC23C67FC30F42FA8594
+:1063400005DFEA136487B2F7311FABEFF990213F05
+:106350009E7D0FF6B4A6D33F1D6559A4FF3A4EAEFD
+:1063600087105BE7435A4C23BB760A33594BC9BEAF
+:1063700075C4AA70F6457F2531FAE6C40292A622BA
+:106380007D40C2761E740891BE4A3C68B657FBFA3F
+:106390001F1E0B2E64FDC5AE77850F90F88063DE5F
+:1063A000D8CC72BFBEEDDEAF6A69EC27BF4322FED8
+:1063B0009EBCBEB008FD5D17048AB227E03C72C1E6
+:1063C000015C9FAE5F3C329AA65D6A3E19F651FAB7
+:1063D00067A6766E195ABA4CFD963B1CA42FC1E1F4
+:1063E000A1676E09979750A5909B18687A1A3BF39E
+:1063F000F3027E8F128380B0A73F4D7ABD2D713896
+:10640000D74BD0D095061E1DE19988F3A02986FEB2
+:10641000404E1B9757A6B534AC1F52F8D3A87FA3A4
+:10642000A8FFA4C0E332F44DE1A3386FF307A9EF4E
+:1064300070DC34F884C5F89733EED651688C062C9E
+:1064400074B7F3B36F7C8797EA5DBC7E7B10FDE782
+:106450004C70865A58DDA1EC592F9E55E25949BA25
+:10646000BDDF7897DBDF144788F0B4F70BFBB9FD8D
+:106470009423D6A913935D34CF873F00229E62D523
+:106480001BC3991F89FA4D3FC8167809F5062F3F9F
+:10649000B61FC89EEABDE721B23B4B50AFCA18E712
+:1064A00088D23C2E8510950DFDB616F51D7B5E84B9
+:1064B000C82D8E02D42B5D27515FD64FB87B6ABAA8
+:1064C00078D11DC6FCB88CF5E8F3ECB9C013B9134C
+:1064D000FB57C3A735B66243EE5C29969DD37F5E1A
+:1064E00031F10CCE31CF873EB9E0F3A91DE5BD8A6D
+:1064F000CF9BD9AC5C579E1E4EBDED6291B0FB8622
+:10650000917FA3C0B039A6F9A83FC8E6156BF7B8CC
+:10651000E8CF78BF5DE017FB04F3A08E3D03615D1B
+:106520004375394F6F7122DF6E96A26B10EFB9F58C
+:1065300091E791F5EAC16E2D2B44EF3B1C6C9CBAA0
+:10654000501C3907AAD61DC3E763F72CD4908FBD22
+:106550004C67C969FC66E399A539AC7E92DDEF1BF7
+:10656000E47CBC3A1C9F8A765865C3891388EE0286
+:106570004F7427C23524F2945680F0864E6B7926EC
+:106580007E8D14FC5AE6E0F8E73E20F8A66841E468
+:10659000C75D10D98BED039AB0BB07094726F947B1
+:1065A0003B13E93812E59DE9CDF63093F7D2D47C60
+:1065B000C811F3A15DCC87DE095CFEDB03D58174D5
+:1065C000EB8521EF86FC1BFAD05E2FF109E4FC2A53
+:1065D000F6AC8000F9311721FADF900E0C7BB26B1C
+:1065E00072A777913F67CCABFAF0E9E943183EEA2E
+:1065F000845035D2DF18F7BC90BB051EEDE7241F91
+:10660000E56D4A1EC36BCC3D101EC5EACD2ACF9561
+:10661000CCF2FE6A5FFDC8699A5FF7746B4A68E066
+:1066200076FF43E077B31479CD2C87AC9F5F615937
+:106630000D75A384F5D13924EC7BB96D21D90F4CAC
+:106640003E0348E7792D2DCFE37873AB226BB0BEC4
+:10665000D1FFAC90CD6E97A26F61BF7639AD83B894
+:106660000297B17E8C94A217B09FFA5037C19B3B22
+:106670003D4272C6E0FEE05382FB2F48D74C70BF0C
+:10668000858D516F86F7905E63F0C9328363F403A2
+:1066900009258FE87E5A41BA333A3BE582149D07BB
+:1066A0003BCFB7897936D07C6FC77F4C46BB383A31
+:1066B00004C7CF13762E244F00F7AFAC71CA19F27E
+:1066C00079403B2BB72E09181F1A724A0EDFC83EBD
+:1066D0000DAD0309ED62C38ECD13F3D180674B9FDF
+:1066E0009D1CA4F933444D06232ACED74964B73DF7
+:1066F000529B0CA29FB7B63544DF033593D6DF110A
+:10670000C2E1A304C786D6B0B0AF6BE819AFEB3DCA
+:1067100085FB025B820EB27F37B5561A71598237FC
+:10672000CFB093EBCE909DDC1BCC127EA315BE7830
+:10673000DD19CBBE87D10E82A6385619F623ECEBB5
+:1067400010D73703B5574BAC74EF6BAF0DAE7DD69A
+:10675000046BFB5A2DD981F1C400C68F100FA1F72D
+:10676000FC02C6408D83FC6483DE9E2A6B1C2E5E79
+:10677000977E1FA76F5DB08D07E559A932068B6222
+:106780008D04DF4A015FA67ED6887895517666D063
+:10679000934DB25827C57E5440C0FA88C6E8A1A6DA
+:1067A000E83144C8DD967AEE874180C7E70C3FC7E1
+:1067B00009FC7B6A3C8E379549DFC7F83836F88D7F
+:1067C000F62ED13E131C2E7B7F67593F934CFDD88C
+:1067D000E0CC049F7D7F0CDEB6F693597FD9DA9D1D
+:1067E0001F1C1FFAB503133FA99C672B0FB3D52FAE
+:1067F000B37DBFDAF6BDDA56BECE567FAAADFC0534
+:106800005BFD39B6F2576DF517DABE2FB57D5F69BE
+:106810002BFF576BFDAABB3E197DFF3FA39331AF02
+:10682000FAD345B7ECEFDAE75519244624D8736F4D
+:10683000EE4B8BF1D3BFC892728EFB243C8E058940
+:106840007111933DFE7B357A06D7B1BD1F6959A8FA
+:10685000F7F7C75FF6A33E32DE9F97DEF05F156263
+:106860007AC19558C1E33E719A3759A09C49562286
+:1068700097248A9779D44544724F397B6FD26F6ED3
+:1068800088109F5D25D6F710E7F3B01C7D7AD65FA0
+:106890006C9B8BECC15811E8A3315E94CFFBA7FA37
+:1068A000652978AB15AE9F8291782DCEE1610D5DA3
+:1068B00027F069A753705AECDA1730DEF008F7CBEF
+:1068C000F7CFB0FAD5B728DC0FB94DB96CBFE0D51A
+:1068D000F172AAFFFD0FAAE13656653F02C1CAB1A7
+:1068E000073D3AC63746605C8E6F1A505C6E38883A
+:1068F0003F117F2BC17FB376C3D55314670B350689
+:106900004EA2CE9BA354D0788F4B3D57E1788EECAE
+:10691000F3D7F2FDBCBF7C4CF17741AFE0C649C96B
+:1069200018A3176C758547139DC34467B702EDEE36
+:106930006A14134EDFD5ECB578AFF8F2D06D12FCC7
+:1069400040FD3B0AF7B575E0FE6482CA3E48523905
+:1069500047D8B9639452EE17083F9379F612FA5F5D
+:10696000C12F32BF3CCDFA315BAA1DA314A4E29320
+:106970005288C721A54D2FFC59C278572584F8FEAF
+:10698000948807AE97A58F311E1E18DCFE4EF06B63
+:1069900056BE821285D92679FE5A1F3F39BD46055B
+:1069A00039FEC1ADAE16F46BF6CFB2CA81515F5657
+:1069B0002E3B5EB17DDCA84F4F0E729551044F7F88
+:1069C00039B83580FB07528CD12D7BF074CB91B553
+:1069D000AF2A13114FA0F22149BB5529489515D074
+:1069E000E69BBFBF2A4716E0F7D854A86C5153FD69
+:1069F000B0F78B32BC5F92EE7DA961B79EE5EB7874
+:106A0000B1B0AF86B6C7C92E2D6ACACB32DB59C525
+:106A1000625DD8D3B4D08BF86E6F48AF078DE74670
+:106A2000E1F765AAA74A5D11D42B3056810369ECC2
+:106A3000F26751BE4DFA54ADB2DA5BD317C56AB1F5
+:106A4000BDBFCE01B86FC2D679B2EF8A842E7B78F3
+:106A50004A4CC2BC97F872083FC4F0F22F2AF3A642
+:106A6000B3931ED6B6D3FB1DF5876791DFC2EC3A10
+:106A700099E2E25DEBB13CA4C6011BD2EC173C21CC
+:106A8000F0DB5CCFE964FF5EE18268BA79F8AC22A2
+:106A9000F61994980485A9FD92274E147DA192C100
+:106AA0005B1C7684BDA1149CA57D765382E855516C
+:106AB000AD0430DF80297E8BBDB9A3BD7AC71D68C8
+:106AC000B7B3F768B7EFBC3E300CD78D3DB515B303
+:106AD0001A517FDFE980D1A1141C633AADF43CD197
+:106AE000373FADE3B27E6BC97FAA67E44A43872B89
+:106AF000A547A71837939CD8D755BB1C5CCEFA7016
+:106B0000937CE5F8FD00E7E144921F8AD30CAD6762
+:106B10007E5C556A1E197E8A5DCE02750B49CEB623
+:106B2000D7977911CFDEBA6AC9C5EA6DC19A69FCF7
+:106B30007163BC4CF05438A3DE00CDC385523ABA21
+:106B40001546D3C7CF35A7883F2B5109DB67AA3736
+:106B5000C229E441CCAB4231AF82535AE6D0BCD813
+:106B6000A5C0438C5E0FD755B78D26FA3948EEA6DF
+:106B70006B5CCF164EE0FB993E46AF67D9BAF7483B
+:106B8000038413ECFD23135C96FD9942411FBB3C2B
+:106B90003E32807E01B3FFC5E45F71AA7CFFB61C64
+:106BA000CAD19E7AB8EED2ED074BDF608343D39112
+:106BB000BF35D503C44DDA2E779D9A773DCA63CD94
+:106BC00020F3276CFA029EBB6BFD68C607DF2EA67A
+:106BD0002F201D7D5C167F7C207AD8E93F0EE99935
+:106BE000FDE9D1D3FE7D8853C40107498F27EBCB44
+:106BF000B6968732D7B7E363B4DB28E6DBE7A14775
+:106C0000C6F9AF4180E24B53214CCFE910A167B7E1
+:106C100012FD9293D59F092D5436E2508D0ADF97CD
+:106C2000802A3EAEB1BFAD4C03B293C78C077D2F17
+:106C3000EAE72973C4A6AFA29DF3A0D1C6E048E35A
+:106C400057013C447817DBD663234E31B4295E5F8D
+:106C5000CDFA2DAE77501CA3B8E6B0D7BC2EFBC53D
+:106C6000FC31FADBC9BEE3FABCB36970FC32EA3D21
+:106C7000A12429AFEB899A87DA70B951F2DE0EA60A
+:106C80006B6FA7EB968FBABC9134F0EC5C7494F206
+:106C9000B776D65C3A8E3290DC8C91D3DBB39F779B
+:106CA0007B896E3B733DB7F0E49C5596FC0390D511
+:106CB00052F3B83B3F82DCC8A5F489669D2F5B9CEC
+:106CC000221FC4073E94FF4CF4309E9F361D9E9CAD
+:106CD000DAB23492A67D859BDB136B722186F92292
+:106CE0004FBEAEE898DFC00496E471D22D211DEDB1
+:106CF00097355EAE979FAC05FA3E29577C7F2C44B2
+:106D0000F954C59D1073B1F5ACF8B5458FE4B27A6E
+:106D10009B16310FB234F57E53F86407EE133FF340
+:106D20008A2380F6D1246FC2136678D5887570E700
+:106D3000A29394771CDBA58447937E97409A44DE08
+:106D4000BC25AE79DCA910BC3BC30F7B716F6E47CD
+:106D50002849FD7C63F2494F88E1B7A9A4DB837819
+:106D60006EAE7998D6CBC38BCABE5C4164B5E6974C
+:106D7000CC94A7746B98BFBB88EF5BE426BB3D98AF
+:106D80009FE46F50E046069F5FE5F86E5A033AAE07
+:106D900053D5228F4482D9E41717D9F2B80A6D79F6
+:106DA0002681F0CC77709F9FF6FF1109B9E991B168
+:106DB000184F6C7688F4538DE6A94FE0E70B6B54BF
+:106DC0007FA67CCC8B790B3BDA9500AE7F015BBF55
+:106DD000763C02103DA149D40F8DB3E351BE4E065F
+:106DE000265266316B2AE00E30B887B021DBAD70D9
+:106DF0001B74B58FE3B395DF36E4B91846A31E3292
+:106E0000E2CE06FC76B9CD9FA41F7999E1BBF315BC
+:106E100095D6EB9D352F7FAD19D7F94A37E5717DB2
+:106E2000E1E2C1A6EFB3E72F3E385A8ECF2F16ED21
+:106E30009FD08C74107912463CAF107B26FB55E82E
+:106E40003563BCAA3DEDCE7C7A45F9159B4FBEDE7D
+:106E50008871E7A22620FBB748E1F2E96B77E86D7D
+:106E60000CFEFCEBE2240FC50D09025A6DE892629C
+:106E7000267B5E15F69CAF292AE13EFE8D0D712F13
+:106E8000E68BF844FCD737214E76D20CF90D4F52E1
+:106E90004DF1CFC87F37E69F9D3F158B78DE497156
+:106EA000BB1246B08B9B5A1C6487D7F07CEF8ACE0E
+:106EB0002E89FB7F3C9F9E87D4D933D2C8F30977B4
+:106EC000713BDDC8FFF63759F917E8CB9F8FD2BE6B
+:106ED0006B69A7ED7BA4EE2D2E87567E96B9043FF5
+:106EE0002B44FEA0CD4FDBDC24F6E9548F7E29BB7A
+:106EF000F6159187F32AE23FA6FFF79B33E8DF9B65
+:106F0000DC7C9F5F767477901F779D83FC383B1CF9
+:106F10005B9AB8DEDBEF7258ECF82B1DFF36A1FF51
+:106F20006547F26F327E531FFE7F9BF1EFFF1B8F91
+:106F3000BFE16F4CFF1D7F63FC0FFE07E33FAF52C5
+:106F4000B2F8697B5D1EEAEF87EEBEBC0D8BFE9644
+:106F50001DE9FDED332E87258FD8C84B9CD6A02D7B
+:106F600070A1BE0CF3731EF6FE66C82F75A01EDC62
+:106F700021F2B1991ED564CC779A6C9CD3E0FAAF1C
+:106F80004EE8BF3AA1FF0E67D0ABD5355CBF33FBEF
+:106F9000420F95E292119F5581EBF72985F28B0FF5
+:106FA000035B6650AF85DC69F3B10B05DC767D5A77
+:106FB00028F469F54BB6F7428FDAD7F9D2BEF82933
+:106FC00050FCF4BFBB447EA94DAF1A74D851C3ED39
+:106FD000E5FC39E9EDC14D363EAA135A280FC1CE62
+:106FE0008F332EEE5F1BFC58E0D17EED2AC8CCEF2C
+:106FF000A4E0F70D82DFBF7405E869E48D64E277F1
+:107000008D9B8FF359DFD9601B6213A9253EC8827F
+:107010004F326CEAA6F82F7C03CCFEE5968F981DC4
+:1070200082EBBFAA52FCECB3F9E03092ED3F32F6AE
+:10703000E9D89FB39BC751E57C97CDDFB2DBC11E7A
+:10704000CA8FDBA9F1F3563B6BF6EE5C81EBD32BD9
+:107050007C9F79676EE74B78F40DE2E31584C3B04B
+:107060001B41C467D1A4E0F928F6FD27ABDDBFF3CF
+:10707000A3AE04DA5F815229CC3C2BE8083D9C9FEB
+:10708000F63C9ECDDE57DD3E8BBF0B370ECE6E5FDE
+:107090002DF8CDFCC502B7697EAFF6CD1CCFF3A2AB
+:1070A000A607709F47D2663A309E9EA91F8CF49E19
+:1070B00033ED3B352ADA70EC4F42FFB132E53F0247
+:1070C00094F0F8BC81FF60CF0D34DDC5F7BF055DDE
+:1070D000F3AFEBFAABF891469CD7A8A72A094877FB
+:1070E0003EC81EB7BBD1A94D46FC060BFF6E143837
+:1070F000F6FCE72AB92E5DFC2029F4AB1A79EAC523
+:107100009B59D50973251EDF67669B795F6D53BE5A
+:1071100052972EDEF533314F7E894139D2EB09C8C3
+:107120009328AF04102F633EDAC7BF568C7BED1552
+:107130008EFF8A98D7D78A790D10A6FD984CE3D692
+:107140000ABD613C3FE9B8498177AD4BC4350618AB
+:1071500077B6C073F615E27B5E8C3B7B90F82E1001
+:10716000E32DB8C2713F14E32E18E4B8770BFADEB2
+:107170007D8574563C92E86770746E13E3B55DE1EB
+:10718000B801316EDB20C7DD26E8BBED0AE95C22E1
+:10719000C6DD66A373A6F9BBF70AC7ABF4F0F9B373
+:1071A0005FCC5FBB5E33C6578B1C116CBF3368ED81
+:1071B000E78B6E3EBEF184C4C7E4BF168B7DDDC98C
+:1071C0002BEE5DA8A519D7A86F5F8F338DF335110E
+:1071D000AF319EC6387EB11F3AF93A364E1AFA18C8
+:1071E000F5AF75713D98A9FFA5029EA597898751B6
+:1071F000BF16FB9F98B9FFFB041CF7D9E01FA87FBF
+:10720000A3FEEC01E0EF1070745C26FC46FD050364
+:10721000F4FF2D01C7B72E137EA3FEDD03D0E709CF
+:1072200001C7139709BF51BF6D80FE9F16703C7D4B
+:1072300099F01BF5B70D409FE7041CCF5D26FC4677
+:10724000FDFD7DF3DD3AFF54E33C50182A31DF7831
+:10725000046485E97E8370F204FA01EA2A7EBF01A4
+:1072600074D9CF4199CE4FB1297EE2BE8A18D6DFBC
+:107270007D178FFBEDBE16C88FD85D20F295455C5B
+:107280004B15F6E0EE6B791C647790E7EF832D5E8B
+:10729000B49BF93BB4EF5BC2F399D5AA3899983403
+:1072A0005CA13011439857C3CF5319F69E71AE6A53
+:1072B000B58853EDD680E254BBAB7879E774D01D26
+:1072C000A5A6F3569509CA4345C316E3B1A9F362CF
+:1072D0001AACAA36E563AC4A50BE8122F246184188
+:1072E000C09297613BA765DCA37073589B816AAE1F
+:1072F0007402DFCF2B8D58FD87263CBCC5EAFF56B4
+:10730000E8C900D64BA3670E7914CE3F91B7395721
+:10731000E06FD0AD5AF073CBEC0FBAA7313C5F9C55
+:10732000E2C44C1678F194A0E31459E7FBE7E0348B
+:10733000EBED3E39CFE00FAA9D2D27BD8C3E37BF28
+:10734000046164A36F97B6264471B58F48FE28AEDA
+:10735000C6C6BD79575C41F99BD5199A86F1C0B96B
+:107360002F8556AB987FDD09610DC9FBD1D7A99F49
+:10737000BC7608EB9C556D01B2736DF139E3BCAF7F
+:1073800088CF61B8DAEC5FCE127857B707D6E0D66F
+:107390005DF574B7C57E9D25FCCC2F696EEB394930
+:1073A00071EE7196CDCFECF458E3756A676406C64A
+:1073B000BFE5B9A7353CF73C26220586B2CFB745D5
+:1073C000B629189F9CB5AB85E7F567B80F23E7B1E1
+:1073D000393EB3FD3E46C8F32F775DDA5E37E20CE7
+:1073E00046DCE114E619BBD14F0F0ABE70B932E496
+:1073F000236FAE6491934E0FD7239D1E1EC7FF4F80
+:1074000039F9EBCAC96F3CD6F843277E63F3B12242
+:107410009C7E9FBED1E3FACFF9FA29F0C1EF4DCFA0
+:107420000768CAB1E4131B795576BA19F7C618650F
+:107430000FA43F8F57E215EBACDDAF7F235A8B785B
+:1074400019711A80FB6DFB9B53C2978A4BC8C6BD4E
+:10745000038E3764C4A7D22BF48F020AF56FC3835F
+:10746000E67D61EA3E1D7B7F6BC4791E032F677941
+:1074700044C37B56D818B4DF8779EB87AB707D0C9B
+:1074800058F0D6BC7CBDD950C9E56D43A5A2679321
+:10749000BC45ADF71695EFF5A4B32B8C2798EFAB51
+:1074A00028EB0FAFAB3C1A33C3E312F0D8FB999330
+:1074B000119E464BFCEB72E1715F05D08D72AB30D3
+:1074C0002926F9FDBAA53F47A54EE7FA33F58367AC
+:1074D00064082F1B5F328DEF29B19E5770E5675905
+:1074E000E45D51F36CF78AD8E4AB2F2E34B8F1EC9D
+:1074F000E718DBC5F9147B7BAF1287701ABA7B43A0
+:10750000F67C0C9DF8603F5FE30CD8E0B6F5BF0950
+:10751000DFA5C9F730EE195A27D6B5F58A4EF656CB
+:107520008C8189F99E6B845C2A019DEE67FAA657CF
+:107530004A8B3F84D3AFB74A797AF83D2556BABB18
+:10754000F2F3AC7C50D29FE7586FCCFBC07ECD7C71
+:10755000BF56FF797E2C7CA9F5BCEF5E2DE937F292
+:10756000C70CA5035EDB3D1683E4AFF2E11080217A
+:10757000A632D3AB18AF657384F279EDF54F1BF4E7
+:107580007B632FC16FE8E9EC5D465EED27C3439254
+:1075900040EC935BDB679C8742CFC942AE9F1F00E4
+:1075A000FF4CFCCD2A77D8E6CBE0F8EBC5798FEB22
+:1075B0009EA2894BB0ACF33ED37810E0F85EEEBCEF
+:1075C000FFA4700EA98B02EA3357300A51B6CE17CA
+:1075D00005E3B44FAE4A3D31F4C7D89C0A219F77EA
+:1075E0000E09F1F3E3A67A53593B67A923E6C43C9D
+:1075F00010089FC0FAB12074617D8CC7ECAD4AD5EC
+:10760000532588A0BCAB054A04DF1BFDE54CB1F651
+:10761000C7CC04D97C1ECBC817205787E1EF9CCC80
+:10762000FC53D6DEC5ECD03DE9F44916B743B39F11
+:10763000F3D279435F44D551248B26E894175CD468
+:107640000861F4E72A3ABB21CA3AFD26C23111BFCC
+:10765000C7E9DE85A25D71DAB7CF77F373EC454DEC
+:10766000716981699CCA2C2EDF53E778689DF87A8E
+:107670002DBFDFA23BB8305E8BE3D5F07D2F5FBE20
+:1076800002C3183D7CAFB9B9FF392109E67B23DE7F
+:107690006E85EA45A301DE6DF5D0F37C6B809E819B
+:1076A0008FFE279DE75B33715208F3472FFA1A4785
+:1076B000E2BAF17E6B90BE6F7E301CC27C22F9E490
+:1076C000EB749F444ADE6332D430BA4D486AC83FF7
+:1076D00013FE7BBDA67DFE3EBC18BE0BD8381B2515
+:1076E000C7ED381E9617929C7A649729FFC325FC34
+:1076F00046E71A883C5585F797E8D2DD55A6F75E30
+:1077000066B7E1FA3A31407C4FD1536F13F4BE169D
+:10771000FDDDA297045DE7D45C72DF64536BA27B4E
+:10772000FAE85459CD70EE6DB673EA0D591837C2A8
+:10773000439F6CBC69732A8722BD1E755ACF931B69
+:107740004F39303E5C8E7563450E9A87E27E959583
+:10775000578586E69AFA9F2DE4523EF923A26F766A
+:1077600015CF0F617FF545A6FCFF926823BFC7AF19
+:10777000859F9331F62147DE9A6CC32D8991ABAC7E
+:10778000E767668AFB504AD73828FFB57432E9505C
+:10779000286D03CAB3DA2787AB51BE1F835772F136
+:1077A000007B09836F389BAAA5316B3FFB16D7BFBF
+:1077B000807100E37E95D5EDBCBF11A1F0A910C684
+:1077C0004FAA1C642F8F84B007FB1FA93A00CF1764
+:1077D0008D02533FAC3CBCC5DAAF1DDE529FC38166
+:1077E000F10E039E1170C4A3E553FFA0B3F625CCA0
+:1077F000CD2B4E039F7D9C5146BDB1D5D509483355
+:107800002EF4B4E1BE50BFF107E8B7354BD8E13EE6
+:10781000F0A33EDF2571FC632FCAE103C8D7BB0F7D
+:1078200052BCA6646527ADEB9D59DCBE5BCBEC0179
+:10783000D589760A7B8ECE2C877280112E87D68FC3
+:10784000B4F2F76456EDD62C8C87654DDD8A7298BC
+:10785000A584BE82FCC83AE504DCC7CCD2E234FF82
+:10786000A09CDB191BABCA7270BE65B5B8D2FA6BAF
+:10787000ED594E826F5796A4605E28932DC24B69D6
+:107880000A7D6B262B7617688FE3387F2E88D2D33C
+:10789000781F5CD81042F99CB6A48AE25FBD9D12A5
+:1078A000C5BFDE927417A66A2F9BDB32EE46468F69
+:1078B000D9B9D127B0DD1239B1D6C9E0597E6B4BA9
+:1078C00005D2A71EF3FD0A70B818F7074BCE841532
+:1078D0003C1756A2249C4CBE3D8193AFF167AC1679
+:1078E000E5DD832761183FFDE5DA3BE837F9C43968
+:1078F00024197A629817E89F0270C6C437F4E9CC5D
+:1079000065DCD3359733D17FA0E722D6F6CC685C0F
+:10791000E5C39A4476814EF47305C2E3104E39787C
+:10792000AAB0DCB4CEB9057EEE690BC5FD489AF06D
+:107930006FC260F66FDD022FD4E1674CED9D416BA5
+:10794000590EFC75F130EC6EE9A7FF7E0EF9B8FA1E
+:107950006927C53DA73DED4CDCC0CACBF748B4CE86
+:10796000388E73BDFEFE7E89E67DC2E7223DF05E65
+:10797000C043E56677F796CFB172CFD332EC25B22C
+:1079800034D07D52E78CF5F4282F2F160ED2F23D1D
+:1079900027E6637F8D47DD80EBC4F21F2DB9E973C5
+:1079A000ACBC84C93156597EA0CD358C95EFD2A59B
+:1079B0002E2C5F980A2467B13C978E792D17FCDD39
+:1079C0008537ABB48E41680CEE6F7717CE65F2B891
+:1079D000547F6A26B65B7A48C2482AC3E3C00B4587
+:1079E0000CAEE5DF91687D5C76309BDFBD22E877E9
+:1079F0008EA17203FBBE92E189FA7009C46722BFAF
+:107A0000961FD8E632AF73EFB65652EA87515EFE44
+:107A10001D360E6BB7E27B5218515C81F90EB85ED1
+:107A2000FEC8DBB04F45FCDA5C153EC46B9D0BEB2A
+:107A30002DD1173CE30D217C7B5C33D9F7A5BBF638
+:107A4000B8165721DDE0765C57971DFC0CBFB3C01C
+:107A500080AB53267F6165AE672FDD6BAADAEE47F8
+:107A6000E9830B2C702D157A83F97D2EF379B76796
+:107A7000B273494E971D942DE318FC8F9D067E1E10
+:107A8000ED273E3A8F66F0CF58AF0CFEAD342EFA9C
+:107A9000537A26A583670BF283C11367FE0D3E1F41
+:107AA0006E0DD2F3D1D610F1693BD2710CCF4BC120
+:107AB000F76CDED6E23D687E0D2F0403C8ABD76AB3
+:107AC000310F332FC2CB85B746A5D025EC74E3B96F
+:107AD000DD195D8046CE94EC6FCF50983FB6DD1532
+:107AE000BD1B43D60165EF8CE96CCD6BCA8E4CCAC9
+:107AF00036EDFBAD15F7275D931D22FCD716B9882F
+:107B0000DEDB6F9BB44FC49F689DDC7EDBE22730D9
+:107B10003ECEDA7F3E1BFD0BB1FF97A97DE1FC1A3B
+:107B20004BFBC2F98D46FB99D4DE73E9F6DBE75FC8
+:107B3000671D7FFE52A3FD4D04BF7A69F80B6F9F4E
+:107B4000621DFFF6266ADFECE6FCEDC9F550BE7556
+:107B5000BB379C407D4C17A94DC07CF28ABD58CFE5
+:107B6000587798E6D7307F5B3D945BBD01CC72348B
+:107B7000753EC28179596639CAA9C9B2CCAB5C2DB0
+:107B8000CF521E5237CC52BF205266F93EB4E16A42
+:107B90009B5CAA747E91CA08141AE60C4ED7301763
+:107BA000E9A3DA61DC0EBEF7B897CAF75EC7F1BB8E
+:107BB00077984AF3186146BFFC5E57F41AF3BDADDF
+:107BC0000C2F093773EE54A3F7211EA9F72107BE26
+:107BD000CF12F94E596E207DB7AE74D2BE98899EF1
+:107BE0001DC3993CB0727BB68BD35DF061DDF0C5EF
+:107BF00041B3BDBE76B8AB01FD0D7C7F878AE345FE
+:107C0000D6E278CDAE9E0AB43BECE3B8CB6A2CE367
+:107C1000784634D238DBB2793CD518C73DA2D1368C
+:107C20008EA761AF782FC67904E52CD338EBCAAEA6
+:107C3000B3E23362298DB3DB36CEBA114B6DE36408
+:107C4000717CD87B318E7EA971DCA3A658F119D93D
+:107C500044E3FC931D9F914DB671541A07DFE3383E
+:107C6000CCF00DE17D592E77CF62E2FF4FBD64E786
+:107C7000B8DCD127C9CEF9B597EC1C564BC37A5066
+:107C8000C9FDDB7BB2F3F8BD5F598CFFAA99CF31F8
+:107C900091771023BFF84E0122E80C22A6DF560888
+:107CA000195C7468F688367C1E9D165C80FEE8A31D
+:107CB0003E8AE3BD7F749AEB8E34FAE8CEB8F35C6B
+:107CC000D224CF7D7A55C46383D97C1FD2289F13D9
+:107CD000F19F33182762CFB79C40FED059112F4A2D
+:107CE000C1DB46EDCE897DBD73BBF83A7571DB69AA
+:107CF00027BF37155EA96270CF1368DC19B7DE9312
+:107D0000D92CF8D1F323373F07045A31DD8FD73907
+:107D1000C4122FFCCDF17F7881E7DD4131DEF7FB26
+:107D2000D58EA79EC76AAF4A0B86AF64F8361CD9BA
+:107D3000E62C66E5F79DC9F961D5D44F8393CEDF74
+:107D40001B7EC82D51A7C57EFE5AA3B57C9BCD9E38
+:107D50007E23BBCCD89FE5E3867427F26B1EEEB181
+:107D60003216DE864F4ABE0B10BFE607785B039ED5
+:107D7000E6FB9D90A0F52E594071CE5801C569A231
+:107D8000C6BA65836FBED3A345183FE7DF27131D2F
+:107D9000EDF0268F676B0EE6E7243BFF9713CFF1DC
+:107DA0000C04FFEDABACDF21E6B4DC4760C8C15783
+:107DB0001A6AF79D35C9C72DD159FBCE5AE834DB75
+:107DC00052BEADE5164BFDDB572DB07C5F10BBCB33
+:107DD000F2FD8E8EBB2DE53BE3F759EA2FE96CB33C
+:107DE0007CBF4B5F6FF9BEECE0364B7979D70E4B19
+:107DF000FDE6A37B2CDF1DC7AFFA12F981BF94E922
+:107E0000BCF31FD5735BD07EFB6340A1FD9CB7C55F
+:107E1000FEDDBBE23EA015287B9371FE8CF7A0DF50
+:107E2000D09CC5E633B325C6A9056B3BA6A01E01B1
+:107E3000BA5AA35A2D5E1B63CEEE64713E51EE74A6
+:107E40004162086EAFA4E2B03D72EABB9264DFC744
+:107E500067FE2E772A69BF2B49256DBF17A49E0A9E
+:107E6000B41F63AFBBD39E034FCD4B28864BDC2F93
+:107E700079DE018D66FF6D9ECAE3432F644F9DA797
+:107E800016D071699AEF4D878BA6A2DFD0E44A54D1
+:107E9000A4DBB7E91BAF4BA27B03E7A97CBEDCA543
+:107EA000175BE269CB0E8EB2CCFBD7B2A237ABAC7C
+:107EB000DEF91332E959483C37E2CB63717C6D1E21
+:107EC000BE87A305B43EBEDAAAED3BCBFC80D75AF1
+:107ED000EBE8F9ABD6C8BEB3CC257CA3B581CABF4D
+:107EE0006D8DD233D9DA48CF33AD2DF4FD6CEB2A4A
+:107EF0002A9F6B8DD1F3EDD60E7ABEDB1AA7EFE782
+:107F00005B3BA9FC7EAB4E4F631E18F62E44843DAE
+:107F1000D9F78309BCDC2B70900B8D386698EE95F1
+:107F2000EA552F56A01DDDFB9A9BF26E33D1C92E68
+:107F30007799F9A7D17ABF58B7C6998DA7378BF330
+:107F4000C7EB803ACC91583FDA4571B4AC9F7E863E
+:107F5000EC71F65E017ECF7278769AFB3ED1FF46D9
+:107F60007E0DC427A3FEB96FFFDBA48555C89F32E1
+:107F70007EEFD773720BE7DBBEF097C70E4C3FB2B4
+:107F8000F98AFAD351FAE96F46607CEABD02839E12
+:107F9000DD2330B8A5A8911D2887BD47DC8457EFA5
+:107FA000B16C9E8F8241B541E4BF2E3BE8D5CDFA3E
+:107FB000617957AE6ED51745BA595FF49EDAE7C7B7
+:107FC00079BF3228EB67C7A37C68423EB8DC19FD55
+:107FD0002FEF2AD5554B3FD6726F5CAAA37B202189
+:107FE0009433F712F7A7AE0CBA689C770F8EA2FCF9
+:107FF00003E627EA6779BC53E7E30675B35C36AD61
+:10800000CAD6CF0E49C197A9DFBF367C0047E077BB
+:108010009ECCE771077A82F2AF2EBAE7ED98F32291
+:10802000AE3B6EF6BF8F295F48A1B2D16F73971C2C
+:1080300073E3795E3864198FB50B193EBAF9FE9C6B
+:10804000FE7CB7E683FF166589D66D7EBE3C8AE767
+:10805000CB597F1714B543BA2675BEBC59C8E57213
+:108060004FD21565AFDE3B32EA92F920EFB69E0A99
+:1080700028A3318F20EE4267A4B1EBAAE9A81FDF45
+:108080003BB2BA10E369CBE4DE7BD39D9BFD50E5A8
+:108090007136D09D3D49133E467C0680F5EB49C1C3
+:1080A0008F927ECE54B6EB6BE3E9F0F1B8FB8A43D6
+:1080B000A7677E8EC1BFE2E8072E84E3A81A75F891
+:1080C0004CF84BE27CFDD2836FBA10BFB79DB18AEA
+:1080D000FB2FA1A7FAC3A9062DFBA131E8C679BCE5
+:1080E00090FFF602CAD3577ECDA6E63BBF7002FED4
+:1080F0009E83B15F619C7B5804113FD26BE1916517
+:10810000141F7EE7992F0A7B2E3E09E5E33D70D4CC
+:10811000217EEFC1CBFEF126FA95FBB81F031DDCD3
+:108120008E31CE05327BD662D72CE9B49617C39C2C
+:1081300042D41B8B1F75822EE1FD9FA67B9818DE13
+:10814000F93E6EEF2E8196B568CF296EEE1F2C0C8E
+:108150008052CCF4E9F21F3E3609EDFECFF8F8BEAE
+:10816000A311C7B82B8FDB7B4BF37517EE27FCEE03
+:10817000C8F8799F43E973EB6B715D869CF4FB7FD4
+:10818000777458E11B087E3BBCC6B9F77EF1140139
+:10819000877C504A9B9F36D927E44EE891877C56CE
+:1081A0003B7F9DAD5CEF1371561964E4F37B014F87
+:1081B000CC9143DFE99C6DECB03BBC3A84F76A4557
+:1081C00022285FCC2E1807A67ABF57A3F4FEBCF472
+:1081D000D2623A67AE24C6513E9E07284FD125E4AD
+:1081E00041CEF28F836B304EDA424EFD6AAF7F2F65
+:1081F00096D7FAF839A8669CA7ACBFCDFE99A730F0
+:10820000AEEF8178422BC5FD6F6BFCDB1BB296B3E2
+:10821000713EA13EC117C88F3050BC28BBD25ACF87
+:1082200017B69697F6D129219BCF7DF83D6A027F3C
+:10823000AF026A94F366BB798587C30F78AF2AAB28
+:108240007F8FB0E757402846798B412E07F7CCE265
+:108250007913F7F842E118FB2E291A9D8F58874DA4
+:108260004DEB58F38712E826BDDEACF4B8502E9BD8
+:108270003F54E8FD6E35FA20D2D5051AD9B91E460D
+:1082800034DCBF56D43A8BDD0B25E27E405BFEC268
+:10829000265FC0E2EF197AC129F422D317EB7C05DF
+:1082A000A8077B66F27DF5A48BEFEFF07AAE54BDA4
+:1082B0004D0847A67ADE54BD6DE9EA2DFFE1779FB0
+:1082C00089B1F9BEF4FBDFF4E366DA3B4ABC10F394
+:1082D0001F9A0EACF1A31CBFADC4FC88F73B7AFA21
+:1082E000BCF79F097D87F94E785E7E85E0D3BBFFA2
+:1082F000B8F126A4FBC5034E3A6FDF7CD09D7033E6
+:1083000026AE38721797A783EE3779791DFDFE48A0
+:10831000F351EB7C5BFAE4370B43B4B9172B16F738
+:10832000B393FDBC62FFEF67A23DD20C3DA427ECE6
+:10833000ED70FC0FF368FD5A80E7FEEDDF8D7CAB3E
+:108340006621F7CD4736525E55F391599447D56C67
+:108350009BE78DC20F39EAB3FE6E83410FD0B95D42
+:10836000BCFA3BDF1AF72683E7FCFE5FF8254BFCDF
+:1083700088EB89DEAE3B1E7F369459BFBF2FFCFAD7
+:10838000543B9DDFFF7D94DBF1708C3F9B9C093F4C
+:10839000FA4D4D7B9C61A641A0E9BBFB9EF836CA15
+:1083A000F7EB6E8A372CFBEEF3AF5EC7CACB9E723B
+:1083B000E6D7733454CC0336F88267DC315FD7E0FC
+:1083C000C3D21F3CEF0A8DE5EF1FC84BF163D953B1
+:1083D000275C30B63FFDA6759D70F1F3E736BE749D
+:1083E000BD3913EDEED5DFF9930BE7D73BC7251861
+:1083F0005ADABF7DE39EE7C9AE433A111F059FFAE3
+:10840000F8D68F5F899B9E9D40F502B88E0DC4AF54
+:108410006FA3CC14905C7FEF59DC2FF8953B8C74E4
+:1084200068FCDED7FD88CF5B4A0B97EFC7D614E216
+:108430003E7AA3335618A0277FDFB8FB1B24774B67
+:108440004E7FA390E7416945FCF78C62451407DC39
+:108450007533E1B918A2247F8D8FC99487FE470533
+:10846000EA9E4A333F6EF0733DF6D65E375D7EF787
+:10847000162A5CF4175F96757EDE96E7257EC3D8D4
+:10848000F7C0FB1B59F98F1ECEAF02BFC3B8D7CAC6
+:108490006391DBFDEBBA914FEF0ED78662BC92D1B0
+:1084A0002126E826A11E924FCF18CAF90421659211
+:1084B00068C7F4E4347C8FF5BB9D9A779CA59D58E2
+:1084C000D7F8F8F788F119DC59689FBD55C8EC9DBD
+:1084D00034F82DF31BF39FD91F263933CD733EEFAC
+:1084E000F7AFE7F3DC98F7FAEC3AFCFEAFAFF079C0
+:1084F00084ED709D67702586D2F7137325D20B6EBD
+:1085000048A49BDFFB9D627E5BBF33AF9CEC5B436B
+:108510004E18FC0AAE5B2979E1FBBC8C0F64BF2DC1
+:108520007E94B537DBE7382ED573A5DE9BD6FB25C9
+:10853000421F5CE7B7FD8ECBAE8241DDFBD3E4D4B6
+:108540009FF836CE5F365F71FD69FAAE93F244FE56
+:1085500070E8B957BFCAE4FC0F5DC6BCB5EA53FB6F
+:10856000BC6D3C3C11D2CDDB3FA861483B6FD9FBD1
+:10857000B4F3564D923CFF47E953837E0BFDD63C46
+:1085800027433F66A2A35D3FFEC517227ADAF52393
+:10859000FB7B0526F5974343FE0CB95BFA4FCBE90D
+:1085A0007742FAE4D390BF3EF934E4CF8EAF957EA4
+:1085B000F6EF9F4143C58817B3A7F32188F9309E92
+:1085C000FA1399E2A917184C6B199F2F1C2AA5734F
+:1085D000C46BBCDC3FBF10E8F1E755D13D3854EE29
+:1085E0002970AD457D61BCEFF1F2F8F785488FDF6A
+:1085F0009C07F2E631D98FFB5D491DEAD2F9234C85
+:1086000023131C49C8F49DC78B2FA0FD87E3658DFC
+:10861000D0916F336475C42AF4F3E3FCBCFCA2B6BA
+:10862000AFF8711FFEC2B1515B517FDDF9A20CE2C0
+:10863000F71315CC37B943F0FF6D886D9FC2F0BCBE
+:10864000E318F72B166D4A2F2F4B45FDC5EA3D2E3B
+:10865000D44BCC2F38638E872F15BF4BD6B8CBF6B3
+:10866000FED81749AE96DAE42A2AFCC6EF1A7275CC
+:108670002D5C2BFC3687399F6D865CB515ED920B12
+:10868000A7781CB2F7984CFCE83D24F1FC278C0736
+:108690004F4679E87199F3D8CEA3FCA5B9DFA0EFD6
+:1086A000FBD3BF99743FABD2F4CCAFC7ED64CFF32B
+:1086B000CFBC5EF1632CFFF09F47FC1AFAD79F7680
+:1086C000FCCFB49F7DE1B89BE0B870FC6723EEC798
+:1086D000F2B36EBAAFE6C2436E9EFF79DC47F7D6BF
+:1086E0005E18CEF38556FFE44FE3E8BE3EBCC99D5D
+:1086F000F1ED353FF7C77A8FFDDB6F317FB8F79823
+:108700003B8478341FCFA6FDADE667BD14A7B9F052
+:10871000933F4D32E7335D293E2BC47D88177CD0D3
+:108720008079CA1772F9BE41F38F27EFC37344CB28
+:108730008F9C70E17ECCB49FFEFB38D43B170E7348
+:108740007BE27D677237EEB3FECE7FFB3A27C677BA
+:1087500071BD1E06D09AA3DF88F7E1F4A70BA7C36B
+:10876000054607C48BD1A511F565267AFCEFBF5BE2
+:108770007A7C301FC76F3AF6599A3729BA481A7F60
+:10878000EFD3F16813C39FBF3FFEA771681FFDA120
+:10879000AB8DD6F981F02ECAF97F0D6F293118BC47
+:1087A0006BFE6EF1E6F27FDC1FE2797FB679D05F77
+:1087B000CE7F782F95BFE70B13BC839CFF0D7FB74F
+:1087C000F87F42BE1F667CF70FCCF7FF92C3F78598
+:1087D000FFFEF01E88EF2F0ABEFB02988770E1278C
+:1087E000FF4EF17503FF81F0DEFE7F29DE863DB48A
+:1087F000C1118E9795621E76A23BC4E05C53392767
+:108800008E612959E45DDBE17A2187FB17B2C4E36D
+:1088100036309CC78F40F81B7DBF03A9F2F3558A01
+:10882000BA96DF47A684E97EBD0D572F0C536E071D
+:1088300054BF16C572C914FA7D5BBBDFD52E8126E5
+:1088400031FB4FB9FA0BA7D0FE77563A12EE71F40E
+:108850007C139FEB44DCCB197059FC0DD5E62778CF
+:1088600043D6EF6ED19F07AAE3F8FBDD1E5509E85A
+:108870006C7CB5364EF8606E67DCB46F88BF8F9D38
+:1088800030F9637BF107024DF6E4E5D2EF4F39DCB6
+:10889000FF94A5EA6ECC8B85AB1CFC7E73E0E78A67
+:1088A00037948475BA8F59F897297AAEED463A2AEB
+:1088B000C0FC438E1FF99520FC494574A1543A34FD
+:1088C000AFB59EF09706E40FE7C78826C19F9516BF
+:1088D0007E18F44FC3170B3F0CFA5E2E5FECFCB012
+:1088E000D3FDE7393C3E67E793251FA480FB2509AC
+:1088F0006620FFECD03E8A8BBCF78F6FDE84F59745
+:10890000FD5806FCDDC4F70FF92081F357D15DE86F
+:10891000672D3D22535CF8FF002820961900800047
+:10892000000000001F8B080000000000000BED7D20
+:108930007B7C54D5B5F03E73CE4C6692C964F29AF6
+:10894000CCE4C524811834E0244040419D104010FF
+:10895000EE754011B451470810CC13A4BDB4D51F17
+:1089600003C1343C6C43E5A5453A202AAD5803A623
+:108970005E50D4411E62AB6DB4DC5BB46883A280F0
+:10898000F24869F5C3FB79CBB7D6DA7B67CE994C51
+:1089900040FBF577BF7FBEFC73B2CFD967EFB5D789
+:1089A0007BADBDCE9E4B97E0EF26C62E892B632D67
+:1089B0008C653256F77C3263198CDDBF2B213CA5C8
+:1089C00000AE2F7E3C940D61ECDCB29E4339703FCB
+:1089D000F44BC5F714760F750FBD0DEEDFAFB17B0D
+:1089E00003A5D171E435CD69626C046367F624CDCB
+:1089F0000CDB1953B6EFBB87C6ED98614E50A2FD54
+:108A00006C4E33CD0BFDFCF83CF40B253C48E93BA8
+:108A10001E634BF978BF50387CBBCD611BC2B77D5C
+:108A20008B250870346DFF8BC50F70543DFF9CA3E0
+:108A30001BE66BDAADB24809A3BF4B0C9FAB918428
+:108A4000A1743D8E57C6FC76A582B146FCD70BD7E4
+:108A5000CE8629CC01D78E557F511DF8BEF9A36E65
+:108A60006BF4FDBAE75F793104A8A97BE119871798
+:108A7000AE9F753DE560A534DE7D9614C634BB66B9
+:108A8000E88FE35E4CEB3B0ECCCB980BEEF35BAC8C
+:108A9000A963059FAFF35F4E32848FC138126E58C1
+:108AA000DF67F88F87B151CEE48C4FAF81FF47B2BB
+:108AB000919754B86E4F67ECBABE788AE22BC4E93E
+:108AC000F9DC179B43809F33BB3EDF8CF0D7FFFD63
+:108AD000AF9B7F08F863AFDA9C4FC1BA9B7EF91F4A
+:108AE0000EA4AF7C6F9A53A1F7CEE5B19007FA9D23
+:108AF0007B2F211C825BE75E3999EF85F59EDBF9C0
+:108B000095CB0BFD17BD323E0BD7BFE8D75559CCDF
+:108B1000DE3F1CE79630164ED0C315263A7A77C34F
+:108B2000A059D0DC2BAE31F4D8DFB93F1FE13C7B3C
+:108B300034C1978078827B8BCB913E40A7A1BCFD4E
+:108B400020E0B771C78FFEA20E8D87E7508EC98DCA
+:108B500074FD7802C2C9582487B911BF3DAD4E7B60
+:108B6000DFFEBDF43A02F4BCF61BD06DC70A3E6FBF
+:108B700007D0CDD1976E67F11FA04F13D22D294A90
+:108B8000B72F58F0E79E226877A6135DE3E12BF23A
+:108B90000DF055ABF0F16F70FA7FE044F9D995D440
+:108BA0004BAF2948AFE7BEC86740EF53E69E7BD87E
+:108BB00070C67A5E49706E85FBF7BFF24792937379
+:108BC000BF7EC78274843FBB02EB3AC77AFFBA709C
+:108BD0009D8D8A58E7B6E44882238AF7C6F0D48987
+:108BE0005E07DD3F4EF7C39C7F117F39489FF0BE83
+:108BF000DB9538F4E87016D23A583893D6DDB0EDEC
+:108C00004F16E41B4927A48F320AE9757C02DE97D0
+:108C10007492EB8E1DCF897818A9A3DB362E877D41
+:108C2000E9DA636145F1E805F0E27B082FB4CF6D26
+:108C300049D094147E3F17D671CECC6676201C6145
+:108C4000E58FF1E8CBD8325ACFB3B17229D6772568
+:108C5000B9BC12DCFF285E9E703A697C899F335F45
+:108C6000C7D7CF8750CE01FEDDF6E041E41FC6AC8A
+:108C7000E11330CEBD4C61294551BC4978CF688C99
+:108C8000F4EE995FAAE110ACBFB5633FE9D958F99A
+:108C90008675F93BE2CCF747315FE3EE7D43510F38
+:108CA0009D797D0FF15FE38EE396108C7368FB0B6B
+:108CB00096EED228BFA3FE0EEBF4F7995FED1B4AA8
+:108CC000FA16C78FA36F4E88F19BF61AC76FDAF1B9
+:108CD00017C3F875A10E8BD37EE5793ED3FC3370B4
+:108CE000BD9F759919EABFCF3AD489E138F3BE29FF
+:108CF000EC97C453EB3B16B263C3DF4D0C27009EC9
+:108D000016BD33F14F291978B57801B5AC7329E751
+:108D1000ABCE87FC394897CE77EE52D19EBC88788F
+:108D2000BC2A3A6EC591E6AA6490DB8A6381E1C8E9
+:108D300056B1FA60E45193016E98270BF5F372185F
+:108D4000C70BE330CDE70EC0B8AA63C244844775B1
+:108D50009A9CB6B876958F67B6075810E03283DDD7
+:108D6000F6EAF8C93DCD3194A5E0F23C26D40B0BD0
+:108D700081BD503FBB2DAC4403F89829D1F7148C2A
+:108D8000BB70B0BFEC20B417CE71FB42F0DC731B9C
+:108D90007FEFACD31E325D8BEDFC30CA51D24595CE
+:108DA0007941F59D51DE9ACB40252409BECAE94898
+:108DB000223B93A4793754433BA956F30146D92764
+:108DC000F6605E6A26BE67A1F73CA98AF629AEDB8B
+:108DD000C11C286F727CD94F8ECBB4C8505C3FB396
+:108DE000328D815DC9651C6E55ACA7887529C8DFB9
+:108DF0002D531D5BB1BD29B996EC7F3EEBD9E7073A
+:108E0000BA3DE9987018F518FC6BC27E79CD46FB27
+:108E10003E60B1B15D10D262E4D76B0A00FF15B5B8
+:108E200019EF6754552E18E063EC9ED4CE891AE8EA
+:108E3000EF8C19953B7300A79357BECBDBCF5496AD
+:108E400079A0FD1F6B1A2669A047327E5F59960FE5
+:108E5000ED0B69DF9F44CFEB0049D783EA5F3374A2
+:108E600052A8342AB79900668A4AF27C23E2E16C60
+:108E7000E04C2B3E6D98FEA5051EE15F00F190379A
+:108E80008AE321D77E6C2783FE034CDD4B912F7F35
+:108E9000FECAFF4AC57E5EE6A4F53AD972E7A75638
+:108EA0005C3C1B7569D8E5F499C63E957CA846E5FF
+:108EB00020C515BC3515F8AA7556C98609A86BEBEF
+:108EC0007DC45F30B393ECA1ECEFCC20FAD408FA68
+:108ED000209C56E0B339BC0BAB65ED420F8D73E2BD
+:108EE0003C4AA85EBD74CDB7876796E49B64968CB8
+:108EF000F7B57A2FC1D595E99F83F8FA2A334857F9
+:108F000079DF3D6BA63708F8BD3135300FD7E199D1
+:108F10007B311FE19F92CA68BCAA79763FDAD50BF4
+:108F20007B41FDC5912B79DDBA84F9B441FD3F9FAA
+:108F30009616FC2E8E5FF89A77D76118EFDA1A8BA7
+:108F4000CF06535CBB78B84F4B677C41E87708BAD3
+:108F5000B991962877DF636194BBF3098ADF0FED3F
+:108F6000F30F38492FE7D64C398CF6EC7C52414749
+:108F700004EFFFD04BF2081E8082F290B7372562D3
+:108F800073103F7F19C3CF5F1AF9D738EFF94BDE63
+:108F9000DDDD349E538C070E113CCF13743AAF7253
+:108FA000BFFCFC122FC101EEE33EB4B7DF74BEB5C7
+:108FB000A9C24F12F479C8E65F87F400FC6FD0E3D2
+:108FC000FF67FDD37133F6033AD235968E73ADCD7C
+:108FD000F9A817EE0F744C008DCD4ECEFD5E053214
+:108FE000F7D4D4E036EC5F3FB3EB9099A0692E46FE
+:108FF000B9ED4B6785F4B96BEF7D4BCDD06E423A3E
+:1090000079FBD2F3DAC56544371D7D3B70FC6BF705
+:10901000FEC584F04BBA6E50B81D887DFFE55445FF
+:10902000CC5BBFD40CF8BCB0DB42FE6F6CBF83A935
+:109030005EEA27DB43AD153E0DE434CBC482F1C6B6
+:109040003DD8675CAB2F210EFCBDE339F97880FF7A
+:1090500037F4F8FF6DFFF8FF9DC0FFEFBE25FE8FD0
+:10906000209DFBC3BFF4BBEB847EA863ABC9DFFCD0
+:10907000C43FCD3510E69FA0DA491EE63FA5921CFD
+:1090800042FF291E57549FCCBFAE791FAE77FE1307
+:109090000AF16D4D90EBF9CFE74E3984FA7D4EBB66
+:1090A000D17F9A3B33644138E76D34DE9F1F8E8950
+:1090B00007994EAF035F9C89F2EF00AE77DC642F17
+:1090C00055211F55F34A53D05F7AD5ECFD3DF9E3A6
+:1090D0006FAA6C6B1CFCE7A715903D96EDBC664033
+:1090E00092CECEB31A9B09F5A51C77DCBCD22CF42A
+:1090F0006B16267B2F1B870D586CB4EB05A144E63D
+:10910000D58D5BD49666680F6ACF36F4BF6A63A1CB
+:10911000E1F9E0F0D586E7D76C2F37B487745C6F40
+:10912000E87FEDEEB1867659E41643FF6187A71913
+:10913000DA23BAEE32F41F797496E1F975DDF71B84
+:109140009E8F3EB5D0D0BEA1E707463FC6C4484F6C
+:10915000B24485F4E68125A72A4E20C30D57C621C7
+:109160003EAB46F1BE0716584C4E075E8B4D4EE0A7
+:109170008FD7E74C213FE0C00297DF4BD70A3FC6AD
+:109180003F4C1D333C18C7CF1DEF3C5D7142376F1C
+:1091900095D56CD073E39DC6F6B034113F0CE07CDE
+:1091A000332ACD285F6AF39488059AD9F30766E1DC
+:1091B0007C2067A3D3B89CD1F58A72E668AEC0362E
+:1091C000C859655A1C3963C2DE560A7E82ABDF522B
+:1091D0008E8C954C76D98F37BD743FA441BC32D666
+:1091E000EACB3D88EB32F9329009C7CD0C1CE0E3A5
+:1091F00009FBCC4A4CDFC63E4B39779BBC21B26B96
+:10920000698CF24B8FCD294E613AFCDE956612FADD
+:10921000A09DC791CEEDC33489C742FDFD8923B41B
+:1092200092E87D65DE942C943B773F7AD1E22E1A4A
+:10923000BC0DF4B1C553405779BF75A66962380EAD
+:109240007D1BD2789C21FDAEC151BFAB01F17BD615
+:10925000FDEEFA4180AFC6EA1EF2BBDCA6F605873A
+:10926000705DBF5179DE0C3C2BD40B73841F3D67BE
+:10927000D24F171C02FD34E7ED41A49FE43C9B96BE
+:109280004406EBFD86DC7EE2AAED029ECD4BFC831C
+:109290006B06115CA41FA49F9E1F6A9880F1CE00EC
+:1092A000D64C71E37A13AB8D37CE0A314E16921C31
+:1092B000E175DA494ECECE3DE6D0601D89C9C115B3
+:1092C000C86FB3AEEDAAE0FE98DF370DF8273F7206
+:1092D000F77AEC9FEFD65858E93B7F5675B0AD0052
+:1092E000D6B73CCDE4B353BB47C1FE090F32960E4F
+:1092F000FD97FF5D257896BF7E1DC3782DC1DECC1E
+:10930000D0AF95EBDA9FF638E147ED4C223BC8D061
+:109310002505FC7D57D0FE0B774D17FA1D5FAC3548
+:10932000D37C5FC01A9D30FE179D6A189DF7436974
+:10933000891113B4D5B664B2DFF9E88342FFB99D51
+:10934000C9616F41142FDAC6312C02F62E2197AF76
+:109350007F799A3D6C2FA075AFC1754B38E5BAF394
+:10936000FA89432369DCCE327F8981CE1E88C9BA4F
+:10937000706E0D9C7F18475D6BA638714EAA9DE0FC
+:109380000C2F090DAE31F75D5FAB7BDAAD77023C98
+:109390002D4754A6C238DEEE76C2C75CC047D8DB84
+:1093A00017DF67BD055F9A54823B82FCA86E9C4024
+:1093B000EB62E8D7C37B0D3F57D8E305C897C18957
+:1093C00044E76C137BAAA0EF3ADE48E3F9DBC369FC
+:1093D0004EBA5ADCC55C4EDC03076F83F1DE423DBA
+:1093E0006565F1FC80DFA7717F9AAEB1FA09EC6088
+:1093F00008E1B8B051217A9E54C21633A0ACEEF603
+:1094000066F207A47E52FD2AF91F524F49B8408FD9
+:10941000BD9FA6B38F6ACA834371DCFEFDB59DFB79
+:109420002CE8AF3919F96B528FF6E7AFA19F86FC94
+:1094300027FDB45331EB84F57D2ED6F779BCF5F5D5
+:10944000D1BF77354B3FE72F6997F133332DF1F5D6
+:10945000D355E99C0E4D4E0BA3FC14C6CBE83FCC74
+:109460003785B7621E4A0BDBA6EAF0939D2EFD3CC2
+:10947000EE6FF4A7F7AE149714AE2A25FD7BA1CBAF
+:109480009B9206D78C8F95E678E3A88B9F1D8674F8
+:109490009A6FAB4C4A07389DE9467C3DB6A28FFDDA
+:1094A0004A4FE7F8A36B1FFCD9017F26839FF86220
+:1094B000B197F0E749BF8C9F78F6B60F2BD02E9D61
+:1094C00013786AEC8D7BB99ECE06638579AD06E68E
+:1094D0007FF244096F5F5268D783F2759BED81413B
+:1094E000387ED3EE494FEAEDF7D7693C9FC6EC6969
+:1094F000946F95E3B984DE8738FBC64FBCA4FFBFE9
+:1095000044FA46E3EDEE0A8CB75A7E7D550AFA67B7
+:10951000E35EBCD389D70B190309AF675F4CF02317
+:109520009C67D3401FDBB13DF210E6213E5F7238ED
+:109530004D4F97B3BF7AA7C20CE39CDDF54E8586ED
+:10954000F90C91AFE9B54797FE501180F743635985
+:1095500049B35DC727566E2FD6DA78BE23D3656927
+:1095600065D7423C92994AEFAF73997E8CF755EBE1
+:109570001FF24FA09CC5E477D69ABD2D76E03388C4
+:10958000E57CB84FB070B0DF3307F33B53DD949701
+:109590006951B81E0DCDE1716846212B2980F1CCAF
+:1095A0002655C5F77A3CCCB715BA241C688FA0DACB
+:1095B0004BECEAF023F8C313D3089FA3CF38158CE4
+:1095C00027643E48ABE2E3F54CB784B7EAF240EEDD
+:1095D000991AD9C524AD83A19EBE2F338DE097F98A
+:1095E000A0AA6933039508D7C3268A6740F12AA841
+:1095F0000F73C43A0A3CBB5648DF4673215B324CBA
+:10960000FEB055C0FF0301CF0EAFC98FF957476EAB
+:10961000E4A819FCBB9CE58C7DA4F323932C42DECB
+:10962000DE5649DE92BFBEC93A13FCA3A4449E573E
+:1096300075045A17605E1CEF7FA71CE9C2DF27FA8A
+:10964000A898A662A11400397994715C49BFCE250F
+:1096500056DF4060E85D4B9C747D7A899BE0FAE9B7
+:10966000122F5D7FB2A484EEF727A757BA3EB2044B
+:10967000E6D5F153C648C00AAC37436524CF8F8C7A
+:10968000A8489915C71F90D7C7971C768D1B241023
+:1096900008F4C8AE776E59594074462182D5BDBDD5
+:1096A000C23F86B187CDFE050C586B4DFAD7E3302B
+:1096B0006FB54A31519EEAA7E96FAC08E5E2D54B98
+:1096C000744FDAFF1EC37CA76778BB82F2EEA96FE6
+:1096D000273E18DED5C582E2BE1FDA9E23FCFEC3FC
+:1096E000368EE7D58C4D4478ED0A0BE0F59C8DFB6A
+:1096F000839FDAB87E3C2DAE43D2839B518EFFE62A
+:109700003C5AFC3080672B7D3F1FF73B92F67F452C
+:10971000F96075A8C58AF2E1D97B9CF6415453B72C
+:109720008581497EEDD13F537E4DB5040A78FBD744
+:109730002BB19DE9086C41978D85FE3CE9801BE4C7
+:1097400006F9E17AC24608E578954DB443C7080F9B
+:10975000ABCCBCFDDAA37FA275AF3207E6235EB0C7
+:10976000BD1CC65B95DAE13641DBBEF4BD15876FE3
+:10977000C0B6ECFFDE8A10BCFF52BAD437010FEA44
+:109780008FDEB613DA43746D8DB799955FE5FA1ADB
+:10979000F67F752807F8B571AFD281A079F6AE5182
+:1097A000709D9EDD6B08DFF407F281CBA03CA935EC
+:1097B00064C1F79F5E72D8B91CE8ACA5B5B910EFCB
+:1097C00057B9837E7FBCFC44A6F47FA1BF3ECF1671
+:1097D00036F774EBFC710FE372C396837E88E35F08
+:1097E0000CCDAC3C9D01E3AC55822B55D433CF99C5
+:1097F0009DA8475817D74367C4582C9C4DFE4DBDB4
+:109800008D37CDCB822B07A39EB85BF361FC5C57F1
+:10981000D05E89F6BD6E4F816F298BF24B5D6A87F2
+:10982000AB1CF927D5D86E117997ACD4E6D4D452B5
+:10983000DC8F58938FFB058DACFD9E1F20BC6FA95C
+:109840000CFDF4D3FBAE4B190DED0668A3DFD0D0B1
+:10985000F98E05F9F3D10CAE3F1B3B817F609CD59F
+:10986000205F7E7064B668CE44D44F4FFB9BAF46FA
+:1098700017EFEB47FF6B920DE8FB4CA1DF89F47605
+:109880006798575AC1697CC6E21CCCCAB06D27FEE6
+:10989000AA2B33713962F6DFF835B1FF09EDE38F9A
+:1098A0004EBA459FDFF5E0BE0CE0B969933D644ACE
+:1098B000217BF3BFD1DE366E3485507F99AC5D16C7
+:1098C000A4AF1BF776893E4EC2DB22A9CF63F4F525
+:1098D000A24969B7607BD1C385CED065F297B51731
+:1098E000935858E71F3D9AC1E5B8560BD13E4AED53
+:1098F00045073DFFE7CD6763E161979BCF4ECFE51D
+:109900007CF5D1F988AEFBCB7FB37E20D06DD14EF4
+:10991000B32941C7778B768AFD6A9B3F0BC7C9B4D1
+:10992000308177F0F701BF5A416F3BA4819C3FD251
+:109930002BE703568E1B83748B3E67A30C7AC08F74
+:10994000F1E62389520F5C15BF7F624CFF42D9F6C6
+:10995000AD1C97DB179ECCC468DB0AFDB5FF4EE853
+:109960006D237C6B4C31E3A5C9F947D17892AF8E5A
+:10997000A757FE2634109EA7B65762FD46CF1CE6B9
+:1099800045BB8CFCEAD3E9FDE3E95CAE6B2F16190D
+:10999000E81DC57BB1E1FEC9256EC3BEDFBCEA454B
+:1099A000B43F791CF53C8EC3421457D56ECA616131
+:1099B0009D3FF5FFE1F847E118DD0F1C37FE0FC3AF
+:1099C000516090CF281C030DF7FF5138B6DE517C53
+:1099D0004B017459A784AC8568171E3251DE444D83
+:1099E0001DE75D8AFB0F0F69E4E7A14B82F51F8538
+:1099F0001A3BAC95A3FCB4FB31CE67CB78FE08EEE6
+:109A0000B799CBC90E911F5CB437E13EF4D30A6B12
+:109A1000FDF3F1CA724B697F43EE0B32910793FB62
+:109A200019839CAC5203E76D74E67D64A70A03D5E5
+:109A300075E8CCA9C9C313D13EAE338543385FE87E
+:109A4000A77CBE4C53B8C38ABAD731D089F62ED37F
+:109A5000C1F51F5B594AF66FABA9F0EA0500C7C311
+:109A60004A65E29B88E7D442CAFFE2FD85707FAB7E
+:109A7000B05B6AAACF89766AABB05B2D42BFCBFBE5
+:109A8000496981FBD09F3895B1E816EB75A887FC32
+:109A90006DE9606F4E662C5AE9F6A0BDF1165AC109
+:109AA000BE9C5CFB00D99BAD4BBDD9CED4687BD0AE
+:109AB0007F83B5263DF1C04AF45796DB17DE8FFE53
+:109AC0000E3CFF8D15F4EC336942EF88E785BD7AD3
+:109AD0000AF412E83175696F3B847AA9B057EF3CFC
+:109AE000407A67DB6695DA6FC37CE8FFC03A422AAA
+:109AF000AE7790467EBD0D604984B66D7021ED1342
+:109B0000C1BA5922FAD783F97399CFB70C32513EB3
+:109B10001FFB231E6D1EDEDF3295F9705FCB926C4A
+:109B2000A73844EE0FA8629F2A51D46928CEA91401
+:109B3000DF5957972FC478CC3AD0B80F6B89A9E773
+:109B40005063EB3BEC11F2BF4E6788BC7E3A735F0B
+:109B50002A8ADE07BD5D8E57D79DCB2B11DE85C9C6
+:109B6000CCA9625E2518A17DCE58BB66053BEAD51F
+:109B7000C987D5CEFCF1EA090E65723FD67E51A3A6
+:109B8000F866AD02FE0DDAD164CE67D23F323B25D6
+:109B9000DF1AEDAEF497CCA97C2D8B268DCDC2F8C3
+:109BA0005DB5FBADE8E7EC7396535E4065BE5B2B9D
+:109BB00075FECEF2C824CABF694E3FF9E145224E78
+:109BC000549D3EA6F7735A9740607915634F56141B
+:109BD0008F457978DC16B116217DD79928DEDB5FB9
+:109BE0007E7F48C1FCDB624672FA64856B2CE6D14D
+:109BF000B7688194BB515E8EC07C5E4E37BE9FDBE2
+:109C0000A260BEF80B6B2005F5C123C8F73ABC3C37
+:109C10002FF0F1F70CAE7F1E3673B968057822007D
+:109C20008776F11ACA6FADC9E4790F4BF538CAFFD0
+:109C300058001F98DF4B60CD2127AD97E7EB12DC72
+:109C400026435DA0767128BDFFF70C9321AE6E838D
+:109C5000757A75FACBC64294AF431C3F15C77F791E
+:109C60003B93C72356F087BCE49FC4EC73F7F58F92
+:109C7000C85F91F4E9F55314F04F2E138F3541BCB2
+:109C8000ACD7F74D5A0FE9DF268887F1FE39A79543
+:109C9000FC4359F76017FAACD51D6C1F8D7C9EE80C
+:109CA000188A79008D7510525663DD03EA43B7D6E2
+:109CB000D3CBFF20F32D36C756ECB75CD44124F943
+:109CC0008CF293C8DA237E94CF129DDC30C477885F
+:109CD000C64DF01AEF331664186768EED83A89500B
+:109CE0006F3D14D5F369EC31DCBF967E6F8EA847CB
+:109CF0003A9BF421E5D1C0EFAD4CA77D801E8A5B75
+:109D000064BEE7DBFAC9453806E61116FFB5E20482
+:109D1000CAD9D40905783F49E37C02AEB896508E83
+:109D2000E1D584F9A9B0FE3B85FDCB50DBA96EE4FB
+:109D30003511CFFECD39D3437114E093EA6D127D16
+:109D4000DD142F0A3F4DEDD58F7F5EE137FA9D215F
+:109D5000BD9FB76ADD9F572CE7F10AB55F7B3442A0
+:109D6000FAF3619B6CBF4C6DB073118C97D88B0963
+:109D70005EE44378DF8FF2C6EE28263F5B2D64D980
+:109D8000888F710E2BE94DF5C584ADE807435CFC67
+:109D900052BA6EBFF86CF2D17CF487E38C17328C28
+:109DA00097FFEDC683F93BB11E473E1FE7D8185118
+:109DB000F97B5E7C8FE5767D1882F1D7FD3A81AD27
+:109DC00004143E6E36CABBBC6E15F28CFA465F0FA9
+:109DD00069A9AEF123534BB94E7027B2888E9FA468
+:109DE0009C6B1707B3884E4E8A32F9BEAAA6F92992
+:109DF0008FA45D2CA5E77F4799A6799C579827AD3E
+:109E00009F798691FEE87F9E0AA15F98D8BFD2A86D
+:109E1000AE46EA85FEE43C769F2C562FCAABD48B27
+:109E200059997CFC7D99C6FCEBFD1B3B0E210B7DFB
+:109E3000660F1EC8A4FAA8630E34E1F5A6C850E464
+:109E4000E34FFADE6FC4C5BD95CEF3FEC5DB17BC8C
+:109E50008EECDA9519FC02FDA0DF648AFD4937D843
+:109E60004315ED1DD88B52CAE77E9181F9DCA077AE
+:109E7000C37886F27407E573535C81521CBF755A30
+:109E800005E51C24DCAB96F03A35A967ED5A90F055
+:109E900065D542FCEA0C820D67EC42A679B2A62099
+:109EA0003EB91C1D5D7781E4C0A6F989AF6C4E9365
+:109EB00017FD021BC485A877973A4D7CFFC66DA598
+:109EC000FC7FAB021122E88D85A98597DD1FB75C69
+:109ED0007491BD0548DC7ABDFDCF9F2743D807E3C9
+:109EE0003C9A93FB0D6C3FB7C388848F75FA58FA80
+:109EF00003B1EFC58E2FF129F16B45BC96923D8CD5
+:109F0000EB6FD85CC6FDCC2CA96F338F1647E06E83
+:109F100083D2ED40BF06F4A8CD857A7A488FC3E49A
+:109F200025FDEBE27E5048F035B3EBF95AE6A9E5A2
+:109F3000BA24FC0BDF9C63D5EFBFC4C21B6B67ED7B
+:109F4000A5C6BA059BD758B720BF0B50B500F18DF9
+:109F5000798CDF8A72B2D459EE443F67B9E6FDA32B
+:109F60009FEA2DCCE46F83FF6E985F5E1F01F94777
+:109F700038CA5C26435D8DBC26E33E4A9CF7A6BAF0
+:109F8000B89E7A64DF9DA487351FDF678AA51F63AB
+:109F9000EDC42FC9C5CC49F95301AFE30AE3F6C7B5
+:109FA000473FDE67233F591B650D635D67EC7CAA65
+:109FB00039E05750EF9631F293D53C3EBF3A885185
+:109FC0001DB863781A2BD1E1B1D53D8D9E2FCC748D
+:109FD00032A4B79A6C0AC4E31789A7812E93816FC4
+:109FE000DC926F3CEF17A31CE8F826108F6F06BABF
+:109FF000B8BE4238F4F46D751766C5A34F542F727E
+:10A00000BEBA125FCC4AE27E4EA785EBCD06C411E4
+:10A01000C44BF5999656CC7F9FB1F2E7CC5FC2FD59
+:10A02000322BE7B95949F961F4873A357F12FA655D
+:10A03000B37AF76DFDF4BD47BDCD9F721DDAC777CA
+:10A04000B8DF7CB2D2DEA6C03827CDFE14C4F7C973
+:10A0500077546529ED83F3FA39598774D2EC5D752D
+:10A06000353C9FFD33D5BF941E1BFDC133CC3FEC67
+:10A070006DF48F77ABB4DF52F0D3FBD421D0BF06A1
+:10A080001C45E4A75955F610DAE1CEF79B3F447D15
+:10A09000347B73827719D6B16C1CF625B63F5D9D73
+:10A0A000EC4DA03C5BA1E2C1FCD79A0227ED9B2CB2
+:10A0B00066229EBB7D7215E8D05FE2D4327F0D6BC5
+:10A0C000FE94C9E7A155E3609D5767769AEC00932B
+:10A0D000B221B4CA0AF47B7869C08DF163876BC67C
+:10A0E0002A8C1F5D2E7FD74D102F9E70DD3919DB16
+:10A0F0009D8FCBF1EE5AE507BDFCB22958A0C0F305
+:10A10000A4AC072653FD6A911CBF959ECFFAF95562
+:10A110005F1E85F1CB366C9C8C39B78A6AF17EE87C
+:10A1200009826FCE18D9DE9A543510DE4F62863C14
+:10A130009A391A8F529EAEB3D7BF7A7A32C69FB37E
+:10A14000C736576930FEB20D3B569582888C6CAF8E
+:10A1500074FAA1FDA30DAF4F4E027EEB64FE3A8C64
+:10A1600077576D3830D97A038C9F6E1C3F4315F9B1
+:10A17000D8D0E15598C7EB858FBDB7CA3F30DA7F9D
+:10A18000983B61752837CAFFFF2AF81FF8FD572E44
+:10A19000DC07B4761FC2145DFEE21E0BAF7B15F523
+:10A1A00029B9DD4379DD8D689774F33A65D976F383
+:10A1B00076E7B2F8F6FE2F6E2E779D89F19F7F2805
+:10A1C000F439C0EDC7FA9594A3CCBF238E3C1D741F
+:10A1D000D949FE0E82BF674D8BCAD5AD20DBA3B037
+:10A1E000FEC7CAE194E3C4BE7F4CE82716BA350D1A
+:10A1F000F9788AE0F3229FC2EB7876278507A1BF22
+:10A20000C722DA6DB09EED229FB1DDC6EE9D0A53E6
+:10A21000BB12597027FA9FE9D02EA5F7FD3BEDD16F
+:10A22000F1DEE2A2CCC61705B6E178E3B33C652DBA
+:10A2300005D17100EEE5D67203DCDAA8347C1ECAC3
+:10A240005E50AAC367295F07F009E10BA679F626DD
+:10A250009097CEAEAB0B57C21256B9BC86B8AFA220
+:10A260006B1A7D97F29F6EEEFF302F7F3FB38AD738
+:10A2700085F4EC49A23C05B37615239DE47B1705D4
+:10A280003EAA7E346503F6ABEF3233AAFFDF59797D
+:10A29000597FA01EF37A3AFFB15E8B503C578F79FD
+:10A2A000BD6138DE5B16B463388E57E4AF312F974B
+:10A2B000D9129FFED21ED65F4C65A1617DF56674F2
+:10A2C000FC0C7A7EA57545C733C69D7DC7B3887DD6
+:10A2D0000081774DE0DD121FCE0159824F01DF264C
+:10A2E0001D7FCD11FC06DA93FC80732F0EDEBAB20F
+:10A2F000403F2FFFEE06F4F3B337A1BEEC4AA4B8FB
+:10A30000A542F34FC6FE155D69B4BF20F943F2853F
+:10A31000A46B675A33E56B7A1E53C80EC6C2552C20
+:10A32000E1DAA8101C59D541F53E1D7C521E60FC97
+:10A330004E31FEF051243F4F707900B9B91BE5173B
+:10A34000F72B711DBEEEA1D386F485FF2768FF466B
+:10A35000101D39FE7F6D13F51C1C6F7DF19F730579
+:10A360007AE6D3F38AAED7699DF5FDC8ED5B6E073B
+:10A37000C1997534E2F042BF4705FF77767CEC184F
+:10A380008D72B15B658A97AF1BF55685D4C76CEEAD
+:10A390005B6341FF65F5B6415F7A910EBDFA3362AA
+:10A3A000B546FBBFE29E3B65393CCB48E0F29AA143
+:10A3B00082B5298FC2313D8BFB59A382F1FDD27743
+:10A3C000DDC9F45CE2FBB1C555EC6358DFCF5C7CC2
+:10A3D000FF7354774841BA48B98ED5538BB2B83C15
+:10A3E0002EC8FA7FA4A76C57D05336A9A7F8FD83CF
+:10A3F000101C613F97AB7BA802FE738DC9EFC2387A
+:10A40000ECC43B3FA0EF38E689BA952158B7827675
+:10A41000F36880ECCA697CC8EB571EC218704EBB4B
+:10A42000B17E856DE3DF89C6F255948F42C27F17F6
+:10A4300070087B706B42F7AF7891B1519E651BE05D
+:10A440006C3415E99EDBB9DD9274007A2F6769518F
+:10A4500039FEE8C5AC2DA86F87B9795E31A3C85F16
+:10A4600086EB9772097655F089E9DE6976AE37A6F4
+:10A47000C5E1DF27847CCED9C8F9A6F3BFAA26237D
+:10A48000DE3BDF4D4B5DA6D3134F093B28C7957AC2
+:10A4900048BE279F3F29F8637B9683DA4FB99245E0
+:10A4A0009EC714F7BBB9A774F695F8A78DF30FAC48
+:10A4B00037A4E7EF616EC5605F7BEDAAC0738305CB
+:10A4C000F00BF8DB6E0E6563DD4E459789C6ABD9A0
+:10A4D0009D4CF580351D1C8F35EDFB4C753AFCC449
+:10A4E0008EF71F59DC1FD862E27544074DC06F8894
+:10A4F000773B87EFDC8B1ED29F8745BF2BDB8D6FB1
+:10A50000A667B658781D29D097EAF91A5ECAD962AB
+:10A51000D4D34B05FE832DF81D5BC606E6C35A2B2C
+:10A52000C0534401B867B885DEB1F82DF8DD6ACFB5
+:10A53000638CF6F30755FBCBBCD06E0AD8CB15184D
+:10A54000AFB89DEBE18AB5E0C7A0DC59A55D787393
+:10A55000877EBE6359C9221EE1FC5CB391E36F1094
+:10A56000F83FCFE215C6F915F9F11C9E8FD6778C0E
+:10A57000C6FC937CFFB4A0FF95E0AB40F88647E1B2
+:10A58000C3F1919F983DB00CC76DFCC3AE1CFDB8E4
+:10A590005F66717D9BA1CE1A6B433DBF06EC0E49F1
+:10A5A00067703F7E9750B337D5B992913C9B30EEA0
+:10A5B00091F3D6883C24C85DC554585A71EF3C923B
+:10A5C000AEEF3DA75FBFE6E6FEDC3F8BBE9D96206B
+:10A5D000ADA76727C0EB8DE2A5B3E3BE6536B41324
+:10A5E00047990FED8484775075B703EB4E9A84FD3D
+:10A5F00080F59A307EC9F89997B520DEBAC65A30F0
+:10A600007E8AE56B49A712C6E547C66925B84100B1
+:10A61000ED3CF750A17F18C5BB1FBDF4CAB32B2971
+:10A62000BEE27469AAE674AC740767B833A3720813
+:10A63000FABC02F555CDDA5E7DD4C1EF77E557035C
+:10A640003EAF754B3937D22523D061C37D0DC9D7B5
+:10A6500067F70C09AFE474A6F93B3B92C38A82DF2B
+:10A66000A1362FC5B85BEA0984475F8729E1E9A5D0
+:10A6700023033A0E89DE1F54CDC76B0279473EAAE9
+:10A68000579B158F427A80F2AC59A807A09DD5C17F
+:10A69000FBB1BDFC5C0489A7FA193028C49D7E7704
+:10A6A00029AD43E22BAB3A62AA875B13AD55FE138B
+:10A6B0003A7FEDB0D86F40BC4CA37883EBEB7A3592
+:10A6C000908B712BCB4AA0EF38C10E917E39686315
+:10A6D0009A0DC67B03AE6897C6AB0BE83B9AF14573
+:10A6E0000AC931680099F789A03F7DEB4D4924FFE5
+:10A6F000ECEB0706E23A3393381FC23856318E9599
+:10A70000ECA0B007BFCF07BF4E89EAE5838A42E3DA
+:10A710001CBCE19AAD545B28F812C743FFE9A03294
+:10A720003597EC6567A6282EE2F0F76FCFBAF3F104
+:10A73000B93E5EC4F82E1A6F96ADBE19786AE4C4AD
+:10A740008E88C989D2317CCABF01FCE321DEB4C145
+:10A75000FAEF137C7DB020A43A10AE41B06EB8750C
+:10A76000283158DA6C8FCEE312F91B97A8DF457FAA
+:10A7700001AF260FD7FF3FF6707BF181B8BA1CF10D
+:10A78000F33D1745FF3FDBB99E5E5919FFBBED87CF
+:10A79000845D9171E7AD62BF03E2CE87DC3CEE14CD
+:10A7A000F5A77C7F04FC7BC26FD58FAA69DFEF8B96
+:10A7B000AEE929FC3C04AE0FE688FACF7B1F9AFE77
+:10A7C00013E4B31358670E78F844F0CB09A7DF8180
+:10A7D00075520D89F1EB889F14F034083C9C5CC2E3
+:10A7E000CF2F9883FB72C07FEBDCDCCF9BD77EDB67
+:10A7F00004A4FBBCB50AEDCBC9FD7F49E7DA4DAA3D
+:10A8000021BF3E07F7E5D2FF9178AAAC9F786AB8DE
+:10A81000219E92F3C6C6551F2D711BF60166B51712
+:10A8200089F32378FFD9CC4770CF6ECB31EC23B2BC
+:10A83000B6CC6FF4DD3FC651A1B8F0590CF73F5AC2
+:10A840006265213D1CA70652FDC443EEE0CB6E03BA
+:10A850001C492C64C8878E71D2F744369E87057FC9
+:10A860009CC73170DD62277F7D22FAB3BDF930D0FD
+:10A8700023CE14D44B95FBDD23A2F18394B3FA319C
+:10A88000F1E38875C20F5AE7E27172CA511957276E
+:10A890007A513F4ABF3CF6BD777BF9D7E8575E292E
+:10A8A0000F017C1CD2C749B1E39E72FFA3F177511F
+:10A8B0003FFC52FC3F127F578C09529E8FB52B54A0
+:10A8C000D332729C311EFA1AEDFA08BC2619E2A1A5
+:10A8D0009A6A633FE6E1F69F79920C7E7C7FF8D41A
+:10A8E000FBF14A11EA413E5EA3E08B82CFDEA57AFE
+:10A8F000D2311EEE178DC8F62778E0BA5AD493AF3E
+:10A90000B6F1EFF9B7FCF77EF76CF48FDE36D3FEC5
+:10A910003FDBCDF9A6F289452D783E80BD4371EA33
+:10A92000BF5FFD97C58ABF06E43A5DE8BB7A1F5F4B
+:10A930004FBD2F621968C7FA620E476EC73E45D3F6
+:10A94000F15D6E2DEF97E7311BF2E205A23DC0E30A
+:10A950009471CCBE4919D8DFAFA15F90DDA190FD05
+:10A96000CC6E66E457670F5768FC7F19BE45995D4A
+:10A970001A5D6F9B696AA913DE6B7325F9D0FE2CF3
+:10A98000C90E5EE541F88E4522682E471EEBD23097
+:10A99000DE5A93ED2F413CC8757A556736FAF14976
+:10A9A000C7387CEDBD79266E7F185B25FCD2ADDC07
+:10A9B0003F53D961C6FD73B2F3AE65256407E57AEE
+:10A9C0005C69C28EB85870979DFAB791DF62E57ED8
+:10A9D000806B5931F9F392AED1B8737039C69D4589
+:10A9E000AB23DA2C78EFA54DA6B8E7554C10788745
+:10A9F0007554EAD77125BD25FB99FBC93B4ABE4F6B
+:10AA00009A183F9E074B48CF2B9FC8B88BE473B969
+:10AA10008561BE5AE27F4D76E0768427BB638B82E8
+:10AA2000B8F948D4297C94C8F3F11FAD7C5641FF96
+:10AA3000F281F9CCA9B2FEE1AE5FACFA6BF4F2BCE4
+:10AA4000DC427491F14A141E9E8769F070FB7428F1
+:10AA50003B5083F46EDCBD86E2EAF9DB8E5B2EBBF5
+:10AA60000FF10DF1A6D4727FBD7EA695EA992A9FBB
+:10AA7000D088EE75CB2DB46F58BF63277D9FC61E5F
+:10AA8000643E94FFFA8E9D4A0DCC5BB763A73247B4
+:10AA900087C79CFA30D56F5F952CF72322E44FC708
+:10AAA000F237E611D07F3964E3F27FA6D21EC2FDF1
+:10AAB0008933E6603DF63BE349F2E13EA6C4FB1B69
+:10AAC0003B6FA6F30292772544F0DA66DAEAB642E3
+:10AAD000BFB6AB2D3EE4A735D9C1154897342DD06C
+:10AAE00089EFA76624FB707FC39BC0CAC97E7F43E2
+:10AAF0003C8C8CE18B910F72797959E817F8A37A25
+:10AB0000AA273DDC2FC7ED25D45787CC7C1DBB1869
+:10AB100087D7E4F16F443AB1C369346F767D44C19D
+:10AB2000FA8BD879A37CE5DFECC9FC3670765850F7
+:10AB3000CFD7097D53F9C436E5631DDCCF79548244
+:10AB40002F7BC71605F367F09CF40DF46758EF945C
+:10AB5000BD83C7AB75F07C8E4EBFC875C4D1339D25
+:10AB6000089FFD58D701AE67227CBF40C01B4BCF6A
+:10AB700088C74BF34F007781EE5B4225182F1F2AC1
+:10AB80004CA4F1A4DCC7CA69C4C3FDCAEC4DDB14F4
+:10AB9000939DF655C8BF94F0C97E23B2C71EF0102E
+:10ABA0001EBA080F0D9B345ACF784B60E0029D3CD3
+:10ABB000BC2BC67B7DC68774AECEDA7F7F87F8B1AB
+:10ABC00001E26C8A33DADFB14C473B13FA858AFB2A
+:10ABD0006093B98BC2D68B73A72677723DDCD0B950
+:10ABE000539B6D8FF269C167AFD379550D1D090C69
+:10ABF000E32BE0BFA3084F2C9F4AFC483DDB1F3DE1
+:10AC0000411FF1F829641179BE6001C63F524F9B84
+:10AC100084FC333BBFFF855857947F829F790C7A21
+:10AC2000D6467251F059F9EB58EFD9E053E8BC8E93
+:10AC30008C2A8E4F3D5CFA7830564F623E31C0E32D
+:10AC4000FBFC69BAEFBA7AF5BD78FF22D29BDB8DA7
+:10AC500008BFCF0AD17E4BF863E937309BFB6571A3
+:10AC6000F84CC91ED1D79E493B5FB0799786DFE586
+:10AC700048FE998C74D7F18F33DB42E33AB33582C7
+:10AC8000677D25DF8F5C6FE6766CFD522BD567BE46
+:10AC90007127AF174BBECB12C1EB41D3AC7A7C7E90
+:10ACA000309BC3D1665A46DFA9815CA66613FF3884
+:10ACB00018D78F5C1FAE7D81EBB3FA909DE2DFFA6F
+:10ACC000E0ED35540F9061F3611D2D0B1EB04C4F1C
+:10ACD000EECB57DE5DFB2C08FFE40E2E7F920EA01C
+:10ACE0004F89BFA43C48BC46F11936C893A487A934
+:10ACF000D79F0816707F89C75BA5E23BC25AABFF9E
+:10AD000090D98B710CCFCB968AEF09655E7696A0B1
+:10AD1000CB667BC087EBEC9397FD86F142DDE2DFEB
+:10AD2000527C76BFFB4DBA4AB985B8D620DF3709C9
+:10AD3000BA176773FB3E219BF34DDDF00E92CBBA41
+:10AD400013CD24CFF6895CAFD98FC5F88FEC11A154
+:10AD50008757D37BE3933A26E0BEF2F89F2B4E8CC5
+:10AD6000F7FB83731E7E8F8571DFA6FD8EFB10BF00
+:10AD70005F43D4A1FB5E67463697AF33DB01E1C486
+:10AD8000EFCD96CBF9E3571A8F458E28741E88C0F5
+:10AD9000E5991D55D77D82FB40DB537CF8DDFDE74F
+:10ADA0003B6EFBFE2700F7996D37F9D04FC8680955
+:10ADB00010FFF464DA7C5B799E7622E6B19676EC3D
+:10ADC00077E0F73DA79FBDB61CF576A380F3B317D8
+:10ADD000D4C5889765CF3C7F233EAF0B2BE9E8BFF6
+:10ADE0009ED9FEF3BF67C338B5DB9AF0A431D6F223
+:10ADF000EC6B141798C25BF8FDED29E4E79E7E72B8
+:10AE0000CD8D88EF968E167AFED9935BA8FDFA3326
+:10AE1000CFBFFA5FD0AF3EE0A0EF9E3F7B611FD176
+:10AE2000A53EA8517D7A7F7CBD7EE73EAE2FD1CE78
+:10AE3000A31CCCE47A4CF2B5E4DFD3CFDC7B9DDEFF
+:10AE40006EC8FB6D229FD396C8EDC8E7426EEBC675
+:10AE5000DADBF0FAF973363A9FB3D1D25D8C717EAA
+:10AE60007D29E78B07053EEA3B16981BEDF43E8DE6
+:10AE7000F39F20EF781D02FC897560D06BDB25AA5B
+:10AE800067FA15F5877EA330DF33A3FA38FFBEB328
+:10AE9000B4D95C47703ECB9FC3AAF5CF2B16C58FA4
+:10AEA0002FD767DB0DE7AA65774ECDF5921E48F0E8
+:10AEB0000DD2F9BFD9B5C19664B87FCBA2A00FBFA0
+:10AEC0008F7FE9D4BB13F03B86674A9461447F557A
+:10AED000E1762E64A7791A701F09E28FED424E20A9
+:10AEE0007CCDB81ED6335E6319F889EF78C68E988C
+:10AEF000492F3C45E3839F43FE9BF7B5194FA1DFE4
+:10AF0000B3DE1CF48CC071DA847DDCC6E187F79D6A
+:10AF1000F6721ACF793DF7D717E27BE7974EC94013
+:10AF2000FF1EC6ED32EBE231E0C87CB48F38DE7034
+:10AF3000C4D3C4D04CB2535E0BAD4F9EFB09EB1F84
+:10AF40007AF790A87CC6E69B503F617EF85076E584
+:10AF5000BEECCCE8D5D54FBEC69C03CFD19EE5F85C
+:10AF6000E9FA4DCF117D7DC6396EE75F3E4E7CDB41
+:10AF7000887C8BF3074F18ECBCAC7759BFE738F1EE
+:10AF80006DCD6EAE8F1B77575A30DEFA7C899F7D70
+:10AF90000C8E6EA3E0BFF54AF75CFA4E6C8F8DBE47
+:10AFA000FF3B27F9B3FDF8A7A87F0A777B289F709E
+:10AFB0006E0FE7D3832613E5010E6EBD664B8BD271
+:10AFC000D7AE82BF4D72D2D8CC84BFBDE85DF4CF7E
+:10AFD0001A6A793D7A630C1F156CFEA815F92515C0
+:10AFE000BC63ACB3017F66027D3F59CF46A09C662F
+:10AFF0008FF3EFC9A17D421E9F67D7823E81F62D58
+:10B0000019F37D78E455EA38F08B91FF326EF061E8
+:10B01000DE6C7D5E472BFACFA1F18CCE575D6F6E53
+:10B020001F8B71F0FAF15E276012F0B68DFC6B5643
+:10B030006211F6AC86FCF246F7777C94D78E95FFCA
+:10B040003D4BC9BF6BF426FAF0BCDBC9BB9585DC70
+:10B050009FB13384BF11F08BEDC9E1D16184E7ACBE
+:10B06000C09FC4E33973179DBB7BEED709748EE193
+:10B07000E4719C5F53C77590FE7863CFCD64AF25B4
+:10B080005F26BF9840763B4D732A98E760ECB60484
+:10B090008467B680A75DD4EBA60A3B52B49AFB71D5
+:10B0A00029395C9E52724CE26A117C2ECF6509519F
+:10B0B000DEE1ACA03FB189EE5CA7869A08C953FDDA
+:10B0C0000E3E5E4682BFEC011DFF4AFF4AEECBE218
+:10B0D0003EEDD438FC3D42C051B07921D17D76ADF2
+:10B0E00038F76135F72B18F005E20DE8487C704B16
+:10B0F000C63CA2DBECD5CA5D44C75005E53FA57F41
+:10B10000163BFE75627DDB6D81E158EFD79399ECBC
+:10B11000C33A82EDA97E13ED2394A5521E24339DDC
+:10B12000FB8B99C25F8CCA7D60B809E639E54AE6B7
+:10B13000F40EFF5EC3FCF6F81CAFF4FF0C7E5EDF7E
+:10B14000389F8F37A53D3414E31EB9CF2CF1115E23
+:10B150009A3853AF4F6F12F8080F6633516F403C67
+:10B1600061A73CBC13E6C17CC2D6D14FF27C023F42
+:10B17000FFB92487FB3DE3D303C3D14FCB2C0A2C6B
+:10B18000E2F693AF33161F87B2651C704F19C6B134
+:10B190008DB7DB7D28776B5F5666115F87AC7828AB
+:10B1A00010F03D97437098A8BE8D0535A247637394
+:10B1B000201C9FEFA7929C3582DF8771C064E4F367
+:10B1C0000CE2FB30E77B6EFF64BE01F5A4DEDF9688
+:10B1D000FA40EA19B46FC8CF522E1A6FEC2E46FA15
+:10B1E0007E53BD72CECCE5FC1CE001E548CA4DF2B1
+:10B1F0004B5C5E562EF556E2F39520F77A7AC7C679
+:10B20000670827C62B52BF2FC90E3C90837907537E
+:10B21000A495BE4115FAB8F1A515C5F1BE2392FA61
+:10B22000D82ACECDB48693C2FAFD12ACC1482EA75F
+:10B230006B08ED51D2E2F8F998D61C695FFBD4AFE8
+:10B24000B5223CB1F56B2EB45D283F5B93E87B36AD
+:10B25000999F8A1D77B1E037491719A7E0BE07F615
+:10B26000DF9AC3F9659DE8F76C8E22E4226CE07FDB
+:10B27000AF29781CEB0FFAB363F2BD7F56BE4CCEFC
+:10B2800023ED692CFDE5BE0DAE676A69FFFDDAF7B7
+:10B29000893830861F77093969CE61B4EE7673E458
+:10B2A0000B92AB05C98CEA7E36327F3AEE07BE7A46
+:10B2B0001597077F4F318E3F342FE8C81D11CD0BF6
+:10B2C000E37D8C4FEA34164A009AD46D3787F5DF58
+:10B2D000D33C95CBC73F9F6C0DA9C0E7FEBCE0BE39
+:10B2E0009C11743E087D3717FA818DF6B1C0911E0E
+:10B2F00081FAA589753B10CF8D6A5731E631AB5D78
+:10B30000C14348FF8F4C5DF9BCFE83EFB31D137939
+:10B31000DF6322EFDB6989E4FD5B46F41CBB0B8C29
+:10B32000D75F5DE832A5611CF8C1EE3F3CF732BC47
+:10B330007DF7CB67EFFE21626B65D23D3F836BB536
+:10B34000550D68BAFCDCB1E4F87AF6CF82BEBDF5E3
+:10B35000514B13E2E6FD9FCFE5FD9A62F6B59FCF14
+:10B36000E5FA34FA7D14DFD7FEA09FF3AFAA72B9D5
+:10B370005EEF14755BB1CF278A79B69B59F146848D
+:10B38000674B32D503308D9F5B56FB68810FF7F119
+:10B390003B0BF939F93DEB14B203C7CC5CFFC0DFBE
+:10B3A000EDD68AA81D453705FDC45A67286202FDFF
+:10B3B00051BB283982E765C27D6D0CCA5AC849F570
+:10B3C000C3B3847D9CDDFCC65798F7A8D598750C4F
+:10B3D000BC77D25EE340F330F7BB0FE051342CABC7
+:10B3E000BA5DD4998A73D8FC53D44B4997F3EB8C4C
+:10B3F000DF97BC901B30E7C2FAAB5338BEAB1FE0FF
+:10B40000E7F1CAFEBB85DD8BE5B7EDC8AB00EF8782
+:10B410000AB72FB1F364E78DED40FEAB76079CC809
+:10B42000C7D50F9C35E8B5734AF7D33F43BE5C9050
+:10B430002CCE4763F9FA3AA521B95C6EEA70DF0CAD
+:10B4400054E3F9B2AEE2C505C8FF3DF97FC4BCDBE9
+:10B45000DE04AA73AEC3FD33DD7E777FFB67FDEFAD
+:10B460009B792DC8E78D1715E293597BDF388A7ACF
+:10B47000BD51EB26FE9965B5137D1A2F6AF49CB574
+:10B4800099CFE8BF975BE4F65F83EB0BFD684C2A2E
+:10B49000EDBF65C17DC273099DB7B150D49767E711
+:10B4A00005CB11CF1B921CF7627C78C1CACF576ABB
+:10B4B000B2F03A7226BE43967CC272938D7CB0F78E
+:10B4C000CDAF10AE1A6B90CEA99C3313E26915E98B
+:10B4D0001619E12CD5D37FCCB73A27D7857A03E06C
+:10B4E000FFC0C2EB88FAF23FA7C3F342BF7C90CD06
+:10B4F000E5E8837C56BB0BAF57C315DEFBA050B409
+:10B50000CB793B769C7A21471F0CE5F62BB430298A
+:10B51000EEF920F708797C21D77F07E255DE7F52CC
+:10B52000C0919DE7BF13F108FAF16EE2AB14164922
+:10B5300085F1AA5FE3BF57C096F7501D6BEFBA8A3B
+:10B5400005BCAEF8702D8D8E5B83E3413F3FF9F172
+:10B55000AFDAE83B383605F435EAE785790CF533A0
+:10B56000CC5B8FF3C3B89154EA9740EB606DA0B702
+:10B57000817FCF8FF0125D5656029F0E17E7EF7B4B
+:10B58000A37C25F929968FBE9FABF4B7BFFF7D84BE
+:10B590002B767F9FB181446FE2B76FF13DD9E8749C
+:10B5A0008E1790FB965CB2BF91217AB9937896FA88
+:10B5B000F28344235F240A3AAE12FD7AF12CCEB313
+:10B5C000CA28E27650C60B3F13EB72C45CA55D8BB4
+:10B5D000DD1F7008FA3B7279FD14D06503C229EDB6
+:10B5E000611F7A6FE2F4867E9B488F25F4DC930E10
+:10B5F000F6EC0EF093F03C4B78CF85EFF5C95B8C01
+:10B60000E376B8696132433FE1E95C51F73DBC87BD
+:10B61000EFDF95F4903E9AC540EF2857A61FE60845
+:10B620003CA00F9FC7FA118043C17AA43452035E35
+:10B630001C0FF0BD3337338AEFD8F98EE123F00BBE
+:10B640005FCE15DFD995B132A4D73DEFFC35F96E49
+:10B650002F9E77CEBFEFFDC41E7C0DC739F3FD379B
+:10B66000290E38668914B7DBE33CB744366F50A225
+:10B67000CFEFFD851AC2DFB7E8EC3AB36E06F0E50E
+:10B68000AC2ED58753CE7AF08BB747A27FDD65A667
+:10B690007D28F02F56E3799FC7445D216B36E6097C
+:10B6A000FE24E82EBF3396FA49FA09F3998FEBA5E9
+:10B6B000447EBEFA470BE6D177C6352C7008CF57CB
+:10B6C0003FBD7012F9CFF35890CEF79EDD663C5F18
+:10B6D00037F65CDED8F37831A18FF88A3D97F7F31F
+:10B6E000EFC5AF9BE9CDBB57C5F737B43CCECF9F75
+:10B6F000F753AFFE37C1AFB2BEA049D617BC72F93F
+:10B70000FA82A698FA82A83F22EB0BBEE6F505AFB7
+:10B7100018EB0B3E1F1B1F8EAF7BFD9DA47EC675D5
+:10B72000D0FDCF0B2FBFCE263C6727EE77E476BA4D
+:10B73000DF5F7D43A6C4533FF51DA9791C4F4D170C
+:10B740003D067B9C99E78DF1C772E979534C9D4486
+:10B75000F439AF8F90F903A02BD5E3493F30F6FBC6
+:10B760007A99DF97F2F3B1C2AC1ECAB7AD11FAD421
+:10B770003714FDE68FD11F43F9BDD9FB6A37803AF4
+:10B78000FB87D7156B8551F98A5D0FF0E567FAEFF6
+:10B79000D807E789F3207CCC47DF390AB9B8E7FB43
+:10B7A000E353707FF6CF0F5619BE5FEBFDBEDD226F
+:10B7B000FD40BBC19EB3187B3F7BF79BE4E7D558A8
+:10B7C00003F41DDD27AF7C9FECFC5C1670A19C9CF4
+:10B7D0007FE5AAFCE0FF859D97F0DC16BACFCCFD93
+:10B7E000FB0CF24FA609786EDBCBFD4C93D56FA610
+:10B7F00079FCCCEB745108CFE105658BE7E8DDD02F
+:10B800000B7F299DBF3146C0AFE0FB80DF1BC49595
+:10B81000CD0ABA116E792E00709D1BAF2DD7F9BCE1
+:10B8200078BD4909684CF7BDE804D69C8BFD4DD620
+:10B830006E559C5746E7CC2744F145ED64D15E7EBA
+:10B84000FB857BE6E07D3B3FAFD822E0B83F4F7CF5
+:10B85000076D65565C77823D729AF60FC535349652
+:10B86000FBEDA1425E979C88E721C0BC76FBD91016
+:10B870002ED6C99CF49DBFCD792182F18BEE77261F
+:10B880001AF346E87E678245785EABBFE731BF4377
+:10B890009126E06B117AD283E71516D1B90CA42753
+:10B8A0007F9A3C97CE27CFB42FA27DEDC71C13699A
+:10B8B000DFD38588C77AFB89BA7315E07966C078CB
+:10B8C0009E42D64C63DB1334B6ADEC18D587299174
+:10B8D00080FB527AF4DC48B3D037B72772B86E4F8A
+:10B8E000E471DE237926833F1290BF0F93C6CF5DAC
+:10B8F00038E7B25AB14E03FC9347F2B87FF22150B9
+:10B900001AE249FEFB316537F907AD1B8EBF8BA2EA
+:10B91000FA96019D5A93BD4B35F4FBEE14BF23A656
+:10B920007550FDC3967B527D58AFD36A735662BE85
+:10B930003494C7F3444DE2BB0FA048DD0E786FCBC3
+:10B94000B41CEA9751D54379D69E158CFCAA3E7C4F
+:10B95000FA35F03FE0FB496CE3791035BE2EFC0E62
+:10B96000D8E357A96E593EDF86CF014E45F005DE7C
+:10B97000BFA922FA3B4F457BCBF6E379962CA8F87A
+:10B9800078DAD24BFC3E5DF8F34D7B2B6F1D0170D6
+:10B9900015750D23361EB857ECD3642488FD667EDA
+:10B9A0009E6F6CFF81D81FDA4987BDDFA9C7472684
+:10B9B00088CFF1BDB149B4EE23224FC5847E18195A
+:10B9C000237FA3A3F240CFCB44BB49D417E2191481
+:10B9D000FE0A9E06A17E195C3E7C4CFE71B9BD9E9E
+:10B9E00045FF709CAAE8B8A4A7C6451F47E5109676
+:10B9F000586EF5B5D443BF8353F9BEFC482DB20F42
+:10BA0000E57DB4B896892B9BD54EF85DB934F2BA72
+:10BA1000B90053320115DB15CE152D38CE0D4A84F1
+:10BA2000AEF933D7B4209B5D9D5F24F241C1F1286C
+:10BA30009FADE3F9F7D22DA37C3E273C9A3193E7E3
+:10BA400071A7CFB4521DF6748D9FEFC4B460C11DB1
+:10BA500020677754F3FC31B6AB75F919B95F7204FE
+:10BA6000E29B9D71FC83ABF3B95D93EF3789BA21FB
+:10BA7000F9BC389FE7CBECF9134EE771F8685FF833
+:10BA80007C9EF0D34A5849CCEFD1FC350FFDAFCAAC
+:10BA9000DFF6A7278CCF859E98EE7FD44CFEBDD0D5
+:10BAA00017522F07443D54973897E5BDB11CEFEF6F
+:10BAB00056CE277D713B6B267D7E070B9911BFBD4E
+:10BAC000FA7FA2CE3F8279A6078CFED28C99B17EF6
+:10BAD00015E75739EF9D41E3F369D2EF9D68F47B99
+:10BAE000ABFFEDEB54B28B594F375C1A10AD7B6A4C
+:10BAF0008AA97B6A14754F4DBB171CCCD4D53D3534
+:10BB0000EDE5754F8DBBAF54F7D443FB4F47CCE108
+:10BB10007DB82F73643E8804C0B95FD4C91CC03A95
+:10BB200099F2285F264FE3F959605FDA67C97526F5
+:10BB3000F9909FDA4CE594CF6D7324FBF4F9D3951B
+:10BB40004B81EF74795C59E774A49FB8B83C9FFBB4
+:10BB5000C1EB159E4F0FDD69A53830B32860D8BF03
+:10BB6000C854D951CC4B9E167ED07A912FC1FDBFBF
+:10BB700061700D2BDCBFE97D1FBF9FC23C668C3E10
+:10BB8000CA4CF7D1FE4166CA10DA0798B9B76C1BE8
+:10BB9000E91BBBCD87DF07C8F16706B768587FD4BC
+:10BBA000B4778B56638FF2DDF87CC1AF492C09F96D
+:10BBB000B5372FB82B81F2829FD80393F2E1FD7A3B
+:10BBC0004B642833F233DDEFCFAECD13FC621E1B86
+:10BBD000B8730EC073FE6D0BCF8F3DC8485E5FD843
+:10BBE000934A794D6D1A23FBB2BC92F1DF8BD9A237
+:10BBF000903F7732959F43B47C2A233B782E6D0289
+:10BC0000D16F3E0B1FC273866A37990DE709DDBFFE
+:10BC1000CDD8AE671D646FEA77F4E167D25B523F1F
+:10BC20003630AF8A7AA8B1D3F83E1B68D48F65C28C
+:10BC30001E0C9B3EAE05EB3C8699B8DE620FFA7295
+:10BC4000A651DC5DCDED287B9ACEAF3A9F7C4AE5CC
+:10BC500072CEF5F188A8D634D8A511C2BFBA51E387
+:10BC6000BFB320FDA511E277170E98F6AAF41B3F8B
+:10BC7000029EE1E23DE9A7497D2DE952390A7F3371
+:10BC800002E2F07CE1EF14B242A42B8C4FF2A060F0
+:10BC9000A0C48F4CA6DF6F182DE603BAF3F3EB4C6C
+:10BCA000D630F251ABD24C7ADACA84BE5682A4970F
+:10BCB000FF3D1452910FAE63CDB7E1EF818EB176A7
+:10BCC00025915F6A0FFE44CF272D2C92BF5331F090
+:10BCD0000B3D3F93FADBB8FC22ED4AE43DEE6F4C9E
+:10BCE00066E007C2BCFEF7B91F7440E1F122F88399
+:10BCF00007305EFCAD6912F1C3245806F61BEF3421
+:10BD0000D2F966B7B13DC9DB870F54FDEF5980C446
+:10BD10006908CFE412633FBFD46FCCA8DF0AD8D73D
+:10BD2000BCAE7EC5A1EF62DE2069312B413F063CEF
+:10BD3000475FBCDF2BDD85F68298A0CFFECAAEFC44
+:10BD4000117DF757CE8B3CF1F5AC7BEE0EA52FDFC6
+:10BD50009C3BB85875EBF84BF2F34BA21E43794D60
+:10BD6000ECE30EE7F9C2A89DE77C53215AD723DF05
+:10BD700041FF3F483D207E77E486DDB608FEAE4EAB
+:10BD80009918E77AE49FF2A85D8F98EC5E4B21F258
+:10BD900089AF4D55FBFAF3AE342FF1CB30939FF8BA
+:10BDA0006504F3A5239D46593B5A34847FCFC89C34
+:10BDB000A0DDC01F7FCC47FBA7007F503EAB8F7D2F
+:10BDC000343E8FE11F49C7C3C28FBE9979298E982F
+:10BDD00028FCE84801E79F2AFBED1ABEFF4621CF69
+:10BDE000378CC38D47FA6ED56817ABAC463E88E5F5
+:10BDF0002F98D1A49F3796DFFAE39B01C837D22E44
+:10BE0000A65F996FBEEA9F6FBEBA1CDFC4F28BD4E7
+:10BE10002B3B6DCE2A3BE6B76A15D2C7C3DE1ED8D0
+:10BE200082EDAB1A0AA85E6667AA6F3F3D6FE6CF48
+:10BE30008777F955ACA7295A249E1704AAB0DDB418
+:10BE400098EF678C38C2EB6D063EC89F972D6BDE6E
+:10BE50008FDF093685F8FB2F9D6EA5EFA5C2ADE2F9
+:10BE6000FDCAF62A6C37B5F1F74FE2BED4B55827B4
+:10BE7000176EC1FB835717F87858CAFDDA9B049FE9
+:10BE8000EE5476EDA7F7DAF97BF30E5913E977084C
+:10BE900085DF7AA358E74D9BF83A333EBE857E97FF
+:10BEA000744E4F88FCA74F4DF5F4BB37FDC59F95E9
+:10BEB0004A7B2E5E6F467D8287795981AF0BF9BE32
+:10BEC000E5569862C400EE0FCAFD3EAC3FD0D71BCA
+:10BED0008C18C0EDBEECE74AE3DFB5B1C793295F2C
+:10BEE0002CF723231B98827A19D728FC80B8FB9360
+:10BEF000371735D3BEE4CD03E4BE64B786E7B29707
+:10BF00005DFAEB847879963162DE53A29E42DEAF11
+:10BF10000D17D0EF8CED4426A1EFF29FFA3DB5C589
+:10BF200039E34C7C07B7B380B76F19B0E5276D10C4
+:10BF3000BCCF33356B782E1BCB57E83BC07FED620F
+:10BF40009114475FF86FD658C4C2BFE323F8E7B631
+:10BF500058B6F2EF31B95E9A2ED5CE984124A7B7E4
+:10BF60000B3ACD1820ECD330360CF5CD7441B73BED
+:10BF7000ACE0B7925E6B37C7C8FF7706A0FC3FD630
+:10BF8000AFFF6C7C1EA31F6AC5BC7385DF3C1F7F9F
+:10BF9000CF54C5F3E2B9FF7CEA31EE37DFCF3A2860
+:10BFA0001F79FE71EE2F36C0F2905FFAFCDED77675
+:10BFB00063BBA123F6776643347E9FDF712DE5795D
+:10BFC000DDF38F3554607EAF76E3DB943FAE95FAB8
+:10BFD000226CD417E060707DB1E16ACAEB98ACFCCA
+:10BFE00077368781BEC0BA9461586F0AE30F15E7B0
+:10BFF00000ACC057C4F7FF03486F4CA47A541A4FE3
+:10C00000A57DE0B7FDDE287DA4DD88D51765325F0C
+:10C0100033308DF259527F94093F854D8C8D1FD757
+:10C02000921C0E13AD8D92BE220E927E07BC4F7EE7
+:10C030004797C91E3699F47E4698E4B2DC0AF68228
+:10C0400044C96765E23C81183A6FC2755D268E323D
+:10C050003E8FE10319C754083EB893F9293E7A513F
+:10C06000F0C1BBEFF1DF839B6E5F447CF8DEFBDC4D
+:10C07000EF9471D4B78F9F22FF50FCD44B771BF8FD
+:10C080009349F8BB169306ADC3FDF44E1BFFFD6B41
+:10C0900085D3D975E7917C7D7EF15DFC1D17DDEFC1
+:10C0A00043B44C4AB0E23E628B99C717D3267F5007
+:10C0B000314BA73F86A45746105FAD4AD7F7FE84A1
+:10C0C000F1C69BE23CD6BD9944F70B5DFCFE854D65
+:10C0D000D7F84270FB73B338DF4A699E8B25541240
+:10C0E0008EB9E2775FE6A9E157BB713F5609BF58A9
+:10C0F000AFD0EFB4FC0EE5B2CE14B1F0BC5E17E5E4
+:10C10000E9E5F8FDE72943145F5B5EE7F6B14749CF
+:10C11000F4F13C6FC8F0FB3FBFF3F27C943F2FF08B
+:10C120003ECE23ED5F6C7DC2B10537D377AE7F6322
+:10C13000FE14DC175534FE7BCFB1F3623DC2725D55
+:10C140009EFA982DFEFEC129A16F4B105730EF4388
+:10C1500039FED338FF2911179E12FB63A71C7CBF41
+:10C16000EC6F03781EBCC4CBDF4B14D753623FED9A
+:10C17000549A319E94FDECE27A628935B05C47575F
+:10C18000EF868466CC4B641689FA93458CC74F7B47
+:10C19000520DE72E64792B4BBCB8CF5124CE2DD84D
+:10C1A000C3ED32EE63E33EF313D941133EFF3FFD8F
+:10C1B0002524DF00800000001F8B08000000000025
+:10C1C000000BD57D09785445D668DDBEBD857487E2
+:10C1D000CE06618B9D7D0F9D0DC3269D8428B86082
+:10C1E0002780A06C0D0804C8C6E27CCCE8BC3406ED
+:10C1F00011F95CE2382AFE2E7F83E0EF366384A0DB
+:10C200005103D32A8330EAD820286A465B46013599
+:10C21000242D2E836F783FAFCEA9AA74DFDBDD6CAF
+:10C22000BFFABD47FCACD4ADBA75EB9C3A7BD5A93F
+:10C23000345A897D7B3E21C4EAD34F2D20A44F225E
+:10C2400033DB4DB4D4D1923EEF8B6265B65522A458
+:10C250008C90C1D69A6C6B227DBEC2A7277250BD4E
+:10C2600086D6D3A0EEC8B6D27E7DD3453BAFDFC322
+:10C27000EAF49F860C226401FC66A5A5D1E4910B2B
+:10C28000E9EF1B743DBE6C6C276753099164E22291
+:10C2900071B4924DAC0E333C1D673996478B28DA4A
+:10C2A0004EC769D29B364823B1BBC348C79BC3C79F
+:10C2B00023C3CD5A187F361B8ACCE9DAFF93144387
+:10C2C000C85C23593F8CB6CFEB1AACA7332075312D
+:10C2D000AE4C0BC04D265A8ED1EF4AAE68F96C3485
+:10C2E0001D1BFE4D082D09D19263627E08878B10BD
+:10C2F000807B8417E1DA58E14FFE8F5242FCBB0C81
+:10C30000962DF43B0D5D6F1D91285C0D02BE0E2530
+:10C310007C651C9F8418DD5F1809B99E4864201D48
+:10C32000A7D3E42C037C36187D384F3AA2DE41D7E0
+:10C33000C575E7B858847F307D9FCEE7A5163BF9D9
+:10C34000A72E80CF9516067FB55C5FA54F20E4D45D
+:10C35000CDC462A08F56EE5FD86AA4F59577110B15
+:10C36000FBBA5D4346D1F139BE22CD2FD1A1215672
+:10C3700023AFC367670E20D6EC407D88334E51A7AC
+:10C38000E31298C7723EEEB0BAA18AF74734A72AE3
+:10C39000FA5FB62657D19EE22A56D4D3368C51F492
+:10C3A000CF68AB54D4B3365DADE85F44D206120A11
+:10C3B00067D33E99B8296A73DCB58AF6BCA76F5279
+:10C3C000BC7F9C343F348EF6EB888A2924948E5AA5
+:10C3D000A362B640495C766F3EC5CFCD1C8E82F617
+:10C3E000058A71BE89B9721FACEBCDDEC5D7124A82
+:10C3F00057233B9729C65D2ED7B3756BD31DF5D157
+:10C40000F79AE90FE0B398F8F70EA3F4D1E8966C29
+:10C410001EDABC64136B17EF2DEDDC8CEF2D752B42
+:10C420009F2F7F5A59775592EC66CA9FBFB59A13D2
+:10C43000901E8692A16783F82A4007B413FDDEA9F7
+:10C44000C764B72105F093F5F038C48F8EB8ADA15D
+:10C45000EB758A109B07FA3F6FB6B9687DC9FE85F8
+:10C46000381F4392920EA2AC4A3A88CE56D281D956
+:10C47000A65CF781E5CA7557E337D69E7B4EFCC6AE
+:10C480004F52D285C06B39FDF939F1FA24E0333AC5
+:10C4900080CF923DF65613E2894C338E02FCB1F9FF
+:10C4A0001A884306394712A89CA1CF6D6C0872D236
+:10C4B00062726928FDECB04ADA63C6C038455ACFCB
+:10C4C000EB00CF7AC945E0BD28E24E0279D15AEEA1
+:10C4D00049F6D075293636C3CA912F4D8E97414EF5
+:10C4E000D6EB3D85D02EC6FBD2E4C4E73DD23B8BD4
+:10C4F000098597683D85280F8D04BF2FF0386A00A5
+:10C50000A3E3E5C48172F8254ECF5F7C5487785C45
+:10C510004C9AF7DAE9F7BEF998E177297161BF45DE
+:10C520006D4A3C84E04F85374A3656F86E13877B58
+:10C5300019216E4D5A283EA52EC9632E0434740964
+:10C54000B9ED3C5BC2C80EF03986F4FF43F92DF01B
+:10C550004B3B48C1F209BE671914F89EC0A7905B17
+:10C56000E23B06D22C27011FA8E418C956AE1301DE
+:10C5700021310AFFC37FAF52196A8CE31F1B04E30A
+:10C58000C0E409B99C7F872C7026019E8CA40DD72E
+:10C590006FA364DB20D3EFC897A5B4128ACF128BA8
+:10C5A0005D86F52A23DE59F0BCDCD8DEAAA5435D02
+:10C5B00046CE58909E063FD570363E008724E072E6
+:10C5C00049444BEBE3797DAA4BF23D9A02F0BCF56E
+:10C5D000137C773C2FA74249D78F82F9CF4FE8CB06
+:10C5E000E324EB08F85EEDAB59894037EBA566A272
+:10C5F0009ADF91D7E838B2C61F0FFDAA8953CBF452
+:10C60000AE1BF5CD5B920FE77D03B1DF01A5D06FC7
+:10C610008DA4FDCA59B4DED841F5560C94511E992B
+:10C6200096A453854FA23D0A750D8504E87B39D445
+:10C63000C5BAA704DAB12E87D6D7521886C49D5F33
+:10C64000BF3F9C62E1FAD19FC9DA997CABE3F8AABB
+:10C65000137ACBAD9C5F37FC328490BFEA294E8AB7
+:10C66000818F8C2ECD40425253385F169242189FD4
+:10C67000F255660A1D7F501CE5432998EF587FD17B
+:10C680001EC2772AF849335DDCD114DFE652BD9330
+:10C690008ADC85C1F05E003E841DB10CFA02BC2923
+:10C6A00056AC370CE8FEC00ECDA5DE64D0FF629D0F
+:10C6B0009AF4C409F618694FC4EF8AE757A7683897
+:10C6C000BE283D5E009E22AF433ADA43621D2ED45F
+:10C6D0001E1A1BCFE62FF0E708C5F734053E09C543
+:10C6E000678102DFD3C2E29BE3E36499F72958270D
+:10C6F000D97C6810E0797692E346E83FE288EF98CB
+:10C70000A409CCAB5AEE79EA51D0639DB20D78B949
+:10C71000713C93738DAFC8C8FABD5D06B744C7A915
+:10C72000EB7C13EDB39E162A487591F1D40FAF0A36
+:10C73000DFA1F860EB28E059A1827FEE81EFCC7396
+:10C74000AC08E72DE7C1C32DE1F0F0CD6FC83C4741
+:10C750003EC0973FD0971FF86E315FF7DFC7386E46
+:10C760004DA1DF2F7D7F780CE0A75AEEDA3B14F065
+:10C77000B05AB219E8772718882B8AAEF39035554E
+:10C78000E49F74ADCA7DCD360BC547D270934DA6DC
+:10C79000F8C8BA4576B8E9B8FF58BD2A6E212DBF52
+:10C7A0006EA19FCEA0CF258D03E98D6CFFF4777429
+:10C7B000BC2CF36CDB465A9B63A0F3A1DF49F94D17
+:10C7C000B4278DCA89BFE88911F84D97DA7C703299
+:10C7D0001DD71F2BDBC00E4E90C944A02F81E784CC
+:10C7E000680687785EF1F856C9670A3C9FD0EA2F41
+:10C7F0005949CB19B0EE6501382754F94BC0EE11F9
+:10C80000784E4863FD89D69F5C1BC41F65800FDA94
+:10C81000DE0D761DC56763A27E3DE8C15E23AB13C6
+:10C820007B36DABFAB8D8C3FBAA392DDA01FBB294C
+:10C83000AC5E1CCF6326A620B918651F7839859B8E
+:10C840001C90C9365A7C6FB10F8C457C58D838DCA7
+:10C85000DEEA256412E069F5E4CAC171B44C6C6586
+:10C86000F851D3C9AB29CCEEAF3F4D19AF24F0BC82
+:10C870005EEBD15B4CF05CAF787E94E2CD6508D482
+:10C88000179C48BF92A09CB1AD87FE0B374413574D
+:10C89000907DD5C1E711092F8DB15AA2A5F86894F2
+:10C8A00088E35CFD5EFB6F19F1AB9EFFE7BC3DB119
+:10C8B0002A3C7C47003EDA5E75E7B50F83FDD9E878
+:10C8C000D511037DB4FA958AC124CC78FD783E3D1C
+:10C8D00096B8E383EA5A1FE2A3F1F415F8BCEACE56
+:10C8E0001E3DD03D8C63A5CF5747D907DBCE81E7EE
+:10C8F000323E8FC6D3B1C4151FFC9CC993C0F80942
+:10C90000D8FE2C2090D2ADAB53766FA3AF3EBB4F79
+:10C9100033694B98F9EA5319FCB9895AE4973C0FEB
+:10C92000B16F0EF37DD16F501C95D72686E79A82A2
+:10C93000D0F97554FAE6C2FC2F9F48ECE1BE779A15
+:10C94000D38B9877479C6F31A7FBCC1A7350DDA22D
+:10C950005CC7442E173AAEF625C3F8BD93991F1F46
+:10C960008A2736CF51DA6609F05191E42C02395208
+:10C970003F8356289D0C9EEDD138F3037C1769DD6B
+:10C9800003F8A6FE57C9B9F0ADC77631DE570739AF
+:10C990005F12BB49A2FC349FEBADF95B975F4B651F
+:10C9A00067BF1FF3D526EAC7D04F7C459ADF3443D3
+:10C9B000BD4D423F658193903554EE2CDE56B21E3C
+:10C9C000D4C5FC2442AE8863CF6F83729D2EA06FC6
+:10C9D000F1FF7612AC1FC5F76FBE5B69BFD691BB86
+:10C9E000BF05FBE7AB834C3E508D867EF8E23F2AC5
+:10C9F000C7ABDB7ACD7198679DCA0ECA02438FDA46
+:10CA00002185A9DC4F1B4546811E58B9ED3B7D8C25
+:10CA100035321F7C4DF93D3D03E4A505CB8A547B9F
+:10CA2000592AC4190EB0793A529DA353219E72809F
+:10CA3000CDEB54FD29A6271E4B40FD6400614E7FBF
+:10CA400035CC32BA5BE93CEEA4E2248AE2C76060EE
+:10CA5000F690B0036579951C43DB477FB93A0ED653
+:10CA600037E1B9AB26C17889CF45DB019E8D15F63C
+:10CA700022881B6CAC31D95AE99046FA3EE80FF790
+:10CA8000B3A3DF180A5642FBFD95C380ECBA5EF7EC
+:10CA9000405C6583E6DBBDC368FF0D57105B2B0967
+:10CAA0007CA7A9ABE645984FF234A66736A6D88B8B
+:10CAB0002C41E3126ED73572DCF5EDCABA6F2C5DEE
+:10CAC000DF47F7A1594DE14B1D08722397B075263A
+:10CAD00067289E289DC0B783EDD71EAAAF4856A0F1
+:10CAE0009EDB2E7974149E868E1735A00FEB6FF7A0
+:10CAF0000C9A057AE919AD6D4BD0FC12FE32A4D226
+:10CB00001A13D047B3240BDA0BC23EBF91887FF9CA
+:10CB100048373339DDDCC8EDF259D10CBF0B882D15
+:10CB200019DEBBC948623494A56655B597A1BE5AB3
+:10CB3000AE8B053B096009B7DEA28C145F6A7CCA24
+:10CB4000EC92E8BAF74AFE4C18E46B88F9B03893D7
+:10CB50007B4B4AE838EB5399BC68CCE476623AB137
+:10CB60009B29DC8DBBB3366FA44D8601741D8B51A0
+:10CB70002E19CB8BD14E3682FFB3F4B5288F141308
+:10CB8000C00BB1D88B34102FA81D5EBC116CD32301
+:10CB900054BE5006EBD5F992918FA9DC91A8EEFB1B
+:10CBA000CF2D936BB494EE1A87523B8CD6DF4D9DFC
+:10CBB000C1EAA9BEC51A5AFF614B33ABE7FA8E41F1
+:10CBC000FDEC965B6BB4942F1A8B7D8B655A1FFA24
+:10CBD000E45DAC1D1C424A58594FB6D5B8E8F85F21
+:10CBE000C772FD6EF3CD05FA697C354BB33108DEB3
+:10CBF000F83426B7BE8E62FDBE4E21F36A01DFD93E
+:10CC0000BE4C98A7E8F7AF546117B76129E014EF5D
+:10CC100091A4F0E3FF99BFB7B48ADB25D16403E0A8
+:10CC20008D2E932B86E27F4F57D616E8FF406A1C65
+:10CC3000C7171DA734308EC0A3184F7C7719E85D45
+:10CC400090C73A166715EDAFA532F949BFB30EBFCD
+:10CC500093CFF0DF583BBC08D68DAE9796AF979632
+:10CC6000F9AB9BB13F8C1B5B88F2BF444BFBEF39A8
+:10CC700043FBA704E6ADA68F7D9C3E96B652418845
+:10CC8000765A1AD2D18468661F9252251C43399E67
+:10CC9000E3D362199CFDEB3158C2EFB4723C0EA78E
+:10CCA000782FB878B83FE6F3F9B9E10E5A2FBB0CEC
+:10CCB000ED9D395B82E121E47EC5385FAF55BD57FC
+:10CCC0004E1910E6119786EFDD19458CF89C6CE93A
+:10CCD0007F2FA590D9A560AF3670BB9AB8AEC0E0E3
+:10CCE000423D971A0D1BBC7A2BB4B74B7637D067F1
+:10CCF0003A850FF05B7B6D2987CFC2E1B330F8DC5A
+:10CD00000A3A2587FCC9D3CCA1F4DB8FF7FEF1F2F8
+:10CD10008BF9780ABE0E371EF047A4F530A5FDCC7E
+:10CD2000EB21E6A9C2673F9E55F313F8047EC6F7D0
+:10CD3000F295F4D84FCFA9621D557C9D7289DFAB67
+:10CD400060EF35FC96AE23D82756253D3774A4688E
+:10CD500016E407DEEB84B52C0BC4E946A6717F6FA1
+:10CD600038190EF2DB55C9E2A9AEED065BAB15E34F
+:10CD70007B2569E1E37BF85CEDEFF5C5EA89847614
+:10CD80009132DED09768F3DAC14E3D496CDBE8B8EA
+:10CD900063557607ECDB6C3705DE0BE81365DDC504
+:10CDA000F920347EE44F86F9951A2A77586D845C11
+:10CDB000F7E453289F4B0756AE4AA1F5DA279F6642
+:10CDC000F56195DF418866DA93CFA03C2FCDABFCAF
+:10CDD0002E15EA69CFB2F609F61D32EE383C5B3308
+:10CDE0007148C07E989E6665F6479586001D19E4D9
+:10CDF0001536D093029F91CA5283A6399CFD3AB74B
+:10CE00009F9FD9BE4639D7CFE5C29FF76915FE7CF3
+:10CE10005F8CD1250F847D2EAA4F29BC4BD39C0B50
+:10CE200001FF4DD13D73C114BE3DFA533DD843922D
+:10CE30009DDA1B101FB15AC86C3A4FA967A303EDC6
+:10CE4000C06536A316F1C9E35514B6B3749CD77602
+:10CE50003F73EB30F61907CC6334E7FFA6DD3FFDE7
+:10CE6000F809E8D1AF4D3608078EEE7A6415D85729
+:10CE7000A3BBDEFE89E95B13EE5789798F86B82361
+:10CE80007D5EDE69C0F98FEECA5904FDC7BEDF952D
+:10CE900006F431BEDBD30AE2A06FD7CBC39CC1FB43
+:10CEA00057E4B87436EFE2ED8B7E7C7CA927605F97
+:10CEB000527CDC919608F838B318E28BBD8907D70D
+:10CEC000FBD04E1BCEE299FC7D6A9767039F9F22A1
+:10CED000036CB0BFD06766E3A8E39C476A287CF484
+:10CEE000F9783F9D4190DD3CE1B4910A9040BD82CC
+:10CEF000C42AEA55C6218AFED5961445FB55493900
+:10CF00008AF6C9D62245FD9AECD18AFED7D92A14D1
+:10CF1000F5EBCB272BFAD7D86B14F5224FBBA27FAA
+:10CF2000C9BE4E65FB212BAE4349B7A30AEC799BE2
+:10CF3000D7D90AE5E53D6D5503AD2424BE5BEA7300
+:10CF4000B7C2F3B1679ACB3C2434CE4B9639715FAC
+:10CF5000C000EB2207ED135478911F7B35366B70C0
+:10CF60003C77F620E7ABB04E6F4914ED14D9571853
+:10CF7000FDF1B05ED5F3EE9163605DFC04E35F1DEF
+:10CF80007ADFBD6341CFCF91D1EEEDD012B41F3B1C
+:10CF90006616B821067844F2BDF409C8A939D1282B
+:10CFA0004FC6530B17E186BD5009D6C9A980BB8275
+:10CFB0002C55ADD30A45BDDAF25B45FFAB92D62ABC
+:10CFC000DA275BEF52ADD3FD8AFA75B64754EBB45E
+:10CFD00059B54ECF28DAC77FE16B05369AD0E39278
+:10CFE000CD74FE638EB455C1BA8CED76CD017E2929
+:10CFF000F5385B5184EC697E134A0FF5AB20AEF532
+:10D00000464B12967B5AAC1897DADB928DE5BE162A
+:10D010001B3EFF5B4B3996EFB4D8B1FC7BCB242C85
+:10D02000BD2D0E2CDB5BDAB1FFF6964E2C290647A0
+:10D0300080BE4888E7FA87D6C1DFEFD5F81A61E7E6
+:10D04000D59FF6BF514EF60EF0F542FD76D76994A6
+:10D050008B9FA413946FF119ACFC29DDBE2ABD8C03
+:10D06000C914E44F9D6903E881768DBD08EC6B6DB2
+:10D07000BAE60FDA1184DCB1D6916489657523AD07
+:10D08000E362836346347FB00F27E44FA03270938E
+:10D0900045530BF5BE28D67E364D53EB42FDC0F608
+:10D0A0009DA705F69DB5E961F69DFF74C26A867875
+:10D0B000CBC133596680EB208F2FD949916E3E2D1D
+:10D0C0002BB4453AD08B47547684283F335598018A
+:10D0D0009E768D6D3AD829AEAB75641B9517B51247
+:10D0E000F347FBEDC074666FF75D67407FE790C65E
+:10D0F000BE08E89CCAE927005F195BE36A41AFF408
+:10D1000099FDC98087B4ADB1AC9EE87F42B205D528
+:10D11000750CCEE15B2DB5AEFCB070A6C07CD470B2
+:10D1200066A6F3FD068F7D04E85F513F54636F00F0
+:10D130003D71A8C29E01F339E83020FFB81C667724
+:10D14000060839ADBD6C7A50DCC59DAEC3F7A6E9C3
+:10D15000199F919B64F7B6307EDAEE7466EFE3BAFE
+:10D16000813F776334DAE18734A46E7B183C7EC05C
+:10D17000F1F3CD80F0F1970FD3991EAC9C6AC6F104
+:10D18000FA5647E1BE6F9F230BEDA0BE668A25CA03
+:10D190001F7D279A4FEEC47683D812C3FDCD595C0C
+:10D1A0004EFDA96BD50F8769FF4F5747DB50865B54
+:10D1B00072513FDDC43BCF8937A2DD32A7764425CB
+:10D1C000E8A5597C9F6CAE593B08B7CBB4B17A0B3C
+:10D1D0001DE76653D17A50FF8B136AF4B1B45E3702
+:10D1E0007CC57A2897A5DFAF8FA3657DFE8BEBC149
+:10D1F0007C6CA0AC5586FE92EFDD163AAF796B647D
+:10D200002BF39FB85EB32FBFA87319820E018F4016
+:10D21000A714BFE8171EE1F816EF1DE1F85A9CCEDF
+:10D22000EDB602527056B9FFB30CF8A167CEBB99A8
+:10D2300011E2F4CA766EB77DA067DF5DFEB4CE1D45
+:10D240001C4F12DFFD289DD9D787F4C42E811D778E
+:10D250009319E9A370E677B79751F80BBB2C1ADC4A
+:10D26000BF1772DC4B307E5FF68513E5DCE53DBE13
+:10D27000A70E13A4F34EE093F3E9A9A9AEB5A81F36
+:10D28000467F4FF50FC8C533CE4F0FA31CACE372DA
+:10D29000B019E5D79E963558DFDBE2C2725FCB0648
+:10D2A0002E07DBB0FD9D964D5C0EBAB91C7C1A9F13
+:10D2B00077B5CCC472778B93CB41B6BF5ACBE969B3
+:10D2C0007692F33EC093D8C79C6674EA005F7F7D78
+:10D2D000C44064D89FE832209D520E78E2D10438D1
+:10D2E0003763B06CB4869E9F51CBDBFEF557EDF7EC
+:10D2F000AE4EB23F0AFCDD7F5E06ECB3CB22D3CF4D
+:10D30000416235833CD9917E432DC8E78356AB19E2
+:10D31000ECD68EADBC6EB79A75B4BE337D06CA9797
+:10D32000834EABD940EB2F6D9DC1DA5D567314ADC2
+:10D33000BF9C3E93D5DD0437B7BBD2E7A09CAD20A0
+:10D34000D21EE0872A63CA442AAEA97EACD8037CE9
+:10D350007055D2FC89C00779E956A4C3C9D6B57BFC
+:10D36000A07E4DF6666DBC15A2A145EBE0BDCA845A
+:10D370001A2DBC3771F88A75F0DE95E9F76B83DFFB
+:10D380009B94FFE23AA85F6BDBAC057B300FE45661
+:10D3900062601C5117ED42BE8AF35D23BB1C28C797
+:10D3A0000B3B1D28C7055E2AA7D5DC0171BAA64E26
+:10D3B000C922C13CA649FD9BF612B5211ACF506E79
+:10D3C000A172F6EDF4BAB8B514CE26A88FC1FA1F33
+:10D3D000D68697BBDE70FAE543CEA7A0376BE83858
+:10D3E0001F52FE81F368360E5F53D77CF37CD4570F
+:10D3F0004E33E8D7515C5F8EE1E5325E36F1F233B1
+:10D4000093FD63F8CEE791F9FA4BA00FCAB78BD919
+:10D410003C42F85AD9CEF9FA38C72329F52743BD3B
+:10D4200081B4619CF07CE7BC9606FB6F29705EA21C
+:10D430001DCF61A8CF4BD4132F1BAF5D75DE82F8D3
+:10D44000F4B80FDA19F41CE511F73F0630B93713B9
+:10D450008435381D1914EEECB0706B3312CF09B758
+:10D46000B29DC3BD94B8F17C9B1A0EE24C44DE5AC7
+:10D470006E3A84EB190A8F2F3C3C217030FF5D9C83
+:10D48000671171796A07256494811C341388DF045D
+:10D49000CB89C3E790136A79F473C9B973C89B1C2D
+:10D4A000C09B5ADE88735AEA52D873B4EE82737AFC
+:10D4B000AEDD5118A73F697596C2387D95FE1F35C0
+:10D4C000E09F25F890CE7E3FCC7939E041D2B3FD84
+:10D4D0007AFA4626ACDB098DEBCF601755656C41B7
+:10D4E000B9D30BCA81F2E3585A07BBE7F1A18EF119
+:10D4F000F01EC966F413E95CE7C40CA68F424BA288
+:10D5000038DFD8B7F9A7648C639D87DE23E1A15A81
+:10D510001EE77381BC2F8F4693A747221E89DA7FAF
+:10D520003D1583D08EE819A1D742F973FB893D23BD
+:10D5300032717CB5BFD833A4DCC8BE7BE524283B60
+:10D54000F5CE4DF3C14F1A6D403FE93D7E2E704A36
+:10D55000343B47F51EEC13D37E538E9E4900FDA548
+:10D56000F6377BF6CFAEB41686FA9D14CE890067E7
+:10D57000FDE79A3BE0D9C5FAA1F56B7E24DA78BACB
+:10D58000AE6BCE106DC985F8A5440671517CC4F60A
+:10D590002694655F78E30AADE07F0AFB81FBA7E78D
+:10D5A000398F54EE67F6C28433245B5B0A71A6019F
+:10D5B000B87F2395BFCDFC565E8A7D91716C0A645D
+:10D5C000AEC6E4D6A72ACE23256969395BF68D82DB
+:10D5D0007A2FF1E23E89DA9F7D8BC7A1A85FFB20FD
+:10D5E000D0ED7A7E4E89AE483CD06FF5EF3E9A7B07
+:10D5F0002BCA8128B487FAFDDA9D1A3C67D0A1B501
+:10D600000F1C0F7EED9A0CDB5A5AFFCC9BF8E06B97
+:10D61000B46CB2FC887813FC5BBFE63BC4A7A8F7E8
+:10D62000F0B86F9B8EEA1F5AD6FFB78C7AA89E90EF
+:10D630000DB86EE40DFDCA20BD48DABFEDC7FF4846
+:10D640002AF76A0081A8172BA7DA69BF1AEE7F10A4
+:10D65000F226AB73BF8BB852A7DAE9B83589BCBFE5
+:10D66000EB21561F21DA1F66FD33C478FFAAC5FAE5
+:10D670001051E7E3E588FA7BAC9E22BEE767F5022E
+:10D680005137B3F1CDACFFEE6D3BA6823D22E4FDF8
+:10D690009E0CAE1F8B48113F9FB30FE57FE47329AB
+:10D6A000CA76AE1FE63D23BBF423617D2647BF0B40
+:10D6B000FCDD2EE119BAFADB7418EFFE26AEBD7060
+:10D6C0005590BF22CEB138AACC76B0FF1A5ECADA26
+:10D6D00022F3733D607F10BE1F5D2D9B707FE2D4EF
+:10D6E000DD4CEE47B2DF16AF794DB19E21EDB2C4ED
+:10D6F000FC71D8B8A3DF3B79CFE0CDE85FA47B71A4
+:10D70000FFFC588624F6E949795CE0DC58421AB1FE
+:10D7100083BF9AF03295CFB0C65F78511E2F7E99A5
+:10D72000C57F1B1E7913F5DE02D98AF1DCEBF29D71
+:10D730003D809F5EB317E38A8BD7ECC679FD9F1CB3
+:10D740006E3758FCF9C1F8FC3E14FFA7CF83FFD316
+:10D75000BF26FED571E765A63D08EFB28B3CDFD64C
+:10D760006B66FBA236BE4E4735D6511C5F719910D1
+:10D770003F5FE4CD8C95E1F0B177103BB7F44E19E3
+:10D78000F845A79ACD04D67DF6AA7F143AC3C47D86
+:10D79000D5FEC0CDF0CDC400BEAC9921F84DCF2C44
+:10D7A0003B277E95EDBF307E076B7D7A1BECA31E79
+:10D7B0002138CE28EF517DF0F99889994C0F0FEC64
+:10D7C00064FB46EA735F1333CDCC6EE2FB330DB5D9
+:10D7D000EF8C83FD19C10F13A2493BC4DB295DDB2C
+:10D7E000385DDB80AE05FD06F669E87B61F82B400D
+:10D7F000BF4471AEEF9A4C6E5F06F07A7DE6B9E9F0
+:10D8000056D9FE0BE3B583DAC3B8AFB9330AE329BF
+:10D810006A3CAFE47815F86ECD64FC1F09CFAD808B
+:10D82000E7C49F1FCFAD9956453C42E03B927E52E4
+:10D83000AF8F9877183E2DBB143ED5677339A5F589
+:10D84000E17953F5BA6F0CE5A77BCFC34FF7FE9A8A
+:10D85000FCA4C69BBAACE7FB9DEAE7CF678AF3015D
+:10D86000BF0C1EFF7F8BA7CF697E5DD13E6FCD7E43
+:10D8700045FB7CD701457D9CCF5B05642EE2E357D9
+:10D880009CF0BF09F54B8DB3478AAF4FD9B1440324
+:10D89000FB6FE55E16DF6FC8764A5974DDDED3B8DC
+:10D8A0005BCD14AF9777B7CBB81FE62EC27DC055BE
+:10D8B0007C8EDF8DFBD7A7B752BAF98E1830FEE900
+:10D8C000793D476B2D08A5838AD332B107D98915D5
+:10D8D000C6582DD85315D4520E4737FA2C467778B0
+:10D8E0001E88F2FB4C23D125503E9F3953C2F34F83
+:10D8F00033093B574D4B8F93B64FD1128F81D66B67
+:10D900004C5A8F01F7FD58DEC374364D62D01217A2
+:10D91000B4938478F483A7C1433A5FD92EE379B6F0
+:10D92000E9E56CBFF02653BB0EF4E98DFB6E3F7941
+:10D930002B6D27EB5C65ECDCB6C863FB587331FBE1
+:10D9400080FA2CC6E77D12DF5796743638E7AA7E38
+:10D95000EFE34C06EF1479AD0CE75FFC0708DADD66
+:10D9600082EF287CFB0CC52C4F630CC049749EAC25
+:10D9700018B09FEFAF82FEF587AC8897A6F2B58509
+:10D98000B08E4D13A5CF0D8501FFA669CDF768A711
+:10D9900057CBCFB742FF53475868FCF21E970CFE97
+:10D9A0004A207EE99B0B7C793E3F48CCBBBBC583BC
+:10D9B000F4F469CB3E2CDFBBE2ED32B0337C2DDEDC
+:10D9C000B0F1CB4B8D17883881881B0839F0D96DA1
+:10D9D0005583812E6D595C2E18A561201788969568
+:10D9E000425E8ECA0A91AF63B2CEAD5795EDBFB01D
+:10D9F0007CBD503AAF4F627A514DDF6ABA16F44C93
+:10DA00005F2B93E8776FA2F61EE8D559C455504FA7
+:10DA1000E5ECCC256DBAB1D2A5D3F532D317C92424
+:10DA20004CBECAC5CB732BC22F57C9E81F88F30A57
+:10DA3000621D1AB242ECA115E759B715BFE6BA85C7
+:10DA4000EAB52FE65E9A5E230A7BE0EE50B8DBCEA5
+:10DA50000377DBAF0A778A55E4D1CC953581BC11C9
+:10DA6000384F0C765C9F9BE545D6A5B4C5E0E1CC6C
+:10DA7000727F0CD88D4B77C94887446BD70EA1F4C1
+:10DA8000BA84D36B0FF17C00F4B864DC12CCA7AB82
+:10DA90007B2CFCB9E246DE7F99A9430F702EDBAAEE
+:10DAA000ECD7C8CF15D73FAF8C8B368EBBEA388CFE
+:10DAB000DBA83ACFF35216CF4B2C26C5ECDC85D22F
+:10DAC0003E5597BD2D4411AFEC3DD382F180DD5919
+:10DAD000FE075CC383FCFFD0F5DB97756E7B4ED9E8
+:10DAE000FE2BD3AD6CDE8AF955174BB76B73EDFF88
+:10DAF00080790B793C1B6413FDEEECD70C6E17ECB0
+:10DB00008F9659597C5372B7C27E5BDF4F04E3474F
+:10DB10000B789C33527EBA386F30FA90BB959D37A4
+:10DB2000B0CB902F3A6A9FA30AB62B4ADE69467B98
+:10DB300024E2BE95C8B3E2E7872E54AE89B8DEA8CA
+:10DB400013CD6867D9BC16B487C69C6E7F13F4E307
+:10DB5000CF15EF16FA706C3CC35BA9CF81765EAF30
+:10DB6000CE53F621D809AF4485B51362B3D9FA4D27
+:10DB700075CDD7B1BCC390FDC0D86CBA1E53B9FCEB
+:10DB8000D718ED3AC053B5DCF3E00CA01FAF8CF111
+:10DB9000BDD5BF7FFFCF8F5ACFEFF73759BE43BBFD
+:10DBA0002192FDDFA461F917C555563CE707FE1425
+:10DBB000C4F744BC4FDD7F426E651ACCAF5A1EE7F6
+:10DBC000B5C37C36B1F9445A9FA635DF2AE28B9162
+:10DBD000BEDFB4ABCCB220880F6ECE9684DF613945
+:10DBE000660CACEF85D2C178FF4C85FDF3FFBA5FC0
+:10DBF0003145A6A625D59F05929BD9AF84D9B1B34F
+:10DC00008917CBB9C48FA593B0F3F70B880DCB9BC5
+:10DC1000793EF3811CE74C58973E9D7F109E9F7C78
+:10DC2000E9DFF9403727AF18DB06DB5EBF941DD76D
+:10DC30005764C5EFF7EDFC77329C83399F5C589DA4
+:10DC4000645F9E1D66FFF9EF15F24C966FF518EABA
+:10DC5000891A7E1B0399C8F6D1484A0AD243402E3E
+:10DC60000EDE2CE422ECCF167CAE61E749964AEE3C
+:10DC70000CDAB5D3A741D62A5894E296A1DEC1DAD0
+:10DC80000B1A62DD12AD178C8E62ED2B62DD104730
+:10DC90009F437CC88FF3A82884723E61726F21B1C4
+:10DCA000B37C07E24F053B6C5197919DF727BE74FB
+:10DCB00090EF8511FC9FB7B299DF3C3295C9F39183
+:10DCC00095CA38C53D5C0EF4E6549EC8A6E5A96C1D
+:10DCD000FBBD80979171DE8D0F9462DC9E80FF709A
+:10DCE0007CF46F71BF51BC97985BF900F47B416283
+:10DCF000E7D35DBB0C783E82BE31C81174AEFF40E5
+:10DD00004ED523D0CFCDED928878257E45FE6C8010
+:10DD10009F5C38BF91E07361BC9C3E28C7EF62FDF9
+:10DD2000C5ECDA69EB4C18E37781DD9B98EB7C1648
+:10DD3000E7AF27C404F37FDCE0DE82F6697332C408
+:10DD40002B973C61D080DDF01155B79087F2498B5D
+:10DD500011CB7F503F18CACFA81F0CE5E7D40F8620
+:10DD6000F29FD40F8672D1E922AA2C283FE5D8DF92
+:10DD700064F41D3E4FAB4BE05B7C7F971EBFDF9B87
+:10DD8000E344FCF6AFF72BC40D9B3A2FC4FA87C6C9
+:10DD90009D83DE22CB198617B15FA86EDFCED7B583
+:10DDA000B0438BFABDB0D317B338A8DF816C3DCE3A
+:10DDB000B360E7179887DA6BE9C7AF5DA2204FD150
+:10DDC000B0FA81EC3AC46F6F8EFD04C04DF9FB30A0
+:10DDD00094859DEFFF01F27FE8F878EEA04FF23FC7
+:10DDE000847E800A0E351E045C2FC47A37C2FB2F56
+:10DDF000EC4C0548A8BC218C6F808EA470F0AEC599
+:10DE0000F95E6FF097425ECBF567E5B0E78C7B7308
+:10DE10002A10CFEB04BD093CF1F5BA54BEEEDFFF8A
+:10DE2000E6744AC43D1E203BADA087CEC480BD57DA
+:10DE3000C3F7F73B3BD2DF03F85CFB64926145FA22
+:10DE400055F0DDB01C4627A22CD8A577C03ABDB04E
+:10DE5000EB58FACD265C97F445B47F744E8622FECB
+:10DE60005830FAA7FF782001FB5BE0533792CDD5FD
+:10DE700070FE6496F1F5BF0248732C9F57C3F99367
+:10DE80007949D25E28E75B53AE847327E27CFCC2FB
+:10DE9000EC8ABDC04AD7DA6AD04EAB00E112A40FBB
+:10DEA000AA8CD1B029D85FAFB6C42BEA57250D5341
+:10DEB000F49F6C4D53B45F939DA76817DFBDD65692
+:10DEC000A2E83732CE9F0AFE198503F9816C93F1DF
+:10DED0009C5EC1CE4357E7D1FA94A7A6DBC02C794C
+:10DEE00081B74FD95EE586F5E8A3F8D45303EA4439
+:10DEF000F95D0F3D0083A9ECFFFA5D4FEEB55B2F96
+:10DF0000C2FE8F60F70B39BBBCCB580672F642FDE0
+:10DF100000F5FA8CCE51FA0591E8A69F2F242BA389
+:10DF20009BFD32D916866E08B99DD3212BA71C64A0
+:10DF3000F963172BCFBE0479161FE08FFE52159799
+:10DF40001BA9B7BDB70AE2F4EFCA04F3F1785EDFAC
+:10DF500062F85D0ED03BB979F31D4312F0B90BECBA
+:10DF60005CC82FB5D3F157E470FBA9FEF53B86944E
+:10DF700006DAC9EACF15FDC96DD27A457D5D8AB250
+:10DF80007E77C5FAE0F723C9C5C59BE6EB9D98FFF0
+:10DF900029D9DD61E483984FF51B5178AEEF3A380B
+:10DFA000AF421F35961ED0C23EEC7511F4A8903FCB
+:10DFB00037CAA4395CFB6D392CCE7FED1B51780E2E
+:10DFC000E662C7FD88E212CF19BECCF4E84703BD74
+:10DFD000DAE075BF93CFFB64D9FDBFFF11F6475F51
+:10DFE0002178EEF3642C93FF851DC7351AD0830387
+:10DFF00018BD145A7C1AD02B7D75D12E38D7DFB4BA
+:10E00000D4CCF25F52FD1F18E9D2DF97F3CE1F8DFB
+:10E0100074DD3E8624C820BDDA074E11AD6F7AE666
+:10E02000ED69EBE8FBD7BC11E5D15C023C9BF8BE87
+:10E03000C4C84AC6E773816EB87E81187BD31DA41D
+:10E040005FDF805C00F8A1FE5ECE7B87FE0876F87D
+:10E050007EC6E770C24EEDDFCF0AF2EFC9638C2FA8
+:10E060008DF4879D5352F1F79E36BDE99C7CDE8E80
+:10E07000E76E2E94BF77E4F03CE1C8FC7CF01ABA5E
+:10E080003E4DAFB07B2D4E7565605E6C247DDEB479
+:10E0900049463EECD75F5DF22437EA29651EBAC0D7
+:10E0A0002BB1DB903FC5FD512BC7FFAB16F4E6CA81
+:10E0B0005D5A764824D27736C8C41AF49D17761B69
+:10E0C000EA30CF8DCFBF4FE8EB5D3FC455E4B3726C
+:10E0D0006D18BD47F5B42E01F4748D847EE5E15DC5
+:10E0E000832B014F8725E2B162DE163BA73C950DDD
+:10E0F00007CF4D786F4952369E4F16FEA5F02BA7DD
+:10E10000EF9A9E0176E5071D0B0ED39523C772D2B9
+:10E11000908F661017DAC187631D23202E31859FEB
+:10E120000F381CEBEF01B97C787CB404FBFD74FC68
+:10E130007530BE80EBB0CE3182DD3F21CE25E75E6B
+:10E14000D27D71D5F26D15D7C0FEF66C6201BFF2BB
+:10E150007A99D9B9E42F8C3F85DC6B92BC7130CFB2
+:10E160000339B5A773289E06AFB997C75539DEB4F2
+:10E17000EC1CE285DAB9FDFEECD312BB17C5C6EC88
+:10E18000FFC671DF3C3803F2E4A8DF2DD1F92CE89B
+:10E190007C1DEFFF51FBD9FDFECEFF309E1AEA2F0A
+:10E1A00039E27283E2E46ABFA9DF4E17F6DE367603
+:10E1B0004EFECDF10FF72EA7F5D5DBA2118F5F3DF7
+:10E1C0006170811CFF6A8B01FD9FAFE2FCDDABA09B
+:10E1D000BEBDC0E6C2AFD914F7A32DD1583F04FD90
+:10E1E00043FEA6C37B3D8E3F6EF0C0798FA54FE600
+:10E1F0006C017FEAF808EB73CF433CF0B944BC678D
+:10E200008038D9FBD7717E04FEB252D343FE2F3340
+:10E21000DA114B770C413926D6EFC4E3519847FF0A
+:10E22000D5BEA903215ED6A37911F378886C7281DB
+:10E230003C5EBE250AEDC035166729C05FF55FD785
+:10E24000CD2881EFBF9F48009EBEAE1D18AF0CAC1D
+:10E250006F78FD7EAA2B8DC9817E7DCBCEDDCE83EE
+:10E2600073B76978EE760C8CDF40C4FD8BECDC6D07
+:10E27000B12CD931EFE09EF079E4D7E432FBB15E06
+:10E28000C44FE2893109F8D04910DEBE7BB2B680B6
+:10E29000BFB330378E7FD7CFF32505BD7537BE8628
+:10E2A000F113033BEF17157E1F7B462ECB2B5E6CC5
+:10E2B000FC5E11BF695CF39322AED2984F50EF160B
+:10E2C000B75A4B56D07215C7F3EA54C74D00DFB2A8
+:10E2D000F6FB5F7A07F1F2D86F3E86EFEE3361DC32
+:10E2E00086BCC3F0A7F667161BBFE5FCB4596107EF
+:10E2F0001F7BE4433C6F726C675E21ACDB02D97B11
+:10E300000CEEE5EA357B3FBD9596DBF71DC47551F4
+:10E31000CF3764DF5E6272A51EE08887F32E8EE63B
+:10E320005CDC1766FC7E746301E24FC473FBBE0ABB
+:10E33000EF6F89798AF1C5FCC4F8A2DFFFE2EB75C3
+:10E3400052EF2D04FD9C06FB166581F69331DEC26B
+:10E3500058133C67792D27E3683D886E7EA9FD9DA3
+:10E360009B789CE78866ED2D7A4A7F3DED0FE89C0F
+:10E37000C172F422F775C47CC5B9529147FB9FB9AD
+:10E380003C9E3D828C88907FFB646E59D8FC5B7C00
+:10E390001E29FFB63FDFF607966F2BF26B4BAB34AF
+:10E3A000CDC179B6421E96E6D1E7F9B0EFAFD4EF12
+:10E3B000A52395FD23C9C7F1796C1D4BE3C3E7BBCA
+:10E3C0001EE2EBDC4A3CEC1E42AE17C772BC8BFB74
+:10E3D000BF849DD2C8E5B6C8F31CDBC5CE6D8EE503
+:10E3E000793B540A609E6BC83D6F4979A857C53D7B
+:10E3F0007D121D6B765CB87C612FCEE30AE2C7D23A
+:10E400004E2C5A2829FAB19C481C585E499AB19C56
+:10E4100044DAB0BC9AB463792DF16249723DFCBC18
+:10E42000E76D2CCF74F2120DE8D7D219E1EDE21F9F
+:10E43000CF8B0717DE2378B178B892B0FBFE42F09D
+:10E44000313C1BE95B8D0F75BEE678E2C38B4B2632
+:10E4500000E1A6811F6CC5F3AD55C48EF5EA0BC46F
+:10E4600043B9CFA965F9BD2A7C5485A78BB31C1F7E
+:10E470001B40779605D6A9348FC901B15ED4114BE4
+:10E4800002F9AF5E47F1BC34BAF23B2B1511C3F26F
+:10E49000EE988E79DC2595ABD268BDE0B907597D41
+:10E4A0006CE50EC8F31E99F7F074CCFB1E5959A207
+:10E4B000B3C17D729BA64FA4ED4E7E6EDAC9CF4BE1
+:10E4C000136791E29E2CE7DA5BF0DE31E708930DEB
+:10E4D000E01479E1721ADB5F4D9EE4794347FBED6E
+:10E4E000B23807E595C139734F8C15EC84B5D578F2
+:10E4F0007FD49D7AD65FDC6723E013F7DC6CDF9E68
+:10E50000B74A4A3DFF3CE8F8E97989309F0CCC8F47
+:10E5100073EE94783E5CE5E099546EF4787504F2FD
+:10E520000BC4F72CA9CE1C980F81A478CA17C3B8C6
+:10E530001EEED99E9707EB549AC7F30713524A0071
+:10E540008F0B521DA5D05FE44597C2BA24462E67B3
+:10E55000E7D98BA1BFFAB9C8CBAECE7396437B5334
+:10E56000F419CC37EB2D7A7FBD2F25344FBDD54E16
+:10E57000DC7A942BCAFCF4BE457ABCCFA9D4E16CFA
+:10E580008523CA97CFF68FC27CE13C67158EABF727
+:10E590002517D1F7FE3895E5BFABF3BD77EDDEAFBC
+:10E5A000C86F177CD69FDF7E8AE5B707F8EB9155D9
+:10E5B0002428BF5DF08DE0BB3190DF1E03F59C4544
+:10E5C000D06FFCFBDD98DF3EA1DBC7F3DB3F54E6F9
+:10E5D000B7DBFF7549F9EDC7F9BD6FC78DECBE24F8
+:10E5E000719FD4CA9D6CFF77A5C4EE935AF9277624
+:10E5F0009F94F00BEB387C0DFBB7AD877DBEBAC79F
+:10E6000016E27D5484DF876AA53FC17EA1B89F547E
+:10E610009D07D304FE20DACD1EB4BBD4F9304D8F54
+:10E6200055A13FD8A4B2A36FC9E3F11DAECF08B77F
+:10E63000FF96F077010E13FA677AB43B573EBECAD5
+:10E6400066813AE72BB2EF7912DC9F3C168FB4203B
+:10E65000F86CE90609ED5781BF914F19EC789FF1ED
+:10E660005383D16EA5F636CF6376337F9BD20A9C57
+:10E67000877F21D69F0A76F20BBBB26D54C29257A8
+:10E6800023DE43FDBCEA1EEA2715F7509F82FF8177
+:10E690009D7642E386714691ECFBC6D17AD909ADED
+:10E6A000CD6D0DDCCB7CBEFB8705FE0D7CBD2EF653
+:10E6B0003E62F5BDCF22FF417D2FF19DFC5EE2F170
+:10E6C00011EE2536C85D32DA0FDF6B15F7135FCE1A
+:10E6D000E12CB71237DCF73BA647AB58FF725F1B44
+:10E6E000017B28EA90561147305895F597F3787CCE
+:10E6F00080DF2F128A6F533F3E0D88CFF487119F22
+:10E70000AAFB9E059EFAEF7B1E6E42BA1FB37F875F
+:10E710000CF2E062EFFDFEB5EFF93EDFBDDEEAFB95
+:10E72000BAD5F77347BAEF5BAC7B9167A5A2BF7A06
+:10E73000DD4BF6FD4E791F355F6F17FDF939D7FBBD
+:10E7400007D57AFF1B2E40A37CF8F7981377035B5D
+:10E750004E896672ADDFAF1FA7433FEB3D6B7C95E3
+:10E7600019F89FEB2907D753E4B676DC8777707AE0
+:10E77000B179D93982E223ECFE8A521F3B4F30EA4D
+:10E7800044F8FCA0EBCB25C5FE6EE8FDC52CCF7888
+:10E79000EC19764E4FBDEF2FF2866AEC51CAFB1B87
+:10E7A00022E41189380EB5E3891EEC780DBBCF2E1B
+:10E7B000CC7DC79BE4B4E03C2227C677A619BDC92F
+:10E7C00040CFF129CECBF21303F9461320AF4842D4
+:10E7D0007F90E7E124DC0071C73E48B21D4AC8675C
+:10E7E00077C7DE80F70624108B6F1473777176F984
+:10E7F000CE6C18E7A864595F42DFFDFB986F924129
+:10E800003F19605FBB18F77D73A15D7D4FBF4F63FC
+:10E8100045FBC2F53B09FD876F60B0D141FCBA41B1
+:10E82000C7F31A557FC780FB53E2EF181CA543D4EA
+:10E8300051B93DA793E5512F4FEAE17E18BBC7754B
+:10E84000E17013DEFF44EC2536E6870BFF6A987C07
+:10E85000317AF37CE78B96277DA5F073C9F3F11726
+:10E86000B49F18809B8D7FF4AE68D43747EF1A8130
+:10E8700071BEC0F8BDE8F7CF69569E339EB7E62358
+:10E8800005FDCD777DAE68F725F875C328FCBE97EA
+:10E89000865C398BE2EFE44EC328E033BA6EF3F2C4
+:10E8A00083FC7BDF3D5913991D703E38BFC17974DD
+:10E8B000F373A202CE4F5B8E60DDD7E2539DE7710A
+:10E8C00029FC5251EADF20784F8E5F1A600B1767E0
+:10E8D000399ECFECF66E9E07D9CDF320BB79DE6270
+:10E8E00037CF53ECE6798A227FB45B2276384F31FA
+:10E8F0005B723C315FC2FCD1DB00CEA665FE42C834
+:10E90000B76B1AE99B2BC9983FDA925F16367FB432
+:10E9100010F2DE5F797EF60D60D79F18E0C27B496A
+:10E920005ECC9F7903D8F527F48C3F5E7FBEF2065C
+:10E93000C81B7B7CA8F32E18E74B49F6203DBF226D
+:10E94000E17E2AB1FBF4B5E7C82F6DCB67FB0BF76F
+:10E95000E7B37D0C513E97CFE4D9EBBCAC96EFCE3C
+:10E96000C4BC9F4D06CCFBA1DFB16B82F6FFD5F98D
+:10E9700059C57F3178406E8838CCD67CB6CF0A79BD
+:10E980005B30BF84FB0C2C6FCBE74D863C2F38EF00
+:10E9900003F7669043C4CEF2C0D8FD7D621DB6E693
+:10E9A000F3736770A17E69204FAC61FFD14F418E38
+:10E9B0005C97EF7C1AF99FE72F35C4BC8EE7265E83
+:10E9C000CDB7E27B74BE083F9507EB24C473481CA7
+:10E9D000AE3DBF2C34FF3D12FC2717791FCA4F09EB
+:10E9E000E44F05E54DBD0AF310708B7904C6393745
+:10E9F0005D8B785220DE756726F049B78ED97BE2B1
+:10EA0000BEDA62599A574BEB6F71BC88FE9FF2F5E4
+:10EA10005C9DEAD80FF358D6CCE26EA2BD4F6AFBDC
+:10EA2000CDC7B06EFB4D28EFD4DF17EFABE16DD84B
+:10EA3000BD1FF142E19D0B7006C1FB617E507CF071
+:10EA4000E4AE0F1F02945F2A9C179BCF6C18C0EE98
+:10EA5000450C8D4BD3850DB2A70CE2FDE1CAFBC678
+:10EA60000CF0F711E8F73AB81FD2C1FD904E1DFF28
+:10EA7000FB352ABFB4C3CBCEF57424E9F1DC0EE13B
+:10EA80007F6F41E8E1D507D8399FD52904DB617E46
+:10EA9000C00F926F2FEA85FE7BA324AAEF285D7C2E
+:10EAA00063719202A06BE72AD413F265261BD0F59E
+:10EAB000F6BF5DCDFD2BA677CAB89E298371008E67
+:10EAC000FC81A87F4AF97747199BD1BE1D4D5C3C5C
+:10EAD000DEC2E31277ED55F865FF17386EB02750A8
+:10EAE00068000000000000001F8B0800000000000C
+:10EAF000000BFB51CFC0F0038AAF9B3330E4593198
+:10EB000030CCB1666060B56160683047C8BD114700
+:10EB1000B0A9897FCB53A67F932403C31620DE06BA
+:10EB2000C43B2449D7CFAD8D6037AB3230F000F90C
+:10EB300021409A558381E1B51603032F903F03C806
+:10EB4000DF03C42780580528F612480BAB31307C10
+:10EB500001D27C40796D20FB8A1A76F3F9B5F1DB9E
+:10EB60007F5C0395FF138DFF401DBFFE2C4D02E11E
+:10EB70004B401E1BE6B3273F3E8228D03B10F830A7
+:10EB80005ABA7E6CC2C0F0CB9481C10E9AF60F20A7
+:10EB9000C90700C59E9840E34D8F81E1961903C3D4
+:10EBA0005E1CF9E20450FE36503EC61CBFFD0ACC86
+:10EBB000A87C615E4C35DF9810ECC942A872C7840E
+:10EBC00031D5F38A323000002621667DD80300005B
+:10EBD00000000000000000001F8B08000000000083
+:10EBE000000BE57D0D7C54D599F7B973EFDC99499D
+:10EBF0006E269310C24002CE2411A2243040C09849
+:10EC00004CE0E68B041270F87829565A27E8226DFA
+:10EC10004111DDAEEF2E2DC347435454D8A26BAD46
+:10EC2000BFDD812AEDEE6BFB0B162D9B049D8480CE
+:10EC300068F88868B5AE6D376AD7061B6C88C1D294
+:10EC4000DF4BCB7B9EE79C93997B33930475B7FB9B
+:10EC5000BEAFFCFCDDDC7BCF3D1FCF799EE7FC9F88
+:10EC60008F73C66AB111D775845C85FF1610327F29
+:10EC70002221646EF42A9E57D8492879262169F604
+:10EC8000435D33320859A8C9BE1A0F2113EC0D9DFC
+:10EC9000A488903262F3D8BC84B44B3FEB9A41EF26
+:10ECA0004FA4587D3602FFDD4BC83C4236DBE99F5E
+:10ECB000B4FC894BF44ABF3FF1474B98488454CB8E
+:10ECC000F54482EFED122FAF6B4B3209A922ECBF56
+:10ECD000F99748152D46AADC77D593198454BA685C
+:10ECE000293B7B7795952784962F25AC7EDD6E7C1E
+:10ECF0005F4A765F949D70D72F070A697D5754E36A
+:10ED00007B77CD6F8913CAC53C8771C01F940653AA
+:10ED1000494AC687C9F4EF9BC84D57657A55C61155
+:10ED20007273942EE62B212142C613D2C2BF5748DC
+:10ED30006006DC13F23CB69F2EE858DB43DC74DC43
+:10ED400019C5C457430738A1566F07BA9456A91E70
+:10ED50001BBD6FAF9E37B14723E4BB179AB3480181
+:10ED6000FD3CBC01E998C1E9D87EE1C577EFA6DF9B
+:10ED7000FB6B89CF46EF5BADBE898182E1FDF1D7A8
+:10ED8000A63B08AD676FA02319EB21E4CF57337979
+:10ED90003DB984B40572528371BE13D7C7B6BA08A1
+:10EDA000B145EFF7E8A4B6591B5EEE4598CCB950D3
+:10EDB000FD1AEC6729A7E57725B2BA19DB5D8DF35B
+:10EDC000D4CAFBDFA97724F714C0FB48B2858E2391
+:10EDD00074D1429EA555B4F55524417FB7EB9608F2
+:10EDE0003C6FEB53C3400FE26ECE5A5638BCFFADBA
+:10EDF00017D7CEC671053718DAFDFB3E3A5E0DC651
+:10EE0000F77CF2425ACF409FC525D379DDCB9FB71F
+:10EE1000069B935DF05D6F3ACEE7635BE9DFD3124B
+:10EE2000D3E3B1F95FCF096A50CE6EA447DFC0C902
+:10EE30005C3A6F6DFB141F8C6B347AFE3D6F47DCC0
+:10EE4000A7FB22952E5AAFBFDF27811CA5F71132F1
+:10EE5000CE0B72D176CC09F35B4F502EFC810AC7E2
+:10EE6000F56C1C3ED903EF4FC9C01F7E5704C73154
+:10EE7000D41FE8DF34E8A71BAF4FF2F69E8079C4B9
+:10EE8000F16D774CA5FD1D2856B09E03FAF672056C
+:10EE9000EBBB1291811F37307ECAF004B75981FE57
+:10EEA00077125FC803F5121CF73FF2F13FCDEB1369
+:10EEB000EDB4F5A5972BD0BFD5C40762522D6F696D
+:10EEC00087EFFDEB59FFA73CB04902FA5DB7A507F4
+:10EED000AF61DECF3DF03D2D90BDA95F02BA4DBEC2
+:10EEE0003F82D77DDB7ED90EFD4BDD491CA00BF6A2
+:10EEF0005659D2E0BBBD0B2739E0BD3340059FEA30
+:10EF000003BFCF756F271DCFBE2A05FBB9AF8FD2C8
+:10EF10009F9673865C3E906B67C8C3AF3E1F946F2D
+:10EF2000E5E338CADB7D998FC719D279B94D055011
+:10EF3000CE190AE135CCC7493C1B91EF360BBEB365
+:10EF4000066F8479CB18246E42E5F9E8A78B274237
+:10EF5000BBA27E73F9834FB5CC817E8F1F24EF59FE
+:10EF600067C035D200ED4D837138E1BEBB41423DF3
+:10EF7000154639F2F75908C98FEAA90CB2ECD55BEE
+:10EF8000F0AE1AE548E881D23ED522A5C6CA591589
+:10EF9000CAC13E2E07557D11E4132A67C72C944E33
+:10EFA000A10B54CE287FB5062C38DFCFF4ABA88751
+:10EFB000497E246B59CA70396ABBB86E36F45BC897
+:10EFC000D370FDF1FF867CEDA3E308C6D16BA23DB3
+:10EFD000216FE6F7A3CA9B2B84F2D646E52D04F4F5
+:10EFE0000C581C79207F4D1694137755733B9397DB
+:10EFF0000D286F1977B2FE4C58134639184DEEF6AE
+:10F00000795CE50AD4BF9AC9695BDFFBDB6C301F12
+:10F010006B08D71357DAE1DEFF00936BB39C99E5D9
+:10F0200030D5DF8DF2E9DDD94FE0EAD9518F7C4D43
+:10F030005B71A0FC2590C33690C3A2FF7FE4B012A1
+:10F04000D6712A7769DAAC4E171DF7A27EC2F0900E
+:10F05000B6B713D6F1EA6C1B5BC727BF7DDB3DF467
+:10F06000FEA43519E97F723C7D5804F732CA5DBBB6
+:10F070007757F666FA7E518684EF09598FF25D2341
+:10F08000F0123CA2F253DE239179E950EE833D95D4
+:10F09000F4FB577B890F5EBD9A2D637DC7FA0893F9
+:10F0A000632E9F357CBCC7F8FB81CB240CF2B900E2
+:10F0B00020097DFEE9F9FE2976FAEAF7962B8524E8
+:10F0C00087AEC79C6F05CEA8E6F2FF6A86AC83DEEA
+:10F0D00038B625254CBC585F04F8EDD5076C61990E
+:10F0E000B6379097FB5C8400FEEB9FBA99BEEF7435
+:10F0F0007D92122B9FBD7C1E3EE2F3DBC7F144CB19
+:10F10000F4C03289E2A257F37251BE06F23E994230
+:10F1100028A9EFC9FDC3877025A4590DA40CAF47DA
+:10F120007CDFE50E7E59A2F3D31BFEC009F37DE11F
+:10F13000F02733E04ADCE310778D86CF4A040EEBEC
+:10F140006DDE01388454513E9917E59309BDCDC752
+:10F15000806E257D0C8F91DA8D0C67BA185D28FEC4
+:10F16000CA82EF5EE2FD6A3D4F719A86E50CF5B406
+:10F170005A7BD60458FDF87D898BCDEB907EE174E7
+:10F180007F529208C3896CFE4AF8F77EA5F9BB80CE
+:10F19000B7FD2765DF36FA9DFF724F1589A3870EED
+:10F1A0004869C8AF65FD467E6DBD705006BAD0FE99
+:10F1B000CAD0DFD2DE6699E971C66725621DE97D96
+:10F1C000DEA0DF45FBADBDCF239E1FE855505F2578
+:10F1D000A26B071FC74B5C9FB4F179A20C85FD3F62
+:10F1E00046FBFFD008DF570233C6F45BC8DF82CB93
+:10F1F0004906BC5ED69F6EC2FFC6FECE57587BF353
+:10F20000815E2431BDB648E9BCFECF462FB35E1106
+:10F21000F5B6021D0B86F78B00538B7ECBFFFDE905
+:10F22000DA067F30FBE504C819E93924833C56CB64
+:10F230001AEA93D22A89E1723ECE7AF89636552B95
+:10F24000E4CA23A19DB7D82F856B006FF87E807626
+:10F25000E24091CD037A688267AFD213C36F8BF916
+:10F26000F7A2DF47B7EA38DEF6B96F6741B9A3D72F
+:10F270006FCB867958E4793B7933A5FF092E772D3A
+:10F280005B6BB15CE965F2C82C98973C2667F3F993
+:10F29000583AB9DEE9E0747B99AF9B6F6D0DE2F5EA
+:10F2A000CDADEBF17A6EEB26BCBE7AF9790DE6AF07
+:10F2B0002B3F17D7AF5AA5598967579598D6859789
+:10F2C0003C14EFD0F2757D6B77CFA2E33E75D98207
+:10F2D000FAF9547EEE8878A585CFAF28F78AFB0728
+:10F2E0009540B7FA5EDA5DEFF0F2A5BDC6764B89C0
+:10F2F000D40CF8AFD4F7BA42A87DB4A468BF168B7B
+:10F30000635A2F641642BDADD2AF56CCF124EE47FE
+:10F31000A9BF1BC7B924F28EE249495CEEB4D25DA5
+:10F320003F07ED54A68F4A7DEF55E9B4BD9A82FDA3
+:10F33000F5C817838A05F8A2BEE0109F5F17CEC7F5
+:10F3400012B19E15C9B561E84FDF00F6B3AB401EA0
+:10F350000FFD7BC822235F2EF1D810CF266C7F5083
+:10F360002111902F2582F3748AD6037C719ACA31B9
+:10F370007BDECDEE69BDF0BEDD6BD37C404FB7F0D8
+:10F3800047AC37F0477DDE9C53BE22584F64C4978C
+:10F390005D972B94347A7F1AD6574F943F4B397F21
+:10F3A0009E8679073E0ECBB8FE09BC2CEA3B7A3923
+:10F3B000E79122DADEE9B035EEF7812AA33CDEE2FE
+:10F3C0004E36DC57658F33DC9FEE9BFD6600DAA37B
+:10F3D000FD073C47421B0CFD3F0AFA0BDA7349B8A4
+:10F3E000FE9FB852D5770F940B1BFB65EE47D7E510
+:10F3F0009CC757D27A4F1D96914FABDCC67E555EA7
+:10F400007AF314E8A73AAA5F806E2FE98A0EE33EEA
+:10F410007D3825BC8DF2E54B05AF27036EA0FF6953
+:10F420004B683B9584CD6F4586B19E537DEF3F3C45
+:10F4300013F0AE5D463D57F1C78E9D00AFCE16DD91
+:10F44000D709746E2512D2A9ECC20119EA5B1536F0
+:10F450007EBF728D913E1B578E33E97FA37FA9D269
+:10F46000C3FC44F37D17B1BE12F0FFD0FB0ACDE818
+:10F47000179A0FCA20A6DE32935FA8C4C3FC4225A8
+:10F48000E01712E5BC6498DEA7F7D8BEDFB4AE9BE8
+:10F49000E53BA1FC5BC87AF0A790FEE5A3E096ED02
+:10F4A000DCBF62D4B744D927C5E28A166B7332E257
+:10F4B00086594C7F91FEF4B8FE2AB31E21E43EE447
+:10F4C0002B4147E20A918C79307E5EC6ACFF385DF5
+:10F4D0009AE8745CC57520C4F18B27AEBC9BBFCF86
+:10F4E000E6F2BEB097EA4D58AF7DB20BF4C6A9CB99
+:10F4F0004403793C4BF99DB5DC7335966FEB7A9BF1
+:10F50000912F69795C064F5DF6A1FC062632F96DF4
+:10F51000F7D628694C7FC69577B31CF492D0134573
+:10F52000745E4FE5E53EBE927ED77558E8018B8E3E
+:10F53000727598E1DED37D9B915F0728BF02D98762
+:10F54000CBFD392D76DDFFAF9277B39C0FC9FF302D
+:10F5500079677AEBD4A005C7537949C17AEAAE102E
+:10F560005CC7CDF27F9ADB6F2FE96F6A3E580F0BB5
+:10F570003E40FB987C66796776486B2FC1F6CB2EB0
+:10F58000BC2FD3917F61F22EE45CC8ED35CBFB7FBD
+:10F59000919C9B9F7FD3C2717F02398DCA7F08CB1C
+:10F5A000ED4821F9E0676B91927CDBBD20EFCCEF59
+:10F5B000632E3F4E16FE587BE837745C0D9459520B
+:10F5C00029A937929E29C00F13267AF0FDDD969E59
+:10F5D0004CB8FF3DE9CF9C4EAF250A3902EBAFA4F2
+:10F5E00013F200ED92E4719135B309794C0EDA65AE
+:10F5F0005A5EEA8DFC51A27426F7130FE0C16952DE
+:10F6000030199EDB289D345A9E28E710271212419C
+:10F610007A2DE542B7D4AE45D00F5F6CEDEB117497
+:10F62000C7F5638DEBC3E9B45E1291AE4E8F8EF3D6
+:10F63000A0359CE5D3609CE1EFDF0D7EABEFA9BE6A
+:10F6400067E3D0DDF219C709EA07E96961F40C59EB
+:10F65000927CCFC6C15B8BAEBDFEB792E8B514E815
+:10F660003873381DA53E4A3FA083F2E7AB6027966A
+:10F67000BA197FC9BF5775F0D310D91EBE3E4E3F91
+:10F6800036F27E3C26EB37516443E4CA66A44F2B26
+:10F69000CCBF06F4CB20DF8CE1AF85B28AE393EBDD
+:10F6A000C8265C5F48C4027A64B4F9B02A44916108
+:10F6B0001EBBAFA2DE6DE4FDB3D1E7DAECC4F325E7
+:10F6C000D7F9FA23749EC8EFD93CB52E32F2E5166D
+:10F6D000DEFFFB78BF403DA17D04F5537AC9BF53DF
+:10F6E00037C55B27760BFA737A99CBB7DECAC62F7C
+:10F6F000CAEF92993C85AE7DDE564DC84D3C6F8277
+:10F70000DFA5BE1389E66F53388E7CCF932D7CBC6A
+:10F7100021692CF2B090F3A55C49E70DC6576DA4A2
+:10F72000E30E3EAE35BCDEDB25FD7F023F4C93028F
+:10F730007F075752D58DF2073C0EE5A613FD5BFC03
+:10F74000FD569053526B7C4F9F6FC7EF5677637C8B
+:10F750004A3C3F26E93B65F6BE11BFD38DEF291F1A
+:10F7600036C173CA2F449E0DCF3DD81FCA27C44E41
+:10F77000EF1BF7DFF165A02BFDFE51AC9F9C337CA6
+:10F780006F050591CEAED26C767D0AF88EDBA73B75
+:10F7900056EB4857956CE2F6335BCFE6F3F5CCFEBB
+:10F7A00047B60E0EB854F46B290E3D1CA1D7745702
+:10F7B0004407BFF338D21D027B6CD54AD9A0E75766
+:10F7C0009BD6972FDF695C7FD76CC832DC7FF5FE54
+:10F7D0005CC37D70CB74437D6B77CE31DCDFB9BB0E
+:10F7E000D470BF6E5FA5E1FBF54FD719DE7FFD99A1
+:10F7F0001586FB0DCFDD1637BE29D6BB072DEF6D65
+:10F8000008D071ED805731785189C62F2D0C8F1992
+:10F81000BFA3ECE751E6413982AE08339F2AA6F830
+:10F8200067CF90FC6C36ACB71D216F064005DDAB91
+:10F830006888FF437A775E66140F547AD6D5C75B23
+:10F840007F457F145EAE9CF454C2BCE98AB19CC271
+:10F85000E3B59AAF1FFD30E678ADE25988EBBBB94E
+:10F86000BFEFCA2919A09768DD1E8CD36A635B4F6E
+:10F87000471D1FD584631A1F6FAF1CC6999B785C08
+:10F88000F38BFA65E8DE58C715EDA711F78838F94C
+:10F8900012569494789F417B6C09F40FD6E7228628
+:10F8A00077ECF41F5B6719FDEB78F9C0FD2E2BE0B8
+:10F8B000E34095B19F751C47513954404F94E49BE8
+:10F8C000DE433F674039235EEAE4FCA8293C5E3E04
+:10F8D0008FCCC379E072BB4CC86D35F3731057FC05
+:10F8E00038FAE2CBB4D01C6CDF907FF05A7E6E12F7
+:10F8F0007CB7A489786C149F3C38779BAB0270BEB0
+:10F900006EF5D5D2D2953EEE6FD265C4B3D7E5B3CE
+:10F91000FBFA2AE67F5A1CEC463F60FD9DE16D70C4
+:10F920009DB43EA2603F4C747DCA134E436CC0E947
+:10F930009BC5E99525E8CAE928F4F8A40DC679AC79
+:10F940002F32D26B29A7A799CE4B391D979AE87809
+:10F9500014FEA074999B808E4B381EB5CFE5F6DD62
+:10F96000607A5CBBF129EE1F13FCA398D635A13F4A
+:10F9700086D637CEBF8F811E079CE7E23885AF7BE6
+:10F9800089E4A83CAF614F39F8C933AC86F8C54269
+:10F990003ED6923C16EF28C99011F797B8DF88EB56
+:10F9A00067067A57CF8BF2E7D15E667F34BACFC94C
+:10F9B000304F75790CE7EFE4F411FEBF56EE1735C2
+:10F9C000F7EBC4945036E0A3939742D99B8BC0FFCA
+:10F9D00023219FB4CDBA379BE50BB07EFA797BAF7C
+:10F9E0005C0CA1FD76B277E4F8A2C0F966BE29F1FD
+:10F9F0008531CE5802FE62DA5E6D3F5D83E8D01736
+:10FA000046FE59F61402AE8E28D09F7AF75A05FDAD
+:10FA100065EE0605FCCBB5EEFD95400F3F09EF7096
+:10FA2000825FCD23F92240C70226BFEBE9BF58F918
+:10FA300015FDADE90B2A20EF351EA35DE3E7FC566B
+:10FA4000ED363DCFAB417EF39BF86DBBE0B3EBC928
+:10FA5000F5B17CE6E7F3A25ECCE1F21A9FCF44FC5D
+:10FA6000E2DFB99FF5573C4EF72E8FEBBDB3D58340
+:10FA7000D757B6E6E3F3E35B7D78FFF6D662BCFFCB
+:10FA800039F879E9FD1BDC8FFBFAD600DE9FDDBA81
+:10FA90001AEFBBB89F56F0F12E1E4FA996DBD0BFD0
+:10FAA00058E70BDA5D31FC54C7FB8DAC0F38A4204E
+:10FAB000BEFFD536E58802FC756E484E08EA8BE538
+:10FAC000F5DE030F51BAD8BE4D82802B6D1DFFAA03
+:10FAD0004CA5FC5F57EBB5AE83F642CDCA1CE0C720
+:10FAE000C8BF2AB9F0BC7E96F58E38ED8B7612B57C
+:10FAF0006FD66F2B6A8D76B05FF8D1FB832118E744
+:10FB000084FE6004FAE777AB9E787EE1F689EBDC51
+:10FB1000C04F8D17836EE0A7C689276466AF337F19
+:10FB2000B8CAF95494F7BB8DF17C95F7BB8D3E872D
+:10FB3000FEB6F58F4D0E44B952A559766989C7674F
+:10FB4000F637ED94E2DBAD4956866B9D3CBE4A75B7
+:10FB5000A60272062C0AFD9F40D906E44BD398DF1B
+:10FB600022D917E47AD9B88EA7150702A097B40C4A
+:10FB7000E2AB01F5A6F5B8816FE4E285E7619D256A
+:10FB800005317A1BEC1EB3FD1F7B2FE3D2154A49CA
+:10FB900087ABB91CA3AFC659A86916EBDFA3DCCFAE
+:10FBA00021E8AB71FA96784EFE02F4EAA33EE68FA6
+:10FBB000793483C565078AD7222E2BE176818DECB7
+:10FBC000C1F249A419AF3B38BD078ACF11907B59C8
+:10FBD000A1B83903FA630F87E8F74E937E573423B1
+:10FBE000BD254A933580AF7B1583BD2115333D6F0D
+:10FBF000077B1DEC188E5FA2765E905C05E28F118C
+:10FC00004FEDB41AED3171ED552CC80F2EAB299F75
+:10FC1000EEFF7AFA9DF842E927ECC4219C77EC6B61
+:10FC200004E231229F50947FC5E46F52B3591CC641
+:10FC30005CEF2D5646F705568E8F059EF09BDB71C7
+:10FC400084809E2AB5A71CD2F07A12B5477A678FB6
+:10FC5000E2B7DE86ED9F555CCC9EE0F940D42C9750
+:10FC60000CF6895D77837D38EC7BB7C520A7C3FB95
+:10FC7000CDE8F345F777093548E1BA54E8E1628603
+:10FC8000279779289EA47F2ED3189F9E2997C2DBA1
+:10FC9000914F7583BD555B5C731EF512B547D479E2
+:10FCA0001CA7D3FE3741BDB49ED7278AEF86F489BF
+:10FCB000E5EACCE1F504AA18EE21A17F5914EB3F47
+:10FCC000085076C99F0DF5B2EF69D1F6ABF1FAC1D4
+:10FCD000F556A0F8DEA59A13EE75E949C07B05310B
+:10FCE000F800E89A6733D2D9A4FFAA86E93DA3BEFB
+:10FCF0005D48F9F7086DA756DE540F2EEF9ABD6BDD
+:10FD00000FBF8ADD117688276EBDA7E08F9B01FDAE
+:10FD100019F10AF1B13C8ECA90A71EE99E2191B05B
+:10FD200017FA6FECC7C26C931D96611EC71E9CC765
+:10FD30000E85AE2374BE3AE83CEE41FB38BE3D254D
+:10FD4000ECBC05DE41B4A784BD47B8BDE7A2FF62A5
+:10FD5000F158192F5F7EBF4701FC5B6E37F9998719
+:10FD6000F28F09DA530B88B1BF65DCEE2B33D97DF6
+:10FD700042DE5F14FA52D8B55C1FDE22ECA9B291C4
+:10FD8000E3CB9DA67CBA2ADAF1E66B900302BD8232
+:10FD9000781319A29381BFDABD539B2394AEB7F8B1
+:10FDA0001C2CDE42FBA9087D8E7462387B292F7FD4
+:10FDB0008B4745FEF76B2C7E513F8ADFC25FCCE25A
+:10FDC0000667ED125B0F42E44D12931F5EE961FA84
+:10FDD0005A33F145B627500571204D917C61329C14
+:10FDE0005FABB83D07DF6FA1A4A8CAA336F9EC78D2
+:10FDF000F9E5DDE05A2565B40F4F7913CFAFEEEB8F
+:10FE0000AF84E919EBFC1213CE3EDBFF3EE6750D25
+:10FE1000144818F769F77E8AF68188EF44E977027B
+:10FE2000F351FCC59FA0BD3294B7C5EB5B2AEA2B0A
+:10FE30003E86F19AEFB88E25433CE60CC471E9F793
+:10FE400067947E0DEC9045025F518A46043DBDD11A
+:10FE50007C9308B7ABCEDADF4806BDF912C7F54789
+:10FE6000FD726D3C3FE70299F999C5F54695AD3BAA
+:10FE7000F35486E7C4BD98DF217E924F15313BFCD9
+:10FE80006F0DF36EAE1FCAAF46FF60A460247BB453
+:10FE9000DE44E7292A5FF738DE180DD78A719AE920
+:10FEA000601EA7F93BA7CAFC65775AF5E9EADC684A
+:10FEB0003B62BD33975F96202FA7BCD8E89F5C704C
+:10FEC000D9989773A73558A2527A562AD2CE540F92
+:10FED000EA3594A78E2B1AE29881FE8E9D30ADC72D
+:10FEE00007997FB48CC8611B5B17EA216E27E44633
+:10FEF000F0BFB91FA3B55F36D883F678F9E5FE2ABF
+:10FF0000E0BF5BFCEDA8579750BD3A2E8E5E5D2892
+:10FF1000F7ED1C07F2EB63FB3BCEFEB2BB0AEF35FD
+:10FF200009F361F5B25C651CF0812BBEBF6A3EE748
+:10FF300093E1F13CA1575D0AE006B3BF6D3E97BB6C
+:10FF4000F9267E08AA4338E8A6ABB9A3CF53227E90
+:10FF500018E81FB82F9E1F555C13E55DDD4D4CF46E
+:10FF60006D33FA9FCDF5087F1091DBB2419E85FD80
+:10FF70006B2ED7A4B2B8C7F1C2BB486C5E95D00750
+:10FF80006A71B3067EF1AEE291D70B733E5C39F431
+:10FF90003786AE9576633CF609457F10F8318A9333
+:10FFA0001A98BD5ADC80F6EAD202BE2FA8F02EB411
+:10FFB0004F855DDD78F321CCE712F95AC23E35F763
+:10FFC000BB6BE2F398CF335ABF851D7FCA26B33887
+:10FFD00004B5DB3D68B753DC17E7BB576C8C5E3F5D
+:10FFE00055F4FD20AF3BADBABB01E28C8536DFB3E3
+:10FFF00071E6A1D7C6E4BB2B41BCF55710F8988B2E
+:020000021000EC
+:10000000E3403A98D71B61C78A7D4A13DC4C6EEBFC
+:10001000B81D5B5AD080F298E6A6762BD0CDC7ECFF
+:1000200056D267B453976ADD5930FFE6F54E1EE4A9
+:1000300076ED18EDD65D0EC6474117B1BBE97B875B
+:1000400042A1295DFF1E972B8E013D76A511B407B5
+:10005000CEA4A9E10371FC0D6F737EAB963718F83F
+:10006000AD8CE312B5AA47037FC09941E6C74B3474
+:100070006F0F99707A4E3E29B739E1DA5F0EF4A01E
+:10008000F7BA0DAFFD989FFD70E1BA9C78F51D6839
+:1000900052E2AE4BBFE3F3B65CE46BD7327FE4DDF4
+:1000A000052AFA8527D4BE7702F9B49EF3E9121B1C
+:1000B0008EBBAB50C179E9BAD9DB0C71CDAE423BF6
+:1000C000E6A3B417FEEC9790AF5D562C19F24B04E3
+:1000D000FF9601AE86FAEDCCDF79B79BE9E12E8D74
+:1000E000E3179E37B291CFE999C31F3863F34656A1
+:1000F00008BEAFE77E72137EA26A246E1C47E4211D
+:100100007F5CCFFCC2778BF11E39B413E4AE8EF363
+:100110004DFBA5756E94CF232C3FAFB1B001FD45CB
+:10012000ED13DF52E17EA3FB4315EECDB842CCEBDD
+:10013000DDC53F65F9917C5E37823F9EF2FB4B99AE
+:10014000D3AD1E7ABF3C72B315FC9DC23F3B2C0E53
+:10015000C5E329356CF8A4C6CDF0F589CC6492943A
+:1001600001F492C312D02DE22049907FE6B6861D9D
+:10017000F4BE4EE99902B825D984173F7EE1503686
+:10018000C8F7F119BF55A0DDEB8ADF6B84714C2AEB
+:100190003E84FEFEAC23873AD3693D4BF3894FF78B
+:1001A0000CEF4F355F9FEECE60F94277FBC221D84E
+:1001B0007776E10ADB4F51F1C21B95B0AC0D8FCBC6
+:1001C000E804708888EB286E1E17E1F10972E5AA31
+:1001D000143B6F754AD00EFAB7B1F80D27F4773992
+:1001E000A75BCE61B901F8BBEA85395F013E2137D3
+:1001F000DB5CD7D3062FB87EEE9CAAB1F777B17A35
+:10020000E70769F9BA8243D9EB0A87EB9721F92905
+:10021000F8C3D620EDCF99453FCB06DCF606D5BB1B
+:100220001E6897EB2DB3BD645E57CD7931E67167DB
+:100230002ACB6A6D7361BEBFEFF6C6F019D5036BAA
+:10024000A1FF1B9FB4631E57DA91D75519F41BC544
+:10025000EF3552948F36723EAAD398FE6B2C24E170
+:10026000ED12F0DF87F5A52077AFB27CC30947DE3A
+:1002700063F9A3A6F5A18BAF1BC2EFDC35F17D942A
+:100280009F8F0F73790959A4587F9256DCBF12E6ED
+:10029000C52C27E27E7E7F4FDCF5E15D1BF79B0CD2
+:1002A000B2F71AD5DF10D736BFF7737BAA0CAE3181
+:1002B000F5DC6763B8575CAF210FE1896F53F96FC5
+:1002C000DFDDE1BE03F59486B87DE39143F910B319
+:1002D000C93C7CA88AEB0BB4CB643ECE09C4837ABC
+:1002E0006AA96667F103139F5B8BF747003E8B7526
+:1002F0001A0C722533AA47E4583F441C3B8C84F403
+:1003000037F362F2BEE8FA4E40AF54BA99FFD5CC4B
+:100310002769C554EFE024502E8C89FB9AF9B64E1C
+:100320000BBA219E4DE5E73C8B7FD2F50AFC137298
+:10033000BD0FE793F3A785FE83F52FD967E44F6BD5
+:10034000BE6AC02BE67EFCA3CD88FFC5FA9CE6EE14
+:10035000C1FE2DD59AB3A1FD09EE1EB4B7A87ECF7C
+:1003600086ABE033A1AF87F8AFF0A6C5A0DF81AFC1
+:1003700021447EA6784E12E8C13A37C329C4E44F1F
+:10038000EF728F6C6F749AD6BF332E665FD515935C
+:1003900024572AC83BF33B753D92BE3F39C62FF721
+:1003A0004FD6608B2DC6BFEE2CF8D2629713F40C9B
+:1003B000CBDF2AA1EACB9A1BF5670ABFA988F70908
+:1003C0003FE9307F66413BE6775945DE058FFF0DFB
+:1003D000CBFB4910771457E1CFB46D6F567C3C5E70
+:1003E0008278AC9EFBE106678FE20F65FE078ACF3D
+:1003F0007E6E1B3F3A3E3BC8EDCC5E501EF4BADE2B
+:10040000E6C2AB06F928B4AB5D8EF8B8ED656EB701
+:100410005D8B7C9E94E13BD6CE4726FE12CFA3781F
+:1004200098C9C184E2439DB178B8AC89D286CE9395
+:10043000DA44A690D4C47CB77448EFFDD4C05F43BF
+:10044000F878145C2CF8EB92ACFF19E898A85C1DC6
+:10045000EF47A2F78D85B6D5906F45CB9109A9ECF2
+:100460003A8D5E3B671CCAB6D0E7AF01FE8AE9470A
+:10047000D7F78EE0387EA5B27D365D97D6E5003E93
+:1004800038ABE8A9F6F163E71FB33CD9E7EA9E6D04
+:1004900054FE8E66DB717D3EEA6638E4752819C32A
+:1004A0004F9BD5E075F6B9A8EA7592CE959CE0739E
+:1004B000509A5563DB27767B72CFFD81185CB91BA0
+:1004C0005E4D84381FE39B07D51ECCC7B99DD66E01
+:1004D000A3ED1CD3E4CCB5F47EB69DF1E3B1903529
+:1004E0006EFEF36C3BC3CF9BD5C06CE82769DE84FE
+:1004F00072D620C901907FE21B9B7F6E474BFCBCEC
+:10050000D2CA68FDF3B1FEC3B47EC00D3EEE7F27B4
+:10051000AECCB8FE763EEE0821B5202F8FA619EDA1
+:100520004DBF9DAD7BF3A3F52F8EAD1FF3B3E6E278
+:10053000F32538CFCFB1E7F9762617E5B92CAF4DC3
+:10054000D051D4BB325ADF4AACEF08FB2ECFCEE3FA
+:1005500006BCDF02E79BF39F163AD87C44E3A6046F
+:10056000F56689C6FCF513FAC3C7E0BE9CF07D9919
+:10057000D2DBB87FEFA8D58BF900ED8E694F6FCA3B
+:10058000803C0923AEB7719E51EC3F946371BACEA3
+:10059000714C49760EE2E10E923BA29D237087904A
+:1005A000EB05C27F7AE500EE176BE1DF8B76CB4D72
+:1005B000B82EBA5FB11BF72B4EE8EDC6FD89152E9C
+:1005C0007E5E44DA37D1BEDEE5B897E1F9C99FE235
+:1005D0007EE505D907E5787E4245F45F7903DB3F88
+:1005E000EA62EBD402815F4D76C64B995D32E0C87A
+:1005F00044B8FE84147C26C2FC9A067CEF8F7C6D86
+:10060000C3214A57BD97B81CF4BE24C2E24C151C46
+:10061000D75728E12C581F6AB2993FAAE54FDD59F8
+:10062000B03E1CFF3413D78BEB94FD38DE498A179C
+:10063000F1FC4213FEAFB01FDA0679138B14898CDC
+:1006400023C3FB05FBD5C08E2871B3BCA0126AC5BD
+:10065000819DF1326D1FFC65157FA2F3678987EFDD
+:100660008D38A5562927AC1CC7FBD9CCBF341A9EA0
+:10067000AE30D903625E2B943D556097B4809D41A6
+:100680001FB5283B9474DAAF5D8304229BC4CFBFAF
+:10069000CBC9B630FB60B2650DD08D58997DB0CB1B
+:1006A000F5D776B40FE87BB00F2AB87D5061F7A27A
+:1006B0007D301A8ECFB1333BA1FDE254B49F228E20
+:1006C0001F66817E16F9E402DF0BFECB54CA4F8011
+:1006D0003C2FE07C28F0BE4DE0FD2B9B089C275072
+:1006E000A118F1BE8DF35905C7FB2D10F7027E3D11
+:1006F0009F79CA0BF11881F7AFB898BF9BE37DB122
+:10070000CFB203E43306EF779C1FC0BC8597B39943
+:10071000DE17787FC89EFC8C78BF4CE80F8EE76BA5
+:10072000386E10EFFBB9DE33E37CF3FB6BC5F98465
+:10073000E3F8283E36F26FFBEE1C8CAF94B8EC6801
+:10074000072CE80D0EDE4BAF995736FD662FCA51C8
+:10075000B20F3EB3713B6CD43C5013EEA776C34E40
+:10076000D87F539EC7F28ED2B25D55B09FBDC223D3
+:10077000A1FF69985C98ED806C17DA69954A83C887
+:100780008F1B11EF57682EC4DB8A523326BC6F963D
+:10079000AFDA3CDB887C9DED30E617940BBDA9DC1D
+:1007A0001B42BDA9DC1B01392AB7737F8FE36FDCC5
+:1007B000B1E73AECE2EB81D0D3425E3B1CD39460CC
+:1007C0000CFE1AE26B25578BDD5FDCC1F9F2078A5C
+:1007D00007FDAD1D76661F98F1D850798EF72B383E
+:1007E000DEAFB033BCDF311CEF173B62F09BD3CEE2
+:1007F000F0FE58F30A841D5B63B263DFB71BEDD8CC
+:10080000447CFD215FD7A3F4F4325CAB7811D70AA6
+:100810007A2A1CD7DA004FCEC4751571AD90E3610A
+:1008200074B5E61A706D39C7791DCA9871EDADB10E
+:1008300074315F2B46C1B5BB1C14D76A580E716D5D
+:1008400085C0B5495E03AE251AC3631DDFCBC771F2
+:1008500074A4313C6BC66389F107D76F265C21BE57
+:100860006F4921D9E89F1BC225D3E2E2924438C4E4
+:100870003CAE16C025DA5F029778709C663E3F9AC0
+:10088000A2A39D1FC529BFFDC6212A87BB2E123CEE
+:100890005141E0157FE48FC71A8A102F1087273A3D
+:1008A0004E8157043E11EB638BC2F249057E49E449
+:1008B0001F15D76BC52F2732FF17E21E336E117835
+:1008C000C55C7F8795E199963FBDF59F8A6316EEDB
+:1008D000A7DC47E5A45CD9867AC9AC075BC05B4D51
+:1008E000CBBFEC22E110D4FFA773727A1C7D6CC6DB
+:1008F00033669C32567CB328EF22E61B8E863B3A49
+:100900009430EE936F51EEB3833E32E31A333D736E
+:10091000B24903C40304DE49C4C750EE2E6714076E
+:10092000252A47F538E2A384F5D82F5E2B2E3AEF1F
+:10093000181117313D50E1667A20115ED9E57369CF
+:10094000B179AC627D69CFCEF925EE37EF55F1DC98
+:1009500084F6F353519F26C24B6D26B9EB003DA29E
+:1009600045D7AF8474E91D407917B86A347D21EE0C
+:1009700013E129B1AE9401E81F9F386E392589D95A
+:100980007D0FE6303BDAFC3E9A8762C45524A31003
+:10099000F9F81EBE1F3311CEA22B9893F9AF42D89F
+:1009A000CE2A6E87A2CF701ECF43A05D0DE4913C8E
+:1009B00058270276263767E64A2837CBE0399DD795
+:1009C000F22A16373A5728613CFD4CB90DE7F5D4A9
+:1009D000C72C4FB13D85F95FCFCC72F80ED02E7C7D
+:1009E0000CF5D275F99CA3BB0870C0AC24EE2F485F
+:1009F00067E35C921CD98071F339D32D21EF7079B4
+:100A00007F3089F7235DC3F85B1DC7A3103FCC9AE5
+:100A10003D7C9FC1D3495EAC1FF2E7B368B99D9698
+:100A2000EE8773E8238785C55BCD74FD98D31D08D9
+:100A3000638BA1437D9E5D7750FE77DCC8E256470D
+:100A4000AB6C98A7E380103BADF7A1FC9C9478FCBD
+:100A500021C6657EBE9F8FFBDCE47E5CDFCEF2BCF0
+:100A6000DF8D8A14027AA3A22E82631527ED7F8878
+:100A700016FD4A521AF6EBEC0BAF23DF9E4EE374E1
+:100A8000D025B4D7CE78983C855C5A18F66BD2EF57
+:100A9000ADAB46C807E92EAFC9677134422488AFB1
+:100AA000C11F39C3E9BDA256C671AF70EDBE17E4D0
+:100AB000F15CED1BC9702EE5D2410B01B95BE12A57
+:100AC000B90B9EB7A7303E063A038E5A51F5A56F73
+:100AD000C0F3FA7AE37C9C4CCAC171942A6C3E60E4
+:100AE000FEB2660F6F97AE7E41353386FEFE9FFDE8
+:100AF0008D14B3AE887C167B82FCBE44E39662F50F
+:100B0000AE1CF5474E28DEBF07F6CD048AD879180B
+:100B1000751E1282F86F9D8F44BC9CBF30CFA633E8
+:100B20008FED17E2F29556BCBF2907FC97830A8B1D
+:100B30004B9BD691523A57D9E9E04F67F37366AEB3
+:100B40008C765E6931C3F9A51CE7D7E90D18EFABC8
+:100B50007FA473770EBC97B3ABCB3D3C6E1A433F7B
+:100B60007284F9E79699F83CC5E4FF2FF599F206EF
+:100B700079BEDFD1FC675CC03F0FA673FE992DA143
+:100B80001CBD2E791E01B910745A9224E233C4633D
+:100B90008DE18F217EE0F36BA67B227A9AE964E6F1
+:100BA0000B33BDCFA498E89580FE89E85D5A5CFEC2
+:100BB00017A5EF05ABCD0A7CDB6EFD6D36B78F88D0
+:100BC0001CA34FCC74BBA07952404F9C1B3C87B8F0
+:100BD000EDF464CF57F07C2C2AC778BE279787E8BE
+:100BE0003C507970C6CAF3DB53409E299F59A19EA1
+:100BF0007A5DD21D207F8777DD8BE306397546E568
+:100C0000C84CFF61F247FF57447F7387CB91399FF0
+:100C1000ECB3CADFB7409F53BA2D4CF2E055E8D38E
+:100C20007AE2FA4AECFE5611676FF73606605F7A91
+:100C30005DAF05CF016A197C5E590BFB5D6B255CCE
+:100C4000D634D28DFDD59A58BEC4D4A71E2090CFDD
+:100C5000FEC864E2037DA535B1FC09FA1EF3270442
+:100C60007E17E73AD2F73ACB17319EBF94E233E6CC
+:100C7000FF2CEFAB403BA2939F8724EC0491F74AF3
+:100C80004CFB5E1AE1C9C4E8FE90A64B616647249E
+:100C9000D80723AE667BC17C3DDEF1CFDF003F622B
+:100CA000599E8A7EC4B2C1881DEA7BB8A0A316F300
+:100CB000DC6A2517C4E38E7FDABC03CE415A5EF0AE
+:100CC0007E5C5CD27AE1091F8CA3D5BAC7970EFA75
+:100CD000613B5BB71CD30A26AF1D01F7046BCB6BDE
+:100CE000BD3312E799DC93CCD7F7F6AF1D7810E24D
+:100CF000DE7DAA0FEC97C53CCE5FA7EC59BD96CE22
+:100D000067E722C9B78D3EEFBC61EFA60E88639CF2
+:100D100057D1DFD775E96036D819AF7DCF8EF6E8A9
+:100D2000F14F0F3E8D79267DEA3C18EF50FFAFD78B
+:100D3000D8FB8F5F3C097A6679FEF22268C7A190E2
+:100D40003DC04FD70D36BF0BE725D4F5AA7341FF41
+:100D50002CAFDD6FFF2BA053ED4FEDD783FD31E8B6
+:100D6000A986F9BC2E2958994CF55E5681F73B1996
+:100D7000D08E8FF874A46B3701BA8AFC04610F948B
+:100D800071BE6959E44D2131743D3798930274CE98
+:100D9000A9E5790C8BE400D8CBE75CD7A7A07FB29C
+:100DA00096E52F98E9B51C707A2AF4CF3B795D9CC3
+:100DB000F53BA7F60F5B83E00FBE81D9E7E6F77737
+:100DC000707A3B7EB7EE008CD7F17DBB0BE0B5238C
+:100DD000417EE6D464AEE7DD63F397083C43E96AFD
+:100DE000B7C6F80129DE5F9F1C1377BDD6F6BF9A00
+:100DF000CCF4C02539B819E85FCAFD2565DC5F92DF
+:100E0000A85F25A3F831281F219D96831F6326BB69
+:100E10004EA3D7CEC5DEC9063F06D1DDA067CF41C0
+:100E20007C0EF098B26C3BF4A3EB02F36724E2DF94
+:100E3000E579076FEB88D1775D563D1BECDCCE1B67
+:100E4000DECE82F9FFCFE2DF213EABFD69139CAB22
+:100E5000F550C1F2F1A0FF62F8F869988F6BE56375
+:100E600033FD5A16E5A6102DCACF828F87F3A584CD
+:100E7000F6A8E0EF44F301E5C01E157C9EA8DCB99E
+:100E800045D3E2F27FB49E8B23CAC16ACE57770066
+:100E90005F8D07BDACBB400F2FCC7A17EDD657B88E
+:100EA0003E1EE29394EEDBEEA17A27F4AC1DE3E85C
+:100EB000472FA978FEFAD167D6FF00D68DCEC10A9A
+:100EC000D787B88E97BB56D07EDD00F64301CE4F54
+:100ED000A712E337BC902CE2E6C67CDF9FB87E9376
+:100EE0005ECED659AD9CD27B265F276EF43E93042E
+:100EF000EBF94CBE9F62469B1A775DE61082146444
+:100F0000BC6E01E85F70D8584E1BDA9FDE6C81F82A
+:100F1000E08DCF99DEF37DD5E6FCC87F4F36ED7FBF
+:100F200032ADB7F64B23E769FC0BB77B9FE3F9BF04
+:100F30003FE1E70936F3F3049F877DAEF47A18F6B4
+:100F4000B9D2E72FC23E577A7F84EF7325D9633B2E
+:100F5000375E9CF7A4723A344D0C1BF6698AFDDFAC
+:100F60002D709E12E001B7CACEA17351B405792A43
+:100F70001C2F5A92FD7615F6737D44304FE5AFCFA6
+:100F800077233FECE6EBAC19C788F31ECDFD52A3E7
+:100F90007454C04F7574727075A0804F18F0CDDC1A
+:100FA00009FB1F8AC1D3A91AB32B1BB9DD16BA449A
+:100FB000C2CF4AD1F2A72F91830F313F5B4806DCA5
+:100FC000017F51165EDC4B10C72D2EDA85F617E037
+:100FD00040C06578FE580EF8BD5E443CB77870DEC0
+:100FE0005D0CB7E8C370DC10DD64A413C3E745AF44
+:100FF000A35F71716F7C7E8BE637ADEECC8BD9979A
+:10100000503F18ACE7F8C8157B6E826AE22B733D3F
+:101010006945CC7FBF249FFB7B783C44CCE78E4D59
+:10102000DDE82FEF2AB279C0BF60C689669CAF1693
+:10103000B17D64CACD6C3FEBE24B2C5E880C9319FA
+:101040003D9F4DE579BE2DAEA00FFC98753E13EE89
+:10105000E5E74B95E51BF1BC19EFABBDAA09EF879E
+:10106000D87AB89DCDE7998F09DA51CFEE63FE812A
+:1010700056B787F11F09A3DDB3C06D99F59007E25C
+:10108000566C7F66C920417F4949AF07FD4F0BFA77
+:101090004864EA0C3C87B809CF1932D16F01B87A9D
+:1010A000D3A11E4FE7784AFF050AD909E7CB64DAD6
+:1010B0001B749003D5BD09F7E3407EC338C647F6DD
+:1010C00058FAAA49A77680082CE07E35F1BB1513A3
+:1010D000EC87900F62E66FC4F898CAF94EC4BBCA99
+:1010E00079FDE57D2CDFCDCC0769F68BEFC239CFDA
+:1010F00015831A9E036D9EF7E171B0FE0F1E8338B3
+:10110000CFA524DF7698673B9B67318FAADC26C387
+:10111000FE0EA2B0F912F130B37FB5D4B46FCEDCBD
+:101120002F715EC256CDB48F8CE3F80ADEBB26C7A2
+:1011300021C3B9B5155CCF0CADDBF65C1ED762E7F9
+:101140009CB6F6CD1E31AED5EA62E7FE11D7F2515C
+:10115000F4DE76B68EF0F3054A8B4912E09CD23E5F
+:10116000C2F8EB114B38D91B5B3E6CD857EEEC5BE9
+:10117000B518CF6974B9AAC0CF564A58FC52EF25AA
+:1011800018CFD4C9213918332E112F51B95F4C957E
+:10119000D8B8049DCCFDBB7DD0680F7D2564DC0FE5
+:1011A00071DB03C6FD1BB76ECA32BCAF599F6B78AB
+:1011B0005FED996EB8FF92DB787ED0FF081ACF0FF3
+:1011C0005AB1BAD2507E59C0787ED02DB5C6F383BD
+:1011D000EAF4DB4CF2AB1BF8FBA8D4FD5D18BF258D
+:1011E000F997B923F979CB468B2387D879426807D9
+:1011F000C689B398F7BB7DA409BC609483CE5039EF
+:101200003B6FA7D7B3AFDC03F12A9F82062E3F576F
+:10121000A89AB072D56E166FA9CA886FCF0B3D68B9
+:101220008E4F8873014BFBBA910FCA4CE70096B8FA
+:1012300017C63DE7F33F34D3B91809CEBF18B67EC1
+:101240008F757C3CCE34EAF878BB25A4FB98D39B01
+:10125000787C631DD7507E179C4748E9D10D8F26B7
+:10126000B2F71A95B79D69F978FE4586BD424919CE
+:101270001FF577127DCE98F2D1DAB91F9FE82BC601
+:10128000749E6986DDC3F84267F868A7A487E1FC0D
+:101290003C731C55CD177154E339188E9D442FA013
+:1012A000240A55108CEB8772ECE11D12E493B37D98
+:1012B000A68D375870FD69BCA8EF81FC94A61B145D
+:1012C000DCE7582D6B585ECD66EB931F72EF217FE4
+:1012D000E2357DB5E1FC0EF77617C889FA347B9FBD
+:1012E000683C6D13D5D5F1EC859B52181E3AAB04C2
+:1012F00066A6207FE86E168F08E37968222F3751A3
+:101300003E2E058E2EE44322F0019BBFEF403C258C
+:101310008EFC56A53039F31748612BE497AE246153
+:10132000EB0876659BDB12D79F5198C2F359AE5CF0
+:10133000C573EE5471EE5E163B77AFDD749E65218A
+:101340006FF7788A9DF181F7A021DEEDE7F2B0D842
+:10135000B38EC4E25971FE8FDAFF3EFA99CE8C72D9
+:10136000FE8E886FEDE6FB9A2B2F5902F1FA3F9023
+:10137000A2209D9ED5AC71C7F700EF6FDB141F9EB6
+:10138000B7DAF8B8859D17EF6E9C84FBBE53FE8AD2
+:10139000307F17EBFF622EA77E777807498138F5FB
+:1013A0003B4FC2EF87A8C536F0E591333734E0797B
+:1013B000B1BBFB295EF446C797C2D71BFFBE8EDACE
+:1013C0005CC0432765F4F7D4F4B27CF3A5C5FBF900
+:1013D000392D3DB88FD1FCFB2525B5411DD6E5A59E
+:1013E000F5911D887F7C9E72FC3D13E2DB86BFAFCA
+:1013F000326CBFA586B8AB6D90F17DDB8F7CEDF8CC
+:10140000FB206E811BF5FAEACCE8B96165173B76E3
+:101410004208C67C6E98F9DC216197A9265C29EC0C
+:10142000B13A123EA648C3FDCC89ECB1BD29DC1E01
+:10143000BB81DA6374FE6FB7B13C5BFF16A9188CF1
+:1014400046C7166922E8AFA7F83CBD5916C4F35B3E
+:101450001A13ECBFFBDF5CCEDE2C8BE03EA7366FB1
+:10146000D0ED1BA17C610ADB27A85E61E77EA87630
+:1014700096D73574E5F93082AFE7396D782D75323E
+:101480007B7BC1D5E7B2465A3F4BFC4102E3A1FA50
+:10149000256EBED80BD03EEC178CB0F32BD4A6F73C
+:1014A000ABE2C9B390C3CD6AE067A03F764A9BC266
+:1014B0000ED403633FD772A6FCF9F5CD554D3F918D
+:1014C00042EB7DCDFA0F1E908F1D41E3EF4E89EB6D
+:1014D0006B5AD08EF477772483BD7931297836859D
+:1014E000FBBB617F615BFFF376D4A726BA9BEBB9A8
+:1014F000CFC9E653F5B0F7E417BA67798C9FA4CE4D
+:1015000029F1F5437F07EA9F6DD5FF0DAE0F56C455
+:101510008F43662A15BF06FA556B811EB8B6F51FB4
+:1015200040FF714A92FE1EDC9729FAFBF0FD3F59FD
+:10153000F50F989EAE727D981FDDEF90689E21702A
+:10154000F1617E2CBD3E1F9D33EC814136CF7A5038
+:10155000BBC67976D2EB1A585BE8F73D65F1E3ED4F
+:101560004F717EA27286F982623F8CDF4DF478EB78
+:1015700097284FE75F7562BE7B2800FBBACE4CB25E
+:101580009003317A4E9C63D0D8CFECC281FBA50387
+:10159000CC2E2478FFA3AF790F407C77E5142EC7BB
+:1015A0007C3FC61DF71BF7498B766F4E95C6249F6F
+:1015B0000FF3728DA94C3E1F4FBD46F9CC60F50864
+:1015C000395515765DEB62F57E98CAF82C294D12D7
+:1015D000F9E9F94E26873D29D7363F4FACC8FDFCC7
+:1015E000FC21E441F519F3F51EE1F220F415ED6755
+:1015F00019CC17ED6730E9DAFA9959F205F0B1D84C
+:101600009720274B067F78C0C9F8E90EDEDFB38A42
+:10161000BECCC9E477B97364F95DE564F2BBDA69FD
+:1016200094DF5B9D4C7EBFEC64F27B9BF373C8EF51
+:1016300047203F90E7C8FDF8E49451EF505C7C17D9
+:10164000D4BF5891F83E6FF21B29C6FE58DC1B240C
+:101650003A5B2C9F89C50D14BFEAB8AFE34D637D9B
+:10166000EFF0758BEAB1CD50EF3BBCFD1DFFC6E836
+:1016700007747C3E8E5C0A3ACAB60637EC8B4DB4D2
+:10168000CE059C6C9D2BB7B17D17E4246DBFD03087
+:101690009E6D40B7A1F184A865177F3CA1B8E3E92E
+:1016A00036D617339EDD50AF18CF82ABA74694478E
+:1016B000BF904757448675DBAFC45F17CE38D9BAA1
+:1016C0003990AC3F09F432F397B886397F25DA1F99
+:1016D0007356A90843FF4A14A6078916E99163C601
+:1016E0005792DF20C61DB4C4FAD97AE3EBC9E79C50
+:1016F0004372F71CF2DF3EB69F87F2F58FA19DDBA8
+:10170000C7B956E1FEAF4F98DE7CEB4F5BAC69B4D6
+:101710009DD5197BBF03D75F3B59DE4BC3C51C2743
+:101720004C434F19DB17D938919DA7D62819CF55AF
+:10173000FBB59077AEFFAE41BEDFCA913FBB7C7C6C
+:101740005EBD40E9D3CDF5528F23F7DAF4D2DC2F1A
+:10175000A0FD955308E2E3C6FD2A9EBF25E4E67688
+:10176000985B760E820E79145FA5F7167A3F0846CD
+:1017700037ED47309B10F76C2C1752F19C04BD17C6
+:10178000C651ADE9E7E14AF5D04770A57AE8775C44
+:101790000FF57D1E3D7402C644BF6FA23CD40D7C84
+:1017A000A88479DE2FB747F8584BF28FC5FDBDA945
+:1017B000B6DE035A08F206F3D93ED544ED46C0DE44
+:1017C00080C49504BF6725AEE58FAFB58311B083A4
+:1017D000E23AF0A3BECCED9436685F83F62CF8FBBA
+:1017E0003FAF1119E3F0E6FA1A27F3753F85F3F3DB
+:1017F000C475685FE9578CFEB54A7778F7EC22F834
+:10180000BDB33BD83EAC2B77905585804F8204CE3C
+:10181000E154E915F23745BFBDA953193EE5FD5422
+:1018200089A42C2C88EA91CA7E12595084F806F3B8
+:1018300066A11E0FAF275808EB7D9A02F1BED712A2
+:10184000FC4ED3E372303F35C6DF584E8C7885CEE0
+:10185000FF0DA9E371FE6F4C65EBD074B8D2F92F80
+:1018600080EFFA9C4CFF3D2E0766C2F360060B41E9
+:10187000D3F2BE54C62FB352E77E7E3ED941D8EF95
+:10188000F202FFC6C6AB9FE5FAE1E8F8A00EED5400
+:10189000FD6859E724FAC986E6063CFF78C175FD64
+:1018A0009F9C85FCDB2C15E3818D8F18D7911F72CF
+:1018B000FCF3D2B5EB19C41154FF2D81767710A635
+:1018C000FF426EF6FBA30D13731E65F0911A9899F3
+:1018D000D1736DAB5CCBF0DCAEAF3FE79D0DE76045
+:1018E000A95C3F2F74B7AB6B615E21DF348E3E0F76
+:1018F0000EF58F6A6FC33A15FFFC97CD1C2752393E
+:101900006E4865F2BB16E6E785F1FA1DA97F41FC3A
+:101910002FF4505061FA86DA4D21B09B565DDE748B
+:101920001C96A9D5646F35C437285FFE2DF4F3CB20
+:10193000F643C7D94F12862641BB941FFF8E8F678F
+:101940000BE7C76F717EFCF6E719D7D753191F272E
+:10195000C29F02870BFC4DF5FC23A94CCF7B9C5FFB
+:10196000CCBAF10FA90C77079DD7B86EDCFA05B495
+:101970004FF1C641685F4F2523E2DBE7F8F87F9C13
+:101980003A846F7F0CDF2DB5EB3F81EB10DE2838FA
+:10199000F91BC8938BE28D7699E30D25D69FEDA7B1
+:1019A000F88BE7D5DD6999179513B53F3E0EA94F22
+:1019B0001DC2214751AFEC6638A47EA8DFBEDE30E1
+:1019C000C8E1242EEFEF307DDCA0F6DC09FA594D9A
+:1019D00067F3A8A4337CF92A9FD7F7A494B8FECD67
+:1019E000AE687B5DC85F5B587B72F22CF67B204251
+:1019F000AF58256C47F887EBD3D977A29D45FC2AD1
+:101A000070AAB99D5FA40ED95FBFC071DD2FF60724
+:101A1000EBEF40BBFE285D23B17405FD62991743CF
+:101A20004F8EEB12E1B818FAFD078EA789B5334443
+:101A3000BF607C3D7BAB4B167CF2BBD411F8A39FFF
+:101A4000F3C7C5287F5CE4FC31908AF884CDC3EDF0
+:101A5000E38CFBCEFF90CAE8B39BD349CC97B9FF88
+:101A60000FF2F743F4F09C7C2616D7FAF3D356AD69
+:101A700006BF6593ECB3D0FBFF032FADAD0C008028
+:101A8000000000001F8B080000000000000BE57D37
+:101A90000B6014D5B9F0999DD9D94DB29B4C924D9C
+:101AA000B281246C20D858032E21C42841264F022D
+:101AB000448C88888ABA014C42802422B6B6D5CBA1
+:101AC0006242785A637D142DB60B420B16DB88A94F
+:101AD000A518700382F80EB68AD6DB1AC4F25084B9
+:101AE00005B55D5A5AEFF9BE73263BB3D905D4B696
+:101AF000B7F7FFE3ED3D9C33E7F9BDBFEF7C334B18
+:101B00000891482A215790FEBF1C13AD17F38A7C19
+:101B1000D42779F208991420AACF46C817F0373E87
+:101B200054C629022129842C946BE29431744079A3
+:101B30008BAB6604213DA57DF36B22F4BF2789F5AD
+:101B4000BF21635D798A8BF6F7D27658DF49FF2D86
+:101B5000127263438FE8D18DBBE1A3C373D408F342
+:101B60007C37C944085DAF75A67B9FAB804EE334DC
+:101B7000B9379281FD1E4C94B1DF84A13E2981F6D4
+:101B80007BFD1451D6D37E374E13541F3D57253F4E
+:101B90005702DF578E2261FF32A8C338B96F4EA4B7
+:101BA000735CC69F57B988DA49E7A95288BA3542AB
+:101BB000BFB17C9F136223CF73139F672261F384AD
+:101BC0003FBF95EF6B4269E4F157F2F967389FAE7A
+:101BD0004822B09F7566805FBE592D56E8B81551F2
+:101BE000F0902A95AA80AF180A3A733E21B7D0B177
+:101BF000263AC1AD80735A3E2C7A2AE1B98782C356
+:101C0000990F94E01D0478ADB0A913605E7BAC5AC7
+:101C100005E538499D08E54FCCEA242809F113521F
+:101C200048C8144E3F53AC36BF184FFF51643EDED8
+:101C300067656D5F0C85FF3F53397C092102F10B0D
+:101C40005F5C02759F08F35FE1DAF78E40FB5FA1EE
+:101C50008D3B2A858DCB500EC7F1BA88FB42F86CBC
+:101C600037FFD065330D3CA7566EB779AC0087536C
+:101C7000B19E5AD867AB73BDCD45E1FDB2A7D3EA9B
+:101C8000A6ED1F271084E3E93875369CBB753B69C8
+:101C9000E8A4ED629CD0D2A9835F8362C2F5E62AF4
+:101CA0000C6F6F48EA5C986F8A556D84725A16C53E
+:101CB000139DF7D6E4BE457AB8DFC1F1343F898D74
+:101CC000BF4566FDC2F739973F2F96046F1CECC9DC
+:101CD000B6EF4331027F4E827F51FE293EAA4C9FD0
+:101CE000E1A0385B2EBA4DB42EE70A11F9D41BE2FD
+:101CF000532FF2A98BF2A99DD2871C993E82BC7FFB
+:101D00004514BA1CC3F7590ECF238C1FC1E9B6DCAA
+:101D1000D123123ABE98F35B78BFBA2491F1B19BFC
+:101D200054459AE787A17DFF10F7ADB07DE79B6B27
+:101D30001E85FA4C657F45226D2EB9CF319D380046
+:101D40001E2662C946385941AE491C4E749B04EAAE
+:101D50000BADAC2EC5CE2709B4CC72FA568D04F863
+:101D6000B599DD2E5AFFE0E80722A174B6F1A1D3A0
+:101D700002A1F2627B8090E46C98478619E1CFF46F
+:101D80008530703EFACC2569EB51D05C7994A81669
+:101D90004ABF571605A69278C378F2059DCF16E87C
+:101DA000F50A803F2BF1C65D8A64FCBB9C549C15F0
+:101DB000E74BA3EBC279E4CF880FCEA33A3DD564BD
+:101DC00024218981BE1F3563BBCD3D01CF456CC049
+:101DD0006FA1732E44FED3F625DBFA9EB89FF6EF73
+:101DE000FE3CD67D2F9C3B50798CED8778EDC0D79B
+:101DF00062B51BE43B2116DC9F89FE077C362E482A
+:101E0000F79BCBF70B8B14E8F64F069EE761B1E624
+:101E100015C0C7AD56A2C6E7A37C7815F86198999E
+:101E200076A0706C57049F97F66B7F68CEF26C902B
+:101E3000D7AB25F77002744EB60994CEC7D275EFB2
+:101E4000A272472E223685D665273B7FFB7D8E7595
+:101E500071023C97C84CFA7C6CC07F46A0708877B2
+:101E6000D6552BF41C321F2F50C0C178C1A59099B4
+:101E7000F940B7BD2241F9E0447868FCA37E8308AD
+:101E800087ADA86A08D057B944BC56DA5F70B279FA
+:101E9000AF2401910C033C504540CB52E2C6F27E88
+:101EA000D1730CCE6395295EE9FEAD26AB6F890038
+:101EB000F8AB79B50AE15EAE1CCE0DC9B368720805
+:101EC00020775883ABF8F5E55EC5A2C87CF58F1086
+:101ED000DFFC03F98630BD3C6D28933B7BEC7D3302
+:101EE000F57CBF5C61F26939976B44627CB65056F1
+:101EF000CD89E7E0F3D55C1E8E4862F2B39544E6E7
+:101F0000E36712D9BCD3EEF5B50FA2F09B9224B8CB
+:101F1000410F576CA99506BB42FD06717D989CAA9E
+:101F20003A60DDD6EDEEA33E07681F19F57BFBBBDB
+:101F30006406CC5FCBE5E7DFF8BC6712D93E86F0DC
+:101F4000FA41C13E23125CB213FBE1929D08E7F413
+:101F500030B88871A3027EBA0E19CCD7310BB84EB7
+:101F6000CF50261F872719D719CAE51F95FB1727BA
+:101F7000A2DCF76540BF97CD6C7FE1EBBA43EBBACB
+:101F800071DDF96CDD4920E781FF5DFB5E10757640
+:101F9000D7A4808780DD033C6C2A0CC97BD9E51768
+:101FA0005B687B7114393F8E9F9FAE330EF6455AA6
+:101FB000181EFDA9EA9550A776C17858BF67A88278
+:101FC000F2F2F54126B29EF2656DFAD0EF83D8D4D5
+:101FD000E6F95522A3879EEC76E72C8A2F3940DC60
+:101FE00016A4F306947BC55CBEB46EF71078EE1DA4
+:101FF0004465A66EBC1C986525363CCA3FBED0FA27
+:10200000533E6A0F0C4DF044C08B56AE5ACC44116F
+:10201000712DC0710BF9B8F07EB68777C5C1FC2B66
+:10202000A1FF370899CAF1430F8CFB9BC479A735F0
+:10203000B03EAE8FF6DB9E3BDBB01F7C4EF9A83D79
+:10204000F78938B097BA33A91E0039F5928872B271
+:10205000DDCEF0D89E5E47F4F66899D32F1E8679C0
+:10206000CECE26D329FE8A9D1E72913DB4EFE2DCCE
+:102070003AAFE0C0F66763E83CDF4EBC08F12EE7FC
+:102080007948A50DE0D249EAE8F965C52FBA695942
+:102090001620FEF105D09FCA7981CDE7B2EBE7218A
+:1020A0009D308FECA6F400E3027EDCCFF6A3E7863A
+:1020B000A32DCF6490DF1A5F52BBEE5EC07FB97272
+:1020C0004D79229DBF714B76BE48E7AF74F6C8B319
+:1020D000F2506EB7029DFC2A456D4BFC5FB4E7667B
+:1020E000109F19F03E218BE981294D826F3D854F6C
+:1020F0007B989DF018E7C7B12179B716F9AB48B3C3
+:1021000013D4C713CF6D07AF83E7E7B0837F06CF44
+:1021100023D8C19B12991DBC19D6A376F09389CC04
+:102120000EFE39AEFF15E1768D42343BB40BE673FB
+:102130002472B9FA7B668F86EFFF1E7EFEE5F4AC53
+:10214000BD4097924F6274CEF8F40ACEA7938E5298
+:102150007EC91B48FFDD94FEBD94FE4E53BB49CCA7
+:102160008E4E4FFE0BE4CB928719DFB73A7721DF13
+:102170003DCFF9B39BAFDF9D2B56033E5F26A222D6
+:102180000A03E76BCFF43841AE87F39F7AD648CF86
+:10219000654EDFEA7CE09B7DB3DDB0AD707E946977
+:1021A000593722B4EFC3C0876374F2890852E5053A
+:1021B000F021CCE319017646A204FCD74AD8BADE56
+:1021C0007D22EA89687C44E9E624E0AF1F2E006C9A
+:1021D000DDFE29DD04804E289F9DFA3AF4B28AD3B1
+:1021E00007F543FE0AF3E4F27A6D14FF4248EAD79A
+:1021F0000F4212F0F74CA687B2135D4847B5C421D1
+:10220000837E51C5CC2C902F745E7312EDFF66C295
+:10221000B9E7B525F5F39F0DFA93BBD8BCAF809114
+:102220003D66E0BC1392A8FD11619E0CBEBF1BA3CE
+:10223000F80B399A7D92D76F9FA4C37A39C037744F
+:10224000FD1D29EA60A86B7C53CCED961705A35EB3
+:10225000BEA4DFDF677A2E8DDB2F644EFFBC390012
+:102260001F0D9E9A1D50CBE583364F2EE7BF614967
+:102270000A1BDFC0C63BA04EDB2BB9FF44E172292D
+:10228000C2DBCA9E9FCF2F7A4061718B3ABE2F2945
+:1022900051D1F41BC2B52A9ADFA584F43FAEE7669C
+:1022A000FD4770F8D07615DBABD93EC62A0CEFE1BE
+:1022B000F18368F8D1E0EFE4E723B96C7EE2ED87C3
+:1022C000DB64985FA39768707B3381C16D9206B71A
+:1022D000363E4F983C5825755A9508E7BC91D3ABCC
+:1022E000568FCB35CA8768F1943121F8D4221C0A65
+:1022F000D8BEA3C5572EE7FDAF4CEA875F038EB368
+:10230000B1FD3EC0E5356D9F87ED196CBE3B42EDDA
+:102310004DD8EE64FDA3F9FD7770FD3537A97FDC5C
+:102320009D38CEC1C685C713B4B299EF6F7E68DC05
+:10233000DD382E878D7386F0BE18DBAB58FBD78D4A
+:10234000BF39F9BADF0DC16515F2BDCACEFFB7843A
+:10235000FEF6EF637B315B379AFCF85B029B6F05FF
+:102360009FEF4AF08BE91C8941922B39C06B8A752B
+:102370004FA05DD282AA1FF447E967B20BE47485CF
+:1023800068F30A541E4B2E2BFAC9311251C1AFED1E
+:10239000F9FC5BCEBE3CACFB41AF2F8B29B182DF99
+:1023A000B93C5B72833E2C794062FEF57113CAFB27
+:1023B0004A713ECEB34BD1ECDCDB0D7EB44B715594
+:1023C000C7C03EAC227131FFBFFA2AFA7C3C97D7D6
+:1023D000BBACC926986F6C268B178C77D5A1BF4EE6
+:1023E000CE323F5AA5FF31F9ADA25E96F93829A346
+:1023F0008508581AFD6D99AC3E258E44BD8076D473
+:10240000D880D1FF965D9547607E99E8C6D175BBAF
+:1024100093EC0EB4A772C8F02F28FF58720562A182
+:10242000FE4585E4F1031E26BAEA94527A1E4B86D5
+:10243000C70A7238C7EC1F0CF184B60CD9ED05360B
+:102440007CA8DC9A0DFE5607F5CF110E6AD2352313
+:102450004278B214AB04E890E204F9ABBFB4B132F5
+:102460002599D1F1F1240BE2B382D7B5E7E1782FBA
+:102470004C8E65728458BD1FE6829C104802A5C32D
+:1024800005A42F0BE8312D9DE98F26535F2AD44FE9
+:102490009240AA8396AD1D525524FFE727DC2F5B9F
+:1024A000618A6C2FFDC43CF17D80830471834B31C4
+:1024B0002EE0B10C0BC50F347B558B2344B35BEF7F
+:1024C000176B8EC13C82E23F03FD07DABF5E76EEFA
+:1024D0000C26A7B552DB472D87CBE0642B9E6FE718
+:1024E000DD6564960BF1F439C7D3BECB002AD973EE
+:1024F00014C0D34BD98FE4405CCA9AFD9003F8B363
+:102500008A30FBB4C205B29890476D9EB3493AFB3E
+:1025100066624E2DDA4DC5592D684F2D8BE2977EA0
+:1025200047C38F4627368F39790CC4BF165A61BC12
+:10253000A4D4C442B93338154B6AF75AE0F9B20C47
+:10254000563F1F1EDEE37229DAFE27805E80784D3B
+:1025500046FF3952607EFADC2BE787CEA1DB5F7A3B
+:1025600072CAC0FD5993993ED2F625E570BACC35B2
+:10257000D25D4D32933397246BFEE205D3DDDB173A
+:102580004277E1E79D98BDA8EA6212DABF765EED78
+:10259000FCF4BCA3E13C15123BFF46C5A3C21414D6
+:1025A000CE05008701E7B246D6FBAE64D397E5A31C
+:1025B0004792865DF879BEC4BCD393BF049CF68C69
+:1025C000539D204FDA52287D523CB509ACD4FADB3A
+:1025D000397D3EC3CB2F2327867F89F39538851716
+:1025E000401F8EF71C2C8365CA8B4781DA017EACB5
+:1025F000073C94E63D20CDA2F5F6BB67A3FCDC3397
+:10260000AE05F7BDCC6EDCAF56A6707C1467A9C8CA
+:102610007F6D9CFF2A08F323B57ECFF37385F347C4
+:10262000F87CE17CFDA84DBD0BF69592CCF61FF22F
+:10263000FF7A45BDFF57CAF5D738EB1D86F8C73876
+:10264000EEFF2DFB6CA8CD4B0F7A9AEAB57F8AFF7F
+:1026500077863E013F29A3D4AAF7FFDAAC65D8BE3E
+:102660002C53ADBAD401FA5874DF4B107EE80F7AC0
+:102670000551D918C11F5C9629FBC7D3E71685FC05
+:1026800014F65746F525C45F2C8A4A2E1A31D02FEE
+:10269000DC652D23103739AD9067C11F3BDF7936DC
+:1026A000271BFD4209FC423E3FFA854A0BE9C378ED
+:1026B0004F1901BB06DA5D2340EEA8C463073D4213
+:1026C000FD429D7C3A6DBD03F93D7C3D2AB79E06D7
+:1026D0007CB5298C8FC3FD413999D9C19A9C0DA72E
+:1026E000870A27A39B18BA7533931BDB9323C8FB78
+:1026F0002F2F9FE694830B703D59B2075CB5EB8298
+:1027000001095C9E6F27337EAAB13DDD06CFB5F986
+:10271000C3F1434FAE423C1DEC1916BFA1F61AB5EA
+:10272000A3CCD45E5B2984D65FC6E11D0D1FCB40D0
+:102730005F47E0A303C9262E7FC2E3447718EF5F0B
+:10274000142F7114B2B83E89007F91DB49CB29BFA9
+:10275000C0FDCD32B3DBA9009D6616BFE3017F3E0D
+:1027600053C6FB0822B538AFB10F3CE772889F45CE
+:10277000D8DF9F939310AED60C93C13E23E41E8303
+:10278000FD18EDDC84EFCBCCCF25003C73F5F00CCD
+:102790003B77B982E706B31EE68D37B9899FF245CC
+:1027A0007C1671A3C08A37611C56E37385F3B92682
+:1027B0000F6C0A1B77B56318B3CF445B40A4E75F87
+:1027C000E5A0F6349DA755DD857A551B9FC0CF6FD8
+:1027D0001BC7E28D36BB5F5122C0E17ECEE7D1CE72
+:1027E000D9A14A89E5747FF72BCCFE96C6996A7CFD
+:1027F000188F62F15A85C34E2C29B082DD3E091C28
+:10280000F814D8CF56451FB712F97EE2EC743FE7B3
+:1028100090932BC2F61393DB570EFB97B2552551BD
+:10282000B7FF0A876607F4227F479BEF3E2EE763D8
+:1028300072DCA40EEC0D9BDB0FF75A316A5D218828
+:10284000C5D85C3799AD6B8F550B475B7474D891C5
+:102850002947BC8FF82F0793FF7649AD81717645E4
+:1028600022704F66E7F672B479A3EDE37CEBDDC42A
+:10287000CF3B603D5764BB62A883C90D69DCD61AA3
+:1028800090D36484448647D013290EC6A7F1729F63
+:102890000BFC754A8F9E48F3890E99C3FB5FC41FDA
+:1028A0009ADD5DD2B56F28DD6FAB4D720B20BF8A0C
+:1028B0008EF6BA74F0A17A7D9643173F106D1E9480
+:1028C0006FA28BDDBB575998BFBD679CF19EAC8151
+:1028D000C3EF7D5E46930BE31D9A3DF6AF39E79754
+:1028E000C55F05E04E07970E800B01FEFA415B6B5A
+:1028F000047949E1D3FE55E0B39AC3E5694ED7D1D7
+:10290000E033CA61FA97D241387CCEC7D7213EF373
+:10291000914311E0D86A97D3671BF8BF03ED904845
+:10292000FDEA74E78DC6871A7DDCC4F14205A42157
+:102930002E203BBCBDCCAFBCD3A8E7C4F96E2E9F04
+:10294000C9590AB744DE3FD146FC71F1A1F9E572DD
+:10295000633CE179078F0BC4901880CF69F754016D
+:10296000F2142CA699A394A1B04487007A2215E60C
+:102970001949C8035C7E86EBC11495F9C983498B5C
+:10298000C0F44A06EECFC1F711AE07D3A95F03F139
+:10299000183822F8D38369DD0A360851F11E5CF03D
+:1029A0009AD05F76129F00F367903E2C87402A02F0
+:1029B0009D3F9BF40A39147F0F54D48D02F9FD0E0C
+:1029C0009CE392D039CE678F6AA5667FACFE37C193
+:1029D000FB93B07DFE1F82F792321DBCE51423DD10
+:1029E0007C597837707887C7F38A219E970DF13C20
+:1029F000FF6EE053F92CB33F7AFE2E637CAF2D9B24
+:102A0000C5F32AC4EA35780FEA92D1FD9072FB56DD
+:102A1000419E936677A2CE1B168AFB594FFD4082DA
+:102A2000380A918E229CF06EC885F22C3B05E53168
+:102A3000B323C6F3FDCBD973AC70EF1DF29FFC221C
+:102A4000B33798BD24733A287696A2FFD276F6DC87
+:102A500076C785FA493BA53D787FADF947AD8159E9
+:102A6000E82F858FF34BFEF7E0FCFE80EC827C9331
+:102A70006E7E2FD67D6AAF214E1BEE076976D57824
+:102A8000BEFFB28067DFA570BFA5CC222CBEC9E017
+:102A900020F375DA9CA7F11EFCF9B326F4B74E7348
+:102AA0007FAB18FC2C3BF377EAEC03CF794DCA459A
+:102AB0008638BCE63FC138C8AB2B53FC22D8739A8A
+:102AC000FF04ED2EFB40FFA9CA127805F637E51585
+:102AD00011F342A2C137DC6F0AD73F335398FEF996
+:102AE000560A8F1784C1538BF785DF4BB76BFC27D2
+:102AF00079053DFF87AF2FEF9A88FB278A2E1E3B73
+:102B000034144F14542FB92B3F143F8C10376C01E1
+:102B10003AD4E2869A1ED3E8D842FB5AF19E397223
+:102B20003CB13B7BEF30E617BE900CFC59A1B0B82E
+:102B300091B63FEA17DE93A2C3477180E96DCB7F60
+:102B4000B5F42DA1F02549C4CDFC83169795D62B5D
+:102B50001592BC12F9CC86795AC50E01F94EF2C70E
+:102B600060BDF2B8DB1743EB965D2F89A203D69BBD
+:102B700045628410FD68791D6D810F5601FE4E1F60
+:102B800097DCE7F2BB2B218866F0936243F844F9A7
+:102B90009664A83F22791E4D413B6150689C08F91C
+:102BA00060430DF967CF48EA63D06FBA55FD11F65F
+:102BB000FFCFC3FB2F53305EBCF72BE13DB40ED3E8
+:102BC0000760B39174DD7A36DA7839ACE342FAEF14
+:102BD0008F4B2F22781FB309700671964F880FE232
+:102BE0002CCF995F14411FB5F379AE201D2E7918B3
+:102BF000DB2FF4DBBCD1B90EE8E2AD946C9CEF396D
+:102C00009B67F528DABE6F83340AE236ADAE67AC57
+:102C1000903FBB6B637B469F8EFFF66DF60C89E49D
+:102C20001F6A25FD4B3015E1B9E259A98A2627B65E
+:102C30008B501F609F6DE852609DCD1BAD3322C548
+:102C400035E454C6EF576C60766D55AEC90DE2ADF4
+:102C50009878A524B88F7113B79F36C48DD8DA5BE6
+:102C60000ABA285BC47B0D5ADF1D4FEB716354F425
+:102C70000F2E1EB115C75FFC49A99BE5517A6DF96E
+:102C8000B4BE2AB774CC4A5A1F12EB39067C45F5FC
+:102C90004C8784FAB4330EF200E2464C4D59496B2E
+:102CA0007102A98964E7FE3D85D9799BCD1A5C251F
+:102CB000CC83DCB55146FEDA972EE2FD1385DB7C32
+:102CC000A8FF393D8E504A24E5AAB71CE058413A86
+:102CD0005BC19F2A775DF3423CF90AF02BD8AA002A
+:102CE000FFAF8A6287BFC5F7874284D2CFDE0D6D02
+:102CF00037920879D4FD79D671AA2515EE57F8BD1B
+:102D00002E714E45FA898EEF7B99BFD9E96F8DA55B
+:102D100070BC624BC720FDFCEF42D0356520BE2160
+:102D2000FF995C0AF9B71ECCA76D3D6A42F8BD9CBD
+:102D300027F8040A9FBDB922B5D9E8AE72ACBEE14E
+:102D4000B4BE9AD371F596FD6D8380E5531DB8EE40
+:102D5000CBB94F58597EEB85C7AF47533E6884FBCC
+:102D6000648A8F094AACCF45F1350FA6A0F5718A68
+:102D7000D5E7A7EBF5D87BCB12E812CFA508EEF587
+:102D8000402FB94401F9812E8889214AA175101973
+:102D9000484F0E82F95CAB0AF3D6435C6C6586AB98
+:102DA00013F20D778CB062BE59783EF10EA1E58525
+:102DB00044884B250A28AFF7E6BE89F7747B332C8D
+:102DC00004E815137EE9F3B624C6A7710546FBB3E4
+:102DD0002A359BFB9FC46B290CED2B2EC7AAC6502E
+:102DE000427A31918DDF9723F880DEF6B9B87CA066
+:102DF000E7DD080691D4214D1F111DAF2F0D9FE077
+:102E0000D2EC62413BA769E0399E137CCB87C23983
+:102E10002EA6E7A0757BAE80EBDB9595B7132C8BC8
+:102E2000EAE11E337CFFF7A632FF50A664970BF24F
+:102E3000AD73F9447D7E8C5C74FB145B3CE631A180
+:102E40005D99962BE079261E65F7B903F2B315E27A
+:102E5000910DF8A156476A68BEB8CF9EFD36E4FFD3
+:102E60004E2E12FC31B01F9EDF4CFFAF07F48B9C3F
+:102E700053CBF2AF73D7E179261599DD709733C93B
+:102E8000E6EB28A5F5978E4918CF9E9C3301F3AB4E
+:102E9000C3D75FA9107F1585EF4B7912C23BE6A21D
+:102EA00027709ED7F34C286F26433E36E42FEBF372
+:102EB000AA511F1AF3B9278BFFAD9640B39BF12B94
+:102EC00091BC8340BE4F711AE1673F6ABC2FAE2EA2
+:102ED000B018EA93F3E4303DEC457A793193D1C5EB
+:102EE0008B170BBEF5D9213A9B7434C90774067F42
+:102EF00062A1018E8673C6056415E0B7EFE29F3DBF
+:102F000008F72471AE65B7E33D3887BF4627711CCB
+:102F1000EFF68C5F7F1BF49406FF703AB870FC5F8D
+:102F2000535302F82FD0EEEFC3F01F866F8C416A27
+:102F3000E7183610EFB87EF6407C6B7430E0DCF7B3
+:102F4000752D1F4AF1FAB29D3E003CAF937DF70A02
+:102F5000213C9D17AF392548372B950E1BC8FD988E
+:102F60008B0ED9C03FD0E88288DD057A7BFF9F8534
+:102F7000EFD2D5027326DD820FE27A6FC0A3CB4376
+:102F8000EBBC98DA9FD7F5622AD855352C8FA3551C
+:102F9000CD67EF5D15307D1A2E1FFE902AE2B81E18
+:102FA000F38B19E7CA53ADB67908DC8FB542BE1D65
+:102FB0003D9FBCBA16DE6820F2B45A949764B5C03F
+:102FC000F2108A7F8BF27D8ED3B75488B01E5A32AE
+:102FD000B84F17937BC5C9D89FCCD0F2926ADEC791
+:102FE000FD4F63F50BDDD76BFFA47DFD9ED20A8BF1
+:102FF0007731BBF96A1E97D7ECEE2936967738A55C
+:1030000058447CBCBE41F0617E24EDE7A574D2C873
+:10301000C9F66A6E079E2E7AA67D940BEC41D560A8
+:10302000770AC53D68F7251419FDC14435D680FFE0
+:10303000E4AA24433DA56690A17FDA8CA1C6B8829C
+:10304000E79B86E7831BF20DF5CC962B0CFD87DC06
+:10305000556AA8677B2719FA0F5B3ED5501FDE71B2
+:10306000A3A1FF37D6CC323CBFD8D768787EC9A69B
+:103070008586FA88CEEF1AFA5FBAED5EC3F351FE89
+:103080009586E7A3F7FDC0501FD3FB98A1FF65EF1E
+:10309000AC373CBFBCEF49C3F3B147B71AEAE30210
+:1030A000DB0DFDC7077719EA25E41543FF32EB6F07
+:1030B0000DF50AE53D43FF09CE4386E7135D1F1B6F
+:1030C0009E6B743039F75343FB55EEBF85BDA75354
+:1030D000C3E21C100F18068F3AB08C259DEC5E875A
+:1030E000F462F960A1A73C0DE8F3C7DE7648486AB0
+:1030F000F506FE0857D3AF170D4B60F6934AF4F26E
+:1031000053CB4FA57E8B378692427C90D2ED684A96
+:103110007741014B2548256B32C47B62B04C0A26AF
+:10312000637B7230114B477030B6A704D3B14C0D9E
+:103130000EC3322D988DA533780996E9C18BB11C49
+:10314000141C8DE30607476199111C8BED99C1CBC7
+:10315000B1CC0A9661FB90600996AEE0642CB38313
+:1031600013B11C1ABC16FB0D0B5E83654EF0266C6A
+:103170001F1EBC01CB8B82B3B1FC46B016CBDCE08A
+:103180003C2C2F0ECEC5F29BC13B70DC25C1DBB1C0
+:10319000CC0B7E0FDB4704BF83E5C8602B969706F8
+:1031A0009760E90EAEC27EA3822BB0CC0F3E88EDB5
+:1031B000A3830F605910FC11B68F093E8A6561F038
+:1031C000092C2F0BAEC3B228F8732C2F0F6EC6F24A
+:1031D0008AE033386E6CF0692C8B83CF61FBB8E0EA
+:1031E0006FB0BC32B81BDBC7077BB05483AF607BCA
+:1031F00049F0252C4B83BFC5F6B2E07E2CCB83EF84
+:10320000617B45F05D2C2B8387B09C103C88655515
+:10321000F0632C27068F613929F8298E9B1C3C8589
+:103220006575F06FD87E55F00C96FDF22E6ABEB231
+:10323000C784FE2CF753A3FB0B5E949766FE5E1CBF
+:10324000E45663FE7F8BE0C378A1A3EF05A89B8BB8
+:103250002C182FBC9904F03D813F903E3BC8D39E73
+:10326000CB8F6440BCE9F5147FA63EDFC1CCE30000
+:1032700015E27109FCD5298E5D29A04F6FA6CD906E
+:103280006744D42F300F720ACF83BC59A20E16DDCB
+:10329000EA7E98E172ECE7B7D0FACC6AA2E6D3FEF8
+:1032A000ED975B30AEDF9E4FFD205ADE97CDF26585
+:1032B000BBD298BE7C2A8DF9A5CFA531FFEAC942C1
+:1032C00096C733F3F6E18C9FCA93CFE33731387C4E
+:1032D0006324CFB3B505B2303FF602C79D48E57908
+:1032E000B5BCFF836935CFA7D1766F29C96DB1858C
+:1032F000FAD1F65D51DAF7803C086FDF6562F8F0CD
+:10330000BE2D723FA12661EA39FC84D717F77EF300
+:1033100085E1A1FA1B51FC504296B0FBC35DC7AAE0
+:10332000AFA7FAF0EA22D14D2507F9EFC5DBC67D3C
+:10333000389CAD0BF999DE5211E317338BF7EF4947
+:10334000A6F5998B1231EFBE7F5FA5667C3EC5F96D
+:10335000F6375FA047BFB9E537E33E34C4453D6863
+:1033600077DDC16994A8E6BFF669CF915E59DCF7B5
+:103370000E58DC05F2CF8CF3F6AA66DFB9F263884B
+:103380006A21AA81EE19BC56C1FEC1F7275613ACBB
+:103390001BCFFB50B8A2DEF7C6CBBE56019C7757B9
+:1033A00002D05D5C5E809C2BBE0CF0943051A1CFAE
+:1033B00006764C3478A63819FD2514AB4E2FC54F30
+:1033C000DBDF45BCE7DA9D58A800FD7FDF9693065A
+:1033D000FCE174327A6DEB7917E35B090501E2B524
+:1033E000B1FB739705E2F8562C972E7663D9B6B8E1
+:1033F00008CB95193FB042BC444C91201398C4644B
+:10340000CEC17890B6BE397196B5C44DE75B63A95D
+:103410008610920871066A2224D2FA12EA539C4D51
+:103420006374FDBAF3431BF0C3D93417D64513BBFD
+:10343000378E2BF0AB909710E7564A2557A81DFF03
+:103440001CD8BE1EFC91D749DFEA6B018E2A7B1F78
+:10345000A395BF6FDA5A329CC3551B1786F7303CD1
+:103460008BB21BEFADC558DA3F2F3A5EF39C2C2F81
+:1034700001E84BA2F4F529DF3751E34C309F86DF9A
+:10348000D35200F3A95A85C87997851ADC155539A6
+:10349000D73D0A51A4BFEAE5A92D6F5B183DDB506B
+:1034A000BE621DF2B9B8BCDA9BA6163BE9FC8BAE36
+:1034B000E472202309E5006D9F7E056DDF66627E64
+:1034C0008A3749467EA14048803C5F6275254C3D65
+:1034D000471EC4B2C58A2A99E17EC09500F05AC63B
+:1034E000F3F5E00D65BD1CF857F50BC90B1F9E2BBE
+:1034F000BCFF3613E7ABD8183C97C8E1A18D9BEF12
+:10350000E4F238BBA6D689F1115706C8555A9FED8B
+:103510001C83E7CF00BEA2F5DBB0AEF4D7EBB1BFA2
+:1035200093F5C7449A0B90C3745C138E93FAE769C2
+:10353000C1BAAD7FDD85B88EA3BFBE08EB19ACFF65
+:1035400085AEA395FDE77F93C9C9CF24352189C2F4
+:10355000A7E6AED935E5546F5F7BD75C2C3F58DCCE
+:10356000AB825C3D4CE5491B856B4DC93007F83992
+:10357000D75E35CCE6D2D16B3D8F6BEE5A6EAE0284
+:103580007D57BA42ACD980FCB4C49037B7CA69E65B
+:10359000FE0DDB471DE5F1BB29C9D5AFD9FFCD36FF
+:1035A0009D3D3A8BB865A0F7D9CBCD21BA263AFE1E
+:1035B0005458DB3693E7FB37C039568AFCBE82F39A
+:1035C0006B22E1FEBC2BB5E61C7A872CB7104F04AA
+:1035D000793C103E84FC95F2C167B61C8CCB524BF3
+:1035E000CD1A695E0D4ED1D6AB8F12FFD5E0A4C1C6
+:1035F0005B6B3FB47AB4C2EC6A9F018EB3EF1B835E
+:10360000F1CA7A1EAF278956CE9FAC5F1D5D672B2E
+:103610008C935417D03BD423C9176DDD3AFAAFBB56
+:10362000F323C197C361A599E9F130F81E5E333CDD
+:103630001EF45038FE2E14CECD1682EF530436DA27
+:10364000591CC93103E76FE0EB13C74CDC4F035F34
+:10365000EF859D717E13ED5FBAD1BE1EFCE093A590
+:10366000DE476A403EAD37633EDBBD3B57BDFD23C1
+:1036700078EF639D19EF4CE6C63D5C08F7B1A7B83B
+:103680009EA30AA007BE9FE021DA9F2AC0FCF58412
+:10369000CD7F52BBFFD89880F03C5ABEA17D2C2D27
+:1036A000FB762CA886B8CB919D57ED05BF796E2C83
+:1036B00091D231BEAFC8C87F5EF38746FB400AD5C2
+:1036C000C581F57AA8EBE247737DE60FF5743E6F8E
+:1036D00093B1AE8797490F2F57B9115EAE0A03BC5D
+:1036E00084E7ED7E5107AFF298E10ED0EBEF3A5D43
+:1036F000088F8698A5A9009F861D2BB09CB729C668
+:10370000FBA16EDD059D89867AF3B674AF5EAF9C32
+:10371000DEF7443CD0E142A7E8FD90EAB9E38BD55F
+:1037200056B0634E2CAEC252C3FF82CE6CAFCD30CA
+:103730008FB17EBA43A862F2D99530ED1CFCBAD0A5
+:1037400029E33A1F6D62FEE6478BAD5E58E7F862EB
+:10375000C5CBD6757A991DC5E035FFAE38EF87A386
+:1037600043FB8B36EF3F7B7FD4C22787AC04DFD986
+:10377000F9E21C7A3BAA5C923E93517F749BFF0C4A
+:103780007463A5FFFB02E3A812D6B5799B3B452FD6
+:10379000E41313B2C5B01E1DE73AACE3B7E87AC133
+:1037A000F89D8971100B43F9CCEE413C700F42E754
+:1037B0003B29D996431C41BB0769868568DF05D63E
+:1037C0003ED9439B3EE91A76CEF7CC299EB2412FD3
+:1037D00037583B6450B60D9D1797033F7DD2D59A5D
+:1037E0000AF2639E78FA5B91DEF7BA3E9DDFCFFB6B
+:1037F000CC01A3BFE8D3F6992D19F88CD8FACF4D98
+:10380000EBC7A3BCDF53CBE76DDAB2BF722CDD7F11
+:10381000D3B65332EC232DDD539B9E123ABFC0EF3B
+:10382000811A371D94E17C47CDDE8BBE772EFB7E5F
+:10383000C03E6D4E43DEA197F4027FCE2A221AC30A
+:103840005EFF1E9537C75E3113B83F2467692FFAB4
+:103850003C8B3F9D436AE2015EB3BAE6A1FC39F6B8
+:10386000ECE4BD2CFFA8A310E8E31362C2F7DC3F31
+:10387000216FC68FD6C16F75BA963FC9BE6FA3E5DB
+:10388000B7D00DA6637E7A437B2FBC376621929713
+:10389000CB25817DAFC627A03C6B60ED5E625D826B
+:1038A000E758CEE49197FE07F5DB3A8CF2A97E8DBE
+:1038B000B15E47A6A6427E77DD4366C8202273F537
+:1038C000F28FC2EF8E7466D7D7939676B0E71E97C5
+:1038D000595EF72C854883A91E5AF0EBC70B6B691C
+:1038E000FDC17476BFF311F733E0BDC774FABCF1C4
+:1038F0002E9FACE60D3CDFA1AED1D3C7129C8FE961
+:10390000AD46CD6E252E88E30F867F0D8D7EFEC1E0
+:103910005D22DE3B0D86769D7C9EBDDC78BEF39DF0
+:103920003FFCBC84FC00CFDBB8E91AF4DBB4F368DD
+:10393000F8D2CE63DE14F93DDF27D30583DDB49DD5
+:10394000C34FF3BB9F0FABBF10567F299DD9F72103
+:103950003F9DD1B799F337A5FBE781EE1758039543
+:103960008C4EFA64FD7DA81CEAF7C2B9FA5938BF3B
+:10397000D07E2FA58F89DE2F2634DFEB91E65BF01A
+:10398000EBA79E057FB4F1970FC7C365D031A9237C
+:1039900015DEB398BF71693CC0E9A8E48D07BA3958
+:1039A000E613AB22C14B1AC4E506516D02C57B93E9
+:1039B00046FFC54BA6807EFFF346B3027E61F32629
+:1039C0008B1FBEBFD4D43517EF6B68FD20AB2FC360
+:1039D000F72A9BB7993FD0E3B5F1670FA7627E073F
+:1039E000F10E66F7E9FEC1F0E9A0A60D7FAA043F3B
+:1039F000B99904909EC3C7C1FAC12494D7B572C2C5
+:103A0000C0E75ADCB4993591E6AE55A7206EDADCF2
+:103A100035F108F07D33913ED0D35303D034F557C0
+:103A20003E4FE779779791CB40BE68F020BE149463
+:103A3000CFAD9B7F38F220DDCFF10DAFC40B7A7F85
+:103A400095DFB79FEE9CFD7EF239F4C3094AA7FAD1
+:103A5000F73134B9EBDA46379046ABDDAC9C6FF604
+:103A6000C78FA5709DBFCE8CEF87CE7FEA899F3E22
+:103A7000067944EF5AF0FE63DE537BDEBE82D6E762
+:103A80003D6D7654B363D8E03E58C34B33FD1FDC25
+:103A90004F6878687C668F0CEFCF403BF8071A3E82
+:103AA000E63DDD23931103E157D6D923F7D922E070
+:103AB000A5F36025BE67B4F92F32E0FDD84E81A48E
+:103AC000650F1CDFB06E0FDA310027C423C7533FE8
+:103AD000DE06E0CB3F657B01F653406E9F0F5F072C
+:103AE00040AFA6205DFF623BDD47C3EF2D6E8043F4
+:103AF000C32FEE8887F31C915A187D3FBE3415F210
+:103B0000DC1ACCDE54054BD6DEF0E33B91EEEAF74F
+:103B1000DF99CAF20ED5749EDF910EE7BC6DED758C
+:103B200078CE3AE241FA6B785CAC813C98CF255272
+:103B3000F57404FEB89BF3C791F514B9F49C4740A3
+:103B40005E3A42FE8EF65EF39DFD7110760FF939F6
+:103B5000BF879C3A48CB5B67F2B79F6E372C43B95F
+:103B6000FA51A69A06F793140E9A1C45F92AEEAF5D
+:103B700048637862F218C751FA2B8376E8DF6BC688
+:103B80007B61DD382E3FD9FA8BF8FA74DFB1608F94
+:103B90001C498DFC3ED0A67EFEA7FA5647673A3EEA
+:103BA000677CBF6105E3738DEF7DD754C1F3CF7E92
+:103BB000C7F808C6813EA2FBF2A7E1F39E6902CADC
+:103BC000050BF147E2EF0D66CEDFC6E7D462477B17
+:103BD0004EA313BA7F09BE4716A217BA4E12E201CE
+:103BE000ED95BA87E8789D9DDD0CEB623F39D49E58
+:103BF0001DE2E37A2E0FBE3DC8280FC8DA940B8A67
+:103C00000BCC37FB7EFA18F02FE557AF0BF8D78CAB
+:103C1000EFDD7CBC65F7DB37523AFFB853E35BA3BB
+:103C20003C0DE7DB86AD77627C309C6F3FCE682130
+:103C300011F93683BF3717CEB7197DFF5679AAC160
+:103C4000EF2761F0A3F2F127DB5DD1E1182E1FC74A
+:103C50000E72213CC3E523FDFB1D291C48871AFD7C
+:103C60006974D7F8F30543400EF5D3A7467FFDF4FA
+:103C7000A9D15FF8798DF01B20DF20D949673F98E3
+:103C8000EF255E3BC577608788DF4B3AE90AC4437E
+:103C9000FC67690CB915ECF0930AAF27B27A20459E
+:103CA0006E0739A1B5076258BCF2644D203E5167DA
+:103CB0005F1FEC16E321BEDBE78BFC7D37CC48A40D
+:103CC000EBF745F9FE9B168F38191B3F12D78BCDAA
+:103CD000F201BE2A445BD65D9037DA21E2777CE6BA
+:103CE0002CB93E1EF2434E760FBB7A066DBFED2512
+:103CF000FE193FAF2AA55338CFE6783F4ABC8F1450
+:103D0000D3F3CDEE66F6F39CD591E944BB37AFB360
+:103D10002D92411E51BB35441F049EB3EF2C34AC91
+:103D20000D6BEF9E8CF4D418464F1EEE1F1D1BC466
+:103D3000F3FB479151DC3F31E9F3412AC4BCABE1CD
+:103D4000BB9C27F789986F7DBA5B24ED70CE2D82DE
+:103D50008F007F7B53902E9BA8FCD0C77F8F03DD05
+:103D60009DE33DBAE3BFFA43E1F76897F9CFBE3769
+:103D7000F247B43CFEECBB173D07F55F1FC87A8FD6
+:103D80000CEC5FB6F3CC2D20FF4FEEB4108CABECF7
+:103D90007C31EB7B50DF6EC1BCA393F75A54B4A7C0
+:103DA00077DA318FEE64268BA7B6EEF8CB48CCDB02
+:103DB000266D8837C760E6779CEEFEDB1FF1FDDAE3
+:103DC0006E7A2AD0B73BE3D01E6FDE1EE30327F5E1
+:103DD000E48EBF14EAEF2FBEEE799A6416BF3F69F6
+:103DE000273320EE753291C5AD9B9FBBFC892574AE
+:103DF000FD055D3D32BCB753F6FCDF4782BC39B9E7
+:103E000095D91127CC7D3F266E42860CBEE73E3306
+:103E1000C5D709B0ED28AF3C3778E755DEBC487010
+:103E200061703849E100E7A270690039190D1E85FB
+:103E3000FFB1F038750BAC3FBFFB32BC7F08C1450A
+:103E40005059BBDD6715F0FCAC7DE75F46823CFE58
+:103E5000B87309EAF7F39DFBBAFFE7CE2DF82FE41C
+:103E6000DC8BFE63CFCDE8FFAFA09FC60CE483815F
+:103E700074FEEB6F61FD177637EEF702F9FF21381C
+:103E80007FCA7FE2F9BF22DEB70A98BF723EBC3F0D
+:103E9000F31F7BEEF3E1FD258E77BB0279122777C6
+:103EA000FC3D8BE8CE7FBE73BFF97F94DE353BA827
+:103EB000D7D4A214D0FDBD4B3AAECBA6E51BEAA7E2
+:103EC0000E705B2D51EE694C19CCAFB0082CEF9BF6
+:103ED0005C2768F1A55E43DE534603DA1B53D4FB2F
+:103EE000D8F799A4965EC83BED2D9DED5E893DF215
+:103EF000F17B02BDD3C6F1BAD1DF7A5D20AA40EDD5
+:103F0000DB29A593F781BD77B52AA23D484BB403C1
+:103F1000DFCAAA64ED45463FE38630FFE0FA19C6E2
+:103F2000E7D7F1F9A693854A0185D7F40C49F151F9
+:103F300010DD50D26286F3DC70B3403A74F1CDEB01
+:103F4000C2E6FB2304D07476E497855F413FFC16FC
+:103F5000223C4889766F771EF81106EFDE69A35878
+:103F60007EB1E466F09BBEC08D7153EE879AF978FE
+:103F7000B36D792FF0AD9918FD4FCD8F8C0667C2C8
+:103F8000FD529C676808EE665544BF54371FC24314
+:103F9000C3C797C58386BFAF8B0F398318EE75B53E
+:103FA00072AEB5761EDC435821DF9DCE7BF56AF6F6
+:103FB000FE88354F4038D61499F1FDAD3F996A0A15
+:103FC000C170AE1E7D59D377D9B46E80CF5C0EC759
+:103FD0003AD282762739FBC517C58578FB8776EB01
+:103FE0005C9590ABA85F52572CF863E9F9EB25E29A
+:103FF0004DC88738A8403ED0C7417DC63AFC5D9980
+:104000001A9AE77CFDA3C9877F76F93E95471F5032
+:10401000A41F8412F366D8EF5D68FEE3ADDD0C8E5D
+:10402000CDF305DF50A423BF597FFFBB3983C5679C
+:10403000DFBF7B34CAB992FB472430BFB600F379A7
+:104040009AB9BD7FDAEB4A8078CEE9EE610910AF0C
+:1040500039BDAF2C3E521ECF7EEE57FE76B115CB4A
+:1040600093E542879880EF9D4C413D5C1E4340EEB6
+:10407000848F5B91A1C5655AD8BD246179F875FC20
+:104080001CF5746842920E6FABAF3A268D1C880700
+:10409000F8FB4077AFF275E10B7E2CC0757F4C5F6B
+:1040A00065A4EF13FE88CB85EA5D6764881F4CED3D
+:1040B000CEC6EF4B4E2D37BE07F86006F7CF4793BD
+:1040C000D1B0AFEA5D13E32F07BCEC13DD3114BEB2
+:1040D000CDDDA7644F84FBB97078C2FC10473E6405
+:1040E00076D7013C0FDD1783EFFFBFC6EF8BF2F8E9
+:1040F0007721E1D341103FDBC0E17A2683C5D1AF00
+:10410000AD2E31A7D075F3BA945190573688F73F4A
+:1041100093E1C2E783F938ADDFA0F9ACDF4159691B
+:104120008A74FE21598C7EEA89FB5B45C27F1EDEC4
+:104130004AEEB7FBE1BDB8D3E5027F6F269CAE091E
+:10414000F2C7E92AC107FA17FC58AC570BA8FF5F62
+:10415000D3F2EEA6327DA9D17D389CF767980C7911
+:104160000EA738DCDFE6F4A1C159836FF87EB5FEF7
+:10417000545E8DD7C75BAEDE36EA17609F34750B91
+:104180008A894ED524F5C9C087CDDB1E30C3FDC258
+:104190000DFCF759885433527FBF7B2683FDCECB6D
+:1041A000EEFCB1683F7EBA9AD9C7EA9C53F160072A
+:1041B000BD6672BF3116F8F175D1F05DF3F0F2BD56
+:1041C000C54A63B9593F6F36EEF3DAF92566080F31
+:1041D000DD34BFC79CA6A3A73319EC7B415AFBA0D3
+:1041E000F92ECC5FA4EBE13EBCDFB710C8C7C8EB2B
+:1041F000EC2D8DA3CF6F6A496474D8D0D923639D09
+:104200007D67585B4F5B279C9FA655C719EAB3CBC8
+:10421000FA32002ED516FF2277043A7D2853BB8749
+:10422000FA927A42A5743BF2FF073D71AA32D27727
+:1042300050676732FAD5E987B448FA61E112571A34
+:10424000C07FE18E6169C01C0B5FAA488DA41FDE90
+:104250005ACCEE0F0FF0BCCB93D3A87EB854A71F57
+:10426000A6C5207D848FBB2AF302F58386AF7FB37A
+:104270009C790BF44304BEF6641AF5C3F4EE5AD4E9
+:104280000FD3A789C4A58BC75D9F793EFD50927A55
+:1042900003D6CDEEB80874F316F74B00AE50C23A11
+:1042A000A027EECF64723F5C5F4493E7395902BFA9
+:1042B000DF3E8F3CFF5F82B326CF175EC7DEE31F72
+:1042C000488704E5F5C21B04FCFD92853B983C5FE2
+:1042D00078338F4B86C9D71A90AF057AF9CAC6379B
+:1042E00079983E68DE96FDC399F4F98D1D66B79501
+:1042F000F6BF31246F0BF5F2F6FE4C49837396122C
+:1043000001BF3366C61197515EE5809C3A34EAC519
+:10431000BC6780EE5F63EF99FD89EBF15747BD58AD
+:1043200000F1F4C37CDE67B9FC3AB1983496533897
+:1043300094CD61F6F0822D22C2A1A98BD9794D9B33
+:10434000047C9FB732FF0CDE1BCEDBC1EE0DE17BA0
+:10435000BE253A3CCE7BADAF7D303C5F27E0BD67EC
+:104360009D7B1E7BEF6F0D8B135BE97F902FB1223E
+:10437000367E3DC13C1D15E3CD0B38DCAA2D81BD39
+:1043800030BEFA67827B1DCA35637C7A41CEA46356
+:10439000E01FCCDB14D6EE5E81F7190B20EEACF3F8
+:1043A00047DEE2E7BB4DF4E73D0379816F88117F7B
+:1043B000EFECAD7038347C4D38ECA77028F8EA701B
+:1043C00068EE7E00F36FBEEEF90F64F2787B3E2953
+:1043D000007EF9934945FEF7BE2CE27BC5731E189B
+:1043E0009EA6CF53FA1387C36B264F7B3AF46B62BA
+:1043F000EF1FD7AF7D7A0FBC1A3EB3938C82B07D8E
+:10440000FD1AA39EECD7CB5D2ED4BB335B9E16E08A
+:104410007BFEB789047F076C76BEC503F7AFFB63ED
+:104420000228CF343A4CC892D877DCB8BD776850B0
+:10443000A01CFD8A6D82827C02DFD3803AC5037C9A
+:104440004F63F7E57FA9E470C7F84CF33686A7669B
+:104450008A17E0B34A6AEF821EB989EA1DBC2FEBC6
+:10446000EE3143FF06DA2F19E58E1BFD5D4D3FC18E
+:10447000FD5D49AA0E6F3B0E32FADD28B84904BC37
+:10448000E5D2FFCE85B768F8D2EC870BC59B068FC7
+:10449000842C23FEF6C7F4568FC67B2AF63B40A435
+:1044A0003B11EF553EEC188678CCE472369CBEC1C9
+:1044B000DE77E9E24BD7C0C6F1C3F531982787EB29
+:1044C0000E65F6905EBE84FBD1CDA417ED9AB47450
+:1044D000CF5319BABCB0E93C7FA5FF5E37D4AF3EDD
+:1044E000734CF47EC4598AF73F5A7E2DFC7214E651
+:1044F00083F1FAEECCC20333E9793F5D2EE2FBC9CA
+:10450000D79B5C6F17031FAF3413A0CB4F5F35AB46
+:10451000CC0E8D43395CFBDA213384466A21BF809F
+:10452000F6ABBD87C9DB4330196DFB3DD5632A7CF3
+:10453000B784748E81BCFD69EE9E0AC8DBBEAE6096
+:10454000FF52B8A7BBB64C79FB6D80EF0A91007C97
+:104550003F585E86FECA1DB70B48D7EF2CC6DFC298
+:1045600022D74DCB7EFB6DBAEECDCB53F09E6DA620
+:10457000BAA702E86DF6D5761BDCD34DCE15894778
+:1045800007C79B49EF5290DF335B6EBF0EF6DB40EF
+:10459000F502C45D1BBAF757A4417DAD80BFA3D619
+:1045A000ECF5C8F00A54EF9A5332C43FEA683F4032
+:1045B0004FF35AD6AF798380EFF7D451F900E7ABC8
+:1045C000DB20107891A497DA7F5636AF0F3ECCD41B
+:1045D000BB968EA7F57A180FF36E48C4DFBB6B7ECF
+:1045E00095BD1F5457B4642FC8A73A3A8E3E26BDD6
+:1045F0001B6EC7F9E6AE1508A4063714657FBF0821
+:10460000E67BD58CDF0539D0F3A80CFBBE85AE97D1
+:104610004EE79F2DF655609EF5F70405F3A0ABBF5E
+:104620008B783BC9F980647C87F199C0EBDC2ED490
+:10463000F4E3C6ACA12CCFFAAE25ED70AE3E6F4AC6
+:1046400036B844CDDB4EC960E77DB8183E3C43F137
+:10465000C6F3E0767B0FC97D3A39B52B6B188E9F78
+:10466000B3AD04F9FC365283F7E29E254C2F1F5C54
+:104670001AE313C01E312BA837772FFDC62370FE17
+:10468000134F99F1BEF444661FC6678FAC35E377CC
+:10469000435AD78A28478E6C617121F1F1EB2AD3F6
+:1046A000017E540E00DDED5E5B26833C3CE2137020
+:1046B0007CD9E377A6B2B8AF517ED4B91A515E3C2B
+:1046C0001EC3E443FD9AC8F7AB51E5C5A24A26DFF5
+:1046D000C3E4C1828C768CFB85CB89666263F65D10
+:1046E0003EC9877AAF3F1DE9B7E9553301FBAE49B3
+:1046F000526E5903743333066E92295FF8F7807C4B
+:10470000FBD427B8BCF4F94DB7FE660CC0EF30C03F
+:104710001BF8627532DEAFD6F96A11AE5A3E62FD01
+:104720001A233D6B794F3778C4D07B3EF47F373501
+:10473000C41155D7EFC03D942EE97AB76E137CF0C3
+:10474000FDA303F71CDC7B6701D615A0C3A6BBB88D
+:104750005E5D6D47BA3DF09D534B812E6FB95BC0D6
+:10476000FD13AFA71DF44AD31AC10571CDFABBD909
+:10477000F87A3A1EE8E5C0A38C7E281DBB80CE9B4C
+:10478000D63EB017FB6F105C30FF8175B5A8871B54
+:10479000BC22C1E71B0EA2BD4CF501E60DEDF68A69
+:1047A000A940E74D6D1605F0AAD18B467F07F9F7B2
+:1047B000A789D53DF25AF87D8A2C5744BA1367640D
+:1047C000237D356F3123BD347B193D1D7C4A443A2E
+:1047D000DCBDF4FA4AA09F131B8528F447E9AB20FF
+:1047E000445FE2E3661C5FBF99C51776AF65747DD1
+:1047F000A48BD9A7658F0F47BFA6FE353361F1079C
+:1048000062D3DB1FE7A3C370BA1BA097381D46A372
+:104810003B8FB9733AE41FD4FE82EEDF15825759FD
+:10482000FB77300E50D67E039E57E31F78AF05F21C
+:1048300036E6742C61F98C12CBEFF9D2FB0ADBC798
+:104840008321FD980FFA11F24FFC741F2F6E79022D
+:10485000ED804F9E3C88F98DF39EA3F8A7FD4F6C29
+:10486000B1133FDAD93E94338D5D22E69712C95FCA
+:1048700078ADEEFD2D2D2F63DE2FED08F7C6AD16BA
+:104880005F351DDFF8ECA191784F7E2FB353BD4FFC
+:10489000B2EFCC106FDFC86B213F5362F921E1FA10
+:1048A000D73684C5718EFF260EBFC7246CEAC17B44
+:1048B000A6C6CEEBCD165DDC521C6266BF03F19B33
+:1048C00038F69E19C53FDC2FC2FEF4BF27A1E5854F
+:1048D0001CDFCCF8A7719B19EDA3C64DEB30DED7DA
+:1048E000BCE914E6CF96FDF2A9788043F336D1985F
+:1048F0003FB549F45B30CF4B3C6861DFE530E431D4
+:104900003575B1F73B9A3A799E5058FECCBC5FEEB4
+:1049100078D64B4133EF999FC5033F7DD4BB311E01
+:10492000E049E7C3FCA3AB8BA2E4279D2F2FA9731B
+:1049300005CF4BBA0A7FA7233C2FE923F807D5E31D
+:10494000F94338DEB5BCAE4D4C6E51EC17467A0FCC
+:1049500049B35FE63DF5F98F218FF6F8D68F7F0CCE
+:10496000FB9FFF8F4F7F0C791D64678C02F644F329
+:10497000936F61FEA136AE7A08B3A74E6CFE19E6BE
+:104980006F9E78D78276E1891D47B2C05E38F1F418
+:104990009954C8CB5CB4A302E3138B7E5586EF8792
+:1049A00046F337813E7D17903F1A8E8FDD5DA2DF83
+:1049B00046F7F9C93B16E4FFFE3CB3CE052C7FCF8A
+:1049C000C5F3CBB644CED3D5F2A19ABAAEBD7A1C0C
+:1049D000C8BB2EA6D7FBF3A3CE9757F63B8AD74B7F
+:1049E0002F007F5B78FE60E75511F3CA3E817F5050
+:1049F0003C350E31E6957DDE75DB4F1E83675D919C
+:104A0000DFD3D6F8FA7C70D3F2802F1BA2DE3904F4
+:104A1000F868EBCF318F0FF056ED02FDFF7916C429
+:104A2000378F9A0318370CECB02890EFD5B8E30015
+:104A3000F2CB895FEDC73C5BC2F3714F90FE3F96AE
+:104A400037C96317CD1BEC2C1F8DC31FF2D55CF14A
+:104A5000D8CEF3D2181D6BF96AD1F2D47E3E84D938
+:104A6000415A7EF20257AFACD842F802FC084580AA
+:104A7000AF8386FC3FEDDCE1F3290087CBF4F997A7
+:104A8000D1F201B99D3E005F4C2E9F58C7F331FB18
+:104A9000F32CA949970FF9414C1F36FB840391F081
+:104AA000ABE55FFE340CBFDAF9A2F185C69FE7DF04
+:104AB000F75783CB9A212CFF5F83CFF1B391E57435
+:104AC0000FE777EAB7F887E8FC965BB9DFA2E59DC8
+:104AD00069FB6DEF647AF9F826663786F3775394AD
+:104AE000DFD37A6308F3EF9AB6F58C0439747CD778
+:104AF0006F38DD31BA6EDA7250F672B9EDD3CBEDA4
+:104B000028BF5FF62EDF37F57723CED7BCE554C438
+:104B1000F93E92D4EB61FF1FF5323BE4A34E31E244
+:104B2000EF20ECE67AA9FFDC7619FD2E313E16E582
+:104B3000D1227BD13BF05DB7457619F31D5A97F032
+:104B4000FC887BDCF83B1EADF649F8FB0F4B013EC1
+:104B50003A3FD4AC78F07727CCCE9A02F0AFC2DFE0
+:104B6000EB941D26E2D3E35FF2E2FBBD5386FE45E4
+:104B700002BDD3BBD8F8DE48AFA4EC49A6F3F59646
+:104B80000B6EB07707D29971FE6B54D1103F8358EA
+:104B9000359CEBB49B7D0FCD6EF22BB40BB1C7F4FB
+:104BA0003AD1D173B1DFABFE1F05EC5EF50080009A
+:104BB000000000001F8B080000000000000BB57D06
+:104BC0000B7C54C5B9F89C3D67379B6437D990047A
+:104BD000121EE1ECE64D4258C2534539092426F233
+:104BE00070414554D4253CC23389F8B8D4D2B24080
+:104BF0008C88B40D824A7BD12E34A87F4B5B40BC9D
+:104C0000050DFE170816ADB551D16AFFDA06880802
+:104C10001A6005CBCDF542B9F37D33933DE764438C
+:104C2000D0DB7FFCB5C39C7366E69BEF3DDF7C3336
+:104C30009B48E89F8790752BED598A959004E295E3
+:104C4000884C88D3AB04DAF208FE5DA1FF4B24B494
+:104C50006EE775371647B34613E2608FE87BD701DE
+:104C60008B44485C1EC9534612E222715E99D637C6
+:104C700026686F4A0984AC77FA27D3CEC915F81B8A
+:104C8000DFBD245EA51DC6B3D3FFAE507812C7D2D8
+:104C9000BA3D327E9266AC27135D1DE1D108E90B67
+:104CA000CFE99F4A48B94C21A3702495598231120B
+:104CB000BE9F9CDD37026F522AF186E0FD148737D4
+:104CC00040BF7738187C025E0ACF718047A5FF216C
+:104CD0003C856D010B41B88EEBE1A07F92CF89F04E
+:104CE0001D37C1775C0FDF30D59972B2805614A2A0
+:104CF0005CA1F875D85B09C7F3793D9E0909106579
+:104D000034E053E095BEA7FDB8A54DCA1509F0EAF9
+:104D10009248268E676A37D075329ED769BF7BE18D
+:104D20001FD711D27F89DA62A3F3F4D92517A0A186
+:104D30001F85B51590A0B4DA0019CF3A443D64231D
+:104D400085F4BB3DEFD9DA68B974E77BF8DE02750C
+:104D50005A26C7AB13070C27E4FEE0305F5A3E7CAF
+:104D6000373BCDE2C57AAB924A48C3347F9A653867
+:104D7000803FACB16520212F92BA21127D6FAF2FF9
+:104D8000683D7223F015FDEB0FEF0B5AB54278CF5B
+:104D9000EB8484089DC78B715D75CD9E46EB9EAEFE
+:104DA0007A00EA4D80FCEB61BC82D67ADAFEB0EA8A
+:104DB000BB5B1D45C8B4E72C444A21647CA723286B
+:104DC000011FB4F521241D9AD5C5015DBAF119C59D
+:104DD0002F498D7CD7233FF2EF289C153BE9FCA798
+:104DE000F967FB268E20648CC4F04A5C6D23A63BD9
+:104DF000018EAA256A6AA4DDB4E7CECB1E0ADF12B3
+:104E0000CA53D03EB1C2754B1E852F710BC5960A91
+:104E1000DFFB1F00B8B357F82DC01EE349DB831238
+:104E2000A527F93405E111E334EC97917F1B1EB3FC
+:104E3000045723FFAA926FA89E7E6D26FA8519FD5E
+:104E4000F61E43FAD5341F63F4DBBBF500D0BFA6D2
+:104E50005972C5A8301FEF2ECA44E4F1E0049F3216
+:104E600088D23526DC0074B59212DFE47CC4EB6393
+:104E7000309F6E78E5F0F586D7174F6D7BB2887E50
+:104E80001AE8B078B349045FE2BB1DAA0DBF2BF24C
+:104E9000F89F023CD46E6A6B88A570BD76EAFD046B
+:104EA0003F8537BBE37CA888C29B3D0EC5B86BDC51
+:104EB000173BB61DB0D17FBE087C4C5FE410FF6A83
+:104EC00097E36AF860FCDD858F3DC7103F16A8D3D5
+:104ED000E7BB6D6401D0B574AFA40581BF63C8FDA5
+:104EE0003E5A6E5729A351B8F6A9322F2546C70E50
+:104EF0008FA2D2F6A5B75BB4202D137919997F3D07
+:104F0000FF5E61FCC5F121E829F88890C6F8699434
+:104F10008E79B9FEDD46BE792ADE43DF8F6F3FFE14
+:104F200020B144DA6D5F497C73AD91EF28FFFCCC72
+:104F3000D0AEECE1387F61E47BE04BE013337D6879
+:104F4000BB109397A7E2611EFBDACFCB80EF6BA576
+:104F5000ABF979EB4ABF6FA2B567F9F195C83EC0CE
+:104F6000ABF9F9518E5FAA1902ED79A0B5259248E7
+:104F700051DD2FDD7F14E05B6A6F4BB89DD2B7A681
+:104F8000E4820DF0B03AFEEC0DFE28FDF40447EB90
+:104F9000A55C878FCEEF60670CE2BB5B3BA0271D53
+:104FA000E7DD95337D1329833E119750C4952DDAA3
+:104FB000B3895CEF4ECC5A349929AD2EBB275D895D
+:104FC000216810146A47CAE00985AF62EC2E05EC2F
+:104FD0006719D1D94B37F6BB8D0C037A580D766D16
+:104FE00052D62DA7C1BEB42A6D6B1229EA5BD32419
+:104FF000B43F375F6A6C01DB75739AD560E72A5559
+:10500000637D126176528C334DA374E7EF2FE0FF7E
+:1050100007717E53558A5ADAFFD4ACB860804EF9D6
+:10502000D6B177F926EAECC57B97E5FB7D85DDF106
+:1050300033D92DF0E343BCFE3E96E26718CC73767D
+:105040003D43D3D5F161C6A3192F133F9D3F99145A
+:1050500075C7CBB5CEBF0BAF84FC04E6374993C907
+:105060003A7704AF66FCD0BF29F0DD7B25F43B091D
+:10507000FC820EC542EB95D74944F805657D7574F1
+:10508000E7F099F16AC69FF03726F176EF00BE2867
+:105090003F4D92B738801F2A7FD43A3199EAB1CA7E
+:1050A000418CBE2444914BF17213419C015EB721A7
+:1050B000DFB9ACE86750BBCEF8E3D3F2D3121D7F63
+:1050C00072277D47E12C57A5201511C0CB71135EC7
+:1050D0008E9BF8E2B87EDE66787F0FFFB82E0ABF9F
+:1050E000288D7920F713DCD43F01FF2183A857A82E
+:1050F0003D1AFDC9C844A61FA2DBC9F19DBEAE7E04
+:10510000183E1A916F24E2EF7AEEA2FD84346B0A06
+:105110004503996077A19C4C20DA9A763BA04246E1
+:1051200038055C97D37CB7BB69FB1252B9A65D8F7B
+:10513000E74F853D67F89EC0F13781040EC80950DE
+:105140002ADFE8E72DFABB57CC6730190CFED08771
+:10515000AACAF432EF4FCC2F399984240A6058B28E
+:1051600007B749003F09D8FA44C6B372FA9ECE9AEF
+:105170005EED46BD5E47005FE0B6003D4BF9FB5279
+:10518000BB2304F010BBB5A38B2EE0C390592EF0C7
+:10519000FB285EC895F8087C0FBB25E5645E04BE5D
+:1051A0003347EC0199F2F5C474FF0F000F1DD23B99
+:1051B00045802FEA97E5803E37BFBFF0714B0DBCAD
+:1051C000A7DFCDC7EFF8BC1683D34DF926BC3F2629
+:1051D000B8CD1D4D9FAF62FAD74E3D519D9C96C6EE
+:1051E00031399F447C0AF8970763999CB5C42E44D3
+:1051F00079282775F543697F7F8CBBF908C8592545
+:1052000009E077652E231FF6C6A7B790F07DE0F77B
+:105210004ECAB39AFCE800D2E7606C6E16D8B3832E
+:10522000B14C2F0BFFE165B7EF5937BECF08825E57
+:105230003EAE8D7A17EC4455C9888F46D2D262F7BC
+:10524000D9809EF380BF285EC7027FD1B607A1EB4D
+:1052500074E4AF20B49FB3D6C45FF664ECDF47D5E7
+:1052600018C055AA59BFD5FBD55D78E376B2377F14
+:1052700091B428248FE2752EE7D383B13101F0E396
+:105280004A9FA0724CF13787F89F6F94000EABC114
+:105290007F9F1B6B457F6FEECF6351DE69E32D75FA
+:1052A00074C8F9F4F93ADA0FC95307EAED3A69D448
+:1052B000B507FADB55E4C7B92EF6AC9DF691DE07CB
+:1052C000FAA5DA8DE2936CB69ED7F3A579FC1EFBA6
+:1052D00035B53B28919960570F5AD5815E9DFD7871
+:1052E000D36DC1F99FB7676FB1787AC6D37C7BB2B3
+:1052F000A68C88D44FC6C6CE8CE62788FE045EBB3B
+:10530000D617E49BC6967191F5C563ABBF6E3D326F
+:1053100048BFBEF8BA55737CFFF5C5A9AD5FE3FA87
+:10532000E2690BF50F016F8A2F7F9ACE2FFADACD43
+:10533000FC976096F635C8E1D3DC8FA41C943F6DD2
+:1053400068F7EFFA2E9F404E50168BB193406C31A8
+:10535000D5030A09588BE17BFF2A0BA5B73293A02E
+:105360005DA27A08FD4F331E4E6795FE03F856C8BE
+:1053700067691CE57F2A8F4F58D4A646F0B3DF96A5
+:10538000A9CF4A475F3E07FDBFDB962FC4F2DCF191
+:105390004B39A0174A39BE150FB3EBB5F14CAE6AC5
+:1053A000E3991CFD31CDAF78E8F3564D768EA4FD20
+:1053B0002DDE2B7B63102DE10CE0B7DBA6C8A9F036
+:1053C000FC84DD8AEBC7834E46FF1344AA00FC949D
+:1053D000BE17E3DB43CB47D34A723D3A3FF1D1B42A
+:1053E00089582715D4E1A37CB9CCCEE4E10471330C
+:1053F000B8D74ADEEDF4D1F9B5EE44E0CF8356627A
+:10540000F047D23D0AC29BEE6178ACEAA4C2398271
+:10541000F15D1D1DBF4A516DE0FF5775DAF039C0CF
+:10542000817C196BECC7E361FEB8C7C3F8A9AA5326
+:10543000C220C1C158733F0A7BCEF9DB4C87A7DC81
+:105440001372603E8FA669B91EF45F5505F0533A9A
+:10545000B2E563D087BDEBFF8004FABFF692141A61
+:105460004CE7DFB1C78AEBBA0EBE2E38B3E750DF88
+:105470002A5A2EDDF54102AC1FC7727A9D515A138C
+:1054800000BE25AF527FBA10D9B9EF3DD87ECEE825
+:10549000756C18BBDE2E5E7F3973A00FBFA3008E24
+:1054A0008EF86513EC8120C07770953C13E846EDCB
+:1054B000A6F0CB24D093657B642DB6A8BBBF36D5B0
+:1054C00063E5FE3AA3E3432E364E4FF25DDA194F01
+:1054D000823AF92E555405E02FED4CC0E7674E6D2A
+:1054E000DB3895F27D20CD8AEB436A855AD05F94F4
+:1054F000085FF0D13A9D4F0B9FCFE13DB7DD7E03B2
+:10550000FDE79B607FE83713DBFC294CD8E9EA6EA6
+:1055100074C4FF2A7319FD44B31F29EC5945F3865F
+:10552000FA0104F01EBCED06E0C3530A013EECE6AE
+:1055300067DB6FEEC19FDC807CF4DA9E5FE13AAA04
+:10554000C8A362BD76CF8572E0E31A129A01FDD638
+:10555000EC915D21FAF561B2A700EC8AB0FB022F55
+:10556000A14B87EC5EB00BB1B26B35CCD37E8743D9
+:10557000A578BAE15C610ADA3FBBB502F462696CF6
+:10558000B6638E8E9F0FA6C815C0078753328DCF86
+:10559000ED1B0BC0FEEDB3307DD472F26E471B7E67
+:1055A000775B0AFA71C2EE9BFC561127ABCC96834F
+:1055B000D1FC61226FD9144BDF4FCAB51219FCF729
+:1055C000B645E80F74B3FB97FCB83E30DB7F8177BC
+:1055D0008A6994976E7E6B04CF06FFF5690F8F97EB
+:1055E000A96428F8A3A14B1B17039CE79AE35DABC2
+:1055F000311EC1FC9D73ED8B364E81E7EFC8185FFD
+:1056000039774946793AF8C6E2C16D3A39A61604A7
+:10561000E97471F8D7675FA7F4B9F8799C3780FC13
+:10562000B7B320DA7A59ACA3E8C8FD2D69087F7FAB
+:10563000CB5814375CB7DE1459B7FEDA83EBD6705B
+:10564000399893B42DC76CC01767A80B0FF00628C4
+:10565000F1B753BCDEA4B5C92E1D3CFF97CB7791A3
+:1056600047DB057A25404A0750A7852C88D34A6E28
+:10567000007F741A716DA3F3D97FAA54B2D2FAB81D
+:10568000ED6EAF44EBBBC12105BE7D550E6EA77814
+:10569000D84DF5F16EDAEFC2D6469B9B8E1BD843F0
+:1056A000811A43EB9490808753D64046928E4F16D2
+:1056B00065B2714F59FDBF847E4E7D1243607D7887
+:1056C000EAF3B8A876B83893E9CDD7B99D7364AA40
+:1056D000D83ED4F1DA9BFD295CA14ED770C0FBA265
+:1056E00097BE9667D3716EE4FEDAE44DADF510D740
+:1056F00099BA25AC80FEF1055D656082A7BFE4B56F
+:10570000825DBA7D87CF0AEEF98C3D7556783F737E
+:105710006FE361A8DF1DDA89755BA6FF23C0EB4D3F
+:105720006BC387805DB21A89027241BE617E589850
+:10573000CB9DA7D37B3011B9BAC4027CDE35FE8A7B
+:1057400056055CA2A9F56C7CDA5F1BF657179E0024
+:10575000F62D6339EB2F831C5895A846FA1D7FA9B7
+:1057600055D2C71B4A7FB804F9E8F947970C4E0693
+:10577000BCFF358664BBB96CA4C0F38141587F126D
+:10578000A52D7FBADE3F23A118C637C4CE4AC14F2C
+:105790009A9DF1912B0EFC85479EA98B03FD90E20B
+:1057A000536D7E1D9D4A374E1EF216F0696C0CC675
+:1057B000ED2E0E677EFDC50D8E6080C5BB8700DFB8
+:1057C0000A7B5505F436C4A384BC33BEA75D04012F
+:1057D0000E511269B58BE8EB24940670757A187D2A
+:1057E0009B6CEA2C18AF292EC605E355D9B36DA0E2
+:1057F0009FBAE29F1044A47AE206EE6FEE3F753046
+:1058000019E87A71F8AA0C5817842CFF8EFAA83779
+:10581000BE5AE2D1923211CE4006ACABC4F7FB4E79
+:10582000C615823D7C5DF861DED98361BEA25D5103
+:1058300026F30BA83CE0FC851CA4B4126D6B21A2DE
+:105840004ADBADC3477E268BE38972B7550D3039ED
+:10585000A27E08C8953364CF0479DD9789F5141FBB
+:105860007178E9FBDABDD95E594539CFCF4C8DC887
+:10587000FF8D5CFE535AC32877D7BA3E706532BE9F
+:105880000D293BB9FC10D443203F4C4F870630FE16
+:10589000080C00BA805EE0F449976859CDE92CE61F
+:1058A0009DC2E57E2A976BC003BCAFE4F314EF6F93
+:1058B000E6F82A930B13DBA2C47DBAF86E793A019D
+:1058C0007FB16CF9002C2B39BC0BED1B309EBA302C
+:1058D0006503C65153B4462C174E6CC4E7695B662A
+:1058E000237F2CDC2C19E2A2A27C81FB5F674E593E
+:1058F000D07E114B5C7FE03FF1FED7E067B0B8F09F
+:105900001D80E7D37B363E53A446E2C2A79B983D59
+:105910005C1067F4EFEEE6F3DAFFCDC164E0978B3D
+:10592000B18D53EF0639D92EBB56011D9BCA2435C4
+:105930000AFFE9F10C78AD6DFA4739CCA386B4358E
+:10594000809E3ECDFD32B559427DAAEEA5653F2A27
+:105950002C4D4CBF9EB232FD7E4A4A96403E40BF1F
+:10596000839E3DF5F9BA8C47818F2427FA37A037FB
+:1059700077E9F863F18EAD0DFDE93F6FBAE41A0ED9
+:105980007C15528843AF9F059F087D6B867B05A7DA
+:10599000ABE0C31B22766805E00DE2A740B29A0D8A
+:1059A000E7317EBA81D3AF09F80DE479ADE0B7E114
+:1059B00016D4A726391EF32FD2DFFB9EFA4506C662
+:1059C00025C652B9A5727D1AE43A0A5FFC9CD36FD2
+:1059D00089C7BF29338ABE3F2DF97F999C1969BFBA
+:1059E000EFE42D43AA74FD3CC8F171D1EA1FEC8AA3
+:1059F00082AF085E497FA0F3024A19C003D922B9D9
+:105A0000C0EF13EF53B6B07D8097B91C89E7A22E83
+:105A1000F03D1EF09D89F87E3993D97D1B98E4B442
+:105A200020B3FBC4724B7FB0E30BE3B45B300EB327
+:105A3000C14220AE44A452E4F794A6A74F5E1E09CB
+:105A400065AC07F755A85F0DFBA50B9F50711DB8FE
+:105A5000FA8558E4B350A607E7B5BAC98AFC76DAE6
+:105A6000DA98817CF9F9A2C1B02F13F884D9A19EEC
+:105A7000F029F8E727DC5E0BBEF3AC677CD7A4689F
+:105A800071C077C28E0AFE3CBDFDE6629037D13E02
+:105A9000C237AEE1826F66D3E79EB56D32D087D252
+:105AA000ED8F8087CCF561D45F3DD14DECB709FA1D
+:105AB00009BD9E906531E0FB330E7F0AF75FBAD3D4
+:105AC0007195811E3746F8FF5333FF5BD5883CFD47
+:105AD000A11739B83ECBC5E20C9FCD4903FD22F694
+:105AE0006BC43EAA18FF2CE7879EF65B0EABFE3315
+:105AF00099BAF9C07EA08A7A9DEDAF94717F7BD967
+:105B0000F698600CA5DF3E7805FAA23D2E087EA22D
+:105B10006897AB104D2926E4BF33DD385E2EA80A06
+:105B20005A4F596E235974DC8BD71D6849A0DF4F3B
+:105B300009B74D1E46A7B6CFD676FBAD10F725DACE
+:105B400022F02730560F7CDEC1FA25AE9D0638AD17
+:105B50005916C33EA898774F76AB277A5C9FC5F756
+:105B6000C7F87BB39C1FE3F83AC4CBDEE53490085A
+:105B7000727A1309AC82FD117289B8C01E77C9E927
+:105B80002582F6657096514E453D8A9C0ECED2CB4D
+:105B900069671B93532E8F894D562D9A7F32348B14
+:105BA000AD7B139BCA4AC09E24FA08C63FE8345115
+:105BB000AE1752B906790D807CF6037C32FEF2688E
+:105BC0008DF7C17B4F13F3AB2F26B1F92EBC513BA0
+:105BD00020839C53BF5EA29F3672B9EE19EFA14499
+:105BE00089D9A744D027378D6B9B00F656857D81D8
+:105BF0007E303F46DFF1E3483044E9AE5E224C4F51
+:105C00007CFE8BFB1E05FDB0C1E1CD5623F627ECD3
+:105C1000F197001E7A9267CA971AC4A396FD9783DC
+:105C2000AD037BD81F1FBF5C46FEA37C7E4B960E48
+:105C3000FFE37D6119F09A1CEF4FB32611724FD329
+:105C4000D0E9F641747E6EEADFD2FA4C5A5F0F71EA
+:105C5000B73E6D84D79F72A47FFF38DD3D5985EF35
+:105C6000D753B80399DA5D59A9B86F7D0FC073D3C4
+:105C700080B00CFEE7B5EEEFD7427C8ECEE7F81D84
+:105C8000435E984D9F56DDE56B80B7228E3C86C7FC
+:105C9000916B9B87637C59174F5E94759578726FF3
+:105CA000E32670B9A7FC8DEBB884B16119F4A2D0DA
+:105CB0002BCBB3FA707E6E23B0AE10F2057A09FCDE
+:105CC0005A916700714527EE5704F17BA8271647C4
+:105CD000F4CDFA464B4534FE7E3CCB11558F92E60F
+:105CE000FFFE8F4747D3F9C22BA6571FCFD2E9D566
+:105CF000A6C6E37D999F4AAD3CF51B1EE46BF98D6A
+:105D0000ABBD7FCE02BE7B57C678CA7531B6800464
+:105D1000EB7E8DA8AEBEBC3F10BB6629E42CA2F57D
+:105D20006F25A2419CF25B19CB8D3FF655B8216ED1
+:105D3000F2B1C5BB9A60BE02E267EC6012B4D37FD9
+:105D4000EEE5F1CF92130E0DF200CE4976D49FE727
+:105D50008EC505C07E9E735A306EDEB23F06E5E208
+:105D600042561C8F67040D710FB19F73E19D39C9B5
+:105D7000A0F79FE1FB9BCFC4B2B8EA3377E5603C64
+:105D800052C46D1585E2BE0F84A9285EFB807F3C5E
+:105D900000E3A9228EDBD73E5B6249456C1CC5CE71
+:105DA000E6D757F14B101FDFDA4B3EC4EB59361ED6
+:105DB00007F0EF01FEAD5DD1668375ABF07B855DCD
+:105DC0001EDCE139007911832B58986C6B87C50272
+:105DD000F3DC4AD929C9DD9DBF041F6DED9E7770A4
+:105DE000204B17A79DF618CB3BE8AAF376BFE479C2
+:105DF00007E3DB8FBF02FE1C95F75D867665A97110
+:105E0000FE287A6BC6F21F62FB9EF87F8685F8A398
+:105E1000D99113427F2B7503C04E91BF3F12AF46FD
+:105E200089CBCCF8AC2A15F0628EA745C6FF318E1F
+:105E3000FF59168F1F65900CD85FEB6D3FD30CF7A1
+:105E40004756FFA068764AD0D93C5EF7F66C1DD65F
+:105E5000F59D8DF8773958BFC5BA7E53B299BF33D7
+:105E60004362FBF5E432417B2DF884E2FD3F812F54
+:105E700046FFE9C48838DCE709CBA00F2E7C9C35AF
+:105E800010F7DB7B58770A7808F16747CBEBA0E384
+:105E9000F9A2D121299BD1618695ED4748776563A9
+:105EA0001C60466C8C14A3F34F2E77D95BCDB02FBA
+:105EB0007B3076CC488C5F5AD581D1F067DEAFBDA0
+:105EC0009C45905F012FDE28FC24F695059E1B4A19
+:105ED000B41285C5C7C83630811AD3A3291504F773
+:105EE000D7C6481AE223339BF94D5B79BEDC857730
+:105EF00064D40BA34BD4206C91527BE1CE1E85F968
+:105F000057AF5874F957824F1A7E43EDB2217EC8BD
+:105F1000E44AAC9F93B83EA65EA3B64BF79DBA0287
+:105F20007440C41E0CACB71BEA190FB988A2B31792
+:105F3000495A9AA13ED0E78A8375D3C00AD5D04E7C
+:105F4000F09DC8FFC3BF1498B70BE34F7D383C6387
+:105F5000243FF20DE837880F97707AD2F98EC7F98F
+:105F600056B45DD0F38D986F6FF33ABE92C243156D
+:105F700058FB4A0A2FD50B73D6BB57A521DE5D040B
+:105F8000D6132757DAF1F93CDE3E69D3EC86743A32
+:105F90004452BD8A71D924ADEECD74C8B7ACA37597
+:105FA000FA37B7519260BD4EF50CB67B6EA50B4B20
+:105FB000416F177D2F817D2F2579B04FD3931DF32E
+:105FC000673B0CEBE1ABD8317FF6A8EE76CC62F7FD
+:105FD000BE05FBFF4B9B6515F862CDE43E1AF0D37E
+:105FE000C69D9217E26E879A591EDEC619CC9E880E
+:105FF00071CFBE9A8876E3ACC4E49CB424A11CD4CF
+:106000002671DAD427E17EEC39BEAE5E91E5AFCBE6
+:10601000D6E9CF8DCDA362715FD66497E89F4BA27E
+:10602000ED700F4E02FF69F85A2513F5C072809F7C
+:10603000CC6F1B119B097CEBFF609C047AE09B0CEE
+:10604000A0A7795F4FECFF897DC13FA6F95765EBAB
+:10605000F456F7FD3EE33E959C60C73CDEB132CB83
+:10606000E3D5D95F02745D037E22E5BB35C7E2103C
+:106070003F6B2E33F9A370FE04C669718E467E1203
+:106080007696C259F42EE90E67AD258CF1421D9C1F
+:10609000CF5C1D4E539E2B87AB0BFF7C7F4A762A2D
+:1060A00008FF3912E70538F7DABC1FFBC10E9F8DD8
+:1060B000C3F89EA04F0D97B173941E1285F3DCDEDA
+:1060C00011B11607F847FE17805EF2A07002F8E7DC
+:1060D000879A47E4C37C7ADAA73D9255FA7236CAAA
+:1060E00099FF37D06EBCABEDC26FD5C8FCAFB2BF65
+:1060F000BB0BDA7D07FCBCA6E7A3DEF053AB38D6BA
+:106100004A2C408E7E98C4F5B499EFA4E603FF05AF
+:10611000794754DE30EF339041826B28DE1A8632A5
+:10612000FE2373898A76D9C4272BB27C6F03FC4285
+:106130004EAF829F7701EEDA2C5F2B7C0F700C281C
+:1061400046BDF47E36B36FAFD82CD89EE5AF241190
+:10615000CCC731EF9F9FCEAAFA04DB0BFF2BCF2FCA
+:10616000B90ABF931C1CBF3A7F85902F96723C2DB5
+:10617000857D5DC857DB63ED30E44598F0F0789697
+:10618000AF83E181F2D948C6676BC855F11186EF3C
+:106190006BB3FC17002F4E2BE51740CAD8D9698086
+:1061A000E7C3AAF635ECFBEF5EC5F071EE4F0C1FAE
+:1061B000FBDA2DC8D74F93212897C596F3F741FFF7
+:1061C00054BF5C867EC685774AB06EEEB740B58018
+:1061D0005E1E10F6CA96ABF3AD9483EB27BF022583
+:1061E000A5C383408711EFB078CE55F8D60EDF7F78
+:1061F00007BC27E57C07FD43F92A15FA177C75AD26
+:10620000F956942FC8803EDDFBA3EB28DC5F38B045
+:106210002F06F555CD6E09F579CD1B5FE07ABDE609
+:10622000B51864CA89AFC5E2FBF37BD8FBB325D1AF
+:10623000F3013272FAA0DD59BAF3019FD14E07F093
+:10624000F9CFB4F3AE2C39B2BF9A3C859D435813B5
+:106250002BF24DD93E6B02E7B3E4413E0DEC507298
+:1062600019C17CC10407CB43EC7EDE80C96D2A6F67
+:10627000E772A912E0D97CFE408E63F985A964FD1E
+:10628000D780A7E40AE3FB544705EEBBA69ACE29C4
+:10629000087C97E570FFD946D2408FEC34E55588ED
+:1062A000F2FD1CEE07D627E17A50E170B5386DC8D3
+:1062B000B7CB9C769CF7B224923C19EB0ADA7F7339
+:1062C0003F5DFEA76621AAFE1C45451C5175FE5187
+:1062D000AAAF8FA1DE6F667FC3F7E97E8FE1FD80F5
+:1062E00005430CEF07D5151BEA83975F6FF8DE4D6A
+:1062F00011A0AF67AEBDC5F07D76E374433D77F383
+:10630000DD86EFF3835586F7052F2D32BC1FBA7358
+:1063100099A13E6CEFA386EFE51EFCF26773589CD3
+:106320004D167EB973A41FF84A76DAA518DDFA6F08
+:1063300019A7474942451AEC5BD63BCBD3607DDABF
+:106340009244EDF155E26EDF77DDD628E8CFFDAF60
+:10635000521E773B7B906A11CA7F3587281F0C43FA
+:10636000FFAB3187FB5FB355F83E6C437BA278717E
+:106370001E3312EC184F33F7BF2C478DBADE922D27
+:106380005ED764A9677C09BEEC0D5F9B395EFFB7E1
+:10639000F8FAC8943724D67BE6767FCEB1707FDCDE
+:1063A000BF3B47BFAE2361D987EBBA6FCE0608E883
+:1063B00051827E4D6DBC0BE312663F408CFFC734AB
+:1063C000DFEBD08F599FFA96CF67DF59E80243EE93
+:1063D00079BDF7E71CF37AAF6C26D223C966C0D328
+:1063E000FE2E3A6B86F55E7DD2685CEFD55BB5B468
+:1063F0006B59EFEDCF2188EFCD40D7541D3D6D5E39
+:10640000D5857ADEE8BF74F7CFA9FDA3F3DC087E5B
+:106410009D047E5932F3D7774B386F31EEF7F0CFCA
+:10642000DBF5F6A927FF3C8678D72A32D2EF4BB0AE
+:106430004FD41F7F3056FE5EFEF885EF620FDFB748
+:106440007A318FFDFD29325945F178A1624C3F1216
+:10645000451F8BF2288FDFECCE2548B7DEE21FEF19
+:10646000AF5C70D5F31CEF57B23CCDE9C047BA71B1
+:10647000D373195F8CC8E5FB92312C8E71E63F9C7B
+:1064800078EEE0CC2D1F261027E4B78D1819803C3C
+:1064900066E27D08F26F020E27C609A7578E1AB969
+:1064A000CAA9E3ABB10CCF137EFFA70488FF4CDF72
+:1064B00095991A70F4CC4F23F8FC88D2968379D939
+:1064C000AF9FEEABD272FABEEC5416A734E6AD998C
+:1064D000E346D397D718E47869A74482C9BABAD2F9
+:1064E0008AF9814B3B157C7E39C71857EA115FD773
+:1064F000884FF37381CFF72B4F67403CFD6C6C7472
+:10650000FFE37E8EEF2EFE319D83E9E97C4739EF74
+:10651000FF42C575FD40CF4DB7A9D9D712E7127814
+:106520006ABDF4453CE88937E07C4D94FEC7E7B28C
+:106530007DA537B4CFE1F80329B1872700DF97F0B5
+:10654000787A94BCFFDB7261BDD459F12FC9FB9FEF
+:1065500095CBE9C3F3EAF372D5A879FFBD9D5F9AA5
+:10656000668B6EEFC646F0F721C8EB83CF595D000E
+:106570005735F84E10BFDB6AC5F8DD07976208ECA7
+:10658000A77CB1C5FA2BC8575BF05CE6739B687DAE
+:1065900041650CEEFF546FB5B2FDB9CAD82084AA8C
+:1065A000166C7DB8EF1C3ADE57546E9764D3F7CF64
+:1065B0003D8DF9331FB4AFC3FCEDD320CFF4F98286
+:1065C000CB8FCF00FCEFB335160CA7E5921D92E1FF
+:1065D0001CC6A2A658435DE4030AFA1129723E4381
+:1065E000A5F6A421D7781E6B4464DFAC2197D96B44
+:1065F000CCB3AF99C2CE631D3AC9D6FB87B358BEA0
+:1066000060A8F2CEC9C3E93C2A53AD182F31E71771
+:1066100012824427F379FE6FE5270A9EBBAD1CEA80
+:10662000443FF0CD95754807DACE51A63B8F50F91F
+:10663000731677A974B3BCF91EF30E4DF986E27C8C
+:1066400050B73CC3C8F9A0E3D1F8E657B946B93E04
+:106650007492E515CE7F4766F3EA456F1EE5F3F8C1
+:10666000A07DC8BDBFA5F8F8A08269F10F2EDDFCA2
+:1066700018C4BDBEF04904F23CBFB814FD5CDA3F5B
+:10668000BAECABBFEBDC0ED0E7B68A855D7510CBFC
+:106690003B7C0F18CEF55CBBBEB9BA3EA9CE65E710
+:1066A00032CDFADDCCF7FFBFF4FBF4CAC3190127E2
+:1066B000962F40D9B18BE947B39C9BF5B980CB0CA1
+:1066C000EFD24ED990873C16F4C028BD3EB7E17B8F
+:1066D000EAEEE37C02A395E01A09FD80CF81EF4743
+:1066E0003A82C92574887AD7B6F8ABC56FE8FAF94B
+:1066F000347C5FE3F6774099FCC7FEA560EF47BCAA
+:10670000B313F308CFF5904FFEA1DB94BF2619F722
+:106710000BBECD2DF910D6FFEB54560AF91C498556
+:1067200090E73B7C9BCBF6E57E0AFB96356F5D449C
+:10673000F97CDAE64F83F840A0BFCDBB3D4A7E88A6
+:1067400092F7DDCE25EC80F83CD03D2FCFB0DF07AF
+:106750007122CC5B381E8771A2E7D3B4B83CFADD56
+:106760002B695A7C1EE8F334CD91A7B34FF57C9E7C
+:106770008A25BA5F5C9627F8DF87767C5E29D5BFCD
+:1067800051F8D09BC7F2F94B9EB92B03E2719F1FC2
+:10679000BB3B03F463CBD363AE9AD7F633904FAAD7
+:1067A0003F9F04BD9F1DD94FFD09971B11EF9E67A9
+:1067B000F3E5E8F3B192F392D87EED75BB5B3D94BF
+:1067C0004FDAD7CBA8BFDB1D2C8FED8443A9682AF5
+:1067D00064ED520CEDD8F90519F89ECAB1E250BE2D
+:1067E000D5EBA332E0E9D49EE759C6E964235E3BCA
+:1067F000B4B71DBFC50E76549634178BFF337EB8E1
+:106800008E8E00FCF038D76397D3FCE301EF366E31
+:106810006FAFE3F6567198ECEBC0ABEF8FEF4DD353
+:1068200026423F77A7696540D7BDB64001C8CDDE97
+:10683000B8E8796993F2983F129BC7F98538D07F01
+:10684000C5F164DCA79F9AC7F6E97D50DE3420BC11
+:1068500006F2C93F74BBBAF6B97D789EDE7707BCF5
+:1068600027696DE456C893A3C0C23987D74F1D2747
+:10687000A0BF12C2ED04F269124CF9AEA2FC2A8F3D
+:10688000F91FAFF17DCFEE72C7F8CCCFE16CA2F269
+:1068900002E74185BCC0FE3AE44BAC53FD5CEE58C8
+:1068A000BE47D3537D24D867F168AA05F803F24C9C
+:1068B000413F99F3839AF3981E053994AE22870FCE
+:1068C0007F47396C7A6AB22516E07C94605E075582
+:1068D0007EABEDB4FEFC329717CE8765AE27B80EBF
+:1068E0001AB43C6E1BAC93025C9E066F22AB63E94C
+:1068F000D76E9EC727F2A2DDF56D0A9E177894E544
+:10690000E99DFEFC16D909FD7F2DFA37E6058A3C84
+:10691000BE468E5F318F251EFF93C01FE6BCEA9EE8
+:10692000F3BFBECC873C87E784BCF33C9C713C0F33
+:10693000675CD3D3188F1BD774B322D14F9E5742B5
+:1069400012ACF79EAFD314B037BFCB637939BDE536
+:10695000C1BDCCF9B191D3B9A77CCA17F87751F270
+:10696000295FC84BD5E593FD80E5533E9EA7E2F72E
+:10697000CFF33C9AE7EB58BC6ED14BEF49FABC39E8
+:10698000F19DC8BB1BF810CBBB7B5E698B05FEB9C4
+:1069900018CBE875F10771C15518946F1B1EFD1CCB
+:1069A00082398F9CE58F0F0E874B301F8810BC07F4
+:1069B0006148BE6AA0CBD6B02B0EE4A5377BF0268B
+:1069C000A7E7B5F2E18BF90C9F51ECE63B80AFEF06
+:1069D00060375BF398DDFC20EFFBD84D6E2F85FD13
+:1069E00014EF8F717A56E751BBA9F36B7576F358A4
+:1069F0005E14BB99428298A7413A2C5E7D5EA8281E
+:106A0000FDBCDFB73DDA17D07E1C8FA724741C278E
+:106A1000924E0F4DE7722DEE9778B10FB97F5A94D1
+:106A2000794CE1FD596685F13E8A8466296A1EDA51
+:106A3000876EA64FA85EFC4F94B3C1546F4ADDF534
+:106A400066147AFC13BE1FF08E760898E4FAA4A6AA
+:106A500078709FAE420F4B7E2AD04393A114F82F3B
+:106A6000BE625C470AFCC7E533F9ED9BADC5E6D3D2
+:106A7000F22F5CCE7AA24B7A3EF36386F052E4A901
+:106A8000EF36F9A313F2195E6ECE37C61575F44BC7
+:106A9000CF8F423FA187DFF6F806023CAF9DDA1D9B
+:106AA0000F7C24E824F48F995E11395B25F6C9B375
+:106AB000F3A3D81FD1DE6C8722ED0308F756E0A3BD
+:106AC000912CDF07CF11F0F308023EC1E71A9FE7D0
+:106AD0005F3DDA7080D70CA7ABC3225D0DCEA470EA
+:106AE0008A04F29FA4B9B07CFD944502B85C6105AC
+:106AF000F3DD5DDC3E9AED2055171CAFAC9F17B956
+:106B0000DE6838C3F2101B4AFC6910FFCFC9D626D5
+:106B1000025CD5795A1994D7656BE5507EE8667E9C
+:106B20004B7ABE560175912F6086D397DF957770AB
+:106B30002BE033612209803D84FB64609F2581E75F
+:106B4000312468AE52B063095B08E60924C7870F99
+:106B5000C4C0FEDFD3C40BE79F7202AA05D65F99BB
+:106B60000F69ABA16C38C3EFC52921787EB22B8F9A
+:106B7000AEDE837974206F7A7EADE278AECA677A32
+:106B80008EFA21F7E733B866E7EBFC1021473DF9B1
+:106B9000153A395C80EDAE5D0E6BF3BF9B1C3EC8B1
+:106BA000E5F0A16B91C31F46E4F051F8BE37395CA4
+:106BB000C7E5EFC55EE4F0FFF07E7F97DFA31E5DC3
+:106BC000174D0E459EB0E0779043B0F741DE1FD5DC
+:106BD0009F3FCB4FFD5E72B9399A5C9AE5B1ABBF6E
+:106BE0006BE4FF9EFCBF0143FC7CDED1FDBF1D3C7E
+:106BF0005F5CC833959797B9BCFC9ACBCB0E80F7F6
+:106C000043B78AE398E5ABCBDE84999E80FC3C7D5C
+:106C10009ED6E108BE5E857ECC7939E34CF1FCCF8F
+:106C2000F2193FBCC3CB84F071027A81E2ED8D7C16
+:106C30009DDD7891CB4B602CCB3BA5925A0A7EE52B
+:106C4000BE0EEA470238F90CDE719B5B0F81DF480C
+:106C500094C678B8E7AA273C7986A8625F202A9E66
+:106C6000E8F87F86F1CD746B06BA39BAFBF3667A21
+:106C70003573B90D737C7C5F3804FE008E61088724
+:106C80006A59A7B3F39F733D41E16D0778C74F0C75
+:106C9000CB04E10AC5C3FE89D0A764206D3FB27B57
+:106CA000FB8E48FB0EA0D7788DB62F8CB44F825048
+:106CB0007E26E831AACFD04FD6F0BC62839BF18309
+:106CC00099EF9B6CEC7C4417BD1AFB23BDE6AAFE32
+:106CD0006FA1FF26859D1B695AEB92D8794096EFEC
+:106CE0007B225343BE8DA287C890EFA68794214C88
+:106CF0000F59875C831E720CE9D243F1F07D38F79F
+:106D0000EA7A6800FF7EE090ABEBA10CFE9D67483D
+:106D10008FFEC0009897590FAD53191EA2C8E960A5
+:106D200080EFDB5C4D8592CAA97B486AC4AED17600
+:106D300099509FCBDBAF6F64F9160112E78DB6CE89
+:106D4000F00E715C6BFE9997C3F99DF2A837FEB8FF
+:106D5000CD06F816794E625C73FEB4A0634DF3AABB
+:106D6000116428E4695DCA00BFF2DCB16F313E7284
+:106D700024AB4A83F15BF68F31E46589F197F178B2
+:106D80005A995CB813E2B3E78FD830EE2913F5D9DE
+:106D900071149EDA235612443DC5EE1B10FB61D6DA
+:106DA000230DAD108FB712DDBD50B89E5113816F0A
+:106DB000AD47D8FD4C2485BD0F10FB2A76BFA371CB
+:106DC0009F3F4933EEF32757F431EDFB1BF7F9FBF7
+:106DD000CD34EEF3A7FB8DFBFC0316149BF6FD8D63
+:106DE000FBFC8397979AF6FD8DFBFC996BA79BF6AE
+:106DF000FD8DFBFCB99B8DFBFCF941E33E7FF55B10
+:106E0000AFD8605D5DF0D232D3FEBF71BF9F22A4C8
+:106E1000354B775FCCB0BDAB0DDFCF6D63F7900D19
+:106E20000FAD33B66B64F71504E87F80CF2F88DF92
+:106E3000067CA690F09B0320BF25287943F4B385F8
+:106E40007B778D86B298C7C5AB371BEF395818349E
+:106E5000D6BF7ABBE208E481D58210D17E6A5F9208
+:106E6000824177CF745FFC92B1BD88F32EE6F3398F
+:106E7000CF9D82F35B643CB76CE693EAB76E63F731
+:106E80008605B456B8F741E041F08B8BF38B804B0D
+:106E9000E063B1BC04E55CE041DC9F55639A7FB7D9
+:106EA000F9EEDD8AEDCCF336CF63FB90AEFBB0702C
+:106EB0003F8074931307CB13A2F3827D72399067DE
+:106EC0009213231E7AC2DFB5CA8DCAF1109366945D
+:106ED0009B5835CECC77486F333EE3F38CF264C6D3
+:106EE000A7D3DB3F2A7F89FB4F713EB01FB25722E9
+:106EF000BF90BAE37541F386860151F8897A7E988E
+:106F0000E761C6EF7B26FC1E56FD47413F5DF8F862
+:106F10001B19E9EA6F1B01F6EC2AF9671FF3EFAFC3
+:106F200075BFFD187C2FDA9BF7DBCF419EA4EEBC2A
+:106F30008AD44537CD942779E8BF601F89B6F1DB45
+:106F4000200E5BE1B5B3FBC0CCF96BFE736047026A
+:106F5000A51AC138E079E25D43FB5BE3FC8F825EFA
+:106F6000E2221786A0BFEBC7FB85C687DB2EFC1687
+:106F7000BA575A5D304EB47B484DE70F2FC3B8DF88
+:106F8000F79E47E1B7D3759252C0FC6E5B817E9D40
+:106F9000D475BF2A5BEFF4D48FC823EBA9940ECA33
+:106FA0006857C3529C37DA3D65E905467BAF3BE73E
+:106FB000995EA0B3A3350F5F7813F41EC5F7407830
+:106FC000EE7452FF46BA26FF4685EF9F8D4F40BEB6
+:106FD0000EBF250773DD707F959AD8A7B0FB7D4B58
+:106FE00022AFB00EEE534A86E7F98957CBBF28355A
+:106FF000DD7365BE97A8A198C155CCE7E9E7F75DB9
+:1070000095F3BA389726E271B53359BCF969531C28
+:10701000B3BCC0C9DA679596039D1ADC12FA4F0D0E
+:107020009264D84FBA38A4A41CE6ABF1FECB21364B
+:107030009F8AE7EB10AE14D33ADE52C0BEB7149469
+:1070400062092B7AA0B74D96A3E2735201835FF8D1
+:1070500051DFE39E99A33123BBDF3363BE1FB13CF5
+:10706000AFAE05D48379DFF7D5DEEE99395A1E75B8
+:10707000FF17F01BDF27C2F7730B8CF72086E2FCAB
+:107080001BA7403CE24FB217CE9B98E7FD4001F3AF
+:10709000FBD7F3750BEC2BC17AA40F2FBB7FCFF07E
+:1070A00014CCF23D807855285E29BC211BBB0F34DF
+:1070B000FC21C171FA2FD00E407D944FC5F3150D00
+:1070C0006EE280FB82C2C32D181749F1BB26C2BDF8
+:1070D000BE295BA43E804EA117AC0A093829BF34F3
+:1070E00016B891CEEBC99A0370BF49E296AF8907F3
+:1070F000D713AE892ED0477349D438E7937C3ED35B
+:107100009EF328B02E4BB447BFCFE1493E0FAA1FD4
+:10711000D6C13CC6DB8F8D903C11FD024B5BFCBFA2
+:10712000768BE15CB3284F644E68047E1DB580F415
+:1071300010F7647C7A83EA7B06FA1F7554C5FD8AD2
+:107140006AA1A7E75A08DC3B7A17679FBBB6B0FC79
+:107150007572E9CA1559F8DD04FB27B07F50BDC42C
+:107160001984FD84EA6637DEC7471648B8CF51DB7D
+:10717000FC9E0FEAD52347BA50BFC54B12DCCB08A3
+:10718000269FE933859C14FC22F349D1FE6772FBEC
+:1071900020D6F7D41EAC8FA778AFDEB2F5009C8F57
+:1071A000F87FD4F003DD3E96FD1FFF90F67B073598
+:1071B00052CB8BA154C82C8CABA7613FB7F37E0296
+:1071C000DF12E9A43D32EE1DCD6FE17C3EB6928028
+:1071D0009D3293B5940D6D7D3411F75B457ECE0CD9
+:1071E0007B6319D8B973B670119C9F3AB7FF2F8390
+:1071F000601FFEB31F5D70C2BEFCDF95B0139E9F83
+:107200005AF18113EEC5FB6C05BB3FEA3E6E3F04AD
+:10721000BEFFC4F5825AE86B01BADCBFF2F268FD2A
+:107220003D3864792AEAFD854119533A845C2D7E04
+:10723000291E3C9BAEFAD29DC986BAB0074B634863
+:107240005DB438A1A590F1D1C21D5B6D035418DF68
+:10725000FF118C7F0A1289295D4EED71A2DF28E0B3
+:10726000A9DA31DC067EC6DF9B634808D62F4AAB1D
+:10727000959DBFD4264B941FFC9CEE6638DF7C2383
+:107280001EFB9BF734D33FB3E958CB295EFDCDEC11
+:107290007E4BF33CE67DA696F7A3F89EF704B5E88F
+:1072A0002AFB7E05A59B7FF9E3984F6D9EE7EC8056
+:1072B000F93E4B0DF55F35A7EF9CB5C6F7D5CD4F21
+:1072C000623F7389BA1EF206E7359ADF577E017E68
+:1072D0004CB5293FBB53E8A7D1640CE8A783F6CC93
+:1072E000C468E73045D9B1D285CCF9E54A3B96A7C9
+:1072F00056122C5B0A18DF2E697EEF11E09F9ABDB3
+:10730000BBF0FEA143C15129D7D34F263557E27EAA
+:10731000E124BE8F7C6FF7FB34E30A69FB890ED34F
+:10732000F9673EEF599C0EE23CF42C986F113C57E4
+:10733000BED1CFE7FC914C07FA43853CFF660C9D1C
+:10734000977CEDF312F311F313EF97CA94DFA2B415
+:10735000177CDE52C0E216739BA635F4A7A858B37B
+:10736000FF0B5C2F13D37D7A13EC4FB6F27C33C343
+:107370007D79F4EF28C8AFE0B76AE2C5FB43CD7C66
+:1073800025E84C1CD600BFEF18FDF82E7E6AFE09DA
+:10739000E245D01B6EC6D3DFC744F9CAE037533E7F
+:1073A00032D4E7351AEB67AD6D1920EFD5A6DF476C
+:1073B000386BCA2F11A5A7D083F23757D5CAE11C65
+:1073C000CD3CE26B6079B8EC1CDE29A5F1CD1F82C3
+:1073D0001C363139F83BA7FFB6425F6521DA2FAD85
+:1073E00008EF415C9D2EC345BFB3D74B2E90AF39FC
+:1073F000F5C3F13E9D62A2617FF7F6E0872D296417
+:1074000074A8AAB3121B359E55740CD073557B64B7
+:1074100071CF95634A5FB8B785D163E913BB6CE957
+:10742000B45C5057CDFC8320931B718FB4E03FA117
+:10743000FF17AD3F80EB70BAFE30C8572D9C8B28EC
+:107440000239363DAFBB19E9506BF213AA057F7ABA
+:107450008917F8D3FF88D30EE7AA7A9B37E91E5F16
+:10746000C1F8CBF923D9E83F9E57D57EF09D3F81E7
+:10747000DD5B2F29FE31F09CE20BED5478553CDEAC
+:10748000E37BAC53262ADE37E21F03E7DFDBFE3A5D
+:1074900008F76305BF8AF9D6DAD723BFD612E3BA55
+:1074A00072365DC040DC74F6F664CCDBA2FD17EDED
+:1074B000057F63BB15FD8900599606F74CF81E63DE
+:1074C000F7D056ED4DC2756D553DDB6FA9DA91844D
+:1074D000E766E9BA12EFF716F438563FC1968EF414
+:1074E00072E33D5964AF91CF059DBAAF0B4D745A0D
+:1074F0007BE0CD34B5FB3A5147A7F61EE864B89F50
+:10750000714B21D78F9C4E6405D73F0F1CCE867DD3
+:10751000A6F375B15E39CA7AA3EBFEDEB9D7637EF6
+:107520009988C755F417BF27E0ED0B74BDB07E14E2
+:10753000D2CD4CAF8A7FCE41BA90BF3A09C469EF31
+:10754000CD24F74FA7CFEF9798BCDCBBA6B202ECD7
+:10755000F9AB85CCBFFA33D55B5A2E5D0753BDA579
+:1075600051BDF501D56750FF70651AD6FFB252C5FF
+:10757000F293957958B673BF5FC81165041BF8592B
+:10758000AF73F979BD50AC971E4A03D7A2E29F1F93
+:107590008CB240E83370DF8CB24184DCAA19EDE193
+:1075A000CCDB8DF6AECDEA2A87F3BC8127D87D6887
+:1075B00055BE1B0CDF1345B5C13DB8246F44E439FB
+:1075C000CA9B6A83F3E8774D4E367C3F63ED0043F8
+:1075D000FD834295F995159986E777CF2A30D467D0
+:1075E000F3FB5C893A16E5E6219E374AC8584617F0
+:1075F0009E8FF24DDD987EFF46E1FDE61D2BBE37E6
+:10760000D343D075EE6699F8697F733653FD4541D3
+:107610006C6FA474A2EDBEFAD809674748C38E11F7
+:10762000EF8EA5F5633B58FEEAB1FAE49F82FF7442
+:107630006C476A02C451FD0D32F7335C78CF99E88C
+:107640007742FD2ACC53991D8CC17308B35B02CFDE
+:107650008B3AFCC400BA78203747E5604842FAB15B
+:1076600038C0CB3118C73F45FD3A571FB83F8CD4BF
+:10767000430907A712E9FB7FB4A60641AE2BFE29FA
+:107680006B69C04F2FC7F27D1A09FBFBF2BDEC6D91
+:10769000EB90BFD49D2194DF185C2FCC6963F3235A
+:1076A00052F100A0FFA924A2255120962EFBCBDF8A
+:1076B000144AA78539AD45704FCC2C7728F54EDAA2
+:1076C000AEA3C9CAEEA5A7FDBA687DE9AF63B6321D
+:1076D0007DA2F5837B2222F80C16C1BCF3FBFB6272
+:1076E0008652FA7D393F58847A6D452ACA9519EF3A
+:1076F000ED363FE23700722045F46444CED8FE1BDD
+:10770000556EE9A06FE658BD7DC15EB5AFB7B27BDF
+:10771000E1142D611A9E33DD8D7CDCAEA8E530EFDF
+:10772000F6B56EBC4F478C5BB55ED6D87DB8942F4E
+:10773000E1FB0DB21FEEBF11762BB056F2C33D39FF
+:1077400066BE79F0813198F76EF67F457996CAAAC0
+:107750005FE7472CDA2FE3EF5890916DCAED86FB77
+:107760001DD9EF7D10FF58433EEA12CF1FFEE6B051
+:10777000A05F9308EB8ED34765E4B3D39EC6D1696F
+:1077800099905E7270F4BFD1FA57530227E15CED15
+:107790008383FD2301AF8B2DEB3360FD74AEF9C401
+:1077A0004FE1FED82F7F63F5C2B08B5E5E3818E3E1
+:1077B000F4DCFFEEAEB7C4FDA45A3ADC17B458DDD2
+:1077C00089765CDD211136FF20C229ECBA6B9384E7
+:1077D000F7049D18E55C07EBE539A6735D27F8BD56
+:1077E00015E543993E11F6FE315E9F63617C4DDEE7
+:1077F00090D8BD52FCF71E843D10FA5AE8FD19439B
+:107800003D2C9EC1F535213B516FCD87DB94E83C83
+:1078100097BC14C3E2CB2A5DE08FC67B4BF16FE3CC
+:1078200050A62F16D97EF30CC852356945F8BFB45F
+:1078300006E7B7BAA1FDD6FA3ED8DEEAC5782BB77F
+:107840002F70AD3DE8A56A2E7F4B1B25BC1F8970AC
+:107850003B398FF74F5EB246EC86278A7D31D9954A
+:1078600079DCAECE23A6786DA3D1DEF9E2D9E2773A
+:10787000111D17EC67042EEA3F53DCCDF707DF9CA0
+:107880008A704BDE601438AA493804F7442DDDC1F4
+:10789000E2D766B8CCF3B85638E77BA74D4C1AA9A7
+:1078A0001BD704B7C037067C757410789F1F60F82B
+:1078B0009CDFCCF6033EE7FE1AFDC338B399FED534
+:1078C000C43715F2F3AA3751FDE98EF083E08385C2
+:1078D000BB82B85FF115694C70503958B279D78CBA
+:1078E000EB54583FBF87EB90597D42D99624BA2E6E
+:1078F00008BCFD4CC5A0DEE3F5FF2A3C117E6F36C7
+:10790000B6A37899D7C4EEC5D67DC7F3D00388AFA8
+:107910000581800DE2990B787CB037386B1576EED7
+:10792000BD7778191EFFD57087861AFDD8887F9499
+:107930001D75BDD5E517F5628F3FB58606813D0EF5
+:107940000F52D01E7DA378FF529202F6391BD70D3D
+:107950003DE9DBF9DC2ECF033B4DCB939B5FC17B35
+:107960008F3EDFF40AEE8FDA7E332F01FCE5939B26
+:10797000E7FC14CE059CDC3107ED72F52F845DF633
+:10798000DBF4F67EC2E6D9BFFC11F0E94BB118D7A3
+:107990009FDFE2E7FE38D57FA0173733FD4736314A
+:1079A000FD580DF6AB10ED572E7CF7C87C7F2EF0FE
+:1079B000BBEE39DAB547E6F8C7607BE20AF1FB7B3C
+:1079C0004360BF847D1576F7DD74FFD9A16017E4AD
+:1079D000773EFC019DFF99DD32C67496CA5B33E0A9
+:1079E000F7507AD2E3DF1FDF962E7CBBAF01DF5565
+:1079F000806FF48718BE8FAF65783EB19EE1BD61A0
+:107A0000476602AC838FAFCD443FE8F88E6CC4F775
+:107A1000DC7514DFE807AB463F682DC537F8FF80FB
+:107A20006F3A6E558BCAF1ED65F85ECBEDD07A56A4
+:107A3000CEED86D7C07DA0571EF9558C17EFA18ECD
+:107A40000DA5C23AE5D42E9940DE42979FC4FD1998
+:107A500081E77F90C6E7C1AFEAE6DF6C882110DFDF
+:107A60005CF8AA13CF0D7D2995F403027434FE212E
+:107A700001C68B8CDFE5D7788A46E9FC9A6BA44F68
+:107A80000DF1615E7F4DF31F3E06BF1EAE1D827578
+:107A90007F8DB82F62AFF1BE0849059D86E747ED9F
+:107AA00076E08381E6FB34FCF8FB3017B3BFBE6F92
+:107AB00019CA733847BFBF521B17B2423C2ABC4B8E
+:107AC000427A2F7DA824A184C0BE541DC231BE8835
+:107AD000AD2B244DC338630CE59B38B8AF0C2ED1C9
+:107AE00085E7AA8BC51DB7D0719D1178CDCFA78230
+:107AF0002202FBEE881EB7AD2B627EC052D982EB0C
+:107B0000902536B61E11F921B7F2F7B716B175C92F
+:107B10001D452CFFE21C2413D17ECF6D88E7F9CEE2
+:107B20001331FE29EE0B5004DE5CCA59C3EF27F077
+:107B3000F8C2DFA00D85736E0C8FFFC24FB6D0F672
+:107B4000F7F0F6F734FE09F7E5E84AE639B0BFF793
+:107B50002E8FF1E2FD8C701F1CE5BBC7E3D83E0AF7
+:107B600049495440AEEEE67AF69EC6277D608FEE18
+:107B70006D8CD7A0A4E304088FB78E847DD8FE3621
+:107B80008CB7CEB2B7FD06DCEBFBD34E3C6CA753F3
+:107B90005B6561FECBAA3E04F36B8651371EE2B7EC
+:107BA000F4D59E2BC957E31F633C7909C475AF27F1
+:107BB0008CB1C6225E0D758A5FAC3714DD70E7A606
+:107BC0007184BC4FD4A140EF25801BE087D9891870
+:107BD0001FB815E2CB7DA05490CFA62B246061E5A1
+:107BE0005A07DE87C1E2CD53F9BCEF184B428974C6
+:107BF000BEA1B78821DE7D67C812CAA574B8550931
+:107C00001D00BEB6D8552BAC0F7C155231AC9B97DE
+:107C1000ACBE36787F5E547EE7A681B46E61FBFF12
+:107C2000E11F48787FC93D54C8813FEF53488B5CC2
+:107C3000CCE807FC57DB87DDC71D7E80F1B788B332
+:107C40000B3A0DA7DDEBF17B0F878FF6B33601DA28
+:107C5000DBA2C797B673B9107EE7622EAF8B05BF64
+:107C6000ED30CAE961212FE0E752BCDDC3CB9EF8BD
+:107C7000FD20E7F7839CDF77168975F8B58DB7345B
+:107C80008684F4BFD724C6BD9597A122E63F0B3862
+:107C9000043F131E9FB250CD017CD4DEB806FDA672
+:107CA00005A67831D1C7B1E468F52EFD63B902A508
+:107CB0002D3C17E0916E8AF5025FDF63DB99CDEE14
+:107CC0005F317E27F6716791562BBF8F8CC5B9B88F
+:107CD000BD2A931D784E7F96C4EE5F3A57E20C584A
+:107CE000A8BFF829BFFFE47C1D3BFF3AEB07EC7C03
+:107CF000E7BD898F4C05FF7056824D81F253FE3BE4
+:107D00004FF79356A7DB1DF14F1A4A647E1FE8BF59
+:107D1000DD09FB196B40AFB0FAB3DA388C2AF1FAFF
+:107D20008ABFC0FBDB2F513EC0FA8FEED4E8B8E724
+:107D30000EF3F7015A87FD92C7043FAFC6FECE3D52
+:107D40002DDE37B0FA13E2FD93ACFE13D13FAF6FD7
+:107D500030BD5F657AFF7356BF50F4E49D70CE71FD
+:107D600016DFC79975BD847AA518F88DD277D6EA43
+:107D700010E27996E5202B4B4908CE5DF4F6DDE064
+:107D800061BEE2A254B8D7A2DD09F63B77B886F50A
+:107D90008143FDFF04BBB6689A14B081BE3C1ACC87
+:107DA000E1FA3D6ABE7631E7DF415ED69FC037ED2E
+:107DB000276658EA77EF6707C035CAD08FEBFBF428
+:107DC000B3BC3B3CE9DFA79FCF4CFD08FFE8E16275
+:107DD0006D24F44726DE6088FB2DFEB13711FC2BA5
+:107DE000F22EFB7DA5C5AB77668CA0FD2FFEEDBE08
+:107DF0008CF9BAF5784DA74C34AA8F6A3B252CBF75
+:107E00003AF0890DEE1FA8D973C0565E08BF0B73F8
+:107E1000C0364107D71291874ADA94E93AFB7EDDF2
+:107E2000300BD71BECF76516FFF634EE772EB6EC69
+:107E30003CF90B88035DCFE272E6F9B979BBBFC1AB
+:107E4000FE7314FF7DFC30A68FE68FD46E1A06FBFE
+:107E50007B80335A4E58137D1F7F2DEF6F561CD3F6
+:107E60007373463BEDD066D451FF1A381F367F8BB3
+:107E7000BB18E2BCE38796560CBB6ABC34CCE2A5C7
+:107E8000CD2C5E3AAB4FEB4354899335BF7BF95908
+:107E9000FB8D844C7A9674DDF30B71483C2E8D7209
+:107EA00077E0CE890331FE85F5F9C35E7F3640DB8E
+:107EB0001FE1F7FEDF3B66681CE8873677BCC545E7
+:107EC000E5B9BC70F61A80E3DE313796C3F3921839
+:107ED00067CE6C167747BE282FF4DD07F386EF21B7
+:107EE000DEE1B7B1F897FF6D19E35FFEA2787FB4CA
+:107EF000FDED591C0F6B8631FFE58885C2591C8149
+:107F0000438C4F1D96875A697FEDABD387C339BC2D
+:107F10006D8525AB112F7CFC6D85FE5AA88BF1E990
+:107F2000748BE0F9B5C2B184C3B11ADAD27E7CE3B6
+:107F300028BFE9D68DD327C61BEAB74F4E269A3EF7
+:107F40000E7BFB00437DE6AC4CC3F777CF2D30BCF6
+:107F50009F12D33AB2EE3BF8C1B54E671CF8639F4F
+:107F600035FFE3A37BC0BF6B92F1776A16EEDFFEAD
+:107F700011FC6ED3793AE1640C86AA180FFBF20863
+:107F8000FB1D4EEAD729FA7D9D33A4F519D807D5F4
+:107F9000ED1744DD4F15FB058B5D2D98C7F7BFDD51
+:107FA000D7D9368CAF878B21B519ECD2871887AB20
+:107FB00071B0799DD9770C7FD702F20AAE503EBFDF
+:107FC000191AC2BD7A9DABF0F7C226F0DF139E00EE
+:107FD00097B0C3BA60E0030A9C6BAFA525D897722F
+:107FE000AAA712299FB41E2043F7405EAFDB897910
+:107FF000174B3B6FC338F791B840E103F4BBC56B37
+:108000002BB15ED3198FFDFE596E2DC7FCEDDF4BF2
+:10801000B89F3065C0BDAB017EF8FE413ADE94DF0B
+:10802000DD5C0178AAD9C3F233A6C8EF8F847E96AF
+:10803000345662FB29323922517F21B1F31EEC778D
+:108040000AD87A5A97473BD781FD956DA19C7F0747
+:10805000BD6273A25EA9ED8CC5769326303BFD36DA
+:10806000D71BD636065759E7347C2FE8DF3ACC6366
+:1080700038776F4D6D52E03E4F6B9B84DFDFD259F6
+:1080800080A598E7DB79BFC2DFA1B2A67E530EF9C7
+:10809000996FA7482E743F4C7AF742DD98441245F9
+:1080A0002F758DD3C9F29D633A59FE73EB70ED24A1
+:1080B000C8D7D4156D0AECEF1087DD05F89A3A762B
+:1080C000B83A5F274FF2C1BB6C4017EBA6F76C6064
+:1080D0009763683941F77EA9C8EF37E9E58E6116E5
+:1080E000EE3FAEC2F90A3B438EEC457EBC4F9C8FFF
+:1080F000E5F2F209FFBE0B4FC0EB40C75763703D7E
+:10810000757AB8FF0AC0DB5AC27EAF8628AD19B0B7
+:10811000AFF2AF829FD2D92EA1BFDFC67EFF77AC70
+:108120006A81FD02C52BEC0B935B318FFF017C0252
+:1081300054430080000000001F8B08000000000076
+:10814000000BC57D0B7854D5B5F03E73CEBC92992B
+:10815000C9E43D210F4E208420012643124208C964
+:10816000242408486080AA840699208F8804424409
+:108170001BAFF6CF842410042D8AB7372AD2019181
+:10818000A2D53620B6698B382168E3B5D7467BDBAC
+:10819000E2ADB5F151048B3580D72FB62A77ADB556
+:1081A000CFC9CC9924886DEFFDA37C27EBEC7DF63D
+:1081B00063ADB5D76BAFBDC37ABB184B60EC163B54
+:1081C000E33F8DF18C253176719A8E31F8F5572287
+:1081D0006BECCC866749499F3B8EB1EE7BA64F176F
+:1081E00065C6AEE04F0954711AA81EB30F7CCE725B
+:1081F00019DB7C3252BE4F60AC3216DE013CF0829D
+:10820000D17F309DDE33210E9FC68302946FB60D61
+:10821000647A2C8CCD79D11C6053A1DD17CD1283EB
+:108220007E3A72BDF1CE787C3FB15CB031E63E6102
+:108230009418D41B3BCD9DE0CC83364719AF3A9EB2
+:10824000F027633E3EBEF2593A96CFD81D26FED99E
+:10825000DC25822F2A8A316FFB7CC660AC3583CB4C
+:10826000189BCED8EAC14882BD7BF8FBCBF5897359
+:10827000198CFBF2BD306898C7EA7B8529C7615E1F
+:108280004CB63A27001E2A93576E6330CE4A5147A8
+:10829000F3AD9C1CED6F81AA1B07A3E9FB4A91F586
+:1082A0000A318CD50DA653FB9B0663E9FDE64133ED
+:1082B0003D570F4EA6F7C64191B9015E33283037BE
+:1082C000C037CCB1FA7430BE492E6F05E2A3B2E5D7
+:1082D000FA79D88F775B52AE17F0B1E8DE7EC90429
+:1082E000E3621683FD49E86F51418E639D2538EFA7
+:1082F00096EE2A1822B41BE731B8E1FD1A78CE09B0
+:10830000295F0BA8EDB42026EC731360DC8B5AD3E5
+:1083100075F7B160F90227CC07F1CD9AE9B948ADFC
+:108320003F0AFE6728F5575B021374D09EBEDEEC51
+:10833000DC06E3BA1427CF45BC34ECE4F86BD07B01
+:10834000E65861DC0D8F084EA00CBB35DF6A623049
+:10835000CFFC33F5066F76B0FFAAC1A94C063C2CC2
+:108360001BCCA067C914EF72C443CDE04D0A9DA693
+:10837000D293C9053A1CCF56A4AB8C032AE074569D
+:10838000C6F749FD8CC46F41FF9FFC524FE5796EE3
+:10839000DF2D381EBDDFE83C00E33967F68A48DF91
+:1083A00073A9CCBE1786784ECF7C76A0D7AD1D22A0
+:1083B000F341FB6BE0E985E7B968E68E76213E6123
+:1083C0009E59BCED2BF0EFBFA53D696C3CD0B7E1E9
+:1083D000776F4BE318BB2DB36F6A00DAAD2E0DC477
+:1083E000DF0CED5E38A477FAA0DF8DDD6FE4EBA043
+:1083F000FCC37477221381AE63BC0DC8CF1B96FA01
+:108400007FA807F8F6FB9FB3CD9483F8EC94021392
+:1084100024F8BE13F0E8837175EE16E7F9895E2C37
+:1084200072C994205FAB7C1CCEDF1B06C7137E2E67
+:10843000D71BA71C47FE057EC5F7750A9FDF8E7CFC
+:108440000F4F7DFF7C852F39DFABFC5C274165F842
+:10845000AECE12E5F7C17C2A7F04FC0728DF747CCE
+:1084600089A714F92E4B704E80C746659D548A0724
+:108470001F2844FEFF38CED902EF7FD2E400640506
+:10848000F9BF627009D58B1AFC26F5A7F2BF51E13E
+:10849000773DF27F08DFC3778CC177F7E5789F449B
+:1084A0003C95FDE06FCFFD17BC5A2005321F8BC3F2
+:1084B000A795F827B80E4CF627D3691DC8EB42F8EC
+:1084C000483C556590015FFA87DFA1756084E79CA1
+:1084D00090F24DC8D7D988997E69A935F8FE6927E9
+:1084E000977FD7CAFF1D0AFFCF33B2551E6C4FEAE4
+:1084F0004B0B6DEF7C4ED90B388F534E81B7F74F36
+:108500001A37E0C984F885F1BB915E8B0A64DD7D82
+:10851000E9D88FBA7E399F7CD5F87FE4BC3679FFE5
+:108520001B45DE87CB7706EDA17CFFF885497E945D
+:10853000FF6F33D00700FB4E44CA4F2AF29FF4432B
+:108540004494FF6AF27F5DEEADBF413C8D20FF7F1A
+:10855000FB8FC87F95AFD4F5A2AE0F753D84AF1FDA
+:10856000753DDCB0CB19F52DA41320E6495C3F9294
+:10857000EF199C479D1C9983EB525D479B8E0BB472
+:10858000CE86E90565DD04D789564F8CB64EEA9450
+:1085900075B1565917EA7AE8113BF716C277753963
+:1085A0005E634EC8BAD8782C5C2F8CCA570CF96A17
+:1085B0006D5C3D43BEAA8367285F1947590F969C9F
+:1085C000AFA70FFE7A8DFC3436C740EDFD2FF2D3F6
+:1085D000D89C91ED0919DFFFB3EC89CBF5BFCB95A2
+:1085E000613C977341CEA607F9ED865719B717C6B8
+:1085F0005B9DC83FBD117C9EBD86547F0BD6BBC220
+:10860000EA118FAAFE5F8B748F0DF269B5CB5B8E7A
+:108610007456E9DF1BE1CBDE927DED7436C6F519A9
+:10862000DCD948EF3E8DFEAF1B85CEF373BE9EDCDA
+:108630009B91736D745E91F34FB713D78E4457E6D9
+:10864000E6F640902EC66564BF0540A109A3D35548
+:10865000DFC1F1AEC26D0149D5B7B1A86F815FD658
+:10866000E5FC03F2A7720EFC3A06C11797BB8B809C
+:10867000EEDF5160D6B31CD7E14D056A79A0C32D5A
+:10868000A1DC81DF0BA9073733117E39ECEB3E53B8
+:108690000EF56FD83B54EEC3F28AA228A53DE6162C
+:1086A00058B07EDBD1936776D33CF6F0F5EBED97CF
+:1086B0003C5342E05C80AD21704118BC8FD7B74974
+:1086C000FDCC4EEDF8F97A85F60517E71F4F883D8A
+:1086D00002949C1B8DF6E471C17E1FD07F45D1C7EB
+:1086E00006A45770FEAF2C77A780BC3C2128F07FF2
+:1086F0009CC1F9AE38CEE11F1C7DBDC32729ED0119
+:108700009E372A68D6770A6E11DADD5820F8C7A599
+:108710000FC7F30F86F8561D07A860EDF7CC10F7CA
+:10872000F5BEC7F54DDF8FA3EF03C6AFD1FFCD4533
+:10873000CCEDB70CAFF773558E7E0EB0DA3EE0721B
+:1087400019CCCF9F3DBC7E8F52BF4FA753F075B65B
+:1087500003F9A7CFA0E2F34F0457300EFFC7D13F74
+:108760002DF771BE65EEB0F95F6DFC3FCAD1DA0B33
+:10877000F8236BBF0F5C0D7FCF0FC39FC23FB55A6D
+:108780007E8A923CA72F433B5171821DEDE24D1E24
+:10879000F36EB4FF83FC3140FCD1676643FCACE56B
+:1087A000FF8BCBCBB3C9FE51EA5FEE40F9E6D10DAA
+:1087B000D5E7EB41E52FF83E0BF8094D64FCFE834D
+:1087C000A3973A7CD9441F2A2758BACA7AE80C835F
+:1087D0008BC2D68FC2FFB47E51CE037E268C20671B
+:1087E0000C2E8EDF8F04B61CE5645F19B713FBC631
+:1087F000F167A64B20BCD95C1C8F09CAB32F220499
+:108800000F29413AC34F00FD909079139EAAE2D4FC
+:1088100079C7562DCC80EF6378B9EC8A7AC4971269
+:1088200084C3DB1BE78AAD42BC04DB8F7E13E552B9
+:108830009582B74C57CC9B0A5F09B82EEB884180D4
+:108840002F8E0B3E11FD04E48B11E6FD97E17CE5D4
+:108850000BFBDEADBFCAF79F0C5F97EEB0EF993E02
+:10886000F7EB7CAFD06D61185DE785D1B53C0CAE00
+:108870005661BF46FEA9727175D7836D09308FDBD3
+:108880008F08A86642F839BD0AD7E7ED76957FC70D
+:10889000BD89FC1AE4E7F184E7A59DAA3CCC78C425
+:1088A0000D745B82F2B030082F437941F0842AF7CF
+:1088B000B4507D91F908CACF9BDBD5FA13A9FE8A83
+:1088C00056B5BD2C82553A32DFA42AECBF2A57D1C7
+:1088D00017BEEBDEC4F20D27F8F755C726BFE9CB6C
+:1088E000B8CA7AD81386977D61B02FACFEC35FA15A
+:1088F0005F5AC3BEBF37AC7C7718DC1106B76BBFBD
+:10890000AF5923D03AAC017E40427CD5BABC4D5918
+:108910009743F480190816B2DB34EBEA86160EDFB3
+:1089200071ACA0AADD1202BB0A69DDA8EB42CFF848
+:108930008F318ED1BAD08F222F6B5CA3F06556B8E1
+:10894000BEE5E57FC45F93D00E661ABBA047D4C2D4
+:10895000DDA23AEE796F6ECDC6972A7C7D15FA07B7
+:1089600037FC9B765EE0AF2A704555794A885DE218
+:108970002BAF7287CC53AD3FF78B2B22F6B7D35575
+:108980005E7508DAAF2E0B4CA8877AD531FC097AD0
+:108990004D44BDB95989C7CC7D41F4A05EAB8E086A
+:1089A0004C68C80E9927EBCCC47976DF23127D7C06
+:1089B0002D401F8CAF317030C135EB8E8A6A3C0C74
+:1089C000F57BEE111B518FBEDD189B80E33FEBE280
+:1089D000FE424FD4D884B5007747AE32C850AF7B43
+:1089E00047053D4F89EEED03B0D6BE7F6C599565C6
+:1089F000129647117E9E702DAE6A06BE3EEC92E93D
+:108A00007B6F8C3DA10BEDE7FBF4EC4919C7E3DC70
+:108A10004F7C73BF3107FDE79AE6C909684FAEFE88
+:108A2000D7257393A0DEEA36BD53A07A6C2A8EDB7D
+:108A30007B5F8501CBD7B42A4FDFF5F47CF1CB27E0
+:108A40005A6C507FE071C17910EACFFEA4F3D5A92A
+:108A500000AF6F1FEF44D29C1CD4313BF4F36EC7C0
+:108A600044BF08FCF89EB9FEE545BC3EC3FAEB3FA7
+:108A7000975F5B948BF545FB36A87F16DEA33D7CA4
+:108A800076A77850C071D9AC11024CE9EC17F26BA3
+:108A900068D742B97D1BBC3FDB765B02DA596705BC
+:108AA000D926C0FC7B8ED55439805FD67718157ACD
+:108AB000D624D5C0FC6B7443FC42FA635D34877BDB
+:108AC0005C35554F227E1F9968433CCF9AEE3EEDB0
+:108AD000023C9972DD2FE1F33D33D7532F7E29AE4F
+:108AE000427BFCE717562760BCEE57CAFA3939B803
+:108AF0003A617588BDB3EE2389E8FEA241DE8AE3C0
+:108B00007C312255407F19E81EBB04D6EF1AC5FF01
+:108B100000FE6D7C6E04BBE76997487CDFBD2BBE11
+:108B200048D6F0713DC94FF21B00EE3FB6F1111F60
+:108B3000C8D7F78D8DEC3D5C7CF742C14C78F69838
+:108B4000297EA57FC6EC37A763FCD33D17F9993979
+:108B50003A33975A43D69D52FF0F3E2BD5FF03D48D
+:108B600047FFED0FBEDF5B9965B81DBFDE66F5A15F
+:108B700031F181D52A211DDE969ACEDE0DDFAD7B47
+:108B80005C4F727FDDE3F1F70EA0BC017EC1F858A7
+:108B9000F8BCA64CD713BE465D87BE6F6BD721FBD2
+:108BA00036C9EBD1D6E15F8FDD5B75C832FA3A5C2E
+:108BB000AFF829731FD77B701DADCFB34A0CF447B4
+:108BC000D9E32F3D89FCBE7E8BD9658481AF7FDCE4
+:108BD00048F4EAB75A7D7628F7DAAC52343C4DD3E4
+:108BE000397DAF9BCED7CD1C914926173D5B314EC9
+:108BF0007A09C6130BF0F9C6BDDF9D01FD7CC8FCE8
+:108C000037CD00FC5D4282015E2E1D17297EC824EF
+:108C1000B75409F2B19671B950F7CA738652F8B5D4
+:108C2000B67EFD42F4EB6EF3EBDFED577CB62BCA5C
+:108C300034519E6EE6AF40AF6ACB37B3DD17C5A99E
+:108C4000C4C6065C8F759D61E5F5D77F80F197CD31
+:108C50004C7AB75F8DD7C238E4E9D6B8B39100B883
+:108C6000980B30C42ED5EB33194C71BD05D615CCFD
+:108C700077CE3E81C6BDBE51F41BA1FE9C581EF7A7
+:108C80007DBF09E83F91E6EDB303BCFE61AE67D658
+:108C900033C16F825FAFDFB745C2F5D081F205E324
+:108CA000D402F3207FBF6776A6A1BFBEEE7133E189
+:108CB00077FDFEDB7EFB087CD7DF5C1917EA1FE738
+:108CC0002B7C01ED33534CB09D0F9ABF9D86FC3F2A
+:108CD000E77BE0E7C27CD747B31F56A523BD92D2FE
+:108CE000644BB0DEFA6DF764F27AE027C3BC6B76B2
+:108CF0008A340FF6BC91F41EAC7507C965059F6BED
+:108D00005A5F3118B2514EEFEE13A1FEBB008B1625
+:108D1000C2974FC1A301F1B50ABF4DE2DF38F2158A
+:108D2000BB5B2639E2C5F955EB84554B49AE0F18AC
+:108D3000685D4FE7F1CDAAE9DC9EAD4973DE427173
+:108D4000E4078C4E9453F823AAE300BFAA4ED7B78A
+:108D50000EE3B9ECC7468A8F6C6E35BBCD36F23B5D
+:108D6000DCC7707C12930C808F8D3297176B143E8A
+:108D7000DC2C2FB91EF906CACF48B8BF62E572B124
+:108D80002E1AF0CEED54B70EFAF9187F1BCFDB4D3B
+:108D90009A1AD2BFA0BC8776645BB0DD5E1D6BC73C
+:108DA000380BD69F3415F1187BD3721CDFB322AD7C
+:108DB0006798FC030568E73D2B4E47FFB66667CF13
+:108DC000DC0E848FE6D8B1C99A1FFE9AF4C6ED0A6C
+:108DD000FDFBD1DE473D02F051787E7B3AD7FB5E4A
+:108DE00091C77DBEADE049E503B5BC6EA79EC7DF68
+:108DF000DB8C64C7D435FF8EDAADB3F625A0FCADAD
+:108E00007B5E9F8F72DAA78C7B75736AD119E0AB9A
+:108E1000D5FA28BB00AF36FA2A0D086FDC23101CE8
+:108E2000FC2E3E0DF9F4CFAD3FB121FFBC670E4CD7
+:108E3000407D34B0C5EC3C881350E26E7F6E9D706F
+:108E400010E3336BEC7D5601CAD76C1D1F83F2FB18
+:108E50006D7BC080E56F77A6EB1076DBED4508BB38
+:108E6000A56904FF1944198F2B31F29F37099CCE55
+:108E70001B9FE9318C83FE9E54E6FBD1B3BFCE44E9
+:108E80007D5597D697897A05F8203319F1FCB440BF
+:108E9000FA78D333A2DB3C35C8079B900F60DD6DB9
+:108EA00050F860D3F19F7C0BD7C326A4BF6B381F4B
+:108EB000019F9EA6F7C70ECC65FCFBD3C827AA1E50
+:108EC00003B8558FF1348302433F081F9ECED7135A
+:108ED0009497F3725F36C953D66F40BB737397DEB6
+:108EE000D71FB2FF331A9D7B143AAE6E3692DCED7B
+:108EF00051E6DDBFF3791BD2F1A3677B5EC6FD921D
+:108F0000BA63A0ADE511D6858297CD88071BCD83C6
+:108F1000EC8BCD386F5B100F43FCAFACC7CD8CCF63
+:108F2000539DF76649C1835AAE7C7F5AE19B8D4CB5
+:108F3000C1DBF1897CFD29EB0DD733CA55757EDE87
+:108F400018FEBDCAA7E715BDF08632CF8DC017CE7B
+:108F50006CE21FB741951350F4D1D10314FF51E9CE
+:108F6000A58EFB6F417DE28E8E09D2B15FC76A3B51
+:108F700047889BBCABE0EF9DB6C4B42EC0DB9FC15D
+:108F8000CF427B0AF9550AE94FE51BB5BF393F5877
+:108F9000B200E70BED07B07DB5DFB77D9112B6F3F8
+:108FA00036E3EB03F913E5A7BA2EE7B4AC5C9063A4
+:108FB000C37A1F59C767E37CB95CFBDB743B3DDDBB
+:108FC000682FC0F7EE2E81E2CFEF287EFD3B6D3F8C
+:108FD000B1AD0EC1D367CAB8553EC31F8C4BA9E3D0
+:108FE000ED8DE1F1DCF071AB72481DF79C1D372F60
+:108FF000C0F7EAF8557E55F953C5A3CAA7ECDE7849
+:10900000B26BC2F995784DD5ABA246DE937EBC3EDD
+:10901000E5A2C16B19FE3E1C56EDA1F7304E83F25E
+:10902000E329D14FF2A3D5713A2344CFC38F2554FE
+:10903000EF346FB9DE5E8AFBAFCF084E347942F46D
+:10904000CB6E2944BFA876C12DB9E3B8BC8F739FFE
+:10905000473A6E3CD737D72607EDD0D99F04C428AE
+:109060008C4B1D4F7785EAD38D174E13FFD7B1BEBA
+:10907000EDE847D5ECFC75E50CE4F3A7F4B43F53F9
+:10908000D3566140BBFEB6276FCD473E7AB77D3CD5
+:10909000C9F5F387F2A6135F317BC24DC0FF6B0E9B
+:1090A000EDBD6905BC5FD3253A49BE433BB86E6B45
+:1090B000EE9CCE906FDE33F75716A2FD7EB7684761
+:1090C000FB7DD69379F762FD59D6B1D1380FF7A160
+:1090D0005882DD5214E907D5EE7D5B91932D7ACE4F
+:1090E00017F372F97A2A197A727E9BD3D29289FB8E
+:1090F000E90307403EE3BEB241EE0C607F2F2492AD
+:109100007FB119DC2107D0FD9CC0EDB25A03332595
+:10911000B9E8BD2909DEBFA2EFBB13F5C82B775A0A
+:10912000739A7100E2E7F9ABB93DCDF70F6379FFB0
+:109130002ADED4715CAFF41FDE9EFA7D2FFA11286F
+:109140004F95F19F6F7DEA26D483E78F4C88C179D4
+:109150007FF082B91DEDA90FF45C2E0EF9DB7EFDC8
+:10916000FBA1761AD8751A18EC380D0CFCFBBED68C
+:109170002EDCC6ED8B5CAD1DA7F27BF5960951A1E7
+:109180007904E1F63BCB08DFB79911C5469037EA81
+:10919000F34213200A1835156D7AF8BE3CF28BE7BE
+:1091A000FAD0DEDF63B41B619EEF23FFE3BED4F38E
+:1091B000A21FF761D036C7F5F0FED11C3FFA91EB44
+:1091C000DEF2CEC5F64F3FB883F20CD6827D9928E9
+:1091D00084D8CD0F3F7813B2FF25A7777B127C7719
+:1091E000E908CF8B80624B98BDFC7292FC8FDBCB81
+:1091F000D76A27ABF186ED88E7C9F0BB933911CF69
+:109200002A7E55BFE945E083025748BCAFA996ECDA
+:10921000E40B4D5E7A7E2CBCF3C02CE45F6B94F3C0
+:10922000207CF6F3AEBD6232D2F978CEE7E8F716CD
+:109230005AA2ECB86EFFD2D4489B8F179AEAE9A9DC
+:10924000D2598DB7CD3EDE4DDFFDA56BFA8959F0C1
+:10925000DD494B1497FFC3F67B383DC3F340EED88E
+:10926000322311DFABF3FAF06E4E5775DC1F1EB9D7
+:10927000D586F3EA7E2CF6C44CA46764941DEDBD3C
+:10928000F54AFEC7D90E6E4F9F33451D5E88792380
+:10929000FB96253090B36BBBBF7113BE5FF7826046
+:1092A000473FC0F9C2121BFA6B7F92FA6D767CC2FF
+:1092B00077011C8FE417511E15CE63B41F5518900B
+:1092C000989C4E5BBDC42F332F487ECC1BF933EEE8
+:1092D00053613CE4F3088A873065FF69ED4F791CE0
+:1092E00065C8BF55FCBB59CABCDFCD8DE1FCADBC28
+:1092F0009F53C0DF7FB0EFB945D8DEF9437A3B8E8C
+:10930000FB2F87F4D4FE06F0CB7430DE7347B8BF72
+:10931000B3A153203FF9FC11D0D730AFBA2D7AB7A3
+:10932000216A381FCE81F27E4B900F37B8FDC4DF23
+:109330004CE14713FC7765DC707E8C669DDB111F6A
+:10934000FF285F9E095BF743FC381A1F28F8C27597
+:109350008CFCA8D27B4307DF578FE9CC2945BE524E
+:10936000E9AFCA095F19CB42BDDA6260599887E359
+:10937000D34538717D2FB1C87A01F0B02CAEBF1C37
+:10938000C569451E9793E21C9D5B87FAA5C5487287
+:10939000205C8E5CCCE5765223F234FCB3E6713B64
+:1093A00042CFEAC90F519FA07752517F2F898CF984
+:1093B0006F19AA7C79FCDB2B2418FF925931778E28
+:1093C000778253F67CCB0A09F877C9F498E7C7018E
+:1093D0006CCADBC6CBA7C5E4E9016E6E6E5D510EAB
+:1093E000F0843CF7E7B9F1C17ED476E1FD157CFF4E
+:1093F000CC64AF2E2F1EE5BA85E4F4C7C2C0D4C634
+:10940000F460FDD705F6F6CF8520DCAF676968DF2D
+:1094100059B1ADF8D19F8BF2DC917979C3DFAF669A
+:10942000AC8DF2E77CBF3823703FCC63027A2D56B7
+:10943000F86AB5C912207FBE5D7F6188DEC847CE5D
+:109440002809E9BA48E1A3C552A01BBF9FC45AED41
+:10945000674D6442EDBB123BBAFC8685C7CEAAEDD0
+:1094600001BF7CAC87F9025F0BC09E8DB0640440E5
+:109470007235C82FE1C42F3EC3765B7CACDF4C74E1
+:10948000A8B6A3DC13985777059E7591B6A918372F
+:10949000A98B4CF323DF373CFFD16964AFDB54FB6E
+:1094A000C55B40FCBED5CEE7C3BC85C48F772AFC24
+:1094B000F84113ABCF80A5B7B8AFCF26C3A02F2CF0
+:1094C0000A64E27ABF9CE6CD453A7CB0AF25A5019F
+:1094D000F8E7A36346E742A87FCEFF1CC5E1362A22
+:1094E000F6283B14AFAC7B315002F57AD3271D44EC
+:1094F000FD529CC7F5F585F440DA3D2837D2B9FF17
+:1095000003F528CF6DDEB6EBE3B1DE85A33B32D6A3
+:1095100002FD8C12F35963E8C96C30EFF9D0760183
+:10952000C07A8045DACFF5537B58CF86FA5EBED538
+:10953000C1E3EDCC837245A5974A8761F48121A0F0
+:10954000BDAA33313D8E7F12DB67C7F5AAD2E9038E
+:1095500013E011E36726C023ACEF0A0C3AE4223E85
+:1095600079BCA541E86F8D45F85981F2E686EBC1DB
+:10957000270D88F2DA7DB792FC51E58E0CFF8D2421
+:1095800077BE76DC68DF9C11E5CEFA3C45EEE4B0B0
+:109590009C2BDC4024FAAE57BEAD10AB6509C71D4D
+:1095A0006F72623CADE1F1F1A46F58F67FB2D07AF0
+:1095B0006C5F2CD7ABE922E1FDB62E81F21B2BBBF1
+:1095C00092990C450BBB62E9691B4CA2F7E70FBFF0
+:1095D0009ACBE512A74BE5F713CB28AFE8FB13E9CD
+:1095E000A98EA341E1BB0A31BB3380768405C60155
+:1095F00070C32B5C6F35DC28525C93A1884E4062AF
+:10960000F21F8FA59DE23F1E3664DF0B57284E2BBD
+:1096100047215D3CBD2243FE016FC3C7F16C6A4622
+:109620003C1B1D3A268F607F18153A99E50826875E
+:10963000F81D926FD2778A301EFB0DBDD30FE52D3A
+:1096400066DB415C4FCCE7EE437F61B9F25D9F99E9
+:10965000F34764568CE6FB1DB6B9BDC86FCBDD5C25
+:10966000EF589D6334FD1BC58D7A6432E6E5F6A2A2
+:10967000CA0FC497D0EF628F40FAF5C6E5501ED2EC
+:10968000AEBEE822C9717D91D6CE347AB4F5BEAFB4
+:10969000D27F129B144AFF20DE2D6EB4D32FB9ADBA
+:1096A000C4C7A0DDFFAD08E09B7AF50CE76B8CE04A
+:1096B000F3BA8498C2B8A85BF463BC6407E201DE25
+:1096C000471568F119EDD6E22F769E161FF11EEDB3
+:1096D000FC13978FD3942779AFD39427D7BA3470DC
+:1096E0006A7DA1A6FED8C6320D9CEE5BA0A93FBE46
+:1096F0007DA9069EB06785A6FEC48ED59AF249FE66
+:109700000D9AF2C9471A34F094CE7FD1D49FD6B5C2
+:109710004D539E13B84F533EBDF7210D9CD7F7A86C
+:10972000A6FE8C330735E533FB9FD694CF3A774CB2
+:1097300003CF1EF899A67EC9E0290D5CCA5ED5D478
+:109740009F63FAB506AEB0FF5E53FF7AC77B9AF20D
+:10975000F9F29F35E537645DD6F26B04977F95CEBD
+:10976000BF69BE1353BC9FA23E60E20509F9B6650E
+:10977000A5C062319EDEBBCC847260308C0F3FCEC0
+:10978000B52B7E0D4B43795621160570DD5EEA122E
+:1097900068FD87EB3BE9CF1E37C6F3D84F0427C6D9
+:1097A000D9A2406D4921FD47BB4DE04806E1D8797B
+:1097B000760D1CEF7168EA272E9735E549DE2C4DB2
+:1097C0007972AD5303A7D61768EA8F6D746BE07496
+:1097D000DF3C4DFDF1ED1E0D3C61CF724DFD891D4D
+:1097E0005E4DF9247FADA67CF2917A0D3CA5B35174
+:1097F000537F5A974F539E1368D7944FEFDDA38141
+:10980000F3FA3A34F5679CF16BCA67F61FD194CF2F
+:109810003AD7A981670F7469EA970C063470297BDF
+:1098200045537F8EE9750D5C617F5353FF7AC73BCB
+:109830009AF2F9F2794DB96ADFDC907551FB5EB1AD
+:10984000772A9D9F69BEF795B919F287EF98E06C6A
+:1098500091417EE5F3F80BC8F57EB388F69187E277
+:1098600046319820087C1905420CF90A5D856A8A00
+:109870003FC551DC9754938CF93E60270010A34BF1
+:109880004F477B3A3268B7A55C997EED76DB1A6864
+:1098900013F97C6FBEB72A3F0FFD95A373D16EBF3E
+:1098A0008DF9B6E33840EF45F5C3FA78CDAC8D6756
+:1098B000A8CFF926C04B487FAF98F7A4B8AEE2F71F
+:1098C000CF375DA0FA43ED2A710E01E6D710D2FE24
+:1098D00003E0574860D7ED698275030EE3434D7688
+:1098E000821F6E7210FCDD26999E1D4D59F47CB4CA
+:1098F000C949E5FB9A0A08DEDFE426D8DF348F9EEB
+:10990000079B3CF4FE50D372820F831F8DCF23E060
+:1099100057E3F369F08FB1FC19F09711FE61938F53
+:109920009E9D4DEDF4FE58D31E828F377510FCE3DB
+:10993000263F3DBB9A8ED0F3674D9D547EA2A98BE6
+:10994000E0934D0182034DBD049F6AEA23F874D36E
+:1099500019825F6EEAA7676FD3397AFE7BD30095D1
+:10996000FFB26990E0568CD7023E1ECCE77E908A0B
+:10997000171566AC9CF841B50F17A19D8FCC51A06F
+:10998000FF8BC6CE0FB3B7C3E9F1A11217D69781EB
+:10999000B988F1C33199075B42FCACC795FE7644A8
+:1099A000309F19F8BD59C7FDDAE6184679D64CB193
+:1099B0005FD72B7CC9E2B8DDBA4E19D77A653DE492
+:1099C000217F66117FFEF2EBF815AADF9832C5FB06
+:1099D0002CF167AACE47FEB3C59F89F673C9146FF1
+:1099E000677E3CEE37AE7D99FAB33B69DFB1D218A2
+:1099F00088BF19E323AF8814CF1BADBFCD4AFEF853
+:109A0000A8E527CFA7A0BD3DEF4BD18B787A4D6F4E
+:109A10005D8EF1829E7C1E7FEEC9D7699E2F4DF12F
+:109A20009EC2F17C6AADBF4507E3FFB478CBE13B52
+:109A3000D283FEF4627449C10F5AC2643DE52732F5
+:109A4000F74BE9D0D48D6060217C33F3D1736EB6CF
+:109A5000F7556CA70A0C7184BD85C6B491E6153E16
+:109A6000AEDF2AF4FA6DBE4EF3BC3CC5FB1B3E2EA6
+:109A7000378DEBB599D767E2BCD471E54E9595BCAF
+:109A8000E481FD38BE4F5FB87856181FC4BFEAB7EF
+:109A90006F2F55F24AB6083C2EA7DA6B4A5E8AEA67
+:109AA0007754DF29F8D15E5F09FE0EEE2FBDA5D8F1
+:109AB0009F6F99B97EBE54AFCF42BBBE5A8870E249
+:109AC0003EDCA5FA3F5950DD427D86FB242D98737C
+:109AD00000E52D770B94CF5D0DEDE8A09D6A0C0499
+:109AE000E277F70AC47F13A7A6D3B8ABC1FC233F24
+:109AF0002B6E200DF74B815F2EE37C37CC147D0657
+:109B0000B0875FD3F93305DA975E6B10609CEBE3A7
+:109B1000804FC68DCE0F9B94F307EA7BE0B32FB046
+:109B2000BDBFFC744616C5F14FCE94116F2D3A7E21
+:109B30001EC9F7EFA293E7BB70512DCE9A42714A2E
+:109B400026399D1867AA54CEAF748BACF1E8087221
+:109B500074EC0CCE4FAF39F4F3FCD4AE76BF267163
+:109B600006A763E20C4EDFCA53AFA4E2F9AB4DBDCA
+:109B70007AB247586E7FB6C73AC27C1A77DD951124
+:109B8000C2DF9BBBDEE1F91AAC3F3B343FBD40E98D
+:109B90005FE527D160F51EB0848E6F88BFD3662045
+:109BA0001F45037F8F27FE3E8BF6F622A31C7533DD
+:109BB0003CFB014501787ABF67A77C2335EF680D30
+:109BC000F3D0733DB003F2B3C7F7A001F1BF8175C5
+:109BD000D2FB4D05B7A621BC990D943BD09F686F71
+:109BE0007EC901A35CB6E7C10A8CCF2EF5D7BC8431
+:109BF000CF258784B3E8BFC2FA983603E327427DB6
+:109C0000DB18E86FC533A56DC9F07E91C8E9C15E68
+:109C1000E5F400BE718B31C3E709EB61067EFF6995
+:109C2000B49BE621DAE669D643F536E616E282F918
+:109C3000F343EBA3E0F63F26A33F240DD0FEFBE663
+:109C400093C618A4F306C6F57730FEA1EA6D467CEC
+:109C50007E3B8B7062BD0F15BEFE3095115F7F2875
+:109C60008083E70ADA932CCDEB708D0FEADF0F7556
+:109C7000FE7CDB78D2CF8B10EF2F3B96C91837BB19
+:109C80003DCEE414B13CDA9FC6F75187E43CBB12E9
+:109C9000198C7B3DA0E771A8F07109052F7F86F62E
+:109CA00083D1C07CB8BF01EB9BE5E3BA1E63A0750E
+:109CB000D582A8C5F85999471EA9FD56A5DDDE2F06
+:109CC000B81FEC83F9E079C961FDD8957E22783F11
+:109CD000AA1EC1FE488E24304D7F9B31C905D78115
+:109CE000D54DE36FD64593DCF978AC7713D24B8D25
+:109CF000FFA8FE616FFA0719E4C77FDE9282763A09
+:109D0000F02FCF4B2CE6F2E935BDEC43F8B5D27419
+:109D10008AFFAB727771018F972D56E3634561F12E
+:109D2000B1B0B80C2B1A395EC698538FFD4E626FD6
+:109D3000A9F8A178CCA92289E8EE03BA63BCF9940A
+:109D4000E2A7964672FFFCF73362899F62E66710CE
+:109D5000BFD9625980F6A3AC22F15B0FCBB1C484AA
+:109D6000C889FB9438EB6EB08758487CFDBEDC0692
+:109D700013E61BECB0F0738CF79745D486E6BBFF77
+:109D80006EB69EF0797B71E92BC83FD9167F19A971
+:109D90006DB724E37C04657E93ED807F1D36ED5125
+:109DA000E2A54E138F4F9593DE56E97EAD7AFB699F
+:109DB000C9BF2D02E71FC7681D5A3BCC244FC54EB3
+:109DC000770053AF27152F3D4CF4943C59D84F776B
+:109DD0007E04B340FD4FBB0DE4E79FD4ADFE1EE60D
+:109DE000C50FBC6964B8FFD9694D96506F747E7118
+:109DF0005D393DADB3E6321EEF8CD481A0C8B1B35E
+:109E0000277E844453CE9F750AAC9751DCCD1DA9A3
+:109E1000035FAC53C72E97C0B88E595C7BA711EB7C
+:109E200079449CE77B45DE9F225EF2593DC1F71BDA
+:109E30003CB507A0DFFB634CC42FF714794EF071DB
+:109E4000B2B68530BEE23902C3F3BC6D066E9F59CF
+:109E50009D117C6F8A713BDF339849FDFF429197DA
+:109E6000AD0E771F1E1C19156F766960283E427C67
+:109E70009742713D158FA1F4B2E76BE8E5D587D223
+:109E8000AB00E83525945E6EE1EBD0CB8F4966F1EF
+:109E9000C3F9D457263F589ECBF51BA6CA85F36954
+:109EA000A971B605F35CBA6DA20EE9D61D919C8D21
+:109EB000F139954F55BE1D815FB7F4A0DC4891EC98
+:109EC000B86F6CAC8CA07D18957F55BEB514F2FCB4
+:109ED0002DE0DF5585F05C69F154A06C09E75F8CDB
+:109EE0009385F269F5A8FCCCECA1EB7811D815515B
+:109EF00031680F9D3BD419C2A7D5F517252E57AE53
+:109F00009444E407E37A8B8A04F66E28BDE1DFBB54
+:109F100059CAFCC81E92C80F53F17AADF8D77FA377
+:109F2000390BEDBBED786E11F0D52E38DD8918EFC9
+:109F3000AA7FE70E7CDFA69C1BF6651BB8DDA5ACEF
+:109F40001BB5BD49C5655105B82F30E342E43AA8B9
+:109F5000F769824E46E4B4C9AB7F44EBF04C24C3AE
+:109F6000EF6CB17DB54FD0BA9AC870DFF0D3DBBCCF
+:109F700063711F7F27D0E95D4AB2F627EA688FAB8D
+:109F80003F11D71520D7C19F5E077FCF94723FC185
+:109F900087668E53F2ACDD4AFD7EAABFD3B0C714EC
+:109FA00081FDA49BEC0743F8BF4489BB5716A8E783
+:109FB000755A64B4D72A0BB85DB3B7E9C8ECF72774
+:109FC000E0783A67BF0FE3895DE8675EE0EB882CD5
+:109FD0009F8CA921A62FE70878AE815DC73A311E74
+:109FE0008FEF9BA704DB7715F07567423B06E867A8
+:109FF000DAE69343E5A849277847CA83393C53E218
+:10A00000DF6D63546E3AF5089DF38FCD700A980F9B
+:10A010006DDAB687E13E8D39C0DFC765B885352179
+:10A02000EDC62D847187F005F0972F0AE48FE920A3
+:10A0300030662ED22182E292E1FD2E8A2FEB956CC2
+:10A04000A3F34938BF3185DF54BE51E74927564253
+:10A05000CEEB978FE376725BA3E100E5A116441384
+:10A060007E3F892B8B6223D89FEA733FF081CF8894
+:10A070007EB3899E07C1EFF64D44BFD941F061F030
+:10A08000BBF17904FC6E7C3E0D7E37963F037E3734
+:10A09000C23F04BF1BE14EF0BB113E067E37C2C774
+:10A0A000C1EF46F8C7E077E3B30BFC6E7CFE0CFC17
+:10A0B0006E2C3F017E37C22546E00F9C4F96CFB1F4
+:10A0C00014E8DA7EB7C18D7984FB15BAF6B8C7C536
+:10A0D0003A81FEE62C1DC5C4CDBF7C88E17CCC0E48
+:10A0E0001D9D0BDBEE7888DD8AFE6CBE95ECA9B673
+:10A0F00067B99D6296F632943BFB055F2D73C2FBF8
+:10A10000AE926ADCDFCB706C298B01785757C53E65
+:10A1100013AC8F4C79C9F2E61058B6BA361CB507A5
+:10A12000E1B1D90724F058D89E8279FBF048108E0F
+:10A1300003F3871FED5A50DD0C2C1418C7C8DE1826
+:10A14000483750DECE1AA417C6230A783CF106D64B
+:10A15000E2C0FDCCB132784502D50FB0B86BAFBFCD
+:10A16000BF40A6F7E1DF5DAD9E2EF79AEA31F12AF6
+:10A17000ED61B97095764CC232531F8C7D975E911C
+:10A1800053F1169253ED18DF01BCB79BF9F3BF678B
+:10A190002A7ECECCB25533E1B96A26A76BBBD9670C
+:10A1A0002FC3FEA7E8289F8135A6FF7A1CF477D736
+:10A1B000BF4B0CF34155FE7C5EE1830963AD742E09
+:10A1C0009FDD63A2FDFCEBC73EDB1A03F084279CF6
+:10A1D0004ECC7BD8C59C11C827BEDD3ACA7BFC415A
+:10A1E000EEF89825507D72DEF33128D763677279D7
+:10A1F000E357F2859ADBD68DC578D4A7AF7379780B
+:10A200005AE9E780BEAF9EE89967213B04284FF6E4
+:10A2100046B303880D3A5397C49F06BD7D05D633D8
+:10A2200080618079D9862F6698D0DF6B1934CEE3B0
+:10A2300079B37D648718CC5E7B34BCDFE3D3915C5B
+:10A2400068912D94E7B6CBE2EAC573CE3EBB8EF2A1
+:10A25000617765EB088FAD969BFC68E74B42732DE9
+:10A26000EA31BFFD98291DDEFBB37594DFE8772F37
+:10A270009D87B0CF2B51FE15FD60B93786CE77EFA5
+:10A280006203AF4EC3F26A6E87B525FCF55424C64F
+:10A29000BF6FB43BF9760B93313F8C52C574E877AE
+:10A2A000F76F8BC4715431C59FF591FF6A3372FA11
+:10A2B0007DA77BBE7D1CD91921FB5A468CD5394D13
+:10A2C0004E289F6A71CD43FF52B2BA4C98F7D76AB5
+:10A2D00077996A68FE3C5F8DF232A0DD16BB8EFC7A
+:10A2E0005C2CBF359BD4E1E98C7C25155FC6793F9A
+:10A2F000D48DF890D632962EE3F8245FE8BEA1699B
+:10A300007C51AF0CF3685F1743F3900427C16CAD29
+:10A3100044E31E2347D0B9E6BD86CA5EB417C7988A
+:10A320006EA7FDADA45A49B3FF94E8D5C2F1CBB5F1
+:10A33000702C9382FB57D0AF7DA61A7FD3E22D1CE1
+:10A340001F49F6D6D771FC495E3A04396CFC8FD8A8
+:10A350001F8E2E65384E0B8D33C1B2BA14EDA67820
+:10A36000E66946FEFB47C739D5BED4940EFD4F8D36
+:10A37000D39179348D0D6CC3767729FCDE9ECEE9BE
+:10A38000195C5722CD0BD6E53C5C97631B75E0B09A
+:10A3900005DB4FF781E3A6D93F88D1C013F68CD1F6
+:10A3A000D49FD8314E533EC97F9DA67CF2119706AB
+:10A3B0009ED259A8A93FADAB4C03E7041668EA4FFB
+:10A3C000EF5DAA81F3FA5668EACF38B35A533EB329
+:10A3D0007F83A67CD6B9060D3C7BE05F34F555FB48
+:10A3E0003E5C3F96CDFCFBEC7AA3638CE67E9B70D3
+:10A3F000BF21DCEE377DD9226F437EB619889F25B9
+:10A40000D4E7B8DF7C37F78F4CC54E19E54B81C2D6
+:10A410008F9F15BB1723DD4A6D26D20B9285D793EC
+:10A420002C73C95E49EB30D0BD3B929D0D9547A280
+:10A430007C6EF2CDCE98101CB7D9BE87EEAF28B592
+:10A44000CD63988FA47E2FD9DDCC6BC5FE64EACF97
+:10A4500064F7513DB30CDF87CCE3A44EC72C28C76B
+:10A46000C18F43FF6034BF4DF5D7543F6D34FF4C6F
+:10A47000F5CBD2742C029F0784FE3BD07FCFAE7FFA
+:10A48000BD2C9191FFB605E77D3F9EDB46BF6D2A4F
+:10A49000B7B3DA1216C818CF694FEFEC1D87E389FE
+:10A4A000D751BC14EC66E7D2107BF1B199DC0E9564
+:10A4B000C6B5F7A3FE6B8836C9682F49A603B3DF7C
+:10A4C000077CEDD7F73F85F18956C1BEB113E5E2B0
+:10A4D000DD16CA03D9ABE04DB6EAA66F83763B9B87
+:10A4E000DD129ECFEFDCC99CADB83EE24AB745C352
+:10A4F000FB0929353A0C034DCC68DE86CFFB67F2A9
+:10A500007D9F49D90774B1503E39B77439C6BD44EF
+:10A510003BF4779538B468EB60381F96219D45BEB3
+:10A5200042EBFE0A0CBD34C644FB9266A4B7404F12
+:10A53000C28379D0E237239CC1F162760BFE488159
+:10A54000DBAD9847571AD341F455ED59B473B1FDBB
+:10A550007B8ABC8F213EE3166AE92A990E113E766A
+:10A5600029FB12EDD1F22F513FB7A767C4E07E96C9
+:10A570003A4E55AE1C56EC7BF5BD2A571C986B9392
+:10A5800017B46F80CF3B30FE6696F6D0B94CF3BD62
+:10A590007B18F2B5194FB193BDEF933DA43F3C9AA0
+:10A5A0003CB4F271CB4DA8AF2FC7B9C89E3537FE6A
+:10A5B00098C6178E37733FCF471B0DAFB6CC4749B0
+:10A5C000BF830096F13CCFA9044B6D68DC537DBA84
+:10A5D0000BB8DDA257F386C093407D7659CD4B7200
+:10A5E00047F2F14573B82773058DEF8E7857E2D5A2
+:10A5F000EC6D33F89BDE10BAEF943C26C443DBE7E6
+:10A600004BE6D1BC255A0C6CD717D907289EACF85D
+:10A610004B6EC53EA9445F0C9E69067E8EC019B77D
+:10A6200090EE3353E3209766F2FC45A78F893C8E6A
+:10A630003794B7AEBB328DC62A1B54BD4BA62CD760
+:10A6400053F07F37E6AB8C6F97B479EE8A1E57F5DF
+:10A65000F4843DDAF2891D5A78927FD8F7FF897A1F
+:10A66000FE46FE3BE8016DF9A38ABEBE11F535EE4C
+:10A67000677D83E78B98604457B89E0DEA3D900351
+:10A68000A99D8152149B295B254D9EC998307D78E8
+:10A690004F914C78F0F44A7AD4B36A9C265C0E0B46
+:10A6A000F75CD882EBA534325246F989710CAF9130
+:10A6B000FBE55EF053EE979CBFAB46BFAA57A43CA8
+:10A6C0002A954EE174AD2D14147DEA110BC93FEEAD
+:10A6D0009F8EFE3AF6E70DE94F8DB79C2FF69A3123
+:10A6E000BEA1C65D2ECD935E12E4601C458D0BAC01
+:10A6F00052D6CF2EE71BF53D308E9E33468A8154CD
+:10A7000088BFEC6DC23CA95489E4977DC6C6EFA111
+:10A71000FF5DF67B28C778A22C27925DDEABA738B9
+:10A720004099C2C7658ABFA5C65BD20B399FA72ACD
+:10A730004FF82282FBF58108B45F271F01D9ABA532
+:10A7400067242FE771B6299DE1E56ECA5FBA4EE135
+:10A7500017CC3B2B4DC0742F0E773221D60E749C34
+:10A76000B6BCFF14BA0ED9AFBC14817C78D4CCED42
+:10A77000B5A7157E48608213F3F3138E589C7EA80C
+:10A780006715D9D13E9887F3B4A4C9339B7A420B9D
+:10A7900067B310381DC7A18577CBF5B8F5CC7657D0
+:10A7A000834D0E539E59A8E46567B24CE4AF0AD1BD
+:10A7B0009283FE5343A985215E8DEF4CFCB73E94F6
+:10A7C00017AFF37BABEC91F283E5F0BDFDD5586795
+:10A7D000B31CA4FFD3E047A37EF8EE15276BD50783
+:10A7E000E35ACF003D33687FD94EE59D4057848FB3
+:10A7F000815F9D41FBCB59F4FEC7E05723DC057E0A
+:10A80000353E7F067E35BE3F017E35C2B71797DEE7
+:10A8100084FCF216D443BE88C8396E1A8F716E8BD1
+:10A8200048E76EC2F97147FD7B969B4156153BC6C2
+:10A830002E8C477ED82AD2F9E49B0AC72EC4F3DBBC
+:10A84000A171B5D0386330AED62FA8713523D0E7CB
+:10A85000F20C59C95F50E26B5E1E5FFBEA76DC6A60
+:10A860003B14BF1CD6CE501CD3E47B3F0B8F6C092E
+:10A870002C0ADE7F74F77F1D463D9398E4ADC579C1
+:10A88000D7E5BD6BE076373F4F95A2ACA37D669EC2
+:10A890004F9AA2E40185C72F8BE7BC73473CA0EC1D
+:10A8A0009E9FCD5E89FE7FF1EDEF4C4F03F854E1A2
+:10A8B000532B31FFB7F8FBEF3C970C78CA9AB58160
+:10A8C000C37BDFB99CE2C43C8C875762FEAF2D96F8
+:10A8D000EBB77DCAB9A421BDA7AC97CD8D4F901E13
+:10A8E000073B83213E5A123CA45F3F8E1BB0D540EC
+:10A8F000FDCDF10309ABAFA20F36371EA6EFF70966
+:10A90000CE737E1CF74C13CF3B55F4CD2585775580
+:10A910007DD360E6A03A1ED0B0F47EAF120762EE9F
+:10A9200064FA2ED6CCE11E5B21E9A507CAE45FC913
+:10A930007CDF92FCE31EDB75DFC1BCBA967912EDB9
+:10A9400027EEB5B8CCA8B79E53E418B4EFA3FC9596
+:10A950000A13EDF3B0B8E5B4AE63D47EE2AA291FC2
+:10A96000214619CFE9C28800C6075ACA4D07518E41
+:10A970003E641947EDB514187C189751E16D853088
+:10A980001EC067B42D261D6155CEA9716386BB6AB2
+:10A99000D06E9932ED3235CFC1A4BF106A5F5B58DB
+:10A9A0001FF18F53278B681FBA67C9448FE9CCB951
+:10A9B0001CDF1B847A1F3223CE43173A0FB95C3B4E
+:10A9C0000FB942330FA1C11440BBB0A502E601F597
+:10A9D0004F5BF369BCE17453E7F3FD42CECFE1F383
+:10A9E00064CA7E927A7EA0CC5E741CC755A173B7F0
+:10A9F000E2B85EFAAC3A0E2F929CCBEA257C3F3E41
+:10AA000098CFD3FA75F2258ADF13F8FED7ED069AB0
+:10AA1000DF2BB3F9781E35F8D3E96087E44FC27DA8
+:10AA2000DFD1F8F84F0ABD837CEC66B8BE5A62DC11
+:10AA30009C8FED03B666E4E3E881846D34AFC08893
+:10AA4000F409E7E7707A0DE05D09E447FB44C4FFD1
+:10AA500057D157A56BF83E98CA2FEE597695DE0E62
+:10AA60009A67204DB34F082DC823ED8F6F87F6E40A
+:10AA700090FD3483C34376B63ECE9985F1E6962F9A
+:10AA8000C511CF4DCAB3F87A6FB64590FDDD62E3CC
+:10AA9000F677B76D81C66F2A073F0AF791C558D67A
+:10AAA00089EB4A8C5A41713431112D2F620BAD5D07
+:10AAB0001BB590DBB576D755CF4F49FDA2E65EB505
+:10AAC00061766DCC026ED7DA0C64D7EEB31A961F9E
+:10AAD0001841EE0C16723BBD1BE73182DF08FE22E7
+:10AAE000C533557FD160F792DFA7CE7350E177B5BC
+:10AAF000BED15ECF30BE261A9C32DAB1A272BE152C
+:10AB0000F39AB342EC02B5FFCBCAFECEDBC5FC3CE8
+:10AB1000849ADF5EFC2BA17E24BCE7CC52ED92919F
+:10AB2000F9EE1FE01B92132E8BC18D7687CBE2A02E
+:10AB30003CF0D1BEC32DEC73314139E3FC325F24CC
+:10AB40007D243929AFBF53DFFFDCAFD01F7CC94262
+:10AB50007AA7D39A52166A9783D14AF9C9E0FFFAC5
+:10AB6000B2A0B1A37F8315A90BFABDE087DD302B1E
+:10AB7000645FF254C359DA070AB757C3E30A43EBD9
+:10AB8000DD76389D8FC79F84EB5768284844BE0AFE
+:10AB90005FEFEA33D531FDBA3530AED4A41C7AAAC2
+:10ABA000EF1F67E2BC91EE4F5B3D4407AEA7274124
+:10ABB000675122E9E7D538EE8FB6BE91E094F19C5B
+:10ABC000ED45D2D397EA0BA27620BF67C5907C4DA6
+:10ABD00051CE8FA9E349B9AD3B3AC682797C039344
+:10ABE00030FFCDDFE4B9AE5C4F7E867BA4F13E3012
+:10ABF0004B89C305C6B2D0FB81E4B8BEF91301EF9F
+:10AC0000B245E794697DD949FFA972A0548A2EB74D
+:10AC1000039FA73631A745C6AB93ED14174BBD2252
+:10AC200012BFA5F6F0FB9DC7C60D0878FFD0503FB8
+:10AC30004A9E93BABFF2497D39ADCFD444C6FA28B3
+:10AC40007EE9A17D884FE2024B707D7FF2301F517B
+:10AC5000EA13DA72D0B914B75EB735C22F43D363A3
+:10AC6000EF85F1E178BE27B094741C474FFA0E8C43
+:10AC7000FBFC2492E23E624706C56D6E4BF2DE4558
+:10AC800078F5CB77E9C62B93857A75DF8AA0FB042C
+:10AC9000F6097DF3299FE24E1D7B7284B8D4BFCEA6
+:10ACA000E2EBFCBBB3F83A4B75E4737A3B72AF5BF3
+:10ACB000137BEDEBE914CA6D18C7AE283FEDD3A99D
+:10ACC0007961BBF523F3152BE27EEA903C56F067E1
+:10ACD000422F08F8451414BBEFC8D34F3F9DC0F86E
+:10ACE00011C3717C3F3274DF3822C34F85114E3758
+:10ACF000C91FC1EEE672D65EEFF0017FEFF8421C8D
+:10AD0000B1FFD715FA35A7DEE5C0FAE5B2939EDDAF
+:10AD1000A9F9676A007F168B811943E4B0CA27E15D
+:10AD20007ABEC13AEEAA7EBC01E4B17C953883417B
+:10AD3000C9FFDA7E6AA609EF0FDD6E71F5A1FDB5D8
+:10AD4000DD12E7A238BC05E446485CCA627999F88E
+:10AD5000D0E2E4F13A0BCA5F8C4BE1FCB371FC2FFB
+:10AD6000D3FCD57ACF2A72C8E20CD07EA9D9B98794
+:10AD7000EA99240F9D9F33C531CA6730D9F9BDA325
+:10AD800011193A661A411E1F9EC5FDC0EDD9AEBE0F
+:10AD9000321A9F84C7AAD87687CB41FA10F10CDF0C
+:10ADA000F758F3A342F1F39E220F5ABAF9FC3C8DF7
+:10ADB00049F6723C6753ECF9AF5979D8CE6A13DE85
+:10ADC00073275A73AFDACE8561ED3C92501E4BED7E
+:10ADD000BC87ED8856971DDBD12BF7A786E3F933A7
+:10ADE00085DE7F6F3C0D3048793C8417224C404310
+:10ADF00097F0A705E362B1237DC7E562BAE2BF80A1
+:10AE00005CD417C1BCEAB2DF7D99AF31EEB7C4CCD8
+:10AE1000E779429780B3F1DEAAF0FC8B703B46D510
+:10AE20003FAA3E8276446CE751B4632606D7911A56
+:10AE3000CF49AEF5F0F512E7217E01BB46C6F522FB
+:10AE40002A797EE1F3B9A188E35FB015C8A82FCABB
+:10AE50003FEF4FC6EF4E5ACF25733B56BBCF7CFA20
+:10AE6000B3C3662CFFA4B6ECAAF68ABAAF3CDA7E6E
+:10AE7000B2ED5F3EDC126AAF8CB6BFFC55FBCAA7D1
+:10AE80006C068ADFED17B4E7E32B8AB8FC7317A9C9
+:10AE90007119EF8C228C430A1E273FF0CCE3339FBD
+:10AEA000157B0B914E69ED06E603BA9EFC2CDFE1A3
+:10AEB0000D69E75AF1ACC6E1C728F6D418CB610199
+:10AEC000D7E9985ABF8071F4E4DA4EC17D957AB122
+:10AED000455C8FABF5F54AFB25D28088FAAAC4CE33
+:10AEE000F562F2A0C4B242E48EAD88AF5FBD62BF2E
+:10AEF000DB4E3D65C6F64EE93CED99A81F6C3AF96C
+:10AF0000C990F5AEBFCD652A0B995F0BEE0F8D4052
+:10AF1000C74D45AA1E0C90FE56F5AD5ED513719235
+:10AF2000464F6C8EE47CACDA3B9B0BB93FB4399254
+:10AF3000FBE5AF3ABCEB11FF1F177EB868BC8CE78E
+:10AF4000643B0DB89FFE55FB2443F68DCE5FA3FAFC
+:10AF500033C8FF4EC9FEF37EF83EE7FBA564EFE57C
+:10AF6000E18D23226ECD72FB0FECA93B8BE2F9D56C
+:10AF7000FCA1F46661F70B8E361F2FDE6B9A87F10A
+:10AF8000BF3E8ACFDEFFB930E27988AE22D52E1AD5
+:10AF9000DA0FD4C4599315FD96AC94CB18674DC7FE
+:10AFA000FD2D6D1C747AAF16CEEBD3C233CE84C5A3
+:10AFB000557DEEDFE0793FCC1FC046F7C13A4339FB
+:10AFC000B146D9F74CF1F94BF19C782AEBA4FDC5B9
+:10AFD000E4DA180D5E8B4525EF02AF3956C7093FFD
+:10AFE000C952E579FCFED921FAFB9826BFBF7CCD7A
+:10AFF0005D782526DBC3CFF999A073C4D7FAF94B46
+:10B000002B90AEC3E2B5F5DA386D726839E061DDD8
+:10B010003EED79418F3B87FC8165DFD09E1B54F369
+:10B02000D271BEC9AEE1FD7F75BFF02F6678FF6AB1
+:10B03000BB8F82FC21F9AADC279C8A45D88E14108C
+:10B04000709F7B4C3DA37B8593B732F748FB057F10
+:10B0500054F0158E67E62B21FCCD51DE8DB1F07CCE
+:10B06000D5315B75640F8E01B9407F6F6023C800D6
+:10B07000809337CA644F2EAED531D40FECF326CD72
+:10B08000F7305C8AA7AA747FD4C2F37153EB985F40
+:10B0900087F3A9BF8ED6138D6B5C901F005F9A7BE0
+:10B0A00005161768CFEBA6869DD355F92039ECBD60
+:10B0B000AFC8AE5917A0E7FE58447CC2F5DF04D4F0
+:10B0C0007F30A48F669E398CF975C5DB18BFD726F3
+:10B0D0003A82DF6B13DC8F10AF00BF9E32CDC942C6
+:10B0E0007B65973D4287790F27A3FB1F63D18C5D5A
+:10B0F0002C62BEF222BCEF7060B200F017275AF744
+:10B10000B7CF8672F3C00F30986CD9BDEB9679A992
+:10B1100041D8F6C0F70866054CC67B8130E714D7E6
+:10B120005D847DC111BCEF3A22DB42C1C908A6BDD6
+:10B130007FA7B550DE8D7923AD1374CA39E99072BB
+:10B1400098C786D9EAB97F37E5DFB1793C0F20B4DB
+:10B150007DCCCF1EB5FD05D07EEED768DFC4C79F7E
+:10B1600080AF40CF24E0F8310E8EED237D3168149E
+:10B17000DABFD29EC47C0770FF06FAB308BC3F3B1F
+:10B18000E6A524306D1EC2507F76E86FCAFFC17CF1
+:10B19000960FA787FE6AF458F1F5E8D1AA73D37821
+:10B1A0007D532DE407E13D56785F9D59E9CFACDC36
+:10B1B000DB85786DCD0FE215EC406A17AA375F5139
+:10B1C000F08C7986097603E17934BC9DB2F3BCA892
+:10B1D0009DF6087F73FAFF077A3938BD42FB437B3F
+:10B1E000F29AFB5B01FDC55D7B7F885F5C3F43F8A6
+:10B1F000059A6C4BB876FCC2A87CD782DF53D0AEE0
+:10B200002E04AFC1FCA347ECE81798F51E13E663C4
+:10B210007E6B7634C9EBECB8A526CA47885F4AF93D
+:10B22000C56DD916CA876FCBF886491FA2A7DBB2B6
+:10B23000ABA91CEA53DE54762002C3146C0AEBA3BC
+:10B2400038C0CEA27207FA85BE7A9E87A5E625A9E8
+:10B25000FA9029FB9F342FF8306AF6F18153507F22
+:10B26000677D2EE59D4545FF95F2AD76D53A9D5813
+:10B27000FE9899EF637E57D9C74246A578DAD4C2C3
+:10B2800027703FD735A141A0FDCB8D57DFBF745D3F
+:10B29000EC2BC3BC2D56C3F3B21CD552983ED4AE92
+:10B2A000DB5D88579E3FE517387E35ED3D3B3B9E85
+:10B2B000F0B633E320C3BF3BF41CB4256AD7970E26
+:10B2C000F398C2D7A36470D33D63AC4147E348C64B
+:10B2D000D4005071AE290B1D35F03E65AD44F7F931
+:10B2E0002666DF4BF94C60E593BD919DFDCB328422
+:10B2F00087CD738D761EE1F30A1FB77ACFB14A2F3F
+:10B30000D7456724FA57AE094B29DF8C7ED4F52E3A
+:10B3100086CD07EC61739C8EEE838BC8089917D39A
+:10B32000D453FCB77F2EFC18E82A5A47E1FB62FF92
+:10B330008F9F1B3232A7C940DFA9E76CF87EDB186C
+:10B340005C3B48F734C6F3BEC3BFCFE7DF3307DF4C
+:10B350007F334630139EB3113644501CD368041813
+:10B36000CFE128F78D3DAAC4DB9A052625B942FB1B
+:10B370000B50DEBC68BA2103FD8653A665763ADF22
+:10B38000A6F851FA680FE52DB2AC188D3F7A4A390C
+:10B39000A7D6705B7A22C6EFA2A0AC0FFD6AC9697E
+:10B3A000427AAB7113DBF8FE6FA21E3F3B5BBFCA54
+:10B3B000847A1B9DE042C62EBF70653FDE33ACAE83
+:10B3C0004FE320BFAF630896EA292FC43898A679C7
+:10B3D0001F50FC301576C749E5141F2A9609CFA5E2
+:10B3E000CCDE8ADF95027234F70328F77F0C6F3FBB
+:10B3F00045F33E00FE75E8BEC0E8ED476AEE193041
+:10B4000082BF3372FB9961EDDB476C3FD86EACA60F
+:10B41000DD3689CB0D5F5C847FA4F81EE6FF17C77D
+:10B420008F9EB79655ACE4DB9B40A2E13E94C23FB1
+:10B430003B1CF594C72646F07D533D8811E4A71EBA
+:10B440006B2DCFBF48D1E6B1A9F78BB4E1BD215038
+:10B450005E66D1DAEBA56CA0679A807EAAD65E2FD5
+:10B4600046498AFB532CDC8EAFA77D527D8A562E2F
+:10B47000F4E07A81F9E8ACB97D94F7166FA1BC8647
+:10B48000D1E20B6F3531CAC7D2477AEA51E7959EB0
+:10B490004C1ADB56007014E7B3C527A7AEC2B8D16B
+:10B4A0005B0A3FB7811CA073A40D8907C49076ABDB
+:10B4B0000D8109A857AA75FC1C00FD40FF6FC58FC0
+:10B4C000A1386B78BFEAFD312ABCB25E989D11327B
+:10B4D000BFB794F531D4DF1DC907D0AE1DEACF1830
+:10B4E000C8A3FE86F28A94FE12FEBEFEFEA0AC6FDA
+:10B4F000B5BF957769E7B7D2D047F35BA9DC5BAA04
+:10B50000F6F7079C5FFADFD19F920F36D4DFB7B40E
+:10B51000F35B69ECA3F9AD1CF22F95FE12FEBEFEA3
+:10B52000D47C07A3B1BE16F969B4BC0735DFA1D03E
+:10B5300091AAC97700CF6661A9C4D88302E78BEFCF
+:10B5400014CFFA1EF2C5E5850D4EB253147F8FCE8F
+:10B550000789743E88F4E8E2146E87A8ED1F692A13
+:10B5600060EE893C1E84CFAC2281CE1F4C2A10DCB9
+:10B57000B8CFB60FE407DE83B71FD63996FB9B1C06
+:10B58000F43CD824D3F310F8976E8A7F39090E144F
+:10B59000737FF1C1247BD51AB43F4A2378FE75D15D
+:10B5A0002CB06C83FE1BAC975366CC73BC89E5E072
+:10B5B00039B4CC0E8ECFB8F204BAF73E22E7745FEE
+:10B5C00013C03B0A4419F3CA77C823C7737E5ECC05
+:10B5D000E3443B94BC491F9E9724A502FE24CC7FE4
+:10B5E00095422A262EA4F3368BBF154DF64DF5371E
+:10B5F000FAAD7618C72D42CE6F32001F7F54EC9BF8
+:10B6000055690B481E84FBA771A8A972319F50F49D
+:10B61000FBE1D765D665E4DF2EBB91B118F87E312A
+:10B620007E077AEA578A7DF45ABF91A1FFE72BE79C
+:10B63000FBD7B7DCABF54B1F3407EC68173E98130C
+:10B64000C7901ED55BB5E53B0C7CBD2D0BF35317A6
+:10B6500087E5FDA8F720EEC05F6732D655ACDCFF6A
+:10B66000A2E4FDDC85721EE338293194E4AD9ED35B
+:10B67000341AD988FB926A7BBF53E4168B73131E6E
+:10B68000D43C39263E9383DFABFDA9DF3D2A3C93B2
+:10B6900074B5B829D88167FBB3B8BE477BFD3F8A34
+:10B6A000B5F94997178EFB4E391B896F07248C53C8
+:10B6B000A8E3FFDFE2D71DC57CBEBF9AF3492E3F4A
+:10B6C0006797C242CFD7A9F95FCB866089EE15563E
+:10B6D000F3FF9863201BE9FD9FB3239DF711FF291A
+:10B6E000F648E04DDD95C8AFDFDED0381CEE54CD16
+:10B6F000F955A5BDD1F03CDABD13F413921FD9D290
+:10B70000EC74D079BA78BECF3626AEEC3C9EDFC260
+:10B71000F27735FCA53DA7D5D2FD94807ECB63782A
+:10B72000BE4D1FEC17E3C06D166CD7CFE34A81A75F
+:10B7300028FE9B521B105AB383E781C2E562CA46BA
+:10B74000ED79B3F0FB142B2DFD922063BC7F80CEEE
+:10B7500031CE2FE1F4A23B3BB05E3CB727C5641D60
+:10B76000CF17192B73FB3263202D74BF636A899244
+:10B77000671AF9C65619446F46C943AB306FAA32EF
+:10B78000EA8DADE9288A4BF6AEC23CA9CAE4373E41
+:10B790004907793BA9E4610E4F7EE39371004F2E78
+:10B7A000F9570ECF6284A42925DF5D85FBAA534B90
+:10B7B00094FB95581F9DDB4E4CE27CF4F73E45A36D
+:10B7C0006EC47539A3448D5B323AA7ED39F18B33E2
+:10B7D00028A73C6A9CD7ADDDDF64CAFD8937A8EC99
+:10B7E0001567237B6901FE0EF8BC41B97747670AEC
+:10B7F000105E2706EF3579F8EBDCBB133C27CFEF63
+:10B80000116A69645EEDFD886E85FF79DE903A1EEF
+:10B81000B5FF61E3C2FB016342C7B58FDA51C7F5DB
+:10B82000718ED1274C0BEED7AAE3FA5818D88F4166
+:10B830008F033D7D3548D78FAD0369F8774E60990A
+:10B8400079098E1FD82F3843603DA7E3CA921F9114
+:10B850003D559CE45E5982F97B067E7F41BB624781
+:10B86000EE8AF7FAD0AF077EA3BC4D5F2A3FC750E0
+:10B870009EABFD7B6CEB4BB85DFA27E55961DC5361
+:10B88000FF7A2EDEA72EB066A8BFF9F3CB06F4FB35
+:10B890002B4FF0BFD7BAE9F83B06F4DF37210CEDA8
+:10B8A0006CDA6718F1EFC17D888709F8FAD5F82BB3
+:10B8B0002FA566B6C5C17836ADE1F76437FC34BA5A
+:10B8C00002E1861A9A255B5174B4023F5BE9E96E86
+:10B8D000C3E72AD6FF12EE4B5479B57EC4376BB559
+:10B8E00076FFCA7AADBDBE6A0F5007F4DAAAC6E485
+:10B8F000B0FBFCF83D81550A3DAB1CBBFBF0FE8163
+:10B900002A16764FA08FC791BEC967004F6D7CA4E1
+:10B9100012FFAE14CE63A34871DE9752B74B78FE88
+:10B920006D733DBF9FACA2EBA281CAA11EEE2B2579
+:10B930008CE1F7E1A9F253D5EFDF7CE1801EE3054E
+:10B94000E1F705AE5A3E8FEE055F2E6FE0FA7DEC13
+:10B950006F2B62E07DF83D80D55D5CBF57370A7E76
+:10B96000BC77F79BB55A7F6025EB6B437F6665BD5F
+:10B97000F6FDAA462D7CA444D1BF93D9645C1FCFA9
+:10B98000960812AD1705BE90FADBD702C83F499E54
+:10B990004EE4B78D86C054D473E5495E82D5727883
+:10B9A000BF89EB21AEFF75B09248FEEA79DCC25741
+:10B9B000C7EF67FBE6307B20C45E1087C3EFA9F2B8
+:10B9C000D3ECD94A7ED80B02FD7DF072C92DC58417
+:10B9D000F8C9E17CF8BE223F5F63FDD938AE4C6404
+:10B9E0003AA04BE632FEF79F335FACA1BCCACCE96C
+:10B9F000825347EB58C71AF15E3190172817D0FED3
+:10BA0000C4FB3232C5CEE524A7A719ECFCDE1D0726
+:10BA10000B5DFFEEA79880F9823874DAC74DE9A56F
+:10BA20007B371675ECBE88722E63BCDBF5208C6FFD
+:10BA30009772AFF6AE9F0A64CF6ECA7E99E4612218
+:10BA4000B005F6BBC9A1C8C52EED7D188928A7F0A1
+:10BA500000CBC26CEA3749DD7F50F37A036574BFCF
+:10BA600054A2D2EF971532FF7B7B1B3A059C772AB5
+:10BA7000F335631CEAD7280BE3834F759FE0C6E0DC
+:10BA80003EF97AA4679DA39FEE8751F7C947A8B7EF
+:10BA9000A5247E78BDD1E4EFFFF5F37F007E0B583F
+:10BAA000CA008000000000001F8B0800000000009A
+:10BAB000000BED5A7B7054559AFF4EF7ED4E7712FE
+:10BAC0004227813C0C819BD72C90109B8420E8EE70
+:10BAD00078BB3BC984D7D8E1310642A49909BB5150
+:10BAE00092741474A3656D1A616207DD2AA1D045B2
+:10BAF000CB3F1A4A5CA756778366B1D186ED80A109
+:10BB000050519B151D184B2AB0AC23C50089382E07
+:10BB1000CEB0C37EDF39F7D27D3B378A535356ED23
+:10BB2000EC26953A39F73CEE39DFFBFB7D171430F4
+:10BB3000C15C80071C002003D499AF650C5760FFDF
+:10BB400040492E607B9D7EEE1CDB9A6D26906DC079
+:10BB50007FAEE39FC5910AF2F4787FD1F46C5D7FEC
+:10BB600089B34037FFAE7925BAF146A55C37BEAC44
+:10BB7000A15AD75FE1BD4337FFEE268FAE9F92B744
+:10BB80005037DF2E2FD5F5D3A6AFD2CD9FE0FCA93D
+:10BB90006E1C26F5E7792700586D81611FD221C8F8
+:10BBA00000E665E1BED6F4209B08509E8193B14D1E
+:10BBB000ADB6A7531B9C9D126519D8DE925149FD65
+:10BBC00094B71FCC8BE236B6892FDB5CD8FE130B03
+:10BBD000B9B3710F2493AF1FE938F351504209F400
+:10BBE000FC3B8F09A026DECE517C77BAB0AD7849F8
+:10BBF0002E408EE04F6CA67716AE4FC57FE7E0DF94
+:10BC00003E5B684F11C0ADB827CC8FEF03F5AEF99E
+:10BC10000AAD7B54590093B01F064719CEDB6D0562
+:10BC200085FA817D56BEAE223C6C52D2E3EB86147F
+:10BC3000C6DFFBB4D7BD80F6EF8C3007E0BCCE9DED
+:10BC400067AD7205F50733146C2BBD67AD909EF898
+:10BC5000FC8C959E774A23A90E6CFFA5DFDC103281
+:10BC6000909307152BDFFF4821B6788E9607CDA15C
+:10BC7000143A3B288B5D286F4D20E4AD65EF48D426
+:10BC80008CEF6FE960CE003E6A92EF5B0C4857F094
+:10BC900059CE0E23C96DF87BBD18CF999FB11B6E8D
+:10BCA000E5EB017200D608D6C1AA79510BD1ABB928
+:10BCB0004DCCD7F8B96679FD795689FB76253D9F3D
+:10BCC000D23B6ACEA0F5D2D9614D1EF0DE3F53269D
+:10BCD0004CFA2C0D3BE55071BD04E0A4D76478AF5D
+:10BCE000CD1E0960328EFB3C9CDE4F23DDCC8CE800
+:10BCF000984C2741BF6FA3CF2BC4EB043E25CF0B3D
+:10BD00007A049F5E61D0D49F3E76FC5DE2239E67FD
+:10BD1000378B558119C0EF4DE572DA6C5BBBFE5C69
+:10BD200035D1FFAB5E46F4FF570629B8FF27836F76
+:10BD3000E7C824E77B877286713F7FFF500EA09C87
+:10BD4000B55BE44DD2242E07CE4DC897CE70949F9C
+:10BD5000BFA3BF7A909E778499D38E47F50F8CD678
+:10BD6000F37BC270AF239DDE6B7CAE6D8A899FEB47
+:10BD70007945E6E7F7FBF09D93687D4A28C488EF94
+:10BD8000C3562E17FB193C85FDDD7DB6A690C13E3E
+:10BD90007F4FF4C6F56FF55941423969C7F5748F85
+:10BDA000238547AC36929BBD782F46F738BE228D4F
+:10BDB000F6DF680199C5CF77B130769AEE7FAAD5C4
+:10BDC00002017CBEB9D5CCE97D6AA399EF635EF729
+:10BDD0009FBD05D85F89F29782473DDC7AE548012F
+:10BDE000EE7BAA0DFB785FCF3A0BD7BF95F7333EBA
+:10BDF0003F597E35797D4E95CF953EBDBC25CBEB29
+:10BE000018396DFB6E721A8ECB69E57533E77B5D71
+:10BE10002EC9CFC3E0DC43FA73EDB02517CF5BDC4E
+:10BE2000EB703E86FD59E6D0CF73C82E1C16E3B3E7
+:10BE3000DB7731615FE45574AF82A015B63292238F
+:10BE4000C1AF77895F93E96A232C8DF4558A1593E6
+:10BE50001DC2572BC4E7572DD0B4B7829E0BFB32BF
+:10BE6000EBF5BC5D5B13E4F611551E35BB576E0553
+:10BE7000DFDE749ADF7F4B23EEF30AAEA7E753D5DC
+:10BE8000FDCA4A46EA1BB1BDA0083BF8917A0EAD47
+:10BE9000FF0F1EB11FB4A396211D97D804DD17769E
+:10BEA0004757D33DE64EF17D42F66FF1D48FDB016B
+:10BEB000ED44B0F89D0A1F9D0F9C269AEF57E97E2E
+:10BEC00078FEAF9FDF80F7B5CF48E57C6D3CF46C22
+:10BED0008CF8DC592A01F1DD5E3627D767207F5ABE
+:10BEE000EBBF5A04BEEC78BF33325AAF18E8F57690
+:10BEF000F5BCB3ACE2FE104122E5737B2CCDAB8ADE
+:10BF0000CFD3EE0FF018BFA7BDEC05CEA70DF7C33A
+:10BF10006C333FF136BE4F73FB71B616F7B9DBA237
+:10BF200058D291CE1F4F6C5A7FAE0CE09D1E3491BB
+:10BF30007891633D36F0FD05C0FB3D0EDE8FF5E4E4
+:10BF4000F1FEBFF7C8BC9D31D5FB0705F759F15687
+:10BF50005719D1EB70E1335E37BEE7F2310BA7031F
+:10BF6000809BD369832A7B572266B0E1F89501163E
+:10BF700002163FFF3D570BC087F6E457F43E5CD8EE
+:10BF8000D1FD21B773CEB6D17A399DE4EA4C2FF5B5
+:10BF9000FDDDBFADA7B8E134FA09922F7F98411EAD
+:10BFA000EEB3FA6A365FDF113E6E95490E4C23F50B
+:10BFB00044FFC041062497FEAE516E3F9FC77B29C8
+:10BFC00078EE1FBA32F9FDFD91D926C1CF39224E44
+:10BFD00051F93F38F3771964BF6CDDF20777101F12
+:10BFE0008F9A391FB7BA47321C067C3989FB428ABF
+:10BFF000383FB5C9E34DD6409913D735A9729B3C5C
+:10C000007EBB4BC82552D8427102FD30A4DB6A5575
+:10C01000BE5AF02A13315E581D66D154D4DB96887F
+:10C02000E7BC446D1783B33A7B007056D367F3F8CF
+:10C03000F276B36D27ED5716EFAFF4E1A609714E16
+:10C04000735B1A39D184F707F83D520A4B737DDFD1
+:10C0500010DFF987315E437E75622024A3DC775CB4
+:10C060002DE7EDA5FD8FCBA427B6D49167C82FC0CF
+:10C070000F4C8E3DC8DF8E803EBE2953F5A0CC23E9
+:10C08000E8B6D4C5A4CFA673BB554EF7AECDF7AD79
+:10C0900070E1F3DF147E9C7188D4DB1AAD04E3E712
+:10C0A0009D80FED846FA84EF2D47FEBC6A70EE995B
+:10C0B0001EF72A8A9FA6C2535CBE01E59BE42AF9BB
+:10C0C0009EEB5CE25C9A3EAF3C74DE4AF1AE3F6CA4
+:10C0D000ACCF351ED73A3A4F1F4083919F2B57FD67
+:10C0E00073C74EC6E9E5DF99CDE97411767ADD288C
+:10C0F0009717F11CBB512E2F7BBD6999B8FEB2CFAB
+:10C100009B96951ED7FFCE9D697C5D5FE9D2ECB50D
+:10C11000D87F4495FB4B618F8DE87CCF4EA177DAB9
+:10C12000FB4E47576693FED45846AC4E1C9F1239BF
+:10C130009341715DCDFE65D9A47FE39DF33EB7B811
+:10C140007747F786F5E7B2853C98519FD6AB7ECC12
+:10C15000FF58D44AF45FDF0D5C7E07F77DD249FAC1
+:10C160007B2992E620BF77F1405A80ECFDE58329D8
+:10C1700021136ED54EF28EF6ECA265F8C73C7EDC3C
+:10C180006F7604709EFFE08567481FFDFB501B71B2
+:10C19000DFF591C747C9BFB547169C97A87DF9FB46
+:10C1A000D5878EEE87F87DB5FE851E9B4CF6F39203
+:10C1B00024ECC4FAF06B3C9E5D7FED4AA5B782EE9D
+:10C1C000F9FBB964CFFCFF76652ED931FF9B57E6AA
+:10C1D000D2B8FFF5B42EA3F8E4798F99D355F38F35
+:10C1E00045272425715E9DAA07455B9E6A2846FA6D
+:10C1F000D51C5FEE34CB09F25566F2D2FC9A8F6AF9
+:10C20000B3D725ACDB12931AE8F99CE3B569AD0905
+:10C210007279BBC7A2DA21D46AB43F2B551AAECCCF
+:10C220007B3266AEA4BE1450E308769DC7DB204B7C
+:10C23000C8E766FA0F55B12F26F17826D0660E951D
+:10C24000E17873CCA4D82B691CD725C41900DE452E
+:10C25000B388DFF74E766E95B9BF871EEA3F5C164E
+:10C26000227F0F01DB5069421CB432668AA6A0DC33
+:10C27000344552A2140FAD8C4967785F8D8F4E3BC9
+:10C280005EFD7931F0F8E85C629C83F1D0397DBCC9
+:10C290000413E8BC5ABCF431C55518CFB66C8C5A9F
+:10C2A000C85F619CA49BBFA6E947E7290F5BD3AD9C
+:10C2B0007F5E14934C4BF09E4568EE880C7DB11D5B
+:10C2C00036D20F2DCE247E0D18E8FB4FDD429F3570
+:10C2D0003DDA1233713E6C89B96DA5D836ABE303F4
+:10C2E0000E130470FF2D91657B186EB6E5DADD69DB
+:10C2F00044AF2D2796C263A4EF0EB7AD8CD65DFB7D
+:10C30000916D45455C3EC6D80FB7B08FF178C0D867
+:10C31000CF4D51DFFB7DF9BB3CF79F87BFC3BC7A94
+:10C320009A7B32CFAB9B293ED4F2EA643FA1D95F1E
+:10C330006DDFBB547A8FB5BFE779FC82F92FB7BFA9
+:10C3400077B9653E6F4AA4319BE7C5279667CBE96D
+:10C3500063F72F919CA6AC8AB1FB6BF19A3FA00CBE
+:10C36000D9288F51CC5C3FFDCB598851DFCB789CCD
+:10C37000ED5F6D09D1B8769ED872C6E7AD70B29008
+:10C380009DC5E33F2D3EBC313E07C78BE2F1A216AF
+:10C3900017C6BC8CE741CB150B1F9F31D557EFAEAD
+:10C3A000A1FBD9F9F39AF9625FB40343941FDDFD51
+:10C3B0001306DC0EA8F1A2269FC9F1E41791928919
+:10C3C000DF841B3DAFCAA5A65F5393F442F3538F9E
+:10C3D000B8047D3AC94F57939FFEDA4A7A305EDC43
+:10C3E0008D7E7A959BAF03BE7ECE4792D728EFBE57
+:10C3F000A8FAFFFB886FD84E89BDE5A2F316426C00
+:10C4000013E58BE3F9CF856A1C33DEF8232E91AF59
+:10C410007C9B1E3FADDEEFFBD2E36D6E71AEFFED98
+:10C420007A7C23FEB31ADF73A6C7F51CC96FAAB9BD
+:10C430002BE622BD7B17F54E1E3BEF2E2D9F944021
+:10C44000C79FA142AB89F21E7F9BC0018299F20770
+:10C450003C3F79DB0CB4CFFAABF93C4EBBEF6A261C
+:10C460006F83F920FCE883451CB7B9EFA5E31605F7
+:10C47000D7376F64B3090F6A6ED3DF273859E138B5
+:10C480005BE000E3F17230BFFF08E955604F894C73
+:10C49000FBB7D065090F69CB0C6D26FC82709C5BE5
+:10C4A000E9796A9C0EF89E0EF5F91D2ABE034971C2
+:10C4B000C09B83A738DEE31F6040FA6B8DA0FD2090
+:10C4C0007B7254E01D9D1161173EEFB6737BF2B98C
+:10C4D00024EEE1EF66A14D2C1E479C8F6CCB213DD5
+:10C4E0001B134F28184FE4C4E3898E173EE2F63041
+:10C4F000397EC81A10EFF1B79B4384C70C15CE657F
+:10C50000D4EFC07C3097E24459BEAB409C0B42DC78
+:10C51000AE283A9C64F72DC2EF7F71F43F781ED9A4
+:10C52000BC9F41368F3B9458694E3CEE58135CC813
+:10C53000FDBF1667AC997664A880F653E30C07FE3E
+:10C54000127E981C6774868F5B282F18134F24C5A2
+:10C55000119FB9F5B8E03449E0ACD322CC4178D290
+:10C5600034959EB7F5A5F2B8B8FED3D66CD2738DCC
+:10C570003F971A05BF2E9DFAD245EBE67E2A39C8B1
+:10C58000DEBE796AE38705A22FDB645AB7318DF2EC
+:10C59000904B9F3E9046F47C135B407D7DFDA464F0
+:10C5A000881F2E57ED11FAB7DF73FFF6A88A1B4BD1
+:10C5B000E8DF26C4F197E4751BD475414C3338EE9F
+:10C5C000B81FB8FC06F37D0B79FFD962D8C3711F81
+:10C5D00021AFAF45321D14EF95E365BBD14EFC731F
+:10C5E0002A6CB157913CFBDEE1FAF1AC89CB2FAE5E
+:10C5F0000F30EAEF95B9BF2BC7BFD538BFD28A67D6
+:10C60000A902F132D4B7992ADFF2310FFDCCC64529
+:10C6100068F975A453F994A35F131F2B5341A2FD2E
+:10C620009FB0F8B6CEC0254F0C4ACE4DB4467266C8
+:10C6300037E2BD9EB08BAD9ED88FF28AE742E9E625
+:10C64000E7EAAC387292D633D901AB717D675E7A76
+:10C6500094F033085B7E73432E510E18BDA752C869
+:10C660001BE5A30C14761DF9FB873A59D8859F78F2
+:10C6700081F2A0CDF3BA80F2CEDFD5811A07D902BC
+:10C68000E770FE0A5C31119FE7E6FB96505ED89199
+:10C69000376C1571C58895E28A55E47FB8BD15B829
+:10C6A0009D09E793BDDC3AFD552E6FCDF43C419FCB
+:10C6B0002111DF338FED3FEDD6F64B7EBF2CF2CE4E
+:10C6C000A4F7CFC9FC2287E72FFFFD5F19DC9F4548
+:10C6D000AE70BF73792405621CB71B163875C4C2CF
+:10C6E000F3F5CB98074D4EF067AFBB041D0E453CEC
+:10C6F0005C1E0762B56934FFB4FABCEFC4F2654B47
+:10C70000484E6292B38C9F52E4350331A946C40768
+:10C7100063E8F4D76E033AD952853D4F96CF1C5546
+:10C720003E733CE2DE9E53225FF16F14F50387AA4D
+:10C730006FFE2EC6EDCA91C21CA6E1C8B946F585AA
+:10C74000FD23DCCEB6DCCB9C0179FCFAC27635CF7A
+:10C7500048B6439DE1BD826FC9B86D433DB73B37D5
+:10C760008BDB0265C373E376FA7E8F6A5766091C1A
+:10C77000F7AADBC1EF9BD535DB950BF1FB1BD0F3A3
+:10C780008CC780EF06F3466A0DE86E306FB67273A1
+:10C79000F3FEE626E73D7893F39E566EEE1E176E87
+:10C7A00072DE4737F9DE5F18E92DFC1FAD8326D70F
+:10C7B0003993EBA2C9F5CE94B7D70568EC71F6E4CE
+:10C7C0004894A89BB1AF89A1CA4A992FD8484F165F
+:10C7D000CF177581BE5A5B68178BD747357A9DAAEC
+:10C7E00013F197A36234908D749EAAC46AB3519FCB
+:10C7F0002FCF079E3F5CB68BFA00488EFC46CE3F9B
+:10C8000047FE52B4FB41BB719DE94975BFF1EC098C
+:10C81000D4BB3E257D71505C6EC0C78D2A7EE70873
+:10C8200003C76D4092F397F2F7CAF9E46F26BE256D
+:10C830009E674441D9C5CF25172DE571B45C44E707
+:10C84000DBAED6BFB216FEA088F0BA2CF4BB541FE4
+:10C85000D94675129E0738F83CED7DADB5E27DDB1B
+:10C860002DC0A89E1598C1789C0AC31319C99F565C
+:10C87000DF3866899E5BCB787DE3AA07EFF79E29B8
+:10C880005AB1BB48F085E85B31E0E07597F7E7FF08
+:10C89000E3741F7F8FA8776C7088298729DFC073A6
+:10C8A0006C3850CDE5B7F9D0FC5FAEA6B8B054E215
+:10C8B000741E138FAB79D649354FD4F2AC61CA17C9
+:10C8C00013F28EF45AD378FE30DDC8DE6C67220F87
+:10C8D0000EBC27F2E06AABB3A42B814F79B5827FFF
+:10C8E0006BA3028FD5F2DB4A2564CA413A543F6CF0
+:10C8F0008EA6A0BFAEEE9D6525BB5DDD5B98CAF13F
+:10C90000A5D6BD268DDE467C2F56CFD9777484D729
+:10C91000275E4BAA53B6D65AF9F887AAFCB4D602BA
+:10C920006F3794499BC90D4FFC4B87D9081F6FC1C6
+:10C93000F89FCEB73628CEABD5435AA2B287DE7366
+:10C940006668A497DAAAB6220FC70FDB477BC97FB8
+:10C95000FAAF5D397227C703AC32C557C9FB5EA871
+:10C960001338E26B149010BD1648219A57BD40E26F
+:10C97000FCCE6AB1F37C3CCB02E674EA370A7F5600
+:10C98000D530C9437D589EC9FD71D55139735D4578
+:10C990003CDFCF5AB07132D1E9DBEA441A6E306322
+:10C9A000AAE2213E7ED73A51C7B11356BAF73DC32A
+:10C9B000FA3A9156F719AF4EA4D569FD0D5FEAEA30
+:10C9C000CA7E69A49EF095EA0367789DD81F668E9B
+:10C9D000BCA278FDC83F306AE5F455EB4638DF4A23
+:10C9E000EB067A44FD681FBE9FDA30DE57C173BC88
+:10C9F00081F7A53682F7A5E7077BA6F336DAE3E4ED
+:10CA0000EDA19E79BCAD46B1C9CFA2BAD328AF3B48
+:10CA1000DD5BCB248A53B5BA855697A8CDF7B613FC
+:10CA20009D12EA16BC9F5CB730A78A7CD47FD4E203
+:10CA3000DC8DCFFDC76CDCCEBA226BA7515CF6D57E
+:10CA400071DF3407AF0364F3BC5293874B8AD39EE4
+:10CA500049F980D769A77A41F5E079ABCCED4EB4BE
+:10CA600000F2087F8A5929EF273A283C9E73D9891A
+:10CA7000AEDF8AEF87FF1FDFFF2EF8FE485C2FB97D
+:10CA8000FDA8F29A945DD41E55ECEB12EC439F572F
+:10CA9000E0C47DA5C55CFF76788B335B13F1FC06A3
+:10CAA00091C7652D28B5273EAFA917787E1603AF2D
+:10CAB000911D7BA3D6345E1CF846AD615C645C17A7
+:10CAC000E86B107644C3FDC7D6099C6F9726E0FD3E
+:10CAD00097DE4339C5BC75707F0AF7E75F1D48D9FB
+:10CAE0004DF1775543EBB409D8AF3A990245C21FCF
+:10CAF000E9EA0BCD0D26C59E61544F500A4C28B76C
+:10CB000063EA060D266EDF6FD40D1AA433BCAFC6E0
+:10CB1000E9F78CFE7A421123FA87829467BCD6C16A
+:10CB20009C8330B68E801B17C03CBC45C3095E5742
+:10CB3000767631A72C7F7B7D2147C5193AC399664C
+:10CB400092F396B700E8BBADB17586061EEF57C1EC
+:10CB500053C15AFA1EABD4E4207F968C17909C9058
+:10CB6000FF4FC60947547F34A2FABB87D5F8BE4AA7
+:10CB70008D4BB475C9FCAF53FDD378B8634D9D8818
+:10CB800027B63454F511FF028B4D407E604B83DB9A
+:10CB9000569AB09FB94E7C47B39DEA169312EB1696
+:10CBA000A23E915CAFD0EC54F5E0D7F5C4FF1D1167
+:10CBB0008127F9F304BE597DD07594F43E7E4E7101
+:10CBC000BF1DC8E3188FA39C9920EE0536817B71A9
+:10CBD0009CA16AF19787D2887E5EF45764978E9500
+:10CBE0006E4E277BB258AA6132C7BB6FE0DF844F1D
+:10CBF0002DFBA06D2190FF5F31FB38D17DC56A0B05
+:10CC0000FF0E49F357CB3E68AA17E3BB1E4BA5F1B5
+:10CC1000E9CC6997E979839B9E2F7A394A481F2C82
+:10CC2000A1D3A1DEC48E9D93485F664CF595D4E1F7
+:10CC300079AB1B551C7CB5F0AF2B228D16481FEB32
+:10CC4000EF0E177EC5F3E82B916A8E6F6753FDB523
+:10CC500022EE2FAA0FA01F9AF0A7F34375750E4E70
+:10CC6000CF5BD10FD179B21A459D3099FF6695FF00
+:10CC7000E3F995F1EC28F911D33CA1372C2FEE7F85
+:10CC800065CAAF6F8BFB614718FBB9DF807BABF6E2
+:10CC900029739C38EC21557EC7FD7E23FCFDE0E026
+:10CCA0000FD4FD99E0E06A9EA3E1E15A5EF49E4A4A
+:10CCB00067AD7D5F6D93F1320D27CB5500BABF0193
+:10CCC00027CB251C2D8BCC7605C7EDF2D533DCC0E8
+:10CCD000CDA259A6EBE5384FC5ED34FC2CE79E7E7E
+:10CCE000467146210436917D19B2826BEF24FA6EAB
+:10CCF0008FC126D2EF50238F73869EFB55EF2FE80E
+:10CD00007BC301E620F7D3D17F9CFBE90E8C6B78C7
+:10CD10003C14B92070AA7EF1BD694798294638E8CD
+:10CD20006F55FF5CAB00B71B1DEA777DF50342AF83
+:10CD3000E338D14352224EE4976393B5EF0543C2E3
+:10CD40003F197ED7D70923FC7BC0CE36E68CE2F3B1
+:10CD500064DC28192F7A4AFD0E705CDC48F96EDF1E
+:10CD6000FBEDAB9B30E933025355FCF99447D88572
+:10CD7000261F63B4BFCDE46DE7DFFD1E640EA3EF95
+:10CD8000478FA972BF48C56F5FB40A7978F17616EC
+:10CD9000A2786E11089CF6C5836B397EFB62157311
+:10CDA0009AE89E2A5EBB50A5C78C385EBB83F0DA3A
+:10CDB0001FA33B219C7691CA7F80107F4FE3CED486
+:10CDC00028C51B4F58FAF3481FB5EF8D1EAD13FE53
+:10CDD0002E3505BA8CF4335CE77AB48ECF1B37BF9F
+:10CDE0003C596710EF14D58A7D4FD7E9BF2F4A8889
+:10CDF000D3CFD0BA84389DF793E3F43F155EFBB7E9
+:10CE0000E3E3C555C6F1DA98797B6E12B77BD68815
+:10CE10001E9B55FC2499BE4ABD6687A73838EE781C
+:10CE2000E3FC20EAB92AEE35A4FAB920937F79070A
+:10CE3000AF7F5978FD4BB333C10962FF89F5C2EF6B
+:10CE400068ED4C75FFA0C518A7A951E7FD305FC973
+:10CE5000A8C779E52FE971B359FD7ADCECD6709655
+:10CE6000AE3F3B7A8B6E7EF5D162DD784D6CA66E5F
+:10CE7000FCB69355BAFEFCE1DB75F3EFF8DCADEBE5
+:10CE8000FFD5881E37BBF3AA1E37D3E4DB8512918A
+:10CE9000B8CE63FB996E5E419BFE5E855DFA7B4D6D
+:10CEA000EBD6DF4BDBB728A0BF5F49507FBF2CC25A
+:10CEB000F52BFE785C7F6FADACE2FA25765AB7BDF4
+:10CEC000A1D44E714C6EBE90576DDEFF0085A782D7
+:10CED000721032000000000000000000000000009E
+:10CEE0001F8B080000000000000BE3146060F85185
+:10CEF0000FC1D3F9191836F323F8F4C0C7981918DD
+:10CF00008E83302303C33E20DE0AC46B80F83D03CA
+:10CF100003C352203D07882703711710BF048AD529
+:10CF2000B1623787858D81810D884F02CD3AC54C1E
+:10CF3000BCFD8A7C08F6215E0686B5407C9497BECF
+:10CF40006130D8F00C41FAD9F50C6AD76ED181F76F
+:10CF50003708B38A3330304A20F8FD12A8F26CE269
+:10CF60000876960C65769501F50300295128158001
+:10CF700003000000000000001F8B080000000000FC
+:10CF8000000BED7D09785445B670DDEE7B7B49BA28
+:10CF90003B9D9095257480202A4BCB1201113B219B
+:10CFA00089010306440928D26C2184249D01661E50
+:10CFB0003EFDFF6E0842C4D1898A1AFC195F83E0E6
+:10CFC00004079DE0A0139DC0348B8833E804C70597
+:10CFD00097795F401E204212A338E8F3C9AB73AAC9
+:10CFE0006EBAEB763769B7FFF97FFF840F8ABA55BF
+:10CFF000F7D4A9B3D5A953754F149D9124DD40C82A
+:10D0000025F8A1E5AB0A2124255876489DC3E58182
+:10D01000C1F6B55E1771190979C06BC272BD379D33
+:10D02000B8AEA0CF47EB8AFC1642EEF7DAF1F9E38F
+:10D03000DE122C1FF59662F988D78DFD1EF29663DD
+:10D04000F92B6F0D96F77A8BB0BDCEBB0AEB372A62
+:10D050000BD2605C425CA6AC64423C2F0F1CB981D1
+:10D06000D6D6678E4F9047D3FA5FF5449F45DF1BB6
+:10D070002D17F987D206B9A4286B74B09F8AE78D63
+:10D080004A5E5F80F3F8581DEB67AA792D3B72BFAB
+:10D090002C3286E2395646FC89A564727672C47ECB
+:10D0A0008301DE2343D93C89DDF9DAA0C8F0AE065E
+:10D0B000780F0DE5F825DB270F8A0CCF09FD7EE5FB
+:10D0C000E4F0D23B0F0F8CDC6F0CF4AB7372787D05
+:10D0D0007DA60191C71D0FFD62E013C589105F8B0E
+:10D0E000D19F9DF5FDF9455CF42FC5A763AF79EBA2
+:10D0F0000609F9370DE8B4D6BEFCCC163A4E7BCB08
+:10D1000030A7DE41C8672E6782DD1213DF6E81799A
+:10D11000C4C0B752182706BECD8D916F0BA05F0C0F
+:10D120007C5B02FD62E05B658C7CFBD94F846FF712
+:10D13000021EDF836F1B62D4B75FC5C8B78D31F2A3
+:10D140006D538CFAF6648C7C7B2A946FEA73B5DCA1
+:10D150004124B48B372A253BA09F27B3CD3620EB43
+:10D1600027C1BF3DDF53EFF6C7C8BF5763E4DF11E8
+:10D17000A04F0CFC3B1A23FFDE89917F1FC4A877C8
+:10D180006DB8CE58E4AFDA8610FCB93400FEB5D8DD
+:10D190004F5DCDEB7AC03B89908C7039504BCA51B2
+:10D1A000940799B8DBD9BA55F0CDA51C425698E83A
+:10D1B0007FE9FBBE3C12D0D3F17D36E2AF9584FE11
+:10D1C0009F039E84E47F732955E8EFD345EC4F74A9
+:10D1D000D0FE30C815E5FF66EF102CEBB91C6D2EA4
+:10D1E000D2A13CF8920D285F4F789DD8DEE01D8BD0
+:10D1F000E5635C2E3772397A00E4EE0A90C3522E52
+:10D20000574CEE0829719453BA76EC89271B1C28D9
+:10D21000576609F09499BCDDBBE7CAAD1B28FCCD6D
+:10D2200035BA2BB785C8D91345AA7C51C94C0EF61F
+:10D230007BA2FC846DC150A4B70DE03414EBD47E06
+:10D24000BED07E0DEEEE7EBDA0DF63C55CBE641277
+:10D25000081DF7B1D2EE7EE912A5CBBD12296DB241
+:10D2600084F3658AC4F4942A0AF243E6F4DD9F77D6
+:10D2700096B4D1F76DF6916984964F827EA2FE39FD
+:10D28000B054DFAFA77476537A641A494D13E04B5C
+:10D290005A2585E22B8F7524821C3D34CE45242BE4
+:10D2A00021FDA19D8EDF67741BC9A265E2F83622BD
+:10D2B0000D837EB49DD653787BC650DA4EE13C0494
+:10D2C000EDD6607B2A6F4F73F0F7AF63ED0F7B09EC
+:10D2D0008EAFF6BB8FF2D94DF15B47F1C5E7C5C400
+:10D2E000057494293BFD21F39F2DE971DE95BC5413
+:10D2F000F1BF2FFB54C6FCA1417CCD832F66CC0F20
+:10D30000C1EFBEC173B0AEE263BEA212EBFD57F532
+:10D31000A69E18D707124EE7D49903847687EC446B
+:10D320003FCD71444F7C945F0E2A9E91F8F3051512
+:10D33000E71F54FF5C8C1EDAF6BB3574589721D278
+:10D34000C1D05BA4C3BADE221D0C7D2E4F8729926B
+:10D3500003E147A3873AEE862BC571E3AE12C7DD22
+:10D360007095386EDCD53FCCB8EBFB89E31A33C53A
+:10D3700071D7678AE31AFB7FBF7189ECA40F99B953
+:10D38000200EF8679E60DF2E10F7C3A0DF60E7F481
+:10D39000C9413B27DB4B88DB12E42791E9CB39A15C
+:10D3A00070EE14EC2A85F37F381CD7E5E1D8357090
+:10D3B000E66AE16CE37048A89D0E8343EED0CEE3AD
+:10D3C000B7FCBD802E647CBABE92126BE87B4ECD5A
+:10D3D000F8B76BC7DF0D760CE6A1BBECF80E0D5D60
+:10D3E000E768F1D9C3E110DDE5E841EC1A38B3B5DF
+:10D3F000700E713801E9B2704AB5F3785DE5AB247F
+:10D40000AC5F941EC382EF75E4759E423FE845C54C
+:10D41000B19DB64B7FB2066EA0FD8F6C91FC465A53
+:10D420000FEC8DC7F5E3FCB6E958DF778D11D7898E
+:10D43000F3CEC97E23B527935E78DB06F6A5EA0511
+:10D44000BD0C75DDDE8F6D6D142F8FB1F5C1EBE86E
+:10D45000F3CE17F4642B4A63A10EE87E8ACB2659DB
+:10D46000C5EA656656ADDAB2EF4E805BDE6C2466C7
+:10D470000AA7EAA525D3AEA3F5258715025DAAB6AE
+:10D48000AF36F4A6F5A57EA909EA1D79A41CF469B6
+:10D49000CDDEFF6C87F5E8FC6E251BC63F4BD70938
+:10D4A00007B5C747ACADA933291E15FE5D85F05EF3
+:10D4B000C54EC9492D1CC577FBA10CC07787E43444
+:10D4C000527A2F6B8C270ED5DED1BFA776EB71FE7B
+:10D4D000CBE9FC0985B784D417023DAB803830BE58
+:10D4E000D3E8374B417D3BEB3D8CE3A9F5AA1D7496
+:10D4F0003CFA7EF5739213A65AAD236EC0B3FD2598
+:10D5000073E9531698E76AC3602BCC6FBD01FA2DFF
+:10D51000F1CF7FD1EC003CB7180A01DFCD5B0C6581
+:10D5200043817E645EC950C0EF2F227E0D7A17CCF6
+:10D5300077F935C6AD7AE0A72530688635DCCE9E12
+:10D54000A5EB952364FDAC20CCEE13D96F983E2C4F
+:10D55000F8FC257D22CAC1B2463D7184DA0D2E1F2A
+:10D56000BEA384F9317BACFEED59413E2EB77379F1
+:10D57000E57C5C9EC8F92A77E6CC18168ECF83C06E
+:10D580001723F38FA07C98AE9B0EF47F1C48BFC777
+:10D59000A8FFE440FFC889CF9FA07E12949BA99F5B
+:10D5A00004E593D44F82D24FFD24E8B795FA495051
+:10D5B0006EA37E123C7F9AFAE7503652FF1C9E3FC4
+:10D5C00043FD7228777A7DF8FC396F1D964DDE7A1F
+:10D5D0002C9FF73660B9DBEBC77E2F7A1BB16CF658
+:10D5E00036E1F397BDCD58B6780358EE053ED332F9
+:10D5F000E06DC572BFF7189607BD6DF8DE21EF1913
+:10D600002C7FC9E96E9B4072652A2F3617B1039BA8
+:10D61000928A5DB9E0AF2495B07AEA1DBE5C03AD95
+:10D62000A7BA699DD2B1776520D748EBBD6B587B0F
+:10D63000E63D24CF44EB993ED63EE097AE3C33AD79
+:10D640000FA867ED8337FBF2E2687DB09FB55FB549
+:10D650003390174FEB5735B1F6E12D649285D6879D
+:10D6600007587DE411D7242BAD8F6C65F59C0F7D99
+:10D67000936CB49ED3C6DE1F7F2E302981D6C77728
+:10D68000B2F6895F937C3BAD4F2412D6F32CB9F9E7
+:10D6900089B49E6767F5C2BEF3654784F57DAFD256
+:10D6A000B6104CDACF7539B932F513F61ADA56805E
+:10D6B000C95DAFBB21571E47E9A79045D0BE49576A
+:10D6C000C4EA06B212DA7FAB9B8EF5FD8A03DBF764
+:10D6D000E8E6B0BAC181ED7FD52DC4FA41C585ED2C
+:10D6E000C77595AC6E7061FB67BA9FE37887143796
+:10D6F000B62BFAFFCDEA0637B63F2CAFCFCDA7FD4C
+:10D700002BF56E8F8ECA75ADE42E2703415E9BD23A
+:10D71000C11EAEE37EEB2C9D03E57E5D8601F56CBC
+:10D72000EF7FE53C857A063FC9502F7B1AFC5E0AE5
+:10D730006715C251281C7DCF70267E33568033F189
+:10D740009B7215CE6A84638E0DCEDE6FC68BF87C1D
+:10D7500053A1C2D9A0A3F6BED61ADBBC265E9A207E
+:10D76000E273A95285F308E293181B3E01E55A01C2
+:10D770004E4059A2C2D98C705262C3C7651827C0E7
+:10D78000711996AA70B6239C8CD8E0040CD789F83E
+:10D790001896A9709E43FAF48B6D5E2EE3F5223E37
+:10D7A000C62A15CE1F109FACD8E0ECB78AF4D96F0B
+:10D7B000EDA64F00E164C736AF3C9B489F3C5B370A
+:10D7C0007D5E433857C60667BF4DA4CF7E5B377D6D
+:10D7D000DE4438C3629B575E82489FBC846EFA7CED
+:10D7E0008070AE890D9F8329227D0EA674D3E72415
+:10D7F000C219131B3EF9A9227DF253BBE9731EE146
+:10D800008C8B0DCEC154913E0753BBE9F305C2B9D1
+:10D810003EB679E5A789F4C94FEBA6CF258493EBF3
+:10D820006E447C0885638D0EE7503F913E87FA7504
+:10D83000D3C7A407380514CEC09EE114668AF42924
+:10D84000CCECA64FA21EF462726C700E658AF4399D
+:10D8500094D94D9FDE88CFD4D8E655D85FA44F61C8
+:10D860007F461F8FB173921DFCC644E2DC4A5F996C
+:10D8700094FCB383B0EE2816E204B047A4C036800F
+:10D880004FD756F44B65A7EA073909F8B9C536876B
+:10D8900013E2017AD5DF21ADB81FB1EC4C14E24D93
+:10D8A0002FE9F38603BE56EA1586FA3D0963E304C1
+:10D8B0007F2BD19524D47B15F516FAA7940C10DA9A
+:10D8C000D34AAF12DA33DC23857A9FF2F142FF7E2E
+:10D8D000357942BDFFAA2942FF2CDF0CA13EB06E74
+:10D8E0008ED03FBB7E81D07E454385D07EA57FB95B
+:10D8F00050BFBAF15F85FEC39AD608ED239A370868
+:10D90000EDD7041E16EAA30E3F21F41FD3BA5568C3
+:10D91000BFF6D83342FBB8B6E785FA75675E16FAEC
+:10D920005FDFB95FA8DF70F1CF42FF5CF237A13E45
+:10D93000C9F481D0BFC0FE91D07E63FA271A3F564A
+:10D940008C5FD4E612E6CF6618D09F0D580D58377D
+:10D95000EC35B3FD0DD493210E518C75C3FE858E2D
+:10D960006488070000EA4FE4F62EBF02E255BF18B4
+:10D97000EFBE02E2B8BF30B847D823F841EDB2FBA2
+:10D980001E3DC6135B25920EA54307659C9EC713DB
+:10D990008C4C7ED767E53CE50BD183BA7ED4BFA023
+:10D9A000F5F57A8AC798A0FEACEF57963E3F649C87
+:10D9B00075FD0CA55B87B2E70B2D305EC97D309EEF
+:10D9C000C7D03918F0D28E631C305618C794598EC0
+:10D9D000E36C84715282E31833CB35E3984AB7F293
+:10D9E000E77C9CC7406FA28DB37EC078713E9915CD
+:10D9F00038CE16CD38EB332B34E3C4B1F9D0E77C05
+:10DA00009CA72E378E71E004713EFD2B719CE7B40C
+:10DA1000F3E95FA919C782E3C0731887F4A5BB981F
+:10DA200034CA67636719CAC19FCC182733F4A9F8B1
+:10DA30000DD4C90766920DE338E8B8B41F199244B3
+:10DA4000859A907FD127217FBE88A3FC0F89A705E7
+:10DA5000F7E33EDCD72FE628123FC588EE93AAB93C
+:10DA60006C2EDA393D73858396CD07063D02E36C53
+:10DA7000B43AB369BDBD7992616104795A5CAF9CD7
+:10DA80006A0B91F3EEFD591E195243C75F116747A8
+:10DA90007CD4BA5A26E9C4E727E8BE8BD0FDC987F3
+:10DAA000749F42E87EE52385ED33FF9DEECFA0DE37
+:10DAB00046F767D04EC86A7CEF048F339FF8A5E421
+:10DAC000077A7F71D7CF145C277CE4ADF4548826A5
+:10DAD000B09F79ABE2291382F8CDF7F512EAD41C96
+:10DAE000F7D1A5E3BE16E3079D2F19FD5B81AE7547
+:10DAF0007D284D79BF0184BCBB77EA21C986D53E1C
+:10DB0000BAB184CCAC995E90865A24F55B4EF19CF8
+:10DB1000B1FB1A85BE41DA95B63B9D96205CE25278
+:10DB20004E007D4CF40FC0B9A588D643C6BFB5449E
+:10DB3000ACCF2272B04EF97D523F80B0F83F1FD774
+:10DB4000E15280AF25748E1994D5B3A01C09CD2C59
+:10DB50005E536A67EFAAF878162A2480FB6B5F0A87
+:10DB6000C4B1892F19FBCD51F7C91AFC4A1593ABE3
+:10DB700084D2B574BE1EE9AAC5F7FDBDF12EDD70D5
+:10DB80005AD63DA24068B627FC67BBC57652CEC6C2
+:10DB900053E9AACACB29CEDF13C07F5A9E06FE5393
+:10DBA000BC4F72FE07E598F1DF63744F03FE776E9A
+:10DBB000D213E417E7FB6D9CEF8BEB45BEDF06E766
+:10DBC00071B4FF6D2BB358BCA9A197C05F3A719196
+:10DBD0000EF50F1550B31A86FFDFB91CCCA9DBF583
+:10DBE0000AB0F7F672CDFC381FEEE47C98ABA1C703
+:10DBF0006D9C6F7339DF9610DFBD1918BFF02B10C5
+:10DC0000D79B5D2E11B0179EBB55BEB5097C73AB7B
+:10DC10007CD3E07B27E7DB9D7731BE69F16EE37C47
+:10DC20006B6BF84C2103C2F1D6E2396F95665E3E0C
+:10DC30002DDFEAB95CDA0DE04F4D77E5AE3819D249
+:10DC4000FF96A2C92B4E86D8855B4BA60BF559A52E
+:10DC5000B385FEB3DDF385F6DBCB970AED736B7E00
+:10DC600026D4E7ADBA4BE83FDFB75A685F58779FD5
+:10DC7000D0BEB8FE21A1BEA46193D07FA97F8BD076
+:10DC8000BEAC7187D05ED5B44BA87B9A5F12FAEB1D
+:10DC9000F65E7933C8D791B7F504E27D179CA731BA
+:10DCA000CE78C1A938A1CF49AF03E5F8947708969B
+:10DCB00067BC4E94F3B3DEB15856834C8E033B7B66
+:10DCC000C002F1534F1CB5FB89741D97C7ADA99BCA
+:10DCD00000EB0D6D1F4FC8BFCA37ACF1F5A55A0058
+:10DCE000716F4AFFE20603098C2254BA7B77CB732B
+:10DCF000A73EA4BDAD87F60699047A85B717B74548
+:10DD00007EDE21750ECE80B8EC7B46B23D24DE1857
+:10DD10007EDE42FA805F11ADFD9C8E94879EF76C8B
+:10DD200095D939CF117DDE5699E2556960FA5FF9D0
+:10DD30007C461EB1413D30B8C67299F19A283269CD
+:10DD4000C0E78182DE2F69B83AA8E704C661F6749D
+:10DD5000A97F94F07C59E375C27B6F48EE2D80C794
+:10DD6000B97D7A5CAF49E040E62DC3003FD7561934
+:10DD7000D6D1E614F4BB5ABDAE15271542DEF41613
+:10DD800061F996B704CB77BCA5581EF3BAB17CDF16
+:10DD90005B8EE587DE1A2CFFDDBB0ACB36AF0FCBDF
+:10DDA00013DE3A2C4F7AEBB13CE56DC0F28CD78F85
+:10DDB000E5596F2396E7BC4D58B67B9BB154ED6790
+:10DDC0004FF27786AFAF67410E8DE1727670EDBC92
+:10DDD00035757D837276582E433953E95BDC60E4F8
+:10DDE000F2902AC8C35F611D4E0179E9A1BD41E1EE
+:10DDF0007218EDFDC8ED206FBD7F047923640DCA54
+:10DE00008105E4EE7BC81B8153841490A73E1A79E8
+:10DE100012E550952355CFDF904ACE817CA97265DB
+:10DE200091993FA4CAD5FDE02746F0B77A2B125F3F
+:10DE3000FF987F4402B93A20D9727E5E417C2EACB5
+:10DE400077F1B16B29B856E827FB87C03AD235E4A1
+:10DE5000ABC110DFEF3A4685202BFAFCB4F2129DDD
+:10DE6000EE2EDC3F94F929F37B85B79BE3185DCD5B
+:10DE70003A524446C2F972CE3137E567DC9FAE1E96
+:10DE800009FB66FA5C264900C7EF9C1EE1BC800CCA
+:10DE90002248E79EE8ABF63FF5C47FE6C0B9BF0570
+:10DEA000F49CCE3DEE80BE86E9EF53CE5B42CE972A
+:10DEB0003C46673AC4C13BB30D76E63F4C12E94895
+:10DEC00026E1F9814AC703D95F0C86F399FBA81CA8
+:10DED000827E750D1A9C402E231F3DD9FB9EE8B90A
+:10DEE00000E61B133D0D04CEB9283DB7C27DC758CF
+:10DEF000E9D9939DECC93E9ED8C0E87C84FBA7D1AC
+:10DF0000E8AC9E8769F1B84591391FB81C933B3442
+:10DF1000F42F15E8DFD7EAC0FE07F77E9009E7780F
+:10DF20005DBBAF48204343DF2F60E73DDDEFE70BEC
+:10DF30007A20FDE9EF99B03F3EF8C2BB58AE254CC0
+:10DF40000F375A4AE62A6382F062BD47106D5E1EA3
+:10DF50004512E7D5837E76A4AAFAD99A09F2B49B32
+:10DF6000DB81B0F9F5209FEAFC0EC0FC289CA920BB
+:10DF7000D3741EF972C95DC2FC46A7E0BC7B9A9FB0
+:10DF800027C140A411143FABC14012A83C2AEEB5F2
+:10DF90000AEEEB9C6D3E8853EC8D77D65296786CEA
+:10DFA00067DF0838E03D319EB1ACD15C23FA4F8980
+:10DFB00035A2FF945113EA3F751D7ECAE6A6F82DDF
+:10DFC0004FD7D79CEC05EB9C8BAF736C5D55F1ABD9
+:10DFD0006ACAAAB10870C47A57BD54C4EEE13812B7
+:10DFE000664638EF53CBE5E9061CE76CE3C004183E
+:10DFF000F7ACD754C3D6577B0D1B37BD26747DAD08
+:10E000005C155F73725410BF68707F68FCA8449001
+:10E010008F4CB02ED2B681D1FB47E5A7FCB901CF1A
+:10E02000D55B942FC07F370F51FD7719EB2A5C4FDA
+:10E0300093DE671C01CF770AE3D1F71CEAD938BC1D
+:10E04000175D6E64724AE5A71ECEBB08DF1F98906D
+:10E05000CF6E0A3181C2EB902D7520577E85E9B3D2
+:10E0600087CB6995A9CDE07620B95B41AE178C5579
+:10E07000E5DC31EB036AA73FFE8B82F7CCC8D714EF
+:10E080007A4EF0AAC322526283A0EA82DDCB8A6173
+:10E09000DDFEF8C59BF83EBD3E07E67D9EE88AC0E2
+:10E0A0002E9D276FDA4685E8EB6985C5B1481DDBF3
+:10E0B000E7F8E81F98DFE27A71DFB3A441AC9791EB
+:10E0C00019A9606FCB362AC44F715F0AFB2675DE33
+:10E0D000D4FEBEABD811B925A4661DECD31F53588E
+:10E0E000BC67819DC87DA8BDAEFAC3AF7320EED3D7
+:10E0F000AE307F573D0F5F9AC4F6831533FD061788
+:10E10000EDFFD1EE51B7518B4BDFF7AF43FF673ACD
+:10E11000716E27E1745F5827E2D713FE5A7C553F92
+:10E1200028EC5C9EE391DC2845BC2FF535B773AA3B
+:10E130007E2419EC42DC274D5357E540E172E0574D
+:10E14000DC56430AE33BF051923B0DEE907E866035
+:10E15000BF24C398E8FD8CD04F8FFDD258BFCE426C
+:10E16000DC1F132A4F4383FDCC41787DD9B862BFB1
+:10E17000AA3F3CFBA28FCA4BC5EF1EB511BA6E7EFB
+:10E180002CD7A73AE9F3CAEDF7DA5CB43C23FB6C71
+:10E19000C0CF8FFDFA88F77D6F31A8F470592488BD
+:10E1A000A771F924753E8C537CB15DB1E33942A36C
+:10E1B0003160A4F259BD7B6931198EF5E3ACBEFE26
+:10E1C000533DD49B457E55FCE6D15407BB27C4E2A2
+:10E1D0004924807E6EF5B6FF2884F5C2433A51CEBD
+:10E1E000B4EFC1F8179350AFE71B12C2DBF16270B6
+:10E1F0002ABCCF7E3CBBEFFF546F8372F269D02301
+:10E200008F464ECAB9DF0AF482FD7EBEC19A8CF6F3
+:10E21000FE5A722DE8BB4A17E267FE6BED8EC78788
+:10E220001FA7789DDBF6179B3434D44E3079EB6A08
+:10E230005AF86F265D747BD24EE531D44FA280F13F
+:10E240003D4733F7BB5B5859A9046C701FA7728B0D
+:10E25000E2A492482A9FD513B89F40DE33FA213EAC
+:10E26000BAECD957DE194FE9BF6C97925CCCA66324
+:10E27000915283FCF1D0BFAB4606F951F1FB570C2C
+:10E280008E61ECF93D4941BE2CDBB5CF408685D38C
+:10E290007152D33E439B25027F9A8E17C27A5BBB95
+:10E2A000E31F06882B7EBC57226959E1EF976F79EF
+:10E2B00005D73DA013F293F3AB9B7F617C0B4C7BA6
+:10E2C0007934F6B3833DEC896FD9B09F4B41F97E29
+:10E2D000EE65B8C7F4BED10974287F6E850DE6736C
+:10E2E0005AAE6172FEEB7B5341DFCB155FAA1D4B2B
+:10E2F000F6BCFCC99FA3FC2D39FAF354F41F882BFC
+:10E300004387B6D99701F35CBCF9569C671971A392
+:10E310001C96FF5A5F02F74C2FC8A46857043DF9BA
+:10E320008B81ED5F4E6FA5CCA5F33C0DF8817D7B15
+:10E3300053EFDF8E71F39FE13DB89FF339D3951012
+:10E34000EB174C8C5F5B0C3A351E6A12E477DBFAF4
+:10E3500056E0D3D97EAE3438F7A074F071BA49973D
+:10E36000285CFDD18234C627E29073F87BD4DE4F5F
+:10E3700082E7D0BF557199870BEF71FBC8C65FC9A3
+:10E38000C7A778C7C1FA753A35B2FFF70F3E3FFA13
+:10E39000D34A42E42C44DF99FE6FBB8FE9BBAAFF4E
+:10E3A000FEE945D0FEF95B4C8FE03D582F285E8199
+:10E3B000346CDF375342FB40F7D991F47C9BC2F5B4
+:10E3C0005C6CA73B1C5CFF5539A1F8CB5242A8BC42
+:10E3D000D07192900FB83F2EDB48DF0FF1CB3C306D
+:10E3E0002EF633049F87AC1B4BB85D38A4B107648D
+:10E3F000734A4C7E74A5E27FFA09D0DFF78C4E9FFA
+:10E4000003F4572981F97FB2F3C03B73A89C7FD2F4
+:10E41000A4EAAD6857B57A5BFEFC1812496F3FB1AC
+:10E42000D07D5724BDA5CF23EAADA50DE5F9FF9614
+:10E430005D55E9D7AEA11FD8C7971DD1E9A8B58F03
+:10E440001B0C8E88F691FEBC4572C2E550953F5577
+:10E45000EE2A7E5BD51FEC50B77CAAF2D72D9FAA7F
+:10E46000FC69E72BD24FDBFE07D06F8AD7EDA64DB4
+:10E47000D3C07F3675128CC3E7CED4E33D4DD3E7CE
+:10E4800084DDD3B8231EEBB3F46DBF079FF083AADE
+:10E4900059C3609DBF9DF814766E5FAFA01FFBF55A
+:10E4A000A54B13E87CE670FADE4EC93D95F2A35405
+:10E4B00096027114CFD932F12524413C59222742CA
+:10E4C000F0B8BD5CACC3CFC4D4209C9EFA7F5BBFC8
+:10E4D000FBBB9647295F4F6413F2372871FF411D3C
+:10E4E000EB10799ADEC2CE313CA325FF00D4C336AF
+:10E4F000B924641FE13132FB7334FF963140BFDC35
+:10E5000059C312989C0FC6FDA287DBB12E9F230131
+:10E51000EC7B57CB40DC17761D5E687547B067070C
+:10E52000B89CBDC2CF613A2C52BD9ECA7D07E9445A
+:10E53000BFC66731478CCBCD31AA769AF38DFEE802
+:10E54000E9F8A55C0E67D357134686F06DE6D48FC5
+:10E55000655B381FE0E744C8BEE2FBD217E41AE867
+:10E560007BC0DC565812217E53C9E93771FF9706EC
+:10E5700058F7F25B7265A063BE452FC4431619B904
+:10E58000BE0E254301AF89FB973E3086CAB1E7B086
+:10E59000DE69A6F3F3B47C6A7047D8DF69E909F055
+:10E5A000C1BFDC6A64FEF2DB4AC962A0EBDBB7B232
+:10E5B000F3DEBF199C5591F04C37337F733629B980
+:10E5C000305AFAE9D1377796359047E9D16561F746
+:10E5D000B5C3E58FE97D975DF2AF96400EF5AC9E31
+:10E5E000CCEE371712F7031324D4F71B42ED576E06
+:10E5F000F3F467E13E4D758B64D7D1F66AB9CD006F
+:10E6000072EC69DE2583DF7E9383B8707F2DD70C93
+:10E610009B1912FFA2CB1ED2EBC05773E6027D3FBF
+:10E620009B692480976BE8A73658FF3F6B19857A62
+:10E63000106D5EAF7BC9B47C05E0307BA69587C2C8
+:10E64000E478A17EEB24D217CE81271ADB5638233B
+:10E65000F02FDFC4E42C66FB66FAFFCCBE4DA0F6BB
+:10E660008DC9B5126ADF2CA630FB9616C9BE2D5F88
+:10E67000ED4803B958BE67207EBFB5FCB5C52991EA
+:10E68000ECDBAB7CDFFB1ABF07DED197DAB71121D9
+:10E69000F6AD2FB56F11E2E45FC46ADF4CFF33FAC9
+:10E6A000F72AD8B708F3359B44FB56D4B21AED5B72
+:10E6B000515FBD705F8998A87D8BBF9C7D9BFFE8F3
+:10E6C000AD58579CF111E407E80AF6ED356EE760A6
+:10E6D0001CB0733798587C33563BD72F563BF73FC7
+:10E6E0004467D5CE2DEF27A1FF122E87CCCE2DCF9C
+:10E6F00062766EF91E66E79667333BA7B56F796160
+:10E70000F68DBD5F3D84BE8FFBC7ACC7EF80FB8439
+:10E71000A58AD344FB173BD4EF276AC684DABB1B18
+:10E720004C32D239CCDE393FC5EF607AB2777F0503
+:10E730007B978D766C10E891563EA60C8A17EEB347
+:10E74000BDFDE5A9DFFE0EF4E5753DDE177A57C77E
+:10E75000F6477BBF3C350AF4EE2113B3BF4B4C8C1C
+:10E760009FED5E1FDAD3494399BE57DDC3E857BD1D
+:10E770005B62F35DA9F73B601DF8EA22EE9FE7EECE
+:10E7800061FBE759C6D69478B897F42F0A61DF7D0C
+:10E7900090E2F921F2507AB102E380CFC7D9B6C234
+:10E7A000FEB2542626F063E71D9EF231F8AFF32E39
+:10E7B000D6A1DF3B0F9EC33909BF27A1DEA398D3A3
+:10E7C000BCEB953E24FC7EC44423E3C3C415927F76
+:10E7D0004B16DC4710DBE769FCFA757C9ED49F453D
+:10E7E000BA90BFEA23C6EFD669E9E164F3AF5AA94C
+:10E7F00017E9512345A407E568F1FCD4E0FCE7BE26
+:10E80000D0B6AE0FB42F95703FA5D2433B4F953E87
+:10E81000EA7E651ED7114FCB2E05F8A59DBF4ABFD6
+:10E82000B079ABF4D4CCBF4EB51F579361A06FEF56
+:10E83000EADC0F8C01F9F833A503C5EBB6D9D96929
+:10E84000A1F6F8416E97A6BA8FE7A73A806EECBBA7
+:10E85000C439E5BB5E49A5F3B9D9953512BE1FBED3
+:10E86000F52B831BE20B07CC9D68DF54F9FA84CBB0
+:10E870007B80C379BBB73D1FD79166C98E7A13D011
+:10E88000D82F7E7FCC730FD3AB03D23FD6F5198D33
+:10E890007485658014AAEB10F081FE776A0BE38320
+:10E8A00007F840FF3B8D741E023A57274BCE00F409
+:10E8B0006FDE752FC8CDAB66FA1CF4B75C72B2EF91
+:10E8C000CB882523F5B2F22947924F0C4EE404D7AA
+:10E8D000C579D02F29DCEF98686C7D1BF09848F53E
+:10E8E000610B09F74354BE0FA17F2E45BAF7D383BE
+:10E8F0001C7FCCE5F355A0B705E8DA69007FC613A5
+:10E9000060EB87DAEE911DF9481F95DECD747D1816
+:10E91000CDE8AD8B40CF9BD53AA7A7A74552E0FDE8
+:10E92000C974FFDA4B82D3AD2F0FA9720CDFC36914
+:10E93000E901F1808C10BD07FB147A3E59DD7C148F
+:10E94000E932652575AF42E80E76EB72F489A617B9
+:10E95000D5CD3F8C5E7CA2D18BBDE6CEBF8C80F83E
+:10E96000D71E09ED03694914F6FBF166E6671C3012
+:10E97000BB517E3B5F53F0FEB9D68E7CCDE51EF6D3
+:10E9800017A1DFFD4D8289809DB39BC9472A1E03D5
+:10E99000981C85DAEF57CD6EE45734F8717C1D8EE4
+:10E9A000E63FA9F51B613CB88FE810C70BF32F7841
+:10E9B000FCA7A779A5F171BFEBBCBACF3349AB81F6
+:10E9C000B0F8FF0A63C8B9D46DFC5CA03B4E16ECEE
+:10E9D00067375DA61FC45F0274DEAFEE7C0AE3BF3B
+:10E9E000E79F393E0DE477D91FF5C444F9DCBED367
+:10E9F0004A02ECDE8501D6D98ADDFA88E72884D47C
+:10EA0000B2EF1C7F6745FB52F1BCD15F4CDFAF78A2
+:10EA1000F1A3E110B76A5FC3EC8CEF192E1FBEB6ED
+:10EA2000E170BE5E21B373612DBCEBB8BC9C7B2949
+:10EA3000BE14ECA4D4C8BE5FAD689AA51843F6E92D
+:10EA400023CD0A8E4BFBE1BD65DF0E09E3E5E1F85E
+:10EA5000AD66F07630FB57D1ACF8E13BD88AC62DD5
+:10EA6000B8BFF5347E6A00BF6ED2EF9E65DFD73641
+:10EA7000EBC5F861A33E60C438A7FEB87138D35B1C
+:10EA800049884755A15E5637F13899267EB4EC7710
+:10EA90007B5EF451D22CFBFD6F6C606FCEB66EB70F
+:10EAA000617CAE91C5DF648B1C393ED7535CAEE907
+:10EAB0003E1E979B7A9A0C0F8FCB9D85FF503D9CF5
+:10EAC0006FE6FAAAC6351B7BC5747EBEECD90B4F28
+:10EAD000C279D2B9E73F7912F0AFFCE6B327EF86EF
+:10EAE0007389BD663BAC7F9E67DEC6F8BBFADEDD90
+:10EAF0005CCEDB77FCE6E927A81EB6BF67C47B5B6C
+:10EB0000ED7B4E67C2F78CEDBBBE4C85F8E6CA3D87
+:10EB100005B89F59F9C2A4B4CBDD3F01F9F4C77021
+:10EB20007EA2E5C781DD7A02DF739E3F6644FFA3C4
+:10EB30003BCEDA54C5E2D70E1E5FDD19F9BC4A8D13
+:10EB40000756EFBEE5E6EB611DDCAD381DF89CC74E
+:10EB5000077B8AABBE45F93A2206FEEDE4F1F3A647
+:10EB6000A911E3AAE7E13F944F9BCC625CF5C2EEAA
+:10EB7000C5FFF604B4EDEE1535AE1A88816EEA795C
+:10EB80005899D9B5CD0CFAF1FC6F318E0D7CA33EAE
+:10EB900039697FF64226C423CE289D77E23DE53DC4
+:10EBA00046BC6754B1E75DD497F6178EE23913E19E
+:10EBB000E751EDA4FB879D1BF0BD8E679B95C56358
+:10EBC00039FD215EEBB0E1731E976572ACC66BA395
+:10EBD000C569DF37B3FB50EAF95CD5B60F0C4413B7
+:10EBE000FF96C602BF8E0BE78AEABCB5F0EC408701
+:10EBF0006B43CF1FA2C5C3B95D0DE3173B7768DF39
+:10EC0000C2CF23BACF1908E93B12CEC7D9B9B9C7C9
+:10EC10002FBD1B89BFEAF9C3DB5AFDF4C776EED0DE
+:10EC200033DEDF8D2EAF9AD9FE56A5CFB9AF23DBE9
+:10EC3000E94EAEEF749DE930E3B9315B67E6F175FB
+:10EC4000A69AD28D7DF7C6F03DC7F781E79ED1FB2E
+:10EC500061BFBCAEE900DA5BAD9E571316FFD28EE2
+:10EC600027C531FFA0BA79DF70B047E7F6BF84F25D
+:10EC700057BDF3B8C147E11C6AFCBDA16D6850DE09
+:10EC8000C18EFB43ECF8B9E7F60D67E72291F3B4C8
+:10EC9000D8387C4F8B08DFB3F35301FE325F93C14A
+:10ECA0006EE9799CB3B26B16CCF76CAB42E03EFBDD
+:10ECB000D9267D913FC2B89FC13A362648A77556DE
+:10ECC000F61D9F3EC9807EE64AEBD863F0FDF84A08
+:10ECD000ABC101FBEDDAD5EC5E65EDFF72A6035F1B
+:10ECE0006A136FC373A37A0D1DEDC9F65CD887DB79
+:10ECF000F34B46835869ED41A24B27E0BDD25A94AD
+:10ED0000E6B0405E2FE6A710D989DF19EA6D854588
+:10ED1000300FBD5D6737475C5F193CC5C2F266289E
+:10ED200076F1BBBFEF900783403E8E6F9D07A353E4
+:10ED30009307A3FCC6FFD7F260F8609C9F401E8C2F
+:10ED400000C677D43C18C93F721E0C882F8D0EC99F
+:10ED500083D1A9C983C1F9F8CF3C18FFCC8301A5A1
+:10ED60009A07E39D0D650590A742CD83716683A741
+:10ED700000F252A87930BEDAB08AD5791E0CCBFDEC
+:10ED8000AB0B42F36064DEBF01DBD53C18CEFB1F4A
+:10ED90002908CD839177FFE682D03C1833EFDF5E00
+:10EDA000109A07A3ECFEE70A843C186BFF50007929
+:10EDB000305E8F77B7C6A544CF83D11CE788290F73
+:10EDC0000685F31EC2899207430B275A1E0C0AE7D9
+:10EDD00044DC98E87930C2F089920783C2F904E1F3
+:10EDE00044C98311864F943C1814CEE738AF287974
+:10EDF00030B470A2E5C1A070FE0BE144C983A185C7
+:10EE0000132D0F068563884F899E07230C9F287951
+:10EE100030289C048413250F46183E51F260503868
+:10EE2000E908274A1E0C2D9C687930289C2C8413F5
+:10EE3000250F86164EB43C1814CE55F163A2E7C1D7
+:10EE400008C3274A1E0C0A6714E213250F46183E12
+:10EE500051F260503813104E943C185A38D1F26079
+:10EE600050380538AF287930B470A2E5C1A070A63B
+:10EE7000213E51F26084E113250F0685330BF189A1
+:10EE80009207230C9F287930281C37E213250F8620
+:10EE9000164EB43C1814CE528413250F86164EB469
+:10EEA0003C1814CE728413250F46183E51F2605060
+:10EEB0003877239C287930C2F0F9AE7930CC814183
+:10EEC000D240CC8381F938BBF360247FEB3C18BF80
+:10EED000027CFF9907E39F79307E8C3C18B75ADD9E
+:10EEE0007F8FC77DE377CB8371265E9337A2873C04
+:10EEF00018B75A4BCE823C7FDB3C1817E2BF5D1E31
+:10EF00000C3ACE3F2E374EB43C183ACBB7CB8341A8
+:10EF1000C7912D632E339F287930122C62FE901FEB
+:10EF20002B0FC6B1F8249C4FB43C183FB97C137426
+:10EF30009B05FBB4E9288AE427937F62B485C70D5B
+:10EF40007FA8FC1330E99C9F52FE09358F41930244
+:10EF5000EBE1FB9CEFEF70B9F880E7A13816350FB5
+:10EF6000857F2AC677978A7928A6703ECE768BF25F
+:10EF70003085B0739429F959FE5AD8AF976BF25087
+:10EF80000C11CFE98BDD47F3293832D529CEE328A0
+:10EF9000978769A59F1E04F6DC3C36721E8A199C71
+:10EFA0001FD3357499C2F9369D97B7C3A739549EBC
+:10EFB0008BCB8FCA40D7698E3619E3F437A9FC731F
+:10EFC00008FC9BC9E16AF19DC1F9376332E39F16E2
+:10EFD000EFB7807F14EFB7CA4721FFB4786BF1D445
+:10EFE000F29F84F23B247F482E11F34F4C3289F973
+:10EFF000270AEC62FE891BD3C5FC13931D62FE89B0
+:10F000009B8688F927A63AC5FC13378F15F34F4C1A
+:10F0100077ADD6E4BFB84F93FFE2214DFE8B4D9AFA
+:10F02000FC175B34F92F7668F25FECD2E4BF7849C5
+:10F0300093FF629F505F58F79AD07F71FD51A1BE38
+:10F04000A4E13DA1FF52FF71A17D59E3C7427B5569
+:10F05000D3A742DDD3FCA5D0BFA7FC036FF1EFA17E
+:10F06000DFE1DF431FE3DF43BFDF43FE8B772C4B42
+:10F07000D785E6BF78DFE2590779098E5B1C3CAF84
+:10F0800040E4FC16DDED51F25F04DFFFF6F92F528C
+:10F09000927FF87C043A2BFB1EB0B7254F674DF9E1
+:10F0A000EEF9086E2D11BFEB9E552A7ED7ADB3B297
+:10F0B000EFB567BBC5EFBB6F2F17BFEF1E11E7960C
+:10F0C000000F6DFE8BDE1697CE0AF692E72908C078
+:10F0D00077BAD9106F2BC2F220E4BFC886785B29BB
+:10F0E000968721FF052DFF0CF92F687904F25FD078
+:10F0F000F20DC87F910DF9337C3C7F461DCF9F51A7
+:10F10000CFF36734F0FC197E9E3FA391E7CF68E20E
+:10F11000F9339A79FE8C00C239E13D8CE5496F2BB9
+:10F1200096A7BCC7B03CE36DC3F2ACF70C96E7BC46
+:10F130009D58B67B2F62196BFE0C552E3F04BFE124
+:10F140000A189FC9B32AA7573FF0C8BAD0FC1923A1
+:10F150001ED884721A2D6F460E7CD397123D6F46CF
+:10F16000777B94BC19C1F7A3E7CD481BFDE3E5CD40
+:10F17000986BF961F266CCAD11F33ACC5B75F9BCD2
+:10F180001923E24A6E41F9E3F238D7125BDE0C9F95
+:10F1900055E2DFE553BA80DF45E982EB750F790769
+:10F1A0000E5A9F1E02FB89AE21575D36DF83562E15
+:10F1B000A2D39BE57798F323E7CBE889AE6AFFF704
+:10F1C0002B581E87B9966F992FA3877C0B07B3BF67
+:10F1D000403B196BBE8C9ED6879EE839E347CE979D
+:10F1E000D1935DEDC99EBE3985D1B9770F7456BFF5
+:10F1F00097AE34B51EC297ED2E546D997F0F9F3B8D
+:10F20000D38EF1998E9DFC5E9C8B38ECA9EC7B7DB6
+:10F21000F0373B9E4F184EF03B7E3B7151FEC4F3DE
+:10F22000E7D2CE7DFBE05EC05A1B71252681B34735
+:10F230001CFA81B00FBBC604F19AAADD9FBEF1474C
+:10F240000AD7DCA2C7FB721D148756F4FB5C89C089
+:10F25000B778F24BDCA7C319DDA55EA1DF756B7E25
+:10F260000F0774490D9E3F15E82DB86FEADACCEE12
+:10F27000B3EAC9D58F4F188DF7C689DF81FC433FAC
+:10F280007519C7B38B106700FAEFB4E2FDD525AF4F
+:10F290002D34C0A070DE1A1A37E85524C6811ACC66
+:10F2A000B6E1706F2F5DBDBFE773B5821FBE88C327
+:10F2B0004D2911E3449F2C283A0CFEF3227719DEE6
+:10F2C000AB482B15E346847F470FDB32F03365C232
+:10F2D000EF75FAD97DCFB0EFEA9BB7209E4BFD9A30
+:10F2E000FB4B8D625DA5DB392BBF9762219698E8B9
+:10F2F000D676C5E31392BF3DDD8CE922DDCC0E91BD
+:10F300006EF14344BA68E966758A74D1D22D61AC56
+:10F31000185F53E9A6DEA7FCA1E89664E3F73C82F8
+:10F32000F42A31A5A2C9473C33E400CAB7561FFAF4
+:10F330005802F01B7E48BF64FF6A7CCB6995C16EA2
+:10F34000A533D0445AC4DE8B077D80FCBDC489FA46
+:10F35000A0FE3E8A78F22197FB8FC8255AAE987E90
+:10F36000F0F802DABA19E46D04FB3D1A18AF4A222C
+:10F37000B89F5388D30EFBA826AFC9B94881734DF7
+:10F38000E25C940DE799762C1FE4DF3B770C25B8FF
+:10F39000EF6F0A7C9E0AF7061E1CD9390DE20F9EFC
+:10F3A000C5A404D6AF59096C7D5DC64B5B028BCFFB
+:10F3B0006C28D111D768F87D4A7ABF44C76BB7BBB8
+:10F3C0005EBB01FCD116763F80D83BDFB81DDB4722
+:10F3D000E1F7E119BAFA6B001FDA1FBF2BEE68F9EB
+:10F3E000C8B630C40EB7373F7225DC6BDDA48BFC8A
+:10F3F0003D73818DFFFE1D7E3F654430DF42816D90
+:10F400000CE6657870001DA77A7A17F25195CBEB60
+:10F4100038FD0F964D41FC5E68911C10AF2BD4DF78
+:10F4200071D3308ADFB8B7657EAF97DD5F1FCDFB44
+:10F43000D79AA9FEA2FDAAFF1BFC9E95974ECA98DB
+:10F440000F71744D19DE13FCA3ADF030F02BC7D54E
+:10F45000340AE429BF2511CF713D1F12277E9AD5AA
+:10F460002ADE07CCE1F7B673DA881F84E2DA63623A
+:10F47000FBB836B17E9D66FF39DFC6F5D4465241F2
+:10F48000EE367EAD9760FDE8E824CE3514DF8E457C
+:10F49000BD71FC8ECF09FA891D5FEB8B22DD8F5980
+:10F4A0006E63FCDB642068BF379559F0DEF9FEB26D
+:10F4B0008AFEE05F7C7197BB7FA43865889F96C009
+:10F4C000BEBB772590B120876B2546EFFA8C92085A
+:10F4D000EB962A77AA1CAAF2975116E78E740FF5BD
+:10F4E000339B8472965736443280FCEC9530FCD5C1
+:10F4F000BE86E2759975DB47D6F4017C3CCD9FE171
+:10F500007D32538BE48A744FE7619B8DDD6F5CE342
+:10F510005B0DF7467E419508EC5486A13E2B127C8C
+:10F520001FD9887EE95D36077BCFC4F320C9F51962
+:10F53000709FA2BD79D2E47514CF27A83EC07AB5DA
+:10F54000497122DEBE2A42F09E2C8FD7F59D46B629
+:10F550006C08F17F37DB721B6D145EA38D7D6FD954
+:10F56000CBED94006FE77FFDC306F03B2E1A917F31
+:10F57000BDB9BFA9BE7780D3675C826B2BBC4FE05F
+:10F58000979F51E3E374DB9C8B46415C9ED23BC466
+:10F590000E06F9E663F951DC04CF3F922C3A94430E
+:10F5A000E27239ECC27D761FEA8DAA07242011C8C9
+:10F5B00053A0DA37A9450A58A9DC8F365902708F53
+:10F5C0002EA99CCE3B19F29A9818BC56F99C18D7D4
+:10F5D000A2F29803CE3DC1ABF3104805F8AADD5363
+:10F5E000EDE5DA44668FD63E24635ED4CD729B1976
+:10F5F000E2A9592E471EA4884C921D78AFA65F3908
+:10F6000071520C49FCC05F2776FB0154C9AFF94623
+:10F610003F2FD2775B176DCCDF1E97E0FE33D06BA8
+:10F62000F8E1CEFDE02E38CDA417BBFFC5ED04F701
+:10F630006B0AF97A37EE3F74EC7BD1C00D24F43BB2
+:10F640002AAD9DD86466EBFCB8EBD9BA37EEBC05A1
+:10F65000D7BD6E3B515688EBD4C8965107E09EC586
+:10F66000C80F997E126E1FECF40FD029E7B04F0F30
+:10F67000F4F9B67641CB6F123075D787EAE01C8675
+:10F68000EA5BC8FB67357664C5F441B5185EE6727F
+:10F69000D4FF1EA7DE1D4247EDFBDD714AC9D4FD34
+:10F6A000DC3110ECC8113DDC0BE9C8A5F3A3F3DF96
+:10F6B000C8F525F173FF6498D7C6961BCD20DF6B84
+:10F6C0000379F662FA4EA2A9049997485C18CF19FB
+:10F6D000493D32C88F518B4241FD41A58424A4C0CD
+:10F6E0003DB42221DE432C493CFF4B00F9D22DA72B
+:10F6F000548E43EFE5AAF2A99547557E6BE1A0052C
+:10F70000CE0721624E4BBDD484878146B2D90EEB21
+:10F71000BBEA5FD6727FAED69CE9C7EF977C19E84B
+:10F720001FADE4FE51ADA5D084E6605F32AEEB2B99
+:10F73000217E42E9B03285D979753E5AB9F45CD45C
+:10F74000137FC83EC12377E27D44CF45033E5FA7C8
+:10F75000B807C0FC55FA5CC3E9A3A58794C0F79D20
+:10F760009C2E3DE39B63877BC1892617598FF8E662
+:10F77000E13DEEA6C04813ACBFF76AF08D01CF6B38
+:10F7800013C684E3295BA2E099CCF0BC8EB8FFD805
+:10F7900046E53767455D6D3CEA15792B3D275CAF43
+:10F7A000B47AA4EA8D1AE7BDB6B2FE005EBBED41A5
+:10F7B0006F3CF18C2E4EA504EF5739F7C4A31DD131
+:10F7C000EAD3E77CFE9E7846BF058A7B06CCCFA3B2
+:10F7D000EBCC043919EE20BD8A2992C39BF5A8E72A
+:10F7E000A435B67BF8AA7FA5FA55DA7EAA5FA5DA1A
+:10F7F00063F51EFCDA04F77C9003A999CA2DC5A70E
+:10F80000D6CEF64B9B6DEE4580573CC53D0EF68D32
+:10F81000430259ECFB5F512FA2E941BC46CE9B024B
+:10F8200032AE0B3EBA2E644BE178A8E30F4A48642F
+:10F830007CA45A0EEB7DDF1CC206AB269837A7EFDF
+:10F8400070E28675ABEF48769F714D02B3BFB50984
+:10F850006CDD52CBCDB692BB51BF65E2338EFCEE70
+:10F860007803AA70DF7C6D82EB2EA087A9C885F390
+:10F87000E863274EF04BFBC84D127C379A54E99051
+:10F88000D83D7312FC7E8BC2EB53ECC8057DED03B3
+:10F89000FB6BE8DF1239CFD8A309EAFD5EE67F3AB9
+:10F8A00049771EAF471398FF7908529FF42A56F301
+:10F8B00082A9E7394E09E8D46EBD0D916EBF2031A3
+:10F8C0003F3D91D14BBB4F00C287FEFEBD7B0D4437
+:10F8D000362791E0EF59D599D0BF8F27CE26B05764
+:10F8E000BB1206F0734C671DD47F25779A128706EA
+:10F8F000E55D95E30727CC70422A52DBF55DC361D5
+:10F900004F45E57A27D0BF7D42D760CC41493A3395
+:10F9100099FCB8F442BE20950FCD8AC00733ECC3E2
+:10F9200043EDA4D53004FCD17629CE09F72CDA9723
+:10F930004A0C5FC9C4F329C9C23CD3E3997FDDC136
+:10F94000EDD53B09592827AA3DA6F3AB83523B0FBF
+:10F950008F11EF7490CE3DF1FEAD706EA5C93FA939
+:10F96000CD4F3969A105EF7F6CDC63C6FD6B57098C
+:10F970003BC7EF6A31A27D8EA6B7696DE688711C20
+:10F98000B5A4F47B0BE897A6D424823D4C9B7BD294
+:10F99000067CD7D2A543F25D7308F645AF2B11BFA5
+:10F9A000BB55CBF4F49B1217D1FEE91993B1549FC8
+:10F9B0003758E488F7CD4F73BD52E5F14A3A22DF5C
+:10F9C0000F9D06793CEF7EF31D1709DEDF6F88631C
+:10F9D000746C886374EC728F4F781AE4CD9781FA57
+:10F9E000B0583D07E5FB7F35CF943ADE46AF29514D
+:10F9F000A62AD0B0608A19D68914E29A3C1B947565
+:10FA0000A342E03BA2C7BC3B12F3318E6D12EFF96B
+:10FA1000DAD9BDE1CF3716E077DEA9648D7930A55C
+:10FA2000475989CE09F183F30BDEB7E9A83C2DE8ED
+:10FA3000D39A03F2FBBAE226F63118EAC2FDC99264
+:10FA400052833F40F996DC400D05A5CB7F03F9D4E6
+:10FA500012800080000000001F8B080000000000E2
+:10FA6000000BB57D0B7854D5B5F03E73CE3C929922
+:10FA70002433794E1EC009E19D108724BC1F4E9E81
+:10FA8000448830BC0485EA8028CF2488D6DFB6DEDF
+:10FA9000CBC444F4A2B745E9AFF4D6DB7FB0A2A84B
+:10FAA000200182069AA41340E4113408A8A8AD519D
+:10FAB00029620BC908EAC5D67BFDD75A7B9FCCCCFF
+:10FAC0004922D8DE4E3EBFED3E8FBDD75EEFB5F684
+:10FAD000DA872EC977134B64CCB7D8C0B64A8C7D71
+:10FAE00087BF1B43ADD96E602C89B196383BB54EAC
+:10FAF000E70CC7D284F07E8563693E63D5D6D85CB7
+:10FB000016876D7F3F8B85F18A58EAD202685BAC1D
+:10FB1000AE5A95B12546AFDD0ECF774EBA3CA48ED6
+:10FB2000E12FD8DF3392B12E236B94E2B01F606CCB
+:10FB30000C4350F8CFED56EDD097F0FFE1FD448B2C
+:10FB40002D20C3B8CCA35CECB0F047BE1B281E4DE3
+:10FB500066CC285E939ADEF846CA652C76721163ED
+:10FB600070DFCA5C8FB22CB8318CA99E18C6A2D89F
+:10FB700033F6F3D98C19F07D584757F3BBFD7C0061
+:10FB8000C71FFEE54A0C83FB1F29C118570E6317D8
+:10FB90001E3C15E3B6C1F507E5723FF46F4740C65A
+:10FBA00087F0926F870BA3197BC4EE1981EBBA63C0
+:10FBB000DD7F8FF1DA42F7D903703195B1157E19E7
+:10FBC000E7E6F0C27FABB65919B384FA95F509118F
+:10FBD0007DC018E1B5D2CCD6D4DB7AD26305D2038E
+:10FBE000E65DB17D8B295DC5F9BD93ECD0BFA0C0AA
+:10FBF000AB80EF0B0D317E5F66089E25DB4799D207
+:10FC0000E1D6474D6616807530A5DDC86C84B50A0F
+:10FC100009F0E61578D3C379B8C54AE3DDF57F6509
+:10FC2000BF1996BA18E67A201E9E6F5A51C1727B90
+:10FC3000AEE3AE3FA8652940BCBBFE4D623E953F9A
+:10FC4000FF601E3CFFC0235F20DDF4EB5CEC337EE5
+:10FC5000D211B16E376300CF3241EF3B1F8DBCBF75
+:10FC6000ACE9311A6729F39A909E776DD4DFBFE92A
+:10FC700033E4BB654C095D073C5C3E9265453CDC6A
+:10FC8000618F493C0F20038F8DFD0EDEDF7D6460A8
+:10FC90009C37A7277EB5F6E23AE06F33637F5E6755
+:10FCA000A1F6C23A46ED08BB4AF459DD74F27EE48F
+:10FCB000AFAAC65D261CA7C5FFA78409F04861D37B
+:10FCC000373232572173DF7B0EF0F92326B3EF0072
+:10FCD0007FBB19E79FF546CF3D48AF1BAF96D37D5D
+:10FCE000FDFA1769FC7F249EF86711AE3B17AF2B16
+:10FCF0005FF6B6AE9FE2BA809FD95858977CFDEB6D
+:10FD0000D2D6A3AD4FBB5F2903DFF5F2BEC6EF230A
+:10FD1000843E58FADCACF569808ADAE6CFFA7710CF
+:10FD20003FB1D328BF1A3F2D1374D2F38D46C76E4F
+:10FD3000FE68FA775A9F463FE07FA7C1896DC06988
+:10FD400018D7934FF47CA1E7834E63477F945F3DC0
+:10FD50001F744A6C416FEBFA37FB405AD752D55D9E
+:10FD60006687FB7731CF7A3BAD67235DBFA06C3CE4
+:10FD7000FC3394ABE7385F77EB3933973776DCE8C1
+:10FD800047BDB936464D71D804FD80CE9DBBCC3EF3
+:10FD90007C4E9BE7FC3AB77B9011F15E4EED9FD70E
+:10FDA00079DC830687EEDFFDAB2BB12ABCDF358C17
+:10FDB00095A3DC77C644C2BBCF2E133CFB900EC884
+:10FDC0007F4AFBFF7C803AE9B9F631A847CF7FFB39
+:10FDD0005FB11E78BEEB5B73796FEB3C2DE807EAF1
+:10FDE000E5B413F8EC762167B73755125D963C33CE
+:10FDF000CB84FCCC1EE0F8B4C01FEAD7B6A8D86705
+:10FE0000711D8B1B24D2237A7ADCE59AFA39EADB5E
+:10FE10003BFD85F47E0FFAB0C789BE77213D86850C
+:10FE2000E831D6A1727854F803BEB943F0CD7965B4
+:10FE30008DC9007AE4FC33806F007995C2DCBDE99E
+:10FE4000C1FE0ECE877DAD47BF8EBEE05FF65CCDB6
+:10FE5000FA3486EB1F654AEB45EF68EBBF8BB9625E
+:10FE600049EF88F5B28E1B495EAB2D7C5E6D9D2BF4
+:10FE70009AEE9C817C51B519E895D973DDA8771766
+:10FE8000F7026F997CD16881F7BA1E905CA86FFB6E
+:10FE9000A283A627EE12F85AB96DF10C349A8B6141
+:10FEA0003E3913F5D1176FC624A25C415FFA1E7A62
+:10FEB00035C91F9B711D8CE37B09E07B8374FDF4C6
+:10FEC0005BB6B9D03D28ECB915FE9BDC83C2F59931
+:10FED0008EAE6CDBACD0F364B7DD26B4C7F10EA1F7
+:10FEE000BF845EEE5BBE60E100E7DA1D0EB26F6CB0
+:10FEF0008D83F46375D31653B8DDD5E44B93B7B156
+:10FF00000E3BF15955E313F41CE85FD501FD4A4B54
+:10FF1000C7CF6F55C3F0394ED051AE30A1FEEE4B76
+:10FF20007F82BEF9B2236C9D231CC2AE08FD7B2DDF
+:10FF3000FDA0C1AD1F57D3071ADC1ADF6BEBD1F35D
+:10FF40007D5FF0E9E9C2989FFB0B3AFAAC427A84F4
+:10FF5000F5115E05F0DBD66CF53F04F0B6491C7E6A
+:10FF60005F7314C1DFE92C769F033FAF2A7521B57B
+:10FF700027F0C554F4EB3CD3109F9A3FC70A1222D6
+:10FF8000FC247DABF93779C29FDA1BE5CE07130954
+:10FF90003F4F02F2C3949A8E391620D9AD8EEDE50B
+:10FFA0000A8C3FE5898E3951D05FE8D8C1FB5B3BB5
+:10FFB0004E595C8CD5B057CA4BA07F3BA013C7BB32
+:10FFC000565B60F62C44F95D0D7E9205ECD1EAD3C8
+:10FFD000430EA1DCAD6EAF2897C0EEAC0683238143
+:10FFE0003DAA74C706ACB9D46713E0B9E7EDDE6586
+:10FFF000C42F57EBC86EAD3EAD70B9399248EB5780
+:020000022000DC
+:1000000000F62878AF2E1AFC55C0575DBCC5559B2D
+:1000100049D77D51F1D877AB6AD8758D1EF81EC2CD
+:100020005167606E07B4AD4787C4757C8FDD6E5D28
+:10003000C72A14E08383EB2CD4EAEF179AEC83D021
+:10004000EE151A98B7377DF9A483FB8DC0E4E94813
+:10005000E7AA23269277FCA11F5829F451151028EE
+:100060000EE0A93CCD02D1B1F85CD9E70AB60D1279
+:10007000FB24C25F61A1BEDC37DCD7DB56E17883AD
+:10008000C3F984E3A948912A94B0794B6C51117D4E
+:1000900039C5300CD7C3E468D756C0AF9C6E58B38F
+:1000A0001BD62F0F8016F0A1D85DF2626837164F6D
+:1000B0009197405B6BE476B5D6C09687E3E90581FE
+:1000C0001FADFDC0E1D98A74BFF456FB182BE9AB14
+:1000D0000C3BC9B9586FADE40A50DCD4CA5C5BE193
+:1000E0005A9DEC619C8FEB19F2F11B621C97D9B001
+:1000F00047057E6D747C40FCEB8A33DC9B09FDC0B8
+:10010000131FF17EBAE14A26F0F781273ACA15900B
+:100110000757B6E1CA40E81F7AE2637E7F220C09E6
+:1001200006EAF0139F94FB6C382ED7676CBB3B1B21
+:10013000E7510C12C9A972C0E4AF85FFAD8BE5FC95
+:1001400054073C82FCF786B0B3EB6B8A5EB602FFC5
+:100150002B456E750D8CE3C78069F4DFDF6A7894F8
+:10016000AD068A53B0457CBF29D6ADD18135B8B331
+:1001700067A15EA87767CF8E41BC7A4F225EF3DB22
+:10018000DAA7A03E6E78FBFD31E8AF22BD709CFC83
+:100190003688DD603D975EEBB7450E8B473F7014A8
+:1001A000BEE3003996DCDC9F94543B5B047257EB52
+:1001B00066AA09D695A28BEB1A18D72FCFDB3D7F05
+:1001C000C4F7584680EC4DA1C3FB31CEAF8F5759D1
+:1001D0007B7CAF7A59AFB74CB90FC8E8E7C4A737F3
+:1001E000BEB704F5FBEFCDAEC12AC2E5660F003CF9
+:1001F0003B0D4C61F1C426C394028C3FA35D1B50A0
+:10020000EE5DCCE90339C3308D80845FE298B0B8ED
+:1002100055AC07DE2F61D08E45F86EA0F5C9C857E2
+:10022000A3984746FD3586F9ADD87635BFE644BC80
+:100230003D19C5EE40BFCFB28DB9FD61FA63403CB8
+:10024000F7F726251809EE6863FD6CE4D7E82F98C8
+:100250001DFDAAAEFF3429383E08C874BCEE3A6CC6
+:100260006008E70B46BF3D0EFAC1E18AFA2C0B8D00
+:10027000D725E8AD8DFBA4491DEE407D93C0FB2F33
+:100280001472FB1CFCDCE47F3613F16359E30F931B
+:100290002F673CF75BBD4945F1F1D0D63747339C1A
+:1002A0007F6C4BB401E9F0F2F6BC28E4879D881B13
+:1002B000587FBCD97E0F8E177F05E0CDA4EB6EC2B0
+:1002C000ABA28E8A03BC4E9866533700DE5F88AAC5
+:1002D0009F86FC1FDC6160CFC2143B4DAE59D8DF56
+:1002E0007959B5A3BE7D21B33E9AD6B3C340EBD9AD
+:1002F000191D1CB116E0DE304C2947F8142B535061
+:100300000F2B8622F51EB83E349EDB574D2F2F88CB
+:10031000E7F2F3A404F3E7E17385243FA5B28DE48B
+:10032000AE2BC8FC669827696EBB8CF4889E05AC22
+:10033000847CAF046406FD491E46498D4936A35F9F
+:10034000257DEBB62D06BA4F11FA76CA87AB2B780E
+:10035000DCE33A3D11C63B6833325CD764D621A357
+:100360003F38F92A7305907FAEF278C60E7FE83FDA
+:100370003DAFF3074BC578EEA0BD042F17B2483F41
+:10038000AE7473D9E712CDA32A68A78B2DBAFBE808
+:10039000E7C5621B193795C50BFFA63FEBFF1DE9AB
+:1003A00037E05E98EF3E3B9FAF54CEF915AEAFAB52
+:1003B000DCE4423CECB2B9DF9D887AB1DDC8B6B26C
+:1003C000BEE5E979883FFDE0730CBB6A65FE7CE21F
+:1003D000471BAE67C4E68DBE2858F788417C7CE495
+:1003E0003BD42343FF333101F5F855A15FB456E305
+:1003F00033E4277B1CE727FB0D2139BC333E939E5A
+:10040000D3E40AF90CC7D96FF42FF4F46227813FC3
+:10041000EF44FEDC656314473D966A598072A5CDB2
+:10042000F3BCE0637DBBBE666DAB11D7FD15D80391
+:1004300080BB24EDAA29DC9EEF49E27C552A7F4B44
+:10044000FE766793C4D0CF4F6EE2FA3B9C3F527B5F
+:10045000E78F5F225EAFC51F5ABCB0FB87F2C79122
+:10046000BF8F3F365C933FBE8D453CDCD75C9CC262
+:10047000BEC7BF6914FCD0D7FDF156AEE7F4D75F15
+:100480001178DD67DA383D17F5C0CD0617CA395047
+:100490003F7D36AC635F347F8F296BB2B0BF4BE1D9
+:1004A0007A65579399F4CA2E9BD74B76DC6961E83D
+:1004B0003F30C5DBF133D4876916754318FF2E8DA5
+:1004C000E7FC566F0C8CFF0CFDE2A39CCEE36ECED6
+:1004D000934DF05CEA522EE705174C5B300E2B4D26
+:1004E00028DC817C74027516B4D5E7E029407CD500
+:1004F0003913E9BBD75A4E96617E11FC1E37F2D9EB
+:10050000D8FD27CB8A72F079AE4FF78A56EB8FC7AA
+:1005100035C5B3EE78D723ECC678C6F59207F92433
+:1005200037D4676E23C56B1A3FD447033F805CCC3A
+:1005300067AA3116869C73CEF330984336A73C9257
+:10054000CEF303D3283E9C7BBAFD55D0CC6C9E479E
+:10055000775FF0C17C1D1F809D3D1E8FFED2F18014
+:10056000C980F399D664737F684D16F293264FF4D1
+:10057000033CD5FF61D8B31BC2EC7B6C0297A3C7C9
+:100580005D0ADDF77598FC83E1D2BF33FE5EBDB036
+:100590003F9FA33C63FC70DF2B0BD18EE62F771FB0
+:1005A00044FC4F4F92E9FA2F58C09285F47129E428
+:1005B00097D51BD5E2CFA4D0734CF10CB3C1FDFD90
+:1005C00049D1F9387F6982F722D28929C123F8DE1F
+:1005D000D80979F9285FB6517509688F34B801AE2A
+:1005E000F2ADB6101C1A5C67055F94262CBE88EB32
+:1005F000C7F750BF347E7CDE82EF6B74AF6FFE8234
+:10060000D33B8CFE48EF10FDA53BB0AFE1E12BA141
+:1006100057B4FE3F4A7F2D7F704DFA637E20F6EF80
+:10062000A2BF352129447FF0B3E2B1AFF7B3EA4D61
+:10063000E077E7F4BC5EE828A4E75D265821FA5588
+:100640002D1077A23C7A1DB42FB0C7CEE7EAFAC3CB
+:10065000F9FEE022B2C109F184F76A537008FA2169
+:10066000A30212F985A340F01791FF95417ACF2597
+:10067000F0C4CE4BD2F961DC45FF2E1DFDC3400214
+:10068000FA51A3CC1501E4F7DDD629E9E8D7E559FD
+:100690002765215FBD3AECBEE368825E4D5BBEE735
+:1006A0003935E4FF68FAEDA018569BBF2081EBA115
+:1006B0001B41DDA21F882E63381C9A3E47F2201C86
+:1006C0005260BEE13B2BE9E5A60EA0C78D0807E00E
+:1006D000A155620DA8CF0B0DEEC462F4D392020AAD
+:1006E000F7F7BEE98FF9C18AA637DE43782B703F52
+:1006F00004E35097F162773E62604F3F58F357B47E
+:10070000B840F367B4F813FD1EBC3F405CB79B01D3
+:1007100040B447018BBF06E67FF2B23ADC2DE456C7
+:100720008175548875CC64ED0417FBF6BBEF260188
+:100730007D66087C541C81B83117EF337633E0E1D5
+:100740006685C79337BB207E0CE3A399E322FBF8B1
+:100750009B921C1AE75ACFEBEDC044DDFECC3FDA8A
+:100760001E017BF409B8CEC7D6F1B874C240D9A730
+:10077000A0E11C9769407EAC16F60DC2E85EEDD292
+:100780004BC22F9E60E8C875017E5BF7FF8DECE0E1
+:1007900081FD7F7B07FDBCF19F2BCC0CEF4FF8BC9C
+:1007A000200EF5041BA7125F69E356FFA9C1CAF822
+:1007B00075E2FF2AB1F6C3008F7B28C267A1F677E6
+:1007C000179FDC84E37D794EE1BC2DE62F3379075A
+:1007D000611EBBCCC4F3018725EEFF68F70F1B0138
+:1007E0006EB8BE2941CB0BB493DDC79F398CCE3791
+:1007F000633E202F44D79B2F947FAEE4F6A40FFED8
+:10080000FE37F2015A1E60ABC01F3B78D6A4025CD3
+:10081000531BEE51D0BF9EEA94993B6CDE9B542B48
+:100820007387E5039E49D0F923075FDC3403EC4965
+:10083000759BEC8A42796DDA753C17FBEDB2CBDA29
+:100840000B1FE9F13BB5E91E05F9DF98A8927C5F23
+:100850006BFE0923804F6E40BA33F2EB3AC748244F
+:10086000477AFA1ED8FFEB848E9CBEF1DD17FDF5AA
+:1008700074F8DDC522DAEFB9163DF47CDB02EBF447
+:10088000C1FA02B04E1FF85D07D6D9A97F689D93C3
+:10089000FA1ABF5637FF3601FD368D4F4B1338DF3E
+:1008A0008CDFB72981D942F4D2F0F5A1B0577BA3F0
+:1008B000347FC3356F065C3A05768718D4C7DA9D56
+:1008C0006342F66BFEE932F23734FB355F5E544A21
+:1008D0006A53D82F4C23A35ED3DBA9B9EA6223EB7A
+:1008E000CD3E2D88EC97B76D5462A867203A4992A7
+:1008F000C087F0B33538CE300FC1A9A7A706971E21
+:100900001E6D7D9A7F3D5FD06FCEA04C23C2DFC3AA
+:10091000AE8A75E2409887B85EBBFAB58E9FAF5C31
+:1009200028792BB717BEED8B7FF5F7357D508613F1
+:10093000E451EB43BFC298984C742BBB6A626EB013
+:100940001B2C238A7D1A665758C550E29F7B851D54
+:10095000EE8B7FAAAECACC9B1FE22363E31356E45F
+:10096000A37DCA462BE62727DB66D5C6019E4AFE35
+:10097000543417FDBCEA0E03C3145669D31707316C
+:10098000AEAF7E8FB9502F1635B51623DF1D52DA64
+:10099000658AB3BF64EC89307FB1B1A9D68AFE54B1
+:1009A00063A24C71FC6107E74BEDFE9644AE3F1A23
+:1009B000CF5D9EE1EEE5FE1971BFE4E33CE2A3B238
+:1009C0004741AE310E4D8AA1BC4489649F53817E5C
+:1009D000C84D46F2F3218EF923EE035E6A34EFC26E
+:1009E000D47E69E323F7D88110F5FFFD698D19F3F3
+:1009F0000BB324D7B3F05C991A6CC57ED9DC4CAA32
+:100A00007B18FB3F32F9B3C15B25CA8B9401BB60F5
+:100A1000BF6C51A61FF313FB25DEF735F37D02668D
+:100A2000F725CC8079DEAE4818B581784AEB0FCE39
+:100A3000DBC0042387C557F7ED9549CFDC572AF96A
+:100A400071BFA9D49ECE7C617C55F6A889D635BBF2
+:100A500029A508F9784EB9CCFC61FC1D107EE13C5B
+:100A60000FC4E161EF1D8EE270051703DC52486E82
+:100A7000A7093E9FC5B89F387F4142C47BF0C62D71
+:100A8000688F6E6D8238157AD344FC7AAB373D623D
+:100A90005E0FE37ECD09162C8983F1FB250D24FE24
+:100AA0009B11B48F0EA8A877CE24A25E63C3B89C16
+:100AB0006872572AAFAE237E70F27DB279124893E6
+:100AC0008CFA2F529E668E8BECCF72F7A8378890E7
+:100AD0007FBD5ED7E47E5EB34CFB72F30A2517EB55
+:100AE000453FE8FDECB1D17DE8856FD587E37AD34A
+:100AF0000B1F96FF5D7AE135082BC681FCFE345151
+:100B0000E8877EAC1FEA875279FB26E4972EB07700
+:100B1000E65EF845B3175A3C5E06F24AF27E91EF64
+:100B200067945E4D65BEFC503CDEAD2FC09F70F5F6
+:100B3000E2E73C9D984572D4AD5F34FD11E64F1855
+:100B4000C7FCE3FE4429F891A63C842F83E02B6385
+:100B50003C1F588685439897737E41F9966A88F3BF
+:100B600029DE67BF25B850CF49F12139D0FB195A8A
+:100B70005ED72AF2087ABEE8CEF3CD35521D8CC678
+:100B80001765762E1F657365CABBEBF9449B4FCF83
+:100B90001F015D5EE69AFC21E4EC87F24773A2D860
+:100BA000571DC4065D0F5F68FCA0F187DE8E1CD365
+:100BB000E567FAB2236FA21D19DDB71D797D989103
+:100BC000F4B5DE7E68F6E277495C2F6724F27D8E0D
+:100BD00069C3E7D9D0EFB026F13A0DCD0E75E7978E
+:100BE00036737E78BD638922A13D41BD9019867F11
+:100BF000916FD5F8AFEA5189F28D15422F7536F312
+:100C0000FC5B7589ECB7C0FF16373DB189F78D9451
+:100C10009F2B545A150B8C3BD325B930AFE316F9F3
+:100C2000BA196E89E7EB5C91FBF42D3AFACE117C90
+:100C3000349305EBD01FD7EBA53957B95FA0D74F39
+:100C400073C4BEFB1CDDBEFB554DDE07B001FF4C7F
+:100C50007FC09CF4FDFE80F6BE46478D7E2AEEC521
+:100C6000A11C1DFCC6A4C670FF19E937F5AA42E312
+:100C7000D893045F0A7FE6CB8B79BFA0984F3C5F87
+:100C8000DDF485C93BB26FF8AFE5B7C6A29F3E3A27
+:100C9000E4B76BF34E53184B47C74C674F6689EB6D
+:100CA0003FD47E0CD7AD43A383A6477BE059E8D958
+:100CB000BEE8742D3DABE9B37FB69ED5C6D7EC80B8
+:100CC00036AF5EFFF615B769FA74FD1603E54B26DD
+:100CD0008BF878B2C8C3CE4FE2F1C1AD493CEEEC1F
+:100CE000FACA62407BB9B385FB272EB3FD38FA05FB
+:100CF000A17C1FA7E7C331CC87FBEC4C69B7D0BE02
+:100D000067119012F73DD3F8BEE77625E0213DED5F
+:100D100052580DC8C9397C0FE679F8806F21EAE98D
+:100D2000873F1962A0FD7725D08EFEC9D83C85F695
+:100D30008F1C6695F2C19DCD663BBED7B5EFFFB463
+:100D40001A719CAF980B43B843CDE6EEFD1BD40758
+:100D5000A5729B8CF9FBAE20C8083C3F6941A018E6
+:100D6000E3A0C9ACBD16E57B02D2B117FAFD2A4952
+:100D70008BB37BCFEF1737733FAE3846263F6E8A73
+:100D8000AFBD18F7ADA62892AB169FD5E5F75FD19A
+:100D9000C51FA1FCBEAAF0FA435DFEBE91EB99EB24
+:100DA000CDEB4F40DD067CBC5EE373A16F581FF9AD
+:100DB000FD9D26BEEF133C6964E807B30B89BDE6D1
+:100DC00063AE95E7DFD712ED5663719F8EFBEBFBA9
+:100DD0005AD2DC6A6EDFCFE776048BD03CEEDC3E85
+:100DE0005BA1FA35911FEDB17FD2C7FE88BBD17EE2
+:100DF00008D5695FFB21C55FAA94F6B95EBC697529
+:100E00000B4CD43FDDC8B49F9BE474E7F96837F21C
+:100E1000F9CEF3696E84EB79C1A71ADFEF3B77391E
+:100E20009AF6414D6E15F78F830E8BEB59E25BCE30
+:100E3000EFF5A943FCB84FFB1B21173BA383C7B2B7
+:100E400013C3F73DF83E47CBBA47679F33D27EB90D
+:100E500084F9486D7FD9077243753DF18CE20F2309
+:100E6000AB67386FAD9BFD1ADB2993D438C4FBE523
+:100E7000446D1F538DA33CC4B757A8CE508FFFDDE0
+:100E8000EB9807EB511AD6593C0AC8FFABEBECD4F0
+:100E90006F5CE7A476FF3A95DA878EC73E8076BF0F
+:100EA000DA6DF22861FAE39D64EE77E5657F524CD6
+:100EB000C5DF7F6354873EE5C10E19F5C58D5761C7
+:100EC0001D117527CA65C437E537B342FD4C6971FA
+:100ED0000CF66FBC0AFDB0E7AF2439B83DAA53EA5F
+:100EE000462793B4105FFC2DC9DD9104D7EF7178CC
+:100EF0003EC176B734FFE02546FD73BC7FAB7C096D
+:100F00009ECB0F14525E391FF3CA7934EC42C4DF12
+:100F1000E85613ED976BF9DD3C4DFEBE8ECC33E702
+:100F20008BBCEEABAC83F2CD051608B40C0817A74A
+:100F30009F5B9AE794301F98647261BDC3E82C4FA1
+:100F40003EE6635B9318C547ADADC9196A0E720FD3
+:100F5000CFFBBAB5BC2FFBFEBCEF918F627DA4B76F
+:100F6000AE9A687FFAC8A9585780F60B2DE4FF693E
+:100F7000F5C82DD1BCCE80652CA03CD38DA29ED1CE
+:100F800062F69A93495F050E9E80F77E7F99F17D08
+:100F9000C7F60F695FBBD8303C05EB7E0F4A43E3D1
+:100FA000B07DEAA3D81C6A4FC55E44FCB418AC2AD5
+:100FB000CE7B669D5A82756D27D6B112AC637B6B72
+:100FC0009D85DA93EBECD49E5AE7A4F675B88EFCB7
+:100FD000731C9E477E71BF65A37D92296FD9146CE7
+:100FE000F316C650BBFBB61813C2DB12CBB66BF3BD
+:100FF00060BD5A203AD080C9FED6A7BC8F59FA816D
+:10100000DD337B474AA3186B7BCA3B5D990CE34EEB
+:10101000EDFF93AFE0FE9BC9CB1EB3005C734FD9CD
+:101020001ADAA0FF76F2F2C76CA86F8F4783D2C39B
+:10103000F5AE38EE1E047443A590C605978D837EE9
+:1010400082D65F31BD641263B71477643360ADEC50
+:10105000E495D32D80C75BACDE1F63DFE44B9A5E63
+:10106000D20FFBCC87F56041C948713FCB9012B1DC
+:10107000FE65A6C3FB467258FD9E5BFA13ED338DE9
+:10108000714BCC41871F8CB4EFC5EC1F2784CBDBA1
+:101090004C47E91B488F89C9BC0E78F424C91D5EF2
+:1010A0005FA17F6EF439B504E934E642591DB633C9
+:1010B000CB1DD4F72C185B87F25C62EBEBFD627AF8
+:1010C000BF3C99D78D142952445D89FEB97C6026B6
+:1010D000F48F8347A3294F30FAB4B716EB4F4B9DDB
+:1010E0009979B2A6FAA8EFD882FB6DA32BCE9424EF
+:1010F000A0FCD824179A8931ACA32E01EE17DAB1DF
+:10110000A00AD7F54431D6FF8C562517A2ADD0DD05
+:10111000DA80EF17BA625C85E88F9F564BD0F49C5B
+:1011200052469D2880E7A60E925D1618E854E0A668
+:101130008997A05F382C8EF2BC85CA9A2B27A81FEE
+:10114000E3AA51711D5B7E5D45E398C9AEEF9E51E8
+:10115000FC2FC83F459E38CA09023E4AC2EBCA600E
+:10116000DD0477A15DF64749C8DFFF5A6287FEEECE
+:10117000FE1296CBC37CC3FF42F78F44AB5100E80D
+:101180006E93BD04C7DB6D92EC0F51DF538CCFFB28
+:10119000861855CC1F952546458C3FB5441A7F0EC1
+:1011A000E1CF891B85D7CA331C11F7DB6EB3929D43
+:1011B000A8782B87FCA2B6DBD2C95E54BC35A9083F
+:1011C000DB3603F7D32BDEAA28A7FB061E07572C16
+:1011D000FC915BF429EEAD585849FD5629E52738B6
+:1011E000DF959CB83CCCAF4D1B945AA244F88103C8
+:1011F00049FEF3447EAFD0307CD32480FFDEA37C55
+:101200009FA2222733E2F91905524978FDA86752B7
+:1012100054447F7689A324BC0E756E456A44FF96BC
+:10122000B99911FD92A30564BF410F5494801E38F3
+:101230000AED5260C1025107A5E59F0A054B15B69C
+:101240008BBCACC2E3EB61F0877AB0C41669A777B8
+:1012500047733B5FCED6D00649F911BEBF5D966895
+:10126000FC24DC4E94CB15365E97158987BCA346CB
+:10127000B2977931921FE3FA92A34BEBD0F49667C1
+:1012800044BEAFF961E5023E6D5EE673B7A33FA2CF
+:10129000C1ADCDAFC15F2E2F2AA17CF735D6A18776
+:1012A00097C17A503FE8E1684A16FE1AF81FE4AF8A
+:1012B000897324F04BECCD7E6BFE7A05E82B47B8A2
+:1012C000BEB2498958B7D797BED2C6EDCB2FD3C689
+:1012D0009DE9F0D0FBEE1D9F9E9A2087F5333F4E8F
+:1012E000880FEFBFF8E9A688FB491FCF7184F7B7D5
+:1012F0007E3A07EF4F51D45A1BF0E53126B97CC82E
+:10130000076DAA1203F4283EEDAEC3B6F4432F9640
+:10131000ABB2A9E77C75D84EBCE86F33C3BA6E1A7E
+:1013200026AB18BF6B7E881EDEBF26F3BCC3B1ABF5
+:10133000AA15F75977FB542BFAF3BB1F54ADE88776
+:10134000EC76F37319EE2C039D8F7167F37AC5BFAA
+:1013500024F3BA834EF1BED6FA8DDE4E841BEBCC5D
+:10136000D137A8FA264875E5C7D0BFCAE9E95F1D9D
+:1013700053FC369CEFD8837E5BF87EE2F5FA577F0C
+:10138000041E43380A99E409D723C596284FB8DCD0
+:1013900096DA1D11FD93C20F99EA4C8D78EF263530
+:1013A00033E239F01B87A15F526B62546FEB33F06D
+:1013B0007A5B3D1E57A4F0F8CE65B3A33B83FB6672
+:1013C000726FE7915CC5865ECFB7A5A4707FF03FD2
+:1013D0005218C1352B85C3A7AFAFD5F76BF17C0F82
+:1013E000E293B99CC8E72EABE10AB8BCACE0E927B0
+:1013F000A6535D6DBEE1DE2CE8573CBD753AAFAB40
+:1014000035ECC13ADB194F3FCFEFDF60C837823F81
+:10141000B0CDF7C274AC2BAF8AE2F5095551A23EAC
+:10142000B46E7444DCA3183E7E6A21C69FFB8D0C0B
+:10143000F3FC8F99C00EE685F6D9AD661EAF5A4D06
+:10144000BC0E7C7DE6A9F5A83F3E8BF2E6A5509E3A
+:10145000B148453C5EB45BA83EF4BE7DA529C807F3
+:10146000B35278DE2B7BCF44279D2FFBE7C151FC85
+:101470007D7060FD308E73717736F9E5D903189D64
+:1014800027D1E801E1335D8F82F081CE6330B7135D
+:10149000F36FB50E138D332B85F3E3F5B63DEA8973
+:1014A000E30C6B7641BB2085C7CDB7E2BC046FB0BF
+:1014B000FF2CDCD0B307FBCF1EC9FB486F59CE0B06
+:1014C000A27F1BFC510CEDC3BC1FCDF1C63282B410
+:1014D0006FF3EEA26CD706BACEF1B8C03FB0B643F8
+:1014E000C5FA0F7F3FACB718E8F42E457CDC66F6F2
+:1014F0000F26BEB2AD89C179AEB7DEB8EFF921E0F3
+:10150000047B327F3CA797363FE0D882747C579C9F
+:101510003BD1E001387E8C70687075C3A3AB3FEFA0
+:10152000147E7B278E971BCA5357FFC940798A6A5E
+:1015300009F424F4F77CC85C3E95E8437950DCD28A
+:10154000C2F9C69F58526C83B6A071158F8FDB9578
+:1015500088BC9866CF268AE7C7BEA744D8A389224D
+:10156000FE1DAFCB4F4E6C9C4EE7F826EAE2E25FE1
+:10157000A488BC651A4B0BCF23AC15F1C6E5B68128
+:1015800071E89F2A10E7CA806F932AB371F121BDD9
+:10159000D0B08E459C53D4F870E469FB9D38DFC809
+:1015A000D3EC0EF207B471BBF3131C2F97DFE37873
+:1015B00019D531ECE949D0371E3132BF1A5AE70448
+:1015C0000E2A833087E2A4CB176C645FC61C9D4350
+:1015D000F5DE66A781A961EB8F52A3991AA62FADFC
+:1015E000C3E223FAB2A04F5D54A41F902FE6897185
+:1015F000A5458CB73FBEEC08FA05F9B6E5E417C47B
+:101600008D1B18311E6B5322FC833CE67163DCE8B2
+:1016100002FAE27ED998D34A841F302EB091CEA12F
+:101620008EFB30F2FA847391FD037DD1A52FFCB1BE
+:10163000DCA7D12FFCA1F873B823F197501E89BF06
+:10164000244F24FE521644E227D51B898FF4E5234C
+:1016500022EEF75B9317D11FF0C08488E733C18077
+:1016600085F7B31E9D16F1FCE08DB323FA4337DFF7
+:1016700016F1FC70FF9288FBD9DB56FE207A8FAC06
+:101680005F1BF1BC9EDE3734FE34627C8DDE3EF89B
+:10169000FBDFA437730AFF50D03B51D859879BD743
+:1016A000AD75196D8FE2797C3C3682FACE81E7E91F
+:1016B00063D1FEAB5497E79BC6685FFB97B2474286
+:1016C000BD940EA8356451BD3CD5F5FDDC6088D8CD
+:1016D00067B73BB93F6477723DFE6B133F2F950EA2
+:1016E000FE26D929030BC5D916AC77648299AC8F35
+:1016F000639C5DE7E818A63A306F07FDC921BDAAD3
+:10170000E9D1DBCC6A6D07E8975132D793A03FFB54
+:1017100039619EF7A5078DDCFFF019D1FF48B7307E
+:101720005F6C1ED919CA433B58A284E700E2427A93
+:101730005CFD0E88757065369DC37A134140BF59B4
+:1017400075D17ED3AD9A9E5A3E9CF4D4655BA4FFBE
+:10175000767969165D3F7BBB99EA07CE8A3A470DD9
+:101760000FFAF3D6DA396CEDFEF22D9B62D0EF3C26
+:101770002BCEFF6AD7270BFC4D76CAC2FE59D66026
+:101780003E6C1118F138C07BE5918ED8DB18F99BBF
+:101790009370DD555BAEDCFE2AF4AB0DC1646E3791
+:1017A0007CF4DEFC77F9B9EEF97F8BFCAE408593D3
+:1017B000C7F91562FC5BA0B1039E6E013A38B07D9B
+:1017C000635219F2275CA7F371338F3023CAF32CCD
+:1017D0006F26D54D9C62AE337B01C4F94E95E09CDB
+:1017E000CB3C46CC5BBD737B650C3ED73D9E360E35
+:1017F000300CFA25EF3A7CC664CC1B4CE6751330EE
+:101800009F05AF7B16A53F8C76499BEF1DE6BD7407
+:1018100006E83B9BB9685C6D7C86E9F9303DB57B99
+:10182000F9AA8F1260BEB5470D948F58DB6CA6786D
+:10183000AD6BE57FED780AEEDF91DED10FEDF6FBC3
+:101840002BFF3604F9E1D6CD325381DEAADD7BA72A
+:10185000336C5FE5ECD22B31781FECEED6A7D05875
+:10186000BE6CA63AE2F757BE3C24DC8FAD74162E50
+:10187000C7F7D8B8EB3BEF58FCD2F014AAF712FC2C
+:10188000B442F0D3DA178792BFB536A69B9F787F14
+:101890002BAF1BD1D67146F0E3CA97BE89F8CEC4F0
+:1018A0006EE023D5CCF7C5D4A160EFDB2EE7D2776D
+:1018B0001F8CDE7F75C2BC2D573F89C5FE9E37FF4A
+:1018C0004AF0B3B9D7072FCAA26F4C687F5A3BEFD3
+:1018D000B9A029211FE90E72B601C7BFED772F5EAF
+:1018E000FA00F1D3FCF2D69FE133D779FE739796D5
+:1018F0007714F6C625F001F686E28B2E16CDCF932F
+:1019000008FF46C11DF92CFA9E874A7CED66C77117
+:101910001FA7B6D5407526B1B8091496AF8B950DA3
+:101920009A51725B9CA0AF859EF97FCEDB2AEAA814
+:101930003E20D21F2A38B432C20FF2C05FAF7ED031
+:1019400033DE5ACC2FE9FDA1F101C36253DCF7F875
+:101950004587A6F5EA174140ED96C688AD21F835D2
+:10196000E8F4F37E2157F53816E6FF03D1FCFC338B
+:10197000980EF47B7F9ACAF5B72D83F1F36952E78D
+:10198000300BE8CB16E7A2C71F856B96417CDDD8EC
+:10199000AFA53335F9C47FDD7ED7A111A4B7D8B781
+:1019A000301BE243E43DF4742BC0F3ECF961722781
+:1019B000DE0F1CFE6B2CE67D77C4AB6F213D8247AA
+:1019C00065DAFF89523A4C8E5EE2BB57510F029F97
+:1019D000CAA9DC1E581A797ED1A2BA19C60F51764F
+:1019E000FBA8F0737F8D4E1E4F561E7EBFBF09E8C9
+:1019F00071C9D0169B03E3AFDEBB3B16DDFF0C9332
+:101A0000F703E4C35567DF1E63A7FCCD96FE180FEE
+:101A1000D607F87730462ACCA7E4F584A37A332C8E
+:101A20002601CFE927503BB2297F19F2597580AFC3
+:101A300013C7C642BEE18D12F53B1B6BE371BCEAD6
+:101A4000DF37A7A13CBD9CC4E3CD97AE66F3F71585
+:101A5000A6E0F341A74310D36FC0F8E46511D77433
+:101A60005E95E9396DFE918D85B21DF82127B0F1A3
+:101A700000C5514D6615E91AF51CE378688A22B94C
+:101A8000AF6E99CAD0EE7739984B82FB3BA2837F29
+:101A9000A4F36ECD6615F3AD51F68D2C1EC6DF2175
+:101AA000F659870347E17929EDBA365F54D3D31845
+:101AB00073203F50DE374AD9C826DBC2F11C437879
+:101AC00076A4723EDA111D30609E253898B1670900
+:101AD000AE109C8CE6D5E01CEEC7F3843B4CC1F302
+:101AE000786E06E0B223FD87330E276B1AAA629E3A
+:101AF00020CAEEA67544D955974FEA0957752EF3BB
+:101B0000A35DFFF943AC5B6E518EABA3437D0BC865
+:101B1000C08E814CC8F9CF1F2FC908EF83621917F7
+:101B20007A7FC8AF363E5E3789E2099F8CF12FB4C9
+:101B300031F1B84E95D6A7608A298FE301F7DBAD66
+:101B4000167EBFFB79E06F1BF66DFC39579CDD3AC2
+:101B50004D2239E1F5B8421FDC2705CEDF08A4FD90
+:101B60002A702057055856BFB19FF87495A1E9A96E
+:101B70009170FFEE28AF2B15E67BED43039D6BFDC7
+:101B8000F38B51FE0AC0C7B07D5B92DDBDC8877E76
+:101B9000FC47DE7BE8C974A4FF3E49C53C6C973125
+:101BA00048DF37A96AFACC44F50D8D1F53DDD39B6E
+:101BB000A9DE4938CFB8C61ADA8F1ECF36D27E7466
+:101BC000B6380F5EEFE4FAE3F2E921CFD684E17F85
+:101BD000492A972F16F40E40B96912F2D9827E0A6B
+:101BE000B47B85BFB4B7F5D62C352C7F58C30EA473
+:101BF00023BE1F6287A8D5AE77F9F9B9CAEC772C56
+:101C000077B8C3F86F9190F745A9224F96EA9D8D5A
+:101C1000F0AE6AFDC414ABE23999FAFE6857EAC126
+:101C20009FB2F782976EB9D5C951B51234E1F3D599
+:101C300017F8F957A0731D9E3778F99DC6118BE1EF
+:101C4000FA5EC035D695FACE9AA9BE72AFD1938E00
+:101C5000CFD79CF93A17F556090201F07CDDBC6A32
+:101C600000E20DF8BE281AE56B17233DA6C9670EE2
+:101C7000CA27BC9F837C5F80FDE1A4877798DAF94F
+:101C8000F9D3BDFCFC29F03DC901F0BD1DFD861C4A
+:101C90003BC801BD3F94E47B47BB81CEC9FA408F6E
+:101CA0000FA67ED11CECEF682FB1937C635E3F0FD3
+:101CB000E5347080C6A987D8044927314FB83FD989
+:101CC000E88C25BA69FAF1B093093BA1C6E1790322
+:101CD000AB2C47C845983DE47D612F4FFC2AF0F8B6
+:101CE0002FD176B8855D10FE14F3E6939EBF57D8CA
+:101CF000AAB5AF4F98B91DD6B9F684DC5D3F8EFE0C
+:101D00006B40F0C901E1CFA29D5013783D0E5E1FDC
+:101D1000BD99D7D58E71AF29C6B3CFE3CA371EC4DC
+:101D20007682A7BE18CF3E4F5AD07E909F81E6E7BD
+:101D3000D91B0EDC948DFBDE5D67CD0CF75D1AFEC2
+:101D40001AFCE34B8087FB5B00FFBDD825580EF1E2
+:101D50001F58EC74E6EC79BF4BD2F4C7A90AE4C76C
+:101D6000CE0639D40740AA80C1B1FFDBD4938FFBE4
+:101D7000A09F95E67E3E15FDED742FB55D27FF9A79
+:101D80008CB660EF69EE473598DCD9C83F0D032368
+:101D9000BF1FA0B54FA61A890E057D7CBFEB482A50
+:101DA000CF6F0EF1B1C7908FAA1A64BB1FE87EA94E
+:101DB00041769BC01F3AEFF626E3D99C0BCC77CB3C
+:101DC00044B4F3228ED4BEF77217FA2960A7EEFE50
+:101DD00065EFFB0FAB99F65B6340BE5AD624B1FFAB
+:101DE000001C2C7F26F2F9D5DAF76A1AB71CC6EF69
+:101DF00088AD7C4E771FFD15FA0E46A41F7324553F
+:101E0000F827592C0BFD13E023D20F46851D310313
+:101E1000DFAE48F7EE437BFCB2F8BE02E85192C752
+:101E20007D4E615744FD417007AF2B1EBECD2F1B69
+:101E3000E0FD098A5F467BC5A0C57D87716E6F197D
+:101E40007D87C9E73E8DFB3ECB853E5CAEF9697E62
+:101E5000BE3F026637C24FAB16AB1FCFFCB5B1B861
+:101E6000FE6D12C5CBABB645EEA7548BF5AFDE7C4D
+:101E7000F2309ABCCA7ADD7DB1FE6ADDFAB57DF337
+:101E8000CF5323EBBFAE773FE42F46EE37BC2DC6D2
+:101E9000D1EE9BD2B87EAC826520DD56FB65BF9F3C
+:101EA000FB7936FC5ED09D625D770AFAD33AE1B9E0
+:101EB000CA6D923F803CFE78649DE95DF58BCB90C6
+:101EC000AE7A3E5929D6BD7CBB91FC55FCFE0FCAAB
+:101ED0009D9E3F568AF5AFD4ADBFCA2BE9E0E37EA5
+:101EE000744FF8EA6F413A576E37B2DEE0D3E8B587
+:101EF00052E3EB3EE0D5E0D4E0FEA1F0F64F13F95B
+:101F0000AD116C04D1A93CE1BAE8A4F773771D1EAA
+:101F100041DF5BBB7C6420C5FB1A1FE8DF2F137E0B
+:101F2000F2D4CDDC6FBCD4586C1D89F14C9BC1251B
+:101F3000A9149FC58E04BCE437CBAC02FA5D4D59A1
+:101F40009BF0FB8379270AE660FC9F7FC240E7EFA6
+:101F5000F61C29A07DE7FCA38312B228CFEDA2EFE7
+:101F6000E3C038645FBBDAF236E1F984AEB69202C0
+:101F70001C5782E7D00FC81376A2A62DCF1A7EFE7B
+:101F80007C4C1A8FEFD73B3FFD39FAE9537719E9BB
+:101F90009CC55463F04DACDBDA7344A17DF2D527C8
+:101FA000963C1485F47D51A27DF2C3ED6B1317228C
+:101FB0009F3519EDB8EFDDD5F4E30378DFB75DA207
+:101FC000EF5E54379766EF807EDE967C57F8F9B364
+:101FD0003C874AF0B1542BC5CF53FB19C96E5E4CF8
+:101FE000B3FE16FD9F95EE2D24DF17F7EF3151DD7F
+:101FF000DE0E89A1293BEC3CF80AE2E3E2AB274D77
+:10200000E88417379C34757C8F3F70C92FB300C5A7
+:10201000CD1B4D18C7546ED1FA1D26A49347F8471F
+:1020200055CF7D4CFD95E8CFC37C2B9F91A97EF7C2
+:1020300060F36B26E4E7AAED124BC90CBBBF598ACB
+:10204000F85EC312C6F96089D03FAB987F7D1A3C19
+:10205000B76A23AF5B608F46D6016BFCBD42F0F7D9
+:10206000AAEDB3E8FB533DBE5B8871E30DF81CE7B6
+:10207000EF659B23EFAF107CBD42C7D73F4913FAF2
+:1020800067381B8E7CFD75A11A9703D7BF3EB972C6
+:10209000406FE7ECDB84BDD6ECE5E58081EC8DFE9E
+:1020A000B9CEC62B046775DB6513FAA7654D5F10C3
+:1020B000FE2B9A5AA97EE466E65D8DF8BAB9C96A24
+:1020C00047B9AEE8E07A685A93D9EF97F07E3DD5EC
+:1020D0003977B5F0BA49DF7E89FC1C4D8F69DF770F
+:1020E0005C26F0B80C14787A1EFABB3C6EAE127106
+:1020F000F28A615B0EE33E7B95B8BFFAE8C158F403
+:102100000FA7B12F6E47FAC07C0CE763CF44E27D86
+:10211000BAD08BD3B773BDA8B76B5DA9D933298F5C
+:1021200009712AC2B57A7B24BEAB74F1F963693CAC
+:102130003FF6820EDF154166CD413854D9E5A7A799
+:10214000DB159CF7482ED85BB4936AD6F77E87F1EF
+:102150004DE1676BFD99E21C78BD7DA32D3C6E8E31
+:102160004AE7FEC2CAF1B20FE9D51D6F0C3A98AB2F
+:102170001A42F106C419CD69493CEEC08292373249
+:10218000649698188A371E716EAAC8837EF5762EDB
+:10219000F79DE3603C3C7FAD30F247ABB79BE99CD9
+:1021A0006235D09FE28A267E9EC2D3249522DDC16D
+:1021B0005F3F9A86FBB198528575CF6AE47C3FAB4E
+:1021C000E40BE297A383F87A2F2B6A4A6FFEBBE6F3
+:1021D000B7E3F93035CC7FAF0239C5E7AB9A783D2C
+:1021E00052C3816FFA67A29E6BFEAFFE8BA1FD5AB0
+:1021F000D845CD2F0C825F3890FB45F4BDC9BB8517
+:102200007C2DB3F37DBABB85FD61521DF17995B18B
+:10221000FE503CFA593B78BD00DB871F8503FDF873
+:10222000F64B75F1B0EECE9724AA87C3F7F17B94F5
+:102230009D4BEA3F41BFFBEB1D16F237EF06BF6532
+:102240004A5E4FB9D4E45BFB6E560D7B88FCCF87AA
+:10225000581DB595829F3B1B6BE9FBA09ABF42EFCF
+:102260000FECE98F540ABEAFD4F15F547A24DFD566
+:10227000BC1D4D7E63D751D98EFB3180AFDFA48565
+:10228000E345F8210D07A288AE5D276D6447FE2C5B
+:10229000F8EDA2C83FD78C93090F86F1BCCD6E79BB
+:1022A0006D20D211F18EF5F72FB7BC36829FFBF669
+:1022B00013FE576D9323BE0F5B591FF9FDD79AB7D5
+:1022C0006FA3EF0855EFEF866B88293104575F72D3
+:1022D00020493C8E3448917164F53ED9135E7706EF
+:1022E000EBB903F551BA9007A6049331FF35009D71
+:1022F0000680AFA689D3D5D0CC5B98FF169E273138
+:10230000D2FC3DEE17F956E3FDAF33AD7CFFFAAAE0
+:10231000AF02FBF70F94A9AEF3FEB7570E0DD7A38C
+:102320000CE104BA561B83C9146F9E34107CD52768
+:102330002F270FB2A15EDA5282DF0F9D2EF4DFE16C
+:1023400081D6E5C8CF3E9C372534CECB69BC7E8F85
+:10235000E17A9DE86DFC928F2BD6FB109B2DE26AF3
+:10236000CE4F39697CBD108F8C4BEF251EB95EBFF7
+:1023700013ECC3A98512D633293E8C87F7BCC7F569
+:10238000424DF3B28F90DFABDF37539DD7FD2DCB9E
+:102390008652BDAFD77B03FA1B5FB7ACB881F2831F
+:1023A000D24304970FE173A25F732619EB522B9B64
+:1023B000CF2493DDDD3B7A932F06FD97BCE9781D92
+:1023C000FC09E23FF06B88FFF6B415687E8C15C7F8
+:1023D000AD3CAA78103F95470B8E57A07F71A2A8FD
+:1023E00000D5B974A280FC987CF4636C21BFA65B15
+:1023F0004FA6733FA6AB358AF20B121BC8F9870DA7
+:102400008AE09FD50DAF93BD5FDD2847D42F6AEFDB
+:10241000DD99AED038CB34FEA997DCC41FBB78BBA6
+:10242000BA710FAD6F95B19EE85DB3DDC8EFEFE017
+:10243000ADF67D581F8BF7213E8EE325A0C3349364
+:102440003F03F3D3C732B99FAFA7C7E7E93CFF719A
+:10245000ECAC7700F2CBB142EF507B2F76C2C78A4B
+:10246000785C2B097C37F07353FAE73E4B97C477BF
+:102470004222CFB76AEDA974AE3FA7997AFF2EE04A
+:102480006FD2B57309EC31430146C546FB06E1D76F
+:10249000A7867DD761CECD46F2174E31FBEB58EFC4
+:1024A0003843D3B3E3B87DD5E7CBE789F73C9B55F9
+:1024B000BE5FA43B3F334F3BDFA43BEF364FF83BBF
+:1024C000F374FECED3E9C28F1FC286A01EAC17E7FD
+:1024D000EFD60E8FF287E7B3F4ED61B12F82E78775
+:1024E000B0AD19FE2EE57D8EB59E7D85EADDCE462A
+:1024F000B1813CAF47F9EFCA3EF2DF35DD723937C3
+:1025000082CF34BA5C12DF83D1D365B7A6AFC4BE25
+:102510005DB4D8B7F31BBDBB519E2B2D174DBCEE40
+:102520003068427D56339CFB4D974A25DA6F073859
+:10253000FB9BC3F4FBA5541E7FDD7F8B4479D756EC
+:102540007C1EE3AC7A89EABC2B03ED26E4A7210DBF
+:102550008B1F26B9F5B1D32CECBB1A332DDC4E768C
+:10256000D34F5B77B71D8BF7717D9C482D3E8F76DF
+:102570007186B083FA735143597B593AC033DF2DCA
+:10258000B9B01EA02F3ACF5E30EA7544C3F5D2BB76
+:1025900033DDFB4E3ACA79FBE55B308F7A6CF86726
+:1025A000FDD18E56F5C1C71F0B3CEBBF2BE31AAA1A
+:1025B000D6E2F7556A9DDE0ED29F866F6347301CC8
+:1025C000A7E3376B25A41323FEEF4B7E3E13E37E78
+:1025D00096CEBF770FB8A77D9755E9BC4EEB98D143
+:1025E0009F41798A9CEBDBF7AAD9F7462EEAB3CE56
+:1025F000D6A3B9A630BA5E5C0B7A00ED4AF3C1648B
+:10260000D516CE7706E23749D2F84F11F632920F3F
+:102610002F221FE6607B267610EAE35DA76207E3C0
+:10262000787B79DBCDAF4DFC7BF6101F0D9917132E
+:102630000EDFC304DFA57A3E0E631D43E68C0CBF9C
+:102640005FDB171F5B33888F3B22F8585B6F3D7E43
+:10265000CF07E38016337DCF07F3D78E3039199A31
+:10266000C1F5CF58F1FD9EF1CC47DF391C2BBEE3FD
+:10267000335E6101251EF7CD0232DFF7E5E72DC697
+:10268000087E1EAB045AB18E62BCD8E799C0DAE965
+:10269000B9292C48AD9BD9E91C451173513BCE1289
+:1026A000988EEE544E7D3DD525069215C7798B3810
+:1026B000AFD10BDD42EB57E8BB3DC49F329ED7E95B
+:1026C000FDBB2FB333B8DCD3C74590BE9718E5B92F
+:1026D000F07B6D38C9448595637DD3648559A2012B
+:1026E000DE5D870C24CF2D1DAA1FEB535D09E2BDD3
+:1026F000CF19D5E18E757379459383F518DA7AF59C
+:10270000789800E3619E6DAC029128E13140F3DDE1
+:10271000C8F8399242A652FD736946A6D0F7418A9D
+:10272000A38A218E427D6FB0F8081FD33354BA8F2D
+:10273000FB25B130CE848D127B0FF73FB2F87AB50E
+:10274000F1270023E0F9C2E919DC9E614AF5BD7862
+:10275000BE8F124B05CD2576FE9DA364FACED1F532
+:10276000E2B52B997FEF32F6CE60E7CF0A42FB4904
+:102770002EFCEE516CE83B9B2EEDDF830844FE7B84
+:102780001077642CF911F2A356AFC7BCFCDF7DD0E3
+:10279000D7EB85D5E7B10B61E7B0B5BA926DFED93D
+:1027A0002A9EF35B9068A173BF7996FEF968C7060D
+:1027B0003ABD34FEFBD2F6C13498E21FED8909F12F
+:1027C000BB95B9C721BE437583FC3B50DDE7AE9294
+:1027D000199D57B49A797DE563201FF81D26902E28
+:1027E00015EB68D883C5548FB9DE6171E17909337F
+:1027F000C26D0DC15D6B11DF05B5F07D717D3D686A
+:10280000ADCD40DF1DAD65D1740E3D29DABB2E0381
+:10281000E0BA2FA688CE7767EF9CE444BF317CFDF9
+:1028200093B4F51B7AD647C27A1FC9E8A51E515B3F
+:10283000A7F6EF76D805FEB475DBB5734A6E25E2D0
+:102840009C92868FC7A2F9BA8DB8F39F45EFAAA8CC
+:1028500037F4EBFDFFDC29BC16A06400000000008B
+:1028600000000000000000001F8B080000000000B6
+:10287000000BB3D36660F8518FC0C19A0C0C5DD2C7
+:10288000A862B4C41D120C0C9780F80B106702EDFF
+:10289000F5926460F006E26D40BC1D88C5A518186D
+:1028A0000280381088FB80FC7E204E07E224A81BA3
+:1028B000B30519187281381F880B815848808141EF
+:1028C000588078FB8B1519185EAB22F85A6A0C0CED
+:1028D000C91AF4F3FF60C381B6F4B5EF16D0BEE5B4
+:1028E0006E08BE0490BDC20D55CD4A37FC66AC42A1
+:1028F000935F8DC65F83477F810D2A7FAB292A7F37
+:10290000AF3903C3072435DB4CF1BB051D2B00FD9C
+:10291000A788274C9730A2F22732A1F2F9A17C00B8
+:10292000BE1E313CA80300000000000000000000B3
+:102930001F8B080000000000000BED7D0D7854D5C2
+:1029400099F0B93F7367269999DC24433260126E7F
+:102950007ED0A001879860B0586E20E147A30E0892
+:102960002CB440262888166DC49FC6DD500609BFCA
+:102970000921E14F70D11D105DEA63FBC5565B75FF
+:10298000BB7682D646AB3568D787767765A015BF0C
+:10299000BA761BD96D976EBBF57BDFF79CCBCCBDB0
+:1029A0009900FEECB7BBDFF3C5C7E770EE3D3FEF24
+:1029B00079CFFB7FDE73C725BB59701A631FE31FF6
+:1029C0009413731963B5A9B2C5C362D9398CE5767E
+:1029D000488CD530B6B25D89CF827F1676B4BC8282
+:1029E000F5E56D6EC35DCA58FF036E7F0DD44F6F62
+:1029F00057C26EE8DAA8F8A8BEACCB15761BF07CFF
+:102A0000EB472FE7E3FB8D5298419DB1BB199BCC5F
+:102A1000D81A0FFC13EACB2A921DF8FEDD2D52388E
+:102A200086AF99E99B04EF6F65FC7DF3038AC6646A
+:102A3000A8EFBBAD894D64EC961E98C5430DD9C770
+:102A4000BC3D63058C45F823D6B205DE57A6DE47AC
+:102A500058D7470AF46B8E399EEF9BF53E0BE07B0F
+:102A60002DF51CD6730CFF3185B14B993F783A1B7D
+:102A7000FE1D66E18F15281BF2191B9DC297B364DA
+:102A80000CA01FC5D85CC65CAC1CC6A9BDCCC5CA11
+:102A9000607D161EDB381E97354984C7653E46F5B6
+:102AA00077E74AF1074BA91F9B5E0D253C2FC88392
+:102AB00032C8CC4228231E96C806F8E7B65DF61E3B
+:102AC000AE7F034E359ADA2702F07E018BBA18C02A
+:102AD000F7672C46E56216A7F2CB2C41702C6543B4
+:102AE000252AD4EF52129B18CC130E45A7E3FEFE05
+:102AF000AEFED8BB12BCBFBF5AAA9D0225F3E5D1DA
+:102B0000BA2FB43E6B7E9545AEC37118935D113FED
+:102B100063E3AD751E66B18A20637A8F8FD3CB6174
+:102B2000D6CFA03EBE41D04BE3FB7208D6DDF33CCE
+:102B30000B633D049B3905EAA1AEACF806A8F73C4F
+:102B40001EAB47BC1C6B01CC43FF638D6E295A053D
+:102B5000A54B7745A00CA98C2980A7FA86F592028F
+:102B6000EDE646F938E34D4D665742FD704C52C5CF
+:102B700073ECAFEB314987FA78A83F28E17BDDC5DC
+:102B8000609C86865C57B20AF1DD334687B2E2B0BC
+:102B9000969001BFF5A64ECF195B4474355ED0DA2E
+:102BA0005C93F79B7B38CFCFE83DFBD3C7D67BC088
+:102BB000EF25457CDF8E1D2ECB417859D4DEBF48F2
+:102BC00065314F5E0ACF3BD7C10B770ABFBB0E976B
+:102BD0006D45BC1DEB53C382946DE3C3B8BD0DF0CE
+:102BE000FE4C951C560CE4B3220E7F85EED77DA9D2
+:102BF0007176AE83F697A5E06854A6F6133E4C4670
+:102C0000FC38B706DA57A5DA3F81ED018E3D080F93
+:102C1000F55B73D48BF34418CD33123DBCB04EA793
+:102C20007E83621DD7FCEF30EDD3DC861689CF2B77
+:102C3000E06BB0C36795167C238D7F4CC0658D6FAC
+:102C4000CDF7C4BA10958D4AD523F7E2BA8E687CC9
+:102C50005DF38DC77723FE8E78C231A83F79DDDF23
+:102C60008CB91786B862FAF3973FC370BEE50FDFE1
+:102C70008EEB7A2E8BD6F5D487675EBB910D9FF7CE
+:102C80002D81879F9E9B3F44756BFEB9A6344602FB
+:102C90003AAB34A5840BE8E558FD571EBED7C07A81
+:102CA000BF89F2A4D23C664A504E846168BF99FA4B
+:102CB000A78F419E554277E4C7490D520BB67BE280
+:102CC000C687BE741F3CFAA98BC37DC55F72B82F3F
+:102CD000BB7EED9308EF6537AEFDF93350BF02853B
+:102CE00020F0DDA537ED5FF377F0CF6F2CFCCBE55F
+:102CF0007B18C9855836C0916B4A0CF777D9F7DD38
+:102D000036B972EC793FC99542B33486FCB7AC4F03
+:102D100022F9DCDF08721FDFFFCC1D77237F3D2007
+:102D200099D4FE59771CE5C3311763288F971DF797
+:102D3000C6915FD8AA6524AF2396BC36F397DE0B05
+:102D4000E3BDDB60C9734EA7F41ED6F7AEF98BED79
+:102D50005743FF33A62B8C62D392174E3CBF2BF008
+:102D60001BA92F273A58A6265DE10CF4D0DCA6D883
+:102D7000E4767DC349A2AB6550B2343E9D2BF86C1E
+:102D800059C32F047FEA24979CF0BC515B589C895F
+:102D9000EE4E09789282DEDEC5FDBE0CE1835E4810
+:102DA000375D4A5C4993D3F0E78A4CA07A0C59FA14
+:102DB000962D76382DB9DD12CBB6E92B90BFFF8268
+:102DC00072B3B92DDFF67C6E0EAB9DFAE9E4F01F0D
+:102DD000480E27258207F42FED7F242EC5512E5A49
+:102DE000FB7387D89F4805A3F5FCEA80148FC1FECA
+:102DF000FEEA8858DF3E29AE4844AFE6690F8E0BE5
+:102E00007396A7F6FF76B1FFA9FDE3F8B1F095D26E
+:102E100073B99B9200428B2F5282F2DAE21F0BBFF2
+:102E2000FD7B7E5482FB57D856DA5D87701E508832
+:102E30007F3FAC3F598CFBF6AE0BF00AFD23871F9A
+:102E40000B305F0AFE1621073FE8007A81E712C2C5
+:102E5000599906A780DB857568777B83D4877CFAD0
+:102E60004B31AFD5EF475B66CC44FCDCD12331C49A
+:102E7000CFED477A97FD39AC7F753C3B8C53FCAA6C
+:102E8000B1387009C0B3A2C7BE9FA7B6DC1C40BA58
+:102E9000F9B02FBF00C7B97D6A42433857275ED5C6
+:102EA0000CA0B35966AF96CC40571FF66D0860FB77
+:102EB0000FD59E1BAFC179F629E1F530FEEA23A5B7
+:102EC000334D4EA744BFAB057E4FAA3D33C7007CB0
+:102ED0002DDF282779F05E9F323B9E417E7E5D523A
+:102EE000880E56B7B9655CE748F4F261878B2570A8
+:102EF0001E3541F81CA9DD077D2DF4BEFF81C21BE4
+:102F0000D07EBBBDDD45F2E2F63637D1D3EA0629E5
+:102F1000CEA414BFAD10F0AEDEADD0FB93A644F24C
+:102F2000C3DAAFDB05BD9D3C7CD52BA8EFCF80FC81
+:102F300041B93B63E30FB54B000F2BB67079747248
+:102F400077EED27B508E087D798718F7B6B862E3AA
+:102F50008F95EDD9B6FD8876E5DBEAA78FE4DF58DB
+:102F60008774DDA590FEBC65E3635A88E493DDDEDB
+:102F7000440E9B5490B22F4FB0A105D748297AB286
+:102F8000E8E7D636B03703C3EDCD962312D9A317A1
+:102F90006D67B6819D3971B89D69C99108DA67E599
+:102FA000293962C98DBB94E8D820C0F16B57F4B2BF
+:102FB000FC72921B0F48B54827FA6FD1AE6431A559
+:102FC00016E5DBC5CA0B5AACC547F0F75E07D0550E
+:102FD000067A9D817405F3CCECE9CF48CF33248386
+:102FE000C64BD1CD2D01E25B1C14E068F6985D085C
+:102FF000E72530B1B79A4AA6E4F15285FA668419FA
+:10300000E8E1D45A297EA894B7F3A13C05B8AE8173
+:10301000E7CD5D97C7B7496817C21FEACF366E770D
+:10302000433BD39F47CF4D09CAA2F6D297717F2E5B
+:103030000101A055F3F6380FD8598412689F7057D4
+:1030400053D75800CA62E827F3FEF41EDB05488E0A
+:10305000C769BD383E8E53A1C4D7A09CB1E878990A
+:10306000903B20572B55A0AF66961546BDD9DC5630
+:103070007E5EFBE586B05D7EDC5467D703734DBB97
+:10308000FCBF79F625B6F60B22E5B6F77FB6E80A5F
+:10309000DBFBC5D1AB6CF52FAFFA82ADFDD2D619F3
+:1030A000763FE9A7B9B49E35822F4782FB75212F61
+:1030B0007FE2B04FADB2E9FA44CDDBB04F6C9D3B3F
+:1030C000FC381427E6B0457D6972C5274B84CFDFF5
+:1030D000009B70FFE04F1F131E437CDEA6BF70B73E
+:1030E00066A23B4DF4437309ED2567FB138B619E8C
+:1030F000B47EFF26494487E7FA314FCF2F01E4160B
+:10310000E0E41C40FD9D2C5982FBE6CE35E8FD5DD8
+:1031100072B200EBBF61437BF3717F7DC962E49FB4
+:1031200066953D27E560BFB0C70DF38135C4DA80F1
+:103130003E5ADA7E741CED38C908B22558F7F812E9
+:10314000C8DFACC3F561D2C23BF0616F28FAA104BD
+:103150007048EDFDBF97F0FDF799817A98258B7245
+:10316000D17FC4A9D2F9B069066B457C9D68B4E3F0
+:10317000CD2BD6F17349A676CF31F3B7C8472725B3
+:103180009DAF4FC0BB4D32CFE27C16DCEFE6EA1AB2
+:10319000FB74702B722DC2FD23827B432B4B662B5D
+:1031A00023C37D0533DDF2A8E1F09C656656A6E7F2
+:1031B000B3805D333DBFDCCD2AD15E3D216585D72F
+:1031C000976239F48F5F03BE8A7DC3177EDC184E89
+:1031D0001753E55C9ABF59D8BB85ED52221BED53BE
+:1031E000E621FB95F53C647A50AE0911D7D2269DB5
+:1031F000C4F5B38E4633E949AD9719124B6F776E1C
+:10320000DFDBDCD4DE923796DCB2F069C9154B7E89
+:103210005978758E3F929CC1F1D43C843F3A494E17
+:10322000A7131DF03101E131AB71FFAC7D033732E3
+:10323000E6A91E79DF2C3905ED18FAFF23ED17E01A
+:1032400089EC3A5798119EDE0D0E2D7D0AD63DD0A1
+:10325000C6F5F5BB458CECC3336D570DE4207E3CC1
+:103260009E0AC44F219F8A150687D6A17CF5A9899D
+:103270007E84AB50E82F2FE3FAAB90193BAE46FFAC
+:10328000BEFDE4126C67ED4FAED89F66D81FF447C1
+:103290009A7D43C56827B951AF413B37C85D94CB90
+:1032A00085EDEFFF07EAC542875E4448583A1C594E
+:1032B000553BAE36D2C7FF6823DA97D6B8D4217D06
+:1032C000FF83DA49C46F61FBE6BB95806D7CE963DF
+:1032D000C48390DB68769D9BA714ED5539E10EA45D
+:1032E000E8C20997D56F243A61E9F394DBEA644FA9
+:1032F00038EBEEB06693CFEFFEB13CA7D5771E7AE0
+:10330000738EE7A46F271F083C7C0A3ADDC4E9945A
+:10331000CB058B6FFFB3E8346AED6B2CF78E23A8D7
+:103320005FBBB4F02C03ED84A11F723BC16D1C4246
+:103330003A8B495995F03EDAA192DD68D915FD6BBB
+:10334000FF7A4B193C3F512B931F71623DA7FB3D08
+:103350000F707BD4D2DB51A1B7D12E40BC82DD30BF
+:10336000E0E6A507C7F1AFBFB95402B83DC650BFEC
+:103370001BDBB71964AFE6D4C5F54628E315873CD7
+:10338000E38C945C4AC6F2F396C37E7D2BD7581625
+:1033900021FB3A3A7AAE3FF5FEC732D74FD34A58AF
+:1033A000DE6C182FB9550E3F08FD932EBB1EB3CA15
+:1033B000350AD797492F2B413F78A476438AA557E2
+:1033C000758DF665FEC071DCA791F6017640A738D1
+:1033D000E6393AE478877968FCA4DFAE874E0A3D87
+:1033E00064C1FF09F4EAC262A08FBD5266B83F1201
+:1033F000E3459F030060BFA32A3333B573AEFB1FC1
+:1034000044BF84ACD27C3B2A76CEC6FD8EC5947078
+:10341000FA7E58E55F285C7FE6CC6DC86D84766CDB
+:103420007DE67679A2DD63F7652D42FF0A50A7623B
+:10343000BC2614D3E7CDC678E4D4BC49E863FF18B2
+:10344000F50FCCBB3B72466FF17D227C14849491C6
+:10345000F1F1A62CF37D74F0ED1E70D7507E262579
+:103460000FC55F5A62EE8C7C6CC929A73C72EA39A1
+:10347000C934595BF570B9628DFB49F519C8872CC1
+:103480006554CA6E3FA7CF2E961E47900325328BF8
+:10349000F665F04FAF56389EFA633C4EA19A32E97A
+:1034A000AD994A1393004F1B828CE4411EEE35F216
+:1034B0006D038B030A583E0B0FF8509E046596204F
+:1034C000BFD5E9079A4DE8070639684C1F55D65F06
+:1034D00008CF83F357D239038B7079ABC37F9C8FAE
+:1034E0004CD2176E81D7686C12C539F39AEC72DC36
+:1034F0008D7E20C847BDC1F17CFE4C3A6F70B3B4DD
+:10350000E7B08EAB147FF03498F6AC9AD5207F5696
+:10351000EFBF6AD76218BFE6919BDFC672F2C17B2C
+:10352000F2BF0465DDE3BB6EC6B2E4B5E8D84CF18A
+:1035300054AB044E61721DC0E763863B67E476C6F8
+:103540007A25827635EC6307D24332569E85F4BDE8
+:103550004AE1FCDFBF400B607C46DDC2E5AA3A1FB2
+:103560009047F4CFFDF4E6943F4D7E852AFC24A5D8
+:103570005DA13842522FA378CBA12DB28625C8D9A0
+:1035800018CE63CDDF2BE2D49D22DEEA84AFB76490
+:10359000A818E5E089F51F917DA8E859E1D9305FC9
+:1035A000979F95101C225ED02CF62FB9B6DE931E85
+:1035B0002F52849FD37174CE80817430A084BD0655
+:1035C000F18D86E346B74C67187F99A58719DA1302
+:1035D0009DC2EF517C26C37DCDD6D94CF46BE195CD
+:1035E00016C2FE552C9CC0FEEDFD885B58AF793BA2
+:1035F000F2C10FAEE576C88952BBDC0612EA823D05
+:1036000065B38AD6AB489B4DC1495721CDFF5E2992
+:10361000107295D3EB1BB5531EDB0674F09CDBBC1C
+:103620004719F509F8C821D77F006C82FBF6A8641A
+:1036300097E75679D0C9476D12D985AAC9D73953AA
+:10364000F9B011F5E446B01B0B8DE1FCB2F1754603
+:1036500076E346E0BF586926FEA99650465C2CFFEB
+:10366000E4B5E74A18C7F8ACFCF3978A38A713FC0F
+:10367000037496403BE651C9E89C02EBFBCEBEC604
+:103680001F4F81D7CF1E58917D0D94DF8B6FBCFEED
+:103690001A98FFF6C7F764E33E3FFA2AF0D379FCA5
+:1036A000788B9F9AD1863D4F9CCD586BE727637DE1
+:1036B00005F1D35B0AD75FFD0B7EF7C6D5FF9F9F51
+:1036C000CEC74F6F2B409FD3FE74B6387A1EF9D603
+:1036D0005CC434B4B7A08D89741E0DDA4B9F9A4533
+:1036E000F85EE7E272CCEFF272BB23C4DF3BC7FBAC
+:1036F0001BF593C70F16947F763E5DE7333FFA3C88
+:10370000F81DE40EC99B13E3EC7CDFE9E274F72BB0
+:10371000D7275EDF3B5FF81CD607763DD977D7A960
+:10372000CC403F60E20B1E1216AF8EDB780459626C
+:103730001A3C0FE5F1F7EE3C929771B46386944A18
+:10374000EA6F326EC737D56C3EC2CF25062B168185
+:10375000BF3C07FE85F6C8753EEE57C0382C04E323
+:10376000AFF6468BD551341EF997AF3EBF2F88F286
+:10377000E5758F5982CF5952CDC5F301CBEE18991B
+:10378000DF55763ACDCF7A5A6304C7A94B358A57AD
+:10379000A2180B407D6BE9A514A764E1D87109EB71
+:1037A000A37486725C094616931DD2E63666417D87
+:1037B0002B1850B120D12DC94DA5BD37144039006B
+:1037C0007609BE5763733D1AFA2FA3640C42337710
+:1037D000DB47E4779F28E6F2B6630AA3739A810772
+:1037E000FE6DA98CF64EBB9BCE2DC06E247E8D0A3D
+:1037F000B9910C4E0FB5A09F51A48525A86F8AFDE5
+:10380000E2F8D7B83C313D93D3E3233CDED112E25A
+:10381000FEAED3EEDBFCF5CBDE3470BC1FBED6753E
+:103820003994AF3FF9F3D72F87776F7CEBB51A8CBC
+:103830007BBBEB345BDCD1CD8C37D1DE029F29A181
+:10384000A17C8E9D5C829B99F2EBA418E2275AE33F
+:103850008FE37A91B7113FC9290A3F5F84BF10C037
+:103860001710F075074F55D13CB1F7FF2393BCA754
+:10387000BFC9428F40BBCD79F7C7518EA4E69B44A8
+:10388000F2290AF209FDC8A8AF67C91A9ACF1F7EAC
+:1038900010FBFC11767572EABCF0D096792D88E7A2
+:1038A000B90B3C3AD2993BB6F96EA473E73ACFF81C
+:1038B0001EBC144373B6F9814FDC159AE925FB97BA
+:1038C0001DA6FD104D2CB8755020187780FECB56E4
+:1038D000B00CFD0DE88FEB047986F6B6D50FC8D88D
+:1038E000C4F59EF14DBF94E2FD225E61F5BB292631
+:1038F000D139C14DE5C006E5C3F1B4C127FFE46B82
+:1039000078EE12537485D341A8220D6FF8678F9B10
+:1039100071BAB86C9F5DEFC2FC0B4BF17D4C217A04
+:1039200071F2CBF8B8BDFD06DFF9CFF587EF27C7F9
+:10393000F344C16F567F0B3E8257CA145FB79FCBCB
+:10394000DC5467AFCF1D868FF3C3355DB59FDB3485
+:10395000F8ECE3CD0CDADFCF2EB2D73760FCE6937C
+:10396000ACDBC1774F8F31BFA37E06BFDE92BBEFCA
+:103970007B227F4BE3A86186E3F42FD83B7F1ED0E8
+:1039800041A1CEED8EC2F90B1B726B504E31916787
+:1039900092D9FE2814FA5E697F49C9417FD4E4EDCB
+:1039A000934BDE9A9183E7C5758CCED3A3EA3DB1E4
+:1039B0001C23658FF4ABE55988E7CFDF1EB9DB9B8D
+:1039C0009E7793B2471E78D5A8C9608FA8F748267E
+:1039D0008C336B09D82355E9F648AB8432287B0930
+:1039E000D823647744DF437C8D6497FCD8B2EFFD25
+:1039F00099EDEA3FA85CCF829EF9A7CFA267C6796E
+:103A0000CD7F513F077B605A89B13292810E3F5082
+:103A100079BCC3D29F8DC1848267E7A03755173C1C
+:103A2000BFB62EF9128AE30E7D6710D70DEB71B980
+:103A30006A3FFD7ACEA81C9E892ACF8319A9DFB7D9
+:103A400046F057BC9A57D82DF6FDEE5FF08E2EA3A8
+:103A5000FF027E0CFA2F495FD9368C0B9E89A91480
+:103A6000AF53E7AFDC3D17E909EC6C4ECFE7B7AFDA
+:103A7000AF1D926D7C3CED6C968DEFEB99FD9C6ECD
+:103A800086C77E4ED7A8DBCFE96685ECE774730C5A
+:103A9000FB39DDF595F6733AA77D3F73B4EBBFA70D
+:103AA0007D1F6A64C44F17B0EF819F6E427A1A89F6
+:103AB0009FAECB37EE8F64D8EF6A8DDBA9ABBD919B
+:103AC000054877D30C6ED74563EB291F302F0AF2D8
+:103AD000A694E28614F7B2E25A56DCCBCA0BB4E2E3
+:103AE00059CEF89515F7B2E258528CC7AD9A3DD130
+:103AF00015086F73FB4919E588FE1CCC838C609D0B
+:103B0000E30D8BCF7179D0D29E392EE78CBF8DD843
+:103B1000EE53F2D5E7A01FD6E37A2DFD007CFEE040
+:103B200067E173905BDB70BC7F417E1F45F2A49B15
+:103B3000F6AF02708D763AEC838671FA05A7F763CB
+:103B40003C4E3DEE26BEBD58FF17131D64D8B42869
+:103B5000F8E018CF8AC64A49BF587C63F189D33F41
+:103B60001EC61FFFD5FC7391FE31F0CFF75CE7D185
+:103B700047C01FCF23BEA75572FC3AF9C1A27F20D0
+:103B80008984548DFB1D4D607B8BDED98B6113E1E5
+:103B90009C28FC9A13A335F22F4E3CFFEFFC1CF639
+:103BA000794F789C5823BE9FD85D10DF569AE23338
+:103BB0008B9FDA3DD11FBBD2F240AC7CC7C31EF352
+:103BC000757C1E52FB12E8AF8466B3F00683F8ECF6
+:103BD000187FCEF9D41766143FFDCC7ED95E571CF2
+:103BE000CF875AA4A1A58CFC56A621DFAA429EBC71
+:103BF00098153D89F86C9E1E29E1F43434CE077087
+:103C0000FDA243217FEDB3F253F348F83F878FE8DD
+:103C100090AB76787E40BADC42F9160A69F10D5213
+:103C2000067925F01567E131B83ED8CF7F473CE6ED
+:103C30005531899623F8B8D963FEC1F5D9EC0F4503
+:103C4000AB4DF131E0CDA3A15CAC06BC950FC7DB59
+:103C500049175FBF93FE426A5246FA0F811CDD206E
+:103C6000A59D930ABC58EB19493E5B749A76DE1009
+:103C7000D2D2D7FBFFA85CB6E4E5E59EE864DC079A
+:103C8000B71911F2CFA4FD75CA99E176904CE78C73
+:103C900067C0EEC16E172B5FA79DF5E261099B7AA5
+:103CA00056A1F2DAB37478C2BE78369B4AF36C3E02
+:103CB00095F56773A99C7EF6122A679C1D4D65C316
+:103CC0005900064C9CC6B3A554CE3C7B0595B3CE9B
+:103CD0008EA772F6D9ABA8DD9CB393A8BCEEEC1707
+:103CE000A8BCFEEC142A9DF68FB15E25F96DC92F94
+:103CF0004BBE3BE5B725FFFEAFC9EF58C345D93FE3
+:103D0000A0FFBEAA9D477E8F242F80AFEFD3D2E5C0
+:103D1000444A3FDFAF7D06BE3E2EF814F8F73D8CD7
+:103D2000C378C08BA3385598C7A9028666609EC623
+:103D30003E6C025BEA2F8D9CC4B841F3028F1E03D8
+:103D4000B8074A35924FDB821A9DBB6D96F4D15C61
+:103D50001E2413487F3B431A8DB7ED8F8A17F31744
+:103D60005E1A5510C079BAFDB28EEDBF959BDC7717
+:103D70000B9EE34F61E14330DE8A3D7B3CE97EF8F8
+:103D80007E340E00BE40EC69C680AF378EFADD523D
+:103D90009CCF3795513C064A3353BED837DDE27C81
+:103DA0005A1D0A219EB6FA64D207DDBA47E4A1265D
+:103DB000075AD0CFAD93D9369877C3E877B620D8D5
+:103DC000EAB8B21D6550DF5957E6C54D7AFA950F2E
+:103DD00042644FC03B0405CA8428CD1CD89F4E6F57
+:103DE000D838DF799B620CAD4362C5FEEEEA91DB09
+:103DF0006DF20F84903E3A264DAEBC05E6EF9D5421
+:103E0000301AE7DF5E73D4860F45B7C753140C38FA
+:103E1000A21F5E97A4B8DA06D9D85106EB0B887CAE
+:103E20006B00B33292967760C1A184611D1CAE8491
+:103E3000C2D7C30AE0796E5D2296E4EB3531EEEA33
+:103E4000F32543E82F2A75A729DED6E94F2EA2BA1B
+:103E5000030E6BFCDF6A565E00E71B9FE09BE649A2
+:103E6000DF5E4479E4551AED5BB76B6801D6636B8E
+:103E70005DECF10CF19B0D829FB7559E3F2EA3FA8E
+:103E8000EC70747BEDFEA205CFFBA274C2D1EC1ADC
+:103E90001A9569FF3EEDFC175AF7E73D5FE708F911
+:103EA0000397BBEDFB1010F2BC79CAB743782E6EB6
+:103EB000C1D329C13ED47CFEFBD03C85CBEBCF7B6C
+:103EC000BDFFD3C6FDBDC6E32AC0A7B3CB31CE38F4
+:103ED000667208E3B53E2B1E1D8E537E5200E3D161
+:103EE000D4CB203DA4EA7C0C456509E44339FBC3EF
+:103EF00004EE9352AD190AC9D9CCFBAE8437515E9A
+:103F00009B933F2DB8E96FB2301DE8FCD06BC5A77D
+:103F10000D7532BF2F81F15F8559E7B33C3E6DF5DA
+:103F2000572B648A4753203B6D1C15F4309EE328C1
+:103F300018A7CE1B3EFF7753F4689FBF88C7C715ED
+:103F400095FB81EF491C1FB15715CAF7EC7A9ECB40
+:103F500037769C91FCEEAA35E85C6507FC8FFE4342
+:103F6000ACD61747BA551CF978672AA787508E5ADE
+:103F700071719A8F9F0F509C1BF314296E6EB00ABB
+:103F80007CDF2D40B3C651ADB87CE59A49D8CE6FE1
+:103F900030CF73B03E7F1D4B5C02F006DDAD5B2F72
+:103FA0002FCD100FAF5CF38D2761DEDD4F4DFFD5B8
+:103FB0009350DF25875FAD8376F95FAE23BC3AE38C
+:103FC000E1DB2A655347F9E0F31DC27D051B9AE842
+:103FD000E2D61E2986CFB37DBE837CBF5B430AE257
+:103FE00005F424E2C5EBCC8B4CC77719C2B17360E2
+:103FF0001EFCDBBB75DE329C17E1C6FCCA15BDF5A5
+:104000001AEA99E012FBF985BFC95EF756D9E1DCDF
+:104010002AF6EF42F4EFCC43EC31E72D42BA3D13E0
+:10402000D418CA9B8D6BAFBE91E4FE76858D2BCDE7
+:1040300040BF8E75756A2ED2FFDD46FDDE0AD41BA9
+:104040000D1AE5F574C7BD714CF1DE5E973A37B1D4
+:10405000D9EF86C6CFB16AE4843B931D2FCEC70249
+:10406000E219739C8375CF96C9AEE9EEE1F358E38C
+:1040700075D7BDE5413931D2B84F8F318FB8D19E58
+:104080008AE65DD4BD8BFB36BA385D4FD1E252294A
+:10409000DAA3FAC24550DF3C4E267B8809FFAFFB0E
+:1040A0005A7E9EF8B066D8EE576C9AB292EC869B18
+:1040B000DCBAE02FB00B27A4EE5B1CF09A2FB8E11E
+:1040C000B9FA1C8C04F6C07BB9E11B912E1A831F30
+:1040D000911D756B91AC237DADD8D348EBDAACCB99
+:1040E0002C8176AFDA4A466A136B35F13C00133502
+:1040F00091EEE6C01B99EE45240F75029C73C61520
+:104100004EDA063577512BE5B1341A12F961D70131
+:1041100066501EB4144754A90AFBCD7F07EDBE3983
+:10412000C15219FDFDEB54D6A0A5D9E760171F7346
+:10413000A7ADEBC4B83D41B90AE7877970FE451ECB
+:10414000BA4FE046FBF8CA947D3C1111996627FFEF
+:104150001A8D4A8C6714257E4F79DEDF4FCA382FBF
+:104160007B81556F933EB95F0DFEE52F713FE3CC28
+:10417000E8C754C3CF1A97F8BA26F649DC5B39EC86
+:1041800089FC06C7B7E20113357EBF79730B0BC7F5
+:10419000D2E22A9B9FFFF3E368AF5AF197737977D6
+:1041A000024E0BEE4D12CB223DEF89FEC19DEE1764
+:1041B000B364D9DC099F1FDC19F2E57CB5C04F63FD
+:1041C00005FFE4D55678516E8EC57C1FDC87762EB0
+:1041D0004F4CF82F3DDF4711CC170CB7F6CBC6700C
+:1041E000B9A4887B5340D712DAB1CE7C2005F37E88
+:1041F000260E971B0704FD5FE211F93F93D964EE89
+:1042000087DBCFAFFC4BB9DE67AD7919EFA17E5FDD
+:10421000E8FD17855F9910F71A8F8A7B8B2FAF33D4
+:10422000C8CF7B655D259503EBC2F4FCB57575546D
+:10423000A6EE57F179F3851DA662500DCFF97D2CBE
+:104240006E00BCFE516B064A91CFEBF8FDEEEEA678
+:10425000535BCAC96EE4E7169B8BAA1385E8BF00BF
+:10426000ACF95077F9FA3CFC9E97395859C0D51CE7
+:10427000E2FDBFFABCC24917BAB5FF8EFDF6B156D2
+:1042800086F22E60DAF73B3BECF46FF8FEBB8A2E29
+:104290006EDF7BF11FB08F5FB2F6FD6A7635FF3EB1
+:1042A000C3C5C963E4A34A2107C6003F1D007FDEE2
+:1042B000ADF07CF57C9EE76A8638BF992AAFC7C609
+:1042C0008BF62E4E426C208FE7B517F3F304EA8786
+:1042D00079E5F81EC3922FF0F816CB11F9EF63C5FC
+:1042E00038ABC5B813ABE9DE2E3FFF677D3A963E8B
+:1042F00096A47A2EF0019641D62A2132C7B041F217
+:10430000B78BA521AA1B929E85F532295CC6FDF0CC
+:1043100038E9CF72C5FC7605213F22F3785172311E
+:10432000D993A097512EC6D5C822942F1BDAB4304A
+:1043300060E25C9E1CDE9FC372435FCD009E7FC423
+:104340006232C91FE53996A55F49F61EE9AF0DEB4C
+:10435000F30E6653BE4692F2DCF77B4A6D7A6AA290
+:104360006FE1753AECD746914FE782FE2C43FEA9E8
+:10437000954F07E396647A6F951BFDDAA24C7EFF9A
+:10438000C31E49C43392A3290E28F6353E55CE7874
+:104390009F719F87DB358F9666B6A7197B90C6DB2A
+:1043A000EFD11DE3265BE8FE8CCEE31B592E93F282
+:1043B0006B36B6F17BFA16FE46835D8BF6F0C6BE11
+:1043C000F9B391BF63952AE59BC3FA7D883F97C8EF
+:1043D0004BDE383E78309BC7254A514EF723FE6AA4
+:1043E000D3F0175CD984F8EB7895E7F7823EF7B104
+:1043F0000CF98616FE5C3EF6C54CEFADB26394B682
+:1044000028D3BDE1A31ECB4E4F96723AE1F8CBBA4A
+:10441000568D646A9F10F82E2963D1F3E1AFDFA3B4
+:10442000DBC6B5CE7D9511E25D922F4171AE891A42
+:10443000B733362CE678DDF0FC35C7A369E710BF4B
+:10444000C421A7A4E2C156DCD8D29BED9EE83F7AF6
+:1044500046A5F425FB3E23B9CB5EF01CC47DCB7092
+:104460000E71CA539BE11CA2E7E2BEEF3256F0ED9B
+:10447000A12D47E7E13C7F55C7C8BE0A3CC3E7CD45
+:10448000D5595C2EC5EF149812C659AE89E8F56867
+:10449000BFB9DA9989F9336345DCA6B0BD4F41BA9B
+:1044A00008C25E164A78AF2919C3EF998CDDCDC8D2
+:1044B0004F540B67AE5A6F08519A961FA5B0A17E54
+:1044C0005A5FBB663C5E4A60FD14F5C318F13ED0EE
+:1044D0003EF3572837C744A294870BFD627EB42F62
+:1044E000041E0BBC9C6F9737842509DA0783498A21
+:1044F0004F3AE5FA18C0CF2569F65B40D4D92A2E89
+:10450000A765F80FF57C7EC42EB7C739EE45071CAA
+:10451000792FB95E91EF6EC9ED22BEA913D441394E
+:10452000935F9ED2AF0EF8508655A7FA07ACFA6794
+:10453000840F0881E8D98207AF52A2DCDDE3D2BF45
+:10454000F214EAE77A8DE79189FB72D902EF3E74A3
+:1045500098A1DDC094574CDCD71D61FE5D9A3353A2
+:10456000E7911F9A5D67DDA7E3F795A18C619C2E0B
+:104570005BCC6FDDABCB66C69BE5400FD96692EE98
+:10458000D5E9D677154C96C03C1CDD27531E9DEE11
+:104590008B907CEA59E0D1F13B1F9AB8A7E712F75C
+:1045A000C7B3CDD374BF2E7BD8FAF8FD3A0BEEEC2F
+:1045B000ACAA37CB0DDB3CEB31BE0D6B1F9DF17E02
+:1045C0005D1DF793B24D1E87481B9FEED7ED985A9D
+:1045D00066BB5F47F3A01F27E8CFBA67E784EB5CB1
+:1045E000BF9ACC76DA84B0DD8EB8D0FD3A57C8DEFB
+:1045F0007EC705F2B33EF1FD3A818761ED1CF6A05E
+:10460000CBB24347C90CF7EF4C834CDF11C9FD28EF
+:10461000199921515C82F4BD65E7E5F1A1FEDBD972
+:104620007979565EBFC3CEB3ECB7DCD9767C3BED6F
+:104630003E775584FA5CAC9DB70BFF01F4F290D73E
+:1046400061E73565A60FA7BCC86783BBAF84718ED1
+:10465000D6FE48C17CB55DB9FCFB476C987FF0D6AF
+:104660000CDA171FFFDED1AE29FD2A7EFFE6774B5D
+:1046700019D949561CC12D60DE5524AFA7B07BD790
+:1046800043849FA0C043137E80AC8670151F477C77
+:10469000667A316F21BF8951A3C28A30ED3B7E9685
+:1046A00040A64B5B3115F5783D62250D4F333CF646
+:1046B000EF0434EAF98E7DB4EFF3B973F007F9F73C
+:1046C00014E618F67DB7FC24346771BEEB2BED744D
+:1046D00070428A0C2AD0E5E9AC5261FF0CEAA82F9F
+:1046E000BBD7BAC86E7C6849D9D62BD15F0DCA3A00
+:1046F0003F8E1C1A87F651F351D38B76DEF6C874C1
+:10470000EF3878FF50871246F3F0A9256B5EC57A23
+:104710006CB78BECA0A7FAE615AC48E3BBCDBB1792
+:104720002C5C8CEF3B5CA4DF57ECB96FA03488FDA8
+:104730005DB5E9DF9B6AD9789F8E7EDB1BB5DE8C89
+:1047400076CCD559DC2ED9A82529FEB4719EC6D0C9
+:10475000E5DA58523F7A05DA0FD76819EF93DF95FB
+:10476000E5E6F7F95CAD12CAF7C268E67B0156BB15
+:10477000B135BFA5738CE06C99A11FE7BA7E9E8C02
+:10478000F587605F7529454F79829E3616DDBBB58A
+:1047900002D73790F9DEA155AECD1AC7E93462E7EA
+:1047A000735761D3685CB7CB1D19A847E22A94758B
+:1047B0008C8BB8DCAD919BD11EBDDA8514CE3677DB
+:1047C000FCB06111EE4B58D2259827A84656119D92
+:1047D00005B318EA8386259156C44B21E83F0CEDBA
+:1047E0001516FD92CE290AEB34E685BA67494FC209
+:1047F00005EF3D15D1AB10EF2FADE5DF79290CFAB0
+:10480000E85E5061849FC315B6BB199A0C1BC105A5
+:1048100076917F20519CC8C947D6BA9A977239BE03
+:104820007BED6F4765FADE4C455619E1D56BD8D75D
+:10483000ED41BD0BE34C35079710BE6BDC2C4EFCF5
+:10484000EB26FADE55EB22B8764D39F91584EB7775
+:10485000BFCFA2FDBE969912C2953FC4CF59AD7984
+:10486000F29B06151E0FE77CE8E43B8B1F9CF0EDE6
+:104870009C3D8FCEE336B3C1F988EFD85999E868EB
+:1048800073D11A6F7A5CB455D01FEC03C99798CED8
+:1048900068BF957F65EB311F76E3172395C81F6FBF
+:1048A0007BF9BDD5FB966AB48E87E66A146F7CC827
+:1048B000DF4A747F6AA32B7C08C151F585B89FBB82
+:1048C0008B2BC2186FFB3B3C7C4EF30F768FFA525A
+:1048D00025E2F38B7FC8E2E34C51AD717E46F45E76
+:1048E000EB25386728ED3F5B8176E8127932E54E9B
+:1048F000AF5A42F2CB25E4F8CB4BF2EAD14F09DCB8
+:10490000B09C7179C8E31481B5D5FC3E8343EE2792
+:10491000EAD4DD33689778FCA75EC8BBB1374CAFEB
+:10492000C775D60BBD60AA99BFCB982BDA170E4579
+:10493000D0241B16FFC915FA63EC6EC773A117725A
+:1049400087C5C1072B6E06F9F3A52C61478E10F7BA
+:10495000D9B5641EF1C319E0078A4B979C24FA8FDE
+:10496000819C40BBF90D29195A91761E667D67EE30
+:1049700027221E14314B294FF82D110FFAA9F8EEFA
+:10498000DC3B221E745CC4837E2EE241FF80F1205A
+:10499000FC7E98F772DAB771751FF5631C6767CDF7
+:1049A000028F01E34CD5075F4220BF680EFA44FE38
+:1049B0003DC11BB4F4D0DCF3C7A91208971BE35226
+:1049C0001CCE97C5F7E85E11700D08B85E137059DC
+:1049D0007A10E506D2191BABEA99E461506D95F0A7
+:1049E000BC17E5457F90E405CF130FAE918C09C34A
+:1049F000E5048C373ADD4EB7E8EFD4281FD1B17308
+:104A0000FC47B3F8BDC397D6CEDACF8269F228B29D
+:104A10007015D25D3EEC0FCAA3681397E351BC77C3
+:104A2000912657AD781AEC4898F4CE0D1C4F23C947
+:104A3000970BC99542875CD98D7205EABB51AE04CC
+:104A4000D3E54A6B3FAE3B887285A5F45030F2C97E
+:104A5000E4CACFBC65B63889255FAE0636263B3141
+:104A60000CFAD4FFE9F5E9DB424E5C48AF5AF91F76
+:104A70000193915EDF837921E8CF8C67740F473112
+:104A800007299F28B7DDC5301F642B76198DFECC12
+:104A900042CA07D931DFA3235D3C2C254288CF7D54
+:104AA000528F97EF8BDE8FF6C2B6093C4EB2E38F82
+:104AB000F778D1CE7EE9F682009EE3F4E65A7920BB
+:104AC000FAE25BA17EAA91119DACD8B3C296F7F031
+:104AD000F3AC3CC2476E0CE40FE0E3E1DBB9FED17E
+:104AE0000D9E070265C63C10B74FC483D45808E931
+:104AF000639B14F5501CA651263DD51BE6F92BBD32
+:104B0000E097E3F9606FC3CE39A89F37DC2A33CA38
+:104B100017AFECB907E54CC7848506F2A56B74D9CD
+:104B20009B688E6FF0C9DEF43C523C4ED0AAF9B9B6
+:104B3000A128CD1C0079B3D734CE777F54157E1FC2
+:104B4000F6779F270FBE3337341AE304BD8D0B432E
+:104B5000386FEFA848288FF253C6903DB071D4A6A5
+:104B6000C5187FEA58AEB1743B69D87C41BB7D6DF6
+:104B7000C519D5069E3FD22173FF32579C4F035F64
+:104B80005522DED2D78970AA26CF1FC1F52A7CBD57
+:104B9000F47DD3DC06F00FABF8FAD17FD57DFA684F
+:104BA000941F6A03CF1FD9ECD717A3DFE884C31A79
+:104BB000FFDA6CC9E61FE956DE42FD1A7E8E58C444
+:104BC000F3167A5DE7CF5BE810F2D0F21B47C2879D
+:104BD000CB714EDDEBB5C7012D78AE14A5138E91C8
+:104BE000F2053EEDFC175AF7E73DDF4879046BB25A
+:104BF00025DBFD8A5C2B9FA5714D08E58405CFE67A
+:104C00000BE48F7C5AB89A1B79FBCF7BBDFFD3C6D0
+:104C1000ADCFE6FA11F87400EF51764C9C19423989
+:104C2000948AC70C0D94A33D27EE335AF9232E9D89
+:104C3000FF5355F977EEE4EC22FACEB23A9DE78FB6
+:104C4000D05F863C904D8CCD467F4715F11B279F4A
+:104C50005E087E67DEC8CD3EE137461DF3893C1114
+:104C6000E6C83B51433CBFC4CA27E992607DC154AA
+:104C70003EC888F33AF0365EC8FDF71CFD87AD3BB1
+:104C8000CCEF575AF927C3F248A6CAFB710B86E549
+:104C900091887C949E5C23CEF3C4795E09AA4D8CE6
+:104CA000E70DCB23993A3D84DF949C5622FADDC070
+:104CB000E8FBBB3D5E5EEF9DC3E2F8BDB35EAC2397
+:104CC0003FD532CA6B19965F32750DE14963916524
+:104CD000FC7C879FF75B7870E6975C90DE2E9047B0
+:104CE00012F459DFA388D03C3DFEF04FEA083E990C
+:104CF000CEE30BBE743C9C3EFE253E2E277B441E1D
+:104D00005E4FAE3D1FEF3EB12F15A29D737FF52282
+:104D10004ED75DF53AC5DDDD0D3C5E39EC3B103517
+:104D2000767FC019CF3B21E4F585D6EF8CEB6D1B68
+:104D3000E1BED9021FCFE37A68C921CA8B3DB30A0D
+:104D4000F42CE0EB61CC67A9B9F87C96D7B3783E38
+:104D50004BAF51BFF052D463518DA13CEDC57C16D1
+:104D600078BFA161847C16114FB4E2A323E5B3E4BC
+:104D70009E3B8FB7E7B3F4DECAF3597A7BF83CD693
+:104D800078BD0DD564678D34EED3634CD987FB5F56
+:104D90007171E7A7D34A227F86F92B3DA59AFEA021
+:104DA00081F4C2E9B9AB5123FAEE72713F36369AFB
+:104DB000FBCD4C8D8716429B2DFEC4228A278BBCCF
+:104DC0008C5E717FFEEFB30C9B7DDCD9F8DD10DAD1
+:104DD000F540872FEB9C4F689C7CB5743DD880CC08
+:104DE000ADB798E8530E64F338822B746CA02E8D07
+:104DF0004EB7087D87F891013FB9D2397C45E5026D
+:104E00008AEED3DF1A419F6F64F3F92D3A64EAA466
+:104E1000303FFF631528472CFF75583B0F6F374C09
+:104E2000FE38E4480FE6B761C592273758F2C44E02
+:104E30009796FC600E39734E9ECCE176FA39790272
+:104E4000F2033F75E69443BD5EAE2F2C78DC2898C4
+:104E5000418EBCE70ADBE2344EB973213EFABCE571
+:104E6000CE4BD9F9C2FEE0722788B4817C936D9D48
+:104E700023F27B0F67A63E48F2D0A3F2757B228C0B
+:104E80007E2700EB28CF3D788E9251AE574B146FA2
+:104E900010E722F9E2FB830FBBC2949FF630F03398
+:104EA000FA79130CA77D76FE7305E779D2C36BBF41
+:104EB000C6FD33C037FA5D172B872C39F161365F99
+:104EC000F739FA32399C167DA5D1337D5FC0A25FD8
+:104ED0006B5C8B8E193268C179E855D03586A32971
+:104EE0004E1D93E21807B1F2C8ACF1DEF0717B649D
+:104EF000A4FB5556BBEF587ED7B978B01ED0299F7A
+:104F0000AC87EE9BB32E4E7F73D86E754D15E513AF
+:104F1000A88CF2092225E8CF1CF6D9FD622B1F6C64
+:104F20005A493884726283B0D3AD3C322B2FEDB036
+:104F30002FD73A67B6E5A76D18E17EF69BE7F073C9
+:104F4000F1DF3FC1EFB6ADF69A8FA35C047C99E226
+:104F50007B4E9487668DFB5D81A7D73DE693BECFE0
+:104F6000707FF2C52C7BDE55A7CF70C405385E2755
+:104F7000EAB17ABA8F17E5F7AA9CE7EA23DD7F75D5
+:104F8000DEDB3B77FF559CBF377BA22F13FC2FF254
+:104F9000FC373D1C3DD8C93EBFF51CF09A3FC1F11E
+:104FA0003B057F4F0BF27B3BEF7BA26FE3F3EB18EC
+:104FB000F7AB2D3BE730B683FEFE97416A03BD6C2D
+:104FC000AAE5F45A54C9E8FBE3D35B797DC752FEE6
+:104FD0005DD3FED7F9BD8F6D51FE3D53E8D7270352
+:104FE0005E768CE7FA707F15EFB71FEF37219F567B
+:104FF00070BB2B0FA3F70A8AEB2895D36B7ABC13EF
+:10500000E0FD81A532C545F708BE083093E21CDB00
+:105010002AF93CBB2AE427C4F76816DD02F5CED98D
+:105020002B27E3FD92ED229EB26FF1CA2730AFEF3E
+:105030008340B9A0BB04DD7BED397E1BC5471E5AFA
+:105040009227AD8435EE3B9839BFA5CAAF8A7E3131
+:10505000B788278932A161B9D51479ABAD4C7C8F63
+:105060003DA661FCE999419EB7DABDFA99633351D7
+:105070001F57CA9467D63578D47B19AEBB8EE7F537
+:1050800014A90929DD7FF1FA5DDC4EAB39EA31AABA
+:1050900086B77F66F028D1DD76C0BB92E6FFC902F5
+:1050A000CE6EF427A0DF5E57CFC04C68B7775C9E0A
+:1050B000143352ED46FB39FF752F91C577E8197D02
+:1050C000C7A1D33CE541B9D989E71FD0BEBBC6CA49
+:1050D0004BEDA17B597BE74C9E8379E2DB6EE0C10F
+:1050E000D2AEF021F2937B6673BB6CAF04ED605FD0
+:1050F000F6B568D7D33DA6561E278232639CA81703
+:10510000138111AFE2DC8E525F60DECE86BE019C61
+:10511000A7A88E7FDFA2A82673FF17026EEABFCF73
+:1051200015A3F8E748FBF7AF3E8ECFCE2A7E5EC0D0
+:10513000589CE252BB85DFC5D4A891FE9DD0960055
+:10514000C7CF4E1733315EE6ABD348AFCB6183ECAC
+:10515000503FD88F188FDB26C516637E486C92C6E9
+:105160001E278C98DE7118BF9B901746FADB24250A
+:1051700042F85DE5D8381EDF3E1AD949F7AE0E80F9
+:105180001D4DE16096203DD51DCDA3FB504723D595
+:1051900083D4DF57A1BB2D8D8279F3F4A148C626B5
+:1051A0005DB6692BDA359D53641DF3363BA5FA28AD
+:1051B0008E17CBF5501CD935651EED9F6B549E9410
+:1051C000AE8F6EF473BD30342172A31FD6159A7260
+:1051D0002A17E396DB6B5FD987FBF7C8FD1EA2A3F6
+:1051E000476A07EFC679F69FBDEA7894F8929FD791
+:1051F0003D5A7BBA14ED9E5D4DA772117FC5189F75
+:10520000037D585CC1E368A801C93E537BD8CD80BB
+:10521000C7E2368D1969FAD8CBF8791EFEF92693C4
+:10522000DCA3BF67064F795A70BC252C7169809E3C
+:105230007B309E65C999E23A96280079B87FC53BD4
+:1052400031CC937B646201DDA32C12EF4972C278EA
+:105250002562BCFE375E598FED1EAD2E30505E14B8
+:105260000F0CCD4325515C759AE26C21EBFE47D4BF
+:10527000D87F2BD1A74CDFA92C0EBFF317B88E8097
+:10528000AF8FF41CB4A7B899731D8189E67D7EC0E9
+:10529000E337A5D657C70553FE18FD213FDECBEFF8
+:1052A000651767FDC35C252DDFB644C40536498309
+:1052B000B3C92E7D80DBE163599CE45C7155EC6ED3
+:1052C0009E6F1BA57C5BE7BCDBFDE7F4AB44F7A856
+:1052D000F39BC4BD12FE3B3625E2776C9C741F0A1B
+:1052E000E557755C95AAEF8B9E22FA7F5A33EECA7A
+:1052F000F4BD877D422E6C12FE9835FED85C3EBE12
+:10530000557F54E7F4F8F4CB79D757C17AFEAAADAC
+:105310006C12C63F778CE0C7AD0C70FACB1E000B49
+:1053200007F440FF6BAF79319FE56999AD4239557C
+:105330005F95F024AB041E617CF2C560FC03E16F55
+:105340007B502E7D35504970AD98CAE3069D550FB0
+:10535000D2395048E77A07F913E5BB2F149330EEA2
+:10536000BDBC86E98744BC2506F8A7BBF3324BE5F4
+:10537000F56FCF253F077885DFABC1DCA4C9E2F725
+:1053800027CAF19C68D3DD227F56467C778A7980D4
+:105390006F699E0345629CFBB8FD8FFE05F62F17D3
+:1053A000F394D77DF76BA8C78B744E1729F8FA3C96
+:1053B000045FABCC083E35F12AFAA1DB271518486B
+:1053C000370742E1B79BA0BE7C914AF1F8F21A0E72
+:1053D000C78156997E0FC85FA71DA4FB6326E88B83
+:1053E000347C1962DEA29A8484E75A462B5F17B494
+:1053F000F3A25C34C2000FD40DB1AE73F04FD208EB
+:10540000FE22CF20E6169DC3C34A1C0FE877651D18
+:10541000EFE70FF56D4139B6BC8EC30DFA9DE0295B
+:105420000A6B0751DF1785F878CB013F87A4145C1E
+:10543000D9165C7532E55F15D56807D10FCE16F029
+:10544000AD0C7378FA5F3F3520F1F10C1C2F5BC077
+:105450009B2DD64F09BB05423FC0784FB912F57856
+:105460002FE7D414661CE2B3513CCB7ABFAB15F0E6
+:1054700000F8F18B79D86E37F1132C31F6B1CC7F6F
+:105480003FC4488B5B54ECD66C75BFD83FD6C59FE4
+:10549000931F472A91D765E1D7ADACB2F763356961
+:1054A000F532BC5FC6E97DFDB5FCBCE3C0046E1FF0
+:1054B000A1DF718EBF91CEA7188F7505F1BD46FA99
+:1054C000AEA4DD3E6E716BC174940FC5030FCF9314
+:1054D000613D45F73259C9217A96CEC93F98EFDB35
+:1054E0006B12747F367B209287F2AEA4356F3A7EC2
+:1054F000FF2D7B204AF5EC815693E79F810B938724
+:10550000F97A69F394A29CE6F974AC55EB43B95669
+:105510009B0E27BC2F79B9672EF6DF7CF72BA39162
+:105520007F0B1CFD3D39DC7F287E195A0570FED3A8
+:105530006BB1BD15DFC94688F3A87C19CB621FC8C3
+:1055400063284B44FE9D252F3A27BC3329EA13F4E8
+:1055500043F9782C916EE73B4B683F5EB48F49E787
+:105560006D779ADA8D146F1A08F0785340D8AB3DF6
+:10557000CCD84FFABD86E77BF8F039E88FBE9AA306
+:10558000D3693FFB5818E9B9B8ED4FEE74797D73D4
+:10559000A054DC834E10DD6B255974BE077C4CDFB4
+:1055A000373DA0B6D2396B5F113FD73C3AE71509BA
+:1055B000F159F41CCFD3B6ECE5E93589103EEF7A0A
+:1055C000357A19F1E708F6A7656F3AD77349FD8375
+:1055D000240FC6469917CFD7FCAB55CA632D890255
+:1055E0005C55281780A40B01FE9AD87AA41B23CA05
+:1055F000EBC66A51AE82F26AB06FD70D94FFD295B6
+:105600001A776B05D8B5683F0DEEF6DC80F64A2BAD
+:10561000582306DA8BA73CF83D95EED6E9F988E7E2
+:105620006722967D999070FCA29F9A642FD6EA9A81
+:105630008E719809EEC4E8F473BA0373DEA9A6EF7D
+:1056400089CDBFB87CB291F409C222A7E991FEAA24
+:10565000A3A45F9EF08F273D64E9154B8FD088206F
+:105660005F6E117CD465243C12C92BE05D80F3167B
+:10567000942340C7FE222ECF410E733967E993BBB6
+:10568000B9DEB7E4678518E71694B7D0AFBBF689E3
+:10569000DC1B50AE0839EB0F1933F17CAE42C85712
+:1056A000A6C6249CEFC014FEBDCA80439E56B4F229
+:1056B00071BA428CE809F4D041A49B034509BA278A
+:1056C0007EA0F5A8947ECFD4D27781D624C3FD1FC7
+:1056D00057C7E5E0382157BFE337387D7AB85C3DDE
+:1056E000A7F784BCDD6A1E65E2BBB019F3B0FE5EAD
+:1056F000E8F39E8A43E4176CBBF514E1D38A8786EE
+:10570000443CB4BBEA2D7ABF3DCAEF01EC32A7CFCF
+:1057100021F823CB35CA3FAD393AA70CFD8DA6E55C
+:105720001ADA75270305D6F9977721DA93ADABC856
+:10573000FEF5897D7C28CC84DFA9919F75DFD26F2F
+:105740000F60FF10F84592818DFA3C6EA473FC9EA9
+:1057500002E23B3A489D7D35067D07C2B98EEF05D2
+:10576000F87769FDD1E4C038DA5799AEF4F86A18D1
+:10577000F99DCBC1AFC36177AB61EF0478BFBB4983
+:10578000D6D7B354FFFF15E0F96813FDFC9EC2CED7
+:10579000C5A7B7609C6FE752F19D3307FCF735F65C
+:1057A00079149A07630294C79CF17BFB55FE2CFE8B
+:1057B000FD859ABE01B4E703551CAE170306C7FB6F
+:1057C00020C7634F44263EDA3558ED457DE7B41BCC
+:1057D0001FC97E7712CF6BB1EB9B0BD58B1D727FF0
+:1057E00082BBEF3A9277DF94495E31C6E59DC4648F
+:1057F000037F57A325C0E9A94AC8EB0E57623FE6CD
+:1058000015743CEB63EB8D145D1489313B5BE58CC7
+:10581000BF9F7628A0F0FD1FBEEFDC7E10FBFEA42C
+:10582000C0C385F61FC32C684FF7C5378DB903E594
+:10583000782BF79FFB126F51DE51D1EC85E4F71CFA
+:10584000397829F9034555A6EDF735B347F05B2BB9
+:10585000723CE78D078C248FF7ADEE203F7BDF6035
+:10586000E67B3105393C2FAD0FE4257EDF64A4F9DA
+:10587000F51CCE7FFF14107437E71DFA5E469A9E22
+:105880007D59E859D2B7C52A8B2969790E1304FED0
+:105890009CFA93A971CFA53544E784BF7DE2FCE271
+:1058A000215326BC5B748EE7078857588729E890F8
+:1058B000CE377A58DC837C136BE2791E4EB827F81A
+:1058C000E58B5A5F3087FB21E7E613FEFA443F87FA
+:1058D0007B67EDFD74CF11E60B217D483FF88FD338
+:1058E000741FEA5917FD9EED8C675D098C69DD799F
+:1058F00090FFDEA2FCA297E0FCE7C3FCFBEA093FB5
+:10590000B7C77EADF3DF2BFAAA7BB0FB0B501F7A33
+:105910005661644FC6417101BD9E16F4CA9EE3F5FF
+:10592000955E5EBDF360FF321C6FD5733C0FF3CE06
+:10593000E76FBBF10B50BF6DC0457706EE7C7CBDB9
+:105940003606EAB7C7A53EACFF663AA3DFFB8CE597
+:105950006914E7FA4D60B06001E0FB83751E665C78
+:105960008671D2C182F980873BE24FCFC47E773CFB
+:105970002585916D673CFBF82BA301AE3BBF215100
+:10598000FED7578E64DBECC2D3B09469F07ECD4174
+:10599000FEBB91B7B19E99888F3B1FEFA5DF3FB447
+:1059A000F0F9C1BA4A66A4FD6ED89DDF789A7ECF21
+:1059B000F0AE6F49F4FB8A77C9FC1ED13F3FEF5D23
+:1059C000F4980FD7B75EBBD48FEBDAAC61BBDBE2E8
+:1059D0002DDFC594A63BE207B599F0FE8E0307B50F
+:1059E00095E897B95933EA9FAF1CB9C226774EEFB5
+:1059F00053C83F5893EBA1FBF5CC6786E64D18BE24
+:105A0000CF1FAC6336B8EEB0E2046A5C9B9BD6DE77
+:105A1000A573FFF72B4714DB3C961D103BC6F542E0
+:105A2000EC6FFD143FB7F66F8DF0BBADFD5B63050A
+:105A3000E2D5A1C999E0E9C6FD00787AD6E954EE2D
+:105A40005C17A272F73A83F6692FE211CA2E01772A
+:105A5000602AABC7EFF3074C9E769CD764D6E3DD94
+:105A6000B2BC08AF172C89921F32921D63957B5DE3
+:105A7000D116F4213B77F4CF52C1EED9AB45EFC636
+:105A8000C897DEF1EAAC06A8FF4D4E64630EC99BD1
+:105A9000B0817C67F9E75FCFE17277D3688DF0BDA5
+:105AA00077E9E4C714CBFFC2B8DFD2954FA03D0120
+:105AB000FDB7E710DF86E93B5D23F52F585667EB0E
+:105AC0005FB06C95D57F0FF5F79CBFFFDE65D7D82B
+:105AD000E75F7687D5FF1182DF777EF80B9AA7DA2A
+:105AE000E76F5E4DFDBFEAE6FB3B94EBA17CFA0E4F
+:105AF0006F38E122FF99D1F739D4BC4B0FD1F7931E
+:105B0000CEC599064DD4B3BEA772AB518EA5E86839
+:105B1000FA37711D7EE0AE743ACAA9CBB2F155AE28
+:105B20009967ABE7CF1E636B3F2A52667B5FB8E88D
+:105B300072075DFA74CA83655C9F9A18E70438B5EA
+:105B400031FC7B4DF5633CB4BEFB5FF452FDFE6B54
+:105B5000F8FAEE1FE3233E26DD05FB7EBF16BD32BD
+:105B6000DD3E86754918F27A468F0EE4D4A63F379B
+:105B7000647C9EA5F0DFB1CB72737DB9B974F2631A
+:105B8000B1347C6E29067A80FADB399A2DCEB3B90E
+:105B90007865A8256D9E4DC5DAA24355FCF92D68A0
+:105BA000C7EB91BFC3F9BEAA0D5D8AF6AB731E7732
+:105BB000599D6D1E4FC92A9A27E998C75DB2CA310F
+:105BC0008F67D121F15CCC730AE964A47936975DC3
+:105BD000635F4FC91D34CFAF719EDAB4F594DCE139
+:105BE00098278BAF079E8B797E73DEF5944FB5AF08
+:105BF00067EC6A9AE7DF1DF3B8C7AE76CCE3A3790A
+:105C0000F039CEC38AB81FA5B98756D2FEFFC0CBE4
+:105C1000300EA4B9A37F4D9754FEDE4B71616865C9
+:105C200062BBFF03D8CCA6FA008000000000000091
+:105C30001F8B080000000000000BE57D097854452B
+:105C4000B670DDBEF7F69274773AFB4208378010E3
+:105C500034C40E840C203A0D41061DC0E00A2ED03B
+:105C600061C99E74449C87A34E1AA28888DA286A68
+:105C700050601A04071CD0C0040810B001757006EB
+:105C800035BEE7B8CC82CD2241884983A8F866F1B9
+:105C9000AF73AA6EFADE4E079837F3FF6FDEFBE3B1
+:105CA0003753D4ADFD6C75CEA953D52427819051BF
+:105CB000841C8CA3E90842BE89715FEDB012F23DED
+:105CC000FCFD90D03F2F21C93C4D21642EE17FFE89
+:105CD000C5022924A4D6CCB273364FCD5A08694BDD
+:105CE000515A4901FDC70A9BF30A8590CE9622E3DB
+:105CF000ECDC707F6A3AD7279F0CE6B0B6DF93F0F2
+:105D000038DE7124A78E8E5F16E7C0F9A8F993F5E7
+:105D1000346F22E4583DC1B45D26338BE9F713F5A7
+:105D2000740283B5F35D88ED4E4AF49F49345D25D6
+:105D3000F8BD025DD7F20F64320087F93087AEE319
+:105D400076BE8CB9BE5842CCE179784CC405ED42A0
+:105D5000BB4CFE75027C75F531A4D1A43191107550
+:105D6000BEFD09F9D3BEC96F0B76CCF6318C24E4A5
+:105D7000CE255BDF826A1F09257DE7D1F54E6B5E7C
+:105D80002EF7A1F94E3938C369D5F4334D3E06EBF1
+:105D900036D3FFA09FE96E9AD78C7F57B93E7F0F0D
+:105DA00091C2F96C42AE72F4E7F8E0E32A7E19F092
+:105DB000753B5D533A45E13D900E836207E26B8689
+:105DC00083B555E7E379502601988F144C26B950D6
+:105DD000928CF5DC504FE939BF19B2D9554CF139E5
+:105DE000E30111E11839DFE0BE5897218FA68D5FDE
+:105DF000C9A4FFA5E73F7381BE9C78D9782A5C557A
+:105E00003AB863DAD8674F68E863BAFB86674FE849
+:105E1000E0345597BFA76EBAAEFECC0525BAF21294
+:105E20006F85AE7CF6927B75F9B9BE0774F5CB1A17
+:105E300017EACA2BFC8FEBCAAB362ED7E56B9A5606
+:105E4000EAEA7B5AD6EACA0DFB86DC44281C1B7E94
+:105E500027121385E3D7D6934F5D9304A9E404B8C2
+:105E60009FAA4F43BA3E5DAF605A0BB4370AF8673A
+:105E7000B8D94DF1E48909959278421EF68D59B250
+:105E8000640CCD1B69F9684AEDBE714BBC99842C3A
+:105E9000712848F762A3910428A90A24A19BAE4364
+:105EA000A2A63C7889F246890486F72C1783D1BFD5
+:105EB0007709A14119741DDE4F4D6483D093CFC380
+:105EC0007C49FA90B4DECB3B0CA4BC49237736382E
+:105ED0000C389F64C7B80D0E4A0FD546C6EFD5DB08
+:105EE000D2C7113BE40383EAAC1719AF894E2615DC
+:105EF000FA61FC52E1EF13E65FC4DF001DDF0F8E95
+:105F000073AF77D0F13AF68BD3601E247030EB96E6
+:105F1000A130BE6B037C272DB49374CADFF5AE6746
+:105F20004F5C41C827F51331FD7D7DF1B3276442F5
+:105F3000FE583F0DF347EADD9806EBCB313D565F47
+:105F400087E527EA1760FE64BD17D353F54B303D54
+:105F50005DEFC3F28EFA46CC77D6FB3155F980CA95
+:105F6000A399C5C0A7C5C506E0D37916C2FF58FEE0
+:105F70001C5F8348FFDD867CED4C03BE3E67FD66FB
+:105F80005006A5B7739F5062CAEE1D4E9174D73B61
+:105F9000FE5C06C05FA99F124F62CF724B0CC38F8D
+:105FA000C54026122A7F1EBFC248243A7ECC1B570A
+:105FB000AD13B3F1BB04A443370EE7545B94FE0763
+:105FC00012C4D7A5F0A4D63FF9E29F0B67E5027E85
+:105FD000FA239DC41C14EB18DE5E7602DE2E053F0C
+:105FE00089F357241C8537FE9415A4F5BF4C56E160
+:105FF000D99645687A8BA3F814D0C1B96613AEEB75
+:106000005C6BAC9F401F8E24A48BDEE1C6E651B5CD
+:10601000D1E2D3CA879AA6789F5E5EA4FBB4F2E26F
+:10602000DCA197EDC0F7F3D244DF89E1401F2E4E8B
+:106030001F8CEED4FE6B9AB27D565D3FFAFC399F01
+:1060400030B109E5BC1277EBD0DEE7392FCD88E31C
+:106050009CDE38200EC63D5D6FF6C1381DF50E1F63
+:106060001B37CDA7A5CBEA05B1BE1389E1F9F5D65B
+:10607000EF3F7B7E843493E36682A0FF7E40EFF5A2
+:106080007BC58774DE580CF4D12A7F03FB4E4C8EFF
+:10609000BAEF489857FBF534895ED3D5F07DB36EDF
+:1060A0003CDA4E39A9E2A9FFC5F02E9193EA3AA94C
+:1060B0009C1C4A6537D0292566C4B39BF61847FB5C
+:1060C000EB92AC4B043A8E295EC1720F0C44E9A9E5
+:1060D000C61C34BA1504771BE859B346AA7CAFDC5A
+:1060E000F1074A725FFC56264BA1FC2FB4775A2E5B
+:1060F000F3D239A4D84EE878B39AAB26819CFC62DF
+:10610000C78FB99EE22B84757F490C13814FBE2443
+:10611000FF6E1FAED1CBA6C41BD9FC96B0FDD94BE8
+:10612000FF83F5513D4DB75F9735EAF3A5E4E614DB
+:10613000E087D21532F1D3B957C07EAFAE9BF2FDE6
+:1061400075F14C8F2B23758B414F592A936980EF42
+:10615000590E22F5A172A266E7EAC2129ABF2DDE9D
+:106160008074759AEA770A954315094C8FA94CF209
+:106170001B5DB4FC78F3F0DBAF21D0DEBF18E49AEE
+:10618000D7469C1B484FB8CF5EA29FDFA5E61F39BC
+:106190005F4216E17CD579A8FDAAF310370A2E7F5D
+:1061A000147D7676BC10D693697A5FBC5E7F5D0005
+:1061B000798D7EFB70447E51445EA51399D3892965
+:1061C000DEBD203E19E8223401F53442E923375C74
+:1061D000CF18AEF7F0C5EA99A09E88F5165DAC9E83
+:1061E00025DCDF63D1EAD5ECDCB2C34BE9A9F2F5DB
+:1061F000E7EC84CAF32F245F8A937EAFDEF0A81DFC
+:10620000E0744AF2DA01DF5FF8C589D1E0B5AF1B6F
+:106210005E2EAB007604923685FBAB4F4C013DE918
+:106220009B0DB243A4553C1B4D0113A5DFDAE68A52
+:1062300049240FF34759FEB1B322E45BF4F8ACFCF8
+:10624000C573298A0DF1C0F46D1240BDA376FDE738
+:1062500013408E7B4808E930B21D8C7F2101F9BEC6
+:10626000C418D7B39CCE13F5640FE7334FF313670D
+:10627000453BA437B4039F7922E8A8BC7B7F091A69
+:106280008BE97C5E8FB7259DBC8A667F407E00F2DD
+:1062900040850BF133BDA261D30B7947E9BC3AD6F7
+:1062A000FFD62EE46AE508A3C7734DB37FBE5BE952
+:1062B0005DDE7472BB28DCCE8FED9416A607915676
+:1062C0009656CB013BE89DD56B6527A55452BDE59D
+:1062D000E5575E047BED5313DA6B555BDEFA6834E9
+:1062E000CD576D959326B1E5588594307E3CF47F6B
+:1062F0000B8685F151F9ABB78CCA50F6FDA18430FD
+:106300005EAAB6EE3792A13DE158D4B4DF18B44688
+:10631000C14FD3D109A0B7346CFAD608F6D717FB12
+:1063200004929ADDB37DF9DAB7705F0438213E3903
+:10633000BEBAF1D7036F8129BB0BB09E03E4E5A57C
+:10634000F0E6E372BA66A78DC4D37994FFDEE49FCA
+:1063500004F87CED3E3BACA75DAA6374BEFAD11491
+:10636000171DBF5CF6A6383065DFCBD7DC8FF4573E
+:1063700026D4A538909F5CE90694DDDE7458E7DCEE
+:1063800055B7E13A4B891BE9B07CB558ECA7E9D782
+:106390001299B8350A9F1426303E695F47914BD752
+:1063A000D90E7A3FE8DBFF2EFA37A07D7A2F01F96C
+:1063B0007F3F5F33DD2931FFB599E1CB9A6050ED26
+:1063C00045B38E7ED73FD606783ADDD7950AF3A43B
+:1063D00070F072B809DFD37EC50FAE4F6578228AA0
+:1063E00054C8DBD1FDA008BE43FD36D965C9D3B57D
+:1063F000E3F2938D3F9F8F4FE71D03FB5B7B0AD535
+:10640000EFA3AC6F16AC0FF745BACF69E84CC3EFFA
+:106410008CFFD73FCEF85DE57FFFD489507EFE43E9
+:10642000C647D00EF6133AAF402A96EFBF5540F953
+:10643000602281687CBE5EE67CAE2FF7507E053F11
+:10644000814A2774FE9210A7A5173A4E02E201ED89
+:1064500095D215B4BD56BF8171B19E31FC5DB3AF0D
+:106460009471B9909F40E5416C581E9055C997A50D
+:106470004756CBC40B2A67F5A726B4C7ABB7C8C528
+:10648000B0FE339B0F7E7427A5F3334D2ADFEAE578
+:106490006A24DF966FDB20009D46F2ED9972BA8B7D
+:1064A00047E35BFA3D2ADF9607FF9FCA55157ED367
+:1064B00013F4F294CAC77EA042F406C748F9F8352F
+:1064C000E85BC93DE523FDFB9014F6A44395FE541B
+:1064D000BAA31A5C3F90EBDDF4A9D25F377DAAF432
+:1064E00017B95E3DFC22CBFB838D44E9A47817D518
+:1064F000E8283EAB5B05BF09F9DCFB769F0284937D
+:106500000BB737E27BBB4F9236EF8FC83745D47756
+:1065100045E48B23EABB23F275BAFAD52D078D0427
+:10652000F11FD0D5332D78891C8F620FAAFB8FA75E
+:10653000F9ACD10B7491193282DC931751D50DFC53
+:106540006B7B45F4AF7529217B02FDFEA885D969D7
+:106550005D0E9E8F67F950B27131C83DF57BC84220
+:10656000D03EEF2A0ED9E335F6FFD156D1AED0F2A8
+:10657000A09F4CD4FA11C2F369407C07496FE5CC67
+:106580006FD81563CFC3F162B2FC407FD78BD6AC16
+:106590000560EFF94427251F3267E11D7642E9AC1B
+:1065A000AB75C04DD3E8F7B9EF88A06E53F4B8A42B
+:1065B000744A37B3391D9F22DEE7C7D0F5CD6E652B
+:1065C0007AF89C65D1E9BE92D72FB5CE37827CA5EB
+:1065D0007AF431AD5FB4922C43BA2B5F15F1BDF55F
+:1065E000C7C81F9511FCE1E6F6C35E953FF2493E30
+:1065F000CA174298FDCBE5F2F562EE4DD3281EBADC
+:106600000E89C4A4803D2B92C5B0CECD821FFC055F
+:10661000C49B8C7C564B42280F553875001F0DEEDD
+:106620005D4E756CFF53E183402F3BFE90F7124D9A
+:106630003B767C3A680FE4777E9CF507D2B37ED137
+:10664000BEEF66C07ED6B5CF847EB1AE7DBFCE7ABA
+:1066500010F2BB4DE817EB5A6472011F78F7D9FCB2
+:106660005740795F663F34ECFD362F88FBEB23887B
+:10667000B75309CC7E39D7FAE7234212A47455A048
+:106680003FEC8B453EF2ECB6A0BDDEB5F7DB42B782
+:10669000F59FB79E5A2371233DDAC8B46D40BFF110
+:1066A000CC7FECD933EAE58574FC9AE6FDC6D9B413
+:1066B000BCE88DBFE681FCECDAC6F4A24E39B886A0
+:1066C0003809F92AA1EC7119FC7CC04C19843C9D55
+:1066D000B8F1066F6E34B83038745138C0BA285CDF
+:1066E000CA41EEF7068F984423D2FBBF1E3CCECEA4
+:1066F0006072ED0704FC4261B8082EF6DDE6370B48
+:10670000B87EF67DDFB7792077CE342D447DE55213
+:10671000EB1E92F8AF4A07FFD5750B81CB59F7C432
+:106720007F597C33FA7F2F41C17946F2414F3ADFDE
+:10673000F913CCBF6673E27C2F93FFCBFFB7E17DEB
+:106740001BC5BBFDD2787FEC7F2CDEDFE178B7394B
+:106750004C20CFF6FE15FDACEAFA2FB5EE57FE87BA
+:10676000AE5BD5E36F34D41D9E4AEB1F268115C561
+:10677000749E6F665EFFE1545AFAEB5EF4938F12DB
+:10678000991DF86B503EC0FE4B13FC1BD0AE6076DB
+:10679000531161FB7A514E19EA1B45394FA0DE4077
+:1067A000A4BAC3F9141E3766CD752EC5EAC33E716F
+:1067B000D3FC8FD2AF75A2FF30C27E3C2810974029
+:1067C000F5D8A22B6F380476CCF84C3960CAC3F4E4
+:1067D00028A46FDB27B2EF56BDDD3409EC1D8D1DFB
+:1067E0007883A22F9FC0FB9B48E61D9E4AC79F98B7
+:1067F000293AFCD06EAC4F82F54CA2CCEDD39C1F55
+:106800004D88E86F1BD531B5FEB5BF177EE624660F
+:1068100067FE9A8E9F0FF0CB94D17F7849F801BC28
+:10682000115EF9FEA5A05B494E84DF8D19351C9ED3
+:10683000CCAE96787BC9BAB80DF85622D42E667ABB
+:1068400019DAD3AA5DDC1B9C09B7B3253EA40A77ED
+:106850002993DAD9FAFE101E2A3EFE5E3CA8F8FB08
+:1068600047F1F17BC0C788303E32CF3B24E0CF22D6
+:106870006E0F8C3FDF26623ED329E1F90BB707C6C6
+:106880005AE325B007AE953E10812FCBCCBB2AE151
+:106890001CC1EC1490AE077718D0DE31170808F74A
+:1068A0009C4609F31F181C2340D19E72CDCE330F96
+:1068B00010F027BB8C4CF12E66FEFCBF7CFFFD98D0
+:1068C00042F0ABB0BF32FABFC914BE735691400C50
+:1068D0005DE75C897821C4612E5DD4319D3F589F6E
+:1068E00087BFEB52C2FD5CAA7E6F72E49F9DEEA44F
+:1068F00072EBD81584EC829439FB25ADDDFC835610
+:10690000062FCF61E2EF8F72C125166BCED9FE2D17
+:1069100089C98F9D7FDC361CFC6763BB72E3983CA2
+:106920002D30005D7AB85D708E287110AF70AE7535
+:10693000401C9E231E126DEE287E9B4DDC9EFE6544
+:106940003D3A9549D77AE213C16E2221F4DF7AD716
+:106950009BA39E07CF4A3270BAE178A37F62219C45
+:106960005BB0F1E7D2A6715ABC754CFA42CAEB890A
+:1069700007F83BA6395FF947E10BF63BC077932553
+:1069800038A1388AFC98CFE137E5C077E8EFBCB290
+:1069900075AD01E8F7CAF506DDF9647512B7BB8677
+:1069A000916130AF29072CB602C0CB21D169A1EB90
+:1069B000F3B49E35BAA39C7345C213FA073FFAABF2
+:1069C00049EC5C608FDC341BE0BAE74B33F152FCDE
+:1069D000EE32FAAAA2CD332985C9B9B9A4E9BEBC61
+:1069E000EC7F3DF88EEDB206C6819DB99E70BF4624
+:1069F00024FD11A4E3731B891FF653B04B412E9C59
+:106A0000DB4C703FA7207912EC6ACAEF3FD4FA69D9
+:106A100006B76CFD25E801B5AD82C340CB6BA5A0E0
+:106A200011FCB19E967811F6DD7C85B8F07C587229
+:106A30000CBD55C317AF264908DF83A3F7DC05E378
+:106A40007ED56124A08FB8DE0CD961DFFEAA75382F
+:106A5000F2416FEBFA553DA91C2F433F4C1E46D225
+:106A600043EEE6185DFE1AD19D01FC35C5149CEF7E
+:106A70008C82BF49C98CCE2E5BBEF9FF3F936F1F3E
+:106A8000AAF2CD2D166BF8282999D1BD46BEA54690
+:106A9000936FF3042515E03E6FEF8054C0EBBC7795
+:106AA000E4E468F26D4B3D3BFF7B9DF223A45DCD9A
+:106AB00054BE5DAD916FCD54BE65F76CF7B7CB9505
+:106AC0006FFEFF1EFEDB02F22DCA7AE339FC54F999
+:106AD00096D77A14E55B5EB381281ABF9339F952D1
+:106AE000F24D48BE15F4E143B233360AFD6CE1FACB
+:106AF000F7EB3C6E0FC60139F7A364765E7AB97284
+:106B00002E3D85F1C925E5DC7F139C5539376F3B58
+:106B10009573D9D1E890C9B979BBA89C13801E9907
+:106B20009C9BB79730FF5B847CCBE921DF08D6AF15
+:106B30000DB0F69E96EC17EEA6FD0D73C94E33AD63
+:106B40003F2C2CEF4668E5DD8F922584730F797713
+:106B5000E8F2E4DD762EEFA81CEB0FF235923E9CB6
+:106B6000AD31BAFC9E51ED9B7F05FCF2AE88E78B00
+:106B70001F18D839D07BA3DA0B80BE56F2F97838CB
+:106B8000FD75D67BB1FFA237D9FA6A3633FF776D30
+:106B900033D30F6BD78B7E85FE73C2E8EF8C30FF4B
+:106BA0008ABD0249A5F9A926DFF35690C1BF900915
+:106BB0003B172393F235F430676415FAF11B2CF67A
+:106BC0007584F2F11C8998C15F5F659DF005F8E955
+:106BD000AB4632FF7E15FF4E78DC801A0759DA7219
+:106BE000EFDB7D48CFF881292686C7292F0BFEB51C
+:106BF000D910BFA42FAF8A887F7C8AAF73AA1844AC
+:106C0000B890F7C5A8710C4F45C2E31087075DBF68
+:106C10000E1E7E212A3C284627E5A784D75FF16E09
+:106C20007031F8F32B560A78EEABC223729D2A7CA2
+:106C300054FF74156FEF69BD17CFFD23D7AFC2AFF7
+:106C4000C7BA557846ACDF97CCCFBDF2C97088A7DC
+:106C5000A1F480F2C3FB1B0A073A4EF1D82B52B5C0
+:106C6000F2F8790E87E1BEB145E904E046EA807E9C
+:106C70004A1BEF7D3B9DAE7FC427CA30D826AF1993
+:106C80006D72C339EA264B08E59B4A5FED2ABDF3D6
+:106C90007EF664D48D437BBD4570807EE10958103B
+:106CA0008E1E4A67165AE5E0CA6F2670383A4CC8FD
+:106CB000577CDFA17037D0FA13D47D88C21DF866E7
+:106CC00078EB593CCF2D20213C2FA96D149C01BAA3
+:106CD0008EDA16062F55DED23FAB161F51E8518AC9
+:106CE000468F049CC485E17DB08AD79B62F27D0407
+:106CF000E7305328BDAF25613CE6D0FF008F917887
+:106D000052E17929FAFC9CEB1F5B008E5680578874
+:106D1000E95101BA2FD8C2E51EC9AB8363D18B17E5
+:106D2000187DED1514384FE88613D02B2D1FD1CACE
+:106D3000E815E0A600DC5B4B44C89752F82666F7DE
+:106D40005C279C5F6AF9B762EF51D6FF6AC149A21E
+:106D5000D0AFBAEEDEE8F71FA5DBF608BA7DCF129A
+:106D60003A3C1CE876AFC0FC08ADF1BA7347530A51
+:106D70003B77DF64A1F40DE75DEFC8CE754A4F3E67
+:106D8000BFC0E109FABFA2F14B0D8105C059E04631
+:106D900033C69FE13CFA33FD522B5FB75848F2AD42
+:106DA00005BDF76FE4F6406FFA8D9A1F0AE381DCA8
+:106DB0006BA1E3E584C78B94EFAABD7FA97525A6D7
+:106DC000FC63EBEA8EDF246D78FE648A773F98845B
+:106DD000FE1F169F743B8F4FA233403D4B532F2D08
+:106DE0007944EFF5489A19F7E1FB785CFCF5A29538
+:106DF00078E93ABE72C948A77497FEDD1890CBE3D4
+:106E0000E83E4293AF0E8FF8F86E2C17F13CEAA6DD
+:106E100077136BE09CEE261046F4FB4DF902EEBFB3
+:106E20001F4067A3408F3513978993302D1FF98337
+:106E300078F41BE5AFF71529949F866DF43740EA87
+:106E40002C0A25BD07F01B2B12805F9B2BB108F687
+:106E5000AFFB3E27F9A282FB2CF633EC1049867A71
+:106E6000A35DC9680E8C6A5E5104FED1A907AD56B8
+:106E7000A0F39C5506E2D6D0EF68E26F8073F8511C
+:106E8000275CB700FF95537D01FCCEE5AD6B1BEC95
+:106E9000905F253815DABFC7EB9E60A7F3DAD2788A
+:106EA00076C255C087B41E74E359C5EA79D60B4E35
+:106EB00008952D6D5D8EF138A5EB05E280FA7E8197
+:106EC0009859BF7E33ED77CB2ADA9EE6CBA03DF40E
+:106ED000BBFEEC87B7009F1F1659FBCDECDCBA94C4
+:106EE000B653805ED7DF8BFD55AC12481AEDAF7CF0
+:106EF0003393FFE58765279437EF5F89FBD8243A02
+:106F00005E7A36C8FBC078C893E18203FD9D99770D
+:106F1000225F7771BE261DD398DC10789EDB0DAA08
+:106F2000DE742085C507973A171A13693FEF8D4C19
+:106F3000CE8630014FCB593C8F3E41E1ECA670FE2E
+:106F400080C7731C1C79DC18D4EC3F9FA50C403A19
+:106F50009CD33216E31CE692628C7398328AE96BFA
+:106F6000EF5F6BF10B745EEFCBA14CF87EF05A1320
+:106F7000EABF9D5B643C2FEEEC1B44FF74FB2A9937
+:106F800040BC46C32A11E562FB66B68F8BAB6F9B94
+:106F9000900EF0DB2038416E1E5C5564847DADDDC3
+:106FA0002F60FBA2D5F7A7303B86C943D56E2B7562
+:106FB00054E8F68F48F9A6CABF1A0E87483957A376
+:106FC000EE331172AE06CE9BED90EABF7B8895C979
+:106FD0003FD0FB01EF81EF907E6B0FCB04F47EE19D
+:106FE00078C7048CDB827D93968F6A155C70CE5FC8
+:106FF000FE89C98FFAAABF64E64F417E7F6A22826A
+:107000000271F014EE542E8C3485FEF82CFDFEC572
+:1070100007668890A17452827056E3450B36B0F82B
+:1070200096820F56A494021CC627A29C2D6B14892D
+:107030005B232FBE105CB7DCC9E4B16383461E1529
+:10704000187DA5B07F3952991C5436C8103342B60A
+:1070500073F944F56917E80D15BB96A71869BDC506
+:107060003C1EA462EFF2142A1A4803EC5BB47E853E
+:1070700091F55FB14F70ACD5F4AFB657FB53FB3110
+:10708000EED2F733602FCF5F663FEA3CD4F17BD37B
+:10709000C747FEC7851502ED6FE4FB2206298F3C2A
+:1070A0003E6980F6BC434D55FF6BE18706E2D2C0D6
+:1070B0006DE41F63884B4317CD23287F53BC4D6E6F
+:1070C00061FA50F388A3C69A02CC3B809F6BB99FAC
+:1070D000B6763C3BB76ACEFFE011E0EF490502D23D
+:1070E00001F1BA8D8949A8072970BE5056C0DA97B8
+:1070F000D1F6C077CD2B191F5279A080BCA85DB501
+:107100007C02D65F2F28D07FF3DA12DCE7CB478AE8
+:1071100004CBD71F45BDA3BCE56812F02BE5CF1506
+:10712000B0EFD68E3139803F54BE53F9F87D99C502
+:107130008710B36328DC03284B51A2F2AF78983054
+:107140003B75B38C7CE719C9F8F2FD2D22F2F3C12F
+:107150006BEF98007CD8B941E8858F299F1684F998
+:10716000545CCDE275CA36317BE5E02A261FDA9BF6
+:10717000999E58B45A9E0CF9B27765C2FC5E4C1FBA
+:10718000BC5C7EEEA1A76C8CCECFBDF1EF14B9E94B
+:10719000A3FBE8FC6E7A8DCE5F09C3ABE8BA07ECBF
+:1071A000E8A7BF6E3AAE579543A5128B679AE35B8B
+:1071B000C8E27D2516F7F677CF2B621E8FA5D8C2C1
+:1071C0007244047A8F6771D2EB65A4F7487EFC475E
+:1071D000F9E89FC5D7DB391DA9F311F7B2F61057AF
+:1071E00016A070FCF5E69731AEF5CB578F4E013CFB
+:1071F00057EDA1F44BD7DBB9D9460220B7243FEEB7
+:107200003795CD22C68F132950788B4DCB9F2C3EBE
+:10721000A9EA751BD24DE53616775AB9E3781EC632
+:107220008B2C0A61DC95F755AE6F7A837940DF9538
+:10723000128B938AE4F7B1A94CFFECD8153B0DD61D
+:10724000216CDC8FE7AD954D77C8407FDDF223558B
+:1072500056EBE139A697D22F9CB3C3FCA60ED5CE30
+:107260006F21E2A96313E3FFCA16D96F81F96D5C40
+:107270008BFE6CCFC6B3181F5FF4FA16F423785A4E
+:10728000447D5CE44611CFB3688AE75691F189B535
+:10729000CD3578EE56DBC4E3FF22E2E2AA5EDFBB27
+:1072A000C34B4153F5AB5FD8411E9C6EDB60077842
+:1072B000D2FE30AEF0BAF3922E3EAAF77860973E37
+:1072C000DEB0E9711E6F38B99DE4F58C373C0DFFD7
+:1072D00080FD2635225E7363228FEF0E141647F170
+:1072E000E777DFFBD9F2F51A8893EFD876660DCCF5
+:1072F000BFFA6F5FAD81F826B2CF82FB94E7D5DF8E
+:10730000615CB1DA6E612AA3B7CE4DBFC0B8ECCED6
+:107310004F4D68EF74EE6DCF82F8B6CEADDFA5802D
+:107320007F6EFEDEEBD17F397F7B512A8922EFD53C
+:1073300014E8D37F1971E191F838D87C10E3B0BE1E
+:10734000FCC484F2AD3B7EB4A986C5E52A3C6E74CC
+:1073500073F4387C35CEB1B6F9969BAE0579DDCCA9
+:10736000F4BBEEB8C74BC58B7E48F17AF565E06F8C
+:10737000338F0B6E9A1C355EF44BF807C5D3CF5391
+:10738000F5F1A25F37CFFDF98B50D69CD86BBC6866
+:10739000E032E0A6C6F957A7BA5E4D053EDA16EB15
+:1073A0004D6378F34F12400FFC3A0BEE479C92432B
+:1073B000180712DA6B7240DC63E5DE8F915F3AB733
+:1073C0007F80FE56C2E3EC3B49F71F8B8716F83AE5
+:1073D000D7DB589C29873FC4A12A76FCCEE34D1900
+:1073E0001DAB71A8BDC59F0653F9FD617EEFA08658
+:1073F000DA4D2C4E3D1C972A8C047C1DD5C5F5AA70
+:10740000EB8EECCFC1E56838AE3A7A9CAF1A47D81C
+:10741000135F6C5F51E3A63BD7F2786BFA3D7318AC
+:10742000C4C9B1FDDCE3173E8E865F35AEFA0F119D
+:10743000F855D7D71B5FA8FC79A979FF57E1F26E01
+:107440002AF367ABF0E9F84B7439FD0DE7776AB7BB
+:107450007E9DAAB16F6772BB55859B3ADFC54D4CC7
+:10746000AFE8D8C8EC8748FEA6EB71458BB397D23E
+:1074700098FE5BDBB23F0FE450C7815D9CEE185D68
+:10748000D76E3ECAE274A9DCF66BE536617EE4C8CD
+:10749000FEECBC3F4F6BF4FE3C9BCF46EDEFB4E4FB
+:1074A000BA03E67FBA8DE951A79BC489FE28FD5F28
+:1074B000E0FB52F7BA6D468C9712ED31A84FCDB76D
+:1074C0008DFC242E095223C6FD342CE471420F3B5F
+:1074D000D300CE0DB61B09CCE751808FC6FF203BF1
+:1074E000DC04F43839ADB84054C2F355CB8D4906AD
+:1074F000E2D7E25F0A64827C3F92DF2E437F9F45A2
+:10750000F84D3E93C8E2543AAFCFBC8273A1D2BBD0
+:10751000DEADE6DD0F893A3F47AD297404F477F21A
+:107520008605FDD6E23E8B17FD666B2CB8CE83DB5D
+:10753000BF7D05E0D5F9731361E7089430A85C2896
+:10754000E3FE8BF6EDDFAEF933E899D0988E5FB6A7
+:1075500086D607FD7A732CDA035DDBE2F2509F7C5E
+:10756000E3C1292037CA600F033DEFF5547F03EDD7
+:10757000EF6432CB9FDCD217EF13546DB361BCE1E3
+:10758000C1ED3B6B41FE77BE1E0BC7D1E44B39F812
+:1075900037C87BF6C491B50AEA818A76BFAD2092DE
+:1075A000A2D5F3AA20AF8B7F2168A7A33F8ED27309
+:1075B000554B1CDE1FD1D4E3FCECCD60F7650219FE
+:1075C000C077549FD48DA396DF9AD69FDFEF0DFD31
+:1075D00084BDAFC0EA7B8CA15296F76530BE6DC307
+:1075E000FA252ABDF2F29EFDB2FA33D3FAEBEAA9EC
+:1075F000ED6B4DA42E1A1F54A709FC7EEF5F0747C1
+:107600007BCF22CAFCF1FBFD02F11A400FD86AC100
+:1076100038AE6A636010C4B7EF30B2F3916A7B6032
+:1076200010C4B7EFE1F2AF3A86E6E9F70C3E0FA8D7
+:107630000F79620EBE06F8AED969214BC17E7FC3B9
+:10764000E6023CD7ECF8F6E44B0510CF168B7EAB88
+:107650009A37FE0DF15F630ACC00FA0F6D35917514
+:10766000B47EC7D677B2408FE8900359091739F72F
+:10767000A96932E9CEB1D5759CAEF70F84FBEBEA70
+:10768000BDC5CA5EE4C5DE34A68F2E4F733D9D8610
+:107690007C6D75A0BC86FE44E8A76580F65E73A588
+:1076A000125D8EAD4A9375F768C5F03DC555D0EFB4
+:1076B0009724B83883A2A44608E1F979E5C6B34314
+:1076C000C11EFEEC6757E1B9D667C6D05090DB9F6C
+:1076D0006585866AE5F1A97AB322C9E897C0B46BDB
+:1076E000EDD9D20C02F1839669D1E4D396B4589CBB
+:1076F00047E543B151EF83EEE6F4B61A6830998D51
+:107700000B7E0875DCCF8C7E23CC23375DC1F2CA9B
+:107710004CBF11BE576DDC3540F7EE84E4C37A945C
+:10772000BF101E156485B1C0DA53AE542CB02A12B6
+:10773000DE8F96FEB39BDEC4309ED0C909716A1CF1
+:10774000877467423FA87A1F40928BCD002F232970
+:10775000764822A0DA877C1A439A30B5527584EDB8
+:10776000437504E28A4EF1F35B93A43C0DF2C374BB
+:107770004844797E29B8FD3ACD8EF3364975C489DF
+:107780007AC72407E8D582D74DBEA7F4D050BF7181
+:10779000C00976FEEF8278380C8DA3F3B33BDEFE92
+:1077A0000EF4034A6768677BAF23FE063A9E646463
+:1077B00079328EF8A39DC777703C10EF7E943F56C8
+:1077C00012FE0BD17C2C4A283A6EDCDF46829D6B80
+:1077D000759000E84DB1561288A5A935573AADE528
+:1077E0005F3B61F9FE949C41AE39C6E8CB23E99A30
+:1077F00038A5F3DD7251C4F6E723DA9FBF587B1535
+:107800001E1EF3806C76FF9DC12586AFC13BCE79ED
+:107810002108F0C8B33B1B008FC6D09107011E7929
+:10782000566627263512AD1D37209DC9AB4704B6D5
+:107830005FD2BF62ABA63FE230A3FFF4710EF7EE5A
+:10784000FAAA5FA5477D8B0470ED51DFD25BFD98EE
+:10785000E8F56DBDCD2736FA7CE27BE9DF1BBD7E06
+:10786000ED1B1FBF1750E023931B1231A8F7A00791
+:10787000A483BD157724A58451053B2788C05B0CE4
+:10788000D01FA58798819AEFF07FB91AFCF58F82F7
+:107890007F1240BA2BE1F3A1796B3A9DDF9D7CBA50
+:1078A000E3D7B373CCBBE7333FD29D0FB1FB424765
+:1078B0007FC6EEEDDFDDC8ECEDBB17B0733352CE03
+:1078C000EE0139E87F30DE3DD009C5F73D3EC11FEE
+:1078D000C886777022F4D7EEF776EE97A07E4984BB
+:1078E0003F46A527F5DED26CAE5F6773FA9C4B422C
+:1078F00036E0FBC87BF4CD692C2E8D9A632E58DFC1
+:107900005D7C7DEA3EE05D4E72E05D00D110E38477
+:10791000F31191DF5B257623BBB77A6B824EFE9C19
+:10792000CB51E260BF236FF2EFFC3DA2793728A96B
+:10793000DA7B5ED285587C7FA44176A6815C942F49
+:10794000FC9828942F8C17061045730F8DEA77C882
+:10795000ECB283A01F4772149332D00BE3399D25FC
+:10796000DDD8AD87BD4FE1326FB982F760EF486770
+:10797000FBCBD28CE2B94017A27DA4D36DED895721
+:10798000EF76B6BE06585F76CF7937189D4ED44352
+:107990006FA41A04FA7B9C66988F68523E56803F0B
+:1079A0007F2B13B0FF7BC281E1F35C52821FE25F49
+:1079B000E6D8971E01BA5D56EFC073B425F5399825
+:1079C0002EAD4F433D7471BD1353152E66A7CF25C1
+:1079D00052389B07B2FECC0E37D333E83E04F11782
+:1079E00092A32E007973661D01FDD7D20D1F1FC211
+:1079F000C7D89D7763DE04799ACA8D9310BEB43DD3
+:107A000029033F6A867B19C0C7A25C49140D5D98A3
+:107A1000D286E9F23DE0A6D2C71606BF2705461F6B
+:107A200091F07B526E53E0FCF9C91BBADFB541F807
+:107A300051759FC1EF37EC7CAE57F83912509F9DBE
+:107A400053B8784603FDF4043F877CAC7E24C2EB38
+:107A50007188EB1A0CF6810B5311E047E9C894EBDF
+:107A600025226D6F52D89C4DD66297A180D12EC031
+:107A70004FB432789AD2EAF03CCE6C65F012AD5E2B
+:107A8000848B6C65F012AD8CDE8C3C2F01FC866320
+:107A90007BFC4EE1D79C3E02F0305A072F63D2B8F0
+:107AA000CB83DF4A0A3F3A8F24CE5F917048827BB6
+:107AB0000AB961BEEA4DAF7B8EAE1FF6F117287C86
+:107AC000204DEEC57E4CCE607234C950B75F06784B
+:107AD0002410BEBF7849662161A18AF097E6250A85
+:107AE000E405360FB25E8F57D12145BCFBA6BC0022
+:107AF00074B0E21DD900E7A4E2821FEBEE938AD3B3
+:107B00005CF10AC2D32DC0FEFC44BD82F85B0E7846
+:107B10001C0CFB23B3C71EE5F87C0CF804F1CBF872
+:107B2000E349CE2F4F733E6970B2FB13CB26B2B838
+:107B3000ACA47C037F0F2D40B4714FF1CE2662A41C
+:107B4000F3421D5BC134807AC62726FF15B45D6CF5
+:107B50002E71019DC47FF2801FD74A8AD3412F8A9C
+:107B6000E7FA2F19A3C44FC78BB40189D921541444
+:107B7000A25DD36688F60E5683F38019FCA6BDCDB0
+:107B800067FFD41D4897A5576378304974174F9FF6
+:107B90004BF3D6C658F40FC63ADD858F029F37DA0D
+:107BA000904EAD74FE651ABCC7F682D717336E309F
+:107BB00064503A144169A3F87DA6718005E0FC9CED
+:107BC0005C9C0EF2F539BECF521C28DA73A80E2E3B
+:107BD00027ED0557EAECD915B20BDB39C6E8E5C04D
+:107BE0000A2E7713C6EBE95D95BB1F75CB5D773227
+:107BF000CC27E5C278E4C7A49BA3CBDF06D9E885F0
+:107C000077051A86327EF79618D97D989EF200FD88
+:107C1000DAE7DC83D6813C55E96B1161F2C74B6230
+:107C20009CB81FF1777454FD7809BC37C8E52CA4C3
+:107C3000E24023D24DCADD068CCF5BC6DFCB7A8A09
+:107C4000D217A43E4A5F905E9BC1CE33169987E15E
+:107C5000BB6D0D5603CA0BE95393DF0AFAEAFE51D6
+:107C60000EF02348B2B3CD05FE409BD4B48E40BD88
+:107C70000233BC2721C41738800EBEB1CDE977B1DD
+:107C8000383C8A4E01E8C891544C8EE5E2E901DEA9
+:107C90007B911D3713F02BBE90546701B8E5663019
+:107CA000BBABB1A410E148E13B2E2339DC4FEAB471
+:107CB0001BBBDFDB826E5FE8E5FECC940CAE476752
+:107CC0007AC9400DBF370A5C0F53BC2447C3F78BFA
+:107CD000AE9840E05CA927BFF722CF363079F6880E
+:107CE000105D9EA9FAA72ACFE40839A1A68BFB4D07
+:107CF000D4DDEF322639817621F51A288A24EFD592
+:107D00004FDE158F70980D7020693776DBB53FEC2C
+:107D10000F7A6561547A8B946373BAF775570AE0EA
+:107D2000E994ACA44E077A7AA7B77DDD558A74E84A
+:107D3000EBA3C0BEB4FF991FA35FE7C4333605E4CD
+:107D400050D985C7717F28BD300AD3F2C61B703F5A
+:107D5000179E9D5C08F4D0BEEAFABC4FC1CFE3B3D6
+:107D6000E1BEDDDE583408CF237DB10AC477B437D5
+:107D7000D2F2827039C48B8B9A780102DE77CDFD06
+:107D80006F52A0A05EAABE7B46ED3AFB68F00BAD39
+:107D900016F15E58E9B33617E89FBDD15FE9AAE84E
+:107DA000FE00D86BC1EF4A07CC013D7ABF7D742835
+:107DB00040FB9DB38E9D2334185D2703A0373D63A0
+:107DC000C173C88684E8EF82CCCDB87E19C881B96A
+:107DD00019AEE7104F56F64E69EFFCC0C63F098753
+:107DE000CC708EF5227F1F4572DBA7EACED9D83939
+:107DF000D649EE6721E65ECA6378B9D24BB99DC514
+:107E00008B1047F472D5CE880DDB194DB08E9AC613
+:107E1000338B3F4578713B83CFFB94CCE67DEA15ED
+:107E2000937F5114FA3FC5E3532A04065F950F4E22
+:107E300075EB476E7C0F27924E8575435E1845FBA8
+:107E4000FDEA908CFB4635A52FA4AB75A3303E5EB2
+:107E50007866D4D310377CFEB088E595172C58DEB1
+:107E6000F1B0F305887B0ABD2B13904FE70F5D1F20
+:107E7000C7FC447A3FF63D7D985C38C6E543E9850A
+:107E800027907EBBE9C437D708FC577AE12946DF43
+:107E90001B057CB79278ABDF1D3B90D3E768685F2A
+:107EA000317911C07B8C0FCF49CA36989CA00F4402
+:107EB000E2F95886A2F37B94059761BF84EA5F4993
+:107EC0009AF3F4533CCEB8EC027BAF9038BC240D4F
+:107ED000F881CBA7301DEBDFA1EDB044F7D39FE3D2
+:107EE000FA4FE9856B747646787DD7E1F752BEFF8D
+:107EF000970547613EBC9E1746455B4F781D63B0B2
+:107F00007E477CF4F1D3399C4FD6971317956FE5D4
+:107F10004656AFD477BF11E44EE9AAF80441B3AE98
+:107F2000B2C62A5D9C47D9AA12E32C4DBF613C2CF6
+:107F30007E77AC14C643FA4B0B272FB2825E502CCF
+:107F4000F7017E5A5751F85305FA63F2E90BD997B6
+:107F500005F2BABDF13E7BB47B13E97D22F0D3C8B4
+:107F6000F143F5EA020D7E54BC44B63FB9B6ACF01D
+:107F7000A7E08F5EC95E21E95DFE44E02D3B3ADC5F
+:107F80008675C32D07E38D2E0DB7AB7471453DE0AB
+:107F9000C6F1ABC245FD4EF5A8ABFA8C80F108BB2B
+:107FA000BFD3C8F07F297885C7E5F81F1B7D1DD397
+:107FB000BAD7B1807829A3CEB9E43A1E245EF3453E
+:107FC000D6A1E29FBCA2C3FFB497D6221FAAF89EF7
+:107FD000736025D2EF1CCA8F70DEDFEEBBDF1E2D73
+:107FE000BE685A6F781FE825B985FFF7F0FE85EC6B
+:107FF000CD82B832EF720BDA23A7D63D91A585F377
+:10800000DC8CB1F7005EC8FAE4CBDA3FBCE39C87B6
+:10801000C0BEF43E23A33F6D6B86BB0CDA97733B67
+:10802000FC91F80983A2E9078FD61F1A027EBA864F
+:10803000FA364C65AE5F12D02FB3515F72457BDFCD
+:108040006B491F26571EAD6F637E4FB39738B4F749
+:108050008909D39FFE93307F8DDACE28BB1DE03F88
+:10806000350AA418F53EC9BD24BB00FC1E49F95EC3
+:108070000DFC16F761F79196A51D70C0BD6213ED5A
+:108080001FFC39E64CE99CFE9C93E5F3854F45883F
+:108090006F96939A08FA4373E9770DBC8D496D3A50
+:1080A000FF74241C24B31DCF9B24C2F43975FDF446
+:1080B0000BEE4B8FF17D6905F76B3E5FDF847EFF32
+:1080C00045B176DCFF16F733307BCA2CE17B35A651
+:1080D0007856DF18C7E66D01BFB708FB6A00F336B4
+:1080E00078D147C4A7D104C8C71345807C22092C86
+:1080F000C67752C6067F02DF9D696E3FE0F19BF4B2
+:10810000B62302F8B18BDD8361FF6D14BDF90AADB2
+:10811000FF7331940FF5B268D127092CED07F1D028
+:108120006ECDB9167B2754D1FA0523F3FD164811FD
+:10813000E73D7F19AC2D5F9EE67A1DE6D16061EFC9
+:108140000C251D17F03CA7C1C2DE1B6AB0DD1E075F
+:10815000FBF86FFA30BD1DE900E8E810D367CE499F
+:108160004A5C02F3932A6FEAFCFC66E54DCD3812B7
+:10817000B7F7D653BA9434E72A03259701E8E60AFD
+:108180001FFDAE9D67147F5C82159FE58D7A9EA3CF
+:10819000CE0FE2F6018EE2850968AF45D2C39E6E2E
+:1081A0003FB357047C4E57DF2F961E61F978A2FE2D
+:1081B000A1FDF569B73EFA08CBF3734ECF2C768E4E
+:1081C000D9501287F171EA3CA6B73ED6067AEAF496
+:1081D000D6F4D970BE35DD3AE87348F7C8A103B1CB
+:1081E000A007DE2FE0BD923B7FF7A61C4BD3ED1F0F
+:1081F000AEC3FBCC9F73793A8384F05D783771F01E
+:1082000073763F7E9F459C3CDF24835D7F77C07FF4
+:10821000DB649ABBE74DFF6450DB661C0ABD056258
+:10822000C0DDE4988067086ABB16E7DB2CCFDA75FF
+:10823000AF5F32E37AC2EB35E3FAD5F5D19922FC90
+:10824000BBE1C3DF6B52E121CEA2EBA6F4323DEEDF
+:10825000F61BC945F4F2E9D69CCFD9A1099B4F245E
+:108260007CCE4311D51F3BFAB84826C5DF1FFAB8AC
+:108270000448ABCDA12CA93FF2890CF95AD1DD0FEE
+:10828000429FBFECEB1E9C0C70684BBC2CF979C470
+:10829000C2F8FF08D033C4795D48C275A9EFD01F7A
+:1082A0007CA0DD067AE7E2ED1FE33BCB3562F0C947
+:1082B0003BD01F2AA2DD74AE79F045EF9F1D013F30
+:1082C00015DDFFFA66AAF72CD93A674A8C4F663655
+:1082D000C7623CFECC05A2EE1DE9990B583C1F91EC
+:1082E000DAF26ED5E9EB8FF4DA0FF80B22FB99BDC9
+:1082F000A0881C1F0EE7B48EB1E83F58C3E86BF6A8
+:10830000789708F1CEA3970878DE3AEA84D212A4CF
+:10831000F9D9FE7827B0E7EC07FE6300BC7350DBA9
+:10832000C6FC81A9E2BDF90F839FE500DBC7217F71
+:108330002FD089D5A55835E7051D725D3EBCF7E7FE
+:10834000BDC7EA02FE2FB9D5F529BE17C1FD15EA52
+:10835000BEBAB3B104E3644BEE564602FE4B9A2C10
+:108360002E4CCD448AA172AC44226648538D44B24F
+:10837000401A43CC90162E62EF7697364E45FDC0DC
+:108380003EB2D808EFF196B4FEE26B685F2605F6C0
+:108390000B7961F894B4BEF31DE075AEAB18E31928
+:1083A000AFDA68D4D981439BF4F9AB5BF4F9FC8074
+:1083B0003E3FFC903EBF2193201DCD32DF920BF05B
+:1083C0003AB0D744F72288FF3361BCCB3181E1C793
+:1083D000BBC982F2B0A8AAB510ECE033AFD90C60EB
+:1083E00047EFF9EBAFF03C3CB42596409CD5FEDF5F
+:1083F000C7901888577CDDB20ECAAB28EEC07F59F3
+:10840000F5BA652DD8E13BAE54ED787F1EAC67C759
+:10841000DF587C4D6893C90FE7E36776FDE2353896
+:108420004F3BB3A90FEA57C704AF2106C6FF82F935
+:108430003F83FCBDB8207F2FAE6AA3DE2E9E97C976
+:10844000E44C70D13571D1F42635CD494BCC1D4F5C
+:10845000E7D6F5B86926F8810637EAE1A2D61BE22D
+:10846000D77F7F90F73F9A18C3749A0D7102FE066A
+:108470003BECBF2F477F277911E79F575FED6E27B2
+:10848000F277E288A2B9371596DF647E1F88DF0095
+:10849000F8F70F7FAF229AF968F49389BCFFAFCC4D
+:1084A0002C9E3989BFDF7FBAFE10EEFBDD7A5FBDFF
+:1084B000CB355E932F6DDC9F5202F6D3AAFD29B314
+:1084C00034F0AADE7430E52E8C7B92C0834BAAA7D1
+:1084D000BFF214F82BAA37894D304F2807B87534EE
+:1084E000BD65877A541F1E067E90B03E7ABD6BBC78
+:1084F000868FFF5EBA55F9AD9AEB2F3B47B64D809C
+:1085000038F5AA46C109D5AA9A6EBB6532C07B155B
+:10851000BBE75A28916291F257F5D6DB7E3C14E214
+:1085200066568F70C27C6817B7C2F7AACD67F13E56
+:10853000C3D288DF3D50D3DD994C2FA4F503065AF2
+:108540007FE9EDD672905FB4DF37217F20671DBED3
+:10855000AF623FC5CE1FE8F74F0C546F3935CEFBE5
+:10856000DE5DB4E919D2F4D164F02B35EAE991D299
+:10857000B7007A596883E05C875F1715DE0C2AB76D
+:108580006B21C6FBD2F299D1EE5B57F8F5FD44E2C0
+:10859000FD233E5FFA97A3A59FC87A8993BC184F25
+:1085A0005EBD80CA438D9FA0FA840FDF978C1C8725
+:1085B00068E99AE913440179B8C5A2BE7F24980BF3
+:1085C000799CEE0096C77715814E29A1545D49C666
+:1085D0002B00EF9BC9444847835C81F7F44736E59D
+:1085E00041FDDD42F09597B03F1BCAF10E4700DF19
+:1085F00099CCE0F74C3B1496EFE27E4EB5BCB2D579
+:1086000082713667BE34A29C5DD87410E3E83B5E8D
+:10861000B3180C541E9CD99A380EE2313B9AD83BC1
+:10862000C5A79B12C7192FB26F47CA0D753F3D0AE8
+:10863000FFA4FBEE9F335DDF64C23EF5088B574D10
+:108640004DACCB8FF6FB176ABB24635D3ED831A1DE
+:108650007BACCE7508276FB6847EF03427C40995AD
+:1086600008AC5F63BF62B12FAD6FA375C11F9D7072
+:1086700048C4DF6B382E3A7FE21880EFC9A31E345E
+:10868000A7C08DEF539247585CE56C8904244A6F6C
+:10869000B3613FCAC33CCAE5D9AB048C2B9BB34C36
+:1086A000BF1E782757BB8F56103F7BDF42EB47EC4E
+:1086B0000FF12E74BF81772DCD2CFEA272BDBE5D51
+:1086C0001509E07CAA377F6F8A06AFAF89BA2E57AB
+:1086D00026AC4BB8D98CF3BAEFB93876DE63242ECA
+:1086E000D84F43CFD950BE571137F67727DFD73D44
+:1086F0000F94B8E6801C5E30DB352711EEDBB2FD4F
+:108700000F4D3EE46F01F79DAAF124D097BDBB4108
+:10871000605FAD6A150243216F265EFB30F61DDEF9
+:108720001F80756BEFD794131F8E57BE4AFF9D7C39
+:10873000C8F05ACDEF3192F59AF2FEA09F317854ED
+:108740006F36E9FC3AA3370B5E1BDE77F537A4D012
+:10875000F9D59EA2B282409CEAF7265DFF10CF3386
+:1087600002F77D62A1787BAE5BAEFB87448BF33F63
+:10877000C2E1F8DC6DA5E9C0AF4F83DE9AC1013DCF
+:1087800012E516F71F9080998E1333BC3B8FE58559
+:108790008B587ECAEA57A6348EA1769EECC673A18A
+:1087A000D962F1DB701FECE57EEE9BFBD271661B9C
+:1087B0005C5912F2AD6B10FA43173038BC30AC6E16
+:1087C000485D143D50C5F3F3425300CE65BDBB98E0
+:1087D000FE652B08C9DAFDB5BA2F93477107827879
+:1087E0006F22B45DC07B962B85A3781F71E50D0ABF
+:1087F00001FB3E8DE209E4F14A813C2250B8143479
+:108800004FBDF72DC073418C137EEEA2A679AC58F4
+:1088100063C5F5333D2DB66E2D9CE7A4CECC19066D
+:10882000744ED73DF366FAFDDEBE0A8E976E65780C
+:108830004F5BE4CD86DF818A3B507CEF5BC0874392
+:1088400063F09E6C2A85952D01D325A07FA5918587
+:1088500002D47BCECEFA4F368833A7427E18CB2780
+:108860003C24B8D621F12DC7FE534D6422CC13BE53
+:10887000831E6906BF0296FB197E8BEAF2A1BFD464
+:10888000012C4D320632A19FC3DDF876A35D319FE6
+:10889000EF63F3B78E4D053BEF700735B8A9DC3AAF
+:1088A0009CA6EA43012BFE3ED4C01C569FDB85F3F9
+:1088B000F3D97D83A42C7DBD2ED915371CE4E807A0
+:1088C0004C8F3F6F75A17FFA1A63747FD64B7D99E9
+:1088D000DEE2B92010BF661FF04CFB06F54ACF055B
+:1088E00049F7BDA3DEAC8B73AE2E3F80F7EE6B482D
+:1088F0001BC661D734C5EAE276AF89893EAE4ADF4E
+:108900009E0B22F1461DD7A8FF7E21917813A3D597
+:108910004BD17FA7EBD0E55BBEED5E077C272383C1
+:1089200076B0072771BDB6CB6FF0CA5787F1D2E991
+:1089300008EAF69D4E85E5BBF8799C5AAEF6DF391C
+:10894000CDC8EF15B17795013EDEC184BCD87A164B
+:10895000FDD1D5ADFB27B0DFF76274A18593572316
+:108960003F521ADA0206CADBFFDEF7D453B94328B6
+:10897000891D50F9F8F4532ECAB729A241C7D7B1BF
+:1089800005DD7C8EE2E53983C8E5C299A7C68FD1A3
+:10899000E659FD70FB8E29E3A96E5F90CBDAFFB13B
+:1089A000EF97EF2D1A18964B741D59C5364DDE1CE6
+:1089B00091B7D2FC504DDE11519E14519E1691CFAD
+:1089C00064F53B6C812CD149487BDFB353A45170D3
+:1089D0008E1D98012F0A2C6BF86ACA789AAF296805
+:1089E000C3F899DA56C189C7FA6A7CBC93E959562B
+:1089F00067107FCF2EB6A0ED6D9003D52D8243A0DA
+:108A0000F46E6DDA8A7135D5D04ED1B46B6276676B
+:108A100075D3516CD76BFF3906E4E7A539C7B09E13
+:108A20007A7E7407E9FEBD8E0B202F6B9ADAD93E51
+:108A30001C717ED499EE3A88F230E2FEAB07FAB5AB
+:108A400086E95EADFF87A1ADBF836E62E79F5D28BB
+:108A5000D1FA7FAA691F01FA12BC710972FF79C1AC
+:108A60003F04F6E717897B08EC47F7D45CB1DF4099
+:108A7000EB1D9183ABE1A9864159969B242AA78FD0
+:108A8000D8827D052A4B72D624DE04F03C921CC4A9
+:108A9000171A7EB6268995F70DF68573D7DCAC1FBD
+:108AA000B2FC15C1D590BF75CD952C3F34D857A4D5
+:108AB000EDFB7BAFBA09E0BFC1119D6FFB66317959
+:108AC000AECEAF2CDF959605FA6635DB2FE0FAA522
+:108AD00099CAC51995A7B76CA07098F1D358945747
+:108AE0001B3A6EB9B118D7EF2D863837F6C43BDF85
+:108AF000CF502E4BA807A4C31E9610C6872DAB4D92
+:108B000041797F65DD56D8F75367E4A2BC3F9FE902
+:108B1000AACF1A114EBF1DC0D2FA2C76DF235534CE
+:108B200060BC41EA8336D4839EE6E749946F10BF68
+:108B3000568E8F61594CFE0DCB62765246DFEBEBC1
+:108B4000613D7772FD74C5E3FE4D160AFFDF0391A8
+:108B500024A17F1BF5DDBBD652B91107F114AE7409
+:108B600090077781FF37379C57F5F715F9346F0D6C
+:108B7000DB692BA6BAD2B571402BD6B27255DEACEA
+:108B8000C866EDD57D27B581C127F5E921EB601DCC
+:108B9000B112C1FB1773A70D5AB710F7EF9B71BE47
+:108BA000C4E54A07FBFB44457F03E8952A7E1ECBBC
+:108BB000774DC2F5882C5E5DC5933A7E3D5FF76CBC
+:108BC00091EEFF749D0FF673231CA93E90C7820B94
+:108BD000983E500F8ED8E4307C89141C01DFFF17BB
+:108BE000C1E95E58F73F0AA728F2E267306ECD026E
+:108BF0002A2F0C1A79C1E1F7BC1090530B34EF9770
+:108C0000D0EF6007DED1D7FD6896E61C67C68335D6
+:108C1000A8FFA9F38AFDB79D13EF203DF92C523F21
+:108C20003BF27BF332F4031A9B502E1EB991381796
+:108C300082FCE0E7B2AA7E59F8D3AAC360479DCB75
+:108C400012B19D45C5AB50BCB594C2E971BAADC275
+:108C50007D74EF5416DFA3EE9B2BF8BBBB2B1EB825
+:108C60000AE3FCBA48107F97CD3B92A0FCEB2E9F05
+:108C70003E08CB29BEBD16E0F78A18FCDD8115F948
+:108C800004EFD9AC987E2596EF51FD4AD3CD38CE6E
+:108C90008AA98C9E5654B0384CD847006EBDD1433B
+:108CA0004A03F36F10C995A78D077897E32FB62075
+:108CB000B8FD63D02B975950AF84BD13CF477CA923
+:108CC000381EC5EBF62CA46F368FD9CFA6FB97E2E2
+:108CD000B84EB4CF1FB3B94A505E3D1CABC0FC5771
+:108CE00059C812F3303047C82328F7F87C88EF05BD
+:108CF0008CF398C9F5B5CFCACFD9401F7893CB1B59
+:108D00002018B0976711563EEBA1D8A360DFCC7A4C
+:108D100048C4FB8564C9F52EFD79079D6B0AF8C729
+:108D2000F95F63C8067070433B3BF4FF9F3678CF12
+:108D3000C4FD10BBDF4BBCB4BD261EFA63E05FF080
+:108D4000B38B6CFEA43E5689F62EE8C75CBED3F901
+:108D5000BBB4E3A9E344F64BEDBB4F005E14EE0158
+:108D6000B807167A58E4BFD7AA9F6F9231F4A4854A
+:108D700096CFA817E3175178BA17D870BDEA7C6769
+:108D8000A686AE65BF0BABEFFF646C6D21F8C355D3
+:108D90007B843CA4B7C7C02FD19D17314E1AED9AE2
+:108DA0001EDFB93D1B690712F23793B65EF73D0D22
+:108DB0004588983FA72B4590006F6E1EBFD08DEF62
+:108DC0008879ABF034F48B0ECF2463B02FC82DF725
+:108DD0000213C221B2BDBAFFBD60215EB0131B05F4
+:108DE00001E9B1F18158DCCF8899E1D15319A30091
+:108DF0007DBE680C611C937737FBFDCF2E4B680757
+:108E0000CAA581CC9FD0F59EB816EA752633BAEE76
+:108E1000DC25737E22EC1D89F7C475582EB07E3B8D
+:108E200017C6627C14DCFF34C2BD4CEF9FEBC1BFA0
+:108E3000A2DAF1C777B0F714E0777BB47630DC9B29
+:108E40002D1F16960FF83E0CF0734B2CF713B92B11
+:108E500070BCBB6208C461D41A048CEBADADBC120B
+:108E6000EF9110FE8E73359F5AAD81DA83C3C27CB9
+:108E70005E6B383608ECA96AF3327CDF9996BF093D
+:108E80007618FCCC6EF7EF7864F7A4EBDA6567FE32
+:108E90008AF7DA9BF5F8AF0ED309DE8FABD4D24D4B
+:108EA00076981E50DF0639319EE0BD7C1BCFC74E41
+:108EB0006CF3839FC6C3FD16C907D8BBB5B682261F
+:108EC000027E53CF29A66F8C6E5D7B10ECDFF88994
+:108ED0006D6071D1FACCEF16797F6854EB7211ECAA
+:108EE0003A554FD1D895436E1EAA4DD97D5BB053EC
+:108EF00061BC207C02FE90D8FEF63CDFDFE83E88B5
+:108F0000F278AE6F30EE83B04F811C53ED5C906B06
+:108F100020475EEE376E5A3FBACE3C65DC2DFDD859
+:108F200039CC10D4EBBD9777DEA4D6037BF7E2FEF5
+:108F30003006B7D0CA382627E00740C14FFC5B791E
+:108F40002DBEEB0D8297CE77DEEA6C94BBAA9FA66E
+:108F50009AFBA94AB95FA794FB75C0AFAA8D7B05A0
+:108F6000BFA5365FCDF9BE067E4F0ADF0B3085E325
+:108F70005EC19F339E046C500E7E1D3BBB5FA76D90
+:108F8000EF21FE2209E9FC7B93EE5DAC156CBD334D
+:108F900039DE575A983F67F4436B45E6A462EB8D80
+:108FA0001BE6CA7EB420FC3ED7E71C4F2A5C8CFD32
+:108FB000C6DD03708F11D9FBE6A147D9EF5D9FA0F5
+:108FC000FBF356EEEFB8D98AF78B5D03212E417281
+:108FD00064DD1CE5775B97EEB6E03BFDCBFAB1F3C1
+:108FE00060F5FBB87EECFE2EFA8100EE0B6351CFEC
+:108FF000A660CE033A2AECAFEE97240FFC4F4779D8
+:109000007C67EDED5637F417E47EF195FDD8BEB5DB
+:10901000B21F7BEF5FCD77DB759C5ED4732CF0C7FE
+:1090200068FDD7FEEEFACC7FA2EEAFCF57C4A05CAE
+:109030000AD3AD01EF4FC6E6161BC18FB49BCB918F
+:10904000126EAFEF86035A90274DDCEF2C3966C0C5
+:10905000EF02ED3E958BF1924946265F76DF19438C
+:10906000207EEFD0E9579F788F969F3B65C4F7F03D
+:10907000E6707FEB6E78F71DE4E57613FA11AB8DA1
+:109080004C5FACDE3794E92946F74A88EBF66E93DD
+:10909000D1AF556DF76F7A05CBD39D14B3701F9484
+:1090A000E9B9BB6259FB18FF2F5F03BB735FAAD3FB
+:1090B0004BEB2F4873EF03BC66989438A29EAB0A23
+:1090C000E1FBA2C7FC4C2F3E068207C669B5F1DF63
+:1090D0009173A5CFA5FD1C7F3C15D743E52DEA4F25
+:1090E000C79F32E1B9D9F3DDE332FFE731B918DFC9
+:1090F0008B39B63DDF492D4BD2556C0C807FDBF3AD
+:1091000034D3E7661B9435001FB22FD6A9B3479F0F
+:109110002A63EF47543E34E562E7D820DFB5FEDD31
+:109120004E12CA427BB4BC7F13C49376B60E71B2A2
+:10913000E3AA343C24A9E5E7CB276406DFD05E1917
+:10914000E9F972FB07BAE8FE9D3B91E0EFB769CF02
+:10915000D322CF217AE6191E3DBB53B9DEA62FBF1D
+:1091600025D31D02F956FBCCB7471628305E08E51B
+:1091700021F1317FFA09D93503E8367E7C4017A703
+:109180006556185FCD36F1FD9E048C5A3E54CB0BCC
+:10919000C791A8E7362685E901367EEE1C59FE7F89
+:1091A00000F2988AEC008000000000001F8B08008D
+:1091B00000000000000BC57D0B7854D5B5F03E7360
+:1091C000CEBC92996426992493F7C93BE4014308E5
+:1091D000112DEA24040C98D209A062B538BC41C90B
+:1091E00043B0BDB1C566201102A2861A1128E084E1
+:1091F0008762D5367801A346EF8048B1D5FBC747D3
+:109200005BB4F7F78B4A29528188964BEFB5F55F2F
+:109210006BED7D92394322D8DBDB3F7CB0D967BF51
+:10922000D65E6BEDB5D65E7BED1DB36A602C81C159
+:10923000CF4C334B64EC1AC67F324F316FD0C69897
+:109240004555A9FC9A5321D37CC867AE0C99168961
+:10925000D40FE909230B59CA21DD620FEECCC29667
+:109260005E86FD2C9A00FF85A68B64D66629C3EF27
+:109270006A4FBF8BB193079C9EF5F09D7DF995CC0D
+:109280002A189BCB443D336BB7C431F67C9B14B298
+:1092900040BDB99BCD3BADD05FC56AAF6C87FCC00C
+:1092A00076C9B313EACD6DABCCDF02F93BF7977A01
+:1092B00064681A83E3603EE80CCA50FF9AE649EC02
+:1092C000E3718CCD37074D0A7C674F4B6C0FA3FEC3
+:1092D000DBB0FF65D02819E0F90A7FAE1F4A176F8F
+:1092E00036C364F9DCBFC27F8261F96CE8B7BB4B5F
+:1092F00066305FB617BE170E7D5FA6840E49318CAF
+:10930000D57747B4677F330FD643405980F0E832B2
+:10931000B13B7C369A74525D29637FC0FF26336669
+:10932000CAF48D53C763263769861DE65DC5E735E8
+:10933000B04F22BCD6B32613C37E3AE319BB3A6CB6
+:109340005C0B0B45437A520E50F922F3464A6BD41C
+:109350002C1AEF4ED66F6239D8EF80C907E3D9FBDC
+:1093600080AE2597CEBF06F960FCC87C3055F0C1B1
+:10937000B2532C742D8CB76C250BD58FE6A91DD25A
+:10938000450A0BC4005E17010E62451A55C6F1AAC4
+:10939000160EE16569509F477CAA6178463C869726
+:1093A00037F67C650ECF279918B3C60DD11908453D
+:1093B00070274D6A1ADB04705EB3322833985F4A17
+:1093C000BA77522EC01B5DCEE7DB78DC6251C760F6
+:1093D000DEC7B2A1DE176995CFE54179A3C2BCDD36
+:1093E000501E0D78E982EFDBAD2C80FD3F9EA75229
+:1093F000BF6E13E75FA3E263636D4897BE9001E918
+:1094000092C01CC88F1A3EB7DBA15D19B693A8DDC8
+:10941000607B0B6B8B0A6B5FF5A29531582F175E43
+:10942000B007CD509529FE4C27F497F87B335B0F9E
+:10943000F9B32FDA97607F678D6C7637D477C9AC34
+:10944000A99BF8650DE1FF8748D7F1C84D55A90CD8
+:10945000795F9A96CADC58BE9ABED73B81BF86A177
+:10946000EF607956DFCD9CAFCCEA4E18EF82B3FFA8
+:10947000079807785800F2CB550E77E3FE49637FD3
+:1094800004DF1B7D360FC7BE7F2CF2AB59BEE766EB
+:109490000BF0D71479E5C0BD308FFA749BC30C4D27
+:1094A000AA33FFE3B7B742FE93FD4666463AEF990B
+:1094B000349B655F0A87962E0D1A3FEA0F5B2F7764
+:1094C000EDD5E7EBBBF5F946A67CD4AFF101A06082
+:1094D0008B6A779D8C26D9E1F90AF8DB6C6E3AD558
+:1094E00005F09A5F327B56C1E706D5BF03D7538399
+:1094F00061E028E2D99CF9E9683FE0A52AF3CBA313
+:10950000A988FFFB9807E1BE60AD9C4BF4D862557B
+:109510000361F2AB51F07F67462D95776E35AB1244
+:109520002FAF1D0F726B092D61AA623100FE1B3730
+:109530004FFD441A4DE516A44727F029B57B4E0A86
+:10954000AE82764B362FAE65507E86054D1680E78F
+:109550000F623D35CABD532CF0DFCEB89A51285F5B
+:1095600094BF2A3EA4FF5AECEAEA217CBD34B83EFF
+:109570002D1D27002F373289C5E2BC9DFE97709EB6
+:10958000F5967E5325F473FD5FBF20B9BCB8F9D5BD
+:109590009C13E350DE78E712BD617E284716DF7B1F
+:1095A00088BE4B332C04DFC9745BD00CDF5FDD62F7
+:1095B000E679A789F227B74B945FDC2D052D595822
+:1095C000FF627C25CAEFED4687995D8AA748BCFCFF
+:1095D00071DBEF621880FC47102DB8BE98A329C636
+:1095E00067C7B2A69819A588AF1B3E41F9B578BBED
+:1095F000EC09A19C7ED9EEC963989F3C6AA10DDB62
+:109600007F1E5F89F8DB31D921D377D9877288290A
+:10961000DEBEEBE1BBB2E32A15D7CB91ED1CEEC564
+:109620004ECB1348E7EBFF2A13FF2B06E6DF674319
+:109630003A7847E1BA53B7ED9982F8FD635D8A81C4
+:10964000EA3F2B3107E2C3D99C88DF174B8A0FD73B
+:10965000D992CD4B6B59CC10DED7A832E1BD327315
+:109660006562BF8DF8FE66D477F5DB81CF71FC199A
+:10967000EFFFF656D710DF4B33364FBF06FB7FD2D6
+:1096800048FCA5F5D3B8EDDB823F180B019E160B05
+:109690003C993357E6E3F8975B0F8B5737E53B6C04
+:1096A000975F1783EB7D1BAC8F62C6FEAA4AEC2B3B
+:1096B000A0034B8B233D33D27AD4F493ADD0C0F5C5
+:1096C000BE8779F7409A64665E09E457769642E56C
+:1096D000D95926C287F297E57BDF04F89F53FDD165
+:1096E0005990CF64DEB1A867D40147552CF4664386
+:1096F00006294738CCC13D24E7200F78DA94C09E74
+:10970000581F066786E80FD6AB0BFB39FBDE974781
+:10971000118F0D199F8E46BDDD78F10B930AF4B4BD
+:10972000F54A24676D1E1F43FE68ECAD630B4A8645
+:10973000E463A387CBEF4BE44C9691CB33D700F592
+:1097400033359BCBB74E275F9F5B9BA38228F7B631
+:10975000BA8256043ABA3CC050BE4F2F973D08B665
+:1097600066A7F82C9C5E16EFAB4C467EF5C81E141F
+:10977000F17DDE8FDBE221FF66F9648F0C799B7748
+:10978000577B36CEDB6314E539019CF71B132BC9DD
+:109790005E99EE95695CB6242688AAA2CFFB8E6BF3
+:1097A000018CFB1DE67DE404D0B1069437D2B10FE5
+:1097B000C7067A9D71F827205EB4F97CDB33F591FA
+:1097C00013E1768697DB03F089EBB1F2E1F1305AD1
+:1097D000ADBC0EFBB9FE3A4E87D3CF9A83AB61FC8A
+:1097E000D356D03361FAE2B49DEB1D5F9624ECC2F0
+:1097F000EE0C94FB8379659401D7FD3D0E8E0F9797
+:10980000A93B03D7DB9F247D3F77B6CB2C0872663C
+:1098100069BBC48200E2E9A79ECF40F9FBC99EE77D
+:1098200033E685C117D94E4BBFAB8DD7F198D70220
+:10983000E3CD63DA78A1341C6F9EC7FC21CA0FD632
+:109840003ED9DB1F663F90840CABCF367B497E9FB1
+:1098500083D5887CA7B53BB724CA8B76E6396609E1
+:109860004A30D4BC5E3964C6FEBCDE5C17D0BB4156
+:109870006B1FD17FA7E01FA9470AD9A17E74C90039
+:10988000C9DBA516DFD154285A8A7484FA53918E05
+:1098900012F2ABD784F356242ECFCF387C7767C132
+:1098A000BC1676E8E9989EE5E0F375B8B83DD86057
+:1098B00053505F24B6326E077EDF10447DED8A8AF6
+:1098C00019CDC08E31A5B86D28A7AECF8F6A33C42D
+:1098D000E2F78C20D64F4F29A476812ACEDF81442F
+:1098E000166C95B0CB2689EC40473F53E07BDA04F9
+:1098F000E6580FD9DE2C6E27BA9967B34C7662B75B
+:109900008476A286074DBE23DFA0DC3B2D59886FED
+:10991000A45E89EC3ED9D03D07FB1D898FB644F08B
+:10992000D1967F321FED1A918FFC2AF191DB323CE8
+:109930001F81DCFC46F559C0A700BE9204BE1E166E
+:10994000F265E0FB16A21BFC4838DF5AD15FADC5BB
+:10995000169247939CF874507E433FDBC0FEC47D53
+:109960004A32DACF90A6B6CE55B9FDDED72F417F69
+:10997000D1575948EF3D60E8CB423B3FA9A8691F4A
+:10998000F247D29C92B256B24FD29C28F751D6E001
+:10999000FC1B9A27F9B81D00FD221FD599683FD1FD
+:1099A000706FA58FDB0135B43E1A375855D46793D5
+:1099B0007AB356217F34AE04FB08E56F4FD7964546
+:1099C000906F9865F3A09D62B5CC2CC176AC5DBF5D
+:1099D000CED649DD641707A6320FCAED734143C0E6
+:1099E0003806E56CFF8E1FA11E5F5AE209A8B8DE9B
+:1099F000045FE632D20B9D4E6F721CE0F5E0DF642F
+:109A0000DA17758E853CA42F097A76D679939D90C6
+:109A10009FB7C14A78EFECE2E5E7EC8020E83F45EC
+:109A2000E6FDB1580BD73397CA030BE23D7102D361
+:109A30007E36633E45CB773C46768CB6DE3BB3380C
+:109A40003CF6125F165ABEB7ABE3FAA260BD27CA56
+:109A5000066D531440BB3B1AC7E4792F0EF7A801DB
+:109A60000049C1EC7F6FAC9E189EE7F587DA3F3066
+:109A7000A33A8DF4EB6039820D7A57CB7BAD00C7EA
+:109A80005AFB50B902F6A4A54712ED27CC980CAAB0
+:109A9000F89C24C60F281BBD808F87AD4C375E38DD
+:109AA0007C4A44FF46E8DFA68AFA8152DFE45C8004
+:109AB000B74C6BBFAAC30BF03D6CD4F7472815ED2C
+:109AC00031A38DF7EBDCD7376E481BD2FF600FD880
+:109AD000B3C70FD9016BDFAFED180363453B3E37CA
+:109AE000A17ED5F479A34B223B2372BD2665F3F505
+:109AF0000A766D5236C90D6EEFD6A2BD2B939D3BF3
+:109B0000059756E34A1F43FB12EC86D46CB21B3E0A
+:109B10003D7908BE77CE384D767EE34585EC8F469D
+:109B2000B03FD06EB7F4727B96F51849EF6A74BFF8
+:109B300053C89F4E27E87DE4D397A5F1C8A78C357D
+:109B400065DC043468C9F6E6211CDA7E2C12DEEBF3
+:109B5000B2B95DDE5858B5251FFBDF2D31D4FBEBC4
+:109B60000B3F4A44FBA4B1F7C3C48561ED96F63CB4
+:109B70004A7858BAD738ECFCAFCB9669FE0D2F1C4B
+:109B8000F0E27A3F1D94682D2F5182EBD0AE5CB28B
+:109B9000C480961A2B0FCEBD15D73D9B6D627930D0
+:109BA000BF5CD44BB89FD83B33700DEEDBE0AF0405
+:109BB0009FB6FA16D1FADE3ADB62635908E7BCBBFE
+:109BC000090F8E282FE2617D6155328ED35037C543
+:109BD00081FE9346B0B3B0BCE1DEEF923F45836BAC
+:109BE0007D8FB106EDAF0AB0B7FE15E04E8F9B56E4
+:109BF000E381F5982AEF1BBB02F29B4690BFBFC9D9
+:109C0000E1F46C937C81EFE0BA7F41627BD4A1F2F6
+:109C1000CC1E6ED7DD9CCDED40EDFBCDD9DCDE9CBE
+:109C200018E89B84BCF78AD21F8DF66F23F37E86DB
+:109C3000FB4EE6B3A97B884E5CEEB85A54F22B5922
+:109C40005CFD0F8CC1F2890AED2798D2FF088E7B4C
+:109C5000769DCBB39E09FEC5FCBD2541DA3F64FB72
+:109C6000E7237D2B841D79F6851BC6CE2B19B29375
+:109C7000D6755983AB010FEBECEA4F6A50BEFD4538
+:109C800021F9C62C037D93901EFF1547FDAEB30648
+:109C9000D721FD031B8D54BE2FC5DF807C79AAAE72
+:109CA000261FF7C1CC16C8AF037E32BA3A18DA0BBA
+:109CB000B07D203F83C5E5632AE42705E62A12CA62
+:109CC000F908FB6312FA7968DF0083C3F72A21B62B
+:109CD000F2800B4E5A6809B47D153F648F1CFB72ED
+:109CE00096821F353BC560F12FC5A6D5B3A3988CCE
+:109CF0007CBF66E0A801E613EDEA233BB6BE5BA29B
+:109D000071EA0B9F33A1DFE4AE6EBE2E1BC53E0091
+:109D1000F09781F6C0DAEC68A1C7DB38BFB33EDA52
+:109D200047B367383D19837AF6F0FDC42AAAA7F530
+:109D3000675ACDFD5EF5C21F037290CA7F922D89CE
+:109D40007DED6A9176F0548CBB49EAF3CA88D7B1AD
+:109D500092279C6FB4F429212F620F0F4CC1F53B61
+:109D600000FC857E992D52DDDDAFC1FCB68C2FF253
+:109D7000A009E5067692CBF03BB022E0BDBCE7B38C
+:109D800029C8376070D37A6DE8A994EB6DA4B769E0
+:109D9000FF9814DDD485E5497714925E8D1AC7EEDD
+:109DA0009801DF7F2EF09A6CE37E2EF7EA40D6F220
+:109DB000121CDF77F76B387E6914F929938036F629
+:109DC000384ADBD12FE466AB24ACF7680CEF3FC117
+:109DD00020DF5157427297F2711EC9BB13D29E6C9D
+:109DE00027F76799590DC289DF693F069C81FB59A6
+:109DF000F473613F49393C3D9B1C5250406C65FDFA
+:109E00003BF6207FF6981D88A7DA9E5F1E477D5996
+:109E10006B61DD32DA2B1176C6CAF49987903FCF99
+:109E20009D39B9E37EF8F6E84D073D7EA28BDE7ED4
+:109E300088DC2FECC42AC923DB7BBFCBD6DB7B833A
+:109E4000F97FB8BDC7EDFAC09E68754F983C6F1496
+:109E5000FBB4734BCEC7A09EF97890BF404F570C10
+:109E6000D92BF376477F88EB6AD0EE8FB01B8E3DFF
+:109E7000111D40FA9FEFB6929F4E41BB07E0396338
+:109E80001FF80122C765F27925DC3FEC337A56438F
+:109E90007F8D779EFEB901D69DD205764F2CDAFBD9
+:109EA0006A2CC9D9D765B607ED32C5EB40BF870626
+:109EB000BFE29CE2F696A05CE4F35F660AE5931DC0
+:109EC00064624B281F13CA47BBE725A1779645411B
+:109ED0001EBE37BBFD7F41BAA598B9BCC276F8BD9E
+:109EE0004BD85B5D801207E2E538ECBBB384FEC65D
+:109EF000FDCF83E9C1F5E4C7B1103D3F7EC5BC137A
+:109F0000FD3C1F171A4226EE97203F96DAAEB0644A
+:109F1000A8AF1EB70655EEEFB21840FFCF7FF8AEE0
+:109F200037705F31FF15EEC79A7FE7CAE9B8FFF8CF
+:109F300078C61413CA9B85CC4F7EE7C58CFBA197CE
+:109F4000B220F757338701C7BB0BC4C6561435017F
+:109F5000C0FE55F05932486857A86D9027A3D9DB49
+:109F60005103E3CE6B33D0BE647EBBDE9F7E61FDCA
+:109F7000DD35A8C7D7B619B8FDD82E911E9FCFBC26
+:109F80006EB43B34BC16E4C473FF689BC18BE35CC6
+:109F90009F6322FE031205697E226D330A3FBC8057
+:109FA000631533843035483C5DEB506A86D3CF5A15
+:109FB0007F6DC6260BFAC306D20DE407BE60F2CE53
+:109FC000263F6A5C3E433F629BBDA9BD8697D39AFC
+:109FD000B9601DF051F9B50A37F8981A87F2323D89
+:109FE00087DB0F91F35DD8A1CF479E4F2C0DEAF38D
+:109FF000F399BF203907FD46FAEFE9395C5E5D58F9
+:10A000009F25CE013C740ED06654DFCE4279B54E0A
+:10A010002179B92A8DE3CB90CED36C67F56CE25FE2
+:10A0200027D817042F873FFB5A97847AB3CDC9F9F5
+:10A03000F27F0A7724BC37E4E413BC6D68E4C1788E
+:10A040006DEBA420C71787FB4AFD174B72F47268AB
+:10A0500030FF8FDF77727E5C278BF5E6203934CFB7
+:10A06000C1E7F4B1E4792284DF6D601F00DCF3D72F
+:10A07000C96568A74C9A69A37934BC62257F6BFDDA
+:10A08000CAFE0CB267ABFAF39B86C12B42AB68F2F7
+:10A090000BEACD73C13E01D76DBBFE9C0A342D0B7C
+:10A0A0003F779A99E6BD2F2701F7231FEFFB25D2B3
+:10A0B0007B9F95F413FCEF9019E5D70B596437E5B6
+:10A0C000A7F9EFCF41BD1E15DAF16416DA29DC4E8F
+:10A0D000AAEF3577A11D38AF2DECDC0BFFD9A03FDF
+:10A0E0000763ED71E4DF609DFAEF4BB645B4BBE466
+:10A0F0005C8CEBFB4D26FF28B4EFAEBFCE9B8C7281
+:10A10000F5CC520343FACE973D8B508E9CB1EAEDCD
+:10A11000EF33764EAFDD8374F6E4239D778F486787
+:10A120004F3ED279BE81F9C3FBA9473A037D970917
+:10A130003A9F3970553ED2F9D37D57E5239D3719A3
+:10A140003BBCB86E7665FAF7221E4F4CF691FD04C3
+:10A15000F22AFF9BF0E38B11FCF8E2FF1E3F52BB9B
+:10A1600091F4E1D19CE1F5A1CBA4A6A13C9C67317F
+:10A170007FAD5EC49F61FD6B1633F9255EF9F2F386
+:10A18000879E403BA457263B44EBEF15C59F837E3B
+:10A1900085578EBB3D0169E4FEEF16FB18B78505B8
+:10A1A000D0FFA1D9FD9AFD18298FDF17783C9DE3D8
+:10A1B000FD36ED1785BF7689E8D312FC9CDBA9BB81
+:10A1C00025F2C75AD46E2FDABD0D2FCF75A0BFF67A
+:10A1D0005490FB671B0E8C25FFEDD2E0ABA154B46D
+:10A1E0000B7B2507EE1F96EEFE3006CFBB613FFAD4
+:10A1F000494ED87E74B2D88F9E0A7E1C83E7E23027
+:10A20000FE54D4CBD1AE0113F26F03ECD3A00A6B92
+:10A2100050068E627F0D2EE609A0A8E8D1EFDBB4D0
+:10A22000F3CBAD3E13C9BBADBD5210F76989267F94
+:10A23000561AEA2796E6A0732EB15EFE33C79B98A6
+:10A240003B3EFCDCD8FB971C7EAE4CEDFBB7C4124A
+:10A250001FF61B9997EC802D7621971492537FDE81
+:10A26000E6A47D0FFD40FD3F07B328AFE9EB450AAB
+:10A270000B2980F745B3BCEF21DD507E8722E477C0
+:10A28000787EF03C9AF571FD02F23C34DCF9B83886
+:10A29000A7C6F3DDF0F60D6C80DAE139AFAE5F6D85
+:10A2A0001FC09AC6AA00F75DB7DB3C68BF34025FE7
+:10A2B00037970DF1E13231158D0F1B849FB771C9AE
+:10A2C00047B41F68EC911CE8DF5DE6E17CB80CF652
+:10A2D00049E6D197AE5BD60D7C1806F748EB785C63
+:10A2E000AE7E1D0FE6FF49FECCEB72F5EB579BBF30
+:10A2F000E6171F9C67AFC4D757C4BC22F79791FEDF
+:10A300006C6D7F78A572EDA6087CDCF4BF8C8F9114
+:10A31000E4DADCDC91E49AFEBCE01BCBB5C87383C5
+:10A320005CEE07C773033CD7FD9F9E1B7CA276247F
+:10A330001A480F7A75E7A968A7E338EDDB65B20F15
+:10A34000A6C8FC1CBADE6E263F6DE4796BA33A45C5
+:10A350009C2FF6FDF66AD49FFB8D0CF5FA12DB629A
+:10A360003ACF6C949F3139D461CE19954364BF7F45
+:10A37000D3F3F775B983E7EF5978FEFEAAEDF378CA
+:10A380007F185DAB4AC0D02FA1389661E5F62382D5
+:10A390004FA245FC844509306758FB91DAFD34979C
+:10A3A000DBCBAF8A381AB789B5637CC6C3F6682F92
+:10A3B000EE4BDC061EE7D392EDDB8E72D2A2723C2E
+:10A3C0003FFEC22DCC00F37FDCD84DF224506FF35A
+:10A3D000A05CD4FC305AFF56B15FBD52FE3F30C87E
+:10A3E000779CFF07F3FF2479F06FDA78DFF49C6C39
+:10A3F00033E046B74E189D87BD81E73B5997F2F38E
+:10A4000048FD8CC4D76FE7FADECC25B9E01D4DE7D7
+:10A41000FE572877A2CB073E467F0FDB6F5671DFD2
+:10A42000817E0FD2971B92B91E533C158867B0F7F7
+:10A430002A304EEA03FCEFD523DB87A706E513B7E6
+:10A440000F4F8D289FFE3EFBF04799BED3C867276C
+:10A450002ABDF9A83FD7DA017EDCF73DC5E36BB62C
+:10A4600059397F6E93385FB2E678CD7F42F30A3C6C
+:10A47000CBCFC723F98AE5E9F96A30FF4F96ABB62F
+:10A480004138FE97E5EA92FF8A413FE8C8FD04881B
+:10A490006E15557D84B7819725B633CC3FDDD8C77F
+:10A4A000E3D4D205BCDAF70BC2DE5D94E7CDC07809
+:10A4B000AF4FDFB358582C9842C8636897F96C7453
+:10A4C0003ED0D0CDE3481A56323A0F6E40FF6709AE
+:10A4D000FA05EB18DA7FCFA9FEC2BCF1789E610BBA
+:10A4E000C8B1E8379FC1D0EE3BFB1ECF37A8FE12A4
+:10A4F0002C6F5CD9AF3B87A8F8EAF335E8D7007832
+:10A50000C94FE042BF4D189D66E7F1F84B2DBD29BC
+:10A51000027EF4E313FF77CB41B417A3D53E3A177D
+:10A5200068D8CF8DB80AD94BFE7B76571C433E6A5C
+:10A53000D85F39F635AA6F1D8BF66EC5EF6B1DE837
+:10A54000A7F8F45A17C51F64C8FD4BD1DE3A92ED47
+:10A550009F84F8B09707A7A2BD9A09F62ADABF9F91
+:10A56000EE9B3A16E1D6E4DF26F47F43BF9BEC7AFC
+:10A57000FF36B378B3EE47FFF7CE24DA3FEE4BF168
+:10A580007F1BE7BFC9CAE10D6CB4F2F52AFCDE916E
+:10A59000EB5F5BF749B281C649BACD42E7D49A5C1A
+:10A5A000D864647E4BCE903C1927E2E9001F3C9EA4
+:10A5B000AFB78EC78188BCCDA58F6B3C9D33791C0E
+:10A5C000C2332E4FA1760B2D0312FAE1178AF3F94D
+:10A5D0001B449C85166775C6E15B80F8602B6B8613
+:10A5E000CEE5B3B1BD83F3BF889F89BEC8EDE86CEB
+:10A5F0008789F8C6DECEF8B912F00DD267E240DFE7
+:10A60000A458984F6E676822E2F3958B06C2875272
+:10A61000F7069DA7C422D9A09F9C0DFDEB0AD09FF1
+:10A62000E278F75AA48BDAE1A842D43DA7FAEEC942
+:10A63000A375DE5488FBCBAADF1879BCE0CBD164CC
+:10A640000774662CA378C1B3EF03BF665DAA0FB48D
+:10A6500034C056537C6076CF3BE4D7B7EF97868DF6
+:10A66000FB7C38CFC6E36F027D1487C626BA081F6D
+:10A67000CACBBF0FA0FDA1AC53C893D166F41AACEE
+:10A6800048D7558CFCF0799D0E03D22553C49D9C70
+:10A690007BE5BF47FB69BFA2F9F1833C4EC8D8BF39
+:10A6A00006F75FCAAAFEEB6005B3FAFD4E4303FA54
+:10A6B0003D8D030DE43779399AFCA3993D39ABBF41
+:10A6C00005F9CC76079350FEBC785726F27500E664
+:10A6D0009937CC3C9BF38CB45E9497A30DA8B794A8
+:10A6E0008D8CE21415676215C1FD28E4A19FE582F7
+:10A6F0006FB4F34900D78DFA68519E7F37D23B5A29
+:10A70000C801D61C45FE44BBC2FD1EF6E6F79F5DA0
+:10A7100005F91DC21F7BF895E219E4BF5BA7484805
+:10A72000870BCEB9990EF8FE8B3C6E8FD8953EE61E
+:10A73000B085E3FF30C56566BFCCE3D61423E713CD
+:10A74000659DAB0BFD835FA4F929FEF4DAB6904C4E
+:10A75000E75B8E138FD4A861FB9BCD5C8F34ECE557
+:10A76000FBEAC8FDCCE5F4C7B13CBD5D3E98FF27D0
+:10A77000D925EF0C8EFF77EE53987E7F17699F44A3
+:10A78000EEE72EB1BF23FA1BC94ED1E23CAA86C622
+:10A79000217E78D5AED941015D1C4C958D8FCB2C97
+:10A7A000FAFE9F12F13B5A5C4C62ABBA0AE3CF0748
+:10A7B000EE63E46FD3E276B4389D4015DF47040CB6
+:10A7C00020F7B2F07CA883E27352594892683FD0D8
+:10A7D000CFB07D12C6E940FBFEBC6C827F3BF3B478
+:10A7E000CB24175509E1B7627C473CC21DDCB20897
+:10A7F000C7BBC946E35931BE239EF611B48E537CC4
+:10A800003CAE73D2121E0F9A02FA17F329B99C2F8D
+:10A81000ADB34D14E7A9C56D68F11D1A5EAA04BE5B
+:10A82000530A1665E17E418B03D914157CCA2A634D
+:10A83000FC8790FB4B0D24F7B5F8BACE3C3588FC6D
+:10A840007E0EE3406D571EEF11895F2DEEE3FA7423
+:10A850007F72FE788AFB203DAAC56B68FC1246C752
+:10A860008015C6DFFA32B7DFAB969808FE734BA7A8
+:10A87000917FF1DC5203C37554D56BE6FC1731DED2
+:10A88000D6D92616C27E95A015E5A7C60797B35F51
+:10A8900081AE85E8BF3DDCB237E704ACF9232DDD9E
+:10A8A000949EB34ADDF2184C07E6A0A41AFD64C6D4
+:10A8B0004CE56A8C6319C8908075CAF6E6CEA27C16
+:10A8C000C2C007989FF6E4AC590AE8897379033B44
+:10A8D00024A8EF2FF87026E5912753189BF0C46F3A
+:10A8E000660668DEDC1F3549F8A3CC4EFFB5F909D2
+:10A8F000785FA07F4D1FF97D78DC3FC605223DDCE7
+:10A900003613D9376E118FC9AA457C269ECC40BE1E
+:10A9100035792C9D67DB98BABF0FCBD3CC5CDF3386
+:10A92000CECFAD79DC5F4C2A1265679AE65FEA0FFD
+:10A93000A0BC6ACD7252FB41B9BADF1CE47E2E3E48
+:10A94000FE5B074AE91C4A8B3365CC913EAB94E22F
+:10A950005174F987ADFC5C94298E74B41F5A8DC272
+:10A960004E15F9A834FF77F3C3ECA4B726FF4B09C3
+:10A97000AE8733077F948B72EA0613D8F1C3C8A55C
+:10A98000D4422E97CE196DED12D86D6FA4FAE7233D
+:10A99000BE8E47CF99E28479CD8EAF343911DEC0B7
+:10A9A0005332CAC904416FE72C0E9FB3DA272D84B6
+:10A9B0007E5BADB09EA17D825FF192BDEE9F25DDF5
+:10A9C0000470B74AC27E676A2CD9ED856A2C9EFB5B
+:10A9D0002D6B7E87E2AE652107642107DE6EE9CF2D
+:10A9E00055F240E5766F94D1DE7E479C3FBF93C51C
+:10A9F000EEA81B66FFBB299FDB873364B514F9C83B
+:10AA000075FFC4776A812F64932748F44BB7ABC8AE
+:10AA1000EF87EC15EE7EE847CABCAF1CE3965BD32C
+:10AA2000EF2BC7B81339CEE3F685E537E5733EAEB5
+:10AA3000C67A88B7E8A672D463FFB0FE62A1BF925F
+:10AA4000BFBFBFC17ECC1CAE6596810C05D6A7C723
+:10AA5000EDDF8A74BB30F7433A8FFD41CA5B1F605C
+:10AA6000FCC45BC68E49312887B224C1B7DC5E3B8B
+:10AA70005AA0F93D79DCFBD162EEF70439C4E32B2F
+:10AA80004BF93D9BDA598CD673AD88BB98E2E0F761
+:10AA900096A69467795A616AD3D98082727ACA710C
+:10AAA0005F0CD28FCDF297FB4A47B6C398DBA886DE
+:10AAB000CB95A96A581EFEDE58A8CF7FDBA3CF7FB7
+:10AAC00067C25F0BC2F31BDDDEE771DE2F493C8EF0
+:10AAD00033703573D03C5D5200EDA5E2E753BA8484
+:10AAE0007F97E20D7F26F673CF4F60549EB8D7B2A2
+:10AAF00013EF1F687E72599417BB9925338EF0416E
+:10AB00007A764012718B2E3A0B6207EF7670FC4119
+:10AB10005D13F47370AE4AEB38D16660D7E15A2FFB
+:10AB2000B790FDA4AD8B562BF037E0B122D512853E
+:10AB3000FCDE6AF46CC6BEE428B38A7AB532C6423B
+:10AB40007DCB3F56482FADB29A29F4F5F08351944E
+:10AB5000AF50980FE33500C45998BE65F4049B705C
+:10AB6000BE500FE7DBEA6424AFE40A13E969E89713
+:10AB7000E87A78A321C868FE950AC5630A98B57576
+:10AB80000723D1F7C7C4BA960D2C44722CC5427264
+:10AB9000EC08F48FFD1E7E5DEE223F5BA17A3B96B2
+:10ABA0009FB714D0FD9CC6C17B478A01812B1476C8
+:10ABB00094B397DF0FD3D6B3265F22D73348C15C57
+:10ABC0005722E320AAF80F4C2311F53E237B5E3B6E
+:10ABD0003F4CB768E58A17C7491EACCFEF67258A97
+:10ABE0007C6A4116AD37A8123294A1FDF1CBBF208B
+:10ABF000DF6AF261C7DA1F937CB814FF85DFA7FC18
+:10AC000034BB83E3BF200DD7A11C559086FAAED587
+:10AC1000E9517D61F9425846B3E3103F500FF233DA
+:10AC20006B3ECC55C2FC83A9052A094BA8E78D07CA
+:10AC3000380E5BD5345CAFC38C5BCFC78DFEC78E3F
+:10AC4000EB8671A1DE613B8C0BF5765BCD2143CCAD
+:10AC500070E34F5071BCCB8D0BE824A44E137806E3
+:10AC6000BE08A05FEAB0DD40FC394DC4EF1E4EE0E7
+:10AC7000E3B1427D7C4D6E148C4FFE587D3CCD0D72
+:10AC8000D2B636D4CB8F596376223FFE52F0C9D16B
+:10AC9000E81FE7A25DF5CB39F94750AE4C895DD589
+:10ACA000864C328D7593BCD1E4DE85E40F2B300FDA
+:10ACB000F2EF9A02A0FB0FB2DF9A839D1F713E96BE
+:10ACC0008BFA0FE4C3B70A122E855FE3470D6EE4DB
+:10ACD000435C07837C1801BFC6476C7A3705206E3A
+:10ACE00007BB1453CD4E65AC89C789ABE943F30369
+:10ACF000269E6269E2F3581520B86F703E42F168F3
+:10AD0000D78EF2FB10DED9633ECB50B0B27B6E0122
+:10AD1000EEC300DEBAFF9FF046DAE5978B97D6E0E8
+:10AD20008A5CC7DAF8D28CBD142FDD38CB46F1D35C
+:10AD30009344DC69E31203C511C1FE8DECFE066687
+:10AD400009A21CBE46D8D15A1CFF8B12F77F060EF3
+:10AD500098D53D61F6F8A571D42AC5690756F278F1
+:10AD6000EB417BBB9EDBDB837A4DDC1BE81CCB65B8
+:10AD700079E7DD2AC553BC24F1FA81B98CDBEB7588
+:10AD8000A27CA143C45BC05C1287E2D93BBB18F133
+:10AD90007FA73D9BCA5364AE7FD8B7B8FEE9CCE22B
+:10ADA000F664E7ADF9540EFB825188F7F932D8CF3B
+:10ADB000FCFC9EEF0FF2F878917EDA4D05DC2E1B3D
+:10ADC000B473443ED22FBB2BD3BF05F965618937DD
+:10ADD0004302BE9A6FE27E57E0BB6D7867A6863568
+:10ADE000ED5672F0FE45D3BB861CE2BBC789EF8AE5
+:10ADF00081EF72747C172C18CFE52F0A538DEF0664
+:10AE0000F9AD30325ECEFF148EDBE9ECFE7D03EE51
+:10AE10002B7ACD44072DEE31729D87C173C2C8E1F4
+:10AE200071C932C1B36F3878AE84FFC3F92D89710F
+:10AE30003E1F691D24292C602F1B5A071BDDFE10A5
+:10AE4000C23FB81ED6F07DE42570CB36E28B9B6FF7
+:10AE50009539BF46737D8EE74DC9307E9D18FFE65C
+:10AE600075BE6A27D6AB93080F75BDF51417C6AA31
+:10AE7000F9B99107FE203CAD42CE69E75BB345FBD3
+:10AE8000998E3A23FAE366D5EACF9966DBF839D68C
+:10AE9000CDB38C1F85DB3DB3D986CF308E71369E06
+:10AEA0004369F5818FDE2F183C872AC073A823C21F
+:10AEB000CF720EF81AF9FEB584C5DBEE06BE2BF88C
+:10AEC000694919FAE326272EDDBD11F24F6E2DA236
+:10AED000FC6B89B7DDF31696EFC8A77CB541223E1F
+:10AEE0003D57CFDB1756DC3A2D2B06E5BFE817D7C9
+:10AEF00013EED7A3FC9D7550CF3D3ABB0CE34BAB93
+:10AF000085DFE0DCDD8CCA6F1C63E721BB8B55F26B
+:10AF1000FB554789F2EFF17EDF18FBBB328C33AE75
+:10AF2000CE1E9883FCFD46D94B45983F227D36675F
+:10AF3000B873AFE24229340AF0521DC7EBD7963DF1
+:10AF400095827E98EA2A9E2FF654AECBC172C3F941
+:10AF500039C3DDFF8D12FB9EC1FB6C625D3FEFFDCF
+:10AF600090EEAFF92C9207A7E89BF021F91D984DC0
+:10AF700072A0EBCCE7CD52D0CF3DC9CBE350AB2C88
+:10AF8000AB92517E4DF79BCA319ED861197B04E389
+:10AF90000C6227548E47BA4EB230A22BF0794C2166
+:10AFA000FAB5AFFA2C230699CBA6E7738D8FEA3456
+:10AFB000FEAED6F331AC4F57E1F8CBCBDB91F818AE
+:10AFC000C6CFC0F6B3BFA5D73783FD45ACB7C8FE23
+:10AFD000479203F8132E1787E0E8A6759586D17D72
+:10AFE00039B8EE3AB4753706E13019FAE81E4FA6C3
+:10AFF000E429A20BAD133C16D24711706BF0A58368
+:10B000006C636597C2853F8A662F72081C8E441C4C
+:10B010009797433B2F8B1B820BC6BF1EE9C0D67090
+:10B0200078B64B4D5C6E88FD81E6CF68D0E6DBA339
+:10B030009F6F4514BFD7EE46BF13B6738D2DFA3AF6
+:10B04000B81B853E9D65F13D688639DCE49C4FFC6C
+:10B05000700B683427CCFF6FA9FE3AC447AB147855
+:10B06000B93F8BFCF114FF01F49E5118660768701C
+:10B0700045E2A3610479180977241E86E8D3978CEA
+:10B08000A9761F6E705E11F369B5F3F53A30DECC28
+:10B09000DFB550C01485FC9B5211C5A16870BD2955
+:10B0A00071BF6440E2F78F347B2212BEC87B7A1AEC
+:10B0B0005CE8EFE3700CACC23B820F166A7E3E4E3A
+:10B0C000AF24019FC9200D7B1EFE60A141F3B3EAAE
+:10B0D000E819797F4DC39B16E715892F2D4EEB920A
+:10B0E00073B78873E591EA4960A7A7C65D8A47ED03
+:10B0F000DC2E6ED04FC9FD4003F7DA490EC60DFABB
+:10B10000298F2968DF4FF21C52D02EAFAD81090084
+:10B110000DDE147E1F0DDF0F64F8B71492DEEE1FF4
+:10B120008FFE959F4C7D82CEAB3E30703F7D247E5E
+:10B13000F68C809F91F87D24F8A3D27C4FE2B8670B
+:10B14000A4BE0A2CECCC16E742CC9F85EBC1E9C823
+:10B15000AA44FF11C8D7AFBEC24D2B16015DCB3339
+:10B16000FDBFC076B730DF64A46F5C8DDFC8CF4908
+:10B1700018F9E1978BFDE364A177CF6FE3F11ED55A
+:10B18000DE518F4D44BBF198910569DD7B497FDE2F
+:10B1900025E03F0F2A3684F59FB193FE5DFCFA7CD3
+:10B1A0008AE328D86C187A4F03FE8E0A46E9DED36C
+:10B1B00028DE1BA7CB9776A7E8EA8FE9C9D6958F3B
+:10B1C0000D15E9CAC71D2BD3E5C7F75DA3AB7FD526
+:10B1D000F12A5DFEEAFE69BAFADF3A354397BF7697
+:10B1E000E0BBBAFA1F0FFA0F84DD10F0F615C2BCEF
+:10B1F0001788795F7F719EAEFD9F62A61C437E5CBF
+:10B20000B081C7A557028674EF8B7470FBA209FE4C
+:10B21000207D27B3018A076C084A9E10C3F836BD0B
+:10B22000FDB1B4A78BF078B9FBF805AEB90634B917
+:10B230004F170AFBE32A76158F67FD7ABAE6B3BC8F
+:10B24000BF8BAE66B79EAE56554FD7E8423D5DED1B
+:10B250001E3D5D6327E8E9EAF4EAE91A5FA3A76BFC
+:10B26000824F4FD7A4D97ABA26FBF5744D5DA2A7B9
+:10B270006B7A939EAE99CD7ABA6505EED4958F44DC
+:10B280006F4D9EE6B42FD7D51FA4BB6F09C537E518
+:10B2900075FC50D7BF46F700FC41BA17301187F94B
+:10B2A0003FA47BE1283DBD416F8D1A359EEC8D1288
+:10B2B0004C671708BBDE37BCBDA1C99F70FD1EBE21
+:10B2C000AF1D492E5DA2CFC43E77447D16B1CF7D20
+:10B2D0008F81BEA5413690DFEA56C19F87A338DE35
+:10B2E0003FC7A2ABA11ED4990070BD8770C338EFD1
+:10B2F0004515933FE2BBACDB88FDDFCEFA289DC34A
+:10B300000628F53307E9EF79CC43E902E63309FF74
+:10B31000C4F45109E8B7E8AF40FD7F61EE5B1FD090
+:10B32000B9D61BF157F40EC547787E92C7D849218C
+:10B330000F4EE0390AE4CF5A07F5ABEA0AC3DB49FE
+:10B34000E16F9C3749223DCDE4288AEF9A778B4400
+:10B35000E744F3FE93A78B46493C1E24226D6DD62D
+:10B36000F0C7F7473B47A904471AEB16F61CF3DB77
+:10B3700072A81F7EEEB1CB44FB58B785C3F7ACC4AF
+:10B38000940971741D8EE8EAB670789E35320BE22E
+:10B39000F369E65791180F2820A2F83D8C22E48F1C
+:10B3A00079FFF95636FAE9A2A25E98557D359ECB13
+:10B3B0000456919FFC7B4CEF27BFBD49223FF9F714
+:10B3C000004E48DD0E8F1BED7C2DFFB080B71AEBD1
+:10B3D000C1F7247793847EA97F587FFB7FC8EBFD5C
+:10B3E0009DFD0DF6C3385CF883F4D3FC9E85061EE4
+:10B3F00027317037DF1FEDFE1EE3FEBBE640650020
+:10B40000CF45653094308ECAC8EFC7EF1CC5FD9E8E
+:10B41000C9AC8FFC0BECA866D7FA49FE9688FB17DF
+:10B4200067C5B9E2A22E0BC3389D927D87E2F01C5E
+:10B430007111F0601FEA61C54FEFBF946C792D8EDA
+:10B44000FBFD8C4EBC57A9E9FF91F9546127C3EE6F
+:10B450003100DF350D677FBC5AC4E3035A5BFA46FF
+:10B46000E139A006CFFD2DC7282F2B1E86E797F8C0
+:10B470003E5478FCA3C905E561F24EB141FB303979
+:10B4800064B4F9E89195352D7D74BE6814EF58AD1C
+:10B490004D5BEEF087D989874609FBC71260B84F2C
+:10B4A000E02A0A53E524CAB5FF627C1F6D76433F4C
+:10B4B000E1F2F362020B3F1F686F394EF0AE91FC70
+:10B4C0007EECC49CCB4256A08F59C1BBC0F07DCB53
+:10B4D0000DC7308ECB645FEE09A923E3CDEC562E69
+:10B4E00084CBD3B723E4E94F5A068A719CD6967E63
+:10B4F0000D5F0CCF6B03C9DCBE6E6DF984BE1BC043
+:10B500003E447E7B754BC12115CA3F80BFF8DE8E5D
+:10B51000D9C5E162175DA457E7083E405F5C3AF089
+:10B52000CF07CD46E2B315E9363A2758F166DE215A
+:10B530002FAC67134C57FE06700F8DC3F16412F2E7
+:10B5400014F8C987F2C194A2D079419C6306D1E96D
+:10B55000EFED4FC3AFC9CAE89D2453BA8DEC822BDF
+:10B5600085F36FA3F83B4083F6C94517C9FF150261
+:10B570002FDABB4F1FDCC3C8DFB3E25EEE375C518E
+:10B58000CFE81E026B869F8A21BED1F44C02BE50CA
+:10B59000031F3B5A60C541170FB55898BF00EC1008
+:10B5A0008CDBCF19A2638757716288C1C66A571DA9
+:10B5B000A60F4D38D181E2EFE1895FF4618A67041B
+:10B5C00038BEA38905D13EA6B37F18DFB904F23097
+:10B5D0007E8C288FF1F37CAC288F9DCDF3E9DEE7DC
+:10B5E000A46A042CE23C2BDD16373517E5F402C6BD
+:10B5F000EF818B7720B60B7D916A8BABABC6F2DB0C
+:10B6000019DD0BD1CA7F2ACA936D1FB5E7A01E9919
+:10B61000A56FBF45E021C9F651C7243AF7D2976B11
+:10B62000E74A09B6F3C7A87D89BEFC51D1DE6E3B5F
+:10B63000DF3709CB73F5E33F28CAA36D5C1E321FC9
+:10B64000E3EF1588F20744B915CB717C0F2F97B53E
+:10B65000773944BD75020E8CA923BFEB28EE77DD48
+:10B66000D1622921BAB45C24FA3CD4C2287F6B5140
+:10B670001CC909430DC7779C8BF383A3990DFB4E1F
+:10B68000C1AD42AEC5A8FD5EEF30724F2B8F73F097
+:10B69000771864B789F8C96C137243ACC741B921F4
+:10B6A00035793893713FFDE5F81A16DA05B48F3213
+:10B6B000E007F93AED1E03F387C9CB946551CC1F1F
+:10B6C00056DFBD204E974FBC3D4557DF352B5B57AE
+:10B6D0006E2B2FD295B35971B46E960BFE8A2A2920
+:10B6E000D3956BEF43B0DDA29E58BFC6DC6B74F5FB
+:10B6F000CE17AAB1C8E327A782FEA178068F05E579
+:10B70000C3727B7612EA9FA75B2610729E85750531
+:10B71000462B7BC6C9E3DC9FC1F34328FF598B97B7
+:10B72000BEEF817215D25DB0EE54A8DFD5E2A0FC69
+:10B73000E32D6E4AB7B7A894FEB4A590CAB7B47803
+:10B7400028FF18F48FE9A3D00F7E7FA4A586F21BF3
+:10B750005B7C947FB86536E51F6CF153FA40CB12E1
+:10B76000FABEAEA589F26B5B9A29BDBF2540696B15
+:10B770004B3B6F57C4F5CC33E25EED3395FCBE7C9A
+:10B78000241D3B8B841F52C4ADD887E2563A8B30C0
+:10B790006EA5BB9FEC702D6E05E74DFD59F9FC239E
+:10B7A000FB7BAA88DB6F45AC6F55345FCF743E9C42
+:10B7B000D7E3591D0D7C9FDAC4E990D53340E5C924
+:10B7C0004B382D9E12FCC95C01965641510254EF34
+:10B7D000ACD45715CDCFD529CE91B9619E15E2FDD8
+:10B7E0002662BBA001E1522670FDA9D17570DE4E24
+:10B7F0000E27CE7F3878F70B78E5F26EFE2E4B4D94
+:10B800004708D93ECADB44EFB25866FB420AA42E71
+:10B810009F9FDE8928BA38053667206F2E5EC75491
+:10B8200048D396E9F76D290BCA74FB22F9E2434C21
+:10B830000539602BD1EFAFA27297EBDA59D27EA80F
+:10B840002B37B956EBCAE7DD95B5C68DF84CE5E761
+:10B850004BE60DAB5832C0B5B07323C1F59198C714
+:10B860005949A5FBE5817D5ABC05DF5F3C29F40BF6
+:10B87000B36C207BACC0C9B3F9B10103EA874FFFB9
+:10B880003596E4D2138F1B82E84706F164C0F55F5A
+:10B890000C661F9697B27ECA63A80CE6C73255C6DF
+:10B8A000FC383640FB2BD85FBC5F8471ABB2FF71B4
+:10B8B0002BE4CFA4FB9FE4717321D29FF9829EF900
+:10B8C000DA7E6AB312E95FEE2F22FF8DFE7E5D9B6A
+:10B8D000D85FB459B99F6E95B32209EDD6B323C48E
+:10B8E00039DADDAF1E5D00F8B6271FA274D02FA78E
+:10B8F0001A86BD3FFE4504FF8F026617FCFF05F266
+:10B90000FF99F2B713D10DD5903B40EBE0ACE47555
+:10B91000CF45FCBE2E737E841D17CE4F11F855F611
+:10B9200055BAE7021E9537733C013634CE132DC746
+:10B9300073300E41CBE78B38DDBD2DC9B9D561DF42
+:10B94000D5624EC742D65783FAAAB0C4E00962C78F
+:10B950005E87CE8F61CDEDF0E27B084A19F3A098A7
+:10B960001BC53A56A3EE56FE26539C9572F86AA65E
+:10B97000C27EC6660B318C4BD3FA65C21F728F90A4
+:10B980009B5F38AA63E99DCB9441F9873A927D6128
+:10B99000F3F6211F7DD169E4F33AAC2F2FB471BFC8
+:10B9A000E1A242535095F05DB50E7AC751D921B14D
+:10B9B000B42C846312E1811D8C263E8CDE3C9A05FA
+:10B9C00060BD943BFD9662F4DB85D483861CC193F5
+:10B9D00050AFBED8B413EDB302C48B0DF1726B6ED1
+:10B9E000350E9D5B48F85D28E63DBE98D3AB2D3DF6
+:10B9F000021EE6F1E27BA78B3A353F8E7E9E0F96C4
+:10BA0000577D07DF856CED93B95A8BC0E77A63DF0A
+:10BA1000E8B9D0F5997E804B2638C717A30DBAB97F
+:10BA20008205488FF3F9D53F2EB1AD5924976A4866
+:10BA30008F8F37B0F0F3532D9D58CCE5EFB1221E18
+:10BA4000876A771F257E1CCA1F39BA00F0F1B481BE
+:10BA500015D2B9B181EF8FB5781D19FD0078AFA16E
+:10BA600058C845D6C6A6A1DE761A28FE54EE8AA28C
+:10BA70007BB3B253A1B8F7365BB5E34EECC7A1D0A8
+:10BA800039D11479621FDAD166A7611CDAE14776F1
+:10BA9000FEB00FE386E47485A1DFABCDA1703B243B
+:10BAA000CD40F1808AB3DA82E74AF9B6139588CFA0
+:10BAB000435D3FA07722E4EF8B981DE117330A9294
+:10BAC000B5B126EA3F90A688F766BCB56313C59169
+:10BAD000888AFBA19A4F70BF7DC471DE8AFB02D5B4
+:10BAE000B688FC81F715F37DA211CF0F21FFF8CAAC
+:10BAF000F34E945FAF77AD89CB427B3AA8902D523D
+:10BB0000F8D7D6147A0FA1CB44EF356878CD0C283E
+:10BB1000BA73C8F4667DDE1C711E698CB827B75CE9
+:10BB20008C8F2797A1B0F918DD7CFFC65C36DAFF51
+:10BB3000DC572CDEE914F97B447EAF3190E201FC46
+:10BB40001CEE5A9489F3BAF0829FE2CE47B2FF27E7
+:10BB500015AB62BC80D540EF0287AC1887BEBB85B1
+:10BB600079D0CEB30415BA07B047C8B35C1BE7FF62
+:10BB70003B4AF87A8D4C733BF8BA539E890A4623A8
+:10BB8000DD1CDD650158E7C5AF4E652AE8C15C875D
+:10BB9000D780FEF7DC669307EDCF29BFB0119F9CDD
+:10BBA000B7F1382EA5F90115BFB7EEAC2854C3E0A4
+:10BBB0000EB6383C289F76B6583C181B1F1C41BE59
+:10BBC000E6380D143FAF1A783CE72EB11E7715F317
+:10BBD000F788760A39B34B09CC403877013D316E8E
+:10BBE000FFD0066E1F2F5F65213896BF9E43F6D5A6
+:10BBF00048787BA2C5EDC94578361852D05F55B953
+:10BC00002E773DBEDFB1DCCEDF3796638B1EC3AB34
+:10BC100011ECD74686F67C6BCC359EF961F25D8ED1
+:10BC20009D58887C25CB8114F4E7F43C7DE1268C7B
+:10BC3000E705FA6DC57CA8F8839B307E77AF3D9011
+:10BC400082F1BDC78A3FE2E50981AD18DFDB577C91
+:10BC50009297A707520C903F5E7C9A97E705B662D1
+:10BC6000BEBFF82CCFE3D91BC8CE53C5E76F0AA0DF
+:10BC7000BFC5E4598202F9E7007F092CB16E919E9D
+:10BC80001678D1CA9FC3EFB001DB2FD2C8F283A2CE
+:10BC90005DCF08E52F8AF2DE11FA7F45B40B8DD017
+:10BCA000FEB068776484F64745BB632394FF4A94EB
+:10BCB000BF3142FFFF2EDAF58DD0FE6DD1EEDD11E2
+:10BCC000DAFF56B43B3E42F9FBA2FC3F22FAFF40AA
+:10BCD000D4EF17DFB3ED1BDE47FF7D36C811944B61
+:10BCE00085F60D71B8CE77B69713FFB756F0732A65
+:10BCF0008DDFB32546EF0EDF56C2DF3BBBAD84CBF5
+:10BD000071A584F339F0E1C3C877CBDF94299EA8ED
+:10BD1000D5E039154439BADE40F6C0F2D7F97E7D58
+:10BD2000F93A25187E1F486BAFC1BF06E103C66D07
+:10BD3000C314D6DB97C5FC9CD1EC767B6AC3E4992F
+:10BD4000D1A1CF83BC602877417E53DC78E1BAAAC9
+:10BD5000F6C2723CEB339005A2D45B42F88E886247
+:10BD6000177AC151DE5188F0D9147A3F4193F3CC50
+:10BD7000E6D6F935DA6C0ABD2727DB79F9945F4CF2
+:10BD800074A09DD5C6FC7D5E6CEF56C88E3FD45E18
+:10BD9000E640B967B22F70E0FAFDB894E3BDBAA1EE
+:10BDA000300AE5B5FCA081E4F711075FEF3BDC3C0E
+:10BDB000CE0AF40ADDAF0279ED411D51C042AB500D
+:10BDC0006EEE7DE8E05CEEE763F6B115747F493B0B
+:10BDD000579794B07D406D09C74FA6D0230AEA1744
+:10BDE0004877958B7B3701EE8FCA54983B35ECFE34
+:10BDF000706D89CCEF3D69E7A1722DBDAB95B15255
+:10BE0000D19D23A4DDA3CF9B22F48612A15772DA21
+:10BE1000414EEACE4F1CBAFCB74A849FC7C33C6868
+:10BE2000C74EF9C5069287E751BF4923CBBD41F9FB
+:10BE30002BE4F12E4400CAD100BFDF7E6843D9AFA6
+:10BE400090DECBD719E83DEB2B95A30AE218F090D2
+:10BE5000E797482FC0845270DF74393CE4197D7134
+:10BE6000F4DEC765F091F768791CCADB3CBF42FD80
+:10BE70005FA2372E83AF6725CF713FD2D11925EC52
+:10BE80006A6000F4DBC54575E1F9BE49F853B43882
+:10BE9000652549E1EFF58B7BB2B2E0E3FB99578D65
+:10BEA000CBC1F78A9AC8BFBF62DF3D6EB4DBD71A39
+:10BEB000FC0ECC1F8B9B3680E32C874D3FE26F2F0F
+:10BEC000F641EF72BE7D33FA4DBA8326ED5DCD109B
+:10BED000FEB30FE38FB4773BDD64AF897CD5CDD55E
+:10BEE00030DF6EC5518C266847C9E44D46B049F72E
+:10BEF00099D8607DBCEFF7F41183E8EFC64DD520EB
+:10BF000097F64531DDBBA5FBD0CF4EF9E99BF09DFF
+:10BF10005218EF4619F6663B9F99B5C976F5103C65
+:10BF2000BB9FFDEEA655E8B013FB1427E3EFCD9FB2
+:10BF300051FB6390B4B05F595F82FBF5AE1389E1AA
+:10BF4000FB75AD7EACA8DFD03BD0F08C4AF53B4A08
+:10BF5000801FEA7B06624A08DF0315E1F563841F50
+:10BF600020ACFEA6AFAB5FA8C1F3CCDB3797F0FAED
+:10BF7000DBB0FE59B53F91627A22E089BFB4FF9DE4
+:10BF800004FF08FD1789FA67426F53FDB3AC3FB158
+:10BF9000348BDA3D85E39C7BE3ED0A31EF443CC70B
+:10BFA00079D7E6FD197E6FC13E707FA734A9F8BD31
+:10BFB000DBD2E140FBCD6AECF0A11CCEC5F7C72671
+:10BFC0000CA5CFA2F2187FE9F7487EEEB6B0F85A7A
+:10BFD000E4D76603ED6F7AFA0D0F205FEE489BE819
+:10BFE000C0FDF33E535F5909DAAF076C64BF1A32E4
+:10BFF0003FB5A2DFDC5CC0D7BFD5D9E42981BC3511
+:10C00000BD84DE0F95EF5DDE4DEF98DFC7DFF752A1
+:10C010007E6CF2EF46FE0A2D2F5C18B6BE7797F2C3
+:10C020007B96EB5EB36DC0FDC13AA3A7A300ED7094
+:10C03000BB42719FCA8F0F4E23FBF0E70646F21FEB
+:10C04000E65905FDB6CD55E8F7300C94CEEB2B2123
+:10C050007CF87C55502F234191F07ED0FD8ACF8211
+:10C06000E71D6661D7EDF0F0FB61DAB81784FD7962
+:10C07000A184BFB7B623EDC27B8B5DF8FE8389EE4A
+:10C0800075DA961942A618BCE7B6F3D462A46774B1
+:10C09000FF3ABCE71C95A238707E3FAD85323A97D7
+:10C0A000EBA6EF817A03ED1BE29719BCE87F8CCAFF
+:10C0B00035E9FC1D361827DC1F1233DAFF47A4E7E9
+:10C0C000B837951B11CFEEBB0DF43EEA83EE772D0A
+:10C0D000068033A65CDFDE3151DF3EAE5A5FEEAA4A
+:10C0E000D59727CED297BB6F3745F875F4F9268DD3
+:10C0F000AF4026D8404F45F1221665BBD082FB9E4B
+:10C10000B5AF4531A2CFCA4D1D05B83EA307085FA4
+:10C11000514551E417589B6C22B9BEB694FBF50FFC
+:10C12000A79B6EA43CCC0BF96347DA51DA8F5C8293
+:10C1300017DBA9BF62FF3616F61DFDF2A3BD9652AE
+:10C140001E57C3DC15E8C763240F9F95BC9E438828
+:10C15000EFB7B8BF624733F7633F388BC741D20CA4
+:10C160002A70BDF3FA31960D7DB82F8BB1B5DF8DF6
+:10C17000F19D91784D14E70D3BF0762FF29D9FBF16
+:10C180001BBD46BB6785DF2BE8D604BD8B366BB481
+:10C1900078EF4FD809B1EEF892B6B0FB1A89C26FAA
+:10C1A000F2F0C47956D41FFBC43B2283FDA9342886
+:10C1B0000F79457F54A9E6AFE1ED3769E73C229F4F
+:10C1C000E0E4F97D47E26EC4F5B569565C19EEF717
+:10C1D000D70AFB2E36CDE41D05F37AE49829208D8D
+:10C1E00081BCC28E18C12ED817C7C735BD1E15C059
+:10C1F0007B818FB8CBE99E61AD80FBB94ACF3BB85C
+:10C20000DE07601DED84FE1F7179AC65E2DC340051
+:10C21000F051A8159828876ACB68BFFB88D763457B
+:10C22000BDF9489AC78A71DAD664C581716B716E9F
+:10C2300085DE897BC4E277A0FD13078AD484E749B1
+:10C24000E91D53E97E1DE0DA50C18F1A98886FC44A
+:10C25000F8C27881CF1DEE050E7C97C195BBFF5FBC
+:10C26000D04F1F8FFDC5F0768827A7C0D3AC52955D
+:10C27000E07689FEE3173C47F5F1A7AD22AC3F41DC
+:10C2800047D35416C47D9A36BED6CF60FFCC4BE759
+:10C29000006B7EC5F1B62A9DBF8F65BA8BD17EEE4D
+:10C2A000B94AFF5EE4B381E428927729EE942AE448
+:10C2B000A394635B67E0BD8B35BF8AE2E32CE4FCAB
+:10C2C0009EA230CB7538EF04BF03F118B95E938F8F
+:10C2D00074D421536A74895CBFC90A6B97E32E5DDD
+:10C2E000C7C96E5755FEE861D673C47A493E36F029
+:10C2F0007DEC3F725D6F8FFE602CD72361DFE5CB55
+:10C30000E7DBA4FE75248793155A67E911E3E13B47
+:10C310007B98979841C5B8E8DDA54EC1C7A0974A5C
+:10C3200091EF1D936CFCBC9DF8ABEAF90DDFFD3578
+:10C33000E42FE0EFF3815AA9C73AFA482FF6F80B39
+:10C34000B0FE36C5FF38FAD3B71D4FA2F72BCDD1BB
+:10C35000FCFD5153C47B299ABED85DCAFD486AC40E
+:10C36000BB9BDF34ED4E4B2B7678B0BFB77F6B496C
+:10C37000F8C7DB3F6947BA57D9604D3F5372F32680
+:10C38000BCFF6C7D93973F0DF980827859467E976C
+:10C39000C31977D2FC5BDF33933FAB54F66CC63CDA
+:10C3A000FBBD95FC717B0F4C9C8DEBA4D55EA1A2CF
+:10C3B000BD7F40ACE37F1569E4BC6493C78FF64052
+:10C3C000E4F7674B35FF9BE77817D0B7749789DEA2
+:10C3D000711A8C8FE8B2F2785461872E10F26CC11A
+:10C3E000C1F5198718BEC351F75A29B45F60AF4E23
+:10C3F0004478522F4ACC0FF26F9B389F4D753D27E2
+:10C40000A19C49731DA944799FCEFA56A1DC486FBF
+:10C41000D29F97A55E54A8DDBE142FF5873F18075D
+:10C420006A62624DC7F9D92A94F329FCBCC5E48835
+:10C43000E271A1EE6ADD3D6AED7DDBB7851C350159
+:10C440004E8D6590DA147E6F3FA2FEEF443D19FDDC
+:10C45000F6E8FC771C3D4EFDDA944FC3E34D715F67
+:10C460004A426B193FFF043C05701FCA62E3F8792A
+:10C47000A9D7AB86C7DFA682DC359761FC4980E28D
+:10C480004492C5BD082DAE0730E044BF9B16F7B1FE
+:10C4900093E9ED112DD5F6E7B9CD32ED3B8A5FB5C5
+:10C4A000F2FD413B0B5A25F48731923BB91BF8F959
+:10C4B000B4E617BB0D1713EA257C0F97C6EBA63819
+:10C4C0006ACDAE02FA92DC5917F1CE94F68EB661BF
+:10C4D00034E78B6D2D0EA2A3569EE68FA4A3FE9C7F
+:10C4E00053AB977A3195F9E3C3FB0D527FA9CDFB8E
+:10C4F000891F522F6650F9B616F532FD678FD07F2F
+:10C5000032F1CBC8FDA751F9F6D0BBCEE9808A9FA6
+:10C510000EEC77FA54942BA1A99E61F09C7A8F5E61
+:10C520004E8EE9D1CB5D0D2FDB14AFAB0EF0BDED20
+:10C530001E83A78B61FCA9BE5E4DD66F9CFC5D6B14
+:10C54000AD7EC83513EB2FE3F5BF754A5FDF577932
+:10C5500020B23EC177FD457DBD48FA44C20B70252F
+:10C56000DC1406D7248BFEF7DACD9E7B095C09B775
+:10C5700084C175835B5FDFBF6A78B86E2C347F2D12
+:10C580005C5ABDEF4CB8B27A91F39859631E01EF33
+:10C59000BCFE2DB3AFACDFDB967C7DBD3B9A23C7E1
+:10C5A000096871DB3A7B24BE99DBEF0E36407126B9
+:10C5B0009ADD11C71C22FE8BDB0DEFE07F93197B08
+:10C5C00060B46FCEE804C4BFF7F64755BC1FC3F58F
+:10C5D00015ABE5EF56C2BEA434FC5DEE21B8565350
+:10C5E000BF2F61BC13E9598B07EDCEE25466494673
+:10C5F000E3CB1DCCC6F7C7EA476BF29AC79717097A
+:10C60000DC3D9BD2BDDC49EB3C1887F07CD371EF5D
+:10C610001DEDBD67F4F8A1FA23F95B343C994CDDBC
+:10C62000F47B1D06EA6D1ED40FEF6211B4DB75B307
+:10C63000398476B516877A3C7ACED10495DE3D589A
+:10C640008DFDCFBE65EA1ACC4B87E3D5E536BC3706
+:10C65000D5AFDD2F5D83785B66F167261AE87CB580
+:10C6600000F7C3CC172F2E23FB4A878BD3D0E0A92A
+:10C670009638FEA3D2FC0FE338D586BE1D3EFCA63D
+:10C68000F4F17DB62381BFBB84EFEB0CB3FE353CE8
+:10C6900054897E0E193D5F0EC0FC0E6D8CA57BF893
+:10C6A0000BE26F99836FB22C34F812F1003D0CEE5F
+:10C6B000ED04B76D6E6632C26D14705B1204DEBDA0
+:10C6C000B95F07F760BCCC7D92F67E3AE59F0F38E4
+:10C6D000E9BEBBD9F0F9BB33510F971A3C68776EAE
+:10C6E00003FB02DF77FB3F02DFDBF18C258EBED33D
+:10C6F000BB6F6E71EFCBBDC940EFBCF8AA5E203AAC
+:10C70000ED6AB07970DF3E97A9F4EEEA7C710FE62E
+:10C710000F95FFFD723FCCEFA5D1FE83388F3BE232
+:10C720000D19EF121CFE627A476BE295C5CF6AE7DE
+:10C73000F033847DB050E07126F352DCEE4DCC6FC7
+:10C74000C471DF3E6BF2A25DFAB68847BE8505E88C
+:10C75000FBAD2C48E96D2C44F5BF872FCA42FEADD6
+:10C76000E8D1E9CD005FDD630579B81EC3F0FE06B0
+:10C77000D219F8E50E17E7973F2621DE3B13AE8866
+:10C780007FEB248EBF0746FB7FC3D7ABEAF2204C7A
+:10C790008E4969E847195C3FD5099CFF1447DED7ED
+:10C7A000AD9FBEF3DA7D7FAF2DB902DFFBE23F37ED
+:10C7B00078EFA278718CCB77011DFA547ECF11C42B
+:10C7C000863D0074AAA994296E6FED67E27E363A21
+:10C7D00031A0DE2FC7CAF43E99762E395DF4373D7D
+:10C7E0008DDF57ACAD9CD9160B7899F2657F79082F
+:10C7F000D29A34FDFDC5A9AE2E7AD27C5AAEFEFB8C
+:10C800008DAC830E886B4BF471E6D323FC9F87704D
+:10C810006CE0AB8BA345BC64112B0ABF6FF01DD13C
+:10C82000F67CEDE7A673307EC918FF57488FE5DF29
+:10C83000FEC31CDAD729ECCD7130BF867F97C99E25
+:10C84000FCA80566528071D516E60583FF24D8152D
+:10C85000983FD5E2A6F434D801987EDA5248E567CD
+:10C860005B3C949F35C6671903FDCE6BFF4C417D41
+:10C87000B4568BC716706871856B45FCC40AFBF211
+:10C88000E318BFB08202DE192CF68E2908FE9D3D0A
+:10C89000DD473185EF32EE43566C94C8AFB3F08874
+:10C8A0007F0D9279F11BFDD3514C8CFFCD8944DC77
+:10C8B000A7D7A31D0BACBF22CE9B340658C0DBFB11
+:10C8C000E1D178A8FFC7960904DF272D5E82EF4FDC
+:10C8D0002D3594D68FF1A5533DF619BDF3F4ED67D0
+:10C8E0003E54F0F7B34DF64AE4BFBFCECB8241C011
+:10C8F000EB662397EF9B41BEE3FAAC2C9DB1FD1E86
+:10C9000086F2D75F80F3BC296EFEE478F83E7DC2E4
+:10C910005C05EBDDF225E8A0AC213EBC1C5F9F79F5
+:10C920004522FC9C79C549F8D0F0542FE875E660A3
+:10C93000F177F0DDB3578EC9147F7AFEA281E03B18
+:10C940007F3C8AE25323DB2F3F909384F6D89F806D
+:10C950007E78F0B1FC4031F9E3FFF4ECBFA8E1715F
+:10C96000BF7F8AEBBEF03ECAA9FFCBE514D89B2758
+:10C97000B7A21C4B4BA1F77B06E3D5585334EAB161
+:10C980000693585F206730FFA728BE0FAEF8796A7C
+:10C9900015AE171C0FE3BDCCE2F760407F1FFC1003
+:10C9A000FA3BB8D54DEFFD7CBAEFB16C1C7F6FF749
+:10C9B000C2F7B742FF6782FCF7609C61DD675F44A6
+:10C9C00079BADB467ECBB512C085FA744F0AE50B07
+:10C9D0002525AA999C19411E8722A90ABE7FB6EC7B
+:10C9E000B92D29C85F784F1DE3EA5FDA184D72EA66
+:10C9F00025A3E78366EC6F3BEFEFC987EEFDA80741
+:10CA0000D307EBCBEE45393786C7312EF8C9D22292
+:10CA10006C0FFA9A7EDFF3D3CF4B21F48394761E0A
+:10CA20005A8D714C63B67D68488174EC6EA915D33C
+:10CA3000E2F469C7D07F70D71895DA8F7B264BC692
+:10CA4000D8F4A294E0FBD7F3B8119D7E2FE9FCAC9B
+:10CA50000AB7999A9E2F92BA4F77E1BE38E37819B8
+:10CA6000BFDFC5DFAF3ED03BF39DDB18CE032C0804
+:10CA7000847BAE89E22E5830D085743EE32FF4D00B
+:10CA8000BB2ABEC016E4AF33FE44BA5F78D010882C
+:10CA9000C1DFE314F880FFBEA1E777BF1583F1146F
+:10CAA000B1FB8D0C7F2F76FDD88129141F92AED259
+:10CAB0007E3C7DC70D35889F86FD07BAA89F651609
+:10CAC0000FFA63971CF89CEEBDB0A93C0EF5CC7E26
+:10CAD0009E7FA0DA4BEF9D2FE9FA33CFF7F928EFCD
+:10CAE000930359747F623EB7771E13FA8CF58F66F5
+:10CAF000E1EF2169F47A008AB17C73562019DFBD19
+:10CB0000D2F420E8AF8770FDA1DB91DA3B66F27BBF
+:10CB1000F257A8BF4C421F69FD3D66E2EFF4A21830
+:10CB2000C1DF8BB3CDC4F5EE1E9037C82F9ADE85DA
+:10CB30007177E0BA3589FB32A9A064C7C27C521F65
+:10CB40003373F97D85E347DE67D5EC90D9F1AD7499
+:10CB50006FF5D354FFCF701CEDFE2A533CF4AEE0CA
+:10CB6000EF53BD4F8F49E0EF75E01C402FFE02F3FD
+:10CB70000D32D85139617694E5CAF4E2DF52BD072F
+:10CB8000709C2BAD1F2987270AF857D80D8487156D
+:10CB90008F9AC91F3651DC439D78FE7834CA9315AD
+:10CBA0007F2E23B9D2CAD8B0F879B985C779FF1BCF
+:10CBB000FA1120BDF68B7E99F623470CCB8E827E30
+:10CBC0002510C87F38D01A5B4E792F92FBBA2F0CF4
+:10CBD000C3EE17B514E8F52EC9E92FF5FE87EBBFB4
+:10CBE00074D0EFCD64B6B82B9AF7D0FB3EFAF96B50
+:10CBF000EF6CC1FCFA51BFAFF8CC40FCBBE2B332E2
+:10CC0000929BBD57385FABCB7B12E18C9C0FC0FF72
+:10CC100029D22712FE417E1FB832F8BF2F31FA7D8C
+:10CC200043A0AEC8BFDD2BDE31E85D5A42EF691C80
+:10CC3000C4F748506ECEE0F78E7AC5FDE4DE0407F7
+:10CC4000BDF7F19291E703B78AF6E27DC8DE5B5348
+:10CC5000F87B1DE6A65F9762FFAD3C3EAED718A4F9
+:10CC6000DF53FBFF00D94A3097008000000000002E
+:10CC70001F8B080000000000000BE57D7B7CD4C505
+:10CC8000D5F7FCF696DD64936C42C88590B0B91078
+:10CC90008206DCDCB806582041B468038802C6B8B6
+:10CCA0002101426E844BFBC4969AC500A2C51A1E90
+:10CCB00011D1A22E14282ADA50115183CF0A4269C9
+:10CCC000BDA5D5FAD86A692278E59210B40FF6E1CD
+:10CCD0006DDFF99E99C9EE6F49D4F67DFAC7F379F5
+:10CCE000E347C7F9CDFD9C33E79C3967CE6CFB8FDA
+:10CCF00006B9BC4EC68CD6B939A7F3197BCF67F0FD
+:10CD00009AA3196BD1FCB71A0B18F35EB0B0DD69AA
+:10CD10008C6D89F1272FE7F92DCBAEA2FAEF3136D2
+:10CD2000B32D07DFDD49B13C3DF837E3EDA5769E35
+:10CD3000CFE5799EBEA4B1F9543EDB9D14C3F30B3D
+:10CD4000C3A346B36B787E876FF7D6387CCFA67EB9
+:10CD500086185923D54B13FDFCD12CDAFD81F1BF88
+:10CD600024C61E3533AF2D96B1F1AE45C35D858C1B
+:10CD7000796E8C30B16814BA93343E9F47AA86B35B
+:10CD80007B359E6D7D88B178C6E65B19FDA9F150B3
+:10CD9000D13A86B179E2335BB078B7CDC3E733AF30
+:10CDA000DAD6A58DE6EBA8BE2BD2C9C79BE731FA30
+:10CDB000C3A278859B4ADC9DD9A2EEDFD331AE9B1E
+:10CDC000C66555837886A7267F25E3E3BEDC6365C9
+:10CDD000F772B8FC1D7F5302298718638319FBD4AF
+:10CDE00026C6AF6F9BFAC069D51FFFB7DA62DFA80E
+:10CDF00045A33CD5C7F8F8FB87780AD0FFF243D7A4
+:10CE00003D70DA1AA857B5B8248B1902E3868E1341
+:10CE10003A5E0BF0C6C71B063CF2262DBCC000FCD8
+:10CE2000B5D97CC01F33F5FC6129CFB7CCBFCA751B
+:10CE30002FCFCE9C63756B1C0FBD07C27C611ABEE1
+:10CE400087BBB1AE96C3913E03CFDFAE09F8B7689A
+:10CE50008CBE7BF79B7DBBF9B73A8BEF893DBC5D00
+:10CE6000DDCB235D7C6476D0C2FF83F21723447947
+:10CE7000943B6D7D01CA1308BF2F999DD154FE6B61
+:10CE800023A3F2707F560C877753A2678E8BCF7BDC
+:10CE90004818C7BF1DFD8AEF2725FD9DE4DD02BFB1
+:10CEA000DEC648EA97C9BCE787837CF7D27ADC49BB
+:10CEB0008B915F7535ADC78379F079B1068DD67BDF
+:10CEC000D2E1BB278B979F6C1F4CF38893F470B211
+:10CED000F42F6F8CE5F54E1E32BAD0E7074D46BFF2
+:10CEE000250AE5021FDA1C6BD636DEEED48B91AE36
+:10CEF000305E5E767FEDEBF85E7657FD2C4A6BD6A2
+:10CF0000DCC878FDCEBBDE4FF5E45C898FB23ADE3B
+:10CF10002A088F77BADCF5C0EF232E4F23D6BB3C0F
+:10CF2000A77309E37475DED2F1183332F6EE50CFF1
+:10CF30002A7CEF7EE1933DF8CEF194553A8A2FC3D7
+:10CF4000C4E904F4DB399AE87AB9A4DFF45CCF1DB4
+:10CF5000E88FC3B19C65301691D361C13CD89AC1AA
+:10CF6000DF8A4E3E6FDF7D50E3E3D486B737506AE9
+:10CF7000F48D463F67347F94964170F460FF9D7551
+:10CF8000F8A3800F8F81E7397E6AF7EAD7853F13D0
+:10CF90009F572DFE87B7AB6D33BA6DD83FCC67C1B5
+:10CFA000FC6B9925503F4DEC43D001EF6727ED57BF
+:10CFB000FB07E53FE478A8796264DEBD1C3FB5312C
+:10CFC000877E3291EAF1766ABF18AFCCABF55C3957
+:10CFD0001FB1BEB3721F9CE55FCCA09F7D6182FE36
+:10CFE00099A08FF34F2449FA11747BFE89113ECC2E
+:10CFF000275EEE9BF39AD7108E763F62AEDD7C5EA5
+:10D00000CCD53666F628CCBE6DCC9C48C6B64ABE9A
+:10D01000563BA86D0CF895E25FCCDA367A362F676E
+:10D02000D96DA3E78C0AF03F56DA9645DF7D6D593E
+:10D03000687FD0C0AA014F359F9AA79277103CAC69
+:10D0400062BFD63C7535C1478DD3023E027E0C7E51
+:10D050001175E5BA5F766962FF478E49005F1B086C
+:10D06000FFD9898372C04ACE2FB0DCEEE6FD8ED8A0
+:10D0700066D1F5A3EA8DF4E9BFFF0AFD737A1B16AA
+:10D0800082CF21C69E57C2F87CD9CF389CD895E371
+:10D09000BD29DB3DF9641FFE8C029F8C3915DD38FC
+:10D0A000094E024F7FB0283CAD4EE6FCBA1630491F
+:10D0B0000FC0EB60AE271972E53CF29037313CCFE0
+:10D0C000D306097F9557700FA5BFBBFEB024B99357
+:10D0D000B7FF6F9781E6150AD7B51C7E286F31B36D
+:10D0E000DB4B79FBCF9B4F649C3607D6F371B3DBE8
+:10D0F000CD454D5F7EC9B65C2BF6DDD2EDB9D64588
+:10D1000041706FD99B7FC2C9F17A76AF0923B116FE
+:10D1100093EF2713E2F0DDD8E665546E75F3FA67F6
+:10D12000ED47DE44BD25DB63F28CCE40FBA5DB4A38
+:10D13000DC5541F0BF7AAF1E1FA3DAF4F96B0EE99C
+:10D14000F3E65C46F4F08FB6CBF5EBF3F927F4F990
+:10D150004FDE597D33B6C1F3E3C4BEF9D417E9B34A
+:10D1600072B856BF3FE304E4E8A7079F8F02BE6A88
+:10D17000FF54753C99611D7A3AE578D44C7CBDDE4C
+:10D180003D1AD1CB325FE8FE957CE38A7DBD96F0F7
+:10D19000859D154C37A1F83DC3DA6E7673FAAA6BFC
+:10D1A0007A3B037A4CF52C4EC890DF6D9B2DCC7EDC
+:10D1B000E57803F10F66773B19A7BF8A71A26C422D
+:10D1C000D374768AF7C736FD7606F66BC58F35D2EF
+:10D1D000372A9E1DF12AE8A66BFF82EB29BD79262E
+:10D1E000C1A192B92DE0874BDB357F24CF3BC639F7
+:10D1F0000F75F2768B7D9A0BF35EB42E2CC0CFF8B0
+:10D20000BF559B42E6B125A89CCF7FE9A157BED26E
+:10D2100078FFD5DBF5ED967178417ED4ECFA7B583A
+:10D22000F077AE0811BC26B4EF3062DD8BE5FC95DB
+:10D23000FC63DEC90CEB9B209AB0D3F80F971B96CA
+:10D24000619EE2DCC2801C9CB045B4E78CAF02EB6F
+:10D25000AEB75B9C5877BD95F923F87C4E445ADCF9
+:10D260000EFEFDE2B648D21F968431AF358F52666E
+:10D27000CB433B5734DA7DFC9691F4A47ACE7BA85D
+:10D280009FC7355F0BFA316A22FF33915FC6FCB44A
+:10D290001ED08D3B789D3E7D9EB50E22BDA4CEE472
+:10D2A0007F0570A9619D046FC6F1E95670E470AB0B
+:10D2B000E3EB7C2F16FA97BEFD72D646F5971FFA60
+:10D2C0007B58F077AE67322BAFBF3D9CA7347F1FF2
+:10D2D000C1D168616E039FA7F1CE709F97F490D281
+:10D2E00070D0A959EACB5BEE716761DEEB357796BA
+:10D2F000037C6CB3CD053EB6708790435B62B8FE8D
+:10D300001A477A33B55F087D0A7ACA02C1EFB6C4FC
+:10D31000B4F9C1F7B73C9826F4A9BF19092E3DF717
+:10D32000D97C3B35E8D342EFD9B27904B507BF24A5
+:10D330007DEABE48D17EB680EB96C10E9F97E7FF8F
+:10D3400088292641CF766759A91DD7D3D202724AC0
+:10D35000E9D33F1BE6B90BF856EB55FA37ABFE762F
+:10D36000FAE66E293F7B36F379F2FE4F6BA5C70DC7
+:10D3700041FAF003B982FF8F99E6DE23EBB950AF93
+:10D38000CA30FBDE297CBE555B0DCE96B400DC991D
+:10D39000DB9D05389FDE6CCB039D8D99C6E83C7103
+:10D3A0003257F0F38802E6F6F174BBEC777BAE41BE
+:10D3B00097268673FAE3FD9C2EF19B81DFC882528B
+:10D3C0000BE42197E1C4CF43D7B13757C8CD2A4BDF
+:10D3D000E96F26F5339F3E3A28167ACBE915DA4EE7
+:10D3E000312F81E731FF6E73B5D0BAC5FC14DC393B
+:10D3F000DD1492BC977C2BA68F4E7C4FD8386A37B1
+:10D400002B7D1AF8D7747442F0DC72DF28C2E34235
+:10D410008967769F4DD209637F45798993CABFE9B1
+:10D42000BCA5D6C9E980CA39BEFDC077E8794BE111
+:10D430009B997C85A59103E37BD1B898311A077538
+:10D44000B28979C3385C20F3082EF7987C77F1F91C
+:10D450000C3509F8A798047D71EEEC0DCFA3FA6E98
+:10D460000BCF573CB094B979FD8A64E6D2447D165F
+:10D470008DFABC1B234F2133D0AE225AF45B91C0EE
+:10D480007C7749BD1FFC2A13693AF5EB36C48AF64E
+:10D490005179D4DE6B10EDDD269E0ECB10FBA56717
+:10D4A0007D18ED9F8ABB53B24007B3A6E9E9203F40
+:10D4B0004FD08D4A1FCF734A39E34AC4FE5EB46E23
+:10D4C00024C98D165B69FD73C0D7D311A40F566CA8
+:10D4D000B8ED8642CCEF9941D070D8E737EE1F0304
+:10D4E0007A5BB46EC1F77E8FF3C85E1B7D6FCFF39E
+:10D4F0009CCF85BEAD39CB9FE31F16CD3B6A49E477
+:10D50000ED3D6DB3CFBDC8D31BBDFBDF845E70E3C3
+:10D510004D46AA7F236BFBCB1FC117D689716EF0D6
+:10D520005E3025F2FE6E28D218CABB6C8ED4157CF4
+:10D53000FE15127F7F95FBA0C5C6E6FFD28E79A5AA
+:10D5400064A5F3EF374053ED470F1C9727F5C4A9A7
+:10D55000DA76E83DC3A68BFDA5EAA31FF43B19F0DC
+:10D56000E0F5CC122E2ACFE14AF5AB36867565443C
+:10D570002135FB47F07471C1345B1EAF372B9DCD55
+:10D58000C0B9A9E70E23DB49F3EDA9A07D1F99E5FA
+:10D59000C4BEF730E627BEE71B4974DF35B5A7EBFD
+:10D5A0006E9EEFDA31C2D5427C5D9CDF173B18C915
+:10D5B000F7AEA982AF29FE72D2D11949F42ACFF36E
+:10D5C0009592343E6A9ABE752CAF5F69B774411E5E
+:10D5D0002C7E706E9493CFB3720B3FCF7339C636E7
+:10D5E000E9CFF3FCBC9D9137F8CA7379E8F91B3495
+:10D5F000033AAADAA4111D0E6B715992888F690E35
+:10D60000ACAFCAEECF84FCAB72D95C283FDBEC7EBA
+:10D61000E034D70FCF37CFA4945DE670E7F3BC0AB0
+:10D62000C8E3FB7E6CBEC7053855B456D0793222AC
+:10D63000C743FC69B9A4BB591CCC1AF88DA933099E
+:10D64000FBB02B577E8F7564D9899E6D0C70E832C4
+:10D650003BB230AFAEF53603E4E6ACBB045DF37D20
+:10D660006635F1F6F7985838F6FBDFD09EAFB36C0D
+:10D67000ADA97407CF0FB53253642CE82A97E8FAA6
+:10D68000E7051E33E0F0E98FD838E805959B36D3DF
+:10D690007C145D305347F120E879BBD3F270BE565D
+:10D6A00074F4F38269D7E605D3C34D1AD1014F5FF5
+:10D6B000C9207A98338BE8619A3F73259F5789B1C7
+:10D6C0008EB961674864AE303EFF5ED643FA442FA0
+:10D6D000D72720CF143F517C83D381DB1A1FC0EFA3
+:10D6E0009E663E15CE93F7365B297DB2D9C14C1CA0
+:10D6F000BEFB9A1329FF4CB393D2B6E66CFAFECB6D
+:10D700006617E50F348FA3FCC16637E50F35CFA44C
+:10D71000F4C5E652FAAEF812870BF121C557143F53
+:10D7200052F4A4F852281D953BB137A83DF13DC5F0
+:10D73000EFB00E435E801F29FCA66BA5DEC434F05B
+:10D74000B1CE05E01725C6B34F3FCFE1DB5B6D7768
+:10D7500085390117C1F77AED5692F3A9167608E7D5
+:10D76000FF9615EEAEBB83E4EAADD51A3305D1EDD5
+:10D770006D8D36660AA2DBDB9B6274F9B2A6B78FA9
+:10D7800025F0FEFF9EE2F1022F27EFFCF8D1FFE427
+:10D79000DF1FBFF3F3E1C0379FC7EE8730EE9AF08B
+:10D7A000BE79C422BFCE4C726658B838270D0B170D
+:10D7B000E724FC013F8B98D8A78FDFF957DAE75DA4
+:10D7C0004D614E23F40FE08BC3F70389AF454D61E4
+:10D7D00004C78AF5A79E7E1EFB7D8D85F8DDA275A8
+:10D7E000727F6EE4700DD2DB3E4C62A49F696EC600
+:10D7F0009A38FC3EFC91C5CF653FFB50B3FA34DE4E
+:10D8000050E387A632FEDDB3F157EF41DFD69A4EE3
+:10D81000907EECB1DAFD46CCCF6B3E1BDC9FD6741C
+:10D820009CEAB1CEA1311F47D0566480634481DBAE
+:10D83000023E01DA06FE16651F61D8DFAC55730C97
+:10D84000E7EBAA92DFAB366AA47728F83F9167A48A
+:10D850007D753AD744789D863D3B981818C929456F
+:10D86000B79C6FB87DD81FADB9962541FC7891FC67
+:10D870005E996DA0547D3FCDB725FA9986CDC5FB45
+:10D88000BD373BDDB298F89DD3027EA0EA2FCACE09
+:10D89000DB905E807EA6C6B1A07DF95C9E49CECBB2
+:10D8A00021E49895CB31DEAE6E0079A0F4934FF170
+:10D8B000BFE369FE74FEAA79E6A9675E845DE2FDB6
+:10D8C00030C253CD35D2BE91E31B3397F41AB75D06
+:10D8D000E3EB6C90F82F7EEA4F519DBC7CF901611F
+:10D8E0003FE56917D28635D5642F6B70F17D827D57
+:10D8F00070C8FC6167105DBEFACCFB519D74BEF030
+:10D90000261B1291FA93194F1B0E9C9AC1D01FEB44
+:10D91000D9E0B05FD96EB97699CE996A1D2587BFD7
+:10D920008CA7F1B54BF154FFF0FAF8FEEC20CB993F
+:10D93000E9C3BEFD4B7606B7CEAEB69C6DBA60E4C9
+:10D94000F35DBE66E627A0F3D0FA9FE445C6817E6C
+:10D95000D8583696EC18266600BE575A051C7A7DB4
+:10D96000C3A3D9D7D85F966FE38DB8AAD56B72469B
+:10D97000BBF87CBB613FEFA77E4EBE90EBE7F83E65
+:10D9800062FC2CD5BDCF48E785EE7D9144FF0DFBB1
+:10D990001E383E91E71B76691896D5B30E8253C3A5
+:10D9A0000123B306CB33D877060D3CCFDAA7221B71
+:10D9B000414FCBDA34F76E3E9F5EAB337A70D07C4A
+:10D9C0006CF9829E6AC3DAC6105CE5FCFF2EF999F9
+:10D9D000AAB7ACFD010BF0C5EB9D27FDE517118C37
+:10D9E000EC66ACE74DCCF3CCF67C17EC7BCBDAF6EF
+:10D9F0003790FCDF17E118CED7F1B9B4F3AB7E0650
+:10DA0000E78BFD34385FE81D67A43DF7CC3346E271
+:10DA1000439827F6E1E7D07383E6992CE7999C2F8A
+:10DA2000F49B23D88F8581FACBDABAA23279FD4FE5
+:10DA30000EBD4DE97039CE327BC768C8CD4F0E445C
+:10DA4000CCF451FAD3192FF1F1CEB54D8DD382F626
+:10DA5000555EBE99FA3DB7DD3813F062BE4152CF34
+:10DA60006FA3F59CD997ACD1F916F0E67AFE99032D
+:10DA7000CF461968DF7A453B89478355D869C36229
+:10DA80009C52CFB4B642DF58C8B5BB68CEEFEA0FA0
+:10DA90005C20F91BFA5DD5A7FD9684F3770FD93585
+:10DAA000F89F01F45BEF10382F31E624601F945F7C
+:10DAB000E3BCE556F0B1D7CC020F439D0FE15C55B6
+:10DAC000FED620B25BAC343B1390FFE2757E10E4CF
+:10DAD000F32ECF97FB3BB1B31076CEAE3421D7EB0C
+:10DAE00036F2830A5FCF108E772F5F729DCFC83CCE
+:10DAF000F9013FD1FCFC745ADF23D506B785FC2C15
+:10DB0000FE2CD83D4F5A9897FC46BFB4097F40BAC7
+:10DB1000B0EB3F22FD4575B1FEAC41B07F493CD62C
+:10DB2000CDE1E541F8ACDBE9CF82FE72D622EC7C98
+:10DB3000287720CD13F55A24DDA01FF4DB95E638B5
+:10DB40004F7AE673910CFABEE1F9486157F8B96D66
+:10DB5000675890DCAC9674C575262FD6EFDD2DE6A0
+:10DB60008779417F5E6669CD827EA9C65D16D54AFA
+:10DB7000E39D95E32D0B6F15FE098BB047A23E8DFB
+:10DB80006F66E447E979228CF4D4CF933A0E62FCB5
+:10DB9000CF9F18C920C7BBD27C4B0E5139D7DF3875
+:10DBA0003E6A9E0CF363BE9F3D11E963BCFE67664F
+:10DBB000A10F7D16194FFAD089C8ADE5E497D915A4
+:10DBC000A6C1AEF299C62C8928DF2DFC1835CD4DA3
+:10DBD000E47FA8E1DB9DE5513A93C5A27C24D95BA3
+:10DBE0003EFB35DFA71A7DDF88EF1ED65AFE03EC19
+:10DBF000BBBD116477FBFCC9FF1ED99FDFA26697EE
+:10DC0000DEBEA4E84095DF23F9D23D128EF7E53B56
+:10DC100008FFF5116D5BD3699D62BF723CD0B98B73
+:10DC2000EF8F78D8BB4FB6BD10AFD901677FD64F05
+:10DC300001F7BDE27CF3F93E33F95D6A9E8F749380
+:10DC40001DE7EEB106C88B1AA3D0836B0C1C7C3C7D
+:10DC5000D5EEDC9B053DBBE5095B1EE0C1E14DE770
+:10DC6000C89EDD46398E18F7B33D29C2AEEF97F94D
+:10DC700083A3C8AE3F2B96DD3E87F49CEDA301D76E
+:10DC80008BBB220CA00B3E8E5BE3F0A9F9C10F0504
+:10DC90003CA397905ECEF71FF1CB3AC92FEBEF9ED6
+:10DCA000183D11FBE92D23835E70D1E44A003F0C3F
+:10DCB00085D70792AFD41E7CD402BF5D1DDF371E0F
+:10DCC000BE6F6AA57FACF6498DF4BADA0D131F2238
+:10DCD0003EF8A6990DE7F338DBF64054303E8E4B04
+:10DCE0007E1668EFA2FAB5BCBE68FF5A14CD678FE6
+:10DCF000D985F984E2F15BB77FD2F8ADDAF7D14785
+:10DD00001B97EBA3AF5CF745D6F1FDF7C14FF6D9F2
+:10DD1000C87EC5F19E0ABDE38CB96D09D67DE66962
+:10DD20001BF199333162BF7FC2F9A17704E6F19DFF
+:10DD3000FBC9BEF1BBB90CF260A94FDFAF1AF735D2
+:10DD4000C97FEB07B9A26127ABE778407F1C2FDFC3
+:10DD5000A5F66F99A97DE83A9E44BBC2A0FDF9746F
+:10DD600004D1CB9921021F679E194172A52B46D081
+:10DD7000399F6F2ACE2B676244CAA08C703AA89153
+:10DD8000E7D13353DBE8FC7D46DB4F699759B4ABF1
+:10DD900069927E634E7789A01BD024FC61D64D1D0D
+:10DDA000D02760AF1E9347A93F2CF64ABB33E81338
+:10DDB0007228A340C82F86F1E2A5FF83F494360BA6
+:10DDC000F8B247EA7175FBAEF4C301BF75FB34F2DC
+:10DDD0002319543F7CD671CA5ECEE9B1D6ABB96D7A
+:10DDE00098CFBA15CBC88FD4B8F956D0BB5A47AD27
+:10DDF00089CDC479A84B33D27CBA6C7CDF000EC1CC
+:10DE0000E305E95D91817198239EF44C52AE630A5B
+:10DE100084BC42BE95F757B74EDB44E3A4A973A573
+:10DE2000589F8213078B05F6327EDE17E503AC5F41
+:10DE3000CD3374FD6A3EC30B849DA22BCD797F1137
+:10DE4000F0FD86D18573FAC5CBF9D1B15FA397E117
+:10DE5000E4D66737E6F3CF034DF1F97F29F95B2D5F
+:10DE6000ECD27C9E59DBF5FE90EC5DFAFC55FBF4A0
+:10DE7000F99C03FAFCE8767DDEF5AA3E3F448EABC2
+:10DE8000E08473AF738438F722C5B9D71926CEBDA5
+:10DE9000C8E3DC8B14E75E7CC7B917799C7B91C71C
+:10DEA000B917799C7B91E2DC8BEF9505827FD7498E
+:10DEB000BB23F000BF0C7BC1A6FCECB45FBA17C457
+:10DEC00013FF547ED2EE653994EFB3EBCCB6925D7E
+:10DED000876C375C2F993BD473434121FCA71D1BF2
+:10DEE0009280375327D97397BF28ECB97579363BA1
+:10DEF000EC0C9DEB3FD900F5296BA8670EEA779BE8
+:10DF00007BF6101D98FCC4373AD73ADF9A22F047C7
+:10DF1000F60E668FA5F34905E45DECC0780CF5AB11
+:10DF2000B04D7A3F4AA85F25D49F124A07CA8FF2A4
+:10DF3000B8B92709FCFED413D64D98FF2969276389
+:10DF4000F3ADA47F29BDBAC4682738ADBC4FDB0947
+:10DF500039B5AA2096DAF79EE0FA763FF256A595F3
+:10DF600097F2855EADF29B3403F9693C6E9243AB48
+:10DF7000E49C52B59EAEBB4123910692E317ED0699
+:10DF80003A175C7CC7487AC4886D06DD7A46FAC2C7
+:10DF900075F475F5DED8107FE0105DFD6B0EA5877A
+:10DFA000F803AFD2FBA96E5AFB0ACED77337E5EB65
+:10DFB000EA55954E0C81A39CB7D44B5BD66C4B05B0
+:10DFC000FF5915D94BF35FF59C8DEE5D5471F9E265
+:10DFD000E6EBAE4686F3C76AABFB46C0AFBACD1CD4
+:10DFE00003BB56A5943FAC492F8FAB4DCCEB880DAE
+:10DFF000D05DB583B96378FB73B9AD7B0C1C6FE75B
+:10E000000CDBB71639E15FDA91EAE074B55A6B8B35
+:10E010001FCFFB3B15E3D951C0F773AAD9FF933249
+:10E02000F0CBFD196C2DAF776AD3B351A4774B3A7F
+:10E030004B353BC281EF1DAD463A17C03E057B9084
+:10E04000A2871DAD83C233ED817506F07F99D6C7D7
+:10E05000F142F7467AED4786AE821ED726D65B3D63
+:10E0600055F3929E2CD7B352CA15B64EF4B35AE666
+:10E070004FCBF3825ADFD991AF8C76C2AFD97C28CF
+:10E08000D5083E6ED8B72709FA4582A71DFBA77AA7
+:10E09000C7F0FF2CE2E3D6FCDEC8E047FE68CBF415
+:10E0A000A8F1D03F9F36BB66F1FCDDAD3FB3E05C2D
+:10E0B0005063F25970EEAC7E628705FEFF6BF7EE9F
+:10E0C000A0EF4BF656D0797B296BA473E4A76621A9
+:10E0D000A7153CAAA769DB1D7CDE998582BF568700
+:10E0E0008BFB2025C6A2637158EF5E2D17EBBDA9EF
+:10E0F00074BFA5827F7F57F2E1D0FDD1FBFADC929D
+:10E10000C1B02BB5093FE840FB619E7F24ED87B984
+:10E1100097D228BDE9D2D574AEFA3D2B1D457C229D
+:10E1200027E43CFBBA51D8CDDAC53EA8B6F8E3E601
+:10E13000629FBC6CA67D526F82ED1BE764C626F021
+:10E14000B4B4C8A8A3D7E5C5113A7A9ECF62757E4C
+:10E15000E59BD9105DFEA65919BAFAB7DC747508AB
+:10E16000FDE705CA898F4CD0DD5FA95FE3756A645E
+:10E17000479BA6FFCED3354467D7EBDAD7B33981B7
+:10E180007A3807EFFA2DC199B10E0BCE5BD5067127
+:10E190005F67BEA74B7EEFA4EF7C21BA7D382CC30E
+:10E1A000F59F422E9AC93EAFECD3F3F1FF19FDC99A
+:10E1B000458E68396EB451D8173C7ABDA383CE9F83
+:10E1C0004CE0A15EDA7BEAB385BDA7DEDB6169B412
+:10E1D00013FC4DC91C240DAD1AD9F3787D6B72ACBC
+:10E1E000C8AFC1F703E6809D8589FE2EA1FC84B1EE
+:10E1F00002FB25B4BC81AF1B7A4603EC3564679AF9
+:10E20000F909D999D438B27F45A74BB7E9ED470D45
+:10E21000B0EB04E17359A193E8B566EFFEE3433830
+:10E220007CE696C6E4621FD5B5CD3657E45C496FEF
+:10E230008ACF5FAC3690DFBBF7F5A3446FBDD52620
+:10E24000A2EB6F824B835BD83543E970095F9795EA
+:10E250008FBFE480E6F269A21EE03304F419029F46
+:10E26000E47EE0A6E0D507BF90F2A5F89F02DC2788
+:10E27000D07CFEB4FEE012024F354E08BCD8383DCB
+:10E280003C96789C6F81FF2C396164BE6FB1FEA50E
+:10E290005827E6C1D78979CCB924EC26CA9F70F3F8
+:10E2A0002513E5FBE8A694C32B0FFB4EBF4FFBE8FD
+:10E2B000A854EC9B7997E2A9DDBF8A9EBE898ED4D3
+:10E2C000FC15DF0EECA3BB486E2C2F8C8CFB98B397
+:10E2D0000AFEFF85C417247F1D582FF50A3EEAD198
+:10E2E000CB9961778EA37B47BDF674D22BFAE4906D
+:10E2F000435FBE32323D01E51E69B753FCD823EBC4
+:10E30000A9712A78B97310E87A683CECB11BD6651C
+:10E31000A47606E92B9EF5E678D80B53D70EA2B467
+:10E32000C2E688871CA9586B2C857CFCF09E84F87B
+:10E3300071B0CFAF37C7CDE25D7F7847412A1B85EB
+:10E340007C09A5A73687CD0FB673AB745BA1D0430C
+:10E35000EBEF7C8FE4DA39C3EB51F3B1EFD63F1723
+:10E3600085AB37B5EBDF1EE3E02AC9DD319E870AB6
+:10E37000C98FBA638F037073EC180D3BF5CF6143FF
+:10E380001B1CD01F6AD69724C02E56F7B7A38F4107
+:10E39000EE7BD69AE3A17F7EF60E978B1AC935D213
+:10E3A0001B3EB5313A2F7DBA3BC207FFFDA71A735A
+:10E3B000C3BFB3CCF8CA68874ECEB6DF8C79EC4DBC
+:10E3C000F0FCBCB010E3FBF624627C9797EE677A12
+:10E3D000D60E8FEECF8EA2D2E5DB845EB747D97121
+:10E3E000A5BD17FA3CF2D0E7D908A1CF230F7D1EB7
+:10E3F00029F4797C3F26EDF8C35A7A72711EF54EE6
+:10E4000063D98D2477EDD9D0D75769E12ED2333532
+:10E410005702EC63EC9D18216F43F0ABD2493D5C91
+:10E42000E70AA2FB2997AC2CF89ED95416A3CB4F30
+:10E43000B726E9EA9738D274E5D7268ED4955FE7F8
+:10E44000CCD5E5BF933D5E57FF06D7545DFEBBE3D9
+:10E45000AED3D59FED9EADCBCF9DB940577F5E69C2
+:10E4600085AEFC96F9CB74E50B3C2B74F95BABEFF6
+:10E47000D0D5BFAD71ADAEDCCD1C26C8BD769CB38A
+:10E4800038DC5FC6398BA7ABDE186E0FC66BD17454
+:10E4900043637F76FAF3521F9A38D6FD19E823C5F5
+:10E4A00020E890A76EA81097A55C49667E4D9C73E6
+:10E4B0003B924037A1F542CB8B228E5C74721C2EAE
+:10E4C00039187BAB89F391A2B147F23378FE9931C9
+:10E4D0000B447EE29167D379FEE0C1ADB79A38FF75
+:10E4E00028BAE6C845948F1E5B2EF27319A91C4703
+:10E4F000C6FC6DA197AFA3684AFA2697B093F47B48
+:10E500004F53A58003EE37020E48FD9C3E911EE15D
+:10E51000F489F4554E9F5566C68E73FA447A829FED
+:10E5200037F1FD37FCBC89F4757EDE44FA263F6F77
+:10E5300022EDE0E74DA4BF6B9E4FE93BCD1E6AF78D
+:10E540006E7335A5EF3537D2F73F363751FA41B301
+:10E5500097BE278E5176053FD95F949FA901FE3D56
+:10E56000D8E70E99CF06FB61959F50F9055B1A59C4
+:10E570006704F669A729E6636BC0DF37309F35B1C2
+:10E580008F83F4B0CD89EE8C3134FE5007F97BE4F3
+:10E59000F769DADC14B8FE6E1DED193986E37B5E8F
+:10E5A0005EE5FA68CE3FA65C6E34835E7E2FEFA9EF
+:10E5B00086F67F59D249DC58F768B49B6C15F7F0A2
+:10E5C000265BC53DBBC9A6CE16F0A3962F9913F7BF
+:10E5D000685E89B4107F6AB9C7E4839D52FB82519B
+:10E5E0007E521CA37CCB971D742F6FB2C39548F24B
+:10E5F00046E6FBFCE7F80BBA2FA3FCD9EA9E4CF1E8
+:10E60000179DD3A1074CB25B9C6121FE77F8AD5FEB
+:10E61000897C57CD87613CE527DFF525F31B46074D
+:10E62000FCE193AD1D69B0134C5A6D7505DFFF51C8
+:10E630007E6FED8B0E23E489BAE7A3C651F38D34C8
+:10E64000F1FEF202F778263BDA7271AFA1A5DE4E39
+:10E65000FD25F0EF963CAAE73652BBB65CD8812781
+:10E66000D5D95DB06F2B7F7B825C37AF47EB2CFE3B
+:10E67000C243F70D26C9FB06E8C72ACABDE86752A0
+:10E680009C3FC984F5375A5CB0873EAAF1F6790100
+:10E69000FF3FEA4704ED5FCC13FD66FE85CF177A96
+:10E6A000BBDB4DF09DABCE6F4E9997F29959A79178
+:10E6B000FDCA28F3BF1DED590EBC978639FE1441E3
+:10E6C000FB3C2305768ED9526FFF1A7A59FD3F43E2
+:10E6D0002F6E81EFA18CEC69A174A3F0A2F03C1025
+:10E6E0001D29BC07DDD7223CF7DDBF92FD84D2D7C0
+:10E6F0004074A5E869B255E01D78C53D1A4547DA72
+:10E70000176D3B681D755692738A8E42E9E04A3A4E
+:10E710001274D9F23D2BF577251D05F00F78FCF327
+:10E7200074D46184DCFD47E9E7F61E36239A17DDD1
+:10E730007B8DE732E446C525E771E42BD9D4192057
+:10E740002955FE00CA075F591E4A5FAAFE8B03F4D3
+:10E75000E7F9A2C71C1D449793A40CFCC300F55F06
+:10E7600093F7E25FB3A9FB1E6E7B2EA783E9920F9E
+:10E77000AF2A11F43533CD48FE8CE9394B49BF67D8
+:10E7800076A11F3BF93F646F93FEF5EB65BB1997CC
+:10E790004BD7619C19717AFDFB7AA977CF0CF1B741
+:10E7A0005F9F732DE9E1D787E8D9EF8D917A741ACD
+:10E7B0004B13E7EB4DA4FF16CBFD982CF19DE134F4
+:10E7C000B2220EF712E6314108BC7ADEE2467FD76C
+:10E7D000322FE5AF633E4ABFC3FCA407DCC0050689
+:10E7E000F2DF658CEE8F1E8DB8B16C39EF6F7AFE5B
+:10E7F000F44C7CAFB3F6A45A0CB81DE8F90CF2A1A6
+:10E80000C1E8F933F4CC73299E11381F1F29769281
+:10E810001E76C49A417A21F69339C85EF96B2E4769
+:10E8200033B99C3BCAE52CD2635CCE667279F72B78
+:10E830002E6791BF3E7B2D43BB194EFDFD1ED5FEBD
+:10E840003B8EE9CC34686039F69DD12F0C851DEBE9
+:10E85000B59811C5C0DB6B31638BB1DED762120C8A
+:10E86000220DB3503AEAF9CCFEF45645AF81F16679
+:10E87000D078A1F055F00C85A382EF3F01CF416322
+:10E880000BAF84E765E8F7B09F5ADF8E4A4C879F4D
+:10E8900051C6D345083E58FFFCA804ACA3CE2AE0DD
+:10E8A00032A96922A5939BC633533EF999BC80EFE8
+:10E8B0006758020CCE217636669A46F9EF49DACAD5
+:10E8C0004EF00CC73CCEE6F9B3B846C63ED9DE12D0
+:10E8D00085FB99E79E31BA70AEA9333A37B9602704
+:10E8E0007FCD28E2822E1F4D857F93EDEAFFBE7417
+:10E8F0009D55C1CF4B70FDD9356EDA6F0CDED9F85E
+:10E90000805E33344CDC3326F742DEC07ACE98701A
+:10E91000C167868609FEA8F0C5DB09B9CBFB19C320
+:10E92000F95AF2FDE174AE2918E62EC27AF879811F
+:10E93000E28A7AB323C85EF11B199738D97F35C5AF
+:10E94000E5CDC4B99D7F378647EDC4BEFF8D8C4BA6
+:10E95000FCC520CFB5687F6D5A5E22E0318509BFC6
+:10E96000CA7556B3CBCFE774DD58B90F47B3D13270
+:10E97000AE4777FE507692DE3823C9A1C92CEB2131
+:10E98000D8098A4F98C94ED077DF2D51F8457B4F73
+:10E990005C3482AF94446A6C505A203E272CD1C01C
+:10E9A0009C417ABBCD19CE9C41FB23223B56978FCD
+:10E9B000740DD1D58F1E97AE2B8F715FA52B1F3491
+:10E9C000334F971F5C3A41573F61FE345D3EC97338
+:10E9D000BDAE7E72F51C5D5EF1BD64F189A5342E7D
+:10E9E000D4B51FD6B448573FCD5BA32B5778605E94
+:10E9F0007747763CF8A2F8CBD8B85257EFA7512208
+:10EA0000DE64A67DC92CECF7E1AD3FD0CFCBF8BAE0
+:10EA100046F1A34EC16FBDFC1FD05149A29EFF4ECF
+:10EA200077E8ED1AC98D265D7EC33F8A67CF553AD8
+:10EA30003C87C283E3DDE5477D2EBFBD3C5FF2EB43
+:10EA40004A13F40BF82F82E70FFF45F07AE1BF0875
+:10EA5000CEC37F115C1FFE8BE072F82F82CBF34F89
+:10EA6000E8F15CD8A1C7F3D8F7F47856F437103E34
+:10EA7000C677EAE920141F133F0DA10B8987F9FC23
+:10EA80009FFEF04047114EFFD31B19D9E7BE092F57
+:10EA90002F84E065D2484F3BF6EBFC4117532DC065
+:10EAA000538F6704CE939F493B49E83D4E2F57074C
+:10EAB000280EE107468ABF396968D5C097FD299EAF
+:10EAC000636379FDDB731A897E1259E9FE257C3E6A
+:10EAD000E5FF11467E9CF261225E97E574529C83AD
+:10EAE000E277E5C9E21ED11B63E5F9CD25EE13758A
+:10EAF0008C15FA6CA4CB41F78E2B72441C073F7621
+:10EB0000A5968F02FDBC6E1B017AD822FC269D883B
+:10EB1000178E0BC40B43DF847E9722F5AB963F58CC
+:10EB2000AD58C7886D4C272747FAACBA7BAF57EF73
+:10EB300075E8F2A3DA1275F5AF39E4D495E7FAB3C4
+:10EB400075E5F9275CBA7C61C7385DFDB1EFB97531
+:10EB5000F9F19D3375F5277E5AAACB27B39E87011D
+:10EB6000DF619A38EF5B395FA27B604E110F547EF4
+:10EB7000778C8803957600A54FABFBD01E4977A113
+:10EB80007AFA308BD0535B9298388759E5798BE9C4
+:10EB9000F5758FBCCFACF454E6D5DF6756F798FB1C
+:10EBA000F47AA9B72BFD38E81EB33BF81E73B98C75
+:10EBB000DF0E957F71E3847D2F74FEC32C62BD2D23
+:10EBC0007758286E44CD2B743ECBF304DDEEB6F6B9
+:10EBD0001FBF933E4EA3FE8B724B878CE3F51E3313
+:10EBE000BB7C6447B9623C57A717E7CA1F595C77DB
+:10EBF00039BF79BCF26BC47ACA0C86DB67E7D07D7B
+:10EC0000B1F9BF0C1A3F6F9CA0EFF8095ABFEB2B6C
+:10EC10008F16F7B958B4C509FA1D783C01CF440BDB
+:10EC20005B477146F2DEFF6D9BDAEE1BC18BCA2C8F
+:10EC3000AD66325E309F19F4306B1AD7A772611738
+:10EC40007CF1113BD7371E6B32919D67FCB8616533
+:10EC50005C13EB8BE318C6CF1BA00FE82C38A73C46
+:10EC600039DE48E32C1C27D65762BCDC77FF9EFCBC
+:10EC7000178C49FECDE83E4C3FF44674A8D6F1AF60
+:10EC8000BA8FAFE836144EEA7CC9A4DCC994F352BB
+:10EC9000F053FB41C14FC5433857984B77DA29AE43
+:10ECA0006226EE9129FCBD3C5EF0A34D8047A1A8F1
+:10ECB000077E3450BD12634E34ECE1BDCC19EDF843
+:10ECC0001A7BEFBF304E81E03F507CD540FCE10A1B
+:10ECD000BE3040BCD540F4497FFF40DC55107F106A
+:10ECE000F77A243E7C9906F2A3DF1DA9DFC72F8C9B
+:10ECF00013F0F5C87DCCE5AB3D57CF2718ECF72DC9
+:10ED0000EB8D924F08B90A7D03DF17AF3793BEC171
+:10ED100058E956C4117DB4C54CF75B27BB9D335CE5
+:10ED2000C23F4F7A07F9BDF8D42ABC7A79CAE5FB0D
+:10ED30004EE8C153986B03FC19951BF5E54BED3379
+:10ED40003E833C5F1C722E5D2ACFAB4B43CEA54F5A
+:10ED50008D93F2D8C55CA427493F7FB5ACD3474714
+:10ED6000BE8C686977A1FDC953BA17A6E0E284BFDB
+:10ED7000263F90E7F00BCF869C5E67EAF7BE5E1FEA
+:10ED8000FC06B88F7016F7119CD8EFBD146FD57BB9
+:10ED9000C026FC94CA1F24EB9FF55EA472D4476F73
+:10EDA000E7723B46430FE9F31F85F8A17AED86A889
+:10EDB00071E86F9F99FA53F72D6AFEEA1BED08F28E
+:10EDC000277B3A8DBAFB2D57CC7FED7374FFE2EEB3
+:10EDD00018CF3BE0E3674C2E2BF0778FFD483CE2E9
+:10EDE000E46749BB4DE87CFBF4CE224DF861BD22BF
+:10EDF0006EB677A646F700381F64D837EADEC06CD7
+:10EE0000E68F43AAFC319E8DE309CECA1F53E11F52
+:10EE10004FF39CD7B2D41CCEAB743EBCA624DC19F5
+:10EE2000F0D374A6887B3F03F96BE65ECAA5FE6E3D
+:10EE3000BA3491FAB9382E4DE85DEBEE5B013ABA7F
+:10EE40006A2F33639D9D21F7DE555A29F98D77BCD2
+:10EE5000E2D3F23ED15A8DE87CA5C6D4FD22E2D39E
+:10EE60002A7FB155E64B447ED57A91EF348B776695
+:10EE7000F6487B03D68914EBC1B9789FB447601D6F
+:10EE800048B10E7C075F421E7C0979F025E4C197EA
+:10EE900090822FE1FB22569A9A6B147EA5E2A07D08
+:10EEA00003BF527190DE03BF52701E7EA5E0FAF0E0
+:10EEB0002B0597C3AF145C0EBF52701E7EA5E0FAFF
+:10EEC000F02B05E7D9B8EB0279F031F76C5D7E2EB7
+:10EED000D7BF8B83F62DFC4AC1FDC3AFA4EBCFB3E4
+:10EEE00042D7FE56D6A46B0FBF5270FDDB9B349DFC
+:10EEF000DFE976F91E40E5B641441F2F8D2E758D52
+:10EF0000E7FBF5CF117FFB9E19E70063FB32D0EDE5
+:10EF1000CAFA7097C073EB4C8177031378EE5940AF
+:10EF2000785E6311F91271FFB83FFF4DB159F86F68
+:10EF300090C27F8314FE1BA4F0DF140F17FE1BA4E6
+:10EF4000F0DFE03BFC3748E1BF410AFF0D52F86FAC
+:10EF500090C27F8314FE1BB483FF0629FC37F80E92
+:10EF6000FF0D52F86FF0FD24FC4841EF66404FCF93
+:10EF7000D49DEB381DEACE750E5D1E7A7A707DE861
+:10EF8000E9C1E5D0D383CBA1A707E7A1A707D7871E
+:10EF90009E1E9C5F3DCE49FC12FA7A703BE8EBC1A5
+:10EFA000F951ADDE63B01DDDB0FDFCAB483B23B5D0
+:10EFB000C734CE0A56BC70A00C7EB64E9B961AC3C0
+:10EFC00039A5597BB1AC98E73DF21EDF68D66300E6
+:10EFD000BEC9CFCEF1E6F133BA773CEAAB242A576B
+:10EFE0007E5DFAE378CF3DC048EF3F26E33D557B99
+:10EFF00017731891AAFA817CFFF542C757F5885F0D
+:10F0000006CD831F0C7371CF24778D3D0FF7E5F785
+:10F01000183471DFF42E71DF3794AE764BBEB4C76F
+:10F02000B0FF4838EE0F55682EC4316499D8097383
+:10F030001EE0D49807FDE0BEF131725D8D1370FFC4
+:10F0400048CD5BD901399FA0F8B5A21E66A9E2E3BD
+:10F050004CFA82591683BF5B845E8076382F5EED52
+:10F06000D5DC3B83E8FBA1F142BE79BC2B2654F1F1
+:10F07000EF57EF6B9C80B8B859E1A2DDCF1F8F220C
+:10F0800038DEB84EDB89F8C3A27DCC8D78579F9CC3
+:10F09000F7D5FB1C962A1AD741F174AADF8AEDA98D
+:10F0A00014FF57C13A8B115FC10A3406FFA8821BB7
+:10F0B0005FDFAB585F16DF2A66D23F455C4EB88CE7
+:10F0C000CB51F1386131A555905B2A2E6752414CE6
+:10F0D00009EEC5B176E64218F00D0515EB07F3FE13
+:10F0E0003D3EB70BF78A267DD1788CF2BB4A294F7B
+:10F0F000643086C621B936C2ABD1FB1A377A77188D
+:10F10000E29C88D75D6B8E47FD7DCC0575878B1A99
+:10F110008A3B55F3CB611D069B06BCB3A38382E8F3
+:10F120008873809B80F75C9799DEDF986D7298C139
+:10F130003742E5F895F71643F48490FB252D6BDEF6
+:10F140004B35A6E37E89C1E507DF7A2E82F405A55B
+:10F15000EF54C8FB6617D71D1B7C0B2FAFD82FF4BD
+:10F1600003CF368DF89FBA6F529FE14B35405F1841
+:10F17000B26374AC51C87FF0C533DE676FC616AD9D
+:10F18000587F8CE2222AD617468BB828E187A892AE
+:10F1900070AA92F78A588E231E7AE6879CEFB847AA
+:10F1A000D0BDC4688A2B6C15FA9CB2B7287D50BDBF
+:10F1B0001F53F146FE71E0BDE251F92ECBC60A8A1B
+:10F1C000BF0ABDE7532BF5BD65EBCC747F6859884A
+:10F1D0003E582BEF0BD586E883E7C687E883F2FC21
+:10F1E000A2EEF356BC71741EE92B8D66F2CB95AD81
+:10F1F00015FA0BDBCF7C8867285B3BDD807743CA41
+:10F200009E73BBB47EE8E42DA9C7CCEAB4115CE7D9
+:10F210005C4AA6F4E64B4994DE7249DCA344EC0B4D
+:10F22000E8A0F305467AF4DB526F99877B9588470F
+:10F23000F486C9FB938CF4A65CE62801FFB8CAAD3E
+:10F240001D85DA37CBEC598F7B9BB376308A3FBA7A
+:10F2500001FA0DE2BFA0EFC0EE5E90564271183386
+:10F26000358A67B9A16085A46F4EEF0CF4EE95F472
+:10F270005B4AF93EB920E9DCE3ED3201EE3778353F
+:10F280000BDEE1F3C873ACA2E3507A2F8F90F62720
+:10F29000BBB02FF5D99F30593C6AE38DBE0DF75BAB
+:10F2A000CB61B31BC204E239CC237344F98817A3A2
+:10F2B0006F5B8743CDFFA35DA2CC6010F14E5CDF96
+:10F2C000025FBD6D75AE6551107FF962E2B419132E
+:10F2D0000B03785F1412A7B7F29EE1095F172F5A4C
+:10F2E000C9E18C7D521EDDF93D4EA1ECDA09CC5D01
+:10F2F000CCCFAC0B18538FF7F8712F70A1CCAF7E29
+:10F3000071DC9F36DA093E949F3E21F5362FF15588
+:10F31000C1B76E05DF32825F79A64E207ED53903F4
+:10F32000F888C8E991EF1048B9146287583DC1299F
+:10F33000D61B628FA8CC11FC9C999CA9B7525CB0DB
+:10F3400093EC796AFE1F9AF5719A7D7E9109529E1F
+:10F3500034FF6BE21BFE2BC3731BD6B7D520E2E64E
+:10F3600087185B99B40BD1FE57FC83C9772402F848
+:10F37000E77A1AF9D1354730FE3D1B3511A73E809B
+:10F38000FD8665F73CBC1BF6BB660B439CEBE35963
+:10F39000828E1EFF8185F4F0324BC731BC93A5E00D
+:10F3A000F87ED3BF9BC92ECFFCC3F1FED7C2469BCC
+:10F3B0000BFCF98B89A5AB30EF881C17E16306DFE6
+:10F3C00066E8FF644AE9F7095F9B5E790C71FBCB45
+:10F3D000DBD3288EB4E250EE06BC27F2C544CF0F33
+:10F3E00027C08F6B775820C71BD6C5905C2B4F90DA
+:10F3F000719DAC87FC540AFE0F4C10F6ABEB8A04EF
+:10F400001D77CBF30818E66C5D3D798F3B649F2830
+:10F41000BB60A87D21F41D8781F68FB223C06E608A
+:10F4200009B22B2ABB8439FBC30590A365167DFC6A
+:10F43000A14A5F557637791E5CDC27C77266244087
+:10F440006FDEAC3920C7AAECCE5BC6F37CD509339E
+:10F450006E60B259B14EF17EC73DE2FD8E457CBF74
+:10F4600082DF94C9FB5855DBC6D37EABF2F1347F03
+:10F47000E07D79EBE6A3292F807EFC6E8ACBAF720C
+:10F48000B82DB141FBBEB255D3C5F5ABFC8109C265
+:10F490000E57C6D574C0EFB6D56916BCA153C6D5F4
+:10F4A0000BDCEF7B7582531757CDEBD1BD8659E945
+:10F4B000ECB8783F89CF3B4D8C9717D4FFA256FD0F
+:10F4C000FB04BC3EE9452F4F8824FC5538F8BAD3DD
+:10F4D000903A689E1C0E04A79EFB787F4E1A87F018
+:10F4E00051E9F79971EE2EC37D0A9E5FE8F09931DC
+:10F4F000CEA275E2BD10CF26318E67638C6514F401
+:10F500002693C39202F8E1B01C47F3233E58C5E1AD
+:10F5100082782B1577190A9F0A39DFAAD618BD3EC3
+:10F52000D6BAD90C7C2C18E0BD821E49B78BD64DBB
+:10F53000A578F32A939BE2193C12BE1FADB0DD0BF8
+:10F54000BFC0822D0F99D370CE9E20ECCF3D72DFCD
+:10F55000CD4AF70FA7778156D85C98E702472BADC5
+:10F56000AF0FBE0F727868787FA694E0CBE9C28BAC
+:10F57000FB79555BF4F80CCC47C0B76A4B05EDB787
+:10F5800025268FC5113C8F6DAF0CC73D94057C7F40
+:10F59000E3BD23E6F0507CD3C70FDE924AEBE4F3E1
+:10F5A000A47B502EE70CBCF3C3E984E858D18B8AC6
+:10F5B000CB56E359278AB84CEBC46FDA976ED26BFF
+:10F5C0005A387E61EF1E685F5A10D8C5C7B5548996
+:10F5D000F7D742F7A9DA9F6A5FAA7DAAF6EF63E63A
+:10F5E000527FA216E0335CDE36FEB21F38CD90F3B8
+:10F5F0005D28F1CAE1FA6A701CD73513055ECBD2DB
+:10F60000F5FB1DFDA1DF948962BF974DF30F47DC29
+:10F61000A5AAAFC62D8B15ED40F7A0B7948986BE7D
+:10F62000FA2BA9BE3E1EA5B28F5FEC5B1F0F7EB109
+:10F630005F23BD77E57D4753FE0DFAECD3429F3D36
+:10F6400053B7BB21097AA3C9971AFC2E56955FF0D0
+:10F6500087C55CFF01BF5822E5747B9E276762D097
+:10F66000FEAD7AE0E92C8FE02F7EF0970F9E7EE9C9
+:10F67000F7139C01F9A9E6BF68E36FCD15F6607832
+:10F6800089F5DD9BDD4B717695768B13F7972BD73C
+:10F690005510BF6589FC5CA105F01D4A0715EB34C8
+:10F6A0007A5FACB2698CCFF83FC8972B37CDA637BD
+:10F6B00091149ED47B274A9EAAF97F57CE7FA1A49E
+:10F6C000E33913C5FE5B589D665942FB3ECD520996
+:10F6D000FA97E50BAAF4DFFBF0D4E75FCED980FD03
+:10F6E00081B8213A9F6C320B3BDFBE48D257CFAC7A
+:10F6F0007CFECD9B79BDCFB7EE48857EA2E6B154A6
+:10F70000DAF3164BBBDC12A9B7723C5504E369E986
+:10F71000E3024F95CFBCF127BCCB55962EF9D97D8E
+:10F72000229E7F51DB7EC2DB828D9BCD69BCDE8A4F
+:10F730008969BA7B32958DFCA0CBE1B970E30E33B9
+:10F74000F8C08A89026EA1F45E26EFFB2AB842EE69
+:10F7500068417E0B551FFC6F3F1F67F50A5B14EC79
+:10F76000D36A9C47245D5736C6C462BCCAC68A9F0A
+:10F77000E0DCA1F87DE8BE3B6513FB6111EF0FFBF8
+:10F78000F2D45417C535C3AFD59F5CDD2CF1F653C9
+:10F79000B378BF3139A2ED09C0217979B80BFC21CA
+:10F7A00033B393FCC6A067CCDB6210EF3D66D67521
+:10F7B0005EC03CB84A4DF75390E29D29A8D8F13C71
+:10F7C000BFD320E2AFD28D227D5EC28797FB51CEA0
+:10F7D000E23AE9DDB9BE779342E8D5C2766DC47BE3
+:10F7E000379638E66A7106E853F5A3E853D1EF403F
+:10F7F000EBFB85E423DFB4BE5369D21E91ED4A458D
+:10F800009C4AF9FD235CB0CF7CD33A2DF2FDC1BEFA
+:10F81000F572621D17DBCF7A33C5B965E0F56E2945
+:10F8200089EF67BDA1EB54FB44DD69EFF32FB40A08
+:10F83000FFC2298DCB2FDEEED40A1BDDFF52EB5227
+:10F84000F6EF6F1B87F0F6C458694FE88C841E5999
+:10F85000162EF7BF5FE4F17D76D07725F7D57B6D67
+:10F860008A3F9F6E94729175DE87FDCC9A32E87D57
+:10F870009293ADA722F15ECAA9A9627EAADD6AB3FE
+:10F88000883366911627DE3FE4E7AB934DF0FBAC7F
+:10F890004BA073E46D4D19C4176EF3C608FB83D4F7
+:10F8A000EF97483E18B1BA6203DEF95EBC2DCDA1D8
+:10F8B000F17116DB5D1F6FA3F657BBA00F466C9965
+:10F8C0006D4927BD579C03949F68B5C64A296E0CA5
+:10F8D0007C12FBCBF04A26E4CED26DE21C30CBC0CA
+:10F8E00036C24F38ACA5744612F8C4C31AC599B3D2
+:10F8F000EDFA77ACC6E6979EA7F35FC83B70ABCD39
+:10F900006DEE04F071AE6FC0DEB4D85E4A7A7BBD96
+:10F91000E49327B774D17BF40AAE57C4FF58441C54
+:10F92000704FA481EC70DF360EA84AFA9514DD28DA
+:10F93000BFD423F8CF78C0C94872ADC45846EF2968
+:10F940006DD8329DD2AACD255BBDA3107F5C1A3F36
+:10F9500081E66D263B5955FD7411AFBB332C06E78C
+:10F960009B54B33735582FADDA7137C5FF7CBAC316
+:10F9700046F13FC58ED9C53171F4DE31C5D7A97ABC
+:10F98000A94582EFD4D44FD7C5EF2CE67DE29DCDBB
+:10F990002FDB22E87E988ACBA94BF024150D16F1B7
+:10F9A00039E39D222E2789EA3BFBB58BABF4E36656
+:10F9B00011E711146F74E302DEBEAEFED928F453D2
+:10F9C000FBE0DB631C06B2430D47FF7DF146DB44E1
+:10F9D000BC51963C2FCD8A2DBD7901E0FF6B23C130
+:10F9E0007FA0F1AA0F693A3FDE6DBE68D25B3D7E13
+:10F9F00066811FD9E360A4177F6A644DD00394FE2B
+:10FA0000A2BE8F9770F934BA3515F4B16CCF43A903
+:10FA1000902F9F458A7CD99E5B7E037EE5D9152673
+:10FA2000F47313237DB8D22BF46B561DABDE23B5D4
+:10FA300095733A9A5E1421DE3DDAA68F3757EFDCD4
+:10FA40007E6612EFF320DE08F4FEBEC9BF18F87D13
+:10FA50009FEBAF38C7A61609FA7CBFD53883EE0DE9
+:10FA6000F18D023DE4FDD66723110FADF4B512E32D
+:10FA7000076EBCFFB3F23911178CF7E9E9AD506995
+:10FA80000769907690952F986724C791FE455FEAA5
+:10FA90004C7E4B7FF8AB91FA555FFEC07E3AB7D5EE
+:10FAA000ED13FA435D5B17E90F4A1F517187B5FBF0
+:10FAB000BA489F50ED1A0E08B8D41F10DF2BB20DB4
+:10FAC000CA8EE2D632719ED628EF7D31BF7CAD2939
+:10FAD000389F57BE16CC7E82B28FF4903E786FF678
+:10FAE000EFE81C5EBF4EF6CBF3E6A0F1AA414485D9
+:10FAF000E27B861DED9DBAF35DFD81186AEFAF0FC5
+:10FB0000DF0839EF6EB09B90B6D4DB49EE6F6F34EF
+:10FB100064E39EBA5B0B77418F6B97F7B706D7BE4E
+:10FB20006B83FD2089F51CC57BBBFE14CF0F8B7842
+:10FB3000BF0978DDC5188827EA3EFC493EFA9F3C9C
+:10FB4000ACF322DED4306B53CAE1A7682992EBC82C
+:10FB5000E9CC075D0F3E22F8F3A366B691DE6D3661
+:10FB60009532D8EFFDD2BFE8FDCA40EFCFB66BFEAD
+:10FB70009F05EB5787247D9686093FE3CED19E4DA6
+:10FB800098C77735F3A85CBA77681C8EFEBBA51FB3
+:10FB900052E9A9D3247F4E91E72BCB90443BE85800
+:10FBA000DDB7D3DC6E8AF7BC2BE74825E4F38F7B07
+:10FBB000AC142F30AD279CF4D6942133499EA977FD
+:10FBC000DB35A78995F1FA47720C7EC4C5FD9859BB
+:10FBD000C5BD006B887E6BB0D1FD64ADFD575F8104
+:10FBE000AF271B2F1C8DC67DD97FD3E8FDD1F2DE58
+:10FBF0008F1F7D8BE13CECCBA578E814CF1EACE7E2
+:10FC000064EFCC2E0F47DD8F1D6D569790172C7823
+:10FC10001DED777C15156B08CCAFBBE7637AD7B1C8
+:10FC2000BBC74A76DB69EDF29DC390F974273AE9C8
+:10FC30009E34AF47FA66B7DD40EFBB4D6B3F4AEFEE
+:10FC4000154E53EF195AF5EF1932674A0CECCA6496
+:10FC50004BE5CA417C8BC0DFE468FD79F1B522A198
+:10FC60002FBE56A4F5FBDEBD8A5B5172E565FB9E97
+:10FC7000DB845D4AECD3E5CACF7F299DF489DEF6AB
+:10FC80008CAF7DC7E26DE8155C5FB8708DFBEDA2AF
+:10FC9000C2805C9D27E1A4E4B38A5B9827E135CF5D
+:10FCA0006E10F009F9DD154537A17411C0BB88F756
+:10FCB00052F8643FE83886782C8EC751F733C2DF9C
+:10FCC00049C2DF57AFAFC7B30B438CEE2E4FDABF3D
+:10FCD000047FF47EF7B7C65F4728FEFCB611D02339
+:10FCE0001E34901EA1EE3B7AE47BEDEADE23CB6668
+:10FCF000C40FCA8DE1642FF4C877DA391F38063E85
+:10FD0000A0F6FFB0999DA320474FF2233AE6D769AA
+:10FD100068A3EFA993D269BF0E651D49F27E4E21FB
+:10FD2000F43763E07D6AA2FB16CDF7F012DCBF9CCE
+:10FD300067A77BEEDDBE90F7A9E53BE6DD4CF287D9
+:10FD4000F9EA1D73BE9F79BB2D0B4479DF3BE6C3F7
+:10FD5000199DA3B6E4B22CE85FEA777F067CC77CE6
+:10FD6000592CD94D1F79C43712F240BD5F3D25C5CE
+:10FD7000933869F095EF576FD54A17E07760BCA3C9
+:10FD8000C47C3B17843FB34780DB0F7BCFC9A648B9
+:10FD90007AB75BD1A9B2730FF3763D0C38A9B8DA04
+:10FDA0003F4B7A53F05771857121785074E73533A2
+:10FDB0008AC3053E1067D4F7FB316B247F51719DD8
+:10FDC0002FBB9C487F9CEAC99D847DB882C399EC77
+:10FDD000E89DDFC37A1FBD23D28DF99D94BF6B11BF
+:10FDE000BAAF8A261994BF98E206CAA57C2B577130
+:10FDF000024DFA3881D0774EC387964E06DCCE6925
+:10FE00006F8FC1C7D7FF8FB1DFFB27D74E127C2280
+:10FE100033D1336312C9B9693A7DF2F5DC4F52E848
+:10FE200077662E1F1D0AF9774B4AE975E8D79629A0
+:10FE3000FC077F4EEAA4388F3F2FF86B0AD99FD773
+:10FE400088F759BFED3CAF8C6B16F4B06AB1B89728
+:10FE500098CC1A898E1303F1B236CCE37F5B5C73C6
+:10FE600020EE782FFDBEC8CBCD6D19A787F783F79D
+:10FE7000B023CF3AF9C9C67BF8E5728AFB8D3EB252
+:10FE80002A8DE7371E3E5A4E71BEC9472EA671DC39
+:10FE9000DC7BF85591BFFAC845C4056F3A7C4CD459
+:10FEA00087FF6008633F397CBCDCCBF171C768CF4A
+:10FEB000FDC0D7CD971A8F411CFF7EED9CC56914FC
+:10FEC000D73A3B255BC4B5AE03DEE7C52F5A1FAD5D
+:10FED00005E25AF74D12EDBA2F887DD07D41D079D9
+:10FEE00018F8C1E07F3E55F1BD8A0F0FC42FD53EF3
+:10FEF000FC57C527ABFDCCF6B8369A418CDE7F3A6D
+:10FF00006EF8C949B42E7DDC70B7B9E731F22B5DCC
+:10FF1000604EF0895722DF75425EB4148AB846AD50
+:10FF2000A7C389FB18450522DF72A1C3093E8F3C98
+:10FF3000EC5BDD3122DE51C5C5B65CF027619F1454
+:10FF4000217E91D72FEEE929071F2DC27DDE34F4E3
+:10FF50007FFCA81C8FA1BF5D1744DC61B7ADC3E96E
+:10FF600090E3A01F3E6E1AF863D16A2BDD3B6AB99D
+:10FF7000D0B882FA29B3F78DAB858C6BFDFA71A7E7
+:10FF80006B41E366F68AF84E8CEBD48DEBA7B86034
+:10FF9000DE1FC59F76C7B81271EE57F96294F3FC65
+:10FFA00043F2772A8A9C7E23E4808A934AB0C8F77A
+:10FFB000B8E5B985D7A3B8CC5DBD629DE79BFD359B
+:10FFC000D84FC5926F175B84DC64867017EE639719
+:10FFD000182F1F4FC6F9E405713E290E2BDD8EFD4B
+:10FFE000D86012FC86C5A9DF4BEB58F6735EEF773D
+:10FFF000F1C9F4FB6243130FB24C9C8F97CFCC81B5
+:020000023000CC
+:10000000DCE07AF719E0FB77AC5513BFC325DACFF4
+:100010009D1941F750BA0F8F28C4FE9913E67C8EC4
+:10002000F17DDB3BE92BDAA773A29D8538F1F41E45
+:10003000FE6F914F703E07FFAE957D45FAB9F2D73E
+:10004000DE12F0D7FE17C6A99F79CE22F4B31E7A2E
+:10005000A7F9BF2789F7E9B8FE4EFA47CF75F2DD59
+:10006000CD1C6721CA53CD3D51805BF7659378B7AE
+:1000700096F544DD14E49F7DAC5DBC671B4AD787D1
+:10008000270B39B03CD34EEF9D35245AAD94B65F63
+:100090009841BF07632ACDC4F9C06DE9DFEEF88B44
+:1000A000C9425EA56DB004FCEF5C7EB8C399CA7B03
+:1000B000D938C6767C3FBCEFFC051163192ECF639F
+:1000C000DEC4C78B4DBAFA6ED4EF2B67E29936D5F2
+:1000D0003EE765FBE3EB4C723CE07989B83F112ABF
+:1000E0002F1AA6C4F6BD57487237CE46F7AE328DEA
+:1000F000D29EC7EB3AC82E28FCB7C9FF61A338BA15
+:100100005D364187990691EE32C8785F69EF53E713
+:10011000981F4FF14C9A3298FAF1533FC6FDB9D06F
+:100120002B92581B8DAFF433558FEB61366232F250
+:10013000F7DE8A8C867EE1F9CEE4A9A5930B41D740
+:100140005EF651909C381F11D5148CBF06A3DEEECD
+:10015000F9CEE469D44EB5AF6F9ACE3EA278443F53
+:10016000D14F7DA681CEAD0D46F62AFDEE00EB20E7
+:100170007FA66AF72EE7931FD1BB0D6E4ADFE3FC23
+:10018000F223BAEF379FD20F9A3DF4FD647335A581
+:100190009DCD8DF4FDC3E6264A6FBE35B200F4BF97
+:1001A000FCD05AF651907CAC6F337B82EFD7BC3BCE
+:1001B000B57F3AFAFE64E1B77937ADFFF2FB55F946
+:1001C0006481CFEEC542CFE474B9CE113BB0BED04E
+:1001D0001D29EE25BC344D9C5FBB9344BE71B278A3
+:1001E0002FD46D60DBD0FEA56916CABF9B6EA077C9
+:1001F0001DDCB1A2DF77B30CA4A75D3F636A03E007
+:10020000E48EE7DFF302F977AF12E5EE21E2BB9A65
+:10021000AF2A9F34A5CF8E9025CEC7C2FFCEE99DD1
+:10022000FAEFC36FB1985F687D759F3E141EBF954E
+:10023000FB96F605F477EC83B4A07DD1E0A47DA114
+:10024000E850D15FC314B15F33C3249D73D945F027
+:10025000830CC3F938C146FE4137FC177C3DBB64B3
+:10026000BCFB15FB41FA03D47E50FB40D17B32DF4F
+:1002700067C2DF21D631C9D8BF9DFEA1C962DD1D8D
+:10028000F191A41F77B79B1D9037938CC2EFD0DDFF
+:100290003EAF00F7C24BEEB637F6C7BFDE94EDFFB8
+:1002A0006938287E30001CAE58BF45DAEDFFC1F535
+:1002B000137F03DF5E2CEE6586D26BFB64657717D8
+:1002C00074FBCE64F741D04FB76633E19CD26DEB3F
+:1002D000FF1EF94BD3C4BE50F4D33085C97768F8FC
+:1002E0003A33AEE4776A3D7DEB5CCA88EF65CA7845
+:1002F000E350FCAA7505F1BDD7270F0EC09331AEB0
+:10030000AFF07E86D6D9E99CAAE8F7FCE0AF96402C
+:100310007ECD9FEC147E268351BE072BE449DF7708
+:10032000CD487157417286416FE9392CFC717E7E50
+:100330004E823F0B36E8E0B86BCB14B1EEDEF985A8
+:1003400006D809CEFFC5EE85DC3A3FA4E724F49237
+:10035000F3DBC47BE7BCC7591AEE8D20FEC789DFEB
+:100360006D117E10E3C35F9E843EB4E46123E92FE8
+:10037000E7716CE6ED963F287EE74EDD1FAC93ED0E
+:100380005AB65DBC997EDF8CD327F49F8F6C0DE944
+:10039000D08BA73FFCE009BCBFBEE4390DE6667612
+:1003A0001476779EFF78AF51FCCEAA8C3B9921EF53
+:1003B000F7D7EC16F7FBEB106F02FDE5C08EADF83A
+:1003C000FDC9FABD6666E3DF67E09D343ECED2B676
+:1003D000487E90E4FD6ED1C78D5ECBBC1B604FAEF6
+:1003E000DEAEFF5EB34B9FAF0BB9B7A84D91BF67B1
+:1003F0003092E5D2FDC42DC25EACF8F695FAAE9708
+:10040000E0EB5EA9EEEB7E41EF7B1B0F7F99FAA13B
+:100410005DE467CB7C17CF9FFB52C05FC1AD41F25B
+:10042000FC7349ACA08DAFAFE1B0CD013B40C30B35
+:10043000C24E70BE2D9AE0BC3CBC93FC0AEC45A3B6
+:10044000037AD83D878C6457A86FB7FD0CBF4BDB90
+:10045000F09C46EFD5D61F0AF309F85C5882F2A546
+:10046000876C0E27CA5F0C63B03F9FE778C3BDD887
+:10047000F3299D847FE0157609FE370BBF5FA1F05D
+:100480006F7C58F893973C21F1B36D9589F0EAD3CE
+:100490005842DA95785278FE95E1A93E3CA1DDF408
+:1004A000877F7F5CE29D21DEE6E8B64AFA5D0C8537
+:1004B0006FCBE18F52A1F72A3C1B399E7FA8DA3B14
+:1004C000E57B785F83E76AE0D9FE8FE3F98F908F51
+:1004D00085A4F77EFC53E8BD9116F2A32BBB86B230
+:1004E0005B0CAE7DF7581C1F7878E2B3A4E796C783
+:1004F0009EA95FC1C88E76ED14D8D1AE7B033FEBC9
+:10050000CB7E77FD53B9A08F167327FD6E8C3746CF
+:10051000BC2BDF9D367BFBF37CBCE2D8AF52F7638C
+:10052000DFBC1C46EE93B9725FE2CF1AFC2E60BBB3
+:100530008DEC6DF5ED61C2BE7640EF3FEB4E12BF24
+:10054000D35762E9295F01BD9CF78771D479B0B6B2
+:100550005DFEFE8B3CBFD52A3BC3BE90F7A11C6F4E
+:1005600050BDBA2922DE36236192137CA86501F3BF
+:1005700084677C1DBF67C4EFD5EFE50DA8070EC0EB
+:10058000F795FEC7BC7A3B87E23F4BE5EF4BF6EDB4
+:100590000F99AF5EEB8DB21A89EEE8DD86BA47C5DA
+:1005A000EF2B7E02BA8B0AD053838C4F3BF6FDDFD4
+:1005B00098F03B4DDDBBC4FD08CE21B7E29EFED9CD
+:1005C00036110F5753D035C6EFC4EF74083EB46CE4
+:1005D0009FE673A6F54347CCB741BC6B1F424FFB68
+:1005E000BEFEDDC37B037C64D4DF393C77943029C5
+:1005F000B7BCFDC64FF6C9AF90DFF1F8DF16CFDD0F
+:100600009BC3D7F335FEC66B13F5EFB85CE7D4FF99
+:100610004ED377B2F5BFD3D46B97F091FAA0D253F3
+:100620000F4D11723C3455F0BDC1A51F479D8BBFC6
+:100630003B4E3FDE6CB77EBC6F8B977F555CEB37D4
+:10064000C1EFB81CF7841CF73772DC7F164E2A1DE9
+:1006500068BCFF5FD3FF0B8D21EA0800800000001B
+:100660001F8B080000000000000BB55B0B7C94D5CD
+:1006700095BFDF7CF3CC7308210904C224242160D8
+:10068000880324542B94C9D300D6065C2D688401BA
+:1006900052C83B80B5D2D6FE3208222F5BA8D1A229
+:1006A000224E82E1A1613B118289863A286411AD14
+:1006B0001B698BFDFD56DCF828F23213A374E55755
+:1006C0005DF6FCCFFD3E321942B5DDDDE4A737E72C
+:1006D000BEBE73CFFB9C7BA929CE317C394588DC1B
+:1006E0009873E69E08215CAB7A8A12B385E87B4357
+:1006F000154D0E2184DB7BBC3E5688DA8EE16253B9
+:1007000032C1257D6F1A00B78DB36FA2F18DED7FD9
+:10071000781BE3BD07558785C65F6BFF280AFB5C26
+:10072000FC325C88E158F7519420B8FAB2C2F02646
+:100730001A77103CAB5515FE4CDACFE83363FC62F8
+:10074000AA0E7BCD82DA929656730FB5557B5B79F4
+:10075000FC0D9F69F0F8DEC641E376CCA7B6CAE887
+:100760008DB2537BBE5DDFCFCFF3AB53159717FD33
+:100770007BFF10B70CF35ADE895B4AED15FCCCBC4D
+:10078000B6FDF4D00B996E5A57D341FB440CEC5391
+:10079000D361D2608977756A6B510CD14BB4282232
+:1007A0008D9A8B62AB584DF4AC6A6FAE16D45F95E0
+:1007B000718F49105D023EB518DFA71F8388A375AE
+:1007C00076FA8BE877D1F779D452DAF755DFB1DBD7
+:1007D0005DD4063A5F8FC2770307697EE6003ED399
+:1007E0005D44BF1CB4662146D0BA83AF4739687CEC
+:1007F000A3EF75496FA39FCFFD9A0607A8653AB787
+:10080000AB7CEE8A2F55A6BFBEDFAD2E95F799D5EE
+:100810009E1689739DF4C9EFCD7539647FEAE23283
+:10082000E07F2261418E9ACC78BB000726CE69DE3C
+:1008300044A854F968DFCC6BE9B654DBB7CB24E6A7
+:10084000FBC0B7D4035DA3483E4E140F9F4C235703
+:10085000E7DDE332F0BC22B33B7505CD3B19E188FF
+:10086000B4D37E0F158F8B045F5F438BFEE25D6612
+:1008700037B59507E5F74EDABBA3206F270F4E5526
+:100880003DCAC07E776ADF15C2C3ED00DF3CCCA74E
+:10089000726F6304F619E09FEC9FEBB2F3FC13DE7A
+:1008A00077EEBA87CE773223DC09BE749945B98FCB
+:1008B000E5843E82EF752636820EFAF7E6821FB493
+:1008C0002E906160BEF6B69BB479F7348B41F34C41
+:1008D000CCB78BCF0DC6C7EEFDE097F7D0FCEA672B
+:1008E0005461A1EE6AD38A389CFF931D83F12BD704
+:1008F000E85C6DF2C7C505C96B75C7557D8960F9A0
+:10090000EED0F5C3C1FCD4F978324395782558BCB4
+:100910008250AE6E6D66B92675F3D8A6702BECD4F6
+:10092000268677272B74FEC407ACCEB584FF738A66
+:10093000366EA03686608384CDD45AA97DC624FB4A
+:10094000A1B6583F86D8A9106C2A1E976348A17D8E
+:10095000D4D6C9E0EBAB335D8FBA088FCD334B668D
+:10096000CC043EA26F99A06FD65C8AF08868210AF9
+:10097000D5F79EC077FB0F9A04EC478DB5A3F263C1
+:1009800092D37E27290AE1DDBFC3E4F5B0FCB9228A
+:100990009469422CBB49EACD270EF734751CCD5F14
+:1009A00063E0F355B7A85E1BCDEBAD271210C93F2E
+:1009B0006D4DFE01E4B5FAB86AB7D2B9F37DC9BF8F
+:1009C0009A0EB8C5E4B4D0FA5A1F75125CBB57F141
+:1009D0003AE4FE027A597313CBBA3863AB4D11591E
+:1009E000D4AEE93363DE99C38A788CE66D0E8B6AE8
+:1009F00002DE3599B3CF2951D4AA5BD627D27ECB5C
+:100A0000B79B3EECB1CAB557E8BFBACE6D2CB7154F
+:100A1000DEC1FD557B07C335C23800D3FECDF8E3F8
+:100A20006621DA5C91B1676EA0BF2788095754D060
+:100A3000697A3CF4E104F84AF2241A88D82385B88C
+:100A40006F92331E7ABFD1E8980D3A043A4D76D0B2
+:100A5000ABEEF0810AE0EDAD0E731AE8A8B5AB5F1E
+:100A600061BA06BE20BADF486D82E0F30784A46F46
+:100A7000A05DCA799D49F15AB19E68C8FB5915EF2E
+:100A80001A1A0A78FAA3D83E09510CBD58B520C7E6
+:100A9000003B07351684CAAF747D506C46251AADED
+:100AA000D4FFEF197BD4614176E23F5D298C7F81D1
+:100AB00059B87DD47F5FA4331A723FD61A9505BC0E
+:100AC000C65A93BCA0FB5863DF1A7C7FF328C5F19C
+:100AD000106D7D24EBE5C90AE0DA0827E4444958A3
+:100AE0006C043D368F5A6C84BC8FB5FB324A32079A
+:100AF000E0028C431F8497BF5714E136E23BCF8D51
+:100B000054FC06DA3F6023FCA02746BB09F8054CDD
+:100B1000121662CD20FCC82231FCFF8E9F9DF08B07
+:100B200018C08FF81D8DF59F67137DA84D9A2B4433
+:100B300037DB85156C17747A5E24792F205EA52922
+:100B4000526EAA771C29C2788DE85E8F754551F2E6
+:100B50001C45380FE030D9AAB9925FB95A7B7FAEF5
+:100B6000F42FBAFDECC8751973A9DD9E5B62465B74
+:100B7000A866C6F70C61EF5729569693CF49FF60D8
+:100B80008FEF5DA1D8533306E45BD7AB3AD97555E7
+:100B90007FAA7EBFCB2C52F0395777068D970BA9D1
+:100BA000D78B56DBECA9C17A043D237A94DB2B6EFC
+:100BB00013A46FEED571F6D4A9D4AF5E340BC89EE2
+:100BC000A65FB1F47B256508FDF285E865FB60D87A
+:100BD0006F9372EE8F54BC6B09FFD4DCC17A97A47B
+:100BE000E941A35BE1F3357E6564D853AA7841F30C
+:100BF0003BA973758C7638CC2BCFF5C23FDE4960AC
+:100C000029FA1B62594F7990ECD7BF68E7BCD3E84B
+:100C10003F02FB71CCE44BB6D3D0B11AAB13FB2F20
+:100C20001014E8905D2B15DDDC9E0AAF6DF3F3E642
+:100C30009E3190AF77DD1627E2B0C6754D91B0E3D7
+:100C400059629DFD4C06820AB1F7CAD4EBC7332422
+:100C500038E28CCE1738628A53C06F9DAFDB735D6C
+:100C600079B939D75F5FF5A7B6DBBF03FB757FB3F3
+:100C7000395E8A4977C6B401BEE97CAD131EC65BF6
+:100C8000E7D755FE11EEA3410FF5E25CB633CFAACC
+:100C900082E30A8D7F56FA1D8A7F3A7D676A7C5807
+:100CA000DE21ED51285F757AFF9036C4F7C98FEECB
+:100CB000607E080BDBBF50BE7F135F28C22CC5507F
+:100CC0007EAC45809F8906691F1397919C10DEF7C3
+:100CD00008F7E11E6AEF0A7FCBC472A8F1E75EF065
+:100CE00087A6BE2BBCDFCF48FEBFE34F476EC903CC
+:100CF000C17A18AA77D7D3B36A87F3DF75BF47964F
+:100D000086F42B443F43F44FE7977B7514EBD9559A
+:100D10003EAA2D525F357E45D0EF90FA863FE87BA4
+:100D200035ED8AD79FFC2DF44F21C4896F8F85E85C
+:100D30009DCE9FEBD91DDD4E9D16FE63763AFFA931
+:100D4000141907787E62F136034E3794C3EE9D9AEC
+:100D500028DB039A7D0B6D4F539CA3901FDB94718E
+:100D60007204FCF529B3BE8FCDDB4CF89F5ED33DFA
+:100D70006625AD3F9D2BDB53880B83605798580445
+:100D8000BB7E7AA4C5033A9D5626E4C13F9C561EFD
+:100D9000B85DC2F16607E005F17976824F99E47C8F
+:100DA000DDAFE8F6FFF482EF14F03C451C053D1C76
+:100DB0008A28E1EF284A4C31E173FAFEB4296BC569
+:100DC000C0F99B720DBCCEABD96FC283E9DEF7537D
+:100DD000C5DB445D8BE05208FFE4BCDF14A750FF85
+:100DE000FB3F1B3719FC75AD1AFC7DF8EBE41B01CA
+:100DF0006FE37DBEF7659F6971905FBAEA270B3E8E
+:100E000093FD653906E84BB9C64357CC8468F0A713
+:100E1000DF3B2E1A7E47F743FDC70F44B883F876B1
+:100E20008EFC94181F044F783429D88F1DD9BD39F2
+:100E30001DFB949B3D594EEA3FDBF87412E28DF2A4
+:100E4000DD8FA4731CBC7B633AF299F2A6CDE92E28
+:100E500086C3DD9C4F19E5B92FECBF79D7A6A0B8A2
+:100E6000BB2A5F65FC4BAD470AE16F67DFF0E9C362
+:100E7000769A97F633C50EF1BA57743F0CFFB81047
+:100E8000F131F2B7062BDB73DACF05FE374FF8FEF0
+:100E900073D0E313191F99CA68DEE55C23D367A1F9
+:100EA000F06E89A771B141B1378BE0F9631A317FD8
+:100EB000F13AC59C003BB062D864D58175C3188FE8
+:100EC000251B2677A17FE183B27FB6C57BF024F690
+:100ED000F98DD9D9EC607B9352326900FFCBB966AA
+:100EE0005EB7688BC2F1BFFE9DB427E21A83CF794B
+:100EF00059E3BFF8CAA2802F3FD0F872DB83EF1C02
+:100F00004DA07DEDB1EE2BB01B6F3F7E26D54FFD82
+:100F10000531E73221E76966F75315387793C589BC
+:100F200073646725AAF1347FCA8F731F43BBE8C17E
+:100F3000C54F55C0DE6EB772DEA6E3B74A711A60C0
+:100F40008F5F6FFCE112D0EDECE3568EDB57358EF0
+:100F50008F1743E8A9DEEE21FE3B28D1D9576FE574
+:100F6000F6857ABB70903CECAF4F60F8B7F50E6E2B
+:100F7000C57C295FABB4FCF87AFB4DFD325C3828A8
+:100F80009ECDDE60130EB2534971AE517974CEB46A
+:100F900089354D1BB573A5D1FAC99EE47CD0217B60
+:100FA000E3CA2E84BCE63C998FBD797243128CF261
+:100FB000F2073FD85941E373F34AC6E551BF75C7FD
+:100FC000675C5778BDE39185A0777993459E4F3B49
+:100FD000F7D9C7D3E39FA2FD3D6F9838DFAFDBF1B0
+:100FE000C1CE8DD42EDDB2D21C2CEFDFF6BCC91AD7
+:100FF0003EDFA457D7A3C33FAE579B93587F9A4871
+:10100000AF32FF79BDAA7B700DD3EF81BC92D9A01E
+:10101000FB59932709FA7476C20C9673CF6185E960
+:10102000AFDB717D7DB176DE2A836FCBF4E4013BCB
+:101030007E4964337D8F747C928EB8F752FB82BFF9
+:101040007BEE43746E3F9DBB9DE8EB1F7FEDF83454
+:10105000B37B9C93CE37CD20E3DD6BE2D63C835649
+:101060002FE83697444A9A2BA8CB68FE93FC982722
+:101070009AF0A9EE54FC6159F067B79E3322DFA3C2
+:10108000BCF1C3E038827E3E0CF2DBD7C3F79BDABB
+:101090005AEC93366077BFF36783F007F9E99B7BDF
+:1010A000C2843FE8BB57F313EA33139F7A3B46B23F
+:1010B0005D00DF8CA8C7754C68027CCE2CF9D87B0C
+:1010C00088E22659C711EAB481739EEBB890053BBC
+:1010D0001B7ADEDA972FB07C54B73FF299C2E79FB4
+:1010E00075CE98F5CDE73FB2FB4216F877CED433F4
+:1010F0000DF956AFB9270B7CA87D45DAF37F940E26
+:101100007A7FC5063A08E979AD62653929542F72AC
+:10111000DDA0F7B8AC1BD476EC627BDADF29EB37C5
+:101120007586EEA278D43B567CD0057BD69F20F303
+:1011300028DADF05BA4D1FA7F941635FD25CB26BB5
+:101140002F5E950799FF9D85FE8EC73EBE6AD8012A
+:1011500091152E10579C873E53FFC2D5C9EB21E74E
+:1011600067BD23A6C03EBE99F5B75AAEF7BD1A6E4D
+:101170005739EEA1DE20FE5D3D875715AE41F58063
+:1011800070E10A9A576776FC80E3E313AA405C5744
+:101190003751EA937859EA53CDBA23E684A0FD7615
+:1011A000429F186F192FCE7EF56FAC975B66BA3AE7
+:1011B000A197E1B085D82F21DAAB28DA3CE27FADE8
+:1011C000864344A796F717AB3C5ED7AE8A915893F7
+:1011D00010E94DA373148BAD46C4D3B3856F3AEABF
+:1011E00036C2D8F3CB5B687CCEABEAD44D82F3A792
+:1011F00045259C57BA5357213E32281A5D7DD97335
+:1012000083FD599EF453D35585FD58DFC8708E5326
+:1012100066CDAF2905BEFABCAC61721EEDC37196F6
+:10122000F0F665CD857EFAFBB2E6450ECCBBEBD57C
+:10123000F015EC17852FFBAEA0EF84E5CBFAE8E7BD
+:10124000E4472027759764BDA350FDEA09C4E7ABC6
+:101250000E93BC203E3424BF6B801D273A83AF170A
+:1012600088AF2EF81FB770B9A03F934678A13F759D
+:10127000FB1561449DA8C3D2843A52ADA9270EF252
+:10128000BCB1FD4F66C8735DDB3B66C724AC977588
+:10129000275248B6E3759AFFAA691FFF2EEA7C35EC
+:1012A000C7A517AD31BEC3F97BD5C156CED3AB852B
+:1012B0009FF3F4EA96C1F2D29FE0E0BA48A87E8498
+:1012C000E53B06E9C5ACED522FEE52C50AD839A16F
+:1012D000D5696725C4733C32B04EC6BB2EF5C2C378
+:1012E000885F02298A53A1AD02619E75888B3CE913
+:1012F000329E09FCEE85EC656C57BCD977D0B902FB
+:101300005ABC3B6BC336A31A84CFAC4E59970C849E
+:1013100089F243CC6FF768F041B84A22F27358AFB4
+:10132000B26057030659470D3D47BD562F3A817AA3
+:1013300052E600DE731213A51D135E969F2E83FCEA
+:10134000BECB40E35306D62FC997EB07F2215907CE
+:10135000BB9E5DD94DFC2923FEEC253EA37D9EFC62
+:101360007119D99916F2C780FF95FC315A5F7D0635
+:10137000F7BF58EF64F860FD4D0C1FAA7731DC5EB3
+:101380005FCCEDCBF525DC7F02A87E17FF7BBA1181
+:10139000F2D0051D1B35009F8A0981470D9E7F2ACB
+:1013A00046190C8F52787E76FED38D1ED48B66DA6A
+:1013B00035FD764422FE3A6B9375A8B33659876A99
+:1013C0001DE5BE259FC6CB66ADDD2DF350573AE631
+:1013D00015C42CE0FCB59FF257D8A395F9EE3CF06C
+:1013E000E5F8F1FCD46D6C276D5C073D75F70DD108
+:1013F0005C077C83F271FA746EC6D475D904E74633
+:10140000282CBF642F6E2CD1F34ADA27BF53DEA3FA
+:1014100014AAD565D87FD548DB54D8DFCF5DEEDB85
+:1014200080874EEFA251CB53110F75991CEFA28EFE
+:10143000EBF9BD49209FD2EB7DFABC0E57EEDD588B
+:10144000372B63DCBA29B03BA464B0732EB36801B8
+:101450005E2E43B8B296ED96C3083B70B726C779A7
+:101460000E1917FBCD0E630CEA3761B9B11E5AD7BE
+:10147000A5F1F9B8C6E7131A9FDF429D8CDAB7A928
+:101480001F6D37F5A39D01FA4A7965BA3D91575210
+:10149000C6F22BFA9200EB75C1D9D02F696F92205A
+:1014A000D75B34F94DD0EC4D576E49955CE7E37D41
+:1014B000AAB47ADB05ED1E443FAFBE6E60BDE07698
+:1014C000DE8DC263859D7F49E69D6234C52304CFCE
+:1014D0007B299EED906ABD23F363D2F37953651E99
+:1014E000200E58E4BC04470EF464AD566FEDF51AB7
+:1014F0003C26D4A763BAD363E07F35FDD2E143FF36
+:10150000ADB2BDAE994230B5AF28F27C35F3BAD357
+:101510008761BD6233707DBB498E9FD4F4AF264591
+:10152000DB4F3B8FB0FA92C08FC0E197929610BC10
+:1015300029C2BF4CDA7D7F3ADB6BE14F9F07BBA826
+:10154000F8DE174E8A2B0BA62E318E043D7C3B0114
+:101550005717E42C31DE8CF1D6F7EDC1E3237C493B
+:101560008A1D70B61C1FD1BA7398330836BDF83E79
+:10157000C6CD869C250504CFB1788FD7436E7E2BD0
+:10158000E5CBB6BFED0CE856D521E3F6BCFD6D17F3
+:101590005F845F6E8B74C2BCEFCB4F667AAFEDD8C1
+:1015A000B305F2D6DB2AEF0336B5FC69E7CF799EA7
+:1015B00005D724B4AF2F5BD077561EFDE362E0352C
+:1015C00027DCF705E0878ECE643CE70C977AFDC8F0
+:1015D000D1BC25D0D3DEB6FD3F81FECD89A68016D5
+:1015E000F8BC60E33A44E5810905D0D3DEC8EE8556
+:1015F000D8BFF6798B13725A79203E0FF58143F9E3
+:10160000B21E5E31716B12FCACE1E57DBB7F8EFBDF
+:10161000D5E76D7C2F541723E3BC4AB571DA4AE64F
+:10162000DFAEDD4F03EF7D36BE9FAD40AD8AE08A71
+:10163000DD695CC77FE5EB8F16820F85EA8EDDE8FA
+:10164000FFE2399B017438697645CF801E9E347164
+:10165000BE59A1C115A7864B7CC27B8A987FB15B1E
+:1016600093E0672B87FFF476E03D47DDBA13F98EF0
+:10167000D863E1BB8973FB886EB4EE5CB3690AB8CA
+:10168000DCBB2FD20879B9A06C5DF814F66F96F325
+:101690002ED8B6323D3DCDE305BE47F304ECD6056A
+:1016A00065DBA0FE73CD7BB2908F9E7F7E0EE7A59B
+:1016B000BAFCEAFA52F99C65905F644B40F6A85276
+:1016C000FB5BD83D2282FC6D85069E3FF464EF53A0
+:1016D0006260FDF91693DF4C34AAB08875D6980184
+:1016E0007DA84CBCB518E7AB3434A6236EA998DAB4
+:1016F000B3107A71CE26AC0934EF4DCD6F551E5C18
+:101700003317F1EFF5F0B9A2D9A34B09D27F5D6A87
+:10171000B77983EF2543DBF7EA85FDADB401F8DE49
+:1017200015168EE1F5FDDE34FBAA91A7D5C648FB60
+:10173000F13ECD6F213BF6B5E6EF16AD1E3CBF3F47
+:101740003F86BF5F6BEE4987FFD3F70FE46B7EC325
+:10175000D8930E7B15BA6E0EC211D8911714B6230A
+:101760009507950F54A253A5D5E355411761D6CFE0
+:1017700069BCA2C87509D334BAD3DA0D05C9FCDD3A
+:10178000CA169BCB46EBAAC27AA210175547F6445D
+:1017900021DEE97D59154D1ABB62E334FEA4682CA5
+:1017A0000BAA3756F84C2E5BD6107C46FC44F396B9
+:1017B000E36FFAFE3305297C9EF2F670FE9EB0F7C9
+:1017C0004C839C96EF18BC0EE7B207E95F6FFBAE47
+:1017D000B8E0BC3C45C33BA07CC07A12F8FAC324F5
+:1017E000F0BDD220D6E1FEF23CADC1BD26C1C22A79
+:1017F00061BEF7ACFC6B4418E4E5FCA56AD6DB5E81
+:10180000A587EDDADB0573D92EF59A7AD8AEBD7EC1
+:10181000F42EB60FBDC37A16C24EBD5DB05C8E8F7E
+:10182000EC59E8A0F1FD3A3C46B0DF7FEF680DDBF4
+:101830008F39AA7C57217699ECB21EB4E1543DE76A
+:1018400017264770FE7DBA40ABF70CF087F32E5D8C
+:101850006F7A8563FF41E8617904D775288E6A79CC
+:1018600011F1DE823827DE6B94639D940373F07D63
+:10187000636CCCE565E0CF1DA3DD450539B8DFEC31
+:10188000E13C82A49AFD4DEDEF2C9C4F064C7DBBB4
+:1018900061A7D247BB6717101ED5E6EEF5D984D2F3
+:1018A00045534F174AE4B355698FC41E2957BD9954
+:1018B000BBE43D8D765F79B7467F41494C23E442D6
+:1018C00091FC7DBDFDC05BB02BBDDDE3D81E87EA7A
+:1018D000CDB9F6C7A2601FFE4C7EDC1394EFFF79F2
+:1018E000F11EBE679D8FF720D42E5937581EFABFC0
+:1018F000BA83F33EB125A81F72D830180E9523C8BD
+:10190000A37F90DDF130DDB76B7A5595D75D0B3A4B
+:101910005C85E711AC06C1AF85C021F345898C1306
+:10192000B6C3FF133DAAC7F84F719EBEDF2460C740
+:10193000D792FF62B82DDC8B7CC5B09FFC53ACF412
+:101940004FF00B5551DD5C9FEA6DB3F07DEF431D09
+:101950009F24E1FC24875C87A9EA78290EF9FB3EE5
+:101960002D5F203F18C7EF63DA3AE29077E8FDD5A4
+:10197000065F3AF0A28888E375BDBF46F5A703FF6E
+:101980002AA53B0BE3FBF2EDDA7C8255C082CF51F6
+:10199000AD487D171D2ADBF350BE3DA9C92BD98563
+:1019A0002C7EDFF1B2AC0FE876A042B327AFA13FA7
+:1019B00053EABD5DBF57A2A515D0F721EC43428184
+:1019C0001E17AFE0FACDE3050E096BEB795F595FA7
+:1019D000E2F1DA572E64A564629D362FD80E8D1B76
+:1019E000B02BD0FF04D6FF874C7174AECA9D8A73AA
+:1019F0002DEC54E99A229A2E961B571671DD4C78DD
+:101A0000386F0BC52B548E2617483A551A8615C6C3
+:101A100006ED779E6C7AC214B6337ED89D1FC53E04
+:101A20005A843AC50F4BE5BB81ABFE2658CF719E59
+:101A30001DD28E436DAE18AE95E3E52B1AD7C70FB6
+:101A40008147289E15EEC6A238C7B5FD3ABEE76DA0
+:101A50003A7E79A611C17498BFA66804B5CBADFFD4
+:101A60002C1DE479CF7758FCF0AB15A52BD7470F89
+:101A70002137D7F8831D41FE2B05FCF5F2FDC6F595
+:101A8000F00F6DAB15FF29D48B04E95533EB17E943
+:101A90004B905FB8B920A4EE50BE782CE26AE15EAC
+:101AA0003C167E86F46AA17388FC920CE42803BF7E
+:101AB00019F1701B8ACF5F0AE4BBA49B0BA49E6F35
+:101AC00099E90AC06ECE500D1C8787EEF765818CB0
+:101AD00027BAE322EFD7DF7380D9335449B74443A1
+:101AE000FFDBD0B7C4B84807EE830AF3C3E5BCC335
+:101AF000363BEA3781C397B9BE1B783862BEBC3724
+:101B000088102369BC2B615253B01FF975A13C6F3B
+:101B100078B68C5BEA324C7FBF3E941979B53EC4EF
+:101B200071436638DF97F4B67FCE7E2BD09963C7BA
+:101B3000BD466F376587A44F755FFF571CFC6B6F01
+:101B4000E75FF81D5AEF579FF0FBB48DDAFBC0D763
+:101B5000DAB5F75DDD8E48F4078A3F2AC2BC4D5ADC
+:101B60003B502790F562BDD5F35FBD1E1094078FE3
+:101B70002E1C3A0F8E714704D7091CF143D55582AC
+:101B8000EB04A969B24E801675825493AC130046DB
+:101B90009D002DEA04E8479D0030EA0480512700AB
+:101BA0008C3A015AD409D0FFC57CF95E2640422CFC
+:101BB000EB97116CDFEF6B56BD88CFEF3B2CEFA19D
+:101BC000EE6B54F89DD645FA3EFCDC35EF750E6A97
+:101BD000EF757CDBF85EAFAE4D75825575A6BE63C2
+:101BE000A8EBD4B52ACE35B02FF5F3F9FB1B3B7328
+:101BF000DE2D457FB3C96970804F97E250AFAAECE4
+:101C00006CE6FA5341FC6133F3B74511A897DE65E2
+:101C100091796E8D4ABD53F83E94E3E01A4B37E755
+:101C20001F557B157B59F07DEE4D9FB11D586B8B79
+:101C30006A029E353E9BBD6C88F71F7C2FEC1057C7
+:101C4000EF9B97C929A226A288EF9B97E19E995AFC
+:101C5000A17E65E4FB634A4C87431EF1AE2A03660E
+:101C6000DD2EF53EE43D556567EBFA4471ED3D34FC
+:101C70002A03E07FE8FDB3BB3032F64C380C859880
+:101C80008CB8A9F8F1B2FD6DF4BDFEAD168E3B56D1
+:101C9000E6BB97438E8E995C5C273976D8C6F9D11E
+:101CA000C7DBC60FAA937CEE725717F2FDFC68AE35
+:101CB0005BAC3229EC97F38BC7C5F3BB81E326F607
+:101CC0003F1DAE925ACC5B35C9C1F5A9428BB89F76
+:101CD000F7D1DE6951CBFA54B856F11A085E2C9C44
+:101CE00066E8CF22221BCB8B296203DE532D12F232
+:101CF0007D832E37ABB6291C1770A1200EF7929268
+:101D0000BE8B3AFFED32DE2F2CB5C8F835D120EF6F
+:101D1000B31337C9F72D3F126E33FCED72F28B68A7
+:101D2000C94FFEAE87FADDE1A393647CEE88C7FE5F
+:101D30008B4F98F8BD6F61FCF7D3DDECAF0BF81D4E
+:101D400083E2BF47BD72C3F5F527F41DC33193B4D9
+:101D50002F4447CE8BBA20975C9F71737BA2BE9CA9
+:101D6000DB1933A59DBEFA2E91786407FEE17DEF65
+:101D7000235F4C8C8F74C2DEE97A7FCDFBC430D9EF
+:101D8000EAEF13C7502B82DE276E713978FF44C308
+:101D9000C9A90ED0E3AF114ED0437FA7B86566C97D
+:101DA0002EF0C915253CF82EEE51B6125D8B701041
+:101DB00005756E9F4B45DDFAB062E777D1D7D8C97C
+:101DC0006D0FE31D4F5DAA62571CA8876F2D8C23F2
+:101DD000BC8B529219EFBA76592F650AC5A19EAEF7
+:101DE000E983CBDD563862A07F8EA617BD345FCA6B
+:101DF000C92D5EC8DBB7A8A33E87F91E6173366B99
+:101E0000F91AF83EE786315C4FD5E5A6BF25BE0935
+:101E100072F346A1F433A5A5EF98100774E5BA8FC5
+:101E2000E2FC0BCB3E7B388ECF37741D8BEC28DF6A
+:101E30004B86D6B174BBBC5BAB83C37E1AB53AABE1
+:101E400051ABB31AB53AAB51ABB31AB53AAB51ABD0
+:101E5000B31AB53AAB51ABB31AB53AAB91EB772B9A
+:101E6000B87DBB7E35B7DDF51E1E0FB2FFEF5DC737
+:101E7000FE87D6413FC2BCD03AA8B03AA2D98F92D1
+:101E80007ECBFA7348DDB378F8920D44BFFC06B3FD
+:101E9000135D7A1D14EF97EF8B607B70B170C8FAF9
+:101EA000A74EB708AE97F60BDB14D03F2F639CD13B
+:101EB00040E37FD5F8A0D71FA11F381FF4032DF4EE
+:101EC000C39836A01FCF984985B3A5BFF7B0BFB759
+:101ED000315FD7AF21FB41F052611F643F2E86D89E
+:101EE0000F4A3CEE061ECB3AE5BB26FDFD661E35CD
+:101EF0005F4E19C29EF8A43D1913E6DB87EF8CA94B
+:101F00000DE3F7C1C7B4F758C736CA777165A28425
+:101F1000BF3B845D89023F960EEF7BFF699ABF74D9
+:101F20007304C72DEB472E9BF6BFB12B9F150AA656
+:101F3000DB6FEAFD951F132E056152FE0ACC2203CA
+:101F4000F735C210C67A50A86E51703FBAEA5E31BA
+:101F5000197C2EB094EC009EF1DAFDB688D5EAAD7E
+:101F6000C6EE8A3D049F8C4B74E25E6B74C2218185
+:101F7000F74F8575C599B08BFE31EE09453978BFAD
+:101F8000BC55C1FAF04C79FE3B8AC39B205781C3F4
+:101F9000E373C0EF7916471BEA00CEA284A5C8F30D
+:101FA000E7453B72500770768D9270BCA34D71224D
+:101FB000944D585AC0EFCFAC5B3FB6E2DD9A22A2F7
+:101FC000E95C9661EE1C7CA7A6F85399378B3EF628
+:101FD000633717C9FC6BC46BC28F7BABBE59917C56
+:101FE0007F26321D3918A7B8F2BB45241F7FFC9EFF
+:101FF000EB16AC4FD4F08CC72DA20AAE76DBD09E88
+:10200000D0EEF3BA0CEE52B445511E23F71BBCD9E7
+:1020100068DF34F87E8C7E92E722EC57F4D8E489AE
+:102020001904275A7C6C273B5CAE5BB1FFAB335D78
+:10203000C5180FAD9F83B7C8F3099FDB302FF41D80
+:1020400096CECFA54552EECB8AA4FD98BE56DEC7EC
+:1020500086F2BDACC8A0D9B7BF8F37E15B8AEFE984
+:10206000F88BAD8BB3810FE17B2FF0247C17625C82
+:1020700044C470BDE3FA72E6E1EF951549F9227B9D
+:1020800056F5B1B467DCA61BBDC3103F8EFA857749
+:1020900018F01DD5D867C3BFC378D6D367837F7FB9
+:1020A000F6C13E1BFA9F75C977D2A1FB3716C9F757
+:1020B00013E9D3FB78FD58FA5637C7E97DC31047BB
+:1020C000A5977FBC5EDEBB64B07F19ABF997B1BF4B
+:1020D0004869EF21791BFB6434DF6F8B82581EAF98
+:1020E000B44A3DADFC45D9A1366AC76F277C83E26F
+:1020F000AF095EC27B505C64EC97EF2D09069DF63C
+:102100009A1886CC22BEAA11F2BDE528CD6E206EAB
+:102110002B25BB50537EF432BF03C07AEC8F3B5B60
+:10212000C85FBB49C2E4AE918F2E9FBFA68BF3C39D
+:10213000ED57FBB57CB3753DF2678ADF06F5579620
+:102140001DE982BFA9DA3BB8BF66C5679CC752FCD0
+:1021500036A8FFDE1F7FC0EF6CEADA07F7137F9F18
+:10216000029F75FE1E33F92620DF3B5613E694FFCF
+:102170007EC0B712FADE541DC1EF6777FD3A8FE5D6
+:1021800046E737AD6FFA76F2B196E77BF24406F494
+:10219000E19BDA5ED8A7B441F6C9C375BED9916C8C
+:1021A00077EAB4FCAAB6CCCE7E3EB1D6CAF6AB5026
+:1021B0000D7302AE354A3B238A55CD4EF958FF4F79
+:1021C000DE3E8CEB797C00C03193F8DD71DC5A097E
+:1021D000F78DB0B07D28349454EFA1F6A86105DBEB
+:1021E0008104BCB824BE3F03FBA0427F655DB5CE31
+:1021F000EC53E4FDBE2307F9AE7EDFD4B0D1DB7A29
+:1022000010F9B2E27D7219EA8A7746F0FD4100F5D5
+:10221000463A4FC33069471B16A4B31F088892D2B1
+:10222000958843E68771FDB16198E351DC27365408
+:102230004CE438FAD07F4BBFDB37D7EA441CD530AB
+:10224000D9B106EF551A7EE1E0F15714B99FE75175
+:10225000499F86B9F2FC0D15319CF7E87C686874DB
+:102260008DC4FDD4CC31EEFF00DF4769F7730DC993
+:10227000D44FED134AC9821F619F4912DF19331DE4
+:10228000AC77C7164C7C74B783DD891FF74475B3F0
+:102290002307E5C5FF033C759D8B10370000000048
+:1022A0000000000000000000050207000000000020
+:00000001FF
diff --git a/fs/Kconfig b/fs/Kconfig
index d4bf8caad8d0..3fd92d66b5ef 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -135,7 +135,7 @@ config TMPFS_POSIX_ACL
config HUGETLBFS
bool "HugeTLB file system support"
- depends on X86 || IA64 || PPC64 || SPARC64 || (SUPERH && MMU) || \
+ depends on X86 || IA64 || PPC_BOOK3S_64 || SPARC64 || \
(S390 && 64BIT) || SYS_SUPPORTS_HUGETLBFS || BROKEN
help
hugetlbfs is a filesystem backing for HugeTLB pages, based on
@@ -234,6 +234,7 @@ config NFS_COMMON
source "net/sunrpc/Kconfig"
source "fs/smbfs/Kconfig"
+source "fs/ceph/Kconfig"
source "fs/cifs/Kconfig"
source "fs/ncpfs/Kconfig"
source "fs/coda/Kconfig"
diff --git a/fs/Makefile b/fs/Makefile
index af6d04700d9c..5ef73a0a9f25 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -124,3 +124,4 @@ obj-$(CONFIG_OCFS2_FS) += ocfs2/
obj-$(CONFIG_BTRFS_FS) += btrfs/
obj-$(CONFIG_GFS2_FS) += gfs2/
obj-$(CONFIG_EXOFS_FS) += exofs/
+obj-$(CONFIG_CEPH_FS) += ceph/
diff --git a/fs/afs/write.c b/fs/afs/write.c
index c63a3c8beb73..5e15a21dbf9f 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -671,7 +671,6 @@ ssize_t afs_file_write(struct kiocb *iocb, const struct iovec *iov,
struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
ssize_t result;
size_t count = iov_length(iov, nr_segs);
- int ret;
_enter("{%x.%u},{%zu},%lu,",
vnode->fid.vid, vnode->fid.vnode, count, nr_segs);
@@ -691,13 +690,6 @@ ssize_t afs_file_write(struct kiocb *iocb, const struct iovec *iov,
return result;
}
- /* return error values for O_SYNC and IS_SYNC() */
- if (IS_SYNC(&vnode->vfs_inode) || iocb->ki_filp->f_flags & O_SYNC) {
- ret = afs_fsync(iocb->ki_filp, dentry, 1);
- if (ret < 0)
- result = ret;
- }
-
_leave(" = %zd", result);
return result;
}
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 06550affbd27..77f759302e12 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -909,7 +909,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
unsigned long last_index;
int will_write;
- will_write = ((file->f_flags & O_SYNC) || IS_SYNC(inode) ||
+ will_write = ((file->f_flags & O_DSYNC) || IS_SYNC(inode) ||
(file->f_flags & O_DIRECT));
nrptrs = min((count + PAGE_CACHE_SIZE - 1) / PAGE_CACHE_SIZE,
@@ -1076,7 +1076,7 @@ out_nolock:
if (err)
num_written = err;
- if ((file->f_flags & O_SYNC) || IS_SYNC(inode)) {
+ if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) {
trans = btrfs_start_transaction(root, 1);
ret = btrfs_log_dentry_safe(trans, root,
file->f_dentry);
diff --git a/fs/ceph/Kconfig b/fs/ceph/Kconfig
new file mode 100644
index 000000000000..bc1fbd956187
--- /dev/null
+++ b/fs/ceph/Kconfig
@@ -0,0 +1,26 @@
+config CEPH_FS
+ tristate "Ceph distributed file system (EXPERIMENTAL)"
+ depends on INET && EXPERIMENTAL
+ select LIBCRC32C
+ help
+ Choose Y or M here to include support for mounting the
+ experimental Ceph distributed file system. Ceph is an extremely
+ scalable file system designed to provide high performance,
+ reliable access to petabytes of storage.
+
+ More information at http://ceph.newdream.net/.
+
+ If unsure, say N.
+
+config CEPH_FS_PRETTYDEBUG
+ bool "Include file:line in ceph debug output"
+ depends on CEPH_FS
+ default n
+ help
+ If you say Y here, debug output will include a filename and
+ line to aid debugging. This icnreases kernel size and slows
+ execution slightly when debug call sites are enabled (e.g.,
+ via CONFIG_DYNAMIC_DEBUG).
+
+ If unsure, say N.
+
diff --git a/fs/ceph/Makefile b/fs/ceph/Makefile
new file mode 100644
index 000000000000..7da6d69dba29
--- /dev/null
+++ b/fs/ceph/Makefile
@@ -0,0 +1,36 @@
+#
+# Makefile for CEPH filesystem.
+#
+
+ifneq ($(KERNELRELEASE),)
+
+obj-$(CONFIG_CEPH_FS) += ceph.o
+
+ceph-objs := super.o inode.o dir.o file.o addr.o ioctl.o \
+ export.o caps.o snap.o xattr.o \
+ messenger.o msgpool.o buffer.o \
+ mds_client.o mdsmap.o \
+ mon_client.o \
+ osd_client.o osdmap.o crush/crush.o crush/mapper.o \
+ debugfs.o \
+ ceph_fs.o ceph_strings.o ceph_frag.o
+
+else
+#Otherwise we were called directly from the command
+# line; invoke the kernel build system.
+
+KERNELDIR ?= /lib/modules/$(shell uname -r)/build
+PWD := $(shell pwd)
+
+default: all
+
+all:
+ $(MAKE) -C $(KERNELDIR) M=$(PWD) CONFIG_CEPH_FS=m modules
+
+modules_install:
+ $(MAKE) -C $(KERNELDIR) M=$(PWD) CONFIG_CEPH_FS=m modules_install
+
+clean:
+ $(MAKE) -C $(KERNELDIR) M=$(PWD) clean
+
+endif
diff --git a/fs/ceph/README b/fs/ceph/README
new file mode 100644
index 000000000000..231a1df5eafe
--- /dev/null
+++ b/fs/ceph/README
@@ -0,0 +1,17 @@
+#
+# The following files are shared by (and manually synchronized
+# between) the Ceph userland and kernel client.
+#
+# userland kernel
+src/include/ceph_fs.h fs/ceph/ceph_fs.h
+src/include/ceph_fs.cc fs/ceph/ceph_fs.c
+src/include/msgr.h fs/ceph/msgr.h
+src/include/rados.h fs/ceph/rados.h
+src/include/ceph_strings.cc fs/ceph/ceph_strings.c
+src/include/ceph_frag.h fs/ceph/ceph_frag.h
+src/include/ceph_frag.cc fs/ceph/ceph_frag.c
+src/crush/crush.c fs/ceph/crush/crush.c
+src/crush/crush.h fs/ceph/crush/crush.h
+src/crush/mapper.c fs/ceph/crush/mapper.c
+src/crush/mapper.h fs/ceph/crush/mapper.h
+src/crush/hash.h fs/ceph/crush/hash.h
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
new file mode 100644
index 000000000000..c7d673ffe023
--- /dev/null
+++ b/fs/ceph/addr.c
@@ -0,0 +1,1115 @@
+#include "ceph_debug.h"
+
+#include <linux/backing-dev.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/writeback.h> /* generic_writepages */
+#include <linux/pagevec.h>
+#include <linux/task_io_accounting_ops.h>
+
+#include "super.h"
+#include "osd_client.h"
+
+/*
+ * Ceph address space ops.
+ *
+ * There are a few funny things going on here.
+ *
+ * The page->private field is used to reference a struct
+ * ceph_snap_context for _every_ dirty page. This indicates which
+ * snapshot the page was logically dirtied in, and thus which snap
+ * context needs to be associated with the osd write during writeback.
+ *
+ * Similarly, struct ceph_inode_info maintains a set of counters to
+ * count dirty pages on the inode. In the absense of snapshots,
+ * i_wrbuffer_ref == i_wrbuffer_ref_head == the dirty page count.
+ *
+ * When a snapshot is taken (that is, when the client receives
+ * notification that a snapshot was taken), each inode with caps and
+ * with dirty pages (dirty pages implies there is a cap) gets a new
+ * ceph_cap_snap in the i_cap_snaps list (which is sorted in ascending
+ * order, new snaps go to the tail). The i_wrbuffer_ref_head count is
+ * moved to capsnap->dirty. (Unless a sync write is currently in
+ * progress. In that case, the capsnap is said to be "pending", new
+ * writes cannot start, and the capsnap isn't "finalized" until the
+ * write completes (or fails) and a final size/mtime for the inode for
+ * that snap can be settled upon.) i_wrbuffer_ref_head is reset to 0.
+ *
+ * On writeback, we must submit writes to the osd IN SNAP ORDER. So,
+ * we look for the first capsnap in i_cap_snaps and write out pages in
+ * that snap context _only_. Then we move on to the next capsnap,
+ * eventually reaching the "live" or "head" context (i.e., pages that
+ * are not yet snapped) and are writing the most recently dirtied
+ * pages.
+ *
+ * Invalidate and so forth must take care to ensure the dirty page
+ * accounting is preserved.
+ */
+
+
+/*
+ * Dirty a page. Optimistically adjust accounting, on the assumption
+ * that we won't race with invalidate. If we do, readjust.
+ */
+static int ceph_set_page_dirty(struct page *page)
+{
+ struct address_space *mapping = page->mapping;
+ struct inode *inode;
+ struct ceph_inode_info *ci;
+ int undo = 0;
+ struct ceph_snap_context *snapc;
+
+ if (unlikely(!mapping))
+ return !TestSetPageDirty(page);
+
+ if (TestSetPageDirty(page)) {
+ dout("%p set_page_dirty %p idx %lu -- already dirty\n",
+ mapping->host, page, page->index);
+ return 0;
+ }
+
+ inode = mapping->host;
+ ci = ceph_inode(inode);
+
+ /*
+ * Note that we're grabbing a snapc ref here without holding
+ * any locks!
+ */
+ snapc = ceph_get_snap_context(ci->i_snap_realm->cached_context);
+
+ /* dirty the head */
+ spin_lock(&inode->i_lock);
+ if (ci->i_wrbuffer_ref_head == 0)
+ ci->i_head_snapc = ceph_get_snap_context(snapc);
+ ++ci->i_wrbuffer_ref_head;
+ if (ci->i_wrbuffer_ref == 0)
+ igrab(inode);
+ ++ci->i_wrbuffer_ref;
+ dout("%p set_page_dirty %p idx %lu head %d/%d -> %d/%d "
+ "snapc %p seq %lld (%d snaps)\n",
+ mapping->host, page, page->index,
+ ci->i_wrbuffer_ref-1, ci->i_wrbuffer_ref_head-1,
+ ci->i_wrbuffer_ref, ci->i_wrbuffer_ref_head,
+ snapc, snapc->seq, snapc->num_snaps);
+ spin_unlock(&inode->i_lock);
+
+ /* now adjust page */
+ spin_lock_irq(&mapping->tree_lock);
+ if (page->mapping) { /* Race with truncate? */
+ WARN_ON_ONCE(!PageUptodate(page));
+
+ if (mapping_cap_account_dirty(mapping)) {
+ __inc_zone_page_state(page, NR_FILE_DIRTY);
+ __inc_bdi_stat(mapping->backing_dev_info,
+ BDI_RECLAIMABLE);
+ task_io_account_write(PAGE_CACHE_SIZE);
+ }
+ radix_tree_tag_set(&mapping->page_tree,
+ page_index(page), PAGECACHE_TAG_DIRTY);
+
+ /*
+ * Reference snap context in page->private. Also set
+ * PagePrivate so that we get invalidatepage callback.
+ */
+ page->private = (unsigned long)snapc;
+ SetPagePrivate(page);
+ } else {
+ dout("ANON set_page_dirty %p (raced truncate?)\n", page);
+ undo = 1;
+ }
+
+ spin_unlock_irq(&mapping->tree_lock);
+
+ if (undo)
+ /* whoops, we failed to dirty the page */
+ ceph_put_wrbuffer_cap_refs(ci, 1, snapc);
+
+ __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+
+ BUG_ON(!PageDirty(page));
+ return 1;
+}
+
+/*
+ * If we are truncating the full page (i.e. offset == 0), adjust the
+ * dirty page counters appropriately. Only called if there is private
+ * data on the page.
+ */
+static void ceph_invalidatepage(struct page *page, unsigned long offset)
+{
+ struct inode *inode = page->mapping->host;
+ struct ceph_inode_info *ci;
+ struct ceph_snap_context *snapc = (void *)page->private;
+
+ BUG_ON(!PageLocked(page));
+ BUG_ON(!page->private);
+ BUG_ON(!PagePrivate(page));
+ BUG_ON(!page->mapping);
+
+ /*
+ * We can get non-dirty pages here due to races between
+ * set_page_dirty and truncate_complete_page; just spit out a
+ * warning, in case we end up with accounting problems later.
+ */
+ if (!PageDirty(page))
+ pr_err("%p invalidatepage %p page not dirty\n", inode, page);
+
+ if (offset == 0)
+ ClearPageChecked(page);
+
+ ci = ceph_inode(inode);
+ if (offset == 0) {
+ dout("%p invalidatepage %p idx %lu full dirty page %lu\n",
+ inode, page, page->index, offset);
+ ceph_put_wrbuffer_cap_refs(ci, 1, snapc);
+ ceph_put_snap_context(snapc);
+ page->private = 0;
+ ClearPagePrivate(page);
+ } else {
+ dout("%p invalidatepage %p idx %lu partial dirty page\n",
+ inode, page, page->index);
+ }
+}
+
+/* just a sanity check */
+static int ceph_releasepage(struct page *page, gfp_t g)
+{
+ struct inode *inode = page->mapping ? page->mapping->host : NULL;
+ dout("%p releasepage %p idx %lu\n", inode, page, page->index);
+ WARN_ON(PageDirty(page));
+ WARN_ON(page->private);
+ WARN_ON(PagePrivate(page));
+ return 0;
+}
+
+/*
+ * read a single page, without unlocking it.
+ */
+static int readpage_nounlock(struct file *filp, struct page *page)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_osd_client *osdc = &ceph_inode_to_client(inode)->osdc;
+ int err = 0;
+ u64 len = PAGE_CACHE_SIZE;
+
+ dout("readpage inode %p file %p page %p index %lu\n",
+ inode, filp, page, page->index);
+ err = ceph_osdc_readpages(osdc, ceph_vino(inode), &ci->i_layout,
+ page->index << PAGE_CACHE_SHIFT, &len,
+ ci->i_truncate_seq, ci->i_truncate_size,
+ &page, 1);
+ if (err == -ENOENT)
+ err = 0;
+ if (err < 0) {
+ SetPageError(page);
+ goto out;
+ } else if (err < PAGE_CACHE_SIZE) {
+ /* zero fill remainder of page */
+ zero_user_segment(page, err, PAGE_CACHE_SIZE);
+ }
+ SetPageUptodate(page);
+
+out:
+ return err < 0 ? err : 0;
+}
+
+static int ceph_readpage(struct file *filp, struct page *page)
+{
+ int r = readpage_nounlock(filp, page);
+ unlock_page(page);
+ return r;
+}
+
+/*
+ * Build a vector of contiguous pages from the provided page list.
+ */
+static struct page **page_vector_from_list(struct list_head *page_list,
+ unsigned *nr_pages)
+{
+ struct page **pages;
+ struct page *page;
+ int next_index, contig_pages = 0;
+
+ /* build page vector */
+ pages = kmalloc(sizeof(*pages) * *nr_pages, GFP_NOFS);
+ if (!pages)
+ return ERR_PTR(-ENOMEM);
+
+ BUG_ON(list_empty(page_list));
+ next_index = list_entry(page_list->prev, struct page, lru)->index;
+ list_for_each_entry_reverse(page, page_list, lru) {
+ if (page->index == next_index) {
+ dout("readpages page %d %p\n", contig_pages, page);
+ pages[contig_pages] = page;
+ contig_pages++;
+ next_index++;
+ } else {
+ break;
+ }
+ }
+ *nr_pages = contig_pages;
+ return pages;
+}
+
+/*
+ * Read multiple pages. Leave pages we don't read + unlock in page_list;
+ * the caller (VM) cleans them up.
+ */
+static int ceph_readpages(struct file *file, struct address_space *mapping,
+ struct list_head *page_list, unsigned nr_pages)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_osd_client *osdc = &ceph_inode_to_client(inode)->osdc;
+ int rc = 0;
+ struct page **pages;
+ struct pagevec pvec;
+ loff_t offset;
+ u64 len;
+
+ dout("readpages %p file %p nr_pages %d\n",
+ inode, file, nr_pages);
+
+ pages = page_vector_from_list(page_list, &nr_pages);
+ if (IS_ERR(pages))
+ return PTR_ERR(pages);
+
+ /* guess read extent */
+ offset = pages[0]->index << PAGE_CACHE_SHIFT;
+ len = nr_pages << PAGE_CACHE_SHIFT;
+ rc = ceph_osdc_readpages(osdc, ceph_vino(inode), &ci->i_layout,
+ offset, &len,
+ ci->i_truncate_seq, ci->i_truncate_size,
+ pages, nr_pages);
+ if (rc == -ENOENT)
+ rc = 0;
+ if (rc < 0)
+ goto out;
+
+ /* set uptodate and add to lru in pagevec-sized chunks */
+ pagevec_init(&pvec, 0);
+ for (; !list_empty(page_list) && len > 0;
+ rc -= PAGE_CACHE_SIZE, len -= PAGE_CACHE_SIZE) {
+ struct page *page =
+ list_entry(page_list->prev, struct page, lru);
+
+ list_del(&page->lru);
+
+ if (rc < (int)PAGE_CACHE_SIZE) {
+ /* zero (remainder of) page */
+ int s = rc < 0 ? 0 : rc;
+ zero_user_segment(page, s, PAGE_CACHE_SIZE);
+ }
+
+ if (add_to_page_cache(page, mapping, page->index, GFP_NOFS)) {
+ page_cache_release(page);
+ dout("readpages %p add_to_page_cache failed %p\n",
+ inode, page);
+ continue;
+ }
+ dout("readpages %p adding %p idx %lu\n", inode, page,
+ page->index);
+ flush_dcache_page(page);
+ SetPageUptodate(page);
+ unlock_page(page);
+ if (pagevec_add(&pvec, page) == 0)
+ pagevec_lru_add_file(&pvec); /* add to lru */
+ }
+ pagevec_lru_add_file(&pvec);
+ rc = 0;
+
+out:
+ kfree(pages);
+ return rc;
+}
+
+/*
+ * Get ref for the oldest snapc for an inode with dirty data... that is, the
+ * only snap context we are allowed to write back.
+ *
+ * Caller holds i_lock.
+ */
+static struct ceph_snap_context *__get_oldest_context(struct inode *inode,
+ u64 *snap_size)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_snap_context *snapc = NULL;
+ struct ceph_cap_snap *capsnap = NULL;
+
+ list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) {
+ dout(" cap_snap %p snapc %p has %d dirty pages\n", capsnap,
+ capsnap->context, capsnap->dirty_pages);
+ if (capsnap->dirty_pages) {
+ snapc = ceph_get_snap_context(capsnap->context);
+ if (snap_size)
+ *snap_size = capsnap->size;
+ break;
+ }
+ }
+ if (!snapc && ci->i_snap_realm) {
+ snapc = ceph_get_snap_context(ci->i_snap_realm->cached_context);
+ dout(" head snapc %p has %d dirty pages\n",
+ snapc, ci->i_wrbuffer_ref_head);
+ }
+ return snapc;
+}
+
+static struct ceph_snap_context *get_oldest_context(struct inode *inode,
+ u64 *snap_size)
+{
+ struct ceph_snap_context *snapc = NULL;
+
+ spin_lock(&inode->i_lock);
+ snapc = __get_oldest_context(inode, snap_size);
+ spin_unlock(&inode->i_lock);
+ return snapc;
+}
+
+/*
+ * Write a single page, but leave the page locked.
+ *
+ * If we get a write error, set the page error bit, but still adjust the
+ * dirty page accounting (i.e., page is no longer dirty).
+ */
+static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
+{
+ struct inode *inode;
+ struct ceph_inode_info *ci;
+ struct ceph_osd_client *osdc;
+ loff_t page_off = page->index << PAGE_CACHE_SHIFT;
+ int len = PAGE_CACHE_SIZE;
+ loff_t i_size;
+ int err = 0;
+ struct ceph_snap_context *snapc;
+ u64 snap_size = 0;
+
+ dout("writepage %p idx %lu\n", page, page->index);
+
+ if (!page->mapping || !page->mapping->host) {
+ dout("writepage %p - no mapping\n", page);
+ return -EFAULT;
+ }
+ inode = page->mapping->host;
+ ci = ceph_inode(inode);
+ osdc = &ceph_inode_to_client(inode)->osdc;
+
+ /* verify this is a writeable snap context */
+ snapc = (void *)page->private;
+ if (snapc == NULL) {
+ dout("writepage %p page %p not dirty?\n", inode, page);
+ goto out;
+ }
+ if (snapc != get_oldest_context(inode, &snap_size)) {
+ dout("writepage %p page %p snapc %p not writeable - noop\n",
+ inode, page, (void *)page->private);
+ /* we should only noop if called by kswapd */
+ WARN_ON((current->flags & PF_MEMALLOC) == 0);
+ goto out;
+ }
+
+ /* is this a partial page at end of file? */
+ if (snap_size)
+ i_size = snap_size;
+ else
+ i_size = i_size_read(inode);
+ if (i_size < page_off + len)
+ len = i_size - page_off;
+
+ dout("writepage %p page %p index %lu on %llu~%u\n",
+ inode, page, page->index, page_off, len);
+
+ set_page_writeback(page);
+ err = ceph_osdc_writepages(osdc, ceph_vino(inode),
+ &ci->i_layout, snapc,
+ page_off, len,
+ ci->i_truncate_seq, ci->i_truncate_size,
+ &inode->i_mtime,
+ &page, 1, 0, 0, true);
+ if (err < 0) {
+ dout("writepage setting page/mapping error %d %p\n", err, page);
+ SetPageError(page);
+ mapping_set_error(&inode->i_data, err);
+ if (wbc)
+ wbc->pages_skipped++;
+ } else {
+ dout("writepage cleaned page %p\n", page);
+ err = 0; /* vfs expects us to return 0 */
+ }
+ page->private = 0;
+ ClearPagePrivate(page);
+ end_page_writeback(page);
+ ceph_put_wrbuffer_cap_refs(ci, 1, snapc);
+ ceph_put_snap_context(snapc);
+out:
+ return err;
+}
+
+static int ceph_writepage(struct page *page, struct writeback_control *wbc)
+{
+ int err = writepage_nounlock(page, wbc);
+ unlock_page(page);
+ return err;
+}
+
+
+/*
+ * lame release_pages helper. release_pages() isn't exported to
+ * modules.
+ */
+static void ceph_release_pages(struct page **pages, int num)
+{
+ struct pagevec pvec;
+ int i;
+
+ pagevec_init(&pvec, 0);
+ for (i = 0; i < num; i++) {
+ if (pagevec_add(&pvec, pages[i]) == 0)
+ pagevec_release(&pvec);
+ }
+ pagevec_release(&pvec);
+}
+
+
+/*
+ * async writeback completion handler.
+ *
+ * If we get an error, set the mapping error bit, but not the individual
+ * page error bits.
+ */
+static void writepages_finish(struct ceph_osd_request *req,
+ struct ceph_msg *msg)
+{
+ struct inode *inode = req->r_inode;
+ struct ceph_osd_reply_head *replyhead;
+ struct ceph_osd_op *op;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ unsigned wrote;
+ loff_t offset = req->r_pages[0]->index << PAGE_CACHE_SHIFT;
+ struct page *page;
+ int i;
+ struct ceph_snap_context *snapc = req->r_snapc;
+ struct address_space *mapping = inode->i_mapping;
+ struct writeback_control *wbc = req->r_wbc;
+ __s32 rc = -EIO;
+ u64 bytes = 0;
+
+ /* parse reply */
+ replyhead = msg->front.iov_base;
+ WARN_ON(le32_to_cpu(replyhead->num_ops) == 0);
+ op = (void *)(replyhead + 1);
+ rc = le32_to_cpu(replyhead->result);
+ bytes = le64_to_cpu(op->extent.length);
+
+ if (rc >= 0) {
+ wrote = (bytes + (offset & ~PAGE_CACHE_MASK) + ~PAGE_CACHE_MASK)
+ >> PAGE_CACHE_SHIFT;
+ WARN_ON(wrote != req->r_num_pages);
+ } else {
+ wrote = 0;
+ mapping_set_error(mapping, rc);
+ }
+ dout("writepages_finish %p rc %d bytes %llu wrote %d (pages)\n",
+ inode, rc, bytes, wrote);
+
+ /* clean all pages */
+ for (i = 0; i < req->r_num_pages; i++) {
+ page = req->r_pages[i];
+ BUG_ON(!page);
+ WARN_ON(!PageUptodate(page));
+
+ if (i >= wrote) {
+ dout("inode %p skipping page %p\n", inode, page);
+ wbc->pages_skipped++;
+ }
+ page->private = 0;
+ ClearPagePrivate(page);
+ ceph_put_snap_context(snapc);
+ dout("unlocking %d %p\n", i, page);
+ end_page_writeback(page);
+ unlock_page(page);
+ }
+ dout("%p wrote+cleaned %d pages\n", inode, wrote);
+ ceph_put_wrbuffer_cap_refs(ci, req->r_num_pages, snapc);
+
+ ceph_release_pages(req->r_pages, req->r_num_pages);
+ if (req->r_pages_from_pool)
+ mempool_free(req->r_pages,
+ ceph_client(inode->i_sb)->wb_pagevec_pool);
+ else
+ kfree(req->r_pages);
+ ceph_osdc_put_request(req);
+}
+
+/*
+ * allocate a page vec, either directly, or if necessary, via a the
+ * mempool. we avoid the mempool if we can because req->r_num_pages
+ * may be less than the maximum write size.
+ */
+static void alloc_page_vec(struct ceph_client *client,
+ struct ceph_osd_request *req)
+{
+ req->r_pages = kmalloc(sizeof(struct page *) * req->r_num_pages,
+ GFP_NOFS);
+ if (!req->r_pages) {
+ req->r_pages = mempool_alloc(client->wb_pagevec_pool, GFP_NOFS);
+ req->r_pages_from_pool = 1;
+ WARN_ON(!req->r_pages);
+ }
+}
+
+/*
+ * initiate async writeback
+ */
+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_client *client = ceph_inode_to_client(inode);
+ pgoff_t index, start, end;
+ int range_whole = 0;
+ int should_loop = 1;
+ pgoff_t max_pages = 0, max_pages_ever = 0;
+ struct ceph_snap_context *snapc = NULL, *last_snapc = NULL;
+ struct pagevec pvec;
+ int done = 0;
+ int rc = 0;
+ unsigned wsize = 1 << inode->i_blkbits;
+ struct ceph_osd_request *req = NULL;
+ int do_sync;
+ u64 snap_size = 0;
+
+ /*
+ * Include a 'sync' in the OSD request if this is a data
+ * integrity write (e.g., O_SYNC write or fsync()), or if our
+ * cap is being revoked.
+ */
+ do_sync = wbc->sync_mode == WB_SYNC_ALL;
+ if (ceph_caps_revoking(ci, CEPH_CAP_FILE_BUFFER))
+ do_sync = 1;
+ dout("writepages_start %p dosync=%d (mode=%s)\n",
+ inode, do_sync,
+ wbc->sync_mode == WB_SYNC_NONE ? "NONE" :
+ (wbc->sync_mode == WB_SYNC_ALL ? "ALL" : "HOLD"));
+
+ client = ceph_inode_to_client(inode);
+ if (client->mount_state == CEPH_MOUNT_SHUTDOWN) {
+ pr_warning("writepage_start %p on forced umount\n", inode);
+ return -EIO; /* we're in a forced umount, don't write! */
+ }
+ if (client->mount_args.wsize && client->mount_args.wsize < wsize)
+ wsize = client->mount_args.wsize;
+ if (wsize < PAGE_CACHE_SIZE)
+ wsize = PAGE_CACHE_SIZE;
+ max_pages_ever = wsize >> PAGE_CACHE_SHIFT;
+
+ 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 */
+ end = -1;
+ dout(" cyclic, start at %lu\n", start);
+ } else {
+ start = wbc->range_start >> PAGE_CACHE_SHIFT;
+ end = wbc->range_end >> PAGE_CACHE_SHIFT;
+ if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
+ range_whole = 1;
+ should_loop = 0;
+ dout(" not cyclic, %lu to %lu\n", start, end);
+ }
+ index = start;
+
+retry:
+ /* find oldest snap context with dirty data */
+ ceph_put_snap_context(snapc);
+ snapc = get_oldest_context(inode, &snap_size);
+ if (!snapc) {
+ /* hmm, why does writepages get called when there
+ is no dirty data? */
+ dout(" no snap context with dirty data?\n");
+ goto out;
+ }
+ dout(" oldest snapc is %p seq %lld (%d snaps)\n",
+ snapc, snapc->seq, snapc->num_snaps);
+ if (last_snapc && snapc != last_snapc) {
+ /* if we switched to a newer snapc, restart our scan at the
+ * start of the original file range. */
+ dout(" snapc differs from last pass, restarting at %lu\n",
+ index);
+ index = start;
+ }
+ last_snapc = snapc;
+
+ while (!done && index <= end) {
+ unsigned i;
+ int first;
+ pgoff_t next;
+ int pvec_pages, locked_pages;
+ struct page *page;
+ int want;
+ u64 offset, len;
+ struct ceph_osd_request_head *reqhead;
+ struct ceph_osd_op *op;
+
+ next = 0;
+ locked_pages = 0;
+ max_pages = max_pages_ever;
+
+get_more_pages:
+ first = -1;
+ want = min(end - index,
+ min((pgoff_t)PAGEVEC_SIZE,
+ max_pages - (pgoff_t)locked_pages) - 1)
+ + 1;
+ pvec_pages = pagevec_lookup_tag(&pvec, mapping, &index,
+ PAGECACHE_TAG_DIRTY,
+ want);
+ dout("pagevec_lookup_tag got %d\n", pvec_pages);
+ if (!pvec_pages && !locked_pages)
+ break;
+ for (i = 0; i < pvec_pages && locked_pages < max_pages; i++) {
+ page = pvec.pages[i];
+ dout("? %p idx %lu\n", page, page->index);
+ if (locked_pages == 0)
+ lock_page(page); /* first page */
+ else if (!trylock_page(page))
+ break;
+
+ /* only dirty pages, or our accounting breaks */
+ if (unlikely(!PageDirty(page)) ||
+ unlikely(page->mapping != mapping)) {
+ dout("!dirty or !mapping %p\n", page);
+ unlock_page(page);
+ break;
+ }
+ if (!wbc->range_cyclic && page->index > end) {
+ dout("end of range %p\n", page);
+ done = 1;
+ unlock_page(page);
+ break;
+ }
+ if (next && (page->index != next)) {
+ dout("not consecutive %p\n", page);
+ unlock_page(page);
+ break;
+ }
+ if (wbc->sync_mode != WB_SYNC_NONE) {
+ dout("waiting on writeback %p\n", page);
+ wait_on_page_writeback(page);
+ }
+ if ((snap_size && page_offset(page) > snap_size) ||
+ (!snap_size &&
+ page_offset(page) > i_size_read(inode))) {
+ dout("%p page eof %llu\n", page, snap_size ?
+ snap_size : i_size_read(inode));
+ done = 1;
+ unlock_page(page);
+ break;
+ }
+ if (PageWriteback(page)) {
+ dout("%p under writeback\n", page);
+ unlock_page(page);
+ break;
+ }
+
+ /* only if matching snap context */
+ if (snapc != (void *)page->private) {
+ dout("page snapc %p != oldest %p\n",
+ (void *)page->private, snapc);
+ unlock_page(page);
+ if (!locked_pages)
+ continue; /* keep looking for snap */
+ break;
+ }
+
+ if (!clear_page_dirty_for_io(page)) {
+ dout("%p !clear_page_dirty_for_io\n", page);
+ unlock_page(page);
+ break;
+ }
+
+ /* ok */
+ if (locked_pages == 0) {
+ /* prepare async write request */
+ offset = page->index << PAGE_CACHE_SHIFT;
+ len = wsize;
+ req = ceph_osdc_new_request(&client->osdc,
+ &ci->i_layout,
+ ceph_vino(inode),
+ offset, &len,
+ CEPH_OSD_OP_WRITE,
+ CEPH_OSD_FLAG_WRITE |
+ CEPH_OSD_FLAG_ONDISK,
+ snapc, do_sync,
+ ci->i_truncate_seq,
+ ci->i_truncate_size,
+ &inode->i_mtime, true, 1);
+ max_pages = req->r_num_pages;
+
+ alloc_page_vec(client, req);
+ req->r_callback = writepages_finish;
+ req->r_inode = inode;
+ req->r_wbc = wbc;
+ }
+
+ /* note position of first page in pvec */
+ if (first < 0)
+ first = i;
+ dout("%p will write page %p idx %lu\n",
+ inode, page, page->index);
+ set_page_writeback(page);
+ req->r_pages[locked_pages] = page;
+ locked_pages++;
+ next = page->index + 1;
+ }
+
+ /* did we get anything? */
+ if (!locked_pages)
+ goto release_pvec_pages;
+ if (i) {
+ int j;
+ BUG_ON(!locked_pages || first < 0);
+
+ if (pvec_pages && i == pvec_pages &&
+ locked_pages < max_pages) {
+ dout("reached end pvec, trying for more\n");
+ pagevec_reinit(&pvec);
+ goto get_more_pages;
+ }
+
+ /* shift unused pages over in the pvec... we
+ * will need to release them below. */
+ for (j = i; j < pvec_pages; j++) {
+ dout(" pvec leftover page %p\n",
+ pvec.pages[j]);
+ pvec.pages[j-i+first] = pvec.pages[j];
+ }
+ pvec.nr -= i-first;
+ }
+
+ /* submit the write */
+ offset = req->r_pages[0]->index << PAGE_CACHE_SHIFT;
+ len = min((snap_size ? snap_size : i_size_read(inode)) - offset,
+ (u64)locked_pages << PAGE_CACHE_SHIFT);
+ dout("writepages got %d pages at %llu~%llu\n",
+ locked_pages, offset, len);
+
+ /* revise final length, page count */
+ req->r_num_pages = locked_pages;
+ reqhead = req->r_request->front.iov_base;
+ op = (void *)(reqhead + 1);
+ op->extent.length = cpu_to_le64(len);
+ op->payload_len = cpu_to_le32(len);
+ req->r_request->hdr.data_len = cpu_to_le32(len);
+
+ ceph_osdc_start_request(&client->osdc, req, true);
+ req = NULL;
+
+ /* continue? */
+ index = next;
+ wbc->nr_to_write -= locked_pages;
+ if (wbc->nr_to_write <= 0)
+ done = 1;
+
+release_pvec_pages:
+ dout("pagevec_release on %d pages (%p)\n", (int)pvec.nr,
+ pvec.nr ? pvec.pages[0] : NULL);
+ pagevec_release(&pvec);
+
+ if (locked_pages && !done)
+ goto retry;
+ }
+
+ if (should_loop && !done) {
+ /* more to do; loop back to beginning of file */
+ dout("writepages looping back to beginning of file\n");
+ should_loop = 0;
+ index = 0;
+ goto retry;
+ }
+
+ if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
+ mapping->writeback_index = index;
+
+out:
+ if (req)
+ ceph_osdc_put_request(req);
+ if (rc > 0)
+ rc = 0; /* vfs expects us to return 0 */
+ ceph_put_snap_context(snapc);
+ dout("writepages done, rc = %d\n", rc);
+out_final:
+ return rc;
+}
+
+
+
+/*
+ * See if a given @snapc is either writeable, or already written.
+ */
+static int context_is_writeable_or_written(struct inode *inode,
+ struct ceph_snap_context *snapc)
+{
+ struct ceph_snap_context *oldest = get_oldest_context(inode, NULL);
+ return !oldest || snapc->seq <= oldest->seq;
+}
+
+/*
+ * We are only allowed to write into/dirty the page if the page is
+ * clean, or already dirty within the same snap context.
+ */
+static int ceph_write_begin(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned flags,
+ struct page **pagep, void **fsdata)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc;
+ struct page *page;
+ pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+ loff_t page_off = pos & PAGE_CACHE_MASK;
+ int pos_in_page = pos & ~PAGE_CACHE_MASK;
+ int end_in_page = pos_in_page + len;
+ loff_t i_size;
+ struct ceph_snap_context *snapc;
+ int r;
+
+ /* get a page*/
+retry:
+ page = grab_cache_page_write_begin(mapping, index, 0);
+ if (!page)
+ return -ENOMEM;
+ *pagep = page;
+
+ dout("write_begin file %p inode %p page %p %d~%d\n", file,
+ inode, page, (int)pos, (int)len);
+
+retry_locked:
+ /* writepages currently holds page lock, but if we change that later, */
+ wait_on_page_writeback(page);
+
+ /* check snap context */
+ BUG_ON(!ci->i_snap_realm);
+ down_read(&mdsc->snap_rwsem);
+ BUG_ON(!ci->i_snap_realm->cached_context);
+ if (page->private &&
+ (void *)page->private != ci->i_snap_realm->cached_context) {
+ /*
+ * this page is already dirty in another (older) snap
+ * context! is it writeable now?
+ */
+ snapc = get_oldest_context(inode, NULL);
+ up_read(&mdsc->snap_rwsem);
+
+ if (snapc != (void *)page->private) {
+ dout(" page %p snapc %p not current or oldest\n",
+ page, (void *)page->private);
+ /*
+ * queue for writeback, and wait for snapc to
+ * be writeable or written
+ */
+ snapc = ceph_get_snap_context((void *)page->private);
+ unlock_page(page);
+ if (ceph_queue_writeback(inode))
+ igrab(inode);
+ wait_event_interruptible(ci->i_cap_wq,
+ context_is_writeable_or_written(inode, snapc));
+ ceph_put_snap_context(snapc);
+ goto retry;
+ }
+
+ /* yay, writeable, do it now (without dropping page lock) */
+ dout(" page %p snapc %p not current, but oldest\n",
+ page, snapc);
+ if (!clear_page_dirty_for_io(page))
+ goto retry_locked;
+ r = writepage_nounlock(page, NULL);
+ if (r < 0)
+ goto fail_nosnap;
+ goto retry_locked;
+ }
+
+ if (PageUptodate(page)) {
+ dout(" page %p already uptodate\n", page);
+ return 0;
+ }
+
+ /* full page? */
+ if (pos_in_page == 0 && len == PAGE_CACHE_SIZE)
+ return 0;
+
+ /* past end of file? */
+ i_size = inode->i_size; /* caller holds i_mutex */
+
+ if (i_size + len > inode->i_sb->s_maxbytes) {
+ /* file is too big */
+ r = -EINVAL;
+ goto fail;
+ }
+
+ if (page_off >= i_size ||
+ (pos_in_page == 0 && (pos+len) >= i_size &&
+ end_in_page - pos_in_page != PAGE_CACHE_SIZE)) {
+ dout(" zeroing %p 0 - %d and %d - %d\n",
+ page, pos_in_page, end_in_page, (int)PAGE_CACHE_SIZE);
+ zero_user_segments(page,
+ 0, pos_in_page,
+ end_in_page, PAGE_CACHE_SIZE);
+ return 0;
+ }
+
+ /* we need to read it. */
+ up_read(&mdsc->snap_rwsem);
+ r = readpage_nounlock(file, page);
+ if (r < 0)
+ goto fail_nosnap;
+ goto retry_locked;
+
+fail:
+ up_read(&mdsc->snap_rwsem);
+fail_nosnap:
+ unlock_page(page);
+ return r;
+}
+
+/*
+ * we don't do anything in here that simple_write_end doesn't do
+ * except adjust dirty page accounting and drop read lock on
+ * mdsc->snap_rwsem.
+ */
+static int ceph_write_end(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *page, void *fsdata)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc;
+ unsigned from = pos & (PAGE_CACHE_SIZE - 1);
+ int check_cap = 0;
+
+ dout("write_end file %p inode %p page %p %d~%d (%d)\n", file,
+ inode, page, (int)pos, (int)copied, (int)len);
+
+ /* zero the stale part of the page if we did a short copy */
+ if (copied < len)
+ zero_user_segment(page, from+copied, len);
+
+ /* did file size increase? */
+ /* (no need for i_size_read(); we caller holds i_mutex */
+ if (pos+copied > inode->i_size)
+ check_cap = ceph_inode_set_size(inode, pos+copied);
+
+ if (!PageUptodate(page))
+ SetPageUptodate(page);
+
+ set_page_dirty(page);
+
+ unlock_page(page);
+ up_read(&mdsc->snap_rwsem);
+ page_cache_release(page);
+
+ if (check_cap)
+ ceph_check_caps(ceph_inode(inode), CHECK_CAPS_AUTHONLY, NULL);
+
+ return copied;
+}
+
+/*
+ * we set .direct_IO to indicate direct io is supported, but since we
+ * intercept O_DIRECT reads and writes early, this function should
+ * never get called.
+ */
+static ssize_t ceph_direct_io(int rw, struct kiocb *iocb,
+ const struct iovec *iov,
+ loff_t pos, unsigned long nr_segs)
+{
+ WARN_ON(1);
+ return -EINVAL;
+}
+
+const struct address_space_operations ceph_aops = {
+ .readpage = ceph_readpage,
+ .readpages = ceph_readpages,
+ .writepage = ceph_writepage,
+ .writepages = ceph_writepages_start,
+ .write_begin = ceph_write_begin,
+ .write_end = ceph_write_end,
+ .set_page_dirty = ceph_set_page_dirty,
+ .invalidatepage = ceph_invalidatepage,
+ .releasepage = ceph_releasepage,
+ .direct_IO = ceph_direct_io,
+};
+
+
+/*
+ * vm ops
+ */
+
+/*
+ * Reuse write_begin here for simplicity.
+ */
+static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+ struct inode *inode = vma->vm_file->f_dentry->d_inode;
+ struct page *page = vmf->page;
+ struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc;
+ loff_t off = page->index << PAGE_CACHE_SHIFT;
+ loff_t size, len;
+ struct page *locked_page = NULL;
+ void *fsdata = NULL;
+ int ret;
+
+ size = i_size_read(inode);
+ if (off + PAGE_CACHE_SIZE <= size)
+ len = PAGE_CACHE_SIZE;
+ else
+ len = size & ~PAGE_CACHE_MASK;
+
+ dout("page_mkwrite %p %llu~%llu page %p idx %lu\n", inode,
+ off, len, page, page->index);
+ ret = ceph_write_begin(vma->vm_file, inode->i_mapping, off, len, 0,
+ &locked_page, &fsdata);
+ WARN_ON(page != locked_page);
+ if (!ret) {
+ /*
+ * doing the following, instead of calling
+ * ceph_write_end. Note that we keep the
+ * page locked
+ */
+ set_page_dirty(page);
+ up_read(&mdsc->snap_rwsem);
+ page_cache_release(page);
+ ret = VM_FAULT_LOCKED;
+ } else {
+ ret = VM_FAULT_SIGBUS;
+ }
+ dout("page_mkwrite %p %llu~%llu = %d\n", inode, off, len, ret);
+ return ret;
+}
+
+static struct vm_operations_struct ceph_vmops = {
+ .fault = filemap_fault,
+ .page_mkwrite = ceph_page_mkwrite,
+};
+
+int ceph_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct address_space *mapping = file->f_mapping;
+
+ if (!mapping->a_ops->readpage)
+ return -ENOEXEC;
+ file_accessed(file);
+ vma->vm_ops = &ceph_vmops;
+ vma->vm_flags |= VM_CAN_NONLINEAR;
+ return 0;
+}
diff --git a/fs/ceph/buffer.c b/fs/ceph/buffer.c
new file mode 100644
index 000000000000..cf9aaccef22b
--- /dev/null
+++ b/fs/ceph/buffer.c
@@ -0,0 +1,34 @@
+
+#include "ceph_debug.h"
+#include "buffer.h"
+
+struct ceph_buffer *ceph_buffer_new(gfp_t gfp)
+{
+ struct ceph_buffer *b;
+
+ b = kmalloc(sizeof(*b), gfp);
+ if (!b)
+ return NULL;
+ atomic_set(&b->nref, 1);
+ b->vec.iov_base = NULL;
+ b->vec.iov_len = 0;
+ b->alloc_len = 0;
+ return b;
+}
+
+int ceph_buffer_alloc(struct ceph_buffer *b, int len, gfp_t gfp)
+{
+ b->vec.iov_base = kmalloc(len, gfp | __GFP_NOWARN);
+ if (b->vec.iov_base) {
+ b->is_vmalloc = false;
+ } else {
+ b->vec.iov_base = __vmalloc(len, gfp, PAGE_KERNEL);
+ b->is_vmalloc = true;
+ }
+ if (!b->vec.iov_base)
+ return -ENOMEM;
+ b->alloc_len = len;
+ b->vec.iov_len = len;
+ return 0;
+}
+
diff --git a/fs/ceph/buffer.h b/fs/ceph/buffer.h
new file mode 100644
index 000000000000..16b1930acc45
--- /dev/null
+++ b/fs/ceph/buffer.h
@@ -0,0 +1,55 @@
+#ifndef __FS_CEPH_BUFFER_H
+#define __FS_CEPH_BUFFER_H
+
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/types.h>
+#include <linux/uio.h>
+
+/*
+ * a simple reference counted buffer.
+ *
+ * use kmalloc for small sizes (<= one page), vmalloc for larger
+ * sizes.
+ */
+struct ceph_buffer {
+ atomic_t nref;
+ struct kvec vec;
+ size_t alloc_len;
+ bool is_vmalloc;
+};
+
+struct ceph_buffer *ceph_buffer_new(gfp_t gfp);
+int ceph_buffer_alloc(struct ceph_buffer *b, int len, gfp_t gfp);
+
+static inline struct ceph_buffer *ceph_buffer_get(struct ceph_buffer *b)
+{
+ atomic_inc(&b->nref);
+ return b;
+}
+
+static inline void ceph_buffer_put(struct ceph_buffer *b)
+{
+ if (b && atomic_dec_and_test(&b->nref)) {
+ if (b->vec.iov_base) {
+ if (b->is_vmalloc)
+ vfree(b->vec.iov_base);
+ else
+ kfree(b->vec.iov_base);
+ }
+ kfree(b);
+ }
+}
+
+static inline struct ceph_buffer *ceph_buffer_new_alloc(int len, gfp_t gfp)
+{
+ struct ceph_buffer *b = ceph_buffer_new(gfp);
+
+ if (b && ceph_buffer_alloc(b, len, gfp) < 0) {
+ ceph_buffer_put(b);
+ b = NULL;
+ }
+ return b;
+}
+
+#endif
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
new file mode 100644
index 000000000000..7d166182e98d
--- /dev/null
+++ b/fs/ceph/caps.c
@@ -0,0 +1,2863 @@
+#include "ceph_debug.h"
+
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+
+#include "super.h"
+#include "decode.h"
+#include "messenger.h"
+
+/*
+ * Capability management
+ *
+ * The Ceph metadata servers control client access to inode metadata
+ * and file data by issuing capabilities, granting clients permission
+ * to read and/or write both inode field and file data to OSDs
+ * (storage nodes). Each capability consists of a set of bits
+ * indicating which operations are allowed.
+ *
+ * If the client holds a *_SHARED cap, the client has a coherent value
+ * that can be safely read from the cached inode.
+ *
+ * In the case of a *_EXCL (exclusive) or FILE_WR capabilities, the
+ * client is allowed to change inode attributes (e.g., file size,
+ * mtime), note its dirty state in the ceph_cap, and asynchronously
+ * flush that metadata change to the MDS.
+ *
+ * In the event of a conflicting operation (perhaps by another
+ * client), the MDS will revoke the conflicting client capabilities.
+ *
+ * In order for a client to cache an inode, it must hold a capability
+ * with at least one MDS server. When inodes are released, release
+ * notifications are batched and periodically sent en masse to the MDS
+ * cluster to release server state.
+ */
+
+
+/*
+ * Generate readable cap strings for debugging output.
+ */
+#define MAX_CAP_STR 20
+static char cap_str[MAX_CAP_STR][40];
+static DEFINE_SPINLOCK(cap_str_lock);
+static int last_cap_str;
+
+static char *gcap_string(char *s, int c)
+{
+ if (c & CEPH_CAP_GSHARED)
+ *s++ = 's';
+ if (c & CEPH_CAP_GEXCL)
+ *s++ = 'x';
+ if (c & CEPH_CAP_GCACHE)
+ *s++ = 'c';
+ if (c & CEPH_CAP_GRD)
+ *s++ = 'r';
+ if (c & CEPH_CAP_GWR)
+ *s++ = 'w';
+ if (c & CEPH_CAP_GBUFFER)
+ *s++ = 'b';
+ if (c & CEPH_CAP_GLAZYIO)
+ *s++ = 'l';
+ return s;
+}
+
+const char *ceph_cap_string(int caps)
+{
+ int i;
+ char *s;
+ int c;
+
+ spin_lock(&cap_str_lock);
+ i = last_cap_str++;
+ if (last_cap_str == MAX_CAP_STR)
+ last_cap_str = 0;
+ spin_unlock(&cap_str_lock);
+
+ s = cap_str[i];
+
+ if (caps & CEPH_CAP_PIN)
+ *s++ = 'p';
+
+ c = (caps >> CEPH_CAP_SAUTH) & 3;
+ if (c) {
+ *s++ = 'A';
+ s = gcap_string(s, c);
+ }
+
+ c = (caps >> CEPH_CAP_SLINK) & 3;
+ if (c) {
+ *s++ = 'L';
+ s = gcap_string(s, c);
+ }
+
+ c = (caps >> CEPH_CAP_SXATTR) & 3;
+ if (c) {
+ *s++ = 'X';
+ s = gcap_string(s, c);
+ }
+
+ c = caps >> CEPH_CAP_SFILE;
+ if (c) {
+ *s++ = 'F';
+ s = gcap_string(s, c);
+ }
+
+ if (s == cap_str[i])
+ *s++ = '-';
+ *s = 0;
+ return cap_str[i];
+}
+
+/*
+ * Cap reservations
+ *
+ * Maintain a global pool of preallocated struct ceph_caps, referenced
+ * by struct ceph_caps_reservations. This ensures that we preallocate
+ * memory needed to successfully process an MDS response. (If an MDS
+ * sends us cap information and we fail to process it, we will have
+ * problems due to the client and MDS being out of sync.)
+ *
+ * Reservations are 'owned' by a ceph_cap_reservation context.
+ */
+static spinlock_t caps_list_lock;
+static struct list_head caps_list; /* unused (reserved or unreserved) */
+static int caps_total_count; /* total caps allocated */
+static int caps_use_count; /* in use */
+static int caps_reserve_count; /* unused, reserved */
+static int caps_avail_count; /* unused, unreserved */
+
+void __init ceph_caps_init(void)
+{
+ INIT_LIST_HEAD(&caps_list);
+ spin_lock_init(&caps_list_lock);
+}
+
+void ceph_caps_finalize(void)
+{
+ struct ceph_cap *cap;
+
+ spin_lock(&caps_list_lock);
+ while (!list_empty(&caps_list)) {
+ cap = list_first_entry(&caps_list, struct ceph_cap, caps_item);
+ list_del(&cap->caps_item);
+ kmem_cache_free(ceph_cap_cachep, cap);
+ }
+ caps_total_count = 0;
+ caps_avail_count = 0;
+ caps_use_count = 0;
+ caps_reserve_count = 0;
+ spin_unlock(&caps_list_lock);
+}
+
+int ceph_reserve_caps(struct ceph_cap_reservation *ctx, int need)
+{
+ int i;
+ struct ceph_cap *cap;
+ int have;
+ int alloc = 0;
+ LIST_HEAD(newcaps);
+ int ret = 0;
+
+ dout("reserve caps ctx=%p need=%d\n", ctx, need);
+
+ /* first reserve any caps that are already allocated */
+ spin_lock(&caps_list_lock);
+ if (caps_avail_count >= need)
+ have = need;
+ else
+ have = caps_avail_count;
+ caps_avail_count -= have;
+ caps_reserve_count += have;
+ BUG_ON(caps_total_count != caps_use_count + caps_reserve_count +
+ caps_avail_count);
+ spin_unlock(&caps_list_lock);
+
+ for (i = have; i < need; i++) {
+ cap = kmem_cache_alloc(ceph_cap_cachep, GFP_NOFS);
+ if (!cap) {
+ ret = -ENOMEM;
+ goto out_alloc_count;
+ }
+ list_add(&cap->caps_item, &newcaps);
+ alloc++;
+ }
+ BUG_ON(have + alloc != need);
+
+ spin_lock(&caps_list_lock);
+ caps_total_count += alloc;
+ caps_reserve_count += alloc;
+ list_splice(&newcaps, &caps_list);
+
+ BUG_ON(caps_total_count != caps_use_count + caps_reserve_count +
+ caps_avail_count);
+ spin_unlock(&caps_list_lock);
+
+ ctx->count = need;
+ dout("reserve caps ctx=%p %d = %d used + %d resv + %d avail\n",
+ ctx, caps_total_count, caps_use_count, caps_reserve_count,
+ caps_avail_count);
+ return 0;
+
+out_alloc_count:
+ /* we didn't manage to reserve as much as we needed */
+ pr_warning("reserve caps ctx=%p ENOMEM need=%d got=%d\n",
+ ctx, need, have);
+ return ret;
+}
+
+int ceph_unreserve_caps(struct ceph_cap_reservation *ctx)
+{
+ dout("unreserve caps ctx=%p count=%d\n", ctx, ctx->count);
+ if (ctx->count) {
+ spin_lock(&caps_list_lock);
+ BUG_ON(caps_reserve_count < ctx->count);
+ caps_reserve_count -= ctx->count;
+ caps_avail_count += ctx->count;
+ ctx->count = 0;
+ dout("unreserve caps %d = %d used + %d resv + %d avail\n",
+ caps_total_count, caps_use_count, caps_reserve_count,
+ caps_avail_count);
+ BUG_ON(caps_total_count != caps_use_count + caps_reserve_count +
+ caps_avail_count);
+ spin_unlock(&caps_list_lock);
+ }
+ return 0;
+}
+
+static struct ceph_cap *get_cap(struct ceph_cap_reservation *ctx)
+{
+ struct ceph_cap *cap = NULL;
+
+ /* temporary, until we do something about cap import/export */
+ if (!ctx)
+ return kmem_cache_alloc(ceph_cap_cachep, GFP_NOFS);
+
+ spin_lock(&caps_list_lock);
+ dout("get_cap ctx=%p (%d) %d = %d used + %d resv + %d avail\n",
+ ctx, ctx->count, caps_total_count, caps_use_count,
+ caps_reserve_count, caps_avail_count);
+ BUG_ON(!ctx->count);
+ BUG_ON(ctx->count > caps_reserve_count);
+ BUG_ON(list_empty(&caps_list));
+
+ ctx->count--;
+ caps_reserve_count--;
+ caps_use_count++;
+
+ cap = list_first_entry(&caps_list, struct ceph_cap, caps_item);
+ list_del(&cap->caps_item);
+
+ BUG_ON(caps_total_count != caps_use_count + caps_reserve_count +
+ caps_avail_count);
+ spin_unlock(&caps_list_lock);
+ return cap;
+}
+
+static void put_cap(struct ceph_cap *cap,
+ struct ceph_cap_reservation *ctx)
+{
+ spin_lock(&caps_list_lock);
+ dout("put_cap ctx=%p (%d) %d = %d used + %d resv + %d avail\n",
+ ctx, ctx ? ctx->count : 0, caps_total_count, caps_use_count,
+ caps_reserve_count, caps_avail_count);
+ caps_use_count--;
+ /*
+ * Keep some preallocated caps around, at least enough to do a
+ * readdir (which needs to preallocate lots of them), to avoid
+ * lots of free/alloc churn.
+ */
+ if (caps_avail_count >= caps_reserve_count +
+ ceph_client(cap->ci->vfs_inode.i_sb)->mount_args.max_readdir) {
+ caps_total_count--;
+ kmem_cache_free(ceph_cap_cachep, cap);
+ } else {
+ if (ctx) {
+ ctx->count++;
+ caps_reserve_count++;
+ } else {
+ caps_avail_count++;
+ }
+ list_add(&cap->caps_item, &caps_list);
+ }
+
+ BUG_ON(caps_total_count != caps_use_count + caps_reserve_count +
+ caps_avail_count);
+ spin_unlock(&caps_list_lock);
+}
+
+void ceph_reservation_status(struct ceph_client *client,
+ int *total, int *avail, int *used, int *reserved)
+{
+ if (total)
+ *total = caps_total_count;
+ if (avail)
+ *avail = caps_avail_count;
+ if (used)
+ *used = caps_use_count;
+ if (reserved)
+ *reserved = caps_reserve_count;
+}
+
+/*
+ * Find ceph_cap for given mds, if any.
+ *
+ * Called with i_lock held.
+ */
+static struct ceph_cap *__get_cap_for_mds(struct ceph_inode_info *ci, int mds)
+{
+ struct ceph_cap *cap;
+ struct rb_node *n = ci->i_caps.rb_node;
+
+ while (n) {
+ cap = rb_entry(n, struct ceph_cap, ci_node);
+ if (mds < cap->mds)
+ n = n->rb_left;
+ else if (mds > cap->mds)
+ n = n->rb_right;
+ else
+ return cap;
+ }
+ return NULL;
+}
+
+/*
+ * Return id of any MDS with a cap, preferably FILE_WR|WRBUFFER|EXCL, else
+ * -1.
+ */
+static int __ceph_get_cap_mds(struct ceph_inode_info *ci, u32 *mseq)
+{
+ struct ceph_cap *cap;
+ int mds = -1;
+ struct rb_node *p;
+
+ /* prefer mds with WR|WRBUFFER|EXCL caps */
+ for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
+ cap = rb_entry(p, struct ceph_cap, ci_node);
+ mds = cap->mds;
+ if (mseq)
+ *mseq = cap->mseq;
+ if (cap->issued & (CEPH_CAP_FILE_WR |
+ CEPH_CAP_FILE_BUFFER |
+ CEPH_CAP_FILE_EXCL))
+ break;
+ }
+ return mds;
+}
+
+int ceph_get_cap_mds(struct inode *inode)
+{
+ int mds;
+ spin_lock(&inode->i_lock);
+ mds = __ceph_get_cap_mds(ceph_inode(inode), NULL);
+ spin_unlock(&inode->i_lock);
+ return mds;
+}
+
+/*
+ * Called under i_lock.
+ */
+static void __insert_cap_node(struct ceph_inode_info *ci,
+ struct ceph_cap *new)
+{
+ struct rb_node **p = &ci->i_caps.rb_node;
+ struct rb_node *parent = NULL;
+ struct ceph_cap *cap = NULL;
+
+ while (*p) {
+ parent = *p;
+ cap = rb_entry(parent, struct ceph_cap, ci_node);
+ if (new->mds < cap->mds)
+ p = &(*p)->rb_left;
+ else if (new->mds > cap->mds)
+ p = &(*p)->rb_right;
+ else
+ BUG();
+ }
+
+ rb_link_node(&new->ci_node, parent, p);
+ rb_insert_color(&new->ci_node, &ci->i_caps);
+}
+
+/*
+ * (re)set cap hold timeouts, which control the delayed release
+ * of unused caps back to the MDS. Should be called on cap use.
+ */
+static void __cap_set_timeouts(struct ceph_mds_client *mdsc,
+ struct ceph_inode_info *ci)
+{
+ struct ceph_mount_args *ma = &mdsc->client->mount_args;
+
+ ci->i_hold_caps_min = round_jiffies(jiffies +
+ ma->caps_wanted_delay_min * HZ);
+ ci->i_hold_caps_max = round_jiffies(jiffies +
+ ma->caps_wanted_delay_max * HZ);
+ dout("__cap_set_timeouts %p min %lu max %lu\n", &ci->vfs_inode,
+ ci->i_hold_caps_min - jiffies, ci->i_hold_caps_max - jiffies);
+}
+
+/*
+ * (Re)queue cap at the end of the delayed cap release list.
+ *
+ * If I_FLUSH is set, leave the inode at the front of the list.
+ *
+ * Caller holds i_lock
+ * -> we take mdsc->cap_delay_lock
+ */
+static void __cap_delay_requeue(struct ceph_mds_client *mdsc,
+ struct ceph_inode_info *ci)
+{
+ __cap_set_timeouts(mdsc, ci);
+ dout("__cap_delay_requeue %p flags %d at %lu\n", &ci->vfs_inode,
+ ci->i_ceph_flags, ci->i_hold_caps_max);
+ if (!mdsc->stopping) {
+ spin_lock(&mdsc->cap_delay_lock);
+ if (!list_empty(&ci->i_cap_delay_list)) {
+ if (ci->i_ceph_flags & CEPH_I_FLUSH)
+ goto no_change;
+ list_del_init(&ci->i_cap_delay_list);
+ }
+ list_add_tail(&ci->i_cap_delay_list, &mdsc->cap_delay_list);
+no_change:
+ spin_unlock(&mdsc->cap_delay_lock);
+ }
+}
+
+/*
+ * Queue an inode for immediate writeback. Mark inode with I_FLUSH,
+ * indicating we should send a cap message to flush dirty metadata
+ * asap, and move to the front of the delayed cap list.
+ */
+static void __cap_delay_requeue_front(struct ceph_mds_client *mdsc,
+ struct ceph_inode_info *ci)
+{
+ dout("__cap_delay_requeue_front %p\n", &ci->vfs_inode);
+ spin_lock(&mdsc->cap_delay_lock);
+ ci->i_ceph_flags |= CEPH_I_FLUSH;
+ if (!list_empty(&ci->i_cap_delay_list))
+ list_del_init(&ci->i_cap_delay_list);
+ list_add(&ci->i_cap_delay_list, &mdsc->cap_delay_list);
+ spin_unlock(&mdsc->cap_delay_lock);
+}
+
+/*
+ * Cancel delayed work on cap.
+ *
+ * Caller must hold i_lock.
+ */
+static void __cap_delay_cancel(struct ceph_mds_client *mdsc,
+ struct ceph_inode_info *ci)
+{
+ dout("__cap_delay_cancel %p\n", &ci->vfs_inode);
+ if (list_empty(&ci->i_cap_delay_list))
+ return;
+ spin_lock(&mdsc->cap_delay_lock);
+ list_del_init(&ci->i_cap_delay_list);
+ spin_unlock(&mdsc->cap_delay_lock);
+}
+
+/*
+ * Common issue checks for add_cap, handle_cap_grant.
+ */
+static void __check_cap_issue(struct ceph_inode_info *ci, struct ceph_cap *cap,
+ unsigned issued)
+{
+ unsigned had = __ceph_caps_issued(ci, NULL);
+
+ /*
+ * Each time we receive FILE_CACHE anew, we increment
+ * i_rdcache_gen.
+ */
+ if ((issued & CEPH_CAP_FILE_CACHE) &&
+ (had & CEPH_CAP_FILE_CACHE) == 0)
+ ci->i_rdcache_gen++;
+
+ /*
+ * if we are newly issued FILE_SHARED, clear I_COMPLETE; we
+ * don't know what happened to this directory while we didn't
+ * have the cap.
+ */
+ if ((issued & CEPH_CAP_FILE_SHARED) &&
+ (had & CEPH_CAP_FILE_SHARED) == 0) {
+ ci->i_shared_gen++;
+ if (S_ISDIR(ci->vfs_inode.i_mode)) {
+ dout(" marking %p NOT complete\n", &ci->vfs_inode);
+ ci->i_ceph_flags &= ~CEPH_I_COMPLETE;
+ }
+ }
+}
+
+/*
+ * Add a capability under the given MDS session.
+ *
+ * Caller should hold session snap_rwsem (read) and s_mutex.
+ *
+ * @fmode is the open file mode, if we are opening a file, otherwise
+ * it is < 0. (This is so we can atomically add the cap and add an
+ * open file reference to it.)
+ */
+int ceph_add_cap(struct inode *inode,
+ struct ceph_mds_session *session, u64 cap_id,
+ int fmode, unsigned issued, unsigned wanted,
+ unsigned seq, unsigned mseq, u64 realmino, int flags,
+ struct ceph_cap_reservation *caps_reservation)
+{
+ struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_cap *new_cap = NULL;
+ struct ceph_cap *cap;
+ int mds = session->s_mds;
+ int actual_wanted;
+
+ dout("add_cap %p mds%d cap %llx %s seq %d\n", inode,
+ session->s_mds, cap_id, ceph_cap_string(issued), seq);
+
+ /*
+ * If we are opening the file, include file mode wanted bits
+ * in wanted.
+ */
+ if (fmode >= 0)
+ wanted |= ceph_caps_for_mode(fmode);
+
+retry:
+ spin_lock(&inode->i_lock);
+ cap = __get_cap_for_mds(ci, mds);
+ if (!cap) {
+ if (new_cap) {
+ cap = new_cap;
+ new_cap = NULL;
+ } else {
+ spin_unlock(&inode->i_lock);
+ new_cap = get_cap(caps_reservation);
+ if (new_cap == NULL)
+ return -ENOMEM;
+ goto retry;
+ }
+
+ cap->issued = 0;
+ cap->implemented = 0;
+ cap->mds = mds;
+ cap->mds_wanted = 0;
+
+ cap->ci = ci;
+ __insert_cap_node(ci, cap);
+
+ /* clear out old exporting info? (i.e. on cap import) */
+ if (ci->i_cap_exporting_mds == mds) {
+ ci->i_cap_exporting_issued = 0;
+ ci->i_cap_exporting_mseq = 0;
+ ci->i_cap_exporting_mds = -1;
+ }
+
+ /* add to session cap list */
+ cap->session = session;
+ spin_lock(&session->s_cap_lock);
+ list_add_tail(&cap->session_caps, &session->s_caps);
+ session->s_nr_caps++;
+ spin_unlock(&session->s_cap_lock);
+ }
+
+ if (!ci->i_snap_realm) {
+ /*
+ * add this inode to the appropriate snap realm
+ */
+ struct ceph_snap_realm *realm = ceph_lookup_snap_realm(mdsc,
+ realmino);
+ if (realm) {
+ ceph_get_snap_realm(mdsc, realm);
+ spin_lock(&realm->inodes_with_caps_lock);
+ ci->i_snap_realm = realm;
+ list_add(&ci->i_snap_realm_item,
+ &realm->inodes_with_caps);
+ spin_unlock(&realm->inodes_with_caps_lock);
+ } else {
+ pr_err("ceph_add_cap: couldn't find snap realm %llx\n",
+ realmino);
+ }
+ }
+
+ __check_cap_issue(ci, cap, issued);
+
+ /*
+ * If we are issued caps we don't want, or the mds' wanted
+ * value appears to be off, queue a check so we'll release
+ * later and/or update the mds wanted value.
+ */
+ actual_wanted = __ceph_caps_wanted(ci);
+ if ((wanted & ~actual_wanted) ||
+ (issued & ~actual_wanted & CEPH_CAP_ANY_WR)) {
+ dout(" issued %s, mds wanted %s, actual %s, queueing\n",
+ ceph_cap_string(issued), ceph_cap_string(wanted),
+ ceph_cap_string(actual_wanted));
+ __cap_delay_requeue(mdsc, ci);
+ }
+
+ if (flags & CEPH_CAP_FLAG_AUTH)
+ ci->i_auth_cap = cap;
+ else if (ci->i_auth_cap == cap)
+ ci->i_auth_cap = NULL;
+
+ dout("add_cap inode %p (%llx.%llx) cap %p %s now %s seq %d mds%d\n",
+ inode, ceph_vinop(inode), cap, ceph_cap_string(issued),
+ ceph_cap_string(issued|cap->issued), seq, mds);
+ cap->cap_id = cap_id;
+ cap->issued = issued;
+ cap->implemented |= issued;
+ cap->mds_wanted |= wanted;
+ cap->seq = seq;
+ cap->issue_seq = seq;
+ cap->mseq = mseq;
+ cap->gen = session->s_cap_gen;
+
+ if (fmode >= 0)
+ __ceph_get_fmode(ci, fmode);
+ spin_unlock(&inode->i_lock);
+ wake_up(&ci->i_cap_wq);
+ return 0;
+}
+
+/*
+ * Return true if cap has not timed out and belongs to the current
+ * generation of the MDS session (i.e. has not gone 'stale' due to
+ * us losing touch with the mds).
+ */
+static int __cap_is_valid(struct ceph_cap *cap)
+{
+ unsigned long ttl;
+ u32 gen;
+
+ spin_lock(&cap->session->s_cap_lock);
+ gen = cap->session->s_cap_gen;
+ ttl = cap->session->s_cap_ttl;
+ spin_unlock(&cap->session->s_cap_lock);
+
+ if (cap->gen < gen || time_after_eq(jiffies, ttl)) {
+ dout("__cap_is_valid %p cap %p issued %s "
+ "but STALE (gen %u vs %u)\n", &cap->ci->vfs_inode,
+ cap, ceph_cap_string(cap->issued), cap->gen, gen);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Return set of valid cap bits issued to us. Note that caps time
+ * out, and may be invalidated in bulk if the client session times out
+ * and session->s_cap_gen is bumped.
+ */
+int __ceph_caps_issued(struct ceph_inode_info *ci, int *implemented)
+{
+ int have = ci->i_snap_caps;
+ struct ceph_cap *cap;
+ struct rb_node *p;
+
+ if (implemented)
+ *implemented = 0;
+ for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
+ cap = rb_entry(p, struct ceph_cap, ci_node);
+ if (!__cap_is_valid(cap))
+ continue;
+ dout("__ceph_caps_issued %p cap %p issued %s\n",
+ &ci->vfs_inode, cap, ceph_cap_string(cap->issued));
+ have |= cap->issued;
+ if (implemented)
+ *implemented |= cap->implemented;
+ }
+ return have;
+}
+
+/*
+ * Get cap bits issued by caps other than @ocap
+ */
+int __ceph_caps_issued_other(struct ceph_inode_info *ci, struct ceph_cap *ocap)
+{
+ int have = ci->i_snap_caps;
+ struct ceph_cap *cap;
+ struct rb_node *p;
+
+ for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
+ cap = rb_entry(p, struct ceph_cap, ci_node);
+ if (cap == ocap)
+ continue;
+ if (!__cap_is_valid(cap))
+ continue;
+ have |= cap->issued;
+ }
+ return have;
+}
+
+/*
+ * Move a cap to the end of the LRU (oldest caps at list head, newest
+ * at list tail).
+ */
+static void __touch_cap(struct ceph_cap *cap)
+{
+ struct ceph_mds_session *s = cap->session;
+
+ dout("__touch_cap %p cap %p mds%d\n", &cap->ci->vfs_inode, cap,
+ s->s_mds);
+ spin_lock(&s->s_cap_lock);
+ list_move_tail(&cap->session_caps, &s->s_caps);
+ spin_unlock(&s->s_cap_lock);
+}
+
+/*
+ * Check if we hold the given mask. If so, move the cap(s) to the
+ * front of their respective LRUs. (This is the preferred way for
+ * callers to check for caps they want.)
+ */
+int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch)
+{
+ struct ceph_cap *cap;
+ struct rb_node *p;
+ int have = ci->i_snap_caps;
+
+ if ((have & mask) == mask) {
+ dout("__ceph_caps_issued_mask %p snap issued %s"
+ " (mask %s)\n", &ci->vfs_inode,
+ ceph_cap_string(have),
+ ceph_cap_string(mask));
+ return 1;
+ }
+
+ for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
+ cap = rb_entry(p, struct ceph_cap, ci_node);
+ if (!__cap_is_valid(cap))
+ continue;
+ if ((cap->issued & mask) == mask) {
+ dout("__ceph_caps_issued_mask %p cap %p issued %s"
+ " (mask %s)\n", &ci->vfs_inode, cap,
+ ceph_cap_string(cap->issued),
+ ceph_cap_string(mask));
+ if (touch)
+ __touch_cap(cap);
+ return 1;
+ }
+
+ /* does a combination of caps satisfy mask? */
+ have |= cap->issued;
+ if ((have & mask) == mask) {
+ dout("__ceph_caps_issued_mask %p combo issued %s"
+ " (mask %s)\n", &ci->vfs_inode,
+ ceph_cap_string(cap->issued),
+ ceph_cap_string(mask));
+ if (touch) {
+ struct rb_node *q;
+
+ /* touch this + preceeding caps */
+ __touch_cap(cap);
+ for (q = rb_first(&ci->i_caps); q != p;
+ q = rb_next(q)) {
+ cap = rb_entry(q, struct ceph_cap,
+ ci_node);
+ if (!__cap_is_valid(cap))
+ continue;
+ __touch_cap(cap);
+ }
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Return true if mask caps are currently being revoked by an MDS.
+ */
+int ceph_caps_revoking(struct ceph_inode_info *ci, int mask)
+{
+ struct inode *inode = &ci->vfs_inode;
+ struct ceph_cap *cap;
+ struct rb_node *p;
+ int ret = 0;
+
+ spin_lock(&inode->i_lock);
+ for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
+ cap = rb_entry(p, struct ceph_cap, ci_node);
+ if (__cap_is_valid(cap) &&
+ (cap->implemented & ~cap->issued & mask)) {
+ ret = 1;
+ break;
+ }
+ }
+ spin_unlock(&inode->i_lock);
+ dout("ceph_caps_revoking %p %s = %d\n", inode,
+ ceph_cap_string(mask), ret);
+ return ret;
+}
+
+int __ceph_caps_used(struct ceph_inode_info *ci)
+{
+ int used = 0;
+ if (ci->i_pin_ref)
+ used |= CEPH_CAP_PIN;
+ if (ci->i_rd_ref)
+ used |= CEPH_CAP_FILE_RD;
+ if (ci->i_rdcache_ref || ci->i_rdcache_gen)
+ used |= CEPH_CAP_FILE_CACHE;
+ if (ci->i_wr_ref)
+ used |= CEPH_CAP_FILE_WR;
+ if (ci->i_wrbuffer_ref)
+ used |= CEPH_CAP_FILE_BUFFER;
+ return used;
+}
+
+/*
+ * wanted, by virtue of open file modes
+ */
+int __ceph_caps_file_wanted(struct ceph_inode_info *ci)
+{
+ int want = 0;
+ int mode;
+ for (mode = 0; mode < 4; mode++)
+ if (ci->i_nr_by_mode[mode])
+ want |= ceph_caps_for_mode(mode);
+ return want;
+}
+
+/*
+ * Return caps we have registered with the MDS(s) as 'wanted'.
+ */
+int __ceph_caps_mds_wanted(struct ceph_inode_info *ci)
+{
+ struct ceph_cap *cap;
+ struct rb_node *p;
+ int mds_wanted = 0;
+
+ for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
+ cap = rb_entry(p, struct ceph_cap, ci_node);
+ if (!__cap_is_valid(cap))
+ continue;
+ mds_wanted |= cap->mds_wanted;
+ }
+ return mds_wanted;
+}
+
+/*
+ * called under i_lock
+ */
+static int __ceph_is_any_caps(struct ceph_inode_info *ci)
+{
+ return !RB_EMPTY_ROOT(&ci->i_caps) || ci->i_cap_exporting_mds >= 0;
+}
+
+/*
+ * caller should hold i_lock, and session s_mutex.
+ * returns true if this is the last cap. if so, caller should iput.
+ */
+void __ceph_remove_cap(struct ceph_cap *cap,
+ struct ceph_cap_reservation *ctx)
+{
+ struct ceph_mds_session *session = cap->session;
+ struct ceph_inode_info *ci = cap->ci;
+ struct ceph_mds_client *mdsc = &ceph_client(ci->vfs_inode.i_sb)->mdsc;
+
+ dout("__ceph_remove_cap %p from %p\n", cap, &ci->vfs_inode);
+
+ /* remove from session list */
+ spin_lock(&session->s_cap_lock);
+ list_del_init(&cap->session_caps);
+ session->s_nr_caps--;
+ spin_unlock(&session->s_cap_lock);
+
+ /* remove from inode list */
+ rb_erase(&cap->ci_node, &ci->i_caps);
+ cap->session = NULL;
+ if (ci->i_auth_cap == cap)
+ ci->i_auth_cap = NULL;
+
+ put_cap(cap, ctx);
+
+ if (!__ceph_is_any_caps(ci) && ci->i_snap_realm) {
+ struct ceph_snap_realm *realm = ci->i_snap_realm;
+ spin_lock(&realm->inodes_with_caps_lock);
+ list_del_init(&ci->i_snap_realm_item);
+ ci->i_snap_realm_counter++;
+ ci->i_snap_realm = NULL;
+ spin_unlock(&realm->inodes_with_caps_lock);
+ ceph_put_snap_realm(mdsc, realm);
+ }
+ if (!__ceph_is_any_real_caps(ci))
+ __cap_delay_cancel(mdsc, ci);
+}
+
+/*
+ * Build and send a cap message to the given MDS.
+ *
+ * Caller should be holding s_mutex.
+ */
+static int send_cap_msg(struct ceph_mds_session *session,
+ u64 ino, u64 cid, int op,
+ int caps, int wanted, int dirty,
+ u32 seq, u64 flush_tid, u32 issue_seq, u32 mseq,
+ u64 size, u64 max_size,
+ struct timespec *mtime, struct timespec *atime,
+ u64 time_warp_seq,
+ uid_t uid, gid_t gid, mode_t mode,
+ u64 xattr_version,
+ struct ceph_buffer *xattrs_buf,
+ u64 follows)
+{
+ struct ceph_mds_caps *fc;
+ struct ceph_msg *msg;
+
+ dout("send_cap_msg %s %llx %llx caps %s wanted %s dirty %s"
+ " seq %u/%u mseq %u follows %lld size %llu/%llu"
+ " xattr_ver %llu xattr_len %d\n", ceph_cap_op_name(op),
+ cid, ino, ceph_cap_string(caps), ceph_cap_string(wanted),
+ ceph_cap_string(dirty),
+ seq, issue_seq, mseq, follows, size, max_size,
+ xattr_version, xattrs_buf ? (int)xattrs_buf->vec.iov_len : 0);
+
+ msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, sizeof(*fc), 0, 0, NULL);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ fc = msg->front.iov_base;
+
+ memset(fc, 0, sizeof(*fc));
+
+ fc->cap_id = cpu_to_le64(cid);
+ fc->op = cpu_to_le32(op);
+ fc->seq = cpu_to_le32(seq);
+ fc->client_tid = cpu_to_le64(flush_tid);
+ fc->issue_seq = cpu_to_le32(issue_seq);
+ fc->migrate_seq = cpu_to_le32(mseq);
+ fc->caps = cpu_to_le32(caps);
+ fc->wanted = cpu_to_le32(wanted);
+ fc->dirty = cpu_to_le32(dirty);
+ fc->ino = cpu_to_le64(ino);
+ fc->snap_follows = cpu_to_le64(follows);
+
+ fc->size = cpu_to_le64(size);
+ fc->max_size = cpu_to_le64(max_size);
+ if (mtime)
+ ceph_encode_timespec(&fc->mtime, mtime);
+ if (atime)
+ ceph_encode_timespec(&fc->atime, atime);
+ fc->time_warp_seq = cpu_to_le32(time_warp_seq);
+
+ fc->uid = cpu_to_le32(uid);
+ fc->gid = cpu_to_le32(gid);
+ fc->mode = cpu_to_le32(mode);
+
+ fc->xattr_version = cpu_to_le64(xattr_version);
+ if (xattrs_buf) {
+ msg->middle = ceph_buffer_get(xattrs_buf);
+ fc->xattr_len = cpu_to_le32(xattrs_buf->vec.iov_len);
+ msg->hdr.middle_len = cpu_to_le32(xattrs_buf->vec.iov_len);
+ }
+
+ ceph_con_send(&session->s_con, msg);
+ return 0;
+}
+
+/*
+ * Queue cap releases when an inode is dropped from our
+ * cache.
+ */
+void ceph_queue_caps_release(struct inode *inode)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct rb_node *p;
+
+ spin_lock(&inode->i_lock);
+ p = rb_first(&ci->i_caps);
+ while (p) {
+ struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node);
+ struct ceph_mds_session *session = cap->session;
+ struct ceph_msg *msg;
+ struct ceph_mds_cap_release *head;
+ struct ceph_mds_cap_item *item;
+
+ spin_lock(&session->s_cap_lock);
+ BUG_ON(!session->s_num_cap_releases);
+ msg = list_first_entry(&session->s_cap_releases,
+ struct ceph_msg, list_head);
+
+ dout(" adding %p release to mds%d msg %p (%d left)\n",
+ inode, session->s_mds, msg, session->s_num_cap_releases);
+
+ BUG_ON(msg->front.iov_len + sizeof(*item) > PAGE_CACHE_SIZE);
+ head = msg->front.iov_base;
+ head->num = cpu_to_le32(le32_to_cpu(head->num) + 1);
+ item = msg->front.iov_base + msg->front.iov_len;
+ item->ino = cpu_to_le64(ceph_ino(inode));
+ item->cap_id = cpu_to_le64(cap->cap_id);
+ item->migrate_seq = cpu_to_le32(cap->mseq);
+ item->seq = cpu_to_le32(cap->issue_seq);
+
+ session->s_num_cap_releases--;
+
+ msg->front.iov_len += sizeof(*item);
+ if (le32_to_cpu(head->num) == CEPH_CAPS_PER_RELEASE) {
+ dout(" release msg %p full\n", msg);
+ list_move_tail(&msg->list_head,
+ &session->s_cap_releases_done);
+ } else {
+ dout(" release msg %p at %d/%d (%d)\n", msg,
+ (int)le32_to_cpu(head->num),
+ (int)CEPH_CAPS_PER_RELEASE,
+ (int)msg->front.iov_len);
+ }
+ spin_unlock(&session->s_cap_lock);
+ p = rb_next(p);
+ __ceph_remove_cap(cap, NULL);
+
+ }
+ spin_unlock(&inode->i_lock);
+}
+
+/*
+ * Send a cap msg on the given inode. Update our caps state, then
+ * drop i_lock and send the message.
+ *
+ * Make note of max_size reported/requested from mds, revoked caps
+ * that have now been implemented.
+ *
+ * Make half-hearted attempt ot to invalidate page cache if we are
+ * dropping RDCACHE. Note that this will leave behind locked pages
+ * that we'll then need to deal with elsewhere.
+ *
+ * Return non-zero if delayed release, or we experienced an error
+ * such that the caller should requeue + retry later.
+ *
+ * called with i_lock, then drops it.
+ * caller should hold snap_rwsem (read), s_mutex.
+ */
+static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
+ int op, int used, int want, int retain, int flushing,
+ unsigned *pflush_tid)
+ __releases(cap->ci->vfs_inode->i_lock)
+{
+ struct ceph_inode_info *ci = cap->ci;
+ struct inode *inode = &ci->vfs_inode;
+ u64 cap_id = cap->cap_id;
+ int held = cap->issued | cap->implemented;
+ int revoking = cap->implemented & ~cap->issued;
+ int dropping = cap->issued & ~retain;
+ int keep;
+ u64 seq, issue_seq, mseq, time_warp_seq, follows;
+ u64 size, max_size;
+ struct timespec mtime, atime;
+ int wake = 0;
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
+ struct ceph_mds_session *session;
+ u64 xattr_version = 0;
+ int delayed = 0;
+ u64 flush_tid = 0;
+ int i;
+ int ret;
+
+ dout("__send_cap %p cap %p session %p %s -> %s (revoking %s)\n",
+ inode, cap, cap->session,
+ ceph_cap_string(held), ceph_cap_string(held & retain),
+ ceph_cap_string(revoking));
+ BUG_ON((retain & CEPH_CAP_PIN) == 0);
+
+ session = cap->session;
+
+ /* don't release wanted unless we've waited a bit. */
+ if ((ci->i_ceph_flags & CEPH_I_NODELAY) == 0 &&
+ time_before(jiffies, ci->i_hold_caps_min)) {
+ dout(" delaying issued %s -> %s, wanted %s -> %s on send\n",
+ ceph_cap_string(cap->issued),
+ ceph_cap_string(cap->issued & retain),
+ ceph_cap_string(cap->mds_wanted),
+ ceph_cap_string(want));
+ want |= cap->mds_wanted;
+ retain |= cap->issued;
+ delayed = 1;
+ }
+ ci->i_ceph_flags &= ~(CEPH_I_NODELAY | CEPH_I_FLUSH);
+
+ cap->issued &= retain; /* drop bits we don't want */
+ if (cap->implemented & ~cap->issued) {
+ /*
+ * Wake up any waiters on wanted -> needed transition.
+ * This is due to the weird transition from buffered
+ * to sync IO... we need to flush dirty pages _before_
+ * allowing sync writes to avoid reordering.
+ */
+ wake = 1;
+ }
+ cap->implemented &= cap->issued | used;
+ cap->mds_wanted = want;
+
+ if (flushing) {
+ /*
+ * assign a tid for flush operations so we can avoid
+ * flush1 -> dirty1 -> flush2 -> flushack1 -> mark
+ * clean type races. track latest tid for every bit
+ * so we can handle flush AxFw, flush Fw, and have the
+ * first ack clean Ax.
+ */
+ flush_tid = ++ci->i_cap_flush_last_tid;
+ if (pflush_tid)
+ *pflush_tid = flush_tid;
+ dout(" cap_flush_tid %d\n", (int)flush_tid);
+ for (i = 0; i < CEPH_CAP_BITS; i++)
+ if (flushing & (1 << i))
+ ci->i_cap_flush_tid[i] = flush_tid;
+ }
+
+ keep = cap->implemented;
+ seq = cap->seq;
+ issue_seq = cap->issue_seq;
+ mseq = cap->mseq;
+ size = inode->i_size;
+ ci->i_reported_size = size;
+ max_size = ci->i_wanted_max_size;
+ ci->i_requested_max_size = max_size;
+ mtime = inode->i_mtime;
+ atime = inode->i_atime;
+ time_warp_seq = ci->i_time_warp_seq;
+ follows = ci->i_snap_realm->cached_context->seq;
+ uid = inode->i_uid;
+ gid = inode->i_gid;
+ mode = inode->i_mode;
+
+ if (dropping & CEPH_CAP_XATTR_EXCL) {
+ __ceph_build_xattrs_blob(ci);
+ xattr_version = ci->i_xattrs.version + 1;
+ }
+
+ spin_unlock(&inode->i_lock);
+
+ if (dropping & CEPH_CAP_FILE_CACHE) {
+ /* invalidate what we can */
+ dout("invalidating pages on %p\n", inode);
+ invalidate_mapping_pages(&inode->i_data, 0, -1);
+ }
+
+ ret = send_cap_msg(session, ceph_vino(inode).ino, cap_id,
+ op, keep, want, flushing, seq, flush_tid, issue_seq, mseq,
+ size, max_size, &mtime, &atime, time_warp_seq,
+ uid, gid, mode,
+ xattr_version,
+ (flushing & CEPH_CAP_XATTR_EXCL) ? ci->i_xattrs.blob : NULL,
+ follows);
+ if (ret < 0) {
+ dout("error sending cap msg, must requeue %p\n", inode);
+ delayed = 1;
+ }
+
+ if (wake)
+ wake_up(&ci->i_cap_wq);
+
+ return delayed;
+}
+
+/*
+ * When a snapshot is taken, clients accumulate dirty metadata on
+ * inodes with capabilities in ceph_cap_snaps to describe the file
+ * state at the time the snapshot was taken. This must be flushed
+ * asynchronously back to the MDS once sync writes complete and dirty
+ * data is written out.
+ *
+ * Called under i_lock. Takes s_mutex as needed.
+ */
+void __ceph_flush_snaps(struct ceph_inode_info *ci,
+ struct ceph_mds_session **psession)
+{
+ struct inode *inode = &ci->vfs_inode;
+ int mds;
+ struct ceph_cap_snap *capsnap;
+ u32 mseq;
+ struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc;
+ struct ceph_mds_session *session = NULL; /* if session != NULL, we hold
+ session->s_mutex */
+ u64 next_follows = 0; /* keep track of how far we've gotten through the
+ i_cap_snaps list, and skip these entries next time
+ around to avoid an infinite loop */
+
+ if (psession)
+ session = *psession;
+
+ dout("__flush_snaps %p\n", inode);
+retry:
+ list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) {
+ /* avoid an infiniute loop after retry */
+ if (capsnap->follows < next_follows)
+ continue;
+ /*
+ * we need to wait for sync writes to complete and for dirty
+ * pages to be written out.
+ */
+ if (capsnap->dirty_pages || capsnap->writing)
+ continue;
+
+ /* pick mds, take s_mutex */
+ mds = __ceph_get_cap_mds(ci, &mseq);
+ if (session && session->s_mds != mds) {
+ dout("oops, wrong session %p mutex\n", session);
+ mutex_unlock(&session->s_mutex);
+ ceph_put_mds_session(session);
+ session = NULL;
+ }
+ if (!session) {
+ spin_unlock(&inode->i_lock);
+ mutex_lock(&mdsc->mutex);
+ session = __ceph_lookup_mds_session(mdsc, mds);
+ mutex_unlock(&mdsc->mutex);
+ if (session) {
+ dout("inverting session/ino locks on %p\n",
+ session);
+ mutex_lock(&session->s_mutex);
+ }
+ /*
+ * if session == NULL, we raced against a cap
+ * deletion. retry, and we'll get a better
+ * @mds value next time.
+ */
+ spin_lock(&inode->i_lock);
+ goto retry;
+ }
+
+ capsnap->flush_tid = ++ci->i_cap_flush_last_tid;
+ atomic_inc(&capsnap->nref);
+ if (!list_empty(&capsnap->flushing_item))
+ list_del_init(&capsnap->flushing_item);
+ list_add_tail(&capsnap->flushing_item,
+ &session->s_cap_snaps_flushing);
+ spin_unlock(&inode->i_lock);
+
+ dout("flush_snaps %p cap_snap %p follows %lld size %llu\n",
+ inode, capsnap, next_follows, capsnap->size);
+ send_cap_msg(session, ceph_vino(inode).ino, 0,
+ CEPH_CAP_OP_FLUSHSNAP, capsnap->issued, 0,
+ capsnap->dirty, 0, capsnap->flush_tid, 0, mseq,
+ capsnap->size, 0,
+ &capsnap->mtime, &capsnap->atime,
+ capsnap->time_warp_seq,
+ capsnap->uid, capsnap->gid, capsnap->mode,
+ 0, NULL,
+ capsnap->follows);
+
+ next_follows = capsnap->follows + 1;
+ ceph_put_cap_snap(capsnap);
+
+ spin_lock(&inode->i_lock);
+ goto retry;
+ }
+
+ /* we flushed them all; remove this inode from the queue */
+ spin_lock(&mdsc->snap_flush_lock);
+ list_del_init(&ci->i_snap_flush_item);
+ spin_unlock(&mdsc->snap_flush_lock);
+
+ if (psession)
+ *psession = session;
+ else if (session) {
+ mutex_unlock(&session->s_mutex);
+ ceph_put_mds_session(session);
+ }
+}
+
+static void ceph_flush_snaps(struct ceph_inode_info *ci)
+{
+ struct inode *inode = &ci->vfs_inode;
+
+ spin_lock(&inode->i_lock);
+ __ceph_flush_snaps(ci, NULL);
+ spin_unlock(&inode->i_lock);
+}
+
+/*
+ * Mark caps dirty. If inode is newly dirty, add to the global dirty
+ * list.
+ */
+void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask)
+{
+ struct ceph_mds_client *mdsc = &ceph_client(ci->vfs_inode.i_sb)->mdsc;
+ struct inode *inode = &ci->vfs_inode;
+ int was = ci->i_dirty_caps;
+ int dirty = 0;
+
+ dout("__mark_dirty_caps %p %s dirty %s -> %s\n", &ci->vfs_inode,
+ ceph_cap_string(mask), ceph_cap_string(was),
+ ceph_cap_string(was | mask));
+ ci->i_dirty_caps |= mask;
+ if (was == 0) {
+ dout(" inode %p now dirty\n", &ci->vfs_inode);
+ BUG_ON(!list_empty(&ci->i_dirty_item));
+ spin_lock(&mdsc->cap_dirty_lock);
+ list_add(&ci->i_dirty_item, &mdsc->cap_dirty);
+ spin_unlock(&mdsc->cap_dirty_lock);
+ if (ci->i_flushing_caps == 0) {
+ igrab(inode);
+ dirty |= I_DIRTY_SYNC;
+ }
+ }
+ BUG_ON(list_empty(&ci->i_dirty_item));
+ if (((was | ci->i_flushing_caps) & CEPH_CAP_FILE_BUFFER) &&
+ (mask & CEPH_CAP_FILE_BUFFER))
+ dirty |= I_DIRTY_DATASYNC;
+ if (dirty)
+ __mark_inode_dirty(inode, dirty);
+ __cap_delay_requeue(mdsc, ci);
+}
+
+/*
+ * Add dirty inode to the flushing list. Assigned a seq number so we
+ * can wait for caps to flush without starving.
+ *
+ * Called under i_lock.
+ */
+static int __mark_caps_flushing(struct inode *inode,
+ struct ceph_mds_session *session)
+{
+ struct ceph_mds_client *mdsc = &ceph_client(inode->i_sb)->mdsc;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ int flushing;
+
+ BUG_ON(ci->i_dirty_caps == 0);
+ BUG_ON(list_empty(&ci->i_dirty_item));
+
+ flushing = ci->i_dirty_caps;
+ dout("__mark_caps_flushing flushing %s, flushing_caps %s -> %s\n",
+ ceph_cap_string(flushing),
+ ceph_cap_string(ci->i_flushing_caps),
+ ceph_cap_string(ci->i_flushing_caps | flushing));
+ ci->i_flushing_caps |= flushing;
+ ci->i_dirty_caps = 0;
+ dout(" inode %p now !dirty\n", inode);
+
+ spin_lock(&mdsc->cap_dirty_lock);
+ list_del_init(&ci->i_dirty_item);
+
+ ci->i_cap_flush_seq = ++mdsc->cap_flush_seq;
+ if (list_empty(&ci->i_flushing_item)) {
+ list_add_tail(&ci->i_flushing_item, &session->s_cap_flushing);
+ mdsc->num_cap_flushing++;
+ dout(" inode %p now flushing seq %lld\n", inode,
+ ci->i_cap_flush_seq);
+ } else {
+ list_move_tail(&ci->i_flushing_item, &session->s_cap_flushing);
+ dout(" inode %p now flushing (more) seq %lld\n", inode,
+ ci->i_cap_flush_seq);
+ }
+ spin_unlock(&mdsc->cap_dirty_lock);
+
+ return flushing;
+}
+
+/*
+ * Swiss army knife function to examine currently used and wanted
+ * versus held caps. Release, flush, ack revoked caps to mds as
+ * appropriate.
+ *
+ * CHECK_CAPS_NODELAY - caller is delayed work and we should not delay
+ * cap release further.
+ * CHECK_CAPS_AUTHONLY - we should only check the auth cap
+ * CHECK_CAPS_FLUSH - we should flush any dirty caps immediately, without
+ * further delay.
+ */
+void ceph_check_caps(struct ceph_inode_info *ci, int flags,
+ struct ceph_mds_session *session)
+{
+ struct ceph_client *client = ceph_inode_to_client(&ci->vfs_inode);
+ struct ceph_mds_client *mdsc = &client->mdsc;
+ struct inode *inode = &ci->vfs_inode;
+ struct ceph_cap *cap;
+ int file_wanted, used;
+ int took_snap_rwsem = 0; /* true if mdsc->snap_rwsem held */
+ int drop_session_lock = session ? 0 : 1;
+ int want, retain, revoking, flushing = 0;
+ int mds = -1; /* keep track of how far we've gone through i_caps list
+ to avoid an infinite loop on retry */
+ struct rb_node *p;
+ int tried_invalidate = 0;
+ int delayed = 0, sent = 0, force_requeue = 0, num;
+ int is_delayed = flags & CHECK_CAPS_NODELAY;
+
+ /* if we are unmounting, flush any unused caps immediately. */
+ if (mdsc->stopping)
+ is_delayed = 1;
+
+ spin_lock(&inode->i_lock);
+
+ if (ci->i_ceph_flags & CEPH_I_FLUSH)
+ flags |= CHECK_CAPS_FLUSH;
+
+ /* flush snaps first time around only */
+ if (!list_empty(&ci->i_cap_snaps))
+ __ceph_flush_snaps(ci, &session);
+ goto retry_locked;
+retry:
+ spin_lock(&inode->i_lock);
+retry_locked:
+ file_wanted = __ceph_caps_file_wanted(ci);
+ used = __ceph_caps_used(ci);
+ want = file_wanted | used;
+
+ retain = want | CEPH_CAP_PIN;
+ if (!mdsc->stopping && inode->i_nlink > 0) {
+ if (want) {
+ retain |= CEPH_CAP_ANY; /* be greedy */
+ } else {
+ retain |= CEPH_CAP_ANY_SHARED;
+ /*
+ * keep RD only if we didn't have the file open RW,
+ * because then the mds would revoke it anyway to
+ * journal max_size=0.
+ */
+ if (ci->i_max_size == 0)
+ retain |= CEPH_CAP_ANY_RD;
+ }
+ }
+
+ dout("check_caps %p file_want %s used %s dirty %s flushing %s"
+ " issued %s retain %s %s%s%s\n", inode,
+ ceph_cap_string(file_wanted),
+ ceph_cap_string(used), ceph_cap_string(ci->i_dirty_caps),
+ ceph_cap_string(ci->i_flushing_caps),
+ ceph_cap_string(__ceph_caps_issued(ci, NULL)),
+ ceph_cap_string(retain),
+ (flags & CHECK_CAPS_AUTHONLY) ? " AUTHONLY" : "",
+ (flags & CHECK_CAPS_NODELAY) ? " NODELAY" : "",
+ (flags & CHECK_CAPS_FLUSH) ? " FLUSH" : "");
+
+ /*
+ * If we no longer need to hold onto old our caps, and we may
+ * have cached pages, but don't want them, then try to invalidate.
+ * If we fail, it's because pages are locked.... try again later.
+ */
+ if ((!is_delayed || mdsc->stopping) &&
+ ci->i_wrbuffer_ref == 0 && /* no dirty pages... */
+ ci->i_rdcache_gen && /* may have cached pages */
+ file_wanted == 0 && /* no open files */
+ !ci->i_truncate_pending &&
+ !tried_invalidate) {
+ u32 invalidating_gen = ci->i_rdcache_gen;
+ int ret;
+
+ dout("check_caps trying to invalidate on %p\n", inode);
+ spin_unlock(&inode->i_lock);
+ ret = invalidate_inode_pages2(&inode->i_data);
+ spin_lock(&inode->i_lock);
+ if (ret == 0 && invalidating_gen == ci->i_rdcache_gen) {
+ /* success. */
+ ci->i_rdcache_gen = 0;
+ ci->i_rdcache_revoking = 0;
+ } else {
+ dout("check_caps failed to invalidate pages\n");
+ /* we failed to invalidate pages. check these
+ caps again later. */
+ force_requeue = 1;
+ __cap_set_timeouts(mdsc, ci);
+ }
+ tried_invalidate = 1;
+ goto retry_locked;
+ }
+
+ num = 0;
+ for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
+ cap = rb_entry(p, struct ceph_cap, ci_node);
+ num++;
+
+ /* avoid looping forever */
+ if (mds >= cap->mds ||
+ ((flags & CHECK_CAPS_AUTHONLY) && cap != ci->i_auth_cap))
+ continue;
+
+ /* NOTE: no side-effects allowed, until we take s_mutex */
+
+ revoking = cap->implemented & ~cap->issued;
+ if (revoking)
+ dout("mds%d revoking %s\n", cap->mds,
+ ceph_cap_string(revoking));
+
+ if (cap == ci->i_auth_cap &&
+ (cap->issued & CEPH_CAP_FILE_WR)) {
+ /* request larger max_size from MDS? */
+ if (ci->i_wanted_max_size > ci->i_max_size &&
+ ci->i_wanted_max_size > ci->i_requested_max_size) {
+ dout("requesting new max_size\n");
+ goto ack;
+ }
+
+ /* approaching file_max? */
+ if ((inode->i_size << 1) >= ci->i_max_size &&
+ (ci->i_reported_size << 1) < ci->i_max_size) {
+ dout("i_size approaching max_size\n");
+ goto ack;
+ }
+ }
+ /* flush anything dirty? */
+ if (cap == ci->i_auth_cap && (flags & CHECK_CAPS_FLUSH) &&
+ ci->i_dirty_caps) {
+ dout("flushing dirty caps\n");
+ goto ack;
+ }
+
+ /* completed revocation? going down and there are no caps? */
+ if (revoking && (revoking & used) == 0) {
+ dout("completed revocation of %s\n",
+ ceph_cap_string(cap->implemented & ~cap->issued));
+ goto ack;
+ }
+
+ /* want more caps from mds? */
+ if (want & ~(cap->mds_wanted | cap->issued))
+ goto ack;
+
+ /* things we might delay */
+ if ((cap->issued & ~retain) == 0 &&
+ cap->mds_wanted == want)
+ continue; /* nope, all good */
+
+ if (is_delayed)
+ goto ack;
+
+ /* delay? */
+ if ((ci->i_ceph_flags & CEPH_I_NODELAY) == 0 &&
+ time_before(jiffies, ci->i_hold_caps_max)) {
+ dout(" delaying issued %s -> %s, wanted %s -> %s\n",
+ ceph_cap_string(cap->issued),
+ ceph_cap_string(cap->issued & retain),
+ ceph_cap_string(cap->mds_wanted),
+ ceph_cap_string(want));
+ delayed++;
+ continue;
+ }
+
+ack:
+ if (session && session != cap->session) {
+ dout("oops, wrong session %p mutex\n", session);
+ mutex_unlock(&session->s_mutex);
+ session = NULL;
+ }
+ if (!session) {
+ session = cap->session;
+ if (mutex_trylock(&session->s_mutex) == 0) {
+ dout("inverting session/ino locks on %p\n",
+ session);
+ spin_unlock(&inode->i_lock);
+ if (took_snap_rwsem) {
+ up_read(&mdsc->snap_rwsem);
+ took_snap_rwsem = 0;
+ }
+ mutex_lock(&session->s_mutex);
+ goto retry;
+ }
+ }
+ /* take snap_rwsem after session mutex */
+ if (!took_snap_rwsem) {
+ if (down_read_trylock(&mdsc->snap_rwsem) == 0) {
+ dout("inverting snap/in locks on %p\n",
+ inode);
+ spin_unlock(&inode->i_lock);
+ down_read(&mdsc->snap_rwsem);
+ took_snap_rwsem = 1;
+ goto retry;
+ }
+ took_snap_rwsem = 1;
+ }
+
+ if (cap == ci->i_auth_cap && ci->i_dirty_caps)
+ flushing = __mark_caps_flushing(inode, session);
+
+ mds = cap->mds; /* remember mds, so we don't repeat */
+ sent++;
+
+ /* __send_cap drops i_lock */
+ delayed += __send_cap(mdsc, cap, CEPH_CAP_OP_UPDATE, used, want,
+ retain, flushing, NULL);
+ goto retry; /* retake i_lock and restart our cap scan. */
+ }
+
+ /*
+ * Reschedule delayed caps release if we delayed anything,
+ * otherwise cancel.
+ */
+ if (delayed && is_delayed)
+ force_requeue = 1; /* __send_cap delayed release; requeue */
+ if (!delayed && !is_delayed)
+ __cap_delay_cancel(mdsc, ci);
+ else if (!is_delayed || force_requeue)
+ __cap_delay_requeue(mdsc, ci);
+
+ spin_unlock(&inode->i_lock);
+
+ if (session && drop_session_lock)
+ mutex_unlock(&session->s_mutex);
+ if (took_snap_rwsem)
+ up_read(&mdsc->snap_rwsem);
+}
+
+/*
+ * Try to flush dirty caps back to the auth mds.
+ */
+static int try_flush_caps(struct inode *inode, struct ceph_mds_session *session,
+ unsigned *flush_tid)
+{
+ struct ceph_mds_client *mdsc = &ceph_client(inode->i_sb)->mdsc;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ int unlock_session = session ? 0 : 1;
+ int flushing = 0;
+
+retry:
+ spin_lock(&inode->i_lock);
+ if (ci->i_dirty_caps && ci->i_auth_cap) {
+ struct ceph_cap *cap = ci->i_auth_cap;
+ int used = __ceph_caps_used(ci);
+ int want = __ceph_caps_wanted(ci);
+ int delayed;
+
+ if (!session) {
+ spin_unlock(&inode->i_lock);
+ session = cap->session;
+ mutex_lock(&session->s_mutex);
+ goto retry;
+ }
+ BUG_ON(session != cap->session);
+ if (cap->session->s_state < CEPH_MDS_SESSION_OPEN)
+ goto out;
+
+ flushing = __mark_caps_flushing(inode, session);
+
+ /* __send_cap drops i_lock */
+ delayed = __send_cap(mdsc, cap, CEPH_CAP_OP_FLUSH, used, want,
+ cap->issued | cap->implemented, flushing,
+ flush_tid);
+ if (!delayed)
+ goto out_unlocked;
+
+ spin_lock(&inode->i_lock);
+ __cap_delay_requeue(mdsc, ci);
+ }
+out:
+ spin_unlock(&inode->i_lock);
+out_unlocked:
+ if (session && unlock_session)
+ mutex_unlock(&session->s_mutex);
+ return flushing;
+}
+
+/*
+ * Return true if we've flushed caps through the given flush_tid.
+ */
+static int caps_are_flushed(struct inode *inode, unsigned tid)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ int dirty, i, ret = 1;
+
+ spin_lock(&inode->i_lock);
+ dirty = __ceph_caps_dirty(ci);
+ for (i = 0; i < CEPH_CAP_BITS; i++)
+ if ((ci->i_flushing_caps & (1 << i)) &&
+ ci->i_cap_flush_tid[i] <= tid) {
+ /* still flushing this bit */
+ ret = 0;
+ break;
+ }
+ spin_unlock(&inode->i_lock);
+ return ret;
+}
+
+/*
+ * Wait on any unsafe replies for the given inode. First wait on the
+ * newest request, and make that the upper bound. Then, if there are
+ * more requests, keep waiting on the oldest as long as it is still older
+ * than the original request.
+ */
+static void sync_write_wait(struct inode *inode)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct list_head *head = &ci->i_unsafe_writes;
+ struct ceph_osd_request *req;
+ u64 last_tid;
+
+ spin_lock(&ci->i_unsafe_lock);
+ if (list_empty(head))
+ goto out;
+
+ /* set upper bound as _last_ entry in chain */
+ req = list_entry(head->prev, struct ceph_osd_request,
+ r_unsafe_item);
+ last_tid = req->r_tid;
+
+ do {
+ ceph_osdc_get_request(req);
+ spin_unlock(&ci->i_unsafe_lock);
+ dout("sync_write_wait on tid %llu (until %llu)\n",
+ req->r_tid, last_tid);
+ wait_for_completion(&req->r_safe_completion);
+ spin_lock(&ci->i_unsafe_lock);
+ ceph_osdc_put_request(req);
+
+ /*
+ * from here on look at first entry in chain, since we
+ * only want to wait for anything older than last_tid
+ */
+ if (list_empty(head))
+ break;
+ req = list_entry(head->next, struct ceph_osd_request,
+ r_unsafe_item);
+ } while (req->r_tid < last_tid);
+out:
+ spin_unlock(&ci->i_unsafe_lock);
+}
+
+int ceph_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+ struct inode *inode = dentry->d_inode;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ unsigned flush_tid;
+ int ret;
+ int dirty;
+
+ dout("fsync %p%s\n", inode, datasync ? " datasync" : "");
+ sync_write_wait(inode);
+
+ ret = filemap_write_and_wait(inode->i_mapping);
+ if (ret < 0)
+ return ret;
+
+ dirty = try_flush_caps(inode, NULL, &flush_tid);
+ dout("fsync dirty caps are %s\n", ceph_cap_string(dirty));
+
+ /*
+ * only wait on non-file metadata writeback (the mds
+ * can recover size and mtime, so we don't need to
+ * wait for that)
+ */
+ if (!datasync && (dirty & ~CEPH_CAP_ANY_FILE_WR)) {
+ dout("fsync waiting for flush_tid %u\n", flush_tid);
+ ret = wait_event_interruptible(ci->i_cap_wq,
+ caps_are_flushed(inode, flush_tid));
+ }
+
+ dout("fsync %p%s done\n", inode, datasync ? " datasync" : "");
+ return ret;
+}
+
+/*
+ * Flush any dirty caps back to the mds. If we aren't asked to wait,
+ * queue inode for flush but don't do so immediately, because we can
+ * get by with fewer MDS messages if we wait for data writeback to
+ * complete first.
+ */
+int ceph_write_inode(struct inode *inode, int wait)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ unsigned flush_tid;
+ int err = 0;
+ int dirty;
+
+ dout("write_inode %p wait=%d\n", inode, wait);
+ if (wait) {
+ dirty = try_flush_caps(inode, NULL, &flush_tid);
+ if (dirty)
+ err = wait_event_interruptible(ci->i_cap_wq,
+ caps_are_flushed(inode, flush_tid));
+ } else {
+ struct ceph_mds_client *mdsc = &ceph_client(inode->i_sb)->mdsc;
+
+ spin_lock(&inode->i_lock);
+ if (__ceph_caps_dirty(ci))
+ __cap_delay_requeue_front(mdsc, ci);
+ spin_unlock(&inode->i_lock);
+ }
+ return err;
+}
+
+/*
+ * After a recovering MDS goes active, we need to resend any caps
+ * we were flushing.
+ *
+ * Caller holds session->s_mutex.
+ */
+static void kick_flushing_capsnaps(struct ceph_mds_client *mdsc,
+ struct ceph_mds_session *session)
+{
+ struct ceph_cap_snap *capsnap;
+
+ dout("kick_flushing_capsnaps mds%d\n", session->s_mds);
+ list_for_each_entry(capsnap, &session->s_cap_snaps_flushing,
+ flushing_item) {
+ struct ceph_inode_info *ci = capsnap->ci;
+ struct inode *inode = &ci->vfs_inode;
+ struct ceph_cap *cap;
+
+ spin_lock(&inode->i_lock);
+ cap = ci->i_auth_cap;
+ if (cap && cap->session == session) {
+ dout("kick_flushing_caps %p cap %p capsnap %p\n", inode,
+ cap, capsnap);
+ __ceph_flush_snaps(ci, &session);
+ } else {
+ pr_err("%p auth cap %p not mds%d ???\n", inode,
+ cap, session->s_mds);
+ spin_unlock(&inode->i_lock);
+ }
+ }
+}
+
+void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc,
+ struct ceph_mds_session *session)
+{
+ struct ceph_inode_info *ci;
+
+ kick_flushing_capsnaps(mdsc, session);
+
+ dout("kick_flushing_caps mds%d\n", session->s_mds);
+ list_for_each_entry(ci, &session->s_cap_flushing, i_flushing_item) {
+ struct inode *inode = &ci->vfs_inode;
+ struct ceph_cap *cap;
+ int delayed = 0;
+
+ spin_lock(&inode->i_lock);
+ cap = ci->i_auth_cap;
+ if (cap && cap->session == session) {
+ dout("kick_flushing_caps %p cap %p %s\n", inode,
+ cap, ceph_cap_string(ci->i_flushing_caps));
+ delayed = __send_cap(mdsc, cap, CEPH_CAP_OP_FLUSH,
+ __ceph_caps_used(ci),
+ __ceph_caps_wanted(ci),
+ cap->issued | cap->implemented,
+ ci->i_flushing_caps, NULL);
+ if (delayed) {
+ spin_lock(&inode->i_lock);
+ __cap_delay_requeue(mdsc, ci);
+ spin_unlock(&inode->i_lock);
+ }
+ } else {
+ pr_err("%p auth cap %p not mds%d ???\n", inode,
+ cap, session->s_mds);
+ spin_unlock(&inode->i_lock);
+ }
+ }
+}
+
+
+/*
+ * Take references to capabilities we hold, so that we don't release
+ * them to the MDS prematurely.
+ *
+ * Protected by i_lock.
+ */
+static void __take_cap_refs(struct ceph_inode_info *ci, int got)
+{
+ if (got & CEPH_CAP_PIN)
+ ci->i_pin_ref++;
+ if (got & CEPH_CAP_FILE_RD)
+ ci->i_rd_ref++;
+ if (got & CEPH_CAP_FILE_CACHE)
+ ci->i_rdcache_ref++;
+ if (got & CEPH_CAP_FILE_WR)
+ ci->i_wr_ref++;
+ if (got & CEPH_CAP_FILE_BUFFER) {
+ if (ci->i_wrbuffer_ref == 0)
+ igrab(&ci->vfs_inode);
+ ci->i_wrbuffer_ref++;
+ dout("__take_cap_refs %p wrbuffer %d -> %d (?)\n",
+ &ci->vfs_inode, ci->i_wrbuffer_ref-1, ci->i_wrbuffer_ref);
+ }
+}
+
+/*
+ * Try to grab cap references. Specify those refs we @want, and the
+ * minimal set we @need. Also include the larger offset we are writing
+ * to (when applicable), and check against max_size here as well.
+ * Note that caller is responsible for ensuring max_size increases are
+ * requested from the MDS.
+ */
+static int try_get_cap_refs(struct ceph_inode_info *ci, int need, int want,
+ int *got, loff_t endoff, int *check_max, int *err)
+{
+ struct inode *inode = &ci->vfs_inode;
+ int ret = 0;
+ int have, implemented;
+
+ dout("get_cap_refs %p need %s want %s\n", inode,
+ ceph_cap_string(need), ceph_cap_string(want));
+ spin_lock(&inode->i_lock);
+
+ /* make sure we _have_ some caps! */
+ if (!__ceph_is_any_caps(ci)) {
+ dout("get_cap_refs %p no real caps\n", inode);
+ *err = -EBADF;
+ ret = 1;
+ goto out;
+ }
+
+ if (need & CEPH_CAP_FILE_WR) {
+ if (endoff >= 0 && endoff > (loff_t)ci->i_max_size) {
+ dout("get_cap_refs %p endoff %llu > maxsize %llu\n",
+ inode, endoff, ci->i_max_size);
+ if (endoff > ci->i_wanted_max_size) {
+ *check_max = 1;
+ ret = 1;
+ }
+ goto out;
+ }
+ /*
+ * If a sync write is in progress, we must wait, so that we
+ * can get a final snapshot value for size+mtime.
+ */
+ if (__ceph_have_pending_cap_snap(ci)) {
+ dout("get_cap_refs %p cap_snap_pending\n", inode);
+ goto out;
+ }
+ }
+ have = __ceph_caps_issued(ci, &implemented);
+
+ /*
+ * disallow writes while a truncate is pending
+ */
+ if (ci->i_truncate_pending)
+ have &= ~CEPH_CAP_FILE_WR;
+
+ if ((have & need) == need) {
+ /*
+ * Look at (implemented & ~have & not) so that we keep waiting
+ * on transition from wanted -> needed caps. This is needed
+ * for WRBUFFER|WR -> WR to avoid a new WR sync write from
+ * going before a prior buffered writeback happens.
+ */
+ int not = want & ~(have & need);
+ int revoking = implemented & ~have;
+ dout("get_cap_refs %p have %s but not %s (revoking %s)\n",
+ inode, ceph_cap_string(have), ceph_cap_string(not),
+ ceph_cap_string(revoking));
+ if ((revoking & not) == 0) {
+ *got = need | (have & want);
+ __take_cap_refs(ci, *got);
+ ret = 1;
+ }
+ } else {
+ dout("get_cap_refs %p have %s needed %s\n", inode,
+ ceph_cap_string(have), ceph_cap_string(need));
+ }
+out:
+ spin_unlock(&inode->i_lock);
+ dout("get_cap_refs %p ret %d got %s\n", inode,
+ ret, ceph_cap_string(*got));
+ return ret;
+}
+
+/*
+ * Check the offset we are writing up to against our current
+ * max_size. If necessary, tell the MDS we want to write to
+ * a larger offset.
+ */
+static void check_max_size(struct inode *inode, loff_t endoff)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ int check = 0;
+
+ /* do we need to explicitly request a larger max_size? */
+ spin_lock(&inode->i_lock);
+ if ((endoff >= ci->i_max_size ||
+ endoff > (inode->i_size << 1)) &&
+ endoff > ci->i_wanted_max_size) {
+ dout("write %p at large endoff %llu, req max_size\n",
+ inode, endoff);
+ ci->i_wanted_max_size = endoff;
+ check = 1;
+ }
+ spin_unlock(&inode->i_lock);
+ if (check)
+ ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL);
+}
+
+/*
+ * Wait for caps, and take cap references. If we can't get a WR cap
+ * due to a small max_size, make sure we check_max_size (and possibly
+ * ask the mds) so we don't get hung up indefinitely.
+ */
+int ceph_get_caps(struct ceph_inode_info *ci, int need, int want, int *got,
+ loff_t endoff)
+{
+ int check_max, ret, err;
+
+retry:
+ if (endoff > 0)
+ check_max_size(&ci->vfs_inode, endoff);
+ check_max = 0;
+ err = 0;
+ ret = wait_event_interruptible(ci->i_cap_wq,
+ try_get_cap_refs(ci, need, want,
+ got, endoff,
+ &check_max, &err));
+ if (err)
+ ret = err;
+ if (check_max)
+ goto retry;
+ return ret;
+}
+
+/*
+ * Take cap refs. Caller must already know we hold at least one ref
+ * on the caps in question or we don't know this is safe.
+ */
+void ceph_get_cap_refs(struct ceph_inode_info *ci, int caps)
+{
+ spin_lock(&ci->vfs_inode.i_lock);
+ __take_cap_refs(ci, caps);
+ spin_unlock(&ci->vfs_inode.i_lock);
+}
+
+/*
+ * Release cap refs.
+ *
+ * If we released the last ref on any given cap, call ceph_check_caps
+ * to release (or schedule a release).
+ *
+ * If we are releasing a WR cap (from a sync write), finalize any affected
+ * cap_snap, and wake up any waiters.
+ */
+void ceph_put_cap_refs(struct ceph_inode_info *ci, int had)
+{
+ struct inode *inode = &ci->vfs_inode;
+ int last = 0, put = 0, flushsnaps = 0, wake = 0;
+ struct ceph_cap_snap *capsnap;
+
+ spin_lock(&inode->i_lock);
+ if (had & CEPH_CAP_PIN)
+ --ci->i_pin_ref;
+ if (had & CEPH_CAP_FILE_RD)
+ if (--ci->i_rd_ref == 0)
+ last++;
+ if (had & CEPH_CAP_FILE_CACHE)
+ if (--ci->i_rdcache_ref == 0)
+ last++;
+ if (had & CEPH_CAP_FILE_BUFFER) {
+ if (--ci->i_wrbuffer_ref == 0) {
+ last++;
+ put++;
+ }
+ dout("put_cap_refs %p wrbuffer %d -> %d (?)\n",
+ inode, ci->i_wrbuffer_ref+1, ci->i_wrbuffer_ref);
+ }
+ if (had & CEPH_CAP_FILE_WR)
+ if (--ci->i_wr_ref == 0) {
+ last++;
+ if (!list_empty(&ci->i_cap_snaps)) {
+ capsnap = list_first_entry(&ci->i_cap_snaps,
+ struct ceph_cap_snap,
+ ci_item);
+ if (capsnap->writing) {
+ capsnap->writing = 0;
+ flushsnaps =
+ __ceph_finish_cap_snap(ci,
+ capsnap);
+ wake = 1;
+ }
+ }
+ }
+ spin_unlock(&inode->i_lock);
+
+ dout("put_cap_refs %p had %s %s\n", inode, ceph_cap_string(had),
+ last ? "last" : "");
+
+ if (last && !flushsnaps)
+ ceph_check_caps(ci, 0, NULL);
+ else if (flushsnaps)
+ ceph_flush_snaps(ci);
+ if (wake)
+ wake_up(&ci->i_cap_wq);
+ if (put)
+ iput(inode);
+}
+
+/*
+ * Release @nr WRBUFFER refs on dirty pages for the given @snapc snap
+ * context. Adjust per-snap dirty page accounting as appropriate.
+ * Once all dirty data for a cap_snap is flushed, flush snapped file
+ * metadata back to the MDS. If we dropped the last ref, call
+ * ceph_check_caps.
+ */
+void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr,
+ struct ceph_snap_context *snapc)
+{
+ struct inode *inode = &ci->vfs_inode;
+ int last = 0;
+ int last_snap = 0;
+ int found = 0;
+ struct ceph_cap_snap *capsnap = NULL;
+
+ spin_lock(&inode->i_lock);
+ ci->i_wrbuffer_ref -= nr;
+ last = !ci->i_wrbuffer_ref;
+
+ if (ci->i_head_snapc == snapc) {
+ ci->i_wrbuffer_ref_head -= nr;
+ if (!ci->i_wrbuffer_ref_head) {
+ ceph_put_snap_context(ci->i_head_snapc);
+ ci->i_head_snapc = NULL;
+ }
+ dout("put_wrbuffer_cap_refs on %p head %d/%d -> %d/%d %s\n",
+ inode,
+ ci->i_wrbuffer_ref+nr, ci->i_wrbuffer_ref_head+nr,
+ ci->i_wrbuffer_ref, ci->i_wrbuffer_ref_head,
+ last ? " LAST" : "");
+ } else {
+ list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) {
+ if (capsnap->context == snapc) {
+ found = 1;
+ capsnap->dirty_pages -= nr;
+ last_snap = !capsnap->dirty_pages;
+ break;
+ }
+ }
+ BUG_ON(!found);
+ dout("put_wrbuffer_cap_refs on %p cap_snap %p "
+ " snap %lld %d/%d -> %d/%d %s%s\n",
+ inode, capsnap, capsnap->context->seq,
+ ci->i_wrbuffer_ref+nr, capsnap->dirty_pages + nr,
+ ci->i_wrbuffer_ref, capsnap->dirty_pages,
+ last ? " (wrbuffer last)" : "",
+ last_snap ? " (capsnap last)" : "");
+ }
+
+ spin_unlock(&inode->i_lock);
+
+ if (last) {
+ ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL);
+ iput(inode);
+ } else if (last_snap) {
+ ceph_flush_snaps(ci);
+ wake_up(&ci->i_cap_wq);
+ }
+}
+
+/*
+ * Handle a cap GRANT message from the MDS. (Note that a GRANT may
+ * actually be a revocation if it specifies a smaller cap set.)
+ *
+ * caller holds s_mutex.
+ * return value:
+ * 0 - ok
+ * 1 - check_caps on auth cap only (writeback)
+ * 2 - check_caps (ack revoke)
+ */
+static int handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
+ struct ceph_mds_session *session,
+ struct ceph_cap *cap,
+ struct ceph_buffer *xattr_buf)
+ __releases(inode->i_lock)
+
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ int mds = session->s_mds;
+ int seq = le32_to_cpu(grant->seq);
+ int newcaps = le32_to_cpu(grant->caps);
+ int issued, implemented, used, wanted, dirty;
+ u64 size = le64_to_cpu(grant->size);
+ u64 max_size = le64_to_cpu(grant->max_size);
+ struct timespec mtime, atime, ctime;
+ int reply = 0;
+ int wake = 0;
+ int writeback = 0;
+ int revoked_rdcache = 0;
+ int invalidate_async = 0;
+ int tried_invalidate = 0;
+ int ret;
+
+ dout("handle_cap_grant inode %p cap %p mds%d seq %d %s\n",
+ inode, cap, mds, seq, ceph_cap_string(newcaps));
+ dout(" size %llu max_size %llu, i_size %llu\n", size, max_size,
+ inode->i_size);
+
+ /*
+ * If CACHE is being revoked, and we have no dirty buffers,
+ * try to invalidate (once). (If there are dirty buffers, we
+ * will invalidate _after_ writeback.)
+ */
+restart:
+ if (((cap->issued & ~newcaps) & CEPH_CAP_FILE_CACHE) &&
+ !ci->i_wrbuffer_ref && !tried_invalidate) {
+ dout("CACHE invalidation\n");
+ spin_unlock(&inode->i_lock);
+ tried_invalidate = 1;
+
+ ret = invalidate_inode_pages2(&inode->i_data);
+ spin_lock(&inode->i_lock);
+ if (ret < 0) {
+ /* there were locked pages.. invalidate later
+ in a separate thread. */
+ if (ci->i_rdcache_revoking != ci->i_rdcache_gen) {
+ invalidate_async = 1;
+ ci->i_rdcache_revoking = ci->i_rdcache_gen;
+ }
+ } else {
+ /* we successfully invalidated those pages */
+ revoked_rdcache = 1;
+ ci->i_rdcache_gen = 0;
+ ci->i_rdcache_revoking = 0;
+ }
+ goto restart;
+ }
+
+ /* side effects now are allowed */
+
+ issued = __ceph_caps_issued(ci, &implemented);
+ issued |= implemented | __ceph_caps_dirty(ci);
+
+ cap->gen = session->s_cap_gen;
+
+ __check_cap_issue(ci, cap, newcaps);
+
+ if ((issued & CEPH_CAP_AUTH_EXCL) == 0) {
+ inode->i_mode = le32_to_cpu(grant->mode);
+ inode->i_uid = le32_to_cpu(grant->uid);
+ inode->i_gid = le32_to_cpu(grant->gid);
+ dout("%p mode 0%o uid.gid %d.%d\n", inode, inode->i_mode,
+ inode->i_uid, inode->i_gid);
+ }
+
+ if ((issued & CEPH_CAP_LINK_EXCL) == 0)
+ inode->i_nlink = le32_to_cpu(grant->nlink);
+
+ if ((issued & CEPH_CAP_XATTR_EXCL) == 0 && grant->xattr_len) {
+ int len = le32_to_cpu(grant->xattr_len);
+ u64 version = le64_to_cpu(grant->xattr_version);
+
+ if (version > ci->i_xattrs.version) {
+ dout(" got new xattrs v%llu on %p len %d\n",
+ version, inode, len);
+ if (ci->i_xattrs.blob)
+ ceph_buffer_put(ci->i_xattrs.blob);
+ ci->i_xattrs.blob = ceph_buffer_get(xattr_buf);
+ ci->i_xattrs.version = version;
+ }
+ }
+
+ /* size/ctime/mtime/atime? */
+ ceph_fill_file_size(inode, issued,
+ le32_to_cpu(grant->truncate_seq),
+ le64_to_cpu(grant->truncate_size), size);
+ ceph_decode_timespec(&mtime, &grant->mtime);
+ ceph_decode_timespec(&atime, &grant->atime);
+ ceph_decode_timespec(&ctime, &grant->ctime);
+ ceph_fill_file_time(inode, issued,
+ le32_to_cpu(grant->time_warp_seq), &ctime, &mtime,
+ &atime);
+
+ /* max size increase? */
+ if (max_size != ci->i_max_size) {
+ dout("max_size %lld -> %llu\n", ci->i_max_size, max_size);
+ ci->i_max_size = max_size;
+ if (max_size >= ci->i_wanted_max_size) {
+ ci->i_wanted_max_size = 0; /* reset */
+ ci->i_requested_max_size = 0;
+ }
+ wake = 1;
+ }
+
+ /* check cap bits */
+ wanted = __ceph_caps_wanted(ci);
+ used = __ceph_caps_used(ci);
+ dirty = __ceph_caps_dirty(ci);
+ dout(" my wanted = %s, used = %s, dirty %s\n",
+ ceph_cap_string(wanted),
+ ceph_cap_string(used),
+ ceph_cap_string(dirty));
+ if (wanted != le32_to_cpu(grant->wanted)) {
+ dout("mds wanted %s -> %s\n",
+ ceph_cap_string(le32_to_cpu(grant->wanted)),
+ ceph_cap_string(wanted));
+ grant->wanted = cpu_to_le32(wanted);
+ }
+
+ cap->seq = seq;
+
+ /* file layout may have changed */
+ ci->i_layout = grant->layout;
+
+ /* revocation, grant, or no-op? */
+ if (cap->issued & ~newcaps) {
+ dout("revocation: %s -> %s\n", ceph_cap_string(cap->issued),
+ ceph_cap_string(newcaps));
+ if ((used & ~newcaps) & CEPH_CAP_FILE_BUFFER)
+ writeback = 1; /* will delay ack */
+ else if (dirty & ~newcaps)
+ reply = 1; /* initiate writeback in check_caps */
+ else if (((used & ~newcaps) & CEPH_CAP_FILE_CACHE) == 0 ||
+ revoked_rdcache)
+ reply = 2; /* send revoke ack in check_caps */
+ cap->issued = newcaps;
+ } else if (cap->issued == newcaps) {
+ dout("caps unchanged: %s -> %s\n",
+ ceph_cap_string(cap->issued), ceph_cap_string(newcaps));
+ } else {
+ dout("grant: %s -> %s\n", ceph_cap_string(cap->issued),
+ ceph_cap_string(newcaps));
+ cap->issued = newcaps;
+ cap->implemented |= newcaps; /* add bits only, to
+ * avoid stepping on a
+ * pending revocation */
+ wake = 1;
+ }
+
+ spin_unlock(&inode->i_lock);
+ if (writeback) {
+ /*
+ * queue inode for writeback: we can't actually call
+ * filemap_write_and_wait, etc. from message handler
+ * context.
+ */
+ dout("queueing %p for writeback\n", inode);
+ if (ceph_queue_writeback(inode))
+ igrab(inode);
+ }
+ if (invalidate_async) {
+ dout("queueing %p for page invalidation\n", inode);
+ if (ceph_queue_page_invalidation(inode))
+ igrab(inode);
+ }
+ if (wake)
+ wake_up(&ci->i_cap_wq);
+ return reply;
+}
+
+/*
+ * Handle FLUSH_ACK from MDS, indicating that metadata we sent to the
+ * MDS has been safely committed.
+ */
+static void handle_cap_flush_ack(struct inode *inode,
+ struct ceph_mds_caps *m,
+ struct ceph_mds_session *session,
+ struct ceph_cap *cap)
+ __releases(inode->i_lock)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_mds_client *mdsc = &ceph_client(inode->i_sb)->mdsc;
+ unsigned seq = le32_to_cpu(m->seq);
+ int dirty = le32_to_cpu(m->dirty);
+ int cleaned = 0;
+ u64 flush_tid = le64_to_cpu(m->client_tid);
+ int drop = 0;
+ int i;
+
+ for (i = 0; i < CEPH_CAP_BITS; i++)
+ if ((dirty & (1 << i)) &&
+ flush_tid == ci->i_cap_flush_tid[i])
+ cleaned |= 1 << i;
+
+ dout("handle_cap_flush_ack inode %p mds%d seq %d on %s cleaned %s,"
+ " flushing %s -> %s\n",
+ inode, session->s_mds, seq, ceph_cap_string(dirty),
+ ceph_cap_string(cleaned), ceph_cap_string(ci->i_flushing_caps),
+ ceph_cap_string(ci->i_flushing_caps & ~cleaned));
+
+ if (ci->i_flushing_caps == (ci->i_flushing_caps & ~cleaned))
+ goto out;
+
+ ci->i_flushing_caps &= ~cleaned;
+
+ spin_lock(&mdsc->cap_dirty_lock);
+ if (ci->i_flushing_caps == 0) {
+ list_del_init(&ci->i_flushing_item);
+ if (!list_empty(&session->s_cap_flushing))
+ dout(" mds%d still flushing cap on %p\n",
+ session->s_mds,
+ &list_entry(session->s_cap_flushing.next,
+ struct ceph_inode_info,
+ i_flushing_item)->vfs_inode);
+ mdsc->num_cap_flushing--;
+ wake_up(&mdsc->cap_flushing_wq);
+ dout(" inode %p now !flushing\n", inode);
+
+ if (ci->i_dirty_caps == 0) {
+ dout(" inode %p now clean\n", inode);
+ BUG_ON(!list_empty(&ci->i_dirty_item));
+ drop = 1;
+ } else {
+ BUG_ON(list_empty(&ci->i_dirty_item));
+ }
+ }
+ spin_unlock(&mdsc->cap_dirty_lock);
+ wake_up(&ci->i_cap_wq);
+
+out:
+ spin_unlock(&inode->i_lock);
+ if (drop)
+ iput(inode);
+}
+
+/*
+ * Handle FLUSHSNAP_ACK. MDS has flushed snap data to disk and we can
+ * throw away our cap_snap.
+ *
+ * Caller hold s_mutex.
+ */
+static void handle_cap_flushsnap_ack(struct inode *inode,
+ struct ceph_mds_caps *m,
+ struct ceph_mds_session *session)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ u64 follows = le64_to_cpu(m->snap_follows);
+ u64 flush_tid = le64_to_cpu(m->client_tid);
+ struct ceph_cap_snap *capsnap;
+ int drop = 0;
+
+ dout("handle_cap_flushsnap_ack inode %p ci %p mds%d follows %lld\n",
+ inode, ci, session->s_mds, follows);
+
+ spin_lock(&inode->i_lock);
+ list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) {
+ if (capsnap->follows == follows) {
+ if (capsnap->flush_tid != flush_tid) {
+ dout(" cap_snap %p follows %lld tid %lld !="
+ " %lld\n", capsnap, follows,
+ flush_tid, capsnap->flush_tid);
+ break;
+ }
+ WARN_ON(capsnap->dirty_pages || capsnap->writing);
+ dout(" removing cap_snap %p follows %lld\n",
+ capsnap, follows);
+ ceph_put_snap_context(capsnap->context);
+ list_del(&capsnap->ci_item);
+ list_del(&capsnap->flushing_item);
+ ceph_put_cap_snap(capsnap);
+ drop = 1;
+ break;
+ } else {
+ dout(" skipping cap_snap %p follows %lld\n",
+ capsnap, capsnap->follows);
+ }
+ }
+ spin_unlock(&inode->i_lock);
+ if (drop)
+ iput(inode);
+}
+
+/*
+ * Handle TRUNC from MDS, indicating file truncation.
+ *
+ * caller hold s_mutex.
+ */
+static void handle_cap_trunc(struct inode *inode,
+ struct ceph_mds_caps *trunc,
+ struct ceph_mds_session *session)
+ __releases(inode->i_lock)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ int mds = session->s_mds;
+ int seq = le32_to_cpu(trunc->seq);
+ u32 truncate_seq = le32_to_cpu(trunc->truncate_seq);
+ u64 truncate_size = le64_to_cpu(trunc->truncate_size);
+ u64 size = le64_to_cpu(trunc->size);
+ int implemented = 0;
+ int dirty = __ceph_caps_dirty(ci);
+ int issued = __ceph_caps_issued(ceph_inode(inode), &implemented);
+ int queue_trunc = 0;
+
+ issued |= implemented | dirty;
+
+ dout("handle_cap_trunc inode %p mds%d seq %d to %lld seq %d\n",
+ inode, mds, seq, truncate_size, truncate_seq);
+ queue_trunc = ceph_fill_file_size(inode, issued,
+ truncate_seq, truncate_size, size);
+ spin_unlock(&inode->i_lock);
+
+ if (queue_trunc)
+ if (queue_work(ceph_client(inode->i_sb)->trunc_wq,
+ &ci->i_vmtruncate_work))
+ igrab(inode);
+}
+
+/*
+ * Handle EXPORT from MDS. Cap is being migrated _from_ this mds to a
+ * different one. If we are the most recent migration we've seen (as
+ * indicated by mseq), make note of the migrating cap bits for the
+ * duration (until we see the corresponding IMPORT).
+ *
+ * caller holds s_mutex
+ */
+static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex,
+ struct ceph_mds_session *session)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ int mds = session->s_mds;
+ unsigned mseq = le32_to_cpu(ex->migrate_seq);
+ struct ceph_cap *cap = NULL, *t;
+ struct rb_node *p;
+ int remember = 1;
+
+ dout("handle_cap_export inode %p ci %p mds%d mseq %d\n",
+ inode, ci, mds, mseq);
+
+ spin_lock(&inode->i_lock);
+
+ /* make sure we haven't seen a higher mseq */
+ for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
+ t = rb_entry(p, struct ceph_cap, ci_node);
+ if (ceph_seq_cmp(t->mseq, mseq) > 0) {
+ dout(" higher mseq on cap from mds%d\n",
+ t->session->s_mds);
+ remember = 0;
+ }
+ if (t->session->s_mds == mds)
+ cap = t;
+ }
+
+ if (cap) {
+ if (remember) {
+ /* make note */
+ ci->i_cap_exporting_mds = mds;
+ ci->i_cap_exporting_mseq = mseq;
+ ci->i_cap_exporting_issued = cap->issued;
+ }
+ __ceph_remove_cap(cap, NULL);
+ } else {
+ WARN_ON(!cap);
+ }
+
+ spin_unlock(&inode->i_lock);
+}
+
+/*
+ * Handle cap IMPORT. If there are temp bits from an older EXPORT,
+ * clean them up.
+ *
+ * caller holds s_mutex.
+ */
+static void handle_cap_import(struct ceph_mds_client *mdsc,
+ struct inode *inode, struct ceph_mds_caps *im,
+ struct ceph_mds_session *session,
+ void *snaptrace, int snaptrace_len)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ int mds = session->s_mds;
+ unsigned issued = le32_to_cpu(im->caps);
+ unsigned wanted = le32_to_cpu(im->wanted);
+ unsigned seq = le32_to_cpu(im->seq);
+ unsigned mseq = le32_to_cpu(im->migrate_seq);
+ u64 realmino = le64_to_cpu(im->realm);
+ u64 cap_id = le64_to_cpu(im->cap_id);
+
+ if (ci->i_cap_exporting_mds >= 0 &&
+ ceph_seq_cmp(ci->i_cap_exporting_mseq, mseq) < 0) {
+ dout("handle_cap_import inode %p ci %p mds%d mseq %d"
+ " - cleared exporting from mds%d\n",
+ inode, ci, mds, mseq,
+ ci->i_cap_exporting_mds);
+ ci->i_cap_exporting_issued = 0;
+ ci->i_cap_exporting_mseq = 0;
+ ci->i_cap_exporting_mds = -1;
+ } else {
+ dout("handle_cap_import inode %p ci %p mds%d mseq %d\n",
+ inode, ci, mds, mseq);
+ }
+
+ down_write(&mdsc->snap_rwsem);
+ ceph_update_snap_trace(mdsc, snaptrace, snaptrace+snaptrace_len,
+ false);
+ downgrade_write(&mdsc->snap_rwsem);
+ ceph_add_cap(inode, session, cap_id, -1,
+ issued, wanted, seq, mseq, realmino, CEPH_CAP_FLAG_AUTH,
+ NULL /* no caps context */);
+ try_flush_caps(inode, session, NULL);
+ up_read(&mdsc->snap_rwsem);
+}
+
+/*
+ * Handle a caps message from the MDS.
+ *
+ * Identify the appropriate session, inode, and call the right handler
+ * based on the cap op.
+ */
+void ceph_handle_caps(struct ceph_mds_session *session,
+ struct ceph_msg *msg)
+{
+ struct ceph_mds_client *mdsc = session->s_mdsc;
+ struct super_block *sb = mdsc->client->sb;
+ struct inode *inode;
+ struct ceph_cap *cap;
+ struct ceph_mds_caps *h;
+ int mds = le64_to_cpu(msg->hdr.src.name.num);
+ int op;
+ u32 seq;
+ struct ceph_vino vino;
+ u64 cap_id;
+ u64 size, max_size;
+ int check_caps = 0;
+ int r;
+
+ dout("handle_caps from mds%d\n", mds);
+
+ /* decode */
+ if (msg->front.iov_len < sizeof(*h))
+ goto bad;
+ h = msg->front.iov_base;
+ op = le32_to_cpu(h->op);
+ vino.ino = le64_to_cpu(h->ino);
+ vino.snap = CEPH_NOSNAP;
+ cap_id = le64_to_cpu(h->cap_id);
+ seq = le32_to_cpu(h->seq);
+ size = le64_to_cpu(h->size);
+ max_size = le64_to_cpu(h->max_size);
+
+ mutex_lock(&session->s_mutex);
+ session->s_seq++;
+ dout(" mds%d seq %lld cap seq %u\n", session->s_mds, session->s_seq,
+ (unsigned)seq);
+
+ /* lookup ino */
+ inode = ceph_find_inode(sb, vino);
+ dout(" op %s ino %llx.%llx inode %p\n", ceph_cap_op_name(op), vino.ino,
+ vino.snap, inode);
+ if (!inode) {
+ dout(" i don't have ino %llx\n", vino.ino);
+ goto done;
+ }
+
+ /* these will work even if we don't have a cap yet */
+ switch (op) {
+ case CEPH_CAP_OP_FLUSHSNAP_ACK:
+ handle_cap_flushsnap_ack(inode, h, session);
+ goto done;
+
+ case CEPH_CAP_OP_EXPORT:
+ handle_cap_export(inode, h, session);
+ goto done;
+
+ case CEPH_CAP_OP_IMPORT:
+ handle_cap_import(mdsc, inode, h, session,
+ msg->middle,
+ le32_to_cpu(h->snap_trace_len));
+ check_caps = 1; /* we may have sent a RELEASE to the old auth */
+ goto done;
+ }
+
+ /* the rest require a cap */
+ spin_lock(&inode->i_lock);
+ cap = __get_cap_for_mds(ceph_inode(inode), mds);
+ if (!cap) {
+ dout("no cap on %p ino %llx.%llx from mds%d, releasing\n",
+ inode, ceph_ino(inode), ceph_snap(inode), mds);
+ spin_unlock(&inode->i_lock);
+ goto done;
+ }
+
+ /* note that each of these drops i_lock for us */
+ switch (op) {
+ case CEPH_CAP_OP_REVOKE:
+ case CEPH_CAP_OP_GRANT:
+ r = handle_cap_grant(inode, h, session, cap, msg->middle);
+ if (r == 1)
+ ceph_check_caps(ceph_inode(inode),
+ CHECK_CAPS_NODELAY|CHECK_CAPS_AUTHONLY,
+ session);
+ else if (r == 2)
+ ceph_check_caps(ceph_inode(inode),
+ CHECK_CAPS_NODELAY,
+ session);
+ break;
+
+ case CEPH_CAP_OP_FLUSH_ACK:
+ handle_cap_flush_ack(inode, h, session, cap);
+ break;
+
+ case CEPH_CAP_OP_TRUNC:
+ handle_cap_trunc(inode, h, session);
+ break;
+
+ default:
+ spin_unlock(&inode->i_lock);
+ pr_err("ceph_handle_caps: unknown cap op %d %s\n", op,
+ ceph_cap_op_name(op));
+ }
+
+done:
+ mutex_unlock(&session->s_mutex);
+
+ if (check_caps)
+ ceph_check_caps(ceph_inode(inode), CHECK_CAPS_NODELAY, NULL);
+ if (inode)
+ iput(inode);
+ return;
+
+bad:
+ pr_err("ceph_handle_caps: corrupt message\n");
+ return;
+}
+
+/*
+ * Delayed work handler to process end of delayed cap release LRU list.
+ */
+void ceph_check_delayed_caps(struct ceph_mds_client *mdsc)
+{
+ struct ceph_inode_info *ci;
+ int flags = CHECK_CAPS_NODELAY;
+
+ dout("check_delayed_caps\n");
+ while (1) {
+ spin_lock(&mdsc->cap_delay_lock);
+ if (list_empty(&mdsc->cap_delay_list))
+ break;
+ ci = list_first_entry(&mdsc->cap_delay_list,
+ struct ceph_inode_info,
+ i_cap_delay_list);
+ if ((ci->i_ceph_flags & CEPH_I_FLUSH) == 0 &&
+ time_before(jiffies, ci->i_hold_caps_max))
+ break;
+ list_del_init(&ci->i_cap_delay_list);
+ spin_unlock(&mdsc->cap_delay_lock);
+ dout("check_delayed_caps on %p\n", &ci->vfs_inode);
+ ceph_check_caps(ci, flags, NULL);
+ }
+ spin_unlock(&mdsc->cap_delay_lock);
+}
+
+/*
+ * Flush all dirty caps to the mds
+ */
+void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc)
+{
+ struct ceph_inode_info *ci;
+ struct inode *inode;
+
+ dout("flush_dirty_caps\n");
+ spin_lock(&mdsc->cap_dirty_lock);
+ while (!list_empty(&mdsc->cap_dirty)) {
+ ci = list_first_entry(&mdsc->cap_dirty,
+ struct ceph_inode_info,
+ i_dirty_item);
+ inode = igrab(&ci->vfs_inode);
+ spin_unlock(&mdsc->cap_dirty_lock);
+ if (inode) {
+ ceph_check_caps(ci, CHECK_CAPS_NODELAY|CHECK_CAPS_FLUSH,
+ NULL);
+ iput(inode);
+ }
+ spin_lock(&mdsc->cap_dirty_lock);
+ }
+ spin_unlock(&mdsc->cap_dirty_lock);
+}
+
+/*
+ * Drop open file reference. If we were the last open file,
+ * we may need to release capabilities to the MDS (or schedule
+ * their delayed release).
+ */
+void ceph_put_fmode(struct ceph_inode_info *ci, int fmode)
+{
+ struct inode *inode = &ci->vfs_inode;
+ int last = 0;
+
+ spin_lock(&inode->i_lock);
+ dout("put_fmode %p fmode %d %d -> %d\n", inode, fmode,
+ ci->i_nr_by_mode[fmode], ci->i_nr_by_mode[fmode]-1);
+ BUG_ON(ci->i_nr_by_mode[fmode] == 0);
+ if (--ci->i_nr_by_mode[fmode] == 0)
+ last++;
+ spin_unlock(&inode->i_lock);
+
+ if (last && ci->i_vino.snap == CEPH_NOSNAP)
+ ceph_check_caps(ci, 0, NULL);
+}
+
+/*
+ * Helpers for embedding cap and dentry lease releases into mds
+ * requests.
+ *
+ * @force is used by dentry_release (below) to force inclusion of a
+ * record for the directory inode, even when there aren't any caps to
+ * drop.
+ */
+int ceph_encode_inode_release(void **p, struct inode *inode,
+ int mds, int drop, int unless, int force)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_cap *cap;
+ struct ceph_mds_request_release *rel = *p;
+ int ret = 0;
+
+ dout("encode_inode_release %p mds%d drop %s unless %s\n", inode,
+ mds, ceph_cap_string(drop), ceph_cap_string(unless));
+
+ spin_lock(&inode->i_lock);
+ cap = __get_cap_for_mds(ci, mds);
+ if (cap && __cap_is_valid(cap)) {
+ if (force ||
+ ((cap->issued & drop) &&
+ (cap->issued & unless) == 0)) {
+ if ((cap->issued & drop) &&
+ (cap->issued & unless) == 0) {
+ dout("encode_inode_release %p cap %p %s -> "
+ "%s\n", inode, cap,
+ ceph_cap_string(cap->issued),
+ ceph_cap_string(cap->issued & ~drop));
+ cap->issued &= ~drop;
+ cap->implemented &= ~drop;
+ if (ci->i_ceph_flags & CEPH_I_NODELAY) {
+ int wanted = __ceph_caps_wanted(ci);
+ dout(" wanted %s -> %s (act %s)\n",
+ ceph_cap_string(cap->mds_wanted),
+ ceph_cap_string(cap->mds_wanted &
+ ~wanted),
+ ceph_cap_string(wanted));
+ cap->mds_wanted &= wanted;
+ }
+ } else {
+ dout("encode_inode_release %p cap %p %s"
+ " (force)\n", inode, cap,
+ ceph_cap_string(cap->issued));
+ }
+
+ rel->ino = cpu_to_le64(ceph_ino(inode));
+ rel->cap_id = cpu_to_le64(cap->cap_id);
+ rel->seq = cpu_to_le32(cap->seq);
+ rel->issue_seq = cpu_to_le32(cap->issue_seq),
+ rel->mseq = cpu_to_le32(cap->mseq);
+ rel->caps = cpu_to_le32(cap->issued);
+ rel->wanted = cpu_to_le32(cap->mds_wanted);
+ rel->dname_len = 0;
+ rel->dname_seq = 0;
+ *p += sizeof(*rel);
+ ret = 1;
+ } else {
+ dout("encode_inode_release %p cap %p %s\n",
+ inode, cap, ceph_cap_string(cap->issued));
+ }
+ }
+ spin_unlock(&inode->i_lock);
+ return ret;
+}
+
+int ceph_encode_dentry_release(void **p, struct dentry *dentry,
+ int mds, int drop, int unless)
+{
+ struct inode *dir = dentry->d_parent->d_inode;
+ struct ceph_mds_request_release *rel = *p;
+ struct ceph_dentry_info *di = ceph_dentry(dentry);
+ int force = 0;
+ int ret;
+
+ /*
+ * force an record for the directory caps if we have a dentry lease.
+ * this is racy (can't take i_lock and d_lock together), but it
+ * doesn't have to be perfect; the mds will revoke anything we don't
+ * release.
+ */
+ spin_lock(&dentry->d_lock);
+ if (di->lease_session && di->lease_session->s_mds == mds)
+ force = 1;
+ spin_unlock(&dentry->d_lock);
+
+ ret = ceph_encode_inode_release(p, dir, mds, drop, unless, force);
+
+ spin_lock(&dentry->d_lock);
+ if (ret && di->lease_session && di->lease_session->s_mds == mds) {
+ dout("encode_dentry_release %p mds%d seq %d\n",
+ dentry, mds, (int)di->lease_seq);
+ rel->dname_len = cpu_to_le32(dentry->d_name.len);
+ memcpy(*p, dentry->d_name.name, dentry->d_name.len);
+ *p += dentry->d_name.len;
+ rel->dname_seq = cpu_to_le32(di->lease_seq);
+ }
+ spin_unlock(&dentry->d_lock);
+ return ret;
+}
diff --git a/fs/ceph/ceph_debug.h b/fs/ceph/ceph_debug.h
new file mode 100644
index 000000000000..1818c2305610
--- /dev/null
+++ b/fs/ceph/ceph_debug.h
@@ -0,0 +1,37 @@
+#ifndef _FS_CEPH_DEBUG_H
+#define _FS_CEPH_DEBUG_H
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#ifdef CONFIG_CEPH_FS_PRETTYDEBUG
+
+/*
+ * wrap pr_debug to include a filename:lineno prefix on each line.
+ * this incurs some overhead (kernel size and execution time) due to
+ * the extra function call at each call site.
+ */
+
+# if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
+extern const char *ceph_file_part(const char *s, int len);
+# define dout(fmt, ...) \
+ pr_debug(" %12.12s:%-4d : " fmt, \
+ ceph_file_part(__FILE__, sizeof(__FILE__)), \
+ __LINE__, ##__VA_ARGS__)
+# else
+/* faux printk call just to see any compiler warnings. */
+# define dout(fmt, ...) do { \
+ if (0) \
+ printk(KERN_DEBUG fmt, ##__VA_ARGS__); \
+ } while (0)
+# endif
+
+#else
+
+/*
+ * or, just wrap pr_debug
+ */
+# define dout(fmt, ...) pr_debug(" " fmt, ##__VA_ARGS__)
+
+#endif
+
+#endif
diff --git a/fs/ceph/ceph_frag.c b/fs/ceph/ceph_frag.c
new file mode 100644
index 000000000000..ab6cf35c4091
--- /dev/null
+++ b/fs/ceph/ceph_frag.c
@@ -0,0 +1,21 @@
+/*
+ * Ceph 'frag' type
+ */
+#include "types.h"
+
+int ceph_frag_compare(__u32 a, __u32 b)
+{
+ unsigned va = ceph_frag_value(a);
+ unsigned vb = ceph_frag_value(b);
+ if (va < vb)
+ return -1;
+ if (va > vb)
+ return 1;
+ va = ceph_frag_bits(a);
+ vb = ceph_frag_bits(b);
+ if (va < vb)
+ return -1;
+ if (va > vb)
+ return 1;
+ return 0;
+}
diff --git a/fs/ceph/ceph_frag.h b/fs/ceph/ceph_frag.h
new file mode 100644
index 000000000000..793f50cb7c22
--- /dev/null
+++ b/fs/ceph/ceph_frag.h
@@ -0,0 +1,109 @@
+#ifndef _FS_CEPH_FRAG_H
+#define _FS_CEPH_FRAG_H
+
+/*
+ * "Frags" are a way to describe a subset of a 32-bit number space,
+ * using a mask and a value to match against that mask. Any given frag
+ * (subset of the number space) can be partitioned into 2^n sub-frags.
+ *
+ * Frags are encoded into a 32-bit word:
+ * 8 upper bits = "bits"
+ * 24 lower bits = "value"
+ * (We could go to 5+27 bits, but who cares.)
+ *
+ * We use the _most_ significant bits of the 24 bit value. This makes
+ * values logically sort.
+ *
+ * Unfortunately, because the "bits" field is still in the high bits, we
+ * can't sort encoded frags numerically. However, it does allow you
+ * to feed encoded frags as values into frag_contains_value.
+ */
+static inline __u32 ceph_frag_make(__u32 b, __u32 v)
+{
+ return (b << 24) |
+ (v & (0xffffffu << (24-b)) & 0xffffffu);
+}
+static inline __u32 ceph_frag_bits(__u32 f)
+{
+ return f >> 24;
+}
+static inline __u32 ceph_frag_value(__u32 f)
+{
+ return f & 0xffffffu;
+}
+static inline __u32 ceph_frag_mask(__u32 f)
+{
+ return (0xffffffu << (24-ceph_frag_bits(f))) & 0xffffffu;
+}
+static inline __u32 ceph_frag_mask_shift(__u32 f)
+{
+ return 24 - ceph_frag_bits(f);
+}
+
+static inline int ceph_frag_contains_value(__u32 f, __u32 v)
+{
+ return (v & ceph_frag_mask(f)) == ceph_frag_value(f);
+}
+static inline int ceph_frag_contains_frag(__u32 f, __u32 sub)
+{
+ /* is sub as specific as us, and contained by us? */
+ return ceph_frag_bits(sub) >= ceph_frag_bits(f) &&
+ (ceph_frag_value(sub) & ceph_frag_mask(f)) == ceph_frag_value(f);
+}
+
+static inline __u32 ceph_frag_parent(__u32 f)
+{
+ return ceph_frag_make(ceph_frag_bits(f) - 1,
+ ceph_frag_value(f) & (ceph_frag_mask(f) << 1));
+}
+static inline int ceph_frag_is_left_child(__u32 f)
+{
+ return ceph_frag_bits(f) > 0 &&
+ (ceph_frag_value(f) & (0x1000000 >> ceph_frag_bits(f))) == 0;
+}
+static inline int ceph_frag_is_right_child(__u32 f)
+{
+ return ceph_frag_bits(f) > 0 &&
+ (ceph_frag_value(f) & (0x1000000 >> ceph_frag_bits(f))) == 1;
+}
+static inline __u32 ceph_frag_sibling(__u32 f)
+{
+ return ceph_frag_make(ceph_frag_bits(f),
+ ceph_frag_value(f) ^ (0x1000000 >> ceph_frag_bits(f)));
+}
+static inline __u32 ceph_frag_left_child(__u32 f)
+{
+ return ceph_frag_make(ceph_frag_bits(f)+1, ceph_frag_value(f));
+}
+static inline __u32 ceph_frag_right_child(__u32 f)
+{
+ return ceph_frag_make(ceph_frag_bits(f)+1,
+ ceph_frag_value(f) | (0x1000000 >> (1+ceph_frag_bits(f))));
+}
+static inline __u32 ceph_frag_make_child(__u32 f, int by, int i)
+{
+ int newbits = ceph_frag_bits(f) + by;
+ return ceph_frag_make(newbits,
+ ceph_frag_value(f) | (i << (24 - newbits)));
+}
+static inline int ceph_frag_is_leftmost(__u32 f)
+{
+ return ceph_frag_value(f) == 0;
+}
+static inline int ceph_frag_is_rightmost(__u32 f)
+{
+ return ceph_frag_value(f) == ceph_frag_mask(f);
+}
+static inline __u32 ceph_frag_next(__u32 f)
+{
+ return ceph_frag_make(ceph_frag_bits(f),
+ ceph_frag_value(f) + (0x1000000 >> ceph_frag_bits(f)));
+}
+
+/*
+ * comparator to sort frags logically, as when traversing the
+ * number space in ascending order...
+ */
+int ceph_frag_compare(__u32 a, __u32 b);
+
+#endif
diff --git a/fs/ceph/ceph_fs.c b/fs/ceph/ceph_fs.c
new file mode 100644
index 000000000000..a950b4083577
--- /dev/null
+++ b/fs/ceph/ceph_fs.c
@@ -0,0 +1,104 @@
+/*
+ * Some non-inline ceph helpers
+ */
+#include "types.h"
+
+/*
+ * return true if @layout appears to be valid
+ */
+int ceph_file_layout_is_valid(const struct ceph_file_layout *layout)
+{
+ __u32 su = le32_to_cpu(layout->fl_stripe_unit);
+ __u32 sc = le32_to_cpu(layout->fl_stripe_count);
+ __u32 os = le32_to_cpu(layout->fl_object_size);
+
+ /* stripe unit, object size must be non-zero, 64k increment */
+ if (!su || (su & (CEPH_MIN_STRIPE_UNIT-1)))
+ return 0;
+ if (!os || (os & (CEPH_MIN_STRIPE_UNIT-1)))
+ return 0;
+ /* object size must be a multiple of stripe unit */
+ if (os < su || os % su)
+ return 0;
+ /* stripe count must be non-zero */
+ if (!sc)
+ return 0;
+ return 1;
+}
+
+
+int ceph_flags_to_mode(int flags)
+{
+#ifdef O_DIRECTORY /* fixme */
+ if ((flags & O_DIRECTORY) == O_DIRECTORY)
+ return CEPH_FILE_MODE_PIN;
+#endif
+#ifdef O_LAZY
+ if (flags & O_LAZY)
+ return CEPH_FILE_MODE_LAZY;
+#endif
+ if ((flags & O_APPEND) == O_APPEND)
+ flags |= O_WRONLY;
+
+ flags &= O_ACCMODE;
+ if ((flags & O_RDWR) == O_RDWR)
+ return CEPH_FILE_MODE_RDWR;
+ if ((flags & O_WRONLY) == O_WRONLY)
+ return CEPH_FILE_MODE_WR;
+ return CEPH_FILE_MODE_RD;
+}
+
+int ceph_caps_for_mode(int mode)
+{
+ switch (mode) {
+ case CEPH_FILE_MODE_PIN:
+ return CEPH_CAP_PIN;
+ case CEPH_FILE_MODE_RD:
+ return CEPH_CAP_PIN | CEPH_CAP_FILE_SHARED |
+ CEPH_CAP_FILE_RD | CEPH_CAP_FILE_CACHE;
+ case CEPH_FILE_MODE_RDWR:
+ return CEPH_CAP_PIN | CEPH_CAP_FILE_SHARED |
+ CEPH_CAP_FILE_EXCL |
+ CEPH_CAP_FILE_RD | CEPH_CAP_FILE_CACHE |
+ CEPH_CAP_FILE_WR | CEPH_CAP_FILE_BUFFER |
+ CEPH_CAP_AUTH_SHARED | CEPH_CAP_AUTH_EXCL |
+ CEPH_CAP_XATTR_SHARED | CEPH_CAP_XATTR_EXCL;
+ case CEPH_FILE_MODE_WR:
+ return CEPH_CAP_PIN | CEPH_CAP_FILE_SHARED |
+ CEPH_CAP_FILE_EXCL |
+ CEPH_CAP_FILE_WR | CEPH_CAP_FILE_BUFFER |
+ CEPH_CAP_AUTH_SHARED | CEPH_CAP_AUTH_EXCL |
+ CEPH_CAP_XATTR_SHARED | CEPH_CAP_XATTR_EXCL;
+ }
+ return 0;
+}
+
+/* Name hashing routines. Initial hash value */
+/* Hash courtesy of the R5 hash in reiserfs modulo sign bits */
+#define ceph_init_name_hash() 0
+
+/* partial hash update function. Assume roughly 4 bits per character */
+static unsigned long ceph_partial_name_hash(unsigned long c,
+ unsigned long prevhash)
+{
+ return (prevhash + (c << 4) + (c >> 4)) * 11;
+}
+
+/*
+ * Finally: cut down the number of bits to a int value (and try to avoid
+ * losing bits)
+ */
+static unsigned long ceph_end_name_hash(unsigned long hash)
+{
+ return hash & 0xffffffff;
+}
+
+/* Compute the hash for a name string. */
+unsigned int ceph_full_name_hash(const char *name, unsigned int len)
+{
+ unsigned long hash = ceph_init_name_hash();
+ while (len--)
+ hash = ceph_partial_name_hash(*name++, hash);
+ return ceph_end_name_hash(hash);
+}
+
diff --git a/fs/ceph/ceph_fs.h b/fs/ceph/ceph_fs.h
new file mode 100644
index 000000000000..ae523828c538
--- /dev/null
+++ b/fs/ceph/ceph_fs.h
@@ -0,0 +1,639 @@
+/*
+ * ceph_fs.h - Ceph constants and data types to share between kernel and
+ * user space.
+ *
+ * Most types in this file are defined as little-endian, and are
+ * primarily intended to describe data structures that pass over the
+ * wire or that are stored on disk.
+ *
+ * LGPL2
+ */
+
+#ifndef _FS_CEPH_CEPH_FS_H
+#define _FS_CEPH_CEPH_FS_H
+
+#include "msgr.h"
+#include "rados.h"
+
+/*
+ * Ceph release version
+ */
+#define CEPH_VERSION_MAJOR 0
+#define CEPH_VERSION_MINOR 17
+#define CEPH_VERSION_PATCH 0
+
+#define _CEPH_STRINGIFY(x) #x
+#define CEPH_STRINGIFY(x) _CEPH_STRINGIFY(x)
+#define CEPH_MAKE_VERSION(x, y, z) CEPH_STRINGIFY(x) "." CEPH_STRINGIFY(y) \
+ "." CEPH_STRINGIFY(z)
+#define CEPH_VERSION CEPH_MAKE_VERSION(CEPH_VERSION_MAJOR, \
+ CEPH_VERSION_MINOR, CEPH_VERSION_PATCH)
+
+/*
+ * subprotocol versions. when specific messages types or high-level
+ * protocols change, bump the affected components. we keep rev
+ * internal cluster protocols separately from the public,
+ * client-facing protocol.
+ */
+#define CEPH_OSD_PROTOCOL 7 /* cluster internal */
+#define CEPH_MDS_PROTOCOL 9 /* cluster internal */
+#define CEPH_MON_PROTOCOL 5 /* cluster internal */
+#define CEPH_OSDC_PROTOCOL 21 /* server/client */
+#define CEPH_MDSC_PROTOCOL 29 /* server/client */
+#define CEPH_MONC_PROTOCOL 15 /* server/client */
+
+
+#define CEPH_INO_ROOT 1
+
+/* arbitrary limit on max # of monitors (cluster of 3 is typical) */
+#define CEPH_MAX_MON 31
+
+
+unsigned int ceph_full_name_hash(const char *name, unsigned int len);
+
+
+/*
+ * ceph_file_layout - describe data layout for a file/inode
+ */
+struct ceph_file_layout {
+ /* file -> object mapping */
+ __le32 fl_stripe_unit; /* stripe unit, in bytes. must be multiple
+ of page size. */
+ __le32 fl_stripe_count; /* over this many objects */
+ __le32 fl_object_size; /* until objects are this big, then move to
+ new objects */
+ __le32 fl_cas_hash; /* 0 = none; 1 = sha256 */
+
+ /* pg -> disk layout */
+ __le32 fl_object_stripe_unit; /* for per-object parity, if any */
+
+ /* object -> pg layout */
+ __le32 fl_pg_preferred; /* preferred primary for pg (-1 for none) */
+ __le32 fl_pg_pool; /* namespace, crush ruleset, rep level */
+} __attribute__ ((packed));
+
+#define CEPH_MIN_STRIPE_UNIT 65536
+
+int ceph_file_layout_is_valid(const struct ceph_file_layout *layout);
+
+
+/*********************************************
+ * message layer
+ */
+
+/*
+ * message types
+ */
+
+/* misc */
+#define CEPH_MSG_SHUTDOWN 1
+#define CEPH_MSG_PING 2
+
+/* client <-> monitor */
+#define CEPH_MSG_MON_MAP 4
+#define CEPH_MSG_MON_GET_MAP 5
+#define CEPH_MSG_CLIENT_MOUNT 10
+#define CEPH_MSG_CLIENT_MOUNT_ACK 11
+#define CEPH_MSG_STATFS 13
+#define CEPH_MSG_STATFS_REPLY 14
+#define CEPH_MSG_MON_SUBSCRIBE 15
+#define CEPH_MSG_MON_SUBSCRIBE_ACK 16
+
+/* client <-> mds */
+#define CEPH_MSG_MDS_MAP 21
+
+#define CEPH_MSG_CLIENT_SESSION 22
+#define CEPH_MSG_CLIENT_RECONNECT 23
+
+#define CEPH_MSG_CLIENT_REQUEST 24
+#define CEPH_MSG_CLIENT_REQUEST_FORWARD 25
+#define CEPH_MSG_CLIENT_REPLY 26
+#define CEPH_MSG_CLIENT_CAPS 0x310
+#define CEPH_MSG_CLIENT_LEASE 0x311
+#define CEPH_MSG_CLIENT_SNAP 0x312
+#define CEPH_MSG_CLIENT_CAPRELEASE 0x313
+
+/* osd */
+#define CEPH_MSG_OSD_MAP 41
+#define CEPH_MSG_OSD_OP 42
+#define CEPH_MSG_OSD_OPREPLY 43
+
+struct ceph_mon_request_header {
+ __le64 have_version;
+ __le16 session_mon;
+ __le64 session_mon_tid;
+} __attribute__ ((packed));
+
+struct ceph_mon_statfs {
+ struct ceph_mon_request_header monhdr;
+ struct ceph_fsid fsid;
+ __le64 tid;
+} __attribute__ ((packed));
+
+struct ceph_statfs {
+ __le64 kb, kb_used, kb_avail;
+ __le64 num_objects;
+} __attribute__ ((packed));
+
+struct ceph_mon_statfs_reply {
+ struct ceph_fsid fsid;
+ __le64 tid;
+ __le64 version;
+ struct ceph_statfs st;
+} __attribute__ ((packed));
+
+struct ceph_osd_getmap {
+ struct ceph_mon_request_header monhdr;
+ struct ceph_fsid fsid;
+ __le32 start;
+} __attribute__ ((packed));
+
+struct ceph_mds_getmap {
+ struct ceph_mon_request_header monhdr;
+ struct ceph_fsid fsid;
+} __attribute__ ((packed));
+
+struct ceph_client_mount {
+ struct ceph_mon_request_header monhdr;
+} __attribute__ ((packed));
+
+struct ceph_mon_subscribe_item {
+ __le64 have_version; __le64 have;
+ __u8 onetime;
+} __attribute__ ((packed));
+
+struct ceph_mon_subscribe_ack {
+ __le32 duration; /* seconds */
+ struct ceph_fsid fsid;
+} __attribute__ ((packed));
+
+/*
+ * mds states
+ * > 0 -> in
+ * <= 0 -> out
+ */
+#define CEPH_MDS_STATE_DNE 0 /* down, does not exist. */
+#define CEPH_MDS_STATE_STOPPED -1 /* down, once existed, but no subtrees.
+ empty log. */
+#define CEPH_MDS_STATE_BOOT -4 /* up, boot announcement. */
+#define CEPH_MDS_STATE_STANDBY -5 /* up, idle. waiting for assignment. */
+#define CEPH_MDS_STATE_CREATING -6 /* up, creating MDS instance. */
+#define CEPH_MDS_STATE_STARTING -7 /* up, starting previously stopped mds */
+#define CEPH_MDS_STATE_STANDBY_REPLAY -8 /* up, tailing active node's journal */
+
+#define CEPH_MDS_STATE_REPLAY 8 /* up, replaying journal. */
+#define CEPH_MDS_STATE_RESOLVE 9 /* up, disambiguating distributed
+ operations (import, rename, etc.) */
+#define CEPH_MDS_STATE_RECONNECT 10 /* up, reconnect to clients */
+#define CEPH_MDS_STATE_REJOIN 11 /* up, rejoining distributed cache */
+#define CEPH_MDS_STATE_CLIENTREPLAY 12 /* up, replaying client operations */
+#define CEPH_MDS_STATE_ACTIVE 13 /* up, active */
+#define CEPH_MDS_STATE_STOPPING 14 /* up, but exporting metadata */
+
+extern const char *ceph_mds_state_name(int s);
+
+
+/*
+ * metadata lock types.
+ * - these are bitmasks.. we can compose them
+ * - they also define the lock ordering by the MDS
+ * - a few of these are internal to the mds
+ */
+#define CEPH_LOCK_DN 1
+#define CEPH_LOCK_ISNAP 2
+#define CEPH_LOCK_IVERSION 4 /* mds internal */
+#define CEPH_LOCK_IFILE 8 /* mds internal */
+#define CEPH_LOCK_IAUTH 32
+#define CEPH_LOCK_ILINK 64
+#define CEPH_LOCK_IDFT 128 /* dir frag tree */
+#define CEPH_LOCK_INEST 256 /* mds internal */
+#define CEPH_LOCK_IXATTR 512
+#define CEPH_LOCK_INO 2048 /* immutable inode bits; not a lock */
+
+/* client_session ops */
+enum {
+ CEPH_SESSION_REQUEST_OPEN,
+ CEPH_SESSION_OPEN,
+ CEPH_SESSION_REQUEST_CLOSE,
+ CEPH_SESSION_CLOSE,
+ CEPH_SESSION_REQUEST_RENEWCAPS,
+ CEPH_SESSION_RENEWCAPS,
+ CEPH_SESSION_STALE,
+ CEPH_SESSION_RECALL_STATE,
+};
+
+extern const char *ceph_session_op_name(int op);
+
+struct ceph_mds_session_head {
+ __le32 op;
+ __le64 seq;
+ struct ceph_timespec stamp;
+ __le32 max_caps, max_leases;
+} __attribute__ ((packed));
+
+/* client_request */
+/*
+ * metadata ops.
+ * & 0x001000 -> write op
+ * & 0x010000 -> follow symlink (e.g. stat(), not lstat()).
+ & & 0x100000 -> use weird ino/path trace
+ */
+#define CEPH_MDS_OP_WRITE 0x001000
+enum {
+ CEPH_MDS_OP_LOOKUP = 0x00100,
+ CEPH_MDS_OP_GETATTR = 0x00101,
+ CEPH_MDS_OP_LOOKUPHASH = 0x00102,
+ CEPH_MDS_OP_LOOKUPPARENT = 0x00103,
+
+ CEPH_MDS_OP_SETXATTR = 0x01105,
+ CEPH_MDS_OP_RMXATTR = 0x01106,
+ CEPH_MDS_OP_SETLAYOUT = 0x01107,
+ CEPH_MDS_OP_SETATTR = 0x01108,
+
+ CEPH_MDS_OP_MKNOD = 0x01201,
+ CEPH_MDS_OP_LINK = 0x01202,
+ CEPH_MDS_OP_UNLINK = 0x01203,
+ CEPH_MDS_OP_RENAME = 0x01204,
+ CEPH_MDS_OP_MKDIR = 0x01220,
+ CEPH_MDS_OP_RMDIR = 0x01221,
+ CEPH_MDS_OP_SYMLINK = 0x01222,
+
+ CEPH_MDS_OP_CREATE = 0x00301,
+ CEPH_MDS_OP_OPEN = 0x00302,
+ CEPH_MDS_OP_READDIR = 0x00305,
+
+ CEPH_MDS_OP_LOOKUPSNAP = 0x00400,
+ CEPH_MDS_OP_MKSNAP = 0x01400,
+ CEPH_MDS_OP_RMSNAP = 0x01401,
+ CEPH_MDS_OP_LSSNAP = 0x00402,
+};
+
+extern const char *ceph_mds_op_name(int op);
+
+
+#define CEPH_SETATTR_MODE 1
+#define CEPH_SETATTR_UID 2
+#define CEPH_SETATTR_GID 4
+#define CEPH_SETATTR_MTIME 8
+#define CEPH_SETATTR_ATIME 16
+#define CEPH_SETATTR_SIZE 32
+#define CEPH_SETATTR_CTIME 64
+
+union ceph_mds_request_args {
+ struct {
+ __le32 mask; /* CEPH_CAP_* */
+ } __attribute__ ((packed)) getattr;
+ struct {
+ __le32 mode;
+ __le32 uid;
+ __le32 gid;
+ struct ceph_timespec mtime;
+ struct ceph_timespec atime;
+ __le64 size, old_size; /* old_size needed by truncate */
+ __le32 mask; /* CEPH_SETATTR_* */
+ } __attribute__ ((packed)) setattr;
+ struct {
+ __le32 frag; /* which dir fragment */
+ __le32 max_entries; /* how many dentries to grab */
+ } __attribute__ ((packed)) readdir;
+ struct {
+ __le32 mode;
+ __le32 rdev;
+ } __attribute__ ((packed)) mknod;
+ struct {
+ __le32 mode;
+ } __attribute__ ((packed)) mkdir;
+ struct {
+ __le32 flags;
+ __le32 mode;
+ __le32 stripe_unit; /* layout for newly created file */
+ __le32 stripe_count; /* ... */
+ __le32 object_size;
+ __le32 file_replication;
+ __le32 preferred;
+ } __attribute__ ((packed)) open;
+ struct {
+ __le32 flags;
+ } __attribute__ ((packed)) setxattr;
+ struct {
+ struct ceph_file_layout layout;
+ } __attribute__ ((packed)) setlayout;
+} __attribute__ ((packed));
+
+#define CEPH_MDS_FLAG_REPLAY 1 /* this is a replayed op */
+#define CEPH_MDS_FLAG_WANT_DENTRY 2 /* want dentry in reply */
+
+struct ceph_mds_request_head {
+ __le64 tid, oldest_client_tid;
+ __le32 mdsmap_epoch; /* on client */
+ __le32 flags; /* CEPH_MDS_FLAG_* */
+ __u8 num_retry, num_fwd; /* count retry, fwd attempts */
+ __le16 num_releases; /* # include cap/lease release records */
+ __le32 op; /* mds op code */
+ __le32 caller_uid, caller_gid;
+ __le64 ino; /* use this ino for openc, mkdir, mknod,
+ etc. (if replaying) */
+ union ceph_mds_request_args args;
+} __attribute__ ((packed));
+
+/* cap/lease release record */
+struct ceph_mds_request_release {
+ __le64 ino, cap_id; /* ino and unique cap id */
+ __le32 caps, wanted; /* new issued, wanted */
+ __le32 seq, issue_seq, mseq;
+ __le32 dname_seq; /* if releasing a dentry lease, a */
+ __le32 dname_len; /* string follows. */
+} __attribute__ ((packed));
+
+/* client reply */
+struct ceph_mds_reply_head {
+ __le64 tid;
+ __le32 op;
+ __le32 result;
+ __le32 mdsmap_epoch;
+ __u8 safe; /* true if committed to disk */
+ __u8 is_dentry, is_target; /* true if dentry, target inode records
+ are included with reply */
+} __attribute__ ((packed));
+
+/* one for each node split */
+struct ceph_frag_tree_split {
+ __le32 frag; /* this frag splits... */
+ __le32 by; /* ...by this many bits */
+} __attribute__ ((packed));
+
+struct ceph_frag_tree_head {
+ __le32 nsplits; /* num ceph_frag_tree_split records */
+ struct ceph_frag_tree_split splits[];
+} __attribute__ ((packed));
+
+/* capability issue, for bundling with mds reply */
+struct ceph_mds_reply_cap {
+ __le32 caps, wanted; /* caps issued, wanted */
+ __le64 cap_id;
+ __le32 seq, mseq;
+ __le64 realm; /* snap realm */
+ __u8 flags; /* CEPH_CAP_FLAG_* */
+} __attribute__ ((packed));
+
+#define CEPH_CAP_FLAG_AUTH 1 /* cap is issued by auth mds */
+
+/* inode record, for bundling with mds reply */
+struct ceph_mds_reply_inode {
+ __le64 ino;
+ __le64 snapid;
+ __le32 rdev;
+ __le64 version; /* inode version */
+ __le64 xattr_version; /* version for xattr blob */
+ struct ceph_mds_reply_cap cap; /* caps issued for this inode */
+ struct ceph_file_layout layout;
+ struct ceph_timespec ctime, mtime, atime;
+ __le32 time_warp_seq;
+ __le64 size, max_size, truncate_size;
+ __le32 truncate_seq;
+ __le32 mode, uid, gid;
+ __le32 nlink;
+ __le64 files, subdirs, rbytes, rfiles, rsubdirs; /* dir stats */
+ struct ceph_timespec rctime;
+ struct ceph_frag_tree_head fragtree; /* (must be at end of struct) */
+} __attribute__ ((packed));
+/* followed by frag array, then symlink string, then xattr blob */
+
+/* reply_lease follows dname, and reply_inode */
+struct ceph_mds_reply_lease {
+ __le16 mask; /* lease type(s) */
+ __le32 duration_ms; /* lease duration */
+ __le32 seq;
+} __attribute__ ((packed));
+
+struct ceph_mds_reply_dirfrag {
+ __le32 frag; /* fragment */
+ __le32 auth; /* auth mds, if this is a delegation point */
+ __le32 ndist; /* number of mds' this is replicated on */
+ __le32 dist[];
+} __attribute__ ((packed));
+
+/* file access modes */
+#define CEPH_FILE_MODE_PIN 0
+#define CEPH_FILE_MODE_RD 1
+#define CEPH_FILE_MODE_WR 2
+#define CEPH_FILE_MODE_RDWR 3 /* RD | WR */
+#define CEPH_FILE_MODE_LAZY 4 /* lazy io */
+#define CEPH_FILE_MODE_NUM 8 /* bc these are bit fields.. mostly */
+
+int ceph_flags_to_mode(int flags);
+
+
+/* capability bits */
+#define CEPH_CAP_PIN 1 /* no specific capabilities beyond the pin */
+
+/* generic cap bits */
+#define CEPH_CAP_GSHARED 1 /* client can reads */
+#define CEPH_CAP_GEXCL 2 /* client can read and update */
+#define CEPH_CAP_GCACHE 4 /* (file) client can cache reads */
+#define CEPH_CAP_GRD 8 /* (file) client can read */
+#define CEPH_CAP_GWR 16 /* (file) client can write */
+#define CEPH_CAP_GBUFFER 32 /* (file) client can buffer writes */
+#define CEPH_CAP_GWREXTEND 64 /* (file) client can extend EOF */
+#define CEPH_CAP_GLAZYIO 128 /* (file) client can perform lazy io */
+
+/* per-lock shift */
+#define CEPH_CAP_SAUTH 2
+#define CEPH_CAP_SLINK 4
+#define CEPH_CAP_SXATTR 6
+#define CEPH_CAP_SFILE 8 /* goes at the end (uses >2 cap bits) */
+
+#define CEPH_CAP_BITS 16
+
+/* composed values */
+#define CEPH_CAP_AUTH_SHARED (CEPH_CAP_GSHARED << CEPH_CAP_SAUTH)
+#define CEPH_CAP_AUTH_EXCL (CEPH_CAP_GEXCL << CEPH_CAP_SAUTH)
+#define CEPH_CAP_LINK_SHARED (CEPH_CAP_GSHARED << CEPH_CAP_SLINK)
+#define CEPH_CAP_LINK_EXCL (CEPH_CAP_GEXCL << CEPH_CAP_SLINK)
+#define CEPH_CAP_XATTR_SHARED (CEPH_CAP_GSHARED << CEPH_CAP_SXATTR)
+#define CEPH_CAP_XATTR_EXCL (CEPH_CAP_GEXCL << CEPH_CAP_SXATTR)
+#define CEPH_CAP_FILE(x) (x << CEPH_CAP_SFILE)
+#define CEPH_CAP_FILE_SHARED (CEPH_CAP_GSHARED << CEPH_CAP_SFILE)
+#define CEPH_CAP_FILE_EXCL (CEPH_CAP_GEXCL << CEPH_CAP_SFILE)
+#define CEPH_CAP_FILE_CACHE (CEPH_CAP_GCACHE << CEPH_CAP_SFILE)
+#define CEPH_CAP_FILE_RD (CEPH_CAP_GRD << CEPH_CAP_SFILE)
+#define CEPH_CAP_FILE_WR (CEPH_CAP_GWR << CEPH_CAP_SFILE)
+#define CEPH_CAP_FILE_BUFFER (CEPH_CAP_GBUFFER << CEPH_CAP_SFILE)
+#define CEPH_CAP_FILE_WREXTEND (CEPH_CAP_GWREXTEND << CEPH_CAP_SFILE)
+#define CEPH_CAP_FILE_LAZYIO (CEPH_CAP_GLAZYIO << CEPH_CAP_SFILE)
+
+/* cap masks (for getattr) */
+#define CEPH_STAT_CAP_INODE CEPH_CAP_PIN
+#define CEPH_STAT_CAP_TYPE CEPH_CAP_PIN /* mode >> 12 */
+#define CEPH_STAT_CAP_SYMLINK CEPH_CAP_PIN
+#define CEPH_STAT_CAP_UID CEPH_CAP_AUTH_SHARED
+#define CEPH_STAT_CAP_GID CEPH_CAP_AUTH_SHARED
+#define CEPH_STAT_CAP_MODE CEPH_CAP_AUTH_SHARED
+#define CEPH_STAT_CAP_NLINK CEPH_CAP_LINK_SHARED
+#define CEPH_STAT_CAP_LAYOUT CEPH_CAP_FILE_SHARED
+#define CEPH_STAT_CAP_MTIME CEPH_CAP_FILE_SHARED
+#define CEPH_STAT_CAP_SIZE CEPH_CAP_FILE_SHARED
+#define CEPH_STAT_CAP_ATIME CEPH_CAP_FILE_SHARED /* fixme */
+#define CEPH_STAT_CAP_XATTR CEPH_CAP_XATTR_SHARED
+#define CEPH_STAT_CAP_INODE_ALL (CEPH_CAP_PIN | \
+ CEPH_CAP_AUTH_SHARED | \
+ CEPH_CAP_LINK_SHARED | \
+ CEPH_CAP_FILE_SHARED | \
+ CEPH_CAP_XATTR_SHARED)
+
+#define CEPH_CAP_ANY_SHARED (CEPH_CAP_AUTH_SHARED | \
+ CEPH_CAP_LINK_SHARED | \
+ CEPH_CAP_XATTR_SHARED | \
+ CEPH_CAP_FILE_SHARED)
+#define CEPH_CAP_ANY_RD (CEPH_CAP_ANY_SHARED | CEPH_CAP_FILE_RD | \
+ CEPH_CAP_FILE_CACHE)
+
+#define CEPH_CAP_ANY_EXCL (CEPH_CAP_AUTH_EXCL | \
+ CEPH_CAP_LINK_EXCL | \
+ CEPH_CAP_XATTR_EXCL | \
+ CEPH_CAP_FILE_EXCL)
+#define CEPH_CAP_ANY_FILE_WR (CEPH_CAP_FILE_WR | CEPH_CAP_FILE_BUFFER | \
+ CEPH_CAP_FILE_EXCL)
+#define CEPH_CAP_ANY_WR (CEPH_CAP_ANY_EXCL | CEPH_CAP_ANY_FILE_WR)
+#define CEPH_CAP_ANY (CEPH_CAP_ANY_RD | CEPH_CAP_ANY_EXCL | \
+ CEPH_CAP_ANY_FILE_WR | CEPH_CAP_PIN)
+
+#define CEPH_CAP_LOCKS (CEPH_LOCK_IFILE | CEPH_LOCK_IAUTH | CEPH_LOCK_ILINK | \
+ CEPH_LOCK_IXATTR)
+
+int ceph_caps_for_mode(int mode);
+
+enum {
+ CEPH_CAP_OP_GRANT, /* mds->client grant */
+ CEPH_CAP_OP_REVOKE, /* mds->client revoke */
+ CEPH_CAP_OP_TRUNC, /* mds->client trunc notify */
+ CEPH_CAP_OP_EXPORT, /* mds has exported the cap */
+ CEPH_CAP_OP_IMPORT, /* mds has imported the cap */
+ CEPH_CAP_OP_UPDATE, /* client->mds update */
+ CEPH_CAP_OP_DROP, /* client->mds drop cap bits */
+ CEPH_CAP_OP_FLUSH, /* client->mds cap writeback */
+ CEPH_CAP_OP_FLUSH_ACK, /* mds->client flushed */
+ CEPH_CAP_OP_FLUSHSNAP, /* client->mds flush snapped metadata */
+ CEPH_CAP_OP_FLUSHSNAP_ACK, /* mds->client flushed snapped metadata */
+ CEPH_CAP_OP_RELEASE, /* client->mds release (clean) cap */
+ CEPH_CAP_OP_RENEW, /* client->mds renewal request */
+};
+
+extern const char *ceph_cap_op_name(int op);
+
+/*
+ * caps message, used for capability callbacks, acks, requests, etc.
+ */
+struct ceph_mds_caps {
+ __le32 op; /* CEPH_CAP_OP_* */
+ __le64 ino, realm;
+ __le64 cap_id;
+ __le32 seq, issue_seq;
+ __le32 caps, wanted, dirty; /* latest issued/wanted/dirty */
+ __le32 migrate_seq;
+ __le64 snap_follows;
+ __le32 snap_trace_len;
+ __le64 client_tid; /* for FLUSH(SNAP) -> FLUSH(SNAP)_ACK */
+
+ /* authlock */
+ __le32 uid, gid, mode;
+
+ /* linklock */
+ __le32 nlink;
+
+ /* xattrlock */
+ __le32 xattr_len;
+ __le64 xattr_version;
+
+ /* filelock */
+ __le64 size, max_size, truncate_size;
+ __le32 truncate_seq;
+ struct ceph_timespec mtime, atime, ctime;
+ struct ceph_file_layout layout;
+ __le32 time_warp_seq;
+} __attribute__ ((packed));
+
+/* cap release msg head */
+struct ceph_mds_cap_release {
+ __le32 num; /* number of cap_items that follow */
+} __attribute__ ((packed));
+
+struct ceph_mds_cap_item {
+ __le64 ino;
+ __le64 cap_id;
+ __le32 migrate_seq, seq;
+} __attribute__ ((packed));
+
+#define CEPH_MDS_LEASE_REVOKE 1 /* mds -> client */
+#define CEPH_MDS_LEASE_RELEASE 2 /* client -> mds */
+#define CEPH_MDS_LEASE_RENEW 3 /* client <-> mds */
+#define CEPH_MDS_LEASE_REVOKE_ACK 4 /* client -> mds */
+
+extern const char *ceph_lease_op_name(int o);
+
+/* lease msg header */
+struct ceph_mds_lease {
+ __u8 action; /* CEPH_MDS_LEASE_* */
+ __le16 mask; /* which lease */
+ __le64 ino;
+ __le64 first, last; /* snap range */
+ __le32 seq;
+ __le32 duration_ms; /* duration of renewal */
+} __attribute__ ((packed));
+/* followed by a __le32+string for dname */
+
+/* client reconnect */
+struct ceph_mds_cap_reconnect {
+ __le64 cap_id;
+ __le32 wanted;
+ __le32 issued;
+ __le64 size;
+ struct ceph_timespec mtime, atime;
+ __le64 snaprealm;
+ __le64 pathbase; /* base ino for our path to this ino */
+} __attribute__ ((packed));
+/* followed by encoded string */
+
+struct ceph_mds_snaprealm_reconnect {
+ __le64 ino; /* snap realm base */
+ __le64 seq; /* snap seq for this snap realm */
+ __le64 parent; /* parent realm */
+} __attribute__ ((packed));
+
+/*
+ * snaps
+ */
+enum {
+ CEPH_SNAP_OP_UPDATE, /* CREATE or DESTROY */
+ CEPH_SNAP_OP_CREATE,
+ CEPH_SNAP_OP_DESTROY,
+ CEPH_SNAP_OP_SPLIT,
+};
+
+extern const char *ceph_snap_op_name(int o);
+
+/* snap msg header */
+struct ceph_mds_snap_head {
+ __le32 op; /* CEPH_SNAP_OP_* */
+ __le64 split; /* ino to split off, if any */
+ __le32 num_split_inos; /* # inos belonging to new child realm */
+ __le32 num_split_realms; /* # child realms udner new child realm */
+ __le32 trace_len; /* size of snap trace blob */
+} __attribute__ ((packed));
+/* followed by split ino list, then split realms, then the trace blob */
+
+/*
+ * encode info about a snaprealm, as viewed by a client
+ */
+struct ceph_mds_snap_realm {
+ __le64 ino; /* ino */
+ __le64 created; /* snap: when created */
+ __le64 parent; /* ino: parent realm */
+ __le64 parent_since; /* snap: same parent since */
+ __le64 seq; /* snap: version */
+ __le32 num_snaps;
+ __le32 num_prior_parent_snaps;
+} __attribute__ ((packed));
+/* followed by my snap list, then prior parent snap list */
+
+#endif
diff --git a/fs/ceph/ceph_strings.c b/fs/ceph/ceph_strings.c
new file mode 100644
index 000000000000..90d19d9d8d8f
--- /dev/null
+++ b/fs/ceph/ceph_strings.c
@@ -0,0 +1,163 @@
+/*
+ * Ceph string constants
+ */
+#include "types.h"
+
+const char *ceph_osd_op_name(int op)
+{
+ switch (op) {
+ case CEPH_OSD_OP_READ: return "read";
+ case CEPH_OSD_OP_STAT: return "stat";
+
+ case CEPH_OSD_OP_MASKTRUNC: return "masktrunc";
+
+ case CEPH_OSD_OP_WRITE: return "write";
+ case CEPH_OSD_OP_DELETE: return "delete";
+ case CEPH_OSD_OP_TRUNCATE: return "truncate";
+ case CEPH_OSD_OP_ZERO: return "zero";
+ case CEPH_OSD_OP_WRITEFULL: return "writefull";
+
+ case CEPH_OSD_OP_APPEND: return "append";
+ case CEPH_OSD_OP_STARTSYNC: return "startsync";
+ case CEPH_OSD_OP_SETTRUNC: return "settrunc";
+ case CEPH_OSD_OP_TRIMTRUNC: return "trimtrunc";
+
+ case CEPH_OSD_OP_TMAPUP: return "tmapup";
+ case CEPH_OSD_OP_TMAPGET: return "tmapget";
+ case CEPH_OSD_OP_TMAPPUT: return "tmapput";
+
+ case CEPH_OSD_OP_GETXATTR: return "getxattr";
+ case CEPH_OSD_OP_GETXATTRS: return "getxattrs";
+ case CEPH_OSD_OP_SETXATTR: return "setxattr";
+ case CEPH_OSD_OP_SETXATTRS: return "setxattrs";
+ case CEPH_OSD_OP_RESETXATTRS: return "resetxattrs";
+ case CEPH_OSD_OP_RMXATTR: return "rmxattr";
+
+ case CEPH_OSD_OP_PULL: return "pull";
+ case CEPH_OSD_OP_PUSH: return "push";
+ case CEPH_OSD_OP_BALANCEREADS: return "balance-reads";
+ case CEPH_OSD_OP_UNBALANCEREADS: return "unbalance-reads";
+ case CEPH_OSD_OP_SCRUB: return "scrub";
+
+ case CEPH_OSD_OP_WRLOCK: return "wrlock";
+ case CEPH_OSD_OP_WRUNLOCK: return "wrunlock";
+ case CEPH_OSD_OP_RDLOCK: return "rdlock";
+ case CEPH_OSD_OP_RDUNLOCK: return "rdunlock";
+ case CEPH_OSD_OP_UPLOCK: return "uplock";
+ case CEPH_OSD_OP_DNLOCK: return "dnlock";
+
+ case CEPH_OSD_OP_CALL: return "call";
+
+ case CEPH_OSD_OP_PGLS: return "pgls";
+ }
+ return "???";
+}
+
+const char *ceph_mds_state_name(int s)
+{
+ switch (s) {
+ /* down and out */
+ case CEPH_MDS_STATE_DNE: return "down:dne";
+ case CEPH_MDS_STATE_STOPPED: return "down:stopped";
+ /* up and out */
+ case CEPH_MDS_STATE_BOOT: return "up:boot";
+ case CEPH_MDS_STATE_STANDBY: return "up:standby";
+ case CEPH_MDS_STATE_STANDBY_REPLAY: return "up:standby-replay";
+ case CEPH_MDS_STATE_CREATING: return "up:creating";
+ case CEPH_MDS_STATE_STARTING: return "up:starting";
+ /* up and in */
+ case CEPH_MDS_STATE_REPLAY: return "up:replay";
+ case CEPH_MDS_STATE_RESOLVE: return "up:resolve";
+ case CEPH_MDS_STATE_RECONNECT: return "up:reconnect";
+ case CEPH_MDS_STATE_REJOIN: return "up:rejoin";
+ case CEPH_MDS_STATE_CLIENTREPLAY: return "up:clientreplay";
+ case CEPH_MDS_STATE_ACTIVE: return "up:active";
+ case CEPH_MDS_STATE_STOPPING: return "up:stopping";
+ }
+ return "???";
+}
+
+const char *ceph_session_op_name(int op)
+{
+ switch (op) {
+ case CEPH_SESSION_REQUEST_OPEN: return "request_open";
+ case CEPH_SESSION_OPEN: return "open";
+ case CEPH_SESSION_REQUEST_CLOSE: return "request_close";
+ case CEPH_SESSION_CLOSE: return "close";
+ case CEPH_SESSION_REQUEST_RENEWCAPS: return "request_renewcaps";
+ case CEPH_SESSION_RENEWCAPS: return "renewcaps";
+ case CEPH_SESSION_STALE: return "stale";
+ case CEPH_SESSION_RECALL_STATE: return "recall_state";
+ }
+ return "???";
+}
+
+const char *ceph_mds_op_name(int op)
+{
+ switch (op) {
+ case CEPH_MDS_OP_LOOKUP: return "lookup";
+ case CEPH_MDS_OP_LOOKUPHASH: return "lookuphash";
+ case CEPH_MDS_OP_LOOKUPPARENT: return "lookupparent";
+ case CEPH_MDS_OP_GETATTR: return "getattr";
+ case CEPH_MDS_OP_SETXATTR: return "setxattr";
+ case CEPH_MDS_OP_SETATTR: return "setattr";
+ case CEPH_MDS_OP_RMXATTR: return "rmxattr";
+ case CEPH_MDS_OP_READDIR: return "readdir";
+ case CEPH_MDS_OP_MKNOD: return "mknod";
+ case CEPH_MDS_OP_LINK: return "link";
+ case CEPH_MDS_OP_UNLINK: return "unlink";
+ case CEPH_MDS_OP_RENAME: return "rename";
+ case CEPH_MDS_OP_MKDIR: return "mkdir";
+ case CEPH_MDS_OP_RMDIR: return "rmdir";
+ case CEPH_MDS_OP_SYMLINK: return "symlink";
+ case CEPH_MDS_OP_CREATE: return "create";
+ case CEPH_MDS_OP_OPEN: return "open";
+ case CEPH_MDS_OP_LOOKUPSNAP: return "lookupsnap";
+ case CEPH_MDS_OP_LSSNAP: return "lssnap";
+ case CEPH_MDS_OP_MKSNAP: return "mksnap";
+ case CEPH_MDS_OP_RMSNAP: return "rmsnap";
+ }
+ return "???";
+}
+
+const char *ceph_cap_op_name(int op)
+{
+ switch (op) {
+ case CEPH_CAP_OP_GRANT: return "grant";
+ case CEPH_CAP_OP_REVOKE: return "revoke";
+ case CEPH_CAP_OP_TRUNC: return "trunc";
+ case CEPH_CAP_OP_EXPORT: return "export";
+ case CEPH_CAP_OP_IMPORT: return "import";
+ case CEPH_CAP_OP_UPDATE: return "update";
+ case CEPH_CAP_OP_DROP: return "drop";
+ case CEPH_CAP_OP_FLUSH: return "flush";
+ case CEPH_CAP_OP_FLUSH_ACK: return "flush_ack";
+ case CEPH_CAP_OP_FLUSHSNAP: return "flushsnap";
+ case CEPH_CAP_OP_FLUSHSNAP_ACK: return "flushsnap_ack";
+ case CEPH_CAP_OP_RELEASE: return "release";
+ case CEPH_CAP_OP_RENEW: return "renew";
+ }
+ return "???";
+}
+
+const char *ceph_lease_op_name(int o)
+{
+ switch (o) {
+ case CEPH_MDS_LEASE_REVOKE: return "revoke";
+ case CEPH_MDS_LEASE_RELEASE: return "release";
+ case CEPH_MDS_LEASE_RENEW: return "renew";
+ case CEPH_MDS_LEASE_REVOKE_ACK: return "revoke_ack";
+ }
+ return "???";
+}
+
+const char *ceph_snap_op_name(int o)
+{
+ switch (o) {
+ case CEPH_SNAP_OP_UPDATE: return "update";
+ case CEPH_SNAP_OP_CREATE: return "create";
+ case CEPH_SNAP_OP_DESTROY: return "destroy";
+ case CEPH_SNAP_OP_SPLIT: return "split";
+ }
+ return "???";
+}
diff --git a/fs/ceph/crush/crush.c b/fs/ceph/crush/crush.c
new file mode 100644
index 000000000000..13755cdc4fb3
--- /dev/null
+++ b/fs/ceph/crush/crush.c
@@ -0,0 +1,140 @@
+
+#ifdef __KERNEL__
+# include <linux/slab.h>
+#else
+# include <stdlib.h>
+# include <assert.h>
+# define kfree(x) do { if (x) free(x); } while (0)
+# define BUG_ON(x) assert(!(x))
+#endif
+
+#include "crush.h"
+
+/**
+ * crush_get_bucket_item_weight - Get weight of an item in given bucket
+ * @b: bucket pointer
+ * @p: item index in bucket
+ */
+int crush_get_bucket_item_weight(struct crush_bucket *b, int p)
+{
+ if (p >= b->size)
+ return 0;
+
+ switch (b->alg) {
+ case CRUSH_BUCKET_UNIFORM:
+ return ((struct crush_bucket_uniform *)b)->item_weight;
+ case CRUSH_BUCKET_LIST:
+ return ((struct crush_bucket_list *)b)->item_weights[p];
+ case CRUSH_BUCKET_TREE:
+ if (p & 1)
+ return ((struct crush_bucket_tree *)b)->node_weights[p];
+ return 0;
+ case CRUSH_BUCKET_STRAW:
+ return ((struct crush_bucket_straw *)b)->item_weights[p];
+ }
+ return 0;
+}
+
+/**
+ * crush_calc_parents - Calculate parent vectors for the given crush map.
+ * @map: crush_map pointer
+ */
+void crush_calc_parents(struct crush_map *map)
+{
+ int i, b, c;
+
+ for (b = 0; b < map->max_buckets; b++) {
+ if (map->buckets[b] == NULL)
+ continue;
+ for (i = 0; i < map->buckets[b]->size; i++) {
+ c = map->buckets[b]->items[i];
+ BUG_ON(c >= map->max_devices ||
+ c < -map->max_buckets);
+ if (c >= 0)
+ map->device_parents[c] = map->buckets[b]->id;
+ else
+ map->bucket_parents[-1-c] = map->buckets[b]->id;
+ }
+ }
+}
+
+void crush_destroy_bucket_uniform(struct crush_bucket_uniform *b)
+{
+ kfree(b->h.perm);
+ kfree(b->h.items);
+ kfree(b);
+}
+
+void crush_destroy_bucket_list(struct crush_bucket_list *b)
+{
+ kfree(b->item_weights);
+ kfree(b->sum_weights);
+ kfree(b->h.perm);
+ kfree(b->h.items);
+ kfree(b);
+}
+
+void crush_destroy_bucket_tree(struct crush_bucket_tree *b)
+{
+ kfree(b->node_weights);
+ kfree(b);
+}
+
+void crush_destroy_bucket_straw(struct crush_bucket_straw *b)
+{
+ kfree(b->straws);
+ kfree(b->item_weights);
+ kfree(b->h.perm);
+ kfree(b->h.items);
+ kfree(b);
+}
+
+void crush_destroy_bucket(struct crush_bucket *b)
+{
+ switch (b->alg) {
+ case CRUSH_BUCKET_UNIFORM:
+ crush_destroy_bucket_uniform((struct crush_bucket_uniform *)b);
+ break;
+ case CRUSH_BUCKET_LIST:
+ crush_destroy_bucket_list((struct crush_bucket_list *)b);
+ break;
+ case CRUSH_BUCKET_TREE:
+ crush_destroy_bucket_tree((struct crush_bucket_tree *)b);
+ break;
+ case CRUSH_BUCKET_STRAW:
+ crush_destroy_bucket_straw((struct crush_bucket_straw *)b);
+ break;
+ }
+}
+
+/**
+ * crush_destroy - Destroy a crush_map
+ * @map: crush_map pointer
+ */
+void crush_destroy(struct crush_map *map)
+{
+ int b;
+
+ /* buckets */
+ if (map->buckets) {
+ for (b = 0; b < map->max_buckets; b++) {
+ if (map->buckets[b] == NULL)
+ continue;
+ crush_destroy_bucket(map->buckets[b]);
+ }
+ kfree(map->buckets);
+ }
+
+ /* rules */
+ if (map->rules) {
+ for (b = 0; b < map->max_rules; b++)
+ kfree(map->rules[b]);
+ kfree(map->rules);
+ }
+
+ kfree(map->bucket_parents);
+ kfree(map->device_parents);
+ kfree(map);
+}
+
+
diff --git a/fs/ceph/crush/crush.h b/fs/ceph/crush/crush.h
new file mode 100644
index 000000000000..9ac7e091126f
--- /dev/null
+++ b/fs/ceph/crush/crush.h
@@ -0,0 +1,188 @@
+#ifndef _CRUSH_CRUSH_H
+#define _CRUSH_CRUSH_H
+
+#include <linux/types.h>
+
+/*
+ * CRUSH is a pseudo-random data distribution algorithm that
+ * efficiently distributes input values (typically, data objects)
+ * across a heterogeneous, structured storage cluster.
+ *
+ * The algorithm was originally described in detail in this paper
+ * (although the algorithm has evolved somewhat since then):
+ *
+ * http://www.ssrc.ucsc.edu/Papers/weil-sc06.pdf
+ *
+ * LGPL2
+ */
+
+
+#define CRUSH_MAGIC 0x00010000ul /* for detecting algorithm revisions */
+
+
+#define CRUSH_MAX_DEPTH 10 /* max crush hierarchy depth */
+#define CRUSH_MAX_SET 10 /* max size of a mapping result */
+
+
+/*
+ * CRUSH uses user-defined "rules" to describe how inputs should be
+ * mapped to devices. A rule consists of sequence of steps to perform
+ * to generate the set of output devices.
+ */
+struct crush_rule_step {
+ __u32 op;
+ __s32 arg1;
+ __s32 arg2;
+};
+
+/* step op codes */
+enum {
+ CRUSH_RULE_NOOP = 0,
+ CRUSH_RULE_TAKE = 1, /* arg1 = value to start with */
+ CRUSH_RULE_CHOOSE_FIRSTN = 2, /* arg1 = num items to pick */
+ /* arg2 = type */
+ CRUSH_RULE_CHOOSE_INDEP = 3, /* same */
+ CRUSH_RULE_EMIT = 4, /* no args */
+ CRUSH_RULE_CHOOSE_LEAF_FIRSTN = 6,
+ CRUSH_RULE_CHOOSE_LEAF_INDEP = 7,
+};
+
+/*
+ * for specifying choose num (arg1) relative to the max parameter
+ * passed to do_rule
+ */
+#define CRUSH_CHOOSE_N 0
+#define CRUSH_CHOOSE_N_MINUS(x) (-(x))
+
+/*
+ * The rule mask is used to describe what the rule is intended for.
+ * Given a ruleset and size of output set, we search through the
+ * rule list for a matching rule_mask.
+ */
+struct crush_rule_mask {
+ __u8 ruleset;
+ __u8 type;
+ __u8 min_size;
+ __u8 max_size;
+};
+
+struct crush_rule {
+ __u32 len;
+ struct crush_rule_mask mask;
+ struct crush_rule_step steps[0];
+};
+
+#define crush_rule_size(len) (sizeof(struct crush_rule) + \
+ (len)*sizeof(struct crush_rule_step))
+
+
+
+/*
+ * A bucket is a named container of other items (either devices or
+ * other buckets). Items within a bucket are chosen using one of a
+ * few different algorithms. The table summarizes how the speed of
+ * each option measures up against mapping stability when items are
+ * added or removed.
+ *
+ * Bucket Alg Speed Additions Removals
+ * ------------------------------------------------
+ * uniform O(1) poor poor
+ * list O(n) optimal poor
+ * tree O(log n) good good
+ * straw O(n) optimal optimal
+ */
+enum {
+ CRUSH_BUCKET_UNIFORM = 1,
+ CRUSH_BUCKET_LIST = 2,
+ CRUSH_BUCKET_TREE = 3,
+ CRUSH_BUCKET_STRAW = 4
+};
+static inline const char *crush_bucket_alg_name(int alg)
+{
+ switch (alg) {
+ case CRUSH_BUCKET_UNIFORM: return "uniform";
+ case CRUSH_BUCKET_LIST: return "list";
+ case CRUSH_BUCKET_TREE: return "tree";
+ case CRUSH_BUCKET_STRAW: return "straw";
+ default: return "unknown";
+ }
+}
+
+struct crush_bucket {
+ __s32 id; /* this'll be negative */
+ __u16 type; /* non-zero; type=0 is reserved for devices */
+ __u16 alg; /* one of CRUSH_BUCKET_* */
+ __u32 weight; /* 16-bit fixed point */
+ __u32 size; /* num items */
+ __s32 *items;
+
+ /*
+ * cached random permutation: used for uniform bucket and for
+ * the linear search fallback for the other bucket types.
+ */
+ __u32 perm_x; /* @x for which *perm is defined */
+ __u32 perm_n; /* num elements of *perm that are permuted/defined */
+ __u32 *perm;
+};
+
+struct crush_bucket_uniform {
+ struct crush_bucket h;
+ __u32 item_weight; /* 16-bit fixed point; all items equally weighted */
+};
+
+struct crush_bucket_list {
+ struct crush_bucket h;
+ __u32 *item_weights; /* 16-bit fixed point */
+ __u32 *sum_weights; /* 16-bit fixed point. element i is sum
+ of weights 0..i, inclusive */
+};
+
+struct crush_bucket_tree {
+ struct crush_bucket h; /* note: h.size is _tree_ size, not number of
+ actual items */
+ __u8 num_nodes;
+ __u32 *node_weights;
+};
+
+struct crush_bucket_straw {
+ struct crush_bucket h;
+ __u32 *item_weights; /* 16-bit fixed point */
+ __u32 *straws; /* 16-bit fixed point */
+};
+
+
+
+/*
+ * CRUSH map includes all buckets, rules, etc.
+ */
+struct crush_map {
+ struct crush_bucket **buckets;
+ struct crush_rule **rules;
+
+ /*
+ * Parent pointers to identify the parent bucket a device or
+ * bucket in the hierarchy. If an item appears more than
+ * once, this is the _last_ time it appeared (where buckets
+ * are processed in bucket id order, from -1 on down to
+ * -max_buckets.
+ */
+ __u32 *bucket_parents;
+ __u32 *device_parents;
+
+ __s32 max_buckets;
+ __u32 max_rules;
+ __s32 max_devices;
+};
+
+
+/* crush.c */
+extern int crush_get_bucket_item_weight(struct crush_bucket *b, int pos);
+extern void crush_calc_parents(struct crush_map *map);
+extern void crush_destroy_bucket_uniform(struct crush_bucket_uniform *b);
+extern void crush_destroy_bucket_list(struct crush_bucket_list *b);
+extern void crush_destroy_bucket_tree(struct crush_bucket_tree *b);
+extern void crush_destroy_bucket_straw(struct crush_bucket_straw *b);
+extern void crush_destroy_bucket(struct crush_bucket *b);
+extern void crush_destroy(struct crush_map *map);
+
+#endif
diff --git a/fs/ceph/crush/hash.h b/fs/ceph/crush/hash.h
new file mode 100644
index 000000000000..42f3312783a1
--- /dev/null
+++ b/fs/ceph/crush/hash.h
@@ -0,0 +1,90 @@
+#ifndef _CRUSH_HASH_H
+#define _CRUSH_HASH_H
+
+/*
+ * Robert Jenkins' function for mixing 32-bit values
+ * http://burtleburtle.net/bob/hash/evahash.html
+ * a, b = random bits, c = input and output
+ */
+#define crush_hashmix(a, b, c) do { \
+ a = a-b; a = a-c; a = a^(c>>13); \
+ b = b-c; b = b-a; b = b^(a<<8); \
+ c = c-a; c = c-b; c = c^(b>>13); \
+ a = a-b; a = a-c; a = a^(c>>12); \
+ b = b-c; b = b-a; b = b^(a<<16); \
+ c = c-a; c = c-b; c = c^(b>>5); \
+ a = a-b; a = a-c; a = a^(c>>3); \
+ b = b-c; b = b-a; b = b^(a<<10); \
+ c = c-a; c = c-b; c = c^(b>>15); \
+ } while (0)
+
+#define crush_hash_seed 1315423911
+
+static inline __u32 crush_hash32(__u32 a)
+{
+ __u32 hash = crush_hash_seed ^ a;
+ __u32 b = a;
+ __u32 x = 231232;
+ __u32 y = 1232;
+ crush_hashmix(b, x, hash);
+ crush_hashmix(y, a, hash);
+ return hash;
+}
+
+static inline __u32 crush_hash32_2(__u32 a, __u32 b)
+{
+ __u32 hash = crush_hash_seed ^ a ^ b;
+ __u32 x = 231232;
+ __u32 y = 1232;
+ crush_hashmix(a, b, hash);
+ crush_hashmix(x, a, hash);
+ crush_hashmix(b, y, hash);
+ return hash;
+}
+
+static inline __u32 crush_hash32_3(__u32 a, __u32 b, __u32 c)
+{
+ __u32 hash = crush_hash_seed ^ a ^ b ^ c;
+ __u32 x = 231232;
+ __u32 y = 1232;
+ crush_hashmix(a, b, hash);
+ crush_hashmix(c, x, hash);
+ crush_hashmix(y, a, hash);
+ crush_hashmix(b, x, hash);
+ crush_hashmix(y, c, hash);
+ return hash;
+}
+
+static inline __u32 crush_hash32_4(__u32 a, __u32 b, __u32 c,
+ __u32 d)
+{
+ __u32 hash = crush_hash_seed ^ a ^ b ^ c ^ d;
+ __u32 x = 231232;
+ __u32 y = 1232;
+ crush_hashmix(a, b, hash);
+ crush_hashmix(c, d, hash);
+ crush_hashmix(a, x, hash);
+ crush_hashmix(y, b, hash);
+ crush_hashmix(c, x, hash);
+ crush_hashmix(y, d, hash);
+ return hash;
+}
+
+static inline __u32 crush_hash32_5(__u32 a, __u32 b, __u32 c,
+ __u32 d, __u32 e)
+{
+ __u32 hash = crush_hash_seed ^ a ^ b ^ c ^ d ^ e;
+ __u32 x = 231232;
+ __u32 y = 1232;
+ crush_hashmix(a, b, hash);
+ crush_hashmix(c, d, hash);
+ crush_hashmix(e, x, hash);
+ crush_hashmix(y, a, hash);
+ crush_hashmix(b, x, hash);
+ crush_hashmix(y, c, hash);
+ crush_hashmix(d, x, hash);
+ crush_hashmix(y, e, hash);
+ return hash;
+}
+
+#endif
diff --git a/fs/ceph/crush/mapper.c b/fs/ceph/crush/mapper.c
new file mode 100644
index 000000000000..c268393adfcb
--- /dev/null
+++ b/fs/ceph/crush/mapper.c
@@ -0,0 +1,594 @@
+
+#ifdef __KERNEL__
+# include <linux/string.h>
+# include <linux/slab.h>
+# include <linux/bug.h>
+# include <linux/kernel.h>
+# ifndef dprintk
+# define dprintk(args...)
+# endif
+#else
+# include <string.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <assert.h>
+# define BUG_ON(x) assert(!(x))
+# define dprintk(args...) /* printf(args) */
+# define kmalloc(x, f) malloc(x)
+# define kfree(x) free(x)
+#endif
+
+#include "crush.h"
+#include "hash.h"
+
+/*
+ * Implement the core CRUSH mapping algorithm.
+ */
+
+/**
+ * crush_find_rule - find a crush_rule id for a given ruleset, type, and size.
+ * @map: the crush_map
+ * @ruleset: the storage ruleset id (user defined)
+ * @type: storage ruleset type (user defined)
+ * @size: output set size
+ */
+int crush_find_rule(struct crush_map *map, int ruleset, int type, int size)
+{
+ int i;
+
+ for (i = 0; i < map->max_rules; i++) {
+ if (map->rules[i] &&
+ map->rules[i]->mask.ruleset == ruleset &&
+ map->rules[i]->mask.type == type &&
+ map->rules[i]->mask.min_size <= size &&
+ map->rules[i]->mask.max_size >= size)
+ return i;
+ }
+ return -1;
+}
+
+
+/*
+ * bucket choose methods
+ *
+ * For each bucket algorithm, we have a "choose" method that, given a
+ * crush input @x and replica position (usually, position in output set) @r,
+ * will produce an item in the bucket.
+ */
+
+/*
+ * Choose based on a random permutation of the bucket.
+ *
+ * We used to use some prime number arithmetic to do this, but it
+ * wasn't very random, and had some other bad behaviors. Instead, we
+ * calculate an actual random permutation of the bucket members.
+ * Since this is expensive, we optimize for the r=0 case, which
+ * captures the vast majority of calls.
+ */
+static int bucket_perm_choose(struct crush_bucket *bucket,
+ int x, int r)
+{
+ unsigned pr = r % bucket->size;
+ unsigned i, s;
+
+ /* start a new permutation if @x has changed */
+ if (bucket->perm_x != x || bucket->perm_n == 0) {
+ dprintk("bucket %d new x=%d\n", bucket->id, x);
+ bucket->perm_x = x;
+
+ /* optimize common r=0 case */
+ if (pr == 0) {
+ s = crush_hash32_3(x, bucket->id, 0) %
+ bucket->size;
+ bucket->perm[0] = s;
+ bucket->perm_n = 0xffff; /* magic value, see below */
+ goto out;
+ }
+
+ for (i = 0; i < bucket->size; i++)
+ bucket->perm[i] = i;
+ bucket->perm_n = 0;
+ } else if (bucket->perm_n == 0xffff) {
+ /* clean up after the r=0 case above */
+ for (i = 1; i < bucket->size; i++)
+ bucket->perm[i] = i;
+ bucket->perm[bucket->perm[0]] = 0;
+ bucket->perm_n = 1;
+ }
+
+ /* calculate permutation up to pr */
+ for (i = 0; i < bucket->perm_n; i++)
+ dprintk(" perm_choose have %d: %d\n", i, bucket->perm[i]);
+ while (bucket->perm_n <= pr) {
+ unsigned p = bucket->perm_n;
+ /* no point in swapping the final entry */
+ if (p < bucket->size - 1) {
+ i = crush_hash32_3(x, bucket->id, p) %
+ (bucket->size - p);
+ if (i) {
+ unsigned t = bucket->perm[p + i];
+ bucket->perm[p + i] = bucket->perm[p];
+ bucket->perm[p] = t;
+ }
+ dprintk(" perm_choose swap %d with %d\n", p, p+i);
+ }
+ bucket->perm_n++;
+ }
+ for (i = 0; i < bucket->size; i++)
+ dprintk(" perm_choose %d: %d\n", i, bucket->perm[i]);
+
+ s = bucket->perm[pr];
+out:
+ dprintk(" perm_choose %d sz=%d x=%d r=%d (%d) s=%d\n", bucket->id,
+ bucket->size, x, r, pr, s);
+ return bucket->items[s];
+}
+
+/* uniform */
+static int bucket_uniform_choose(struct crush_bucket_uniform *bucket,
+ int x, int r)
+{
+ return bucket_perm_choose(&bucket->h, x, r);
+}
+
+/* list */
+static int bucket_list_choose(struct crush_bucket_list *bucket,
+ int x, int r)
+{
+ int i;
+
+ for (i = bucket->h.size-1; i >= 0; i--) {
+ __u64 w = crush_hash32_4(x, bucket->h.items[i], r,
+ bucket->h.id);
+ w &= 0xffff;
+ dprintk("list_choose i=%d x=%d r=%d item %d weight %x "
+ "sw %x rand %llx",
+ i, x, r, bucket->h.items[i], bucket->item_weights[i],
+ bucket->sum_weights[i], w);
+ w *= bucket->sum_weights[i];
+ w = w >> 16;
+ /*dprintk(" scaled %llx\n", w);*/
+ if (w < bucket->item_weights[i])
+ return bucket->h.items[i];
+ }
+
+ BUG_ON(1);
+ return 0;
+}
+
+
+/* (binary) tree */
+static int height(int n)
+{
+ int h = 0;
+ while ((n & 1) == 0) {
+ h++;
+ n = n >> 1;
+ }
+ return h;
+}
+
+static int left(int x)
+{
+ int h = height(x);
+ return x - (1 << (h-1));
+}
+
+static int right(int x)
+{
+ int h = height(x);
+ return x + (1 << (h-1));
+}
+
+static int terminal(int x)
+{
+ return x & 1;
+}
+
+static int bucket_tree_choose(struct crush_bucket_tree *bucket,
+ int x, int r)
+{
+ int n, l;
+ __u32 w;
+ __u64 t;
+
+ /* start at root */
+ n = bucket->num_nodes >> 1;
+
+ while (!terminal(n)) {
+ /* pick point in [0, w) */
+ w = bucket->node_weights[n];
+ t = (__u64)crush_hash32_4(x, n, r, bucket->h.id) * (__u64)w;
+ t = t >> 32;
+
+ /* descend to the left or right? */
+ l = left(n);
+ if (t < bucket->node_weights[l])
+ n = l;
+ else
+ n = right(n);
+ }
+
+ return bucket->h.items[n >> 1];
+}
+
+
+/* straw */
+
+static int bucket_straw_choose(struct crush_bucket_straw *bucket,
+ int x, int r)
+{
+ int i;
+ int high = 0;
+ __u64 high_draw = 0;
+ __u64 draw;
+
+ for (i = 0; i < bucket->h.size; i++) {
+ draw = crush_hash32_3(x, bucket->h.items[i], r);
+ draw &= 0xffff;
+ draw *= bucket->straws[i];
+ if (i == 0 || draw > high_draw) {
+ high = i;
+ high_draw = draw;
+ }
+ }
+ return bucket->h.items[high];
+}
+
+static int crush_bucket_choose(struct crush_bucket *in, int x, int r)
+{
+ dprintk("choose %d x=%d r=%d\n", in->id, x, r);
+ switch (in->alg) {
+ case CRUSH_BUCKET_UNIFORM:
+ return bucket_uniform_choose((struct crush_bucket_uniform *)in,
+ x, r);
+ case CRUSH_BUCKET_LIST:
+ return bucket_list_choose((struct crush_bucket_list *)in,
+ x, r);
+ case CRUSH_BUCKET_TREE:
+ return bucket_tree_choose((struct crush_bucket_tree *)in,
+ x, r);
+ case CRUSH_BUCKET_STRAW:
+ return bucket_straw_choose((struct crush_bucket_straw *)in,
+ x, r);
+ default:
+ BUG_ON(1);
+/* return in->items[0] */;
+ }
+}
+
+/*
+ * true if device is marked "out" (failed, fully offloaded)
+ * of the cluster
+ */
+static int is_out(struct crush_map *map, __u32 *weight, int item, int x)
+{
+ if (weight[item] >= 0x1000)
+ return 0;
+ if (weight[item] == 0)
+ return 1;
+ if ((crush_hash32_2(x, item) & 0xffff) < weight[item])
+ return 0;
+ return 1;
+}
+
+/**
+ * crush_choose - choose numrep distinct items of given type
+ * @map: the crush_map
+ * @bucket: the bucket we are choose an item from
+ * @x: crush input value
+ * @numrep: the number of items to choose
+ * @type: the type of item to choose
+ * @out: pointer to output vector
+ * @outpos: our position in that vector
+ * @firstn: true if choosing "first n" items, false if choosing "indep"
+ * @recurse_to_leaf: true if we want one device under each item of given type
+ * @out2: second output vector for leaf items (if @recurse_to_leaf)
+ */
+static int crush_choose(struct crush_map *map,
+ struct crush_bucket *bucket,
+ __u32 *weight,
+ int x, int numrep, int type,
+ int *out, int outpos,
+ int firstn, int recurse_to_leaf,
+ int *out2)
+{
+ int rep;
+ int ftotal, flocal;
+ int retry_descent, retry_bucket, skip_rep;
+ struct crush_bucket *in = bucket;
+ int r;
+ int i;
+ int item = 0;
+ int itemtype;
+ int collide, reject;
+ const int orig_tries = 5; /* attempts before we fall back to search */
+ dprintk("choose bucket %d x %d outpos %d\n", bucket->id, x, outpos);
+
+ for (rep = outpos; rep < numrep; rep++) {
+ /* keep trying until we get a non-out, non-colliding item */
+ ftotal = 0;
+ skip_rep = 0;
+ do {
+ retry_descent = 0;
+ in = bucket; /* initial bucket */
+
+ /* choose through intervening buckets */
+ flocal = 0;
+ do {
+ collide = 0;
+ retry_bucket = 0;
+ r = rep;
+ if (in->alg == CRUSH_BUCKET_UNIFORM) {
+ /* be careful */
+ if (firstn || numrep >= in->size)
+ /* r' = r + f_total */
+ r += ftotal;
+ else if (in->size % numrep == 0)
+ /* r'=r+(n+1)*f_local */
+ r += (numrep+1) *
+ (flocal+ftotal);
+ else
+ /* r' = r + n*f_local */
+ r += numrep * (flocal+ftotal);
+ } else {
+ if (firstn)
+ /* r' = r + f_total */
+ r += ftotal;
+ else
+ /* r' = r + n*f_local */
+ r += numrep * (flocal+ftotal);
+ }
+
+ /* bucket choose */
+ if (in->size == 0) {
+ reject = 1;
+ goto reject;
+ }
+ if (flocal >= (in->size>>1) &&
+ flocal > orig_tries)
+ item = bucket_perm_choose(in, x, r);
+ else
+ item = crush_bucket_choose(in, x, r);
+ BUG_ON(item >= map->max_devices);
+
+ /* desired type? */
+ if (item < 0)
+ itemtype = map->buckets[-1-item]->type;
+ else
+ itemtype = 0;
+ dprintk(" item %d type %d\n", item, itemtype);
+
+ /* keep going? */
+ if (itemtype != type) {
+ BUG_ON(item >= 0 ||
+ (-1-item) >= map->max_buckets);
+ in = map->buckets[-1-item];
+ continue;
+ }
+
+ /* collision? */
+ for (i = 0; i < outpos; i++) {
+ if (out[i] == item) {
+ collide = 1;
+ break;
+ }
+ }
+
+ if (recurse_to_leaf &&
+ item < 0 &&
+ crush_choose(map, map->buckets[-1-item],
+ weight,
+ x, outpos+1, 0,
+ out2, outpos,
+ firstn, 0, NULL) <= outpos) {
+ reject = 1;
+ } else {
+ /* out? */
+ if (itemtype == 0)
+ reject = is_out(map, weight,
+ item, x);
+ else
+ reject = 0;
+ }
+
+reject:
+ if (reject || collide) {
+ ftotal++;
+ flocal++;
+
+ if (collide && flocal < 3)
+ /* retry locally a few times */
+ retry_bucket = 1;
+ else if (flocal < in->size + orig_tries)
+ /* exhaustive bucket search */
+ retry_bucket = 1;
+ else if (ftotal < 20)
+ /* then retry descent */
+ retry_descent = 1;
+ else
+ /* else give up */
+ skip_rep = 1;
+ dprintk(" reject %d collide %d "
+ "ftotal %d flocal %d\n",
+ reject, collide, ftotal,
+ flocal);
+ }
+ } while (retry_bucket);
+ } while (retry_descent);
+
+ if (skip_rep) {
+ dprintk("skip rep\n");
+ continue;
+ }
+
+ dprintk("choose got %d\n", item);
+ out[outpos] = item;
+ outpos++;
+ }
+
+ dprintk("choose returns %d\n", outpos);
+ return outpos;
+}
+
+
+/**
+ * crush_do_rule - calculate a mapping with the given input and rule
+ * @map: the crush_map
+ * @ruleno: the rule id
+ * @x: hash input
+ * @result: pointer to result vector
+ * @result_max: maximum result size
+ * @force: force initial replica choice; -1 for none
+ */
+int crush_do_rule(struct crush_map *map,
+ int ruleno, int x, int *result, int result_max,
+ int force, __u32 *weight)
+{
+ int result_len;
+ int force_context[CRUSH_MAX_DEPTH];
+ int force_pos = -1;
+ int a[CRUSH_MAX_SET];
+ int b[CRUSH_MAX_SET];
+ int c[CRUSH_MAX_SET];
+ int recurse_to_leaf;
+ int *w;
+ int wsize = 0;
+ int *o;
+ int osize;
+ int *tmp;
+ struct crush_rule *rule;
+ int step;
+ int i, j;
+ int numrep;
+ int firstn;
+ int rc = -1;
+
+ BUG_ON(ruleno >= map->max_rules);
+
+ rule = map->rules[ruleno];
+ result_len = 0;
+ w = a;
+ o = b;
+
+ /*
+ * determine hierarchical context of force, if any. note
+ * that this may or may not correspond to the specific types
+ * referenced by the crush rule.
+ */
+ if (force >= 0) {
+ if (force >= map->max_devices ||
+ map->device_parents[force] == 0) {
+ /*dprintk("CRUSH: forcefed device dne\n");*/
+ rc = -1; /* force fed device dne */
+ goto out;
+ }
+ if (!is_out(map, weight, force, x)) {
+ while (1) {
+ force_context[++force_pos] = force;
+ if (force >= 0)
+ force = map->device_parents[force];
+ else
+ force = map->bucket_parents[-1-force];
+ if (force == 0)
+ break;
+ }
+ }
+ }
+
+ for (step = 0; step < rule->len; step++) {
+ firstn = 0;
+ switch (rule->steps[step].op) {
+ case CRUSH_RULE_TAKE:
+ w[0] = rule->steps[step].arg1;
+ if (force_pos >= 0) {
+ BUG_ON(force_context[force_pos] != w[0]);
+ force_pos--;
+ }
+ wsize = 1;
+ break;
+
+ case CRUSH_RULE_CHOOSE_LEAF_FIRSTN:
+ case CRUSH_RULE_CHOOSE_FIRSTN:
+ firstn = 1;
+ case CRUSH_RULE_CHOOSE_LEAF_INDEP:
+ case CRUSH_RULE_CHOOSE_INDEP:
+ BUG_ON(wsize == 0);
+
+ recurse_to_leaf =
+ rule->steps[step].op ==
+ CRUSH_RULE_CHOOSE_LEAF_FIRSTN ||
+ rule->steps[step].op ==
+ CRUSH_RULE_CHOOSE_LEAF_INDEP;
+
+ /* reset output */
+ osize = 0;
+
+ for (i = 0; i < wsize; i++) {
+ /*
+ * see CRUSH_N, CRUSH_N_MINUS macros.
+ * basically, numrep <= 0 means relative to
+ * the provided result_max
+ */
+ numrep = rule->steps[step].arg1;
+ if (numrep <= 0) {
+ numrep += result_max;
+ if (numrep <= 0)
+ continue;
+ }
+ j = 0;
+ if (osize == 0 && force_pos >= 0) {
+ /* skip any intermediate types */
+ while (force_pos &&
+ force_context[force_pos] < 0 &&
+ rule->steps[step].arg2 !=
+ map->buckets[-1 -
+ force_context[force_pos]]->type)
+ force_pos--;
+ o[osize] = force_context[force_pos];
+ if (recurse_to_leaf)
+ c[osize] = force_context[0];
+ j++;
+ force_pos--;
+ }
+ osize += crush_choose(map,
+ map->buckets[-1-w[i]],
+ weight,
+ x, numrep,
+ rule->steps[step].arg2,
+ o+osize, j,
+ firstn,
+ recurse_to_leaf, c+osize);
+ }
+
+ if (recurse_to_leaf)
+ /* copy final _leaf_ values to output set */
+ memcpy(o, c, osize*sizeof(*o));
+
+ /* swap t and w arrays */
+ tmp = o;
+ o = w;
+ w = tmp;
+ wsize = osize;
+ break;
+
+
+ case CRUSH_RULE_EMIT:
+ for (i = 0; i < wsize && result_len < result_max; i++) {
+ result[result_len] = w[i];
+ result_len++;
+ }
+ wsize = 0;
+ break;
+
+ default:
+ BUG_ON(1);
+ }
+ }
+ rc = result_len;
+
+out:
+ return rc;
+}
+
+
diff --git a/fs/ceph/crush/mapper.h b/fs/ceph/crush/mapper.h
new file mode 100644
index 000000000000..98e90046fd9f
--- /dev/null
+++ b/fs/ceph/crush/mapper.h
@@ -0,0 +1,20 @@
+#ifndef _CRUSH_MAPPER_H
+#define _CRUSH_MAPPER_H
+
+/*
+ * CRUSH functions for find rules and then mapping an input to an
+ * output set.
+ *
+ * LGPL2
+ */
+
+#include "crush.h"
+
+extern int crush_find_rule(struct crush_map *map, int pool, int type, int size);
+extern int crush_do_rule(struct crush_map *map,
+ int ruleno,
+ int x, int *result, int result_max,
+ int forcefeed, /* -1 for none */
+ __u32 *weights);
+
+#endif
diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c
new file mode 100644
index 000000000000..9edbad32f116
--- /dev/null
+++ b/fs/ceph/debugfs.c
@@ -0,0 +1,425 @@
+#include "ceph_debug.h"
+
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include "super.h"
+#include "mds_client.h"
+
+/*
+ * Implement /sys/kernel/debug/ceph fun
+ *
+ * /sys/kernel/debug/ceph/client* - an instance of the ceph client
+ * .../osdmap - current osdmap
+ * .../mdsmap - current mdsmap
+ * .../monmap - current monmap
+ * .../osdc - active osd requests
+ * .../mdsc - active mds requests
+ * .../monc - mon client state
+ * .../dentry_lru - dump contents of dentry lru
+ * .../caps - expose cap (reservation) stats
+ */
+
+static struct dentry *ceph_debugfs_dir;
+
+static int monmap_show(struct seq_file *s, void *p)
+{
+ int i;
+ struct ceph_client *client = s->private;
+
+ if (client->monc.monmap == NULL)
+ return 0;
+
+ seq_printf(s, "epoch %d\n", client->monc.monmap->epoch);
+ for (i = 0; i < client->monc.monmap->num_mon; i++) {
+ struct ceph_entity_inst *inst =
+ &client->monc.monmap->mon_inst[i];
+
+ seq_printf(s, "\t%s%lld\t%s\n",
+ ENTITY_NAME(inst->name),
+ pr_addr(&inst->addr.in_addr));
+ }
+ return 0;
+}
+
+static int mdsmap_show(struct seq_file *s, void *p)
+{
+ int i;
+ struct ceph_client *client = s->private;
+
+ if (client->mdsc.mdsmap == NULL)
+ return 0;
+ seq_printf(s, "epoch %d\n", client->mdsc.mdsmap->m_epoch);
+ seq_printf(s, "root %d\n", client->mdsc.mdsmap->m_root);
+ seq_printf(s, "session_timeout %d\n",
+ client->mdsc.mdsmap->m_session_timeout);
+ seq_printf(s, "session_autoclose %d\n",
+ client->mdsc.mdsmap->m_session_autoclose);
+ for (i = 0; i < client->mdsc.mdsmap->m_max_mds; i++) {
+ struct ceph_entity_addr *addr =
+ &client->mdsc.mdsmap->m_info[i].addr;
+ int state = client->mdsc.mdsmap->m_info[i].state;
+
+ seq_printf(s, "\tmds%d\t%s\t(%s)\n", i, pr_addr(&addr->in_addr),
+ ceph_mds_state_name(state));
+ }
+ return 0;
+}
+
+static int osdmap_show(struct seq_file *s, void *p)
+{
+ int i;
+ struct ceph_client *client = s->private;
+
+ if (client->osdc.osdmap == NULL)
+ return 0;
+ seq_printf(s, "epoch %d\n", client->osdc.osdmap->epoch);
+ seq_printf(s, "flags%s%s\n",
+ (client->osdc.osdmap->flags & CEPH_OSDMAP_NEARFULL) ?
+ " NEARFULL" : "",
+ (client->osdc.osdmap->flags & CEPH_OSDMAP_FULL) ?
+ " FULL" : "");
+ for (i = 0; i < client->osdc.osdmap->num_pools; i++) {
+ struct ceph_pg_pool_info *pool =
+ &client->osdc.osdmap->pg_pool[i];
+ seq_printf(s, "pg_pool %d pg_num %d / %d, lpg_num %d / %d\n",
+ i, pool->v.pg_num, pool->pg_num_mask,
+ pool->v.lpg_num, pool->lpg_num_mask);
+ }
+ for (i = 0; i < client->osdc.osdmap->max_osd; i++) {
+ struct ceph_entity_addr *addr =
+ &client->osdc.osdmap->osd_addr[i];
+ int state = client->osdc.osdmap->osd_state[i];
+ char sb[64];
+
+ seq_printf(s, "\tosd%d\t%s\t%3d%%\t(%s)\n",
+ i, pr_addr(&addr->in_addr),
+ ((client->osdc.osdmap->osd_weight[i]*100) >> 16),
+ ceph_osdmap_state_str(sb, sizeof(sb), state));
+ }
+ return 0;
+}
+
+static int monc_show(struct seq_file *s, void *p)
+{
+ struct ceph_client *client = s->private;
+ struct ceph_mon_statfs_request *req;
+ u64 nexttid = 0;
+ int got;
+ struct ceph_mon_client *monc = &client->monc;
+
+ mutex_lock(&monc->mutex);
+
+ if (monc->have_mdsmap)
+ seq_printf(s, "have mdsmap %u\n", (unsigned)monc->have_mdsmap);
+ if (monc->have_osdmap)
+ seq_printf(s, "have osdmap %u\n", (unsigned)monc->have_osdmap);
+ if (monc->want_next_osdmap)
+ seq_printf(s, "want next osdmap\n");
+
+ while (nexttid < monc->last_tid) {
+ got = radix_tree_gang_lookup(&monc->statfs_request_tree,
+ (void **)&req, nexttid, 1);
+ if (got == 0)
+ break;
+ nexttid = req->tid + 1;
+
+ seq_printf(s, "%lld statfs\n", req->tid);
+ }
+ mutex_unlock(&monc->mutex);
+
+ return 0;
+}
+
+static int mdsc_show(struct seq_file *s, void *p)
+{
+ struct ceph_client *client = s->private;
+ struct ceph_mds_request *req;
+ u64 nexttid = 0;
+ int got;
+ struct ceph_mds_client *mdsc = &client->mdsc;
+ int pathlen;
+ u64 pathbase;
+ char *path;
+
+ mutex_lock(&mdsc->mutex);
+ while (nexttid < mdsc->last_tid) {
+ got = radix_tree_gang_lookup(&mdsc->request_tree,
+ (void **)&req, nexttid, 1);
+ if (got == 0)
+ break;
+ nexttid = req->r_tid + 1;
+
+ if (req->r_request)
+ seq_printf(s, "%lld\tmds%d\t", req->r_tid, req->r_mds);
+ else
+ seq_printf(s, "%lld\t(no request)\t", req->r_tid);
+
+ seq_printf(s, "%s", ceph_mds_op_name(req->r_op));
+
+ if (req->r_got_unsafe)
+ seq_printf(s, "\t(unsafe)");
+ else
+ seq_printf(s, "\t");
+
+ if (req->r_inode) {
+ seq_printf(s, " #%llx", ceph_ino(req->r_inode));
+ } else if (req->r_dentry) {
+ path = ceph_mdsc_build_path(req->r_dentry, &pathlen,
+ &pathbase, 0);
+ spin_lock(&req->r_dentry->d_lock);
+ seq_printf(s, " #%llx/%.*s (%s)",
+ ceph_ino(req->r_dentry->d_parent->d_inode),
+ req->r_dentry->d_name.len,
+ req->r_dentry->d_name.name,
+ path ? path : "");
+ spin_unlock(&req->r_dentry->d_lock);
+ kfree(path);
+ } else if (req->r_path1) {
+ seq_printf(s, " #%llx/%s", req->r_ino1.ino,
+ req->r_path1);
+ }
+
+ if (req->r_old_dentry) {
+ path = ceph_mdsc_build_path(req->r_old_dentry, &pathlen,
+ &pathbase, 0);
+ spin_lock(&req->r_old_dentry->d_lock);
+ seq_printf(s, " #%llx/%.*s (%s)",
+ ceph_ino(req->r_old_dentry->d_parent->d_inode),
+ req->r_old_dentry->d_name.len,
+ req->r_old_dentry->d_name.name,
+ path ? path : "");
+ spin_unlock(&req->r_old_dentry->d_lock);
+ kfree(path);
+ } else if (req->r_path2) {
+ if (req->r_ino2.ino)
+ seq_printf(s, " #%llx/%s", req->r_ino2.ino,
+ req->r_path2);
+ else
+ seq_printf(s, " %s", req->r_path2);
+ }
+
+ seq_printf(s, "\n");
+ }
+ mutex_unlock(&mdsc->mutex);
+
+ return 0;
+}
+
+static int osdc_show(struct seq_file *s, void *pp)
+{
+ struct ceph_client *client = s->private;
+ struct ceph_osd_client *osdc = &client->osdc;
+ struct rb_node *p;
+
+ mutex_lock(&osdc->request_mutex);
+ for (p = rb_first(&osdc->requests); p; p = rb_next(p)) {
+ struct ceph_osd_request *req;
+ struct ceph_osd_request_head *head;
+ struct ceph_osd_op *op;
+ int num_ops;
+ int opcode, olen;
+ int i;
+
+ req = rb_entry(p, struct ceph_osd_request, r_node);
+
+ seq_printf(s, "%lld\tosd%d\t", req->r_tid,
+ req->r_osd ? req->r_osd->o_osd : -1);
+
+ head = req->r_request->front.iov_base;
+ op = (void *)(head + 1);
+
+ num_ops = le16_to_cpu(head->num_ops);
+ olen = le32_to_cpu(head->object_len);
+ seq_printf(s, "%.*s", olen,
+ (const char *)(head->ops + num_ops));
+
+ if (req->r_reassert_version.epoch)
+ seq_printf(s, "\t%u'%llu",
+ (unsigned)le32_to_cpu(req->r_reassert_version.epoch),
+ le64_to_cpu(req->r_reassert_version.version));
+ else
+ seq_printf(s, "\t");
+
+ for (i = 0; i < num_ops; i++) {
+ opcode = le16_to_cpu(op->op);
+ seq_printf(s, "\t%s", ceph_osd_op_name(opcode));
+ op++;
+ }
+
+ seq_printf(s, "\n");
+ }
+ mutex_unlock(&osdc->request_mutex);
+ return 0;
+}
+
+static int caps_show(struct seq_file *s, void *p)
+{
+ struct ceph_client *client = p;
+ int total, avail, used, reserved;
+
+ ceph_reservation_status(client, &total, &avail, &used, &reserved);
+ seq_printf(s, "total\t\t%d\n"
+ "avail\t\t%d\n"
+ "used\t\t%d\n"
+ "reserved\t%d\n",
+ total, avail, used, reserved);
+ return 0;
+}
+
+static int dentry_lru_show(struct seq_file *s, void *ptr)
+{
+ struct ceph_client *client = s->private;
+ struct ceph_mds_client *mdsc = &client->mdsc;
+ struct ceph_dentry_info *di;
+
+ spin_lock(&mdsc->dentry_lru_lock);
+ list_for_each_entry(di, &mdsc->dentry_lru, lru) {
+ struct dentry *dentry = di->dentry;
+ seq_printf(s, "%p %p\t%.*s\n",
+ di, dentry, dentry->d_name.len, dentry->d_name.name);
+ }
+ spin_unlock(&mdsc->dentry_lru_lock);
+
+ return 0;
+}
+
+#define DEFINE_SHOW_FUNC(name) \
+static int name##_open(struct inode *inode, struct file *file) \
+{ \
+ struct seq_file *sf; \
+ int ret; \
+ \
+ ret = single_open(file, name, NULL); \
+ sf = file->private_data; \
+ sf->private = inode->i_private; \
+ return ret; \
+} \
+ \
+static const struct file_operations name##_fops = { \
+ .open = name##_open, \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+ .release = single_release, \
+};
+
+DEFINE_SHOW_FUNC(monmap_show)
+DEFINE_SHOW_FUNC(mdsmap_show)
+DEFINE_SHOW_FUNC(osdmap_show)
+DEFINE_SHOW_FUNC(monc_show)
+DEFINE_SHOW_FUNC(mdsc_show)
+DEFINE_SHOW_FUNC(osdc_show)
+DEFINE_SHOW_FUNC(dentry_lru_show)
+DEFINE_SHOW_FUNC(caps_show)
+
+int __init ceph_debugfs_init(void)
+{
+ ceph_debugfs_dir = debugfs_create_dir("ceph", NULL);
+ if (!ceph_debugfs_dir)
+ return -ENOMEM;
+ return 0;
+}
+
+void ceph_debugfs_cleanup(void)
+{
+ debugfs_remove(ceph_debugfs_dir);
+}
+
+int ceph_debugfs_client_init(struct ceph_client *client)
+{
+ int ret = 0;
+ char name[80];
+
+ snprintf(name, sizeof(name), FSID_FORMAT ".client%lld",
+ PR_FSID(&client->monc.monmap->fsid), client->whoami);
+
+ client->debugfs_dir = debugfs_create_dir(name, ceph_debugfs_dir);
+ if (!client->debugfs_dir)
+ goto out;
+
+ client->monc.debugfs_file = debugfs_create_file("monc",
+ 0600,
+ client->debugfs_dir,
+ client,
+ &monc_show_fops);
+ if (!client->monc.debugfs_file)
+ goto out;
+
+ client->mdsc.debugfs_file = debugfs_create_file("mdsc",
+ 0600,
+ client->debugfs_dir,
+ client,
+ &mdsc_show_fops);
+ if (!client->mdsc.debugfs_file)
+ goto out;
+
+ client->osdc.debugfs_file = debugfs_create_file("osdc",
+ 0600,
+ client->debugfs_dir,
+ client,
+ &osdc_show_fops);
+ if (!client->osdc.debugfs_file)
+ goto out;
+
+ client->debugfs_monmap = debugfs_create_file("monmap",
+ 0600,
+ client->debugfs_dir,
+ client,
+ &monmap_show_fops);
+ if (!client->debugfs_monmap)
+ goto out;
+
+ client->debugfs_mdsmap = debugfs_create_file("mdsmap",
+ 0600,
+ client->debugfs_dir,
+ client,
+ &mdsmap_show_fops);
+ if (!client->debugfs_mdsmap)
+ goto out;
+
+ client->debugfs_osdmap = debugfs_create_file("osdmap",
+ 0600,
+ client->debugfs_dir,
+ client,
+ &osdmap_show_fops);
+ if (!client->debugfs_osdmap)
+ goto out;
+
+ client->debugfs_dentry_lru = debugfs_create_file("dentry_lru",
+ 0600,
+ client->debugfs_dir,
+ client,
+ &dentry_lru_show_fops);
+ if (!client->debugfs_dentry_lru)
+ goto out;
+
+ client->debugfs_caps = debugfs_create_file("caps",
+ 0400,
+ client->debugfs_dir,
+ client,
+ &caps_show_fops);
+ if (!client->debugfs_caps)
+ goto out;
+
+ return 0;
+
+out:
+ ceph_debugfs_client_cleanup(client);
+ return ret;
+}
+
+void ceph_debugfs_client_cleanup(struct ceph_client *client)
+{
+ debugfs_remove(client->debugfs_caps);
+ debugfs_remove(client->debugfs_dentry_lru);
+ debugfs_remove(client->debugfs_osdmap);
+ debugfs_remove(client->debugfs_mdsmap);
+ debugfs_remove(client->debugfs_monmap);
+ debugfs_remove(client->osdc.debugfs_file);
+ debugfs_remove(client->mdsc.debugfs_file);
+ debugfs_remove(client->monc.debugfs_file);
+ debugfs_remove(client->debugfs_dir);
+}
+
diff --git a/fs/ceph/decode.h b/fs/ceph/decode.h
new file mode 100644
index 000000000000..91179fb2cc3f
--- /dev/null
+++ b/fs/ceph/decode.h
@@ -0,0 +1,141 @@
+#ifndef __CEPH_DECODE_H
+#define __CEPH_DECODE_H
+
+#include <asm/unaligned.h>
+
+#include "types.h"
+
+/*
+ * in all cases,
+ * void **p pointer to position pointer
+ * void *end pointer to end of buffer (last byte + 1)
+ */
+
+static inline u64 ceph_decode_64(void **p)
+{
+ u64 v = get_unaligned_le64(*p);
+ *p += sizeof(u64);
+ return v;
+}
+static inline u32 ceph_decode_32(void **p)
+{
+ u32 v = get_unaligned_le32(*p);
+ *p += sizeof(u32);
+ return v;
+}
+static inline u16 ceph_decode_16(void **p)
+{
+ u16 v = get_unaligned_le16(*p);
+ *p += sizeof(u16);
+ return v;
+}
+static inline u8 ceph_decode_8(void **p)
+{
+ u8 v = *(u8 *)*p;
+ (*p)++;
+ return v;
+}
+static inline void ceph_decode_copy(void **p, void *pv, size_t n)
+{
+ memcpy(pv, *p, n);
+ *p += n;
+}
+
+/*
+ * bounds check input.
+ */
+#define ceph_decode_need(p, end, n, bad) \
+ do { \
+ if (unlikely(*(p) + (n) > (end))) \
+ goto bad; \
+ } while (0)
+
+#define ceph_decode_64_safe(p, end, v, bad) \
+ do { \
+ ceph_decode_need(p, end, sizeof(u64), bad); \
+ v = ceph_decode_64(p); \
+ } while (0)
+#define ceph_decode_32_safe(p, end, v, bad) \
+ do { \
+ ceph_decode_need(p, end, sizeof(u32), bad); \
+ v = ceph_decode_32(p); \
+ } while (0)
+#define ceph_decode_16_safe(p, end, v, bad) \
+ do { \
+ ceph_decode_need(p, end, sizeof(u16), bad); \
+ v = ceph_decode_16(p); \
+ } while (0)
+
+#define ceph_decode_copy_safe(p, end, pv, n, bad) \
+ do { \
+ ceph_decode_need(p, end, n, bad); \
+ ceph_decode_copy(p, pv, n); \
+ } while (0)
+
+/*
+ * struct ceph_timespec <-> struct timespec
+ */
+static inline void ceph_decode_timespec(struct timespec *ts,
+ struct ceph_timespec *tv)
+{
+ ts->tv_sec = le32_to_cpu(tv->tv_sec);
+ ts->tv_nsec = le32_to_cpu(tv->tv_nsec);
+}
+static inline void ceph_encode_timespec(struct ceph_timespec *tv,
+ struct timespec *ts)
+{
+ tv->tv_sec = cpu_to_le32(ts->tv_sec);
+ tv->tv_nsec = cpu_to_le32(ts->tv_nsec);
+}
+
+/*
+ * encoders
+ */
+static inline void ceph_encode_64(void **p, u64 v)
+{
+ put_unaligned_le64(v, (__le64 *)*p);
+ *p += sizeof(u64);
+}
+static inline void ceph_encode_32(void **p, u32 v)
+{
+ put_unaligned_le32(v, (__le32 *)*p);
+ *p += sizeof(u32);
+}
+static inline void ceph_encode_16(void **p, u16 v)
+{
+ put_unaligned_le16(v, (__le16 *)*p);
+ *p += sizeof(u16);
+}
+static inline void ceph_encode_8(void **p, u8 v)
+{
+ *(u8 *)*p = v;
+ (*p)++;
+}
+
+/*
+ * filepath, string encoders
+ */
+static inline void ceph_encode_filepath(void **p, void *end,
+ u64 ino, const char *path)
+{
+ u32 len = path ? strlen(path) : 0;
+ BUG_ON(*p + sizeof(ino) + sizeof(len) + len > end);
+ ceph_encode_64(p, ino);
+ ceph_encode_32(p, len);
+ if (len)
+ memcpy(*p, path, len);
+ *p += len;
+}
+
+static inline void ceph_encode_string(void **p, void *end,
+ const char *s, u32 len)
+{
+ BUG_ON(*p + sizeof(len) + len > end);
+ ceph_encode_32(p, len);
+ if (len)
+ memcpy(*p, s, len);
+ *p += len;
+}
+
+
+#endif
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
new file mode 100644
index 000000000000..7bb8db524e58
--- /dev/null
+++ b/fs/ceph/dir.c
@@ -0,0 +1,1212 @@
+#include "ceph_debug.h"
+
+#include <linux/spinlock.h>
+#include <linux/fs_struct.h>
+#include <linux/namei.h>
+#include <linux/sched.h>
+
+#include "super.h"
+
+/*
+ * Directory operations: readdir, lookup, create, link, unlink,
+ * rename, etc.
+ */
+
+/*
+ * Ceph MDS operations are specified in terms of a base ino and
+ * relative path. Thus, the client can specify an operation on a
+ * specific inode (e.g., a getattr due to fstat(2)), or as a path
+ * relative to, say, the root directory.
+ *
+ * Normally, we limit ourselves to strict inode ops (no path component)
+ * or dentry operations (a single path component relative to an ino). The
+ * exception to this is open_root_dentry(), which will open the mount
+ * point by name.
+ */
+
+const struct inode_operations ceph_dir_iops;
+const struct file_operations ceph_dir_fops;
+struct dentry_operations ceph_dentry_ops;
+
+/*
+ * Initialize ceph dentry state.
+ */
+int ceph_init_dentry(struct dentry *dentry)
+{
+ struct ceph_dentry_info *di;
+
+ if (dentry->d_fsdata)
+ return 0;
+
+ if (ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP)
+ dentry->d_op = &ceph_dentry_ops;
+ else if (ceph_snap(dentry->d_parent->d_inode) == CEPH_SNAPDIR)
+ dentry->d_op = &ceph_snapdir_dentry_ops;
+ else
+ dentry->d_op = &ceph_snap_dentry_ops;
+
+ di = kmem_cache_alloc(ceph_dentry_cachep, GFP_NOFS);
+ if (!di)
+ return -ENOMEM; /* oh well */
+
+ spin_lock(&dentry->d_lock);
+ if (dentry->d_fsdata) /* lost a race */
+ goto out_unlock;
+ di->dentry = dentry;
+ di->lease_session = NULL;
+ dentry->d_fsdata = di;
+ dentry->d_time = jiffies;
+ ceph_dentry_lru_add(dentry);
+out_unlock:
+ spin_unlock(&dentry->d_lock);
+ return 0;
+}
+
+
+
+/*
+ * for readdir, we encode the directory frag and offset within that
+ * frag into f_pos.
+ */
+static unsigned fpos_frag(loff_t p)
+{
+ return p >> 32;
+}
+static unsigned fpos_off(loff_t p)
+{
+ return p & 0xffffffff;
+}
+
+/*
+ * When possible, we try to satisfy a readdir by peeking at the
+ * dcache. We make this work by carefully ordering dentries on
+ * d_u.d_child when we initially get results back from the MDS, and
+ * falling back to a "normal" sync readdir if any dentries in the dir
+ * are dropped.
+ *
+ * I_COMPLETE tells indicates we have all dentries in the dir. It is
+ * defined IFF we hold CEPH_CAP_FILE_SHARED (which will be revoked by
+ * the MDS if/when the directory is modified).
+ */
+static int __dcache_readdir(struct file *filp,
+ void *dirent, filldir_t filldir)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct ceph_file_info *fi = filp->private_data;
+ struct dentry *parent = filp->f_dentry;
+ struct inode *dir = parent->d_inode;
+ struct list_head *p;
+ struct dentry *dentry, *last;
+ struct ceph_dentry_info *di;
+ int err = 0;
+
+ /* claim ref on last dentry we returned */
+ last = fi->dentry;
+ fi->dentry = NULL;
+
+ dout("__dcache_readdir %p at %llu (last %p)\n", dir, filp->f_pos,
+ last);
+
+ spin_lock(&dcache_lock);
+
+ /* start at beginning? */
+ if (filp->f_pos == 2 || (last &&
+ filp->f_pos < ceph_dentry(last)->offset)) {
+ if (list_empty(&parent->d_subdirs))
+ goto out_unlock;
+ p = parent->d_subdirs.prev;
+ dout(" initial p %p/%p\n", p->prev, p->next);
+ } else {
+ p = last->d_u.d_child.prev;
+ }
+
+more:
+ dentry = list_entry(p, struct dentry, d_u.d_child);
+ di = ceph_dentry(dentry);
+ while (1) {
+ dout(" p %p/%p d_subdirs %p/%p\n", p->prev, p->next,
+ parent->d_subdirs.prev, parent->d_subdirs.next);
+ if (p == &parent->d_subdirs) {
+ fi->at_end = 1;
+ goto out_unlock;
+ }
+ if (!d_unhashed(dentry) && dentry->d_inode &&
+ filp->f_pos <= di->offset)
+ break;
+ dout(" skipping %p %.*s at %llu (%llu)%s%s\n", dentry,
+ dentry->d_name.len, dentry->d_name.name, di->offset,
+ filp->f_pos, d_unhashed(dentry) ? " unhashed" : "",
+ !dentry->d_inode ? " null" : "");
+ p = p->prev;
+ dentry = list_entry(p, struct dentry, d_u.d_child);
+ di = ceph_dentry(dentry);
+ }
+
+ atomic_inc(&dentry->d_count);
+ spin_unlock(&dcache_lock);
+ spin_unlock(&inode->i_lock);
+
+ dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, filp->f_pos,
+ dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
+ filp->f_pos = di->offset;
+ err = filldir(dirent, dentry->d_name.name,
+ dentry->d_name.len, di->offset,
+ dentry->d_inode->i_ino,
+ dentry->d_inode->i_mode >> 12);
+
+ if (last) {
+ if (err < 0) {
+ /* remember our position */
+ fi->dentry = last;
+ fi->next_offset = di->offset;
+ } else {
+ dput(last);
+ }
+ last = NULL;
+ }
+
+ spin_lock(&inode->i_lock);
+ spin_lock(&dcache_lock);
+
+ if (err < 0)
+ goto out_unlock;
+
+ last = dentry;
+
+ p = p->prev;
+ filp->f_pos++;
+
+ /* make sure a dentry wasn't dropped while we didn't have dcache_lock */
+ if ((ceph_inode(dir)->i_ceph_flags & CEPH_I_COMPLETE))
+ goto more;
+ dout(" lost I_COMPLETE on %p; falling back to mds\n", dir);
+ err = -EAGAIN;
+
+out_unlock:
+ spin_unlock(&dcache_lock);
+
+ if (last) {
+ spin_unlock(&inode->i_lock);
+ dput(last);
+ spin_lock(&inode->i_lock);
+ }
+
+ return err;
+}
+
+/*
+ * make note of the last dentry we read, so we can
+ * continue at the same lexicographical point,
+ * regardless of what dir changes take place on the
+ * server.
+ */
+static int note_last_dentry(struct ceph_file_info *fi, const char *name,
+ int len)
+{
+ kfree(fi->last_name);
+ fi->last_name = kmalloc(len+1, GFP_NOFS);
+ if (!fi->last_name)
+ return -ENOMEM;
+ memcpy(fi->last_name, name, len);
+ fi->last_name[len] = 0;
+ dout("note_last_dentry '%s'\n", fi->last_name);
+ return 0;
+}
+
+static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+ struct ceph_file_info *fi = filp->private_data;
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_client *client = ceph_inode_to_client(inode);
+ struct ceph_mds_client *mdsc = &client->mdsc;
+ unsigned frag = fpos_frag(filp->f_pos);
+ int off = fpos_off(filp->f_pos);
+ int err;
+ u32 ftype;
+ struct ceph_mds_reply_info_parsed *rinfo;
+ const int max_entries = client->mount_args.max_readdir;
+
+ dout("readdir %p filp %p frag %u off %u\n", inode, filp, frag, off);
+ if (fi->at_end)
+ return 0;
+
+ /* always start with . and .. */
+ if (filp->f_pos == 0) {
+ /* note dir version at start of readdir so we can tell
+ * if any dentries get dropped */
+ fi->dir_release_count = ci->i_release_count;
+
+ dout("readdir off 0 -> '.'\n");
+ if (filldir(dirent, ".", 1, ceph_make_fpos(0, 0),
+ inode->i_ino, inode->i_mode >> 12) < 0)
+ return 0;
+ filp->f_pos = 1;
+ off = 1;
+ }
+ if (filp->f_pos == 1) {
+ dout("readdir off 1 -> '..'\n");
+ if (filldir(dirent, "..", 2, ceph_make_fpos(0, 1),
+ filp->f_dentry->d_parent->d_inode->i_ino,
+ inode->i_mode >> 12) < 0)
+ return 0;
+ filp->f_pos = 2;
+ off = 2;
+ }
+
+ /* can we use the dcache? */
+ spin_lock(&inode->i_lock);
+ if ((filp->f_pos == 2 || fi->dentry) &&
+ !ceph_test_opt(client, NOASYNCREADDIR) &&
+ (ci->i_ceph_flags & CEPH_I_COMPLETE) &&
+ __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) {
+ err = __dcache_readdir(filp, dirent, filldir);
+ if (err != -EAGAIN) {
+ spin_unlock(&inode->i_lock);
+ return err;
+ }
+ }
+ spin_unlock(&inode->i_lock);
+ if (fi->dentry) {
+ err = note_last_dentry(fi, fi->dentry->d_name.name,
+ fi->dentry->d_name.len);
+ if (err)
+ return err;
+ dput(fi->dentry);
+ fi->dentry = NULL;
+ }
+
+ /* proceed with a normal readdir */
+
+more:
+ /* do we have the correct frag content buffered? */
+ if (fi->frag != frag || fi->last_readdir == NULL) {
+ struct ceph_mds_request *req;
+ int op = ceph_snap(inode) == CEPH_SNAPDIR ?
+ CEPH_MDS_OP_LSSNAP : CEPH_MDS_OP_READDIR;
+
+ /* discard old result, if any */
+ if (fi->last_readdir)
+ ceph_mdsc_put_request(fi->last_readdir);
+
+ /* requery frag tree, as the frag topology may have changed */
+ frag = ceph_choose_frag(ceph_inode(inode), frag, NULL, NULL);
+
+ dout("readdir fetching %llx.%llx frag %x offset '%s'\n",
+ ceph_vinop(inode), frag, fi->last_name);
+ req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+ req->r_inode = igrab(inode);
+ req->r_dentry = dget(filp->f_dentry);
+ /* hints to request -> mds selection code */
+ req->r_direct_mode = USE_AUTH_MDS;
+ req->r_direct_hash = ceph_frag_value(frag);
+ req->r_direct_is_hash = true;
+ req->r_path2 = kstrdup(fi->last_name, GFP_NOFS);
+ req->r_readdir_offset = fi->next_offset;
+ req->r_args.readdir.frag = cpu_to_le32(frag);
+ req->r_args.readdir.max_entries = cpu_to_le32(max_entries);
+ req->r_num_caps = max_entries;
+ err = ceph_mdsc_do_request(mdsc, NULL, req);
+ if (err < 0) {
+ ceph_mdsc_put_request(req);
+ return err;
+ }
+ dout("readdir got and parsed readdir result=%d"
+ " on frag %x, end=%d, complete=%d\n", err, frag,
+ (int)req->r_reply_info.dir_end,
+ (int)req->r_reply_info.dir_complete);
+
+ if (!req->r_did_prepopulate) {
+ dout("readdir !did_prepopulate");
+ fi->dir_release_count--; /* preclude I_COMPLETE */
+ }
+
+ /* note next offset and last dentry name */
+ fi->offset = fi->next_offset;
+ fi->last_readdir = req;
+
+ if (req->r_reply_info.dir_end) {
+ kfree(fi->last_name);
+ fi->last_name = NULL;
+ fi->next_offset = 0;
+ } else {
+ rinfo = &req->r_reply_info;
+ err = note_last_dentry(fi,
+ rinfo->dir_dname[rinfo->dir_nr-1],
+ rinfo->dir_dname_len[rinfo->dir_nr-1]);
+ if (err)
+ return err;
+ fi->next_offset += rinfo->dir_nr;
+ }
+ }
+
+ rinfo = &fi->last_readdir->r_reply_info;
+ dout("readdir frag %x num %d off %d chunkoff %d\n", frag,
+ rinfo->dir_nr, off, fi->offset);
+ while (off - fi->offset >= 0 && off - fi->offset < rinfo->dir_nr) {
+ u64 pos = ceph_make_fpos(frag, off);
+ struct ceph_mds_reply_inode *in =
+ rinfo->dir_in[off - fi->offset].in;
+ dout("readdir off %d (%d/%d) -> %lld '%.*s' %p\n",
+ off, off - fi->offset, rinfo->dir_nr, pos,
+ rinfo->dir_dname_len[off - fi->offset],
+ rinfo->dir_dname[off - fi->offset], in);
+ BUG_ON(!in);
+ ftype = le32_to_cpu(in->mode) >> 12;
+ if (filldir(dirent,
+ rinfo->dir_dname[off - fi->offset],
+ rinfo->dir_dname_len[off - fi->offset],
+ pos,
+ le64_to_cpu(in->ino),
+ ftype) < 0) {
+ dout("filldir stopping us...\n");
+ return 0;
+ }
+ off++;
+ filp->f_pos = pos + 1;
+ }
+
+ if (fi->last_name) {
+ ceph_mdsc_put_request(fi->last_readdir);
+ fi->last_readdir = NULL;
+ goto more;
+ }
+
+ /* more frags? */
+ if (!ceph_frag_is_rightmost(frag)) {
+ frag = ceph_frag_next(frag);
+ off = 0;
+ filp->f_pos = ceph_make_fpos(frag, off);
+ dout("readdir next frag is %x\n", frag);
+ goto more;
+ }
+ fi->at_end = 1;
+
+ /*
+ * if dir_release_count still matches the dir, no dentries
+ * were released during the whole readdir, and we should have
+ * the complete dir contents in our cache.
+ */
+ spin_lock(&inode->i_lock);
+ if (ci->i_release_count == fi->dir_release_count) {
+ dout(" marking %p complete\n", inode);
+ ci->i_ceph_flags |= CEPH_I_COMPLETE;
+ ci->i_max_offset = filp->f_pos;
+ }
+ spin_unlock(&inode->i_lock);
+
+ dout("readdir %p filp %p done.\n", inode, filp);
+ return 0;
+}
+
+static void reset_readdir(struct ceph_file_info *fi)
+{
+ if (fi->last_readdir) {
+ ceph_mdsc_put_request(fi->last_readdir);
+ fi->last_readdir = NULL;
+ }
+ kfree(fi->last_name);
+ fi->next_offset = 2; /* compensate for . and .. */
+ if (fi->dentry) {
+ dput(fi->dentry);
+ fi->dentry = NULL;
+ }
+ fi->at_end = 0;
+}
+
+static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int origin)
+{
+ struct ceph_file_info *fi = file->private_data;
+ struct inode *inode = file->f_mapping->host;
+ loff_t old_offset = offset;
+ loff_t retval;
+
+ mutex_lock(&inode->i_mutex);
+ switch (origin) {
+ case SEEK_END:
+ offset += inode->i_size + 2; /* FIXME */
+ break;
+ case SEEK_CUR:
+ offset += file->f_pos;
+ }
+ retval = -EINVAL;
+ if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) {
+ if (offset != file->f_pos) {
+ file->f_pos = offset;
+ file->f_version = 0;
+ fi->at_end = 0;
+ }
+ retval = offset;
+
+ /*
+ * discard buffered readdir content on seekdir(0), or
+ * seek to new frag, or seek prior to current chunk.
+ */
+ if (offset == 0 ||
+ fpos_frag(offset) != fpos_frag(old_offset) ||
+ fpos_off(offset) < fi->offset) {
+ dout("dir_llseek dropping %p content\n", file);
+ reset_readdir(fi);
+ }
+
+ /* bump dir_release_count if we did a forward seek */
+ if (offset > old_offset)
+ fi->dir_release_count--;
+ }
+ mutex_unlock(&inode->i_mutex);
+ return retval;
+}
+
+/*
+ * Process result of a lookup/open request.
+ *
+ * Mainly, make sure we return the final req->r_dentry (if it already
+ * existed) in place of the original VFS-provided dentry when they
+ * differ.
+ *
+ * Gracefully handle the case where the MDS replies with -ENOENT and
+ * no trace (which it may do, at its discretion, e.g., if it doesn't
+ * care to issue a lease on the negative dentry).
+ */
+struct dentry *ceph_finish_lookup(struct ceph_mds_request *req,
+ struct dentry *dentry, int err)
+{
+ struct ceph_client *client = ceph_client(dentry->d_sb);
+ struct inode *parent = dentry->d_parent->d_inode;
+
+ /* .snap dir? */
+ if (err == -ENOENT &&
+ ceph_vino(parent).ino != CEPH_INO_ROOT && /* no .snap in root dir */
+ strcmp(dentry->d_name.name, client->mount_args.snapdir_name) == 0) {
+ struct inode *inode = ceph_get_snapdir(parent);
+ dout("ENOENT on snapdir %p '%.*s', linking to snapdir %p\n",
+ dentry, dentry->d_name.len, dentry->d_name.name, inode);
+ d_add(dentry, inode);
+ err = 0;
+ }
+
+ if (err == -ENOENT) {
+ /* no trace? */
+ err = 0;
+ if (!req->r_reply_info.head->is_dentry) {
+ dout("ENOENT and no trace, dentry %p inode %p\n",
+ dentry, dentry->d_inode);
+ if (dentry->d_inode) {
+ d_drop(dentry);
+ err = -ENOENT;
+ } else {
+ d_add(dentry, NULL);
+ }
+ }
+ }
+ if (err)
+ dentry = ERR_PTR(err);
+ else if (dentry != req->r_dentry)
+ dentry = dget(req->r_dentry); /* we got spliced */
+ else
+ dentry = NULL;
+ return dentry;
+}
+
+/*
+ * Look up a single dir entry. If there is a lookup intent, inform
+ * the MDS so that it gets our 'caps wanted' value in a single op.
+ */
+static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
+ struct nameidata *nd)
+{
+ struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
+ struct ceph_mds_client *mdsc = &client->mdsc;
+ struct ceph_mds_request *req;
+ int op;
+ int err;
+
+ dout("lookup %p dentry %p '%.*s'\n",
+ dir, dentry, dentry->d_name.len, dentry->d_name.name);
+
+ if (dentry->d_name.len > NAME_MAX)
+ return ERR_PTR(-ENAMETOOLONG);
+
+ err = ceph_init_dentry(dentry);
+ if (err < 0)
+ return ERR_PTR(err);
+
+ /* open (but not create!) intent? */
+ if (nd &&
+ (nd->flags & LOOKUP_OPEN) &&
+ (nd->flags & LOOKUP_CONTINUE) == 0 && /* only open last component */
+ !(nd->intent.open.flags & O_CREAT)) {
+ int mode = nd->intent.open.create_mode & ~current->fs->umask;
+ return ceph_lookup_open(dir, dentry, nd, mode, 1);
+ }
+
+ /* can we conclude ENOENT locally? */
+ if (dentry->d_inode == NULL) {
+ struct ceph_inode_info *ci = ceph_inode(dir);
+ struct ceph_dentry_info *di = ceph_dentry(dentry);
+
+ spin_lock(&dir->i_lock);
+ dout(" dir %p flags are %d\n", dir, ci->i_ceph_flags);
+ if (strncmp(dentry->d_name.name,
+ client->mount_args.snapdir_name,
+ dentry->d_name.len) &&
+ (ci->i_ceph_flags & CEPH_I_COMPLETE) &&
+ (__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) {
+ di->offset = ci->i_max_offset++;
+ spin_unlock(&dir->i_lock);
+ dout(" dir %p complete, -ENOENT\n", dir);
+ d_add(dentry, NULL);
+ di->lease_shared_gen = ci->i_shared_gen;
+ return NULL;
+ }
+ spin_unlock(&dir->i_lock);
+ }
+
+ op = ceph_snap(dir) == CEPH_SNAPDIR ?
+ CEPH_MDS_OP_LOOKUPSNAP : CEPH_MDS_OP_LOOKUP;
+ req = ceph_mdsc_create_request(mdsc, op, USE_ANY_MDS);
+ if (IS_ERR(req))
+ return ERR_PTR(PTR_ERR(req));
+ req->r_dentry = dget(dentry);
+ req->r_num_caps = 2;
+ /* we only need inode linkage */
+ req->r_args.getattr.mask = cpu_to_le32(CEPH_STAT_CAP_INODE);
+ req->r_locked_dir = dir;
+ err = ceph_mdsc_do_request(mdsc, NULL, req);
+ dentry = ceph_finish_lookup(req, dentry, err);
+ ceph_mdsc_put_request(req); /* will dput(dentry) */
+ dout("lookup result=%p\n", dentry);
+ return dentry;
+}
+
+/*
+ * If we do a create but get no trace back from the MDS, follow up with
+ * a lookup (the VFS expects us to link up the provided dentry).
+ */
+int ceph_handle_notrace_create(struct inode *dir, struct dentry *dentry)
+{
+ struct dentry *result = ceph_lookup(dir, dentry, NULL);
+
+ if (result && !IS_ERR(result)) {
+ /*
+ * We created the item, then did a lookup, and found
+ * it was already linked to another inode we already
+ * had in our cache (and thus got spliced). Link our
+ * dentry to that inode, but don't hash it, just in
+ * case the VFS wants to dereference it.
+ */
+ BUG_ON(!result->d_inode);
+ d_instantiate(dentry, result->d_inode);
+ return 0;
+ }
+ return PTR_ERR(result);
+}
+
+static int ceph_mknod(struct inode *dir, struct dentry *dentry,
+ int mode, dev_t rdev)
+{
+ struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
+ struct ceph_mds_client *mdsc = &client->mdsc;
+ struct ceph_mds_request *req;
+ int err;
+
+ if (ceph_snap(dir) != CEPH_NOSNAP)
+ return -EROFS;
+
+ dout("mknod in dir %p dentry %p mode 0%o rdev %d\n",
+ dir, dentry, mode, rdev);
+ req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_MKNOD, USE_AUTH_MDS);
+ if (IS_ERR(req)) {
+ d_drop(dentry);
+ return PTR_ERR(req);
+ }
+ req->r_dentry = dget(dentry);
+ req->r_num_caps = 2;
+ req->r_locked_dir = dir;
+ req->r_args.mknod.mode = cpu_to_le32(mode);
+ req->r_args.mknod.rdev = cpu_to_le32(rdev);
+ req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
+ req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
+ err = ceph_mdsc_do_request(mdsc, dir, req);
+ if (!err && !req->r_reply_info.head->is_dentry)
+ err = ceph_handle_notrace_create(dir, dentry);
+ ceph_mdsc_put_request(req);
+ if (err)
+ d_drop(dentry);
+ return err;
+}
+
+static int ceph_create(struct inode *dir, struct dentry *dentry, int mode,
+ struct nameidata *nd)
+{
+ dout("create in dir %p dentry %p name '%.*s'\n",
+ dir, dentry, dentry->d_name.len, dentry->d_name.name);
+
+ if (ceph_snap(dir) != CEPH_NOSNAP)
+ return -EROFS;
+
+ if (nd) {
+ BUG_ON((nd->flags & LOOKUP_OPEN) == 0);
+ dentry = ceph_lookup_open(dir, dentry, nd, mode, 0);
+ /* hrm, what should i do here if we get aliased? */
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
+ return 0;
+ }
+
+ /* fall back to mknod */
+ return ceph_mknod(dir, dentry, (mode & ~S_IFMT) | S_IFREG, 0);
+}
+
+static int ceph_symlink(struct inode *dir, struct dentry *dentry,
+ const char *dest)
+{
+ struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
+ struct ceph_mds_client *mdsc = &client->mdsc;
+ struct ceph_mds_request *req;
+ int err;
+
+ if (ceph_snap(dir) != CEPH_NOSNAP)
+ return -EROFS;
+
+ dout("symlink in dir %p dentry %p to '%s'\n", dir, dentry, dest);
+ req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SYMLINK, USE_AUTH_MDS);
+ if (IS_ERR(req)) {
+ d_drop(dentry);
+ return PTR_ERR(req);
+ }
+ req->r_dentry = dget(dentry);
+ req->r_num_caps = 2;
+ req->r_path2 = kstrdup(dest, GFP_NOFS);
+ req->r_locked_dir = dir;
+ req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
+ req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
+ err = ceph_mdsc_do_request(mdsc, dir, req);
+ if (!err && !req->r_reply_info.head->is_dentry)
+ err = ceph_handle_notrace_create(dir, dentry);
+ ceph_mdsc_put_request(req);
+ if (err)
+ d_drop(dentry);
+ return err;
+}
+
+static int ceph_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+ struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
+ struct ceph_mds_client *mdsc = &client->mdsc;
+ struct ceph_mds_request *req;
+ int err = -EROFS;
+ int op;
+
+ if (ceph_snap(dir) == CEPH_SNAPDIR) {
+ /* mkdir .snap/foo is a MKSNAP */
+ op = CEPH_MDS_OP_MKSNAP;
+ dout("mksnap dir %p snap '%.*s' dn %p\n", dir,
+ dentry->d_name.len, dentry->d_name.name, dentry);
+ } else if (ceph_snap(dir) == CEPH_NOSNAP) {
+ dout("mkdir dir %p dn %p mode 0%o\n", dir, dentry, mode);
+ op = CEPH_MDS_OP_MKDIR;
+ } else {
+ goto out;
+ }
+ req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ goto out;
+ }
+
+ req->r_dentry = dget(dentry);
+ req->r_num_caps = 2;
+ req->r_locked_dir = dir;
+ req->r_args.mkdir.mode = cpu_to_le32(mode);
+ req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
+ req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
+ err = ceph_mdsc_do_request(mdsc, dir, req);
+ if (!err && !req->r_reply_info.head->is_dentry)
+ err = ceph_handle_notrace_create(dir, dentry);
+ ceph_mdsc_put_request(req);
+out:
+ if (err < 0)
+ d_drop(dentry);
+ return err;
+}
+
+static int ceph_link(struct dentry *old_dentry, struct inode *dir,
+ struct dentry *dentry)
+{
+ struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
+ struct ceph_mds_client *mdsc = &client->mdsc;
+ struct ceph_mds_request *req;
+ int err;
+
+ if (ceph_snap(dir) != CEPH_NOSNAP)
+ return -EROFS;
+
+ dout("link in dir %p old_dentry %p dentry %p\n", dir,
+ old_dentry, dentry);
+ req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LINK, USE_AUTH_MDS);
+ if (IS_ERR(req)) {
+ d_drop(dentry);
+ return PTR_ERR(req);
+ }
+ req->r_dentry = dget(dentry);
+ req->r_num_caps = 2;
+ req->r_old_dentry = dget(old_dentry); /* or inode? hrm. */
+ req->r_locked_dir = dir;
+ req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
+ req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
+ err = ceph_mdsc_do_request(mdsc, dir, req);
+ if (err)
+ d_drop(dentry);
+ else if (!req->r_reply_info.head->is_dentry)
+ d_instantiate(dentry, igrab(old_dentry->d_inode));
+ ceph_mdsc_put_request(req);
+ return err;
+}
+
+/*
+ * For a soon-to-be unlinked file, drop the AUTH_RDCACHE caps. If it
+ * looks like the link count will hit 0, drop any other caps (other
+ * than PIN) we don't specifically want (due to the file still being
+ * open).
+ */
+static int drop_caps_for_unlink(struct inode *inode)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ int drop = CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL;
+
+ spin_lock(&inode->i_lock);
+ if (inode->i_nlink == 1) {
+ drop |= ~(__ceph_caps_wanted(ci) | CEPH_CAP_PIN);
+ ci->i_ceph_flags |= CEPH_I_NODELAY;
+ }
+ spin_unlock(&inode->i_lock);
+ return drop;
+}
+
+/*
+ * rmdir and unlink are differ only by the metadata op code
+ */
+static int ceph_unlink(struct inode *dir, struct dentry *dentry)
+{
+ struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
+ struct ceph_mds_client *mdsc = &client->mdsc;
+ struct inode *inode = dentry->d_inode;
+ struct ceph_mds_request *req;
+ int err = -EROFS;
+ int op;
+
+ if (ceph_snap(dir) == CEPH_SNAPDIR) {
+ /* rmdir .snap/foo is RMSNAP */
+ dout("rmsnap dir %p '%.*s' dn %p\n", dir, dentry->d_name.len,
+ dentry->d_name.name, dentry);
+ op = CEPH_MDS_OP_RMSNAP;
+ } else if (ceph_snap(dir) == CEPH_NOSNAP) {
+ dout("unlink/rmdir dir %p dn %p inode %p\n",
+ dir, dentry, inode);
+ op = ((dentry->d_inode->i_mode & S_IFMT) == S_IFDIR) ?
+ CEPH_MDS_OP_RMDIR : CEPH_MDS_OP_UNLINK;
+ } else
+ goto out;
+ req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ goto out;
+ }
+ req->r_dentry = dget(dentry);
+ req->r_num_caps = 2;
+ req->r_locked_dir = dir;
+ req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
+ req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
+ req->r_inode_drop = drop_caps_for_unlink(inode);
+ err = ceph_mdsc_do_request(mdsc, dir, req);
+ if (!err && !req->r_reply_info.head->is_dentry)
+ d_delete(dentry);
+ ceph_mdsc_put_request(req);
+out:
+ return err;
+}
+
+static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
+{
+ struct ceph_client *client = ceph_sb_to_client(old_dir->i_sb);
+ struct ceph_mds_client *mdsc = &client->mdsc;
+ struct ceph_mds_request *req;
+ int err;
+
+ if (ceph_snap(old_dir) != ceph_snap(new_dir))
+ return -EXDEV;
+ if (ceph_snap(old_dir) != CEPH_NOSNAP ||
+ ceph_snap(new_dir) != CEPH_NOSNAP)
+ return -EROFS;
+ dout("rename dir %p dentry %p to dir %p dentry %p\n",
+ old_dir, old_dentry, new_dir, new_dentry);
+ req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_RENAME, USE_AUTH_MDS);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+ req->r_dentry = dget(new_dentry);
+ req->r_num_caps = 2;
+ req->r_old_dentry = dget(old_dentry);
+ req->r_locked_dir = new_dir;
+ req->r_old_dentry_drop = CEPH_CAP_FILE_SHARED;
+ req->r_old_dentry_unless = CEPH_CAP_FILE_EXCL;
+ req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
+ req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
+ /* release LINK_RDCACHE on source inode (mds will lock it) */
+ req->r_old_inode_drop = CEPH_CAP_LINK_SHARED;
+ if (new_dentry->d_inode)
+ req->r_inode_drop = drop_caps_for_unlink(new_dentry->d_inode);
+ err = ceph_mdsc_do_request(mdsc, old_dir, req);
+ if (!err && !req->r_reply_info.head->is_dentry) {
+ /*
+ * Normally d_move() is done by fill_trace (called by
+ * do_request, above). If there is no trace, we need
+ * to do it here.
+ */
+ d_move(old_dentry, new_dentry);
+ }
+ ceph_mdsc_put_request(req);
+ return err;
+}
+
+
+/*
+ * Check if dentry lease is valid. If not, delete the lease. Try to
+ * renew if the least is more than half up.
+ */
+static int dentry_lease_is_valid(struct dentry *dentry)
+{
+ struct ceph_dentry_info *di;
+ struct ceph_mds_session *s;
+ int valid = 0;
+ u32 gen;
+ unsigned long ttl;
+ struct ceph_mds_session *session = NULL;
+ struct inode *dir = NULL;
+ u32 seq = 0;
+
+ spin_lock(&dentry->d_lock);
+ di = ceph_dentry(dentry);
+ if (di && di->lease_session) {
+ s = di->lease_session;
+ spin_lock(&s->s_cap_lock);
+ gen = s->s_cap_gen;
+ ttl = s->s_cap_ttl;
+ spin_unlock(&s->s_cap_lock);
+
+ if (di->lease_gen == gen &&
+ time_before(jiffies, dentry->d_time) &&
+ time_before(jiffies, ttl)) {
+ valid = 1;
+ if (di->lease_renew_after &&
+ time_after(jiffies, di->lease_renew_after)) {
+ /* we should renew */
+ dir = dentry->d_parent->d_inode;
+ session = ceph_get_mds_session(s);
+ seq = di->lease_seq;
+ di->lease_renew_after = 0;
+ di->lease_renew_from = jiffies;
+ }
+ } else {
+ __ceph_mdsc_drop_dentry_lease(dentry);
+ }
+ }
+ spin_unlock(&dentry->d_lock);
+
+ if (session) {
+ ceph_mdsc_lease_send_msg(session, dir, dentry,
+ CEPH_MDS_LEASE_RENEW, seq);
+ ceph_put_mds_session(session);
+ }
+ dout("dentry_lease_is_valid - dentry %p = %d\n", dentry, valid);
+ return valid;
+}
+
+/*
+ * Check if directory-wide content lease/cap is valid.
+ */
+static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry)
+{
+ struct ceph_inode_info *ci = ceph_inode(dir);
+ struct ceph_dentry_info *di = ceph_dentry(dentry);
+ int valid = 0;
+
+ spin_lock(&dir->i_lock);
+ if (ci->i_shared_gen == di->lease_shared_gen)
+ valid = __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1);
+ spin_unlock(&dir->i_lock);
+ dout("dir_lease_is_valid dir %p v%u dentry %p v%u = %d\n",
+ dir, (unsigned)ci->i_shared_gen, dentry,
+ (unsigned)di->lease_shared_gen, valid);
+ return valid;
+}
+
+/*
+ * Check if cached dentry can be trusted.
+ */
+static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd)
+{
+ struct inode *dir = dentry->d_parent->d_inode;
+
+ dout("d_revalidate %p '%.*s' inode %p\n", dentry,
+ dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
+
+ /* always trust cached snapped dentries, snapdir dentry */
+ if (ceph_snap(dir) != CEPH_NOSNAP) {
+ dout("d_revalidate %p '%.*s' inode %p is SNAPPED\n", dentry,
+ dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
+ goto out_touch;
+ }
+ if (dentry->d_inode && ceph_snap(dentry->d_inode) == CEPH_SNAPDIR)
+ goto out_touch;
+
+ if (dentry_lease_is_valid(dentry) ||
+ dir_lease_is_valid(dir, dentry))
+ goto out_touch;
+
+ dout("d_revalidate %p invalid\n", dentry);
+ d_drop(dentry);
+ return 0;
+out_touch:
+ ceph_dentry_lru_touch(dentry);
+ return 1;
+}
+
+/*
+ * When a dentry is released, clear the dir I_COMPLETE if it was part
+ * of the current dir gen.
+ */
+static void ceph_dentry_release(struct dentry *dentry)
+{
+ struct ceph_dentry_info *di = ceph_dentry(dentry);
+ struct inode *parent_inode = dentry->d_parent->d_inode;
+
+ if (parent_inode) {
+ struct ceph_inode_info *ci = ceph_inode(parent_inode);
+
+ spin_lock(&parent_inode->i_lock);
+ if (ci->i_shared_gen == di->lease_shared_gen) {
+ dout(" clearing %p complete (d_release)\n",
+ parent_inode);
+ ci->i_ceph_flags &= ~CEPH_I_COMPLETE;
+ ci->i_release_count++;
+ }
+ spin_unlock(&parent_inode->i_lock);
+ }
+ if (di) {
+ ceph_dentry_lru_del(dentry);
+ if (di->lease_session)
+ ceph_put_mds_session(di->lease_session);
+ kmem_cache_free(ceph_dentry_cachep, di);
+ dentry->d_fsdata = NULL;
+ }
+}
+
+static int ceph_snapdir_d_revalidate(struct dentry *dentry,
+ struct nameidata *nd)
+{
+ /*
+ * Eventually, we'll want to revalidate snapped metadata
+ * too... probably...
+ */
+ return 1;
+}
+
+
+
+/*
+ * read() on a dir. This weird interface hack only works if mounted
+ * with '-o dirstat'.
+ */
+static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size,
+ loff_t *ppos)
+{
+ struct ceph_file_info *cf = file->private_data;
+ struct inode *inode = file->f_dentry->d_inode;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ int left;
+
+ if (!ceph_test_opt(ceph_client(inode->i_sb), DIRSTAT))
+ return -EISDIR;
+
+ if (!cf->dir_info) {
+ cf->dir_info = kmalloc(1024, GFP_NOFS);
+ if (!cf->dir_info)
+ return -ENOMEM;
+ cf->dir_info_len =
+ sprintf(cf->dir_info,
+ "entries: %20lld\n"
+ " files: %20lld\n"
+ " subdirs: %20lld\n"
+ "rentries: %20lld\n"
+ " rfiles: %20lld\n"
+ " rsubdirs: %20lld\n"
+ "rbytes: %20lld\n"
+ "rctime: %10ld.%09ld\n",
+ ci->i_files + ci->i_subdirs,
+ ci->i_files,
+ ci->i_subdirs,
+ ci->i_rfiles + ci->i_rsubdirs,
+ ci->i_rfiles,
+ ci->i_rsubdirs,
+ ci->i_rbytes,
+ (long)ci->i_rctime.tv_sec,
+ (long)ci->i_rctime.tv_nsec);
+ }
+
+ if (*ppos >= cf->dir_info_len)
+ return 0;
+ size = min_t(unsigned, size, cf->dir_info_len-*ppos);
+ left = copy_to_user(buf, cf->dir_info + *ppos, size);
+ if (left == size)
+ return -EFAULT;
+ *ppos += (size - left);
+ return size - left;
+}
+
+/*
+ * an fsync() on a dir will wait for any uncommitted directory
+ * operations to commit.
+ */
+static int ceph_dir_fsync(struct file *file, struct dentry *dentry,
+ int datasync)
+{
+ struct inode *inode = dentry->d_inode;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct list_head *head = &ci->i_unsafe_dirops;
+ struct ceph_mds_request *req;
+ u64 last_tid;
+ int ret = 0;
+
+ dout("dir_fsync %p\n", inode);
+ spin_lock(&ci->i_unsafe_lock);
+ if (list_empty(head))
+ goto out;
+
+ req = list_entry(head->prev,
+ struct ceph_mds_request, r_unsafe_dir_item);
+ last_tid = req->r_tid;
+
+ do {
+ ceph_mdsc_get_request(req);
+ spin_unlock(&ci->i_unsafe_lock);
+ dout("dir_fsync %p wait on tid %llu (until %llu)\n",
+ inode, req->r_tid, last_tid);
+ if (req->r_timeout) {
+ ret = wait_for_completion_timeout(
+ &req->r_safe_completion, req->r_timeout);
+ if (ret > 0)
+ ret = 0;
+ else if (ret == 0)
+ ret = -EIO; /* timed out */
+ } else {
+ wait_for_completion(&req->r_safe_completion);
+ }
+ spin_lock(&ci->i_unsafe_lock);
+ ceph_mdsc_put_request(req);
+
+ if (ret || list_empty(head))
+ break;
+ req = list_entry(head->next,
+ struct ceph_mds_request, r_unsafe_dir_item);
+ } while (req->r_tid < last_tid);
+out:
+ spin_unlock(&ci->i_unsafe_lock);
+ return ret;
+}
+
+/*
+ * We maintain a private dentry LRU.
+ *
+ * FIXME: this needs to be changed to a per-mds lru to be useful.
+ */
+void ceph_dentry_lru_add(struct dentry *dn)
+{
+ struct ceph_dentry_info *di = ceph_dentry(dn);
+ struct ceph_mds_client *mdsc;
+ dout("dentry_lru_add %p %p\t%.*s\n",
+ di, dn, dn->d_name.len, dn->d_name.name);
+
+ if (di) {
+ mdsc = &ceph_client(dn->d_sb)->mdsc;
+ spin_lock(&mdsc->dentry_lru_lock);
+ list_add_tail(&di->lru, &mdsc->dentry_lru);
+ mdsc->num_dentry++;
+ spin_unlock(&mdsc->dentry_lru_lock);
+ }
+}
+
+void ceph_dentry_lru_touch(struct dentry *dn)
+{
+ struct ceph_dentry_info *di = ceph_dentry(dn);
+ struct ceph_mds_client *mdsc;
+ dout("dentry_lru_touch %p %p\t%.*s\n",
+ di, dn, dn->d_name.len, dn->d_name.name);
+
+ if (di) {
+ mdsc = &ceph_client(dn->d_sb)->mdsc;
+ spin_lock(&mdsc->dentry_lru_lock);
+ list_move_tail(&di->lru, &mdsc->dentry_lru);
+ spin_unlock(&mdsc->dentry_lru_lock);
+ }
+}
+
+void ceph_dentry_lru_del(struct dentry *dn)
+{
+ struct ceph_dentry_info *di = ceph_dentry(dn);
+ struct ceph_mds_client *mdsc;
+
+ dout("dentry_lru_del %p %p\t%.*s\n",
+ di, dn, dn->d_name.len, dn->d_name.name);
+ if (di) {
+ mdsc = &ceph_client(dn->d_sb)->mdsc;
+ spin_lock(&mdsc->dentry_lru_lock);
+ list_del_init(&di->lru);
+ mdsc->num_dentry--;
+ spin_unlock(&mdsc->dentry_lru_lock);
+ }
+}
+
+const struct file_operations ceph_dir_fops = {
+ .read = ceph_read_dir,
+ .readdir = ceph_readdir,
+ .llseek = ceph_dir_llseek,
+ .open = ceph_open,
+ .release = ceph_release,
+ .unlocked_ioctl = ceph_ioctl,
+ .fsync = ceph_dir_fsync,
+};
+
+const struct inode_operations ceph_dir_iops = {
+ .lookup = ceph_lookup,
+ .permission = ceph_permission,
+ .getattr = ceph_getattr,
+ .setattr = ceph_setattr,
+ .setxattr = ceph_setxattr,
+ .getxattr = ceph_getxattr,
+ .listxattr = ceph_listxattr,
+ .removexattr = ceph_removexattr,
+ .mknod = ceph_mknod,
+ .symlink = ceph_symlink,
+ .mkdir = ceph_mkdir,
+ .link = ceph_link,
+ .unlink = ceph_unlink,
+ .rmdir = ceph_unlink,
+ .rename = ceph_rename,
+ .create = ceph_create,
+};
+
+struct dentry_operations ceph_dentry_ops = {
+ .d_revalidate = ceph_d_revalidate,
+ .d_release = ceph_dentry_release,
+};
+
+struct dentry_operations ceph_snapdir_dentry_ops = {
+ .d_revalidate = ceph_snapdir_d_revalidate,
+};
+
+struct dentry_operations ceph_snap_dentry_ops = {
+};
diff --git a/fs/ceph/export.c b/fs/ceph/export.c
new file mode 100644
index 000000000000..fc68e39cbad6
--- /dev/null
+++ b/fs/ceph/export.c
@@ -0,0 +1,223 @@
+#include "ceph_debug.h"
+
+#include <linux/exportfs.h>
+#include <asm/unaligned.h>
+
+#include "super.h"
+
+/*
+ * NFS export support
+ *
+ * NFS re-export of a ceph mount is, at present, only semireliable.
+ * The basic issue is that the Ceph architectures doesn't lend itself
+ * well to generating filehandles that will remain valid forever.
+ *
+ * So, we do our best. If you're lucky, your inode will be in the
+ * client's cache. If it's not, and you have a connectable fh, then
+ * the MDS server may be able to find it for you. Otherwise, you get
+ * ESTALE.
+ *
+ * There are ways to this more reliable, but in the non-connectable fh
+ * case, we won't every work perfectly, and in the connectable case,
+ * some changes are needed on the MDS side to work better.
+ */
+
+/*
+ * Basic fh
+ */
+struct ceph_nfs_fh {
+ u64 ino;
+} __attribute__ ((packed));
+
+/*
+ * Larger 'connectable' fh that includes parent ino and name hash.
+ * Use this whenever possible, as it works more reliably.
+ */
+struct ceph_nfs_confh {
+ u64 ino, parent_ino;
+ u32 parent_name_hash;
+} __attribute__ ((packed));
+
+static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len,
+ int connectable)
+{
+ struct ceph_nfs_fh *fh = (void *)rawfh;
+ struct ceph_nfs_confh *cfh = (void *)rawfh;
+ struct dentry *parent = dentry->d_parent;
+ struct inode *inode = dentry->d_inode;
+ int type;
+
+ /* don't re-export snaps */
+ if (ceph_snap(inode) != CEPH_NOSNAP)
+ return -EINVAL;
+
+ if (*max_len >= sizeof(*cfh)) {
+ dout("encode_fh %p connectable\n", dentry);
+ cfh->ino = ceph_ino(dentry->d_inode);
+ cfh->parent_ino = ceph_ino(parent->d_inode);
+ cfh->parent_name_hash = parent->d_name.hash;
+ *max_len = sizeof(*cfh);
+ type = 2;
+ } else if (*max_len > sizeof(*fh)) {
+ if (connectable)
+ return -ENOSPC;
+ dout("encode_fh %p\n", dentry);
+ fh->ino = ceph_ino(dentry->d_inode);
+ *max_len = sizeof(*fh);
+ type = 1;
+ } else {
+ return -ENOSPC;
+ }
+ return type;
+}
+
+/*
+ * convert regular fh to dentry
+ *
+ * FIXME: we should try harder by querying the mds for the ino.
+ */
+static struct dentry *__fh_to_dentry(struct super_block *sb,
+ struct ceph_nfs_fh *fh)
+{
+ struct inode *inode;
+ struct dentry *dentry;
+ struct ceph_vino vino;
+ int err;
+
+ dout("__fh_to_dentry %llx\n", fh->ino);
+ vino.ino = fh->ino;
+ vino.snap = CEPH_NOSNAP;
+ inode = ceph_find_inode(sb, vino);
+ if (!inode)
+ return ERR_PTR(-ESTALE);
+
+ dentry = d_obtain_alias(inode);
+ if (!dentry) {
+ pr_err("fh_to_dentry %llx -- inode %p but ENOMEM\n",
+ fh->ino, inode);
+ iput(inode);
+ return ERR_PTR(-ENOMEM);
+ }
+ err = ceph_init_dentry(dentry);
+
+ if (err < 0) {
+ iput(inode);
+ return ERR_PTR(err);
+ }
+ dout("__fh_to_dentry %llx %p dentry %p\n", fh->ino, inode, dentry);
+ return dentry;
+}
+
+/*
+ * convert connectable fh to dentry
+ */
+static struct dentry *__cfh_to_dentry(struct super_block *sb,
+ struct ceph_nfs_confh *cfh)
+{
+ struct ceph_mds_client *mdsc = &ceph_client(sb)->mdsc;
+ struct inode *inode;
+ struct dentry *dentry;
+ struct ceph_vino vino;
+ int err;
+
+ dout("__cfh_to_dentry %llx (%llx/%x)\n",
+ cfh->ino, cfh->parent_ino, cfh->parent_name_hash);
+
+ vino.ino = cfh->ino;
+ vino.snap = CEPH_NOSNAP;
+ inode = ceph_find_inode(sb, vino);
+ if (!inode) {
+ struct ceph_mds_request *req;
+
+ req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPHASH,
+ USE_ANY_MDS);
+ if (IS_ERR(req))
+ return ERR_PTR(PTR_ERR(req));
+
+ req->r_ino1 = vino;
+ req->r_ino2.ino = cfh->parent_ino;
+ req->r_ino2.snap = CEPH_NOSNAP;
+ req->r_path2 = kmalloc(16, GFP_NOFS);
+ snprintf(req->r_path2, 16, "%d", cfh->parent_name_hash);
+ req->r_num_caps = 1;
+ err = ceph_mdsc_do_request(mdsc, NULL, req);
+ ceph_mdsc_put_request(req);
+ inode = ceph_find_inode(sb, vino);
+ if (!inode)
+ return ERR_PTR(err ? err : -ESTALE);
+ }
+
+ dentry = d_obtain_alias(inode);
+ if (!dentry) {
+ pr_err("cfh_to_dentry %llx -- inode %p but ENOMEM\n",
+ cfh->ino, inode);
+ iput(inode);
+ return ERR_PTR(-ENOMEM);
+ }
+ err = ceph_init_dentry(dentry);
+ if (err < 0) {
+ iput(inode);
+ return ERR_PTR(err);
+ }
+ dout("__cfh_to_dentry %llx %p dentry %p\n", cfh->ino, inode, dentry);
+ return dentry;
+}
+
+static struct dentry *ceph_fh_to_dentry(struct super_block *sb, struct fid *fid,
+ int fh_len, int fh_type)
+{
+ if (fh_type == 1)
+ return __fh_to_dentry(sb, (struct ceph_nfs_fh *)fid->raw);
+ else
+ return __cfh_to_dentry(sb, (struct ceph_nfs_confh *)fid->raw);
+}
+
+/*
+ * get parent, if possible.
+ *
+ * FIXME: we could do better by querying the mds to discover the
+ * parent.
+ */
+static struct dentry *ceph_fh_to_parent(struct super_block *sb,
+ struct fid *fid,
+ int fh_len, int fh_type)
+{
+ struct ceph_nfs_confh *cfh = (void *)fid->raw;
+ struct ceph_vino vino;
+ struct inode *inode;
+ struct dentry *dentry;
+ int err;
+
+ if (fh_type == 1)
+ return ERR_PTR(-ESTALE);
+
+ pr_debug("fh_to_parent %llx/%d\n", cfh->parent_ino,
+ cfh->parent_name_hash);
+
+ vino.ino = cfh->ino;
+ vino.snap = CEPH_NOSNAP;
+ inode = ceph_find_inode(sb, vino);
+ if (!inode)
+ return ERR_PTR(-ESTALE);
+
+ dentry = d_obtain_alias(inode);
+ if (!dentry) {
+ pr_err("fh_to_parent %llx -- inode %p but ENOMEM\n",
+ cfh->ino, inode);
+ iput(inode);
+ return ERR_PTR(-ENOMEM);
+ }
+ err = ceph_init_dentry(dentry);
+ if (err < 0) {
+ iput(inode);
+ return ERR_PTR(err);
+ }
+ dout("fh_to_parent %llx %p dentry %p\n", cfh->ino, inode, dentry);
+ return dentry;
+}
+
+const struct export_operations ceph_export_ops = {
+ .encode_fh = ceph_encode_fh,
+ .fh_to_dentry = ceph_fh_to_dentry,
+ .fh_to_parent = ceph_fh_to_parent,
+};
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
new file mode 100644
index 000000000000..1bd57c8953bf
--- /dev/null
+++ b/fs/ceph/file.c
@@ -0,0 +1,904 @@
+#include "ceph_debug.h"
+
+#include <linux/sched.h>
+#include <linux/file.h>
+#include <linux/namei.h>
+#include <linux/writeback.h>
+
+#include "super.h"
+#include "mds_client.h"
+
+/*
+ * Ceph file operations
+ *
+ * Implement basic open/close functionality, and implement
+ * read/write.
+ *
+ * We implement three modes of file I/O:
+ * - buffered uses the generic_file_aio_{read,write} helpers
+ *
+ * - synchronous is used when there is multi-client read/write
+ * sharing, avoids the page cache, and synchronously waits for an
+ * ack from the OSD.
+ *
+ * - direct io takes the variant of the sync path that references
+ * user pages directly.
+ *
+ * fsync() flushes and waits on dirty pages, but just queues metadata
+ * for writeback: since the MDS can recover size and mtime there is no
+ * need to wait for MDS acknowledgement.
+ */
+
+
+/*
+ * Prepare an open request. Preallocate ceph_cap to avoid an
+ * inopportune ENOMEM later.
+ */
+static struct ceph_mds_request *
+prepare_open_request(struct super_block *sb, int flags, int create_mode)
+{
+ struct ceph_client *client = ceph_sb_to_client(sb);
+ struct ceph_mds_client *mdsc = &client->mdsc;
+ struct ceph_mds_request *req;
+ int want_auth = USE_ANY_MDS;
+ int op = (flags & O_CREAT) ? CEPH_MDS_OP_CREATE : CEPH_MDS_OP_OPEN;
+
+ if (flags & (O_WRONLY|O_RDWR|O_CREAT|O_TRUNC))
+ want_auth = USE_AUTH_MDS;
+
+ req = ceph_mdsc_create_request(mdsc, op, want_auth);
+ if (IS_ERR(req))
+ goto out;
+ req->r_fmode = ceph_flags_to_mode(flags);
+ req->r_args.open.flags = cpu_to_le32(flags);
+ req->r_args.open.mode = cpu_to_le32(create_mode);
+ req->r_args.open.preferred = -1;
+out:
+ return req;
+}
+
+/*
+ * initialize private struct file data.
+ * if we fail, clean up by dropping fmode reference on the ceph_inode
+ */
+static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
+{
+ struct ceph_file_info *cf;
+ int ret = 0;
+
+ switch (inode->i_mode & S_IFMT) {
+ case S_IFREG:
+ case S_IFDIR:
+ dout("init_file %p %p 0%o (regular)\n", inode, file,
+ inode->i_mode);
+ cf = kmem_cache_alloc(ceph_file_cachep, GFP_NOFS | __GFP_ZERO);
+ if (cf == NULL) {
+ ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
+ return -ENOMEM;
+ }
+ cf->fmode = fmode;
+ cf->next_offset = 2;
+ file->private_data = cf;
+ BUG_ON(inode->i_fop->release != ceph_release);
+ break;
+
+ case S_IFLNK:
+ dout("init_file %p %p 0%o (symlink)\n", inode, file,
+ inode->i_mode);
+ ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
+ break;
+
+ default:
+ dout("init_file %p %p 0%o (special)\n", inode, file,
+ inode->i_mode);
+ /*
+ * we need to drop the open ref now, since we don't
+ * have .release set to ceph_release.
+ */
+ ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
+ BUG_ON(inode->i_fop->release == ceph_release);
+
+ /* call the proper open fop */
+ ret = inode->i_fop->open(inode, file);
+ }
+ return ret;
+}
+
+/*
+ * If the filp already has private_data, that means the file was
+ * already opened by intent during lookup, and we do nothing.
+ *
+ * If we already have the requisite capabilities, we can satisfy
+ * the open request locally (no need to request new caps from the
+ * MDS). We do, however, need to inform the MDS (asynchronously)
+ * if our wanted caps set expands.
+ */
+int ceph_open(struct inode *inode, struct file *file)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_client *client = ceph_sb_to_client(inode->i_sb);
+ struct ceph_mds_client *mdsc = &client->mdsc;
+ struct ceph_mds_request *req;
+ struct ceph_file_info *cf = file->private_data;
+ struct inode *parent_inode = file->f_dentry->d_parent->d_inode;
+ int err;
+ int flags, fmode, wanted;
+
+ if (cf) {
+ dout("open file %p is already opened\n", file);
+ return 0;
+ }
+
+ /* filter out O_CREAT|O_EXCL; vfs did that already. yuck. */
+ flags = file->f_flags & ~(O_CREAT|O_EXCL);
+ if (S_ISDIR(inode->i_mode))
+ flags = O_DIRECTORY; /* mds likes to know */
+
+ dout("open inode %p ino %llx.%llx file %p flags %d (%d)\n", inode,
+ ceph_vinop(inode), file, flags, file->f_flags);
+ fmode = ceph_flags_to_mode(flags);
+ wanted = ceph_caps_for_mode(fmode);
+
+ /* snapped files are read-only */
+ if (ceph_snap(inode) != CEPH_NOSNAP && (file->f_mode & FMODE_WRITE))
+ return -EROFS;
+
+ /* trivially open snapdir */
+ if (ceph_snap(inode) == CEPH_SNAPDIR) {
+ spin_lock(&inode->i_lock);
+ __ceph_get_fmode(ci, fmode);
+ spin_unlock(&inode->i_lock);
+ return ceph_init_file(inode, file, fmode);
+ }
+
+ /*
+ * No need to block if we have any caps. Update wanted set
+ * asynchronously.
+ */
+ spin_lock(&inode->i_lock);
+ if (__ceph_is_any_real_caps(ci)) {
+ int mds_wanted = __ceph_caps_mds_wanted(ci);
+ int issued = __ceph_caps_issued(ci, NULL);
+
+ dout("open %p fmode %d want %s issued %s using existing\n",
+ inode, fmode, ceph_cap_string(wanted),
+ ceph_cap_string(issued));
+ __ceph_get_fmode(ci, fmode);
+ spin_unlock(&inode->i_lock);
+
+ /* adjust wanted? */
+ if ((issued & wanted) != wanted &&
+ (mds_wanted & wanted) != wanted &&
+ ceph_snap(inode) != CEPH_SNAPDIR)
+ ceph_check_caps(ci, 0, NULL);
+
+ return ceph_init_file(inode, file, fmode);
+ } else if (ceph_snap(inode) != CEPH_NOSNAP &&
+ (ci->i_snap_caps & wanted) == wanted) {
+ __ceph_get_fmode(ci, fmode);
+ spin_unlock(&inode->i_lock);
+ return ceph_init_file(inode, file, fmode);
+ }
+ spin_unlock(&inode->i_lock);
+
+ dout("open fmode %d wants %s\n", fmode, ceph_cap_string(wanted));
+ req = prepare_open_request(inode->i_sb, flags, 0);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ goto out;
+ }
+ req->r_inode = igrab(inode);
+ req->r_num_caps = 1;
+ err = ceph_mdsc_do_request(mdsc, parent_inode, req);
+ if (!err)
+ err = ceph_init_file(inode, file, req->r_fmode);
+ ceph_mdsc_put_request(req);
+ dout("open result=%d on %llx.%llx\n", err, ceph_vinop(inode));
+out:
+ return err;
+}
+
+
+/*
+ * Do a lookup + open with a single request.
+ *
+ * If this succeeds, but some subsequent check in the vfs
+ * may_open() fails, the struct *file gets cleaned up (i.e.
+ * ceph_release gets called). So fear not!
+ */
+/*
+ * flags
+ * path_lookup_open -> LOOKUP_OPEN
+ * path_lookup_create -> LOOKUP_OPEN|LOOKUP_CREATE
+ */
+struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
+ struct nameidata *nd, int mode,
+ int locked_dir)
+{
+ struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
+ struct ceph_mds_client *mdsc = &client->mdsc;
+ struct file *file = nd->intent.open.file;
+ struct inode *parent_inode = get_dentry_parent_inode(file->f_dentry);
+ struct ceph_mds_request *req;
+ int err;
+ int flags = nd->intent.open.flags - 1; /* silly vfs! */
+
+ dout("ceph_lookup_open dentry %p '%.*s' flags %d mode 0%o\n",
+ dentry, dentry->d_name.len, dentry->d_name.name, flags, mode);
+
+ /* do the open */
+ req = prepare_open_request(dir->i_sb, flags, mode);
+ if (IS_ERR(req))
+ return ERR_PTR(PTR_ERR(req));
+ req->r_dentry = dget(dentry);
+ req->r_num_caps = 2;
+ if (flags & O_CREAT) {
+ req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
+ req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
+ }
+ req->r_locked_dir = dir; /* caller holds dir->i_mutex */
+ err = ceph_mdsc_do_request(mdsc, parent_inode, req);
+ dentry = ceph_finish_lookup(req, dentry, err);
+ if (!err && (flags & O_CREAT) && !req->r_reply_info.head->is_dentry)
+ err = ceph_handle_notrace_create(dir, dentry);
+ if (!err)
+ err = ceph_init_file(req->r_dentry->d_inode, file,
+ req->r_fmode);
+ ceph_mdsc_put_request(req);
+ dout("ceph_lookup_open result=%p\n", dentry);
+ return dentry;
+}
+
+int ceph_release(struct inode *inode, struct file *file)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_file_info *cf = file->private_data;
+
+ dout("release inode %p file %p\n", inode, file);
+ ceph_put_fmode(ci, cf->fmode);
+ if (cf->last_readdir)
+ ceph_mdsc_put_request(cf->last_readdir);
+ kfree(cf->last_name);
+ kfree(cf->dir_info);
+ dput(cf->dentry);
+ kmem_cache_free(ceph_file_cachep, cf);
+ return 0;
+}
+
+/*
+ * build a vector of user pages
+ */
+static struct page **get_direct_page_vector(const char __user *data,
+ int num_pages,
+ loff_t off, size_t len)
+{
+ struct page **pages;
+ int rc;
+
+ pages = kmalloc(sizeof(*pages) * num_pages, GFP_NOFS);
+ if (!pages)
+ return ERR_PTR(-ENOMEM);
+
+ down_read(&current->mm->mmap_sem);
+ rc = get_user_pages(current, current->mm, (unsigned long)data,
+ num_pages, 0, 0, pages, NULL);
+ up_read(&current->mm->mmap_sem);
+ if (rc < 0)
+ goto fail;
+ return pages;
+
+fail:
+ kfree(pages);
+ return ERR_PTR(rc);
+}
+
+static void put_page_vector(struct page **pages, int num_pages)
+{
+ int i;
+
+ for (i = 0; i < num_pages; i++)
+ put_page(pages[i]);
+ kfree(pages);
+}
+
+void ceph_release_page_vector(struct page **pages, int num_pages)
+{
+ int i;
+
+ for (i = 0; i < num_pages; i++)
+ __free_pages(pages[i], 0);
+ kfree(pages);
+}
+
+/*
+ * allocate a vector new pages
+ */
+static struct page **alloc_page_vector(int num_pages)
+{
+ struct page **pages;
+ int i;
+
+ pages = kmalloc(sizeof(*pages) * num_pages, GFP_NOFS);
+ if (!pages)
+ return ERR_PTR(-ENOMEM);
+ for (i = 0; i < num_pages; i++) {
+ pages[i] = alloc_page(GFP_NOFS);
+ if (pages[i] == NULL) {
+ ceph_release_page_vector(pages, i);
+ return ERR_PTR(-ENOMEM);
+ }
+ }
+ return pages;
+}
+
+/*
+ * copy user data into a page vector
+ */
+static int copy_user_to_page_vector(struct page **pages,
+ const char __user *data,
+ loff_t off, size_t len)
+{
+ int i = 0;
+ int po = off & ~PAGE_CACHE_MASK;
+ int left = len;
+ int l, bad;
+
+ while (left > 0) {
+ l = min_t(int, PAGE_CACHE_SIZE-po, left);
+ bad = copy_from_user(page_address(pages[i]) + po, data, l);
+ if (bad == l)
+ return -EFAULT;
+ data += l - bad;
+ left -= l - bad;
+ if (po) {
+ po += l - bad;
+ if (po == PAGE_CACHE_SIZE)
+ po = 0;
+ }
+ }
+ return len;
+}
+
+/*
+ * copy user data from a page vector into a user pointer
+ */
+static int copy_page_vector_to_user(struct page **pages, char __user *data,
+ loff_t off, size_t len)
+{
+ int i = 0;
+ int po = off & ~PAGE_CACHE_MASK;
+ int left = len;
+ int l, bad;
+
+ while (left > 0) {
+ l = min_t(int, left, PAGE_CACHE_SIZE-po);
+ bad = copy_to_user(data, page_address(pages[i]) + po, l);
+ if (bad == l)
+ return -EFAULT;
+ data += l - bad;
+ left -= l - bad;
+ if (po) {
+ po += l - bad;
+ if (po == PAGE_CACHE_SIZE)
+ po = 0;
+ }
+ i++;
+ }
+ return len;
+}
+
+/*
+ * Zero an extent within a page vector. Offset is relative to the
+ * start of the first page.
+ */
+static void zero_page_vector_range(int off, int len, struct page **pages)
+{
+ int i = off >> PAGE_CACHE_SHIFT;
+
+ dout("zero_page_vector_page %u~%u\n", off, len);
+ BUG_ON(len < PAGE_CACHE_SIZE);
+
+ /* leading partial page? */
+ if (off & ~PAGE_CACHE_MASK) {
+ dout("zeroing %d %p head from %d\n", i, pages[i],
+ (int)(off & ~PAGE_CACHE_MASK));
+ zero_user_segment(pages[i], off & ~PAGE_CACHE_MASK,
+ PAGE_CACHE_SIZE);
+ off += PAGE_CACHE_SIZE;
+ off &= PAGE_CACHE_MASK;
+ i++;
+ }
+ while (len >= PAGE_CACHE_SIZE) {
+ dout("zeroing %d %p\n", i, pages[i]);
+ zero_user_segment(pages[i], 0, PAGE_CACHE_SIZE);
+ off += PAGE_CACHE_SIZE;
+ len -= PAGE_CACHE_SIZE;
+ i++;
+ }
+ /* trailing partial page? */
+ if (len) {
+ dout("zeroing %d %p tail to %d\n", i, pages[i], (int)len);
+ zero_user_segment(pages[i], 0, len);
+ }
+}
+
+
+/*
+ * Read a range of bytes striped over one or more objects. Iterate over
+ * objects we stripe over. (That's not atomic, but good enough for now.)
+ *
+ * If we get a short result from the OSD, check against i_size; we need to
+ * only return a short read to the caller if we hit EOF.
+ */
+static int striped_read(struct inode *inode,
+ u64 off, u64 len,
+ struct page **pages, int num_pages)
+{
+ struct ceph_client *client = ceph_inode_to_client(inode);
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ u64 pos, this_len;
+ int page_off = off & ~PAGE_CACHE_SIZE; /* first byte's offset in page */
+ int left, pages_left;
+ int read;
+ struct page **page_pos;
+ int ret;
+ bool hit_stripe, was_short;
+
+ /*
+ * we may need to do multiple reads. not atomic, unfortunately.
+ */
+ pos = off;
+ left = len;
+ page_pos = pages;
+ pages_left = num_pages;
+ read = 0;
+
+more:
+ this_len = left;
+ ret = ceph_osdc_readpages(&client->osdc, ceph_vino(inode),
+ &ci->i_layout, pos, &this_len,
+ ci->i_truncate_seq,
+ ci->i_truncate_size,
+ page_pos, pages_left);
+ hit_stripe = this_len < left;
+ was_short = ret >= 0 && ret < this_len;
+ if (ret == -ENOENT)
+ ret = 0;
+ dout("striped_read %llu~%u (read %u) got %d%s%s\n", pos, left, read,
+ ret, hit_stripe ? " HITSTRIPE" : "", was_short ? " SHORT" : "");
+
+ if (ret > 0) {
+ int didpages =
+ ((pos & ~PAGE_CACHE_MASK) + ret) >> PAGE_CACHE_SHIFT;
+
+ if (read < pos - off) {
+ dout(" zero gap %llu to %llu\n", off + read, pos);
+ zero_page_vector_range(page_off + read,
+ pos - off - read, pages);
+ }
+ pos += ret;
+ read = pos - off;
+ left -= ret;
+ page_pos += didpages;
+ pages_left -= didpages;
+
+ /* hit stripe? */
+ if (left && hit_stripe)
+ goto more;
+ }
+
+ if (was_short) {
+ /* was original extent fully inside i_size? */
+ if (pos + left <= inode->i_size) {
+ dout("zero tail\n");
+ zero_page_vector_range(page_off + read, len - read,
+ pages);
+ goto out;
+ }
+
+ /* check i_size */
+ ret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE);
+ if (ret < 0)
+ goto out;
+
+ /* hit EOF? */
+ if (pos >= inode->i_size)
+ goto out;
+
+ goto more;
+ }
+
+out:
+ if (ret >= 0)
+ ret = read;
+ dout("striped_read returns %d\n", ret);
+ return ret;
+}
+
+/*
+ * Completely synchronous read and write methods. Direct from __user
+ * buffer to osd, or directly to user pages (if O_DIRECT).
+ *
+ * If the read spans object boundary, just do multiple reads.
+ */
+static ssize_t ceph_sync_read(struct file *file, char __user *data,
+ unsigned len, loff_t *poff)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct page **pages;
+ u64 off = *poff;
+ int num_pages = calc_pages_for(off, len);
+ int ret;
+
+ dout("sync_read on file %p %llu~%u %s\n", file, off, len,
+ (file->f_flags & O_DIRECT) ? "O_DIRECT" : "");
+
+ if (file->f_flags & O_DIRECT) {
+ pages = get_direct_page_vector(data, num_pages, off, len);
+
+ /*
+ * flush any page cache pages in this range. this
+ * will make concurrent normal and O_DIRECT io slow,
+ * but it will at least behave sensibly when they are
+ * in sequence.
+ */
+ filemap_write_and_wait(inode->i_mapping);
+ } else {
+ pages = alloc_page_vector(num_pages);
+ }
+ if (IS_ERR(pages))
+ return PTR_ERR(pages);
+
+ ret = striped_read(inode, off, len, pages, num_pages);
+
+ if (ret >= 0 && (file->f_flags & O_DIRECT) == 0)
+ ret = copy_page_vector_to_user(pages, data, off, ret);
+ if (ret >= 0)
+ *poff = off + ret;
+
+ if (file->f_flags & O_DIRECT)
+ put_page_vector(pages, num_pages);
+ else
+ ceph_release_page_vector(pages, num_pages);
+ dout("sync_read result %d\n", ret);
+ return ret;
+}
+
+/*
+ * Write commit callback, called if we requested both an ACK and
+ * ONDISK commit reply from the OSD.
+ */
+static void sync_write_commit(struct ceph_osd_request *req,
+ struct ceph_msg *msg)
+{
+ struct ceph_inode_info *ci = ceph_inode(req->r_inode);
+
+ dout("sync_write_commit %p tid %llu\n", req, req->r_tid);
+ spin_lock(&ci->i_unsafe_lock);
+ list_del_init(&req->r_unsafe_item);
+ spin_unlock(&ci->i_unsafe_lock);
+ ceph_put_cap_refs(ci, CEPH_CAP_FILE_WR);
+}
+
+/*
+ * Synchronous write, straight from __user pointer or user pages (if
+ * O_DIRECT).
+ *
+ * If write spans object boundary, just do multiple writes. (For a
+ * correct atomic write, we should e.g. take write locks on all
+ * objects, rollback on failure, etc.)
+ */
+static ssize_t ceph_sync_write(struct file *file, const char __user *data,
+ size_t left, loff_t *offset)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_client *client = ceph_inode_to_client(inode);
+ struct ceph_osd_request *req;
+ struct page **pages;
+ int num_pages;
+ long long unsigned pos;
+ u64 len;
+ int written = 0;
+ int flags;
+ int do_sync = 0;
+ int check_caps = 0;
+ int ret;
+ struct timespec mtime = CURRENT_TIME;
+
+ if (ceph_snap(file->f_dentry->d_inode) != CEPH_NOSNAP)
+ return -EROFS;
+
+ dout("sync_write on file %p %lld~%u %s\n", file, *offset,
+ (unsigned)left, (file->f_flags & O_DIRECT) ? "O_DIRECT" : "");
+
+ if (file->f_flags & O_APPEND)
+ pos = i_size_read(inode);
+ else
+ pos = *offset;
+
+ flags = CEPH_OSD_FLAG_ORDERSNAP |
+ CEPH_OSD_FLAG_ONDISK |
+ CEPH_OSD_FLAG_WRITE;
+ if ((file->f_flags & (O_SYNC|O_DIRECT)) == 0)
+ flags |= CEPH_OSD_FLAG_ACK;
+ else
+ do_sync = 1;
+
+ /*
+ * we may need to do multiple writes here if we span an object
+ * boundary. this isn't atomic, unfortunately. :(
+ */
+more:
+ len = left;
+ req = ceph_osdc_new_request(&client->osdc, &ci->i_layout,
+ ceph_vino(inode), pos, &len,
+ CEPH_OSD_OP_WRITE, flags,
+ ci->i_snap_realm->cached_context,
+ do_sync,
+ ci->i_truncate_seq, ci->i_truncate_size,
+ &mtime, false, 2);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ num_pages = calc_pages_for(pos, len);
+
+ if (file->f_flags & O_DIRECT) {
+ pages = get_direct_page_vector(data, num_pages, pos, len);
+ if (IS_ERR(pages)) {
+ ret = PTR_ERR(pages);
+ goto out;
+ }
+
+ /*
+ * throw out any page cache pages in this range. this
+ * may block.
+ */
+ truncate_inode_pages_range(inode->i_mapping, pos, pos+len);
+ } else {
+ pages = alloc_page_vector(num_pages);
+ if (IS_ERR(pages)) {
+ ret = PTR_ERR(pages);
+ goto out;
+ }
+ ret = copy_user_to_page_vector(pages, data, pos, len);
+ if (ret < 0) {
+ ceph_release_page_vector(pages, num_pages);
+ goto out;
+ }
+
+ if ((file->f_flags & O_SYNC) == 0) {
+ /* get a second commit callback */
+ req->r_safe_callback = sync_write_commit;
+ req->r_own_pages = 1;
+ }
+ }
+ req->r_pages = pages;
+ req->r_num_pages = num_pages;
+ req->r_inode = inode;
+
+ ret = ceph_osdc_start_request(&client->osdc, req, false);
+ if (!ret) {
+ if (req->r_safe_callback) {
+ /*
+ * Add to inode unsafe list only after we
+ * start_request so that a tid has been assigned.
+ */
+ spin_lock(&ci->i_unsafe_lock);
+ list_add(&ci->i_unsafe_writes, &req->r_unsafe_item);
+ spin_unlock(&ci->i_unsafe_lock);
+ ceph_get_cap_refs(ci, CEPH_CAP_FILE_WR);
+ }
+ ret = ceph_osdc_wait_request(&client->osdc, req);
+ }
+
+ if (file->f_flags & O_DIRECT)
+ put_page_vector(pages, num_pages);
+ else if (file->f_flags & O_SYNC)
+ ceph_release_page_vector(pages, num_pages);
+
+out:
+ ceph_osdc_put_request(req);
+ if (ret == 0) {
+ pos += len;
+ written += len;
+ left -= len;
+ if (left)
+ goto more;
+
+ ret = written;
+ *offset = pos;
+ if (pos > i_size_read(inode))
+ check_caps = ceph_inode_set_size(inode, pos);
+ if (check_caps)
+ ceph_check_caps(ceph_inode(inode), CHECK_CAPS_AUTHONLY,
+ NULL);
+ }
+ return ret;
+}
+
+/*
+ * Wrap generic_file_aio_read with checks for cap bits on the inode.
+ * Atomically grab references, so that those bits are not released
+ * back to the MDS mid-read.
+ *
+ * Hmm, the sync read case isn't actually async... should it be?
+ */
+static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
+{
+ struct file *filp = iocb->ki_filp;
+ loff_t *ppos = &iocb->ki_pos;
+ size_t len = iov->iov_len;
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ ssize_t ret;
+ int got = 0;
+
+ dout("aio_read %p %llx.%llx %llu~%u trying to get caps on %p\n",
+ inode, ceph_vinop(inode), pos, (unsigned)len, inode);
+ __ceph_do_pending_vmtruncate(inode);
+ ret = ceph_get_caps(ci, CEPH_CAP_FILE_RD, CEPH_CAP_FILE_CACHE,
+ &got, -1);
+ if (ret < 0)
+ goto out;
+ dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s\n",
+ inode, ceph_vinop(inode), pos, (unsigned)len,
+ ceph_cap_string(got));
+
+ if ((got & CEPH_CAP_FILE_CACHE) == 0 ||
+ (iocb->ki_filp->f_flags & O_DIRECT) ||
+ (inode->i_sb->s_flags & MS_SYNCHRONOUS))
+ /* hmm, this isn't really async... */
+ ret = ceph_sync_read(filp, iov->iov_base, len, ppos);
+ else
+ ret = generic_file_aio_read(iocb, iov, nr_segs, pos);
+
+out:
+ dout("aio_read %p %llx.%llx dropping cap refs on %s = %d\n",
+ inode, ceph_vinop(inode), ceph_cap_string(got), (int)ret);
+ ceph_put_cap_refs(ci, got);
+ return ret;
+}
+
+/*
+ * Take cap references to avoid releasing caps to MDS mid-write.
+ *
+ * If we are synchronous, and write with an old snap context, the OSD
+ * may return EOLDSNAPC. In that case, retry the write.. _after_
+ * dropping our cap refs and allowing the pending snap to logically
+ * complete _before_ this write occurs.
+ *
+ * If we are near ENOSPC, write synchronously.
+ */
+static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
+{
+ struct file *file = iocb->ki_filp;
+ struct inode *inode = file->f_dentry->d_inode;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_osd_client *osdc = &ceph_client(inode->i_sb)->osdc;
+ loff_t endoff = pos + iov->iov_len;
+ int got = 0;
+ int ret;
+
+ if (ceph_snap(inode) != CEPH_NOSNAP)
+ return -EROFS;
+
+retry_snap:
+ if (ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL))
+ return -ENOSPC;
+ __ceph_do_pending_vmtruncate(inode);
+ dout("aio_write %p %llx.%llx %llu~%u getting caps. i_size %llu\n",
+ inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len,
+ inode->i_size);
+ ret = ceph_get_caps(ci, CEPH_CAP_FILE_WR, CEPH_CAP_FILE_BUFFER,
+ &got, endoff);
+ if (ret < 0)
+ goto out;
+
+ dout("aio_write %p %llx.%llx %llu~%u got cap refs on %s\n",
+ inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len,
+ ceph_cap_string(got));
+
+ if ((got & CEPH_CAP_FILE_BUFFER) == 0 ||
+ (iocb->ki_filp->f_flags & O_DIRECT) ||
+ (inode->i_sb->s_flags & MS_SYNCHRONOUS)) {
+ ret = ceph_sync_write(file, iov->iov_base, iov->iov_len,
+ &iocb->ki_pos);
+ } else {
+ ret = generic_file_aio_write(iocb, iov, nr_segs, pos);
+
+ if ((ret >= 0 || ret == -EIOCBQUEUED) &&
+ ((file->f_flags & O_SYNC) || IS_SYNC(file->f_mapping->host)
+ || ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_NEARFULL)))
+ ret = vfs_fsync_range(file, file->f_path.dentry,
+ pos, pos + ret - 1, 1);
+ }
+ if (ret >= 0) {
+ spin_lock(&inode->i_lock);
+ __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR);
+ spin_unlock(&inode->i_lock);
+ }
+
+out:
+ dout("aio_write %p %llx.%llx %llu~%u dropping cap refs on %s\n",
+ inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len,
+ ceph_cap_string(got));
+ ceph_put_cap_refs(ci, got);
+
+ if (ret == -EOLDSNAPC) {
+ dout("aio_write %p %llx.%llx %llu~%u got EOLDSNAPC, retrying\n",
+ inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len);
+ goto retry_snap;
+ }
+
+ return ret;
+}
+
+/*
+ * llseek. be sure to verify file size on SEEK_END.
+ */
+static loff_t ceph_llseek(struct file *file, loff_t offset, int origin)
+{
+ struct inode *inode = file->f_mapping->host;
+ int ret;
+
+ mutex_lock(&inode->i_mutex);
+ __ceph_do_pending_vmtruncate(inode);
+ switch (origin) {
+ case SEEK_END:
+ ret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE);
+ if (ret < 0) {
+ offset = ret;
+ goto out;
+ }
+ offset += inode->i_size;
+ break;
+ case SEEK_CUR:
+ /*
+ * Here we special-case the lseek(fd, 0, SEEK_CUR)
+ * position-querying operation. Avoid rewriting the "same"
+ * f_pos value back to the file because a concurrent read(),
+ * write() or lseek() might have altered it
+ */
+ if (offset == 0) {
+ offset = file->f_pos;
+ goto out;
+ }
+ offset += file->f_pos;
+ break;
+ }
+
+ if (offset < 0 || offset > inode->i_sb->s_maxbytes) {
+ offset = -EINVAL;
+ goto out;
+ }
+
+ /* Special lock needed here? */
+ if (offset != file->f_pos) {
+ file->f_pos = offset;
+ file->f_version = 0;
+ }
+
+out:
+ mutex_unlock(&inode->i_mutex);
+ return offset;
+}
+
+const struct file_operations ceph_file_fops = {
+ .open = ceph_open,
+ .release = ceph_release,
+ .llseek = ceph_llseek,
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .aio_read = ceph_aio_read,
+ .aio_write = ceph_aio_write,
+ .mmap = ceph_mmap,
+ .fsync = ceph_fsync,
+ .splice_read = generic_file_splice_read,
+ .splice_write = generic_file_splice_write,
+ .unlocked_ioctl = ceph_ioctl,
+ .compat_ioctl = ceph_ioctl,
+};
+
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
new file mode 100644
index 000000000000..036873c42a78
--- /dev/null
+++ b/fs/ceph/inode.c
@@ -0,0 +1,1622 @@
+#include "ceph_debug.h"
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/smp_lock.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/namei.h>
+#include <linux/writeback.h>
+#include <linux/vmalloc.h>
+
+#include "super.h"
+#include "decode.h"
+
+/*
+ * Ceph inode operations
+ *
+ * Implement basic inode helpers (get, alloc) and inode ops (getattr,
+ * setattr, etc.), xattr helpers, and helpers for assimilating
+ * metadata returned by the MDS into our cache.
+ *
+ * Also define helpers for doing asynchronous writeback, invalidation,
+ * and truncation for the benefit of those who can't afford to block
+ * (typically because they are in the message handler path).
+ */
+
+static const struct inode_operations ceph_symlink_iops;
+
+static void ceph_inode_invalidate_pages(struct work_struct *work);
+
+/*
+ * find or create an inode, given the ceph ino number
+ */
+struct inode *ceph_get_inode(struct super_block *sb, struct ceph_vino vino)
+{
+ struct inode *inode;
+ ino_t t = ceph_vino_to_ino(vino);
+
+ inode = iget5_locked(sb, t, ceph_ino_compare, ceph_set_ino_cb, &vino);
+ if (inode == NULL)
+ return ERR_PTR(-ENOMEM);
+ if (inode->i_state & I_NEW) {
+ dout("get_inode created new inode %p %llx.%llx ino %llx\n",
+ inode, ceph_vinop(inode), (u64)inode->i_ino);
+ unlock_new_inode(inode);
+ }
+
+ dout("get_inode on %lu=%llx.%llx got %p\n", inode->i_ino, vino.ino,
+ vino.snap, inode);
+ return inode;
+}
+
+/*
+ * get/constuct snapdir inode for a given directory
+ */
+struct inode *ceph_get_snapdir(struct inode *parent)
+{
+ struct ceph_vino vino = {
+ .ino = ceph_ino(parent),
+ .snap = CEPH_SNAPDIR,
+ };
+ struct inode *inode = ceph_get_inode(parent->i_sb, vino);
+
+ BUG_ON(!S_ISDIR(parent->i_mode));
+ if (IS_ERR(inode))
+ return ERR_PTR(PTR_ERR(inode));
+ inode->i_mode = parent->i_mode;
+ inode->i_uid = parent->i_uid;
+ inode->i_gid = parent->i_gid;
+ inode->i_op = &ceph_dir_iops;
+ inode->i_fop = &ceph_dir_fops;
+ ceph_inode(inode)->i_snap_caps = CEPH_CAP_PIN; /* so we can open */
+ return inode;
+}
+
+const struct inode_operations ceph_file_iops = {
+ .permission = ceph_permission,
+ .setattr = ceph_setattr,
+ .getattr = ceph_getattr,
+ .setxattr = ceph_setxattr,
+ .getxattr = ceph_getxattr,
+ .listxattr = ceph_listxattr,
+ .removexattr = ceph_removexattr,
+};
+
+
+/*
+ * We use a 'frag tree' to keep track of the MDS's directory fragments
+ * for a given inode (usually there is just a single fragment). We
+ * need to know when a child frag is delegated to a new MDS, or when
+ * it is flagged as replicated, so we can direct our requests
+ * accordingly.
+ */
+
+/*
+ * find/create a frag in the tree
+ */
+static struct ceph_inode_frag *__get_or_create_frag(struct ceph_inode_info *ci,
+ u32 f)
+{
+ struct rb_node **p;
+ struct rb_node *parent = NULL;
+ struct ceph_inode_frag *frag;
+ int c;
+
+ p = &ci->i_fragtree.rb_node;
+ while (*p) {
+ parent = *p;
+ frag = rb_entry(parent, struct ceph_inode_frag, node);
+ c = ceph_frag_compare(f, frag->frag);
+ if (c < 0)
+ p = &(*p)->rb_left;
+ else if (c > 0)
+ p = &(*p)->rb_right;
+ else
+ return frag;
+ }
+
+ frag = kmalloc(sizeof(*frag), GFP_NOFS);
+ if (!frag) {
+ pr_err("__get_or_create_frag ENOMEM on %p %llx.%llx "
+ "frag %x\n", &ci->vfs_inode,
+ ceph_vinop(&ci->vfs_inode), f);
+ return ERR_PTR(-ENOMEM);
+ }
+ frag->frag = f;
+ frag->split_by = 0;
+ frag->mds = -1;
+ frag->ndist = 0;
+
+ rb_link_node(&frag->node, parent, p);
+ rb_insert_color(&frag->node, &ci->i_fragtree);
+
+ dout("get_or_create_frag added %llx.%llx frag %x\n",
+ ceph_vinop(&ci->vfs_inode), f);
+ return frag;
+}
+
+/*
+ * find a specific frag @f
+ */
+struct ceph_inode_frag *__ceph_find_frag(struct ceph_inode_info *ci, u32 f)
+{
+ struct rb_node *n = ci->i_fragtree.rb_node;
+
+ while (n) {
+ struct ceph_inode_frag *frag =
+ rb_entry(n, struct ceph_inode_frag, node);
+ int c = ceph_frag_compare(f, frag->frag);
+ if (c < 0)
+ n = n->rb_left;
+ else if (c > 0)
+ n = n->rb_right;
+ else
+ return frag;
+ }
+ return NULL;
+}
+
+/*
+ * Choose frag containing the given value @v. If @pfrag is
+ * specified, copy the frag delegation info to the caller if
+ * it is present.
+ */
+u32 ceph_choose_frag(struct ceph_inode_info *ci, u32 v,
+ struct ceph_inode_frag *pfrag,
+ int *found)
+{
+ u32 t = ceph_frag_make(0, 0);
+ struct ceph_inode_frag *frag;
+ unsigned nway, i;
+ u32 n;
+
+ if (found)
+ *found = 0;
+
+ mutex_lock(&ci->i_fragtree_mutex);
+ while (1) {
+ WARN_ON(!ceph_frag_contains_value(t, v));
+ frag = __ceph_find_frag(ci, t);
+ if (!frag)
+ break; /* t is a leaf */
+ if (frag->split_by == 0) {
+ if (pfrag)
+ memcpy(pfrag, frag, sizeof(*pfrag));
+ if (found)
+ *found = 1;
+ break;
+ }
+
+ /* choose child */
+ nway = 1 << frag->split_by;
+ dout("choose_frag(%x) %x splits by %d (%d ways)\n", v, t,
+ frag->split_by, nway);
+ for (i = 0; i < nway; i++) {
+ n = ceph_frag_make_child(t, frag->split_by, i);
+ if (ceph_frag_contains_value(n, v)) {
+ t = n;
+ break;
+ }
+ }
+ BUG_ON(i == nway);
+ }
+ dout("choose_frag(%x) = %x\n", v, t);
+
+ mutex_unlock(&ci->i_fragtree_mutex);
+ return t;
+}
+
+/*
+ * Process dirfrag (delegation) info from the mds. Include leaf
+ * fragment in tree ONLY if ndist > 0. Otherwise, only
+ * branches/splits are included in i_fragtree)
+ */
+static int ceph_fill_dirfrag(struct inode *inode,
+ struct ceph_mds_reply_dirfrag *dirinfo)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_inode_frag *frag;
+ u32 id = le32_to_cpu(dirinfo->frag);
+ int mds = le32_to_cpu(dirinfo->auth);
+ int ndist = le32_to_cpu(dirinfo->ndist);
+ int i;
+ int err = 0;
+
+ mutex_lock(&ci->i_fragtree_mutex);
+ if (ndist == 0) {
+ /* no delegation info needed. */
+ frag = __ceph_find_frag(ci, id);
+ if (!frag)
+ goto out;
+ if (frag->split_by == 0) {
+ /* tree leaf, remove */
+ dout("fill_dirfrag removed %llx.%llx frag %x"
+ " (no ref)\n", ceph_vinop(inode), id);
+ rb_erase(&frag->node, &ci->i_fragtree);
+ kfree(frag);
+ } else {
+ /* tree branch, keep and clear */
+ dout("fill_dirfrag cleared %llx.%llx frag %x"
+ " referral\n", ceph_vinop(inode), id);
+ frag->mds = -1;
+ frag->ndist = 0;
+ }
+ goto out;
+ }
+
+
+ /* find/add this frag to store mds delegation info */
+ frag = __get_or_create_frag(ci, id);
+ if (IS_ERR(frag)) {
+ /* this is not the end of the world; we can continue
+ with bad/inaccurate delegation info */
+ pr_err("fill_dirfrag ENOMEM on mds ref %llx.%llx fg %x\n",
+ ceph_vinop(inode), le32_to_cpu(dirinfo->frag));
+ err = -ENOMEM;
+ goto out;
+ }
+
+ frag->mds = mds;
+ frag->ndist = min_t(u32, ndist, CEPH_MAX_DIRFRAG_REP);
+ for (i = 0; i < frag->ndist; i++)
+ frag->dist[i] = le32_to_cpu(dirinfo->dist[i]);
+ dout("fill_dirfrag %llx.%llx frag %x ndist=%d\n",
+ ceph_vinop(inode), frag->frag, frag->ndist);
+
+out:
+ mutex_unlock(&ci->i_fragtree_mutex);
+ return err;
+}
+
+
+/*
+ * initialize a newly allocated inode.
+ */
+struct inode *ceph_alloc_inode(struct super_block *sb)
+{
+ struct ceph_inode_info *ci;
+ int i;
+
+ ci = kmem_cache_alloc(ceph_inode_cachep, GFP_NOFS);
+ if (!ci)
+ return NULL;
+
+ dout("alloc_inode %p\n", &ci->vfs_inode);
+
+ ci->i_version = 0;
+ ci->i_time_warp_seq = 0;
+ ci->i_ceph_flags = 0;
+ ci->i_release_count = 0;
+ ci->i_symlink = NULL;
+
+ ci->i_fragtree = RB_ROOT;
+ mutex_init(&ci->i_fragtree_mutex);
+
+ ci->i_xattrs.blob = NULL;
+ ci->i_xattrs.prealloc_blob = NULL;
+ ci->i_xattrs.dirty = false;
+ ci->i_xattrs.index = RB_ROOT;
+ ci->i_xattrs.count = 0;
+ ci->i_xattrs.names_size = 0;
+ ci->i_xattrs.vals_size = 0;
+ ci->i_xattrs.version = 0;
+ ci->i_xattrs.index_version = 0;
+
+ ci->i_caps = RB_ROOT;
+ ci->i_auth_cap = NULL;
+ ci->i_dirty_caps = 0;
+ ci->i_flushing_caps = 0;
+ INIT_LIST_HEAD(&ci->i_dirty_item);
+ INIT_LIST_HEAD(&ci->i_flushing_item);
+ ci->i_cap_flush_seq = 0;
+ ci->i_cap_flush_last_tid = 0;
+ memset(&ci->i_cap_flush_tid, 0, sizeof(ci->i_cap_flush_tid));
+ init_waitqueue_head(&ci->i_cap_wq);
+ ci->i_hold_caps_min = 0;
+ ci->i_hold_caps_max = 0;
+ INIT_LIST_HEAD(&ci->i_cap_delay_list);
+ ci->i_cap_exporting_mds = 0;
+ ci->i_cap_exporting_mseq = 0;
+ ci->i_cap_exporting_issued = 0;
+ INIT_LIST_HEAD(&ci->i_cap_snaps);
+ ci->i_head_snapc = NULL;
+ ci->i_snap_caps = 0;
+
+ for (i = 0; i < CEPH_FILE_MODE_NUM; i++)
+ ci->i_nr_by_mode[i] = 0;
+
+ ci->i_truncate_seq = 0;
+ ci->i_truncate_size = 0;
+ ci->i_truncate_pending = 0;
+
+ ci->i_max_size = 0;
+ ci->i_reported_size = 0;
+ ci->i_wanted_max_size = 0;
+ ci->i_requested_max_size = 0;
+
+ ci->i_pin_ref = 0;
+ ci->i_rd_ref = 0;
+ ci->i_rdcache_ref = 0;
+ ci->i_wr_ref = 0;
+ ci->i_wrbuffer_ref = 0;
+ ci->i_wrbuffer_ref_head = 0;
+ ci->i_shared_gen = 0;
+ ci->i_rdcache_gen = 0;
+ ci->i_rdcache_revoking = 0;
+
+ INIT_LIST_HEAD(&ci->i_unsafe_writes);
+ INIT_LIST_HEAD(&ci->i_unsafe_dirops);
+ spin_lock_init(&ci->i_unsafe_lock);
+
+ ci->i_snap_realm = NULL;
+ INIT_LIST_HEAD(&ci->i_snap_realm_item);
+ INIT_LIST_HEAD(&ci->i_snap_flush_item);
+
+ INIT_WORK(&ci->i_wb_work, ceph_inode_writeback);
+ INIT_WORK(&ci->i_pg_inv_work, ceph_inode_invalidate_pages);
+
+ INIT_WORK(&ci->i_vmtruncate_work, ceph_vmtruncate_work);
+
+ return &ci->vfs_inode;
+}
+
+void ceph_destroy_inode(struct inode *inode)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_inode_frag *frag;
+ struct rb_node *n;
+
+ dout("destroy_inode %p ino %llx.%llx\n", inode, ceph_vinop(inode));
+
+ ceph_queue_caps_release(inode);
+
+ kfree(ci->i_symlink);
+ while ((n = rb_first(&ci->i_fragtree)) != NULL) {
+ frag = rb_entry(n, struct ceph_inode_frag, node);
+ rb_erase(n, &ci->i_fragtree);
+ kfree(frag);
+ }
+
+ __ceph_destroy_xattrs(ci);
+ ceph_buffer_put(ci->i_xattrs.blob);
+ ceph_buffer_put(ci->i_xattrs.prealloc_blob);
+
+ kmem_cache_free(ceph_inode_cachep, ci);
+}
+
+
+/*
+ * Helpers to fill in size, ctime, mtime, and atime. We have to be
+ * careful because either the client or MDS may have more up to date
+ * info, depending on which capabilities are held, and whether
+ * time_warp_seq or truncate_seq have increased. (Ordinarily, mtime
+ * and size are monotonically increasing, except when utimes() or
+ * truncate() increments the corresponding _seq values.)
+ */
+int ceph_fill_file_size(struct inode *inode, int issued,
+ u32 truncate_seq, u64 truncate_size, u64 size)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ int queue_trunc = 0;
+
+ if (ceph_seq_cmp(truncate_seq, ci->i_truncate_seq) > 0 ||
+ (truncate_seq == ci->i_truncate_seq && size > inode->i_size)) {
+ dout("size %lld -> %llu\n", inode->i_size, size);
+ inode->i_size = size;
+ inode->i_blocks = (size + (1<<9) - 1) >> 9;
+ ci->i_reported_size = size;
+ if (truncate_seq != ci->i_truncate_seq) {
+ dout("truncate_seq %u -> %u\n",
+ ci->i_truncate_seq, truncate_seq);
+ ci->i_truncate_seq = truncate_seq;
+ if (issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_RD|
+ CEPH_CAP_FILE_WR|CEPH_CAP_FILE_BUFFER|
+ CEPH_CAP_FILE_EXCL)) {
+ ci->i_truncate_pending++;
+ queue_trunc = 1;
+ }
+ }
+ }
+ if (ceph_seq_cmp(truncate_seq, ci->i_truncate_seq) >= 0 &&
+ ci->i_truncate_size != truncate_size) {
+ dout("truncate_size %lld -> %llu\n", ci->i_truncate_size,
+ truncate_size);
+ ci->i_truncate_size = truncate_size;
+ }
+ return queue_trunc;
+}
+
+void ceph_fill_file_time(struct inode *inode, int issued,
+ u64 time_warp_seq, struct timespec *ctime,
+ struct timespec *mtime, struct timespec *atime)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ int warn = 0;
+
+ if (issued & (CEPH_CAP_FILE_EXCL|
+ CEPH_CAP_FILE_WR|
+ CEPH_CAP_FILE_BUFFER)) {
+ if (timespec_compare(ctime, &inode->i_ctime) > 0) {
+ dout("ctime %ld.%09ld -> %ld.%09ld inc w/ cap\n",
+ inode->i_ctime.tv_sec, inode->i_ctime.tv_nsec,
+ ctime->tv_sec, ctime->tv_nsec);
+ inode->i_ctime = *ctime;
+ }
+ if (ceph_seq_cmp(time_warp_seq, ci->i_time_warp_seq) > 0) {
+ /* the MDS did a utimes() */
+ dout("mtime %ld.%09ld -> %ld.%09ld "
+ "tw %d -> %d\n",
+ inode->i_mtime.tv_sec, inode->i_mtime.tv_nsec,
+ mtime->tv_sec, mtime->tv_nsec,
+ ci->i_time_warp_seq, (int)time_warp_seq);
+
+ inode->i_mtime = *mtime;
+ inode->i_atime = *atime;
+ ci->i_time_warp_seq = time_warp_seq;
+ } else if (time_warp_seq == ci->i_time_warp_seq) {
+ /* nobody did utimes(); take the max */
+ if (timespec_compare(mtime, &inode->i_mtime) > 0) {
+ dout("mtime %ld.%09ld -> %ld.%09ld inc\n",
+ inode->i_mtime.tv_sec,
+ inode->i_mtime.tv_nsec,
+ mtime->tv_sec, mtime->tv_nsec);
+ inode->i_mtime = *mtime;
+ }
+ if (timespec_compare(atime, &inode->i_atime) > 0) {
+ dout("atime %ld.%09ld -> %ld.%09ld inc\n",
+ inode->i_atime.tv_sec,
+ inode->i_atime.tv_nsec,
+ atime->tv_sec, atime->tv_nsec);
+ inode->i_atime = *atime;
+ }
+ } else if (issued & CEPH_CAP_FILE_EXCL) {
+ /* we did a utimes(); ignore mds values */
+ } else {
+ warn = 1;
+ }
+ } else {
+ /* we have no write caps; whatever the MDS says is true */
+ if (ceph_seq_cmp(time_warp_seq, ci->i_time_warp_seq) >= 0) {
+ inode->i_ctime = *ctime;
+ inode->i_mtime = *mtime;
+ inode->i_atime = *atime;
+ ci->i_time_warp_seq = time_warp_seq;
+ } else {
+ warn = 1;
+ }
+ }
+ if (warn) /* time_warp_seq shouldn't go backwards */
+ dout("%p mds time_warp_seq %llu < %u\n",
+ inode, time_warp_seq, ci->i_time_warp_seq);
+}
+
+/*
+ * Populate an inode based on info from mds. May be called on new or
+ * existing inodes.
+ */
+static int fill_inode(struct inode *inode,
+ struct ceph_mds_reply_info_in *iinfo,
+ struct ceph_mds_reply_dirfrag *dirinfo,
+ struct ceph_mds_session *session,
+ unsigned long ttl_from, int cap_fmode,
+ struct ceph_cap_reservation *caps_reservation)
+{
+ struct ceph_mds_reply_inode *info = iinfo->in;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ int i;
+ int issued, implemented;
+ struct timespec mtime, atime, ctime;
+ u32 nsplits;
+ struct ceph_buffer *xattr_blob = NULL;
+ int err = 0;
+ int queue_trunc = 0;
+
+ dout("fill_inode %p ino %llx.%llx v %llu had %llu\n",
+ inode, ceph_vinop(inode), le64_to_cpu(info->version),
+ ci->i_version);
+
+ /*
+ * prealloc xattr data, if it looks like we'll need it. only
+ * if len > 4 (meaning there are actually xattrs; the first 4
+ * bytes are the xattr count).
+ */
+ if (iinfo->xattr_len > 4) {
+ xattr_blob = ceph_buffer_new_alloc(iinfo->xattr_len, GFP_NOFS);
+ if (!xattr_blob)
+ pr_err("fill_inode ENOMEM xattr blob %d bytes\n",
+ iinfo->xattr_len);
+ }
+
+ spin_lock(&inode->i_lock);
+
+ /*
+ * provided version will be odd if inode value is projected,
+ * even if stable. skip the update if we have a newer info
+ * (e.g., due to inode info racing form multiple MDSs), or if
+ * we are getting projected (unstable) inode info.
+ */
+ if (le64_to_cpu(info->version) > 0 &&
+ (ci->i_version & ~1) > le64_to_cpu(info->version))
+ goto no_change;
+
+ issued = __ceph_caps_issued(ci, &implemented);
+ issued |= implemented | __ceph_caps_dirty(ci);
+
+ /* update inode */
+ ci->i_version = le64_to_cpu(info->version);
+ inode->i_version++;
+ inode->i_rdev = le32_to_cpu(info->rdev);
+
+ if ((issued & CEPH_CAP_AUTH_EXCL) == 0) {
+ inode->i_mode = le32_to_cpu(info->mode);
+ inode->i_uid = le32_to_cpu(info->uid);
+ inode->i_gid = le32_to_cpu(info->gid);
+ dout("%p mode 0%o uid.gid %d.%d\n", inode, inode->i_mode,
+ inode->i_uid, inode->i_gid);
+ }
+
+ if ((issued & CEPH_CAP_LINK_EXCL) == 0)
+ inode->i_nlink = le32_to_cpu(info->nlink);
+
+ /* be careful with mtime, atime, size */
+ ceph_decode_timespec(&atime, &info->atime);
+ ceph_decode_timespec(&mtime, &info->mtime);
+ ceph_decode_timespec(&ctime, &info->ctime);
+ queue_trunc = ceph_fill_file_size(inode, issued,
+ le32_to_cpu(info->truncate_seq),
+ le64_to_cpu(info->truncate_size),
+ le64_to_cpu(info->size));
+ ceph_fill_file_time(inode, issued,
+ le32_to_cpu(info->time_warp_seq),
+ &ctime, &mtime, &atime);
+
+ ci->i_max_size = le64_to_cpu(info->max_size);
+ ci->i_layout = info->layout;
+ inode->i_blkbits = fls(le32_to_cpu(info->layout.fl_stripe_unit)) - 1;
+
+ /* xattrs */
+ /* note that if i_xattrs.len <= 4, i_xattrs.data will still be NULL. */
+ if ((issued & CEPH_CAP_XATTR_EXCL) == 0 &&
+ le64_to_cpu(info->xattr_version) > ci->i_xattrs.version) {
+ if (ci->i_xattrs.blob)
+ ceph_buffer_put(ci->i_xattrs.blob);
+ ci->i_xattrs.blob = xattr_blob;
+ if (xattr_blob)
+ memcpy(ci->i_xattrs.blob->vec.iov_base,
+ iinfo->xattr_data, iinfo->xattr_len);
+ ci->i_xattrs.version = le64_to_cpu(info->xattr_version);
+ }
+
+ inode->i_mapping->a_ops = &ceph_aops;
+ inode->i_mapping->backing_dev_info =
+ &ceph_client(inode->i_sb)->backing_dev_info;
+
+ switch (inode->i_mode & S_IFMT) {
+ case S_IFIFO:
+ case S_IFBLK:
+ case S_IFCHR:
+ case S_IFSOCK:
+ init_special_inode(inode, inode->i_mode, inode->i_rdev);
+ inode->i_op = &ceph_file_iops;
+ break;
+ case S_IFREG:
+ inode->i_op = &ceph_file_iops;
+ inode->i_fop = &ceph_file_fops;
+ break;
+ case S_IFLNK:
+ inode->i_op = &ceph_symlink_iops;
+ if (!ci->i_symlink) {
+ int symlen = iinfo->symlink_len;
+ char *sym;
+
+ BUG_ON(symlen != inode->i_size);
+ spin_unlock(&inode->i_lock);
+
+ err = -ENOMEM;
+ sym = kmalloc(symlen+1, GFP_NOFS);
+ if (!sym)
+ goto out;
+ memcpy(sym, iinfo->symlink, symlen);
+ sym[symlen] = 0;
+
+ spin_lock(&inode->i_lock);
+ if (!ci->i_symlink)
+ ci->i_symlink = sym;
+ else
+ kfree(sym); /* lost a race */
+ }
+ break;
+ case S_IFDIR:
+ inode->i_op = &ceph_dir_iops;
+ inode->i_fop = &ceph_dir_fops;
+
+ ci->i_files = le64_to_cpu(info->files);
+ ci->i_subdirs = le64_to_cpu(info->subdirs);
+ ci->i_rbytes = le64_to_cpu(info->rbytes);
+ ci->i_rfiles = le64_to_cpu(info->rfiles);
+ ci->i_rsubdirs = le64_to_cpu(info->rsubdirs);
+ ceph_decode_timespec(&ci->i_rctime, &info->rctime);
+
+ /* set dir completion flag? */
+ if (ci->i_files == 0 && ci->i_subdirs == 0 &&
+ ceph_snap(inode) == CEPH_NOSNAP &&
+ (le32_to_cpu(info->cap.caps) & CEPH_CAP_FILE_SHARED)) {
+ dout(" marking %p complete (empty)\n", inode);
+ ci->i_ceph_flags |= CEPH_I_COMPLETE;
+ ci->i_max_offset = 2;
+ }
+
+ /* it may be better to set st_size in getattr instead? */
+ if (ceph_test_opt(ceph_client(inode->i_sb), RBYTES))
+ inode->i_size = ci->i_rbytes;
+ break;
+ default:
+ pr_err("fill_inode %llx.%llx BAD mode 0%o\n",
+ ceph_vinop(inode), inode->i_mode);
+ }
+
+no_change:
+ spin_unlock(&inode->i_lock);
+
+ /* queue truncate if we saw i_size decrease */
+ if (queue_trunc)
+ if (queue_work(ceph_client(inode->i_sb)->trunc_wq,
+ &ci->i_vmtruncate_work))
+ igrab(inode);
+
+ /* populate frag tree */
+ /* FIXME: move me up, if/when version reflects fragtree changes */
+ nsplits = le32_to_cpu(info->fragtree.nsplits);
+ mutex_lock(&ci->i_fragtree_mutex);
+ for (i = 0; i < nsplits; i++) {
+ u32 id = le32_to_cpu(info->fragtree.splits[i].frag);
+ struct ceph_inode_frag *frag = __get_or_create_frag(ci, id);
+
+ if (IS_ERR(frag))
+ continue;
+ frag->split_by = le32_to_cpu(info->fragtree.splits[i].by);
+ dout(" frag %x split by %d\n", frag->frag, frag->split_by);
+ }
+ mutex_unlock(&ci->i_fragtree_mutex);
+
+ /* were we issued a capability? */
+ if (info->cap.caps) {
+ if (ceph_snap(inode) == CEPH_NOSNAP) {
+ ceph_add_cap(inode, session,
+ le64_to_cpu(info->cap.cap_id),
+ cap_fmode,
+ le32_to_cpu(info->cap.caps),
+ le32_to_cpu(info->cap.wanted),
+ le32_to_cpu(info->cap.seq),
+ le32_to_cpu(info->cap.mseq),
+ le64_to_cpu(info->cap.realm),
+ info->cap.flags,
+ caps_reservation);
+ } else {
+ spin_lock(&inode->i_lock);
+ dout(" %p got snap_caps %s\n", inode,
+ ceph_cap_string(le32_to_cpu(info->cap.caps)));
+ ci->i_snap_caps |= le32_to_cpu(info->cap.caps);
+ if (cap_fmode >= 0)
+ __ceph_get_fmode(ci, cap_fmode);
+ spin_unlock(&inode->i_lock);
+ }
+ }
+
+ /* update delegation info? */
+ if (dirinfo)
+ ceph_fill_dirfrag(inode, dirinfo);
+
+ err = 0;
+
+out:
+ ceph_buffer_put(xattr_blob);
+ return err;
+}
+
+/*
+ * caller should hold session s_mutex.
+ */
+static void update_dentry_lease(struct dentry *dentry,
+ struct ceph_mds_reply_lease *lease,
+ struct ceph_mds_session *session,
+ unsigned long from_time)
+{
+ struct ceph_dentry_info *di = ceph_dentry(dentry);
+ long unsigned duration = le32_to_cpu(lease->duration_ms);
+ long unsigned ttl = from_time + (duration * HZ) / 1000;
+ long unsigned half_ttl = from_time + (duration * HZ / 2) / 1000;
+ struct inode *dir;
+
+ /* only track leases on regular dentries */
+ if (dentry->d_op != &ceph_dentry_ops)
+ return;
+
+ spin_lock(&dentry->d_lock);
+ dout("update_dentry_lease %p mask %d duration %lu ms ttl %lu\n",
+ dentry, le16_to_cpu(lease->mask), duration, ttl);
+
+ /* make lease_rdcache_gen match directory */
+ dir = dentry->d_parent->d_inode;
+ di->lease_shared_gen = ceph_inode(dir)->i_shared_gen;
+
+ if (lease->mask == 0)
+ goto out_unlock;
+
+ if (di->lease_gen == session->s_cap_gen &&
+ time_before(ttl, dentry->d_time))
+ goto out_unlock; /* we already have a newer lease. */
+
+ if (di->lease_session && di->lease_session != session)
+ goto out_unlock;
+
+ ceph_dentry_lru_touch(dentry);
+
+ if (!di->lease_session)
+ di->lease_session = ceph_get_mds_session(session);
+ di->lease_gen = session->s_cap_gen;
+ di->lease_seq = le32_to_cpu(lease->seq);
+ di->lease_renew_after = half_ttl;
+ di->lease_renew_from = 0;
+ dentry->d_time = ttl;
+out_unlock:
+ spin_unlock(&dentry->d_lock);
+ return;
+}
+
+/*
+ * splice a dentry to an inode.
+ * caller must hold directory i_mutex for this to be safe.
+ *
+ * we will only rehash the resulting dentry if @prehash is
+ * true; @prehash will be set to false (for the benefit of
+ * the caller) if we fail.
+ */
+static struct dentry *splice_dentry(struct dentry *dn, struct inode *in,
+ bool *prehash)
+{
+ struct dentry *realdn;
+
+ /* dn must be unhashed */
+ if (!d_unhashed(dn))
+ d_drop(dn);
+ realdn = d_materialise_unique(dn, in);
+ if (IS_ERR(realdn)) {
+ pr_err("splice_dentry error %p inode %p ino %llx.%llx\n",
+ dn, in, ceph_vinop(in));
+ if (prehash)
+ *prehash = false; /* don't rehash on error */
+ dn = realdn; /* note realdn contains the error */
+ goto out;
+ } else if (realdn) {
+ dout("dn %p (%d) spliced with %p (%d) "
+ "inode %p ino %llx.%llx\n",
+ dn, atomic_read(&dn->d_count),
+ realdn, atomic_read(&realdn->d_count),
+ realdn->d_inode, ceph_vinop(realdn->d_inode));
+ dput(dn);
+ dn = realdn;
+ } else {
+ BUG_ON(!ceph_dentry(dn));
+
+ dout("dn %p attached to %p ino %llx.%llx\n",
+ dn, dn->d_inode, ceph_vinop(dn->d_inode));
+ }
+ if ((!prehash || *prehash) && d_unhashed(dn))
+ d_rehash(dn);
+out:
+ return dn;
+}
+
+/*
+ * Incorporate results into the local cache. This is either just
+ * one inode, or a directory, dentry, and possibly linked-to inode (e.g.,
+ * after a lookup).
+ *
+ * A reply may contain
+ * a directory inode along with a dentry.
+ * and/or a target inode
+ *
+ * Called with snap_rwsem (read).
+ */
+int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
+ struct ceph_mds_session *session)
+{
+ struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
+ struct inode *in = NULL;
+ struct ceph_mds_reply_inode *ininfo;
+ struct ceph_vino vino;
+ int i = 0;
+ int err = 0;
+
+ dout("fill_trace %p is_dentry %d is_target %d\n", req,
+ rinfo->head->is_dentry, rinfo->head->is_target);
+
+#if 0
+ /*
+ * Debugging hook:
+ *
+ * If we resend completed ops to a recovering mds, we get no
+ * trace. Since that is very rare, pretend this is the case
+ * to ensure the 'no trace' handlers in the callers behave.
+ *
+ * Fill in inodes unconditionally to avoid breaking cap
+ * invariants.
+ */
+ if (rinfo->head->op & CEPH_MDS_OP_WRITE) {
+ pr_info("fill_trace faking empty trace on %lld %s\n",
+ req->r_tid, ceph_mds_op_name(rinfo->head->op));
+ if (rinfo->head->is_dentry) {
+ rinfo->head->is_dentry = 0;
+ err = fill_inode(req->r_locked_dir,
+ &rinfo->diri, rinfo->dirfrag,
+ session, req->r_request_started, -1);
+ }
+ if (rinfo->head->is_target) {
+ rinfo->head->is_target = 0;
+ ininfo = rinfo->targeti.in;
+ vino.ino = le64_to_cpu(ininfo->ino);
+ vino.snap = le64_to_cpu(ininfo->snapid);
+ in = ceph_get_inode(sb, vino);
+ err = fill_inode(in, &rinfo->targeti, NULL,
+ session, req->r_request_started,
+ req->r_fmode);
+ iput(in);
+ }
+ }
+#endif
+
+ if (!rinfo->head->is_target && !rinfo->head->is_dentry) {
+ dout("fill_trace reply is empty!\n");
+ if (rinfo->head->result == 0 && req->r_locked_dir) {
+ struct ceph_inode_info *ci =
+ ceph_inode(req->r_locked_dir);
+ dout(" clearing %p complete (empty trace)\n",
+ req->r_locked_dir);
+ ci->i_ceph_flags &= ~CEPH_I_COMPLETE;
+ ci->i_release_count++;
+ }
+ return 0;
+ }
+
+ if (rinfo->head->is_dentry) {
+ /*
+ * lookup link rename : null -> possibly existing inode
+ * mknod symlink mkdir : null -> new inode
+ * unlink : linked -> null
+ */
+ struct inode *dir = req->r_locked_dir;
+ struct dentry *dn = req->r_dentry;
+ bool have_dir_cap, have_lease;
+
+ BUG_ON(!dn);
+ BUG_ON(!dir);
+ BUG_ON(dn->d_parent->d_inode != dir);
+ BUG_ON(ceph_ino(dir) !=
+ le64_to_cpu(rinfo->diri.in->ino));
+ BUG_ON(ceph_snap(dir) !=
+ le64_to_cpu(rinfo->diri.in->snapid));
+
+ err = fill_inode(dir, &rinfo->diri, rinfo->dirfrag,
+ session, req->r_request_started, -1,
+ &req->r_caps_reservation);
+ if (err < 0)
+ return err;
+
+ /* do we have a lease on the whole dir? */
+ have_dir_cap =
+ (le32_to_cpu(rinfo->diri.in->cap.caps) &
+ CEPH_CAP_FILE_SHARED);
+
+ /* do we have a dn lease? */
+ have_lease = have_dir_cap ||
+ (le16_to_cpu(rinfo->dlease->mask) &
+ CEPH_LOCK_DN);
+
+ if (!have_lease)
+ dout("fill_trace no dentry lease or dir cap\n");
+
+ /* rename? */
+ if (req->r_old_dentry && req->r_op == CEPH_MDS_OP_RENAME) {
+ dout(" src %p '%.*s' dst %p '%.*s'\n",
+ req->r_old_dentry,
+ req->r_old_dentry->d_name.len,
+ req->r_old_dentry->d_name.name,
+ dn, dn->d_name.len, dn->d_name.name);
+ dout("fill_trace doing d_move %p -> %p\n",
+ req->r_old_dentry, dn);
+ d_move(req->r_old_dentry, dn);
+ dout(" src %p '%.*s' dst %p '%.*s'\n",
+ req->r_old_dentry,
+ req->r_old_dentry->d_name.len,
+ req->r_old_dentry->d_name.name,
+ dn, dn->d_name.len, dn->d_name.name);
+ /* take overwritten dentry's readdir offset */
+ ceph_dentry(req->r_old_dentry)->offset =
+ ceph_dentry(dn)->offset;
+ dn = req->r_old_dentry; /* use old_dentry */
+ in = dn->d_inode;
+ }
+
+ /* null dentry? */
+ if (!rinfo->head->is_target) {
+ dout("fill_trace null dentry\n");
+ if (dn->d_inode) {
+ dout("d_delete %p\n", dn);
+ d_delete(dn);
+ } else {
+ dout("d_instantiate %p NULL\n", dn);
+ d_instantiate(dn, NULL);
+ if (have_lease && d_unhashed(dn))
+ d_rehash(dn);
+ update_dentry_lease(dn, rinfo->dlease,
+ session,
+ req->r_request_started);
+ }
+ goto done;
+ }
+
+ /* attach proper inode */
+ ininfo = rinfo->targeti.in;
+ vino.ino = le64_to_cpu(ininfo->ino);
+ vino.snap = le64_to_cpu(ininfo->snapid);
+ if (!dn->d_inode) {
+ in = ceph_get_inode(sb, vino);
+ if (IS_ERR(in)) {
+ pr_err("fill_trace bad get_inode "
+ "%llx.%llx\n", vino.ino, vino.snap);
+ err = PTR_ERR(in);
+ d_delete(dn);
+ goto done;
+ }
+ dn = splice_dentry(dn, in, &have_lease);
+ if (IS_ERR(dn)) {
+ err = PTR_ERR(dn);
+ goto done;
+ }
+ req->r_dentry = dn; /* may have spliced */
+ igrab(in);
+ } else if (ceph_ino(in) == vino.ino &&
+ ceph_snap(in) == vino.snap) {
+ igrab(in);
+ } else {
+ dout(" %p links to %p %llx.%llx, not %llx.%llx\n",
+ dn, in, ceph_ino(in), ceph_snap(in),
+ vino.ino, vino.snap);
+ have_lease = false;
+ in = NULL;
+ }
+
+ if (have_lease)
+ update_dentry_lease(dn, rinfo->dlease, session,
+ req->r_request_started);
+ dout(" final dn %p\n", dn);
+ i++;
+ } else if (req->r_op == CEPH_MDS_OP_LOOKUPSNAP ||
+ req->r_op == CEPH_MDS_OP_MKSNAP) {
+ struct dentry *dn = req->r_dentry;
+
+ /* fill out a snapdir LOOKUPSNAP dentry */
+ BUG_ON(!dn);
+ BUG_ON(!req->r_locked_dir);
+ BUG_ON(ceph_snap(req->r_locked_dir) != CEPH_SNAPDIR);
+ ininfo = rinfo->targeti.in;
+ vino.ino = le64_to_cpu(ininfo->ino);
+ vino.snap = le64_to_cpu(ininfo->snapid);
+ in = ceph_get_inode(sb, vino);
+ if (IS_ERR(in)) {
+ pr_err("fill_inode get_inode badness %llx.%llx\n",
+ vino.ino, vino.snap);
+ err = PTR_ERR(in);
+ d_delete(dn);
+ goto done;
+ }
+ dout(" linking snapped dir %p to dn %p\n", in, dn);
+ dn = splice_dentry(dn, in, NULL);
+ if (IS_ERR(dn)) {
+ err = PTR_ERR(dn);
+ goto done;
+ }
+ req->r_dentry = dn; /* may have spliced */
+ igrab(in);
+ rinfo->head->is_dentry = 1; /* fool notrace handlers */
+ }
+
+ if (rinfo->head->is_target) {
+ vino.ino = le64_to_cpu(rinfo->targeti.in->ino);
+ vino.snap = le64_to_cpu(rinfo->targeti.in->snapid);
+
+ if (in == NULL || ceph_ino(in) != vino.ino ||
+ ceph_snap(in) != vino.snap) {
+ in = ceph_get_inode(sb, vino);
+ if (IS_ERR(in)) {
+ err = PTR_ERR(in);
+ goto done;
+ }
+ }
+ req->r_target_inode = in;
+
+ err = fill_inode(in,
+ &rinfo->targeti, NULL,
+ session, req->r_request_started,
+ (le32_to_cpu(rinfo->head->result) == 0) ?
+ req->r_fmode : -1,
+ &req->r_caps_reservation);
+ if (err < 0) {
+ pr_err("fill_inode badness %p %llx.%llx\n",
+ in, ceph_vinop(in));
+ goto done;
+ }
+ }
+
+done:
+ dout("fill_trace done err=%d\n", err);
+ return err;
+}
+
+/*
+ * Prepopulate our cache with readdir results, leases, etc.
+ */
+int ceph_readdir_prepopulate(struct ceph_mds_request *req,
+ struct ceph_mds_session *session)
+{
+ struct dentry *parent = req->r_dentry;
+ struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
+ struct qstr dname;
+ struct dentry *dn;
+ struct inode *in;
+ int err = 0, i;
+ struct inode *snapdir = NULL;
+ struct ceph_mds_request_head *rhead = req->r_request->front.iov_base;
+ u64 frag = le32_to_cpu(rhead->args.readdir.frag);
+ struct ceph_dentry_info *di;
+
+ if (le32_to_cpu(rinfo->head->op) == CEPH_MDS_OP_LSSNAP) {
+ snapdir = ceph_get_snapdir(parent->d_inode);
+ parent = d_find_alias(snapdir);
+ dout("readdir_prepopulate %d items under SNAPDIR dn %p\n",
+ rinfo->dir_nr, parent);
+ } else {
+ dout("readdir_prepopulate %d items under dn %p\n",
+ rinfo->dir_nr, parent);
+ if (rinfo->dir_dir)
+ ceph_fill_dirfrag(parent->d_inode, rinfo->dir_dir);
+ }
+
+ for (i = 0; i < rinfo->dir_nr; i++) {
+ struct ceph_vino vino;
+
+ dname.name = rinfo->dir_dname[i];
+ dname.len = rinfo->dir_dname_len[i];
+ dname.hash = full_name_hash(dname.name, dname.len);
+
+ vino.ino = le64_to_cpu(rinfo->dir_in[i].in->ino);
+ vino.snap = le64_to_cpu(rinfo->dir_in[i].in->snapid);
+
+retry_lookup:
+ dn = d_lookup(parent, &dname);
+ dout("d_lookup on parent=%p name=%.*s got %p\n",
+ parent, dname.len, dname.name, dn);
+
+ if (!dn) {
+ dn = d_alloc(parent, &dname);
+ dout("d_alloc %p '%.*s' = %p\n", parent,
+ dname.len, dname.name, dn);
+ if (dn == NULL) {
+ dout("d_alloc badness\n");
+ err = -ENOMEM;
+ goto out;
+ }
+ err = ceph_init_dentry(dn);
+ if (err < 0)
+ goto out;
+ } else if (dn->d_inode &&
+ (ceph_ino(dn->d_inode) != vino.ino ||
+ ceph_snap(dn->d_inode) != vino.snap)) {
+ dout(" dn %p points to wrong inode %p\n",
+ dn, dn->d_inode);
+ d_delete(dn);
+ dput(dn);
+ goto retry_lookup;
+ } else {
+ /* reorder parent's d_subdirs */
+ spin_lock(&dcache_lock);
+ spin_lock(&dn->d_lock);
+ list_move(&dn->d_u.d_child, &parent->d_subdirs);
+ spin_unlock(&dn->d_lock);
+ spin_unlock(&dcache_lock);
+ }
+
+ di = dn->d_fsdata;
+ di->offset = ceph_make_fpos(frag, i + req->r_readdir_offset);
+
+ /* inode */
+ if (dn->d_inode) {
+ in = dn->d_inode;
+ } else {
+ in = ceph_get_inode(parent->d_sb, vino);
+ if (in == NULL) {
+ dout("new_inode badness\n");
+ d_delete(dn);
+ dput(dn);
+ err = -ENOMEM;
+ goto out;
+ }
+ dn = splice_dentry(dn, in, NULL);
+ }
+
+ if (fill_inode(in, &rinfo->dir_in[i], NULL, session,
+ req->r_request_started, -1,
+ &req->r_caps_reservation) < 0) {
+ pr_err("fill_inode badness on %p\n", in);
+ dput(dn);
+ continue;
+ }
+ update_dentry_lease(dn, rinfo->dir_dlease[i],
+ req->r_session, req->r_request_started);
+ dput(dn);
+ }
+ req->r_did_prepopulate = true;
+
+out:
+ if (snapdir) {
+ iput(snapdir);
+ dput(parent);
+ }
+ dout("readdir_prepopulate done\n");
+ return err;
+}
+
+int ceph_inode_set_size(struct inode *inode, loff_t size)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ int ret = 0;
+
+ spin_lock(&inode->i_lock);
+ dout("set_size %p %llu -> %llu\n", inode, inode->i_size, size);
+ inode->i_size = size;
+ inode->i_blocks = (size + (1 << 9) - 1) >> 9;
+
+ /* tell the MDS if we are approaching max_size */
+ if ((size << 1) >= ci->i_max_size &&
+ (ci->i_reported_size << 1) < ci->i_max_size)
+ ret = 1;
+
+ spin_unlock(&inode->i_lock);
+ return ret;
+}
+
+/*
+ * Write back inode data in a worker thread. (This can't be done
+ * in the message handler context.)
+ */
+void ceph_inode_writeback(struct work_struct *work)
+{
+ struct ceph_inode_info *ci = container_of(work, struct ceph_inode_info,
+ i_wb_work);
+ struct inode *inode = &ci->vfs_inode;
+
+ dout("writeback %p\n", inode);
+ filemap_fdatawrite(&inode->i_data);
+ iput(inode);
+}
+
+/*
+ * Invalidate inode pages in a worker thread. (This can't be done
+ * in the message handler context.)
+ */
+static void ceph_inode_invalidate_pages(struct work_struct *work)
+{
+ struct ceph_inode_info *ci = container_of(work, struct ceph_inode_info,
+ i_pg_inv_work);
+ struct inode *inode = &ci->vfs_inode;
+ u32 orig_gen;
+ int check = 0;
+
+ spin_lock(&inode->i_lock);
+ dout("invalidate_pages %p gen %d revoking %d\n", inode,
+ ci->i_rdcache_gen, ci->i_rdcache_revoking);
+ if (ci->i_rdcache_gen == 0 ||
+ ci->i_rdcache_revoking != ci->i_rdcache_gen) {
+ BUG_ON(ci->i_rdcache_revoking > ci->i_rdcache_gen);
+ /* nevermind! */
+ ci->i_rdcache_revoking = 0;
+ spin_unlock(&inode->i_lock);
+ goto out;
+ }
+ orig_gen = ci->i_rdcache_gen;
+ spin_unlock(&inode->i_lock);
+
+ truncate_inode_pages(&inode->i_data, 0);
+
+ spin_lock(&inode->i_lock);
+ if (orig_gen == ci->i_rdcache_gen) {
+ dout("invalidate_pages %p gen %d successful\n", inode,
+ ci->i_rdcache_gen);
+ ci->i_rdcache_gen = 0;
+ ci->i_rdcache_revoking = 0;
+ check = 1;
+ } else {
+ dout("invalidate_pages %p gen %d raced, gen now %d\n",
+ inode, orig_gen, ci->i_rdcache_gen);
+ }
+ spin_unlock(&inode->i_lock);
+
+ if (check)
+ ceph_check_caps(ci, 0, NULL);
+out:
+ iput(inode);
+}
+
+
+/*
+ * called by trunc_wq; take i_mutex ourselves
+ *
+ * We also truncate in a separate thread as well.
+ */
+void ceph_vmtruncate_work(struct work_struct *work)
+{
+ struct ceph_inode_info *ci = container_of(work, struct ceph_inode_info,
+ i_vmtruncate_work);
+ struct inode *inode = &ci->vfs_inode;
+
+ dout("vmtruncate_work %p\n", inode);
+ mutex_lock(&inode->i_mutex);
+ __ceph_do_pending_vmtruncate(inode);
+ mutex_unlock(&inode->i_mutex);
+ iput(inode);
+}
+
+/*
+ * called with i_mutex held.
+ *
+ * Make sure any pending truncation is applied before doing anything
+ * that may depend on it.
+ */
+void __ceph_do_pending_vmtruncate(struct inode *inode)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ u64 to;
+ int wrbuffer_refs, wake = 0;
+
+retry:
+ spin_lock(&inode->i_lock);
+ if (ci->i_truncate_pending == 0) {
+ dout("__do_pending_vmtruncate %p none pending\n", inode);
+ spin_unlock(&inode->i_lock);
+ return;
+ }
+
+ /*
+ * make sure any dirty snapped pages are flushed before we
+ * possibly truncate them.. so write AND block!
+ */
+ if (ci->i_wrbuffer_ref_head < ci->i_wrbuffer_ref) {
+ dout("__do_pending_vmtruncate %p flushing snaps first\n",
+ inode);
+ spin_unlock(&inode->i_lock);
+ filemap_write_and_wait_range(&inode->i_data, 0,
+ inode->i_sb->s_maxbytes);
+ goto retry;
+ }
+
+ to = ci->i_truncate_size;
+ wrbuffer_refs = ci->i_wrbuffer_ref;
+ dout("__do_pending_vmtruncate %p (%d) to %lld\n", inode,
+ ci->i_truncate_pending, to);
+ spin_unlock(&inode->i_lock);
+
+ truncate_inode_pages(inode->i_mapping, to);
+
+ spin_lock(&inode->i_lock);
+ ci->i_truncate_pending--;
+ if (ci->i_truncate_pending == 0)
+ wake = 1;
+ spin_unlock(&inode->i_lock);
+
+ if (wrbuffer_refs == 0)
+ ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL);
+ if (wake)
+ wake_up(&ci->i_cap_wq);
+}
+
+
+/*
+ * symlinks
+ */
+static void *ceph_sym_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+ struct ceph_inode_info *ci = ceph_inode(dentry->d_inode);
+ nd_set_link(nd, ci->i_symlink);
+ return NULL;
+}
+
+static const struct inode_operations ceph_symlink_iops = {
+ .readlink = generic_readlink,
+ .follow_link = ceph_sym_follow_link,
+};
+
+/*
+ * setattr
+ */
+int ceph_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct inode *inode = dentry->d_inode;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct inode *parent_inode = dentry->d_parent->d_inode;
+ const unsigned int ia_valid = attr->ia_valid;
+ struct ceph_mds_request *req;
+ struct ceph_mds_client *mdsc = &ceph_client(dentry->d_sb)->mdsc;
+ int issued;
+ int release = 0, dirtied = 0;
+ int mask = 0;
+ int err = 0;
+ int queue_trunc = 0;
+
+ if (ceph_snap(inode) != CEPH_NOSNAP)
+ return -EROFS;
+
+ __ceph_do_pending_vmtruncate(inode);
+
+ err = inode_change_ok(inode, attr);
+ if (err != 0)
+ return err;
+
+ req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETATTR,
+ USE_AUTH_MDS);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ spin_lock(&inode->i_lock);
+ issued = __ceph_caps_issued(ci, NULL);
+ dout("setattr %p issued %s\n", inode, ceph_cap_string(issued));
+
+ if (ia_valid & ATTR_UID) {
+ dout("setattr %p uid %d -> %d\n", inode,
+ inode->i_uid, attr->ia_uid);
+ if (issued & CEPH_CAP_AUTH_EXCL) {
+ inode->i_uid = attr->ia_uid;
+ dirtied |= CEPH_CAP_AUTH_EXCL;
+ } else if ((issued & CEPH_CAP_AUTH_SHARED) == 0 ||
+ attr->ia_uid != inode->i_uid) {
+ req->r_args.setattr.uid = cpu_to_le32(attr->ia_uid);
+ mask |= CEPH_SETATTR_UID;
+ release |= CEPH_CAP_AUTH_SHARED;
+ }
+ }
+ if (ia_valid & ATTR_GID) {
+ dout("setattr %p gid %d -> %d\n", inode,
+ inode->i_gid, attr->ia_gid);
+ if (issued & CEPH_CAP_AUTH_EXCL) {
+ inode->i_gid = attr->ia_gid;
+ dirtied |= CEPH_CAP_AUTH_EXCL;
+ } else if ((issued & CEPH_CAP_AUTH_SHARED) == 0 ||
+ attr->ia_gid != inode->i_gid) {
+ req->r_args.setattr.gid = cpu_to_le32(attr->ia_gid);
+ mask |= CEPH_SETATTR_GID;
+ release |= CEPH_CAP_AUTH_SHARED;
+ }
+ }
+ if (ia_valid & ATTR_MODE) {
+ dout("setattr %p mode 0%o -> 0%o\n", inode, inode->i_mode,
+ attr->ia_mode);
+ if (issued & CEPH_CAP_AUTH_EXCL) {
+ inode->i_mode = attr->ia_mode;
+ dirtied |= CEPH_CAP_AUTH_EXCL;
+ } else if ((issued & CEPH_CAP_AUTH_SHARED) == 0 ||
+ attr->ia_mode != inode->i_mode) {
+ req->r_args.setattr.mode = cpu_to_le32(attr->ia_mode);
+ mask |= CEPH_SETATTR_MODE;
+ release |= CEPH_CAP_AUTH_SHARED;
+ }
+ }
+
+ if (ia_valid & ATTR_ATIME) {
+ dout("setattr %p atime %ld.%ld -> %ld.%ld\n", inode,
+ inode->i_atime.tv_sec, inode->i_atime.tv_nsec,
+ attr->ia_atime.tv_sec, attr->ia_atime.tv_nsec);
+ if (issued & CEPH_CAP_FILE_EXCL) {
+ ci->i_time_warp_seq++;
+ inode->i_atime = attr->ia_atime;
+ dirtied |= CEPH_CAP_FILE_EXCL;
+ } else if ((issued & CEPH_CAP_FILE_WR) &&
+ timespec_compare(&inode->i_atime,
+ &attr->ia_atime) < 0) {
+ inode->i_atime = attr->ia_atime;
+ dirtied |= CEPH_CAP_FILE_WR;
+ } else if ((issued & CEPH_CAP_FILE_SHARED) == 0 ||
+ !timespec_equal(&inode->i_atime, &attr->ia_atime)) {
+ ceph_encode_timespec(&req->r_args.setattr.atime,
+ &attr->ia_atime);
+ mask |= CEPH_SETATTR_ATIME;
+ release |= CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_RD |
+ CEPH_CAP_FILE_WR;
+ }
+ }
+ if (ia_valid & ATTR_MTIME) {
+ dout("setattr %p mtime %ld.%ld -> %ld.%ld\n", inode,
+ inode->i_mtime.tv_sec, inode->i_mtime.tv_nsec,
+ attr->ia_mtime.tv_sec, attr->ia_mtime.tv_nsec);
+ if (issued & CEPH_CAP_FILE_EXCL) {
+ ci->i_time_warp_seq++;
+ inode->i_mtime = attr->ia_mtime;
+ dirtied |= CEPH_CAP_FILE_EXCL;
+ } else if ((issued & CEPH_CAP_FILE_WR) &&
+ timespec_compare(&inode->i_mtime,
+ &attr->ia_mtime) < 0) {
+ inode->i_mtime = attr->ia_mtime;
+ dirtied |= CEPH_CAP_FILE_WR;
+ } else if ((issued & CEPH_CAP_FILE_SHARED) == 0 ||
+ !timespec_equal(&inode->i_mtime, &attr->ia_mtime)) {
+ ceph_encode_timespec(&req->r_args.setattr.mtime,
+ &attr->ia_mtime);
+ mask |= CEPH_SETATTR_MTIME;
+ release |= CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_RD |
+ CEPH_CAP_FILE_WR;
+ }
+ }
+ if (ia_valid & ATTR_SIZE) {
+ dout("setattr %p size %lld -> %lld\n", inode,
+ inode->i_size, attr->ia_size);
+ if (attr->ia_size > inode->i_sb->s_maxbytes) {
+ err = -EINVAL;
+ goto out;
+ }
+ if ((issued & CEPH_CAP_FILE_EXCL) &&
+ attr->ia_size > inode->i_size) {
+ inode->i_size = attr->ia_size;
+ if (attr->ia_size < inode->i_size) {
+ ci->i_truncate_size = attr->ia_size;
+ ci->i_truncate_pending++;
+ queue_trunc = 1;
+ }
+ inode->i_blocks =
+ (attr->ia_size + (1 << 9) - 1) >> 9;
+ inode->i_ctime = attr->ia_ctime;
+ ci->i_reported_size = attr->ia_size;
+ dirtied |= CEPH_CAP_FILE_EXCL;
+ } else if ((issued & CEPH_CAP_FILE_SHARED) == 0 ||
+ attr->ia_size != inode->i_size) {
+ req->r_args.setattr.size = cpu_to_le64(attr->ia_size);
+ req->r_args.setattr.old_size =
+ cpu_to_le64(inode->i_size);
+ mask |= CEPH_SETATTR_SIZE;
+ release |= CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_RD |
+ CEPH_CAP_FILE_WR;
+ }
+ }
+
+ /* these do nothing */
+ if (ia_valid & ATTR_CTIME) {
+ bool only = (ia_valid & (ATTR_SIZE|ATTR_MTIME|ATTR_ATIME|
+ ATTR_MODE|ATTR_UID|ATTR_GID)) == 0;
+ dout("setattr %p ctime %ld.%ld -> %ld.%ld (%s)\n", inode,
+ inode->i_ctime.tv_sec, inode->i_ctime.tv_nsec,
+ attr->ia_ctime.tv_sec, attr->ia_ctime.tv_nsec,
+ only ? "ctime only" : "ignored");
+ inode->i_ctime = attr->ia_ctime;
+ if (only) {
+ /*
+ * if kernel wants to dirty ctime but nothing else,
+ * we need to choose a cap to dirty under, or do
+ * a almost-no-op setattr
+ */
+ if (issued & CEPH_CAP_AUTH_EXCL)
+ dirtied |= CEPH_CAP_AUTH_EXCL;
+ else if (issued & CEPH_CAP_FILE_EXCL)
+ dirtied |= CEPH_CAP_FILE_EXCL;
+ else if (issued & CEPH_CAP_XATTR_EXCL)
+ dirtied |= CEPH_CAP_XATTR_EXCL;
+ else
+ mask |= CEPH_SETATTR_CTIME;
+ }
+ }
+ if (ia_valid & ATTR_FILE)
+ dout("setattr %p ATTR_FILE ... hrm!\n", inode);
+
+ if (dirtied) {
+ __ceph_mark_dirty_caps(ci, dirtied);
+ inode->i_ctime = CURRENT_TIME;
+ }
+
+ release &= issued;
+ spin_unlock(&inode->i_lock);
+
+ if (queue_trunc)
+ __ceph_do_pending_vmtruncate(inode);
+
+ if (mask) {
+ req->r_inode = igrab(inode);
+ req->r_inode_drop = release;
+ req->r_args.setattr.mask = cpu_to_le32(mask);
+ req->r_num_caps = 1;
+ err = ceph_mdsc_do_request(mdsc, parent_inode, req);
+ }
+ dout("setattr %p result=%d (%s locally, %d remote)\n", inode, err,
+ ceph_cap_string(dirtied), mask);
+
+ ceph_mdsc_put_request(req);
+ __ceph_do_pending_vmtruncate(inode);
+ return err;
+out:
+ spin_unlock(&inode->i_lock);
+ ceph_mdsc_put_request(req);
+ return err;
+}
+
+/*
+ * Verify that we have a lease on the given mask. If not,
+ * do a getattr against an mds.
+ */
+int ceph_do_getattr(struct inode *inode, int mask)
+{
+ struct ceph_client *client = ceph_sb_to_client(inode->i_sb);
+ struct ceph_mds_client *mdsc = &client->mdsc;
+ struct ceph_mds_request *req;
+ int err;
+
+ if (ceph_snap(inode) == CEPH_SNAPDIR) {
+ dout("do_getattr inode %p SNAPDIR\n", inode);
+ return 0;
+ }
+
+ dout("do_getattr inode %p mask %s\n", inode, ceph_cap_string(mask));
+ if (ceph_caps_issued_mask(ceph_inode(inode), mask, 1))
+ return 0;
+
+ req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_GETATTR, USE_ANY_MDS);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+ req->r_inode = igrab(inode);
+ req->r_num_caps = 1;
+ req->r_args.getattr.mask = cpu_to_le32(mask);
+ err = ceph_mdsc_do_request(mdsc, NULL, req);
+ ceph_mdsc_put_request(req);
+ dout("do_getattr result=%d\n", err);
+ return err;
+}
+
+
+/*
+ * Check inode permissions. We verify we have a valid value for
+ * the AUTH cap, then call the generic handler.
+ */
+int ceph_permission(struct inode *inode, int mask)
+{
+ int err = ceph_do_getattr(inode, CEPH_CAP_AUTH_SHARED);
+
+ if (!err)
+ err = generic_permission(inode, mask, NULL);
+ return err;
+}
+
+/*
+ * Get all attributes. Hopefully somedata we'll have a statlite()
+ * and can limit the fields we require to be accurate.
+ */
+int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry,
+ struct kstat *stat)
+{
+ struct inode *inode = dentry->d_inode;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ int err;
+
+ err = ceph_do_getattr(inode, CEPH_STAT_CAP_INODE_ALL);
+ if (!err) {
+ generic_fillattr(inode, stat);
+ stat->ino = inode->i_ino;
+ if (ceph_snap(inode) != CEPH_NOSNAP)
+ stat->dev = ceph_snap(inode);
+ else
+ stat->dev = 0;
+ if (S_ISDIR(inode->i_mode)) {
+ stat->size = ci->i_rbytes;
+ stat->blocks = 0;
+ stat->blksize = 65536;
+ }
+ }
+ return err;
+}
diff --git a/fs/ceph/ioctl.c b/fs/ceph/ioctl.c
new file mode 100644
index 000000000000..e4f99eff5d93
--- /dev/null
+++ b/fs/ceph/ioctl.c
@@ -0,0 +1,157 @@
+#include <linux/in.h>
+
+#include "ioctl.h"
+#include "super.h"
+#include "ceph_debug.h"
+
+
+/*
+ * ioctls
+ */
+
+/*
+ * get and set the file layout
+ */
+static long ceph_ioctl_get_layout(struct file *file, void __user *arg)
+{
+ struct ceph_inode_info *ci = ceph_inode(file->f_dentry->d_inode);
+ struct ceph_ioctl_layout l;
+ int err;
+
+ err = ceph_do_getattr(file->f_dentry->d_inode, CEPH_STAT_CAP_LAYOUT);
+ if (!err) {
+ l.stripe_unit = ceph_file_layout_su(ci->i_layout);
+ l.stripe_count = ceph_file_layout_stripe_count(ci->i_layout);
+ l.object_size = ceph_file_layout_object_size(ci->i_layout);
+ l.data_pool = le32_to_cpu(ci->i_layout.fl_pg_pool);
+ if (copy_to_user(arg, &l, sizeof(l)))
+ return -EFAULT;
+ }
+
+ return err;
+}
+
+static long ceph_ioctl_set_layout(struct file *file, void __user *arg)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct inode *parent_inode = file->f_dentry->d_parent->d_inode;
+ struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc;
+ struct ceph_mds_request *req;
+ struct ceph_ioctl_layout l;
+ int err, i;
+
+ /* copy and validate */
+ if (copy_from_user(&l, arg, sizeof(l)))
+ return -EFAULT;
+
+ if ((l.object_size & ~PAGE_MASK) ||
+ (l.stripe_unit & ~PAGE_MASK) ||
+ !l.stripe_unit ||
+ (l.object_size &&
+ (unsigned)l.object_size % (unsigned)l.stripe_unit))
+ return -EINVAL;
+
+ /* make sure it's a valid data pool */
+ if (l.data_pool > 0) {
+ mutex_lock(&mdsc->mutex);
+ err = -EINVAL;
+ for (i = 0; i < mdsc->mdsmap->m_num_data_pg_pools; i++)
+ if (mdsc->mdsmap->m_data_pg_pools[i] == l.data_pool) {
+ err = 0;
+ break;
+ }
+ mutex_unlock(&mdsc->mutex);
+ if (err)
+ return err;
+ }
+
+ req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETLAYOUT,
+ USE_AUTH_MDS);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+ req->r_inode = igrab(inode);
+ req->r_inode_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL;
+
+ req->r_args.setlayout.layout.fl_stripe_unit =
+ cpu_to_le32(l.stripe_unit);
+ req->r_args.setlayout.layout.fl_stripe_count =
+ cpu_to_le32(l.stripe_count);
+ req->r_args.setlayout.layout.fl_object_size =
+ cpu_to_le32(l.object_size);
+ req->r_args.setlayout.layout.fl_pg_pool = cpu_to_le32(l.data_pool);
+ req->r_args.setlayout.layout.fl_pg_preferred = cpu_to_le32((s32)-1);
+
+ err = ceph_mdsc_do_request(mdsc, parent_inode, req);
+ ceph_mdsc_put_request(req);
+ return err;
+}
+
+/*
+ * Return object name, size/offset information, and location (OSD
+ * number, network address) for a given file offset.
+ */
+static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)
+{
+ struct ceph_ioctl_dataloc dl;
+ struct inode *inode = file->f_dentry->d_inode;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_osd_client *osdc = &ceph_client(inode->i_sb)->osdc;
+ u64 len = 1, olen;
+ u64 tmp;
+ struct ceph_object_layout ol;
+ union ceph_pg pgid;
+
+ /* copy and validate */
+ if (copy_from_user(&dl, arg, sizeof(dl)))
+ return -EFAULT;
+
+ down_read(&osdc->map_sem);
+ ceph_calc_file_object_mapping(&ci->i_layout, dl.file_offset, &len,
+ &dl.object_no, &dl.object_offset, &olen);
+ dl.file_offset -= dl.object_offset;
+ dl.object_size = ceph_file_layout_object_size(ci->i_layout);
+ dl.block_size = ceph_file_layout_su(ci->i_layout);
+
+ /* block_offset = object_offset % block_size */
+ tmp = dl.object_offset;
+ dl.block_offset = do_div(tmp, dl.block_size);
+
+ snprintf(dl.object_name, sizeof(dl.object_name), "%llx.%08llx",
+ ceph_ino(inode), dl.object_no);
+ ceph_calc_object_layout(&ol, dl.object_name, &ci->i_layout,
+ osdc->osdmap);
+
+ pgid.pg64 = le64_to_cpu(ol.ol_pgid);
+ dl.osd = ceph_calc_pg_primary(osdc->osdmap, pgid);
+ if (dl.osd >= 0) {
+ struct ceph_entity_addr *a =
+ ceph_osd_addr(osdc->osdmap, dl.osd);
+ if (a)
+ memcpy(&dl.osd_addr, &a->in_addr, sizeof(dl.osd_addr));
+ } else {
+ memset(&dl.osd_addr, 0, sizeof(dl.osd_addr));
+ }
+ up_read(&osdc->map_sem);
+
+ /* send result back to user */
+ if (copy_to_user(arg, &dl, sizeof(dl)))
+ return -EFAULT;
+
+ return 0;
+}
+
+long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ dout("ioctl file %p cmd %u arg %lu\n", file, cmd, arg);
+ switch (cmd) {
+ case CEPH_IOC_GET_LAYOUT:
+ return ceph_ioctl_get_layout(file, (void __user *)arg);
+
+ case CEPH_IOC_SET_LAYOUT:
+ return ceph_ioctl_set_layout(file, (void __user *)arg);
+
+ case CEPH_IOC_GET_DATALOC:
+ return ceph_ioctl_get_dataloc(file, (void __user *)arg);
+ }
+ return -ENOTTY;
+}
diff --git a/fs/ceph/ioctl.h b/fs/ceph/ioctl.h
new file mode 100644
index 000000000000..3c511dab3730
--- /dev/null
+++ b/fs/ceph/ioctl.h
@@ -0,0 +1,39 @@
+#ifndef FS_CEPH_IOCTL_H
+#define FS_CEPH_IOCTL_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define CEPH_IOCTL_MAGIC 0x97
+
+/* just use u64 to align sanely on all archs */
+struct ceph_ioctl_layout {
+ __u64 stripe_unit, stripe_count, object_size;
+ __u64 data_pool;
+};
+
+#define CEPH_IOC_GET_LAYOUT _IOR(CEPH_IOCTL_MAGIC, 1, \
+ struct ceph_ioctl_layout)
+#define CEPH_IOC_SET_LAYOUT _IOW(CEPH_IOCTL_MAGIC, 2, \
+ struct ceph_ioctl_layout)
+
+/*
+ * Extract identity, address of the OSD and object storing a given
+ * file offset.
+ */
+struct ceph_ioctl_dataloc {
+ __u64 file_offset; /* in+out: file offset */
+ __u64 object_offset; /* out: offset in object */
+ __u64 object_no; /* out: object # */
+ __u64 object_size; /* out: object size */
+ char object_name[64]; /* out: object name */
+ __u64 block_offset; /* out: offset in block */
+ __u64 block_size; /* out: block length */
+ __s64 osd; /* out: osd # */
+ struct sockaddr_storage osd_addr; /* out: osd address */
+};
+
+#define CEPH_IOC_GET_DATALOC _IOWR(CEPH_IOCTL_MAGIC, 3, \
+ struct ceph_ioctl_dataloc)
+
+#endif
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
new file mode 100644
index 000000000000..12d66c0572ac
--- /dev/null
+++ b/fs/ceph/mds_client.c
@@ -0,0 +1,2912 @@
+#include "ceph_debug.h"
+
+#include <linux/wait.h>
+#include <linux/sched.h>
+
+#include "mds_client.h"
+#include "mon_client.h"
+#include "super.h"
+#include "messenger.h"
+#include "decode.h"
+
+/*
+ * A cluster of MDS (metadata server) daemons is responsible for
+ * managing the file system namespace (the directory hierarchy and
+ * inodes) and for coordinating shared access to storage. Metadata is
+ * partitioning hierarchically across a number of servers, and that
+ * partition varies over time as the cluster adjusts the distribution
+ * in order to balance load.
+ *
+ * The MDS client is primarily responsible to managing synchronous
+ * metadata requests for operations like open, unlink, and so forth.
+ * If there is a MDS failure, we find out about it when we (possibly
+ * request and) receive a new MDS map, and can resubmit affected
+ * requests.
+ *
+ * For the most part, though, we take advantage of a lossless
+ * communications channel to the MDS, and do not need to worry about
+ * timing out or resubmitting requests.
+ *
+ * We maintain a stateful "session" with each MDS we interact with.
+ * Within each session, we sent periodic heartbeat messages to ensure
+ * any capabilities or leases we have been issues remain valid. If
+ * the session times out and goes stale, our leases and capabilities
+ * are no longer valid.
+ */
+
+static void __wake_requests(struct ceph_mds_client *mdsc,
+ struct list_head *head);
+
+const static struct ceph_connection_operations mds_con_ops;
+
+
+/*
+ * mds reply parsing
+ */
+
+/*
+ * parse individual inode info
+ */
+static int parse_reply_info_in(void **p, void *end,
+ struct ceph_mds_reply_info_in *info)
+{
+ int err = -EIO;
+
+ info->in = *p;
+ *p += sizeof(struct ceph_mds_reply_inode) +
+ sizeof(*info->in->fragtree.splits) *
+ le32_to_cpu(info->in->fragtree.nsplits);
+
+ ceph_decode_32_safe(p, end, info->symlink_len, bad);
+ ceph_decode_need(p, end, info->symlink_len, bad);
+ info->symlink = *p;
+ *p += info->symlink_len;
+
+ ceph_decode_32_safe(p, end, info->xattr_len, bad);
+ ceph_decode_need(p, end, info->xattr_len, bad);
+ info->xattr_data = *p;
+ *p += info->xattr_len;
+ return 0;
+bad:
+ return err;
+}
+
+/*
+ * parse a normal reply, which may contain a (dir+)dentry and/or a
+ * target inode.
+ */
+static int parse_reply_info_trace(void **p, void *end,
+ struct ceph_mds_reply_info_parsed *info)
+{
+ int err;
+
+ if (info->head->is_dentry) {
+ err = parse_reply_info_in(p, end, &info->diri);
+ if (err < 0)
+ goto out_bad;
+
+ if (unlikely(*p + sizeof(*info->dirfrag) > end))
+ goto bad;
+ info->dirfrag = *p;
+ *p += sizeof(*info->dirfrag) +
+ sizeof(u32)*le32_to_cpu(info->dirfrag->ndist);
+ if (unlikely(*p > end))
+ goto bad;
+
+ ceph_decode_32_safe(p, end, info->dname_len, bad);
+ ceph_decode_need(p, end, info->dname_len, bad);
+ info->dname = *p;
+ *p += info->dname_len;
+ info->dlease = *p;
+ *p += sizeof(*info->dlease);
+ }
+
+ if (info->head->is_target) {
+ err = parse_reply_info_in(p, end, &info->targeti);
+ if (err < 0)
+ goto out_bad;
+ }
+
+ if (unlikely(*p != end))
+ goto bad;
+ return 0;
+
+bad:
+ err = -EIO;
+out_bad:
+ pr_err("problem parsing mds trace %d\n", err);
+ return err;
+}
+
+/*
+ * parse readdir results
+ */
+static int parse_reply_info_dir(void **p, void *end,
+ struct ceph_mds_reply_info_parsed *info)
+{
+ u32 num, i = 0;
+ int err;
+
+ info->dir_dir = *p;
+ if (*p + sizeof(*info->dir_dir) > end)
+ goto bad;
+ *p += sizeof(*info->dir_dir) +
+ sizeof(u32)*le32_to_cpu(info->dir_dir->ndist);
+ if (*p > end)
+ goto bad;
+
+ ceph_decode_need(p, end, sizeof(num) + 2, bad);
+ num = ceph_decode_32(p);
+ info->dir_end = ceph_decode_8(p);
+ info->dir_complete = ceph_decode_8(p);
+ if (num == 0)
+ goto done;
+
+ /* alloc large array */
+ info->dir_nr = num;
+ info->dir_in = kcalloc(num, sizeof(*info->dir_in) +
+ sizeof(*info->dir_dname) +
+ sizeof(*info->dir_dname_len) +
+ sizeof(*info->dir_dlease),
+ GFP_NOFS);
+ if (info->dir_in == NULL) {
+ err = -ENOMEM;
+ goto out_bad;
+ }
+ info->dir_dname = (void *)(info->dir_in + num);
+ info->dir_dname_len = (void *)(info->dir_dname + num);
+ info->dir_dlease = (void *)(info->dir_dname_len + num);
+
+ while (num) {
+ /* dentry */
+ ceph_decode_need(p, end, sizeof(u32)*2, bad);
+ info->dir_dname_len[i] = ceph_decode_32(p);
+ ceph_decode_need(p, end, info->dir_dname_len[i], bad);
+ info->dir_dname[i] = *p;
+ *p += info->dir_dname_len[i];
+ dout("parsed dir dname '%.*s'\n", info->dir_dname_len[i],
+ info->dir_dname[i]);
+ info->dir_dlease[i] = *p;
+ *p += sizeof(struct ceph_mds_reply_lease);
+
+ /* inode */
+ err = parse_reply_info_in(p, end, &info->dir_in[i]);
+ if (err < 0)
+ goto out_bad;
+ i++;
+ num--;
+ }
+
+done:
+ if (*p != end)
+ goto bad;
+ return 0;
+
+bad:
+ err = -EIO;
+out_bad:
+ pr_err("problem parsing dir contents %d\n", err);
+ return err;
+}
+
+/*
+ * parse entire mds reply
+ */
+static int parse_reply_info(struct ceph_msg *msg,
+ struct ceph_mds_reply_info_parsed *info)
+{
+ void *p, *end;
+ u32 len;
+ int err;
+
+ info->head = msg->front.iov_base;
+ p = msg->front.iov_base + sizeof(struct ceph_mds_reply_head);
+ end = p + msg->front.iov_len - sizeof(struct ceph_mds_reply_head);
+
+ /* trace */
+ ceph_decode_32_safe(&p, end, len, bad);
+ if (len > 0) {
+ err = parse_reply_info_trace(&p, p+len, info);
+ if (err < 0)
+ goto out_bad;
+ }
+
+ /* dir content */
+ ceph_decode_32_safe(&p, end, len, bad);
+ if (len > 0) {
+ err = parse_reply_info_dir(&p, p+len, info);
+ if (err < 0)
+ goto out_bad;
+ }
+
+ /* snap blob */
+ ceph_decode_32_safe(&p, end, len, bad);
+ info->snapblob_len = len;
+ info->snapblob = p;
+ p += len;
+
+ if (p != end)
+ goto bad;
+ return 0;
+
+bad:
+ err = -EIO;
+out_bad:
+ pr_err("mds parse_reply err %d\n", err);
+ return err;
+}
+
+static void destroy_reply_info(struct ceph_mds_reply_info_parsed *info)
+{
+ kfree(info->dir_in);
+}
+
+
+/*
+ * sessions
+ */
+static const char *session_state_name(int s)
+{
+ switch (s) {
+ case CEPH_MDS_SESSION_NEW: return "new";
+ case CEPH_MDS_SESSION_OPENING: return "opening";
+ case CEPH_MDS_SESSION_OPEN: return "open";
+ case CEPH_MDS_SESSION_HUNG: return "hung";
+ case CEPH_MDS_SESSION_CLOSING: return "closing";
+ case CEPH_MDS_SESSION_RECONNECTING: return "reconnecting";
+ default: return "???";
+ }
+}
+
+static struct ceph_mds_session *get_session(struct ceph_mds_session *s)
+{
+ if (atomic_inc_not_zero(&s->s_ref)) {
+ dout("mdsc get_session %p %d -> %d\n", s,
+ atomic_read(&s->s_ref)-1, atomic_read(&s->s_ref));
+ return s;
+ } else {
+ dout("mdsc get_session %p 0 -- FAIL", s);
+ return NULL;
+ }
+}
+
+void ceph_put_mds_session(struct ceph_mds_session *s)
+{
+ dout("mdsc put_session %p %d -> %d\n", s,
+ atomic_read(&s->s_ref), atomic_read(&s->s_ref)-1);
+ if (atomic_dec_and_test(&s->s_ref)) {
+ ceph_con_shutdown(&s->s_con);
+ kfree(s);
+ }
+}
+
+/*
+ * called under mdsc->mutex
+ */
+struct ceph_mds_session *__ceph_lookup_mds_session(struct ceph_mds_client *mdsc,
+ int mds)
+{
+ struct ceph_mds_session *session;
+
+ if (mds >= mdsc->max_sessions || mdsc->sessions[mds] == NULL)
+ return NULL;
+ session = mdsc->sessions[mds];
+ dout("lookup_mds_session %p %d\n", session,
+ atomic_read(&session->s_ref));
+ get_session(session);
+ return session;
+}
+
+static bool __have_session(struct ceph_mds_client *mdsc, int mds)
+{
+ if (mds >= mdsc->max_sessions)
+ return false;
+ return mdsc->sessions[mds];
+}
+
+/*
+ * create+register a new session for given mds.
+ * called under mdsc->mutex.
+ */
+static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc,
+ int mds)
+{
+ struct ceph_mds_session *s;
+
+ s = kzalloc(sizeof(*s), GFP_NOFS);
+ s->s_mdsc = mdsc;
+ s->s_mds = mds;
+ s->s_state = CEPH_MDS_SESSION_NEW;
+ s->s_ttl = 0;
+ s->s_seq = 0;
+ mutex_init(&s->s_mutex);
+
+ ceph_con_init(mdsc->client->msgr, &s->s_con);
+ s->s_con.private = s;
+ s->s_con.ops = &mds_con_ops;
+ s->s_con.peer_name.type = CEPH_ENTITY_TYPE_MDS;
+ s->s_con.peer_name.num = cpu_to_le64(mds);
+ ceph_con_open(&s->s_con, ceph_mdsmap_get_addr(mdsc->mdsmap, mds));
+
+ spin_lock_init(&s->s_cap_lock);
+ s->s_cap_gen = 0;
+ s->s_cap_ttl = 0;
+ s->s_renew_requested = 0;
+ s->s_renew_seq = 0;
+ INIT_LIST_HEAD(&s->s_caps);
+ s->s_nr_caps = 0;
+ atomic_set(&s->s_ref, 1);
+ INIT_LIST_HEAD(&s->s_waiting);
+ INIT_LIST_HEAD(&s->s_unsafe);
+ s->s_num_cap_releases = 0;
+ INIT_LIST_HEAD(&s->s_cap_releases);
+ INIT_LIST_HEAD(&s->s_cap_releases_done);
+ INIT_LIST_HEAD(&s->s_cap_flushing);
+ INIT_LIST_HEAD(&s->s_cap_snaps_flushing);
+
+ dout("register_session mds%d\n", mds);
+ if (mds >= mdsc->max_sessions) {
+ int newmax = 1 << get_count_order(mds+1);
+ struct ceph_mds_session **sa;
+
+ dout("register_session realloc to %d\n", newmax);
+ sa = kcalloc(newmax, sizeof(void *), GFP_NOFS);
+ if (sa == NULL)
+ return ERR_PTR(-ENOMEM);
+ if (mdsc->sessions) {
+ memcpy(sa, mdsc->sessions,
+ mdsc->max_sessions * sizeof(void *));
+ kfree(mdsc->sessions);
+ }
+ mdsc->sessions = sa;
+ mdsc->max_sessions = newmax;
+ }
+ mdsc->sessions[mds] = s;
+ atomic_inc(&s->s_ref); /* one ref to sessions[], one to caller */
+ return s;
+}
+
+/*
+ * called under mdsc->mutex
+ */
+static void unregister_session(struct ceph_mds_client *mdsc, int mds)
+{
+ dout("unregister_session mds%d %p\n", mds, mdsc->sessions[mds]);
+ ceph_put_mds_session(mdsc->sessions[mds]);
+ mdsc->sessions[mds] = NULL;
+}
+
+/*
+ * drop session refs in request.
+ *
+ * should be last request ref, or hold mdsc->mutex
+ */
+static void put_request_session(struct ceph_mds_request *req)
+{
+ if (req->r_session) {
+ ceph_put_mds_session(req->r_session);
+ req->r_session = NULL;
+ }
+}
+
+void ceph_mdsc_put_request(struct ceph_mds_request *req)
+{
+ dout("mdsc put_request %p %d -> %d\n", req,
+ atomic_read(&req->r_ref), atomic_read(&req->r_ref)-1);
+ if (atomic_dec_and_test(&req->r_ref)) {
+ if (req->r_request)
+ ceph_msg_put(req->r_request);
+ if (req->r_reply) {
+ ceph_msg_put(req->r_reply);
+ destroy_reply_info(&req->r_reply_info);
+ }
+ if (req->r_inode) {
+ ceph_put_cap_refs(ceph_inode(req->r_inode),
+ CEPH_CAP_PIN);
+ iput(req->r_inode);
+ }
+ if (req->r_locked_dir)
+ ceph_put_cap_refs(ceph_inode(req->r_locked_dir),
+ CEPH_CAP_PIN);
+ if (req->r_target_inode)
+ iput(req->r_target_inode);
+ if (req->r_dentry)
+ dput(req->r_dentry);
+ if (req->r_old_dentry) {
+ ceph_put_cap_refs(
+ ceph_inode(req->r_old_dentry->d_parent->d_inode),
+ CEPH_CAP_PIN);
+ dput(req->r_old_dentry);
+ }
+ kfree(req->r_path1);
+ kfree(req->r_path2);
+ put_request_session(req);
+ ceph_unreserve_caps(&req->r_caps_reservation);
+ kfree(req);
+ }
+}
+
+/*
+ * lookup session, bump ref if found.
+ *
+ * called under mdsc->mutex.
+ */
+static struct ceph_mds_request *__lookup_request(struct ceph_mds_client *mdsc,
+ u64 tid)
+{
+ struct ceph_mds_request *req;
+ req = radix_tree_lookup(&mdsc->request_tree, tid);
+ if (req)
+ ceph_mdsc_get_request(req);
+ return req;
+}
+
+/*
+ * Register an in-flight request, and assign a tid. Link to directory
+ * are modifying (if any).
+ *
+ * Called under mdsc->mutex.
+ */
+static void __register_request(struct ceph_mds_client *mdsc,
+ struct ceph_mds_request *req,
+ struct inode *dir)
+{
+ req->r_tid = ++mdsc->last_tid;
+ if (req->r_num_caps)
+ ceph_reserve_caps(&req->r_caps_reservation, req->r_num_caps);
+ dout("__register_request %p tid %lld\n", req, req->r_tid);
+ ceph_mdsc_get_request(req);
+ radix_tree_insert(&mdsc->request_tree, req->r_tid, (void *)req);
+
+ if (dir) {
+ struct ceph_inode_info *ci = ceph_inode(dir);
+
+ spin_lock(&ci->i_unsafe_lock);
+ req->r_unsafe_dir = dir;
+ list_add_tail(&req->r_unsafe_dir_item, &ci->i_unsafe_dirops);
+ spin_unlock(&ci->i_unsafe_lock);
+ }
+}
+
+static void __unregister_request(struct ceph_mds_client *mdsc,
+ struct ceph_mds_request *req)
+{
+ dout("__unregister_request %p tid %lld\n", req, req->r_tid);
+ radix_tree_delete(&mdsc->request_tree, req->r_tid);
+ ceph_mdsc_put_request(req);
+
+ if (req->r_unsafe_dir) {
+ struct ceph_inode_info *ci = ceph_inode(req->r_unsafe_dir);
+
+ spin_lock(&ci->i_unsafe_lock);
+ list_del_init(&req->r_unsafe_dir_item);
+ spin_unlock(&ci->i_unsafe_lock);
+ }
+}
+
+/*
+ * Choose mds to send request to next. If there is a hint set in the
+ * request (e.g., due to a prior forward hint from the mds), use that.
+ * Otherwise, consult frag tree and/or caps to identify the
+ * appropriate mds. If all else fails, choose randomly.
+ *
+ * Called under mdsc->mutex.
+ */
+static int __choose_mds(struct ceph_mds_client *mdsc,
+ struct ceph_mds_request *req)
+{
+ struct inode *inode;
+ struct ceph_inode_info *ci;
+ struct ceph_cap *cap;
+ int mode = req->r_direct_mode;
+ int mds = -1;
+ u32 hash = req->r_direct_hash;
+ bool is_hash = req->r_direct_is_hash;
+
+ /*
+ * is there a specific mds we should try? ignore hint if we have
+ * no session and the mds is not up (active or recovering).
+ */
+ if (req->r_resend_mds >= 0 &&
+ (__have_session(mdsc, req->r_resend_mds) ||
+ ceph_mdsmap_get_state(mdsc->mdsmap, req->r_resend_mds) > 0)) {
+ dout("choose_mds using resend_mds mds%d\n",
+ req->r_resend_mds);
+ return req->r_resend_mds;
+ }
+
+ if (mode == USE_RANDOM_MDS)
+ goto random;
+
+ inode = NULL;
+ if (req->r_inode) {
+ inode = req->r_inode;
+ } else if (req->r_dentry) {
+ if (req->r_dentry->d_inode) {
+ inode = req->r_dentry->d_inode;
+ } else {
+ inode = req->r_dentry->d_parent->d_inode;
+ hash = req->r_dentry->d_name.hash;
+ is_hash = true;
+ }
+ }
+ dout("__choose_mds %p is_hash=%d (%d) mode %d\n", inode, (int)is_hash,
+ (int)hash, mode);
+ if (!inode)
+ goto random;
+ ci = ceph_inode(inode);
+
+ if (is_hash && S_ISDIR(inode->i_mode)) {
+ struct ceph_inode_frag frag;
+ int found;
+
+ ceph_choose_frag(ci, hash, &frag, &found);
+ if (found) {
+ if (mode == USE_ANY_MDS && frag.ndist > 0) {
+ u8 r;
+
+ /* choose a random replica */
+ get_random_bytes(&r, 1);
+ r %= frag.ndist;
+ mds = frag.dist[r];
+ dout("choose_mds %p %llx.%llx "
+ "frag %u mds%d (%d/%d)\n",
+ inode, ceph_vinop(inode),
+ frag.frag, frag.mds,
+ (int)r, frag.ndist);
+ return mds;
+ }
+
+ /* since this file/dir wasn't known to be
+ * replicated, then we want to look for the
+ * authoritative mds. */
+ mode = USE_AUTH_MDS;
+ if (frag.mds >= 0) {
+ /* choose auth mds */
+ mds = frag.mds;
+ dout("choose_mds %p %llx.%llx "
+ "frag %u mds%d (auth)\n",
+ inode, ceph_vinop(inode), frag.frag, mds);
+ return mds;
+ }
+ }
+ }
+
+ spin_lock(&inode->i_lock);
+ cap = NULL;
+ if (mode == USE_AUTH_MDS)
+ cap = ci->i_auth_cap;
+ if (!cap && !RB_EMPTY_ROOT(&ci->i_caps))
+ cap = rb_entry(rb_first(&ci->i_caps), struct ceph_cap, ci_node);
+ if (!cap) {
+ spin_unlock(&inode->i_lock);
+ goto random;
+ }
+ mds = cap->session->s_mds;
+ dout("choose_mds %p %llx.%llx mds%d (%scap %p)\n",
+ inode, ceph_vinop(inode), mds,
+ cap == ci->i_auth_cap ? "auth " : "", cap);
+ spin_unlock(&inode->i_lock);
+ return mds;
+
+random:
+ mds = ceph_mdsmap_get_random_mds(mdsc->mdsmap);
+ dout("choose_mds chose random mds%d\n", mds);
+ return mds;
+}
+
+
+/*
+ * session messages
+ */
+static struct ceph_msg *create_session_msg(u32 op, u64 seq)
+{
+ struct ceph_msg *msg;
+ struct ceph_mds_session_head *h;
+
+ msg = ceph_msg_new(CEPH_MSG_CLIENT_SESSION, sizeof(*h), 0, 0, NULL);
+ if (IS_ERR(msg)) {
+ pr_err("create_session_msg ENOMEM creating msg\n");
+ return ERR_PTR(PTR_ERR(msg));
+ }
+ h = msg->front.iov_base;
+ h->op = cpu_to_le32(op);
+ h->seq = cpu_to_le64(seq);
+ return msg;
+}
+
+/*
+ * send session open request.
+ *
+ * called under mdsc->mutex
+ */
+static int __open_session(struct ceph_mds_client *mdsc,
+ struct ceph_mds_session *session)
+{
+ struct ceph_msg *msg;
+ int mstate;
+ int mds = session->s_mds;
+ int err = 0;
+
+ /* wait for mds to go active? */
+ mstate = ceph_mdsmap_get_state(mdsc->mdsmap, mds);
+ dout("open_session to mds%d (%s)\n", mds,
+ ceph_mds_state_name(mstate));
+ session->s_state = CEPH_MDS_SESSION_OPENING;
+ session->s_renew_requested = jiffies;
+
+ /* send connect message */
+ msg = create_session_msg(CEPH_SESSION_REQUEST_OPEN, session->s_seq);
+ if (IS_ERR(msg)) {
+ err = PTR_ERR(msg);
+ goto out;
+ }
+ ceph_con_send(&session->s_con, msg);
+
+out:
+ return 0;
+}
+
+/*
+ * session caps
+ */
+
+/*
+ * Free preallocated cap messages assigned to this session
+ */
+static void cleanup_cap_releases(struct ceph_mds_session *session)
+{
+ struct ceph_msg *msg;
+
+ spin_lock(&session->s_cap_lock);
+ while (!list_empty(&session->s_cap_releases)) {
+ msg = list_first_entry(&session->s_cap_releases,
+ struct ceph_msg, list_head);
+ list_del_init(&msg->list_head);
+ ceph_msg_put(msg);
+ }
+ while (!list_empty(&session->s_cap_releases_done)) {
+ msg = list_first_entry(&session->s_cap_releases_done,
+ struct ceph_msg, list_head);
+ list_del_init(&msg->list_head);
+ ceph_msg_put(msg);
+ }
+ spin_unlock(&session->s_cap_lock);
+}
+
+/*
+ * Helper to safely iterate over all caps associated with a session.
+ *
+ * caller must hold session s_mutex
+ */
+static int iterate_session_caps(struct ceph_mds_session *session,
+ int (*cb)(struct inode *, struct ceph_cap *,
+ void *), void *arg)
+{
+ struct ceph_cap *cap, *ncap;
+ struct inode *inode;
+ int ret;
+
+ dout("iterate_session_caps %p mds%d\n", session, session->s_mds);
+ spin_lock(&session->s_cap_lock);
+ list_for_each_entry_safe(cap, ncap, &session->s_caps, session_caps) {
+ inode = igrab(&cap->ci->vfs_inode);
+ if (!inode)
+ continue;
+ spin_unlock(&session->s_cap_lock);
+ ret = cb(inode, cap, arg);
+ iput(inode);
+ if (ret < 0)
+ return ret;
+ spin_lock(&session->s_cap_lock);
+ }
+ spin_unlock(&session->s_cap_lock);
+
+ return 0;
+}
+
+static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
+ void *arg)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ dout("removing cap %p, ci is %p, inode is %p\n",
+ cap, ci, &ci->vfs_inode);
+ ceph_remove_cap(cap);
+ return 0;
+}
+
+/*
+ * caller must hold session s_mutex
+ */
+static void remove_session_caps(struct ceph_mds_session *session)
+{
+ dout("remove_session_caps on %p\n", session);
+ iterate_session_caps(session, remove_session_caps_cb, NULL);
+ BUG_ON(session->s_nr_caps > 0);
+ cleanup_cap_releases(session);
+}
+
+/*
+ * wake up any threads waiting on this session's caps. if the cap is
+ * old (didn't get renewed on the client reconnect), remove it now.
+ *
+ * caller must hold s_mutex.
+ */
+static int wake_up_session_cb(struct inode *inode, struct ceph_cap *cap,
+ void *arg)
+{
+ struct ceph_mds_session *session = arg;
+
+ spin_lock(&inode->i_lock);
+ if (cap->gen != session->s_cap_gen) {
+ pr_err("failed reconnect %p %llx.%llx cap %p "
+ "(gen %d < session %d)\n", inode, ceph_vinop(inode),
+ cap, cap->gen, session->s_cap_gen);
+ __ceph_remove_cap(cap, NULL);
+ }
+ wake_up(&ceph_inode(inode)->i_cap_wq);
+ spin_unlock(&inode->i_lock);
+ return 0;
+}
+
+static void wake_up_session_caps(struct ceph_mds_session *session)
+{
+ dout("wake_up_session_caps %p mds%d\n", session, session->s_mds);
+ iterate_session_caps(session, wake_up_session_cb, session);
+}
+
+/*
+ * Send periodic message to MDS renewing all currently held caps. The
+ * ack will reset the expiration for all caps from this session.
+ *
+ * caller holds s_mutex
+ */
+static int send_renew_caps(struct ceph_mds_client *mdsc,
+ struct ceph_mds_session *session)
+{
+ struct ceph_msg *msg;
+ int state;
+
+ if (time_after_eq(jiffies, session->s_cap_ttl) &&
+ time_after_eq(session->s_cap_ttl, session->s_renew_requested))
+ pr_info("mds%d caps stale\n", session->s_mds);
+
+ /* do not try to renew caps until a recovering mds has reconnected
+ * with its clients. */
+ state = ceph_mdsmap_get_state(mdsc->mdsmap, session->s_mds);
+ if (state < CEPH_MDS_STATE_RECONNECT) {
+ dout("send_renew_caps ignoring mds%d (%s)\n",
+ session->s_mds, ceph_mds_state_name(state));
+ return 0;
+ }
+
+ dout("send_renew_caps to mds%d (%s)\n", session->s_mds,
+ ceph_mds_state_name(state));
+ session->s_renew_requested = jiffies;
+ msg = create_session_msg(CEPH_SESSION_REQUEST_RENEWCAPS,
+ ++session->s_renew_seq);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+ ceph_con_send(&session->s_con, msg);
+ return 0;
+}
+
+/*
+ * Note new cap ttl, and any transition from stale -> not stale (fresh?).
+ */
+static void renewed_caps(struct ceph_mds_client *mdsc,
+ struct ceph_mds_session *session, int is_renew)
+{
+ int was_stale;
+ int wake = 0;
+
+ spin_lock(&session->s_cap_lock);
+ was_stale = is_renew && (session->s_cap_ttl == 0 ||
+ time_after_eq(jiffies, session->s_cap_ttl));
+
+ session->s_cap_ttl = session->s_renew_requested +
+ mdsc->mdsmap->m_session_timeout*HZ;
+
+ if (was_stale) {
+ if (time_before(jiffies, session->s_cap_ttl)) {
+ pr_info("mds%d caps renewed\n", session->s_mds);
+ wake = 1;
+ } else {
+ pr_info("mds%d caps still stale\n", session->s_mds);
+ }
+ }
+ dout("renewed_caps mds%d ttl now %lu, was %s, now %s\n",
+ session->s_mds, session->s_cap_ttl, was_stale ? "stale" : "fresh",
+ time_before(jiffies, session->s_cap_ttl) ? "stale" : "fresh");
+ spin_unlock(&session->s_cap_lock);
+
+ if (wake)
+ wake_up_session_caps(session);
+}
+
+/*
+ * send a session close request
+ */
+static int request_close_session(struct ceph_mds_client *mdsc,
+ struct ceph_mds_session *session)
+{
+ struct ceph_msg *msg;
+ int err = 0;
+
+ dout("request_close_session mds%d state %s seq %lld\n",
+ session->s_mds, session_state_name(session->s_state),
+ session->s_seq);
+ msg = create_session_msg(CEPH_SESSION_REQUEST_CLOSE, session->s_seq);
+ if (IS_ERR(msg))
+ err = PTR_ERR(msg);
+ else
+ ceph_con_send(&session->s_con, msg);
+ return err;
+}
+
+/*
+ * Called with s_mutex held.
+ */
+static int __close_session(struct ceph_mds_client *mdsc,
+ struct ceph_mds_session *session)
+{
+ if (session->s_state >= CEPH_MDS_SESSION_CLOSING)
+ return 0;
+ session->s_state = CEPH_MDS_SESSION_CLOSING;
+ return request_close_session(mdsc, session);
+}
+
+/*
+ * Trim old(er) caps.
+ *
+ * Because we can't cache an inode without one or more caps, we do
+ * this indirectly: if a cap is unused, we prune its aliases, at which
+ * point the inode will hopefully get dropped to.
+ *
+ * Yes, this is a bit sloppy. Our only real goal here is to respond to
+ * memory pressure from the MDS, though, so it needn't be perfect.
+ */
+static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg)
+{
+ struct ceph_mds_session *session = arg;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ int used, oissued, mine;
+
+ if (session->s_trim_caps <= 0)
+ return -1;
+
+ spin_lock(&inode->i_lock);
+ mine = cap->issued | cap->implemented;
+ used = __ceph_caps_used(ci);
+ oissued = __ceph_caps_issued_other(ci, cap);
+
+ dout("trim_caps_cb %p cap %p mine %s oissued %s used %s\n",
+ inode, cap, ceph_cap_string(mine), ceph_cap_string(oissued),
+ ceph_cap_string(used));
+ if (ci->i_dirty_caps)
+ goto out; /* dirty caps */
+ if ((used & ~oissued) & mine)
+ goto out; /* we need these caps */
+
+ session->s_trim_caps--;
+ if (oissued) {
+ /* we aren't the only cap.. just remove us */
+ __ceph_remove_cap(cap, NULL);
+ } else {
+ /* try to drop referring dentries */
+ spin_unlock(&inode->i_lock);
+ d_prune_aliases(inode);
+ dout("trim_caps_cb %p cap %p pruned, count now %d\n",
+ inode, cap, atomic_read(&inode->i_count));
+ return 0;
+ }
+
+out:
+ spin_unlock(&inode->i_lock);
+ return 0;
+}
+
+/*
+ * Trim session cap count down to some max number.
+ */
+static int trim_caps(struct ceph_mds_client *mdsc,
+ struct ceph_mds_session *session,
+ int max_caps)
+{
+ int trim_caps = session->s_nr_caps - max_caps;
+
+ dout("trim_caps mds%d start: %d / %d, trim %d\n",
+ session->s_mds, session->s_nr_caps, max_caps, trim_caps);
+ if (trim_caps > 0) {
+ session->s_trim_caps = trim_caps;
+ iterate_session_caps(session, trim_caps_cb, session);
+ dout("trim_caps mds%d done: %d / %d, trimmed %d\n",
+ session->s_mds, session->s_nr_caps, max_caps,
+ trim_caps - session->s_trim_caps);
+ }
+ return 0;
+}
+
+/*
+ * Allocate cap_release messages. If there is a partially full message
+ * in the queue, try to allocate enough to cover it's remainder, so that
+ * we can send it immediately.
+ *
+ * Called under s_mutex.
+ */
+static int add_cap_releases(struct ceph_mds_client *mdsc,
+ struct ceph_mds_session *session,
+ int extra)
+{
+ struct ceph_msg *msg;
+ struct ceph_mds_cap_release *head;
+ int err = -ENOMEM;
+
+ if (extra < 0)
+ extra = mdsc->client->mount_args.cap_release_safety;
+
+ spin_lock(&session->s_cap_lock);
+
+ if (!list_empty(&session->s_cap_releases)) {
+ msg = list_first_entry(&session->s_cap_releases,
+ struct ceph_msg,
+ list_head);
+ head = msg->front.iov_base;
+ extra += CEPH_CAPS_PER_RELEASE - le32_to_cpu(head->num);
+ }
+
+ while (session->s_num_cap_releases < session->s_nr_caps + extra) {
+ spin_unlock(&session->s_cap_lock);
+ msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPRELEASE, PAGE_CACHE_SIZE,
+ 0, 0, NULL);
+ if (!msg)
+ goto out_unlocked;
+ dout("add_cap_releases %p msg %p now %d\n", session, msg,
+ (int)msg->front.iov_len);
+ head = msg->front.iov_base;
+ head->num = cpu_to_le32(0);
+ msg->front.iov_len = sizeof(*head);
+ spin_lock(&session->s_cap_lock);
+ list_add(&msg->list_head, &session->s_cap_releases);
+ session->s_num_cap_releases += CEPH_CAPS_PER_RELEASE;
+ }
+
+ if (!list_empty(&session->s_cap_releases)) {
+ msg = list_first_entry(&session->s_cap_releases,
+ struct ceph_msg,
+ list_head);
+ head = msg->front.iov_base;
+ if (head->num) {
+ dout(" queueing non-full %p (%d)\n", msg,
+ le32_to_cpu(head->num));
+ list_move_tail(&msg->list_head,
+ &session->s_cap_releases_done);
+ session->s_num_cap_releases -=
+ CEPH_CAPS_PER_RELEASE - le32_to_cpu(head->num);
+ }
+ }
+ err = 0;
+ spin_unlock(&session->s_cap_lock);
+out_unlocked:
+ return err;
+}
+
+/*
+ * flush all dirty inode data to disk.
+ *
+ * returns true if we've flushed through want_flush_seq
+ */
+static int check_cap_flush(struct ceph_mds_client *mdsc, u64 want_flush_seq)
+{
+ int mds, ret = 1;
+
+ dout("check_cap_flush want %lld\n", want_flush_seq);
+ mutex_lock(&mdsc->mutex);
+ for (mds = 0; ret && mds < mdsc->max_sessions; mds++) {
+ struct ceph_mds_session *session = mdsc->sessions[mds];
+
+ if (!session)
+ continue;
+ get_session(session);
+ mutex_unlock(&mdsc->mutex);
+
+ mutex_lock(&session->s_mutex);
+ if (!list_empty(&session->s_cap_flushing)) {
+ struct ceph_inode_info *ci =
+ list_entry(session->s_cap_flushing.next,
+ struct ceph_inode_info,
+ i_flushing_item);
+ struct inode *inode = &ci->vfs_inode;
+
+ spin_lock(&inode->i_lock);
+ if (ci->i_cap_flush_seq <= want_flush_seq) {
+ dout("check_cap_flush still flushing %p "
+ "seq %lld <= %lld to mds%d\n", inode,
+ ci->i_cap_flush_seq, want_flush_seq,
+ session->s_mds);
+ ret = 0;
+ }
+ spin_unlock(&inode->i_lock);
+ }
+ mutex_unlock(&session->s_mutex);
+ ceph_put_mds_session(session);
+
+ if (!ret)
+ return ret;
+ mutex_lock(&mdsc->mutex);
+ }
+
+ mutex_unlock(&mdsc->mutex);
+ dout("check_cap_flush ok, flushed thru %lld\n", want_flush_seq);
+ return ret;
+}
+
+/*
+ * called under s_mutex
+ */
+static void send_cap_releases(struct ceph_mds_client *mdsc,
+ struct ceph_mds_session *session)
+{
+ struct ceph_msg *msg;
+
+ dout("send_cap_releases mds%d\n", session->s_mds);
+ while (1) {
+ spin_lock(&session->s_cap_lock);
+ if (list_empty(&session->s_cap_releases_done))
+ break;
+ msg = list_first_entry(&session->s_cap_releases_done,
+ struct ceph_msg, list_head);
+ list_del_init(&msg->list_head);
+ spin_unlock(&session->s_cap_lock);
+ msg->hdr.front_len = cpu_to_le32(msg->front.iov_len);
+ dout("send_cap_releases mds%d %p\n", session->s_mds, msg);
+ ceph_con_send(&session->s_con, msg);
+ }
+ spin_unlock(&session->s_cap_lock);
+}
+
+/*
+ * requests
+ */
+
+/*
+ * Create an mds request.
+ */
+struct ceph_mds_request *
+ceph_mdsc_create_request(struct ceph_mds_client *mdsc, int op, int mode)
+{
+ struct ceph_mds_request *req = kzalloc(sizeof(*req), GFP_NOFS);
+
+ if (!req)
+ return ERR_PTR(-ENOMEM);
+
+ req->r_started = jiffies;
+ req->r_resend_mds = -1;
+ INIT_LIST_HEAD(&req->r_unsafe_dir_item);
+ req->r_fmode = -1;
+ atomic_set(&req->r_ref, 1); /* one for request_tree, one for caller */
+ INIT_LIST_HEAD(&req->r_wait);
+ init_completion(&req->r_completion);
+ init_completion(&req->r_safe_completion);
+ INIT_LIST_HEAD(&req->r_unsafe_item);
+
+ req->r_op = op;
+ req->r_direct_mode = mode;
+ return req;
+}
+
+/*
+ * return oldest (lowest) tid in request tree, 0 if none.
+ *
+ * called under mdsc->mutex.
+ */
+static u64 __get_oldest_tid(struct ceph_mds_client *mdsc)
+{
+ struct ceph_mds_request *first;
+ if (radix_tree_gang_lookup(&mdsc->request_tree,
+ (void **)&first, 0, 1) <= 0)
+ return 0;
+ return first->r_tid;
+}
+
+/*
+ * Build a dentry's path. Allocate on heap; caller must kfree. Based
+ * on build_path_from_dentry in fs/cifs/dir.c.
+ *
+ * If @stop_on_nosnap, generate path relative to the first non-snapped
+ * inode.
+ *
+ * Encode hidden .snap dirs as a double /, i.e.
+ * foo/.snap/bar -> foo//bar
+ */
+char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
+ int stop_on_nosnap)
+{
+ struct dentry *temp;
+ char *path;
+ int len, pos;
+
+ if (dentry == NULL)
+ return ERR_PTR(-EINVAL);
+
+retry:
+ len = 0;
+ for (temp = dentry; !IS_ROOT(temp);) {
+ struct inode *inode = temp->d_inode;
+ if (inode && ceph_snap(inode) == CEPH_SNAPDIR)
+ len++; /* slash only */
+ else if (stop_on_nosnap && inode &&
+ ceph_snap(inode) == CEPH_NOSNAP)
+ break;
+ else
+ len += 1 + temp->d_name.len;
+ temp = temp->d_parent;
+ if (temp == NULL) {
+ pr_err("build_path_dentry corrupt dentry %p\n", dentry);
+ return ERR_PTR(-EINVAL);
+ }
+ }
+ if (len)
+ len--; /* no leading '/' */
+
+ path = kmalloc(len+1, GFP_NOFS);
+ if (path == NULL)
+ return ERR_PTR(-ENOMEM);
+ pos = len;
+ path[pos] = 0; /* trailing null */
+ for (temp = dentry; !IS_ROOT(temp) && pos != 0; ) {
+ struct inode *inode = temp->d_inode;
+
+ if (inode && ceph_snap(inode) == CEPH_SNAPDIR) {
+ dout("build_path_dentry path+%d: %p SNAPDIR\n",
+ pos, temp);
+ } else if (stop_on_nosnap && inode &&
+ ceph_snap(inode) == CEPH_NOSNAP) {
+ break;
+ } else {
+ pos -= temp->d_name.len;
+ if (pos < 0)
+ break;
+ strncpy(path + pos, temp->d_name.name,
+ temp->d_name.len);
+ dout("build_path_dentry path+%d: %p '%.*s'\n",
+ pos, temp, temp->d_name.len, path + pos);
+ }
+ if (pos)
+ path[--pos] = '/';
+ temp = temp->d_parent;
+ if (temp == NULL) {
+ pr_err("build_path_dentry corrupt dentry\n");
+ kfree(path);
+ return ERR_PTR(-EINVAL);
+ }
+ }
+ if (pos != 0) {
+ pr_err("build_path_dentry did not end path lookup where "
+ "expected, namelen is %d, pos is %d\n", len, pos);
+ /* presumably this is only possible if racing with a
+ rename of one of the parent directories (we can not
+ lock the dentries above us to prevent this, but
+ retrying should be harmless) */
+ kfree(path);
+ goto retry;
+ }
+
+ *base = ceph_ino(temp->d_inode);
+ *plen = len;
+ dout("build_path_dentry on %p %d built %llx '%.*s'\n",
+ dentry, atomic_read(&dentry->d_count), *base, len, path);
+ return path;
+}
+
+static int build_dentry_path(struct dentry *dentry,
+ const char **ppath, int *ppathlen, u64 *pino,
+ int *pfreepath)
+{
+ char *path;
+
+ if (ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP) {
+ *pino = ceph_ino(dentry->d_parent->d_inode);
+ *ppath = dentry->d_name.name;
+ *ppathlen = dentry->d_name.len;
+ return 0;
+ }
+ path = ceph_mdsc_build_path(dentry, ppathlen, pino, 1);
+ if (IS_ERR(path))
+ return PTR_ERR(path);
+ *ppath = path;
+ *pfreepath = 1;
+ return 0;
+}
+
+static int build_inode_path(struct inode *inode,
+ const char **ppath, int *ppathlen, u64 *pino,
+ int *pfreepath)
+{
+ struct dentry *dentry;
+ char *path;
+
+ if (ceph_snap(inode) == CEPH_NOSNAP) {
+ *pino = ceph_ino(inode);
+ *ppathlen = 0;
+ return 0;
+ }
+ dentry = d_find_alias(inode);
+ path = ceph_mdsc_build_path(dentry, ppathlen, pino, 1);
+ dput(dentry);
+ if (IS_ERR(path))
+ return PTR_ERR(path);
+ *ppath = path;
+ *pfreepath = 1;
+ return 0;
+}
+
+/*
+ * request arguments may be specified via an inode *, a dentry *, or
+ * an explicit ino+path.
+ */
+static int set_request_path_attr(struct inode *rinode, struct dentry *rdentry,
+ const char *rpath, u64 rino,
+ const char **ppath, int *pathlen,
+ u64 *ino, int *freepath)
+{
+ int r = 0;
+
+ if (rinode) {
+ r = build_inode_path(rinode, ppath, pathlen, ino, freepath);
+ dout(" inode %p %llx.%llx\n", rinode, ceph_ino(rinode),
+ ceph_snap(rinode));
+ } else if (rdentry) {
+ r = build_dentry_path(rdentry, ppath, pathlen, ino, freepath);
+ dout(" dentry %p %llx/%.*s\n", rdentry, *ino, *pathlen,
+ *ppath);
+ } else if (rpath) {
+ *ino = rino;
+ *ppath = rpath;
+ *pathlen = strlen(rpath);
+ dout(" path %.*s\n", *pathlen, rpath);
+ }
+
+ return r;
+}
+
+/*
+ * called under mdsc->mutex
+ */
+static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc,
+ struct ceph_mds_request *req,
+ int mds)
+{
+ struct ceph_msg *msg;
+ struct ceph_mds_request_head *head;
+ const char *path1 = NULL;
+ const char *path2 = NULL;
+ u64 ino1 = 0, ino2 = 0;
+ int pathlen1 = 0, pathlen2 = 0;
+ int freepath1 = 0, freepath2 = 0;
+ int len;
+ u16 releases;
+ void *p, *end;
+ int ret;
+
+ ret = set_request_path_attr(req->r_inode, req->r_dentry,
+ req->r_path1, req->r_ino1.ino,
+ &path1, &pathlen1, &ino1, &freepath1);
+ if (ret < 0) {
+ msg = ERR_PTR(ret);
+ goto out;
+ }
+
+ ret = set_request_path_attr(NULL, req->r_old_dentry,
+ req->r_path2, req->r_ino2.ino,
+ &path2, &pathlen2, &ino2, &freepath2);
+ if (ret < 0) {
+ msg = ERR_PTR(ret);
+ goto out_free1;
+ }
+
+ len = sizeof(*head) +
+ pathlen1 + pathlen2 + 2*(sizeof(u32) + sizeof(u64));
+
+ /* calculate (max) length for cap releases */
+ len += sizeof(struct ceph_mds_request_release) *
+ (!!req->r_inode_drop + !!req->r_dentry_drop +
+ !!req->r_old_inode_drop + !!req->r_old_dentry_drop);
+ if (req->r_dentry_drop)
+ len += req->r_dentry->d_name.len;
+ if (req->r_old_dentry_drop)
+ len += req->r_old_dentry->d_name.len;
+
+ msg = ceph_msg_new(CEPH_MSG_CLIENT_REQUEST, len, 0, 0, NULL);
+ if (IS_ERR(msg))
+ goto out_free2;
+
+ head = msg->front.iov_base;
+ p = msg->front.iov_base + sizeof(*head);
+ end = msg->front.iov_base + msg->front.iov_len;
+
+ head->mdsmap_epoch = cpu_to_le32(mdsc->mdsmap->m_epoch);
+ head->op = cpu_to_le32(req->r_op);
+ head->caller_uid = cpu_to_le32(current_fsuid());
+ head->caller_gid = cpu_to_le32(current_fsgid());
+ head->args = req->r_args;
+
+ ceph_encode_filepath(&p, end, ino1, path1);
+ ceph_encode_filepath(&p, end, ino2, path2);
+
+ /* cap releases */
+ releases = 0;
+ if (req->r_inode_drop)
+ releases += ceph_encode_inode_release(&p,
+ req->r_inode ? req->r_inode : req->r_dentry->d_inode,
+ mds, req->r_inode_drop, req->r_inode_unless, 0);
+ if (req->r_dentry_drop)
+ releases += ceph_encode_dentry_release(&p, req->r_dentry,
+ mds, req->r_dentry_drop, req->r_dentry_unless);
+ if (req->r_old_dentry_drop)
+ releases += ceph_encode_dentry_release(&p, req->r_old_dentry,
+ mds, req->r_old_dentry_drop, req->r_old_dentry_unless);
+ if (req->r_old_inode_drop)
+ releases += ceph_encode_inode_release(&p,
+ req->r_old_dentry->d_inode,
+ mds, req->r_old_inode_drop, req->r_old_inode_unless, 0);
+ head->num_releases = cpu_to_le16(releases);
+
+ BUG_ON(p > end);
+ msg->front.iov_len = p - msg->front.iov_base;
+ msg->hdr.front_len = cpu_to_le32(msg->front.iov_len);
+
+ msg->pages = req->r_pages;
+ msg->nr_pages = req->r_num_pages;
+ msg->hdr.data_len = cpu_to_le32(req->r_data_len);
+ msg->hdr.data_off = cpu_to_le16(0);
+
+out_free2:
+ if (freepath2)
+ kfree((char *)path2);
+out_free1:
+ if (freepath1)
+ kfree((char *)path1);
+out:
+ return msg;
+}
+
+/*
+ * called under mdsc->mutex if error, under no mutex if
+ * success.
+ */
+static void complete_request(struct ceph_mds_client *mdsc,
+ struct ceph_mds_request *req)
+{
+ if (req->r_callback)
+ req->r_callback(mdsc, req);
+ else
+ complete(&req->r_completion);
+}
+
+/*
+ * called under mdsc->mutex
+ */
+static int __prepare_send_request(struct ceph_mds_client *mdsc,
+ struct ceph_mds_request *req,
+ int mds)
+{
+ struct ceph_mds_request_head *rhead;
+ struct ceph_msg *msg;
+ int flags = 0;
+
+ req->r_mds = mds;
+ req->r_attempts++;
+ dout("prepare_send_request %p tid %lld %s (attempt %d)\n", req,
+ req->r_tid, ceph_mds_op_name(req->r_op), req->r_attempts);
+
+ if (req->r_request) {
+ ceph_msg_put(req->r_request);
+ req->r_request = NULL;
+ }
+ msg = create_request_message(mdsc, req, mds);
+ if (IS_ERR(msg)) {
+ req->r_reply = ERR_PTR(PTR_ERR(msg));
+ complete_request(mdsc, req);
+ return -PTR_ERR(msg);
+ }
+ req->r_request = msg;
+
+ rhead = msg->front.iov_base;
+ rhead->tid = cpu_to_le64(req->r_tid);
+ rhead->oldest_client_tid = cpu_to_le64(__get_oldest_tid(mdsc));
+ if (req->r_got_unsafe)
+ flags |= CEPH_MDS_FLAG_REPLAY;
+ if (req->r_locked_dir)
+ flags |= CEPH_MDS_FLAG_WANT_DENTRY;
+ rhead->flags = cpu_to_le32(flags);
+ rhead->num_fwd = req->r_num_fwd;
+ rhead->num_retry = req->r_attempts - 1;
+
+ dout(" r_locked_dir = %p\n", req->r_locked_dir);
+
+ if (req->r_target_inode && req->r_got_unsafe)
+ rhead->ino = cpu_to_le64(ceph_ino(req->r_target_inode));
+ else
+ rhead->ino = 0;
+ return 0;
+}
+
+/*
+ * send request, or put it on the appropriate wait list.
+ */
+static int __do_request(struct ceph_mds_client *mdsc,
+ struct ceph_mds_request *req)
+{
+ struct ceph_mds_session *session = NULL;
+ int mds = -1;
+ int err = -EAGAIN;
+
+ if (req->r_reply)
+ goto out;
+
+ if (req->r_timeout &&
+ time_after_eq(jiffies, req->r_started + req->r_timeout)) {
+ dout("do_request timed out\n");
+ err = -EIO;
+ goto finish;
+ }
+
+ mds = __choose_mds(mdsc, req);
+ if (mds < 0 ||
+ ceph_mdsmap_get_state(mdsc->mdsmap, mds) < CEPH_MDS_STATE_ACTIVE) {
+ dout("do_request no mds or not active, waiting for map\n");
+ list_add(&req->r_wait, &mdsc->waiting_for_map);
+ goto out;
+ }
+
+ /* get, open session */
+ session = __ceph_lookup_mds_session(mdsc, mds);
+ if (!session)
+ session = register_session(mdsc, mds);
+ dout("do_request mds%d session %p state %s\n", mds, session,
+ session_state_name(session->s_state));
+ if (session->s_state != CEPH_MDS_SESSION_OPEN &&
+ session->s_state != CEPH_MDS_SESSION_HUNG) {
+ if (session->s_state == CEPH_MDS_SESSION_NEW ||
+ session->s_state == CEPH_MDS_SESSION_CLOSING)
+ __open_session(mdsc, session);
+ list_add(&req->r_wait, &session->s_waiting);
+ goto out_session;
+ }
+
+ /* send request */
+ req->r_session = get_session(session);
+ req->r_resend_mds = -1; /* forget any previous mds hint */
+
+ if (req->r_request_started == 0) /* note request start time */
+ req->r_request_started = jiffies;
+
+ err = __prepare_send_request(mdsc, req, mds);
+ if (!err) {
+ ceph_msg_get(req->r_request);
+ ceph_con_send(&session->s_con, req->r_request);
+ }
+
+out_session:
+ ceph_put_mds_session(session);
+out:
+ return err;
+
+finish:
+ req->r_reply = ERR_PTR(err);
+ complete_request(mdsc, req);
+ goto out;
+}
+
+/*
+ * called under mdsc->mutex
+ */
+static void __wake_requests(struct ceph_mds_client *mdsc,
+ struct list_head *head)
+{
+ struct ceph_mds_request *req, *nreq;
+
+ list_for_each_entry_safe(req, nreq, head, r_wait) {
+ list_del_init(&req->r_wait);
+ __do_request(mdsc, req);
+ }
+}
+
+/*
+ * Wake up threads with requests pending for @mds, so that they can
+ * resubmit their requests to a possibly different mds. If @all is set,
+ * wake up if their requests has been forwarded to @mds, too.
+ */
+static void kick_requests(struct ceph_mds_client *mdsc, int mds, int all)
+{
+ struct ceph_mds_request *reqs[10];
+ u64 nexttid = 0;
+ int i, got;
+
+ dout("kick_requests mds%d\n", mds);
+ while (nexttid <= mdsc->last_tid) {
+ got = radix_tree_gang_lookup(&mdsc->request_tree,
+ (void **)&reqs, nexttid, 10);
+ if (got == 0)
+ break;
+ nexttid = reqs[got-1]->r_tid + 1;
+ for (i = 0; i < got; i++) {
+ if (reqs[i]->r_got_unsafe)
+ continue;
+ if (reqs[i]->r_session &&
+ reqs[i]->r_session->s_mds == mds) {
+ dout(" kicking tid %llu\n", reqs[i]->r_tid);
+ put_request_session(reqs[i]);
+ __do_request(mdsc, reqs[i]);
+ }
+ }
+ }
+}
+
+void ceph_mdsc_submit_request(struct ceph_mds_client *mdsc,
+ struct ceph_mds_request *req)
+{
+ dout("submit_request on %p\n", req);
+ mutex_lock(&mdsc->mutex);
+ __register_request(mdsc, req, NULL);
+ __do_request(mdsc, req);
+ mutex_unlock(&mdsc->mutex);
+}
+
+/*
+ * Synchrously perform an mds request. Take care of all of the
+ * session setup, forwarding, retry details.
+ */
+int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
+ struct inode *dir,
+ struct ceph_mds_request *req)
+{
+ int err;
+
+ dout("do_request on %p\n", req);
+
+ /* take CAP_PIN refs for r_inode, r_locked_dir, r_old_dentry */
+ if (req->r_inode)
+ ceph_get_cap_refs(ceph_inode(req->r_inode), CEPH_CAP_PIN);
+ if (req->r_locked_dir)
+ ceph_get_cap_refs(ceph_inode(req->r_locked_dir), CEPH_CAP_PIN);
+ if (req->r_old_dentry)
+ ceph_get_cap_refs(
+ ceph_inode(req->r_old_dentry->d_parent->d_inode),
+ CEPH_CAP_PIN);
+
+ /* issue */
+ mutex_lock(&mdsc->mutex);
+ __register_request(mdsc, req, dir);
+ __do_request(mdsc, req);
+
+ /* wait */
+ if (!req->r_reply) {
+ mutex_unlock(&mdsc->mutex);
+ if (req->r_timeout) {
+ err = wait_for_completion_timeout(&req->r_completion,
+ req->r_timeout);
+ if (err > 0)
+ err = 0;
+ else if (err == 0)
+ req->r_reply = ERR_PTR(-EIO);
+ } else {
+ wait_for_completion(&req->r_completion);
+ }
+ mutex_lock(&mdsc->mutex);
+ }
+
+ if (IS_ERR(req->r_reply)) {
+ err = PTR_ERR(req->r_reply);
+ req->r_reply = NULL;
+
+ /* clean up */
+ __unregister_request(mdsc, req);
+ if (!list_empty(&req->r_unsafe_item))
+ list_del_init(&req->r_unsafe_item);
+ complete(&req->r_safe_completion);
+ } else if (req->r_err) {
+ err = req->r_err;
+ } else {
+ err = le32_to_cpu(req->r_reply_info.head->result);
+ }
+ mutex_unlock(&mdsc->mutex);
+
+ dout("do_request %p done, result %d\n", req, err);
+ return err;
+}
+
+/*
+ * Handle mds reply.
+ *
+ * We take the session mutex and parse and process the reply immediately.
+ * This preserves the logical ordering of replies, capabilities, etc., sent
+ * by the MDS as they are applied to our local cache.
+ */
+static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
+{
+ struct ceph_mds_client *mdsc = session->s_mdsc;
+ struct ceph_mds_request *req;
+ struct ceph_mds_reply_head *head = msg->front.iov_base;
+ struct ceph_mds_reply_info_parsed *rinfo; /* parsed reply info */
+ u64 tid;
+ int err, result;
+ int mds;
+
+ if (msg->hdr.src.name.type != CEPH_ENTITY_TYPE_MDS)
+ return;
+ if (msg->front.iov_len < sizeof(*head)) {
+ pr_err("mdsc_handle_reply got corrupt (short) reply\n");
+ return;
+ }
+
+ /* get request, session */
+ tid = le64_to_cpu(head->tid);
+ mutex_lock(&mdsc->mutex);
+ req = __lookup_request(mdsc, tid);
+ if (!req) {
+ dout("handle_reply on unknown tid %llu\n", tid);
+ mutex_unlock(&mdsc->mutex);
+ return;
+ }
+ dout("handle_reply %p\n", req);
+ mds = le64_to_cpu(msg->hdr.src.name.num);
+
+ /* correct session? */
+ if (!req->r_session && req->r_session != session) {
+ pr_err("mdsc_handle_reply got %llu on session mds%d"
+ " not mds%d\n", tid, session->s_mds,
+ req->r_session ? req->r_session->s_mds : -1);
+ mutex_unlock(&mdsc->mutex);
+ goto out;
+ }
+
+ /* dup? */
+ if ((req->r_got_unsafe && !head->safe) ||
+ (req->r_got_safe && head->safe)) {
+ pr_warning("got a dup %s reply on %llu from mds%d\n",
+ head->safe ? "safe" : "unsafe", tid, mds);
+ mutex_unlock(&mdsc->mutex);
+ goto out;
+ }
+
+ result = le32_to_cpu(head->result);
+
+ /*
+ * Tolerate 2 consecutive ESTALEs from the same mds.
+ * FIXME: we should be looking at the cap migrate_seq.
+ */
+ if (result == -ESTALE) {
+ req->r_direct_mode = USE_AUTH_MDS;
+ req->r_num_stale++;
+ if (req->r_num_stale <= 2) {
+ __do_request(mdsc, req);
+ mutex_unlock(&mdsc->mutex);
+ goto out;
+ }
+ } else {
+ req->r_num_stale = 0;
+ }
+
+ if (head->safe) {
+ req->r_got_safe = true;
+ __unregister_request(mdsc, req);
+ complete(&req->r_safe_completion);
+
+ if (req->r_got_unsafe) {
+ /*
+ * We already handled the unsafe response, now do the
+ * cleanup. No need to examine the response; the MDS
+ * doesn't include any result info in the safe
+ * response. And even if it did, there is nothing
+ * useful we could do with a revised return value.
+ */
+ dout("got safe reply %llu, mds%d\n", tid, mds);
+ list_del_init(&req->r_unsafe_item);
+
+ /* last unsafe request during umount? */
+ if (mdsc->stopping && !__get_oldest_tid(mdsc))
+ complete(&mdsc->safe_umount_waiters);
+ mutex_unlock(&mdsc->mutex);
+ goto out;
+ }
+ }
+
+ BUG_ON(req->r_reply);
+
+ if (!head->safe) {
+ req->r_got_unsafe = true;
+ list_add_tail(&req->r_unsafe_item, &req->r_session->s_unsafe);
+ }
+
+ dout("handle_reply tid %lld result %d\n", tid, result);
+ rinfo = &req->r_reply_info;
+ err = parse_reply_info(msg, rinfo);
+ mutex_unlock(&mdsc->mutex);
+
+ mutex_lock(&session->s_mutex);
+ if (err < 0) {
+ pr_err("mdsc_handle_reply got corrupt reply mds%d\n", mds);
+ goto out_err;
+ }
+
+ /* snap trace */
+ if (rinfo->snapblob_len) {
+ down_write(&mdsc->snap_rwsem);
+ ceph_update_snap_trace(mdsc, rinfo->snapblob,
+ rinfo->snapblob + rinfo->snapblob_len,
+ le32_to_cpu(head->op) == CEPH_MDS_OP_RMSNAP);
+ downgrade_write(&mdsc->snap_rwsem);
+ } else {
+ down_read(&mdsc->snap_rwsem);
+ }
+
+ /* insert trace into our cache */
+ err = ceph_fill_trace(mdsc->client->sb, req, req->r_session);
+ if (err == 0) {
+ if (result == 0 && rinfo->dir_nr)
+ ceph_readdir_prepopulate(req, req->r_session);
+ ceph_unreserve_caps(&req->r_caps_reservation);
+ }
+
+ up_read(&mdsc->snap_rwsem);
+out_err:
+ if (err) {
+ req->r_err = err;
+ } else {
+ req->r_reply = msg;
+ ceph_msg_get(msg);
+ }
+
+ add_cap_releases(mdsc, req->r_session, -1);
+ mutex_unlock(&session->s_mutex);
+
+ /* kick calling process */
+ complete_request(mdsc, req);
+out:
+ ceph_mdsc_put_request(req);
+ return;
+}
+
+
+
+/*
+ * handle mds notification that our request has been forwarded.
+ */
+static void handle_forward(struct ceph_mds_client *mdsc, struct ceph_msg *msg)
+{
+ struct ceph_mds_request *req;
+ u64 tid;
+ u32 next_mds;
+ u32 fwd_seq;
+ u8 must_resend;
+ int err = -EINVAL;
+ void *p = msg->front.iov_base;
+ void *end = p + msg->front.iov_len;
+ int from_mds, state;
+
+ if (msg->hdr.src.name.type != CEPH_ENTITY_TYPE_MDS)
+ goto bad;
+ from_mds = le64_to_cpu(msg->hdr.src.name.num);
+
+ ceph_decode_need(&p, end, sizeof(u64)+2*sizeof(u32), bad);
+ tid = ceph_decode_64(&p);
+ next_mds = ceph_decode_32(&p);
+ fwd_seq = ceph_decode_32(&p);
+ must_resend = ceph_decode_8(&p);
+
+ WARN_ON(must_resend); /* shouldn't happen. */
+
+ mutex_lock(&mdsc->mutex);
+ req = __lookup_request(mdsc, tid);
+ if (!req) {
+ dout("forward %llu dne\n", tid);
+ goto out; /* dup reply? */
+ }
+
+ state = mdsc->sessions[next_mds]->s_state;
+ if (fwd_seq <= req->r_num_fwd) {
+ dout("forward %llu to mds%d - old seq %d <= %d\n",
+ tid, next_mds, req->r_num_fwd, fwd_seq);
+ } else {
+ /* resend. forward race not possible; mds would drop */
+ dout("forward %llu to mds%d (we resend)\n", tid, next_mds);
+ req->r_num_fwd = fwd_seq;
+ req->r_resend_mds = next_mds;
+ put_request_session(req);
+ __do_request(mdsc, req);
+ }
+ ceph_mdsc_put_request(req);
+out:
+ mutex_unlock(&mdsc->mutex);
+ return;
+
+bad:
+ pr_err("mdsc_handle_forward decode error err=%d\n", err);
+}
+
+/*
+ * handle a mds session control message
+ */
+static void handle_session(struct ceph_mds_session *session,
+ struct ceph_msg *msg)
+{
+ struct ceph_mds_client *mdsc = session->s_mdsc;
+ u32 op;
+ u64 seq;
+ int mds;
+ struct ceph_mds_session_head *h = msg->front.iov_base;
+ int wake = 0;
+
+ if (msg->hdr.src.name.type != CEPH_ENTITY_TYPE_MDS)
+ return;
+ mds = le64_to_cpu(msg->hdr.src.name.num);
+
+ /* decode */
+ if (msg->front.iov_len != sizeof(*h))
+ goto bad;
+ op = le32_to_cpu(h->op);
+ seq = le64_to_cpu(h->seq);
+
+ mutex_lock(&mdsc->mutex);
+ /* FIXME: this ttl calculation is generous */
+ session->s_ttl = jiffies + HZ*mdsc->mdsmap->m_session_autoclose;
+ mutex_unlock(&mdsc->mutex);
+
+ mutex_lock(&session->s_mutex);
+
+ dout("handle_session mds%d %s %p state %s seq %llu\n",
+ mds, ceph_session_op_name(op), session,
+ session_state_name(session->s_state), seq);
+
+ if (session->s_state == CEPH_MDS_SESSION_HUNG) {
+ session->s_state = CEPH_MDS_SESSION_OPEN;
+ pr_info("mds%d came back\n", session->s_mds);
+ }
+
+ switch (op) {
+ case CEPH_SESSION_OPEN:
+ session->s_state = CEPH_MDS_SESSION_OPEN;
+ renewed_caps(mdsc, session, 0);
+ wake = 1;
+ if (mdsc->stopping)
+ __close_session(mdsc, session);
+ break;
+
+ case CEPH_SESSION_RENEWCAPS:
+ if (session->s_renew_seq == seq)
+ renewed_caps(mdsc, session, 1);
+ break;
+
+ case CEPH_SESSION_CLOSE:
+ unregister_session(mdsc, mds);
+ remove_session_caps(session);
+ wake = 1; /* for good measure */
+ complete(&mdsc->session_close_waiters);
+ kick_requests(mdsc, mds, 0); /* cur only */
+ break;
+
+ case CEPH_SESSION_STALE:
+ pr_info("mds%d caps went stale, renewing\n",
+ session->s_mds);
+ spin_lock(&session->s_cap_lock);
+ session->s_cap_gen++;
+ session->s_cap_ttl = 0;
+ spin_unlock(&session->s_cap_lock);
+ send_renew_caps(mdsc, session);
+ break;
+
+ case CEPH_SESSION_RECALL_STATE:
+ trim_caps(mdsc, session, le32_to_cpu(h->max_caps));
+ break;
+
+ default:
+ pr_err("mdsc_handle_session bad op %d mds%d\n", op, mds);
+ WARN_ON(1);
+ }
+
+ mutex_unlock(&session->s_mutex);
+ if (wake) {
+ mutex_lock(&mdsc->mutex);
+ __wake_requests(mdsc, &session->s_waiting);
+ mutex_unlock(&mdsc->mutex);
+ }
+ return;
+
+bad:
+ pr_err("mdsc_handle_session corrupt message mds%d len %d\n", mds,
+ (int)msg->front.iov_len);
+ return;
+}
+
+
+/*
+ * called under session->mutex.
+ */
+static void replay_unsafe_requests(struct ceph_mds_client *mdsc,
+ struct ceph_mds_session *session)
+{
+ struct ceph_mds_request *req, *nreq;
+ int err;
+
+ dout("replay_unsafe_requests mds%d\n", session->s_mds);
+
+ mutex_lock(&mdsc->mutex);
+ list_for_each_entry_safe(req, nreq, &session->s_unsafe, r_unsafe_item) {
+ err = __prepare_send_request(mdsc, req, session->s_mds);
+ if (!err) {
+ ceph_msg_get(req->r_request);
+ ceph_con_send(&session->s_con, req->r_request);
+ }
+ }
+ mutex_unlock(&mdsc->mutex);
+}
+
+/*
+ * Encode information about a cap for a reconnect with the MDS.
+ */
+struct encode_caps_data {
+ void **pp;
+ void *end;
+ int *num_caps;
+};
+
+static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
+ void *arg)
+{
+ struct ceph_mds_cap_reconnect *rec;
+ struct ceph_inode_info *ci;
+ struct encode_caps_data *data = (struct encode_caps_data *)arg;
+ void *p = *(data->pp);
+ void *end = data->end;
+ char *path;
+ int pathlen, err;
+ u64 pathbase;
+ struct dentry *dentry;
+
+ ci = cap->ci;
+
+ dout(" adding %p ino %llx.%llx cap %p %lld %s\n",
+ inode, ceph_vinop(inode), cap, cap->cap_id,
+ ceph_cap_string(cap->issued));
+ ceph_decode_need(&p, end, sizeof(u64), needmore);
+ ceph_encode_64(&p, ceph_ino(inode));
+
+ dentry = d_find_alias(inode);
+ if (dentry) {
+ path = ceph_mdsc_build_path(dentry, &pathlen, &pathbase, 0);
+ if (IS_ERR(path)) {
+ err = PTR_ERR(path);
+ BUG_ON(err);
+ }
+ } else {
+ path = NULL;
+ pathlen = 0;
+ }
+ ceph_decode_need(&p, end, pathlen+4, needmore);
+ ceph_encode_string(&p, end, path, pathlen);
+
+ ceph_decode_need(&p, end, sizeof(*rec), needmore);
+ rec = p;
+ p += sizeof(*rec);
+ BUG_ON(p > end);
+ spin_lock(&inode->i_lock);
+ cap->seq = 0; /* reset cap seq */
+ cap->issue_seq = 0; /* and issue_seq */
+ rec->cap_id = cpu_to_le64(cap->cap_id);
+ rec->pathbase = cpu_to_le64(pathbase);
+ rec->wanted = cpu_to_le32(__ceph_caps_wanted(ci));
+ rec->issued = cpu_to_le32(cap->issued);
+ rec->size = cpu_to_le64(inode->i_size);
+ ceph_encode_timespec(&rec->mtime, &inode->i_mtime);
+ ceph_encode_timespec(&rec->atime, &inode->i_atime);
+ rec->snaprealm = cpu_to_le64(ci->i_snap_realm->ino);
+ spin_unlock(&inode->i_lock);
+
+ kfree(path);
+ dput(dentry);
+ (*data->num_caps)++;
+ *(data->pp) = p;
+ return 0;
+needmore:
+ return -ENOSPC;
+}
+
+
+/*
+ * If an MDS fails and recovers, clients need to reconnect in order to
+ * reestablish shared state. This includes all caps issued through
+ * this session _and_ the snap_realm hierarchy. Because it's not
+ * clear which snap realms the mds cares about, we send everything we
+ * know about.. that ensures we'll then get any new info the
+ * recovering MDS might have.
+ *
+ * This is a relatively heavyweight operation, but it's rare.
+ *
+ * called with mdsc->mutex held.
+ */
+static void send_mds_reconnect(struct ceph_mds_client *mdsc, int mds)
+{
+ struct ceph_mds_session *session;
+ struct ceph_msg *reply;
+ int newlen, len = 4 + 1;
+ void *p, *end;
+ int err;
+ int num_caps, num_realms = 0;
+ int got;
+ u64 next_snap_ino = 0;
+ __le32 *pnum_caps, *pnum_realms;
+ struct encode_caps_data iter_args;
+
+ pr_info("reconnect to recovering mds%d\n", mds);
+
+ /* find session */
+ session = __ceph_lookup_mds_session(mdsc, mds);
+ mutex_unlock(&mdsc->mutex); /* drop lock for duration */
+
+ if (session) {
+ mutex_lock(&session->s_mutex);
+
+ session->s_state = CEPH_MDS_SESSION_RECONNECTING;
+ session->s_seq = 0;
+
+ ceph_con_open(&session->s_con,
+ ceph_mdsmap_get_addr(mdsc->mdsmap, mds));
+
+ /* replay unsafe requests */
+ replay_unsafe_requests(mdsc, session);
+
+ /* estimate needed space */
+ len += session->s_nr_caps *
+ (100+sizeof(struct ceph_mds_cap_reconnect));
+ pr_info("estimating i need %d bytes for %d caps\n",
+ len, session->s_nr_caps);
+ } else {
+ dout("no session for mds%d, will send short reconnect\n",
+ mds);
+ }
+
+ down_read(&mdsc->snap_rwsem);
+
+retry:
+ /* build reply */
+ reply = ceph_msg_new(CEPH_MSG_CLIENT_RECONNECT, len, 0, 0, NULL);
+ if (IS_ERR(reply)) {
+ err = PTR_ERR(reply);
+ pr_err("send_mds_reconnect ENOMEM on %d for mds%d\n",
+ len, mds);
+ goto out;
+ }
+ p = reply->front.iov_base;
+ end = p + len;
+
+ if (!session) {
+ ceph_encode_8(&p, 1); /* session was closed */
+ ceph_encode_32(&p, 0);
+ goto send;
+ }
+ dout("session %p state %s\n", session,
+ session_state_name(session->s_state));
+
+ /* traverse this session's caps */
+ ceph_encode_8(&p, 0);
+ pnum_caps = p;
+ ceph_encode_32(&p, session->s_nr_caps);
+ num_caps = 0;
+
+ iter_args.pp = &p;
+ iter_args.end = end;
+ iter_args.num_caps = &num_caps;
+ err = iterate_session_caps(session, encode_caps_cb, &iter_args);
+ if (err == -ENOSPC)
+ goto needmore;
+ if (err < 0)
+ goto out;
+ *pnum_caps = cpu_to_le32(num_caps);
+
+ /*
+ * snaprealms. we provide mds with the ino, seq (version), and
+ * parent for all of our realms. If the mds has any newer info,
+ * it will tell us.
+ */
+ next_snap_ino = 0;
+ /* save some space for the snaprealm count */
+ pnum_realms = p;
+ ceph_decode_need(&p, end, sizeof(*pnum_realms), needmore);
+ p += sizeof(*pnum_realms);
+ num_realms = 0;
+ while (1) {
+ struct ceph_snap_realm *realm;
+ struct ceph_mds_snaprealm_reconnect *sr_rec;
+ got = radix_tree_gang_lookup(&mdsc->snap_realms,
+ (void **)&realm, next_snap_ino, 1);
+ if (!got)
+ break;
+
+ dout(" adding snap realm %llx seq %lld parent %llx\n",
+ realm->ino, realm->seq, realm->parent_ino);
+ ceph_decode_need(&p, end, sizeof(*sr_rec), needmore);
+ sr_rec = p;
+ sr_rec->ino = cpu_to_le64(realm->ino);
+ sr_rec->seq = cpu_to_le64(realm->seq);
+ sr_rec->parent = cpu_to_le64(realm->parent_ino);
+ p += sizeof(*sr_rec);
+ num_realms++;
+ next_snap_ino = realm->ino + 1;
+ }
+ *pnum_realms = cpu_to_le32(num_realms);
+
+send:
+ reply->front.iov_len = p - reply->front.iov_base;
+ reply->hdr.front_len = cpu_to_le32(reply->front.iov_len);
+ dout("final len was %u (guessed %d)\n",
+ (unsigned)reply->front.iov_len, len);
+ ceph_con_send(&session->s_con, reply);
+
+ if (session) {
+ session->s_state = CEPH_MDS_SESSION_OPEN;
+ __wake_requests(mdsc, &session->s_waiting);
+ }
+
+out:
+ up_read(&mdsc->snap_rwsem);
+ if (session) {
+ mutex_unlock(&session->s_mutex);
+ ceph_put_mds_session(session);
+ }
+ mutex_lock(&mdsc->mutex);
+ return;
+
+needmore:
+ /*
+ * we need a larger buffer. this doesn't very accurately
+ * factor in snap realms, but it's safe.
+ */
+ num_caps += num_realms;
+ newlen = len * ((100 * (session->s_nr_caps+3)) / (num_caps + 1)) / 100;
+ pr_info("i guessed %d, and did %d of %d caps, retrying with %d\n",
+ len, num_caps, session->s_nr_caps, newlen);
+ len = newlen;
+ ceph_msg_put(reply);
+ goto retry;
+}
+
+
+/*
+ * compare old and new mdsmaps, kicking requests
+ * and closing out old connections as necessary
+ *
+ * called under mdsc->mutex.
+ */
+static void check_new_map(struct ceph_mds_client *mdsc,
+ struct ceph_mdsmap *newmap,
+ struct ceph_mdsmap *oldmap)
+{
+ int i;
+ int oldstate, newstate;
+ struct ceph_mds_session *s;
+
+ dout("check_new_map new %u old %u\n",
+ newmap->m_epoch, oldmap->m_epoch);
+
+ for (i = 0; i < oldmap->m_max_mds && i < mdsc->max_sessions; i++) {
+ if (mdsc->sessions[i] == NULL)
+ continue;
+ s = mdsc->sessions[i];
+ oldstate = ceph_mdsmap_get_state(oldmap, i);
+ newstate = ceph_mdsmap_get_state(newmap, i);
+
+ dout("check_new_map mds%d state %s -> %s (session %s)\n",
+ i, ceph_mds_state_name(oldstate),
+ ceph_mds_state_name(newstate),
+ session_state_name(s->s_state));
+
+ if (memcmp(ceph_mdsmap_get_addr(oldmap, i),
+ ceph_mdsmap_get_addr(newmap, i),
+ sizeof(struct ceph_entity_addr))) {
+ if (s->s_state == CEPH_MDS_SESSION_OPENING) {
+ /* the session never opened, just close it
+ * out now */
+ __wake_requests(mdsc, &s->s_waiting);
+ unregister_session(mdsc, i);
+ } else {
+ /* just close it */
+ mutex_unlock(&mdsc->mutex);
+ mutex_lock(&s->s_mutex);
+ mutex_lock(&mdsc->mutex);
+ ceph_con_close(&s->s_con);
+ mutex_unlock(&s->s_mutex);
+ s->s_state = CEPH_MDS_SESSION_RESTARTING;
+ }
+
+ /* kick any requests waiting on the recovering mds */
+ kick_requests(mdsc, i, 1);
+ } else if (oldstate == newstate) {
+ continue; /* nothing new with this mds */
+ }
+
+ /*
+ * send reconnect?
+ */
+ if (s->s_state == CEPH_MDS_SESSION_RESTARTING &&
+ newstate >= CEPH_MDS_STATE_RECONNECT)
+ send_mds_reconnect(mdsc, i);
+
+ /*
+ * kick requests on any mds that has gone active.
+ *
+ * kick requests on cur or forwarder: we may have sent
+ * the request to mds1, mds1 told us it forwarded it
+ * to mds2, but then we learn mds1 failed and can't be
+ * sure it successfully forwarded our request before
+ * it died.
+ */
+ if (oldstate < CEPH_MDS_STATE_ACTIVE &&
+ newstate >= CEPH_MDS_STATE_ACTIVE) {
+ kick_requests(mdsc, i, 1);
+ ceph_kick_flushing_caps(mdsc, s);
+ }
+ }
+}
+
+
+
+/*
+ * leases
+ */
+
+/*
+ * caller must hold session s_mutex, dentry->d_lock
+ */
+void __ceph_mdsc_drop_dentry_lease(struct dentry *dentry)
+{
+ struct ceph_dentry_info *di = ceph_dentry(dentry);
+
+ ceph_put_mds_session(di->lease_session);
+ di->lease_session = NULL;
+}
+
+static void handle_lease(struct ceph_mds_client *mdsc, struct ceph_msg *msg)
+{
+ struct super_block *sb = mdsc->client->sb;
+ struct inode *inode;
+ struct ceph_mds_session *session;
+ struct ceph_inode_info *ci;
+ struct dentry *parent, *dentry;
+ struct ceph_dentry_info *di;
+ int mds;
+ struct ceph_mds_lease *h = msg->front.iov_base;
+ struct ceph_vino vino;
+ int mask;
+ struct qstr dname;
+ int release = 0;
+
+ if (msg->hdr.src.name.type != CEPH_ENTITY_TYPE_MDS)
+ return;
+ mds = le64_to_cpu(msg->hdr.src.name.num);
+ dout("handle_lease from mds%d\n", mds);
+
+ /* decode */
+ if (msg->front.iov_len < sizeof(*h) + sizeof(u32))
+ goto bad;
+ vino.ino = le64_to_cpu(h->ino);
+ vino.snap = CEPH_NOSNAP;
+ mask = le16_to_cpu(h->mask);
+ dname.name = (void *)h + sizeof(*h) + sizeof(u32);
+ dname.len = msg->front.iov_len - sizeof(*h) - sizeof(u32);
+ if (dname.len != get_unaligned_le32(h+1))
+ goto bad;
+
+ /* find session */
+ mutex_lock(&mdsc->mutex);
+ session = __ceph_lookup_mds_session(mdsc, mds);
+ mutex_unlock(&mdsc->mutex);
+ if (!session) {
+ pr_err("handle_lease got lease but no session mds%d\n", mds);
+ return;
+ }
+
+ mutex_lock(&session->s_mutex);
+ session->s_seq++;
+
+ /* lookup inode */
+ inode = ceph_find_inode(sb, vino);
+ dout("handle_lease '%s', mask %d, ino %llx %p\n",
+ ceph_lease_op_name(h->action), mask, vino.ino, inode);
+ if (inode == NULL) {
+ dout("handle_lease no inode %llx\n", vino.ino);
+ goto release;
+ }
+ ci = ceph_inode(inode);
+
+ /* dentry */
+ parent = d_find_alias(inode);
+ if (!parent) {
+ dout("no parent dentry on inode %p\n", inode);
+ WARN_ON(1);
+ goto release; /* hrm... */
+ }
+ dname.hash = full_name_hash(dname.name, dname.len);
+ dentry = d_lookup(parent, &dname);
+ dput(parent);
+ if (!dentry)
+ goto release;
+
+ spin_lock(&dentry->d_lock);
+ di = ceph_dentry(dentry);
+ switch (h->action) {
+ case CEPH_MDS_LEASE_REVOKE:
+ if (di && di->lease_session == session) {
+ h->seq = cpu_to_le32(di->lease_seq);
+ __ceph_mdsc_drop_dentry_lease(dentry);
+ }
+ release = 1;
+ break;
+
+ case CEPH_MDS_LEASE_RENEW:
+ if (di && di->lease_session == session &&
+ di->lease_gen == session->s_cap_gen &&
+ di->lease_renew_from &&
+ di->lease_renew_after == 0) {
+ unsigned long duration =
+ le32_to_cpu(h->duration_ms) * HZ / 1000;
+
+ di->lease_seq = le32_to_cpu(h->seq);
+ dentry->d_time = di->lease_renew_from + duration;
+ di->lease_renew_after = di->lease_renew_from +
+ (duration >> 1);
+ di->lease_renew_from = 0;
+ }
+ break;
+ }
+ spin_unlock(&dentry->d_lock);
+ dput(dentry);
+
+ if (!release)
+ goto out;
+
+release:
+ /* let's just reuse the same message */
+ h->action = CEPH_MDS_LEASE_REVOKE_ACK;
+ ceph_msg_get(msg);
+ ceph_con_send(&session->s_con, msg);
+
+out:
+ iput(inode);
+ mutex_unlock(&session->s_mutex);
+ ceph_put_mds_session(session);
+ return;
+
+bad:
+ pr_err("corrupt lease message\n");
+}
+
+void ceph_mdsc_lease_send_msg(struct ceph_mds_session *session,
+ struct inode *inode,
+ struct dentry *dentry, char action,
+ u32 seq)
+{
+ struct ceph_msg *msg;
+ struct ceph_mds_lease *lease;
+ int len = sizeof(*lease) + sizeof(u32);
+ int dnamelen = 0;
+
+ dout("lease_send_msg inode %p dentry %p %s to mds%d\n",
+ inode, dentry, ceph_lease_op_name(action), session->s_mds);
+ dnamelen = dentry->d_name.len;
+ len += dnamelen;
+
+ msg = ceph_msg_new(CEPH_MSG_CLIENT_LEASE, len, 0, 0, NULL);
+ if (IS_ERR(msg))
+ return;
+ lease = msg->front.iov_base;
+ lease->action = action;
+ lease->mask = cpu_to_le16(CEPH_LOCK_DN);
+ lease->ino = cpu_to_le64(ceph_vino(inode).ino);
+ lease->first = lease->last = cpu_to_le64(ceph_vino(inode).snap);
+ lease->seq = cpu_to_le32(seq);
+ put_unaligned_le32(dnamelen, lease + 1);
+ memcpy((void *)(lease + 1) + 4, dentry->d_name.name, dnamelen);
+
+ /*
+ * if this is a preemptive lease RELEASE, no need to
+ * flush request stream, since the actual request will
+ * soon follow.
+ */
+ msg->more_to_follow = (action == CEPH_MDS_LEASE_RELEASE);
+
+ ceph_con_send(&session->s_con, msg);
+}
+
+/*
+ * Preemptively release a lease we expect to invalidate anyway.
+ * Pass @inode always, @dentry is optional.
+ */
+void ceph_mdsc_lease_release(struct ceph_mds_client *mdsc, struct inode *inode,
+ struct dentry *dentry, int mask)
+{
+ struct ceph_dentry_info *di;
+ struct ceph_mds_session *session;
+ u32 seq;
+
+ BUG_ON(inode == NULL);
+ BUG_ON(dentry == NULL);
+ BUG_ON(mask != CEPH_LOCK_DN);
+
+ /* is dentry lease valid? */
+ spin_lock(&dentry->d_lock);
+ di = ceph_dentry(dentry);
+ if (!di || !di->lease_session ||
+ di->lease_session->s_mds < 0 ||
+ di->lease_gen != di->lease_session->s_cap_gen ||
+ !time_before(jiffies, dentry->d_time)) {
+ dout("lease_release inode %p dentry %p -- "
+ "no lease on %d\n",
+ inode, dentry, mask);
+ spin_unlock(&dentry->d_lock);
+ return;
+ }
+
+ /* we do have a lease on this dentry; note mds and seq */
+ session = ceph_get_mds_session(di->lease_session);
+ seq = di->lease_seq;
+ __ceph_mdsc_drop_dentry_lease(dentry);
+ spin_unlock(&dentry->d_lock);
+
+ dout("lease_release inode %p dentry %p mask %d to mds%d\n",
+ inode, dentry, mask, session->s_mds);
+ ceph_mdsc_lease_send_msg(session, inode, dentry,
+ CEPH_MDS_LEASE_RELEASE, seq);
+ ceph_put_mds_session(session);
+}
+
+/*
+ * drop all leases (and dentry refs) in preparation for umount
+ */
+static void drop_leases(struct ceph_mds_client *mdsc)
+{
+ int i;
+
+ dout("drop_leases\n");
+ mutex_lock(&mdsc->mutex);
+ for (i = 0; i < mdsc->max_sessions; i++) {
+ struct ceph_mds_session *s = __ceph_lookup_mds_session(mdsc, i);
+ if (!s)
+ continue;
+ mutex_unlock(&mdsc->mutex);
+ mutex_lock(&s->s_mutex);
+ mutex_unlock(&s->s_mutex);
+ ceph_put_mds_session(s);
+ mutex_lock(&mdsc->mutex);
+ }
+ mutex_unlock(&mdsc->mutex);
+}
+
+
+
+/*
+ * delayed work -- periodically trim expired leases, renew caps with mds
+ */
+static void schedule_delayed(struct ceph_mds_client *mdsc)
+{
+ int delay = 5;
+ unsigned hz = round_jiffies_relative(HZ * delay);
+ schedule_delayed_work(&mdsc->delayed_work, hz);
+}
+
+static void delayed_work(struct work_struct *work)
+{
+ int i;
+ struct ceph_mds_client *mdsc =
+ container_of(work, struct ceph_mds_client, delayed_work.work);
+ int renew_interval;
+ int renew_caps;
+
+ dout("mdsc delayed_work\n");
+ ceph_check_delayed_caps(mdsc);
+
+ mutex_lock(&mdsc->mutex);
+ renew_interval = mdsc->mdsmap->m_session_timeout >> 2;
+ renew_caps = time_after_eq(jiffies, HZ*renew_interval +
+ mdsc->last_renew_caps);
+ if (renew_caps)
+ mdsc->last_renew_caps = jiffies;
+
+ for (i = 0; i < mdsc->max_sessions; i++) {
+ struct ceph_mds_session *s = __ceph_lookup_mds_session(mdsc, i);
+ if (s == NULL)
+ continue;
+ if (s->s_state == CEPH_MDS_SESSION_CLOSING) {
+ dout("resending session close request for mds%d\n",
+ s->s_mds);
+ request_close_session(mdsc, s);
+ ceph_put_mds_session(s);
+ continue;
+ }
+ if (s->s_ttl && time_after(jiffies, s->s_ttl)) {
+ if (s->s_state == CEPH_MDS_SESSION_OPEN) {
+ s->s_state = CEPH_MDS_SESSION_HUNG;
+ pr_info("mds%d hung\n", s->s_mds);
+ }
+ }
+ if (s->s_state < CEPH_MDS_SESSION_OPEN) {
+ /* this mds is failed or recovering, just wait */
+ ceph_put_mds_session(s);
+ continue;
+ }
+ mutex_unlock(&mdsc->mutex);
+
+ mutex_lock(&s->s_mutex);
+ if (renew_caps)
+ send_renew_caps(mdsc, s);
+ else
+ ceph_con_keepalive(&s->s_con);
+ add_cap_releases(mdsc, s, -1);
+ send_cap_releases(mdsc, s);
+ mutex_unlock(&s->s_mutex);
+ ceph_put_mds_session(s);
+
+ mutex_lock(&mdsc->mutex);
+ }
+ mutex_unlock(&mdsc->mutex);
+
+ schedule_delayed(mdsc);
+}
+
+
+void ceph_mdsc_init(struct ceph_mds_client *mdsc, struct ceph_client *client)
+{
+ mdsc->client = client;
+ mutex_init(&mdsc->mutex);
+ mdsc->mdsmap = kzalloc(sizeof(*mdsc->mdsmap), GFP_NOFS);
+ init_completion(&mdsc->safe_umount_waiters);
+ init_completion(&mdsc->session_close_waiters);
+ INIT_LIST_HEAD(&mdsc->waiting_for_map);
+ mdsc->sessions = NULL;
+ mdsc->max_sessions = 0;
+ mdsc->stopping = 0;
+ init_rwsem(&mdsc->snap_rwsem);
+ INIT_RADIX_TREE(&mdsc->snap_realms, GFP_NOFS);
+ INIT_LIST_HEAD(&mdsc->snap_empty);
+ spin_lock_init(&mdsc->snap_empty_lock);
+ mdsc->last_tid = 0;
+ INIT_RADIX_TREE(&mdsc->request_tree, GFP_NOFS);
+ INIT_DELAYED_WORK(&mdsc->delayed_work, delayed_work);
+ mdsc->last_renew_caps = jiffies;
+ INIT_LIST_HEAD(&mdsc->cap_delay_list);
+ spin_lock_init(&mdsc->cap_delay_lock);
+ INIT_LIST_HEAD(&mdsc->snap_flush_list);
+ spin_lock_init(&mdsc->snap_flush_lock);
+ mdsc->cap_flush_seq = 0;
+ INIT_LIST_HEAD(&mdsc->cap_dirty);
+ mdsc->num_cap_flushing = 0;
+ spin_lock_init(&mdsc->cap_dirty_lock);
+ init_waitqueue_head(&mdsc->cap_flushing_wq);
+ spin_lock_init(&mdsc->dentry_lru_lock);
+ INIT_LIST_HEAD(&mdsc->dentry_lru);
+}
+
+/*
+ * Wait for safe replies on open mds requests. If we time out, drop
+ * all requests from the tree to avoid dangling dentry refs.
+ */
+static void wait_requests(struct ceph_mds_client *mdsc)
+{
+ struct ceph_mds_request *req;
+ struct ceph_client *client = mdsc->client;
+
+ mutex_lock(&mdsc->mutex);
+ if (__get_oldest_tid(mdsc)) {
+ mutex_unlock(&mdsc->mutex);
+ dout("wait_requests waiting for requests\n");
+ wait_for_completion_timeout(&mdsc->safe_umount_waiters,
+ client->mount_args.mount_timeout * HZ);
+ mutex_lock(&mdsc->mutex);
+
+ /* tear down remaining requests */
+ while (radix_tree_gang_lookup(&mdsc->request_tree,
+ (void **)&req, 0, 1)) {
+ dout("wait_requests timed out on tid %llu\n",
+ req->r_tid);
+ radix_tree_delete(&mdsc->request_tree, req->r_tid);
+ ceph_mdsc_put_request(req);
+ }
+ }
+ mutex_unlock(&mdsc->mutex);
+ dout("wait_requests done\n");
+}
+
+/*
+ * called before mount is ro, and before dentries are torn down.
+ * (hmm, does this still race with new lookups?)
+ */
+void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc)
+{
+ dout("pre_umount\n");
+ mdsc->stopping = 1;
+
+ drop_leases(mdsc);
+ ceph_flush_dirty_caps(mdsc);
+ wait_requests(mdsc);
+}
+
+/*
+ * wait for all write mds requests to flush.
+ */
+static void wait_unsafe_requests(struct ceph_mds_client *mdsc, u64 want_tid)
+{
+ struct ceph_mds_request *req;
+ u64 next_tid = 0;
+ int got;
+
+ mutex_lock(&mdsc->mutex);
+ dout("wait_unsafe_requests want %lld\n", want_tid);
+ while (1) {
+ got = radix_tree_gang_lookup(&mdsc->request_tree, (void **)&req,
+ next_tid, 1);
+ if (!got)
+ break;
+ if (req->r_tid > want_tid)
+ break;
+
+ next_tid = req->r_tid + 1;
+ if ((req->r_op & CEPH_MDS_OP_WRITE) == 0)
+ continue; /* not a write op */
+
+ ceph_mdsc_get_request(req);
+ mutex_unlock(&mdsc->mutex);
+ dout("wait_unsafe_requests wait on %llu (want %llu)\n",
+ req->r_tid, want_tid);
+ wait_for_completion(&req->r_safe_completion);
+ mutex_lock(&mdsc->mutex);
+ ceph_mdsc_put_request(req);
+ }
+ mutex_unlock(&mdsc->mutex);
+ dout("wait_unsafe_requests done\n");
+}
+
+void ceph_mdsc_sync(struct ceph_mds_client *mdsc)
+{
+ u64 want_tid, want_flush;
+
+ dout("sync\n");
+ mutex_lock(&mdsc->mutex);
+ want_tid = mdsc->last_tid;
+ want_flush = mdsc->cap_flush_seq;
+ mutex_unlock(&mdsc->mutex);
+ dout("sync want tid %lld flush_seq %lld\n", want_tid, want_flush);
+
+ ceph_flush_dirty_caps(mdsc);
+
+ wait_unsafe_requests(mdsc, want_tid);
+ wait_event(mdsc->cap_flushing_wq, check_cap_flush(mdsc, want_flush));
+}
+
+
+/*
+ * called after sb is ro.
+ */
+void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc)
+{
+ struct ceph_mds_session *session;
+ int i;
+ int n;
+ struct ceph_client *client = mdsc->client;
+ unsigned long started, timeout = client->mount_args.mount_timeout * HZ;
+
+ dout("close_sessions\n");
+
+ mutex_lock(&mdsc->mutex);
+
+ /* close sessions */
+ started = jiffies;
+ while (time_before(jiffies, started + timeout)) {
+ dout("closing sessions\n");
+ n = 0;
+ for (i = 0; i < mdsc->max_sessions; i++) {
+ session = __ceph_lookup_mds_session(mdsc, i);
+ if (!session)
+ continue;
+ mutex_unlock(&mdsc->mutex);
+ mutex_lock(&session->s_mutex);
+ __close_session(mdsc, session);
+ mutex_unlock(&session->s_mutex);
+ ceph_put_mds_session(session);
+ mutex_lock(&mdsc->mutex);
+ n++;
+ }
+ if (n == 0)
+ break;
+
+ if (client->mount_state == CEPH_MOUNT_SHUTDOWN)
+ break;
+
+ dout("waiting for sessions to close\n");
+ mutex_unlock(&mdsc->mutex);
+ wait_for_completion_timeout(&mdsc->session_close_waiters,
+ timeout);
+ mutex_lock(&mdsc->mutex);
+ }
+
+ /* tear down remaining sessions */
+ for (i = 0; i < mdsc->max_sessions; i++) {
+ if (mdsc->sessions[i]) {
+ session = get_session(mdsc->sessions[i]);
+ unregister_session(mdsc, i);
+ mutex_unlock(&mdsc->mutex);
+ mutex_lock(&session->s_mutex);
+ remove_session_caps(session);
+ mutex_unlock(&session->s_mutex);
+ ceph_put_mds_session(session);
+ mutex_lock(&mdsc->mutex);
+ }
+ }
+
+ WARN_ON(!list_empty(&mdsc->cap_delay_list));
+
+ mutex_unlock(&mdsc->mutex);
+
+ ceph_cleanup_empty_realms(mdsc);
+
+ cancel_delayed_work_sync(&mdsc->delayed_work); /* cancel timer */
+
+ dout("stopped\n");
+}
+
+void ceph_mdsc_stop(struct ceph_mds_client *mdsc)
+{
+ dout("stop\n");
+ cancel_delayed_work_sync(&mdsc->delayed_work); /* cancel timer */
+ if (mdsc->mdsmap)
+ ceph_mdsmap_destroy(mdsc->mdsmap);
+ kfree(mdsc->sessions);
+}
+
+
+/*
+ * handle mds map update.
+ */
+void ceph_mdsc_handle_map(struct ceph_mds_client *mdsc, struct ceph_msg *msg)
+{
+ u32 epoch;
+ u32 maplen;
+ void *p = msg->front.iov_base;
+ void *end = p + msg->front.iov_len;
+ struct ceph_mdsmap *newmap, *oldmap;
+ struct ceph_fsid fsid;
+ int err = -EINVAL;
+
+ ceph_decode_need(&p, end, sizeof(fsid)+2*sizeof(u32), bad);
+ ceph_decode_copy(&p, &fsid, sizeof(fsid));
+ if (ceph_fsid_compare(&fsid, &mdsc->client->monc.monmap->fsid)) {
+ pr_err("got mdsmap with wrong fsid\n");
+ return;
+ }
+ epoch = ceph_decode_32(&p);
+ maplen = ceph_decode_32(&p);
+ dout("handle_map epoch %u len %d\n", epoch, (int)maplen);
+
+ /* do we need it? */
+ ceph_monc_got_mdsmap(&mdsc->client->monc, epoch);
+ mutex_lock(&mdsc->mutex);
+ if (mdsc->mdsmap && epoch <= mdsc->mdsmap->m_epoch) {
+ dout("handle_map epoch %u <= our %u\n",
+ epoch, mdsc->mdsmap->m_epoch);
+ mutex_unlock(&mdsc->mutex);
+ return;
+ }
+
+ newmap = ceph_mdsmap_decode(&p, end);
+ if (IS_ERR(newmap)) {
+ err = PTR_ERR(newmap);
+ goto bad_unlock;
+ }
+
+ /* swap into place */
+ if (mdsc->mdsmap) {
+ oldmap = mdsc->mdsmap;
+ mdsc->mdsmap = newmap;
+ check_new_map(mdsc, newmap, oldmap);
+ ceph_mdsmap_destroy(oldmap);
+ } else {
+ mdsc->mdsmap = newmap; /* first mds map */
+ }
+ mdsc->client->sb->s_maxbytes = mdsc->mdsmap->m_max_file_size;
+
+ __wake_requests(mdsc, &mdsc->waiting_for_map);
+
+ mutex_unlock(&mdsc->mutex);
+ schedule_delayed(mdsc);
+ return;
+
+bad_unlock:
+ mutex_unlock(&mdsc->mutex);
+bad:
+ pr_err("error decoding mdsmap %d\n", err);
+ return;
+}
+
+static struct ceph_connection *con_get(struct ceph_connection *con)
+{
+ struct ceph_mds_session *s = con->private;
+
+ if (get_session(s)) {
+ dout("mdsc con_get %p %d -> %d\n", s,
+ atomic_read(&s->s_ref) - 1, atomic_read(&s->s_ref));
+ return con;
+ }
+ dout("mdsc con_get %p FAIL\n", s);
+ return NULL;
+}
+
+static void con_put(struct ceph_connection *con)
+{
+ struct ceph_mds_session *s = con->private;
+
+ dout("mdsc con_put %p %d -> %d\n", s, atomic_read(&s->s_ref),
+ atomic_read(&s->s_ref) - 1);
+ ceph_put_mds_session(s);
+}
+
+/*
+ * if the client is unresponsive for long enough, the mds will kill
+ * the session entirely.
+ */
+static void peer_reset(struct ceph_connection *con)
+{
+ struct ceph_mds_session *s = con->private;
+
+ pr_err("mds%d gave us the boot. IMPLEMENT RECONNECT.\n",
+ s->s_mds);
+}
+
+static void dispatch(struct ceph_connection *con, struct ceph_msg *msg)
+{
+ struct ceph_mds_session *s = con->private;
+ struct ceph_mds_client *mdsc = s->s_mdsc;
+ int type = le16_to_cpu(msg->hdr.type);
+
+ switch (type) {
+ case CEPH_MSG_MDS_MAP:
+ ceph_mdsc_handle_map(mdsc, msg);
+ break;
+ case CEPH_MSG_CLIENT_SESSION:
+ handle_session(s, msg);
+ break;
+ case CEPH_MSG_CLIENT_REPLY:
+ handle_reply(s, msg);
+ break;
+ case CEPH_MSG_CLIENT_REQUEST_FORWARD:
+ handle_forward(mdsc, msg);
+ break;
+ case CEPH_MSG_CLIENT_CAPS:
+ ceph_handle_caps(s, msg);
+ break;
+ case CEPH_MSG_CLIENT_SNAP:
+ ceph_handle_snap(mdsc, msg);
+ break;
+ case CEPH_MSG_CLIENT_LEASE:
+ handle_lease(mdsc, msg);
+ break;
+
+ default:
+ pr_err("received unknown message type %d %s\n", type,
+ ceph_msg_type_name(type));
+ }
+ ceph_msg_put(msg);
+}
+
+const static struct ceph_connection_operations mds_con_ops = {
+ .get = con_get,
+ .put = con_put,
+ .dispatch = dispatch,
+ .peer_reset = peer_reset,
+ .alloc_msg = ceph_alloc_msg,
+ .alloc_middle = ceph_alloc_middle,
+};
+
+
+
+
+/* eof */
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h
new file mode 100644
index 000000000000..f566e9c84295
--- /dev/null
+++ b/fs/ceph/mds_client.h
@@ -0,0 +1,321 @@
+#ifndef _FS_CEPH_MDS_CLIENT_H
+#define _FS_CEPH_MDS_CLIENT_H
+
+#include <linux/completion.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/radix-tree.h>
+#include <linux/spinlock.h>
+
+#include "types.h"
+#include "messenger.h"
+#include "mdsmap.h"
+
+/*
+ * Some lock dependencies:
+ *
+ * session->s_mutex
+ * mdsc->mutex
+ *
+ * mdsc->snap_rwsem
+ *
+ * inode->i_lock
+ * mdsc->snap_flush_lock
+ * mdsc->cap_delay_lock
+ *
+ */
+
+struct ceph_client;
+struct ceph_cap;
+
+/*
+ * parsed info about a single inode. pointers are into the encoded
+ * on-wire structures within the mds reply message payload.
+ */
+struct ceph_mds_reply_info_in {
+ struct ceph_mds_reply_inode *in;
+ u32 symlink_len;
+ char *symlink;
+ u32 xattr_len;
+ char *xattr_data;
+};
+
+/*
+ * parsed info about an mds reply, including information about the
+ * target inode and/or its parent directory and dentry, and directory
+ * contents (for readdir results).
+ */
+struct ceph_mds_reply_info_parsed {
+ struct ceph_mds_reply_head *head;
+
+ struct ceph_mds_reply_info_in diri, targeti;
+ struct ceph_mds_reply_dirfrag *dirfrag;
+ char *dname;
+ u32 dname_len;
+ struct ceph_mds_reply_lease *dlease;
+
+ struct ceph_mds_reply_dirfrag *dir_dir;
+ int dir_nr;
+ char **dir_dname;
+ u32 *dir_dname_len;
+ struct ceph_mds_reply_lease **dir_dlease;
+ struct ceph_mds_reply_info_in *dir_in;
+ u8 dir_complete, dir_end;
+
+ /* encoded blob describing snapshot contexts for certain
+ operations (e.g., open) */
+ void *snapblob;
+ int snapblob_len;
+};
+
+
+/*
+ * cap releases are batched and sent to the MDS en masse.
+ */
+#define CEPH_CAPS_PER_RELEASE ((PAGE_CACHE_SIZE - \
+ sizeof(struct ceph_mds_cap_release)) / \
+ sizeof(struct ceph_mds_cap_item))
+
+
+/*
+ * state associated with each MDS<->client session
+ */
+enum {
+ CEPH_MDS_SESSION_NEW = 1,
+ CEPH_MDS_SESSION_OPENING = 2,
+ CEPH_MDS_SESSION_OPEN = 3,
+ CEPH_MDS_SESSION_HUNG = 4,
+ CEPH_MDS_SESSION_CLOSING = 5,
+ CEPH_MDS_SESSION_RESTARTING = 6,
+ CEPH_MDS_SESSION_RECONNECTING = 7,
+};
+
+struct ceph_mds_session {
+ struct ceph_mds_client *s_mdsc;
+ int s_mds;
+ int s_state;
+ unsigned long s_ttl; /* time until mds kills us */
+ u64 s_seq; /* incoming msg seq # */
+ struct mutex s_mutex; /* serialize session messages */
+
+ struct ceph_connection s_con;
+
+ /* protected by s_cap_lock */
+ spinlock_t s_cap_lock;
+ u32 s_cap_gen; /* inc each time we get mds stale msg */
+ unsigned long s_cap_ttl; /* when session caps expire */
+ struct list_head s_caps; /* all caps issued by this session */
+ int s_nr_caps, s_trim_caps;
+ int s_num_cap_releases;
+ struct list_head s_cap_releases; /* waiting cap_release messages */
+ struct list_head s_cap_releases_done; /* ready to send */
+
+ /* protected by mutex */
+ struct list_head s_cap_flushing; /* inodes w/ flushing caps */
+ struct list_head s_cap_snaps_flushing;
+ unsigned long s_renew_requested; /* last time we sent a renew req */
+ u64 s_renew_seq;
+
+ atomic_t s_ref;
+ struct list_head s_waiting; /* waiting requests */
+ struct list_head s_unsafe; /* unsafe requests */
+};
+
+/*
+ * modes of choosing which MDS to send a request to
+ */
+enum {
+ USE_ANY_MDS,
+ USE_RANDOM_MDS,
+ USE_AUTH_MDS, /* prefer authoritative mds for this metadata item */
+};
+
+struct ceph_mds_request;
+struct ceph_mds_client;
+
+/*
+ * request completion callback
+ */
+typedef void (*ceph_mds_request_callback_t) (struct ceph_mds_client *mdsc,
+ struct ceph_mds_request *req);
+
+/*
+ * an in-flight mds request
+ */
+struct ceph_mds_request {
+ u64 r_tid; /* transaction id */
+
+ int r_op; /* mds op code */
+ int r_mds;
+
+ /* operation on what? */
+ struct inode *r_inode; /* arg1 */
+ struct dentry *r_dentry; /* arg1 */
+ struct dentry *r_old_dentry; /* arg2: rename from or link from */
+ char *r_path1, *r_path2;
+ struct ceph_vino r_ino1, r_ino2;
+
+ struct inode *r_locked_dir; /* dir (if any) i_mutex locked by vfs */
+ struct inode *r_target_inode; /* resulting inode */
+
+ union ceph_mds_request_args r_args;
+ int r_fmode; /* file mode, if expecting cap */
+
+ /* for choosing which mds to send this request to */
+ int r_direct_mode;
+ u32 r_direct_hash; /* choose dir frag based on this dentry hash */
+ bool r_direct_is_hash; /* true if r_direct_hash is valid */
+
+ /* data payload is used for xattr ops */
+ struct page **r_pages;
+ int r_num_pages;
+ int r_data_len;
+
+ /* what caps shall we drop? */
+ int r_inode_drop, r_inode_unless;
+ int r_dentry_drop, r_dentry_unless;
+ int r_old_dentry_drop, r_old_dentry_unless;
+ struct inode *r_old_inode;
+ int r_old_inode_drop, r_old_inode_unless;
+
+ struct ceph_msg *r_request; /* original request */
+ struct ceph_msg *r_reply;
+ struct ceph_mds_reply_info_parsed r_reply_info;
+ int r_err;
+
+ unsigned long r_timeout; /* optional. jiffies */
+ unsigned long r_started; /* start time to measure timeout against */
+ unsigned long r_request_started; /* start time for mds request only,
+ used to measure lease durations */
+
+ /* link unsafe requests to parent directory, for fsync */
+ struct inode *r_unsafe_dir;
+ struct list_head r_unsafe_dir_item;
+
+ struct ceph_mds_session *r_session;
+
+ int r_attempts; /* resend attempts */
+ int r_num_fwd; /* number of forward attempts */
+ int r_num_stale;
+ int r_resend_mds; /* mds to resend to next, if any*/
+
+ atomic_t r_ref;
+ struct list_head r_wait;
+ struct completion r_completion;
+ struct completion r_safe_completion;
+ ceph_mds_request_callback_t r_callback;
+ struct list_head r_unsafe_item; /* per-session unsafe list item */
+ bool r_got_unsafe, r_got_safe;
+
+ bool r_did_prepopulate;
+ u32 r_readdir_offset;
+
+ struct ceph_cap_reservation r_caps_reservation;
+ int r_num_caps;
+};
+
+/*
+ * mds client state
+ */
+struct ceph_mds_client {
+ struct ceph_client *client;
+ struct mutex mutex; /* all nested structures */
+
+ struct ceph_mdsmap *mdsmap;
+ struct completion safe_umount_waiters, session_close_waiters;
+ struct list_head waiting_for_map;
+
+ struct ceph_mds_session **sessions; /* NULL for mds if no session */
+ int max_sessions; /* len of s_mds_sessions */
+ int stopping; /* true if shutting down */
+
+ /*
+ * snap_rwsem will cover cap linkage into snaprealms, and
+ * realm snap contexts. (later, we can do per-realm snap
+ * contexts locks..) the empty list contains realms with no
+ * references (implying they contain no inodes with caps) that
+ * should be destroyed.
+ */
+ struct rw_semaphore snap_rwsem;
+ struct radix_tree_root snap_realms;
+ struct list_head snap_empty;
+ spinlock_t snap_empty_lock; /* protect snap_empty */
+
+ u64 last_tid; /* most recent mds request */
+ struct radix_tree_root request_tree; /* pending mds requests */
+ struct delayed_work delayed_work; /* delayed work */
+ unsigned long last_renew_caps; /* last time we renewed our caps */
+ struct list_head cap_delay_list; /* caps with delayed release */
+ spinlock_t cap_delay_lock; /* protects cap_delay_list */
+ struct list_head snap_flush_list; /* cap_snaps ready to flush */
+ spinlock_t snap_flush_lock;
+
+ u64 cap_flush_seq;
+ struct list_head cap_dirty; /* inodes with dirty caps */
+ int num_cap_flushing; /* # caps we are flushing */
+ spinlock_t cap_dirty_lock; /* protects above items */
+ wait_queue_head_t cap_flushing_wq;
+
+ struct dentry *debugfs_file;
+
+ spinlock_t dentry_lru_lock;
+ struct list_head dentry_lru;
+ int num_dentry;
+};
+
+extern const char *ceph_mds_op_name(int op);
+
+extern struct ceph_mds_session *
+__ceph_lookup_mds_session(struct ceph_mds_client *, int mds);
+
+static inline struct ceph_mds_session *
+ceph_get_mds_session(struct ceph_mds_session *s)
+{
+ atomic_inc(&s->s_ref);
+ return s;
+}
+
+extern void ceph_put_mds_session(struct ceph_mds_session *s);
+
+extern int ceph_send_msg_mds(struct ceph_mds_client *mdsc,
+ struct ceph_msg *msg, int mds);
+
+extern void ceph_mdsc_init(struct ceph_mds_client *mdsc,
+ struct ceph_client *client);
+extern void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc);
+extern void ceph_mdsc_stop(struct ceph_mds_client *mdsc);
+
+extern void ceph_mdsc_sync(struct ceph_mds_client *mdsc);
+
+extern void ceph_mdsc_lease_release(struct ceph_mds_client *mdsc,
+ struct inode *inode,
+ struct dentry *dn, int mask);
+
+extern struct ceph_mds_request *
+ceph_mdsc_create_request(struct ceph_mds_client *mdsc, int op, int mode);
+extern void ceph_mdsc_submit_request(struct ceph_mds_client *mdsc,
+ struct ceph_mds_request *req);
+extern int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
+ struct inode *dir,
+ struct ceph_mds_request *req);
+static inline void ceph_mdsc_get_request(struct ceph_mds_request *req)
+{
+ atomic_inc(&req->r_ref);
+}
+extern void ceph_mdsc_put_request(struct ceph_mds_request *req);
+
+extern void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc);
+
+extern char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
+ int stop_on_nosnap);
+
+extern void __ceph_mdsc_drop_dentry_lease(struct dentry *dentry);
+extern void ceph_mdsc_lease_send_msg(struct ceph_mds_session *session,
+ struct inode *inode,
+ struct dentry *dentry, char action,
+ u32 seq);
+
+extern void ceph_mdsc_handle_map(struct ceph_mds_client *mdsc,
+ struct ceph_msg *msg);
+
+#endif
diff --git a/fs/ceph/mdsmap.c b/fs/ceph/mdsmap.c
new file mode 100644
index 000000000000..80daea064470
--- /dev/null
+++ b/fs/ceph/mdsmap.c
@@ -0,0 +1,166 @@
+#include "ceph_debug.h"
+
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "mdsmap.h"
+#include "messenger.h"
+#include "decode.h"
+
+#include "super.h"
+
+
+/*
+ * choose a random mds that is "up" (i.e. has a state > 0), or -1.
+ */
+int ceph_mdsmap_get_random_mds(struct ceph_mdsmap *m)
+{
+ int n = 0;
+ int i;
+ char r;
+
+ /* count */
+ for (i = 0; i < m->m_max_mds; i++)
+ if (m->m_info[i].state > 0)
+ n++;
+ if (n == 0)
+ return -1;
+
+ /* pick */
+ get_random_bytes(&r, 1);
+ n = r % n;
+ i = 0;
+ for (i = 0; n > 0; i++, n--)
+ while (m->m_info[i].state <= 0)
+ i++;
+
+ return i;
+}
+
+/*
+ * Decode an MDS map
+ *
+ * Ignore any fields we don't care about (there are quite a few of
+ * them).
+ */
+struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end)
+{
+ struct ceph_mdsmap *m;
+ int i, j, n;
+ int err = -EINVAL;
+ u16 version;
+
+ m = kzalloc(sizeof(*m), GFP_NOFS);
+ if (m == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ ceph_decode_16_safe(p, end, version, bad);
+
+ ceph_decode_need(p, end, 8*sizeof(u32) + sizeof(u64), bad);
+ m->m_epoch = ceph_decode_32(p);
+ m->m_client_epoch = ceph_decode_32(p);
+ m->m_last_failure = ceph_decode_32(p);
+ m->m_root = ceph_decode_32(p);
+ m->m_session_timeout = ceph_decode_32(p);
+ m->m_session_autoclose = ceph_decode_32(p);
+ m->m_max_file_size = ceph_decode_64(p);
+ m->m_max_mds = ceph_decode_32(p);
+
+ m->m_info = kcalloc(m->m_max_mds, sizeof(*m->m_info), GFP_NOFS);
+ if (m->m_info == NULL)
+ goto badmem;
+
+ /* pick out active nodes from mds_info (state > 0) */
+ n = ceph_decode_32(p);
+ for (i = 0; i < n; i++) {
+ u32 namelen;
+ s32 mds, inc, state;
+ u64 state_seq;
+ u8 infoversion;
+ struct ceph_entity_addr addr;
+ u32 num_export_targets;
+ void *pexport_targets = NULL;
+
+ ceph_decode_need(p, end, sizeof(addr) + 1 + sizeof(u32), bad);
+ ceph_decode_copy(p, &addr, sizeof(addr));
+ infoversion = ceph_decode_8(p);
+ namelen = ceph_decode_32(p); /* skip mds name */
+ *p += namelen;
+
+ ceph_decode_need(p, end,
+ 4*sizeof(u32) + sizeof(u64) +
+ sizeof(addr) + sizeof(struct ceph_timespec),
+ bad);
+ mds = ceph_decode_32(p);
+ inc = ceph_decode_32(p);
+ state = ceph_decode_32(p);
+ state_seq = ceph_decode_64(p);
+ *p += sizeof(addr);
+ *p += sizeof(struct ceph_timespec);
+ *p += sizeof(u32);
+ ceph_decode_32_safe(p, end, namelen, bad);
+ *p += namelen;
+ if (infoversion >= 2) {
+ ceph_decode_32_safe(p, end, num_export_targets, bad);
+ pexport_targets = *p;
+ *p += num_export_targets * sizeof(u32);
+ } else {
+ num_export_targets = 0;
+ }
+
+ dout("mdsmap_decode %d/%d mds%d.%d %s %s\n",
+ i+1, n, mds, inc, pr_addr(&addr.in_addr),
+ ceph_mds_state_name(state));
+ if (mds >= 0 && mds < m->m_max_mds && state > 0) {
+ m->m_info[mds].state = state;
+ m->m_info[mds].addr = addr;
+ m->m_info[mds].num_export_targets = num_export_targets;
+ if (num_export_targets) {
+ m->m_info[mds].export_targets =
+ kcalloc(num_export_targets, sizeof(u32),
+ GFP_NOFS);
+ for (j = 0; j < num_export_targets; j++)
+ m->m_info[mds].export_targets[j] =
+ ceph_decode_32(&pexport_targets);
+ } else {
+ m->m_info[mds].export_targets = NULL;
+ }
+ }
+ }
+
+ /* pg_pools */
+ ceph_decode_32_safe(p, end, n, bad);
+ m->m_num_data_pg_pools = n;
+ m->m_data_pg_pools = kcalloc(n, sizeof(u32), GFP_NOFS);
+ if (!m->m_data_pg_pools)
+ goto badmem;
+ ceph_decode_need(p, end, sizeof(u32)*(n+1), bad);
+ for (i = 0; i < n; i++)
+ m->m_data_pg_pools[i] = ceph_decode_32(p);
+ m->m_cas_pg_pool = ceph_decode_32(p);
+
+ /* ok, we don't care about the rest. */
+ dout("mdsmap_decode success epoch %u\n", m->m_epoch);
+ return m;
+
+badmem:
+ err = -ENOMEM;
+bad:
+ pr_err("corrupt mdsmap\n");
+ ceph_mdsmap_destroy(m);
+ return ERR_PTR(-EINVAL);
+}
+
+void ceph_mdsmap_destroy(struct ceph_mdsmap *m)
+{
+ int i;
+
+ for (i = 0; i < m->m_max_mds; i++)
+ kfree(m->m_info[i].export_targets);
+ kfree(m->m_info);
+ kfree(m->m_data_pg_pools);
+ kfree(m);
+}
diff --git a/fs/ceph/mdsmap.h b/fs/ceph/mdsmap.h
new file mode 100644
index 000000000000..d317308648fb
--- /dev/null
+++ b/fs/ceph/mdsmap.h
@@ -0,0 +1,53 @@
+#ifndef _FS_CEPH_MDSMAP_H
+#define _FS_CEPH_MDSMAP_H
+
+#include "types.h"
+
+/*
+ * mds map - describe servers in the mds cluster.
+ *
+ * we limit fields to those the client actually xcares about
+ */
+struct ceph_mds_info {
+ struct ceph_entity_addr addr;
+ s32 state;
+ int num_export_targets;
+ u32 *export_targets;
+};
+
+struct ceph_mdsmap {
+ u32 m_epoch, m_client_epoch, m_last_failure;
+ u32 m_root;
+ u32 m_session_timeout; /* seconds */
+ u32 m_session_autoclose; /* seconds */
+ u64 m_max_file_size;
+ u32 m_max_mds; /* size of m_addr, m_state arrays */
+ struct ceph_mds_info *m_info;
+
+ /* which object pools file data can be stored in */
+ int m_num_data_pg_pools;
+ u32 *m_data_pg_pools;
+ u32 m_cas_pg_pool;
+};
+
+static inline struct ceph_entity_addr *
+ceph_mdsmap_get_addr(struct ceph_mdsmap *m, int w)
+{
+ if (w >= m->m_max_mds)
+ return NULL;
+ return &m->m_info[w].addr;
+}
+
+static inline int ceph_mdsmap_get_state(struct ceph_mdsmap *m, int w)
+{
+ BUG_ON(w < 0);
+ if (w >= m->m_max_mds)
+ return CEPH_MDS_STATE_DNE;
+ return m->m_info[w].state;
+}
+
+extern int ceph_mdsmap_get_random_mds(struct ceph_mdsmap *m);
+extern struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end);
+extern void ceph_mdsmap_destroy(struct ceph_mdsmap *m);
+
+#endif
diff --git a/fs/ceph/messenger.c b/fs/ceph/messenger.c
new file mode 100644
index 000000000000..b48abc0b3be7
--- /dev/null
+++ b/fs/ceph/messenger.c
@@ -0,0 +1,2019 @@
+#include "ceph_debug.h"
+
+#include <linux/crc32c.h>
+#include <linux/ctype.h>
+#include <linux/highmem.h>
+#include <linux/inet.h>
+#include <linux/kthread.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <linux/string.h>
+#include <net/tcp.h>
+
+#include "super.h"
+#include "messenger.h"
+
+/*
+ * Ceph uses the messenger to exchange ceph_msg messages with other
+ * hosts in the system. The messenger provides ordered and reliable
+ * delivery. We tolerate TCP disconnects by reconnecting (with
+ * exponential backoff) in the case of a fault (disconnection, bad
+ * crc, protocol error). Acks allow sent messages to be discarded by
+ * the sender.
+ */
+
+/* static tag bytes (protocol control messages) */
+static char tag_msg = CEPH_MSGR_TAG_MSG;
+static char tag_ack = CEPH_MSGR_TAG_ACK;
+static char tag_keepalive = CEPH_MSGR_TAG_KEEPALIVE;
+
+
+static void queue_con(struct ceph_connection *con);
+static void con_work(struct work_struct *);
+static void ceph_fault(struct ceph_connection *con);
+
+const char *ceph_name_type_str(int t)
+{
+ switch (t) {
+ case CEPH_ENTITY_TYPE_MON: return "mon";
+ case CEPH_ENTITY_TYPE_MDS: return "mds";
+ case CEPH_ENTITY_TYPE_OSD: return "osd";
+ case CEPH_ENTITY_TYPE_CLIENT: return "client";
+ case CEPH_ENTITY_TYPE_ADMIN: return "admin";
+ default: return "???";
+ }
+}
+
+/*
+ * nicely render a sockaddr as a string.
+ */
+#define MAX_ADDR_STR 20
+static char addr_str[MAX_ADDR_STR][40];
+static DEFINE_SPINLOCK(addr_str_lock);
+static int last_addr_str;
+
+const char *pr_addr(const struct sockaddr_storage *ss)
+{
+ int i;
+ char *s;
+ struct sockaddr_in *in4 = (void *)ss;
+ unsigned char *quad = (void *)&in4->sin_addr.s_addr;
+ struct sockaddr_in6 *in6 = (void *)ss;
+
+ spin_lock(&addr_str_lock);
+ i = last_addr_str++;
+ if (last_addr_str == MAX_ADDR_STR)
+ last_addr_str = 0;
+ spin_unlock(&addr_str_lock);
+ s = addr_str[i];
+
+ switch (ss->ss_family) {
+ case AF_INET:
+ sprintf(s, "%u.%u.%u.%u:%u",
+ (unsigned int)quad[0],
+ (unsigned int)quad[1],
+ (unsigned int)quad[2],
+ (unsigned int)quad[3],
+ (unsigned int)ntohs(in4->sin_port));
+ break;
+
+ case AF_INET6:
+ sprintf(s, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%u",
+ in6->sin6_addr.s6_addr16[0],
+ in6->sin6_addr.s6_addr16[1],
+ in6->sin6_addr.s6_addr16[2],
+ in6->sin6_addr.s6_addr16[3],
+ in6->sin6_addr.s6_addr16[4],
+ in6->sin6_addr.s6_addr16[5],
+ in6->sin6_addr.s6_addr16[6],
+ in6->sin6_addr.s6_addr16[7],
+ (unsigned int)ntohs(in6->sin6_port));
+ break;
+
+ default:
+ sprintf(s, "(unknown sockaddr family %d)", (int)ss->ss_family);
+ }
+
+ return s;
+}
+
+/*
+ * work queue for all reading and writing to/from the socket.
+ */
+struct workqueue_struct *ceph_msgr_wq;
+
+int __init ceph_msgr_init(void)
+{
+ ceph_msgr_wq = create_workqueue("ceph-msgr");
+ if (IS_ERR(ceph_msgr_wq)) {
+ int ret = PTR_ERR(ceph_msgr_wq);
+ pr_err("msgr_init failed to create workqueue: %d\n", ret);
+ ceph_msgr_wq = NULL;
+ return ret;
+ }
+ return 0;
+}
+
+void ceph_msgr_exit(void)
+{
+ destroy_workqueue(ceph_msgr_wq);
+}
+
+/*
+ * socket callback functions
+ */
+
+/* data available on socket, or listen socket received a connect */
+static void ceph_data_ready(struct sock *sk, int count_unused)
+{
+ struct ceph_connection *con =
+ (struct ceph_connection *)sk->sk_user_data;
+ if (sk->sk_state != TCP_CLOSE_WAIT) {
+ dout("ceph_data_ready on %p state = %lu, queueing work\n",
+ con, con->state);
+ queue_con(con);
+ }
+}
+
+/* socket has buffer space for writing */
+static void ceph_write_space(struct sock *sk)
+{
+ struct ceph_connection *con =
+ (struct ceph_connection *)sk->sk_user_data;
+
+ /* only queue to workqueue if there is data we want to write. */
+ if (test_bit(WRITE_PENDING, &con->state)) {
+ dout("ceph_write_space %p queueing write work\n", con);
+ queue_con(con);
+ } else {
+ dout("ceph_write_space %p nothing to write\n", con);
+ }
+
+ /* since we have our own write_space, clear the SOCK_NOSPACE flag */
+ clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
+}
+
+/* socket's state has changed */
+static void ceph_state_change(struct sock *sk)
+{
+ struct ceph_connection *con =
+ (struct ceph_connection *)sk->sk_user_data;
+
+ dout("ceph_state_change %p state = %lu sk_state = %u\n",
+ con, con->state, sk->sk_state);
+
+ if (test_bit(CLOSED, &con->state))
+ return;
+
+ switch (sk->sk_state) {
+ case TCP_CLOSE:
+ dout("ceph_state_change TCP_CLOSE\n");
+ case TCP_CLOSE_WAIT:
+ dout("ceph_state_change TCP_CLOSE_WAIT\n");
+ if (test_and_set_bit(SOCK_CLOSED, &con->state) == 0) {
+ if (test_bit(CONNECTING, &con->state))
+ con->error_msg = "connection failed";
+ else
+ con->error_msg = "socket closed";
+ queue_con(con);
+ }
+ break;
+ case TCP_ESTABLISHED:
+ dout("ceph_state_change TCP_ESTABLISHED\n");
+ queue_con(con);
+ break;
+ }
+}
+
+/*
+ * set up socket callbacks
+ */
+static void set_sock_callbacks(struct socket *sock,
+ struct ceph_connection *con)
+{
+ struct sock *sk = sock->sk;
+ sk->sk_user_data = (void *)con;
+ sk->sk_data_ready = ceph_data_ready;
+ sk->sk_write_space = ceph_write_space;
+ sk->sk_state_change = ceph_state_change;
+}
+
+
+/*
+ * socket helpers
+ */
+
+/*
+ * initiate connection to a remote socket.
+ */
+static struct socket *ceph_tcp_connect(struct ceph_connection *con)
+{
+ struct sockaddr *paddr = (struct sockaddr *)&con->peer_addr.in_addr;
+ struct socket *sock;
+ int ret;
+
+ BUG_ON(con->sock);
+ ret = sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
+ if (ret)
+ return ERR_PTR(ret);
+ con->sock = sock;
+ sock->sk->sk_allocation = GFP_NOFS;
+
+ set_sock_callbacks(sock, con);
+
+ dout("connect %s\n", pr_addr(&con->peer_addr.in_addr));
+
+ ret = sock->ops->connect(sock, paddr, sizeof(*paddr), O_NONBLOCK);
+ if (ret == -EINPROGRESS) {
+ dout("connect %s EINPROGRESS sk_state = %u\n",
+ pr_addr(&con->peer_addr.in_addr),
+ sock->sk->sk_state);
+ ret = 0;
+ }
+ if (ret < 0) {
+ pr_err("connect %s error %d\n",
+ pr_addr(&con->peer_addr.in_addr), ret);
+ sock_release(sock);
+ con->sock = NULL;
+ con->error_msg = "connect error";
+ }
+
+ if (ret < 0)
+ return ERR_PTR(ret);
+ return sock;
+}
+
+static int ceph_tcp_recvmsg(struct socket *sock, void *buf, size_t len)
+{
+ struct kvec iov = {buf, len};
+ struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL };
+
+ return kernel_recvmsg(sock, &msg, &iov, 1, len, msg.msg_flags);
+}
+
+/*
+ * write something. @more is true if caller will be sending more data
+ * shortly.
+ */
+static int ceph_tcp_sendmsg(struct socket *sock, struct kvec *iov,
+ size_t kvlen, size_t len, int more)
+{
+ struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL };
+
+ if (more)
+ msg.msg_flags |= MSG_MORE;
+ else
+ msg.msg_flags |= MSG_EOR; /* superfluous, but what the hell */
+
+ return kernel_sendmsg(sock, &msg, iov, kvlen, len);
+}
+
+
+/*
+ * Shutdown/close the socket for the given connection.
+ */
+static int con_close_socket(struct ceph_connection *con)
+{
+ int rc;
+
+ dout("con_close_socket on %p sock %p\n", con, con->sock);
+ if (!con->sock)
+ return 0;
+ set_bit(SOCK_CLOSED, &con->state);
+ rc = con->sock->ops->shutdown(con->sock, SHUT_RDWR);
+ sock_release(con->sock);
+ con->sock = NULL;
+ clear_bit(SOCK_CLOSED, &con->state);
+ return rc;
+}
+
+/*
+ * Reset a connection. Discard all incoming and outgoing messages
+ * and clear *_seq state.
+ */
+static void ceph_msg_remove(struct ceph_msg *msg)
+{
+ list_del_init(&msg->list_head);
+ ceph_msg_put(msg);
+}
+static void ceph_msg_remove_list(struct list_head *head)
+{
+ while (!list_empty(head)) {
+ struct ceph_msg *msg = list_first_entry(head, struct ceph_msg,
+ list_head);
+ ceph_msg_remove(msg);
+ }
+}
+
+static void reset_connection(struct ceph_connection *con)
+{
+ /* reset connection, out_queue, msg_ and connect_seq */
+ /* discard existing out_queue and msg_seq */
+ mutex_lock(&con->out_mutex);
+ ceph_msg_remove_list(&con->out_queue);
+ ceph_msg_remove_list(&con->out_sent);
+
+ con->connect_seq = 0;
+ con->out_seq = 0;
+ con->out_msg = NULL;
+ con->in_seq = 0;
+ mutex_unlock(&con->out_mutex);
+}
+
+/*
+ * mark a peer down. drop any open connections.
+ */
+void ceph_con_close(struct ceph_connection *con)
+{
+ dout("con_close %p peer %s\n", con, pr_addr(&con->peer_addr.in_addr));
+ set_bit(CLOSED, &con->state); /* in case there's queued work */
+ clear_bit(STANDBY, &con->state); /* avoid connect_seq bump */
+ reset_connection(con);
+ queue_con(con);
+}
+
+/*
+ * clean up connection state
+ */
+void ceph_con_shutdown(struct ceph_connection *con)
+{
+ dout("con_shutdown %p\n", con);
+ reset_connection(con);
+ set_bit(DEAD, &con->state);
+ con_close_socket(con); /* silently ignore errors */
+}
+
+/*
+ * Reopen a closed connection, with a new peer address.
+ */
+void ceph_con_open(struct ceph_connection *con, struct ceph_entity_addr *addr)
+{
+ dout("con_open %p %s\n", con, pr_addr(&addr->in_addr));
+ set_bit(OPENING, &con->state);
+ clear_bit(CLOSED, &con->state);
+ memcpy(&con->peer_addr, addr, sizeof(*addr));
+ queue_con(con);
+}
+
+/*
+ * generic get/put
+ */
+struct ceph_connection *ceph_con_get(struct ceph_connection *con)
+{
+ dout("con_get %p nref = %d -> %d\n", con,
+ atomic_read(&con->nref), atomic_read(&con->nref) + 1);
+ if (atomic_inc_not_zero(&con->nref))
+ return con;
+ return NULL;
+}
+
+void ceph_con_put(struct ceph_connection *con)
+{
+ dout("con_put %p nref = %d -> %d\n", con,
+ atomic_read(&con->nref), atomic_read(&con->nref) - 1);
+ BUG_ON(atomic_read(&con->nref) == 0);
+ if (atomic_dec_and_test(&con->nref)) {
+ ceph_con_shutdown(con);
+ kfree(con);
+ }
+}
+
+/*
+ * initialize a new connection.
+ */
+void ceph_con_init(struct ceph_messenger *msgr, struct ceph_connection *con)
+{
+ dout("con_init %p\n", con);
+ memset(con, 0, sizeof(*con));
+ atomic_set(&con->nref, 1);
+ con->msgr = msgr;
+ mutex_init(&con->out_mutex);
+ INIT_LIST_HEAD(&con->out_queue);
+ INIT_LIST_HEAD(&con->out_sent);
+ INIT_DELAYED_WORK(&con->work, con_work);
+}
+
+
+/*
+ * We maintain a global counter to order connection attempts. Get
+ * a unique seq greater than @gt.
+ */
+static u32 get_global_seq(struct ceph_messenger *msgr, u32 gt)
+{
+ u32 ret;
+
+ spin_lock(&msgr->global_seq_lock);
+ if (msgr->global_seq < gt)
+ msgr->global_seq = gt;
+ ret = ++msgr->global_seq;
+ spin_unlock(&msgr->global_seq_lock);
+ return ret;
+}
+
+
+/*
+ * Prepare footer for currently outgoing message, and finish things
+ * off. Assumes out_kvec* are already valid.. we just add on to the end.
+ */
+static void prepare_write_message_footer(struct ceph_connection *con, int v)
+{
+ struct ceph_msg *m = con->out_msg;
+
+ dout("prepare_write_message_footer %p\n", con);
+ con->out_kvec_is_msg = true;
+ con->out_kvec[v].iov_base = &m->footer;
+ con->out_kvec[v].iov_len = sizeof(m->footer);
+ con->out_kvec_bytes += sizeof(m->footer);
+ con->out_kvec_left++;
+ con->out_more = m->more_to_follow;
+ con->out_msg = NULL; /* we're done with this one */
+}
+
+/*
+ * Prepare headers for the next outgoing message.
+ */
+static void prepare_write_message(struct ceph_connection *con)
+{
+ struct ceph_msg *m;
+ int v = 0;
+
+ con->out_kvec_bytes = 0;
+ con->out_kvec_is_msg = true;
+
+ /* Sneak an ack in there first? If we can get it into the same
+ * TCP packet that's a good thing. */
+ if (con->in_seq > con->in_seq_acked) {
+ con->in_seq_acked = con->in_seq;
+ con->out_kvec[v].iov_base = &tag_ack;
+ con->out_kvec[v++].iov_len = 1;
+ con->out_temp_ack = cpu_to_le64(con->in_seq_acked);
+ con->out_kvec[v].iov_base = &con->out_temp_ack;
+ con->out_kvec[v++].iov_len = sizeof(con->out_temp_ack);
+ con->out_kvec_bytes = 1 + sizeof(con->out_temp_ack);
+ }
+
+ /* move message to sending/sent list */
+ m = list_first_entry(&con->out_queue,
+ struct ceph_msg, list_head);
+ list_move_tail(&m->list_head, &con->out_sent);
+ con->out_msg = m; /* we don't bother taking a reference here. */
+
+ m->hdr.seq = cpu_to_le64(++con->out_seq);
+
+ dout("prepare_write_message %p seq %lld type %d len %d+%d+%d %d pgs\n",
+ m, con->out_seq, le16_to_cpu(m->hdr.type),
+ le32_to_cpu(m->hdr.front_len), le32_to_cpu(m->hdr.middle_len),
+ le32_to_cpu(m->hdr.data_len),
+ m->nr_pages);
+ BUG_ON(le32_to_cpu(m->hdr.front_len) != m->front.iov_len);
+
+ /* tag + hdr + front + middle */
+ con->out_kvec[v].iov_base = &tag_msg;
+ con->out_kvec[v++].iov_len = 1;
+ con->out_kvec[v].iov_base = &m->hdr;
+ con->out_kvec[v++].iov_len = sizeof(m->hdr);
+ con->out_kvec[v++] = m->front;
+ if (m->middle)
+ con->out_kvec[v++] = m->middle->vec;
+ con->out_kvec_left = v;
+ con->out_kvec_bytes += 1 + sizeof(m->hdr) + m->front.iov_len +
+ (m->middle ? m->middle->vec.iov_len : 0);
+ con->out_kvec_cur = con->out_kvec;
+
+ /* fill in crc (except data pages), footer */
+ con->out_msg->hdr.crc =
+ cpu_to_le32(crc32c(0, (void *)&m->hdr,
+ sizeof(m->hdr) - sizeof(m->hdr.crc)));
+ con->out_msg->footer.flags = CEPH_MSG_FOOTER_COMPLETE;
+ con->out_msg->footer.front_crc =
+ cpu_to_le32(crc32c(0, m->front.iov_base, m->front.iov_len));
+ if (m->middle)
+ con->out_msg->footer.middle_crc =
+ cpu_to_le32(crc32c(0, m->middle->vec.iov_base,
+ m->middle->vec.iov_len));
+ else
+ con->out_msg->footer.middle_crc = 0;
+ con->out_msg->footer.data_crc = 0;
+ dout("prepare_write_message front_crc %u data_crc %u\n",
+ le32_to_cpu(con->out_msg->footer.front_crc),
+ le32_to_cpu(con->out_msg->footer.middle_crc));
+
+ /* is there a data payload? */
+ if (le32_to_cpu(m->hdr.data_len) > 0) {
+ /* initialize page iterator */
+ con->out_msg_pos.page = 0;
+ con->out_msg_pos.page_pos =
+ le16_to_cpu(m->hdr.data_off) & ~PAGE_MASK;
+ con->out_msg_pos.data_pos = 0;
+ con->out_msg_pos.did_page_crc = 0;
+ con->out_more = 1; /* data + footer will follow */
+ } else {
+ /* no, queue up footer too and be done */
+ prepare_write_message_footer(con, v);
+ }
+
+ set_bit(WRITE_PENDING, &con->state);
+}
+
+/*
+ * Prepare an ack.
+ */
+static void prepare_write_ack(struct ceph_connection *con)
+{
+ dout("prepare_write_ack %p %llu -> %llu\n", con,
+ con->in_seq_acked, con->in_seq);
+ con->in_seq_acked = con->in_seq;
+
+ con->out_kvec[0].iov_base = &tag_ack;
+ con->out_kvec[0].iov_len = 1;
+ con->out_temp_ack = cpu_to_le64(con->in_seq_acked);
+ con->out_kvec[1].iov_base = &con->out_temp_ack;
+ con->out_kvec[1].iov_len = sizeof(con->out_temp_ack);
+ con->out_kvec_left = 2;
+ con->out_kvec_bytes = 1 + sizeof(con->out_temp_ack);
+ con->out_kvec_cur = con->out_kvec;
+ con->out_more = 1; /* more will follow.. eventually.. */
+ set_bit(WRITE_PENDING, &con->state);
+}
+
+/*
+ * Prepare to write keepalive byte.
+ */
+static void prepare_write_keepalive(struct ceph_connection *con)
+{
+ dout("prepare_write_keepalive %p\n", con);
+ con->out_kvec[0].iov_base = &tag_keepalive;
+ con->out_kvec[0].iov_len = 1;
+ con->out_kvec_left = 1;
+ con->out_kvec_bytes = 1;
+ con->out_kvec_cur = con->out_kvec;
+ set_bit(WRITE_PENDING, &con->state);
+}
+
+/*
+ * Connection negotiation.
+ */
+
+/*
+ * We connected to a peer and are saying hello.
+ */
+static void prepare_write_connect(struct ceph_messenger *msgr,
+ struct ceph_connection *con)
+{
+ int len = strlen(CEPH_BANNER);
+ unsigned global_seq = get_global_seq(con->msgr, 0);
+ int proto;
+
+ switch (con->peer_name.type) {
+ case CEPH_ENTITY_TYPE_MON:
+ proto = CEPH_MONC_PROTOCOL;
+ break;
+ case CEPH_ENTITY_TYPE_OSD:
+ proto = CEPH_OSDC_PROTOCOL;
+ break;
+ case CEPH_ENTITY_TYPE_MDS:
+ proto = CEPH_MDSC_PROTOCOL;
+ break;
+ default:
+ BUG();
+ }
+
+ dout("prepare_write_connect %p cseq=%d gseq=%d proto=%d\n", con,
+ con->connect_seq, global_seq, proto);
+ con->out_connect.host_type = cpu_to_le32(CEPH_ENTITY_TYPE_CLIENT);
+ con->out_connect.connect_seq = cpu_to_le32(con->connect_seq);
+ con->out_connect.global_seq = cpu_to_le32(global_seq);
+ con->out_connect.protocol_version = cpu_to_le32(proto);
+ con->out_connect.flags = 0;
+ if (test_bit(LOSSYTX, &con->state))
+ con->out_connect.flags = CEPH_MSG_CONNECT_LOSSY;
+
+ con->out_kvec[0].iov_base = CEPH_BANNER;
+ con->out_kvec[0].iov_len = len;
+ con->out_kvec[1].iov_base = &msgr->inst.addr;
+ con->out_kvec[1].iov_len = sizeof(msgr->inst.addr);
+ con->out_kvec[2].iov_base = &con->out_connect;
+ con->out_kvec[2].iov_len = sizeof(con->out_connect);
+ con->out_kvec_left = 3;
+ con->out_kvec_bytes = len + sizeof(msgr->inst.addr) +
+ sizeof(con->out_connect);
+ con->out_kvec_cur = con->out_kvec;
+ con->out_more = 0;
+ set_bit(WRITE_PENDING, &con->state);
+}
+
+static void prepare_write_connect_retry(struct ceph_messenger *msgr,
+ struct ceph_connection *con)
+{
+ dout("prepare_write_connect_retry %p\n", con);
+ con->out_connect.connect_seq = cpu_to_le32(con->connect_seq);
+ con->out_connect.global_seq =
+ cpu_to_le32(get_global_seq(con->msgr, 0));
+
+ con->out_kvec[0].iov_base = &con->out_connect;
+ con->out_kvec[0].iov_len = sizeof(con->out_connect);
+ con->out_kvec_left = 1;
+ con->out_kvec_bytes = sizeof(con->out_connect);
+ con->out_kvec_cur = con->out_kvec;
+ con->out_more = 0;
+ set_bit(WRITE_PENDING, &con->state);
+}
+
+
+/*
+ * write as much of pending kvecs to the socket as we can.
+ * 1 -> done
+ * 0 -> socket full, but more to do
+ * <0 -> error
+ */
+static int write_partial_kvec(struct ceph_connection *con)
+{
+ int ret;
+
+ dout("write_partial_kvec %p %d left\n", con, con->out_kvec_bytes);
+ while (con->out_kvec_bytes > 0) {
+ ret = ceph_tcp_sendmsg(con->sock, con->out_kvec_cur,
+ con->out_kvec_left, con->out_kvec_bytes,
+ con->out_more);
+ if (ret <= 0)
+ goto out;
+ con->out_kvec_bytes -= ret;
+ if (con->out_kvec_bytes == 0)
+ break; /* done */
+ while (ret > 0) {
+ if (ret >= con->out_kvec_cur->iov_len) {
+ ret -= con->out_kvec_cur->iov_len;
+ con->out_kvec_cur++;
+ con->out_kvec_left--;
+ } else {
+ con->out_kvec_cur->iov_len -= ret;
+ con->out_kvec_cur->iov_base += ret;
+ ret = 0;
+ break;
+ }
+ }
+ }
+ con->out_kvec_left = 0;
+ con->out_kvec_is_msg = false;
+ ret = 1;
+out:
+ dout("write_partial_kvec %p %d left in %d kvecs ret = %d\n", con,
+ con->out_kvec_bytes, con->out_kvec_left, ret);
+ return ret; /* done! */
+}
+
+/*
+ * Write as much message data payload as we can. If we finish, queue
+ * up the footer.
+ * 1 -> done, footer is now queued in out_kvec[].
+ * 0 -> socket full, but more to do
+ * <0 -> error
+ */
+static int write_partial_msg_pages(struct ceph_connection *con)
+{
+ struct ceph_msg *msg = con->out_msg;
+ unsigned data_len = le32_to_cpu(msg->hdr.data_len);
+ size_t len;
+ int crc = con->msgr->nocrc;
+ int ret;
+
+ dout("write_partial_msg_pages %p msg %p page %d/%d offset %d\n",
+ con, con->out_msg, con->out_msg_pos.page, con->out_msg->nr_pages,
+ con->out_msg_pos.page_pos);
+
+ while (con->out_msg_pos.page < con->out_msg->nr_pages) {
+ struct page *page = NULL;
+ void *kaddr = NULL;
+
+ /*
+ * if we are calculating the data crc (the default), we need
+ * to map the page. if our pages[] has been revoked, use the
+ * zero page.
+ */
+ if (msg->pages) {
+ page = msg->pages[con->out_msg_pos.page];
+ if (crc)
+ kaddr = kmap(page);
+ } else {
+ page = con->msgr->zero_page;
+ if (crc)
+ kaddr = page_address(con->msgr->zero_page);
+ }
+ len = min((int)(PAGE_SIZE - con->out_msg_pos.page_pos),
+ (int)(data_len - con->out_msg_pos.data_pos));
+ if (crc && !con->out_msg_pos.did_page_crc) {
+ void *base = kaddr + con->out_msg_pos.page_pos;
+ u32 tmpcrc = le32_to_cpu(con->out_msg->footer.data_crc);
+
+ BUG_ON(kaddr == NULL);
+ con->out_msg->footer.data_crc =
+ cpu_to_le32(crc32c(tmpcrc, base, len));
+ con->out_msg_pos.did_page_crc = 1;
+ }
+
+ ret = kernel_sendpage(con->sock, page,
+ con->out_msg_pos.page_pos, len,
+ MSG_DONTWAIT | MSG_NOSIGNAL |
+ MSG_MORE);
+
+ if (crc && msg->pages)
+ kunmap(page);
+
+ if (ret <= 0)
+ goto out;
+
+ con->out_msg_pos.data_pos += ret;
+ con->out_msg_pos.page_pos += ret;
+ if (ret == len) {
+ con->out_msg_pos.page_pos = 0;
+ con->out_msg_pos.page++;
+ con->out_msg_pos.did_page_crc = 0;
+ }
+ }
+
+ dout("write_partial_msg_pages %p msg %p done\n", con, msg);
+
+ /* prepare and queue up footer, too */
+ if (!crc)
+ con->out_msg->footer.flags |= CEPH_MSG_FOOTER_NOCRC;
+ con->out_kvec_bytes = 0;
+ con->out_kvec_left = 0;
+ con->out_kvec_cur = con->out_kvec;
+ prepare_write_message_footer(con, 0);
+ ret = 1;
+out:
+ return ret;
+}
+
+/*
+ * write some zeros
+ */
+static int write_partial_skip(struct ceph_connection *con)
+{
+ int ret;
+
+ while (con->out_skip > 0) {
+ struct kvec iov = {
+ .iov_base = page_address(con->msgr->zero_page),
+ .iov_len = min(con->out_skip, (int)PAGE_CACHE_SIZE)
+ };
+
+ ret = ceph_tcp_sendmsg(con->sock, &iov, 1, iov.iov_len, 1);
+ if (ret <= 0)
+ goto out;
+ con->out_skip -= ret;
+ }
+ ret = 1;
+out:
+ return ret;
+}
+
+/*
+ * Prepare to read connection handshake, or an ack.
+ */
+static void prepare_read_connect(struct ceph_connection *con)
+{
+ dout("prepare_read_connect %p\n", con);
+ con->in_base_pos = 0;
+}
+
+static void prepare_read_ack(struct ceph_connection *con)
+{
+ dout("prepare_read_ack %p\n", con);
+ con->in_base_pos = 0;
+}
+
+static void prepare_read_tag(struct ceph_connection *con)
+{
+ dout("prepare_read_tag %p\n", con);
+ con->in_base_pos = 0;
+ con->in_tag = CEPH_MSGR_TAG_READY;
+}
+
+/*
+ * Prepare to read a message.
+ */
+static int prepare_read_message(struct ceph_connection *con)
+{
+ dout("prepare_read_message %p\n", con);
+ BUG_ON(con->in_msg != NULL);
+ con->in_base_pos = 0;
+ con->in_front_crc = con->in_middle_crc = con->in_data_crc = 0;
+ return 0;
+}
+
+
+static int read_partial(struct ceph_connection *con,
+ int *to, int size, void *object)
+{
+ *to += size;
+ while (con->in_base_pos < *to) {
+ int left = *to - con->in_base_pos;
+ int have = size - left;
+ int ret = ceph_tcp_recvmsg(con->sock, object + have, left);
+ if (ret <= 0)
+ return ret;
+ con->in_base_pos += ret;
+ }
+ return 1;
+}
+
+
+/*
+ * Read all or part of the connect-side handshake on a new connection
+ */
+static int read_partial_connect(struct ceph_connection *con)
+{
+ int ret, to = 0;
+
+ dout("read_partial_connect %p at %d\n", con, con->in_base_pos);
+
+ /* peer's banner */
+ ret = read_partial(con, &to, strlen(CEPH_BANNER), con->in_banner);
+ if (ret <= 0)
+ goto out;
+ ret = read_partial(con, &to, sizeof(con->actual_peer_addr),
+ &con->actual_peer_addr);
+ if (ret <= 0)
+ goto out;
+ ret = read_partial(con, &to, sizeof(con->peer_addr_for_me),
+ &con->peer_addr_for_me);
+ if (ret <= 0)
+ goto out;
+ ret = read_partial(con, &to, sizeof(con->in_reply), &con->in_reply);
+ if (ret <= 0)
+ goto out;
+
+ dout("read_partial_connect %p connect_seq = %u, global_seq = %u\n",
+ con, le32_to_cpu(con->in_reply.connect_seq),
+ le32_to_cpu(con->in_reply.global_seq));
+out:
+ return ret;
+}
+
+/*
+ * Verify the hello banner looks okay.
+ */
+static int verify_hello(struct ceph_connection *con)
+{
+ if (memcmp(con->in_banner, CEPH_BANNER, strlen(CEPH_BANNER))) {
+ pr_err("connect to %s got bad banner\n",
+ pr_addr(&con->peer_addr.in_addr));
+ con->error_msg = "protocol error, bad banner";
+ return -1;
+ }
+ return 0;
+}
+
+static bool addr_is_blank(struct sockaddr_storage *ss)
+{
+ switch (ss->ss_family) {
+ case AF_INET:
+ return ((struct sockaddr_in *)ss)->sin_addr.s_addr == 0;
+ case AF_INET6:
+ return
+ ((struct sockaddr_in6 *)ss)->sin6_addr.s6_addr32[0] == 0 &&
+ ((struct sockaddr_in6 *)ss)->sin6_addr.s6_addr32[1] == 0 &&
+ ((struct sockaddr_in6 *)ss)->sin6_addr.s6_addr32[2] == 0 &&
+ ((struct sockaddr_in6 *)ss)->sin6_addr.s6_addr32[3] == 0;
+ }
+ return false;
+}
+
+static int addr_port(struct sockaddr_storage *ss)
+{
+ switch (ss->ss_family) {
+ case AF_INET:
+ return ((struct sockaddr_in *)ss)->sin_port;
+ case AF_INET6:
+ return ((struct sockaddr_in6 *)ss)->sin6_port;
+ }
+ return 0;
+}
+
+static void addr_set_port(struct sockaddr_storage *ss, int p)
+{
+ switch (ss->ss_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)ss)->sin_port = htons(p);
+ case AF_INET6:
+ ((struct sockaddr_in6 *)ss)->sin6_port = htons(p);
+ }
+}
+
+/*
+ * Parse an ip[:port] list into an addr array. Use the default
+ * monitor port if a port isn't specified.
+ */
+int ceph_parse_ips(const char *c, const char *end,
+ struct ceph_entity_addr *addr,
+ int max_count, int *count)
+{
+ int i;
+ const char *p = c;
+
+ dout("parse_ips on '%.*s'\n", (int)(end-c), c);
+ for (i = 0; i < max_count; i++) {
+ const char *ipend;
+ struct sockaddr_storage *ss = &addr[i].in_addr;
+ struct sockaddr_in *in4 = (void *)ss;
+ struct sockaddr_in6 *in6 = (void *)ss;
+ int port;
+
+ memset(ss, 0, sizeof(*ss));
+ if (in4_pton(p, end - p, (u8 *)&in4->sin_addr.s_addr,
+ ',', &ipend)) {
+ ss->ss_family = AF_INET;
+ } else if (in6_pton(p, end - p, (u8 *)&in6->sin6_addr.s6_addr,
+ ',', &ipend)) {
+ ss->ss_family = AF_INET6;
+ } else {
+ goto bad;
+ }
+ p = ipend;
+
+ /* port? */
+ if (p < end && *p == ':') {
+ port = 0;
+ p++;
+ while (p < end && *p >= '0' && *p <= '9') {
+ port = (port * 10) + (*p - '0');
+ p++;
+ }
+ if (port > 65535 || port == 0)
+ goto bad;
+ } else {
+ port = CEPH_MON_PORT;
+ }
+
+ addr_set_port(ss, port);
+
+ dout("parse_ips got %s\n", pr_addr(ss));
+
+ if (p == end)
+ break;
+ if (*p != ',')
+ goto bad;
+ p++;
+ }
+
+ if (p != end)
+ goto bad;
+
+ if (count)
+ *count = i + 1;
+ return 0;
+
+bad:
+ pr_err("parse_ips bad ip '%s'\n", c);
+ return -EINVAL;
+}
+
+static int process_connect(struct ceph_connection *con)
+{
+ dout("process_connect on %p tag %d\n", con, (int)con->in_tag);
+
+ if (verify_hello(con) < 0)
+ return -1;
+
+ /*
+ * Make sure the other end is who we wanted. note that the other
+ * end may not yet know their ip address, so if it's 0.0.0.0, give
+ * them the benefit of the doubt.
+ */
+ if (!ceph_entity_addr_is_local(&con->peer_addr,
+ &con->actual_peer_addr) &&
+ !(addr_is_blank(&con->actual_peer_addr.in_addr) &&
+ con->actual_peer_addr.nonce == con->peer_addr.nonce)) {
+ pr_err("wrong peer, want %s/%d, "
+ "got %s/%d, wtf\n",
+ pr_addr(&con->peer_addr.in_addr),
+ con->peer_addr.nonce,
+ pr_addr(&con->actual_peer_addr.in_addr),
+ con->actual_peer_addr.nonce);
+ con->error_msg = "protocol error, wrong peer";
+ return -1;
+ }
+
+ /*
+ * did we learn our address?
+ */
+ if (addr_is_blank(&con->msgr->inst.addr.in_addr)) {
+ int port = addr_port(&con->msgr->inst.addr.in_addr);
+
+ memcpy(&con->msgr->inst.addr.in_addr,
+ &con->peer_addr_for_me.in_addr,
+ sizeof(con->peer_addr_for_me.in_addr));
+ addr_set_port(&con->msgr->inst.addr.in_addr, port);
+ dout("process_connect learned my addr is %s\n",
+ pr_addr(&con->msgr->inst.addr.in_addr));
+ }
+
+ switch (con->in_reply.tag) {
+ case CEPH_MSGR_TAG_BADPROTOVER:
+ dout("process_connect got BADPROTOVER my %d != their %d\n",
+ le32_to_cpu(con->out_connect.protocol_version),
+ le32_to_cpu(con->in_reply.protocol_version));
+ pr_err("%s%lld %s protocol version mismatch,"
+ " my %d != server's %d\n",
+ ENTITY_NAME(con->peer_name),
+ pr_addr(&con->peer_addr.in_addr),
+ le32_to_cpu(con->out_connect.protocol_version),
+ le32_to_cpu(con->in_reply.protocol_version));
+ con->error_msg = "protocol version mismatch";
+ if (con->ops->bad_proto)
+ con->ops->bad_proto(con);
+ reset_connection(con);
+ set_bit(CLOSED, &con->state); /* in case there's queued work */
+ return -1;
+
+
+ case CEPH_MSGR_TAG_RESETSESSION:
+ /*
+ * If we connected with a large connect_seq but the peer
+ * has no record of a session with us (no connection, or
+ * connect_seq == 0), they will send RESETSESION to indicate
+ * that they must have reset their session, and may have
+ * dropped messages.
+ */
+ dout("process_connect got RESET peer seq %u\n",
+ le32_to_cpu(con->in_connect.connect_seq));
+ pr_err("%s%lld %s connection reset\n",
+ ENTITY_NAME(con->peer_name),
+ pr_addr(&con->peer_addr.in_addr));
+ reset_connection(con);
+ prepare_write_connect_retry(con->msgr, con);
+ prepare_read_connect(con);
+
+ /* Tell ceph about it. */
+ pr_info("reset on %s%lld\n", ENTITY_NAME(con->peer_name));
+ if (con->ops->peer_reset)
+ con->ops->peer_reset(con);
+ break;
+
+ case CEPH_MSGR_TAG_RETRY_SESSION:
+ /*
+ * If we sent a smaller connect_seq than the peer has, try
+ * again with a larger value.
+ */
+ dout("process_connect got RETRY my seq = %u, peer_seq = %u\n",
+ le32_to_cpu(con->out_connect.connect_seq),
+ le32_to_cpu(con->in_connect.connect_seq));
+ con->connect_seq = le32_to_cpu(con->in_connect.connect_seq);
+ prepare_write_connect_retry(con->msgr, con);
+ prepare_read_connect(con);
+ break;
+
+ case CEPH_MSGR_TAG_RETRY_GLOBAL:
+ /*
+ * If we sent a smaller global_seq than the peer has, try
+ * again with a larger value.
+ */
+ dout("process_connect got RETRY_GLOBAL my %u, peer_gseq = %u\n",
+ con->peer_global_seq,
+ le32_to_cpu(con->in_connect.global_seq));
+ get_global_seq(con->msgr,
+ le32_to_cpu(con->in_connect.global_seq));
+ prepare_write_connect_retry(con->msgr, con);
+ prepare_read_connect(con);
+ break;
+
+ case CEPH_MSGR_TAG_READY:
+ clear_bit(CONNECTING, &con->state);
+ if (con->in_reply.flags & CEPH_MSG_CONNECT_LOSSY)
+ set_bit(LOSSYRX, &con->state);
+ con->peer_global_seq = le32_to_cpu(con->in_reply.global_seq);
+ con->connect_seq++;
+ dout("process_connect got READY gseq %d cseq %d (%d)\n",
+ con->peer_global_seq,
+ le32_to_cpu(con->in_reply.connect_seq),
+ con->connect_seq);
+ WARN_ON(con->connect_seq !=
+ le32_to_cpu(con->in_reply.connect_seq));
+
+ con->delay = 0; /* reset backoff memory */
+ prepare_read_tag(con);
+ break;
+
+ case CEPH_MSGR_TAG_WAIT:
+ /*
+ * If there is a connection race (we are opening
+ * connections to each other), one of us may just have
+ * to WAIT. This shouldn't happen if we are the
+ * client.
+ */
+ pr_err("process_connect peer connecting WAIT\n");
+
+ default:
+ pr_err("connect protocol error, will retry\n");
+ con->error_msg = "protocol error, garbage tag during connect";
+ return -1;
+ }
+ return 0;
+}
+
+
+/*
+ * read (part of) an ack
+ */
+static int read_partial_ack(struct ceph_connection *con)
+{
+ int to = 0;
+
+ return read_partial(con, &to, sizeof(con->in_temp_ack),
+ &con->in_temp_ack);
+}
+
+
+/*
+ * We can finally discard anything that's been acked.
+ */
+static void process_ack(struct ceph_connection *con)
+{
+ struct ceph_msg *m;
+ u64 ack = le64_to_cpu(con->in_temp_ack);
+ u64 seq;
+
+ mutex_lock(&con->out_mutex);
+ while (!list_empty(&con->out_sent)) {
+ m = list_first_entry(&con->out_sent, struct ceph_msg,
+ list_head);
+ seq = le64_to_cpu(m->hdr.seq);
+ if (seq > ack)
+ break;
+ dout("got ack for seq %llu type %d at %p\n", seq,
+ le16_to_cpu(m->hdr.type), m);
+ ceph_msg_remove(m);
+ }
+ mutex_unlock(&con->out_mutex);
+ prepare_read_tag(con);
+}
+
+
+
+
+
+
+/*
+ * read (part of) a message.
+ */
+static int read_partial_message(struct ceph_connection *con)
+{
+ struct ceph_msg *m = con->in_msg;
+ void *p;
+ int ret;
+ int to, want, left;
+ unsigned front_len, middle_len, data_len, data_off;
+ int datacrc = con->msgr->nocrc;
+
+ dout("read_partial_message con %p msg %p\n", con, m);
+
+ /* header */
+ while (con->in_base_pos < sizeof(con->in_hdr)) {
+ left = sizeof(con->in_hdr) - con->in_base_pos;
+ ret = ceph_tcp_recvmsg(con->sock,
+ (char *)&con->in_hdr + con->in_base_pos,
+ left);
+ if (ret <= 0)
+ return ret;
+ con->in_base_pos += ret;
+ if (con->in_base_pos == sizeof(con->in_hdr)) {
+ u32 crc = crc32c(0, (void *)&con->in_hdr,
+ sizeof(con->in_hdr) - sizeof(con->in_hdr.crc));
+ if (crc != le32_to_cpu(con->in_hdr.crc)) {
+ pr_err("read_partial_message bad hdr "
+ " crc %u != expected %u\n",
+ crc, con->in_hdr.crc);
+ return -EBADMSG;
+ }
+ }
+ }
+
+ front_len = le32_to_cpu(con->in_hdr.front_len);
+ if (front_len > CEPH_MSG_MAX_FRONT_LEN)
+ return -EIO;
+ middle_len = le32_to_cpu(con->in_hdr.middle_len);
+ if (middle_len > CEPH_MSG_MAX_DATA_LEN)
+ return -EIO;
+ data_len = le32_to_cpu(con->in_hdr.data_len);
+ if (data_len > CEPH_MSG_MAX_DATA_LEN)
+ return -EIO;
+
+ /* allocate message? */
+ if (!con->in_msg) {
+ dout("got hdr type %d front %d data %d\n", con->in_hdr.type,
+ con->in_hdr.front_len, con->in_hdr.data_len);
+ con->in_msg = con->ops->alloc_msg(con, &con->in_hdr);
+ if (!con->in_msg) {
+ /* skip this message */
+ dout("alloc_msg returned NULL, skipping message\n");
+ con->in_base_pos = -front_len - middle_len - data_len -
+ sizeof(m->footer);
+ con->in_tag = CEPH_MSGR_TAG_READY;
+ return 0;
+ }
+ if (IS_ERR(con->in_msg)) {
+ ret = PTR_ERR(con->in_msg);
+ con->in_msg = NULL;
+ con->error_msg = "out of memory for incoming message";
+ return ret;
+ }
+ m = con->in_msg;
+ m->front.iov_len = 0; /* haven't read it yet */
+ memcpy(&m->hdr, &con->in_hdr, sizeof(con->in_hdr));
+ }
+
+ /* front */
+ while (m->front.iov_len < front_len) {
+ BUG_ON(m->front.iov_base == NULL);
+ left = front_len - m->front.iov_len;
+ ret = ceph_tcp_recvmsg(con->sock, (char *)m->front.iov_base +
+ m->front.iov_len, left);
+ if (ret <= 0)
+ return ret;
+ m->front.iov_len += ret;
+ if (m->front.iov_len == front_len)
+ con->in_front_crc = crc32c(0, m->front.iov_base,
+ m->front.iov_len);
+ }
+
+ /* middle */
+ while (middle_len > 0 && (!m->middle ||
+ m->middle->vec.iov_len < middle_len)) {
+ if (m->middle == NULL) {
+ ret = -EOPNOTSUPP;
+ if (con->ops->alloc_middle)
+ ret = con->ops->alloc_middle(con, m);
+ if (ret < 0) {
+ dout("alloc_middle failed, skipping payload\n");
+ con->in_base_pos = -middle_len - data_len
+ - sizeof(m->footer);
+ ceph_msg_put(con->in_msg);
+ con->in_msg = NULL;
+ con->in_tag = CEPH_MSGR_TAG_READY;
+ return 0;
+ }
+ m->middle->vec.iov_len = 0;
+ }
+ left = middle_len - m->middle->vec.iov_len;
+ ret = ceph_tcp_recvmsg(con->sock,
+ (char *)m->middle->vec.iov_base +
+ m->middle->vec.iov_len, left);
+ if (ret <= 0)
+ return ret;
+ m->middle->vec.iov_len += ret;
+ if (m->middle->vec.iov_len == middle_len)
+ con->in_middle_crc = crc32c(0, m->middle->vec.iov_base,
+ m->middle->vec.iov_len);
+ }
+
+ /* (page) data */
+ data_off = le16_to_cpu(m->hdr.data_off);
+ if (data_len == 0)
+ goto no_data;
+
+ if (m->nr_pages == 0) {
+ con->in_msg_pos.page = 0;
+ con->in_msg_pos.page_pos = data_off & ~PAGE_MASK;
+ con->in_msg_pos.data_pos = 0;
+ /* find pages for data payload */
+ want = calc_pages_for(data_off & ~PAGE_MASK, data_len);
+ ret = -1;
+ if (con->ops->prepare_pages)
+ ret = con->ops->prepare_pages(con, m, want);
+ if (ret < 0) {
+ dout("%p prepare_pages failed, skipping payload\n", m);
+ con->in_base_pos = -data_len - sizeof(m->footer);
+ ceph_msg_put(con->in_msg);
+ con->in_msg = NULL;
+ con->in_tag = CEPH_MSGR_TAG_READY;
+ return 0;
+ }
+ BUG_ON(m->nr_pages < want);
+ }
+ while (con->in_msg_pos.data_pos < data_len) {
+ left = min((int)(data_len - con->in_msg_pos.data_pos),
+ (int)(PAGE_SIZE - con->in_msg_pos.page_pos));
+ BUG_ON(m->pages == NULL);
+ p = kmap(m->pages[con->in_msg_pos.page]);
+ ret = ceph_tcp_recvmsg(con->sock, p + con->in_msg_pos.page_pos,
+ left);
+ if (ret > 0 && datacrc)
+ con->in_data_crc =
+ crc32c(con->in_data_crc,
+ p + con->in_msg_pos.page_pos, ret);
+ kunmap(m->pages[con->in_msg_pos.page]);
+ if (ret <= 0)
+ return ret;
+ con->in_msg_pos.data_pos += ret;
+ con->in_msg_pos.page_pos += ret;
+ if (con->in_msg_pos.page_pos == PAGE_SIZE) {
+ con->in_msg_pos.page_pos = 0;
+ con->in_msg_pos.page++;
+ }
+ }
+
+no_data:
+ /* footer */
+ to = sizeof(m->hdr) + sizeof(m->footer);
+ while (con->in_base_pos < to) {
+ left = to - con->in_base_pos;
+ ret = ceph_tcp_recvmsg(con->sock, (char *)&m->footer +
+ (con->in_base_pos - sizeof(m->hdr)),
+ left);
+ if (ret <= 0)
+ return ret;
+ con->in_base_pos += ret;
+ }
+ dout("read_partial_message got msg %p %d (%u) + %d (%u) + %d (%u)\n",
+ m, front_len, m->footer.front_crc, middle_len,
+ m->footer.middle_crc, data_len, m->footer.data_crc);
+
+ /* crc ok? */
+ if (con->in_front_crc != le32_to_cpu(m->footer.front_crc)) {
+ pr_err("read_partial_message %p front crc %u != exp. %u\n",
+ m, con->in_front_crc, m->footer.front_crc);
+ return -EBADMSG;
+ }
+ if (con->in_middle_crc != le32_to_cpu(m->footer.middle_crc)) {
+ pr_err("read_partial_message %p middle crc %u != exp %u\n",
+ m, con->in_middle_crc, m->footer.middle_crc);
+ return -EBADMSG;
+ }
+ if (datacrc &&
+ (m->footer.flags & CEPH_MSG_FOOTER_NOCRC) == 0 &&
+ con->in_data_crc != le32_to_cpu(m->footer.data_crc)) {
+ pr_err("read_partial_message %p data crc %u != exp. %u\n", m,
+ con->in_data_crc, le32_to_cpu(m->footer.data_crc));
+ return -EBADMSG;
+ }
+
+ return 1; /* done! */
+}
+
+/*
+ * Process message. This happens in the worker thread. The callback should
+ * be careful not to do anything that waits on other incoming messages or it
+ * may deadlock.
+ */
+static void process_message(struct ceph_connection *con)
+{
+ struct ceph_msg *msg = con->in_msg;
+
+ con->in_msg = NULL;
+
+ /* if first message, set peer_name */
+ if (con->peer_name.type == 0)
+ con->peer_name = msg->hdr.src.name;
+
+ mutex_lock(&con->out_mutex);
+ con->in_seq++;
+ mutex_unlock(&con->out_mutex);
+
+ dout("===== %p %llu from %s%lld %d=%s len %d+%d (%u %u %u) =====\n",
+ msg, le64_to_cpu(msg->hdr.seq),
+ ENTITY_NAME(msg->hdr.src.name),
+ le16_to_cpu(msg->hdr.type),
+ ceph_msg_type_name(le16_to_cpu(msg->hdr.type)),
+ le32_to_cpu(msg->hdr.front_len),
+ le32_to_cpu(msg->hdr.data_len),
+ con->in_front_crc, con->in_middle_crc, con->in_data_crc);
+ con->ops->dispatch(con, msg);
+ prepare_read_tag(con);
+}
+
+
+/*
+ * Write something to the socket. Called in a worker thread when the
+ * socket appears to be writeable and we have something ready to send.
+ */
+static int try_write(struct ceph_connection *con)
+{
+ struct ceph_messenger *msgr = con->msgr;
+ int ret = 1;
+
+ dout("try_write start %p state %lu nref %d\n", con, con->state,
+ atomic_read(&con->nref));
+
+ mutex_lock(&con->out_mutex);
+more:
+ dout("try_write out_kvec_bytes %d\n", con->out_kvec_bytes);
+
+ /* open the socket first? */
+ if (con->sock == NULL) {
+ /*
+ * if we were STANDBY and are reconnecting _this_
+ * connection, bump connect_seq now. Always bump
+ * global_seq.
+ */
+ if (test_and_clear_bit(STANDBY, &con->state))
+ con->connect_seq++;
+
+ prepare_write_connect(msgr, con);
+ prepare_read_connect(con);
+ set_bit(CONNECTING, &con->state);
+
+ con->in_tag = CEPH_MSGR_TAG_READY;
+ dout("try_write initiating connect on %p new state %lu\n",
+ con, con->state);
+ con->sock = ceph_tcp_connect(con);
+ if (IS_ERR(con->sock)) {
+ con->sock = NULL;
+ con->error_msg = "connect error";
+ ret = -1;
+ goto out;
+ }
+ }
+
+more_kvec:
+ /* kvec data queued? */
+ if (con->out_skip) {
+ ret = write_partial_skip(con);
+ if (ret <= 0)
+ goto done;
+ if (ret < 0) {
+ dout("try_write write_partial_skip err %d\n", ret);
+ goto done;
+ }
+ }
+ if (con->out_kvec_left) {
+ ret = write_partial_kvec(con);
+ if (ret <= 0)
+ goto done;
+ if (ret < 0) {
+ dout("try_write write_partial_kvec err %d\n", ret);
+ goto done;
+ }
+ }
+
+ /* msg pages? */
+ if (con->out_msg) {
+ ret = write_partial_msg_pages(con);
+ if (ret == 1)
+ goto more_kvec; /* we need to send the footer, too! */
+ if (ret == 0)
+ goto done;
+ if (ret < 0) {
+ dout("try_write write_partial_msg_pages err %d\n",
+ ret);
+ goto done;
+ }
+ }
+
+ if (!test_bit(CONNECTING, &con->state)) {
+ /* is anything else pending? */
+ if (!list_empty(&con->out_queue)) {
+ prepare_write_message(con);
+ goto more;
+ }
+ if (con->in_seq > con->in_seq_acked) {
+ prepare_write_ack(con);
+ goto more;
+ }
+ if (test_and_clear_bit(KEEPALIVE_PENDING, &con->state)) {
+ prepare_write_keepalive(con);
+ goto more;
+ }
+ }
+
+ /* Nothing to do! */
+ clear_bit(WRITE_PENDING, &con->state);
+ dout("try_write nothing else to write.\n");
+done:
+ ret = 0;
+out:
+ mutex_unlock(&con->out_mutex);
+ dout("try_write done on %p\n", con);
+ return ret;
+}
+
+
+
+/*
+ * Read what we can from the socket.
+ */
+static int try_read(struct ceph_connection *con)
+{
+ struct ceph_messenger *msgr;
+ int ret = -1;
+
+ if (!con->sock)
+ return 0;
+
+ if (test_bit(STANDBY, &con->state))
+ return 0;
+
+ dout("try_read start on %p\n", con);
+ msgr = con->msgr;
+
+more:
+ dout("try_read tag %d in_base_pos %d\n", (int)con->in_tag,
+ con->in_base_pos);
+ if (test_bit(CONNECTING, &con->state)) {
+ dout("try_read connecting\n");
+ ret = read_partial_connect(con);
+ if (ret <= 0)
+ goto done;
+ if (process_connect(con) < 0) {
+ ret = -1;
+ goto out;
+ }
+ goto more;
+ }
+
+ if (con->in_base_pos < 0) {
+ /*
+ * skipping + discarding content.
+ *
+ * FIXME: there must be a better way to do this!
+ */
+ static char buf[1024];
+ int skip = min(1024, -con->in_base_pos);
+ dout("skipping %d / %d bytes\n", skip, -con->in_base_pos);
+ ret = ceph_tcp_recvmsg(con->sock, buf, skip);
+ if (ret <= 0)
+ goto done;
+ con->in_base_pos += ret;
+ if (con->in_base_pos)
+ goto more;
+ }
+ if (con->in_tag == CEPH_MSGR_TAG_READY) {
+ /*
+ * what's next?
+ */
+ ret = ceph_tcp_recvmsg(con->sock, &con->in_tag, 1);
+ if (ret <= 0)
+ goto done;
+ dout("try_read got tag %d\n", (int)con->in_tag);
+ switch (con->in_tag) {
+ case CEPH_MSGR_TAG_MSG:
+ prepare_read_message(con);
+ break;
+ case CEPH_MSGR_TAG_ACK:
+ prepare_read_ack(con);
+ break;
+ case CEPH_MSGR_TAG_CLOSE:
+ set_bit(CLOSED, &con->state); /* fixme */
+ goto done;
+ default:
+ goto bad_tag;
+ }
+ }
+ if (con->in_tag == CEPH_MSGR_TAG_MSG) {
+ ret = read_partial_message(con);
+ if (ret <= 0) {
+ switch (ret) {
+ case -EBADMSG:
+ con->error_msg = "bad crc";
+ ret = -EIO;
+ goto out;
+ case -EIO:
+ con->error_msg = "io error";
+ goto out;
+ default:
+ goto done;
+ }
+ }
+ if (con->in_tag == CEPH_MSGR_TAG_READY)
+ goto more;
+ process_message(con);
+ goto more;
+ }
+ if (con->in_tag == CEPH_MSGR_TAG_ACK) {
+ ret = read_partial_ack(con);
+ if (ret <= 0)
+ goto done;
+ process_ack(con);
+ goto more;
+ }
+
+done:
+ ret = 0;
+out:
+ dout("try_read done on %p\n", con);
+ return ret;
+
+bad_tag:
+ pr_err("try_read bad con->in_tag = %d\n", (int)con->in_tag);
+ con->error_msg = "protocol error, garbage tag";
+ ret = -1;
+ goto out;
+}
+
+
+/*
+ * Atomically queue work on a connection. Bump @con reference to
+ * avoid races with connection teardown.
+ *
+ * There is some trickery going on with QUEUED and BUSY because we
+ * only want a _single_ thread operating on each connection at any
+ * point in time, but we want to use all available CPUs.
+ *
+ * The worker thread only proceeds if it can atomically set BUSY. It
+ * clears QUEUED and does it's thing. When it thinks it's done, it
+ * clears BUSY, then rechecks QUEUED.. if it's set again, it loops
+ * (tries again to set BUSY).
+ *
+ * To queue work, we first set QUEUED, _then_ if BUSY isn't set, we
+ * try to queue work. If that fails (work is already queued, or BUSY)
+ * we give up (work also already being done or is queued) but leave QUEUED
+ * set so that the worker thread will loop if necessary.
+ */
+static void queue_con(struct ceph_connection *con)
+{
+ if (test_bit(DEAD, &con->state)) {
+ dout("queue_con %p ignoring: DEAD\n",
+ con);
+ return;
+ }
+
+ if (!con->ops->get(con)) {
+ dout("queue_con %p ref count 0\n", con);
+ return;
+ }
+
+ set_bit(QUEUED, &con->state);
+ if (test_bit(BUSY, &con->state)) {
+ dout("queue_con %p - already BUSY\n", con);
+ con->ops->put(con);
+ } else if (!queue_work(ceph_msgr_wq, &con->work.work)) {
+ dout("queue_con %p - already queued\n", con);
+ con->ops->put(con);
+ } else {
+ dout("queue_con %p\n", con);
+ }
+}
+
+/*
+ * Do some work on a connection. Drop a connection ref when we're done.
+ */
+static void con_work(struct work_struct *work)
+{
+ struct ceph_connection *con = container_of(work, struct ceph_connection,
+ work.work);
+ int backoff = 0;
+
+more:
+ if (test_and_set_bit(BUSY, &con->state) != 0) {
+ dout("con_work %p BUSY already set\n", con);
+ goto out;
+ }
+ dout("con_work %p start, clearing QUEUED\n", con);
+ clear_bit(QUEUED, &con->state);
+
+ if (test_bit(CLOSED, &con->state)) { /* e.g. if we are replaced */
+ dout("con_work CLOSED\n");
+ con_close_socket(con);
+ goto done;
+ }
+ if (test_and_clear_bit(OPENING, &con->state)) {
+ /* reopen w/ new peer */
+ dout("con_work OPENING\n");
+ con_close_socket(con);
+ }
+
+ if (test_and_clear_bit(SOCK_CLOSED, &con->state) ||
+ try_read(con) < 0 ||
+ try_write(con) < 0) {
+ backoff = 1;
+ ceph_fault(con); /* error/fault path */
+ }
+
+done:
+ clear_bit(BUSY, &con->state);
+ dout("con->state=%lu\n", con->state);
+ if (test_bit(QUEUED, &con->state)) {
+ if (!backoff) {
+ dout("con_work %p QUEUED reset, looping\n", con);
+ goto more;
+ }
+ dout("con_work %p QUEUED reset, but just faulted\n", con);
+ clear_bit(QUEUED, &con->state);
+ }
+ dout("con_work %p done\n", con);
+
+out:
+ con->ops->put(con);
+}
+
+
+/*
+ * Generic error/fault handler. A retry mechanism is used with
+ * exponential backoff
+ */
+static void ceph_fault(struct ceph_connection *con)
+{
+ pr_err("%s%lld %s %s\n", ENTITY_NAME(con->peer_name),
+ pr_addr(&con->peer_addr.in_addr), con->error_msg);
+ dout("fault %p state %lu to peer %s\n",
+ con, con->state, pr_addr(&con->peer_addr.in_addr));
+
+ if (test_bit(LOSSYTX, &con->state)) {
+ dout("fault on LOSSYTX channel\n");
+ goto out;
+ }
+
+ clear_bit(BUSY, &con->state); /* to avoid an improbable race */
+
+ con_close_socket(con);
+ con->in_msg = NULL;
+
+ /* If there are no messages in the queue, place the connection
+ * in a STANDBY state (i.e., don't try to reconnect just yet). */
+ mutex_lock(&con->out_mutex);
+ if (list_empty(&con->out_queue) && !con->out_keepalive_pending) {
+ dout("fault setting STANDBY\n");
+ set_bit(STANDBY, &con->state);
+ mutex_unlock(&con->out_mutex);
+ goto out;
+ }
+
+ /* Requeue anything that hasn't been acked, and retry after a
+ * delay. */
+ list_splice_init(&con->out_sent, &con->out_queue);
+ mutex_unlock(&con->out_mutex);
+
+ if (con->delay == 0)
+ con->delay = BASE_DELAY_INTERVAL;
+ else if (con->delay < MAX_DELAY_INTERVAL)
+ con->delay *= 2;
+
+ /* explicitly schedule work to try to reconnect again later. */
+ dout("fault queueing %p delay %lu\n", con, con->delay);
+ con->ops->get(con);
+ if (queue_delayed_work(ceph_msgr_wq, &con->work,
+ round_jiffies_relative(con->delay)) == 0)
+ con->ops->put(con);
+
+out:
+ if (con->ops->fault)
+ con->ops->fault(con);
+}
+
+
+
+/*
+ * create a new messenger instance
+ */
+struct ceph_messenger *ceph_messenger_create(struct ceph_entity_addr *myaddr)
+{
+ struct ceph_messenger *msgr;
+
+ msgr = kzalloc(sizeof(*msgr), GFP_KERNEL);
+ if (msgr == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ spin_lock_init(&msgr->global_seq_lock);
+
+ /* the zero page is needed if a request is "canceled" while the message
+ * is being written over the socket */
+ msgr->zero_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (!msgr->zero_page) {
+ kfree(msgr);
+ return ERR_PTR(-ENOMEM);
+ }
+ kmap(msgr->zero_page);
+
+ if (myaddr)
+ msgr->inst.addr = *myaddr;
+
+ /* select a random nonce */
+ get_random_bytes(&msgr->inst.addr.nonce,
+ sizeof(msgr->inst.addr.nonce));
+
+ dout("messenger_create %p\n", msgr);
+ return msgr;
+}
+
+void ceph_messenger_destroy(struct ceph_messenger *msgr)
+{
+ dout("destroy %p\n", msgr);
+ kunmap(msgr->zero_page);
+ __free_page(msgr->zero_page);
+ kfree(msgr);
+ dout("destroyed messenger %p\n", msgr);
+}
+
+/*
+ * Queue up an outgoing message on the given connection.
+ */
+void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg)
+{
+ if (test_bit(CLOSED, &con->state)) {
+ dout("con_send %p closed, dropping %p\n", con, msg);
+ ceph_msg_put(msg);
+ return;
+ }
+
+ /* set src+dst */
+ msg->hdr.src = con->msgr->inst;
+ msg->hdr.orig_src = con->msgr->inst;
+ msg->hdr.dst_erank = con->peer_addr.erank;
+
+ /* queue */
+ mutex_lock(&con->out_mutex);
+ BUG_ON(!list_empty(&msg->list_head));
+ list_add_tail(&msg->list_head, &con->out_queue);
+ dout("----- %p to %s%lld %d=%s len %d+%d+%d -----\n", msg,
+ ENTITY_NAME(con->peer_name), le16_to_cpu(msg->hdr.type),
+ ceph_msg_type_name(le16_to_cpu(msg->hdr.type)),
+ le32_to_cpu(msg->hdr.front_len),
+ le32_to_cpu(msg->hdr.middle_len),
+ le32_to_cpu(msg->hdr.data_len));
+ mutex_unlock(&con->out_mutex);
+
+ /* if there wasn't anything waiting to send before, queue
+ * new work */
+ if (test_and_set_bit(WRITE_PENDING, &con->state) == 0)
+ queue_con(con);
+}
+
+/*
+ * Revoke a message that was previously queued for send
+ */
+void ceph_con_revoke(struct ceph_connection *con, struct ceph_msg *msg)
+{
+ mutex_lock(&con->out_mutex);
+ if (!list_empty(&msg->list_head)) {
+ dout("con_revoke %p msg %p\n", con, msg);
+ list_del_init(&msg->list_head);
+ ceph_msg_put(msg);
+ msg->hdr.seq = 0;
+ if (con->out_msg == msg)
+ con->out_msg = NULL;
+ if (con->out_kvec_is_msg) {
+ con->out_skip = con->out_kvec_bytes;
+ con->out_kvec_is_msg = false;
+ }
+ } else {
+ dout("con_revoke %p msg %p - not queued (sent?)\n", con, msg);
+ }
+ mutex_unlock(&con->out_mutex);
+}
+
+/*
+ * Queue a keepalive byte to ensure the tcp connection is alive.
+ */
+void ceph_con_keepalive(struct ceph_connection *con)
+{
+ if (test_and_set_bit(KEEPALIVE_PENDING, &con->state) == 0 &&
+ test_and_set_bit(WRITE_PENDING, &con->state) == 0)
+ queue_con(con);
+}
+
+
+/*
+ * construct a new message with given type, size
+ * the new msg has a ref count of 1.
+ */
+struct ceph_msg *ceph_msg_new(int type, int front_len,
+ int page_len, int page_off, struct page **pages)
+{
+ struct ceph_msg *m;
+
+ m = kmalloc(sizeof(*m), GFP_NOFS);
+ if (m == NULL)
+ goto out;
+ atomic_set(&m->nref, 1);
+ INIT_LIST_HEAD(&m->list_head);
+
+ m->hdr.type = cpu_to_le16(type);
+ m->hdr.front_len = cpu_to_le32(front_len);
+ m->hdr.middle_len = 0;
+ m->hdr.data_len = cpu_to_le32(page_len);
+ m->hdr.data_off = cpu_to_le16(page_off);
+ m->hdr.priority = cpu_to_le16(CEPH_MSG_PRIO_DEFAULT);
+ m->footer.front_crc = 0;
+ m->footer.middle_crc = 0;
+ m->footer.data_crc = 0;
+ m->front_max = front_len;
+ m->front_is_vmalloc = false;
+ m->more_to_follow = false;
+ m->pool = NULL;
+
+ /* front */
+ if (front_len) {
+ if (front_len > PAGE_CACHE_SIZE) {
+ m->front.iov_base = __vmalloc(front_len, GFP_NOFS,
+ PAGE_KERNEL);
+ m->front_is_vmalloc = true;
+ } else {
+ m->front.iov_base = kmalloc(front_len, GFP_NOFS);
+ }
+ if (m->front.iov_base == NULL) {
+ pr_err("msg_new can't allocate %d bytes\n",
+ front_len);
+ goto out2;
+ }
+ } else {
+ m->front.iov_base = NULL;
+ }
+ m->front.iov_len = front_len;
+
+ /* middle */
+ m->middle = NULL;
+
+ /* data */
+ m->nr_pages = calc_pages_for(page_off, page_len);
+ m->pages = pages;
+
+ dout("ceph_msg_new %p page %d~%d -> %d\n", m, page_off, page_len,
+ m->nr_pages);
+ return m;
+
+out2:
+ ceph_msg_put(m);
+out:
+ pr_err("msg_new can't create type %d len %d\n", type, front_len);
+ return ERR_PTR(-ENOMEM);
+}
+
+/*
+ * Generic message allocator, for incoming messages.
+ */
+struct ceph_msg *ceph_alloc_msg(struct ceph_connection *con,
+ struct ceph_msg_header *hdr)
+{
+ int type = le16_to_cpu(hdr->type);
+ int front_len = le32_to_cpu(hdr->front_len);
+ struct ceph_msg *msg = ceph_msg_new(type, front_len, 0, 0, NULL);
+
+ if (!msg) {
+ pr_err("unable to allocate msg type %d len %d\n",
+ type, front_len);
+ return ERR_PTR(-ENOMEM);
+ }
+ return msg;
+}
+
+/*
+ * Allocate "middle" portion of a message, if it is needed and wasn't
+ * allocated by alloc_msg. This allows us to read a small fixed-size
+ * per-type header in the front and then gracefully fail (i.e.,
+ * propagate the error to the caller based on info in the front) when
+ * the middle is too large.
+ */
+int ceph_alloc_middle(struct ceph_connection *con, struct ceph_msg *msg)
+{
+ int type = le16_to_cpu(msg->hdr.type);
+ int middle_len = le32_to_cpu(msg->hdr.middle_len);
+
+ dout("alloc_middle %p type %d %s middle_len %d\n", msg, type,
+ ceph_msg_type_name(type), middle_len);
+ BUG_ON(!middle_len);
+ BUG_ON(msg->middle);
+
+ msg->middle = ceph_buffer_new_alloc(middle_len, GFP_NOFS);
+ if (!msg->middle)
+ return -ENOMEM;
+ return 0;
+}
+
+
+/*
+ * Free a generically kmalloc'd message.
+ */
+void ceph_msg_kfree(struct ceph_msg *m)
+{
+ dout("msg_kfree %p\n", m);
+ if (m->front_is_vmalloc)
+ vfree(m->front.iov_base);
+ else
+ kfree(m->front.iov_base);
+ kfree(m);
+}
+
+/*
+ * Drop a msg ref. Destroy as needed.
+ */
+void ceph_msg_put(struct ceph_msg *m)
+{
+ dout("ceph_msg_put %p %d -> %d\n", m, atomic_read(&m->nref),
+ atomic_read(&m->nref)-1);
+ if (atomic_read(&m->nref) <= 0) {
+ pr_err("bad ceph_msg_put on %p %llu %d=%s %d+%d\n",
+ m, le64_to_cpu(m->hdr.seq),
+ le16_to_cpu(m->hdr.type),
+ ceph_msg_type_name(le16_to_cpu(m->hdr.type)),
+ le32_to_cpu(m->hdr.front_len),
+ le32_to_cpu(m->hdr.data_len));
+ WARN_ON(1);
+ }
+ if (atomic_dec_and_test(&m->nref)) {
+ dout("ceph_msg_put last one on %p\n", m);
+ WARN_ON(!list_empty(&m->list_head));
+
+ /* drop middle, data, if any */
+ if (m->middle) {
+ ceph_buffer_put(m->middle);
+ m->middle = NULL;
+ }
+ m->nr_pages = 0;
+ m->pages = NULL;
+
+ if (m->pool)
+ ceph_msgpool_put(m->pool, m);
+ else
+ ceph_msg_kfree(m);
+ }
+}
diff --git a/fs/ceph/messenger.h b/fs/ceph/messenger.h
new file mode 100644
index 000000000000..dcd98b64dca9
--- /dev/null
+++ b/fs/ceph/messenger.h
@@ -0,0 +1,243 @@
+#ifndef __FS_CEPH_MESSENGER_H
+#define __FS_CEPH_MESSENGER_H
+
+#include <linux/mutex.h>
+#include <linux/net.h>
+#include <linux/radix-tree.h>
+#include <linux/uio.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+
+#include "types.h"
+#include "buffer.h"
+
+struct ceph_msg;
+struct ceph_connection;
+
+extern struct workqueue_struct *ceph_msgr_wq; /* receive work queue */
+
+/*
+ * Ceph defines these callbacks for handling connection events.
+ */
+struct ceph_connection_operations {
+ struct ceph_connection *(*get)(struct ceph_connection *);
+ void (*put)(struct ceph_connection *);
+
+ /* handle an incoming message. */
+ void (*dispatch) (struct ceph_connection *con, struct ceph_msg *m);
+
+ /* protocol version mismatch */
+ void (*bad_proto) (struct ceph_connection *con);
+
+ /* there was some error on the socket (disconnect, whatever) */
+ void (*fault) (struct ceph_connection *con);
+
+ /* a remote host as terminated a message exchange session, and messages
+ * we sent (or they tried to send us) may be lost. */
+ void (*peer_reset) (struct ceph_connection *con);
+
+ struct ceph_msg * (*alloc_msg) (struct ceph_connection *con,
+ struct ceph_msg_header *hdr);
+ int (*alloc_middle) (struct ceph_connection *con,
+ struct ceph_msg *msg);
+ /* an incoming message has a data payload; tell me what pages I
+ * should read the data into. */
+ int (*prepare_pages) (struct ceph_connection *con, struct ceph_msg *m,
+ int want);
+};
+
+extern const char *ceph_name_type_str(int t);
+
+/* use format string %s%d */
+#define ENTITY_NAME(n) ceph_name_type_str((n).type), le64_to_cpu((n).num)
+
+struct ceph_messenger {
+ struct ceph_entity_inst inst; /* my name+address */
+ struct page *zero_page; /* used in certain error cases */
+
+ bool nocrc;
+
+ /*
+ * the global_seq counts connections i (attempt to) initiate
+ * in order to disambiguate certain connect race conditions.
+ */
+ u32 global_seq;
+ spinlock_t global_seq_lock;
+};
+
+/*
+ * a single message. it contains a header (src, dest, message type, etc.),
+ * footer (crc values, mainly), a "front" message body, and possibly a
+ * data payload (stored in some number of pages).
+ */
+struct ceph_msg {
+ struct ceph_msg_header hdr; /* header */
+ struct ceph_msg_footer footer; /* footer */
+ struct kvec front; /* unaligned blobs of message */
+ struct ceph_buffer *middle;
+ struct page **pages; /* data payload. NOT OWNER. */
+ unsigned nr_pages; /* size of page array */
+ struct list_head list_head;
+ atomic_t nref;
+ bool front_is_vmalloc;
+ bool more_to_follow;
+ int front_max;
+
+ struct ceph_msgpool *pool;
+};
+
+struct ceph_msg_pos {
+ int page, page_pos; /* which page; offset in page */
+ int data_pos; /* offset in data payload */
+ int did_page_crc; /* true if we've calculated crc for current page */
+};
+
+/* ceph connection fault delay defaults, for exponential backoff */
+#define BASE_DELAY_INTERVAL (HZ/2)
+#define MAX_DELAY_INTERVAL (5 * 60 * HZ)
+
+/*
+ * ceph_connection state bit flags
+ *
+ * QUEUED and BUSY are used together to ensure that only a single
+ * thread is currently opening, reading or writing data to the socket.
+ */
+#define LOSSYTX 0 /* we can close channel or drop messages on errors */
+#define LOSSYRX 1 /* peer may reset/drop messages */
+#define CONNECTING 2
+#define KEEPALIVE_PENDING 3
+#define WRITE_PENDING 4 /* we have data ready to send */
+#define QUEUED 5 /* there is work queued on this connection */
+#define BUSY 6 /* work is being done */
+#define STANDBY 8 /* no outgoing messages, socket closed. we keep
+ * the ceph_connection around to maintain shared
+ * state with the peer. */
+#define CLOSED 10 /* we've closed the connection */
+#define SOCK_CLOSED 11 /* socket state changed to closed */
+#define REGISTERED 12 /* connection appears in con_tree */
+#define OPENING 13 /* open connection w/ (possibly new) peer */
+#define DEAD 14 /* dead, about to kfree */
+
+/*
+ * A single connection with another host.
+ *
+ * We maintain a queue of outgoing messages, and some session state to
+ * ensure that we can preserve the lossless, ordered delivery of
+ * messages in the case of a TCP disconnect.
+ */
+struct ceph_connection {
+ void *private;
+ atomic_t nref;
+
+ const struct ceph_connection_operations *ops;
+
+ struct ceph_messenger *msgr;
+ struct socket *sock;
+ unsigned long state; /* connection state (see flags above) */
+ const char *error_msg; /* error message, if any */
+
+ struct ceph_entity_addr peer_addr; /* peer address */
+ struct ceph_entity_name peer_name; /* peer name */
+ struct ceph_entity_addr peer_addr_for_me;
+ u32 connect_seq; /* identify the most recent connection
+ attempt for this connection, client */
+ u32 peer_global_seq; /* peer's global seq for this connection */
+
+ /* out queue */
+ struct mutex out_mutex;
+ struct list_head out_queue;
+ struct list_head out_sent; /* sending or sent but unacked */
+ u64 out_seq; /* last message queued for send */
+ u64 out_seq_sent; /* last message sent */
+ bool out_keepalive_pending;
+
+ u64 in_seq, in_seq_acked; /* last message received, acked */
+
+ /* connection negotiation temps */
+ char in_banner[CEPH_BANNER_MAX_LEN];
+ union {
+ struct { /* outgoing connection */
+ struct ceph_msg_connect out_connect;
+ struct ceph_msg_connect_reply in_reply;
+ };
+ struct { /* incoming */
+ struct ceph_msg_connect in_connect;
+ struct ceph_msg_connect_reply out_reply;
+ };
+ };
+ struct ceph_entity_addr actual_peer_addr;
+
+ /* message out temps */
+ struct ceph_msg *out_msg; /* sending message (== tail of
+ out_sent) */
+ struct ceph_msg_pos out_msg_pos;
+
+ struct kvec out_kvec[8], /* sending header/footer data */
+ *out_kvec_cur;
+ int out_kvec_left; /* kvec's left in out_kvec */
+ int out_skip; /* skip this many bytes */
+ int out_kvec_bytes; /* total bytes left */
+ bool out_kvec_is_msg; /* kvec refers to out_msg */
+ int out_more; /* there is more data after the kvecs */
+ __le64 out_temp_ack; /* for writing an ack */
+
+ /* message in temps */
+ struct ceph_msg_header in_hdr;
+ struct ceph_msg *in_msg;
+ struct ceph_msg_pos in_msg_pos;
+ u32 in_front_crc, in_middle_crc, in_data_crc; /* calculated crc */
+
+ char in_tag; /* protocol control byte */
+ int in_base_pos; /* bytes read */
+ __le64 in_temp_ack; /* for reading an ack */
+
+ struct delayed_work work; /* send|recv work */
+ unsigned long delay; /* current delay interval */
+};
+
+
+extern const char *pr_addr(const struct sockaddr_storage *ss);
+extern int ceph_parse_ips(const char *c, const char *end,
+ struct ceph_entity_addr *addr,
+ int max_count, int *count);
+
+
+extern int ceph_msgr_init(void);
+extern void ceph_msgr_exit(void);
+
+extern struct ceph_messenger *ceph_messenger_create(
+ struct ceph_entity_addr *myaddr);
+extern void ceph_messenger_destroy(struct ceph_messenger *);
+
+extern void ceph_con_init(struct ceph_messenger *msgr,
+ struct ceph_connection *con);
+extern void ceph_con_shutdown(struct ceph_connection *con);
+extern void ceph_con_open(struct ceph_connection *con,
+ struct ceph_entity_addr *addr);
+extern void ceph_con_close(struct ceph_connection *con);
+extern void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg);
+extern void ceph_con_revoke(struct ceph_connection *con, struct ceph_msg *msg);
+extern void ceph_con_keepalive(struct ceph_connection *con);
+extern struct ceph_connection *ceph_con_get(struct ceph_connection *con);
+extern void ceph_con_put(struct ceph_connection *con);
+
+extern struct ceph_msg *ceph_msg_new(int type, int front_len,
+ int page_len, int page_off,
+ struct page **pages);
+extern void ceph_msg_kfree(struct ceph_msg *m);
+
+extern struct ceph_msg *ceph_alloc_msg(struct ceph_connection *con,
+ struct ceph_msg_header *hdr);
+extern int ceph_alloc_middle(struct ceph_connection *con, struct ceph_msg *msg);
+
+
+static inline struct ceph_msg *ceph_msg_get(struct ceph_msg *msg)
+{
+ dout("ceph_msg_get %p %d -> %d\n", msg, atomic_read(&msg->nref),
+ atomic_read(&msg->nref)+1);
+ atomic_inc(&msg->nref);
+ return msg;
+}
+extern void ceph_msg_put(struct ceph_msg *msg);
+
+#endif
diff --git a/fs/ceph/mon_client.c b/fs/ceph/mon_client.c
new file mode 100644
index 000000000000..e6e954cac6b9
--- /dev/null
+++ b/fs/ceph/mon_client.c
@@ -0,0 +1,699 @@
+#include "ceph_debug.h"
+
+#include <linux/types.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+
+#include "mon_client.h"
+#include "super.h"
+#include "decode.h"
+
+/*
+ * Interact with Ceph monitor cluster. Handle requests for new map
+ * versions, and periodically resend as needed. Also implement
+ * statfs() and umount().
+ *
+ * A small cluster of Ceph "monitors" are responsible for managing critical
+ * cluster configuration and state information. An odd number (e.g., 3, 5)
+ * of cmon daemons use a modified version of the Paxos part-time parliament
+ * algorithm to manage the MDS map (mds cluster membership), OSD map, and
+ * list of clients who have mounted the file system.
+ *
+ * We maintain an open, active session with a monitor at all times in order to
+ * receive timely MDSMap updates. We periodically send a keepalive byte on the
+ * TCP socket to ensure we detect a failure. If the connection does break, we
+ * randomly hunt for a new monitor. Once the connection is reestablished, we
+ * resend any outstanding requests.
+ */
+
+const static struct ceph_connection_operations mon_con_ops;
+
+/*
+ * Decode a monmap blob (e.g., during mount).
+ */
+struct ceph_monmap *ceph_monmap_decode(void *p, void *end)
+{
+ struct ceph_monmap *m = NULL;
+ int i, err = -EINVAL;
+ struct ceph_fsid fsid;
+ u32 epoch, num_mon;
+ u16 version;
+
+ dout("monmap_decode %p %p len %d\n", p, end, (int)(end-p));
+
+ ceph_decode_16_safe(&p, end, version, bad);
+
+ ceph_decode_need(&p, end, sizeof(fsid) + 2*sizeof(u32), bad);
+ ceph_decode_copy(&p, &fsid, sizeof(fsid));
+ epoch = ceph_decode_32(&p);
+
+ num_mon = ceph_decode_32(&p);
+ ceph_decode_need(&p, end, num_mon*sizeof(m->mon_inst[0]), bad);
+
+ if (num_mon >= CEPH_MAX_MON)
+ goto bad;
+ m = kmalloc(sizeof(*m) + sizeof(m->mon_inst[0])*num_mon, GFP_NOFS);
+ if (m == NULL)
+ return ERR_PTR(-ENOMEM);
+ m->fsid = fsid;
+ m->epoch = epoch;
+ m->num_mon = num_mon;
+ ceph_decode_copy(&p, m->mon_inst, num_mon*sizeof(m->mon_inst[0]));
+
+ dout("monmap_decode epoch %d, num_mon %d\n", m->epoch,
+ m->num_mon);
+ for (i = 0; i < m->num_mon; i++)
+ dout("monmap_decode mon%d is %s\n", i,
+ pr_addr(&m->mon_inst[i].addr.in_addr));
+ return m;
+
+bad:
+ dout("monmap_decode failed with %d\n", err);
+ kfree(m);
+ return ERR_PTR(err);
+}
+
+/*
+ * return true if *addr is included in the monmap.
+ */
+int ceph_monmap_contains(struct ceph_monmap *m, struct ceph_entity_addr *addr)
+{
+ int i;
+
+ for (i = 0; i < m->num_mon; i++)
+ if (ceph_entity_addr_equal(addr, &m->mon_inst[i].addr))
+ return 1;
+ return 0;
+}
+
+/*
+ * Close monitor session, if any.
+ */
+static void __close_session(struct ceph_mon_client *monc)
+{
+ if (monc->con) {
+ dout("__close_session closing mon%d\n", monc->cur_mon);
+ ceph_con_close(monc->con);
+ monc->cur_mon = -1;
+ }
+}
+
+/*
+ * Open a session with a (new) monitor.
+ */
+static int __open_session(struct ceph_mon_client *monc)
+{
+ char r;
+
+ if (monc->cur_mon < 0) {
+ get_random_bytes(&r, 1);
+ monc->cur_mon = r % monc->monmap->num_mon;
+ dout("open_session num=%d r=%d -> mon%d\n",
+ monc->monmap->num_mon, r, monc->cur_mon);
+ monc->sub_sent = 0;
+ monc->sub_renew_after = jiffies; /* i.e., expired */
+ monc->want_next_osdmap = !!monc->want_next_osdmap;
+
+ dout("open_session mon%d opening\n", monc->cur_mon);
+ monc->con->peer_name.type = CEPH_ENTITY_TYPE_MON;
+ monc->con->peer_name.num = cpu_to_le64(monc->cur_mon);
+ ceph_con_open(monc->con,
+ &monc->monmap->mon_inst[monc->cur_mon].addr);
+ } else {
+ dout("open_session mon%d already open\n", monc->cur_mon);
+ }
+ return 0;
+}
+
+static bool __sub_expired(struct ceph_mon_client *monc)
+{
+ return time_after_eq(jiffies, monc->sub_renew_after);
+}
+
+/*
+ * Reschedule delayed work timer.
+ */
+static void __schedule_delayed(struct ceph_mon_client *monc)
+{
+ unsigned delay;
+
+ if (monc->cur_mon < 0 || monc->want_mount || __sub_expired(monc))
+ delay = 10 * HZ;
+ else
+ delay = 20 * HZ;
+ dout("__schedule_delayed after %u\n", delay);
+ schedule_delayed_work(&monc->delayed_work, delay);
+}
+
+/*
+ * Send subscribe request for mdsmap and/or osdmap.
+ */
+static void __send_subscribe(struct ceph_mon_client *monc)
+{
+ dout("__send_subscribe sub_sent=%u exp=%u want_osd=%d\n",
+ (unsigned)monc->sub_sent, __sub_expired(monc),
+ monc->want_next_osdmap);
+ if ((__sub_expired(monc) && !monc->sub_sent) ||
+ monc->want_next_osdmap == 1) {
+ struct ceph_msg *msg;
+ struct ceph_mon_subscribe_item *i;
+ void *p, *end;
+
+ msg = ceph_msg_new(CEPH_MSG_MON_SUBSCRIBE, 64, 0, 0, NULL);
+ if (!msg)
+ return;
+
+ p = msg->front.iov_base;
+ end = p + msg->front.iov_len;
+
+ dout("__send_subscribe to 'mdsmap' %u+\n",
+ (unsigned)monc->have_mdsmap);
+ if (monc->want_next_osdmap) {
+ dout("__send_subscribe to 'osdmap' %u\n",
+ (unsigned)monc->have_osdmap);
+ ceph_encode_32(&p, 2);
+ ceph_encode_string(&p, end, "osdmap", 6);
+ i = p;
+ i->have = cpu_to_le64(monc->have_osdmap);
+ i->onetime = 1;
+ p += sizeof(*i);
+ monc->want_next_osdmap = 2; /* requested */
+ } else {
+ ceph_encode_32(&p, 1);
+ }
+ ceph_encode_string(&p, end, "mdsmap", 6);
+ i = p;
+ i->have = cpu_to_le64(monc->have_mdsmap);
+ i->onetime = 0;
+ p += sizeof(*i);
+
+ msg->front.iov_len = p - msg->front.iov_base;
+ msg->hdr.front_len = cpu_to_le32(msg->front.iov_len);
+ ceph_con_send(monc->con, msg);
+
+ monc->sub_sent = jiffies | 1; /* never 0 */
+ }
+}
+
+static void handle_subscribe_ack(struct ceph_mon_client *monc,
+ struct ceph_msg *msg)
+{
+ unsigned seconds;
+ struct ceph_mon_subscribe_ack *h = msg->front.iov_base;
+
+ if (msg->front.iov_len < sizeof(*h))
+ goto bad;
+ seconds = le32_to_cpu(h->duration);
+
+ mutex_lock(&monc->mutex);
+ if (monc->hunting) {
+ pr_info("mon%d %s session established\n",
+ monc->cur_mon, pr_addr(&monc->con->peer_addr.in_addr));
+ monc->hunting = false;
+ }
+ dout("handle_subscribe_ack after %d seconds\n", seconds);
+ monc->sub_renew_after = monc->sub_sent + (seconds >> 1)*HZ - 1;
+ monc->sub_sent = 0;
+ mutex_unlock(&monc->mutex);
+ return;
+bad:
+ pr_err("got corrupt subscribe-ack msg\n");
+}
+
+/*
+ * Keep track of which maps we have
+ */
+int ceph_monc_got_mdsmap(struct ceph_mon_client *monc, u32 got)
+{
+ mutex_lock(&monc->mutex);
+ monc->have_mdsmap = got;
+ mutex_unlock(&monc->mutex);
+ return 0;
+}
+
+int ceph_monc_got_osdmap(struct ceph_mon_client *monc, u32 got)
+{
+ mutex_lock(&monc->mutex);
+ monc->have_osdmap = got;
+ monc->want_next_osdmap = 0;
+ mutex_unlock(&monc->mutex);
+ return 0;
+}
+
+/*
+ * Register interest in the next osdmap
+ */
+void ceph_monc_request_next_osdmap(struct ceph_mon_client *monc)
+{
+ dout("request_next_osdmap have %u\n", monc->have_osdmap);
+ mutex_lock(&monc->mutex);
+ if (!monc->want_next_osdmap)
+ monc->want_next_osdmap = 1;
+ if (monc->want_next_osdmap < 2)
+ __send_subscribe(monc);
+ mutex_unlock(&monc->mutex);
+}
+
+
+/*
+ * mount
+ */
+static void __request_mount(struct ceph_mon_client *monc)
+{
+ struct ceph_msg *msg;
+ struct ceph_client_mount *h;
+ int err;
+
+ dout("__request_mount\n");
+ err = __open_session(monc);
+ if (err)
+ return;
+ msg = ceph_msg_new(CEPH_MSG_CLIENT_MOUNT, sizeof(*h), 0, 0, NULL);
+ if (IS_ERR(msg))
+ return;
+ h = msg->front.iov_base;
+ h->monhdr.have_version = 0;
+ h->monhdr.session_mon = cpu_to_le16(-1);
+ h->monhdr.session_mon_tid = 0;
+ ceph_con_send(monc->con, msg);
+}
+
+int ceph_monc_request_mount(struct ceph_mon_client *monc)
+{
+ if (!monc->con) {
+ monc->con = kmalloc(sizeof(*monc->con), GFP_KERNEL);
+ if (!monc->con)
+ return -ENOMEM;
+ ceph_con_init(monc->client->msgr, monc->con);
+ monc->con->private = monc;
+ monc->con->ops = &mon_con_ops;
+ }
+
+ mutex_lock(&monc->mutex);
+ __request_mount(monc);
+ __schedule_delayed(monc);
+ mutex_unlock(&monc->mutex);
+ return 0;
+}
+
+/*
+ * The monitor responds with mount ack indicate mount success. The
+ * included client ticket allows the client to talk to MDSs and OSDs.
+ */
+static void handle_mount_ack(struct ceph_mon_client *monc, struct ceph_msg *msg)
+{
+ struct ceph_client *client = monc->client;
+ struct ceph_monmap *monmap = NULL, *old = monc->monmap;
+ void *p, *end;
+ s32 result;
+ u32 len;
+ s64 cnum;
+ int err = -EINVAL;
+
+ if (client->whoami >= 0) {
+ dout("handle_mount_ack - already mounted\n");
+ return;
+ }
+
+ mutex_lock(&monc->mutex);
+
+ dout("handle_mount_ack\n");
+ p = msg->front.iov_base;
+ end = p + msg->front.iov_len;
+
+ ceph_decode_64_safe(&p, end, cnum, bad);
+ ceph_decode_32_safe(&p, end, result, bad);
+ ceph_decode_32_safe(&p, end, len, bad);
+ if (result) {
+ pr_err("mount denied: %.*s (%d)\n", len, (char *)p,
+ result);
+ err = result;
+ goto out;
+ }
+ p += len;
+
+ ceph_decode_32_safe(&p, end, len, bad);
+ ceph_decode_need(&p, end, len, bad);
+ monmap = ceph_monmap_decode(p, p + len);
+ if (IS_ERR(monmap)) {
+ pr_err("problem decoding monmap, %d\n",
+ (int)PTR_ERR(monmap));
+ err = -EINVAL;
+ goto out;
+ }
+ p += len;
+
+ client->monc.monmap = monmap;
+ kfree(old);
+
+ client->signed_ticket = NULL;
+ client->signed_ticket_len = 0;
+
+ monc->want_mount = false;
+
+ client->whoami = cnum;
+ client->msgr->inst.name.type = CEPH_ENTITY_TYPE_CLIENT;
+ client->msgr->inst.name.num = cpu_to_le64(cnum);
+ pr_info("client%lld fsid " FSID_FORMAT "\n",
+ client->whoami, PR_FSID(&client->monc.monmap->fsid));
+
+ ceph_debugfs_client_init(client);
+ __send_subscribe(monc);
+
+ err = 0;
+ goto out;
+
+bad:
+ pr_err("error decoding mount_ack message\n");
+out:
+ client->mount_err = err;
+ mutex_unlock(&monc->mutex);
+ wake_up(&client->mount_wq);
+}
+
+
+
+
+/*
+ * statfs
+ */
+static void handle_statfs_reply(struct ceph_mon_client *monc,
+ struct ceph_msg *msg)
+{
+ struct ceph_mon_statfs_request *req;
+ struct ceph_mon_statfs_reply *reply = msg->front.iov_base;
+ u64 tid;
+
+ if (msg->front.iov_len != sizeof(*reply))
+ goto bad;
+ tid = le64_to_cpu(reply->tid);
+ dout("handle_statfs_reply %p tid %llu\n", msg, tid);
+
+ mutex_lock(&monc->mutex);
+ req = radix_tree_lookup(&monc->statfs_request_tree, tid);
+ if (req) {
+ *req->buf = reply->st;
+ req->result = 0;
+ }
+ mutex_unlock(&monc->mutex);
+ if (req)
+ complete(&req->completion);
+ return;
+
+bad:
+ pr_err("corrupt statfs reply, no tid\n");
+}
+
+/*
+ * (re)send a statfs request
+ */
+static int send_statfs(struct ceph_mon_client *monc,
+ struct ceph_mon_statfs_request *req)
+{
+ struct ceph_msg *msg;
+ struct ceph_mon_statfs *h;
+ int err;
+
+ dout("send_statfs tid %llu\n", req->tid);
+ err = __open_session(monc);
+ if (err)
+ return err;
+ msg = ceph_msg_new(CEPH_MSG_STATFS, sizeof(*h), 0, 0, NULL);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+ req->request = msg;
+ h = msg->front.iov_base;
+ h->monhdr.have_version = 0;
+ h->monhdr.session_mon = cpu_to_le16(-1);
+ h->monhdr.session_mon_tid = 0;
+ h->fsid = monc->monmap->fsid;
+ h->tid = cpu_to_le64(req->tid);
+ ceph_con_send(monc->con, msg);
+ return 0;
+}
+
+/*
+ * Do a synchronous statfs().
+ */
+int ceph_monc_do_statfs(struct ceph_mon_client *monc, struct ceph_statfs *buf)
+{
+ struct ceph_mon_statfs_request req;
+ int err;
+
+ req.buf = buf;
+ init_completion(&req.completion);
+
+ /* allocate memory for reply */
+ err = ceph_msgpool_resv(&monc->msgpool_statfs_reply, 1);
+ if (err)
+ return err;
+
+ /* register request */
+ mutex_lock(&monc->mutex);
+ req.tid = ++monc->last_tid;
+ req.last_attempt = jiffies;
+ req.delay = BASE_DELAY_INTERVAL;
+ if (radix_tree_insert(&monc->statfs_request_tree, req.tid, &req) < 0) {
+ mutex_unlock(&monc->mutex);
+ pr_err("ENOMEM in do_statfs\n");
+ return -ENOMEM;
+ }
+ monc->num_statfs_requests++;
+ mutex_unlock(&monc->mutex);
+
+ /* send request and wait */
+ err = send_statfs(monc, &req);
+ if (!err)
+ err = wait_for_completion_interruptible(&req.completion);
+
+ mutex_lock(&monc->mutex);
+ radix_tree_delete(&monc->statfs_request_tree, req.tid);
+ monc->num_statfs_requests--;
+ ceph_msgpool_resv(&monc->msgpool_statfs_reply, -1);
+ mutex_unlock(&monc->mutex);
+
+ if (!err)
+ err = req.result;
+ return err;
+}
+
+/*
+ * Resend pending statfs requests.
+ */
+static void __resend_statfs(struct ceph_mon_client *monc)
+{
+ u64 next_tid = 0;
+ int got;
+ int did = 0;
+ struct ceph_mon_statfs_request *req;
+
+ while (1) {
+ got = radix_tree_gang_lookup(&monc->statfs_request_tree,
+ (void **)&req,
+ next_tid, 1);
+ if (got == 0)
+ break;
+ did++;
+ next_tid = req->tid + 1;
+
+ send_statfs(monc, req);
+ }
+}
+
+/*
+ * Delayed work. If we haven't mounted yet, retry. Otherwise,
+ * renew/retry subscription as needed (in case it is timing out, or we
+ * got an ENOMEM). And keep the monitor connection alive.
+ */
+static void delayed_work(struct work_struct *work)
+{
+ struct ceph_mon_client *monc =
+ container_of(work, struct ceph_mon_client, delayed_work.work);
+
+ dout("monc delayed_work\n");
+ mutex_lock(&monc->mutex);
+ if (monc->want_mount) {
+ __request_mount(monc);
+ } else {
+ if (monc->hunting) {
+ __close_session(monc);
+ __open_session(monc); /* continue hunting */
+ } else {
+ ceph_con_keepalive(monc->con);
+ }
+ }
+ __send_subscribe(monc);
+ __schedule_delayed(monc);
+ mutex_unlock(&monc->mutex);
+}
+
+int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl)
+{
+ int err = 0;
+
+ dout("init\n");
+ memset(monc, 0, sizeof(*monc));
+ monc->client = cl;
+ monc->monmap = NULL;
+ mutex_init(&monc->mutex);
+
+ monc->con = NULL;
+
+ /* msg pools */
+ err = ceph_msgpool_init(&monc->msgpool_mount_ack, 4096, 1, false);
+ if (err < 0)
+ goto out;
+ err = ceph_msgpool_init(&monc->msgpool_subscribe_ack,
+ sizeof(struct ceph_mon_subscribe_ack), 1, false);
+ if (err < 0)
+ goto out;
+ err = ceph_msgpool_init(&monc->msgpool_statfs_reply,
+ sizeof(struct ceph_mon_statfs_reply), 0, false);
+ if (err < 0)
+ goto out;
+
+ monc->cur_mon = -1;
+ monc->hunting = false; /* not really */
+ monc->sub_renew_after = jiffies;
+ monc->sub_sent = 0;
+
+ INIT_DELAYED_WORK(&monc->delayed_work, delayed_work);
+ INIT_RADIX_TREE(&monc->statfs_request_tree, GFP_NOFS);
+ monc->num_statfs_requests = 0;
+ monc->last_tid = 0;
+
+ monc->have_mdsmap = 0;
+ monc->have_osdmap = 0;
+ monc->want_next_osdmap = 1;
+ monc->want_mount = true;
+out:
+ return err;
+}
+
+void ceph_monc_stop(struct ceph_mon_client *monc)
+{
+ dout("stop\n");
+ cancel_delayed_work_sync(&monc->delayed_work);
+
+ mutex_lock(&monc->mutex);
+ __close_session(monc);
+ if (monc->con) {
+ monc->con->private = NULL;
+ monc->con->ops->put(monc->con);
+ monc->con = NULL;
+ }
+ mutex_unlock(&monc->mutex);
+
+ ceph_msgpool_destroy(&monc->msgpool_mount_ack);
+ ceph_msgpool_destroy(&monc->msgpool_subscribe_ack);
+ ceph_msgpool_destroy(&monc->msgpool_statfs_reply);
+
+ kfree(monc->monmap);
+}
+
+
+/*
+ * handle incoming message
+ */
+static void dispatch(struct ceph_connection *con, struct ceph_msg *msg)
+{
+ struct ceph_mon_client *monc = con->private;
+ int type = le16_to_cpu(msg->hdr.type);
+
+ if (!monc)
+ return;
+
+ switch (type) {
+ case CEPH_MSG_CLIENT_MOUNT_ACK:
+ handle_mount_ack(monc, msg);
+ break;
+
+ case CEPH_MSG_MON_SUBSCRIBE_ACK:
+ handle_subscribe_ack(monc, msg);
+ break;
+
+ case CEPH_MSG_STATFS_REPLY:
+ handle_statfs_reply(monc, msg);
+ break;
+
+ case CEPH_MSG_MDS_MAP:
+ ceph_mdsc_handle_map(&monc->client->mdsc, msg);
+ break;
+
+ case CEPH_MSG_OSD_MAP:
+ ceph_osdc_handle_map(&monc->client->osdc, msg);
+ break;
+
+ default:
+ pr_err("received unknown message type %d %s\n", type,
+ ceph_msg_type_name(type));
+ }
+ ceph_msg_put(msg);
+}
+
+/*
+ * Allocate memory for incoming message
+ */
+static struct ceph_msg *mon_alloc_msg(struct ceph_connection *con,
+ struct ceph_msg_header *hdr)
+{
+ struct ceph_mon_client *monc = con->private;
+ int type = le16_to_cpu(hdr->type);
+ int front = le32_to_cpu(hdr->front_len);
+
+ switch (type) {
+ case CEPH_MSG_CLIENT_MOUNT_ACK:
+ return ceph_msgpool_get(&monc->msgpool_mount_ack, front);
+ case CEPH_MSG_MON_SUBSCRIBE_ACK:
+ return ceph_msgpool_get(&monc->msgpool_subscribe_ack, front);
+ case CEPH_MSG_STATFS_REPLY:
+ return ceph_msgpool_get(&monc->msgpool_statfs_reply, front);
+ }
+ return ceph_alloc_msg(con, hdr);
+}
+
+/*
+ * If the monitor connection resets, pick a new monitor and resubmit
+ * any pending requests.
+ */
+static void mon_fault(struct ceph_connection *con)
+{
+ struct ceph_mon_client *monc = con->private;
+
+ if (!monc)
+ return;
+
+ dout("mon_fault\n");
+ mutex_lock(&monc->mutex);
+ if (!con->private)
+ goto out;
+
+ if (monc->con && !monc->hunting)
+ pr_info("mon%d %s session lost, "
+ "hunting for new mon\n", monc->cur_mon,
+ pr_addr(&monc->con->peer_addr.in_addr));
+
+ __close_session(monc);
+ if (!monc->hunting) {
+ /* start hunting */
+ monc->hunting = true;
+ if (__open_session(monc) == 0) {
+ __send_subscribe(monc);
+ __resend_statfs(monc);
+ }
+ } else {
+ /* already hunting, let's wait a bit */
+ __schedule_delayed(monc);
+ }
+out:
+ mutex_unlock(&monc->mutex);
+}
+
+const static struct ceph_connection_operations mon_con_ops = {
+ .get = ceph_con_get,
+ .put = ceph_con_put,
+ .dispatch = dispatch,
+ .fault = mon_fault,
+ .alloc_msg = mon_alloc_msg,
+ .alloc_middle = ceph_alloc_middle,
+};
diff --git a/fs/ceph/mon_client.h b/fs/ceph/mon_client.h
new file mode 100644
index 000000000000..5258c5693b03
--- /dev/null
+++ b/fs/ceph/mon_client.h
@@ -0,0 +1,109 @@
+#ifndef _FS_CEPH_MON_CLIENT_H
+#define _FS_CEPH_MON_CLIENT_H
+
+#include <linux/completion.h>
+#include <linux/radix-tree.h>
+
+#include "messenger.h"
+#include "msgpool.h"
+
+struct ceph_client;
+struct ceph_mount_args;
+
+/*
+ * The monitor map enumerates the set of all monitors.
+ */
+struct ceph_monmap {
+ struct ceph_fsid fsid;
+ u32 epoch;
+ u32 num_mon;
+ struct ceph_entity_inst mon_inst[0];
+};
+
+struct ceph_mon_client;
+struct ceph_mon_statfs_request;
+
+
+/*
+ * Generic mechanism for resending monitor requests.
+ */
+typedef void (*ceph_monc_request_func_t)(struct ceph_mon_client *monc,
+ int newmon);
+
+/* a pending monitor request */
+struct ceph_mon_request {
+ struct ceph_mon_client *monc;
+ struct delayed_work delayed_work;
+ unsigned long delay;
+ ceph_monc_request_func_t do_request;
+};
+
+/*
+ * statfs() is done a bit differently because we need to get data back
+ * to the caller
+ */
+struct ceph_mon_statfs_request {
+ u64 tid;
+ int result;
+ struct ceph_statfs *buf;
+ struct completion completion;
+ unsigned long last_attempt, delay; /* jiffies */
+ struct ceph_msg *request; /* original request */
+};
+
+struct ceph_mon_client {
+ struct ceph_client *client;
+ struct ceph_monmap *monmap;
+
+ struct mutex mutex;
+ struct delayed_work delayed_work;
+
+ bool hunting;
+ int cur_mon; /* last monitor i contacted */
+ unsigned long sub_sent, sub_renew_after;
+ struct ceph_connection *con;
+
+ /* msg pools */
+ struct ceph_msgpool msgpool_mount_ack;
+ struct ceph_msgpool msgpool_subscribe_ack;
+ struct ceph_msgpool msgpool_statfs_reply;
+
+ /* pending statfs requests */
+ struct radix_tree_root statfs_request_tree;
+ int num_statfs_requests;
+ u64 last_tid;
+
+ /* mds/osd map or mount requests */
+ bool want_mount;
+ int want_next_osdmap; /* 1 = want, 2 = want+asked */
+ u32 have_osdmap, have_mdsmap;
+
+ struct dentry *debugfs_file;
+};
+
+extern struct ceph_monmap *ceph_monmap_decode(void *p, void *end);
+extern int ceph_monmap_contains(struct ceph_monmap *m,
+ struct ceph_entity_addr *addr);
+
+extern int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl);
+extern void ceph_monc_stop(struct ceph_mon_client *monc);
+
+/*
+ * The model here is to indicate that we need a new map of at least
+ * epoch @want, and also call in when we receive a map. We will
+ * periodically rerequest the map from the monitor cluster until we
+ * get what we want.
+ */
+extern int ceph_monc_got_mdsmap(struct ceph_mon_client *monc, u32 have);
+extern int ceph_monc_got_osdmap(struct ceph_mon_client *monc, u32 have);
+
+extern void ceph_monc_request_next_osdmap(struct ceph_mon_client *monc);
+
+extern int ceph_monc_request_mount(struct ceph_mon_client *monc);
+
+extern int ceph_monc_do_statfs(struct ceph_mon_client *monc,
+ struct ceph_statfs *buf);
+
+
+
+#endif
diff --git a/fs/ceph/msgpool.c b/fs/ceph/msgpool.c
new file mode 100644
index 000000000000..7599b3382076
--- /dev/null
+++ b/fs/ceph/msgpool.c
@@ -0,0 +1,181 @@
+#include "ceph_debug.h"
+
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+
+#include "msgpool.h"
+
+/*
+ * We use msg pools to preallocate memory for messages we expect to
+ * receive over the wire, to avoid getting ourselves into OOM
+ * conditions at unexpected times. We take use a few different
+ * strategies:
+ *
+ * - for request/response type interactions, we preallocate the
+ * memory needed for the response when we generate the request.
+ *
+ * - for messages we can receive at any time from the MDS, we preallocate
+ * a pool of messages we can re-use.
+ *
+ * - for writeback, we preallocate some number of messages to use for
+ * requests and their replies, so that we always make forward
+ * progress.
+ *
+ * The msgpool behaves like a mempool_t, but keeps preallocated
+ * ceph_msgs strung together on a list_head instead of using a pointer
+ * vector. This avoids vector reallocation when we adjust the number
+ * of preallocated items (which happens frequently).
+ */
+
+
+/*
+ * Allocate or release as necessary to meet our target pool size.
+ */
+static int __fill_msgpool(struct ceph_msgpool *pool)
+{
+ struct ceph_msg *msg;
+
+ while (pool->num < pool->min) {
+ dout("fill_msgpool %p %d/%d allocating\n", pool, pool->num,
+ pool->min);
+ spin_unlock(&pool->lock);
+ msg = ceph_msg_new(0, pool->front_len, 0, 0, NULL);
+ spin_lock(&pool->lock);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+ msg->pool = pool;
+ list_add(&msg->list_head, &pool->msgs);
+ pool->num++;
+ }
+ while (pool->num > pool->min) {
+ msg = list_first_entry(&pool->msgs, struct ceph_msg, list_head);
+ dout("fill_msgpool %p %d/%d releasing %p\n", pool, pool->num,
+ pool->min, msg);
+ list_del_init(&msg->list_head);
+ pool->num--;
+ ceph_msg_kfree(msg);
+ }
+ return 0;
+}
+
+int ceph_msgpool_init(struct ceph_msgpool *pool,
+ int front_len, int min, bool blocking)
+{
+ int ret;
+
+ dout("msgpool_init %p front_len %d min %d\n", pool, front_len, min);
+ spin_lock_init(&pool->lock);
+ pool->front_len = front_len;
+ INIT_LIST_HEAD(&pool->msgs);
+ pool->num = 0;
+ pool->min = min;
+ pool->blocking = blocking;
+ init_waitqueue_head(&pool->wait);
+
+ spin_lock(&pool->lock);
+ ret = __fill_msgpool(pool);
+ spin_unlock(&pool->lock);
+ return ret;
+}
+
+void ceph_msgpool_destroy(struct ceph_msgpool *pool)
+{
+ dout("msgpool_destroy %p\n", pool);
+ spin_lock(&pool->lock);
+ pool->min = 0;
+ __fill_msgpool(pool);
+ spin_unlock(&pool->lock);
+}
+
+int ceph_msgpool_resv(struct ceph_msgpool *pool, int delta)
+{
+ int ret;
+
+ spin_lock(&pool->lock);
+ dout("msgpool_resv %p delta %d\n", pool, delta);
+ pool->min += delta;
+ ret = __fill_msgpool(pool);
+ spin_unlock(&pool->lock);
+ return ret;
+}
+
+struct ceph_msg *ceph_msgpool_get(struct ceph_msgpool *pool, int front_len)
+{
+ wait_queue_t wait;
+ struct ceph_msg *msg;
+
+ if (front_len && front_len > pool->front_len) {
+ pr_err("msgpool_get pool %p need front %d, pool size is %d\n",
+ pool, front_len, pool->front_len);
+ WARN_ON(1);
+
+ /* try to alloc a fresh message */
+ msg = ceph_msg_new(0, front_len, 0, 0, NULL);
+ if (!IS_ERR(msg))
+ return msg;
+ }
+
+ if (!front_len)
+ front_len = pool->front_len;
+
+ if (pool->blocking) {
+ /* mempool_t behavior; first try to alloc */
+ msg = ceph_msg_new(0, front_len, 0, 0, NULL);
+ if (!IS_ERR(msg))
+ return msg;
+ }
+
+ while (1) {
+ spin_lock(&pool->lock);
+ if (likely(pool->num)) {
+ msg = list_entry(pool->msgs.next, struct ceph_msg,
+ list_head);
+ list_del_init(&msg->list_head);
+ pool->num--;
+ dout("msgpool_get %p got %p, now %d/%d\n", pool, msg,
+ pool->num, pool->min);
+ spin_unlock(&pool->lock);
+ return msg;
+ }
+ pr_err("msgpool_get %p now %d/%d, %s\n", pool, pool->num,
+ pool->min, pool->blocking ? "waiting" : "failing");
+ spin_unlock(&pool->lock);
+
+ if (!pool->blocking) {
+ WARN_ON(1);
+
+ /* maybe we can allocate it now? */
+ msg = ceph_msg_new(0, front_len, 0, 0, NULL);
+ if (!IS_ERR(msg))
+ return msg;
+
+ return ERR_PTR(-ENOMEM);
+ }
+
+ init_wait(&wait);
+ prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE);
+ schedule();
+ finish_wait(&pool->wait, &wait);
+ }
+}
+
+void ceph_msgpool_put(struct ceph_msgpool *pool, struct ceph_msg *msg)
+{
+ spin_lock(&pool->lock);
+ if (pool->num < pool->min) {
+ ceph_msg_get(msg); /* retake a single ref */
+ list_add(&msg->list_head, &pool->msgs);
+ pool->num++;
+ dout("msgpool_put %p reclaim %p, now %d/%d\n", pool, msg,
+ pool->num, pool->min);
+ spin_unlock(&pool->lock);
+ wake_up(&pool->wait);
+ } else {
+ dout("msgpool_put %p drop %p, at %d/%d\n", pool, msg,
+ pool->num, pool->min);
+ spin_unlock(&pool->lock);
+ ceph_msg_kfree(msg);
+ }
+}
diff --git a/fs/ceph/msgpool.h b/fs/ceph/msgpool.h
new file mode 100644
index 000000000000..bc834bfcd720
--- /dev/null
+++ b/fs/ceph/msgpool.h
@@ -0,0 +1,27 @@
+#ifndef _FS_CEPH_MSGPOOL
+#define _FS_CEPH_MSGPOOL
+
+#include "messenger.h"
+
+/*
+ * we use memory pools for preallocating messages we may receive, to
+ * avoid unexpected OOM conditions.
+ */
+struct ceph_msgpool {
+ spinlock_t lock;
+ int front_len; /* preallocated payload size */
+ struct list_head msgs; /* msgs in the pool; each has 1 ref */
+ int num, min; /* cur, min # msgs in the pool */
+ bool blocking;
+ wait_queue_head_t wait;
+};
+
+extern int ceph_msgpool_init(struct ceph_msgpool *pool,
+ int front_len, int size, bool blocking);
+extern void ceph_msgpool_destroy(struct ceph_msgpool *pool);
+extern int ceph_msgpool_resv(struct ceph_msgpool *, int delta);
+extern struct ceph_msg *ceph_msgpool_get(struct ceph_msgpool *,
+ int front_len);
+extern void ceph_msgpool_put(struct ceph_msgpool *, struct ceph_msg *);
+
+#endif
diff --git a/fs/ceph/msgr.h b/fs/ceph/msgr.h
new file mode 100644
index 000000000000..9abc879e25b1
--- /dev/null
+++ b/fs/ceph/msgr.h
@@ -0,0 +1,158 @@
+#ifndef __MSGR_H
+#define __MSGR_H
+
+/*
+ * Data types for message passing layer used by Ceph.
+ */
+
+#define CEPH_MON_PORT 6789 /* default monitor port */
+
+/*
+ * client-side processes will try to bind to ports in this
+ * range, simply for the benefit of tools like nmap or wireshark
+ * that would like to identify the protocol.
+ */
+#define CEPH_PORT_FIRST 6789
+#define CEPH_PORT_START 6800 /* non-monitors start here */
+#define CEPH_PORT_LAST 6900
+
+/*
+ * tcp connection banner. include a protocol version. and adjust
+ * whenever the wire protocol changes. try to keep this string length
+ * constant.
+ */
+#define CEPH_BANNER "ceph v022"
+#define CEPH_BANNER_MAX_LEN 30
+
+
+/*
+ * Rollover-safe type and comparator for 32-bit sequence numbers.
+ * Comparator returns -1, 0, or 1.
+ */
+typedef __u32 ceph_seq_t;
+
+static inline __s32 ceph_seq_cmp(__u32 a, __u32 b)
+{
+ return (__s32)a - (__s32)b;
+}
+
+
+/*
+ * entity_name -- logical name for a process participating in the
+ * network, e.g. 'mds0' or 'osd3'.
+ */
+struct ceph_entity_name {
+ __u8 type; /* CEPH_ENTITY_TYPE_* */
+ __le64 num;
+} __attribute__ ((packed));
+
+#define CEPH_ENTITY_TYPE_MON 1
+#define CEPH_ENTITY_TYPE_MDS 2
+#define CEPH_ENTITY_TYPE_OSD 3
+#define CEPH_ENTITY_TYPE_CLIENT 4
+#define CEPH_ENTITY_TYPE_ADMIN 5
+
+/*
+ * entity_addr -- network address
+ */
+struct ceph_entity_addr {
+ __le32 erank; /* entity's rank in process */
+ __le32 nonce; /* unique id for process (e.g. pid) */
+ struct sockaddr_storage in_addr;
+} __attribute__ ((packed));
+
+static inline bool ceph_entity_addr_is_local(const struct ceph_entity_addr *a,
+ const struct ceph_entity_addr *b)
+{
+ return a->nonce == b->nonce &&
+ memcmp(&a->in_addr, &b->in_addr, sizeof(a->in_addr)) == 0;
+}
+
+static inline bool ceph_entity_addr_equal(const struct ceph_entity_addr *a,
+ const struct ceph_entity_addr *b)
+{
+ return memcmp(a, b, sizeof(*a)) == 0;
+}
+
+struct ceph_entity_inst {
+ struct ceph_entity_name name;
+ struct ceph_entity_addr addr;
+} __attribute__ ((packed));
+
+
+/* used by message exchange protocol */
+#define CEPH_MSGR_TAG_READY 1 /* server->client: ready for messages */
+#define CEPH_MSGR_TAG_RESETSESSION 2 /* server->client: reset, try again */
+#define CEPH_MSGR_TAG_WAIT 3 /* server->client: wait for racing
+ incoming connection */
+#define CEPH_MSGR_TAG_RETRY_SESSION 4 /* server->client + cseq: try again
+ with higher cseq */
+#define CEPH_MSGR_TAG_RETRY_GLOBAL 5 /* server->client + gseq: try again
+ with higher gseq */
+#define CEPH_MSGR_TAG_CLOSE 6 /* closing pipe */
+#define CEPH_MSGR_TAG_MSG 7 /* message */
+#define CEPH_MSGR_TAG_ACK 8 /* message ack */
+#define CEPH_MSGR_TAG_KEEPALIVE 9 /* just a keepalive byte! */
+#define CEPH_MSGR_TAG_BADPROTOVER 10 /* bad protocol version */
+
+
+/*
+ * connection negotiation
+ */
+struct ceph_msg_connect {
+ __le32 host_type; /* CEPH_ENTITY_TYPE_* */
+ __le32 global_seq; /* count connections initiated by this host */
+ __le32 connect_seq; /* count connections initiated in this session */
+ __le32 protocol_version;
+ __u8 flags; /* CEPH_MSG_CONNECT_* */
+} __attribute__ ((packed));
+
+struct ceph_msg_connect_reply {
+ __u8 tag;
+ __le32 global_seq;
+ __le32 connect_seq;
+ __le32 protocol_version;
+ __u8 flags;
+} __attribute__ ((packed));
+
+#define CEPH_MSG_CONNECT_LOSSY 1 /* messages i send may be safely dropped */
+
+
+/*
+ * message header
+ */
+struct ceph_msg_header {
+ __le64 seq; /* message seq# for this session */
+ __le16 type; /* message type */
+ __le16 priority; /* priority. higher value == higher priority */
+ __le16 version; /* version of message encoding */
+
+ __le32 front_len; /* bytes in main payload */
+ __le32 middle_len;/* bytes in middle payload */
+ __le32 data_len; /* bytes of data payload */
+ __le16 data_off; /* sender: include full offset;
+ receiver: mask against ~PAGE_MASK */
+
+ struct ceph_entity_inst src, orig_src;
+ __le32 dst_erank;
+ __le32 crc; /* header crc32c */
+} __attribute__ ((packed));
+
+#define CEPH_MSG_PRIO_LOW 64
+#define CEPH_MSG_PRIO_DEFAULT 127
+#define CEPH_MSG_PRIO_HIGH 196
+#define CEPH_MSG_PRIO_HIGHEST 255
+
+/*
+ * follows data payload
+ */
+struct ceph_msg_footer {
+ __le32 front_crc, middle_crc, data_crc;
+ __u8 flags;
+} __attribute__ ((packed));
+
+#define CEPH_MSG_FOOTER_COMPLETE (1<<0) /* msg wasn't aborted */
+#define CEPH_MSG_FOOTER_NOCRC (1<<1) /* no data crc */
+
+
+#endif
diff --git a/fs/ceph/osd_client.c b/fs/ceph/osd_client.c
new file mode 100644
index 000000000000..0a254054a82a
--- /dev/null
+++ b/fs/ceph/osd_client.c
@@ -0,0 +1,1308 @@
+#include "ceph_debug.h"
+
+#include <linux/err.h>
+#include <linux/highmem.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include "super.h"
+#include "osd_client.h"
+#include "messenger.h"
+#include "decode.h"
+
+const static struct ceph_connection_operations osd_con_ops;
+
+static void kick_requests(struct ceph_osd_client *osdc, struct ceph_osd *osd);
+
+/*
+ * Implement client access to distributed object storage cluster.
+ *
+ * All data objects are stored within a cluster/cloud of OSDs, or
+ * "object storage devices." (Note that Ceph OSDs have _nothing_ to
+ * do with the T10 OSD extensions to SCSI.) Ceph OSDs are simply
+ * remote daemons serving up and coordinating consistent and safe
+ * access to storage.
+ *
+ * Cluster membership and the mapping of data objects onto storage devices
+ * are described by the osd map.
+ *
+ * We keep track of pending OSD requests (read, write), resubmit
+ * requests to different OSDs when the cluster topology/data layout
+ * change, or retry the affected requests when the communications
+ * channel with an OSD is reset.
+ */
+
+/*
+ * calculate the mapping of a file extent onto an object, and fill out the
+ * request accordingly. shorten extent as necessary if it crosses an
+ * object boundary.
+ *
+ * fill osd op in request message.
+ */
+static void calc_layout(struct ceph_osd_client *osdc,
+ struct ceph_vino vino, struct ceph_file_layout *layout,
+ u64 off, u64 *plen,
+ struct ceph_osd_request *req)
+{
+ struct ceph_osd_request_head *reqhead = req->r_request->front.iov_base;
+ struct ceph_osd_op *op = (void *)(reqhead + 1);
+ u64 orig_len = *plen;
+ u64 objoff, objlen; /* extent in object */
+ u64 bno;
+
+ reqhead->snapid = cpu_to_le64(vino.snap);
+
+ /* object extent? */
+ ceph_calc_file_object_mapping(layout, off, plen, &bno,
+ &objoff, &objlen);
+ if (*plen < orig_len)
+ dout(" skipping last %llu, final file extent %llu~%llu\n",
+ orig_len - *plen, off, *plen);
+
+ sprintf(req->r_oid, "%llx.%08llx", vino.ino, bno);
+ req->r_oid_len = strlen(req->r_oid);
+
+ op->extent.offset = cpu_to_le64(objoff);
+ op->extent.length = cpu_to_le64(objlen);
+ req->r_num_pages = calc_pages_for(off, *plen);
+
+ dout("calc_layout %s (%d) %llu~%llu (%d pages)\n",
+ req->r_oid, req->r_oid_len, objoff, objlen, req->r_num_pages);
+}
+
+
+/*
+ * requests
+ */
+void ceph_osdc_put_request(struct ceph_osd_request *req)
+{
+ dout("osdc put_request %p %d -> %d\n", req, atomic_read(&req->r_ref),
+ atomic_read(&req->r_ref)-1);
+ BUG_ON(atomic_read(&req->r_ref) <= 0);
+ if (atomic_dec_and_test(&req->r_ref)) {
+ if (req->r_request)
+ ceph_msg_put(req->r_request);
+ if (req->r_reply)
+ ceph_msg_put(req->r_reply);
+ if (req->r_own_pages)
+ ceph_release_page_vector(req->r_pages,
+ req->r_num_pages);
+ ceph_put_snap_context(req->r_snapc);
+ if (req->r_mempool)
+ mempool_free(req, req->r_osdc->req_mempool);
+ else
+ kfree(req);
+ }
+}
+
+/*
+ * build new request AND message, calculate layout, and adjust file
+ * extent as needed.
+ *
+ * if the file was recently truncated, we include information about its
+ * old and new size so that the object can be updated appropriately. (we
+ * avoid synchronously deleting truncated objects because it's slow.)
+ *
+ * if @do_sync, include a 'startsync' command so that the osd will flush
+ * data quickly.
+ */
+struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
+ struct ceph_file_layout *layout,
+ struct ceph_vino vino,
+ u64 off, u64 *plen,
+ int opcode, int flags,
+ struct ceph_snap_context *snapc,
+ int do_sync,
+ u32 truncate_seq,
+ u64 truncate_size,
+ struct timespec *mtime,
+ bool use_mempool, int num_reply)
+{
+ struct ceph_osd_request *req;
+ struct ceph_msg *msg;
+ struct ceph_osd_request_head *head;
+ struct ceph_osd_op *op;
+ void *p;
+ int do_trunc = truncate_seq && (off + *plen > truncate_size);
+ int num_op = 1 + do_sync + do_trunc;
+ size_t msg_size = sizeof(*head) + num_op*sizeof(*op);
+ int err, i;
+ u64 prevofs;
+
+ if (use_mempool) {
+ req = mempool_alloc(osdc->req_mempool, GFP_NOFS);
+ memset(req, 0, sizeof(*req));
+ } else {
+ req = kzalloc(sizeof(*req), GFP_NOFS);
+ }
+ if (req == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ err = ceph_msgpool_resv(&osdc->msgpool_op_reply, num_reply);
+ if (err) {
+ ceph_osdc_put_request(req);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ req->r_osdc = osdc;
+ req->r_mempool = use_mempool;
+ atomic_set(&req->r_ref, 1);
+ init_completion(&req->r_completion);
+ init_completion(&req->r_safe_completion);
+ INIT_LIST_HEAD(&req->r_unsafe_item);
+ req->r_flags = flags;
+
+ WARN_ON((flags & (CEPH_OSD_FLAG_READ|CEPH_OSD_FLAG_WRITE)) == 0);
+
+ /* create message; allow space for oid */
+ msg_size += 40;
+ if (snapc)
+ msg_size += sizeof(u64) * snapc->num_snaps;
+ if (use_mempool)
+ msg = ceph_msgpool_get(&osdc->msgpool_op, 0);
+ else
+ msg = ceph_msg_new(CEPH_MSG_OSD_OP, msg_size, 0, 0, NULL);
+ if (IS_ERR(msg)) {
+ ceph_msgpool_resv(&osdc->msgpool_op_reply, num_reply);
+ ceph_osdc_put_request(req);
+ return ERR_PTR(PTR_ERR(msg));
+ }
+ msg->hdr.type = cpu_to_le16(CEPH_MSG_OSD_OP);
+ memset(msg->front.iov_base, 0, msg->front.iov_len);
+ head = msg->front.iov_base;
+ op = (void *)(head + 1);
+ p = (void *)(op + num_op);
+
+ req->r_request = msg;
+ req->r_snapc = ceph_get_snap_context(snapc);
+
+ head->client_inc = cpu_to_le32(1); /* always, for now. */
+ head->flags = cpu_to_le32(flags);
+ if (flags & CEPH_OSD_FLAG_WRITE)
+ ceph_encode_timespec(&head->mtime, mtime);
+ head->num_ops = cpu_to_le16(num_op);
+ op->op = cpu_to_le16(opcode);
+
+ /* calculate max write size */
+ calc_layout(osdc, vino, layout, off, plen, req);
+ req->r_file_layout = *layout; /* keep a copy */
+
+ if (flags & CEPH_OSD_FLAG_WRITE) {
+ req->r_request->hdr.data_off = cpu_to_le16(off);
+ req->r_request->hdr.data_len = cpu_to_le32(*plen);
+ op->payload_len = cpu_to_le32(*plen);
+ }
+
+ /* fill in oid */
+ head->object_len = cpu_to_le32(req->r_oid_len);
+ memcpy(p, req->r_oid, req->r_oid_len);
+ p += req->r_oid_len;
+
+ /* additional ops */
+ if (do_trunc) {
+ op++;
+ op->op = cpu_to_le16(opcode == CEPH_OSD_OP_READ ?
+ CEPH_OSD_OP_MASKTRUNC : CEPH_OSD_OP_SETTRUNC);
+ op->trunc.truncate_seq = cpu_to_le32(truncate_seq);
+ prevofs = le64_to_cpu((op-1)->extent.offset);
+ op->trunc.truncate_size = cpu_to_le64(truncate_size -
+ (off-prevofs));
+ }
+ if (do_sync) {
+ op++;
+ op->op = cpu_to_le16(CEPH_OSD_OP_STARTSYNC);
+ }
+ if (snapc) {
+ head->snap_seq = cpu_to_le64(snapc->seq);
+ head->num_snaps = cpu_to_le32(snapc->num_snaps);
+ for (i = 0; i < snapc->num_snaps; i++) {
+ put_unaligned_le64(snapc->snaps[i], p);
+ p += sizeof(u64);
+ }
+ }
+
+ BUG_ON(p > msg->front.iov_base + msg->front.iov_len);
+ return req;
+}
+
+/*
+ * We keep osd requests in an rbtree, sorted by ->r_tid.
+ */
+static void __insert_request(struct ceph_osd_client *osdc,
+ struct ceph_osd_request *new)
+{
+ struct rb_node **p = &osdc->requests.rb_node;
+ struct rb_node *parent = NULL;
+ struct ceph_osd_request *req = NULL;
+
+ while (*p) {
+ parent = *p;
+ req = rb_entry(parent, struct ceph_osd_request, r_node);
+ if (new->r_tid < req->r_tid)
+ p = &(*p)->rb_left;
+ else if (new->r_tid > req->r_tid)
+ p = &(*p)->rb_right;
+ else
+ BUG();
+ }
+
+ rb_link_node(&new->r_node, parent, p);
+ rb_insert_color(&new->r_node, &osdc->requests);
+}
+
+static struct ceph_osd_request *__lookup_request(struct ceph_osd_client *osdc,
+ u64 tid)
+{
+ struct ceph_osd_request *req;
+ struct rb_node *n = osdc->requests.rb_node;
+
+ while (n) {
+ req = rb_entry(n, struct ceph_osd_request, r_node);
+ if (tid < req->r_tid)
+ n = n->rb_left;
+ else if (tid > req->r_tid)
+ n = n->rb_right;
+ else
+ return req;
+ }
+ return NULL;
+}
+
+static struct ceph_osd_request *
+__lookup_request_ge(struct ceph_osd_client *osdc,
+ u64 tid)
+{
+ struct ceph_osd_request *req;
+ struct rb_node *n = osdc->requests.rb_node;
+
+ while (n) {
+ req = rb_entry(n, struct ceph_osd_request, r_node);
+ if (tid < req->r_tid) {
+ if (!n->rb_left)
+ return req;
+ n = n->rb_left;
+ } else if (tid > req->r_tid) {
+ n = n->rb_right;
+ } else {
+ return req;
+ }
+ }
+ return NULL;
+}
+
+
+/*
+ * If the osd connection drops, we need to resubmit all requests.
+ */
+static void osd_reset(struct ceph_connection *con)
+{
+ struct ceph_osd *osd = con->private;
+ struct ceph_osd_client *osdc;
+
+ if (!osd)
+ return;
+ dout("osd_reset osd%d\n", osd->o_osd);
+ osdc = osd->o_osdc;
+ osd->o_incarnation++;
+ down_read(&osdc->map_sem);
+ kick_requests(osdc, osd);
+ up_read(&osdc->map_sem);
+}
+
+/*
+ * Track open sessions with osds.
+ */
+static struct ceph_osd *create_osd(struct ceph_osd_client *osdc)
+{
+ struct ceph_osd *osd;
+
+ osd = kzalloc(sizeof(*osd), GFP_NOFS);
+ if (!osd)
+ return NULL;
+
+ atomic_set(&osd->o_ref, 1);
+ osd->o_osdc = osdc;
+ INIT_LIST_HEAD(&osd->o_requests);
+ osd->o_incarnation = 1;
+
+ ceph_con_init(osdc->client->msgr, &osd->o_con);
+ osd->o_con.private = osd;
+ osd->o_con.ops = &osd_con_ops;
+ osd->o_con.peer_name.type = CEPH_ENTITY_TYPE_OSD;
+ return osd;
+}
+
+static struct ceph_osd *get_osd(struct ceph_osd *osd)
+{
+ if (atomic_inc_not_zero(&osd->o_ref)) {
+ dout("get_osd %p %d -> %d\n", osd, atomic_read(&osd->o_ref)-1,
+ atomic_read(&osd->o_ref));
+ return osd;
+ } else {
+ dout("get_osd %p FAIL\n", osd);
+ return NULL;
+ }
+}
+
+static void put_osd(struct ceph_osd *osd)
+{
+ dout("put_osd %p %d -> %d\n", osd, atomic_read(&osd->o_ref),
+ atomic_read(&osd->o_ref) - 1);
+ if (atomic_dec_and_test(&osd->o_ref)) {
+ ceph_con_shutdown(&osd->o_con);
+ kfree(osd);
+ }
+}
+
+/*
+ * remove an osd from our map
+ */
+static void remove_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd)
+{
+ dout("remove_osd %p\n", osd);
+ BUG_ON(!list_empty(&osd->o_requests));
+ rb_erase(&osd->o_node, &osdc->osds);
+ ceph_con_close(&osd->o_con);
+ put_osd(osd);
+}
+
+/*
+ * reset osd connect
+ */
+static int reset_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd)
+{
+ int ret = 0;
+
+ dout("reset_osd %p osd%d\n", osd, osd->o_osd);
+ if (list_empty(&osd->o_requests)) {
+ remove_osd(osdc, osd);
+ } else {
+ ceph_con_close(&osd->o_con);
+ ceph_con_open(&osd->o_con, &osdc->osdmap->osd_addr[osd->o_osd]);
+ osd->o_incarnation++;
+ }
+ return ret;
+}
+
+static void __insert_osd(struct ceph_osd_client *osdc, struct ceph_osd *new)
+{
+ struct rb_node **p = &osdc->osds.rb_node;
+ struct rb_node *parent = NULL;
+ struct ceph_osd *osd = NULL;
+
+ while (*p) {
+ parent = *p;
+ osd = rb_entry(parent, struct ceph_osd, o_node);
+ if (new->o_osd < osd->o_osd)
+ p = &(*p)->rb_left;
+ else if (new->o_osd > osd->o_osd)
+ p = &(*p)->rb_right;
+ else
+ BUG();
+ }
+
+ rb_link_node(&new->o_node, parent, p);
+ rb_insert_color(&new->o_node, &osdc->osds);
+}
+
+static struct ceph_osd *__lookup_osd(struct ceph_osd_client *osdc, int o)
+{
+ struct ceph_osd *osd;
+ struct rb_node *n = osdc->osds.rb_node;
+
+ while (n) {
+ osd = rb_entry(n, struct ceph_osd, o_node);
+ if (o < osd->o_osd)
+ n = n->rb_left;
+ else if (o > osd->o_osd)
+ n = n->rb_right;
+ else
+ return osd;
+ }
+ return NULL;
+}
+
+
+/*
+ * Register request, assign tid. If this is the first request, set up
+ * the timeout event.
+ */
+static void register_request(struct ceph_osd_client *osdc,
+ struct ceph_osd_request *req)
+{
+ struct ceph_osd_request_head *head = req->r_request->front.iov_base;
+
+ mutex_lock(&osdc->request_mutex);
+ req->r_tid = ++osdc->last_tid;
+ head->tid = cpu_to_le64(req->r_tid);
+
+ dout("register_request %p tid %lld\n", req, req->r_tid);
+ __insert_request(osdc, req);
+ ceph_osdc_get_request(req);
+ osdc->num_requests++;
+
+ req->r_timeout_stamp =
+ jiffies + osdc->client->mount_args.osd_timeout*HZ;
+
+ if (osdc->num_requests == 1) {
+ osdc->timeout_tid = req->r_tid;
+ dout(" timeout on tid %llu at %lu\n", req->r_tid,
+ req->r_timeout_stamp);
+ schedule_delayed_work(&osdc->timeout_work,
+ round_jiffies_relative(req->r_timeout_stamp - jiffies));
+ }
+ mutex_unlock(&osdc->request_mutex);
+}
+
+/*
+ * called under osdc->request_mutex
+ */
+static void __unregister_request(struct ceph_osd_client *osdc,
+ struct ceph_osd_request *req)
+{
+ dout("__unregister_request %p tid %lld\n", req, req->r_tid);
+ rb_erase(&req->r_node, &osdc->requests);
+ osdc->num_requests--;
+
+ if (req->r_osd) {
+ /* make sure the original request isn't in flight. */
+ ceph_con_revoke(&req->r_osd->o_con, req->r_request);
+
+ list_del_init(&req->r_osd_item);
+ if (list_empty(&req->r_osd->o_requests))
+ remove_osd(osdc, req->r_osd);
+ req->r_osd = NULL;
+ }
+
+ ceph_osdc_put_request(req);
+
+ if (req->r_tid == osdc->timeout_tid) {
+ if (osdc->num_requests == 0) {
+ dout("no requests, canceling timeout\n");
+ osdc->timeout_tid = 0;
+ cancel_delayed_work(&osdc->timeout_work);
+ } else {
+ req = rb_entry(rb_first(&osdc->requests),
+ struct ceph_osd_request, r_node);
+ osdc->timeout_tid = req->r_tid;
+ dout("rescheduled timeout on tid %llu at %lu\n",
+ req->r_tid, req->r_timeout_stamp);
+ schedule_delayed_work(&osdc->timeout_work,
+ round_jiffies_relative(req->r_timeout_stamp -
+ jiffies));
+ }
+ }
+}
+
+/*
+ * Cancel a previously queued request message
+ */
+static void __cancel_request(struct ceph_osd_request *req)
+{
+ if (req->r_sent) {
+ ceph_con_revoke(&req->r_osd->o_con, req->r_request);
+ req->r_sent = 0;
+ }
+}
+
+/*
+ * Pick an osd (the first 'up' osd in the pg), allocate the osd struct
+ * (as needed), and set the request r_osd appropriately. If there is
+ * no up osd, set r_osd to NULL.
+ *
+ * Return 0 if unchanged, 1 if changed, or negative on error.
+ *
+ * Caller should hold map_sem for read and request_mutex.
+ */
+static int __map_osds(struct ceph_osd_client *osdc,
+ struct ceph_osd_request *req)
+{
+ struct ceph_osd_request_head *reqhead = req->r_request->front.iov_base;
+ union ceph_pg pgid;
+ int o = -1;
+ int err;
+ struct ceph_osd *newosd = NULL;
+
+ dout("map_osds %p tid %lld\n", req, req->r_tid);
+ err = ceph_calc_object_layout(&reqhead->layout, req->r_oid,
+ &req->r_file_layout, osdc->osdmap);
+ if (err)
+ return err;
+ pgid.pg64 = le64_to_cpu(reqhead->layout.ol_pgid);
+ o = ceph_calc_pg_primary(osdc->osdmap, pgid);
+
+ if ((req->r_osd && req->r_osd->o_osd == o &&
+ req->r_sent >= req->r_osd->o_incarnation) ||
+ (req->r_osd == NULL && o == -1))
+ return 0; /* no change */
+
+ dout("map_osds tid %llu pgid %llx pool %d osd%d (was osd%d)\n",
+ req->r_tid, pgid.pg64, pgid.pg.pool, o,
+ req->r_osd ? req->r_osd->o_osd : -1);
+
+ if (req->r_osd) {
+ __cancel_request(req);
+ list_del_init(&req->r_osd_item);
+ if (list_empty(&req->r_osd->o_requests)) {
+ /* try to re-use r_osd if possible */
+ newosd = get_osd(req->r_osd);
+ remove_osd(osdc, newosd);
+ }
+ req->r_osd = NULL;
+ }
+
+ req->r_osd = __lookup_osd(osdc, o);
+ if (!req->r_osd && o >= 0) {
+ if (newosd) {
+ req->r_osd = newosd;
+ newosd = NULL;
+ } else {
+ err = -ENOMEM;
+ req->r_osd = create_osd(osdc);
+ if (!req->r_osd)
+ goto out;
+ }
+
+ dout("map_osds osd %p is osd%d\n", req->r_osd, o);
+ req->r_osd->o_osd = o;
+ req->r_osd->o_con.peer_name.num = cpu_to_le64(o);
+ __insert_osd(osdc, req->r_osd);
+
+ ceph_con_open(&req->r_osd->o_con, &osdc->osdmap->osd_addr[o]);
+ }
+
+ if (req->r_osd)
+ list_add(&req->r_osd_item, &req->r_osd->o_requests);
+ err = 1; /* osd changed */
+
+out:
+ if (newosd)
+ put_osd(newosd);
+ return err;
+}
+
+/*
+ * caller should hold map_sem (for read) and request_mutex
+ */
+static int __send_request(struct ceph_osd_client *osdc,
+ struct ceph_osd_request *req)
+{
+ struct ceph_osd_request_head *reqhead;
+ int err;
+
+ err = __map_osds(osdc, req);
+ if (err < 0)
+ return err;
+ if (req->r_osd == NULL) {
+ dout("send_request %p no up osds in pg\n", req);
+ ceph_monc_request_next_osdmap(&osdc->client->monc);
+ return 0;
+ }
+
+ dout("send_request %p tid %llu to osd%d flags %d\n",
+ req, req->r_tid, req->r_osd->o_osd, req->r_flags);
+
+ reqhead = req->r_request->front.iov_base;
+ reqhead->osdmap_epoch = cpu_to_le32(osdc->osdmap->epoch);
+ reqhead->flags |= cpu_to_le32(req->r_flags); /* e.g., RETRY */
+ reqhead->reassert_version = req->r_reassert_version;
+
+ req->r_timeout_stamp = jiffies+osdc->client->mount_args.osd_timeout*HZ;
+
+ ceph_msg_get(req->r_request); /* send consumes a ref */
+ ceph_con_send(&req->r_osd->o_con, req->r_request);
+ req->r_sent = req->r_osd->o_incarnation;
+ return 0;
+}
+
+/*
+ * Timeout callback, called every N seconds when 1 or more osd
+ * requests has been active for more than N seconds. When this
+ * happens, we ping all OSDs with requests who have timed out to
+ * ensure any communications channel reset is detected. Reset the
+ * request timeouts another N seconds in the future as we go.
+ * Reschedule the timeout event another N seconds in future (unless
+ * there are no open requests).
+ */
+static void handle_timeout(struct work_struct *work)
+{
+ struct ceph_osd_client *osdc =
+ container_of(work, struct ceph_osd_client, timeout_work.work);
+ struct ceph_osd_request *req;
+ struct ceph_osd *osd;
+ unsigned long timeout = osdc->client->mount_args.osd_timeout * HZ;
+ unsigned long next_timeout = timeout + jiffies;
+ struct rb_node *p;
+
+ dout("timeout\n");
+ down_read(&osdc->map_sem);
+
+ ceph_monc_request_next_osdmap(&osdc->client->monc);
+
+ mutex_lock(&osdc->request_mutex);
+ for (p = rb_first(&osdc->requests); p; p = rb_next(p)) {
+ req = rb_entry(p, struct ceph_osd_request, r_node);
+
+ if (req->r_resend) {
+ int err;
+
+ dout("osdc resending prev failed %lld\n", req->r_tid);
+ err = __send_request(osdc, req);
+ if (err)
+ dout("osdc failed again on %lld\n", req->r_tid);
+ else
+ req->r_resend = false;
+ continue;
+ }
+ }
+ for (p = rb_first(&osdc->osds); p; p = rb_next(p)) {
+ osd = rb_entry(p, struct ceph_osd, o_node);
+ if (list_empty(&osd->o_requests))
+ continue;
+ req = list_first_entry(&osd->o_requests,
+ struct ceph_osd_request, r_osd_item);
+ if (time_before(jiffies, req->r_timeout_stamp))
+ continue;
+
+ dout(" tid %llu (at least) timed out on osd%d\n",
+ req->r_tid, osd->o_osd);
+ req->r_timeout_stamp = next_timeout;
+ ceph_con_keepalive(&osd->o_con);
+ }
+
+ if (osdc->timeout_tid)
+ schedule_delayed_work(&osdc->timeout_work,
+ round_jiffies_relative(timeout));
+
+ mutex_unlock(&osdc->request_mutex);
+
+ up_read(&osdc->map_sem);
+}
+
+/*
+ * handle osd op reply. either call the callback if it is specified,
+ * or do the completion to wake up the waiting thread.
+ */
+static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg)
+{
+ struct ceph_osd_reply_head *rhead = msg->front.iov_base;
+ struct ceph_osd_request *req;
+ u64 tid;
+ int numops, object_len, flags;
+
+ if (msg->front.iov_len < sizeof(*rhead))
+ goto bad;
+ tid = le64_to_cpu(rhead->tid);
+ numops = le32_to_cpu(rhead->num_ops);
+ object_len = le32_to_cpu(rhead->object_len);
+ if (msg->front.iov_len != sizeof(*rhead) + object_len +
+ numops * sizeof(struct ceph_osd_op))
+ goto bad;
+ dout("handle_reply %p tid %llu\n", msg, tid);
+
+ /* lookup */
+ mutex_lock(&osdc->request_mutex);
+ req = __lookup_request(osdc, tid);
+ if (req == NULL) {
+ dout("handle_reply tid %llu dne\n", tid);
+ mutex_unlock(&osdc->request_mutex);
+ return;
+ }
+ ceph_osdc_get_request(req);
+ flags = le32_to_cpu(rhead->flags);
+
+ if (req->r_reply) {
+ /*
+ * once we see the message has been received, we don't
+ * need a ref (which is only needed for revoking
+ * pages)
+ */
+ ceph_msg_put(req->r_reply);
+ req->r_reply = NULL;
+ }
+
+ if (!req->r_got_reply) {
+ unsigned bytes;
+
+ req->r_result = le32_to_cpu(rhead->result);
+ bytes = le32_to_cpu(msg->hdr.data_len);
+ dout("handle_reply result %d bytes %d\n", req->r_result,
+ bytes);
+ if (req->r_result == 0)
+ req->r_result = bytes;
+
+ /* in case this is a write and we need to replay, */
+ req->r_reassert_version = rhead->reassert_version;
+
+ req->r_got_reply = 1;
+ } else if ((flags & CEPH_OSD_FLAG_ONDISK) == 0) {
+ dout("handle_reply tid %llu dup ack\n", tid);
+ goto done;
+ }
+
+ dout("handle_reply tid %llu flags %d\n", tid, flags);
+
+ /* either this is a read, or we got the safe response */
+ if ((flags & CEPH_OSD_FLAG_ONDISK) ||
+ ((flags & CEPH_OSD_FLAG_WRITE) == 0))
+ __unregister_request(osdc, req);
+
+ mutex_unlock(&osdc->request_mutex);
+
+ if (req->r_callback)
+ req->r_callback(req, msg);
+ else
+ complete(&req->r_completion);
+
+ if (flags & CEPH_OSD_FLAG_ONDISK) {
+ if (req->r_safe_callback)
+ req->r_safe_callback(req, msg);
+ complete(&req->r_safe_completion); /* fsync waiter */
+ }
+
+done:
+ ceph_osdc_put_request(req);
+ return;
+
+bad:
+ pr_err("corrupt osd_op_reply got %d %d expected %d\n",
+ (int)msg->front.iov_len, le32_to_cpu(msg->hdr.front_len),
+ (int)sizeof(*rhead));
+}
+
+
+/*
+ * Resubmit osd requests whose osd or osd address has changed. Request
+ * a new osd map if osds are down, or we are otherwise unable to determine
+ * how to direct a request.
+ *
+ * Close connections to down osds.
+ *
+ * If @who is specified, resubmit requests for that specific osd.
+ *
+ * Caller should hold map_sem for read and request_mutex.
+ */
+static void kick_requests(struct ceph_osd_client *osdc,
+ struct ceph_osd *kickosd)
+{
+ struct ceph_osd_request *req;
+ struct rb_node *p, *n;
+ int needmap = 0;
+ int err;
+
+ dout("kick_requests osd%d\n", kickosd ? kickosd->o_osd : -1);
+ mutex_lock(&osdc->request_mutex);
+ if (!kickosd) {
+ for (p = rb_first(&osdc->osds); p; p = n) {
+ struct ceph_osd *osd =
+ rb_entry(p, struct ceph_osd, o_node);
+
+ n = rb_next(p);
+ if (!ceph_osd_is_up(osdc->osdmap, osd->o_osd) ||
+ !ceph_entity_addr_equal(&osd->o_con.peer_addr,
+ ceph_osd_addr(osdc->osdmap,
+ osd->o_osd)))
+ reset_osd(osdc, osd);
+ }
+ }
+
+ for (p = rb_first(&osdc->requests); p; p = rb_next(p)) {
+ req = rb_entry(p, struct ceph_osd_request, r_node);
+
+ if (req->r_resend) {
+ dout(" r_resend set on tid %llu\n", req->r_tid);
+ __cancel_request(req);
+ goto kick;
+ }
+ if (req->r_osd && kickosd == req->r_osd) {
+ __cancel_request(req);
+ goto kick;
+ }
+
+ err = __map_osds(osdc, req);
+ if (err == 0)
+ continue; /* no change */
+ if (err < 0) {
+ /*
+ * FIXME: really, we should set the request
+ * error and fail if this isn't a 'nofail'
+ * request, but that's a fair bit more
+ * complicated to do. So retry!
+ */
+ dout(" setting r_resend on %llu\n", req->r_tid);
+ req->r_resend = true;
+ continue;
+ }
+ if (req->r_osd == NULL) {
+ dout("tid %llu maps to no valid osd\n", req->r_tid);
+ needmap++; /* request a newer map */
+ continue;
+ }
+
+kick:
+ dout("kicking %p tid %llu osd%d\n", req, req->r_tid,
+ req->r_osd->o_osd);
+ req->r_flags |= CEPH_OSD_FLAG_RETRY;
+ err = __send_request(osdc, req);
+ if (err) {
+ dout(" setting r_resend on %llu\n", req->r_tid);
+ req->r_resend = true;
+ }
+ }
+ mutex_unlock(&osdc->request_mutex);
+
+ if (needmap) {
+ dout("%d requests for down osds, need new map\n", needmap);
+ ceph_monc_request_next_osdmap(&osdc->client->monc);
+ }
+}
+
+/*
+ * Process updated osd map.
+ *
+ * The message contains any number of incremental and full maps, normally
+ * indicating some sort of topology change in the cluster. Kick requests
+ * off to different OSDs as needed.
+ */
+void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
+{
+ void *p, *end, *next;
+ u32 nr_maps, maplen;
+ u32 epoch;
+ struct ceph_osdmap *newmap = NULL, *oldmap;
+ int err;
+ struct ceph_fsid fsid;
+
+ dout("handle_map have %u\n", osdc->osdmap ? osdc->osdmap->epoch : 0);
+ p = msg->front.iov_base;
+ end = p + msg->front.iov_len;
+
+ /* verify fsid */
+ ceph_decode_need(&p, end, sizeof(fsid), bad);
+ ceph_decode_copy(&p, &fsid, sizeof(fsid));
+ if (ceph_fsid_compare(&fsid, &osdc->client->monc.monmap->fsid)) {
+ pr_err("got osdmap with wrong fsid, ignoring\n");
+ return;
+ }
+
+ down_write(&osdc->map_sem);
+
+ /* incremental maps */
+ ceph_decode_32_safe(&p, end, nr_maps, bad);
+ dout(" %d inc maps\n", nr_maps);
+ while (nr_maps > 0) {
+ ceph_decode_need(&p, end, 2*sizeof(u32), bad);
+ epoch = ceph_decode_32(&p);
+ maplen = ceph_decode_32(&p);
+ ceph_decode_need(&p, end, maplen, bad);
+ next = p + maplen;
+ if (osdc->osdmap && osdc->osdmap->epoch+1 == epoch) {
+ dout("applying incremental map %u len %d\n",
+ epoch, maplen);
+ newmap = osdmap_apply_incremental(&p, next,
+ osdc->osdmap,
+ osdc->client->msgr);
+ if (IS_ERR(newmap)) {
+ err = PTR_ERR(newmap);
+ goto bad;
+ }
+ if (newmap != osdc->osdmap) {
+ ceph_osdmap_destroy(osdc->osdmap);
+ osdc->osdmap = newmap;
+ }
+ } else {
+ dout("ignoring incremental map %u len %d\n",
+ epoch, maplen);
+ }
+ p = next;
+ nr_maps--;
+ }
+ if (newmap)
+ goto done;
+
+ /* full maps */
+ ceph_decode_32_safe(&p, end, nr_maps, bad);
+ dout(" %d full maps\n", nr_maps);
+ while (nr_maps) {
+ ceph_decode_need(&p, end, 2*sizeof(u32), bad);
+ epoch = ceph_decode_32(&p);
+ maplen = ceph_decode_32(&p);
+ ceph_decode_need(&p, end, maplen, bad);
+ if (nr_maps > 1) {
+ dout("skipping non-latest full map %u len %d\n",
+ epoch, maplen);
+ } else if (osdc->osdmap && osdc->osdmap->epoch >= epoch) {
+ dout("skipping full map %u len %d, "
+ "older than our %u\n", epoch, maplen,
+ osdc->osdmap->epoch);
+ } else {
+ dout("taking full map %u len %d\n", epoch, maplen);
+ newmap = osdmap_decode(&p, p+maplen);
+ if (IS_ERR(newmap)) {
+ err = PTR_ERR(newmap);
+ goto bad;
+ }
+ oldmap = osdc->osdmap;
+ osdc->osdmap = newmap;
+ if (oldmap)
+ ceph_osdmap_destroy(oldmap);
+ }
+ p += maplen;
+ nr_maps--;
+ }
+
+done:
+ downgrade_write(&osdc->map_sem);
+ ceph_monc_got_osdmap(&osdc->client->monc, osdc->osdmap->epoch);
+ if (newmap)
+ kick_requests(osdc, NULL);
+ up_read(&osdc->map_sem);
+ return;
+
+bad:
+ pr_err("osdc handle_map corrupt msg\n");
+ up_write(&osdc->map_sem);
+ return;
+}
+
+
+/*
+ * A read request prepares specific pages that data is to be read into.
+ * When a message is being read off the wire, we call prepare_pages to
+ * find those pages.
+ * 0 = success, -1 failure.
+ */
+static int prepare_pages(struct ceph_connection *con, struct ceph_msg *m,
+ int want)
+{
+ struct ceph_osd *osd = con->private;
+ struct ceph_osd_client *osdc;
+ struct ceph_osd_reply_head *rhead = m->front.iov_base;
+ struct ceph_osd_request *req;
+ u64 tid;
+ int ret = -1;
+ int type = le16_to_cpu(m->hdr.type);
+
+ if (!osd)
+ return -1;
+ osdc = osd->o_osdc;
+
+ dout("prepare_pages on msg %p want %d\n", m, want);
+ if (unlikely(type != CEPH_MSG_OSD_OPREPLY))
+ return -1; /* hmm! */
+
+ tid = le64_to_cpu(rhead->tid);
+ mutex_lock(&osdc->request_mutex);
+ req = __lookup_request(osdc, tid);
+ if (!req) {
+ dout("prepare_pages unknown tid %llu\n", tid);
+ goto out;
+ }
+ dout("prepare_pages tid %llu has %d pages, want %d\n",
+ tid, req->r_num_pages, want);
+ if (likely(req->r_num_pages >= want && !req->r_prepared_pages)) {
+ m->pages = req->r_pages;
+ m->nr_pages = req->r_num_pages;
+ req->r_reply = m; /* only for duration of read over socket */
+ ceph_msg_get(m);
+ req->r_prepared_pages = 1;
+ ret = 0; /* success */
+ }
+out:
+ mutex_unlock(&osdc->request_mutex);
+ return ret;
+}
+
+/*
+ * Register request, send initial attempt.
+ */
+int ceph_osdc_start_request(struct ceph_osd_client *osdc,
+ struct ceph_osd_request *req,
+ bool nofail)
+{
+ int rc = 0;
+
+ req->r_request->pages = req->r_pages;
+ req->r_request->nr_pages = req->r_num_pages;
+
+ register_request(osdc, req);
+
+ down_read(&osdc->map_sem);
+ mutex_lock(&osdc->request_mutex);
+ /*
+ * a racing kick_requests() may have sent the message for us
+ * while we dropped request_mutex above, so only send now if
+ * the request still han't been touched yet.
+ */
+ if (req->r_sent == 0) {
+ rc = __send_request(osdc, req);
+ if (rc) {
+ if (nofail) {
+ dout("osdc_start_request failed send, "
+ " marking %lld\n", req->r_tid);
+ req->r_resend = true;
+ rc = 0;
+ } else {
+ __unregister_request(osdc, req);
+ }
+ }
+ }
+ mutex_unlock(&osdc->request_mutex);
+ up_read(&osdc->map_sem);
+ return rc;
+}
+
+/*
+ * wait for a request to complete
+ */
+int ceph_osdc_wait_request(struct ceph_osd_client *osdc,
+ struct ceph_osd_request *req)
+{
+ int rc;
+
+ rc = wait_for_completion_interruptible(&req->r_completion);
+ if (rc < 0) {
+ mutex_lock(&osdc->request_mutex);
+ __cancel_request(req);
+ mutex_unlock(&osdc->request_mutex);
+ dout("wait_request tid %llu timed out\n", req->r_tid);
+ return rc;
+ }
+
+ dout("wait_request tid %llu result %d\n", req->r_tid, req->r_result);
+ return req->r_result;
+}
+
+/*
+ * sync - wait for all in-flight requests to flush. avoid starvation.
+ */
+void ceph_osdc_sync(struct ceph_osd_client *osdc)
+{
+ struct ceph_osd_request *req;
+ u64 last_tid, next_tid = 0;
+
+ mutex_lock(&osdc->request_mutex);
+ last_tid = osdc->last_tid;
+ while (1) {
+ req = __lookup_request_ge(osdc, next_tid);
+ if (!req)
+ break;
+ if (req->r_tid > last_tid)
+ break;
+
+ next_tid = req->r_tid + 1;
+ if ((req->r_flags & CEPH_OSD_FLAG_WRITE) == 0)
+ continue;
+
+ ceph_osdc_get_request(req);
+ mutex_unlock(&osdc->request_mutex);
+ dout("sync waiting on tid %llu (last is %llu)\n",
+ req->r_tid, last_tid);
+ wait_for_completion(&req->r_safe_completion);
+ mutex_lock(&osdc->request_mutex);
+ ceph_osdc_put_request(req);
+ }
+ mutex_unlock(&osdc->request_mutex);
+ dout("sync done (thru tid %llu)\n", last_tid);
+}
+
+/*
+ * init, shutdown
+ */
+int ceph_osdc_init(struct ceph_osd_client *osdc, struct ceph_client *client)
+{
+ int err;
+
+ dout("init\n");
+ osdc->client = client;
+ osdc->osdmap = NULL;
+ init_rwsem(&osdc->map_sem);
+ init_completion(&osdc->map_waiters);
+ osdc->last_requested_map = 0;
+ mutex_init(&osdc->request_mutex);
+ osdc->timeout_tid = 0;
+ osdc->last_tid = 0;
+ osdc->osds = RB_ROOT;
+ osdc->requests = RB_ROOT;
+ osdc->num_requests = 0;
+ INIT_DELAYED_WORK(&osdc->timeout_work, handle_timeout);
+
+ osdc->req_mempool = mempool_create_kmalloc_pool(10,
+ sizeof(struct ceph_osd_request));
+ if (!osdc->req_mempool)
+ return -ENOMEM;
+
+ err = ceph_msgpool_init(&osdc->msgpool_op, 4096, 10, true);
+ if (err < 0)
+ return -ENOMEM;
+ err = ceph_msgpool_init(&osdc->msgpool_op_reply, 512, 0, false);
+ if (err < 0)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void ceph_osdc_stop(struct ceph_osd_client *osdc)
+{
+ cancel_delayed_work_sync(&osdc->timeout_work);
+ if (osdc->osdmap) {
+ ceph_osdmap_destroy(osdc->osdmap);
+ osdc->osdmap = NULL;
+ }
+ mempool_destroy(osdc->req_mempool);
+ ceph_msgpool_destroy(&osdc->msgpool_op);
+ ceph_msgpool_destroy(&osdc->msgpool_op_reply);
+}
+
+/*
+ * Read some contiguous pages. If we cross a stripe boundary, shorten
+ * *plen. Return number of bytes read, or error.
+ */
+int ceph_osdc_readpages(struct ceph_osd_client *osdc,
+ struct ceph_vino vino, struct ceph_file_layout *layout,
+ u64 off, u64 *plen,
+ u32 truncate_seq, u64 truncate_size,
+ struct page **pages, int num_pages)
+{
+ struct ceph_osd_request *req;
+ int rc = 0;
+
+ dout("readpages on ino %llx.%llx on %llu~%llu\n", vino.ino,
+ vino.snap, off, *plen);
+ req = ceph_osdc_new_request(osdc, layout, vino, off, plen,
+ CEPH_OSD_OP_READ, CEPH_OSD_FLAG_READ,
+ NULL, 0, truncate_seq, truncate_size, NULL,
+ false, 1);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ /* it may be a short read due to an object boundary */
+ req->r_pages = pages;
+ num_pages = calc_pages_for(off, *plen);
+ req->r_num_pages = num_pages;
+
+ dout("readpages final extent is %llu~%llu (%d pages)\n",
+ off, *plen, req->r_num_pages);
+
+ rc = ceph_osdc_start_request(osdc, req, false);
+ if (!rc)
+ rc = ceph_osdc_wait_request(osdc, req);
+
+ ceph_osdc_put_request(req);
+ dout("readpages result %d\n", rc);
+ return rc;
+}
+
+/*
+ * do a synchronous write on N pages
+ */
+int ceph_osdc_writepages(struct ceph_osd_client *osdc, struct ceph_vino vino,
+ struct ceph_file_layout *layout,
+ struct ceph_snap_context *snapc,
+ u64 off, u64 len,
+ u32 truncate_seq, u64 truncate_size,
+ struct timespec *mtime,
+ struct page **pages, int num_pages,
+ int flags, int do_sync, bool nofail)
+{
+ struct ceph_osd_request *req;
+ int rc = 0;
+
+ BUG_ON(vino.snap != CEPH_NOSNAP);
+ req = ceph_osdc_new_request(osdc, layout, vino, off, &len,
+ CEPH_OSD_OP_WRITE,
+ flags | CEPH_OSD_FLAG_ONDISK |
+ CEPH_OSD_FLAG_WRITE,
+ snapc, do_sync,
+ truncate_seq, truncate_size, mtime,
+ nofail, 1);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ /* it may be a short write due to an object boundary */
+ req->r_pages = pages;
+ req->r_num_pages = calc_pages_for(off, len);
+ dout("writepages %llu~%llu (%d pages)\n", off, len,
+ req->r_num_pages);
+
+ rc = ceph_osdc_start_request(osdc, req, nofail);
+ if (!rc)
+ rc = ceph_osdc_wait_request(osdc, req);
+
+ ceph_osdc_put_request(req);
+ if (rc == 0)
+ rc = len;
+ dout("writepages result %d\n", rc);
+ return rc;
+}
+
+/*
+ * handle incoming message
+ */
+static void dispatch(struct ceph_connection *con, struct ceph_msg *msg)
+{
+ struct ceph_osd *osd = con->private;
+ struct ceph_osd_client *osdc = osd->o_osdc;
+ int type = le16_to_cpu(msg->hdr.type);
+
+ if (!osd)
+ return;
+
+ switch (type) {
+ case CEPH_MSG_OSD_MAP:
+ ceph_osdc_handle_map(osdc, msg);
+ break;
+ case CEPH_MSG_OSD_OPREPLY:
+ handle_reply(osdc, msg);
+ break;
+
+ default:
+ pr_err("received unknown message type %d %s\n", type,
+ ceph_msg_type_name(type));
+ }
+ ceph_msg_put(msg);
+}
+
+static struct ceph_msg *alloc_msg(struct ceph_connection *con,
+ struct ceph_msg_header *hdr)
+{
+ struct ceph_osd *osd = con->private;
+ struct ceph_osd_client *osdc = osd->o_osdc;
+ int type = le16_to_cpu(hdr->type);
+ int front = le32_to_cpu(hdr->front_len);
+
+ switch (type) {
+ case CEPH_MSG_OSD_OPREPLY:
+ return ceph_msgpool_get(&osdc->msgpool_op_reply, front);
+ }
+ return ceph_alloc_msg(con, hdr);
+}
+
+/*
+ * Wrappers to refcount containing ceph_osd struct
+ */
+static struct ceph_connection *get_osd_con(struct ceph_connection *con)
+{
+ struct ceph_osd *osd = con->private;
+ if (get_osd(osd))
+ return con;
+ return NULL;
+}
+
+static void put_osd_con(struct ceph_connection *con)
+{
+ struct ceph_osd *osd = con->private;
+ put_osd(osd);
+}
+
+const static struct ceph_connection_operations osd_con_ops = {
+ .get = get_osd_con,
+ .put = put_osd_con,
+ .dispatch = dispatch,
+ .alloc_msg = alloc_msg,
+ .fault = osd_reset,
+ .alloc_middle = ceph_alloc_middle,
+ .prepare_pages = prepare_pages,
+};
diff --git a/fs/ceph/osd_client.h b/fs/ceph/osd_client.h
new file mode 100644
index 000000000000..9a4addf7d651
--- /dev/null
+++ b/fs/ceph/osd_client.h
@@ -0,0 +1,144 @@
+#ifndef _FS_CEPH_OSD_CLIENT_H
+#define _FS_CEPH_OSD_CLIENT_H
+
+#include <linux/completion.h>
+#include <linux/mempool.h>
+#include <linux/rbtree.h>
+
+#include "types.h"
+#include "osdmap.h"
+#include "messenger.h"
+
+struct ceph_msg;
+struct ceph_snap_context;
+struct ceph_osd_request;
+struct ceph_osd_client;
+
+/*
+ * completion callback for async writepages
+ */
+typedef void (*ceph_osdc_callback_t)(struct ceph_osd_request *,
+ struct ceph_msg *);
+
+/* a given osd we're communicating with */
+struct ceph_osd {
+ atomic_t o_ref;
+ struct ceph_osd_client *o_osdc;
+ int o_osd;
+ int o_incarnation;
+ struct rb_node o_node;
+ struct ceph_connection o_con;
+ struct list_head o_requests;
+};
+
+/* an in-flight request */
+struct ceph_osd_request {
+ u64 r_tid; /* unique for this client */
+ struct rb_node r_node;
+ struct list_head r_osd_item;
+ struct ceph_osd *r_osd;
+
+ struct ceph_msg *r_request, *r_reply;
+ int r_result;
+ int r_flags; /* any additional flags for the osd */
+ u32 r_sent; /* >0 if r_request is sending/sent */
+ int r_prepared_pages, r_got_reply;
+
+ struct ceph_osd_client *r_osdc;
+ atomic_t r_ref;
+ bool r_mempool;
+ struct completion r_completion, r_safe_completion;
+ ceph_osdc_callback_t r_callback, r_safe_callback;
+ struct ceph_eversion r_reassert_version;
+ struct list_head r_unsafe_item;
+
+ struct inode *r_inode; /* for use by callbacks */
+ struct writeback_control *r_wbc; /* ditto */
+
+ char r_oid[40]; /* object name */
+ int r_oid_len;
+ unsigned long r_timeout_stamp;
+ bool r_resend; /* msg send failed, needs retry */
+
+ struct ceph_file_layout r_file_layout;
+ struct ceph_snap_context *r_snapc; /* snap context for writes */
+ unsigned r_num_pages; /* size of page array (follows) */
+ struct page **r_pages; /* pages for data payload */
+ int r_pages_from_pool;
+ int r_own_pages; /* if true, i own page list */
+};
+
+struct ceph_osd_client {
+ struct ceph_client *client;
+
+ struct ceph_osdmap *osdmap; /* current map */
+ struct rw_semaphore map_sem;
+ struct completion map_waiters;
+ u64 last_requested_map;
+
+ struct mutex request_mutex;
+ struct rb_root osds; /* osds */
+ u64 timeout_tid; /* tid of timeout triggering rq */
+ u64 last_tid; /* tid of last request */
+ struct rb_root requests; /* pending requests */
+ int num_requests;
+ struct delayed_work timeout_work;
+ struct dentry *debugfs_file;
+
+ mempool_t *req_mempool;
+
+ struct ceph_msgpool msgpool_op;
+ struct ceph_msgpool msgpool_op_reply;
+};
+
+extern int ceph_osdc_init(struct ceph_osd_client *osdc,
+ struct ceph_client *client);
+extern void ceph_osdc_stop(struct ceph_osd_client *osdc);
+
+extern void ceph_osdc_handle_reply(struct ceph_osd_client *osdc,
+ struct ceph_msg *msg);
+extern void ceph_osdc_handle_map(struct ceph_osd_client *osdc,
+ struct ceph_msg *msg);
+
+extern struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *,
+ struct ceph_file_layout *layout,
+ struct ceph_vino vino,
+ u64 offset, u64 *len, int op, int flags,
+ struct ceph_snap_context *snapc,
+ int do_sync, u32 truncate_seq,
+ u64 truncate_size,
+ struct timespec *mtime,
+ bool use_mempool, int num_reply);
+
+static inline void ceph_osdc_get_request(struct ceph_osd_request *req)
+{
+ atomic_inc(&req->r_ref);
+}
+extern void ceph_osdc_put_request(struct ceph_osd_request *req);
+
+extern int ceph_osdc_start_request(struct ceph_osd_client *osdc,
+ struct ceph_osd_request *req,
+ bool nofail);
+extern int ceph_osdc_wait_request(struct ceph_osd_client *osdc,
+ struct ceph_osd_request *req);
+extern void ceph_osdc_sync(struct ceph_osd_client *osdc);
+
+extern int ceph_osdc_readpages(struct ceph_osd_client *osdc,
+ struct ceph_vino vino,
+ struct ceph_file_layout *layout,
+ u64 off, u64 *plen,
+ u32 truncate_seq, u64 truncate_size,
+ struct page **pages, int nr_pages);
+
+extern int ceph_osdc_writepages(struct ceph_osd_client *osdc,
+ struct ceph_vino vino,
+ struct ceph_file_layout *layout,
+ struct ceph_snap_context *sc,
+ u64 off, u64 len,
+ u32 truncate_seq, u64 truncate_size,
+ struct timespec *mtime,
+ struct page **pages, int nr_pages,
+ int flags, int do_sync, bool nofail);
+
+#endif
+
diff --git a/fs/ceph/osdmap.c b/fs/ceph/osdmap.c
new file mode 100644
index 000000000000..72d75a239ac2
--- /dev/null
+++ b/fs/ceph/osdmap.c
@@ -0,0 +1,882 @@
+
+#include <asm/div64.h>
+
+#include "super.h"
+#include "osdmap.h"
+#include "crush/hash.h"
+#include "crush/mapper.h"
+#include "decode.h"
+#include "ceph_debug.h"
+
+char *ceph_osdmap_state_str(char *str, int len, int state)
+{
+ int flag = 0;
+
+ if (!len)
+ goto done;
+
+ *str = '\0';
+ if (state) {
+ if (state & CEPH_OSD_EXISTS) {
+ snprintf(str, len, "exists");
+ flag = 1;
+ }
+ if (state & CEPH_OSD_UP) {
+ snprintf(str, len, "%s%s%s", str, (flag ? ", " : ""),
+ "up");
+ flag = 1;
+ }
+ } else {
+ snprintf(str, len, "doesn't exist");
+ }
+done:
+ return str;
+}
+
+/* maps */
+
+static int calc_bits_of(unsigned t)
+{
+ int b = 0;
+ while (t) {
+ t = t >> 1;
+ b++;
+ }
+ return b;
+}
+
+/*
+ * the foo_mask is the smallest value 2^n-1 that is >= foo.
+ */
+static void calc_pg_masks(struct ceph_pg_pool_info *pi)
+{
+ pi->pg_num_mask = (1 << calc_bits_of(le32_to_cpu(pi->v.pg_num)-1)) - 1;
+ pi->pgp_num_mask =
+ (1 << calc_bits_of(le32_to_cpu(pi->v.pgp_num)-1)) - 1;
+ pi->lpg_num_mask =
+ (1 << calc_bits_of(le32_to_cpu(pi->v.lpg_num)-1)) - 1;
+ pi->lpgp_num_mask =
+ (1 << calc_bits_of(le32_to_cpu(pi->v.lpgp_num)-1)) - 1;
+}
+
+/*
+ * decode crush map
+ */
+static int crush_decode_uniform_bucket(void **p, void *end,
+ struct crush_bucket_uniform *b)
+{
+ dout("crush_decode_uniform_bucket %p to %p\n", *p, end);
+ ceph_decode_need(p, end, (1+b->h.size) * sizeof(u32), bad);
+ b->item_weight = ceph_decode_32(p);
+ return 0;
+bad:
+ return -EINVAL;
+}
+
+static int crush_decode_list_bucket(void **p, void *end,
+ struct crush_bucket_list *b)
+{
+ int j;
+ dout("crush_decode_list_bucket %p to %p\n", *p, end);
+ b->item_weights = kcalloc(b->h.size, sizeof(u32), GFP_NOFS);
+ if (b->item_weights == NULL)
+ return -ENOMEM;
+ b->sum_weights = kcalloc(b->h.size, sizeof(u32), GFP_NOFS);
+ if (b->sum_weights == NULL)
+ return -ENOMEM;
+ ceph_decode_need(p, end, 2 * b->h.size * sizeof(u32), bad);
+ for (j = 0; j < b->h.size; j++) {
+ b->item_weights[j] = ceph_decode_32(p);
+ b->sum_weights[j] = ceph_decode_32(p);
+ }
+ return 0;
+bad:
+ return -EINVAL;
+}
+
+static int crush_decode_tree_bucket(void **p, void *end,
+ struct crush_bucket_tree *b)
+{
+ int j;
+ dout("crush_decode_tree_bucket %p to %p\n", *p, end);
+ ceph_decode_32_safe(p, end, b->num_nodes, bad);
+ b->node_weights = kcalloc(b->num_nodes, sizeof(u32), GFP_NOFS);
+ if (b->node_weights == NULL)
+ return -ENOMEM;
+ ceph_decode_need(p, end, b->num_nodes * sizeof(u32), bad);
+ for (j = 0; j < b->num_nodes; j++)
+ b->node_weights[j] = ceph_decode_32(p);
+ return 0;
+bad:
+ return -EINVAL;
+}
+
+static int crush_decode_straw_bucket(void **p, void *end,
+ struct crush_bucket_straw *b)
+{
+ int j;
+ dout("crush_decode_straw_bucket %p to %p\n", *p, end);
+ b->item_weights = kcalloc(b->h.size, sizeof(u32), GFP_NOFS);
+ if (b->item_weights == NULL)
+ return -ENOMEM;
+ b->straws = kcalloc(b->h.size, sizeof(u32), GFP_NOFS);
+ if (b->straws == NULL)
+ return -ENOMEM;
+ ceph_decode_need(p, end, 2 * b->h.size * sizeof(u32), bad);
+ for (j = 0; j < b->h.size; j++) {
+ b->item_weights[j] = ceph_decode_32(p);
+ b->straws[j] = ceph_decode_32(p);
+ }
+ return 0;
+bad:
+ return -EINVAL;
+}
+
+static struct crush_map *crush_decode(void *pbyval, void *end)
+{
+ struct crush_map *c;
+ int err = -EINVAL;
+ int i, j;
+ void **p = &pbyval;
+ void *start = pbyval;
+ u32 magic;
+
+ dout("crush_decode %p to %p len %d\n", *p, end, (int)(end - *p));
+
+ c = kzalloc(sizeof(*c), GFP_NOFS);
+ if (c == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ ceph_decode_need(p, end, 4*sizeof(u32), bad);
+ magic = ceph_decode_32(p);
+ if (magic != CRUSH_MAGIC) {
+ pr_err("crush_decode magic %x != current %x\n",
+ (unsigned)magic, (unsigned)CRUSH_MAGIC);
+ goto bad;
+ }
+ c->max_buckets = ceph_decode_32(p);
+ c->max_rules = ceph_decode_32(p);
+ c->max_devices = ceph_decode_32(p);
+
+ c->device_parents = kcalloc(c->max_devices, sizeof(u32), GFP_NOFS);
+ if (c->device_parents == NULL)
+ goto badmem;
+ c->bucket_parents = kcalloc(c->max_buckets, sizeof(u32), GFP_NOFS);
+ if (c->bucket_parents == NULL)
+ goto badmem;
+
+ c->buckets = kcalloc(c->max_buckets, sizeof(*c->buckets), GFP_NOFS);
+ if (c->buckets == NULL)
+ goto badmem;
+ c->rules = kcalloc(c->max_rules, sizeof(*c->rules), GFP_NOFS);
+ if (c->rules == NULL)
+ goto badmem;
+
+ /* buckets */
+ for (i = 0; i < c->max_buckets; i++) {
+ int size = 0;
+ u32 alg;
+ struct crush_bucket *b;
+
+ ceph_decode_32_safe(p, end, alg, bad);
+ if (alg == 0) {
+ c->buckets[i] = NULL;
+ continue;
+ }
+ dout("crush_decode bucket %d off %x %p to %p\n",
+ i, (int)(*p-start), *p, end);
+
+ switch (alg) {
+ case CRUSH_BUCKET_UNIFORM:
+ size = sizeof(struct crush_bucket_uniform);
+ break;
+ case CRUSH_BUCKET_LIST:
+ size = sizeof(struct crush_bucket_list);
+ break;
+ case CRUSH_BUCKET_TREE:
+ size = sizeof(struct crush_bucket_tree);
+ break;
+ case CRUSH_BUCKET_STRAW:
+ size = sizeof(struct crush_bucket_straw);
+ break;
+ default:
+ goto bad;
+ }
+ BUG_ON(size == 0);
+ b = c->buckets[i] = kzalloc(size, GFP_NOFS);
+ if (b == NULL)
+ goto badmem;
+
+ ceph_decode_need(p, end, 4*sizeof(u32), bad);
+ b->id = ceph_decode_32(p);
+ b->type = ceph_decode_16(p);
+ b->alg = ceph_decode_16(p);
+ b->weight = ceph_decode_32(p);
+ b->size = ceph_decode_32(p);
+
+ dout("crush_decode bucket size %d off %x %p to %p\n",
+ b->size, (int)(*p-start), *p, end);
+
+ b->items = kcalloc(b->size, sizeof(__s32), GFP_NOFS);
+ if (b->items == NULL)
+ goto badmem;
+ b->perm = kcalloc(b->size, sizeof(u32), GFP_NOFS);
+ if (b->perm == NULL)
+ goto badmem;
+ b->perm_n = 0;
+
+ ceph_decode_need(p, end, b->size*sizeof(u32), bad);
+ for (j = 0; j < b->size; j++)
+ b->items[j] = ceph_decode_32(p);
+
+ switch (b->alg) {
+ case CRUSH_BUCKET_UNIFORM:
+ err = crush_decode_uniform_bucket(p, end,
+ (struct crush_bucket_uniform *)b);
+ if (err < 0)
+ goto bad;
+ break;
+ case CRUSH_BUCKET_LIST:
+ err = crush_decode_list_bucket(p, end,
+ (struct crush_bucket_list *)b);
+ if (err < 0)
+ goto bad;
+ break;
+ case CRUSH_BUCKET_TREE:
+ err = crush_decode_tree_bucket(p, end,
+ (struct crush_bucket_tree *)b);
+ if (err < 0)
+ goto bad;
+ break;
+ case CRUSH_BUCKET_STRAW:
+ err = crush_decode_straw_bucket(p, end,
+ (struct crush_bucket_straw *)b);
+ if (err < 0)
+ goto bad;
+ break;
+ }
+ }
+
+ /* rules */
+ dout("rule vec is %p\n", c->rules);
+ for (i = 0; i < c->max_rules; i++) {
+ u32 yes;
+ struct crush_rule *r;
+
+ ceph_decode_32_safe(p, end, yes, bad);
+ if (!yes) {
+ dout("crush_decode NO rule %d off %x %p to %p\n",
+ i, (int)(*p-start), *p, end);
+ c->rules[i] = NULL;
+ continue;
+ }
+
+ dout("crush_decode rule %d off %x %p to %p\n",
+ i, (int)(*p-start), *p, end);
+
+ /* len */
+ ceph_decode_32_safe(p, end, yes, bad);
+#if BITS_PER_LONG == 32
+ if (yes > ULONG_MAX / sizeof(struct crush_rule_step))
+ goto bad;
+#endif
+ r = c->rules[i] = kmalloc(sizeof(*r) +
+ yes*sizeof(struct crush_rule_step),
+ GFP_NOFS);
+ if (r == NULL)
+ goto badmem;
+ dout(" rule %d is at %p\n", i, r);
+ r->len = yes;
+ ceph_decode_copy_safe(p, end, &r->mask, 4, bad); /* 4 u8's */
+ ceph_decode_need(p, end, r->len*3*sizeof(u32), bad);
+ for (j = 0; j < r->len; j++) {
+ r->steps[j].op = ceph_decode_32(p);
+ r->steps[j].arg1 = ceph_decode_32(p);
+ r->steps[j].arg2 = ceph_decode_32(p);
+ }
+ }
+
+ /* ignore trailing name maps. */
+
+ dout("crush_decode success\n");
+ return c;
+
+badmem:
+ err = -ENOMEM;
+bad:
+ dout("crush_decode fail %d\n", err);
+ crush_destroy(c);
+ return ERR_PTR(err);
+}
+
+
+/*
+ * osd map
+ */
+void ceph_osdmap_destroy(struct ceph_osdmap *map)
+{
+ dout("osdmap_destroy %p\n", map);
+ if (map->crush)
+ crush_destroy(map->crush);
+ while (!RB_EMPTY_ROOT(&map->pg_temp))
+ rb_erase(rb_first(&map->pg_temp), &map->pg_temp);
+ kfree(map->osd_state);
+ kfree(map->osd_weight);
+ kfree(map->pg_pool);
+ kfree(map->osd_addr);
+ kfree(map);
+}
+
+/*
+ * adjust max osd value. reallocate arrays.
+ */
+static int osdmap_set_max_osd(struct ceph_osdmap *map, int max)
+{
+ u8 *state;
+ struct ceph_entity_addr *addr;
+ u32 *weight;
+
+ state = kcalloc(max, sizeof(*state), GFP_NOFS);
+ addr = kcalloc(max, sizeof(*addr), GFP_NOFS);
+ weight = kcalloc(max, sizeof(*weight), GFP_NOFS);
+ if (state == NULL || addr == NULL || weight == NULL) {
+ kfree(state);
+ kfree(addr);
+ kfree(weight);
+ return -ENOMEM;
+ }
+
+ /* copy old? */
+ if (map->osd_state) {
+ memcpy(state, map->osd_state, map->max_osd*sizeof(*state));
+ memcpy(addr, map->osd_addr, map->max_osd*sizeof(*addr));
+ memcpy(weight, map->osd_weight, map->max_osd*sizeof(*weight));
+ kfree(map->osd_state);
+ kfree(map->osd_addr);
+ kfree(map->osd_weight);
+ }
+
+ map->osd_state = state;
+ map->osd_weight = weight;
+ map->osd_addr = addr;
+ map->max_osd = max;
+ return 0;
+}
+
+/*
+ * Insert a new pg_temp mapping
+ */
+static int __insert_pg_mapping(struct ceph_pg_mapping *new,
+ struct rb_root *root)
+{
+ struct rb_node **p = &root->rb_node;
+ struct rb_node *parent = NULL;
+ struct ceph_pg_mapping *pg = NULL;
+
+ while (*p) {
+ parent = *p;
+ pg = rb_entry(parent, struct ceph_pg_mapping, node);
+ if (new->pgid < pg->pgid)
+ p = &(*p)->rb_left;
+ else if (new->pgid > pg->pgid)
+ p = &(*p)->rb_right;
+ else
+ return -EEXIST;
+ }
+
+ rb_link_node(&new->node, parent, p);
+ rb_insert_color(&new->node, root);
+ return 0;
+}
+
+/*
+ * decode a full map.
+ */
+struct ceph_osdmap *osdmap_decode(void **p, void *end)
+{
+ struct ceph_osdmap *map;
+ u16 version;
+ u32 len, max, i;
+ int err = -EINVAL;
+ void *start = *p;
+
+ dout("osdmap_decode %p to %p len %d\n", *p, end, (int)(end - *p));
+
+ map = kzalloc(sizeof(*map), GFP_NOFS);
+ if (map == NULL)
+ return ERR_PTR(-ENOMEM);
+ map->pg_temp = RB_ROOT;
+
+ ceph_decode_16_safe(p, end, version, bad);
+
+ ceph_decode_need(p, end, 2*sizeof(u64)+6*sizeof(u32), bad);
+ ceph_decode_copy(p, &map->fsid, sizeof(map->fsid));
+ map->epoch = ceph_decode_32(p);
+ ceph_decode_copy(p, &map->created, sizeof(map->created));
+ ceph_decode_copy(p, &map->modified, sizeof(map->modified));
+
+ map->num_pools = ceph_decode_32(p);
+ map->pg_pool = kcalloc(map->num_pools, sizeof(*map->pg_pool),
+ GFP_NOFS);
+ if (!map->pg_pool) {
+ err = -ENOMEM;
+ goto bad;
+ }
+ ceph_decode_32_safe(p, end, max, bad);
+ while (max--) {
+ ceph_decode_need(p, end, 4+sizeof(map->pg_pool->v), bad);
+ i = ceph_decode_32(p);
+ if (i >= map->num_pools)
+ goto bad;
+ ceph_decode_copy(p, &map->pg_pool[i].v,
+ sizeof(map->pg_pool->v));
+ calc_pg_masks(&map->pg_pool[i]);
+ p += le32_to_cpu(map->pg_pool[i].v.num_snaps) * sizeof(u64);
+ p += le32_to_cpu(map->pg_pool[i].v.num_removed_snap_intervals)
+ * sizeof(u64) * 2;
+ }
+
+ ceph_decode_32_safe(p, end, map->flags, bad);
+
+ max = ceph_decode_32(p);
+
+ /* (re)alloc osd arrays */
+ err = osdmap_set_max_osd(map, max);
+ if (err < 0)
+ goto bad;
+ dout("osdmap_decode max_osd = %d\n", map->max_osd);
+
+ /* osds */
+ err = -EINVAL;
+ ceph_decode_need(p, end, 3*sizeof(u32) +
+ map->max_osd*(1 + sizeof(*map->osd_weight) +
+ sizeof(*map->osd_addr)), bad);
+ *p += 4; /* skip length field (should match max) */
+ ceph_decode_copy(p, map->osd_state, map->max_osd);
+
+ *p += 4; /* skip length field (should match max) */
+ for (i = 0; i < map->max_osd; i++)
+ map->osd_weight[i] = ceph_decode_32(p);
+
+ *p += 4; /* skip length field (should match max) */
+ ceph_decode_copy(p, map->osd_addr, map->max_osd*sizeof(*map->osd_addr));
+
+ /* pg_temp */
+ ceph_decode_32_safe(p, end, len, bad);
+ for (i = 0; i < len; i++) {
+ int n, j;
+ u64 pgid;
+ struct ceph_pg_mapping *pg;
+
+ ceph_decode_need(p, end, sizeof(u32) + sizeof(u64), bad);
+ pgid = ceph_decode_64(p);
+ n = ceph_decode_32(p);
+ ceph_decode_need(p, end, n * sizeof(u32), bad);
+ pg = kmalloc(sizeof(*pg) + n*sizeof(u32), GFP_NOFS);
+ if (!pg) {
+ err = -ENOMEM;
+ goto bad;
+ }
+ pg->pgid = pgid;
+ pg->len = n;
+ for (j = 0; j < n; j++)
+ pg->osds[j] = ceph_decode_32(p);
+
+ err = __insert_pg_mapping(pg, &map->pg_temp);
+ if (err)
+ goto bad;
+ dout(" added pg_temp %llx len %d\n", pgid, len);
+ }
+
+ /* crush */
+ ceph_decode_32_safe(p, end, len, bad);
+ dout("osdmap_decode crush len %d from off 0x%x\n", len,
+ (int)(*p - start));
+ ceph_decode_need(p, end, len, bad);
+ map->crush = crush_decode(*p, end);
+ *p += len;
+ if (IS_ERR(map->crush)) {
+ err = PTR_ERR(map->crush);
+ map->crush = NULL;
+ goto bad;
+ }
+
+ /* ignore the rest of the map */
+ *p = end;
+
+ dout("osdmap_decode done %p %p\n", *p, end);
+ return map;
+
+bad:
+ dout("osdmap_decode fail\n");
+ ceph_osdmap_destroy(map);
+ return ERR_PTR(err);
+}
+
+/*
+ * decode and apply an incremental map update.
+ */
+struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
+ struct ceph_osdmap *map,
+ struct ceph_messenger *msgr)
+{
+ struct ceph_osdmap *newmap = map;
+ struct crush_map *newcrush = NULL;
+ struct ceph_fsid fsid;
+ u32 epoch = 0;
+ struct ceph_timespec modified;
+ u32 len, pool;
+ __s32 new_flags, max;
+ void *start = *p;
+ int err = -EINVAL;
+ u16 version;
+ struct rb_node *rbp;
+
+ ceph_decode_16_safe(p, end, version, bad);
+
+ ceph_decode_need(p, end, sizeof(fsid)+sizeof(modified)+2*sizeof(u32),
+ bad);
+ ceph_decode_copy(p, &fsid, sizeof(fsid));
+ epoch = ceph_decode_32(p);
+ BUG_ON(epoch != map->epoch+1);
+ ceph_decode_copy(p, &modified, sizeof(modified));
+ new_flags = ceph_decode_32(p);
+
+ /* full map? */
+ ceph_decode_32_safe(p, end, len, bad);
+ if (len > 0) {
+ dout("apply_incremental full map len %d, %p to %p\n",
+ len, *p, end);
+ newmap = osdmap_decode(p, min(*p+len, end));
+ return newmap; /* error or not */
+ }
+
+ /* new crush? */
+ ceph_decode_32_safe(p, end, len, bad);
+ if (len > 0) {
+ dout("apply_incremental new crush map len %d, %p to %p\n",
+ len, *p, end);
+ newcrush = crush_decode(*p, min(*p+len, end));
+ if (IS_ERR(newcrush))
+ return ERR_PTR(PTR_ERR(newcrush));
+ }
+
+ /* new flags? */
+ if (new_flags >= 0)
+ map->flags = new_flags;
+
+ ceph_decode_need(p, end, 5*sizeof(u32), bad);
+
+ /* new max? */
+ max = ceph_decode_32(p);
+ if (max >= 0) {
+ err = osdmap_set_max_osd(map, max);
+ if (err < 0)
+ goto bad;
+ }
+
+ map->epoch++;
+ map->modified = map->modified;
+ if (newcrush) {
+ if (map->crush)
+ crush_destroy(map->crush);
+ map->crush = newcrush;
+ newcrush = NULL;
+ }
+
+ /* new_pool */
+ ceph_decode_32_safe(p, end, len, bad);
+ while (len--) {
+ ceph_decode_32_safe(p, end, pool, bad);
+ if (pool >= map->num_pools) {
+ void *pg_pool = kcalloc(pool + 1,
+ sizeof(*map->pg_pool),
+ GFP_NOFS);
+ if (!pg_pool) {
+ err = -ENOMEM;
+ goto bad;
+ }
+ memcpy(pg_pool, map->pg_pool,
+ map->num_pools * sizeof(*map->pg_pool));
+ kfree(map->pg_pool);
+ map->pg_pool = pg_pool;
+ map->num_pools = pool+1;
+ }
+ ceph_decode_copy(p, &map->pg_pool[pool].v,
+ sizeof(map->pg_pool->v));
+ calc_pg_masks(&map->pg_pool[pool]);
+ }
+
+ /* old_pool (ignore) */
+ ceph_decode_32_safe(p, end, len, bad);
+ *p += len * sizeof(u32);
+
+ /* new_up */
+ err = -EINVAL;
+ ceph_decode_32_safe(p, end, len, bad);
+ while (len--) {
+ u32 osd;
+ struct ceph_entity_addr addr;
+ ceph_decode_32_safe(p, end, osd, bad);
+ ceph_decode_copy_safe(p, end, &addr, sizeof(addr), bad);
+ pr_info("osd%d up\n", osd);
+ BUG_ON(osd >= map->max_osd);
+ map->osd_state[osd] |= CEPH_OSD_UP;
+ map->osd_addr[osd] = addr;
+ }
+
+ /* new_down */
+ ceph_decode_32_safe(p, end, len, bad);
+ while (len--) {
+ u32 osd;
+ ceph_decode_32_safe(p, end, osd, bad);
+ (*p)++; /* clean flag */
+ pr_info("ceph osd%d down\n", osd);
+ if (osd < map->max_osd)
+ map->osd_state[osd] &= ~CEPH_OSD_UP;
+ }
+
+ /* new_weight */
+ ceph_decode_32_safe(p, end, len, bad);
+ while (len--) {
+ u32 osd, off;
+ ceph_decode_need(p, end, sizeof(u32)*2, bad);
+ osd = ceph_decode_32(p);
+ off = ceph_decode_32(p);
+ pr_info("osd%d weight 0x%x %s\n", osd, off,
+ off == CEPH_OSD_IN ? "(in)" :
+ (off == CEPH_OSD_OUT ? "(out)" : ""));
+ if (osd < map->max_osd)
+ map->osd_weight[osd] = off;
+ }
+
+ /* new_pg_temp */
+ rbp = rb_first(&map->pg_temp);
+ ceph_decode_32_safe(p, end, len, bad);
+ while (len--) {
+ struct ceph_pg_mapping *pg;
+ int j;
+ u64 pgid;
+ u32 pglen;
+ ceph_decode_need(p, end, sizeof(u64) + sizeof(u32), bad);
+ pgid = ceph_decode_64(p);
+ pglen = ceph_decode_32(p);
+
+ /* remove any? */
+ while (rbp && rb_entry(rbp, struct ceph_pg_mapping,
+ node)->pgid <= pgid) {
+ struct rb_node *cur = rbp;
+ rbp = rb_next(rbp);
+ dout(" removed pg_temp %llx\n",
+ rb_entry(cur, struct ceph_pg_mapping, node)->pgid);
+ rb_erase(cur, &map->pg_temp);
+ }
+
+ if (pglen) {
+ /* insert */
+ ceph_decode_need(p, end, pglen*sizeof(u32), bad);
+ pg = kmalloc(sizeof(*pg) + sizeof(u32)*pglen, GFP_NOFS);
+ if (!pg) {
+ err = -ENOMEM;
+ goto bad;
+ }
+ pg->pgid = pgid;
+ pg->len = pglen;
+ for (j = 0; j < len; j++)
+ pg->osds[j] = ceph_decode_32(p);
+ err = __insert_pg_mapping(pg, &map->pg_temp);
+ if (err)
+ goto bad;
+ dout(" added pg_temp %llx len %d\n", pgid, pglen);
+ }
+ }
+ while (rbp) {
+ struct rb_node *cur = rbp;
+ rbp = rb_next(rbp);
+ dout(" removed pg_temp %llx\n",
+ rb_entry(cur, struct ceph_pg_mapping, node)->pgid);
+ rb_erase(cur, &map->pg_temp);
+ }
+
+ /* ignore the rest */
+ *p = end;
+ return map;
+
+bad:
+ pr_err("corrupt inc osdmap epoch %d off %d (%p of %p-%p)\n",
+ epoch, (int)(*p - start), *p, start, end);
+ if (newcrush)
+ crush_destroy(newcrush);
+ return ERR_PTR(err);
+}
+
+
+
+
+/*
+ * calculate file layout from given offset, length.
+ * fill in correct oid, logical length, and object extent
+ * offset, length.
+ *
+ * for now, we write only a single su, until we can
+ * pass a stride back to the caller.
+ */
+void ceph_calc_file_object_mapping(struct ceph_file_layout *layout,
+ u64 off, u64 *plen,
+ u64 *bno,
+ u64 *oxoff, u64 *oxlen)
+{
+ u32 osize = le32_to_cpu(layout->fl_object_size);
+ u32 su = le32_to_cpu(layout->fl_stripe_unit);
+ u32 sc = le32_to_cpu(layout->fl_stripe_count);
+ u32 bl, stripeno, stripepos, objsetno;
+ u32 su_per_object;
+ u64 t;
+
+ dout("mapping %llu~%llu osize %u fl_su %u\n", off, *plen,
+ osize, su);
+ su_per_object = osize / le32_to_cpu(layout->fl_stripe_unit);
+ dout("osize %u / su %u = su_per_object %u\n", osize, su,
+ su_per_object);
+
+ BUG_ON((su & ~PAGE_MASK) != 0);
+ /* bl = *off / su; */
+ t = off;
+ do_div(t, su);
+ bl = t;
+ dout("off %llu / su %u = bl %u\n", off, su, bl);
+
+ stripeno = bl / sc;
+ stripepos = bl % sc;
+ objsetno = stripeno / su_per_object;
+
+ *bno = objsetno * sc + stripepos;
+ dout("objset %u * sc %u = bno %u\n", objsetno, sc, (unsigned)*bno);
+ /* *oxoff = *off / layout->fl_stripe_unit; */
+ t = off;
+ *oxoff = do_div(t, su);
+ *oxlen = min_t(u64, *plen, su - *oxoff);
+ *plen = *oxlen;
+
+ dout(" obj extent %llu~%llu\n", *oxoff, *oxlen);
+}
+
+/*
+ * calculate an object layout (i.e. pgid) from an oid,
+ * file_layout, and osdmap
+ */
+int ceph_calc_object_layout(struct ceph_object_layout *ol,
+ const char *oid,
+ struct ceph_file_layout *fl,
+ struct ceph_osdmap *osdmap)
+{
+ unsigned num, num_mask;
+ union ceph_pg pgid;
+ s32 preferred = (s32)le32_to_cpu(fl->fl_pg_preferred);
+ int poolid = le32_to_cpu(fl->fl_pg_pool);
+ struct ceph_pg_pool_info *pool;
+
+ if (poolid >= osdmap->num_pools)
+ return -EIO;
+ pool = &osdmap->pg_pool[poolid];
+
+ if (preferred >= 0) {
+ num = le32_to_cpu(pool->v.lpg_num);
+ num_mask = pool->lpg_num_mask;
+ } else {
+ num = le32_to_cpu(pool->v.pg_num);
+ num_mask = pool->pg_num_mask;
+ }
+
+ pgid.pg64 = 0; /* start with it zeroed out */
+ pgid.pg.ps = ceph_full_name_hash(oid, strlen(oid));
+ pgid.pg.preferred = preferred;
+ if (preferred >= 0)
+ pgid.pg.ps += preferred;
+ pgid.pg.pool = le32_to_cpu(fl->fl_pg_pool);
+ if (preferred >= 0)
+ dout("calc_object_layout '%s' pgid %d.%xp%d (%llx)\n", oid,
+ pgid.pg.pool, pgid.pg.ps, (int)preferred, pgid.pg64);
+ else
+ dout("calc_object_layout '%s' pgid %d.%x (%llx)\n", oid,
+ pgid.pg.pool, pgid.pg.ps, pgid.pg64);
+
+ ol->ol_pgid = cpu_to_le64(pgid.pg64);
+ ol->ol_stripe_unit = fl->fl_object_stripe_unit;
+
+ return 0;
+}
+
+/*
+ * Calculate raw osd vector for the given pgid. Return pointer to osd
+ * array, or NULL on failure.
+ */
+static int *calc_pg_raw(struct ceph_osdmap *osdmap, union ceph_pg pgid,
+ int *osds, int *num)
+{
+ struct rb_node *n = osdmap->pg_temp.rb_node;
+ struct ceph_pg_mapping *pg;
+ struct ceph_pg_pool_info *pool;
+ int ruleno;
+ unsigned pps; /* placement ps */
+
+ /* pg_temp? */
+ while (n) {
+ pg = rb_entry(n, struct ceph_pg_mapping, node);
+ if (pgid.pg64 < pg->pgid)
+ n = n->rb_left;
+ else if (pgid.pg64 > pg->pgid)
+ n = n->rb_right;
+ else {
+ *num = pg->len;
+ return pg->osds;
+ }
+ }
+
+ /* crush */
+ if (pgid.pg.pool >= osdmap->num_pools)
+ return NULL;
+ pool = &osdmap->pg_pool[pgid.pg.pool];
+ ruleno = crush_find_rule(osdmap->crush, pool->v.crush_ruleset,
+ pool->v.type, pool->v.size);
+ if (ruleno < 0) {
+ pr_err("no crush rule pool %d type %d size %d\n",
+ pgid.pg.pool, pool->v.type, pool->v.size);
+ return NULL;
+ }
+
+ if (pgid.pg.preferred >= 0)
+ pps = ceph_stable_mod(pgid.pg.ps,
+ le32_to_cpu(pool->v.lpgp_num),
+ pool->lpgp_num_mask);
+ else
+ pps = ceph_stable_mod(pgid.pg.ps,
+ le32_to_cpu(pool->v.pgp_num),
+ pool->pgp_num_mask);
+ pps += pgid.pg.pool;
+ *num = crush_do_rule(osdmap->crush, ruleno, pps, osds,
+ min_t(int, pool->v.size, *num),
+ pgid.pg.preferred, osdmap->osd_weight);
+ return osds;
+}
+
+/*
+ * Return primary osd for given pgid, or -1 if none.
+ */
+int ceph_calc_pg_primary(struct ceph_osdmap *osdmap, union ceph_pg pgid)
+{
+ int rawosds[10], *osds;
+ int i, num = ARRAY_SIZE(rawosds);
+
+ osds = calc_pg_raw(osdmap, pgid, rawosds, &num);
+ if (!osds)
+ return -1;
+
+ /* primary is first up osd */
+ for (i = 0; i < num; i++)
+ if (ceph_osd_is_up(osdmap, osds[i])) {
+ return osds[i];
+ break;
+ }
+ return -1;
+}
diff --git a/fs/ceph/osdmap.h b/fs/ceph/osdmap.h
new file mode 100644
index 000000000000..07127c6fb134
--- /dev/null
+++ b/fs/ceph/osdmap.h
@@ -0,0 +1,123 @@
+#ifndef _FS_CEPH_OSDMAP_H
+#define _FS_CEPH_OSDMAP_H
+
+#include <linux/rbtree.h>
+#include "types.h"
+#include "ceph_fs.h"
+#include "crush/crush.h"
+
+/*
+ * The osd map describes the current membership of the osd cluster and
+ * specifies the mapping of objects to placement groups and placement
+ * groups to (sets of) osds. That is, it completely specifies the
+ * (desired) distribution of all data objects in the system at some
+ * point in time.
+ *
+ * Each map version is identified by an epoch, which increases monotonically.
+ *
+ * The map can be updated either via an incremental map (diff) describing
+ * the change between two successive epochs, or as a fully encoded map.
+ */
+struct ceph_pg_pool_info {
+ struct ceph_pg_pool v;
+ int pg_num_mask, pgp_num_mask, lpg_num_mask, lpgp_num_mask;
+};
+
+struct ceph_pg_mapping {
+ struct rb_node node;
+ u64 pgid;
+ int len;
+ int osds[];
+};
+
+struct ceph_osdmap {
+ struct ceph_fsid fsid;
+ u32 epoch;
+ u32 mkfs_epoch;
+ struct ceph_timespec created, modified;
+
+ u32 flags; /* CEPH_OSDMAP_* */
+
+ u32 max_osd; /* size of osd_state, _offload, _addr arrays */
+ u8 *osd_state; /* CEPH_OSD_* */
+ u32 *osd_weight; /* 0 = failed, 0x10000 = 100% normal */
+ struct ceph_entity_addr *osd_addr;
+
+ struct rb_root pg_temp;
+
+ u32 num_pools;
+ struct ceph_pg_pool_info *pg_pool;
+
+ /* the CRUSH map specifies the mapping of placement groups to
+ * the list of osds that store+replicate them. */
+ struct crush_map *crush;
+};
+
+/*
+ * file layout helpers
+ */
+#define ceph_file_layout_su(l) ((__s32)le32_to_cpu((l).fl_stripe_unit))
+#define ceph_file_layout_stripe_count(l) \
+ ((__s32)le32_to_cpu((l).fl_stripe_count))
+#define ceph_file_layout_object_size(l) ((__s32)le32_to_cpu((l).fl_object_size))
+#define ceph_file_layout_cas_hash(l) ((__s32)le32_to_cpu((l).fl_cas_hash))
+#define ceph_file_layout_object_su(l) \
+ ((__s32)le32_to_cpu((l).fl_object_stripe_unit))
+#define ceph_file_layout_pg_preferred(l) \
+ ((__s32)le32_to_cpu((l).fl_pg_preferred))
+#define ceph_file_layout_pg_pool(l) \
+ ((__s32)le32_to_cpu((l).fl_pg_pool))
+
+static inline unsigned ceph_file_layout_stripe_width(struct ceph_file_layout *l)
+{
+ return le32_to_cpu(l->fl_stripe_unit) *
+ le32_to_cpu(l->fl_stripe_count);
+}
+
+/* "period" == bytes before i start on a new set of objects */
+static inline unsigned ceph_file_layout_period(struct ceph_file_layout *l)
+{
+ return le32_to_cpu(l->fl_object_size) *
+ le32_to_cpu(l->fl_stripe_count);
+}
+
+
+static inline int ceph_osd_is_up(struct ceph_osdmap *map, int osd)
+{
+ return (osd < map->max_osd) && (map->osd_state[osd] & CEPH_OSD_UP);
+}
+
+static inline bool ceph_osdmap_flag(struct ceph_osdmap *map, int flag)
+{
+ return map && (map->flags & flag);
+}
+
+extern char *ceph_osdmap_state_str(char *str, int len, int state);
+
+static inline struct ceph_entity_addr *ceph_osd_addr(struct ceph_osdmap *map,
+ int osd)
+{
+ if (osd >= map->max_osd)
+ return NULL;
+ return &map->osd_addr[osd];
+}
+
+extern struct ceph_osdmap *osdmap_decode(void **p, void *end);
+extern struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
+ struct ceph_osdmap *map,
+ struct ceph_messenger *msgr);
+extern void ceph_osdmap_destroy(struct ceph_osdmap *map);
+
+/* calculate mapping of a file extent to an object */
+extern void ceph_calc_file_object_mapping(struct ceph_file_layout *layout,
+ u64 off, u64 *plen,
+ u64 *bno, u64 *oxoff, u64 *oxlen);
+
+/* calculate mapping of object to a placement group */
+extern int ceph_calc_object_layout(struct ceph_object_layout *ol,
+ const char *oid,
+ struct ceph_file_layout *fl,
+ struct ceph_osdmap *osdmap);
+extern int ceph_calc_pg_primary(struct ceph_osdmap *osdmap, union ceph_pg pgid);
+
+#endif
diff --git a/fs/ceph/rados.h b/fs/ceph/rados.h
new file mode 100644
index 000000000000..a48cf4ae391e
--- /dev/null
+++ b/fs/ceph/rados.h
@@ -0,0 +1,372 @@
+#ifndef __RADOS_H
+#define __RADOS_H
+
+/*
+ * Data types for the Ceph distributed object storage layer RADOS
+ * (Reliable Autonomic Distributed Object Store).
+ */
+
+#include "msgr.h"
+
+/*
+ * fs id
+ */
+struct ceph_fsid {
+ unsigned char fsid[16];
+};
+
+static inline int ceph_fsid_compare(const struct ceph_fsid *a,
+ const struct ceph_fsid *b)
+{
+ return memcmp(a, b, sizeof(*a));
+}
+
+/*
+ * ino, object, etc.
+ */
+typedef __le64 ceph_snapid_t;
+#define CEPH_SNAPDIR ((__u64)(-1)) /* reserved for hidden .snap dir */
+#define CEPH_NOSNAP ((__u64)(-2)) /* "head", "live" revision */
+#define CEPH_MAXSNAP ((__u64)(-3)) /* largest valid snapid */
+
+struct ceph_timespec {
+ __le32 tv_sec;
+ __le32 tv_nsec;
+} __attribute__ ((packed));
+
+
+/*
+ * object layout - how objects are mapped into PGs
+ */
+#define CEPH_OBJECT_LAYOUT_HASH 1
+#define CEPH_OBJECT_LAYOUT_LINEAR 2
+#define CEPH_OBJECT_LAYOUT_HASHINO 3
+
+/*
+ * pg layout -- how PGs are mapped onto (sets of) OSDs
+ */
+#define CEPH_PG_LAYOUT_CRUSH 0
+#define CEPH_PG_LAYOUT_HASH 1
+#define CEPH_PG_LAYOUT_LINEAR 2
+#define CEPH_PG_LAYOUT_HYBRID 3
+
+
+/*
+ * placement group.
+ * we encode this into one __le64.
+ */
+union ceph_pg {
+ __u64 pg64;
+ struct {
+ __s16 preferred; /* preferred primary osd */
+ __u16 ps; /* placement seed */
+ __u32 pool; /* object pool */
+ } __attribute__ ((packed)) pg;
+} __attribute__ ((packed));
+
+/*
+ * pg_pool is a set of pgs storing a pool of objects
+ *
+ * pg_num -- base number of pseudorandomly placed pgs
+ *
+ * pgp_num -- effective number when calculating pg placement. this
+ * is used for pg_num increases. new pgs result in data being "split"
+ * into new pgs. for this to proceed smoothly, new pgs are intiially
+ * colocated with their parents; that is, pgp_num doesn't increase
+ * until the new pgs have successfully split. only _then_ are the new
+ * pgs placed independently.
+ *
+ * lpg_num -- localized pg count (per device). replicas are randomly
+ * selected.
+ *
+ * lpgp_num -- as above.
+ */
+#define CEPH_PG_TYPE_REP 1
+#define CEPH_PG_TYPE_RAID4 2
+struct ceph_pg_pool {
+ __u8 type; /* CEPH_PG_TYPE_* */
+ __u8 size; /* number of osds in each pg */
+ __u8 crush_ruleset; /* crush placement rule */
+ __le32 pg_num, pgp_num; /* number of pg's */
+ __le32 lpg_num, lpgp_num; /* number of localized pg's */
+ __le32 last_change; /* most recent epoch changed */
+ __le64 snap_seq; /* seq for per-pool snapshot */
+ __le32 snap_epoch; /* epoch of last snap */
+ __le32 num_snaps;
+ __le32 num_removed_snap_intervals;
+} __attribute__ ((packed));
+
+/*
+ * stable_mod func is used to control number of placement groups.
+ * similar to straight-up modulo, but produces a stable mapping as b
+ * increases over time. b is the number of bins, and bmask is the
+ * containing power of 2 minus 1.
+ *
+ * b <= bmask and bmask=(2**n)-1
+ * e.g., b=12 -> bmask=15, b=123 -> bmask=127
+ */
+static inline int ceph_stable_mod(int x, int b, int bmask)
+{
+ if ((x & bmask) < b)
+ return x & bmask;
+ else
+ return x & (bmask >> 1);
+}
+
+/*
+ * object layout - how a given object should be stored.
+ */
+struct ceph_object_layout {
+ __le64 ol_pgid; /* raw pg, with _full_ ps precision. */
+ __le32 ol_stripe_unit; /* for per-object parity, if any */
+} __attribute__ ((packed));
+
+/*
+ * compound epoch+version, used by storage layer to serialize mutations
+ */
+struct ceph_eversion {
+ __le32 epoch;
+ __le64 version;
+} __attribute__ ((packed));
+
+/*
+ * osd map bits
+ */
+
+/* status bits */
+#define CEPH_OSD_EXISTS 1
+#define CEPH_OSD_UP 2
+
+/* osd weights. fixed point value: 0x10000 == 1.0 ("in"), 0 == "out" */
+#define CEPH_OSD_IN 0x10000
+#define CEPH_OSD_OUT 0
+
+
+/*
+ * osd map flag bits
+ */
+#define CEPH_OSDMAP_NEARFULL (1<<0) /* sync writes (near ENOSPC) */
+#define CEPH_OSDMAP_FULL (1<<1) /* no data writes (ENOSPC) */
+#define CEPH_OSDMAP_PAUSERD (1<<2) /* pause all reads */
+#define CEPH_OSDMAP_PAUSEWR (1<<3) /* pause all writes */
+#define CEPH_OSDMAP_PAUSEREC (1<<4) /* pause recovery */
+
+/*
+ * osd ops
+ */
+#define CEPH_OSD_OP_MODE 0xf000
+#define CEPH_OSD_OP_MODE_RD 0x1000
+#define CEPH_OSD_OP_MODE_WR 0x2000
+#define CEPH_OSD_OP_MODE_RMW 0x3000
+#define CEPH_OSD_OP_MODE_SUB 0x4000
+#define CEPH_OSD_OP_MODE_EXEC 0x8000
+
+#define CEPH_OSD_OP_TYPE 0x0f00
+#define CEPH_OSD_OP_TYPE_LOCK 0x0100
+#define CEPH_OSD_OP_TYPE_DATA 0x0200
+#define CEPH_OSD_OP_TYPE_ATTR 0x0300
+#define CEPH_OSD_OP_TYPE_EXEC 0x0400
+#define CEPH_OSD_OP_TYPE_PG 0x0500
+
+enum {
+ /** data **/
+ /* read */
+ CEPH_OSD_OP_READ = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 1,
+ CEPH_OSD_OP_STAT = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 2,
+
+ /* fancy read */
+ CEPH_OSD_OP_MASKTRUNC = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 4,
+
+ /* write */
+ CEPH_OSD_OP_WRITE = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 1,
+ CEPH_OSD_OP_WRITEFULL = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 2,
+ CEPH_OSD_OP_TRUNCATE = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 3,
+ CEPH_OSD_OP_ZERO = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 4,
+ CEPH_OSD_OP_DELETE = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 5,
+
+ /* fancy write */
+ CEPH_OSD_OP_APPEND = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 6,
+ CEPH_OSD_OP_STARTSYNC = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 7,
+ CEPH_OSD_OP_SETTRUNC = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 8,
+ CEPH_OSD_OP_TRIMTRUNC = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 9,
+
+ CEPH_OSD_OP_TMAPUP = CEPH_OSD_OP_MODE_RMW | CEPH_OSD_OP_TYPE_DATA | 10,
+ CEPH_OSD_OP_TMAPPUT = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 11,
+ CEPH_OSD_OP_TMAPGET = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 12,
+
+ CEPH_OSD_OP_CREATE = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 13,
+
+ /** attrs **/
+ /* read */
+ CEPH_OSD_OP_GETXATTR = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_ATTR | 1,
+ CEPH_OSD_OP_GETXATTRS = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_ATTR | 2,
+
+ /* write */
+ CEPH_OSD_OP_SETXATTR = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_ATTR | 1,
+ CEPH_OSD_OP_SETXATTRS = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_ATTR | 2,
+ CEPH_OSD_OP_RESETXATTRS = CEPH_OSD_OP_MODE_WR|CEPH_OSD_OP_TYPE_ATTR | 3,
+ CEPH_OSD_OP_RMXATTR = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_ATTR | 4,
+
+ /** subop **/
+ CEPH_OSD_OP_PULL = CEPH_OSD_OP_MODE_SUB | 1,
+ CEPH_OSD_OP_PUSH = CEPH_OSD_OP_MODE_SUB | 2,
+ CEPH_OSD_OP_BALANCEREADS = CEPH_OSD_OP_MODE_SUB | 3,
+ CEPH_OSD_OP_UNBALANCEREADS = CEPH_OSD_OP_MODE_SUB | 4,
+ CEPH_OSD_OP_SCRUB = CEPH_OSD_OP_MODE_SUB | 5,
+
+ /** lock **/
+ CEPH_OSD_OP_WRLOCK = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 1,
+ CEPH_OSD_OP_WRUNLOCK = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 2,
+ CEPH_OSD_OP_RDLOCK = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 3,
+ CEPH_OSD_OP_RDUNLOCK = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 4,
+ CEPH_OSD_OP_UPLOCK = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 5,
+ CEPH_OSD_OP_DNLOCK = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 6,
+
+ /** exec **/
+ CEPH_OSD_OP_CALL = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_EXEC | 1,
+
+ /** pg **/
+ CEPH_OSD_OP_PGLS = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_PG | 1,
+};
+
+static inline int ceph_osd_op_type_lock(int op)
+{
+ return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_LOCK;
+}
+static inline int ceph_osd_op_type_data(int op)
+{
+ return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_DATA;
+}
+static inline int ceph_osd_op_type_attr(int op)
+{
+ return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_ATTR;
+}
+static inline int ceph_osd_op_type_exec(int op)
+{
+ return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_EXEC;
+}
+static inline int ceph_osd_op_type_pg(int op)
+{
+ return (op & CEPH_OSD_OP_TYPE) == CEPH_OSD_OP_TYPE_PG;
+}
+
+static inline int ceph_osd_op_mode_subop(int op)
+{
+ return (op & CEPH_OSD_OP_MODE) == CEPH_OSD_OP_MODE_SUB;
+}
+static inline int ceph_osd_op_mode_read(int op)
+{
+ return (op & CEPH_OSD_OP_MODE) == CEPH_OSD_OP_MODE_RD;
+}
+static inline int ceph_osd_op_mode_modify(int op)
+{
+ return (op & CEPH_OSD_OP_MODE) == CEPH_OSD_OP_MODE_WR;
+}
+
+#define CEPH_OSD_TMAP_HDR 'h'
+#define CEPH_OSD_TMAP_SET 's'
+#define CEPH_OSD_TMAP_RM 'r'
+
+extern const char *ceph_osd_op_name(int op);
+
+
+/*
+ * osd op flags
+ *
+ * An op may be READ, WRITE, or READ|WRITE.
+ */
+enum {
+ CEPH_OSD_FLAG_ACK = 1, /* want (or is) "ack" ack */
+ CEPH_OSD_FLAG_ONNVRAM = 2, /* want (or is) "onnvram" ack */
+ CEPH_OSD_FLAG_ONDISK = 4, /* want (or is) "ondisk" ack */
+ CEPH_OSD_FLAG_RETRY = 8, /* resend attempt */
+ CEPH_OSD_FLAG_READ = 16, /* op may read */
+ CEPH_OSD_FLAG_WRITE = 32, /* op may write */
+ CEPH_OSD_FLAG_ORDERSNAP = 64, /* EOLDSNAP if snapc is out of order */
+ CEPH_OSD_FLAG_PEERSTAT = 128, /* msg includes osd_peer_stat */
+ CEPH_OSD_FLAG_BALANCE_READS = 256,
+ CEPH_OSD_FLAG_PARALLELEXEC = 512, /* execute op in parallel */
+ CEPH_OSD_FLAG_PGOP = 1024, /* pg op, no object */
+};
+
+enum {
+ CEPH_OSD_OP_FLAG_EXCL = 1, /* EXCL object create */
+};
+
+#define EOLDSNAPC ERESTART /* ORDERSNAP flag set; writer has old snapc*/
+#define EBLACKLISTED ESHUTDOWN /* blacklisted */
+
+/*
+ * an individual object operation. each may be accompanied by some data
+ * payload
+ */
+struct ceph_osd_op {
+ __le16 op; /* CEPH_OSD_OP_* */
+ __le32 flags; /* CEPH_OSD_FLAG_* */
+ union {
+ struct {
+ __le64 offset, length;
+ } __attribute__ ((packed)) extent;
+ struct {
+ __le32 name_len;
+ __le32 value_len;
+ } __attribute__ ((packed)) xattr;
+ struct {
+ __le64 truncate_size;
+ __le32 truncate_seq;
+ } __attribute__ ((packed)) trunc;
+ struct {
+ __u8 class_len;
+ __u8 method_len;
+ __u8 argc;
+ __le32 indata_len;
+ } __attribute__ ((packed)) cls;
+ struct {
+ __le64 cookie, count;
+ } __attribute__ ((packed)) pgls;
+ };
+ __le32 payload_len;
+} __attribute__ ((packed));
+
+/*
+ * osd request message header. each request may include multiple
+ * ceph_osd_op object operations.
+ */
+struct ceph_osd_request_head {
+ __le64 tid; /* transaction id */
+ __le32 client_inc; /* client incarnation */
+ struct ceph_object_layout layout; /* pgid */
+ __le32 osdmap_epoch; /* client's osdmap epoch */
+
+ __le32 flags;
+
+ struct ceph_timespec mtime; /* for mutations only */
+ struct ceph_eversion reassert_version; /* if we are replaying op */
+
+ __le32 object_len; /* length of object name */
+
+ __le64 snapid; /* snapid to read */
+ __le64 snap_seq; /* writer's snap context */
+ __le32 num_snaps;
+
+ __le16 num_ops;
+ struct ceph_osd_op ops[]; /* followed by ops[], obj, ticket, snaps */
+} __attribute__ ((packed));
+
+struct ceph_osd_reply_head {
+ __le64 tid; /* transaction id */
+ __le32 client_inc; /* client incarnation */
+ __le32 flags;
+ struct ceph_object_layout layout;
+ __le32 osdmap_epoch;
+ struct ceph_eversion reassert_version; /* for replaying uncommitted */
+
+ __le32 result; /* result code */
+
+ __le32 object_len; /* length of object name */
+ __le32 num_ops;
+ struct ceph_osd_op ops[0]; /* ops[], object */
+} __attribute__ ((packed));
+
+
+#endif
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c
new file mode 100644
index 000000000000..2e3cb40b7e48
--- /dev/null
+++ b/fs/ceph/snap.c
@@ -0,0 +1,897 @@
+#include "ceph_debug.h"
+
+#include <linux/radix-tree.h>
+#include <linux/sort.h>
+
+#include "super.h"
+#include "decode.h"
+
+/*
+ * Snapshots in ceph are driven in large part by cooperation from the
+ * client. In contrast to local file systems or file servers that
+ * implement snapshots at a single point in the system, ceph's
+ * distributed access to storage requires clients to help decide
+ * whether a write logically occurs before or after a recently created
+ * snapshot.
+ *
+ * This provides a perfect instantanous client-wide snapshot. Between
+ * clients, however, snapshots may appear to be applied at slightly
+ * different points in time, depending on delays in delivering the
+ * snapshot notification.
+ *
+ * Snapshots are _not_ file system-wide. Instead, each snapshot
+ * applies to the subdirectory nested beneath some directory. This
+ * effectively divides the hierarchy into multiple "realms," where all
+ * of the files contained by each realm share the same set of
+ * snapshots. An individual realm's snap set contains snapshots
+ * explicitly created on that realm, as well as any snaps in its
+ * parent's snap set _after_ the point at which the parent became it's
+ * parent (due to, say, a rename). Similarly, snaps from prior parents
+ * during the time intervals during which they were the parent are included.
+ *
+ * The client is spared most of this detail, fortunately... it must only
+ * maintains a hierarchy of realms reflecting the current parent/child
+ * realm relationship, and for each realm has an explicit list of snaps
+ * inherited from prior parents.
+ *
+ * A snap_realm struct is maintained for realms containing every inode
+ * with an open cap in the system. (The needed snap realm information is
+ * provided by the MDS whenever a cap is issued, i.e., on open.) A 'seq'
+ * version number is used to ensure that as realm parameters change (new
+ * snapshot, new parent, etc.) the client's realm hierarchy is updated.
+ *
+ * The realm hierarchy drives the generation of a 'snap context' for each
+ * realm, which simply lists the resulting set of snaps for the realm. This
+ * is attached to any writes sent to OSDs.
+ */
+/*
+ * Unfortunately error handling is a bit mixed here. If we get a snap
+ * update, but don't have enough memory to update our realm hierarchy,
+ * it's not clear what we can do about it (besides complaining to the
+ * console).
+ */
+
+
+/*
+ * increase ref count for the realm
+ *
+ * caller must hold snap_rwsem for write.
+ */
+void ceph_get_snap_realm(struct ceph_mds_client *mdsc,
+ struct ceph_snap_realm *realm)
+{
+ dout("get_realm %p %d -> %d\n", realm,
+ atomic_read(&realm->nref), atomic_read(&realm->nref)+1);
+ /*
+ * since we _only_ increment realm refs or empty the empty
+ * list with snap_rwsem held, adjusting the empty list here is
+ * safe. we do need to protect against concurrent empty list
+ * additions, however.
+ */
+ if (atomic_read(&realm->nref) == 0) {
+ spin_lock(&mdsc->snap_empty_lock);
+ list_del_init(&realm->empty_item);
+ spin_unlock(&mdsc->snap_empty_lock);
+ }
+
+ atomic_inc(&realm->nref);
+}
+
+/*
+ * create and get the realm rooted at @ino and bump its ref count.
+ *
+ * caller must hold snap_rwsem for write.
+ */
+static struct ceph_snap_realm *ceph_create_snap_realm(
+ struct ceph_mds_client *mdsc,
+ u64 ino)
+{
+ struct ceph_snap_realm *realm;
+
+ realm = kzalloc(sizeof(*realm), GFP_NOFS);
+ if (!realm)
+ return ERR_PTR(-ENOMEM);
+
+ radix_tree_insert(&mdsc->snap_realms, ino, realm);
+
+ atomic_set(&realm->nref, 0); /* tree does not take a ref */
+ realm->ino = ino;
+ INIT_LIST_HEAD(&realm->children);
+ INIT_LIST_HEAD(&realm->child_item);
+ INIT_LIST_HEAD(&realm->empty_item);
+ INIT_LIST_HEAD(&realm->inodes_with_caps);
+ spin_lock_init(&realm->inodes_with_caps_lock);
+ dout("create_snap_realm %llx %p\n", realm->ino, realm);
+ return realm;
+}
+
+/*
+ * find and get (if found) the realm rooted at @ino and bump its ref count.
+ *
+ * caller must hold snap_rwsem for write.
+ */
+struct ceph_snap_realm *ceph_lookup_snap_realm(struct ceph_mds_client *mdsc,
+ u64 ino)
+{
+ struct ceph_snap_realm *realm;
+
+ realm = radix_tree_lookup(&mdsc->snap_realms, ino);
+ if (realm)
+ dout("lookup_snap_realm %llx %p\n", realm->ino, realm);
+ return realm;
+}
+
+static void __put_snap_realm(struct ceph_mds_client *mdsc,
+ struct ceph_snap_realm *realm);
+
+/*
+ * called with snap_rwsem (write)
+ */
+static void __destroy_snap_realm(struct ceph_mds_client *mdsc,
+ struct ceph_snap_realm *realm)
+{
+ dout("__destroy_snap_realm %p %llx\n", realm, realm->ino);
+
+ radix_tree_delete(&mdsc->snap_realms, realm->ino);
+
+ if (realm->parent) {
+ list_del_init(&realm->child_item);
+ __put_snap_realm(mdsc, realm->parent);
+ }
+
+ kfree(realm->prior_parent_snaps);
+ kfree(realm->snaps);
+ ceph_put_snap_context(realm->cached_context);
+ kfree(realm);
+}
+
+/*
+ * caller holds snap_rwsem (write)
+ */
+static void __put_snap_realm(struct ceph_mds_client *mdsc,
+ struct ceph_snap_realm *realm)
+{
+ dout("__put_snap_realm %llx %p %d -> %d\n", realm->ino, realm,
+ atomic_read(&realm->nref), atomic_read(&realm->nref)-1);
+ if (atomic_dec_and_test(&realm->nref))
+ __destroy_snap_realm(mdsc, realm);
+}
+
+/*
+ * caller needn't hold any locks
+ */
+void ceph_put_snap_realm(struct ceph_mds_client *mdsc,
+ struct ceph_snap_realm *realm)
+{
+ dout("put_snap_realm %llx %p %d -> %d\n", realm->ino, realm,
+ atomic_read(&realm->nref), atomic_read(&realm->nref)-1);
+ if (!atomic_dec_and_test(&realm->nref))
+ return;
+
+ if (down_write_trylock(&mdsc->snap_rwsem)) {
+ __destroy_snap_realm(mdsc, realm);
+ up_write(&mdsc->snap_rwsem);
+ } else {
+ spin_lock(&mdsc->snap_empty_lock);
+ list_add(&mdsc->snap_empty, &realm->empty_item);
+ spin_unlock(&mdsc->snap_empty_lock);
+ }
+}
+
+/*
+ * Clean up any realms whose ref counts have dropped to zero. Note
+ * that this does not include realms who were created but not yet
+ * used.
+ *
+ * Called under snap_rwsem (write)
+ */
+static void __cleanup_empty_realms(struct ceph_mds_client *mdsc)
+{
+ struct ceph_snap_realm *realm;
+
+ spin_lock(&mdsc->snap_empty_lock);
+ while (!list_empty(&mdsc->snap_empty)) {
+ realm = list_first_entry(&mdsc->snap_empty,
+ struct ceph_snap_realm, empty_item);
+ list_del(&realm->empty_item);
+ spin_unlock(&mdsc->snap_empty_lock);
+ __destroy_snap_realm(mdsc, realm);
+ spin_lock(&mdsc->snap_empty_lock);
+ }
+ spin_unlock(&mdsc->snap_empty_lock);
+}
+
+void ceph_cleanup_empty_realms(struct ceph_mds_client *mdsc)
+{
+ down_write(&mdsc->snap_rwsem);
+ __cleanup_empty_realms(mdsc);
+ up_write(&mdsc->snap_rwsem);
+}
+
+/*
+ * adjust the parent realm of a given @realm. adjust child list, and parent
+ * pointers, and ref counts appropriately.
+ *
+ * return true if parent was changed, 0 if unchanged, <0 on error.
+ *
+ * caller must hold snap_rwsem for write.
+ */
+static int adjust_snap_realm_parent(struct ceph_mds_client *mdsc,
+ struct ceph_snap_realm *realm,
+ u64 parentino)
+{
+ struct ceph_snap_realm *parent;
+
+ if (realm->parent_ino == parentino)
+ return 0;
+
+ parent = ceph_lookup_snap_realm(mdsc, parentino);
+ if (IS_ERR(parent))
+ return PTR_ERR(parent);
+ if (!parent) {
+ parent = ceph_create_snap_realm(mdsc, parentino);
+ if (IS_ERR(parent))
+ return PTR_ERR(parent);
+ }
+ dout("adjust_snap_realm_parent %llx %p: %llx %p -> %llx %p\n",
+ realm->ino, realm, realm->parent_ino, realm->parent,
+ parentino, parent);
+ if (realm->parent) {
+ list_del_init(&realm->child_item);
+ ceph_put_snap_realm(mdsc, realm->parent);
+ }
+ realm->parent_ino = parentino;
+ realm->parent = parent;
+ ceph_get_snap_realm(mdsc, parent);
+ list_add(&realm->child_item, &parent->children);
+ return 1;
+}
+
+
+static int cmpu64_rev(const void *a, const void *b)
+{
+ if (*(u64 *)a < *(u64 *)b)
+ return 1;
+ if (*(u64 *)a > *(u64 *)b)
+ return -1;
+ return 0;
+}
+
+/*
+ * build the snap context for a given realm.
+ */
+static int build_snap_context(struct ceph_snap_realm *realm)
+{
+ struct ceph_snap_realm *parent = realm->parent;
+ struct ceph_snap_context *snapc;
+ int err = 0;
+ int i;
+ int num = realm->num_prior_parent_snaps + realm->num_snaps;
+
+ /*
+ * build parent context, if it hasn't been built.
+ * conservatively estimate that all parent snaps might be
+ * included by us.
+ */
+ if (parent) {
+ if (!parent->cached_context) {
+ err = build_snap_context(parent);
+ if (err)
+ goto fail;
+ }
+ num += parent->cached_context->num_snaps;
+ }
+
+ /* do i actually need to update? not if my context seq
+ matches realm seq, and my parents' does to. (this works
+ because we rebuild_snap_realms() works _downward_ in
+ hierarchy after each update.) */
+ if (realm->cached_context &&
+ realm->cached_context->seq <= realm->seq &&
+ (!parent ||
+ realm->cached_context->seq <= parent->cached_context->seq)) {
+ dout("build_snap_context %llx %p: %p seq %lld (%d snaps)"
+ " (unchanged)\n",
+ realm->ino, realm, realm->cached_context,
+ realm->cached_context->seq,
+ realm->cached_context->num_snaps);
+ return 0;
+ }
+
+ /* alloc new snap context */
+ err = -ENOMEM;
+ if (num > ULONG_MAX / sizeof(u64) - sizeof(*snapc))
+ goto fail;
+ snapc = kzalloc(sizeof(*snapc) + num*sizeof(u64), GFP_NOFS);
+ if (!snapc)
+ goto fail;
+ atomic_set(&snapc->nref, 1);
+
+ /* build (reverse sorted) snap vector */
+ num = 0;
+ snapc->seq = realm->seq;
+ if (parent) {
+ /* include any of parent's snaps occuring _after_ my
+ parent became my parent */
+ for (i = 0; i < parent->cached_context->num_snaps; i++)
+ if (parent->cached_context->snaps[i] >=
+ realm->parent_since)
+ snapc->snaps[num++] =
+ parent->cached_context->snaps[i];
+ if (parent->cached_context->seq > snapc->seq)
+ snapc->seq = parent->cached_context->seq;
+ }
+ memcpy(snapc->snaps + num, realm->snaps,
+ sizeof(u64)*realm->num_snaps);
+ num += realm->num_snaps;
+ memcpy(snapc->snaps + num, realm->prior_parent_snaps,
+ sizeof(u64)*realm->num_prior_parent_snaps);
+ num += realm->num_prior_parent_snaps;
+
+ sort(snapc->snaps, num, sizeof(u64), cmpu64_rev, NULL);
+ snapc->num_snaps = num;
+ dout("build_snap_context %llx %p: %p seq %lld (%d snaps)\n",
+ realm->ino, realm, snapc, snapc->seq, snapc->num_snaps);
+
+ if (realm->cached_context)
+ ceph_put_snap_context(realm->cached_context);
+ realm->cached_context = snapc;
+ return 0;
+
+fail:
+ /*
+ * if we fail, clear old (incorrect) cached_context... hopefully
+ * we'll have better luck building it later
+ */
+ if (realm->cached_context) {
+ ceph_put_snap_context(realm->cached_context);
+ realm->cached_context = NULL;
+ }
+ pr_err("build_snap_context %llx %p fail %d\n", realm->ino,
+ realm, err);
+ return err;
+}
+
+/*
+ * rebuild snap context for the given realm and all of its children.
+ */
+static void rebuild_snap_realms(struct ceph_snap_realm *realm)
+{
+ struct ceph_snap_realm *child;
+
+ dout("rebuild_snap_realms %llx %p\n", realm->ino, realm);
+ build_snap_context(realm);
+
+ list_for_each_entry(child, &realm->children, child_item)
+ rebuild_snap_realms(child);
+}
+
+
+/*
+ * helper to allocate and decode an array of snapids. free prior
+ * instance, if any.
+ */
+static int dup_array(u64 **dst, __le64 *src, int num)
+{
+ int i;
+
+ kfree(*dst);
+ if (num) {
+ *dst = kcalloc(num, sizeof(u64), GFP_NOFS);
+ if (!*dst)
+ return -ENOMEM;
+ for (i = 0; i < num; i++)
+ (*dst)[i] = get_unaligned_le64(src + i);
+ } else {
+ *dst = NULL;
+ }
+ return 0;
+}
+
+
+/*
+ * When a snapshot is applied, the size/mtime inode metadata is queued
+ * in a ceph_cap_snap (one for each snapshot) until writeback
+ * completes and the metadata can be flushed back to the MDS.
+ *
+ * However, if a (sync) write is currently in-progress when we apply
+ * the snapshot, we have to wait until the write succeeds or fails
+ * (and a final size/mtime is known). In this case the
+ * cap_snap->writing = 1, and is said to be "pending." When the write
+ * finishes, we __ceph_finish_cap_snap().
+ *
+ * Caller must hold snap_rwsem for read (i.e., the realm topology won't
+ * change).
+ */
+void ceph_queue_cap_snap(struct ceph_inode_info *ci,
+ struct ceph_snap_context *snapc)
+{
+ struct inode *inode = &ci->vfs_inode;
+ struct ceph_cap_snap *capsnap;
+ int used;
+
+ capsnap = kzalloc(sizeof(*capsnap), GFP_NOFS);
+ if (!capsnap) {
+ pr_err("ENOMEM allocating ceph_cap_snap on %p\n", inode);
+ return;
+ }
+
+ spin_lock(&inode->i_lock);
+ used = __ceph_caps_used(ci);
+ if (__ceph_have_pending_cap_snap(ci)) {
+ /* there is no point in queuing multiple "pending" cap_snaps,
+ as no new writes are allowed to start when pending, so any
+ writes in progress now were started before the previous
+ cap_snap. lucky us. */
+ dout("queue_cap_snap %p snapc %p seq %llu used %d"
+ " already pending\n", inode, snapc, snapc->seq, used);
+ kfree(capsnap);
+ } else if (ci->i_wrbuffer_ref_head || (used & CEPH_CAP_FILE_WR)) {
+ igrab(inode);
+
+ atomic_set(&capsnap->nref, 1);
+ capsnap->ci = ci;
+ INIT_LIST_HEAD(&capsnap->ci_item);
+ INIT_LIST_HEAD(&capsnap->flushing_item);
+
+ capsnap->follows = snapc->seq - 1;
+ capsnap->context = ceph_get_snap_context(snapc);
+ capsnap->issued = __ceph_caps_issued(ci, NULL);
+ capsnap->dirty = __ceph_caps_dirty(ci);
+
+ capsnap->mode = inode->i_mode;
+ capsnap->uid = inode->i_uid;
+ capsnap->gid = inode->i_gid;
+
+ /* fixme? */
+ capsnap->xattr_blob = NULL;
+ capsnap->xattr_len = 0;
+
+ /* dirty page count moved from _head to this cap_snap;
+ all subsequent writes page dirties occur _after_ this
+ snapshot. */
+ capsnap->dirty_pages = ci->i_wrbuffer_ref_head;
+ ci->i_wrbuffer_ref_head = 0;
+ ceph_put_snap_context(ci->i_head_snapc);
+ ci->i_head_snapc = NULL;
+ list_add_tail(&capsnap->ci_item, &ci->i_cap_snaps);
+
+ if (used & CEPH_CAP_FILE_WR) {
+ dout("queue_cap_snap %p cap_snap %p snapc %p"
+ " seq %llu used WR, now pending\n", inode,
+ capsnap, snapc, snapc->seq);
+ capsnap->writing = 1;
+ } else {
+ /* note mtime, size NOW. */
+ __ceph_finish_cap_snap(ci, capsnap);
+ }
+ } else {
+ dout("queue_cap_snap %p nothing dirty|writing\n", inode);
+ kfree(capsnap);
+ }
+
+ spin_unlock(&inode->i_lock);
+}
+
+/*
+ * Finalize the size, mtime for a cap_snap.. that is, settle on final values
+ * to be used for the snapshot, to be flushed back to the mds.
+ *
+ * If capsnap can now be flushed, add to snap_flush list, and return 1.
+ *
+ * Caller must hold i_lock.
+ */
+int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
+ struct ceph_cap_snap *capsnap)
+{
+ struct inode *inode = &ci->vfs_inode;
+ struct ceph_mds_client *mdsc = &ceph_client(inode->i_sb)->mdsc;
+
+ BUG_ON(capsnap->writing);
+ capsnap->size = inode->i_size;
+ capsnap->mtime = inode->i_mtime;
+ capsnap->atime = inode->i_atime;
+ capsnap->ctime = inode->i_ctime;
+ capsnap->time_warp_seq = ci->i_time_warp_seq;
+ if (capsnap->dirty_pages) {
+ dout("finish_cap_snap %p cap_snap %p snapc %p %llu s=%llu "
+ "still has %d dirty pages\n", inode, capsnap,
+ capsnap->context, capsnap->context->seq,
+ capsnap->size, capsnap->dirty_pages);
+ return 0;
+ }
+ dout("finish_cap_snap %p cap_snap %p snapc %p %llu s=%llu clean\n",
+ inode, capsnap, capsnap->context,
+ capsnap->context->seq, capsnap->size);
+
+ spin_lock(&mdsc->snap_flush_lock);
+ list_add_tail(&ci->i_snap_flush_item, &mdsc->snap_flush_list);
+ spin_unlock(&mdsc->snap_flush_lock);
+ return 1; /* caller may want to ceph_flush_snaps */
+}
+
+
+/*
+ * Parse and apply a snapblob "snap trace" from the MDS. This specifies
+ * the snap realm parameters from a given realm and all of its ancestors,
+ * up to the root.
+ *
+ * Caller must hold snap_rwsem for write.
+ */
+int ceph_update_snap_trace(struct ceph_mds_client *mdsc,
+ void *p, void *e, bool deletion)
+{
+ struct ceph_mds_snap_realm *ri; /* encoded */
+ __le64 *snaps; /* encoded */
+ __le64 *prior_parent_snaps; /* encoded */
+ struct ceph_snap_realm *realm;
+ int invalidate = 0;
+ int err = -ENOMEM;
+
+ dout("update_snap_trace deletion=%d\n", deletion);
+more:
+ ceph_decode_need(&p, e, sizeof(*ri), bad);
+ ri = p;
+ p += sizeof(*ri);
+ ceph_decode_need(&p, e, sizeof(u64)*(le32_to_cpu(ri->num_snaps) +
+ le32_to_cpu(ri->num_prior_parent_snaps)), bad);
+ snaps = p;
+ p += sizeof(u64) * le32_to_cpu(ri->num_snaps);
+ prior_parent_snaps = p;
+ p += sizeof(u64) * le32_to_cpu(ri->num_prior_parent_snaps);
+
+ realm = ceph_lookup_snap_realm(mdsc, le64_to_cpu(ri->ino));
+ if (IS_ERR(realm)) {
+ err = PTR_ERR(realm);
+ goto fail;
+ }
+ if (!realm) {
+ realm = ceph_create_snap_realm(mdsc, le64_to_cpu(ri->ino));
+ if (IS_ERR(realm)) {
+ err = PTR_ERR(realm);
+ goto fail;
+ }
+ }
+
+ if (le64_to_cpu(ri->seq) > realm->seq) {
+ dout("update_snap_trace updating %llx %p %lld -> %lld\n",
+ realm->ino, realm, realm->seq, le64_to_cpu(ri->seq));
+ /*
+ * if the realm seq has changed, queue a cap_snap for every
+ * inode with open caps. we do this _before_ we update
+ * the realm info so that we prepare for writeback under the
+ * _previous_ snap context.
+ *
+ * ...unless it's a snap deletion!
+ */
+ if (!deletion) {
+ struct ceph_inode_info *ci;
+ struct inode *lastinode = NULL;
+
+ spin_lock(&realm->inodes_with_caps_lock);
+ list_for_each_entry(ci, &realm->inodes_with_caps,
+ i_snap_realm_item) {
+ struct inode *inode = igrab(&ci->vfs_inode);
+ if (!inode)
+ continue;
+ spin_unlock(&realm->inodes_with_caps_lock);
+ if (lastinode)
+ iput(lastinode);
+ lastinode = inode;
+ ceph_queue_cap_snap(ci, realm->cached_context);
+ spin_lock(&realm->inodes_with_caps_lock);
+ }
+ spin_unlock(&realm->inodes_with_caps_lock);
+ if (lastinode)
+ iput(lastinode);
+ dout("update_snap_trace cap_snaps queued\n");
+ }
+
+ } else {
+ dout("update_snap_trace %llx %p seq %lld unchanged\n",
+ realm->ino, realm, realm->seq);
+ }
+
+ /* ensure the parent is correct */
+ err = adjust_snap_realm_parent(mdsc, realm, le64_to_cpu(ri->parent));
+ if (err < 0)
+ goto fail;
+ invalidate += err;
+
+ if (le64_to_cpu(ri->seq) > realm->seq) {
+ /* update realm parameters, snap lists */
+ realm->seq = le64_to_cpu(ri->seq);
+ realm->created = le64_to_cpu(ri->created);
+ realm->parent_since = le64_to_cpu(ri->parent_since);
+
+ realm->num_snaps = le32_to_cpu(ri->num_snaps);
+ err = dup_array(&realm->snaps, snaps, realm->num_snaps);
+ if (err < 0)
+ goto fail;
+
+ realm->num_prior_parent_snaps =
+ le32_to_cpu(ri->num_prior_parent_snaps);
+ err = dup_array(&realm->prior_parent_snaps, prior_parent_snaps,
+ realm->num_prior_parent_snaps);
+ if (err < 0)
+ goto fail;
+
+ invalidate = 1;
+ } else if (!realm->cached_context) {
+ invalidate = 1;
+ }
+
+ dout("done with %llx %p, invalidated=%d, %p %p\n", realm->ino,
+ realm, invalidate, p, e);
+
+ if (p < e)
+ goto more;
+
+ /* invalidate when we reach the _end_ (root) of the trace */
+ if (invalidate)
+ rebuild_snap_realms(realm);
+
+ __cleanup_empty_realms(mdsc);
+ return 0;
+
+bad:
+ err = -EINVAL;
+fail:
+ pr_err("update_snap_trace error %d\n", err);
+ return err;
+}
+
+
+/*
+ * Send any cap_snaps that are queued for flush. Try to carry
+ * s_mutex across multiple snap flushes to avoid locking overhead.
+ *
+ * Caller holds no locks.
+ */
+static void flush_snaps(struct ceph_mds_client *mdsc)
+{
+ struct ceph_inode_info *ci;
+ struct inode *inode;
+ struct ceph_mds_session *session = NULL;
+
+ dout("flush_snaps\n");
+ spin_lock(&mdsc->snap_flush_lock);
+ while (!list_empty(&mdsc->snap_flush_list)) {
+ ci = list_first_entry(&mdsc->snap_flush_list,
+ struct ceph_inode_info, i_snap_flush_item);
+ inode = &ci->vfs_inode;
+ igrab(inode);
+ spin_unlock(&mdsc->snap_flush_lock);
+ spin_lock(&inode->i_lock);
+ __ceph_flush_snaps(ci, &session);
+ spin_unlock(&inode->i_lock);
+ iput(inode);
+ spin_lock(&mdsc->snap_flush_lock);
+ }
+ spin_unlock(&mdsc->snap_flush_lock);
+
+ if (session) {
+ mutex_unlock(&session->s_mutex);
+ ceph_put_mds_session(session);
+ }
+ dout("flush_snaps done\n");
+}
+
+
+/*
+ * Handle a snap notification from the MDS.
+ *
+ * This can take two basic forms: the simplest is just a snap creation
+ * or deletion notification on an existing realm. This should update the
+ * realm and its children.
+ *
+ * The more difficult case is realm creation, due to snap creation at a
+ * new point in the file hierarchy, or due to a rename that moves a file or
+ * directory into another realm.
+ */
+void ceph_handle_snap(struct ceph_mds_client *mdsc,
+ struct ceph_msg *msg)
+{
+ struct super_block *sb = mdsc->client->sb;
+ struct ceph_mds_session *session;
+ int mds;
+ u64 split;
+ int op;
+ int trace_len;
+ struct ceph_snap_realm *realm = NULL;
+ void *p = msg->front.iov_base;
+ void *e = p + msg->front.iov_len;
+ struct ceph_mds_snap_head *h;
+ int num_split_inos, num_split_realms;
+ __le64 *split_inos = NULL, *split_realms = NULL;
+ int i;
+ int locked_rwsem = 0;
+
+ if (msg->hdr.src.name.type != CEPH_ENTITY_TYPE_MDS)
+ return;
+ mds = le64_to_cpu(msg->hdr.src.name.num);
+
+ /* decode */
+ if (msg->front.iov_len < sizeof(*h))
+ goto bad;
+ h = p;
+ op = le32_to_cpu(h->op);
+ split = le64_to_cpu(h->split); /* non-zero if we are splitting an
+ * existing realm */
+ num_split_inos = le32_to_cpu(h->num_split_inos);
+ num_split_realms = le32_to_cpu(h->num_split_realms);
+ trace_len = le32_to_cpu(h->trace_len);
+ p += sizeof(*h);
+
+ dout("handle_snap from mds%d op %s split %llx tracelen %d\n", mds,
+ ceph_snap_op_name(op), split, trace_len);
+
+ /* find session */
+ mutex_lock(&mdsc->mutex);
+ session = __ceph_lookup_mds_session(mdsc, mds);
+ mutex_unlock(&mdsc->mutex);
+ if (!session) {
+ dout("WTF, got snap but no session for mds%d\n", mds);
+ return;
+ }
+
+ mutex_lock(&session->s_mutex);
+ session->s_seq++;
+ mutex_unlock(&session->s_mutex);
+
+ down_write(&mdsc->snap_rwsem);
+ locked_rwsem = 1;
+
+ if (op == CEPH_SNAP_OP_SPLIT) {
+ struct ceph_mds_snap_realm *ri;
+
+ /*
+ * A "split" breaks part of an existing realm off into
+ * a new realm. The MDS provides a list of inodes
+ * (with caps) and child realms that belong to the new
+ * child.
+ */
+ split_inos = p;
+ p += sizeof(u64) * num_split_inos;
+ split_realms = p;
+ p += sizeof(u64) * num_split_realms;
+ ceph_decode_need(&p, e, sizeof(*ri), bad);
+ /* we will peek at realm info here, but will _not_
+ * advance p, as the realm update will occur below in
+ * ceph_update_snap_trace. */
+ ri = p;
+
+ realm = ceph_lookup_snap_realm(mdsc, split);
+ if (IS_ERR(realm))
+ goto out;
+ if (!realm) {
+ realm = ceph_create_snap_realm(mdsc, split);
+ if (IS_ERR(realm))
+ goto out;
+ }
+ ceph_get_snap_realm(mdsc, realm);
+
+ dout("splitting snap_realm %llx %p\n", realm->ino, realm);
+ for (i = 0; i < num_split_inos; i++) {
+ struct ceph_vino vino = {
+ .ino = le64_to_cpu(split_inos[i]),
+ .snap = CEPH_NOSNAP,
+ };
+ struct inode *inode = ceph_find_inode(sb, vino);
+ struct ceph_inode_info *ci;
+
+ if (!inode)
+ continue;
+ ci = ceph_inode(inode);
+
+ spin_lock(&inode->i_lock);
+ if (!ci->i_snap_realm)
+ goto skip_inode;
+ /*
+ * If this inode belongs to a realm that was
+ * created after our new realm, we experienced
+ * a race (due to another split notifications
+ * arriving from a different MDS). So skip
+ * this inode.
+ */
+ if (ci->i_snap_realm->created >
+ le64_to_cpu(ri->created)) {
+ dout(" leaving %p in newer realm %llx %p\n",
+ inode, ci->i_snap_realm->ino,
+ ci->i_snap_realm);
+ goto skip_inode;
+ }
+ dout(" will move %p to split realm %llx %p\n",
+ inode, realm->ino, realm);
+ /*
+ * Remove the inode from the realm's inode
+ * list, but don't add it to the new realm
+ * yet. We don't want the cap_snap to be
+ * queued (again) by ceph_update_snap_trace()
+ * below. Queue it _now_, under the old context.
+ */
+ list_del_init(&ci->i_snap_realm_item);
+ spin_unlock(&inode->i_lock);
+
+ ceph_queue_cap_snap(ci,
+ ci->i_snap_realm->cached_context);
+
+ iput(inode);
+ continue;
+
+skip_inode:
+ spin_unlock(&inode->i_lock);
+ iput(inode);
+ }
+
+ /* we may have taken some of the old realm's children. */
+ for (i = 0; i < num_split_realms; i++) {
+ struct ceph_snap_realm *child =
+ ceph_lookup_snap_realm(mdsc,
+ le64_to_cpu(split_realms[i]));
+ if (IS_ERR(child))
+ continue;
+ if (!child)
+ continue;
+ adjust_snap_realm_parent(mdsc, child, realm->ino);
+ }
+ }
+
+ /*
+ * update using the provided snap trace. if we are deleting a
+ * snap, we can avoid queueing cap_snaps.
+ */
+ ceph_update_snap_trace(mdsc, p, e,
+ op == CEPH_SNAP_OP_DESTROY);
+
+ if (op == CEPH_SNAP_OP_SPLIT) {
+ /*
+ * ok, _now_ add the inodes into the new realm.
+ */
+ for (i = 0; i < num_split_inos; i++) {
+ struct ceph_vino vino = {
+ .ino = le64_to_cpu(split_inos[i]),
+ .snap = CEPH_NOSNAP,
+ };
+ struct inode *inode = ceph_find_inode(sb, vino);
+ struct ceph_inode_info *ci;
+
+ if (!inode)
+ continue;
+ ci = ceph_inode(inode);
+ spin_lock(&inode->i_lock);
+ if (!ci->i_snap_realm)
+ goto split_skip_inode;
+ ceph_put_snap_realm(mdsc, ci->i_snap_realm);
+ spin_lock(&realm->inodes_with_caps_lock);
+ list_add(&ci->i_snap_realm_item,
+ &realm->inodes_with_caps);
+ ci->i_snap_realm = realm;
+ spin_unlock(&realm->inodes_with_caps_lock);
+ ceph_get_snap_realm(mdsc, realm);
+split_skip_inode:
+ spin_unlock(&inode->i_lock);
+ iput(inode);
+ }
+
+ /* we took a reference when we created the realm, above */
+ ceph_put_snap_realm(mdsc, realm);
+ }
+
+ __cleanup_empty_realms(mdsc);
+
+ up_write(&mdsc->snap_rwsem);
+
+ flush_snaps(mdsc);
+ return;
+
+bad:
+ pr_err("corrupt snap message from mds%d\n", mds);
+out:
+ if (locked_rwsem)
+ up_write(&mdsc->snap_rwsem);
+ return;
+}
+
+
+
diff --git a/fs/ceph/super.c b/fs/ceph/super.c
new file mode 100644
index 000000000000..924e6cad0b66
--- /dev/null
+++ b/fs/ceph/super.c
@@ -0,0 +1,947 @@
+
+#include "ceph_debug.h"
+
+#include <linux/backing-dev.h>
+#include <linux/fs.h>
+#include <linux/inet.h>
+#include <linux/in6.h>
+#include <linux/module.h>
+#include <linux/mount.h>
+#include <linux/parser.h>
+#include <linux/rwsem.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/statfs.h>
+#include <linux/string.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+
+#include "decode.h"
+#include "super.h"
+#include "mon_client.h"
+
+/*
+ * Ceph superblock operations
+ *
+ * Handle the basics of mounting, unmounting.
+ */
+
+
+/*
+ * find filename portion of a path (/foo/bar/baz -> baz)
+ */
+const char *ceph_file_part(const char *s, int len)
+{
+ const char *e = s + len;
+
+ while (e != s && *(e-1) != '/')
+ e--;
+ return e;
+}
+
+
+/*
+ * super ops
+ */
+static void ceph_put_super(struct super_block *s)
+{
+ struct ceph_client *cl = ceph_client(s);
+
+ dout("put_super\n");
+ ceph_mdsc_close_sessions(&cl->mdsc);
+ return;
+}
+
+static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+ struct ceph_client *client = ceph_inode_to_client(dentry->d_inode);
+ struct ceph_monmap *monmap = client->monc.monmap;
+ struct ceph_statfs st;
+ u64 fsid;
+ int err;
+
+ dout("statfs\n");
+ err = ceph_monc_do_statfs(&client->monc, &st);
+ if (err < 0)
+ return err;
+
+ /* fill in kstatfs */
+ buf->f_type = CEPH_SUPER_MAGIC; /* ?? */
+
+ /*
+ * express utilization in terms of large blocks to avoid
+ * overflow on 32-bit machines.
+ */
+ buf->f_bsize = 1 << CEPH_BLOCK_SHIFT;
+ buf->f_blocks = le64_to_cpu(st.kb) >> (CEPH_BLOCK_SHIFT-10);
+ buf->f_bfree = (le64_to_cpu(st.kb) - le64_to_cpu(st.kb_used)) >>
+ (CEPH_BLOCK_SHIFT-10);
+ buf->f_bavail = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10);
+
+ buf->f_files = le64_to_cpu(st.num_objects);
+ buf->f_ffree = -1;
+ buf->f_namelen = PATH_MAX;
+ buf->f_frsize = PAGE_CACHE_SIZE;
+
+ /* leave fsid little-endian, regardless of host endianness */
+ fsid = *(u64 *)(&monmap->fsid) ^ *((u64 *)&monmap->fsid + 1);
+ buf->f_fsid.val[0] = fsid & 0xffffffff;
+ buf->f_fsid.val[1] = fsid >> 32;
+
+ return 0;
+}
+
+
+static int ceph_syncfs(struct super_block *sb, int wait)
+{
+ dout("sync_fs %d\n", wait);
+ ceph_osdc_sync(&ceph_client(sb)->osdc);
+ ceph_mdsc_sync(&ceph_client(sb)->mdsc);
+ dout("sync_fs %d done\n", wait);
+ return 0;
+}
+
+
+/**
+ * ceph_show_options - Show mount options in /proc/mounts
+ * @m: seq_file to write to
+ * @mnt: mount descriptor
+ */
+static int ceph_show_options(struct seq_file *m, struct vfsmount *mnt)
+{
+ struct ceph_client *client = ceph_sb_to_client(mnt->mnt_sb);
+ struct ceph_mount_args *args = &client->mount_args;
+
+ if (args->flags & CEPH_OPT_FSID)
+ seq_printf(m, ",fsidmajor=%llu,fsidminor%llu",
+ le64_to_cpu(*(__le64 *)&args->fsid.fsid[0]),
+ le64_to_cpu(*(__le64 *)&args->fsid.fsid[8]));
+ if (args->flags & CEPH_OPT_NOSHARE)
+ seq_puts(m, ",noshare");
+ if (args->flags & CEPH_OPT_DIRSTAT)
+ seq_puts(m, ",dirstat");
+ if ((args->flags & CEPH_OPT_RBYTES) == 0)
+ seq_puts(m, ",norbytes");
+ if (args->flags & CEPH_OPT_NOCRC)
+ seq_puts(m, ",nocrc");
+ if (args->flags & CEPH_OPT_NOASYNCREADDIR)
+ seq_puts(m, ",noasyncreaddir");
+ if (strcmp(args->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT))
+ seq_printf(m, ",snapdirname=%s", args->snapdir_name);
+ if (args->secret)
+ seq_puts(m, ",secret=<hidden>");
+ return 0;
+}
+
+/*
+ * caches
+ */
+struct kmem_cache *ceph_inode_cachep;
+struct kmem_cache *ceph_cap_cachep;
+struct kmem_cache *ceph_dentry_cachep;
+struct kmem_cache *ceph_file_cachep;
+
+static void ceph_inode_init_once(void *foo)
+{
+ struct ceph_inode_info *ci = foo;
+ inode_init_once(&ci->vfs_inode);
+}
+
+static int __init init_caches(void)
+{
+ ceph_inode_cachep = kmem_cache_create("ceph_inode_info",
+ sizeof(struct ceph_inode_info),
+ __alignof__(struct ceph_inode_info),
+ (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD),
+ ceph_inode_init_once);
+ if (ceph_inode_cachep == NULL)
+ return -ENOMEM;
+
+ ceph_cap_cachep = KMEM_CACHE(ceph_cap,
+ SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
+ if (ceph_cap_cachep == NULL)
+ goto bad_cap;
+
+ ceph_dentry_cachep = KMEM_CACHE(ceph_dentry_info,
+ SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
+ if (ceph_dentry_cachep == NULL)
+ goto bad_dentry;
+
+ ceph_file_cachep = KMEM_CACHE(ceph_file_info,
+ SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
+ if (ceph_file_cachep == NULL)
+ goto bad_file;
+
+ return 0;
+
+bad_file:
+ kmem_cache_destroy(ceph_dentry_cachep);
+bad_dentry:
+ kmem_cache_destroy(ceph_cap_cachep);
+bad_cap:
+ kmem_cache_destroy(ceph_inode_cachep);
+ return -ENOMEM;
+}
+
+static void destroy_caches(void)
+{
+ kmem_cache_destroy(ceph_inode_cachep);
+ kmem_cache_destroy(ceph_cap_cachep);
+ kmem_cache_destroy(ceph_dentry_cachep);
+ kmem_cache_destroy(ceph_file_cachep);
+}
+
+
+/*
+ * ceph_umount_begin - initiate forced umount. Tear down down the
+ * mount, skipping steps that may hang while waiting for server(s).
+ */
+static void ceph_umount_begin(struct super_block *sb)
+{
+ struct ceph_client *client = ceph_sb_to_client(sb);
+
+ dout("ceph_umount_begin - starting forced umount\n");
+ if (!client)
+ return;
+ client->mount_state = CEPH_MOUNT_SHUTDOWN;
+ return;
+}
+
+static const struct super_operations ceph_super_ops = {
+ .alloc_inode = ceph_alloc_inode,
+ .destroy_inode = ceph_destroy_inode,
+ .write_inode = ceph_write_inode,
+ .sync_fs = ceph_syncfs,
+ .put_super = ceph_put_super,
+ .show_options = ceph_show_options,
+ .statfs = ceph_statfs,
+ .umount_begin = ceph_umount_begin,
+};
+
+
+const char *ceph_msg_type_name(int type)
+{
+ switch (type) {
+ case CEPH_MSG_SHUTDOWN: return "shutdown";
+ case CEPH_MSG_PING: return "ping";
+ case CEPH_MSG_MON_MAP: return "mon_map";
+ case CEPH_MSG_MON_GET_MAP: return "mon_get_map";
+ case CEPH_MSG_MON_SUBSCRIBE: return "mon_subscribe";
+ case CEPH_MSG_MON_SUBSCRIBE_ACK: return "mon_subscribe_ack";
+ case CEPH_MSG_CLIENT_MOUNT: return "client_mount";
+ case CEPH_MSG_CLIENT_MOUNT_ACK: return "client_mount_ack";
+ case CEPH_MSG_STATFS: return "statfs";
+ case CEPH_MSG_STATFS_REPLY: return "statfs_reply";
+ case CEPH_MSG_MDS_MAP: return "mds_map";
+ case CEPH_MSG_CLIENT_SESSION: return "client_session";
+ case CEPH_MSG_CLIENT_RECONNECT: return "client_reconnect";
+ case CEPH_MSG_CLIENT_REQUEST: return "client_request";
+ case CEPH_MSG_CLIENT_REQUEST_FORWARD: return "client_request_forward";
+ case CEPH_MSG_CLIENT_REPLY: return "client_reply";
+ case CEPH_MSG_CLIENT_CAPS: return "client_caps";
+ case CEPH_MSG_CLIENT_CAPRELEASE: return "client_cap_release";
+ case CEPH_MSG_CLIENT_SNAP: return "client_snap";
+ case CEPH_MSG_CLIENT_LEASE: return "client_lease";
+ case CEPH_MSG_OSD_MAP: return "osd_map";
+ case CEPH_MSG_OSD_OP: return "osd_op";
+ case CEPH_MSG_OSD_OPREPLY: return "osd_opreply";
+ default: return "unknown";
+ }
+}
+
+
+/*
+ * mount options
+ */
+enum {
+ Opt_fsidmajor,
+ Opt_fsidminor,
+ Opt_monport,
+ Opt_wsize,
+ Opt_rsize,
+ Opt_osdtimeout,
+ Opt_mount_timeout,
+ Opt_caps_wanted_delay_min,
+ Opt_caps_wanted_delay_max,
+ Opt_readdir_max_entries,
+ /* int args above */
+ Opt_snapdirname,
+ Opt_secret,
+ /* string args above */
+ Opt_ip,
+ Opt_noshare,
+ Opt_dirstat,
+ Opt_nodirstat,
+ Opt_rbytes,
+ Opt_norbytes,
+ Opt_nocrc,
+ Opt_noasyncreaddir,
+};
+
+static match_table_t arg_tokens = {
+ {Opt_fsidmajor, "fsidmajor=%ld"},
+ {Opt_fsidminor, "fsidminor=%ld"},
+ {Opt_monport, "monport=%d"},
+ {Opt_wsize, "wsize=%d"},
+ {Opt_rsize, "rsize=%d"},
+ {Opt_osdtimeout, "osdtimeout=%d"},
+ {Opt_mount_timeout, "mount_timeout=%d"},
+ {Opt_caps_wanted_delay_min, "caps_wanted_delay_min=%d"},
+ {Opt_caps_wanted_delay_max, "caps_wanted_delay_max=%d"},
+ {Opt_readdir_max_entries, "readdir_max_entries=%d"},
+ /* int args above */
+ {Opt_snapdirname, "snapdirname=%s"},
+ {Opt_secret, "secret=%s"},
+ /* string args above */
+ {Opt_ip, "ip=%s"},
+ {Opt_noshare, "noshare"},
+ {Opt_dirstat, "dirstat"},
+ {Opt_nodirstat, "nodirstat"},
+ {Opt_rbytes, "rbytes"},
+ {Opt_norbytes, "norbytes"},
+ {Opt_nocrc, "nocrc"},
+ {Opt_noasyncreaddir, "noasyncreaddir"},
+ {-1, NULL}
+};
+
+
+static int parse_mount_args(struct ceph_client *client,
+ int flags, char *options, const char *dev_name,
+ const char **path)
+{
+ struct ceph_mount_args *args = &client->mount_args;
+ const char *c;
+ int err;
+ substring_t argstr[MAX_OPT_ARGS];
+ int num_mon;
+ struct ceph_entity_addr *mon_addr;
+ int i;
+
+ dout("parse_mount_args dev_name '%s'\n", dev_name);
+ memset(args, 0, sizeof(*args));
+
+ mon_addr = kcalloc(CEPH_MAX_MON, sizeof(*mon_addr), GFP_KERNEL);
+ if (!mon_addr)
+ return -ENOMEM;
+
+ /* start with defaults */
+ args->sb_flags = flags;
+ args->flags = CEPH_OPT_DEFAULT;
+ args->osd_timeout = 5; /* seconds */
+ args->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT; /* seconds */
+ args->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT;
+ args->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT;
+ args->rsize = CEPH_MOUNT_RSIZE_DEFAULT;
+ args->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL);
+ args->cap_release_safety = CEPH_CAPS_PER_RELEASE * 4;
+ args->max_readdir = 1024;
+
+ /* ip1[:port1][,ip2[:port2]...]:/subdir/in/fs */
+ err = -EINVAL;
+ if (!dev_name)
+ goto out;
+ *path = strstr(dev_name, ":/");
+ if (*path == NULL) {
+ pr_err("device name is missing path (no :/ in %s)\n",
+ dev_name);
+ goto out;
+ }
+
+ /* get mon ip(s) */
+ err = ceph_parse_ips(dev_name, *path, mon_addr,
+ CEPH_MAX_MON, &num_mon);
+ if (err < 0)
+ goto out;
+
+ /* build initial monmap */
+ err = -ENOMEM;
+ client->monc.monmap = kzalloc(sizeof(*client->monc.monmap) +
+ num_mon*sizeof(client->monc.monmap->mon_inst[0]),
+ GFP_KERNEL);
+ if (!client->monc.monmap)
+ goto out;
+ for (i = 0; i < num_mon; i++) {
+ client->monc.monmap->mon_inst[i].addr = mon_addr[i];
+ client->monc.monmap->mon_inst[i].addr.erank = 0;
+ client->monc.monmap->mon_inst[i].addr.nonce = 0;
+ client->monc.monmap->mon_inst[i].name.type =
+ CEPH_ENTITY_TYPE_MON;
+ client->monc.monmap->mon_inst[i].name.num = cpu_to_le64(i);
+ }
+ client->monc.monmap->num_mon = num_mon;
+ memset(&args->my_addr.in_addr, 0, sizeof(args->my_addr.in_addr));
+
+ /* path on server */
+ *path += 2;
+ dout("server path '%s'\n", *path);
+
+ /* parse mount options */
+ while ((c = strsep(&options, ",")) != NULL) {
+ int token, intval, ret;
+ if (!*c)
+ continue;
+ err = -EINVAL;
+ token = match_token((char *)c, arg_tokens, argstr);
+ if (token < 0) {
+ pr_err("bad mount option at '%s'\n", c);
+ goto out;
+ }
+ if (token < Opt_ip) {
+ ret = match_int(&argstr[0], &intval);
+ if (ret < 0) {
+ pr_err("bad mount option arg (not int) "
+ "at '%s'\n", c);
+ continue;
+ }
+ dout("got token %d intval %d\n", token, intval);
+ }
+ switch (token) {
+ case Opt_fsidmajor:
+ *(__le64 *)&args->fsid.fsid[0] = cpu_to_le64(intval);
+ break;
+ case Opt_fsidminor:
+ *(__le64 *)&args->fsid.fsid[8] = cpu_to_le64(intval);
+ break;
+ case Opt_ip:
+ err = ceph_parse_ips(argstr[0].from,
+ argstr[0].to,
+ &args->my_addr,
+ 1, NULL);
+ if (err < 0)
+ return err;
+ args->flags |= CEPH_OPT_MYIP;
+ break;
+
+ case Opt_snapdirname:
+ kfree(args->snapdir_name);
+ args->snapdir_name = kstrndup(argstr[0].from,
+ argstr[0].to-argstr[0].from,
+ GFP_KERNEL);
+ break;
+ case Opt_secret:
+ args->secret = kstrndup(argstr[0].from,
+ argstr[0].to-argstr[0].from,
+ GFP_KERNEL);
+ break;
+
+ /* misc */
+ case Opt_wsize:
+ args->wsize = intval;
+ break;
+ case Opt_rsize:
+ args->rsize = intval;
+ break;
+ case Opt_osdtimeout:
+ args->osd_timeout = intval;
+ break;
+ case Opt_mount_timeout:
+ args->mount_timeout = intval;
+ break;
+ case Opt_caps_wanted_delay_min:
+ args->caps_wanted_delay_min = intval;
+ break;
+ case Opt_caps_wanted_delay_max:
+ args->caps_wanted_delay_max = intval;
+ break;
+ case Opt_readdir_max_entries:
+ args->max_readdir = intval;
+ break;
+
+ case Opt_noshare:
+ args->flags |= CEPH_OPT_NOSHARE;
+ break;
+
+ case Opt_dirstat:
+ args->flags |= CEPH_OPT_DIRSTAT;
+ break;
+ case Opt_nodirstat:
+ args->flags &= ~CEPH_OPT_DIRSTAT;
+ break;
+ case Opt_rbytes:
+ args->flags |= CEPH_OPT_RBYTES;
+ break;
+ case Opt_norbytes:
+ args->flags &= ~CEPH_OPT_RBYTES;
+ break;
+ case Opt_nocrc:
+ args->flags |= CEPH_OPT_NOCRC;
+ break;
+ case Opt_noasyncreaddir:
+ args->flags |= CEPH_OPT_NOASYNCREADDIR;
+ break;
+
+ default:
+ BUG_ON(token);
+ }
+ }
+ err = 0;
+
+out:
+ kfree(mon_addr);
+ return err;
+}
+
+static void release_mount_args(struct ceph_mount_args *args)
+{
+ kfree(args->snapdir_name);
+ args->snapdir_name = NULL;
+ kfree(args->secret);
+ args->secret = NULL;
+}
+
+/*
+ * create a fresh client instance
+ */
+static struct ceph_client *ceph_create_client(void)
+{
+ struct ceph_client *client;
+ int err = -ENOMEM;
+
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (client == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_init(&client->mount_mutex);
+
+ init_waitqueue_head(&client->mount_wq);
+
+ client->sb = NULL;
+ client->mount_state = CEPH_MOUNT_MOUNTING;
+ client->whoami = -1;
+
+ client->msgr = NULL;
+
+ client->mount_err = 0;
+ client->signed_ticket = NULL;
+ client->signed_ticket_len = 0;
+
+ err = -ENOMEM;
+ client->wb_wq = create_workqueue("ceph-writeback");
+ if (client->wb_wq == NULL)
+ goto fail;
+ client->pg_inv_wq = create_singlethread_workqueue("ceph-pg-invalid");
+ if (client->pg_inv_wq == NULL)
+ goto fail_wb_wq;
+ client->trunc_wq = create_singlethread_workqueue("ceph-trunc");
+ if (client->trunc_wq == NULL)
+ goto fail_pg_inv_wq;
+
+ /* subsystems */
+ err = ceph_monc_init(&client->monc, client);
+ if (err < 0)
+ goto fail_trunc_wq;
+ err = ceph_osdc_init(&client->osdc, client);
+ if (err < 0)
+ goto fail_monc;
+ ceph_mdsc_init(&client->mdsc, client);
+ return client;
+
+fail_monc:
+ ceph_monc_stop(&client->monc);
+fail_trunc_wq:
+ destroy_workqueue(client->trunc_wq);
+fail_pg_inv_wq:
+ destroy_workqueue(client->pg_inv_wq);
+fail_wb_wq:
+ destroy_workqueue(client->wb_wq);
+fail:
+ kfree(client);
+ return ERR_PTR(err);
+}
+
+static void ceph_destroy_client(struct ceph_client *client)
+{
+ dout("destroy_client %p\n", client);
+
+ /* unmount */
+ ceph_mdsc_stop(&client->mdsc);
+ ceph_monc_stop(&client->monc);
+ ceph_osdc_stop(&client->osdc);
+
+ kfree(client->signed_ticket);
+
+ ceph_debugfs_client_cleanup(client);
+ destroy_workqueue(client->wb_wq);
+ destroy_workqueue(client->pg_inv_wq);
+ destroy_workqueue(client->trunc_wq);
+
+ if (client->msgr)
+ ceph_messenger_destroy(client->msgr);
+ if (client->wb_pagevec_pool)
+ mempool_destroy(client->wb_pagevec_pool);
+
+ release_mount_args(&client->mount_args);
+
+ kfree(client);
+ dout("destroy_client %p done\n", client);
+}
+
+/*
+ * true if we have the mon map (and have thus joined the cluster)
+ */
+static int have_mon_map(struct ceph_client *client)
+{
+ return client->monc.monmap && client->monc.monmap->epoch;
+}
+
+/*
+ * Bootstrap mount by opening the root directory. Note the mount
+ * @started time from caller, and time out if this takes too long.
+ */
+static struct dentry *open_root_dentry(struct ceph_client *client,
+ const char *path,
+ unsigned long started)
+{
+ struct ceph_mds_client *mdsc = &client->mdsc;
+ struct ceph_mds_request *req = NULL;
+ int err;
+ struct dentry *root;
+
+ /* open dir */
+ dout("open_root_inode opening '%s'\n", path);
+ req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_GETATTR, USE_ANY_MDS);
+ if (IS_ERR(req))
+ return ERR_PTR(PTR_ERR(req));
+ req->r_path1 = kstrdup(path, GFP_NOFS);
+ req->r_ino1.ino = CEPH_INO_ROOT;
+ req->r_ino1.snap = CEPH_NOSNAP;
+ req->r_started = started;
+ req->r_timeout = client->mount_args.mount_timeout * HZ;
+ req->r_args.getattr.mask = cpu_to_le32(CEPH_STAT_CAP_INODE);
+ req->r_num_caps = 2;
+ err = ceph_mdsc_do_request(mdsc, NULL, req);
+ if (err == 0) {
+ dout("open_root_inode success\n");
+ if (ceph_ino(req->r_target_inode) == CEPH_INO_ROOT &&
+ client->sb->s_root == NULL)
+ root = d_alloc_root(req->r_target_inode);
+ else
+ root = d_obtain_alias(req->r_target_inode);
+ req->r_target_inode = NULL;
+ dout("open_root_inode success, root dentry is %p\n", root);
+ } else {
+ root = ERR_PTR(err);
+ }
+ ceph_mdsc_put_request(req);
+ return root;
+}
+
+/*
+ * mount: join the ceph cluster, and open root directory.
+ */
+static int ceph_mount(struct ceph_client *client, struct vfsmount *mnt,
+ const char *path)
+{
+ struct ceph_entity_addr *myaddr = NULL;
+ int err;
+ unsigned long timeout = client->mount_args.mount_timeout * HZ;
+ unsigned long started = jiffies; /* note the start time */
+ struct dentry *root;
+
+ dout("mount start\n");
+ mutex_lock(&client->mount_mutex);
+
+ /* initialize the messenger */
+ if (client->msgr == NULL) {
+ if (ceph_test_opt(client, MYIP))
+ myaddr = &client->mount_args.my_addr;
+ client->msgr = ceph_messenger_create(myaddr);
+ if (IS_ERR(client->msgr)) {
+ err = PTR_ERR(client->msgr);
+ client->msgr = NULL;
+ goto out;
+ }
+ client->msgr->nocrc = ceph_test_opt(client, NOCRC);
+ }
+
+ /* send mount request, and wait for mon, mds, and osd maps */
+ err = ceph_monc_request_mount(&client->monc);
+ if (err < 0)
+ goto out;
+
+ while (!have_mon_map(client) && !client->mount_err) {
+ err = -EIO;
+ if (timeout && time_after_eq(jiffies, started + timeout))
+ goto out;
+
+ /* wait */
+ dout("mount waiting for mount\n");
+ err = wait_event_interruptible_timeout(client->mount_wq,
+ client->mount_err || have_mon_map(client),
+ timeout);
+ if (err == -EINTR || err == -ERESTARTSYS)
+ goto out;
+ if (client->mount_err) {
+ err = client->mount_err;
+ goto out;
+ }
+ }
+
+ dout("mount opening root\n");
+ root = open_root_dentry(client, "", started);
+ if (IS_ERR(root)) {
+ err = PTR_ERR(root);
+ goto out;
+ }
+ if (client->sb->s_root)
+ dput(root);
+ else
+ client->sb->s_root = root;
+
+ if (path[0] == 0) {
+ dget(root);
+ } else {
+ dout("mount opening base mountpoint\n");
+ root = open_root_dentry(client, path, started);
+ if (IS_ERR(root)) {
+ err = PTR_ERR(root);
+ dput(client->sb->s_root);
+ client->sb->s_root = NULL;
+ goto out;
+ }
+ }
+
+ mnt->mnt_root = root;
+ mnt->mnt_sb = client->sb;
+
+ client->mount_state = CEPH_MOUNT_MOUNTED;
+ dout("mount success\n");
+ err = 0;
+
+out:
+ mutex_unlock(&client->mount_mutex);
+ return err;
+}
+
+static int ceph_set_super(struct super_block *s, void *data)
+{
+ struct ceph_client *client = data;
+ int ret;
+
+ dout("set_super %p data %p\n", s, data);
+
+ s->s_flags = client->mount_args.sb_flags;
+ s->s_maxbytes = 1ULL << 40; /* temp value until we get mdsmap */
+
+ s->s_fs_info = client;
+ client->sb = s;
+
+ s->s_op = &ceph_super_ops;
+ s->s_export_op = &ceph_export_ops;
+
+ s->s_time_gran = 1000; /* 1000 ns == 1 us */
+
+ ret = set_anon_super(s, NULL); /* what is that second arg for? */
+ if (ret != 0)
+ goto fail;
+
+ return ret;
+
+fail:
+ s->s_fs_info = NULL;
+ client->sb = NULL;
+ return ret;
+}
+
+/*
+ * share superblock if same fs AND options
+ */
+static int ceph_compare_super(struct super_block *sb, void *data)
+{
+ struct ceph_client *new = data;
+ struct ceph_mount_args *args = &new->mount_args;
+ struct ceph_client *other = ceph_sb_to_client(sb);
+ int i;
+
+ dout("ceph_compare_super %p\n", sb);
+ if (args->flags & CEPH_OPT_FSID) {
+ if (ceph_fsid_compare(&args->fsid, &other->fsid)) {
+ dout("fsid doesn't match\n");
+ return 0;
+ }
+ } else {
+ /* do we share (a) monitor? */
+ for (i = 0; i < new->monc.monmap->num_mon; i++)
+ if (ceph_monmap_contains(other->monc.monmap,
+ &new->monc.monmap->mon_inst[i].addr))
+ break;
+ if (i == new->monc.monmap->num_mon) {
+ dout("mon ip not part of monmap\n");
+ return 0;
+ }
+ dout("mon ip matches existing sb %p\n", sb);
+ }
+ if (args->sb_flags != other->mount_args.sb_flags) {
+ dout("flags differ\n");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * construct our own bdi so we can control readahead, etc.
+ */
+static int ceph_init_bdi(struct super_block *sb, struct ceph_client *client)
+{
+ int err;
+
+ err = bdi_init(&client->backing_dev_info);
+ if (err < 0)
+ return err;
+ sb->s_bdi = &client->backing_dev_info;
+
+ /* set ra_pages based on rsize mount option? */
+ if (client->mount_args.rsize >= PAGE_CACHE_SIZE)
+ client->backing_dev_info.ra_pages =
+ (client->mount_args.rsize + PAGE_CACHE_SIZE - 1)
+ >> PAGE_SHIFT;
+
+ err = bdi_register_dev(&client->backing_dev_info, sb->s_dev);
+ return err;
+}
+
+static int ceph_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data,
+ struct vfsmount *mnt)
+{
+ struct super_block *sb;
+ struct ceph_client *client;
+ int err;
+ int (*compare_super)(struct super_block *, void *) = ceph_compare_super;
+ const char *path = 0;
+
+ dout("ceph_get_sb\n");
+
+ /* create client (which we may/may not use) */
+ client = ceph_create_client();
+ if (IS_ERR(client))
+ return PTR_ERR(client);
+
+ err = parse_mount_args(client, flags, data, dev_name, &path);
+ if (err < 0)
+ goto out;
+
+ if (client->mount_args.flags & CEPH_OPT_NOSHARE)
+ compare_super = NULL;
+ sb = sget(fs_type, compare_super, ceph_set_super, client);
+ if (IS_ERR(sb)) {
+ err = PTR_ERR(sb);
+ goto out;
+ }
+
+ if (ceph_client(sb) != client) {
+ ceph_destroy_client(client);
+ client = ceph_client(sb);
+ dout("get_sb got existing client %p\n", client);
+ } else {
+ dout("get_sb using new client %p\n", client);
+
+ /* set up mempools */
+ err = -ENOMEM;
+ client->wb_pagevec_pool = mempool_create_kmalloc_pool(10,
+ client->mount_args.wsize >> PAGE_CACHE_SHIFT);
+ if (!client->wb_pagevec_pool)
+ goto out_splat;
+
+ err = ceph_init_bdi(sb, client);
+ if (err < 0)
+ goto out_splat;
+ }
+
+ err = ceph_mount(client, mnt, path);
+ if (err < 0)
+ goto out_splat;
+ dout("root %p inode %p ino %llx.%llx\n", mnt->mnt_root,
+ mnt->mnt_root->d_inode, ceph_vinop(mnt->mnt_root->d_inode));
+ return 0;
+
+out_splat:
+ ceph_mdsc_close_sessions(&client->mdsc);
+ up_write(&sb->s_umount);
+ deactivate_super(sb);
+ goto out_final;
+
+out:
+ ceph_destroy_client(client);
+out_final:
+ dout("ceph_get_sb fail %d\n", err);
+ return err;
+}
+
+static void ceph_kill_sb(struct super_block *s)
+{
+ struct ceph_client *client = ceph_sb_to_client(s);
+ dout("kill_sb %p\n", s);
+ ceph_mdsc_pre_umount(&client->mdsc);
+ kill_anon_super(s); /* will call put_super after sb is r/o */
+ bdi_unregister(&client->backing_dev_info);
+ bdi_destroy(&client->backing_dev_info);
+ ceph_destroy_client(client);
+}
+
+static struct file_system_type ceph_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "ceph",
+ .get_sb = ceph_get_sb,
+ .kill_sb = ceph_kill_sb,
+ .fs_flags = FS_RENAME_DOES_D_MOVE,
+};
+
+#define _STRINGIFY(x) #x
+#define STRINGIFY(x) _STRINGIFY(x)
+
+static int __init init_ceph(void)
+{
+ int ret = 0;
+
+ ret = ceph_debugfs_init();
+ if (ret < 0)
+ goto out;
+
+ ret = ceph_msgr_init();
+ if (ret < 0)
+ goto out_debugfs;
+
+ ret = init_caches();
+ if (ret)
+ goto out_msgr;
+
+ ceph_caps_init();
+
+ ret = register_filesystem(&ceph_fs_type);
+ if (ret)
+ goto out_icache;
+
+ pr_info("loaded %d.%d.%d (mon/mds/osd proto %d/%d/%d)\n",
+ CEPH_VERSION_MAJOR, CEPH_VERSION_MINOR, CEPH_VERSION_PATCH,
+ CEPH_MONC_PROTOCOL, CEPH_MDSC_PROTOCOL, CEPH_OSDC_PROTOCOL);
+ return 0;
+
+out_icache:
+ destroy_caches();
+out_msgr:
+ ceph_msgr_exit();
+out_debugfs:
+ ceph_debugfs_cleanup();
+out:
+ return ret;
+}
+
+static void __exit exit_ceph(void)
+{
+ dout("exit_ceph\n");
+ unregister_filesystem(&ceph_fs_type);
+ ceph_caps_finalize();
+ destroy_caches();
+ ceph_msgr_exit();
+ ceph_debugfs_cleanup();
+}
+
+module_init(init_ceph);
+module_exit(exit_ceph);
+
+MODULE_AUTHOR("Sage Weil <sage@newdream.net>");
+MODULE_AUTHOR("Yehuda Sadeh <yehuda@hq.newdream.net>");
+MODULE_AUTHOR("Patience Warnick <patience@newdream.net>");
+MODULE_DESCRIPTION("Ceph filesystem for Linux");
+MODULE_LICENSE("GPL");
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
new file mode 100644
index 000000000000..3af42d9097ec
--- /dev/null
+++ b/fs/ceph/super.h
@@ -0,0 +1,888 @@
+#ifndef _FS_CEPH_SUPER_H
+#define _FS_CEPH_SUPER_H
+
+#include "ceph_debug.h"
+
+#include <asm/unaligned.h>
+#include <linux/backing-dev.h>
+#include <linux/completion.h>
+#include <linux/exportfs.h>
+#include <linux/fs.h>
+#include <linux/mempool.h>
+#include <linux/pagemap.h>
+#include <linux/wait.h>
+
+#include "types.h"
+#include "messenger.h"
+#include "msgpool.h"
+#include "mon_client.h"
+#include "mds_client.h"
+#include "osd_client.h"
+#include "ceph_fs.h"
+
+/* f_type in struct statfs */
+#define CEPH_SUPER_MAGIC 0x00c36400
+
+/* large granularity for statfs utilization stats to facilitate
+ * large volume sizes on 32-bit machines. */
+#define CEPH_BLOCK_SHIFT 20 /* 1 MB */
+#define CEPH_BLOCK (1 << CEPH_BLOCK_SHIFT)
+
+/*
+ * mount options
+ */
+#define CEPH_OPT_FSID (1<<0)
+#define CEPH_OPT_NOSHARE (1<<1) /* don't share client with other sbs */
+#define CEPH_OPT_MYIP (1<<2) /* specified my ip */
+#define CEPH_OPT_DIRSTAT (1<<4) /* funky `cat dirname` for stats */
+#define CEPH_OPT_RBYTES (1<<5) /* dir st_bytes = rbytes */
+#define CEPH_OPT_NOCRC (1<<6) /* no data crc on writes */
+#define CEPH_OPT_NOASYNCREADDIR (1<<7) /* no dcache readdir */
+
+#define CEPH_OPT_DEFAULT (CEPH_OPT_RBYTES)
+
+#define ceph_set_opt(client, opt) \
+ (client)->mount_args.flags |= CEPH_OPT_##opt;
+#define ceph_test_opt(client, opt) \
+ (!!((client)->mount_args.flags & CEPH_OPT_##opt))
+
+
+struct ceph_mount_args {
+ int sb_flags;
+ int flags;
+ int mount_timeout;
+ int caps_wanted_delay_min, caps_wanted_delay_max;
+ struct ceph_fsid fsid;
+ struct ceph_entity_addr my_addr;
+ int wsize;
+ int rsize; /* max readahead */
+ int max_readdir; /* max readdir size */
+ int osd_timeout;
+ char *snapdir_name; /* default ".snap" */
+ char *secret;
+ int cap_release_safety;
+};
+
+/*
+ * defaults
+ */
+#define CEPH_MOUNT_TIMEOUT_DEFAULT 60
+#define CEPH_MOUNT_RSIZE_DEFAULT (512*1024) /* readahead */
+
+#define CEPH_MSG_MAX_FRONT_LEN (16*1024*1024)
+#define CEPH_MSG_MAX_DATA_LEN (16*1024*1024)
+
+#define CEPH_SNAPDIRNAME_DEFAULT ".snap"
+
+/*
+ * Delay telling the MDS we no longer want caps, in case we reopen
+ * the file. Delay a minimum amount of time, even if we send a cap
+ * message for some other reason. Otherwise, take the oppotunity to
+ * update the mds to avoid sending another message later.
+ */
+#define CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT 5 /* cap release delay */
+#define CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT 60 /* cap release delay */
+
+
+/* mount state */
+enum {
+ CEPH_MOUNT_MOUNTING,
+ CEPH_MOUNT_MOUNTED,
+ CEPH_MOUNT_UNMOUNTING,
+ CEPH_MOUNT_UNMOUNTED,
+ CEPH_MOUNT_SHUTDOWN,
+};
+
+/*
+ * subtract jiffies
+ */
+static inline unsigned long time_sub(unsigned long a, unsigned long b)
+{
+ BUG_ON(time_after(b, a));
+ return (long)a - (long)b;
+}
+
+/*
+ * per-filesystem client state
+ *
+ * possibly shared by multiple mount points, if they are
+ * mounting the same ceph filesystem/cluster.
+ */
+struct ceph_client {
+ __s64 whoami; /* my client number */
+ struct dentry *debugfs_monmap;
+ struct dentry *debugfs_mdsmap, *debugfs_osdmap;
+ struct dentry *debugfs_dir, *debugfs_dentry_lru, *debugfs_caps;
+
+ struct mutex mount_mutex; /* serialize mount attempts */
+ struct ceph_mount_args mount_args;
+ struct ceph_fsid fsid;
+
+ struct super_block *sb;
+
+ unsigned long mount_state;
+ wait_queue_head_t mount_wq;
+
+ int mount_err;
+ void *signed_ticket; /* our keys to the kingdom */
+ int signed_ticket_len;
+
+ struct ceph_messenger *msgr; /* messenger instance */
+ struct ceph_mon_client monc;
+ struct ceph_mds_client mdsc;
+ struct ceph_osd_client osdc;
+
+ /* writeback */
+ mempool_t *wb_pagevec_pool;
+ struct workqueue_struct *wb_wq;
+ struct workqueue_struct *pg_inv_wq;
+ struct workqueue_struct *trunc_wq;
+
+ struct backing_dev_info backing_dev_info;
+};
+
+static inline struct ceph_client *ceph_client(struct super_block *sb)
+{
+ return sb->s_fs_info;
+}
+
+
+/*
+ * File i/o capability. This tracks shared state with the metadata
+ * server that allows us to cache or writeback attributes or to read
+ * and write data. For any given inode, we should have one or more
+ * capabilities, one issued by each metadata server, and our
+ * cumulative access is the OR of all issued capabilities.
+ *
+ * Each cap is referenced by the inode's i_caps rbtree and by per-mds
+ * session capability lists.
+ */
+struct ceph_cap {
+ struct ceph_inode_info *ci;
+ struct rb_node ci_node; /* per-ci cap tree */
+ struct ceph_mds_session *session;
+ struct list_head session_caps; /* per-session caplist */
+ int mds;
+ u64 cap_id; /* unique cap id (mds provided) */
+ int issued; /* latest, from the mds */
+ int implemented; /* implemented superset of issued (for revocation) */
+ int mds_wanted;
+ u32 seq, issue_seq, mseq, gen;
+ unsigned long last_used;
+ struct list_head caps_item;
+};
+
+#define CHECK_CAPS_NODELAY 1 /* do not delay any further */
+#define CHECK_CAPS_AUTHONLY 2 /* only check auth cap */
+#define CHECK_CAPS_FLUSH 4 /* flush any dirty caps */
+
+/*
+ * Snapped cap state that is pending flush to mds. When a snapshot occurs,
+ * we first complete any in-process sync writes and writeback any dirty
+ * data before flushing the snapped state (tracked here) back to the MDS.
+ */
+struct ceph_cap_snap {
+ atomic_t nref;
+ struct ceph_inode_info *ci;
+ struct list_head ci_item, flushing_item;
+
+ u64 follows, flush_tid;
+ int issued, dirty;
+ struct ceph_snap_context *context;
+
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
+
+ void *xattr_blob;
+ int xattr_len;
+ u64 xattr_version;
+
+ u64 size;
+ struct timespec mtime, atime, ctime;
+ u64 time_warp_seq;
+ int writing; /* a sync write is still in progress */
+ int dirty_pages; /* dirty pages awaiting writeback */
+};
+
+static inline void ceph_put_cap_snap(struct ceph_cap_snap *capsnap)
+{
+ if (atomic_dec_and_test(&capsnap->nref))
+ kfree(capsnap);
+}
+
+/*
+ * The frag tree describes how a directory is fragmented, potentially across
+ * multiple metadata servers. It is also used to indicate points where
+ * metadata authority is delegated, and whether/where metadata is replicated.
+ *
+ * A _leaf_ frag will be present in the i_fragtree IFF there is
+ * delegation info. That is, if mds >= 0 || ndist > 0.
+ */
+#define CEPH_MAX_DIRFRAG_REP 4
+
+struct ceph_inode_frag {
+ struct rb_node node;
+
+ /* fragtree state */
+ u32 frag;
+ int split_by; /* i.e. 2^(split_by) children */
+
+ /* delegation and replication info */
+ int mds; /* -1 if same authority as parent */
+ int ndist; /* >0 if replicated */
+ int dist[CEPH_MAX_DIRFRAG_REP];
+};
+
+/*
+ * We cache inode xattrs as an encoded blob until they are first used,
+ * at which point we parse them into an rbtree.
+ */
+struct ceph_inode_xattr {
+ struct rb_node node;
+
+ const char *name;
+ int name_len;
+ const char *val;
+ int val_len;
+ int dirty;
+
+ int should_free_name;
+ int should_free_val;
+};
+
+struct ceph_inode_xattrs_info {
+ /*
+ * (still encoded) xattr blob. we avoid the overhead of parsing
+ * this until someone actually calls getxattr, etc.
+ *
+ * blob->vec.iov_len == 4 implies there are no xattrs; blob ==
+ * NULL means we don't know.
+ */
+ struct ceph_buffer *blob, *prealloc_blob;
+
+ struct rb_root index;
+ bool dirty;
+ int count;
+ int names_size;
+ int vals_size;
+ u64 version, index_version;
+};
+
+/*
+ * Ceph inode.
+ */
+#define CEPH_I_COMPLETE 1 /* we have complete directory cached */
+#define CEPH_I_NODELAY 4 /* do not delay cap release */
+#define CEPH_I_FLUSH 8 /* do not delay flush of dirty metadata */
+
+struct ceph_inode_info {
+ struct ceph_vino i_vino; /* ceph ino + snap */
+
+ u64 i_version;
+ u32 i_time_warp_seq;
+
+ unsigned i_ceph_flags;
+ unsigned long i_release_count;
+
+ struct ceph_file_layout i_layout;
+ char *i_symlink;
+
+ /* for dirs */
+ struct timespec i_rctime;
+ u64 i_rbytes, i_rfiles, i_rsubdirs;
+ u64 i_files, i_subdirs;
+ u64 i_max_offset; /* largest readdir offset, set with I_COMPLETE */
+
+ struct rb_root i_fragtree;
+ struct mutex i_fragtree_mutex;
+
+ struct ceph_inode_xattrs_info i_xattrs;
+
+ /* capabilities. protected _both_ by i_lock and cap->session's
+ * s_mutex. */
+ struct rb_root i_caps; /* cap list */
+ struct ceph_cap *i_auth_cap; /* authoritative cap, if any */
+ unsigned i_dirty_caps, i_flushing_caps; /* mask of dirtied fields */
+ struct list_head i_dirty_item, i_flushing_item;
+ u64 i_cap_flush_seq;
+ /* we need to track cap writeback on a per-cap-bit basis, to allow
+ * overlapping, pipelined cap flushes to the mds. we can probably
+ * reduce the tid to 8 bits if we're concerned about inode size. */
+ u16 i_cap_flush_last_tid, i_cap_flush_tid[CEPH_CAP_BITS];
+ wait_queue_head_t i_cap_wq; /* threads waiting on a capability */
+ unsigned long i_hold_caps_min; /* jiffies */
+ unsigned long i_hold_caps_max; /* jiffies */
+ struct list_head i_cap_delay_list; /* for delayed cap release to mds */
+ int i_cap_exporting_mds; /* to handle cap migration between */
+ unsigned i_cap_exporting_mseq; /* mds's. */
+ unsigned i_cap_exporting_issued;
+ struct ceph_cap_reservation i_cap_migration_resv;
+ struct list_head i_cap_snaps; /* snapped state pending flush to mds */
+ struct ceph_snap_context *i_head_snapc; /* set if wr_buffer_head > 0 */
+ unsigned i_snap_caps; /* cap bits for snapped files */
+
+ int i_nr_by_mode[CEPH_FILE_MODE_NUM]; /* open file counts */
+
+ u32 i_truncate_seq; /* last truncate to smaller size */
+ u64 i_truncate_size; /* and the size we last truncated down to */
+ int i_truncate_pending; /* still need to call vmtruncate */
+
+ u64 i_max_size; /* max file size authorized by mds */
+ u64 i_reported_size; /* (max_)size reported to or requested of mds */
+ u64 i_wanted_max_size; /* offset we'd like to write too */
+ u64 i_requested_max_size; /* max_size we've requested */
+
+ /* held references to caps */
+ int i_pin_ref;
+ int i_rd_ref, i_rdcache_ref, i_wr_ref;
+ int i_wrbuffer_ref, i_wrbuffer_ref_head;
+ u32 i_shared_gen; /* increment each time we get FILE_SHARED */
+ u32 i_rdcache_gen; /* we increment this each time we get
+ FILE_CACHE. If it's non-zero, we
+ _may_ have cached pages. */
+ u32 i_rdcache_revoking; /* RDCACHE gen to async invalidate, if any */
+
+ struct list_head i_unsafe_writes; /* uncommitted sync writes */
+ struct list_head i_unsafe_dirops; /* uncommitted mds dir ops */
+ spinlock_t i_unsafe_lock;
+
+ struct ceph_snap_realm *i_snap_realm; /* snap realm (if caps) */
+ int i_snap_realm_counter; /* snap realm (if caps) */
+ struct list_head i_snap_realm_item;
+ struct list_head i_snap_flush_item;
+
+ struct work_struct i_wb_work; /* writeback work */
+ struct work_struct i_pg_inv_work; /* page invalidation work */
+
+ struct work_struct i_vmtruncate_work;
+
+ struct inode vfs_inode; /* at end */
+};
+
+static inline struct ceph_inode_info *ceph_inode(struct inode *inode)
+{
+ return list_entry(inode, struct ceph_inode_info, vfs_inode);
+}
+
+static inline void ceph_i_clear(struct inode *inode, unsigned mask)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+
+ spin_lock(&inode->i_lock);
+ ci->i_ceph_flags &= ~mask;
+ spin_unlock(&inode->i_lock);
+}
+
+static inline void ceph_i_set(struct inode *inode, unsigned mask)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+
+ spin_lock(&inode->i_lock);
+ ci->i_ceph_flags |= mask;
+ spin_unlock(&inode->i_lock);
+}
+
+static inline bool ceph_i_test(struct inode *inode, unsigned mask)
+{
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ bool r;
+
+ smp_mb();
+ r = (ci->i_ceph_flags & mask) == mask;
+ return r;
+}
+
+
+/* find a specific frag @f */
+extern struct ceph_inode_frag *__ceph_find_frag(struct ceph_inode_info *ci,
+ u32 f);
+
+/*
+ * choose fragment for value @v. copy frag content to pfrag, if leaf
+ * exists
+ */
+extern u32 ceph_choose_frag(struct ceph_inode_info *ci, u32 v,
+ struct ceph_inode_frag *pfrag,
+ int *found);
+
+/*
+ * Ceph dentry state
+ */
+struct ceph_dentry_info {
+ struct ceph_mds_session *lease_session;
+ u32 lease_gen, lease_shared_gen;
+ u32 lease_seq;
+ unsigned long lease_renew_after, lease_renew_from;
+ struct list_head lru;
+ struct dentry *dentry;
+ u64 time;
+ u64 offset;
+};
+
+static inline struct ceph_dentry_info *ceph_dentry(struct dentry *dentry)
+{
+ return (struct ceph_dentry_info *)dentry->d_fsdata;
+}
+
+static inline loff_t ceph_make_fpos(unsigned frag, unsigned off)
+{
+ return ((loff_t)frag << 32) | (loff_t)off;
+}
+
+/*
+ * ino_t is <64 bits on many architectures, blech.
+ *
+ * don't include snap in ino hash, at least for now.
+ */
+static inline ino_t ceph_vino_to_ino(struct ceph_vino vino)
+{
+ ino_t ino = (ino_t)vino.ino; /* ^ (vino.snap << 20); */
+#if BITS_PER_LONG == 32
+ ino ^= vino.ino >> (sizeof(u64)-sizeof(ino_t)) * 8;
+ if (!ino)
+ ino = 1;
+#endif
+ return ino;
+}
+
+static inline int ceph_set_ino_cb(struct inode *inode, void *data)
+{
+ ceph_inode(inode)->i_vino = *(struct ceph_vino *)data;
+ inode->i_ino = ceph_vino_to_ino(*(struct ceph_vino *)data);
+ return 0;
+}
+
+static inline struct ceph_vino ceph_vino(struct inode *inode)
+{
+ return ceph_inode(inode)->i_vino;
+}
+
+/* for printf-style formatting */
+#define ceph_vinop(i) ceph_inode(i)->i_vino.ino, ceph_inode(i)->i_vino.snap
+
+static inline u64 ceph_ino(struct inode *inode)
+{
+ return ceph_inode(inode)->i_vino.ino;
+}
+static inline u64 ceph_snap(struct inode *inode)
+{
+ return ceph_inode(inode)->i_vino.snap;
+}
+
+static inline int ceph_ino_compare(struct inode *inode, void *data)
+{
+ struct ceph_vino *pvino = (struct ceph_vino *)data;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ return ci->i_vino.ino == pvino->ino &&
+ ci->i_vino.snap == pvino->snap;
+}
+
+static inline struct inode *ceph_find_inode(struct super_block *sb,
+ struct ceph_vino vino)
+{
+ ino_t t = ceph_vino_to_ino(vino);
+ return ilookup5(sb, t, ceph_ino_compare, &vino);
+}
+
+
+/*
+ * caps helpers
+ */
+static inline bool __ceph_is_any_real_caps(struct ceph_inode_info *ci)
+{
+ return !RB_EMPTY_ROOT(&ci->i_caps);
+}
+
+extern int __ceph_caps_issued(struct ceph_inode_info *ci, int *implemented);
+extern int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int t);
+extern int __ceph_caps_issued_other(struct ceph_inode_info *ci,
+ struct ceph_cap *cap);
+
+static inline int ceph_caps_issued(struct ceph_inode_info *ci)
+{
+ int issued;
+ spin_lock(&ci->vfs_inode.i_lock);
+ issued = __ceph_caps_issued(ci, NULL);
+ spin_unlock(&ci->vfs_inode.i_lock);
+ return issued;
+}
+
+static inline int ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask,
+ int touch)
+{
+ int r;
+ spin_lock(&ci->vfs_inode.i_lock);
+ r = __ceph_caps_issued_mask(ci, mask, touch);
+ spin_unlock(&ci->vfs_inode.i_lock);
+ return r;
+}
+
+static inline int __ceph_caps_dirty(struct ceph_inode_info *ci)
+{
+ return ci->i_dirty_caps | ci->i_flushing_caps;
+}
+extern void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask);
+
+extern int ceph_caps_revoking(struct ceph_inode_info *ci, int mask);
+extern int __ceph_caps_used(struct ceph_inode_info *ci);
+
+extern int __ceph_caps_file_wanted(struct ceph_inode_info *ci);
+
+/*
+ * wanted, by virtue of open file modes AND cap refs (buffered/cached data)
+ */
+static inline int __ceph_caps_wanted(struct ceph_inode_info *ci)
+{
+ int w = __ceph_caps_file_wanted(ci) | __ceph_caps_used(ci);
+ if (w & CEPH_CAP_FILE_BUFFER)
+ w |= CEPH_CAP_FILE_EXCL; /* we want EXCL if dirty data */
+ return w;
+}
+
+/* what the mds thinks we want */
+extern int __ceph_caps_mds_wanted(struct ceph_inode_info *ci);
+
+extern void ceph_caps_init(void);
+extern void ceph_caps_finalize(void);
+extern int ceph_reserve_caps(struct ceph_cap_reservation *ctx, int need);
+extern int ceph_unreserve_caps(struct ceph_cap_reservation *ctx);
+extern void ceph_reservation_status(struct ceph_client *client,
+ int *total, int *avail, int *used,
+ int *reserved);
+
+static inline struct ceph_client *ceph_inode_to_client(struct inode *inode)
+{
+ return (struct ceph_client *)inode->i_sb->s_fs_info;
+}
+
+static inline struct ceph_client *ceph_sb_to_client(struct super_block *sb)
+{
+ return (struct ceph_client *)sb->s_fs_info;
+}
+
+static inline int ceph_queue_writeback(struct inode *inode)
+{
+ return queue_work(ceph_inode_to_client(inode)->wb_wq,
+ &ceph_inode(inode)->i_wb_work);
+}
+
+static inline int ceph_queue_page_invalidation(struct inode *inode)
+{
+ return queue_work(ceph_inode_to_client(inode)->pg_inv_wq,
+ &ceph_inode(inode)->i_pg_inv_work);
+}
+
+
+/*
+ * we keep buffered readdir results attached to file->private_data
+ */
+struct ceph_file_info {
+ int fmode; /* initialized on open */
+
+ /* readdir: position within the dir */
+ u32 frag;
+ struct ceph_mds_request *last_readdir;
+ int at_end;
+
+ /* readdir: position within a frag */
+ unsigned offset; /* offset of last chunk, adjusted for . and .. */
+ u64 next_offset; /* offset of next chunk (last_name's + 1) */
+ char *last_name; /* last entry in previous chunk */
+ struct dentry *dentry; /* next dentry (for dcache readdir) */
+ unsigned long dir_release_count;
+
+ /* used for -o dirstat read() on directory thing */
+ char *dir_info;
+ int dir_info_len;
+};
+
+
+
+/*
+ * snapshots
+ */
+
+/*
+ * A "snap context" is the set of existing snapshots when we
+ * write data. It is used by the OSD to guide its COW behavior.
+ *
+ * The ceph_snap_context is refcounted, and attached to each dirty
+ * page, indicating which context the dirty data belonged when it was
+ * dirtied.
+ */
+struct ceph_snap_context {
+ atomic_t nref;
+ u64 seq;
+ int num_snaps;
+ u64 snaps[];
+};
+
+static inline struct ceph_snap_context *
+ceph_get_snap_context(struct ceph_snap_context *sc)
+{
+ /*
+ printk("get_snap_context %p %d -> %d\n", sc, atomic_read(&sc->nref),
+ atomic_read(&sc->nref)+1);
+ */
+ if (sc)
+ atomic_inc(&sc->nref);
+ return sc;
+}
+
+static inline void ceph_put_snap_context(struct ceph_snap_context *sc)
+{
+ if (!sc)
+ return;
+ /*
+ printk("put_snap_context %p %d -> %d\n", sc, atomic_read(&sc->nref),
+ atomic_read(&sc->nref)-1);
+ */
+ if (atomic_dec_and_test(&sc->nref)) {
+ /*printk(" deleting snap_context %p\n", sc);*/
+ kfree(sc);
+ }
+}
+
+/*
+ * A "snap realm" describes a subset of the file hierarchy sharing
+ * the same set of snapshots that apply to it. The realms themselves
+ * are organized into a hierarchy, such that children inherit (some of)
+ * the snapshots of their parents.
+ *
+ * All inodes within the realm that have capabilities are linked into a
+ * per-realm list.
+ */
+struct ceph_snap_realm {
+ u64 ino;
+ atomic_t nref;
+ u64 created, seq;
+ u64 parent_ino;
+ u64 parent_since; /* snapid when our current parent became so */
+
+ u64 *prior_parent_snaps; /* snaps inherited from any parents we */
+ int num_prior_parent_snaps; /* had prior to parent_since */
+ u64 *snaps; /* snaps specific to this realm */
+ int num_snaps;
+
+ struct ceph_snap_realm *parent;
+ struct list_head children; /* list of child realms */
+ struct list_head child_item;
+
+ struct list_head empty_item; /* if i have ref==0 */
+
+ /* the current set of snaps for this realm */
+ struct ceph_snap_context *cached_context;
+
+ struct list_head inodes_with_caps;
+ spinlock_t inodes_with_caps_lock;
+};
+
+
+
+/*
+ * calculate the number of pages a given length and offset map onto,
+ * if we align the data.
+ */
+static inline int calc_pages_for(u64 off, u64 len)
+{
+ return ((off+len+PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT) -
+ (off >> PAGE_CACHE_SHIFT);
+}
+
+
+
+/* snap.c */
+struct ceph_snap_realm *ceph_lookup_snap_realm(struct ceph_mds_client *mdsc,
+ u64 ino);
+extern void ceph_get_snap_realm(struct ceph_mds_client *mdsc,
+ struct ceph_snap_realm *realm);
+extern void ceph_put_snap_realm(struct ceph_mds_client *mdsc,
+ struct ceph_snap_realm *realm);
+extern int ceph_update_snap_trace(struct ceph_mds_client *m,
+ void *p, void *e, bool deletion);
+extern void ceph_handle_snap(struct ceph_mds_client *mdsc,
+ struct ceph_msg *msg);
+extern void ceph_queue_cap_snap(struct ceph_inode_info *ci,
+ struct ceph_snap_context *snapc);
+extern int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
+ struct ceph_cap_snap *capsnap);
+extern void ceph_cleanup_empty_realms(struct ceph_mds_client *mdsc);
+
+/*
+ * a cap_snap is "pending" if it is still awaiting an in-progress
+ * sync write (that may/may not still update size, mtime, etc.).
+ */
+static inline bool __ceph_have_pending_cap_snap(struct ceph_inode_info *ci)
+{
+ return !list_empty(&ci->i_cap_snaps) &&
+ list_entry(ci->i_cap_snaps.prev, struct ceph_cap_snap,
+ ci_item)->writing;
+}
+
+
+/* super.c */
+extern struct kmem_cache *ceph_inode_cachep;
+extern struct kmem_cache *ceph_cap_cachep;
+extern struct kmem_cache *ceph_dentry_cachep;
+extern struct kmem_cache *ceph_file_cachep;
+
+extern const char *ceph_msg_type_name(int type);
+
+#define FSID_FORMAT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" \
+ "%02x%02x%02x%02x%02x%02x"
+#define PR_FSID(f) (f)->fsid[0], (f)->fsid[1], (f)->fsid[2], (f)->fsid[3], \
+ (f)->fsid[4], (f)->fsid[5], (f)->fsid[6], (f)->fsid[7], \
+ (f)->fsid[8], (f)->fsid[9], (f)->fsid[10], (f)->fsid[11], \
+ (f)->fsid[12], (f)->fsid[13], (f)->fsid[14], (f)->fsid[15]
+
+/* inode.c */
+extern const struct inode_operations ceph_file_iops;
+
+extern struct inode *ceph_alloc_inode(struct super_block *sb);
+extern void ceph_destroy_inode(struct inode *inode);
+
+extern struct inode *ceph_get_inode(struct super_block *sb,
+ struct ceph_vino vino);
+extern struct inode *ceph_get_snapdir(struct inode *parent);
+extern int ceph_fill_file_size(struct inode *inode, int issued,
+ u32 truncate_seq, u64 truncate_size, u64 size);
+extern void ceph_fill_file_time(struct inode *inode, int issued,
+ u64 time_warp_seq, struct timespec *ctime,
+ struct timespec *mtime, struct timespec *atime);
+extern int ceph_fill_trace(struct super_block *sb,
+ struct ceph_mds_request *req,
+ struct ceph_mds_session *session);
+extern int ceph_readdir_prepopulate(struct ceph_mds_request *req,
+ struct ceph_mds_session *session);
+
+extern int ceph_inode_holds_cap(struct inode *inode, int mask);
+
+extern int ceph_inode_set_size(struct inode *inode, loff_t size);
+extern void ceph_inode_writeback(struct work_struct *work);
+extern void ceph_vmtruncate_work(struct work_struct *work);
+extern void __ceph_do_pending_vmtruncate(struct inode *inode);
+extern void __ceph_queue_vmtruncate(struct inode *inode);
+
+extern int ceph_do_getattr(struct inode *inode, int mask);
+extern int ceph_permission(struct inode *inode, int mask);
+extern int ceph_setattr(struct dentry *dentry, struct iattr *attr);
+extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry,
+ struct kstat *stat);
+
+/* xattr.c */
+extern int ceph_setxattr(struct dentry *, const char *, const void *,
+ size_t, int);
+extern ssize_t ceph_getxattr(struct dentry *, const char *, void *, size_t);
+extern ssize_t ceph_listxattr(struct dentry *, char *, size_t);
+extern int ceph_removexattr(struct dentry *, const char *);
+extern void __ceph_build_xattrs_blob(struct ceph_inode_info *ci);
+extern void __ceph_destroy_xattrs(struct ceph_inode_info *ci);
+
+/* caps.c */
+extern const char *ceph_cap_string(int c);
+extern void ceph_handle_caps(struct ceph_mds_session *session,
+ struct ceph_msg *msg);
+extern int ceph_add_cap(struct inode *inode,
+ struct ceph_mds_session *session, u64 cap_id,
+ int fmode, unsigned issued, unsigned wanted,
+ unsigned cap, unsigned seq, u64 realmino, int flags,
+ struct ceph_cap_reservation *caps_reservation);
+extern void __ceph_remove_cap(struct ceph_cap *cap,
+ struct ceph_cap_reservation *ctx);
+static inline void ceph_remove_cap(struct ceph_cap *cap)
+{
+ struct inode *inode = &cap->ci->vfs_inode;
+ spin_lock(&inode->i_lock);
+ __ceph_remove_cap(cap, NULL);
+ spin_unlock(&inode->i_lock);
+}
+
+extern void ceph_queue_caps_release(struct inode *inode);
+extern int ceph_write_inode(struct inode *inode, int unused);
+extern int ceph_fsync(struct file *file, struct dentry *dentry, int datasync);
+extern void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc,
+ struct ceph_mds_session *session);
+extern int ceph_get_cap_mds(struct inode *inode);
+extern void ceph_get_cap_refs(struct ceph_inode_info *ci, int caps);
+extern void ceph_put_cap_refs(struct ceph_inode_info *ci, int had);
+extern void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr,
+ struct ceph_snap_context *snapc);
+extern void __ceph_flush_snaps(struct ceph_inode_info *ci,
+ struct ceph_mds_session **psession);
+extern void ceph_check_caps(struct ceph_inode_info *ci, int flags,
+ struct ceph_mds_session *session);
+extern void ceph_check_delayed_caps(struct ceph_mds_client *mdsc);
+extern void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc);
+
+extern int ceph_encode_inode_release(void **p, struct inode *inode,
+ int mds, int drop, int unless, int force);
+extern int ceph_encode_dentry_release(void **p, struct dentry *dn,
+ int mds, int drop, int unless);
+
+extern int ceph_get_caps(struct ceph_inode_info *ci, int need, int want,
+ int *got, loff_t endoff);
+
+/* for counting open files by mode */
+static inline void __ceph_get_fmode(struct ceph_inode_info *ci, int mode)
+{
+ ci->i_nr_by_mode[mode]++;
+}
+extern void ceph_put_fmode(struct ceph_inode_info *ci, int mode);
+
+/* addr.c */
+extern const struct address_space_operations ceph_aops;
+extern int ceph_mmap(struct file *file, struct vm_area_struct *vma);
+
+/* file.c */
+extern const struct file_operations ceph_file_fops;
+extern const struct address_space_operations ceph_aops;
+extern int ceph_open(struct inode *inode, struct file *file);
+extern struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
+ struct nameidata *nd, int mode,
+ int locked_dir);
+extern int ceph_release(struct inode *inode, struct file *filp);
+extern void ceph_release_page_vector(struct page **pages, int num_pages);
+
+/* dir.c */
+extern const struct file_operations ceph_dir_fops;
+extern const struct inode_operations ceph_dir_iops;
+extern struct dentry_operations ceph_dentry_ops, ceph_snap_dentry_ops,
+ ceph_snapdir_dentry_ops;
+
+extern int ceph_handle_notrace_create(struct inode *dir, struct dentry *dentry);
+extern struct dentry *ceph_finish_lookup(struct ceph_mds_request *req,
+ struct dentry *dentry, int err);
+
+extern void ceph_dentry_lru_add(struct dentry *dn);
+extern void ceph_dentry_lru_touch(struct dentry *dn);
+extern void ceph_dentry_lru_del(struct dentry *dn);
+
+/*
+ * our d_ops vary depending on whether the inode is live,
+ * snapshotted (read-only), or a virtual ".snap" directory.
+ */
+int ceph_init_dentry(struct dentry *dentry);
+
+
+/* ioctl.c */
+extern long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+
+/* export.c */
+extern const struct export_operations ceph_export_ops;
+
+/* debugfs.c */
+extern int ceph_debugfs_init(void);
+extern void ceph_debugfs_cleanup(void);
+extern int ceph_debugfs_client_init(struct ceph_client *client);
+extern void ceph_debugfs_client_cleanup(struct ceph_client *client);
+
+static inline struct inode *get_dentry_parent_inode(struct dentry *dentry)
+{
+ if (dentry && dentry->d_parent)
+ return dentry->d_parent->d_inode;
+
+ return NULL;
+}
+
+#endif /* _FS_CEPH_SUPER_H */
diff --git a/fs/ceph/types.h b/fs/ceph/types.h
new file mode 100644
index 000000000000..8a514568cab2
--- /dev/null
+++ b/fs/ceph/types.h
@@ -0,0 +1,28 @@
+#ifndef _FS_CEPH_TYPES_H
+#define _FS_CEPH_TYPES_H
+
+/* needed before including ceph_fs.h */
+#include <linux/in.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+
+#include "ceph_fs.h"
+#include "ceph_frag.h"
+
+/*
+ * Identify inodes by both their ino AND snapshot id (a u64).
+ */
+struct ceph_vino {
+ u64 ino;
+ u64 snap;
+};
+
+
+/* context for the caps reservation mechanism */
+struct ceph_cap_reservation {
+ int count;
+};
+
+
+#endif
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c
new file mode 100644
index 000000000000..65b3a84bbb2e
--- /dev/null
+++ b/fs/ceph/xattr.c
@@ -0,0 +1,840 @@
+#include "ceph_debug.h"
+#include "super.h"
+#include "decode.h"
+
+#include <linux/xattr.h>
+
+static bool ceph_is_valid_xattr(const char *name)
+{
+ return !strncmp(name, XATTR_SECURITY_PREFIX,
+ XATTR_SECURITY_PREFIX_LEN) ||
+ !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) ||
+ !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
+}
+
+/*
+ * These define virtual xattrs exposing the recursive directory
+ * statistics and layout metadata.
+ */
+struct ceph_vxattr_cb {
+ bool readonly;
+ char *name;
+ size_t (*getxattr_cb)(struct ceph_inode_info *ci, char *val,
+ size_t size);
+};
+
+/* directories */
+
+static size_t ceph_vxattrcb_entries(struct ceph_inode_info *ci, char *val,
+ size_t size)
+{
+ return snprintf(val, size, "%lld", ci->i_files + ci->i_subdirs);
+}
+
+static size_t ceph_vxattrcb_files(struct ceph_inode_info *ci, char *val,
+ size_t size)
+{
+ return snprintf(val, size, "%lld", ci->i_files);
+}
+
+static size_t ceph_vxattrcb_subdirs(struct ceph_inode_info *ci, char *val,
+ size_t size)
+{
+ return snprintf(val, size, "%lld", ci->i_subdirs);
+}
+
+static size_t ceph_vxattrcb_rentries(struct ceph_inode_info *ci, char *val,
+ size_t size)
+{
+ return snprintf(val, size, "%lld", ci->i_rfiles + ci->i_rsubdirs);
+}
+
+static size_t ceph_vxattrcb_rfiles(struct ceph_inode_info *ci, char *val,
+ size_t size)
+{
+ return snprintf(val, size, "%lld", ci->i_rfiles);
+}
+
+static size_t ceph_vxattrcb_rsubdirs(struct ceph_inode_info *ci, char *val,
+ size_t size)
+{
+ return snprintf(val, size, "%lld", ci->i_rsubdirs);
+}
+
+static size_t ceph_vxattrcb_rbytes(struct ceph_inode_info *ci, char *val,
+ size_t size)
+{
+ return snprintf(val, size, "%lld", ci->i_rbytes);
+}
+
+static size_t ceph_vxattrcb_rctime(struct ceph_inode_info *ci, char *val,
+ size_t size)
+{
+ return snprintf(val, size, "%ld.%ld", (long)ci->i_rctime.tv_sec,
+ (long)ci->i_rctime.tv_nsec);
+}
+
+static struct ceph_vxattr_cb ceph_dir_vxattrs[] = {
+ { true, "user.ceph.dir.entries", ceph_vxattrcb_entries},
+ { true, "user.ceph.dir.files", ceph_vxattrcb_files},
+ { true, "user.ceph.dir.subdirs", ceph_vxattrcb_subdirs},
+ { true, "user.ceph.dir.rentries", ceph_vxattrcb_rentries},
+ { true, "user.ceph.dir.rfiles", ceph_vxattrcb_rfiles},
+ { true, "user.ceph.dir.rsubdirs", ceph_vxattrcb_rsubdirs},
+ { true, "user.ceph.dir.rbytes", ceph_vxattrcb_rbytes},
+ { true, "user.ceph.dir.rctime", ceph_vxattrcb_rctime},
+ { true, NULL, NULL }
+};
+
+/* files */
+
+static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
+ size_t size)
+{
+ int ret;
+
+ ret = snprintf(val, size,
+ "chunk_bytes=%lld\nstripe_count=%lld\nobject_size=%lld\n",
+ (unsigned long long)ceph_file_layout_su(ci->i_layout),
+ (unsigned long long)ceph_file_layout_stripe_count(ci->i_layout),
+ (unsigned long long)ceph_file_layout_object_size(ci->i_layout));
+ if (ceph_file_layout_pg_preferred(ci->i_layout))
+ ret += snprintf(val + ret, size, "preferred_osd=%lld\n",
+ (unsigned long long)ceph_file_layout_pg_preferred(
+ ci->i_layout));
+ return ret;
+}
+
+static struct ceph_vxattr_cb ceph_file_vxattrs[] = {
+ { true, "user.ceph.layout", ceph_vxattrcb_layout},
+ { NULL, NULL }
+};
+
+static struct ceph_vxattr_cb *ceph_inode_vxattrs(struct inode *inode)
+{
+ if (S_ISDIR(inode->i_mode))
+ return ceph_dir_vxattrs;
+ else if (S_ISREG(inode->i_mode))
+ return ceph_file_vxattrs;
+ return NULL;
+}
+
+static struct ceph_vxattr_cb *ceph_match_vxattr(struct ceph_vxattr_cb *vxattr,
+ const char *name)
+{
+ do {
+ if (strcmp(vxattr->name, name) == 0)
+ return vxattr;
+ vxattr++;
+ } while (vxattr->name);
+ return NULL;
+}
+
+static int __set_xattr(struct ceph_inode_info *ci,
+ const char *name, int name_len,
+ const char *val, int val_len,
+ int dirty,
+ int should_free_name, int should_free_val,
+ struct ceph_inode_xattr **newxattr)
+{
+ struct rb_node **p;
+ struct rb_node *parent = NULL;
+ struct ceph_inode_xattr *xattr = NULL;
+ int c;
+ int new = 0;
+
+ p = &ci->i_xattrs.index.rb_node;
+ while (*p) {
+ parent = *p;
+ xattr = rb_entry(parent, struct ceph_inode_xattr, node);
+ c = strncmp(name, xattr->name, min(name_len, xattr->name_len));
+ if (c < 0)
+ p = &(*p)->rb_left;
+ else if (c > 0)
+ p = &(*p)->rb_right;
+ else {
+ if (name_len == xattr->name_len)
+ break;
+ else if (name_len < xattr->name_len)
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ }
+ xattr = NULL;
+ }
+
+ if (!xattr) {
+ new = 1;
+ xattr = *newxattr;
+ xattr->name = name;
+ xattr->name_len = name_len;
+ xattr->should_free_name = should_free_name;
+
+ ci->i_xattrs.count++;
+ dout("__set_xattr count=%d\n", ci->i_xattrs.count);
+ } else {
+ kfree(*newxattr);
+ *newxattr = NULL;
+ if (xattr->should_free_val)
+ kfree((void *)xattr->val);
+
+ if (should_free_name) {
+ kfree((void *)name);
+ name = xattr->name;
+ }
+ ci->i_xattrs.names_size -= xattr->name_len;
+ ci->i_xattrs.vals_size -= xattr->val_len;
+ }
+ if (!xattr) {
+ pr_err("__set_xattr ENOMEM on %p %llx.%llx xattr %s=%s\n",
+ &ci->vfs_inode, ceph_vinop(&ci->vfs_inode), name,
+ xattr->val);
+ return -ENOMEM;
+ }
+ ci->i_xattrs.names_size += name_len;
+ ci->i_xattrs.vals_size += val_len;
+ if (val)
+ xattr->val = val;
+ else
+ xattr->val = "";
+
+ xattr->val_len = val_len;
+ xattr->dirty = dirty;
+ xattr->should_free_val = (val && should_free_val);
+
+ if (new) {
+ rb_link_node(&xattr->node, parent, p);
+ rb_insert_color(&xattr->node, &ci->i_xattrs.index);
+ dout("__set_xattr_val p=%p\n", p);
+ }
+
+ dout("__set_xattr_val added %llx.%llx xattr %p %s=%.*s\n",
+ ceph_vinop(&ci->vfs_inode), xattr, name, val_len, val);
+
+ return 0;
+}
+
+static struct ceph_inode_xattr *__get_xattr(struct ceph_inode_info *ci,
+ const char *name)
+{
+ struct rb_node **p;
+ struct rb_node *parent = NULL;
+ struct ceph_inode_xattr *xattr = NULL;
+ int c;
+
+ p = &ci->i_xattrs.index.rb_node;
+ while (*p) {
+ parent = *p;
+ xattr = rb_entry(parent, struct ceph_inode_xattr, node);
+ c = strncmp(name, xattr->name, xattr->name_len);
+ if (c < 0)
+ p = &(*p)->rb_left;
+ else if (c > 0)
+ p = &(*p)->rb_right;
+ else {
+ dout("__get_xattr %s: found %.*s\n", name,
+ xattr->val_len, xattr->val);
+ return xattr;
+ }
+ }
+
+ dout("__get_xattr %s: not found\n", name);
+
+ return NULL;
+}
+
+static void __free_xattr(struct ceph_inode_xattr *xattr)
+{
+ BUG_ON(!xattr);
+
+ if (xattr->should_free_name)
+ kfree((void *)xattr->name);
+ if (xattr->should_free_val)
+ kfree((void *)xattr->val);
+
+ kfree(xattr);
+}
+
+static int __remove_xattr(struct ceph_inode_info *ci,
+ struct ceph_inode_xattr *xattr)
+{
+ if (!xattr)
+ return -EOPNOTSUPP;
+
+ rb_erase(&xattr->node, &ci->i_xattrs.index);
+
+ if (xattr->should_free_name)
+ kfree((void *)xattr->name);
+ if (xattr->should_free_val)
+ kfree((void *)xattr->val);
+
+ ci->i_xattrs.names_size -= xattr->name_len;
+ ci->i_xattrs.vals_size -= xattr->val_len;
+ ci->i_xattrs.count--;
+ kfree(xattr);
+
+ return 0;
+}
+
+static int __remove_xattr_by_name(struct ceph_inode_info *ci,
+ const char *name)
+{
+ struct rb_node **p;
+ struct ceph_inode_xattr *xattr;
+ int err;
+
+ p = &ci->i_xattrs.index.rb_node;
+ xattr = __get_xattr(ci, name);
+ err = __remove_xattr(ci, xattr);
+ return err;
+}
+
+static char *__copy_xattr_names(struct ceph_inode_info *ci,
+ char *dest)
+{
+ struct rb_node *p;
+ struct ceph_inode_xattr *xattr = NULL;
+
+ p = rb_first(&ci->i_xattrs.index);
+ dout("__copy_xattr_names count=%d\n", ci->i_xattrs.count);
+
+ while (p) {
+ xattr = rb_entry(p, struct ceph_inode_xattr, node);
+ memcpy(dest, xattr->name, xattr->name_len);
+ dest[xattr->name_len] = '\0';
+
+ dout("dest=%s %p (%s) (%d/%d)\n", dest, xattr, xattr->name,
+ xattr->name_len, ci->i_xattrs.names_size);
+
+ dest += xattr->name_len + 1;
+ p = rb_next(p);
+ }
+
+ return dest;
+}
+
+void __ceph_destroy_xattrs(struct ceph_inode_info *ci)
+{
+ struct rb_node *p, *tmp;
+ struct ceph_inode_xattr *xattr = NULL;
+
+ p = rb_first(&ci->i_xattrs.index);
+
+ dout("__ceph_destroy_xattrs p=%p\n", p);
+
+ while (p) {
+ xattr = rb_entry(p, struct ceph_inode_xattr, node);
+ tmp = p;
+ p = rb_next(tmp);
+ dout("__ceph_destroy_xattrs next p=%p (%.*s)\n", p,
+ xattr->name_len, xattr->name);
+ rb_erase(tmp, &ci->i_xattrs.index);
+
+ __free_xattr(xattr);
+ }
+
+ ci->i_xattrs.names_size = 0;
+ ci->i_xattrs.vals_size = 0;
+ ci->i_xattrs.index_version = 0;
+ ci->i_xattrs.count = 0;
+ ci->i_xattrs.index = RB_ROOT;
+}
+
+static int __build_xattrs(struct inode *inode)
+{
+ u32 namelen;
+ u32 numattr = 0;
+ void *p, *end;
+ u32 len;
+ const char *name, *val;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ int xattr_version;
+ struct ceph_inode_xattr **xattrs = NULL;
+ int err;
+ int i;
+
+ dout("__build_xattrs() len=%d\n",
+ ci->i_xattrs.blob ? (int)ci->i_xattrs.blob->vec.iov_len : 0);
+
+ if (ci->i_xattrs.index_version >= ci->i_xattrs.version)
+ return 0; /* already built */
+
+ __ceph_destroy_xattrs(ci);
+
+start:
+ /* updated internal xattr rb tree */
+ if (ci->i_xattrs.blob && ci->i_xattrs.blob->vec.iov_len > 4) {
+ p = ci->i_xattrs.blob->vec.iov_base;
+ end = p + ci->i_xattrs.blob->vec.iov_len;
+ ceph_decode_32_safe(&p, end, numattr, bad);
+ xattr_version = ci->i_xattrs.version;
+ spin_unlock(&inode->i_lock);
+
+ xattrs = kcalloc(numattr, sizeof(struct ceph_xattr *),
+ GFP_NOFS);
+ err = -ENOMEM;
+ if (!xattrs)
+ goto bad_lock;
+ memset(xattrs, 0, numattr*sizeof(struct ceph_xattr *));
+ for (i = 0; i < numattr; i++) {
+ xattrs[i] = kmalloc(sizeof(struct ceph_inode_xattr),
+ GFP_NOFS);
+ if (!xattrs[i])
+ goto bad_lock;
+ }
+
+ spin_lock(&inode->i_lock);
+ if (ci->i_xattrs.version != xattr_version) {
+ /* lost a race, retry */
+ for (i = 0; i < numattr; i++)
+ kfree(xattrs[i]);
+ kfree(xattrs);
+ goto start;
+ }
+ err = -EIO;
+ while (numattr--) {
+ ceph_decode_32_safe(&p, end, len, bad);
+ namelen = len;
+ name = p;
+ p += len;
+ ceph_decode_32_safe(&p, end, len, bad);
+ val = p;
+ p += len;
+
+ err = __set_xattr(ci, name, namelen, val, len,
+ 0, 0, 0, &xattrs[numattr]);
+
+ if (err < 0)
+ goto bad;
+ }
+ kfree(xattrs);
+ }
+ ci->i_xattrs.index_version = ci->i_xattrs.version;
+ ci->i_xattrs.dirty = false;
+
+ return err;
+bad_lock:
+ spin_lock(&inode->i_lock);
+bad:
+ if (xattrs) {
+ for (i = 0; i < numattr; i++)
+ kfree(xattrs[i]);
+ kfree(xattrs);
+ }
+ ci->i_xattrs.names_size = 0;
+ return err;
+}
+
+static int __get_required_blob_size(struct ceph_inode_info *ci, int name_size,
+ int val_size)
+{
+ /*
+ * 4 bytes for the length, and additional 4 bytes per each xattr name,
+ * 4 bytes per each value
+ */
+ int size = 4 + ci->i_xattrs.count*(4 + 4) +
+ ci->i_xattrs.names_size +
+ ci->i_xattrs.vals_size;
+ dout("__get_required_blob_size c=%d names.size=%d vals.size=%d\n",
+ ci->i_xattrs.count, ci->i_xattrs.names_size,
+ ci->i_xattrs.vals_size);
+
+ if (name_size)
+ size += 4 + 4 + name_size + val_size;
+
+ return size;
+}
+
+/*
+ * If there are dirty xattrs, reencode xattrs into the prealloc_blob
+ * and swap into place.
+ */
+void __ceph_build_xattrs_blob(struct ceph_inode_info *ci)
+{
+ struct rb_node *p;
+ struct ceph_inode_xattr *xattr = NULL;
+ void *dest;
+
+ dout("__build_xattrs_blob %p\n", &ci->vfs_inode);
+ if (ci->i_xattrs.dirty) {
+ int need = __get_required_blob_size(ci, 0, 0);
+
+ BUG_ON(need > ci->i_xattrs.prealloc_blob->alloc_len);
+
+ p = rb_first(&ci->i_xattrs.index);
+ dest = ci->i_xattrs.prealloc_blob->vec.iov_base;
+
+ ceph_encode_32(&dest, ci->i_xattrs.count);
+ while (p) {
+ xattr = rb_entry(p, struct ceph_inode_xattr, node);
+
+ ceph_encode_32(&dest, xattr->name_len);
+ memcpy(dest, xattr->name, xattr->name_len);
+ dest += xattr->name_len;
+ ceph_encode_32(&dest, xattr->val_len);
+ memcpy(dest, xattr->val, xattr->val_len);
+ dest += xattr->val_len;
+
+ p = rb_next(p);
+ }
+
+ /* adjust buffer len; it may be larger than we need */
+ ci->i_xattrs.prealloc_blob->vec.iov_len =
+ dest - ci->i_xattrs.prealloc_blob->vec.iov_base;
+
+ ceph_buffer_put(ci->i_xattrs.blob);
+ ci->i_xattrs.blob = ci->i_xattrs.prealloc_blob;
+ ci->i_xattrs.prealloc_blob = NULL;
+ ci->i_xattrs.dirty = false;
+ }
+}
+
+ssize_t ceph_getxattr(struct dentry *dentry, const char *name, void *value,
+ size_t size)
+{
+ struct inode *inode = dentry->d_inode;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
+ int err;
+ struct ceph_inode_xattr *xattr;
+ struct ceph_vxattr_cb *vxattr = NULL;
+
+ if (!ceph_is_valid_xattr(name))
+ return -ENODATA;
+
+ /* let's see if a virtual xattr was requested */
+ if (vxattrs)
+ vxattr = ceph_match_vxattr(vxattrs, name);
+
+ spin_lock(&inode->i_lock);
+ dout("getxattr %p ver=%lld index_ver=%lld\n", inode,
+ ci->i_xattrs.version, ci->i_xattrs.index_version);
+
+ if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1) &&
+ (ci->i_xattrs.index_version >= ci->i_xattrs.version)) {
+ goto get_xattr;
+ } else {
+ spin_unlock(&inode->i_lock);
+ /* get xattrs from mds (if we don't already have them) */
+ err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR);
+ if (err)
+ return err;
+ }
+
+ spin_lock(&inode->i_lock);
+
+ if (vxattr && vxattr->readonly) {
+ err = vxattr->getxattr_cb(ci, value, size);
+ goto out;
+ }
+
+ err = __build_xattrs(inode);
+ if (err < 0)
+ goto out;
+
+get_xattr:
+ err = -ENODATA; /* == ENOATTR */
+ xattr = __get_xattr(ci, name);
+ if (!xattr) {
+ if (vxattr)
+ err = vxattr->getxattr_cb(ci, value, size);
+ goto out;
+ }
+
+ err = -ERANGE;
+ if (size && size < xattr->val_len)
+ goto out;
+
+ err = xattr->val_len;
+ if (size == 0)
+ goto out;
+
+ memcpy(value, xattr->val, xattr->val_len);
+
+out:
+ spin_unlock(&inode->i_lock);
+ return err;
+}
+
+ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size)
+{
+ struct inode *inode = dentry->d_inode;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
+ u32 vir_namelen = 0;
+ u32 namelen;
+ int err;
+ u32 len;
+ int i;
+
+ spin_lock(&inode->i_lock);
+ dout("listxattr %p ver=%lld index_ver=%lld\n", inode,
+ ci->i_xattrs.version, ci->i_xattrs.index_version);
+
+ if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1) &&
+ (ci->i_xattrs.index_version > ci->i_xattrs.version)) {
+ goto list_xattr;
+ } else {
+ spin_unlock(&inode->i_lock);
+ err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR);
+ if (err)
+ return err;
+ }
+
+ spin_lock(&inode->i_lock);
+
+ err = __build_xattrs(inode);
+ if (err < 0)
+ goto out;
+
+list_xattr:
+ vir_namelen = 0;
+ /* include virtual dir xattrs */
+ if (vxattrs)
+ for (i = 0; vxattrs[i].name; i++)
+ vir_namelen += strlen(vxattrs[i].name) + 1;
+ /* adding 1 byte per each variable due to the null termination */
+ namelen = vir_namelen + ci->i_xattrs.names_size + ci->i_xattrs.count;
+ err = -ERANGE;
+ if (size && namelen > size)
+ goto out;
+
+ err = namelen;
+ if (size == 0)
+ goto out;
+
+ names = __copy_xattr_names(ci, names);
+
+ /* virtual xattr names, too */
+ if (vxattrs)
+ for (i = 0; vxattrs[i].name; i++) {
+ len = sprintf(names, "%s", vxattrs[i].name);
+ names += len + 1;
+ }
+
+out:
+ spin_unlock(&inode->i_lock);
+ return err;
+}
+
+static int ceph_sync_setxattr(struct dentry *dentry, const char *name,
+ const char *value, size_t size, int flags)
+{
+ struct ceph_client *client = ceph_client(dentry->d_sb);
+ struct inode *inode = dentry->d_inode;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct inode *parent_inode = dentry->d_parent->d_inode;
+ struct ceph_mds_request *req;
+ struct ceph_mds_client *mdsc = &client->mdsc;
+ int err;
+ int i, nr_pages;
+ struct page **pages = NULL;
+ void *kaddr;
+
+ /* copy value into some pages */
+ nr_pages = calc_pages_for(0, size);
+ if (nr_pages) {
+ pages = kmalloc(sizeof(pages[0])*nr_pages, GFP_NOFS);
+ if (!pages)
+ return -ENOMEM;
+ err = -ENOMEM;
+ for (i = 0; i < nr_pages; i++) {
+ pages[i] = alloc_page(GFP_NOFS);
+ if (!pages[i]) {
+ nr_pages = i;
+ goto out;
+ }
+ kaddr = kmap(pages[i]);
+ memcpy(kaddr, value + i*PAGE_CACHE_SIZE,
+ min(PAGE_CACHE_SIZE, size-i*PAGE_CACHE_SIZE));
+ }
+ }
+
+ dout("setxattr value=%.*s\n", (int)size, value);
+
+ /* do request */
+ req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETXATTR,
+ USE_AUTH_MDS);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+ req->r_inode = igrab(inode);
+ req->r_inode_drop = CEPH_CAP_XATTR_SHARED;
+ req->r_num_caps = 1;
+ req->r_args.setxattr.flags = cpu_to_le32(flags);
+ req->r_path2 = kstrdup(name, GFP_NOFS);
+
+ req->r_pages = pages;
+ req->r_num_pages = nr_pages;
+ req->r_data_len = size;
+
+ dout("xattr.ver (before): %lld\n", ci->i_xattrs.version);
+ err = ceph_mdsc_do_request(mdsc, parent_inode, req);
+ ceph_mdsc_put_request(req);
+ dout("xattr.ver (after): %lld\n", ci->i_xattrs.version);
+
+out:
+ if (pages) {
+ for (i = 0; i < nr_pages; i++)
+ __free_page(pages[i]);
+ kfree(pages);
+ }
+ return err;
+}
+
+int ceph_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
+{
+ struct inode *inode = dentry->d_inode;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
+ int err;
+ int name_len = strlen(name);
+ int val_len = size;
+ char *newname = NULL;
+ char *newval = NULL;
+ struct ceph_inode_xattr *xattr = NULL;
+ int issued;
+ int required_blob_size;
+
+ if (ceph_snap(inode) != CEPH_NOSNAP)
+ return -EROFS;
+
+ if (!ceph_is_valid_xattr(name))
+ return -EOPNOTSUPP;
+
+ if (vxattrs) {
+ struct ceph_vxattr_cb *vxattr =
+ ceph_match_vxattr(vxattrs, name);
+ if (vxattr && vxattr->readonly)
+ return -EOPNOTSUPP;
+ }
+
+ /* preallocate memory for xattr name, value, index node */
+ err = -ENOMEM;
+ newname = kmalloc(name_len + 1, GFP_NOFS);
+ if (!newname)
+ goto out;
+ memcpy(newname, name, name_len + 1);
+
+ if (val_len) {
+ newval = kmalloc(val_len + 1, GFP_NOFS);
+ if (!newval)
+ goto out;
+ memcpy(newval, value, val_len);
+ newval[val_len] = '\0';
+ }
+
+ xattr = kmalloc(sizeof(struct ceph_inode_xattr), GFP_NOFS);
+ if (!xattr)
+ goto out;
+
+ spin_lock(&inode->i_lock);
+retry:
+ issued = __ceph_caps_issued(ci, NULL);
+ if (!(issued & CEPH_CAP_XATTR_EXCL))
+ goto do_sync;
+ __build_xattrs(inode);
+
+ required_blob_size = __get_required_blob_size(ci, name_len, val_len);
+
+ if (!ci->i_xattrs.prealloc_blob ||
+ required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) {
+ struct ceph_buffer *blob = NULL;
+
+ spin_unlock(&inode->i_lock);
+ dout(" preaallocating new blob size=%d\n", required_blob_size);
+ blob = ceph_buffer_new_alloc(required_blob_size, GFP_NOFS);
+ if (!blob)
+ goto out;
+ spin_lock(&inode->i_lock);
+ ceph_buffer_put(ci->i_xattrs.prealloc_blob);
+ ci->i_xattrs.prealloc_blob = blob;
+ goto retry;
+ }
+
+ dout("setxattr %p issued %s\n", inode, ceph_cap_string(issued));
+ err = __set_xattr(ci, newname, name_len, newval,
+ val_len, 1, 1, 1, &xattr);
+ __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
+ ci->i_xattrs.dirty = true;
+ inode->i_ctime = CURRENT_TIME;
+ spin_unlock(&inode->i_lock);
+
+ return err;
+
+do_sync:
+ spin_unlock(&inode->i_lock);
+ err = ceph_sync_setxattr(dentry, name, value, size, flags);
+out:
+ kfree(newname);
+ kfree(newval);
+ kfree(xattr);
+ return err;
+}
+
+static int ceph_send_removexattr(struct dentry *dentry, const char *name)
+{
+ struct ceph_client *client = ceph_client(dentry->d_sb);
+ struct ceph_mds_client *mdsc = &client->mdsc;
+ struct inode *inode = dentry->d_inode;
+ struct inode *parent_inode = dentry->d_parent->d_inode;
+ struct ceph_mds_request *req;
+ int err;
+
+ req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_RMXATTR,
+ USE_AUTH_MDS);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+ req->r_inode = igrab(inode);
+ req->r_inode_drop = CEPH_CAP_XATTR_SHARED;
+ req->r_num_caps = 1;
+ req->r_path2 = kstrdup(name, GFP_NOFS);
+
+ err = ceph_mdsc_do_request(mdsc, parent_inode, req);
+ ceph_mdsc_put_request(req);
+ return err;
+}
+
+int ceph_removexattr(struct dentry *dentry, const char *name)
+{
+ struct inode *inode = dentry->d_inode;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
+ int issued;
+ int err;
+
+ if (ceph_snap(inode) != CEPH_NOSNAP)
+ return -EROFS;
+
+ if (!ceph_is_valid_xattr(name))
+ return -EOPNOTSUPP;
+
+ if (vxattrs) {
+ struct ceph_vxattr_cb *vxattr =
+ ceph_match_vxattr(vxattrs, name);
+ if (vxattr && vxattr->readonly)
+ return -EOPNOTSUPP;
+ }
+
+ spin_lock(&inode->i_lock);
+ __build_xattrs(inode);
+ issued = __ceph_caps_issued(ci, NULL);
+ dout("removexattr %p issued %s\n", inode, ceph_cap_string(issued));
+
+ if (!(issued & CEPH_CAP_XATTR_EXCL))
+ goto do_sync;
+
+ err = __remove_xattr_by_name(ceph_inode(inode), name);
+ __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
+ ci->i_xattrs.dirty = true;
+ inode->i_ctime = CURRENT_TIME;
+
+ spin_unlock(&inode->i_lock);
+
+ return err;
+do_sync:
+ spin_unlock(&inode->i_lock);
+ err = ceph_send_removexattr(dentry, name);
+ return err;
+}
+
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 43003e0bef18..b09098079916 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1577,7 +1577,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
out_err:
if (tcp_ses) {
- kfree(tcp_ses->hostname);
+ if (!IS_ERR(tcp_ses->hostname))
+ kfree(tcp_ses->hostname);
if (tcp_ses->ssocket)
sock_release(tcp_ses->ssocket);
kfree(tcp_ses);
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 627a60a6c1b1..f1fe5cb348a2 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -216,7 +216,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
posix_flags |= SMB_O_TRUNC;
if (oflags & O_APPEND)
posix_flags |= SMB_O_APPEND;
- if (oflags & O_SYNC)
+ /* be safe and imply O_SYNC for O_DSYNC */
+ if (oflags & O_DSYNC)
posix_flags |= SMB_O_SYNC;
if (oflags & O_DIRECTORY)
posix_flags |= SMB_O_DIRECTORY;
diff --git a/fs/cifs/export.c b/fs/cifs/export.c
index 75949d6a5f1b..6177f7cca16a 100644
--- a/fs/cifs/export.c
+++ b/fs/cifs/export.c
@@ -24,7 +24,7 @@
*/
/*
- * See Documentation/filesystems/Exporting
+ * See Documentation/filesystems/nfs/Exporting
* and examples in fs/exportfs
*
* Since cifs is a network file system, an "fsid" must be included for
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 429337eb7afe..057e1dae12ab 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -76,8 +76,10 @@ static inline fmode_t cifs_posix_convert_flags(unsigned int flags)
reopening a file. They had their effect on the original open */
if (flags & O_APPEND)
posix_flags |= (fmode_t)O_APPEND;
- if (flags & O_SYNC)
- posix_flags |= (fmode_t)O_SYNC;
+ if (flags & O_DSYNC)
+ posix_flags |= (fmode_t)O_DSYNC;
+ if (flags & __O_SYNC)
+ posix_flags |= (fmode_t)__O_SYNC;
if (flags & O_DIRECTORY)
posix_flags |= (fmode_t)O_DIRECTORY;
if (flags & O_NOFOLLOW)
diff --git a/fs/compat.c b/fs/compat.c
index d576b552e8e2..441ef9135179 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1170,11 +1170,10 @@ out:
if (iov != iovstack)
kfree(iov);
if ((ret + (type == READ)) > 0) {
- struct dentry *dentry = file->f_path.dentry;
if (type == READ)
- fsnotify_access(dentry);
+ fsnotify_access(file);
else
- fsnotify_modify(dentry);
+ fsnotify_modify(file);
}
return ret;
}
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 056fed62d0de..371e92eeb9a5 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -772,18 +772,23 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat,
}
/**
- * ecryptfs_truncate
+ * truncate_upper
* @dentry: The ecryptfs layer dentry
- * @new_length: The length to expand the file to
+ * @ia: Address of the ecryptfs inode's attributes
+ * @lower_ia: Address of the lower inode's attributes
*
* Function to handle truncations modifying the size of the file. Note
* that the file sizes are interpolated. When expanding, we are simply
- * writing strings of 0's out. When truncating, we need to modify the
- * underlying file size according to the page index interpolations.
+ * writing strings of 0's out. When truncating, we truncate the upper
+ * inode and update the lower_ia according to the page index
+ * interpolations. If ATTR_SIZE is set in lower_ia->ia_valid upon return,
+ * the caller must use lower_ia in a call to notify_change() to perform
+ * the truncation of the lower inode.
*
* Returns zero on success; non-zero otherwise
*/
-int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
+static int truncate_upper(struct dentry *dentry, struct iattr *ia,
+ struct iattr *lower_ia)
{
int rc = 0;
struct inode *inode = dentry->d_inode;
@@ -794,7 +799,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
loff_t lower_size_before_truncate;
loff_t lower_size_after_truncate;
- if (unlikely((new_length == i_size)))
+ if (unlikely((ia->ia_size == i_size)))
goto out;
crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
/* Set up a fake ecryptfs file, this is used to interface with
@@ -815,28 +820,30 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
&fake_ecryptfs_file,
ecryptfs_inode_to_private(dentry->d_inode)->lower_file);
/* Switch on growing or shrinking file */
- if (new_length > i_size) {
+ if (ia->ia_size > i_size) {
char zero[] = { 0x00 };
+ lower_ia->ia_valid &= ~ATTR_SIZE;
/* Write a single 0 at the last position of the file;
* this triggers code that will fill in 0's throughout
* the intermediate portion of the previous end of the
* file and the new and of the file */
rc = ecryptfs_write(&fake_ecryptfs_file, zero,
- (new_length - 1), 1);
- } else { /* new_length < i_size_read(inode) */
- /* We're chopping off all the pages down do the page
- * in which new_length is located. Fill in the end of
- * that page from (new_length & ~PAGE_CACHE_MASK) to
+ (ia->ia_size - 1), 1);
+ } else { /* ia->ia_size < i_size_read(inode) */
+ /* We're chopping off all the pages down to the page
+ * in which ia->ia_size is located. Fill in the end of
+ * that page from (ia->ia_size & ~PAGE_CACHE_MASK) to
* PAGE_CACHE_SIZE with zeros. */
size_t num_zeros = (PAGE_CACHE_SIZE
- - (new_length & ~PAGE_CACHE_MASK));
+ - (ia->ia_size & ~PAGE_CACHE_MASK));
if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
- rc = vmtruncate(inode, new_length);
+ rc = vmtruncate(inode, ia->ia_size);
if (rc)
goto out_free;
- rc = vmtruncate(lower_dentry->d_inode, new_length);
+ lower_ia->ia_size = ia->ia_size;
+ lower_ia->ia_valid |= ATTR_SIZE;
goto out_free;
}
if (num_zeros) {
@@ -848,7 +855,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
goto out_free;
}
rc = ecryptfs_write(&fake_ecryptfs_file, zeros_virt,
- new_length, num_zeros);
+ ia->ia_size, num_zeros);
kfree(zeros_virt);
if (rc) {
printk(KERN_ERR "Error attempting to zero out "
@@ -857,7 +864,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
goto out_free;
}
}
- vmtruncate(inode, new_length);
+ vmtruncate(inode, ia->ia_size);
rc = ecryptfs_write_inode_size_to_metadata(inode);
if (rc) {
printk(KERN_ERR "Problem with "
@@ -870,10 +877,12 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
lower_size_before_truncate =
upper_size_to_lower_size(crypt_stat, i_size);
lower_size_after_truncate =
- upper_size_to_lower_size(crypt_stat, new_length);
- if (lower_size_after_truncate < lower_size_before_truncate)
- vmtruncate(lower_dentry->d_inode,
- lower_size_after_truncate);
+ upper_size_to_lower_size(crypt_stat, ia->ia_size);
+ if (lower_size_after_truncate < lower_size_before_truncate) {
+ lower_ia->ia_size = lower_size_after_truncate;
+ lower_ia->ia_valid |= ATTR_SIZE;
+ } else
+ lower_ia->ia_valid &= ~ATTR_SIZE;
}
out_free:
if (ecryptfs_file_to_private(&fake_ecryptfs_file))
@@ -883,6 +892,33 @@ out:
return rc;
}
+/**
+ * ecryptfs_truncate
+ * @dentry: The ecryptfs layer dentry
+ * @new_length: The length to expand the file to
+ *
+ * Simple function that handles the truncation of an eCryptfs inode and
+ * its corresponding lower inode.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
+{
+ struct iattr ia = { .ia_valid = ATTR_SIZE, .ia_size = new_length };
+ struct iattr lower_ia = { .ia_valid = 0 };
+ int rc;
+
+ rc = truncate_upper(dentry, &ia, &lower_ia);
+ if (!rc && lower_ia.ia_valid & ATTR_SIZE) {
+ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+
+ mutex_lock(&lower_dentry->d_inode->i_mutex);
+ rc = notify_change(lower_dentry, &lower_ia);
+ mutex_unlock(&lower_dentry->d_inode->i_mutex);
+ }
+ return rc;
+}
+
static int
ecryptfs_permission(struct inode *inode, int mask)
{
@@ -905,6 +941,7 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
{
int rc = 0;
struct dentry *lower_dentry;
+ struct iattr lower_ia;
struct inode *inode;
struct inode *lower_inode;
struct ecryptfs_crypt_stat *crypt_stat;
@@ -943,15 +980,11 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
}
}
mutex_unlock(&crypt_stat->cs_mutex);
+ memcpy(&lower_ia, ia, sizeof(lower_ia));
+ if (ia->ia_valid & ATTR_FILE)
+ lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file);
if (ia->ia_valid & ATTR_SIZE) {
- ecryptfs_printk(KERN_DEBUG,
- "ia->ia_valid = [0x%x] ATTR_SIZE" " = [0x%x]\n",
- ia->ia_valid, ATTR_SIZE);
- rc = ecryptfs_truncate(dentry, ia->ia_size);
- /* ecryptfs_truncate handles resizing of the lower file */
- ia->ia_valid &= ~ATTR_SIZE;
- ecryptfs_printk(KERN_DEBUG, "ia->ia_valid = [%x]\n",
- ia->ia_valid);
+ rc = truncate_upper(dentry, ia, &lower_ia);
if (rc < 0)
goto out;
}
@@ -960,11 +993,11 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
* mode change is for clearing setuid/setgid bits. Allow lower fs
* to interpret this in its own way.
*/
- if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
- ia->ia_valid &= ~ATTR_MODE;
+ if (lower_ia.ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
+ lower_ia.ia_valid &= ~ATTR_MODE;
mutex_lock(&lower_dentry->d_inode->i_mutex);
- rc = notify_change(lower_dentry, ia);
+ rc = notify_change(lower_dentry, &lower_ia);
mutex_unlock(&lower_dentry->d_inode->i_mutex);
out:
fsstack_copy_attr_all(inode, lower_inode, NULL);
diff --git a/fs/exec.c b/fs/exec.c
index d49be6bc1793..d391886fb9b0 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -46,7 +46,6 @@
#include <linux/proc_fs.h>
#include <linux/mount.h>
#include <linux/security.h>
-#include <linux/ima.h>
#include <linux/syscalls.h>
#include <linux/tsacct_kern.h>
#include <linux/cn_proc.h>
@@ -130,7 +129,7 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
if (file->f_path.mnt->mnt_flags & MNT_NOEXEC)
goto exit;
- fsnotify_open(file->f_path.dentry);
+ fsnotify_open(file);
error = -ENOEXEC;
if(file->f_op) {
@@ -665,7 +664,7 @@ struct file *open_exec(const char *name)
if (file->f_path.mnt->mnt_flags & MNT_NOEXEC)
goto exit;
- fsnotify_open(file->f_path.dentry);
+ fsnotify_open(file);
err = deny_write_access(file);
if (err)
@@ -1211,9 +1210,6 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
retval = security_bprm_check(bprm);
if (retval)
return retval;
- retval = ima_bprm_check(bprm);
- if (retval)
- return retval;
/* kernel module loader fixup */
/* so we don't try to load run modprobe in kernel space. */
diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c
index 6c10f7476699..cd034e62a54c 100644
--- a/fs/exofs/inode.c
+++ b/fs/exofs/inode.c
@@ -906,6 +906,12 @@ out:
return ret;
}
+
+static void __oi_init(struct exofs_i_info *oi)
+{
+ init_waitqueue_head(&oi->i_wq);
+ oi->i_flags = 0;
+}
/*
* Fill in an inode read from the OSD and set it up for use
*/
@@ -923,13 +929,13 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino)
if (!(inode->i_state & I_NEW))
return inode;
oi = exofs_i(inode);
+ __oi_init(oi);
/* read the inode from the osd */
ret = exofs_get_inode(sb, oi, &fcb, &sanity);
if (ret)
goto bad_inode;
- init_waitqueue_head(&oi->i_wq);
set_obj_created(oi);
/* copy stuff from on-disk struct to in-memory struct */
@@ -950,8 +956,7 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino)
#ifdef EXOFS_DEBUG_OBJ_ISIZE
if ((inode->i_size != sanity) &&
(!exofs_inode_is_fast_symlink(inode))) {
- EXOFS_ERR("WARNING: Size of object from inode and "
- "attributes differ (%lld != %llu)\n",
+ EXOFS_ERR("WARNING: Size of inode=%llu != object=%llu\n",
inode->i_size, _LLU(sanity));
}
#endif
@@ -1061,8 +1066,8 @@ struct inode *exofs_new_inode(struct inode *dir, int mode)
return ERR_PTR(-ENOMEM);
oi = exofs_i(inode);
+ __oi_init(oi);
- init_waitqueue_head(&oi->i_wq);
set_obj_2bcreated(oi);
sbi = sb->s_fs_info;
diff --git a/fs/exofs/super.c b/fs/exofs/super.c
index 9f500dec3b59..920f0165edf3 100644
--- a/fs/exofs/super.c
+++ b/fs/exofs/super.c
@@ -257,6 +257,15 @@ static void exofs_write_super(struct super_block *sb)
sb->s_dirt = 0;
}
+static void _exofs_print_device(const char *msg, const char *dev_path,
+ struct osd_dev *od, u64 pid)
+{
+ const struct osd_dev_info *odi = osduld_device_info(od);
+
+ printk(KERN_NOTICE "exofs: %s %s osd_name-%s pid-0x%llx\n",
+ msg, dev_path ?: "", odi->osdname, _LLU(pid));
+}
+
/*
* This function is called when the vfs is freeing the superblock. We just
* need to free our own part.
@@ -279,6 +288,7 @@ static void exofs_put_super(struct super_block *sb)
msecs_to_jiffies(100));
}
+ _exofs_print_device("Unmounting", NULL, sbi->s_dev, sbi->s_pid);
osduld_put_device(sbi->s_dev);
kfree(sb->s_fs_info);
sb->s_fs_info = NULL;
@@ -395,6 +405,7 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
goto free_sbi;
}
+ _exofs_print_device("Mounting", opts->dev_name, sbi->s_dev, sbi->s_pid);
ret = 0;
out:
if (or)
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index 197c7db583c7..e9e175949a63 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -6,7 +6,7 @@
* and for mapping back from file handles to dentries.
*
* For details on why we do all the strange and hairy things in here
- * take a look at Documentation/filesystems/Exporting.
+ * take a look at Documentation/filesystems/nfs/Exporting.
*/
#include <linux/exportfs.h>
#include <linux/fs.h>
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index acf1b1423327..069a163393b4 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -1735,6 +1735,7 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb,
ssize_t ret;
int orphan = 0;
size_t count = iov_length(iov, nr_segs);
+ int retries = 0;
if (rw == WRITE) {
loff_t final_size = offset + count;
@@ -1757,9 +1758,12 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb,
}
}
+retry:
ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs,
ext3_get_block, NULL);
+ if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
+ goto retry;
if (orphan) {
int err;
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index 1d0418980f8d..2565b8c7e096 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -519,7 +519,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
metadata = 1;
/* We need to make sure we don't reuse
- * block released untill the transaction commit.
+ * block released until the transaction commit.
* writeback mode have weak data consistency so
* don't force data as metadata when freeing block
* for writeback mode.
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index bba12824defa..d527fd384582 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -3932,7 +3932,7 @@ static void ext4_mb_group_or_file(struct ext4_allocation_context *ac)
* per cpu locality group is to reduce the contention between block
* request from multiple CPUs.
*/
- ac->ac_lg = per_cpu_ptr(sbi->s_locality_groups, raw_smp_processor_id());
+ ac->ac_lg = __this_cpu_ptr(sbi->s_locality_groups);
/* we're going to use group allocation */
ac->ac_flags |= EXT4_MB_HINT_GROUP_ALLOC;
diff --git a/fs/file_table.c b/fs/file_table.c
index 8eb44042e009..4bef4c01ec6f 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/security.h>
-#include <linux/ima.h>
#include <linux/eventpoll.h>
#include <linux/rcupdate.h>
#include <linux/mount.h>
@@ -280,7 +279,6 @@ void __fput(struct file *file)
if (file->f_op && file->f_op->release)
file->f_op->release(inode, file);
security_file_free(file);
- ima_file_free(file);
if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL))
cdev_put(inode->i_cdev);
fops_put(file->f_op);
diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig
index 5971359d2090..4dcddf83326f 100644
--- a/fs/gfs2/Kconfig
+++ b/fs/gfs2/Kconfig
@@ -8,6 +8,8 @@ config GFS2_FS
select FS_POSIX_ACL
select CRC32
select SLOW_WORK
+ select QUOTA
+ select QUOTACTL
help
A cluster filesystem.
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
index 3fc4e3ac7d84..3eb1ea846173 100644
--- a/fs/gfs2/acl.c
+++ b/fs/gfs2/acl.c
@@ -12,6 +12,7 @@
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
+#include <linux/xattr.h>
#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>
#include <linux/gfs2_ondisk.h>
@@ -26,108 +27,44 @@
#include "trans.h"
#include "util.h"
-#define ACL_ACCESS 1
-#define ACL_DEFAULT 0
-
-int gfs2_acl_validate_set(struct gfs2_inode *ip, int access,
- struct gfs2_ea_request *er, int *remove, mode_t *mode)
+static const char *gfs2_acl_name(int type)
{
- struct posix_acl *acl;
- int error;
-
- error = gfs2_acl_validate_remove(ip, access);
- if (error)
- return error;
-
- if (!er->er_data)
- return -EINVAL;
-
- acl = posix_acl_from_xattr(er->er_data, er->er_data_len);
- if (IS_ERR(acl))
- return PTR_ERR(acl);
- if (!acl) {
- *remove = 1;
- return 0;
- }
-
- error = posix_acl_valid(acl);
- if (error)
- goto out;
-
- if (access) {
- error = posix_acl_equiv_mode(acl, mode);
- if (!error)
- *remove = 1;
- else if (error > 0)
- error = 0;
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ return GFS2_POSIX_ACL_ACCESS;
+ case ACL_TYPE_DEFAULT:
+ return GFS2_POSIX_ACL_DEFAULT;
}
-
-out:
- posix_acl_release(acl);
- return error;
-}
-
-int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access)
-{
- if (!GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl)
- return -EOPNOTSUPP;
- if (!is_owner_or_cap(&ip->i_inode))
- return -EPERM;
- if (S_ISLNK(ip->i_inode.i_mode))
- return -EOPNOTSUPP;
- if (!access && !S_ISDIR(ip->i_inode.i_mode))
- return -EACCES;
-
- return 0;
+ return NULL;
}
-static int acl_get(struct gfs2_inode *ip, const char *name,
- struct posix_acl **acl, struct gfs2_ea_location *el,
- char **datap, unsigned int *lenp)
+static struct posix_acl *gfs2_acl_get(struct gfs2_inode *ip, int type)
{
+ struct posix_acl *acl;
+ const char *name;
char *data;
- unsigned int len;
- int error;
-
- el->el_bh = NULL;
+ int len;
if (!ip->i_eattr)
- return 0;
-
- error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, name, el);
- if (error)
- return error;
- if (!el->el_ea)
- return 0;
- if (!GFS2_EA_DATA_LEN(el->el_ea))
- goto out;
+ return NULL;
- len = GFS2_EA_DATA_LEN(el->el_ea);
- data = kmalloc(len, GFP_NOFS);
- error = -ENOMEM;
- if (!data)
- goto out;
+ acl = get_cached_acl(&ip->i_inode, type);
+ if (acl != ACL_NOT_CACHED)
+ return acl;
- error = gfs2_ea_get_copy(ip, el, data, len);
- if (error < 0)
- goto out_kfree;
- error = 0;
+ name = gfs2_acl_name(type);
+ if (name == NULL)
+ return ERR_PTR(-EINVAL);
- if (acl) {
- *acl = posix_acl_from_xattr(data, len);
- if (IS_ERR(*acl))
- error = PTR_ERR(*acl);
- }
+ len = gfs2_xattr_acl_get(ip, name, &data);
+ if (len < 0)
+ return ERR_PTR(len);
+ if (len == 0)
+ return NULL;
-out_kfree:
- if (error || !datap) {
- kfree(data);
- } else {
- *datap = data;
- *lenp = len;
- }
-out:
- return error;
+ acl = posix_acl_from_xattr(data, len);
+ kfree(data);
+ return acl;
}
/**
@@ -140,14 +77,12 @@ out:
int gfs2_check_acl(struct inode *inode, int mask)
{
- struct gfs2_ea_location el;
- struct posix_acl *acl = NULL;
+ struct posix_acl *acl;
int error;
- error = acl_get(GFS2_I(inode), GFS2_POSIX_ACL_ACCESS, &acl, &el, NULL, NULL);
- brelse(el.el_bh);
- if (error)
- return error;
+ acl = gfs2_acl_get(GFS2_I(inode), ACL_TYPE_ACCESS);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
if (acl) {
error = posix_acl_permission(inode, acl, mask);
@@ -158,57 +93,75 @@ int gfs2_check_acl(struct inode *inode, int mask)
return -EAGAIN;
}
-static int munge_mode(struct gfs2_inode *ip, mode_t mode)
+static int gfs2_set_mode(struct inode *inode, mode_t mode)
{
- struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
- struct buffer_head *dibh;
- int error;
+ int error = 0;
- error = gfs2_trans_begin(sdp, RES_DINODE, 0);
- if (error)
- return error;
+ if (mode != inode->i_mode) {
+ struct iattr iattr;
- error = gfs2_meta_inode_buffer(ip, &dibh);
- if (!error) {
- gfs2_assert_withdraw(sdp,
- (ip->i_inode.i_mode & S_IFMT) == (mode & S_IFMT));
- ip->i_inode.i_mode = mode;
- gfs2_trans_add_bh(ip->i_gl, dibh, 1);
- gfs2_dinode_out(ip, dibh->b_data);
- brelse(dibh);
+ iattr.ia_valid = ATTR_MODE;
+ iattr.ia_mode = mode;
+
+ error = gfs2_setattr_simple(GFS2_I(inode), &iattr);
}
- gfs2_trans_end(sdp);
+ return error;
+}
+
+static int gfs2_acl_set(struct inode *inode, int type, struct posix_acl *acl)
+{
+ int error;
+ int len;
+ char *data;
+ const char *name = gfs2_acl_name(type);
- return 0;
+ BUG_ON(name == NULL);
+ len = posix_acl_to_xattr(acl, NULL, 0);
+ if (len == 0)
+ return 0;
+ data = kmalloc(len, GFP_NOFS);
+ if (data == NULL)
+ return -ENOMEM;
+ error = posix_acl_to_xattr(acl, data, len);
+ if (error < 0)
+ goto out;
+ error = gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, data, len, 0);
+ if (!error)
+ set_cached_acl(inode, type, acl);
+out:
+ kfree(data);
+ return error;
}
-int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
+int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode)
{
- struct gfs2_ea_location el;
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
- struct posix_acl *acl = NULL, *clone;
- mode_t mode = ip->i_inode.i_mode;
- char *data = NULL;
- unsigned int len;
- int error;
+ struct posix_acl *acl, *clone;
+ mode_t mode = inode->i_mode;
+ int error = 0;
if (!sdp->sd_args.ar_posix_acl)
return 0;
- if (S_ISLNK(ip->i_inode.i_mode))
+ if (S_ISLNK(inode->i_mode))
return 0;
- error = acl_get(dip, GFS2_POSIX_ACL_DEFAULT, &acl, &el, &data, &len);
- brelse(el.el_bh);
- if (error)
- return error;
+ acl = gfs2_acl_get(dip, ACL_TYPE_DEFAULT);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
if (!acl) {
mode &= ~current_umask();
- if (mode != ip->i_inode.i_mode)
- error = munge_mode(ip, mode);
+ if (mode != inode->i_mode)
+ error = gfs2_set_mode(inode, mode);
return error;
}
+ if (S_ISDIR(inode->i_mode)) {
+ error = gfs2_acl_set(inode, ACL_TYPE_DEFAULT, acl);
+ if (error)
+ goto out;
+ }
+
clone = posix_acl_clone(acl, GFP_NOFS);
error = -ENOMEM;
if (!clone)
@@ -216,43 +169,32 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
posix_acl_release(acl);
acl = clone;
- if (S_ISDIR(ip->i_inode.i_mode)) {
- error = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SYS,
- GFS2_POSIX_ACL_DEFAULT, data, len, 0);
- if (error)
- goto out;
- }
-
error = posix_acl_create_masq(acl, &mode);
if (error < 0)
goto out;
if (error == 0)
goto munge;
- posix_acl_to_xattr(acl, data, len);
- error = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SYS,
- GFS2_POSIX_ACL_ACCESS, data, len, 0);
+ error = gfs2_acl_set(inode, ACL_TYPE_ACCESS, acl);
if (error)
goto out;
munge:
- error = munge_mode(ip, mode);
+ error = gfs2_set_mode(inode, mode);
out:
posix_acl_release(acl);
- kfree(data);
return error;
}
int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
{
- struct posix_acl *acl = NULL, *clone;
- struct gfs2_ea_location el;
+ struct posix_acl *acl, *clone;
char *data;
unsigned int len;
int error;
- error = acl_get(ip, GFS2_POSIX_ACL_ACCESS, &acl, &el, &data, &len);
- if (error)
- goto out_brelse;
+ acl = gfs2_acl_get(ip, ACL_TYPE_ACCESS);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
if (!acl)
return gfs2_setattr_simple(ip, attr);
@@ -265,15 +207,134 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
error = posix_acl_chmod_masq(acl, attr->ia_mode);
if (!error) {
+ len = posix_acl_to_xattr(acl, NULL, 0);
+ data = kmalloc(len, GFP_NOFS);
+ error = -ENOMEM;
+ if (data == NULL)
+ goto out;
posix_acl_to_xattr(acl, data, len);
- error = gfs2_ea_acl_chmod(ip, &el, attr, data);
+ error = gfs2_xattr_acl_chmod(ip, attr, data);
+ kfree(data);
+ set_cached_acl(&ip->i_inode, ACL_TYPE_ACCESS, acl);
}
out:
posix_acl_release(acl);
- kfree(data);
-out_brelse:
- brelse(el.el_bh);
return error;
}
+static int gfs2_acl_type(const char *name)
+{
+ if (strcmp(name, GFS2_POSIX_ACL_ACCESS) == 0)
+ return ACL_TYPE_ACCESS;
+ if (strcmp(name, GFS2_POSIX_ACL_DEFAULT) == 0)
+ return ACL_TYPE_DEFAULT;
+ return -EINVAL;
+}
+
+static int gfs2_xattr_system_get(struct inode *inode, const char *name,
+ void *buffer, size_t size)
+{
+ struct posix_acl *acl;
+ int type;
+ int error;
+
+ type = gfs2_acl_type(name);
+ if (type < 0)
+ return type;
+
+ acl = gfs2_acl_get(GFS2_I(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 gfs2_xattr_system_set(struct inode *inode, const char *name,
+ const void *value, size_t size, int flags)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
+ struct posix_acl *acl = NULL;
+ int error = 0, type;
+
+ if (!sdp->sd_args.ar_posix_acl)
+ return -EOPNOTSUPP;
+
+ type = gfs2_acl_type(name);
+ if (type < 0)
+ return type;
+ if (flags & XATTR_CREATE)
+ return -EINVAL;
+ if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
+ return value ? -EACCES : 0;
+ if ((current_fsuid() != inode->i_uid) && !capable(CAP_FOWNER))
+ return -EPERM;
+ if (S_ISLNK(inode->i_mode))
+ return -EOPNOTSUPP;
+
+ if (!value)
+ goto set_acl;
+
+ acl = posix_acl_from_xattr(value, size);
+ if (!acl) {
+ /*
+ * acl_set_file(3) may request that we set default ACLs with
+ * zero length -- defend (gracefully) against that here.
+ */
+ goto out;
+ }
+ if (IS_ERR(acl)) {
+ error = PTR_ERR(acl);
+ goto out;
+ }
+
+ error = posix_acl_valid(acl);
+ if (error)
+ goto out_release;
+
+ error = -EINVAL;
+ if (acl->a_count > GFS2_ACL_MAX_ENTRIES)
+ goto out_release;
+
+ if (type == ACL_TYPE_ACCESS) {
+ mode_t mode = inode->i_mode;
+ error = posix_acl_equiv_mode(acl, &mode);
+
+ if (error <= 0) {
+ posix_acl_release(acl);
+ acl = NULL;
+
+ if (error < 0)
+ return error;
+ }
+
+ error = gfs2_set_mode(inode, mode);
+ if (error)
+ goto out_release;
+ }
+
+set_acl:
+ error = gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, value, size, 0);
+ if (!error) {
+ if (acl)
+ set_cached_acl(inode, type, acl);
+ else
+ forget_cached_acl(inode, type);
+ }
+out_release:
+ posix_acl_release(acl);
+out:
+ return error;
+}
+
+struct xattr_handler gfs2_xattr_system_handler = {
+ .prefix = XATTR_SYSTEM_PREFIX,
+ .get = gfs2_xattr_system_get,
+ .set = gfs2_xattr_system_set,
+};
+
diff --git a/fs/gfs2/acl.h b/fs/gfs2/acl.h
index 6751930bfb64..9306a2e6620c 100644
--- a/fs/gfs2/acl.h
+++ b/fs/gfs2/acl.h
@@ -13,26 +13,12 @@
#include "incore.h"
#define GFS2_POSIX_ACL_ACCESS "posix_acl_access"
-#define GFS2_POSIX_ACL_ACCESS_LEN 16
#define GFS2_POSIX_ACL_DEFAULT "posix_acl_default"
-#define GFS2_POSIX_ACL_DEFAULT_LEN 17
+#define GFS2_ACL_MAX_ENTRIES 25
-#define GFS2_ACL_IS_ACCESS(name, len) \
- ((len) == GFS2_POSIX_ACL_ACCESS_LEN && \
- !memcmp(GFS2_POSIX_ACL_ACCESS, (name), (len)))
-
-#define GFS2_ACL_IS_DEFAULT(name, len) \
- ((len) == GFS2_POSIX_ACL_DEFAULT_LEN && \
- !memcmp(GFS2_POSIX_ACL_DEFAULT, (name), (len)))
-
-struct gfs2_ea_request;
-
-int gfs2_acl_validate_set(struct gfs2_inode *ip, int access,
- struct gfs2_ea_request *er,
- int *remove, mode_t *mode);
-int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access);
-int gfs2_check_acl(struct inode *inode, int mask);
-int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip);
-int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr);
+extern int gfs2_check_acl(struct inode *inode, int mask);
+extern int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode);
+extern int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr);
+extern struct xattr_handler gfs2_xattr_system_handler;
#endif /* __ACL_DOT_H__ */
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 6d47379e794b..5e630c389938 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -13,6 +13,7 @@
#include <linux/buffer_head.h>
#include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
+#include <trace/events/gfs2.h>
#include "gfs2.h"
#include "incore.h"
@@ -25,7 +26,6 @@
#include "trans.h"
#include "dir.h"
#include "util.h"
-#include "trace_gfs2.h"
/* This doesn't need to be that large as max 64 bit pointers in a 4k
* block is 512, so __u16 is fine for that. It saves stack space to
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 8b674b1f3a55..12390765b57d 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -39,8 +39,9 @@
#include "super.h"
#include "util.h"
#include "bmap.h"
+
#define CREATE_TRACE_POINTS
-#include "trace_gfs2.h"
+#include <trace/events/gfs2.h>
struct gfs2_gl_hash_bucket {
struct hlist_head hb_list;
@@ -672,12 +673,17 @@ out:
return;
out_sched:
+ clear_bit(GLF_LOCK, &gl->gl_flags);
+ smp_mb__after_clear_bit();
gfs2_glock_hold(gl);
if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
gfs2_glock_put_nolock(gl);
+ return;
+
out_unlock:
clear_bit(GLF_LOCK, &gl->gl_flags);
- goto out;
+ smp_mb__after_clear_bit();
+ return;
}
static void delete_work_func(struct work_struct *work)
@@ -1375,10 +1381,11 @@ static int gfs2_shrink_glock_memory(int nr, gfp_t gfp_mask)
handle_callback(gl, LM_ST_UNLOCKED, 0);
nr--;
}
+ clear_bit(GLF_LOCK, &gl->gl_flags);
+ smp_mb__after_clear_bit();
if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
gfs2_glock_put_nolock(gl);
spin_unlock(&gl->gl_spin);
- clear_bit(GLF_LOCK, &gl->gl_flags);
spin_lock(&lru_lock);
continue;
}
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
index c609894ec0d0..13f0bd228132 100644
--- a/fs/gfs2/glock.h
+++ b/fs/gfs2/glock.h
@@ -180,15 +180,6 @@ static inline int gfs2_glock_is_held_shrd(struct gfs2_glock *gl)
return gl->gl_state == LM_ST_SHARED;
}
-static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl)
-{
- int ret;
- spin_lock(&gl->gl_spin);
- ret = test_bit(GLF_DEMOTE, &gl->gl_flags);
- spin_unlock(&gl->gl_spin);
- return ret;
-}
-
int gfs2_glock_get(struct gfs2_sbd *sdp,
u64 number, const struct gfs2_glock_operations *glops,
int create, struct gfs2_glock **glp);
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 6985eef06c39..78554acc0605 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -13,6 +13,7 @@
#include <linux/buffer_head.h>
#include <linux/gfs2_ondisk.h>
#include <linux/bio.h>
+#include <linux/posix_acl.h>
#include "gfs2.h"
#include "incore.h"
@@ -184,8 +185,10 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags)
if (flags & DIO_METADATA) {
struct address_space *mapping = gl->gl_aspace->i_mapping;
truncate_inode_pages(mapping, 0);
- if (ip)
+ if (ip) {
set_bit(GIF_INVALID, &ip->i_flags);
+ forget_all_cached_acls(&ip->i_inode);
+ }
}
if (ip == GFS2_I(gl->gl_sbd->sd_rindex))
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 6edb423f90b3..c239b0f969c8 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -430,6 +430,9 @@ struct gfs2_args {
unsigned int ar_discard:1; /* discard requests */
unsigned int ar_errors:2; /* errors=withdraw | panic */
int ar_commit; /* Commit interval */
+ int ar_statfs_quantum; /* The fast statfs interval */
+ int ar_quota_quantum; /* The quota interval */
+ int ar_statfs_percent; /* The % change to force sync */
};
struct gfs2_tune {
@@ -558,6 +561,7 @@ struct gfs2_sbd {
spinlock_t sd_statfs_spin;
struct gfs2_statfs_change_host sd_statfs_master;
struct gfs2_statfs_change_host sd_statfs_local;
+ int sd_statfs_force_sync;
/* Resource group stuff */
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index fb15d3b1f409..6380cd9314b0 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -871,7 +871,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
if (error)
goto fail_gunlock2;
- error = gfs2_acl_create(dip, GFS2_I(inode));
+ error = gfs2_acl_create(dip, inode);
if (error)
goto fail_gunlock2;
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index 13c6237c5f67..70beadc28ca2 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -18,6 +18,7 @@
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/bio.h>
+#include <trace/events/gfs2.h>
#include "gfs2.h"
#include "incore.h"
@@ -28,7 +29,6 @@
#include "meta_io.h"
#include "util.h"
#include "dir.h"
-#include "trace_gfs2.h"
#define PULL 1
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 9969ff062c5b..c038ae65be45 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -15,6 +15,7 @@
#include <linux/gfs2_ondisk.h>
#include <linux/bio.h>
#include <linux/fs.h>
+#include <trace/events/gfs2.h>
#include "gfs2.h"
#include "incore.h"
@@ -27,7 +28,6 @@
#include "rgrp.h"
#include "trans.h"
#include "util.h"
-#include "trace_gfs2.h"
/**
* gfs2_pin - Pin a buffer in memory
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index 52fb6c048981..cab6c8a61bf6 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -18,6 +18,8 @@
#include <linux/mount.h>
#include <linux/gfs2_ondisk.h>
#include <linux/slow-work.h>
+#include <linux/quotaops.h>
+#include <trace/events/gfs2.h>
#include "gfs2.h"
#include "incore.h"
@@ -33,7 +35,6 @@
#include "log.h"
#include "quota.h"
#include "dir.h"
-#include "trace_gfs2.h"
#define DO 0
#define UNDO 1
@@ -62,13 +63,10 @@ static void gfs2_tune_init(struct gfs2_tune *gt)
gt->gt_quota_warn_period = 10;
gt->gt_quota_scale_num = 1;
gt->gt_quota_scale_den = 1;
- gt->gt_quota_quantum = 60;
gt->gt_new_files_jdata = 0;
gt->gt_max_readahead = 1 << 18;
gt->gt_stall_secs = 600;
gt->gt_complain_secs = 10;
- gt->gt_statfs_quantum = 30;
- gt->gt_statfs_slow = 0;
}
static struct gfs2_sbd *init_sbd(struct super_block *sb)
@@ -1114,7 +1112,7 @@ void gfs2_online_uevent(struct gfs2_sbd *sdp)
* Returns: errno
*/
-static int fill_super(struct super_block *sb, void *data, int silent)
+static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent)
{
struct gfs2_sbd *sdp;
struct gfs2_holder mount_gh;
@@ -1125,17 +1123,7 @@ static int fill_super(struct super_block *sb, void *data, int silent)
printk(KERN_WARNING "GFS2: can't alloc struct gfs2_sbd\n");
return -ENOMEM;
}
-
- sdp->sd_args.ar_quota = GFS2_QUOTA_DEFAULT;
- sdp->sd_args.ar_data = GFS2_DATA_DEFAULT;
- sdp->sd_args.ar_commit = 60;
- sdp->sd_args.ar_errors = GFS2_ERRORS_DEFAULT;
-
- error = gfs2_mount_args(sdp, &sdp->sd_args, data);
- if (error) {
- printk(KERN_WARNING "GFS2: can't parse mount arguments\n");
- goto fail;
- }
+ sdp->sd_args = *args;
if (sdp->sd_args.ar_spectator) {
sb->s_flags |= MS_RDONLY;
@@ -1148,6 +1136,8 @@ static int fill_super(struct super_block *sb, void *data, int silent)
sb->s_op = &gfs2_super_ops;
sb->s_export_op = &gfs2_export_ops;
sb->s_xattr = gfs2_xattr_handlers;
+ sb->s_qcop = &gfs2_quotactl_ops;
+ sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE;
sb->s_time_gran = 1;
sb->s_maxbytes = MAX_LFS_FILESIZE;
@@ -1160,6 +1150,15 @@ static int fill_super(struct super_block *sb, void *data, int silent)
sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift;
sdp->sd_tune.gt_log_flush_secs = sdp->sd_args.ar_commit;
+ sdp->sd_tune.gt_quota_quantum = sdp->sd_args.ar_quota_quantum;
+ if (sdp->sd_args.ar_statfs_quantum) {
+ sdp->sd_tune.gt_statfs_slow = 0;
+ sdp->sd_tune.gt_statfs_quantum = sdp->sd_args.ar_statfs_quantum;
+ }
+ else {
+ sdp->sd_tune.gt_statfs_slow = 1;
+ sdp->sd_tune.gt_statfs_quantum = 30;
+ }
error = init_names(sdp, silent);
if (error)
@@ -1243,18 +1242,127 @@ fail:
return error;
}
-static int gfs2_get_sb(struct file_system_type *fs_type, int flags,
- const char *dev_name, void *data, struct vfsmount *mnt)
+static int set_gfs2_super(struct super_block *s, void *data)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, fill_super, mnt);
+ s->s_bdev = data;
+ s->s_dev = s->s_bdev->bd_dev;
+
+ /*
+ * We set the bdi here to the queue backing, file systems can
+ * overwrite this in ->fill_super()
+ */
+ s->s_bdi = &bdev_get_queue(s->s_bdev)->backing_dev_info;
+ return 0;
}
-static int test_meta_super(struct super_block *s, void *ptr)
+static int test_gfs2_super(struct super_block *s, void *ptr)
{
struct block_device *bdev = ptr;
return (bdev == s->s_bdev);
}
+/**
+ * gfs2_get_sb - Get the GFS2 superblock
+ * @fs_type: The GFS2 filesystem type
+ * @flags: Mount flags
+ * @dev_name: The name of the device
+ * @data: The mount arguments
+ * @mnt: The vfsmnt for this mount
+ *
+ * Q. Why not use get_sb_bdev() ?
+ * A. We need to select one of two root directories to mount, independent
+ * of whether this is the initial, or subsequent, mount of this sb
+ *
+ * Returns: 0 or -ve on error
+ */
+
+static int gfs2_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data, struct vfsmount *mnt)
+{
+ struct block_device *bdev;
+ struct super_block *s;
+ fmode_t mode = FMODE_READ;
+ int error;
+ struct gfs2_args args;
+ struct gfs2_sbd *sdp;
+
+ if (!(flags & MS_RDONLY))
+ mode |= FMODE_WRITE;
+
+ bdev = open_bdev_exclusive(dev_name, mode, fs_type);
+ if (IS_ERR(bdev))
+ return PTR_ERR(bdev);
+
+ /*
+ * once the super is inserted into the list by sget, s_umount
+ * will protect the lockfs code from trying to start a snapshot
+ * while we are mounting
+ */
+ mutex_lock(&bdev->bd_fsfreeze_mutex);
+ if (bdev->bd_fsfreeze_count > 0) {
+ mutex_unlock(&bdev->bd_fsfreeze_mutex);
+ error = -EBUSY;
+ goto error_bdev;
+ }
+ s = sget(fs_type, test_gfs2_super, set_gfs2_super, bdev);
+ mutex_unlock(&bdev->bd_fsfreeze_mutex);
+ error = PTR_ERR(s);
+ if (IS_ERR(s))
+ goto error_bdev;
+
+ memset(&args, 0, sizeof(args));
+ args.ar_quota = GFS2_QUOTA_DEFAULT;
+ args.ar_data = GFS2_DATA_DEFAULT;
+ args.ar_commit = 60;
+ args.ar_statfs_quantum = 30;
+ args.ar_quota_quantum = 60;
+ args.ar_errors = GFS2_ERRORS_DEFAULT;
+
+ error = gfs2_mount_args(&args, data);
+ if (error) {
+ printk(KERN_WARNING "GFS2: can't parse mount arguments\n");
+ if (s->s_root)
+ goto error_super;
+ deactivate_locked_super(s);
+ return error;
+ }
+
+ if (s->s_root) {
+ error = -EBUSY;
+ if ((flags ^ s->s_flags) & MS_RDONLY)
+ goto error_super;
+ close_bdev_exclusive(bdev, mode);
+ } else {
+ char b[BDEVNAME_SIZE];
+
+ s->s_flags = flags;
+ s->s_mode = mode;
+ strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
+ sb_set_blocksize(s, block_size(bdev));
+ error = fill_super(s, &args, flags & MS_SILENT ? 1 : 0);
+ if (error) {
+ deactivate_locked_super(s);
+ return error;
+ }
+ s->s_flags |= MS_ACTIVE;
+ bdev->bd_super = s;
+ }
+
+ sdp = s->s_fs_info;
+ mnt->mnt_sb = s;
+ if (args.ar_meta)
+ mnt->mnt_root = dget(sdp->sd_master_dir);
+ else
+ mnt->mnt_root = dget(sdp->sd_root_dir);
+ return 0;
+
+error_super:
+ deactivate_locked_super(s);
+error_bdev:
+ close_bdev_exclusive(bdev, mode);
+ return error;
+}
+
static int set_meta_super(struct super_block *s, void *ptr)
{
return -EINVAL;
@@ -1274,13 +1382,17 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags,
dev_name, error);
return error;
}
- s = sget(&gfs2_fs_type, test_meta_super, set_meta_super,
+ s = sget(&gfs2_fs_type, test_gfs2_super, set_meta_super,
path.dentry->d_inode->i_sb->s_bdev);
path_put(&path);
if (IS_ERR(s)) {
printk(KERN_WARNING "GFS2: gfs2 mount does not exist\n");
return PTR_ERR(s);
}
+ if ((flags ^ s->s_flags) & MS_RDONLY) {
+ deactivate_locked_super(s);
+ return -EBUSY;
+ }
sdp = s->s_fs_info;
mnt->mnt_sb = s;
mnt->mnt_root = dget(sdp->sd_master_dir);
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index 2e9b9326bfc9..e3bf6eab8750 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -15,7 +15,7 @@
* fuzziness in the current usage value of IDs that are being used on different
* nodes in the cluster simultaneously. So, it is possible for a user on
* multiple nodes to overrun their quota, but that overrun is controlable.
- * Since quota tags are part of transactions, there is no need to a quota check
+ * Since quota tags are part of transactions, there is no need for a quota check
* program to be run on node crashes or anything like that.
*
* There are couple of knobs that let the administrator manage the quota
@@ -47,6 +47,8 @@
#include <linux/gfs2_ondisk.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
+#include <linux/quota.h>
+#include <linux/dqblk_xfs.h>
#include "gfs2.h"
#include "incore.h"
@@ -65,13 +67,6 @@
#define QUOTA_USER 1
#define QUOTA_GROUP 0
-struct gfs2_quota_host {
- u64 qu_limit;
- u64 qu_warn;
- s64 qu_value;
- u32 qu_ll_next;
-};
-
struct gfs2_quota_change_host {
u64 qc_change;
u32 qc_flags; /* GFS2_QCF_... */
@@ -164,7 +159,7 @@ fail:
return error;
}
-static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, int create,
+static int qd_get(struct gfs2_sbd *sdp, int user, u32 id,
struct gfs2_quota_data **qdp)
{
struct gfs2_quota_data *qd = NULL, *new_qd = NULL;
@@ -202,7 +197,7 @@ static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, int create,
spin_unlock(&qd_lru_lock);
- if (qd || !create) {
+ if (qd) {
if (new_qd) {
gfs2_glock_put(new_qd->qd_gl);
kmem_cache_free(gfs2_quotad_cachep, new_qd);
@@ -461,12 +456,12 @@ static void qd_unlock(struct gfs2_quota_data *qd)
qd_put(qd);
}
-static int qdsb_get(struct gfs2_sbd *sdp, int user, u32 id, int create,
+static int qdsb_get(struct gfs2_sbd *sdp, int user, u32 id,
struct gfs2_quota_data **qdp)
{
int error;
- error = qd_get(sdp, user, id, create, qdp);
+ error = qd_get(sdp, user, id, qdp);
if (error)
return error;
@@ -508,20 +503,20 @@ int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid)
if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
return 0;
- error = qdsb_get(sdp, QUOTA_USER, ip->i_inode.i_uid, CREATE, qd);
+ error = qdsb_get(sdp, QUOTA_USER, ip->i_inode.i_uid, qd);
if (error)
goto out;
al->al_qd_num++;
qd++;
- error = qdsb_get(sdp, QUOTA_GROUP, ip->i_inode.i_gid, CREATE, qd);
+ error = qdsb_get(sdp, QUOTA_GROUP, ip->i_inode.i_gid, qd);
if (error)
goto out;
al->al_qd_num++;
qd++;
if (uid != NO_QUOTA_CHANGE && uid != ip->i_inode.i_uid) {
- error = qdsb_get(sdp, QUOTA_USER, uid, CREATE, qd);
+ error = qdsb_get(sdp, QUOTA_USER, uid, qd);
if (error)
goto out;
al->al_qd_num++;
@@ -529,7 +524,7 @@ int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid)
}
if (gid != NO_QUOTA_CHANGE && gid != ip->i_inode.i_gid) {
- error = qdsb_get(sdp, QUOTA_GROUP, gid, CREATE, qd);
+ error = qdsb_get(sdp, QUOTA_GROUP, gid, qd);
if (error)
goto out;
al->al_qd_num++;
@@ -617,48 +612,36 @@ static void do_qc(struct gfs2_quota_data *qd, s64 change)
mutex_unlock(&sdp->sd_quota_mutex);
}
-static void gfs2_quota_in(struct gfs2_quota_host *qu, const void *buf)
-{
- const struct gfs2_quota *str = buf;
-
- qu->qu_limit = be64_to_cpu(str->qu_limit);
- qu->qu_warn = be64_to_cpu(str->qu_warn);
- qu->qu_value = be64_to_cpu(str->qu_value);
- qu->qu_ll_next = be32_to_cpu(str->qu_ll_next);
-}
-
-static void gfs2_quota_out(const struct gfs2_quota_host *qu, void *buf)
-{
- struct gfs2_quota *str = buf;
-
- str->qu_limit = cpu_to_be64(qu->qu_limit);
- str->qu_warn = cpu_to_be64(qu->qu_warn);
- str->qu_value = cpu_to_be64(qu->qu_value);
- str->qu_ll_next = cpu_to_be32(qu->qu_ll_next);
- memset(&str->qu_reserved, 0, sizeof(str->qu_reserved));
-}
-
/**
- * gfs2_adjust_quota
+ * gfs2_adjust_quota - adjust record of current block usage
+ * @ip: The quota inode
+ * @loc: Offset of the entry in the quota file
+ * @change: The amount of usage change to record
+ * @qd: The quota data
+ * @fdq: The updated limits to record
*
* This function was mostly borrowed from gfs2_block_truncate_page which was
* in turn mostly borrowed from ext3
+ *
+ * Returns: 0 or -ve on error
*/
+
static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
- s64 change, struct gfs2_quota_data *qd)
+ s64 change, struct gfs2_quota_data *qd,
+ struct fs_disk_quota *fdq)
{
struct inode *inode = &ip->i_inode;
struct address_space *mapping = inode->i_mapping;
unsigned long index = loc >> PAGE_CACHE_SHIFT;
unsigned offset = loc & (PAGE_CACHE_SIZE - 1);
unsigned blocksize, iblock, pos;
- struct buffer_head *bh;
+ struct buffer_head *bh, *dibh;
struct page *page;
void *kaddr;
- char *ptr;
- struct gfs2_quota_host qp;
+ struct gfs2_quota *qp;
s64 value;
int err = -EIO;
+ u64 size;
if (gfs2_is_stuffed(ip))
gfs2_unstuff_dinode(ip, NULL);
@@ -700,18 +683,38 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
gfs2_trans_add_bh(ip->i_gl, bh, 0);
kaddr = kmap_atomic(page, KM_USER0);
- ptr = kaddr + offset;
- gfs2_quota_in(&qp, ptr);
- qp.qu_value += change;
- value = qp.qu_value;
- gfs2_quota_out(&qp, ptr);
+ qp = kaddr + offset;
+ value = (s64)be64_to_cpu(qp->qu_value) + change;
+ qp->qu_value = cpu_to_be64(value);
+ qd->qd_qb.qb_value = qp->qu_value;
+ if (fdq) {
+ if (fdq->d_fieldmask & FS_DQ_BSOFT) {
+ qp->qu_warn = cpu_to_be64(fdq->d_blk_softlimit);
+ qd->qd_qb.qb_warn = qp->qu_warn;
+ }
+ if (fdq->d_fieldmask & FS_DQ_BHARD) {
+ qp->qu_limit = cpu_to_be64(fdq->d_blk_hardlimit);
+ qd->qd_qb.qb_limit = qp->qu_limit;
+ }
+ }
flush_dcache_page(page);
kunmap_atomic(kaddr, KM_USER0);
- err = 0;
- qd->qd_qb.qb_magic = cpu_to_be32(GFS2_MAGIC);
- qd->qd_qb.qb_value = cpu_to_be64(value);
- ((struct gfs2_quota_lvb*)(qd->qd_gl->gl_lvb))->qb_magic = cpu_to_be32(GFS2_MAGIC);
- ((struct gfs2_quota_lvb*)(qd->qd_gl->gl_lvb))->qb_value = cpu_to_be64(value);
+
+ err = gfs2_meta_inode_buffer(ip, &dibh);
+ if (err)
+ goto unlock;
+
+ size = loc + sizeof(struct gfs2_quota);
+ if (size > inode->i_size) {
+ ip->i_disksize = size;
+ i_size_write(inode, size);
+ }
+ inode->i_mtime = inode->i_atime = CURRENT_TIME;
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(ip, dibh->b_data);
+ brelse(dibh);
+ mark_inode_dirty(inode);
+
unlock:
unlock_page(page);
page_cache_release(page);
@@ -739,9 +742,9 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
return -ENOMEM;
sort(qda, num_qd, sizeof(struct gfs2_quota_data *), sort_qd, NULL);
+ mutex_lock_nested(&ip->i_inode.i_mutex, I_MUTEX_QUOTA);
for (qx = 0; qx < num_qd; qx++) {
- error = gfs2_glock_nq_init(qda[qx]->qd_gl,
- LM_ST_EXCLUSIVE,
+ error = gfs2_glock_nq_init(qda[qx]->qd_gl, LM_ST_EXCLUSIVE,
GL_NOCACHE, &ghs[qx]);
if (error)
goto out;
@@ -795,9 +798,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
for (x = 0; x < num_qd; x++) {
qd = qda[x];
offset = qd2offset(qd);
- error = gfs2_adjust_quota(ip, offset, qd->qd_change_sync,
- (struct gfs2_quota_data *)
- qd);
+ error = gfs2_adjust_quota(ip, offset, qd->qd_change_sync, qd, NULL);
if (error)
goto out_end_trans;
@@ -817,21 +818,44 @@ out_gunlock:
out:
while (qx--)
gfs2_glock_dq_uninit(&ghs[qx]);
+ mutex_unlock(&ip->i_inode.i_mutex);
kfree(ghs);
gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl);
return error;
}
+static int update_qd(struct gfs2_sbd *sdp, struct gfs2_quota_data *qd)
+{
+ struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
+ struct gfs2_quota q;
+ struct gfs2_quota_lvb *qlvb;
+ loff_t pos;
+ int error;
+
+ memset(&q, 0, sizeof(struct gfs2_quota));
+ pos = qd2offset(qd);
+ error = gfs2_internal_read(ip, NULL, (char *)&q, &pos, sizeof(q));
+ if (error < 0)
+ return error;
+
+ qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
+ qlvb->qb_magic = cpu_to_be32(GFS2_MAGIC);
+ qlvb->__pad = 0;
+ qlvb->qb_limit = q.qu_limit;
+ qlvb->qb_warn = q.qu_warn;
+ qlvb->qb_value = q.qu_value;
+ qd->qd_qb = *qlvb;
+
+ return 0;
+}
+
static int do_glock(struct gfs2_quota_data *qd, int force_refresh,
struct gfs2_holder *q_gh)
{
struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
struct gfs2_holder i_gh;
- struct gfs2_quota_host q;
- char buf[sizeof(struct gfs2_quota)];
int error;
- struct gfs2_quota_lvb *qlvb;
restart:
error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_SHARED, 0, q_gh);
@@ -841,11 +865,9 @@ restart:
qd->qd_qb = *(struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
if (force_refresh || qd->qd_qb.qb_magic != cpu_to_be32(GFS2_MAGIC)) {
- loff_t pos;
gfs2_glock_dq_uninit(q_gh);
- error = gfs2_glock_nq_init(qd->qd_gl,
- LM_ST_EXCLUSIVE, GL_NOCACHE,
- q_gh);
+ error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_EXCLUSIVE,
+ GL_NOCACHE, q_gh);
if (error)
return error;
@@ -853,29 +875,14 @@ restart:
if (error)
goto fail;
- memset(buf, 0, sizeof(struct gfs2_quota));
- pos = qd2offset(qd);
- error = gfs2_internal_read(ip, NULL, buf, &pos,
- sizeof(struct gfs2_quota));
- if (error < 0)
+ error = update_qd(sdp, qd);
+ if (error)
goto fail_gunlock;
gfs2_glock_dq_uninit(&i_gh);
-
- gfs2_quota_in(&q, buf);
- qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
- qlvb->qb_magic = cpu_to_be32(GFS2_MAGIC);
- qlvb->__pad = 0;
- qlvb->qb_limit = cpu_to_be64(q.qu_limit);
- qlvb->qb_warn = cpu_to_be64(q.qu_warn);
- qlvb->qb_value = cpu_to_be64(q.qu_value);
- qd->qd_qb = *qlvb;
-
- if (gfs2_glock_is_blocking(qd->qd_gl)) {
- gfs2_glock_dq_uninit(q_gh);
- force_refresh = 0;
- goto restart;
- }
+ gfs2_glock_dq_uninit(q_gh);
+ force_refresh = 0;
+ goto restart;
}
return 0;
@@ -995,7 +1002,7 @@ static int print_message(struct gfs2_quota_data *qd, char *type)
{
struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
- printk(KERN_INFO "GFS2: fsid=%s: quota %s for %s %u\r\n",
+ printk(KERN_INFO "GFS2: fsid=%s: quota %s for %s %u\n",
sdp->sd_fsname, type,
(test_bit(QDF_USER, &qd->qd_flags)) ? "user" : "group",
qd->qd_id);
@@ -1032,6 +1039,10 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) {
print_message(qd, "exceeded");
+ quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
+ USRQUOTA : GRPQUOTA, qd->qd_id,
+ sdp->sd_vfs->s_dev, QUOTA_NL_BHARDWARN);
+
error = -EDQUOT;
break;
} else if (be64_to_cpu(qd->qd_qb.qb_warn) &&
@@ -1039,6 +1050,9 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
time_after_eq(jiffies, qd->qd_last_warn +
gfs2_tune_get(sdp,
gt_quota_warn_period) * HZ)) {
+ quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
+ USRQUOTA : GRPQUOTA, qd->qd_id,
+ sdp->sd_vfs->s_dev, QUOTA_NL_BSOFTWARN);
error = print_message(qd, "warning");
qd->qd_last_warn = jiffies;
}
@@ -1069,8 +1083,9 @@ void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
}
}
-int gfs2_quota_sync(struct gfs2_sbd *sdp)
+int gfs2_quota_sync(struct super_block *sb, int type)
{
+ struct gfs2_sbd *sdp = sb->s_fs_info;
struct gfs2_quota_data **qda;
unsigned int max_qd = gfs2_tune_get(sdp, gt_quota_simul_sync);
unsigned int num_qd;
@@ -1118,7 +1133,7 @@ int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id)
struct gfs2_holder q_gh;
int error;
- error = qd_get(sdp, user, id, CREATE, &qd);
+ error = qd_get(sdp, user, id, &qd);
if (error)
return error;
@@ -1127,7 +1142,6 @@ int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id)
gfs2_glock_dq_uninit(&q_gh);
qd_put(qd);
-
return error;
}
@@ -1298,12 +1312,12 @@ static void quotad_error(struct gfs2_sbd *sdp, const char *msg, int error)
}
static void quotad_check_timeo(struct gfs2_sbd *sdp, const char *msg,
- int (*fxn)(struct gfs2_sbd *sdp),
+ int (*fxn)(struct super_block *sb, int type),
unsigned long t, unsigned long *timeo,
unsigned int *new_timeo)
{
if (t >= *timeo) {
- int error = fxn(sdp);
+ int error = fxn(sdp->sd_vfs, 0);
quotad_error(sdp, msg, error);
*timeo = gfs2_tune_get_i(&sdp->sd_tune, new_timeo) * HZ;
} else {
@@ -1330,6 +1344,14 @@ static void quotad_check_trunc_list(struct gfs2_sbd *sdp)
}
}
+void gfs2_wake_up_statfs(struct gfs2_sbd *sdp) {
+ if (!sdp->sd_statfs_force_sync) {
+ sdp->sd_statfs_force_sync = 1;
+ wake_up(&sdp->sd_quota_wait);
+ }
+}
+
+
/**
* gfs2_quotad - Write cached quota changes into the quota file
* @sdp: Pointer to GFS2 superblock
@@ -1349,8 +1371,15 @@ int gfs2_quotad(void *data)
while (!kthread_should_stop()) {
/* Update the master statfs file */
- quotad_check_timeo(sdp, "statfs", gfs2_statfs_sync, t,
- &statfs_timeo, &tune->gt_statfs_quantum);
+ if (sdp->sd_statfs_force_sync) {
+ int error = gfs2_statfs_sync(sdp->sd_vfs, 0);
+ quotad_error(sdp, "statfs", error);
+ statfs_timeo = gfs2_tune_get(sdp, gt_statfs_quantum) * HZ;
+ }
+ else
+ quotad_check_timeo(sdp, "statfs", gfs2_statfs_sync, t,
+ &statfs_timeo,
+ &tune->gt_statfs_quantum);
/* Update quota file */
quotad_check_timeo(sdp, "sync", gfs2_quota_sync, t,
@@ -1367,7 +1396,7 @@ int gfs2_quotad(void *data)
spin_lock(&sdp->sd_trunc_lock);
empty = list_empty(&sdp->sd_trunc_list);
spin_unlock(&sdp->sd_trunc_lock);
- if (empty)
+ if (empty && !sdp->sd_statfs_force_sync)
t -= schedule_timeout(t);
else
t = 0;
@@ -1377,3 +1406,181 @@ int gfs2_quotad(void *data)
return 0;
}
+static int gfs2_quota_get_xstate(struct super_block *sb,
+ struct fs_quota_stat *fqs)
+{
+ struct gfs2_sbd *sdp = sb->s_fs_info;
+
+ memset(fqs, 0, sizeof(struct fs_quota_stat));
+ fqs->qs_version = FS_QSTAT_VERSION;
+ if (sdp->sd_args.ar_quota == GFS2_QUOTA_ON)
+ fqs->qs_flags = (XFS_QUOTA_UDQ_ENFD | XFS_QUOTA_GDQ_ENFD);
+ else if (sdp->sd_args.ar_quota == GFS2_QUOTA_ACCOUNT)
+ fqs->qs_flags = (XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_GDQ_ACCT);
+ if (sdp->sd_quota_inode) {
+ fqs->qs_uquota.qfs_ino = GFS2_I(sdp->sd_quota_inode)->i_no_addr;
+ fqs->qs_uquota.qfs_nblks = sdp->sd_quota_inode->i_blocks;
+ }
+ fqs->qs_uquota.qfs_nextents = 1; /* unsupported */
+ fqs->qs_gquota = fqs->qs_uquota; /* its the same inode in both cases */
+ fqs->qs_incoredqs = atomic_read(&qd_lru_count);
+ return 0;
+}
+
+static int gfs2_xquota_get(struct super_block *sb, int type, qid_t id,
+ struct fs_disk_quota *fdq)
+{
+ struct gfs2_sbd *sdp = sb->s_fs_info;
+ struct gfs2_quota_lvb *qlvb;
+ struct gfs2_quota_data *qd;
+ struct gfs2_holder q_gh;
+ int error;
+
+ memset(fdq, 0, sizeof(struct fs_disk_quota));
+
+ if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
+ return -ESRCH; /* Crazy XFS error code */
+
+ if (type == USRQUOTA)
+ type = QUOTA_USER;
+ else if (type == GRPQUOTA)
+ type = QUOTA_GROUP;
+ else
+ return -EINVAL;
+
+ error = qd_get(sdp, type, id, &qd);
+ if (error)
+ return error;
+ error = do_glock(qd, FORCE, &q_gh);
+ if (error)
+ goto out;
+
+ qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
+ fdq->d_version = FS_DQUOT_VERSION;
+ fdq->d_flags = (type == QUOTA_USER) ? XFS_USER_QUOTA : XFS_GROUP_QUOTA;
+ fdq->d_id = id;
+ fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit);
+ fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn);
+ fdq->d_bcount = be64_to_cpu(qlvb->qb_value);
+
+ gfs2_glock_dq_uninit(&q_gh);
+out:
+ qd_put(qd);
+ return error;
+}
+
+/* GFS2 only supports a subset of the XFS fields */
+#define GFS2_FIELDMASK (FS_DQ_BSOFT|FS_DQ_BHARD)
+
+static int gfs2_xquota_set(struct super_block *sb, int type, qid_t id,
+ struct fs_disk_quota *fdq)
+{
+ struct gfs2_sbd *sdp = sb->s_fs_info;
+ struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
+ struct gfs2_quota_data *qd;
+ struct gfs2_holder q_gh, i_gh;
+ unsigned int data_blocks, ind_blocks;
+ unsigned int blocks = 0;
+ int alloc_required;
+ struct gfs2_alloc *al;
+ loff_t offset;
+ int error;
+
+ if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
+ return -ESRCH; /* Crazy XFS error code */
+
+ switch(type) {
+ case USRQUOTA:
+ type = QUOTA_USER;
+ if (fdq->d_flags != XFS_USER_QUOTA)
+ return -EINVAL;
+ break;
+ case GRPQUOTA:
+ type = QUOTA_GROUP;
+ if (fdq->d_flags != XFS_GROUP_QUOTA)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (fdq->d_fieldmask & ~GFS2_FIELDMASK)
+ return -EINVAL;
+ if (fdq->d_id != id)
+ return -EINVAL;
+
+ error = qd_get(sdp, type, id, &qd);
+ if (error)
+ return error;
+
+ mutex_lock(&ip->i_inode.i_mutex);
+ error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_EXCLUSIVE, 0, &q_gh);
+ if (error)
+ goto out_put;
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
+ if (error)
+ goto out_q;
+
+ /* Check for existing entry, if none then alloc new blocks */
+ error = update_qd(sdp, qd);
+ if (error)
+ goto out_i;
+
+ /* If nothing has changed, this is a no-op */
+ if ((fdq->d_fieldmask & FS_DQ_BSOFT) &&
+ (fdq->d_blk_softlimit == be64_to_cpu(qd->qd_qb.qb_warn)))
+ fdq->d_fieldmask ^= FS_DQ_BSOFT;
+ if ((fdq->d_fieldmask & FS_DQ_BHARD) &&
+ (fdq->d_blk_hardlimit == be64_to_cpu(qd->qd_qb.qb_limit)))
+ fdq->d_fieldmask ^= FS_DQ_BHARD;
+ if (fdq->d_fieldmask == 0)
+ goto out_i;
+
+ offset = qd2offset(qd);
+ error = gfs2_write_alloc_required(ip, offset, sizeof(struct gfs2_quota),
+ &alloc_required);
+ if (error)
+ goto out_i;
+ if (alloc_required) {
+ al = gfs2_alloc_get(ip);
+ if (al == NULL)
+ goto out_i;
+ gfs2_write_calc_reserv(ip, sizeof(struct gfs2_quota),
+ &data_blocks, &ind_blocks);
+ blocks = al->al_requested = 1 + data_blocks + ind_blocks;
+ error = gfs2_inplace_reserve(ip);
+ if (error)
+ goto out_alloc;
+ }
+
+ error = gfs2_trans_begin(sdp, blocks + RES_DINODE + 1, 0);
+ if (error)
+ goto out_release;
+
+ /* Apply changes */
+ error = gfs2_adjust_quota(ip, offset, 0, qd, fdq);
+
+ gfs2_trans_end(sdp);
+out_release:
+ if (alloc_required) {
+ gfs2_inplace_release(ip);
+out_alloc:
+ gfs2_alloc_put(ip);
+ }
+out_i:
+ gfs2_glock_dq_uninit(&i_gh);
+out_q:
+ gfs2_glock_dq_uninit(&q_gh);
+out_put:
+ mutex_unlock(&ip->i_inode.i_mutex);
+ qd_put(qd);
+ return error;
+}
+
+const struct quotactl_ops gfs2_quotactl_ops = {
+ .quota_sync = gfs2_quota_sync,
+ .get_xstate = gfs2_quota_get_xstate,
+ .get_xquota = gfs2_xquota_get,
+ .set_xquota = gfs2_xquota_set,
+};
+
diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h
index 0fa5fa63d0e8..e271fa07ad02 100644
--- a/fs/gfs2/quota.h
+++ b/fs/gfs2/quota.h
@@ -25,13 +25,15 @@ extern int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid);
extern void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
u32 uid, u32 gid);
-extern int gfs2_quota_sync(struct gfs2_sbd *sdp);
+extern int gfs2_quota_sync(struct super_block *sb, int type);
extern int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id);
extern int gfs2_quota_init(struct gfs2_sbd *sdp);
extern void gfs2_quota_cleanup(struct gfs2_sbd *sdp);
extern int gfs2_quotad(void *data);
+extern void gfs2_wake_up_statfs(struct gfs2_sbd *sdp);
+
static inline int gfs2_quota_lock_check(struct gfs2_inode *ip)
{
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
@@ -50,5 +52,6 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip)
}
extern int gfs2_shrink_qd_memory(int nr, gfp_t gfp_mask);
+extern const struct quotactl_ops gfs2_quotactl_ops;
#endif /* __QUOTA_DOT_H__ */
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index 8f1cfb02a6cb..15332af34d99 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -15,6 +15,7 @@
#include <linux/gfs2_ondisk.h>
#include <linux/prefetch.h>
#include <linux/blkdev.h>
+#include <trace/events/gfs2.h>
#include "gfs2.h"
#include "incore.h"
@@ -29,7 +30,6 @@
#include "util.h"
#include "log.h"
#include "inode.h"
-#include "trace_gfs2.h"
#define BFITNOENT ((u32)~0)
#define NO_BLOCK ((u64)~0)
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 0ec3ec672de1..b1dcfab36465 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -70,6 +70,9 @@ enum {
Opt_commit,
Opt_err_withdraw,
Opt_err_panic,
+ Opt_statfs_quantum,
+ Opt_statfs_percent,
+ Opt_quota_quantum,
Opt_error,
};
@@ -101,18 +104,21 @@ static const match_table_t tokens = {
{Opt_commit, "commit=%d"},
{Opt_err_withdraw, "errors=withdraw"},
{Opt_err_panic, "errors=panic"},
+ {Opt_statfs_quantum, "statfs_quantum=%d"},
+ {Opt_statfs_percent, "statfs_percent=%d"},
+ {Opt_quota_quantum, "quota_quantum=%d"},
{Opt_error, NULL}
};
/**
* gfs2_mount_args - Parse mount options
- * @sdp:
- * @data:
+ * @args: The structure into which the parsed options will be written
+ * @options: The options to parse
*
* Return: errno
*/
-int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
+int gfs2_mount_args(struct gfs2_args *args, char *options)
{
char *o;
int token;
@@ -157,7 +163,7 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
break;
case Opt_debug:
if (args->ar_errors == GFS2_ERRORS_PANIC) {
- fs_info(sdp, "-o debug and -o errors=panic "
+ printk(KERN_WARNING "GFS2: -o debug and -o errors=panic "
"are mutually exclusive.\n");
return -EINVAL;
}
@@ -210,7 +216,29 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
case Opt_commit:
rv = match_int(&tmp[0], &args->ar_commit);
if (rv || args->ar_commit <= 0) {
- fs_info(sdp, "commit mount option requires a positive numeric argument\n");
+ printk(KERN_WARNING "GFS2: commit mount option requires a positive numeric argument\n");
+ return rv ? rv : -EINVAL;
+ }
+ break;
+ case Opt_statfs_quantum:
+ rv = match_int(&tmp[0], &args->ar_statfs_quantum);
+ if (rv || args->ar_statfs_quantum < 0) {
+ printk(KERN_WARNING "GFS2: statfs_quantum mount option requires a non-negative numeric argument\n");
+ return rv ? rv : -EINVAL;
+ }
+ break;
+ case Opt_quota_quantum:
+ rv = match_int(&tmp[0], &args->ar_quota_quantum);
+ if (rv || args->ar_quota_quantum <= 0) {
+ printk(KERN_WARNING "GFS2: quota_quantum mount option requires a positive numeric argument\n");
+ return rv ? rv : -EINVAL;
+ }
+ break;
+ case Opt_statfs_percent:
+ rv = match_int(&tmp[0], &args->ar_statfs_percent);
+ if (rv || args->ar_statfs_percent < 0 ||
+ args->ar_statfs_percent > 100) {
+ printk(KERN_WARNING "statfs_percent mount option requires a numeric argument between 0 and 100\n");
return rv ? rv : -EINVAL;
}
break;
@@ -219,7 +247,7 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
break;
case Opt_err_panic:
if (args->ar_debug) {
- fs_info(sdp, "-o debug and -o errors=panic "
+ printk(KERN_WARNING "GFS2: -o debug and -o errors=panic "
"are mutually exclusive.\n");
return -EINVAL;
}
@@ -227,7 +255,7 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
break;
case Opt_error:
default:
- fs_info(sdp, "invalid mount option: %s\n", o);
+ printk(KERN_WARNING "GFS2: invalid mount option: %s\n", o);
return -EINVAL;
}
}
@@ -442,7 +470,10 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,
{
struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode);
struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local;
+ struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master;
struct buffer_head *l_bh;
+ s64 x, y;
+ int need_sync = 0;
int error;
error = gfs2_meta_inode_buffer(l_ip, &l_bh);
@@ -456,9 +487,17 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,
l_sc->sc_free += free;
l_sc->sc_dinodes += dinodes;
gfs2_statfs_change_out(l_sc, l_bh->b_data + sizeof(struct gfs2_dinode));
+ if (sdp->sd_args.ar_statfs_percent) {
+ x = 100 * l_sc->sc_free;
+ y = m_sc->sc_free * sdp->sd_args.ar_statfs_percent;
+ if (x >= y || x <= -y)
+ need_sync = 1;
+ }
spin_unlock(&sdp->sd_statfs_spin);
brelse(l_bh);
+ if (need_sync)
+ gfs2_wake_up_statfs(sdp);
}
void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh,
@@ -484,8 +523,9 @@ void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh,
gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode));
}
-int gfs2_statfs_sync(struct gfs2_sbd *sdp)
+int gfs2_statfs_sync(struct super_block *sb, int type)
{
+ struct gfs2_sbd *sdp = sb->s_fs_info;
struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode);
struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master;
@@ -521,6 +561,7 @@ int gfs2_statfs_sync(struct gfs2_sbd *sdp)
goto out_bh2;
update_statfs(sdp, m_bh, l_bh);
+ sdp->sd_statfs_force_sync = 0;
gfs2_trans_end(sdp);
@@ -712,8 +753,8 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
int error;
flush_workqueue(gfs2_delete_workqueue);
- gfs2_quota_sync(sdp);
- gfs2_statfs_sync(sdp);
+ gfs2_quota_sync(sdp->sd_vfs, 0);
+ gfs2_statfs_sync(sdp->sd_vfs, 0);
error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, GL_NOCACHE,
&t_gh);
@@ -1061,8 +1102,13 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
spin_lock(&gt->gt_spin);
args.ar_commit = gt->gt_log_flush_secs;
+ args.ar_quota_quantum = gt->gt_quota_quantum;
+ if (gt->gt_statfs_slow)
+ args.ar_statfs_quantum = 0;
+ else
+ args.ar_statfs_quantum = gt->gt_statfs_quantum;
spin_unlock(&gt->gt_spin);
- error = gfs2_mount_args(sdp, &args, data);
+ error = gfs2_mount_args(&args, data);
if (error)
return error;
@@ -1099,6 +1145,15 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
sb->s_flags &= ~MS_POSIXACL;
spin_lock(&gt->gt_spin);
gt->gt_log_flush_secs = args.ar_commit;
+ gt->gt_quota_quantum = args.ar_quota_quantum;
+ if (args.ar_statfs_quantum) {
+ gt->gt_statfs_slow = 0;
+ gt->gt_statfs_quantum = args.ar_statfs_quantum;
+ }
+ else {
+ gt->gt_statfs_slow = 1;
+ gt->gt_statfs_quantum = 30;
+ }
spin_unlock(&gt->gt_spin);
gfs2_online_uevent(sdp);
@@ -1179,7 +1234,7 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
{
struct gfs2_sbd *sdp = mnt->mnt_sb->s_fs_info;
struct gfs2_args *args = &sdp->sd_args;
- int lfsecs;
+ int val;
if (is_ancestor(mnt->mnt_root, sdp->sd_master_dir))
seq_printf(s, ",meta");
@@ -1240,9 +1295,17 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
}
if (args->ar_discard)
seq_printf(s, ",discard");
- lfsecs = sdp->sd_tune.gt_log_flush_secs;
- if (lfsecs != 60)
- seq_printf(s, ",commit=%d", lfsecs);
+ val = sdp->sd_tune.gt_log_flush_secs;
+ if (val != 60)
+ seq_printf(s, ",commit=%d", val);
+ val = sdp->sd_tune.gt_statfs_quantum;
+ if (val != 30)
+ seq_printf(s, ",statfs_quantum=%d", val);
+ val = sdp->sd_tune.gt_quota_quantum;
+ if (val != 60)
+ seq_printf(s, ",quota_quantum=%d", val);
+ if (args->ar_statfs_percent)
+ seq_printf(s, ",statfs_percent=%d", args->ar_statfs_percent);
if (args->ar_errors != GFS2_ERRORS_DEFAULT) {
const char *state;
diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h
index 235db3682885..3df60f2d84e3 100644
--- a/fs/gfs2/super.h
+++ b/fs/gfs2/super.h
@@ -27,7 +27,7 @@ static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp)
extern void gfs2_jindex_free(struct gfs2_sbd *sdp);
-extern int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *data);
+extern int gfs2_mount_args(struct gfs2_args *args, char *data);
extern struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid);
extern int gfs2_jdesc_check(struct gfs2_jdesc *jd);
@@ -44,7 +44,7 @@ extern void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc,
const void *buf);
extern void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh,
struct buffer_head *l_bh);
-extern int gfs2_statfs_sync(struct gfs2_sbd *sdp);
+extern int gfs2_statfs_sync(struct super_block *sb, int type);
extern int gfs2_freeze_fs(struct gfs2_sbd *sdp);
extern void gfs2_unfreeze_fs(struct gfs2_sbd *sdp);
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
index 446329728d52..c5dad1eb7b91 100644
--- a/fs/gfs2/sys.c
+++ b/fs/gfs2/sys.c
@@ -158,7 +158,7 @@ static ssize_t statfs_sync_store(struct gfs2_sbd *sdp, const char *buf,
if (simple_strtol(buf, NULL, 0) != 1)
return -EINVAL;
- gfs2_statfs_sync(sdp);
+ gfs2_statfs_sync(sdp->sd_vfs, 0);
return len;
}
@@ -171,13 +171,14 @@ static ssize_t quota_sync_store(struct gfs2_sbd *sdp, const char *buf,
if (simple_strtol(buf, NULL, 0) != 1)
return -EINVAL;
- gfs2_quota_sync(sdp);
+ gfs2_quota_sync(sdp->sd_vfs, 0);
return len;
}
static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf,
size_t len)
{
+ int error;
u32 id;
if (!capable(CAP_SYS_ADMIN))
@@ -185,13 +186,14 @@ static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf,
id = simple_strtoul(buf, NULL, 0);
- gfs2_quota_refresh(sdp, 1, id);
- return len;
+ error = gfs2_quota_refresh(sdp, 1, id);
+ return error ? error : len;
}
static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf,
size_t len)
{
+ int error;
u32 id;
if (!capable(CAP_SYS_ADMIN))
@@ -199,8 +201,8 @@ static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf,
id = simple_strtoul(buf, NULL, 0);
- gfs2_quota_refresh(sdp, 0, id);
- return len;
+ error = gfs2_quota_refresh(sdp, 0, id);
+ return error ? error : len;
}
static ssize_t demote_rq_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c
index 8a0f8ef6ee27..912f5cbc4740 100644
--- a/fs/gfs2/xattr.c
+++ b/fs/gfs2/xattr.c
@@ -186,8 +186,8 @@ static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh,
return 0;
}
-int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name,
- struct gfs2_ea_location *el)
+static int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name,
+ struct gfs2_ea_location *el)
{
struct ea_find ef;
int error;
@@ -516,8 +516,8 @@ out:
return error;
}
-int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el,
- char *data, size_t size)
+static int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el,
+ char *data, size_t size)
{
int ret;
size_t len = GFS2_EA_DATA_LEN(el->el_ea);
@@ -534,6 +534,36 @@ int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el,
return len;
}
+int gfs2_xattr_acl_get(struct gfs2_inode *ip, const char *name, char **ppdata)
+{
+ struct gfs2_ea_location el;
+ int error;
+ int len;
+ char *data;
+
+ error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, name, &el);
+ if (error)
+ return error;
+ if (!el.el_ea)
+ goto out;
+ if (!GFS2_EA_DATA_LEN(el.el_ea))
+ goto out;
+
+ len = GFS2_EA_DATA_LEN(el.el_ea);
+ data = kmalloc(len, GFP_NOFS);
+ error = -ENOMEM;
+ if (data == NULL)
+ goto out;
+
+ error = gfs2_ea_get_copy(ip, &el, data, len);
+ if (error == 0)
+ error = len;
+ *ppdata = data;
+out:
+ brelse(el.el_bh);
+ return error;
+}
+
/**
* gfs2_xattr_get - Get a GFS2 extended attribute
* @inode: The inode
@@ -1259,22 +1289,26 @@ fail:
return error;
}
-int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el,
- struct iattr *attr, char *data)
+int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
{
+ struct gfs2_ea_location el;
struct buffer_head *dibh;
int error;
- if (GFS2_EA_IS_STUFFED(el->el_ea)) {
+ error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, GFS2_POSIX_ACL_ACCESS, &el);
+ if (error)
+ return error;
+
+ if (GFS2_EA_IS_STUFFED(el.el_ea)) {
error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + RES_EATTR, 0);
if (error)
return error;
- gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1);
- memcpy(GFS2_EA2DATA(el->el_ea), data,
- GFS2_EA_DATA_LEN(el->el_ea));
+ gfs2_trans_add_bh(ip->i_gl, el.el_bh, 1);
+ memcpy(GFS2_EA2DATA(el.el_ea), data,
+ GFS2_EA_DATA_LEN(el.el_ea));
} else
- error = ea_acl_chmod_unstuffed(ip, el->el_ea, data);
+ error = ea_acl_chmod_unstuffed(ip, el.el_ea, data);
if (error)
return error;
@@ -1507,18 +1541,6 @@ static int gfs2_xattr_user_set(struct inode *inode, const char *name,
return gfs2_xattr_set(inode, GFS2_EATYPE_USR, name, value, size, flags);
}
-static int gfs2_xattr_system_get(struct inode *inode, const char *name,
- void *buffer, size_t size)
-{
- return gfs2_xattr_get(inode, GFS2_EATYPE_SYS, name, buffer, size);
-}
-
-static int gfs2_xattr_system_set(struct inode *inode, const char *name,
- const void *value, size_t size, int flags)
-{
- return gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, value, size, flags);
-}
-
static int gfs2_xattr_security_get(struct inode *inode, const char *name,
void *buffer, size_t size)
{
@@ -1543,12 +1565,6 @@ static struct xattr_handler gfs2_xattr_security_handler = {
.set = gfs2_xattr_security_set,
};
-static struct xattr_handler gfs2_xattr_system_handler = {
- .prefix = XATTR_SYSTEM_PREFIX,
- .get = gfs2_xattr_system_get,
- .set = gfs2_xattr_system_set,
-};
-
struct xattr_handler *gfs2_xattr_handlers[] = {
&gfs2_xattr_user_handler,
&gfs2_xattr_security_handler,
diff --git a/fs/gfs2/xattr.h b/fs/gfs2/xattr.h
index cbdfd7743733..8d6ae5813c4d 100644
--- a/fs/gfs2/xattr.h
+++ b/fs/gfs2/xattr.h
@@ -62,11 +62,7 @@ extern int gfs2_ea_dealloc(struct gfs2_inode *ip);
/* Exported to acl.c */
-extern int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name,
- struct gfs2_ea_location *el);
-extern int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el,
- char *data, size_t size);
-extern int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el,
- struct iattr *attr, char *data);
+extern int gfs2_xattr_acl_get(struct gfs2_inode *ip, const char *name, char **data);
+extern int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data);
#endif /* __EATTR_DOT_H__ */
diff --git a/fs/inode.c b/fs/inode.c
index 4d8e3be55976..06c1f02de611 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -18,7 +18,6 @@
#include <linux/hash.h>
#include <linux/swap.h>
#include <linux/security.h>
-#include <linux/ima.h>
#include <linux/pagemap.h>
#include <linux/cdev.h>
#include <linux/bootmem.h>
@@ -157,11 +156,6 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
if (security_inode_alloc(inode))
goto out;
-
- /* allocate and initialize an i_integrity */
- if (ima_inode_alloc(inode))
- goto out_free_security;
-
spin_lock_init(&inode->i_lock);
lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key);
@@ -201,9 +195,6 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
#endif
return 0;
-
-out_free_security:
- security_inode_free(inode);
out:
return -ENOMEM;
}
@@ -235,7 +226,6 @@ static struct inode *alloc_inode(struct super_block *sb)
void __destroy_inode(struct inode *inode)
{
BUG_ON(inode_has_buffers(inode));
- ima_inode_free(inode);
security_inode_free(inode);
fsnotify_inode_delete(inode);
#ifdef CONFIG_FS_POSIX_ACL
diff --git a/fs/isofs/compress.c b/fs/isofs/compress.c
index defb932eee9a..0b3fa7974fa8 100644
--- a/fs/isofs/compress.c
+++ b/fs/isofs/compress.c
@@ -36,286 +36,323 @@ static void *zisofs_zlib_workspace;
static DEFINE_MUTEX(zisofs_zlib_lock);
/*
- * When decompressing, we typically obtain more than one page
- * per reference. We inject the additional pages into the page
- * cache as a form of readahead.
+ * Read data of @inode from @block_start to @block_end and uncompress
+ * to one zisofs block. Store the data in the @pages array with @pcount
+ * entries. Start storing at offset @poffset of the first page.
*/
-static int zisofs_readpage(struct file *file, struct page *page)
+static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
+ loff_t block_end, int pcount,
+ struct page **pages, unsigned poffset,
+ int *errp)
{
- struct inode *inode = file->f_path.dentry->d_inode;
- struct address_space *mapping = inode->i_mapping;
- unsigned int maxpage, xpage, fpage, blockindex;
- unsigned long offset;
- unsigned long blockptr, blockendptr, cstart, cend, csize;
- struct buffer_head *bh, *ptrbh[2];
- unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
- unsigned int bufshift = ISOFS_BUFFER_BITS(inode);
- unsigned long bufmask = bufsize - 1;
- int err = -EIO;
- int i;
- unsigned int header_size = ISOFS_I(inode)->i_format_parm[0];
unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
- /* unsigned long zisofs_block_size = 1UL << zisofs_block_shift; */
- unsigned int zisofs_block_page_shift = zisofs_block_shift-PAGE_CACHE_SHIFT;
- unsigned long zisofs_block_pages = 1UL << zisofs_block_page_shift;
- unsigned long zisofs_block_page_mask = zisofs_block_pages-1;
- struct page *pages[zisofs_block_pages];
- unsigned long index = page->index;
- int indexblocks;
-
- /* We have already been given one page, this is the one
- we must do. */
- xpage = index & zisofs_block_page_mask;
- pages[xpage] = page;
-
- /* The remaining pages need to be allocated and inserted */
- offset = index & ~zisofs_block_page_mask;
- blockindex = offset >> zisofs_block_page_shift;
- maxpage = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-
- /*
- * If this page is wholly outside i_size we just return zero;
- * do_generic_file_read() will handle this for us
- */
- if (page->index >= maxpage) {
- SetPageUptodate(page);
- unlock_page(page);
+ unsigned int bufsize = ISOFS_BUFFER_SIZE(inode);
+ unsigned int bufshift = ISOFS_BUFFER_BITS(inode);
+ unsigned int bufmask = bufsize - 1;
+ int i, block_size = block_end - block_start;
+ z_stream stream = { .total_out = 0,
+ .avail_in = 0,
+ .avail_out = 0, };
+ int zerr;
+ int needblocks = (block_size + (block_start & bufmask) + bufmask)
+ >> bufshift;
+ int haveblocks;
+ blkcnt_t blocknum;
+ struct buffer_head *bhs[needblocks + 1];
+ int curbh, curpage;
+
+ if (block_size > deflateBound(1UL << zisofs_block_shift)) {
+ *errp = -EIO;
return 0;
}
-
- maxpage = min(zisofs_block_pages, maxpage-offset);
-
- for ( i = 0 ; i < maxpage ; i++, offset++ ) {
- if ( i != xpage ) {
- pages[i] = grab_cache_page_nowait(mapping, offset);
- }
- page = pages[i];
- if ( page ) {
- ClearPageError(page);
- kmap(page);
+ /* Empty block? */
+ if (block_size == 0) {
+ for ( i = 0 ; i < pcount ; i++ ) {
+ if (!pages[i])
+ continue;
+ memset(page_address(pages[i]), 0, PAGE_CACHE_SIZE);
+ flush_dcache_page(pages[i]);
+ SetPageUptodate(pages[i]);
}
+ return ((loff_t)pcount) << PAGE_CACHE_SHIFT;
}
- /* This is the last page filled, plus one; used in case of abort. */
- fpage = 0;
+ /* Because zlib is not thread-safe, do all the I/O at the top. */
+ blocknum = block_start >> bufshift;
+ memset(bhs, 0, (needblocks + 1) * sizeof(struct buffer_head *));
+ haveblocks = isofs_get_blocks(inode, blocknum, bhs, needblocks);
+ ll_rw_block(READ, haveblocks, bhs);
- /* Find the pointer to this specific chunk */
- /* Note: we're not using isonum_731() here because the data is known aligned */
- /* Note: header_size is in 32-bit words (4 bytes) */
- blockptr = (header_size + blockindex) << 2;
- blockendptr = blockptr + 4;
+ curbh = 0;
+ curpage = 0;
+ /*
+ * First block is special since it may be fractional. We also wait for
+ * it before grabbing the zlib mutex; odds are that the subsequent
+ * blocks are going to come in in short order so we don't hold the zlib
+ * mutex longer than necessary.
+ */
- indexblocks = ((blockptr^blockendptr) >> bufshift) ? 2 : 1;
- ptrbh[0] = ptrbh[1] = NULL;
+ if (!bhs[0])
+ goto b_eio;
- if ( isofs_get_blocks(inode, blockptr >> bufshift, ptrbh, indexblocks) != indexblocks ) {
- if ( ptrbh[0] ) brelse(ptrbh[0]);
- printk(KERN_DEBUG "zisofs: Null buffer on reading block table, inode = %lu, block = %lu\n",
- inode->i_ino, blockptr >> bufshift);
- goto eio;
- }
- ll_rw_block(READ, indexblocks, ptrbh);
-
- bh = ptrbh[0];
- if ( !bh || (wait_on_buffer(bh), !buffer_uptodate(bh)) ) {
- printk(KERN_DEBUG "zisofs: Failed to read block table, inode = %lu, block = %lu\n",
- inode->i_ino, blockptr >> bufshift);
- if ( ptrbh[1] )
- brelse(ptrbh[1]);
- goto eio;
- }
- cstart = le32_to_cpu(*(__le32 *)(bh->b_data + (blockptr & bufmask)));
-
- if ( indexblocks == 2 ) {
- /* We just crossed a block boundary. Switch to the next block */
- brelse(bh);
- bh = ptrbh[1];
- if ( !bh || (wait_on_buffer(bh), !buffer_uptodate(bh)) ) {
- printk(KERN_DEBUG "zisofs: Failed to read block table, inode = %lu, block = %lu\n",
- inode->i_ino, blockendptr >> bufshift);
- goto eio;
- }
+ wait_on_buffer(bhs[0]);
+ if (!buffer_uptodate(bhs[0])) {
+ *errp = -EIO;
+ goto b_eio;
}
- cend = le32_to_cpu(*(__le32 *)(bh->b_data + (blockendptr & bufmask)));
- brelse(bh);
- if (cstart > cend)
- goto eio;
+ stream.workspace = zisofs_zlib_workspace;
+ mutex_lock(&zisofs_zlib_lock);
- csize = cend-cstart;
-
- if (csize > deflateBound(1UL << zisofs_block_shift))
- goto eio;
-
- /* Now page[] contains an array of pages, any of which can be NULL,
- and the locks on which we hold. We should now read the data and
- release the pages. If the pages are NULL the decompressed data
- for that particular page should be discarded. */
-
- if ( csize == 0 ) {
- /* This data block is empty. */
-
- for ( fpage = 0 ; fpage < maxpage ; fpage++ ) {
- if ( (page = pages[fpage]) != NULL ) {
- memset(page_address(page), 0, PAGE_CACHE_SIZE);
-
- flush_dcache_page(page);
- SetPageUptodate(page);
- kunmap(page);
- unlock_page(page);
- if ( fpage == xpage )
- err = 0; /* The critical page */
- else
- page_cache_release(page);
+ zerr = zlib_inflateInit(&stream);
+ if (zerr != Z_OK) {
+ if (zerr == Z_MEM_ERROR)
+ *errp = -ENOMEM;
+ else
+ *errp = -EIO;
+ printk(KERN_DEBUG "zisofs: zisofs_inflateInit returned %d\n",
+ zerr);
+ goto z_eio;
+ }
+
+ while (curpage < pcount && curbh < haveblocks &&
+ zerr != Z_STREAM_END) {
+ if (!stream.avail_out) {
+ if (pages[curpage]) {
+ stream.next_out = page_address(pages[curpage])
+ + poffset;
+ stream.avail_out = PAGE_CACHE_SIZE - poffset;
+ poffset = 0;
+ } else {
+ stream.next_out = (void *)&zisofs_sink_page;
+ stream.avail_out = PAGE_CACHE_SIZE;
}
}
- } else {
- /* This data block is compressed. */
- z_stream stream;
- int bail = 0, left_out = -1;
- int zerr;
- int needblocks = (csize + (cstart & bufmask) + bufmask) >> bufshift;
- int haveblocks;
- struct buffer_head *bhs[needblocks+1];
- struct buffer_head **bhptr;
-
- /* Because zlib is not thread-safe, do all the I/O at the top. */
-
- blockptr = cstart >> bufshift;
- memset(bhs, 0, (needblocks+1)*sizeof(struct buffer_head *));
- haveblocks = isofs_get_blocks(inode, blockptr, bhs, needblocks);
- ll_rw_block(READ, haveblocks, bhs);
-
- bhptr = &bhs[0];
- bh = *bhptr++;
-
- /* First block is special since it may be fractional.
- We also wait for it before grabbing the zlib
- mutex; odds are that the subsequent blocks are
- going to come in in short order so we don't hold
- the zlib mutex longer than necessary. */
-
- if ( !bh || (wait_on_buffer(bh), !buffer_uptodate(bh)) ) {
- printk(KERN_DEBUG "zisofs: Hit null buffer, fpage = %d, xpage = %d, csize = %ld\n",
- fpage, xpage, csize);
- goto b_eio;
- }
- stream.next_in = bh->b_data + (cstart & bufmask);
- stream.avail_in = min(bufsize-(cstart & bufmask), csize);
- csize -= stream.avail_in;
-
- stream.workspace = zisofs_zlib_workspace;
- mutex_lock(&zisofs_zlib_lock);
-
- zerr = zlib_inflateInit(&stream);
- if ( zerr != Z_OK ) {
- if ( err && zerr == Z_MEM_ERROR )
- err = -ENOMEM;
- printk(KERN_DEBUG "zisofs: zisofs_inflateInit returned %d\n",
- zerr);
- goto z_eio;
+ if (!stream.avail_in) {
+ wait_on_buffer(bhs[curbh]);
+ if (!buffer_uptodate(bhs[curbh])) {
+ *errp = -EIO;
+ break;
+ }
+ stream.next_in = bhs[curbh]->b_data +
+ (block_start & bufmask);
+ stream.avail_in = min_t(unsigned, bufsize -
+ (block_start & bufmask),
+ block_size);
+ block_size -= stream.avail_in;
+ block_start = 0;
}
- while ( !bail && fpage < maxpage ) {
- page = pages[fpage];
- if ( page )
- stream.next_out = page_address(page);
- else
- stream.next_out = (void *)&zisofs_sink_page;
- stream.avail_out = PAGE_CACHE_SIZE;
-
- while ( stream.avail_out ) {
- int ao, ai;
- if ( stream.avail_in == 0 && left_out ) {
- if ( !csize ) {
- printk(KERN_WARNING "zisofs: ZF read beyond end of input\n");
- bail = 1;
- break;
- } else {
- bh = *bhptr++;
- if ( !bh ||
- (wait_on_buffer(bh), !buffer_uptodate(bh)) ) {
- /* Reached an EIO */
- printk(KERN_DEBUG "zisofs: Hit null buffer, fpage = %d, xpage = %d, csize = %ld\n",
- fpage, xpage, csize);
-
- bail = 1;
- break;
- }
- stream.next_in = bh->b_data;
- stream.avail_in = min(csize,bufsize);
- csize -= stream.avail_in;
- }
- }
- ao = stream.avail_out; ai = stream.avail_in;
- zerr = zlib_inflate(&stream, Z_SYNC_FLUSH);
- left_out = stream.avail_out;
- if ( zerr == Z_BUF_ERROR && stream.avail_in == 0 )
- continue;
- if ( zerr != Z_OK ) {
- /* EOF, error, or trying to read beyond end of input */
- if ( err && zerr == Z_MEM_ERROR )
- err = -ENOMEM;
- if ( zerr != Z_STREAM_END )
- printk(KERN_DEBUG "zisofs: zisofs_inflate returned %d, inode = %lu, index = %lu, fpage = %d, xpage = %d, avail_in = %d, avail_out = %d, ai = %d, ao = %d\n",
- zerr, inode->i_ino, index,
- fpage, xpage,
- stream.avail_in, stream.avail_out,
- ai, ao);
- bail = 1;
- break;
+ while (stream.avail_out && stream.avail_in) {
+ zerr = zlib_inflate(&stream, Z_SYNC_FLUSH);
+ if (zerr == Z_BUF_ERROR && stream.avail_in == 0)
+ break;
+ if (zerr == Z_STREAM_END)
+ break;
+ if (zerr != Z_OK) {
+ /* EOF, error, or trying to read beyond end of input */
+ if (zerr == Z_MEM_ERROR)
+ *errp = -ENOMEM;
+ else {
+ printk(KERN_DEBUG
+ "zisofs: zisofs_inflate returned"
+ " %d, inode = %lu,"
+ " page idx = %d, bh idx = %d,"
+ " avail_in = %d,"
+ " avail_out = %d\n",
+ zerr, inode->i_ino, curpage,
+ curbh, stream.avail_in,
+ stream.avail_out);
+ *errp = -EIO;
}
+ goto inflate_out;
}
+ }
- if ( stream.avail_out && zerr == Z_STREAM_END ) {
- /* Fractional page written before EOF. This may
- be the last page in the file. */
- memset(stream.next_out, 0, stream.avail_out);
- stream.avail_out = 0;
+ if (!stream.avail_out) {
+ /* This page completed */
+ if (pages[curpage]) {
+ flush_dcache_page(pages[curpage]);
+ SetPageUptodate(pages[curpage]);
}
+ curpage++;
+ }
+ if (!stream.avail_in)
+ curbh++;
+ }
+inflate_out:
+ zlib_inflateEnd(&stream);
- if ( !stream.avail_out ) {
- /* This page completed */
- if ( page ) {
- flush_dcache_page(page);
- SetPageUptodate(page);
- kunmap(page);
- unlock_page(page);
- if ( fpage == xpage )
- err = 0; /* The critical page */
- else
- page_cache_release(page);
- }
- fpage++;
- }
+z_eio:
+ mutex_unlock(&zisofs_zlib_lock);
+
+b_eio:
+ for (i = 0; i < haveblocks; i++)
+ brelse(bhs[i]);
+ return stream.total_out;
+}
+
+/*
+ * Uncompress data so that pages[full_page] is fully uptodate and possibly
+ * fills in other pages if we have data for them.
+ */
+static int zisofs_fill_pages(struct inode *inode, int full_page, int pcount,
+ struct page **pages)
+{
+ loff_t start_off, end_off;
+ loff_t block_start, block_end;
+ unsigned int header_size = ISOFS_I(inode)->i_format_parm[0];
+ unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
+ unsigned int blockptr;
+ loff_t poffset = 0;
+ blkcnt_t cstart_block, cend_block;
+ struct buffer_head *bh;
+ unsigned int blkbits = ISOFS_BUFFER_BITS(inode);
+ unsigned int blksize = 1 << blkbits;
+ int err;
+ loff_t ret;
+
+ BUG_ON(!pages[full_page]);
+
+ /*
+ * We want to read at least 'full_page' page. Because we have to
+ * uncompress the whole compression block anyway, fill the surrounding
+ * pages with the data we have anyway...
+ */
+ start_off = page_offset(pages[full_page]);
+ end_off = min_t(loff_t, start_off + PAGE_CACHE_SIZE, inode->i_size);
+
+ cstart_block = start_off >> zisofs_block_shift;
+ cend_block = (end_off + (1 << zisofs_block_shift) - 1)
+ >> zisofs_block_shift;
+
+ WARN_ON(start_off - (full_page << PAGE_CACHE_SHIFT) !=
+ ((cstart_block << zisofs_block_shift) & PAGE_CACHE_MASK));
+
+ /* Find the pointer to this specific chunk */
+ /* Note: we're not using isonum_731() here because the data is known aligned */
+ /* Note: header_size is in 32-bit words (4 bytes) */
+ blockptr = (header_size + cstart_block) << 2;
+ bh = isofs_bread(inode, blockptr >> blkbits);
+ if (!bh)
+ return -EIO;
+ block_start = le32_to_cpu(*(__le32 *)
+ (bh->b_data + (blockptr & (blksize - 1))));
+
+ while (cstart_block < cend_block && pcount > 0) {
+ /* Load end of the compressed block in the file */
+ blockptr += 4;
+ /* Traversed to next block? */
+ if (!(blockptr & (blksize - 1))) {
+ brelse(bh);
+
+ bh = isofs_bread(inode, blockptr >> blkbits);
+ if (!bh)
+ return -EIO;
+ }
+ block_end = le32_to_cpu(*(__le32 *)
+ (bh->b_data + (blockptr & (blksize - 1))));
+ if (block_start > block_end) {
+ brelse(bh);
+ return -EIO;
+ }
+ err = 0;
+ ret = zisofs_uncompress_block(inode, block_start, block_end,
+ pcount, pages, poffset, &err);
+ poffset += ret;
+ pages += poffset >> PAGE_CACHE_SHIFT;
+ pcount -= poffset >> PAGE_CACHE_SHIFT;
+ full_page -= poffset >> PAGE_CACHE_SHIFT;
+ poffset &= ~PAGE_CACHE_MASK;
+
+ if (err) {
+ brelse(bh);
+ /*
+ * Did we finish reading the page we really wanted
+ * to read?
+ */
+ if (full_page < 0)
+ return 0;
+ return err;
}
- zlib_inflateEnd(&stream);
- z_eio:
- mutex_unlock(&zisofs_zlib_lock);
+ block_start = block_end;
+ cstart_block++;
+ }
+
+ if (poffset && *pages) {
+ memset(page_address(*pages) + poffset, 0,
+ PAGE_CACHE_SIZE - poffset);
+ flush_dcache_page(*pages);
+ SetPageUptodate(*pages);
+ }
+ return 0;
+}
- b_eio:
- for ( i = 0 ; i < haveblocks ; i++ ) {
- if ( bhs[i] )
- brelse(bhs[i]);
+/*
+ * When decompressing, we typically obtain more than one page
+ * per reference. We inject the additional pages into the page
+ * cache as a form of readahead.
+ */
+static int zisofs_readpage(struct file *file, struct page *page)
+{
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct address_space *mapping = inode->i_mapping;
+ int err;
+ int i, pcount, full_page;
+ unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
+ unsigned int zisofs_pages_per_cblock =
+ PAGE_CACHE_SHIFT <= zisofs_block_shift ?
+ (1 << (zisofs_block_shift - PAGE_CACHE_SHIFT)) : 0;
+ struct page *pages[max_t(unsigned, zisofs_pages_per_cblock, 1)];
+ pgoff_t index = page->index, end_index;
+
+ end_index = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ /*
+ * If this page is wholly outside i_size we just return zero;
+ * do_generic_file_read() will handle this for us
+ */
+ if (index >= end_index) {
+ SetPageUptodate(page);
+ unlock_page(page);
+ return 0;
+ }
+
+ if (PAGE_CACHE_SHIFT <= zisofs_block_shift) {
+ /* We have already been given one page, this is the one
+ we must do. */
+ full_page = index & (zisofs_pages_per_cblock - 1);
+ pcount = min_t(int, zisofs_pages_per_cblock,
+ end_index - (index & ~(zisofs_pages_per_cblock - 1)));
+ index -= full_page;
+ } else {
+ full_page = 0;
+ pcount = 1;
+ }
+ pages[full_page] = page;
+
+ for (i = 0; i < pcount; i++, index++) {
+ if (i != full_page)
+ pages[i] = grab_cache_page_nowait(mapping, index);
+ if (pages[i]) {
+ ClearPageError(pages[i]);
+ kmap(pages[i]);
}
}
-eio:
+ err = zisofs_fill_pages(inode, full_page, pcount, pages);
/* Release any residual pages, do not SetPageUptodate */
- while ( fpage < maxpage ) {
- page = pages[fpage];
- if ( page ) {
- flush_dcache_page(page);
- if ( fpage == xpage )
- SetPageError(page);
- kunmap(page);
- unlock_page(page);
- if ( fpage != xpage )
- page_cache_release(page);
+ for (i = 0; i < pcount; i++) {
+ if (pages[i]) {
+ flush_dcache_page(pages[i]);
+ if (i == full_page && err)
+ SetPageError(pages[i]);
+ kunmap(pages[i]);
+ unlock_page(pages[i]);
+ if (i != full_page)
+ page_cache_release(pages[i]);
}
- fpage++;
}
/* At this point, err contains 0 or -EIO depending on the "critical" page */
diff --git a/fs/isofs/export.c b/fs/isofs/export.c
index e81a30593ba9..ed752cb38474 100644
--- a/fs/isofs/export.c
+++ b/fs/isofs/export.c
@@ -9,7 +9,7 @@
*
* The following files are helpful:
*
- * Documentation/filesystems/Exporting
+ * Documentation/filesystems/nfs/Exporting
* fs/exportfs/expfs.c.
*/
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
index c2fb2dd0131f..96a685c550fd 100644
--- a/fs/isofs/rock.c
+++ b/fs/isofs/rock.c
@@ -518,8 +518,7 @@ repeat:
if (algo == SIG('p', 'z')) {
int block_shift =
isonum_711(&rr->u.ZF.parms[1]);
- if (block_shift < PAGE_CACHE_SHIFT
- || block_shift > 17) {
+ if (block_shift > 17) {
printk(KERN_WARNING "isofs: "
"Can't handle ZF block "
"size of 2^%d\n",
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index d4cfd6d2779e..c5edc13ccdd0 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -286,7 +286,7 @@ static int journal_finish_inode_data_buffers(journal_t *journal,
if (err) {
/*
* Because AS_EIO is cleared by
- * wait_on_page_writeback_range(), set it again so
+ * filemap_fdatawait_range(), set it again so
* that user process can get -EIO from fsync().
*/
set_bit(AS_EIO,
diff --git a/fs/namei.c b/fs/namei.c
index d11f404667e9..b83d38f614ff 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1678,6 +1678,15 @@ struct file *do_filp_open(int dfd, const char *pathname,
int will_write;
int flag = open_to_namei_flags(open_flag);
+ /*
+ * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only
+ * check for O_DSYNC if the need any syncing at all we enforce it's
+ * always set instead of having to deal with possibly weird behaviour
+ * for malicious applications setting only __O_SYNC.
+ */
+ if (open_flag & __O_SYNC)
+ open_flag |= O_DSYNC;
+
if (!acc_mode)
acc_mode = MAY_OPEN | ACC_MODE(flag);
diff --git a/fs/namespace.c b/fs/namespace.c
index bdc3cb4fd222..7d70d63ceb29 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1921,6 +1921,16 @@ long do_mount(char *dev_name, char *dir_name, char *type_page,
if (data_page)
((char *)data_page)[PAGE_SIZE - 1] = 0;
+ /* ... and get the mountpoint */
+ retval = kern_path(dir_name, LOOKUP_FOLLOW, &path);
+ if (retval)
+ return retval;
+
+ retval = security_sb_mount(dev_name, &path,
+ type_page, flags, data_page);
+ if (retval)
+ goto dput_out;
+
/* Default to relatime unless overriden */
if (!(flags & MS_NOATIME))
mnt_flags |= MNT_RELATIME;
@@ -1945,16 +1955,6 @@ long do_mount(char *dev_name, char *dir_name, char *type_page,
MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |
MS_STRICTATIME);
- /* ... and get the mountpoint */
- retval = kern_path(dir_name, LOOKUP_FOLLOW, &path);
- if (retval)
- return retval;
-
- retval = security_sb_mount(dev_name, &path,
- type_page, flags, data_page);
- if (retval)
- goto dput_out;
-
if (flags & MS_REMOUNT)
retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
data_page);
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index 2a77bc25d5af..59e5673b4597 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -90,7 +90,7 @@ config ROOT_NFS
If you want your system to mount its root file system via NFS,
choose Y here. This is common practice for managing systems
without local permanent storage. For details, read
- <file:Documentation/filesystems/nfsroot.txt>.
+ <file:Documentation/filesystems/nfs/nfsroot.txt>.
Most people say N here.
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 32062c33c859..7cb298525eef 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1536,6 +1536,8 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
dentry->d_parent->d_name.name, dentry->d_name.name);
+ nfs_inode_return_delegation(inode);
+
d_drop(dentry);
error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
if (error == 0) {
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 6c3210099d51..e1d415e97849 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -457,6 +457,7 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
};
struct rpc_task_setup task_setup_data = {
.rpc_client = NFS_CLIENT(inode),
+ .rpc_message = &msg,
.callback_ops = &nfs_write_direct_ops,
.workqueue = nfsiod_workqueue,
.flags = RPC_TASK_ASYNC,
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index f5fdd39e037a..6b891328f332 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -581,7 +581,7 @@ static int nfs_need_sync_write(struct file *filp, struct inode *inode)
{
struct nfs_open_context *ctx;
- if (IS_SYNC(inode) || (filp->f_flags & O_SYNC))
+ if (IS_SYNC(inode) || (filp->f_flags & O_DSYNC))
return 1;
ctx = nfs_file_open_context(filp);
if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags))
@@ -622,7 +622,7 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count);
result = generic_file_aio_write(iocb, iov, nr_segs, pos);
- /* Return error values for O_SYNC and IS_SYNC() */
+ /* Return error values for O_DSYNC and IS_SYNC() */
if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) {
int err = nfs_do_fsync(nfs_file_open_context(iocb->ki_filp), inode);
if (err < 0)
diff --git a/fs/nfs/iostat.h b/fs/nfs/iostat.h
index ceda50aad73c..46d779abafd3 100644
--- a/fs/nfs/iostat.h
+++ b/fs/nfs/iostat.h
@@ -25,13 +25,7 @@ struct nfs_iostats {
static inline void nfs_inc_server_stats(const struct nfs_server *server,
enum nfs_stat_eventcounters stat)
{
- struct nfs_iostats *iostats;
- int cpu;
-
- cpu = get_cpu();
- iostats = per_cpu_ptr(server->io_stats, cpu);
- iostats->events[stat]++;
- put_cpu();
+ this_cpu_inc(server->io_stats->events[stat]);
}
static inline void nfs_inc_stats(const struct inode *inode,
@@ -44,13 +38,7 @@ static inline void nfs_add_server_stats(const struct nfs_server *server,
enum nfs_stat_bytecounters stat,
unsigned long addend)
{
- struct nfs_iostats *iostats;
- int cpu;
-
- cpu = get_cpu();
- iostats = per_cpu_ptr(server->io_stats, cpu);
- iostats->bytes[stat] += addend;
- put_cpu();
+ this_cpu_add(server->io_stats->bytes[stat], addend);
}
static inline void nfs_add_stats(const struct inode *inode,
@@ -65,13 +53,7 @@ static inline void nfs_add_fscache_stats(struct inode *inode,
enum nfs_stat_fscachecounters stat,
unsigned long addend)
{
- struct nfs_iostats *iostats;
- int cpu;
-
- cpu = get_cpu();
- iostats = per_cpu_ptr(NFS_SERVER(inode)->io_stats, cpu);
- iostats->fscache[stat] += addend;
- put_cpu();
+ this_cpu_add(NFS_SERVER(inode)->io_stats->fscache[stat], addend);
}
#endif
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index ed7c269e2514..ff37454fa783 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -72,12 +72,17 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
/* Prevent leaks of NFSv4 errors into userland */
static int nfs4_map_errors(int err)
{
- if (err < -1000) {
+ if (err >= -1000)
+ return err;
+ switch (err) {
+ case -NFS4ERR_RESOURCE:
+ return -EREMOTEIO;
+ default:
dprintk("%s could not handle NFSv4 error %d\n",
__func__, -err);
- return -EIO;
+ break;
}
- return err;
+ return -EIO;
}
/*
@@ -3060,9 +3065,6 @@ static void nfs4_renew_done(struct rpc_task *task, void *data)
if (time_before(clp->cl_last_renewal,timestamp))
clp->cl_last_renewal = timestamp;
spin_unlock(&clp->cl_lock);
- dprintk("%s calling put_rpccred on rpc_cred %p\n", __func__,
- task->tk_msg.rpc_cred);
- put_rpccred(task->tk_msg.rpc_cred);
}
static const struct rpc_call_ops nfs4_renew_ops = {
@@ -4877,7 +4879,6 @@ void nfs41_sequence_call_done(struct rpc_task *task, void *data)
nfs41_sequence_free_slot(clp, task->tk_msg.rpc_resp);
dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred);
- put_rpccred(task->tk_msg.rpc_cred);
kfree(task->tk_msg.rpc_argp);
kfree(task->tk_msg.rpc_resp);
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 83ad47cbdd8a..20b4e30e6c82 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -5681,7 +5681,6 @@ static struct {
{ NFS4ERR_SERVERFAULT, -ESERVERFAULT },
{ NFS4ERR_BADTYPE, -EBADTYPE },
{ NFS4ERR_LOCKED, -EAGAIN },
- { NFS4ERR_RESOURCE, -EREMOTEIO },
{ NFS4ERR_SYMLINK, -ELOOP },
{ NFS4ERR_OP_ILLEGAL, -EOPNOTSUPP },
{ NFS4ERR_DEADLOCK, -EDEADLK },
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index a2c18acb8568..90be551b80c1 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1253,6 +1253,7 @@ static int nfs_parse_mount_options(char *raw,
default:
dfprintk(MOUNT, "NFS: unrecognized "
"transport protocol\n");
+ kfree(string);
return 0;
}
break;
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 53eb26c16b50..590dc03b1dd3 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -774,7 +774,7 @@ int nfs_updatepage(struct file *file, struct page *page,
*/
if (nfs_write_pageuptodate(page, inode) &&
inode->i_flock == NULL &&
- !(file->f_flags & O_SYNC)) {
+ !(file->f_flags & O_DSYNC)) {
count = max(count + offset, nfs_page_length(page));
offset = 0;
}
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index c1c9e035d4a4..b73baba3fb97 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -1320,6 +1320,23 @@ rqst_exp_parent(struct svc_rqst *rqstp, struct path *path)
return exp;
}
+static struct svc_export *find_fsidzero_export(struct svc_rqst *rqstp)
+{
+ struct svc_export *exp;
+ u32 fsidv[2];
+
+ mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
+
+ exp = rqst_exp_find(rqstp, FSID_NUM, fsidv);
+ /*
+ * We shouldn't have accepting an nfsv4 request at all if we
+ * don't have a pseudoexport!:
+ */
+ if (IS_ERR(exp) && PTR_ERR(exp) == -ENOENT)
+ exp = ERR_PTR(-ESERVERFAULT);
+ return exp;
+}
+
/*
* Called when we need the filehandle for the root of the pseudofs,
* for a given NFSv4 client. The root is defined to be the
@@ -1330,11 +1347,8 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
{
struct svc_export *exp;
__be32 rv;
- u32 fsidv[2];
-
- mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
- exp = rqst_exp_find(rqstp, FSID_NUM, fsidv);
+ exp = find_fsidzero_export(rqstp);
if (IS_ERR(exp))
return nfserrno(PTR_ERR(exp));
rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL);
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index 725d02f210e2..6d9c6aabc85e 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -389,7 +389,7 @@ sort_pacl(struct posix_acl *pacl)
sort_pacl_range(pacl, 1, i-1);
BUG_ON(pacl->a_entries[i].e_tag != ACL_GROUP_OBJ);
- j = i++;
+ j = ++i;
while (pacl->a_entries[j].e_tag == ACL_GROUP)
j++;
sort_pacl_range(pacl, i, j-1);
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 2153f9bdbebd..42dab9587afe 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -477,13 +477,14 @@ static int set_forechannel_drc_size(struct nfsd4_channel_attrs *fchan)
/*
* 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)
{
int status = 0;
- __u32 maxcount = svc_max_payload(rqstp);
+ __u32 maxcount = nfsd_serv->sv_max_mesg;
/* headerpadsz set to zero in encode routine */
@@ -523,6 +524,15 @@ free_session_slots(struct nfsd4_session *ses)
kfree(ses->se_slots[i]);
}
+/*
+ * 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
alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp,
struct nfsd4_create_session *cses)
@@ -554,7 +564,7 @@ alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp,
memcpy(new, &tmp, sizeof(*new));
/* allocate each struct nfsd4_slot and data cache in one piece */
- cachesize = new->se_fchannel.maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
+ cachesize = slot_bytes(&new->se_fchannel);
for (i = 0; i < new->se_fchannel.maxreqs; i++) {
sp = kzalloc(sizeof(*sp) + cachesize, GFP_KERNEL);
if (!sp)
@@ -628,10 +638,12 @@ 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);
- nfsd_drc_mem_used -= ses->se_fchannel.maxreqs * NFSD_SLOT_CACHE_SIZE;
+ 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);
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 0eb9c820b7a6..c5393d1b8955 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -758,6 +758,7 @@ nfserrno (int errno)
{ nfserr_io, -ETXTBSY },
{ nfserr_notsupp, -EOPNOTSUPP },
{ nfserr_toosmall, -ETOOSMALL },
+ { nfserr_serverfault, -ESERVERFAULT },
};
int i;
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index a293f0273263..098c4b4dfa1f 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -141,6 +141,40 @@ out:
return err;
}
+static void follow_to_parent(struct path *path)
+{
+ struct dentry *dp;
+
+ while (path->dentry == path->mnt->mnt_root && follow_up(path))
+ ;
+ dp = dget_parent(path->dentry);
+ dput(path->dentry);
+ path->dentry = dp;
+}
+
+static int nfsd_lookup_parent(struct svc_rqst *rqstp, struct dentry *dparent, struct svc_export **exp, struct dentry **dentryp)
+{
+ struct svc_export *exp2;
+ struct path path = {.mnt = mntget((*exp)->ex_path.mnt),
+ .dentry = dget(dparent)};
+
+ follow_to_parent(&path);
+
+ exp2 = rqst_exp_parent(rqstp, &path);
+ if (PTR_ERR(exp2) == -ENOENT) {
+ *dentryp = dget(dparent);
+ } else if (IS_ERR(exp2)) {
+ path_put(&path);
+ return PTR_ERR(exp2);
+ } else {
+ *dentryp = dget(path.dentry);
+ exp_put(*exp);
+ *exp = exp2;
+ }
+ path_put(&path);
+ return 0;
+}
+
__be32
nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
const char *name, unsigned int len,
@@ -169,35 +203,13 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
dentry = dget(dparent);
else if (dparent != exp->ex_path.dentry)
dentry = dget_parent(dparent);
- else if (!EX_NOHIDE(exp))
+ else if (!EX_NOHIDE(exp) && !nfsd_v4client(rqstp))
dentry = dget(dparent); /* .. == . just like at / */
else {
/* checking mountpoint crossing is very different when stepping up */
- struct svc_export *exp2 = NULL;
- struct dentry *dp;
- struct path path = {.mnt = mntget(exp->ex_path.mnt),
- .dentry = dget(dparent)};
-
- while (path.dentry == path.mnt->mnt_root &&
- follow_up(&path))
- ;
- dp = dget_parent(path.dentry);
- dput(path.dentry);
- path.dentry = dp;
-
- exp2 = rqst_exp_parent(rqstp, &path);
- if (PTR_ERR(exp2) == -ENOENT) {
- dentry = dget(dparent);
- } else if (IS_ERR(exp2)) {
- host_err = PTR_ERR(exp2);
- path_put(&path);
+ host_err = nfsd_lookup_parent(rqstp, dparent, &exp, &dentry);
+ if (host_err)
goto out_nfserr;
- } else {
- dentry = dget(path.dentry);
- exp_put(exp);
- exp = exp2;
- }
- path_put(&path);
}
} else {
fh_lock(fhp);
@@ -958,7 +970,7 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
nfsdstats.io_read += host_err;
*count = host_err;
err = 0;
- fsnotify_access(file->f_path.dentry);
+ fsnotify_access(file);
} else
err = nfserrno(host_err);
out:
@@ -1069,7 +1081,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
goto out_nfserr;
*cnt = host_err;
nfsdstats.io_write += host_err;
- fsnotify_modify(file->f_path.dentry);
+ fsnotify_modify(file);
/* clear setuid/setgid flag after write */
if (inode->i_mode & (S_ISUID | S_ISGID))
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c
index 828a889be909..fc3a9dc567c5 100644
--- a/fs/notify/dnotify/dnotify.c
+++ b/fs/notify/dnotify/dnotify.c
@@ -70,8 +70,8 @@ static void dnotify_recalc_inode_mask(struct fsnotify_mark_entry *entry)
if (old_mask == new_mask)
return;
- if (entry->inode)
- fsnotify_recalc_inode_mask(entry->inode);
+ if (entry->i.inode)
+ fsnotify_recalc_inode_mask(entry->i.inode);
}
/*
@@ -91,6 +91,7 @@ static int dnotify_handle_event(struct fsnotify_group *group,
struct dnotify_struct *dn;
struct dnotify_struct **prev;
struct fown_struct *fown;
+ __u32 test_mask = event->mask & ~FS_EVENT_ON_CHILD;
to_tell = event->to_tell;
@@ -106,7 +107,7 @@ static int dnotify_handle_event(struct fsnotify_group *group,
spin_lock(&entry->lock);
prev = &dnentry->dn;
while ((dn = *prev) != NULL) {
- if ((dn->dn_mask & event->mask) == 0) {
+ if ((dn->dn_mask & test_mask) == 0) {
prev = &dn->dn_next;
continue;
}
@@ -132,7 +133,8 @@ static int dnotify_handle_event(struct fsnotify_group *group,
* userspace notification for that pair.
*/
static bool dnotify_should_send_event(struct fsnotify_group *group,
- struct inode *inode, __u32 mask)
+ struct inode *inode, struct vfsmount *mnt,
+ __u32 mask, void *data, int data_type)
{
struct fsnotify_mark_entry *entry;
bool send;
@@ -361,7 +363,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
dnentry = container_of(entry, struct dnotify_mark_entry, fsn_entry);
spin_lock(&entry->lock);
} else {
- fsnotify_add_mark(new_entry, dnotify_group, inode);
+ fsnotify_add_mark(new_entry, dnotify_group, inode, 0);
spin_lock(&new_entry->lock);
entry = new_entry;
dnentry = new_dnentry;
@@ -431,8 +433,7 @@ static int __init dnotify_init(void)
dnotify_struct_cache = KMEM_CACHE(dnotify_struct, SLAB_PANIC);
dnotify_mark_entry_cache = KMEM_CACHE(dnotify_mark_entry, SLAB_PANIC);
- dnotify_group = fsnotify_obtain_group(DNOTIFY_GROUP_NUM,
- 0, &dnotify_fsnotify_ops);
+ dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops);
if (IS_ERR(dnotify_group))
panic("unable to allocate fsnotify group for dnotify\n");
return 0;
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 037e878e03fc..5d1d2edc137a 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -20,6 +20,7 @@
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/mount.h>
#include <linux/srcu.h>
#include <linux/fsnotify_backend.h>
@@ -77,13 +78,16 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)
}
/* Notify this dentry's parent about a child's events. */
-void __fsnotify_parent(struct dentry *dentry, __u32 mask)
+void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask)
{
struct dentry *parent;
struct inode *p_inode;
bool send = false;
bool should_update_children = false;
+ if (file)
+ dentry = file->f_path.dentry;
+
if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED))
return;
@@ -114,8 +118,12 @@ void __fsnotify_parent(struct dentry *dentry, __u32 mask)
* specifies these are events which came from a child. */
mask |= FS_EVENT_ON_CHILD;
- fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
- dentry->d_name.name, 0);
+ if (file)
+ fsnotify(p_inode, mask, file, FSNOTIFY_EVENT_FILE,
+ dentry->d_name.name, 0);
+ else
+ fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
+ dentry->d_name.name, 0);
dput(parent);
}
@@ -126,6 +134,38 @@ void __fsnotify_parent(struct dentry *dentry, __u32 mask)
}
EXPORT_SYMBOL_GPL(__fsnotify_parent);
+static void send_to_group(struct fsnotify_group *group, struct inode *to_tell,
+ struct vfsmount *mnt, __u32 mask, void *data,
+ int data_is, u32 cookie, const char *file_name,
+ struct fsnotify_event **event)
+{
+ if (!group->ops->should_send_event(group, to_tell, mnt, mask,
+ data, data_is))
+ return;
+ if (!*event) {
+ *event = fsnotify_create_event(to_tell, mask, data,
+ data_is, file_name,
+ cookie, GFP_KERNEL);
+ /*
+ * shit, we OOM'd and now we can't tell, maybe
+ * someday someone else will want to do something
+ * here
+ */
+ if (!*event)
+ return;
+ }
+ group->ops->handle_event(group, *event);
+}
+
+static bool needed_by_vfsmount(__u32 test_mask, struct vfsmount *mnt)
+{
+ if (!mnt)
+ return false;
+
+ /* hook in this when mnt->mnt_fsnotify_mask is defined */
+ /* return (test_mask & path->mnt->mnt_fsnotify_mask); */
+ return false;
+}
/*
* This is the main call to fsnotify. The VFS calls into hook specific functions
* in linux/fsnotify.h. Those functions then in turn call here. Here will call
@@ -136,41 +176,56 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const
{
struct fsnotify_group *group;
struct fsnotify_event *event = NULL;
+ struct vfsmount *mnt = NULL;
int idx;
/* global tests shouldn't care about events on child only the specific event */
__u32 test_mask = (mask & ~FS_EVENT_ON_CHILD);
- if (list_empty(&fsnotify_groups))
- return;
-
- if (!(test_mask & fsnotify_mask))
- return;
+ /* if no fsnotify listeners, nothing to do */
+ if (list_empty(&fsnotify_inode_groups) &&
+ list_empty(&fsnotify_vfsmount_groups))
+ return;
+
+ /* if none of the directed listeners or vfsmount listeners care */
+ if (!(test_mask & fsnotify_inode_mask) &&
+ !(test_mask & fsnotify_vfsmount_mask))
+ return;
+
+ if (data_is == FSNOTIFY_EVENT_PATH)
+ mnt = ((struct path *)data)->mnt;
+ else if (data_is == FSNOTIFY_EVENT_FILE)
+ mnt = ((struct file *)data)->f_path.mnt;
+
+ /* if this inode's directed listeners don't care and nothing on the vfsmount
+ * listeners list cares, nothing to do */
+ if (!(test_mask & to_tell->i_fsnotify_mask) &&
+ !needed_by_vfsmount(test_mask, mnt))
+ return;
- if (!(test_mask & to_tell->i_fsnotify_mask))
- return;
/*
* SRCU!! the groups list is very very much read only and the path is
* very hot. The VAST majority of events are not going to need to do
* anything other than walk the list so it's crazy to pre-allocate.
*/
idx = srcu_read_lock(&fsnotify_grp_srcu);
- list_for_each_entry_rcu(group, &fsnotify_groups, group_list) {
- if (test_mask & group->mask) {
- if (!group->ops->should_send_event(group, to_tell, mask))
- continue;
- if (!event) {
- event = fsnotify_create_event(to_tell, mask, data,
- data_is, file_name, cookie,
- GFP_KERNEL);
- /* shit, we OOM'd and now we can't tell, maybe
- * someday someone else will want to do something
- * here */
- if (!event)
- break;
+
+ if (test_mask & to_tell->i_fsnotify_mask) {
+ list_for_each_entry_rcu(group, &fsnotify_inode_groups, inode_group_list) {
+ if (test_mask & group->mask) {
+ send_to_group(group, to_tell, NULL, mask, data, data_is,
+ cookie, file_name, &event);
}
- group->ops->handle_event(group, event);
}
}
+ if (needed_by_vfsmount(test_mask, mnt)) {
+ list_for_each_entry_rcu(group, &fsnotify_vfsmount_groups, vfsmount_group_list) {
+ if (test_mask & group->mask) {
+ send_to_group(group, to_tell, mnt, mask, data, data_is,
+ cookie, file_name, &event);
+ }
+ }
+ }
+
srcu_read_unlock(&fsnotify_grp_srcu, idx);
/*
* fsnotify_create_event() took a reference so the event can't be cleaned
diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h
index 4dc240824b2d..2ba59158969f 100644
--- a/fs/notify/fsnotify.h
+++ b/fs/notify/fsnotify.h
@@ -8,14 +8,22 @@
/* protects reads of fsnotify_groups */
extern struct srcu_struct fsnotify_grp_srcu;
-/* all groups which receive fsnotify events */
-extern struct list_head fsnotify_groups;
-/* all bitwise OR of all event types (FS_*) for all fsnotify_groups */
-extern __u32 fsnotify_mask;
+/* all groups which receive inode fsnotify events */
+extern struct list_head fsnotify_inode_groups;
+/* all groups which receive vfsmount fsnotify events */
+extern struct list_head fsnotify_vfsmount_groups;
+/* all bitwise OR of all event types (FS_*) for all fsnotify_inode_groups */
+extern __u32 fsnotify_inode_mask;
+/* all bitwise OR of all event types (FS_*) for all fsnotify_vfsmount_groups */
+extern __u32 fsnotify_vfsmount_mask;
/* destroy all events sitting in this groups notification queue */
extern void fsnotify_flush_notify(struct fsnotify_group *group);
+/* add a group to the inode group list */
+extern void fsnotify_add_inode_group(struct fsnotify_group *group);
+/* add a group to the vfsmount group list */
+extern void fsnotify_add_vfsmount_group(struct fsnotify_group *group);
/* final kfree of a group */
extern void fsnotify_final_destroy_group(struct fsnotify_group *group);
diff --git a/fs/notify/group.c b/fs/notify/group.c
index 0e1677144bc5..aa4654fe6ec2 100644
--- a/fs/notify/group.c
+++ b/fs/notify/group.c
@@ -32,10 +32,14 @@
static DEFINE_MUTEX(fsnotify_grp_mutex);
/* protects reads while running the fsnotify_groups list */
struct srcu_struct fsnotify_grp_srcu;
-/* all groups registered to receive filesystem notifications */
-LIST_HEAD(fsnotify_groups);
+/* all groups registered to receive inode filesystem notifications */
+LIST_HEAD(fsnotify_inode_groups);
+/* all groups registered to receive mount point filesystem notifications */
+LIST_HEAD(fsnotify_vfsmount_groups);
/* bitwise OR of all events (FS_*) interesting to some group on this system */
-__u32 fsnotify_mask;
+__u32 fsnotify_inode_mask;
+/* bitwise OR of all events (FS_*) interesting to some group on this system */
+__u32 fsnotify_vfsmount_mask;
/*
* When a new group registers or changes it's set of interesting events
@@ -44,14 +48,20 @@ __u32 fsnotify_mask;
void fsnotify_recalc_global_mask(void)
{
struct fsnotify_group *group;
- __u32 mask = 0;
+ __u32 inode_mask = 0;
+ __u32 vfsmount_mask = 0;
int idx;
idx = srcu_read_lock(&fsnotify_grp_srcu);
- list_for_each_entry_rcu(group, &fsnotify_groups, group_list)
- mask |= group->mask;
+ list_for_each_entry_rcu(group, &fsnotify_inode_groups, inode_group_list)
+ inode_mask |= group->mask;
+ list_for_each_entry_rcu(group, &fsnotify_vfsmount_groups, vfsmount_group_list)
+ vfsmount_mask |= group->mask;
+
srcu_read_unlock(&fsnotify_grp_srcu, idx);
- fsnotify_mask = mask;
+
+ fsnotify_inode_mask = inode_mask;
+ fsnotify_vfsmount_mask = vfsmount_mask;
}
/*
@@ -77,13 +87,26 @@ void fsnotify_recalc_group_mask(struct fsnotify_group *group)
fsnotify_recalc_global_mask();
}
-/*
- * Take a reference to a group so things found under the fsnotify_grp_mutex
- * can't get freed under us
- */
-static void fsnotify_get_group(struct fsnotify_group *group)
+void fsnotify_add_vfsmount_group(struct fsnotify_group *group)
{
- atomic_inc(&group->refcnt);
+ mutex_lock(&fsnotify_grp_mutex);
+
+ if (!group->on_vfsmount_group_list)
+ list_add_tail_rcu(&group->vfsmount_group_list, &fsnotify_vfsmount_groups);
+ group->on_vfsmount_group_list = 1;
+
+ mutex_unlock(&fsnotify_grp_mutex);
+}
+
+void fsnotify_add_inode_group(struct fsnotify_group *group)
+{
+ mutex_lock(&fsnotify_grp_mutex);
+
+ if (!group->on_inode_group_list)
+ list_add_tail_rcu(&group->inode_group_list, &fsnotify_inode_groups);
+ group->on_inode_group_list = 1;
+
+ mutex_unlock(&fsnotify_grp_mutex);
}
/*
@@ -127,9 +150,12 @@ static void __fsnotify_evict_group(struct fsnotify_group *group)
{
BUG_ON(!mutex_is_locked(&fsnotify_grp_mutex));
- if (group->on_group_list)
- list_del_rcu(&group->group_list);
- group->on_group_list = 0;
+ if (group->on_inode_group_list)
+ list_del_rcu(&group->inode_group_list);
+ group->on_inode_group_list = 0;
+ if (group->on_vfsmount_group_list)
+ list_del_rcu(&group->vfsmount_group_list);
+ group->on_vfsmount_group_list = 0;
}
/*
@@ -171,84 +197,36 @@ void fsnotify_put_group(struct fsnotify_group *group)
}
/*
- * Simply run the fsnotify_groups list and find a group which matches
- * the given parameters. If a group is found we take a reference to that
- * group.
+ * Create a new fsnotify_group and hold a reference for the group returned.
*/
-static struct fsnotify_group *fsnotify_find_group(unsigned int group_num, __u32 mask,
- const struct fsnotify_ops *ops)
+struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops)
{
- struct fsnotify_group *group_iter;
- struct fsnotify_group *group = NULL;
-
- BUG_ON(!mutex_is_locked(&fsnotify_grp_mutex));
-
- list_for_each_entry_rcu(group_iter, &fsnotify_groups, group_list) {
- if (group_iter->group_num == group_num) {
- if ((group_iter->mask == mask) &&
- (group_iter->ops == ops)) {
- fsnotify_get_group(group_iter);
- group = group_iter;
- } else
- group = ERR_PTR(-EEXIST);
- }
- }
- return group;
-}
-
-/*
- * Either finds an existing group which matches the group_num, mask, and ops or
- * creates a new group and adds it to the global group list. In either case we
- * take a reference for the group returned.
- */
-struct fsnotify_group *fsnotify_obtain_group(unsigned int group_num, __u32 mask,
- const struct fsnotify_ops *ops)
-{
- struct fsnotify_group *group, *tgroup;
+ struct fsnotify_group *group;
- /* very low use, simpler locking if we just always alloc */
- group = kmalloc(sizeof(struct fsnotify_group), GFP_KERNEL);
+ group = kzalloc(sizeof(struct fsnotify_group), GFP_KERNEL);
if (!group)
return ERR_PTR(-ENOMEM);
+ /* set to 0 when there a no external references to this group */
atomic_set(&group->refcnt, 1);
-
- group->on_group_list = 0;
- group->group_num = group_num;
- group->mask = mask;
+ /*
+ * hits 0 when there are no external references AND no marks for
+ * this group
+ */
+ atomic_set(&group->num_marks, 1);
mutex_init(&group->notification_mutex);
INIT_LIST_HEAD(&group->notification_list);
init_waitqueue_head(&group->notification_waitq);
- group->q_len = 0;
group->max_events = UINT_MAX;
+ INIT_LIST_HEAD(&group->inode_group_list);
+ INIT_LIST_HEAD(&group->vfsmount_group_list);
+
spin_lock_init(&group->mark_lock);
- atomic_set(&group->num_marks, 0);
INIT_LIST_HEAD(&group->mark_entries);
group->ops = ops;
- mutex_lock(&fsnotify_grp_mutex);
- tgroup = fsnotify_find_group(group_num, mask, ops);
- if (tgroup) {
- /* group already exists */
- mutex_unlock(&fsnotify_grp_mutex);
- /* destroy the new one we made */
- fsnotify_put_group(group);
- return tgroup;
- }
-
- /* group not found, add a new one */
- list_add_rcu(&group->group_list, &fsnotify_groups);
- group->on_group_list = 1;
- /* being on the fsnotify_groups list holds one num_marks */
- atomic_inc(&group->num_marks);
-
- mutex_unlock(&fsnotify_grp_mutex);
-
- if (mask)
- fsnotify_recalc_global_mask();
-
return group;
}
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c
index c8a07c65482b..cee44045b60d 100644
--- a/fs/notify/inode_mark.c
+++ b/fs/notify/inode_mark.c
@@ -118,7 +118,7 @@ static void fsnotify_recalc_inode_mask_locked(struct inode *inode)
assert_spin_locked(&inode->i_lock);
- hlist_for_each_entry(entry, pos, &inode->i_fsnotify_mark_entries, i_list)
+ hlist_for_each_entry(entry, pos, &inode->i_fsnotify_mark_entries, i.i_list)
new_mask |= entry->mask;
inode->i_fsnotify_mask = new_mask;
}
@@ -149,7 +149,7 @@ void fsnotify_destroy_mark_by_entry(struct fsnotify_mark_entry *entry)
spin_lock(&entry->lock);
group = entry->group;
- inode = entry->inode;
+ inode = entry->i.inode;
BUG_ON(group && !inode);
BUG_ON(!group && inode);
@@ -166,8 +166,8 @@ void fsnotify_destroy_mark_by_entry(struct fsnotify_mark_entry *entry)
spin_lock(&group->mark_lock);
spin_lock(&inode->i_lock);
- hlist_del_init(&entry->i_list);
- entry->inode = NULL;
+ hlist_del_init(&entry->i.i_list);
+ entry->i.inode = NULL;
list_del_init(&entry->g_list);
entry->group = NULL;
@@ -249,14 +249,14 @@ void fsnotify_clear_marks_by_inode(struct inode *inode)
LIST_HEAD(free_list);
spin_lock(&inode->i_lock);
- hlist_for_each_entry_safe(entry, pos, n, &inode->i_fsnotify_mark_entries, i_list) {
- list_add(&entry->free_i_list, &free_list);
- hlist_del_init(&entry->i_list);
+ hlist_for_each_entry_safe(entry, pos, n, &inode->i_fsnotify_mark_entries, i.i_list) {
+ list_add(&entry->i.free_i_list, &free_list);
+ hlist_del_init(&entry->i.i_list);
fsnotify_get_mark(entry);
}
spin_unlock(&inode->i_lock);
- list_for_each_entry_safe(entry, lentry, &free_list, free_i_list) {
+ list_for_each_entry_safe(entry, lentry, &free_list, i.free_i_list) {
fsnotify_destroy_mark_by_entry(entry);
fsnotify_put_mark(entry);
}
@@ -274,7 +274,7 @@ struct fsnotify_mark_entry *fsnotify_find_mark_entry(struct fsnotify_group *grou
assert_spin_locked(&inode->i_lock);
- hlist_for_each_entry(entry, pos, &inode->i_fsnotify_mark_entries, i_list) {
+ hlist_for_each_entry(entry, pos, &inode->i_fsnotify_mark_entries, i.i_list) {
if (entry->group == group) {
fsnotify_get_mark(entry);
return entry;
@@ -283,19 +283,27 @@ struct fsnotify_mark_entry *fsnotify_find_mark_entry(struct fsnotify_group *grou
return NULL;
}
+void fsnotify_duplicate_mark(struct fsnotify_mark_entry *new, struct fsnotify_mark_entry *old)
+{
+ assert_spin_locked(&old->lock);
+ new->i.inode = old->i.inode;
+ new->group = old->group;
+ new->mask = old->mask;
+ new->free_mark = old->free_mark;
+}
+
/*
* Nothing fancy, just initialize lists and locks and counters.
*/
void fsnotify_init_mark(struct fsnotify_mark_entry *entry,
void (*free_mark)(struct fsnotify_mark_entry *entry))
-
{
spin_lock_init(&entry->lock);
atomic_set(&entry->refcnt, 1);
- INIT_HLIST_NODE(&entry->i_list);
+ INIT_HLIST_NODE(&entry->i.i_list);
entry->group = NULL;
entry->mask = 0;
- entry->inode = NULL;
+ entry->i.inode = NULL;
entry->free_mark = free_mark;
}
@@ -305,15 +313,32 @@ void fsnotify_init_mark(struct fsnotify_mark_entry *entry,
* event types should be delivered to which group and for which inodes.
*/
int fsnotify_add_mark(struct fsnotify_mark_entry *entry,
- struct fsnotify_group *group, struct inode *inode)
+ struct fsnotify_group *group, struct inode *inode,
+ int allow_dups)
{
- struct fsnotify_mark_entry *lentry;
+ struct fsnotify_mark_entry *lentry = NULL;
int ret = 0;
inode = igrab(inode);
if (unlikely(!inode))
return -EINVAL;
+ entry->flags = FSNOTIFY_MARK_FLAG_INODE;
+
+ /*
+ * if this group isn't being testing for inode type events we need
+ * to start testing
+ */
+ if (unlikely(list_empty(&group->inode_group_list)))
+ fsnotify_add_inode_group(group);
+ /*
+ * XXX This is where we could also do the fsnotify_add_vfsmount_group
+ * if we are setting and vfsmount mark....
+
+ if (unlikely(list_empty(&group->vfsmount_group_list)))
+ fsnotify_add_vfsmount_group(group);
+ */
+
/*
* LOCKING ORDER!!!!
* entry->lock
@@ -324,12 +349,13 @@ int fsnotify_add_mark(struct fsnotify_mark_entry *entry,
spin_lock(&group->mark_lock);
spin_lock(&inode->i_lock);
- entry->group = group;
- entry->inode = inode;
-
- lentry = fsnotify_find_mark_entry(group, inode);
+ if (!allow_dups)
+ lentry = fsnotify_find_mark_entry(group, inode);
if (!lentry) {
- hlist_add_head(&entry->i_list, &inode->i_fsnotify_mark_entries);
+ entry->group = group;
+ entry->i.inode = inode;
+
+ hlist_add_head(&entry->i.i_list, &inode->i_fsnotify_mark_entries);
list_add(&entry->g_list, &group->mark_entries);
fsnotify_get_mark(entry); /* for i_list and g_list */
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c
index c9ee67b442e1..badf1a90bff9 100644
--- a/fs/notify/inotify/inotify_fsnotify.c
+++ b/fs/notify/inotify/inotify_fsnotify.c
@@ -31,6 +31,60 @@
#include "inotify.h"
+/*
+ * Check if 2 events contain the same information. We do not compare private data
+ * but at this moment that isn't a problem for any know fsnotify listeners.
+ */
+static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new)
+{
+ if ((old->mask == new->mask) &&
+ (old->to_tell == new->to_tell) &&
+ (old->data_type == new->data_type) &&
+ (old->name_len == new->name_len)) {
+ switch (old->data_type) {
+ case (FSNOTIFY_EVENT_INODE):
+ /* remember, after old was put on the wait_q we aren't
+ * allowed to look at the inode any more, only thing
+ * left to check was if the file_name is the same */
+ if (!old->name_len ||
+ !strcmp(old->file_name, new->file_name))
+ return true;
+ break;
+ case (FSNOTIFY_EVENT_PATH):
+ if ((old->path.mnt == new->path.mnt) &&
+ (old->path.dentry == new->path.dentry))
+ return true;
+ break;
+ case (FSNOTIFY_EVENT_NONE):
+ if (old->mask & FS_Q_OVERFLOW)
+ return true;
+ else if (old->mask & FS_IN_IGNORED)
+ return false;
+ return true;
+ };
+ }
+ return false;
+}
+
+static int inotify_merge(struct list_head *list, struct fsnotify_event *event)
+{
+ struct fsnotify_event_holder *last_holder;
+ struct fsnotify_event *last_event;
+ int ret = 0;
+
+ /* and the list better be locked by something too */
+ spin_lock(&event->lock);
+
+ last_holder = list_entry(list->prev, struct fsnotify_event_holder, event_list);
+ last_event = last_holder->event;
+ if (event_compare(last_event, event))
+ ret = -EEXIST;
+
+ spin_unlock(&event->lock);
+
+ return ret;
+}
+
static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
{
struct fsnotify_mark_entry *entry;
@@ -61,7 +115,7 @@ static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_ev
fsn_event_priv->group = group;
event_priv->wd = wd;
- ret = fsnotify_add_notify_event(group, event, fsn_event_priv);
+ ret = fsnotify_add_notify_event(group, event, fsn_event_priv, inotify_merge);
if (ret) {
inotify_free_event_priv(fsn_event_priv);
/* EEXIST says we tail matched, EOVERFLOW isn't something
@@ -85,7 +139,9 @@ static void inotify_freeing_mark(struct fsnotify_mark_entry *entry, struct fsnot
inotify_ignored_and_remove_idr(entry, group);
}
-static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode, __u32 mask)
+static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode,
+ struct vfsmount *mnt, __u32 mask, void *data,
+ int data_type)
{
struct fsnotify_mark_entry *entry;
bool send;
@@ -136,7 +192,7 @@ static int idr_callback(int id, void *p, void *data)
*/
if (entry)
printk(KERN_WARNING "entry->group=%p inode=%p wd=%d\n",
- entry->group, entry->inode, ientry->wd);
+ entry->group, entry->i.inode, ientry->wd);
return 0;
}
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index dcd2040d330c..f323a026e83c 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -55,12 +55,6 @@ int inotify_max_user_watches __read_mostly;
static struct kmem_cache *inotify_inode_mark_cachep __read_mostly;
struct kmem_cache *event_priv_cachep __read_mostly;
-/*
- * When inotify registers a new group it increments this and uses that
- * value as an offset to set the fsnotify group "name" and priority.
- */
-static atomic_t inotify_grp_num;
-
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
@@ -367,6 +361,77 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns
return error;
}
+static int inotify_add_to_idr(struct idr *idr, spinlock_t *idr_lock,
+ int last_wd,
+ struct inotify_inode_mark_entry *ientry)
+{
+ int ret;
+
+ do {
+ if (unlikely(!idr_pre_get(idr, GFP_KERNEL)))
+ return -ENOMEM;
+
+ spin_lock(idr_lock);
+ ret = idr_get_new_above(idr, ientry, last_wd + 1,
+ &ientry->wd);
+ /* we added the mark to the idr, take a reference */
+ if (!ret)
+ fsnotify_get_mark(&ientry->fsn_entry);
+ spin_unlock(idr_lock);
+ } while (ret == -EAGAIN);
+
+ return ret;
+}
+
+static struct inotify_inode_mark_entry *inotify_idr_find_locked(struct fsnotify_group *group,
+ int wd)
+{
+ struct idr *idr = &group->inotify_data.idr;
+ spinlock_t *idr_lock = &group->inotify_data.idr_lock;
+ struct inotify_inode_mark_entry *ientry;
+
+ assert_spin_locked(idr_lock);
+
+ ientry = idr_find(idr, wd);
+ if (ientry) {
+ struct fsnotify_mark_entry *fsn_entry = &ientry->fsn_entry;
+
+ fsnotify_get_mark(fsn_entry);
+ /* One ref for being in the idr, one ref we just took */
+ BUG_ON(atomic_read(&fsn_entry->refcnt) < 2);
+ }
+
+ return ientry;
+}
+
+static struct inotify_inode_mark_entry *inotify_idr_find(struct fsnotify_group *group,
+ int wd)
+{
+ struct inotify_inode_mark_entry *ientry;
+ spinlock_t *idr_lock = &group->inotify_data.idr_lock;
+
+ spin_lock(idr_lock);
+ ientry = inotify_idr_find_locked(group, wd);
+ spin_unlock(idr_lock);
+
+ return ientry;
+}
+
+static void do_inotify_remove_from_idr(struct fsnotify_group *group,
+ struct inotify_inode_mark_entry *ientry)
+{
+ struct idr *idr = &group->inotify_data.idr;
+ spinlock_t *idr_lock = &group->inotify_data.idr_lock;
+ int wd = ientry->wd;
+
+ assert_spin_locked(idr_lock);
+
+ idr_remove(idr, wd);
+
+ /* removed from the idr, drop that ref */
+ fsnotify_put_mark(&ientry->fsn_entry);
+}
+
/*
* Remove the mark from the idr (if present) and drop the reference
* on the mark because it was in the idr.
@@ -374,42 +439,72 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns
static void inotify_remove_from_idr(struct fsnotify_group *group,
struct inotify_inode_mark_entry *ientry)
{
- struct idr *idr;
- struct fsnotify_mark_entry *entry;
- struct inotify_inode_mark_entry *found_ientry;
+ spinlock_t *idr_lock = &group->inotify_data.idr_lock;
+ struct inotify_inode_mark_entry *found_ientry = NULL;
int wd;
- spin_lock(&group->inotify_data.idr_lock);
- idr = &group->inotify_data.idr;
+ spin_lock(idr_lock);
wd = ientry->wd;
- if (wd == -1)
+ /*
+ * does this ientry think it is in the idr? we shouldn't get called
+ * if it wasn't....
+ */
+ if (wd == -1) {
+ printk(KERN_WARNING "%s: ientry=%p ientry->wd=%d ientry->group=%p"
+ " ientry->inode=%p\n", __func__, ientry, ientry->wd,
+ ientry->fsn_entry.group, ientry->fsn_entry.i.inode);
+ WARN_ON(1);
goto out;
+ }
- entry = idr_find(&group->inotify_data.idr, wd);
- if (unlikely(!entry))
+ /* Lets look in the idr to see if we find it */
+ found_ientry = inotify_idr_find_locked(group, wd);
+ if (unlikely(!found_ientry)) {
+ printk(KERN_WARNING "%s: ientry=%p ientry->wd=%d ientry->group=%p"
+ " ientry->inode=%p\n", __func__, ientry, ientry->wd,
+ ientry->fsn_entry.group, ientry->fsn_entry.i.inode);
+ WARN_ON(1);
goto out;
+ }
- found_ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
+ /*
+ * We found an entry in the idr at the right wd, but it's
+ * not the entry we were told to remove. eparis seriously
+ * fucked up somewhere.
+ */
if (unlikely(found_ientry != ientry)) {
- /* We found an entry in the idr with the right wd, but it's
- * not the entry we were told to remove. eparis seriously
- * fucked up somewhere. */
WARN_ON(1);
- ientry->wd = -1;
+ printk(KERN_WARNING "%s: ientry=%p ientry->wd=%d ientry->group=%p "
+ "entry->inode=%p found_ientry=%p found_ientry->wd=%d "
+ "found_ientry->group=%p found_ientry->inode=%p\n",
+ __func__, ientry, ientry->wd, ientry->fsn_entry.group,
+ ientry->fsn_entry.i.inode, found_ientry, found_ientry->wd,
+ found_ientry->fsn_entry.group,
+ found_ientry->fsn_entry.i.inode);
goto out;
}
- /* One ref for being in the idr, one ref held by the caller */
- BUG_ON(atomic_read(&entry->refcnt) < 2);
-
- idr_remove(idr, wd);
- ientry->wd = -1;
+ /*
+ * One ref for being in the idr
+ * one ref held by the caller trying to kill us
+ * one ref grabbed by inotify_idr_find
+ */
+ if (unlikely(atomic_read(&ientry->fsn_entry.refcnt) < 3)) {
+ printk(KERN_WARNING "%s: ientry=%p ientry->wd=%d ientry->group=%p"
+ " ientry->inode=%p\n", __func__, ientry, ientry->wd,
+ ientry->fsn_entry.group, ientry->fsn_entry.i.inode);
+ /* we can't really recover with bad ref cnting.. */
+ BUG();
+ }
- /* removed from the idr, drop that ref */
- fsnotify_put_mark(entry);
+ do_inotify_remove_from_idr(group, ientry);
out:
- spin_unlock(&group->inotify_data.idr_lock);
+ /* match the ref taken by inotify_idr_find_locked() */
+ if (found_ientry)
+ fsnotify_put_mark(&found_ientry->fsn_entry);
+ ientry->wd = -1;
+ spin_unlock(idr_lock);
}
/*
@@ -441,7 +536,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
fsn_event_priv->group = group;
event_priv->wd = ientry->wd;
- ret = fsnotify_add_notify_event(group, ignored_event, fsn_event_priv);
+ ret = fsnotify_add_notify_event(group, ignored_event, fsn_event_priv, NULL);
if (ret)
inotify_free_event_priv(fsn_event_priv);
@@ -459,7 +554,9 @@ skip_send_ignore:
/* ding dong the mark is dead */
static void inotify_free_mark(struct fsnotify_mark_entry *entry)
{
- struct inotify_inode_mark_entry *ientry = (struct inotify_inode_mark_entry *)entry;
+ struct inotify_inode_mark_entry *ientry;
+
+ ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
kmem_cache_free(inotify_inode_mark_cachep, ientry);
}
@@ -534,6 +631,8 @@ static int inotify_new_watch(struct fsnotify_group *group,
struct inotify_inode_mark_entry *tmp_ientry;
__u32 mask;
int ret;
+ struct idr *idr = &group->inotify_data.idr;
+ spinlock_t *idr_lock = &group->inotify_data.idr_lock;
/* don't allow invalid bits: we don't want flags set */
mask = inotify_arg_to_mask(arg);
@@ -551,28 +650,14 @@ static int inotify_new_watch(struct fsnotify_group *group,
ret = -ENOSPC;
if (atomic_read(&group->inotify_data.user->inotify_watches) >= inotify_max_user_watches)
goto out_err;
-retry:
- ret = -ENOMEM;
- if (unlikely(!idr_pre_get(&group->inotify_data.idr, GFP_KERNEL)))
- goto out_err;
- spin_lock(&group->inotify_data.idr_lock);
- ret = idr_get_new_above(&group->inotify_data.idr, &tmp_ientry->fsn_entry,
- group->inotify_data.last_wd,
- &tmp_ientry->wd);
- spin_unlock(&group->inotify_data.idr_lock);
- if (ret) {
- /* idr was out of memory allocate and try again */
- if (ret == -EAGAIN)
- goto retry;
+ ret = inotify_add_to_idr(idr, idr_lock, group->inotify_data.last_wd,
+ tmp_ientry);
+ if (ret)
goto out_err;
- }
-
- /* we put the mark on the idr, take a reference */
- fsnotify_get_mark(&tmp_ientry->fsn_entry);
/* we are on the idr, now get on the inode */
- ret = fsnotify_add_mark(&tmp_ientry->fsn_entry, group, inode);
+ ret = fsnotify_add_mark(&tmp_ientry->fsn_entry, group, inode, 0);
if (ret) {
/* we failed to get on the inode, get off the idr */
inotify_remove_from_idr(group, tmp_ientry);
@@ -588,16 +673,13 @@ retry:
/* return the watch descriptor for this new entry */
ret = tmp_ientry->wd;
- /* match the ref from fsnotify_init_markentry() */
- fsnotify_put_mark(&tmp_ientry->fsn_entry);
-
/* if this mark added a new event update the group mask */
if (mask & ~group->mask)
fsnotify_recalc_group_mask(group);
out_err:
- if (ret < 0)
- kmem_cache_free(inotify_inode_mark_cachep, tmp_ientry);
+ /* match the ref from fsnotify_init_markentry() */
+ fsnotify_put_mark(&tmp_ientry->fsn_entry);
return ret;
}
@@ -626,11 +708,8 @@ retry:
static struct fsnotify_group *inotify_new_group(struct user_struct *user, unsigned int max_events)
{
struct fsnotify_group *group;
- unsigned int grp_num;
- /* fsnotify_obtain_group took a reference to group, we put this when we kill the file in the end */
- grp_num = (INOTIFY_GROUP_NUM - atomic_inc_return(&inotify_grp_num));
- group = fsnotify_obtain_group(grp_num, 0, &inotify_fsnotify_ops);
+ group = fsnotify_alloc_group(&inotify_fsnotify_ops);
if (IS_ERR(group))
return group;
@@ -638,7 +717,7 @@ static struct fsnotify_group *inotify_new_group(struct user_struct *user, unsign
spin_lock_init(&group->inotify_data.idr_lock);
idr_init(&group->inotify_data.idr);
- group->inotify_data.last_wd = 1;
+ group->inotify_data.last_wd = 0;
group->inotify_data.user = user;
group->inotify_data.fa = NULL;
@@ -760,7 +839,7 @@ fput_and_out:
SYSCALL_DEFINE2(inotify_rm_watch, int, fd, __s32, wd)
{
struct fsnotify_group *group;
- struct fsnotify_mark_entry *entry;
+ struct inotify_inode_mark_entry *ientry;
struct file *filp;
int ret = 0, fput_needed;
@@ -769,25 +848,23 @@ SYSCALL_DEFINE2(inotify_rm_watch, int, fd, __s32, wd)
return -EBADF;
/* verify that this is indeed an inotify instance */
- if (unlikely(filp->f_op != &inotify_fops)) {
- ret = -EINVAL;
+ ret = -EINVAL;
+ if (unlikely(filp->f_op != &inotify_fops))
goto out;
- }
group = filp->private_data;
- spin_lock(&group->inotify_data.idr_lock);
- entry = idr_find(&group->inotify_data.idr, wd);
- if (unlikely(!entry)) {
- spin_unlock(&group->inotify_data.idr_lock);
- ret = -EINVAL;
+ ret = -EINVAL;
+ ientry = inotify_idr_find(group, wd);
+ if (unlikely(!ientry))
goto out;
- }
- fsnotify_get_mark(entry);
- spin_unlock(&group->inotify_data.idr_lock);
- fsnotify_destroy_mark_by_entry(entry);
- fsnotify_put_mark(entry);
+ ret = 0;
+
+ fsnotify_destroy_mark_by_entry(&ientry->fsn_entry);
+
+ /* match ref taken by inotify_idr_find */
+ fsnotify_put_mark(&ientry->fsn_entry);
out:
fput_light(filp, fput_needed);
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index 3816d5750dd5..dafd0b7687b8 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -56,7 +56,7 @@ static struct kmem_cache *fsnotify_event_holder_cachep;
* it is needed. It's refcnt is set 1 at kernel init time and will never
* get set to 0 so it will never get 'freed'
*/
-static struct fsnotify_event q_overflow_event;
+static struct fsnotify_event *q_overflow_event;
static atomic_t fsnotify_sync_cookie = ATOMIC_INIT(0);
/**
@@ -104,7 +104,8 @@ struct fsnotify_event_holder *fsnotify_alloc_event_holder(void)
void fsnotify_destroy_event_holder(struct fsnotify_event_holder *holder)
{
- kmem_cache_free(fsnotify_event_holder_cachep, holder);
+ if (holder)
+ kmem_cache_free(fsnotify_event_holder_cachep, holder);
}
/*
@@ -129,53 +130,17 @@ struct fsnotify_event_private_data *fsnotify_remove_priv_from_event(struct fsnot
}
/*
- * Check if 2 events contain the same information. We do not compare private data
- * but at this moment that isn't a problem for any know fsnotify listeners.
- */
-static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new)
-{
- if ((old->mask == new->mask) &&
- (old->to_tell == new->to_tell) &&
- (old->data_type == new->data_type) &&
- (old->name_len == new->name_len)) {
- switch (old->data_type) {
- case (FSNOTIFY_EVENT_INODE):
- /* remember, after old was put on the wait_q we aren't
- * allowed to look at the inode any more, only thing
- * left to check was if the file_name is the same */
- if (old->name_len &&
- !strcmp(old->file_name, new->file_name))
- return true;
- break;
- case (FSNOTIFY_EVENT_PATH):
- if ((old->path.mnt == new->path.mnt) &&
- (old->path.dentry == new->path.dentry))
- return true;
- break;
- case (FSNOTIFY_EVENT_NONE):
- if (old->mask & FS_Q_OVERFLOW)
- return true;
- else if (old->mask & FS_IN_IGNORED)
- return false;
- return false;
- };
- }
- return false;
-}
-
-/*
* Add an event to the group notification queue. The group can later pull this
* event off the queue to deal with. If the event is successfully added to the
* group's notification queue, a reference is taken on event.
*/
int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event,
- struct fsnotify_event_private_data *priv)
+ struct fsnotify_event_private_data *priv,
+ int (*merge)(struct list_head *, struct fsnotify_event *))
{
struct fsnotify_event_holder *holder = NULL;
struct list_head *list = &group->notification_list;
- struct fsnotify_event_holder *last_holder;
- struct fsnotify_event *last_event;
- int ret = 0;
+ int rc = 0;
/*
* There is one fsnotify_event_holder embedded inside each fsnotify_event.
@@ -195,12 +160,24 @@ alloc_holder:
mutex_lock(&group->notification_mutex);
if (group->q_len >= group->max_events) {
- event = &q_overflow_event;
- ret = -EOVERFLOW;
+ event = q_overflow_event;
+ rc = -EOVERFLOW;
/* sorry, no private data on the overflow event */
priv = NULL;
}
+ if (!list_empty(list) && merge) {
+ int ret;
+
+ ret = merge(list, event);
+ if (ret) {
+ mutex_unlock(&group->notification_mutex);
+ if (holder != &event->holder)
+ fsnotify_destroy_event_holder(holder);
+ return ret;
+ }
+ }
+
spin_lock(&event->lock);
if (list_empty(&event->holder.event_list)) {
@@ -215,18 +192,6 @@ alloc_holder:
goto alloc_holder;
}
- if (!list_empty(list)) {
- last_holder = list_entry(list->prev, struct fsnotify_event_holder, event_list);
- last_event = last_holder->event;
- if (event_compare(last_event, event)) {
- spin_unlock(&event->lock);
- mutex_unlock(&group->notification_mutex);
- if (holder != &event->holder)
- fsnotify_destroy_event_holder(holder);
- return -EEXIST;
- }
- }
-
group->q_len++;
holder->event = event;
@@ -238,7 +203,7 @@ alloc_holder:
mutex_unlock(&group->notification_mutex);
wake_up(&group->notification_waitq);
- return ret;
+ return rc;
}
/*
@@ -314,25 +279,77 @@ void fsnotify_flush_notify(struct fsnotify_group *group)
static void initialize_event(struct fsnotify_event *event)
{
- event->holder.event = NULL;
INIT_LIST_HEAD(&event->holder.event_list);
atomic_set(&event->refcnt, 1);
spin_lock_init(&event->lock);
- event->path.dentry = NULL;
- event->path.mnt = NULL;
- event->inode = NULL;
- event->data_type = FSNOTIFY_EVENT_NONE;
-
INIT_LIST_HEAD(&event->private_data_list);
+}
+
+/*
+ * Caller damn well better be holding whatever mutex is protecting the
+ * old_holder->event_list and the new_event must be a clean event which
+ * cannot be found anywhere else in the kernel.
+ */
+int fsnotify_replace_event(struct fsnotify_event_holder *old_holder,
+ struct fsnotify_event *new_event)
+{
+ struct fsnotify_event *old_event = old_holder->event;
+ struct fsnotify_event_holder *new_holder = &new_event->holder;
- event->to_tell = NULL;
+ enum event_spinlock_class {
+ SPINLOCK_OLD,
+ SPINLOCK_NEW,
+ };
- event->file_name = NULL;
- event->name_len = 0;
+ /*
+ * if the new_event's embedded holder is in use someone
+ * screwed up and didn't give us a clean new event.
+ */
+ BUG_ON(!list_empty(&new_holder->event_list));
+
+ spin_lock_nested(&old_event->lock, SPINLOCK_OLD);
+ spin_lock_nested(&new_event->lock, SPINLOCK_NEW);
+
+ new_holder->event = new_event;
+ list_replace_init(&old_holder->event_list, &new_holder->event_list);
+
+ spin_unlock(&new_event->lock);
+ spin_unlock(&old_event->lock);
+
+ /* event == holder means we are referenced through the in event holder */
+ if (old_holder != &old_event->holder)
+ fsnotify_destroy_event_holder(old_holder);
+
+ fsnotify_get_event(new_event); /* on the list take reference */
+ fsnotify_put_event(old_event); /* off the list, drop reference */
+
+ return 0;
+}
+
+struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event)
+{
+ struct fsnotify_event *event;
- event->sync_cookie = 0;
+ event = kmem_cache_alloc(fsnotify_event_cachep, GFP_KERNEL);
+ if (!event)
+ return NULL;
+
+ memcpy(event, old_event, sizeof(*event));
+ initialize_event(event);
+
+ if (event->name_len) {
+ event->file_name = kstrdup(old_event->file_name, GFP_KERNEL);
+ if (!event->file_name) {
+ kmem_cache_free(fsnotify_event_cachep, event);
+ return NULL;
+ }
+ }
+ if (event->data_type == FSNOTIFY_EVENT_PATH)
+ path_get(&event->path);
+
+ return event;
}
/*
@@ -353,7 +370,7 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
{
struct fsnotify_event *event;
- event = kmem_cache_alloc(fsnotify_event_cachep, gfp);
+ event = kmem_cache_zalloc(fsnotify_event_cachep, gfp);
if (!event)
return NULL;
@@ -370,6 +387,7 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
event->sync_cookie = cookie;
event->to_tell = to_tell;
+ event->data_type = data_type;
switch (data_type) {
case FSNOTIFY_EVENT_FILE: {
@@ -386,12 +404,10 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
event->path.dentry = path->dentry;
event->path.mnt = path->mnt;
path_get(&event->path);
- event->data_type = FSNOTIFY_EVENT_PATH;
break;
}
case FSNOTIFY_EVENT_INODE:
event->inode = data;
- event->data_type = FSNOTIFY_EVENT_INODE;
break;
case FSNOTIFY_EVENT_NONE:
event->inode = NULL;
@@ -412,8 +428,11 @@ __init int fsnotify_notification_init(void)
fsnotify_event_cachep = KMEM_CACHE(fsnotify_event, SLAB_PANIC);
fsnotify_event_holder_cachep = KMEM_CACHE(fsnotify_event_holder, SLAB_PANIC);
- initialize_event(&q_overflow_event);
- q_overflow_event.mask = FS_Q_OVERFLOW;
+ q_overflow_event = fsnotify_create_event(NULL, FS_Q_OVERFLOW, NULL,
+ FSNOTIFY_EVENT_NONE, NULL, 0,
+ GFP_KERNEL);
+ if (!q_overflow_event)
+ panic("unable to allocate fsnotify q_overflow_event\n");
return 0;
}
diff --git a/fs/ocfs2/cluster/netdebug.c b/fs/ocfs2/cluster/netdebug.c
index da794bc07a6c..a3f150e52b02 100644
--- a/fs/ocfs2/cluster/netdebug.c
+++ b/fs/ocfs2/cluster/netdebug.c
@@ -294,10 +294,10 @@ static int sc_seq_show(struct seq_file *seq, void *v)
if (sc->sc_sock) {
inet = inet_sk(sc->sc_sock->sk);
/* the stack's structs aren't sparse endian clean */
- saddr = (__force __be32)inet->saddr;
- daddr = (__force __be32)inet->daddr;
- sport = (__force __be16)inet->sport;
- dport = (__force __be16)inet->dport;
+ saddr = (__force __be32)inet->inet_saddr;
+ daddr = (__force __be32)inet->inet_daddr;
+ sport = (__force __be16)inet->inet_sport;
+ dport = (__force __be16)inet->inet_dport;
}
/* XXX sigh, inet-> doesn't have sparse annotation so any
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 89fc8ee1f5a5..0eaec993b741 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -2005,7 +2005,7 @@ out_dio:
/* buffered aio wouldn't have proper lock coverage today */
BUG_ON(ret == -EIOCBQUEUED && !(file->f_flags & O_DIRECT));
- if ((file->f_flags & O_SYNC && !direct_io) || IS_SYNC(inode)) {
+ if ((file->f_flags & O_DSYNC && !direct_io) || IS_SYNC(inode)) {
ret = filemap_fdatawrite_range(file->f_mapping, pos,
pos + count - 1);
if (ret < 0)
diff --git a/fs/open.c b/fs/open.c
index 4f01e06227c6..ce737b3e4c6f 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -587,6 +587,9 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
error = -EPERM;
if (!capable(CAP_SYS_CHROOT))
goto dput_and_out;
+ error = security_path_chroot(&path);
+ if (error)
+ goto dput_and_out;
set_fs_root(current->fs, &path);
error = 0;
@@ -616,6 +619,9 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode)
err = mnt_want_write_file(file);
if (err)
goto out_putf;
+ err = security_path_chmod(dentry, file->f_vfsmnt, mode);
+ if (err)
+ goto out_drop_write;
mutex_lock(&inode->i_mutex);
if (mode == (mode_t) -1)
mode = inode->i_mode;
@@ -623,6 +629,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode)
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
err = notify_change(dentry, &newattrs);
mutex_unlock(&inode->i_mutex);
+out_drop_write:
mnt_drop_write(file->f_path.mnt);
out_putf:
fput(file);
@@ -645,6 +652,9 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode)
error = mnt_want_write(path.mnt);
if (error)
goto dput_and_out;
+ error = security_path_chmod(path.dentry, path.mnt, mode);
+ if (error)
+ goto out_drop_write;
mutex_lock(&inode->i_mutex);
if (mode == (mode_t) -1)
mode = inode->i_mode;
@@ -652,6 +662,7 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode)
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
error = notify_change(path.dentry, &newattrs);
mutex_unlock(&inode->i_mutex);
+out_drop_write:
mnt_drop_write(path.mnt);
dput_and_out:
path_put(&path);
@@ -700,7 +711,9 @@ SYSCALL_DEFINE3(chown, const char __user *, filename, uid_t, user, gid_t, group)
error = mnt_want_write(path.mnt);
if (error)
goto out_release;
- error = chown_common(path.dentry, user, group);
+ error = security_path_chown(&path, user, group);
+ if (!error)
+ error = chown_common(path.dentry, user, group);
mnt_drop_write(path.mnt);
out_release:
path_put(&path);
@@ -725,7 +738,9 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user,
error = mnt_want_write(path.mnt);
if (error)
goto out_release;
- error = chown_common(path.dentry, user, group);
+ error = security_path_chown(&path, user, group);
+ if (!error)
+ error = chown_common(path.dentry, user, group);
mnt_drop_write(path.mnt);
out_release:
path_put(&path);
@@ -744,7 +759,9 @@ SYSCALL_DEFINE3(lchown, const char __user *, filename, uid_t, user, gid_t, group
error = mnt_want_write(path.mnt);
if (error)
goto out_release;
- error = chown_common(path.dentry, user, group);
+ error = security_path_chown(&path, user, group);
+ if (!error)
+ error = chown_common(path.dentry, user, group);
mnt_drop_write(path.mnt);
out_release:
path_put(&path);
@@ -767,7 +784,9 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
goto out_fput;
dentry = file->f_path.dentry;
audit_inode(NULL, dentry);
- error = chown_common(dentry, user, group);
+ error = security_path_chown(&file->f_path, user, group);
+ if (!error)
+ error = chown_common(dentry, user, group);
mnt_drop_write(file->f_path.mnt);
out_fput:
fput(file);
@@ -1041,7 +1060,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
put_unused_fd(fd);
fd = PTR_ERR(f);
} else {
- fsnotify_open(f->f_path.dentry);
+ fsnotify_open(f);
fd_install(fd, f);
}
}
diff --git a/fs/pipe.c b/fs/pipe.c
index 52c415114838..ae17d026aaa3 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -777,36 +777,55 @@ pipe_rdwr_release(struct inode *inode, struct file *filp)
static int
pipe_read_open(struct inode *inode, struct file *filp)
{
- /* We could have perhaps used atomic_t, but this and friends
- below are the only places. So it doesn't seem worthwhile. */
+ int ret = -ENOENT;
+
mutex_lock(&inode->i_mutex);
- inode->i_pipe->readers++;
+
+ if (inode->i_pipe) {
+ ret = 0;
+ inode->i_pipe->readers++;
+ }
+
mutex_unlock(&inode->i_mutex);
- return 0;
+ return ret;
}
static int
pipe_write_open(struct inode *inode, struct file *filp)
{
+ int ret = -ENOENT;
+
mutex_lock(&inode->i_mutex);
- inode->i_pipe->writers++;
+
+ if (inode->i_pipe) {
+ ret = 0;
+ inode->i_pipe->writers++;
+ }
+
mutex_unlock(&inode->i_mutex);
- return 0;
+ return ret;
}
static int
pipe_rdwr_open(struct inode *inode, struct file *filp)
{
+ int ret = -ENOENT;
+
mutex_lock(&inode->i_mutex);
- if (filp->f_mode & FMODE_READ)
- inode->i_pipe->readers++;
- if (filp->f_mode & FMODE_WRITE)
- inode->i_pipe->writers++;
+
+ if (inode->i_pipe) {
+ ret = 0;
+ if (filp->f_mode & FMODE_READ)
+ inode->i_pipe->readers++;
+ if (filp->f_mode & FMODE_WRITE)
+ inode->i_pipe->writers++;
+ }
+
mutex_unlock(&inode->i_mutex);
- return 0;
+ return ret;
}
/*
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 07f77a7945c3..e209f64ab27b 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -410,6 +410,16 @@ static void task_show_stack_usage(struct seq_file *m, struct task_struct *task)
}
#endif /* CONFIG_MMU */
+static void task_cpus_allowed(struct seq_file *m, struct task_struct *task)
+{
+ seq_printf(m, "Cpus_allowed:\t");
+ seq_cpumask(m, &task->cpus_allowed);
+ seq_printf(m, "\n");
+ seq_printf(m, "Cpus_allowed_list:\t");
+ seq_cpumask_list(m, &task->cpus_allowed);
+ seq_printf(m, "\n");
+}
+
int proc_pid_status(struct seq_file *m, struct pid_namespace *ns,
struct pid *pid, struct task_struct *task)
{
@@ -424,6 +434,7 @@ int proc_pid_status(struct seq_file *m, struct pid_namespace *ns,
}
task_sig(m, task);
task_cap(m, task);
+ task_cpus_allowed(m, task);
cpuset_task_status_allowed(m, task);
#if defined(CONFIG_S390)
task_show_regs(m, task);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 837469a96598..9701ff56ec01 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -128,6 +128,8 @@ struct pid_entry {
NULL, &proc_single_file_operations, \
{ .proc_show = show } )
+static ssize_t proc_info_read(struct file * file, char __user * buf,
+ size_t count, loff_t *ppos);
/*
* Count the number of hardlinks for the pid_entry table, excluding the .
* and .. links.
@@ -521,6 +523,74 @@ static int proc_pid_limits(struct task_struct *task, char *buffer)
return count;
}
+static ssize_t limits_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
+ char str[32 + 1 + 16 + 1 + 16 + 1], *delim, *next;
+ struct rlimit new_rlimit;
+ unsigned int i;
+ int ret;
+
+ if (!task) {
+ count = -ESRCH;
+ goto out;
+ }
+ if (copy_from_user(str, buf, min(count, sizeof(str) - 1))) {
+ count = -EFAULT;
+ goto put_task;
+ }
+
+ str[min(count, sizeof(str) - 1)] = 0;
+
+ delim = strchr(str, '=');
+ if (!delim) {
+ count = -EINVAL;
+ goto put_task;
+ }
+ *delim++ = 0; /* for easy 'str' usage */
+ new_rlimit.rlim_cur = simple_strtoul(delim, &next, 0);
+ if (*next != ':') {
+ if (strncmp(delim, "unlimited:", 10)) {
+ count = -EINVAL;
+ goto put_task;
+ }
+ new_rlimit.rlim_cur = RLIM_INFINITY;
+ next = delim + 9; /* move to ':' */
+ }
+ delim = next + 1;
+ new_rlimit.rlim_max = simple_strtoul(delim, &next, 0);
+ if (*next != 0) {
+ if (strcmp(delim, "unlimited")) {
+ count = -EINVAL;
+ goto put_task;
+ }
+ new_rlimit.rlim_max = RLIM_INFINITY;
+ }
+
+ for (i = 0; i < RLIM_NLIMITS; i++)
+ if (!strcmp(str, lnames[i].name))
+ break;
+ if (i >= RLIM_NLIMITS) {
+ count = -EINVAL;
+ goto put_task;
+ }
+
+ ret = setrlimit(task, i, &new_rlimit);
+ if (ret)
+ count = ret;
+
+put_task:
+ put_task_struct(task);
+out:
+ return count;
+}
+
+static const struct file_operations proc_pid_limits_operations = {
+ .read = proc_info_read,
+ .write = limits_write,
+};
+
#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
static int proc_pid_syscall(struct task_struct *task, char *buffer)
{
@@ -2500,7 +2570,9 @@ static const struct pid_entry tgid_base_stuff[] = {
INF("auxv", S_IRUSR, proc_pid_auxv),
ONE("status", S_IRUGO, proc_pid_status),
ONE("personality", S_IRUSR, proc_pid_personality),
- INF("limits", S_IRUSR, proc_pid_limits),
+ NOD("limits", S_IFREG|S_IRUSR|S_IWUSR, NULL,
+ &proc_pid_limits_operations,
+ { .proc_read = proc_pid_limits }),
#ifdef CONFIG_SCHED_DEBUG
REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations),
#endif
@@ -2835,7 +2907,9 @@ static const struct pid_entry tid_base_stuff[] = {
INF("auxv", S_IRUSR, proc_pid_auxv),
ONE("status", S_IRUGO, proc_pid_status),
ONE("personality", S_IRUSR, proc_pid_personality),
- INF("limits", S_IRUSR, proc_pid_limits),
+ NOD("limits", S_IFREG|S_IRUSR|S_IWUSR, NULL,
+ &proc_pid_limits_operations,
+ { .proc_read = proc_pid_limits }),
#ifdef CONFIG_SCHED_DEBUG
REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations),
#endif
diff --git a/fs/proc/stat.c b/fs/proc/stat.c
index 7cc726c6d70a..b9b7aad2003d 100644
--- a/fs/proc/stat.c
+++ b/fs/proc/stat.c
@@ -27,7 +27,7 @@ static int show_stat(struct seq_file *p, void *v)
int i, j;
unsigned long jif;
cputime64_t user, nice, system, idle, iowait, irq, softirq, steal;
- cputime64_t guest;
+ cputime64_t guest, guest_nice;
u64 sum = 0;
u64 sum_softirq = 0;
unsigned int per_softirq_sums[NR_SOFTIRQS] = {0};
@@ -36,7 +36,7 @@ static int show_stat(struct seq_file *p, void *v)
user = nice = system = idle = iowait =
irq = softirq = steal = cputime64_zero;
- guest = cputime64_zero;
+ guest = guest_nice = cputime64_zero;
getboottime(&boottime);
jif = boottime.tv_sec;
@@ -51,6 +51,8 @@ static int show_stat(struct seq_file *p, void *v)
softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
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);
}
@@ -65,7 +67,8 @@ static int show_stat(struct seq_file *p, void *v)
}
sum += arch_irq_stat();
- seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
+ seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu "
+ "%llu\n",
(unsigned long long)cputime64_to_clock_t(user),
(unsigned long long)cputime64_to_clock_t(nice),
(unsigned long long)cputime64_to_clock_t(system),
@@ -74,7 +77,8 @@ static int show_stat(struct seq_file *p, void *v)
(unsigned long long)cputime64_to_clock_t(irq),
(unsigned long long)cputime64_to_clock_t(softirq),
(unsigned long long)cputime64_to_clock_t(steal),
- (unsigned long long)cputime64_to_clock_t(guest));
+ (unsigned long long)cputime64_to_clock_t(guest),
+ (unsigned long long)cputime64_to_clock_t(guest_nice));
for_each_online_cpu(i) {
/* Copy values here to work around gcc-2.95.3, gcc-2.96 */
@@ -88,8 +92,10 @@ static int show_stat(struct seq_file *p, void *v)
softirq = kstat_cpu(i).cpustat.softirq;
steal = kstat_cpu(i).cpustat.steal;
guest = kstat_cpu(i).cpustat.guest;
+ guest_nice = kstat_cpu(i).cpustat.guest_nice;
seq_printf(p,
- "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
+ "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu "
+ "%llu\n",
i,
(unsigned long long)cputime64_to_clock_t(user),
(unsigned long long)cputime64_to_clock_t(nice),
@@ -99,7 +105,8 @@ static int show_stat(struct seq_file *p, void *v)
(unsigned long long)cputime64_to_clock_t(irq),
(unsigned long long)cputime64_to_clock_t(softirq),
(unsigned long long)cputime64_to_clock_t(steal),
- (unsigned long long)cputime64_to_clock_t(guest));
+ (unsigned long long)cputime64_to_clock_t(guest),
+ (unsigned long long)cputime64_to_clock_t(guest_nice));
}
seq_printf(p, "intr %llu", (unsigned long long)sum);
diff --git a/fs/qnx4/bitmap.c b/fs/qnx4/bitmap.c
index 0afba069d567..32f5d131a644 100644
--- a/fs/qnx4/bitmap.c
+++ b/fs/qnx4/bitmap.c
@@ -67,7 +67,7 @@ unsigned long qnx4_count_free_blocks(struct super_block *sb)
while (total < size) {
if ((bh = sb_bread(sb, start + offset)) == NULL) {
- printk("qnx4: I/O error in counting free blocks\n");
+ printk(KERN_ERR "qnx4: I/O error in counting free blocks\n");
break;
}
count_bits(bh->b_data, size - total, &total_free);
diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c
index 86cc39cb1398..6f30c3d5bcbf 100644
--- a/fs/qnx4/dir.c
+++ b/fs/qnx4/dir.c
@@ -26,8 +26,8 @@ static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir)
int ix, ino;
int size;
- QNX4DEBUG(("qnx4_readdir:i_size = %ld\n", (long) inode->i_size));
- QNX4DEBUG(("filp->f_pos = %ld\n", (long) filp->f_pos));
+ QNX4DEBUG((KERN_INFO "qnx4_readdir:i_size = %ld\n", (long) inode->i_size));
+ QNX4DEBUG((KERN_INFO "filp->f_pos = %ld\n", (long) filp->f_pos));
lock_kernel();
@@ -50,7 +50,7 @@ static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir)
size = QNX4_NAME_MAX;
if ( ( de->di_status & (QNX4_FILE_USED|QNX4_FILE_LINK) ) != 0 ) {
- QNX4DEBUG(("qnx4_readdir:%.*s\n", size, de->di_fname));
+ QNX4DEBUG((KERN_INFO "qnx4_readdir:%.*s\n", size, de->di_fname));
if ( ( de->di_status & QNX4_FILE_LINK ) == 0 )
ino = blknum * QNX4_INODES_PER_BLOCK + ix - 1;
else {
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index d2cd1798d8c4..449f5a66dd34 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -107,7 +107,7 @@ static int qnx4_get_block( struct inode *inode, sector_t iblock, struct buffer_h
{
unsigned long phys;
- QNX4DEBUG(("qnx4: qnx4_get_block inode=[%ld] iblock=[%ld]\n",inode->i_ino,iblock));
+ QNX4DEBUG((KERN_INFO "qnx4: qnx4_get_block inode=[%ld] iblock=[%ld]\n",inode->i_ino,iblock));
phys = qnx4_block_map( inode, iblock );
if ( phys ) {
@@ -142,12 +142,12 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock )
// read next xtnt block.
bh = sb_bread(inode->i_sb, i_xblk - 1);
if ( !bh ) {
- QNX4DEBUG(("qnx4: I/O error reading xtnt block [%ld])\n", i_xblk - 1));
+ QNX4DEBUG((KERN_ERR "qnx4: I/O error reading xtnt block [%ld])\n", i_xblk - 1));
return -EIO;
}
xblk = (struct qnx4_xblk*)bh->b_data;
if ( memcmp( xblk->xblk_signature, "IamXblk", 7 ) ) {
- QNX4DEBUG(("qnx4: block at %ld is not a valid xtnt\n", qnx4_inode->i_xblk));
+ QNX4DEBUG((KERN_ERR "qnx4: block at %ld is not a valid xtnt\n", qnx4_inode->i_xblk));
return -EIO;
}
}
@@ -168,7 +168,7 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock )
brelse( bh );
}
- QNX4DEBUG(("qnx4: mapping block %ld of inode %ld = %ld\n",iblock,inode->i_ino,block));
+ QNX4DEBUG((KERN_INFO "qnx4: mapping block %ld of inode %ld = %ld\n",iblock,inode->i_ino,block));
return block;
}
@@ -209,7 +209,7 @@ static const char *qnx4_checkroot(struct super_block *sb)
if (*(qnx4_sb(sb)->sb->RootDir.di_fname) != '/') {
return "no qnx4 filesystem (no root dir).";
} else {
- QNX4DEBUG(("QNX4 filesystem found on dev %s.\n", sb->s_id));
+ QNX4DEBUG((KERN_NOTICE "QNX4 filesystem found on dev %s.\n", sb->s_id));
rd = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_blk) - 1;
rl = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_size);
for (j = 0; j < rl; j++) {
@@ -220,7 +220,7 @@ static const char *qnx4_checkroot(struct super_block *sb)
for (i = 0; i < QNX4_INODES_PER_BLOCK; i++) {
rootdir = (struct qnx4_inode_entry *) (bh->b_data + i * QNX4_DIR_ENTRY_SIZE);
if (rootdir->di_fname != NULL) {
- QNX4DEBUG(("Rootdir entry found : [%s]\n", rootdir->di_fname));
+ QNX4DEBUG((KERN_INFO "rootdir entry found : [%s]\n", rootdir->di_fname));
if (!strncmp(rootdir->di_fname, QNX4_BMNAME, sizeof QNX4_BMNAME)) {
found = 1;
qnx4_sb(sb)->BitMap = kmalloc( sizeof( struct qnx4_inode_entry ), GFP_KERNEL );
@@ -265,12 +265,12 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
if we don't belong here... */
bh = sb_bread(s, 1);
if (!bh) {
- printk("qnx4: unable to read the superblock\n");
+ printk(KERN_ERR "qnx4: unable to read the superblock\n");
goto outnobh;
}
if ( le32_to_cpup((__le32*) bh->b_data) != QNX4_SUPER_MAGIC ) {
if (!silent)
- printk("qnx4: wrong fsid in superblock.\n");
+ printk(KERN_ERR "qnx4: wrong fsid in superblock.\n");
goto out;
}
s->s_op = &qnx4_sops;
@@ -284,14 +284,14 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
errmsg = qnx4_checkroot(s);
if (errmsg != NULL) {
if (!silent)
- printk("qnx4: %s\n", errmsg);
+ printk(KERN_ERR "qnx4: %s\n", errmsg);
goto out;
}
/* does root not have inode number QNX4_ROOT_INO ?? */
root = qnx4_iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK);
if (IS_ERR(root)) {
- printk("qnx4: get inode failed\n");
+ printk(KERN_ERR "qnx4: get inode failed\n");
ret = PTR_ERR(root);
goto out;
}
@@ -374,7 +374,7 @@ struct inode *qnx4_iget(struct super_block *sb, unsigned long ino)
qnx4_inode = qnx4_raw_inode(inode);
inode->i_mode = 0;
- QNX4DEBUG(("Reading inode : [%d]\n", ino));
+ QNX4DEBUG((KERN_INFO "reading inode : [%d]\n", ino));
if (!ino) {
printk(KERN_ERR "qnx4: bad inode number on dev %s: %lu is "
"out of range\n",
@@ -385,7 +385,7 @@ struct inode *qnx4_iget(struct super_block *sb, unsigned long ino)
block = ino / QNX4_INODES_PER_BLOCK;
if (!(bh = sb_bread(sb, block))) {
- printk("qnx4: major problem: unable to read inode from dev "
+ printk(KERN_ERR "qnx4: major problem: unable to read inode from dev "
"%s\n", sb->s_id);
iget_failed(inode);
return ERR_PTR(-EIO);
@@ -499,7 +499,7 @@ static int __init init_qnx4_fs(void)
return err;
}
- printk("QNX4 filesystem 0.2.3 registered.\n");
+ printk(KERN_INFO "QNX4 filesystem 0.2.3 registered.\n");
return 0;
}
diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c
index ae1e7edbacd6..58703ebba879 100644
--- a/fs/qnx4/namei.c
+++ b/fs/qnx4/namei.c
@@ -30,7 +30,7 @@ static int qnx4_match(int len, const char *name,
int namelen, thislen;
if (bh == NULL) {
- printk("qnx4: matching unassigned buffer !\n");
+ printk(KERN_WARNING "qnx4: matching unassigned buffer !\n");
return 0;
}
de = (struct qnx4_inode_entry *) (bh->b_data + *offset);
@@ -66,7 +66,7 @@ static struct buffer_head *qnx4_find_entry(int len, struct inode *dir,
*res_dir = NULL;
if (!dir->i_sb) {
- printk("qnx4: no superblock on dir.\n");
+ printk(KERN_WARNING "qnx4: no superblock on dir.\n");
return NULL;
}
bh = NULL;
@@ -124,7 +124,7 @@ struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, struct nam
foundinode = qnx4_iget(dir->i_sb, ino);
if (IS_ERR(foundinode)) {
unlock_kernel();
- QNX4DEBUG(("qnx4: lookup->iget -> error %ld\n",
+ QNX4DEBUG((KERN_ERR "qnx4: lookup->iget -> error %ld\n",
PTR_ERR(foundinode)));
return ERR_CAST(foundinode);
}
diff --git a/fs/quota/Kconfig b/fs/quota/Kconfig
index 8047e01ef46b..353e78a9ebee 100644
--- a/fs/quota/Kconfig
+++ b/fs/quota/Kconfig
@@ -17,7 +17,7 @@ config QUOTA
config QUOTA_NETLINK_INTERFACE
bool "Report quota messages through netlink interface"
- depends on QUOTA && NET
+ depends on QUOTACTL && NET
help
If you say Y here, quota warnings (about exceeding softlimit, reaching
hardlimit, etc.) will be reported through netlink interface. If unsure,
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 39b49c42a7ed..9b6ad908dcb2 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -77,10 +77,6 @@
#include <linux/capability.h>
#include <linux/quotaops.h>
#include <linux/writeback.h> /* for inode_lock, oddly enough.. */
-#ifdef CONFIG_QUOTA_NETLINK_INTERFACE
-#include <net/netlink.h>
-#include <net/genetlink.h>
-#endif
#include <asm/uaccess.h>
@@ -1071,73 +1067,6 @@ static void print_warning(struct dquot *dquot, const int warntype)
}
#endif
-#ifdef CONFIG_QUOTA_NETLINK_INTERFACE
-
-/* Netlink family structure for quota */
-static struct genl_family quota_genl_family = {
- .id = GENL_ID_GENERATE,
- .hdrsize = 0,
- .name = "VFS_DQUOT",
- .version = 1,
- .maxattr = QUOTA_NL_A_MAX,
-};
-
-/* Send warning to userspace about user which exceeded quota */
-static void send_warning(const struct dquot *dquot, const char warntype)
-{
- static atomic_t seq;
- struct sk_buff *skb;
- void *msg_head;
- int ret;
- int msg_size = 4 * nla_total_size(sizeof(u32)) +
- 2 * nla_total_size(sizeof(u64));
-
- /* We have to allocate using GFP_NOFS as we are called from a
- * filesystem performing write and thus further recursion into
- * the fs to free some data could cause deadlocks. */
- skb = genlmsg_new(msg_size, GFP_NOFS);
- if (!skb) {
- printk(KERN_ERR
- "VFS: Not enough memory to send quota warning.\n");
- return;
- }
- msg_head = genlmsg_put(skb, 0, atomic_add_return(1, &seq),
- &quota_genl_family, 0, QUOTA_NL_C_WARNING);
- if (!msg_head) {
- printk(KERN_ERR
- "VFS: Cannot store netlink header in quota warning.\n");
- goto err_out;
- }
- ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, dquot->dq_type);
- if (ret)
- goto attr_err_out;
- ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, dquot->dq_id);
- if (ret)
- goto attr_err_out;
- ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype);
- if (ret)
- goto attr_err_out;
- ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MAJOR,
- MAJOR(dquot->dq_sb->s_dev));
- if (ret)
- goto attr_err_out;
- ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR,
- MINOR(dquot->dq_sb->s_dev));
- if (ret)
- goto attr_err_out;
- ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid());
- if (ret)
- goto attr_err_out;
- genlmsg_end(skb, msg_head);
-
- genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS);
- return;
-attr_err_out:
- printk(KERN_ERR "VFS: Not enough space to compose quota message!\n");
-err_out:
- kfree_skb(skb);
-}
-#endif
/*
* Write warnings to the console and send warning messages over netlink.
*
@@ -1145,18 +1074,20 @@ err_out:
*/
static void flush_warnings(struct dquot *const *dquots, char *warntype)
{
+ struct dquot *dq;
int i;
- for (i = 0; i < MAXQUOTAS; i++)
- if (dquots[i] && warntype[i] != QUOTA_NL_NOWARN &&
- !warning_issued(dquots[i], warntype[i])) {
+ for (i = 0; i < MAXQUOTAS; i++) {
+ dq = dquots[i];
+ if (dq && warntype[i] != QUOTA_NL_NOWARN &&
+ !warning_issued(dq, warntype[i])) {
#ifdef CONFIG_PRINT_QUOTA_WARNING
- print_warning(dquots[i], warntype[i]);
-#endif
-#ifdef CONFIG_QUOTA_NETLINK_INTERFACE
- send_warning(dquots[i], warntype[i]);
+ print_warning(dq, warntype[i]);
#endif
+ quota_send_warning(dq->dq_type, dq->dq_id,
+ dq->dq_sb->s_dev, warntype[i]);
}
+ }
}
static int ignore_hardlimit(struct dquot *dquot)
@@ -2607,12 +2538,6 @@ static int __init dquot_init(void)
register_shrinker(&dqcache_shrinker);
-#ifdef CONFIG_QUOTA_NETLINK_INTERFACE
- if (genl_register_family(&quota_genl_family) != 0)
- printk(KERN_ERR
- "VFS: Failed to create quota netlink interface.\n");
-#endif
-
return 0;
}
module_init(dquot_init);
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 95c5b42384b2..ee91e2756950 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -18,6 +18,8 @@
#include <linux/capability.h>
#include <linux/quotaops.h>
#include <linux/types.h>
+#include <net/netlink.h>
+#include <net/genetlink.h>
/* Check validity of generic quotactl commands */
static int generic_quotactl_valid(struct super_block *sb, int type, int cmd,
@@ -525,3 +527,94 @@ asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special,
return ret;
}
#endif
+
+
+#ifdef CONFIG_QUOTA_NETLINK_INTERFACE
+
+/* Netlink family structure for quota */
+static struct genl_family quota_genl_family = {
+ .id = GENL_ID_GENERATE,
+ .hdrsize = 0,
+ .name = "VFS_DQUOT",
+ .version = 1,
+ .maxattr = QUOTA_NL_A_MAX,
+};
+
+/**
+ * quota_send_warning - Send warning to userspace about exceeded quota
+ * @type: The quota type: USRQQUOTA, GRPQUOTA,...
+ * @id: The user or group id of the quota that was exceeded
+ * @dev: The device on which the fs is mounted (sb->s_dev)
+ * @warntype: The type of the warning: QUOTA_NL_...
+ *
+ * This can be used by filesystems (including those which don't use
+ * dquot) to send a message to userspace relating to quota limits.
+ *
+ */
+
+void quota_send_warning(short type, unsigned int id, dev_t dev,
+ const char warntype)
+{
+ static atomic_t seq;
+ struct sk_buff *skb;
+ void *msg_head;
+ int ret;
+ int msg_size = 4 * nla_total_size(sizeof(u32)) +
+ 2 * nla_total_size(sizeof(u64));
+
+ /* We have to allocate using GFP_NOFS as we are called from a
+ * filesystem performing write and thus further recursion into
+ * the fs to free some data could cause deadlocks. */
+ skb = genlmsg_new(msg_size, GFP_NOFS);
+ if (!skb) {
+ printk(KERN_ERR
+ "VFS: Not enough memory to send quota warning.\n");
+ return;
+ }
+ msg_head = genlmsg_put(skb, 0, atomic_add_return(1, &seq),
+ &quota_genl_family, 0, QUOTA_NL_C_WARNING);
+ if (!msg_head) {
+ printk(KERN_ERR
+ "VFS: Cannot store netlink header in quota warning.\n");
+ goto err_out;
+ }
+ ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, type);
+ if (ret)
+ goto attr_err_out;
+ ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, id);
+ if (ret)
+ goto attr_err_out;
+ ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype);
+ if (ret)
+ goto attr_err_out;
+ ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MAJOR, MAJOR(dev));
+ if (ret)
+ goto attr_err_out;
+ ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, MINOR(dev));
+ if (ret)
+ goto attr_err_out;
+ ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid());
+ if (ret)
+ goto attr_err_out;
+ genlmsg_end(skb, msg_head);
+
+ genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS);
+ return;
+attr_err_out:
+ printk(KERN_ERR "VFS: Not enough space to compose quota message!\n");
+err_out:
+ kfree_skb(skb);
+}
+EXPORT_SYMBOL(quota_send_warning);
+
+static int __init quota_init(void)
+{
+ if (genl_register_family(&quota_genl_family) != 0)
+ printk(KERN_ERR
+ "VFS: Failed to create quota netlink interface.\n");
+ return 0;
+};
+
+module_init(quota_init);
+#endif
+
diff --git a/fs/read_write.c b/fs/read_write.c
index 3ac28987f22a..0ddf1626e202 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -293,7 +293,7 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
else
ret = do_sync_read(file, buf, count, pos);
if (ret > 0) {
- fsnotify_access(file->f_path.dentry);
+ fsnotify_access(file);
add_rchar(current, ret);
}
inc_syscr(current);
@@ -348,7 +348,7 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_
else
ret = do_sync_write(file, buf, count, pos);
if (ret > 0) {
- fsnotify_modify(file->f_path.dentry);
+ fsnotify_modify(file);
add_wchar(current, ret);
}
inc_syscw(current);
@@ -656,9 +656,9 @@ out:
kfree(iov);
if ((ret + (type == READ)) > 0) {
if (type == READ)
- fsnotify_access(file->f_path.dentry);
+ fsnotify_access(file);
else
- fsnotify_modify(file->f_path.dentry);
+ fsnotify_modify(file);
}
return ret;
}
diff --git a/fs/reiserfs/Makefile b/fs/reiserfs/Makefile
index 7c5ab6330dd6..6a9e30c041dd 100644
--- a/fs/reiserfs/Makefile
+++ b/fs/reiserfs/Makefile
@@ -7,7 +7,7 @@ obj-$(CONFIG_REISERFS_FS) += reiserfs.o
reiserfs-objs := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o \
super.o prints.o objectid.o lbalance.o ibalance.o stree.o \
hashes.o tail_conversion.o journal.o resize.o \
- item_ops.o ioctl.o procfs.o xattr.o
+ item_ops.o ioctl.o procfs.o xattr.o lock.o
ifeq ($(CONFIG_REISERFS_FS_XATTR),y)
reiserfs-objs += xattr_user.o xattr_trusted.o
diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c
index e716161ab325..685495707181 100644
--- a/fs/reiserfs/bitmap.c
+++ b/fs/reiserfs/bitmap.c
@@ -1249,14 +1249,18 @@ struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb,
else if (bitmap == 0)
block = (REISERFS_DISK_OFFSET_IN_BYTES >> sb->s_blocksize_bits) + 1;
+ reiserfs_write_unlock(sb);
bh = sb_bread(sb, block);
+ reiserfs_write_lock(sb);
if (bh == NULL)
reiserfs_warning(sb, "sh-2029: %s: bitmap block (#%u) "
"reading failed", __func__, block);
else {
if (buffer_locked(bh)) {
PROC_INFO_INC(sb, scan_bitmap.wait);
+ reiserfs_write_unlock(sb);
__wait_on_buffer(bh);
+ reiserfs_write_lock(sb);
}
BUG_ON(!buffer_uptodate(bh));
BUG_ON(atomic_read(&bh->b_count) == 0);
diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
index 6d2668fdc384..c094f58c7448 100644
--- a/fs/reiserfs/dir.c
+++ b/fs/reiserfs/dir.c
@@ -20,7 +20,7 @@ const struct file_operations reiserfs_dir_operations = {
.read = generic_read_dir,
.readdir = reiserfs_readdir,
.fsync = reiserfs_dir_fsync,
- .ioctl = reiserfs_ioctl,
+ .unlocked_ioctl = reiserfs_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = reiserfs_compat_ioctl,
#endif
@@ -174,14 +174,22 @@ int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent,
// user space buffer is swapped out. At that time
// entry can move to somewhere else
memcpy(local_buf, d_name, d_reclen);
+
+ /*
+ * Since filldir might sleep, we can release
+ * the write lock here for other waiters
+ */
+ reiserfs_write_unlock(inode->i_sb);
if (filldir
(dirent, local_buf, d_reclen, d_off, d_ino,
DT_UNKNOWN) < 0) {
+ reiserfs_write_lock(inode->i_sb);
if (local_buf != small_buf) {
kfree(local_buf);
}
goto end;
}
+ reiserfs_write_lock(inode->i_sb);
if (local_buf != small_buf) {
kfree(local_buf);
}
diff --git a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c
index 128d3f7c8aa5..60c080440661 100644
--- a/fs/reiserfs/do_balan.c
+++ b/fs/reiserfs/do_balan.c
@@ -21,14 +21,6 @@
#include <linux/buffer_head.h>
#include <linux/kernel.h>
-#ifdef CONFIG_REISERFS_CHECK
-
-struct tree_balance *cur_tb = NULL; /* detects whether more than one
- copy of tb exists as a means
- of checking whether schedule
- is interrupting do_balance */
-#endif
-
static inline void buffer_info_init_left(struct tree_balance *tb,
struct buffer_info *bi)
{
@@ -1840,11 +1832,12 @@ static int check_before_balancing(struct tree_balance *tb)
{
int retval = 0;
- if (cur_tb) {
+ if (REISERFS_SB(tb->tb_sb)->cur_tb) {
reiserfs_panic(tb->tb_sb, "vs-12335", "suspect that schedule "
"occurred based on cur_tb not being null at "
"this point in code. do_balance cannot properly "
- "handle schedule occurring while it runs.");
+ "handle concurrent tree accesses on a same "
+ "mount point.");
}
/* double check that buffers that we will modify are unlocked. (fix_nodes should already have
@@ -1986,7 +1979,7 @@ static inline void do_balance_starts(struct tree_balance *tb)
"check");*/
RFALSE(check_before_balancing(tb), "PAP-12340: locked buffers in TB");
#ifdef CONFIG_REISERFS_CHECK
- cur_tb = tb;
+ REISERFS_SB(tb->tb_sb)->cur_tb = tb;
#endif
}
@@ -1996,7 +1989,7 @@ static inline void do_balance_completed(struct tree_balance *tb)
#ifdef CONFIG_REISERFS_CHECK
check_leaf_level(tb);
check_internal_levels(tb);
- cur_tb = NULL;
+ REISERFS_SB(tb->tb_sb)->cur_tb = NULL;
#endif
/* reiserfs_free_block is no longer schedule safe. So, we need to
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index 9f436668b7f8..da2dba082e2d 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -284,7 +284,7 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t
const struct file_operations reiserfs_file_operations = {
.read = do_sync_read,
.write = reiserfs_file_write,
- .ioctl = reiserfs_ioctl,
+ .unlocked_ioctl = reiserfs_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = reiserfs_compat_ioctl,
#endif
diff --git a/fs/reiserfs/fix_node.c b/fs/reiserfs/fix_node.c
index 5e5a4e6fbaf8..d2f31330dcae 100644
--- a/fs/reiserfs/fix_node.c
+++ b/fs/reiserfs/fix_node.c
@@ -563,9 +563,6 @@ static int get_num_ver(int mode, struct tree_balance *tb, int h,
return needed_nodes;
}
-#ifdef CONFIG_REISERFS_CHECK
-extern struct tree_balance *cur_tb;
-#endif
/* Set parameters for balancing.
* Performs write of results of analysis of balancing into structure tb,
@@ -1022,7 +1019,11 @@ static int get_far_parent(struct tree_balance *tb,
/* Check whether the common parent is locked. */
if (buffer_locked(*pcom_father)) {
+
+ /* Release the write lock while the buffer is busy */
+ reiserfs_write_unlock(tb->tb_sb);
__wait_on_buffer(*pcom_father);
+ reiserfs_write_lock(tb->tb_sb);
if (FILESYSTEM_CHANGED_TB(tb)) {
brelse(*pcom_father);
return REPEAT_SEARCH;
@@ -1927,7 +1928,9 @@ static int get_direct_parent(struct tree_balance *tb, int h)
return REPEAT_SEARCH;
if (buffer_locked(bh)) {
+ reiserfs_write_unlock(tb->tb_sb);
__wait_on_buffer(bh);
+ reiserfs_write_lock(tb->tb_sb);
if (FILESYSTEM_CHANGED_TB(tb))
return REPEAT_SEARCH;
}
@@ -1965,7 +1968,9 @@ static int get_neighbors(struct tree_balance *tb, int h)
tb->FL[h]) ? tb->lkey[h] : B_NR_ITEMS(tb->
FL[h]);
son_number = B_N_CHILD_NUM(tb->FL[h], child_position);
+ reiserfs_write_unlock(sb);
bh = sb_bread(sb, son_number);
+ reiserfs_write_lock(sb);
if (!bh)
return IO_ERROR;
if (FILESYSTEM_CHANGED_TB(tb)) {
@@ -2003,7 +2008,9 @@ static int get_neighbors(struct tree_balance *tb, int h)
child_position =
(bh == tb->FR[h]) ? tb->rkey[h] + 1 : 0;
son_number = B_N_CHILD_NUM(tb->FR[h], child_position);
+ reiserfs_write_unlock(sb);
bh = sb_bread(sb, son_number);
+ reiserfs_write_lock(sb);
if (!bh)
return IO_ERROR;
if (FILESYSTEM_CHANGED_TB(tb)) {
@@ -2278,7 +2285,9 @@ static int wait_tb_buffers_until_unlocked(struct tree_balance *tb)
REPEAT_SEARCH : CARRY_ON;
}
#endif
+ reiserfs_write_unlock(tb->tb_sb);
__wait_on_buffer(locked);
+ reiserfs_write_lock(tb->tb_sb);
if (FILESYSTEM_CHANGED_TB(tb))
return REPEAT_SEARCH;
}
@@ -2349,12 +2358,14 @@ int fix_nodes(int op_mode, struct tree_balance *tb,
/* if it possible in indirect_to_direct conversion */
if (buffer_locked(tbS0)) {
+ reiserfs_write_unlock(tb->tb_sb);
__wait_on_buffer(tbS0);
+ reiserfs_write_lock(tb->tb_sb);
if (FILESYSTEM_CHANGED_TB(tb))
return REPEAT_SEARCH;
}
#ifdef CONFIG_REISERFS_CHECK
- if (cur_tb) {
+ if (REISERFS_SB(tb->tb_sb)->cur_tb) {
print_cur_tb("fix_nodes");
reiserfs_panic(tb->tb_sb, "PAP-8305",
"there is pending do_balance");
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index a14d6cd9eeda..0d493a3bb749 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -251,7 +251,6 @@ static int _get_block_create_0(struct inode *inode, sector_t block,
struct cpu_key key;
struct buffer_head *bh;
struct item_head *ih, tmp_ih;
- int fs_gen;
b_blocknr_t blocknr;
char *p = NULL;
int chars;
@@ -265,7 +264,6 @@ static int _get_block_create_0(struct inode *inode, sector_t block,
(loff_t) block * inode->i_sb->s_blocksize + 1, TYPE_ANY,
3);
- research:
result = search_for_position_by_key(inode->i_sb, &key, &path);
if (result != POSITION_FOUND) {
pathrelse(&path);
@@ -340,7 +338,6 @@ static int _get_block_create_0(struct inode *inode, sector_t block,
}
// read file tail into part of page
offset = (cpu_key_k_offset(&key) - 1) & (PAGE_CACHE_SIZE - 1);
- fs_gen = get_generation(inode->i_sb);
copy_item_head(&tmp_ih, ih);
/* we only want to kmap if we are reading the tail into the page.
@@ -348,13 +345,9 @@ static int _get_block_create_0(struct inode *inode, sector_t block,
** sure we need to. But, this means the item might move if
** kmap schedules
*/
- if (!p) {
+ if (!p)
p = (char *)kmap(bh_result->b_page);
- if (fs_changed(fs_gen, inode->i_sb)
- && item_moved(&tmp_ih, &path)) {
- goto research;
- }
- }
+
p += offset;
memset(p, 0, inode->i_sb->s_blocksize);
do {
@@ -489,10 +482,14 @@ static int reiserfs_get_blocks_direct_io(struct inode *inode,
disappeared */
if (REISERFS_I(inode)->i_flags & i_pack_on_close_mask) {
int err;
- lock_kernel();
+
+ reiserfs_write_lock(inode->i_sb);
+
err = reiserfs_commit_for_inode(inode);
REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask;
- unlock_kernel();
+
+ reiserfs_write_unlock(inode->i_sb);
+
if (err < 0)
ret = err;
}
@@ -601,6 +598,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
__le32 *item;
int done;
int fs_gen;
+ int lock_depth;
struct reiserfs_transaction_handle *th = NULL;
/* space reserved in transaction batch:
. 3 balancings in direct->indirect conversion
@@ -616,12 +614,11 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
loff_t new_offset =
(((loff_t) block) << inode->i_sb->s_blocksize_bits) + 1;
- /* bad.... */
- reiserfs_write_lock(inode->i_sb);
+ lock_depth = reiserfs_write_lock_once(inode->i_sb);
version = get_inode_item_key_version(inode);
if (!file_capable(inode, block)) {
- reiserfs_write_unlock(inode->i_sb);
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
return -EFBIG;
}
@@ -633,7 +630,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
/* find number of block-th logical block of the file */
ret = _get_block_create_0(inode, block, bh_result,
create | GET_BLOCK_READ_DIRECT);
- reiserfs_write_unlock(inode->i_sb);
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
return ret;
}
/*
@@ -751,7 +748,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
if (!dangle && th)
retval = reiserfs_end_persistent_transaction(th);
- reiserfs_write_unlock(inode->i_sb);
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
/* the item was found, so new blocks were not added to the file
** there is no need to make sure the inode is updated with this
@@ -997,10 +994,16 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
if (retval)
goto failure;
}
- /* inserting indirect pointers for a hole can take a
- ** long time. reschedule if needed
+ /*
+ * inserting indirect pointers for a hole can take a
+ * long time. reschedule if needed and also release the write
+ * lock for others.
*/
- cond_resched();
+ if (need_resched()) {
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
+ schedule();
+ lock_depth = reiserfs_write_lock_once(inode->i_sb);
+ }
retval = search_for_position_by_key(inode->i_sb, &key, &path);
if (retval == IO_ERROR) {
@@ -1035,7 +1038,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
retval = err;
}
- reiserfs_write_unlock(inode->i_sb);
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
reiserfs_check_path(&path);
return retval;
}
@@ -2072,8 +2075,9 @@ int reiserfs_truncate_file(struct inode *inode, int update_timestamps)
int error;
struct buffer_head *bh = NULL;
int err2;
+ int lock_depth;
- reiserfs_write_lock(inode->i_sb);
+ lock_depth = reiserfs_write_lock_once(inode->i_sb);
if (inode->i_size > 0) {
error = grab_tail_page(inode, &page, &bh);
@@ -2142,14 +2146,17 @@ int reiserfs_truncate_file(struct inode *inode, int update_timestamps)
page_cache_release(page);
}
- reiserfs_write_unlock(inode->i_sb);
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
+
return 0;
out:
if (page) {
unlock_page(page);
page_cache_release(page);
}
- reiserfs_write_unlock(inode->i_sb);
+
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
+
return error;
}
@@ -2608,7 +2615,10 @@ int reiserfs_prepare_write(struct file *f, struct page *page,
int ret;
int old_ref = 0;
+ reiserfs_write_unlock(inode->i_sb);
reiserfs_wait_on_write_block(inode->i_sb);
+ reiserfs_write_lock(inode->i_sb);
+
fix_tail_page_for_writing(page);
if (reiserfs_transaction_running(inode->i_sb)) {
struct reiserfs_transaction_handle *th;
@@ -2664,6 +2674,8 @@ static int reiserfs_write_end(struct file *file, struct address_space *mapping,
int update_sd = 0;
struct reiserfs_transaction_handle *th;
unsigned start;
+ int lock_depth = 0;
+ bool locked = false;
if ((unsigned long)fsdata & AOP_FLAG_CONT_EXPAND)
pos ++;
@@ -2690,9 +2702,11 @@ static int reiserfs_write_end(struct file *file, struct address_space *mapping,
** to do the i_size updates here.
*/
pos += copied;
+
if (pos > inode->i_size) {
struct reiserfs_transaction_handle myth;
- reiserfs_write_lock(inode->i_sb);
+ lock_depth = reiserfs_write_lock_once(inode->i_sb);
+ locked = true;
/* If the file have grown beyond the border where it
can have a tail, unmark it as needing a tail
packing */
@@ -2703,10 +2717,9 @@ static int reiserfs_write_end(struct file *file, struct address_space *mapping,
REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask;
ret = journal_begin(&myth, inode->i_sb, 1);
- if (ret) {
- reiserfs_write_unlock(inode->i_sb);
+ if (ret)
goto journal_error;
- }
+
reiserfs_update_inode_transaction(inode);
inode->i_size = pos;
/*
@@ -2718,34 +2731,36 @@ static int reiserfs_write_end(struct file *file, struct address_space *mapping,
reiserfs_update_sd(&myth, inode);
update_sd = 1;
ret = journal_end(&myth, inode->i_sb, 1);
- reiserfs_write_unlock(inode->i_sb);
if (ret)
goto journal_error;
}
if (th) {
- reiserfs_write_lock(inode->i_sb);
+ if (!locked) {
+ lock_depth = reiserfs_write_lock_once(inode->i_sb);
+ locked = true;
+ }
if (!update_sd)
mark_inode_dirty(inode);
ret = reiserfs_end_persistent_transaction(th);
- reiserfs_write_unlock(inode->i_sb);
if (ret)
goto out;
}
out:
+ if (locked)
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
unlock_page(page);
page_cache_release(page);
return ret == 0 ? copied : ret;
journal_error:
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
+ locked = false;
if (th) {
- reiserfs_write_lock(inode->i_sb);
if (!update_sd)
reiserfs_update_sd(th, inode);
ret = reiserfs_end_persistent_transaction(th);
- reiserfs_write_unlock(inode->i_sb);
}
-
goto out;
}
@@ -2758,7 +2773,10 @@ int reiserfs_commit_write(struct file *f, struct page *page,
int update_sd = 0;
struct reiserfs_transaction_handle *th = NULL;
+ reiserfs_write_unlock(inode->i_sb);
reiserfs_wait_on_write_block(inode->i_sb);
+ reiserfs_write_lock(inode->i_sb);
+
if (reiserfs_transaction_running(inode->i_sb)) {
th = current->journal_info;
}
@@ -2770,7 +2788,6 @@ int reiserfs_commit_write(struct file *f, struct page *page,
*/
if (pos > inode->i_size) {
struct reiserfs_transaction_handle myth;
- reiserfs_write_lock(inode->i_sb);
/* If the file have grown beyond the border where it
can have a tail, unmark it as needing a tail
packing */
@@ -2781,10 +2798,9 @@ int reiserfs_commit_write(struct file *f, struct page *page,
REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask;
ret = journal_begin(&myth, inode->i_sb, 1);
- if (ret) {
- reiserfs_write_unlock(inode->i_sb);
+ if (ret)
goto journal_error;
- }
+
reiserfs_update_inode_transaction(inode);
inode->i_size = pos;
/*
@@ -2796,16 +2812,13 @@ int reiserfs_commit_write(struct file *f, struct page *page,
reiserfs_update_sd(&myth, inode);
update_sd = 1;
ret = journal_end(&myth, inode->i_sb, 1);
- reiserfs_write_unlock(inode->i_sb);
if (ret)
goto journal_error;
}
if (th) {
- reiserfs_write_lock(inode->i_sb);
if (!update_sd)
mark_inode_dirty(inode);
ret = reiserfs_end_persistent_transaction(th);
- reiserfs_write_unlock(inode->i_sb);
if (ret)
goto out;
}
@@ -2815,11 +2828,9 @@ int reiserfs_commit_write(struct file *f, struct page *page,
journal_error:
if (th) {
- reiserfs_write_lock(inode->i_sb);
if (!update_sd)
reiserfs_update_sd(th, inode);
ret = reiserfs_end_persistent_transaction(th);
- reiserfs_write_unlock(inode->i_sb);
}
return ret;
diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c
index 0ccc3fdda7bf..ace77451ceb1 100644
--- a/fs/reiserfs/ioctl.c
+++ b/fs/reiserfs/ioctl.c
@@ -13,44 +13,52 @@
#include <linux/compat.h>
/*
-** reiserfs_ioctl - handler for ioctl for inode
-** supported commands:
-** 1) REISERFS_IOC_UNPACK - try to unpack tail from direct item into indirect
-** and prevent packing file (argument arg has to be non-zero)
-** 2) REISERFS_IOC_[GS]ETFLAGS, REISERFS_IOC_[GS]ETVERSION
-** 3) That's all for a while ...
-*/
-int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+ * reiserfs_ioctl - handler for ioctl for inode
+ * supported commands:
+ * 1) REISERFS_IOC_UNPACK - try to unpack tail from direct item into indirect
+ * and prevent packing file (argument arg has to be non-zero)
+ * 2) REISERFS_IOC_[GS]ETFLAGS, REISERFS_IOC_[GS]ETVERSION
+ * 3) That's all for a while ...
+ */
+long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
+ struct inode *inode = filp->f_path.dentry->d_inode;
unsigned int flags;
int err = 0;
+ reiserfs_write_lock(inode->i_sb);
+
switch (cmd) {
case REISERFS_IOC_UNPACK:
if (S_ISREG(inode->i_mode)) {
if (arg)
- return reiserfs_unpack(inode, filp);
- else
- return 0;
+ err = reiserfs_unpack(inode, filp);
} else
- return -ENOTTY;
- /* following two cases are taken from fs/ext2/ioctl.c by Remy
- Card (card@masi.ibp.fr) */
+ err = -ENOTTY;
+ break;
+ /*
+ * following two cases are taken from fs/ext2/ioctl.c by Remy
+ * Card (card@masi.ibp.fr)
+ */
case REISERFS_IOC_GETFLAGS:
- if (!reiserfs_attrs(inode->i_sb))
- return -ENOTTY;
+ if (!reiserfs_attrs(inode->i_sb)) {
+ err = -ENOTTY;
+ break;
+ }
flags = REISERFS_I(inode)->i_attrs;
i_attrs_to_sd_attrs(inode, (__u16 *) & flags);
- return put_user(flags, (int __user *)arg);
+ err = put_user(flags, (int __user *)arg);
+ break;
case REISERFS_IOC_SETFLAGS:{
- if (!reiserfs_attrs(inode->i_sb))
- return -ENOTTY;
+ if (!reiserfs_attrs(inode->i_sb)) {
+ err = -ENOTTY;
+ break;
+ }
err = mnt_want_write(filp->f_path.mnt);
if (err)
- return err;
+ break;
if (!is_owner_or_cap(inode)) {
err = -EPERM;
@@ -90,16 +98,18 @@ int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
mark_inode_dirty(inode);
setflags_out:
mnt_drop_write(filp->f_path.mnt);
- return err;
+ break;
}
case REISERFS_IOC_GETVERSION:
- return put_user(inode->i_generation, (int __user *)arg);
+ err = put_user(inode->i_generation, (int __user *)arg);
+ break;
case REISERFS_IOC_SETVERSION:
if (!is_owner_or_cap(inode))
- return -EPERM;
+ err = -EPERM;
+ break;
err = mnt_want_write(filp->f_path.mnt);
if (err)
- return err;
+ break;
if (get_user(inode->i_generation, (int __user *)arg)) {
err = -EFAULT;
goto setversion_out;
@@ -108,19 +118,20 @@ setflags_out:
mark_inode_dirty(inode);
setversion_out:
mnt_drop_write(filp->f_path.mnt);
- return err;
+ break;
default:
- return -ENOTTY;
+ err = -ENOTTY;
}
+
+ reiserfs_write_unlock(inode->i_sb);
+
+ return err;
}
#ifdef CONFIG_COMPAT
long reiserfs_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
- struct inode *inode = file->f_path.dentry->d_inode;
- int ret;
-
/* These are just misnamed, they actually get/put from/to user an int */
switch (cmd) {
case REISERFS_IOC32_UNPACK:
@@ -141,10 +152,8 @@ long reiserfs_compat_ioctl(struct file *file, unsigned int cmd,
default:
return -ENOIOCTLCMD;
}
- lock_kernel();
- ret = reiserfs_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
- unlock_kernel();
- return ret;
+
+ return reiserfs_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
}
#endif
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index 90622200b39c..2f8a7e7b8dab 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -429,21 +429,6 @@ static void clear_prepared_bits(struct buffer_head *bh)
clear_buffer_journal_restore_dirty(bh);
}
-/* utility function to force a BUG if it is called without the big
-** kernel lock held. caller is the string printed just before calling BUG()
-*/
-void reiserfs_check_lock_depth(struct super_block *sb, char *caller)
-{
-#ifdef CONFIG_SMP
- if (current->lock_depth < 0) {
- reiserfs_panic(sb, "journal-1", "%s called without kernel "
- "lock held", caller);
- }
-#else
- ;
-#endif
-}
-
/* return a cnode with same dev, block number and size in table, or null if not found */
static inline struct reiserfs_journal_cnode *get_journal_hash_dev(struct
super_block
@@ -556,7 +541,8 @@ static inline void insert_journal_hash(struct reiserfs_journal_cnode **table,
static inline void lock_journal(struct super_block *sb)
{
PROC_INFO_INC(sb, journal.lock_journal);
- mutex_lock(&SB_JOURNAL(sb)->j_mutex);
+
+ reiserfs_mutex_lock_safe(&SB_JOURNAL(sb)->j_mutex, sb);
}
/* unlock the current transaction */
@@ -708,7 +694,9 @@ static void check_barrier_completion(struct super_block *s,
disable_barrier(s);
set_buffer_uptodate(bh);
set_buffer_dirty(bh);
+ reiserfs_write_unlock(s);
sync_dirty_buffer(bh);
+ reiserfs_write_lock(s);
}
}
@@ -996,8 +984,13 @@ static int reiserfs_async_progress_wait(struct super_block *s)
{
DEFINE_WAIT(wait);
struct reiserfs_journal *j = SB_JOURNAL(s);
- if (atomic_read(&j->j_async_throttle))
+
+ if (atomic_read(&j->j_async_throttle)) {
+ reiserfs_write_unlock(s);
congestion_wait(BLK_RW_ASYNC, HZ / 10);
+ reiserfs_write_lock(s);
+ }
+
return 0;
}
@@ -1043,7 +1036,8 @@ static int flush_commit_list(struct super_block *s,
}
/* make sure nobody is trying to flush this one at the same time */
- mutex_lock(&jl->j_commit_mutex);
+ reiserfs_mutex_lock_safe(&jl->j_commit_mutex, s);
+
if (!journal_list_still_alive(s, trans_id)) {
mutex_unlock(&jl->j_commit_mutex);
goto put_jl;
@@ -1061,12 +1055,17 @@ static int flush_commit_list(struct super_block *s,
if (!list_empty(&jl->j_bh_list)) {
int ret;
- unlock_kernel();
+
+ /*
+ * We might sleep in numerous places inside
+ * write_ordered_buffers. Relax the write lock.
+ */
+ reiserfs_write_unlock(s);
ret = write_ordered_buffers(&journal->j_dirty_buffers_lock,
journal, jl, &jl->j_bh_list);
if (ret < 0 && retval == 0)
retval = ret;
- lock_kernel();
+ reiserfs_write_lock(s);
}
BUG_ON(!list_empty(&jl->j_bh_list));
/*
@@ -1085,8 +1084,11 @@ static int flush_commit_list(struct super_block *s,
SB_ONDISK_JOURNAL_SIZE(s);
tbh = journal_find_get_block(s, bn);
if (tbh) {
- if (buffer_dirty(tbh))
- ll_rw_block(WRITE, 1, &tbh) ;
+ if (buffer_dirty(tbh)) {
+ reiserfs_write_unlock(s);
+ ll_rw_block(WRITE, 1, &tbh);
+ reiserfs_write_lock(s);
+ }
put_bh(tbh) ;
}
}
@@ -1114,12 +1116,19 @@ static int flush_commit_list(struct super_block *s,
bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) +
(jl->j_start + i) % SB_ONDISK_JOURNAL_SIZE(s);
tbh = journal_find_get_block(s, bn);
+
+ reiserfs_write_unlock(s);
wait_on_buffer(tbh);
+ reiserfs_write_lock(s);
// since we're using ll_rw_blk above, it might have skipped over
// a locked buffer. Double check here
//
- if (buffer_dirty(tbh)) /* redundant, sync_dirty_buffer() checks */
+ /* redundant, sync_dirty_buffer() checks */
+ if (buffer_dirty(tbh)) {
+ reiserfs_write_unlock(s);
sync_dirty_buffer(tbh);
+ reiserfs_write_lock(s);
+ }
if (unlikely(!buffer_uptodate(tbh))) {
#ifdef CONFIG_REISERFS_CHECK
reiserfs_warning(s, "journal-601",
@@ -1143,10 +1152,15 @@ static int flush_commit_list(struct super_block *s,
if (buffer_dirty(jl->j_commit_bh))
BUG();
mark_buffer_dirty(jl->j_commit_bh) ;
+ reiserfs_write_unlock(s);
sync_dirty_buffer(jl->j_commit_bh) ;
+ reiserfs_write_lock(s);
}
- } else
+ } else {
+ reiserfs_write_unlock(s);
wait_on_buffer(jl->j_commit_bh);
+ reiserfs_write_lock(s);
+ }
check_barrier_completion(s, jl->j_commit_bh);
@@ -1286,7 +1300,9 @@ static int _update_journal_header_block(struct super_block *sb,
if (trans_id >= journal->j_last_flush_trans_id) {
if (buffer_locked((journal->j_header_bh))) {
+ reiserfs_write_unlock(sb);
wait_on_buffer((journal->j_header_bh));
+ reiserfs_write_lock(sb);
if (unlikely(!buffer_uptodate(journal->j_header_bh))) {
#ifdef CONFIG_REISERFS_CHECK
reiserfs_warning(sb, "journal-699",
@@ -1312,12 +1328,16 @@ static int _update_journal_header_block(struct super_block *sb,
disable_barrier(sb);
goto sync;
}
+ reiserfs_write_unlock(sb);
wait_on_buffer(journal->j_header_bh);
+ reiserfs_write_lock(sb);
check_barrier_completion(sb, journal->j_header_bh);
} else {
sync:
set_buffer_dirty(journal->j_header_bh);
+ reiserfs_write_unlock(sb);
sync_dirty_buffer(journal->j_header_bh);
+ reiserfs_write_lock(sb);
}
if (!buffer_uptodate(journal->j_header_bh)) {
reiserfs_warning(sb, "journal-837",
@@ -1409,7 +1429,7 @@ static int flush_journal_list(struct super_block *s,
/* if flushall == 0, the lock is already held */
if (flushall) {
- mutex_lock(&journal->j_flush_mutex);
+ reiserfs_mutex_lock_safe(&journal->j_flush_mutex, s);
} else if (mutex_trylock(&journal->j_flush_mutex)) {
BUG();
}
@@ -1553,7 +1573,11 @@ static int flush_journal_list(struct super_block *s,
reiserfs_panic(s, "journal-1011",
"cn->bh is NULL");
}
+
+ reiserfs_write_unlock(s);
wait_on_buffer(cn->bh);
+ reiserfs_write_lock(s);
+
if (!cn->bh) {
reiserfs_panic(s, "journal-1012",
"cn->bh is NULL");
@@ -1769,7 +1793,7 @@ static int kupdate_transactions(struct super_block *s,
struct reiserfs_journal *journal = SB_JOURNAL(s);
chunk.nr = 0;
- mutex_lock(&journal->j_flush_mutex);
+ reiserfs_mutex_lock_safe(&journal->j_flush_mutex, s);
if (!journal_list_still_alive(s, orig_trans_id)) {
goto done;
}
@@ -1973,11 +1997,19 @@ static int do_journal_release(struct reiserfs_transaction_handle *th,
reiserfs_mounted_fs_count--;
/* wait for all commits to finish */
cancel_delayed_work(&SB_JOURNAL(sb)->j_work);
+
+ /*
+ * We must release the write lock here because
+ * the workqueue job (flush_async_commit) needs this lock
+ */
+ reiserfs_write_unlock(sb);
flush_workqueue(commit_wq);
+
if (!reiserfs_mounted_fs_count) {
destroy_workqueue(commit_wq);
commit_wq = NULL;
}
+ reiserfs_write_lock(sb);
free_journal_ram(sb);
@@ -2243,7 +2275,11 @@ static int journal_read_transaction(struct super_block *sb,
/* read in the log blocks, memcpy to the corresponding real block */
ll_rw_block(READ, get_desc_trans_len(desc), log_blocks);
for (i = 0; i < get_desc_trans_len(desc); i++) {
+
+ reiserfs_write_unlock(sb);
wait_on_buffer(log_blocks[i]);
+ reiserfs_write_lock(sb);
+
if (!buffer_uptodate(log_blocks[i])) {
reiserfs_warning(sb, "journal-1212",
"REPLAY FAILURE fsck required! "
@@ -2765,11 +2801,27 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
goto free_and_return;
}
+ /*
+ * We need to unlock here to avoid creating the following
+ * dependency:
+ * reiserfs_lock -> sysfs_mutex
+ * Because the reiserfs mmap path creates the following dependency:
+ * mm->mmap -> reiserfs_lock, hence we have
+ * mm->mmap -> reiserfs_lock ->sysfs_mutex
+ * This would ends up in a circular dependency with sysfs readdir path
+ * which does sysfs_mutex -> mm->mmap_sem
+ * This is fine because the reiserfs lock is useless in mount path,
+ * at least until we call journal_begin. We keep it for paranoid
+ * reasons.
+ */
+ reiserfs_write_unlock(sb);
if (journal_init_dev(sb, journal, j_dev_name) != 0) {
+ reiserfs_write_lock(sb);
reiserfs_warning(sb, "sh-462",
"unable to initialize jornal device");
goto free_and_return;
}
+ reiserfs_write_lock(sb);
rs = SB_DISK_SUPER_BLOCK(sb);
@@ -2881,8 +2933,11 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
}
reiserfs_mounted_fs_count++;
- if (reiserfs_mounted_fs_count <= 1)
+ if (reiserfs_mounted_fs_count <= 1) {
+ reiserfs_write_unlock(sb);
commit_wq = create_workqueue("reiserfs");
+ reiserfs_write_lock(sb);
+ }
INIT_DELAYED_WORK(&journal->j_work, flush_async_commits);
journal->j_work_sb = sb;
@@ -2964,8 +3019,11 @@ static void queue_log_writer(struct super_block *s)
init_waitqueue_entry(&wait, current);
add_wait_queue(&journal->j_join_wait, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
- if (test_bit(J_WRITERS_QUEUED, &journal->j_state))
+ if (test_bit(J_WRITERS_QUEUED, &journal->j_state)) {
+ reiserfs_write_unlock(s);
schedule();
+ reiserfs_write_lock(s);
+ }
__set_current_state(TASK_RUNNING);
remove_wait_queue(&journal->j_join_wait, &wait);
}
@@ -2982,7 +3040,9 @@ static void let_transaction_grow(struct super_block *sb, unsigned int trans_id)
struct reiserfs_journal *journal = SB_JOURNAL(sb);
unsigned long bcount = journal->j_bcount;
while (1) {
+ reiserfs_write_unlock(sb);
schedule_timeout_uninterruptible(1);
+ reiserfs_write_lock(sb);
journal->j_current_jl->j_state |= LIST_COMMIT_PENDING;
while ((atomic_read(&journal->j_wcount) > 0 ||
atomic_read(&journal->j_jlock)) &&
@@ -3033,7 +3093,9 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th,
if (test_bit(J_WRITERS_BLOCKED, &journal->j_state)) {
unlock_journal(sb);
+ reiserfs_write_unlock(sb);
reiserfs_wait_on_write_block(sb);
+ reiserfs_write_lock(sb);
PROC_INFO_INC(sb, journal.journal_relock_writers);
goto relock;
}
@@ -3506,14 +3568,14 @@ static void flush_async_commits(struct work_struct *work)
struct reiserfs_journal_list *jl;
struct list_head *entry;
- lock_kernel();
+ reiserfs_write_lock(sb);
if (!list_empty(&journal->j_journal_list)) {
/* last entry is the youngest, commit it and you get everything */
entry = journal->j_journal_list.prev;
jl = JOURNAL_LIST_ENTRY(entry);
flush_commit_list(sb, jl, 1);
}
- unlock_kernel();
+ reiserfs_write_unlock(sb);
}
/*
@@ -4041,7 +4103,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
* the new transaction is fully setup, and we've already flushed the
* ordered bh list
*/
- mutex_lock(&jl->j_commit_mutex);
+ reiserfs_mutex_lock_safe(&jl->j_commit_mutex, sb);
/* save the transaction id in case we need to commit it later */
commit_trans_id = jl->j_trans_id;
@@ -4156,7 +4218,9 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
next = cn->next;
free_cnode(sb, cn);
cn = next;
+ reiserfs_write_unlock(sb);
cond_resched();
+ reiserfs_write_lock(sb);
}
/* we are done with both the c_bh and d_bh, but
@@ -4203,10 +4267,10 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
* is lost.
*/
if (!list_empty(&jl->j_tail_bh_list)) {
- unlock_kernel();
+ reiserfs_write_unlock(sb);
write_ordered_buffers(&journal->j_dirty_buffers_lock,
journal, jl, &jl->j_tail_bh_list);
- lock_kernel();
+ reiserfs_write_lock(sb);
}
BUG_ON(!list_empty(&jl->j_tail_bh_list));
mutex_unlock(&jl->j_commit_mutex);
diff --git a/fs/reiserfs/lock.c b/fs/reiserfs/lock.c
new file mode 100644
index 000000000000..ee2cfc0fd8a7
--- /dev/null
+++ b/fs/reiserfs/lock.c
@@ -0,0 +1,88 @@
+#include <linux/reiserfs_fs.h>
+#include <linux/mutex.h>
+
+/*
+ * The previous reiserfs locking scheme was heavily based on
+ * the tricky properties of the Bkl:
+ *
+ * - it was acquired recursively by a same task
+ * - the performances relied on the release-while-schedule() property
+ *
+ * Now that we replace it by a mutex, we still want to keep the same
+ * recursive property to avoid big changes in the code structure.
+ * We use our own lock_owner here because the owner field on a mutex
+ * is only available in SMP or mutex debugging, also we only need this field
+ * for this mutex, no need for a system wide mutex facility.
+ *
+ * Also this lock is often released before a call that could block because
+ * reiserfs performances were partialy based on the release while schedule()
+ * property of the Bkl.
+ */
+void reiserfs_write_lock(struct super_block *s)
+{
+ struct reiserfs_sb_info *sb_i = REISERFS_SB(s);
+
+ if (sb_i->lock_owner != current) {
+ mutex_lock(&sb_i->lock);
+ sb_i->lock_owner = current;
+ }
+
+ /* No need to protect it, only the current task touches it */
+ sb_i->lock_depth++;
+}
+
+void reiserfs_write_unlock(struct super_block *s)
+{
+ struct reiserfs_sb_info *sb_i = REISERFS_SB(s);
+
+ /*
+ * Are we unlocking without even holding the lock?
+ * Such a situation must raise a BUG() if we don't want
+ * to corrupt the data.
+ */
+ BUG_ON(sb_i->lock_owner != current);
+
+ if (--sb_i->lock_depth == -1) {
+ sb_i->lock_owner = NULL;
+ mutex_unlock(&sb_i->lock);
+ }
+}
+
+/*
+ * If we already own the lock, just exit and don't increase the depth.
+ * Useful when we don't want to lock more than once.
+ *
+ * We always return the lock_depth we had before calling
+ * this function.
+ */
+int reiserfs_write_lock_once(struct super_block *s)
+{
+ struct reiserfs_sb_info *sb_i = REISERFS_SB(s);
+
+ if (sb_i->lock_owner != current) {
+ mutex_lock(&sb_i->lock);
+ sb_i->lock_owner = current;
+ return sb_i->lock_depth++;
+ }
+
+ return sb_i->lock_depth;
+}
+
+void reiserfs_write_unlock_once(struct super_block *s, int lock_depth)
+{
+ if (lock_depth == -1)
+ reiserfs_write_unlock(s);
+}
+
+/*
+ * Utility function to force a BUG if it is called without the superblock
+ * write lock held. caller is the string printed just before calling BUG()
+ */
+void reiserfs_check_lock_depth(struct super_block *sb, char *caller)
+{
+ struct reiserfs_sb_info *sb_i = REISERFS_SB(sb);
+
+ if (sb_i->lock_depth < 0)
+ reiserfs_panic(sb, "%s called without kernel lock held %d",
+ caller);
+}
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index 271579128634..e296ff72a6cc 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -324,6 +324,7 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
{
int retval;
+ int lock_depth;
struct inode *inode = NULL;
struct reiserfs_dir_entry de;
INITIALIZE_PATH(path_to_entry);
@@ -331,7 +332,13 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry,
if (REISERFS_MAX_NAME(dir->i_sb->s_blocksize) < dentry->d_name.len)
return ERR_PTR(-ENAMETOOLONG);
- reiserfs_write_lock(dir->i_sb);
+ /*
+ * Might be called with or without the write lock, must be careful
+ * to not recursively hold it in case we want to release the lock
+ * before rescheduling.
+ */
+ lock_depth = reiserfs_write_lock_once(dir->i_sb);
+
de.de_gen_number_bit_string = NULL;
retval =
reiserfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len,
@@ -341,7 +348,7 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry,
inode = reiserfs_iget(dir->i_sb,
(struct cpu_key *)&(de.de_dir_id));
if (!inode || IS_ERR(inode)) {
- reiserfs_write_unlock(dir->i_sb);
+ reiserfs_write_unlock_once(dir->i_sb, lock_depth);
return ERR_PTR(-EACCES);
}
@@ -350,7 +357,7 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry,
if (IS_PRIVATE(dir))
inode->i_flags |= S_PRIVATE;
}
- reiserfs_write_unlock(dir->i_sb);
+ reiserfs_write_unlock_once(dir->i_sb, lock_depth);
if (retval == IO_ERROR) {
return ERR_PTR(-EIO);
}
@@ -725,6 +732,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
struct inode *inode;
struct reiserfs_transaction_handle th;
struct reiserfs_security_handle security;
+ int lock_depth;
/* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
int jbegin_count =
JOURNAL_PER_BALANCE_CNT * 3 +
@@ -748,7 +756,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
return retval;
}
jbegin_count += retval;
- reiserfs_write_lock(dir->i_sb);
+ lock_depth = reiserfs_write_lock_once(dir->i_sb);
retval = journal_begin(&th, dir->i_sb, jbegin_count);
if (retval) {
@@ -798,8 +806,8 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
d_instantiate(dentry, inode);
unlock_new_inode(inode);
retval = journal_end(&th, dir->i_sb, jbegin_count);
- out_failed:
- reiserfs_write_unlock(dir->i_sb);
+out_failed:
+ reiserfs_write_unlock_once(dir->i_sb, lock_depth);
return retval;
}
diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c
index 536eacaeb710..adbc6f538515 100644
--- a/fs/reiserfs/prints.c
+++ b/fs/reiserfs/prints.c
@@ -349,10 +349,6 @@ void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...)
. */
-#ifdef CONFIG_REISERFS_CHECK
-extern struct tree_balance *cur_tb;
-#endif
-
void __reiserfs_panic(struct super_block *sb, const char *id,
const char *function, const char *fmt, ...)
{
diff --git a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c
index 18b315d3d104..b3a94d20f0fc 100644
--- a/fs/reiserfs/resize.c
+++ b/fs/reiserfs/resize.c
@@ -141,7 +141,9 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new)
set_buffer_uptodate(bh);
mark_buffer_dirty(bh);
+ reiserfs_write_unlock(s);
sync_dirty_buffer(bh);
+ reiserfs_write_lock(s);
// update bitmap_info stuff
bitmap[i].free_count = sb_blocksize(sb) * 8 - 1;
brelse(bh);
diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c
index d036ee5b1c81..5fa7118f04e1 100644
--- a/fs/reiserfs/stree.c
+++ b/fs/reiserfs/stree.c
@@ -222,9 +222,6 @@ static inline int bin_search(const void *key, /* Key to search for. */
return ITEM_NOT_FOUND;
}
-#ifdef CONFIG_REISERFS_CHECK
-extern struct tree_balance *cur_tb;
-#endif
/* Minimal possible key. It is never in the tree. */
const struct reiserfs_key MIN_KEY = { 0, 0, {{0, 0},} };
@@ -519,25 +516,48 @@ static int is_tree_node(struct buffer_head *bh, int level)
#define SEARCH_BY_KEY_READA 16
-/* The function is NOT SCHEDULE-SAFE! */
-static void search_by_key_reada(struct super_block *s,
+/*
+ * The function is NOT SCHEDULE-SAFE!
+ * It might unlock the write lock if we needed to wait for a block
+ * to be read. Note that in this case it won't recover the lock to avoid
+ * high contention resulting from too much lock requests, especially
+ * the caller (search_by_key) will perform other schedule-unsafe
+ * operations just after calling this function.
+ *
+ * @return true if we have unlocked
+ */
+static bool search_by_key_reada(struct super_block *s,
struct buffer_head **bh,
b_blocknr_t *b, int num)
{
int i, j;
+ bool unlocked = false;
for (i = 0; i < num; i++) {
bh[i] = sb_getblk(s, b[i]);
}
+ /*
+ * We are going to read some blocks on which we
+ * have a reference. It's safe, though we might be
+ * reading blocks concurrently changed if we release
+ * the lock. But it's still fine because we check later
+ * if the tree changed
+ */
for (j = 0; j < i; j++) {
/*
* note, this needs attention if we are getting rid of the BKL
* you have to make sure the prepared bit isn't set on this buffer
*/
- if (!buffer_uptodate(bh[j]))
+ if (!buffer_uptodate(bh[j])) {
+ if (!unlocked) {
+ reiserfs_write_unlock(s);
+ unlocked = true;
+ }
ll_rw_block(READA, 1, bh + j);
+ }
brelse(bh[j]);
}
+ return unlocked;
}
/**************************************************************************
@@ -625,11 +645,26 @@ int search_by_key(struct super_block *sb, const struct cpu_key *key, /* Key to s
have a pointer to it. */
if ((bh = last_element->pe_buffer =
sb_getblk(sb, block_number))) {
+ bool unlocked = false;
+
if (!buffer_uptodate(bh) && reada_count > 1)
- search_by_key_reada(sb, reada_bh,
+ /* may unlock the write lock */
+ unlocked = search_by_key_reada(sb, reada_bh,
reada_blocks, reada_count);
+ /*
+ * If we haven't already unlocked the write lock,
+ * then we need to do that here before reading
+ * the current block
+ */
+ if (!buffer_uptodate(bh) && !unlocked) {
+ reiserfs_write_unlock(sb);
+ unlocked = true;
+ }
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
+
+ if (unlocked)
+ reiserfs_write_lock(sb);
if (!buffer_uptodate(bh))
goto io_error;
} else {
@@ -673,7 +708,7 @@ int search_by_key(struct super_block *sb, const struct cpu_key *key, /* Key to s
!key_in_buffer(search_path, key, sb),
"PAP-5130: key is not in the buffer");
#ifdef CONFIG_REISERFS_CHECK
- if (cur_tb) {
+ if (REISERFS_SB(sb)->cur_tb) {
print_cur_tb("5140");
reiserfs_panic(sb, "PAP-5140",
"schedule occurred in do_balance!");
@@ -1024,7 +1059,9 @@ static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, st
reiserfs_free_block(th, inode, block, 1);
}
+ reiserfs_write_unlock(sb);
cond_resched();
+ reiserfs_write_lock(sb);
if (item_moved (&s_ih, path)) {
need_re_search = 1;
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index f0ad05f38022..339b0baf2af6 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -465,7 +465,7 @@ static void reiserfs_put_super(struct super_block *s)
struct reiserfs_transaction_handle th;
th.t_trans_id = 0;
- lock_kernel();
+ reiserfs_write_lock(s);
if (s->s_dirt)
reiserfs_write_super(s);
@@ -499,10 +499,10 @@ static void reiserfs_put_super(struct super_block *s)
reiserfs_proc_info_done(s);
+ reiserfs_write_unlock(s);
+ mutex_destroy(&REISERFS_SB(s)->lock);
kfree(s->s_fs_info);
s->s_fs_info = NULL;
-
- unlock_kernel();
}
static struct kmem_cache *reiserfs_inode_cachep;
@@ -554,25 +554,28 @@ static void reiserfs_dirty_inode(struct inode *inode)
struct reiserfs_transaction_handle th;
int err = 0;
+ int lock_depth;
+
if (inode->i_sb->s_flags & MS_RDONLY) {
reiserfs_warning(inode->i_sb, "clm-6006",
"writing inode %lu on readonly FS",
inode->i_ino);
return;
}
- reiserfs_write_lock(inode->i_sb);
+ lock_depth = reiserfs_write_lock_once(inode->i_sb);
/* this is really only used for atime updates, so they don't have
** to be included in O_SYNC or fsync
*/
err = journal_begin(&th, inode->i_sb, 1);
- if (err) {
- reiserfs_write_unlock(inode->i_sb);
- return;
- }
+ if (err)
+ goto out;
+
reiserfs_update_sd(&th, inode);
journal_end(&th, inode->i_sb, 1);
- reiserfs_write_unlock(inode->i_sb);
+
+out:
+ reiserfs_write_unlock_once(inode->i_sb, lock_depth);
}
#ifdef CONFIG_QUOTA
@@ -1168,11 +1171,14 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
unsigned int qfmt = 0;
#ifdef CONFIG_QUOTA
int i;
+#endif
+
+ reiserfs_write_lock(s);
+#ifdef CONFIG_QUOTA
memcpy(qf_names, REISERFS_SB(s)->s_qf_names, sizeof(qf_names));
#endif
- lock_kernel();
rs = SB_DISK_SUPER_BLOCK(s);
if (!reiserfs_parse_options
@@ -1295,12 +1301,12 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
out_ok:
replace_mount_options(s, new_opts);
- unlock_kernel();
+ reiserfs_write_unlock(s);
return 0;
out_err:
kfree(new_opts);
- unlock_kernel();
+ reiserfs_write_unlock(s);
return err;
}
@@ -1404,7 +1410,9 @@ static int read_super_block(struct super_block *s, int offset)
static int reread_meta_blocks(struct super_block *s)
{
ll_rw_block(READ, 1, &(SB_BUFFER_WITH_SB(s)));
+ reiserfs_write_unlock(s);
wait_on_buffer(SB_BUFFER_WITH_SB(s));
+ reiserfs_write_lock(s);
if (!buffer_uptodate(SB_BUFFER_WITH_SB(s))) {
reiserfs_warning(s, "reiserfs-2504", "error reading the super");
return 1;
@@ -1613,7 +1621,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
sbi = kzalloc(sizeof(struct reiserfs_sb_info), GFP_KERNEL);
if (!sbi) {
errval = -ENOMEM;
- goto error;
+ goto error_alloc;
}
s->s_fs_info = sbi;
/* Set default values for options: non-aggressive tails, RO on errors */
@@ -1627,6 +1635,20 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
/* setup default block allocator options */
reiserfs_init_alloc_options(s);
+ mutex_init(&REISERFS_SB(s)->lock);
+ REISERFS_SB(s)->lock_depth = -1;
+
+ /*
+ * This function is called with the bkl, which also was the old
+ * locking used here.
+ * do_journal_begin() will soon check if we hold the lock (ie: was the
+ * bkl). This is likely because do_journal_begin() has several another
+ * callers because at this time, it doesn't seem to be necessary to
+ * protect against anything.
+ * Anyway, let's be conservative and lock for now.
+ */
+ reiserfs_write_lock(s);
+
jdev_name = NULL;
if (reiserfs_parse_options
(s, (char *)data, &(sbi->s_mount_opt), &blocks, &jdev_name,
@@ -1852,9 +1874,13 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
init_waitqueue_head(&(sbi->s_wait));
spin_lock_init(&sbi->bitmap_lock);
+ reiserfs_write_unlock(s);
+
return (0);
error:
+ reiserfs_write_unlock(s);
+error_alloc:
if (jinit_done) { /* kill the commit thread, free journal ram */
journal_release_error(NULL, s);
}
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index 6925b835a43b..58aa8e75f7f5 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -975,7 +975,7 @@ int reiserfs_lookup_privroot(struct super_block *s)
int err = 0;
/* If we don't have the privroot located yet - go find it */
- mutex_lock(&s->s_root->d_inode->i_mutex);
+ reiserfs_mutex_lock_safe(&s->s_root->d_inode->i_mutex, s);
dentry = lookup_one_len(PRIVROOT_NAME, s->s_root,
strlen(PRIVROOT_NAME));
if (!IS_ERR(dentry)) {
@@ -1004,14 +1004,14 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags)
goto error;
if (!privroot->d_inode && !(mount_flags & MS_RDONLY)) {
- mutex_lock(&s->s_root->d_inode->i_mutex);
+ reiserfs_mutex_lock_safe(&s->s_root->d_inode->i_mutex, s);
err = create_privroot(REISERFS_SB(s)->priv_root);
mutex_unlock(&s->s_root->d_inode->i_mutex);
}
if (privroot->d_inode) {
s->s_xattr = reiserfs_xattr_handlers;
- mutex_lock(&privroot->d_inode->i_mutex);
+ reiserfs_mutex_lock_safe(&privroot->d_inode->i_mutex, s);
if (!REISERFS_SB(s)->xattr_root) {
struct dentry *dentry;
dentry = lookup_one_len(XAROOT_NAME, privroot,
diff --git a/fs/sync.c b/fs/sync.c
index d104591b066b..36752a683481 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -295,10 +295,11 @@ SYSCALL_DEFINE1(fdatasync, unsigned int, fd)
*/
int generic_write_sync(struct file *file, loff_t pos, loff_t count)
{
- if (!(file->f_flags & O_SYNC) && !IS_SYNC(file->f_mapping->host))
+ if (!(file->f_flags & O_DSYNC) && !IS_SYNC(file->f_mapping->host))
return 0;
return vfs_fsync_range(file, file->f_path.dentry, pos,
- pos + count - 1, 1);
+ pos + count - 1,
+ (file->f_flags & __O_SYNC) ? 0 : 1);
}
EXPORT_SYMBOL(generic_write_sync);
@@ -452,9 +453,7 @@ int do_sync_mapping_range(struct address_space *mapping, loff_t offset,
ret = 0;
if (flags & SYNC_FILE_RANGE_WAIT_BEFORE) {
- ret = wait_on_page_writeback_range(mapping,
- offset >> PAGE_CACHE_SHIFT,
- endbyte >> PAGE_CACHE_SHIFT);
+ ret = filemap_fdatawait_range(mapping, offset, endbyte);
if (ret < 0)
goto out;
}
@@ -467,9 +466,7 @@ int do_sync_mapping_range(struct address_space *mapping, loff_t offset,
}
if (flags & SYNC_FILE_RANGE_WAIT_AFTER) {
- ret = wait_on_page_writeback_range(mapping,
- offset >> PAGE_CACHE_SHIFT,
- endbyte >> PAGE_CACHE_SHIFT);
+ ret = filemap_fdatawait_range(mapping, offset, endbyte);
}
out:
return ret;
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 1009adc8d602..39849f887e72 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1389,7 +1389,6 @@ static ssize_t ubifs_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
int err;
- ssize_t ret;
struct inode *inode = iocb->ki_filp->f_mapping->host;
struct ubifs_info *c = inode->i_sb->s_fs_info;
@@ -1397,17 +1396,7 @@ static ssize_t ubifs_aio_write(struct kiocb *iocb, const struct iovec *iov,
if (err)
return err;
- ret = generic_file_aio_write(iocb, iov, nr_segs, pos);
- if (ret < 0)
- return ret;
-
- if (ret > 0 && (IS_SYNC(inode) || iocb->ki_filp->f_flags & O_SYNC)) {
- err = ubifs_sync_wbufs_by_inode(c, inode);
- if (err)
- return err;
- }
-
- return ret;
+ return generic_file_aio_write(iocb, iov, nr_segs, pos);
}
static int ubifs_set_page_dirty(struct page *page)
diff --git a/fs/xattr_acl.c b/fs/xattr_acl.c
index c6ad7c7e3ee9..05ac0fe9c4d3 100644
--- a/fs/xattr_acl.c
+++ b/fs/xattr_acl.c
@@ -36,7 +36,7 @@ posix_acl_from_xattr(const void *value, size_t size)
if (count == 0)
return NULL;
- acl = posix_acl_alloc(count, GFP_KERNEL);
+ acl = posix_acl_alloc(count, GFP_NOFS);
if (!acl)
return ERR_PTR(-ENOMEM);
acl_e = acl->a_entries;
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c
index 072050f8d346..339c52b1a434 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -811,7 +811,7 @@ write_retry:
XFS_STATS_ADD(xs_write_bytes, ret);
/* Handle various SYNC-type writes */
- if ((file->f_flags & O_SYNC) || IS_SYNC(inode)) {
+ if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) {
loff_t end = pos + ret - 1;
int error2;
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c
index 4e4276b956e8..5d1a3b98a6e6 100644
--- a/fs/xfs/quota/xfs_qm_syscalls.c
+++ b/fs/xfs/quota/xfs_qm_syscalls.c
@@ -876,7 +876,6 @@ xfs_dqrele_inode(
ip->i_gdquot = NULL;
}
xfs_iput(ip, XFS_ILOCK_EXCL);
- IRELE(ip);
return 0;
}
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 8b6c9e807efb..ccafe8ef7ad5 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -2389,12 +2389,12 @@ xfs_icsb_modify_counters(
{
xfs_icsb_cnts_t *icsbp;
long long lcounter; /* long counter for 64 bit fields */
- int cpu, ret = 0;
+ int ret = 0;
might_sleep();
again:
- cpu = get_cpu();
- icsbp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, cpu);
+ preempt_disable();
+ icsbp = this_cpu_ptr(mp->m_sb_cnts);
/*
* if the counter is disabled, go to slow path
@@ -2438,11 +2438,11 @@ again:
break;
}
xfs_icsb_unlock_cntr(icsbp);
- put_cpu();
+ preempt_enable();
return 0;
slow_path:
- put_cpu();
+ preempt_enable();
/*
* serialise with a mutex so we don't burn lots of cpu on
@@ -2490,7 +2490,7 @@ slow_path:
balance_counter:
xfs_icsb_unlock_cntr(icsbp);
- put_cpu();
+ preempt_enable();
/*
* We may have multiple threads here if multiple per-cpu
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index e723b0fd8e41..0e7efeacf6cb 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 0x20090903
+#define ACPI_CA_VERSION 0x20091013
#include "actypes.h"
#include "actbl.h"
diff --git a/include/asm-generic/fcntl.h b/include/asm-generic/fcntl.h
index 0c3dd8603927..104fce8dd19c 100644
--- a/include/asm-generic/fcntl.h
+++ b/include/asm-generic/fcntl.h
@@ -3,8 +3,6 @@
#include <linux/types.h>
-/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
#define O_ACCMODE 00000003
#define O_RDONLY 00000000
#define O_WRONLY 00000001
@@ -27,8 +25,8 @@
#ifndef O_NONBLOCK
#define O_NONBLOCK 00004000
#endif
-#ifndef O_SYNC
-#define O_SYNC 00010000
+#ifndef O_DSYNC
+#define O_DSYNC 00010000 /* used to be O_SYNC, see below */
#endif
#ifndef FASYNC
#define FASYNC 00020000 /* fcntl, for BSD compatibility */
@@ -51,6 +49,25 @@
#ifndef O_CLOEXEC
#define O_CLOEXEC 02000000 /* set close_on_exec */
#endif
+
+/*
+ * Before Linux 2.6.32 only O_DSYNC semantics were implemented, but using
+ * the O_SYNC flag. We continue to use the existing numerical value
+ * for O_DSYNC semantics now, but using the correct symbolic name for it.
+ * This new value is used to request true Posix O_SYNC semantics. It is
+ * defined in this strange way to make sure applications compiled against
+ * new headers get at least O_DSYNC semantics on older kernels.
+ *
+ * This has the nice side-effect that we can simply test for O_DSYNC
+ * wherever we do not care if O_DSYNC or O_SYNC is used.
+ *
+ * Note: __O_SYNC must never be used directly.
+ */
+#ifndef O_SYNC
+#define __O_SYNC 04000000
+#define O_SYNC (__O_SYNC|O_DSYNC)
+#endif
+
#ifndef O_NDELAY
#define O_NDELAY O_NONBLOCK
#endif
diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h
index 90079c373f1c..8087b90d4673 100644
--- a/include/asm-generic/percpu.h
+++ b/include/asm-generic/percpu.h
@@ -56,6 +56,9 @@ extern unsigned long __per_cpu_offset[NR_CPUS];
#define __raw_get_cpu_var(var) \
(*SHIFT_PERCPU_PTR(&per_cpu_var(var), __my_cpu_offset))
+#define this_cpu_ptr(ptr) SHIFT_PERCPU_PTR(ptr, my_cpu_offset)
+#define __this_cpu_ptr(ptr) SHIFT_PERCPU_PTR(ptr, __my_cpu_offset)
+
#ifdef CONFIG_HAVE_SETUP_PER_CPU_AREA
extern void setup_per_cpu_areas(void);
@@ -66,6 +69,8 @@ extern void setup_per_cpu_areas(void);
#define per_cpu(var, cpu) (*((void)(cpu), &per_cpu_var(var)))
#define __get_cpu_var(var) per_cpu_var(var)
#define __raw_get_cpu_var(var) per_cpu_var(var)
+#define this_cpu_ptr(ptr) per_cpu_ptr(ptr, 0)
+#define __this_cpu_ptr(ptr) this_cpu_ptr(ptr)
#endif /* SMP */
diff --git a/include/asm-generic/socket.h b/include/asm-generic/socket.h
index 538991cef6f0..9a6115e7cf63 100644
--- a/include/asm-generic/socket.h
+++ b/include/asm-generic/socket.h
@@ -63,4 +63,5 @@
#define SO_PROTOCOL 38
#define SO_DOMAIN 39
+#define SO_RXQ_OVFL 40
#endif /* __ASM_GENERIC_SOCKET_H */
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
index 1ffb53f74d37..fc0d575c71e0 100644
--- a/include/crypto/algapi.h
+++ b/include/crypto/algapi.h
@@ -106,7 +106,6 @@ struct blkcipher_walk {
extern const struct crypto_type crypto_ablkcipher_type;
extern const struct crypto_type crypto_aead_type;
extern const struct crypto_type crypto_blkcipher_type;
-extern const struct crypto_type crypto_hash_type;
void crypto_mod_put(struct crypto_alg *alg);
diff --git a/include/crypto/cryptd.h b/include/crypto/cryptd.h
index 2f65a6e8ea4d..1c96b255017c 100644
--- a/include/crypto/cryptd.h
+++ b/include/crypto/cryptd.h
@@ -39,6 +39,7 @@ static inline struct cryptd_ahash *__cryptd_ahash_cast(
struct cryptd_ahash *cryptd_alloc_ahash(const char *alg_name,
u32 type, u32 mask);
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);
#endif
diff --git a/include/drm/drm.h b/include/drm/drm.h
index 7cb50bdde46d..fa6d9155873d 100644
--- a/include/drm/drm.h
+++ b/include/drm/drm.h
@@ -454,6 +454,7 @@ struct drm_irq_busid {
enum drm_vblank_seq_type {
_DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */
_DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */
+ _DRM_VBLANK_EVENT = 0x4000000, /**< Send event instead of blocking */
_DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */
_DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */
_DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */
@@ -461,8 +462,8 @@ enum drm_vblank_seq_type {
};
#define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE)
-#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY | \
- _DRM_VBLANK_NEXTONMISS)
+#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_EVENT | _DRM_VBLANK_SIGNAL | \
+ _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)
struct drm_wait_vblank_request {
enum drm_vblank_seq_type type;
@@ -698,6 +699,34 @@ struct drm_gem_open {
#define DRM_COMMAND_BASE 0x40
#define DRM_COMMAND_END 0xA0
+/**
+ * Header for events written back to userspace on the drm fd. The
+ * type defines the type of event, the length specifies the total
+ * length of the event (including the header), and user_data is
+ * typically a 64 bit value passed with the ioctl that triggered the
+ * event. A read on the drm fd will always only return complete
+ * events, that is, if for example the read buffer is 100 bytes, and
+ * there are two 64 byte events pending, only one will be returned.
+ *
+ * Event types 0 - 0x7fffffff are generic drm events, 0x80000000 and
+ * up are chipset specific.
+ */
+struct drm_event {
+ __u32 type;
+ __u32 length;
+};
+
+#define DRM_EVENT_VBLANK 0x01
+
+struct drm_event_vblank {
+ struct drm_event base;
+ __u64 user_data;
+ __u32 tv_sec;
+ __u32 tv_usec;
+ __u32 sequence;
+ __u32 reserved;
+};
+
/* typedef area */
#ifndef __KERNEL__
typedef struct drm_clip_rect drm_clip_rect_t;
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index c8e64bbadbcf..b0b36838ab11 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -426,6 +426,14 @@ struct drm_buf_entry {
struct drm_freelist freelist;
};
+/* Event queued up for userspace to read */
+struct drm_pending_event {
+ struct drm_event *event;
+ struct list_head link;
+ struct drm_file *file_priv;
+ void (*destroy)(struct drm_pending_event *event);
+};
+
/** File private data */
struct drm_file {
int authenticated;
@@ -449,6 +457,10 @@ struct drm_file {
struct drm_master *master; /* master this node is currently associated with
N.B. not always minor->master */
struct list_head fbs;
+
+ wait_queue_head_t event_wait;
+ struct list_head event_list;
+ int event_space;
};
/** Wait queue */
@@ -900,6 +912,12 @@ struct drm_minor {
struct drm_mode_group mode_group;
};
+struct drm_pending_vblank_event {
+ struct drm_pending_event base;
+ int pipe;
+ struct drm_event_vblank event;
+};
+
/**
* DRM device structure. This structure represent a complete card that
* may contain multiple heads.
@@ -999,6 +1017,12 @@ struct drm_device {
u32 max_vblank_count; /**< size of vblank counter register */
+ /**
+ * List of events
+ */
+ struct list_head vblank_event_list;
+ spinlock_t event_lock;
+
/*@} */
cycles_t ctx_start;
cycles_t lck_start;
@@ -1135,6 +1159,8 @@ extern int drm_lastclose(struct drm_device *dev);
extern int drm_open(struct inode *inode, struct file *filp);
extern int drm_stub_open(struct inode *inode, struct file *filp);
extern int drm_fasync(int fd, struct file *filp, int on);
+extern ssize_t drm_read(struct file *filp, char __user *buffer,
+ size_t count, loff_t *offset);
extern int drm_release(struct inode *inode, struct file *filp);
/* Mapping support (drm_vm.h) */
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 3e1266d435f4..e1006c22862b 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -247,6 +247,7 @@ unifdef-y += in.h
unifdef-y += in6.h
unifdef-y += inotify.h
unifdef-y += input.h
+unifdef-y += ioq.h
unifdef-y += ip.h
unifdef-y += ipc.h
unifdef-y += ipmi.h
@@ -335,6 +336,7 @@ unifdef-y += serial_core.h
unifdef-y += serial.h
unifdef-y += serio.h
unifdef-y += shm.h
+unifdef-y += shm_signal.h
unifdef-y += signal.h
unifdef-y += smb_fs.h
unifdef-y += smb.h
@@ -360,9 +362,12 @@ unifdef-y += uio.h
unifdef-y += unistd.h
unifdef-y += usbdevice_fs.h
unifdef-y += utsname.h
+unifdef-y += vbus_pci.h
+unifdef-y += venet.h
unifdef-y += videodev2.h
unifdef-y += videodev.h
unifdef-y += virtio_config.h
+unifdef-y += virtio_ids.h
unifdef-y += virtio_blk.h
unifdef-y += virtio_net.h
unifdef-y += virtio_9p.h
diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h
index 5824b20b5fcb..1ed2a5cc03f5 100644
--- a/include/linux/can/dev.h
+++ b/include/linux/can/dev.h
@@ -29,8 +29,6 @@ enum can_mode {
/*
* CAN common private data
*/
-#define CAN_ECHO_SKB_MAX 4
-
struct can_priv {
struct can_device_stats can_stats;
@@ -44,15 +42,16 @@ struct can_priv {
int restart_ms;
struct timer_list restart_timer;
- struct sk_buff *echo_skb[CAN_ECHO_SKB_MAX];
-
int (*do_set_bittiming)(struct net_device *dev);
int (*do_set_mode)(struct net_device *dev, enum can_mode mode);
int (*do_get_state)(const struct net_device *dev,
enum can_state *state);
+
+ unsigned int echo_skb_max;
+ struct sk_buff **echo_skb;
};
-struct net_device *alloc_candev(int sizeof_priv);
+struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max);
void free_candev(struct net_device *dev);
int open_candev(struct net_device *dev);
@@ -64,8 +63,13 @@ void unregister_candev(struct net_device *dev);
int can_restart_now(struct net_device *dev);
void can_bus_off(struct net_device *dev);
-void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, int idx);
-void can_get_echo_skb(struct net_device *dev, int idx);
-void can_free_echo_skb(struct net_device *dev, int idx);
+void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
+ unsigned int idx);
+void can_get_echo_skb(struct net_device *dev, unsigned int idx);
+void can_free_echo_skb(struct net_device *dev, unsigned int idx);
+
+struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf);
+struct sk_buff *alloc_can_err_skb(struct net_device *dev,
+ struct can_frame **cf);
#endif /* CAN_DEV_H */
diff --git a/include/linux/can/platform/ti_hecc.h b/include/linux/can/platform/ti_hecc.h
new file mode 100644
index 000000000000..4688c7bb1bd1
--- /dev/null
+++ b/include/linux/can/platform/ti_hecc.h
@@ -0,0 +1,40 @@
+/*
+ * TI HECC (High End CAN Controller) driver platform header
+ *
+ * Copyright (C) 2009 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 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.
+ *
+ */
+
+/**
+ * struct hecc_platform_data - HECC Platform Data
+ *
+ * @scc_hecc_offset: mostly 0 - should really never change
+ * @scc_ram_offset: SCC RAM offset
+ * @hecc_ram_offset: HECC RAM offset
+ * @mbx_offset: Mailbox RAM offset
+ * @int_line: Interrupt line to use - 0 or 1
+ * @version: version for future use
+ *
+ * Platform data structure to get all platform specific settings.
+ * this structure also accounts the fact that the IP may have different
+ * RAM and mailbox offsets for different SOC's
+ */
+struct ti_hecc_platform_data {
+ u32 scc_hecc_offset;
+ u32 scc_ram_offset;
+ u32 hecc_ram_offset;
+ u32 mbx_offset;
+ u32 int_line;
+ u32 version;
+};
+
+
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 83d2fbd81b93..9ea40ff26f0e 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -277,7 +277,6 @@ extern struct clocksource* clocksource_get_next(void);
extern void clocksource_change_rating(struct clocksource *cs, int rating);
extern void clocksource_resume(void);
extern struct clocksource * __init __weak clocksource_default_clock(void);
-extern void clocksource_mark_unstable(struct clocksource *cs);
#ifdef CONFIG_GENERIC_TIME_VSYSCALL
extern void update_vsyscall(struct timespec *ts, struct clocksource *c);
diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h
index 450fa597c94d..77542c57e20a 100644
--- a/include/linux/compiler-gcc4.h
+++ b/include/linux/compiler-gcc4.h
@@ -37,3 +37,9 @@
#define __cold __attribute__((__cold__))
#endif
+
+#define __compiletime_object_size(obj) __builtin_object_size(obj, 0)
+#if __GNUC_MINOR__ >= 4
+#define __compiletime_warning(message) __attribute__((warning(message)))
+#define __compiletime_error(message) __attribute__((error(message)))
+#endif
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 04fb5135b4e1..88fd4b673cb4 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -266,6 +266,17 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#endif
+/* Compile time object size, -1 for unknown */
+#ifndef __compiletime_object_size
+# define __compiletime_object_size(obj) -1
+#endif
+#ifndef __compiletime_warning
+# define __compiletime_warning(message)
+#endif
+#ifndef __compiletime_error
+# define __compiletime_error(message)
+#endif
+
/*
* Prevent the compiler from merging or refetching accesses. The compiler
* is also forbidden from reordering successive instances of ACCESS_ONCE(),
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index fd929889e8dc..24d2e30f1b46 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -250,29 +250,6 @@ struct cipher_alg {
void (*cia_decrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
};
-struct digest_alg {
- unsigned int dia_digestsize;
- void (*dia_init)(struct crypto_tfm *tfm);
- void (*dia_update)(struct crypto_tfm *tfm, const u8 *data,
- unsigned int len);
- void (*dia_final)(struct crypto_tfm *tfm, u8 *out);
- int (*dia_setkey)(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen);
-};
-
-struct hash_alg {
- int (*init)(struct hash_desc *desc);
- int (*update)(struct hash_desc *desc, struct scatterlist *sg,
- unsigned int nbytes);
- int (*final)(struct hash_desc *desc, u8 *out);
- int (*digest)(struct hash_desc *desc, struct scatterlist *sg,
- unsigned int nbytes, u8 *out);
- int (*setkey)(struct crypto_hash *tfm, const u8 *key,
- unsigned int keylen);
-
- unsigned int digestsize;
-};
-
struct compress_alg {
int (*coa_compress)(struct crypto_tfm *tfm, const u8 *src,
unsigned int slen, u8 *dst, unsigned int *dlen);
@@ -293,8 +270,6 @@ struct rng_alg {
#define cra_aead cra_u.aead
#define cra_blkcipher cra_u.blkcipher
#define cra_cipher cra_u.cipher
-#define cra_digest cra_u.digest
-#define cra_hash cra_u.hash
#define cra_compress cra_u.compress
#define cra_rng cra_u.rng
@@ -320,8 +295,6 @@ struct crypto_alg {
struct aead_alg aead;
struct blkcipher_alg blkcipher;
struct cipher_alg cipher;
- struct digest_alg digest;
- struct hash_alg hash;
struct compress_alg compress;
struct rng_alg rng;
} cra_u;
diff --git a/include/linux/device.h b/include/linux/device.h
index 2ea3e4921812..71fbd582a265 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -472,6 +472,17 @@ static inline int device_is_registered(struct device *dev)
return dev->kobj.state_in_sysfs;
}
+static inline void device_enable_async_suspend(struct device *dev, bool enable)
+{
+ if (dev->power.status == DPM_ON)
+ dev->power.async_suspend = enable;
+}
+
+static inline bool device_async_suspend_enabled(struct device *dev)
+{
+ return !!dev->power.async_suspend;
+}
+
void driver_init(void);
/*
diff --git a/include/linux/dm-log-userspace.h b/include/linux/dm-log-userspace.h
index 8a1f972c0fe9..0c3c3a2110c4 100644
--- a/include/linux/dm-log-userspace.h
+++ b/include/linux/dm-log-userspace.h
@@ -363,7 +363,7 @@
* various request types above. The remaining 24-bits are currently
* set to zero and are reserved for future use and compatibility concerns.
*
- * User-space should always use DM_ULOG_REQUEST_TYPE to aquire the
+ * User-space should always use DM_ULOG_REQUEST_TYPE to acquire the
* request type from the 'request_type' field to maintain forward compatibility.
*/
#define DM_ULOG_REQUEST_MASK 0xFF
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index 4a2b162c256a..69a6fbac0921 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -126,7 +126,9 @@ extern int free_irte(int irq);
extern int irq_remapped(int irq);
extern struct intel_iommu *map_dev_to_ir(struct pci_dev *dev);
extern struct intel_iommu *map_ioapic_to_ir(int apic);
+extern struct intel_iommu *map_hpet_to_ir(u8 id);
extern int set_ioapic_sid(struct irte *irte, int apic);
+extern int set_hpet_sid(struct irte *irte, u8 id);
extern int set_msi_sid(struct irte *irte, struct pci_dev *dev);
#else
static inline int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
@@ -158,10 +160,18 @@ static inline struct intel_iommu *map_ioapic_to_ir(int apic)
{
return NULL;
}
+static inline struct intel_iommu *map_hpet_to_ir(unsigned int hpet_id)
+{
+ return NULL;
+}
static inline int set_ioapic_sid(struct irte *irte, int apic)
{
return 0;
}
+static inline int set_hpet_sid(struct irte *irte, u8 id)
+{
+ return -1;
+}
static inline int set_msi_sid(struct irte *irte, struct pci_dev *dev)
{
return 0;
diff --git a/include/linux/drbd.h b/include/linux/drbd.h
new file mode 100644
index 000000000000..233db5c18b86
--- /dev/null
+++ b/include/linux/drbd.h
@@ -0,0 +1,350 @@
+/*
+ drbd.h
+ Kernel module for 2.6.x Kernels
+
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2001-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 2001-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+ Copyright (C) 2001-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+ drbd 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.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT 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 drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifndef DRBD_H
+#define DRBD_H
+#include <linux/connector.h>
+#include <asm/types.h>
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#else
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <limits.h>
+
+/* Altough the Linux source code makes a difference between
+ generic endianness and the bitfields' endianness, there is no
+ architecture as of Linux-2.6.24-rc4 where the bitfileds' endianness
+ does not match the generic endianness. */
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN_BITFIELD
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define __BIG_ENDIAN_BITFIELD
+#else
+# error "sorry, weird endianness on this box"
+#endif
+
+#endif
+
+
+extern const char *drbd_buildtag(void);
+#define REL_VERSION "8.3.3rc2"
+#define API_VERSION 88
+#define PRO_VERSION_MIN 86
+#define PRO_VERSION_MAX 91
+
+
+enum drbd_io_error_p {
+ EP_PASS_ON, /* FIXME should the better be named "Ignore"? */
+ EP_CALL_HELPER,
+ EP_DETACH
+};
+
+enum drbd_fencing_p {
+ FP_DONT_CARE,
+ FP_RESOURCE,
+ FP_STONITH
+};
+
+enum drbd_disconnect_p {
+ DP_RECONNECT,
+ DP_DROP_NET_CONF,
+ DP_FREEZE_IO
+};
+
+enum drbd_after_sb_p {
+ ASB_DISCONNECT,
+ ASB_DISCARD_YOUNGER_PRI,
+ ASB_DISCARD_OLDER_PRI,
+ ASB_DISCARD_ZERO_CHG,
+ ASB_DISCARD_LEAST_CHG,
+ ASB_DISCARD_LOCAL,
+ ASB_DISCARD_REMOTE,
+ ASB_CONSENSUS,
+ ASB_DISCARD_SECONDARY,
+ ASB_CALL_HELPER,
+ ASB_VIOLENTLY
+};
+
+/* KEEP the order, do not delete or insert. Only append. */
+enum drbd_ret_codes {
+ ERR_CODE_BASE = 100,
+ NO_ERROR = 101,
+ ERR_LOCAL_ADDR = 102,
+ ERR_PEER_ADDR = 103,
+ ERR_OPEN_DISK = 104,
+ ERR_OPEN_MD_DISK = 105,
+ ERR_DISK_NOT_BDEV = 107,
+ ERR_MD_NOT_BDEV = 108,
+ ERR_DISK_TO_SMALL = 111,
+ ERR_MD_DISK_TO_SMALL = 112,
+ ERR_BDCLAIM_DISK = 114,
+ ERR_BDCLAIM_MD_DISK = 115,
+ ERR_MD_IDX_INVALID = 116,
+ ERR_IO_MD_DISK = 118,
+ ERR_MD_INVALID = 119,
+ ERR_AUTH_ALG = 120,
+ ERR_AUTH_ALG_ND = 121,
+ ERR_NOMEM = 122,
+ ERR_DISCARD = 123,
+ ERR_DISK_CONFIGURED = 124,
+ ERR_NET_CONFIGURED = 125,
+ ERR_MANDATORY_TAG = 126,
+ ERR_MINOR_INVALID = 127,
+ ERR_INTR = 129, /* EINTR */
+ ERR_RESIZE_RESYNC = 130,
+ ERR_NO_PRIMARY = 131,
+ ERR_SYNC_AFTER = 132,
+ ERR_SYNC_AFTER_CYCLE = 133,
+ ERR_PAUSE_IS_SET = 134,
+ ERR_PAUSE_IS_CLEAR = 135,
+ ERR_PACKET_NR = 137,
+ ERR_NO_DISK = 138,
+ ERR_NOT_PROTO_C = 139,
+ ERR_NOMEM_BITMAP = 140,
+ ERR_INTEGRITY_ALG = 141, /* DRBD 8.2 only */
+ ERR_INTEGRITY_ALG_ND = 142, /* DRBD 8.2 only */
+ ERR_CPU_MASK_PARSE = 143, /* DRBD 8.2 only */
+ ERR_CSUMS_ALG = 144, /* DRBD 8.2 only */
+ ERR_CSUMS_ALG_ND = 145, /* DRBD 8.2 only */
+ ERR_VERIFY_ALG = 146, /* DRBD 8.2 only */
+ ERR_VERIFY_ALG_ND = 147, /* DRBD 8.2 only */
+ ERR_CSUMS_RESYNC_RUNNING= 148, /* DRBD 8.2 only */
+ ERR_VERIFY_RUNNING = 149, /* DRBD 8.2 only */
+ ERR_DATA_NOT_CURRENT = 150,
+ ERR_CONNECTED = 151, /* DRBD 8.3 only */
+ ERR_PERM = 152,
+
+ /* insert new ones above this line */
+ AFTER_LAST_ERR_CODE
+};
+
+#define DRBD_PROT_A 1
+#define DRBD_PROT_B 2
+#define DRBD_PROT_C 3
+
+enum drbd_role {
+ R_UNKNOWN = 0,
+ R_PRIMARY = 1, /* role */
+ R_SECONDARY = 2, /* role */
+ R_MASK = 3,
+};
+
+/* The order of these constants is important.
+ * The lower ones (<C_WF_REPORT_PARAMS) indicate
+ * that there is no socket!
+ * >=C_WF_REPORT_PARAMS ==> There is a socket
+ */
+enum drbd_conns {
+ C_STANDALONE,
+ C_DISCONNECTING, /* Temporal state on the way to StandAlone. */
+ C_UNCONNECTED, /* >= C_UNCONNECTED -> inc_net() succeeds */
+
+ /* These temporal states are all used on the way
+ * from >= C_CONNECTED to Unconnected.
+ * The 'disconnect reason' states
+ * I do not allow to change beween them. */
+ C_TIMEOUT,
+ C_BROKEN_PIPE,
+ C_NETWORK_FAILURE,
+ C_PROTOCOL_ERROR,
+ C_TEAR_DOWN,
+
+ C_WF_CONNECTION,
+ C_WF_REPORT_PARAMS, /* we have a socket */
+ C_CONNECTED, /* we have introduced each other */
+ C_STARTING_SYNC_S, /* starting full sync by admin request. */
+ C_STARTING_SYNC_T, /* stariing full sync by admin request. */
+ C_WF_BITMAP_S,
+ C_WF_BITMAP_T,
+ C_WF_SYNC_UUID,
+
+ /* All SyncStates are tested with this comparison
+ * xx >= C_SYNC_SOURCE && xx <= C_PAUSED_SYNC_T */
+ C_SYNC_SOURCE,
+ C_SYNC_TARGET,
+ C_VERIFY_S,
+ C_VERIFY_T,
+ C_PAUSED_SYNC_S,
+ C_PAUSED_SYNC_T,
+ C_MASK = 31
+};
+
+enum drbd_disk_state {
+ D_DISKLESS,
+ D_ATTACHING, /* In the process of reading the meta-data */
+ D_FAILED, /* Becomes D_DISKLESS as soon as we told it the peer */
+ /* when >= D_FAILED it is legal to access mdev->bc */
+ D_NEGOTIATING, /* Late attaching state, we need to talk to the peer */
+ D_INCONSISTENT,
+ D_OUTDATED,
+ D_UNKNOWN, /* Only used for the peer, never for myself */
+ D_CONSISTENT, /* Might be D_OUTDATED, might be D_UP_TO_DATE ... */
+ D_UP_TO_DATE, /* Only this disk state allows applications' IO ! */
+ D_MASK = 15
+};
+
+union drbd_state {
+/* According to gcc's docs is the ...
+ * The order of allocation of bit-fields within a unit (C90 6.5.2.1, C99 6.7.2.1).
+ * Determined by ABI.
+ * pointed out by Maxim Uvarov q<muvarov@ru.mvista.com>
+ * even though we transmit as "cpu_to_be32(state)",
+ * the offsets of the bitfields still need to be swapped
+ * on different endianess.
+ */
+ struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned role:2 ; /* 3/4 primary/secondary/unknown */
+ unsigned peer:2 ; /* 3/4 primary/secondary/unknown */
+ unsigned conn:5 ; /* 17/32 cstates */
+ unsigned disk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */
+ unsigned pdsk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */
+ unsigned susp:1 ; /* 2/2 IO suspended no/yes */
+ unsigned aftr_isp:1 ; /* isp .. imposed sync pause */
+ unsigned peer_isp:1 ;
+ unsigned user_isp:1 ;
+ unsigned _pad:11; /* 0 unused */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ unsigned _pad:11; /* 0 unused */
+ unsigned user_isp:1 ;
+ unsigned peer_isp:1 ;
+ unsigned aftr_isp:1 ; /* isp .. imposed sync pause */
+ unsigned susp:1 ; /* 2/2 IO suspended no/yes */
+ unsigned pdsk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */
+ unsigned disk:4 ; /* 8/16 from D_DISKLESS to D_UP_TO_DATE */
+ unsigned conn:5 ; /* 17/32 cstates */
+ unsigned peer:2 ; /* 3/4 primary/secondary/unknown */
+ unsigned role:2 ; /* 3/4 primary/secondary/unknown */
+#else
+# error "this endianess is not supported"
+#endif
+ };
+ unsigned int i;
+};
+
+enum drbd_state_ret_codes {
+ SS_CW_NO_NEED = 4,
+ SS_CW_SUCCESS = 3,
+ SS_NOTHING_TO_DO = 2,
+ SS_SUCCESS = 1,
+ SS_UNKNOWN_ERROR = 0, /* Used to sleep longer in _drbd_request_state */
+ SS_TWO_PRIMARIES = -1,
+ SS_NO_UP_TO_DATE_DISK = -2,
+ SS_NO_LOCAL_DISK = -4,
+ SS_NO_REMOTE_DISK = -5,
+ SS_CONNECTED_OUTDATES = -6,
+ SS_PRIMARY_NOP = -7,
+ SS_RESYNC_RUNNING = -8,
+ SS_ALREADY_STANDALONE = -9,
+ SS_CW_FAILED_BY_PEER = -10,
+ SS_IS_DISKLESS = -11,
+ SS_DEVICE_IN_USE = -12,
+ SS_NO_NET_CONFIG = -13,
+ SS_NO_VERIFY_ALG = -14, /* drbd-8.2 only */
+ SS_NEED_CONNECTION = -15, /* drbd-8.2 only */
+ SS_LOWER_THAN_OUTDATED = -16,
+ SS_NOT_SUPPORTED = -17, /* drbd-8.2 only */
+ SS_IN_TRANSIENT_STATE = -18, /* Retry after the next state change */
+ SS_CONCURRENT_ST_CHG = -19, /* Concurrent cluster side state change! */
+ SS_AFTER_LAST_ERROR = -20, /* Keep this at bottom */
+};
+
+/* from drbd_strings.c */
+extern const char *drbd_conn_str(enum drbd_conns);
+extern const char *drbd_role_str(enum drbd_role);
+extern const char *drbd_disk_str(enum drbd_disk_state);
+extern const char *drbd_set_st_err_str(enum drbd_state_ret_codes);
+
+#define SHARED_SECRET_MAX 64
+
+#define MDF_CONSISTENT (1 << 0)
+#define MDF_PRIMARY_IND (1 << 1)
+#define MDF_CONNECTED_IND (1 << 2)
+#define MDF_FULL_SYNC (1 << 3)
+#define MDF_WAS_UP_TO_DATE (1 << 4)
+#define MDF_PEER_OUT_DATED (1 << 5)
+#define MDF_CRASHED_PRIMARY (1 << 6)
+
+enum drbd_uuid_index {
+ UI_CURRENT,
+ UI_BITMAP,
+ UI_HISTORY_START,
+ UI_HISTORY_END,
+ UI_SIZE, /* nl-packet: number of dirty bits */
+ UI_FLAGS, /* nl-packet: flags */
+ UI_EXTENDED_SIZE /* Everything. */
+};
+
+enum drbd_timeout_flag {
+ UT_DEFAULT = 0,
+ UT_DEGRADED = 1,
+ UT_PEER_OUTDATED = 2,
+};
+
+#define UUID_JUST_CREATED ((__u64)4)
+
+#define DRBD_MAGIC 0x83740267
+#define BE_DRBD_MAGIC __constant_cpu_to_be32(DRBD_MAGIC)
+
+/* these are of type "int" */
+#define DRBD_MD_INDEX_INTERNAL -1
+#define DRBD_MD_INDEX_FLEX_EXT -2
+#define DRBD_MD_INDEX_FLEX_INT -3
+
+/* Start of the new netlink/connector stuff */
+
+#define DRBD_NL_CREATE_DEVICE 0x01
+#define DRBD_NL_SET_DEFAULTS 0x02
+
+/* The following line should be moved over to linux/connector.h
+ * when the time comes */
+#ifndef CN_IDX_DRBD
+# define CN_IDX_DRBD 0x4
+/* Ubuntu "intrepid ibex" release defined CN_IDX_DRBD as 0x6 */
+#endif
+#define CN_VAL_DRBD 0x1
+
+/* For searching a vacant cn_idx value */
+#define CN_IDX_STEP 6977
+
+struct drbd_nl_cfg_req {
+ int packet_type;
+ unsigned int drbd_minor;
+ int flags;
+ unsigned short tag_list[];
+};
+
+struct drbd_nl_cfg_reply {
+ int packet_type;
+ unsigned int minor;
+ int ret_code; /* enum ret_code or set_st_err_t */
+ unsigned short tag_list[]; /* only used with get_* calls */
+};
+
+#endif
diff --git a/include/linux/drbd_limits.h b/include/linux/drbd_limits.h
new file mode 100644
index 000000000000..9d067ce46960
--- /dev/null
+++ b/include/linux/drbd_limits.h
@@ -0,0 +1,137 @@
+/*
+ drbd_limits.h
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+*/
+
+/*
+ * Our current limitations.
+ * Some of them are hard limits,
+ * some of them are arbitrary range limits, that make it easier to provide
+ * feedback about nonsense settings for certain configurable values.
+ */
+
+#ifndef DRBD_LIMITS_H
+#define DRBD_LIMITS_H 1
+
+#define DEBUG_RANGE_CHECK 0
+
+#define DRBD_MINOR_COUNT_MIN 1
+#define DRBD_MINOR_COUNT_MAX 255
+
+#define DRBD_DIALOG_REFRESH_MIN 0
+#define DRBD_DIALOG_REFRESH_MAX 600
+
+/* valid port number */
+#define DRBD_PORT_MIN 1
+#define DRBD_PORT_MAX 0xffff
+
+/* startup { */
+ /* if you want more than 3.4 days, disable */
+#define DRBD_WFC_TIMEOUT_MIN 0
+#define DRBD_WFC_TIMEOUT_MAX 300000
+#define DRBD_WFC_TIMEOUT_DEF 0
+
+#define DRBD_DEGR_WFC_TIMEOUT_MIN 0
+#define DRBD_DEGR_WFC_TIMEOUT_MAX 300000
+#define DRBD_DEGR_WFC_TIMEOUT_DEF 0
+
+#define DRBD_OUTDATED_WFC_TIMEOUT_MIN 0
+#define DRBD_OUTDATED_WFC_TIMEOUT_MAX 300000
+#define DRBD_OUTDATED_WFC_TIMEOUT_DEF 0
+/* }*/
+
+/* net { */
+ /* timeout, unit centi seconds
+ * more than one minute timeout is not usefull */
+#define DRBD_TIMEOUT_MIN 1
+#define DRBD_TIMEOUT_MAX 600
+#define DRBD_TIMEOUT_DEF 60 /* 6 seconds */
+
+ /* active connection retries when C_WF_CONNECTION */
+#define DRBD_CONNECT_INT_MIN 1
+#define DRBD_CONNECT_INT_MAX 120
+#define DRBD_CONNECT_INT_DEF 10 /* seconds */
+
+ /* keep-alive probes when idle */
+#define DRBD_PING_INT_MIN 1
+#define DRBD_PING_INT_MAX 120
+#define DRBD_PING_INT_DEF 10
+
+ /* timeout for the ping packets.*/
+#define DRBD_PING_TIMEO_MIN 1
+#define DRBD_PING_TIMEO_MAX 100
+#define DRBD_PING_TIMEO_DEF 5
+
+ /* max number of write requests between write barriers */
+#define DRBD_MAX_EPOCH_SIZE_MIN 1
+#define DRBD_MAX_EPOCH_SIZE_MAX 20000
+#define DRBD_MAX_EPOCH_SIZE_DEF 2048
+
+ /* I don't think that a tcp send buffer of more than 10M is usefull */
+#define DRBD_SNDBUF_SIZE_MIN 0
+#define DRBD_SNDBUF_SIZE_MAX (10<<20)
+#define DRBD_SNDBUF_SIZE_DEF (2*65535)
+
+#define DRBD_RCVBUF_SIZE_MIN 0
+#define DRBD_RCVBUF_SIZE_MAX (10<<20)
+#define DRBD_RCVBUF_SIZE_DEF (2*65535)
+
+ /* @4k PageSize -> 128kB - 512MB */
+#define DRBD_MAX_BUFFERS_MIN 32
+#define DRBD_MAX_BUFFERS_MAX 131072
+#define DRBD_MAX_BUFFERS_DEF 2048
+
+ /* @4k PageSize -> 4kB - 512MB */
+#define DRBD_UNPLUG_WATERMARK_MIN 1
+#define DRBD_UNPLUG_WATERMARK_MAX 131072
+#define DRBD_UNPLUG_WATERMARK_DEF (DRBD_MAX_BUFFERS_DEF/16)
+
+ /* 0 is disabled.
+ * 200 should be more than enough even for very short timeouts */
+#define DRBD_KO_COUNT_MIN 0
+#define DRBD_KO_COUNT_MAX 200
+#define DRBD_KO_COUNT_DEF 0
+/* } */
+
+/* syncer { */
+ /* FIXME allow rate to be zero? */
+#define DRBD_RATE_MIN 1
+/* channel bonding 10 GbE, or other hardware */
+#define DRBD_RATE_MAX (4 << 20)
+#define DRBD_RATE_DEF 250 /* kb/second */
+
+ /* less than 7 would hit performance unneccessarily.
+ * 3833 is the largest prime that still does fit
+ * into 64 sectors of activity log */
+#define DRBD_AL_EXTENTS_MIN 7
+#define DRBD_AL_EXTENTS_MAX 3833
+#define DRBD_AL_EXTENTS_DEF 127
+
+#define DRBD_AFTER_MIN -1
+#define DRBD_AFTER_MAX 255
+#define DRBD_AFTER_DEF -1
+
+/* } */
+
+/* drbdsetup XY resize -d Z
+ * you are free to reduce the device size to nothing, if you want to.
+ * the upper limit with 64bit kernel, enough ram and flexible meta data
+ * is 16 TB, currently. */
+/* DRBD_MAX_SECTORS */
+#define DRBD_DISK_SIZE_SECT_MIN 0
+#define DRBD_DISK_SIZE_SECT_MAX (16 * (2LLU << 30))
+#define DRBD_DISK_SIZE_SECT_DEF 0 /* = disabled = no user size... */
+
+#define DRBD_ON_IO_ERROR_DEF EP_PASS_ON
+#define DRBD_FENCING_DEF FP_DONT_CARE
+#define DRBD_AFTER_SB_0P_DEF ASB_DISCONNECT
+#define DRBD_AFTER_SB_1P_DEF ASB_DISCONNECT
+#define DRBD_AFTER_SB_2P_DEF ASB_DISCONNECT
+#define DRBD_RR_CONFLICT_DEF ASB_DISCONNECT
+
+#define DRBD_MAX_BIO_BVECS_MIN 0
+#define DRBD_MAX_BIO_BVECS_MAX 128
+#define DRBD_MAX_BIO_BVECS_DEF 0
+
+#undef RANGE
+#endif
diff --git a/include/linux/drbd_nl.h b/include/linux/drbd_nl.h
new file mode 100644
index 000000000000..db5721ad50d1
--- /dev/null
+++ b/include/linux/drbd_nl.h
@@ -0,0 +1,137 @@
+/*
+ PAKET( name,
+ TYPE ( pn, pr, member )
+ ...
+ )
+
+ You may never reissue one of the pn arguments
+*/
+
+#if !defined(NL_PACKET) || !defined(NL_STRING) || !defined(NL_INTEGER) || !defined(NL_BIT) || !defined(NL_INT64)
+#error "The macros NL_PACKET, NL_STRING, NL_INTEGER, NL_INT64 and NL_BIT needs to be defined"
+#endif
+
+NL_PACKET(primary, 1,
+ NL_BIT( 1, T_MAY_IGNORE, overwrite_peer)
+)
+
+NL_PACKET(secondary, 2, )
+
+NL_PACKET(disk_conf, 3,
+ NL_INT64( 2, T_MAY_IGNORE, disk_size)
+ NL_STRING( 3, T_MANDATORY, backing_dev, 128)
+ NL_STRING( 4, T_MANDATORY, meta_dev, 128)
+ NL_INTEGER( 5, T_MANDATORY, meta_dev_idx)
+ NL_INTEGER( 6, T_MAY_IGNORE, on_io_error)
+ NL_INTEGER( 7, T_MAY_IGNORE, fencing)
+ NL_BIT( 37, T_MAY_IGNORE, use_bmbv)
+ NL_BIT( 53, T_MAY_IGNORE, no_disk_flush)
+ NL_BIT( 54, T_MAY_IGNORE, no_md_flush)
+ /* 55 max_bio_size was available in 8.2.6rc2 */
+ NL_INTEGER( 56, T_MAY_IGNORE, max_bio_bvecs)
+ NL_BIT( 57, T_MAY_IGNORE, no_disk_barrier)
+ NL_BIT( 58, T_MAY_IGNORE, no_disk_drain)
+)
+
+NL_PACKET(detach, 4, )
+
+NL_PACKET(net_conf, 5,
+ NL_STRING( 8, T_MANDATORY, my_addr, 128)
+ NL_STRING( 9, T_MANDATORY, peer_addr, 128)
+ NL_STRING( 10, T_MAY_IGNORE, shared_secret, SHARED_SECRET_MAX)
+ NL_STRING( 11, T_MAY_IGNORE, cram_hmac_alg, SHARED_SECRET_MAX)
+ NL_STRING( 44, T_MAY_IGNORE, integrity_alg, SHARED_SECRET_MAX)
+ NL_INTEGER( 14, T_MAY_IGNORE, timeout)
+ NL_INTEGER( 15, T_MANDATORY, wire_protocol)
+ NL_INTEGER( 16, T_MAY_IGNORE, try_connect_int)
+ NL_INTEGER( 17, T_MAY_IGNORE, ping_int)
+ NL_INTEGER( 18, T_MAY_IGNORE, max_epoch_size)
+ NL_INTEGER( 19, T_MAY_IGNORE, max_buffers)
+ NL_INTEGER( 20, T_MAY_IGNORE, unplug_watermark)
+ NL_INTEGER( 21, T_MAY_IGNORE, sndbuf_size)
+ NL_INTEGER( 22, T_MAY_IGNORE, ko_count)
+ NL_INTEGER( 24, T_MAY_IGNORE, after_sb_0p)
+ NL_INTEGER( 25, T_MAY_IGNORE, after_sb_1p)
+ NL_INTEGER( 26, T_MAY_IGNORE, after_sb_2p)
+ NL_INTEGER( 39, T_MAY_IGNORE, rr_conflict)
+ NL_INTEGER( 40, T_MAY_IGNORE, ping_timeo)
+ NL_INTEGER( 67, T_MAY_IGNORE, rcvbuf_size)
+ /* 59 addr_family was available in GIT, never released */
+ NL_BIT( 60, T_MANDATORY, mind_af)
+ NL_BIT( 27, T_MAY_IGNORE, want_lose)
+ NL_BIT( 28, T_MAY_IGNORE, two_primaries)
+ NL_BIT( 41, T_MAY_IGNORE, always_asbp)
+ NL_BIT( 61, T_MAY_IGNORE, no_cork)
+ NL_BIT( 62, T_MANDATORY, auto_sndbuf_size)
+)
+
+NL_PACKET(disconnect, 6, )
+
+NL_PACKET(resize, 7,
+ NL_INT64( 29, T_MAY_IGNORE, resize_size)
+)
+
+NL_PACKET(syncer_conf, 8,
+ NL_INTEGER( 30, T_MAY_IGNORE, rate)
+ NL_INTEGER( 31, T_MAY_IGNORE, after)
+ NL_INTEGER( 32, T_MAY_IGNORE, al_extents)
+ NL_STRING( 52, T_MAY_IGNORE, verify_alg, SHARED_SECRET_MAX)
+ NL_STRING( 51, T_MAY_IGNORE, cpu_mask, 32)
+ NL_STRING( 64, T_MAY_IGNORE, csums_alg, SHARED_SECRET_MAX)
+ NL_BIT( 65, T_MAY_IGNORE, use_rle)
+)
+
+NL_PACKET(invalidate, 9, )
+NL_PACKET(invalidate_peer, 10, )
+NL_PACKET(pause_sync, 11, )
+NL_PACKET(resume_sync, 12, )
+NL_PACKET(suspend_io, 13, )
+NL_PACKET(resume_io, 14, )
+NL_PACKET(outdate, 15, )
+NL_PACKET(get_config, 16, )
+NL_PACKET(get_state, 17,
+ NL_INTEGER( 33, T_MAY_IGNORE, state_i)
+)
+
+NL_PACKET(get_uuids, 18,
+ NL_STRING( 34, T_MAY_IGNORE, uuids, (UI_SIZE*sizeof(__u64)))
+ NL_INTEGER( 35, T_MAY_IGNORE, uuids_flags)
+)
+
+NL_PACKET(get_timeout_flag, 19,
+ NL_BIT( 36, T_MAY_IGNORE, use_degraded)
+)
+
+NL_PACKET(call_helper, 20,
+ NL_STRING( 38, T_MAY_IGNORE, helper, 32)
+)
+
+/* Tag nr 42 already allocated in drbd-8.1 development. */
+
+NL_PACKET(sync_progress, 23,
+ NL_INTEGER( 43, T_MAY_IGNORE, sync_progress)
+)
+
+NL_PACKET(dump_ee, 24,
+ NL_STRING( 45, T_MAY_IGNORE, dump_ee_reason, 32)
+ NL_STRING( 46, T_MAY_IGNORE, seen_digest, SHARED_SECRET_MAX)
+ NL_STRING( 47, T_MAY_IGNORE, calc_digest, SHARED_SECRET_MAX)
+ NL_INT64( 48, T_MAY_IGNORE, ee_sector)
+ NL_INT64( 49, T_MAY_IGNORE, ee_block_id)
+ NL_STRING( 50, T_MAY_IGNORE, ee_data, 32 << 10)
+)
+
+NL_PACKET(start_ov, 25,
+ NL_INT64( 66, T_MAY_IGNORE, start_sector)
+)
+
+NL_PACKET(new_c_uuid, 26,
+ NL_BIT( 63, T_MANDATORY, clear_bm)
+)
+
+#undef NL_PACKET
+#undef NL_INTEGER
+#undef NL_INT64
+#undef NL_BIT
+#undef NL_STRING
+
diff --git a/include/linux/drbd_tag_magic.h b/include/linux/drbd_tag_magic.h
new file mode 100644
index 000000000000..fcdff8410e99
--- /dev/null
+++ b/include/linux/drbd_tag_magic.h
@@ -0,0 +1,83 @@
+#ifndef DRBD_TAG_MAGIC_H
+#define DRBD_TAG_MAGIC_H
+
+#define TT_END 0
+#define TT_REMOVED 0xE000
+
+/* declare packet_type enums */
+enum packet_types {
+#define NL_PACKET(name, number, fields) P_ ## name = number,
+#define NL_INTEGER(pn, pr, member)
+#define NL_INT64(pn, pr, member)
+#define NL_BIT(pn, pr, member)
+#define NL_STRING(pn, pr, member, len)
+#include "drbd_nl.h"
+ P_nl_after_last_packet,
+};
+
+/* These struct are used to deduce the size of the tag lists: */
+#define NL_PACKET(name, number, fields) \
+ struct name ## _tag_len_struct { fields };
+#define NL_INTEGER(pn, pr, member) \
+ int member; int tag_and_len ## member;
+#define NL_INT64(pn, pr, member) \
+ __u64 member; int tag_and_len ## member;
+#define NL_BIT(pn, pr, member) \
+ unsigned char member:1; int tag_and_len ## member;
+#define NL_STRING(pn, pr, member, len) \
+ unsigned char member[len]; int member ## _len; \
+ int tag_and_len ## member;
+#include "linux/drbd_nl.h"
+
+/* declate tag-list-sizes */
+static const int tag_list_sizes[] = {
+#define NL_PACKET(name, number, fields) 2 fields ,
+#define NL_INTEGER(pn, pr, member) + 4 + 4
+#define NL_INT64(pn, pr, member) + 4 + 8
+#define NL_BIT(pn, pr, member) + 4 + 1
+#define NL_STRING(pn, pr, member, len) + 4 + (len)
+#include "drbd_nl.h"
+};
+
+/* The two highest bits are used for the tag type */
+#define TT_MASK 0xC000
+#define TT_INTEGER 0x0000
+#define TT_INT64 0x4000
+#define TT_BIT 0x8000
+#define TT_STRING 0xC000
+/* The next bit indicates if processing of the tag is mandatory */
+#define T_MANDATORY 0x2000
+#define T_MAY_IGNORE 0x0000
+#define TN_MASK 0x1fff
+/* The remaining 13 bits are used to enumerate the tags */
+
+#define tag_type(T) ((T) & TT_MASK)
+#define tag_number(T) ((T) & TN_MASK)
+
+/* declare tag enums */
+#define NL_PACKET(name, number, fields) fields
+enum drbd_tags {
+#define NL_INTEGER(pn, pr, member) T_ ## member = pn | TT_INTEGER | pr ,
+#define NL_INT64(pn, pr, member) T_ ## member = pn | TT_INT64 | pr ,
+#define NL_BIT(pn, pr, member) T_ ## member = pn | TT_BIT | pr ,
+#define NL_STRING(pn, pr, member, len) T_ ## member = pn | TT_STRING | pr ,
+#include "drbd_nl.h"
+};
+
+struct tag {
+ const char *name;
+ int type_n_flags;
+ int max_len;
+};
+
+/* declare tag names */
+#define NL_PACKET(name, number, fields) fields
+static const struct tag tag_descriptions[] = {
+#define NL_INTEGER(pn, pr, member) [ pn ] = { #member, TT_INTEGER | pr, sizeof(int) },
+#define NL_INT64(pn, pr, member) [ pn ] = { #member, TT_INT64 | pr, sizeof(__u64) },
+#define NL_BIT(pn, pr, member) [ pn ] = { #member, TT_BIT | pr, sizeof(int) },
+#define NL_STRING(pn, pr, member, len) [ pn ] = { #member, TT_STRING | pr, (len) },
+#include "drbd_nl.h"
+};
+
+#endif
diff --git a/include/linux/edac_mce.h b/include/linux/edac_mce.h
new file mode 100644
index 000000000000..f974fc035363
--- /dev/null
+++ b/include/linux/edac_mce.h
@@ -0,0 +1,31 @@
+/* Provides edac interface to mcelog events
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License version 2.
+ *
+ * Copyright (c) 2009 by:
+ * Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Red Hat Inc. http://www.redhat.com
+ */
+
+#if defined(CONFIG_EDAC_MCE) || \
+ (defined(CONFIG_EDAC_MCE_MODULE) && defined(MODULE))
+
+#include <asm/mce.h>
+#include <linux/list.h>
+
+struct edac_mce {
+ struct list_head list;
+
+ void *priv;
+ int (*check_error)(void *priv, struct mce *mce);
+};
+
+int edac_mce_register(struct edac_mce *edac_mce);
+void edac_mce_unregister(struct edac_mce *edac_mce);
+int edac_mce_parse(struct mce *mce);
+
+#else
+#define edac_mce_parse(mce) (0)
+#endif
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 15e4eb713694..eb1a48da2d43 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -495,13 +495,10 @@ struct ethtool_ops {
u32 (*get_priv_flags)(struct net_device *);
int (*set_priv_flags)(struct net_device *, u32);
int (*get_sset_count)(struct net_device *, int);
-
- /* the following hooks are obsolete */
- int (*self_test_count)(struct net_device *);/* use get_sset_count */
- int (*get_stats_count)(struct net_device *);/* use get_sset_count */
int (*get_rxnfc)(struct net_device *, struct ethtool_rxnfc *, void *);
int (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *);
int (*flash_device)(struct net_device *, struct ethtool_flash *);
+ int (*reset)(struct net_device *, u32 *);
};
#endif /* __KERNEL__ */
@@ -559,6 +556,7 @@ struct ethtool_ops {
#define ETHTOOL_SRXCLSRLDEL 0x00000031 /* Delete RX classification rule */
#define ETHTOOL_SRXCLSRLINS 0x00000032 /* Insert RX classification rule */
#define ETHTOOL_FLASHDEV 0x00000033 /* Flash firmware to device */
+#define ETHTOOL_RESET 0x00000034 /* Reset hardware */
/* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET
@@ -689,4 +687,34 @@ struct ethtool_ops {
#define RX_CLS_FLOW_DISC 0xffffffffffffffffULL
+/* Reset flags */
+/* The reset() operation must clear the flags for the components which
+ * were actually reset. On successful return, the flags indicate the
+ * components which were not reset, either because they do not exist
+ * in the hardware or because they cannot be reset independently. The
+ * driver must never reset any components that were not requested.
+ */
+enum ethtool_reset_flags {
+ /* These flags represent components dedicated to the interface
+ * the command is addressed to. Shift any flag left by
+ * ETH_RESET_SHARED_SHIFT to reset a shared component of the
+ * same type.
+ */
+ ETH_RESET_MGMT = 1 << 0, /* Management processor */
+ ETH_RESET_IRQ = 1 << 1, /* Interrupt requester */
+ ETH_RESET_DMA = 1 << 2, /* DMA engine */
+ ETH_RESET_FILTER = 1 << 3, /* Filtering/flow direction */
+ ETH_RESET_OFFLOAD = 1 << 4, /* Protocol offload */
+ ETH_RESET_MAC = 1 << 5, /* Media access controller */
+ ETH_RESET_PHY = 1 << 6, /* Transceiver/PHY */
+ ETH_RESET_RAM = 1 << 7, /* RAM shared between
+ * multiple components */
+
+ ETH_RESET_DEDICATED = 0x0000ffff, /* All components dedicated to
+ * this interface */
+ ETH_RESET_ALL = 0xffffffff, /* All components used by this
+ * interface, even if shared */
+};
+#define ETH_RESET_SHARED_SHIFT 16
+
#endif /* _LINUX_ETHTOOL_H */
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index 27e772cefb6a..dc12f416a49f 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -97,7 +97,7 @@ struct fid {
* @get_name: find the name for a given inode in a given directory
* @get_parent: find the parent of a given directory
*
- * See Documentation/filesystems/Exporting for details on how to use
+ * See Documentation/filesystems/nfs/Exporting for details on how to use
* this interface correctly.
*
* encode_fh:
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 1354aaf6abbe..bb3b4352978a 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -123,7 +123,9 @@ struct sock_fprog /* Required for SO_ATTACH_FILTER. */
#define SKF_AD_IFINDEX 8
#define SKF_AD_NLATTR 12
#define SKF_AD_NLATTR_NEST 16
-#define SKF_AD_MAX 20
+#define SKF_AD_MARK 20
+#define SKF_AD_QUEUE 24
+#define SKF_AD_MAX 28
#define SKF_NET_OFF (-0x100000)
#define SKF_LL_OFF (-0x200000)
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index 7e1d4dec83e7..211a5d7d87b3 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -20,20 +20,6 @@
#define fw_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, ## args)
#define fw_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args)
-static inline void fw_memcpy_from_be32(void *_dst, void *_src, size_t size)
-{
- u32 *dst = _dst;
- __be32 *src = _src;
- int i;
-
- for (i = 0; i < size / 4; i++)
- dst[i] = be32_to_cpu(src[i]);
-}
-
-static inline void fw_memcpy_to_be32(void *_dst, void *_src, size_t size)
-{
- fw_memcpy_from_be32(_dst, _src, size);
-}
#define CSR_REGISTER_BASE 0xfffff0000000ULL
/* register offsets are relative to CSR_REGISTER_BASE */
@@ -131,7 +117,7 @@ struct fw_card {
bool broadcast_channel_allocated;
u32 broadcast_channel;
- u32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4];
+ __be32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4];
};
struct fw_attribute_group {
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 2620a8c63571..cbe468dcda97 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2090,8 +2090,6 @@ extern int filemap_fdatawait_range(struct address_space *, loff_t lstart,
extern int filemap_write_and_wait(struct address_space *mapping);
extern int filemap_write_and_wait_range(struct address_space *mapping,
loff_t lstart, loff_t lend);
-extern int wait_on_page_writeback_range(struct address_space *mapping,
- pgoff_t start, pgoff_t end);
extern int __filemap_fdatawrite_range(struct address_space *mapping,
loff_t start, loff_t end, int sync_mode);
extern int filemap_fdatawrite_range(struct address_space *mapping,
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index 936f9aa8bb97..c0de28b217c9 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -29,9 +29,14 @@ static inline void fsnotify_d_instantiate(struct dentry *entry,
}
/* Notify this dentry's parent about a child's events. */
-static inline void fsnotify_parent(struct dentry *dentry, __u32 mask)
+static inline void fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask)
{
- __fsnotify_parent(dentry, mask);
+ BUG_ON(file && dentry);
+
+ if (file)
+ dentry = file->f_path.dentry;
+
+ __fsnotify_parent(file, dentry, mask);
inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
}
@@ -124,7 +129,7 @@ static inline void fsnotify_nameremove(struct dentry *dentry, int isdir)
if (isdir)
mask |= FS_IN_ISDIR;
- fsnotify_parent(dentry, mask);
+ fsnotify_parent(NULL, dentry, mask);
}
/*
@@ -183,9 +188,9 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
/*
* fsnotify_access - file was read
*/
-static inline void fsnotify_access(struct dentry *dentry)
+static inline void fsnotify_access(struct file *file)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
__u32 mask = FS_ACCESS;
if (S_ISDIR(inode->i_mode))
@@ -193,16 +198,16 @@ static inline void fsnotify_access(struct dentry *dentry)
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
- fsnotify_parent(dentry, mask);
- fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
+ fsnotify_parent(file, NULL, mask);
+ fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
}
/*
* fsnotify_modify - file was modified
*/
-static inline void fsnotify_modify(struct dentry *dentry)
+static inline void fsnotify_modify(struct file *file)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
__u32 mask = FS_MODIFY;
if (S_ISDIR(inode->i_mode))
@@ -210,16 +215,16 @@ static inline void fsnotify_modify(struct dentry *dentry)
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
- fsnotify_parent(dentry, mask);
- fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
+ fsnotify_parent(file, NULL, mask);
+ fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
}
/*
* fsnotify_open - file was opened
*/
-static inline void fsnotify_open(struct dentry *dentry)
+static inline void fsnotify_open(struct file *file)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
__u32 mask = FS_OPEN;
if (S_ISDIR(inode->i_mode))
@@ -227,8 +232,8 @@ static inline void fsnotify_open(struct dentry *dentry)
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
- fsnotify_parent(dentry, mask);
- fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
+ fsnotify_parent(file, NULL, mask);
+ fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
}
/*
@@ -236,8 +241,7 @@ static inline void fsnotify_open(struct dentry *dentry)
*/
static inline void fsnotify_close(struct file *file)
{
- struct dentry *dentry = file->f_path.dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
fmode_t mode = file->f_mode;
__u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE;
@@ -246,7 +250,7 @@ static inline void fsnotify_close(struct file *file)
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
- fsnotify_parent(dentry, mask);
+ fsnotify_parent(file, NULL, mask);
fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
}
@@ -263,7 +267,7 @@ static inline void fsnotify_xattr(struct dentry *dentry)
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
- fsnotify_parent(dentry, mask);
+ fsnotify_parent(NULL, dentry, mask);
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
}
@@ -299,7 +303,7 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
mask |= FS_IN_ISDIR;
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
- fsnotify_parent(dentry, mask);
+ fsnotify_parent(NULL, dentry, mask);
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
}
}
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 4d6f47b51189..cf165857199b 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -58,9 +58,7 @@
FS_MOVED_FROM | FS_MOVED_TO | FS_CREATE |\
FS_DELETE)
-/* listeners that hard code group numbers near the top */
-#define DNOTIFY_GROUP_NUM UINT_MAX
-#define INOTIFY_GROUP_NUM (DNOTIFY_GROUP_NUM-1)
+#define FS_MOVE (FS_MOVED_FROM | FS_MOVED_TO)
struct fsnotify_group;
struct fsnotify_event;
@@ -80,7 +78,9 @@ struct fsnotify_event_private_data;
* valid group and inode to use to clean up.
*/
struct fsnotify_ops {
- bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode, __u32 mask);
+ bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode,
+ struct vfsmount *mnt, __u32 mask, void *data,
+ int data_type);
int (*handle_event)(struct fsnotify_group *group, struct fsnotify_event *event);
void (*free_group_priv)(struct fsnotify_group *group);
void (*freeing_mark)(struct fsnotify_mark_entry *entry, struct fsnotify_group *group);
@@ -96,10 +96,14 @@ struct fsnotify_ops {
struct fsnotify_group {
/*
* global list of all groups receiving events from fsnotify.
- * anchored by fsnotify_groups and protected by either fsnotify_grp_mutex
+ * anchored by fsnotify_inode_groups and protected by either fsnotify_grp_mutex
* or fsnotify_grp_srcu depending on write vs read.
*/
- struct list_head group_list;
+ struct list_head inode_group_list;
+ /*
+ * same as above except anchored by fsnotify_vfsmount_groups
+ */
+ struct list_head vfsmount_group_list;
/*
* Defines all of the event types in which this group is interested.
@@ -119,7 +123,6 @@ struct fsnotify_group {
* closed.
*/
atomic_t refcnt; /* things with interest in this group */
- unsigned int group_num; /* simply prevents accidental group collision */
const struct fsnotify_ops *ops; /* how this group handles things */
@@ -138,7 +141,8 @@ struct fsnotify_group {
struct list_head mark_entries; /* all inode mark entries for this group */
/* prevents double list_del of group_list. protected by global fsnotify_grp_mutex */
- bool on_group_list;
+ bool on_inode_group_list;
+ bool on_vfsmount_group_list;
/* groups can define private fields here or use the void *private */
union {
@@ -223,6 +227,24 @@ struct fsnotify_event {
};
/*
+ * Inode specific fields in an fsnotify_mark_entry
+ */
+struct fsnotify_inode_mark {
+ struct inode *inode; /* inode this entry is associated with */
+ struct hlist_node i_list; /* list of mark_entries by inode->i_fsnotify_mark_entries */
+ struct list_head free_i_list; /* tmp list used when freeing this mark */
+};
+
+/*
+ * Mount point specific fields in an fsnotify_mark_entry
+ */
+struct fsnotify_vfsmount_mark {
+ struct vfsmount *mnt; /* inode this entry is associated with */
+ struct hlist_node m_list; /* list of mark_entries by inode->i_fsnotify_mark_entries */
+ struct list_head free_m_list; /* tmp list used when freeing this mark */
+};
+
+/*
* a mark is simply an entry attached to an in core inode which allows an
* fsnotify listener to indicate they are either no longer interested in events
* of a type matching mask or only interested in those events.
@@ -237,13 +259,17 @@ struct fsnotify_mark_entry {
/* we hold ref for each i_list and g_list. also one ref for each 'thing'
* in kernel that found and may be using this mark. */
atomic_t refcnt; /* active things looking at this mark */
- struct inode *inode; /* inode this entry is associated with */
struct fsnotify_group *group; /* group this mark entry is for */
- struct hlist_node i_list; /* list of mark_entries by inode->i_fsnotify_mark_entries */
struct list_head g_list; /* list of mark_entries by group->i_fsnotify_mark_entries */
- spinlock_t lock; /* protect group, inode, and killme */
- struct list_head free_i_list; /* tmp list used when freeing this mark */
+ spinlock_t lock; /* protect group and inode */
+ union {
+ struct fsnotify_inode_mark i;
+ struct fsnotify_vfsmount_mark m;
+ };
struct list_head free_g_list; /* tmp list used when freeing this mark */
+#define FSNOTIFY_MARK_FLAG_INODE 0x01
+#define FSNOTIFY_MARK_FLAG_VFSMOUNT 0x02
+ unsigned int flags; /* vfsmount or inode mark? */
void (*free_mark)(struct fsnotify_mark_entry *entry); /* called on final put+free */
};
@@ -254,7 +280,7 @@ struct fsnotify_mark_entry {
/* main fsnotify call to send events */
extern void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
const char *name, u32 cookie);
-extern void __fsnotify_parent(struct dentry *dentry, __u32 mask);
+extern void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask);
extern void __fsnotify_inode_delete(struct inode *inode);
extern u32 fsnotify_get_cookie(void);
@@ -307,12 +333,10 @@ static inline void __fsnotify_d_instantiate(struct dentry *dentry, struct inode
/* must call when a group changes its ->mask */
extern void fsnotify_recalc_global_mask(void);
/* get a reference to an existing or create a new group */
-extern struct fsnotify_group *fsnotify_obtain_group(unsigned int group_num,
- __u32 mask,
- const struct fsnotify_ops *ops);
+extern struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops);
/* run all marks associated with this group and update group->mask */
extern void fsnotify_recalc_group_mask(struct fsnotify_group *group);
-/* drop reference on a group from fsnotify_obtain_group */
+/* drop reference on a group from fsnotify_alloc_group */
extern void fsnotify_put_group(struct fsnotify_group *group);
/* take a reference to an event */
@@ -323,8 +347,10 @@ extern struct fsnotify_event_private_data *fsnotify_remove_priv_from_event(struc
struct fsnotify_event *event);
/* attach the event to the group notification queue */
-extern int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event,
- struct fsnotify_event_private_data *priv);
+extern int fsnotify_add_notify_event(struct fsnotify_group *group,
+ struct fsnotify_event *event,
+ struct fsnotify_event_private_data *priv,
+ int (*merge)(struct list_head *, struct fsnotify_event *));
/* true if the group notification queue is empty */
extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group);
/* return, but do not dequeue the first event on the notification queue */
@@ -339,8 +365,10 @@ extern void fsnotify_recalc_inode_mask(struct inode *inode);
extern void fsnotify_init_mark(struct fsnotify_mark_entry *entry, void (*free_mark)(struct fsnotify_mark_entry *entry));
/* find (and take a reference) to a mark associated with group and inode */
extern struct fsnotify_mark_entry *fsnotify_find_mark_entry(struct fsnotify_group *group, struct inode *inode);
+/* copy the values from old into new */
+extern void fsnotify_duplicate_mark(struct fsnotify_mark_entry *new, struct fsnotify_mark_entry *old);
/* attach the mark to both the group and the inode */
-extern int fsnotify_add_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group, struct inode *inode);
+extern int fsnotify_add_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group, struct inode *inode, int allow_dups);
/* given a mark, flag it to be freed when all references are dropped */
extern void fsnotify_destroy_mark_by_entry(struct fsnotify_mark_entry *entry);
/* run all the marks in a group, and flag them to be freed */
@@ -354,13 +382,18 @@ extern struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32
void *data, int data_is, const char *name,
u32 cookie, gfp_t gfp);
+/* fanotify likes to change events after they are on lists... */
+extern struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event);
+extern int fsnotify_replace_event(struct fsnotify_event_holder *old_holder,
+ struct fsnotify_event *new_event);
+
#else
static inline void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
const char *name, u32 cookie)
{}
-static inline void __fsnotify_parent(struct dentry *dentry, __u32 mask)
+static inline void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask)
{}
static inline void __fsnotify_inode_delete(struct inode *inode)
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 4ec5e67e18cf..f7b47c336703 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -117,12 +117,12 @@ struct ftrace_event_call {
struct dentry *dir;
struct trace_event *event;
int enabled;
- int (*regfunc)(void *);
- void (*unregfunc)(void *);
+ int (*regfunc)(struct ftrace_event_call *);
+ void (*unregfunc)(struct ftrace_event_call *);
int id;
- int (*raw_init)(void);
- int (*show_format)(struct ftrace_event_call *call,
- struct trace_seq *s);
+ int (*raw_init)(struct ftrace_event_call *);
+ int (*show_format)(struct ftrace_event_call *,
+ struct trace_seq *);
int (*define_fields)(struct ftrace_event_call *);
struct list_head fields;
int filter_active;
@@ -131,8 +131,8 @@ struct ftrace_event_call {
void *data;
atomic_t profile_count;
- int (*profile_enable)(void);
- void (*profile_disable)(void);
+ int (*profile_enable)(struct ftrace_event_call *);
+ void (*profile_disable)(struct ftrace_event_call *);
};
#define FTRACE_MAX_PROFILE_SIZE 2048
@@ -144,7 +144,7 @@ extern char *trace_profile_buf_nmi;
#define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */
extern void destroy_preds(struct ftrace_event_call *call);
-extern int filter_match_preds(struct ftrace_event_call *call, void *rec);
+extern int filter_match_preds(struct event_filter *filter, void *rec);
extern int filter_current_check_discard(struct ring_buffer *buffer,
struct ftrace_event_call *call,
void *rec,
@@ -157,11 +157,12 @@ enum {
FILTER_PTR_STRING,
};
-extern int trace_define_field(struct ftrace_event_call *call,
- const char *type, const char *name,
- int offset, int size, int is_signed,
- int filter_type);
extern int trace_define_common_fields(struct ftrace_event_call *call);
+extern int trace_define_field(struct ftrace_event_call *call, const char *type,
+ const char *name, int offset, int size,
+ int is_signed, int filter_type);
+extern int trace_add_event_call(struct ftrace_event_call *call);
+extern void trace_remove_event_call(struct ftrace_event_call *call);
#define is_signed_type(type) (((type)(-1)) < 0)
@@ -186,4 +187,13 @@ do { \
__trace_printk(ip, fmt, ##args); \
} while (0)
+#ifdef CONFIG_EVENT_PROFILE
+struct perf_event;
+extern int ftrace_profile_enable(int event_id);
+extern void ftrace_profile_disable(int event_id);
+extern int ftrace_profile_set_filter(struct perf_event *event, int event_id,
+ char *filter_str);
+extern void ftrace_profile_free_filter(struct perf_event *event);
+#endif
+
#endif /* _LINUX_FTRACE_EVENT_H */
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
index 6d527ee82b2b..d5b387669dab 100644
--- a/include/linux/hardirq.h
+++ b/include/linux/hardirq.h
@@ -139,10 +139,34 @@ static inline void account_system_vtime(struct task_struct *tsk)
#endif
#if defined(CONFIG_NO_HZ)
+#if defined(CONFIG_TINY_RCU)
+extern void rcu_enter_nohz(void);
+extern void rcu_exit_nohz(void);
+
+static inline void rcu_irq_enter(void)
+{
+ rcu_exit_nohz();
+}
+
+static inline void rcu_irq_exit(void)
+{
+ rcu_enter_nohz();
+}
+
+static inline void rcu_nmi_enter(void)
+{
+}
+
+static inline void rcu_nmi_exit(void)
+{
+}
+
+#else
extern void rcu_irq_enter(void);
extern void rcu_irq_exit(void);
extern void rcu_nmi_enter(void);
extern void rcu_nmi_exit(void);
+#endif
#else
# define rcu_irq_enter() do { } while (0)
# define rcu_irq_exit() do { } while (0)
diff --git a/include/linux/hpet.h b/include/linux/hpet.h
index 79f63a27bcef..219ca4f6bea6 100644
--- a/include/linux/hpet.h
+++ b/include/linux/hpet.h
@@ -126,4 +126,6 @@ struct hpet_info {
#define HPET_DPI _IO('h', 0x05) /* disable periodic */
#define HPET_IRQFREQ _IOW('h', 0x6, unsigned long) /* IRQFREQ usec */
+#define MAX_HPET_TBS 8 /* maximum hpet timer blocks */
+
#endif /* !__HPET__ */
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 57d41b0abce2..35f10b8bfee3 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -110,7 +110,7 @@ extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client,
* @driver: Device driver model driver
* @id_table: List of I2C devices supported by this driver
* @detect: Callback for device detection
- * @address_data: The I2C addresses to probe, ignore or force (for detect)
+ * @address_data: The I2C addresses to probe (for detect)
* @clients: List of detected clients we created (for i2c-core use only)
*
* The driver.owner field should be set to the module owner of this driver.
@@ -338,8 +338,7 @@ struct i2c_adapter {
void *algo_data;
/* data fields that are valid for all devices */
- u8 level; /* nesting level for lockdep */
- struct mutex bus_lock;
+ struct rt_mutex bus_lock;
int timeout; /* in jiffies */
int retries;
@@ -380,9 +379,6 @@ static inline void i2c_set_adapdata(struct i2c_adapter *dev, void *data)
*/
struct i2c_client_address_data {
const unsigned short *normal_i2c;
- const unsigned short *probe;
- const unsigned short *ignore;
- const unsigned short * const *forces;
};
/* Internal numbers to terminate lists */
@@ -596,134 +592,48 @@ union i2c_smbus_data {
module_param_array(var, short, &var##_num, 0); \
MODULE_PARM_DESC(var, desc)
-#define I2C_CLIENT_MODULE_PARM_FORCE(name) \
-I2C_CLIENT_MODULE_PARM(force_##name, \
- "List of adapter,address pairs which are " \
- "unquestionably assumed to contain a `" \
- # name "' chip")
-
-
#define I2C_CLIENT_INSMOD_COMMON \
-I2C_CLIENT_MODULE_PARM(probe, "List of adapter,address pairs to scan " \
- "additionally"); \
-I2C_CLIENT_MODULE_PARM(ignore, "List of adapter,address pairs not to " \
- "scan"); \
static const struct i2c_client_address_data addr_data = { \
.normal_i2c = normal_i2c, \
- .probe = probe, \
- .ignore = ignore, \
- .forces = forces, \
}
-#define I2C_CLIENT_FORCE_TEXT \
- "List of adapter,address pairs to boldly assume to be present"
-
/* These are the ones you want to use in your own drivers. Pick the one
which matches the number of devices the driver differenciates between. */
#define I2C_CLIENT_INSMOD \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \
-static const unsigned short * const forces[] = { force, NULL }; \
I2C_CLIENT_INSMOD_COMMON
#define I2C_CLIENT_INSMOD_1(chip1) \
enum chips { any_chip, chip1 }; \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
-static const unsigned short * const forces[] = { force, \
- force_##chip1, NULL }; \
I2C_CLIENT_INSMOD_COMMON
#define I2C_CLIENT_INSMOD_2(chip1, chip2) \
enum chips { any_chip, chip1, chip2 }; \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
-static const unsigned short * const forces[] = { force, \
- force_##chip1, force_##chip2, NULL }; \
I2C_CLIENT_INSMOD_COMMON
#define I2C_CLIENT_INSMOD_3(chip1, chip2, chip3) \
enum chips { any_chip, chip1, chip2, chip3 }; \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip3); \
-static const unsigned short * const forces[] = { force, \
- force_##chip1, force_##chip2, force_##chip3, NULL }; \
I2C_CLIENT_INSMOD_COMMON
#define I2C_CLIENT_INSMOD_4(chip1, chip2, chip3, chip4) \
enum chips { any_chip, chip1, chip2, chip3, chip4 }; \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip3); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip4); \
-static const unsigned short * const forces[] = { force, \
- force_##chip1, force_##chip2, force_##chip3, \
- force_##chip4, NULL}; \
I2C_CLIENT_INSMOD_COMMON
#define I2C_CLIENT_INSMOD_5(chip1, chip2, chip3, chip4, chip5) \
enum chips { any_chip, chip1, chip2, chip3, chip4, chip5 }; \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip3); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip4); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip5); \
-static const unsigned short * const forces[] = { force, \
- force_##chip1, force_##chip2, force_##chip3, \
- force_##chip4, force_##chip5, NULL }; \
I2C_CLIENT_INSMOD_COMMON
#define I2C_CLIENT_INSMOD_6(chip1, chip2, chip3, chip4, chip5, chip6) \
enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6 }; \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip3); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip4); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip5); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip6); \
-static const unsigned short * const forces[] = { force, \
- force_##chip1, force_##chip2, force_##chip3, \
- force_##chip4, force_##chip5, force_##chip6, NULL }; \
I2C_CLIENT_INSMOD_COMMON
#define I2C_CLIENT_INSMOD_7(chip1, chip2, chip3, chip4, chip5, chip6, chip7) \
enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6, \
chip7 }; \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip3); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip4); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip5); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip6); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip7); \
-static const unsigned short * const forces[] = { force, \
- force_##chip1, force_##chip2, force_##chip3, \
- force_##chip4, force_##chip5, force_##chip6, \
- force_##chip7, NULL }; \
I2C_CLIENT_INSMOD_COMMON
#define I2C_CLIENT_INSMOD_8(chip1, chip2, chip3, chip4, chip5, chip6, chip7, chip8) \
enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6, \
chip7, chip8 }; \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip3); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip4); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip5); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip6); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip7); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip8); \
-static const unsigned short * const forces[] = { force, \
- force_##chip1, force_##chip2, force_##chip3, \
- force_##chip4, force_##chip5, force_##chip6, \
- force_##chip7, force_##chip8, NULL }; \
I2C_CLIENT_INSMOD_COMMON
#endif /* __KERNEL__ */
#endif /* _LINUX_I2C_H */
diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h
index 508824ee35e6..10e68cbe0f44 100644
--- a/include/linux/i2c/twl4030.h
+++ b/include/linux/i2c/twl4030.h
@@ -250,6 +250,7 @@ int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
#define RES_TYPE_ALL 0x7
+/* Resource states */
#define RES_STATE_WRST 0xF
#define RES_STATE_ACTIVE 0xE
#define RES_STATE_SLEEP 0x8
@@ -312,6 +313,10 @@ int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
/*----------------------------------------------------------------------*/
+struct twl4030_clock_init_data {
+ bool ck32k_lowpwr_enable;
+};
+
struct twl4030_bci_platform_data {
int *battery_tmp_tbl;
unsigned int tblsize;
@@ -391,18 +396,22 @@ struct twl4030_resconfig {
u8 devgroup; /* Processor group that Power resource belongs to */
u8 type; /* Power resource addressed, 6 / broadcast message */
u8 type2; /* Power resource addressed, 3 / broadcast message */
+ u8 remap_off; /* off state remapping */
+ u8 remap_sleep; /* sleep state remapping */
};
struct twl4030_power_data {
struct twl4030_script **scripts;
unsigned num;
struct twl4030_resconfig *resource_config;
+#define TWL4030_RESCONFIG_UNDEF ((u8)-1)
};
extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
struct twl4030_platform_data {
unsigned irq_base, irq_end;
+ struct twl4030_clock_init_data *clock;
struct twl4030_bci_platform_data *bci;
struct twl4030_gpio_platform_data *gpio;
struct twl4030_madc_platform_data *madc;
diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h
index 5a9aae4adb44..8d76cb4c86fa 100644
--- a/include/linux/if_tunnel.h
+++ b/include/linux/if_tunnel.h
@@ -5,6 +5,7 @@
#ifdef __KERNEL__
#include <linux/ip.h>
+#include <linux/in6.h>
#endif
#define SIOCGETTUNNEL (SIOCDEVPRIVATE + 0)
@@ -15,6 +16,10 @@
#define SIOCADDPRL (SIOCDEVPRIVATE + 5)
#define SIOCDELPRL (SIOCDEVPRIVATE + 6)
#define SIOCCHGPRL (SIOCDEVPRIVATE + 7)
+#define SIOCGET6RD (SIOCDEVPRIVATE + 8)
+#define SIOCADD6RD (SIOCDEVPRIVATE + 9)
+#define SIOCDEL6RD (SIOCDEVPRIVATE + 10)
+#define SIOCCHG6RD (SIOCDEVPRIVATE + 11)
#define GRE_CSUM __cpu_to_be16(0x8000)
#define GRE_ROUTING __cpu_to_be16(0x4000)
@@ -51,6 +56,13 @@ struct ip_tunnel_prl {
/* PRL flags */
#define PRL_DEFAULT 0x0001
+struct ip_tunnel_6rd {
+ struct in6_addr prefix;
+ __be32 relay_prefix;
+ __u16 prefixlen;
+ __u16 relay_prefixlen;
+};
+
enum
{
IFLA_GRE_UNSPEC,
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 7ff9af1d0f05..8898cbebcf34 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -63,7 +63,11 @@ static inline struct vlan_ethhdr *vlan_eth_hdr(const struct sk_buff *skb)
return (struct vlan_ethhdr *)skb_mac_header(skb);
}
-#define VLAN_VID_MASK 0xfff
+#define VLAN_PRIO_MASK 0xe000 /* Priority Code Point */
+#define VLAN_PRIO_SHIFT 13
+#define VLAN_CFI_MASK 0x1000 /* Canonical Format Indicator */
+#define VLAN_TAG_PRESENT VLAN_CFI_MASK
+#define VLAN_VID_MASK 0x0fff /* VLAN Identifier */
/* found in socket.c */
extern void vlan_ioctl_set(int (*hook)(struct net *, void __user *));
@@ -105,8 +109,8 @@ static inline void vlan_group_set_device(struct vlan_group *vg,
array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev;
}
-#define vlan_tx_tag_present(__skb) ((__skb)->vlan_tci)
-#define vlan_tx_tag_get(__skb) ((__skb)->vlan_tci)
+#define vlan_tx_tag_present(__skb) ((__skb)->vlan_tci & VLAN_TAG_PRESENT)
+#define vlan_tx_tag_get(__skb) ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT)
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
@@ -231,7 +235,7 @@ static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, u16 vlan_tci)
static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb,
u16 vlan_tci)
{
- skb->vlan_tci = vlan_tci;
+ skb->vlan_tci = VLAN_TAG_PRESENT | vlan_tci;
return skb;
}
@@ -284,7 +288,7 @@ static inline int __vlan_hwaccel_get_tag(const struct sk_buff *skb,
u16 *vlan_tci)
{
if (vlan_tx_tag_present(skb)) {
- *vlan_tci = skb->vlan_tci;
+ *vlan_tci = vlan_tx_tag_get(skb);
return 0;
} else {
*vlan_tci = 0;
diff --git a/include/linux/input-polldev.h b/include/linux/input-polldev.h
index 597a0077b3c5..5c0ec68a965e 100644
--- a/include/linux/input-polldev.h
+++ b/include/linux/input-polldev.h
@@ -14,9 +14,11 @@
/**
* struct input_polled_dev - simple polled input device
- * @private: private driver data
- * @flush: driver-supplied method that flushes device's state upon
- * opening (optional)
+ * @private: private driver data.
+ * @open: driver-supplied method that prepares device for polling
+ * (enabled the device and maybe flushes device state).
+ * @close: driver-supplied method that is called when device is no
+ * longer being polled. Used to put device into low power mode.
* @poll: driver-supplied method that polls the device and posts
* input events (mandatory).
* @poll_interval: specifies how often the poll() method shoudl be called.
@@ -30,7 +32,8 @@
struct input_polled_dev {
void *private;
- void (*flush)(struct input_polled_dev *dev);
+ void (*open)(struct input_polled_dev *dev);
+ void (*close)(struct input_polled_dev *dev);
void (*poll)(struct input_polled_dev *dev);
unsigned int poll_interval; /* msec */
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 4f0a72a9740c..9310c699a37d 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -332,6 +332,7 @@ struct intel_iommu {
#ifdef CONFIG_INTR_REMAP
struct ir_table *ir_table; /* Interrupt remapping info */
#endif
+ int node;
};
static inline void __iommu_flush_cache(
diff --git a/include/linux/ioq.h b/include/linux/ioq.h
new file mode 100644
index 000000000000..f77e316fc9b9
--- /dev/null
+++ b/include/linux/ioq.h
@@ -0,0 +1,415 @@
+/*
+ * Copyright 2009 Novell. All Rights Reserved.
+ *
+ * IOQ is a generic shared-memory, lockless queue mechanism. It can be used
+ * in a variety of ways, though its intended purpose is to become the
+ * asynchronous communication path for virtual-bus drivers.
+ *
+ * The following are a list of key design points:
+ *
+ * #) All shared-memory is always allocated on explicitly one side of the
+ * link. This typically would be the guest side in a VM/VMM scenario.
+ * #) Each IOQ has the concept of "north" and "south" locales, where
+ * north denotes the memory-owner side (e.g. guest).
+ * #) An IOQ is manipulated using an iterator idiom.
+ * #) Provides a bi-directional signaling/notification infrastructure on
+ * a per-queue basis, which includes an event mitigation strategy
+ * to reduce boundary switching.
+ * #) The signaling path is abstracted so that various technologies and
+ * topologies can define their own specific implementation while sharing
+ * the basic structures and code.
+ *
+ * Author:
+ * Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file 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 St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LINUX_IOQ_H
+#define _LINUX_IOQ_H
+
+#include <linux/types.h>
+#include <linux/shm_signal.h>
+
+/*
+ *---------
+ * The following structures represent data that is shared across boundaries
+ * which may be quite disparate from one another (e.g. Windows vs Linux,
+ * 32 vs 64 bit, etc). Therefore, care has been taken to make sure they
+ * present data in a manner that is independent of the environment.
+ *-----------
+ */
+struct ioq_ring_desc {
+ __u64 cookie; /* for arbitrary use by north-side */
+ __u64 ptr;
+ __u64 len;
+ __u8 valid;
+ __u8 sown; /* South owned = 1, North owned = 0 */
+};
+
+#define IOQ_RING_MAGIC 0x47fa2fe4
+#define IOQ_RING_VER 4
+
+struct ioq_ring_idx {
+ __u32 head; /* 0 based index to head of ptr array */
+ __u32 tail; /* 0 based index to tail of ptr array */
+ __u8 full;
+};
+
+enum ioq_locality {
+ ioq_locality_north,
+ ioq_locality_south,
+};
+
+struct ioq_ring_head {
+ __u32 magic;
+ __u32 ver;
+ struct shm_signal_desc signal;
+ struct ioq_ring_idx idx[2];
+ __u32 count;
+ struct ioq_ring_desc ring[1]; /* "count" elements will be allocated */
+};
+
+#define IOQ_HEAD_DESC_SIZE(count) \
+ (sizeof(struct ioq_ring_head) + sizeof(struct ioq_ring_desc) * (count - 1))
+
+/* --- END SHARED STRUCTURES --- */
+
+#ifdef __KERNEL__
+
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/shm_signal.h>
+#include <linux/kref.h>
+
+enum ioq_idx_type {
+ ioq_idxtype_valid,
+ ioq_idxtype_inuse,
+ ioq_idxtype_both,
+ ioq_idxtype_invalid,
+};
+
+enum ioq_seek_type {
+ ioq_seek_tail,
+ ioq_seek_next,
+ ioq_seek_head,
+ ioq_seek_set
+};
+
+struct ioq_iterator {
+ struct ioq *ioq;
+ struct ioq_ring_idx *idx;
+ u32 pos;
+ struct ioq_ring_desc *desc;
+ int update:1;
+ int dualidx:1;
+ int flipowner:1;
+};
+
+struct ioq_notifier {
+ void (*signal)(struct ioq_notifier *);
+};
+
+struct ioq_ops {
+ void (*release)(struct ioq *ioq);
+};
+
+struct ioq {
+ struct ioq_ops *ops;
+
+ struct kref kref;
+ enum ioq_locality locale;
+ struct ioq_ring_head *head_desc;
+ struct ioq_ring_desc *ring;
+ struct shm_signal *signal;
+ wait_queue_head_t wq;
+ struct ioq_notifier *notifier;
+ size_t count;
+ struct shm_signal_notifier shm_notifier;
+};
+
+#define IOQ_ITER_AUTOUPDATE (1 << 0)
+#define IOQ_ITER_NOFLIPOWNER (1 << 1)
+
+/**
+ * ioq_init() - initialize an IOQ
+ * @ioq: IOQ context
+ *
+ * Initializes IOQ context before first use
+ *
+ **/
+void ioq_init(struct ioq *ioq,
+ struct ioq_ops *ops,
+ enum ioq_locality locale,
+ struct ioq_ring_head *head,
+ struct shm_signal *signal,
+ size_t count);
+
+/**
+ * ioq_get() - acquire an IOQ context reference
+ * @ioq: IOQ context
+ *
+ **/
+static inline struct ioq *ioq_get(struct ioq *ioq)
+{
+ kref_get(&ioq->kref);
+
+ return ioq;
+}
+
+static inline void _ioq_kref_release(struct kref *kref)
+{
+ struct ioq *ioq = container_of(kref, struct ioq, kref);
+
+ shm_signal_put(ioq->signal);
+ ioq->ops->release(ioq);
+}
+
+/**
+ * ioq_put() - release an IOQ context reference
+ * @ioq: IOQ context
+ *
+ **/
+static inline void ioq_put(struct ioq *ioq)
+{
+ kref_put(&ioq->kref, _ioq_kref_release);
+}
+
+/**
+ * ioq_notify_enable() - enables local notifications on an IOQ
+ * @ioq: IOQ context
+ * @flags: Reserved for future use, must be 0
+ *
+ * Enables/unmasks the registered ioq_notifier (if applicable) and waitq to
+ * receive wakeups whenever the remote side performs an ioq_signal() operation.
+ * A notification will be dispatched immediately if any pending signals have
+ * already been issued prior to invoking this call.
+ *
+ * This is synonymous with unmasking an interrupt.
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+static inline int ioq_notify_enable(struct ioq *ioq, int flags)
+{
+ return shm_signal_enable(ioq->signal, 0);
+}
+
+/**
+ * ioq_notify_disable() - disable local notifications on an IOQ
+ * @ioq: IOQ context
+ * @flags: Reserved for future use, must be 0
+ *
+ * Disables/masks the registered ioq_notifier (if applicable) and waitq
+ * from receiving any further notifications. Any subsequent calls to
+ * ioq_signal() by the remote side will update the ring as dirty, but
+ * will not traverse the locale boundary and will not invoke the notifier
+ * callback or wakeup the waitq. Signals delivered while masked will
+ * be deferred until ioq_notify_enable() is invoked
+ *
+ * This is synonymous with masking an interrupt
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+static inline int ioq_notify_disable(struct ioq *ioq, int flags)
+{
+ return shm_signal_disable(ioq->signal, 0);
+}
+
+/**
+ * ioq_signal() - notify the remote side about ring changes
+ * @ioq: IOQ context
+ * @flags: Reserved for future use, must be 0
+ *
+ * Marks the ring state as "dirty" and, if enabled, will traverse
+ * a locale boundary to invoke a remote notification. The remote
+ * side controls whether the notification should be delivered via
+ * the ioq_notify_enable/disable() interface.
+ *
+ * The specifics of how to traverse a locale boundary are abstracted
+ * by the ioq_ops->signal() interface and provided by a particular
+ * implementation. However, typically going north to south would be
+ * something like a syscall/hypercall, and going south to north would be
+ * something like a posix-signal/guest-interrupt.
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+static inline int ioq_signal(struct ioq *ioq, int flags)
+{
+ return shm_signal_inject(ioq->signal, 0);
+}
+
+/**
+ * ioq_count() - counts the number of outstanding descriptors in an index
+ * @ioq: IOQ context
+ * @type: Specifies the index type
+ * (*) valid: the descriptor is valid. This is usually
+ * used to keep track of descriptors that may not
+ * be carrying a useful payload, but still need to
+ * be tracked carefully.
+ * (*) inuse: Descriptors that carry useful payload
+ *
+ * Returns:
+ * (*) >=0: # of descriptors outstanding in the index
+ * (*) <0 = ERRNO
+ *
+ **/
+int ioq_count(struct ioq *ioq, enum ioq_idx_type type);
+
+/**
+ * ioq_remain() - counts the number of remaining descriptors in an index
+ * @ioq: IOQ context
+ * @type: Specifies the index type
+ * (*) valid: the descriptor is valid. This is usually
+ * used to keep track of descriptors that may not
+ * be carrying a useful payload, but still need to
+ * be tracked carefully.
+ * (*) inuse: Descriptors that carry useful payload
+ *
+ * This is the converse of ioq_count(). This function returns the number
+ * of "free" descriptors left in a particular index
+ *
+ * Returns:
+ * (*) >=0: # of descriptors remaining in the index
+ * (*) <0 = ERRNO
+ *
+ **/
+int ioq_remain(struct ioq *ioq, enum ioq_idx_type type);
+
+/**
+ * ioq_size() - counts the maximum number of descriptors in an ring
+ * @ioq: IOQ context
+ *
+ * This function returns the maximum number of descriptors supported in
+ * a ring, regardless of their current state (free or inuse).
+ *
+ * Returns:
+ * (*) >=0: total # of descriptors in the ring
+ * (*) <0 = ERRNO
+ *
+ **/
+int ioq_size(struct ioq *ioq);
+
+/**
+ * ioq_full() - determines if a specific index is "full"
+ * @ioq: IOQ context
+ * @type: Specifies the index type
+ * (*) valid: the descriptor is valid. This is usually
+ * used to keep track of descriptors that may not
+ * be carrying a useful payload, but still need to
+ * be tracked carefully.
+ * (*) inuse: Descriptors that carry useful payload
+ *
+ * Returns:
+ * (*) 0: index is not full
+ * (*) 1: index is full
+ * (*) <0 = ERRNO
+ *
+ **/
+int ioq_full(struct ioq *ioq, enum ioq_idx_type type);
+
+/**
+ * ioq_empty() - determines if a specific index is "empty"
+ * @ioq: IOQ context
+ * @type: Specifies the index type
+ * (*) valid: the descriptor is valid. This is usually
+ * used to keep track of descriptors that may not
+ * be carrying a useful payload, but still need to
+ * be tracked carefully.
+ * (*) inuse: Descriptors that carry useful payload
+ *
+ * Returns:
+ * (*) 0: index is not empty
+ * (*) 1: index is empty
+ * (*) <0 = ERRNO
+ *
+ **/
+static inline int ioq_empty(struct ioq *ioq, enum ioq_idx_type type)
+{
+ return !ioq_count(ioq, type);
+}
+
+/**
+ * ioq_iter_init() - initialize an iterator for IOQ descriptor traversal
+ * @ioq: IOQ context to iterate on
+ * @iter: Iterator context to init (usually from stack)
+ * @type: Specifies the index type to iterate against
+ * (*) valid: iterate against the "valid" index
+ * (*) inuse: iterate against the "inuse" index
+ * (*) both: iterate against both indexes simultaneously
+ * @flags: Bitfield with 0 or more bits set to alter behavior
+ * (*) autoupdate: automatically signal the remote side
+ * whenever the iterator pushes/pops to a new desc
+ * (*) noflipowner: do not flip the ownership bit during
+ * a push/pop operation
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int ioq_iter_init(struct ioq *ioq, struct ioq_iterator *iter,
+ enum ioq_idx_type type, int flags);
+
+/**
+ * ioq_iter_seek() - seek to a specific location in the IOQ ring
+ * @iter: Iterator context (must be initialized with ioq_iter_init)
+ * @type: Specifies the type of seek operation
+ * (*) tail: seek to the absolute tail, offset is ignored
+ * (*) next: seek to the relative next, offset is ignored
+ * (*) head: seek to the absolute head, offset is ignored
+ * (*) set: seek to the absolute offset
+ * @offset: Offset for ioq_seek_set operations
+ * @flags: Reserved for future use, must be 0
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int ioq_iter_seek(struct ioq_iterator *iter, enum ioq_seek_type type,
+ long offset, int flags);
+
+/**
+ * ioq_iter_push() - push the tail pointer forward
+ * @iter: Iterator context (must be initialized with ioq_iter_init)
+ * @flags: Reserved for future use, must be 0
+ *
+ * This function will simultaneously advance the tail ptr in the current
+ * index (valid/inuse, as specified in the ioq_iter_init) as well as
+ * perform a seek(next) operation. This effectively "pushes" a new pointer
+ * onto the tail of the index.
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int ioq_iter_push(struct ioq_iterator *iter, int flags);
+
+/**
+ * ioq_iter_pop() - pop the head pointer from the ring
+ * @iter: Iterator context (must be initialized with ioq_iter_init)
+ * @flags: Reserved for future use, must be 0
+ *
+ * This function will simultaneously advance the head ptr in the current
+ * index (valid/inuse, as specified in the ioq_iter_init) as well as
+ * perform a seek(next) operation. This effectively "pops" a pointer
+ * from the head of the index.
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int ioq_iter_pop(struct ioq_iterator *iter, int flags);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_IOQ_H */
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index c662efa68289..e0cc9a7db2b5 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -167,6 +167,7 @@ struct ipv6_devconf {
#endif
__s32 disable_ipv6;
__s32 accept_dad;
+ __s32 force_tllao;
void *sysctl;
};
@@ -207,6 +208,7 @@ enum {
DEVCONF_MC_FORWARDING,
DEVCONF_DISABLE_IPV6,
DEVCONF_ACCEPT_DAD,
+ DEVCONF_FORCE_TLLAO,
DEVCONF_MAX
};
@@ -503,7 +505,7 @@ static inline struct raw6_sock *raw6_sk(const struct sock *sk)
#define INET6_MATCH(__sk, __net, __hash, __saddr, __daddr, __ports, __dif)\
(((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \
- ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \
+ ((*((__portpair *)&(inet_sk(__sk)->inet_dport))) == (__ports)) && \
((__sk)->sk_family == AF_INET6) && \
ipv6_addr_equal(&inet6_sk(__sk)->daddr, (__saddr)) && \
ipv6_addr_equal(&inet6_sk(__sk)->rcv_saddr, (__daddr)) && \
diff --git a/include/linux/irqflags.h b/include/linux/irqflags.h
index b02a3f1d46a0..006bf45eae30 100644
--- a/include/linux/irqflags.h
+++ b/include/linux/irqflags.h
@@ -124,6 +124,6 @@
typecheck(unsigned long, flags); \
raw_irqs_disabled_flags(flags); \
})
-#endif /* CONFIG_X86 */
+#endif /* CONFIG_TRACE_IRQFLAGS_SUPPORT */
#endif
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index f4e3184fa054..3fa4c590cf12 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -15,7 +15,6 @@
#include <linux/bitops.h>
#include <linux/log2.h>
#include <linux/typecheck.h>
-#include <linux/ratelimit.h>
#include <linux/dynamic_debug.h>
#include <asm/byteorder.h>
#include <asm/bug.h>
@@ -241,8 +240,8 @@ asmlinkage int vprintk(const char *fmt, va_list args)
asmlinkage int printk(const char * fmt, ...)
__attribute__ ((format (printf, 1, 2))) __cold;
-extern struct ratelimit_state printk_ratelimit_state;
-extern int printk_ratelimit(void);
+extern int __printk_ratelimit(const char *func);
+#define printk_ratelimit() __printk_ratelimit(__func__)
extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
unsigned int interval_msec);
diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h
index 348fa8874b52..c059044bc6dc 100644
--- a/include/linux/kernel_stat.h
+++ b/include/linux/kernel_stat.h
@@ -25,6 +25,7 @@ struct cpu_usage_stat {
cputime64_t iowait;
cputime64_t steal;
cputime64_t guest;
+ cputime64_t guest_nice;
};
struct kernel_stat {
diff --git a/include/linux/kmemleak.h b/include/linux/kmemleak.h
index 3c7497d46ee9..99d9a6766f7e 100644
--- a/include/linux/kmemleak.h
+++ b/include/linux/kmemleak.h
@@ -32,8 +32,7 @@ extern void kmemleak_padding(const void *ptr, unsigned long offset,
size_t size) __ref;
extern void kmemleak_not_leak(const void *ptr) __ref;
extern void kmemleak_ignore(const void *ptr) __ref;
-extern void kmemleak_scan_area(const void *ptr, unsigned long offset,
- size_t length, gfp_t gfp) __ref;
+extern void kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp) __ref;
extern void kmemleak_no_scan(const void *ptr) __ref;
static inline void kmemleak_alloc_recursive(const void *ptr, size_t size,
@@ -84,8 +83,7 @@ static inline void kmemleak_not_leak(const void *ptr)
static inline void kmemleak_ignore(const void *ptr)
{
}
-static inline void kmemleak_scan_area(const void *ptr, unsigned long offset,
- size_t length, gfp_t gfp)
+static inline void kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp)
{
}
static inline void kmemleak_erase(void **ptr)
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index 3a46b7b7abb2..1b672f74a32f 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -296,6 +296,8 @@ void recycle_rp_inst(struct kretprobe_instance *ri, struct hlist_head *head);
int disable_kprobe(struct kprobe *kp);
int enable_kprobe(struct kprobe *kp);
+void dump_kprobe(struct kprobe *kp);
+
#else /* !CONFIG_KPROBES: */
static inline int kprobes_built_in(void)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index b7bbb5ddd7ae..b985a29d8175 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -120,7 +120,7 @@ struct kvm_kernel_irq_routing_entry {
u32 gsi;
u32 type;
int (*set)(struct kvm_kernel_irq_routing_entry *e,
- struct kvm *kvm, int level);
+ struct kvm *kvm, int irq_source_id, int level);
union {
struct {
unsigned irqchip;
@@ -128,9 +128,28 @@ struct kvm_kernel_irq_routing_entry {
} irqchip;
struct msi_msg msi;
};
- struct list_head link;
+ struct hlist_node link;
+};
+
+#ifdef __KVM_HAVE_IOAPIC
+
+struct kvm_irq_routing_table {
+ int chip[KVM_NR_IRQCHIPS][KVM_IOAPIC_NUM_PINS];
+ struct kvm_kernel_irq_routing_entry *rt_entries;
+ u32 nr_rt_entries;
+ /*
+ * Array indexed by gsi. Each entry contains list of irq chips
+ * the gsi is connected to.
+ */
+ struct hlist_head map[0];
};
+#else
+
+struct kvm_irq_routing_table {};
+
+#endif
+
struct kvm {
spinlock_t mmu_lock;
spinlock_t requests_lock;
@@ -166,8 +185,9 @@ struct kvm {
struct mutex irq_lock;
#ifdef CONFIG_HAVE_KVM_IRQCHIP
- struct list_head irq_routing; /* of kvm_kernel_irq_routing_entry */
+ struct kvm_irq_routing_table *irq_routing;
struct hlist_head mask_notifier_list;
+ struct hlist_head irq_ack_notifier_list;
#endif
#ifdef KVM_ARCH_WANT_MMU_NOTIFIER
@@ -325,7 +345,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu);
void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu);
int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu);
-void kvm_arch_hardware_enable(void *garbage);
+int kvm_arch_hardware_enable(void *garbage);
void kvm_arch_hardware_disable(void *garbage);
int kvm_arch_hardware_setup(void);
void kvm_arch_hardware_unsetup(void);
@@ -390,7 +410,12 @@ void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq,
struct kvm_irq_mask_notifier *kimn);
void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask);
-int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level);
+#ifdef __KVM_HAVE_IOAPIC
+void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
+ union kvm_ioapic_redirect_entry *entry,
+ unsigned long *deliver_bitmask);
+#endif
+int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level);
void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin);
void kvm_register_irq_ack_notifier(struct kvm *kvm,
struct kvm_irq_ack_notifier *kian);
@@ -552,4 +577,21 @@ static inline bool kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu)
return vcpu->kvm->bsp_vcpu_id == vcpu->vcpu_id;
}
#endif
+
+#ifdef __KVM_HAVE_DEVICE_ASSIGNMENT
+
+long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl,
+ unsigned long arg);
+
+#else
+
+static inline long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl,
+ unsigned long arg)
+{
+ return -ENOTTY;
+}
+
#endif
+
+#endif
+
diff --git a/include/linux/lru_cache.h b/include/linux/lru_cache.h
new file mode 100644
index 000000000000..3a2b2d9b0472
--- /dev/null
+++ b/include/linux/lru_cache.h
@@ -0,0 +1,294 @@
+/*
+ lru_cache.c
+
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2003-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 2003-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+ Copyright (C) 2003-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+ drbd 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.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT 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 drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#ifndef LRU_CACHE_H
+#define LRU_CACHE_H
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/string.h> /* for memset */
+#include <linux/seq_file.h>
+
+/*
+This header file (and its .c file; kernel-doc of functions see there)
+ define a helper framework to easily keep track of index:label associations,
+ and changes to an "active set" of objects, as well as pending transactions,
+ to persistently record those changes.
+
+ We use an LRU policy if it is necessary to "cool down" a region currently in
+ the active set before we can "heat" a previously unused region.
+
+ Because of this later property, it is called "lru_cache".
+ As it actually Tracks Objects in an Active SeT, we could also call it
+ toast (incidentally that is what may happen to the data on the
+ backend storage uppon next resync, if we don't get it right).
+
+What for?
+
+We replicate IO (more or less synchronously) to local and remote disk.
+
+For crash recovery after replication node failure,
+ we need to resync all regions that have been target of in-flight WRITE IO
+ (in use, or "hot", regions), as we don't know wether or not those WRITEs have
+ made it to stable storage.
+
+ To avoid a "full resync", we need to persistently track these regions.
+
+ This is known as "write intent log", and can be implemented as on-disk
+ (coarse or fine grained) bitmap, or other meta data.
+
+ To avoid the overhead of frequent extra writes to this meta data area,
+ usually the condition is softened to regions that _may_ have been target of
+ in-flight WRITE IO, e.g. by only lazily clearing the on-disk write-intent
+ bitmap, trading frequency of meta data transactions against amount of
+ (possibly unneccessary) resync traffic.
+
+ If we set a hard limit on the area that may be "hot" at any given time, we
+ limit the amount of resync traffic needed for crash recovery.
+
+For recovery after replication link failure,
+ we need to resync all blocks that have been changed on the other replica
+ in the mean time, or, if both replica have been changed independently [*],
+ all blocks that have been changed on either replica in the mean time.
+ [*] usually as a result of a cluster split-brain and insufficient protection.
+ but there are valid use cases to do this on purpose.
+
+ Tracking those blocks can be implemented as "dirty bitmap".
+ Having it fine-grained reduces the amount of resync traffic.
+ It should also be persistent, to allow for reboots (or crashes)
+ while the replication link is down.
+
+There are various possible implementations for persistently storing
+write intent log information, three of which are mentioned here.
+
+"Chunk dirtying"
+ The on-disk "dirty bitmap" may be re-used as "write-intent" bitmap as well.
+ To reduce the frequency of bitmap updates for write-intent log purposes,
+ one could dirty "chunks" (of some size) at a time of the (fine grained)
+ on-disk bitmap, while keeping the in-memory "dirty" bitmap as clean as
+ possible, flushing it to disk again when a previously "hot" (and on-disk
+ dirtied as full chunk) area "cools down" again (no IO in flight anymore,
+ and none expected in the near future either).
+
+"Explicit (coarse) write intent bitmap"
+ An other implementation could chose a (probably coarse) explicit bitmap,
+ for write-intent log purposes, additionally to the fine grained dirty bitmap.
+
+"Activity log"
+ Yet an other implementation may keep track of the hot regions, by starting
+ with an empty set, and writing down a journal of region numbers that have
+ become "hot", or have "cooled down" again.
+
+ To be able to use a ring buffer for this journal of changes to the active
+ set, we not only record the actual changes to that set, but also record the
+ not changing members of the set in a round robin fashion. To do so, we use a
+ fixed (but configurable) number of slots which we can identify by index, and
+ associate region numbers (labels) with these indices.
+ For each transaction recording a change to the active set, we record the
+ change itself (index: -old_label, +new_label), and which index is associated
+ with which label (index: current_label) within a certain sliding window that
+ is moved further over the available indices with each such transaction.
+
+ Thus, for crash recovery, if the ringbuffer is sufficiently large, we can
+ accurately reconstruct the active set.
+
+ Sufficiently large depends only on maximum number of active objects, and the
+ size of the sliding window recording "index: current_label" associations within
+ each transaction.
+
+ This is what we call the "activity log".
+
+ Currently we need one activity log transaction per single label change, which
+ does not give much benefit over the "dirty chunks of bitmap" approach, other
+ than potentially less seeks.
+
+ We plan to change the transaction format to support multiple changes per
+ transaction, which then would reduce several (disjoint, "random") updates to
+ the bitmap into one transaction to the activity log ring buffer.
+*/
+
+/* this defines an element in a tracked set
+ * .colision is for hash table lookup.
+ * When we process a new IO request, we know its sector, thus can deduce the
+ * region number (label) easily. To do the label -> object lookup without a
+ * full list walk, we use a simple hash table.
+ *
+ * .list is on one of three lists:
+ * in_use: currently in use (refcnt > 0, lc_number != LC_FREE)
+ * lru: unused but ready to be reused or recycled
+ * (ts_refcnt == 0, lc_number != LC_FREE),
+ * free: unused but ready to be recycled
+ * (ts_refcnt == 0, lc_number == LC_FREE),
+ *
+ * an element is said to be "in the active set",
+ * if either on "in_use" or "lru", i.e. lc_number != LC_FREE.
+ *
+ * DRBD currently (May 2009) only uses 61 elements on the resync lru_cache
+ * (total memory usage 2 pages), and up to 3833 elements on the act_log
+ * lru_cache, totalling ~215 kB for 64bit architechture, ~53 pages.
+ *
+ * We usually do not actually free these objects again, but only "recycle"
+ * them, as the change "index: -old_label, +LC_FREE" would need a transaction
+ * as well. Which also means that using a kmem_cache to allocate the objects
+ * from wastes some resources.
+ * But it avoids high order page allocations in kmalloc.
+ */
+struct lc_element {
+ struct hlist_node colision;
+ struct list_head list; /* LRU list or free list */
+ unsigned refcnt;
+ /* back "pointer" into ts_cache->element[index],
+ * for paranoia, and for "ts_element_to_index" */
+ unsigned lc_index;
+ /* if we want to track a larger set of objects,
+ * it needs to become arch independend u64 */
+ unsigned lc_number;
+
+ /* special label when on free list */
+#define LC_FREE (~0U)
+};
+
+struct lru_cache {
+ /* the least recently used item is kept at lru->prev */
+ struct list_head lru;
+ struct list_head free;
+ struct list_head in_use;
+
+ /* the pre-created kmem cache to allocate the objects from */
+ struct kmem_cache *lc_cache;
+
+ /* size of tracked objects, used to memset(,0,) them in lc_reset */
+ size_t element_size;
+ /* offset of struct lc_element member in the tracked object */
+ size_t element_off;
+
+ /* number of elements (indices) */
+ unsigned int nr_elements;
+ /* Arbitrary limit on maximum tracked objects. Practical limit is much
+ * lower due to allocation failures, probably. For typical use cases,
+ * nr_elements should be a few thousand at most.
+ * This also limits the maximum value of ts_element.ts_index, allowing the
+ * 8 high bits of .ts_index to be overloaded with flags in the future. */
+#define LC_MAX_ACTIVE (1<<24)
+
+ /* statistics */
+ unsigned used; /* number of lelements currently on in_use list */
+ unsigned long hits, misses, starving, dirty, changed;
+
+ /* see below: flag-bits for lru_cache */
+ unsigned long flags;
+
+ /* when changing the label of an index element */
+ unsigned int new_number;
+
+ /* for paranoia when changing the label of an index element */
+ struct lc_element *changing_element;
+
+ void *lc_private;
+ const char *name;
+
+ /* nr_elements there */
+ struct hlist_head *lc_slot;
+ struct lc_element **lc_element;
+};
+
+
+/* flag-bits for lru_cache */
+enum {
+ /* debugging aid, to catch concurrent access early.
+ * user needs to guarantee exclusive access by proper locking! */
+ __LC_PARANOIA,
+ /* if we need to change the set, but currently there is a changing
+ * transaction pending, we are "dirty", and must deferr further
+ * changing requests */
+ __LC_DIRTY,
+ /* if we need to change the set, but currently there is no free nor
+ * unused element available, we are "starving", and must not give out
+ * further references, to guarantee that eventually some refcnt will
+ * drop to zero and we will be able to make progress again, changing
+ * the set, writing the transaction.
+ * if the statistics say we are frequently starving,
+ * nr_elements is too small. */
+ __LC_STARVING,
+};
+#define LC_PARANOIA (1<<__LC_PARANOIA)
+#define LC_DIRTY (1<<__LC_DIRTY)
+#define LC_STARVING (1<<__LC_STARVING)
+
+extern struct lru_cache *lc_create(const char *name, struct kmem_cache *cache,
+ unsigned e_count, size_t e_size, size_t e_off);
+extern void lc_reset(struct lru_cache *lc);
+extern void lc_destroy(struct lru_cache *lc);
+extern void lc_set(struct lru_cache *lc, unsigned int enr, int index);
+extern void lc_del(struct lru_cache *lc, struct lc_element *element);
+
+extern struct lc_element *lc_try_get(struct lru_cache *lc, unsigned int enr);
+extern struct lc_element *lc_find(struct lru_cache *lc, unsigned int enr);
+extern struct lc_element *lc_get(struct lru_cache *lc, unsigned int enr);
+extern unsigned int lc_put(struct lru_cache *lc, struct lc_element *e);
+extern void lc_changed(struct lru_cache *lc, struct lc_element *e);
+
+struct seq_file;
+extern size_t lc_seq_printf_stats(struct seq_file *seq, struct lru_cache *lc);
+
+extern void lc_seq_dump_details(struct seq_file *seq, struct lru_cache *lc, char *utext,
+ void (*detail) (struct seq_file *, struct lc_element *));
+
+/**
+ * lc_try_lock - can be used to stop lc_get() from changing the tracked set
+ * @lc: the lru cache to operate on
+ *
+ * Note that the reference counts and order on the active and lru lists may
+ * still change. Returns true if we aquired the lock.
+ */
+static inline int lc_try_lock(struct lru_cache *lc)
+{
+ return !test_and_set_bit(__LC_DIRTY, &lc->flags);
+}
+
+/**
+ * lc_unlock - unlock @lc, allow lc_get() to change the set again
+ * @lc: the lru cache to operate on
+ */
+static inline void lc_unlock(struct lru_cache *lc)
+{
+ clear_bit(__LC_DIRTY, &lc->flags);
+ smp_mb__after_clear_bit();
+}
+
+static inline int lc_is_used(struct lru_cache *lc, unsigned int enr)
+{
+ struct lc_element *e = lc_find(lc, enr);
+ return e && e->refcnt;
+}
+
+#define lc_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+extern struct lc_element *lc_element_by_index(struct lru_cache *lc, unsigned i);
+extern unsigned int lc_index_of(struct lru_cache *lc, struct lc_element *e);
+
+#endif
diff --git a/include/linux/mfd/88pm8607.h b/include/linux/mfd/88pm8607.h
new file mode 100644
index 000000000000..f41b428d2cec
--- /dev/null
+++ b/include/linux/mfd/88pm8607.h
@@ -0,0 +1,217 @@
+/*
+ * Marvell 88PM8607 Interface
+ *
+ * Copyright (C) 2009 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 __LINUX_MFD_88PM8607_H
+#define __LINUX_MFD_88PM8607_H
+
+enum {
+ PM8607_ID_BUCK1 = 0,
+ PM8607_ID_BUCK2,
+ PM8607_ID_BUCK3,
+
+ PM8607_ID_LDO1,
+ PM8607_ID_LDO2,
+ PM8607_ID_LDO3,
+ PM8607_ID_LDO4,
+ PM8607_ID_LDO5,
+ PM8607_ID_LDO6,
+ PM8607_ID_LDO7,
+ PM8607_ID_LDO8,
+ PM8607_ID_LDO9,
+ PM8607_ID_LDO10,
+ PM8607_ID_LDO12,
+ PM8607_ID_LDO14,
+
+ PM8607_ID_RG_MAX,
+};
+
+#define CHIP_ID (0x40)
+#define CHIP_ID_MASK (0xF8)
+
+/* Interrupt Registers */
+#define PM8607_STATUS_1 (0x01)
+#define PM8607_STATUS_2 (0x02)
+#define PM8607_INT_STATUS1 (0x03)
+#define PM8607_INT_STATUS2 (0x04)
+#define PM8607_INT_STATUS3 (0x05)
+#define PM8607_INT_MASK_1 (0x06)
+#define PM8607_INT_MASK_2 (0x07)
+#define PM8607_INT_MASK_3 (0x08)
+
+/* Regulator Control Registers */
+#define PM8607_LDO1 (0x10)
+#define PM8607_LDO2 (0x11)
+#define PM8607_LDO3 (0x12)
+#define PM8607_LDO4 (0x13)
+#define PM8607_LDO5 (0x14)
+#define PM8607_LDO6 (0x15)
+#define PM8607_LDO7 (0x16)
+#define PM8607_LDO8 (0x17)
+#define PM8607_LDO9 (0x18)
+#define PM8607_LDO10 (0x19)
+#define PM8607_LDO12 (0x1A)
+#define PM8607_LDO14 (0x1B)
+#define PM8607_SLEEP_MODE1 (0x1C)
+#define PM8607_SLEEP_MODE2 (0x1D)
+#define PM8607_SLEEP_MODE3 (0x1E)
+#define PM8607_SLEEP_MODE4 (0x1F)
+#define PM8607_GO (0x20)
+#define PM8607_SLEEP_BUCK1 (0x21)
+#define PM8607_SLEEP_BUCK2 (0x22)
+#define PM8607_SLEEP_BUCK3 (0x23)
+#define PM8607_BUCK1 (0x24)
+#define PM8607_BUCK2 (0x25)
+#define PM8607_BUCK3 (0x26)
+#define PM8607_BUCK_CONTROLS (0x27)
+#define PM8607_SUPPLIES_EN11 (0x2B)
+#define PM8607_SUPPLIES_EN12 (0x2C)
+#define PM8607_GROUP1 (0x2D)
+#define PM8607_GROUP2 (0x2E)
+#define PM8607_GROUP3 (0x2F)
+#define PM8607_GROUP4 (0x30)
+#define PM8607_GROUP5 (0x31)
+#define PM8607_GROUP6 (0x32)
+#define PM8607_SUPPLIES_EN21 (0x33)
+#define PM8607_SUPPLIES_EN22 (0x34)
+
+/* RTC Control Registers */
+#define PM8607_RTC1 (0xA0)
+#define PM8607_RTC_COUNTER1 (0xA1)
+#define PM8607_RTC_COUNTER2 (0xA2)
+#define PM8607_RTC_COUNTER3 (0xA3)
+#define PM8607_RTC_COUNTER4 (0xA4)
+#define PM8607_RTC_EXPIRE1 (0xA5)
+#define PM8607_RTC_EXPIRE2 (0xA6)
+#define PM8607_RTC_EXPIRE3 (0xA7)
+#define PM8607_RTC_EXPIRE4 (0xA8)
+#define PM8607_RTC_TRIM1 (0xA9)
+#define PM8607_RTC_TRIM2 (0xAA)
+#define PM8607_RTC_TRIM3 (0xAB)
+#define PM8607_RTC_TRIM4 (0xAC)
+#define PM8607_RTC_MISC1 (0xAD)
+#define PM8607_RTC_MISC2 (0xAE)
+#define PM8607_RTC_MISC3 (0xAF)
+
+/* Misc Registers */
+#define PM8607_CHIP_ID (0x00)
+#define PM8607_LDO1 (0x10)
+#define PM8607_DVC3 (0x26)
+#define PM8607_MISC1 (0x40)
+
+/* bit definitions for PM8607 events */
+#define PM8607_EVENT_ONKEY (1 << 0)
+#define PM8607_EVENT_EXTON (1 << 1)
+#define PM8607_EVENT_CHG (1 << 2)
+#define PM8607_EVENT_BAT (1 << 3)
+#define PM8607_EVENT_RTC (1 << 4)
+#define PM8607_EVENT_CC (1 << 5)
+#define PM8607_EVENT_VBAT (1 << 8)
+#define PM8607_EVENT_VCHG (1 << 9)
+#define PM8607_EVENT_VSYS (1 << 10)
+#define PM8607_EVENT_TINT (1 << 11)
+#define PM8607_EVENT_GPADC0 (1 << 12)
+#define PM8607_EVENT_GPADC1 (1 << 13)
+#define PM8607_EVENT_GPADC2 (1 << 14)
+#define PM8607_EVENT_GPADC3 (1 << 15)
+#define PM8607_EVENT_AUDIO_SHORT (1 << 16)
+#define PM8607_EVENT_PEN (1 << 17)
+#define PM8607_EVENT_HEADSET (1 << 18)
+#define PM8607_EVENT_HOOK (1 << 19)
+#define PM8607_EVENT_MICIN (1 << 20)
+#define PM8607_EVENT_CHG_TIMEOUT (1 << 21)
+#define PM8607_EVENT_CHG_DONE (1 << 22)
+#define PM8607_EVENT_CHG_FAULT (1 << 23)
+
+/* bit definitions of Status Query Interface */
+#define PM8607_STATUS_CC (1 << 3)
+#define PM8607_STATUS_PEN (1 << 4)
+#define PM8607_STATUS_HEADSET (1 << 5)
+#define PM8607_STATUS_HOOK (1 << 6)
+#define PM8607_STATUS_MICIN (1 << 7)
+#define PM8607_STATUS_ONKEY (1 << 8)
+#define PM8607_STATUS_EXTON (1 << 9)
+#define PM8607_STATUS_CHG (1 << 10)
+#define PM8607_STATUS_BAT (1 << 11)
+#define PM8607_STATUS_VBUS (1 << 12)
+#define PM8607_STATUS_OV (1 << 13)
+
+/* bit definitions of BUCK3 */
+#define PM8607_BUCK3_DOUBLE (1 << 6)
+
+/* bit definitions of Misc1 */
+#define PM8607_MISC1_PI2C (1 << 0)
+
+/* Interrupt Number in 88PM8607 */
+enum {
+ PM8607_IRQ_ONKEY = 0,
+ PM8607_IRQ_EXTON,
+ PM8607_IRQ_CHG,
+ PM8607_IRQ_BAT,
+ PM8607_IRQ_RTC,
+ PM8607_IRQ_VBAT = 8,
+ PM8607_IRQ_VCHG,
+ PM8607_IRQ_VSYS,
+ PM8607_IRQ_TINT,
+ PM8607_IRQ_GPADC0,
+ PM8607_IRQ_GPADC1,
+ PM8607_IRQ_GPADC2,
+ PM8607_IRQ_GPADC3,
+ PM8607_IRQ_AUDIO_SHORT = 16,
+ PM8607_IRQ_PEN,
+ PM8607_IRQ_HEADSET,
+ PM8607_IRQ_HOOK,
+ PM8607_IRQ_MICIN,
+ PM8607_IRQ_CHG_FAIL,
+ PM8607_IRQ_CHG_DONE,
+ PM8607_IRQ_CHG_FAULT,
+};
+
+enum {
+ PM8607_CHIP_A0 = 0x40,
+ PM8607_CHIP_A1 = 0x41,
+ PM8607_CHIP_B0 = 0x48,
+};
+
+
+struct pm8607_chip {
+ struct device *dev;
+ struct mutex io_lock;
+ struct i2c_client *client;
+
+ int (*read)(struct pm8607_chip *chip, int reg, int bytes, void *dest);
+ int (*write)(struct pm8607_chip *chip, int reg, int bytes, void *src);
+
+ int buck3_double; /* DVC ramp slope double */
+ unsigned char chip_id;
+
+};
+
+#define PM8607_MAX_REGULATOR 15 /* 3 Bucks, 12 LDOs */
+
+enum {
+ GI2C_PORT = 0,
+ PI2C_PORT,
+};
+
+struct pm8607_platform_data {
+ int i2c_port; /* Controlled by GI2C or PI2C */
+ struct regulator_init_data *regulator[PM8607_MAX_REGULATOR];
+};
+
+extern int pm8607_reg_read(struct pm8607_chip *, int);
+extern int pm8607_reg_write(struct pm8607_chip *, int, unsigned char);
+extern int pm8607_bulk_read(struct pm8607_chip *, int, int,
+ unsigned char *);
+extern int pm8607_bulk_write(struct pm8607_chip *, int, int,
+ unsigned char *);
+extern int pm8607_set_bits(struct pm8607_chip *, int, unsigned char,
+ unsigned char);
+#endif /* __LINUX_MFD_88PM8607_H */
diff --git a/include/linux/mfd/ab4500.h b/include/linux/mfd/ab4500.h
new file mode 100644
index 000000000000..a42a7033ae53
--- /dev/null
+++ b/include/linux/mfd/ab4500.h
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2009 ST-Ericsson
+ *
+ * Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.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.
+ *
+ * AB4500 device core funtions, for client access
+ */
+#ifndef MFD_AB4500_H
+#define MFD_AB4500_H
+
+#include <linux/device.h>
+
+/*
+ * AB4500 bank addresses
+ */
+#define AB4500_SYS_CTRL1_BLOCK 0x1
+#define AB4500_SYS_CTRL2_BLOCK 0x2
+#define AB4500_REGU_CTRL1 0x3
+#define AB4500_REGU_CTRL2 0x4
+#define AB4500_USB 0x5
+#define AB4500_TVOUT 0x6
+#define AB4500_DBI 0x7
+#define AB4500_ECI_AV_ACC 0x8
+#define AB4500_RESERVED 0x9
+#define AB4500_GPADC 0xA
+#define AB4500_CHARGER 0xB
+#define AB4500_GAS_GAUGE 0xC
+#define AB4500_AUDIO 0xD
+#define AB4500_INTERRUPT 0xE
+#define AB4500_RTC 0xF
+#define AB4500_MISC 0x10
+#define AB4500_DEBUG 0x12
+#define AB4500_PROD_TEST 0x13
+#define AB4500_OTP_EMUL 0x15
+
+/*
+ * System control 1 register offsets.
+ * Bank = 0x01
+ */
+#define AB4500_TURNON_STAT_REG 0x0100
+#define AB4500_RESET_STAT_REG 0x0101
+#define AB4500_PONKEY1_PRESS_STAT_REG 0x0102
+
+#define AB4500_FSM_STAT1_REG 0x0140
+#define AB4500_FSM_STAT2_REG 0x0141
+#define AB4500_SYSCLK_REQ_STAT_REG 0x0142
+#define AB4500_USB_STAT1_REG 0x0143
+#define AB4500_USB_STAT2_REG 0x0144
+#define AB4500_STATUS_SPARE1_REG 0x0145
+#define AB4500_STATUS_SPARE2_REG 0x0146
+
+#define AB4500_CTRL1_REG 0x0180
+#define AB4500_CTRL2_REG 0x0181
+
+/*
+ * System control 2 register offsets.
+ * bank = 0x02
+ */
+#define AB4500_CTRL3_REG 0x0200
+#define AB4500_MAIN_WDOG_CTRL_REG 0x0201
+#define AB4500_MAIN_WDOG_TIMER_REG 0x0202
+#define AB4500_LOW_BAT_REG 0x0203
+#define AB4500_BATT_OK_REG 0x0204
+#define AB4500_SYSCLK_TIMER_REG 0x0205
+#define AB4500_SMPSCLK_CTRL_REG 0x0206
+#define AB4500_SMPSCLK_SEL1_REG 0x0207
+#define AB4500_SMPSCLK_SEL2_REG 0x0208
+#define AB4500_SMPSCLK_SEL3_REG 0x0209
+#define AB4500_SYSULPCLK_CONF_REG 0x020A
+#define AB4500_SYSULPCLK_CTRL1_REG 0x020B
+#define AB4500_SYSCLK_CTRL_REG 0x020C
+#define AB4500_SYSCLK_REQ1_VALID_REG 0x020D
+#define AB4500_SYSCLK_REQ_VALID_REG 0x020E
+#define AB4500_SYSCTRL_SPARE_REG 0x020F
+#define AB4500_PAD_CONF_REG 0x0210
+
+/*
+ * Regu control1 register offsets
+ * Bank = 0x03
+ */
+#define AB4500_REGU_SERIAL_CTRL1_REG 0x0300
+#define AB4500_REGU_SERIAL_CTRL2_REG 0x0301
+#define AB4500_REGU_SERIAL_CTRL3_REG 0x0302
+#define AB4500_REGU_REQ_CTRL1_REG 0x0303
+#define AB4500_REGU_REQ_CTRL2_REG 0x0304
+#define AB4500_REGU_REQ_CTRL3_REG 0x0305
+#define AB4500_REGU_REQ_CTRL4_REG 0x0306
+#define AB4500_REGU_MISC1_REG 0x0380
+#define AB4500_REGU_OTGSUPPLY_CTRL_REG 0x0381
+#define AB4500_REGU_VUSB_CTRL_REG 0x0382
+#define AB4500_REGU_VAUDIO_SUPPLY_REG 0x0383
+#define AB4500_REGU_CTRL1_SPARE_REG 0x0384
+
+/*
+ * Regu control2 Vmod register offsets
+ */
+#define AB4500_REGU_VMOD_REGU_REG 0x0440
+#define AB4500_REGU_VMOD_SEL1_REG 0x0441
+#define AB4500_REGU_VMOD_SEL2_REG 0x0442
+#define AB4500_REGU_CTRL_DISCH_REG 0x0443
+#define AB4500_REGU_CTRL_DISCH2_REG 0x0444
+
+/*
+ * USB/ULPI register offsets
+ * Bank : 0x5
+ */
+#define AB4500_USB_LINE_STAT_REG 0x0580
+#define AB4500_USB_LINE_CTRL1_REG 0x0581
+#define AB4500_USB_LINE_CTRL2_REG 0x0582
+#define AB4500_USB_LINE_CTRL3_REG 0x0583
+#define AB4500_USB_LINE_CTRL4_REG 0x0584
+#define AB4500_USB_LINE_CTRL5_REG 0x0585
+#define AB4500_USB_OTG_CTRL_REG 0x0587
+#define AB4500_USB_OTG_STAT_REG 0x0588
+#define AB4500_USB_OTG_STAT_REG 0x0588
+#define AB4500_USB_CTRL_SPARE_REG 0x0589
+#define AB4500_USB_PHY_CTRL_REG 0x058A
+
+/*
+ * TVOUT / CTRL register offsets
+ * Bank : 0x06
+ */
+#define AB4500_TVOUT_CTRL_REG 0x0680
+
+/*
+ * DBI register offsets
+ * Bank : 0x07
+ */
+#define AB4500_DBI_REG1_REG 0x0700
+#define AB4500_DBI_REG2_REG 0x0701
+
+/*
+ * ECI regsiter offsets
+ * Bank : 0x08
+ */
+#define AB4500_ECI_CTRL_REG 0x0800
+#define AB4500_ECI_HOOKLEVEL_REG 0x0801
+#define AB4500_ECI_DATAOUT_REG 0x0802
+#define AB4500_ECI_DATAIN_REG 0x0803
+
+/*
+ * AV Connector register offsets
+ * Bank : 0x08
+ */
+#define AB4500_AV_CONN_REG 0x0840
+
+/*
+ * Accessory detection register offsets
+ * Bank : 0x08
+ */
+#define AB4500_ACC_DET_DB1_REG 0x0880
+#define AB4500_ACC_DET_DB2_REG 0x0881
+
+/*
+ * GPADC register offsets
+ * Bank : 0x0A
+ */
+#define AB4500_GPADC_CTRL1_REG 0x0A00
+#define AB4500_GPADC_CTRL2_REG 0x0A01
+#define AB4500_GPADC_CTRL3_REG 0x0A02
+#define AB4500_GPADC_AUTO_TIMER_REG 0x0A03
+#define AB4500_GPADC_STAT_REG 0x0A04
+#define AB4500_GPADC_MANDATAL_REG 0x0A05
+#define AB4500_GPADC_MANDATAH_REG 0x0A06
+#define AB4500_GPADC_AUTODATAL_REG 0x0A07
+#define AB4500_GPADC_AUTODATAH_REG 0x0A08
+#define AB4500_GPADC_MUX_CTRL_REG 0x0A09
+
+/*
+ * Charger / status register offfsets
+ * Bank : 0x0B
+ */
+#define AB4500_CH_STATUS1_REG 0x0B00
+#define AB4500_CH_STATUS2_REG 0x0B01
+#define AB4500_CH_USBCH_STAT1_REG 0x0B02
+#define AB4500_CH_USBCH_STAT2_REG 0x0B03
+#define AB4500_CH_FSM_STAT_REG 0x0B04
+#define AB4500_CH_STAT_REG 0x0B05
+
+/*
+ * Charger / control register offfsets
+ * Bank : 0x0B
+ */
+#define AB4500_CH_VOLT_LVL_REG 0x0B40
+
+/*
+ * Charger / main control register offfsets
+ * Bank : 0x0B
+ */
+#define AB4500_MCH_CTRL1 0x0B80
+#define AB4500_MCH_CTRL2 0x0B81
+#define AB4500_MCH_IPT_CURLVL_REG 0x0B82
+#define AB4500_CH_WD_REG 0x0B83
+
+/*
+ * Charger / USB control register offsets
+ * Bank : 0x0B
+ */
+#define AB4500_USBCH_CTRL1_REG 0x0BC0
+#define AB4500_USBCH_CTRL2_REG 0x0BC1
+#define AB4500_USBCH_IPT_CRNTLVL_REG 0x0BC2
+
+/*
+ * RTC bank register offsets
+ * Bank : 0xF
+ */
+#define AB4500_RTC_SOFF_STAT_REG 0x0F00
+#define AB4500_RTC_CC_CONF_REG 0x0F01
+#define AB4500_RTC_READ_REQ_REG 0x0F02
+#define AB4500_RTC_WATCH_TSECMID_REG 0x0F03
+#define AB4500_RTC_WATCH_TSECHI_REG 0x0F04
+#define AB4500_RTC_WATCH_TMIN_LOW_REG 0x0F05
+#define AB4500_RTC_WATCH_TMIN_MID_REG 0x0F06
+#define AB4500_RTC_WATCH_TMIN_HI_REG 0x0F07
+#define AB4500_RTC_ALRM_MIN_LOW_REG 0x0F08
+#define AB4500_RTC_ALRM_MIN_MID_REG 0x0F09
+#define AB4500_RTC_ALRM_MIN_HI_REG 0x0F0A
+#define AB4500_RTC_STAT_REG 0x0F0B
+#define AB4500_RTC_BKUP_CHG_REG 0x0F0C
+#define AB4500_RTC_FORCE_BKUP_REG 0x0F0D
+#define AB4500_RTC_CALIB_REG 0x0F0E
+#define AB4500_RTC_SWITCH_STAT_REG 0x0F0F
+
+/*
+ * PWM Out generators
+ * Bank: 0x10
+ */
+#define AB4500_PWM_OUT_CTRL1_REG 0x1060
+#define AB4500_PWM_OUT_CTRL2_REG 0x1061
+#define AB4500_PWM_OUT_CTRL3_REG 0x1062
+#define AB4500_PWM_OUT_CTRL4_REG 0x1063
+#define AB4500_PWM_OUT_CTRL5_REG 0x1064
+#define AB4500_PWM_OUT_CTRL6_REG 0x1065
+#define AB4500_PWM_OUT_CTRL7_REG 0x1066
+
+#define AB4500_I2C_PAD_CTRL_REG 0x1067
+#define AB4500_REV_REG 0x1080
+
+/**
+ * struct ab4500
+ * @spi: spi device structure
+ * @tx_buf: transmit buffer
+ * @rx_buf: receive buffer
+ * @lock: sync primitive
+ */
+struct ab4500 {
+ struct spi_device *spi;
+ unsigned long tx_buf[4];
+ unsigned long rx_buf[4];
+ struct mutex lock;
+};
+
+int ab4500_write(struct ab4500 *ab4500, unsigned char block,
+ unsigned long addr, unsigned char data);
+int ab4500_read(struct ab4500 *ab4500, unsigned char block,
+ unsigned long addr);
+
+#endif /* MFD_AB4500_H */
diff --git a/include/linux/mfd/adp5520.h b/include/linux/mfd/adp5520.h
new file mode 100644
index 000000000000..ac37558a4673
--- /dev/null
+++ b/include/linux/mfd/adp5520.h
@@ -0,0 +1,299 @@
+/*
+ * Definitions and platform data for Analog Devices
+ * ADP5520/ADP5501 MFD PMICs (Backlight, LED, GPIO and Keys)
+ *
+ * Copyright 2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+
+#ifndef __LINUX_MFD_ADP5520_H
+#define __LINUX_MFD_ADP5520_H
+
+#define ID_ADP5520 5520
+#define ID_ADP5501 5501
+
+/*
+ * ADP5520/ADP5501 Register Map
+ */
+
+#define ADP5520_MODE_STATUS 0x00
+#define ADP5520_INTERRUPT_ENABLE 0x01
+#define ADP5520_BL_CONTROL 0x02
+#define ADP5520_BL_TIME 0x03
+#define ADP5520_BL_FADE 0x04
+#define ADP5520_DAYLIGHT_MAX 0x05
+#define ADP5520_DAYLIGHT_DIM 0x06
+#define ADP5520_OFFICE_MAX 0x07
+#define ADP5520_OFFICE_DIM 0x08
+#define ADP5520_DARK_MAX 0x09
+#define ADP5520_DARK_DIM 0x0A
+#define ADP5520_BL_VALUE 0x0B
+#define ADP5520_ALS_CMPR_CFG 0x0C
+#define ADP5520_L2_TRIP 0x0D
+#define ADP5520_L2_HYS 0x0E
+#define ADP5520_L3_TRIP 0x0F
+#define ADP5520_L3_HYS 0x10
+#define ADP5520_LED_CONTROL 0x11
+#define ADP5520_LED_TIME 0x12
+#define ADP5520_LED_FADE 0x13
+#define ADP5520_LED1_CURRENT 0x14
+#define ADP5520_LED2_CURRENT 0x15
+#define ADP5520_LED3_CURRENT 0x16
+
+/*
+ * ADP5520 Register Map
+ */
+
+#define ADP5520_GPIO_CFG_1 0x17
+#define ADP5520_GPIO_CFG_2 0x18
+#define ADP5520_GPIO_IN 0x19
+#define ADP5520_GPIO_OUT 0x1A
+#define ADP5520_GPIO_INT_EN 0x1B
+#define ADP5520_GPIO_INT_STAT 0x1C
+#define ADP5520_GPIO_INT_LVL 0x1D
+#define ADP5520_GPIO_DEBOUNCE 0x1E
+#define ADP5520_GPIO_PULLUP 0x1F
+#define ADP5520_KP_INT_STAT_1 0x20
+#define ADP5520_KP_INT_STAT_2 0x21
+#define ADP5520_KR_INT_STAT_1 0x22
+#define ADP5520_KR_INT_STAT_2 0x23
+#define ADP5520_KEY_STAT_1 0x24
+#define ADP5520_KEY_STAT_2 0x25
+
+/*
+ * MODE_STATUS bits
+ */
+
+#define ADP5520_nSTNBY (1 << 7)
+#define ADP5520_BL_EN (1 << 6)
+#define ADP5520_DIM_EN (1 << 5)
+#define ADP5520_OVP_INT (1 << 4)
+#define ADP5520_CMPR_INT (1 << 3)
+#define ADP5520_GPI_INT (1 << 2)
+#define ADP5520_KR_INT (1 << 1)
+#define ADP5520_KP_INT (1 << 0)
+
+/*
+ * INTERRUPT_ENABLE bits
+ */
+
+#define ADP5520_AUTO_LD_EN (1 << 4)
+#define ADP5520_CMPR_IEN (1 << 3)
+#define ADP5520_OVP_IEN (1 << 2)
+#define ADP5520_KR_IEN (1 << 1)
+#define ADP5520_KP_IEN (1 << 0)
+
+/*
+ * BL_CONTROL bits
+ */
+
+#define ADP5520_BL_LVL ((x) << 5)
+#define ADP5520_BL_LAW ((x) << 4)
+#define ADP5520_BL_AUTO_ADJ (1 << 3)
+#define ADP5520_OVP_EN (1 << 2)
+#define ADP5520_FOVR (1 << 1)
+#define ADP5520_KP_BL_EN (1 << 0)
+
+/*
+ * ALS_CMPR_CFG bits
+ */
+
+#define ADP5520_L3_OUT (1 << 3)
+#define ADP5520_L2_OUT (1 << 2)
+#define ADP5520_L3_EN (1 << 1)
+
+#define ADP5020_MAX_BRIGHTNESS 0x7F
+
+#define FADE_VAL(in, out) ((0xF & (in)) | ((0xF & (out)) << 4))
+#define BL_CTRL_VAL(law, auto) (((1 & (auto)) << 3) | ((0x3 & (law)) << 4))
+#define ALS_CMPR_CFG_VAL(filt, l3_en) (((0x7 & filt) << 5) | l3_en)
+
+/*
+ * LEDs subdevice bits and masks
+ */
+
+#define ADP5520_01_MAXLEDS 3
+
+#define ADP5520_FLAG_LED_MASK 0x3
+#define ADP5520_FLAG_OFFT_SHIFT 8
+#define ADP5520_FLAG_OFFT_MASK 0x3
+
+#define ADP5520_R3_MODE (1 << 5)
+#define ADP5520_C3_MODE (1 << 4)
+#define ADP5520_LED_LAW (1 << 3)
+#define ADP5520_LED3_EN (1 << 2)
+#define ADP5520_LED2_EN (1 << 1)
+#define ADP5520_LED1_EN (1 << 0)
+
+/*
+ * GPIO subdevice bits and masks
+ */
+
+#define ADP5520_MAXGPIOS 8
+
+#define ADP5520_GPIO_C3 (1 << 7) /* LED2 or GPIO7 aka C3 */
+#define ADP5520_GPIO_C2 (1 << 6)
+#define ADP5520_GPIO_C1 (1 << 5)
+#define ADP5520_GPIO_C0 (1 << 4)
+#define ADP5520_GPIO_R3 (1 << 3) /* LED3 or GPIO3 aka R3 */
+#define ADP5520_GPIO_R2 (1 << 2)
+#define ADP5520_GPIO_R1 (1 << 1)
+#define ADP5520_GPIO_R0 (1 << 0)
+
+struct adp5520_gpio_platform_data {
+ unsigned gpio_start;
+ u8 gpio_en_mask;
+ u8 gpio_pullup_mask;
+};
+
+/*
+ * Keypad subdevice bits and masks
+ */
+
+#define ADP5520_MAXKEYS 16
+
+#define ADP5520_COL_C3 (1 << 7) /* LED2 or GPIO7 aka C3 */
+#define ADP5520_COL_C2 (1 << 6)
+#define ADP5520_COL_C1 (1 << 5)
+#define ADP5520_COL_C0 (1 << 4)
+#define ADP5520_ROW_R3 (1 << 3) /* LED3 or GPIO3 aka R3 */
+#define ADP5520_ROW_R2 (1 << 2)
+#define ADP5520_ROW_R1 (1 << 1)
+#define ADP5520_ROW_R0 (1 << 0)
+
+#define ADP5520_KEY(row, col) (col + row * 4)
+#define ADP5520_KEYMAPSIZE ADP5520_MAXKEYS
+
+struct adp5520_keys_platform_data {
+ int rows_en_mask; /* Number of rows */
+ int cols_en_mask; /* Number of columns */
+ const unsigned short *keymap; /* Pointer to keymap */
+ unsigned short keymapsize; /* Keymap size */
+ unsigned repeat:1; /* Enable key repeat */
+};
+
+
+/*
+ * LEDs subdevice platform data
+ */
+
+#define FLAG_ID_ADP5520_LED1_ADP5501_LED0 1 /* ADP5520 PIN ILED */
+#define FLAG_ID_ADP5520_LED2_ADP5501_LED1 2 /* ADP5520 PIN C3 */
+#define FLAG_ID_ADP5520_LED3_ADP5501_LED2 3 /* ADP5520 PIN R3 */
+
+#define ADP5520_LED_DIS_BLINK (0 << ADP5520_FLAG_OFFT_SHIFT)
+#define ADP5520_LED_OFFT_600ms (1 << ADP5520_FLAG_OFFT_SHIFT)
+#define ADP5520_LED_OFFT_800ms (2 << ADP5520_FLAG_OFFT_SHIFT)
+#define ADP5520_LED_OFFT_1200ms (3 << ADP5520_FLAG_OFFT_SHIFT)
+
+#define ADP5520_LED_ONT_200ms 0
+#define ADP5520_LED_ONT_600ms 1
+#define ADP5520_LED_ONT_800ms 2
+#define ADP5520_LED_ONT_1200ms 3
+
+struct adp5520_leds_platform_data {
+ int num_leds;
+ struct led_info *leds;
+ u8 fade_in; /* Backlight Fade-In Timer */
+ u8 fade_out; /* Backlight Fade-Out Timer */
+ u8 led_on_time;
+};
+
+/*
+ * Backlight subdevice platform data
+ */
+
+#define ADP5520_FADE_T_DIS 0 /* Fade Timer Disabled */
+#define ADP5520_FADE_T_300ms 1 /* 0.3 Sec */
+#define ADP5520_FADE_T_600ms 2
+#define ADP5520_FADE_T_900ms 3
+#define ADP5520_FADE_T_1200ms 4
+#define ADP5520_FADE_T_1500ms 5
+#define ADP5520_FADE_T_1800ms 6
+#define ADP5520_FADE_T_2100ms 7
+#define ADP5520_FADE_T_2400ms 8
+#define ADP5520_FADE_T_2700ms 9
+#define ADP5520_FADE_T_3000ms 10
+#define ADP5520_FADE_T_3500ms 11
+#define ADP5520_FADE_T_4000ms 12
+#define ADP5520_FADE_T_4500ms 13
+#define ADP5520_FADE_T_5000ms 14
+#define ADP5520_FADE_T_5500ms 15 /* 5.5 Sec */
+
+#define ADP5520_BL_LAW_LINEAR 0
+#define ADP5520_BL_LAW_SQUARE 1
+#define ADP5520_BL_LAW_CUBIC1 2
+#define ADP5520_BL_LAW_CUBIC2 3
+
+#define ADP5520_BL_AMBL_FILT_80ms 0 /* Light sensor filter time */
+#define ADP5520_BL_AMBL_FILT_160ms 1
+#define ADP5520_BL_AMBL_FILT_320ms 2
+#define ADP5520_BL_AMBL_FILT_640ms 3
+#define ADP5520_BL_AMBL_FILT_1280ms 4
+#define ADP5520_BL_AMBL_FILT_2560ms 5
+#define ADP5520_BL_AMBL_FILT_5120ms 6
+#define ADP5520_BL_AMBL_FILT_10240ms 7 /* 10.24 sec */
+
+ /*
+ * Blacklight current 0..30mA
+ */
+#define ADP5520_BL_CUR_mA(I) ((I * 127) / 30)
+
+ /*
+ * L2 comparator current 0..1000uA
+ */
+#define ADP5520_L2_COMP_CURR_uA(I) ((I * 255) / 1000)
+
+ /*
+ * L3 comparator current 0..127uA
+ */
+#define ADP5520_L3_COMP_CURR_uA(I) ((I * 255) / 127)
+
+struct adp5520_backlight_platform_data {
+ u8 fade_in; /* Backlight Fade-In Timer */
+ u8 fade_out; /* Backlight Fade-Out Timer */
+ u8 fade_led_law; /* fade-on/fade-off transfer characteristic */
+
+ u8 en_ambl_sens; /* 1 = enable ambient light sensor */
+ u8 abml_filt; /* Light sensor filter time */
+ u8 l1_daylight_max; /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
+ u8 l1_daylight_dim; /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
+ u8 l2_office_max; /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
+ u8 l2_office_dim; /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
+ u8 l3_dark_max; /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
+ u8 l3_dark_dim; /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
+ u8 l2_trip; /* use L2_COMP_CURR_uA(I) 0 <= I <= 1000 uA */
+ u8 l2_hyst; /* use L2_COMP_CURR_uA(I) 0 <= I <= 1000 uA */
+ u8 l3_trip; /* use L3_COMP_CURR_uA(I) 0 <= I <= 127 uA */
+ u8 l3_hyst; /* use L3_COMP_CURR_uA(I) 0 <= I <= 127 uA */
+};
+
+/*
+ * MFD chip platform data
+ */
+
+struct adp5520_platform_data {
+ struct adp5520_keys_platform_data *keys;
+ struct adp5520_gpio_platform_data *gpio;
+ struct adp5520_leds_platform_data *leds;
+ struct adp5520_backlight_platform_data *backlight;
+};
+
+/*
+ * MFD chip functions
+ */
+
+extern int adp5520_read(struct device *dev, int reg, uint8_t *val);
+extern int adp5520_write(struct device *dev, int reg, u8 val);
+extern int adp5520_clr_bits(struct device *dev, int reg, uint8_t bit_mask);
+extern int adp5520_set_bits(struct device *dev, int reg, uint8_t bit_mask);
+
+extern int adp5520_register_notifier(struct device *dev,
+ struct notifier_block *nb, unsigned int events);
+
+extern int adp5520_unregister_notifier(struct device *dev,
+ struct notifier_block *nb, unsigned int events);
+
+#endif /* __LINUX_MFD_ADP5520_H */
diff --git a/include/linux/mfd/pcf50633/core.h b/include/linux/mfd/pcf50633/core.h
index 9aba7b779fbc..d9034cc87f18 100644
--- a/include/linux/mfd/pcf50633/core.h
+++ b/include/linux/mfd/pcf50633/core.h
@@ -40,10 +40,6 @@ struct pcf50633_platform_data {
u8 resumers[5];
};
-struct pcf50633_subdev_pdata {
- struct pcf50633 *pcf;
-};
-
struct pcf50633_irq {
void (*handler) (int, void *);
void *data;
@@ -217,5 +213,9 @@ enum pcf50633_reg_int5 {
#define PCF50633_REG_LEDCTL 0x2a
#define PCF50633_REG_LEDDIM 0x2b
-#endif
+static inline struct pcf50633 *dev_to_pcf50633(struct device *dev)
+{
+ return dev_get_drvdata(dev);
+}
+#endif
diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h
index 6b9c5d06690c..0992e7112d3f 100644
--- a/include/linux/mfd/tmio.h
+++ b/include/linux/mfd/tmio.h
@@ -2,6 +2,8 @@
#define MFD_TMIO_H
#include <linux/fb.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
#define tmio_ioread8(addr) readb(addr)
#define tmio_ioread16(addr) readw(addr)
@@ -18,11 +20,49 @@
writew((val) >> 16, (addr) + 2); \
} while (0)
+#define CNF_CMD 0x04
+#define CNF_CTL_BASE 0x10
+#define CNF_INT_PIN 0x3d
+#define CNF_STOP_CLK_CTL 0x40
+#define CNF_GCLK_CTL 0x41
+#define CNF_SD_CLK_MODE 0x42
+#define CNF_PIN_STATUS 0x44
+#define CNF_PWR_CTL_1 0x48
+#define CNF_PWR_CTL_2 0x49
+#define CNF_PWR_CTL_3 0x4a
+#define CNF_CARD_DETECT_MODE 0x4c
+#define CNF_SD_SLOT 0x50
+#define CNF_EXT_GCLK_CTL_1 0xf0
+#define CNF_EXT_GCLK_CTL_2 0xf1
+#define CNF_EXT_GCLK_CTL_3 0xf9
+#define CNF_SD_LED_EN_1 0xfa
+#define CNF_SD_LED_EN_2 0xfe
+
+#define SDCREN 0x2 /* Enable access to MMC CTL regs. (flag in COMMAND_REG)*/
+
+#define sd_config_write8(base, shift, reg, val) \
+ tmio_iowrite8((val), (base) + ((reg) << (shift)))
+#define sd_config_write16(base, shift, reg, val) \
+ tmio_iowrite16((val), (base) + ((reg) << (shift)))
+#define sd_config_write32(base, shift, reg, val) \
+ do { \
+ tmio_iowrite16((val), (base) + ((reg) << (shift))); \
+ tmio_iowrite16((val) >> 16, (base) + ((reg + 2) << (shift))); \
+ } while (0)
+
+int tmio_core_mmc_enable(void __iomem *cnf, unsigned long base);
+int tmio_core_mmc_resume(void __iomem *cnf, unsigned long base);
+void tmio_core_mmc_pwr(void __iomem *cnf, int state);
+void tmio_core_mmc_clk_div(void __iomem *cnf, int state);
+void tmio_core_set_bus_shift(int bus_shift);
+
/*
* data for the MMC controller
*/
struct tmio_mmc_data {
const unsigned int hclk;
+ void (*set_pwr)(struct platform_device *host, int state);
+ void (*set_no_clk_div)(struct platform_device *host, int state);
};
/*
diff --git a/include/linux/mfd/wm831x/core.h b/include/linux/mfd/wm831x/core.h
index 91eb493bf14c..d01d293a6b25 100644
--- a/include/linux/mfd/wm831x/core.h
+++ b/include/linux/mfd/wm831x/core.h
@@ -117,6 +117,7 @@
#define WM831X_DC3_SLEEP_CONTROL 0x4063
#define WM831X_DC4_CONTROL 0x4064
#define WM831X_DC4_SLEEP_CONTROL 0x4065
+#define WM832X_DC4_SLEEP_CONTROL 0x4067
#define WM831X_EPE1_CONTROL 0x4066
#define WM831X_EPE2_CONTROL 0x4067
#define WM831X_LDO1_CONTROL 0x4068
@@ -253,6 +254,8 @@ struct wm831x {
unsigned int irq_base;
int irq_masks[5];
+ int num_gpio;
+
struct mutex auxadc_lock;
/* The WM831x has a security key blocking access to certain
diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h
index 90d820260aad..318c13a4a92f 100644
--- a/include/linux/mfd/wm831x/pdata.h
+++ b/include/linux/mfd/wm831x/pdata.h
@@ -41,6 +41,23 @@ struct wm831x_battery_pdata {
int timeout; /** Charge cycle timeout, in minutes */
};
+/**
+ * Configuration for the WM831x DC-DC BuckWise convertors. This
+ * should be passed as driver_data in the regulator_init_data.
+ *
+ * Currently all the configuration is for the fast DVS switching
+ * support of the devices. This allows MFPs on the device to be
+ * configured as an input to switch between two output voltages,
+ * allowing voltage transitions without the expense of an access over
+ * I2C or SPI buses.
+ */
+struct wm831x_buckv_pdata {
+ int dvs_gpio; /** CPU GPIO to use for DVS switching */
+ int dvs_control_src; /** Hardware DVS source to use (1 or 2) */
+ int dvs_init_state; /** DVS state to expect on startup */
+ int dvs_state_gpio; /** CPU GPIO to use for monitoring status */
+};
+
/* Sources for status LED configuration. Values are register values
* plus 1 to allow for a zero default for preserve.
*/
diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h
index 1d595de6a055..ffce508a9109 100644
--- a/include/linux/mfd/wm8350/core.h
+++ b/include/linux/mfd/wm8350/core.h
@@ -646,10 +646,12 @@ struct wm8350 {
* @init: Function called during driver initialisation. Should be
* used by the platform to configure GPIO functions and similar.
* @irq_high: Set if WM8350 IRQ is active high.
+ * @irq_base: Base IRQ for genirq (not currently used).
*/
struct wm8350_platform_data {
int (*init)(struct wm8350 *wm8350);
int irq_high;
+ int irq_base;
};
@@ -681,6 +683,8 @@ int wm8350_register_irq(struct wm8350 *wm8350, int irq,
int wm8350_free_irq(struct wm8350 *wm8350, int irq);
int wm8350_mask_irq(struct wm8350 *wm8350, int irq);
int wm8350_unmask_irq(struct wm8350 *wm8350, int irq);
-
+int wm8350_irq_init(struct wm8350 *wm8350, int irq,
+ struct wm8350_platform_data *pdata);
+int wm8350_irq_exit(struct wm8350 *wm8350);
#endif
diff --git a/include/linux/mfd/wm8350/gpio.h b/include/linux/mfd/wm8350/gpio.h
index ed91e8f5d298..71af3d6ebe9d 100644
--- a/include/linux/mfd/wm8350/gpio.h
+++ b/include/linux/mfd/wm8350/gpio.h
@@ -173,6 +173,24 @@
#define WM8350_GPIO_DEBOUNCE_ON 1
/*
+ * R30 (0x1E) - GPIO Interrupt Status
+ */
+#define WM8350_GP12_EINT 0x1000
+#define WM8350_GP11_EINT 0x0800
+#define WM8350_GP10_EINT 0x0400
+#define WM8350_GP9_EINT 0x0200
+#define WM8350_GP8_EINT 0x0100
+#define WM8350_GP7_EINT 0x0080
+#define WM8350_GP6_EINT 0x0040
+#define WM8350_GP5_EINT 0x0020
+#define WM8350_GP4_EINT 0x0010
+#define WM8350_GP3_EINT 0x0008
+#define WM8350_GP2_EINT 0x0004
+#define WM8350_GP1_EINT 0x0002
+#define WM8350_GP0_EINT 0x0001
+
+
+/*
* R128 (0x80) - GPIO Debounce
*/
#define WM8350_GP12_DB 0x1000
diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
index 8a5509877192..ee24ef8ab616 100644
--- a/include/linux/mmdebug.h
+++ b/include/linux/mmdebug.h
@@ -1,8 +1,6 @@
#ifndef LINUX_MM_DEBUG_H
#define LINUX_MM_DEBUG_H 1
-#include <linux/autoconf.h>
-
#ifdef CONFIG_DEBUG_VM
#define VM_BUG_ON(cond) BUG_ON(cond)
#else
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 6f7561730d88..30fe668c2542 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -15,7 +15,7 @@
#include <linux/seqlock.h>
#include <linux/nodemask.h>
#include <linux/pageblock-flags.h>
-#include <linux/bounds.h>
+#include <generated/bounds.h>
#include <asm/atomic.h>
#include <asm/page.h>
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index 6547c3cdbc4c..82a9124f7d75 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -37,7 +37,6 @@ typedef int (*param_set_fn)(const char *val, struct kernel_param *kp);
typedef int (*param_get_fn)(char *buffer, struct kernel_param *kp);
/* Flag bits for kernel_param.flags */
-#define KPARAM_KMALLOCED 1
#define KPARAM_ISBOOL 2
struct kernel_param {
diff --git a/include/linux/mroute.h b/include/linux/mroute.h
index 08bc776d05e2..d5f69151f692 100644
--- a/include/linux/mroute.h
+++ b/include/linux/mroute.h
@@ -59,13 +59,18 @@ struct vifctl {
unsigned char vifc_flags; /* VIFF_ flags */
unsigned char vifc_threshold; /* ttl limit */
unsigned int vifc_rate_limit; /* Rate limiter values (NI) */
- struct in_addr vifc_lcl_addr; /* Our address */
+ union {
+ struct in_addr vifc_lcl_addr; /* Local interface address */
+ int vifc_lcl_ifindex; /* Local interface index */
+ };
struct in_addr vifc_rmt_addr; /* IPIP tunnel addr */
};
-#define VIFF_TUNNEL 0x1 /* IPIP tunnel */
-#define VIFF_SRCRT 0x2 /* NI */
-#define VIFF_REGISTER 0x4 /* register vif */
+#define VIFF_TUNNEL 0x1 /* IPIP tunnel */
+#define VIFF_SRCRT 0x2 /* NI */
+#define VIFF_REGISTER 0x4 /* register vif */
+#define VIFF_USE_IFINDEX 0x8 /* use vifc_lcl_ifindex instead of
+ vifc_lcl_addr to find an interface */
/*
* Cache manipulation structures for mrouted and PIMd
diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h
index fff8c53e5434..9c3757c5759d 100644
--- a/include/linux/mtd/bbm.h
+++ b/include/linux/mtd/bbm.h
@@ -19,22 +19,21 @@
/**
* struct nand_bbt_descr - bad block table descriptor
- * @options: options for this descriptor
- * @pages: the page(s) where we find the bbt, used with
- * option BBT_ABSPAGE when bbt is searched,
- * then we store the found bbts pages here.
- * Its an array and supports up to 8 chips now
- * @offs: offset of the pattern in the oob area of the page
- * @veroffs: offset of the bbt version counter in the oob area of the page
- * @version: version read from the bbt page during scan
- * @len: length of the pattern, if 0 no pattern check is performed
- * @maxblocks: maximum number of blocks to search for a bbt. This
- * number of blocks is reserved at the end of the device
- * where the tables are written.
- * @reserved_block_code: if non-0, this pattern denotes a reserved
- * (rather than bad) block in the stored bbt
- * @pattern: pattern to identify bad block table or factory marked
- * good / bad blocks, can be NULL, if len = 0
+ * @options: options for this descriptor
+ * @pages: the page(s) where we find the bbt, used with option BBT_ABSPAGE
+ * when bbt is searched, then we store the found bbts pages here.
+ * Its an array and supports up to 8 chips now
+ * @offs: offset of the pattern in the oob area of the page
+ * @veroffs: offset of the bbt version counter in the oob are of the page
+ * @version: version read from the bbt page during scan
+ * @len: length of the pattern, if 0 no pattern check is performed
+ * @maxblocks: maximum number of blocks to search for a bbt. This number of
+ * blocks is reserved at the end of the device where the tables are
+ * written.
+ * @reserved_block_code: if non-0, this pattern denotes a reserved (rather than
+ * bad) block in the stored bbt
+ * @pattern: pattern to identify bad block table or factory marked good /
+ * bad blocks, can be NULL, if len = 0
*
* Descriptor for the bad block table marker and the descriptor for the
* pattern which identifies good and bad blocks. The assumption is made
@@ -90,7 +89,9 @@ struct nand_bbt_descr {
/*
* Constants for oob configuration
*/
-#define ONENAND_BADBLOCK_POS 0
+#define NAND_SMALL_BADBLOCK_POS 5
+#define NAND_LARGE_BADBLOCK_POS 0
+#define ONENAND_BADBLOCK_POS 0
/*
* Bad block scanning errors
diff --git a/include/linux/mtd/flashchip.h b/include/linux/mtd/flashchip.h
index d4f38c5fd44e..f350a4879f75 100644
--- a/include/linux/mtd/flashchip.h
+++ b/include/linux/mtd/flashchip.h
@@ -38,6 +38,13 @@ typedef enum {
FL_XIP_WHILE_ERASING,
FL_XIP_WHILE_WRITING,
FL_SHUTDOWN,
+ /* These 2 come from nand_state_t, which has been unified here */
+ FL_READING,
+ FL_CACHEDPRG,
+ /* These 2 come from onenand_state_t, which has been unified here */
+ FL_RESETING,
+ FL_OTPING,
+
FL_UNKNOWN
} flstate_t;
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 7a232a9bdd62..2476078a032f 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -21,6 +21,8 @@
#include <linux/wait.h>
#include <linux/spinlock.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/flashchip.h>
+#include <linux/mtd/bbm.h>
struct mtd_info;
/* Scan and identify a NAND device */
@@ -202,20 +204,6 @@ typedef enum {
#define NAND_CI_CHIPNR_MSK 0x03
#define NAND_CI_CELLTYPE_MSK 0x0C
-/*
- * nand_state_t - chip states
- * Enumeration for NAND flash chip state
- */
-typedef enum {
- FL_READY,
- FL_READING,
- FL_WRITING,
- FL_ERASING,
- FL_SYNCING,
- FL_CACHEDPRG,
- FL_PM_SUSPENDED,
-} nand_state_t;
-
/* Keep gcc happy */
struct nand_chip;
@@ -402,7 +390,7 @@ struct nand_chip {
uint8_t cellinfo;
int badblockpos;
- nand_state_t state;
+ flstate_t state;
uint8_t *oob_poi;
struct nand_hw_control *controller;
@@ -470,75 +458,6 @@ struct nand_manufacturers {
extern struct nand_flash_dev nand_flash_ids[];
extern struct nand_manufacturers nand_manuf_ids[];
-/**
- * struct nand_bbt_descr - bad block table descriptor
- * @options: options for this descriptor
- * @pages: the page(s) where we find the bbt, used with option BBT_ABSPAGE
- * when bbt is searched, then we store the found bbts pages here.
- * Its an array and supports up to 8 chips now
- * @offs: offset of the pattern in the oob area of the page
- * @veroffs: offset of the bbt version counter in the oob are of the page
- * @version: version read from the bbt page during scan
- * @len: length of the pattern, if 0 no pattern check is performed
- * @maxblocks: maximum number of blocks to search for a bbt. This number of
- * blocks is reserved at the end of the device where the tables are
- * written.
- * @reserved_block_code: if non-0, this pattern denotes a reserved (rather than
- * bad) block in the stored bbt
- * @pattern: pattern to identify bad block table or factory marked good /
- * bad blocks, can be NULL, if len = 0
- *
- * Descriptor for the bad block table marker and the descriptor for the
- * pattern which identifies good and bad blocks. The assumption is made
- * that the pattern and the version count are always located in the oob area
- * of the first block.
- */
-struct nand_bbt_descr {
- int options;
- int pages[NAND_MAX_CHIPS];
- int offs;
- int veroffs;
- uint8_t version[NAND_MAX_CHIPS];
- int len;
- int maxblocks;
- int reserved_block_code;
- uint8_t *pattern;
-};
-
-/* Options for the bad block table descriptors */
-
-/* The number of bits used per block in the bbt on the device */
-#define NAND_BBT_NRBITS_MSK 0x0000000F
-#define NAND_BBT_1BIT 0x00000001
-#define NAND_BBT_2BIT 0x00000002
-#define NAND_BBT_4BIT 0x00000004
-#define NAND_BBT_8BIT 0x00000008
-/* The bad block table is in the last good block of the device */
-#define NAND_BBT_LASTBLOCK 0x00000010
-/* The bbt is at the given page, else we must scan for the bbt */
-#define NAND_BBT_ABSPAGE 0x00000020
-/* The bbt is at the given page, else we must scan for the bbt */
-#define NAND_BBT_SEARCH 0x00000040
-/* bbt is stored per chip on multichip devices */
-#define NAND_BBT_PERCHIP 0x00000080
-/* bbt has a version counter at offset veroffs */
-#define NAND_BBT_VERSION 0x00000100
-/* Create a bbt if none axists */
-#define NAND_BBT_CREATE 0x00000200
-/* Search good / bad pattern through all pages of a block */
-#define NAND_BBT_SCANALLPAGES 0x00000400
-/* Scan block empty during good / bad block scan */
-#define NAND_BBT_SCANEMPTY 0x00000800
-/* Write bbt if neccecary */
-#define NAND_BBT_WRITE 0x00001000
-/* Read and write back block contents when writing bbt */
-#define NAND_BBT_SAVECONTENT 0x00002000
-/* Search good / bad pattern on the first and the second page */
-#define NAND_BBT_SCAN2NDPAGE 0x00004000
-
-/* The maximum number of blocks to scan for a bbt */
-#define NAND_BBT_SCAN_MAXBLOCKS 4
-
extern int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
extern int nand_update_bbt(struct mtd_info *mtd, loff_t offs);
extern int nand_default_bbt(struct mtd_info *mtd);
@@ -548,12 +467,6 @@ extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, uint8_t * buf);
-/*
-* Constants for oob configuration
-*/
-#define NAND_SMALL_BADBLOCK_POS 5
-#define NAND_LARGE_BADBLOCK_POS 0
-
/**
* struct platform_nand_chip - chip level device structure
* @nr_chips: max. number of chips to scan for
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index 4e49f3350678..f57e29e17bb0 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -14,6 +14,7 @@
#include <linux/spinlock.h>
#include <linux/completion.h>
+#include <linux/mtd/flashchip.h>
#include <linux/mtd/onenand_regs.h>
#include <linux/mtd/bbm.h>
@@ -25,22 +26,6 @@ extern int onenand_scan(struct mtd_info *mtd, int max_chips);
/* Free resources held by the OneNAND device */
extern void onenand_release(struct mtd_info *mtd);
-/*
- * onenand_state_t - chip states
- * Enumeration for OneNAND flash chip state
- */
-typedef enum {
- FL_READY,
- FL_READING,
- FL_WRITING,
- FL_ERASING,
- FL_SYNCING,
- FL_LOCKING,
- FL_RESETING,
- FL_OTPING,
- FL_PM_SUSPENDED,
-} onenand_state_t;
-
/**
* struct onenand_bufferram - OneNAND BufferRAM Data
* @blockpage: block & page address in BufferRAM
@@ -137,7 +122,7 @@ struct onenand_chip {
spinlock_t chip_lock;
wait_queue_head_t wq;
- onenand_state_t state;
+ flstate_t state;
unsigned char *page_buf;
unsigned char *oob_buf;
diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h
index 6913b71d9ab2..b31bd9e9bca3 100644
--- a/include/linux/mtd/ubi.h
+++ b/include/linux/mtd/ubi.h
@@ -174,6 +174,8 @@ void ubi_get_volume_info(struct ubi_volume_desc *desc,
struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode);
struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
int mode);
+struct ubi_volume_desc *ubi_open_volume_path(const char *pathname, int mode);
+
int ubi_register_volume_notifier(struct notifier_block *nb,
int ignore_existing);
int ubi_unregister_volume_notifier(struct notifier_block *nb);
diff --git a/include/linux/net.h b/include/linux/net.h
index 529a0931711d..d7db1c98c3a1 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -41,6 +41,7 @@
#define SYS_SENDMSG 16 /* sys_sendmsg(2) */
#define SYS_RECVMSG 17 /* sys_recvmsg(2) */
#define SYS_ACCEPT4 18 /* sys_accept4(2) */
+#define SYS_RECVMMSG 19 /* sys_recvmmsg(2) */
typedef enum {
SS_FREE = 0, /* not allocated */
@@ -358,6 +359,7 @@ static const struct proto_ops name##_ops = { \
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
+#include <linux/ratelimit.h>
extern struct ratelimit_state net_ratelimit_state;
#endif
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 812a5f3c2abe..83800091a31a 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -909,7 +909,7 @@ struct net_device
#ifdef CONFIG_DCB
/* Data Center Bridging netlink ops */
- struct dcbnl_rtnl_ops *dcbnl_ops;
+ const struct dcbnl_rtnl_ops *dcbnl_ops;
#endif
#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index a8d71ed43a0e..50afca3dcff1 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1277,6 +1277,7 @@ enum nl80211_channel_type {
* @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
* in unspecified units, scaled to 0..100 (u8)
* @NL80211_BSS_STATUS: status, if this BSS is "used"
+ * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms
* @__NL80211_BSS_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute
*/
@@ -1291,6 +1292,7 @@ enum nl80211_bss {
NL80211_BSS_SIGNAL_MBM,
NL80211_BSS_SIGNAL_UNSPEC,
NL80211_BSS_STATUS,
+ NL80211_BSS_SEEN_MS_AGO,
/* keep last */
__NL80211_BSS_AFTER_LAST,
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 44428d247dbe..29714b8441b1 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -201,6 +201,7 @@ static inline int notifier_to_errno(int ret)
#define NETDEV_PRE_UP 0x000D
#define NETDEV_BONDING_OLDTYPE 0x000E
#define NETDEV_BONDING_NEWTYPE 0x000F
+#define NETDEV_POST_INIT 0x0010
#define SYS_DOWN 0x0001 /* Notify of system down */
#define SYS_RESTART SYS_DOWN
diff --git a/include/linux/of.h b/include/linux/of.h
index 7be2d1043c16..e7facd8fbce8 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -17,14 +17,117 @@
*/
#include <linux/types.h>
#include <linux/bitops.h>
+#include <linux/kref.h>
#include <linux/mod_devicetable.h>
+typedef u32 phandle;
+typedef u32 ihandle;
+
+struct property {
+ char *name;
+ int length;
+ void *value;
+ struct property *next;
+ unsigned long _flags;
+ unsigned int unique_id;
+};
+
+#if defined(CONFIG_SPARC)
+struct of_irq_controller;
+#endif
+
+struct device_node {
+ const char *name;
+ const char *type;
+ phandle node;
+#if !defined(CONFIG_SPARC)
+ phandle linux_phandle;
+#endif
+ char *full_name;
+
+ struct property *properties;
+ struct property *deadprops; /* removed properties */
+ struct device_node *parent;
+ struct device_node *child;
+ struct device_node *sibling;
+ struct device_node *next; /* next device of same type */
+ struct device_node *allnext; /* next in list of all nodes */
+ struct proc_dir_entry *pde; /* this node's proc directory */
+ struct kref kref;
+ unsigned long _flags;
+ void *data;
+#if defined(CONFIG_SPARC)
+ char *path_component_name;
+ unsigned int unique_id;
+ struct of_irq_controller *irq_trans;
+#endif
+};
+
+static inline int of_node_check_flag(struct device_node *n, unsigned long flag)
+{
+ return test_bit(flag, &n->_flags);
+}
+
+static inline void of_node_set_flag(struct device_node *n, unsigned long flag)
+{
+ set_bit(flag, &n->_flags);
+}
+
+static inline void
+set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
+{
+ dn->pde = de;
+}
+
+extern struct device_node *of_find_all_nodes(struct device_node *prev);
+
+#if defined(CONFIG_SPARC)
+/* Dummy ref counting routines - to be implemented later */
+static inline struct device_node *of_node_get(struct device_node *node)
+{
+ return node;
+}
+static inline void of_node_put(struct device_node *node)
+{
+}
+
+#else
+extern struct device_node *of_node_get(struct device_node *node);
+extern void of_node_put(struct device_node *node);
+#endif
+
+/*
+ * OF address retreival & translation
+ */
+
+/* Helper to read a big number; size is in cells (not bytes) */
+static inline u64 of_read_number(const u32 *cell, int size)
+{
+ u64 r = 0;
+ while (size--)
+ r = (r << 32) | *(cell++);
+ return r;
+}
+
+/* Like of_read_number, but we want an unsigned long result */
+#ifdef CONFIG_PPC32
+static inline unsigned long of_read_ulong(const u32 *cell, int size)
+{
+ return cell[size-1];
+}
+#else
+#define of_read_ulong(cell, size) of_read_number(cell, size)
+#endif
+
#include <asm/prom.h>
/* flag descriptions */
#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
#define OF_DETACHED 2 /* node has been detached from the device tree */
+#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
+#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
+
#define OF_BAD_ADDR ((u64)-1)
extern struct device_node *of_find_node_by_name(struct device_node *from,
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
new file mode 100644
index 000000000000..41d432b13553
--- /dev/null
+++ b/include/linux/of_fdt.h
@@ -0,0 +1,86 @@
+/*
+ * Definitions for working with the Flattened Device Tree data format
+ *
+ * Copyright 2009 Benjamin Herrenschmidt, IBM Corp
+ * benh@kernel.crashing.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.
+ */
+
+#ifndef _LINUX_OF_FDT_H
+#define _LINUX_OF_FDT_H
+
+#include <linux/types.h>
+#include <linux/init.h>
+
+/* Definitions used by the flattened device tree */
+#define OF_DT_HEADER 0xd00dfeed /* marker */
+#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */
+#define OF_DT_END_NODE 0x2 /* End node */
+#define OF_DT_PROP 0x3 /* Property: name off, size,
+ * content */
+#define OF_DT_NOP 0x4 /* nop */
+#define OF_DT_END 0x9
+
+#define OF_DT_VERSION 0x10
+
+#ifndef __ASSEMBLY__
+/*
+ * This is what gets passed to the kernel by prom_init or kexec
+ *
+ * The dt struct contains the device tree structure, full pathes and
+ * property contents. The dt strings contain a separate block with just
+ * the strings for the property names, and is fully page aligned and
+ * self contained in a page, so that it can be kept around by the kernel,
+ * each property name appears only once in this page (cheap compression)
+ *
+ * the mem_rsvmap contains a map of reserved ranges of physical memory,
+ * passing it here instead of in the device-tree itself greatly simplifies
+ * the job of everybody. It's just a list of u64 pairs (base/size) that
+ * ends when size is 0
+ */
+struct boot_param_header {
+ u32 magic; /* magic word OF_DT_HEADER */
+ u32 totalsize; /* total size of DT block */
+ u32 off_dt_struct; /* offset to structure */
+ u32 off_dt_strings; /* offset to strings */
+ u32 off_mem_rsvmap; /* offset to memory reserve map */
+ u32 version; /* format version */
+ u32 last_comp_version; /* last compatible version */
+ /* version 2 fields below */
+ u32 boot_cpuid_phys; /* Physical CPU id we're booting on */
+ /* version 3 fields below */
+ u32 dt_strings_size; /* size of the DT strings block */
+ /* version 17 fields below */
+ u32 dt_struct_size; /* size of the DT structure block */
+};
+
+/* For scanning the flat device-tree at boot time */
+extern int __init of_scan_flat_dt(int (*it)(unsigned long node,
+ const char *uname, int depth,
+ void *data),
+ void *data);
+extern void __init *of_get_flat_dt_prop(unsigned long node, const char *name,
+ unsigned long *size);
+extern int __init of_flat_dt_is_compatible(unsigned long node,
+ const char *name);
+extern unsigned long __init of_get_flat_dt_root(void);
+
+/* Other Prototypes */
+extern void finish_device_tree(void);
+extern void unflatten_device_tree(void);
+extern void early_init_devtree(void *);
+extern int machine_is_compatible(const char *compat);
+extern void print_properties(struct device_node *node);
+extern int prom_n_intr_cells(struct device_node* np);
+extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
+extern int prom_add_property(struct device_node* np, struct property* prop);
+extern int prom_remove_property(struct device_node *np, struct property *prop);
+extern int prom_update_property(struct device_node *np,
+ struct property *newprop,
+ struct property *oldprop);
+
+#endif /* __ASSEMBLY__ */
+#endif /* _LINUX_OF_FDT_H */
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 6b202b173955..ef36725aa515 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -8,7 +8,7 @@
#include <linux/types.h>
#ifndef __GENERATING_BOUNDS_H
#include <linux/mm_types.h>
-#include <linux/bounds.h>
+#include <generated/bounds.h>
#endif /* !__GENERATING_BOUNDS_H */
/*
diff --git a/include/linux/pci.h b/include/linux/pci.h
index f5c7cd343e56..4fafc563684d 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -566,6 +566,7 @@ void pcibios_update_irq(struct pci_dev *, int irq);
/* Generic PCI functions used internally */
+void pcibios_scan_specific_bus(int busn);
extern struct pci_bus *pci_find_bus(int domain, int busnr);
void pci_bus_add_devices(const struct pci_bus *bus);
struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus,
@@ -701,6 +702,7 @@ void pci_disable_device(struct pci_dev *dev);
void pci_set_master(struct pci_dev *dev);
void pci_clear_master(struct pci_dev *dev);
int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state);
+int pci_set_cacheline_size(struct pci_dev *dev);
#define HAVE_PCI_SET_MWI
int __must_check pci_set_mwi(struct pci_dev *dev);
int pci_try_set_mwi(struct pci_dev *dev);
@@ -1246,6 +1248,8 @@ extern int pci_pci_problems;
extern unsigned long pci_cardbus_io_size;
extern unsigned long pci_cardbus_mem_size;
+extern u8 pci_dfl_cache_line_size;
+extern u8 pci_cache_line_size;
extern unsigned long pci_hotplug_io_size;
extern unsigned long pci_hotplug_mem_size;
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index f490e7a7307a..b56d98b49e9a 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -379,9 +379,6 @@
#define PCI_DEVICE_ID_ATI_IXP600_IDE 0x438c
#define PCI_DEVICE_ID_ATI_IXP700_SATA 0x4390
#define PCI_DEVICE_ID_ATI_IXP700_IDE 0x439c
-/* AMD SB Chipset */
-#define PCI_DEVICE_ID_AMD_SB900_IDE 0x780c
-#define PCI_DEVICE_ID_AMD_SB900_SATA_IDE 0x7800
#define PCI_VENDOR_ID_VLSI 0x1004
#define PCI_DEVICE_ID_VLSI_82C592 0x0005
@@ -543,7 +540,7 @@
#define PCI_DEVICE_ID_AMD_8131_BRIDGE 0x7450
#define PCI_DEVICE_ID_AMD_8131_APIC 0x7451
#define PCI_DEVICE_ID_AMD_8132_BRIDGE 0x7458
-#define PCI_DEVICE_ID_AMD_SB900_SMBUS 0x780b
+#define PCI_DEVICE_ID_AMD_HUDSON2_SMBUS 0x780b
#define PCI_DEVICE_ID_AMD_CS5535_IDE 0x208F
#define PCI_DEVICE_ID_AMD_CS5536_ISA 0x2090
#define PCI_DEVICE_ID_AMD_CS5536_FLASH 0x2091
@@ -553,9 +550,10 @@
#define PCI_DEVICE_ID_AMD_CS5536_UDC 0x2096
#define PCI_DEVICE_ID_AMD_CS5536_UOC 0x2097
#define PCI_DEVICE_ID_AMD_CS5536_IDE 0x209A
-
#define PCI_DEVICE_ID_AMD_LX_VIDEO 0x2081
#define PCI_DEVICE_ID_AMD_LX_AES 0x2082
+#define PCI_DEVICE_ID_AMD_HUDSON2_IDE 0x780c
+#define PCI_DEVICE_ID_AMD_HUDSON2_SATA_IDE 0x7800
#define PCI_VENDOR_ID_TRIDENT 0x1023
#define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000
@@ -1632,6 +1630,8 @@
#define PCI_DEVICE_ID_O2_6730 0x673a
#define PCI_DEVICE_ID_O2_6832 0x6832
#define PCI_DEVICE_ID_O2_6836 0x6836
+#define PCI_DEVICE_ID_O2_6812 0x6872
+#define PCI_DEVICE_ID_O2_6933 0x6933
#define PCI_VENDOR_ID_3DFX 0x121a
#define PCI_DEVICE_ID_3DFX_VOODOO 0x0001
@@ -2502,11 +2502,30 @@
#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930
#define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916
#define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918
+#define PCI_DEVICE_ID_INTEL_I7_MCR 0x2c18
+#define PCI_DEVICE_ID_INTEL_I7_MC_TAD 0x2c19
+#define PCI_DEVICE_ID_INTEL_I7_MC_RAS 0x2c1a
+#define PCI_DEVICE_ID_INTEL_I7_MC_TEST 0x2c1c
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL 0x2c20
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_ADDR 0x2c21
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_RANK 0x2c22
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_TC 0x2c23
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL 0x2c28
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_ADDR 0x2c29
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_RANK 0x2c2a
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_TC 0x2c2b
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL 0x2c30
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR 0x2c31
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK 0x2c32
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC 0x2c33
+#define PCI_DEVICE_ID_INTEL_I7_NONCORE 0x2c41
+#define PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT 0x2c40
#define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340
#define PCI_DEVICE_ID_INTEL_IOAT_TBG4 0x3429
#define PCI_DEVICE_ID_INTEL_IOAT_TBG5 0x342a
#define PCI_DEVICE_ID_INTEL_IOAT_TBG6 0x342b
#define PCI_DEVICE_ID_INTEL_IOAT_TBG7 0x342c
+#define PCI_DEVICE_ID_INTEL_X58_HUB_MGMT 0x342e
#define PCI_DEVICE_ID_INTEL_IOAT_TBG0 0x3430
#define PCI_DEVICE_ID_INTEL_IOAT_TBG1 0x3431
#define PCI_DEVICE_ID_INTEL_IOAT_TBG2 0x3432
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index dd0bed4f1cf0..d798770f08cd 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -502,6 +502,7 @@
#define PCI_EXT_CAP_ID_VC 2
#define PCI_EXT_CAP_ID_DSN 3
#define PCI_EXT_CAP_ID_PWR 4
+#define PCI_EXT_CAP_ID_ACS 13
#define PCI_EXT_CAP_ID_ARI 14
#define PCI_EXT_CAP_ID_ATS 15
#define PCI_EXT_CAP_ID_SRIOV 16
@@ -662,4 +663,16 @@
#define PCI_SRIOV_VFM_MO 0x2 /* Active.MigrateOut */
#define PCI_SRIOV_VFM_AV 0x3 /* Active.Available */
+/* Access Control Service */
+#define PCI_ACS_CAP 0x04 /* ACS Capability Register */
+#define PCI_ACS_SV 0x01 /* Source Validation */
+#define PCI_ACS_TB 0x02 /* Translation Blocking */
+#define PCI_ACS_RR 0x04 /* P2P Request Redirect */
+#define PCI_ACS_CR 0x08 /* P2P Completion Redirect */
+#define PCI_ACS_UF 0x10 /* Upstream Forwarding */
+#define PCI_ACS_EC 0x20 /* P2P Egress Control */
+#define PCI_ACS_DT 0x40 /* Direct Translated P2P */
+#define PCI_ACS_CTRL 0x06 /* ACS Control Register */
+#define PCI_ACS_EGRESS_CTL_V 0x08 /* ACS Egress Control Vector */
+
#endif /* LINUX_PCI_REGS_H */
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index 878836ca999c..3d9ba92b104f 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -34,8 +34,6 @@
#ifdef CONFIG_SMP
-#ifndef CONFIG_HAVE_LEGACY_PER_CPU_AREA
-
/* minimum unit size, also is the maximum supported allocation size */
#define PCPU_MIN_UNIT_SIZE PFN_ALIGN(64 << 10)
@@ -130,28 +128,6 @@ extern int __init pcpu_page_first_chunk(size_t reserved_size,
#define per_cpu_ptr(ptr, cpu) SHIFT_PERCPU_PTR((ptr), per_cpu_offset((cpu)))
extern void *__alloc_reserved_percpu(size_t size, size_t align);
-
-#else /* CONFIG_HAVE_LEGACY_PER_CPU_AREA */
-
-struct percpu_data {
- void *ptrs[1];
-};
-
-/* pointer disguising messes up the kmemleak objects tracking */
-#ifndef CONFIG_DEBUG_KMEMLEAK
-#define __percpu_disguise(pdata) (struct percpu_data *)~(unsigned long)(pdata)
-#else
-#define __percpu_disguise(pdata) (struct percpu_data *)(pdata)
-#endif
-
-#define per_cpu_ptr(ptr, cpu) \
-({ \
- struct percpu_data *__p = __percpu_disguise(ptr); \
- (__typeof__(ptr))__p->ptrs[(cpu)]; \
-})
-
-#endif /* CONFIG_HAVE_LEGACY_PER_CPU_AREA */
-
extern void *__alloc_percpu(size_t size, size_t align);
extern void free_percpu(void *__pdata);
@@ -243,4 +219,404 @@ do { \
# define percpu_xor(var, val) __percpu_generic_to_op(var, (val), ^=)
#endif
+/*
+ * Branching function to split up a function into a set of functions that
+ * are called for different scalar sizes of the objects handled.
+ */
+
+extern void __bad_size_call_parameter(void);
+
+#define __size_call_return(stem, variable) \
+({ typeof(variable) ret__; \
+ switch(sizeof(variable)) { \
+ case 1: ret__ = stem##1(variable);break; \
+ case 2: ret__ = stem##2(variable);break; \
+ case 4: ret__ = stem##4(variable);break; \
+ case 8: ret__ = stem##8(variable);break; \
+ default: \
+ __bad_size_call_parameter();break; \
+ } \
+ ret__; \
+})
+
+#define __size_call(stem, variable, ...) \
+do { \
+ switch(sizeof(variable)) { \
+ case 1: stem##1(variable, __VA_ARGS__);break; \
+ case 2: stem##2(variable, __VA_ARGS__);break; \
+ case 4: stem##4(variable, __VA_ARGS__);break; \
+ case 8: stem##8(variable, __VA_ARGS__);break; \
+ default: \
+ __bad_size_call_parameter();break; \
+ } \
+} while (0)
+
+/*
+ * Optimized manipulation for memory allocated through the per cpu
+ * allocator or for addresses of per cpu variables (can be determined
+ * using per_cpu_var(xx).
+ *
+ * These operation guarantee exclusivity of access for other operations
+ * on the *same* processor. The assumption is that per cpu data is only
+ * accessed by a single processor instance (the current one).
+ *
+ * The first group is used for accesses that must be done in a
+ * preemption safe way since we know that the context is not preempt
+ * safe. Interrupts may occur. If the interrupt modifies the variable
+ * too then RMW actions will not be reliable.
+ *
+ * The arch code can provide optimized functions in two ways:
+ *
+ * 1. Override the function completely. F.e. define this_cpu_add().
+ * The arch must then ensure that the various scalar format passed
+ * are handled correctly.
+ *
+ * 2. Provide functions for certain scalar sizes. F.e. provide
+ * this_cpu_add_2() to provide per cpu atomic operations for 2 byte
+ * sized RMW actions. If arch code does not provide operations for
+ * a scalar size then the fallback in the generic code will be
+ * used.
+ */
+
+#define _this_cpu_generic_read(pcp) \
+({ typeof(pcp) ret__; \
+ preempt_disable(); \
+ ret__ = *this_cpu_ptr(&(pcp)); \
+ preempt_enable(); \
+ ret__; \
+})
+
+#ifndef this_cpu_read
+# ifndef this_cpu_read_1
+# define this_cpu_read_1(pcp) _this_cpu_generic_read(pcp)
+# endif
+# ifndef this_cpu_read_2
+# define this_cpu_read_2(pcp) _this_cpu_generic_read(pcp)
+# endif
+# ifndef this_cpu_read_4
+# define this_cpu_read_4(pcp) _this_cpu_generic_read(pcp)
+# endif
+# ifndef this_cpu_read_8
+# define this_cpu_read_8(pcp) _this_cpu_generic_read(pcp)
+# endif
+# define this_cpu_read(pcp) __size_call_return(this_cpu_read_, (pcp))
+#endif
+
+#define _this_cpu_generic_to_op(pcp, val, op) \
+do { \
+ preempt_disable(); \
+ *__this_cpu_ptr(&pcp) op val; \
+ preempt_enable(); \
+} while (0)
+
+#ifndef this_cpu_write
+# ifndef this_cpu_write_1
+# define this_cpu_write_1(pcp, val) _this_cpu_generic_to_op((pcp), (val), =)
+# endif
+# ifndef this_cpu_write_2
+# define this_cpu_write_2(pcp, val) _this_cpu_generic_to_op((pcp), (val), =)
+# endif
+# ifndef this_cpu_write_4
+# define this_cpu_write_4(pcp, val) _this_cpu_generic_to_op((pcp), (val), =)
+# endif
+# ifndef this_cpu_write_8
+# define this_cpu_write_8(pcp, val) _this_cpu_generic_to_op((pcp), (val), =)
+# endif
+# define this_cpu_write(pcp, val) __size_call(this_cpu_write_, (pcp), (val))
+#endif
+
+#ifndef this_cpu_add
+# ifndef this_cpu_add_1
+# define this_cpu_add_1(pcp, val) _this_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# ifndef this_cpu_add_2
+# define this_cpu_add_2(pcp, val) _this_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# ifndef this_cpu_add_4
+# define this_cpu_add_4(pcp, val) _this_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# ifndef this_cpu_add_8
+# define this_cpu_add_8(pcp, val) _this_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# define this_cpu_add(pcp, val) __size_call(this_cpu_add_, (pcp), (val))
+#endif
+
+#ifndef this_cpu_sub
+# define this_cpu_sub(pcp, val) this_cpu_add((pcp), -(val))
+#endif
+
+#ifndef this_cpu_inc
+# define this_cpu_inc(pcp) this_cpu_add((pcp), 1)
+#endif
+
+#ifndef this_cpu_dec
+# define this_cpu_dec(pcp) this_cpu_sub((pcp), 1)
+#endif
+
+#ifndef this_cpu_and
+# ifndef this_cpu_and_1
+# define this_cpu_and_1(pcp, val) _this_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# ifndef this_cpu_and_2
+# define this_cpu_and_2(pcp, val) _this_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# ifndef this_cpu_and_4
+# define this_cpu_and_4(pcp, val) _this_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# ifndef this_cpu_and_8
+# define this_cpu_and_8(pcp, val) _this_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# define this_cpu_and(pcp, val) __size_call(this_cpu_and_, (pcp), (val))
+#endif
+
+#ifndef this_cpu_or
+# ifndef this_cpu_or_1
+# define this_cpu_or_1(pcp, val) _this_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# ifndef this_cpu_or_2
+# define this_cpu_or_2(pcp, val) _this_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# ifndef this_cpu_or_4
+# define this_cpu_or_4(pcp, val) _this_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# ifndef this_cpu_or_8
+# define this_cpu_or_8(pcp, val) _this_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# define this_cpu_or(pcp, val) __size_call(this_cpu_or_, (pcp), (val))
+#endif
+
+#ifndef this_cpu_xor
+# ifndef this_cpu_xor_1
+# define this_cpu_xor_1(pcp, val) _this_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# ifndef this_cpu_xor_2
+# define this_cpu_xor_2(pcp, val) _this_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# ifndef this_cpu_xor_4
+# define this_cpu_xor_4(pcp, val) _this_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# ifndef this_cpu_xor_8
+# define this_cpu_xor_8(pcp, val) _this_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# define this_cpu_xor(pcp, val) __size_call(this_cpu_or_, (pcp), (val))
+#endif
+
+/*
+ * Generic percpu operations that do not require preemption handling.
+ * Either we do not care about races or the caller has the
+ * responsibility of handling preemptions issues. Arch code can still
+ * override these instructions since the arch per cpu code may be more
+ * efficient and may actually get race freeness for free (that is the
+ * case for x86 for example).
+ *
+ * If there is no other protection through preempt disable and/or
+ * disabling interupts then one of these RMW operations can show unexpected
+ * behavior because the execution thread was rescheduled on another processor
+ * or an interrupt occurred and the same percpu variable was modified from
+ * the interrupt context.
+ */
+#ifndef __this_cpu_read
+# ifndef __this_cpu_read_1
+# define __this_cpu_read_1(pcp) (*__this_cpu_ptr(&(pcp)))
+# endif
+# ifndef __this_cpu_read_2
+# define __this_cpu_read_2(pcp) (*__this_cpu_ptr(&(pcp)))
+# endif
+# ifndef __this_cpu_read_4
+# define __this_cpu_read_4(pcp) (*__this_cpu_ptr(&(pcp)))
+# endif
+# ifndef __this_cpu_read_8
+# define __this_cpu_read_8(pcp) (*__this_cpu_ptr(&(pcp)))
+# endif
+# define __this_cpu_read(pcp) __size_call_return(__this_cpu_read_, (pcp))
+#endif
+
+#define __this_cpu_generic_to_op(pcp, val, op) \
+do { \
+ *__this_cpu_ptr(&(pcp)) op val; \
+} while (0)
+
+#ifndef __this_cpu_write
+# ifndef __this_cpu_write_1
+# define __this_cpu_write_1(pcp, val) __this_cpu_generic_to_op((pcp), (val), =)
+# endif
+# ifndef __this_cpu_write_2
+# define __this_cpu_write_2(pcp, val) __this_cpu_generic_to_op((pcp), (val), =)
+# endif
+# ifndef __this_cpu_write_4
+# define __this_cpu_write_4(pcp, val) __this_cpu_generic_to_op((pcp), (val), =)
+# endif
+# ifndef __this_cpu_write_8
+# define __this_cpu_write_8(pcp, val) __this_cpu_generic_to_op((pcp), (val), =)
+# endif
+# define __this_cpu_write(pcp, val) __size_call(__this_cpu_write_, (pcp), (val))
+#endif
+
+#ifndef __this_cpu_add
+# ifndef __this_cpu_add_1
+# define __this_cpu_add_1(pcp, val) __this_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# ifndef __this_cpu_add_2
+# define __this_cpu_add_2(pcp, val) __this_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# ifndef __this_cpu_add_4
+# define __this_cpu_add_4(pcp, val) __this_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# ifndef __this_cpu_add_8
+# define __this_cpu_add_8(pcp, val) __this_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# define __this_cpu_add(pcp, val) __size_call(__this_cpu_add_, (pcp), (val))
+#endif
+
+#ifndef __this_cpu_sub
+# define __this_cpu_sub(pcp, val) __this_cpu_add((pcp), -(val))
+#endif
+
+#ifndef __this_cpu_inc
+# define __this_cpu_inc(pcp) __this_cpu_add((pcp), 1)
+#endif
+
+#ifndef __this_cpu_dec
+# define __this_cpu_dec(pcp) __this_cpu_sub((pcp), 1)
+#endif
+
+#ifndef __this_cpu_and
+# ifndef __this_cpu_and_1
+# define __this_cpu_and_1(pcp, val) __this_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# ifndef __this_cpu_and_2
+# define __this_cpu_and_2(pcp, val) __this_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# ifndef __this_cpu_and_4
+# define __this_cpu_and_4(pcp, val) __this_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# ifndef __this_cpu_and_8
+# define __this_cpu_and_8(pcp, val) __this_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# define __this_cpu_and(pcp, val) __size_call(__this_cpu_and_, (pcp), (val))
+#endif
+
+#ifndef __this_cpu_or
+# ifndef __this_cpu_or_1
+# define __this_cpu_or_1(pcp, val) __this_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# ifndef __this_cpu_or_2
+# define __this_cpu_or_2(pcp, val) __this_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# ifndef __this_cpu_or_4
+# define __this_cpu_or_4(pcp, val) __this_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# ifndef __this_cpu_or_8
+# define __this_cpu_or_8(pcp, val) __this_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# define __this_cpu_or(pcp, val) __size_call(__this_cpu_or_, (pcp), (val))
+#endif
+
+#ifndef __this_cpu_xor
+# ifndef __this_cpu_xor_1
+# define __this_cpu_xor_1(pcp, val) __this_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# ifndef __this_cpu_xor_2
+# define __this_cpu_xor_2(pcp, val) __this_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# ifndef __this_cpu_xor_4
+# define __this_cpu_xor_4(pcp, val) __this_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# ifndef __this_cpu_xor_8
+# define __this_cpu_xor_8(pcp, val) __this_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# define __this_cpu_xor(pcp, val) __size_call(__this_cpu_xor_, (pcp), (val))
+#endif
+
+/*
+ * IRQ safe versions of the per cpu RMW operations. Note that these operations
+ * are *not* safe against modification of the same variable from another
+ * processors (which one gets when using regular atomic operations)
+ . They are guaranteed to be atomic vs. local interrupts and
+ * preemption only.
+ */
+#define irqsafe_cpu_generic_to_op(pcp, val, op) \
+do { \
+ unsigned long flags; \
+ local_irq_save(flags); \
+ *__this_cpu_ptr(&(pcp)) op val; \
+ local_irq_restore(flags); \
+} while (0)
+
+#ifndef irqsafe_cpu_add
+# ifndef irqsafe_cpu_add_1
+# define irqsafe_cpu_add_1(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# ifndef irqsafe_cpu_add_2
+# define irqsafe_cpu_add_2(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# ifndef irqsafe_cpu_add_4
+# define irqsafe_cpu_add_4(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# ifndef irqsafe_cpu_add_8
+# define irqsafe_cpu_add_8(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), +=)
+# endif
+# define irqsafe_cpu_add(pcp, val) __size_call(irqsafe_cpu_add_, (pcp), (val))
+#endif
+
+#ifndef irqsafe_cpu_sub
+# define irqsafe_cpu_sub(pcp, val) irqsafe_cpu_add((pcp), -(val))
+#endif
+
+#ifndef irqsafe_cpu_inc
+# define irqsafe_cpu_inc(pcp) irqsafe_cpu_add((pcp), 1)
+#endif
+
+#ifndef irqsafe_cpu_dec
+# define irqsafe_cpu_dec(pcp) irqsafe_cpu_sub((pcp), 1)
+#endif
+
+#ifndef irqsafe_cpu_and
+# ifndef irqsafe_cpu_and_1
+# define irqsafe_cpu_and_1(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# ifndef irqsafe_cpu_and_2
+# define irqsafe_cpu_and_2(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# ifndef irqsafe_cpu_and_4
+# define irqsafe_cpu_and_4(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# ifndef irqsafe_cpu_and_8
+# define irqsafe_cpu_and_8(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), &=)
+# endif
+# define irqsafe_cpu_and(pcp, val) __size_call(irqsafe_cpu_and_, (val))
+#endif
+
+#ifndef irqsafe_cpu_or
+# ifndef irqsafe_cpu_or_1
+# define irqsafe_cpu_or_1(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# ifndef irqsafe_cpu_or_2
+# define irqsafe_cpu_or_2(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# ifndef irqsafe_cpu_or_4
+# define irqsafe_cpu_or_4(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# ifndef irqsafe_cpu_or_8
+# define irqsafe_cpu_or_8(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), |=)
+# endif
+# define irqsafe_cpu_or(pcp, val) __size_call(irqsafe_cpu_or_, (val))
+#endif
+
+#ifndef irqsafe_cpu_xor
+# ifndef irqsafe_cpu_xor_1
+# define irqsafe_cpu_xor_1(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# ifndef irqsafe_cpu_xor_2
+# define irqsafe_cpu_xor_2(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# ifndef irqsafe_cpu_xor_4
+# define irqsafe_cpu_xor_4(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# ifndef irqsafe_cpu_xor_8
+# define irqsafe_cpu_xor_8(pcp, val) irqsafe_cpu_generic_to_op((pcp), (val), ^=)
+# endif
+# define irqsafe_cpu_xor(pcp, val) __size_call(irqsafe_cpu_xor_, (val))
+#endif
+
#endif /* __LINUX_PERCPU_H */
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h
index 7b7fbf433cff..91a2b4309e7a 100644
--- a/include/linux/perf_counter.h
+++ b/include/linux/perf_counter.h
@@ -225,6 +225,7 @@ struct perf_counter_attr {
#define PERF_COUNTER_IOC_RESET _IO ('$', 3)
#define PERF_COUNTER_IOC_PERIOD _IOW('$', 4, u64)
#define PERF_COUNTER_IOC_SET_OUTPUT _IO ('$', 5)
+#define PERF_COUNTER_IOC_SET_FILTER _IOW('$', 6, char *)
enum perf_counter_ioc_flags {
PERF_IOC_FLAG_GROUP = 1U << 0,
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 2e6d95f97419..45b56faf5cdc 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -221,6 +221,7 @@ struct perf_event_attr {
#define PERF_EVENT_IOC_RESET _IO ('$', 3)
#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, u64)
#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5)
+#define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *)
enum perf_event_ioc_flags {
PERF_IOC_FLAG_GROUP = 1U << 0,
@@ -471,8 +472,8 @@ struct hw_perf_event {
unsigned long event_base;
int idx;
};
- union { /* software */
- atomic64_t count;
+ struct { /* software */
+ s64 remaining;
struct hrtimer hrtimer;
};
};
@@ -633,7 +634,12 @@ struct perf_event {
struct pid_namespace *ns;
u64 id;
+
+#ifdef CONFIG_EVENT_PROFILE
+ struct event_filter *filter;
#endif
+
+#endif /* CONFIG_PERF_EVENTS */
};
/**
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 3b7e04b95bd2..b305ebbd4ec4 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -26,6 +26,7 @@
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <linux/timer.h>
+#include <linux/completion.h>
/*
* Callbacks for platform drivers to implement.
@@ -408,19 +409,24 @@ enum rpm_request {
};
struct dev_pm_info {
+ spinlock_t lock;
+ wait_queue_head_t wait_queue;
+ struct list_head master_links;
+ struct list_head slave_links;
pm_message_t power_state;
unsigned int can_wakeup:1;
unsigned int should_wakeup:1;
+ unsigned int async_suspend:1;
enum dpm_state status; /* Owned by the PM core */
#ifdef CONFIG_PM_SLEEP
struct list_head entry;
+ unsigned int op_started:1;
+ unsigned int op_complete:1;
#endif
#ifdef CONFIG_PM_RUNTIME
struct timer_list suspend_timer;
unsigned long timer_expires;
struct work_struct work;
- wait_queue_head_t wait_queue;
- spinlock_t lock;
atomic_t usage_count;
atomic_t child_count;
unsigned int disable_depth:3;
@@ -499,6 +505,9 @@ extern int sysdev_suspend(pm_message_t state);
extern int dpm_suspend_noirq(pm_message_t state);
extern int dpm_suspend_start(pm_message_t state);
+struct timeval;
+extern int pm_time_elapsed(struct timeval *start, struct timeval *stop);
+
extern void __suspend_report_result(const char *function, void *fn, int ret);
#define suspend_report_result(fn, ret) \
diff --git a/include/linux/pm_link.h b/include/linux/pm_link.h
new file mode 100644
index 000000000000..539f8e1ed62d
--- /dev/null
+++ b/include/linux/pm_link.h
@@ -0,0 +1,30 @@
+/*
+ * include/linux/pm_link.h - PM links manipulation core.
+ *
+ * Copyright (c) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _LINUX_PM_LINK_H
+#define _LINUX_PM_LINK_H
+
+#include <linux/list.h>
+
+struct device;
+
+struct pm_link {
+ struct device *master;
+ struct list_head master_hook;
+ struct device *slave;
+ struct list_head slave_hook;
+};
+
+extern int pm_link_add(struct device *slave, struct device *master);
+extern void pm_link_remove(struct device *dev, struct device *master);
+extern int device_for_each_master(struct device *slave, void *data,
+ int (*fn)(struct device *dev, void *data));
+extern int device_for_each_slave(struct device *master, void *data,
+ int (*fn)(struct device *dev, void *data));
+
+#endif
diff --git a/include/linux/poison.h b/include/linux/poison.h
index 7fc194aef8c2..2110a81c5e2a 100644
--- a/include/linux/poison.h
+++ b/include/linux/poison.h
@@ -2,13 +2,25 @@
#define _LINUX_POISON_H
/********** include/linux/list.h **********/
+
+/*
+ * Architectures might want to move the poison pointer offset
+ * into some well-recognized area such as 0xdead000000000000,
+ * that is also not mappable by user-space exploits:
+ */
+#ifdef CONFIG_ILLEGAL_POINTER_VALUE
+# define POISON_POINTER_DELTA _AC(CONFIG_ILLEGAL_POINTER_VALUE, UL)
+#else
+# define POISON_POINTER_DELTA 0
+#endif
+
/*
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses
* non-initialized list entries.
*/
-#define LIST_POISON1 ((void *) 0x00100100)
-#define LIST_POISON2 ((void *) 0x00200200)
+#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA)
+#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA)
/********** include/linux/timer.h **********/
/*
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h
index 4f71bf4e628c..3e23844a6990 100644
--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -117,6 +117,6 @@ void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx,
long clock_nanosleep_restart(struct restart_block *restart_block);
-void update_rlimit_cpu(unsigned long rlim_new);
+void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new);
#endif
diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h
index 065a3652a3ea..67608161df6b 100644
--- a/include/linux/posix_acl.h
+++ b/include/linux/posix_acl.h
@@ -147,6 +147,20 @@ static inline void forget_cached_acl(struct inode *inode, int type)
if (old != ACL_NOT_CACHED)
posix_acl_release(old);
}
+
+static inline void forget_all_cached_acls(struct inode *inode)
+{
+ struct posix_acl *old_access, *old_default;
+ spin_lock(&inode->i_lock);
+ old_access = inode->i_acl;
+ old_default = inode->i_default_acl;
+ inode->i_acl = inode->i_default_acl = ACL_NOT_CACHED;
+ spin_unlock(&inode->i_lock);
+ if (old_access != ACL_NOT_CACHED)
+ posix_acl_release(old_access);
+ if (old_default != ACL_NOT_CACHED)
+ posix_acl_release(old_default);
+}
#endif
static inline void cache_no_acl(struct inode *inode)
diff --git a/include/linux/quota.h b/include/linux/quota.h
index 78c48895b12a..ce9a9b2e5cd4 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -376,6 +376,17 @@ static inline unsigned int dquot_generic_flag(unsigned int flags, int type)
return flags >> _DQUOT_STATE_FLAGS;
}
+#ifdef CONFIG_QUOTA_NETLINK_INTERFACE
+extern void quota_send_warning(short type, unsigned int id, dev_t dev,
+ const char warntype);
+#else
+static inline void quota_send_warning(short type, unsigned int id, dev_t dev,
+ const char warntype)
+{
+ return;
+}
+#endif /* CONFIG_QUOTA_NETLINK_INTERFACE */
+
struct quota_info {
unsigned int flags; /* Flags for diskquotas on this device */
struct mutex dqio_mutex; /* lock device while I/O in progress */
diff --git a/include/linux/ratelimit.h b/include/linux/ratelimit.h
index 00044b856453..668cf1bef030 100644
--- a/include/linux/ratelimit.h
+++ b/include/linux/ratelimit.h
@@ -1,20 +1,31 @@
#ifndef _LINUX_RATELIMIT_H
#define _LINUX_RATELIMIT_H
+
#include <linux/param.h>
+#include <linux/spinlock_types.h>
-#define DEFAULT_RATELIMIT_INTERVAL (5 * HZ)
-#define DEFAULT_RATELIMIT_BURST 10
+#define DEFAULT_RATELIMIT_INTERVAL (5 * HZ)
+#define DEFAULT_RATELIMIT_BURST 10
struct ratelimit_state {
- int interval;
- int burst;
- int printed;
- int missed;
- unsigned long begin;
+ spinlock_t lock; /* protect the state */
+
+ int interval;
+ int burst;
+ int printed;
+ int missed;
+ unsigned long begin;
};
-#define DEFINE_RATELIMIT_STATE(name, interval, burst) \
- struct ratelimit_state name = {interval, burst,}
+#define DEFINE_RATELIMIT_STATE(name, interval_init, burst_init) \
+ \
+ struct ratelimit_state name = { \
+ .lock = __SPIN_LOCK_UNLOCKED(name.lock), \
+ .interval = interval_init, \
+ .burst = burst_init, \
+ }
+
+extern int ___ratelimit(struct ratelimit_state *rs, const char *func);
+#define __ratelimit(state) ___ratelimit(state, __func__)
-extern int __ratelimit(struct ratelimit_state *rs);
-#endif
+#endif /* _LINUX_RATELIMIT_H */
diff --git a/include/linux/rcu_types.h b/include/linux/rcu_types.h
new file mode 100644
index 000000000000..fd3570d0e6c1
--- /dev/null
+++ b/include/linux/rcu_types.h
@@ -0,0 +1,18 @@
+#ifndef __LINUX_RCU_TYPES_H
+#define __LINUX_RCU_TYPES_H
+
+#ifdef __KERNEL__
+
+/**
+ * struct rcu_head - callback structure for use with RCU
+ * @next: next update requests in a list
+ * @func: actual update function to call after the grace period.
+ */
+struct rcu_head {
+ struct rcu_head *next;
+ void (*func)(struct rcu_head *head);
+};
+
+#endif
+
+#endif
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 3ebd0b7bcb08..33ee2cdd019f 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -33,6 +33,7 @@
#ifndef __LINUX_RCUPDATE_H
#define __LINUX_RCUPDATE_H
+#include <linux/rcu_types.h>
#include <linux/cache.h>
#include <linux/spinlock.h>
#include <linux/threads.h>
@@ -41,16 +42,6 @@
#include <linux/lockdep.h>
#include <linux/completion.h>
-/**
- * struct rcu_head - callback structure for use with RCU
- * @next: next update requests in a list
- * @func: actual update function to call after the grace period.
- */
-struct rcu_head {
- struct rcu_head *next;
- void (*func)(struct rcu_head *head);
-};
-
/* Exported common interfaces */
#ifdef CONFIG_TREE_PREEMPT_RCU
extern void synchronize_rcu(void);
@@ -68,11 +59,17 @@ extern int sched_expedited_torture_stats(char *page);
/* Internal to kernel */
extern void rcu_init(void);
extern void rcu_scheduler_starting(void);
+#ifndef CONFIG_TINY_RCU
extern int rcu_needs_cpu(int cpu);
+#else
+static inline int rcu_needs_cpu(int cpu) { return 0; }
+#endif
extern int rcu_scheduler_active;
#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU)
#include <linux/rcutree.h>
+#elif defined(CONFIG_TINY_RCU)
+#include <linux/rcutiny.h>
#else
#error "Unknown RCU implementation specified to kernel configuration"
#endif
diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h
new file mode 100644
index 000000000000..2c1fe8373e71
--- /dev/null
+++ b/include/linux/rcutiny.h
@@ -0,0 +1,95 @@
+/*
+ * Read-Copy Update mechanism for mutual exclusion, the Bloatwatch edition.
+ *
+ * This 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 IBM Corporation, 2008
+ *
+ * Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+ *
+ * For detailed explanation of Read-Copy Update mechanism see -
+ * Documentation/RCU
+ */
+#ifndef __LINUX_TINY_H
+#define __LINUX_TINY_H
+
+#include <linux/cache.h>
+
+void rcu_sched_qs(int cpu);
+void rcu_bh_qs(int cpu);
+
+#define __rcu_read_lock() preempt_disable()
+#define __rcu_read_unlock() preempt_enable()
+#define __rcu_read_lock_bh() local_bh_disable()
+#define __rcu_read_unlock_bh() local_bh_enable()
+#define call_rcu_sched call_rcu
+
+#define rcu_init_sched() do { } while (0)
+extern void rcu_check_callbacks(int cpu, int user);
+extern void __rcu_init(void);
+
+/*
+ * Return the number of grace periods.
+ */
+static inline long rcu_batches_completed(void)
+{
+ return 0;
+}
+
+/*
+ * Return the number of bottom-half grace periods.
+ */
+static inline long rcu_batches_completed_bh(void)
+{
+ return 0;
+}
+
+extern int rcu_expedited_torture_stats(char *page);
+
+static inline void synchronize_rcu_expedited(void)
+{
+ synchronize_sched();
+}
+
+static inline void synchronize_rcu_bh_expedited(void)
+{
+ synchronize_sched();
+}
+
+struct notifier_block;
+extern int rcu_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu);
+
+#ifdef CONFIG_NO_HZ
+
+extern void rcu_enter_nohz(void);
+extern void rcu_exit_nohz(void);
+
+#else /* #ifdef CONFIG_NO_HZ */
+
+static inline void rcu_enter_nohz(void)
+{
+}
+
+static inline void rcu_exit_nohz(void)
+{
+}
+
+#endif /* #else #ifdef CONFIG_NO_HZ */
+
+static inline void exit_rcu(void)
+{
+}
+
+#endif /* __LINUX_RCUTINY_H */
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h
index 46e9ab3ee6e1..9642c6bcb399 100644
--- a/include/linux/rcutree.h
+++ b/include/linux/rcutree.h
@@ -76,11 +76,7 @@ static inline void __rcu_read_unlock_bh(void)
extern void call_rcu_sched(struct rcu_head *head,
void (*func)(struct rcu_head *rcu));
-
-static inline void synchronize_rcu_expedited(void)
-{
- synchronize_sched_expedited();
-}
+extern void synchronize_rcu_expedited(void);
static inline void synchronize_rcu_bh_expedited(void)
{
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index 87f5f176d4ef..234a8476cba8 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -43,16 +43,20 @@ struct regulator;
/**
* struct regulator_state - regulator state during low power system states
*
- * This describes a regulators state during a system wide low power state.
+ * This describes a regulators state during a system wide low power
+ * state. One of enabled or disabled must be set for the
+ * configuration to be applied.
*
* @uV: Operating voltage during suspend.
* @mode: Operating mode during suspend.
* @enabled: Enabled during suspend.
+ * @disabled: Disabled during suspend.
*/
struct regulator_state {
int uV; /* suspend voltage */
unsigned int mode; /* suspend regulator operating mode */
int enabled; /* is regulator enabled in this suspend state */
+ int disabled; /* is the regulator disbled in this suspend state */
};
/**
diff --git a/include/linux/regulator/max8660.h b/include/linux/regulator/max8660.h
new file mode 100644
index 000000000000..9936763621c7
--- /dev/null
+++ b/include/linux/regulator/max8660.h
@@ -0,0 +1,57 @@
+/*
+ * max8660.h -- Voltage regulation for the Maxim 8660/8661
+ *
+ * Copyright (C) 2009 Wolfram Sang, Pengutronix e.K.
+ *
+ * This 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 __LINUX_REGULATOR_MAX8660_H
+#define __LINUX_REGULATOR_MAX8660_H
+
+#include <linux/regulator/machine.h>
+
+enum {
+ MAX8660_V3,
+ MAX8660_V4,
+ MAX8660_V5,
+ MAX8660_V6,
+ MAX8660_V7,
+ MAX8660_V_END,
+};
+
+/**
+ * max8660_subdev_data - regulator subdev data
+ * @id: regulator id
+ * @name: regulator name
+ * @platform_data: regulator init data
+ */
+struct max8660_subdev_data {
+ int id;
+ char *name;
+ struct regulator_init_data *platform_data;
+};
+
+/**
+ * max8660_platform_data - platform data for max8660
+ * @num_subdevs: number of regulators used
+ * @subdevs: pointer to regulators used
+ * @en34_is_high: if EN34 is driven high, regulators cannot be en-/disabled.
+ */
+struct max8660_platform_data {
+ int num_subdevs;
+ struct max8660_subdev_data *subdevs;
+ unsigned en34_is_high:1;
+};
+#endif
diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
index dd31e7bae35c..a05b4a20768d 100644
--- a/include/linux/reiserfs_fs.h
+++ b/include/linux/reiserfs_fs.h
@@ -52,11 +52,63 @@
#define REISERFS_IOC32_GETVERSION FS_IOC32_GETVERSION
#define REISERFS_IOC32_SETVERSION FS_IOC32_SETVERSION
-/* Locking primitives */
-/* Right now we are still falling back to (un)lock_kernel, but eventually that
- would evolve into real per-fs locks */
-#define reiserfs_write_lock( sb ) lock_kernel()
-#define reiserfs_write_unlock( sb ) unlock_kernel()
+/*
+ * Locking primitives. The write lock is a per superblock
+ * special mutex that has properties close to the Big Kernel Lock
+ * which was used in the previous locking scheme.
+ */
+void reiserfs_write_lock(struct super_block *s);
+void reiserfs_write_unlock(struct super_block *s);
+int reiserfs_write_lock_once(struct super_block *s);
+void reiserfs_write_unlock_once(struct super_block *s, int lock_depth);
+
+/*
+ * Several mutexes depend on the write lock.
+ * However sometimes we want to relax the write lock while we hold
+ * these mutexes, according to the release/reacquire on schedule()
+ * properties of the Bkl that were used.
+ * Reiserfs performances and locking were based on this scheme.
+ * Now that the write lock is a mutex and not the bkl anymore, doing so
+ * may result in a deadlock:
+ *
+ * A acquire write_lock
+ * A acquire j_commit_mutex
+ * A release write_lock and wait for something
+ * B acquire write_lock
+ * B can't acquire j_commit_mutex and sleep
+ * A can't acquire write lock anymore
+ * deadlock
+ *
+ * What we do here is avoiding such deadlock by playing the same game
+ * than the Bkl: if we can't acquire a mutex that depends on the write lock,
+ * we release the write lock, wait a bit and then retry.
+ *
+ * The mutexes concerned by this hack are:
+ * - The commit mutex of a journal list
+ * - The flush mutex
+ * - The journal lock
+ * - The inode mutex
+ */
+static inline void reiserfs_mutex_lock_safe(struct mutex *m,
+ struct super_block *s)
+{
+ reiserfs_write_unlock(s);
+ mutex_lock(m);
+ reiserfs_write_lock(s);
+}
+
+/*
+ * When we schedule, we usually want to also release the write lock,
+ * according to the previous bkl based locking scheme of reiserfs.
+ */
+static inline void reiserfs_cond_resched(struct super_block *s)
+{
+ if (need_resched()) {
+ reiserfs_write_unlock(s);
+ schedule();
+ reiserfs_write_lock(s);
+ }
+}
struct fid;
@@ -1329,7 +1381,11 @@ static inline loff_t max_reiserfs_offset(struct inode *inode)
#define get_generation(s) atomic_read (&fs_generation(s))
#define FILESYSTEM_CHANGED_TB(tb) (get_generation((tb)->tb_sb) != (tb)->fs_gen)
#define __fs_changed(gen,s) (gen != get_generation (s))
-#define fs_changed(gen,s) ({cond_resched(); __fs_changed(gen, s);})
+#define fs_changed(gen,s) \
+({ \
+ reiserfs_cond_resched(s); \
+ __fs_changed(gen, s); \
+})
/***************************************************************************/
/* FIXATE NODES */
@@ -2258,8 +2314,7 @@ __u32 r5_hash(const signed char *msg, int len);
#define SPARE_SPACE 500
/* prototypes from ioctl.c */
-int reiserfs_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
long reiserfs_compat_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg);
int reiserfs_unpack(struct inode *inode, struct file *filp);
diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
index dab68bbed675..52c83b6a758a 100644
--- a/include/linux/reiserfs_fs_sb.h
+++ b/include/linux/reiserfs_fs_sb.h
@@ -7,6 +7,8 @@
#ifdef __KERNEL__
#include <linux/workqueue.h>
#include <linux/rwsem.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
#endif
typedef enum {
@@ -355,6 +357,13 @@ struct reiserfs_sb_info {
struct reiserfs_journal *s_journal; /* pointer to journal information */
unsigned short s_mount_state; /* reiserfs state (valid, invalid) */
+ /* Serialize writers access, replace the old bkl */
+ struct mutex lock;
+ /* Owner of the lock (can be recursive) */
+ struct task_struct *lock_owner;
+ /* Depth of the lock, start from -1 like the bkl */
+ int lock_depth;
+
/* Comment? -Hans */
void (*end_io_handler) (struct buffer_head *, int);
hashf_t s_hash_function; /* pointer to function which is used
@@ -408,6 +417,17 @@ struct reiserfs_sb_info {
char *s_qf_names[MAXQUOTAS];
int s_jquota_fmt;
#endif
+#ifdef CONFIG_REISERFS_CHECK
+
+ struct tree_balance *cur_tb; /*
+ * Detects whether more than one
+ * copy of tb exists per superblock
+ * as a means of checking whether
+ * do_balance is executing concurrently
+ * against another tree reader/writer
+ * on a same mount point.
+ */
+#endif
};
/* Definitions of reiserfs on-disk properties: */
diff --git a/include/linux/resource.h b/include/linux/resource.h
index 40fc7e626082..4301d67f8c44 100644
--- a/include/linux/resource.h
+++ b/include/linux/resource.h
@@ -71,5 +71,7 @@ struct rlimit {
#include <asm/resource.h>
int getrusage(struct task_struct *p, int who, struct rusage __user *ru);
+int setrlimit(struct task_struct *tsk, unsigned int resource,
+ struct rlimit *new_rlim);
#endif
diff --git a/include/linux/resume-trace.h b/include/linux/resume-trace.h
index c9ba2fdf807d..4860100e44f4 100644
--- a/include/linux/resume-trace.h
+++ b/include/linux/resume-trace.h
@@ -6,6 +6,11 @@
extern int pm_trace_enabled;
+static inline int pm_trace_is_enabled(void)
+{
+ return pm_trace_enabled;
+}
+
struct device;
extern void set_trace_device(struct device *);
extern void generate_resume_trace(const void *tracedata, unsigned int user);
@@ -17,6 +22,8 @@ extern void generate_resume_trace(const void *tracedata, unsigned int user);
#else
+static inline int pm_trace_is_enabled(void) { return 0; }
+
#define TRACE_DEVICE(dev) do { } while (0)
#define TRACE_RESUME(dev) do { } while (0)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 75e6e60bf583..1aa45747348e 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -307,6 +307,7 @@ extern void sched_show_task(struct task_struct *p);
#ifdef CONFIG_DETECT_SOFTLOCKUP
extern void softlockup_tick(void);
extern void touch_softlockup_watchdog(void);
+extern void touch_softlockup_watchdog_sync(void);
extern void touch_all_softlockup_watchdogs(void);
extern int proc_dosoftlockup_thresh(struct ctl_table *table, int write,
void __user *buffer,
@@ -320,6 +321,9 @@ static inline void softlockup_tick(void)
static inline void touch_softlockup_watchdog(void)
{
}
+static inline void touch_softlockup_watchdog_sync(void)
+{
+}
static inline void touch_all_softlockup_watchdogs(void)
{
}
diff --git a/include/linux/security.h b/include/linux/security.h
index 239e40d0450b..3f3844a7b5cd 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -447,6 +447,22 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @new_dir contains the path structure for parent of the new link.
* @new_dentry contains the dentry structure of the new link.
* Return 0 if permission is granted.
+ * @path_chmod:
+ * Check for permission to change DAC's permission of a file or directory.
+ * @dentry contains the dentry structure.
+ * @mnt contains the vfsmnt structure.
+ * @mode contains DAC's mode.
+ * Return 0 if permission is granted.
+ * @path_chown:
+ * Check for permission to change owner/group of a file or directory.
+ * @path contains the path structure.
+ * @uid contains new owner's ID.
+ * @gid contains new group's ID.
+ * Return 0 if permission is granted.
+ * @path_chroot:
+ * Check for permission to change root directory.
+ * @path contains the path structure.
+ * Return 0 if permission is granted.
* @inode_readlink:
* Check the permission to read the symbolic link.
* @dentry contains the dentry structure for the file link.
@@ -1488,6 +1504,10 @@ struct security_operations {
struct dentry *new_dentry);
int (*path_rename) (struct path *old_dir, struct dentry *old_dentry,
struct path *new_dir, struct dentry *new_dentry);
+ int (*path_chmod) (struct dentry *dentry, struct vfsmount *mnt,
+ mode_t mode);
+ int (*path_chown) (struct path *path, uid_t uid, gid_t gid);
+ int (*path_chroot) (struct path *path);
#endif
int (*inode_alloc_security) (struct inode *inode);
@@ -1570,7 +1590,8 @@ struct security_operations {
int (*task_setnice) (struct task_struct *p, int nice);
int (*task_setioprio) (struct task_struct *p, int ioprio);
int (*task_getioprio) (struct task_struct *p);
- int (*task_setrlimit) (unsigned int resource, struct rlimit *new_rlim);
+ int (*task_setrlimit) (struct task_struct *p, unsigned int resource,
+ struct rlimit *new_rlim);
int (*task_setscheduler) (struct task_struct *p, int policy,
struct sched_param *lp);
int (*task_getscheduler) (struct task_struct *p);
@@ -1835,7 +1856,8 @@ int security_task_setgroups(struct group_info *group_info);
int security_task_setnice(struct task_struct *p, int nice);
int security_task_setioprio(struct task_struct *p, int ioprio);
int security_task_getioprio(struct task_struct *p);
-int security_task_setrlimit(unsigned int resource, struct rlimit *new_rlim);
+int security_task_setrlimit(struct task_struct *p, unsigned int resource,
+ struct rlimit *new_rlim);
int security_task_setscheduler(struct task_struct *p,
int policy, struct sched_param *lp);
int security_task_getscheduler(struct task_struct *p);
@@ -2451,7 +2473,8 @@ static inline int security_task_getioprio(struct task_struct *p)
return 0;
}
-static inline int security_task_setrlimit(unsigned int resource,
+static inline int security_task_setrlimit(struct task_struct *p,
+ unsigned int resource,
struct rlimit *new_rlim)
{
return 0;
@@ -2952,6 +2975,10 @@ int security_path_link(struct dentry *old_dentry, struct path *new_dir,
struct dentry *new_dentry);
int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
struct path *new_dir, struct dentry *new_dentry);
+int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
+ mode_t mode);
+int security_path_chown(struct path *path, uid_t uid, gid_t gid);
+int security_path_chroot(struct path *path);
#else /* CONFIG_SECURITY_PATH */
static inline int security_path_unlink(struct path *dir, struct dentry *dentry)
{
@@ -3001,6 +3028,23 @@ static inline int security_path_rename(struct path *old_dir,
{
return 0;
}
+
+static inline int security_path_chmod(struct dentry *dentry,
+ struct vfsmount *mnt,
+ mode_t mode)
+{
+ return 0;
+}
+
+static inline int security_path_chown(struct path *path, uid_t uid, gid_t gid)
+{
+ return 0;
+}
+
+static inline int security_path_chroot(struct path *path)
+{
+ return 0;
+}
#endif /* CONFIG_SECURITY_PATH */
#ifdef CONFIG_KEYS
diff --git a/include/linux/serio.h b/include/linux/serio.h
index a640bc2afe76..e2f3044d4a4a 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -215,5 +215,6 @@ static inline void serio_unpin_driver(struct serio *serio)
#define SERIO_INEXIO 0x37
#define SERIO_TOUCHIT213 0x38
#define SERIO_W8001 0x39
+#define SERIO_DYNAPRO 0x3a
#endif
diff --git a/include/linux/sh_intc.h b/include/linux/sh_intc.h
index 68e212ff9dde..4e4b22d50164 100644
--- a/include/linux/sh_intc.h
+++ b/include/linux/sh_intc.h
@@ -57,10 +57,8 @@ struct intc_desc {
struct intc_sense_reg *sense_regs;
unsigned int nr_sense_regs;
char *name;
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
struct intc_mask_reg *ack_regs;
unsigned int nr_ack_regs;
-#endif
};
#define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a)
@@ -73,7 +71,6 @@ struct intc_desc symbol __initdata = { \
chipname, \
}
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
#define DECLARE_INTC_DESC_ACK(symbol, chipname, vectors, groups, \
mask_regs, prio_regs, sense_regs, ack_regs) \
struct intc_desc symbol __initdata = { \
@@ -83,7 +80,6 @@ struct intc_desc symbol __initdata = { \
chipname, \
_INTC_ARRAY(ack_regs), \
}
-#endif
void __init register_intc_controller(struct intc_desc *desc);
int intc_set_priority(unsigned int irq, unsigned int prio);
diff --git a/include/linux/shm_signal.h b/include/linux/shm_signal.h
new file mode 100644
index 000000000000..21cf75044d40
--- /dev/null
+++ b/include/linux/shm_signal.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2009 Novell. All Rights Reserved.
+ *
+ * Author:
+ * Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file 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 St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LINUX_SHM_SIGNAL_H
+#define _LINUX_SHM_SIGNAL_H
+
+#include <linux/types.h>
+
+/*
+ *---------
+ * The following structures represent data that is shared across boundaries
+ * which may be quite disparate from one another (e.g. Windows vs Linux,
+ * 32 vs 64 bit, etc). Therefore, care has been taken to make sure they
+ * present data in a manner that is independent of the environment.
+ *-----------
+ */
+
+#define SHM_SIGNAL_MAGIC 0x58fa39df
+#define SHM_SIGNAL_VER 1
+
+struct shm_signal_irq {
+ __u8 enabled;
+ __u8 pending;
+ __u8 dirty;
+};
+
+enum shm_signal_locality {
+ shm_locality_north,
+ shm_locality_south,
+};
+
+struct shm_signal_desc {
+ __u32 magic;
+ __u32 ver;
+ struct shm_signal_irq irq[2];
+};
+
+/* --- END SHARED STRUCTURES --- */
+
+#ifdef __KERNEL__
+
+#include <linux/kref.h>
+#include <linux/interrupt.h>
+
+struct shm_signal_notifier {
+ void (*signal)(struct shm_signal_notifier *);
+};
+
+struct shm_signal;
+
+struct shm_signal_ops {
+ int (*inject)(struct shm_signal *s);
+ void (*fault)(struct shm_signal *s, const char *fmt, ...);
+ void (*release)(struct shm_signal *s);
+};
+
+enum {
+ shm_signal_in_wakeup,
+};
+
+struct shm_signal {
+ struct kref kref;
+ spinlock_t lock;
+ enum shm_signal_locality locale;
+ unsigned long flags;
+ struct shm_signal_ops *ops;
+ struct shm_signal_desc *desc;
+ struct shm_signal_notifier *notifier;
+ struct tasklet_struct deferred_notify;
+};
+
+#define SHM_SIGNAL_FAULT(s, fmt, args...) \
+ ((s)->ops->fault ? (s)->ops->fault((s), fmt, ## args) : panic(fmt, ## args))
+
+ /*
+ * These functions should only be used internally
+ */
+void _shm_signal_release(struct kref *kref);
+void _shm_signal_wakeup(struct shm_signal *s);
+
+/**
+ * shm_signal_init() - initialize an SHM_SIGNAL
+ * @s: SHM_SIGNAL context
+ *
+ * Initializes SHM_SIGNAL context before first use
+ *
+ **/
+void shm_signal_init(struct shm_signal *s, enum shm_signal_locality locale,
+ struct shm_signal_ops *ops, struct shm_signal_desc *desc);
+
+/**
+ * shm_signal_get() - acquire an SHM_SIGNAL context reference
+ * @s: SHM_SIGNAL context
+ *
+ **/
+static inline struct shm_signal *shm_signal_get(struct shm_signal *s)
+{
+ kref_get(&s->kref);
+
+ return s;
+}
+
+/**
+ * shm_signal_put() - release an SHM_SIGNAL context reference
+ * @s: SHM_SIGNAL context
+ *
+ **/
+static inline void shm_signal_put(struct shm_signal *s)
+{
+ kref_put(&s->kref, _shm_signal_release);
+}
+
+/**
+ * shm_signal_enable() - enables local notifications on an SHM_SIGNAL
+ * @s: SHM_SIGNAL context
+ * @flags: Reserved for future use, must be 0
+ *
+ * Enables/unmasks the registered notifier (if applicable) to receive wakeups
+ * whenever the remote side performs an shm_signal() operation. A notification
+ * will be dispatched immediately if any pending signals have already been
+ * issued prior to invoking this call.
+ *
+ * This is synonymous with unmasking an interrupt.
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int shm_signal_enable(struct shm_signal *s, int flags);
+
+/**
+ * shm_signal_disable() - disable local notifications on an SHM_SIGNAL
+ * @s: SHM_SIGNAL context
+ * @flags: Reserved for future use, must be 0
+ *
+ * Disables/masks the registered shm_signal_notifier (if applicable) from
+ * receiving any further notifications. Any subsequent calls to shm_signal()
+ * by the remote side will update the shm as dirty, but will not traverse the
+ * locale boundary and will not invoke the notifier callback. Signals
+ * delivered while masked will be deferred until shm_signal_enable() is
+ * invoked.
+ *
+ * This is synonymous with masking an interrupt
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int shm_signal_disable(struct shm_signal *s, int flags);
+
+/**
+ * shm_signal_inject() - notify the remote side about shm changes
+ * @s: SHM_SIGNAL context
+ * @flags: Reserved for future use, must be 0
+ *
+ * Marks the shm state as "dirty" and, if enabled, will traverse
+ * a locale boundary to inject a remote notification. The remote
+ * side controls whether the notification should be delivered via
+ * the shm_signal_enable/disable() interface.
+ *
+ * The specifics of how to traverse a locale boundary are abstracted
+ * by the shm_signal_ops->signal() interface and provided by a particular
+ * implementation. However, typically going north to south would be
+ * something like a syscall/hypercall, and going south to north would be
+ * something like a posix-signal/guest-interrupt.
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int shm_signal_inject(struct shm_signal *s, int flags);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_SHM_SIGNAL_H */
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index df7b23ac66e6..0c68fbd6faac 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -389,8 +389,10 @@ struct sk_buff {
#ifdef CONFIG_NETWORK_SECMARK
__u32 secmark;
#endif
-
- __u32 mark;
+ union {
+ __u32 mark;
+ __u32 dropcount;
+ };
__u16 vlan_tci;
@@ -1489,6 +1491,16 @@ static inline struct sk_buff *netdev_alloc_skb(struct net_device *dev,
return __netdev_alloc_skb(dev, length, GFP_ATOMIC);
}
+static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev,
+ unsigned int length)
+{
+ struct sk_buff *skb = netdev_alloc_skb(dev, length + NET_IP_ALIGN);
+
+ if (NET_IP_ALIGN && skb)
+ skb_reserve(skb, NET_IP_ALIGN);
+ return skb;
+}
+
extern struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask);
/**
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 2da8372519f5..62d2b16d9ff2 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -74,6 +74,10 @@
/* The following flags affect the page allocator grouping pages by mobility */
#define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */
#define SLAB_TEMPORARY SLAB_RECLAIM_ACCOUNT /* Objects are short-lived */
+
+/* Following flags should only be used by allocator specific flags */
+#define SLAB_ALLOC_PRIVATE 0x000000ffUL
+
/*
* ZERO_SIZE_PTR will be returned for zero sized kmalloc requests.
*
@@ -160,6 +164,8 @@ size_t ksize(const void *);
*/
#ifdef CONFIG_SLUB
#include <linux/slub_def.h>
+#elif defined(CONFIG_SLQB)
+#include <linux/slqb_def.h>
#elif defined(CONFIG_SLOB)
#include <linux/slob_def.h>
#else
@@ -262,7 +268,7 @@ static inline void *kmem_cache_alloc_node(struct kmem_cache *cachep,
* allocator where we care about the real place the memory allocation
* request comes from.
*/
-#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB)
+#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) || defined(CONFIG_SLQB_DEBUG)
extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long);
#define kmalloc_track_caller(size, flags) \
__kmalloc_track_caller(size, flags, _RET_IP_)
@@ -280,7 +286,7 @@ extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long);
* standard allocator where we care about the real place the memory
* allocation request comes from.
*/
-#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB)
+#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) || defined(CONFIG_SLQB_DEBUG)
extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, unsigned long);
#define kmalloc_node_track_caller(size, flags, node) \
__kmalloc_node_track_caller(size, flags, node, \
diff --git a/include/linux/slqb_def.h b/include/linux/slqb_def.h
new file mode 100644
index 000000000000..1243dda50473
--- /dev/null
+++ b/include/linux/slqb_def.h
@@ -0,0 +1,301 @@
+#ifndef _LINUX_SLQB_DEF_H
+#define _LINUX_SLQB_DEF_H
+
+/*
+ * SLQB : A slab allocator with object queues.
+ *
+ * (C) 2008 Nick Piggin <npiggin@suse.de>
+ */
+#include <linux/types.h>
+#include <linux/gfp.h>
+#include <linux/workqueue.h>
+#include <linux/kobject.h>
+#include <linux/rcu_types.h>
+#include <linux/mm_types.h>
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+
+#define SLAB_NUMA 0x00000001UL /* shortcut */
+
+enum stat_item {
+ ALLOC, /* Allocation count */
+ ALLOC_SLAB_FILL, /* Fill freelist from page list */
+ ALLOC_SLAB_NEW, /* New slab acquired from page allocator */
+ FREE, /* Free count */
+ FREE_REMOTE, /* NUMA: freeing to remote list */
+ FLUSH_FREE_LIST, /* Freelist flushed */
+ FLUSH_FREE_LIST_OBJECTS, /* Objects flushed from freelist */
+ FLUSH_FREE_LIST_REMOTE, /* Objects flushed from freelist to remote */
+ FLUSH_SLAB_PARTIAL, /* Freeing moves slab to partial list */
+ FLUSH_SLAB_FREE, /* Slab freed to the page allocator */
+ FLUSH_RFREE_LIST, /* Rfree list flushed */
+ FLUSH_RFREE_LIST_OBJECTS, /* Rfree objects flushed */
+ CLAIM_REMOTE_LIST, /* Remote freed list claimed */
+ CLAIM_REMOTE_LIST_OBJECTS, /* Remote freed objects claimed */
+ NR_SLQB_STAT_ITEMS
+};
+
+/*
+ * Singly-linked list with head, tail, and nr
+ */
+struct kmlist {
+ unsigned long nr;
+ void **head;
+ void **tail;
+};
+
+/*
+ * Every kmem_cache_list has a kmem_cache_remote_free structure, by which
+ * objects can be returned to the kmem_cache_list from remote CPUs.
+ */
+struct kmem_cache_remote_free {
+ spinlock_t lock;
+ struct kmlist list;
+} ____cacheline_aligned;
+
+/*
+ * A kmem_cache_list manages all the slabs and objects allocated from a given
+ * source. Per-cpu kmem_cache_lists allow node-local allocations. Per-node
+ * kmem_cache_lists allow off-node allocations (but require locking).
+ */
+struct kmem_cache_list {
+ /* Fastpath LIFO freelist of objects */
+ struct kmlist freelist;
+#ifdef CONFIG_SMP
+ /* remote_free has reached a watermark */
+ int remote_free_check;
+#endif
+ /* kmem_cache corresponding to this list */
+ struct kmem_cache *cache;
+
+ /* Number of partial slabs (pages) */
+ unsigned long nr_partial;
+
+ /* Slabs which have some free objects */
+ struct list_head partial;
+
+ /* Total number of slabs allocated */
+ unsigned long nr_slabs;
+
+ /* Protects nr_partial, nr_slabs, and partial */
+ spinlock_t page_lock;
+
+#ifdef CONFIG_SMP
+ /*
+ * In the case of per-cpu lists, remote_free is for objects freed by
+ * non-owner CPU back to its home list. For per-node lists, remote_free
+ * is always used to free objects.
+ */
+ struct kmem_cache_remote_free remote_free;
+#endif
+
+#ifdef CONFIG_SLQB_STATS
+ unsigned long stats[NR_SLQB_STAT_ITEMS];
+#endif
+} ____cacheline_aligned;
+
+/*
+ * Primary per-cpu, per-kmem_cache structure.
+ */
+struct kmem_cache_cpu {
+ struct kmem_cache_list list; /* List for node-local slabs */
+ unsigned int colour_next; /* Next colour offset to use */
+
+#ifdef CONFIG_SMP
+ /*
+ * rlist is a list of objects that don't fit on list.freelist (ie.
+ * wrong node). The objects all correspond to a given kmem_cache_list,
+ * remote_cache_list. To free objects to another list, we must first
+ * flush the existing objects, then switch remote_cache_list.
+ *
+ * An NR_CPUS or MAX_NUMNODES array would be nice here, but then we
+ * get to O(NR_CPUS^2) memory consumption situation.
+ */
+ struct kmlist rlist;
+ struct kmem_cache_list *remote_cache_list;
+#endif
+} ____cacheline_aligned_in_smp;
+
+/*
+ * Per-node, per-kmem_cache structure. Used for node-specific allocations.
+ */
+struct kmem_cache_node {
+ struct kmem_cache_list list;
+ spinlock_t list_lock; /* protects access to list */
+} ____cacheline_aligned;
+
+/*
+ * Management object for a slab cache.
+ */
+struct kmem_cache {
+ unsigned long flags;
+ int hiwater; /* LIFO list high watermark */
+ int freebatch; /* LIFO freelist batch flush size */
+#ifdef CONFIG_SMP
+ struct kmem_cache_cpu **cpu_slab; /* dynamic per-cpu structures */
+#else
+ struct kmem_cache_cpu cpu_slab;
+#endif
+ int objsize; /* Size of object without meta data */
+ int offset; /* Free pointer offset. */
+ int objects; /* Number of objects in slab */
+
+#ifdef CONFIG_NUMA
+ struct kmem_cache_node **node_slab; /* dynamic per-node structures */
+#endif
+
+ int size; /* Size of object including meta data */
+ int order; /* Allocation order */
+ gfp_t allocflags; /* gfp flags to use on allocation */
+ unsigned int colour_range; /* range of colour counter */
+ unsigned int colour_off; /* offset per colour */
+ void (*ctor)(void *);
+
+ const char *name; /* Name (only for display!) */
+ struct list_head list; /* List of slab caches */
+
+ int align; /* Alignment */
+ int inuse; /* Offset to metadata */
+
+#ifdef CONFIG_SLQB_SYSFS
+ struct kobject kobj; /* For sysfs */
+#endif
+} ____cacheline_aligned;
+
+/*
+ * Kmalloc subsystem.
+ */
+#if defined(ARCH_KMALLOC_MINALIGN) && ARCH_KMALLOC_MINALIGN > 8
+#define KMALLOC_MIN_SIZE ARCH_KMALLOC_MINALIGN
+#else
+#define KMALLOC_MIN_SIZE 8
+#endif
+
+#define KMALLOC_SHIFT_LOW ilog2(KMALLOC_MIN_SIZE)
+#define KMALLOC_SHIFT_SLQB_HIGH (PAGE_SHIFT + \
+ ((9 <= (MAX_ORDER - 1)) ? 9 : (MAX_ORDER - 1)))
+
+extern struct kmem_cache kmalloc_caches[KMALLOC_SHIFT_SLQB_HIGH + 1];
+extern struct kmem_cache kmalloc_caches_dma[KMALLOC_SHIFT_SLQB_HIGH + 1];
+
+/*
+ * Constant size allocations use this path to find index into kmalloc caches
+ * arrays. get_slab() function is used for non-constant sizes.
+ */
+static __always_inline int kmalloc_index(size_t size)
+{
+ extern int ____kmalloc_too_large(void);
+
+ if (unlikely(size <= KMALLOC_MIN_SIZE))
+ return KMALLOC_SHIFT_LOW;
+
+#if L1_CACHE_BYTES < 64
+ if (size > 64 && size <= 96)
+ return 1;
+#endif
+#if L1_CACHE_BYTES < 128
+ if (size > 128 && size <= 192)
+ return 2;
+#endif
+ if (size <= 8) return 3;
+ if (size <= 16) return 4;
+ if (size <= 32) return 5;
+ if (size <= 64) return 6;
+ if (size <= 128) return 7;
+ if (size <= 256) return 8;
+ if (size <= 512) return 9;
+ if (size <= 1024) return 10;
+ if (size <= 2 * 1024) return 11;
+ if (size <= 4 * 1024) return 12;
+ if (size <= 8 * 1024) return 13;
+ if (size <= 16 * 1024) return 14;
+ if (size <= 32 * 1024) return 15;
+ if (size <= 64 * 1024) return 16;
+ if (size <= 128 * 1024) return 17;
+ if (size <= 256 * 1024) return 18;
+ if (size <= 512 * 1024) return 19;
+ if (size <= 1024 * 1024) return 20;
+ if (size <= 2 * 1024 * 1024) return 21;
+ if (size <= 4 * 1024 * 1024) return 22;
+ if (size <= 8 * 1024 * 1024) return 23;
+ if (size <= 16 * 1024 * 1024) return 24;
+ if (size <= 32 * 1024 * 1024) return 25;
+ return ____kmalloc_too_large();
+}
+
+#ifdef CONFIG_ZONE_DMA
+#define SLQB_DMA __GFP_DMA
+#else
+/* Disable "DMA slabs" */
+#define SLQB_DMA (__force gfp_t)0
+#endif
+
+/*
+ * Find the kmalloc slab cache for a given combination of allocation flags and
+ * size. Should really only be used for constant 'size' arguments, due to
+ * bloat.
+ */
+static __always_inline struct kmem_cache *kmalloc_slab(size_t size, gfp_t flags)
+{
+ int index;
+
+ if (unlikely(size > 1UL << KMALLOC_SHIFT_SLQB_HIGH))
+ return NULL;
+ if (unlikely(!size))
+ return ZERO_SIZE_PTR;
+
+ index = kmalloc_index(size);
+ if (likely(!(flags & SLQB_DMA)))
+ return &kmalloc_caches[index];
+ else
+ return &kmalloc_caches_dma[index];
+}
+
+void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
+void *__kmalloc(size_t size, gfp_t flags);
+
+#ifndef ARCH_KMALLOC_MINALIGN
+#define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long long)
+#endif
+
+#ifndef ARCH_SLAB_MINALIGN
+#define ARCH_SLAB_MINALIGN __alignof__(unsigned long long)
+#endif
+
+#define KMALLOC_HEADER (ARCH_KMALLOC_MINALIGN < sizeof(void *) ? \
+ sizeof(void *) : ARCH_KMALLOC_MINALIGN)
+
+static __always_inline void *kmalloc(size_t size, gfp_t flags)
+{
+ if (__builtin_constant_p(size)) {
+ struct kmem_cache *s;
+
+ s = kmalloc_slab(size, flags);
+ if (unlikely(ZERO_OR_NULL_PTR(s)))
+ return s;
+
+ return kmem_cache_alloc(s, flags);
+ }
+ return __kmalloc(size, flags);
+}
+
+#ifdef CONFIG_NUMA
+void *__kmalloc_node(size_t size, gfp_t flags, int node);
+void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
+
+static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
+{
+ if (__builtin_constant_p(size)) {
+ struct kmem_cache *s;
+
+ s = kmalloc_slab(size, flags);
+ if (unlikely(ZERO_OR_NULL_PTR(s)))
+ return s;
+
+ return kmem_cache_alloc_node(s, flags, node);
+ }
+ return __kmalloc_node(size, flags, node);
+}
+#endif
+
+#endif /* _LINUX_SLQB_DEF_H */
diff --git a/include/linux/smp_lock.h b/include/linux/smp_lock.h
index 813be59bf345..2ea1dd1ba21c 100644
--- a/include/linux/smp_lock.h
+++ b/include/linux/smp_lock.h
@@ -24,8 +24,21 @@ static inline int reacquire_kernel_lock(struct task_struct *task)
return 0;
}
-extern void __lockfunc lock_kernel(void) __acquires(kernel_lock);
-extern void __lockfunc unlock_kernel(void) __releases(kernel_lock);
+extern void __lockfunc
+_lock_kernel(const char *func, const char *file, int line)
+__acquires(kernel_lock);
+
+extern void __lockfunc
+_unlock_kernel(const char *func, const char *file, int line)
+__releases(kernel_lock);
+
+#define lock_kernel() do { \
+ _lock_kernel(__func__, __FILE__, __LINE__); \
+} while (0)
+
+#define unlock_kernel() do { \
+ _unlock_kernel(__func__, __FILE__, __LINE__); \
+} while (0)
/*
* Various legacy drivers don't really need the BKL in a specific
@@ -41,8 +54,8 @@ static inline void cycle_kernel_lock(void)
#else
-#define lock_kernel() do { } while(0)
-#define unlock_kernel() do { } while(0)
+#define lock_kernel()
+#define unlock_kernel()
#define release_kernel_lock(task) do { } while(0)
#define cycle_kernel_lock() do { } while(0)
#define reacquire_kernel_lock(task) 0
diff --git a/include/linux/smsc911x.h b/include/linux/smsc911x.h
index 5241e4fb4eca..7144e8aa1e41 100644
--- a/include/linux/smsc911x.h
+++ b/include/linux/smsc911x.h
@@ -30,6 +30,7 @@ struct smsc911x_platform_config {
unsigned int irq_type;
unsigned int flags;
phy_interface_t phy_interface;
+ unsigned char mac[6];
};
/* Constants for platform_device irq polarity configuration */
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 3273a0c5043b..59966f12990c 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -65,6 +65,12 @@ struct msghdr {
unsigned msg_flags;
};
+/* For recvmmsg/sendmmsg */
+struct mmsghdr {
+ struct msghdr msg_hdr;
+ unsigned msg_len;
+};
+
/*
* POSIX 1003.1g - ancillary data object information
* Ancillary data consits of a sequence of pairs of
@@ -312,6 +318,10 @@ extern int move_addr_to_user(struct sockaddr *kaddr, int klen, void __user *uadd
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);
+struct timespec;
+
+extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
+ unsigned int flags, struct timespec *timeout);
#endif
#endif /* not kernel and not glibc */
#endif /* _LINUX_SOCKET_H */
diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h
index eed4254bd503..3274c507b8a9 100644
--- a/include/linux/spi/spi_bitbang.h
+++ b/include/linux/spi/spi_bitbang.h
@@ -15,7 +15,7 @@
* Some hardware works well with requests at spi_transfer scope:
*
* - Drivers leveraging smarter hardware, with fifos or DMA; or for half
- * duplex (MicroWire) controllers. Provide chipslect() and txrx_bufs(),
+ * duplex (MicroWire) controllers. Provide chipselect() and txrx_bufs(),
* and custom setup()/cleanup() methods.
*/
diff --git a/include/linux/srcu.h b/include/linux/srcu.h
index aca0eee53930..4765d97dcafb 100644
--- a/include/linux/srcu.h
+++ b/include/linux/srcu.h
@@ -48,6 +48,7 @@ void cleanup_srcu_struct(struct srcu_struct *sp);
int srcu_read_lock(struct srcu_struct *sp) __acquires(sp);
void srcu_read_unlock(struct srcu_struct *sp, int idx) __releases(sp);
void synchronize_srcu(struct srcu_struct *sp);
+void synchronize_srcu_expedited(struct srcu_struct *sp);
long srcu_batches_completed(struct srcu_struct *sp);
#endif
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index 3d0a9ff24f01..24f988547361 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -269,7 +269,8 @@ struct ssb_bus {
const struct ssb_bus_ops *ops;
- /* The core in the basic address register window. (PCI bus only) */
+ /* The core currently mapped into the MMIO window.
+ * Not valid on all host-buses. So don't use outside of SSB. */
struct ssb_device *mapped_device;
union {
/* Currently mapped PCMCIA segment. (bustype == SSB_BUSTYPE_PCMCIA only) */
@@ -281,14 +282,17 @@ struct ssb_bus {
* On PCMCIA-host busses this is used to protect the whole MMIO access. */
spinlock_t bar_lock;
- /* The bus this backplane is running on. */
+ /* The host-bus this backplane is running on. */
enum ssb_bustype bustype;
- /* Pointer to the PCI bus (only valid if bustype == SSB_BUSTYPE_PCI). */
- struct pci_dev *host_pci;
- /* Pointer to the PCMCIA device (only if bustype == SSB_BUSTYPE_PCMCIA). */
- struct pcmcia_device *host_pcmcia;
- /* Pointer to the SDIO device (only if bustype == SSB_BUSTYPE_SDIO). */
- struct sdio_func *host_sdio;
+ /* Pointers to the host-bus. Check bustype before using any of these pointers. */
+ union {
+ /* Pointer to the PCI bus (only valid if bustype == SSB_BUSTYPE_PCI). */
+ struct pci_dev *host_pci;
+ /* Pointer to the PCMCIA device (only if bustype == SSB_BUSTYPE_PCMCIA). */
+ struct pcmcia_device *host_pcmcia;
+ /* Pointer to the SDIO device (only if bustype == SSB_BUSTYPE_SDIO). */
+ struct sdio_func *host_sdio;
+ };
/* See enum ssb_quirks */
unsigned int quirks;
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index a990ace1a838..f03a2d9eddc2 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -25,6 +25,7 @@ struct linux_dirent64;
struct list_head;
struct msgbuf;
struct msghdr;
+struct mmsghdr;
struct msqid_ds;
struct new_utsname;
struct nfsctl_arg;
@@ -100,23 +101,23 @@ struct perf_event_attr;
#ifdef CONFIG_EVENT_PROFILE
#define TRACE_SYS_ENTER_PROFILE(sname) \
-static int prof_sysenter_enable_##sname(void) \
+static int prof_sysenter_enable_##sname(struct ftrace_event_call *unused) \
{ \
return reg_prof_syscall_enter("sys"#sname); \
} \
\
-static void prof_sysenter_disable_##sname(void) \
+static void prof_sysenter_disable_##sname(struct ftrace_event_call *unused) \
{ \
unreg_prof_syscall_enter("sys"#sname); \
}
#define TRACE_SYS_EXIT_PROFILE(sname) \
-static int prof_sysexit_enable_##sname(void) \
+static int prof_sysexit_enable_##sname(struct ftrace_event_call *unused) \
{ \
return reg_prof_syscall_exit("sys"#sname); \
} \
\
-static void prof_sysexit_disable_##sname(void) \
+static void prof_sysexit_disable_##sname(struct ftrace_event_call *unused) \
{ \
unreg_prof_syscall_exit("sys"#sname); \
}
@@ -157,7 +158,7 @@ static void prof_sysexit_disable_##sname(void) \
struct trace_event enter_syscall_print_##sname = { \
.trace = print_syscall_enter, \
}; \
- static int init_enter_##sname(void) \
+ static int init_enter_##sname(struct ftrace_event_call *call) \
{ \
int num, id; \
num = syscall_name_to_nr("sys"#sname); \
@@ -193,7 +194,7 @@ static void prof_sysexit_disable_##sname(void) \
struct trace_event exit_syscall_print_##sname = { \
.trace = print_syscall_exit, \
}; \
- static int init_exit_##sname(void) \
+ static int init_exit_##sname(struct ftrace_event_call *call) \
{ \
int num, id; \
num = syscall_name_to_nr("sys"#sname); \
@@ -677,6 +678,9 @@ asmlinkage long sys_recv(int, void __user *, size_t, unsigned);
asmlinkage long sys_recvfrom(int, void __user *, size_t, unsigned,
struct sockaddr __user *, int __user *);
asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags);
+asmlinkage long sys_recvmmsg(int fd, struct mmsghdr __user *msg,
+ unsigned int vlen, unsigned flags,
+ struct timespec __user *timeout);
asmlinkage long sys_socket(int, int, int);
asmlinkage long sys_socketpair(int, int, int, int __user *);
asmlinkage long sys_socketcall(int call, unsigned long __user *args);
diff --git a/include/linux/tc_act/tc_skbedit.h b/include/linux/tc_act/tc_skbedit.h
index a14e461a7af7..7a2e910a5f08 100644
--- a/include/linux/tc_act/tc_skbedit.h
+++ b/include/linux/tc_act/tc_skbedit.h
@@ -26,6 +26,7 @@
#define SKBEDIT_F_PRIORITY 0x1
#define SKBEDIT_F_QUEUE_MAPPING 0x2
+#define SKBEDIT_F_MARK 0x4
struct tc_skbedit {
tc_gen;
@@ -37,6 +38,7 @@ enum {
TCA_SKBEDIT_PARMS,
TCA_SKBEDIT_PRIORITY,
TCA_SKBEDIT_QUEUE_MAPPING,
+ TCA_SKBEDIT_MARK,
__TCA_SKBEDIT_MAX
};
#define TCA_SKBEDIT_MAX (__TCA_SKBEDIT_MAX - 1)
diff --git a/include/linux/timex.h b/include/linux/timex.h
index e6967d10d9e5..94f8faecdcbc 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -115,13 +115,16 @@ struct timex {
#define ADJ_OFFSET_SS_READ 0xa001 /* read-only adjtime */
#endif
-/* xntp 3.4 compatibility names */
+/* NTP userland likes the MOD_ prefix better */
#define MOD_OFFSET ADJ_OFFSET
#define MOD_FREQUENCY ADJ_FREQUENCY
#define MOD_MAXERROR ADJ_MAXERROR
#define MOD_ESTERROR ADJ_ESTERROR
#define MOD_STATUS ADJ_STATUS
#define MOD_TIMECONST ADJ_TIMECONST
+#define MOD_TAI ADJ_TAI
+#define MOD_MICRO ADJ_MICRO
+#define MOD_NANO ADJ_NANO
/*
@@ -261,11 +264,7 @@ static inline int ntp_synced(void)
#define NTP_SCALE_SHIFT 32
-#ifdef CONFIG_NO_HZ
-#define NTP_INTERVAL_FREQ (2)
-#else
#define NTP_INTERVAL_FREQ (HZ)
-#endif
#define NTP_INTERVAL_LENGTH (NSEC_PER_SEC/NTP_INTERVAL_FREQ)
/* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */
diff --git a/include/linux/topology.h b/include/linux/topology.h
index fc0bf3edeb67..57e63579bfdd 100644
--- a/include/linux/topology.h
+++ b/include/linux/topology.h
@@ -129,7 +129,7 @@ int arch_update_cpu_topology(void);
| 1*SD_BALANCE_FORK \
| 0*SD_BALANCE_WAKE \
| 1*SD_WAKE_AFFINE \
- | 1*SD_PREFER_LOCAL \
+ | 0*SD_PREFER_LOCAL \
| 0*SD_SHARE_CPUPOWER \
| 1*SD_SHARE_PKG_RESOURCES \
| 0*SD_SERIALIZE \
@@ -162,7 +162,7 @@ int arch_update_cpu_topology(void);
| 1*SD_BALANCE_FORK \
| 0*SD_BALANCE_WAKE \
| 1*SD_WAKE_AFFINE \
- | 1*SD_PREFER_LOCAL \
+ | 0*SD_PREFER_LOCAL \
| 0*SD_SHARE_CPUPOWER \
| 0*SD_SHARE_PKG_RESOURCES \
| 0*SD_SERIALIZE \
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index 3338b3f5c21a..8eaa8f83effb 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -31,5 +31,12 @@
extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf);
extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash);
+#else
+static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) {
+ return -ENODEV;
+}
+static inline int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) {
+ return -ENODEV;
+}
#endif
#endif
diff --git a/include/linux/trace_seq.h b/include/linux/trace_seq.h
index c134dd1fe6b6..09077f6ed128 100644
--- a/include/linux/trace_seq.h
+++ b/include/linux/trace_seq.h
@@ -7,7 +7,7 @@
/*
* Trace sequences are used to allow a function to call several other functions
- * to create a string of data to use (up to a max of PAGE_SIZE.
+ * to create a string of data to use (up to a max of PAGE_SIZE).
*/
struct trace_seq {
diff --git a/include/linux/udp.h b/include/linux/udp.h
index 0cf5c4c0ec81..832361e3e596 100644
--- a/include/linux/udp.h
+++ b/include/linux/udp.h
@@ -45,11 +45,11 @@ static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
return (struct udphdr *)skb_transport_header(skb);
}
-#define UDP_HTABLE_SIZE 128
+#define UDP_HTABLE_SIZE_MIN (CONFIG_BASE_SMALL ? 128 : 256)
-static inline int udp_hashfn(struct net *net, const unsigned num)
+static inline int udp_hashfn(struct net *net, unsigned num, unsigned mask)
{
- return (num + net_hash_mix(net)) & (UDP_HTABLE_SIZE - 1);
+ return (num + net_hash_mix(net)) & mask;
}
struct udp_sock {
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index f81473052059..86c31b753266 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -90,6 +90,7 @@ struct driver_info {
#define FLAG_WLAN 0x0080 /* use "wlan%d" names */
#define FLAG_AVOID_UNLINK_URBS 0x0100 /* don't unlink urbs at usbnet_stop() */
#define FLAG_SEND_ZLP 0x0200 /* hw requires ZLPs are sent */
+#define FLAG_WWAN 0x0400 /* use "wwan%d" names */
/* init device ... can sleep, or cause probe() failure */
diff --git a/include/linux/user-return-notifier.h b/include/linux/user-return-notifier.h
new file mode 100644
index 000000000000..b6ac056291d7
--- /dev/null
+++ b/include/linux/user-return-notifier.h
@@ -0,0 +1,42 @@
+#ifndef _LINUX_USER_RETURN_NOTIFIER_H
+#define _LINUX_USER_RETURN_NOTIFIER_H
+
+#ifdef CONFIG_USER_RETURN_NOTIFIER
+
+#include <linux/list.h>
+#include <linux/sched.h>
+
+struct user_return_notifier {
+ void (*on_user_return)(struct user_return_notifier *urn);
+ struct hlist_node link;
+};
+
+
+void user_return_notifier_register(struct user_return_notifier *urn);
+void user_return_notifier_unregister(struct user_return_notifier *urn);
+
+static inline void propagate_user_return_notify(struct task_struct *prev,
+ struct task_struct *next)
+{
+ if (test_tsk_thread_flag(prev, TIF_USER_RETURN_NOTIFY)) {
+ clear_tsk_thread_flag(prev, TIF_USER_RETURN_NOTIFY);
+ set_tsk_thread_flag(next, TIF_USER_RETURN_NOTIFY);
+ }
+}
+
+void fire_user_return_notifiers(void);
+
+#else
+
+struct user_return_notifier {};
+
+static inline void propagate_user_return_notify(struct task_struct *prev,
+ struct task_struct *next)
+{
+}
+
+static inline void fire_user_return_notifiers(void) {}
+
+#endif
+
+#endif
diff --git a/include/linux/vbus_driver.h b/include/linux/vbus_driver.h
new file mode 100644
index 000000000000..2b1dac47f180
--- /dev/null
+++ b/include/linux/vbus_driver.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2009 Novell. All Rights Reserved.
+ *
+ * Mediates access to a host VBUS from a guest kernel by providing a
+ * global view of all VBUS devices
+ *
+ * Author:
+ * Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file 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 St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LINUX_VBUS_DRIVER_H
+#define _LINUX_VBUS_DRIVER_H
+
+#include <linux/device.h>
+#include <linux/shm_signal.h>
+#include <linux/ioq.h>
+
+struct vbus_device_proxy;
+struct vbus_driver;
+
+struct vbus_device_proxy_ops {
+ int (*open)(struct vbus_device_proxy *dev, int version, int flags);
+ int (*close)(struct vbus_device_proxy *dev, int flags);
+ int (*shm)(struct vbus_device_proxy *dev, const char *name,
+ int id, int prio,
+ void *ptr, size_t len,
+ struct shm_signal_desc *sigdesc, struct shm_signal **signal,
+ int flags);
+ int (*call)(struct vbus_device_proxy *dev, u32 func,
+ void *data, size_t len, int flags);
+ void (*release)(struct vbus_device_proxy *dev);
+};
+
+struct vbus_device_proxy {
+ char *type;
+ u64 id;
+ void *priv; /* Used by drivers */
+ struct vbus_device_proxy_ops *ops;
+ struct device dev;
+};
+
+int vbus_device_proxy_register(struct vbus_device_proxy *dev);
+void vbus_device_proxy_unregister(struct vbus_device_proxy *dev);
+
+struct vbus_device_proxy *vbus_device_proxy_find(u64 id);
+
+struct vbus_driver_ops {
+ int (*probe)(struct vbus_device_proxy *dev);
+ int (*remove)(struct vbus_device_proxy *dev);
+};
+
+struct vbus_driver {
+ char *type;
+ struct module *owner;
+ struct vbus_driver_ops *ops;
+ struct device_driver drv;
+};
+
+int vbus_driver_register(struct vbus_driver *drv);
+void vbus_driver_unregister(struct vbus_driver *drv);
+
+/*
+ * driver-side IOQ helper - allocates device-shm and maps an IOQ on it
+ */
+int vbus_driver_ioq_alloc(struct vbus_device_proxy *dev, const char *name,
+ int id, int prio, size_t ringsize, struct ioq **ioq);
+
+#endif /* _LINUX_VBUS_DRIVER_H */
diff --git a/include/linux/vbus_pci.h b/include/linux/vbus_pci.h
new file mode 100644
index 000000000000..fe337590e644
--- /dev/null
+++ b/include/linux/vbus_pci.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2009 Novell. All Rights Reserved.
+ *
+ * PCI to Virtual-Bus Bridge
+ *
+ * Author:
+ * Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file 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 St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LINUX_VBUS_PCI_H
+#define _LINUX_VBUS_PCI_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define VBUS_PCI_ABI_MAGIC 0xbf53eef5
+#define VBUS_PCI_ABI_VERSION 2
+#define VBUS_PCI_HC_VERSION 1
+
+enum {
+ VBUS_PCI_BRIDGE_NEGOTIATE,
+ VBUS_PCI_BRIDGE_QREG,
+ VBUS_PCI_BRIDGE_SLOWCALL,
+ VBUS_PCI_BRIDGE_FASTCALL_ADD,
+ VBUS_PCI_BRIDGE_FASTCALL_DROP,
+
+ VBUS_PCI_BRIDGE_MAX, /* must be last */
+};
+
+enum {
+ VBUS_PCI_HC_DEVOPEN,
+ VBUS_PCI_HC_DEVCLOSE,
+ VBUS_PCI_HC_DEVCALL,
+ VBUS_PCI_HC_DEVSHM,
+
+ VBUS_PCI_HC_MAX, /* must be last */
+};
+
+struct vbus_pci_bridge_negotiate {
+ __u32 magic;
+ __u32 version;
+ __u64 capabilities;
+};
+
+struct vbus_pci_deviceopen {
+ __u32 devid;
+ __u32 version; /* device ABI version */
+ __u64 handle; /* return value for devh */
+};
+
+struct vbus_pci_devicecall {
+ __u64 devh; /* device-handle (returned from DEVICEOPEN */
+ __u32 func;
+ __u32 len;
+ __u32 flags;
+ __u64 datap;
+};
+
+struct vbus_pci_deviceshm {
+ __u64 devh; /* device-handle (returned from DEVICEOPEN */
+ __u32 id;
+ __u32 len;
+ __u32 flags;
+ struct {
+ __u32 offset;
+ __u32 prio;
+ __u64 cookie; /* token to pass back when signaling client */
+ } signal;
+ __u64 datap;
+};
+
+struct vbus_pci_call_desc {
+ __u32 vector;
+ __u32 len;
+ __u64 datap;
+};
+
+struct vbus_pci_fastcall_desc {
+ struct vbus_pci_call_desc call;
+ __u32 result;
+};
+
+struct vbus_pci_regs {
+ struct vbus_pci_call_desc bridgecall;
+ __u8 pad[48];
+};
+
+struct vbus_pci_signals {
+ __u32 eventq;
+ __u32 fastcall;
+ __u32 shmsignal;
+ __u8 pad[20];
+};
+
+struct vbus_pci_eventqreg {
+ __u32 count;
+ __u64 ring;
+ __u64 data;
+};
+
+struct vbus_pci_busreg {
+ __u32 count; /* supporting multiple queues allows for prio, etc */
+ struct vbus_pci_eventqreg eventq[1];
+};
+
+enum vbus_pci_eventid {
+ VBUS_PCI_EVENT_DEVADD,
+ VBUS_PCI_EVENT_DEVDROP,
+ VBUS_PCI_EVENT_SHMSIGNAL,
+ VBUS_PCI_EVENT_SHMCLOSE,
+};
+
+#define VBUS_MAX_DEVTYPE_LEN 128
+
+struct vbus_pci_add_event {
+ __u64 id;
+ char type[VBUS_MAX_DEVTYPE_LEN];
+};
+
+struct vbus_pci_handle_event {
+ __u64 handle;
+};
+
+struct vbus_pci_event {
+ __u32 eventid;
+ union {
+ struct vbus_pci_add_event add;
+ struct vbus_pci_handle_event handle;
+ } data;
+};
+
+#endif /* _LINUX_VBUS_PCI_H */
diff --git a/include/linux/venet.h b/include/linux/venet.h
new file mode 100644
index 000000000000..0578d797c973
--- /dev/null
+++ b/include/linux/venet.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2009 Novell. All Rights Reserved.
+ *
+ * Virtual-Ethernet adapter
+ *
+ * Author:
+ * Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file 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 St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LINUX_VENET_H
+#define _LINUX_VENET_H
+
+#include <linux/types.h>
+
+#define VENET_VERSION 1
+
+#define VENET_TYPE "virtual-ethernet"
+
+#define VENET_QUEUE_RX 0
+#define VENET_QUEUE_TX 1
+
+struct venet_capabilities {
+ __u32 gid;
+ __u32 bits;
+};
+
+#define VENET_CAP_GROUP_SG 0
+#define VENET_CAP_GROUP_EVENTQ 1
+#define VENET_CAP_GROUP_L4RO 2 /* layer-4 reassem offloading */
+
+/* CAPABILITIES-GROUP SG */
+#define VENET_CAP_SG (1 << 0)
+#define VENET_CAP_TSO4 (1 << 1)
+#define VENET_CAP_TSO6 (1 << 2)
+#define VENET_CAP_ECN (1 << 3)
+#define VENET_CAP_UFO (1 << 4)
+#define VENET_CAP_PMTD (1 << 5) /* pre-mapped tx desc */
+
+/* CAPABILITIES-GROUP EVENTQ */
+#define VENET_CAP_EVQ_LINKSTATE (1 << 0)
+#define VENET_CAP_EVQ_TXC (1 << 1) /* tx-complete */
+
+struct venet_iov {
+ __u32 len;
+ __u64 ptr;
+};
+
+#define VENET_SG_FLAG_NEEDS_CSUM (1 << 0)
+#define VENET_SG_FLAG_GSO (1 << 1)
+#define VENET_SG_FLAG_ECN (1 << 2)
+
+struct venet_sg {
+ __u64 cookie;
+ __u32 flags;
+ __u32 len; /* total length of all iovs */
+ struct {
+ __u16 start; /* csum starting position */
+ __u16 offset; /* offset to place csum */
+ } csum;
+ struct {
+#define VENET_GSO_TYPE_TCPV4 0 /* IPv4 TCP (TSO) */
+#define VENET_GSO_TYPE_UDP 1 /* IPv4 UDP (UFO) */
+#define VENET_GSO_TYPE_TCPV6 2 /* IPv6 TCP */
+ __u8 type;
+ __u16 hdrlen;
+ __u16 size;
+ } gso;
+ __u32 count; /* nr of iovs */
+ struct venet_iov iov[1];
+};
+
+struct venet_eventq_query {
+ __u32 flags;
+ __u32 evsize; /* size of each event */
+ __u32 dpid; /* descriptor pool-id */
+ __u32 qid;
+ __u8 pad[16];
+};
+
+#define VENET_EVENT_LINKSTATE 0
+#define VENET_EVENT_TXC 1
+
+struct venet_event_header {
+ __u32 flags;
+ __u32 size;
+ __u32 id;
+};
+
+struct venet_event_linkstate {
+ struct venet_event_header header;
+ __u8 state; /* 0 = down, 1 = up */
+};
+
+struct venet_event_txc {
+ struct venet_event_header header;
+ __u32 txqid;
+ __u64 cookie;
+};
+
+struct venet_l4ro_query {
+ __u32 flags;
+ __u32 dpid; /* descriptor pool-id */
+ __u32 pqid; /* page queue-id */
+ __u8 pad[20];
+};
+
+
+#define VSG_DESC_SIZE(count) (sizeof(struct venet_sg) + \
+ sizeof(struct venet_iov) * ((count) - 1))
+
+#define VENET_FUNC_LINKUP 0
+#define VENET_FUNC_LINKDOWN 1
+#define VENET_FUNC_MACQUERY 2
+#define VENET_FUNC_NEGCAP 3 /* negotiate capabilities */
+#define VENET_FUNC_FLUSHRX 4
+#define VENET_FUNC_PMTDQUERY 5
+#define VENET_FUNC_EVQQUERY 6
+#define VENET_FUNC_L4ROQUERY 7
+
+#endif /* _LINUX_VENET_H */
diff --git a/include/linux/vermagic.h b/include/linux/vermagic.h
index 79b9837d9ca0..cf97b5b9d1fe 100644
--- a/include/linux/vermagic.h
+++ b/include/linux/vermagic.h
@@ -1,4 +1,4 @@
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
#include <linux/module.h>
/* Simply sanity version stamp for modules. */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index b59e78c57161..469dbd0ec068 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -361,6 +361,7 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */
#define V4L2_PIX_FMT_OV511 v4l2_fourcc('O', '5', '1', '1') /* ov511 JPEG */
#define V4L2_PIX_FMT_OV518 v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */
+#define V4L2_PIX_FMT_TM6000 v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */
/*
* F O R M A T E N U M E R A T I O N
diff --git a/include/linux/virtio_9p.h b/include/linux/virtio_9p.h
index ea7226a45acb..095e10d148b4 100644
--- a/include/linux/virtio_9p.h
+++ b/include/linux/virtio_9p.h
@@ -2,6 +2,7 @@
#define _LINUX_VIRTIO_9P_H
/* This header is BSD licensed so anyone can use the definitions to implement
* compatible drivers/servers. */
+#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
/* Maximum number of virtio channels per partition (1 for now) */
diff --git a/include/linux/virtio_balloon.h b/include/linux/virtio_balloon.h
index 09d730085060..1418f048cb34 100644
--- a/include/linux/virtio_balloon.h
+++ b/include/linux/virtio_balloon.h
@@ -2,6 +2,7 @@
#define _LINUX_VIRTIO_BALLOON_H
/* This header is BSD licensed so anyone can use the definitions to implement
* compatible drivers/servers. */
+#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
/* The feature bitmap for virtio balloon */
diff --git a/include/linux/virtio_blk.h b/include/linux/virtio_blk.h
index 15cb666581d7..fd294c56d571 100644
--- a/include/linux/virtio_blk.h
+++ b/include/linux/virtio_blk.h
@@ -3,6 +3,7 @@
/* This header is BSD licensed so anyone can use the definitions to implement
* compatible drivers/servers. */
#include <linux/types.h>
+#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
/* Feature bits */
@@ -13,11 +14,8 @@
#define VIRTIO_BLK_F_RO 5 /* Disk is read-only */
#define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/
#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
-#define VIRTIO_BLK_F_IDENTIFY 8 /* ATA IDENTIFY supported */
#define VIRTIO_BLK_F_FLUSH 9 /* Cache flush command support */
-#define VIRTIO_BLK_ID_BYTES (sizeof(__u16[256])) /* IDENTIFY DATA */
-
struct virtio_blk_config {
/* The capacity (in 512-byte sectors). */
__u64 capacity;
@@ -33,7 +31,6 @@ struct virtio_blk_config {
} geometry;
/* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */
__u32 blk_size;
- __u8 identify[VIRTIO_BLK_ID_BYTES];
} __attribute__((packed));
/*
diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h
index b5f519806014..fe885174cc1f 100644
--- a/include/linux/virtio_console.h
+++ b/include/linux/virtio_console.h
@@ -1,6 +1,7 @@
#ifndef _LINUX_VIRTIO_CONSOLE_H
#define _LINUX_VIRTIO_CONSOLE_H
#include <linux/types.h>
+#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
/* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
* anyone can use the definitions to implement compatible drivers/servers. */
diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
index 1f41734bbb77..085e42298ce5 100644
--- a/include/linux/virtio_net.h
+++ b/include/linux/virtio_net.h
@@ -3,6 +3,7 @@
/* This header is BSD licensed so anyone can use the definitions to implement
* compatible drivers/servers. */
#include <linux/types.h>
+#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
#include <linux/if_ether.h>
diff --git a/include/linux/virtio_rng.h b/include/linux/virtio_rng.h
index 48121c3c434b..c4d5de896f0c 100644
--- a/include/linux/virtio_rng.h
+++ b/include/linux/virtio_rng.h
@@ -2,6 +2,7 @@
#define _LINUX_VIRTIO_RNG_H
/* This header is BSD licensed so anyone can use the definitions to implement
* compatible drivers/servers. */
+#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
#endif /* _LINUX_VIRTIO_RNG_H */
diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
index 2d0f222388a8..d85889710f9b 100644
--- a/include/linux/vmstat.h
+++ b/include/linux/vmstat.h
@@ -76,24 +76,22 @@ DECLARE_PER_CPU(struct vm_event_state, vm_event_states);
static inline void __count_vm_event(enum vm_event_item item)
{
- __get_cpu_var(vm_event_states).event[item]++;
+ __this_cpu_inc(per_cpu_var(vm_event_states).event[item]);
}
static inline void count_vm_event(enum vm_event_item item)
{
- get_cpu_var(vm_event_states).event[item]++;
- put_cpu();
+ this_cpu_inc(per_cpu_var(vm_event_states).event[item]);
}
static inline void __count_vm_events(enum vm_event_item item, long delta)
{
- __get_cpu_var(vm_event_states).event[item] += delta;
+ __this_cpu_add(per_cpu_var(vm_event_states).event[item], delta);
}
static inline void count_vm_events(enum vm_event_item item, long delta)
{
- get_cpu_var(vm_event_states).event[item] += delta;
- put_cpu();
+ this_cpu_add(per_cpu_var(vm_event_states).event[item], delta);
}
extern void all_vm_events(unsigned long *);
diff --git a/include/net/ah.h b/include/net/ah.h
index ae1c322f4242..7573a7152a72 100644
--- a/include/net/ah.h
+++ b/include/net/ah.h
@@ -1,43 +1,21 @@
#ifndef _NET_AH_H
#define _NET_AH_H
-#include <linux/crypto.h>
-#include <net/xfrm.h>
+#include <linux/skbuff.h>
/* This is the maximum truncated ICV length that we know of. */
#define MAX_AH_AUTH_LEN 12
+struct crypto_ahash;
+
struct ah_data
{
- u8 *work_icv;
int icv_full_len;
int icv_trunc_len;
- struct crypto_hash *tfm;
+ struct crypto_ahash *ahash;
};
-static inline int ah_mac_digest(struct ah_data *ahp, struct sk_buff *skb,
- u8 *auth_data)
-{
- struct hash_desc desc;
- int err;
-
- desc.tfm = ahp->tfm;
- desc.flags = 0;
-
- memset(auth_data, 0, ahp->icv_trunc_len);
- err = crypto_hash_init(&desc);
- if (unlikely(err))
- goto out;
- err = skb_icv_walk(skb, &desc, 0, skb->len, crypto_hash_update);
- if (unlikely(err))
- goto out;
- err = crypto_hash_final(&desc, ahp->work_icv);
-
-out:
- return err;
-}
-
struct ip_auth_hdr;
static inline struct ip_auth_hdr *ip_auth_hdr(const struct sk_buff *skb)
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 718394e2c01e..04a6908e38d2 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -121,7 +121,7 @@ struct bt_sock_list {
rwlock_t lock;
};
-int bt_sock_register(int proto, struct net_proto_family *ops);
+int bt_sock_register(int proto, const struct net_proto_family *ops);
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);
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 3d874c620219..ff67865de231 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1142,6 +1142,9 @@ struct wiphy {
u32 frag_threshold;
u32 rts_threshold;
+ char fw_version[ETHTOOL_BUSINFO_LEN];
+ u32 hw_version;
+
/* If multiple wiphys are registered and you're handed e.g.
* a regular netdev with assigned ieee80211_ptr, you won't
* know whether it points to a wiphy your driver has registered
@@ -1171,6 +1174,10 @@ struct wiphy {
struct net *_net;
#endif
+#ifdef CONFIG_CFG80211_WEXT
+ const struct iw_handler_def *wext;
+#endif
+
char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
};
@@ -1345,7 +1352,7 @@ struct wireless_dev {
struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES];
struct cfg80211_internal_bss *current_bss; /* associated / joined */
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
/* wext data */
struct {
struct cfg80211_ibss_params ibss;
@@ -1802,30 +1809,45 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr);
* @dev: network device
* @buf: deauthentication frame (header + body)
* @len: length of the frame data
- * @cookie: cookie from ->deauth if called within that callback,
- * %NULL otherwise
*
* This function is called whenever deauthentication has been processed in
* station mode. This includes both received deauthentication frames and
* locally generated ones. This function may sleep.
*/
-void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len,
- void *cookie);
+void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len);
+
+/**
+ * __cfg80211_send_deauth - notification of processed deauthentication
+ * @dev: network device
+ * @buf: deauthentication frame (header + body)
+ * @len: length of the frame data
+ *
+ * Like cfg80211_send_deauth(), but doesn't take the wdev lock.
+ */
+void __cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len);
/**
* cfg80211_send_disassoc - notification of processed disassociation
* @dev: network device
* @buf: disassociation response frame (header + body)
* @len: length of the frame data
- * @cookie: cookie from ->disassoc if called within that callback,
- * %NULL otherwise
*
* This function is called whenever disassociation has been processed in
* station mode. This includes both received disassociation frames and locally
* generated ones. This function may sleep.
*/
-void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len,
- void *cookie);
+void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len);
+
+/**
+ * __cfg80211_send_disassoc - notification of processed disassociation
+ * @dev: network device
+ * @buf: disassociation response frame (header + body)
+ * @len: length of the frame data
+ *
+ * Like cfg80211_send_disassoc(), but doesn't take the wdev lock.
+ */
+void __cfg80211_send_disassoc(struct net_device *dev, const u8 *buf,
+ size_t len);
/**
* cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP)
diff --git a/include/net/compat.h b/include/net/compat.h
index 7c3002832d05..3c7d4e38fa1d 100644
--- a/include/net/compat.h
+++ b/include/net/compat.h
@@ -18,6 +18,11 @@ struct compat_msghdr {
compat_uint_t msg_flags;
};
+struct compat_mmsghdr {
+ struct compat_msghdr msg_hdr;
+ compat_uint_t msg_len;
+};
+
struct compat_cmsghdr {
compat_size_t cmsg_len;
compat_int_t cmsg_level;
@@ -28,13 +33,20 @@ extern int compat_sock_get_timestamp(struct sock *, struct timeval __user *);
extern int compat_sock_get_timestampns(struct sock *, struct timespec __user *);
#else /* defined(CONFIG_COMPAT) */
-#define compat_msghdr msghdr /* to avoid compiler warnings */
+/*
+ * To avoid compiler warnings:
+ */
+#define compat_msghdr msghdr
+#define compat_mmsghdr mmsghdr
#endif /* defined(CONFIG_COMPAT) */
extern int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *);
extern int verify_compat_iovec(struct msghdr *, struct iovec *, struct sockaddr *, int);
extern asmlinkage long compat_sys_sendmsg(int,struct compat_msghdr __user *,unsigned);
extern asmlinkage long compat_sys_recvmsg(int,struct compat_msghdr __user *,unsigned);
+extern asmlinkage long compat_sys_recvmmsg(int, struct compat_mmsghdr __user *,
+ unsigned, unsigned,
+ struct timespec __user *);
extern asmlinkage long compat_sys_getsockopt(int, int, int, char __user *, int __user *);
extern int put_cmsg_compat(struct msghdr*, int, int, int, void *);
diff --git a/include/net/dst.h b/include/net/dst.h
index 5a900ddcf10d..720d90653a8e 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -222,11 +222,19 @@ static inline void dst_confirm(struct dst_entry *dst)
neigh_confirm(dst->neighbour);
}
-static inline void dst_negative_advice(struct dst_entry **dst_p)
+static inline void dst_negative_advice(struct dst_entry **dst_p,
+ struct sock *sk)
{
struct dst_entry * dst = *dst_p;
- if (dst && dst->ops->negative_advice)
+ if (dst && dst->ops->negative_advice) {
*dst_p = dst->ops->negative_advice(dst);
+
+ if (dst != *dst_p) {
+ extern void sk_reset_txq(struct sock *sk);
+
+ sk_reset_txq(sk);
+ }
+ }
}
static inline void dst_link_failure(struct sk_buff *skb)
diff --git a/include/net/gen_stats.h b/include/net/gen_stats.h
index c1488553e349..eb87a1447ae1 100644
--- a/include/net/gen_stats.h
+++ b/include/net/gen_stats.h
@@ -30,6 +30,7 @@ extern int gnet_stats_start_copy_compat(struct sk_buff *skb, int type,
extern int gnet_stats_copy_basic(struct gnet_dump *d,
struct gnet_stats_basic_packed *b);
extern int gnet_stats_copy_rate_est(struct gnet_dump *d,
+ const struct gnet_stats_basic_packed *b,
struct gnet_stats_rate_est *r);
extern int gnet_stats_copy_queue(struct gnet_dump *d,
struct gnet_stats_queue *q);
diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h
index 22c73a77cd99..92838d3a1ab7 100644
--- a/include/net/inet6_hashtables.h
+++ b/include/net/inet6_hashtables.h
@@ -46,8 +46,8 @@ static inline int inet6_sk_ehashfn(const struct sock *sk)
const struct ipv6_pinfo *np = inet6_sk(sk);
const struct in6_addr *laddr = &np->rcv_saddr;
const struct in6_addr *faddr = &np->daddr;
- const __u16 lport = inet->num;
- const __be16 fport = inet->dport;
+ const __u16 lport = inet->inet_num;
+ const __be16 fport = inet->inet_dport;
struct net *net = sock_net(sk);
return inet6_ehashfn(net, laddr, lport, faddr, fport);
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index d522dcf3031a..5b698b3b463d 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -125,7 +125,7 @@ struct inet_hashinfo {
*/
struct inet_ehash_bucket *ehash;
spinlock_t *ehash_locks;
- unsigned int ehash_size;
+ unsigned int ehash_mask;
unsigned int ehash_locks_mask;
/* Ok, let's try this, I give up, we do need a local binding
@@ -158,7 +158,7 @@ static inline struct inet_ehash_bucket *inet_ehash_bucket(
struct inet_hashinfo *hashinfo,
unsigned int hash)
{
- return &hashinfo->ehash[hash & (hashinfo->ehash_size - 1)];
+ return &hashinfo->ehash[hash & hashinfo->ehash_mask];
}
static inline spinlock_t *inet_ehash_lockp(
@@ -241,7 +241,7 @@ static inline int inet_lhashfn(struct net *net, const unsigned short num)
static inline int inet_sk_listen_hashfn(const struct sock *sk)
{
- return inet_lhashfn(sock_net(sk), inet_sk(sk)->num);
+ return inet_lhashfn(sock_net(sk), inet_sk(sk)->inet_num);
}
/* Caller must disable local BH processing. */
@@ -301,8 +301,8 @@ typedef __u64 __bitwise __addrpair;
#endif /* __BIG_ENDIAN */
#define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
(((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \
- ((*((__addrpair *)&(inet_sk(__sk)->daddr))) == (__cookie)) && \
- ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \
+ ((*((__addrpair *)&(inet_sk(__sk)->inet_daddr))) == (__cookie)) && \
+ ((*((__portpair *)&(inet_sk(__sk)->inet_dport))) == (__ports)) && \
(!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
#define INET_TW_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
(((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \
@@ -313,9 +313,9 @@ typedef __u64 __bitwise __addrpair;
#define INET_ADDR_COOKIE(__name, __saddr, __daddr)
#define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif) \
(((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \
- (inet_sk(__sk)->daddr == (__saddr)) && \
- (inet_sk(__sk)->rcv_saddr == (__daddr)) && \
- ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \
+ (inet_sk(__sk)->inet_daddr == (__saddr)) && \
+ (inet_sk(__sk)->inet_rcv_saddr == (__daddr)) && \
+ ((*((__portpair *)&(inet_sk(__sk)->inet_dport))) == (__ports)) && \
(!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
#define INET_TW_MATCH(__sk, __net, __hash,__cookie, __saddr, __daddr, __ports, __dif) \
(((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index 47004f35cc7e..bd4c53f75ac0 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -93,14 +93,14 @@ struct rtable;
*
* @sk - ancestor class
* @pinet6 - pointer to IPv6 control block
- * @daddr - Foreign IPv4 addr
- * @rcv_saddr - Bound local IPv4 addr
- * @dport - Destination port
- * @num - Local port
- * @saddr - Sending source
+ * @inet_daddr - Foreign IPv4 addr
+ * @inet_rcv_saddr - Bound local IPv4 addr
+ * @inet_dport - Destination port
+ * @inet_num - Local port
+ * @inet_saddr - Sending source
* @uc_ttl - Unicast TTL
- * @sport - Source port
- * @id - ID counter for DF pkts
+ * @inet_sport - Source port
+ * @inet_id - ID counter for DF pkts
* @tos - TOS
* @mc_ttl - Multicasting TTL
* @is_icsk - is this an inet_connection_sock?
@@ -115,16 +115,16 @@ struct inet_sock {
struct ipv6_pinfo *pinet6;
#endif
/* Socket demultiplex comparisons on incoming packets. */
- __be32 daddr;
- __be32 rcv_saddr;
- __be16 dport;
- __u16 num;
- __be32 saddr;
+ __be32 inet_daddr;
+ __be32 inet_rcv_saddr;
+ __be16 inet_dport;
+ __u16 inet_num;
+ __be32 inet_saddr;
__s16 uc_ttl;
__u16 cmsg_flags;
struct ip_options *opt;
- __be16 sport;
- __u16 id;
+ __be16 inet_sport;
+ __u16 inet_id;
__u8 tos;
__u8 mc_ttl;
__u8 pmtudisc;
@@ -190,10 +190,10 @@ static inline unsigned int inet_ehashfn(struct net *net,
static inline int inet_sk_ehashfn(const struct sock *sk)
{
const struct inet_sock *inet = inet_sk(sk);
- const __be32 laddr = inet->rcv_saddr;
- const __u16 lport = inet->num;
- const __be32 faddr = inet->daddr;
- const __be16 fport = inet->dport;
+ const __be32 laddr = inet->inet_rcv_saddr;
+ const __u16 lport = inet->inet_num;
+ const __be32 faddr = inet->inet_daddr;
+ const __be16 fport = inet->inet_dport;
struct net *net = sock_net(sk);
return inet_ehashfn(net, laddr, lport, faddr, fport);
diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h
index b63b80fac567..773b10fa38e4 100644
--- a/include/net/inet_timewait_sock.h
+++ b/include/net/inet_timewait_sock.h
@@ -130,11 +130,11 @@ struct inet_timewait_sock {
__u16 tw_num;
kmemcheck_bitfield_begin(flags);
/* And these are ours. */
- __u8 tw_ipv6only:1,
- tw_transparent:1;
- /* 14 bits hole, try to pack */
+ unsigned int tw_ipv6only : 1,
+ tw_transparent : 1,
+ tw_pad : 14, /* 14 bits hole */
+ tw_ipv6_offset : 16;
kmemcheck_bitfield_end(flags);
- __u16 tw_ipv6_offset;
unsigned long tw_ttd;
struct inet_bind_bucket *tw_tb;
struct hlist_node tw_death_node;
@@ -194,7 +194,7 @@ static inline struct inet_timewait_sock *inet_twsk(const struct sock *sk)
static inline __be32 inet_rcv_saddr(const struct sock *sk)
{
return likely(sk->sk_state != TCP_TIME_WAIT) ?
- inet_sk(sk)->rcv_saddr : inet_twsk(sk)->tw_rcv_saddr;
+ inet_sk(sk)->inet_rcv_saddr : inet_twsk(sk)->tw_rcv_saddr;
}
extern void inet_twsk_put(struct inet_timewait_sock *tw);
diff --git a/include/net/ip.h b/include/net/ip.h
index 2f47e5482b55..376adf47764e 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -240,8 +240,8 @@ static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst, str
* does not change, they drop every other packet in
* a TCP stream using header compression.
*/
- iph->id = (sk && inet_sk(sk)->daddr) ?
- htons(inet_sk(sk)->id++) : 0;
+ iph->id = (sk && inet_sk(sk)->inet_daddr) ?
+ htons(inet_sk(sk)->inet_id++) : 0;
} else
__ip_select_ident(iph, dst, 0);
}
@@ -249,9 +249,9 @@ static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst, str
static inline void ip_select_ident_more(struct iphdr *iph, struct dst_entry *dst, struct sock *sk, int more)
{
if (iph->frag_off & htons(IP_DF)) {
- if (sk && inet_sk(sk)->daddr) {
- iph->id = htons(inet_sk(sk)->id);
- inet_sk(sk)->id += 1 + more;
+ if (sk && inet_sk(sk)->inet_daddr) {
+ iph->id = htons(inet_sk(sk)->inet_id);
+ inet_sk(sk)->inet_id += 1 + more;
} else
iph->id = 0;
} else
@@ -317,7 +317,7 @@ static inline void ip_ib_mc_map(__be32 naddr, const unsigned char *broadcast, ch
static __inline__ void inet_reset_saddr(struct sock *sk)
{
- inet_sk(sk)->rcv_saddr = inet_sk(sk)->saddr = 0;
+ inet_sk(sk)->inet_rcv_saddr = inet_sk(sk)->inet_saddr = 0;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
if (sk->sk_family == PF_INET6) {
struct ipv6_pinfo *np = inet6_sk(sk);
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index ef91fe924ba4..68fd5ebd0949 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -144,18 +144,21 @@ struct fib_table {
struct hlist_node tb_hlist;
u32 tb_id;
int tb_default;
- int (*tb_lookup)(struct fib_table *tb, const struct flowi *flp, struct fib_result *res);
- int (*tb_insert)(struct fib_table *, struct fib_config *);
- int (*tb_delete)(struct fib_table *, struct fib_config *);
- int (*tb_dump)(struct fib_table *table, struct sk_buff *skb,
- struct netlink_callback *cb);
- int (*tb_flush)(struct fib_table *table);
- void (*tb_select_default)(struct fib_table *table,
- const struct flowi *flp, struct fib_result *res);
-
unsigned char tb_data[0];
};
+extern int fib_table_lookup(struct fib_table *tb, const struct flowi *flp,
+ struct fib_result *res);
+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,
+ struct netlink_callback *cb);
+extern int fib_table_flush(struct fib_table *table);
+extern void fib_table_select_default(struct fib_table *table,
+ const struct flowi *flp,
+ struct fib_result *res);
+
+
#ifndef CONFIG_IP_MULTIPLE_TABLES
#define TABLE_LOCAL_INDEX 0
@@ -182,11 +185,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 (!table->tb_lookup(table, flp, res))
+ if (!fib_table_lookup(table, flp, res))
return 0;
table = fib_get_table(net, RT_TABLE_MAIN);
- if (!table->tb_lookup(table, flp, res))
+ if (!fib_table_lookup(table, flp, res))
return 0;
return -ENETUNREACH;
}
diff --git a/include/net/ipip.h b/include/net/ipip.h
index 87acf8f3a155..b3db2fd6e61c 100644
--- a/include/net/ipip.h
+++ b/include/net/ipip.h
@@ -7,6 +7,15 @@
/* Keep error state on tunnel for 30 sec */
#define IPTUNNEL_ERR_TIMEO (30*HZ)
+/* 6rd prefix/relay information */
+struct ip_tunnel_6rd_parm
+{
+ struct in6_addr prefix;
+ __be32 relay_prefix;
+ u16 prefixlen;
+ u16 relay_prefixlen;
+};
+
struct ip_tunnel
{
struct ip_tunnel *next;
@@ -23,6 +32,10 @@ struct ip_tunnel
struct ip_tunnel_parm parms;
+ /* for SIT */
+#ifdef CONFIG_IPV6_SIT_6RD
+ struct ip_tunnel_6rd_parm ip6rd;
+#endif
struct ip_tunnel_prl_entry *prl; /* potential router list */
unsigned int prl_count; /* # of entries in PRL */
};
@@ -32,6 +45,7 @@ struct ip_tunnel_prl_entry
struct ip_tunnel_prl_entry *next;
__be32 addr;
u16 flags;
+ struct rcu_head rcu_head;
};
#define IPTUNNEL_XMIT() do { \
@@ -42,9 +56,9 @@ struct ip_tunnel_prl_entry
ip_select_ident(iph, &rt->u.dst, NULL); \
\
err = ip_local_out(skb); \
- if (net_xmit_eval(err) == 0) { \
- stats->tx_bytes += pkt_len; \
- stats->tx_packets++; \
+ if (likely(net_xmit_eval(err) == 0)) { \
+ txq->tx_bytes += pkt_len; \
+ txq->tx_packets++; \
} else { \
stats->tx_errors++; \
stats->tx_aborted_errors++; \
diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h
index e9054a283fde..d5d337170a56 100644
--- a/include/net/iw_handler.h
+++ b/include/net/iw_handler.h
@@ -323,18 +323,19 @@ typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info,
*/
struct iw_handler_def
{
- /* Number of handlers defined (more precisely, index of the
- * last defined handler + 1) */
- __u16 num_standard;
- __u16 num_private;
- /* Number of private arg description */
- __u16 num_private_args;
/* Array of handlers for standard ioctls
* We will call dev->wireless_handlers->standard[ioctl - SIOCSIWCOMMIT]
*/
const iw_handler * standard;
+ /* Number of handlers defined (more precisely, index of the
+ * last defined handler + 1) */
+ __u16 num_standard;
+#ifdef CONFIG_WEXT_PRIV
+ __u16 num_private;
+ /* Number of private arg description */
+ __u16 num_private_args;
/* Array of handlers for private ioctls
* Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV]
*/
@@ -344,6 +345,7 @@ struct iw_handler_def
* can put it in any order you want and should not leave holes...
* We will automatically export that to user space... */
const struct iw_priv_args * private_args;
+#endif
/* New location of get_wireless_stats, to de-bloat struct net_device.
* The old pointer in struct net_device will be gradually phased
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index c75b960c8ac8..c42c4a820b89 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1665,11 +1665,11 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw);
* header if %RX_FLAG_RADIOTAP is set in the @status flags.
*
* This function may not be called in IRQ context. Calls to this function
- * for a single hardware must be synchronized against each other. Calls
- * to this function and ieee80211_rx_irqsafe() may not be mixed for a
- * single hardware.
+ * for a single hardware must be synchronized against each other. Calls to
+ * this function, ieee80211_rx_ni() and ieee80211_rx_irqsafe() may not be
+ * mixed for a single hardware.
*
- * Note that right now, this function must be called with softirqs disabled.
+ * In process context use instead ieee80211_rx_ni().
*
* @hw: the hardware this frame came in on
* @skb: the buffer to receive, owned by mac80211 after this call
@@ -1682,8 +1682,8 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb);
* Like ieee80211_rx() but can be called in IRQ context
* (internally defers to a tasklet.)
*
- * Calls to this function and ieee80211_rx() may not be mixed for a
- * single hardware.
+ * Calls to this function, ieee80211_rx() or ieee80211_rx_ni() may not
+ * be mixed for a single hardware.
*
* @hw: the hardware this frame came in on
* @skb: the buffer to receive, owned by mac80211 after this call
@@ -1691,6 +1691,26 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb);
void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb);
/**
+ * ieee80211_rx_ni - receive frame (in process context)
+ *
+ * Like ieee80211_rx() but can be called in process context
+ * (internally disables bottom halves).
+ *
+ * Calls to this function, ieee80211_rx() and ieee80211_rx_irqsafe() may
+ * not be mixed for a single hardware.
+ *
+ * @hw: the hardware this frame came in on
+ * @skb: the buffer to receive, owned by mac80211 after this call
+ */
+static inline void ieee80211_rx_ni(struct ieee80211_hw *hw,
+ struct sk_buff *skb)
+{
+ local_bh_disable();
+ ieee80211_rx(hw, skb);
+ local_bh_enable();
+}
+
+/**
* ieee80211_tx_status - transmit status callback
*
* Call this function for all transmitted frames after they have been
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index 3817fda82a80..f28403ff7648 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -90,12 +90,7 @@ struct neigh_statistics
unsigned long unres_discards; /* number of unresolved drops */
};
-#define NEIGH_CACHE_STAT_INC(tbl, field) \
- do { \
- preempt_disable(); \
- (per_cpu_ptr((tbl)->stats, smp_processor_id())->field)++; \
- preempt_enable(); \
- } while (0)
+#define NEIGH_CACHE_STAT_INC(tbl, field) this_cpu_inc((tbl)->stats->field)
struct neighbour
{
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index a1202841aadd..0addd45038ac 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -28,6 +28,10 @@ struct ctl_table_header;
struct net_generic;
struct sock;
+
+#define NETDEV_HASHBITS 8
+#define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS)
+
struct net {
atomic_t count; /* To decided when the network
* namespace should be freed.
@@ -80,7 +84,7 @@ struct net {
#ifdef CONFIG_XFRM
struct netns_xfrm xfrm;
#endif
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_WEXT_CORE
struct sk_buff_head wext_nlevents;
#endif
struct net_generic *gen;
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index cbdd6284996d..dde549779e42 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -295,11 +295,11 @@ extern unsigned int nf_conntrack_htable_size;
extern unsigned int nf_conntrack_max;
#define NF_CT_STAT_INC(net, count) \
- (per_cpu_ptr((net)->ct.stat, raw_smp_processor_id())->count++)
+ __this_cpu_inc((net)->ct.stat->count)
#define NF_CT_STAT_INC_ATOMIC(net, count) \
do { \
local_bh_disable(); \
- per_cpu_ptr((net)->ct.stat, raw_smp_processor_id())->count++; \
+ __this_cpu_inc((net)->ct.stat->count); \
local_bh_enable(); \
} while (0)
diff --git a/include/net/phonet/phonet.h b/include/net/phonet/phonet.h
index d43f71b5ec00..fdb05fa0346f 100644
--- a/include/net/phonet/phonet.h
+++ b/include/net/phonet/phonet.h
@@ -47,6 +47,7 @@ static inline struct pn_sock *pn_sk(struct sock *sk)
extern const struct proto_ops phonet_dgram_ops;
struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *sa);
+void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb);
void phonet_get_local_port_range(int *min, int *max);
void pn_sock_hash(struct sock *sk);
void pn_sock_unhash(struct sock *sk);
diff --git a/include/net/phonet/pn_dev.h b/include/net/phonet/pn_dev.h
index 44c923c9e21d..afa7defceb14 100644
--- a/include/net/phonet/pn_dev.h
+++ b/include/net/phonet/pn_dev.h
@@ -47,6 +47,12 @@ u8 phonet_address_get(struct net_device *dev, u8 addr);
int phonet_address_lookup(struct net *net, u8 addr);
void phonet_address_notify(int event, struct net_device *dev, u8 addr);
+int phonet_route_add(struct net_device *dev, u8 daddr);
+int phonet_route_del(struct net_device *dev, u8 daddr);
+void rtm_phonet_notify(int event, struct net_device *dev, u8 dst);
+struct net_device *phonet_route_get(struct net *net, u8 daddr);
+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;
diff --git a/include/net/snmp.h b/include/net/snmp.h
index 8c842e06bec8..f0d756f2ac99 100644
--- a/include/net/snmp.h
+++ b/include/net/snmp.h
@@ -136,45 +136,31 @@ struct linux_xfrm_mib {
#define SNMP_STAT_BHPTR(name) (name[0])
#define SNMP_STAT_USRPTR(name) (name[1])
-#define SNMP_INC_STATS_BH(mib, field) \
- (per_cpu_ptr(mib[0], raw_smp_processor_id())->mibs[field]++)
-#define SNMP_INC_STATS_USER(mib, field) \
- do { \
- per_cpu_ptr(mib[1], get_cpu())->mibs[field]++; \
- put_cpu(); \
- } while (0)
-#define SNMP_INC_STATS(mib, field) \
- do { \
- per_cpu_ptr(mib[!in_softirq()], get_cpu())->mibs[field]++; \
- put_cpu(); \
- } while (0)
-#define SNMP_DEC_STATS(mib, field) \
- do { \
- per_cpu_ptr(mib[!in_softirq()], get_cpu())->mibs[field]--; \
- put_cpu(); \
- } while (0)
-#define SNMP_ADD_STATS(mib, field, addend) \
- do { \
- per_cpu_ptr(mib[!in_softirq()], get_cpu())->mibs[field] += addend; \
- put_cpu(); \
- } while (0)
-#define SNMP_ADD_STATS_BH(mib, field, addend) \
- (per_cpu_ptr(mib[0], raw_smp_processor_id())->mibs[field] += addend)
-#define SNMP_ADD_STATS_USER(mib, field, addend) \
- do { \
- per_cpu_ptr(mib[1], get_cpu())->mibs[field] += addend; \
- put_cpu(); \
- } while (0)
+#define SNMP_INC_STATS_BH(mib, field) \
+ __this_cpu_inc(mib[0]->mibs[field])
+#define SNMP_INC_STATS_USER(mib, field) \
+ this_cpu_inc(mib[1]->mibs[field])
+#define SNMP_INC_STATS(mib, field) \
+ this_cpu_inc(mib[!in_softirq()]->mibs[field])
+#define SNMP_DEC_STATS(mib, field) \
+ this_cpu_dec(mib[!in_softirq()]->mibs[field])
+#define SNMP_ADD_STATS_BH(mib, field, addend) \
+ __this_cpu_add(mib[0]->mibs[field], addend)
+#define SNMP_ADD_STATS_USER(mib, field, addend) \
+ this_cpu_add(mib[1]->mibs[field], addend)
#define SNMP_UPD_PO_STATS(mib, basefield, addend) \
do { \
- __typeof__(mib[0]) ptr = per_cpu_ptr(mib[!in_softirq()], get_cpu());\
+ __typeof__(mib[0]) ptr; \
+ preempt_disable(); \
+ ptr = this_cpu_ptr((mib)[!in_softirq()]); \
ptr->mibs[basefield##PKTS]++; \
ptr->mibs[basefield##OCTETS] += addend;\
- put_cpu(); \
+ preempt_enable(); \
} while (0)
#define SNMP_UPD_PO_STATS_BH(mib, basefield, addend) \
do { \
- __typeof__(mib[0]) ptr = per_cpu_ptr(mib[!in_softirq()], raw_smp_processor_id());\
+ __typeof__(mib[0]) ptr = \
+ __this_cpu_ptr((mib)[!in_softirq()]); \
ptr->mibs[basefield##PKTS]++; \
ptr->mibs[basefield##OCTETS] += addend;\
} while (0)
diff --git a/include/net/sock.h b/include/net/sock.h
index 9f96394f694e..55de3bd719a5 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -107,6 +107,7 @@ struct net;
* @skc_node: main hash linkage for various protocol lookup tables
* @skc_nulls_node: main hash linkage for UDP/UDP-Lite protocol
* @skc_refcnt: reference count
+ * @skc_tx_queue_mapping: tx queue number for this connection
* @skc_hash: hash value used with various protocol lookup tables
* @skc_family: network address family
* @skc_state: Connection state
@@ -128,6 +129,7 @@ struct sock_common {
struct hlist_nulls_node skc_nulls_node;
};
atomic_t skc_refcnt;
+ int skc_tx_queue_mapping;
unsigned int skc_hash;
unsigned short skc_family;
@@ -215,6 +217,7 @@ struct sock {
#define sk_node __sk_common.skc_node
#define sk_nulls_node __sk_common.skc_nulls_node
#define sk_refcnt __sk_common.skc_refcnt
+#define sk_tx_queue_mapping __sk_common.skc_tx_queue_mapping
#define sk_copy_start __sk_common.skc_hash
#define sk_hash __sk_common.skc_hash
@@ -504,6 +507,8 @@ enum sock_flags {
SOCK_TIMESTAMPING_SOFTWARE, /* %SOF_TIMESTAMPING_SOFTWARE */
SOCK_TIMESTAMPING_RAW_HARDWARE, /* %SOF_TIMESTAMPING_RAW_HARDWARE */
SOCK_TIMESTAMPING_SYS_HARDWARE, /* %SOF_TIMESTAMPING_SYS_HARDWARE */
+ SOCK_FASYNC, /* fasync() active */
+ SOCK_RXQ_OVFL,
};
static inline void sock_copy_flags(struct sock *nsk, struct sock *osk)
@@ -1092,8 +1097,29 @@ static inline void sock_put(struct sock *sk)
extern int sk_receive_skb(struct sock *sk, struct sk_buff *skb,
const int nested);
+static inline void sk_tx_queue_set(struct sock *sk, int tx_queue)
+{
+ sk->sk_tx_queue_mapping = tx_queue;
+}
+
+static inline void sk_tx_queue_clear(struct sock *sk)
+{
+ sk->sk_tx_queue_mapping = -1;
+}
+
+static inline int sk_tx_queue_get(const struct sock *sk)
+{
+ return sk->sk_tx_queue_mapping;
+}
+
+static inline bool sk_tx_queue_recorded(const struct sock *sk)
+{
+ return (sk && sk->sk_tx_queue_mapping >= 0);
+}
+
static inline void sk_set_socket(struct sock *sk, struct socket *sock)
{
+ sk_tx_queue_clear(sk);
sk->sk_socket = sock;
}
@@ -1150,6 +1176,7 @@ __sk_dst_set(struct sock *sk, struct dst_entry *dst)
{
struct dst_entry *old_dst;
+ sk_tx_queue_clear(sk);
old_dst = sk->sk_dst_cache;
sk->sk_dst_cache = dst;
dst_release(old_dst);
@@ -1168,6 +1195,7 @@ __sk_dst_reset(struct sock *sk)
{
struct dst_entry *old_dst;
+ sk_tx_queue_clear(sk);
old_dst = sk->sk_dst_cache;
sk->sk_dst_cache = NULL;
dst_release(old_dst);
@@ -1396,7 +1424,7 @@ static inline unsigned long sock_wspace(struct sock *sk)
static inline void sk_wake_async(struct sock *sk, int how, int band)
{
- if (sk->sk_socket && sk->sk_socket->fasync_list)
+ if (sock_flag(sk, SOCK_FASYNC))
sock_wake_async(sk->sk_socket, how, band);
}
@@ -1492,6 +1520,8 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
sk->sk_stamp = kt;
}
+extern void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, struct sk_buff *skb);
+
/**
* sock_tx_timestamp - checks whether the outgoing packet is to be time stamped
* @msg: outgoing packet
diff --git a/include/net/tc_act/tc_skbedit.h b/include/net/tc_act/tc_skbedit.h
index 6abb3ed3ebf7..e103fe02f375 100644
--- a/include/net/tc_act/tc_skbedit.h
+++ b/include/net/tc_act/tc_skbedit.h
@@ -26,7 +26,9 @@ struct tcf_skbedit {
struct tcf_common common;
u32 flags;
u32 priority;
+ u32 mark;
u16 queue_mapping;
+ /* XXX: 16-bit pad here? */
};
#define to_skbedit(pc) \
container_of(pc, struct tcf_skbedit, common)
diff --git a/include/net/udp.h b/include/net/udp.h
index f98abd2ce709..22aa2e7eb1d7 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -54,12 +54,19 @@ struct udp_hslot {
struct hlist_nulls_head head;
spinlock_t lock;
} __attribute__((aligned(2 * sizeof(long))));
+
struct udp_table {
- struct udp_hslot hash[UDP_HTABLE_SIZE];
+ struct udp_hslot *hash;
+ unsigned int mask;
+ unsigned int log;
};
extern struct udp_table udp_table;
-extern void udp_table_init(struct udp_table *);
-
+extern void udp_table_init(struct udp_table *, const char *);
+static inline struct udp_hslot *udp_hashslot(struct udp_table *table,
+ struct net *net, unsigned num)
+{
+ return &table->hash[udp_hashfn(net, num, table->mask)];
+}
/* Note: this must match 'valbool' in sock_setsockopt */
#define UDP_CSUM_NOXMIT 1
diff --git a/include/net/wext.h b/include/net/wext.h
index 3f2b94de2cfa..4f6e7423174c 100644
--- a/include/net/wext.h
+++ b/include/net/wext.h
@@ -1,29 +1,19 @@
#ifndef __NET_WEXT_H
#define __NET_WEXT_H
-/*
- * wireless extensions interface to the core code
- */
+#include <net/iw_handler.h>
struct net;
-#ifdef CONFIG_WIRELESS_EXT
-extern int wext_proc_init(struct net *net);
-extern void wext_proc_exit(struct net *net);
+#ifdef CONFIG_WEXT_CORE
extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
void __user *arg);
extern int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
unsigned long arg);
+
extern struct iw_statistics *get_wireless_stats(struct net_device *dev);
+extern int call_commit_handler(struct net_device *dev);
#else
-static inline int wext_proc_init(struct net *net)
-{
- return 0;
-}
-static inline void wext_proc_exit(struct net *net)
-{
- return;
-}
static inline int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
void __user *arg)
{
@@ -36,4 +26,35 @@ static inline int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
}
#endif
+#ifdef CONFIG_WEXT_PROC
+extern int wext_proc_init(struct net *net);
+extern void wext_proc_exit(struct net *net);
+#else
+static inline int wext_proc_init(struct net *net)
+{
+ return 0;
+}
+static inline void wext_proc_exit(struct net *net)
+{
+ return;
+}
+#endif
+
+#ifdef CONFIG_WEXT_PRIV
+int ioctl_private_call(struct net_device *dev, struct iwreq *iwr,
+ unsigned int cmd, struct iw_request_info *info,
+ iw_handler handler);
+int compat_private_call(struct net_device *dev, struct iwreq *iwr,
+ unsigned int cmd, struct iw_request_info *info,
+ iw_handler handler);
+int iw_handler_get_private(struct net_device * dev,
+ struct iw_request_info * info,
+ union iwreq_data * wrqu,
+ char * extra);
+#else
+#define ioctl_private_call NULL
+#define compat_private_call NULL
+#endif
+
+
#endif /* __NET_WEXT_H */
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 223e90a44824..d9c6dbb92719 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1500,9 +1500,6 @@ struct scatterlist;
typedef int (icv_update_fn_t)(struct hash_desc *, struct scatterlist *,
unsigned int);
-extern int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *tfm,
- int offset, int len, icv_update_fn_t icv_update);
-
static inline int xfrm_addr_cmp(xfrm_address_t *a, xfrm_address_t *b,
int family)
{
diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h
index a2be80b9a095..6c37d4ed7832 100644
--- a/include/pcmcia/ds.h
+++ b/include/pcmcia/ds.h
@@ -34,6 +34,7 @@
struct pcmcia_socket;
struct pcmcia_device;
struct config_t;
+struct net_device;
/* dynamic device IDs for PCMCIA device drivers. See
* Documentation/pcmcia/driver.txt for details.
@@ -176,25 +177,38 @@ const char *pcmcia_error_ret(int ret);
pcmcia_error_ret(ret)); \
}
-/* CIS access.
- * Use the pcmcia_* versions in PCMCIA drivers
+
+/*
+ * CIS access.
+ *
+ * Please use the following functions to access CIS tuples:
+ * - pcmcia_get_tuple()
+ * - pcmcia_loop_tuple()
+ * - pcmcia_get_mac_from_cis()
+ *
+ * To parse a tuple_t, pcmcia_parse_tuple() exists. Its interface
+ * might change in future.
*/
-int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse);
-int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function,
- tuple_t *tuple);
-#define pcmcia_get_first_tuple(p_dev, tuple) \
- pccard_get_first_tuple(p_dev->socket, p_dev->func, tuple)
+/* get the very first CIS entry of type @code. Note that buf is pointer
+ * to u8 *buf; and that you need to kfree(buf) afterwards. */
+size_t pcmcia_get_tuple(struct pcmcia_device *p_dev, cisdata_t code,
+ u8 **buf);
+
+/* loop over CIS entries */
+int pcmcia_loop_tuple(struct pcmcia_device *p_dev, cisdata_t code,
+ int (*loop_tuple) (struct pcmcia_device *p_dev,
+ tuple_t *tuple,
+ void *priv_data),
+ void *priv_data);
-int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function,
- tuple_t *tuple);
-#define pcmcia_get_next_tuple(p_dev, tuple) \
- pccard_get_next_tuple(p_dev->socket, p_dev->func, tuple)
+/* get the MAC address from CISTPL_FUNCE */
+int pcmcia_get_mac_from_cis(struct pcmcia_device *p_dev,
+ struct net_device *dev);
-int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple);
-#define pcmcia_get_tuple_data(p_dev, tuple) \
- pccard_get_tuple_data(p_dev->socket, tuple)
+/* parse a tuple_t */
+int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse);
/* loop CIS entries for valid configuration */
int pcmcia_loop_config(struct pcmcia_device *p_dev,
diff --git a/include/scsi/osd_initiator.h b/include/scsi/osd_initiator.h
index 02bd9f716357..3ec346e15dda 100644
--- a/include/scsi/osd_initiator.h
+++ b/include/scsi/osd_initiator.h
@@ -48,7 +48,6 @@ enum osd_std_version {
*/
struct osd_dev {
struct scsi_device *scsi_device;
- struct file *file;
unsigned def_timeout;
#ifdef OSD_VER1_SUPPORT
@@ -56,10 +55,24 @@ struct osd_dev {
#endif
};
-/* Retrieve/return osd_dev(s) for use by Kernel clients */
-struct osd_dev *osduld_path_lookup(const char *dev_name); /*Use IS_ERR/ERR_PTR*/
+/* Unique Identification of an OSD device */
+struct osd_dev_info {
+ unsigned systemid_len;
+ u8 systemid[OSD_SYSTEMID_LEN];
+ unsigned osdname_len;
+ u8 *osdname;
+};
+
+/* Retrieve/return osd_dev(s) for use by Kernel clients
+ * Use IS_ERR/ERR_PTR on returned "osd_dev *".
+ */
+struct osd_dev *osduld_path_lookup(const char *dev_name);
+struct osd_dev *osduld_info_lookup(const struct osd_dev_info *odi);
void osduld_put_device(struct osd_dev *od);
+const struct osd_dev_info *osduld_device_info(struct osd_dev *od);
+bool osduld_device_same(struct osd_dev *od, const struct osd_dev_info *odi);
+
/* Add/remove test ioctls from external modules */
typedef int (do_test_fn)(struct osd_dev *od, unsigned cmd, unsigned long arg);
int osduld_register_test(unsigned ioctl, do_test_fn *do_test);
@@ -69,8 +82,24 @@ void osduld_unregister_test(unsigned ioctl);
void osd_dev_init(struct osd_dev *od, struct scsi_device *scsi_device);
void osd_dev_fini(struct osd_dev *od);
-/* some hi level device operations */
-int osd_auto_detect_ver(struct osd_dev *od, void *caps); /* GFP_KERNEL */
+/**
+ * osd_auto_detect_ver - Detect the OSD version, return Unique Identification
+ *
+ * @od: OSD target lun handle
+ * @caps: Capabilities authorizing OSD root read attributes access
+ * @odi: Retrieved information uniquely identifying the osd target lun
+ * Note: odi->osdname must be kfreed by caller.
+ *
+ * Auto detects the OSD version of the OSD target and sets the @od
+ * accordingly. Meanwhile also returns the "system id" and "osd name" root
+ * attributes which uniquely identify the OSD target. This member is usually
+ * called by the ULD. ULD users should call osduld_device_info().
+ * This rutine allocates osd requests and memory at GFP_KERNEL level and might
+ * sleep.
+ */
+int osd_auto_detect_ver(struct osd_dev *od,
+ void *caps, struct osd_dev_info *odi);
+
static inline struct request_queue *osd_request_queue(struct osd_dev *od)
{
return od->scsi_device->request_queue;
@@ -84,6 +113,15 @@ static inline void osd_dev_set_ver(struct osd_dev *od, enum osd_std_version v)
#endif
}
+static inline bool osd_dev_is_ver1(struct osd_dev *od)
+{
+#ifdef OSD_VER1_SUPPORT
+ return od->version == OSD_VER1;
+#else
+ return false;
+#endif
+}
+
struct osd_request;
typedef void (osd_req_done_fn)(struct osd_request *or, void *private);
@@ -120,14 +158,9 @@ struct osd_request {
int async_error;
};
-/* OSD Version control */
static inline bool osd_req_is_ver1(struct osd_request *or)
{
-#ifdef OSD_VER1_SUPPORT
- return or->osd_dev->version == OSD_VER1;
-#else
- return false;
-#endif
+ return osd_dev_is_ver1(or->osd_dev);
}
/*
diff --git a/include/scsi/osd_sense.h b/include/scsi/osd_sense.h
index ff9b33c773c7..91db543a5502 100644
--- a/include/scsi/osd_sense.h
+++ b/include/scsi/osd_sense.h
@@ -255,6 +255,9 @@ enum osdv2_cdb_field_offset {
OSD_CFO_STARTING_BYTE = OSD_CDB_OFFSET(v2.start_address),
OSD_CFO_PARTITION_ID = OSD_CDB_OFFSET(partition),
OSD_CFO_OBJECT_ID = OSD_CDB_OFFSET(object),
+ OSD_CFO_PERMISSIONS = sizeof(struct osd_cdb_head) +
+ offsetof(struct osd_capability_head,
+ permissions_bit_mask),
};
#endif /* ndef __OSD_SENSE_H__ */
diff --git a/include/sound/Kbuild b/include/sound/Kbuild
index fd054a344324..e9dd9369ecb9 100644
--- a/include/sound/Kbuild
+++ b/include/sound/Kbuild
@@ -2,7 +2,6 @@ header-y += asound_fm.h
header-y += hdsp.h
header-y += hdspm.h
header-y += sfnt_info.h
-header-y += sscape_ioctl.h
unifdef-y += asequencer.h
unifdef-y += asound.h
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index 3dae3f799b9b..49400459b477 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -593,7 +593,7 @@ enum {
struct ac97_quirk {
unsigned short subvendor; /* PCI subsystem vendor id */
- unsigned short subdevice; /* PCI sybsystem device id */
+ unsigned short subdevice; /* PCI subsystem device id */
unsigned short mask; /* device id bit mask, 0 = accept all */
unsigned int codec_id; /* codec id (if any), 0 = accept all */
const char *name; /* name shown as info */
diff --git a/include/sound/ak4113.h b/include/sound/ak4113.h
new file mode 100644
index 000000000000..8988edae1609
--- /dev/null
+++ b/include/sound/ak4113.h
@@ -0,0 +1,321 @@
+#ifndef __SOUND_AK4113_H
+#define __SOUND_AK4113_H
+
+/*
+ * Routines for Asahi Kasei AK4113
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>,
+ * Copyright (c) by Pavel Hofman <pavel.hofman@ivitera.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
+ *
+ */
+
+/* AK4113 registers */
+/* power down */
+#define AK4113_REG_PWRDN 0x00
+/* format control */
+#define AK4113_REG_FORMAT 0x01
+/* input/output control */
+#define AK4113_REG_IO0 0x02
+/* input/output control */
+#define AK4113_REG_IO1 0x03
+/* interrupt0 mask */
+#define AK4113_REG_INT0_MASK 0x04
+/* interrupt1 mask */
+#define AK4113_REG_INT1_MASK 0x05
+/* DAT mask & DTS select */
+#define AK4113_REG_DATDTS 0x06
+/* receiver status 0 */
+#define AK4113_REG_RCS0 0x07
+/* receiver status 1 */
+#define AK4113_REG_RCS1 0x08
+/* receiver status 2 */
+#define AK4113_REG_RCS2 0x09
+/* RX channel status byte 0 */
+#define AK4113_REG_RXCSB0 0x0a
+/* RX channel status byte 1 */
+#define AK4113_REG_RXCSB1 0x0b
+/* RX channel status byte 2 */
+#define AK4113_REG_RXCSB2 0x0c
+/* RX channel status byte 3 */
+#define AK4113_REG_RXCSB3 0x0d
+/* RX channel status byte 4 */
+#define AK4113_REG_RXCSB4 0x0e
+/* burst preamble Pc byte 0 */
+#define AK4113_REG_Pc0 0x0f
+/* burst preamble Pc byte 1 */
+#define AK4113_REG_Pc1 0x10
+/* burst preamble Pd byte 0 */
+#define AK4113_REG_Pd0 0x11
+/* burst preamble Pd byte 1 */
+#define AK4113_REG_Pd1 0x12
+/* Q-subcode address + control */
+#define AK4113_REG_QSUB_ADDR 0x13
+/* Q-subcode track */
+#define AK4113_REG_QSUB_TRACK 0x14
+/* Q-subcode index */
+#define AK4113_REG_QSUB_INDEX 0x15
+/* Q-subcode minute */
+#define AK4113_REG_QSUB_MINUTE 0x16
+/* Q-subcode second */
+#define AK4113_REG_QSUB_SECOND 0x17
+/* Q-subcode frame */
+#define AK4113_REG_QSUB_FRAME 0x18
+/* Q-subcode zero */
+#define AK4113_REG_QSUB_ZERO 0x19
+/* Q-subcode absolute minute */
+#define AK4113_REG_QSUB_ABSMIN 0x1a
+/* Q-subcode absolute second */
+#define AK4113_REG_QSUB_ABSSEC 0x1b
+/* Q-subcode absolute frame */
+#define AK4113_REG_QSUB_ABSFRM 0x1c
+
+/* sizes */
+#define AK4113_REG_RXCSB_SIZE ((AK4113_REG_RXCSB4-AK4113_REG_RXCSB0)+1)
+#define AK4113_REG_QSUB_SIZE ((AK4113_REG_QSUB_ABSFRM-AK4113_REG_QSUB_ADDR)\
+ +1)
+
+#define AK4113_WRITABLE_REGS (AK4113_REG_DATDTS + 1)
+
+/* AK4113_REG_PWRDN bits */
+/* Channel Status Select */
+#define AK4113_CS12 (1<<7)
+/* Block Start & C/U Output Mode */
+#define AK4113_BCU (1<<6)
+/* Master Clock Operation Select */
+#define AK4113_CM1 (1<<5)
+/* Master Clock Operation Select */
+#define AK4113_CM0 (1<<4)
+/* Master Clock Frequency Select */
+#define AK4113_OCKS1 (1<<3)
+/* Master Clock Frequency Select */
+#define AK4113_OCKS0 (1<<2)
+/* 0 = power down, 1 = normal operation */
+#define AK4113_PWN (1<<1)
+/* 0 = reset & initialize (except thisregister), 1 = normal operation */
+#define AK4113_RST (1<<0)
+
+/* AK4113_REQ_FORMAT bits */
+/* V/TX Output select: 0 = Validity Flag Output, 1 = TX */
+#define AK4113_VTX (1<<7)
+/* Audio Data Control */
+#define AK4113_DIF2 (1<<6)
+/* Audio Data Control */
+#define AK4113_DIF1 (1<<5)
+/* Audio Data Control */
+#define AK4113_DIF0 (1<<4)
+/* Deemphasis Autodetect Enable (1 = enable) */
+#define AK4113_DEAU (1<<3)
+/* 32kHz-48kHz Deemphasis Control */
+#define AK4113_DEM1 (1<<2)
+/* 32kHz-48kHz Deemphasis Control */
+#define AK4113_DEM0 (1<<1)
+#define AK4113_DEM_OFF (AK4113_DEM0)
+#define AK4113_DEM_44KHZ (0)
+#define AK4113_DEM_48KHZ (AK4113_DEM1)
+#define AK4113_DEM_32KHZ (AK4113_DEM0|AK4113_DEM1)
+/* STDO: 16-bit, right justified */
+#define AK4113_DIF_16R (0)
+/* STDO: 18-bit, right justified */
+#define AK4113_DIF_18R (AK4113_DIF0)
+/* STDO: 20-bit, right justified */
+#define AK4113_DIF_20R (AK4113_DIF1)
+/* STDO: 24-bit, right justified */
+#define AK4113_DIF_24R (AK4113_DIF1|AK4113_DIF0)
+/* STDO: 24-bit, left justified */
+#define AK4113_DIF_24L (AK4113_DIF2)
+/* STDO: I2S */
+#define AK4113_DIF_24I2S (AK4113_DIF2|AK4113_DIF0)
+/* STDO: 24-bit, left justified; LRCLK, BICK = Input */
+#define AK4113_DIF_I24L (AK4113_DIF2|AK4113_DIF1)
+/* STDO: I2S; LRCLK, BICK = Input */
+#define AK4113_DIF_I24I2S (AK4113_DIF2|AK4113_DIF1|AK4113_DIF0)
+
+/* AK4113_REG_IO0 */
+/* XTL1=0,XTL0=0 -> 11.2896Mhz; XTL1=0,XTL0=1 -> 12.288Mhz */
+#define AK4113_XTL1 (1<<6)
+/* XTL1=1,XTL0=0 -> 24.576Mhz; XTL1=1,XTL0=1 -> use channel status */
+#define AK4113_XTL0 (1<<5)
+/* Block Start Signal Output: 0 = U-bit, 1 = C-bit (req. BCU = 1) */
+#define AK4113_UCE (1<<4)
+/* TX Output Enable (1 = enable) */
+#define AK4113_TXE (1<<3)
+/* Output Through Data Selector for TX pin */
+#define AK4113_OPS2 (1<<2)
+/* Output Through Data Selector for TX pin */
+#define AK4113_OPS1 (1<<1)
+/* Output Through Data Selector for TX pin */
+#define AK4113_OPS0 (1<<0)
+/* 11.2896 MHz ref. Xtal freq. */
+#define AK4113_XTL_11_2896M (0)
+/* 12.288 MHz ref. Xtal freq. */
+#define AK4113_XTL_12_288M (AK4113_XTL0)
+/* 24.576 MHz ref. Xtal freq. */
+#define AK4113_XTL_24_576M (AK4113_XTL1)
+
+/* AK4113_REG_IO1 */
+/* Interrupt 0 pin Hold */
+#define AK4113_EFH1 (1<<7)
+/* Interrupt 0 pin Hold */
+#define AK4113_EFH0 (1<<6)
+#define AK4113_EFH_512LRCLK (0)
+#define AK4113_EFH_1024LRCLK (AK4113_EFH0)
+#define AK4113_EFH_2048LRCLK (AK4113_EFH1)
+#define AK4113_EFH_4096LRCLK (AK4113_EFH1|AK4113_EFH0)
+/* PLL Lock Time: 0 = 384/fs, 1 = 1/fs */
+#define AK4113_FAST (1<<5)
+/* MCKO2 Output Select: 0 = CMx/OCKSx, 1 = Xtal */
+#define AK4113_XMCK (1<<4)
+/* MCKO2 Output Freq. Select: 0 = x1, 1 = x0.5 (req. XMCK = 1) */
+#define AK4113_DIV (1<<3)
+/* Input Recovery Data Select */
+#define AK4113_IPS2 (1<<2)
+/* Input Recovery Data Select */
+#define AK4113_IPS1 (1<<1)
+/* Input Recovery Data Select */
+#define AK4113_IPS0 (1<<0)
+#define AK4113_IPS(x) ((x)&7)
+
+/* AK4113_REG_INT0_MASK && AK4113_REG_INT1_MASK*/
+/* mask enable for QINT bit */
+#define AK4113_MQI (1<<7)
+/* mask enable for AUTO bit */
+#define AK4113_MAUT (1<<6)
+/* mask enable for CINT bit */
+#define AK4113_MCIT (1<<5)
+/* mask enable for UNLOCK bit */
+#define AK4113_MULK (1<<4)
+/* mask enable for V bit */
+#define AK4113_V (1<<3)
+/* mask enable for STC bit */
+#define AK4113_STC (1<<2)
+/* mask enable for AUDN bit */
+#define AK4113_MAN (1<<1)
+/* mask enable for PAR bit */
+#define AK4113_MPR (1<<0)
+
+/* AK4113_REG_DATDTS */
+/* DAT Start ID Counter */
+#define AK4113_DCNT (1<<4)
+/* DTS-CD 16-bit Sync Word Detect */
+#define AK4113_DTS16 (1<<3)
+/* DTS-CD 14-bit Sync Word Detect */
+#define AK4113_DTS14 (1<<2)
+/* mask enable for DAT bit (if 1, no INT1 effect */
+#define AK4113_MDAT1 (1<<1)
+/* mask enable for DAT bit (if 1, no INT0 effect */
+#define AK4113_MDAT0 (1<<0)
+
+/* AK4113_REG_RCS0 */
+/* Q-subcode buffer interrupt, 0 = no change, 1 = changed */
+#define AK4113_QINT (1<<7)
+/* Non-PCM or DTS stream auto detection, 0 = no detect, 1 = detect */
+#define AK4113_AUTO (1<<6)
+/* channel status buffer interrupt, 0 = no change, 1 = change */
+#define AK4113_CINT (1<<5)
+/* PLL lock status, 0 = lock, 1 = unlock */
+#define AK4113_UNLCK (1<<4)
+/* Validity bit, 0 = valid, 1 = invalid */
+#define AK4113_V (1<<3)
+/* sampling frequency or Pre-emphasis change, 0 = no detect, 1 = detect */
+#define AK4113_STC (1<<2)
+/* audio bit output, 0 = audio, 1 = non-audio */
+#define AK4113_AUDION (1<<1)
+/* parity error or biphase error status, 0 = no error, 1 = error */
+#define AK4113_PAR (1<<0)
+
+/* AK4113_REG_RCS1 */
+/* sampling frequency detection */
+#define AK4113_FS3 (1<<7)
+#define AK4113_FS2 (1<<6)
+#define AK4113_FS1 (1<<5)
+#define AK4113_FS0 (1<<4)
+/* Pre-emphasis detect, 0 = OFF, 1 = ON */
+#define AK4113_PEM (1<<3)
+/* DAT Start ID Detect, 0 = no detect, 1 = detect */
+#define AK4113_DAT (1<<2)
+/* DTS-CD bit audio stream detect, 0 = no detect, 1 = detect */
+#define AK4113_DTSCD (1<<1)
+/* Non-PCM bit stream detection, 0 = no detect, 1 = detect */
+#define AK4113_NPCM (1<<0)
+#define AK4113_FS_8000HZ (AK4113_FS3|AK4113_FS0)
+#define AK4113_FS_11025HZ (AK4113_FS2|AK4113_FS0)
+#define AK4113_FS_16000HZ (AK4113_FS2|AK4113_FS1|AK4113_FS0)
+#define AK4113_FS_22050HZ (AK4113_FS2)
+#define AK4113_FS_24000HZ (AK4113_FS2|AK4113_FS1)
+#define AK4113_FS_32000HZ (AK4113_FS1|AK4113_FS0)
+#define AK4113_FS_44100HZ (0)
+#define AK4113_FS_48000HZ (AK4113_FS1)
+#define AK4113_FS_64000HZ (AK4113_FS3|AK4113_FS1|AK4113_FS0)
+#define AK4113_FS_88200HZ (AK4113_FS3)
+#define AK4113_FS_96000HZ (AK4113_FS3|AK4113_FS1)
+#define AK4113_FS_176400HZ (AK4113_FS3|AK4113_FS2)
+#define AK4113_FS_192000HZ (AK4113_FS3|AK4113_FS2|AK4113_FS1)
+
+/* AK4113_REG_RCS2 */
+/* CRC for Q-subcode, 0 = no error, 1 = error */
+#define AK4113_QCRC (1<<1)
+/* CRC for channel status, 0 = no error, 1 = error */
+#define AK4113_CCRC (1<<0)
+
+/* flags for snd_ak4113_check_rate_and_errors() */
+#define AK4113_CHECK_NO_STAT (1<<0) /* no statistics */
+#define AK4113_CHECK_NO_RATE (1<<1) /* no rate check */
+
+#define AK4113_CONTROLS 13
+
+typedef void (ak4113_write_t)(void *private_data, unsigned char addr,
+ unsigned char data);
+typedef unsigned char (ak4113_read_t)(void *private_data, unsigned char addr);
+
+struct ak4113 {
+ struct snd_card *card;
+ ak4113_write_t *write;
+ ak4113_read_t *read;
+ void *private_data;
+ unsigned int init:1;
+ spinlock_t lock;
+ unsigned char regmap[AK4113_WRITABLE_REGS];
+ struct snd_kcontrol *kctls[AK4113_CONTROLS];
+ struct snd_pcm_substream *substream;
+ unsigned long parity_errors;
+ unsigned long v_bit_errors;
+ unsigned long qcrc_errors;
+ unsigned long ccrc_errors;
+ unsigned char rcs0;
+ unsigned char rcs1;
+ unsigned char rcs2;
+ struct delayed_work work;
+ unsigned int check_flags;
+ void *change_callback_private;
+ void (*change_callback)(struct ak4113 *ak4113, unsigned char c0,
+ unsigned char c1);
+};
+
+int snd_ak4113_create(struct snd_card *card, ak4113_read_t *read,
+ ak4113_write_t *write,
+ const unsigned char pgm[AK4113_WRITABLE_REGS],
+ void *private_data, struct ak4113 **r_ak4113);
+void snd_ak4113_reg_write(struct ak4113 *ak4113, unsigned char reg,
+ unsigned char mask, unsigned char val);
+void snd_ak4113_reinit(struct ak4113 *ak4113);
+int snd_ak4113_build(struct ak4113 *ak4113,
+ struct snd_pcm_substream *capture_substream);
+int snd_ak4113_external_rate(struct ak4113 *ak4113);
+int snd_ak4113_check_rate_and_errors(struct ak4113 *ak4113, unsigned int flags);
+
+#endif /* __SOUND_AK4113_H */
+
diff --git a/include/sound/ak4114.h b/include/sound/ak4114.h
index d293d36a66b8..3ce69fd92523 100644
--- a/include/sound/ak4114.h
+++ b/include/sound/ak4114.h
@@ -95,13 +95,13 @@
/* AK4114_REG_IO0 */
#define AK4114_TX1E (1<<7) /* TX1 Output Enable (1 = enable) */
-#define AK4114_OPS12 (1<<2) /* Output Though Data Selector for TX1 pin */
-#define AK4114_OPS11 (1<<1) /* Output Though Data Selector for TX1 pin */
-#define AK4114_OPS10 (1<<0) /* Output Though Data Selector for TX1 pin */
+#define AK4114_OPS12 (1<<6) /* Output Data Selector for TX1 pin */
+#define AK4114_OPS11 (1<<5) /* Output Data Selector for TX1 pin */
+#define AK4114_OPS10 (1<<4) /* Output Data Selector for TX1 pin */
#define AK4114_TX0E (1<<3) /* TX0 Output Enable (1 = enable) */
-#define AK4114_OPS02 (1<<2) /* Output Though Data Selector for TX0 pin */
-#define AK4114_OPS01 (1<<1) /* Output Though Data Selector for TX0 pin */
-#define AK4114_OPS00 (1<<0) /* Output Though Data Selector for TX0 pin */
+#define AK4114_OPS02 (1<<2) /* Output Data Selector for TX0 pin */
+#define AK4114_OPS01 (1<<1) /* Output Data Selector for TX0 pin */
+#define AK4114_OPS00 (1<<0) /* Output Data Selector for TX0 pin */
/* AK4114_REG_IO1 */
#define AK4114_EFH1 (1<<7) /* Interrupt 0 pin Hold */
diff --git a/include/sound/ak4xxx-adda.h b/include/sound/ak4xxx-adda.h
index 891cf1aea8b1..030b87c2f6d4 100644
--- a/include/sound/ak4xxx-adda.h
+++ b/include/sound/ak4xxx-adda.h
@@ -68,7 +68,7 @@ struct snd_akm4xxx {
enum {
SND_AK4524, SND_AK4528, SND_AK4529,
SND_AK4355, SND_AK4358, SND_AK4381,
- SND_AK5365
+ SND_AK5365, SND_AK4620,
} type;
/* (array) information of combined codecs */
@@ -76,6 +76,9 @@ struct snd_akm4xxx {
const struct snd_akm4xxx_adc_channel *adc_info;
struct snd_ak4xxx_ops ops;
+ unsigned int num_chips;
+ unsigned int total_regs;
+ const char *name;
};
void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 97ca9af414dc..ca24e7f7a3f5 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -30,6 +30,7 @@ struct snd_pcm_substream;
#define SND_SOC_DAIFMT_DSP_A 3 /* L data MSB after FRM LRC */
#define SND_SOC_DAIFMT_DSP_B 4 /* L data MSB during FRM LRC */
#define SND_SOC_DAIFMT_AC97 5 /* AC97 */
+#define SND_SOC_DAIFMT_PDM 6 /* Pulse density modulation */
/* left and right justified also known as MSB and LSB respectively */
#define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J
@@ -106,7 +107,7 @@ int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
int div_id, int div);
int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
- int pll_id, unsigned int freq_in, unsigned int freq_out);
+ int pll_id, int source, unsigned int freq_in, unsigned int freq_out);
/* Digital Audio interface formatting */
int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
@@ -114,6 +115,10 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int 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);
+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);
+
int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
/* Digital Audio Interface mute */
@@ -136,8 +141,8 @@ struct snd_soc_dai_ops {
*/
int (*set_sysclk)(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir);
- int (*set_pll)(struct snd_soc_dai *dai,
- int pll_id, unsigned int freq_in, unsigned int freq_out);
+ int (*set_pll)(struct snd_soc_dai *dai, int pll_id, int source,
+ unsigned int freq_in, unsigned int freq_out);
int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div);
/*
@@ -148,6 +153,9 @@ struct snd_soc_dai_ops {
int (*set_tdm_slot)(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask,
int slots, int slot_width);
+ int (*set_channel_map)(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot);
int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
/*
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index c1410e3191e3..c5c95e1da65b 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -206,6 +206,12 @@
.get = snd_soc_dapm_get_enum_double, \
.put = snd_soc_dapm_put_enum_double, \
.private_value = (unsigned long)&xenum }
+#define SOC_DAPM_ENUM_VIRT(xname, xenum) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_enum_double, \
+ .get = snd_soc_dapm_get_enum_virt, \
+ .put = snd_soc_dapm_put_enum_virt, \
+ .private_value = (unsigned long)&xenum }
#define SOC_DAPM_VALUE_ENUM(xname, xenum) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_enum_double, \
@@ -260,6 +266,10 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
@@ -333,6 +343,10 @@ struct snd_soc_dapm_route {
const char *sink;
const char *control;
const char *source;
+
+ /* Note: currently only supported for links where source is a supply */
+ int (*connected)(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink);
};
/* dapm audio path between two widgets */
@@ -349,6 +363,9 @@ struct snd_soc_dapm_path {
u32 connect:1; /* source and sink widgets are connected */
u32 walked:1; /* path has been walked */
+ int (*connected)(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink);
+
struct list_head list_source;
struct list_head list_sink;
struct list_head list;
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 475cb7ed6bec..b1245e3acdfc 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -223,11 +223,6 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
int addr_bits, int data_bits,
enum snd_soc_control_type control);
-#ifdef CONFIG_PM
-int snd_soc_suspend_device(struct device *dev);
-int snd_soc_resume_device(struct device *dev);
-#endif
-
/* 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);
@@ -413,6 +408,7 @@ struct snd_soc_codec {
unsigned int num_dai;
#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_codec_root;
struct dentry *debugfs_reg;
struct dentry *debugfs_pop_time;
struct dentry *debugfs_dapm;
diff --git a/include/sound/sscape_ioctl.h b/include/sound/sscape_ioctl.h
deleted file mode 100644
index 0d8885969c64..000000000000
--- a/include/sound/sscape_ioctl.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef SSCAPE_IOCTL_H
-#define SSCAPE_IOCTL_H
-
-
-struct sscape_bootblock
-{
- unsigned char code[256];
- unsigned version;
-};
-
-#define SSCAPE_MICROCODE_SIZE 65536
-
-struct sscape_microcode
-{
- unsigned char __user *code;
-};
-
-#define SND_SSCAPE_LOAD_BOOTB _IOWR('P', 100, struct sscape_bootblock)
-#define SND_SSCAPE_LOAD_MCODE _IOW ('P', 101, struct sscape_microcode)
-
-#endif
diff --git a/include/sound/tlv320dac33-plat.h b/include/sound/tlv320dac33-plat.h
new file mode 100644
index 000000000000..5858d06a7ffa
--- /dev/null
+++ b/include/sound/tlv320dac33-plat.h
@@ -0,0 +1,20 @@
+/*
+ * Platform header for Texas Instruments TLV320DAC33 codec driver
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *
+ * Copyright: (C) 2009 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.
+ */
+
+#ifndef __TLV320DAC33_PLAT_H
+#define __TLV320DAC33_PLAT_H
+
+struct tlv320dac33_platform_data {
+ int power_gpio;
+};
+
+#endif /* __TLV320DAC33_PLAT_H */
diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.h b/include/sound/tpa6130a2-plat.h
index ee36695e134e..e8c901e749d8 100644
--- a/drivers/net/wireless/wl12xx/wl1251_netlink.h
+++ b/include/sound/tpa6130a2-plat.h
@@ -1,9 +1,9 @@
/*
- * This file is part of wl1251
+ * TPA6130A2 driver platform header
*
- * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) Nokia Corporation
*
- * Contact: Kalle Valo <kalle.valo@nokia.com>
+ * Written by Peter Ujfalusi <peter.ujfalusi@nokia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -18,13 +18,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
- *
*/
-#ifndef __WL1251_NETLINK_H__
-#define __WL1251_NETLINK_H__
+#ifndef TPA6130A2_PLAT_H
+#define TPA6130A2_PLAT_H
-int wl1251_nl_register(void);
-void wl1251_nl_unregister(void);
+struct tpa6130a2_platform_data {
+ int power_gpio;
+};
-#endif /* __WL1251_NETLINK_H__ */
+#endif
diff --git a/include/trace/events/bkl.h b/include/trace/events/bkl.h
new file mode 100644
index 000000000000..1af72dc24278
--- /dev/null
+++ b/include/trace/events/bkl.h
@@ -0,0 +1,61 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM bkl
+
+#if !defined(_TRACE_BKL_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_BKL_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(lock_kernel,
+
+ TP_PROTO(const char *func, const char *file, int line),
+
+ TP_ARGS(func, file, line),
+
+ TP_STRUCT__entry(
+ __field( int, depth )
+ __field_ext( const char *, func, FILTER_PTR_STRING )
+ __field_ext( const char *, file, FILTER_PTR_STRING )
+ __field( int, line )
+ ),
+
+ TP_fast_assign(
+ /* We want to record the lock_depth after lock is acquired */
+ __entry->depth = current->lock_depth + 1;
+ __entry->func = func;
+ __entry->file = file;
+ __entry->line = line;
+ ),
+
+ TP_printk("depth=%d file:line=%s:%d func=%s()", __entry->depth,
+ __entry->file, __entry->line, __entry->func)
+);
+
+TRACE_EVENT(unlock_kernel,
+
+ TP_PROTO(const char *func, const char *file, int line),
+
+ TP_ARGS(func, file, line),
+
+ TP_STRUCT__entry(
+ __field(int, depth )
+ __field(const char *, func )
+ __field(const char *, file )
+ __field(int, line )
+ ),
+
+ TP_fast_assign(
+ __entry->depth = current->lock_depth;
+ __entry->func = func;
+ __entry->file = file;
+ __entry->line = line;
+ ),
+
+ TP_printk("depth=%d file:line=%s:%d func=%s()", __entry->depth,
+ __entry->file, __entry->line, __entry->func)
+);
+
+#endif /* _TRACE_BKL_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/fs/gfs2/trace_gfs2.h b/include/trace/events/gfs2.h
index 148d55c14171..38db1b7ab071 100644
--- a/fs/gfs2/trace_gfs2.h
+++ b/include/trace/events/gfs2.h
@@ -10,8 +10,8 @@
#include <linux/buffer_head.h>
#include <linux/dlmconstants.h>
#include <linux/gfs2_ondisk.h>
-#include "incore.h"
-#include "glock.h"
+#include "../../../fs/gfs2/incore.h"
+#include "../../../fs/gfs2/glock.h"
#define dlm_state_name(nn) { DLM_LOCK_##nn, #nn }
#define glock_trace_name(x) __print_symbolic(x, \
@@ -400,8 +400,5 @@ TRACE_EVENT(gfs2_block_alloc,
#endif /* _TRACE_GFS2_H */
/* This part must be outside protection */
-#undef TRACE_INCLUDE_PATH
-#define TRACE_INCLUDE_PATH .
-#define TRACE_INCLUDE_FILE trace_gfs2
#include <trace/define_trace.h>
diff --git a/include/trace/events/irq.h b/include/trace/events/irq.h
index b89f9db4a404..dcfcd4407623 100644
--- a/include/trace/events/irq.h
+++ b/include/trace/events/irq.h
@@ -48,7 +48,7 @@ TRACE_EVENT(irq_handler_entry,
__assign_str(name, action->name);
),
- TP_printk("irq=%d handler=%s", __entry->irq, __get_str(name))
+ TP_printk("irq=%d name=%s", __entry->irq, __get_str(name))
);
/**
@@ -78,7 +78,7 @@ TRACE_EVENT(irq_handler_exit,
__entry->ret = ret;
),
- TP_printk("irq=%d return=%s",
+ TP_printk("irq=%d ret=%s",
__entry->irq, __entry->ret ? "handled" : "unhandled")
);
@@ -107,7 +107,7 @@ TRACE_EVENT(softirq_entry,
__entry->vec = (int)(h - vec);
),
- TP_printk("softirq=%d action=%s", __entry->vec,
+ TP_printk("vec=%d [action=%s]", __entry->vec,
show_softirq_name(__entry->vec))
);
@@ -136,7 +136,7 @@ TRACE_EVENT(softirq_exit,
__entry->vec = (int)(h - vec);
),
- TP_printk("softirq=%d action=%s", __entry->vec,
+ TP_printk("vec=%d [action=%s]", __entry->vec,
show_softirq_name(__entry->vec))
);
diff --git a/include/trace/events/mce.h b/include/trace/events/mce.h
new file mode 100644
index 000000000000..7eee77895cb3
--- /dev/null
+++ b/include/trace/events/mce.h
@@ -0,0 +1,69 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mce
+
+#if !defined(_TRACE_MCE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_MCE_H
+
+#include <linux/ktime.h>
+#include <linux/tracepoint.h>
+#include <asm/mce.h>
+
+TRACE_EVENT(mce_record,
+
+ TP_PROTO(struct mce *m),
+
+ TP_ARGS(m),
+
+ TP_STRUCT__entry(
+ __field( u64, mcgcap )
+ __field( u64, mcgstatus )
+ __field( u8, bank )
+ __field( u64, status )
+ __field( u64, addr )
+ __field( u64, misc )
+ __field( u64, ip )
+ __field( u8, cs )
+ __field( u64, tsc )
+ __field( u64, walltime )
+ __field( u32, cpu )
+ __field( u32, cpuid )
+ __field( u32, apicid )
+ __field( u32, socketid )
+ __field( u8, cpuvendor )
+ ),
+
+ TP_fast_assign(
+ __entry->mcgcap = m->mcgcap;
+ __entry->mcgstatus = m->mcgstatus;
+ __entry->bank = m->bank;
+ __entry->status = m->status;
+ __entry->addr = m->addr;
+ __entry->misc = m->misc;
+ __entry->ip = m->ip;
+ __entry->cs = m->cs;
+ __entry->tsc = m->tsc;
+ __entry->walltime = m->time;
+ __entry->cpu = m->extcpu;
+ __entry->cpuid = m->cpuid;
+ __entry->apicid = m->apicid;
+ __entry->socketid = m->socketid;
+ __entry->cpuvendor = m->cpuvendor;
+ ),
+
+ TP_printk("CPU: %d, MCGc/s: %llx/%llx, MC%d: %016Lx, ADDR/MISC: %016Lx/%016Lx, RIP: %02x:<%016Lx>, TSC: %llx, PROCESSOR: %u:%x, TIME: %llu, SOCKET: %u, APIC: %x",
+ __entry->cpu,
+ __entry->mcgcap, __entry->mcgstatus,
+ __entry->bank, __entry->status,
+ __entry->addr, __entry->misc,
+ __entry->cs, __entry->ip,
+ __entry->tsc,
+ __entry->cpuvendor, __entry->cpuid,
+ __entry->walltime,
+ __entry->socketid,
+ __entry->apicid)
+);
+
+#endif /* _TRACE_MCE_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/power.h b/include/trace/events/power.h
index ea6d579261ad..9bb96e5a2848 100644
--- a/include/trace/events/power.h
+++ b/include/trace/events/power.h
@@ -16,8 +16,6 @@ enum {
};
#endif
-
-
TRACE_EVENT(power_start,
TP_PROTO(unsigned int type, unsigned int state),
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index 4069c43f4187..b50b9856c59f 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -26,7 +26,7 @@ TRACE_EVENT(sched_kthread_stop,
__entry->pid = t->pid;
),
- TP_printk("task %s:%d", __entry->comm, __entry->pid)
+ TP_printk("comm=%s pid=%d", __entry->comm, __entry->pid)
);
/*
@@ -46,7 +46,7 @@ TRACE_EVENT(sched_kthread_stop_ret,
__entry->ret = ret;
),
- TP_printk("ret %d", __entry->ret)
+ TP_printk("ret=%d", __entry->ret)
);
/*
@@ -73,7 +73,7 @@ TRACE_EVENT(sched_wait_task,
__entry->prio = p->prio;
),
- TP_printk("task %s:%d [%d]",
+ TP_printk("comm=%s pid=%d prio=%d",
__entry->comm, __entry->pid, __entry->prio)
);
@@ -94,7 +94,7 @@ TRACE_EVENT(sched_wakeup,
__field( pid_t, pid )
__field( int, prio )
__field( int, success )
- __field( int, cpu )
+ __field( int, target_cpu )
),
TP_fast_assign(
@@ -102,12 +102,12 @@ TRACE_EVENT(sched_wakeup,
__entry->pid = p->pid;
__entry->prio = p->prio;
__entry->success = success;
- __entry->cpu = task_cpu(p);
+ __entry->target_cpu = task_cpu(p);
),
- TP_printk("task %s:%d [%d] success=%d [%03d]",
+ TP_printk("comm=%s pid=%d prio=%d success=%d target_cpu=%03d",
__entry->comm, __entry->pid, __entry->prio,
- __entry->success, __entry->cpu)
+ __entry->success, __entry->target_cpu)
);
/*
@@ -127,7 +127,7 @@ TRACE_EVENT(sched_wakeup_new,
__field( pid_t, pid )
__field( int, prio )
__field( int, success )
- __field( int, cpu )
+ __field( int, target_cpu )
),
TP_fast_assign(
@@ -135,12 +135,12 @@ TRACE_EVENT(sched_wakeup_new,
__entry->pid = p->pid;
__entry->prio = p->prio;
__entry->success = success;
- __entry->cpu = task_cpu(p);
+ __entry->target_cpu = task_cpu(p);
),
- TP_printk("task %s:%d [%d] success=%d [%03d]",
+ TP_printk("comm=%s pid=%d prio=%d success=%d target_cpu=%03d",
__entry->comm, __entry->pid, __entry->prio,
- __entry->success, __entry->cpu)
+ __entry->success, __entry->target_cpu)
);
/*
@@ -176,7 +176,7 @@ TRACE_EVENT(sched_switch,
__entry->next_prio = next->prio;
),
- TP_printk("task %s:%d [%d] (%s) ==> %s:%d [%d]",
+ TP_printk("prev_comm=%s prev_pid=%d prev_prio=%d prev_state=%s ==> next_comm=%s next_pid=%d next_prio=%d",
__entry->prev_comm, __entry->prev_pid, __entry->prev_prio,
__entry->prev_state ?
__print_flags(__entry->prev_state, "|",
@@ -211,7 +211,7 @@ TRACE_EVENT(sched_migrate_task,
__entry->dest_cpu = dest_cpu;
),
- TP_printk("task %s:%d [%d] from: %d to: %d",
+ TP_printk("comm=%s pid=%d prio=%d orig_cpu=%d dest_cpu=%d",
__entry->comm, __entry->pid, __entry->prio,
__entry->orig_cpu, __entry->dest_cpu)
);
@@ -237,7 +237,7 @@ TRACE_EVENT(sched_process_free,
__entry->prio = p->prio;
),
- TP_printk("task %s:%d [%d]",
+ TP_printk("comm=%s pid=%d prio=%d",
__entry->comm, __entry->pid, __entry->prio)
);
@@ -262,7 +262,7 @@ TRACE_EVENT(sched_process_exit,
__entry->prio = p->prio;
),
- TP_printk("task %s:%d [%d]",
+ TP_printk("comm=%s pid=%d prio=%d",
__entry->comm, __entry->pid, __entry->prio)
);
@@ -287,7 +287,7 @@ TRACE_EVENT(sched_process_wait,
__entry->prio = current->prio;
),
- TP_printk("task %s:%d [%d]",
+ TP_printk("comm=%s pid=%d prio=%d",
__entry->comm, __entry->pid, __entry->prio)
);
@@ -314,7 +314,7 @@ TRACE_EVENT(sched_process_fork,
__entry->child_pid = child->pid;
),
- TP_printk("parent %s:%d child %s:%d",
+ TP_printk("comm=%s pid=%d child_comm=%s child_pid=%d",
__entry->parent_comm, __entry->parent_pid,
__entry->child_comm, __entry->child_pid)
);
@@ -340,7 +340,7 @@ TRACE_EVENT(sched_signal_send,
__entry->sig = sig;
),
- TP_printk("sig: %d task %s:%d",
+ TP_printk("sig=%d comm=%s pid=%d",
__entry->sig, __entry->comm, __entry->pid)
);
@@ -374,7 +374,7 @@ TRACE_EVENT(sched_stat_wait,
__perf_count(delay);
),
- TP_printk("task: %s:%d wait: %Lu [ns]",
+ TP_printk("comm=%s pid=%d delay=%Lu [ns]",
__entry->comm, __entry->pid,
(unsigned long long)__entry->delay)
);
@@ -406,7 +406,7 @@ TRACE_EVENT(sched_stat_runtime,
__perf_count(runtime);
),
- TP_printk("task: %s:%d runtime: %Lu [ns], vruntime: %Lu [ns]",
+ TP_printk("comm=%s pid=%d runtime=%Lu [ns] vruntime=%Lu [ns]",
__entry->comm, __entry->pid,
(unsigned long long)__entry->runtime,
(unsigned long long)__entry->vruntime)
@@ -437,7 +437,7 @@ TRACE_EVENT(sched_stat_sleep,
__perf_count(delay);
),
- TP_printk("task: %s:%d sleep: %Lu [ns]",
+ TP_printk("comm=%s pid=%d delay=%Lu [ns]",
__entry->comm, __entry->pid,
(unsigned long long)__entry->delay)
);
@@ -467,7 +467,7 @@ TRACE_EVENT(sched_stat_iowait,
__perf_count(delay);
),
- TP_printk("task: %s:%d iowait: %Lu [ns]",
+ TP_printk("comm=%s pid=%d delay=%Lu [ns]",
__entry->comm, __entry->pid,
(unsigned long long)__entry->delay)
);
diff --git a/include/trace/events/timer.h b/include/trace/events/timer.h
index 1844c48d640e..e5ce87a0498d 100644
--- a/include/trace/events/timer.h
+++ b/include/trace/events/timer.h
@@ -26,7 +26,7 @@ TRACE_EVENT(timer_init,
__entry->timer = timer;
),
- TP_printk("timer %p", __entry->timer)
+ TP_printk("timer=%p", __entry->timer)
);
/**
@@ -54,7 +54,7 @@ TRACE_EVENT(timer_start,
__entry->now = jiffies;
),
- TP_printk("timer %p: func %pf, expires %lu, timeout %ld",
+ TP_printk("timer=%p function=%pf expires=%lu [timeout=%ld]",
__entry->timer, __entry->function, __entry->expires,
(long)__entry->expires - __entry->now)
);
@@ -81,7 +81,7 @@ TRACE_EVENT(timer_expire_entry,
__entry->now = jiffies;
),
- TP_printk("timer %p: now %lu", __entry->timer, __entry->now)
+ TP_printk("timer=%p now=%lu", __entry->timer, __entry->now)
);
/**
@@ -108,7 +108,7 @@ TRACE_EVENT(timer_expire_exit,
__entry->timer = timer;
),
- TP_printk("timer %p", __entry->timer)
+ TP_printk("timer=%p", __entry->timer)
);
/**
@@ -129,7 +129,7 @@ TRACE_EVENT(timer_cancel,
__entry->timer = timer;
),
- TP_printk("timer %p", __entry->timer)
+ TP_printk("timer=%p", __entry->timer)
);
/**
@@ -140,24 +140,24 @@ TRACE_EVENT(timer_cancel,
*/
TRACE_EVENT(hrtimer_init,
- TP_PROTO(struct hrtimer *timer, clockid_t clockid,
+ TP_PROTO(struct hrtimer *hrtimer, clockid_t clockid,
enum hrtimer_mode mode),
- TP_ARGS(timer, clockid, mode),
+ TP_ARGS(hrtimer, clockid, mode),
TP_STRUCT__entry(
- __field( void *, timer )
+ __field( void *, hrtimer )
__field( clockid_t, clockid )
__field( enum hrtimer_mode, mode )
),
TP_fast_assign(
- __entry->timer = timer;
+ __entry->hrtimer = hrtimer;
__entry->clockid = clockid;
__entry->mode = mode;
),
- TP_printk("hrtimer %p, clockid %s, mode %s", __entry->timer,
+ TP_printk("hrtimer=%p clockid=%s mode=%s", __entry->hrtimer,
__entry->clockid == CLOCK_REALTIME ?
"CLOCK_REALTIME" : "CLOCK_MONOTONIC",
__entry->mode == HRTIMER_MODE_ABS ?
@@ -170,26 +170,26 @@ TRACE_EVENT(hrtimer_init,
*/
TRACE_EVENT(hrtimer_start,
- TP_PROTO(struct hrtimer *timer),
+ TP_PROTO(struct hrtimer *hrtimer),
- TP_ARGS(timer),
+ TP_ARGS(hrtimer),
TP_STRUCT__entry(
- __field( void *, timer )
+ __field( void *, hrtimer )
__field( void *, function )
__field( s64, expires )
__field( s64, softexpires )
),
TP_fast_assign(
- __entry->timer = timer;
- __entry->function = timer->function;
- __entry->expires = hrtimer_get_expires(timer).tv64;
- __entry->softexpires = hrtimer_get_softexpires(timer).tv64;
+ __entry->hrtimer = hrtimer;
+ __entry->function = hrtimer->function;
+ __entry->expires = hrtimer_get_expires(hrtimer).tv64;
+ __entry->softexpires = hrtimer_get_softexpires(hrtimer).tv64;
),
- TP_printk("hrtimer %p, func %pf, expires %llu, softexpires %llu",
- __entry->timer, __entry->function,
+ TP_printk("hrtimer=%p function=%pf expires=%llu softexpires=%llu",
+ __entry->hrtimer, __entry->function,
(unsigned long long)ktime_to_ns((ktime_t) {
.tv64 = __entry->expires }),
(unsigned long long)ktime_to_ns((ktime_t) {
@@ -206,23 +206,22 @@ TRACE_EVENT(hrtimer_start,
*/
TRACE_EVENT(hrtimer_expire_entry,
- TP_PROTO(struct hrtimer *timer, ktime_t *now),
+ TP_PROTO(struct hrtimer *hrtimer, ktime_t *now),
- TP_ARGS(timer, now),
+ TP_ARGS(hrtimer, now),
TP_STRUCT__entry(
- __field( void *, timer )
+ __field( void *, hrtimer )
__field( s64, now )
),
TP_fast_assign(
- __entry->timer = timer;
- __entry->now = now->tv64;
+ __entry->hrtimer = hrtimer;
+ __entry->now = now->tv64;
),
- TP_printk("hrtimer %p, now %llu", __entry->timer,
- (unsigned long long)ktime_to_ns((ktime_t) {
- .tv64 = __entry->now }))
+ TP_printk("hrtimer=%p now=%llu", __entry->hrtimer,
+ (unsigned long long)ktime_to_ns((ktime_t) { .tv64 = __entry->now }))
);
/**
@@ -234,40 +233,40 @@ TRACE_EVENT(hrtimer_expire_entry,
*/
TRACE_EVENT(hrtimer_expire_exit,
- TP_PROTO(struct hrtimer *timer),
+ TP_PROTO(struct hrtimer *hrtimer),
- TP_ARGS(timer),
+ TP_ARGS(hrtimer),
TP_STRUCT__entry(
- __field( void *, timer )
+ __field( void *, hrtimer )
),
TP_fast_assign(
- __entry->timer = timer;
+ __entry->hrtimer = hrtimer;
),
- TP_printk("hrtimer %p", __entry->timer)
+ TP_printk("hrtimer=%p", __entry->hrtimer)
);
/**
* hrtimer_cancel - called when the hrtimer is canceled
- * @timer: pointer to struct hrtimer
+ * @hrtimer: pointer to struct hrtimer
*/
TRACE_EVENT(hrtimer_cancel,
- TP_PROTO(struct hrtimer *timer),
+ TP_PROTO(struct hrtimer *hrtimer),
- TP_ARGS(timer),
+ TP_ARGS(hrtimer),
TP_STRUCT__entry(
- __field( void *, timer )
+ __field( void *, hrtimer )
),
TP_fast_assign(
- __entry->timer = timer;
+ __entry->hrtimer = hrtimer;
),
- TP_printk("hrtimer %p", __entry->timer)
+ TP_printk("hrtimer=%p", __entry->hrtimer)
);
/**
@@ -302,7 +301,7 @@ TRACE_EVENT(itimer_state,
__entry->interval_usec = value->it_interval.tv_usec;
),
- TP_printk("which %d, expires %lu, it_value %lu.%lu, it_interval %lu.%lu",
+ TP_printk("which=%d expires=%lu it_value=%lu.%lu it_interval=%lu.%lu",
__entry->which, __entry->expires,
__entry->value_sec, __entry->value_usec,
__entry->interval_sec, __entry->interval_usec)
@@ -332,7 +331,7 @@ TRACE_EVENT(itimer_expire,
__entry->pid = pid_nr(pid);
),
- TP_printk("which %d, pid %d, now %lu", __entry->which,
+ TP_printk("which=%d pid=%d now=%lu", __entry->which,
(int) __entry->pid, __entry->now)
);
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index cc0d9667e182..a7f946094128 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -120,9 +120,10 @@
#undef __field
#define __field(type, item) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \
- "offset:%u;\tsize:%u;\n", \
+ "offset:%u;\tsize:%u;\tsigned:%u;\n", \
(unsigned int)offsetof(typeof(field), item), \
- (unsigned int)sizeof(field.item)); \
+ (unsigned int)sizeof(field.item), \
+ (unsigned int)is_signed_type(type)); \
if (!ret) \
return 0;
@@ -132,19 +133,21 @@
#undef __array
#define __array(type, item, len) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \
- "offset:%u;\tsize:%u;\n", \
+ "offset:%u;\tsize:%u;\tsigned:%u;\n", \
(unsigned int)offsetof(typeof(field), item), \
- (unsigned int)sizeof(field.item)); \
+ (unsigned int)sizeof(field.item), \
+ (unsigned int)is_signed_type(type)); \
if (!ret) \
return 0;
#undef __dynamic_array
#define __dynamic_array(type, item, len) \
ret = trace_seq_printf(s, "\tfield:__data_loc " #type "[] " #item ";\t"\
- "offset:%u;\tsize:%u;\n", \
+ "offset:%u;\tsize:%u;\tsigned:%u;\n", \
(unsigned int)offsetof(typeof(field), \
__data_loc_##item), \
- (unsigned int)sizeof(field.__data_loc_##item)); \
+ (unsigned int)sizeof(field.__data_loc_##item), \
+ (unsigned int)is_signed_type(type)); \
if (!ret) \
return 0;
@@ -399,12 +402,12 @@ static inline int ftrace_get_offsets_##call( \
\
static void ftrace_profile_##call(proto); \
\
-static int ftrace_profile_enable_##call(void) \
+static int ftrace_profile_enable_##call(struct ftrace_event_call *unused)\
{ \
return register_trace_##call(ftrace_profile_##call); \
} \
\
-static void ftrace_profile_disable_##call(void) \
+static void ftrace_profile_disable_##call(struct ftrace_event_call *unused)\
{ \
unregister_trace_##call(ftrace_profile_##call); \
}
@@ -423,7 +426,7 @@ static void ftrace_profile_disable_##call(void) \
* event_trace_printk(_RET_IP_, "<call>: " <fmt>);
* }
*
- * static int ftrace_reg_event_<call>(void)
+ * static int ftrace_reg_event_<call>(struct ftrace_event_call *unused)
* {
* int ret;
*
@@ -434,7 +437,7 @@ static void ftrace_profile_disable_##call(void) \
* return ret;
* }
*
- * static void ftrace_unreg_event_<call>(void)
+ * static void ftrace_unreg_event_<call>(struct ftrace_event_call *unused)
* {
* unregister_trace_<call>(ftrace_event_<call>);
* }
@@ -469,7 +472,7 @@ static void ftrace_profile_disable_##call(void) \
* trace_current_buffer_unlock_commit(buffer, event, irq_flags, pc);
* }
*
- * static int ftrace_raw_reg_event_<call>(void)
+ * static int ftrace_raw_reg_event_<call>(struct ftrace_event_call *unused)
* {
* int ret;
*
@@ -480,7 +483,7 @@ static void ftrace_profile_disable_##call(void) \
* return ret;
* }
*
- * static void ftrace_unreg_event_<call>(void)
+ * static void ftrace_unreg_event_<call>(struct ftrace_event_call *unused)
* {
* unregister_trace_<call>(ftrace_raw_event_<call>);
* }
@@ -489,7 +492,7 @@ static void ftrace_profile_disable_##call(void) \
* .trace = ftrace_raw_output_<call>, <-- stage 2
* };
*
- * static int ftrace_raw_init_event_<call>(void)
+ * static int ftrace_raw_init_event_<call>(struct ftrace_event_call *unused)
* {
* int id;
*
@@ -586,7 +589,7 @@ static void ftrace_raw_event_##call(proto) \
event, irq_flags, pc); \
} \
\
-static int ftrace_raw_reg_event_##call(void *ptr) \
+static int ftrace_raw_reg_event_##call(struct ftrace_event_call *unused)\
{ \
int ret; \
\
@@ -597,7 +600,7 @@ static int ftrace_raw_reg_event_##call(void *ptr) \
return ret; \
} \
\
-static void ftrace_raw_unreg_event_##call(void *ptr) \
+static void ftrace_raw_unreg_event_##call(struct ftrace_event_call *unused)\
{ \
unregister_trace_##call(ftrace_raw_event_##call); \
} \
@@ -606,7 +609,7 @@ static struct trace_event ftrace_event_type_##call = { \
.trace = ftrace_raw_output_##call, \
}; \
\
-static int ftrace_raw_init_event_##call(void) \
+static int ftrace_raw_init_event_##call(struct ftrace_event_call *unused)\
{ \
int id; \
\
diff --git a/include/trace/syscall.h b/include/trace/syscall.h
index 5dc283ba5ae0..51ee17d3632a 100644
--- a/include/trace/syscall.h
+++ b/include/trace/syscall.h
@@ -33,22 +33,25 @@ struct syscall_metadata {
};
#ifdef CONFIG_FTRACE_SYSCALLS
-extern struct syscall_metadata *syscall_nr_to_meta(int nr);
+extern unsigned long arch_syscall_addr(int nr);
extern int syscall_name_to_nr(char *name);
void set_syscall_enter_id(int num, int id);
void set_syscall_exit_id(int num, int id);
extern struct trace_event event_syscall_enter;
extern struct trace_event event_syscall_exit;
-extern int reg_event_syscall_enter(void *ptr);
-extern void unreg_event_syscall_enter(void *ptr);
-extern int reg_event_syscall_exit(void *ptr);
-extern void unreg_event_syscall_exit(void *ptr);
+
extern int syscall_enter_format(struct ftrace_event_call *call,
struct trace_seq *s);
extern int syscall_exit_format(struct ftrace_event_call *call,
struct trace_seq *s);
extern int syscall_enter_define_fields(struct ftrace_event_call *call);
extern int syscall_exit_define_fields(struct ftrace_event_call *call);
+extern int reg_event_syscall_enter(struct ftrace_event_call *call);
+extern void unreg_event_syscall_enter(struct ftrace_event_call *call);
+extern int reg_event_syscall_exit(struct ftrace_event_call *call);
+extern void unreg_event_syscall_exit(struct ftrace_event_call *call);
+extern int
+ftrace_format_syscall(struct ftrace_event_call *call, struct trace_seq *s);
enum print_line_t print_syscall_enter(struct trace_iterator *iter, int flags);
enum print_line_t print_syscall_exit(struct trace_iterator *iter, int flags);
#endif
diff --git a/include/xen/xen.h b/include/xen/xen.h
new file mode 100644
index 000000000000..a16402418d31
--- /dev/null
+++ b/include/xen/xen.h
@@ -0,0 +1,32 @@
+#ifndef _XEN_XEN_H
+#define _XEN_XEN_H
+
+enum xen_domain_type {
+ XEN_NATIVE, /* running on bare hardware */
+ XEN_PV_DOMAIN, /* running in a PV domain */
+ XEN_HVM_DOMAIN, /* running in a Xen hvm domain */
+};
+
+#ifdef CONFIG_XEN
+extern enum xen_domain_type xen_domain_type;
+#else
+#define xen_domain_type XEN_NATIVE
+#endif
+
+#define xen_domain() (xen_domain_type != XEN_NATIVE)
+#define xen_pv_domain() (xen_domain() && \
+ xen_domain_type == XEN_PV_DOMAIN)
+#define xen_hvm_domain() (xen_domain() && \
+ xen_domain_type == XEN_HVM_DOMAIN)
+
+#ifdef CONFIG_XEN_DOM0
+#include <xen/interface/xen.h>
+#include <asm/xen/hypervisor.h>
+
+#define xen_initial_domain() (xen_pv_domain() && \
+ xen_start_info->flags & SIF_INITDOMAIN)
+#else /* !CONFIG_XEN_DOM0 */
+#define xen_initial_domain() (0)
+#endif /* CONFIG_XEN_DOM0 */
+
+#endif /* _XEN_XEN_H */
diff --git a/init/Kconfig b/init/Kconfig
index 09c5c6431f42..a669eb0b5683 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -297,18 +297,22 @@ config AUDIT
config AUDITSYSCALL
bool "Enable system-call auditing support"
- depends on AUDIT && (X86 || PPC || PPC64 || S390 || IA64 || UML || SPARC64|| SUPERH)
+ depends on AUDIT && (X86 || PPC || S390 || IA64 || UML || SPARC64 || SUPERH)
default y if SECURITY_SELINUX
help
Enable low-overhead system-call auditing infrastructure that
can be used independently or with another kernel subsystem,
- such as SELinux. To use audit's filesystem watch feature, please
- ensure that INOTIFY is configured.
+ such as SELinux.
+
+config AUDIT_WATCH
+ def_bool y
+ depends on AUDITSYSCALL
+ select FSNOTIFY
config AUDIT_TREE
def_bool y
depends on AUDITSYSCALL
- select INOTIFY
+ select FSNOTIFY
menu "RCU Subsystem"
@@ -334,6 +338,15 @@ config TREE_PREEMPT_RCU
is also required. It also scales down nicely to
smaller systems.
+config TINY_RCU
+ bool "UP-only small-memory-footprint RCU"
+ depends on !SMP
+ help
+ This option selects the RCU implementation that is
+ designed for UP systems from which real-time response
+ is not required. This option greatly reduces the
+ memory footprint of RCU.
+
endchoice
config RCU_TRACE
@@ -1059,6 +1072,11 @@ config SLUB
and has enhanced diagnostics. SLUB is the default choice for
a slab allocator.
+config SLQB
+ bool "SLQB (Queued allocator)"
+ help
+ SLQB is a proposed new slab allocator.
+
config SLOB
depends on EMBEDDED
bool "SLOB (Simple Allocator)"
@@ -1107,7 +1125,7 @@ config HAVE_GENERIC_DMA_COHERENT
config SLABINFO
bool
depends on PROC_FS
- depends on SLAB || SLUB_DEBUG
+ depends on SLAB || SLUB_DEBUG || SLQB
default y
config RT_MUTEXES
diff --git a/init/Makefile b/init/Makefile
index 4a243df426f7..0bf677aa0872 100644
--- a/init/Makefile
+++ b/init/Makefile
@@ -15,12 +15,8 @@ mounts-$(CONFIG_BLK_DEV_RAM) += do_mounts_rd.o
mounts-$(CONFIG_BLK_DEV_INITRD) += do_mounts_initrd.o
mounts-$(CONFIG_BLK_DEV_MD) += do_mounts_md.o
-# files to be removed upon make clean
-clean-files := ../include/linux/compile.h
-
# dependencies on generated files need to be listed explicitly
-
-$(obj)/version.o: include/linux/compile.h
+$(obj)/version.o: include/generated/compile.h
# compile.h changes depending on hostname, generation number, etc,
# so we regenerate it always.
@@ -30,7 +26,7 @@ $(obj)/version.o: include/linux/compile.h
chk_compile.h = :
quiet_chk_compile.h = echo ' CHK $@'
silent_chk_compile.h = :
-include/linux/compile.h: FORCE
+include/generated/compile.h: FORCE
@$($(quiet)chk_compile.h)
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ \
"$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CONFIG_PREEMPT)" "$(CC) $(KBUILD_CFLAGS)"
diff --git a/init/version.c b/init/version.c
index 52a8b98642b8..adff586401a5 100644
--- a/init/version.c
+++ b/init/version.c
@@ -6,11 +6,11 @@
* May be freely distributed as part of Linux.
*/
-#include <linux/compile.h>
+#include <generated/compile.h>
#include <linux/module.h>
#include <linux/uts.h>
#include <linux/utsname.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
#include <linux/version.h>
#ifndef CONFIG_KALLSYMS
diff --git a/ipc/msg.c b/ipc/msg.c
index 2ceab7f12fcb..085bd58f2f07 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -412,7 +412,7 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
struct msqid_ds __user *buf, int version)
{
struct kern_ipc_perm *ipcp;
- struct msqid64_ds msqid64;
+ struct msqid64_ds uninitialized_var(msqid64);
struct msg_queue *msq;
int err;
diff --git a/kernel/Makefile b/kernel/Makefile
index b8d4cd8ac0b9..e85a971198b5 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -68,10 +68,11 @@ obj-$(CONFIG_IKCONFIG) += configs.o
obj-$(CONFIG_RESOURCE_COUNTERS) += res_counter.o
obj-$(CONFIG_STOP_MACHINE) += stop_machine.o
obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o
-obj-$(CONFIG_AUDIT) += audit.o auditfilter.o audit_watch.o
+obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
-obj-$(CONFIG_GCOV_KERNEL) += gcov/
+obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o
obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
+obj-$(CONFIG_GCOV_KERNEL) += gcov/
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_KGDB) += kgdb.o
obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
@@ -82,6 +83,7 @@ obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
obj-$(CONFIG_TREE_RCU) += rcutree.o
obj-$(CONFIG_TREE_PREEMPT_RCU) += rcutree.o
obj-$(CONFIG_TREE_RCU_TRACE) += rcutree_trace.o
+obj-$(CONFIG_TINY_RCU) += rcutiny.o
obj-$(CONFIG_RELAY) += relay.o
obj-$(CONFIG_SYSCTL) += utsname_sysctl.o
obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
@@ -95,6 +97,7 @@ obj-$(CONFIG_RING_BUFFER) += trace/
obj-$(CONFIG_SMP) += sched_cpupri.o
obj-$(CONFIG_SLOW_WORK) += slow-work.o
obj-$(CONFIG_PERF_EVENTS) += perf_event.o
+obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
# According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/audit.c b/kernel/audit.c
index 5feed232be9d..057a3a4dbfa5 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -55,7 +55,6 @@
#include <net/netlink.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
-#include <linux/inotify.h>
#include <linux/freezer.h>
#include <linux/tty.h>
diff --git a/kernel/audit.h b/kernel/audit.h
index 208687be4f30..f7206db4e13d 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -103,21 +103,27 @@ extern struct mutex audit_filter_mutex;
extern void audit_free_rule_rcu(struct rcu_head *);
extern struct list_head audit_filter_list[];
+extern struct audit_entry *audit_dupe_rule(struct audit_krule *old);
+
/* audit watch functions */
-extern unsigned long audit_watch_inode(struct audit_watch *watch);
-extern dev_t audit_watch_dev(struct audit_watch *watch);
+#ifdef CONFIG_AUDIT_WATCH
extern void audit_put_watch(struct audit_watch *watch);
extern void audit_get_watch(struct audit_watch *watch);
extern int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op);
-extern int audit_add_watch(struct audit_krule *krule);
-extern void audit_remove_watch(struct audit_watch *watch);
-extern void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list);
-extern void audit_inotify_unregister(struct list_head *in_list);
+extern int audit_add_watch(struct audit_krule *krule, struct list_head **list);
+extern void audit_remove_watch_rule(struct audit_krule *krule);
extern char *audit_watch_path(struct audit_watch *watch);
-extern struct list_head *audit_watch_rules(struct audit_watch *watch);
-
-extern struct audit_entry *audit_dupe_rule(struct audit_krule *old,
- struct audit_watch *watch);
+extern int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev);
+#else
+#define audit_put_watch(w) {}
+#define audit_get_watch(w) {}
+#define audit_to_watch(k, p, l, o) (-EINVAL)
+#define audit_add_watch(k, l) (-EINVAL)
+#define audit_remove_watch_rule(k) BUG()
+#define audit_watch_path(w) ""
+#define audit_watch_compare(w, i, d) 0
+
+#endif /* CONFIG_AUDIT_WATCH */
#ifdef CONFIG_AUDIT_TREE
extern struct audit_chunk *audit_tree_lookup(const struct inode *);
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index 2451dc6f3282..f2e191d6892e 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -1,5 +1,5 @@
#include "audit.h"
-#include <linux/inotify.h>
+#include <linux/fsnotify_backend.h>
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/kthread.h>
@@ -21,7 +21,7 @@ struct audit_tree {
struct audit_chunk {
struct list_head hash;
- struct inotify_watch watch;
+ struct fsnotify_mark_entry mark;
struct list_head trees; /* with root here */
int dead;
int count;
@@ -67,7 +67,7 @@ static LIST_HEAD(prune_list);
* that makes a difference. Some.
*/
-static struct inotify_handle *rtree_ih;
+static struct fsnotify_group *audit_tree_group;
static struct audit_tree *alloc_tree(const char *s)
{
@@ -110,29 +110,6 @@ const char *audit_tree_path(struct audit_tree *tree)
return tree->pathname;
}
-static struct audit_chunk *alloc_chunk(int count)
-{
- struct audit_chunk *chunk;
- size_t size;
- int i;
-
- size = offsetof(struct audit_chunk, owners) + count * sizeof(struct node);
- chunk = kzalloc(size, GFP_KERNEL);
- if (!chunk)
- return NULL;
-
- INIT_LIST_HEAD(&chunk->hash);
- INIT_LIST_HEAD(&chunk->trees);
- chunk->count = count;
- atomic_long_set(&chunk->refs, 1);
- for (i = 0; i < count; i++) {
- INIT_LIST_HEAD(&chunk->owners[i].list);
- chunk->owners[i].index = i;
- }
- inotify_init_watch(&chunk->watch);
- return chunk;
-}
-
static void free_chunk(struct audit_chunk *chunk)
{
int i;
@@ -156,6 +133,35 @@ static void __put_chunk(struct rcu_head *rcu)
audit_put_chunk(chunk);
}
+static void audit_tree_destroy_watch(struct fsnotify_mark_entry *entry)
+{
+ struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark);
+ call_rcu(&chunk->head, __put_chunk);
+}
+
+static struct audit_chunk *alloc_chunk(int count)
+{
+ struct audit_chunk *chunk;
+ size_t size;
+ int i;
+
+ size = offsetof(struct audit_chunk, owners) + count * sizeof(struct node);
+ chunk = kzalloc(size, GFP_KERNEL);
+ if (!chunk)
+ return NULL;
+
+ INIT_LIST_HEAD(&chunk->hash);
+ INIT_LIST_HEAD(&chunk->trees);
+ chunk->count = count;
+ atomic_long_set(&chunk->refs, 1);
+ for (i = 0; i < count; i++) {
+ INIT_LIST_HEAD(&chunk->owners[i].list);
+ chunk->owners[i].index = i;
+ }
+ fsnotify_init_mark(&chunk->mark, audit_tree_destroy_watch);
+ return chunk;
+}
+
enum {HASH_SIZE = 128};
static struct list_head chunk_hash_heads[HASH_SIZE];
static __cacheline_aligned_in_smp DEFINE_SPINLOCK(hash_lock);
@@ -166,10 +172,15 @@ static inline struct list_head *chunk_hash(const struct inode *inode)
return chunk_hash_heads + n % HASH_SIZE;
}
-/* hash_lock is held by caller */
+/* hash_lock & entry->lock is held by caller */
static void insert_hash(struct audit_chunk *chunk)
{
- struct list_head *list = chunk_hash(chunk->watch.inode);
+ struct fsnotify_mark_entry *entry = &chunk->mark;
+ struct list_head *list;
+
+ if (!entry->i.inode)
+ return;
+ list = chunk_hash(entry->i.inode);
list_add_rcu(&chunk->hash, list);
}
@@ -180,7 +191,8 @@ struct audit_chunk *audit_tree_lookup(const struct inode *inode)
struct audit_chunk *p;
list_for_each_entry_rcu(p, list, hash) {
- if (p->watch.inode == inode) {
+ /* mark.inode may have gone NULL, but who cares? */
+ if (p->mark.i.inode == inode) {
atomic_long_inc(&p->refs);
return p;
}
@@ -209,38 +221,19 @@ static struct audit_chunk *find_chunk(struct node *p)
static void untag_chunk(struct node *p)
{
struct audit_chunk *chunk = find_chunk(p);
+ struct fsnotify_mark_entry *entry = &chunk->mark;
struct audit_chunk *new;
struct audit_tree *owner;
int size = chunk->count - 1;
int i, j;
- if (!pin_inotify_watch(&chunk->watch)) {
- /*
- * Filesystem is shutting down; all watches are getting
- * evicted, just take it off the node list for this
- * tree and let the eviction logics take care of the
- * rest.
- */
- owner = p->owner;
- if (owner->root == chunk) {
- list_del_init(&owner->same_root);
- owner->root = NULL;
- }
- list_del_init(&p->list);
- p->owner = NULL;
- put_tree(owner);
- return;
- }
+ fsnotify_get_mark(entry);
spin_unlock(&hash_lock);
- /*
- * pin_inotify_watch() succeeded, so the watch won't go away
- * from under us.
- */
- mutex_lock(&chunk->watch.inode->inotify_mutex);
- if (chunk->dead) {
- mutex_unlock(&chunk->watch.inode->inotify_mutex);
+ spin_lock(&entry->lock);
+ if (chunk->dead || !entry->i.inode) {
+ spin_unlock(&entry->lock);
goto out;
}
@@ -255,16 +248,17 @@ static void untag_chunk(struct node *p)
list_del_init(&p->list);
list_del_rcu(&chunk->hash);
spin_unlock(&hash_lock);
- inotify_evict_watch(&chunk->watch);
- mutex_unlock(&chunk->watch.inode->inotify_mutex);
- put_inotify_watch(&chunk->watch);
+ spin_unlock(&entry->lock);
+ fsnotify_destroy_mark_by_entry(entry);
+ fsnotify_put_mark(entry);
goto out;
}
new = alloc_chunk(size);
if (!new)
goto Fallback;
- if (inotify_clone_watch(&chunk->watch, &new->watch) < 0) {
+ fsnotify_duplicate_mark(&new->mark, entry);
+ if (fsnotify_add_mark(&new->mark, new->mark.group, new->mark.i.inode, 1)) {
free_chunk(new);
goto Fallback;
}
@@ -297,9 +291,9 @@ static void untag_chunk(struct node *p)
list_for_each_entry(owner, &new->trees, same_root)
owner->root = new;
spin_unlock(&hash_lock);
- inotify_evict_watch(&chunk->watch);
- mutex_unlock(&chunk->watch.inode->inotify_mutex);
- put_inotify_watch(&chunk->watch);
+ spin_unlock(&entry->lock);
+ fsnotify_destroy_mark_by_entry(entry);
+ fsnotify_put_mark(entry);
goto out;
Fallback:
@@ -313,31 +307,33 @@ Fallback:
p->owner = NULL;
put_tree(owner);
spin_unlock(&hash_lock);
- mutex_unlock(&chunk->watch.inode->inotify_mutex);
+ spin_unlock(&entry->lock);
out:
- unpin_inotify_watch(&chunk->watch);
+ fsnotify_put_mark(entry);
spin_lock(&hash_lock);
}
static int create_chunk(struct inode *inode, struct audit_tree *tree)
{
+ struct fsnotify_mark_entry *entry;
struct audit_chunk *chunk = alloc_chunk(1);
if (!chunk)
return -ENOMEM;
- if (inotify_add_watch(rtree_ih, &chunk->watch, inode, IN_IGNORED | IN_DELETE_SELF) < 0) {
+ entry = &chunk->mark;
+ if (fsnotify_add_mark(entry, audit_tree_group, inode, 0)) {
free_chunk(chunk);
return -ENOSPC;
}
- mutex_lock(&inode->inotify_mutex);
+ spin_lock(&entry->lock);
spin_lock(&hash_lock);
if (tree->goner) {
spin_unlock(&hash_lock);
chunk->dead = 1;
- inotify_evict_watch(&chunk->watch);
- mutex_unlock(&inode->inotify_mutex);
- put_inotify_watch(&chunk->watch);
+ spin_unlock(&entry->lock);
+ fsnotify_destroy_mark_by_entry(entry);
+ fsnotify_put_mark(entry);
return 0;
}
chunk->owners[0].index = (1U << 31);
@@ -350,30 +346,33 @@ static int create_chunk(struct inode *inode, struct audit_tree *tree)
}
insert_hash(chunk);
spin_unlock(&hash_lock);
- mutex_unlock(&inode->inotify_mutex);
+ spin_unlock(&entry->lock);
return 0;
}
/* the first tagged inode becomes root of tree */
static int tag_chunk(struct inode *inode, struct audit_tree *tree)
{
- struct inotify_watch *watch;
+ struct fsnotify_mark_entry *old_entry, *chunk_entry;
struct audit_tree *owner;
struct audit_chunk *chunk, *old;
struct node *p;
int n;
- if (inotify_find_watch(rtree_ih, inode, &watch) < 0)
+ spin_lock(&inode->i_lock);
+ old_entry = fsnotify_find_mark_entry(audit_tree_group, inode);
+ spin_unlock(&inode->i_lock);
+ if (!old_entry)
return create_chunk(inode, tree);
- old = container_of(watch, struct audit_chunk, watch);
+ old = container_of(old_entry, struct audit_chunk, mark);
/* are we already there? */
spin_lock(&hash_lock);
for (n = 0; n < old->count; n++) {
if (old->owners[n].owner == tree) {
spin_unlock(&hash_lock);
- put_inotify_watch(watch);
+ fsnotify_put_mark(old_entry);
return 0;
}
}
@@ -382,22 +381,40 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
chunk = alloc_chunk(old->count + 1);
if (!chunk)
return -ENOMEM;
+ chunk_entry = &chunk->mark;
- mutex_lock(&inode->inotify_mutex);
- if (inotify_clone_watch(&old->watch, &chunk->watch) < 0) {
- mutex_unlock(&inode->inotify_mutex);
- put_inotify_watch(&old->watch);
+ spin_lock(&old_entry->lock);
+ if (!old_entry->i.inode) {
+ /* old_entry is being shot, lets just lie */
+ spin_unlock(&old_entry->lock);
+ fsnotify_put_mark(old_entry);
free_chunk(chunk);
+ return -ENOENT;
+ }
+
+ fsnotify_duplicate_mark(chunk_entry, old_entry);
+ if (fsnotify_add_mark(chunk_entry, chunk_entry->group, chunk_entry->i.inode, 1)) {
+ spin_unlock(&old_entry->lock);
+ free_chunk(chunk);
+ fsnotify_put_mark(old_entry);
return -ENOSPC;
}
+
+ /* even though we hold old_entry->lock, this is safe since chunk_entry->lock could NEVER have been grabbed before */
+ spin_lock(&chunk_entry->lock);
spin_lock(&hash_lock);
+
+ /* we now hold old_entry->lock, chunk_entry->lock, and hash_lock */
if (tree->goner) {
spin_unlock(&hash_lock);
chunk->dead = 1;
- inotify_evict_watch(&chunk->watch);
- mutex_unlock(&inode->inotify_mutex);
- put_inotify_watch(&old->watch);
- put_inotify_watch(&chunk->watch);
+ spin_unlock(&chunk_entry->lock);
+ spin_unlock(&old_entry->lock);
+
+ fsnotify_destroy_mark_by_entry(chunk_entry);
+
+ fsnotify_put_mark(chunk_entry);
+ fsnotify_put_mark(old_entry);
return 0;
}
list_replace_init(&old->trees, &chunk->trees);
@@ -423,9 +440,10 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
list_add(&tree->same_root, &chunk->trees);
}
spin_unlock(&hash_lock);
- inotify_evict_watch(&old->watch);
- mutex_unlock(&inode->inotify_mutex);
- put_inotify_watch(&old->watch);
+ spin_unlock(&chunk_entry->lock);
+ spin_unlock(&old_entry->lock);
+ fsnotify_destroy_mark_by_entry(old_entry);
+ fsnotify_put_mark(old_entry);
return 0;
}
@@ -578,7 +596,8 @@ void audit_trim_trees(void)
spin_lock(&hash_lock);
list_for_each_entry(node, &tree->chunks, list) {
struct audit_chunk *chunk = find_chunk(node);
- struct inode *inode = chunk->watch.inode;
+ /* this could be NULL if the watch is dieing else where... */
+ struct inode *inode = chunk->mark.i.inode;
struct vfsmount *mnt;
node->index |= 1U<<31;
list_for_each_entry(mnt, &list, mnt_list) {
@@ -925,34 +944,41 @@ static void evict_chunk(struct audit_chunk *chunk)
mutex_unlock(&audit_filter_mutex);
}
-static void handle_event(struct inotify_watch *watch, u32 wd, u32 mask,
- u32 cookie, const char *dname, struct inode *inode)
+static int audit_tree_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
{
- struct audit_chunk *chunk = container_of(watch, struct audit_chunk, watch);
+ BUG();
+ return -EOPNOTSUPP;
+}
- if (mask & IN_IGNORED) {
- evict_chunk(chunk);
- put_inotify_watch(watch);
- }
+static void audit_tree_freeing_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group)
+{
+ struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark);
+
+ evict_chunk(chunk);
+ fsnotify_put_mark(entry);
}
-static void destroy_watch(struct inotify_watch *watch)
+static bool audit_tree_send_event(struct fsnotify_group *group, struct inode *inode,
+ struct vfsmount *mnt, __u32 mask, void *data,
+ int data_type)
{
- struct audit_chunk *chunk = container_of(watch, struct audit_chunk, watch);
- call_rcu(&chunk->head, __put_chunk);
+ return 0;
}
-static const struct inotify_operations rtree_inotify_ops = {
- .handle_event = handle_event,
- .destroy_watch = destroy_watch,
+static const struct fsnotify_ops audit_tree_ops = {
+ .handle_event = audit_tree_handle_event,
+ .should_send_event = audit_tree_send_event,
+ .free_group_priv = NULL,
+ .free_event_priv = NULL,
+ .freeing_mark = audit_tree_freeing_mark,
};
static int __init audit_tree_init(void)
{
int i;
- rtree_ih = inotify_init(&rtree_inotify_ops);
- if (IS_ERR(rtree_ih))
+ audit_tree_group = fsnotify_alloc_group(&audit_tree_ops);
+ if (IS_ERR(audit_tree_group))
audit_panic("cannot initialize inotify handle for rectree watches");
for (i = 0; i < HASH_SIZE; i++)
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index cc7e87936cbc..ab8a5b3b07ef 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -24,17 +24,17 @@
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/fs.h>
+#include <linux/fsnotify_backend.h>
#include <linux/namei.h>
#include <linux/netlink.h>
#include <linux/sched.h>
-#include <linux/inotify.h>
#include <linux/security.h>
#include "audit.h"
/*
* Reference counting:
*
- * audit_parent: lifetime is from audit_init_parent() to receipt of an IN_IGNORED
+ * audit_parent: lifetime is from audit_init_parent() to receipt of an FS_IGNORED
* event. Each audit_watch holds a reference to its associated parent.
*
* audit_watch: if added to lists, lifetime is from audit_init_watch() to
@@ -50,40 +50,64 @@ struct audit_watch {
unsigned long ino; /* associated inode number */
struct audit_parent *parent; /* associated parent */
struct list_head wlist; /* entry in parent->watches list */
- struct list_head rules; /* associated rules */
+ struct list_head rules; /* anchor for krule->rlist */
};
struct audit_parent {
- struct list_head ilist; /* entry in inotify registration list */
- struct list_head watches; /* associated watches */
- struct inotify_watch wdata; /* inotify watch data */
- unsigned flags; /* status flags */
+ struct list_head watches; /* anchor for audit_watch->wlist */
+ struct fsnotify_mark_entry mark; /* fsnotify mark on the inode */
};
-/* Inotify handle. */
-struct inotify_handle *audit_ih;
+/* fsnotify handle. */
+struct fsnotify_group *audit_watch_group;
-/*
- * audit_parent status flags:
- *
- * AUDIT_PARENT_INVALID - set anytime rules/watches are auto-removed due to
- * a filesystem event to ensure we're adding audit watches to a valid parent.
- * Technically not needed for IN_DELETE_SELF or IN_UNMOUNT events, as we cannot
- * receive them while we have nameidata, but must be used for IN_MOVE_SELF which
- * we can receive while holding nameidata.
- */
-#define AUDIT_PARENT_INVALID 0x001
+/* fsnotify events we care about. */
+#define AUDIT_FS_WATCH (FS_MOVE | FS_CREATE | FS_DELETE | FS_DELETE_SELF |\
+ FS_MOVE_SELF | FS_EVENT_ON_CHILD)
-/* Inotify events we care about. */
-#define AUDIT_IN_WATCH IN_MOVE|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF
+static void audit_free_parent(struct audit_parent *parent)
+{
+ WARN_ON(!list_empty(&parent->watches));
+ kfree(parent);
+}
-static void audit_free_parent(struct inotify_watch *i_watch)
+static void audit_watch_free_mark(struct fsnotify_mark_entry *entry)
{
struct audit_parent *parent;
- parent = container_of(i_watch, struct audit_parent, wdata);
- WARN_ON(!list_empty(&parent->watches));
- kfree(parent);
+ parent = container_of(entry, struct audit_parent, mark);
+ audit_free_parent(parent);
+}
+
+static void audit_get_parent(struct audit_parent *parent)
+{
+ if (likely(parent))
+ fsnotify_get_mark(&parent->mark);
+}
+
+static void audit_put_parent(struct audit_parent *parent)
+{
+ if (likely(parent))
+ fsnotify_put_mark(&parent->mark);
+}
+
+/*
+ * Find and return the audit_parent on the given inode. If found a reference
+ * is taken on this parent.
+ */
+static inline struct audit_parent *audit_find_parent(struct inode *inode)
+{
+ struct audit_parent *parent = NULL;
+ struct fsnotify_mark_entry *entry;
+
+ spin_lock(&inode->i_lock);
+ entry = fsnotify_find_mark_entry(audit_watch_group, inode);
+ spin_unlock(&inode->i_lock);
+
+ if (entry)
+ parent = container_of(entry, struct audit_parent, mark);
+
+ return parent;
}
void audit_get_watch(struct audit_watch *watch)
@@ -104,7 +128,7 @@ void audit_put_watch(struct audit_watch *watch)
void audit_remove_watch(struct audit_watch *watch)
{
list_del(&watch->wlist);
- put_inotify_watch(&watch->parent->wdata);
+ audit_put_parent(watch->parent);
watch->parent = NULL;
audit_put_watch(watch); /* match initial get */
}
@@ -114,44 +138,36 @@ char *audit_watch_path(struct audit_watch *watch)
return watch->path;
}
-struct list_head *audit_watch_rules(struct audit_watch *watch)
+int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
{
- return &watch->rules;
-}
-
-unsigned long audit_watch_inode(struct audit_watch *watch)
-{
- return watch->ino;
-}
-
-dev_t audit_watch_dev(struct audit_watch *watch)
-{
- return watch->dev;
+ return (watch->ino != (unsigned long)-1) &&
+ (watch->ino == ino) &&
+ (watch->dev == dev);
}
/* Initialize a parent watch entry. */
static struct audit_parent *audit_init_parent(struct nameidata *ndp)
{
+ struct inode *inode = ndp->path.dentry->d_inode;
struct audit_parent *parent;
- s32 wd;
+ int ret;
parent = kzalloc(sizeof(*parent), GFP_KERNEL);
if (unlikely(!parent))
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&parent->watches);
- parent->flags = 0;
-
- inotify_init_watch(&parent->wdata);
- /* grab a ref so inotify watch hangs around until we take audit_filter_mutex */
- get_inotify_watch(&parent->wdata);
- wd = inotify_add_watch(audit_ih, &parent->wdata,
- ndp->path.dentry->d_inode, AUDIT_IN_WATCH);
- if (wd < 0) {
- audit_free_parent(&parent->wdata);
- return ERR_PTR(wd);
+
+ fsnotify_init_mark(&parent->mark, audit_watch_free_mark);
+ parent->mark.mask = AUDIT_FS_WATCH;
+ ret = fsnotify_add_mark(&parent->mark, audit_watch_group, inode, 0);
+ if (ret < 0) {
+ audit_free_parent(parent);
+ return ERR_PTR(ret);
}
+ fsnotify_recalc_group_mask(audit_watch_group);
+
return parent;
}
@@ -178,7 +194,7 @@ int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op)
{
struct audit_watch *watch;
- if (!audit_ih)
+ if (!audit_watch_group)
return -EOPNOTSUPP;
if (path[0] != '/' || path[len-1] == '/' ||
@@ -216,7 +232,7 @@ static struct audit_watch *audit_dupe_watch(struct audit_watch *old)
new->dev = old->dev;
new->ino = old->ino;
- get_inotify_watch(&old->parent->wdata);
+ audit_get_parent(old->parent);
new->parent = old->parent;
out:
@@ -250,15 +266,19 @@ static void audit_update_watch(struct audit_parent *parent,
struct audit_entry *oentry, *nentry;
mutex_lock(&audit_filter_mutex);
+ /* Run all of the watches on this parent looking for the one that
+ * matches the given dname */
list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
if (audit_compare_dname_path(dname, owatch->path, NULL))
continue;
/* If the update involves invalidating rules, do the inode-based
* filtering now, so we don't omit records. */
- if (invalidating && current->audit_context)
+ if (invalidating && !audit_dummy_context())
audit_filter_inodes(current, current->audit_context);
+ /* updating ino will likely change which audit_hash_list we
+ * are on so we need a new watch for the new list */
nwatch = audit_dupe_watch(owatch);
if (IS_ERR(nwatch)) {
mutex_unlock(&audit_filter_mutex);
@@ -274,12 +294,21 @@ static void audit_update_watch(struct audit_parent *parent,
list_del(&oentry->rule.rlist);
list_del_rcu(&oentry->list);
- nentry = audit_dupe_rule(&oentry->rule, nwatch);
+ nentry = audit_dupe_rule(&oentry->rule);
if (IS_ERR(nentry)) {
list_del(&oentry->rule.list);
audit_panic("error updating watch, removing");
} else {
int h = audit_hash_ino((u32)ino);
+
+ /*
+ * nentry->rule.watch == oentry->rule.watch so
+ * we must drop that reference and set it to our
+ * new watch.
+ */
+ audit_put_watch(nentry->rule.watch);
+ audit_get_watch(nwatch);
+ nentry->rule.watch = nwatch;
list_add(&nentry->rule.rlist, &nwatch->rules);
list_add_rcu(&nentry->list, &audit_inode_hash[h]);
list_replace(&oentry->rule.list,
@@ -311,7 +340,6 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
struct audit_entry *e;
mutex_lock(&audit_filter_mutex);
- parent->flags |= AUDIT_PARENT_INVALID;
list_for_each_entry_safe(w, nextw, &parent->watches, wlist) {
list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
e = container_of(r, struct audit_entry, rule);
@@ -324,20 +352,11 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
audit_remove_watch(w);
}
mutex_unlock(&audit_filter_mutex);
-}
-/* Unregister inotify watches for parents on in_list.
- * Generates an IN_IGNORED event. */
-void audit_inotify_unregister(struct list_head *in_list)
-{
- struct audit_parent *p, *n;
+ fsnotify_destroy_mark_by_entry(&parent->mark);
+
+ fsnotify_recalc_group_mask(audit_watch_group);
- list_for_each_entry_safe(p, n, in_list, ilist) {
- list_del(&p->ilist);
- inotify_rm_watch(audit_ih, &p->wdata);
- /* the unpin matching the pin in audit_do_del_rule() */
- unpin_inotify_watch(&p->wdata);
- }
}
/* Get path information necessary for adding watches. */
@@ -388,7 +407,7 @@ static void audit_put_nd(struct nameidata *ndp, struct nameidata *ndw)
}
}
-/* Associate the given rule with an existing parent inotify_watch.
+/* Associate the given rule with an existing parent.
* Caller must hold audit_filter_mutex. */
static void audit_add_to_parent(struct audit_krule *krule,
struct audit_parent *parent)
@@ -396,6 +415,8 @@ static void audit_add_to_parent(struct audit_krule *krule,
struct audit_watch *w, *watch = krule->watch;
int watch_found = 0;
+ BUG_ON(!mutex_is_locked(&audit_filter_mutex));
+
list_for_each_entry(w, &parent->watches, wlist) {
if (strcmp(watch->path, w->path))
continue;
@@ -412,7 +433,7 @@ static void audit_add_to_parent(struct audit_krule *krule,
}
if (!watch_found) {
- get_inotify_watch(&parent->wdata);
+ audit_get_parent(parent);
watch->parent = parent;
list_add(&watch->wlist, &parent->watches);
@@ -422,13 +443,12 @@ static void audit_add_to_parent(struct audit_krule *krule,
/* Find a matching watch entry, or add this one.
* Caller must hold audit_filter_mutex. */
-int audit_add_watch(struct audit_krule *krule)
+int audit_add_watch(struct audit_krule *krule, struct list_head **list)
{
struct audit_watch *watch = krule->watch;
- struct inotify_watch *i_watch;
struct audit_parent *parent;
struct nameidata *ndp = NULL, *ndw = NULL;
- int ret = 0;
+ int h, ret = 0;
mutex_unlock(&audit_filter_mutex);
@@ -440,47 +460,38 @@ int audit_add_watch(struct audit_krule *krule)
goto error;
}
+ mutex_lock(&audit_filter_mutex);
+
/* update watch filter fields */
if (ndw) {
watch->dev = ndw->path.dentry->d_inode->i_sb->s_dev;
watch->ino = ndw->path.dentry->d_inode->i_ino;
}
- /* The audit_filter_mutex must not be held during inotify calls because
- * we hold it during inotify event callback processing. If an existing
- * inotify watch is found, inotify_find_watch() grabs a reference before
- * returning.
- */
- if (inotify_find_watch(audit_ih, ndp->path.dentry->d_inode,
- &i_watch) < 0) {
+ /* either find an old parent or attach a new one */
+ parent = audit_find_parent(ndp->path.dentry->d_inode);
+ if (!parent) {
parent = audit_init_parent(ndp);
if (IS_ERR(parent)) {
- /* caller expects mutex locked */
- mutex_lock(&audit_filter_mutex);
ret = PTR_ERR(parent);
goto error;
}
- } else
- parent = container_of(i_watch, struct audit_parent, wdata);
-
- mutex_lock(&audit_filter_mutex);
+ }
- /* parent was moved before we took audit_filter_mutex */
- if (parent->flags & AUDIT_PARENT_INVALID)
- ret = -ENOENT;
- else
- audit_add_to_parent(krule, parent);
+ audit_add_to_parent(krule, parent);
- /* match get in audit_init_parent or inotify_find_watch */
- put_inotify_watch(&parent->wdata);
+ /* match get in audit_find_parent or audit_init_parent */
+ audit_put_parent(parent);
+ h = audit_hash_ino((u32)watch->ino);
+ *list = &audit_inode_hash[h];
error:
audit_put_nd(ndp, ndw); /* NULL args OK */
return ret;
}
-void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list)
+void audit_remove_watch_rule(struct audit_krule *krule)
{
struct audit_watch *watch = krule->watch;
struct audit_parent *parent = watch->parent;
@@ -491,53 +502,94 @@ void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list)
audit_remove_watch(watch);
if (list_empty(&parent->watches)) {
- /* Put parent on the inotify un-registration
- * list. Grab a reference before releasing
- * audit_filter_mutex, to be released in
- * audit_inotify_unregister().
- * If filesystem is going away, just leave
- * the sucker alone, eviction will take
- * care of it. */
- if (pin_inotify_watch(&parent->wdata))
- list_add(&parent->ilist, list);
+ audit_get_parent(parent);
+ fsnotify_destroy_mark_by_entry(&parent->mark);
+ audit_put_parent(parent);
}
}
+
+ fsnotify_recalc_group_mask(audit_watch_group);
+
}
-/* Update watch data in audit rules based on inotify events. */
-static void audit_handle_ievent(struct inotify_watch *i_watch, u32 wd, u32 mask,
- u32 cookie, const char *dname, struct inode *inode)
+static bool audit_watch_should_send_event(struct fsnotify_group *group, struct inode *inode,
+ struct vfsmount *mnt, __u32 mask, void *data,
+ int data_type)
{
+ struct fsnotify_mark_entry *entry;
+ bool send;
+
+ spin_lock(&inode->i_lock);
+ entry = fsnotify_find_mark_entry(group, inode);
+ spin_unlock(&inode->i_lock);
+ if (!entry)
+ return false;
+
+ mask = (mask & ~FS_EVENT_ON_CHILD);
+ send = (entry->mask & mask);
+
+ /* find took a reference */
+ fsnotify_put_mark(entry);
+
+ return send;
+}
+
+/* Update watch data in audit rules based on fsnotify events. */
+static int audit_watch_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
+{
+ struct inode *inode;
+ __u32 mask = event->mask;
+ const char *dname = event->file_name;
struct audit_parent *parent;
- parent = container_of(i_watch, struct audit_parent, wdata);
+ BUG_ON(group != audit_watch_group);
- if (mask & (IN_CREATE|IN_MOVED_TO) && inode)
- audit_update_watch(parent, dname, inode->i_sb->s_dev,
- inode->i_ino, 0);
- else if (mask & (IN_DELETE|IN_MOVED_FROM))
+ parent = audit_find_parent(event->to_tell);
+ if (unlikely(!parent))
+ return 0;
+
+ switch (event->data_type) {
+ case (FSNOTIFY_EVENT_PATH):
+ inode = event->path.dentry->d_inode;
+ break;
+ case (FSNOTIFY_EVENT_INODE):
+ inode = event->inode;
+ break;
+ default:
+ BUG();
+ inode = NULL;
+ break;
+ };
+
+ if (mask & (FS_CREATE|FS_MOVED_TO) && inode)
+ audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0);
+ else if (mask & (FS_DELETE|FS_MOVED_FROM))
audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1, 1);
- /* inotify automatically removes the watch and sends IN_IGNORED */
- else if (mask & (IN_DELETE_SELF|IN_UNMOUNT))
+ else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
audit_remove_parent_watches(parent);
- /* inotify does not remove the watch, so remove it manually */
- else if(mask & IN_MOVE_SELF) {
- audit_remove_parent_watches(parent);
- inotify_remove_watch_locked(audit_ih, i_watch);
- } else if (mask & IN_IGNORED)
- put_inotify_watch(i_watch);
+ /* moved put_inotify_watch to freeing mark */
+
+ /* matched the ref taken by audit_find_parent */
+ audit_put_parent(parent);
+
+ return 0;
}
-static const struct inotify_operations audit_inotify_ops = {
- .handle_event = audit_handle_ievent,
- .destroy_watch = audit_free_parent,
+static const struct fsnotify_ops audit_watch_fsnotify_ops = {
+ .should_send_event = audit_watch_should_send_event,
+ .handle_event = audit_watch_handle_event,
+ .free_group_priv = NULL,
+ .freeing_mark = NULL,
+ .free_event_priv = NULL,
};
static int __init audit_watch_init(void)
{
- audit_ih = inotify_init(&audit_inotify_ops);
- if (IS_ERR(audit_ih))
- audit_panic("cannot initialize inotify handle");
+ audit_watch_group = fsnotify_alloc_group(&audit_watch_fsnotify_ops);
+ if (IS_ERR(audit_watch_group)) {
+ audit_watch_group = NULL;
+ audit_panic("cannot create audit fsnotify group");
+ }
return 0;
}
-subsys_initcall(audit_watch_init);
+device_initcall(audit_watch_init);
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index a70604047f3c..f5e4cae5ad82 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -70,6 +70,7 @@ static inline void audit_free_rule(struct audit_entry *e)
{
int i;
struct audit_krule *erule = &e->rule;
+
/* some rules don't have associated watches */
if (erule->watch)
audit_put_watch(erule->watch);
@@ -745,8 +746,7 @@ static inline int audit_dupe_lsm_field(struct audit_field *df,
* rule with the new rule in the filterlist, then free the old rule.
* The rlist element is undefined; list manipulations are handled apart from
* the initial copy. */
-struct audit_entry *audit_dupe_rule(struct audit_krule *old,
- struct audit_watch *watch)
+struct audit_entry *audit_dupe_rule(struct audit_krule *old)
{
u32 fcount = old->field_count;
struct audit_entry *entry;
@@ -768,8 +768,8 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old,
new->prio = old->prio;
new->buflen = old->buflen;
new->inode_f = old->inode_f;
- new->watch = NULL;
new->field_count = old->field_count;
+
/*
* note that we are OK with not refcounting here; audit_match_tree()
* never dereferences tree and we can't get false positives there
@@ -810,9 +810,9 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old,
}
}
- if (watch) {
- audit_get_watch(watch);
- new->watch = watch;
+ if (old->watch) {
+ audit_get_watch(old->watch);
+ new->watch = old->watch;
}
return entry;
@@ -865,7 +865,7 @@ static inline int audit_add_rule(struct audit_entry *entry)
struct audit_watch *watch = entry->rule.watch;
struct audit_tree *tree = entry->rule.tree;
struct list_head *list;
- int h, err;
+ int err;
#ifdef CONFIG_AUDITSYSCALL
int dont_count = 0;
@@ -888,15 +888,11 @@ static inline int audit_add_rule(struct audit_entry *entry)
if (watch) {
/* audit_filter_mutex is dropped and re-taken during this call */
- err = audit_add_watch(&entry->rule);
+ err = audit_add_watch(&entry->rule, &list);
if (err) {
mutex_unlock(&audit_filter_mutex);
goto error;
}
- /* entry->rule.watch may have changed during audit_add_watch() */
- watch = entry->rule.watch;
- h = audit_hash_ino((u32)audit_watch_inode(watch));
- list = &audit_inode_hash[h];
}
if (tree) {
err = audit_add_tree_rule(&entry->rule);
@@ -948,7 +944,6 @@ static inline int audit_del_rule(struct audit_entry *entry)
struct audit_watch *watch = entry->rule.watch;
struct audit_tree *tree = entry->rule.tree;
struct list_head *list;
- LIST_HEAD(inotify_list);
int ret = 0;
#ifdef CONFIG_AUDITSYSCALL
int dont_count = 0;
@@ -968,7 +963,7 @@ static inline int audit_del_rule(struct audit_entry *entry)
}
if (e->rule.watch)
- audit_remove_watch_rule(&e->rule, &inotify_list);
+ audit_remove_watch_rule(&e->rule);
if (e->rule.tree)
audit_remove_tree_rule(&e->rule);
@@ -986,9 +981,6 @@ static inline int audit_del_rule(struct audit_entry *entry)
#endif
mutex_unlock(&audit_filter_mutex);
- if (!list_empty(&inotify_list))
- audit_inotify_unregister(&inotify_list);
-
out:
if (watch)
audit_put_watch(watch); /* match initial get */
@@ -1322,30 +1314,23 @@ static int update_lsm_rule(struct audit_krule *r)
{
struct audit_entry *entry = container_of(r, struct audit_entry, rule);
struct audit_entry *nentry;
- struct audit_watch *watch;
- struct audit_tree *tree;
int err = 0;
if (!security_audit_rule_known(r))
return 0;
- watch = r->watch;
- tree = r->tree;
- nentry = audit_dupe_rule(r, watch);
+ nentry = audit_dupe_rule(r);
if (IS_ERR(nentry)) {
/* save the first error encountered for the
* return value */
err = PTR_ERR(nentry);
audit_panic("error updating LSM filters");
- if (watch)
+ if (r->watch)
list_del(&r->rlist);
list_del_rcu(&entry->list);
list_del(&r->list);
} else {
- if (watch) {
- list_add(&nentry->rule.rlist, audit_watch_rules(watch));
- list_del(&r->rlist);
- } else if (tree)
+ if (r->watch || r->tree)
list_replace_init(&r->rlist, &nentry->rule.rlist);
list_replace_rcu(&entry->list, &nentry->list);
list_replace(&r->list, &nentry->rule.list);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 267e484f0198..ef0410c3c355 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -549,9 +549,8 @@ static int audit_filter_rules(struct task_struct *tsk,
}
break;
case AUDIT_WATCH:
- if (name && audit_watch_inode(rule->watch) != (unsigned long)-1)
- result = (name->dev == audit_watch_dev(rule->watch) &&
- name->ino == audit_watch_inode(rule->watch));
+ if (name)
+ result = audit_watch_compare(rule->watch, name->ino, name->dev);
break;
case AUDIT_DIR:
if (ctx)
@@ -1726,7 +1725,7 @@ static inline void handle_one(const struct inode *inode)
struct audit_tree_refs *p;
struct audit_chunk *chunk;
int count;
- if (likely(list_empty(&inode->inotify_watches)))
+ if (likely(hlist_empty(&inode->i_fsnotify_mark_entries)))
return;
context = current->audit_context;
p = context->trees;
@@ -1769,7 +1768,7 @@ retry:
seq = read_seqbegin(&rename_lock);
for(;;) {
struct inode *inode = d->d_inode;
- if (inode && unlikely(!list_empty(&inode->inotify_watches))) {
+ if (inode && unlikely(!hlist_empty(&inode->i_fsnotify_mark_entries))) {
struct audit_chunk *chunk;
chunk = audit_tree_lookup(inode);
if (chunk) {
diff --git a/kernel/bounds.c b/kernel/bounds.c
index 3c5301381837..98a51f26c136 100644
--- a/kernel/bounds.c
+++ b/kernel/bounds.c
@@ -12,7 +12,7 @@
void foo(void)
{
- /* The enum constants to put into include/linux/bounds.h */
+ /* The enum constants to put into include/generated/bounds.h */
DEFINE(NR_PAGEFLAGS, __NR_PAGEFLAGS);
DEFINE(MAX_NR_ZONES, __MAX_NR_ZONES);
/* End of constants */
diff --git a/kernel/capability.c b/kernel/capability.c
index 4e17041963f5..c2316d3fa094 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -238,7 +238,7 @@ SYSCALL_DEFINE2(capget, cap_user_header_t, header, cap_user_data_t, dataptr)
SYSCALL_DEFINE2(capset, cap_user_header_t, header, const cap_user_data_t, data)
{
struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S];
- unsigned i, tocopy;
+ unsigned i, tocopy, copybytes;
kernel_cap_t inheritable, permitted, effective;
struct cred *new;
int ret;
@@ -255,8 +255,11 @@ SYSCALL_DEFINE2(capset, cap_user_header_t, header, const cap_user_data_t, data)
if (pid != 0 && pid != task_pid_vnr(current))
return -EPERM;
- if (copy_from_user(&kdata, data,
- tocopy * sizeof(struct __user_cap_data_struct)))
+ copybytes = tocopy * sizeof(struct __user_cap_data_struct);
+ if (copybytes > sizeof(kdata))
+ return -EFAULT;
+
+ if (copy_from_user(&kdata, data, copybytes))
return -EFAULT;
for (i = 0; i < tocopy; i++) {
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index b5cb469d2545..d247381e7371 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -2537,15 +2537,9 @@ const struct file_operations proc_cpuset_operations = {
};
#endif /* CONFIG_PROC_PID_CPUSET */
-/* Display task cpus_allowed, mems_allowed in /proc/<pid>/status file. */
+/* Display task mems_allowed in /proc/<pid>/status file. */
void cpuset_task_status_allowed(struct seq_file *m, struct task_struct *task)
{
- seq_printf(m, "Cpus_allowed:\t");
- seq_cpumask(m, &task->cpus_allowed);
- seq_printf(m, "\n");
- seq_printf(m, "Cpus_allowed_list:\t");
- seq_cpumask_list(m, &task->cpus_allowed);
- seq_printf(m, "\n");
seq_printf(m, "Mems_allowed:\t");
seq_nodemask(m, &task->mems_allowed);
seq_printf(m, "\n");
diff --git a/kernel/futex.c b/kernel/futex.c
index 4949d336d88d..642f3bbaacc7 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -150,7 +150,8 @@ static struct futex_hash_bucket *hash_futex(union futex_key *key)
*/
static inline int match_futex(union futex_key *key1, union futex_key *key2)
{
- return (key1->both.word == key2->both.word
+ return (key1 && key2
+ && key1->both.word == key2->both.word
&& key1->both.ptr == key2->both.ptr
&& key1->both.offset == key2->both.offset);
}
@@ -1028,7 +1029,6 @@ static inline
void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key,
struct futex_hash_bucket *hb)
{
- drop_futex_key_refs(&q->key);
get_futex_key_refs(key);
q->key = *key;
@@ -1226,6 +1226,7 @@ retry_private:
*/
if (ret == 1) {
WARN_ON(pi_state);
+ drop_count++;
task_count++;
ret = get_futex_value_locked(&curval2, uaddr2);
if (!ret)
@@ -1304,6 +1305,7 @@ retry_private:
if (ret == 1) {
/* We got the lock. */
requeue_pi_wake_futex(this, &key2, hb2);
+ drop_count++;
continue;
} else if (ret) {
/* -EDEADLK */
@@ -1791,6 +1793,7 @@ static int futex_wait(u32 __user *uaddr, int fshared,
current->timer_slack_ns);
}
+retry:
/* Prepare to wait on uaddr. */
ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
if (ret)
@@ -1808,9 +1811,14 @@ static int futex_wait(u32 __user *uaddr, int fshared,
goto out_put_key;
/*
- * We expect signal_pending(current), but another thread may
- * have handled it for us already.
+ * We expect signal_pending(current), but we might be the
+ * victim of a spurious wakeup as well.
*/
+ if (!signal_pending(current)) {
+ put_futex_key(fshared, &q.key);
+ goto retry;
+ }
+
ret = -ERESTARTSYS;
if (!abs_time)
goto out_put_key;
@@ -2118,9 +2126,11 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
*/
plist_del(&q->list, &q->list.plist);
+ /* Handle spurious wakeups gracefully */
+ ret = -EAGAIN;
if (timeout && !timeout->task)
ret = -ETIMEDOUT;
- else
+ else if (signal_pending(current))
ret = -ERESTARTNOINTR;
}
return ret;
@@ -2198,6 +2208,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
debug_rt_mutex_init_waiter(&rt_waiter);
rt_waiter.task = NULL;
+retry:
key2 = FUTEX_KEY_INIT;
ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE);
if (unlikely(ret != 0))
@@ -2292,6 +2303,9 @@ out_put_keys:
out_key2:
put_futex_key(fshared, &key2);
+ /* Spurious wakeup ? */
+ if (ret == -EAGAIN)
+ goto retry;
out:
if (to) {
hrtimer_cancel(&to->timer);
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index bde4c667d24d..7305b297d1eb 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -1067,7 +1067,7 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
kfree(action);
#ifdef CONFIG_DEBUG_SHIRQ
- if (irqflags & IRQF_SHARED) {
+ if (!retval && (irqflags & IRQF_SHARED)) {
/*
* It's a shared IRQ -- the driver ought to be prepared for it
* to happen immediately, so let's make sure....
diff --git a/kernel/kexec.c b/kernel/kexec.c
index f336e2107f98..83f54e2a6eed 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -21,7 +21,7 @@
#include <linux/hardirq.h>
#include <linux/elf.h>
#include <linux/elfcore.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
#include <linux/utsname.h>
#include <linux/numa.h>
#include <linux/suspend.h>
diff --git a/kernel/kgdb.c b/kernel/kgdb.c
index 9147a3190c9d..609cbdef5a71 100644
--- a/kernel/kgdb.c
+++ b/kernel/kgdb.c
@@ -129,6 +129,7 @@ struct task_struct *kgdb_usethread;
struct task_struct *kgdb_contthread;
int kgdb_single_step;
+pid_t kgdb_sstep_pid;
/* Our I/O buffers. */
static char remcom_in_buffer[BUFMAX];
@@ -541,12 +542,17 @@ static struct task_struct *getthread(struct pt_regs *regs, int tid)
*/
if (tid == 0 || tid == -1)
tid = -atomic_read(&kgdb_active) - 2;
- if (tid < 0) {
+ if (tid < -1 && tid > -NR_CPUS - 2) {
if (kgdb_info[-tid - 2].task)
return kgdb_info[-tid - 2].task;
else
return idle_task(-tid - 2);
}
+ if (tid <= 0) {
+ printk(KERN_ERR "KGDB: Internal thread select error\n");
+ dump_stack();
+ return NULL;
+ }
/*
* find_task_by_pid_ns() does not take the tasklist lock anymore
@@ -590,7 +596,7 @@ static void kgdb_wait(struct pt_regs *regs)
/* Signal the primary CPU that we are done: */
atomic_set(&cpu_in_kgdb[cpu], 0);
- touch_softlockup_watchdog();
+ touch_softlockup_watchdog_sync();
clocksource_touch_watchdog();
local_irq_restore(flags);
}
@@ -1204,8 +1210,10 @@ static int gdb_cmd_exception_pass(struct kgdb_state *ks)
return 1;
} else {
- error_packet(remcom_out_buffer, -EINVAL);
- return 0;
+ kgdb_msg_write("KGDB only knows signal 9 (pass)"
+ " and 15 (pass and disconnect)\n"
+ "Executing a continue without signal passing\n", 0);
+ remcom_in_buffer[0] = 'c';
}
/* Indicate fall through */
@@ -1430,10 +1438,10 @@ acquirelock:
* debugger on a different CPU via a single step
*/
if (atomic_read(&kgdb_cpu_doing_single_step) != -1 &&
- atomic_read(&kgdb_cpu_doing_single_step) != cpu) {
-
+ kgdb_info[cpu].task &&
+ kgdb_info[cpu].task->pid != kgdb_sstep_pid) {
atomic_set(&kgdb_active, -1);
- touch_softlockup_watchdog();
+ touch_softlockup_watchdog_sync();
clocksource_touch_watchdog();
local_irq_restore(flags);
@@ -1524,9 +1532,16 @@ acquirelock:
}
kgdb_restore:
+ if (atomic_read(&kgdb_cpu_doing_single_step) != -1) {
+ int sstep_cpu = atomic_read(&kgdb_cpu_doing_single_step);
+ if (kgdb_info[sstep_cpu].task)
+ kgdb_sstep_pid = kgdb_info[sstep_cpu].task->pid;
+ else
+ kgdb_sstep_pid = 0;
+ }
/* Free kgdb_active */
atomic_set(&kgdb_active, -1);
- touch_softlockup_watchdog();
+ touch_softlockup_watchdog_sync();
clocksource_touch_watchdog();
local_irq_restore(flags);
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 5240d75f4c60..84495958e703 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -90,6 +90,9 @@ static spinlock_t *kretprobe_table_lock_ptr(unsigned long hash)
*/
static struct kprobe_blackpoint kprobe_blacklist[] = {
{"preempt_schedule",},
+ {"native_get_debugreg",},
+ {"irq_entries_start",},
+ {"common_interrupt",},
{NULL} /* Terminator */
};
@@ -673,6 +676,40 @@ static kprobe_opcode_t __kprobes *kprobe_addr(struct kprobe *p)
return (kprobe_opcode_t *)(((char *)addr) + p->offset);
}
+/* Check passed kprobe is valid and return kprobe in kprobe_table. */
+static struct kprobe * __kprobes __get_valid_kprobe(struct kprobe *p)
+{
+ struct kprobe *old_p, *list_p;
+
+ old_p = get_kprobe(p->addr);
+ if (unlikely(!old_p))
+ return NULL;
+
+ if (p != old_p) {
+ list_for_each_entry_rcu(list_p, &old_p->list, list)
+ if (list_p == p)
+ /* kprobe p is a valid probe */
+ goto valid;
+ return NULL;
+ }
+valid:
+ return old_p;
+}
+
+/* Return error if the kprobe is being re-registered */
+static inline int check_kprobe_rereg(struct kprobe *p)
+{
+ int ret = 0;
+ struct kprobe *old_p;
+
+ mutex_lock(&kprobe_mutex);
+ old_p = __get_valid_kprobe(p);
+ if (old_p)
+ ret = -EINVAL;
+ mutex_unlock(&kprobe_mutex);
+ return ret;
+}
+
int __kprobes register_kprobe(struct kprobe *p)
{
int ret = 0;
@@ -685,6 +722,10 @@ int __kprobes register_kprobe(struct kprobe *p)
return -EINVAL;
p->addr = addr;
+ ret = check_kprobe_rereg(p);
+ if (ret)
+ return ret;
+
preempt_disable();
if (!kernel_text_address((unsigned long) p->addr) ||
in_kprobes_functions((unsigned long) p->addr)) {
@@ -754,26 +795,6 @@ out:
}
EXPORT_SYMBOL_GPL(register_kprobe);
-/* Check passed kprobe is valid and return kprobe in kprobe_table. */
-static struct kprobe * __kprobes __get_valid_kprobe(struct kprobe *p)
-{
- struct kprobe *old_p, *list_p;
-
- old_p = get_kprobe(p->addr);
- if (unlikely(!old_p))
- return NULL;
-
- if (p != old_p) {
- list_for_each_entry_rcu(list_p, &old_p->list, list)
- if (list_p == p)
- /* kprobe p is a valid probe */
- goto valid;
- return NULL;
- }
-valid:
- return old_p;
-}
-
/*
* Unregister a kprobe without a scheduler synchronization.
*/
@@ -1141,6 +1162,13 @@ static void __kprobes kill_kprobe(struct kprobe *p)
arch_remove_kprobe(p);
}
+void __kprobes dump_kprobe(struct kprobe *kp)
+{
+ printk(KERN_WARNING "Dumping kprobe:\n");
+ printk(KERN_WARNING "Name: %s\nAddress: %p\nOffset: %x\n",
+ kp->symbol_name, kp->addr, kp->offset);
+}
+
/* Module notifier call back, checking kprobes on the module */
static int __kprobes kprobes_module_callback(struct notifier_block *nb,
unsigned long val, void *data)
diff --git a/kernel/module.c b/kernel/module.c
index 8b7d8805819d..5a43807304ee 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -370,8 +370,6 @@ EXPORT_SYMBOL_GPL(find_module);
#ifdef CONFIG_SMP
-#ifndef CONFIG_HAVE_LEGACY_PER_CPU_AREA
-
static void *percpu_modalloc(unsigned long size, unsigned long align,
const char *name)
{
@@ -395,154 +393,6 @@ static void percpu_modfree(void *freeme)
free_percpu(freeme);
}
-#else /* ... CONFIG_HAVE_LEGACY_PER_CPU_AREA */
-
-/* Number of blocks used and allocated. */
-static unsigned int pcpu_num_used, pcpu_num_allocated;
-/* Size of each block. -ve means used. */
-static int *pcpu_size;
-
-static int split_block(unsigned int i, unsigned short size)
-{
- /* Reallocation required? */
- if (pcpu_num_used + 1 > pcpu_num_allocated) {
- int *new;
-
- new = krealloc(pcpu_size, sizeof(new[0])*pcpu_num_allocated*2,
- GFP_KERNEL);
- if (!new)
- return 0;
-
- pcpu_num_allocated *= 2;
- pcpu_size = new;
- }
-
- /* Insert a new subblock */
- memmove(&pcpu_size[i+1], &pcpu_size[i],
- sizeof(pcpu_size[0]) * (pcpu_num_used - i));
- pcpu_num_used++;
-
- pcpu_size[i+1] -= size;
- pcpu_size[i] = size;
- return 1;
-}
-
-static inline unsigned int block_size(int val)
-{
- if (val < 0)
- return -val;
- return val;
-}
-
-static void *percpu_modalloc(unsigned long size, unsigned long align,
- const char *name)
-{
- unsigned long extra;
- unsigned int i;
- void *ptr;
- int cpu;
-
- if (align > PAGE_SIZE) {
- printk(KERN_WARNING "%s: per-cpu alignment %li > %li\n",
- name, align, PAGE_SIZE);
- align = PAGE_SIZE;
- }
-
- ptr = __per_cpu_start;
- for (i = 0; i < pcpu_num_used; ptr += block_size(pcpu_size[i]), i++) {
- /* Extra for alignment requirement. */
- extra = ALIGN((unsigned long)ptr, align) - (unsigned long)ptr;
- BUG_ON(i == 0 && extra != 0);
-
- if (pcpu_size[i] < 0 || pcpu_size[i] < extra + size)
- continue;
-
- /* Transfer extra to previous block. */
- if (pcpu_size[i-1] < 0)
- pcpu_size[i-1] -= extra;
- else
- pcpu_size[i-1] += extra;
- pcpu_size[i] -= extra;
- ptr += extra;
-
- /* Split block if warranted */
- if (pcpu_size[i] - size > sizeof(unsigned long))
- if (!split_block(i, size))
- return NULL;
-
- /* add the per-cpu scanning areas */
- for_each_possible_cpu(cpu)
- kmemleak_alloc(ptr + per_cpu_offset(cpu), size, 0,
- GFP_KERNEL);
-
- /* Mark allocated */
- pcpu_size[i] = -pcpu_size[i];
- return ptr;
- }
-
- printk(KERN_WARNING "Could not allocate %lu bytes percpu data\n",
- size);
- return NULL;
-}
-
-static void percpu_modfree(void *freeme)
-{
- unsigned int i;
- void *ptr = __per_cpu_start + block_size(pcpu_size[0]);
- int cpu;
-
- /* First entry is core kernel percpu data. */
- for (i = 1; i < pcpu_num_used; ptr += block_size(pcpu_size[i]), i++) {
- if (ptr == freeme) {
- pcpu_size[i] = -pcpu_size[i];
- goto free;
- }
- }
- BUG();
-
- free:
- /* remove the per-cpu scanning areas */
- for_each_possible_cpu(cpu)
- kmemleak_free(freeme + per_cpu_offset(cpu));
-
- /* Merge with previous? */
- if (pcpu_size[i-1] >= 0) {
- pcpu_size[i-1] += pcpu_size[i];
- pcpu_num_used--;
- memmove(&pcpu_size[i], &pcpu_size[i+1],
- (pcpu_num_used - i) * sizeof(pcpu_size[0]));
- i--;
- }
- /* Merge with next? */
- if (i+1 < pcpu_num_used && pcpu_size[i+1] >= 0) {
- pcpu_size[i] += pcpu_size[i+1];
- pcpu_num_used--;
- memmove(&pcpu_size[i+1], &pcpu_size[i+2],
- (pcpu_num_used - (i+1)) * sizeof(pcpu_size[0]));
- }
-}
-
-static int percpu_modinit(void)
-{
- pcpu_num_used = 2;
- pcpu_num_allocated = 2;
- pcpu_size = kmalloc(sizeof(pcpu_size[0]) * pcpu_num_allocated,
- GFP_KERNEL);
- /* Static in-kernel percpu data (used). */
- pcpu_size[0] = -(__per_cpu_end-__per_cpu_start);
- /* Free room. */
- pcpu_size[1] = PERCPU_ENOUGH_ROOM + pcpu_size[0];
- if (pcpu_size[1] < 0) {
- printk(KERN_ERR "No per-cpu room for modules.\n");
- pcpu_num_used = 1;
- }
-
- return 0;
-}
-__initcall(percpu_modinit);
-
-#endif /* CONFIG_HAVE_LEGACY_PER_CPU_AREA */
-
static unsigned int find_pcpusec(Elf_Ehdr *hdr,
Elf_Shdr *sechdrs,
const char *secstrings)
@@ -2043,9 +1893,7 @@ static void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr,
unsigned int i;
/* only scan the sections containing data */
- kmemleak_scan_area(mod->module_core, (unsigned long)mod -
- (unsigned long)mod->module_core,
- sizeof(struct module), GFP_KERNEL);
+ kmemleak_scan_area(mod, sizeof(struct module), GFP_KERNEL);
for (i = 1; i < hdr->e_shnum; i++) {
if (!(sechdrs[i].sh_flags & SHF_ALLOC))
@@ -2054,8 +1902,7 @@ static void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr,
&& strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) != 0)
continue;
- kmemleak_scan_area(mod->module_core, sechdrs[i].sh_addr -
- (unsigned long)mod->module_core,
+ kmemleak_scan_area((void *)sechdrs[i].sh_addr,
sechdrs[i].sh_size, GFP_KERNEL);
}
}
@@ -2383,6 +2230,12 @@ static noinline struct module *load_module(void __user *umod,
"_ftrace_events",
sizeof(*mod->trace_events),
&mod->num_trace_events);
+ /*
+ * This section contains pointers to allocated objects in the trace
+ * code and not scanning it leads to false positives.
+ */
+ kmemleak_scan_area(mod->trace_events, sizeof(*mod->trace_events) *
+ mod->num_trace_events, GFP_KERNEL);
#endif
#ifdef CONFIG_FTRACE_MCOUNT_RECORD
/* sechdrs[0].sh_size is always zero */
diff --git a/kernel/notifier.c b/kernel/notifier.c
index 61d5aa5eced3..acd24e7643eb 100644
--- a/kernel/notifier.c
+++ b/kernel/notifier.c
@@ -558,7 +558,7 @@ EXPORT_SYMBOL(unregister_reboot_notifier);
static ATOMIC_NOTIFIER_HEAD(die_chain);
-int notrace notify_die(enum die_val val, const char *str,
+int notrace __kprobes notify_die(enum die_val val, const char *str,
struct pt_regs *regs, long err, int trap, int sig)
{
struct die_args args = {
diff --git a/kernel/params.c b/kernel/params.c
index 9da58eabdcb2..d656c276508d 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -218,15 +218,11 @@ int param_set_charp(const char *val, struct kernel_param *kp)
return -ENOSPC;
}
- if (kp->flags & KPARAM_KMALLOCED)
- kfree(*(char **)kp->arg);
-
/* This is a hack. We can't need to strdup in early boot, and we
* don't need to; this mangled commandline is preserved. */
if (slab_is_available()) {
- kp->flags |= KPARAM_KMALLOCED;
*(char **)kp->arg = kstrdup(val, GFP_KERNEL);
- if (!kp->arg)
+ if (!*(char **)kp->arg)
return -ENOMEM;
} else
*(const char **)kp->arg = val;
@@ -304,6 +300,7 @@ static int param_array(const char *name,
unsigned int min, unsigned int max,
void *elem, int elemsize,
int (*set)(const char *, struct kernel_param *kp),
+ u16 flags,
unsigned int *num)
{
int ret;
@@ -313,6 +310,7 @@ static int param_array(const char *name,
/* Get the name right for errors. */
kp.name = name;
kp.arg = elem;
+ kp.flags = flags;
/* No equals sign? */
if (!val) {
@@ -358,7 +356,8 @@ int param_array_set(const char *val, struct kernel_param *kp)
unsigned int temp_num;
return param_array(kp->name, val, 1, arr->max, arr->elem,
- arr->elemsize, arr->set, arr->num ?: &temp_num);
+ arr->elemsize, arr->set, kp->flags,
+ arr->num ?: &temp_num);
}
int param_array_get(char *buffer, struct kernel_param *kp)
@@ -605,11 +604,7 @@ void module_param_sysfs_remove(struct module *mod)
void destroy_params(const struct kernel_param *params, unsigned num)
{
- unsigned int i;
-
- for (i = 0; i < num; i++)
- if (params[i].flags & KPARAM_KMALLOCED)
- kfree(*(char **)params[i].arg);
+ /* FIXME: This should free kmalloced charp parameters. It doesn't. */
}
static void __init kernel_add_sysfs_param(const char *name,
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index 9d0b5c665883..a69d4ed6a666 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -28,6 +28,7 @@
#include <linux/anon_inodes.h>
#include <linux/kernel_stat.h>
#include <linux/perf_event.h>
+#include <linux/ftrace_event.h>
#include <asm/irq_regs.h>
@@ -1355,7 +1356,7 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx)
u64 interrupts, freq;
spin_lock(&ctx->lock);
- list_for_each_entry(event, &ctx->group_list, group_entry) {
+ list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
if (event->state != PERF_EVENT_STATE_ACTIVE)
continue;
@@ -1658,6 +1659,8 @@ static struct perf_event_context *find_get_context(pid_t pid, int cpu)
return ERR_PTR(err);
}
+static void perf_event_free_filter(struct perf_event *event);
+
static void free_event_rcu(struct rcu_head *head)
{
struct perf_event *event;
@@ -1665,6 +1668,7 @@ static void free_event_rcu(struct rcu_head *head)
event = container_of(head, struct perf_event, rcu_head);
if (event->ns)
put_pid_ns(event->ns);
+ perf_event_free_filter(event);
kfree(event);
}
@@ -1974,7 +1978,8 @@ unlock:
return ret;
}
-int perf_event_set_output(struct perf_event *event, int output_fd);
+static int perf_event_set_output(struct perf_event *event, int output_fd);
+static int perf_event_set_filter(struct perf_event *event, void __user *arg);
static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
@@ -2002,6 +2007,9 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case PERF_EVENT_IOC_SET_OUTPUT:
return perf_event_set_output(event, arg);
+ case PERF_EVENT_IOC_SET_FILTER:
+ return perf_event_set_filter(event, (void __user *)arg);
+
default:
return -ENOTTY;
}
@@ -3806,9 +3814,14 @@ static int perf_swevent_is_counting(struct perf_event *event)
return 1;
}
+static int perf_tp_event_match(struct perf_event *event,
+ struct perf_sample_data *data);
+
static int perf_swevent_match(struct perf_event *event,
enum perf_type_id type,
- u32 event_id, struct pt_regs *regs)
+ u32 event_id,
+ struct perf_sample_data *data,
+ struct pt_regs *regs)
{
if (!perf_swevent_is_counting(event))
return 0;
@@ -3826,6 +3839,10 @@ static int perf_swevent_match(struct perf_event *event,
return 0;
}
+ if (event->attr.type == PERF_TYPE_TRACEPOINT &&
+ !perf_tp_event_match(event, data))
+ return 0;
+
return 1;
}
@@ -3842,7 +3859,7 @@ static void perf_swevent_ctx_event(struct perf_event_context *ctx,
rcu_read_lock();
list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
- if (perf_swevent_match(event, type, event_id, regs))
+ if (perf_swevent_match(event, type, event_id, data, regs))
perf_swevent_add(event, nr, nmi, data, regs);
}
rcu_read_unlock();
@@ -3959,8 +3976,9 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer)
regs = task_pt_regs(current);
if (regs) {
- if (perf_event_overflow(event, 0, &data, regs))
- ret = HRTIMER_NORESTART;
+ if (!(event->attr.exclude_idle && current->pid == 0))
+ if (perf_event_overflow(event, 0, &data, regs))
+ ret = HRTIMER_NORESTART;
}
period = max_t(u64, 10000, event->hw.sample_period);
@@ -3969,6 +3987,42 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer)
return ret;
}
+static void perf_swevent_start_hrtimer(struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+
+ hrtimer_init(&hwc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hwc->hrtimer.function = perf_swevent_hrtimer;
+ if (hwc->sample_period) {
+ u64 period;
+
+ if (hwc->remaining) {
+ if (hwc->remaining < 0)
+ period = 10000;
+ else
+ period = hwc->remaining;
+ hwc->remaining = 0;
+ } else {
+ period = max_t(u64, 10000, hwc->sample_period);
+ }
+ __hrtimer_start_range_ns(&hwc->hrtimer,
+ ns_to_ktime(period), 0,
+ HRTIMER_MODE_REL, 0);
+ }
+}
+
+static void perf_swevent_cancel_hrtimer(struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+
+ if (hwc->sample_period) {
+ ktime_t remaining = hrtimer_get_remaining(&hwc->hrtimer);
+ hwc->remaining = ktime_to_ns(remaining);
+
+ hrtimer_cancel(&hwc->hrtimer);
+ }
+}
+
/*
* Software event: cpu wall time clock
*/
@@ -3991,22 +4045,14 @@ static int cpu_clock_perf_event_enable(struct perf_event *event)
int cpu = raw_smp_processor_id();
atomic64_set(&hwc->prev_count, cpu_clock(cpu));
- hrtimer_init(&hwc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- hwc->hrtimer.function = perf_swevent_hrtimer;
- if (hwc->sample_period) {
- u64 period = max_t(u64, 10000, hwc->sample_period);
- __hrtimer_start_range_ns(&hwc->hrtimer,
- ns_to_ktime(period), 0,
- HRTIMER_MODE_REL, 0);
- }
+ perf_swevent_start_hrtimer(event);
return 0;
}
static void cpu_clock_perf_event_disable(struct perf_event *event)
{
- if (event->hw.sample_period)
- hrtimer_cancel(&event->hw.hrtimer);
+ perf_swevent_cancel_hrtimer(event);
cpu_clock_perf_event_update(event);
}
@@ -4043,22 +4089,15 @@ static int task_clock_perf_event_enable(struct perf_event *event)
now = event->ctx->time;
atomic64_set(&hwc->prev_count, now);
- hrtimer_init(&hwc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- hwc->hrtimer.function = perf_swevent_hrtimer;
- if (hwc->sample_period) {
- u64 period = max_t(u64, 10000, hwc->sample_period);
- __hrtimer_start_range_ns(&hwc->hrtimer,
- ns_to_ktime(period), 0,
- HRTIMER_MODE_REL, 0);
- }
+
+ perf_swevent_start_hrtimer(event);
return 0;
}
static void task_clock_perf_event_disable(struct perf_event *event)
{
- if (event->hw.sample_period)
- hrtimer_cancel(&event->hw.hrtimer);
+ perf_swevent_cancel_hrtimer(event);
task_clock_perf_event_update(event, event->ctx->time);
}
@@ -4086,6 +4125,7 @@ static const struct pmu perf_ops_task_clock = {
};
#ifdef CONFIG_EVENT_PROFILE
+
void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
int entry_size)
{
@@ -4109,8 +4149,15 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
}
EXPORT_SYMBOL_GPL(perf_tp_event);
-extern int ftrace_profile_enable(int);
-extern void ftrace_profile_disable(int);
+static int perf_tp_event_match(struct perf_event *event,
+ struct perf_sample_data *data)
+{
+ void *record = data->raw->data;
+
+ if (likely(!event->filter) || filter_match_preds(event->filter, record))
+ return 1;
+ return 0;
+}
static void tp_perf_event_destroy(struct perf_event *event)
{
@@ -4135,12 +4182,53 @@ static const struct pmu *tp_perf_event_init(struct perf_event *event)
return &perf_ops_generic;
}
+
+static int perf_event_set_filter(struct perf_event *event, void __user *arg)
+{
+ char *filter_str;
+ int ret;
+
+ if (event->attr.type != PERF_TYPE_TRACEPOINT)
+ return -EINVAL;
+
+ filter_str = strndup_user(arg, PAGE_SIZE);
+ if (IS_ERR(filter_str))
+ return PTR_ERR(filter_str);
+
+ ret = ftrace_profile_set_filter(event, event->attr.config, filter_str);
+
+ kfree(filter_str);
+ return ret;
+}
+
+static void perf_event_free_filter(struct perf_event *event)
+{
+ ftrace_profile_free_filter(event);
+}
+
#else
+
+static int perf_tp_event_match(struct perf_event *event,
+ struct perf_sample_data *data)
+{
+ return 1;
+}
+
static const struct pmu *tp_perf_event_init(struct perf_event *event)
{
return NULL;
}
-#endif
+
+static int perf_event_set_filter(struct perf_event *event, void __user *arg)
+{
+ return -ENOENT;
+}
+
+static void perf_event_free_filter(struct perf_event *event)
+{
+}
+
+#endif /* CONFIG_EVENT_PROFILE */
atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];
@@ -4394,7 +4482,7 @@ err_size:
goto out;
}
-int perf_event_set_output(struct perf_event *event, int output_fd)
+static int perf_event_set_output(struct perf_event *event, int output_fd)
{
struct perf_event *output_event = NULL;
struct file *output_file = NULL;
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
index 5c9dc228747b..102c34516e76 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -13,16 +13,16 @@
/*
* Called after updating RLIMIT_CPU to set timer expiration if necessary.
*/
-void update_rlimit_cpu(unsigned long rlim_new)
+void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new)
{
cputime_t cputime = secs_to_cputime(rlim_new);
- struct signal_struct *const sig = current->signal;
+ struct signal_struct *const sig = task->signal;
if (cputime_eq(sig->it[CPUCLOCK_PROF].expires, cputime_zero) ||
cputime_gt(sig->it[CPUCLOCK_PROF].expires, cputime)) {
- spin_lock_irq(&current->sighand->siglock);
- set_process_cpu_timer(current, CPUCLOCK_PROF, &cputime, NULL);
- spin_unlock_irq(&current->sighand->siglock);
+ spin_lock_irq(&task->sighand->siglock);
+ set_process_cpu_timer(task, CPUCLOCK_PROF, &cputime, NULL);
+ spin_unlock_irq(&task->sighand->siglock);
}
}
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 91e09d3b2eb2..39263f41c534 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -27,6 +27,15 @@ config PM_DEBUG
code. This is helpful when debugging and reporting PM bugs, like
suspend support.
+config PM_ADVANCED_DEBUG
+ bool "Extra PM attributes in sysfs for low-level debugging/testing"
+ depends on PM_DEBUG
+ default n
+ ---help---
+ Add extra sysfs attributes allowing one to access some Power Management
+ fields of device objects from user space. If you are not a kernel
+ developer interested in debugging/testing Power Management, say "no".
+
config PM_VERBOSE
bool "Verbose Power Management debugging"
depends on PM_DEBUG
@@ -85,6 +94,11 @@ config PM_SLEEP
depends on SUSPEND || HIBERNATION || XEN_SAVE_RESTORE
default y
+config PM_SLEEP_ADVANCED_DEBUG
+ bool
+ depends on PM_ADVANCED_DEBUG
+ default n
+
config SUSPEND
bool "Suspend to RAM and standby"
depends on PM && ARCH_SUSPEND_POSSIBLE
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index c3b81c30e5d5..43191815f874 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -8,7 +8,7 @@ obj-$(CONFIG_PM_SLEEP) += console.o
obj-$(CONFIG_FREEZER) += process.o
obj-$(CONFIG_SUSPEND) += suspend.o
obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o
-obj-$(CONFIG_HIBERNATION) += swsusp.o hibernate.o snapshot.o swap.o user.o
+obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o
obj-$(CONFIG_HIBERNATION_NVS) += hibernate_nvs.o
obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 04b3a83d686f..5d0d1500d526 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -32,6 +32,7 @@ static int noresume = 0;
static char resume_file[256] = CONFIG_PM_STD_PARTITION;
dev_t swsusp_resume_device;
sector_t swsusp_resume_block;
+int in_suspend __nosavedata = 0;
enum {
HIBERNATION_INVALID,
@@ -202,6 +203,31 @@ static void platform_recover(int platform_mode)
}
/**
+ * swsusp_show_speed - print the time elapsed between two events represented by
+ * @start and @stop
+ *
+ * @nr_pages - number of pages processed between @start and @stop
+ * @msg - introductory message to print
+ */
+
+void swsusp_show_speed(struct timeval *start, struct timeval *stop,
+ unsigned nr_pages, char *msg)
+{
+ int centisecs = pm_time_elapsed(start, stop) / 10;
+ int k;
+ int kps;
+
+ if (centisecs == 0)
+ centisecs = 1; /* avoid div-by-zero */
+ k = nr_pages * (PAGE_SIZE / 1024);
+ kps = (k * 100) / centisecs;
+ printk(KERN_INFO "PM: %s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n",
+ msg, k,
+ centisecs / 100, centisecs % 100,
+ kps / 1000, (kps % 1000) / 10);
+}
+
+/**
* create_image - freeze devices that need to be frozen with interrupts
* off, create the hibernation image and thaw those devices. Control
* reappears in this routine after a restore.
@@ -693,21 +719,22 @@ static int software_resume(void)
/* The snapshot device should not be opened while we're running */
if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
error = -EBUSY;
+ swsusp_close(FMODE_READ);
goto Unlock;
}
pm_prepare_console();
error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
if (error)
- goto Finish;
+ goto close_finish;
error = usermodehelper_disable();
if (error)
- goto Finish;
+ goto close_finish;
error = create_basic_memory_bitmaps();
if (error)
- goto Finish;
+ goto close_finish;
pr_debug("PM: Preparing processes for restore.\n");
error = prepare_processes();
@@ -719,6 +746,7 @@ static int software_resume(void)
pr_debug("PM: Reading hibernation image.\n");
error = swsusp_read(&flags);
+ swsusp_close(FMODE_READ);
if (!error)
hibernation_restore(flags & SF_PLATFORM_MODE);
@@ -737,6 +765,9 @@ static int software_resume(void)
mutex_unlock(&pm_mutex);
pr_debug("PM: Resume from disk failed.\n");
return error;
+close_finish:
+ swsusp_close(FMODE_READ);
+ goto Finish;
}
late_initcall(software_resume);
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 347d2cc88cd0..eea5403c7d4d 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -44,6 +44,32 @@ int pm_notifier_call_chain(unsigned long val)
== NOTIFY_BAD) ? -EINVAL : 0;
}
+/* If set, devices may be suspended and resumed asynchronously. */
+int pm_async_enabled = 1;
+
+static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", pm_async_enabled);
+}
+
+static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ unsigned long val;
+
+ if (strict_strtoul(buf, 10, &val))
+ return -EINVAL;
+
+ if (val > 1)
+ return -EINVAL;
+
+ pm_async_enabled = val;
+ return n;
+}
+
+power_attr(pm_async);
+
#ifdef CONFIG_PM_DEBUG
int pm_test_level = TEST_NONE;
@@ -208,9 +234,12 @@ static struct attribute * g[] = {
#ifdef CONFIG_PM_TRACE
&pm_trace_attr.attr,
#endif
-#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_DEBUG)
+#ifdef CONFIG_PM_SLEEP
+ &pm_async_attr.attr,
+#ifdef CONFIG_PM_DEBUG
&pm_test_attr.attr,
#endif
+#endif
NULL,
};
diff --git a/kernel/power/process.c b/kernel/power/process.c
index cc2e55373b68..5ade1bdcf366 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/syscalls.h>
#include <linux/freezer.h>
+#include <linux/delay.h>
/*
* Timeout for stopping processes
@@ -41,7 +42,7 @@ static int try_to_freeze_tasks(bool sig_only)
do_gettimeofday(&start);
end_time = jiffies + TIMEOUT;
- do {
+ while (true) {
todo = 0;
read_lock(&tasklist_lock);
do_each_thread(g, p) {
@@ -62,10 +63,15 @@ static int try_to_freeze_tasks(bool sig_only)
todo++;
} while_each_thread(g, p);
read_unlock(&tasklist_lock);
- yield(); /* Yield is okay here */
- if (time_after(jiffies, end_time))
+ if (!todo || time_after(jiffies, end_time))
break;
- } while (todo);
+
+ /*
+ * We need to retry, but first give the freezing tasks some
+ * time to enter the regrigerator.
+ */
+ msleep(10);
+ }
do_gettimeofday(&end);
elapsed_csecs64 = timeval_to_ns(&end) - timeval_to_ns(&start);
diff --git a/kernel/power/suspend_test.c b/kernel/power/suspend_test.c
index 17d8bb1acf9c..25596e450ac7 100644
--- a/kernel/power/suspend_test.c
+++ b/kernel/power/suspend_test.c
@@ -19,7 +19,7 @@
* The time it takes is system-specific though, so when we test this
* during system bootup we allow a LOT of time.
*/
-#define TEST_SUSPEND_SECONDS 5
+#define TEST_SUSPEND_SECONDS 10
static unsigned long suspend_test_start_time;
@@ -49,7 +49,8 @@ void suspend_test_finish(const char *label)
* has some performance issues. The stack dump of a WARN_ON
* is more likely to get the right attention than a printk...
*/
- WARN(msec > (TEST_SUSPEND_SECONDS * 1000), "Component: %s\n", label);
+ WARN(msec > (TEST_SUSPEND_SECONDS * 1000),
+ "Component: %s, time: %u\n", label, msec);
}
/*
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index b101cdc4df3f..89e958ef819b 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -38,6 +38,107 @@ struct swsusp_header {
static struct swsusp_header *swsusp_header;
+/**
+ * The following functions are used for tracing the allocated
+ * swap pages, so that they can be freed in case of an error.
+ */
+
+struct swsusp_extent {
+ struct rb_node node;
+ unsigned long start;
+ unsigned long end;
+};
+
+static struct rb_root swsusp_extents = RB_ROOT;
+
+static int swsusp_extents_insert(unsigned long swap_offset)
+{
+ struct rb_node **new = &(swsusp_extents.rb_node);
+ struct rb_node *parent = NULL;
+ struct swsusp_extent *ext;
+
+ /* Figure out where to put the new node */
+ while (*new) {
+ ext = container_of(*new, struct swsusp_extent, node);
+ parent = *new;
+ if (swap_offset < ext->start) {
+ /* Try to merge */
+ if (swap_offset == ext->start - 1) {
+ ext->start--;
+ return 0;
+ }
+ new = &((*new)->rb_left);
+ } else if (swap_offset > ext->end) {
+ /* Try to merge */
+ if (swap_offset == ext->end + 1) {
+ ext->end++;
+ return 0;
+ }
+ new = &((*new)->rb_right);
+ } else {
+ /* It already is in the tree */
+ return -EINVAL;
+ }
+ }
+ /* Add the new node and rebalance the tree. */
+ ext = kzalloc(sizeof(struct swsusp_extent), GFP_KERNEL);
+ if (!ext)
+ return -ENOMEM;
+
+ ext->start = swap_offset;
+ ext->end = swap_offset;
+ rb_link_node(&ext->node, parent, new);
+ rb_insert_color(&ext->node, &swsusp_extents);
+ return 0;
+}
+
+/**
+ * alloc_swapdev_block - allocate a swap page and register that it has
+ * been allocated, so that it can be freed in case of an error.
+ */
+
+sector_t alloc_swapdev_block(int swap)
+{
+ unsigned long offset;
+
+ offset = swp_offset(get_swap_page_of_type(swap));
+ if (offset) {
+ if (swsusp_extents_insert(offset))
+ swap_free(swp_entry(swap, offset));
+ else
+ return swapdev_block(swap, offset);
+ }
+ return 0;
+}
+
+/**
+ * free_all_swap_pages - free swap pages allocated for saving image data.
+ * It also frees the extents used to register which swap entres had been
+ * allocated.
+ */
+
+void free_all_swap_pages(int swap)
+{
+ struct rb_node *node;
+
+ while ((node = swsusp_extents.rb_node)) {
+ struct swsusp_extent *ext;
+ unsigned long offset;
+
+ ext = container_of(node, struct swsusp_extent, node);
+ rb_erase(node, &swsusp_extents);
+ for (offset = ext->start; offset <= ext->end; offset++)
+ swap_free(swp_entry(swap, offset));
+
+ kfree(ext);
+ }
+}
+
+int swsusp_swap_in_use(void)
+{
+ return (swsusp_extents.rb_node != NULL);
+}
+
/*
* General things
*/
@@ -572,8 +673,6 @@ int swsusp_read(unsigned int *flags_p)
error = load_image(&handle, &snapshot, header->pages - 1);
release_swap_reader(&handle);
- blkdev_put(resume_bdev, FMODE_READ);
-
if (!error)
pr_debug("PM: Image successfully loaded\n");
else
@@ -596,7 +695,7 @@ int swsusp_check(void)
error = bio_read_page(swsusp_resume_block,
swsusp_header, NULL);
if (error)
- return error;
+ goto put;
if (!memcmp(SWSUSP_SIG, swsusp_header->sig, 10)) {
memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10);
@@ -604,8 +703,10 @@ int swsusp_check(void)
error = bio_write_page(swsusp_resume_block,
swsusp_header, NULL);
} else {
- return -EINVAL;
+ error = -EINVAL;
}
+
+put:
if (error)
blkdev_put(resume_bdev, FMODE_READ);
else
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
deleted file mode 100644
index 6a07f4dbf2f8..000000000000
--- a/kernel/power/swsusp.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * linux/kernel/power/swsusp.c
- *
- * This file provides code to write suspend image to swap and read it back.
- *
- * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu>
- * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@suse.cz>
- *
- * This file is released under the GPLv2.
- *
- * I'd like to thank the following people for their work:
- *
- * Pavel Machek <pavel@ucw.cz>:
- * Modifications, defectiveness pointing, being with me at the very beginning,
- * suspend to swap space, stop all tasks. Port to 2.4.18-ac and 2.5.17.
- *
- * Steve Doddi <dirk@loth.demon.co.uk>:
- * Support the possibility of hardware state restoring.
- *
- * Raph <grey.havens@earthling.net>:
- * Support for preserving states of network devices and virtual console
- * (including X and svgatextmode)
- *
- * Kurt Garloff <garloff@suse.de>:
- * Straightened the critical function in order to prevent compilers from
- * playing tricks with local variables.
- *
- * Andreas Mohr <a.mohr@mailto.de>
- *
- * Alex Badea <vampire@go.ro>:
- * Fixed runaway init
- *
- * Rafael J. Wysocki <rjw@sisk.pl>
- * Reworked the freeing of memory and the handling of swap
- *
- * More state savers are welcome. Especially for the scsi layer...
- *
- * For TODOs,FIXMEs also look in Documentation/power/swsusp.txt
- */
-
-#include <linux/mm.h>
-#include <linux/suspend.h>
-#include <linux/spinlock.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/swap.h>
-#include <linux/pm.h>
-#include <linux/swapops.h>
-#include <linux/bootmem.h>
-#include <linux/syscalls.h>
-#include <linux/highmem.h>
-#include <linux/time.h>
-#include <linux/rbtree.h>
-#include <linux/io.h>
-
-#include "power.h"
-
-int in_suspend __nosavedata = 0;
-
-/**
- * The following functions are used for tracing the allocated
- * swap pages, so that they can be freed in case of an error.
- */
-
-struct swsusp_extent {
- struct rb_node node;
- unsigned long start;
- unsigned long end;
-};
-
-static struct rb_root swsusp_extents = RB_ROOT;
-
-static int swsusp_extents_insert(unsigned long swap_offset)
-{
- struct rb_node **new = &(swsusp_extents.rb_node);
- struct rb_node *parent = NULL;
- struct swsusp_extent *ext;
-
- /* Figure out where to put the new node */
- while (*new) {
- ext = container_of(*new, struct swsusp_extent, node);
- parent = *new;
- if (swap_offset < ext->start) {
- /* Try to merge */
- if (swap_offset == ext->start - 1) {
- ext->start--;
- return 0;
- }
- new = &((*new)->rb_left);
- } else if (swap_offset > ext->end) {
- /* Try to merge */
- if (swap_offset == ext->end + 1) {
- ext->end++;
- return 0;
- }
- new = &((*new)->rb_right);
- } else {
- /* It already is in the tree */
- return -EINVAL;
- }
- }
- /* Add the new node and rebalance the tree. */
- ext = kzalloc(sizeof(struct swsusp_extent), GFP_KERNEL);
- if (!ext)
- return -ENOMEM;
-
- ext->start = swap_offset;
- ext->end = swap_offset;
- rb_link_node(&ext->node, parent, new);
- rb_insert_color(&ext->node, &swsusp_extents);
- return 0;
-}
-
-/**
- * alloc_swapdev_block - allocate a swap page and register that it has
- * been allocated, so that it can be freed in case of an error.
- */
-
-sector_t alloc_swapdev_block(int swap)
-{
- unsigned long offset;
-
- offset = swp_offset(get_swap_page_of_type(swap));
- if (offset) {
- if (swsusp_extents_insert(offset))
- swap_free(swp_entry(swap, offset));
- else
- return swapdev_block(swap, offset);
- }
- return 0;
-}
-
-/**
- * free_all_swap_pages - free swap pages allocated for saving image data.
- * It also frees the extents used to register which swap entres had been
- * allocated.
- */
-
-void free_all_swap_pages(int swap)
-{
- struct rb_node *node;
-
- while ((node = swsusp_extents.rb_node)) {
- struct swsusp_extent *ext;
- unsigned long offset;
-
- ext = container_of(node, struct swsusp_extent, node);
- rb_erase(node, &swsusp_extents);
- for (offset = ext->start; offset <= ext->end; offset++)
- swap_free(swp_entry(swap, offset));
-
- kfree(ext);
- }
-}
-
-int swsusp_swap_in_use(void)
-{
- return (swsusp_extents.rb_node != NULL);
-}
-
-/**
- * swsusp_show_speed - print the time elapsed between two events represented by
- * @start and @stop
- *
- * @nr_pages - number of pages processed between @start and @stop
- * @msg - introductory message to print
- */
-
-void swsusp_show_speed(struct timeval *start, struct timeval *stop,
- unsigned nr_pages, char *msg)
-{
- s64 elapsed_centisecs64;
- int centisecs;
- int k;
- int kps;
-
- elapsed_centisecs64 = timeval_to_ns(stop) - timeval_to_ns(start);
- do_div(elapsed_centisecs64, NSEC_PER_SEC / 100);
- centisecs = elapsed_centisecs64;
- if (centisecs == 0)
- centisecs = 1; /* avoid div-by-zero */
- k = nr_pages * (PAGE_SIZE / 1024);
- kps = (k * 100) / centisecs;
- printk(KERN_INFO "PM: %s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n",
- msg, k,
- centisecs / 100, centisecs % 100,
- kps / 1000, (kps % 1000) / 10);
-}
diff --git a/kernel/printk.c b/kernel/printk.c
index f38b07f78a4e..b5ac4d99c667 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -33,6 +33,7 @@
#include <linux/bootmem.h>
#include <linux/syscalls.h>
#include <linux/kexec.h>
+#include <linux/ratelimit.h>
#include <asm/uaccess.h>
@@ -1376,11 +1377,11 @@ late_initcall(disable_boot_consoles);
*/
DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10);
-int printk_ratelimit(void)
+int __printk_ratelimit(const char *func)
{
- return __ratelimit(&printk_ratelimit_state);
+ return ___ratelimit(&printk_ratelimit_state, func);
}
-EXPORT_SYMBOL(printk_ratelimit);
+EXPORT_SYMBOL(__printk_ratelimit);
/**
* printk_timed_ratelimit - caller-controlled printk ratelimiting
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 400183346ad2..7625f207f65e 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -67,6 +67,8 @@ void wakeme_after_rcu(struct rcu_head *head)
complete(&rcu->completion);
}
+#ifndef CONFIG_TINY_RCU
+
#ifdef CONFIG_TREE_PREEMPT_RCU
/**
@@ -157,6 +159,8 @@ void synchronize_rcu_bh(void)
}
EXPORT_SYMBOL_GPL(synchronize_rcu_bh);
+#endif /* #ifndef CONFIG_TINY_RCU */
+
static int __cpuinit rcu_barrier_cpu_hotplug(struct notifier_block *self,
unsigned long action, void *hcpu)
{
diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c
new file mode 100644
index 000000000000..b33ec3aa377a
--- /dev/null
+++ b/kernel/rcutiny.c
@@ -0,0 +1,291 @@
+/*
+ * Read-Copy Update mechanism for mutual exclusion, the Bloatwatch edition.
+ *
+ * This 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 IBM Corporation, 2008
+ *
+ * Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+ *
+ * For detailed explanation of Read-Copy Update mechanism see -
+ * Documentation/RCU
+ */
+#include <linux/moduleparam.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <linux/rcupdate.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/cpu.h>
+
+/* Global control variables for rcupdate callback mechanism. */
+struct rcu_ctrlblk {
+ struct rcu_head *rcucblist; /* List of pending callbacks (CBs). */
+ struct rcu_head **donetail; /* ->next pointer of last "done" CB. */
+ struct rcu_head **curtail; /* ->next pointer of last CB. */
+};
+
+/* Definition for rcupdate control block. */
+static struct rcu_ctrlblk rcu_ctrlblk = {
+ .donetail = &rcu_ctrlblk.rcucblist,
+ .curtail = &rcu_ctrlblk.rcucblist,
+};
+
+static struct rcu_ctrlblk rcu_bh_ctrlblk = {
+ .donetail = &rcu_bh_ctrlblk.rcucblist,
+ .curtail = &rcu_bh_ctrlblk.rcucblist,
+};
+
+#ifdef CONFIG_NO_HZ
+
+static long rcu_dynticks_nesting = 1;
+
+/*
+ * Enter dynticks-idle mode, which is an extended quiescent state
+ * if we have fully entered that mode (i.e., if the new value of
+ * dynticks_nesting is zero).
+ */
+void rcu_enter_nohz(void)
+{
+ if (--rcu_dynticks_nesting == 0)
+ rcu_sched_qs(0); /* implies rcu_bh_qsctr_inc(0) */
+}
+
+/*
+ * Exit dynticks-idle mode, so that we are no longer in an extended
+ * quiescent state.
+ */
+void rcu_exit_nohz(void)
+{
+ rcu_dynticks_nesting++;
+}
+
+#endif /* #ifdef CONFIG_NO_HZ */
+
+/*
+ * Helper function for rcu_qsctr_inc() and rcu_bh_qsctr_inc().
+ * Also disable irqs to avoid confusion due to interrupt handlers
+ * invoking call_rcu().
+ */
+static int rcu_qsctr_help(struct rcu_ctrlblk *rcp)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if (rcp->rcucblist != NULL &&
+ rcp->donetail != rcp->curtail) {
+ rcp->donetail = rcp->curtail;
+ local_irq_restore(flags);
+ return 1;
+ }
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+/*
+ * Record an rcu quiescent state. And an rcu_bh quiescent state while we
+ * are at it, given that any rcu quiescent state is also an rcu_bh
+ * quiescent state. Use "+" instead of "||" to defeat short circuiting.
+ */
+void rcu_sched_qs(int cpu)
+{
+ if (rcu_qsctr_help(&rcu_ctrlblk) + rcu_qsctr_help(&rcu_bh_ctrlblk))
+ raise_softirq(RCU_SOFTIRQ);
+}
+
+/*
+ * Record an rcu_bh quiescent state.
+ */
+void rcu_bh_qs(int cpu)
+{
+ if (rcu_qsctr_help(&rcu_bh_ctrlblk))
+ raise_softirq(RCU_SOFTIRQ);
+}
+
+/*
+ * Check to see if the scheduling-clock interrupt came from an extended
+ * quiescent state, and, if so, tell RCU about it.
+ */
+void rcu_check_callbacks(int cpu, int user)
+{
+ if (user ||
+ (idle_cpu(cpu) &&
+ !in_softirq() &&
+ hardirq_count() <= (1 << HARDIRQ_SHIFT)))
+ rcu_sched_qs(cpu);
+ else if (!in_softirq())
+ rcu_bh_qs(cpu);
+}
+
+/*
+ * Helper function for rcu_process_callbacks() that operates on the
+ * specified rcu_ctrlkblk structure.
+ */
+static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
+{
+ struct rcu_head *next, *list;
+ unsigned long flags;
+
+ /* If no RCU callbacks ready to invoke, just return. */
+ if (&rcp->rcucblist == rcp->donetail)
+ return;
+
+ /* Move the ready-to-invoke callbacks to a local list. */
+ local_irq_save(flags);
+ list = rcp->rcucblist;
+ rcp->rcucblist = *rcp->donetail;
+ *rcp->donetail = NULL;
+ if (rcp->curtail == rcp->donetail)
+ rcp->curtail = &rcp->rcucblist;
+ rcp->donetail = &rcp->rcucblist;
+ local_irq_restore(flags);
+
+ /* Invoke the callbacks on the local list. */
+ while (list) {
+ next = list->next;
+ prefetch(next);
+ list->func(list);
+ list = next;
+ }
+}
+
+/*
+ * Invoke any callbacks whose grace period has completed.
+ */
+static void rcu_process_callbacks(struct softirq_action *unused)
+{
+ __rcu_process_callbacks(&rcu_ctrlblk);
+ __rcu_process_callbacks(&rcu_bh_ctrlblk);
+}
+
+/*
+ * Null function to handle CPU being onlined. Longer term, we want to
+ * make TINY_RCU avoid using rcupdate.c, but later...
+ */
+int rcu_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
+{
+ return NOTIFY_OK;
+}
+
+/*
+ * Wait for a grace period to elapse. But it is illegal to invoke
+ * synchronize_sched() from within an RCU read-side critical section.
+ * Therefore, any legal call to synchronize_sched() is a quiescent
+ * state, and so on a UP system, synchronize_sched() need do nothing.
+ * Ditto for synchronize_rcu_bh(). (But Lai Jiangshan points out the
+ * benefits of doing might_sleep() to reduce latency.)
+ *
+ * Cool, huh? (Due to Josh Triplett.)
+ *
+ * But we want to make this a static inline later.
+ */
+void synchronize_sched(void)
+{
+ cond_resched();
+}
+EXPORT_SYMBOL_GPL(synchronize_sched);
+
+void synchronize_rcu_bh(void)
+{
+ synchronize_sched();
+}
+EXPORT_SYMBOL_GPL(synchronize_rcu_bh);
+
+/*
+ * Helper function for call_rcu() and call_rcu_bh().
+ */
+static void __call_rcu(struct rcu_head *head,
+ void (*func)(struct rcu_head *rcu),
+ struct rcu_ctrlblk *rcp)
+{
+ unsigned long flags;
+
+ head->func = func;
+ head->next = NULL;
+
+ local_irq_save(flags);
+ *rcp->curtail = head;
+ rcp->curtail = &head->next;
+ local_irq_restore(flags);
+}
+
+/*
+ * Post an RCU callback to be invoked after the end of an RCU grace
+ * period. But since we have but one CPU, that would be after any
+ * quiescent state.
+ */
+void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
+{
+ __call_rcu(head, func, &rcu_ctrlblk);
+}
+EXPORT_SYMBOL_GPL(call_rcu);
+
+/*
+ * Post an RCU bottom-half callback to be invoked after any subsequent
+ * quiescent state.
+ */
+void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
+{
+ __call_rcu(head, func, &rcu_bh_ctrlblk);
+}
+EXPORT_SYMBOL_GPL(call_rcu_bh);
+
+void rcu_barrier(void)
+{
+ struct rcu_synchronize rcu;
+
+ init_completion(&rcu.completion);
+ /* Will wake me after RCU finished. */
+ call_rcu(&rcu.head, wakeme_after_rcu);
+ /* Wait for it. */
+ wait_for_completion(&rcu.completion);
+}
+EXPORT_SYMBOL_GPL(rcu_barrier);
+
+void rcu_barrier_bh(void)
+{
+ struct rcu_synchronize rcu;
+
+ init_completion(&rcu.completion);
+ /* Will wake me after RCU finished. */
+ call_rcu_bh(&rcu.head, wakeme_after_rcu);
+ /* Wait for it. */
+ wait_for_completion(&rcu.completion);
+}
+EXPORT_SYMBOL_GPL(rcu_barrier_bh);
+
+void rcu_barrier_sched(void)
+{
+ struct rcu_synchronize rcu;
+
+ init_completion(&rcu.completion);
+ /* Will wake me after RCU finished. */
+ call_rcu_sched(&rcu.head, wakeme_after_rcu);
+ /* Wait for it. */
+ wait_for_completion(&rcu.completion);
+}
+EXPORT_SYMBOL_GPL(rcu_barrier_sched);
+
+void __rcu_init(void)
+{
+ open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
+}
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index 697c0a0229d4..a86004e4bc92 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -547,6 +547,25 @@ static struct rcu_torture_ops srcu_ops = {
.name = "srcu"
};
+static void srcu_torture_synchronize_expedited(void)
+{
+ synchronize_srcu_expedited(&srcu_ctl);
+}
+
+static struct rcu_torture_ops srcu_expedited_ops = {
+ .init = srcu_torture_init,
+ .cleanup = srcu_torture_cleanup,
+ .readlock = srcu_torture_read_lock,
+ .read_delay = srcu_read_delay,
+ .readunlock = srcu_torture_read_unlock,
+ .completed = srcu_torture_completed,
+ .deferred_free = rcu_sync_torture_deferred_free,
+ .sync = srcu_torture_synchronize_expedited,
+ .cb_barrier = NULL,
+ .stats = srcu_torture_stats,
+ .name = "srcu_expedited"
+};
+
/*
* Definitions for sched torture testing.
*/
@@ -592,7 +611,7 @@ static struct rcu_torture_ops sched_ops = {
.name = "sched"
};
-static struct rcu_torture_ops sched_ops_sync = {
+static struct rcu_torture_ops sched_sync_ops = {
.init = rcu_sync_torture_init,
.cleanup = NULL,
.readlock = sched_torture_read_lock,
@@ -729,13 +748,13 @@ static void rcu_torture_timer(unsigned long unused)
/* Should not happen, but... */
pipe_count = RCU_TORTURE_PIPE_LEN;
}
- ++__get_cpu_var(rcu_torture_count)[pipe_count];
+ __this_cpu_inc(per_cpu_var(rcu_torture_count)[pipe_count]);
completed = cur_ops->completed() - completed;
if (completed > RCU_TORTURE_PIPE_LEN) {
/* Should not happen, but... */
completed = RCU_TORTURE_PIPE_LEN;
}
- ++__get_cpu_var(rcu_torture_batch)[completed];
+ __this_cpu_inc(per_cpu_var(rcu_torture_batch)[completed]);
preempt_enable();
cur_ops->readunlock(idx);
}
@@ -784,13 +803,13 @@ rcu_torture_reader(void *arg)
/* Should not happen, but... */
pipe_count = RCU_TORTURE_PIPE_LEN;
}
- ++__get_cpu_var(rcu_torture_count)[pipe_count];
+ __this_cpu_inc(per_cpu_var(rcu_torture_count)[pipe_count]);
completed = cur_ops->completed() - completed;
if (completed > RCU_TORTURE_PIPE_LEN) {
/* Should not happen, but... */
completed = RCU_TORTURE_PIPE_LEN;
}
- ++__get_cpu_var(rcu_torture_batch)[completed];
+ __this_cpu_inc(per_cpu_var(rcu_torture_batch)[completed]);
preempt_enable();
cur_ops->readunlock(idx);
schedule();
@@ -1098,8 +1117,8 @@ rcu_torture_init(void)
int firsterr = 0;
static struct rcu_torture_ops *torture_ops[] =
{ &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops,
- &sched_expedited_ops,
- &srcu_ops, &sched_ops, &sched_ops_sync, };
+ &srcu_ops, &srcu_expedited_ops,
+ &sched_ops, &sched_sync_ops, &sched_expedited_ops, };
mutex_lock(&fullstop_mutex);
@@ -1110,8 +1129,12 @@ rcu_torture_init(void)
break;
}
if (i == ARRAY_SIZE(torture_ops)) {
- printk(KERN_ALERT "rcutorture: invalid torture type: \"%s\"\n",
+ printk(KERN_ALERT "rcu-torture: invalid torture type: \"%s\"\n",
torture_type);
+ printk(KERN_ALERT "rcu-torture types:");
+ for (i = 0; i < ARRAY_SIZE(torture_ops); i++)
+ printk(KERN_ALERT " %s", torture_ops[i]->name);
+ printk(KERN_ALERT "\n");
mutex_unlock(&fullstop_mutex);
return -EINVAL;
}
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index 705f02ac7433..3de8069ff0cc 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -51,6 +51,8 @@
/* Data structures. */
+static struct lock_class_key rcu_root_class;
+
#define RCU_STATE_INITIALIZER(name) { \
.level = { &name.node[0] }, \
.levelcnt = { \
@@ -913,7 +915,20 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp)
spin_unlock(&rnp->lock); /* irqs remain disabled. */
break;
}
- rcu_preempt_offline_tasks(rsp, rnp, rdp);
+
+ /*
+ * If there was a task blocking the current grace period,
+ * and if all CPUs have checked in, we need to propagate
+ * the quiescent state up the rcu_node hierarchy. But that
+ * is inconvenient at the moment due to deadlock issues if
+ * this should end the current grace period. So set the
+ * offlined CPU's bit in ->qsmask in order to force the
+ * next force_quiescent_state() invocation to clean up this
+ * mess in a deadlock-free manner.
+ */
+ if (rcu_preempt_offline_tasks(rsp, rnp, rdp) && !rnp->qsmask)
+ rnp->qsmask |= mask;
+
mask = rnp->grpmask;
spin_unlock(&rnp->lock); /* irqs remain disabled. */
rnp = rnp->parent;
@@ -958,7 +973,7 @@ static void rcu_offline_cpu(int cpu)
* Invoke any RCU callbacks that have made it to the end of their grace
* period. Thottle as specified by rdp->blimit.
*/
-static void rcu_do_batch(struct rcu_data *rdp)
+static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
{
unsigned long flags;
struct rcu_head *next, *list, **tail;
@@ -1011,6 +1026,13 @@ static void rcu_do_batch(struct rcu_data *rdp)
if (rdp->blimit == LONG_MAX && rdp->qlen <= qlowmark)
rdp->blimit = blimit;
+ /* Reset ->qlen_last_fqs_check trigger if enough CBs have drained. */
+ if (rdp->qlen == 0 && rdp->qlen_last_fqs_check != 0) {
+ rdp->qlen_last_fqs_check = 0;
+ rdp->n_force_qs_snap = rsp->n_force_qs;
+ } else if (rdp->qlen < rdp->qlen_last_fqs_check - qhimark)
+ rdp->qlen_last_fqs_check = rdp->qlen;
+
local_irq_restore(flags);
/* Re-raise the RCU softirq if there are callbacks remaining. */
@@ -1224,7 +1246,7 @@ __rcu_process_callbacks(struct rcu_state *rsp, struct rcu_data *rdp)
}
/* If there are callbacks ready, invoke them. */
- rcu_do_batch(rdp);
+ rcu_do_batch(rsp, rdp);
}
/*
@@ -1288,10 +1310,20 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
rcu_start_gp(rsp, nestflag); /* releases rnp_root->lock. */
}
- /* Force the grace period if too many callbacks or too long waiting. */
- if (unlikely(++rdp->qlen > qhimark)) {
+ /*
+ * Force the grace period if too many callbacks or too long waiting.
+ * Enforce hysteresis, and don't invoke force_quiescent_state()
+ * if some other CPU has recently done so. Also, don't bother
+ * invoking force_quiescent_state() if the newly enqueued callback
+ * is the only one waiting for a grace period to complete.
+ */
+ if (unlikely(++rdp->qlen > rdp->qlen_last_fqs_check + qhimark)) {
rdp->blimit = LONG_MAX;
- force_quiescent_state(rsp, 0);
+ if (rsp->n_force_qs == rdp->n_force_qs_snap &&
+ *rdp->nxttail[RCU_DONE_TAIL] != head)
+ force_quiescent_state(rsp, 0);
+ rdp->n_force_qs_snap = rsp->n_force_qs;
+ rdp->qlen_last_fqs_check = rdp->qlen;
} else if ((long)(ACCESS_ONCE(rsp->jiffies_force_qs) - jiffies) < 0)
force_quiescent_state(rsp, 1);
local_irq_restore(flags);
@@ -1523,6 +1555,8 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptable)
rdp->beenonline = 1; /* We have now been online. */
rdp->preemptable = preemptable;
rdp->passed_quiesc_completed = lastcomp - 1;
+ rdp->qlen_last_fqs_check = 0;
+ rdp->n_force_qs_snap = rsp->n_force_qs;
rdp->blimit = blimit;
spin_unlock(&rnp->lock); /* irqs remain disabled. */
@@ -1647,8 +1681,7 @@ static void __init rcu_init_one(struct rcu_state *rsp)
cpustride *= rsp->levelspread[i];
rnp = rsp->level[i];
for (j = 0; j < rsp->levelcnt[i]; j++, rnp++) {
- if (rnp != rcu_get_root(rsp))
- spin_lock_init(&rnp->lock);
+ spin_lock_init(&rnp->lock);
rnp->gpnum = 0;
rnp->qsmask = 0;
rnp->qsmaskinit = 0;
@@ -1671,7 +1704,7 @@ static void __init rcu_init_one(struct rcu_state *rsp)
INIT_LIST_HEAD(&rnp->blocked_tasks[1]);
}
}
- spin_lock_init(&rcu_get_root(rsp)->lock);
+ lockdep_set_class(&rcu_get_root(rsp)->lock, &rcu_root_class);
}
/*
diff --git a/kernel/rcutree.h b/kernel/rcutree.h
index b40ac5706040..1823c6e20609 100644
--- a/kernel/rcutree.h
+++ b/kernel/rcutree.h
@@ -167,6 +167,10 @@ struct rcu_data {
struct rcu_head *nxtlist;
struct rcu_head **nxttail[RCU_NEXT_SIZE];
long qlen; /* # of queued callbacks */
+ long qlen_last_fqs_check;
+ /* qlen at last check for QS forcing */
+ unsigned long n_force_qs_snap;
+ /* did other CPU force QS recently? */
long blimit; /* Upper limit on a processed batch */
#ifdef CONFIG_NO_HZ
@@ -302,9 +306,9 @@ static void rcu_print_task_stall(struct rcu_node *rnp);
#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp);
#ifdef CONFIG_HOTPLUG_CPU
-static void rcu_preempt_offline_tasks(struct rcu_state *rsp,
- struct rcu_node *rnp,
- struct rcu_data *rdp);
+static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
+ struct rcu_node *rnp,
+ struct rcu_data *rdp);
static void rcu_preempt_offline_cpu(int cpu);
#endif /* #ifdef CONFIG_HOTPLUG_CPU */
static void rcu_preempt_check_callbacks(int cpu);
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h
index c0cb783aa16a..ef2a58c2b9d5 100644
--- a/kernel/rcutree_plugin.h
+++ b/kernel/rcutree_plugin.h
@@ -304,21 +304,25 @@ static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp)
* parent is to remove the need for rcu_read_unlock_special() to
* make more than two attempts to acquire the target rcu_node's lock.
*
+ * Returns 1 if there was previously a task blocking the current grace
+ * period on the specified rcu_node structure.
+ *
* The caller must hold rnp->lock with irqs disabled.
*/
-static void rcu_preempt_offline_tasks(struct rcu_state *rsp,
- struct rcu_node *rnp,
- struct rcu_data *rdp)
+static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
+ struct rcu_node *rnp,
+ struct rcu_data *rdp)
{
int i;
struct list_head *lp;
struct list_head *lp_root;
+ int retval = rcu_preempted_readers(rnp);
struct rcu_node *rnp_root = rcu_get_root(rsp);
struct task_struct *tp;
if (rnp == rnp_root) {
WARN_ONCE(1, "Last CPU thought to be offlined?");
- return; /* Shouldn't happen: at least one CPU online. */
+ return 0; /* Shouldn't happen: at least one CPU online. */
}
WARN_ON_ONCE(rnp != rdp->mynode &&
(!list_empty(&rnp->blocked_tasks[0]) ||
@@ -342,6 +346,8 @@ static void rcu_preempt_offline_tasks(struct rcu_state *rsp,
spin_unlock(&rnp_root->lock); /* irqs remain disabled */
}
}
+
+ return retval;
}
/*
@@ -393,6 +399,17 @@ void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
EXPORT_SYMBOL_GPL(call_rcu);
/*
+ * Wait for an rcu-preempt grace period. We are supposed to expedite the
+ * grace period, but this is the crude slow compatability hack, so just
+ * invoke synchronize_rcu().
+ */
+void synchronize_rcu_expedited(void)
+{
+ synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);
+
+/*
* Check to see if there is any immediate preemptable-RCU-related work
* to be done.
*/
@@ -521,12 +538,15 @@ static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp)
/*
* Because preemptable RCU does not exist, it never needs to migrate
- * tasks that were blocked within RCU read-side critical sections.
+ * tasks that were blocked within RCU read-side critical sections, and
+ * such non-existent tasks cannot possibly have been blocking the current
+ * grace period.
*/
-static void rcu_preempt_offline_tasks(struct rcu_state *rsp,
- struct rcu_node *rnp,
- struct rcu_data *rdp)
+static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
+ struct rcu_node *rnp,
+ struct rcu_data *rdp)
{
+ return 0;
}
/*
@@ -565,6 +585,16 @@ void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
EXPORT_SYMBOL_GPL(call_rcu);
/*
+ * Wait for an rcu-preempt grace period, but make it happen quickly.
+ * But because preemptable RCU does not exist, map to rcu-sched.
+ */
+void synchronize_rcu_expedited(void)
+{
+ synchronize_sched_expedited();
+}
+EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);
+
+/*
* Because preemptable RCU does not exist, it never has any work to do.
*/
static int rcu_preempt_pending(int cpu)
diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c
index 4b31c779e62e..1984cdc51e9a 100644
--- a/kernel/rcutree_trace.c
+++ b/kernel/rcutree_trace.c
@@ -155,12 +155,14 @@ static const struct file_operations rcudata_csv_fops = {
static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp)
{
+ long gpnum;
int level = 0;
struct rcu_node *rnp;
+ gpnum = rsp->gpnum;
seq_printf(m, "c=%ld g=%ld s=%d jfq=%ld j=%x "
"nfqs=%lu/nfqsng=%lu(%lu) fqlh=%lu oqlen=%ld\n",
- rsp->completed, rsp->gpnum, rsp->signaled,
+ rsp->completed, gpnum, rsp->signaled,
(long)(rsp->jiffies_force_qs - jiffies),
(int)(jiffies & 0xffff),
rsp->n_force_qs, rsp->n_force_qs_ngp,
@@ -171,8 +173,10 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp)
seq_puts(m, "\n");
level = rnp->level;
}
- seq_printf(m, "%lx/%lx %d:%d ^%d ",
+ seq_printf(m, "%lx/%lx %c>%c %d:%d ^%d ",
rnp->qsmask, rnp->qsmaskinit,
+ "T."[list_empty(&rnp->blocked_tasks[gpnum & 1])],
+ "T."[list_empty(&rnp->blocked_tasks[!(gpnum & 1)])],
rnp->grplo, rnp->grphi, rnp->grpnum);
}
seq_puts(m, "\n");
diff --git a/kernel/sched.c b/kernel/sched.c
index e88689522e66..370ff601c925 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -2008,7 +2008,7 @@ task_hot(struct task_struct *p, u64 now, struct sched_domain *sd)
/*
* Buddy candidates are cache hot:
*/
- if (sched_feat(CACHE_HOT_BUDDY) &&
+ if (sched_feat(CACHE_HOT_BUDDY) && this_rq()->nr_running &&
(&p->se == cfs_rq_of(&p->se)->next ||
&p->se == cfs_rq_of(&p->se)->last))
return 1;
@@ -5017,8 +5017,13 @@ static void account_guest_time(struct task_struct *p, cputime_t cputime,
p->gtime = cputime_add(p->gtime, cputime);
/* Add guest time to cpustat. */
- cpustat->user = cputime64_add(cpustat->user, tmp);
- cpustat->guest = cputime64_add(cpustat->guest, tmp);
+ if (TASK_NICE(p) > 0) {
+ cpustat->nice = cputime64_add(cpustat->nice, tmp);
+ cpustat->guest_nice = cputime64_add(cpustat->guest_nice, tmp);
+ } else {
+ cpustat->user = cputime64_add(cpustat->user, tmp);
+ cpustat->guest = cputime64_add(cpustat->guest, tmp);
+ }
}
/*
@@ -9335,10 +9340,6 @@ void __init sched_init(void)
#ifdef CONFIG_CPUMASK_OFFSTACK
alloc_size += num_possible_cpus() * cpumask_size();
#endif
- /*
- * As sched_init() is called before page_alloc is setup,
- * we use alloc_bootmem().
- */
if (alloc_size) {
ptr = (unsigned long)kzalloc(alloc_size, GFP_NOWAIT);
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
index 4e777b47eeda..37087a7fac22 100644
--- a/kernel/sched_fair.c
+++ b/kernel/sched_fair.c
@@ -822,6 +822,26 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
* re-elected due to buddy favours.
*/
clear_buddies(cfs_rq, curr);
+ return;
+ }
+
+ /*
+ * Ensure that a task that missed wakeup preemption by a
+ * narrow margin doesn't have to wait for a full slice.
+ * This also mitigates buddy induced latencies under load.
+ */
+ if (!sched_feat(WAKEUP_PREEMPT))
+ return;
+
+ if (delta_exec < sysctl_sched_min_granularity)
+ return;
+
+ if (cfs_rq->nr_running > 1) {
+ struct sched_entity *se = __pick_next_entity(cfs_rq);
+ s64 delta = curr->vruntime - se->vruntime;
+
+ if (delta > ideal_runtime)
+ resched_task(rq_of(cfs_rq)->curr);
}
}
@@ -861,12 +881,18 @@ wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se);
static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq)
{
struct sched_entity *se = __pick_next_entity(cfs_rq);
+ struct sched_entity *left = se;
- if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, se) < 1)
- return cfs_rq->next;
+ if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, left) < 1)
+ se = cfs_rq->next;
- if (cfs_rq->last && wakeup_preempt_entity(cfs_rq->last, se) < 1)
- return cfs_rq->last;
+ /*
+ * Prefer last buddy, try to return the CPU to a preempted task.
+ */
+ if (cfs_rq->last && wakeup_preempt_entity(cfs_rq->last, left) < 1)
+ se = cfs_rq->last;
+
+ clear_buddies(cfs_rq, se);
return se;
}
@@ -1568,6 +1594,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_
struct sched_entity *se = &curr->se, *pse = &p->se;
struct cfs_rq *cfs_rq = task_cfs_rq(curr);
int sync = wake_flags & WF_SYNC;
+ int scale = cfs_rq->nr_running >= sched_nr_latency;
update_curr(cfs_rq);
@@ -1582,18 +1609,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_
if (unlikely(se == pse))
return;
- /*
- * Only set the backward buddy when the current task is still on the
- * rq. This can happen when a wakeup gets interleaved with schedule on
- * the ->pre_schedule() or idle_balance() point, either of which can
- * drop the rq lock.
- *
- * Also, during early boot the idle thread is in the fair class, for
- * obvious reasons its a bad idea to schedule back to the idle thread.
- */
- if (sched_feat(LAST_BUDDY) && likely(se->on_rq && curr != rq->idle))
- set_last_buddy(se);
- if (sched_feat(NEXT_BUDDY) && !(wake_flags & WF_FORK))
+ if (sched_feat(NEXT_BUDDY) && scale && !(wake_flags & WF_FORK))
set_next_buddy(pse);
/*
@@ -1639,8 +1655,22 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_
BUG_ON(!pse);
- if (wakeup_preempt_entity(se, pse) == 1)
+ if (wakeup_preempt_entity(se, pse) == 1) {
resched_task(curr);
+ /*
+ * Only set the backward buddy when the current task is still
+ * on the rq. This can happen when a wakeup gets interleaved
+ * with schedule on the ->pre_schedule() or idle_balance()
+ * point, either of which can * drop the rq lock.
+ *
+ * Also, during early boot the idle thread is in the fair class,
+ * for obvious reasons its a bad idea to schedule back to it.
+ */
+ if (unlikely(!se->on_rq || curr == rq->idle))
+ return;
+ if (sched_feat(LAST_BUDDY) && scale && entity_is_task(se))
+ set_last_buddy(se);
+ }
}
static struct task_struct *pick_next_task_fair(struct rq *rq)
@@ -1654,16 +1684,6 @@ static struct task_struct *pick_next_task_fair(struct rq *rq)
do {
se = pick_next_entity(cfs_rq);
- /*
- * If se was a buddy, clear it so that it will have to earn
- * the favour again.
- *
- * If se was not a buddy, clear the buddies because neither
- * was elegible to run, let them earn it again.
- *
- * IOW. unconditionally clear buddies.
- */
- __clear_buddies(cfs_rq, NULL);
set_next_entity(cfs_rq, se);
cfs_rq = group_cfs_rq(se);
} while (cfs_rq);
diff --git a/kernel/smp.c b/kernel/smp.c
index c9d1c7835c2f..8bd618f0364d 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -265,9 +265,7 @@ static DEFINE_PER_CPU(struct call_single_data, csd_data);
* @info: An arbitrary pointer to pass to the function.
* @wait: If true, wait until function has completed on other CPUs.
*
- * Returns 0 on success, else a negative status code. Note that @wait
- * will be implicitly turned on in case of allocation failures, since
- * we fall back to on-stack allocation.
+ * Returns 0 on success, else a negative status code.
*/
int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
int wait)
@@ -355,9 +353,7 @@ void __smp_call_function_single(int cpu, struct call_single_data *data,
* @wait: If true, wait (atomically) until function has completed
* on other CPUs.
*
- * If @wait is true, then returns once @func has returned. Note that @wait
- * will be implicitly turned on in case of allocation failures, since
- * we fall back to on-stack allocation.
+ * If @wait is true, then returns once @func has returned.
*
* You must not call this function with disabled interrupts or from a
* hardware interrupt handler or from a bottom half handler. Preemption
@@ -443,8 +439,7 @@ EXPORT_SYMBOL(smp_call_function_many);
* Returns 0.
*
* If @wait is true, then returns once @func has returned; otherwise
- * it returns just before the target cpu calls @func. In case of allocation
- * failure, @wait will be implicitly turned on.
+ * it returns just before the target cpu calls @func.
*
* You must not call this function with disabled interrupts or from a
* hardware interrupt handler or from a bottom half handler.
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
index 81324d12eb35..a85ace2bc018 100644
--- a/kernel/softlockup.c
+++ b/kernel/softlockup.c
@@ -79,6 +79,14 @@ void touch_softlockup_watchdog(void)
}
EXPORT_SYMBOL(touch_softlockup_watchdog);
+static int softlock_touch_sync[NR_CPUS];
+
+void touch_softlockup_watchdog_sync(void)
+{
+ softlock_touch_sync[raw_smp_processor_id()] = 1;
+ __raw_get_cpu_var(touch_timestamp) = 0;
+}
+
void touch_all_softlockup_watchdogs(void)
{
int cpu;
@@ -118,6 +126,14 @@ void softlockup_tick(void)
}
if (touch_timestamp == 0) {
+ if (unlikely(softlock_touch_sync[this_cpu])) {
+ /*
+ * If the time stamp was touched atomically
+ * make sure the scheduler tick is up to date.
+ */
+ softlock_touch_sync[this_cpu] = 0;
+ sched_clock_tick();
+ }
__touch_softlockup_watchdog();
return;
}
diff --git a/kernel/srcu.c b/kernel/srcu.c
index b0aeeaf22ce4..818d7d9aa03c 100644
--- a/kernel/srcu.c
+++ b/kernel/srcu.c
@@ -49,6 +49,7 @@ int init_srcu_struct(struct srcu_struct *sp)
sp->per_cpu_ref = alloc_percpu(struct srcu_struct_array);
return (sp->per_cpu_ref ? 0 : -ENOMEM);
}
+EXPORT_SYMBOL_GPL(init_srcu_struct);
/*
* srcu_readers_active_idx -- returns approximate number of readers
@@ -97,6 +98,7 @@ void cleanup_srcu_struct(struct srcu_struct *sp)
free_percpu(sp->per_cpu_ref);
sp->per_cpu_ref = NULL;
}
+EXPORT_SYMBOL_GPL(cleanup_srcu_struct);
/**
* srcu_read_lock - register a new reader for an SRCU-protected structure.
@@ -118,6 +120,7 @@ int srcu_read_lock(struct srcu_struct *sp)
preempt_enable();
return idx;
}
+EXPORT_SYMBOL_GPL(srcu_read_lock);
/**
* srcu_read_unlock - unregister a old reader from an SRCU-protected structure.
@@ -136,22 +139,12 @@ void srcu_read_unlock(struct srcu_struct *sp, int idx)
per_cpu_ptr(sp->per_cpu_ref, smp_processor_id())->c[idx]--;
preempt_enable();
}
+EXPORT_SYMBOL_GPL(srcu_read_unlock);
-/**
- * synchronize_srcu - wait for prior SRCU read-side critical-section completion
- * @sp: srcu_struct with which to synchronize.
- *
- * Flip the completed counter, and wait for the old count to drain to zero.
- * As with classic RCU, the updater must use some separate means of
- * synchronizing concurrent updates. Can block; must be called from
- * process context.
- *
- * Note that it is illegal to call synchornize_srcu() from the corresponding
- * SRCU read-side critical section; doing so will result in deadlock.
- * However, it is perfectly legal to call synchronize_srcu() on one
- * srcu_struct from some other srcu_struct's read-side critical section.
+/*
+ * Helper function for synchronize_srcu() and synchronize_srcu_expedited().
*/
-void synchronize_srcu(struct srcu_struct *sp)
+void __synchronize_srcu(struct srcu_struct *sp, void (*sync_func)(void))
{
int idx;
@@ -173,7 +166,7 @@ void synchronize_srcu(struct srcu_struct *sp)
return;
}
- synchronize_sched(); /* Force memory barrier on all CPUs. */
+ sync_func(); /* Force memory barrier on all CPUs. */
/*
* The preceding synchronize_sched() ensures that any CPU that
@@ -190,7 +183,7 @@ void synchronize_srcu(struct srcu_struct *sp)
idx = sp->completed & 0x1;
sp->completed++;
- synchronize_sched(); /* Force memory barrier on all CPUs. */
+ sync_func(); /* Force memory barrier on all CPUs. */
/*
* At this point, because of the preceding synchronize_sched(),
@@ -203,7 +196,7 @@ void synchronize_srcu(struct srcu_struct *sp)
while (srcu_readers_active_idx(sp, idx))
schedule_timeout_interruptible(1);
- synchronize_sched(); /* Force memory barrier on all CPUs. */
+ sync_func(); /* Force memory barrier on all CPUs. */
/*
* The preceding synchronize_sched() forces all srcu_read_unlock()
@@ -237,6 +230,47 @@ void synchronize_srcu(struct srcu_struct *sp)
}
/**
+ * synchronize_srcu - wait for prior SRCU read-side critical-section completion
+ * @sp: srcu_struct with which to synchronize.
+ *
+ * Flip the completed counter, and wait for the old count to drain to zero.
+ * As with classic RCU, the updater must use some separate means of
+ * synchronizing concurrent updates. Can block; must be called from
+ * process context.
+ *
+ * Note that it is illegal to call synchronize_srcu() from the corresponding
+ * SRCU read-side critical section; doing so will result in deadlock.
+ * However, it is perfectly legal to call synchronize_srcu() on one
+ * srcu_struct from some other srcu_struct's read-side critical section.
+ */
+void synchronize_srcu(struct srcu_struct *sp)
+{
+ __synchronize_srcu(sp, synchronize_sched);
+}
+EXPORT_SYMBOL_GPL(synchronize_srcu);
+
+/**
+ * synchronize_srcu_expedited - like synchronize_srcu, but less patient
+ * @sp: srcu_struct with which to synchronize.
+ *
+ * Flip the completed counter, and wait for the old count to drain to zero.
+ * As with classic RCU, the updater must use some separate means of
+ * synchronizing concurrent updates. Can block; must be called from
+ * process context.
+ *
+ * Note that it is illegal to call synchronize_srcu_expedited()
+ * from the corresponding SRCU read-side critical section; doing so
+ * will result in deadlock. However, it is perfectly legal to call
+ * synchronize_srcu_expedited() on one srcu_struct from some other
+ * srcu_struct's read-side critical section.
+ */
+void synchronize_srcu_expedited(struct srcu_struct *sp)
+{
+ __synchronize_srcu(sp, synchronize_sched_expedited);
+}
+EXPORT_SYMBOL_GPL(synchronize_srcu_expedited);
+
+/**
* srcu_batches_completed - return batches completed.
* @sp: srcu_struct on which to report batch completion.
*
@@ -248,10 +282,4 @@ long srcu_batches_completed(struct srcu_struct *sp)
{
return sp->completed;
}
-
-EXPORT_SYMBOL_GPL(init_srcu_struct);
-EXPORT_SYMBOL_GPL(cleanup_srcu_struct);
-EXPORT_SYMBOL_GPL(srcu_read_lock);
-EXPORT_SYMBOL_GPL(srcu_read_unlock);
-EXPORT_SYMBOL_GPL(synchronize_srcu);
EXPORT_SYMBOL_GPL(srcu_batches_completed);
diff --git a/kernel/sys.c b/kernel/sys.c
index 255475d163e0..60c9fbaa0ba2 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1236,43 +1236,52 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
#endif
-SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim)
+/* make sure you are allowed to change @tsk limits before calling this */
+int setrlimit(struct task_struct *tsk, unsigned int resource,
+ struct rlimit *new_rlim)
{
- struct rlimit new_rlim, *old_rlim;
+ struct rlimit *old_rlim;
int retval;
- if (resource >= RLIM_NLIMITS)
+ if (new_rlim->rlim_cur > new_rlim->rlim_max)
return -EINVAL;
- if (copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
- return -EFAULT;
- if (new_rlim.rlim_cur > new_rlim.rlim_max)
- return -EINVAL;
- old_rlim = current->signal->rlim + resource;
- if ((new_rlim.rlim_max > old_rlim->rlim_max) &&
- !capable(CAP_SYS_RESOURCE))
- return -EPERM;
- if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open)
+ if (resource == RLIMIT_NOFILE && new_rlim->rlim_max > sysctl_nr_open)
return -EPERM;
- retval = security_task_setrlimit(resource, &new_rlim);
+ /* optimization: 'current' doesn't need locking, e.g. setrlimit */
+ if (tsk != current) {
+ /* protect tsk->signal and tsk->sighand from disappearing */
+ read_lock(&tasklist_lock);
+ if (!tsk->sighand) {
+ retval = -ESRCH;
+ goto out;
+ }
+ }
+
+ retval = security_task_setrlimit(tsk, resource, new_rlim);
if (retval)
- return retval;
+ goto out;
- if (resource == RLIMIT_CPU && new_rlim.rlim_cur == 0) {
+ if (resource == RLIMIT_CPU && new_rlim->rlim_cur == 0) {
/*
* The caller is asking for an immediate RLIMIT_CPU
* expiry. But we use the zero value to mean "it was
* never set". So let's cheat and make it one second
* instead
*/
- new_rlim.rlim_cur = 1;
+ new_rlim->rlim_cur = 1;
}
- task_lock(current->group_leader);
- *old_rlim = new_rlim;
- task_unlock(current->group_leader);
+ old_rlim = tsk->signal->rlim + resource;
+ task_lock(tsk->group_leader);
+ if ((new_rlim->rlim_max <= old_rlim->rlim_max) ||
+ capable(CAP_SYS_RESOURCE))
+ *old_rlim = *new_rlim;
+ else
+ retval = -EPERM;
+ task_unlock(tsk->group_leader);
- if (resource != RLIMIT_CPU)
+ if (retval || resource != RLIMIT_CPU)
goto out;
/*
@@ -1281,12 +1290,25 @@ SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim)
* very long-standing error, and fixing it now risks breakage of
* applications, so we live with it
*/
- if (new_rlim.rlim_cur == RLIM_INFINITY)
+ if (new_rlim->rlim_cur == RLIM_INFINITY)
goto out;
- update_rlimit_cpu(new_rlim.rlim_cur);
+ update_rlimit_cpu(tsk, new_rlim->rlim_cur);
out:
- return 0;
+ if (tsk != current)
+ read_unlock(&tasklist_lock);
+ return retval;
+}
+
+SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim)
+{
+ struct rlimit new_rlim;
+
+ if (resource >= RLIM_NLIMITS)
+ return -EINVAL;
+ if (copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
+ return -EFAULT;
+ return setrlimit(current, resource, &new_rlim);
}
/*
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index e06d0b8d1951..f050ba85d420 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -48,8 +48,10 @@ cond_syscall(sys_shutdown);
cond_syscall(sys_sendmsg);
cond_syscall(compat_sys_sendmsg);
cond_syscall(sys_recvmsg);
+cond_syscall(sys_recvmmsg);
cond_syscall(compat_sys_recvmsg);
cond_syscall(compat_sys_recvfrom);
+cond_syscall(compat_sys_recvmmsg);
cond_syscall(sys_socketcall);
cond_syscall(sys_futex);
cond_syscall(compat_sys_futex);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 0d949c517412..4dbf93a52ee9 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -36,6 +36,7 @@
#include <linux/sysrq.h>
#include <linux/highuid.h>
#include <linux/writeback.h>
+#include <linux/ratelimit.h>
#include <linux/hugetlb.h>
#include <linux/initrd.h>
#include <linux/key.h>
@@ -158,6 +159,8 @@ extern int no_unaligned_warning;
extern int unaligned_dump_stack;
#endif
+extern struct ratelimit_state printk_ratelimit_state;
+
#ifdef CONFIG_RT_MUTEXES
extern int max_lock_depth;
#endif
diff --git a/kernel/time.c b/kernel/time.c
index 2e2e469a7fec..2ef4fe2079b6 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -136,7 +136,6 @@ static inline void warp_clock(void)
write_seqlock_irq(&xtime_lock);
wall_to_monotonic.tv_sec -= sys_tz.tz_minuteswest * 60;
xtime.tv_sec += sys_tz.tz_minuteswest * 60;
- update_xtime_cache(0);
write_sequnlock_irq(&xtime_lock);
clock_was_set();
}
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 5e18c6ab2c6a..c403567f78c0 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -580,7 +580,7 @@ sysfs_show_current_clocksources(struct sys_device *dev,
* @count: length of buffer
*
* Takes input from sysfs interface for manually overriding the default
- * clocksource selction.
+ * clocksource selection.
*/
static ssize_t sysfs_override_clocksource(struct sys_device *dev,
struct sysdev_attribute *attr,
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index c3a4e2907eaa..5a447b9e7bc7 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -165,13 +165,6 @@ struct timespec raw_time;
/* flag for if timekeeping is suspended */
int __read_mostly timekeeping_suspended;
-static struct timespec xtime_cache __attribute__ ((aligned (16)));
-void update_xtime_cache(u64 nsec)
-{
- xtime_cache = xtime;
- timespec_add_ns(&xtime_cache, nsec);
-}
-
/* must hold xtime_lock */
void timekeeping_leap_insert(int leapsecond)
{
@@ -332,8 +325,6 @@ int do_settimeofday(struct timespec *tv)
xtime = *tv;
- update_xtime_cache(0);
-
timekeeper.ntp_error = 0;
ntp_clear();
@@ -548,7 +539,6 @@ void __init timekeeping_init(void)
}
set_normalized_timespec(&wall_to_monotonic,
-boot.tv_sec, -boot.tv_nsec);
- update_xtime_cache(0);
total_sleep_time.tv_sec = 0;
total_sleep_time.tv_nsec = 0;
write_sequnlock_irqrestore(&xtime_lock, flags);
@@ -582,7 +572,6 @@ static int timekeeping_resume(struct sys_device *dev)
wall_to_monotonic = timespec_sub(wall_to_monotonic, ts);
total_sleep_time = timespec_add_safe(total_sleep_time, ts);
}
- update_xtime_cache(0);
/* re-base the last cycle value */
timekeeper.clock->cycle_last = timekeeper.clock->read(timekeeper.clock);
timekeeper.ntp_error = 0;
@@ -723,6 +712,49 @@ static void timekeeping_adjust(s64 offset)
}
/**
+ * logarithmic_accumulation - shifted accumulation of cycles
+ *
+ * This functions accumulates a shifted interval of cycles into
+ * into a shifted interval nanoseconds. Allows for O(log) accumulation
+ * loop.
+ *
+ * Returns the unconsumed cycles.
+ */
+static cycle_t logarithmic_accumulation(cycle_t offset, int shift)
+{
+ u64 nsecps = (u64)NSEC_PER_SEC << timekeeper.shift;
+
+ /* If the offset is smaller then a shifted interval, do nothing */
+ if (offset < timekeeper.cycle_interval<<shift)
+ return offset;
+
+ /* Accumulate one shifted interval */
+ offset -= timekeeper.cycle_interval << shift;
+ timekeeper.clock->cycle_last += timekeeper.cycle_interval << shift;
+
+ timekeeper.xtime_nsec += timekeeper.xtime_interval << shift;
+ while (timekeeper.xtime_nsec >= nsecps) {
+ timekeeper.xtime_nsec -= nsecps;
+ xtime.tv_sec++;
+ second_overflow();
+ }
+
+ /* Accumulate into raw time */
+ raw_time.tv_nsec += timekeeper.raw_interval << shift;;
+ while (raw_time.tv_nsec >= NSEC_PER_SEC) {
+ raw_time.tv_nsec -= NSEC_PER_SEC;
+ raw_time.tv_sec++;
+ }
+
+ /* Accumulate error between NTP and clock interval */
+ timekeeper.ntp_error += tick_length << shift;
+ timekeeper.ntp_error -= timekeeper.xtime_interval <<
+ (timekeeper.ntp_error_shift + shift);
+
+ return offset;
+}
+
+/**
* update_wall_time - Uses the current clocksource to increment the wall time
*
* Called from the timer interrupt, must hold a write on xtime_lock.
@@ -731,7 +763,7 @@ void update_wall_time(void)
{
struct clocksource *clock;
cycle_t offset;
- u64 nsecs;
+ int shift = 0, maxshift;
/* Make sure we're fully resumed: */
if (unlikely(timekeeping_suspended))
@@ -745,33 +777,22 @@ void update_wall_time(void)
#endif
timekeeper.xtime_nsec = (s64)xtime.tv_nsec << timekeeper.shift;
- /* normally this loop will run just once, however in the
- * case of lost or late ticks, it will accumulate correctly.
+ /*
+ * With NO_HZ we may have to accumulate many cycle_intervals
+ * (think "ticks") worth of time at once. To do this efficiently,
+ * we calculate the largest doubling multiple of cycle_intervals
+ * that is smaller then the offset. We then accumulate that
+ * chunk in one go, and then try to consume the next smaller
+ * doubled multiple.
*/
+ shift = ilog2(offset) - ilog2(timekeeper.cycle_interval);
+ shift = max(0, shift);
+ /* Bound shift to one less then what overflows tick_length */
+ maxshift = (8*sizeof(tick_length) - (ilog2(tick_length)+1)) - 1;
+ shift = min(shift, maxshift);
while (offset >= timekeeper.cycle_interval) {
- u64 nsecps = (u64)NSEC_PER_SEC << timekeeper.shift;
-
- /* accumulate one interval */
- offset -= timekeeper.cycle_interval;
- clock->cycle_last += timekeeper.cycle_interval;
-
- timekeeper.xtime_nsec += timekeeper.xtime_interval;
- if (timekeeper.xtime_nsec >= nsecps) {
- timekeeper.xtime_nsec -= nsecps;
- xtime.tv_sec++;
- second_overflow();
- }
-
- raw_time.tv_nsec += timekeeper.raw_interval;
- if (raw_time.tv_nsec >= NSEC_PER_SEC) {
- raw_time.tv_nsec -= NSEC_PER_SEC;
- raw_time.tv_sec++;
- }
-
- /* accumulate error between NTP and clock interval */
- timekeeper.ntp_error += tick_length;
- timekeeper.ntp_error -= timekeeper.xtime_interval <<
- timekeeper.ntp_error_shift;
+ offset = logarithmic_accumulation(offset, shift);
+ shift--;
}
/* correct the clock when NTP error is too big */
@@ -807,9 +828,6 @@ void update_wall_time(void)
timekeeper.ntp_error += timekeeper.xtime_nsec <<
timekeeper.ntp_error_shift;
- nsecs = clocksource_cyc2ns(offset, timekeeper.mult, timekeeper.shift);
- update_xtime_cache(nsecs);
-
/* check to see if there is a new clocksource to use */
update_vsyscall(&xtime, timekeeper.clock);
}
@@ -846,13 +864,13 @@ void monotonic_to_bootbased(struct timespec *ts)
unsigned long get_seconds(void)
{
- return xtime_cache.tv_sec;
+ return xtime.tv_sec;
}
EXPORT_SYMBOL(get_seconds);
struct timespec __current_kernel_time(void)
{
- return xtime_cache;
+ return xtime;
}
struct timespec current_kernel_time(void)
@@ -862,8 +880,7 @@ struct timespec current_kernel_time(void)
do {
seq = read_seqbegin(&xtime_lock);
-
- now = xtime_cache;
+ now = xtime;
} while (read_seqretry(&xtime_lock, seq));
return now;
@@ -877,8 +894,7 @@ struct timespec get_monotonic_coarse(void)
do {
seq = read_seqbegin(&xtime_lock);
-
- now = xtime_cache;
+ now = xtime;
mono = wall_to_monotonic;
} while (read_seqretry(&xtime_lock, seq));
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index b416512ad17f..15372a9f2399 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -428,6 +428,18 @@ config BLK_DEV_IO_TRACE
If unsure, say N.
+config KPROBE_TRACER
+ depends on KPROBES
+ depends on X86
+ bool "Trace kprobes"
+ select TRACING
+ select GENERIC_TRACER
+ help
+ This tracer probes everywhere where kprobes can probe it, and
+ records various registers and memories specified by user.
+ This also allows you to trace kprobe probe points as a dynamic
+ defined events. It provides per-probe event filtering interface.
+
config DYNAMIC_FTRACE
bool "enable/disable ftrace tracepoints dynamically"
depends on FUNCTION_TRACER
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 26f03ac07c2b..c8cb75d7f280 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_EVENT_TRACING) += trace_export.o
obj-$(CONFIG_FTRACE_SYSCALLS) += trace_syscalls.o
obj-$(CONFIG_EVENT_PROFILE) += trace_event_profile.o
obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o
+obj-$(CONFIG_KPROBE_TRACER) += trace_kprobe.o
obj-$(CONFIG_EVENT_TRACING) += power-traces.o
libftrace-y := ftrace.o
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 37ba67e33265..1ed514fe3a30 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -60,6 +60,13 @@ static int last_ftrace_enabled;
/* Quick disabling of function tracer. */
int function_trace_stop;
+/* List for set_ftrace_pid's pids. */
+LIST_HEAD(ftrace_pids);
+struct ftrace_pid {
+ struct list_head list;
+ struct pid *pid;
+};
+
/*
* ftrace_disabled is set when an anomaly is discovered.
* ftrace_disabled is much stronger than ftrace_enabled.
@@ -78,6 +85,10 @@ ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub;
ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub;
ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub;
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+static int ftrace_set_func(unsigned long *array, int *idx, char *buffer);
+#endif
+
static void ftrace_list_func(unsigned long ip, unsigned long parent_ip)
{
struct ftrace_ops *op = ftrace_list;
@@ -155,7 +166,7 @@ static int __register_ftrace_function(struct ftrace_ops *ops)
else
func = ftrace_list_func;
- if (ftrace_pid_trace) {
+ if (!list_empty(&ftrace_pids)) {
set_ftrace_pid_function(func);
func = ftrace_pid_func;
}
@@ -203,7 +214,7 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops)
if (ftrace_list->next == &ftrace_list_end) {
ftrace_func_t func = ftrace_list->func;
- if (ftrace_pid_trace) {
+ if (!list_empty(&ftrace_pids)) {
set_ftrace_pid_function(func);
func = ftrace_pid_func;
}
@@ -231,7 +242,7 @@ static void ftrace_update_pid_func(void)
func = __ftrace_trace_function;
#endif
- if (ftrace_pid_trace) {
+ if (!list_empty(&ftrace_pids)) {
set_ftrace_pid_function(func);
func = ftrace_pid_func;
} else {
@@ -740,7 +751,7 @@ ftrace_profile_write(struct file *filp, const char __user *ubuf,
out:
mutex_unlock(&ftrace_profile_lock);
- filp->f_pos += cnt;
+ *ppos += cnt;
return cnt;
}
@@ -821,8 +832,6 @@ static __init void ftrace_profile_debugfs(struct dentry *d_tracer)
}
#endif /* CONFIG_FUNCTION_PROFILER */
-/* set when tracing only a pid */
-struct pid *ftrace_pid_trace;
static struct pid * const ftrace_swapper_pid = &init_struct_pid;
#ifdef CONFIG_DYNAMIC_FTRACE
@@ -1261,12 +1270,34 @@ static int ftrace_update_code(struct module *mod)
ftrace_new_addrs = p->newlist;
p->flags = 0L;
- /* convert record (i.e, patch mcount-call with NOP) */
- if (ftrace_code_disable(mod, p)) {
- p->flags |= FTRACE_FL_CONVERTED;
- ftrace_update_cnt++;
- } else
+ /*
+ * Do the initial record convertion from mcount jump
+ * to the NOP instructions.
+ */
+ if (!ftrace_code_disable(mod, p)) {
ftrace_free_rec(p);
+ continue;
+ }
+
+ p->flags |= FTRACE_FL_CONVERTED;
+ ftrace_update_cnt++;
+
+ /*
+ * If the tracing is enabled, go ahead and enable the record.
+ *
+ * The reason not to enable the record immediatelly is the
+ * inherent check of ftrace_make_nop/ftrace_make_call for
+ * correct previous instructions. Making first the NOP
+ * conversion puts the module to the correct state, thus
+ * passing the ftrace_make_call check.
+ */
+ if (ftrace_start_up) {
+ int failed = __ftrace_replace_code(p, 1);
+ if (failed) {
+ ftrace_bug(failed, p->ip);
+ ftrace_free_rec(p);
+ }
+ }
}
stop = ftrace_now(raw_smp_processor_id());
@@ -1656,60 +1687,6 @@ ftrace_regex_lseek(struct file *file, loff_t offset, int origin)
return ret;
}
-enum {
- MATCH_FULL,
- MATCH_FRONT_ONLY,
- MATCH_MIDDLE_ONLY,
- MATCH_END_ONLY,
-};
-
-/*
- * (static function - no need for kernel doc)
- *
- * Pass in a buffer containing a glob and this function will
- * set search to point to the search part of the buffer and
- * return the type of search it is (see enum above).
- * This does modify buff.
- *
- * Returns enum type.
- * search returns the pointer to use for comparison.
- * not returns 1 if buff started with a '!'
- * 0 otherwise.
- */
-static int
-ftrace_setup_glob(char *buff, int len, char **search, int *not)
-{
- int type = MATCH_FULL;
- int i;
-
- if (buff[0] == '!') {
- *not = 1;
- buff++;
- len--;
- } else
- *not = 0;
-
- *search = buff;
-
- for (i = 0; i < len; i++) {
- if (buff[i] == '*') {
- if (!i) {
- *search = buff + 1;
- type = MATCH_END_ONLY;
- } else {
- if (type == MATCH_END_ONLY)
- type = MATCH_MIDDLE_ONLY;
- else
- type = MATCH_FRONT_ONLY;
- buff[i] = 0;
- break;
- }
- }
- }
-
- return type;
-}
-
static int ftrace_match(char *str, char *regex, int len, int type)
{
int matched = 0;
@@ -1758,7 +1735,7 @@ static void ftrace_match_records(char *buff, int len, int enable)
int not;
flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
- type = ftrace_setup_glob(buff, len, &search, &not);
+ type = filter_parse_regex(buff, len, &search, &not);
search_len = strlen(search);
@@ -1826,7 +1803,7 @@ static void ftrace_match_module_records(char *buff, char *mod, int enable)
}
if (strlen(buff)) {
- type = ftrace_setup_glob(buff, strlen(buff), &search, &not);
+ type = filter_parse_regex(buff, strlen(buff), &search, &not);
search_len = strlen(search);
}
@@ -1991,7 +1968,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
int count = 0;
char *search;
- type = ftrace_setup_glob(glob, strlen(glob), &search, &not);
+ type = filter_parse_regex(glob, strlen(glob), &search, &not);
len = strlen(search);
/* we do not support '!' for function probes */
@@ -2068,7 +2045,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
else if (glob) {
int not;
- type = ftrace_setup_glob(glob, strlen(glob), &search, &not);
+ type = filter_parse_regex(glob, strlen(glob), &search, &not);
len = strlen(search);
/* we do not support '!' for function probes */
@@ -2297,6 +2274,7 @@ void ftrace_set_notrace(unsigned char *buf, int len, int reset)
#define FTRACE_FILTER_SIZE COMMAND_LINE_SIZE
static char ftrace_notrace_buf[FTRACE_FILTER_SIZE] __initdata;
static char ftrace_filter_buf[FTRACE_FILTER_SIZE] __initdata;
+static char ftrace_graph_buf[FTRACE_FILTER_SIZE] __initdata;
static int __init set_ftrace_notrace(char *str)
{
@@ -2312,6 +2290,31 @@ static int __init set_ftrace_filter(char *str)
}
__setup("ftrace_filter=", set_ftrace_filter);
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+static int __init set_graph_function(char *str)
+{
+ strlcpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE);
+ return 1;
+}
+__setup("ftrace_graph_filter=", set_graph_function);
+
+static void __init set_ftrace_early_graph(char *buf)
+{
+ int ret;
+ char *func;
+
+ while (buf) {
+ func = strsep(&buf, ",");
+ /* we allow only one expression at a time */
+ ret = ftrace_set_func(ftrace_graph_funcs, &ftrace_graph_count,
+ func);
+ if (ret)
+ printk(KERN_DEBUG "ftrace: function %s not "
+ "traceable\n", func);
+ }
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
static void __init set_ftrace_early_filter(char *buf, int enable)
{
char *func;
@@ -2328,6 +2331,10 @@ static void __init set_ftrace_early_filters(void)
set_ftrace_early_filter(ftrace_filter_buf, 1);
if (ftrace_notrace_buf[0])
set_ftrace_early_filter(ftrace_notrace_buf, 0);
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ if (ftrace_graph_buf[0])
+ set_ftrace_early_graph(ftrace_graph_buf);
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
}
static int
@@ -2513,7 +2520,7 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer)
return -ENODEV;
/* decode regex */
- type = ftrace_setup_glob(buffer, strlen(buffer), &search, &not);
+ type = filter_parse_regex(buffer, strlen(buffer), &search, &not);
if (not)
return -EINVAL;
@@ -2624,7 +2631,7 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer)
return 0;
}
-static int ftrace_convert_nops(struct module *mod,
+static int ftrace_process_locs(struct module *mod,
unsigned long *start,
unsigned long *end)
{
@@ -2684,7 +2691,7 @@ static void ftrace_init_module(struct module *mod,
{
if (ftrace_disabled || start == end)
return;
- ftrace_convert_nops(mod, start, end);
+ ftrace_process_locs(mod, start, end);
}
static int ftrace_module_notify(struct notifier_block *self,
@@ -2745,7 +2752,7 @@ void __init ftrace_init(void)
last_ftrace_enabled = ftrace_enabled = 1;
- ret = ftrace_convert_nops(NULL,
+ ret = ftrace_process_locs(NULL,
__start_mcount_loc,
__stop_mcount_loc);
@@ -2778,23 +2785,6 @@ static inline void ftrace_startup_enable(int command) { }
# define ftrace_shutdown_sysctl() do { } while (0)
#endif /* CONFIG_DYNAMIC_FTRACE */
-static ssize_t
-ftrace_pid_read(struct file *file, char __user *ubuf,
- size_t cnt, loff_t *ppos)
-{
- char buf[64];
- int r;
-
- if (ftrace_pid_trace == ftrace_swapper_pid)
- r = sprintf(buf, "swapper tasks\n");
- else if (ftrace_pid_trace)
- r = sprintf(buf, "%u\n", pid_vnr(ftrace_pid_trace));
- else
- r = sprintf(buf, "no pid\n");
-
- return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
-}
-
static void clear_ftrace_swapper(void)
{
struct task_struct *p;
@@ -2845,14 +2835,12 @@ static void set_ftrace_pid(struct pid *pid)
rcu_read_unlock();
}
-static void clear_ftrace_pid_task(struct pid **pid)
+static void clear_ftrace_pid_task(struct pid *pid)
{
- if (*pid == ftrace_swapper_pid)
+ if (pid == ftrace_swapper_pid)
clear_ftrace_swapper();
else
- clear_ftrace_pid(*pid);
-
- *pid = NULL;
+ clear_ftrace_pid(pid);
}
static void set_ftrace_pid_task(struct pid *pid)
@@ -2863,11 +2851,140 @@ static void set_ftrace_pid_task(struct pid *pid)
set_ftrace_pid(pid);
}
+static int ftrace_pid_add(int p)
+{
+ struct pid *pid;
+ struct ftrace_pid *fpid;
+ int ret = -EINVAL;
+
+ mutex_lock(&ftrace_lock);
+
+ if (!p)
+ pid = ftrace_swapper_pid;
+ else
+ pid = find_get_pid(p);
+
+ if (!pid)
+ goto out;
+
+ ret = 0;
+
+ list_for_each_entry(fpid, &ftrace_pids, list)
+ if (fpid->pid == pid)
+ goto out_put;
+
+ ret = -ENOMEM;
+
+ fpid = kmalloc(sizeof(*fpid), GFP_KERNEL);
+ if (!fpid)
+ goto out_put;
+
+ list_add(&fpid->list, &ftrace_pids);
+ fpid->pid = pid;
+
+ set_ftrace_pid_task(pid);
+
+ ftrace_update_pid_func();
+ ftrace_startup_enable(0);
+
+ mutex_unlock(&ftrace_lock);
+ return 0;
+
+out_put:
+ if (pid != ftrace_swapper_pid)
+ put_pid(pid);
+
+out:
+ mutex_unlock(&ftrace_lock);
+ return ret;
+}
+
+static void ftrace_pid_reset(void)
+{
+ struct ftrace_pid *fpid, *safe;
+
+ mutex_lock(&ftrace_lock);
+ list_for_each_entry_safe(fpid, safe, &ftrace_pids, list) {
+ struct pid *pid = fpid->pid;
+
+ clear_ftrace_pid_task(pid);
+
+ list_del(&fpid->list);
+ kfree(fpid);
+ }
+
+ ftrace_update_pid_func();
+ ftrace_startup_enable(0);
+
+ mutex_unlock(&ftrace_lock);
+}
+
+static void *fpid_start(struct seq_file *m, loff_t *pos)
+{
+ mutex_lock(&ftrace_lock);
+
+ if (list_empty(&ftrace_pids) && (!*pos))
+ return (void *) 1;
+
+ return seq_list_start(&ftrace_pids, *pos);
+}
+
+static void *fpid_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ if (v == (void *)1)
+ return NULL;
+
+ return seq_list_next(v, &ftrace_pids, pos);
+}
+
+static void fpid_stop(struct seq_file *m, void *p)
+{
+ mutex_unlock(&ftrace_lock);
+}
+
+static int fpid_show(struct seq_file *m, void *v)
+{
+ const struct ftrace_pid *fpid = list_entry(v, struct ftrace_pid, list);
+
+ if (v == (void *)1) {
+ seq_printf(m, "no pid\n");
+ return 0;
+ }
+
+ if (fpid->pid == ftrace_swapper_pid)
+ seq_printf(m, "swapper tasks\n");
+ else
+ seq_printf(m, "%u\n", pid_vnr(fpid->pid));
+
+ return 0;
+}
+
+static const struct seq_operations ftrace_pid_sops = {
+ .start = fpid_start,
+ .next = fpid_next,
+ .stop = fpid_stop,
+ .show = fpid_show,
+};
+
+static int
+ftrace_pid_open(struct inode *inode, struct file *file)
+{
+ int ret = 0;
+
+ if ((file->f_mode & FMODE_WRITE) &&
+ (file->f_flags & O_TRUNC))
+ ftrace_pid_reset();
+
+ if (file->f_mode & FMODE_READ)
+ ret = seq_open(file, &ftrace_pid_sops);
+
+ return ret;
+}
+
static ssize_t
ftrace_pid_write(struct file *filp, const char __user *ubuf,
size_t cnt, loff_t *ppos)
{
- struct pid *pid;
char buf[64];
long val;
int ret;
@@ -2880,57 +2997,38 @@ ftrace_pid_write(struct file *filp, const char __user *ubuf,
buf[cnt] = 0;
+ /*
+ * Allow "echo > set_ftrace_pid" or "echo -n '' > set_ftrace_pid"
+ * to clean the filter quietly.
+ */
+ strstrip(buf);
+ if (strlen(buf) == 0)
+ return 1;
+
ret = strict_strtol(buf, 10, &val);
if (ret < 0)
return ret;
- mutex_lock(&ftrace_lock);
- if (val < 0) {
- /* disable pid tracing */
- if (!ftrace_pid_trace)
- goto out;
-
- clear_ftrace_pid_task(&ftrace_pid_trace);
-
- } else {
- /* swapper task is special */
- if (!val) {
- pid = ftrace_swapper_pid;
- if (pid == ftrace_pid_trace)
- goto out;
- } else {
- pid = find_get_pid(val);
+ ret = ftrace_pid_add(val);
- if (pid == ftrace_pid_trace) {
- put_pid(pid);
- goto out;
- }
- }
-
- if (ftrace_pid_trace)
- clear_ftrace_pid_task(&ftrace_pid_trace);
-
- if (!pid)
- goto out;
-
- ftrace_pid_trace = pid;
-
- set_ftrace_pid_task(ftrace_pid_trace);
- }
-
- /* update the function call */
- ftrace_update_pid_func();
- ftrace_startup_enable(0);
+ return ret ? ret : cnt;
+}
- out:
- mutex_unlock(&ftrace_lock);
+static int
+ftrace_pid_release(struct inode *inode, struct file *file)
+{
+ if (file->f_mode & FMODE_READ)
+ seq_release(inode, file);
- return cnt;
+ return 0;
}
static const struct file_operations ftrace_pid_fops = {
- .read = ftrace_pid_read,
- .write = ftrace_pid_write,
+ .open = ftrace_pid_open,
+ .write = ftrace_pid_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = ftrace_pid_release,
};
static __init int ftrace_init_debugfs(void)
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index d4ff01970547..63446f12e470 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -397,18 +397,21 @@ int ring_buffer_print_page_header(struct trace_seq *s)
int ret;
ret = trace_seq_printf(s, "\tfield: u64 timestamp;\t"
- "offset:0;\tsize:%u;\n",
- (unsigned int)sizeof(field.time_stamp));
+ "offset:0;\tsize:%u;\tsigned:%u;\n",
+ (unsigned int)sizeof(field.time_stamp),
+ (unsigned int)is_signed_type(u64));
ret = trace_seq_printf(s, "\tfield: local_t commit;\t"
- "offset:%u;\tsize:%u;\n",
+ "offset:%u;\tsize:%u;\tsigned:%u;\n",
(unsigned int)offsetof(typeof(field), commit),
- (unsigned int)sizeof(field.commit));
+ (unsigned int)sizeof(field.commit),
+ (unsigned int)is_signed_type(long));
ret = trace_seq_printf(s, "\tfield: char data;\t"
- "offset:%u;\tsize:%u;\n",
+ "offset:%u;\tsize:%u;\tsigned:%u;\n",
(unsigned int)offsetof(typeof(field), data),
- (unsigned int)BUF_PAGE_SIZE);
+ (unsigned int)BUF_PAGE_SIZE,
+ (unsigned int)is_signed_type(char));
return ret;
}
@@ -483,7 +486,7 @@ struct ring_buffer_iter {
/* Up this if you want to test the TIME_EXTENTS and normalization */
#define DEBUG_SHIFT 0
-static inline u64 rb_time_stamp(struct ring_buffer *buffer, int cpu)
+static inline u64 rb_time_stamp(struct ring_buffer *buffer)
{
/* shift to debug/test normalization and TIME_EXTENTS */
return buffer->clock() << DEBUG_SHIFT;
@@ -494,7 +497,7 @@ u64 ring_buffer_time_stamp(struct ring_buffer *buffer, int cpu)
u64 time;
preempt_disable_notrace();
- time = rb_time_stamp(buffer, cpu);
+ time = rb_time_stamp(buffer);
preempt_enable_no_resched_notrace();
return time;
@@ -599,7 +602,7 @@ static struct list_head *rb_list_head(struct list_head *list)
}
/*
- * rb_is_head_page - test if the give page is the head page
+ * rb_is_head_page - test if the given page is the head page
*
* Because the reader may move the head_page pointer, we can
* not trust what the head page is (it may be pointing to
@@ -1868,7 +1871,7 @@ 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, cpu_buffer->cpu);
+ *ts = rb_time_stamp(buffer);
next_page->page->time_stamp = *ts;
}
@@ -2111,7 +2114,7 @@ rb_reserve_next_event(struct ring_buffer *buffer,
if (RB_WARN_ON(cpu_buffer, ++nr_loops > 1000))
goto out_fail;
- ts = rb_time_stamp(cpu_buffer->buffer, cpu_buffer->cpu);
+ ts = rb_time_stamp(cpu_buffer->buffer);
/*
* Only the first commit can update the timestamp.
@@ -2681,7 +2684,7 @@ unsigned long ring_buffer_entries(struct ring_buffer *buffer)
EXPORT_SYMBOL_GPL(ring_buffer_entries);
/**
- * ring_buffer_overrun_cpu - get the number of overruns in buffer
+ * ring_buffer_overruns - get the number of overruns in buffer
* @buffer: The ring buffer
*
* Returns the total number of overruns in the ring buffer
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index c820b0310a12..1659a74addc0 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -12,7 +12,7 @@
* Copyright (C) 2004 William Lee Irwin III
*/
#include <linux/ring_buffer.h>
-#include <linux/utsrelease.h>
+#include <generated/utsrelease.h>
#include <linux/stacktrace.h>
#include <linux/writeback.h>
#include <linux/kallsyms.h>
@@ -86,17 +86,17 @@ static int dummy_set_flag(u32 old_flags, u32 bit, int set)
*/
static int tracing_disabled = 1;
-DEFINE_PER_CPU(local_t, ftrace_cpu_disabled);
+DEFINE_PER_CPU(int, ftrace_cpu_disabled);
static inline void ftrace_disable_cpu(void)
{
preempt_disable();
- local_inc(&__get_cpu_var(ftrace_cpu_disabled));
+ __this_cpu_inc(per_cpu_var(ftrace_cpu_disabled));
}
static inline void ftrace_enable_cpu(void)
{
- local_dec(&__get_cpu_var(ftrace_cpu_disabled));
+ __this_cpu_dec(per_cpu_var(ftrace_cpu_disabled));
preempt_enable();
}
@@ -129,7 +129,7 @@ static int tracing_set_tracer(const char *buf);
static char bootup_tracer_buf[MAX_TRACER_SIZE] __initdata;
static char *default_bootup_tracer;
-static int __init set_ftrace(char *str)
+static int __init set_cmdline_ftrace(char *str)
{
strncpy(bootup_tracer_buf, str, MAX_TRACER_SIZE);
default_bootup_tracer = bootup_tracer_buf;
@@ -137,7 +137,7 @@ static int __init set_ftrace(char *str)
ring_buffer_expanded = 1;
return 1;
}
-__setup("ftrace=", set_ftrace);
+__setup("ftrace=", set_cmdline_ftrace);
static int __init set_ftrace_dump_on_oops(char *str)
{
@@ -1085,7 +1085,7 @@ trace_function(struct trace_array *tr,
struct ftrace_entry *entry;
/* If we are reading the ring buffer, don't trace */
- if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled))))
+ if (unlikely(__this_cpu_read(per_cpu_var(ftrace_cpu_disabled))))
return;
event = trace_buffer_lock_reserve(buffer, TRACE_FN, sizeof(*entry),
@@ -2440,7 +2440,7 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
return ret;
}
- filp->f_pos += cnt;
+ *ppos += cnt;
return cnt;
}
@@ -2582,7 +2582,7 @@ tracing_ctrl_write(struct file *filp, const char __user *ubuf,
}
mutex_unlock(&trace_types_lock);
- filp->f_pos += cnt;
+ *ppos += cnt;
return cnt;
}
@@ -2764,7 +2764,7 @@ tracing_set_trace_write(struct file *filp, const char __user *ubuf,
if (err)
return err;
- filp->f_pos += ret;
+ *ppos += ret;
return ret;
}
@@ -3299,7 +3299,7 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
}
}
- filp->f_pos += cnt;
+ *ppos += cnt;
/* If check pages failed, return ENOMEM */
if (tracing_disabled)
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 405cb850b75d..b01a5cf6543d 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -101,6 +101,29 @@ struct syscall_trace_exit {
unsigned long ret;
};
+struct kprobe_trace_entry {
+ struct trace_entry ent;
+ unsigned long ip;
+ int nargs;
+ unsigned long args[];
+};
+
+#define SIZEOF_KPROBE_TRACE_ENTRY(n) \
+ (offsetof(struct kprobe_trace_entry, args) + \
+ (sizeof(unsigned long) * (n)))
+
+struct kretprobe_trace_entry {
+ struct trace_entry ent;
+ unsigned long func;
+ unsigned long ret_ip;
+ int nargs;
+ unsigned long args[];
+};
+
+#define SIZEOF_KRETPROBE_TRACE_ENTRY(n) \
+ (offsetof(struct kretprobe_trace_entry, args) + \
+ (sizeof(unsigned long) * (n)))
+
/*
* trace_flag_type is an enumeration that holds different
* states when a trace occurs. These are:
@@ -413,7 +436,7 @@ extern int DYN_FTRACE_TEST_NAME(void);
extern int ring_buffer_expanded;
extern bool tracing_selftest_disabled;
-DECLARE_PER_CPU(local_t, ftrace_cpu_disabled);
+DECLARE_PER_CPU(int, ftrace_cpu_disabled);
#ifdef CONFIG_FTRACE_STARTUP_TEST
extern int trace_selftest_startup_function(struct tracer *trace,
@@ -483,10 +506,6 @@ static inline int ftrace_graph_addr(unsigned long addr)
return 0;
}
#else
-static inline int ftrace_trace_addr(unsigned long addr)
-{
- return 1;
-}
static inline int ftrace_graph_addr(unsigned long addr)
{
return 1;
@@ -500,12 +519,12 @@ print_graph_function(struct trace_iterator *iter)
}
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
-extern struct pid *ftrace_pid_trace;
+extern struct list_head ftrace_pids;
#ifdef CONFIG_FUNCTION_TRACER
static inline int ftrace_trace_task(struct task_struct *task)
{
- if (!ftrace_pid_trace)
+ if (list_empty(&ftrace_pids))
return 1;
return test_tsk_trace_trace(task);
@@ -687,7 +706,6 @@ struct event_filter {
int n_preds;
struct filter_pred **preds;
char *filter_string;
- bool no_reset;
};
struct event_subsystem {
@@ -699,22 +717,40 @@ struct event_subsystem {
};
struct filter_pred;
+struct regex;
typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event,
int val1, int val2);
+typedef int (*regex_match_func)(char *str, struct regex *r, int len);
+
+enum regex_type {
+ MATCH_FULL = 0,
+ MATCH_FRONT_ONLY,
+ MATCH_MIDDLE_ONLY,
+ MATCH_END_ONLY,
+};
+
+struct regex {
+ char pattern[MAX_FILTER_STR_VAL];
+ int len;
+ int field_len;
+ regex_match_func match;
+};
+
struct filter_pred {
- filter_pred_fn_t fn;
- u64 val;
- char str_val[MAX_FILTER_STR_VAL];
- int str_len;
- char *field_name;
- int offset;
- int not;
- int op;
- int pop_n;
+ filter_pred_fn_t fn;
+ u64 val;
+ struct regex regex;
+ char *field_name;
+ int offset;
+ int not;
+ int op;
+ int pop_n;
};
+extern enum regex_type
+filter_parse_regex(char *buff, int len, char **search, int *not);
extern void print_event_filter(struct ftrace_event_call *call,
struct trace_seq *s);
extern int apply_event_filter(struct ftrace_event_call *call,
@@ -730,7 +766,8 @@ filter_check_discard(struct ftrace_event_call *call, void *rec,
struct ring_buffer *buffer,
struct ring_buffer_event *event)
{
- if (unlikely(call->filter_active) && !filter_match_preds(call, rec)) {
+ if (unlikely(call->filter_active) &&
+ !filter_match_preds(call->filter, rec)) {
ring_buffer_discard_commit(buffer, event);
return 1;
}
diff --git a/kernel/trace/trace_event_profile.c b/kernel/trace/trace_event_profile.c
index 8d5c171cc998..c9f687ab0d4f 100644
--- a/kernel/trace/trace_event_profile.c
+++ b/kernel/trace/trace_event_profile.c
@@ -45,7 +45,7 @@ static int ftrace_profile_enable_event(struct ftrace_event_call *event)
rcu_assign_pointer(trace_profile_buf_nmi, buf);
}
- ret = event->profile_enable();
+ ret = event->profile_enable(event);
if (!ret) {
total_profile_count++;
return 0;
@@ -89,7 +89,7 @@ static void ftrace_profile_disable_event(struct ftrace_event_call *event)
if (!atomic_add_negative(-1, &event->profile_count))
return;
- event->profile_disable();
+ event->profile_disable(event);
if (!--total_profile_count) {
buf = trace_profile_buf;
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index d128f65778e6..1d18315dc836 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -93,9 +93,7 @@ int trace_define_common_fields(struct ftrace_event_call *call)
}
EXPORT_SYMBOL_GPL(trace_define_common_fields);
-#ifdef CONFIG_MODULES
-
-static void trace_destroy_fields(struct ftrace_event_call *call)
+void trace_destroy_fields(struct ftrace_event_call *call)
{
struct ftrace_event_field *field, *next;
@@ -107,8 +105,6 @@ static void trace_destroy_fields(struct ftrace_event_call *call)
}
}
-#endif /* CONFIG_MODULES */
-
static void ftrace_event_enable_disable(struct ftrace_event_call *call,
int enable)
{
@@ -117,14 +113,14 @@ static void ftrace_event_enable_disable(struct ftrace_event_call *call,
if (call->enabled) {
call->enabled = 0;
tracing_stop_cmdline_record();
- call->unregfunc(call->data);
+ call->unregfunc(call);
}
break;
case 1:
if (!call->enabled) {
call->enabled = 1;
tracing_start_cmdline_record();
- call->regfunc(call->data);
+ call->regfunc(call);
}
break;
}
@@ -507,7 +503,7 @@ extern char *__bad_type_size(void);
#define FIELD(type, name) \
sizeof(type) != sizeof(field.name) ? __bad_type_size() : \
#type, "common_" #name, offsetof(typeof(field), name), \
- sizeof(field.name)
+ sizeof(field.name), is_signed_type(type)
static int trace_write_header(struct trace_seq *s)
{
@@ -515,17 +511,17 @@ static int trace_write_header(struct trace_seq *s)
/* struct trace_entry */
return trace_seq_printf(s,
- "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
- "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
- "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
- "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
- "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
- "\n",
- FIELD(unsigned short, type),
- FIELD(unsigned char, flags),
- FIELD(unsigned char, preempt_count),
- FIELD(int, pid),
- FIELD(int, lock_depth));
+ "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
+ "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
+ "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
+ "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
+ "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n"
+ "\n",
+ FIELD(unsigned short, type),
+ FIELD(unsigned char, flags),
+ FIELD(unsigned char, preempt_count),
+ FIELD(int, pid),
+ FIELD(int, lock_depth));
}
static ssize_t
@@ -878,9 +874,9 @@ event_subsystem_dir(const char *name, struct dentry *d_events)
"'%s/filter' entry\n", name);
}
- entry = trace_create_file("enable", 0644, system->entry,
- (void *)system->name,
- &ftrace_system_enable_fops);
+ trace_create_file("enable", 0644, system->entry,
+ (void *)system->name,
+ &ftrace_system_enable_fops);
return system->entry;
}
@@ -892,7 +888,6 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
const struct file_operations *filter,
const struct file_operations *format)
{
- struct dentry *entry;
int ret;
/*
@@ -910,12 +905,12 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
}
if (call->regfunc)
- entry = trace_create_file("enable", 0644, call->dir, call,
- enable);
+ trace_create_file("enable", 0644, call->dir, call,
+ enable);
if (call->id && call->profile_enable)
- entry = trace_create_file("id", 0444, call->dir, call,
- id);
+ trace_create_file("id", 0444, call->dir, call,
+ id);
if (call->define_fields) {
ret = call->define_fields(call);
@@ -924,41 +919,60 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
" events/%s\n", call->name);
return ret;
}
- entry = trace_create_file("filter", 0644, call->dir, call,
- filter);
+ trace_create_file("filter", 0644, call->dir, call,
+ filter);
}
/* A trace may not want to export its format */
if (!call->show_format)
return 0;
- entry = trace_create_file("format", 0444, call->dir, call,
- format);
+ trace_create_file("format", 0444, call->dir, call,
+ format);
return 0;
}
-#define for_each_event(event, start, end) \
- for (event = start; \
- (unsigned long)event < (unsigned long)end; \
- event++)
+static int __trace_add_event_call(struct ftrace_event_call *call)
+{
+ struct dentry *d_events;
+ int ret;
-#ifdef CONFIG_MODULES
+ if (!call->name)
+ return -EINVAL;
-static LIST_HEAD(ftrace_module_file_list);
+ if (call->raw_init) {
+ ret = call->raw_init(call);
+ if (ret < 0) {
+ if (ret != -ENOSYS)
+ pr_warning("Could not initialize trace "
+ "events/%s\n", call->name);
+ return ret;
+ }
+ }
-/*
- * Modules must own their file_operations to keep up with
- * reference counting.
- */
-struct ftrace_module_file_ops {
- struct list_head list;
- struct module *mod;
- struct file_operations id;
- struct file_operations enable;
- struct file_operations format;
- struct file_operations filter;
-};
+ d_events = event_trace_events_dir();
+ if (!d_events)
+ return -ENOENT;
+
+ ret = event_create_dir(call, d_events, &ftrace_event_id_fops,
+ &ftrace_enable_fops, &ftrace_event_filter_fops,
+ &ftrace_event_format_fops);
+ if (!ret)
+ list_add(&call->list, &ftrace_events);
+
+ return ret;
+}
+
+/* Add an additional event_call dynamically */
+int trace_add_event_call(struct ftrace_event_call *call)
+{
+ int ret;
+ mutex_lock(&event_mutex);
+ ret = __trace_add_event_call(call);
+ mutex_unlock(&event_mutex);
+ return ret;
+}
static void remove_subsystem_dir(const char *name)
{
@@ -986,6 +1000,53 @@ static void remove_subsystem_dir(const char *name)
}
}
+/*
+ * Must be called under locking both of event_mutex and trace_event_mutex.
+ */
+static void __trace_remove_event_call(struct ftrace_event_call *call)
+{
+ ftrace_event_enable_disable(call, 0);
+ if (call->event)
+ __unregister_ftrace_event(call->event);
+ debugfs_remove_recursive(call->dir);
+ list_del(&call->list);
+ trace_destroy_fields(call);
+ destroy_preds(call);
+ remove_subsystem_dir(call->system);
+}
+
+/* Remove an event_call */
+void trace_remove_event_call(struct ftrace_event_call *call)
+{
+ mutex_lock(&event_mutex);
+ down_write(&trace_event_mutex);
+ __trace_remove_event_call(call);
+ up_write(&trace_event_mutex);
+ mutex_unlock(&event_mutex);
+}
+
+#define for_each_event(event, start, end) \
+ for (event = start; \
+ (unsigned long)event < (unsigned long)end; \
+ event++)
+
+#ifdef CONFIG_MODULES
+
+static LIST_HEAD(ftrace_module_file_list);
+
+/*
+ * Modules must own their file_operations to keep up with
+ * reference counting.
+ */
+struct ftrace_module_file_ops {
+ struct list_head list;
+ struct module *mod;
+ struct file_operations id;
+ struct file_operations enable;
+ struct file_operations format;
+ struct file_operations filter;
+};
+
static struct ftrace_module_file_ops *
trace_create_file_ops(struct module *mod)
{
@@ -1043,7 +1104,7 @@ static void trace_module_add_events(struct module *mod)
if (!call->name)
continue;
if (call->raw_init) {
- ret = call->raw_init();
+ ret = call->raw_init(call);
if (ret < 0) {
if (ret != -ENOSYS)
pr_warning("Could not initialize trace "
@@ -1061,10 +1122,11 @@ static void trace_module_add_events(struct module *mod)
return;
}
call->mod = mod;
- list_add(&call->list, &ftrace_events);
- event_create_dir(call, d_events,
- &file_ops->id, &file_ops->enable,
- &file_ops->filter, &file_ops->format);
+ ret = event_create_dir(call, d_events,
+ &file_ops->id, &file_ops->enable,
+ &file_ops->filter, &file_ops->format);
+ if (!ret)
+ list_add(&call->list, &ftrace_events);
}
}
@@ -1078,14 +1140,7 @@ static void trace_module_remove_events(struct module *mod)
list_for_each_entry_safe(call, p, &ftrace_events, list) {
if (call->mod == mod) {
found = true;
- ftrace_event_enable_disable(call, 0);
- if (call->event)
- __unregister_ftrace_event(call->event);
- debugfs_remove_recursive(call->dir);
- list_del(&call->list);
- trace_destroy_fields(call);
- destroy_preds(call);
- remove_subsystem_dir(call->system);
+ __trace_remove_event_call(call);
}
}
@@ -1203,7 +1258,7 @@ static __init int event_trace_init(void)
if (!call->name)
continue;
if (call->raw_init) {
- ret = call->raw_init();
+ ret = call->raw_init(call);
if (ret < 0) {
if (ret != -ENOSYS)
pr_warning("Could not initialize trace "
@@ -1211,10 +1266,12 @@ static __init int event_trace_init(void)
continue;
}
}
- list_add(&call->list, &ftrace_events);
- event_create_dir(call, d_events, &ftrace_event_id_fops,
- &ftrace_enable_fops, &ftrace_event_filter_fops,
- &ftrace_event_format_fops);
+ ret = event_create_dir(call, d_events, &ftrace_event_id_fops,
+ &ftrace_enable_fops,
+ &ftrace_event_filter_fops,
+ &ftrace_event_format_fops);
+ if (!ret)
+ list_add(&call->list, &ftrace_events);
}
while (true) {
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 98a6cc5c64ed..21d34757b955 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -18,11 +18,10 @@
* Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
*/
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/ctype.h>
#include <linux/mutex.h>
+#include <linux/perf_event.h>
#include "trace.h"
#include "trace_output.h"
@@ -31,6 +30,7 @@ enum filter_op_ids
{
OP_OR,
OP_AND,
+ OP_GLOB,
OP_NE,
OP_EQ,
OP_LT,
@@ -48,16 +48,17 @@ struct filter_op {
};
static struct filter_op filter_ops[] = {
- { OP_OR, "||", 1 },
- { OP_AND, "&&", 2 },
- { OP_NE, "!=", 4 },
- { OP_EQ, "==", 4 },
- { OP_LT, "<", 5 },
- { OP_LE, "<=", 5 },
- { OP_GT, ">", 5 },
- { OP_GE, ">=", 5 },
- { OP_NONE, "OP_NONE", 0 },
- { OP_OPEN_PAREN, "(", 0 },
+ { OP_OR, "||", 1 },
+ { OP_AND, "&&", 2 },
+ { OP_GLOB, "~", 4 },
+ { OP_NE, "!=", 4 },
+ { OP_EQ, "==", 4 },
+ { OP_LT, "<", 5 },
+ { OP_LE, "<=", 5 },
+ { OP_GT, ">", 5 },
+ { OP_GE, ">=", 5 },
+ { OP_NONE, "OP_NONE", 0 },
+ { OP_OPEN_PAREN, "(", 0 },
};
enum {
@@ -197,9 +198,9 @@ static int filter_pred_string(struct filter_pred *pred, void *event,
char *addr = (char *)(event + pred->offset);
int cmp, match;
- cmp = strncmp(addr, pred->str_val, pred->str_len);
+ cmp = pred->regex.match(addr, &pred->regex, pred->regex.field_len);
- match = (!cmp) ^ pred->not;
+ match = cmp ^ pred->not;
return match;
}
@@ -211,9 +212,9 @@ static int filter_pred_pchar(struct filter_pred *pred, void *event,
char **addr = (char **)(event + pred->offset);
int cmp, match;
- cmp = strncmp(*addr, pred->str_val, pred->str_len);
+ cmp = pred->regex.match(*addr, &pred->regex, pred->regex.field_len);
- match = (!cmp) ^ pred->not;
+ match = cmp ^ pred->not;
return match;
}
@@ -237,9 +238,9 @@ static int filter_pred_strloc(struct filter_pred *pred, void *event,
char *addr = (char *)(event + str_loc);
int cmp, match;
- cmp = strncmp(addr, pred->str_val, str_len);
+ cmp = pred->regex.match(addr, &pred->regex, str_len);
- match = (!cmp) ^ pred->not;
+ match = cmp ^ pred->not;
return match;
}
@@ -250,10 +251,121 @@ static int filter_pred_none(struct filter_pred *pred, void *event,
return 0;
}
+/* Basic regex callbacks */
+static int regex_match_full(char *str, struct regex *r, int len)
+{
+ if (strncmp(str, r->pattern, len) == 0)
+ return 1;
+ return 0;
+}
+
+static int regex_match_front(char *str, struct regex *r, int len)
+{
+ if (strncmp(str, r->pattern, len) == 0)
+ return 1;
+ return 0;
+}
+
+static int regex_match_middle(char *str, struct regex *r, int len)
+{
+ if (strstr(str, r->pattern))
+ return 1;
+ return 0;
+}
+
+static int regex_match_end(char *str, struct regex *r, int len)
+{
+ char *ptr = strstr(str, r->pattern);
+
+ if (ptr && (ptr[r->len] == 0))
+ return 1;
+ return 0;
+}
+
+/**
+ * filter_parse_regex - parse a basic regex
+ * @buff: the raw regex
+ * @len: length of the regex
+ * @search: will point to the beginning of the string to compare
+ * @not: tell whether the match will have to be inverted
+ *
+ * This passes in a buffer containing a regex and this function will
+ * set search to point to the search part of the buffer and
+ * return the type of search it is (see enum above).
+ * This does modify buff.
+ *
+ * Returns enum type.
+ * search returns the pointer to use for comparison.
+ * not returns 1 if buff started with a '!'
+ * 0 otherwise.
+ */
+enum regex_type filter_parse_regex(char *buff, int len, char **search, int *not)
+{
+ int type = MATCH_FULL;
+ int i;
+
+ if (buff[0] == '!') {
+ *not = 1;
+ buff++;
+ len--;
+ } else
+ *not = 0;
+
+ *search = buff;
+
+ for (i = 0; i < len; i++) {
+ if (buff[i] == '*') {
+ if (!i) {
+ *search = buff + 1;
+ type = MATCH_END_ONLY;
+ } else {
+ if (type == MATCH_END_ONLY)
+ type = MATCH_MIDDLE_ONLY;
+ else
+ type = MATCH_FRONT_ONLY;
+ buff[i] = 0;
+ break;
+ }
+ }
+ }
+
+ return type;
+}
+
+static void filter_build_regex(struct filter_pred *pred)
+{
+ struct regex *r = &pred->regex;
+ char *search;
+ enum regex_type type = MATCH_FULL;
+ int not = 0;
+
+ if (pred->op == OP_GLOB) {
+ type = filter_parse_regex(r->pattern, r->len, &search, &not);
+ r->len = strlen(search);
+ memmove(r->pattern, search, r->len+1);
+ }
+
+ switch (type) {
+ case MATCH_FULL:
+ r->match = regex_match_full;
+ break;
+ case MATCH_FRONT_ONLY:
+ r->match = regex_match_front;
+ break;
+ case MATCH_MIDDLE_ONLY:
+ r->match = regex_match_middle;
+ break;
+ case MATCH_END_ONLY:
+ r->match = regex_match_end;
+ break;
+ }
+
+ pred->not ^= not;
+}
+
/* return 1 if event matches, 0 otherwise (discard) */
-int filter_match_preds(struct ftrace_event_call *call, void *rec)
+int filter_match_preds(struct event_filter *filter, void *rec)
{
- struct event_filter *filter = call->filter;
int match, top = 0, val1 = 0, val2 = 0;
int stack[MAX_FILTER_PRED];
struct filter_pred *pred;
@@ -396,7 +508,7 @@ static void filter_clear_pred(struct filter_pred *pred)
{
kfree(pred->field_name);
pred->field_name = NULL;
- pred->str_len = 0;
+ pred->regex.len = 0;
}
static int filter_set_pred(struct filter_pred *dest,
@@ -426,9 +538,8 @@ static void filter_disable_preds(struct ftrace_event_call *call)
filter->preds[i]->fn = filter_pred_none;
}
-void destroy_preds(struct ftrace_event_call *call)
+static void __free_preds(struct event_filter *filter)
{
- struct event_filter *filter = call->filter;
int i;
if (!filter)
@@ -441,21 +552,24 @@ void destroy_preds(struct ftrace_event_call *call)
kfree(filter->preds);
kfree(filter->filter_string);
kfree(filter);
+}
+
+void destroy_preds(struct ftrace_event_call *call)
+{
+ __free_preds(call->filter);
call->filter = NULL;
+ call->filter_active = 0;
}
-static int init_preds(struct ftrace_event_call *call)
+static struct event_filter *__alloc_preds(void)
{
struct event_filter *filter;
struct filter_pred *pred;
int i;
- if (call->filter)
- return 0;
-
- filter = call->filter = kzalloc(sizeof(*filter), GFP_KERNEL);
- if (!call->filter)
- return -ENOMEM;
+ filter = kzalloc(sizeof(*filter), GFP_KERNEL);
+ if (!filter)
+ return ERR_PTR(-ENOMEM);
filter->n_preds = 0;
@@ -471,12 +585,24 @@ static int init_preds(struct ftrace_event_call *call)
filter->preds[i] = pred;
}
- return 0;
+ return filter;
oom:
- destroy_preds(call);
+ __free_preds(filter);
+ return ERR_PTR(-ENOMEM);
+}
+
+static int init_preds(struct ftrace_event_call *call)
+{
+ if (call->filter)
+ return 0;
- return -ENOMEM;
+ call->filter_active = 0;
+ call->filter = __alloc_preds();
+ if (IS_ERR(call->filter))
+ return PTR_ERR(call->filter);
+
+ return 0;
}
static int init_subsystem_preds(struct event_subsystem *system)
@@ -499,14 +625,7 @@ static int init_subsystem_preds(struct event_subsystem *system)
return 0;
}
-enum {
- FILTER_DISABLE_ALL,
- FILTER_INIT_NO_RESET,
- FILTER_SKIP_NO_RESET,
-};
-
-static void filter_free_subsystem_preds(struct event_subsystem *system,
- int flag)
+static void filter_free_subsystem_preds(struct event_subsystem *system)
{
struct ftrace_event_call *call;
@@ -517,14 +636,6 @@ static void filter_free_subsystem_preds(struct event_subsystem *system,
if (strcmp(call->system, system->name) != 0)
continue;
- if (flag == FILTER_INIT_NO_RESET) {
- call->filter->no_reset = false;
- continue;
- }
-
- if (flag == FILTER_SKIP_NO_RESET && call->filter->no_reset)
- continue;
-
filter_disable_preds(call);
remove_filter_string(call->filter);
}
@@ -532,10 +643,10 @@ static void filter_free_subsystem_preds(struct event_subsystem *system,
static int filter_add_pred_fn(struct filter_parse_state *ps,
struct ftrace_event_call *call,
+ struct event_filter *filter,
struct filter_pred *pred,
filter_pred_fn_t fn)
{
- struct event_filter *filter = call->filter;
int idx, err;
if (filter->n_preds == MAX_FILTER_PRED) {
@@ -550,7 +661,6 @@ static int filter_add_pred_fn(struct filter_parse_state *ps,
return err;
filter->n_preds++;
- call->filter_active = 1;
return 0;
}
@@ -575,7 +685,10 @@ static bool is_string_field(struct ftrace_event_field *field)
static int is_legal_op(struct ftrace_event_field *field, int op)
{
- if (is_string_field(field) && (op != OP_EQ && op != OP_NE))
+ if (is_string_field(field) &&
+ (op != OP_EQ && op != OP_NE && op != OP_GLOB))
+ return 0;
+ if (!is_string_field(field) && op == OP_GLOB)
return 0;
return 1;
@@ -626,6 +739,7 @@ static filter_pred_fn_t select_comparison_fn(int op, int field_size,
static int filter_add_pred(struct filter_parse_state *ps,
struct ftrace_event_call *call,
+ struct event_filter *filter,
struct filter_pred *pred,
bool dry_run)
{
@@ -660,21 +774,22 @@ static int filter_add_pred(struct filter_parse_state *ps,
}
if (is_string_field(field)) {
- pred->str_len = field->size;
+ filter_build_regex(pred);
- if (field->filter_type == FILTER_STATIC_STRING)
+ if (field->filter_type == FILTER_STATIC_STRING) {
fn = filter_pred_string;
- else if (field->filter_type == FILTER_DYN_STRING)
+ pred->regex.field_len = field->size;
+ } else if (field->filter_type == FILTER_DYN_STRING)
fn = filter_pred_strloc;
else {
fn = filter_pred_pchar;
- pred->str_len = strlen(pred->str_val);
+ pred->regex.field_len = strlen(pred->regex.pattern);
}
} else {
if (field->is_signed)
- ret = strict_strtoll(pred->str_val, 0, &val);
+ ret = strict_strtoll(pred->regex.pattern, 0, &val);
else
- ret = strict_strtoull(pred->str_val, 0, &val);
+ ret = strict_strtoull(pred->regex.pattern, 0, &val);
if (ret) {
parse_error(ps, FILT_ERR_ILLEGAL_INTVAL, 0);
return -EINVAL;
@@ -694,45 +809,7 @@ static int filter_add_pred(struct filter_parse_state *ps,
add_pred_fn:
if (!dry_run)
- return filter_add_pred_fn(ps, call, pred, fn);
- return 0;
-}
-
-static int filter_add_subsystem_pred(struct filter_parse_state *ps,
- struct event_subsystem *system,
- struct filter_pred *pred,
- char *filter_string,
- bool dry_run)
-{
- struct ftrace_event_call *call;
- int err = 0;
- bool fail = true;
-
- list_for_each_entry(call, &ftrace_events, list) {
-
- if (!call->define_fields)
- continue;
-
- if (strcmp(call->system, system->name))
- continue;
-
- if (call->filter->no_reset)
- continue;
-
- err = filter_add_pred(ps, call, pred, dry_run);
- if (err)
- call->filter->no_reset = true;
- else
- fail = false;
-
- if (!dry_run)
- replace_filter_string(call->filter, filter_string);
- }
-
- if (fail) {
- parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0);
- return err;
- }
+ return filter_add_pred_fn(ps, call, filter, pred, fn);
return 0;
}
@@ -1045,8 +1122,8 @@ static struct filter_pred *create_pred(int op, char *operand1, char *operand2)
return NULL;
}
- strcpy(pred->str_val, operand2);
- pred->str_len = strlen(operand2);
+ strcpy(pred->regex.pattern, operand2);
+ pred->regex.len = strlen(pred->regex.pattern);
pred->op = op;
@@ -1090,8 +1167,8 @@ static int check_preds(struct filter_parse_state *ps)
return 0;
}
-static int replace_preds(struct event_subsystem *system,
- struct ftrace_event_call *call,
+static int replace_preds(struct ftrace_event_call *call,
+ struct event_filter *filter,
struct filter_parse_state *ps,
char *filter_string,
bool dry_run)
@@ -1138,11 +1215,7 @@ static int replace_preds(struct event_subsystem *system,
add_pred:
if (!pred)
return -ENOMEM;
- if (call)
- err = filter_add_pred(ps, call, pred, false);
- else
- err = filter_add_subsystem_pred(ps, system, pred,
- filter_string, dry_run);
+ err = filter_add_pred(ps, call, filter, pred, dry_run);
filter_free_pred(pred);
if (err)
return err;
@@ -1153,10 +1226,50 @@ add_pred:
return 0;
}
-int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
+static int replace_system_preds(struct event_subsystem *system,
+ struct filter_parse_state *ps,
+ char *filter_string)
{
+ struct event_filter *filter = system->filter;
+ struct ftrace_event_call *call;
+ bool fail = true;
int err;
+ list_for_each_entry(call, &ftrace_events, list) {
+
+ if (!call->define_fields)
+ continue;
+
+ if (strcmp(call->system, system->name) != 0)
+ continue;
+
+ /* try to see if the filter can be applied */
+ err = replace_preds(call, filter, ps, filter_string, true);
+ if (err)
+ continue;
+
+ /* really apply the filter */
+ filter_disable_preds(call);
+ err = replace_preds(call, filter, ps, filter_string, false);
+ if (err)
+ filter_disable_preds(call);
+ else {
+ call->filter_active = 1;
+ replace_filter_string(filter, filter_string);
+ }
+ fail = false;
+ }
+
+ if (fail) {
+ parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
+{
+ int err;
struct filter_parse_state *ps;
mutex_lock(&event_mutex);
@@ -1168,8 +1281,7 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
if (!strcmp(strstrip(filter_string), "0")) {
filter_disable_preds(call);
remove_filter_string(call->filter);
- mutex_unlock(&event_mutex);
- return 0;
+ goto out_unlock;
}
err = -ENOMEM;
@@ -1187,10 +1299,11 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
goto out;
}
- err = replace_preds(NULL, call, ps, filter_string, false);
+ err = replace_preds(call, call->filter, ps, filter_string, false);
if (err)
append_filter_err(ps, call->filter);
-
+ else
+ call->filter_active = 1;
out:
filter_opstack_clear(ps);
postfix_clear(ps);
@@ -1205,7 +1318,6 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
char *filter_string)
{
int err;
-
struct filter_parse_state *ps;
mutex_lock(&event_mutex);
@@ -1215,10 +1327,9 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
goto out_unlock;
if (!strcmp(strstrip(filter_string), "0")) {
- filter_free_subsystem_preds(system, FILTER_DISABLE_ALL);
+ filter_free_subsystem_preds(system);
remove_filter_string(system->filter);
- mutex_unlock(&event_mutex);
- return 0;
+ goto out_unlock;
}
err = -ENOMEM;
@@ -1235,31 +1346,87 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
goto out;
}
- filter_free_subsystem_preds(system, FILTER_INIT_NO_RESET);
-
- /* try to see the filter can be applied to which events */
- err = replace_preds(system, NULL, ps, filter_string, true);
- if (err) {
+ err = replace_system_preds(system, ps, filter_string);
+ if (err)
append_filter_err(ps, system->filter);
- goto out;
+
+out:
+ filter_opstack_clear(ps);
+ postfix_clear(ps);
+ kfree(ps);
+out_unlock:
+ mutex_unlock(&event_mutex);
+
+ return err;
+}
+
+#ifdef CONFIG_EVENT_PROFILE
+
+void ftrace_profile_free_filter(struct perf_event *event)
+{
+ struct event_filter *filter = event->filter;
+
+ event->filter = NULL;
+ __free_preds(filter);
+}
+
+int ftrace_profile_set_filter(struct perf_event *event, int event_id,
+ char *filter_str)
+{
+ int err;
+ struct event_filter *filter;
+ struct filter_parse_state *ps;
+ struct ftrace_event_call *call = NULL;
+
+ mutex_lock(&event_mutex);
+
+ list_for_each_entry(call, &ftrace_events, list) {
+ if (call->id == event_id)
+ break;
}
- filter_free_subsystem_preds(system, FILTER_SKIP_NO_RESET);
+ err = -EINVAL;
+ if (!call)
+ goto out_unlock;
- /* really apply the filter to the events */
- err = replace_preds(system, NULL, ps, filter_string, false);
- if (err) {
- append_filter_err(ps, system->filter);
- filter_free_subsystem_preds(system, 2);
+ err = -EEXIST;
+ if (event->filter)
+ goto out_unlock;
+
+ filter = __alloc_preds();
+ if (IS_ERR(filter)) {
+ err = PTR_ERR(filter);
+ goto out_unlock;
}
-out:
+ err = -ENOMEM;
+ ps = kzalloc(sizeof(*ps), GFP_KERNEL);
+ if (!ps)
+ goto free_preds;
+
+ parse_init(ps, filter_ops, filter_str);
+ err = filter_parse(ps);
+ if (err)
+ goto free_ps;
+
+ err = replace_preds(call, filter, ps, filter_str, false);
+ if (!err)
+ event->filter = filter;
+
+free_ps:
filter_opstack_clear(ps);
postfix_clear(ps);
kfree(ps);
+
+free_preds:
+ if (err)
+ __free_preds(filter);
+
out_unlock:
mutex_unlock(&event_mutex);
return err;
}
+#endif /* CONFIG_EVENT_PROFILE */
+
diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c
index 9753fcc61bc5..934d81fb4ca4 100644
--- a/kernel/trace/trace_export.c
+++ b/kernel/trace/trace_export.c
@@ -66,44 +66,47 @@ static void __used ____ftrace_check_##name(void) \
#undef __field
#define __field(type, item) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \
- "offset:%zu;\tsize:%zu;\n", \
+ "offset:%zu;\tsize:%zu;\tsigned:%u;\n", \
offsetof(typeof(field), item), \
- sizeof(field.item)); \
+ sizeof(field.item), is_signed_type(type)); \
if (!ret) \
return 0;
#undef __field_desc
#define __field_desc(type, container, item) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \
- "offset:%zu;\tsize:%zu;\n", \
+ "offset:%zu;\tsize:%zu;\tsigned:%u;\n", \
offsetof(typeof(field), container.item), \
- sizeof(field.container.item)); \
+ sizeof(field.container.item), \
+ is_signed_type(type)); \
if (!ret) \
return 0;
#undef __array
#define __array(type, item, len) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \
- "offset:%zu;\tsize:%zu;\n", \
- offsetof(typeof(field), item), \
- sizeof(field.item)); \
+ "offset:%zu;\tsize:%zu;\tsigned:%u;\n", \
+ offsetof(typeof(field), item), \
+ sizeof(field.item), is_signed_type(type)); \
if (!ret) \
return 0;
#undef __array_desc
#define __array_desc(type, container, item, len) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \
- "offset:%zu;\tsize:%zu;\n", \
+ "offset:%zu;\tsize:%zu;\tsigned:%u;\n", \
offsetof(typeof(field), container.item), \
- sizeof(field.container.item)); \
+ sizeof(field.container.item), \
+ is_signed_type(type)); \
if (!ret) \
return 0;
#undef __dynamic_array
#define __dynamic_array(type, item) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \
- "offset:%zu;\tsize:0;\n", \
- offsetof(typeof(field), item)); \
+ "offset:%zu;\tsize:0;\tsigned:%u;\n", \
+ offsetof(typeof(field), item), \
+ is_signed_type(type)); \
if (!ret) \
return 0;
@@ -131,7 +134,6 @@ ftrace_format_##name(struct ftrace_event_call *unused, \
#include "trace_entries.h"
-
#undef __field
#define __field(type, item) \
ret = trace_define_field(event_call, #type, #item, \
@@ -193,6 +195,11 @@ ftrace_define_fields_##name(struct ftrace_event_call *event_call) \
#include "trace_entries.h"
+static int ftrace_raw_init_event(struct ftrace_event_call *call)
+{
+ INIT_LIST_HEAD(&call->fields);
+ return 0;
+}
#undef __field
#define __field(type, item)
@@ -211,7 +218,6 @@ ftrace_define_fields_##name(struct ftrace_event_call *event_call) \
#undef FTRACE_ENTRY
#define FTRACE_ENTRY(call, struct_name, type, tstruct, print) \
-static int ftrace_raw_init_event_##call(void); \
\
struct ftrace_event_call __used \
__attribute__((__aligned__(4))) \
@@ -219,14 +225,9 @@ __attribute__((section("_ftrace_events"))) event_##call = { \
.name = #call, \
.id = type, \
.system = __stringify(TRACE_SYSTEM), \
- .raw_init = ftrace_raw_init_event_##call, \
+ .raw_init = ftrace_raw_init_event, \
.show_format = ftrace_format_##call, \
.define_fields = ftrace_define_fields_##call, \
}; \
-static int ftrace_raw_init_event_##call(void) \
-{ \
- INIT_LIST_HEAD(&event_##call.fields); \
- return 0; \
-} \
#include "trace_entries.h"
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
index 45e6c01b2e4d..90a6daa10962 100644
--- a/kernel/trace/trace_functions_graph.c
+++ b/kernel/trace/trace_functions_graph.c
@@ -176,7 +176,7 @@ static int __trace_graph_entry(struct trace_array *tr,
struct ring_buffer *buffer = tr->buffer;
struct ftrace_graph_ent_entry *entry;
- if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled))))
+ if (unlikely(__this_cpu_read(per_cpu_var(ftrace_cpu_disabled))))
return 0;
event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_ENT,
@@ -240,7 +240,7 @@ static void __trace_graph_return(struct trace_array *tr,
struct ring_buffer *buffer = tr->buffer;
struct ftrace_graph_ret_entry *entry;
- if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled))))
+ if (unlikely(__this_cpu_read(per_cpu_var(ftrace_cpu_disabled))))
return;
event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_RET,
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
new file mode 100644
index 000000000000..b8ef707c84d7
--- /dev/null
+++ b/kernel/trace/trace_kprobe.c
@@ -0,0 +1,1479 @@
+/*
+ * kprobe based kernel tracer
+ *
+ * Created by Masami Hiramatsu <mhiramat@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/uaccess.h>
+#include <linux/kprobes.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/debugfs.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/ptrace.h>
+#include <linux/perf_event.h>
+
+#include "trace.h"
+#include "trace_output.h"
+
+#define MAX_TRACE_ARGS 128
+#define MAX_ARGSTR_LEN 63
+#define MAX_EVENT_NAME_LEN 64
+#define KPROBE_EVENT_SYSTEM "kprobes"
+
+/* Reserved field names */
+#define FIELD_STRING_IP "__probe_ip"
+#define FIELD_STRING_NARGS "__probe_nargs"
+#define FIELD_STRING_RETIP "__probe_ret_ip"
+#define FIELD_STRING_FUNC "__probe_func"
+
+const char *reserved_field_names[] = {
+ "common_type",
+ "common_flags",
+ "common_preempt_count",
+ "common_pid",
+ "common_tgid",
+ "common_lock_depth",
+ FIELD_STRING_IP,
+ FIELD_STRING_NARGS,
+ FIELD_STRING_RETIP,
+ FIELD_STRING_FUNC,
+};
+
+/* currently, trace_kprobe only supports X86. */
+
+struct fetch_func {
+ unsigned long (*func)(struct pt_regs *, void *);
+ void *data;
+};
+
+static __kprobes unsigned long call_fetch(struct fetch_func *f,
+ struct pt_regs *regs)
+{
+ return f->func(regs, f->data);
+}
+
+/* fetch handlers */
+static __kprobes unsigned long fetch_register(struct pt_regs *regs,
+ void *offset)
+{
+ return regs_get_register(regs, (unsigned int)((unsigned long)offset));
+}
+
+static __kprobes unsigned long fetch_stack(struct pt_regs *regs,
+ void *num)
+{
+ return regs_get_kernel_stack_nth(regs,
+ (unsigned int)((unsigned long)num));
+}
+
+static __kprobes unsigned long fetch_memory(struct pt_regs *regs, void *addr)
+{
+ unsigned long retval;
+
+ if (probe_kernel_address(addr, retval))
+ return 0;
+ return retval;
+}
+
+static __kprobes unsigned long fetch_argument(struct pt_regs *regs, void *num)
+{
+ return regs_get_argument_nth(regs, (unsigned int)((unsigned long)num));
+}
+
+static __kprobes unsigned long fetch_retvalue(struct pt_regs *regs,
+ void *dummy)
+{
+ return regs_return_value(regs);
+}
+
+static __kprobes unsigned long fetch_stack_address(struct pt_regs *regs,
+ void *dummy)
+{
+ return kernel_stack_pointer(regs);
+}
+
+/* Memory fetching by symbol */
+struct symbol_cache {
+ char *symbol;
+ long offset;
+ unsigned long addr;
+};
+
+static unsigned long update_symbol_cache(struct symbol_cache *sc)
+{
+ sc->addr = (unsigned long)kallsyms_lookup_name(sc->symbol);
+ if (sc->addr)
+ sc->addr += sc->offset;
+ return sc->addr;
+}
+
+static void free_symbol_cache(struct symbol_cache *sc)
+{
+ kfree(sc->symbol);
+ kfree(sc);
+}
+
+static struct symbol_cache *alloc_symbol_cache(const char *sym, long offset)
+{
+ struct symbol_cache *sc;
+
+ if (!sym || strlen(sym) == 0)
+ return NULL;
+ sc = kzalloc(sizeof(struct symbol_cache), GFP_KERNEL);
+ if (!sc)
+ return NULL;
+
+ sc->symbol = kstrdup(sym, GFP_KERNEL);
+ if (!sc->symbol) {
+ kfree(sc);
+ return NULL;
+ }
+ sc->offset = offset;
+
+ update_symbol_cache(sc);
+ return sc;
+}
+
+static __kprobes unsigned long fetch_symbol(struct pt_regs *regs, void *data)
+{
+ struct symbol_cache *sc = data;
+
+ if (sc->addr)
+ return fetch_memory(regs, (void *)sc->addr);
+ else
+ return 0;
+}
+
+/* Special indirect memory access interface */
+struct indirect_fetch_data {
+ struct fetch_func orig;
+ long offset;
+};
+
+static __kprobes unsigned long fetch_indirect(struct pt_regs *regs, void *data)
+{
+ struct indirect_fetch_data *ind = data;
+ unsigned long addr;
+
+ addr = call_fetch(&ind->orig, regs);
+ if (addr) {
+ addr += ind->offset;
+ return fetch_memory(regs, (void *)addr);
+ } else
+ return 0;
+}
+
+static __kprobes void free_indirect_fetch_data(struct indirect_fetch_data *data)
+{
+ if (data->orig.func == fetch_indirect)
+ free_indirect_fetch_data(data->orig.data);
+ else if (data->orig.func == fetch_symbol)
+ free_symbol_cache(data->orig.data);
+ kfree(data);
+}
+
+/**
+ * Kprobe tracer core functions
+ */
+
+struct probe_arg {
+ struct fetch_func fetch;
+ const char *name;
+};
+
+/* Flags for trace_probe */
+#define TP_FLAG_TRACE 1
+#define TP_FLAG_PROFILE 2
+
+struct trace_probe {
+ struct list_head list;
+ struct kretprobe rp; /* Use rp.kp for kprobe use */
+ unsigned long nhit;
+ unsigned int flags; /* For TP_FLAG_* */
+ const char *symbol; /* symbol name */
+ struct ftrace_event_call call;
+ struct trace_event event;
+ unsigned int nr_args;
+ struct probe_arg args[];
+};
+
+#define SIZEOF_TRACE_PROBE(n) \
+ (offsetof(struct trace_probe, args) + \
+ (sizeof(struct probe_arg) * (n)))
+
+static __kprobes int probe_is_return(struct trace_probe *tp)
+{
+ return tp->rp.handler != NULL;
+}
+
+static __kprobes const char *probe_symbol(struct trace_probe *tp)
+{
+ return tp->symbol ? tp->symbol : "unknown";
+}
+
+static int probe_arg_string(char *buf, size_t n, struct fetch_func *ff)
+{
+ int ret = -EINVAL;
+
+ if (ff->func == fetch_argument)
+ ret = snprintf(buf, n, "$arg%lu", (unsigned long)ff->data);
+ else if (ff->func == fetch_register) {
+ const char *name;
+ name = regs_query_register_name((unsigned int)((long)ff->data));
+ ret = snprintf(buf, n, "%%%s", name);
+ } else if (ff->func == fetch_stack)
+ ret = snprintf(buf, n, "$stack%lu", (unsigned long)ff->data);
+ else if (ff->func == fetch_memory)
+ ret = snprintf(buf, n, "@0x%p", ff->data);
+ else if (ff->func == fetch_symbol) {
+ struct symbol_cache *sc = ff->data;
+ ret = snprintf(buf, n, "@%s%+ld", sc->symbol, sc->offset);
+ } else if (ff->func == fetch_retvalue)
+ ret = snprintf(buf, n, "$retval");
+ else if (ff->func == fetch_stack_address)
+ ret = snprintf(buf, n, "$stack");
+ else if (ff->func == fetch_indirect) {
+ struct indirect_fetch_data *id = ff->data;
+ size_t l = 0;
+ ret = snprintf(buf, n, "%+ld(", id->offset);
+ if (ret >= n)
+ goto end;
+ l += ret;
+ ret = probe_arg_string(buf + l, n - l, &id->orig);
+ if (ret < 0)
+ goto end;
+ l += ret;
+ ret = snprintf(buf + l, n - l, ")");
+ ret += l;
+ }
+end:
+ if (ret >= n)
+ return -ENOSPC;
+ return ret;
+}
+
+static int register_probe_event(struct trace_probe *tp);
+static void unregister_probe_event(struct trace_probe *tp);
+
+static DEFINE_MUTEX(probe_lock);
+static LIST_HEAD(probe_list);
+
+static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs);
+static int kretprobe_dispatcher(struct kretprobe_instance *ri,
+ struct pt_regs *regs);
+
+/*
+ * Allocate new trace_probe and initialize it (including kprobes).
+ */
+static struct trace_probe *alloc_trace_probe(const char *group,
+ const char *event,
+ void *addr,
+ const char *symbol,
+ unsigned long offs,
+ int nargs, int is_return)
+{
+ struct trace_probe *tp;
+
+ tp = kzalloc(SIZEOF_TRACE_PROBE(nargs), GFP_KERNEL);
+ if (!tp)
+ return ERR_PTR(-ENOMEM);
+
+ if (symbol) {
+ tp->symbol = kstrdup(symbol, GFP_KERNEL);
+ if (!tp->symbol)
+ goto error;
+ tp->rp.kp.symbol_name = tp->symbol;
+ tp->rp.kp.offset = offs;
+ } else
+ tp->rp.kp.addr = addr;
+
+ if (is_return)
+ tp->rp.handler = kretprobe_dispatcher;
+ else
+ tp->rp.kp.pre_handler = kprobe_dispatcher;
+
+ if (!event)
+ goto error;
+ tp->call.name = kstrdup(event, GFP_KERNEL);
+ if (!tp->call.name)
+ goto error;
+
+ if (!group)
+ goto error;
+ tp->call.system = kstrdup(group, GFP_KERNEL);
+ if (!tp->call.system)
+ goto error;
+
+ INIT_LIST_HEAD(&tp->list);
+ return tp;
+error:
+ kfree(tp->call.name);
+ kfree(tp->symbol);
+ kfree(tp);
+ return ERR_PTR(-ENOMEM);
+}
+
+static void free_probe_arg(struct probe_arg *arg)
+{
+ if (arg->fetch.func == fetch_symbol)
+ free_symbol_cache(arg->fetch.data);
+ else if (arg->fetch.func == fetch_indirect)
+ free_indirect_fetch_data(arg->fetch.data);
+ kfree(arg->name);
+}
+
+static void free_trace_probe(struct trace_probe *tp)
+{
+ int i;
+
+ for (i = 0; i < tp->nr_args; i++)
+ free_probe_arg(&tp->args[i]);
+
+ kfree(tp->call.system);
+ kfree(tp->call.name);
+ kfree(tp->symbol);
+ kfree(tp);
+}
+
+static struct trace_probe *find_probe_event(const char *event)
+{
+ struct trace_probe *tp;
+
+ list_for_each_entry(tp, &probe_list, list)
+ if (!strcmp(tp->call.name, event))
+ return tp;
+ return NULL;
+}
+
+/* Unregister a trace_probe and probe_event: call with locking probe_lock */
+static void unregister_trace_probe(struct trace_probe *tp)
+{
+ if (probe_is_return(tp))
+ unregister_kretprobe(&tp->rp);
+ else
+ unregister_kprobe(&tp->rp.kp);
+ list_del(&tp->list);
+ unregister_probe_event(tp);
+}
+
+/* Register a trace_probe and probe_event */
+static int register_trace_probe(struct trace_probe *tp)
+{
+ struct trace_probe *old_tp;
+ int ret;
+
+ mutex_lock(&probe_lock);
+
+ /* register as an event */
+ old_tp = find_probe_event(tp->call.name);
+ if (old_tp) {
+ /* delete old event */
+ unregister_trace_probe(old_tp);
+ free_trace_probe(old_tp);
+ }
+ ret = register_probe_event(tp);
+ if (ret) {
+ pr_warning("Faild to register probe event(%d)\n", ret);
+ goto end;
+ }
+
+ tp->rp.kp.flags |= KPROBE_FLAG_DISABLED;
+ if (probe_is_return(tp))
+ ret = register_kretprobe(&tp->rp);
+ else
+ ret = register_kprobe(&tp->rp.kp);
+
+ if (ret) {
+ pr_warning("Could not insert probe(%d)\n", ret);
+ if (ret == -EILSEQ) {
+ pr_warning("Probing address(0x%p) is not an "
+ "instruction boundary.\n",
+ tp->rp.kp.addr);
+ ret = -EINVAL;
+ }
+ unregister_probe_event(tp);
+ } else
+ list_add_tail(&tp->list, &probe_list);
+end:
+ mutex_unlock(&probe_lock);
+ return ret;
+}
+
+/* Split symbol and offset. */
+static int split_symbol_offset(char *symbol, unsigned long *offset)
+{
+ char *tmp;
+ int ret;
+
+ if (!offset)
+ return -EINVAL;
+
+ tmp = strchr(symbol, '+');
+ if (tmp) {
+ /* skip sign because strict_strtol doesn't accept '+' */
+ ret = strict_strtoul(tmp + 1, 0, offset);
+ if (ret)
+ return ret;
+ *tmp = '\0';
+ } else
+ *offset = 0;
+ return 0;
+}
+
+#define PARAM_MAX_ARGS 16
+#define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))
+
+static int parse_probe_vars(char *arg, struct fetch_func *ff, int is_return)
+{
+ int ret = 0;
+ unsigned long param;
+
+ if (strcmp(arg, "retval") == 0) {
+ if (is_return) {
+ ff->func = fetch_retvalue;
+ ff->data = NULL;
+ } else
+ ret = -EINVAL;
+ } else if (strncmp(arg, "stack", 5) == 0) {
+ if (arg[5] == '\0') {
+ ff->func = fetch_stack_address;
+ ff->data = NULL;
+ } else if (isdigit(arg[5])) {
+ ret = strict_strtoul(arg + 5, 10, &param);
+ if (ret || param > PARAM_MAX_STACK)
+ ret = -EINVAL;
+ else {
+ ff->func = fetch_stack;
+ ff->data = (void *)param;
+ }
+ } else
+ ret = -EINVAL;
+ } else if (strncmp(arg, "arg", 3) == 0 && isdigit(arg[3])) {
+ ret = strict_strtoul(arg + 3, 10, &param);
+ if (ret || param > PARAM_MAX_ARGS)
+ ret = -EINVAL;
+ else {
+ ff->func = fetch_argument;
+ ff->data = (void *)param;
+ }
+ } else
+ ret = -EINVAL;
+ return ret;
+}
+
+static int parse_probe_arg(char *arg, struct fetch_func *ff, int is_return)
+{
+ int ret = 0;
+ unsigned long param;
+ long offset;
+ char *tmp;
+
+ switch (arg[0]) {
+ case '$':
+ ret = parse_probe_vars(arg + 1, ff, is_return);
+ break;
+ case '%': /* named register */
+ ret = regs_query_register_offset(arg + 1);
+ if (ret >= 0) {
+ ff->func = fetch_register;
+ ff->data = (void *)(unsigned long)ret;
+ ret = 0;
+ }
+ break;
+ case '@': /* memory or symbol */
+ if (isdigit(arg[1])) {
+ ret = strict_strtoul(arg + 1, 0, &param);
+ if (ret)
+ break;
+ ff->func = fetch_memory;
+ ff->data = (void *)param;
+ } else {
+ ret = split_symbol_offset(arg + 1, &offset);
+ if (ret)
+ break;
+ ff->data = alloc_symbol_cache(arg + 1, offset);
+ if (ff->data)
+ ff->func = fetch_symbol;
+ else
+ ret = -EINVAL;
+ }
+ break;
+ case '+': /* indirect memory */
+ case '-':
+ tmp = strchr(arg, '(');
+ if (!tmp) {
+ ret = -EINVAL;
+ break;
+ }
+ *tmp = '\0';
+ ret = strict_strtol(arg + 1, 0, &offset);
+ if (ret)
+ break;
+ if (arg[0] == '-')
+ offset = -offset;
+ arg = tmp + 1;
+ tmp = strrchr(arg, ')');
+ if (tmp) {
+ struct indirect_fetch_data *id;
+ *tmp = '\0';
+ id = kzalloc(sizeof(struct indirect_fetch_data),
+ GFP_KERNEL);
+ if (!id)
+ return -ENOMEM;
+ id->offset = offset;
+ ret = parse_probe_arg(arg, &id->orig, is_return);
+ if (ret)
+ kfree(id);
+ else {
+ ff->func = fetch_indirect;
+ ff->data = (void *)id;
+ }
+ } else
+ ret = -EINVAL;
+ break;
+ default:
+ /* TODO: support custom handler */
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+/* Return 1 if name is reserved or already used by another argument */
+static int conflict_field_name(const char *name,
+ struct probe_arg *args, int narg)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(reserved_field_names); i++)
+ if (strcmp(reserved_field_names[i], name) == 0)
+ return 1;
+ for (i = 0; i < narg; i++)
+ if (strcmp(args[i].name, name) == 0)
+ return 1;
+ return 0;
+}
+
+static int create_trace_probe(int argc, char **argv)
+{
+ /*
+ * Argument syntax:
+ * - Add kprobe: p[:[GRP/]EVENT] KSYM[+OFFS]|KADDR [FETCHARGS]
+ * - Add kretprobe: r[:[GRP/]EVENT] KSYM[+0] [FETCHARGS]
+ * Fetch args:
+ * $argN : fetch Nth of function argument. (N:0-)
+ * $retval : fetch return value
+ * $stack : fetch stack address
+ * $stackN : fetch Nth of stack (N:0-)
+ * @ADDR : fetch memory at ADDR (ADDR should be in kernel)
+ * @SYM[+|-offs] : fetch memory at SYM +|- offs (SYM is a data symbol)
+ * %REG : fetch register REG
+ * Indirect memory fetch:
+ * +|-offs(ARG) : fetch memory at ARG +|- offs address.
+ * Alias name of args:
+ * NAME=FETCHARG : set NAME as alias of FETCHARG.
+ */
+ struct trace_probe *tp;
+ int i, ret = 0;
+ int is_return = 0;
+ char *symbol = NULL, *event = NULL, *arg = NULL, *group = NULL;
+ unsigned long offset = 0;
+ void *addr = NULL;
+ char buf[MAX_EVENT_NAME_LEN];
+
+ if (argc < 2) {
+ pr_info("Probe point is not specified.\n");
+ return -EINVAL;
+ }
+
+ if (argv[0][0] == 'p')
+ is_return = 0;
+ else if (argv[0][0] == 'r')
+ is_return = 1;
+ else {
+ pr_info("Probe definition must be started with 'p' or 'r'.\n");
+ return -EINVAL;
+ }
+
+ if (argv[0][1] == ':') {
+ event = &argv[0][2];
+ if (strchr(event, '/')) {
+ group = event;
+ event = strchr(group, '/') + 1;
+ event[-1] = '\0';
+ if (strlen(group) == 0) {
+ pr_info("Group name is not specifiled\n");
+ return -EINVAL;
+ }
+ }
+ if (strlen(event) == 0) {
+ pr_info("Event name is not specifiled\n");
+ return -EINVAL;
+ }
+ }
+
+ if (isdigit(argv[1][0])) {
+ if (is_return) {
+ pr_info("Return probe point must be a symbol.\n");
+ return -EINVAL;
+ }
+ /* an address specified */
+ ret = strict_strtoul(&argv[0][2], 0, (unsigned long *)&addr);
+ if (ret) {
+ pr_info("Failed to parse address.\n");
+ return ret;
+ }
+ } else {
+ /* a symbol specified */
+ symbol = argv[1];
+ /* TODO: support .init module functions */
+ ret = split_symbol_offset(symbol, &offset);
+ if (ret) {
+ pr_info("Failed to parse symbol.\n");
+ return ret;
+ }
+ if (offset && is_return) {
+ pr_info("Return probe must be used without offset.\n");
+ return -EINVAL;
+ }
+ }
+ argc -= 2; argv += 2;
+
+ /* setup a probe */
+ if (!group)
+ group = KPROBE_EVENT_SYSTEM;
+ if (!event) {
+ /* Make a new event name */
+ if (symbol)
+ snprintf(buf, MAX_EVENT_NAME_LEN, "%c@%s%+ld",
+ is_return ? 'r' : 'p', symbol, offset);
+ else
+ snprintf(buf, MAX_EVENT_NAME_LEN, "%c@0x%p",
+ is_return ? 'r' : 'p', addr);
+ event = buf;
+ }
+ tp = alloc_trace_probe(group, event, addr, symbol, offset, argc,
+ is_return);
+ if (IS_ERR(tp)) {
+ pr_info("Failed to allocate trace_probe.(%d)\n",
+ (int)PTR_ERR(tp));
+ return PTR_ERR(tp);
+ }
+
+ /* parse arguments */
+ ret = 0;
+ for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
+ /* Parse argument name */
+ arg = strchr(argv[i], '=');
+ if (arg)
+ *arg++ = '\0';
+ else
+ arg = argv[i];
+
+ if (conflict_field_name(argv[i], tp->args, i)) {
+ pr_info("Argument%d name '%s' conflicts with "
+ "another field.\n", i, argv[i]);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ tp->args[i].name = kstrdup(argv[i], GFP_KERNEL);
+
+ /* Parse fetch argument */
+ if (strlen(arg) > MAX_ARGSTR_LEN) {
+ pr_info("Argument%d(%s) is too long.\n", i, arg);
+ ret = -ENOSPC;
+ goto error;
+ }
+ ret = parse_probe_arg(arg, &tp->args[i].fetch, is_return);
+ if (ret) {
+ pr_info("Parse error at argument%d. (%d)\n", i, ret);
+ goto error;
+ }
+ }
+ tp->nr_args = i;
+
+ ret = register_trace_probe(tp);
+ if (ret)
+ goto error;
+ return 0;
+
+error:
+ free_trace_probe(tp);
+ return ret;
+}
+
+static void cleanup_all_probes(void)
+{
+ struct trace_probe *tp;
+
+ mutex_lock(&probe_lock);
+ /* TODO: Use batch unregistration */
+ while (!list_empty(&probe_list)) {
+ tp = list_entry(probe_list.next, struct trace_probe, list);
+ unregister_trace_probe(tp);
+ free_trace_probe(tp);
+ }
+ mutex_unlock(&probe_lock);
+}
+
+
+/* Probes listing interfaces */
+static void *probes_seq_start(struct seq_file *m, loff_t *pos)
+{
+ mutex_lock(&probe_lock);
+ return seq_list_start(&probe_list, *pos);
+}
+
+static void *probes_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ return seq_list_next(v, &probe_list, pos);
+}
+
+static void probes_seq_stop(struct seq_file *m, void *v)
+{
+ mutex_unlock(&probe_lock);
+}
+
+static int probes_seq_show(struct seq_file *m, void *v)
+{
+ struct trace_probe *tp = v;
+ int i, ret;
+ char buf[MAX_ARGSTR_LEN + 1];
+
+ seq_printf(m, "%c", probe_is_return(tp) ? 'r' : 'p');
+ seq_printf(m, ":%s", tp->call.name);
+
+ if (tp->symbol)
+ seq_printf(m, " %s+%u", probe_symbol(tp), tp->rp.kp.offset);
+ else
+ seq_printf(m, " 0x%p", tp->rp.kp.addr);
+
+ for (i = 0; i < tp->nr_args; i++) {
+ ret = probe_arg_string(buf, MAX_ARGSTR_LEN, &tp->args[i].fetch);
+ if (ret < 0) {
+ pr_warning("Argument%d decoding error(%d).\n", i, ret);
+ return ret;
+ }
+ seq_printf(m, " %s=%s", tp->args[i].name, buf);
+ }
+ seq_printf(m, "\n");
+ return 0;
+}
+
+static const struct seq_operations probes_seq_op = {
+ .start = probes_seq_start,
+ .next = probes_seq_next,
+ .stop = probes_seq_stop,
+ .show = probes_seq_show
+};
+
+static int probes_open(struct inode *inode, struct file *file)
+{
+ if ((file->f_mode & FMODE_WRITE) &&
+ (file->f_flags & O_TRUNC))
+ cleanup_all_probes();
+
+ return seq_open(file, &probes_seq_op);
+}
+
+static int command_trace_probe(const char *buf)
+{
+ char **argv;
+ int argc = 0, ret = 0;
+
+ argv = argv_split(GFP_KERNEL, buf, &argc);
+ if (!argv)
+ return -ENOMEM;
+
+ if (argc)
+ ret = create_trace_probe(argc, argv);
+
+ argv_free(argv);
+ return ret;
+}
+
+#define WRITE_BUFSIZE 128
+
+static ssize_t probes_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char *kbuf, *tmp;
+ int ret;
+ size_t done;
+ size_t size;
+
+ kbuf = kmalloc(WRITE_BUFSIZE, GFP_KERNEL);
+ if (!kbuf)
+ return -ENOMEM;
+
+ ret = done = 0;
+ while (done < count) {
+ size = count - done;
+ if (size >= WRITE_BUFSIZE)
+ size = WRITE_BUFSIZE - 1;
+ if (copy_from_user(kbuf, buffer + done, size)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ kbuf[size] = '\0';
+ tmp = strchr(kbuf, '\n');
+ if (tmp) {
+ *tmp = '\0';
+ size = tmp - kbuf + 1;
+ } else if (done + size < count) {
+ pr_warning("Line length is too long: "
+ "Should be less than %d.", WRITE_BUFSIZE);
+ ret = -EINVAL;
+ goto out;
+ }
+ done += size;
+ /* Remove comments */
+ tmp = strchr(kbuf, '#');
+ if (tmp)
+ *tmp = '\0';
+
+ ret = command_trace_probe(kbuf);
+ if (ret)
+ goto out;
+ }
+ ret = done;
+out:
+ kfree(kbuf);
+ return ret;
+}
+
+static const struct file_operations kprobe_events_ops = {
+ .owner = THIS_MODULE,
+ .open = probes_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+ .write = probes_write,
+};
+
+/* Probes profiling interfaces */
+static int probes_profile_seq_show(struct seq_file *m, void *v)
+{
+ struct trace_probe *tp = v;
+
+ seq_printf(m, " %-44s %15lu %15lu\n", tp->call.name, tp->nhit,
+ tp->rp.kp.nmissed);
+
+ return 0;
+}
+
+static const struct seq_operations profile_seq_op = {
+ .start = probes_seq_start,
+ .next = probes_seq_next,
+ .stop = probes_seq_stop,
+ .show = probes_profile_seq_show
+};
+
+static int profile_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &profile_seq_op);
+}
+
+static const struct file_operations kprobe_profile_ops = {
+ .owner = THIS_MODULE,
+ .open = profile_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/* Kprobe handler */
+static __kprobes int kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs)
+{
+ struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp);
+ struct kprobe_trace_entry *entry;
+ struct ring_buffer_event *event;
+ struct ring_buffer *buffer;
+ int size, i, pc;
+ unsigned long irq_flags;
+ struct ftrace_event_call *call = &tp->call;
+
+ tp->nhit++;
+
+ local_save_flags(irq_flags);
+ pc = preempt_count();
+
+ size = SIZEOF_KPROBE_TRACE_ENTRY(tp->nr_args);
+
+ event = trace_current_buffer_lock_reserve(&buffer, call->id, size,
+ irq_flags, pc);
+ if (!event)
+ return 0;
+
+ entry = ring_buffer_event_data(event);
+ entry->nargs = tp->nr_args;
+ entry->ip = (unsigned long)kp->addr;
+ for (i = 0; i < tp->nr_args; i++)
+ entry->args[i] = call_fetch(&tp->args[i].fetch, regs);
+
+ if (!filter_current_check_discard(buffer, call, entry, event))
+ trace_nowake_buffer_unlock_commit(buffer, event, irq_flags, pc);
+ return 0;
+}
+
+/* Kretprobe handler */
+static __kprobes int kretprobe_trace_func(struct kretprobe_instance *ri,
+ struct pt_regs *regs)
+{
+ struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp);
+ struct kretprobe_trace_entry *entry;
+ struct ring_buffer_event *event;
+ struct ring_buffer *buffer;
+ int size, i, pc;
+ unsigned long irq_flags;
+ struct ftrace_event_call *call = &tp->call;
+
+ local_save_flags(irq_flags);
+ pc = preempt_count();
+
+ size = SIZEOF_KRETPROBE_TRACE_ENTRY(tp->nr_args);
+
+ event = trace_current_buffer_lock_reserve(&buffer, call->id, size,
+ irq_flags, pc);
+ if (!event)
+ return 0;
+
+ entry = ring_buffer_event_data(event);
+ entry->nargs = tp->nr_args;
+ entry->func = (unsigned long)tp->rp.kp.addr;
+ entry->ret_ip = (unsigned long)ri->ret_addr;
+ for (i = 0; i < tp->nr_args; i++)
+ entry->args[i] = call_fetch(&tp->args[i].fetch, regs);
+
+ if (!filter_current_check_discard(buffer, call, entry, event))
+ trace_nowake_buffer_unlock_commit(buffer, event, irq_flags, pc);
+
+ return 0;
+}
+
+/* Event entry printers */
+enum print_line_t
+print_kprobe_event(struct trace_iterator *iter, int flags)
+{
+ struct kprobe_trace_entry *field;
+ struct trace_seq *s = &iter->seq;
+ struct trace_event *event;
+ struct trace_probe *tp;
+ int i;
+
+ field = (struct kprobe_trace_entry *)iter->ent;
+ event = ftrace_find_event(field->ent.type);
+ tp = container_of(event, struct trace_probe, event);
+
+ if (!trace_seq_printf(s, "%s: (", tp->call.name))
+ goto partial;
+
+ if (!seq_print_ip_sym(s, field->ip, flags | TRACE_ITER_SYM_OFFSET))
+ goto partial;
+
+ if (!trace_seq_puts(s, ")"))
+ goto partial;
+
+ for (i = 0; i < field->nargs; i++)
+ if (!trace_seq_printf(s, " %s=%lx",
+ tp->args[i].name, field->args[i]))
+ goto partial;
+
+ if (!trace_seq_puts(s, "\n"))
+ goto partial;
+
+ return TRACE_TYPE_HANDLED;
+partial:
+ return TRACE_TYPE_PARTIAL_LINE;
+}
+
+enum print_line_t
+print_kretprobe_event(struct trace_iterator *iter, int flags)
+{
+ struct kretprobe_trace_entry *field;
+ struct trace_seq *s = &iter->seq;
+ struct trace_event *event;
+ struct trace_probe *tp;
+ int i;
+
+ field = (struct kretprobe_trace_entry *)iter->ent;
+ event = ftrace_find_event(field->ent.type);
+ tp = container_of(event, struct trace_probe, event);
+
+ if (!trace_seq_printf(s, "%s: (", tp->call.name))
+ goto partial;
+
+ if (!seq_print_ip_sym(s, field->ret_ip, flags | TRACE_ITER_SYM_OFFSET))
+ goto partial;
+
+ if (!trace_seq_puts(s, " <- "))
+ goto partial;
+
+ if (!seq_print_ip_sym(s, field->func, flags & ~TRACE_ITER_SYM_OFFSET))
+ goto partial;
+
+ if (!trace_seq_puts(s, ")"))
+ goto partial;
+
+ for (i = 0; i < field->nargs; i++)
+ if (!trace_seq_printf(s, " %s=%lx",
+ tp->args[i].name, field->args[i]))
+ goto partial;
+
+ if (!trace_seq_puts(s, "\n"))
+ goto partial;
+
+ return TRACE_TYPE_HANDLED;
+partial:
+ return TRACE_TYPE_PARTIAL_LINE;
+}
+
+static int probe_event_enable(struct ftrace_event_call *call)
+{
+ struct trace_probe *tp = (struct trace_probe *)call->data;
+
+ tp->flags |= TP_FLAG_TRACE;
+ if (probe_is_return(tp))
+ return enable_kretprobe(&tp->rp);
+ else
+ return enable_kprobe(&tp->rp.kp);
+}
+
+static void probe_event_disable(struct ftrace_event_call *call)
+{
+ struct trace_probe *tp = (struct trace_probe *)call->data;
+
+ tp->flags &= ~TP_FLAG_TRACE;
+ if (!(tp->flags & (TP_FLAG_TRACE | TP_FLAG_PROFILE))) {
+ if (probe_is_return(tp))
+ disable_kretprobe(&tp->rp);
+ else
+ disable_kprobe(&tp->rp.kp);
+ }
+}
+
+static int probe_event_raw_init(struct ftrace_event_call *event_call)
+{
+ INIT_LIST_HEAD(&event_call->fields);
+
+ return 0;
+}
+
+#undef DEFINE_FIELD
+#define DEFINE_FIELD(type, item, name, is_signed) \
+ do { \
+ ret = trace_define_field(event_call, #type, name, \
+ offsetof(typeof(field), item), \
+ sizeof(field.item), is_signed, \
+ FILTER_OTHER); \
+ if (ret) \
+ return ret; \
+ } while (0)
+
+static int kprobe_event_define_fields(struct ftrace_event_call *event_call)
+{
+ int ret, i;
+ struct kprobe_trace_entry field;
+ struct trace_probe *tp = (struct trace_probe *)event_call->data;
+
+ ret = trace_define_common_fields(event_call);
+ if (!ret)
+ return ret;
+
+ DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0);
+ DEFINE_FIELD(int, nargs, FIELD_STRING_NARGS, 1);
+ /* Set argument names as fields */
+ for (i = 0; i < tp->nr_args; i++)
+ DEFINE_FIELD(unsigned long, args[i], tp->args[i].name, 0);
+ return 0;
+}
+
+static int kretprobe_event_define_fields(struct ftrace_event_call *event_call)
+{
+ int ret, i;
+ struct kretprobe_trace_entry field;
+ struct trace_probe *tp = (struct trace_probe *)event_call->data;
+
+ ret = trace_define_common_fields(event_call);
+ if (!ret)
+ return ret;
+
+ DEFINE_FIELD(unsigned long, func, FIELD_STRING_FUNC, 0);
+ DEFINE_FIELD(unsigned long, ret_ip, FIELD_STRING_RETIP, 0);
+ DEFINE_FIELD(int, nargs, FIELD_STRING_NARGS, 1);
+ /* Set argument names as fields */
+ for (i = 0; i < tp->nr_args; i++)
+ DEFINE_FIELD(unsigned long, args[i], tp->args[i].name, 0);
+ return 0;
+}
+
+static int __probe_event_show_format(struct trace_seq *s,
+ struct trace_probe *tp, const char *fmt,
+ const char *arg)
+{
+ int i;
+
+ /* Show format */
+ if (!trace_seq_printf(s, "\nprint fmt: \"%s", fmt))
+ return 0;
+
+ for (i = 0; i < tp->nr_args; i++)
+ if (!trace_seq_printf(s, " %s=%%lx", tp->args[i].name))
+ return 0;
+
+ if (!trace_seq_printf(s, "\", %s", arg))
+ return 0;
+
+ for (i = 0; i < tp->nr_args; i++)
+ if (!trace_seq_printf(s, ", REC->%s", tp->args[i].name))
+ return 0;
+
+ return trace_seq_puts(s, "\n");
+}
+
+#undef SHOW_FIELD
+#define SHOW_FIELD(type, item, name) \
+ do { \
+ ret = trace_seq_printf(s, "\tfield: " #type " %s;\t" \
+ "offset:%u;\tsize:%u;\n", name, \
+ (unsigned int)offsetof(typeof(field), item),\
+ (unsigned int)sizeof(type)); \
+ if (!ret) \
+ return 0; \
+ } while (0)
+
+static int kprobe_event_show_format(struct ftrace_event_call *call,
+ struct trace_seq *s)
+{
+ struct kprobe_trace_entry field __attribute__((unused));
+ int ret, i;
+ struct trace_probe *tp = (struct trace_probe *)call->data;
+
+ SHOW_FIELD(unsigned long, ip, FIELD_STRING_IP);
+ SHOW_FIELD(int, nargs, FIELD_STRING_NARGS);
+
+ /* Show fields */
+ for (i = 0; i < tp->nr_args; i++)
+ SHOW_FIELD(unsigned long, args[i], tp->args[i].name);
+ trace_seq_puts(s, "\n");
+
+ return __probe_event_show_format(s, tp, "(%lx)",
+ "REC->" FIELD_STRING_IP);
+}
+
+static int kretprobe_event_show_format(struct ftrace_event_call *call,
+ struct trace_seq *s)
+{
+ struct kretprobe_trace_entry field __attribute__((unused));
+ int ret, i;
+ struct trace_probe *tp = (struct trace_probe *)call->data;
+
+ SHOW_FIELD(unsigned long, func, FIELD_STRING_FUNC);
+ SHOW_FIELD(unsigned long, ret_ip, FIELD_STRING_RETIP);
+ SHOW_FIELD(int, nargs, FIELD_STRING_NARGS);
+
+ /* Show fields */
+ for (i = 0; i < tp->nr_args; i++)
+ SHOW_FIELD(unsigned long, args[i], tp->args[i].name);
+ trace_seq_puts(s, "\n");
+
+ return __probe_event_show_format(s, tp, "(%lx <- %lx)",
+ "REC->" FIELD_STRING_FUNC
+ ", REC->" FIELD_STRING_RETIP);
+}
+
+#ifdef CONFIG_EVENT_PROFILE
+
+/* Kprobe profile handler */
+static __kprobes int kprobe_profile_func(struct kprobe *kp,
+ struct pt_regs *regs)
+{
+ struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp);
+ struct ftrace_event_call *call = &tp->call;
+ struct kprobe_trace_entry *entry;
+ struct trace_entry *ent;
+ int size, __size, i, pc, __cpu;
+ unsigned long irq_flags;
+ char *raw_data;
+
+ pc = preempt_count();
+ __size = SIZEOF_KPROBE_TRACE_ENTRY(tp->nr_args);
+ size = ALIGN(__size + sizeof(u32), sizeof(u64));
+ size -= sizeof(u32);
+ if (WARN_ONCE(size > FTRACE_MAX_PROFILE_SIZE,
+ "profile buffer not large enough"))
+ return 0;
+
+ /*
+ * Protect the non nmi buffer
+ * This also protects the rcu read side
+ */
+ local_irq_save(irq_flags);
+ __cpu = smp_processor_id();
+
+ if (in_nmi())
+ raw_data = rcu_dereference(trace_profile_buf_nmi);
+ else
+ raw_data = rcu_dereference(trace_profile_buf);
+
+ if (!raw_data)
+ goto end;
+
+ raw_data = per_cpu_ptr(raw_data, __cpu);
+ /* Zero dead bytes from alignment to avoid buffer leak to userspace */
+ *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL;
+ entry = (struct kprobe_trace_entry *)raw_data;
+ ent = &entry->ent;
+
+ tracing_generic_entry_update(ent, irq_flags, pc);
+ ent->type = call->id;
+ entry->nargs = tp->nr_args;
+ entry->ip = (unsigned long)kp->addr;
+ for (i = 0; i < tp->nr_args; i++)
+ entry->args[i] = call_fetch(&tp->args[i].fetch, regs);
+ perf_tp_event(call->id, entry->ip, 1, entry, size);
+end:
+ local_irq_restore(irq_flags);
+ return 0;
+}
+
+/* Kretprobe profile handler */
+static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri,
+ struct pt_regs *regs)
+{
+ struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp);
+ struct ftrace_event_call *call = &tp->call;
+ struct kretprobe_trace_entry *entry;
+ struct trace_entry *ent;
+ int size, __size, i, pc, __cpu;
+ unsigned long irq_flags;
+ char *raw_data;
+
+ pc = preempt_count();
+ __size = SIZEOF_KRETPROBE_TRACE_ENTRY(tp->nr_args);
+ size = ALIGN(__size + sizeof(u32), sizeof(u64));
+ size -= sizeof(u32);
+ if (WARN_ONCE(size > FTRACE_MAX_PROFILE_SIZE,
+ "profile buffer not large enough"))
+ return 0;
+
+ /*
+ * Protect the non nmi buffer
+ * This also protects the rcu read side
+ */
+ local_irq_save(irq_flags);
+ __cpu = smp_processor_id();
+
+ if (in_nmi())
+ raw_data = rcu_dereference(trace_profile_buf_nmi);
+ else
+ raw_data = rcu_dereference(trace_profile_buf);
+
+ if (!raw_data)
+ goto end;
+
+ raw_data = per_cpu_ptr(raw_data, __cpu);
+ /* Zero dead bytes from alignment to avoid buffer leak to userspace */
+ *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL;
+ entry = (struct kretprobe_trace_entry *)raw_data;
+ ent = &entry->ent;
+
+ tracing_generic_entry_update(ent, irq_flags, pc);
+ ent->type = call->id;
+ entry->nargs = tp->nr_args;
+ entry->func = (unsigned long)tp->rp.kp.addr;
+ entry->ret_ip = (unsigned long)ri->ret_addr;
+ for (i = 0; i < tp->nr_args; i++)
+ entry->args[i] = call_fetch(&tp->args[i].fetch, regs);
+ perf_tp_event(call->id, entry->ret_ip, 1, entry, size);
+end:
+ local_irq_restore(irq_flags);
+ return 0;
+}
+
+static int probe_profile_enable(struct ftrace_event_call *call)
+{
+ struct trace_probe *tp = (struct trace_probe *)call->data;
+
+ tp->flags |= TP_FLAG_PROFILE;
+
+ if (probe_is_return(tp))
+ return enable_kretprobe(&tp->rp);
+ else
+ return enable_kprobe(&tp->rp.kp);
+}
+
+static void probe_profile_disable(struct ftrace_event_call *call)
+{
+ struct trace_probe *tp = (struct trace_probe *)call->data;
+
+ tp->flags &= ~TP_FLAG_PROFILE;
+
+ if (!(tp->flags & TP_FLAG_TRACE)) {
+ if (probe_is_return(tp))
+ disable_kretprobe(&tp->rp);
+ else
+ disable_kprobe(&tp->rp.kp);
+ }
+}
+#endif /* CONFIG_EVENT_PROFILE */
+
+
+static __kprobes
+int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs)
+{
+ struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp);
+
+ if (tp->flags & TP_FLAG_TRACE)
+ kprobe_trace_func(kp, regs);
+#ifdef CONFIG_EVENT_PROFILE
+ if (tp->flags & TP_FLAG_PROFILE)
+ kprobe_profile_func(kp, regs);
+#endif /* CONFIG_EVENT_PROFILE */
+ return 0; /* We don't tweek kernel, so just return 0 */
+}
+
+static __kprobes
+int kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+ struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp);
+
+ if (tp->flags & TP_FLAG_TRACE)
+ kretprobe_trace_func(ri, regs);
+#ifdef CONFIG_EVENT_PROFILE
+ if (tp->flags & TP_FLAG_PROFILE)
+ kretprobe_profile_func(ri, regs);
+#endif /* CONFIG_EVENT_PROFILE */
+ return 0; /* We don't tweek kernel, so just return 0 */
+}
+
+static int register_probe_event(struct trace_probe *tp)
+{
+ struct ftrace_event_call *call = &tp->call;
+ int ret;
+
+ /* Initialize ftrace_event_call */
+ if (probe_is_return(tp)) {
+ tp->event.trace = print_kretprobe_event;
+ call->raw_init = probe_event_raw_init;
+ call->show_format = kretprobe_event_show_format;
+ call->define_fields = kretprobe_event_define_fields;
+ } else {
+ tp->event.trace = print_kprobe_event;
+ call->raw_init = probe_event_raw_init;
+ call->show_format = kprobe_event_show_format;
+ call->define_fields = kprobe_event_define_fields;
+ }
+ call->event = &tp->event;
+ call->id = register_ftrace_event(&tp->event);
+ if (!call->id)
+ return -ENODEV;
+ call->enabled = 0;
+ call->regfunc = probe_event_enable;
+ call->unregfunc = probe_event_disable;
+
+#ifdef CONFIG_EVENT_PROFILE
+ atomic_set(&call->profile_count, -1);
+ call->profile_enable = probe_profile_enable;
+ call->profile_disable = probe_profile_disable;
+#endif
+ call->data = tp;
+ ret = trace_add_event_call(call);
+ if (ret) {
+ pr_info("Failed to register kprobe event: %s\n", call->name);
+ unregister_ftrace_event(&tp->event);
+ }
+ return ret;
+}
+
+static void unregister_probe_event(struct trace_probe *tp)
+{
+ /* tp->event is unregistered in trace_remove_event_call() */
+ trace_remove_event_call(&tp->call);
+}
+
+/* Make a debugfs interface for controling probe points */
+static __init int init_kprobe_trace(void)
+{
+ struct dentry *d_tracer;
+ struct dentry *entry;
+
+ d_tracer = tracing_init_dentry();
+ if (!d_tracer)
+ return 0;
+
+ entry = debugfs_create_file("kprobe_events", 0644, d_tracer,
+ NULL, &kprobe_events_ops);
+
+ /* Event list interface */
+ if (!entry)
+ pr_warning("Could not create debugfs "
+ "'kprobe_events' entry\n");
+
+ /* Profile interface */
+ entry = debugfs_create_file("kprobe_profile", 0444, d_tracer,
+ NULL, &kprobe_profile_ops);
+
+ if (!entry)
+ pr_warning("Could not create debugfs "
+ "'kprobe_profile' entry\n");
+ return 0;
+}
+fs_initcall(init_kprobe_trace);
+
+
+#ifdef CONFIG_FTRACE_STARTUP_TEST
+
+static int kprobe_trace_selftest_target(int a1, int a2, int a3,
+ int a4, int a5, int a6)
+{
+ return a1 + a2 + a3 + a4 + a5 + a6;
+}
+
+static __init int kprobe_trace_self_tests_init(void)
+{
+ int ret;
+ int (*target)(int, int, int, int, int, int);
+
+ target = kprobe_trace_selftest_target;
+
+ pr_info("Testing kprobe tracing: ");
+
+ ret = command_trace_probe("p:testprobe kprobe_trace_selftest_target "
+ "$arg1 $arg2 $arg3 $arg4 $stack $stack0");
+ if (WARN_ON_ONCE(ret))
+ pr_warning("error enabling function entry\n");
+
+ ret = command_trace_probe("r:testprobe2 kprobe_trace_selftest_target "
+ "$retval");
+ if (WARN_ON_ONCE(ret))
+ pr_warning("error enabling function return\n");
+
+ ret = target(1, 2, 3, 4, 5, 6);
+
+ cleanup_all_probes();
+
+ pr_cont("OK\n");
+ return 0;
+}
+
+late_initcall(kprobe_trace_self_tests_init);
+
+#endif
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
index ed17565826b0..b6c12c6a1bcd 100644
--- a/kernel/trace/trace_output.c
+++ b/kernel/trace/trace_output.c
@@ -69,6 +69,9 @@ enum print_line_t trace_print_printk_msg_only(struct trace_iterator *iter)
* @s: trace sequence descriptor
* @fmt: printf format string
*
+ * It returns 0 if the trace oversizes the buffer's free
+ * space, 1 otherwise.
+ *
* The tracer may use either sequence operations or its own
* copy to user routines. To simplify formating of a trace
* trace_seq_printf is used to store strings into a special
@@ -95,7 +98,7 @@ trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
s->len += ret;
- return len;
+ return 1;
}
EXPORT_SYMBOL_GPL(trace_seq_printf);
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index 527e17eae575..58b8e5370767 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -14,6 +14,69 @@ static int sys_refcount_exit;
static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls);
static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls);
+extern unsigned long __start_syscalls_metadata[];
+extern unsigned long __stop_syscalls_metadata[];
+
+static struct syscall_metadata **syscalls_metadata;
+
+static struct syscall_metadata *find_syscall_meta(unsigned long syscall)
+{
+ struct syscall_metadata *start;
+ struct syscall_metadata *stop;
+ char str[KSYM_SYMBOL_LEN];
+
+
+ start = (struct syscall_metadata *)__start_syscalls_metadata;
+ stop = (struct syscall_metadata *)__stop_syscalls_metadata;
+ kallsyms_lookup(syscall, NULL, NULL, NULL, str);
+
+ for ( ; start < stop; start++) {
+ /*
+ * Only compare after the "sys" prefix. Archs that use
+ * syscall wrappers may have syscalls symbols aliases prefixed
+ * with "SyS" instead of "sys", leading to an unwanted
+ * mismatch.
+ */
+ if (start->name && !strcmp(start->name + 3, str + 3))
+ return start;
+ }
+ return NULL;
+}
+
+static struct syscall_metadata *syscall_nr_to_meta(int nr)
+{
+ if (!syscalls_metadata || nr >= NR_syscalls || nr < 0)
+ return NULL;
+
+ return syscalls_metadata[nr];
+}
+
+int syscall_name_to_nr(char *name)
+{
+ int i;
+
+ if (!syscalls_metadata)
+ return -1;
+
+ for (i = 0; i < NR_syscalls; i++) {
+ if (syscalls_metadata[i]) {
+ if (!strcmp(syscalls_metadata[i]->name, name))
+ return i;
+ }
+ }
+ return -1;
+}
+
+void set_syscall_enter_id(int num, int id)
+{
+ syscalls_metadata[num]->enter_id = id;
+}
+
+void set_syscall_exit_id(int num, int id)
+{
+ syscalls_metadata[num]->exit_id = id;
+}
+
enum print_line_t
print_syscall_enter(struct trace_iterator *iter, int flags)
{
@@ -103,7 +166,8 @@ extern char *__bad_type_size(void);
#define SYSCALL_FIELD(type, name) \
sizeof(type) != sizeof(trace.name) ? \
__bad_type_size() : \
- #type, #name, offsetof(typeof(trace), name), sizeof(trace.name)
+ #type, #name, offsetof(typeof(trace), name), \
+ sizeof(trace.name), is_signed_type(type)
int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s)
{
@@ -120,7 +184,8 @@ int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s)
if (!entry)
return 0;
- ret = trace_seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n",
+ ret = trace_seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%zu;"
+ "\tsigned:%u;\n",
SYSCALL_FIELD(int, nr));
if (!ret)
return 0;
@@ -130,8 +195,10 @@ int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s)
entry->args[i]);
if (!ret)
return 0;
- ret = trace_seq_printf(s, "\toffset:%d;\tsize:%zu;\n", offset,
- sizeof(unsigned long));
+ ret = trace_seq_printf(s, "\toffset:%d;\tsize:%zu;"
+ "\tsigned:%u;\n", offset,
+ sizeof(unsigned long),
+ is_signed_type(unsigned long));
if (!ret)
return 0;
offset += sizeof(unsigned long);
@@ -163,8 +230,10 @@ int syscall_exit_format(struct ftrace_event_call *call, struct trace_seq *s)
struct syscall_trace_exit trace;
ret = trace_seq_printf(s,
- "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
- "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n",
+ "\tfield:%s %s;\toffset:%zu;\tsize:%zu;"
+ "\tsigned:%u;\n"
+ "\tfield:%s %s;\toffset:%zu;\tsize:%zu;"
+ "\tsigned:%u;\n",
SYSCALL_FIELD(int, nr),
SYSCALL_FIELD(long, ret));
if (!ret)
@@ -212,7 +281,7 @@ int syscall_exit_define_fields(struct ftrace_event_call *call)
if (ret)
return ret;
- ret = trace_define_field(call, SYSCALL_FIELD(long, ret), 0,
+ ret = trace_define_field(call, SYSCALL_FIELD(long, ret),
FILTER_OTHER);
return ret;
@@ -285,13 +354,13 @@ void ftrace_syscall_exit(struct pt_regs *regs, long ret)
trace_current_buffer_unlock_commit(buffer, event, 0, 0);
}
-int reg_event_syscall_enter(void *ptr)
+int reg_event_syscall_enter(struct ftrace_event_call *call)
{
int ret = 0;
int num;
char *name;
- name = (char *)ptr;
+ name = (char *)call->data;
num = syscall_name_to_nr(name);
if (num < 0 || num >= NR_syscalls)
return -ENOSYS;
@@ -309,12 +378,12 @@ int reg_event_syscall_enter(void *ptr)
return ret;
}
-void unreg_event_syscall_enter(void *ptr)
+void unreg_event_syscall_enter(struct ftrace_event_call *call)
{
int num;
char *name;
- name = (char *)ptr;
+ name = (char *)call->data;
num = syscall_name_to_nr(name);
if (num < 0 || num >= NR_syscalls)
return;
@@ -326,13 +395,13 @@ void unreg_event_syscall_enter(void *ptr)
mutex_unlock(&syscall_trace_lock);
}
-int reg_event_syscall_exit(void *ptr)
+int reg_event_syscall_exit(struct ftrace_event_call *call)
{
int ret = 0;
int num;
char *name;
- name = (char *)ptr;
+ name = call->data;
num = syscall_name_to_nr(name);
if (num < 0 || num >= NR_syscalls)
return -ENOSYS;
@@ -350,12 +419,12 @@ int reg_event_syscall_exit(void *ptr)
return ret;
}
-void unreg_event_syscall_exit(void *ptr)
+void unreg_event_syscall_exit(struct ftrace_event_call *call)
{
int num;
char *name;
- name = (char *)ptr;
+ name = call->data;
num = syscall_name_to_nr(name);
if (num < 0 || num >= NR_syscalls)
return;
@@ -375,6 +444,29 @@ struct trace_event event_syscall_exit = {
.trace = print_syscall_exit,
};
+int __init init_ftrace_syscalls(void)
+{
+ struct syscall_metadata *meta;
+ unsigned long addr;
+ int i;
+
+ syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) *
+ NR_syscalls, GFP_KERNEL);
+ if (!syscalls_metadata) {
+ WARN_ON(1);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < NR_syscalls; i++) {
+ addr = arch_syscall_addr(i);
+ meta = find_syscall_meta(addr);
+ syscalls_metadata[i] = meta;
+ }
+
+ return 0;
+}
+core_initcall(init_ftrace_syscalls);
+
#ifdef CONFIG_EVENT_PROFILE
static DECLARE_BITMAP(enabled_prof_enter_syscalls, NR_syscalls);
diff --git a/kernel/user-return-notifier.c b/kernel/user-return-notifier.c
new file mode 100644
index 000000000000..530ccb816513
--- /dev/null
+++ b/kernel/user-return-notifier.c
@@ -0,0 +1,46 @@
+
+#include <linux/user-return-notifier.h>
+#include <linux/percpu.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+
+static DEFINE_PER_CPU(struct hlist_head, return_notifier_list);
+
+#define URN_LIST_HEAD per_cpu(return_notifier_list, raw_smp_processor_id())
+
+/*
+ * Request a notification when the current cpu returns to userspace. Must be
+ * called in atomic context. The notifier will also be called in atomic
+ * context.
+ */
+void user_return_notifier_register(struct user_return_notifier *urn)
+{
+ set_tsk_thread_flag(current, TIF_USER_RETURN_NOTIFY);
+ hlist_add_head(&urn->link, &URN_LIST_HEAD);
+}
+EXPORT_SYMBOL_GPL(user_return_notifier_register);
+
+/*
+ * Removes a registered user return notifier. Must be called from atomic
+ * context, and from the same cpu registration occured in.
+ */
+void user_return_notifier_unregister(struct user_return_notifier *urn)
+{
+ hlist_del(&urn->link);
+ if (hlist_empty(&URN_LIST_HEAD))
+ clear_tsk_thread_flag(current, TIF_USER_RETURN_NOTIFY);
+}
+EXPORT_SYMBOL_GPL(user_return_notifier_unregister);
+
+/* Calls registered user return notifiers */
+void fire_user_return_notifiers(void)
+{
+ struct user_return_notifier *urn;
+ struct hlist_node *tmp1, *tmp2;
+ struct hlist_head *head;
+
+ head = &get_cpu_var(return_notifier_list);
+ hlist_for_each_entry_safe(urn, tmp1, tmp2, head, link)
+ urn->on_user_return(urn);
+ put_cpu_var();
+}
diff --git a/lib/Kconfig b/lib/Kconfig
index bb1326d3839c..272cecfc8d9c 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -200,4 +200,28 @@ config NLATTR
config GENERIC_ATOMIC64
bool
+config LRU_CACHE
+ tristate
+
+config SHM_SIGNAL
+ tristate "SHM Signal - Generic shared-memory signaling mechanism"
+ default n
+ help
+ Provides a shared-memory based signaling mechansim to indicate
+ memory-dirty notifications between two end-points.
+
+ If unsure, say N
+
+config IOQ
+ tristate "IO-Queue library - Generic shared-memory queue"
+ select SHM_SIGNAL
+ default n
+ help
+ IOQ is a generic shared-memory-queue mechanism that happens to be
+ friendly to virtualization boundaries. It can be used in a variety
+ of ways, though its intended purpose is to become a low-level
+ communication path for paravirtualized drivers.
+
+ If unsure, say N
+
endmenu
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 30df5865ecbe..c84ce7ddadac 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -344,6 +344,26 @@ config SLUB_STATS
out which slabs are relevant to a particular load.
Try running: slabinfo -DA
+config SLQB_DEBUG
+ default y
+ bool "Enable SLQB debugging support"
+ depends on SLQB
+
+config SLQB_DEBUG_ON
+ default n
+ bool "SLQB debugging on by default"
+ depends on SLQB_DEBUG
+
+config SLQB_SYSFS
+ bool "Create SYSFS entries for slab caches"
+ default n
+ depends on SLQB
+
+config SLQB_STATS
+ bool "Enable SLQB performance statistics"
+ default n
+ depends on SLQB_SYSFS
+
config DEBUG_KMEMLEAK
bool "Kernel memory leak detector"
depends on DEBUG_KERNEL && EXPERIMENTAL && !MEMORY_HOTPLUG && \
@@ -392,7 +412,7 @@ config DEBUG_KMEMLEAK_TEST
config DEBUG_PREEMPT
bool "Debug preemptible kernel"
- depends on DEBUG_KERNEL && PREEMPT && (TRACE_IRQFLAGS_SUPPORT || PPC64)
+ depends on DEBUG_KERNEL && PREEMPT && TRACE_IRQFLAGS_SUPPORT
default y
help
If you say Y here then the kernel will use a debug variant of the
diff --git a/lib/Makefile b/lib/Makefile
index 2e78277eff9d..10412a2201ee 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -76,6 +76,8 @@ obj-$(CONFIG_TEXTSEARCH_BM) += ts_bm.o
obj-$(CONFIG_TEXTSEARCH_FSM) += ts_fsm.o
obj-$(CONFIG_SMP) += percpu_counter.o
obj-$(CONFIG_AUDIT_GENERIC) += audit.o
+obj-$(CONFIG_SHM_SIGNAL) += shm_signal.o
+obj-$(CONFIG_IOQ) += ioq.o
obj-$(CONFIG_SWIOTLB) += swiotlb.o
obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o
@@ -91,6 +93,8 @@ obj-$(CONFIG_DYNAMIC_DEBUG) += dynamic_debug.o
obj-$(CONFIG_NLATTR) += nlattr.o
+obj-$(CONFIG_LRU_CACHE) += lru_cache.o
+
obj-$(CONFIG_DMA_API_DEBUG) += dma-debug.o
obj-$(CONFIG_GENERIC_CSUM) += checksum.o
diff --git a/lib/checksum.c b/lib/checksum.c
index b2e2fd468461..097508732f34 100644
--- a/lib/checksum.c
+++ b/lib/checksum.c
@@ -37,7 +37,8 @@
#include <asm/byteorder.h>
-static inline unsigned short from32to16(unsigned long x)
+#ifndef do_csum
+static inline unsigned short from32to16(unsigned int x)
{
/* add up 16-bit and 16-bit for 16+c bit */
x = (x & 0xffff) + (x >> 16);
@@ -49,16 +50,16 @@ static inline unsigned short from32to16(unsigned long x)
static unsigned int do_csum(const unsigned char *buff, int len)
{
int odd, count;
- unsigned long result = 0;
+ unsigned int result = 0;
if (len <= 0)
goto out;
odd = 1 & (unsigned long) buff;
if (odd) {
#ifdef __LITTLE_ENDIAN
- result = *buff;
-#else
result += (*buff << 8);
+#else
+ result = *buff;
#endif
len--;
buff++;
@@ -73,9 +74,9 @@ static unsigned int do_csum(const unsigned char *buff, int len)
}
count >>= 1; /* nr of 32-bit words.. */
if (count) {
- unsigned long carry = 0;
+ unsigned int carry = 0;
do {
- unsigned long w = *(unsigned int *) buff;
+ unsigned int w = *(unsigned int *) buff;
count--;
buff += 4;
result += carry;
@@ -102,6 +103,7 @@ static unsigned int do_csum(const unsigned char *buff, int len)
out:
return result;
}
+#endif
/*
* This is a version of ip_compute_csum() optimized for IP headers,
diff --git a/lib/idr.c b/lib/idr.c
index 80ca9aca038b..1cac726c44bc 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -281,7 +281,7 @@ 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 ide
+ * @ptr: pointer you want associated with the id
* @start_id: id to start search at
* @id: pointer to the allocated handle
*
@@ -313,7 +313,7 @@ EXPORT_SYMBOL(idr_get_new_above);
/**
* idr_get_new - allocate new idr entry
* @idp: idr handle
- * @ptr: pointer you want associated with the ide
+ * @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
diff --git a/lib/ioq.c b/lib/ioq.c
new file mode 100644
index 000000000000..a6c86644df4c
--- /dev/null
+++ b/lib/ioq.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2009 Novell. All Rights Reserved.
+ *
+ * See include/linux/ioq.h for documentation
+ *
+ * Author:
+ * Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file 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 St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/sched.h>
+#include <linux/ioq.h>
+#include <linux/bitops.h>
+#include <linux/module.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+static int ioq_iter_setpos(struct ioq_iterator *iter, u32 pos)
+{
+ struct ioq *ioq = iter->ioq;
+
+ BUG_ON(pos >= ioq->count);
+
+ iter->pos = pos;
+ iter->desc = &ioq->ring[pos];
+
+ return 0;
+}
+
+static inline u32 modulo_inc(u32 val, u32 mod)
+{
+ BUG_ON(val >= mod);
+
+ if (val == (mod - 1))
+ return 0;
+
+ return val + 1;
+}
+
+static inline int idx_full(struct ioq_ring_idx *idx)
+{
+ return idx->full && (idx->head == idx->tail);
+}
+
+int ioq_iter_seek(struct ioq_iterator *iter, enum ioq_seek_type type,
+ long offset, int flags)
+{
+ struct ioq_ring_idx *idx = iter->idx;
+ u32 pos;
+
+ switch (type) {
+ case ioq_seek_next:
+ pos = modulo_inc(iter->pos, iter->ioq->count);
+ break;
+ case ioq_seek_tail:
+ pos = idx->tail;
+ break;
+ case ioq_seek_head:
+ pos = idx->head;
+ break;
+ case ioq_seek_set:
+ if (offset >= iter->ioq->count)
+ return -1;
+ pos = offset;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ioq_iter_setpos(iter, pos);
+}
+EXPORT_SYMBOL_GPL(ioq_iter_seek);
+
+static int ioq_ring_count(struct ioq_ring_idx *idx, int count)
+{
+ if (idx->full && (idx->head == idx->tail))
+ return count;
+ else if (idx->tail >= idx->head)
+ return idx->tail - idx->head;
+ else
+ return (idx->tail + count) - idx->head;
+}
+
+static void idx_tail_push(struct ioq_ring_idx *idx, int count)
+{
+ u32 tail = modulo_inc(idx->tail, count);
+
+ if (idx->head == tail) {
+ rmb();
+
+ /*
+ * Setting full here may look racy, but note that we havent
+ * flipped the owner bit yet. So it is impossible for the
+ * remote locale to move head in such a way that this operation
+ * becomes invalid
+ */
+ idx->full = 1;
+ wmb();
+ }
+
+ idx->tail = tail;
+}
+
+int ioq_iter_push(struct ioq_iterator *iter, int flags)
+{
+ struct ioq_ring_head *head_desc = iter->ioq->head_desc;
+ struct ioq_ring_idx *idx = iter->idx;
+ int ret;
+
+ /*
+ * Its only valid to push if we are currently pointed at the tail
+ */
+ if (iter->pos != idx->tail || iter->desc->sown != iter->ioq->locale)
+ return -EINVAL;
+
+ idx_tail_push(idx, iter->ioq->count);
+ if (iter->dualidx) {
+ idx_tail_push(&head_desc->idx[ioq_idxtype_inuse],
+ iter->ioq->count);
+ if (head_desc->idx[ioq_idxtype_inuse].tail !=
+ head_desc->idx[ioq_idxtype_valid].tail) {
+ SHM_SIGNAL_FAULT(iter->ioq->signal,
+ "Tails not synchronized");
+ return -EINVAL;
+ }
+ }
+
+ wmb(); /* the index must be visible before the sown, or signal */
+
+ if (iter->flipowner) {
+ iter->desc->sown = !iter->ioq->locale;
+ wmb(); /* sown must be visible before we signal */
+ }
+
+ ret = ioq_iter_seek(iter, ioq_seek_next, 0, flags);
+
+ if (iter->update)
+ ioq_signal(iter->ioq, 0);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ioq_iter_push);
+
+int ioq_iter_pop(struct ioq_iterator *iter, int flags)
+{
+ struct ioq_ring_idx *idx = iter->idx;
+ int ret;
+
+ /*
+ * Its only valid to pop if we are currently pointed at the head
+ */
+ if (iter->pos != idx->head || iter->desc->sown != iter->ioq->locale)
+ return -EINVAL;
+
+ idx->head = modulo_inc(idx->head, iter->ioq->count);
+ wmb(); /* head must be visible before full */
+
+ if (idx->full) {
+ idx->full = 0;
+ wmb(); /* full must be visible before sown */
+ }
+
+ if (iter->flipowner) {
+ iter->desc->sown = !iter->ioq->locale;
+ wmb(); /* sown must be visible before we signal */
+ }
+
+ ret = ioq_iter_seek(iter, ioq_seek_next, 0, flags);
+
+ if (iter->update)
+ ioq_signal(iter->ioq, 0);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ioq_iter_pop);
+
+static struct ioq_ring_idx *idxtype_to_idx(struct ioq *ioq,
+ enum ioq_idx_type type)
+{
+ struct ioq_ring_idx *idx;
+
+ switch (type) {
+ case ioq_idxtype_valid:
+ case ioq_idxtype_inuse:
+ idx = &ioq->head_desc->idx[type];
+ break;
+ default:
+ panic("IOQ: illegal index type: %d", type);
+ break;
+ }
+
+ return idx;
+}
+
+int ioq_iter_init(struct ioq *ioq, struct ioq_iterator *iter,
+ enum ioq_idx_type type, int flags)
+{
+ iter->ioq = ioq;
+ iter->update = (flags & IOQ_ITER_AUTOUPDATE);
+ iter->flipowner = !(flags & IOQ_ITER_NOFLIPOWNER);
+ iter->pos = -1;
+ iter->desc = NULL;
+ iter->dualidx = 0;
+
+ if (type == ioq_idxtype_both) {
+ /*
+ * "both" is a special case, so we set the dualidx flag.
+ *
+ * However, we also just want to use the valid-index
+ * for normal processing, so override that here
+ */
+ type = ioq_idxtype_valid;
+ iter->dualidx = 1;
+ }
+
+ iter->idx = idxtype_to_idx(ioq, type);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ioq_iter_init);
+
+int ioq_count(struct ioq *ioq, enum ioq_idx_type type)
+{
+ return ioq_ring_count(idxtype_to_idx(ioq, type), ioq->count);
+}
+EXPORT_SYMBOL_GPL(ioq_count);
+
+int ioq_remain(struct ioq *ioq, enum ioq_idx_type type)
+{
+ int count = ioq_ring_count(idxtype_to_idx(ioq, type), ioq->count);
+
+ return ioq->count - count;
+}
+EXPORT_SYMBOL_GPL(ioq_remain);
+
+int ioq_size(struct ioq *ioq)
+{
+ return ioq->count;
+}
+EXPORT_SYMBOL_GPL(ioq_size);
+
+int ioq_full(struct ioq *ioq, enum ioq_idx_type type)
+{
+ struct ioq_ring_idx *idx = idxtype_to_idx(ioq, type);
+
+ return idx_full(idx);
+}
+EXPORT_SYMBOL_GPL(ioq_full);
+
+static void ioq_shm_signal(struct shm_signal_notifier *notifier)
+{
+ struct ioq *ioq = container_of(notifier, struct ioq, shm_notifier);
+
+ if (waitqueue_active(&ioq->wq))
+ wake_up(&ioq->wq);
+
+ if (ioq->notifier)
+ ioq->notifier->signal(ioq->notifier);
+}
+
+void ioq_init(struct ioq *ioq,
+ struct ioq_ops *ops,
+ enum ioq_locality locale,
+ struct ioq_ring_head *head,
+ struct shm_signal *signal,
+ size_t count)
+{
+ memset(ioq, 0, sizeof(*ioq));
+ kref_init(&ioq->kref);
+ init_waitqueue_head(&ioq->wq);
+
+ ioq->ops = ops;
+ ioq->locale = locale;
+ ioq->head_desc = head;
+ ioq->ring = &head->ring[0];
+ ioq->count = count;
+ ioq->signal = signal;
+
+ ioq->shm_notifier.signal = &ioq_shm_signal;
+ signal->notifier = &ioq->shm_notifier;
+}
+EXPORT_SYMBOL_GPL(ioq_init);
diff --git a/lib/kernel_lock.c b/lib/kernel_lock.c
index 39f1029e3525..4ebfa5a164d7 100644
--- a/lib/kernel_lock.c
+++ b/lib/kernel_lock.c
@@ -5,10 +5,13 @@
* relegated to obsolescence, but used by various less
* important (or lazy) subsystems.
*/
-#include <linux/smp_lock.h>
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/semaphore.h>
+#include <linux/smp_lock.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/bkl.h>
/*
* The 'big kernel lock'
@@ -113,21 +116,26 @@ static inline void __unlock_kernel(void)
* This cannot happen asynchronously, so we only need to
* worry about other CPU's.
*/
-void __lockfunc lock_kernel(void)
+void __lockfunc _lock_kernel(const char *func, const char *file, int line)
{
- int depth = current->lock_depth+1;
+ int depth = current->lock_depth + 1;
+
+ trace_lock_kernel(func, file, line);
+
if (likely(!depth))
__lock_kernel();
current->lock_depth = depth;
}
-void __lockfunc unlock_kernel(void)
+void __lockfunc _unlock_kernel(const char *func, const char *file, int line)
{
BUG_ON(current->lock_depth < 0);
if (likely(--current->lock_depth < 0))
__unlock_kernel();
+
+ trace_unlock_kernel(func, file, line);
}
-EXPORT_SYMBOL(lock_kernel);
-EXPORT_SYMBOL(unlock_kernel);
+EXPORT_SYMBOL(_lock_kernel);
+EXPORT_SYMBOL(_unlock_kernel);
diff --git a/lib/lru_cache.c b/lib/lru_cache.c
new file mode 100644
index 000000000000..270de9d31b8c
--- /dev/null
+++ b/lib/lru_cache.c
@@ -0,0 +1,560 @@
+/*
+ lru_cache.c
+
+ This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
+
+ Copyright (C) 2003-2008, LINBIT Information Technologies GmbH.
+ Copyright (C) 2003-2008, Philipp Reisner <philipp.reisner@linbit.com>.
+ Copyright (C) 2003-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
+
+ drbd 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.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT 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 drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/string.h> /* for memset */
+#include <linux/seq_file.h> /* for seq_printf */
+#include <linux/lru_cache.h>
+
+MODULE_AUTHOR("Philipp Reisner <phil@linbit.com>, "
+ "Lars Ellenberg <lars@linbit.com>");
+MODULE_DESCRIPTION("lru_cache - Track sets of hot objects");
+MODULE_LICENSE("GPL");
+
+/* this is developers aid only.
+ * it catches concurrent access (lack of locking on the users part) */
+#define PARANOIA_ENTRY() do { \
+ BUG_ON(!lc); \
+ BUG_ON(!lc->nr_elements); \
+ BUG_ON(test_and_set_bit(__LC_PARANOIA, &lc->flags)); \
+} while (0)
+
+#define RETURN(x...) do { \
+ clear_bit(__LC_PARANOIA, &lc->flags); \
+ smp_mb__after_clear_bit(); return x ; } while (0)
+
+/* BUG() if e is not one of the elements tracked by lc */
+#define PARANOIA_LC_ELEMENT(lc, e) do { \
+ struct lru_cache *lc_ = (lc); \
+ struct lc_element *e_ = (e); \
+ unsigned i = e_->lc_index; \
+ BUG_ON(i >= lc_->nr_elements); \
+ BUG_ON(lc_->lc_element[i] != e_); } while (0)
+
+/**
+ * lc_create - prepares to track objects in an active set
+ * @name: descriptive name only used in lc_seq_printf_stats and lc_seq_dump_details
+ * @e_count: number of elements allowed to be active simultaneously
+ * @e_size: size of the tracked objects
+ * @e_off: offset to the &struct lc_element member in a tracked object
+ *
+ * Returns a pointer to a newly initialized struct lru_cache on success,
+ * or NULL on (allocation) failure.
+ */
+struct lru_cache *lc_create(const char *name, struct kmem_cache *cache,
+ unsigned e_count, size_t e_size, size_t e_off)
+{
+ struct hlist_head *slot = NULL;
+ struct lc_element **element = NULL;
+ struct lru_cache *lc;
+ struct lc_element *e;
+ unsigned cache_obj_size = kmem_cache_size(cache);
+ unsigned i;
+
+ WARN_ON(cache_obj_size < e_size);
+ if (cache_obj_size < e_size)
+ return NULL;
+
+ /* e_count too big; would probably fail the allocation below anyways.
+ * for typical use cases, e_count should be few thousand at most. */
+ if (e_count > LC_MAX_ACTIVE)
+ return NULL;
+
+ slot = kzalloc(e_count * sizeof(struct hlist_head*), GFP_KERNEL);
+ if (!slot)
+ goto out_fail;
+ element = kzalloc(e_count * sizeof(struct lc_element *), GFP_KERNEL);
+ if (!element)
+ goto out_fail;
+
+ lc = kzalloc(sizeof(*lc), GFP_KERNEL);
+ if (!lc)
+ goto out_fail;
+
+ INIT_LIST_HEAD(&lc->in_use);
+ INIT_LIST_HEAD(&lc->lru);
+ INIT_LIST_HEAD(&lc->free);
+
+ lc->name = name;
+ lc->element_size = e_size;
+ lc->element_off = e_off;
+ lc->nr_elements = e_count;
+ lc->new_number = LC_FREE;
+ lc->lc_cache = cache;
+ lc->lc_element = element;
+ lc->lc_slot = slot;
+
+ /* preallocate all objects */
+ for (i = 0; i < e_count; i++) {
+ void *p = kmem_cache_alloc(cache, GFP_KERNEL);
+ if (!p)
+ break;
+ memset(p, 0, lc->element_size);
+ e = p + e_off;
+ e->lc_index = i;
+ e->lc_number = LC_FREE;
+ list_add(&e->list, &lc->free);
+ element[i] = e;
+ }
+ if (i == e_count)
+ return lc;
+
+ /* else: could not allocate all elements, give up */
+ for (i--; i; i--) {
+ void *p = element[i];
+ kmem_cache_free(cache, p - e_off);
+ }
+ kfree(lc);
+out_fail:
+ kfree(element);
+ kfree(slot);
+ return NULL;
+}
+
+void lc_free_by_index(struct lru_cache *lc, unsigned i)
+{
+ void *p = lc->lc_element[i];
+ WARN_ON(!p);
+ if (p) {
+ p -= lc->element_off;
+ kmem_cache_free(lc->lc_cache, p);
+ }
+}
+
+/**
+ * lc_destroy - frees memory allocated by lc_create()
+ * @lc: the lru cache to destroy
+ */
+void lc_destroy(struct lru_cache *lc)
+{
+ unsigned i;
+ if (!lc)
+ return;
+ for (i = 0; i < lc->nr_elements; i++)
+ lc_free_by_index(lc, i);
+ kfree(lc->lc_element);
+ kfree(lc->lc_slot);
+ kfree(lc);
+}
+
+/**
+ * lc_reset - does a full reset for @lc and the hash table slots.
+ * @lc: the lru cache to operate on
+ *
+ * It is roughly the equivalent of re-allocating a fresh lru_cache object,
+ * basically a short cut to lc_destroy(lc); lc = lc_create(...);
+ */
+void lc_reset(struct lru_cache *lc)
+{
+ unsigned i;
+
+ INIT_LIST_HEAD(&lc->in_use);
+ INIT_LIST_HEAD(&lc->lru);
+ INIT_LIST_HEAD(&lc->free);
+ lc->used = 0;
+ lc->hits = 0;
+ lc->misses = 0;
+ lc->starving = 0;
+ lc->dirty = 0;
+ lc->changed = 0;
+ lc->flags = 0;
+ lc->changing_element = NULL;
+ lc->new_number = LC_FREE;
+ memset(lc->lc_slot, 0, sizeof(struct hlist_head) * lc->nr_elements);
+
+ for (i = 0; i < lc->nr_elements; i++) {
+ struct lc_element *e = lc->lc_element[i];
+ void *p = e;
+ p -= lc->element_off;
+ memset(p, 0, lc->element_size);
+ /* re-init it */
+ e->lc_index = i;
+ e->lc_number = LC_FREE;
+ list_add(&e->list, &lc->free);
+ }
+}
+
+/**
+ * lc_seq_printf_stats - print stats about @lc into @seq
+ * @seq: the seq_file to print into
+ * @lc: the lru cache to print statistics of
+ */
+size_t lc_seq_printf_stats(struct seq_file *seq, struct lru_cache *lc)
+{
+ /* NOTE:
+ * total calls to lc_get are
+ * (starving + hits + misses)
+ * misses include "dirty" count (update from an other thread in
+ * progress) and "changed", when this in fact lead to an successful
+ * update of the cache.
+ */
+ return seq_printf(seq, "\t%s: used:%u/%u "
+ "hits:%lu misses:%lu starving:%lu dirty:%lu changed:%lu\n",
+ lc->name, lc->used, lc->nr_elements,
+ lc->hits, lc->misses, lc->starving, lc->dirty, lc->changed);
+}
+
+static struct hlist_head *lc_hash_slot(struct lru_cache *lc, unsigned int enr)
+{
+ return lc->lc_slot + (enr % lc->nr_elements);
+}
+
+
+/**
+ * lc_find - find element by label, if present in the hash table
+ * @lc: The lru_cache object
+ * @enr: element number
+ *
+ * Returns the pointer to an element, if the element with the requested
+ * "label" or element number is present in the hash table,
+ * or NULL if not found. Does not change the refcnt.
+ */
+struct lc_element *lc_find(struct lru_cache *lc, unsigned int enr)
+{
+ struct hlist_node *n;
+ struct lc_element *e;
+
+ BUG_ON(!lc);
+ BUG_ON(!lc->nr_elements);
+ hlist_for_each_entry(e, n, lc_hash_slot(lc, enr), colision) {
+ if (e->lc_number == enr)
+ return e;
+ }
+ return NULL;
+}
+
+/* returned element will be "recycled" immediately */
+static struct lc_element *lc_evict(struct lru_cache *lc)
+{
+ struct list_head *n;
+ struct lc_element *e;
+
+ if (list_empty(&lc->lru))
+ return NULL;
+
+ n = lc->lru.prev;
+ e = list_entry(n, struct lc_element, list);
+
+ PARANOIA_LC_ELEMENT(lc, e);
+
+ list_del(&e->list);
+ hlist_del(&e->colision);
+ return e;
+}
+
+/**
+ * lc_del - removes an element from the cache
+ * @lc: The lru_cache object
+ * @e: The element to remove
+ *
+ * @e must be unused (refcnt == 0). Moves @e from "lru" to "free" list,
+ * sets @e->enr to %LC_FREE.
+ */
+void lc_del(struct lru_cache *lc, struct lc_element *e)
+{
+ PARANOIA_ENTRY();
+ PARANOIA_LC_ELEMENT(lc, e);
+ BUG_ON(e->refcnt);
+
+ e->lc_number = LC_FREE;
+ hlist_del_init(&e->colision);
+ list_move(&e->list, &lc->free);
+ RETURN();
+}
+
+static struct lc_element *lc_get_unused_element(struct lru_cache *lc)
+{
+ struct list_head *n;
+
+ if (list_empty(&lc->free))
+ return lc_evict(lc);
+
+ n = lc->free.next;
+ list_del(n);
+ return list_entry(n, struct lc_element, list);
+}
+
+static int lc_unused_element_available(struct lru_cache *lc)
+{
+ if (!list_empty(&lc->free))
+ return 1; /* something on the free list */
+ if (!list_empty(&lc->lru))
+ return 1; /* something to evict */
+
+ return 0;
+}
+
+
+/**
+ * lc_get - get element by label, maybe change the active set
+ * @lc: the lru cache to operate on
+ * @enr: the label to look up
+ *
+ * Finds an element in the cache, increases its usage count,
+ * "touches" and returns it.
+ *
+ * In case the requested number is not present, it needs to be added to the
+ * cache. Therefore it is possible that an other element becomes evicted from
+ * the cache. In either case, the user is notified so he is able to e.g. keep
+ * a persistent log of the cache changes, and therefore the objects in use.
+ *
+ * Return values:
+ * NULL
+ * The cache was marked %LC_STARVING,
+ * or the requested label was not in the active set
+ * and a changing transaction is still pending (@lc was marked %LC_DIRTY).
+ * Or no unused or free element could be recycled (@lc will be marked as
+ * %LC_STARVING, blocking further lc_get() operations).
+ *
+ * pointer to the element with the REQUESTED element number.
+ * In this case, it can be used right away
+ *
+ * pointer to an UNUSED element with some different element number,
+ * where that different number may also be %LC_FREE.
+ *
+ * In this case, the cache is marked %LC_DIRTY (blocking further changes),
+ * and the returned element pointer is removed from the lru list and
+ * hash collision chains. The user now should do whatever housekeeping
+ * is necessary.
+ * Then he must call lc_changed(lc,element_pointer), to finish
+ * the change.
+ *
+ * NOTE: The user needs to check the lc_number on EACH use, so he recognizes
+ * any cache set change.
+ */
+struct lc_element *lc_get(struct lru_cache *lc, unsigned int enr)
+{
+ struct lc_element *e;
+
+ PARANOIA_ENTRY();
+ if (lc->flags & LC_STARVING) {
+ ++lc->starving;
+ RETURN(NULL);
+ }
+
+ e = lc_find(lc, enr);
+ if (e) {
+ ++lc->hits;
+ if (e->refcnt++ == 0)
+ lc->used++;
+ list_move(&e->list, &lc->in_use); /* Not evictable... */
+ RETURN(e);
+ }
+
+ ++lc->misses;
+
+ /* In case there is nothing available and we can not kick out
+ * the LRU element, we have to wait ...
+ */
+ if (!lc_unused_element_available(lc)) {
+ __set_bit(__LC_STARVING, &lc->flags);
+ RETURN(NULL);
+ }
+
+ /* it was not present in the active set.
+ * we are going to recycle an unused (or even "free") element.
+ * user may need to commit a transaction to record that change.
+ * we serialize on flags & TF_DIRTY */
+ if (test_and_set_bit(__LC_DIRTY, &lc->flags)) {
+ ++lc->dirty;
+ RETURN(NULL);
+ }
+
+ e = lc_get_unused_element(lc);
+ BUG_ON(!e);
+
+ clear_bit(__LC_STARVING, &lc->flags);
+ BUG_ON(++e->refcnt != 1);
+ lc->used++;
+
+ lc->changing_element = e;
+ lc->new_number = enr;
+
+ RETURN(e);
+}
+
+/* similar to lc_get,
+ * but only gets a new reference on an existing element.
+ * you either get the requested element, or NULL.
+ * will be consolidated into one function.
+ */
+struct lc_element *lc_try_get(struct lru_cache *lc, unsigned int enr)
+{
+ struct lc_element *e;
+
+ PARANOIA_ENTRY();
+ if (lc->flags & LC_STARVING) {
+ ++lc->starving;
+ RETURN(NULL);
+ }
+
+ e = lc_find(lc, enr);
+ if (e) {
+ ++lc->hits;
+ if (e->refcnt++ == 0)
+ lc->used++;
+ list_move(&e->list, &lc->in_use); /* Not evictable... */
+ }
+ RETURN(e);
+}
+
+/**
+ * lc_changed - tell @lc that the change has been recorded
+ * @lc: the lru cache to operate on
+ * @e: the element pending label change
+ */
+void lc_changed(struct lru_cache *lc, struct lc_element *e)
+{
+ PARANOIA_ENTRY();
+ BUG_ON(e != lc->changing_element);
+ PARANOIA_LC_ELEMENT(lc, e);
+ ++lc->changed;
+ e->lc_number = lc->new_number;
+ list_add(&e->list, &lc->in_use);
+ hlist_add_head(&e->colision, lc_hash_slot(lc, lc->new_number));
+ lc->changing_element = NULL;
+ lc->new_number = LC_FREE;
+ clear_bit(__LC_DIRTY, &lc->flags);
+ smp_mb__after_clear_bit();
+ RETURN();
+}
+
+
+/**
+ * lc_put - give up refcnt of @e
+ * @lc: the lru cache to operate on
+ * @e: the element to put
+ *
+ * If refcnt reaches zero, the element is moved to the lru list,
+ * and a %LC_STARVING (if set) is cleared.
+ * Returns the new (post-decrement) refcnt.
+ */
+unsigned int lc_put(struct lru_cache *lc, struct lc_element *e)
+{
+ PARANOIA_ENTRY();
+ PARANOIA_LC_ELEMENT(lc, e);
+ BUG_ON(e->refcnt == 0);
+ BUG_ON(e == lc->changing_element);
+ if (--e->refcnt == 0) {
+ /* move it to the front of LRU. */
+ list_move(&e->list, &lc->lru);
+ lc->used--;
+ clear_bit(__LC_STARVING, &lc->flags);
+ smp_mb__after_clear_bit();
+ }
+ RETURN(e->refcnt);
+}
+
+/**
+ * lc_element_by_index
+ * @lc: the lru cache to operate on
+ * @i: the index of the element to return
+ */
+struct lc_element *lc_element_by_index(struct lru_cache *lc, unsigned i)
+{
+ BUG_ON(i >= lc->nr_elements);
+ BUG_ON(lc->lc_element[i] == NULL);
+ BUG_ON(lc->lc_element[i]->lc_index != i);
+ return lc->lc_element[i];
+}
+
+/**
+ * lc_index_of
+ * @lc: the lru cache to operate on
+ * @e: the element to query for its index position in lc->element
+ */
+unsigned int lc_index_of(struct lru_cache *lc, struct lc_element *e)
+{
+ PARANOIA_LC_ELEMENT(lc, e);
+ return e->lc_index;
+}
+
+/**
+ * lc_set - associate index with label
+ * @lc: the lru cache to operate on
+ * @enr: the label to set
+ * @index: the element index to associate label with.
+ *
+ * Used to initialize the active set to some previously recorded state.
+ */
+void lc_set(struct lru_cache *lc, unsigned int enr, int index)
+{
+ struct lc_element *e;
+
+ if (index < 0 || index >= lc->nr_elements)
+ return;
+
+ e = lc_element_by_index(lc, index);
+ e->lc_number = enr;
+
+ hlist_del_init(&e->colision);
+ hlist_add_head(&e->colision, lc_hash_slot(lc, enr));
+ list_move(&e->list, e->refcnt ? &lc->in_use : &lc->lru);
+}
+
+/**
+ * lc_dump - Dump a complete LRU cache to seq in textual form.
+ * @lc: the lru cache to operate on
+ * @seq: the &struct seq_file pointer to seq_printf into
+ * @utext: user supplied "heading" or other info
+ * @detail: function pointer the user may provide to dump further details
+ * of the object the lc_element is embedded in.
+ */
+void lc_seq_dump_details(struct seq_file *seq, struct lru_cache *lc, char *utext,
+ void (*detail) (struct seq_file *, struct lc_element *))
+{
+ unsigned int nr_elements = lc->nr_elements;
+ struct lc_element *e;
+ int i;
+
+ seq_printf(seq, "\tnn: lc_number refcnt %s\n ", utext);
+ for (i = 0; i < nr_elements; i++) {
+ e = lc_element_by_index(lc, i);
+ if (e->lc_number == LC_FREE) {
+ seq_printf(seq, "\t%2d: FREE\n", i);
+ } else {
+ seq_printf(seq, "\t%2d: %4u %4u ", i,
+ e->lc_number, e->refcnt);
+ detail(seq, e);
+ }
+ }
+}
+
+EXPORT_SYMBOL(lc_create);
+EXPORT_SYMBOL(lc_reset);
+EXPORT_SYMBOL(lc_destroy);
+EXPORT_SYMBOL(lc_set);
+EXPORT_SYMBOL(lc_del);
+EXPORT_SYMBOL(lc_try_get);
+EXPORT_SYMBOL(lc_find);
+EXPORT_SYMBOL(lc_get);
+EXPORT_SYMBOL(lc_put);
+EXPORT_SYMBOL(lc_changed);
+EXPORT_SYMBOL(lc_element_by_index);
+EXPORT_SYMBOL(lc_index_of);
+EXPORT_SYMBOL(lc_seq_printf_stats);
+EXPORT_SYMBOL(lc_seq_dump_details);
diff --git a/lib/ratelimit.c b/lib/ratelimit.c
index 26187edcc7ea..09f5ce1810dc 100644
--- a/lib/ratelimit.c
+++ b/lib/ratelimit.c
@@ -7,15 +7,12 @@
* parameter. Now every user can use their own standalone ratelimit_state.
*
* This file is released under the GPLv2.
- *
*/
-#include <linux/kernel.h>
+#include <linux/ratelimit.h>
#include <linux/jiffies.h>
#include <linux/module.h>
-static DEFINE_SPINLOCK(ratelimit_lock);
-
/*
* __ratelimit - rate limiting
* @rs: ratelimit_state data
@@ -23,35 +20,43 @@ static DEFINE_SPINLOCK(ratelimit_lock);
* This enforces a rate limit: not more than @rs->ratelimit_burst callbacks
* in every @rs->ratelimit_jiffies
*/
-int __ratelimit(struct ratelimit_state *rs)
+int ___ratelimit(struct ratelimit_state *rs, const char *func)
{
unsigned long flags;
+ int ret;
if (!rs->interval)
return 1;
- spin_lock_irqsave(&ratelimit_lock, flags);
+ /*
+ * If we contend on this state's lock then almost
+ * by definition we are too busy to print a message,
+ * in addition to the one that will be printed by
+ * the entity that is holding the lock already:
+ */
+ if (!spin_trylock_irqsave(&rs->lock, flags))
+ return 1;
+
if (!rs->begin)
rs->begin = jiffies;
if (time_is_before_jiffies(rs->begin + rs->interval)) {
if (rs->missed)
printk(KERN_WARNING "%s: %d callbacks suppressed\n",
- __func__, rs->missed);
- rs->begin = 0;
+ func, rs->missed);
+ rs->begin = 0;
rs->printed = 0;
- rs->missed = 0;
+ rs->missed = 0;
}
- if (rs->burst && rs->burst > rs->printed)
- goto print;
-
- rs->missed++;
- spin_unlock_irqrestore(&ratelimit_lock, flags);
- return 0;
+ if (rs->burst && rs->burst > rs->printed) {
+ rs->printed++;
+ ret = 1;
+ } else {
+ rs->missed++;
+ ret = 0;
+ }
+ spin_unlock_irqrestore(&rs->lock, flags);
-print:
- rs->printed++;
- spin_unlock_irqrestore(&ratelimit_lock, flags);
- return 1;
+ return ret;
}
-EXPORT_SYMBOL(__ratelimit);
+EXPORT_SYMBOL(___ratelimit);
diff --git a/lib/shm_signal.c b/lib/shm_signal.c
new file mode 100644
index 000000000000..fbba74f914b9
--- /dev/null
+++ b/lib/shm_signal.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2009 Novell. All Rights Reserved.
+ *
+ * See include/linux/shm_signal.h for documentation
+ *
+ * Author:
+ * Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file 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 St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/shm_signal.h>
+
+int shm_signal_enable(struct shm_signal *s, int flags)
+{
+ struct shm_signal_irq *irq = &s->desc->irq[s->locale];
+ unsigned long iflags;
+
+ spin_lock_irqsave(&s->lock, iflags);
+
+ irq->enabled = 1;
+ wmb();
+
+ if ((irq->dirty || irq->pending)
+ && !test_bit(shm_signal_in_wakeup, &s->flags)) {
+ rmb();
+ tasklet_schedule(&s->deferred_notify);
+ }
+
+ spin_unlock_irqrestore(&s->lock, iflags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(shm_signal_enable);
+
+int shm_signal_disable(struct shm_signal *s, int flags)
+{
+ struct shm_signal_irq *irq = &s->desc->irq[s->locale];
+
+ irq->enabled = 0;
+ wmb();
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(shm_signal_disable);
+
+/*
+ * signaling protocol:
+ *
+ * each side of the shm_signal has an "irq" structure with the following
+ * fields:
+ *
+ * - enabled: controlled by shm_signal_enable/disable() to mask/unmask
+ * the notification locally
+ * - dirty: indicates if the shared-memory is dirty or clean. This
+ * is updated regardless of the enabled/pending state so that
+ * the state is always accurately tracked.
+ * - pending: indicates if a signal is pending to the remote locale.
+ * This allows us to determine if a remote-notification is
+ * already in flight to optimize spurious notifications away.
+ */
+int shm_signal_inject(struct shm_signal *s, int flags)
+{
+ /* Load the irq structure from the other locale */
+ struct shm_signal_irq *irq = &s->desc->irq[!s->locale];
+
+ /*
+ * We always mark the remote side as dirty regardless of whether
+ * they need to be notified.
+ */
+ irq->dirty = 1;
+ wmb(); /* dirty must be visible before we test the pending state */
+
+ if (irq->enabled && !irq->pending) {
+ rmb();
+
+ /*
+ * If the remote side has enabled notifications, and we do
+ * not see a notification pending, we must inject a new one.
+ */
+ irq->pending = 1;
+ wmb(); /* make it visible before we do the injection */
+
+ s->ops->inject(s);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(shm_signal_inject);
+
+void _shm_signal_wakeup(struct shm_signal *s)
+{
+ struct shm_signal_irq *irq = &s->desc->irq[s->locale];
+ int dirty;
+ unsigned long flags;
+
+ spin_lock_irqsave(&s->lock, flags);
+
+ __set_bit(shm_signal_in_wakeup, &s->flags);
+
+ /*
+ * The outer loop protects against race conditions between
+ * irq->dirty and irq->pending updates
+ */
+ while (irq->enabled && (irq->dirty || irq->pending)) {
+
+ /*
+ * Run until we completely exhaust irq->dirty (it may
+ * be re-dirtied by the remote side while we are in the
+ * callback). We let "pending" remain untouched until we have
+ * processed them all so that the remote side knows we do not
+ * need a new notification (yet).
+ */
+ do {
+ irq->dirty = 0;
+ /* the unlock is an implicit wmb() for dirty = 0 */
+ spin_unlock_irqrestore(&s->lock, flags);
+
+ if (s->notifier)
+ s->notifier->signal(s->notifier);
+
+ spin_lock_irqsave(&s->lock, flags);
+ dirty = irq->dirty;
+ rmb();
+
+ } while (irq->enabled && dirty);
+
+ barrier();
+
+ /*
+ * We can finally acknowledge the notification by clearing
+ * "pending" after all of the dirty memory has been processed
+ * Races against this clearing are handled by the outer loop.
+ * Subsequent iterations of this loop will execute with
+ * pending=0 potentially leading to future spurious
+ * notifications, but this is an acceptable tradeoff as this
+ * will be rare and harmless.
+ */
+ irq->pending = 0;
+ wmb();
+
+ }
+
+ __clear_bit(shm_signal_in_wakeup, &s->flags);
+ spin_unlock_irqrestore(&s->lock, flags);
+
+}
+EXPORT_SYMBOL_GPL(_shm_signal_wakeup);
+
+void _shm_signal_release(struct kref *kref)
+{
+ struct shm_signal *s = container_of(kref, struct shm_signal, kref);
+
+ s->ops->release(s);
+}
+EXPORT_SYMBOL_GPL(_shm_signal_release);
+
+static void
+deferred_notify(unsigned long data)
+{
+ struct shm_signal *s = (struct shm_signal *)data;
+
+ _shm_signal_wakeup(s);
+}
+
+void shm_signal_init(struct shm_signal *s, enum shm_signal_locality locale,
+ struct shm_signal_ops *ops, struct shm_signal_desc *desc)
+{
+ memset(s, 0, sizeof(*s));
+ kref_init(&s->kref);
+ spin_lock_init(&s->lock);
+ tasklet_init(&s->deferred_notify,
+ deferred_notify,
+ (unsigned long)s);
+ s->locale = locale;
+ s->ops = ops;
+ s->desc = desc;
+}
+EXPORT_SYMBOL_GPL(shm_signal_init);
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 33bed5e67a21..a6e195163eb3 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -595,35 +595,81 @@ static char *symbol_string(char *buf, char *end, void *ptr,
}
static char *resource_string(char *buf, char *end, struct resource *res,
- struct printf_spec spec)
+ struct printf_spec spec, const char *fmt)
{
#ifndef IO_RSRC_PRINTK_SIZE
-#define IO_RSRC_PRINTK_SIZE 4
+#define IO_RSRC_PRINTK_SIZE 6
#endif
#ifndef MEM_RSRC_PRINTK_SIZE
-#define MEM_RSRC_PRINTK_SIZE 8
+#define MEM_RSRC_PRINTK_SIZE 10
#endif
- struct printf_spec num_spec = {
+ struct printf_spec hex_spec = {
.base = 16,
.precision = -1,
.flags = SPECIAL | SMALL | ZEROPAD,
};
- /* room for the actual numbers, the two "0x", -, [, ] and the final zero */
- char sym[4*sizeof(resource_size_t) + 8];
+ struct printf_spec dec_spec = {
+ .base = 10,
+ .precision = -1,
+ .flags = 0,
+ };
+ struct printf_spec str_spec = {
+ .field_width = -1,
+ .precision = 10,
+ .flags = LEFT,
+ };
+ struct printf_spec flag_spec = {
+ .base = 16,
+ .precision = -1,
+ .flags = SPECIAL | SMALL,
+ };
+ /*
+ * room for three actual numbers (decimal or hex), plus
+ * "[mem 0x-0x 64bit pref disabled flags 0x]\0"
+ */
+ char sym[3*3*sizeof(resource_size_t) + 41];
char *p = sym, *pend = sym + sizeof(sym);
- int size = -1;
+ int size = -1, addr = 0;
- if (res->flags & IORESOURCE_IO)
+ if (res->flags & IORESOURCE_IO) {
size = IO_RSRC_PRINTK_SIZE;
- else if (res->flags & IORESOURCE_MEM)
+ addr = 1;
+ } else if (res->flags & IORESOURCE_MEM) {
size = MEM_RSRC_PRINTK_SIZE;
+ addr = 1;
+ }
*p++ = '[';
- num_spec.field_width = size;
- p = number(p, pend, res->start, num_spec);
- *p++ = '-';
- p = number(p, pend, res->end, num_spec);
+ if (fmt[1] == 't' || fmt[1] == 'f') {
+ if (res->flags & IORESOURCE_IO)
+ p = string(p, pend, "io ", str_spec);
+ else if (res->flags & IORESOURCE_MEM)
+ p = string(p, pend, "mem ", str_spec);
+ else if (res->flags & IORESOURCE_IRQ)
+ p = string(p, pend, "irq ", str_spec);
+ else if (res->flags & IORESOURCE_DMA)
+ p = string(p, pend, "dma ", str_spec);
+ }
+ hex_spec.field_width = size;
+ p = number(p, pend, res->start, addr ? hex_spec : dec_spec);
+ if (res->start != res->end) {
+ *p++ = '-';
+ p = number(p, pend, res->end, addr ? hex_spec : dec_spec);
+ }
+ if (fmt[1] == 't' || fmt[1] == 'f') {
+ if (res->flags & IORESOURCE_MEM_64)
+ p = string(p, pend, " 64bit", str_spec);
+ if (res->flags & IORESOURCE_PREFETCH)
+ p = string(p, pend, " pref", str_spec);
+ if (res->flags & IORESOURCE_DISABLED)
+ p = string(p, pend, " disabled", str_spec);
+ if (fmt[1] == 'f') {
+ p = string(p, pend, " flags ", str_spec);
+ p = number(p, pend, res->flags & ~IORESOURCE_TYPE_BITS,
+ flag_spec);
+ }
+ }
*p++ = ']';
*p = 0;
@@ -801,8 +847,10 @@ static char *ip4_addr_string(char *buf, char *end, const u8 *addr,
* - 'f' For simple symbolic function names without offset
* - 'S' For symbolic direct pointers with offset
* - 's' For symbolic direct pointers without offset
- * - 'R' For a struct resource pointer, it prints the range of
- * addresses (not the name nor the flags)
+ * - 'R' For a struct resource pointer, print:
+ * R address range only ([0x0-0x1f])
+ * Rt type and range ([mem 0x0-0x1f 64bit pref])
+ * Rf type, range, and flags ([mem 0x0-0x1f 64bit pref flags 0x1])
* - 'M' For a 6-byte MAC address, it prints the address in the
* usual colon-separated hex notation
* - 'm' For a 6-byte MAC address, it prints the hex address without colons
@@ -833,7 +881,7 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
case 'S':
return symbol_string(buf, end, ptr, spec, *fmt);
case 'R':
- return resource_string(buf, end, ptr, spec);
+ return resource_string(buf, end, ptr, spec, fmt);
case 'M': /* Colon separated: 00:01:02:03:04:05 */
case 'm': /* Contiguous: 000102030405 */
return mac_address_string(buf, end, ptr, spec, fmt);
diff --git a/mm/Kconfig b/mm/Kconfig
index 57963c6063d1..7ca3777bdede 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -129,7 +129,7 @@ config MEMORY_HOTPLUG
bool "Allow for memory hot-add"
depends on SPARSEMEM || X86_64_ACPI_NUMA
depends on HOTPLUG && !(HIBERNATION && !S390) && ARCH_ENABLE_MEMORY_HOTPLUG
- depends on (IA64 || X86 || PPC64 || SUPERH || S390)
+ depends on (IA64 || X86 || PPC_BOOK3S_64 || SUPERH || S390)
comment "Memory hotplug is currently incompatible with Software Suspend"
depends on SPARSEMEM && HOTPLUG && HIBERNATION && !S390
diff --git a/mm/Makefile b/mm/Makefile
index ebf849042ed3..1f6e10c384cc 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -29,16 +29,13 @@ obj-$(CONFIG_KSM) += ksm.o
obj-$(CONFIG_PAGE_POISONING) += debug-pagealloc.o
obj-$(CONFIG_SLAB) += slab.o
obj-$(CONFIG_SLUB) += slub.o
+obj-$(CONFIG_SLQB) += slqb.o
obj-$(CONFIG_KMEMCHECK) += kmemcheck.o
obj-$(CONFIG_FAILSLAB) += failslab.o
obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
obj-$(CONFIG_FS_XIP) += filemap_xip.o
obj-$(CONFIG_MIGRATION) += migrate.o
-ifndef CONFIG_HAVE_LEGACY_PER_CPU_AREA
obj-$(CONFIG_SMP) += percpu.o
-else
-obj-$(CONFIG_SMP) += allocpercpu.o
-endif
obj-$(CONFIG_QUICKLIST) += quicklist.o
obj-$(CONFIG_CGROUP_MEM_RES_CTLR) += memcontrol.o page_cgroup.o
obj-$(CONFIG_MEMORY_FAILURE) += memory-failure.o
diff --git a/mm/allocpercpu.c b/mm/allocpercpu.c
deleted file mode 100644
index df34ceae0c67..000000000000
--- a/mm/allocpercpu.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * linux/mm/allocpercpu.c
- *
- * Separated from slab.c August 11, 2006 Christoph Lameter
- */
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/bootmem.h>
-#include <asm/sections.h>
-
-#ifndef cache_line_size
-#define cache_line_size() L1_CACHE_BYTES
-#endif
-
-/**
- * percpu_depopulate - depopulate per-cpu data for given cpu
- * @__pdata: per-cpu data to depopulate
- * @cpu: depopulate per-cpu data for this cpu
- *
- * Depopulating per-cpu data for a cpu going offline would be a typical
- * use case. You need to register a cpu hotplug handler for that purpose.
- */
-static void percpu_depopulate(void *__pdata, int cpu)
-{
- struct percpu_data *pdata = __percpu_disguise(__pdata);
-
- kfree(pdata->ptrs[cpu]);
- pdata->ptrs[cpu] = NULL;
-}
-
-/**
- * percpu_depopulate_mask - depopulate per-cpu data for some cpu's
- * @__pdata: per-cpu data to depopulate
- * @mask: depopulate per-cpu data for cpu's selected through mask bits
- */
-static void __percpu_depopulate_mask(void *__pdata, const cpumask_t *mask)
-{
- int cpu;
- for_each_cpu_mask_nr(cpu, *mask)
- percpu_depopulate(__pdata, cpu);
-}
-
-#define percpu_depopulate_mask(__pdata, mask) \
- __percpu_depopulate_mask((__pdata), &(mask))
-
-/**
- * percpu_populate - populate per-cpu data for given cpu
- * @__pdata: per-cpu data to populate further
- * @size: size of per-cpu object
- * @gfp: may sleep or not etc.
- * @cpu: populate per-data for this cpu
- *
- * Populating per-cpu data for a cpu coming online would be a typical
- * use case. You need to register a cpu hotplug handler for that purpose.
- * Per-cpu object is populated with zeroed buffer.
- */
-static void *percpu_populate(void *__pdata, size_t size, gfp_t gfp, int cpu)
-{
- struct percpu_data *pdata = __percpu_disguise(__pdata);
- int node = cpu_to_node(cpu);
-
- /*
- * We should make sure each CPU gets private memory.
- */
- size = roundup(size, cache_line_size());
-
- BUG_ON(pdata->ptrs[cpu]);
- if (node_online(node))
- pdata->ptrs[cpu] = kmalloc_node(size, gfp|__GFP_ZERO, node);
- else
- pdata->ptrs[cpu] = kzalloc(size, gfp);
- return pdata->ptrs[cpu];
-}
-
-/**
- * percpu_populate_mask - populate per-cpu data for more cpu's
- * @__pdata: per-cpu data to populate further
- * @size: size of per-cpu object
- * @gfp: may sleep or not etc.
- * @mask: populate per-cpu data for cpu's selected through mask bits
- *
- * Per-cpu objects are populated with zeroed buffers.
- */
-static int __percpu_populate_mask(void *__pdata, size_t size, gfp_t gfp,
- cpumask_t *mask)
-{
- cpumask_t populated;
- int cpu;
-
- cpus_clear(populated);
- for_each_cpu_mask_nr(cpu, *mask)
- if (unlikely(!percpu_populate(__pdata, size, gfp, cpu))) {
- __percpu_depopulate_mask(__pdata, &populated);
- return -ENOMEM;
- } else
- cpu_set(cpu, populated);
- return 0;
-}
-
-#define percpu_populate_mask(__pdata, size, gfp, mask) \
- __percpu_populate_mask((__pdata), (size), (gfp), &(mask))
-
-/**
- * alloc_percpu - initial setup of per-cpu data
- * @size: size of per-cpu object
- * @align: alignment
- *
- * Allocate dynamic percpu area. Percpu objects are populated with
- * zeroed buffers.
- */
-void *__alloc_percpu(size_t size, size_t align)
-{
- /*
- * We allocate whole cache lines to avoid false sharing
- */
- size_t sz = roundup(nr_cpu_ids * sizeof(void *), cache_line_size());
- void *pdata = kzalloc(sz, GFP_KERNEL);
- void *__pdata = __percpu_disguise(pdata);
-
- /*
- * Can't easily make larger alignment work with kmalloc. WARN
- * on it. Larger alignment should only be used for module
- * percpu sections on SMP for which this path isn't used.
- */
- WARN_ON_ONCE(align > SMP_CACHE_BYTES);
-
- if (unlikely(!pdata))
- return NULL;
- if (likely(!__percpu_populate_mask(__pdata, size, GFP_KERNEL,
- &cpu_possible_map)))
- return __pdata;
- kfree(pdata);
- return NULL;
-}
-EXPORT_SYMBOL_GPL(__alloc_percpu);
-
-/**
- * free_percpu - final cleanup of per-cpu data
- * @__pdata: object to clean up
- *
- * We simply clean up any per-cpu object left. No need for the client to
- * track and specify through a bis mask which per-cpu objects are to free.
- */
-void free_percpu(void *__pdata)
-{
- if (unlikely(!__pdata))
- return;
- __percpu_depopulate_mask(__pdata, cpu_possible_mask);
- kfree(__percpu_disguise(__pdata));
-}
-EXPORT_SYMBOL_GPL(free_percpu);
-
-/*
- * Generic percpu area setup.
- */
-#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
-unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
-
-EXPORT_SYMBOL(__per_cpu_offset);
-
-void __init setup_per_cpu_areas(void)
-{
- unsigned long size, i;
- char *ptr;
- unsigned long nr_possible_cpus = num_possible_cpus();
-
- /* Copy section for each CPU (we discard the original) */
- size = ALIGN(PERCPU_ENOUGH_ROOM, PAGE_SIZE);
- ptr = alloc_bootmem_pages(size * nr_possible_cpus);
-
- for_each_possible_cpu(i) {
- __per_cpu_offset[i] = ptr - __per_cpu_start;
- memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
- ptr += size;
- }
-}
-#endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */
diff --git a/mm/filemap.c b/mm/filemap.c
index ef169f37156d..00c1bfd310ce 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -260,27 +260,27 @@ int filemap_flush(struct address_space *mapping)
EXPORT_SYMBOL(filemap_flush);
/**
- * wait_on_page_writeback_range - wait for writeback to complete
- * @mapping: target address_space
- * @start: beginning page index
- * @end: ending page index
+ * filemap_fdatawait_range - wait for writeback to complete
+ * @mapping: address space structure to wait for
+ * @start_byte: offset in bytes where the range starts
+ * @end_byte: offset in bytes where the range ends (inclusive)
*
- * Wait for writeback to complete against pages indexed by start->end
- * inclusive
+ * Walk the list of under-writeback pages of the given address space
+ * in the given range and wait for all of them.
*/
-int wait_on_page_writeback_range(struct address_space *mapping,
- pgoff_t start, pgoff_t end)
+int filemap_fdatawait_range(struct address_space *mapping, loff_t start_byte,
+ loff_t end_byte)
{
+ pgoff_t index = start_byte >> PAGE_CACHE_SHIFT;
+ pgoff_t end = end_byte >> PAGE_CACHE_SHIFT;
struct pagevec pvec;
int nr_pages;
int ret = 0;
- pgoff_t index;
- if (end < start)
+ if (end_byte < start_byte)
return 0;
pagevec_init(&pvec, 0);
- index = start;
while ((index <= end) &&
(nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
PAGECACHE_TAG_WRITEBACK,
@@ -310,25 +310,6 @@ int wait_on_page_writeback_range(struct address_space *mapping,
return ret;
}
-
-/**
- * filemap_fdatawait_range - wait for all under-writeback pages to complete in a given range
- * @mapping: address space structure to wait for
- * @start: offset in bytes where the range starts
- * @end: offset in bytes where the range ends (inclusive)
- *
- * Walk the list of under-writeback pages of the given address space
- * in the given range and wait for all of them.
- *
- * This is just a simple wrapper so that callers don't have to convert offsets
- * to page indexes themselves
- */
-int filemap_fdatawait_range(struct address_space *mapping, loff_t start,
- loff_t end)
-{
- return wait_on_page_writeback_range(mapping, start >> PAGE_CACHE_SHIFT,
- end >> PAGE_CACHE_SHIFT);
-}
EXPORT_SYMBOL(filemap_fdatawait_range);
/**
@@ -345,8 +326,7 @@ int filemap_fdatawait(struct address_space *mapping)
if (i_size == 0)
return 0;
- return wait_on_page_writeback_range(mapping, 0,
- (i_size - 1) >> PAGE_CACHE_SHIFT);
+ return filemap_fdatawait_range(mapping, 0, i_size - 1);
}
EXPORT_SYMBOL(filemap_fdatawait);
@@ -393,9 +373,8 @@ int filemap_write_and_wait_range(struct address_space *mapping,
WB_SYNC_ALL);
/* See comment of filemap_write_and_wait() */
if (err != -EIO) {
- int err2 = wait_on_page_writeback_range(mapping,
- lstart >> PAGE_CACHE_SHIFT,
- lend >> PAGE_CACHE_SHIFT);
+ int err2 = filemap_fdatawait_range(mapping,
+ lstart, lend);
if (!err)
err = err2;
}
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index 8bf765c4f58d..a1e413f6cd0e 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -119,8 +119,8 @@
/* scanning area inside a memory block */
struct kmemleak_scan_area {
struct hlist_node node;
- unsigned long offset;
- size_t length;
+ unsigned long start;
+ size_t size;
};
#define KMEMLEAK_GREY 0
@@ -241,8 +241,6 @@ struct early_log {
const void *ptr; /* allocated/freed memory block */
size_t size; /* memory block size */
int min_count; /* minimum reference count */
- unsigned long offset; /* scan area offset */
- size_t length; /* scan area length */
unsigned long trace[MAX_TRACE]; /* stack trace */
unsigned int trace_len; /* stack trace length */
};
@@ -720,14 +718,13 @@ static void make_black_object(unsigned long ptr)
* Add a scanning area to the object. If at least one such area is added,
* kmemleak will only scan these ranges rather than the whole memory block.
*/
-static void add_scan_area(unsigned long ptr, unsigned long offset,
- size_t length, gfp_t gfp)
+static void add_scan_area(unsigned long ptr, size_t size, gfp_t gfp)
{
unsigned long flags;
struct kmemleak_object *object;
struct kmemleak_scan_area *area;
- object = find_and_get_object(ptr, 0);
+ object = find_and_get_object(ptr, 1);
if (!object) {
kmemleak_warn("Adding scan area to unknown object at 0x%08lx\n",
ptr);
@@ -741,7 +738,7 @@ static void add_scan_area(unsigned long ptr, unsigned long offset,
}
spin_lock_irqsave(&object->lock, flags);
- if (offset + length > object->size) {
+ if (ptr + size > object->pointer + object->size) {
kmemleak_warn("Scan area larger than object 0x%08lx\n", ptr);
dump_object_info(object);
kmem_cache_free(scan_area_cache, area);
@@ -749,8 +746,8 @@ static void add_scan_area(unsigned long ptr, unsigned long offset,
}
INIT_HLIST_NODE(&area->node);
- area->offset = offset;
- area->length = length;
+ area->start = ptr;
+ area->size = size;
hlist_add_head(&area->node, &object->area_list);
out_unlock:
@@ -786,7 +783,7 @@ static void object_no_scan(unsigned long ptr)
* processed later once kmemleak is fully initialized.
*/
static void __init log_early(int op_type, const void *ptr, size_t size,
- int min_count, unsigned long offset, size_t length)
+ int min_count)
{
unsigned long flags;
struct early_log *log;
@@ -808,8 +805,6 @@ static void __init log_early(int op_type, const void *ptr, size_t size,
log->ptr = ptr;
log->size = size;
log->min_count = min_count;
- log->offset = offset;
- log->length = length;
if (op_type == KMEMLEAK_ALLOC)
log->trace_len = __save_stack_trace(log->trace);
crt_early_log++;
@@ -858,7 +853,7 @@ void __ref kmemleak_alloc(const void *ptr, size_t size, int min_count,
if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
create_object((unsigned long)ptr, size, min_count, gfp);
else if (atomic_read(&kmemleak_early_log))
- log_early(KMEMLEAK_ALLOC, ptr, size, min_count, 0, 0);
+ log_early(KMEMLEAK_ALLOC, ptr, size, min_count);
}
EXPORT_SYMBOL_GPL(kmemleak_alloc);
@@ -873,7 +868,7 @@ void __ref kmemleak_free(const void *ptr)
if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
delete_object_full((unsigned long)ptr);
else if (atomic_read(&kmemleak_early_log))
- log_early(KMEMLEAK_FREE, ptr, 0, 0, 0, 0);
+ log_early(KMEMLEAK_FREE, ptr, 0, 0);
}
EXPORT_SYMBOL_GPL(kmemleak_free);
@@ -888,7 +883,7 @@ void __ref kmemleak_free_part(const void *ptr, size_t size)
if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
delete_object_part((unsigned long)ptr, size);
else if (atomic_read(&kmemleak_early_log))
- log_early(KMEMLEAK_FREE_PART, ptr, size, 0, 0, 0);
+ log_early(KMEMLEAK_FREE_PART, ptr, size, 0);
}
EXPORT_SYMBOL_GPL(kmemleak_free_part);
@@ -903,7 +898,7 @@ void __ref kmemleak_not_leak(const void *ptr)
if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
make_gray_object((unsigned long)ptr);
else if (atomic_read(&kmemleak_early_log))
- log_early(KMEMLEAK_NOT_LEAK, ptr, 0, 0, 0, 0);
+ log_early(KMEMLEAK_NOT_LEAK, ptr, 0, 0);
}
EXPORT_SYMBOL(kmemleak_not_leak);
@@ -919,22 +914,21 @@ void __ref kmemleak_ignore(const void *ptr)
if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
make_black_object((unsigned long)ptr);
else if (atomic_read(&kmemleak_early_log))
- log_early(KMEMLEAK_IGNORE, ptr, 0, 0, 0, 0);
+ log_early(KMEMLEAK_IGNORE, ptr, 0, 0);
}
EXPORT_SYMBOL(kmemleak_ignore);
/*
* Limit the range to be scanned in an allocated memory block.
*/
-void __ref kmemleak_scan_area(const void *ptr, unsigned long offset,
- size_t length, gfp_t gfp)
+void __ref kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp)
{
pr_debug("%s(0x%p)\n", __func__, ptr);
if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
- add_scan_area((unsigned long)ptr, offset, length, gfp);
+ add_scan_area((unsigned long)ptr, size, gfp);
else if (atomic_read(&kmemleak_early_log))
- log_early(KMEMLEAK_SCAN_AREA, ptr, 0, 0, offset, length);
+ log_early(KMEMLEAK_SCAN_AREA, ptr, size, 0);
}
EXPORT_SYMBOL(kmemleak_scan_area);
@@ -948,7 +942,7 @@ void __ref kmemleak_no_scan(const void *ptr)
if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
object_no_scan((unsigned long)ptr);
else if (atomic_read(&kmemleak_early_log))
- log_early(KMEMLEAK_NO_SCAN, ptr, 0, 0, 0, 0);
+ log_early(KMEMLEAK_NO_SCAN, ptr, 0, 0);
}
EXPORT_SYMBOL(kmemleak_no_scan);
@@ -1050,8 +1044,8 @@ static void scan_object(struct kmemleak_object *object)
unsigned long flags;
/*
- * Once the object->lock is aquired, the corresponding memory block
- * cannot be freed (the same lock is aquired in delete_object).
+ * Once the object->lock is acquired, the corresponding memory block
+ * cannot be freed (the same lock is acquired in delete_object).
*/
spin_lock_irqsave(&object->lock, flags);
if (object->flags & OBJECT_NO_SCAN)
@@ -1075,9 +1069,9 @@ static void scan_object(struct kmemleak_object *object)
}
} else
hlist_for_each_entry(area, elem, &object->area_list, node)
- scan_block((void *)(object->pointer + area->offset),
- (void *)(object->pointer + area->offset
- + area->length), object, 0);
+ scan_block((void *)area->start,
+ (void *)(area->start + area->size),
+ object, 0);
out:
spin_unlock_irqrestore(&object->lock, flags);
}
@@ -1642,8 +1636,7 @@ void __init kmemleak_init(void)
kmemleak_ignore(log->ptr);
break;
case KMEMLEAK_SCAN_AREA:
- kmemleak_scan_area(log->ptr, log->offset, log->length,
- GFP_KERNEL);
+ kmemleak_scan_area(log->ptr, log->size, GFP_KERNEL);
break;
case KMEMLEAK_NO_SCAN:
kmemleak_no_scan(log->ptr);
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index f99f5991d6bb..7226e60e52af 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1720,7 +1720,7 @@ int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
/*
* While swap-in, try_charge -> commit or cancel, the page is locked.
* And when try_charge() successfully returns, one refcnt to memcg without
- * struct page_cgroup is aquired. This refcnt will be cumsumed by
+ * struct page_cgroup is acquired. This refcnt will be consumed by
* "commit()" or removed by "cancel()"
*/
int mem_cgroup_try_charge_swapin(struct mm_struct *mm,
diff --git a/mm/mmap.c b/mm/mmap.c
index 73f5e4b64010..292ddc3cef9c 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -20,7 +20,6 @@
#include <linux/fs.h>
#include <linux/personality.h>
#include <linux/security.h>
-#include <linux/ima.h>
#include <linux/hugetlb.h>
#include <linux/profile.h>
#include <linux/module.h>
@@ -1061,9 +1060,6 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
error = security_file_mmap(file, reqprot, prot, flags, addr, 0);
if (error)
return error;
- error = ima_file_mmap(file, prot);
- if (error)
- return error;
return mmap_region(file, addr, len, flags, vm_flags, pgoff);
}
diff --git a/mm/percpu.c b/mm/percpu.c
index 6af78c1ee704..ec158bb5f86d 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -46,8 +46,6 @@
*
* To use this allocator, arch code should do the followings.
*
- * - drop CONFIG_HAVE_LEGACY_PER_CPU_AREA
- *
* - define __addr_to_pcpu_ptr() and __pcpu_ptr_to_addr() to translate
* regular address to percpu pointer and back if they need to be
* different from the default
diff --git a/mm/slab.c b/mm/slab.c
index 7dfa481c96ba..d2713a944ebd 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -2261,9 +2261,11 @@ kmem_cache_create (const char *name, size_t size, size_t align,
/*
* Determine if the slab management is 'on' or 'off' slab.
* (bootstrapping cannot cope with offslab caches so don't do
- * it too early on.)
+ * it too early on. Always use on-slab management when
+ * SLAB_NOLEAKTRACE to avoid recursive calls into kmemleak)
*/
- if ((size >= (PAGE_SIZE >> 3)) && !slab_early_init)
+ if ((size >= (PAGE_SIZE >> 3)) && !slab_early_init &&
+ !(flags & SLAB_NOLEAKTRACE))
/*
* Size is large, assume best to place the slab management obj
* off-slab (should allow better packing of objs).
@@ -2582,8 +2584,8 @@ static struct slab *alloc_slabmgmt(struct kmem_cache *cachep, void *objp,
* kmemleak does not treat the ->s_mem pointer as a reference
* to the object. Otherwise we will not report the leak.
*/
- kmemleak_scan_area(slabp, offsetof(struct slab, list),
- sizeof(struct list_head), local_flags);
+ kmemleak_scan_area(&slabp->list, sizeof(struct list_head),
+ local_flags);
if (!slabp)
return NULL;
} else {
diff --git a/mm/slqb.c b/mm/slqb.c
new file mode 100644
index 000000000000..e745d9ac0956
--- /dev/null
+++ b/mm/slqb.c
@@ -0,0 +1,3791 @@
+/*
+ * SLQB: A slab allocator that focuses on per-CPU scaling, and good performance
+ * with order-0 allocations. Fastpaths emphasis is placed on local allocaiton
+ * and freeing, but with a secondary goal of good remote freeing (freeing on
+ * another CPU from that which allocated).
+ *
+ * Using ideas and code from mm/slab.c, mm/slob.c, and mm/slub.c.
+ */
+
+#include <linux/mm.h>
+#include <linux/swap.h> /* struct reclaim_state */
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/cpu.h>
+#include <linux/cpuset.h>
+#include <linux/mempolicy.h>
+#include <linux/ctype.h>
+#include <linux/kallsyms.h>
+#include <linux/memory.h>
+#include <linux/fault-inject.h>
+
+/*
+ * TODO
+ * - fix up releasing of offlined data structures. Not a big deal because
+ * they don't get cumulatively leaked with successive online/offline cycles
+ * - allow OOM conditions to flush back per-CPU pages to common lists to be
+ * reused by other CPUs.
+ * - investiage performance with memoryless nodes. Perhaps CPUs can be given
+ * a default closest home node via which it can use fastpath functions.
+ * Perhaps it is not a big problem.
+ */
+
+/*
+ * slqb_page overloads struct page, and is used to manage some slob allocation
+ * aspects, however to avoid the horrible mess in include/linux/mm_types.h,
+ * we'll just define our own struct slqb_page type variant here.
+ */
+struct slqb_page {
+ union {
+ struct {
+ unsigned long flags; /* mandatory */
+ atomic_t _count; /* mandatory */
+ unsigned int inuse; /* Nr of objects */
+ struct kmem_cache_list *list; /* Pointer to list */
+ void **freelist; /* LIFO freelist */
+ union {
+ struct list_head lru; /* misc. list */
+ struct rcu_head rcu_head; /* for rcu freeing */
+ };
+ };
+ struct page page;
+ };
+};
+static inline void struct_slqb_page_wrong_size(void)
+{ BUILD_BUG_ON(sizeof(struct slqb_page) != sizeof(struct page)); }
+
+#define PG_SLQB_BIT (1 << PG_slab)
+
+/*
+ * slqb_min_order: minimum allocation order for slabs
+ */
+static int slqb_min_order;
+
+/*
+ * slqb_min_objects: minimum number of objects per slab. Increasing this
+ * will increase the allocation order for slabs with larger objects
+ */
+static int slqb_min_objects = 1;
+
+#ifdef CONFIG_NUMA
+static inline int slab_numa(struct kmem_cache *s)
+{
+ return s->flags & SLAB_NUMA;
+}
+#else
+static inline int slab_numa(struct kmem_cache *s)
+{
+ return 0;
+}
+#endif
+
+static inline int slab_hiwater(struct kmem_cache *s)
+{
+ return s->hiwater;
+}
+
+static inline int slab_freebatch(struct kmem_cache *s)
+{
+ return s->freebatch;
+}
+
+/*
+ * Lock order:
+ * kmem_cache_node->list_lock
+ * kmem_cache_remote_free->lock
+ *
+ * Data structures:
+ * SLQB is primarily per-cpu. For each kmem_cache, each CPU has:
+ *
+ * - A LIFO list of node-local objects. Allocation and freeing of node local
+ * objects goes first to this list.
+ *
+ * - 2 Lists of slab pages, free and partial pages. If an allocation misses
+ * the object list, it tries from the partial list, then the free list.
+ * After freeing an object to the object list, if it is over a watermark,
+ * some objects are freed back to pages. If an allocation misses these lists,
+ * a new slab page is allocated from the page allocator. If the free list
+ * reaches a watermark, some of its pages are returned to the page allocator.
+ *
+ * - A remote free queue, where objects freed that did not come from the local
+ * node are queued to. When this reaches a watermark, the objects are
+ * flushed.
+ *
+ * - A remotely freed queue, where objects allocated from this CPU are flushed
+ * to from other CPUs' remote free queues. kmem_cache_remote_free->lock is
+ * used to protect access to this queue.
+ *
+ * When the remotely freed queue reaches a watermark, a flag is set to tell
+ * the owner CPU to check it. The owner CPU will then check the queue on the
+ * next allocation that misses the object list. It will move all objects from
+ * this list onto the object list and then allocate one.
+ *
+ * This system of remote queueing is intended to reduce lock and remote
+ * cacheline acquisitions, and give a cooling off period for remotely freed
+ * objects before they are re-allocated.
+ *
+ * node specific allocations from somewhere other than the local node are
+ * handled by a per-node list which is the same as the above per-CPU data
+ * structures except for the following differences:
+ *
+ * - kmem_cache_node->list_lock is used to protect access for multiple CPUs to
+ * allocate from a given node.
+ *
+ * - There is no remote free queue. Nodes don't free objects, CPUs do.
+ */
+
+static inline void slqb_stat_inc(struct kmem_cache_list *list,
+ enum stat_item si)
+{
+#ifdef CONFIG_SLQB_STATS
+ list->stats[si]++;
+#endif
+}
+
+static inline void slqb_stat_add(struct kmem_cache_list *list,
+ enum stat_item si, unsigned long nr)
+{
+#ifdef CONFIG_SLQB_STATS
+ list->stats[si] += nr;
+#endif
+}
+
+static inline int slqb_page_to_nid(struct slqb_page *page)
+{
+ return page_to_nid(&page->page);
+}
+
+static inline void *slqb_page_address(struct slqb_page *page)
+{
+ return page_address(&page->page);
+}
+
+static inline struct zone *slqb_page_zone(struct slqb_page *page)
+{
+ return page_zone(&page->page);
+}
+
+static inline int virt_to_nid(const void *addr)
+{
+ return page_to_nid(virt_to_page(addr));
+}
+
+static inline struct slqb_page *virt_to_head_slqb_page(const void *addr)
+{
+ struct page *p;
+
+ p = virt_to_head_page(addr);
+ return (struct slqb_page *)p;
+}
+
+static inline void __free_slqb_pages(struct slqb_page *page, unsigned int order,
+ int pages)
+{
+ struct page *p = &page->page;
+
+ reset_page_mapcount(p);
+ p->mapping = NULL;
+ VM_BUG_ON(!(p->flags & PG_SLQB_BIT));
+ p->flags &= ~PG_SLQB_BIT;
+
+ if (current->reclaim_state)
+ current->reclaim_state->reclaimed_slab += pages;
+ __free_pages(p, order);
+}
+
+#ifdef CONFIG_SLQB_DEBUG
+static inline int slab_debug(struct kmem_cache *s)
+{
+ return s->flags &
+ (SLAB_DEBUG_FREE |
+ SLAB_RED_ZONE |
+ SLAB_POISON |
+ SLAB_STORE_USER |
+ SLAB_TRACE);
+}
+static inline int slab_poison(struct kmem_cache *s)
+{
+ return s->flags & SLAB_POISON;
+}
+#else
+static inline int slab_debug(struct kmem_cache *s)
+{
+ return 0;
+}
+static inline int slab_poison(struct kmem_cache *s)
+{
+ return 0;
+}
+#endif
+
+#define DEBUG_DEFAULT_FLAGS (SLAB_DEBUG_FREE | SLAB_RED_ZONE | \
+ SLAB_POISON | SLAB_STORE_USER)
+
+/* Internal SLQB flags */
+#define __OBJECT_POISON 0x80000000 /* Poison object */
+
+/* Not all arches define cache_line_size */
+#ifndef cache_line_size
+#define cache_line_size() L1_CACHE_BYTES
+#endif
+
+#ifdef CONFIG_SMP
+static struct notifier_block slab_notifier;
+#endif
+
+/*
+ * slqb_lock protects slab_caches list and serialises hotplug operations.
+ * hotplug operations take lock for write, other operations can hold off
+ * hotplug by taking it for read (or write).
+ */
+static DECLARE_RWSEM(slqb_lock);
+
+/*
+ * A list of all slab caches on the system
+ */
+static LIST_HEAD(slab_caches);
+
+/*
+ * Tracking user of a slab.
+ */
+struct track {
+ unsigned long addr; /* Called from address */
+ int cpu; /* Was running on cpu */
+ int pid; /* Pid context */
+ unsigned long when; /* When did the operation occur */
+};
+
+enum track_item { TRACK_ALLOC, TRACK_FREE };
+
+static struct kmem_cache kmem_cache_cache;
+
+#ifdef CONFIG_SLQB_SYSFS
+static int sysfs_slab_add(struct kmem_cache *s);
+static void sysfs_slab_remove(struct kmem_cache *s);
+#else
+static inline int sysfs_slab_add(struct kmem_cache *s)
+{
+ return 0;
+}
+static inline void sysfs_slab_remove(struct kmem_cache *s)
+{
+ kmem_cache_free(&kmem_cache_cache, s);
+}
+#endif
+
+/********************************************************************
+ * Core slab cache functions
+ *******************************************************************/
+
+static int __slab_is_available __read_mostly;
+int slab_is_available(void)
+{
+ return __slab_is_available;
+}
+
+static inline struct kmem_cache_cpu *get_cpu_slab(struct kmem_cache *s, int cpu)
+{
+#ifdef CONFIG_SMP
+ VM_BUG_ON(!s->cpu_slab[cpu]);
+ return s->cpu_slab[cpu];
+#else
+ return &s->cpu_slab;
+#endif
+}
+
+static inline int check_valid_pointer(struct kmem_cache *s,
+ struct slqb_page *page, const void *object)
+{
+ void *base;
+
+ base = slqb_page_address(page);
+ if (object < base || object >= base + s->objects * s->size ||
+ (object - base) % s->size) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static inline void *get_freepointer(struct kmem_cache *s, void *object)
+{
+ return *(void **)(object + s->offset);
+}
+
+static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
+{
+ *(void **)(object + s->offset) = fp;
+}
+
+/* Loop over all objects in a slab */
+#define for_each_object(__p, __s, __addr) \
+ for (__p = (__addr); __p < (__addr) + (__s)->objects * (__s)->size;\
+ __p += (__s)->size)
+
+/* Scan freelist */
+#define for_each_free_object(__p, __s, __free) \
+ for (__p = (__free); (__p) != NULL; __p = get_freepointer((__s),\
+ __p))
+
+#ifdef CONFIG_SLQB_DEBUG
+/*
+ * Debug settings:
+ */
+#ifdef CONFIG_SLQB_DEBUG_ON
+static int slqb_debug __read_mostly = DEBUG_DEFAULT_FLAGS;
+#else
+static int slqb_debug __read_mostly;
+#endif
+
+static char *slqb_debug_slabs;
+
+/*
+ * Object debugging
+ */
+static void print_section(char *text, u8 *addr, unsigned int length)
+{
+ int i, offset;
+ int newline = 1;
+ char ascii[17];
+
+ ascii[16] = 0;
+
+ for (i = 0; i < length; i++) {
+ if (newline) {
+ printk(KERN_ERR "%8s 0x%p: ", text, addr + i);
+ newline = 0;
+ }
+ printk(KERN_CONT " %02x", addr[i]);
+ offset = i % 16;
+ ascii[offset] = isgraph(addr[i]) ? addr[i] : '.';
+ if (offset == 15) {
+ printk(KERN_CONT " %s\n", ascii);
+ newline = 1;
+ }
+ }
+ if (!newline) {
+ i %= 16;
+ while (i < 16) {
+ printk(KERN_CONT " ");
+ ascii[i] = ' ';
+ i++;
+ }
+ printk(KERN_CONT " %s\n", ascii);
+ }
+}
+
+static struct track *get_track(struct kmem_cache *s, void *object,
+ enum track_item alloc)
+{
+ struct track *p;
+
+ if (s->offset)
+ p = object + s->offset + sizeof(void *);
+ else
+ p = object + s->inuse;
+
+ return p + alloc;
+}
+
+static void set_track(struct kmem_cache *s, void *object,
+ enum track_item alloc, unsigned long addr)
+{
+ struct track *p;
+
+ if (s->offset)
+ p = object + s->offset + sizeof(void *);
+ else
+ p = object + s->inuse;
+
+ p += alloc;
+ if (addr) {
+ p->addr = addr;
+ p->cpu = raw_smp_processor_id();
+ p->pid = current ? current->pid : -1;
+ p->when = jiffies;
+ } else
+ memset(p, 0, sizeof(struct track));
+}
+
+static void init_tracking(struct kmem_cache *s, void *object)
+{
+ if (!(s->flags & SLAB_STORE_USER))
+ return;
+
+ set_track(s, object, TRACK_FREE, 0UL);
+ set_track(s, object, TRACK_ALLOC, 0UL);
+}
+
+static void print_track(const char *s, struct track *t)
+{
+ if (!t->addr)
+ return;
+
+ printk(KERN_ERR "INFO: %s in ", s);
+ __print_symbol("%s", (unsigned long)t->addr);
+ printk(" age=%lu cpu=%u pid=%d\n", jiffies - t->when, t->cpu, t->pid);
+}
+
+static void print_tracking(struct kmem_cache *s, void *object)
+{
+ if (!(s->flags & SLAB_STORE_USER))
+ return;
+
+ print_track("Allocated", get_track(s, object, TRACK_ALLOC));
+ print_track("Freed", get_track(s, object, TRACK_FREE));
+}
+
+static void print_page_info(struct slqb_page *page)
+{
+ printk(KERN_ERR "INFO: Slab 0x%p used=%u fp=0x%p flags=0x%04lx\n",
+ page, page->inuse, page->freelist, page->flags);
+
+}
+
+#define MAX_ERR_STR 100
+static void slab_bug(struct kmem_cache *s, char *fmt, ...)
+{
+ va_list args;
+ char buf[MAX_ERR_STR];
+
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+ printk(KERN_ERR "========================================"
+ "=====================================\n");
+ printk(KERN_ERR "BUG %s: %s\n", s->name, buf);
+ printk(KERN_ERR "----------------------------------------"
+ "-------------------------------------\n\n");
+}
+
+static void slab_fix(struct kmem_cache *s, char *fmt, ...)
+{
+ va_list args;
+ char buf[100];
+
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+ printk(KERN_ERR "FIX %s: %s\n", s->name, buf);
+}
+
+static void print_trailer(struct kmem_cache *s, struct slqb_page *page, u8 *p)
+{
+ unsigned int off; /* Offset of last byte */
+ u8 *addr = slqb_page_address(page);
+
+ print_tracking(s, p);
+
+ print_page_info(page);
+
+ printk(KERN_ERR "INFO: Object 0x%p @offset=%tu fp=0x%p\n\n",
+ p, p - addr, get_freepointer(s, p));
+
+ if (p > addr + 16)
+ print_section("Bytes b4", p - 16, 16);
+
+ print_section("Object", p, min(s->objsize, 128));
+
+ if (s->flags & SLAB_RED_ZONE)
+ print_section("Redzone", p + s->objsize, s->inuse - s->objsize);
+
+ if (s->offset)
+ off = s->offset + sizeof(void *);
+ else
+ off = s->inuse;
+
+ if (s->flags & SLAB_STORE_USER)
+ off += 2 * sizeof(struct track);
+
+ if (off != s->size) {
+ /* Beginning of the filler is the free pointer */
+ print_section("Padding", p + off, s->size - off);
+ }
+
+ dump_stack();
+}
+
+static void object_err(struct kmem_cache *s, struct slqb_page *page,
+ u8 *object, char *reason)
+{
+ slab_bug(s, reason);
+ print_trailer(s, page, object);
+}
+
+static void slab_err(struct kmem_cache *s, struct slqb_page *page,
+ char *fmt, ...)
+{
+ slab_bug(s, fmt);
+ print_page_info(page);
+ dump_stack();
+}
+
+static void init_object(struct kmem_cache *s, void *object, int active)
+{
+ u8 *p = object;
+
+ if (s->flags & __OBJECT_POISON) {
+ memset(p, POISON_FREE, s->objsize - 1);
+ p[s->objsize - 1] = POISON_END;
+ }
+
+ if (s->flags & SLAB_RED_ZONE) {
+ memset(p + s->objsize,
+ active ? SLUB_RED_ACTIVE : SLUB_RED_INACTIVE,
+ s->inuse - s->objsize);
+ }
+}
+
+static u8 *check_bytes(u8 *start, unsigned int value, unsigned int bytes)
+{
+ while (bytes) {
+ if (*start != (u8)value)
+ return start;
+ start++;
+ bytes--;
+ }
+ return NULL;
+}
+
+static void restore_bytes(struct kmem_cache *s, char *message, u8 data,
+ void *from, void *to)
+{
+ slab_fix(s, "Restoring 0x%p-0x%p=0x%x\n", from, to - 1, data);
+ memset(from, data, to - from);
+}
+
+static int check_bytes_and_report(struct kmem_cache *s, struct slqb_page *page,
+ u8 *object, char *what,
+ u8 *start, unsigned int value, unsigned int bytes)
+{
+ u8 *fault;
+ u8 *end;
+
+ fault = check_bytes(start, value, bytes);
+ if (!fault)
+ return 1;
+
+ end = start + bytes;
+ while (end > fault && end[-1] == value)
+ end--;
+
+ slab_bug(s, "%s overwritten", what);
+ printk(KERN_ERR "INFO: 0x%p-0x%p. First byte 0x%x instead of 0x%x\n",
+ fault, end - 1, fault[0], value);
+ print_trailer(s, page, object);
+
+ restore_bytes(s, what, value, fault, end);
+ return 0;
+}
+
+/*
+ * Object layout:
+ *
+ * object address
+ * Bytes of the object to be managed.
+ * If the freepointer may overlay the object then the free
+ * pointer is the first word of the object.
+ *
+ * Poisoning uses 0x6b (POISON_FREE) and the last byte is
+ * 0xa5 (POISON_END)
+ *
+ * object + s->objsize
+ * Padding to reach word boundary. This is also used for Redzoning.
+ * Padding is extended by another word if Redzoning is enabled and
+ * objsize == inuse.
+ *
+ * We fill with 0xbb (RED_INACTIVE) for inactive objects and with
+ * 0xcc (RED_ACTIVE) for objects in use.
+ *
+ * object + s->inuse
+ * Meta data starts here.
+ *
+ * A. Free pointer (if we cannot overwrite object on free)
+ * B. Tracking data for SLAB_STORE_USER
+ * C. Padding to reach required alignment boundary or at mininum
+ * one word if debuggin is on to be able to detect writes
+ * before the word boundary.
+ *
+ * Padding is done using 0x5a (POISON_INUSE)
+ *
+ * object + s->size
+ * Nothing is used beyond s->size.
+ */
+
+static int check_pad_bytes(struct kmem_cache *s, struct slqb_page *page, u8 *p)
+{
+ unsigned long off = s->inuse; /* The end of info */
+
+ if (s->offset) {
+ /* Freepointer is placed after the object. */
+ off += sizeof(void *);
+ }
+
+ if (s->flags & SLAB_STORE_USER) {
+ /* We also have user information there */
+ off += 2 * sizeof(struct track);
+ }
+
+ if (s->size == off)
+ return 1;
+
+ return check_bytes_and_report(s, page, p, "Object padding",
+ p + off, POISON_INUSE, s->size - off);
+}
+
+static int slab_pad_check(struct kmem_cache *s, struct slqb_page *page)
+{
+ u8 *start;
+ u8 *fault;
+ u8 *end;
+ int length;
+ int remainder;
+
+ if (!(s->flags & SLAB_POISON))
+ return 1;
+
+ start = slqb_page_address(page);
+ end = start + (PAGE_SIZE << s->order);
+ length = s->objects * s->size;
+ remainder = end - (start + length);
+ if (!remainder)
+ return 1;
+
+ fault = check_bytes(start + length, POISON_INUSE, remainder);
+ if (!fault)
+ return 1;
+
+ while (end > fault && end[-1] == POISON_INUSE)
+ end--;
+
+ slab_err(s, page, "Padding overwritten. 0x%p-0x%p", fault, end - 1);
+ print_section("Padding", start, length);
+
+ restore_bytes(s, "slab padding", POISON_INUSE, start, end);
+ return 0;
+}
+
+static int check_object(struct kmem_cache *s, struct slqb_page *page,
+ void *object, int active)
+{
+ 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))
+ return 0;
+ } else {
+ if ((s->flags & SLAB_POISON) && s->objsize < s->inuse) {
+ check_bytes_and_report(s, page, p, "Alignment padding",
+ endobject, POISON_INUSE, s->inuse - s->objsize);
+ }
+ }
+
+ if (s->flags & SLAB_POISON) {
+ if (!active && (s->flags & __OBJECT_POISON)) {
+ if (!check_bytes_and_report(s, page, p, "Poison", p,
+ POISON_FREE, s->objsize - 1))
+ return 0;
+
+ if (!check_bytes_and_report(s, page, p, "Poison",
+ p + s->objsize - 1, POISON_END, 1))
+ return 0;
+ }
+
+ /*
+ * check_pad_bytes cleans up on its own.
+ */
+ check_pad_bytes(s, page, p);
+ }
+
+ return 1;
+}
+
+static int check_slab(struct kmem_cache *s, struct slqb_page *page)
+{
+ if (!(page->flags & PG_SLQB_BIT)) {
+ slab_err(s, page, "Not a valid slab page");
+ return 0;
+ }
+ if (page->inuse == 0) {
+ slab_err(s, page, "inuse before free / after alloc", s->name);
+ return 0;
+ }
+ if (page->inuse > s->objects) {
+ slab_err(s, page, "inuse %u > max %u",
+ s->name, page->inuse, s->objects);
+ return 0;
+ }
+ /* Slab_pad_check fixes things up after itself */
+ slab_pad_check(s, page);
+ return 1;
+}
+
+static void trace(struct kmem_cache *s, struct slqb_page *page,
+ void *object, int alloc)
+{
+ if (s->flags & SLAB_TRACE) {
+ printk(KERN_INFO "TRACE %s %s 0x%p inuse=%d fp=0x%p\n",
+ s->name,
+ alloc ? "alloc" : "free",
+ object, page->inuse,
+ page->freelist);
+
+ if (!alloc)
+ print_section("Object", (void *)object, s->objsize);
+
+ dump_stack();
+ }
+}
+
+static void setup_object_debug(struct kmem_cache *s, struct slqb_page *page,
+ void *object)
+{
+ if (!slab_debug(s))
+ return;
+
+ if (!(s->flags & (SLAB_STORE_USER|SLAB_RED_ZONE|__OBJECT_POISON)))
+ return;
+
+ init_object(s, object, 0);
+ init_tracking(s, object);
+}
+
+static int alloc_debug_processing(struct kmem_cache *s,
+ void *object, unsigned long addr)
+{
+ struct slqb_page *page;
+ page = virt_to_head_slqb_page(object);
+
+ if (!check_slab(s, page))
+ goto bad;
+
+ if (!check_valid_pointer(s, page, object)) {
+ object_err(s, page, object, "Freelist Pointer check fails");
+ goto bad;
+ }
+
+ if (object && !check_object(s, page, object, 0))
+ 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);
+ return 1;
+
+bad:
+ return 0;
+}
+
+static int free_debug_processing(struct kmem_cache *s,
+ void *object, unsigned long addr)
+{
+ struct slqb_page *page;
+ page = virt_to_head_slqb_page(object);
+
+ if (!check_slab(s, page))
+ goto fail;
+
+ if (!check_valid_pointer(s, page, object)) {
+ slab_err(s, page, "Invalid object pointer 0x%p", object);
+ goto fail;
+ }
+
+ if (!check_object(s, page, object, 1))
+ return 0;
+
+ /* Special debug activities for freeing objects */
+ if (s->flags & SLAB_STORE_USER)
+ set_track(s, object, TRACK_FREE, addr);
+ trace(s, page, object, 0);
+ init_object(s, object, 0);
+ return 1;
+
+fail:
+ slab_fix(s, "Object at 0x%p not freed", object);
+ return 0;
+}
+
+static int __init setup_slqb_debug(char *str)
+{
+ slqb_debug = DEBUG_DEFAULT_FLAGS;
+ if (*str++ != '=' || !*str) {
+ /*
+ * No options specified. Switch on full debugging.
+ */
+ goto out;
+ }
+
+ if (*str == ',') {
+ /*
+ * No options but restriction on slabs. This means full
+ * debugging for slabs matching a pattern.
+ */
+ goto check_slabs;
+ }
+
+ slqb_debug = 0;
+ if (*str == '-') {
+ /*
+ * Switch off all debugging measures.
+ */
+ goto out;
+ }
+
+ /*
+ * Determine which debug features should be switched on
+ */
+ for (; *str && *str != ','; str++) {
+ switch (tolower(*str)) {
+ case 'f':
+ slqb_debug |= SLAB_DEBUG_FREE;
+ break;
+ case 'z':
+ slqb_debug |= SLAB_RED_ZONE;
+ break;
+ case 'p':
+ slqb_debug |= SLAB_POISON;
+ break;
+ case 'u':
+ slqb_debug |= SLAB_STORE_USER;
+ break;
+ case 't':
+ slqb_debug |= SLAB_TRACE;
+ break;
+ default:
+ printk(KERN_ERR "slqb_debug option '%c' "
+ "unknown. skipped\n", *str);
+ }
+ }
+
+check_slabs:
+ if (*str == ',')
+ slqb_debug_slabs = str + 1;
+out:
+ return 1;
+}
+__setup("slqb_debug", setup_slqb_debug);
+
+static int __init setup_slqb_min_order(char *str)
+{
+ get_option(&str, &slqb_min_order);
+ slqb_min_order = min(slqb_min_order, MAX_ORDER - 1);
+
+ return 1;
+}
+__setup("slqb_min_order=", setup_slqb_min_order);
+
+static int __init setup_slqb_min_objects(char *str)
+{
+ get_option(&str, &slqb_min_objects);
+
+ return 1;
+}
+
+__setup("slqb_min_objects=", setup_slqb_min_objects);
+
+static unsigned long kmem_cache_flags(unsigned long objsize,
+ unsigned long flags, const char *name,
+ void (*ctor)(void *))
+{
+ /*
+ * Enable debugging if selected on the kernel commandline.
+ */
+ if (slqb_debug && (!slqb_debug_slabs ||
+ strncmp(slqb_debug_slabs, name,
+ strlen(slqb_debug_slabs)) == 0))
+ flags |= slqb_debug;
+
+ if (num_possible_nodes() > 1)
+ flags |= SLAB_NUMA;
+
+ return flags;
+}
+#else
+static inline void setup_object_debug(struct kmem_cache *s,
+ struct slqb_page *page, void *object)
+{
+}
+
+static inline int alloc_debug_processing(struct kmem_cache *s,
+ void *object, unsigned long addr)
+{
+ return 0;
+}
+
+static inline int free_debug_processing(struct kmem_cache *s,
+ void *object, unsigned long addr)
+{
+ return 0;
+}
+
+static inline int slab_pad_check(struct kmem_cache *s, struct slqb_page *page)
+{
+ return 1;
+}
+
+static inline int check_object(struct kmem_cache *s, struct slqb_page *page,
+ void *object, int active)
+{
+ return 1;
+}
+
+static inline void add_full(struct kmem_cache_node *n, struct slqb_page *page)
+{
+}
+
+static inline unsigned long kmem_cache_flags(unsigned long objsize,
+ unsigned long flags, const char *name, void (*ctor)(void *))
+{
+ if (num_possible_nodes() > 1)
+ flags |= SLAB_NUMA;
+ return flags;
+}
+
+static const int slqb_debug;
+#endif
+
+/*
+ * allocate a new slab (return its corresponding struct slqb_page)
+ */
+static struct slqb_page *allocate_slab(struct kmem_cache *s,
+ gfp_t flags, int node)
+{
+ struct slqb_page *page;
+ int pages = 1 << s->order;
+
+ flags |= s->allocflags;
+
+ page = (struct slqb_page *)alloc_pages_node(node, flags, s->order);
+ if (!page)
+ return NULL;
+
+ mod_zone_page_state(slqb_page_zone(page),
+ (s->flags & SLAB_RECLAIM_ACCOUNT) ?
+ NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
+ pages);
+
+ return page;
+}
+
+/*
+ * Called once for each object on a new slab page
+ */
+static void setup_object(struct kmem_cache *s,
+ struct slqb_page *page, void *object)
+{
+ setup_object_debug(s, page, object);
+ if (unlikely(s->ctor))
+ s->ctor(object);
+}
+
+/*
+ * Allocate a new slab, set up its object list.
+ */
+static struct slqb_page *new_slab_page(struct kmem_cache *s,
+ gfp_t flags, int node, unsigned int colour)
+{
+ struct slqb_page *page;
+ void *start;
+ void *last;
+ void *p;
+
+ BUG_ON(flags & GFP_SLAB_BUG_MASK);
+
+ page = allocate_slab(s,
+ flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node);
+ if (!page)
+ goto out;
+
+ page->flags |= PG_SLQB_BIT;
+
+ start = page_address(&page->page);
+
+ if (unlikely(slab_poison(s)))
+ memset(start, POISON_INUSE, PAGE_SIZE << s->order);
+
+ start += colour;
+
+ last = start;
+ for_each_object(p, s, start) {
+ setup_object(s, page, p);
+ set_freepointer(s, last, p);
+ last = p;
+ }
+ set_freepointer(s, last, NULL);
+
+ page->freelist = start;
+ page->inuse = 0;
+out:
+ return page;
+}
+
+/*
+ * Free a slab page back to the page allocator
+ */
+static void __free_slab(struct kmem_cache *s, struct slqb_page *page)
+{
+ int pages = 1 << s->order;
+
+ if (unlikely(slab_debug(s))) {
+ void *p;
+
+ slab_pad_check(s, page);
+ for_each_free_object(p, s, page->freelist)
+ check_object(s, page, p, 0);
+ }
+
+ mod_zone_page_state(slqb_page_zone(page),
+ (s->flags & SLAB_RECLAIM_ACCOUNT) ?
+ NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
+ -pages);
+
+ __free_slqb_pages(page, s->order, pages);
+}
+
+static void rcu_free_slab(struct rcu_head *h)
+{
+ struct slqb_page *page;
+
+ page = container_of(h, struct slqb_page, rcu_head);
+ __free_slab(page->list->cache, page);
+}
+
+static void free_slab(struct kmem_cache *s, struct slqb_page *page)
+{
+ VM_BUG_ON(page->inuse);
+ if (unlikely(s->flags & SLAB_DESTROY_BY_RCU))
+ call_rcu(&page->rcu_head, rcu_free_slab);
+ else
+ __free_slab(s, page);
+}
+
+/*
+ * Return an object to its slab.
+ *
+ * Caller must be the owner CPU in the case of per-CPU list, or hold the node's
+ * list_lock in the case of per-node list.
+ */
+static int free_object_to_page(struct kmem_cache *s,
+ struct kmem_cache_list *l, struct slqb_page *page,
+ void *object)
+{
+ VM_BUG_ON(page->list != l);
+
+ set_freepointer(s, object, page->freelist);
+ page->freelist = object;
+ page->inuse--;
+
+ if (!page->inuse) {
+ if (likely(s->objects > 1)) {
+ l->nr_partial--;
+ list_del(&page->lru);
+ }
+ l->nr_slabs--;
+ free_slab(s, page);
+ slqb_stat_inc(l, FLUSH_SLAB_FREE);
+ return 1;
+
+ } else if (page->inuse + 1 == s->objects) {
+ l->nr_partial++;
+ list_add(&page->lru, &l->partial);
+ slqb_stat_inc(l, FLUSH_SLAB_PARTIAL);
+ return 0;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_SMP
+static void slab_free_to_remote(struct kmem_cache *s, struct slqb_page *page,
+ void *object, struct kmem_cache_cpu *c);
+#endif
+
+/*
+ * Flush the LIFO list of objects on a list. They are sent back to their pages
+ * in case the pages also belong to the list, or to our CPU's remote-free list
+ * in the case they do not.
+ *
+ * Doesn't flush the entire list. flush_free_list_all does.
+ *
+ * Caller must be the owner CPU in the case of per-CPU list, or hold the node's
+ * list_lock in the case of per-node list.
+ */
+static void flush_free_list(struct kmem_cache *s, struct kmem_cache_list *l)
+{
+ void **head;
+ int nr;
+ int locked = 0;
+
+ nr = l->freelist.nr;
+ if (unlikely(!nr))
+ return;
+
+ nr = min(slab_freebatch(s), nr);
+
+ slqb_stat_inc(l, FLUSH_FREE_LIST);
+ slqb_stat_add(l, FLUSH_FREE_LIST_OBJECTS, nr);
+
+ l->freelist.nr -= nr;
+ head = l->freelist.head;
+
+ do {
+ struct slqb_page *page;
+ void **object;
+
+ object = head;
+ VM_BUG_ON(!object);
+ head = get_freepointer(s, object);
+ page = virt_to_head_slqb_page(object);
+
+#ifdef CONFIG_SMP
+ if (page->list != l) {
+ struct kmem_cache_cpu *c;
+
+ if (locked) {
+ spin_unlock(&l->page_lock);
+ locked = 0;
+ }
+
+ c = get_cpu_slab(s, smp_processor_id());
+
+ slab_free_to_remote(s, page, object, c);
+ slqb_stat_inc(l, FLUSH_FREE_LIST_REMOTE);
+ } else
+#endif
+ {
+ if (!locked) {
+ spin_lock(&l->page_lock);
+ locked = 1;
+ }
+ free_object_to_page(s, l, page, object);
+ }
+
+ nr--;
+ } while (nr);
+
+ if (locked)
+ spin_unlock(&l->page_lock);
+
+ l->freelist.head = head;
+ if (!l->freelist.nr)
+ l->freelist.tail = NULL;
+}
+
+static void flush_free_list_all(struct kmem_cache *s, struct kmem_cache_list *l)
+{
+ while (l->freelist.nr)
+ flush_free_list(s, l);
+}
+
+#ifdef CONFIG_SMP
+/*
+ * If enough objects have been remotely freed back to this list,
+ * remote_free_check will be set. In which case, we'll eventually come here
+ * to take those objects off our remote_free list and onto our LIFO freelist.
+ *
+ * Caller must be the owner CPU in the case of per-CPU list, or hold the node's
+ * list_lock in the case of per-node list.
+ */
+static void claim_remote_free_list(struct kmem_cache *s,
+ struct kmem_cache_list *l)
+{
+ void **head, **tail;
+ int nr;
+
+ if (!l->remote_free.list.nr)
+ return;
+
+ spin_lock(&l->remote_free.lock);
+
+ l->remote_free_check = 0;
+ head = l->remote_free.list.head;
+ l->remote_free.list.head = NULL;
+ tail = l->remote_free.list.tail;
+ l->remote_free.list.tail = NULL;
+ nr = l->remote_free.list.nr;
+ l->remote_free.list.nr = 0;
+
+ spin_unlock(&l->remote_free.lock);
+
+ VM_BUG_ON(!nr);
+
+ if (!l->freelist.nr) {
+ /* Get head hot for likely subsequent allocation or flush */
+ prefetchw(head);
+ l->freelist.head = head;
+ } else
+ set_freepointer(s, l->freelist.tail, head);
+ l->freelist.tail = tail;
+
+ l->freelist.nr += nr;
+
+ slqb_stat_inc(l, CLAIM_REMOTE_LIST);
+ slqb_stat_add(l, CLAIM_REMOTE_LIST_OBJECTS, nr);
+}
+#else
+static inline void claim_remote_free_list(struct kmem_cache *s,
+ struct kmem_cache_list *l)
+{
+}
+#endif
+
+/*
+ * Allocation fastpath. Get an object from the list's LIFO freelist, or
+ * return NULL if it is empty.
+ *
+ * Caller must be the owner CPU in the case of per-CPU list, or hold the node's
+ * list_lock in the case of per-node list.
+ */
+static __always_inline void *__cache_list_get_object(struct kmem_cache *s,
+ struct kmem_cache_list *l)
+{
+ void *object;
+
+ object = l->freelist.head;
+ if (likely(object)) {
+ void *next = get_freepointer(s, object);
+
+ VM_BUG_ON(!l->freelist.nr);
+ l->freelist.nr--;
+ l->freelist.head = next;
+
+ return object;
+ }
+ VM_BUG_ON(l->freelist.nr);
+
+#ifdef CONFIG_SMP
+ if (unlikely(l->remote_free_check)) {
+ claim_remote_free_list(s, l);
+
+ if (l->freelist.nr > slab_hiwater(s))
+ flush_free_list(s, l);
+
+ /* repetition here helps gcc :( */
+ object = l->freelist.head;
+ if (likely(object)) {
+ void *next = get_freepointer(s, object);
+
+ VM_BUG_ON(!l->freelist.nr);
+ l->freelist.nr--;
+ l->freelist.head = next;
+
+ return object;
+ }
+ VM_BUG_ON(l->freelist.nr);
+ }
+#endif
+
+ return NULL;
+}
+
+/*
+ * Slow(er) path. Get a page from this list's existing pages. Will be a
+ * new empty page in the case that __slab_alloc_page has just been called
+ * (empty pages otherwise never get queued up on the lists), or a partial page
+ * already on the list.
+ *
+ * Caller must be the owner CPU in the case of per-CPU list, or hold the node's
+ * list_lock in the case of per-node list.
+ */
+static noinline void *__cache_list_get_page(struct kmem_cache *s,
+ struct kmem_cache_list *l)
+{
+ struct slqb_page *page;
+ void *object;
+
+ if (unlikely(!l->nr_partial))
+ return NULL;
+
+ page = list_first_entry(&l->partial, struct slqb_page, lru);
+ VM_BUG_ON(page->inuse == s->objects);
+ if (page->inuse + 1 == s->objects) {
+ l->nr_partial--;
+ list_del(&page->lru);
+ }
+
+ VM_BUG_ON(!page->freelist);
+
+ page->inuse++;
+
+ object = page->freelist;
+ page->freelist = get_freepointer(s, object);
+ if (page->freelist)
+ prefetchw(page->freelist);
+ VM_BUG_ON((page->inuse == s->objects) != (page->freelist == NULL));
+ slqb_stat_inc(l, ALLOC_SLAB_FILL);
+
+ return object;
+}
+
+static void *cache_list_get_page(struct kmem_cache *s,
+ struct kmem_cache_list *l)
+{
+ void *object;
+
+ if (unlikely(!l->nr_partial))
+ return NULL;
+
+ spin_lock(&l->page_lock);
+ object = __cache_list_get_page(s, l);
+ spin_unlock(&l->page_lock);
+
+ return object;
+}
+
+/*
+ * Allocation slowpath. Allocate a new slab page from the page allocator, and
+ * put it on the list's partial list. Must be followed by an allocation so
+ * that we don't have dangling empty pages on the partial list.
+ *
+ * Returns 0 on allocation failure.
+ *
+ * Must be called with interrupts disabled.
+ */
+static noinline void *__slab_alloc_page(struct kmem_cache *s,
+ gfp_t gfpflags, int node)
+{
+ struct slqb_page *page;
+ struct kmem_cache_list *l;
+ struct kmem_cache_cpu *c;
+ unsigned int colour;
+ void *object;
+
+ c = get_cpu_slab(s, smp_processor_id());
+ colour = c->colour_next;
+ c->colour_next += s->colour_off;
+ if (c->colour_next >= s->colour_range)
+ c->colour_next = 0;
+
+ /* Caller handles __GFP_ZERO */
+ gfpflags &= ~__GFP_ZERO;
+
+ if (gfpflags & __GFP_WAIT)
+ local_irq_enable();
+ page = new_slab_page(s, gfpflags, node, colour);
+ if (gfpflags & __GFP_WAIT)
+ local_irq_disable();
+ if (unlikely(!page))
+ return page;
+
+ if (!NUMA_BUILD || likely(slqb_page_to_nid(page) == numa_node_id())) {
+ struct kmem_cache_cpu *c;
+ int cpu = smp_processor_id();
+
+ c = get_cpu_slab(s, cpu);
+ l = &c->list;
+ page->list = l;
+
+ spin_lock(&l->page_lock);
+ l->nr_slabs++;
+ l->nr_partial++;
+ list_add(&page->lru, &l->partial);
+ slqb_stat_inc(l, ALLOC);
+ slqb_stat_inc(l, ALLOC_SLAB_NEW);
+ object = __cache_list_get_page(s, l);
+ spin_unlock(&l->page_lock);
+ } else {
+#ifdef CONFIG_NUMA
+ struct kmem_cache_node *n;
+
+ n = s->node_slab[slqb_page_to_nid(page)];
+ l = &n->list;
+ page->list = l;
+
+ spin_lock(&n->list_lock);
+ spin_lock(&l->page_lock);
+ l->nr_slabs++;
+ l->nr_partial++;
+ list_add(&page->lru, &l->partial);
+ slqb_stat_inc(l, ALLOC);
+ slqb_stat_inc(l, ALLOC_SLAB_NEW);
+ object = __cache_list_get_page(s, l);
+ spin_unlock(&l->page_lock);
+ spin_unlock(&n->list_lock);
+#endif
+ }
+ VM_BUG_ON(!object);
+ return object;
+}
+
+#ifdef CONFIG_NUMA
+static noinline int alternate_nid(struct kmem_cache *s,
+ gfp_t gfpflags, int node)
+{
+ if (in_interrupt() || (gfpflags & __GFP_THISNODE))
+ return node;
+ if (cpuset_do_slab_mem_spread() && (s->flags & SLAB_MEM_SPREAD))
+ return cpuset_mem_spread_node();
+ else if (current->mempolicy)
+ return slab_node(current->mempolicy);
+ return node;
+}
+
+/*
+ * Allocate an object from a remote node. Return NULL if none could be found
+ * (in which case, caller should allocate a new slab)
+ *
+ * Must be called with interrupts disabled.
+ */
+static void *__remote_slab_alloc_node(struct kmem_cache *s,
+ gfp_t gfpflags, int node)
+{
+ struct kmem_cache_node *n;
+ struct kmem_cache_list *l;
+ void *object;
+
+ n = s->node_slab[node];
+ if (unlikely(!n)) /* node has no memory */
+ return NULL;
+ l = &n->list;
+
+ spin_lock(&n->list_lock);
+
+ object = __cache_list_get_object(s, l);
+ if (unlikely(!object)) {
+ object = cache_list_get_page(s, l);
+ if (unlikely(!object)) {
+ spin_unlock(&n->list_lock);
+ return __slab_alloc_page(s, gfpflags, node);
+ }
+ }
+ if (likely(object))
+ slqb_stat_inc(l, ALLOC);
+ spin_unlock(&n->list_lock);
+ return object;
+}
+
+static noinline void *__remote_slab_alloc(struct kmem_cache *s,
+ gfp_t gfpflags, int node)
+{
+ void *object;
+ struct zonelist *zonelist;
+ struct zoneref *z;
+ struct zone *zone;
+ enum zone_type high_zoneidx = gfp_zone(gfpflags);
+
+ object = __remote_slab_alloc_node(s, gfpflags, node);
+ if (likely(object || (gfpflags & __GFP_THISNODE)))
+ return object;
+
+ zonelist = node_zonelist(slab_node(current->mempolicy), gfpflags);
+ for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
+ if (!cpuset_zone_allowed_hardwall(zone, gfpflags))
+ continue;
+
+ node = zone_to_nid(zone);
+ object = __remote_slab_alloc_node(s, gfpflags, node);
+ if (likely(object))
+ return object;
+ }
+ return NULL;
+}
+#endif
+
+/*
+ * Main allocation path. Return an object, or NULL on allocation failure.
+ *
+ * Must be called with interrupts disabled.
+ */
+static __always_inline void *__slab_alloc(struct kmem_cache *s,
+ gfp_t gfpflags, int node)
+{
+ void *object;
+ struct kmem_cache_cpu *c;
+ struct kmem_cache_list *l;
+
+#ifdef CONFIG_NUMA
+ if (unlikely(node != -1) && unlikely(node != numa_node_id())) {
+try_remote:
+ return __remote_slab_alloc(s, gfpflags, node);
+ }
+#endif
+
+ c = get_cpu_slab(s, smp_processor_id());
+ VM_BUG_ON(!c);
+ l = &c->list;
+ object = __cache_list_get_object(s, l);
+ if (unlikely(!object)) {
+#ifdef CONFIG_NUMA
+ int thisnode = numa_node_id();
+
+ /*
+ * If the local node is memoryless, try remote alloc before
+ * trying the page allocator. Otherwise, what happens is
+ * objects are always freed to remote lists but the allocation
+ * side always allocates a new page with only one object
+ * used in each page
+ */
+ if (unlikely(!node_state(thisnode, N_HIGH_MEMORY)))
+ object = __remote_slab_alloc(s, gfpflags, thisnode);
+#endif
+
+ if (!object) {
+ object = cache_list_get_page(s, l);
+ if (unlikely(!object)) {
+ object = __slab_alloc_page(s, gfpflags, node);
+#ifdef CONFIG_NUMA
+ if (unlikely(!object)) {
+ node = numa_node_id();
+ goto try_remote;
+ }
+#endif
+ return object;
+ }
+ }
+ }
+ if (likely(object))
+ slqb_stat_inc(l, ALLOC);
+ return object;
+}
+
+/*
+ * Perform some interrupts-on processing around the main allocation path
+ * (debug checking and memset()ing).
+ */
+static __always_inline void *slab_alloc(struct kmem_cache *s,
+ gfp_t gfpflags, int node, unsigned long addr)
+{
+ void *object;
+ unsigned long flags;
+
+ gfpflags &= gfp_allowed_mask;
+
+ lockdep_trace_alloc(gfpflags);
+ might_sleep_if(gfpflags & __GFP_WAIT);
+
+ if (should_failslab(s->objsize, gfpflags))
+ return NULL;
+
+again:
+ local_irq_save(flags);
+ object = __slab_alloc(s, gfpflags, node);
+ local_irq_restore(flags);
+
+ if (unlikely(slab_debug(s)) && likely(object)) {
+ if (unlikely(!alloc_debug_processing(s, object, addr)))
+ goto again;
+ }
+
+ if (unlikely(gfpflags & __GFP_ZERO) && likely(object))
+ memset(object, 0, s->objsize);
+
+ return object;
+}
+
+static __always_inline void *__kmem_cache_alloc(struct kmem_cache *s,
+ gfp_t gfpflags, unsigned long caller)
+{
+ int node = -1;
+
+#ifdef CONFIG_NUMA
+ if (unlikely(current->flags & (PF_SPREAD_SLAB | PF_MEMPOLICY)))
+ node = alternate_nid(s, gfpflags, node);
+#endif
+ return slab_alloc(s, gfpflags, node, caller);
+}
+
+void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
+{
+ return __kmem_cache_alloc(s, gfpflags, _RET_IP_);
+}
+EXPORT_SYMBOL(kmem_cache_alloc);
+
+#ifdef CONFIG_NUMA
+void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node)
+{
+ return slab_alloc(s, gfpflags, node, _RET_IP_);
+}
+EXPORT_SYMBOL(kmem_cache_alloc_node);
+#endif
+
+#ifdef CONFIG_SMP
+/*
+ * Flush this CPU's remote free list of objects back to the list from where
+ * they originate. They end up on that list's remotely freed list, and
+ * eventually we set it's remote_free_check if there are enough objects on it.
+ *
+ * This seems convoluted, but it keeps is from stomping on the target CPU's
+ * fastpath cachelines.
+ *
+ * Must be called with interrupts disabled.
+ */
+static void flush_remote_free_cache(struct kmem_cache *s,
+ struct kmem_cache_cpu *c)
+{
+ struct kmlist *src;
+ struct kmem_cache_list *dst;
+ unsigned int nr;
+ int set;
+
+ src = &c->rlist;
+ nr = src->nr;
+ if (unlikely(!nr))
+ return;
+
+#ifdef CONFIG_SLQB_STATS
+ {
+ struct kmem_cache_list *l = &c->list;
+
+ slqb_stat_inc(l, FLUSH_RFREE_LIST);
+ slqb_stat_add(l, FLUSH_RFREE_LIST_OBJECTS, nr);
+ }
+#endif
+
+ dst = c->remote_cache_list;
+
+ /*
+ * Less common case, dst is filling up so free synchronously.
+ * No point in having remote CPU free thse as it will just
+ * free them back to the page list anyway.
+ */
+ if (unlikely(dst->remote_free.list.nr > (slab_hiwater(s) >> 1))) {
+ void **head;
+
+ head = src->head;
+ spin_lock(&dst->page_lock);
+ do {
+ struct slqb_page *page;
+ void **object;
+
+ object = head;
+ VM_BUG_ON(!object);
+ head = get_freepointer(s, object);
+ page = virt_to_head_slqb_page(object);
+
+ free_object_to_page(s, dst, page, object);
+ nr--;
+ } while (nr);
+ spin_unlock(&dst->page_lock);
+
+ src->head = NULL;
+ src->tail = NULL;
+ src->nr = 0;
+
+ return;
+ }
+
+ spin_lock(&dst->remote_free.lock);
+
+ if (!dst->remote_free.list.head)
+ dst->remote_free.list.head = src->head;
+ else
+ set_freepointer(s, dst->remote_free.list.tail, src->head);
+ dst->remote_free.list.tail = src->tail;
+
+ src->head = NULL;
+ src->tail = NULL;
+ src->nr = 0;
+
+ if (dst->remote_free.list.nr < slab_freebatch(s))
+ set = 1;
+ else
+ set = 0;
+
+ dst->remote_free.list.nr += nr;
+
+ if (unlikely(dst->remote_free.list.nr >= slab_freebatch(s) && set))
+ dst->remote_free_check = 1;
+
+ spin_unlock(&dst->remote_free.lock);
+}
+
+/*
+ * Free an object to this CPU's remote free list.
+ *
+ * Must be called with interrupts disabled.
+ */
+static noinline void slab_free_to_remote(struct kmem_cache *s,
+ struct slqb_page *page, void *object,
+ struct kmem_cache_cpu *c)
+{
+ struct kmlist *r;
+
+ /*
+ * Our remote free list corresponds to a different list. Must
+ * flush it and switch.
+ */
+ if (page->list != c->remote_cache_list) {
+ flush_remote_free_cache(s, c);
+ c->remote_cache_list = page->list;
+ }
+
+ r = &c->rlist;
+ if (!r->head)
+ r->head = object;
+ else
+ set_freepointer(s, r->tail, object);
+ set_freepointer(s, object, NULL);
+ r->tail = object;
+ r->nr++;
+
+ if (unlikely(r->nr >= slab_freebatch(s)))
+ flush_remote_free_cache(s, c);
+}
+#endif
+
+/*
+ * Main freeing path. Return an object, or NULL on allocation failure.
+ *
+ * Must be called with interrupts disabled.
+ */
+static __always_inline void __slab_free(struct kmem_cache *s,
+ struct slqb_page *page, void *object)
+{
+ struct kmem_cache_cpu *c;
+ struct kmem_cache_list *l;
+ int thiscpu = smp_processor_id();
+
+ c = get_cpu_slab(s, thiscpu);
+ l = &c->list;
+
+ slqb_stat_inc(l, FREE);
+
+ if (!NUMA_BUILD || !slab_numa(s) ||
+ likely(slqb_page_to_nid(page) == numa_node_id())) {
+ /*
+ * Freeing fastpath. Collects all local-node objects, not
+ * just those allocated from our per-CPU list. This allows
+ * fast transfer of objects from one CPU to another within
+ * a given node.
+ */
+ set_freepointer(s, object, l->freelist.head);
+ l->freelist.head = object;
+ if (!l->freelist.nr)
+ l->freelist.tail = object;
+ l->freelist.nr++;
+
+ if (unlikely(l->freelist.nr > slab_hiwater(s)))
+ flush_free_list(s, l);
+
+ } else {
+#ifdef CONFIG_SMP
+ /*
+ * Freeing an object that was allocated on a remote node.
+ */
+ slab_free_to_remote(s, page, object, c);
+ slqb_stat_inc(l, FREE_REMOTE);
+#endif
+ }
+}
+
+/*
+ * Perform some interrupts-on processing around the main freeing path
+ * (debug checking).
+ */
+static __always_inline void slab_free(struct kmem_cache *s,
+ struct slqb_page *page, void *object)
+{
+ unsigned long flags;
+
+ prefetchw(object);
+
+ debug_check_no_locks_freed(object, s->objsize);
+ if (likely(object) && unlikely(slab_debug(s))) {
+ if (unlikely(!free_debug_processing(s, object, _RET_IP_)))
+ return;
+ }
+
+ local_irq_save(flags);
+ __slab_free(s, page, object);
+ local_irq_restore(flags);
+}
+
+void kmem_cache_free(struct kmem_cache *s, void *object)
+{
+ struct slqb_page *page = NULL;
+
+ if (slab_numa(s))
+ page = virt_to_head_slqb_page(object);
+ slab_free(s, page, object);
+}
+EXPORT_SYMBOL(kmem_cache_free);
+
+/*
+ * Calculate the order of allocation given an slab object size.
+ *
+ * Order 0 allocations are preferred since order 0 does not cause fragmentation
+ * in the page allocator, and they have fastpaths in the page allocator. But
+ * also minimise external fragmentation with large objects.
+ */
+static int slab_order(int size, int max_order, int frac)
+{
+ int order;
+
+ if (fls(size - 1) <= PAGE_SHIFT)
+ order = 0;
+ else
+ order = fls(size - 1) - PAGE_SHIFT;
+ if (order < slqb_min_order)
+ order = slqb_min_order;
+
+ while (order <= max_order) {
+ unsigned long slab_size = PAGE_SIZE << order;
+ unsigned long objects;
+ unsigned long waste;
+
+ objects = slab_size / size;
+ if (!objects)
+ goto next;
+
+ if (order < MAX_ORDER && objects < slqb_min_objects) {
+ /*
+ * if we don't have enough objects for min_objects,
+ * then try the next size up. Unless we have reached
+ * our maximum possible page size.
+ */
+ goto next;
+ }
+
+ waste = slab_size - (objects * size);
+
+ if (waste * frac <= slab_size)
+ break;
+
+next:
+ order++;
+ }
+
+ return order;
+}
+
+static int calculate_order(int size)
+{
+ int order;
+
+ /*
+ * Attempt to find best configuration for a slab. This
+ * works by first attempting to generate a layout with
+ * the best configuration and backing off gradually.
+ */
+ order = slab_order(size, 1, 4);
+ if (order <= 1)
+ return order;
+
+ /*
+ * This size cannot fit in order-1. Allow bigger orders, but
+ * forget about trying to save space.
+ */
+ order = slab_order(size, MAX_ORDER - 1, 0);
+ if (order < MAX_ORDER)
+ return order;
+
+ return -ENOSYS;
+}
+
+/*
+ * Figure out what the alignment of the objects will be.
+ */
+static unsigned long calculate_alignment(unsigned long flags,
+ unsigned long align, unsigned long size)
+{
+ /*
+ * If the user wants hardware cache aligned objects then follow that
+ * suggestion if the object is sufficiently large.
+ *
+ * The hardware cache alignment cannot override the specified
+ * alignment though. If that is greater then use it.
+ */
+ if (flags & SLAB_HWCACHE_ALIGN) {
+ unsigned long ralign = cache_line_size();
+
+ while (size <= ralign / 2)
+ ralign /= 2;
+ align = max(align, ralign);
+ }
+
+ if (align < ARCH_SLAB_MINALIGN)
+ align = ARCH_SLAB_MINALIGN;
+
+ return ALIGN(align, sizeof(void *));
+}
+
+static void init_kmem_cache_list(struct kmem_cache *s,
+ struct kmem_cache_list *l)
+{
+ l->cache = s;
+ l->freelist.nr = 0;
+ l->freelist.head = NULL;
+ l->freelist.tail = NULL;
+ l->nr_partial = 0;
+ l->nr_slabs = 0;
+ INIT_LIST_HEAD(&l->partial);
+ spin_lock_init(&l->page_lock);
+
+#ifdef CONFIG_SMP
+ l->remote_free_check = 0;
+ spin_lock_init(&l->remote_free.lock);
+ l->remote_free.list.nr = 0;
+ l->remote_free.list.head = NULL;
+ l->remote_free.list.tail = NULL;
+#endif
+
+#ifdef CONFIG_SLQB_STATS
+ memset(l->stats, 0, sizeof(l->stats));
+#endif
+}
+
+static void init_kmem_cache_cpu(struct kmem_cache *s,
+ struct kmem_cache_cpu *c)
+{
+ init_kmem_cache_list(s, &c->list);
+
+ c->colour_next = 0;
+#ifdef CONFIG_SMP
+ c->rlist.nr = 0;
+ c->rlist.head = NULL;
+ c->rlist.tail = NULL;
+ c->remote_cache_list = NULL;
+#endif
+}
+
+#ifdef CONFIG_NUMA
+static void init_kmem_cache_node(struct kmem_cache *s,
+ struct kmem_cache_node *n)
+{
+ spin_lock_init(&n->list_lock);
+ init_kmem_cache_list(s, &n->list);
+}
+#endif
+
+/* Initial slabs. */
+#ifdef CONFIG_SMP
+static DEFINE_PER_CPU(struct kmem_cache_cpu, kmem_cache_cpus);
+#endif
+#ifdef CONFIG_NUMA
+/* XXX: really need a DEFINE_PER_NODE for per-node data because a static
+ * array is wasteful */
+static struct kmem_cache_node kmem_cache_nodes[MAX_NUMNODES];
+#endif
+
+#ifdef CONFIG_SMP
+static struct kmem_cache kmem_cpu_cache;
+static DEFINE_PER_CPU(struct kmem_cache_cpu, kmem_cpu_cpus);
+#ifdef CONFIG_NUMA
+static struct kmem_cache_node kmem_cpu_nodes[MAX_NUMNODES]; /* XXX per-nid */
+#endif
+#endif
+
+#ifdef CONFIG_NUMA
+static struct kmem_cache kmem_node_cache;
+#ifdef CONFIG_SMP
+static DEFINE_PER_CPU(struct kmem_cache_cpu, kmem_node_cpus);
+#endif
+static struct kmem_cache_node kmem_node_nodes[MAX_NUMNODES]; /*XXX per-nid */
+#endif
+
+#ifdef CONFIG_SMP
+static struct kmem_cache_cpu *alloc_kmem_cache_cpu(struct kmem_cache *s,
+ int cpu)
+{
+ struct kmem_cache_cpu *c;
+ int node;
+
+ node = cpu_to_node(cpu);
+
+ c = kmem_cache_alloc_node(&kmem_cpu_cache, GFP_KERNEL, node);
+ if (!c)
+ return NULL;
+
+ init_kmem_cache_cpu(s, c);
+ return c;
+}
+
+static void free_kmem_cache_cpus(struct kmem_cache *s)
+{
+ int cpu;
+
+ for_each_online_cpu(cpu) {
+ struct kmem_cache_cpu *c;
+
+ c = s->cpu_slab[cpu];
+ if (c) {
+ kmem_cache_free(&kmem_cpu_cache, c);
+ s->cpu_slab[cpu] = NULL;
+ }
+ }
+}
+
+static int alloc_kmem_cache_cpus(struct kmem_cache *s)
+{
+ int cpu;
+
+ for_each_online_cpu(cpu) {
+ struct kmem_cache_cpu *c;
+
+ c = s->cpu_slab[cpu];
+ if (c)
+ continue;
+
+ c = alloc_kmem_cache_cpu(s, cpu);
+ if (!c) {
+ free_kmem_cache_cpus(s);
+ return 0;
+ }
+ s->cpu_slab[cpu] = c;
+ }
+ return 1;
+}
+
+#else
+static inline void free_kmem_cache_cpus(struct kmem_cache *s)
+{
+}
+
+static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
+{
+ init_kmem_cache_cpu(s, &s->cpu_slab);
+ return 1;
+}
+#endif
+
+#ifdef CONFIG_NUMA
+static void free_kmem_cache_nodes(struct kmem_cache *s)
+{
+ int node;
+
+ for_each_node_state(node, N_NORMAL_MEMORY) {
+ struct kmem_cache_node *n;
+
+ n = s->node_slab[node];
+ if (n) {
+ kmem_cache_free(&kmem_node_cache, n);
+ s->node_slab[node] = NULL;
+ }
+ }
+}
+
+static int alloc_kmem_cache_nodes(struct kmem_cache *s)
+{
+ int node;
+
+ for_each_node_state(node, N_NORMAL_MEMORY) {
+ struct kmem_cache_node *n;
+
+ n = kmem_cache_alloc_node(&kmem_node_cache, GFP_KERNEL, node);
+ if (!n) {
+ free_kmem_cache_nodes(s);
+ return 0;
+ }
+ init_kmem_cache_node(s, n);
+ s->node_slab[node] = n;
+ }
+ return 1;
+}
+#else
+static void free_kmem_cache_nodes(struct kmem_cache *s)
+{
+}
+
+static int alloc_kmem_cache_nodes(struct kmem_cache *s)
+{
+ return 1;
+}
+#endif
+
+/*
+ * calculate_sizes() determines the order and the distribution of data within
+ * a slab object.
+ */
+static int calculate_sizes(struct kmem_cache *s)
+{
+ unsigned long flags = s->flags;
+ unsigned long size = s->objsize;
+ unsigned long align = s->align;
+
+ /*
+ * Determine if we can poison the object itself. If the user of
+ * the slab may touch the object after free or before allocation
+ * then we should never poison the object itself.
+ */
+ if (slab_poison(s) && !(flags & SLAB_DESTROY_BY_RCU) && !s->ctor)
+ s->flags |= __OBJECT_POISON;
+ else
+ s->flags &= ~__OBJECT_POISON;
+
+ /*
+ * Round up object size to the next word boundary. We can only
+ * place the free pointer at word boundaries and this determines
+ * the possible location of the free pointer.
+ */
+ size = ALIGN(size, sizeof(void *));
+
+#ifdef CONFIG_SLQB_DEBUG
+ /*
+ * If we are Redzoning then check if there is some space between the
+ * end of the object and the free pointer. If not then add an
+ * additional word to have some bytes to store Redzone information.
+ */
+ if ((flags & SLAB_RED_ZONE) && size == s->objsize)
+ size += sizeof(void *);
+#endif
+
+ /*
+ * With that we have determined the number of bytes in actual use
+ * by the object. This is the potential offset to the free pointer.
+ */
+ s->inuse = size;
+
+ if (((flags & (SLAB_DESTROY_BY_RCU | SLAB_POISON)) || s->ctor)) {
+ /*
+ * Relocate free pointer after the object if it is not
+ * permitted to overwrite the first word of the object on
+ * kmem_cache_free.
+ *
+ * This is the case if we do RCU, have a constructor or
+ * destructor or are poisoning the objects.
+ */
+ s->offset = size;
+ size += sizeof(void *);
+ }
+
+#ifdef CONFIG_SLQB_DEBUG
+ if (flags & SLAB_STORE_USER) {
+ /*
+ * Need to store information about allocs and frees after
+ * the object.
+ */
+ size += 2 * sizeof(struct track);
+ }
+
+ if (flags & SLAB_RED_ZONE) {
+ /*
+ * Add some empty padding so that we can catch
+ * overwrites from earlier objects rather than let
+ * tracking information or the free pointer be
+ * corrupted if an user writes before the start
+ * of the object.
+ */
+ size += sizeof(void *);
+ }
+#endif
+
+ /*
+ * Determine the alignment based on various parameters that the
+ * user specified and the dynamic determination of cache line size
+ * on bootup.
+ */
+ align = calculate_alignment(flags, align, s->objsize);
+
+ /*
+ * SLQB stores one object immediately after another beginning from
+ * offset 0. In order to align the objects we have to simply size
+ * each object to conform to the alignment.
+ */
+ size = ALIGN(size, align);
+ s->size = size;
+ s->order = calculate_order(size);
+
+ if (s->order < 0)
+ return 0;
+
+ s->allocflags = 0;
+ if (s->order)
+ s->allocflags |= __GFP_COMP;
+
+ if (s->flags & SLAB_CACHE_DMA)
+ s->allocflags |= SLQB_DMA;
+
+ if (s->flags & SLAB_RECLAIM_ACCOUNT)
+ s->allocflags |= __GFP_RECLAIMABLE;
+
+ /*
+ * Determine the number of objects per slab
+ */
+ s->objects = (PAGE_SIZE << s->order) / size;
+
+ s->freebatch = max(4UL*PAGE_SIZE / size,
+ min(256UL, 64*PAGE_SIZE / size));
+ if (!s->freebatch)
+ s->freebatch = 1;
+ s->hiwater = s->freebatch << 2;
+
+ return !!s->objects;
+
+}
+
+#ifdef CONFIG_SMP
+/*
+ * Per-cpu allocator can't be used because it always uses slab allocator,
+ * and it can't do per-node allocations.
+ */
+static void *kmem_cache_dyn_array_alloc(int ids)
+{
+ size_t size = sizeof(void *) * ids;
+
+ BUG_ON(!size);
+
+ if (unlikely(!slab_is_available())) {
+ static void *nextmem;
+ static size_t nextleft;
+ void *ret;
+
+ /*
+ * Special case for setting up initial caches. These will
+ * never get freed by definition so we can do it rather
+ * simply.
+ */
+ if (size > nextleft) {
+ nextmem = alloc_pages_exact(size, GFP_KERNEL);
+ if (!nextmem)
+ return NULL;
+ nextleft = roundup(size, PAGE_SIZE);
+ }
+
+ ret = nextmem;
+ nextleft -= size;
+ nextmem += size;
+ memset(ret, 0, size);
+ return ret;
+ } else {
+ return kzalloc(size, GFP_KERNEL);
+ }
+}
+
+static void kmem_cache_dyn_array_free(void *array)
+{
+ if (unlikely(!slab_is_available()))
+ return; /* error case without crashing here (will panic soon) */
+ kfree(array);
+}
+#endif
+
+/*
+ * Except in early boot, this should be called with slqb_lock held for write
+ * to lock out hotplug, and protect list modifications.
+ */
+static int kmem_cache_open(struct kmem_cache *s,
+ const char *name, size_t size, size_t align,
+ unsigned long flags, void (*ctor)(void *), int alloc)
+{
+ unsigned int left_over;
+
+ memset(s, 0, sizeof(struct kmem_cache));
+ s->name = name;
+ s->ctor = ctor;
+ s->objsize = size;
+ s->align = align;
+ s->flags = kmem_cache_flags(size, flags, name, ctor);
+
+ if (!calculate_sizes(s))
+ goto error;
+
+ if (!slab_debug(s)) {
+ left_over = (PAGE_SIZE << s->order) - (s->objects * s->size);
+ s->colour_off = max(cache_line_size(), s->align);
+ s->colour_range = left_over;
+ } else {
+ s->colour_off = 0;
+ s->colour_range = 0;
+ }
+
+#ifdef CONFIG_SMP
+ s->cpu_slab = kmem_cache_dyn_array_alloc(nr_cpu_ids);
+ if (!s->cpu_slab)
+ goto error;
+# ifdef CONFIG_NUMA
+ s->node_slab = kmem_cache_dyn_array_alloc(nr_node_ids);
+ if (!s->node_slab)
+ goto error_cpu_array;
+# endif
+#endif
+
+ if (likely(alloc)) {
+ if (!alloc_kmem_cache_nodes(s))
+ goto error_node_array;
+
+ if (!alloc_kmem_cache_cpus(s))
+ goto error_nodes;
+ }
+
+ sysfs_slab_add(s);
+ list_add(&s->list, &slab_caches);
+
+ return 1;
+
+error_nodes:
+ free_kmem_cache_nodes(s);
+error_node_array:
+#if defined(CONFIG_NUMA) && defined(CONFIG_SMP)
+ kmem_cache_dyn_array_free(s->node_slab);
+error_cpu_array:
+#endif
+#ifdef CONFIG_SMP
+ kmem_cache_dyn_array_free(s->cpu_slab);
+#endif
+error:
+ if (flags & SLAB_PANIC)
+ panic("%s: failed to create slab `%s'\n", __func__, name);
+ return 0;
+}
+
+/**
+ * kmem_ptr_validate - check if an untrusted pointer might be a slab entry.
+ * @s: the cache we're checking against
+ * @ptr: pointer to validate
+ *
+ * This verifies that the untrusted pointer looks sane;
+ * it is _not_ a guarantee that the pointer is actually
+ * part of the slab cache in question, but it at least
+ * validates that the pointer can be dereferenced and
+ * looks half-way sane.
+ *
+ * Currently only used for dentry validation.
+ */
+int kmem_ptr_validate(struct kmem_cache *s, const void *ptr)
+{
+ unsigned long addr = (unsigned long)ptr;
+ struct slqb_page *page;
+
+ if (unlikely(addr < PAGE_OFFSET))
+ goto out;
+ if (unlikely(addr > (unsigned long)high_memory - s->size))
+ goto out;
+ if (unlikely(!IS_ALIGNED(addr, s->align)))
+ goto out;
+ if (unlikely(!kern_addr_valid(addr)))
+ goto out;
+ if (unlikely(!kern_addr_valid(addr + s->size - 1)))
+ goto out;
+ if (unlikely(!pfn_valid(addr >> PAGE_SHIFT)))
+ goto out;
+ page = virt_to_head_slqb_page(ptr);
+ if (unlikely(!(page->flags & PG_SLQB_BIT)))
+ goto out;
+ if (unlikely(page->list->cache != s)) /* XXX: ouch, racy */
+ goto out;
+ return 1;
+out:
+ return 0;
+}
+EXPORT_SYMBOL(kmem_ptr_validate);
+
+/*
+ * Determine the size of a slab object
+ */
+unsigned int kmem_cache_size(struct kmem_cache *s)
+{
+ return s->objsize;
+}
+EXPORT_SYMBOL(kmem_cache_size);
+
+const char *kmem_cache_name(struct kmem_cache *s)
+{
+ return s->name;
+}
+EXPORT_SYMBOL(kmem_cache_name);
+
+/*
+ * Release all resources used by a slab cache. No more concurrency on the
+ * slab, so we can touch remote kmem_cache_cpu structures.
+ */
+void kmem_cache_destroy(struct kmem_cache *s)
+{
+#ifdef CONFIG_NUMA
+ int node;
+#endif
+ int cpu;
+
+ down_write(&slqb_lock);
+ list_del(&s->list);
+
+ local_irq_disable();
+#ifdef CONFIG_SMP
+ for_each_online_cpu(cpu) {
+ struct kmem_cache_cpu *c = get_cpu_slab(s, cpu);
+ struct kmem_cache_list *l = &c->list;
+
+ flush_free_list_all(s, l);
+ flush_remote_free_cache(s, c);
+ }
+#endif
+
+ for_each_online_cpu(cpu) {
+ struct kmem_cache_cpu *c = get_cpu_slab(s, cpu);
+ struct kmem_cache_list *l = &c->list;
+
+ claim_remote_free_list(s, l);
+ flush_free_list_all(s, l);
+
+ WARN_ON(l->freelist.nr);
+ WARN_ON(l->nr_slabs);
+ WARN_ON(l->nr_partial);
+ }
+
+ free_kmem_cache_cpus(s);
+
+#ifdef CONFIG_NUMA
+ for_each_node_state(node, N_NORMAL_MEMORY) {
+ struct kmem_cache_node *n;
+ struct kmem_cache_list *l;
+
+ n = s->node_slab[node];
+ if (!n)
+ continue;
+ l = &n->list;
+
+ claim_remote_free_list(s, l);
+ flush_free_list_all(s, l);
+
+ WARN_ON(l->freelist.nr);
+ WARN_ON(l->nr_slabs);
+ WARN_ON(l->nr_partial);
+ }
+
+ free_kmem_cache_nodes(s);
+#endif
+ local_irq_enable();
+
+ sysfs_slab_remove(s);
+ up_write(&slqb_lock);
+}
+EXPORT_SYMBOL(kmem_cache_destroy);
+
+/********************************************************************
+ * Kmalloc subsystem
+ *******************************************************************/
+
+struct kmem_cache kmalloc_caches[KMALLOC_SHIFT_SLQB_HIGH + 1] __cacheline_aligned;
+EXPORT_SYMBOL(kmalloc_caches);
+
+#ifdef CONFIG_ZONE_DMA
+struct kmem_cache kmalloc_caches_dma[KMALLOC_SHIFT_SLQB_HIGH + 1] __cacheline_aligned;
+EXPORT_SYMBOL(kmalloc_caches_dma);
+#endif
+
+#ifndef ARCH_KMALLOC_FLAGS
+#define ARCH_KMALLOC_FLAGS SLAB_HWCACHE_ALIGN
+#endif
+
+static struct kmem_cache *open_kmalloc_cache(struct kmem_cache *s,
+ const char *name, int size, gfp_t gfp_flags)
+{
+ unsigned int flags = ARCH_KMALLOC_FLAGS | SLAB_PANIC;
+
+ if (gfp_flags & SLQB_DMA)
+ flags |= SLAB_CACHE_DMA;
+
+ kmem_cache_open(s, name, size, ARCH_KMALLOC_MINALIGN, flags, NULL, 1);
+
+ return s;
+}
+
+/*
+ * 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
+ * of two cache sizes there. The size of larger slabs can be determined using
+ * fls.
+ */
+static s8 size_index[24] __cacheline_aligned = {
+ 3, /* 8 */
+ 4, /* 16 */
+ 5, /* 24 */
+ 5, /* 32 */
+ 6, /* 40 */
+ 6, /* 48 */
+ 6, /* 56 */
+ 6, /* 64 */
+#if L1_CACHE_BYTES < 64
+ 1, /* 72 */
+ 1, /* 80 */
+ 1, /* 88 */
+ 1, /* 96 */
+#else
+ 7,
+ 7,
+ 7,
+ 7,
+#endif
+ 7, /* 104 */
+ 7, /* 112 */
+ 7, /* 120 */
+ 7, /* 128 */
+#if L1_CACHE_BYTES < 128
+ 2, /* 136 */
+ 2, /* 144 */
+ 2, /* 152 */
+ 2, /* 160 */
+ 2, /* 168 */
+ 2, /* 176 */
+ 2, /* 184 */
+ 2 /* 192 */
+#else
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1
+#endif
+};
+
+static struct kmem_cache *get_slab(size_t size, gfp_t flags)
+{
+ int index;
+
+ if (unlikely(size <= KMALLOC_MIN_SIZE)) {
+ if (unlikely(!size))
+ return ZERO_SIZE_PTR;
+
+ index = KMALLOC_SHIFT_LOW;
+ goto got_index;
+ }
+
+#if L1_CACHE_BYTES >= 128
+ if (size <= 128) {
+#else
+ if (size <= 192) {
+#endif
+ index = size_index[(size - 1) / 8];
+ } else {
+ if (unlikely(size > 1UL << KMALLOC_SHIFT_SLQB_HIGH))
+ return NULL;
+
+ index = fls(size - 1);
+ }
+
+got_index:
+ if (unlikely((flags & SLQB_DMA)))
+ return &kmalloc_caches_dma[index];
+ else
+ return &kmalloc_caches[index];
+}
+
+void *__kmalloc(size_t size, gfp_t flags)
+{
+ struct kmem_cache *s;
+
+ s = get_slab(size, flags);
+ if (unlikely(ZERO_OR_NULL_PTR(s)))
+ return s;
+
+ return __kmem_cache_alloc(s, flags, _RET_IP_);
+}
+EXPORT_SYMBOL(__kmalloc);
+
+#ifdef CONFIG_NUMA
+void *__kmalloc_node(size_t size, gfp_t flags, int node)
+{
+ struct kmem_cache *s;
+
+ s = get_slab(size, flags);
+ if (unlikely(ZERO_OR_NULL_PTR(s)))
+ return s;
+
+ return kmem_cache_alloc_node(s, flags, node);
+}
+EXPORT_SYMBOL(__kmalloc_node);
+#endif
+
+size_t ksize(const void *object)
+{
+ struct slqb_page *page;
+ struct kmem_cache *s;
+
+ BUG_ON(!object);
+ if (unlikely(object == ZERO_SIZE_PTR))
+ return 0;
+
+ page = virt_to_head_slqb_page(object);
+ BUG_ON(!(page->flags & PG_SLQB_BIT));
+
+ s = page->list->cache;
+
+ /*
+ * Debugging requires use of the padding between object
+ * and whatever may come after it.
+ */
+ if (s->flags & (SLAB_RED_ZONE | SLAB_POISON))
+ return s->objsize;
+
+ /*
+ * If we have the need to store the freelist pointer
+ * back there or track user information then we can
+ * only use the space before that information.
+ */
+ if (s->flags & (SLAB_DESTROY_BY_RCU | SLAB_STORE_USER))
+ return s->inuse;
+
+ /*
+ * Else we can use all the padding etc for the allocation
+ */
+ return s->size;
+}
+EXPORT_SYMBOL(ksize);
+
+void kfree(const void *object)
+{
+ struct kmem_cache *s;
+ struct slqb_page *page;
+
+ if (unlikely(ZERO_OR_NULL_PTR(object)))
+ return;
+
+ page = virt_to_head_slqb_page(object);
+ s = page->list->cache;
+
+ slab_free(s, page, (void *)object);
+}
+EXPORT_SYMBOL(kfree);
+
+static void kmem_cache_trim_percpu(void *arg)
+{
+ int cpu = smp_processor_id();
+ struct kmem_cache *s = arg;
+ struct kmem_cache_cpu *c = get_cpu_slab(s, cpu);
+ struct kmem_cache_list *l = &c->list;
+
+ claim_remote_free_list(s, l);
+ flush_free_list(s, l);
+#ifdef CONFIG_SMP
+ flush_remote_free_cache(s, c);
+#endif
+}
+
+int kmem_cache_shrink(struct kmem_cache *s)
+{
+#ifdef CONFIG_NUMA
+ int node;
+#endif
+
+ on_each_cpu(kmem_cache_trim_percpu, s, 1);
+
+#ifdef CONFIG_NUMA
+ for_each_node_state(node, N_NORMAL_MEMORY) {
+ struct kmem_cache_node *n;
+ struct kmem_cache_list *l;
+
+ n = s->node_slab[node];
+ if (!n)
+ continue;
+ l = &n->list;
+
+ spin_lock_irq(&n->list_lock);
+ claim_remote_free_list(s, l);
+ flush_free_list(s, l);
+ spin_unlock_irq(&n->list_lock);
+ }
+#endif
+
+ return 0;
+}
+EXPORT_SYMBOL(kmem_cache_shrink);
+
+#if defined(CONFIG_NUMA) && defined(CONFIG_MEMORY_HOTPLUG)
+static void kmem_cache_reap_percpu(void *arg)
+{
+ int cpu = smp_processor_id();
+ struct kmem_cache *s;
+ long phase = (long)arg;
+
+ list_for_each_entry(s, &slab_caches, list) {
+ struct kmem_cache_cpu *c = get_cpu_slab(s, cpu);
+ struct kmem_cache_list *l = &c->list;
+
+ if (phase == 0) {
+ flush_free_list_all(s, l);
+ flush_remote_free_cache(s, c);
+ }
+
+ if (phase == 1) {
+ claim_remote_free_list(s, l);
+ flush_free_list_all(s, l);
+ }
+ }
+}
+
+static void kmem_cache_reap(void)
+{
+ struct kmem_cache *s;
+ int node;
+
+ down_read(&slqb_lock);
+ on_each_cpu(kmem_cache_reap_percpu, (void *)0, 1);
+ on_each_cpu(kmem_cache_reap_percpu, (void *)1, 1);
+
+ list_for_each_entry(s, &slab_caches, list) {
+ for_each_node_state(node, N_NORMAL_MEMORY) {
+ struct kmem_cache_node *n;
+ struct kmem_cache_list *l;
+
+ n = s->node_slab[node];
+ if (!n)
+ continue;
+ l = &n->list;
+
+ spin_lock_irq(&n->list_lock);
+ claim_remote_free_list(s, l);
+ flush_free_list_all(s, l);
+ spin_unlock_irq(&n->list_lock);
+ }
+ }
+ up_read(&slqb_lock);
+}
+#endif
+
+static void cache_trim_worker(struct work_struct *w)
+{
+ struct delayed_work *work =
+ container_of(w, struct delayed_work, work);
+ struct kmem_cache *s;
+
+ if (!down_read_trylock(&slqb_lock))
+ goto out;
+
+ list_for_each_entry(s, &slab_caches, list) {
+#ifdef CONFIG_NUMA
+ int node = numa_node_id();
+ struct kmem_cache_node *n = s->node_slab[node];
+
+ if (n) {
+ struct kmem_cache_list *l = &n->list;
+
+ spin_lock_irq(&n->list_lock);
+ claim_remote_free_list(s, l);
+ flush_free_list(s, l);
+ spin_unlock_irq(&n->list_lock);
+ }
+#endif
+
+ local_irq_disable();
+ kmem_cache_trim_percpu(s);
+ local_irq_enable();
+ }
+
+ up_read(&slqb_lock);
+out:
+ schedule_delayed_work(work, round_jiffies_relative(3*HZ));
+}
+
+static DEFINE_PER_CPU(struct delayed_work, cache_trim_work);
+
+static void __cpuinit start_cpu_timer(int cpu)
+{
+ struct delayed_work *cache_trim_work = &per_cpu(cache_trim_work, cpu);
+
+ /*
+ * When this gets called from do_initcalls via cpucache_init(),
+ * init_workqueues() has already run, so keventd will be setup
+ * at that time.
+ */
+ if (keventd_up() && cache_trim_work->work.func == NULL) {
+ INIT_DELAYED_WORK(cache_trim_work, cache_trim_worker);
+ schedule_delayed_work_on(cpu, cache_trim_work,
+ __round_jiffies_relative(HZ, cpu));
+ }
+}
+
+static int __init cpucache_init(void)
+{
+ int cpu;
+
+ for_each_online_cpu(cpu)
+ start_cpu_timer(cpu);
+
+ return 0;
+}
+device_initcall(cpucache_init);
+
+#if defined(CONFIG_NUMA) && defined(CONFIG_MEMORY_HOTPLUG)
+static void slab_mem_going_offline_callback(void *arg)
+{
+ kmem_cache_reap();
+}
+
+static void slab_mem_offline_callback(void *arg)
+{
+ /* XXX: should release structures, see CPU offline comment */
+}
+
+static int slab_mem_going_online_callback(void *arg)
+{
+ struct kmem_cache *s;
+ struct kmem_cache_node *n;
+ struct memory_notify *marg = arg;
+ int nid = marg->status_change_nid;
+ int ret = 0;
+
+ /*
+ * If the node's memory is already available, then kmem_cache_node is
+ * already created. Nothing to do.
+ */
+ if (nid < 0)
+ return 0;
+
+ /*
+ * We are bringing a node online. No memory is availabe yet. We must
+ * allocate a kmem_cache_node structure in order to bring the node
+ * online.
+ */
+ down_write(&slqb_lock);
+ list_for_each_entry(s, &slab_caches, list) {
+ /*
+ * XXX: kmem_cache_alloc_node will fallback to other nodes
+ * since memory is not yet available from the node that
+ * is brought up.
+ */
+ if (s->node_slab[nid]) /* could be lefover from last online */
+ continue;
+ n = kmem_cache_alloc(&kmem_node_cache, GFP_KERNEL);
+ if (!n) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ init_kmem_cache_node(s, n);
+ s->node_slab[nid] = n;
+ }
+out:
+ up_write(&slqb_lock);
+ return ret;
+}
+
+static int slab_memory_callback(struct notifier_block *self,
+ unsigned long action, void *arg)
+{
+ int ret = 0;
+
+ switch (action) {
+ case MEM_GOING_ONLINE:
+ ret = slab_mem_going_online_callback(arg);
+ break;
+ case MEM_GOING_OFFLINE:
+ slab_mem_going_offline_callback(arg);
+ break;
+ case MEM_OFFLINE:
+ case MEM_CANCEL_ONLINE:
+ slab_mem_offline_callback(arg);
+ break;
+ case MEM_ONLINE:
+ case MEM_CANCEL_OFFLINE:
+ break;
+ }
+
+ if (ret)
+ ret = notifier_from_errno(ret);
+ else
+ ret = NOTIFY_OK;
+ return ret;
+}
+
+#endif /* CONFIG_MEMORY_HOTPLUG */
+
+/********************************************************************
+ * Basic setup of slabs
+ *******************************************************************/
+
+void __init kmem_cache_init(void)
+{
+ int i;
+ unsigned int flags = SLAB_HWCACHE_ALIGN|SLAB_PANIC;
+
+ /*
+ * All the ifdefs are rather ugly here, but it's just the setup code,
+ * so it doesn't have to be too readable :)
+ */
+
+ /*
+ * No need to take slqb_lock here: there should be no concurrency
+ * anyway, and spin_unlock_irq in rwsem code could enable interrupts
+ * too early.
+ */
+ kmem_cache_open(&kmem_cache_cache, "kmem_cache",
+ sizeof(struct kmem_cache), 0, flags, NULL, 0);
+#ifdef CONFIG_SMP
+ kmem_cache_open(&kmem_cpu_cache, "kmem_cache_cpu",
+ sizeof(struct kmem_cache_cpu), 0, flags, NULL, 0);
+#endif
+#ifdef CONFIG_NUMA
+ kmem_cache_open(&kmem_node_cache, "kmem_cache_node",
+ sizeof(struct kmem_cache_node), 0, flags, NULL, 0);
+#endif
+
+#ifdef CONFIG_SMP
+ for_each_possible_cpu(i) {
+ struct kmem_cache_cpu *c;
+
+ c = &per_cpu(kmem_cache_cpus, i);
+ init_kmem_cache_cpu(&kmem_cache_cache, c);
+ kmem_cache_cache.cpu_slab[i] = c;
+
+ c = &per_cpu(kmem_cpu_cpus, i);
+ init_kmem_cache_cpu(&kmem_cpu_cache, c);
+ kmem_cpu_cache.cpu_slab[i] = c;
+
+#ifdef CONFIG_NUMA
+ c = &per_cpu(kmem_node_cpus, i);
+ init_kmem_cache_cpu(&kmem_node_cache, c);
+ kmem_node_cache.cpu_slab[i] = c;
+#endif
+ }
+#else
+ init_kmem_cache_cpu(&kmem_cache_cache, &kmem_cache_cache.cpu_slab);
+#endif
+
+#ifdef CONFIG_NUMA
+ for_each_node_state(i, N_NORMAL_MEMORY) {
+ struct kmem_cache_node *n;
+
+ n = &kmem_cache_nodes[i];
+ init_kmem_cache_node(&kmem_cache_cache, n);
+ kmem_cache_cache.node_slab[i] = n;
+#ifdef CONFIG_SMP
+ n = &kmem_cpu_nodes[i];
+ init_kmem_cache_node(&kmem_cpu_cache, n);
+ kmem_cpu_cache.node_slab[i] = n;
+#endif
+ n = &kmem_node_nodes[i];
+ init_kmem_cache_node(&kmem_node_cache, n);
+ kmem_node_cache.node_slab[i] = n;
+ }
+#endif
+
+ /* Caches that are not of the two-to-the-power-of size */
+ if (L1_CACHE_BYTES < 64 && KMALLOC_MIN_SIZE <= 64) {
+ open_kmalloc_cache(&kmalloc_caches[1],
+ "kmalloc-96", 96, GFP_KERNEL);
+#ifdef CONFIG_ZONE_DMA
+ open_kmalloc_cache(&kmalloc_caches_dma[1],
+ "kmalloc_dma-96", 96, GFP_KERNEL|SLQB_DMA);
+#endif
+ }
+ if (L1_CACHE_BYTES < 128 && KMALLOC_MIN_SIZE <= 128) {
+ open_kmalloc_cache(&kmalloc_caches[2],
+ "kmalloc-192", 192, GFP_KERNEL);
+#ifdef CONFIG_ZONE_DMA
+ open_kmalloc_cache(&kmalloc_caches_dma[2],
+ "kmalloc_dma-192", 192, GFP_KERNEL|SLQB_DMA);
+#endif
+ }
+
+ for (i = KMALLOC_SHIFT_LOW; i <= KMALLOC_SHIFT_SLQB_HIGH; i++) {
+ open_kmalloc_cache(&kmalloc_caches[i],
+ "kmalloc", 1 << i, GFP_KERNEL);
+#ifdef CONFIG_ZONE_DMA
+ open_kmalloc_cache(&kmalloc_caches_dma[i],
+ "kmalloc_dma", 1 << i, GFP_KERNEL|SLQB_DMA);
+#endif
+ }
+
+ /*
+ * Patch up the size_index table if we have strange large alignment
+ * requirements for the kmalloc array. This is only the case for
+ * mips it seems. The standard arches will not generate any code here.
+ *
+ * Largest permitted alignment is 256 bytes due to the way we
+ * handle the index determination for the smaller caches.
+ *
+ * Make sure that nothing crazy happens if someone starts tinkering
+ * around with ARCH_KMALLOC_MINALIGN
+ */
+ BUILD_BUG_ON(KMALLOC_MIN_SIZE > 256 ||
+ (KMALLOC_MIN_SIZE & (KMALLOC_MIN_SIZE - 1)));
+
+ for (i = 8; i < KMALLOC_MIN_SIZE; i += 8)
+ size_index[(i - 1) / 8] = KMALLOC_SHIFT_LOW;
+
+ /* Provide the correct kmalloc names now that the caches are up */
+ for (i = KMALLOC_SHIFT_LOW; i <= KMALLOC_SHIFT_SLQB_HIGH; i++) {
+ kmalloc_caches[i].name =
+ kasprintf(GFP_KERNEL, "kmalloc-%d", 1 << i);
+#ifdef CONFIG_ZONE_DMA
+ kmalloc_caches_dma[i].name =
+ kasprintf(GFP_KERNEL, "kmalloc_dma-%d", 1 << i);
+#endif
+ }
+
+#ifdef CONFIG_SMP
+ register_cpu_notifier(&slab_notifier);
+#endif
+#ifdef CONFIG_NUMA
+ hotplug_memory_notifier(slab_memory_callback, 1);
+#endif
+ /*
+ * smp_init() has not yet been called, so no worries about memory
+ * ordering with __slab_is_available.
+ */
+ __slab_is_available = 1;
+}
+
+void __init kmem_cache_init_late(void)
+{
+}
+
+/*
+ * Some basic slab creation sanity checks
+ */
+static int kmem_cache_create_ok(const char *name, size_t size,
+ size_t align, unsigned long flags)
+{
+ struct kmem_cache *tmp;
+
+ /*
+ * Sanity checks... these are all serious usage bugs.
+ */
+ if (!name || in_interrupt() || (size < sizeof(void *))) {
+ printk(KERN_ERR "kmem_cache_create(): early error in slab %s\n",
+ name);
+ dump_stack();
+
+ return 0;
+ }
+
+ list_for_each_entry(tmp, &slab_caches, list) {
+ char x;
+ int res;
+
+ /*
+ * This happens when the module gets unloaded and doesn't
+ * destroy its slab cache and no-one else reuses the vmalloc
+ * area of the module. Print a warning.
+ */
+ res = probe_kernel_address(tmp->name, x);
+ if (res) {
+ printk(KERN_ERR
+ "SLAB: cache with size %d has lost its name\n",
+ tmp->size);
+ continue;
+ }
+
+ if (!strcmp(tmp->name, name)) {
+ printk(KERN_ERR
+ "SLAB: duplicate cache %s\n", name);
+ dump_stack();
+
+ return 0;
+ }
+ }
+
+ WARN_ON(strchr(name, ' ')); /* It confuses parsers */
+ if (flags & SLAB_DESTROY_BY_RCU)
+ WARN_ON(flags & SLAB_POISON);
+
+ return 1;
+}
+
+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;
+
+ down_write(&slqb_lock);
+ if (!kmem_cache_create_ok(name, size, align, flags))
+ goto err;
+
+ s = kmem_cache_alloc(&kmem_cache_cache, GFP_KERNEL);
+ if (!s)
+ goto err;
+
+ if (kmem_cache_open(s, name, size, align, flags, ctor, 1)) {
+ up_write(&slqb_lock);
+ return s;
+ }
+
+ kmem_cache_free(&kmem_cache_cache, s);
+
+err:
+ up_write(&slqb_lock);
+ if (flags & SLAB_PANIC)
+ panic("%s: failed to create slab `%s'\n", __func__, name);
+
+ return NULL;
+}
+EXPORT_SYMBOL(kmem_cache_create);
+
+#ifdef CONFIG_SMP
+/*
+ * Use the cpu notifier to insure that the cpu slabs are flushed when
+ * necessary.
+ */
+static int __cpuinit slab_cpuup_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ long cpu = (long)hcpu;
+ struct kmem_cache *s;
+
+ switch (action) {
+ case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
+ down_write(&slqb_lock);
+ list_for_each_entry(s, &slab_caches, list) {
+ if (s->cpu_slab[cpu]) /* could be lefover last online */
+ continue;
+ s->cpu_slab[cpu] = alloc_kmem_cache_cpu(s, cpu);
+ if (!s->cpu_slab[cpu]) {
+ up_read(&slqb_lock);
+ return NOTIFY_BAD;
+ }
+ }
+ up_write(&slqb_lock);
+ break;
+
+ case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
+ case CPU_DOWN_FAILED:
+ case CPU_DOWN_FAILED_FROZEN:
+ start_cpu_timer(cpu);
+ break;
+
+ case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
+ cancel_rearming_delayed_work(&per_cpu(cache_trim_work, cpu));
+ per_cpu(cache_trim_work, cpu).work.func = NULL;
+ break;
+
+ case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
+ case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
+ /*
+ * XXX: Freeing here doesn't work because objects can still be
+ * on this CPU's list. periodic timer needs to check if a CPU
+ * is offline and then try to cleanup from there. Same for node
+ * offline.
+ */
+ default:
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata slab_notifier = {
+ .notifier_call = slab_cpuup_callback
+};
+
+#endif
+
+#ifdef CONFIG_SLQB_DEBUG
+void *__kmalloc_track_caller(size_t size, gfp_t flags, unsigned long caller)
+{
+ struct kmem_cache *s;
+ int node = -1;
+
+ s = get_slab(size, flags);
+ if (unlikely(ZERO_OR_NULL_PTR(s)))
+ return s;
+
+#ifdef CONFIG_NUMA
+ if (unlikely(current->flags & (PF_SPREAD_SLAB | PF_MEMPOLICY)))
+ node = alternate_nid(s, flags, node);
+#endif
+ return slab_alloc(s, flags, node, caller);
+}
+
+void *__kmalloc_node_track_caller(size_t size, gfp_t flags, int node,
+ unsigned long caller)
+{
+ struct kmem_cache *s;
+
+ s = get_slab(size, flags);
+ if (unlikely(ZERO_OR_NULL_PTR(s)))
+ return s;
+
+ return slab_alloc(s, flags, node, caller);
+}
+#endif
+
+#if defined(CONFIG_SLQB_SYSFS) || defined(CONFIG_SLABINFO)
+struct stats_gather {
+ struct kmem_cache *s;
+ spinlock_t lock;
+ unsigned long nr_slabs;
+ unsigned long nr_partial;
+ unsigned long nr_inuse;
+ unsigned long nr_objects;
+
+#ifdef CONFIG_SLQB_STATS
+ unsigned long stats[NR_SLQB_STAT_ITEMS];
+#endif
+};
+
+static void __gather_stats(void *arg)
+{
+ unsigned long nr_slabs;
+ unsigned long nr_partial;
+ unsigned long nr_inuse;
+ struct stats_gather *gather = arg;
+ int cpu = smp_processor_id();
+ struct kmem_cache *s = gather->s;
+ struct kmem_cache_cpu *c = get_cpu_slab(s, cpu);
+ struct kmem_cache_list *l = &c->list;
+ struct slqb_page *page;
+#ifdef CONFIG_SLQB_STATS
+ int i;
+#endif
+
+ spin_lock(&l->page_lock);
+ nr_slabs = l->nr_slabs;
+ nr_partial = l->nr_partial;
+ nr_inuse = (nr_slabs - nr_partial) * s->objects;
+
+ list_for_each_entry(page, &l->partial, lru) {
+ nr_inuse += page->inuse;
+ }
+ spin_unlock(&l->page_lock);
+
+ spin_lock(&gather->lock);
+ gather->nr_slabs += nr_slabs;
+ gather->nr_partial += nr_partial;
+ gather->nr_inuse += nr_inuse;
+#ifdef CONFIG_SLQB_STATS
+ for (i = 0; i < NR_SLQB_STAT_ITEMS; i++)
+ gather->stats[i] += l->stats[i];
+#endif
+ spin_unlock(&gather->lock);
+}
+
+/* must be called with slqb_lock held */
+static void gather_stats_locked(struct kmem_cache *s,
+ struct stats_gather *stats)
+{
+#ifdef CONFIG_NUMA
+ int node;
+#endif
+
+ memset(stats, 0, sizeof(struct stats_gather));
+ stats->s = s;
+ spin_lock_init(&stats->lock);
+
+ on_each_cpu(__gather_stats, stats, 1);
+
+#ifdef CONFIG_NUMA
+ for_each_online_node(node) {
+ struct kmem_cache_node *n = s->node_slab[node];
+ struct kmem_cache_list *l = &n->list;
+ struct slqb_page *page;
+ unsigned long flags;
+#ifdef CONFIG_SLQB_STATS
+ int i;
+#endif
+
+ spin_lock_irqsave(&n->list_lock, flags);
+#ifdef CONFIG_SLQB_STATS
+ for (i = 0; i < NR_SLQB_STAT_ITEMS; i++)
+ stats->stats[i] += l->stats[i];
+#endif
+ stats->nr_slabs += l->nr_slabs;
+ stats->nr_partial += l->nr_partial;
+ stats->nr_inuse += (l->nr_slabs - l->nr_partial) * s->objects;
+
+ list_for_each_entry(page, &l->partial, lru) {
+ stats->nr_inuse += page->inuse;
+ }
+ spin_unlock_irqrestore(&n->list_lock, flags);
+ }
+#endif
+
+ stats->nr_objects = stats->nr_slabs * s->objects;
+}
+
+#ifdef CONFIG_SLQB_SYSFS
+static void gather_stats(struct kmem_cache *s, struct stats_gather *stats)
+{
+ down_read(&slqb_lock); /* hold off hotplug */
+ gather_stats_locked(s, stats);
+ up_read(&slqb_lock);
+}
+#endif
+#endif
+
+/*
+ * The /proc/slabinfo ABI
+ */
+#ifdef CONFIG_SLABINFO
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+ssize_t slabinfo_write(struct file *file, const char __user * buffer,
+ size_t count, loff_t *ppos)
+{
+ return -EINVAL;
+}
+
+static void print_slabinfo_header(struct seq_file *m)
+{
+ seq_puts(m, "slabinfo - version: 2.1\n");
+ seq_puts(m, "# name <active_objs> <num_objs> <objsize> "
+ "<objperslab> <pagesperslab>");
+ seq_puts(m, " : tunables <limit> <batchcount> <sharedfactor>");
+ seq_puts(m, " : slabdata <active_slabs> <num_slabs> <sharedavail>");
+ seq_putc(m, '\n');
+}
+
+static void *s_start(struct seq_file *m, loff_t *pos)
+{
+ loff_t n = *pos;
+
+ down_read(&slqb_lock);
+ if (!n)
+ print_slabinfo_header(m);
+
+ return seq_list_start(&slab_caches, *pos);
+}
+
+static void *s_next(struct seq_file *m, void *p, loff_t *pos)
+{
+ return seq_list_next(p, &slab_caches, pos);
+}
+
+static void s_stop(struct seq_file *m, void *p)
+{
+ up_read(&slqb_lock);
+}
+
+static int s_show(struct seq_file *m, void *p)
+{
+ struct stats_gather stats;
+ struct kmem_cache *s;
+
+ s = list_entry(p, struct kmem_cache, list);
+
+ gather_stats_locked(s, &stats);
+
+ seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d", s->name, stats.nr_inuse,
+ stats.nr_objects, s->size, s->objects, (1 << s->order));
+ seq_printf(m, " : tunables %4u %4u %4u", slab_hiwater(s),
+ slab_freebatch(s), 0);
+ seq_printf(m, " : slabdata %6lu %6lu %6lu", stats.nr_slabs,
+ stats.nr_slabs, 0UL);
+ seq_putc(m, '\n');
+ return 0;
+}
+
+static const struct seq_operations slabinfo_op = {
+ .start = s_start,
+ .next = s_next,
+ .stop = s_stop,
+ .show = s_show,
+};
+
+static int slabinfo_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &slabinfo_op);
+}
+
+static const struct file_operations proc_slabinfo_operations = {
+ .open = slabinfo_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static int __init slab_proc_init(void)
+{
+ proc_create("slabinfo", S_IWUSR|S_IRUGO, NULL,
+ &proc_slabinfo_operations);
+ return 0;
+}
+module_init(slab_proc_init);
+#endif /* CONFIG_SLABINFO */
+
+#ifdef CONFIG_SLQB_SYSFS
+/*
+ * sysfs API
+ */
+#define to_slab_attr(n) container_of(n, struct slab_attribute, attr)
+#define to_slab(n) container_of(n, struct kmem_cache, kobj);
+
+struct slab_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct kmem_cache *s, char *buf);
+ ssize_t (*store)(struct kmem_cache *s, const char *x, size_t count);
+};
+
+#define SLAB_ATTR_RO(_name) \
+ static struct slab_attribute _name##_attr = __ATTR_RO(_name)
+
+#define SLAB_ATTR(_name) \
+ static struct slab_attribute _name##_attr = \
+ __ATTR(_name, 0644, _name##_show, _name##_store)
+
+static ssize_t slab_size_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", s->size);
+}
+SLAB_ATTR_RO(slab_size);
+
+static ssize_t align_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", s->align);
+}
+SLAB_ATTR_RO(align);
+
+static ssize_t object_size_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", s->objsize);
+}
+SLAB_ATTR_RO(object_size);
+
+static ssize_t objs_per_slab_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", s->objects);
+}
+SLAB_ATTR_RO(objs_per_slab);
+
+static ssize_t order_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", s->order);
+}
+SLAB_ATTR_RO(order);
+
+static ssize_t ctor_show(struct kmem_cache *s, char *buf)
+{
+ if (s->ctor) {
+ int n = sprint_symbol(buf, (unsigned long)s->ctor);
+
+ return n + sprintf(buf + n, "\n");
+ }
+ return 0;
+}
+SLAB_ATTR_RO(ctor);
+
+static ssize_t slabs_show(struct kmem_cache *s, char *buf)
+{
+ struct stats_gather stats;
+
+ gather_stats(s, &stats);
+
+ return sprintf(buf, "%lu\n", stats.nr_slabs);
+}
+SLAB_ATTR_RO(slabs);
+
+static ssize_t objects_show(struct kmem_cache *s, char *buf)
+{
+ struct stats_gather stats;
+
+ gather_stats(s, &stats);
+
+ return sprintf(buf, "%lu\n", stats.nr_inuse);
+}
+SLAB_ATTR_RO(objects);
+
+static ssize_t total_objects_show(struct kmem_cache *s, char *buf)
+{
+ struct stats_gather stats;
+
+ gather_stats(s, &stats);
+
+ return sprintf(buf, "%lu\n", stats.nr_objects);
+}
+SLAB_ATTR_RO(total_objects);
+
+static ssize_t reclaim_account_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_RECLAIM_ACCOUNT));
+}
+SLAB_ATTR_RO(reclaim_account);
+
+static ssize_t hwcache_align_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_HWCACHE_ALIGN));
+}
+SLAB_ATTR_RO(hwcache_align);
+
+#ifdef CONFIG_ZONE_DMA
+static ssize_t cache_dma_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_CACHE_DMA));
+}
+SLAB_ATTR_RO(cache_dma);
+#endif
+
+static ssize_t destroy_by_rcu_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_DESTROY_BY_RCU));
+}
+SLAB_ATTR_RO(destroy_by_rcu);
+
+static ssize_t red_zone_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_RED_ZONE));
+}
+SLAB_ATTR_RO(red_zone);
+
+static ssize_t poison_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_POISON));
+}
+SLAB_ATTR_RO(poison);
+
+static ssize_t store_user_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_STORE_USER));
+}
+SLAB_ATTR_RO(store_user);
+
+static ssize_t hiwater_store(struct kmem_cache *s,
+ const char *buf, size_t length)
+{
+ long hiwater;
+ int err;
+
+ err = strict_strtol(buf, 10, &hiwater);
+ if (err)
+ return err;
+
+ if (hiwater < 0)
+ return -EINVAL;
+
+ s->hiwater = hiwater;
+
+ return length;
+}
+
+static ssize_t hiwater_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", slab_hiwater(s));
+}
+SLAB_ATTR(hiwater);
+
+static ssize_t freebatch_store(struct kmem_cache *s,
+ const char *buf, size_t length)
+{
+ long freebatch;
+ int err;
+
+ err = strict_strtol(buf, 10, &freebatch);
+ if (err)
+ return err;
+
+ if (freebatch <= 0 || freebatch - 1 > s->hiwater)
+ return -EINVAL;
+
+ s->freebatch = freebatch;
+
+ return length;
+}
+
+static ssize_t freebatch_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", slab_freebatch(s));
+}
+SLAB_ATTR(freebatch);
+
+#ifdef CONFIG_SLQB_STATS
+static int show_stat(struct kmem_cache *s, char *buf, enum stat_item si)
+{
+ struct stats_gather stats;
+ int len;
+#ifdef CONFIG_SMP
+ int cpu;
+#endif
+
+ gather_stats(s, &stats);
+
+ len = sprintf(buf, "%lu", stats.stats[si]);
+
+#ifdef CONFIG_SMP
+ for_each_online_cpu(cpu) {
+ struct kmem_cache_cpu *c = get_cpu_slab(s, cpu);
+ struct kmem_cache_list *l = &c->list;
+
+ if (len < PAGE_SIZE - 20)
+ len += sprintf(buf+len, " C%d=%lu", cpu, l->stats[si]);
+ }
+#endif
+ return len + sprintf(buf + len, "\n");
+}
+
+#define STAT_ATTR(si, text) \
+static ssize_t text##_show(struct kmem_cache *s, char *buf) \
+{ \
+ return show_stat(s, buf, si); \
+} \
+SLAB_ATTR_RO(text); \
+
+STAT_ATTR(ALLOC, alloc);
+STAT_ATTR(ALLOC_SLAB_FILL, alloc_slab_fill);
+STAT_ATTR(ALLOC_SLAB_NEW, alloc_slab_new);
+STAT_ATTR(FREE, free);
+STAT_ATTR(FREE_REMOTE, free_remote);
+STAT_ATTR(FLUSH_FREE_LIST, flush_free_list);
+STAT_ATTR(FLUSH_FREE_LIST_OBJECTS, flush_free_list_objects);
+STAT_ATTR(FLUSH_FREE_LIST_REMOTE, flush_free_list_remote);
+STAT_ATTR(FLUSH_SLAB_PARTIAL, flush_slab_partial);
+STAT_ATTR(FLUSH_SLAB_FREE, flush_slab_free);
+STAT_ATTR(FLUSH_RFREE_LIST, flush_rfree_list);
+STAT_ATTR(FLUSH_RFREE_LIST_OBJECTS, flush_rfree_list_objects);
+STAT_ATTR(CLAIM_REMOTE_LIST, claim_remote_list);
+STAT_ATTR(CLAIM_REMOTE_LIST_OBJECTS, claim_remote_list_objects);
+#endif
+
+static struct attribute *slab_attrs[] = {
+ &slab_size_attr.attr,
+ &object_size_attr.attr,
+ &objs_per_slab_attr.attr,
+ &order_attr.attr,
+ &objects_attr.attr,
+ &total_objects_attr.attr,
+ &slabs_attr.attr,
+ &ctor_attr.attr,
+ &align_attr.attr,
+ &hwcache_align_attr.attr,
+ &reclaim_account_attr.attr,
+ &destroy_by_rcu_attr.attr,
+ &red_zone_attr.attr,
+ &poison_attr.attr,
+ &store_user_attr.attr,
+ &hiwater_attr.attr,
+ &freebatch_attr.attr,
+#ifdef CONFIG_ZONE_DMA
+ &cache_dma_attr.attr,
+#endif
+#ifdef CONFIG_SLQB_STATS
+ &alloc_attr.attr,
+ &alloc_slab_fill_attr.attr,
+ &alloc_slab_new_attr.attr,
+ &free_attr.attr,
+ &free_remote_attr.attr,
+ &flush_free_list_attr.attr,
+ &flush_free_list_objects_attr.attr,
+ &flush_free_list_remote_attr.attr,
+ &flush_slab_partial_attr.attr,
+ &flush_slab_free_attr.attr,
+ &flush_rfree_list_attr.attr,
+ &flush_rfree_list_objects_attr.attr,
+ &claim_remote_list_attr.attr,
+ &claim_remote_list_objects_attr.attr,
+#endif
+ NULL
+};
+
+static struct attribute_group slab_attr_group = {
+ .attrs = slab_attrs,
+};
+
+static ssize_t slab_attr_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct slab_attribute *attribute;
+ struct kmem_cache *s;
+ int err;
+
+ attribute = to_slab_attr(attr);
+ s = to_slab(kobj);
+
+ if (!attribute->show)
+ return -EIO;
+
+ err = attribute->show(s, buf);
+
+ return err;
+}
+
+static ssize_t slab_attr_store(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t len)
+{
+ struct slab_attribute *attribute;
+ struct kmem_cache *s;
+ int err;
+
+ attribute = to_slab_attr(attr);
+ s = to_slab(kobj);
+
+ if (!attribute->store)
+ return -EIO;
+
+ err = attribute->store(s, buf, len);
+
+ return err;
+}
+
+static void kmem_cache_release(struct kobject *kobj)
+{
+ struct kmem_cache *s = to_slab(kobj);
+
+ kmem_cache_free(&kmem_cache_cache, s);
+}
+
+static struct sysfs_ops slab_sysfs_ops = {
+ .show = slab_attr_show,
+ .store = slab_attr_store,
+};
+
+static struct kobj_type slab_ktype = {
+ .sysfs_ops = &slab_sysfs_ops,
+ .release = kmem_cache_release
+};
+
+static int uevent_filter(struct kset *kset, struct kobject *kobj)
+{
+ struct kobj_type *ktype = get_ktype(kobj);
+
+ if (ktype == &slab_ktype)
+ return 1;
+ return 0;
+}
+
+static struct kset_uevent_ops slab_uevent_ops = {
+ .filter = uevent_filter,
+};
+
+static struct kset *slab_kset;
+
+static int sysfs_available __read_mostly;
+
+static int sysfs_slab_add(struct kmem_cache *s)
+{
+ int err;
+
+ if (!sysfs_available)
+ return 0;
+
+ s->kobj.kset = slab_kset;
+ err = kobject_init_and_add(&s->kobj, &slab_ktype, NULL, s->name);
+ if (err) {
+ kobject_put(&s->kobj);
+ return err;
+ }
+
+ err = sysfs_create_group(&s->kobj, &slab_attr_group);
+ if (err)
+ return err;
+
+ kobject_uevent(&s->kobj, KOBJ_ADD);
+
+ return 0;
+}
+
+static void sysfs_slab_remove(struct kmem_cache *s)
+{
+ kobject_uevent(&s->kobj, KOBJ_REMOVE);
+ kobject_del(&s->kobj);
+ kobject_put(&s->kobj);
+}
+
+static int __init slab_sysfs_init(void)
+{
+ struct kmem_cache *s;
+ int err;
+
+ slab_kset = kset_create_and_add("slab", &slab_uevent_ops, kernel_kobj);
+ if (!slab_kset) {
+ printk(KERN_ERR "Cannot register slab subsystem.\n");
+ return -ENOSYS;
+ }
+
+ down_write(&slqb_lock);
+
+ sysfs_available = 1;
+
+ list_for_each_entry(s, &slab_caches, list) {
+ err = sysfs_slab_add(s);
+ if (err)
+ printk(KERN_ERR "SLQB: Unable to add boot slab %s"
+ " to sysfs\n", s->name);
+ }
+
+ up_write(&slqb_lock);
+
+ return 0;
+}
+device_initcall(slab_sysfs_init);
+
+#endif
diff --git a/mm/slub.c b/mm/slub.c
index 4996fc719552..ac0ca4c0d054 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -4371,12 +4371,28 @@ static int show_stat(struct kmem_cache *s, char *buf, enum stat_item si)
return len + sprintf(buf + len, "\n");
}
+static void clear_stat(struct kmem_cache *s, enum stat_item si)
+{
+ int cpu;
+
+ for_each_online_cpu(cpu)
+ get_cpu_slab(s, cpu)->stat[si] = 0;
+}
+
#define STAT_ATTR(si, text) \
static ssize_t text##_show(struct kmem_cache *s, char *buf) \
{ \
return show_stat(s, buf, si); \
} \
-SLAB_ATTR_RO(text); \
+static ssize_t text##_store(struct kmem_cache *s, \
+ const char *buf, size_t length) \
+{ \
+ if (buf[0] != '0') \
+ return -EINVAL; \
+ clear_stat(s, si); \
+ return length; \
+} \
+SLAB_ATTR(text); \
STAT_ATTR(ALLOC_FASTPATH, alloc_fastpath);
STAT_ATTR(ALLOC_SLOWPATH, alloc_slowpath);
diff --git a/mm/truncate.c b/mm/truncate.c
index 450cebdabfc0..2c147a7e5f2c 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -490,7 +490,7 @@ EXPORT_SYMBOL_GPL(invalidate_inode_pages2_range);
* Any pages which are found to be mapped into pagetables are unmapped prior to
* invalidation.
*
- * Returns -EIO if any pages could not be invalidated.
+ * Returns -EBUSY if any pages could not be invalidated.
*/
int invalidate_inode_pages2(struct address_space *mapping)
{
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index 82570bc2a180..4ade5edf1033 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -89,7 +89,7 @@ static inline u32 vlan_get_ingress_priority(struct net_device *dev,
{
struct vlan_dev_info *vip = vlan_dev_info(dev);
- return vip->ingress_priority_map[(vlan_tci >> 13) & 0x7];
+ return vip->ingress_priority_map[(vlan_tci >> VLAN_PRIO_SHIFT) & 0x7];
}
#ifdef CONFIG_VLAN_8021Q_GVRP
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 4198ec5c8abc..e3701977f58d 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -393,7 +393,7 @@ int vlan_dev_set_egress_priority(const struct net_device *dev,
struct vlan_dev_info *vlan = vlan_dev_info(dev);
struct vlan_priority_tci_mapping *mp = NULL;
struct vlan_priority_tci_mapping *np;
- u32 vlan_qos = (vlan_prio << 13) & 0xE000;
+ u32 vlan_qos = (vlan_prio << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK;
/* See if a priority mapping exists.. */
mp = vlan->egress_priority_map[skb_prio & 0xF];
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index b2e07f0dd298..ea1e3daabefe 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -43,7 +43,6 @@
#include <net/9p/transport.h>
#include <linux/scatterlist.h>
#include <linux/virtio.h>
-#include <linux/virtio_ids.h>
#include <linux/virtio_9p.h>
#define VIRTQUEUE_NUM 128
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index b1a4290996b5..abe38014b7fd 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -1821,7 +1821,7 @@ static int atalk_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned lo
#endif
-static struct net_proto_family atalk_family_ops = {
+static const struct net_proto_family atalk_family_ops = {
.family = PF_APPLETALK,
.create = atalk_create,
.owner = THIS_MODULE,
diff --git a/net/atm/common.c b/net/atm/common.c
index 950bd16d2383..d61e051e0a3f 100644
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -496,7 +496,7 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
error = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
if (error)
return error;
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
pr_debug("RcvM %d -= %d\n", atomic_read(&sk->sk_rmem_alloc), skb->truesize);
atm_return(vcc, skb->truesize);
skb_free_datagram(sk, skb);
diff --git a/net/atm/pvc.c b/net/atm/pvc.c
index d4c024504f99..a6e1fdbae87f 100644
--- a/net/atm/pvc.c
+++ b/net/atm/pvc.c
@@ -137,7 +137,7 @@ static int pvc_create(struct net *net, struct socket *sock,int protocol)
}
-static struct net_proto_family pvc_family_ops = {
+static const struct net_proto_family pvc_family_ops = {
.family = PF_ATMPVC,
.create = pvc_create,
.owner = THIS_MODULE,
diff --git a/net/atm/svc.c b/net/atm/svc.c
index f90d143c4b25..819354233318 100644
--- a/net/atm/svc.c
+++ b/net/atm/svc.c
@@ -666,7 +666,7 @@ static int svc_create(struct net *net, struct socket *sock,int protocol)
}
-static struct net_proto_family svc_family_ops = {
+static const struct net_proto_family svc_family_ops = {
.family = PF_ATMSVC,
.create = svc_create,
.owner = THIS_MODULE,
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index f45460730371..f05306f168fa 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1961,7 +1961,7 @@ static const struct file_operations ax25_info_fops = {
#endif
-static struct net_proto_family ax25_family_ops = {
+static const struct net_proto_family ax25_family_ops = {
.family = PF_AX25,
.create = ax25_create,
.owner = THIS_MODULE,
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 8cfb5a849841..399e59c9c6cb 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -45,7 +45,7 @@
/* Bluetooth sockets */
#define BT_MAX_PROTO 8
-static struct net_proto_family *bt_proto[BT_MAX_PROTO];
+static const struct net_proto_family *bt_proto[BT_MAX_PROTO];
static DEFINE_RWLOCK(bt_proto_lock);
static struct lock_class_key bt_lock_key[BT_MAX_PROTO];
@@ -86,7 +86,7 @@ static inline void bt_sock_reclassify_lock(struct socket *sock, int proto)
bt_key_strings[proto], &bt_lock_key[proto]);
}
-int bt_sock_register(int proto, struct net_proto_family *ops)
+int bt_sock_register(int proto, const struct net_proto_family *ops)
{
int err = 0;
@@ -257,7 +257,7 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
skb_reset_transport_header(skb);
err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
if (err == 0)
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
skb_free_datagram(sk, skb);
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index cafe9f54d841..9ac0497decb8 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -78,7 +78,7 @@ static struct bnep_session *__bnep_get_session(u8 *dst)
static void __bnep_link_session(struct bnep_session *s)
{
/* It's safe to call __module_get() here because sessions are added
- by the socket layer which has to hold the refference to this module.
+ by the socket layer which has to hold the reference to this module.
*/
__module_get(THIS_MODULE);
list_add(&s->list, &bnep_session_list);
@@ -629,7 +629,7 @@ int bnep_del_connection(struct bnep_conndel_req *req)
s = __bnep_get_session(req->dst);
if (s) {
/* Wakeup user-space which is polling for socket errors.
- * This is temporary hack untill we have shutdown in L2CAP */
+ * This is temporary hack until we have shutdown in L2CAP */
s->sock->sk->sk_err = EUNATCH;
/* Kill session thread */
diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
index e857628b0b27..0a2c5460bb48 100644
--- a/net/bluetooth/bnep/sock.c
+++ b/net/bluetooth/bnep/sock.c
@@ -222,7 +222,7 @@ static int bnep_sock_create(struct net *net, struct socket *sock, int protocol)
return 0;
}
-static struct net_proto_family bnep_sock_family_ops = {
+static const struct net_proto_family bnep_sock_family_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.create = bnep_sock_create
diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c
index 16b0fad74f6e..de7c8040bc56 100644
--- a/net/bluetooth/cmtp/sock.c
+++ b/net/bluetooth/cmtp/sock.c
@@ -217,7 +217,7 @@ static int cmtp_sock_create(struct net *net, struct socket *sock, int protocol)
return 0;
}
-static struct net_proto_family cmtp_sock_family_ops = {
+static const struct net_proto_family cmtp_sock_family_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.create = cmtp_sock_create
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 75302a986067..e7395f231989 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -687,7 +687,7 @@ static int hci_sock_dev_event(struct notifier_block *this, unsigned long event,
return NOTIFY_DONE;
}
-static struct net_proto_family hci_sock_family_ops = {
+static const struct net_proto_family hci_sock_family_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.create = hci_sock_create,
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 7f939ce29801..2bc6f6a8de68 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -92,6 +92,8 @@ static void add_conn(struct work_struct *work)
dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle);
+ dev_set_drvdata(&conn->dev, conn);
+
if (device_add(&conn->dev) < 0) {
BT_ERR("Failed to register connection device");
return;
@@ -144,8 +146,6 @@ void hci_conn_init_sysfs(struct hci_conn *conn)
conn->dev.class = bt_class;
conn->dev.parent = &hdev->dev;
- dev_set_drvdata(&conn->dev, conn);
-
device_initialize(&conn->dev);
INIT_WORK(&conn->work_add, add_conn);
diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c
index 37c9d7d2e688..4beb6a7a2953 100644
--- a/net/bluetooth/hidp/sock.c
+++ b/net/bluetooth/hidp/sock.c
@@ -268,7 +268,7 @@ static int hidp_sock_create(struct net *net, struct socket *sock, int protocol)
return 0;
}
-static struct net_proto_family hidp_sock_family_ops = {
+static const struct net_proto_family hidp_sock_family_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.create = hidp_sock_create
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 555d9da1869b..d65101d92ee5 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -555,12 +555,12 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
conn->feat_mask = 0;
- setup_timer(&conn->info_timer, l2cap_info_timeout,
- (unsigned long) conn);
-
spin_lock_init(&conn->lock);
rwlock_init(&conn->chan_list.lock);
+ setup_timer(&conn->info_timer, l2cap_info_timeout,
+ (unsigned long) conn);
+
conn->disc_reason = 0x13;
return conn;
@@ -783,6 +783,9 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
/* Default config options */
pi->conf_len = 0;
pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
+ skb_queue_head_init(TX_QUEUE(sk));
+ skb_queue_head_init(SREJ_QUEUE(sk));
+ INIT_LIST_HEAD(SREJ_LIST(sk));
}
static struct proto l2cap_proto = {
@@ -3916,7 +3919,7 @@ static const struct proto_ops l2cap_sock_ops = {
.getsockopt = l2cap_sock_getsockopt
};
-static struct net_proto_family l2cap_sock_family_ops = {
+static const struct net_proto_family l2cap_sock_family_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.create = l2cap_sock_create,
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 8a20aaf1f231..d3bfc1b0afb1 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -703,7 +703,7 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
copied += chunk;
size -= chunk;
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
if (!(flags & MSG_PEEK)) {
atomic_sub(chunk, &sk->sk_rmem_alloc);
@@ -1101,7 +1101,7 @@ static const struct proto_ops rfcomm_sock_ops = {
.mmap = sock_no_mmap
};
-static struct net_proto_family rfcomm_sock_family_ops = {
+static const struct net_proto_family rfcomm_sock_family_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.create = rfcomm_sock_create
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 77f4153bdb5e..694a65541b73 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -993,7 +993,7 @@ static const struct proto_ops sco_sock_ops = {
.getsockopt = sco_sock_getsockopt
};
-static struct net_proto_family sco_sock_family_ops = {
+static const struct net_proto_family sco_sock_family_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.create = sco_sock_create,
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 07a07770c8b6..1a99c4e04e85 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -157,6 +157,7 @@ static const struct ethtool_ops br_ethtool_ops = {
.get_tso = ethtool_op_get_tso,
.set_tso = br_set_tso,
.get_ufo = ethtool_op_get_ufo,
+ .set_ufo = ethtool_op_set_ufo,
.get_flags = ethtool_op_get_flags,
};
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 606832115674..3f2eb27e1ffb 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -842,7 +842,7 @@ static struct packet_type can_packet __read_mostly = {
.func = can_rcv,
};
-static struct net_proto_family can_family_ops __read_mostly = {
+static const struct net_proto_family can_family_ops = {
.family = PF_CAN,
.create = can_create,
.owner = THIS_MODULE,
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 597da4f8f888..2f47039c79dd 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1534,7 +1534,7 @@ static int bcm_recvmsg(struct kiocb *iocb, struct socket *sock,
return err;
}
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
if (msg->msg_name) {
msg->msg_namelen = sizeof(struct sockaddr_can);
diff --git a/net/can/raw.c b/net/can/raw.c
index b5e897922d32..962fc9f1d0c7 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -702,7 +702,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
return err;
}
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
if (msg->msg_name) {
msg->msg_namelen = sizeof(struct sockaddr_can);
diff --git a/net/compat.c b/net/compat.c
index a407c3addbae..e13f5256fd20 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -727,10 +727,10 @@ EXPORT_SYMBOL(compat_mc_getsockopt);
/* Argument list sizes for compat_sys_socketcall */
#define AL(x) ((x) * sizeof(u32))
-static unsigned char nas[19]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
+static unsigned char nas[20]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
AL(6),AL(2),AL(5),AL(5),AL(3),AL(3),
- AL(4)};
+ AL(4),AL(5)};
#undef AL
asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned flags)
@@ -755,13 +755,36 @@ asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, size_t len,
return sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr, addrlen);
}
+asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
+ unsigned vlen, unsigned int flags,
+ struct timespec __user *timeout)
+{
+ int datagrams;
+ struct timespec ktspec;
+ struct compat_timespec __user *utspec =
+ (struct compat_timespec __user *)timeout;
+
+ if (get_user(ktspec.tv_sec, &utspec->tv_sec) ||
+ get_user(ktspec.tv_nsec, &utspec->tv_nsec))
+ return -EFAULT;
+
+ datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
+ flags | MSG_CMSG_COMPAT, &ktspec);
+ if (datagrams > 0 &&
+ (put_user(ktspec.tv_sec, &utspec->tv_sec) ||
+ put_user(ktspec.tv_nsec, &utspec->tv_nsec)))
+ datagrams = -EFAULT;
+
+ return datagrams;
+}
+
asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
{
int ret;
u32 a[6];
u32 a0, a1;
- if (call < SYS_SOCKET || call > SYS_ACCEPT4)
+ if (call < SYS_SOCKET || call > SYS_RECVMMSG)
return -EINVAL;
if (copy_from_user(a, args, nas[call]))
return -EFAULT;
@@ -823,6 +846,10 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
case SYS_RECVMSG:
ret = compat_sys_recvmsg(a0, compat_ptr(a1), a[2]);
break;
+ case SYS_RECVMMSG:
+ ret = compat_sys_recvmmsg(a0, compat_ptr(a1), a[2], a[3],
+ compat_ptr(a[4]));
+ break;
case SYS_ACCEPT4:
ret = sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]);
break;
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 1c6cf3a1a4f6..4d57f5e12b05 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -262,6 +262,7 @@ int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags)
}
kfree_skb(skb);
+ atomic_inc(&sk->sk_drops);
sk_mem_reclaim_partial(sk);
return err;
diff --git a/net/core/dev.c b/net/core/dev.c
index b8f74cfb1bfd..950c13fa60d2 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -193,18 +193,15 @@ static struct list_head ptype_all __read_mostly; /* Taps */
DEFINE_RWLOCK(dev_base_lock);
EXPORT_SYMBOL(dev_base_lock);
-#define NETDEV_HASHBITS 8
-#define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS)
-
static inline struct hlist_head *dev_name_hash(struct net *net, const char *name)
{
unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ));
- return &net->dev_name_head[hash & ((1 << NETDEV_HASHBITS) - 1)];
+ return &net->dev_name_head[hash & (NETDEV_HASHENTRIES - 1)];
}
static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex)
{
- return &net->dev_index_head[ifindex & ((1 << NETDEV_HASHBITS) - 1)];
+ return &net->dev_index_head[ifindex & (NETDEV_HASHENTRIES - 1)];
}
/* Device list insertion */
@@ -1791,13 +1788,25 @@ EXPORT_SYMBOL(skb_tx_hash);
static struct netdev_queue *dev_pick_tx(struct net_device *dev,
struct sk_buff *skb)
{
- const struct net_device_ops *ops = dev->netdev_ops;
- u16 queue_index = 0;
+ u16 queue_index;
+ struct sock *sk = skb->sk;
- if (ops->ndo_select_queue)
- queue_index = ops->ndo_select_queue(dev, skb);
- else if (dev->real_num_tx_queues > 1)
- queue_index = skb_tx_hash(dev, skb);
+ if (sk_tx_queue_recorded(sk)) {
+ queue_index = sk_tx_queue_get(sk);
+ } else {
+ const struct net_device_ops *ops = dev->netdev_ops;
+
+ if (ops->ndo_select_queue) {
+ queue_index = ops->ndo_select_queue(dev, skb);
+ } else {
+ queue_index = 0;
+ if (dev->real_num_tx_queues > 1)
+ queue_index = skb_tx_hash(dev, skb);
+
+ if (sk && sk->sk_dst_cache)
+ sk_tx_queue_set(sk, queue_index);
+ }
+ }
skb_set_queue_mapping(skb, queue_index);
return netdev_get_tx_queue(dev, queue_index);
@@ -2291,7 +2300,7 @@ int netif_receive_skb(struct sk_buff *skb)
if (!skb->tstamp.tv64)
net_timestamp(skb);
- if (skb->vlan_tci && vlan_hwaccel_do_receive(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 */
@@ -2604,20 +2613,13 @@ EXPORT_SYMBOL(napi_reuse_skb);
struct sk_buff *napi_get_frags(struct napi_struct *napi)
{
- struct net_device *dev = napi->dev;
struct sk_buff *skb = napi->skb;
if (!skb) {
- skb = netdev_alloc_skb(dev, GRO_MAX_HEAD + NET_IP_ALIGN);
- if (!skb)
- goto out;
-
- skb_reserve(skb, NET_IP_ALIGN);
-
- napi->skb = skb;
+ skb = netdev_alloc_skb_ip_align(napi->dev, GRO_MAX_HEAD);
+ if (skb)
+ napi->skb = skb;
}
-
-out:
return skb;
}
EXPORT_SYMBOL(napi_get_frags);
@@ -4836,6 +4838,12 @@ int register_netdevice(struct net_device *dev)
dev->features |= NETIF_F_GSO;
netdev_initialize_kobject(dev);
+
+ ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev);
+ ret = notifier_to_errno(ret);
+ if (ret)
+ goto err_uninit;
+
ret = netdev_register_kobject(dev);
if (ret)
goto err_uninit;
@@ -5483,7 +5491,7 @@ unsigned long netdev_increment_features(unsigned long all, unsigned long one,
one |= NETIF_F_ALL_CSUM;
one |= all & NETIF_F_ONE_FOR_ALL;
- all &= one | NETIF_F_LLTX | NETIF_F_GSO;
+ all &= one | NETIF_F_LLTX | NETIF_F_GSO | NETIF_F_UFO;
all |= one & mask & NETIF_F_ONE_FOR_ALL;
return all;
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 4c12ddb5f5ee..d8aee584e8d1 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -198,13 +198,6 @@ static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr)
rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
if (rc >= 0)
info.n_priv_flags = rc;
- } else {
- /* code path for obsolete hooks */
-
- if (ops->self_test_count)
- info.testinfo_len = ops->self_test_count(dev);
- if (ops->get_stats_count)
- info.n_stats = ops->get_stats_count(dev);
}
if (ops->get_regs_len)
info.regdump_len = ops->get_regs_len(dev);
@@ -309,6 +302,26 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
return ret;
}
+static int ethtool_reset(struct net_device *dev, char __user *useraddr)
+{
+ struct ethtool_value reset;
+ int ret;
+
+ if (!dev->ethtool_ops->reset)
+ return -EOPNOTSUPP;
+
+ if (copy_from_user(&reset, useraddr, sizeof(reset)))
+ return -EFAULT;
+
+ ret = dev->ethtool_ops->reset(dev, &reset.data);
+ if (ret)
+ return ret;
+
+ if (copy_to_user(useraddr, &reset, sizeof(reset)))
+ return -EFAULT;
+ return 0;
+}
+
static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
{
struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
@@ -684,16 +697,10 @@ static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
u64 *data;
int ret, test_len;
- if (!ops->self_test)
- return -EOPNOTSUPP;
- if (!ops->get_sset_count && !ops->self_test_count)
+ if (!ops->self_test || !ops->get_sset_count)
return -EOPNOTSUPP;
- if (ops->get_sset_count)
- test_len = ops->get_sset_count(dev, ETH_SS_TEST);
- else
- /* code path for obsolete hook */
- test_len = ops->self_test_count(dev);
+ test_len = ops->get_sset_count(dev, ETH_SS_TEST);
if (test_len < 0)
return test_len;
WARN_ON(test_len == 0);
@@ -728,36 +735,17 @@ static int ethtool_get_strings(struct net_device *dev, void __user *useraddr)
u8 *data;
int ret;
- if (!ops->get_strings)
+ if (!ops->get_strings || !ops->get_sset_count)
return -EOPNOTSUPP;
if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
return -EFAULT;
- if (ops->get_sset_count) {
- ret = ops->get_sset_count(dev, gstrings.string_set);
- if (ret < 0)
- return ret;
-
- gstrings.len = ret;
- } else {
- /* code path for obsolete hooks */
-
- switch (gstrings.string_set) {
- case ETH_SS_TEST:
- if (!ops->self_test_count)
- return -EOPNOTSUPP;
- gstrings.len = ops->self_test_count(dev);
- break;
- case ETH_SS_STATS:
- if (!ops->get_stats_count)
- return -EOPNOTSUPP;
- gstrings.len = ops->get_stats_count(dev);
- break;
- default:
- return -EINVAL;
- }
- }
+ ret = ops->get_sset_count(dev, gstrings.string_set);
+ if (ret < 0)
+ return ret;
+
+ gstrings.len = ret;
data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
if (!data)
@@ -798,16 +786,10 @@ static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
u64 *data;
int ret, n_stats;
- if (!ops->get_ethtool_stats)
- return -EOPNOTSUPP;
- if (!ops->get_sset_count && !ops->get_stats_count)
+ if (!ops->get_ethtool_stats || !ops->get_sset_count)
return -EOPNOTSUPP;
- if (ops->get_sset_count)
- n_stats = ops->get_sset_count(dev, ETH_SS_STATS);
- else
- /* code path for obsolete hook */
- n_stats = ops->get_stats_count(dev);
+ n_stats = ops->get_sset_count(dev, ETH_SS_STATS);
if (n_stats < 0)
return n_stats;
WARN_ON(n_stats == 0);
@@ -1127,6 +1109,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
case ETHTOOL_FLASHDEV:
rc = ethtool_flash_device(dev, useraddr);
break;
+ case ETHTOOL_RESET:
+ rc = ethtool_reset(dev, useraddr);
+ break;
default:
rc = -EOPNOTSUPP;
}
diff --git a/net/core/filter.c b/net/core/filter.c
index d1d779ca096d..08db7b9143a3 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -303,6 +303,12 @@ load_b:
case SKF_AD_IFINDEX:
A = skb->dev->ifindex;
continue;
+ case SKF_AD_MARK:
+ A = skb->mark;
+ continue;
+ case SKF_AD_QUEUE:
+ A = skb->queue_mapping;
+ continue;
case SKF_AD_NLATTR: {
struct nlattr *nla;
diff --git a/net/core/gen_stats.c b/net/core/gen_stats.c
index 8569310268ab..393b1d8618e2 100644
--- a/net/core/gen_stats.c
+++ b/net/core/gen_stats.c
@@ -127,6 +127,7 @@ gnet_stats_copy_basic(struct gnet_dump *d, struct gnet_stats_basic_packed *b)
/**
* gnet_stats_copy_rate_est - copy rate estimator statistics into statistics TLV
* @d: dumping handle
+ * @b: basic statistics
* @r: rate estimator statistics
*
* Appends the rate estimator statistics to the top level TLV created by
@@ -136,8 +137,13 @@ gnet_stats_copy_basic(struct gnet_dump *d, struct gnet_stats_basic_packed *b)
* if the room in the socket buffer was not sufficient.
*/
int
-gnet_stats_copy_rate_est(struct gnet_dump *d, struct gnet_stats_rate_est *r)
+gnet_stats_copy_rate_est(struct gnet_dump *d,
+ const struct gnet_stats_basic_packed *b,
+ struct gnet_stats_rate_est *r)
{
+ if (b && !gen_estimator_active(b, r))
+ return 0;
+
if (d->compat_tc_stats) {
d->tc_stats.bps = r->bps;
d->tc_stats.pps = r->pps;
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 427ded841224..753c420060df 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -130,6 +130,44 @@ static ssize_t show_carrier(struct device *dev,
return -EINVAL;
}
+static ssize_t show_speed(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ int ret = -EINVAL;
+
+ if (!rtnl_trylock())
+ return restart_syscall();
+
+ if (netif_running(netdev) && netdev->ethtool_ops->get_settings) {
+ struct ethtool_cmd cmd = { ETHTOOL_GSET };
+
+ if (!netdev->ethtool_ops->get_settings(netdev, &cmd))
+ ret = sprintf(buf, fmt_dec, ethtool_cmd_speed(&cmd));
+ }
+ rtnl_unlock();
+ return ret;
+}
+
+static ssize_t show_duplex(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ int ret = -EINVAL;
+
+ if (!rtnl_trylock())
+ return restart_syscall();
+
+ if (netif_running(netdev) && netdev->ethtool_ops->get_settings) {
+ struct ethtool_cmd cmd = { ETHTOOL_GSET };
+
+ if (!netdev->ethtool_ops->get_settings(netdev, &cmd))
+ ret = sprintf(buf, "%s\n", cmd.duplex ? "full" : "half");
+ }
+ rtnl_unlock();
+ return ret;
+}
+
static ssize_t show_dormant(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -259,6 +297,8 @@ static struct device_attribute net_class_attributes[] = {
__ATTR(address, S_IRUGO, show_address, NULL),
__ATTR(broadcast, S_IRUGO, show_broadcast, NULL),
__ATTR(carrier, S_IRUGO, show_carrier, NULL),
+ __ATTR(speed, S_IRUGO, show_speed, NULL),
+ __ATTR(duplex, S_IRUGO, show_duplex, NULL),
__ATTR(dormant, S_IRUGO, show_dormant, NULL),
__ATTR(operstate, S_IRUGO, show_operstate, NULL),
__ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu),
@@ -503,9 +543,13 @@ int netdev_register_kobject(struct net_device *net)
*groups++ = &netstat_group;
#ifdef CONFIG_WIRELESS_EXT_SYSFS
- if (net->wireless_handlers || net->ieee80211_ptr)
+ if (net->ieee80211_ptr)
+ *groups++ = &wireless_group;
+#ifdef CONFIG_WIRELESS_EXT
+ else if (net->wireless_handlers)
*groups++ = &wireless_group;
#endif
+#endif
#endif /* CONFIG_SYSFS */
if (dev_net(net) != &init_net)
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 86acdba0a97d..5ce017bf4afa 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -335,6 +335,7 @@ struct pktgen_dev {
__u32 cur_src_mac_offset;
__be32 cur_saddr;
__be32 cur_daddr;
+ __u16 ip_id;
__u16 cur_udp_dst;
__u16 cur_udp_src;
__u16 cur_queue_map;
@@ -2630,6 +2631,8 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
iph->protocol = IPPROTO_UDP; /* UDP */
iph->saddr = pkt_dev->cur_saddr;
iph->daddr = pkt_dev->cur_daddr;
+ iph->id = htons(pkt_dev->ip_id);
+ pkt_dev->ip_id++;
iph->frag_off = 0;
iplen = 20 + 8 + datalen;
iph->tot_len = htons(iplen);
@@ -2641,24 +2644,26 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
skb->dev = odev;
skb->pkt_type = PACKET_HOST;
- if (pkt_dev->nfrags <= 0)
+ if (pkt_dev->nfrags <= 0) {
pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
- else {
+ memset(pgh + 1, 0, datalen - sizeof(struct pktgen_hdr));
+ } else {
int frags = pkt_dev->nfrags;
- int i;
+ int i, len;
pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8);
if (frags > MAX_SKB_FRAGS)
frags = MAX_SKB_FRAGS;
if (datalen > frags * PAGE_SIZE) {
- skb_put(skb, datalen - frags * PAGE_SIZE);
+ len = datalen - frags * PAGE_SIZE;
+ memset(skb_put(skb, len), 0, len);
datalen = frags * PAGE_SIZE;
}
i = 0;
while (datalen > 0) {
- struct page *page = alloc_pages(GFP_KERNEL, 0);
+ struct page *page = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0);
skb_shinfo(skb)->frags[i].page = page;
skb_shinfo(skb)->frags[i].page_offset = 0;
skb_shinfo(skb)->frags[i].size =
@@ -3441,12 +3446,14 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
txq = netdev_get_tx_queue(odev, queue_map);
__netif_tx_lock_bh(txq);
- atomic_inc(&(pkt_dev->skb->users));
- if (unlikely(netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq)))
+ if (unlikely(netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq))) {
ret = NETDEV_TX_BUSY;
- else
- ret = (*xmit)(pkt_dev->skb, odev);
+ pkt_dev->last_ok = 0;
+ goto unlock;
+ }
+ atomic_inc(&(pkt_dev->skb->users));
+ ret = (*xmit)(pkt_dev->skb, odev);
switch (ret) {
case NETDEV_TX_OK:
@@ -3468,6 +3475,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
atomic_dec(&(pkt_dev->skb->users));
pkt_dev->last_ok = 0;
}
+unlock:
__netif_tx_unlock_bh(txq);
/* If pkt_dev->count is zero, then run forever */
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index eb42873f2a3a..52ea418d5302 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -682,22 +682,33 @@ nla_put_failure:
static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
{
struct net *net = sock_net(skb->sk);
- int idx;
- int s_idx = cb->args[0];
+ int h, s_h;
+ int idx = 0, s_idx;
struct net_device *dev;
-
- idx = 0;
- for_each_netdev(net, dev) {
- if (idx < s_idx)
- goto cont;
- if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
- NETLINK_CB(cb->skb).pid,
- cb->nlh->nlmsg_seq, 0, NLM_F_MULTI) <= 0)
- break;
+ struct hlist_head *head;
+ struct hlist_node *node;
+
+ s_h = cb->args[0];
+ s_idx = cb->args[1];
+
+ for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
+ idx = 0;
+ head = &net->dev_index_head[h];
+ hlist_for_each_entry(dev, node, head, index_hlist) {
+ if (idx < s_idx)
+ goto cont;
+ if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
+ NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq, 0,
+ NLM_F_MULTI) <= 0)
+ goto out;
cont:
- idx++;
+ idx++;
+ }
}
- cb->args[0] = idx;
+out:
+ cb->args[1] = idx;
+ cb->args[0] = h;
return skb->len;
}
@@ -910,9 +921,9 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
err = -EINVAL;
ifm = nlmsg_data(nlh);
if (ifm->ifi_index > 0)
- dev = dev_get_by_index(net, ifm->ifi_index);
+ dev = __dev_get_by_index(net, ifm->ifi_index);
else if (tb[IFLA_IFNAME])
- dev = dev_get_by_name(net, ifname);
+ dev = __dev_get_by_name(net, ifname);
else
goto errout;
@@ -922,11 +933,9 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
}
if ((err = validate_linkmsg(dev, tb)) < 0)
- goto errout_dev;
+ goto errout;
err = do_setlink(dev, ifm, tb, ifname, 0);
-errout_dev:
- dev_put(dev);
errout:
return err;
}
@@ -1154,6 +1163,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
{
struct net *net = sock_net(skb->sk);
struct ifinfomsg *ifm;
+ char ifname[IFNAMSIZ];
struct nlattr *tb[IFLA_MAX+1];
struct net_device *dev = NULL;
struct sk_buff *nskb;
@@ -1163,19 +1173,23 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
if (err < 0)
return err;
+ if (tb[IFLA_IFNAME])
+ nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
+
ifm = nlmsg_data(nlh);
- if (ifm->ifi_index > 0) {
- dev = dev_get_by_index(net, ifm->ifi_index);
- if (dev == NULL)
- return -ENODEV;
- } else
+ if (ifm->ifi_index > 0)
+ dev = __dev_get_by_index(net, ifm->ifi_index);
+ else if (tb[IFLA_IFNAME])
+ dev = __dev_get_by_name(net, ifname);
+ else
return -EINVAL;
+ if (dev == NULL)
+ return -ENODEV;
+
nskb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL);
- if (nskb == NULL) {
- err = -ENOBUFS;
- goto errout;
- }
+ if (nskb == NULL)
+ return -ENOBUFS;
err = rtnl_fill_ifinfo(nskb, dev, RTM_NEWLINK, NETLINK_CB(skb).pid,
nlh->nlmsg_seq, 0, 0);
@@ -1183,11 +1197,8 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
/* -EMSGSIZE implies BUG in if_nlmsg_size */
WARN_ON(err == -EMSGSIZE);
kfree_skb(nskb);
- goto errout;
- }
- err = rtnl_unicast(nskb, net, NETLINK_CB(skb).pid);
-errout:
- dev_put(dev);
+ } else
+ err = rtnl_unicast(nskb, net, NETLINK_CB(skb).pid);
return err;
}
diff --git a/net/core/sock.c b/net/core/sock.c
index 7626b6aacd68..5a51512f638a 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -274,25 +274,27 @@ static void sock_disable_timestamp(struct sock *sk, int flag)
int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
- int err = 0;
+ int err;
int skb_len;
+ unsigned long flags;
+ struct sk_buff_head *list = &sk->sk_receive_queue;
/* Cast sk->rcvbuf to unsigned... It's pointless, but reduces
number of warnings when compiling with -W --ANK
*/
if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
(unsigned)sk->sk_rcvbuf) {
- err = -ENOMEM;
- goto out;
+ atomic_inc(&sk->sk_drops);
+ return -ENOMEM;
}
err = sk_filter(sk, skb);
if (err)
- goto out;
+ return err;
if (!sk_rmem_schedule(sk, skb->truesize)) {
- err = -ENOBUFS;
- goto out;
+ atomic_inc(&sk->sk_drops);
+ return -ENOBUFS;
}
skb->dev = NULL;
@@ -305,12 +307,14 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
*/
skb_len = skb->len;
- skb_queue_tail(&sk->sk_receive_queue, skb);
+ spin_lock_irqsave(&list->lock, flags);
+ skb->dropcount = atomic_read(&sk->sk_drops);
+ __skb_queue_tail(list, skb);
+ spin_unlock_irqrestore(&list->lock, flags);
if (!sock_flag(sk, SOCK_DEAD))
sk->sk_data_ready(sk, skb_len);
-out:
- return err;
+ return 0;
}
EXPORT_SYMBOL(sock_queue_rcv_skb);
@@ -348,11 +352,18 @@ discard_and_relse:
}
EXPORT_SYMBOL(sk_receive_skb);
+void sk_reset_txq(struct sock *sk)
+{
+ sk_tx_queue_clear(sk);
+}
+EXPORT_SYMBOL(sk_reset_txq);
+
struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie)
{
struct dst_entry *dst = sk->sk_dst_cache;
if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) {
+ sk_tx_queue_clear(sk);
sk->sk_dst_cache = NULL;
dst_release(dst);
return NULL;
@@ -702,6 +713,12 @@ set_rcvbuf:
/* We implement the SO_SNDLOWAT etc to
not be settable (1003.1g 5.3) */
+ case SO_RXQ_OVFL:
+ if (valbool)
+ sock_set_flag(sk, SOCK_RXQ_OVFL);
+ else
+ sock_reset_flag(sk, SOCK_RXQ_OVFL);
+ break;
default:
ret = -ENOPROTOOPT;
break;
@@ -901,6 +918,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
v.val = sk->sk_mark;
break;
+ case SO_RXQ_OVFL:
+ v.val = !!sock_flag(sk, SOCK_RXQ_OVFL);
+ break;
+
default:
return -ENOPROTOOPT;
}
@@ -939,7 +960,8 @@ static void sock_copy(struct sock *nsk, const struct sock *osk)
void *sptr = nsk->sk_security;
#endif
BUILD_BUG_ON(offsetof(struct sock, sk_copy_start) !=
- sizeof(osk->sk_node) + sizeof(osk->sk_refcnt));
+ sizeof(osk->sk_node) + sizeof(osk->sk_refcnt) +
+ sizeof(osk->sk_tx_queue_mapping));
memcpy(&nsk->sk_copy_start, &osk->sk_copy_start,
osk->sk_prot->obj_size - offsetof(struct sock, sk_copy_start));
#ifdef CONFIG_SECURITY_NETWORK
@@ -983,6 +1005,7 @@ static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority,
if (!try_module_get(prot->owner))
goto out_free_sec;
+ sk_tx_queue_clear(sk);
}
return sk;
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 7db1de0497c6..887c03c4e3c6 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -10,7 +10,9 @@
#include <linux/module.h>
#include <linux/socket.h>
#include <linux/netdevice.h>
+#include <linux/ratelimit.h>
#include <linux/init.h>
+
#include <net/ip.h>
#include <net/sock.h>
diff --git a/net/core/utils.c b/net/core/utils.c
index 83221aee7084..838250241d26 100644
--- a/net/core/utils.c
+++ b/net/core/utils.c
@@ -24,6 +24,8 @@
#include <linux/types.h>
#include <linux/percpu.h>
#include <linux/init.h>
+#include <linux/ratelimit.h>
+
#include <net/sock.h>
#include <asm/byteorder.h>
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c
index e8cf99e880b0..a47a8c918ee8 100644
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -33,20 +33,20 @@
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 *hctx)
+static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hc)
{
int len = 0;
int pipe = 0;
- struct ccid2_seq *seqp = hctx->ccid2hctx_seqh;
+ struct ccid2_seq *seqp = hc->tx_seqh;
/* there is data in the chain */
- if (seqp != hctx->ccid2hctx_seqt) {
+ if (seqp != hc->tx_seqt) {
seqp = seqp->ccid2s_prev;
len++;
if (!seqp->ccid2s_acked)
pipe++;
- while (seqp != hctx->ccid2hctx_seqt) {
+ while (seqp != hc->tx_seqt) {
struct ccid2_seq *prev = seqp->ccid2s_prev;
len++;
@@ -63,30 +63,30 @@ static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx)
}
}
- BUG_ON(pipe != hctx->ccid2hctx_pipe);
+ BUG_ON(pipe != hc->tx_pipe);
ccid2_pr_debug("len of chain=%d\n", len);
do {
seqp = seqp->ccid2s_prev;
len++;
- } while (seqp != hctx->ccid2hctx_seqh);
+ } while (seqp != hc->tx_seqh);
ccid2_pr_debug("total len=%d\n", len);
- BUG_ON(len != hctx->ccid2hctx_seqbufc * CCID2_SEQBUF_LEN);
+ BUG_ON(len != hc->tx_seqbufc * CCID2_SEQBUF_LEN);
}
#else
#define ccid2_pr_debug(format, a...)
-#define ccid2_hc_tx_check_sanity(hctx)
+#define ccid2_hc_tx_check_sanity(hc)
#endif
-static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hctx)
+static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hc)
{
struct ccid2_seq *seqp;
int i;
/* check if we have space to preserve the pointer to the buffer */
- if (hctx->ccid2hctx_seqbufc >= (sizeof(hctx->ccid2hctx_seqbuf) /
- sizeof(struct ccid2_seq*)))
+ if (hc->tx_seqbufc >= (sizeof(hc->tx_seqbuf) /
+ sizeof(struct ccid2_seq *)))
return -ENOMEM;
/* allocate buffer and initialize linked list */
@@ -102,29 +102,29 @@ static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hctx)
seqp->ccid2s_prev = &seqp[CCID2_SEQBUF_LEN - 1];
/* This is the first allocation. Initiate the head and tail. */
- if (hctx->ccid2hctx_seqbufc == 0)
- hctx->ccid2hctx_seqh = hctx->ccid2hctx_seqt = seqp;
+ if (hc->tx_seqbufc == 0)
+ hc->tx_seqh = hc->tx_seqt = seqp;
else {
/* link the existing list with the one we just created */
- hctx->ccid2hctx_seqh->ccid2s_next = seqp;
- seqp->ccid2s_prev = hctx->ccid2hctx_seqh;
+ hc->tx_seqh->ccid2s_next = seqp;
+ seqp->ccid2s_prev = hc->tx_seqh;
- hctx->ccid2hctx_seqt->ccid2s_prev = &seqp[CCID2_SEQBUF_LEN - 1];
- seqp[CCID2_SEQBUF_LEN - 1].ccid2s_next = hctx->ccid2hctx_seqt;
+ hc->tx_seqt->ccid2s_prev = &seqp[CCID2_SEQBUF_LEN - 1];
+ seqp[CCID2_SEQBUF_LEN - 1].ccid2s_next = hc->tx_seqt;
}
/* store the original pointer to the buffer so we can free it */
- hctx->ccid2hctx_seqbuf[hctx->ccid2hctx_seqbufc] = seqp;
- hctx->ccid2hctx_seqbufc++;
+ hc->tx_seqbuf[hc->tx_seqbufc] = seqp;
+ hc->tx_seqbufc++;
return 0;
}
static int ccid2_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
{
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
- if (hctx->ccid2hctx_pipe < hctx->ccid2hctx_cwnd)
+ if (hc->tx_pipe < hc->tx_cwnd)
return 0;
return 1; /* XXX CCID should dequeue when ready instead of polling */
@@ -133,7 +133,7 @@ static int ccid2_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val)
{
struct dccp_sock *dp = dccp_sk(sk);
- u32 max_ratio = DIV_ROUND_UP(ccid2_hc_tx_sk(sk)->ccid2hctx_cwnd, 2);
+ u32 max_ratio = DIV_ROUND_UP(ccid2_hc_tx_sk(sk)->tx_cwnd, 2);
/*
* Ensure that Ack Ratio does not exceed ceil(cwnd/2), which is (2) from
@@ -155,10 +155,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 *hctx, long val)
+static void ccid2_change_srtt(struct ccid2_hc_tx_sock *hc, long val)
{
ccid2_pr_debug("change SRTT to %ld\n", val);
- hctx->ccid2hctx_srtt = val;
+ hc->tx_srtt = val;
}
static void ccid2_start_rto_timer(struct sock *sk);
@@ -166,45 +166,44 @@ 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 *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
long s;
bh_lock_sock(sk);
if (sock_owned_by_user(sk)) {
- sk_reset_timer(sk, &hctx->ccid2hctx_rtotimer,
- jiffies + HZ / 5);
+ sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + HZ / 5);
goto out;
}
ccid2_pr_debug("RTO_EXPIRE\n");
- ccid2_hc_tx_check_sanity(hctx);
+ ccid2_hc_tx_check_sanity(hc);
/* back-off timer */
- hctx->ccid2hctx_rto <<= 1;
+ hc->tx_rto <<= 1;
- s = hctx->ccid2hctx_rto / HZ;
+ s = hc->tx_rto / HZ;
if (s > 60)
- hctx->ccid2hctx_rto = 60 * HZ;
+ hc->tx_rto = 60 * HZ;
ccid2_start_rto_timer(sk);
/* adjust pipe, cwnd etc */
- hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd / 2;
- if (hctx->ccid2hctx_ssthresh < 2)
- hctx->ccid2hctx_ssthresh = 2;
- hctx->ccid2hctx_cwnd = 1;
- hctx->ccid2hctx_pipe = 0;
+ hc->tx_ssthresh = hc->tx_cwnd / 2;
+ if (hc->tx_ssthresh < 2)
+ hc->tx_ssthresh = 2;
+ hc->tx_cwnd = 1;
+ hc->tx_pipe = 0;
/* clear state about stuff we sent */
- hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqh;
- hctx->ccid2hctx_packets_acked = 0;
+ hc->tx_seqt = hc->tx_seqh;
+ hc->tx_packets_acked = 0;
/* clear ack ratio state. */
- hctx->ccid2hctx_rpseq = 0;
- hctx->ccid2hctx_rpdupack = -1;
+ hc->tx_rpseq = 0;
+ hc->tx_rpdupack = -1;
ccid2_change_l_ack_ratio(sk, 1);
- ccid2_hc_tx_check_sanity(hctx);
+ ccid2_hc_tx_check_sanity(hc);
out:
bh_unlock_sock(sk);
sock_put(sk);
@@ -212,42 +211,40 @@ out:
static void ccid2_start_rto_timer(struct sock *sk)
{
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
- ccid2_pr_debug("setting RTO timeout=%ld\n", hctx->ccid2hctx_rto);
+ ccid2_pr_debug("setting RTO timeout=%ld\n", hc->tx_rto);
- BUG_ON(timer_pending(&hctx->ccid2hctx_rtotimer));
- sk_reset_timer(sk, &hctx->ccid2hctx_rtotimer,
- jiffies + hctx->ccid2hctx_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)
{
struct dccp_sock *dp = dccp_sk(sk);
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
struct ccid2_seq *next;
- hctx->ccid2hctx_pipe++;
+ hc->tx_pipe++;
- hctx->ccid2hctx_seqh->ccid2s_seq = dp->dccps_gss;
- hctx->ccid2hctx_seqh->ccid2s_acked = 0;
- hctx->ccid2hctx_seqh->ccid2s_sent = jiffies;
+ hc->tx_seqh->ccid2s_seq = dp->dccps_gss;
+ hc->tx_seqh->ccid2s_acked = 0;
+ hc->tx_seqh->ccid2s_sent = jiffies;
- next = hctx->ccid2hctx_seqh->ccid2s_next;
+ next = hc->tx_seqh->ccid2s_next;
/* check if we need to alloc more space */
- if (next == hctx->ccid2hctx_seqt) {
- if (ccid2_hc_tx_alloc_seq(hctx)) {
+ if (next == hc->tx_seqt) {
+ if (ccid2_hc_tx_alloc_seq(hc)) {
DCCP_CRIT("packet history - out of memory!");
/* FIXME: find a more graceful way to bail out */
return;
}
- next = hctx->ccid2hctx_seqh->ccid2s_next;
- BUG_ON(next == hctx->ccid2hctx_seqt);
+ next = hc->tx_seqh->ccid2s_next;
+ BUG_ON(next == hc->tx_seqt);
}
- hctx->ccid2hctx_seqh = next;
+ hc->tx_seqh = next;
- ccid2_pr_debug("cwnd=%d pipe=%d\n", hctx->ccid2hctx_cwnd,
- hctx->ccid2hctx_pipe);
+ ccid2_pr_debug("cwnd=%d pipe=%d\n", hc->tx_cwnd, hc->tx_pipe);
/*
* FIXME: The code below is broken and the variables have been removed
@@ -270,12 +267,12 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len)
*/
#if 0
/* Ack Ratio. Need to maintain a concept of how many windows we sent */
- hctx->ccid2hctx_arsent++;
+ hc->tx_arsent++;
/* We had an ack loss in this window... */
- if (hctx->ccid2hctx_ackloss) {
- if (hctx->ccid2hctx_arsent >= hctx->ccid2hctx_cwnd) {
- hctx->ccid2hctx_arsent = 0;
- hctx->ccid2hctx_ackloss = 0;
+ if (hc->tx_ackloss) {
+ if (hc->tx_arsent >= hc->tx_cwnd) {
+ hc->tx_arsent = 0;
+ hc->tx_ackloss = 0;
}
} else {
/* No acks lost up to now... */
@@ -285,28 +282,28 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len)
int denom = dp->dccps_l_ack_ratio * dp->dccps_l_ack_ratio -
dp->dccps_l_ack_ratio;
- denom = hctx->ccid2hctx_cwnd * hctx->ccid2hctx_cwnd / denom;
+ denom = hc->tx_cwnd * hc->tx_cwnd / denom;
- if (hctx->ccid2hctx_arsent >= denom) {
+ if (hc->tx_arsent >= denom) {
ccid2_change_l_ack_ratio(sk, dp->dccps_l_ack_ratio - 1);
- hctx->ccid2hctx_arsent = 0;
+ hc->tx_arsent = 0;
}
} else {
/* we can't increase ack ratio further [1] */
- hctx->ccid2hctx_arsent = 0; /* or maybe set it to cwnd*/
+ hc->tx_arsent = 0; /* or maybe set it to cwnd*/
}
}
#endif
/* setup RTO timer */
- if (!timer_pending(&hctx->ccid2hctx_rtotimer))
+ if (!timer_pending(&hc->tx_rtotimer))
ccid2_start_rto_timer(sk);
#ifdef CONFIG_IP_DCCP_CCID2_DEBUG
do {
- struct ccid2_seq *seqp = hctx->ccid2hctx_seqt;
+ struct ccid2_seq *seqp = hc->tx_seqt;
- while (seqp != hctx->ccid2hctx_seqh) {
+ while (seqp != hc->tx_seqh) {
ccid2_pr_debug("out seq=%llu acked=%d time=%lu\n",
(unsigned long long)seqp->ccid2s_seq,
seqp->ccid2s_acked, seqp->ccid2s_sent);
@@ -314,7 +311,7 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len)
}
} while (0);
ccid2_pr_debug("=========\n");
- ccid2_hc_tx_check_sanity(hctx);
+ ccid2_hc_tx_check_sanity(hc);
#endif
}
@@ -382,9 +379,9 @@ out_invalid_option:
static void ccid2_hc_tx_kill_rto_timer(struct sock *sk)
{
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
- sk_stop_timer(sk, &hctx->ccid2hctx_rtotimer);
+ sk_stop_timer(sk, &hc->tx_rtotimer);
ccid2_pr_debug("deleted RTO timer\n");
}
@@ -392,75 +389,75 @@ static inline void ccid2_new_ack(struct sock *sk,
struct ccid2_seq *seqp,
unsigned int *maxincr)
{
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
- if (hctx->ccid2hctx_cwnd < hctx->ccid2hctx_ssthresh) {
- if (*maxincr > 0 && ++hctx->ccid2hctx_packets_acked == 2) {
- hctx->ccid2hctx_cwnd += 1;
- *maxincr -= 1;
- hctx->ccid2hctx_packets_acked = 0;
+ if (hc->tx_cwnd < hc->tx_ssthresh) {
+ if (*maxincr > 0 && ++hc->tx_packets_acked == 2) {
+ hc->tx_cwnd += 1;
+ *maxincr -= 1;
+ hc->tx_packets_acked = 0;
}
- } else if (++hctx->ccid2hctx_packets_acked >= hctx->ccid2hctx_cwnd) {
- hctx->ccid2hctx_cwnd += 1;
- hctx->ccid2hctx_packets_acked = 0;
+ } else if (++hc->tx_packets_acked >= hc->tx_cwnd) {
+ hc->tx_cwnd += 1;
+ hc->tx_packets_acked = 0;
}
/* update RTO */
- if (hctx->ccid2hctx_srtt == -1 ||
- time_after(jiffies, hctx->ccid2hctx_lastrtt + hctx->ccid2hctx_srtt)) {
+ 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 (hctx->ccid2hctx_srtt == -1) {
+ 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(hctx, r);
- hctx->ccid2hctx_rttvar = r >> 1;
+ ccid2_change_srtt(hc, r);
+ hc->tx_rttvar = r >> 1;
} else {
/* RTTVAR */
- long tmp = hctx->ccid2hctx_srtt - r;
+ long tmp = hc->tx_srtt - r;
long srtt;
if (tmp < 0)
tmp *= -1;
tmp >>= 2;
- hctx->ccid2hctx_rttvar *= 3;
- hctx->ccid2hctx_rttvar >>= 2;
- hctx->ccid2hctx_rttvar += tmp;
+ hc->tx_rttvar *= 3;
+ hc->tx_rttvar >>= 2;
+ hc->tx_rttvar += tmp;
/* SRTT */
- srtt = hctx->ccid2hctx_srtt;
+ srtt = hc->tx_srtt;
srtt *= 7;
srtt >>= 3;
tmp = r >> 3;
srtt += tmp;
- ccid2_change_srtt(hctx, srtt);
+ ccid2_change_srtt(hc, srtt);
}
- s = hctx->ccid2hctx_rttvar << 2;
+ s = hc->tx_rttvar << 2;
/* clock granularity is 1 when based on jiffies */
if (!s)
s = 1;
- hctx->ccid2hctx_rto = hctx->ccid2hctx_srtt + s;
+ hc->tx_rto = hc->tx_srtt + s;
/* must be at least a second */
- s = hctx->ccid2hctx_rto / HZ;
+ s = hc->tx_rto / HZ;
/* DCCP doesn't require this [but I like it cuz my code sux] */
#if 1
if (s < 1)
- hctx->ccid2hctx_rto = HZ;
+ hc->tx_rto = HZ;
#endif
/* max 60 seconds */
if (s > 60)
- hctx->ccid2hctx_rto = HZ * 60;
+ hc->tx_rto = HZ * 60;
- hctx->ccid2hctx_lastrtt = jiffies;
+ hc->tx_lastrtt = jiffies;
ccid2_pr_debug("srtt: %ld rttvar: %ld rto: %ld (HZ=%d) R=%lu\n",
- hctx->ccid2hctx_srtt, hctx->ccid2hctx_rttvar,
- hctx->ccid2hctx_rto, HZ, r);
+ hc->tx_srtt, hc->tx_rttvar,
+ hc->tx_rto, HZ, r);
}
/* we got a new ack, so re-start RTO timer */
@@ -470,40 +467,40 @@ static inline void ccid2_new_ack(struct sock *sk,
static void ccid2_hc_tx_dec_pipe(struct sock *sk)
{
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
- if (hctx->ccid2hctx_pipe == 0)
+ if (hc->tx_pipe == 0)
DCCP_BUG("pipe == 0");
else
- hctx->ccid2hctx_pipe--;
+ hc->tx_pipe--;
- if (hctx->ccid2hctx_pipe == 0)
+ if (hc->tx_pipe == 0)
ccid2_hc_tx_kill_rto_timer(sk);
}
static void ccid2_congestion_event(struct sock *sk, struct ccid2_seq *seqp)
{
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
- if (time_before(seqp->ccid2s_sent, hctx->ccid2hctx_last_cong)) {
+ if (time_before(seqp->ccid2s_sent, hc->tx_last_cong)) {
ccid2_pr_debug("Multiple losses in an RTT---treating as one\n");
return;
}
- hctx->ccid2hctx_last_cong = jiffies;
+ hc->tx_last_cong = jiffies;
- hctx->ccid2hctx_cwnd = hctx->ccid2hctx_cwnd / 2 ? : 1U;
- hctx->ccid2hctx_ssthresh = max(hctx->ccid2hctx_cwnd, 2U);
+ hc->tx_cwnd = hc->tx_cwnd / 2 ? : 1U;
+ hc->tx_ssthresh = max(hc->tx_cwnd, 2U);
/* Avoid spurious timeouts resulting from Ack Ratio > cwnd */
- if (dccp_sk(sk)->dccps_l_ack_ratio > hctx->ccid2hctx_cwnd)
- ccid2_change_l_ack_ratio(sk, hctx->ccid2hctx_cwnd);
+ if (dccp_sk(sk)->dccps_l_ack_ratio > hc->tx_cwnd)
+ ccid2_change_l_ack_ratio(sk, hc->tx_cwnd);
}
static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
{
struct dccp_sock *dp = dccp_sk(sk);
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
u64 ackno, seqno;
struct ccid2_seq *seqp;
unsigned char *vector;
@@ -512,7 +509,7 @@ 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(hctx);
+ ccid2_hc_tx_check_sanity(hc);
/* check reverse path congestion */
seqno = DCCP_SKB_CB(skb)->dccpd_seq;
@@ -521,21 +518,21 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
* -sorbo.
*/
/* need to bootstrap */
- if (hctx->ccid2hctx_rpdupack == -1) {
- hctx->ccid2hctx_rpdupack = 0;
- hctx->ccid2hctx_rpseq = seqno;
+ if (hc->tx_rpdupack == -1) {
+ hc->tx_rpdupack = 0;
+ hc->tx_rpseq = seqno;
} else {
/* check if packet is consecutive */
- if (dccp_delta_seqno(hctx->ccid2hctx_rpseq, seqno) == 1)
- hctx->ccid2hctx_rpseq = seqno;
+ if (dccp_delta_seqno(hc->tx_rpseq, seqno) == 1)
+ hc->tx_rpseq = seqno;
/* it's a later packet */
- else if (after48(seqno, hctx->ccid2hctx_rpseq)) {
- hctx->ccid2hctx_rpdupack++;
+ else if (after48(seqno, hc->tx_rpseq)) {
+ hc->tx_rpdupack++;
/* check if we got enough dupacks */
- if (hctx->ccid2hctx_rpdupack >= NUMDUPACK) {
- hctx->ccid2hctx_rpdupack = -1; /* XXX lame */
- hctx->ccid2hctx_rpseq = 0;
+ if (hc->tx_rpdupack >= NUMDUPACK) {
+ hc->tx_rpdupack = -1; /* XXX lame */
+ hc->tx_rpseq = 0;
ccid2_change_l_ack_ratio(sk, 2 * dp->dccps_l_ack_ratio);
}
@@ -544,7 +541,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
/* check forward path congestion */
/* still didn't send out new data packets */
- if (hctx->ccid2hctx_seqh == hctx->ccid2hctx_seqt)
+ if (hc->tx_seqh == hc->tx_seqt)
return;
switch (DCCP_SKB_CB(skb)->dccpd_type) {
@@ -556,14 +553,14 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
}
ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq;
- if (after48(ackno, hctx->ccid2hctx_high_ack))
- hctx->ccid2hctx_high_ack = ackno;
+ if (after48(ackno, hc->tx_high_ack))
+ hc->tx_high_ack = ackno;
- seqp = hctx->ccid2hctx_seqt;
+ seqp = hc->tx_seqt;
while (before48(seqp->ccid2s_seq, ackno)) {
seqp = seqp->ccid2s_next;
- if (seqp == hctx->ccid2hctx_seqh) {
- seqp = hctx->ccid2hctx_seqh->ccid2s_prev;
+ if (seqp == hc->tx_seqh) {
+ seqp = hc->tx_seqh->ccid2s_prev;
break;
}
}
@@ -573,7 +570,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
* packets per acknowledgement. Rounding up avoids that cwnd is not
* advanced when Ack Ratio is 1 and gives a slight edge otherwise.
*/
- if (hctx->ccid2hctx_cwnd < hctx->ccid2hctx_ssthresh)
+ if (hc->tx_cwnd < hc->tx_ssthresh)
maxincr = DIV_ROUND_UP(dp->dccps_l_ack_ratio, 2);
/* go through all ack vectors */
@@ -592,7 +589,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
* seqnos.
*/
while (after48(seqp->ccid2s_seq, ackno)) {
- if (seqp == hctx->ccid2hctx_seqt) {
+ if (seqp == hc->tx_seqt) {
done = 1;
break;
}
@@ -624,7 +621,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
(unsigned long long)seqp->ccid2s_seq);
ccid2_hc_tx_dec_pipe(sk);
}
- if (seqp == hctx->ccid2hctx_seqt) {
+ if (seqp == hc->tx_seqt) {
done = 1;
break;
}
@@ -643,11 +640,11 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
/* The state about what is acked should be correct now
* Check for NUMDUPACK
*/
- seqp = hctx->ccid2hctx_seqt;
- while (before48(seqp->ccid2s_seq, hctx->ccid2hctx_high_ack)) {
+ seqp = hc->tx_seqt;
+ while (before48(seqp->ccid2s_seq, hc->tx_high_ack)) {
seqp = seqp->ccid2s_next;
- if (seqp == hctx->ccid2hctx_seqh) {
- seqp = hctx->ccid2hctx_seqh->ccid2s_prev;
+ if (seqp == hc->tx_seqh) {
+ seqp = hc->tx_seqh->ccid2s_prev;
break;
}
}
@@ -658,7 +655,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
if (done == NUMDUPACK)
break;
}
- if (seqp == hctx->ccid2hctx_seqt)
+ if (seqp == hc->tx_seqt)
break;
seqp = seqp->ccid2s_prev;
}
@@ -681,86 +678,86 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
ccid2_congestion_event(sk, seqp);
ccid2_hc_tx_dec_pipe(sk);
}
- if (seqp == hctx->ccid2hctx_seqt)
+ if (seqp == hc->tx_seqt)
break;
seqp = seqp->ccid2s_prev;
}
- hctx->ccid2hctx_seqt = last_acked;
+ hc->tx_seqt = last_acked;
}
/* trim acked packets in tail */
- while (hctx->ccid2hctx_seqt != hctx->ccid2hctx_seqh) {
- if (!hctx->ccid2hctx_seqt->ccid2s_acked)
+ while (hc->tx_seqt != hc->tx_seqh) {
+ if (!hc->tx_seqt->ccid2s_acked)
break;
- hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqt->ccid2s_next;
+ hc->tx_seqt = hc->tx_seqt->ccid2s_next;
}
- ccid2_hc_tx_check_sanity(hctx);
+ ccid2_hc_tx_check_sanity(hc);
}
static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
{
- struct ccid2_hc_tx_sock *hctx = ccid_priv(ccid);
+ struct ccid2_hc_tx_sock *hc = ccid_priv(ccid);
struct dccp_sock *dp = dccp_sk(sk);
u32 max_ratio;
/* RFC 4341, 5: initialise ssthresh to arbitrarily high (max) value */
- hctx->ccid2hctx_ssthresh = ~0U;
+ 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.
*/
- hctx->ccid2hctx_cwnd = clamp(4380U / dp->dccps_mss_cache, 2U, 4U);
+ hc->tx_cwnd = clamp(4380U / dp->dccps_mss_cache, 2U, 4U);
/* Make sure that Ack Ratio is enabled and within bounds. */
- max_ratio = DIV_ROUND_UP(hctx->ccid2hctx_cwnd, 2);
+ max_ratio = DIV_ROUND_UP(hc->tx_cwnd, 2);
if (dp->dccps_l_ack_ratio == 0 || dp->dccps_l_ack_ratio > max_ratio)
dp->dccps_l_ack_ratio = max_ratio;
/* XXX init ~ to window size... */
- if (ccid2_hc_tx_alloc_seq(hctx))
+ if (ccid2_hc_tx_alloc_seq(hc))
return -ENOMEM;
- hctx->ccid2hctx_rto = 3 * HZ;
- ccid2_change_srtt(hctx, -1);
- hctx->ccid2hctx_rttvar = -1;
- hctx->ccid2hctx_rpdupack = -1;
- hctx->ccid2hctx_last_cong = jiffies;
- setup_timer(&hctx->ccid2hctx_rtotimer, ccid2_hc_tx_rto_expire,
+ hc->tx_rto = 3 * HZ;
+ ccid2_change_srtt(hc, -1);
+ hc->tx_rttvar = -1;
+ hc->tx_rpdupack = -1;
+ hc->tx_last_cong = jiffies;
+ setup_timer(&hc->tx_rtotimer, ccid2_hc_tx_rto_expire,
(unsigned long)sk);
- ccid2_hc_tx_check_sanity(hctx);
+ ccid2_hc_tx_check_sanity(hc);
return 0;
}
static void ccid2_hc_tx_exit(struct sock *sk)
{
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
int i;
ccid2_hc_tx_kill_rto_timer(sk);
- for (i = 0; i < hctx->ccid2hctx_seqbufc; i++)
- kfree(hctx->ccid2hctx_seqbuf[i]);
- hctx->ccid2hctx_seqbufc = 0;
+ for (i = 0; i < hc->tx_seqbufc; i++)
+ kfree(hc->tx_seqbuf[i]);
+ hc->tx_seqbufc = 0;
}
static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
{
const struct dccp_sock *dp = dccp_sk(sk);
- struct ccid2_hc_rx_sock *hcrx = ccid2_hc_rx_sk(sk);
+ struct ccid2_hc_rx_sock *hc = ccid2_hc_rx_sk(sk);
switch (DCCP_SKB_CB(skb)->dccpd_type) {
case DCCP_PKT_DATA:
case DCCP_PKT_DATAACK:
- hcrx->ccid2hcrx_data++;
- if (hcrx->ccid2hcrx_data >= dp->dccps_r_ack_ratio) {
+ hc->rx_data++;
+ if (hc->rx_data >= dp->dccps_r_ack_ratio) {
dccp_send_ack(sk);
- hcrx->ccid2hcrx_data = 0;
+ hc->rx_data = 0;
}
break;
}
diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h
index 326ac90fb909..1ec6a30103bb 100644
--- a/net/dccp/ccids/ccid2.h
+++ b/net/dccp/ccids/ccid2.h
@@ -40,34 +40,34 @@ struct ccid2_seq {
/**
* struct ccid2_hc_tx_sock - CCID2 TX half connection
- * @ccid2hctx_{cwnd,ssthresh,pipe}: as per RFC 4341, section 5
- * @ccid2hctx_packets_acked - Ack counter for deriving cwnd growth (RFC 3465)
- * @ccid2hctx_lastrtt -time RTT was last measured
- * @ccid2hctx_rpseq - last consecutive seqno
- * @ccid2hctx_rpdupack - dupacks since rpseq
+ * @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_rpseq: last consecutive seqno
+ * @tx_rpdupack: dupacks since rpseq
*/
struct ccid2_hc_tx_sock {
- u32 ccid2hctx_cwnd;
- u32 ccid2hctx_ssthresh;
- u32 ccid2hctx_pipe;
- u32 ccid2hctx_packets_acked;
- struct ccid2_seq *ccid2hctx_seqbuf[CCID2_SEQBUF_MAX];
- int ccid2hctx_seqbufc;
- struct ccid2_seq *ccid2hctx_seqh;
- struct ccid2_seq *ccid2hctx_seqt;
- long ccid2hctx_rto;
- long ccid2hctx_srtt;
- long ccid2hctx_rttvar;
- unsigned long ccid2hctx_lastrtt;
- struct timer_list ccid2hctx_rtotimer;
- u64 ccid2hctx_rpseq;
- int ccid2hctx_rpdupack;
- unsigned long ccid2hctx_last_cong;
- u64 ccid2hctx_high_ack;
+ u32 tx_cwnd;
+ u32 tx_ssthresh;
+ u32 tx_pipe;
+ u32 tx_packets_acked;
+ struct ccid2_seq *tx_seqbuf[CCID2_SEQBUF_MAX];
+ 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;
+ struct timer_list tx_rtotimer;
+ u64 tx_rpseq;
+ int tx_rpdupack;
+ unsigned long tx_last_cong;
+ u64 tx_high_ack;
};
struct ccid2_hc_rx_sock {
- int ccid2hcrx_data;
+ int rx_data;
};
static inline struct ccid2_hc_tx_sock *ccid2_hc_tx_sk(const struct sock *sk)
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
index 34dcc798c457..bcd7632299f5 100644
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -64,14 +64,14 @@ static const char *ccid3_tx_state_name(enum ccid3_hc_tx_states state)
static void ccid3_hc_tx_set_state(struct sock *sk,
enum ccid3_hc_tx_states state)
{
- struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
- enum ccid3_hc_tx_states oldstate = hctx->ccid3hctx_state;
+ struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
+ enum ccid3_hc_tx_states oldstate = hc->tx_state;
ccid3_pr_debug("%s(%p) %-8.8s -> %s\n",
dccp_role(sk), sk, ccid3_tx_state_name(oldstate),
ccid3_tx_state_name(state));
WARN_ON(state == oldstate);
- hctx->ccid3hctx_state = state;
+ hc->tx_state = state;
}
/*
@@ -85,37 +85,32 @@ static void ccid3_hc_tx_set_state(struct sock *sk,
*/
static inline u64 rfc3390_initial_rate(struct sock *sk)
{
- const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
- const __u32 w_init = clamp_t(__u32, 4380U,
- 2 * hctx->ccid3hctx_s, 4 * hctx->ccid3hctx_s);
+ const struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
+ const __u32 w_init = clamp_t(__u32, 4380U, 2 * hc->tx_s, 4 * hc->tx_s);
- return scaled_div(w_init << 6, hctx->ccid3hctx_rtt);
+ return scaled_div(w_init << 6, hc->tx_rtt);
}
/*
* Recalculate t_ipi and delta (should be called whenever X changes)
*/
-static void ccid3_update_send_interval(struct ccid3_hc_tx_sock *hctx)
+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) */
- hctx->ccid3hctx_t_ipi = scaled_div32(((u64)hctx->ccid3hctx_s) << 6,
- hctx->ccid3hctx_x);
+ 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) */
- hctx->ccid3hctx_delta = min_t(u32, hctx->ccid3hctx_t_ipi / 2,
- TFRC_OPSYS_HALF_TIME_GRAN);
-
- ccid3_pr_debug("t_ipi=%u, delta=%u, s=%u, X=%u\n",
- hctx->ccid3hctx_t_ipi, hctx->ccid3hctx_delta,
- hctx->ccid3hctx_s, (unsigned)(hctx->ccid3hctx_x >> 6));
+ 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));
}
-static u32 ccid3_hc_tx_idle_rtt(struct ccid3_hc_tx_sock *hctx, ktime_t now)
+static u32 ccid3_hc_tx_idle_rtt(struct ccid3_hc_tx_sock *hc, ktime_t now)
{
- u32 delta = ktime_us_delta(now, hctx->ccid3hctx_t_last_win_count);
+ u32 delta = ktime_us_delta(now, hc->tx_t_last_win_count);
- return delta / hctx->ccid3hctx_rtt;
+ return delta / hc->tx_rtt;
}
/**
@@ -130,9 +125,9 @@ static u32 ccid3_hc_tx_idle_rtt(struct ccid3_hc_tx_sock *hctx, ktime_t now)
*/
static void ccid3_hc_tx_update_x(struct sock *sk, ktime_t *stamp)
{
- struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
- __u64 min_rate = 2 * hctx->ccid3hctx_x_recv;
- const __u64 old_x = hctx->ccid3hctx_x;
+ struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
+ __u64 min_rate = 2 * hc->tx_x_recv;
+ const __u64 old_x = hc->tx_x;
ktime_t now = stamp ? *stamp : ktime_get_real();
/*
@@ -141,37 +136,31 @@ static void ccid3_hc_tx_update_x(struct sock *sk, ktime_t *stamp)
* a sender is idle if it has not sent anything over a 2-RTT-period.
* For consistency with X and X_recv, min_rate is also scaled by 2^6.
*/
- if (ccid3_hc_tx_idle_rtt(hctx, now) >= 2) {
+ if (ccid3_hc_tx_idle_rtt(hc, now) >= 2) {
min_rate = rfc3390_initial_rate(sk);
- min_rate = max(min_rate, 2 * hctx->ccid3hctx_x_recv);
+ min_rate = max(min_rate, 2 * hc->tx_x_recv);
}
- if (hctx->ccid3hctx_p > 0) {
+ if (hc->tx_p > 0) {
- hctx->ccid3hctx_x = min(((__u64)hctx->ccid3hctx_x_calc) << 6,
- min_rate);
- hctx->ccid3hctx_x = max(hctx->ccid3hctx_x,
- (((__u64)hctx->ccid3hctx_s) << 6) /
- TFRC_T_MBI);
+ hc->tx_x = min(((__u64)hc->tx_x_calc) << 6, min_rate);
+ hc->tx_x = max(hc->tx_x, (((__u64)hc->tx_s) << 6) / TFRC_T_MBI);
- } else if (ktime_us_delta(now, hctx->ccid3hctx_t_ld)
- - (s64)hctx->ccid3hctx_rtt >= 0) {
+ } else if (ktime_us_delta(now, hc->tx_t_ld) - (s64)hc->tx_rtt >= 0) {
- hctx->ccid3hctx_x = min(2 * hctx->ccid3hctx_x, min_rate);
- hctx->ccid3hctx_x = max(hctx->ccid3hctx_x,
- scaled_div(((__u64)hctx->ccid3hctx_s) << 6,
- hctx->ccid3hctx_rtt));
- hctx->ccid3hctx_t_ld = now;
+ hc->tx_x = min(2 * hc->tx_x, min_rate);
+ hc->tx_x = max(hc->tx_x,
+ scaled_div(((__u64)hc->tx_s) << 6, hc->tx_rtt));
+ hc->tx_t_ld = now;
}
- if (hctx->ccid3hctx_x != old_x) {
+ if (hc->tx_x != old_x) {
ccid3_pr_debug("X_prev=%u, X_now=%u, X_calc=%u, "
"X_recv=%u\n", (unsigned)(old_x >> 6),
- (unsigned)(hctx->ccid3hctx_x >> 6),
- hctx->ccid3hctx_x_calc,
- (unsigned)(hctx->ccid3hctx_x_recv >> 6));
+ (unsigned)(hc->tx_x >> 6), hc->tx_x_calc,
+ (unsigned)(hc->tx_x_recv >> 6));
- ccid3_update_send_interval(hctx);
+ ccid3_update_send_interval(hc);
}
}
@@ -179,37 +168,37 @@ static void ccid3_hc_tx_update_x(struct sock *sk, ktime_t *stamp)
* Track the mean packet size `s' (cf. RFC 4342, 5.3 and RFC 3448, 4.1)
* @len: DCCP packet payload size in bytes
*/
-static inline void ccid3_hc_tx_update_s(struct ccid3_hc_tx_sock *hctx, int len)
+static inline void ccid3_hc_tx_update_s(struct ccid3_hc_tx_sock *hc, int len)
{
- const u16 old_s = hctx->ccid3hctx_s;
+ const u16 old_s = hc->tx_s;
- hctx->ccid3hctx_s = tfrc_ewma(hctx->ccid3hctx_s, len, 9);
+ hc->tx_s = tfrc_ewma(hc->tx_s, len, 9);
- if (hctx->ccid3hctx_s != old_s)
- ccid3_update_send_interval(hctx);
+ if (hc->tx_s != old_s)
+ ccid3_update_send_interval(hc);
}
/*
* Update Window Counter using the algorithm from [RFC 4342, 8.1].
* As elsewhere, RTT > 0 is assumed by using dccp_sample_rtt().
*/
-static inline void ccid3_hc_tx_update_win_count(struct ccid3_hc_tx_sock *hctx,
+static inline void ccid3_hc_tx_update_win_count(struct ccid3_hc_tx_sock *hc,
ktime_t now)
{
- u32 delta = ktime_us_delta(now, hctx->ccid3hctx_t_last_win_count),
- quarter_rtts = (4 * delta) / hctx->ccid3hctx_rtt;
+ u32 delta = ktime_us_delta(now, hc->tx_t_last_win_count),
+ quarter_rtts = (4 * delta) / hc->tx_rtt;
if (quarter_rtts > 0) {
- hctx->ccid3hctx_t_last_win_count = now;
- hctx->ccid3hctx_last_win_count += min(quarter_rtts, 5U);
- hctx->ccid3hctx_last_win_count &= 0xF; /* mod 16 */
+ hc->tx_t_last_win_count = now;
+ hc->tx_last_win_count += min(quarter_rtts, 5U);
+ hc->tx_last_win_count &= 0xF; /* mod 16 */
}
}
static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
{
struct sock *sk = (struct sock *)data;
- struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
+ struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
unsigned long t_nfb = USEC_PER_SEC / 5;
bh_lock_sock(sk);
@@ -220,24 +209,23 @@ 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(hctx->ccid3hctx_state));
+ ccid3_tx_state_name(hc->tx_state));
- if (hctx->ccid3hctx_state == TFRC_SSTATE_FBACK)
+ if (hc->tx_state == TFRC_SSTATE_FBACK)
ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK);
- else if (hctx->ccid3hctx_state != 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
*/
- if (hctx->ccid3hctx_t_rto == 0 || /* no feedback received yet */
- hctx->ccid3hctx_p == 0) {
+ if (hc->tx_t_rto == 0 || /* no feedback received yet */
+ hc->tx_p == 0) {
/* halve send rate directly */
- hctx->ccid3hctx_x = max(hctx->ccid3hctx_x / 2,
- (((__u64)hctx->ccid3hctx_s) << 6) /
- TFRC_T_MBI);
- ccid3_update_send_interval(hctx);
+ hc->tx_x = max(hc->tx_x / 2,
+ (((__u64)hc->tx_s) << 6) / TFRC_T_MBI);
+ ccid3_update_send_interval(hc);
} else {
/*
* Modify the cached value of X_recv
@@ -249,33 +237,32 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
*
* Note that X_recv is scaled by 2^6 while X_calc is not
*/
- BUG_ON(hctx->ccid3hctx_p && !hctx->ccid3hctx_x_calc);
+ BUG_ON(hc->tx_p && !hc->tx_x_calc);
- if (hctx->ccid3hctx_x_calc > (hctx->ccid3hctx_x_recv >> 5))
- hctx->ccid3hctx_x_recv =
- max(hctx->ccid3hctx_x_recv / 2,
- (((__u64)hctx->ccid3hctx_s) << 6) /
- (2 * TFRC_T_MBI));
+ if (hc->tx_x_calc > (hc->tx_x_recv >> 5))
+ hc->tx_x_recv =
+ max(hc->tx_x_recv / 2,
+ (((__u64)hc->tx_s) << 6) / (2*TFRC_T_MBI));
else {
- hctx->ccid3hctx_x_recv = hctx->ccid3hctx_x_calc;
- hctx->ccid3hctx_x_recv <<= 4;
+ hc->tx_x_recv = hc->tx_x_calc;
+ hc->tx_x_recv <<= 4;
}
ccid3_hc_tx_update_x(sk, NULL);
}
ccid3_pr_debug("Reduced X to %llu/64 bytes/sec\n",
- (unsigned long long)hctx->ccid3hctx_x);
+ (unsigned long long)hc->tx_x);
/*
* Set new timeout for the nofeedback timer.
* See comments in packet_recv() regarding the value of t_RTO.
*/
- if (unlikely(hctx->ccid3hctx_t_rto == 0)) /* no feedback yet */
+ if (unlikely(hc->tx_t_rto == 0)) /* no feedback yet */
t_nfb = TFRC_INITIAL_TIMEOUT;
else
- t_nfb = max(hctx->ccid3hctx_t_rto, 2 * hctx->ccid3hctx_t_ipi);
+ t_nfb = max(hc->tx_t_rto, 2 * hc->tx_t_ipi);
restart_timer:
- sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
+ sk_reset_timer(sk, &hc->tx_no_feedback_timer,
jiffies + usecs_to_jiffies(t_nfb));
out:
bh_unlock_sock(sk);
@@ -291,7 +278,7 @@ out:
static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
{
struct dccp_sock *dp = dccp_sk(sk);
- struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
+ struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
ktime_t now = ktime_get_real();
s64 delay;
@@ -303,18 +290,17 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
if (unlikely(skb->len == 0))
return -EBADMSG;
- switch (hctx->ccid3hctx_state) {
+ switch (hc->tx_state) {
case TFRC_SSTATE_NO_SENT:
- sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
- (jiffies +
- usecs_to_jiffies(TFRC_INITIAL_TIMEOUT)));
- hctx->ccid3hctx_last_win_count = 0;
- hctx->ccid3hctx_t_last_win_count = now;
+ sk_reset_timer(sk, &hc->tx_no_feedback_timer, (jiffies +
+ usecs_to_jiffies(TFRC_INITIAL_TIMEOUT)));
+ hc->tx_last_win_count = 0;
+ hc->tx_t_last_win_count = now;
/* Set t_0 for initial packet */
- hctx->ccid3hctx_t_nom = now;
+ hc->tx_t_nom = now;
- hctx->ccid3hctx_s = skb->len;
+ hc->tx_s = skb->len;
/*
* Use initial RTT sample when available: recommended by erratum
@@ -323,9 +309,9 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
*/
if (dp->dccps_syn_rtt) {
ccid3_pr_debug("SYN RTT = %uus\n", dp->dccps_syn_rtt);
- hctx->ccid3hctx_rtt = dp->dccps_syn_rtt;
- hctx->ccid3hctx_x = rfc3390_initial_rate(sk);
- hctx->ccid3hctx_t_ld = now;
+ hc->tx_rtt = dp->dccps_syn_rtt;
+ hc->tx_x = rfc3390_initial_rate(sk);
+ hc->tx_t_ld = now;
} else {
/*
* Sender does not have RTT sample:
@@ -333,17 +319,17 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
* is needed in several parts (e.g. window counter);
* - set sending rate X_pps = 1pps as per RFC 3448, 4.2.
*/
- hctx->ccid3hctx_rtt = DCCP_FALLBACK_RTT;
- hctx->ccid3hctx_x = hctx->ccid3hctx_s;
- hctx->ccid3hctx_x <<= 6;
+ hc->tx_rtt = DCCP_FALLBACK_RTT;
+ hc->tx_x = hc->tx_s;
+ hc->tx_x <<= 6;
}
- ccid3_update_send_interval(hctx);
+ 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:
- delay = ktime_us_delta(hctx->ccid3hctx_t_nom, now);
+ 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]
@@ -353,10 +339,10 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
* else
* // send the packet in (t_nom - t_now) milliseconds.
*/
- if (delay - (s64)hctx->ccid3hctx_delta >= 1000)
+ if (delay - (s64)hc->tx_delta >= 1000)
return (u32)delay / 1000L;
- ccid3_hc_tx_update_win_count(hctx, now);
+ ccid3_hc_tx_update_win_count(hc, now);
break;
case TFRC_SSTATE_TERM:
DCCP_BUG("%s(%p) - Illegal state TERM", dccp_role(sk), sk);
@@ -365,28 +351,27 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
/* prepare to send now (add options etc.) */
dp->dccps_hc_tx_insert_options = 1;
- DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count;
+ DCCP_SKB_CB(skb)->dccpd_ccval = hc->tx_last_win_count;
/* set the nominal send time for the next following packet */
- hctx->ccid3hctx_t_nom = ktime_add_us(hctx->ccid3hctx_t_nom,
- hctx->ccid3hctx_t_ipi);
+ hc->tx_t_nom = ktime_add_us(hc->tx_t_nom, hc->tx_t_ipi);
return 0;
}
static void ccid3_hc_tx_packet_sent(struct sock *sk, int more,
unsigned int len)
{
- struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
+ struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
- ccid3_hc_tx_update_s(hctx, len);
+ ccid3_hc_tx_update_s(hc, len);
- if (tfrc_tx_hist_add(&hctx->ccid3hctx_hist, dccp_sk(sk)->dccps_gss))
+ if (tfrc_tx_hist_add(&hc->tx_hist, dccp_sk(sk)->dccps_gss))
DCCP_CRIT("packet history - out of memory!");
}
static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
{
- struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
+ struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
struct ccid3_options_received *opt_recv;
ktime_t now;
unsigned long t_nfb;
@@ -397,15 +382,15 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_DATAACK))
return;
/* ... and only in the established state */
- if (hctx->ccid3hctx_state != TFRC_SSTATE_FBACK &&
- hctx->ccid3hctx_state != TFRC_SSTATE_NO_FBACK)
+ if (hc->tx_state != TFRC_SSTATE_FBACK &&
+ hc->tx_state != TFRC_SSTATE_NO_FBACK)
return;
- opt_recv = &hctx->ccid3hctx_options_received;
+ 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(hctx->ccid3hctx_hist,
+ 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,
@@ -415,37 +400,37 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
}
/* Update receive rate in units of 64 * bytes/second */
- hctx->ccid3hctx_x_recv = opt_recv->ccid3or_receive_rate;
- hctx->ccid3hctx_x_recv <<= 6;
+ 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 */
- hctx->ccid3hctx_p = 0;
+ hc->tx_p = 0;
else /* can not exceed 100% */
- hctx->ccid3hctx_p = scaled_div(1, pinv);
+ hc->tx_p = scaled_div(1, pinv);
/*
* Validate new RTT sample and update moving average
*/
r_sample = dccp_sample_rtt(sk, r_sample);
- hctx->ccid3hctx_rtt = tfrc_ewma(hctx->ccid3hctx_rtt, r_sample, 9);
+ hc->tx_rtt = tfrc_ewma(hc->tx_rtt, r_sample, 9);
/*
* Update allowed sending rate X as per draft rfc3448bis-00, 4.2/3
*/
- if (hctx->ccid3hctx_state == TFRC_SSTATE_NO_FBACK) {
+ if (hc->tx_state == TFRC_SSTATE_NO_FBACK) {
ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK);
- if (hctx->ccid3hctx_t_rto == 0) {
+ if (hc->tx_t_rto == 0) {
/*
* Initial feedback packet: Larger Initial Windows (4.2)
*/
- hctx->ccid3hctx_x = rfc3390_initial_rate(sk);
- hctx->ccid3hctx_t_ld = now;
+ hc->tx_x = rfc3390_initial_rate(sk);
+ hc->tx_t_ld = now;
- ccid3_update_send_interval(hctx);
+ ccid3_update_send_interval(hc);
goto done_computing_x;
- } else if (hctx->ccid3hctx_p == 0) {
+ } else if (hc->tx_p == 0) {
/*
* First feedback after nofeedback timer expiry (4.3)
*/
@@ -454,25 +439,20 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
}
/* Update sending rate (step 4 of [RFC 3448, 4.3]) */
- if (hctx->ccid3hctx_p > 0)
- hctx->ccid3hctx_x_calc =
- tfrc_calc_x(hctx->ccid3hctx_s,
- hctx->ccid3hctx_rtt,
- hctx->ccid3hctx_p);
+ if (hc->tx_p > 0)
+ hc->tx_x_calc = tfrc_calc_x(hc->tx_s, hc->tx_rtt, hc->tx_p);
ccid3_hc_tx_update_x(sk, &now);
done_computing_x:
ccid3_pr_debug("%s(%p), RTT=%uus (sample=%uus), s=%u, "
"p=%u, X_calc=%u, X_recv=%u, X=%u\n",
- dccp_role(sk),
- sk, hctx->ccid3hctx_rtt, r_sample,
- hctx->ccid3hctx_s, hctx->ccid3hctx_p,
- hctx->ccid3hctx_x_calc,
- (unsigned)(hctx->ccid3hctx_x_recv >> 6),
- (unsigned)(hctx->ccid3hctx_x >> 6));
+ dccp_role(sk), sk, hc->tx_rtt, r_sample,
+ hc->tx_s, hc->tx_p, hc->tx_x_calc,
+ (unsigned)(hc->tx_x_recv >> 6),
+ (unsigned)(hc->tx_x >> 6));
/* unschedule no feedback timer */
- sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer);
+ sk_stop_timer(sk, &hc->tx_no_feedback_timer);
/*
* As we have calculated new ipi, delta, t_nom it is possible
@@ -486,21 +466,19 @@ done_computing_x:
* This can help avoid triggering the nofeedback timer too
* often ('spinning') on LANs with small RTTs.
*/
- hctx->ccid3hctx_t_rto = max_t(u32, 4 * hctx->ccid3hctx_rtt,
- (CONFIG_IP_DCCP_CCID3_RTO *
- (USEC_PER_SEC / 1000)));
+ hc->tx_t_rto = max_t(u32, 4 * hc->tx_rtt, (CONFIG_IP_DCCP_CCID3_RTO *
+ (USEC_PER_SEC / 1000)));
/*
* Schedule no feedback timer to expire in
* max(t_RTO, 2 * s/X) = max(t_RTO, 2 * t_ipi)
*/
- t_nfb = max(hctx->ccid3hctx_t_rto, 2 * hctx->ccid3hctx_t_ipi);
+ t_nfb = max(hc->tx_t_rto, 2 * hc->tx_t_ipi);
ccid3_pr_debug("%s(%p), Scheduled no feedback timer to "
"expire in %lu jiffies (%luus)\n",
- dccp_role(sk),
- sk, usecs_to_jiffies(t_nfb), t_nfb);
+ dccp_role(sk), sk, usecs_to_jiffies(t_nfb), t_nfb);
- sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
+ sk_reset_timer(sk, &hc->tx_no_feedback_timer,
jiffies + usecs_to_jiffies(t_nfb));
}
@@ -510,11 +488,11 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
{
int rc = 0;
const struct dccp_sock *dp = dccp_sk(sk);
- struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
+ struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
struct ccid3_options_received *opt_recv;
__be32 opt_val;
- opt_recv = &hctx->ccid3hctx_options_received;
+ opt_recv = &hc->tx_options_received;
if (opt_recv->ccid3or_seqno != dp->dccps_gsr) {
opt_recv->ccid3or_seqno = dp->dccps_gsr;
@@ -568,56 +546,55 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk)
{
- struct ccid3_hc_tx_sock *hctx = ccid_priv(ccid);
+ struct ccid3_hc_tx_sock *hc = ccid_priv(ccid);
- hctx->ccid3hctx_state = TFRC_SSTATE_NO_SENT;
- hctx->ccid3hctx_hist = NULL;
- setup_timer(&hctx->ccid3hctx_no_feedback_timer,
+ hc->tx_state = TFRC_SSTATE_NO_SENT;
+ hc->tx_hist = NULL;
+ setup_timer(&hc->tx_no_feedback_timer,
ccid3_hc_tx_no_feedback_timer, (unsigned long)sk);
-
return 0;
}
static void ccid3_hc_tx_exit(struct sock *sk)
{
- struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(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, &hctx->ccid3hctx_no_feedback_timer);
+ sk_stop_timer(sk, &hc->tx_no_feedback_timer);
- tfrc_tx_hist_purge(&hctx->ccid3hctx_hist);
+ 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 *hctx;
+ struct ccid3_hc_tx_sock *hc;
/* Listen socks doesn't have a private CCID block */
if (sk->sk_state == DCCP_LISTEN)
return;
- hctx = ccid3_hc_tx_sk(sk);
- info->tcpi_rto = hctx->ccid3hctx_t_rto;
- info->tcpi_rtt = hctx->ccid3hctx_rtt;
+ hc = ccid3_hc_tx_sk(sk);
+ info->tcpi_rto = hc->tx_t_rto;
+ info->tcpi_rtt = hc->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 *hctx;
+ const struct ccid3_hc_tx_sock *hc;
const void *val;
/* Listen socks doesn't have a private CCID block */
if (sk->sk_state == DCCP_LISTEN)
return -EINVAL;
- hctx = ccid3_hc_tx_sk(sk);
+ hc = ccid3_hc_tx_sk(sk);
switch (optname) {
case DCCP_SOCKOPT_CCID_TX_INFO:
- if (len < sizeof(hctx->ccid3hctx_tfrc))
+ if (len < sizeof(hc->tx_tfrc))
return -EINVAL;
- len = sizeof(hctx->ccid3hctx_tfrc);
- val = &hctx->ccid3hctx_tfrc;
+ len = sizeof(hc->tx_tfrc);
+ val = &hc->tx_tfrc;
break;
default:
return -ENOPROTOOPT;
@@ -657,34 +634,34 @@ static const char *ccid3_rx_state_name(enum ccid3_hc_rx_states state)
static void ccid3_hc_rx_set_state(struct sock *sk,
enum ccid3_hc_rx_states state)
{
- struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
- enum ccid3_hc_rx_states oldstate = hcrx->ccid3hcrx_state;
+ struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
+ enum ccid3_hc_rx_states oldstate = hc->rx_state;
ccid3_pr_debug("%s(%p) %-8.8s -> %s\n",
dccp_role(sk), sk, ccid3_rx_state_name(oldstate),
ccid3_rx_state_name(state));
WARN_ON(state == oldstate);
- hcrx->ccid3hcrx_state = state;
+ hc->rx_state = state;
}
static void ccid3_hc_rx_send_feedback(struct sock *sk,
const struct sk_buff *skb,
enum ccid3_fback_type fbtype)
{
- struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
+ struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
struct dccp_sock *dp = dccp_sk(sk);
ktime_t now;
s64 delta = 0;
- if (unlikely(hcrx->ccid3hcrx_state == TFRC_RSTATE_TERM))
+ if (unlikely(hc->rx_state == TFRC_RSTATE_TERM))
return;
now = ktime_get_real();
switch (fbtype) {
case CCID3_FBACK_INITIAL:
- hcrx->ccid3hcrx_x_recv = 0;
- hcrx->ccid3hcrx_pinv = ~0U; /* see RFC 4342, 8.5 */
+ hc->rx_x_recv = 0;
+ hc->rx_pinv = ~0U; /* see RFC 4342, 8.5 */
break;
case CCID3_FBACK_PARAM_CHANGE:
/*
@@ -697,27 +674,26 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk,
* the number of bytes since last feedback.
* This is a safe fallback, since X is bounded above by X_calc.
*/
- if (hcrx->ccid3hcrx_x_recv > 0)
+ if (hc->rx_x_recv > 0)
break;
/* fall through */
case CCID3_FBACK_PERIODIC:
- delta = ktime_us_delta(now, hcrx->ccid3hcrx_tstamp_last_feedback);
+ delta = ktime_us_delta(now, hc->rx_tstamp_last_feedback);
if (delta <= 0)
DCCP_BUG("delta (%ld) <= 0", (long)delta);
else
- hcrx->ccid3hcrx_x_recv =
- scaled_div32(hcrx->ccid3hcrx_bytes_recv, delta);
+ hc->rx_x_recv = scaled_div32(hc->rx_bytes_recv, delta);
break;
default:
return;
}
ccid3_pr_debug("Interval %ldusec, X_recv=%u, 1/p=%u\n", (long)delta,
- hcrx->ccid3hcrx_x_recv, hcrx->ccid3hcrx_pinv);
+ hc->rx_x_recv, hc->rx_pinv);
- hcrx->ccid3hcrx_tstamp_last_feedback = now;
- hcrx->ccid3hcrx_last_counter = dccp_hdr(skb)->dccph_ccval;
- hcrx->ccid3hcrx_bytes_recv = 0;
+ hc->rx_tstamp_last_feedback = now;
+ hc->rx_last_counter = dccp_hdr(skb)->dccph_ccval;
+ hc->rx_bytes_recv = 0;
dp->dccps_hc_rx_insert_options = 1;
dccp_send_ack(sk);
@@ -725,19 +701,19 @@ 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 *hcrx;
+ const struct ccid3_hc_rx_sock *hc;
__be32 x_recv, pinv;
if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN))
return 0;
- hcrx = ccid3_hc_rx_sk(sk);
+ hc = ccid3_hc_rx_sk(sk);
if (dccp_packet_without_ack(skb))
return 0;
- x_recv = htonl(hcrx->ccid3hcrx_x_recv);
- pinv = htonl(hcrx->ccid3hcrx_pinv);
+ x_recv = htonl(hc->rx_x_recv);
+ pinv = htonl(hc->rx_pinv);
if (dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE,
&pinv, sizeof(pinv)) ||
@@ -760,26 +736,26 @@ static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
*/
static u32 ccid3_first_li(struct sock *sk)
{
- struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
+ struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
u32 x_recv, p, delta;
u64 fval;
- if (hcrx->ccid3hcrx_rtt == 0) {
+ if (hc->rx_rtt == 0) {
DCCP_WARN("No RTT estimate available, using fallback RTT\n");
- hcrx->ccid3hcrx_rtt = DCCP_FALLBACK_RTT;
+ hc->rx_rtt = DCCP_FALLBACK_RTT;
}
- delta = ktime_to_us(net_timedelta(hcrx->ccid3hcrx_tstamp_last_feedback));
- x_recv = scaled_div32(hcrx->ccid3hcrx_bytes_recv, delta);
+ delta = ktime_to_us(net_timedelta(hc->rx_tstamp_last_feedback));
+ 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 = hcrx->ccid3hcrx_x_recv) == 0) {
+ if ((x_recv = hc->rx_x_recv) == 0) {
DCCP_BUG("stored value of X_recv is zero");
return ~0U;
}
}
- fval = scaled_div(hcrx->ccid3hcrx_s, hcrx->ccid3hcrx_rtt);
+ fval = scaled_div(hc->rx_s, hc->rx_rtt);
fval = scaled_div32(fval, x_recv);
p = tfrc_calc_x_reverse_lookup(fval);
@@ -791,19 +767,19 @@ static u32 ccid3_first_li(struct sock *sk)
static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
{
- struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
+ struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
enum ccid3_fback_type do_feedback = CCID3_FBACK_NONE;
const u64 ndp = dccp_sk(sk)->dccps_options_received.dccpor_ndp;
const bool is_data_packet = dccp_data_packet(skb);
- if (unlikely(hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA)) {
+ if (unlikely(hc->rx_state == TFRC_RSTATE_NO_DATA)) {
if (is_data_packet) {
const u32 payload = skb->len - dccp_hdr(skb)->dccph_doff * 4;
do_feedback = CCID3_FBACK_INITIAL;
ccid3_hc_rx_set_state(sk, TFRC_RSTATE_DATA);
- hcrx->ccid3hcrx_s = payload;
+ hc->rx_s = payload;
/*
- * Not necessary to update ccid3hcrx_bytes_recv here,
+ * Not necessary to update rx_bytes_recv here,
* since X_recv = 0 for the first feedback packet (cf.
* RFC 3448, 6.3) -- gerrit
*/
@@ -811,7 +787,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
goto update_records;
}
- if (tfrc_rx_hist_duplicate(&hcrx->ccid3hcrx_hist, skb))
+ if (tfrc_rx_hist_duplicate(&hc->rx_hist, skb))
return; /* done receiving */
if (is_data_packet) {
@@ -819,20 +795,20 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
/*
* Update moving-average of s and the sum of received payload bytes
*/
- hcrx->ccid3hcrx_s = tfrc_ewma(hcrx->ccid3hcrx_s, payload, 9);
- hcrx->ccid3hcrx_bytes_recv += payload;
+ hc->rx_s = tfrc_ewma(hc->rx_s, payload, 9);
+ hc->rx_bytes_recv += payload;
}
/*
* Perform loss detection and handle pending losses
*/
- if (tfrc_rx_handle_loss(&hcrx->ccid3hcrx_hist, &hcrx->ccid3hcrx_li_hist,
+ if (tfrc_rx_handle_loss(&hc->rx_hist, &hc->rx_li_hist,
skb, ndp, ccid3_first_li, sk)) {
do_feedback = CCID3_FBACK_PARAM_CHANGE;
goto done_receiving;
}
- if (tfrc_rx_hist_loss_pending(&hcrx->ccid3hcrx_hist))
+ if (tfrc_rx_hist_loss_pending(&hc->rx_hist))
return; /* done receiving */
/*
@@ -841,17 +817,17 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
if (unlikely(!is_data_packet))
goto update_records;
- if (!tfrc_lh_is_initialised(&hcrx->ccid3hcrx_li_hist)) {
- const u32 sample = tfrc_rx_hist_sample_rtt(&hcrx->ccid3hcrx_hist, skb);
+ if (!tfrc_lh_is_initialised(&hc->rx_li_hist)) {
+ const u32 sample = tfrc_rx_hist_sample_rtt(&hc->rx_hist, skb);
/*
* Empty loss history: no loss so far, hence p stays 0.
* Sample RTT values, since an RTT estimate is required for the
* computation of p when the first loss occurs; RFC 3448, 6.3.1.
*/
if (sample != 0)
- hcrx->ccid3hcrx_rtt = tfrc_ewma(hcrx->ccid3hcrx_rtt, sample, 9);
+ hc->rx_rtt = tfrc_ewma(hc->rx_rtt, sample, 9);
- } else if (tfrc_lh_update_i_mean(&hcrx->ccid3hcrx_li_hist, skb)) {
+ } else if (tfrc_lh_update_i_mean(&hc->rx_li_hist, skb)) {
/*
* Step (3) of [RFC 3448, 6.1]: Recompute I_mean and, if I_mean
* has decreased (resp. p has increased), send feedback now.
@@ -862,11 +838,11 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
/*
* Check if the periodic once-per-RTT feedback is due; RFC 4342, 10.3
*/
- if (SUB16(dccp_hdr(skb)->dccph_ccval, hcrx->ccid3hcrx_last_counter) > 3)
+ if (SUB16(dccp_hdr(skb)->dccph_ccval, hc->rx_last_counter) > 3)
do_feedback = CCID3_FBACK_PERIODIC;
update_records:
- tfrc_rx_hist_add_packet(&hcrx->ccid3hcrx_hist, skb, ndp);
+ tfrc_rx_hist_add_packet(&hc->rx_hist, skb, ndp);
done_receiving:
if (do_feedback)
@@ -875,41 +851,41 @@ done_receiving:
static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk)
{
- struct ccid3_hc_rx_sock *hcrx = ccid_priv(ccid);
+ struct ccid3_hc_rx_sock *hc = ccid_priv(ccid);
- hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA;
- tfrc_lh_init(&hcrx->ccid3hcrx_li_hist);
- return tfrc_rx_hist_alloc(&hcrx->ccid3hcrx_hist);
+ hc->rx_state = TFRC_RSTATE_NO_DATA;
+ tfrc_lh_init(&hc->rx_li_hist);
+ return tfrc_rx_hist_alloc(&hc->rx_hist);
}
static void ccid3_hc_rx_exit(struct sock *sk)
{
- struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(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(&hcrx->ccid3hcrx_hist);
- tfrc_lh_cleanup(&hcrx->ccid3hcrx_li_hist);
+ 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 *hcrx;
+ const struct ccid3_hc_rx_sock *hc;
/* Listen socks doesn't have a private CCID block */
if (sk->sk_state == DCCP_LISTEN)
return;
- hcrx = ccid3_hc_rx_sk(sk);
- info->tcpi_ca_state = hcrx->ccid3hcrx_state;
+ hc = ccid3_hc_rx_sk(sk);
+ info->tcpi_ca_state = hc->rx_state;
info->tcpi_options |= TCPI_OPT_TIMESTAMPS;
- info->tcpi_rcv_rtt = hcrx->ccid3hcrx_rtt;
+ info->tcpi_rcv_rtt = hc->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 *hcrx;
+ const struct ccid3_hc_rx_sock *hc;
struct tfrc_rx_info rx_info;
const void *val;
@@ -917,15 +893,15 @@ static int ccid3_hc_rx_getsockopt(struct sock *sk, const int optname, int len,
if (sk->sk_state == DCCP_LISTEN)
return -EINVAL;
- hcrx = ccid3_hc_rx_sk(sk);
+ 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 = hcrx->ccid3hcrx_x_recv;
- rx_info.tfrcrx_rtt = hcrx->ccid3hcrx_rtt;
- rx_info.tfrcrx_p = hcrx->ccid3hcrx_pinv == 0 ? ~0U :
- scaled_div(1, hcrx->ccid3hcrx_pinv);
+ 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);
len = sizeof(rx_info);
val = &rx_info;
break;
diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h
index e5a244143846..032635776653 100644
--- a/net/dccp/ccids/ccid3.h
+++ b/net/dccp/ccids/ccid3.h
@@ -75,44 +75,44 @@ enum ccid3_hc_tx_states {
/**
* struct ccid3_hc_tx_sock - CCID3 sender half-connection socket
- * @ccid3hctx_x - Current sending rate in 64 * bytes per second
- * @ccid3hctx_x_recv - Receive rate in 64 * bytes per second
- * @ccid3hctx_x_calc - Calculated rate in bytes per second
- * @ccid3hctx_rtt - Estimate of current round trip time in usecs
- * @ccid3hctx_p - Current loss event rate (0-1) scaled by 1000000
- * @ccid3hctx_s - Packet size in bytes
- * @ccid3hctx_t_rto - Nofeedback Timer setting in usecs
- * @ccid3hctx_t_ipi - Interpacket (send) interval (RFC 3448, 4.6) in usecs
- * @ccid3hctx_state - Sender state, one of %ccid3_hc_tx_states
- * @ccid3hctx_last_win_count - Last window counter sent
- * @ccid3hctx_t_last_win_count - Timestamp of earliest packet
- * with last_win_count value sent
- * @ccid3hctx_no_feedback_timer - Handle to no feedback timer
- * @ccid3hctx_t_ld - Time last doubled during slow start
- * @ccid3hctx_t_nom - Nominal send time of next packet
- * @ccid3hctx_delta - Send timer delta (RFC 3448, 4.6) in usecs
- * @ccid3hctx_hist - Packet history
- * @ccid3hctx_options_received - Parsed set of retrieved options
+ * @tx_x: Current sending rate in 64 * bytes per second
+ * @tx_x_recv: Receive rate in 64 * bytes per second
+ * @tx_x_calc: Calculated rate in bytes per second
+ * @tx_rtt: Estimate of current round trip time in usecs
+ * @tx_p: Current loss event rate (0-1) scaled by 1000000
+ * @tx_s: Packet size in bytes
+ * @tx_t_rto: Nofeedback Timer setting in usecs
+ * @tx_t_ipi: Interpacket (send) interval (RFC 3448, 4.6) in usecs
+ * @tx_state: Sender state, one of %ccid3_hc_tx_states
+ * @tx_last_win_count: Last window counter sent
+ * @tx_t_last_win_count: Timestamp of earliest packet
+ * with last_win_count value sent
+ * @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 ccid3hctx_tfrc;
-#define ccid3hctx_x ccid3hctx_tfrc.tfrctx_x
-#define ccid3hctx_x_recv ccid3hctx_tfrc.tfrctx_x_recv
-#define ccid3hctx_x_calc ccid3hctx_tfrc.tfrctx_x_calc
-#define ccid3hctx_rtt ccid3hctx_tfrc.tfrctx_rtt
-#define ccid3hctx_p ccid3hctx_tfrc.tfrctx_p
-#define ccid3hctx_t_rto ccid3hctx_tfrc.tfrctx_rto
-#define ccid3hctx_t_ipi ccid3hctx_tfrc.tfrctx_ipi
- u16 ccid3hctx_s;
- enum ccid3_hc_tx_states ccid3hctx_state:8;
- u8 ccid3hctx_last_win_count;
- ktime_t ccid3hctx_t_last_win_count;
- struct timer_list ccid3hctx_no_feedback_timer;
- ktime_t ccid3hctx_t_ld;
- ktime_t ccid3hctx_t_nom;
- u32 ccid3hctx_delta;
- struct tfrc_tx_hist_entry *ccid3hctx_hist;
- struct ccid3_options_received ccid3hctx_options_received;
+ 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
+ u16 tx_s;
+ enum ccid3_hc_tx_states tx_state:8;
+ u8 tx_last_win_count;
+ ktime_t tx_t_last_win_count;
+ 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)
@@ -131,32 +131,32 @@ enum ccid3_hc_rx_states {
/**
* struct ccid3_hc_rx_sock - CCID3 receiver half-connection socket
- * @ccid3hcrx_x_recv - Receiver estimate of send rate (RFC 3448 4.3)
- * @ccid3hcrx_rtt - Receiver estimate of rtt (non-standard)
- * @ccid3hcrx_p - Current loss event rate (RFC 3448 5.4)
- * @ccid3hcrx_last_counter - Tracks window counter (RFC 4342, 8.1)
- * @ccid3hcrx_state - Receiver state, one of %ccid3_hc_rx_states
- * @ccid3hcrx_bytes_recv - Total sum of DCCP payload bytes
- * @ccid3hcrx_x_recv - Receiver estimate of send rate (RFC 3448, sec. 4.3)
- * @ccid3hcrx_rtt - Receiver estimate of RTT
- * @ccid3hcrx_tstamp_last_feedback - Time at which last feedback was sent
- * @ccid3hcrx_tstamp_last_ack - Time at which last feedback was sent
- * @ccid3hcrx_hist - Packet history (loss detection + RTT sampling)
- * @ccid3hcrx_li_hist - Loss Interval database
- * @ccid3hcrx_s - Received packet size in bytes
- * @ccid3hcrx_pinv - Inverse of Loss Event Rate (RFC 4342, sec. 8.5)
+ * @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
+ * @rx_pinv: Inverse of Loss Event Rate (RFC 4342, sec. 8.5)
*/
struct ccid3_hc_rx_sock {
- u8 ccid3hcrx_last_counter:4;
- enum ccid3_hc_rx_states ccid3hcrx_state:8;
- u32 ccid3hcrx_bytes_recv;
- u32 ccid3hcrx_x_recv;
- u32 ccid3hcrx_rtt;
- ktime_t ccid3hcrx_tstamp_last_feedback;
- struct tfrc_rx_hist ccid3hcrx_hist;
- struct tfrc_loss_hist ccid3hcrx_li_hist;
- u16 ccid3hcrx_s;
-#define ccid3hcrx_pinv ccid3hcrx_li_hist.i_mean
+ u8 rx_last_counter:4;
+ enum ccid3_hc_rx_states rx_state:8;
+ u32 rx_bytes_recv;
+ u32 rx_x_recv;
+ u32 rx_rtt;
+ ktime_t rx_tstamp_last_feedback;
+ struct tfrc_rx_hist rx_hist;
+ struct tfrc_loss_hist rx_li_hist;
+ u16 rx_s;
+#define rx_pinv rx_li_hist.i_mean
};
static inline struct ccid3_hc_rx_sock *ccid3_hc_rx_sk(const struct sock *sk)
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 7302e1498d46..00028d4b09d9 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -62,10 +62,10 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
nexthop = inet->opt->faddr;
}
- tmp = ip_route_connect(&rt, nexthop, inet->saddr,
+ tmp = ip_route_connect(&rt, nexthop, inet->inet_saddr,
RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
IPPROTO_DCCP,
- inet->sport, usin->sin_port, sk, 1);
+ inet->inet_sport, usin->sin_port, sk, 1);
if (tmp < 0)
return tmp;
@@ -77,12 +77,12 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (inet->opt == NULL || !inet->opt->srr)
daddr = rt->rt_dst;
- if (inet->saddr == 0)
- inet->saddr = rt->rt_src;
- inet->rcv_saddr = inet->saddr;
+ if (inet->inet_saddr == 0)
+ inet->inet_saddr = rt->rt_src;
+ inet->inet_rcv_saddr = inet->inet_saddr;
- inet->dport = usin->sin_port;
- inet->daddr = daddr;
+ inet->inet_dport = usin->sin_port;
+ inet->inet_daddr = daddr;
inet_csk(sk)->icsk_ext_hdr_len = 0;
if (inet->opt != NULL)
@@ -98,17 +98,19 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (err != 0)
goto failure;
- err = ip_route_newports(&rt, IPPROTO_DCCP, inet->sport, inet->dport,
- sk);
+ err = ip_route_newports(&rt, IPPROTO_DCCP, inet->inet_sport,
+ inet->inet_dport, sk);
if (err != 0)
goto failure;
/* OK, now commit destination to socket. */
sk_setup_caps(sk, &rt->u.dst);
- dp->dccps_iss = secure_dccp_sequence_number(inet->saddr, inet->daddr,
- inet->sport, inet->dport);
- inet->id = dp->dccps_iss ^ jiffies;
+ dp->dccps_iss = secure_dccp_sequence_number(inet->inet_saddr,
+ inet->inet_daddr,
+ inet->inet_sport,
+ inet->inet_dport);
+ inet->inet_id = dp->dccps_iss ^ jiffies;
err = dccp_connect(sk);
rt = NULL;
@@ -123,7 +125,7 @@ failure:
dccp_set_state(sk, DCCP_CLOSED);
ip_rt_put(rt);
sk->sk_route_caps = 0;
- inet->dport = 0;
+ inet->inet_dport = 0;
goto out;
}
@@ -352,7 +354,9 @@ void dccp_v4_send_check(struct sock *sk, int unused, struct sk_buff *skb)
struct dccp_hdr *dh = dccp_hdr(skb);
dccp_csum_outgoing(skb);
- dh->dccph_checksum = dccp_v4_csum_finish(skb, inet->saddr, inet->daddr);
+ dh->dccph_checksum = dccp_v4_csum_finish(skb,
+ inet->inet_saddr,
+ inet->inet_daddr);
}
EXPORT_SYMBOL_GPL(dccp_v4_send_check);
@@ -393,14 +397,14 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb,
newinet = inet_sk(newsk);
ireq = inet_rsk(req);
- newinet->daddr = ireq->rmt_addr;
- newinet->rcv_saddr = ireq->loc_addr;
- newinet->saddr = ireq->loc_addr;
+ newinet->inet_daddr = ireq->rmt_addr;
+ newinet->inet_rcv_saddr = ireq->loc_addr;
+ newinet->inet_saddr = ireq->loc_addr;
newinet->opt = ireq->opt;
ireq->opt = NULL;
newinet->mc_index = inet_iif(skb);
newinet->mc_ttl = ip_hdr(skb)->ttl;
- newinet->id = jiffies;
+ newinet->inet_id = jiffies;
dccp_sync_mss(newsk, dst_mtu(dst));
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index e48ca5d45658..6d89f9f7d5d8 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -158,8 +158,8 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
ipv6_addr_copy(&fl.fl6_src, &np->saddr);
fl.oif = sk->sk_bound_dev_if;
- fl.fl_ip_dport = inet->dport;
- fl.fl_ip_sport = inet->sport;
+ fl.fl_ip_dport = inet->inet_dport;
+ fl.fl_ip_sport = inet->inet_sport;
security_sk_classify_flow(sk, &fl);
err = ip6_dst_lookup(sk, &dst, &fl);
@@ -510,11 +510,9 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
memcpy(newnp, np, sizeof(struct ipv6_pinfo));
- ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),
- newinet->daddr);
+ ipv6_addr_set_v4mapped(newinet->inet_daddr, &newnp->daddr);
- ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
- newinet->saddr);
+ ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr);
ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
@@ -642,7 +640,8 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
dccp_sync_mss(newsk, dst_mtu(dst));
- newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
+ newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
+ newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
__inet6_hash(newsk);
__inet_inherit_port(sk, newsk);
@@ -970,12 +969,9 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
icsk->icsk_af_ops = &dccp_ipv6_af_ops;
sk->sk_backlog_rcv = dccp_v6_do_rcv;
goto failure;
- } else {
- ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
- inet->saddr);
- ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
- inet->rcv_saddr);
}
+ ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr);
+ ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, &np->rcv_saddr);
return err;
}
@@ -988,7 +984,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
ipv6_addr_copy(&fl.fl6_src, saddr ? saddr : &np->saddr);
fl.oif = sk->sk_bound_dev_if;
fl.fl_ip_dport = usin->sin6_port;
- fl.fl_ip_sport = inet->sport;
+ fl.fl_ip_sport = inet->inet_sport;
security_sk_classify_flow(sk, &fl);
if (np->opt != NULL && np->opt->srcrt != NULL) {
@@ -1021,7 +1017,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
/* set the source address */
ipv6_addr_copy(&np->saddr, saddr);
- inet->rcv_saddr = LOOPBACK4_IPV6;
+ inet->inet_rcv_saddr = LOOPBACK4_IPV6;
__ip6_dst_store(sk, dst, NULL, NULL);
@@ -1030,7 +1026,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
np->opt->opt_nflen);
- inet->dport = usin->sin6_port;
+ inet->inet_dport = usin->sin6_port;
dccp_set_state(sk, DCCP_REQUESTING);
err = inet6_hash_connect(&dccp_death_row, sk);
@@ -1039,7 +1035,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
dp->dccps_iss = secure_dccpv6_sequence_number(np->saddr.s6_addr32,
np->daddr.s6_addr32,
- inet->sport, inet->dport);
+ inet->inet_sport,
+ inet->inet_dport);
err = dccp_connect(sk);
if (err)
goto late_failure;
@@ -1050,7 +1047,7 @@ late_failure:
dccp_set_state(sk, DCCP_CLOSED);
__sk_dst_reset(sk);
failure:
- inet->dport = 0;
+ inet->inet_dport = 0;
sk->sk_route_caps = 0;
return err;
}
diff --git a/net/dccp/output.c b/net/dccp/output.c
index c96119fda688..d6bb753bf6ad 100644
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -99,8 +99,8 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
/* Build DCCP header and checksum it. */
dh = dccp_zeroed_hdr(skb, dccp_header_size);
dh->dccph_type = dcb->dccpd_type;
- dh->dccph_sport = inet->sport;
- dh->dccph_dport = inet->dport;
+ dh->dccph_sport = inet->inet_sport;
+ dh->dccph_dport = inet->inet_dport;
dh->dccph_doff = (dccp_header_size + dcb->dccpd_opt_len) / 4;
dh->dccph_ccval = dcb->dccpd_ccval;
dh->dccph_cscov = dp->dccps_pcslen;
diff --git a/net/dccp/probe.c b/net/dccp/probe.c
index 37731da41481..dc328425fa20 100644
--- a/net/dccp/probe.c
+++ b/net/dccp/probe.c
@@ -75,26 +75,25 @@ static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk,
struct msghdr *msg, size_t size)
{
const struct inet_sock *inet = inet_sk(sk);
- struct ccid3_hc_tx_sock *hctx = NULL;
+ struct ccid3_hc_tx_sock *hc = NULL;
if (ccid_get_current_tx_ccid(dccp_sk(sk)) == DCCPC_CCID3)
- hctx = ccid3_hc_tx_sk(sk);
-
- if (port == 0 || ntohs(inet->dport) == port ||
- ntohs(inet->sport) == port) {
- if (hctx)
- printl("%pI4:%u %pI4:%u %d %d %d %d %u "
- "%llu %llu %d\n",
- &inet->saddr, ntohs(inet->sport),
- &inet->daddr, ntohs(inet->dport), size,
- hctx->ccid3hctx_s, hctx->ccid3hctx_rtt,
- hctx->ccid3hctx_p, hctx->ccid3hctx_x_calc,
- hctx->ccid3hctx_x_recv >> 6,
- hctx->ccid3hctx_x >> 6, hctx->ccid3hctx_t_ipi);
+ hc = ccid3_hc_tx_sk(sk);
+
+ if (port == 0 || ntohs(inet->inet_dport) == port ||
+ ntohs(inet->inet_sport) == port) {
+ if (hc)
+ printl("%pI4:%u %pI4:%u %d %d %d %d %u %llu %llu %d\n",
+ &inet->inet_saddr, ntohs(inet->inet_sport),
+ &inet->inet_daddr, ntohs(inet->inet_dport), size,
+ hc->tx_s, hc->tx_rtt, hc->tx_p,
+ hc->tx_x_calc, hc->tx_x_recv >> 6,
+ hc->tx_x >> 6, hc->tx_t_ipi);
else
printl("%pI4:%u %pI4:%u %d\n",
- &inet->saddr, ntohs(inet->sport),
- &inet->daddr, ntohs(inet->dport), size);
+ &inet->inet_saddr, ntohs(inet->inet_sport),
+ &inet->inet_daddr, ntohs(inet->inet_dport),
+ size);
}
jprobe_return();
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index a156319fd0ac..671cd1413d59 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -278,7 +278,7 @@ int dccp_disconnect(struct sock *sk, int flags)
sk->sk_send_head = NULL;
}
- inet->dport = 0;
+ inet->inet_dport = 0;
if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))
inet_reset_saddr(sk);
@@ -290,7 +290,7 @@ int dccp_disconnect(struct sock *sk, int flags)
inet_csk_delack_init(sk);
__sk_dst_reset(sk);
- WARN_ON(inet->num && !icsk->icsk_bind_hash);
+ WARN_ON(inet->inet_num && !icsk->icsk_bind_hash);
sk->sk_error_report(sk);
return err;
@@ -1060,11 +1060,12 @@ static int __init dccp_init(void)
for (ehash_order = 0; (1UL << ehash_order) < goal; ehash_order++)
;
do {
- dccp_hashinfo.ehash_size = (1UL << ehash_order) * PAGE_SIZE /
+ unsigned long hash_size = (1UL << ehash_order) * PAGE_SIZE /
sizeof(struct inet_ehash_bucket);
- while (dccp_hashinfo.ehash_size &
- (dccp_hashinfo.ehash_size - 1))
- dccp_hashinfo.ehash_size--;
+
+ while (hash_size & (hash_size - 1))
+ hash_size--;
+ dccp_hashinfo.ehash_mask = hash_size - 1;
dccp_hashinfo.ehash = (struct inet_ehash_bucket *)
__get_free_pages(GFP_ATOMIC|__GFP_NOWARN, ehash_order);
} while (!dccp_hashinfo.ehash && --ehash_order > 0);
@@ -1074,7 +1075,7 @@ static int __init dccp_init(void)
goto out_free_bind_bucket_cachep;
}
- for (i = 0; i < dccp_hashinfo.ehash_size; i++) {
+ for (i = 0; i <= dccp_hashinfo.ehash_mask; i++) {
INIT_HLIST_NULLS_HEAD(&dccp_hashinfo.ehash[i].chain, i);
INIT_HLIST_NULLS_HEAD(&dccp_hashinfo.ehash[i].twchain, i);
}
@@ -1153,7 +1154,7 @@ static void __exit dccp_fini(void)
get_order(dccp_hashinfo.bhash_size *
sizeof(struct inet_bind_hashbucket)));
free_pages((unsigned long)dccp_hashinfo.ehash,
- get_order(dccp_hashinfo.ehash_size *
+ get_order((dccp_hashinfo.ehash_mask + 1) *
sizeof(struct inet_ehash_bucket)));
inet_ehash_locks_free(&dccp_hashinfo);
kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
diff --git a/net/dccp/timer.c b/net/dccp/timer.c
index 162d1e683c39..bbfeb5eae46a 100644
--- a/net/dccp/timer.c
+++ b/net/dccp/timer.c
@@ -38,7 +38,7 @@ static int dccp_write_timeout(struct sock *sk)
if (sk->sk_state == DCCP_REQUESTING || sk->sk_state == DCCP_PARTOPEN) {
if (icsk->icsk_retransmits != 0)
- dst_negative_advice(&sk->sk_dst_cache);
+ dst_negative_advice(&sk->sk_dst_cache, sk);
retry_until = icsk->icsk_syn_retries ?
: sysctl_dccp_request_retries;
} else {
@@ -63,7 +63,7 @@ static int dccp_write_timeout(struct sock *sk)
Golden words :-).
*/
- dst_negative_advice(&sk->sk_dst_cache);
+ dst_negative_advice(&sk->sk_dst_cache, sk);
}
retry_until = sysctl_dccp_retries2;
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 7a58c87baf17..664965c87e16 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -1955,7 +1955,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
}
if ((flags & MSG_TRYHARD) && sk->sk_dst_cache)
- dst_negative_advice(&sk->sk_dst_cache);
+ dst_negative_advice(&sk->sk_dst_cache, sk);
mss = scp->segsize_rem;
fctype = scp->services_rem & NSP_FC_MASK;
@@ -2325,7 +2325,7 @@ static const struct file_operations dn_socket_seq_fops = {
};
#endif
-static struct net_proto_family dn_family_ops = {
+static const struct net_proto_family dn_family_ops = {
.family = AF_DECnet,
.create = dn_create,
.owner = THIS_MODULE,
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index 0e0254fd767d..5e9426a11c3e 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -457,15 +457,15 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
iov[0].iov_len = size;
for (i = 0; i < msg->msg_iovlen; i++) {
void __user *base = msg->msg_iov[i].iov_base;
- size_t len = msg->msg_iov[i].iov_len;
+ size_t iov_len = msg->msg_iov[i].iov_len;
/* Check it now since we switch to KERNEL_DS later. */
- if (!access_ok(VERIFY_READ, base, len)) {
+ if (!access_ok(VERIFY_READ, base, iov_len)) {
mutex_unlock(&econet_mutex);
return -EFAULT;
}
iov[i+1].iov_base = base;
- iov[i+1].iov_len = len;
- size += len;
+ iov[i+1].iov_len = iov_len;
+ size += iov_len;
}
/* Get a skbuff (no data, just holds our cb information) */
@@ -742,7 +742,7 @@ static int econet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg
return 0;
}
-static struct net_proto_family econet_family_ops = {
+static const struct net_proto_family econet_family_ops = {
.family = PF_ECONET,
.create = econet_create,
.owner = THIS_MODULE,
diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c
index cd949d5e451b..309348fba72b 100644
--- a/net/ieee802154/af_ieee802154.c
+++ b/net/ieee802154/af_ieee802154.c
@@ -285,7 +285,7 @@ out:
return rc;
}
-static struct net_proto_family ieee802154_family_ops = {
+static const struct net_proto_family ieee802154_family_ops = {
.family = PF_IEEE802154,
.create = ieee802154_create,
.owner = THIS_MODULE,
diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c
index a413b1bf4465..9aac5aee1575 100644
--- a/net/ieee802154/dgram.c
+++ b/net/ieee802154/dgram.c
@@ -303,7 +303,7 @@ static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk,
if (err)
goto done;
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
if (flags & MSG_TRUNC)
copied = skb->len;
@@ -318,7 +318,6 @@ out:
static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
if (sock_queue_rcv_skb(sk, skb) < 0) {
- atomic_inc(&sk->sk_drops);
kfree_skb(skb);
return NET_RX_DROP;
}
diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c
index 30e74eee07d6..9c9b85c00033 100644
--- a/net/ieee802154/raw.c
+++ b/net/ieee802154/raw.c
@@ -191,7 +191,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
if (err)
goto done;
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
if (flags & MSG_TRUNC)
copied = skb->len;
@@ -206,7 +206,6 @@ out:
static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
if (sock_queue_rcv_skb(sk, skb) < 0) {
- atomic_inc(&sk->sk_drops);
kfree_skb(skb);
return NET_RX_DROP;
}
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 70491d9035eb..0c94a1ac2946 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -166,7 +166,7 @@ config IP_PNP_DHCP
If unsure, say Y. Note that if you want to use DHCP, a DHCP server
must be operating on your network. Read
- <file:Documentation/filesystems/nfsroot.txt> for details.
+ <file:Documentation/filesystems/nfs/nfsroot.txt> for details.
config IP_PNP_BOOTP
bool "IP: BOOTP support"
@@ -181,7 +181,7 @@ config IP_PNP_BOOTP
does BOOTP itself, providing all necessary information on the kernel
command line, you can say N here. If unsure, say Y. Note that if you
want to use BOOTP, a BOOTP server must be operating on your network.
- Read <file:Documentation/filesystems/nfsroot.txt> for details.
+ Read <file:Documentation/filesystems/nfs/nfsroot.txt> for details.
config IP_PNP_RARP
bool "IP: RARP support"
@@ -194,7 +194,7 @@ config IP_PNP_RARP
older protocol which is being obsoleted by BOOTP and DHCP), say Y
here. Note that if you want to use RARP, a RARP server must be
operating on your network. Read
- <file:Documentation/filesystems/nfsroot.txt> for details.
+ <file:Documentation/filesystems/nfs/nfsroot.txt> for details.
# not yet ready..
# bool ' IP: ARP support' CONFIG_IP_PNP_ARP
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 57737b8d1711..04a14b1600ac 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -174,12 +174,12 @@ static int inet_autobind(struct sock *sk)
/* We may need to bind the socket. */
lock_sock(sk);
inet = inet_sk(sk);
- if (!inet->num) {
+ if (!inet->inet_num) {
if (sk->sk_prot->get_port(sk, 0)) {
release_sock(sk);
return -EAGAIN;
}
- inet->sport = htons(inet->num);
+ inet->inet_sport = htons(inet->inet_num);
}
release_sock(sk);
return 0;
@@ -354,7 +354,7 @@ lookup_protocol:
inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0;
if (SOCK_RAW == sock->type) {
- inet->num = protocol;
+ inet->inet_num = protocol;
if (IPPROTO_RAW == protocol)
inet->hdrincl = 1;
}
@@ -364,7 +364,7 @@ lookup_protocol:
else
inet->pmtudisc = IP_PMTUDISC_WANT;
- inet->id = 0;
+ inet->inet_id = 0;
sock_init_data(sock, sk);
@@ -381,13 +381,13 @@ lookup_protocol:
sk_refcnt_debug_inc(sk);
- if (inet->num) {
+ if (inet->inet_num) {
/* It assumes that any protocol which allows
* the user to assign a number at socket
* creation time automatically
* shares.
*/
- inet->sport = htons(inet->num);
+ inet->inet_sport = htons(inet->inet_num);
/* Add to protocol hash chains. */
sk->sk_prot->hash(sk);
}
@@ -494,27 +494,27 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
/* Check these errors (active socket, double bind). */
err = -EINVAL;
- if (sk->sk_state != TCP_CLOSE || inet->num)
+ if (sk->sk_state != TCP_CLOSE || inet->inet_num)
goto out_release_sock;
- inet->rcv_saddr = inet->saddr = addr->sin_addr.s_addr;
+ inet->inet_rcv_saddr = inet->inet_saddr = addr->sin_addr.s_addr;
if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
- inet->saddr = 0; /* Use device */
+ inet->inet_saddr = 0; /* Use device */
/* Make sure we are allowed to bind here. */
if (sk->sk_prot->get_port(sk, snum)) {
- inet->saddr = inet->rcv_saddr = 0;
+ inet->inet_saddr = inet->inet_rcv_saddr = 0;
err = -EADDRINUSE;
goto out_release_sock;
}
- if (inet->rcv_saddr)
+ if (inet->inet_rcv_saddr)
sk->sk_userlocks |= SOCK_BINDADDR_LOCK;
if (snum)
sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
- inet->sport = htons(inet->num);
- inet->daddr = 0;
- inet->dport = 0;
+ inet->inet_sport = htons(inet->inet_num);
+ inet->inet_daddr = 0;
+ inet->inet_dport = 0;
sk_dst_reset(sk);
err = 0;
out_release_sock:
@@ -532,7 +532,7 @@ int inet_dgram_connect(struct socket *sock, struct sockaddr * uaddr,
if (uaddr->sa_family == AF_UNSPEC)
return sk->sk_prot->disconnect(sk, flags);
- if (!inet_sk(sk)->num && inet_autobind(sk))
+ if (!inet_sk(sk)->inet_num && inet_autobind(sk))
return -EAGAIN;
return sk->sk_prot->connect(sk, (struct sockaddr *)uaddr, addr_len);
}
@@ -689,17 +689,17 @@ int inet_getname(struct socket *sock, struct sockaddr *uaddr,
sin->sin_family = AF_INET;
if (peer) {
- if (!inet->dport ||
+ if (!inet->inet_dport ||
(((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) &&
peer == 1))
return -ENOTCONN;
- sin->sin_port = inet->dport;
- sin->sin_addr.s_addr = inet->daddr;
+ sin->sin_port = inet->inet_dport;
+ sin->sin_addr.s_addr = inet->inet_daddr;
} else {
- __be32 addr = inet->rcv_saddr;
+ __be32 addr = inet->inet_rcv_saddr;
if (!addr)
- addr = inet->saddr;
- sin->sin_port = inet->sport;
+ addr = inet->inet_saddr;
+ sin->sin_port = inet->inet_sport;
sin->sin_addr.s_addr = addr;
}
memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
@@ -714,7 +714,7 @@ int inet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
struct sock *sk = sock->sk;
/* We may need to bind the socket. */
- if (!inet_sk(sk)->num && inet_autobind(sk))
+ if (!inet_sk(sk)->inet_num && inet_autobind(sk))
return -EAGAIN;
return sk->sk_prot->sendmsg(iocb, sk, msg, size);
@@ -728,7 +728,7 @@ static ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset,
struct sock *sk = sock->sk;
/* We may need to bind the socket. */
- if (!inet_sk(sk)->num && inet_autobind(sk))
+ if (!inet_sk(sk)->inet_num && inet_autobind(sk))
return -EAGAIN;
if (sk->sk_prot->sendpage)
@@ -931,7 +931,7 @@ static const struct proto_ops inet_sockraw_ops = {
#endif
};
-static struct net_proto_family inet_family_ops = {
+static const struct net_proto_family inet_family_ops = {
.family = PF_INET,
.create = inet_create,
.owner = THIS_MODULE,
@@ -1059,9 +1059,9 @@ static int inet_sk_reselect_saddr(struct sock *sk)
struct inet_sock *inet = inet_sk(sk);
int err;
struct rtable *rt;
- __be32 old_saddr = inet->saddr;
+ __be32 old_saddr = inet->inet_saddr;
__be32 new_saddr;
- __be32 daddr = inet->daddr;
+ __be32 daddr = inet->inet_daddr;
if (inet->opt && inet->opt->srr)
daddr = inet->opt->faddr;
@@ -1071,7 +1071,7 @@ static int inet_sk_reselect_saddr(struct sock *sk)
RT_CONN_FLAGS(sk),
sk->sk_bound_dev_if,
sk->sk_protocol,
- inet->sport, inet->dport, sk, 0);
+ inet->inet_sport, inet->inet_dport, sk, 0);
if (err)
return err;
@@ -1087,7 +1087,7 @@ static int inet_sk_reselect_saddr(struct sock *sk)
__func__, &old_saddr, &new_saddr);
}
- inet->saddr = inet->rcv_saddr = new_saddr;
+ inet->inet_saddr = inet->inet_rcv_saddr = new_saddr;
/*
* XXX The only one ugly spot where we need to
@@ -1113,7 +1113,7 @@ int inet_sk_rebuild_header(struct sock *sk)
return 0;
/* Reroute. */
- daddr = inet->daddr;
+ daddr = inet->inet_daddr;
if (inet->opt && inet->opt->srr)
daddr = inet->opt->faddr;
{
@@ -1123,7 +1123,7 @@ int inet_sk_rebuild_header(struct sock *sk)
.nl_u = {
.ip4_u = {
.daddr = daddr,
- .saddr = inet->saddr,
+ .saddr = inet->inet_saddr,
.tos = RT_CONN_FLAGS(sk),
},
},
@@ -1131,8 +1131,8 @@ int inet_sk_rebuild_header(struct sock *sk)
.flags = inet_sk_flowi_flags(sk),
.uli_u = {
.ports = {
- .sport = inet->sport,
- .dport = inet->dport,
+ .sport = inet->inet_sport,
+ .dport = inet->inet_dport,
},
},
};
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index 5c662703eb1e..d07b0c1dd350 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -1,3 +1,4 @@
+#include <crypto/hash.h>
#include <linux/err.h>
#include <linux/module.h>
#include <net/ip.h>
@@ -5,10 +6,67 @@
#include <net/ah.h>
#include <linux/crypto.h>
#include <linux/pfkeyv2.h>
-#include <linux/spinlock.h>
+#include <linux/scatterlist.h>
#include <net/icmp.h>
#include <net/protocol.h>
+struct ah_skb_cb {
+ struct xfrm_skb_cb xfrm;
+ void *tmp;
+};
+
+#define AH_SKB_CB(__skb) ((struct ah_skb_cb *)&((__skb)->cb[0]))
+
+static void *ah_alloc_tmp(struct crypto_ahash *ahash, int nfrags,
+ unsigned int size)
+{
+ unsigned int len;
+
+ len = size + crypto_ahash_digestsize(ahash) +
+ (crypto_ahash_alignmask(ahash) &
+ ~(crypto_tfm_ctx_alignment() - 1));
+
+ len = ALIGN(len, crypto_tfm_ctx_alignment());
+
+ len += sizeof(struct ahash_request) + crypto_ahash_reqsize(ahash);
+ len = ALIGN(len, __alignof__(struct scatterlist));
+
+ len += sizeof(struct scatterlist) * nfrags;
+
+ return kmalloc(len, GFP_ATOMIC);
+}
+
+static inline u8 *ah_tmp_auth(void *tmp, unsigned int offset)
+{
+ return tmp + offset;
+}
+
+static inline u8 *ah_tmp_icv(struct crypto_ahash *ahash, void *tmp,
+ unsigned int offset)
+{
+ return PTR_ALIGN((u8 *)tmp + offset, crypto_ahash_alignmask(ahash) + 1);
+}
+
+static inline struct ahash_request *ah_tmp_req(struct crypto_ahash *ahash,
+ u8 *icv)
+{
+ struct ahash_request *req;
+
+ req = (void *)PTR_ALIGN(icv + crypto_ahash_digestsize(ahash),
+ crypto_tfm_ctx_alignment());
+
+ ahash_request_set_tfm(req, ahash);
+
+ return req;
+}
+
+static inline struct scatterlist *ah_req_sg(struct crypto_ahash *ahash,
+ struct ahash_request *req)
+{
+ return (void *)ALIGN((unsigned long)(req + 1) +
+ crypto_ahash_reqsize(ahash),
+ __alignof__(struct scatterlist));
+}
/* Clear mutable options and find final destination to substitute
* into IP header for icv calculation. Options are already checked
@@ -54,20 +112,72 @@ static int ip_clear_mutable_options(struct iphdr *iph, __be32 *daddr)
return 0;
}
+static void ah_output_done(struct crypto_async_request *base, int err)
+{
+ u8 *icv;
+ struct iphdr *iph;
+ struct sk_buff *skb = base->data;
+ struct xfrm_state *x = skb_dst(skb)->xfrm;
+ struct ah_data *ahp = x->data;
+ struct iphdr *top_iph = ip_hdr(skb);
+ struct ip_auth_hdr *ah = ip_auth_hdr(skb);
+ int ihl = ip_hdrlen(skb);
+
+ iph = AH_SKB_CB(skb)->tmp;
+ icv = ah_tmp_icv(ahp->ahash, iph, ihl);
+ memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
+
+ top_iph->tos = iph->tos;
+ top_iph->ttl = iph->ttl;
+ top_iph->frag_off = iph->frag_off;
+ if (top_iph->ihl != 5) {
+ top_iph->daddr = iph->daddr;
+ memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr));
+ }
+
+ err = ah->nexthdr;
+
+ kfree(AH_SKB_CB(skb)->tmp);
+ xfrm_output_resume(skb, err);
+}
+
static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
{
int err;
+ int nfrags;
+ int ihl;
+ u8 *icv;
+ struct sk_buff *trailer;
+ struct crypto_ahash *ahash;
+ struct ahash_request *req;
+ struct scatterlist *sg;
struct iphdr *iph, *top_iph;
struct ip_auth_hdr *ah;
struct ah_data *ahp;
- union {
- struct iphdr iph;
- char buf[60];
- } tmp_iph;
+
+ ahp = x->data;
+ ahash = ahp->ahash;
+
+ if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
+ goto out;
+ nfrags = err;
skb_push(skb, -skb_network_offset(skb));
+ ah = ip_auth_hdr(skb);
+ ihl = ip_hdrlen(skb);
+
+ err = -ENOMEM;
+ iph = ah_alloc_tmp(ahash, nfrags, ihl);
+ if (!iph)
+ goto out;
+
+ icv = ah_tmp_icv(ahash, iph, ihl);
+ req = ah_tmp_req(ahash, icv);
+ sg = ah_req_sg(ahash, req);
+
+ memset(ah->auth_data, 0, ahp->icv_trunc_len);
+
top_iph = ip_hdr(skb);
- iph = &tmp_iph.iph;
iph->tos = top_iph->tos;
iph->ttl = top_iph->ttl;
@@ -78,10 +188,9 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
memcpy(iph+1, top_iph+1, top_iph->ihl*4 - sizeof(struct iphdr));
err = ip_clear_mutable_options(top_iph, &top_iph->daddr);
if (err)
- goto error;
+ goto out_free;
}
- ah = ip_auth_hdr(skb);
ah->nexthdr = *skb_mac_header(skb);
*skb_mac_header(skb) = IPPROTO_AH;
@@ -91,20 +200,31 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
top_iph->ttl = 0;
top_iph->check = 0;
- ahp = x->data;
ah->hdrlen = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2;
ah->reserved = 0;
ah->spi = x->id.spi;
ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output);
- spin_lock_bh(&x->lock);
- err = ah_mac_digest(ahp, skb, ah->auth_data);
- memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len);
- spin_unlock_bh(&x->lock);
+ sg_init_table(sg, nfrags);
+ skb_to_sgvec(skb, sg, 0, skb->len);
- if (err)
- goto error;
+ ahash_request_set_crypt(req, sg, icv, skb->len);
+ ahash_request_set_callback(req, 0, ah_output_done, skb);
+
+ AH_SKB_CB(skb)->tmp = iph;
+
+ err = crypto_ahash_digest(req);
+ if (err) {
+ if (err == -EINPROGRESS)
+ goto out;
+
+ if (err == -EBUSY)
+ err = NET_XMIT_DROP;
+ goto out_free;
+ }
+
+ memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
top_iph->tos = iph->tos;
top_iph->ttl = iph->ttl;
@@ -114,28 +234,67 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr));
}
- err = 0;
-
-error:
+out_free:
+ kfree(iph);
+out:
return err;
}
+static void ah_input_done(struct crypto_async_request *base, int err)
+{
+ u8 *auth_data;
+ u8 *icv;
+ struct iphdr *work_iph;
+ struct sk_buff *skb = base->data;
+ struct xfrm_state *x = xfrm_input_state(skb);
+ struct ah_data *ahp = x->data;
+ struct ip_auth_hdr *ah = ip_auth_hdr(skb);
+ int ihl = ip_hdrlen(skb);
+ int ah_hlen = (ah->hdrlen + 2) << 2;
+
+ work_iph = AH_SKB_CB(skb)->tmp;
+ auth_data = ah_tmp_auth(work_iph, ihl);
+ icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len);
+
+ err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0;
+ if (err)
+ goto out;
+
+ skb->network_header += ah_hlen;
+ memcpy(skb_network_header(skb), work_iph, ihl);
+ __skb_pull(skb, ah_hlen + ihl);
+ skb_set_transport_header(skb, -ihl);
+
+ err = ah->nexthdr;
+out:
+ kfree(AH_SKB_CB(skb)->tmp);
+ xfrm_input_resume(skb, err);
+}
+
static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
{
int ah_hlen;
int ihl;
int nexthdr;
- int err = -EINVAL;
- struct iphdr *iph;
+ int nfrags;
+ u8 *auth_data;
+ u8 *icv;
+ struct sk_buff *trailer;
+ struct crypto_ahash *ahash;
+ struct ahash_request *req;
+ struct scatterlist *sg;
+ struct iphdr *iph, *work_iph;
struct ip_auth_hdr *ah;
struct ah_data *ahp;
- char work_buf[60];
+ int err = -ENOMEM;
if (!pskb_may_pull(skb, sizeof(*ah)))
goto out;
ah = (struct ip_auth_hdr *)skb->data;
ahp = x->data;
+ ahash = ahp->ahash;
+
nexthdr = ah->nexthdr;
ah_hlen = (ah->hdrlen + 2) << 2;
@@ -156,9 +315,24 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
ah = (struct ip_auth_hdr *)skb->data;
iph = ip_hdr(skb);
+ ihl = ip_hdrlen(skb);
+
+ if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
+ goto out;
+ nfrags = err;
+
+ work_iph = ah_alloc_tmp(ahash, nfrags, ihl + ahp->icv_trunc_len);
+ if (!work_iph)
+ goto out;
+
+ auth_data = ah_tmp_auth(work_iph, ihl);
+ icv = ah_tmp_icv(ahash, auth_data, ahp->icv_trunc_len);
+ req = ah_tmp_req(ahash, icv);
+ sg = ah_req_sg(ahash, req);
- ihl = skb->data - skb_network_header(skb);
- memcpy(work_buf, iph, ihl);
+ memcpy(work_iph, iph, ihl);
+ memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
+ memset(ah->auth_data, 0, ahp->icv_trunc_len);
iph->ttl = 0;
iph->tos = 0;
@@ -166,35 +340,44 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
iph->check = 0;
if (ihl > sizeof(*iph)) {
__be32 dummy;
- if (ip_clear_mutable_options(iph, &dummy))
- goto out;
+ err = ip_clear_mutable_options(iph, &dummy);
+ if (err)
+ goto out_free;
}
- spin_lock(&x->lock);
- {
- u8 auth_data[MAX_AH_AUTH_LEN];
+ skb_push(skb, ihl);
- memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
- skb_push(skb, ihl);
- err = ah_mac_digest(ahp, skb, ah->auth_data);
- if (err)
- goto unlock;
- if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len))
- err = -EBADMSG;
+ sg_init_table(sg, nfrags);
+ skb_to_sgvec(skb, sg, 0, skb->len);
+
+ ahash_request_set_crypt(req, sg, icv, skb->len);
+ ahash_request_set_callback(req, 0, ah_input_done, skb);
+
+ AH_SKB_CB(skb)->tmp = work_iph;
+
+ err = crypto_ahash_digest(req);
+ if (err) {
+ if (err == -EINPROGRESS)
+ goto out;
+
+ if (err == -EBUSY)
+ err = NET_XMIT_DROP;
+ goto out_free;
}
-unlock:
- spin_unlock(&x->lock);
+ err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0;
if (err)
- goto out;
+ goto out_free;
skb->network_header += ah_hlen;
- memcpy(skb_network_header(skb), work_buf, ihl);
- skb->transport_header = skb->network_header;
+ memcpy(skb_network_header(skb), work_iph, ihl);
__skb_pull(skb, ah_hlen + ihl);
+ skb_set_transport_header(skb, -ihl);
- return nexthdr;
+ err = nexthdr;
+out_free:
+ kfree (work_iph);
out:
return err;
}
@@ -222,7 +405,7 @@ static int ah_init_state(struct xfrm_state *x)
{
struct ah_data *ahp = NULL;
struct xfrm_algo_desc *aalg_desc;
- struct crypto_hash *tfm;
+ struct crypto_ahash *ahash;
if (!x->aalg)
goto error;
@@ -231,31 +414,31 @@ static int ah_init_state(struct xfrm_state *x)
goto error;
ahp = kzalloc(sizeof(*ahp), GFP_KERNEL);
- if (ahp == NULL)
+ if (!ahp)
return -ENOMEM;
- tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(tfm))
+ ahash = crypto_alloc_ahash(x->aalg->alg_name, 0, 0);
+ if (IS_ERR(ahash))
goto error;
- ahp->tfm = tfm;
- if (crypto_hash_setkey(tfm, x->aalg->alg_key,
- (x->aalg->alg_key_len + 7) / 8))
+ ahp->ahash = ahash;
+ if (crypto_ahash_setkey(ahash, x->aalg->alg_key,
+ (x->aalg->alg_key_len + 7) / 8))
goto error;
/*
* Lookup the algorithm description maintained by xfrm_algo,
* verify crypto transform properties, and store information
* we need for AH processing. This lookup cannot fail here
- * after a successful crypto_alloc_hash().
+ * after a successful crypto_alloc_ahash().
*/
aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
BUG_ON(!aalg_desc);
if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
- crypto_hash_digestsize(tfm)) {
+ crypto_ahash_digestsize(ahash)) {
printk(KERN_INFO "AH: %s digestsize %u != %hu\n",
- x->aalg->alg_name, crypto_hash_digestsize(tfm),
+ x->aalg->alg_name, crypto_ahash_digestsize(ahash),
aalg_desc->uinfo.auth.icv_fullbits/8);
goto error;
}
@@ -265,10 +448,6 @@ static int ah_init_state(struct xfrm_state *x)
BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN);
- ahp->work_icv = kmalloc(ahp->icv_full_len, GFP_KERNEL);
- if (!ahp->work_icv)
- goto error;
-
x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) +
ahp->icv_trunc_len);
if (x->props.mode == XFRM_MODE_TUNNEL)
@@ -279,8 +458,7 @@ static int ah_init_state(struct xfrm_state *x)
error:
if (ahp) {
- kfree(ahp->work_icv);
- crypto_free_hash(ahp->tfm);
+ crypto_free_ahash(ahp->ahash);
kfree(ahp);
}
return -EINVAL;
@@ -293,8 +471,7 @@ static void ah_destroy(struct xfrm_state *x)
if (!ahp)
return;
- kfree(ahp->work_icv);
- crypto_free_hash(ahp->tfm);
+ crypto_free_ahash(ahp->ahash);
kfree(ahp);
}
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 039cc1ffe977..1e029dc75455 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -2017,7 +2017,7 @@ req_setattr_failure:
* values on failure.
*
*/
-int cipso_v4_delopt(struct ip_options **opt_ptr)
+static int cipso_v4_delopt(struct ip_options **opt_ptr)
{
int hdr_delta = 0;
struct ip_options *opt = *opt_ptr;
diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c
index 5e6c5a0f3fde..fb2465811b48 100644
--- a/net/ipv4/datagram.c
+++ b/net/ipv4/datagram.c
@@ -39,7 +39,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
sk_dst_reset(sk);
oif = sk->sk_bound_dev_if;
- saddr = inet->saddr;
+ saddr = inet->inet_saddr;
if (ipv4_is_multicast(usin->sin_addr.s_addr)) {
if (!oif)
oif = inet->mc_index;
@@ -49,7 +49,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
err = ip_route_connect(&rt, usin->sin_addr.s_addr, saddr,
RT_CONN_FLAGS(sk), oif,
sk->sk_protocol,
- inet->sport, usin->sin_port, sk, 1);
+ inet->inet_sport, usin->sin_port, sk, 1);
if (err) {
if (err == -ENETUNREACH)
IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
@@ -60,14 +60,14 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
ip_rt_put(rt);
return -EACCES;
}
- if (!inet->saddr)
- inet->saddr = rt->rt_src; /* Update source address */
- if (!inet->rcv_saddr)
- inet->rcv_saddr = rt->rt_src;
- inet->daddr = rt->rt_dst;
- inet->dport = usin->sin_port;
+ if (!inet->inet_saddr)
+ inet->inet_saddr = rt->rt_src; /* Update source address */
+ if (!inet->inet_rcv_saddr)
+ inet->inet_rcv_saddr = rt->rt_src;
+ inet->inet_daddr = rt->rt_dst;
+ inet->inet_dport = usin->sin_port;
sk->sk_state = TCP_ESTABLISHED;
- inet->id = jiffies;
+ inet->inet_id = jiffies;
sk_dst_set(sk, &rt->u.dst);
return(0);
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index e2f950592566..f73dbed0f0d7 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -125,7 +125,7 @@ void fib_select_default(struct net *net,
#endif
tb = fib_get_table(net, table);
if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
- tb->tb_select_default(tb, flp, res);
+ fib_table_select_default(tb, flp, res);
}
static void fib_flush(struct net *net)
@@ -139,7 +139,7 @@ static void fib_flush(struct net *net)
for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
head = &net->ipv4.fib_table_hash[h];
hlist_for_each_entry(tb, node, head, tb_hlist)
- flushed += tb->tb_flush(tb);
+ flushed += fib_table_flush(tb);
}
if (flushed)
@@ -162,7 +162,7 @@ struct net_device * ip_dev_find(struct net *net, __be32 addr)
#endif
local_table = fib_get_table(net, RT_TABLE_LOCAL);
- if (!local_table || local_table->tb_lookup(local_table, &fl, &res))
+ if (!local_table || fib_table_lookup(local_table, &fl, &res))
return NULL;
if (res.type != RTN_LOCAL)
goto out;
@@ -200,7 +200,7 @@ 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 (!local_table->tb_lookup(local_table, &fl, &res)) {
+ if (!fib_table_lookup(local_table, &fl, &res)) {
if (!dev || dev == res.fi->fib_dev)
ret = res.type;
fib_res_put(&res);
@@ -473,13 +473,13 @@ int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg)
if (cmd == SIOCDELRT) {
tb = fib_get_table(net, cfg.fc_table);
if (tb)
- err = tb->tb_delete(tb, &cfg);
+ err = fib_table_delete(tb, &cfg);
else
err = -ESRCH;
} else {
tb = fib_new_table(net, cfg.fc_table);
if (tb)
- err = tb->tb_insert(tb, &cfg);
+ err = fib_table_insert(tb, &cfg);
else
err = -ENOBUFS;
}
@@ -594,7 +594,7 @@ static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *ar
goto errout;
}
- err = tb->tb_delete(tb, &cfg);
+ err = fib_table_delete(tb, &cfg);
errout:
return err;
}
@@ -616,7 +616,7 @@ static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *ar
goto errout;
}
- err = tb->tb_insert(tb, &cfg);
+ err = fib_table_insert(tb, &cfg);
errout:
return err;
}
@@ -647,7 +647,7 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
if (dumped)
memset(&cb->args[2], 0, sizeof(cb->args) -
2 * sizeof(cb->args[0]));
- if (tb->tb_dump(tb, skb, cb) < 0)
+ if (fib_table_dump(tb, skb, cb) < 0)
goto out;
dumped = 1;
next:
@@ -701,9 +701,9 @@ static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifad
cfg.fc_scope = RT_SCOPE_HOST;
if (cmd == RTM_NEWROUTE)
- tb->tb_insert(tb, &cfg);
+ fib_table_insert(tb, &cfg);
else
- tb->tb_delete(tb, &cfg);
+ fib_table_delete(tb, &cfg);
}
void fib_add_ifaddr(struct in_ifaddr *ifa)
@@ -832,7 +832,7 @@ 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 = tb->tb_lookup(tb, &fl, &res);
+ frn->err = fib_table_lookup(tb, &fl, &res);
if (!frn->err) {
frn->prefixlen = res.prefixlen;
@@ -1009,7 +1009,7 @@ static void __net_exit ip_fib_net_exit(struct net *net)
head = &net->ipv4.fib_table_hash[i];
hlist_for_each_entry_safe(tb, node, tmp, head, tb_hlist) {
hlist_del(node);
- tb->tb_flush(tb);
+ fib_table_flush(tb);
kfree(tb);
}
}
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
index ecd39454235c..14972017b9c2 100644
--- a/net/ipv4/fib_hash.c
+++ b/net/ipv4/fib_hash.c
@@ -242,8 +242,8 @@ fn_new_zone(struct fn_hash *table, int z)
return fz;
}
-static int
-fn_hash_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
+int fib_table_lookup(struct fib_table *tb,
+ const struct flowi *flp, struct fib_result *res)
{
int err;
struct fn_zone *fz;
@@ -274,8 +274,8 @@ out:
return err;
}
-static void
-fn_hash_select_default(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
+void fib_table_select_default(struct fib_table *tb,
+ const struct flowi *flp, struct fib_result *res)
{
int order, last_idx;
struct hlist_node *node;
@@ -366,7 +366,7 @@ static struct fib_node *fib_find_node(struct fn_zone *fz, __be32 key)
return NULL;
}
-static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg)
+int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
{
struct fn_hash *table = (struct fn_hash *) tb->tb_data;
struct fib_node *new_f = NULL;
@@ -544,8 +544,7 @@ out:
return err;
}
-
-static int fn_hash_delete(struct fib_table *tb, struct fib_config *cfg)
+int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
{
struct fn_hash *table = (struct fn_hash *)tb->tb_data;
struct fib_node *f;
@@ -662,7 +661,7 @@ static int fn_flush_list(struct fn_zone *fz, int idx)
return found;
}
-static int fn_hash_flush(struct fib_table *tb)
+int fib_table_flush(struct fib_table *tb)
{
struct fn_hash *table = (struct fn_hash *) tb->tb_data;
struct fn_zone *fz;
@@ -743,7 +742,8 @@ fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb,
return skb->len;
}
-static int fn_hash_dump(struct fib_table *tb, 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;
struct fn_zone *fz;
@@ -787,12 +787,7 @@ struct fib_table *fib_hash_table(u32 id)
tb->tb_id = id;
tb->tb_default = -1;
- tb->tb_lookup = fn_hash_lookup;
- tb->tb_insert = fn_hash_insert;
- tb->tb_delete = fn_hash_delete;
- tb->tb_flush = fn_hash_flush;
- tb->tb_select_default = fn_hash_select_default;
- tb->tb_dump = fn_hash_dump;
+
memset(tb->tb_data, 0, sizeof(struct fn_hash));
return tb;
}
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 92d9d97ec5e3..835262c2b867 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -94,7 +94,7 @@ static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp,
if ((tbl = fib_get_table(rule->fr_net, rule->table)) == NULL)
goto errout;
- err = tbl->tb_lookup(tbl, flp, (struct fib_result *) arg->result);
+ err = fib_table_lookup(tbl, flp, (struct fib_result *) arg->result);
if (err > 0)
err = -EAGAIN;
errout:
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 291bdf50a21f..af5d89792860 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1174,7 +1174,7 @@ done:
/*
* Caller must hold RTNL.
*/
-static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
+int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
{
struct trie *t = (struct trie *) tb->tb_data;
struct fib_alias *fa, *new_fa;
@@ -1373,8 +1373,8 @@ static int check_leaf(struct trie *t, struct leaf *l,
return 1;
}
-static int fn_trie_lookup(struct fib_table *tb, const struct flowi *flp,
- struct fib_result *res)
+int fib_table_lookup(struct fib_table *tb, const struct flowi *flp,
+ struct fib_result *res)
{
struct trie *t = (struct trie *) tb->tb_data;
int ret;
@@ -1595,7 +1595,7 @@ static void trie_leaf_remove(struct trie *t, struct leaf *l)
/*
* Caller must hold RTNL.
*/
-static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
+int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
{
struct trie *t = (struct trie *) tb->tb_data;
u32 key, mask;
@@ -1786,7 +1786,7 @@ static struct leaf *trie_leafindex(struct trie *t, int index)
/*
* Caller must hold RTNL.
*/
-static int fn_trie_flush(struct fib_table *tb)
+int fib_table_flush(struct fib_table *tb)
{
struct trie *t = (struct trie *) tb->tb_data;
struct leaf *l, *ll = NULL;
@@ -1807,9 +1807,9 @@ static int fn_trie_flush(struct fib_table *tb)
return found;
}
-static void fn_trie_select_default(struct fib_table *tb,
- const struct flowi *flp,
- struct fib_result *res)
+void fib_table_select_default(struct fib_table *tb,
+ const struct flowi *flp,
+ struct fib_result *res)
{
struct trie *t = (struct trie *) tb->tb_data;
int order, last_idx;
@@ -1952,8 +1952,8 @@ static int fn_trie_dump_leaf(struct leaf *l, struct fib_table *tb,
return skb->len;
}
-static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb,
- struct netlink_callback *cb)
+int fib_table_dump(struct fib_table *tb, struct sk_buff *skb,
+ struct netlink_callback *cb)
{
struct leaf *l;
struct trie *t = (struct trie *) tb->tb_data;
@@ -2020,12 +2020,6 @@ struct fib_table *fib_hash_table(u32 id)
tb->tb_id = id;
tb->tb_default = -1;
- tb->tb_lookup = fn_trie_lookup;
- tb->tb_insert = fn_trie_insert;
- tb->tb_delete = fn_trie_delete;
- tb->tb_flush = fn_trie_flush;
- tb->tb_select_default = fn_trie_select_default;
- tb->tb_dump = fn_trie_dump;
t = (struct trie *) tb->tb_data;
memset(t, 0, sizeof(*t));
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 5bc13fe816d1..84adb5754c96 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -1165,6 +1165,10 @@ static int __net_init icmp_sk_init(struct net *net)
sk->sk_sndbuf =
(2 * ((64 * 1024) + sizeof(struct sk_buff)));
+ /*
+ * Speedup sock_wfree()
+ */
+ sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
inet_sk(sk)->pmtudisc = IP_PMTUDISC_DONT;
}
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 4351ca2cf0b8..26fb50e91311 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -358,6 +358,7 @@ struct dst_entry *inet_csk_route_req(struct sock *sk,
const struct inet_request_sock *ireq = inet_rsk(req);
struct ip_options *opt = inet_rsk(req)->opt;
struct flowi fl = { .oif = sk->sk_bound_dev_if,
+ .mark = sk->sk_mark,
.nl_u = { .ip4_u =
{ .daddr = ((opt && opt->srr) ?
opt->faddr :
@@ -367,7 +368,7 @@ struct dst_entry *inet_csk_route_req(struct sock *sk,
.proto = sk->sk_protocol,
.flags = inet_sk_flowi_flags(sk),
.uli_u = { .ports =
- { .sport = inet_sk(sk)->sport,
+ { .sport = inet_sk(sk)->inet_sport,
.dport = ireq->rmt_port } } };
struct net *net = sock_net(sk);
@@ -446,6 +447,28 @@ extern int sysctl_tcp_synack_retries;
EXPORT_SYMBOL_GPL(inet_csk_reqsk_queue_hash_add);
+/* Decide when to expire the request and when to resend SYN-ACK */
+static inline void syn_ack_recalc(struct request_sock *req, const int thresh,
+ const int max_retries,
+ const u8 rskq_defer_accept,
+ int *expire, int *resend)
+{
+ if (!rskq_defer_accept) {
+ *expire = req->retrans >= thresh;
+ *resend = 1;
+ return;
+ }
+ *expire = req->retrans >= thresh &&
+ (!inet_rsk(req)->acked || req->retrans >= max_retries);
+ /*
+ * Do not resend while waiting for data after ACK,
+ * start to resend on end of deferring period to give
+ * last chance for data or ACK to create established socket.
+ */
+ *resend = !inet_rsk(req)->acked ||
+ req->retrans >= rskq_defer_accept - 1;
+}
+
void inet_csk_reqsk_queue_prune(struct sock *parent,
const unsigned long interval,
const unsigned long timeout,
@@ -501,9 +524,15 @@ void inet_csk_reqsk_queue_prune(struct sock *parent,
reqp=&lopt->syn_table[i];
while ((req = *reqp) != NULL) {
if (time_after_eq(now, req->expires)) {
- if ((req->retrans < thresh ||
- (inet_rsk(req)->acked && req->retrans < max_retries))
- && !req->rsk_ops->rtx_syn_ack(parent, req)) {
+ int expire = 0, resend = 0;
+
+ syn_ack_recalc(req, thresh, max_retries,
+ queue->rskq_defer_accept,
+ &expire, &resend);
+ if (!expire &&
+ (!resend ||
+ !req->rsk_ops->rtx_syn_ack(parent, req) ||
+ inet_rsk(req)->acked)) {
unsigned long timeo;
if (req->retrans++ == 0)
@@ -546,9 +575,9 @@ struct sock *inet_csk_clone(struct sock *sk, const struct request_sock *req,
newsk->sk_state = TCP_SYN_RECV;
newicsk->icsk_bind_hash = NULL;
- inet_sk(newsk)->dport = inet_rsk(req)->rmt_port;
- inet_sk(newsk)->num = ntohs(inet_rsk(req)->loc_port);
- inet_sk(newsk)->sport = inet_rsk(req)->loc_port;
+ inet_sk(newsk)->inet_dport = inet_rsk(req)->rmt_port;
+ inet_sk(newsk)->inet_num = ntohs(inet_rsk(req)->loc_port);
+ inet_sk(newsk)->inet_sport = inet_rsk(req)->loc_port;
newsk->sk_write_space = sk_stream_write_space;
newicsk->icsk_retransmits = 0;
@@ -579,8 +608,8 @@ void inet_csk_destroy_sock(struct sock *sk)
/* It cannot be in hash table! */
WARN_ON(!sk_unhashed(sk));
- /* If it has not 0 inet_sk(sk)->num, it must be bound */
- WARN_ON(inet_sk(sk)->num && !inet_csk(sk)->icsk_bind_hash);
+ /* If it has not 0 inet_sk(sk)->inet_num, it must be bound */
+ WARN_ON(inet_sk(sk)->inet_num && !inet_csk(sk)->icsk_bind_hash);
sk->sk_prot->destroy(sk);
@@ -615,8 +644,8 @@ int inet_csk_listen_start(struct sock *sk, const int nr_table_entries)
* after validation is complete.
*/
sk->sk_state = TCP_LISTEN;
- if (!sk->sk_prot->get_port(sk, inet->num)) {
- inet->sport = htons(inet->num);
+ if (!sk->sk_prot->get_port(sk, inet->inet_num)) {
+ inet->inet_sport = htons(inet->inet_num);
sk_dst_reset(sk);
sk->sk_prot->hash(sk);
@@ -692,8 +721,8 @@ void inet_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr)
const struct inet_sock *inet = inet_sk(sk);
sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = inet->daddr;
- sin->sin_port = inet->dport;
+ sin->sin_addr.s_addr = inet->inet_daddr;
+ sin->sin_port = inet->inet_dport;
}
EXPORT_SYMBOL_GPL(inet_csk_addr2sockaddr);
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index a706a47f4dbb..bdb78dd180ce 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -116,10 +116,10 @@ static int inet_csk_diag_fill(struct sock *sk,
r->id.idiag_cookie[0] = (u32)(unsigned long)sk;
r->id.idiag_cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1);
- r->id.idiag_sport = inet->sport;
- r->id.idiag_dport = inet->dport;
- r->id.idiag_src[0] = inet->rcv_saddr;
- r->id.idiag_dst[0] = inet->daddr;
+ r->id.idiag_sport = inet->inet_sport;
+ r->id.idiag_dport = inet->inet_dport;
+ r->id.idiag_src[0] = inet->inet_rcv_saddr;
+ r->id.idiag_dst[0] = inet->inet_daddr;
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
if (r->idiag_family == AF_INET6) {
@@ -504,11 +504,11 @@ static int inet_csk_diag_dump(struct sock *sk,
} else
#endif
{
- entry.saddr = &inet->rcv_saddr;
- entry.daddr = &inet->daddr;
+ entry.saddr = &inet->inet_rcv_saddr;
+ entry.daddr = &inet->inet_daddr;
}
- entry.sport = inet->num;
- entry.dport = ntohs(inet->dport);
+ entry.sport = inet->inet_num;
+ entry.dport = ntohs(inet->inet_dport);
entry.userlocks = sk->sk_userlocks;
if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
@@ -584,7 +584,7 @@ static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
if (tmo < 0)
tmo = 0;
- r->id.idiag_sport = inet->sport;
+ r->id.idiag_sport = inet->inet_sport;
r->id.idiag_dport = ireq->rmt_port;
r->id.idiag_src[0] = ireq->loc_addr;
r->id.idiag_dst[0] = ireq->rmt_addr;
@@ -639,7 +639,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
bc = (struct rtattr *)(r + 1);
- entry.sport = inet->num;
+ entry.sport = inet->inet_num;
entry.userlocks = sk->sk_userlocks;
}
@@ -732,7 +732,7 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
continue;
}
- if (r->id.idiag_sport != inet->sport &&
+ if (r->id.idiag_sport != inet->inet_sport &&
r->id.idiag_sport)
goto next_listen;
@@ -774,7 +774,7 @@ skip_listen_ht:
if (!(r->idiag_states & ~(TCPF_LISTEN | TCPF_SYN_RECV)))
goto unlock;
- for (i = s_i; i < hashinfo->ehash_size; i++) {
+ for (i = s_i; i <= hashinfo->ehash_mask; i++) {
struct inet_ehash_bucket *head = &hashinfo->ehash[i];
spinlock_t *lock = inet_ehash_lockp(hashinfo, i);
struct sock *sk;
@@ -797,10 +797,10 @@ skip_listen_ht:
goto next_normal;
if (!(r->idiag_states & (1 << sk->sk_state)))
goto next_normal;
- if (r->id.idiag_sport != inet->sport &&
+ if (r->id.idiag_sport != inet->inet_sport &&
r->id.idiag_sport)
goto next_normal;
- if (r->id.idiag_dport != inet->dport &&
+ if (r->id.idiag_dport != inet->inet_dport &&
r->id.idiag_dport)
goto next_normal;
if (inet_csk_diag_dump(sk, skb, cb) < 0) {
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 625cc5f64c94..47ad7aab51e3 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -64,7 +64,7 @@ void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb,
atomic_inc(&hashinfo->bsockets);
- inet_sk(sk)->num = snum;
+ inet_sk(sk)->inet_num = snum;
sk_add_bind_node(sk, &tb->owners);
tb->num_owners++;
inet_csk(sk)->icsk_bind_hash = tb;
@@ -76,7 +76,7 @@ void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb,
static void __inet_put_port(struct sock *sk)
{
struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
- const int bhash = inet_bhashfn(sock_net(sk), inet_sk(sk)->num,
+ const int bhash = inet_bhashfn(sock_net(sk), inet_sk(sk)->inet_num,
hashinfo->bhash_size);
struct inet_bind_hashbucket *head = &hashinfo->bhash[bhash];
struct inet_bind_bucket *tb;
@@ -88,7 +88,7 @@ static void __inet_put_port(struct sock *sk)
__sk_del_bind_node(sk);
tb->num_owners--;
inet_csk(sk)->icsk_bind_hash = NULL;
- inet_sk(sk)->num = 0;
+ inet_sk(sk)->inet_num = 0;
inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb);
spin_unlock(&head->lock);
}
@@ -105,7 +105,7 @@ EXPORT_SYMBOL(inet_put_port);
void __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)->num,
+ const int bhash = inet_bhashfn(sock_net(sk), inet_sk(child)->inet_num,
table->bhash_size);
struct inet_bind_hashbucket *head = &table->bhash[bhash];
struct inet_bind_bucket *tb;
@@ -126,9 +126,9 @@ static inline int compute_score(struct sock *sk, struct net *net,
int score = -1;
struct inet_sock *inet = inet_sk(sk);
- if (net_eq(sock_net(sk), net) && inet->num == hnum &&
+ if (net_eq(sock_net(sk), net) && inet->inet_num == hnum &&
!ipv6_only_sock(sk)) {
- __be32 rcv_saddr = inet->rcv_saddr;
+ __be32 rcv_saddr = inet->inet_rcv_saddr;
score = sk->sk_family == PF_INET ? 1 : 0;
if (rcv_saddr) {
if (rcv_saddr != daddr)
@@ -209,7 +209,7 @@ struct sock * __inet_lookup_established(struct net *net,
* have wildcards anyways.
*/
unsigned int hash = inet_ehashfn(net, daddr, hnum, saddr, sport);
- unsigned int slot = hash & (hashinfo->ehash_size - 1);
+ unsigned int slot = hash & hashinfo->ehash_mask;
struct inet_ehash_bucket *head = &hashinfo->ehash[slot];
rcu_read_lock();
@@ -273,13 +273,14 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
{
struct inet_hashinfo *hinfo = death_row->hashinfo;
struct inet_sock *inet = inet_sk(sk);
- __be32 daddr = inet->rcv_saddr;
- __be32 saddr = inet->daddr;
+ __be32 daddr = inet->inet_rcv_saddr;
+ __be32 saddr = inet->inet_daddr;
int dif = sk->sk_bound_dev_if;
INET_ADDR_COOKIE(acookie, saddr, daddr)
- const __portpair ports = INET_COMBINED_PORTS(inet->dport, lport);
+ const __portpair ports = INET_COMBINED_PORTS(inet->inet_dport, lport);
struct net *net = sock_net(sk);
- unsigned int hash = inet_ehashfn(net, daddr, lport, saddr, inet->dport);
+ unsigned int hash = inet_ehashfn(net, daddr, lport,
+ saddr, inet->inet_dport);
struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash);
spinlock_t *lock = inet_ehash_lockp(hinfo, hash);
struct sock *sk2;
@@ -312,8 +313,8 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
unique:
/* Must record num and sport now. Otherwise we will see
* in hash table socket with a funny identity. */
- inet->num = lport;
- inet->sport = htons(lport);
+ inet->inet_num = lport;
+ inet->inet_sport = htons(lport);
sk->sk_hash = hash;
WARN_ON(!sk_unhashed(sk));
__sk_nulls_add_node_rcu(sk, &head->chain);
@@ -341,8 +342,9 @@ not_unique:
static inline u32 inet_sk_port_offset(const struct sock *sk)
{
const struct inet_sock *inet = inet_sk(sk);
- return secure_ipv4_port_ephemeral(inet->rcv_saddr, inet->daddr,
- inet->dport);
+ return secure_ipv4_port_ephemeral(inet->inet_rcv_saddr,
+ inet->inet_daddr,
+ inet->inet_dport);
}
void __inet_hash_nolisten(struct sock *sk)
@@ -424,7 +426,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
void (*hash)(struct sock *sk))
{
struct inet_hashinfo *hinfo = death_row->hashinfo;
- const unsigned short snum = inet_sk(sk)->num;
+ const unsigned short snum = inet_sk(sk)->inet_num;
struct inet_bind_hashbucket *head;
struct inet_bind_bucket *tb;
int ret;
@@ -485,7 +487,7 @@ ok:
/* Head lock still held and bh's disabled */
inet_bind_hash(sk, tb, port);
if (sk_unhashed(sk)) {
- inet_sk(sk)->sport = htons(port);
+ inet_sk(sk)->inet_sport = htons(port);
hash(sk);
}
spin_unlock(&head->lock);
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index 13f0781f35cd..1f5d508bb18b 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -86,7 +86,7 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
Note, that any socket with inet->num != 0 MUST be bound in
binding cache, even if it is closed.
*/
- bhead = &hashinfo->bhash[inet_bhashfn(twsk_net(tw), inet->num,
+ bhead = &hashinfo->bhash[inet_bhashfn(twsk_net(tw), inet->inet_num,
hashinfo->bhash_size)];
spin_lock(&bhead->lock);
tw->tw_tb = icsk->icsk_bind_hash;
@@ -124,14 +124,14 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int stat
kmemcheck_annotate_bitfield(tw, flags);
/* Give us an identity. */
- tw->tw_daddr = inet->daddr;
- tw->tw_rcv_saddr = inet->rcv_saddr;
+ tw->tw_daddr = inet->inet_daddr;
+ tw->tw_rcv_saddr = inet->inet_rcv_saddr;
tw->tw_bound_dev_if = sk->sk_bound_dev_if;
- tw->tw_num = inet->num;
+ tw->tw_num = inet->inet_num;
tw->tw_state = TCP_TIME_WAIT;
tw->tw_substate = state;
- tw->tw_sport = inet->sport;
- tw->tw_dport = inet->dport;
+ tw->tw_sport = inet->inet_sport;
+ tw->tw_dport = inet->inet_dport;
tw->tw_family = sk->sk_family;
tw->tw_reuse = sk->sk_reuse;
tw->tw_hash = sk->sk_hash;
@@ -430,7 +430,7 @@ void inet_twsk_purge(struct net *net, struct inet_hashinfo *hashinfo,
int h;
local_bh_disable();
- for (h = 0; h < (hashinfo->ehash_size); h++) {
+ for (h = 0; h <= hashinfo->ehash_mask; h++) {
struct inet_ehash_bucket *head =
inet_ehash_bucket(hashinfo, h);
spinlock_t *lock = inet_ehash_lockp(hashinfo, h);
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 41ada9904d31..40f043915235 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -156,8 +156,13 @@ struct ipgre_net {
#define tunnels_r tunnels[2]
#define tunnels_l tunnels[1]
#define tunnels_wc tunnels[0]
+/*
+ * Locking : hash tables are protected by RCU and a spinlock
+ */
+static DEFINE_SPINLOCK(ipgre_lock);
-static DEFINE_RWLOCK(ipgre_lock);
+#define for_each_ip_tunnel_rcu(start) \
+ for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
/* Given src, dst and key, find appropriate for input tunnel. */
@@ -175,7 +180,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
ARPHRD_ETHER : ARPHRD_IPGRE;
int score, cand_score = 4;
- for (t = ign->tunnels_r_l[h0^h1]; t; t = t->next) {
+ for_each_ip_tunnel_rcu(ign->tunnels_r_l[h0 ^ h1]) {
if (local != t->parms.iph.saddr ||
remote != t->parms.iph.daddr ||
key != t->parms.i_key ||
@@ -200,7 +205,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
}
}
- for (t = ign->tunnels_r[h0^h1]; t; t = t->next) {
+ for_each_ip_tunnel_rcu(ign->tunnels_r[h0 ^ h1]) {
if (remote != t->parms.iph.daddr ||
key != t->parms.i_key ||
!(t->dev->flags & IFF_UP))
@@ -224,7 +229,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
}
}
- for (t = ign->tunnels_l[h1]; t; t = t->next) {
+ for_each_ip_tunnel_rcu(ign->tunnels_l[h1]) {
if ((local != t->parms.iph.saddr &&
(local != t->parms.iph.daddr ||
!ipv4_is_multicast(local))) ||
@@ -250,7 +255,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
}
}
- for (t = ign->tunnels_wc[h1]; t; t = t->next) {
+ for_each_ip_tunnel_rcu(ign->tunnels_wc[h1]) {
if (t->parms.i_key != key ||
!(t->dev->flags & IFF_UP))
continue;
@@ -276,8 +281,9 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
if (cand != NULL)
return cand;
- if (ign->fb_tunnel_dev->flags & IFF_UP)
- return netdev_priv(ign->fb_tunnel_dev);
+ dev = ign->fb_tunnel_dev;
+ if (dev->flags & IFF_UP)
+ return netdev_priv(dev);
return NULL;
}
@@ -311,10 +317,10 @@ static void ipgre_tunnel_link(struct ipgre_net *ign, struct ip_tunnel *t)
{
struct ip_tunnel **tp = ipgre_bucket(ign, t);
+ spin_lock_bh(&ipgre_lock);
t->next = *tp;
- write_lock_bh(&ipgre_lock);
- *tp = t;
- write_unlock_bh(&ipgre_lock);
+ rcu_assign_pointer(*tp, t);
+ spin_unlock_bh(&ipgre_lock);
}
static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t)
@@ -323,9 +329,9 @@ static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t)
for (tp = ipgre_bucket(ign, t); *tp; tp = &(*tp)->next) {
if (t == *tp) {
- write_lock_bh(&ipgre_lock);
+ spin_lock_bh(&ipgre_lock);
*tp = t->next;
- write_unlock_bh(&ipgre_lock);
+ spin_unlock_bh(&ipgre_lock);
break;
}
}
@@ -476,7 +482,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
break;
}
- read_lock(&ipgre_lock);
+ rcu_read_lock();
t = ipgre_tunnel_lookup(skb->dev, iph->daddr, iph->saddr,
flags & GRE_KEY ?
*(((__be32 *)p) + (grehlen / 4) - 1) : 0,
@@ -494,7 +500,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
t->err_count = 1;
t->err_time = jiffies;
out:
- read_unlock(&ipgre_lock);
+ rcu_read_unlock();
return;
}
@@ -573,7 +579,7 @@ static int ipgre_rcv(struct sk_buff *skb)
gre_proto = *(__be16 *)(h + 2);
- read_lock(&ipgre_lock);
+ rcu_read_lock();
if ((tunnel = ipgre_tunnel_lookup(skb->dev,
iph->saddr, iph->daddr, key,
gre_proto))) {
@@ -647,13 +653,13 @@ static int ipgre_rcv(struct sk_buff *skb)
ipgre_ecn_decapsulate(iph, skb);
netif_rx(skb);
- read_unlock(&ipgre_lock);
+ rcu_read_unlock();
return(0);
}
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
drop:
- read_unlock(&ipgre_lock);
+ rcu_read_unlock();
drop_nolock:
kfree_skb(skb);
return(0);
@@ -662,7 +668,8 @@ drop_nolock:
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 = &tunnel->dev->stats;
+ struct net_device_stats *stats = &dev->stats;
+ struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
struct iphdr *old_iph = ip_hdr(skb);
struct iphdr *tiph;
u8 tos;
@@ -810,7 +817,7 @@ static netdev_tx_t ipgre_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);
- stats->tx_dropped++;
+ txq->tx_dropped++;
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 6c98b43badf4..fdf51badc8e5 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -161,7 +161,7 @@ int ip_call_ra_chain(struct sk_buff *skb)
/* If socket is bound to an interface, only report
* the packet if it came from that interface.
*/
- if (sk && inet_sk(sk)->num == protocol &&
+ if (sk && inet_sk(sk)->inet_num == protocol &&
(!sk->sk_bound_dev_if ||
sk->sk_bound_dev_if == dev->ifindex) &&
sock_net(sk) == dev_net(dev)) {
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index f9895180f481..322b40864ac0 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -329,7 +329,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
__be32 daddr;
/* Use correct destination address if we have options. */
- daddr = inet->daddr;
+ daddr = inet->inet_daddr;
if(opt && opt->srr)
daddr = opt->faddr;
@@ -338,13 +338,13 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
.mark = sk->sk_mark,
.nl_u = { .ip4_u =
{ .daddr = daddr,
- .saddr = inet->saddr,
+ .saddr = inet->inet_saddr,
.tos = RT_CONN_FLAGS(sk) } },
.proto = sk->sk_protocol,
.flags = inet_sk_flowi_flags(sk),
.uli_u = { .ports =
- { .sport = inet->sport,
- .dport = inet->dport } } };
+ { .sport = inet->inet_sport,
+ .dport = inet->inet_dport } } };
/* If this fails, retransmit mechanism of transport layer will
* keep trying until route appears or the connection times
@@ -379,7 +379,7 @@ packet_routed:
if (opt && opt->optlen) {
iph->ihl += opt->optlen >> 2;
- ip_options_build(skb, opt, inet->daddr, rt, 0);
+ ip_options_build(skb, opt, inet->inet_daddr, rt, 0);
}
ip_select_ident_more(iph, &rt->u.dst, sk,
@@ -846,7 +846,8 @@ int ip_append_data(struct sock *sk,
maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen;
if (inet->cork.length + length > 0xFFFF - fragheaderlen) {
- ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->dport, mtu-exthdrlen);
+ ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->inet_dport,
+ mtu-exthdrlen);
return -EMSGSIZE;
}
@@ -1100,7 +1101,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page,
maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen;
if (inet->cork.length + size > 0xFFFF - fragheaderlen) {
- ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->dport, mtu);
+ ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->inet_dport, mtu);
return -EMSGSIZE;
}
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 0c0b6e363a20..a72f43ce33be 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -245,7 +245,7 @@ int ip_ra_control(struct sock *sk, unsigned char on,
{
struct ip_ra_chain *ra, *new_ra, **rap;
- if (sk->sk_type != SOCK_RAW || inet_sk(sk)->num == IPPROTO_RAW)
+ if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num == IPPROTO_RAW)
return -EINVAL;
new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
@@ -492,7 +492,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
if (sk->sk_family == PF_INET ||
(!((1 << sk->sk_state) &
(TCPF_LISTEN | TCPF_CLOSE)) &&
- inet->daddr != LOOPBACK4_IPV6)) {
+ inet->inet_daddr != LOOPBACK4_IPV6)) {
#endif
if (inet->opt)
icsk->icsk_ext_hdr_len -= inet->opt->optlen;
@@ -575,7 +575,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
inet->hdrincl = val ? 1 : 0;
break;
case IP_MTU_DISCOVER:
- if (val < 0 || val > 3)
+ if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_PROBE)
goto e_inval;
inet->pmtudisc = val;
break;
@@ -634,17 +634,16 @@ static int do_ip_setsockopt(struct sock *sk, int level,
break;
}
dev = ip_dev_find(sock_net(sk), mreq.imr_address.s_addr);
- if (dev) {
+ if (dev)
mreq.imr_ifindex = dev->ifindex;
- dev_put(dev);
- }
} else
- dev = __dev_get_by_index(sock_net(sk), mreq.imr_ifindex);
+ dev = dev_get_by_index(sock_net(sk), mreq.imr_ifindex);
err = -EADDRNOTAVAIL;
if (!dev)
break;
+ dev_put(dev);
err = -EINVAL;
if (sk->sk_bound_dev_if &&
@@ -1181,8 +1180,8 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
if (inet->cmsg_flags & IP_CMSG_PKTINFO) {
struct in_pktinfo info;
- info.ipi_addr.s_addr = inet->rcv_saddr;
- info.ipi_spec_dst.s_addr = inet->rcv_saddr;
+ info.ipi_addr.s_addr = inet->inet_rcv_saddr;
+ info.ipi_spec_dst.s_addr = inet->inet_rcv_saddr;
info.ipi_ifindex = inet->mc_index;
put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
}
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index f8d04c256454..7dcbf4706099 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -1447,7 +1447,7 @@ late_initcall(ip_auto_config);
/*
* Decode any IP configuration options in the "ip=" or "nfsaddrs=" kernel
- * command line parameter. See Documentation/filesystems/nfsroot.txt.
+ * command line parameter. See Documentation/filesystems/nfs/nfsroot.txt.
*/
static int __init ic_proto_name(char *name)
{
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 08ccd344de7a..3bd69988bccf 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -134,7 +134,13 @@ static void ipip_fb_tunnel_init(struct net_device *dev);
static void ipip_tunnel_init(struct net_device *dev);
static void ipip_tunnel_setup(struct net_device *dev);
-static DEFINE_RWLOCK(ipip_lock);
+/*
+ * Locking : hash tables are protected by RCU and a spinlock
+ */
+static DEFINE_SPINLOCK(ipip_lock);
+
+#define for_each_ip_tunnel_rcu(start) \
+ for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
static struct ip_tunnel * ipip_tunnel_lookup(struct net *net,
__be32 remote, __be32 local)
@@ -144,20 +150,21 @@ static struct ip_tunnel * ipip_tunnel_lookup(struct net *net,
struct ip_tunnel *t;
struct ipip_net *ipn = net_generic(net, ipip_net_id);
- for (t = ipn->tunnels_r_l[h0^h1]; t; t = t->next) {
+ for_each_ip_tunnel_rcu(ipn->tunnels_r_l[h0 ^ h1])
if (local == t->parms.iph.saddr &&
remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
return t;
- }
- for (t = ipn->tunnels_r[h0]; t; t = t->next) {
+
+ for_each_ip_tunnel_rcu(ipn->tunnels_r[h0])
if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
return t;
- }
- for (t = ipn->tunnels_l[h1]; t; t = t->next) {
+
+ for_each_ip_tunnel_rcu(ipn->tunnels_l[h1])
if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP))
return t;
- }
- if ((t = ipn->tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP))
+
+ t = rcu_dereference(ipn->tunnels_wc[0]);
+ if (t && (t->dev->flags&IFF_UP))
return t;
return NULL;
}
@@ -193,9 +200,9 @@ static void ipip_tunnel_unlink(struct ipip_net *ipn, struct ip_tunnel *t)
for (tp = ipip_bucket(ipn, t); *tp; tp = &(*tp)->next) {
if (t == *tp) {
- write_lock_bh(&ipip_lock);
+ spin_lock_bh(&ipip_lock);
*tp = t->next;
- write_unlock_bh(&ipip_lock);
+ spin_unlock_bh(&ipip_lock);
break;
}
}
@@ -205,10 +212,10 @@ static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t)
{
struct ip_tunnel **tp = ipip_bucket(ipn, t);
+ spin_lock_bh(&ipip_lock);
t->next = *tp;
- write_lock_bh(&ipip_lock);
- *tp = t;
- write_unlock_bh(&ipip_lock);
+ rcu_assign_pointer(*tp, t);
+ spin_unlock_bh(&ipip_lock);
}
static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
@@ -267,9 +274,9 @@ static void ipip_tunnel_uninit(struct net_device *dev)
struct ipip_net *ipn = net_generic(net, ipip_net_id);
if (dev == ipn->fb_tunnel_dev) {
- write_lock_bh(&ipip_lock);
+ spin_lock_bh(&ipip_lock);
ipn->tunnels_wc[0] = NULL;
- write_unlock_bh(&ipip_lock);
+ spin_unlock_bh(&ipip_lock);
} else
ipip_tunnel_unlink(ipn, netdev_priv(dev));
dev_put(dev);
@@ -318,7 +325,7 @@ static int ipip_err(struct sk_buff *skb, u32 info)
err = -ENOENT;
- read_lock(&ipip_lock);
+ rcu_read_lock();
t = ipip_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr);
if (t == NULL || t->parms.iph.daddr == 0)
goto out;
@@ -333,7 +340,7 @@ static int ipip_err(struct sk_buff *skb, u32 info)
t->err_count = 1;
t->err_time = jiffies;
out:
- read_unlock(&ipip_lock);
+ rcu_read_unlock();
return err;
}
@@ -351,11 +358,11 @@ static int ipip_rcv(struct sk_buff *skb)
struct ip_tunnel *tunnel;
const struct iphdr *iph = ip_hdr(skb);
- read_lock(&ipip_lock);
+ rcu_read_lock();
if ((tunnel = ipip_tunnel_lookup(dev_net(skb->dev),
iph->saddr, iph->daddr)) != NULL) {
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
- read_unlock(&ipip_lock);
+ rcu_read_unlock();
kfree_skb(skb);
return 0;
}
@@ -374,10 +381,10 @@ static int ipip_rcv(struct sk_buff *skb)
nf_reset(skb);
ipip_ecn_decapsulate(iph, skb);
netif_rx(skb);
- read_unlock(&ipip_lock);
+ rcu_read_unlock();
return 0;
}
- read_unlock(&ipip_lock);
+ rcu_read_unlock();
return -1;
}
@@ -390,7 +397,8 @@ 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 = &tunnel->dev->stats;
+ struct net_device_stats *stats = &dev->stats;
+ struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
struct iphdr *tiph = &tunnel->parms.iph;
u8 tos = tunnel->parms.iph.tos;
__be16 df = tiph->frag_off;
@@ -478,7 +486,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);
- stats->tx_dropped++;
+ txq->tx_dropped++;
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 630a56df7b47..694974502ea6 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -469,8 +469,18 @@ static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock)
return err;
}
break;
+
+ case VIFF_USE_IFINDEX:
case 0:
- dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr);
+ if (vifc->vifc_flags == VIFF_USE_IFINDEX) {
+ dev = dev_get_by_index(net, vifc->vifc_lcl_ifindex);
+ if (dev && dev->ip_ptr == NULL) {
+ dev_put(dev);
+ return -EADDRNOTAVAIL;
+ }
+ } else
+ dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr);
+
if (!dev)
return -EADDRNOTAVAIL;
err = dev_set_allmulti(dev, 1);
@@ -946,7 +956,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
switch (optname) {
case MRT_INIT:
if (sk->sk_type != SOCK_RAW ||
- inet_sk(sk)->num != IPPROTO_IGMP)
+ inet_sk(sk)->inet_num != IPPROTO_IGMP)
return -EOPNOTSUPP;
if (optlen != sizeof(int))
return -ENOPROTOOPT;
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index aa95bb82ee6c..9cd423ffafa8 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -255,10 +255,10 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len)
struct nf_conntrack_tuple tuple;
memset(&tuple, 0, sizeof(tuple));
- tuple.src.u3.ip = inet->rcv_saddr;
- tuple.src.u.tcp.port = inet->sport;
- tuple.dst.u3.ip = inet->daddr;
- tuple.dst.u.tcp.port = inet->dport;
+ tuple.src.u3.ip = inet->inet_rcv_saddr;
+ tuple.src.u.tcp.port = inet->inet_sport;
+ tuple.dst.u3.ip = inet->inet_daddr;
+ tuple.dst.u.tcp.port = inet->inet_dport;
tuple.src.l3num = PF_INET;
tuple.dst.protonum = sk->sk_protocol;
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 757c9171e7c2..9ef8c0829a77 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -87,7 +87,7 @@ void raw_hash_sk(struct sock *sk)
struct raw_hashinfo *h = sk->sk_prot->h.raw_hash;
struct hlist_head *head;
- head = &h->ht[inet_sk(sk)->num & (RAW_HTABLE_SIZE - 1)];
+ head = &h->ht[inet_sk(sk)->inet_num & (RAW_HTABLE_SIZE - 1)];
write_lock_bh(&h->lock);
sk_add_node(sk, head);
@@ -115,9 +115,9 @@ static struct sock *__raw_v4_lookup(struct net *net, struct sock *sk,
sk_for_each_from(sk, node) {
struct inet_sock *inet = inet_sk(sk);
- if (net_eq(sock_net(sk), net) && inet->num == num &&
- !(inet->daddr && inet->daddr != raddr) &&
- !(inet->rcv_saddr && inet->rcv_saddr != laddr) &&
+ if (net_eq(sock_net(sk), net) && inet->inet_num == num &&
+ !(inet->inet_daddr && inet->inet_daddr != raddr) &&
+ !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) &&
!(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif))
goto found; /* gotcha */
}
@@ -292,7 +292,6 @@ static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb)
/* Charge it to the socket. */
if (sock_queue_rcv_skb(sk, skb) < 0) {
- atomic_inc(&sk->sk_drops);
kfree_skb(skb);
return NET_RX_DROP;
}
@@ -327,7 +326,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
int err;
if (length > rt->u.dst.dev->mtu) {
- ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->dport,
+ ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->inet_dport,
rt->u.dst.dev->mtu);
return -EMSGSIZE;
}
@@ -490,10 +489,10 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
err = -EDESTADDRREQ;
if (sk->sk_state != TCP_ESTABLISHED)
goto out;
- daddr = inet->daddr;
+ daddr = inet->inet_daddr;
}
- ipc.addr = inet->saddr;
+ ipc.addr = inet->inet_saddr;
ipc.opt = NULL;
ipc.shtx.flags = 0;
ipc.oif = sk->sk_bound_dev_if;
@@ -635,9 +634,9 @@ static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL &&
chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST)
goto out;
- inet->rcv_saddr = inet->saddr = addr->sin_addr.s_addr;
+ inet->inet_rcv_saddr = inet->inet_saddr = addr->sin_addr.s_addr;
if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
- inet->saddr = 0; /* Use device */
+ inet->inet_saddr = 0; /* Use device */
sk_dst_reset(sk);
ret = 0;
out: return ret;
@@ -682,7 +681,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
if (err)
goto done;
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
/* Copy the address. */
if (sin) {
@@ -707,7 +706,7 @@ static int raw_init(struct sock *sk)
{
struct raw_sock *rp = raw_sk(sk);
- if (inet_sk(sk)->num == IPPROTO_ICMP)
+ if (inet_sk(sk)->inet_num == IPPROTO_ICMP)
memset(&rp->filter, 0, sizeof(rp->filter));
return 0;
}
@@ -744,7 +743,7 @@ static int do_raw_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen)
{
if (optname == ICMP_FILTER) {
- if (inet_sk(sk)->num != IPPROTO_ICMP)
+ if (inet_sk(sk)->inet_num != IPPROTO_ICMP)
return -EOPNOTSUPP;
else
return raw_seticmpfilter(sk, optval, optlen);
@@ -774,7 +773,7 @@ static int do_raw_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
if (optname == ICMP_FILTER) {
- if (inet_sk(sk)->num != IPPROTO_ICMP)
+ if (inet_sk(sk)->inet_num != IPPROTO_ICMP)
return -EOPNOTSUPP;
else
return raw_geticmpfilter(sk, optval, optlen);
@@ -933,10 +932,10 @@ EXPORT_SYMBOL_GPL(raw_seq_stop);
static void raw_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
{
struct inet_sock *inet = inet_sk(sp);
- __be32 dest = inet->daddr,
- src = inet->rcv_saddr;
+ __be32 dest = inet->inet_daddr,
+ src = inet->inet_rcv_saddr;
__u16 destp = 0,
- srcp = inet->num;
+ srcp = inet->inet_num;
seq_printf(seq, "%4d: %08X:%04X %08X:%04X"
" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index bb4199252026..68fb22702051 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1628,9 +1628,6 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
__be32 daddr = iph->daddr;
unsigned short est_mtu = 0;
- if (ipv4_config.no_pmtu_disc)
- return 0;
-
for (k = 0; k < 2; k++) {
for (i = 0; i < 2; i++) {
unsigned hash = rt_hash(daddr, skeys[i], ikeys[k],
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index a6e0e077ac33..5ec678ad70ef 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -333,7 +333,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
* no easy way to do this.
*/
{
- struct flowi fl = { .nl_u = { .ip4_u =
+ struct flowi fl = { .mark = sk->sk_mark,
+ .nl_u = { .ip4_u =
{ .daddr = ((opt && opt->srr) ?
opt->faddr :
ireq->rmt_addr),
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 64d0af675823..e0cfa633680a 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -326,6 +326,43 @@ void tcp_enter_memory_pressure(struct sock *sk)
EXPORT_SYMBOL(tcp_enter_memory_pressure);
+/* Convert seconds to retransmits based on initial and max timeout */
+static u8 secs_to_retrans(int seconds, int timeout, int rto_max)
+{
+ u8 res = 0;
+
+ if (seconds > 0) {
+ int period = timeout;
+
+ res = 1;
+ while (seconds > period && res < 255) {
+ res++;
+ timeout <<= 1;
+ if (timeout > rto_max)
+ timeout = rto_max;
+ period += timeout;
+ }
+ }
+ return res;
+}
+
+/* Convert retransmits to seconds based on initial and max timeout */
+static int retrans_to_secs(u8 retrans, int timeout, int rto_max)
+{
+ int period = 0;
+
+ if (retrans > 0) {
+ period = timeout;
+ while (--retrans) {
+ timeout <<= 1;
+ if (timeout > rto_max)
+ timeout = rto_max;
+ period += timeout;
+ }
+ }
+ return period;
+}
+
/*
* Wait for a TCP event.
*
@@ -1405,7 +1442,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
goto found_ok_skb;
if (tcp_hdr(skb)->fin)
goto found_fin_ok;
- WARN_ON(!(flags & MSG_PEEK));
+ WARN(!(flags & MSG_PEEK), KERN_INFO "recvmsg bug 2: "
+ "copied %X seq %X\n", *seq,
+ TCP_SKB_CB(skb)->seq);
}
/* Well, if we have backlog, try to process it now yet. */
@@ -1998,7 +2037,7 @@ int tcp_disconnect(struct sock *sk, int flags)
__skb_queue_purge(&sk->sk_async_wait_queue);
#endif
- inet->dport = 0;
+ inet->inet_dport = 0;
if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))
inet_reset_saddr(sk);
@@ -2022,7 +2061,7 @@ int tcp_disconnect(struct sock *sk, int flags)
memset(&tp->rx_opt, 0, sizeof(tp->rx_opt));
__sk_dst_reset(sk);
- WARN_ON(inet->num && !icsk->icsk_bind_hash);
+ WARN_ON(inet->inet_num && !icsk->icsk_bind_hash);
sk->sk_error_report(sk);
return err;
@@ -2163,16 +2202,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
break;
case TCP_DEFER_ACCEPT:
- icsk->icsk_accept_queue.rskq_defer_accept = 0;
- if (val > 0) {
- /* Translate value in seconds to number of
- * retransmits */
- while (icsk->icsk_accept_queue.rskq_defer_accept < 32 &&
- val > ((TCP_TIMEOUT_INIT / HZ) <<
- icsk->icsk_accept_queue.rskq_defer_accept))
- icsk->icsk_accept_queue.rskq_defer_accept++;
- icsk->icsk_accept_queue.rskq_defer_accept++;
- }
+ /* Translate value in seconds to number of retransmits */
+ icsk->icsk_accept_queue.rskq_defer_accept =
+ secs_to_retrans(val, TCP_TIMEOUT_INIT / HZ,
+ TCP_RTO_MAX / HZ);
break;
case TCP_WINDOW_CLAMP:
@@ -2353,8 +2386,8 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
val = (val ? : sysctl_tcp_fin_timeout) / HZ;
break;
case TCP_DEFER_ACCEPT:
- val = !icsk->icsk_accept_queue.rskq_defer_accept ? 0 :
- ((TCP_TIMEOUT_INIT / HZ) << (icsk->icsk_accept_queue.rskq_defer_accept - 1));
+ val = retrans_to_secs(icsk->icsk_accept_queue.rskq_defer_accept,
+ TCP_TIMEOUT_INIT / HZ, TCP_RTO_MAX / HZ);
break;
case TCP_WINDOW_CLAMP:
val = tp->window_clamp;
@@ -2865,11 +2898,10 @@ void __init tcp_init(void)
(totalram_pages >= 128 * 1024) ?
13 : 15,
0,
- &tcp_hashinfo.ehash_size,
NULL,
+ &tcp_hashinfo.ehash_mask,
thash_entries ? 0 : 512 * 1024);
- tcp_hashinfo.ehash_size = 1 << tcp_hashinfo.ehash_size;
- for (i = 0; i < tcp_hashinfo.ehash_size; i++) {
+ for (i = 0; i <= tcp_hashinfo.ehash_mask; i++) {
INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].chain, i);
INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].twchain, i);
}
@@ -2878,7 +2910,7 @@ void __init tcp_init(void)
tcp_hashinfo.bhash =
alloc_large_system_hash("TCP bind",
sizeof(struct inet_bind_hashbucket),
- tcp_hashinfo.ehash_size,
+ tcp_hashinfo.ehash_mask + 1,
(totalram_pages >= 128 * 1024) ?
13 : 15,
0,
@@ -2933,8 +2965,8 @@ void __init tcp_init(void)
sysctl_tcp_rmem[2] = max(87380, max_share);
printk(KERN_INFO "TCP: Hash tables configured "
- "(established %d bind %d)\n",
- tcp_hashinfo.ehash_size, tcp_hashinfo.bhash_size);
+ "(established %u bind %u)\n",
+ tcp_hashinfo.ehash_mask + 1, tcp_hashinfo.bhash_size);
tcp_register_congestion_control(&tcp_reno);
}
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 7cda24b53f61..a4a3390a5287 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -165,10 +165,10 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
nexthop = inet->opt->faddr;
}
- tmp = ip_route_connect(&rt, nexthop, inet->saddr,
+ tmp = ip_route_connect(&rt, nexthop, inet->inet_saddr,
RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
IPPROTO_TCP,
- inet->sport, usin->sin_port, sk, 1);
+ inet->inet_sport, usin->sin_port, sk, 1);
if (tmp < 0) {
if (tmp == -ENETUNREACH)
IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
@@ -183,11 +183,11 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (!inet->opt || !inet->opt->srr)
daddr = rt->rt_dst;
- if (!inet->saddr)
- inet->saddr = rt->rt_src;
- inet->rcv_saddr = inet->saddr;
+ if (!inet->inet_saddr)
+ inet->inet_saddr = rt->rt_src;
+ inet->inet_rcv_saddr = inet->inet_saddr;
- if (tp->rx_opt.ts_recent_stamp && inet->daddr != daddr) {
+ if (tp->rx_opt.ts_recent_stamp && inet->inet_daddr != daddr) {
/* Reset inherited state */
tp->rx_opt.ts_recent = 0;
tp->rx_opt.ts_recent_stamp = 0;
@@ -210,8 +210,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
}
}
- inet->dport = usin->sin_port;
- inet->daddr = daddr;
+ inet->inet_dport = usin->sin_port;
+ inet->inet_daddr = daddr;
inet_csk(sk)->icsk_ext_hdr_len = 0;
if (inet->opt)
@@ -230,7 +230,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
goto failure;
err = ip_route_newports(&rt, IPPROTO_TCP,
- inet->sport, inet->dport, sk);
+ inet->inet_sport, inet->inet_dport, sk);
if (err)
goto failure;
@@ -239,12 +239,12 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
sk_setup_caps(sk, &rt->u.dst);
if (!tp->write_seq)
- tp->write_seq = secure_tcp_sequence_number(inet->saddr,
- inet->daddr,
- inet->sport,
+ tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,
+ inet->inet_daddr,
+ inet->inet_sport,
usin->sin_port);
- inet->id = tp->write_seq ^ jiffies;
+ inet->inet_id = tp->write_seq ^ jiffies;
err = tcp_connect(sk);
rt = NULL;
@@ -261,7 +261,7 @@ failure:
tcp_set_state(sk, TCP_CLOSE);
ip_rt_put(rt);
sk->sk_route_caps = 0;
- inet->dport = 0;
+ inet->inet_dport = 0;
return err;
}
@@ -520,12 +520,13 @@ void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb)
struct tcphdr *th = tcp_hdr(skb);
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- th->check = ~tcp_v4_check(len, inet->saddr,
- inet->daddr, 0);
+ th->check = ~tcp_v4_check(len, inet->inet_saddr,
+ inet->inet_daddr, 0);
skb->csum_start = skb_transport_header(skb) - skb->head;
skb->csum_offset = offsetof(struct tcphdr, check);
} else {
- th->check = tcp_v4_check(len, inet->saddr, inet->daddr,
+ th->check = tcp_v4_check(len, inet->inet_saddr,
+ inet->inet_daddr,
csum_partial(th,
th->doff << 2,
skb->csum));
@@ -848,7 +849,7 @@ static struct tcp_md5sig_key *
struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk,
struct sock *addr_sk)
{
- return tcp_v4_md5_do_lookup(sk, inet_sk(addr_sk)->daddr);
+ return tcp_v4_md5_do_lookup(sk, inet_sk(addr_sk)->inet_daddr);
}
EXPORT_SYMBOL(tcp_v4_md5_lookup);
@@ -923,7 +924,7 @@ EXPORT_SYMBOL(tcp_v4_md5_do_add);
static int tcp_v4_md5_add_func(struct sock *sk, struct sock *addr_sk,
u8 *newkey, u8 newkeylen)
{
- return tcp_v4_md5_do_add(sk, inet_sk(addr_sk)->daddr,
+ return tcp_v4_md5_do_add(sk, inet_sk(addr_sk)->inet_daddr,
newkey, newkeylen);
}
@@ -1089,8 +1090,8 @@ int tcp_v4_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
__be32 saddr, daddr;
if (sk) {
- saddr = inet_sk(sk)->saddr;
- daddr = inet_sk(sk)->daddr;
+ saddr = inet_sk(sk)->inet_saddr;
+ daddr = inet_sk(sk)->inet_daddr;
} else if (req) {
saddr = inet_rsk(req)->loc_addr;
daddr = inet_rsk(req)->rmt_addr;
@@ -1380,9 +1381,9 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
newtp = tcp_sk(newsk);
newinet = inet_sk(newsk);
ireq = inet_rsk(req);
- newinet->daddr = ireq->rmt_addr;
- newinet->rcv_saddr = ireq->loc_addr;
- newinet->saddr = ireq->loc_addr;
+ newinet->inet_daddr = ireq->rmt_addr;
+ newinet->inet_rcv_saddr = ireq->loc_addr;
+ newinet->inet_saddr = ireq->loc_addr;
newinet->opt = ireq->opt;
ireq->opt = NULL;
newinet->mc_index = inet_iif(skb);
@@ -1390,7 +1391,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
inet_csk(newsk)->icsk_ext_hdr_len = 0;
if (newinet->opt)
inet_csk(newsk)->icsk_ext_hdr_len = newinet->opt->optlen;
- newinet->id = newtp->write_seq ^ jiffies;
+ newinet->inet_id = newtp->write_seq ^ jiffies;
tcp_mtup_init(newsk);
tcp_sync_mss(newsk, dst_mtu(dst));
@@ -1403,7 +1404,8 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
#ifdef CONFIG_TCP_MD5SIG
/* Copy over the MD5 key from the original socket */
- if ((key = tcp_v4_md5_do_lookup(sk, newinet->daddr)) != NULL) {
+ key = tcp_v4_md5_do_lookup(sk, newinet->inet_daddr);
+ if (key != NULL) {
/*
* We're using one, so create a matching key
* on the newsk structure. If we fail to get
@@ -1412,7 +1414,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
*/
char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC);
if (newkey != NULL)
- tcp_v4_md5_do_add(newsk, newinet->daddr,
+ tcp_v4_md5_do_add(newsk, newinet->inet_daddr,
newkey, key->keylen);
newsk->sk_route_caps &= ~NETIF_F_GSO_MASK;
}
@@ -1711,8 +1713,8 @@ int tcp_v4_remember_stamp(struct sock *sk)
struct inet_peer *peer = NULL;
int release_it = 0;
- if (!rt || rt->rt_dst != inet->daddr) {
- peer = inet_getpeer(inet->daddr, 1);
+ if (!rt || rt->rt_dst != inet->inet_daddr) {
+ peer = inet_getpeer(inet->inet_daddr, 1);
release_it = 1;
} else {
if (!rt->peer)
@@ -2000,7 +2002,7 @@ static void *established_get_first(struct seq_file *seq)
struct net *net = seq_file_net(seq);
void *rc = NULL;
- for (st->bucket = 0; st->bucket < tcp_hashinfo.ehash_size; ++st->bucket) {
+ for (st->bucket = 0; st->bucket <= tcp_hashinfo.ehash_mask; ++st->bucket) {
struct sock *sk;
struct hlist_nulls_node *node;
struct inet_timewait_sock *tw;
@@ -2061,10 +2063,10 @@ get_tw:
st->state = TCP_SEQ_STATE_ESTABLISHED;
/* Look for next non empty bucket */
- while (++st->bucket < tcp_hashinfo.ehash_size &&
+ while (++st->bucket <= tcp_hashinfo.ehash_mask &&
empty_bucket(st))
;
- if (st->bucket >= tcp_hashinfo.ehash_size)
+ if (st->bucket > tcp_hashinfo.ehash_mask)
return NULL;
spin_lock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket));
@@ -2225,7 +2227,7 @@ static void get_openreq4(struct sock *sk, struct request_sock *req,
" %02X %08X:%08X %02X:%08lX %08X %5d %8d %u %d %p%n",
i,
ireq->loc_addr,
- ntohs(inet_sk(sk)->sport),
+ ntohs(inet_sk(sk)->inet_sport),
ireq->rmt_addr,
ntohs(ireq->rmt_port),
TCP_SYN_RECV,
@@ -2248,10 +2250,10 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
struct tcp_sock *tp = tcp_sk(sk);
const struct inet_connection_sock *icsk = inet_csk(sk);
struct inet_sock *inet = inet_sk(sk);
- __be32 dest = inet->daddr;
- __be32 src = inet->rcv_saddr;
- __u16 destp = ntohs(inet->dport);
- __u16 srcp = ntohs(inet->sport);
+ __be32 dest = inet->inet_daddr;
+ __be32 src = inet->inet_rcv_saddr;
+ __u16 destp = ntohs(inet->inet_dport);
+ __u16 srcp = ntohs(inet->inet_sport);
if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
timer_active = 1;
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index e320afea07fc..4c03598ed924 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -641,10 +641,9 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
if (!(flg & TCP_FLAG_ACK))
return NULL;
- /* If TCP_DEFER_ACCEPT is set, drop bare ACK. */
- if (inet_csk(sk)->icsk_accept_queue.rskq_defer_accept &&
+ /* While TCP_DEFER_ACCEPT is active, drop bare ACK. */
+ if (req->retrans < inet_csk(sk)->icsk_accept_queue.rskq_defer_accept &&
TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) {
- inet_csk(sk)->icsk_accept_queue.rskq_defer_accept--;
inet_rsk(req)->acked = 1;
return NULL;
}
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index fcd278a7080e..2e2eb74ac4cc 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -661,8 +661,8 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
/* Build TCP header and checksum it. */
th = tcp_hdr(skb);
- th->source = inet->sport;
- th->dest = inet->dport;
+ th->source = inet->inet_sport;
+ th->dest = inet->inet_dport;
th->seq = htonl(tcb->seq);
th->ack_seq = htonl(tp->rcv_nxt);
*(((__be16 *)th) + 6) = htons(((tcp_header_size >> 2) << 12) |
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c
index 59f5b5e7c566..7a3cc2ffad84 100644
--- a/net/ipv4/tcp_probe.c
+++ b/net/ipv4/tcp_probe.c
@@ -94,7 +94,8 @@ static int jtcp_rcv_established(struct sock *sk, struct sk_buff *skb,
const struct inet_sock *inet = inet_sk(sk);
/* Only update if port matches */
- if ((port == 0 || ntohs(inet->dport) == port || ntohs(inet->sport) == port)
+ if ((port == 0 || ntohs(inet->inet_dport) == port ||
+ ntohs(inet->inet_sport) == port)
&& (full || tp->snd_cwnd != tcp_probe.lastcwnd)) {
spin_lock(&tcp_probe.lock);
@@ -103,10 +104,10 @@ static int jtcp_rcv_established(struct sock *sk, struct sk_buff *skb,
struct tcp_log *p = tcp_probe.log + tcp_probe.head;
p->tstamp = ktime_get();
- p->saddr = inet->saddr;
- p->sport = inet->sport;
- p->daddr = inet->daddr;
- p->dport = inet->dport;
+ p->saddr = inet->inet_saddr;
+ p->sport = inet->inet_sport;
+ p->daddr = inet->inet_daddr;
+ p->dport = inet->inet_dport;
p->length = skb->len;
p->snd_nxt = tp->snd_nxt;
p->snd_una = tp->snd_una;
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index cdb2ca7684d4..8353a538cd4c 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -141,14 +141,14 @@ static int tcp_write_timeout(struct sock *sk)
if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
if (icsk->icsk_retransmits)
- dst_negative_advice(&sk->sk_dst_cache);
+ dst_negative_advice(&sk->sk_dst_cache, sk);
retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries;
} else {
if (retransmits_timed_out(sk, sysctl_tcp_retries1)) {
/* Black hole detection */
tcp_mtu_probing(icsk, sk);
- dst_negative_advice(&sk->sk_dst_cache);
+ dst_negative_advice(&sk->sk_dst_cache, sk);
}
retry_until = sysctl_tcp_retries2;
@@ -303,15 +303,15 @@ void tcp_retransmit_timer(struct sock *sk)
struct inet_sock *inet = inet_sk(sk);
if (sk->sk_family == AF_INET) {
LIMIT_NETDEBUG(KERN_DEBUG "TCP: Peer %pI4:%u/%u unexpectedly shrunk window %u:%u (repaired)\n",
- &inet->daddr, ntohs(inet->dport),
- inet->num, tp->snd_una, tp->snd_nxt);
+ &inet->inet_daddr, ntohs(inet->inet_dport),
+ inet->inet_num, tp->snd_una, tp->snd_nxt);
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
else if (sk->sk_family == AF_INET6) {
struct ipv6_pinfo *np = inet6_sk(sk);
LIMIT_NETDEBUG(KERN_DEBUG "TCP: Peer %pI6:%u/%u unexpectedly shrunk window %u:%u (repaired)\n",
- &np->daddr, ntohs(inet->dport),
- inet->num, tp->snd_una, tp->snd_nxt);
+ &np->daddr, ntohs(inet->inet_dport),
+ inet->inet_num, tp->snd_una, tp->snd_nxt);
}
#endif
#endif
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index d0d436d6216c..4274c1cc78fd 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -106,7 +106,7 @@
#include <net/xfrm.h>
#include "udp_impl.h"
-struct udp_table udp_table;
+struct udp_table udp_table __read_mostly;
EXPORT_SYMBOL(udp_table);
int sysctl_udp_mem[3] __read_mostly;
@@ -121,14 +121,16 @@ EXPORT_SYMBOL(sysctl_udp_wmem_min);
atomic_t udp_memory_allocated;
EXPORT_SYMBOL(udp_memory_allocated);
-#define PORTS_PER_CHAIN (65536 / UDP_HTABLE_SIZE)
+#define MAX_UDP_PORTS 65536
+#define PORTS_PER_CHAIN (MAX_UDP_PORTS / UDP_HTABLE_SIZE_MIN)
static int udp_lib_lport_inuse(struct net *net, __u16 num,
const struct udp_hslot *hslot,
unsigned long *bitmap,
struct sock *sk,
int (*saddr_comp)(const struct sock *sk1,
- const struct sock *sk2))
+ const struct sock *sk2),
+ unsigned int log)
{
struct sock *sk2;
struct hlist_nulls_node *node;
@@ -142,8 +144,7 @@ static int udp_lib_lport_inuse(struct net *net, __u16 num,
|| sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
(*saddr_comp)(sk, sk2)) {
if (bitmap)
- __set_bit(sk2->sk_hash / UDP_HTABLE_SIZE,
- bitmap);
+ __set_bit(sk2->sk_hash >> log, bitmap);
else
return 1;
}
@@ -180,13 +181,15 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
/*
* force rand to be an odd multiple of UDP_HTABLE_SIZE
*/
- rand = (rand | 1) * UDP_HTABLE_SIZE;
- for (last = first + UDP_HTABLE_SIZE; first != last; first++) {
- hslot = &udptable->hash[udp_hashfn(net, first)];
+ rand = (rand | 1) * (udptable->mask + 1);
+ for (last = first + udptable->mask + 1;
+ first != last;
+ first++) {
+ hslot = udp_hashslot(udptable, net, first);
bitmap_zero(bitmap, PORTS_PER_CHAIN);
spin_lock_bh(&hslot->lock);
udp_lib_lport_inuse(net, snum, hslot, bitmap, sk,
- saddr_comp);
+ saddr_comp, udptable->log);
snum = first;
/*
@@ -196,7 +199,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
*/
do {
if (low <= snum && snum <= high &&
- !test_bit(snum / UDP_HTABLE_SIZE, bitmap))
+ !test_bit(snum >> udptable->log, bitmap))
goto found;
snum += rand;
} while (snum != first);
@@ -204,13 +207,14 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
}
goto fail;
} else {
- hslot = &udptable->hash[udp_hashfn(net, snum)];
+ hslot = udp_hashslot(udptable, net, snum);
spin_lock_bh(&hslot->lock);
- if (udp_lib_lport_inuse(net, snum, hslot, NULL, sk, saddr_comp))
+ if (udp_lib_lport_inuse(net, snum, hslot, NULL, sk,
+ saddr_comp, 0))
goto fail_unlock;
}
found:
- inet_sk(sk)->num = snum;
+ inet_sk(sk)->inet_num = snum;
sk->sk_hash = snum;
if (sk_unhashed(sk)) {
sk_nulls_add_node_rcu(sk, &hslot->head);
@@ -229,8 +233,8 @@ static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2);
return (!ipv6_only_sock(sk2) &&
- (!inet1->rcv_saddr || !inet2->rcv_saddr ||
- inet1->rcv_saddr == inet2->rcv_saddr));
+ (!inet1->inet_rcv_saddr || !inet2->inet_rcv_saddr ||
+ inet1->inet_rcv_saddr == inet2->inet_rcv_saddr));
}
int udp_v4_get_port(struct sock *sk, unsigned short snum)
@@ -249,18 +253,18 @@ static inline int compute_score(struct sock *sk, struct net *net, __be32 saddr,
struct inet_sock *inet = inet_sk(sk);
score = (sk->sk_family == PF_INET ? 1 : 0);
- if (inet->rcv_saddr) {
- if (inet->rcv_saddr != daddr)
+ if (inet->inet_rcv_saddr) {
+ if (inet->inet_rcv_saddr != daddr)
return -1;
score += 2;
}
- if (inet->daddr) {
- if (inet->daddr != saddr)
+ if (inet->inet_daddr) {
+ if (inet->inet_daddr != saddr)
return -1;
score += 2;
}
- if (inet->dport) {
- if (inet->dport != sport)
+ if (inet->inet_dport) {
+ if (inet->inet_dport != sport)
return -1;
score += 2;
}
@@ -283,7 +287,7 @@ static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
struct sock *sk, *result;
struct hlist_nulls_node *node;
unsigned short hnum = ntohs(dport);
- unsigned int hash = udp_hashfn(net, hnum);
+ unsigned int hash = udp_hashfn(net, hnum, udptable->mask);
struct udp_hslot *hslot = &udptable->hash[hash];
int score, badness;
@@ -356,9 +360,10 @@ static inline struct sock *udp_v4_mcast_next(struct net *net, struct sock *sk,
if (!net_eq(sock_net(s), net) ||
s->sk_hash != hnum ||
- (inet->daddr && inet->daddr != rmt_addr) ||
- (inet->dport != rmt_port && inet->dport) ||
- (inet->rcv_saddr && inet->rcv_saddr != loc_addr) ||
+ (inet->inet_daddr && inet->inet_daddr != rmt_addr) ||
+ (inet->inet_dport != rmt_port && inet->inet_dport) ||
+ (inet->inet_rcv_saddr &&
+ inet->inet_rcv_saddr != loc_addr) ||
ipv6_only_sock(s) ||
(s->sk_bound_dev_if && s->sk_bound_dev_if != dif))
continue;
@@ -642,14 +647,14 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
} else {
if (sk->sk_state != TCP_ESTABLISHED)
return -EDESTADDRREQ;
- daddr = inet->daddr;
- dport = inet->dport;
+ daddr = inet->inet_daddr;
+ dport = inet->inet_dport;
/* Open fast path for connected socket.
Route will not be used, if at least one option is set.
*/
connected = 1;
}
- ipc.addr = inet->saddr;
+ ipc.addr = inet->inet_saddr;
ipc.oif = sk->sk_bound_dev_if;
err = sock_tx_timestamp(msg, sk, &ipc.shtx);
@@ -704,7 +709,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
.proto = sk->sk_protocol,
.flags = inet_sk_flowi_flags(sk),
.uli_u = { .ports =
- { .sport = inet->sport,
+ { .sport = inet->inet_sport,
.dport = dport } } };
struct net *net = sock_net(sk);
@@ -748,7 +753,7 @@ back_from_confirm:
inet->cork.fl.fl4_dst = daddr;
inet->cork.fl.fl_ip_dport = dport;
inet->cork.fl.fl4_src = saddr;
- inet->cork.fl.fl_ip_sport = inet->sport;
+ inet->cork.fl.fl_ip_sport = inet->inet_sport;
up->pending = AF_INET;
do_append_data:
@@ -862,6 +867,7 @@ static unsigned int first_packet_length(struct sock *sk)
udp_lib_checksum_complete(skb)) {
UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS,
IS_UDPLITE(sk));
+ atomic_inc(&sk->sk_drops);
__skb_unlink(skb, rcvq);
__skb_queue_tail(&list_kill, skb);
}
@@ -982,7 +988,7 @@ try_again:
UDP_INC_STATS_USER(sock_net(sk),
UDP_MIB_INDATAGRAMS, is_udplite);
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
/* Copy the address. */
if (sin) {
@@ -1025,15 +1031,15 @@ int udp_disconnect(struct sock *sk, int flags)
*/
sk->sk_state = TCP_CLOSE;
- inet->daddr = 0;
- inet->dport = 0;
+ inet->inet_daddr = 0;
+ inet->inet_dport = 0;
sk->sk_bound_dev_if = 0;
if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))
inet_reset_saddr(sk);
if (!(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) {
sk->sk_prot->unhash(sk);
- inet->sport = 0;
+ inet->inet_sport = 0;
}
sk_dst_reset(sk);
return 0;
@@ -1044,12 +1050,12 @@ void udp_lib_unhash(struct sock *sk)
{
if (sk_hashed(sk)) {
struct udp_table *udptable = sk->sk_prot->h.udp_table;
- unsigned int hash = udp_hashfn(sock_net(sk), sk->sk_hash);
- struct udp_hslot *hslot = &udptable->hash[hash];
+ struct udp_hslot *hslot = udp_hashslot(udptable, sock_net(sk),
+ sk->sk_hash);
spin_lock_bh(&hslot->lock);
if (sk_nulls_del_node_init_rcu(sk)) {
- inet_sk(sk)->num = 0;
+ inet_sk(sk)->inet_num = 0;
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
}
spin_unlock_bh(&hslot->lock);
@@ -1059,25 +1065,22 @@ EXPORT_SYMBOL(udp_lib_unhash);
static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
- int is_udplite = IS_UDPLITE(sk);
- int rc;
+ int rc = sock_queue_rcv_skb(sk, skb);
+
+ if (rc < 0) {
+ int is_udplite = IS_UDPLITE(sk);
- if ((rc = sock_queue_rcv_skb(sk, skb)) < 0) {
/* Note that an ENOMEM error is charged twice */
- if (rc == -ENOMEM) {
+ if (rc == -ENOMEM)
UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS,
is_udplite);
- atomic_inc(&sk->sk_drops);
- }
- goto drop;
+ UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
+ kfree_skb(skb);
+ return -1;
}
return 0;
-drop:
- UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
- kfree_skb(skb);
- return -1;
}
/* returns:
@@ -1184,6 +1187,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
drop:
UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
+ atomic_inc(&sk->sk_drops);
kfree_skb(skb);
return -1;
}
@@ -1200,7 +1204,7 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
struct udp_table *udptable)
{
struct sock *sk;
- struct udp_hslot *hslot = &udptable->hash[udp_hashfn(net, ntohs(uh->dest))];
+ struct udp_hslot *hslot = udp_hashslot(udptable, net, ntohs(uh->dest));
int dif;
spin_lock(&hslot->lock);
@@ -1622,9 +1626,14 @@ static struct sock *udp_get_first(struct seq_file *seq, int start)
struct udp_iter_state *state = seq->private;
struct net *net = seq_file_net(seq);
- for (state->bucket = start; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) {
+ for (state->bucket = start; state->bucket <= state->udp_table->mask;
+ ++state->bucket) {
struct hlist_nulls_node *node;
struct udp_hslot *hslot = &state->udp_table->hash[state->bucket];
+
+ if (hlist_nulls_empty(&hslot->head))
+ continue;
+
spin_lock_bh(&hslot->lock);
sk_nulls_for_each(sk, node, &hslot->head) {
if (!net_eq(sock_net(sk), net))
@@ -1649,7 +1658,7 @@ static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk)
} while (sk && (!net_eq(sock_net(sk), net) || sk->sk_family != state->family));
if (!sk) {
- if (state->bucket < UDP_HTABLE_SIZE)
+ if (state->bucket <= state->udp_table->mask)
spin_unlock_bh(&state->udp_table->hash[state->bucket].lock);
return udp_get_first(seq, state->bucket + 1);
}
@@ -1669,7 +1678,7 @@ static struct sock *udp_get_idx(struct seq_file *seq, loff_t pos)
static void *udp_seq_start(struct seq_file *seq, loff_t *pos)
{
struct udp_iter_state *state = seq->private;
- state->bucket = UDP_HTABLE_SIZE;
+ state->bucket = MAX_UDP_PORTS;
return *pos ? udp_get_idx(seq, *pos-1) : SEQ_START_TOKEN;
}
@@ -1691,7 +1700,7 @@ static void udp_seq_stop(struct seq_file *seq, void *v)
{
struct udp_iter_state *state = seq->private;
- if (state->bucket < UDP_HTABLE_SIZE)
+ if (state->bucket <= state->udp_table->mask)
spin_unlock_bh(&state->udp_table->hash[state->bucket].lock);
}
@@ -1746,12 +1755,12 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
int bucket, int *len)
{
struct inet_sock *inet = inet_sk(sp);
- __be32 dest = inet->daddr;
- __be32 src = inet->rcv_saddr;
- __u16 destp = ntohs(inet->dport);
- __u16 srcp = ntohs(inet->sport);
+ __be32 dest = inet->inet_daddr;
+ __be32 src = inet->inet_rcv_saddr;
+ __u16 destp = ntohs(inet->inet_dport);
+ __u16 srcp = ntohs(inet->inet_sport);
- seq_printf(f, "%4d: %08X:%04X %08X:%04X"
+ seq_printf(f, "%5d: %08X:%04X %08X:%04X"
" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d%n",
bucket, src, srcp, dest, destp, sp->sk_state,
sk_wmem_alloc_get(sp),
@@ -1817,11 +1826,43 @@ void udp4_proc_exit(void)
}
#endif /* CONFIG_PROC_FS */
-void __init udp_table_init(struct udp_table *table)
+static __initdata unsigned long uhash_entries;
+static int __init set_uhash_entries(char *str)
{
- int i;
+ if (!str)
+ return 0;
+ uhash_entries = simple_strtoul(str, &str, 0);
+ if (uhash_entries && uhash_entries < UDP_HTABLE_SIZE_MIN)
+ uhash_entries = UDP_HTABLE_SIZE_MIN;
+ return 1;
+}
+__setup("uhash_entries=", set_uhash_entries);
- for (i = 0; i < UDP_HTABLE_SIZE; i++) {
+void __init udp_table_init(struct udp_table *table, const char *name)
+{
+ unsigned int i;
+
+ if (!CONFIG_BASE_SMALL)
+ table->hash = alloc_large_system_hash(name,
+ sizeof(struct udp_hslot),
+ uhash_entries,
+ 21, /* one slot per 2 MB */
+ 0,
+ &table->log,
+ &table->mask,
+ 64 * 1024);
+ /*
+ * Make sure hash table has the minimum size
+ */
+ if (CONFIG_BASE_SMALL || table->mask < UDP_HTABLE_SIZE_MIN - 1) {
+ table->hash = kmalloc(UDP_HTABLE_SIZE_MIN *
+ sizeof(struct udp_hslot), GFP_KERNEL);
+ if (!table->hash)
+ panic(name);
+ table->log = ilog2(UDP_HTABLE_SIZE_MIN);
+ table->mask = UDP_HTABLE_SIZE_MIN - 1;
+ }
+ for (i = 0; i <= table->mask; i++) {
INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i);
spin_lock_init(&table->hash[i].lock);
}
@@ -1831,7 +1872,7 @@ void __init udp_init(void)
{
unsigned long nr_pages, limit;
- udp_table_init(&udp_table);
+ udp_table_init(&udp_table, "UDP");
/* Set the pressure threshold up by the same strategy of TCP. It is a
* fraction of global memory that is up to 1/2 at 256 MB, decreasing
* toward zero with the amount of memory, with a floor of 128 pages.
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c
index 95248d7f75ec..470c504b9554 100644
--- a/net/ipv4/udplite.c
+++ b/net/ipv4/udplite.c
@@ -12,7 +12,7 @@
*/
#include "udp_impl.h"
-struct udp_table udplite_table;
+struct udp_table udplite_table __read_mostly;
EXPORT_SYMBOL(udplite_table);
static int udplite_rcv(struct sk_buff *skb)
@@ -110,7 +110,7 @@ static inline int udplite4_proc_init(void)
void __init udplite4_register(void)
{
- udp_table_init(&udplite_table);
+ udp_table_init(&udplite_table, "UDP-Lite");
if (proto_register(&udplite_prot, 1))
goto out_register_err;
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index ead6c7a42f44..a578096152ab 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -170,6 +170,25 @@ config IPV6_SIT
Saying M here will produce a module called sit. If unsure, say Y.
+config IPV6_SIT_6RD
+ bool "IPv6: IPv6 Rapid Deployment (6RD) (EXPERIMENTAL)"
+ depends on IPV6_SIT && EXPERIMENTAL
+ default n
+ ---help---
+ IPv6 Rapid Deployment (6rd; draft-ietf-softwire-ipv6-6rd) builds upon
+ mechanisms of 6to4 (RFC3056) to enable a service provider to rapidly
+ deploy IPv6 unicast service to IPv4 sites to which it provides
+ customer premise equipment. Like 6to4, it utilizes stateless IPv6 in
+ IPv4 encapsulation in order to transit IPv4-only network
+ infrastructure. Unlike 6to4, a 6rd service provider uses an IPv6
+ prefix of its own in place of the fixed 6to4 prefix.
+
+ With this option enabled, the SIT driver offers 6rd functionality by
+ providing additional ioctl API to configure the IPv6 Prefix for in
+ stead of static 2002::/16 for 6to4.
+
+ If unsure, say N.
+
config IPV6_NDISC_NODETYPE
bool
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 1fd0a3d775d2..918648409612 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3708,6 +3708,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
#endif
array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6;
array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad;
+ array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao;
}
static inline size_t inet6_if_nlmsg_size(void)
@@ -4353,6 +4354,14 @@ static struct addrconf_sysctl_table
.proc_handler = proc_dointvec,
},
{
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "force_tllao",
+ .data = &ipv6_devconf.force_tllao,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+ {
.ctl_name = 0, /* sentinel */
}
},
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index e127a32f9540..b6d058818673 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -185,7 +185,7 @@ lookup_protocol:
inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0;
if (SOCK_RAW == sock->type) {
- inet->num = protocol;
+ inet->inet_num = protocol;
if (IPPROTO_RAW == protocol)
inet->hdrincl = 1;
}
@@ -228,12 +228,12 @@ lookup_protocol:
*/
sk_refcnt_debug_inc(sk);
- if (inet->num) {
+ if (inet->inet_num) {
/* It assumes that any protocol which allows
* the user to assign a number at socket
* creation time automatically shares.
*/
- inet->sport = htons(inet->num);
+ inet->inet_sport = htons(inet->inet_num);
sk->sk_prot->hash(sk);
}
if (sk->sk_prot->init) {
@@ -281,7 +281,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
lock_sock(sk);
/* Check these errors (active socket, double bind). */
- if (sk->sk_state != TCP_CLOSE || inet->num) {
+ if (sk->sk_state != TCP_CLOSE || inet->inet_num) {
err = -EINVAL;
goto out;
}
@@ -353,8 +353,8 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
}
}
- inet->rcv_saddr = v4addr;
- inet->saddr = v4addr;
+ inet->inet_rcv_saddr = v4addr;
+ inet->inet_saddr = v4addr;
ipv6_addr_copy(&np->rcv_saddr, &addr->sin6_addr);
@@ -375,9 +375,9 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
}
if (snum)
sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
- inet->sport = htons(inet->num);
- inet->dport = 0;
- inet->daddr = 0;
+ inet->inet_sport = htons(inet->inet_num);
+ inet->inet_dport = 0;
+ inet->inet_daddr = 0;
out:
release_sock(sk);
return err;
@@ -441,12 +441,12 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
sin->sin6_flowinfo = 0;
sin->sin6_scope_id = 0;
if (peer) {
- if (!inet->dport)
+ if (!inet->inet_dport)
return -ENOTCONN;
if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) &&
peer == 1)
return -ENOTCONN;
- sin->sin6_port = inet->dport;
+ sin->sin6_port = inet->inet_dport;
ipv6_addr_copy(&sin->sin6_addr, &np->daddr);
if (np->sndflow)
sin->sin6_flowinfo = np->flow_label;
@@ -456,7 +456,7 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
else
ipv6_addr_copy(&sin->sin6_addr, &np->rcv_saddr);
- sin->sin6_port = inet->sport;
+ sin->sin6_port = inet->inet_sport;
}
if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
sin->sin6_scope_id = sk->sk_bound_dev_if;
@@ -552,7 +552,7 @@ const struct proto_ops inet6_dgram_ops = {
#endif
};
-static struct net_proto_family inet6_family_ops = {
+static const struct net_proto_family inet6_family_ops = {
.family = PF_INET6,
.create = inet6_create,
.owner = THIS_MODULE,
@@ -654,8 +654,9 @@ int inet6_sk_rebuild_header(struct sock *sk)
ipv6_addr_copy(&fl.fl6_src, &np->saddr);
fl.fl6_flowlabel = np->flow_label;
fl.oif = sk->sk_bound_dev_if;
- fl.fl_ip_dport = inet->dport;
- fl.fl_ip_sport = inet->sport;
+ fl.mark = sk->sk_mark;
+ fl.fl_ip_dport = inet->inet_dport;
+ fl.fl_ip_sport = inet->inet_sport;
security_sk_classify_flow(sk, &fl);
if (np->opt && np->opt->srcrt) {
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index c1589e2f1dc9..0f526f8ea518 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -24,18 +24,92 @@
* This file is derived from net/ipv4/ah.c.
*/
+#include <crypto/hash.h>
#include <linux/module.h>
#include <net/ip.h>
#include <net/ah.h>
#include <linux/crypto.h>
#include <linux/pfkeyv2.h>
-#include <linux/spinlock.h>
#include <linux/string.h>
+#include <linux/scatterlist.h>
#include <net/icmp.h>
#include <net/ipv6.h>
#include <net/protocol.h>
#include <net/xfrm.h>
+#define IPV6HDR_BASELEN 8
+
+struct tmp_ext {
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
+ struct in6_addr saddr;
+#endif
+ struct in6_addr daddr;
+ char hdrs[0];
+};
+
+struct ah_skb_cb {
+ struct xfrm_skb_cb xfrm;
+ void *tmp;
+};
+
+#define AH_SKB_CB(__skb) ((struct ah_skb_cb *)&((__skb)->cb[0]))
+
+static void *ah_alloc_tmp(struct crypto_ahash *ahash, int nfrags,
+ unsigned int size)
+{
+ unsigned int len;
+
+ len = size + crypto_ahash_digestsize(ahash) +
+ (crypto_ahash_alignmask(ahash) &
+ ~(crypto_tfm_ctx_alignment() - 1));
+
+ len = ALIGN(len, crypto_tfm_ctx_alignment());
+
+ len += sizeof(struct ahash_request) + crypto_ahash_reqsize(ahash);
+ len = ALIGN(len, __alignof__(struct scatterlist));
+
+ len += sizeof(struct scatterlist) * nfrags;
+
+ return kmalloc(len, GFP_ATOMIC);
+}
+
+static inline struct tmp_ext *ah_tmp_ext(void *base)
+{
+ return base + IPV6HDR_BASELEN;
+}
+
+static inline u8 *ah_tmp_auth(u8 *tmp, unsigned int offset)
+{
+ return tmp + offset;
+}
+
+static inline u8 *ah_tmp_icv(struct crypto_ahash *ahash, void *tmp,
+ unsigned int offset)
+{
+ return PTR_ALIGN((u8 *)tmp + offset, crypto_ahash_alignmask(ahash) + 1);
+}
+
+static inline struct ahash_request *ah_tmp_req(struct crypto_ahash *ahash,
+ u8 *icv)
+{
+ struct ahash_request *req;
+
+ req = (void *)PTR_ALIGN(icv + crypto_ahash_digestsize(ahash),
+ crypto_tfm_ctx_alignment());
+
+ ahash_request_set_tfm(req, ahash);
+
+ return req;
+}
+
+static inline struct scatterlist *ah_req_sg(struct crypto_ahash *ahash,
+ struct ahash_request *req)
+{
+ return (void *)ALIGN((unsigned long)(req + 1) +
+ crypto_ahash_reqsize(ahash),
+ __alignof__(struct scatterlist));
+}
+
static int zero_out_mutable_opts(struct ipv6_opt_hdr *opthdr)
{
u8 *opt = (u8 *)opthdr;
@@ -218,24 +292,85 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir)
return 0;
}
+static void ah6_output_done(struct crypto_async_request *base, int err)
+{
+ int extlen;
+ u8 *iph_base;
+ u8 *icv;
+ struct sk_buff *skb = base->data;
+ struct xfrm_state *x = skb_dst(skb)->xfrm;
+ struct ah_data *ahp = x->data;
+ struct ipv6hdr *top_iph = ipv6_hdr(skb);
+ struct ip_auth_hdr *ah = ip_auth_hdr(skb);
+ struct tmp_ext *iph_ext;
+
+ extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
+ if (extlen)
+ extlen += sizeof(*iph_ext);
+
+ iph_base = AH_SKB_CB(skb)->tmp;
+ iph_ext = ah_tmp_ext(iph_base);
+ icv = ah_tmp_icv(ahp->ahash, iph_ext, extlen);
+
+ memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
+ memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
+
+ if (extlen) {
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
+ memcpy(&top_iph->saddr, iph_ext, extlen);
+#else
+ memcpy(&top_iph->daddr, iph_ext, extlen);
+#endif
+ }
+
+ err = ah->nexthdr;
+
+ kfree(AH_SKB_CB(skb)->tmp);
+ xfrm_output_resume(skb, err);
+}
+
static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
{
int err;
+ int nfrags;
int extlen;
+ u8 *iph_base;
+ u8 *icv;
+ u8 nexthdr;
+ struct sk_buff *trailer;
+ struct crypto_ahash *ahash;
+ struct ahash_request *req;
+ struct scatterlist *sg;
struct ipv6hdr *top_iph;
struct ip_auth_hdr *ah;
struct ah_data *ahp;
- u8 nexthdr;
- char tmp_base[8];
- struct {
-#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
- struct in6_addr saddr;
-#endif
- struct in6_addr daddr;
- char hdrs[0];
- } *tmp_ext;
+ struct tmp_ext *iph_ext;
+
+ ahp = x->data;
+ ahash = ahp->ahash;
+
+ if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
+ goto out;
+ nfrags = err;
skb_push(skb, -skb_network_offset(skb));
+ extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
+ if (extlen)
+ extlen += sizeof(*iph_ext);
+
+ err = -ENOMEM;
+ iph_base = ah_alloc_tmp(ahash, nfrags, IPV6HDR_BASELEN + extlen);
+ if (!iph_base)
+ goto out;
+
+ iph_ext = ah_tmp_ext(iph_base);
+ icv = ah_tmp_icv(ahash, iph_ext, extlen);
+ req = ah_tmp_req(ahash, icv);
+ sg = ah_req_sg(ahash, req);
+
+ ah = ip_auth_hdr(skb);
+ memset(ah->auth_data, 0, ahp->icv_trunc_len);
+
top_iph = ipv6_hdr(skb);
top_iph->payload_len = htons(skb->len - sizeof(*top_iph));
@@ -245,31 +380,22 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
/* When there are no extension headers, we only need to save the first
* 8 bytes of the base IP header.
*/
- memcpy(tmp_base, top_iph, sizeof(tmp_base));
+ memcpy(iph_base, top_iph, IPV6HDR_BASELEN);
- tmp_ext = NULL;
- extlen = skb_transport_offset(skb) - sizeof(struct ipv6hdr);
if (extlen) {
- extlen += sizeof(*tmp_ext);
- tmp_ext = kmalloc(extlen, GFP_ATOMIC);
- if (!tmp_ext) {
- err = -ENOMEM;
- goto error;
- }
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
- memcpy(tmp_ext, &top_iph->saddr, extlen);
+ memcpy(iph_ext, &top_iph->saddr, extlen);
#else
- memcpy(tmp_ext, &top_iph->daddr, extlen);
+ memcpy(iph_ext, &top_iph->daddr, extlen);
#endif
err = ipv6_clear_mutable_options(top_iph,
- extlen - sizeof(*tmp_ext) +
+ extlen - sizeof(*iph_ext) +
sizeof(*top_iph),
XFRM_POLICY_OUT);
if (err)
- goto error_free_iph;
+ goto out_free;
}
- ah = ip_auth_hdr(skb);
ah->nexthdr = nexthdr;
top_iph->priority = 0;
@@ -278,36 +404,80 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
top_iph->flow_lbl[2] = 0;
top_iph->hop_limit = 0;
- ahp = x->data;
ah->hdrlen = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2;
ah->reserved = 0;
ah->spi = x->id.spi;
ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output);
- spin_lock_bh(&x->lock);
- err = ah_mac_digest(ahp, skb, ah->auth_data);
- memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len);
- spin_unlock_bh(&x->lock);
+ sg_init_table(sg, nfrags);
+ skb_to_sgvec(skb, sg, 0, skb->len);
- if (err)
- goto error_free_iph;
+ ahash_request_set_crypt(req, sg, icv, skb->len);
+ ahash_request_set_callback(req, 0, ah6_output_done, skb);
+
+ AH_SKB_CB(skb)->tmp = iph_base;
- memcpy(top_iph, tmp_base, sizeof(tmp_base));
- if (tmp_ext) {
+ err = crypto_ahash_digest(req);
+ if (err) {
+ if (err == -EINPROGRESS)
+ goto out;
+
+ if (err == -EBUSY)
+ err = NET_XMIT_DROP;
+ goto out_free;
+ }
+
+ memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
+ memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
+
+ if (extlen) {
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
- memcpy(&top_iph->saddr, tmp_ext, extlen);
+ memcpy(&top_iph->saddr, iph_ext, extlen);
#else
- memcpy(&top_iph->daddr, tmp_ext, extlen);
+ memcpy(&top_iph->daddr, iph_ext, extlen);
#endif
-error_free_iph:
- kfree(tmp_ext);
}
-error:
+out_free:
+ kfree(iph_base);
+out:
return err;
}
+static void ah6_input_done(struct crypto_async_request *base, int err)
+{
+ u8 *auth_data;
+ u8 *icv;
+ u8 *work_iph;
+ struct sk_buff *skb = base->data;
+ struct xfrm_state *x = xfrm_input_state(skb);
+ struct ah_data *ahp = x->data;
+ struct ip_auth_hdr *ah = ip_auth_hdr(skb);
+ int hdr_len = skb_network_header_len(skb);
+ int ah_hlen = (ah->hdrlen + 2) << 2;
+
+ work_iph = AH_SKB_CB(skb)->tmp;
+ auth_data = ah_tmp_auth(work_iph, hdr_len);
+ icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len);
+
+ err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0;
+ if (err)
+ goto out;
+
+ skb->network_header += ah_hlen;
+ memcpy(skb_network_header(skb), work_iph, hdr_len);
+ __skb_pull(skb, ah_hlen + hdr_len);
+ skb_set_transport_header(skb, -hdr_len);
+
+ err = ah->nexthdr;
+out:
+ kfree(AH_SKB_CB(skb)->tmp);
+ xfrm_input_resume(skb, err);
+}
+
+
+
static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
{
/*
@@ -325,14 +495,21 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
* There is offset of AH before IPv6 header after the process.
*/
+ u8 *auth_data;
+ u8 *icv;
+ u8 *work_iph;
+ struct sk_buff *trailer;
+ struct crypto_ahash *ahash;
+ struct ahash_request *req;
+ struct scatterlist *sg;
struct ip_auth_hdr *ah;
struct ipv6hdr *ip6h;
struct ah_data *ahp;
- unsigned char *tmp_hdr = NULL;
u16 hdr_len;
u16 ah_hlen;
int nexthdr;
- int err = -EINVAL;
+ int nfrags;
+ int err = -ENOMEM;
if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr)))
goto out;
@@ -345,9 +522,11 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
skb->ip_summed = CHECKSUM_NONE;
- hdr_len = skb->data - skb_network_header(skb);
+ hdr_len = skb_network_header_len(skb);
ah = (struct ip_auth_hdr *)skb->data;
ahp = x->data;
+ ahash = ahp->ahash;
+
nexthdr = ah->nexthdr;
ah_hlen = (ah->hdrlen + 2) << 2;
@@ -358,48 +537,67 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
if (!pskb_may_pull(skb, ah_hlen))
goto out;
- tmp_hdr = kmemdup(skb_network_header(skb), hdr_len, GFP_ATOMIC);
- if (!tmp_hdr)
- goto out;
ip6h = ipv6_hdr(skb);
+
+ skb_push(skb, hdr_len);
+
+ if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
+ goto out;
+ nfrags = err;
+
+ work_iph = ah_alloc_tmp(ahash, nfrags, hdr_len + ahp->icv_trunc_len);
+ if (!work_iph)
+ goto out;
+
+ auth_data = ah_tmp_auth(work_iph, hdr_len);
+ icv = ah_tmp_icv(ahash, auth_data, ahp->icv_trunc_len);
+ req = ah_tmp_req(ahash, icv);
+ sg = ah_req_sg(ahash, req);
+
+ memcpy(work_iph, ip6h, hdr_len);
+ memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
+ memset(ah->auth_data, 0, ahp->icv_trunc_len);
+
if (ipv6_clear_mutable_options(ip6h, hdr_len, XFRM_POLICY_IN))
- goto free_out;
+ goto out_free;
+
ip6h->priority = 0;
ip6h->flow_lbl[0] = 0;
ip6h->flow_lbl[1] = 0;
ip6h->flow_lbl[2] = 0;
ip6h->hop_limit = 0;
- spin_lock(&x->lock);
- {
- u8 auth_data[MAX_AH_AUTH_LEN];
+ sg_init_table(sg, nfrags);
+ skb_to_sgvec(skb, sg, 0, skb->len);
- memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
- memset(ah->auth_data, 0, ahp->icv_trunc_len);
- skb_push(skb, hdr_len);
- err = ah_mac_digest(ahp, skb, ah->auth_data);
- if (err)
- goto unlock;
- if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len))
- err = -EBADMSG;
+ ahash_request_set_crypt(req, sg, icv, skb->len);
+ ahash_request_set_callback(req, 0, ah6_input_done, skb);
+
+ AH_SKB_CB(skb)->tmp = work_iph;
+
+ err = crypto_ahash_digest(req);
+ if (err) {
+ if (err == -EINPROGRESS)
+ goto out;
+
+ if (err == -EBUSY)
+ err = NET_XMIT_DROP;
+ goto out_free;
}
-unlock:
- spin_unlock(&x->lock);
+ err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0;
if (err)
- goto free_out;
+ goto out_free;
skb->network_header += ah_hlen;
- memcpy(skb_network_header(skb), tmp_hdr, hdr_len);
+ memcpy(skb_network_header(skb), work_iph, hdr_len);
skb->transport_header = skb->network_header;
__skb_pull(skb, ah_hlen + hdr_len);
- kfree(tmp_hdr);
+ err = nexthdr;
- return nexthdr;
-
-free_out:
- kfree(tmp_hdr);
+out_free:
+ kfree(work_iph);
out:
return err;
}
@@ -430,7 +628,7 @@ static int ah6_init_state(struct xfrm_state *x)
{
struct ah_data *ahp = NULL;
struct xfrm_algo_desc *aalg_desc;
- struct crypto_hash *tfm;
+ struct crypto_ahash *ahash;
if (!x->aalg)
goto error;
@@ -442,12 +640,12 @@ static int ah6_init_state(struct xfrm_state *x)
if (ahp == NULL)
return -ENOMEM;
- tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(tfm))
+ ahash = crypto_alloc_ahash(x->aalg->alg_name, 0, 0);
+ if (IS_ERR(ahash))
goto error;
- ahp->tfm = tfm;
- if (crypto_hash_setkey(tfm, x->aalg->alg_key,
+ ahp->ahash = ahash;
+ if (crypto_ahash_setkey(ahash, x->aalg->alg_key,
(x->aalg->alg_key_len + 7) / 8))
goto error;
@@ -461,9 +659,9 @@ static int ah6_init_state(struct xfrm_state *x)
BUG_ON(!aalg_desc);
if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
- crypto_hash_digestsize(tfm)) {
+ crypto_ahash_digestsize(ahash)) {
printk(KERN_INFO "AH: %s digestsize %u != %hu\n",
- x->aalg->alg_name, crypto_hash_digestsize(tfm),
+ x->aalg->alg_name, crypto_ahash_digestsize(ahash),
aalg_desc->uinfo.auth.icv_fullbits/8);
goto error;
}
@@ -473,10 +671,6 @@ static int ah6_init_state(struct xfrm_state *x)
BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN);
- ahp->work_icv = kmalloc(ahp->icv_full_len, GFP_KERNEL);
- if (!ahp->work_icv)
- goto error;
-
x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) +
ahp->icv_trunc_len);
switch (x->props.mode) {
@@ -495,8 +689,7 @@ static int ah6_init_state(struct xfrm_state *x)
error:
if (ahp) {
- kfree(ahp->work_icv);
- crypto_free_hash(ahp->tfm);
+ crypto_free_ahash(ahp->ahash);
kfree(ahp);
}
return -EINVAL;
@@ -509,8 +702,7 @@ static void ah6_destroy(struct xfrm_state *x)
if (!ahp)
return;
- kfree(ahp->work_icv);
- crypto_free_hash(ahp->tfm);
+ crypto_free_ahash(ahp->ahash);
kfree(ahp);
}
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index e2bdc6d83a43..9f70452a69e7 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -98,17 +98,15 @@ ipv4_connected:
if (err)
goto out;
- ipv6_addr_set(&np->daddr, 0, 0, htonl(0x0000ffff), inet->daddr);
+ ipv6_addr_set_v4mapped(inet->inet_daddr, &np->daddr);
- if (ipv6_addr_any(&np->saddr)) {
- ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000ffff),
- inet->saddr);
- }
+ if (ipv6_addr_any(&np->saddr))
+ ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr);
+
+ if (ipv6_addr_any(&np->rcv_saddr))
+ ipv6_addr_set_v4mapped(inet->inet_rcv_saddr,
+ &np->rcv_saddr);
- if (ipv6_addr_any(&np->rcv_saddr)) {
- ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000ffff),
- inet->rcv_saddr);
- }
goto out;
}
@@ -136,7 +134,7 @@ ipv4_connected:
ipv6_addr_copy(&np->daddr, daddr);
np->flow_label = fl.fl6_flowlabel;
- inet->dport = usin->sin6_port;
+ inet->inet_dport = usin->sin6_port;
/*
* Check for a route to destination an obtain the
@@ -147,8 +145,9 @@ ipv4_connected:
ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
ipv6_addr_copy(&fl.fl6_src, &np->saddr);
fl.oif = sk->sk_bound_dev_if;
- fl.fl_ip_dport = inet->dport;
- fl.fl_ip_sport = inet->sport;
+ fl.mark = sk->sk_mark;
+ fl.fl_ip_dport = inet->inet_dport;
+ fl.fl_ip_sport = inet->inet_sport;
if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST))
fl.oif = np->mcast_oif;
@@ -190,7 +189,7 @@ ipv4_connected:
if (ipv6_addr_any(&np->rcv_saddr)) {
ipv6_addr_copy(&np->rcv_saddr, &fl.fl6_src);
- inet->rcv_saddr = LOOPBACK4_IPV6;
+ inet->inet_rcv_saddr = LOOPBACK4_IPV6;
}
ip6_dst_store(sk, dst,
@@ -329,9 +328,8 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
sin->sin6_scope_id = IP6CB(skb)->iif;
} else {
- ipv6_addr_set(&sin->sin6_addr, 0, 0,
- htonl(0xffff),
- *(__be32 *)(nh + serr->addr_offset));
+ ipv6_addr_set_v4mapped(*(__be32 *)(nh + serr->addr_offset),
+ &sin->sin6_addr);
}
}
@@ -351,8 +349,8 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
} else {
struct inet_sock *inet = inet_sk(sk);
- ipv6_addr_set(&sin->sin6_addr, 0, 0,
- htonl(0xffff), ip_hdr(skb)->saddr);
+ ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr,
+ &sin->sin6_addr);
if (inet->cmsg_flags)
ip_cmsg_recv(msg, skb);
}
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index cc4797dd8325..3516e6fe2e56 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -132,7 +132,7 @@ void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
sin6->sin6_family = AF_INET6;
ipv6_addr_copy(&sin6->sin6_addr, &np->daddr);
- sin6->sin6_port = inet_sk(sk)->dport;
+ sin6->sin6_port = inet_sk(sk)->inet_dport;
/* We do not store received flowlabel for TCP */
sin6->sin6_flowinfo = 0;
sin6->sin6_scope_id = 0;
@@ -168,8 +168,7 @@ struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie)
if (dst) {
struct rt6_info *rt = (struct rt6_info *)dst;
if (rt->rt6i_flow_cache_genid != atomic_read(&flow_cache_genid)) {
- sk->sk_dst_cache = NULL;
- dst_release(dst);
+ __sk_dst_reset(sk);
dst = NULL;
}
}
@@ -194,8 +193,9 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
fl.fl6_flowlabel = np->flow_label;
IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel);
fl.oif = sk->sk_bound_dev_if;
- fl.fl_ip_sport = inet->sport;
- fl.fl_ip_dport = inet->dport;
+ fl.mark = sk->sk_mark;
+ fl.fl_ip_sport = inet->inet_sport;
+ fl.fl_ip_dport = inet->inet_dport;
security_sk_classify_flow(sk, &fl);
if (np->opt && np->opt->srcrt) {
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index 1bcc3431859e..00c6a3e6cddf 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -73,7 +73,7 @@ struct sock *__inet6_lookup_established(struct net *net,
* have wildcards anyways.
*/
unsigned int hash = inet6_ehashfn(net, daddr, hnum, saddr, sport);
- unsigned int slot = hash & (hashinfo->ehash_size - 1);
+ unsigned int slot = hash & hashinfo->ehash_mask;
struct inet_ehash_bucket *head = &hashinfo->ehash[slot];
@@ -125,7 +125,7 @@ static int inline compute_score(struct sock *sk, struct net *net,
{
int score = -1;
- if (net_eq(sock_net(sk), net) && inet_sk(sk)->num == hnum &&
+ if (net_eq(sock_net(sk), net) && inet_sk(sk)->inet_num == hnum &&
sk->sk_family == PF_INET6) {
const struct ipv6_pinfo *np = inet6_sk(sk);
@@ -214,10 +214,10 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
const struct in6_addr *daddr = &np->rcv_saddr;
const struct in6_addr *saddr = &np->daddr;
const int dif = sk->sk_bound_dev_if;
- const __portpair ports = INET_COMBINED_PORTS(inet->dport, lport);
+ const __portpair ports = INET_COMBINED_PORTS(inet->inet_dport, lport);
struct net *net = sock_net(sk);
const unsigned int hash = inet6_ehashfn(net, daddr, lport, saddr,
- inet->dport);
+ inet->inet_dport);
struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash);
spinlock_t *lock = inet_ehash_lockp(hinfo, hash);
struct sock *sk2;
@@ -248,8 +248,8 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
unique:
/* Must record num and sport now. Otherwise we will see
* in hash table socket with a funny identity. */
- inet->num = lport;
- inet->sport = htons(lport);
+ inet->inet_num = lport;
+ inet->inet_sport = htons(lport);
WARN_ON(!sk_unhashed(sk));
__sk_nulls_add_node_rcu(sk, &head->chain);
sk->sk_hash = hash;
@@ -279,7 +279,7 @@ static inline u32 inet6_sk_port_offset(const struct sock *sk)
const struct ipv6_pinfo *np = inet6_sk(sk);
return secure_ipv6_port_ephemeral(np->rcv_saddr.s6_addr32,
np->daddr.s6_addr32,
- inet->dport);
+ inet->inet_dport);
}
int inet6_hash_connect(struct inet_timewait_death_row *death_row,
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index c595bbe1ed99..670c291d2567 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -88,8 +88,10 @@ struct ip6_tnl_net {
struct ip6_tnl **tnls[2];
};
-/* lock for the tunnel lists */
-static DEFINE_RWLOCK(ip6_tnl_lock);
+/*
+ * Locking : hash tables are protected by RCU and a spinlock
+ */
+static DEFINE_SPINLOCK(ip6_tnl_lock);
static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t)
{
@@ -130,6 +132,9 @@ static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst)
* else %NULL
**/
+#define for_each_ip6_tunnel_rcu(start) \
+ for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
+
static struct ip6_tnl *
ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local)
{
@@ -138,13 +143,14 @@ ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local)
struct ip6_tnl *t;
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
- for (t = ip6n->tnls_r_l[h0 ^ h1]; t; t = t->next) {
+ for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[h0 ^ h1]) {
if (ipv6_addr_equal(local, &t->parms.laddr) &&
ipv6_addr_equal(remote, &t->parms.raddr) &&
(t->dev->flags & IFF_UP))
return t;
}
- if ((t = ip6n->tnls_wc[0]) != NULL && (t->dev->flags & IFF_UP))
+ t = rcu_dereference(ip6n->tnls_wc[0]);
+ if (t && (t->dev->flags & IFF_UP))
return t;
return NULL;
@@ -186,10 +192,10 @@ ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
{
struct ip6_tnl **tp = ip6_tnl_bucket(ip6n, &t->parms);
+ spin_lock_bh(&ip6_tnl_lock);
t->next = *tp;
- write_lock_bh(&ip6_tnl_lock);
- *tp = t;
- write_unlock_bh(&ip6_tnl_lock);
+ rcu_assign_pointer(*tp, t);
+ spin_unlock_bh(&ip6_tnl_lock);
}
/**
@@ -204,9 +210,9 @@ ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
for (tp = ip6_tnl_bucket(ip6n, &t->parms); *tp; tp = &(*tp)->next) {
if (t == *tp) {
- write_lock_bh(&ip6_tnl_lock);
+ spin_lock_bh(&ip6_tnl_lock);
*tp = t->next;
- write_unlock_bh(&ip6_tnl_lock);
+ spin_unlock_bh(&ip6_tnl_lock);
break;
}
}
@@ -313,9 +319,9 @@ ip6_tnl_dev_uninit(struct net_device *dev)
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
if (dev == ip6n->fb_tnl_dev) {
- write_lock_bh(&ip6_tnl_lock);
+ spin_lock_bh(&ip6_tnl_lock);
ip6n->tnls_wc[0] = NULL;
- write_unlock_bh(&ip6_tnl_lock);
+ spin_unlock_bh(&ip6_tnl_lock);
} else {
ip6_tnl_unlink(ip6n, t);
}
@@ -409,7 +415,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
in trouble since we might need the source address for further
processing of the error. */
- read_lock(&ip6_tnl_lock);
+ rcu_read_lock();
if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->daddr,
&ipv6h->saddr)) == NULL)
goto out;
@@ -482,7 +488,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
*msg = rel_msg;
out:
- read_unlock(&ip6_tnl_lock);
+ rcu_read_unlock();
return err;
}
@@ -693,23 +699,23 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
struct ip6_tnl *t;
struct ipv6hdr *ipv6h = ipv6_hdr(skb);
- read_lock(&ip6_tnl_lock);
+ rcu_read_lock();
if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr,
&ipv6h->daddr)) != NULL) {
if (t->parms.proto != ipproto && t->parms.proto != 0) {
- read_unlock(&ip6_tnl_lock);
+ rcu_read_unlock();
goto discard;
}
if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
- read_unlock(&ip6_tnl_lock);
+ rcu_read_unlock();
goto discard;
}
if (!ip6_tnl_rcv_ctl(t)) {
t->dev->stats.rx_dropped++;
- read_unlock(&ip6_tnl_lock);
+ rcu_read_unlock();
goto discard;
}
secpath_reset(skb);
@@ -727,10 +733,10 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
t->dev->stats.rx_packets++;
t->dev->stats.rx_bytes += skb->len;
netif_rx(skb);
- read_unlock(&ip6_tnl_lock);
+ rcu_read_unlock();
return 0;
}
- read_unlock(&ip6_tnl_lock);
+ rcu_read_unlock();
return 1;
discard:
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 716153941fc4..85849b4f5a36 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -1297,7 +1297,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
switch (optname) {
case MRT6_INIT:
if (sk->sk_type != SOCK_RAW ||
- inet_sk(sk)->num != IPPROTO_ICMPV6)
+ inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
return -EOPNOTSUPP;
if (optlen < sizeof(int))
return -EINVAL;
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 14f54eb5a7fc..430454ee5ead 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -64,7 +64,7 @@ int ip6_ra_control(struct sock *sk, int sel)
struct ip6_ra_chain *ra, *new_ra, **rap;
/* RA packet may be delivered ONLY to IPPROTO_RAW socket */
- if (sk->sk_type != SOCK_RAW || inet_sk(sk)->num != IPPROTO_RAW)
+ if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num != IPPROTO_RAW)
return -ENOPROTOOPT;
new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
@@ -106,7 +106,7 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
if (inet_sk(sk)->is_icsk) {
if (opt &&
!((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) &&
- inet_sk(sk)->daddr != LOOPBACK4_IPV6) {
+ inet_sk(sk)->inet_daddr != LOOPBACK4_IPV6) {
struct inet_connection_sock *icsk = inet_csk(sk);
icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
@@ -234,7 +234,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
case IPV6_V6ONLY:
if (optlen < sizeof(int) ||
- inet_sk(sk)->num)
+ inet_sk(sk)->inet_num)
goto e_inval;
np->ipv6only = valbool;
retv = 0;
@@ -424,6 +424,7 @@ sticky_done:
fl.fl6_flowlabel = 0;
fl.oif = sk->sk_bound_dev_if;
+ fl.mark = sk->sk_mark;
if (optlen == 0)
goto update;
@@ -496,13 +497,17 @@ done:
goto e_inval;
if (val) {
+ struct net_device *dev;
+
if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val)
goto e_inval;
- if (__dev_get_by_index(net, val) == NULL) {
+ dev = dev_get_by_index(net, val);
+ if (!dev) {
retv = -ENODEV;
break;
}
+ dev_put(dev);
}
np->mcast_oif = val;
retv = 0;
@@ -661,7 +666,7 @@ done:
case IPV6_MTU_DISCOVER:
if (optlen < sizeof(int))
goto e_inval;
- if (val<0 || val>3)
+ if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_PROBE)
goto e_inval;
np->pmtudisc = val;
retv = 0;
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index f74e4e2cdd06..3507cfe1e7a2 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -598,6 +598,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
icmp6h.icmp6_solicited = solicited;
icmp6h.icmp6_override = override;
+ inc_opt |= ifp->idev->cnf.force_tllao;
__ndisc_send(dev, neigh, daddr, src_addr,
&icmp6h, solicited_addr,
inc_opt ? ND_OPT_TARGET_LL_ADDR : 0);
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 4f24570b0869..cb834ab7f071 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -72,7 +72,7 @@ static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk,
int is_multicast = ipv6_addr_is_multicast(loc_addr);
sk_for_each_from(sk, node)
- if (inet_sk(sk)->num == num) {
+ if (inet_sk(sk)->inet_num == num) {
struct ipv6_pinfo *np = inet6_sk(sk);
if (!net_eq(sock_net(sk), net))
@@ -298,7 +298,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
dev_put(dev);
}
- inet->rcv_saddr = inet->saddr = v4addr;
+ inet->inet_rcv_saddr = inet->inet_saddr = v4addr;
ipv6_addr_copy(&np->rcv_saddr, &addr->sin6_addr);
if (!(addr_type & IPV6_ADDR_MULTICAST))
ipv6_addr_copy(&np->saddr, &addr->sin6_addr);
@@ -381,8 +381,7 @@ static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb)
}
/* Charge it to the socket. */
- if (sock_queue_rcv_skb(sk,skb)<0) {
- atomic_inc(&sk->sk_drops);
+ if (sock_queue_rcv_skb(sk, skb) < 0) {
kfree_skb(skb);
return NET_RX_DROP;
}
@@ -416,14 +415,14 @@ int rawv6_rcv(struct sock *sk, struct sk_buff *skb)
skb_network_header_len(skb));
if (!csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
&ipv6_hdr(skb)->daddr,
- skb->len, inet->num, skb->csum))
+ skb->len, inet->inet_num, skb->csum))
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
if (!skb_csum_unnecessary(skb))
skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
&ipv6_hdr(skb)->daddr,
skb->len,
- inet->num, 0));
+ inet->inet_num, 0));
if (inet->hdrincl) {
if (skb_checksum_complete(skb)) {
@@ -497,7 +496,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,
sin6->sin6_scope_id = IP6CB(skb)->iif;
}
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
if (np->rxopt.all)
datagram_recv_ctl(sk, msg, skb);
@@ -518,7 +517,6 @@ csum_copy_err:
as some normal condition.
*/
err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
- atomic_inc(&sk->sk_drops);
goto out;
}
@@ -766,8 +764,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
proto = ntohs(sin6->sin6_port);
if (!proto)
- proto = inet->num;
- else if (proto != inet->num)
+ proto = inet->inet_num;
+ else if (proto != inet->inet_num)
return(-EINVAL);
if (proto > 255)
@@ -800,7 +798,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
if (sk->sk_state != TCP_ESTABLISHED)
return -EDESTADDRREQ;
- proto = inet->num;
+ proto = inet->inet_num;
daddr = &np->daddr;
fl.fl6_flowlabel = np->flow_label;
}
@@ -967,7 +965,7 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname,
switch (optname) {
case IPV6_CHECKSUM:
- if (inet_sk(sk)->num == IPPROTO_ICMPV6 &&
+ if (inet_sk(sk)->inet_num == IPPROTO_ICMPV6 &&
level == IPPROTO_IPV6) {
/*
* RFC3542 tells that IPV6_CHECKSUM socket
@@ -1007,7 +1005,7 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname,
break;
case SOL_ICMPV6:
- if (inet_sk(sk)->num != IPPROTO_ICMPV6)
+ if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
return -EOPNOTSUPP;
return rawv6_seticmpfilter(sk, level, optname, optval,
optlen);
@@ -1030,7 +1028,7 @@ static int compat_rawv6_setsockopt(struct sock *sk, int level, int optname,
case SOL_RAW:
break;
case SOL_ICMPV6:
- if (inet_sk(sk)->num != IPPROTO_ICMPV6)
+ if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
return -EOPNOTSUPP;
return rawv6_seticmpfilter(sk, level, optname, optval, optlen);
case SOL_IPV6:
@@ -1087,7 +1085,7 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname,
break;
case SOL_ICMPV6:
- if (inet_sk(sk)->num != IPPROTO_ICMPV6)
+ if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
return -EOPNOTSUPP;
return rawv6_geticmpfilter(sk, level, optname, optval,
optlen);
@@ -1110,7 +1108,7 @@ static int compat_rawv6_getsockopt(struct sock *sk, int level, int optname,
case SOL_RAW:
break;
case SOL_ICMPV6:
- if (inet_sk(sk)->num != IPPROTO_ICMPV6)
+ if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
return -EOPNOTSUPP;
return rawv6_geticmpfilter(sk, level, optname, optval, optlen);
case SOL_IPV6:
@@ -1157,7 +1155,7 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg)
static void rawv6_close(struct sock *sk, long timeout)
{
- if (inet_sk(sk)->num == IPPROTO_RAW)
+ if (inet_sk(sk)->inet_num == IPPROTO_RAW)
ip6_ra_control(sk, -1);
ip6mr_sk_done(sk);
sk_common_release(sk);
@@ -1176,7 +1174,7 @@ static int rawv6_init_sk(struct sock *sk)
{
struct raw6_sock *rp = raw6_sk(sk);
- switch (inet_sk(sk)->num) {
+ switch (inet_sk(sk)->inet_num) {
case IPPROTO_ICMPV6:
rp->checksum = 1;
rp->offset = 2;
@@ -1226,7 +1224,7 @@ static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
dest = &np->daddr;
src = &np->rcv_saddr;
destp = 0;
- srcp = inet_sk(sp)->num;
+ srcp = inet_sk(sp)->inet_num;
seq_printf(seq,
"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
"%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index d6fe7646a8ff..df9432a46ffc 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1471,9 +1471,10 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest,
},
},
},
- .gateway = *gateway,
};
+ ipv6_addr_copy(&rdfl.gateway, gateway);
+
if (rt6_need_strict(dest))
flags |= RT6_LOOKUP_F_IFACE;
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index dbd19a78ca73..b6b16264b305 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -77,8 +77,17 @@ struct sit_net {
struct net_device *fb_tunnel_dev;
};
-static DEFINE_RWLOCK(ipip6_lock);
+/*
+ * Locking : hash tables are protected by RCU and a spinlock
+ */
+static DEFINE_SPINLOCK(ipip6_lock);
+#define for_each_ip_tunnel_rcu(start) \
+ for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
+
+/*
+ * 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)
{
@@ -87,26 +96,26 @@ static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net,
struct ip_tunnel *t;
struct sit_net *sitn = net_generic(net, sit_net_id);
- for (t = sitn->tunnels_r_l[h0^h1]; t; t = t->next) {
+ for_each_ip_tunnel_rcu(sitn->tunnels_r_l[h0 ^ h1]) {
if (local == t->parms.iph.saddr &&
remote == t->parms.iph.daddr &&
(!dev || !t->parms.link || dev->iflink == t->parms.link) &&
(t->dev->flags & IFF_UP))
return t;
}
- for (t = sitn->tunnels_r[h0]; t; t = t->next) {
+ for_each_ip_tunnel_rcu(sitn->tunnels_r[h0]) {
if (remote == t->parms.iph.daddr &&
(!dev || !t->parms.link || dev->iflink == t->parms.link) &&
(t->dev->flags & IFF_UP))
return t;
}
- for (t = sitn->tunnels_l[h1]; t; t = t->next) {
+ for_each_ip_tunnel_rcu(sitn->tunnels_l[h1]) {
if (local == t->parms.iph.saddr &&
(!dev || !t->parms.link || dev->iflink == t->parms.link) &&
(t->dev->flags & IFF_UP))
return t;
}
- t = sitn->tunnels_wc[0];
+ t = rcu_dereference(sitn->tunnels_wc[0]);
if ((t != NULL) && (t->dev->flags & IFF_UP))
return t;
return NULL;
@@ -143,9 +152,9 @@ static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t)
for (tp = ipip6_bucket(sitn, t); *tp; tp = &(*tp)->next) {
if (t == *tp) {
- write_lock_bh(&ipip6_lock);
+ spin_lock_bh(&ipip6_lock);
*tp = t->next;
- write_unlock_bh(&ipip6_lock);
+ spin_unlock_bh(&ipip6_lock);
break;
}
}
@@ -155,10 +164,27 @@ static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t)
{
struct ip_tunnel **tp = ipip6_bucket(sitn, t);
+ spin_lock_bh(&ipip6_lock);
t->next = *tp;
- write_lock_bh(&ipip6_lock);
- *tp = t;
- write_unlock_bh(&ipip6_lock);
+ rcu_assign_pointer(*tp, t);
+ spin_unlock_bh(&ipip6_lock);
+}
+
+static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn)
+{
+#ifdef CONFIG_IPV6_SIT_6RD
+ struct ip_tunnel *t = netdev_priv(dev);
+
+ if (t->dev == sitn->fb_tunnel_dev) {
+ ipv6_addr_set(&t->ip6rd.prefix, htonl(0x20020000), 0, 0, 0);
+ t->ip6rd.relay_prefix = 0;
+ t->ip6rd.prefixlen = 16;
+ t->ip6rd.relay_prefixlen = 0;
+ } else {
+ struct ip_tunnel *t0 = netdev_priv(sitn->fb_tunnel_dev);
+ memcpy(&t->ip6rd, &t0->ip6rd, sizeof(t->ip6rd));
+ }
+#endif
}
static struct ip_tunnel * ipip6_tunnel_locate(struct net *net,
@@ -204,6 +230,7 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net,
nt->parms = *parms;
ipip6_tunnel_init(dev);
+ ipip6_tunnel_clone_6rd(dev, sitn);
if (parms->i_flags & SIT_ISATAP)
dev->priv_flags |= IFF_ISATAP;
@@ -222,15 +249,22 @@ failed:
return NULL;
}
+static DEFINE_SPINLOCK(ipip6_prl_lock);
+
+#define for_each_prl_rcu(start) \
+ for (prl = rcu_dereference(start); \
+ prl; \
+ prl = rcu_dereference(prl->next))
+
static struct ip_tunnel_prl_entry *
__ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr)
{
- struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *)NULL;
+ struct ip_tunnel_prl_entry *prl;
- for (p = t->prl; p; p = p->next)
- if (p->addr == addr)
+ for_each_prl_rcu(t->prl)
+ if (prl->addr == addr)
break;
- return p;
+ return prl;
}
@@ -255,7 +289,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t,
kcalloc(cmax, sizeof(*kp), GFP_KERNEL) :
NULL;
- read_lock(&ipip6_lock);
+ rcu_read_lock();
ca = t->prl_count < cmax ? t->prl_count : cmax;
@@ -273,7 +307,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t,
}
c = 0;
- for (prl = t->prl; prl; prl = prl->next) {
+ for_each_prl_rcu(t->prl) {
if (c >= cmax)
break;
if (kprl.addr != htonl(INADDR_ANY) && prl->addr != kprl.addr)
@@ -285,7 +319,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t,
break;
}
out:
- read_unlock(&ipip6_lock);
+ rcu_read_unlock();
len = sizeof(*kp) * c;
ret = 0;
@@ -306,12 +340,14 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
if (a->addr == htonl(INADDR_ANY))
return -EINVAL;
- write_lock(&ipip6_lock);
+ spin_lock(&ipip6_prl_lock);
for (p = t->prl; p; p = p->next) {
if (p->addr == a->addr) {
- if (chg)
- goto update;
+ if (chg) {
+ p->flags = a->flags;
+ goto out;
+ }
err = -EEXIST;
goto out;
}
@@ -328,46 +364,63 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
goto out;
}
+ INIT_RCU_HEAD(&p->rcu_head);
p->next = t->prl;
- t->prl = p;
- t->prl_count++;
-update:
p->addr = a->addr;
p->flags = a->flags;
+ t->prl_count++;
+ rcu_assign_pointer(t->prl, p);
out:
- write_unlock(&ipip6_lock);
+ spin_unlock(&ipip6_prl_lock);
return err;
}
+static void prl_entry_destroy_rcu(struct rcu_head *head)
+{
+ kfree(container_of(head, struct ip_tunnel_prl_entry, rcu_head));
+}
+
+static void prl_list_destroy_rcu(struct rcu_head *head)
+{
+ struct ip_tunnel_prl_entry *p, *n;
+
+ p = container_of(head, struct ip_tunnel_prl_entry, rcu_head);
+ do {
+ n = p->next;
+ kfree(p);
+ p = n;
+ } while (p);
+}
+
static int
ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
{
struct ip_tunnel_prl_entry *x, **p;
int err = 0;
- write_lock(&ipip6_lock);
+ spin_lock(&ipip6_prl_lock);
if (a && a->addr != htonl(INADDR_ANY)) {
for (p = &t->prl; *p; p = &(*p)->next) {
if ((*p)->addr == a->addr) {
x = *p;
*p = x->next;
- kfree(x);
+ call_rcu(&x->rcu_head, prl_entry_destroy_rcu);
t->prl_count--;
goto out;
}
}
err = -ENXIO;
} else {
- while (t->prl) {
+ if (t->prl) {
+ t->prl_count = 0;
x = t->prl;
- t->prl = t->prl->next;
- kfree(x);
- t->prl_count--;
+ call_rcu(&x->rcu_head, prl_list_destroy_rcu);
+ t->prl = NULL;
}
}
out:
- write_unlock(&ipip6_lock);
+ spin_unlock(&ipip6_prl_lock);
return err;
}
@@ -377,7 +430,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t)
struct ip_tunnel_prl_entry *p;
int ok = 1;
- read_lock(&ipip6_lock);
+ rcu_read_lock();
p = __ipip6_tunnel_locate_prl(t, iph->saddr);
if (p) {
if (p->flags & PRL_DEFAULT)
@@ -393,7 +446,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t)
else
ok = 0;
}
- read_unlock(&ipip6_lock);
+ rcu_read_unlock();
return ok;
}
@@ -403,9 +456,9 @@ 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) {
- write_lock_bh(&ipip6_lock);
+ spin_lock_bh(&ipip6_lock);
sitn->tunnels_wc[0] = NULL;
- write_unlock_bh(&ipip6_lock);
+ spin_unlock_bh(&ipip6_lock);
dev_put(dev);
} else {
ipip6_tunnel_unlink(sitn, netdev_priv(dev));
@@ -458,7 +511,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info)
err = -ENOENT;
- read_lock(&ipip6_lock);
+ rcu_read_lock();
t = ipip6_tunnel_lookup(dev_net(skb->dev),
skb->dev,
iph->daddr,
@@ -476,7 +529,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info)
t->err_count = 1;
t->err_time = jiffies;
out:
- read_unlock(&ipip6_lock);
+ rcu_read_unlock();
return err;
}
@@ -496,7 +549,7 @@ static int ipip6_rcv(struct sk_buff *skb)
iph = ip_hdr(skb);
- read_lock(&ipip6_lock);
+ rcu_read_lock();
tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev,
iph->saddr, iph->daddr);
if (tunnel != NULL) {
@@ -510,7 +563,7 @@ static int ipip6_rcv(struct sk_buff *skb)
if ((tunnel->dev->priv_flags & IFF_ISATAP) &&
!isatap_chksrc(skb, iph, tunnel)) {
tunnel->dev->stats.rx_errors++;
- read_unlock(&ipip6_lock);
+ rcu_read_unlock();
kfree_skb(skb);
return 0;
}
@@ -521,28 +574,52 @@ static int ipip6_rcv(struct sk_buff *skb)
nf_reset(skb);
ipip6_ecn_decapsulate(iph, skb);
netif_rx(skb);
- read_unlock(&ipip6_lock);
+ rcu_read_unlock();
return 0;
}
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
- read_unlock(&ipip6_lock);
+ rcu_read_unlock();
out:
kfree_skb(skb);
return 0;
}
-/* Returns the embedded IPv4 address if the IPv6 address
- comes from 6to4 (RFC 3056) addr space */
-
-static inline __be32 try_6to4(struct in6_addr *v6dst)
+/*
+ * Returns the embedded IPv4 address if the IPv6 address
+ * comes from 6rd / 6to4 (RFC 3056) addr space.
+ */
+static inline
+__be32 try_6rd(struct in6_addr *v6dst, struct ip_tunnel *tunnel)
{
__be32 dst = 0;
+#ifdef CONFIG_IPV6_SIT_6RD
+ if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix,
+ tunnel->ip6rd.prefixlen)) {
+ unsigned pbw0, pbi0;
+ int pbi1;
+ u32 d;
+
+ pbw0 = tunnel->ip6rd.prefixlen >> 5;
+ pbi0 = tunnel->ip6rd.prefixlen & 0x1f;
+
+ d = (ntohl(v6dst->s6_addr32[pbw0]) << pbi0) >>
+ tunnel->ip6rd.relay_prefixlen;
+
+ pbi1 = pbi0 - tunnel->ip6rd.relay_prefixlen;
+ if (pbi1 > 0)
+ d |= ntohl(v6dst->s6_addr32[pbw0 + 1]) >>
+ (32 - pbi1);
+
+ dst = tunnel->ip6rd.relay_prefix | htonl(d);
+ }
+#else
if (v6dst->s6_addr16[0] == htons(0x2002)) {
/* 6to4 v6 addr has 16 bits prefix, 32 v4addr, 16 SLA, ... */
memcpy(&dst, &v6dst->s6_addr16[1], 4);
}
+#endif
return dst;
}
@@ -555,7 +632,8 @@ 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 = &tunnel->dev->stats;
+ struct net_device_stats *stats = &dev->stats;
+ struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
struct iphdr *tiph = &tunnel->parms.iph;
struct ipv6hdr *iph6 = ipv6_hdr(skb);
u8 tos = tunnel->parms.iph.tos;
@@ -595,7 +673,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
}
if (!dst)
- dst = try_6to4(&iph6->daddr);
+ dst = try_6rd(&iph6->daddr, tunnel);
if (!dst) {
struct neighbour *neigh = NULL;
@@ -688,7 +766,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);
- stats->tx_dropped++;
+ txq->tx_dropped++;
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
@@ -785,9 +863,15 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
struct ip_tunnel *t;
struct net *net = dev_net(dev);
struct sit_net *sitn = net_generic(net, sit_net_id);
+#ifdef CONFIG_IPV6_SIT_6RD
+ struct ip_tunnel_6rd ip6rd;
+#endif
switch (cmd) {
case SIOCGETTUNNEL:
+#ifdef CONFIG_IPV6_SIT_6RD
+ case SIOCGET6RD:
+#endif
t = NULL;
if (dev == sitn->fb_tunnel_dev) {
if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
@@ -798,9 +882,25 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
}
if (t == NULL)
t = netdev_priv(dev);
- memcpy(&p, &t->parms, sizeof(p));
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
- err = -EFAULT;
+
+ err = -EFAULT;
+ if (cmd == SIOCGETTUNNEL) {
+ memcpy(&p, &t->parms, sizeof(p));
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &p,
+ sizeof(p)))
+ goto done;
+#ifdef CONFIG_IPV6_SIT_6RD
+ } else {
+ ipv6_addr_copy(&ip6rd.prefix, &t->ip6rd.prefix);
+ ip6rd.relay_prefix = t->ip6rd.relay_prefix;
+ ip6rd.prefixlen = t->ip6rd.prefixlen;
+ ip6rd.relay_prefixlen = t->ip6rd.relay_prefixlen;
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &ip6rd,
+ sizeof(ip6rd)))
+ goto done;
+#endif
+ }
+ err = 0;
break;
case SIOCADDTUNNEL:
@@ -921,6 +1021,54 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
netdev_state_change(dev);
break;
+#ifdef CONFIG_IPV6_SIT_6RD
+ case SIOCADD6RD:
+ case SIOCCHG6RD:
+ case SIOCDEL6RD:
+ err = -EPERM;
+ if (!capable(CAP_NET_ADMIN))
+ goto done;
+
+ err = -EFAULT;
+ if (copy_from_user(&ip6rd, ifr->ifr_ifru.ifru_data,
+ sizeof(ip6rd)))
+ goto done;
+
+ t = netdev_priv(dev);
+
+ if (cmd != SIOCDEL6RD) {
+ struct in6_addr prefix;
+ __be32 relay_prefix;
+
+ err = -EINVAL;
+ if (ip6rd.relay_prefixlen > 32 ||
+ ip6rd.prefixlen + (32 - ip6rd.relay_prefixlen) > 64)
+ goto done;
+
+ ipv6_addr_prefix(&prefix, &ip6rd.prefix,
+ ip6rd.prefixlen);
+ if (!ipv6_addr_equal(&prefix, &ip6rd.prefix))
+ goto done;
+ if (ip6rd.relay_prefixlen)
+ relay_prefix = ip6rd.relay_prefix &
+ htonl(0xffffffffUL <<
+ (32 - ip6rd.relay_prefixlen));
+ else
+ relay_prefix = 0;
+ if (relay_prefix != ip6rd.relay_prefix)
+ goto done;
+
+ ipv6_addr_copy(&t->ip6rd.prefix, &prefix);
+ t->ip6rd.relay_prefix = relay_prefix;
+ t->ip6rd.prefixlen = ip6rd.prefixlen;
+ t->ip6rd.relay_prefixlen = ip6rd.relay_prefixlen;
+ } else
+ ipip6_tunnel_clone_6rd(dev, sitn);
+
+ err = 0;
+ break;
+#endif
+
default:
err = -EINVAL;
}
@@ -1039,6 +1187,7 @@ static int sit_init_net(struct net *net)
dev_net_set(sitn->fb_tunnel_dev, net);
ipip6_fb_tunnel_init(sitn->fb_tunnel_dev);
+ ipip6_tunnel_clone_6rd(sitn->fb_tunnel_dev, sitn);
if ((err = register_netdev(sitn->fb_tunnel_dev)))
goto err_reg_dev;
@@ -1078,6 +1227,7 @@ static void __exit sit_cleanup(void)
xfrm4_tunnel_deregister(&sit_handler, AF_INET6);
unregister_pernet_gen_device(sit_net_id, &sit_net_ops);
+ rcu_barrier(); /* Wait for completion of call_rcu()'s */
}
static int __init sit_init(void)
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 6b6ae913b5d4..c46da533888a 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -252,8 +252,9 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
}
ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
fl.oif = sk->sk_bound_dev_if;
+ fl.mark = sk->sk_mark;
fl.fl_ip_dport = inet_rsk(req)->rmt_port;
- fl.fl_ip_sport = inet_sk(sk)->sport;
+ fl.fl_ip_sport = inet_sk(sk)->inet_sport;
security_req_classify_flow(req, &fl);
if (ip6_dst_lookup(sk, &dst, &fl))
goto out_free;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 21d100b68b19..c54ec3615ded 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -226,10 +226,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
#endif
goto failure;
} else {
- ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
- inet->saddr);
- ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
- inet->rcv_saddr);
+ ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr);
+ ipv6_addr_set_v4mapped(inet->inet_rcv_saddr,
+ &np->rcv_saddr);
}
return err;
@@ -243,8 +242,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
ipv6_addr_copy(&fl.fl6_src,
(saddr ? saddr : &np->saddr));
fl.oif = sk->sk_bound_dev_if;
+ fl.mark = sk->sk_mark;
fl.fl_ip_dport = usin->sin6_port;
- fl.fl_ip_sport = inet->sport;
+ fl.fl_ip_sport = inet->inet_sport;
if (np->opt && np->opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
@@ -276,7 +276,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
/* set the source address */
ipv6_addr_copy(&np->saddr, saddr);
- inet->rcv_saddr = LOOPBACK4_IPV6;
+ inet->inet_rcv_saddr = LOOPBACK4_IPV6;
sk->sk_gso_type = SKB_GSO_TCPV6;
__ip6_dst_store(sk, dst, NULL, NULL);
@@ -288,7 +288,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
- inet->dport = usin->sin6_port;
+ inet->inet_dport = usin->sin6_port;
tcp_set_state(sk, TCP_SYN_SENT);
err = inet6_hash_connect(&tcp_death_row, sk);
@@ -298,8 +298,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
if (!tp->write_seq)
tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
np->daddr.s6_addr32,
- inet->sport,
- inet->dport);
+ inet->inet_sport,
+ inet->inet_dport);
err = tcp_connect(sk);
if (err)
@@ -311,7 +311,7 @@ late_failure:
tcp_set_state(sk, TCP_CLOSE);
__sk_dst_reset(sk);
failure:
- inet->dport = 0;
+ inet->inet_dport = 0;
sk->sk_route_caps = 0;
return err;
}
@@ -383,8 +383,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
ipv6_addr_copy(&fl.fl6_src, &np->saddr);
fl.oif = sk->sk_bound_dev_if;
- fl.fl_ip_dport = inet->dport;
- fl.fl_ip_sport = inet->sport;
+ fl.mark = sk->sk_mark;
+ fl.fl_ip_dport = inet->inet_dport;
+ fl.fl_ip_sport = inet->inet_sport;
security_skb_classify_flow(skb, &fl);
if ((err = ip6_dst_lookup(sk, &dst, &fl))) {
@@ -477,6 +478,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req)
ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
fl.fl6_flowlabel = 0;
fl.oif = treq->iif;
+ fl.mark = sk->sk_mark;
fl.fl_ip_dport = inet_rsk(req)->rmt_port;
fl.fl_ip_sport = inet_rsk(req)->loc_port;
security_req_classify_flow(req, &fl);
@@ -1290,11 +1292,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
memcpy(newnp, np, sizeof(struct ipv6_pinfo));
- ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),
- newinet->daddr);
+ ipv6_addr_set_v4mapped(newinet->inet_daddr, &newnp->daddr);
- ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
- newinet->saddr);
+ ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr);
ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
@@ -1345,6 +1345,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
}
ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
fl.oif = sk->sk_bound_dev_if;
+ fl.mark = sk->sk_mark;
fl.fl_ip_dport = inet_rsk(req)->rmt_port;
fl.fl_ip_sport = inet_rsk(req)->loc_port;
security_req_classify_flow(req, &fl);
@@ -1431,7 +1432,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
tcp_initialize_rcv_mss(newsk);
- newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
+ newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
+ newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
#ifdef CONFIG_TCP_MD5SIG
/* Copy over the MD5 key from the original socket */
@@ -1931,8 +1933,8 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
dest = &np->daddr;
src = &np->rcv_saddr;
- destp = ntohs(inet->dport);
- srcp = ntohs(inet->sport);
+ destp = ntohs(inet->inet_dport);
+ srcp = ntohs(inet->inet_sport);
if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
timer_active = 1;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 3a60f12b34ed..d3b59d73f507 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -53,7 +53,7 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
{
const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr;
const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2);
- __be32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr;
+ __be32 sk1_rcv_saddr = inet_sk(sk)->inet_rcv_saddr;
__be32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
int sk_ipv6only = ipv6_only_sock(sk);
int sk2_ipv6only = inet_v6_ipv6only(sk2);
@@ -63,8 +63,8 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
/* if both are mapped, treat as IPv4 */
if (addr_type == IPV6_ADDR_MAPPED && addr_type2 == IPV6_ADDR_MAPPED)
return (!sk2_ipv6only &&
- (!sk_rcv_saddr || !sk2_rcv_saddr ||
- sk_rcv_saddr == sk2_rcv_saddr));
+ (!sk1_rcv_saddr || !sk2_rcv_saddr ||
+ sk1_rcv_saddr == sk2_rcv_saddr));
if (addr_type2 == IPV6_ADDR_ANY &&
!(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED))
@@ -100,8 +100,8 @@ static inline int compute_score(struct sock *sk, struct net *net,
struct inet_sock *inet = inet_sk(sk);
score = 0;
- if (inet->dport) {
- if (inet->dport != sport)
+ if (inet->inet_dport) {
+ if (inet->inet_dport != sport)
return -1;
score++;
}
@@ -132,7 +132,7 @@ static struct sock *__udp6_lib_lookup(struct net *net,
struct sock *sk, *result;
struct hlist_nulls_node *node;
unsigned short hnum = ntohs(dport);
- unsigned int hash = udp_hashfn(net, hnum);
+ unsigned int hash = udp_hashfn(net, hnum, udptable->mask);
struct udp_hslot *hslot = &udptable->hash[hash];
int score, badness;
@@ -252,7 +252,7 @@ try_again:
UDP_MIB_INDATAGRAMS, is_udplite);
}
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
/* Copy the address. */
if (msg->msg_name) {
@@ -265,8 +265,8 @@ try_again:
sin6->sin6_scope_id = 0;
if (is_udp4)
- ipv6_addr_set(&sin6->sin6_addr, 0, 0,
- htonl(0xffff), ip_hdr(skb)->saddr);
+ ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr,
+ &sin6->sin6_addr);
else {
ipv6_addr_copy(&sin6->sin6_addr,
&ipv6_hdr(skb)->saddr);
@@ -385,18 +385,18 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
goto drop;
}
- if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) {
+ if ((rc = sock_queue_rcv_skb(sk, skb)) < 0) {
/* Note that an ENOMEM error is charged twice */
- if (rc == -ENOMEM) {
+ if (rc == -ENOMEM)
UDP6_INC_STATS_BH(sock_net(sk),
UDP_MIB_RCVBUFERRORS, is_udplite);
- atomic_inc(&sk->sk_drops);
- }
- goto drop;
+ goto drop_no_sk_drops_inc;
}
return 0;
drop:
+ atomic_inc(&sk->sk_drops);
+drop_no_sk_drops_inc:
UDP6_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
kfree_skb(skb);
return -1;
@@ -419,8 +419,8 @@ static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk,
if (s->sk_hash == num && s->sk_family == PF_INET6) {
struct ipv6_pinfo *np = inet6_sk(s);
- if (inet->dport) {
- if (inet->dport != rmt_port)
+ if (inet->inet_dport) {
+ if (inet->inet_dport != rmt_port)
continue;
}
if (!ipv6_addr_any(&np->daddr) &&
@@ -452,7 +452,7 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
{
struct sock *sk, *sk2;
const struct udphdr *uh = udp_hdr(skb);
- struct udp_hslot *hslot = &udptable->hash[udp_hashfn(net, ntohs(uh->dest))];
+ struct udp_hslot *hslot = udp_hashslot(udptable, net, ntohs(uh->dest));
int dif;
spin_lock(&hslot->lock);
@@ -794,7 +794,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
if (ipv6_addr_v4mapped(daddr)) {
struct sockaddr_in sin;
sin.sin_family = AF_INET;
- sin.sin_port = sin6 ? sin6->sin6_port : inet->dport;
+ sin.sin_port = sin6 ? sin6->sin6_port : inet->inet_dport;
sin.sin_addr.s_addr = daddr->s6_addr32[3];
msg->msg_name = &sin;
msg->msg_namelen = sizeof(sin);
@@ -867,7 +867,7 @@ do_udp_sendmsg:
if (sk->sk_state != TCP_ESTABLISHED)
return -EDESTADDRREQ;
- fl.fl_ip_dport = inet->dport;
+ fl.fl_ip_dport = inet->inet_dport;
daddr = &np->daddr;
fl.fl6_flowlabel = np->flow_label;
connected = 1;
@@ -879,6 +879,8 @@ do_udp_sendmsg:
if (!fl.oif)
fl.oif = np->sticky_pktinfo.ipi6_ifindex;
+ fl.mark = sk->sk_mark;
+
if (msg->msg_controllen) {
opt = &opt_space;
memset(opt, 0, sizeof(struct ipv6_txoptions));
@@ -911,7 +913,7 @@ do_udp_sendmsg:
fl.fl6_dst.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */
if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr))
ipv6_addr_copy(&fl.fl6_src, &np->saddr);
- fl.fl_ip_sport = inet->sport;
+ fl.fl_ip_sport = inet->inet_sport;
/* merge ip6_build_xmit from ip6_output */
if (opt && opt->srcrt) {
@@ -1192,10 +1194,10 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket
dest = &np->daddr;
src = &np->rcv_saddr;
- destp = ntohs(inet->dport);
- srcp = ntohs(inet->sport);
+ destp = ntohs(inet->inet_dport);
+ srcp = ntohs(inet->inet_sport);
seq_printf(seq,
- "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
+ "%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
"%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
bucket,
src->s6_addr32[0], src->s6_addr32[1],
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index 81a95c00e503..438831d33593 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -23,7 +23,7 @@
*/
#include <linux/module.h>
#include <linux/xfrm.h>
-#include <linux/list.h>
+#include <linux/rculist.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/ipv6.h>
@@ -36,14 +36,15 @@
* per xfrm_address_t.
*/
struct xfrm6_tunnel_spi {
- struct hlist_node list_byaddr;
- struct hlist_node list_byspi;
- xfrm_address_t addr;
- u32 spi;
- atomic_t refcnt;
+ struct hlist_node list_byaddr;
+ struct hlist_node list_byspi;
+ xfrm_address_t addr;
+ u32 spi;
+ atomic_t refcnt;
+ struct rcu_head rcu_head;
};
-static DEFINE_RWLOCK(xfrm6_tunnel_spi_lock);
+static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock);
static u32 xfrm6_tunnel_spi;
@@ -107,6 +108,7 @@ static void xfrm6_tunnel_spi_fini(void)
if (!hlist_empty(&xfrm6_tunnel_spi_byspi[i]))
return;
}
+ rcu_barrier();
kmem_cache_destroy(xfrm6_tunnel_spi_kmem);
xfrm6_tunnel_spi_kmem = NULL;
}
@@ -116,7 +118,7 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
struct xfrm6_tunnel_spi *x6spi;
struct hlist_node *pos;
- hlist_for_each_entry(x6spi, pos,
+ hlist_for_each_entry_rcu(x6spi, pos,
&xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)],
list_byaddr) {
if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0)
@@ -131,10 +133,10 @@ __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
struct xfrm6_tunnel_spi *x6spi;
u32 spi;
- read_lock_bh(&xfrm6_tunnel_spi_lock);
+ rcu_read_lock_bh();
x6spi = __xfrm6_tunnel_spi_lookup(saddr);
spi = x6spi ? x6spi->spi : 0;
- read_unlock_bh(&xfrm6_tunnel_spi_lock);
+ rcu_read_unlock_bh();
return htonl(spi);
}
@@ -185,14 +187,15 @@ alloc_spi:
if (!x6spi)
goto out;
+ INIT_RCU_HEAD(&x6spi->rcu_head);
memcpy(&x6spi->addr, saddr, sizeof(x6spi->addr));
x6spi->spi = spi;
atomic_set(&x6spi->refcnt, 1);
- hlist_add_head(&x6spi->list_byspi, &xfrm6_tunnel_spi_byspi[index]);
+ hlist_add_head_rcu(&x6spi->list_byspi, &xfrm6_tunnel_spi_byspi[index]);
index = xfrm6_tunnel_spi_hash_byaddr(saddr);
- hlist_add_head(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]);
+ hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]);
out:
return spi;
}
@@ -202,26 +205,32 @@ __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr)
struct xfrm6_tunnel_spi *x6spi;
u32 spi;
- write_lock_bh(&xfrm6_tunnel_spi_lock);
+ spin_lock_bh(&xfrm6_tunnel_spi_lock);
x6spi = __xfrm6_tunnel_spi_lookup(saddr);
if (x6spi) {
atomic_inc(&x6spi->refcnt);
spi = x6spi->spi;
} else
spi = __xfrm6_tunnel_alloc_spi(saddr);
- write_unlock_bh(&xfrm6_tunnel_spi_lock);
+ spin_unlock_bh(&xfrm6_tunnel_spi_lock);
return htonl(spi);
}
EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi);
+static void x6spi_destroy_rcu(struct rcu_head *head)
+{
+ kmem_cache_free(xfrm6_tunnel_spi_kmem,
+ container_of(head, struct xfrm6_tunnel_spi, rcu_head));
+}
+
void xfrm6_tunnel_free_spi(xfrm_address_t *saddr)
{
struct xfrm6_tunnel_spi *x6spi;
struct hlist_node *pos, *n;
- write_lock_bh(&xfrm6_tunnel_spi_lock);
+ spin_lock_bh(&xfrm6_tunnel_spi_lock);
hlist_for_each_entry_safe(x6spi, pos, n,
&xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)],
@@ -229,14 +238,14 @@ void xfrm6_tunnel_free_spi(xfrm_address_t *saddr)
{
if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) {
if (atomic_dec_and_test(&x6spi->refcnt)) {
- hlist_del(&x6spi->list_byaddr);
- hlist_del(&x6spi->list_byspi);
- kmem_cache_free(xfrm6_tunnel_spi_kmem, x6spi);
+ hlist_del_rcu(&x6spi->list_byaddr);
+ hlist_del_rcu(&x6spi->list_byspi);
+ call_rcu(&x6spi->rcu_head, x6spi_destroy_rcu);
break;
}
}
}
- write_unlock_bh(&xfrm6_tunnel_spi_lock);
+ spin_unlock_bh(&xfrm6_tunnel_spi_lock);
}
EXPORT_SYMBOL(xfrm6_tunnel_free_spi);
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
index 66c7a20011f3..6481ee4bdf72 100644
--- a/net/ipx/af_ipx.c
+++ b/net/ipx/af_ipx.c
@@ -1927,7 +1927,7 @@ static int ipx_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long
* Socket family declarations
*/
-static struct net_proto_family ipx_family_ops = {
+static const struct net_proto_family ipx_family_ops = {
.family = PF_IPX,
.create = ipx_create,
.owner = THIS_MODULE,
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index dd35641835f4..9429e4002bca 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -2463,7 +2463,7 @@ bed:
return 0;
}
-static struct net_proto_family irda_family_ops = {
+static const struct net_proto_family irda_family_ops = {
.family = PF_IRDA,
.create = irda_create,
.owner = THIS_MODULE,
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index bada1b9c670b..3aebabb158a8 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -428,7 +428,6 @@ static void iucv_sock_close(struct sock *sk)
break;
default:
- sock_set_flag(sk, SOCK_ZAPPED);
/* nothing to do here */
break;
}
@@ -536,7 +535,7 @@ void iucv_accept_enqueue(struct sock *parent, struct sock *sk)
list_add_tail(&iucv_sk(sk)->accept_q, &par->accept_q);
spin_unlock_irqrestore(&par->accept_q_lock, flags);
iucv_sk(sk)->parent = parent;
- parent->sk_ack_backlog++;
+ sk_acceptq_added(parent);
}
void iucv_accept_unlink(struct sock *sk)
@@ -547,7 +546,7 @@ void iucv_accept_unlink(struct sock *sk)
spin_lock_irqsave(&par->accept_q_lock, flags);
list_del_init(&iucv_sk(sk)->accept_q);
spin_unlock_irqrestore(&par->accept_q_lock, flags);
- iucv_sk(sk)->parent->sk_ack_backlog--;
+ sk_acceptq_removed(iucv_sk(sk)->parent);
iucv_sk(sk)->parent = NULL;
sock_put(sk);
}
@@ -1715,7 +1714,7 @@ static const struct proto_ops iucv_sock_ops = {
.getsockopt = iucv_sock_getsockopt,
};
-static struct net_proto_family iucv_sock_family_ops = {
+static const struct net_proto_family iucv_sock_family_ops = {
.family = AF_IUCV,
.owner = THIS_MODULE,
.create = iucv_sock_create,
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 4e98193dfa0f..472f6594184a 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -3606,7 +3606,7 @@ static int pfkey_recvmsg(struct kiocb *kiocb,
if (err)
goto out_free;
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
err = (flags & MSG_TRUNC) ? skb->len : copied;
@@ -3644,7 +3644,7 @@ static const struct proto_ops pfkey_ops = {
.recvmsg = pfkey_recvmsg,
};
-static struct net_proto_family pfkey_family_ops = {
+static const struct net_proto_family pfkey_family_ops = {
.family = PF_KEY,
.create = pfkey_create,
.owner = THIS_MODULE,
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index 7aa4fd170104..4866b4fb0c27 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -1092,7 +1092,7 @@ out:
return rc;
}
-static struct net_proto_family llc_ui_family_ops = {
+static const struct net_proto_family llc_ui_family_ops = {
.family = PF_LLC,
.create = llc_ui_create,
.owner = THIS_MODULE,
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 6eaf69823439..ca8ecce31d34 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -538,13 +538,12 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
WLAN_CAPABILITY_PRIVACY,
capability);
+ if (bss) {
#ifdef CONFIG_MAC80211_IBSS_DEBUG
- if (bss)
printk(KERN_DEBUG " sta_find_ibss: selected %pM current "
"%pM\n", bss->cbss.bssid, ifibss->bssid);
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
- if (bss && !memcmp(ifibss->bssid, bss->cbss.bssid, ETH_ALEN)) {
printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"
" based on configured SSID\n",
sdata->dev->name, bss->cbss.bssid);
@@ -552,8 +551,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
ieee80211_sta_join_ibss(sdata, bss);
ieee80211_rx_bss_put(local, bss);
return;
- } else if (bss)
- ieee80211_rx_bss_put(local, bss);
+ }
#ifdef CONFIG_MAC80211_IBSS_DEBUG
printk(KERN_DEBUG " did not try to join ibss\n");
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index b8295cbd7e8f..14f10eb91c5c 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -184,10 +184,12 @@ static int ieee80211_open(struct net_device *dev)
* No need to check netif_running since we do not allow
* it to start up with this invalid address.
*/
- if (compare_ether_addr(null_addr, ndev->dev_addr) == 0)
+ 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);
+ }
}
/*
@@ -312,7 +314,7 @@ static int ieee80211_open(struct net_device *dev)
if (sdata->vif.type == NL80211_IFTYPE_STATION)
ieee80211_queue_work(&local->hw, &sdata->u.mgd.work);
- netif_tx_start_all_queues(dev);
+ netif_start_queue(dev);
return 0;
err_del_interface:
@@ -341,7 +343,7 @@ static int ieee80211_stop(struct net_device *dev)
/*
* Stop TX on this interface first.
*/
- netif_tx_stop_all_queues(dev);
+ netif_stop_queue(dev);
/*
* Now delete all active aggregation sessions.
@@ -754,10 +756,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
return 0;
}
-static struct device_type wiphy_type = {
- .name = "wlan",
-};
-
int ieee80211_if_add(struct ieee80211_local *local, const char *name,
struct net_device **new_dev, enum nl80211_iftype type,
struct vif_params *params)
@@ -788,8 +786,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
goto fail;
memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
+ memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN);
SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
- SET_NETDEV_DEVTYPE(ndev, &wiphy_type);
/* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */
sdata = netdev_priv(ndev);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index f7364e56f1ee..9a733890eb47 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -50,7 +50,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data)
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
- ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING;
+ set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
if (local->quiescing) {
set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
@@ -480,7 +480,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_local *local = sdata->local;
- ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING;
+ set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
ieee80211_queue_work(&local->hw, &ifmsh->work);
sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index e12a786e26b8..29b82e98effa 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -259,7 +259,7 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local,
* @hwmp_ie: hwmp information element (PREP or PREQ)
*
* This function updates the path routing information to the originator and the
- * transmitter of a HWMP PREQ or PREP fram.
+ * transmitter of a HWMP PREQ or PREP frame.
*
* Returns: metric to frame originator or 0 if the frame should not be further
* processed
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 8d26e9bf8964..dcc14e99227c 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -458,9 +458,15 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
mgmt->u.deauth.reason_code = cpu_to_le16(reason);
if (stype == IEEE80211_STYPE_DEAUTH)
- cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, cookie);
+ if (cookie)
+ __cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
+ else
+ cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
else
- cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len, cookie);
+ if (cookie)
+ __cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
+ else
+ cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED);
}
@@ -923,7 +929,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
ieee80211_recalc_ps(local, -1);
mutex_unlock(&local->iflist_mtx);
- netif_tx_start_all_queues(sdata->dev);
+ netif_start_queue(sdata->dev);
netif_carrier_on(sdata->dev);
}
@@ -1055,7 +1061,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
* time -- we don't want the scan code to enable queues.
*/
- netif_tx_stop_all_queues(sdata->dev);
+ netif_stop_queue(sdata->dev);
netif_carrier_off(sdata->dev);
rcu_read_lock();
@@ -1457,8 +1463,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
if (status_code != WLAN_STATUS_SUCCESS) {
printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
sdata->dev->name, status_code);
- list_del(&wk->list);
- kfree(wk);
+ wk->state = IEEE80211_MGD_STATE_IDLE;
return RX_MGMT_CFG80211_ASSOC;
}
@@ -1959,12 +1964,10 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
/* no action */
break;
case RX_MGMT_CFG80211_DEAUTH:
- cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len,
- NULL);
+ cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
break;
case RX_MGMT_CFG80211_DISASSOC:
- cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len,
- NULL);
+ cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
break;
default:
WARN(1, "unexpected: %d", rma);
@@ -2019,7 +2022,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len);
break;
case RX_MGMT_CFG80211_DEAUTH:
- cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, NULL);
+ cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
break;
default:
WARN(1, "unexpected: %d", rma);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 7170bf4565a8..5c385e3c1d1f 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1504,19 +1504,28 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
/* illegal frame */
return RX_DROP_MONITOR;
- if (!is_multicast_ether_addr(hdr->addr1) &&
- (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6)) {
+ if (mesh_hdr->flags & MESH_FLAGS_AE) {
struct mesh_path *mppath;
+ char *proxied_addr;
+ char *mpp_addr;
+
+ if (is_multicast_ether_addr(hdr->addr1)) {
+ mpp_addr = hdr->addr3;
+ proxied_addr = mesh_hdr->eaddr1;
+ } else {
+ mpp_addr = hdr->addr4;
+ proxied_addr = mesh_hdr->eaddr2;
+ }
rcu_read_lock();
- mppath = mpp_path_lookup(mesh_hdr->eaddr2, sdata);
+ mppath = mpp_path_lookup(proxied_addr, sdata);
if (!mppath) {
- mpp_path_add(mesh_hdr->eaddr2, hdr->addr4, sdata);
+ mpp_path_add(proxied_addr, mpp_addr, sdata);
} else {
spin_lock_bh(&mppath->state_lock);
mppath->exp_time = jiffies;
- if (compare_ether_addr(mppath->mpp, hdr->addr4) != 0)
- memcpy(mppath->mpp, hdr->addr4, ETH_ALEN);
+ if (compare_ether_addr(mppath->mpp, mpp_addr) != 0)
+ memcpy(mppath->mpp, mpp_addr, ETH_ALEN);
spin_unlock_bh(&mppath->state_lock);
}
rcu_read_unlock();
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 71e10cabf811..7a350d2690a0 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -306,10 +306,10 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
if (sdata->u.mgd.associated) {
ieee80211_scan_ps_disable(sdata);
- netif_tx_wake_all_queues(sdata->dev);
+ netif_wake_queue(sdata->dev);
}
} else
- netif_tx_wake_all_queues(sdata->dev);
+ netif_wake_queue(sdata->dev);
/* re-enable beaconing */
if (sdata->vif.type == NL80211_IFTYPE_AP ||
@@ -364,7 +364,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
* are handled in the scan state machine
*/
if (sdata->vif.type != NL80211_IFTYPE_STATION)
- netif_tx_stop_all_queues(sdata->dev);
+ netif_stop_queue(sdata->dev);
}
mutex_unlock(&local->iflist_mtx);
@@ -523,7 +523,7 @@ static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *loca
continue;
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
- netif_tx_stop_all_queues(sdata->dev);
+ netif_stop_queue(sdata->dev);
if (sdata->u.mgd.associated)
ieee80211_scan_ps_enable(sdata);
}
@@ -558,7 +558,7 @@ static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *loca
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
if (sdata->u.mgd.associated)
ieee80211_scan_ps_disable(sdata);
- netif_tx_wake_all_queues(sdata->dev);
+ netif_wake_queue(sdata->dev);
}
}
mutex_unlock(&local->iflist_mtx);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index db4bda681ec9..eaa4118de988 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1445,7 +1445,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
if (tmp_sdata->vif.type != NL80211_IFTYPE_AP)
continue;
if (compare_ether_addr(tmp_sdata->dev->dev_addr,
- hdr->addr2)) {
+ hdr->addr2) == 0) {
dev_hold(tmp_sdata->dev);
dev_put(sdata->dev);
sdata = tmp_sdata;
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
index ebf00ad5b194..362afbd60a96 100644
--- a/net/netfilter/xt_socket.c
+++ b/net/netfilter/xt_socket.c
@@ -149,7 +149,7 @@ socket_match(const struct sk_buff *skb, const struct xt_match_param *par,
/* Ignore sockets listening on INADDR_ANY */
wildcard = (sk->sk_state != TCP_TIME_WAIT &&
- inet_sk(sk)->rcv_saddr == 0);
+ inet_sk(sk)->inet_rcv_saddr == 0);
/* Ignore non-transparent sockets,
if XT_SOCKET_TRANSPARENT is used */
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 19e98007691c..0cd2d8829313 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -2050,7 +2050,7 @@ static const struct proto_ops netlink_ops = {
.sendpage = sock_no_sendpage,
};
-static struct net_proto_family netlink_family_ops = {
+static const struct net_proto_family netlink_family_ops = {
.family = PF_NETLINK,
.create = netlink_create,
.owner = THIS_MODULE, /* for consistency 8) */
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 44ff3f3810fa..d07ecda0a92d 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -97,25 +97,17 @@ static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family)
*/
static inline u16 genl_generate_id(void)
{
- static u16 id_gen_idx;
- int overflowed = 0;
+ static u16 id_gen_idx = GENL_MIN_ID;
+ int i;
- do {
- if (id_gen_idx == 0)
+ for (i = 0; i <= GENL_MAX_ID - GENL_MIN_ID; i++) {
+ if (!genl_family_find_byid(id_gen_idx))
+ return id_gen_idx;
+ if (++id_gen_idx > GENL_MAX_ID)
id_gen_idx = GENL_MIN_ID;
+ }
- if (++id_gen_idx > GENL_MAX_ID) {
- if (!overflowed) {
- overflowed = 1;
- id_gen_idx = 0;
- continue;
- } else
- return 0;
- }
-
- } while (genl_family_find_byid(id_gen_idx));
-
- return id_gen_idx;
+ return 0;
}
static struct genl_multicast_group notify_grp;
@@ -374,11 +366,6 @@ int genl_register_family(struct genl_family *family)
goto errout_locked;
}
- if (genl_family_find_byid(family->id)) {
- err = -EEXIST;
- goto errout_locked;
- }
-
if (family->id == GENL_ID_GENERATE) {
u16 newid = genl_generate_id();
@@ -388,6 +375,9 @@ int genl_register_family(struct genl_family *family)
}
family->id = newid;
+ } else if (genl_family_find_byid(family->id)) {
+ err = -EEXIST;
+ goto errout_locked;
}
if (family->maxattr) {
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 7a834952f67f..281fa597cae5 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -1372,7 +1372,7 @@ static const struct file_operations nr_info_fops = {
};
#endif /* CONFIG_PROC_FS */
-static struct net_proto_family nr_family_ops = {
+static const struct net_proto_family nr_family_ops = {
.family = PF_NETROM,
.create = nr_create,
.owner = THIS_MODULE,
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index d7ecca0a0c07..33e68f20ec61 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -79,6 +79,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mutex.h>
+#include <linux/if_vlan.h>
#ifdef CONFIG_INET
#include <net/inet_common.h>
@@ -188,7 +189,6 @@ struct packet_sock {
struct packet_ring_buffer tx_ring;
int copy_thresh;
#endif
- struct packet_type prot_hook;
spinlock_t bind_lock;
struct mutex pg_vec_lock;
unsigned int running:1, /* prot_hook is attached*/
@@ -204,6 +204,7 @@ struct packet_sock {
unsigned int tp_reserve;
unsigned int tp_loss:1;
#endif
+ struct packet_type prot_hook ____cacheline_aligned_in_smp;
};
struct packet_skb_cb {
@@ -490,6 +491,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
skb->protocol = proto;
skb->dev = dev;
skb->priority = sk->sk_priority;
+ skb->mark = sk->sk_mark;
if (err)
goto out_free;
@@ -626,15 +628,14 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
spin_lock(&sk->sk_receive_queue.lock);
po->stats.tp_packets++;
+ skb->dropcount = atomic_read(&sk->sk_drops);
__skb_queue_tail(&sk->sk_receive_queue, skb);
spin_unlock(&sk->sk_receive_queue.lock);
sk->sk_data_ready(sk, skb->len);
return 0;
drop_n_acct:
- spin_lock(&sk->sk_receive_queue.lock);
- po->stats.tp_drops++;
- spin_unlock(&sk->sk_receive_queue.lock);
+ po->stats.tp_drops = atomic_inc_return(&sk->sk_drops);
drop_n_restore:
if (skb_head != skb->data && skb_shared(skb)) {
@@ -766,7 +767,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
getnstimeofday(&ts);
h.h2->tp_sec = ts.tv_sec;
h.h2->tp_nsec = ts.tv_nsec;
- h.h2->tp_vlan_tci = skb->vlan_tci;
+ h.h2->tp_vlan_tci = vlan_tx_tag_get(skb);
hdrlen = sizeof(*h.h2);
break;
default:
@@ -856,6 +857,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
skb->protocol = proto;
skb->dev = dev;
skb->priority = po->sk.sk_priority;
+ skb->mark = po->sk.sk_mark;
skb_shinfo(skb)->destructor_arg = ph.raw;
switch (po->tp_version) {
@@ -1125,6 +1127,7 @@ static int packet_snd(struct socket *sock,
skb->protocol = proto;
skb->dev = dev;
skb->priority = sk->sk_priority;
+ skb->mark = sk->sk_mark;
/*
* Now send it
@@ -1475,7 +1478,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
if (err)
goto out_free;
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
if (msg->msg_name)
memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa,
@@ -1491,7 +1494,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
aux.tp_snaplen = skb->len;
aux.tp_mac = 0;
aux.tp_net = skb_network_offset(skb);
- aux.tp_vlan_tci = skb->vlan_tci;
+ aux.tp_vlan_tci = vlan_tx_tag_get(skb);
put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux);
}
@@ -1662,11 +1665,9 @@ static int packet_mc_drop(struct sock *sk, struct packet_mreq_max *mreq)
if (--ml->count == 0) {
struct net_device *dev;
*mlp = ml->next;
- dev = dev_get_by_index(sock_net(sk), ml->ifindex);
- if (dev) {
+ dev = __dev_get_by_index(sock_net(sk), ml->ifindex);
+ if (dev)
packet_dev_mc(dev, ml, -1);
- dev_put(dev);
- }
kfree(ml);
}
rtnl_unlock();
@@ -1690,11 +1691,9 @@ static void packet_flush_mclist(struct sock *sk)
struct net_device *dev;
po->mclist = ml->next;
- dev = dev_get_by_index(sock_net(sk), ml->ifindex);
- if (dev != NULL) {
+ dev = __dev_get_by_index(sock_net(sk), ml->ifindex);
+ if (dev != NULL)
packet_dev_mc(dev, ml, -1);
- dev_put(dev);
- }
kfree(ml);
}
rtnl_unlock();
@@ -2363,7 +2362,7 @@ static const struct proto_ops packet_ops = {
.sendpage = sock_no_sendpage,
};
-static struct net_proto_family packet_family_ops = {
+static const struct net_proto_family packet_family_ops = {
.family = PF_PACKET,
.create = packet_create,
.owner = THIS_MODULE,
diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c
index f60c0c2aacba..66737aa995ea 100644
--- a/net/phonet/af_phonet.c
+++ b/net/phonet/af_phonet.c
@@ -118,7 +118,7 @@ out:
return err;
}
-static struct net_proto_family phonet_proto_family = {
+static const struct net_proto_family phonet_proto_family = {
.family = PF_PHONET,
.create = pn_socket_create,
.owner = THIS_MODULE,
@@ -190,9 +190,8 @@ static int pn_send(struct sk_buff *skb, struct net_device *dev,
skb->priority = 0;
skb->dev = dev;
- if (pn_addr(src) == pn_addr(dst)) {
+ if (skb->pkt_type == PACKET_LOOPBACK) {
skb_reset_mac_header(skb);
- skb->pkt_type = PACKET_LOOPBACK;
skb_orphan(skb);
if (irq)
netif_rx(skb);
@@ -222,6 +221,9 @@ static int pn_raw_send(const void *data, int len, struct net_device *dev,
if (skb == NULL)
return -ENOMEM;
+ if (phonet_address_lookup(dev_net(dev), pn_addr(dst)) == 0)
+ skb->pkt_type = PACKET_LOOPBACK;
+
skb_reserve(skb, MAX_PHONET_HEADER);
__skb_put(skb, len);
skb_copy_to_linear_data(skb, data, len);
@@ -235,6 +237,7 @@ static int pn_raw_send(const void *data, int len, struct net_device *dev,
int pn_skb_send(struct sock *sk, struct sk_buff *skb,
const struct sockaddr_pn *target)
{
+ struct net *net = sock_net(sk);
struct net_device *dev;
struct pn_sock *pn = pn_sk(sk);
int err;
@@ -243,9 +246,13 @@ int pn_skb_send(struct sock *sk, struct sk_buff *skb,
err = -EHOSTUNREACH;
if (sk->sk_bound_dev_if)
- dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if);
- else
- dev = phonet_device_get(sock_net(sk));
+ dev = dev_get_by_index(net, sk->sk_bound_dev_if);
+ else if (phonet_address_lookup(net, daddr) == 0) {
+ dev = phonet_device_get(net);
+ skb->pkt_type = PACKET_LOOPBACK;
+ } else
+ dev = phonet_route_output(net, daddr);
+
if (!dev || !(dev->flags & IFF_UP))
goto drop;
@@ -369,6 +376,12 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev,
pn_skb_get_dst_sockaddr(skb, &sa);
+ /* check if this is broadcasted */
+ if (pn_sockaddr_get_addr(&sa) == PNADDR_BROADCAST) {
+ pn_deliver_sock_broadcast(net, skb);
+ goto out;
+ }
+
/* check if we are the destination */
if (phonet_address_lookup(net, pn_sockaddr_get_addr(&sa)) == 0) {
/* Phonet packet input */
@@ -381,6 +394,38 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev,
send_obj_unreachable(skb);
send_reset_indications(skb);
}
+ } else if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
+ goto out; /* Race between address deletion and loopback */
+ else {
+ /* Phonet packet routing */
+ struct net_device *out_dev;
+
+ out_dev = phonet_route_output(net, pn_sockaddr_get_addr(&sa));
+ if (!out_dev) {
+ LIMIT_NETDEBUG(KERN_WARNING"No Phonet route to %02X\n",
+ pn_sockaddr_get_addr(&sa));
+ goto out;
+ }
+
+ __skb_push(skb, sizeof(struct phonethdr));
+ skb->dev = out_dev;
+ if (out_dev == dev) {
+ LIMIT_NETDEBUG(KERN_ERR"Phonet loop to %02X on %s\n",
+ pn_sockaddr_get_addr(&sa), dev->name);
+ goto out_dev;
+ }
+ /* Some drivers (e.g. TUN) do not allocate HW header space */
+ if (skb_cow_head(skb, out_dev->hard_header_len))
+ goto out_dev;
+
+ if (dev_hard_header(skb, out_dev, ETH_P_PHONET, NULL, NULL,
+ skb->len) < 0)
+ goto out_dev;
+ dev_queue_xmit(skb);
+ dev_put(out_dev);
+ return NET_RX_SUCCESS;
+out_dev:
+ dev_put(out_dev);
}
out:
diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c
index ef5c75c372e4..67f072e94d00 100644
--- a/net/phonet/datagram.c
+++ b/net/phonet/datagram.c
@@ -159,11 +159,9 @@ out_nofree:
static int pn_backlog_rcv(struct sock *sk, struct sk_buff *skb)
{
int err = sock_queue_rcv_skb(sk, skb);
- if (err < 0) {
+
+ if (err < 0)
kfree_skb(skb);
- if (err == -ENOMEM)
- atomic_inc(&sk->sk_drops);
- }
return err ? NET_RX_DROP : NET_RX_SUCCESS;
}
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index 5f32d217535b..cbaa1d67d77b 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -360,8 +360,6 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
err = sock_queue_rcv_skb(sk, skb);
if (!err)
return 0;
- if (err == -ENOMEM)
- atomic_inc(&sk->sk_drops);
break;
}
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index 5f42f30dd168..6d64fda1afc9 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -33,8 +33,14 @@
#include <net/netns/generic.h>
#include <net/phonet/pn_dev.h>
+struct phonet_routes {
+ spinlock_t lock;
+ struct net_device *table[64];
+};
+
struct phonet_net {
struct phonet_device_list pndevs;
+ struct phonet_routes routes;
};
int phonet_net_id;
@@ -154,10 +160,11 @@ int phonet_address_del(struct net_device *dev, u8 addr)
}
/* Gets a source address toward a destination, through a interface. */
-u8 phonet_address_get(struct net_device *dev, u8 addr)
+u8 phonet_address_get(struct net_device *dev, u8 daddr)
{
struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
struct phonet_device *pnd;
+ u8 saddr;
spin_lock_bh(&pndevs->lock);
pnd = __phonet_get(dev);
@@ -165,12 +172,26 @@ u8 phonet_address_get(struct net_device *dev, u8 addr)
BUG_ON(bitmap_empty(pnd->addrs, 64));
/* Use same source address as destination, if possible */
- if (!test_bit(addr >> 2, pnd->addrs))
- addr = find_first_bit(pnd->addrs, 64) << 2;
+ if (test_bit(daddr >> 2, pnd->addrs))
+ saddr = daddr;
+ else
+ saddr = find_first_bit(pnd->addrs, 64) << 2;
} else
- addr = PN_NO_ADDR;
+ saddr = PN_NO_ADDR;
spin_unlock_bh(&pndevs->lock);
- return addr;
+
+ if (saddr == PN_NO_ADDR) {
+ /* Fallback to another device */
+ struct net_device *def_dev;
+
+ def_dev = phonet_device_get(dev_net(dev));
+ if (def_dev) {
+ if (def_dev != dev)
+ saddr = phonet_address_get(def_dev, daddr);
+ dev_put(def_dev);
+ }
+ }
+ return saddr;
}
int phonet_address_lookup(struct net *net, u8 addr)
@@ -219,6 +240,27 @@ static int phonet_device_autoconf(struct net_device *dev)
return 0;
}
+static void phonet_route_autodel(struct net_device *dev)
+{
+ struct phonet_net *pnn = net_generic(dev_net(dev), phonet_net_id);
+ unsigned i;
+ DECLARE_BITMAP(deleted, 64);
+
+ /* Remove left-over Phonet routes */
+ bitmap_zero(deleted, 64);
+ spin_lock_bh(&pnn->routes.lock);
+ for (i = 0; i < 64; i++)
+ if (dev == pnn->routes.table[i]) {
+ set_bit(i, deleted);
+ pnn->routes.table[i] = NULL;
+ dev_put(dev);
+ }
+ spin_unlock_bh(&pnn->routes.lock);
+ for (i = find_first_bit(deleted, 64); i < 64;
+ i = find_next_bit(deleted, 64, i + 1))
+ rtm_phonet_notify(RTM_DELROUTE, dev, i);
+}
+
/* notify Phonet of device events */
static int phonet_device_notify(struct notifier_block *me, unsigned long what,
void *arg)
@@ -232,6 +274,7 @@ static int phonet_device_notify(struct notifier_block *me, unsigned long what,
break;
case NETDEV_UNREGISTER:
phonet_device_destroy(dev);
+ phonet_route_autodel(dev);
break;
}
return 0;
@@ -246,7 +289,7 @@ static struct notifier_block phonet_device_notifier = {
/* Per-namespace Phonet devices handling */
static int phonet_init_net(struct net *net)
{
- struct phonet_net *pnn = kmalloc(sizeof(*pnn), GFP_KERNEL);
+ struct phonet_net *pnn = kzalloc(sizeof(*pnn), GFP_KERNEL);
if (!pnn)
return -ENOMEM;
@@ -257,6 +300,7 @@ static int phonet_init_net(struct net *net)
INIT_LIST_HEAD(&pnn->pndevs.list);
spin_lock_init(&pnn->pndevs.lock);
+ spin_lock_init(&pnn->routes.lock);
net_assign_generic(net, phonet_net_id, pnn);
return 0;
}
@@ -265,10 +309,19 @@ static void phonet_exit_net(struct net *net)
{
struct phonet_net *pnn = net_generic(net, phonet_net_id);
struct net_device *dev;
+ unsigned i;
rtnl_lock();
for_each_netdev(net, dev)
phonet_device_destroy(dev);
+
+ for (i = 0; i < 64; i++) {
+ dev = pnn->routes.table[i];
+ if (dev) {
+ rtm_phonet_notify(RTM_DELROUTE, dev, i);
+ dev_put(dev);
+ }
+ }
rtnl_unlock();
proc_net_remove(net, "phonet");
@@ -300,3 +353,69 @@ void phonet_device_exit(void)
unregister_netdevice_notifier(&phonet_device_notifier);
unregister_pernet_gen_device(phonet_net_id, &phonet_net_ops);
}
+
+int phonet_route_add(struct net_device *dev, u8 daddr)
+{
+ struct phonet_net *pnn = net_generic(dev_net(dev), phonet_net_id);
+ struct phonet_routes *routes = &pnn->routes;
+ int err = -EEXIST;
+
+ daddr = daddr >> 2;
+ spin_lock_bh(&routes->lock);
+ if (routes->table[daddr] == NULL) {
+ routes->table[daddr] = dev;
+ dev_hold(dev);
+ err = 0;
+ }
+ spin_unlock_bh(&routes->lock);
+ return err;
+}
+
+int phonet_route_del(struct net_device *dev, u8 daddr)
+{
+ struct phonet_net *pnn = net_generic(dev_net(dev), phonet_net_id);
+ struct phonet_routes *routes = &pnn->routes;
+ int err = -ENOENT;
+
+ daddr = daddr >> 2;
+ spin_lock_bh(&routes->lock);
+ if (dev == routes->table[daddr]) {
+ routes->table[daddr] = NULL;
+ dev_put(dev);
+ err = 0;
+ }
+ spin_unlock_bh(&routes->lock);
+ return err;
+}
+
+struct net_device *phonet_route_get(struct net *net, u8 daddr)
+{
+ struct phonet_net *pnn = net_generic(net, phonet_net_id);
+ struct phonet_routes *routes = &pnn->routes;
+ struct net_device *dev;
+
+ ASSERT_RTNL(); /* no need to hold the device */
+
+ daddr >>= 2;
+ spin_lock_bh(&routes->lock);
+ dev = routes->table[daddr];
+ spin_unlock_bh(&routes->lock);
+ return dev;
+}
+
+struct net_device *phonet_route_output(struct net *net, u8 daddr)
+{
+ struct phonet_net *pnn = net_generic(net, phonet_net_id);
+ struct phonet_routes *routes = &pnn->routes;
+ struct net_device *dev;
+
+ spin_lock_bh(&routes->lock);
+ dev = routes->table[daddr >> 2];
+ if (dev)
+ dev_hold(dev);
+ spin_unlock_bh(&routes->lock);
+
+ if (!dev)
+ dev = phonet_device_get(net); /* Default route */
+ return dev;
+}
diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c
index d21fd3576610..d8f5d3fb9ee2 100644
--- a/net/phonet/pn_netlink.c
+++ b/net/phonet/pn_netlink.c
@@ -29,6 +29,8 @@
#include <net/sock.h>
#include <net/phonet/pn_dev.h>
+/* Device address handling */
+
static int fill_addr(struct sk_buff *skb, struct net_device *dev, u8 addr,
u32 pid, u32 seq, int event);
@@ -160,6 +162,131 @@ out:
return skb->len;
}
+/* Routes handling */
+
+static int fill_route(struct sk_buff *skb, struct net_device *dev, u8 dst,
+ u32 pid, u32 seq, int event)
+{
+ struct rtmsg *rtm;
+ struct nlmsghdr *nlh;
+
+ nlh = nlmsg_put(skb, pid, seq, event, sizeof(*rtm), 0);
+ if (nlh == NULL)
+ return -EMSGSIZE;
+
+ rtm = nlmsg_data(nlh);
+ rtm->rtm_family = AF_PHONET;
+ rtm->rtm_dst_len = 6;
+ rtm->rtm_src_len = 0;
+ rtm->rtm_tos = 0;
+ rtm->rtm_table = RT_TABLE_MAIN;
+ rtm->rtm_protocol = RTPROT_STATIC;
+ rtm->rtm_scope = RT_SCOPE_UNIVERSE;
+ rtm->rtm_type = RTN_UNICAST;
+ rtm->rtm_flags = 0;
+ NLA_PUT_U8(skb, RTA_DST, dst);
+ NLA_PUT_U32(skb, RTA_OIF, dev->ifindex);
+ return nlmsg_end(skb, nlh);
+
+nla_put_failure:
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
+}
+
+void rtm_phonet_notify(int event, struct net_device *dev, u8 dst)
+{
+ struct sk_buff *skb;
+ int err = -ENOBUFS;
+
+ skb = nlmsg_new(NLMSG_ALIGN(sizeof(struct ifaddrmsg)) +
+ nla_total_size(1) + nla_total_size(4), GFP_KERNEL);
+ if (skb == NULL)
+ goto errout;
+ err = fill_route(skb, dev, dst, 0, 0, event);
+ if (err < 0) {
+ WARN_ON(err == -EMSGSIZE);
+ kfree_skb(skb);
+ goto errout;
+ }
+ rtnl_notify(skb, dev_net(dev), 0,
+ RTNLGRP_PHONET_ROUTE, NULL, GFP_KERNEL);
+ return;
+errout:
+ if (err < 0)
+ rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_ROUTE, err);
+}
+
+static const struct nla_policy rtm_phonet_policy[RTA_MAX+1] = {
+ [RTA_DST] = { .type = NLA_U8 },
+ [RTA_OIF] = { .type = NLA_U32 },
+};
+
+static int route_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *attr)
+{
+ struct net *net = sock_net(skb->sk);
+ struct nlattr *tb[RTA_MAX+1];
+ struct net_device *dev;
+ struct rtmsg *rtm;
+ int err;
+ u8 dst;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ ASSERT_RTNL();
+
+ err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_phonet_policy);
+ if (err < 0)
+ return err;
+
+ rtm = nlmsg_data(nlh);
+ if (rtm->rtm_table != RT_TABLE_MAIN || rtm->rtm_type != RTN_UNICAST)
+ return -EINVAL;
+ if (tb[RTA_DST] == NULL || tb[RTA_OIF] == NULL)
+ return -EINVAL;
+ dst = nla_get_u8(tb[RTA_DST]);
+ if (dst & 3) /* Phonet addresses only have 6 high-order bits */
+ return -EINVAL;
+
+ dev = __dev_get_by_index(net, nla_get_u32(tb[RTA_OIF]));
+ if (dev == NULL)
+ return -ENODEV;
+
+ if (nlh->nlmsg_type == RTM_NEWROUTE)
+ err = phonet_route_add(dev, dst);
+ else
+ err = phonet_route_del(dev, dst);
+ if (!err)
+ rtm_phonet_notify(nlh->nlmsg_type, dev, dst);
+ return err;
+}
+
+static int route_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ struct net *net = sock_net(skb->sk);
+ u8 addr, addr_idx = 0, addr_start_idx = cb->args[0];
+
+ for (addr = 0; addr < 64; addr++) {
+ struct net_device *dev;
+
+ dev = phonet_route_get(net, addr << 2);
+ if (!dev)
+ continue;
+
+ if (addr_idx++ < addr_start_idx)
+ continue;
+ if (fill_route(skb, dev, addr << 2, NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq, RTM_NEWROUTE))
+ goto out;
+ }
+
+out:
+ cb->args[0] = addr_idx;
+ cb->args[1] = 0;
+
+ return skb->len;
+}
+
int __init phonet_netlink_register(void)
{
int err = __rtnl_register(PF_PHONET, RTM_NEWADDR, addr_doit, NULL);
@@ -169,5 +296,8 @@ int __init phonet_netlink_register(void)
/* Further __rtnl_register() cannot fail */
__rtnl_register(PF_PHONET, RTM_DELADDR, addr_doit, NULL);
__rtnl_register(PF_PHONET, RTM_GETADDR, NULL, getaddr_dumpit);
+ __rtnl_register(PF_PHONET, RTM_NEWROUTE, route_doit, NULL);
+ __rtnl_register(PF_PHONET, RTM_DELROUTE, route_doit, NULL);
+ __rtnl_register(PF_PHONET, RTM_GETROUTE, NULL, route_dumpit);
return 0;
}
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index aa5b5a972bff..0412beb59a05 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -94,7 +94,30 @@ struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn)
spin_unlock_bh(&pnsocks.lock);
return rval;
+}
+
+/* Deliver a broadcast packet (only in bottom-half) */
+void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb)
+{
+ struct hlist_node *node;
+ struct sock *sknode;
+
+ spin_lock(&pnsocks.lock);
+ sk_for_each(sknode, node, &pnsocks.hlist) {
+ struct sk_buff *clone;
+ if (!net_eq(sock_net(sknode), net))
+ continue;
+ if (!sock_flag(sknode, SOCK_BROADCAST))
+ continue;
+
+ clone = skb_clone(skb, GFP_ATOMIC);
+ if (clone) {
+ sock_hold(sknode);
+ sk_receive_skb(sknode, clone, 0);
+ }
+ }
+ spin_unlock(&pnsocks.lock);
}
void pn_sock_hash(struct sock *sk)
diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c
index 98e05382fd3c..a202e5b36079 100644
--- a/net/rds/af_rds.c
+++ b/net/rds/af_rds.c
@@ -431,7 +431,7 @@ void rds_sock_put(struct rds_sock *rs)
sock_put(rds_rs_to_sk(rs));
}
-static struct net_proto_family rds_family_ops = {
+static const struct net_proto_family rds_family_ops = {
.family = AF_RDS,
.create = rds_create,
.owner = THIS_MODULE,
diff --git a/net/rds/tcp_listen.c b/net/rds/tcp_listen.c
index 24b743eb0b1b..45474a436862 100644
--- a/net/rds/tcp_listen.c
+++ b/net/rds/tcp_listen.c
@@ -67,11 +67,11 @@ static int rds_tcp_accept_one(struct socket *sock)
inet = inet_sk(new_sock->sk);
rdsdebug("accepted tcp %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n",
- NIPQUAD(inet->saddr), ntohs(inet->sport),
- NIPQUAD(inet->daddr), ntohs(inet->dport));
+ NIPQUAD(inet->inet_saddr), ntohs(inet->inet_sport),
+ NIPQUAD(inet->inet_daddr), ntohs(inet->inet_dport));
- conn = rds_conn_create(inet->saddr, inet->daddr, &rds_tcp_transport,
- GFP_KERNEL);
+ conn = rds_conn_create(inet->inet_saddr, inet->inet_daddr,
+ &rds_tcp_transport, GFP_KERNEL);
if (IS_ERR(conn)) {
ret = PTR_ERR(conn);
goto out;
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index 502cce76621d..c17734c2ce89 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -1509,7 +1509,7 @@ static const struct file_operations rose_info_fops = {
};
#endif /* CONFIG_PROC_FS */
-static struct net_proto_family rose_family_ops = {
+static const struct net_proto_family rose_family_ops = {
.family = PF_ROSE,
.create = rose_create,
.owner = THIS_MODULE,
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index a86afceaa94f..6817c9781ef3 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -777,7 +777,7 @@ static struct proto rxrpc_proto = {
.max_header = sizeof(struct rxrpc_header),
};
-static struct net_proto_family rxrpc_family_ops = {
+static const struct net_proto_family rxrpc_family_ops = {
.family = PF_RXRPC,
.create = rxrpc_create,
.owner = THIS_MODULE,
diff --git a/net/rxrpc/ar-recvmsg.c b/net/rxrpc/ar-recvmsg.c
index a39bf97f8830..60c2b94e6b54 100644
--- a/net/rxrpc/ar-recvmsg.c
+++ b/net/rxrpc/ar-recvmsg.c
@@ -146,7 +146,7 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
memcpy(msg->msg_name,
&call->conn->trans->peer->srx,
sizeof(call->conn->trans->peer->srx));
- sock_recv_timestamp(msg, &rx->sk, skb);
+ sock_recv_ts_and_drops(msg, &rx->sk, skb);
}
/* receive the message */
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 2dfb3e7a040d..29b0b5bbc787 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -598,7 +598,7 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
goto errout;
/* compat_mode being true specifies a call that is supposed
- * to add additional backward compatiblity statistic TLVs.
+ * to add additional backward compatibility statistic TLVs.
*/
if (compat_mode) {
if (a->type == TCA_OLD_COMPAT)
@@ -618,7 +618,8 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
goto errout;
if (gnet_stats_copy_basic(&d, &h->tcf_bstats) < 0 ||
- gnet_stats_copy_rate_est(&d, &h->tcf_rate_est) < 0 ||
+ gnet_stats_copy_rate_est(&d, &h->tcf_bstats,
+ &h->tcf_rate_est) < 0 ||
gnet_stats_copy_queue(&d, &h->tcf_qstats) < 0)
goto errout;
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
index 4ab916b8074b..e9607fe55b58 100644
--- a/net/sched/act_skbedit.c
+++ b/net/sched/act_skbedit.c
@@ -54,6 +54,8 @@ static int tcf_skbedit(struct sk_buff *skb, struct tc_action *a,
if (d->flags & SKBEDIT_F_QUEUE_MAPPING &&
skb->dev->real_num_tx_queues > d->queue_mapping)
skb_set_queue_mapping(skb, d->queue_mapping);
+ if (d->flags & SKBEDIT_F_MARK)
+ skb->mark = d->mark;
spin_unlock(&d->tcf_lock);
return d->tcf_action;
@@ -63,6 +65,7 @@ static const struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = {
[TCA_SKBEDIT_PARMS] = { .len = sizeof(struct tc_skbedit) },
[TCA_SKBEDIT_PRIORITY] = { .len = sizeof(u32) },
[TCA_SKBEDIT_QUEUE_MAPPING] = { .len = sizeof(u16) },
+ [TCA_SKBEDIT_MARK] = { .len = sizeof(u32) },
};
static int tcf_skbedit_init(struct nlattr *nla, struct nlattr *est,
@@ -72,7 +75,7 @@ static int tcf_skbedit_init(struct nlattr *nla, struct nlattr *est,
struct tc_skbedit *parm;
struct tcf_skbedit *d;
struct tcf_common *pc;
- u32 flags = 0, *priority = NULL;
+ u32 flags = 0, *priority = NULL, *mark = NULL;
u16 *queue_mapping = NULL;
int ret = 0, err;
@@ -95,6 +98,12 @@ static int tcf_skbedit_init(struct nlattr *nla, struct nlattr *est,
flags |= SKBEDIT_F_QUEUE_MAPPING;
queue_mapping = nla_data(tb[TCA_SKBEDIT_QUEUE_MAPPING]);
}
+
+ if (tb[TCA_SKBEDIT_MARK] != NULL) {
+ flags |= SKBEDIT_F_MARK;
+ mark = nla_data(tb[TCA_SKBEDIT_MARK]);
+ }
+
if (!flags)
return -EINVAL;
@@ -124,6 +133,9 @@ static int tcf_skbedit_init(struct nlattr *nla, struct nlattr *est,
d->priority = *priority;
if (flags & SKBEDIT_F_QUEUE_MAPPING)
d->queue_mapping = *queue_mapping;
+ if (flags & SKBEDIT_F_MARK)
+ d->mark = *mark;
+
d->tcf_action = parm->action;
spin_unlock_bh(&d->tcf_lock);
@@ -161,6 +173,9 @@ static inline int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a,
if (d->flags & SKBEDIT_F_QUEUE_MAPPING)
NLA_PUT(skb, TCA_SKBEDIT_QUEUE_MAPPING,
sizeof(d->queue_mapping), &d->queue_mapping);
+ if (d->flags & SKBEDIT_F_MARK)
+ NLA_PUT(skb, TCA_SKBEDIT_MARK, sizeof(d->mark),
+ &d->mark);
t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install);
t.lastuse = jiffies_to_clock_t(jiffies - d->tcf_tm.lastuse);
t.expires = jiffies_to_clock_t(d->tcf_tm.expires);
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 903e4188b6ca..1acfd29cc826 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -1179,7 +1179,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
goto nla_put_failure;
if (gnet_stats_copy_basic(&d, &q->bstats) < 0 ||
- gnet_stats_copy_rate_est(&d, &q->rate_est) < 0 ||
+ gnet_stats_copy_rate_est(&d, &q->bstats, &q->rate_est) < 0 ||
gnet_stats_copy_queue(&d, &q->qstats) < 0)
goto nla_put_failure;
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 5b132c473264..3846d65bc03e 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -1609,7 +1609,7 @@ cbq_dump_class_stats(struct Qdisc *sch, unsigned long arg,
cl->xstats.undertime = cl->undertime - q->now;
if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
- gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 ||
+ gnet_stats_copy_rate_est(d, &cl->bstats, &cl->rate_est) < 0 ||
gnet_stats_copy_queue(d, &cl->qstats) < 0)
return -1;
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c
index 5a888af7e5da..a65604f8f2b8 100644
--- a/net/sched/sch_drr.c
+++ b/net/sched/sch_drr.c
@@ -280,7 +280,7 @@ static int drr_dump_class_stats(struct Qdisc *sch, unsigned long arg,
}
if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
- gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 ||
+ gnet_stats_copy_rate_est(d, &cl->bstats, &cl->rate_est) < 0 ||
gnet_stats_copy_queue(d, &cl->qdisc->qstats) < 0)
return -1;
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index 2c5c76be18f8..b38b39c60752 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -1375,7 +1375,7 @@ hfsc_dump_class_stats(struct Qdisc *sch, unsigned long arg,
xstats.rtwork = cl->cl_cumul;
if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
- gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 ||
+ gnet_stats_copy_rate_est(d, &cl->bstats, &cl->rate_est) < 0 ||
gnet_stats_copy_queue(d, &cl->qstats) < 0)
return -1;
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 85acab9dc6fd..2e38d1abd830 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -1105,7 +1105,7 @@ htb_dump_class_stats(struct Qdisc *sch, unsigned long arg, struct gnet_dump *d)
cl->xstats.ctokens = cl->ctokens;
if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
- gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 ||
+ gnet_stats_copy_rate_est(d, NULL, &cl->rate_est) < 0 ||
gnet_stats_copy_queue(d, &cl->qstats) < 0)
return -1;
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 612dc878e05c..d9f4cc2c7869 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -296,19 +296,19 @@ static void sctp_v4_from_sk(union sctp_addr *addr, struct sock *sk)
{
addr->v4.sin_family = AF_INET;
addr->v4.sin_port = 0;
- addr->v4.sin_addr.s_addr = inet_sk(sk)->rcv_saddr;
+ addr->v4.sin_addr.s_addr = inet_sk(sk)->inet_rcv_saddr;
}
/* Initialize sk->sk_rcv_saddr from sctp_addr. */
static void sctp_v4_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
{
- inet_sk(sk)->rcv_saddr = addr->v4.sin_addr.s_addr;
+ inet_sk(sk)->inet_rcv_saddr = addr->v4.sin_addr.s_addr;
}
/* Initialize sk->sk_daddr from sctp_addr. */
static void sctp_v4_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
{
- inet_sk(sk)->daddr = addr->v4.sin_addr.s_addr;
+ inet_sk(sk)->inet_daddr = addr->v4.sin_addr.s_addr;
}
/* Initialize a sctp_addr from an address parameter. */
@@ -598,7 +598,7 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk,
newinet = inet_sk(newsk);
- newinet->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr;
+ newinet->inet_daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr;
sk_refcnt_debug_inc(newsk);
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index c8fae1983dd1..ba2f66d5f0cd 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -3569,7 +3569,7 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
* To do this properly, we'll set the destination address of the chunk
* and at the transmit time, will try look up the transport to use.
* Since ASCONFs may be bundled, the correct transport may not be
- * created untill we process the entire packet, thus this workaround.
+ * created until we process the entire packet, thus this workaround.
*/
asconf_ack->dest = chunk->source;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(asconf_ack));
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index c8d05758661d..4085db99033d 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -394,7 +394,7 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
/* Refresh ephemeral port. */
if (!bp->port)
- bp->port = inet_sk(sk)->num;
+ bp->port = inet_sk(sk)->inet_num;
/* Add the address to the bind address list.
* Use GFP_ATOMIC since BHs will be disabled.
@@ -403,7 +403,7 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
/* Copy back into socket for getsockname() use. */
if (!ret) {
- inet_sk(sk)->sport = htons(inet_sk(sk)->num);
+ inet_sk(sk)->inet_sport = htons(inet_sk(sk)->inet_num);
af->to_sk_saddr(addr, sk);
}
@@ -1115,7 +1115,7 @@ static int __sctp_connect(struct sock* sk,
}
/* Initialize sk's dport and daddr for getpeername() */
- inet_sk(sk)->dport = htons(asoc->peer.port);
+ inet_sk(sk)->inet_dport = htons(asoc->peer.port);
af = sctp_get_af_specific(sa_addr->sa.sa_family);
af->to_sk_daddr(sa_addr, sk);
sk->sk_err = 0;
@@ -1958,7 +1958,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,
if (err)
goto out_free;
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
if (sctp_ulpevent_is_notification(event)) {
msg->msg_flags |= MSG_NOTIFICATION;
sp->pf->event_msgname(event, msg->msg_name, addr_len);
@@ -5851,7 +5851,7 @@ pp_not_found:
*/
success:
if (!sctp_sk(sk)->bind_hash) {
- inet_sk(sk)->num = snum;
+ inet_sk(sk)->inet_num = snum;
sk_add_bind_node(sk, &pp->owner);
sctp_sk(sk)->bind_hash = pp;
}
@@ -5923,7 +5923,7 @@ SCTP_STATIC int sctp_listen_start(struct sock *sk, int backlog)
if (sctp_autobind(sk))
return -EAGAIN;
} else {
- if (sctp_get_port(sk, inet_sk(sk)->num)) {
+ if (sctp_get_port(sk, inet_sk(sk)->inet_num)) {
sk->sk_state = SCTP_SS_CLOSED;
return -EADDRINUSE;
}
@@ -6094,14 +6094,14 @@ static void sctp_bucket_destroy(struct sctp_bind_bucket *pp)
static inline void __sctp_put_port(struct sock *sk)
{
struct sctp_bind_hashbucket *head =
- &sctp_port_hashtable[sctp_phashfn(inet_sk(sk)->num)];
+ &sctp_port_hashtable[sctp_phashfn(inet_sk(sk)->inet_num)];
struct sctp_bind_bucket *pp;
sctp_spin_lock(&head->lock);
pp = sctp_sk(sk)->bind_hash;
__sk_del_bind_node(sk);
sctp_sk(sk)->bind_hash = NULL;
- inet_sk(sk)->num = 0;
+ inet_sk(sk)->inet_num = 0;
sctp_bucket_destroy(pp);
sctp_spin_unlock(&head->lock);
}
@@ -6128,7 +6128,7 @@ static int sctp_autobind(struct sock *sk)
/* Initialize a local sockaddr structure to INADDR_ANY. */
af = sctp_sk(sk)->pf->af;
- port = htons(inet_sk(sk)->num);
+ port = htons(inet_sk(sk)->inet_num);
af->inaddr_any(&autoaddr, port);
return sctp_do_bind(sk, &autoaddr, af->sockaddr_len);
@@ -6697,12 +6697,12 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,
/* Initialize sk's sport, dport, rcv_saddr and daddr for
* getsockname() and getpeername()
*/
- newinet->sport = inet->sport;
- newinet->saddr = inet->saddr;
- newinet->rcv_saddr = inet->rcv_saddr;
- newinet->dport = htons(asoc->peer.port);
+ newinet->inet_sport = inet->inet_sport;
+ newinet->inet_saddr = inet->inet_saddr;
+ newinet->inet_rcv_saddr = inet->inet_rcv_saddr;
+ newinet->inet_dport = htons(asoc->peer.port);
newinet->pmtudisc = inet->pmtudisc;
- newinet->id = asoc->next_tsn ^ jiffies;
+ newinet->inet_id = asoc->next_tsn ^ jiffies;
newinet->uc_ttl = inet->uc_ttl;
newinet->mc_loop = 1;
@@ -6741,13 +6741,13 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
newsp->hmac = NULL;
/* Hook this new socket in to the bind_hash list. */
- head = &sctp_port_hashtable[sctp_phashfn(inet_sk(oldsk)->num)];
+ head = &sctp_port_hashtable[sctp_phashfn(inet_sk(oldsk)->inet_num)];
sctp_local_bh_disable();
sctp_spin_lock(&head->lock);
pp = sctp_sk(oldsk)->bind_hash;
sk_add_bind_node(newsk, &pp->owner);
sctp_sk(newsk)->bind_hash = pp;
- inet_sk(newsk)->num = inet_sk(oldsk)->num;
+ inet_sk(newsk)->inet_num = inet_sk(oldsk)->inet_num;
sctp_spin_unlock(&head->lock);
sctp_local_bh_enable();
diff --git a/net/socket.c b/net/socket.c
index 75655365b5fd..9dff31c9b799 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -668,10 +668,24 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
EXPORT_SYMBOL_GPL(__sock_recv_timestamp);
-static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t size, int flags)
+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,
+ sizeof(__u32), &skb->dropcount);
+}
+
+void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
+ struct sk_buff *skb)
+{
+ sock_recv_timestamp(msg, sk, skb);
+ sock_recv_drops(msg, sk, skb);
+}
+EXPORT_SYMBOL_GPL(sock_recv_ts_and_drops);
+
+static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t size, int flags)
{
- int err;
struct sock_iocb *si = kiocb_to_siocb(iocb);
si->sock = sock;
@@ -680,13 +694,17 @@ static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
si->size = size;
si->flags = flags;
- err = security_socket_recvmsg(sock, msg, size, flags);
- if (err)
- return err;
-
return sock->ops->recvmsg(iocb, sock, msg, size, flags);
}
+static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t size, int flags)
+{
+ int err = security_socket_recvmsg(sock, msg, size, flags);
+
+ return err ?: __sock_recvmsg_nosec(iocb, sock, msg, size, flags);
+}
+
int sock_recvmsg(struct socket *sock, struct msghdr *msg,
size_t size, int flags)
{
@@ -702,6 +720,21 @@ int sock_recvmsg(struct socket *sock, struct msghdr *msg,
return ret;
}
+static int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg,
+ size_t size, int flags)
+{
+ struct kiocb iocb;
+ struct sock_iocb siocb;
+ int ret;
+
+ init_sync_kiocb(&iocb, NULL);
+ iocb.private = &siocb;
+ ret = __sock_recvmsg_nosec(&iocb, sock, msg, size, flags);
+ if (-EIOCBQUEUED == ret)
+ ret = wait_on_sync_kiocb(&iocb);
+ return ret;
+}
+
int kernel_recvmsg(struct socket *sock, struct msghdr *msg,
struct kvec *vec, size_t num, size_t size, int flags)
{
@@ -905,11 +938,11 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
err = dev_ioctl(net, cmd, argp);
} else
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_WEXT_CORE
if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
err = dev_ioctl(net, cmd, argp);
} else
-#endif /* CONFIG_WIRELESS_EXT */
+#endif
switch (cmd) {
case FIOSETOWN:
case SIOCSPGRP:
@@ -1100,11 +1133,14 @@ static int sock_fasync(int fd, struct file *filp, int on)
fna->fa_next = sock->fasync_list;
write_lock_bh(&sk->sk_callback_lock);
sock->fasync_list = fna;
+ sock_set_flag(sk, SOCK_FASYNC);
write_unlock_bh(&sk->sk_callback_lock);
} else {
if (fa != NULL) {
write_lock_bh(&sk->sk_callback_lock);
*prev = fa->fa_next;
+ if (!sock->fasync_list)
+ sock_reset_flag(sk, SOCK_FASYNC);
write_unlock_bh(&sk->sk_callback_lock);
kfree(fa);
}
@@ -1965,22 +2001,15 @@ out:
return err;
}
-/*
- * BSD recvmsg interface
- */
-
-SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
- unsigned int, flags)
+static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
+ struct msghdr *msg_sys, unsigned flags, int nosec)
{
struct compat_msghdr __user *msg_compat =
(struct compat_msghdr __user *)msg;
- struct socket *sock;
struct iovec iovstack[UIO_FASTIOV];
struct iovec *iov = iovstack;
- struct msghdr msg_sys;
unsigned long cmsg_ptr;
int err, iov_size, total_len, len;
- int fput_needed;
/* kernel mode address */
struct sockaddr_storage addr;
@@ -1990,27 +2019,23 @@ SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
int __user *uaddr_len;
if (MSG_CMSG_COMPAT & flags) {
- if (get_compat_msghdr(&msg_sys, msg_compat))
+ if (get_compat_msghdr(msg_sys, msg_compat))
return -EFAULT;
}
- else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
+ else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))
return -EFAULT;
- sock = sockfd_lookup_light(fd, &err, &fput_needed);
- if (!sock)
- goto out;
-
err = -EMSGSIZE;
- if (msg_sys.msg_iovlen > UIO_MAXIOV)
- goto out_put;
+ if (msg_sys->msg_iovlen > UIO_MAXIOV)
+ goto out;
/* Check whether to allocate the iovec area */
err = -ENOMEM;
- iov_size = msg_sys.msg_iovlen * sizeof(struct iovec);
- if (msg_sys.msg_iovlen > UIO_FASTIOV) {
+ iov_size = msg_sys->msg_iovlen * sizeof(struct iovec);
+ if (msg_sys->msg_iovlen > UIO_FASTIOV) {
iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL);
if (!iov)
- goto out_put;
+ goto out;
}
/*
@@ -2018,46 +2043,47 @@ SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
* kernel msghdr to use the kernel address space)
*/
- uaddr = (__force void __user *)msg_sys.msg_name;
+ uaddr = (__force void __user *)msg_sys->msg_name;
uaddr_len = COMPAT_NAMELEN(msg);
if (MSG_CMSG_COMPAT & flags) {
- err = verify_compat_iovec(&msg_sys, iov,
+ err = verify_compat_iovec(msg_sys, iov,
(struct sockaddr *)&addr,
VERIFY_WRITE);
} else
- err = verify_iovec(&msg_sys, iov,
+ err = verify_iovec(msg_sys, iov,
(struct sockaddr *)&addr,
VERIFY_WRITE);
if (err < 0)
goto out_freeiov;
total_len = err;
- cmsg_ptr = (unsigned long)msg_sys.msg_control;
- msg_sys.msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT);
+ cmsg_ptr = (unsigned long)msg_sys->msg_control;
+ msg_sys->msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT);
if (sock->file->f_flags & O_NONBLOCK)
flags |= MSG_DONTWAIT;
- err = sock_recvmsg(sock, &msg_sys, total_len, flags);
+ err = (nosec ? sock_recvmsg_nosec : sock_recvmsg)(sock, msg_sys,
+ total_len, flags);
if (err < 0)
goto out_freeiov;
len = err;
if (uaddr != NULL) {
err = move_addr_to_user((struct sockaddr *)&addr,
- msg_sys.msg_namelen, uaddr,
+ msg_sys->msg_namelen, uaddr,
uaddr_len);
if (err < 0)
goto out_freeiov;
}
- err = __put_user((msg_sys.msg_flags & ~MSG_CMSG_COMPAT),
+ err = __put_user((msg_sys->msg_flags & ~MSG_CMSG_COMPAT),
COMPAT_FLAGS(msg));
if (err)
goto out_freeiov;
if (MSG_CMSG_COMPAT & flags)
- err = __put_user((unsigned long)msg_sys.msg_control - cmsg_ptr,
+ err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr,
&msg_compat->msg_controllen);
else
- err = __put_user((unsigned long)msg_sys.msg_control - cmsg_ptr,
+ err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr,
&msg->msg_controllen);
if (err)
goto out_freeiov;
@@ -2066,21 +2092,150 @@ SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
out_freeiov:
if (iov != iovstack)
sock_kfree_s(sock->sk, iov, iov_size);
-out_put:
+out:
+ return err;
+}
+
+/*
+ * BSD recvmsg interface
+ */
+
+SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
+ unsigned int, flags)
+{
+ int fput_needed, err;
+ struct msghdr msg_sys;
+ struct socket *sock = sockfd_lookup_light(fd, &err, &fput_needed);
+
+ if (!sock)
+ goto out;
+
+ err = __sys_recvmsg(sock, msg, &msg_sys, flags, 0);
+
fput_light(sock->file, fput_needed);
out:
return err;
}
-#ifdef __ARCH_WANT_SYS_SOCKETCALL
+/*
+ * Linux recvmmsg interface
+ */
+
+int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
+ unsigned int flags, struct timespec *timeout)
+{
+ int fput_needed, err, datagrams;
+ struct socket *sock;
+ struct mmsghdr __user *entry;
+ struct msghdr msg_sys;
+ struct timespec end_time;
+
+ if (timeout &&
+ poll_select_set_timeout(&end_time, timeout->tv_sec,
+ timeout->tv_nsec))
+ return -EINVAL;
+
+ datagrams = 0;
+
+ sock = sockfd_lookup_light(fd, &err, &fput_needed);
+ if (!sock)
+ return err;
+
+ err = sock_error(sock->sk);
+ if (err)
+ goto out_put;
+
+ entry = mmsg;
+
+ while (datagrams < vlen) {
+ /*
+ * No need to ask LSM for more than the first datagram.
+ */
+ err = __sys_recvmsg(sock, (struct msghdr __user *)entry,
+ &msg_sys, flags, datagrams);
+ if (err < 0)
+ break;
+ err = put_user(err, &entry->msg_len);
+ if (err)
+ break;
+ ++entry;
+ ++datagrams;
+
+ if (timeout) {
+ ktime_get_ts(timeout);
+ *timeout = timespec_sub(end_time, *timeout);
+ if (timeout->tv_sec < 0) {
+ timeout->tv_sec = timeout->tv_nsec = 0;
+ break;
+ }
+
+ /* Timeout, return less than vlen datagrams */
+ if (timeout->tv_nsec == 0 && timeout->tv_sec == 0)
+ break;
+ }
+
+ /* Out of band data, return right away */
+ if (msg_sys.msg_flags & MSG_OOB)
+ break;
+ }
+
+out_put:
+ fput_light(sock->file, fput_needed);
+
+ if (err == 0)
+ return datagrams;
+
+ if (datagrams != 0) {
+ /*
+ * We may return less entries than requested (vlen) if the
+ * sock is non block and there aren't enough datagrams...
+ */
+ if (err != -EAGAIN) {
+ /*
+ * ... or if recvmsg returns an error after we
+ * received some datagrams, where we record the
+ * error to return on the next call or if the
+ * app asks about it using getsockopt(SO_ERROR).
+ */
+ sock->sk->sk_err = -err;
+ }
+ return datagrams;
+ }
+
+ return err;
+}
+
+SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
+ unsigned int, vlen, unsigned int, flags,
+ struct timespec __user *, timeout)
+{
+ int datagrams;
+ struct timespec timeout_sys;
+
+ if (!timeout)
+ return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL);
+
+ if (copy_from_user(&timeout_sys, timeout, sizeof(timeout_sys)))
+ return -EFAULT;
+
+ datagrams = __sys_recvmmsg(fd, mmsg, vlen, flags, &timeout_sys);
+
+ if (datagrams > 0 &&
+ copy_to_user(timeout, &timeout_sys, sizeof(timeout_sys)))
+ datagrams = -EFAULT;
+
+ return datagrams;
+}
+
+#ifdef __ARCH_WANT_SYS_SOCKETCALL
/* Argument list sizes for sys_socketcall */
#define AL(x) ((x) * sizeof(unsigned long))
-static const unsigned char nargs[19]={
+static const unsigned char nargs[20] = {
AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
AL(6),AL(2),AL(5),AL(5),AL(3),AL(3),
- AL(4)
+ AL(4),AL(5)
};
#undef AL
@@ -2100,7 +2255,7 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
int err;
unsigned int len;
- if (call < 1 || call > SYS_ACCEPT4)
+ if (call < 1 || call > SYS_RECVMMSG)
return -EINVAL;
len = nargs[call];
@@ -2178,6 +2333,10 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
case SYS_RECVMSG:
err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
break;
+ case SYS_RECVMMSG:
+ err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3],
+ (struct timespec __user *)a[4]);
+ break;
case SYS_ACCEPT4:
err = sys_accept4(a0, (struct sockaddr __user *)a1,
(int __user *)a[2], a[3]);
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 117f68a8aa40..7d052f3dc9fe 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -655,23 +655,25 @@ static struct unix_gid *unix_gid_lookup(uid_t uid)
return NULL;
}
-static int unix_gid_find(uid_t uid, struct group_info **gip,
- struct svc_rqst *rqstp)
+static struct group_info *unix_gid_find(uid_t uid, struct svc_rqst *rqstp)
{
- struct unix_gid *ug = unix_gid_lookup(uid);
+ struct unix_gid *ug;
+ struct group_info *gi;
+ int ret;
+
+ ug = unix_gid_lookup(uid);
if (!ug)
- return -EAGAIN;
- switch (cache_check(&unix_gid_cache, &ug->h, &rqstp->rq_chandle)) {
+ return ERR_PTR(-EAGAIN);
+ ret = cache_check(&unix_gid_cache, &ug->h, &rqstp->rq_chandle);
+ switch (ret) {
case -ENOENT:
- *gip = NULL;
- return 0;
+ return ERR_PTR(-ENOENT);
case 0:
- *gip = ug->gi;
- get_group_info(*gip);
+ gi = get_group_info(ug->gi);
cache_put(&ug->h, &unix_gid_cache);
- return 0;
+ return gi;
default:
- return -EAGAIN;
+ return ERR_PTR(-EAGAIN);
}
}
@@ -681,13 +683,14 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6, sin6_storage;
struct ip_map *ipm;
+ struct group_info *gi;
+ struct svc_cred *cred = &rqstp->rq_cred;
switch (rqstp->rq_addr.ss_family) {
case AF_INET:
sin = svc_addr_in(rqstp);
sin6 = &sin6_storage;
- ipv6_addr_set(&sin6->sin6_addr, 0, 0,
- htonl(0x0000FFFF), sin->sin_addr.s_addr);
+ ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &sin6->sin6_addr);
break;
case AF_INET6:
sin6 = svc_addr_in6(rqstp);
@@ -722,6 +725,17 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
ip_map_cached_put(rqstp, ipm);
break;
}
+
+ gi = unix_gid_find(cred->cr_uid, rqstp);
+ switch (PTR_ERR(gi)) {
+ case -EAGAIN:
+ return SVC_DROP;
+ case -ENOENT:
+ break;
+ default:
+ put_group_info(cred->cr_group_info);
+ cred->cr_group_info = gi;
+ }
return SVC_OK;
}
@@ -818,19 +832,11 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
slen = svc_getnl(argv); /* gids length */
if (slen > 16 || (len -= (slen + 2)*4) < 0)
goto badcred;
- if (unix_gid_find(cred->cr_uid, &cred->cr_group_info, rqstp)
- == -EAGAIN)
+ cred->cr_group_info = groups_alloc(slen);
+ if (cred->cr_group_info == NULL)
return SVC_DROP;
- if (cred->cr_group_info == NULL) {
- cred->cr_group_info = groups_alloc(slen);
- if (cred->cr_group_info == NULL)
- return SVC_DROP;
- for (i = 0; i < slen; i++)
- GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv);
- } else {
- for (i = 0; i < slen ; i++)
- svc_getnl(argv);
- }
+ 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) {
*authp = rpc_autherr_badverf;
return SVC_DENIED;
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index ccc5e83cae5d..c2a17876defd 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -272,14 +272,14 @@ static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining)
case PF_INET:
len = snprintf(buf, remaining, "ipv4 %s %pI4 %d\n",
proto_name,
- &inet_sk(sk)->rcv_saddr,
- inet_sk(sk)->num);
+ &inet_sk(sk)->inet_rcv_saddr,
+ inet_sk(sk)->inet_num);
break;
case PF_INET6:
len = snprintf(buf, remaining, "ipv6 %s %pI6 %d\n",
proto_name,
&inet6_sk(sk)->rcv_saddr,
- inet_sk(sk)->num);
+ inet_sk(sk)->inet_num);
break;
default:
len = snprintf(buf, remaining, "*unknown-%d*\n",
@@ -1311,7 +1311,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
/* Register socket with portmapper */
if (*errp >= 0 && pmap_register)
*errp = svc_register(serv, inet->sk_family, inet->sk_protocol,
- ntohs(inet_sk(inet)->sport));
+ ntohs(inet_sk(inet)->inet_sport));
if (*errp < 0) {
kfree(svsk);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 51ab497115eb..3291902f0b88 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1074,6 +1074,8 @@ restart:
err = -ECONNREFUSED;
if (other->sk_state != TCP_LISTEN)
goto out_unlock;
+ if (other->sk_shutdown & RCV_SHUTDOWN)
+ goto out_unlock;
if (unix_recvq_full(other)) {
err = -EAGAIN;
@@ -2214,7 +2216,7 @@ static const struct file_operations unix_seq_fops = {
#endif
-static struct net_proto_family unix_family_ops = {
+static const struct net_proto_family unix_family_ops = {
.family = PF_UNIX,
.create = unix_create,
.owner = THIS_MODULE,
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index abf7ca3f9ff9..614bdcec1c80 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -1,3 +1,21 @@
+config WIRELESS_EXT
+ bool
+
+config WEXT_CORE
+ def_bool y
+ depends on CFG80211_WEXT || WIRELESS_EXT
+
+config WEXT_PROC
+ def_bool y
+ depends on PROC_FS
+ depends on WEXT_CORE
+
+config WEXT_SPY
+ bool
+
+config WEXT_PRIV
+ bool
+
config CFG80211
tristate "cfg80211 - wireless configuration API"
depends on RFKILL || !RFKILL
@@ -56,6 +74,12 @@ config CFG80211_REG_DEBUG
If unsure, say N.
+config CFG80211_DEFAULT_PS_VALUE
+ int
+ default 1 if CFG80211_DEFAULT_PS
+ default 0
+ depends on CFG80211
+
config CFG80211_DEFAULT_PS
bool "enable powersave by default"
depends on CFG80211
@@ -67,14 +91,10 @@ config CFG80211_DEFAULT_PS
applications instead -- they need to register their network
latency requirement, see Documentation/power/pm_qos_interface.txt.
-config CFG80211_DEFAULT_PS_VALUE
- int
- default 1 if CFG80211_DEFAULT_PS
- default 0
-
config CFG80211_DEBUGFS
bool "cfg80211 DebugFS entries"
- depends on CFG80211 && DEBUG_FS
+ depends on CFG80211
+ depends on DEBUG_FS
---help---
You can enable this if you want to debugfs entries for cfg80211.
@@ -83,6 +103,7 @@ config CFG80211_DEBUGFS
config WIRELESS_OLD_REGULATORY
bool "Old wireless static regulatory definitions"
default n
+ depends on CFG80211
---help---
This option enables the old static regulatory information
and uses it within the new framework. This option is available
@@ -94,20 +115,19 @@ config WIRELESS_OLD_REGULATORY
Say N and if you say Y, please tell us why. The default is N.
-config WIRELESS_EXT
- bool "Wireless extensions"
+config CFG80211_WEXT
+ bool "cfg80211 wireless extensions compatibility"
+ depends on CFG80211
+ select WEXT_CORE
default y
- ---help---
- This option enables the legacy wireless extensions
- (wireless network interface configuration via ioctls.)
-
- Say Y unless you've upgraded all your userspace to use
- nl80211 instead of wireless extensions.
+ help
+ Enable this option if you need old userspace for wireless
+ extensions with cfg80211-based drivers.
config WIRELESS_EXT_SYSFS
bool "Wireless extensions sysfs files"
default y
- depends on WIRELESS_EXT && SYSFS
+ depends on WEXT_CORE && SYSFS
help
This option enables the deprecated wireless statistics
files in /sys/class/net/*/wireless/. The same information
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 3ecaa9179977..f07c8dc7aab2 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -1,13 +1,17 @@
-obj-$(CONFIG_WIRELESS_EXT) += wext.o
obj-$(CONFIG_CFG80211) += cfg80211.o
obj-$(CONFIG_LIB80211) += lib80211.o
obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o
obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
+obj-$(CONFIG_WEXT_CORE) += wext-core.o
+obj-$(CONFIG_WEXT_PROC) += wext-proc.o
+obj-$(CONFIG_WEXT_SPY) += wext-spy.o
+obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
+
cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
-cfg80211-y += mlme.o ibss.o sme.o chan.o
+cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o
cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
-cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o wext-sme.o
+cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/net/wireless/core.c b/net/wireless/core.c
index a595f712b5bf..1758f2447ac8 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -22,6 +22,7 @@
#include "sysfs.h"
#include "debugfs.h"
#include "wext-compat.h"
+#include "ethtool.h"
/* name for sysfs, %d is appended */
#define PHY_NAME "phy"
@@ -359,6 +360,10 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
INIT_LIST_HEAD(&rdev->bss_list);
INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
+#ifdef CONFIG_CFG80211_WEXT
+ rdev->wiphy.wext = &cfg80211_wext_handler;
+#endif
+
device_initialize(&rdev->wiphy.dev);
rdev->wiphy.dev.class = &ieee80211_class;
rdev->wiphy.dev.platform_data = rdev;
@@ -626,6 +631,10 @@ static void wdev_cleanup_work(struct work_struct *work)
dev_put(wdev->netdev);
}
+static struct device_type wiphy_type = {
+ .name = "wlan",
+};
+
static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
unsigned long state,
void *ndev)
@@ -642,6 +651,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
WARN_ON(wdev->iftype == NL80211_IFTYPE_UNSPECIFIED);
switch (state) {
+ case NETDEV_POST_INIT:
+ SET_NETDEV_DEVTYPE(dev, &wiphy_type);
+ break;
case NETDEV_REGISTER:
/*
* NB: cannot take rdev->mtx here because this may be
@@ -666,9 +678,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
wdev->netdev = dev;
wdev->sme_state = CFG80211_SME_IDLE;
mutex_unlock(&rdev->devlist_mtx);
-#ifdef CONFIG_WIRELESS_EXT
- if (!dev->wireless_handlers)
- dev->wireless_handlers = &cfg80211_wext_handler;
+#ifdef CONFIG_CFG80211_WEXT
wdev->wext.default_key = -1;
wdev->wext.default_mgmt_key = -1;
wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
@@ -682,6 +692,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
wdev->wext.ps = false;
}
#endif
+ if (!dev->ethtool_ops)
+ dev->ethtool_ops = &cfg80211_ethtool_ops;
break;
case NETDEV_GOING_DOWN:
switch (wdev->iftype) {
@@ -690,7 +702,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
break;
case NL80211_IFTYPE_STATION:
wdev_lock(wdev);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
kfree(wdev->wext.ie);
wdev->wext.ie = NULL;
wdev->wext.ie_len = 0;
@@ -722,7 +734,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
mutex_unlock(&rdev->devlist_mtx);
dev_put(dev);
}
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
cfg80211_lock_rdev(rdev);
mutex_lock(&rdev->devlist_mtx);
wdev_lock(wdev);
@@ -760,7 +772,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
sysfs_remove_link(&dev->dev.kobj, "phy80211");
list_del_init(&wdev->list);
rdev->devlist_generation++;
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
kfree(wdev->wext.keys);
#endif
}
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 2a33d8bc886b..68b321997d4c 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -358,6 +358,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev);
void cfg80211_conn_work(struct work_struct *work);
+void cfg80211_sme_failed_assoc(struct wireless_dev *wdev);
bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev);
/* internal helpers */
diff --git a/net/wireless/ethtool.c b/net/wireless/ethtool.c
new file mode 100644
index 000000000000..ca4c825be93d
--- /dev/null
+++ b/net/wireless/ethtool.c
@@ -0,0 +1,45 @@
+#include <linux/utsname.h>
+#include <net/cfg80211.h>
+#include "ethtool.h"
+
+static void cfg80211_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ strlcpy(info->driver, wiphy_dev(wdev->wiphy)->driver->name,
+ sizeof(info->driver));
+
+ strlcpy(info->version, init_utsname()->release, sizeof(info->version));
+
+ if (wdev->wiphy->fw_version[0])
+ strncpy(info->fw_version, wdev->wiphy->fw_version,
+ sizeof(info->fw_version));
+ else
+ strncpy(info->fw_version, "N/A", sizeof(info->fw_version));
+
+ strlcpy(info->bus_info, dev_name(wiphy_dev(wdev->wiphy)),
+ sizeof(info->bus_info));
+}
+
+static int cfg80211_get_regs_len(struct net_device *dev)
+{
+ /* For now, return 0... */
+ return 0;
+}
+
+static void cfg80211_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+ void *data)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ regs->version = wdev->wiphy->hw_version;
+ regs->len = 0;
+}
+
+const struct ethtool_ops cfg80211_ethtool_ops = {
+ .get_drvinfo = cfg80211_get_drvinfo,
+ .get_regs_len = cfg80211_get_regs_len,
+ .get_regs = cfg80211_get_regs,
+ .get_link = ethtool_op_get_link,
+};
diff --git a/net/wireless/ethtool.h b/net/wireless/ethtool.h
new file mode 100644
index 000000000000..695ecad20bd6
--- /dev/null
+++ b/net/wireless/ethtool.h
@@ -0,0 +1,6 @@
+#ifndef __CFG80211_ETHTOOL__
+#define __CFG80211_ETHTOOL__
+
+extern const struct ethtool_ops cfg80211_ethtool_ops;
+
+#endif /* __CFG80211_ETHTOOL__ */
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index c88338911979..39b6d92e2828 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -15,7 +15,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_bss *bss;
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
#endif
@@ -44,7 +44,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
GFP_KERNEL);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
memset(&wrqu, 0, sizeof(wrqu));
memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
@@ -96,7 +96,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
kfree(wdev->connect_keys);
wdev->connect_keys = connkeys;
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
wdev->wext.ibss.channel = params->channel;
#endif
err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
@@ -154,7 +154,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
wdev->current_bss = NULL;
wdev->ssid_len = 0;
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
if (!nowext)
wdev->wext.ibss.ssid_len = 0;
#endif
@@ -203,7 +203,7 @@ int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
return err;
}
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev)
{
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 79d2eec54cec..83c2a288dc63 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -62,6 +62,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
u8 *ie = mgmt->u.assoc_resp.variable;
int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
struct cfg80211_internal_bss *bss = NULL;
+ bool need_connect_result = true;
wdev_lock(wdev);
@@ -94,6 +95,14 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
}
WARN_ON(!bss);
+ } else if (wdev->conn) {
+ cfg80211_sme_failed_assoc(wdev);
+ need_connect_result = false;
+ /*
+ * do not call connect_result() now because the
+ * sme will schedule work that does it later.
+ */
+ goto out;
}
if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) {
@@ -121,7 +130,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
}
EXPORT_SYMBOL(cfg80211_send_rx_assoc);
-static void __cfg80211_send_deauth(struct net_device *dev,
+void __cfg80211_send_deauth(struct net_device *dev,
const u8 *buf, size_t len)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -130,7 +139,6 @@ static void __cfg80211_send_deauth(struct net_device *dev,
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
const u8 *bssid = mgmt->bssid;
int i;
- bool done = false;
ASSERT_WDEV_LOCK(wdev);
@@ -138,7 +146,6 @@ static void __cfg80211_send_deauth(struct net_device *dev,
if (wdev->current_bss &&
memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
- done = true;
cfg80211_unhold_bss(wdev->current_bss);
cfg80211_put_bss(&wdev->current_bss->pub);
wdev->current_bss = NULL;
@@ -148,7 +155,6 @@ static void __cfg80211_send_deauth(struct net_device *dev,
cfg80211_unhold_bss(wdev->auth_bsses[i]);
cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
wdev->auth_bsses[i] = NULL;
- done = true;
break;
}
if (wdev->authtry_bsses[i] &&
@@ -156,13 +162,10 @@ static void __cfg80211_send_deauth(struct net_device *dev,
cfg80211_unhold_bss(wdev->authtry_bsses[i]);
cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
wdev->authtry_bsses[i] = NULL;
- done = true;
break;
}
}
- WARN_ON(!done);
-
if (wdev->sme_state == CFG80211_SME_CONNECTED) {
u16 reason_code;
bool from_ap;
@@ -177,27 +180,19 @@ static void __cfg80211_send_deauth(struct net_device *dev,
false, NULL);
}
}
+EXPORT_SYMBOL(__cfg80211_send_deauth);
-
-void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len,
- void *cookie)
+void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
- BUG_ON(cookie && wdev != cookie);
-
- if (cookie) {
- /* called within callback */
- __cfg80211_send_deauth(dev, buf, len);
- } else {
- wdev_lock(wdev);
- __cfg80211_send_deauth(dev, buf, len);
- wdev_unlock(wdev);
- }
+ wdev_lock(wdev);
+ __cfg80211_send_deauth(dev, buf, len);
+ wdev_unlock(wdev);
}
EXPORT_SYMBOL(cfg80211_send_deauth);
-static void __cfg80211_send_disassoc(struct net_device *dev,
+void __cfg80211_send_disassoc(struct net_device *dev,
const u8 *buf, size_t len)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -238,22 +233,15 @@ static void __cfg80211_send_disassoc(struct net_device *dev,
from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
__cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
}
+EXPORT_SYMBOL(__cfg80211_send_disassoc);
-void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len,
- void *cookie)
+void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
- BUG_ON(cookie && wdev != cookie);
-
- if (cookie) {
- /* called within callback */
- __cfg80211_send_disassoc(dev, buf, len);
- } else {
- wdev_lock(wdev);
- __cfg80211_send_disassoc(dev, buf, len);
- wdev_unlock(wdev);
- }
+ wdev_lock(wdev);
+ __cfg80211_send_disassoc(dev, buf, len);
+ wdev_unlock(wdev);
}
EXPORT_SYMBOL(cfg80211_send_disassoc);
@@ -331,7 +319,7 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
{
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
char *buf = kmalloc(128, gfp);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ca3c92a0a14f..f48394126bf9 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1264,7 +1264,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
if (!err)
err = func(&rdev->wiphy, dev, key.idx);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
if (!err) {
if (func == rdev->ops->set_default_key)
dev->ieee80211_ptr->wext.default_key = key.idx;
@@ -1365,7 +1365,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
if (!err)
err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
if (!err) {
if (key.idx == dev->ieee80211_ptr->wext.default_key)
dev->ieee80211_ptr->wext.default_key = -1;
@@ -3105,6 +3105,8 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
NLA_PUT_U16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval);
NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability);
NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq);
+ NLA_PUT_U32(msg, NL80211_BSS_SEEN_MS_AGO,
+ jiffies_to_msecs(jiffies - intbss->ts));
switch (rdev->wiphy.signal_type) {
case CFG80211_SIGNAL_TYPE_MBM:
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index e5f92ee758f4..2e8c515f3c5c 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -22,7 +22,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
{
struct cfg80211_scan_request *request;
struct net_device *dev;
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
#endif
@@ -47,7 +47,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
else
nl80211_send_scan_done(rdev, dev);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
if (!request->aborted) {
memset(&wrqu, 0, sizeof(wrqu));
@@ -592,7 +592,7 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
}
EXPORT_SYMBOL(cfg80211_unlink_bss);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
int cfg80211_wext_siwscan(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 93c3ed329204..98a3b7efac4c 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -26,6 +26,7 @@ struct cfg80211_conn {
CFG80211_CONN_AUTHENTICATING,
CFG80211_CONN_ASSOCIATE_NEXT,
CFG80211_CONN_ASSOCIATING,
+ CFG80211_CONN_DEAUTH_ASSOC_FAIL,
} state;
u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
u8 *ie;
@@ -148,6 +149,12 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
NULL, 0,
WLAN_REASON_DEAUTH_LEAVING);
return err;
+ case CFG80211_CONN_DEAUTH_ASSOC_FAIL:
+ __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
+ NULL, 0,
+ WLAN_REASON_DEAUTH_LEAVING);
+ /* return an error so that we call __cfg80211_connect_result() */
+ return -EINVAL;
default:
return 0;
}
@@ -158,6 +165,7 @@ void cfg80211_conn_work(struct work_struct *work)
struct cfg80211_registered_device *rdev =
container_of(work, struct cfg80211_registered_device, conn_work);
struct wireless_dev *wdev;
+ u8 bssid[ETH_ALEN];
rtnl_lock();
cfg80211_lock_rdev(rdev);
@@ -173,10 +181,10 @@ void cfg80211_conn_work(struct work_struct *work)
wdev_unlock(wdev);
continue;
}
+ memcpy(bssid, wdev->conn->params.bssid, ETH_ALEN);
if (cfg80211_conn_do_work(wdev))
__cfg80211_connect_result(
- wdev->netdev,
- wdev->conn->params.bssid,
+ wdev->netdev, bssid,
NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
false, NULL);
@@ -337,6 +345,15 @@ bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev)
return true;
}
+void cfg80211_sme_failed_assoc(struct wireless_dev *wdev)
+{
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+ wdev->conn->state = CFG80211_CONN_DEAUTH_ASSOC_FAIL;
+ schedule_work(&rdev->conn_work);
+}
+
void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
const u8 *req_ie, size_t req_ie_len,
const u8 *resp_ie, size_t resp_ie_len,
@@ -345,7 +362,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
u8 *country_ie;
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
#endif
@@ -362,7 +379,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
resp_ie, resp_ie_len,
status, GFP_KERNEL);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
if (wextev) {
if (req_ie && status == WLAN_STATUS_SUCCESS) {
memset(&wrqu, 0, sizeof(wrqu));
@@ -477,7 +494,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
const u8 *resp_ie, size_t resp_ie_len)
{
struct cfg80211_bss *bss;
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
#endif
@@ -512,7 +529,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
req_ie, req_ie_len, resp_ie, resp_ie_len,
GFP_KERNEL);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
if (req_ie) {
memset(&wrqu, 0, sizeof(wrqu));
wrqu.data.length = req_ie_len;
@@ -573,7 +590,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
int i;
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
#endif
@@ -631,7 +648,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
for (i = 0; i < 6; i++)
rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
memset(&wrqu, 0, sizeof(wrqu));
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
diff --git a/net/wireless/wext.c b/net/wireless/wext-core.c
index 60fe57761ca9..a4e5ddc8d4f5 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext-core.c
@@ -1,112 +1,28 @@
/*
- * This file implement the Wireless Extensions APIs.
+ * This file implement the Wireless Extensions core API.
*
* Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
* Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
+ * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
*
* (As all part of the Linux kernel, this file is GPL)
*/
-
-/************************** DOCUMENTATION **************************/
-/*
- * API definition :
- * --------------
- * See <linux/wireless.h> for details of the APIs and the rest.
- *
- * History :
- * -------
- *
- * v1 - 5.12.01 - Jean II
- * o Created this file.
- *
- * v2 - 13.12.01 - Jean II
- * o Move /proc/net/wireless stuff from net/core/dev.c to here
- * o Make Wireless Extension IOCTLs go through here
- * o Added iw_handler handling ;-)
- * o Added standard ioctl description
- * o Initial dumb commit strategy based on orinoco.c
- *
- * v3 - 19.12.01 - Jean II
- * o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call
- * o Add event dispatcher function
- * o Add event description
- * o Propagate events as rtnetlink IFLA_WIRELESS option
- * o Generate event on selected SET requests
- *
- * v4 - 18.04.02 - Jean II
- * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
- *
- * v5 - 21.06.02 - Jean II
- * o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup)
- * o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
- * o Add IWEVCUSTOM for driver specific event/scanning token
- * o Turn on WE_STRICT_WRITE by default + kernel warning
- * o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num)
- * o Fix off-by-one in test (extra_size <= IFNAMSIZ)
- *
- * v6 - 9.01.03 - Jean II
- * o Add common spy support : iw_handler_set_spy(), wireless_spy_update()
- * o Add enhanced spy support : iw_handler_set_thrspy() and event.
- * o Add WIRELESS_EXT version display in /proc/net/wireless
- *
- * v6 - 18.06.04 - Jean II
- * o Change get_spydata() method for added safety
- * o Remove spy #ifdef, they are always on -> cleaner code
- * o Allow any size GET request if user specifies length > max
- * and if request has IW_DESCR_FLAG_NOMAX flag or is SIOCGIWPRIV
- * o Start migrating get_wireless_stats to struct iw_handler_def
- * o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus
- * Based on patch from Pavel Roskin <proski@gnu.org> :
- * o Fix kernel data leak to user space in private handler handling
- *
- * v7 - 18.3.05 - Jean II
- * o Remove (struct iw_point *)->pointer from events and streams
- * o Remove spy_offset from struct iw_handler_def
- * o Start deprecating dev->get_wireless_stats, output a warning
- * o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless
- * o Don't lose INVALID/DBM flags when clearing UPDATED flags (iwstats)
- *
- * v8 - 17.02.06 - Jean II
- * o RtNetlink requests support (SET/GET)
- *
- * v8b - 03.08.06 - Herbert Xu
- * o Fix Wireless Event locking issues.
- *
- * v9 - 14.3.06 - Jean II
- * o Change length in ESSID and NICK to strlen() instead of strlen()+1
- * o Make standard_ioctl_num and standard_event_num unsigned
- * o Remove (struct net_device *)->get_wireless_stats()
- *
- * v10 - 16.3.07 - Jean II
- * o Prevent leaking of kernel space in stream on 64 bits.
- */
-
-/***************************** INCLUDES *****************************/
-
-#include <linux/module.h>
-#include <linux/types.h> /* off_t */
-#include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */
-#include <linux/proc_fs.h>
-#include <linux/rtnetlink.h> /* rtnetlink stuff */
-#include <linux/seq_file.h>
-#include <linux/init.h> /* for __init */
-#include <linux/if_arp.h> /* ARPHRD_ETHER */
-#include <linux/etherdevice.h> /* compare_ether_addr */
-#include <linux/interrupt.h>
-#include <net/net_namespace.h>
-
-#include <linux/wireless.h> /* Pretty obvious */
-#include <net/iw_handler.h> /* New driver API */
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/wireless.h>
+#include <linux/uaccess.h>
+#include <net/cfg80211.h>
+#include <net/iw_handler.h>
#include <net/netlink.h>
#include <net/wext.h>
+#include <net/net_namespace.h>
+
+typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *,
+ unsigned int, struct iw_request_info *,
+ iw_handler);
-#include <asm/uaccess.h> /* copy_to_user() */
-/************************* GLOBAL VARIABLES *************************/
-/*
- * You should not use global variables, because of re-entrancy.
- * On our case, it's only const, so it's OK...
- */
/*
* Meta-data about all the standard Wireless Extension request we
* know about.
@@ -390,18 +306,6 @@ static const struct iw_ioctl_description standard_event[] = {
};
static const unsigned standard_event_num = ARRAY_SIZE(standard_event);
-/* Size (in bytes) of the various private data types */
-static const char iw_priv_type_size[] = {
- 0, /* IW_PRIV_TYPE_NONE */
- 1, /* IW_PRIV_TYPE_BYTE */
- 1, /* IW_PRIV_TYPE_CHAR */
- 0, /* Not defined */
- sizeof(__u32), /* IW_PRIV_TYPE_INT */
- sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */
- sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */
- 0, /* Not defined */
-};
-
/* Size (in bytes) of various events */
static const int event_type_size[] = {
IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */
@@ -433,323 +337,346 @@ static const int compat_event_type_size[] = {
};
#endif
-/************************ COMMON SUBROUTINES ************************/
-/*
- * Stuff that may be used in various place or doesn't fit in one
- * of the section below.
- */
-
-/* ---------------------------------------------------------------- */
-/*
- * Return the driver handler associated with a specific Wireless Extension.
- */
-static iw_handler get_handler(struct net_device *dev, unsigned int cmd)
-{
- /* Don't "optimise" the following variable, it will crash */
- unsigned int index; /* *MUST* be unsigned */
- /* Check if we have some wireless handlers defined */
- if (dev->wireless_handlers == NULL)
- return NULL;
-
- /* Try as a standard command */
- index = cmd - SIOCIWFIRST;
- if (index < dev->wireless_handlers->num_standard)
- return dev->wireless_handlers->standard[index];
-
- /* Try as a private command */
- index = cmd - SIOCIWFIRSTPRIV;
- if (index < dev->wireless_handlers->num_private)
- return dev->wireless_handlers->private[index];
+/* IW event code */
- /* Not found */
- return NULL;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Get statistics out of the driver
- */
-struct iw_statistics *get_wireless_stats(struct net_device *dev)
+static int __net_init wext_pernet_init(struct net *net)
{
- /* New location */
- if ((dev->wireless_handlers != NULL) &&
- (dev->wireless_handlers->get_wireless_stats != NULL))
- return dev->wireless_handlers->get_wireless_stats(dev);
-
- /* Not found */
- return NULL;
+ skb_queue_head_init(&net->wext_nlevents);
+ return 0;
}
-/* ---------------------------------------------------------------- */
-/*
- * Call the commit handler in the driver
- * (if exist and if conditions are right)
- *
- * Note : our current commit strategy is currently pretty dumb,
- * but we will be able to improve on that...
- * The goal is to try to agreagate as many changes as possible
- * before doing the commit. Drivers that will define a commit handler
- * are usually those that need a reset after changing parameters, so
- * we want to minimise the number of reset.
- * A cool idea is to use a timer : at each "set" command, we re-set the
- * timer, when the timer eventually fires, we call the driver.
- * Hopefully, more on that later.
- *
- * Also, I'm waiting to see how many people will complain about the
- * netif_running(dev) test. I'm open on that one...
- * Hopefully, the driver will remember to do a commit in "open()" ;-)
- */
-static int call_commit_handler(struct net_device *dev)
+static void __net_exit wext_pernet_exit(struct net *net)
{
- if ((netif_running(dev)) &&
- (dev->wireless_handlers->standard[0] != NULL))
- /* Call the commit handler on the driver */
- return dev->wireless_handlers->standard[0](dev, NULL,
- NULL, NULL);
- else
- return 0; /* Command completed successfully */
+ skb_queue_purge(&net->wext_nlevents);
}
-/* ---------------------------------------------------------------- */
-/*
- * Calculate size of private arguments
- */
-static int get_priv_size(__u16 args)
-{
- int num = args & IW_PRIV_SIZE_MASK;
- int type = (args & IW_PRIV_TYPE_MASK) >> 12;
+static struct pernet_operations wext_pernet_ops = {
+ .init = wext_pernet_init,
+ .exit = wext_pernet_exit,
+};
- return num * iw_priv_type_size[type];
+static int __init wireless_nlevent_init(void)
+{
+ return register_pernet_subsys(&wext_pernet_ops);
}
-/* ---------------------------------------------------------------- */
-/*
- * Re-calculate the size of private arguments
- */
-static int adjust_priv_size(__u16 args, struct iw_point *iwp)
+subsys_initcall(wireless_nlevent_init);
+
+/* Process events generated by the wireless layer or the driver. */
+static void wireless_nlevent_process(struct work_struct *work)
{
- int num = iwp->length;
- int max = args & IW_PRIV_SIZE_MASK;
- int type = (args & IW_PRIV_TYPE_MASK) >> 12;
+ struct sk_buff *skb;
+ struct net *net;
- /* Make sure the driver doesn't goof up */
- if (max < num)
- num = max;
+ rtnl_lock();
+
+ for_each_net(net) {
+ while ((skb = skb_dequeue(&net->wext_nlevents)))
+ rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL,
+ GFP_KERNEL);
+ }
- return num * iw_priv_type_size[type];
+ rtnl_unlock();
}
-/* ---------------------------------------------------------------- */
-/*
- * Standard Wireless Handler : get wireless stats
- * Allow programatic access to /proc/net/wireless even if /proc
- * doesn't exist... Also more efficient...
- */
-static int iw_handler_get_iwstats(struct net_device * dev,
- struct iw_request_info * info,
- union iwreq_data * wrqu,
- char * extra)
+static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process);
+
+static struct nlmsghdr *rtnetlink_ifinfo_prep(struct net_device *dev,
+ struct sk_buff *skb)
{
- /* Get stats from the driver */
- struct iw_statistics *stats;
+ struct ifinfomsg *r;
+ struct nlmsghdr *nlh;
- stats = get_wireless_stats(dev);
- if (stats) {
- /* Copy statistics to extra */
- memcpy(extra, stats, sizeof(struct iw_statistics));
- wrqu->data.length = sizeof(struct iw_statistics);
+ nlh = nlmsg_put(skb, 0, 0, RTM_NEWLINK, sizeof(*r), 0);
+ if (!nlh)
+ return NULL;
- /* Check if we need to clear the updated flag */
- if (wrqu->data.flags != 0)
- stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
- return 0;
- } else
- return -EOPNOTSUPP;
+ r = nlmsg_data(nlh);
+ r->ifi_family = AF_UNSPEC;
+ r->__ifi_pad = 0;
+ r->ifi_type = dev->type;
+ r->ifi_index = dev->ifindex;
+ r->ifi_flags = dev_get_flags(dev);
+ r->ifi_change = 0; /* Wireless changes don't affect those flags */
+
+ NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
+
+ return nlh;
+ nla_put_failure:
+ nlmsg_cancel(skb, nlh);
+ return NULL;
}
-/* ---------------------------------------------------------------- */
+
/*
- * Standard Wireless Handler : get iwpriv definitions
- * Export the driver private handler definition
- * They will be picked up by tools like iwpriv...
+ * Main event dispatcher. Called from other parts and drivers.
+ * Send the event on the appropriate channels.
+ * May be called from interrupt context.
*/
-static int iw_handler_get_private(struct net_device * dev,
- struct iw_request_info * info,
- union iwreq_data * wrqu,
- char * extra)
+void wireless_send_event(struct net_device * dev,
+ unsigned int cmd,
+ union iwreq_data * wrqu,
+ const char * extra)
{
- /* Check if the driver has something to export */
- if ((dev->wireless_handlers->num_private_args == 0) ||
- (dev->wireless_handlers->private_args == NULL))
- return -EOPNOTSUPP;
+ const struct iw_ioctl_description * descr = NULL;
+ int extra_len = 0;
+ struct iw_event *event; /* Mallocated whole event */
+ int event_len; /* Its size */
+ int hdr_len; /* Size of the event header */
+ int wrqu_off = 0; /* Offset in wrqu */
+ /* Don't "optimise" the following variable, it will crash */
+ unsigned cmd_index; /* *MUST* be unsigned */
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ struct nlattr *nla;
+#ifdef CONFIG_COMPAT
+ struct __compat_iw_event *compat_event;
+ struct compat_iw_point compat_wrqu;
+ struct sk_buff *compskb;
+#endif
- /* Check if there is enough buffer up there */
- if (wrqu->data.length < dev->wireless_handlers->num_private_args) {
- /* User space can't know in advance how large the buffer
- * needs to be. Give it a hint, so that we can support
- * any size buffer we want somewhat efficiently... */
- wrqu->data.length = dev->wireless_handlers->num_private_args;
- return -E2BIG;
+ /*
+ * Nothing in the kernel sends scan events with data, be safe.
+ * This is necessary because we cannot fix up scan event data
+ * for compat, due to being contained in 'extra', but normally
+ * applications are required to retrieve the scan data anyway
+ * and no data is included in the event, this codifies that
+ * practice.
+ */
+ if (WARN_ON(cmd == SIOCGIWSCAN && extra))
+ extra = NULL;
+
+ /* Get the description of the Event */
+ if (cmd <= SIOCIWLAST) {
+ cmd_index = cmd - SIOCIWFIRST;
+ if (cmd_index < standard_ioctl_num)
+ descr = &(standard_ioctl[cmd_index]);
+ } else {
+ cmd_index = cmd - IWEVFIRST;
+ if (cmd_index < standard_event_num)
+ descr = &(standard_event[cmd_index]);
+ }
+ /* Don't accept unknown events */
+ if (descr == NULL) {
+ /* Note : we don't return an error to the driver, because
+ * the driver would not know what to do about it. It can't
+ * return an error to the user, because the event is not
+ * initiated by a user request.
+ * The best the driver could do is to log an error message.
+ * We will do it ourselves instead...
+ */
+ printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
+ dev->name, cmd);
+ return;
}
- /* Set the number of available ioctls. */
- wrqu->data.length = dev->wireless_handlers->num_private_args;
+ /* Check extra parameters and set extra_len */
+ if (descr->header_type == IW_HEADER_TYPE_POINT) {
+ /* Check if number of token fits within bounds */
+ if (wrqu->data.length > descr->max_tokens) {
+ printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
+ return;
+ }
+ if (wrqu->data.length < descr->min_tokens) {
+ printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
+ return;
+ }
+ /* Calculate extra_len - extra is NULL for restricted events */
+ if (extra != NULL)
+ extra_len = wrqu->data.length * descr->token_size;
+ /* Always at an offset in wrqu */
+ wrqu_off = IW_EV_POINT_OFF;
+ }
- /* Copy structure to the user buffer. */
- memcpy(extra, dev->wireless_handlers->private_args,
- sizeof(struct iw_priv_args) * wrqu->data.length);
+ /* Total length of the event */
+ hdr_len = event_type_size[descr->header_type];
+ event_len = hdr_len + extra_len;
- return 0;
-}
+ /*
+ * The problem for 64/32 bit.
+ *
+ * On 64-bit, a regular event is laid out as follows:
+ * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+ * | event.len | event.cmd | p a d d i n g |
+ * | wrqu data ... (with the correct size) |
+ *
+ * This padding exists because we manipulate event->u,
+ * and 'event' is not packed.
+ *
+ * An iw_point event is laid out like this instead:
+ * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+ * | event.len | event.cmd | p a d d i n g |
+ * | iwpnt.len | iwpnt.flg | p a d d i n g |
+ * | extra data ...
+ *
+ * The second padding exists because struct iw_point is extended,
+ * but this depends on the platform...
+ *
+ * On 32-bit, all the padding shouldn't be there.
+ */
+ skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+ if (!skb)
+ return;
-/******************** /proc/net/wireless SUPPORT ********************/
-/*
- * The /proc/net/wireless file is a human readable user-space interface
- * exporting various wireless specific statistics from the wireless devices.
- * This is the most popular part of the Wireless Extensions ;-)
- *
- * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
- * The content of the file is basically the content of "struct iw_statistics".
- */
+ /* Send via the RtNetlink event channel */
+ nlh = rtnetlink_ifinfo_prep(dev, skb);
+ if (WARN_ON(!nlh)) {
+ kfree_skb(skb);
+ return;
+ }
-#ifdef CONFIG_PROC_FS
+ /* Add the wireless events in the netlink packet */
+ nla = nla_reserve(skb, IFLA_WIRELESS, event_len);
+ if (!nla) {
+ kfree_skb(skb);
+ return;
+ }
+ event = nla_data(nla);
-/* ---------------------------------------------------------------- */
-/*
- * Print one entry (line) of /proc/net/wireless
- */
-static void wireless_seq_printf_stats(struct seq_file *seq,
- struct net_device *dev)
-{
- /* Get stats from the driver */
- struct iw_statistics *stats = get_wireless_stats(dev);
- static struct iw_statistics nullstats = {};
+ /* Fill event - first clear to avoid data leaking */
+ memset(event, 0, hdr_len);
+ event->len = event_len;
+ event->cmd = cmd;
+ memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN);
+ if (extra_len)
+ memcpy(((char *) event) + hdr_len, extra, extra_len);
- /* show device if it's wireless regardless of current stats */
- if (!stats && dev->wireless_handlers)
- stats = &nullstats;
+ nlmsg_end(skb, nlh);
+#ifdef CONFIG_COMPAT
+ hdr_len = compat_event_type_size[descr->header_type];
+ event_len = hdr_len + extra_len;
- if (stats) {
- seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d "
- "%6d %6d %6d\n",
- dev->name, stats->status, stats->qual.qual,
- stats->qual.updated & IW_QUAL_QUAL_UPDATED
- ? '.' : ' ',
- ((__s32) stats->qual.level) -
- ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
- stats->qual.updated & IW_QUAL_LEVEL_UPDATED
- ? '.' : ' ',
- ((__s32) stats->qual.noise) -
- ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
- stats->qual.updated & IW_QUAL_NOISE_UPDATED
- ? '.' : ' ',
- stats->discard.nwid, stats->discard.code,
- stats->discard.fragment, stats->discard.retries,
- stats->discard.misc, stats->miss.beacon);
-
- if (stats != &nullstats)
- stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
+ compskb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+ if (!compskb) {
+ kfree_skb(skb);
+ return;
}
-}
-/* ---------------------------------------------------------------- */
-/*
- * Print info for /proc/net/wireless (print all entries)
- */
-static int wireless_dev_seq_show(struct seq_file *seq, void *v)
-{
- might_sleep();
-
- if (v == SEQ_START_TOKEN)
- seq_printf(seq, "Inter-| sta-| Quality | Discarded "
- "packets | Missed | WE\n"
- " face | tus | link level noise | nwid "
- "crypt frag retry misc | beacon | %d\n",
- WIRELESS_EXT);
- else
- wireless_seq_printf_stats(seq, v);
- return 0;
+ /* Send via the RtNetlink event channel */
+ nlh = rtnetlink_ifinfo_prep(dev, compskb);
+ if (WARN_ON(!nlh)) {
+ kfree_skb(skb);
+ kfree_skb(compskb);
+ return;
+ }
+
+ /* Add the wireless events in the netlink packet */
+ nla = nla_reserve(compskb, IFLA_WIRELESS, event_len);
+ if (!nla) {
+ kfree_skb(skb);
+ kfree_skb(compskb);
+ return;
+ }
+ compat_event = nla_data(nla);
+
+ compat_event->len = event_len;
+ compat_event->cmd = cmd;
+ if (descr->header_type == IW_HEADER_TYPE_POINT) {
+ compat_wrqu.length = wrqu->data.length;
+ compat_wrqu.flags = wrqu->data.flags;
+ memcpy(&compat_event->pointer,
+ ((char *) &compat_wrqu) + IW_EV_COMPAT_POINT_OFF,
+ hdr_len - IW_EV_COMPAT_LCP_LEN);
+ if (extra_len)
+ memcpy(((char *) compat_event) + hdr_len,
+ extra, extra_len);
+ } else {
+ /* extra_len must be zero, so no if (extra) needed */
+ memcpy(&compat_event->pointer, wrqu,
+ hdr_len - IW_EV_COMPAT_LCP_LEN);
+ }
+
+ nlmsg_end(compskb, nlh);
+
+ skb_shinfo(skb)->frag_list = compskb;
+#endif
+ skb_queue_tail(&dev_net(dev)->wext_nlevents, skb);
+ schedule_work(&wireless_nlevent_work);
}
+EXPORT_SYMBOL(wireless_send_event);
+
+
+
+/* IW handlers */
-static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos)
+struct iw_statistics *get_wireless_stats(struct net_device *dev)
{
- struct net *net = seq_file_net(seq);
- loff_t off;
- struct net_device *dev;
+#ifdef CONFIG_WIRELESS_EXT
+ if ((dev->wireless_handlers != NULL) &&
+ (dev->wireless_handlers->get_wireless_stats != NULL))
+ return dev->wireless_handlers->get_wireless_stats(dev);
+#endif
- rtnl_lock();
- if (!*pos)
- return SEQ_START_TOKEN;
+#ifdef CONFIG_CFG80211_WEXT
+ if (dev->ieee80211_ptr && dev->ieee80211_ptr &&
+ dev->ieee80211_ptr->wiphy &&
+ dev->ieee80211_ptr->wiphy->wext &&
+ dev->ieee80211_ptr->wiphy->wext->get_wireless_stats)
+ return dev->ieee80211_ptr->wiphy->wext->get_wireless_stats(dev);
+#endif
- off = 1;
- for_each_netdev(net, dev)
- if (off++ == *pos)
- return dev;
+ /* not found */
return NULL;
}
-static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+static int iw_handler_get_iwstats(struct net_device * dev,
+ struct iw_request_info * info,
+ union iwreq_data * wrqu,
+ char * extra)
{
- struct net *net = seq_file_net(seq);
+ /* Get stats from the driver */
+ struct iw_statistics *stats;
- ++*pos;
+ stats = get_wireless_stats(dev);
+ if (stats) {
+ /* Copy statistics to extra */
+ memcpy(extra, stats, sizeof(struct iw_statistics));
+ wrqu->data.length = sizeof(struct iw_statistics);
- return v == SEQ_START_TOKEN ?
- first_net_device(net) : next_net_device(v);
+ /* Check if we need to clear the updated flag */
+ if (wrqu->data.flags != 0)
+ stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
+ return 0;
+ } else
+ return -EOPNOTSUPP;
}
-static void wireless_dev_seq_stop(struct seq_file *seq, void *v)
+static iw_handler get_handler(struct net_device *dev, unsigned int cmd)
{
- rtnl_unlock();
-}
-
-static const struct seq_operations wireless_seq_ops = {
- .start = wireless_dev_seq_start,
- .next = wireless_dev_seq_next,
- .stop = wireless_dev_seq_stop,
- .show = wireless_dev_seq_show,
-};
+ /* Don't "optimise" the following variable, it will crash */
+ unsigned int index; /* *MUST* be unsigned */
+ const struct iw_handler_def *handlers = NULL;
-static int seq_open_wireless(struct inode *inode, struct file *file)
-{
- return seq_open_net(inode, file, &wireless_seq_ops,
- sizeof(struct seq_net_private));
-}
+#ifdef CONFIG_CFG80211_WEXT
+ if (dev->ieee80211_ptr && dev->ieee80211_ptr->wiphy)
+ handlers = dev->ieee80211_ptr->wiphy->wext;
+#endif
+#ifdef CONFIG_WIRELESS_EXT
+ if (dev->wireless_handlers)
+ handlers = dev->wireless_handlers;
+#endif
-static const struct file_operations wireless_seq_fops = {
- .owner = THIS_MODULE,
- .open = seq_open_wireless,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release_net,
-};
+ if (!handlers)
+ return NULL;
-int wext_proc_init(struct net *net)
-{
- /* Create /proc/net/wireless entry */
- if (!proc_net_fops_create(net, "wireless", S_IRUGO, &wireless_seq_fops))
- return -ENOMEM;
+ /* Try as a standard command */
+ index = cmd - SIOCIWFIRST;
+ if (index < handlers->num_standard)
+ return handlers->standard[index];
- return 0;
-}
+#ifdef CONFIG_WEXT_PRIV
+ /* Try as a private command */
+ index = cmd - SIOCIWFIRSTPRIV;
+ if (index < handlers->num_private)
+ return handlers->private[index];
+#endif
-void wext_proc_exit(struct net *net)
-{
- proc_net_remove(net, "wireless");
+ /* Not found */
+ return NULL;
}
-#endif /* CONFIG_PROC_FS */
-/************************** IOCTL SUPPORT **************************/
-/*
- * The original user space API to configure all those Wireless Extensions
- * is through IOCTLs.
- * In there, we check if we need to call the new driver API (iw_handler)
- * or just call the driver ioctl handler.
- */
-
-/* ---------------------------------------------------------------- */
static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd,
const struct iw_ioctl_description *descr,
iw_handler handler, struct net_device *dev,
@@ -893,188 +820,39 @@ out:
}
/*
- * Wrapper to call a standard Wireless Extension handler.
- * We do various checks and also take care of moving data between
- * user space and kernel space.
- */
-static int ioctl_standard_call(struct net_device * dev,
- struct iwreq *iwr,
- unsigned int cmd,
- struct iw_request_info *info,
- iw_handler handler)
-{
- const struct iw_ioctl_description * descr;
- int ret = -EINVAL;
-
- /* Get the description of the IOCTL */
- if ((cmd - SIOCIWFIRST) >= standard_ioctl_num)
- return -EOPNOTSUPP;
- descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
-
- /* Check if we have a pointer to user space data or not */
- if (descr->header_type != IW_HEADER_TYPE_POINT) {
-
- /* No extra arguments. Trivial to handle */
- ret = handler(dev, info, &(iwr->u), NULL);
-
- /* Generate an event to notify listeners of the change */
- if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
- ((ret == 0) || (ret == -EIWCOMMIT)))
- wireless_send_event(dev, cmd, &(iwr->u), NULL);
- } else {
- ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr,
- handler, dev, info);
- }
-
- /* Call commit handler if needed and defined */
- if (ret == -EIWCOMMIT)
- ret = call_commit_handler(dev);
-
- /* Here, we will generate the appropriate event if needed */
-
- return ret;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Wrapper to call a private Wireless Extension handler.
- * We do various checks and also take care of moving data between
- * user space and kernel space.
- * It's not as nice and slimline as the standard wrapper. The cause
- * is struct iw_priv_args, which was not really designed for the
- * job we are going here.
+ * Call the commit handler in the driver
+ * (if exist and if conditions are right)
+ *
+ * Note : our current commit strategy is currently pretty dumb,
+ * but we will be able to improve on that...
+ * The goal is to try to agreagate as many changes as possible
+ * before doing the commit. Drivers that will define a commit handler
+ * are usually those that need a reset after changing parameters, so
+ * we want to minimise the number of reset.
+ * A cool idea is to use a timer : at each "set" command, we re-set the
+ * timer, when the timer eventually fires, we call the driver.
+ * Hopefully, more on that later.
*
- * IMPORTANT : This function prevent to set and get data on the same
- * IOCTL and enforce the SET/GET convention. Not doing it would be
- * far too hairy...
- * If you need to set and get data at the same time, please don't use
- * a iw_handler but process it in your ioctl handler (i.e. use the
- * old driver API).
+ * Also, I'm waiting to see how many people will complain about the
+ * netif_running(dev) test. I'm open on that one...
+ * Hopefully, the driver will remember to do a commit in "open()" ;-)
*/
-static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd,
- const struct iw_priv_args **descrp)
-{
- const struct iw_priv_args *descr;
- int i, extra_size;
-
- descr = NULL;
- for (i = 0; i < dev->wireless_handlers->num_private_args; i++) {
- if (cmd == dev->wireless_handlers->private_args[i].cmd) {
- descr = &dev->wireless_handlers->private_args[i];
- break;
- }
- }
-
- extra_size = 0;
- if (descr) {
- if (IW_IS_SET(cmd)) {
- int offset = 0; /* For sub-ioctls */
- /* Check for sub-ioctl handler */
- if (descr->name[0] == '\0')
- /* Reserve one int for sub-ioctl index */
- offset = sizeof(__u32);
-
- /* Size of set arguments */
- extra_size = get_priv_size(descr->set_args);
-
- /* Does it fits in iwr ? */
- if ((descr->set_args & IW_PRIV_SIZE_FIXED) &&
- ((extra_size + offset) <= IFNAMSIZ))
- extra_size = 0;
- } else {
- /* Size of get arguments */
- extra_size = get_priv_size(descr->get_args);
-
- /* Does it fits in iwr ? */
- if ((descr->get_args & IW_PRIV_SIZE_FIXED) &&
- (extra_size <= IFNAMSIZ))
- extra_size = 0;
- }
- }
- *descrp = descr;
- return extra_size;
-}
-
-static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd,
- const struct iw_priv_args *descr,
- iw_handler handler, struct net_device *dev,
- struct iw_request_info *info, int extra_size)
-{
- char *extra;
- int err;
-
- /* Check what user space is giving us */
- if (IW_IS_SET(cmd)) {
- if (!iwp->pointer && iwp->length != 0)
- return -EFAULT;
-
- if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK))
- return -E2BIG;
- } else if (!iwp->pointer)
- return -EFAULT;
-
- extra = kmalloc(extra_size, GFP_KERNEL);
- if (!extra)
- return -ENOMEM;
-
- /* If it is a SET, get all the extra data in here */
- if (IW_IS_SET(cmd) && (iwp->length != 0)) {
- if (copy_from_user(extra, iwp->pointer, extra_size)) {
- err = -EFAULT;
- goto out;
- }
- }
-
- /* Call the handler */
- err = handler(dev, info, (union iwreq_data *) iwp, extra);
-
- /* If we have something to return to the user */
- if (!err && IW_IS_GET(cmd)) {
- /* Adjust for the actual length if it's variable,
- * avoid leaking kernel bits outside.
- */
- if (!(descr->get_args & IW_PRIV_SIZE_FIXED))
- extra_size = adjust_priv_size(descr->get_args, iwp);
-
- if (copy_to_user(iwp->pointer, extra, extra_size))
- err = -EFAULT;
- }
-
-out:
- kfree(extra);
- return err;
-}
-
-static int ioctl_private_call(struct net_device *dev, struct iwreq *iwr,
- unsigned int cmd, struct iw_request_info *info,
- iw_handler handler)
+int call_commit_handler(struct net_device *dev)
{
- int extra_size = 0, ret = -EINVAL;
- const struct iw_priv_args *descr;
-
- extra_size = get_priv_descr_and_size(dev, cmd, &descr);
-
- /* Check if we have a pointer to user space data or not. */
- if (extra_size == 0) {
- /* No extra arguments. Trivial to handle */
- ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
- } else {
- ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr,
- handler, dev, info, extra_size);
- }
-
- /* Call commit handler if needed and defined */
- if (ret == -EIWCOMMIT)
- ret = call_commit_handler(dev);
-
- return ret;
+#ifdef CONFIG_WIRELESS_EXT
+ if ((netif_running(dev)) &&
+ (dev->wireless_handlers->standard[0] != NULL))
+ /* Call the commit handler on the driver */
+ return dev->wireless_handlers->standard[0](dev, NULL,
+ NULL, NULL);
+ else
+ return 0; /* Command completed successfully */
+#else
+ /* cfg80211 has no commit */
+ return 0;
+#endif
}
-/* ---------------------------------------------------------------- */
-typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *,
- unsigned int, struct iw_request_info *,
- iw_handler);
-
/*
* Main IOCTl dispatcher.
* Check the type of IOCTL and call the appropriate wrapper...
@@ -1103,9 +881,11 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
return standard(dev, iwr, cmd, info,
&iw_handler_get_iwstats);
+#ifdef CONFIG_WEXT_PRIV
if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
return standard(dev, iwr, cmd, info,
- &iw_handler_get_private);
+ iw_handler_get_private);
+#endif
/* Basic check */
if (!netif_device_present(dev))
@@ -1117,7 +897,7 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
/* Standard and private are not the same */
if (cmd < SIOCIWFIRSTPRIV)
return standard(dev, iwr, cmd, info, handler);
- else
+ else if (private)
return private(dev, iwr, cmd, info, handler);
}
/* Old driver API : call driver ioctl handler */
@@ -1157,6 +937,50 @@ static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
return ret;
}
+/*
+ * Wrapper to call a standard Wireless Extension handler.
+ * We do various checks and also take care of moving data between
+ * user space and kernel space.
+ */
+static int ioctl_standard_call(struct net_device * dev,
+ struct iwreq *iwr,
+ unsigned int cmd,
+ struct iw_request_info *info,
+ iw_handler handler)
+{
+ const struct iw_ioctl_description * descr;
+ int ret = -EINVAL;
+
+ /* Get the description of the IOCTL */
+ if ((cmd - SIOCIWFIRST) >= standard_ioctl_num)
+ return -EOPNOTSUPP;
+ descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
+
+ /* Check if we have a pointer to user space data or not */
+ if (descr->header_type != IW_HEADER_TYPE_POINT) {
+
+ /* No extra arguments. Trivial to handle */
+ ret = handler(dev, info, &(iwr->u), NULL);
+
+ /* Generate an event to notify listeners of the change */
+ if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
+ ((ret == 0) || (ret == -EIWCOMMIT)))
+ wireless_send_event(dev, cmd, &(iwr->u), NULL);
+ } else {
+ ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr,
+ handler, dev, info);
+ }
+
+ /* Call commit handler if needed and defined */
+ if (ret == -EIWCOMMIT)
+ ret = call_commit_handler(dev);
+
+ /* Here, we will generate the appropriate event if needed */
+
+ return ret;
+}
+
+
int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
void __user *arg)
{
@@ -1205,43 +1029,6 @@ static int compat_standard_call(struct net_device *dev,
return err;
}
-static int compat_private_call(struct net_device *dev, struct iwreq *iwr,
- unsigned int cmd, struct iw_request_info *info,
- iw_handler handler)
-{
- const struct iw_priv_args *descr;
- int ret, extra_size;
-
- extra_size = get_priv_descr_and_size(dev, cmd, &descr);
-
- /* Check if we have a pointer to user space data or not. */
- if (extra_size == 0) {
- /* No extra arguments. Trivial to handle */
- ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
- } else {
- struct compat_iw_point *iwp_compat;
- struct iw_point iwp;
-
- iwp_compat = (struct compat_iw_point *) &iwr->u.data;
- iwp.pointer = compat_ptr(iwp_compat->pointer);
- iwp.length = iwp_compat->length;
- iwp.flags = iwp_compat->flags;
-
- ret = ioctl_private_iw_point(&iwp, cmd, descr,
- handler, dev, info, extra_size);
-
- iwp_compat->pointer = ptr_to_compat(iwp.pointer);
- iwp_compat->length = iwp.length;
- iwp_compat->flags = iwp.flags;
- }
-
- /* Call commit handler if needed and defined */
- if (ret == -EIWCOMMIT)
- ret = call_commit_handler(dev);
-
- return ret;
-}
-
int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
unsigned long arg)
{
@@ -1274,502 +1061,3 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
return ret;
}
#endif
-
-static int __net_init wext_pernet_init(struct net *net)
-{
- skb_queue_head_init(&net->wext_nlevents);
- return 0;
-}
-
-static void __net_exit wext_pernet_exit(struct net *net)
-{
- skb_queue_purge(&net->wext_nlevents);
-}
-
-static struct pernet_operations wext_pernet_ops = {
- .init = wext_pernet_init,
- .exit = wext_pernet_exit,
-};
-
-static int __init wireless_nlevent_init(void)
-{
- return register_pernet_subsys(&wext_pernet_ops);
-}
-
-subsys_initcall(wireless_nlevent_init);
-
-/* Process events generated by the wireless layer or the driver. */
-static void wireless_nlevent_process(struct work_struct *work)
-{
- struct sk_buff *skb;
- struct net *net;
-
- rtnl_lock();
-
- for_each_net(net) {
- while ((skb = skb_dequeue(&net->wext_nlevents)))
- rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL,
- GFP_KERNEL);
- }
-
- rtnl_unlock();
-}
-
-static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process);
-
-static struct nlmsghdr *rtnetlink_ifinfo_prep(struct net_device *dev,
- struct sk_buff *skb)
-{
- struct ifinfomsg *r;
- struct nlmsghdr *nlh;
-
- nlh = nlmsg_put(skb, 0, 0, RTM_NEWLINK, sizeof(*r), 0);
- if (!nlh)
- return NULL;
-
- r = nlmsg_data(nlh);
- r->ifi_family = AF_UNSPEC;
- r->__ifi_pad = 0;
- r->ifi_type = dev->type;
- r->ifi_index = dev->ifindex;
- r->ifi_flags = dev_get_flags(dev);
- r->ifi_change = 0; /* Wireless changes don't affect those flags */
-
- NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
-
- return nlh;
- nla_put_failure:
- nlmsg_cancel(skb, nlh);
- return NULL;
-}
-
-
-/*
- * Main event dispatcher. Called from other parts and drivers.
- * Send the event on the appropriate channels.
- * May be called from interrupt context.
- */
-void wireless_send_event(struct net_device * dev,
- unsigned int cmd,
- union iwreq_data * wrqu,
- const char * extra)
-{
- const struct iw_ioctl_description * descr = NULL;
- int extra_len = 0;
- struct iw_event *event; /* Mallocated whole event */
- int event_len; /* Its size */
- int hdr_len; /* Size of the event header */
- int wrqu_off = 0; /* Offset in wrqu */
- /* Don't "optimise" the following variable, it will crash */
- unsigned cmd_index; /* *MUST* be unsigned */
- struct sk_buff *skb;
- struct nlmsghdr *nlh;
- struct nlattr *nla;
-#ifdef CONFIG_COMPAT
- struct __compat_iw_event *compat_event;
- struct compat_iw_point compat_wrqu;
- struct sk_buff *compskb;
-#endif
-
- /*
- * Nothing in the kernel sends scan events with data, be safe.
- * This is necessary because we cannot fix up scan event data
- * for compat, due to being contained in 'extra', but normally
- * applications are required to retrieve the scan data anyway
- * and no data is included in the event, this codifies that
- * practice.
- */
- if (WARN_ON(cmd == SIOCGIWSCAN && extra))
- extra = NULL;
-
- /* Get the description of the Event */
- if (cmd <= SIOCIWLAST) {
- cmd_index = cmd - SIOCIWFIRST;
- if (cmd_index < standard_ioctl_num)
- descr = &(standard_ioctl[cmd_index]);
- } else {
- cmd_index = cmd - IWEVFIRST;
- if (cmd_index < standard_event_num)
- descr = &(standard_event[cmd_index]);
- }
- /* Don't accept unknown events */
- if (descr == NULL) {
- /* Note : we don't return an error to the driver, because
- * the driver would not know what to do about it. It can't
- * return an error to the user, because the event is not
- * initiated by a user request.
- * The best the driver could do is to log an error message.
- * We will do it ourselves instead...
- */
- printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
- dev->name, cmd);
- return;
- }
-
- /* Check extra parameters and set extra_len */
- if (descr->header_type == IW_HEADER_TYPE_POINT) {
- /* Check if number of token fits within bounds */
- if (wrqu->data.length > descr->max_tokens) {
- printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
- return;
- }
- if (wrqu->data.length < descr->min_tokens) {
- printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
- return;
- }
- /* Calculate extra_len - extra is NULL for restricted events */
- if (extra != NULL)
- extra_len = wrqu->data.length * descr->token_size;
- /* Always at an offset in wrqu */
- wrqu_off = IW_EV_POINT_OFF;
- }
-
- /* Total length of the event */
- hdr_len = event_type_size[descr->header_type];
- event_len = hdr_len + extra_len;
-
- /*
- * The problem for 64/32 bit.
- *
- * On 64-bit, a regular event is laid out as follows:
- * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
- * | event.len | event.cmd | p a d d i n g |
- * | wrqu data ... (with the correct size) |
- *
- * This padding exists because we manipulate event->u,
- * and 'event' is not packed.
- *
- * An iw_point event is laid out like this instead:
- * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
- * | event.len | event.cmd | p a d d i n g |
- * | iwpnt.len | iwpnt.flg | p a d d i n g |
- * | extra data ...
- *
- * The second padding exists because struct iw_point is extended,
- * but this depends on the platform...
- *
- * On 32-bit, all the padding shouldn't be there.
- */
-
- skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
- if (!skb)
- return;
-
- /* Send via the RtNetlink event channel */
- nlh = rtnetlink_ifinfo_prep(dev, skb);
- if (WARN_ON(!nlh)) {
- kfree_skb(skb);
- return;
- }
-
- /* Add the wireless events in the netlink packet */
- nla = nla_reserve(skb, IFLA_WIRELESS, event_len);
- if (!nla) {
- kfree_skb(skb);
- return;
- }
- event = nla_data(nla);
-
- /* Fill event - first clear to avoid data leaking */
- memset(event, 0, hdr_len);
- event->len = event_len;
- event->cmd = cmd;
- memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN);
- if (extra_len)
- memcpy(((char *) event) + hdr_len, extra, extra_len);
-
- nlmsg_end(skb, nlh);
-#ifdef CONFIG_COMPAT
- hdr_len = compat_event_type_size[descr->header_type];
- event_len = hdr_len + extra_len;
-
- compskb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
- if (!compskb) {
- kfree_skb(skb);
- return;
- }
-
- /* Send via the RtNetlink event channel */
- nlh = rtnetlink_ifinfo_prep(dev, compskb);
- if (WARN_ON(!nlh)) {
- kfree_skb(skb);
- kfree_skb(compskb);
- return;
- }
-
- /* Add the wireless events in the netlink packet */
- nla = nla_reserve(compskb, IFLA_WIRELESS, event_len);
- if (!nla) {
- kfree_skb(skb);
- kfree_skb(compskb);
- return;
- }
- compat_event = nla_data(nla);
-
- compat_event->len = event_len;
- compat_event->cmd = cmd;
- if (descr->header_type == IW_HEADER_TYPE_POINT) {
- compat_wrqu.length = wrqu->data.length;
- compat_wrqu.flags = wrqu->data.flags;
- memcpy(&compat_event->pointer,
- ((char *) &compat_wrqu) + IW_EV_COMPAT_POINT_OFF,
- hdr_len - IW_EV_COMPAT_LCP_LEN);
- if (extra_len)
- memcpy(((char *) compat_event) + hdr_len,
- extra, extra_len);
- } else {
- /* extra_len must be zero, so no if (extra) needed */
- memcpy(&compat_event->pointer, wrqu,
- hdr_len - IW_EV_COMPAT_LCP_LEN);
- }
-
- nlmsg_end(compskb, nlh);
-
- skb_shinfo(skb)->frag_list = compskb;
-#endif
- skb_queue_tail(&dev_net(dev)->wext_nlevents, skb);
- schedule_work(&wireless_nlevent_work);
-}
-EXPORT_SYMBOL(wireless_send_event);
-
-/********************** ENHANCED IWSPY SUPPORT **********************/
-/*
- * In the old days, the driver was handling spy support all by itself.
- * Now, the driver can delegate this task to Wireless Extensions.
- * It needs to use those standard spy iw_handler in struct iw_handler_def,
- * push data to us via wireless_spy_update() and include struct iw_spy_data
- * in its private part (and export it in net_device->wireless_data->spy_data).
- * One of the main advantage of centralising spy support here is that
- * it becomes much easier to improve and extend it without having to touch
- * the drivers. One example is the addition of the Spy-Threshold events.
- */
-
-/* ---------------------------------------------------------------- */
-/*
- * Return the pointer to the spy data in the driver.
- * Because this is called on the Rx path via wireless_spy_update(),
- * we want it to be efficient...
- */
-static inline struct iw_spy_data *get_spydata(struct net_device *dev)
-{
- /* This is the new way */
- if (dev->wireless_data)
- return dev->wireless_data->spy_data;
- return NULL;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Standard Wireless Handler : set Spy List
- */
-int iw_handler_set_spy(struct net_device * dev,
- struct iw_request_info * info,
- union iwreq_data * wrqu,
- char * extra)
-{
- struct iw_spy_data * spydata = get_spydata(dev);
- struct sockaddr * address = (struct sockaddr *) extra;
-
- /* Make sure driver is not buggy or using the old API */
- if (!spydata)
- return -EOPNOTSUPP;
-
- /* Disable spy collection while we copy the addresses.
- * While we copy addresses, any call to wireless_spy_update()
- * will NOP. This is OK, as anyway the addresses are changing. */
- spydata->spy_number = 0;
-
- /* We want to operate without locking, because wireless_spy_update()
- * most likely will happen in the interrupt handler, and therefore
- * have its own locking constraints and needs performance.
- * The rtnl_lock() make sure we don't race with the other iw_handlers.
- * This make sure wireless_spy_update() "see" that the spy list
- * is temporarily disabled. */
- smp_wmb();
-
- /* Are there are addresses to copy? */
- if (wrqu->data.length > 0) {
- int i;
-
- /* Copy addresses */
- for (i = 0; i < wrqu->data.length; i++)
- memcpy(spydata->spy_address[i], address[i].sa_data,
- ETH_ALEN);
- /* Reset stats */
- memset(spydata->spy_stat, 0,
- sizeof(struct iw_quality) * IW_MAX_SPY);
- }
-
- /* Make sure above is updated before re-enabling */
- smp_wmb();
-
- /* Enable addresses */
- spydata->spy_number = wrqu->data.length;
-
- return 0;
-}
-EXPORT_SYMBOL(iw_handler_set_spy);
-
-/*------------------------------------------------------------------*/
-/*
- * Standard Wireless Handler : get Spy List
- */
-int iw_handler_get_spy(struct net_device * dev,
- struct iw_request_info * info,
- union iwreq_data * wrqu,
- char * extra)
-{
- struct iw_spy_data * spydata = get_spydata(dev);
- struct sockaddr * address = (struct sockaddr *) extra;
- int i;
-
- /* Make sure driver is not buggy or using the old API */
- if (!spydata)
- return -EOPNOTSUPP;
-
- wrqu->data.length = spydata->spy_number;
-
- /* Copy addresses. */
- for (i = 0; i < spydata->spy_number; i++) {
- memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
- address[i].sa_family = AF_UNIX;
- }
- /* Copy stats to the user buffer (just after). */
- if (spydata->spy_number > 0)
- memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number),
- spydata->spy_stat,
- sizeof(struct iw_quality) * spydata->spy_number);
- /* Reset updated flags. */
- for (i = 0; i < spydata->spy_number; i++)
- spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
- return 0;
-}
-EXPORT_SYMBOL(iw_handler_get_spy);
-
-/*------------------------------------------------------------------*/
-/*
- * Standard Wireless Handler : set spy threshold
- */
-int iw_handler_set_thrspy(struct net_device * dev,
- struct iw_request_info *info,
- union iwreq_data * wrqu,
- char * extra)
-{
- struct iw_spy_data * spydata = get_spydata(dev);
- struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
-
- /* Make sure driver is not buggy or using the old API */
- if (!spydata)
- return -EOPNOTSUPP;
-
- /* Just do it */
- memcpy(&(spydata->spy_thr_low), &(threshold->low),
- 2 * sizeof(struct iw_quality));
-
- /* Clear flag */
- memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
-
- return 0;
-}
-EXPORT_SYMBOL(iw_handler_set_thrspy);
-
-/*------------------------------------------------------------------*/
-/*
- * Standard Wireless Handler : get spy threshold
- */
-int iw_handler_get_thrspy(struct net_device * dev,
- struct iw_request_info *info,
- union iwreq_data * wrqu,
- char * extra)
-{
- struct iw_spy_data * spydata = get_spydata(dev);
- struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
-
- /* Make sure driver is not buggy or using the old API */
- if (!spydata)
- return -EOPNOTSUPP;
-
- /* Just do it */
- memcpy(&(threshold->low), &(spydata->spy_thr_low),
- 2 * sizeof(struct iw_quality));
-
- return 0;
-}
-EXPORT_SYMBOL(iw_handler_get_thrspy);
-
-/*------------------------------------------------------------------*/
-/*
- * Prepare and send a Spy Threshold event
- */
-static void iw_send_thrspy_event(struct net_device * dev,
- struct iw_spy_data * spydata,
- unsigned char * address,
- struct iw_quality * wstats)
-{
- union iwreq_data wrqu;
- struct iw_thrspy threshold;
-
- /* Init */
- wrqu.data.length = 1;
- wrqu.data.flags = 0;
- /* Copy address */
- memcpy(threshold.addr.sa_data, address, ETH_ALEN);
- threshold.addr.sa_family = ARPHRD_ETHER;
- /* Copy stats */
- memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
- /* Copy also thresholds */
- memcpy(&(threshold.low), &(spydata->spy_thr_low),
- 2 * sizeof(struct iw_quality));
-
- /* Send event to user space */
- wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Call for the driver to update the spy data.
- * For now, the spy data is a simple array. As the size of the array is
- * small, this is good enough. If we wanted to support larger number of
- * spy addresses, we should use something more efficient...
- */
-void wireless_spy_update(struct net_device * dev,
- unsigned char * address,
- struct iw_quality * wstats)
-{
- struct iw_spy_data * spydata = get_spydata(dev);
- int i;
- int match = -1;
-
- /* Make sure driver is not buggy or using the old API */
- if (!spydata)
- return;
-
- /* Update all records that match */
- for (i = 0; i < spydata->spy_number; i++)
- if (!compare_ether_addr(address, spydata->spy_address[i])) {
- memcpy(&(spydata->spy_stat[i]), wstats,
- sizeof(struct iw_quality));
- match = i;
- }
-
- /* Generate an event if we cross the spy threshold.
- * To avoid event storms, we have a simple hysteresis : we generate
- * event only when we go under the low threshold or above the
- * high threshold. */
- if (match >= 0) {
- if (spydata->spy_thr_under[match]) {
- if (wstats->level > spydata->spy_thr_high.level) {
- spydata->spy_thr_under[match] = 0;
- iw_send_thrspy_event(dev, spydata,
- address, wstats);
- }
- } else {
- if (wstats->level < spydata->spy_thr_low.level) {
- spydata->spy_thr_under[match] = 1;
- iw_send_thrspy_event(dev, spydata,
- address, wstats);
- }
- }
- }
-}
-EXPORT_SYMBOL(wireless_spy_update);
diff --git a/net/wireless/wext-priv.c b/net/wireless/wext-priv.c
new file mode 100644
index 000000000000..a3c2277de9e5
--- /dev/null
+++ b/net/wireless/wext-priv.c
@@ -0,0 +1,248 @@
+/*
+ * This file implement the Wireless Extensions priv API.
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
+ * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * (As all part of the Linux kernel, this file is GPL)
+ */
+#include <linux/wireless.h>
+#include <linux/netdevice.h>
+#include <net/iw_handler.h>
+#include <net/wext.h>
+
+int iw_handler_get_private(struct net_device * dev,
+ struct iw_request_info * info,
+ union iwreq_data * wrqu,
+ char * extra)
+{
+ /* Check if the driver has something to export */
+ if ((dev->wireless_handlers->num_private_args == 0) ||
+ (dev->wireless_handlers->private_args == NULL))
+ return -EOPNOTSUPP;
+
+ /* Check if there is enough buffer up there */
+ if (wrqu->data.length < dev->wireless_handlers->num_private_args) {
+ /* User space can't know in advance how large the buffer
+ * needs to be. Give it a hint, so that we can support
+ * any size buffer we want somewhat efficiently... */
+ wrqu->data.length = dev->wireless_handlers->num_private_args;
+ return -E2BIG;
+ }
+
+ /* Set the number of available ioctls. */
+ wrqu->data.length = dev->wireless_handlers->num_private_args;
+
+ /* Copy structure to the user buffer. */
+ memcpy(extra, dev->wireless_handlers->private_args,
+ sizeof(struct iw_priv_args) * wrqu->data.length);
+
+ return 0;
+}
+
+/* Size (in bytes) of the various private data types */
+static const char iw_priv_type_size[] = {
+ 0, /* IW_PRIV_TYPE_NONE */
+ 1, /* IW_PRIV_TYPE_BYTE */
+ 1, /* IW_PRIV_TYPE_CHAR */
+ 0, /* Not defined */
+ sizeof(__u32), /* IW_PRIV_TYPE_INT */
+ sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */
+ sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */
+ 0, /* Not defined */
+};
+
+static int get_priv_size(__u16 args)
+{
+ int num = args & IW_PRIV_SIZE_MASK;
+ int type = (args & IW_PRIV_TYPE_MASK) >> 12;
+
+ return num * iw_priv_type_size[type];
+}
+
+static int adjust_priv_size(__u16 args, struct iw_point *iwp)
+{
+ int num = iwp->length;
+ int max = args & IW_PRIV_SIZE_MASK;
+ int type = (args & IW_PRIV_TYPE_MASK) >> 12;
+
+ /* Make sure the driver doesn't goof up */
+ if (max < num)
+ num = max;
+
+ return num * iw_priv_type_size[type];
+}
+
+/*
+ * Wrapper to call a private Wireless Extension handler.
+ * We do various checks and also take care of moving data between
+ * user space and kernel space.
+ * It's not as nice and slimline as the standard wrapper. The cause
+ * is struct iw_priv_args, which was not really designed for the
+ * job we are going here.
+ *
+ * IMPORTANT : This function prevent to set and get data on the same
+ * IOCTL and enforce the SET/GET convention. Not doing it would be
+ * far too hairy...
+ * If you need to set and get data at the same time, please don't use
+ * a iw_handler but process it in your ioctl handler (i.e. use the
+ * old driver API).
+ */
+static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd,
+ const struct iw_priv_args **descrp)
+{
+ const struct iw_priv_args *descr;
+ int i, extra_size;
+
+ descr = NULL;
+ for (i = 0; i < dev->wireless_handlers->num_private_args; i++) {
+ if (cmd == dev->wireless_handlers->private_args[i].cmd) {
+ descr = &dev->wireless_handlers->private_args[i];
+ break;
+ }
+ }
+
+ extra_size = 0;
+ if (descr) {
+ if (IW_IS_SET(cmd)) {
+ int offset = 0; /* For sub-ioctls */
+ /* Check for sub-ioctl handler */
+ if (descr->name[0] == '\0')
+ /* Reserve one int for sub-ioctl index */
+ offset = sizeof(__u32);
+
+ /* Size of set arguments */
+ extra_size = get_priv_size(descr->set_args);
+
+ /* Does it fits in iwr ? */
+ if ((descr->set_args & IW_PRIV_SIZE_FIXED) &&
+ ((extra_size + offset) <= IFNAMSIZ))
+ extra_size = 0;
+ } else {
+ /* Size of get arguments */
+ extra_size = get_priv_size(descr->get_args);
+
+ /* Does it fits in iwr ? */
+ if ((descr->get_args & IW_PRIV_SIZE_FIXED) &&
+ (extra_size <= IFNAMSIZ))
+ extra_size = 0;
+ }
+ }
+ *descrp = descr;
+ return extra_size;
+}
+
+static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd,
+ const struct iw_priv_args *descr,
+ iw_handler handler, struct net_device *dev,
+ struct iw_request_info *info, int extra_size)
+{
+ char *extra;
+ int err;
+
+ /* Check what user space is giving us */
+ if (IW_IS_SET(cmd)) {
+ if (!iwp->pointer && iwp->length != 0)
+ return -EFAULT;
+
+ if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK))
+ return -E2BIG;
+ } else if (!iwp->pointer)
+ return -EFAULT;
+
+ extra = kmalloc(extra_size, GFP_KERNEL);
+ if (!extra)
+ return -ENOMEM;
+
+ /* If it is a SET, get all the extra data in here */
+ if (IW_IS_SET(cmd) && (iwp->length != 0)) {
+ if (copy_from_user(extra, iwp->pointer, extra_size)) {
+ err = -EFAULT;
+ goto out;
+ }
+ }
+
+ /* Call the handler */
+ err = handler(dev, info, (union iwreq_data *) iwp, extra);
+
+ /* If we have something to return to the user */
+ if (!err && IW_IS_GET(cmd)) {
+ /* Adjust for the actual length if it's variable,
+ * avoid leaking kernel bits outside.
+ */
+ if (!(descr->get_args & IW_PRIV_SIZE_FIXED))
+ extra_size = adjust_priv_size(descr->get_args, iwp);
+
+ if (copy_to_user(iwp->pointer, extra, extra_size))
+ err = -EFAULT;
+ }
+
+out:
+ kfree(extra);
+ return err;
+}
+
+int ioctl_private_call(struct net_device *dev, struct iwreq *iwr,
+ unsigned int cmd, struct iw_request_info *info,
+ iw_handler handler)
+{
+ int extra_size = 0, ret = -EINVAL;
+ const struct iw_priv_args *descr;
+
+ extra_size = get_priv_descr_and_size(dev, cmd, &descr);
+
+ /* Check if we have a pointer to user space data or not. */
+ if (extra_size == 0) {
+ /* No extra arguments. Trivial to handle */
+ ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
+ } else {
+ ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr,
+ handler, dev, info, extra_size);
+ }
+
+ /* Call commit handler if needed and defined */
+ if (ret == -EIWCOMMIT)
+ ret = call_commit_handler(dev);
+
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+int compat_private_call(struct net_device *dev, struct iwreq *iwr,
+ unsigned int cmd, struct iw_request_info *info,
+ iw_handler handler)
+{
+ const struct iw_priv_args *descr;
+ int ret, extra_size;
+
+ extra_size = get_priv_descr_and_size(dev, cmd, &descr);
+
+ /* Check if we have a pointer to user space data or not. */
+ if (extra_size == 0) {
+ /* No extra arguments. Trivial to handle */
+ ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
+ } else {
+ struct compat_iw_point *iwp_compat;
+ struct iw_point iwp;
+
+ iwp_compat = (struct compat_iw_point *) &iwr->u.data;
+ iwp.pointer = compat_ptr(iwp_compat->pointer);
+ iwp.length = iwp_compat->length;
+ iwp.flags = iwp_compat->flags;
+
+ ret = ioctl_private_iw_point(&iwp, cmd, descr,
+ handler, dev, info, extra_size);
+
+ iwp_compat->pointer = ptr_to_compat(iwp.pointer);
+ iwp_compat->length = iwp.length;
+ iwp_compat->flags = iwp.flags;
+ }
+
+ /* Call commit handler if needed and defined */
+ if (ret == -EIWCOMMIT)
+ ret = call_commit_handler(dev);
+
+ return ret;
+}
+#endif
diff --git a/net/wireless/wext-proc.c b/net/wireless/wext-proc.c
new file mode 100644
index 000000000000..273a7f77c834
--- /dev/null
+++ b/net/wireless/wext-proc.c
@@ -0,0 +1,155 @@
+/*
+ * This file implement the Wireless Extensions proc API.
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
+ *
+ * (As all part of the Linux kernel, this file is GPL)
+ */
+
+/*
+ * The /proc/net/wireless file is a human readable user-space interface
+ * exporting various wireless specific statistics from the wireless devices.
+ * This is the most popular part of the Wireless Extensions ;-)
+ *
+ * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
+ * The content of the file is basically the content of "struct iw_statistics".
+ */
+
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/wireless.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <net/iw_handler.h>
+#include <net/wext.h>
+
+
+static void wireless_seq_printf_stats(struct seq_file *seq,
+ struct net_device *dev)
+{
+ /* Get stats from the driver */
+ struct iw_statistics *stats = get_wireless_stats(dev);
+ static struct iw_statistics nullstats = {};
+
+ /* show device if it's wireless regardless of current stats */
+ if (!stats) {
+#ifdef CONFIG_WIRELESS_EXT
+ if (dev->wireless_handlers)
+ stats = &nullstats;
+#endif
+#ifdef CONFIG_CFG80211
+ if (dev->ieee80211_ptr)
+ stats = &nullstats;
+#endif
+ }
+
+ if (stats) {
+ seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d "
+ "%6d %6d %6d\n",
+ dev->name, stats->status, stats->qual.qual,
+ stats->qual.updated & IW_QUAL_QUAL_UPDATED
+ ? '.' : ' ',
+ ((__s32) stats->qual.level) -
+ ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
+ stats->qual.updated & IW_QUAL_LEVEL_UPDATED
+ ? '.' : ' ',
+ ((__s32) stats->qual.noise) -
+ ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
+ stats->qual.updated & IW_QUAL_NOISE_UPDATED
+ ? '.' : ' ',
+ stats->discard.nwid, stats->discard.code,
+ stats->discard.fragment, stats->discard.retries,
+ stats->discard.misc, stats->miss.beacon);
+
+ if (stats != &nullstats)
+ stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
+ }
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Print info for /proc/net/wireless (print all entries)
+ */
+static int wireless_dev_seq_show(struct seq_file *seq, void *v)
+{
+ might_sleep();
+
+ if (v == SEQ_START_TOKEN)
+ seq_printf(seq, "Inter-| sta-| Quality | Discarded "
+ "packets | Missed | WE\n"
+ " face | tus | link level noise | nwid "
+ "crypt frag retry misc | beacon | %d\n",
+ WIRELESS_EXT);
+ else
+ wireless_seq_printf_stats(seq, v);
+ return 0;
+}
+
+static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ struct net *net = seq_file_net(seq);
+ loff_t off;
+ struct net_device *dev;
+
+ rtnl_lock();
+ if (!*pos)
+ return SEQ_START_TOKEN;
+
+ off = 1;
+ for_each_netdev(net, dev)
+ if (off++ == *pos)
+ return dev;
+ return NULL;
+}
+
+static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct net *net = seq_file_net(seq);
+
+ ++*pos;
+
+ return v == SEQ_START_TOKEN ?
+ first_net_device(net) : next_net_device(v);
+}
+
+static void wireless_dev_seq_stop(struct seq_file *seq, void *v)
+{
+ rtnl_unlock();
+}
+
+static const struct seq_operations wireless_seq_ops = {
+ .start = wireless_dev_seq_start,
+ .next = wireless_dev_seq_next,
+ .stop = wireless_dev_seq_stop,
+ .show = wireless_dev_seq_show,
+};
+
+static int seq_open_wireless(struct inode *inode, struct file *file)
+{
+ return seq_open_net(inode, file, &wireless_seq_ops,
+ sizeof(struct seq_net_private));
+}
+
+static const struct file_operations wireless_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = seq_open_wireless,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_net,
+};
+
+int wext_proc_init(struct net *net)
+{
+ /* Create /proc/net/wireless entry */
+ if (!proc_net_fops_create(net, "wireless", S_IRUGO, &wireless_seq_fops))
+ return -ENOMEM;
+
+ return 0;
+}
+
+void wext_proc_exit(struct net *net)
+{
+ proc_net_remove(net, "wireless");
+}
diff --git a/net/wireless/wext-spy.c b/net/wireless/wext-spy.c
new file mode 100644
index 000000000000..6dcfe65a2d1a
--- /dev/null
+++ b/net/wireless/wext-spy.c
@@ -0,0 +1,231 @@
+/*
+ * This file implement the Wireless Extensions spy API.
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
+ *
+ * (As all part of the Linux kernel, this file is GPL)
+ */
+
+#include <linux/wireless.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <net/iw_handler.h>
+#include <net/arp.h>
+#include <net/wext.h>
+
+static inline struct iw_spy_data *get_spydata(struct net_device *dev)
+{
+ /* This is the new way */
+ if (dev->wireless_data)
+ return dev->wireless_data->spy_data;
+ return NULL;
+}
+
+int iw_handler_set_spy(struct net_device * dev,
+ struct iw_request_info * info,
+ union iwreq_data * wrqu,
+ char * extra)
+{
+ struct iw_spy_data * spydata = get_spydata(dev);
+ struct sockaddr * address = (struct sockaddr *) extra;
+
+ /* Make sure driver is not buggy or using the old API */
+ if (!spydata)
+ return -EOPNOTSUPP;
+
+ /* Disable spy collection while we copy the addresses.
+ * While we copy addresses, any call to wireless_spy_update()
+ * will NOP. This is OK, as anyway the addresses are changing. */
+ spydata->spy_number = 0;
+
+ /* We want to operate without locking, because wireless_spy_update()
+ * most likely will happen in the interrupt handler, and therefore
+ * have its own locking constraints and needs performance.
+ * The rtnl_lock() make sure we don't race with the other iw_handlers.
+ * This make sure wireless_spy_update() "see" that the spy list
+ * is temporarily disabled. */
+ smp_wmb();
+
+ /* Are there are addresses to copy? */
+ if (wrqu->data.length > 0) {
+ int i;
+
+ /* Copy addresses */
+ for (i = 0; i < wrqu->data.length; i++)
+ memcpy(spydata->spy_address[i], address[i].sa_data,
+ ETH_ALEN);
+ /* Reset stats */
+ memset(spydata->spy_stat, 0,
+ sizeof(struct iw_quality) * IW_MAX_SPY);
+ }
+
+ /* Make sure above is updated before re-enabling */
+ smp_wmb();
+
+ /* Enable addresses */
+ spydata->spy_number = wrqu->data.length;
+
+ return 0;
+}
+EXPORT_SYMBOL(iw_handler_set_spy);
+
+int iw_handler_get_spy(struct net_device * dev,
+ struct iw_request_info * info,
+ union iwreq_data * wrqu,
+ char * extra)
+{
+ struct iw_spy_data * spydata = get_spydata(dev);
+ struct sockaddr * address = (struct sockaddr *) extra;
+ int i;
+
+ /* Make sure driver is not buggy or using the old API */
+ if (!spydata)
+ return -EOPNOTSUPP;
+
+ wrqu->data.length = spydata->spy_number;
+
+ /* Copy addresses. */
+ for (i = 0; i < spydata->spy_number; i++) {
+ memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
+ address[i].sa_family = AF_UNIX;
+ }
+ /* Copy stats to the user buffer (just after). */
+ if (spydata->spy_number > 0)
+ memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number),
+ spydata->spy_stat,
+ sizeof(struct iw_quality) * spydata->spy_number);
+ /* Reset updated flags. */
+ for (i = 0; i < spydata->spy_number; i++)
+ spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
+ return 0;
+}
+EXPORT_SYMBOL(iw_handler_get_spy);
+
+/*------------------------------------------------------------------*/
+/*
+ * Standard Wireless Handler : set spy threshold
+ */
+int iw_handler_set_thrspy(struct net_device * dev,
+ struct iw_request_info *info,
+ union iwreq_data * wrqu,
+ char * extra)
+{
+ struct iw_spy_data * spydata = get_spydata(dev);
+ struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
+
+ /* Make sure driver is not buggy or using the old API */
+ if (!spydata)
+ return -EOPNOTSUPP;
+
+ /* Just do it */
+ memcpy(&(spydata->spy_thr_low), &(threshold->low),
+ 2 * sizeof(struct iw_quality));
+
+ /* Clear flag */
+ memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
+
+ return 0;
+}
+EXPORT_SYMBOL(iw_handler_set_thrspy);
+
+/*------------------------------------------------------------------*/
+/*
+ * Standard Wireless Handler : get spy threshold
+ */
+int iw_handler_get_thrspy(struct net_device * dev,
+ struct iw_request_info *info,
+ union iwreq_data * wrqu,
+ char * extra)
+{
+ struct iw_spy_data * spydata = get_spydata(dev);
+ struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
+
+ /* Make sure driver is not buggy or using the old API */
+ if (!spydata)
+ return -EOPNOTSUPP;
+
+ /* Just do it */
+ memcpy(&(threshold->low), &(spydata->spy_thr_low),
+ 2 * sizeof(struct iw_quality));
+
+ return 0;
+}
+EXPORT_SYMBOL(iw_handler_get_thrspy);
+
+/*------------------------------------------------------------------*/
+/*
+ * Prepare and send a Spy Threshold event
+ */
+static void iw_send_thrspy_event(struct net_device * dev,
+ struct iw_spy_data * spydata,
+ unsigned char * address,
+ struct iw_quality * wstats)
+{
+ union iwreq_data wrqu;
+ struct iw_thrspy threshold;
+
+ /* Init */
+ wrqu.data.length = 1;
+ wrqu.data.flags = 0;
+ /* Copy address */
+ memcpy(threshold.addr.sa_data, address, ETH_ALEN);
+ threshold.addr.sa_family = ARPHRD_ETHER;
+ /* Copy stats */
+ memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
+ /* Copy also thresholds */
+ memcpy(&(threshold.low), &(spydata->spy_thr_low),
+ 2 * sizeof(struct iw_quality));
+
+ /* Send event to user space */
+ wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Call for the driver to update the spy data.
+ * For now, the spy data is a simple array. As the size of the array is
+ * small, this is good enough. If we wanted to support larger number of
+ * spy addresses, we should use something more efficient...
+ */
+void wireless_spy_update(struct net_device * dev,
+ unsigned char * address,
+ struct iw_quality * wstats)
+{
+ struct iw_spy_data * spydata = get_spydata(dev);
+ int i;
+ int match = -1;
+
+ /* Make sure driver is not buggy or using the old API */
+ if (!spydata)
+ return;
+
+ /* Update all records that match */
+ for (i = 0; i < spydata->spy_number; i++)
+ if (!compare_ether_addr(address, spydata->spy_address[i])) {
+ memcpy(&(spydata->spy_stat[i]), wstats,
+ sizeof(struct iw_quality));
+ match = i;
+ }
+
+ /* Generate an event if we cross the spy threshold.
+ * To avoid event storms, we have a simple hysteresis : we generate
+ * event only when we go under the low threshold or above the
+ * high threshold. */
+ if (match >= 0) {
+ if (spydata->spy_thr_under[match]) {
+ if (wstats->level > spydata->spy_thr_high.level) {
+ spydata->spy_thr_under[match] = 0;
+ iw_send_thrspy_event(dev, spydata,
+ address, wstats);
+ }
+ } else {
+ if (wstats->level < spydata->spy_thr_low.level) {
+ spydata->spy_thr_under[match] = 1;
+ iw_send_thrspy_event(dev, spydata,
+ address, wstats);
+ }
+ }
+ }
+}
+EXPORT_SYMBOL(wireless_spy_update);
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 7fa9c7ad3d3b..e19d811788a5 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -1363,7 +1363,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
facilities.throughput > 0xDD)
break;
if (facilities.reverse &&
- (facilities.reverse | 0x81)!= 0x81)
+ (facilities.reverse & 0x81) != 0x81)
break;
x25->facilities = facilities;
rc = 0;
@@ -1476,7 +1476,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return rc;
}
-static struct net_proto_family x25_family_ops = {
+static const struct net_proto_family x25_family_ops = {
.family = AF_X25,
.create = x25_create,
.owner = THIS_MODULE,
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
index faf54c6bf96b..b39341072aa6 100644
--- a/net/xfrm/xfrm_algo.c
+++ b/net/xfrm/xfrm_algo.c
@@ -689,84 +689,6 @@ int xfrm_count_enc_supported(void)
}
EXPORT_SYMBOL_GPL(xfrm_count_enc_supported);
-/* Move to common area: it is shared with AH. */
-
-int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc,
- int offset, int len, icv_update_fn_t icv_update)
-{
- int start = skb_headlen(skb);
- int i, copy = start - offset;
- struct sk_buff *frag_iter;
- struct scatterlist sg;
- int err;
-
- /* Checksum header. */
- if (copy > 0) {
- if (copy > len)
- copy = len;
-
- sg_init_one(&sg, skb->data + offset, copy);
-
- err = icv_update(desc, &sg, copy);
- if (unlikely(err))
- return err;
-
- if ((len -= copy) == 0)
- return 0;
- offset += copy;
- }
-
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- int end;
-
- WARN_ON(start > offset + len);
-
- end = start + skb_shinfo(skb)->frags[i].size;
- if ((copy = end - offset) > 0) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-
- if (copy > len)
- copy = len;
-
- sg_init_table(&sg, 1);
- sg_set_page(&sg, frag->page, copy,
- frag->page_offset + offset-start);
-
- err = icv_update(desc, &sg, copy);
- if (unlikely(err))
- return err;
-
- if (!(len -= copy))
- return 0;
- offset += copy;
- }
- start = end;
- }
-
- skb_walk_frags(skb, frag_iter) {
- int end;
-
- WARN_ON(start > offset + len);
-
- end = start + frag_iter->len;
- if ((copy = end - offset) > 0) {
- if (copy > len)
- copy = len;
- err = skb_icv_walk(frag_iter, desc, offset-start,
- copy, icv_update);
- if (unlikely(err))
- return err;
- if ((len -= copy) == 0)
- return 0;
- offset += copy;
- }
- start = end;
- }
- BUG_ON(len);
- return 0;
-}
-EXPORT_SYMBOL_GPL(skb_icv_walk);
-
#if defined(CONFIG_INET_ESP) || defined(CONFIG_INET_ESP_MODULE) || defined(CONFIG_INET6_ESP) || defined(CONFIG_INET6_ESP_MODULE)
void *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len)
diff --git a/samples/Kconfig b/samples/Kconfig
index b92bde3c6a89..04be681a3ded 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -1,5 +1,3 @@
-# samples/Kconfig
-
menuconfig SAMPLES
bool "Sample kernel code"
help
@@ -41,4 +39,3 @@ config SAMPLE_KRETPROBES
depends on SAMPLE_KPROBES && KRETPROBES
endif # SAMPLES
-
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 52cab46ae35a..c5d5db54c009 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -6,5 +6,4 @@ kallsyms
pnmtologo
bin2c
unifdef
-binoffset
ihex2fw
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index ffdafb26f539..d9f0cb837400 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -208,7 +208,7 @@ cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -f -9 > $@) || \
# Bzip2 and LZMA do not include size in file... so we have to fake that;
# append the size as a 32-bit littleendian number as gzip does.
-size_append = /bin/echo -ne $(shell \
+size_append = printf $(shell \
dec_size=0; \
for F in $1; do \
fsize=$$(stat -c "%s" $$F); \
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
index 6bf21f83837d..ea26b23de082 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -16,15 +16,15 @@
* tells make when to remake a file.
*
* To use this list as-is however has the drawback that virtually
- * every file in the kernel includes <linux/autoconf.h>.
+ * every file in the kernel includes autoconf.h.
*
- * If the user re-runs make *config, linux/autoconf.h will be
+ * If the user re-runs make *config, autoconf.h will be
* regenerated. make notices that and will rebuild every file which
* includes autoconf.h, i.e. basically all files. This is extremely
* annoying if the user just changed CONFIG_HIS_DRIVER from n to m.
*
* So we play the same trick that "mkdep" played before. We replace
- * the dependency on linux/autoconf.h by a dependency on every config
+ * the dependency on autoconf.h by a dependency on every config
* option which is mentioned in any of the listed prequisites.
*
* kconfig populates a tree in include/config/ with an empty file
@@ -73,7 +73,7 @@
* cmd_<target> = <cmdline>
*
* and then basically copies the .<target>.d file to stdout, in the
- * process filtering out the dependency on linux/autoconf.h and adding
+ * process filtering out the dependency on autoconf.h and adding
* dependencies on include/config/my/option.h for every
* CONFIG_MY_OPTION encountered in any of the prequisites.
*
@@ -324,7 +324,7 @@ static void parse_dep_file(void *map, size_t len)
p++;
}
memcpy(s, m, p-m); s[p-m] = 0;
- if (strrcmp(s, "include/linux/autoconf.h") &&
+ if (strrcmp(s, "include/generated/autoconf.h") &&
strrcmp(s, "arch/um/include/uml-config.h") &&
strrcmp(s, ".ver")) {
printf(" %s \\\n", s);
diff --git a/scripts/binoffset.c b/scripts/binoffset.c
deleted file mode 100644
index 1a2e39b8e3e5..000000000000
--- a/scripts/binoffset.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/***************************************************************************
- * binoffset.c
- * (C) 2002 Randy Dunlap <rdunlap@xenotime.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; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-# binoffset.c:
-# - searches a (binary) file for a specified (binary) pattern
-# - returns the offset of the located pattern or ~0 if not found
-# - exits with exit status 0 normally or non-0 if pattern is not found
-# or any other error occurs.
-
-****************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-
-#define VERSION "0.1"
-#define BUF_SIZE (16 * 1024)
-#define PAT_SIZE 100
-
-char *progname;
-char *inputname;
-int inputfd;
-unsigned int bix; /* buf index */
-unsigned char patterns [PAT_SIZE] = {0}; /* byte-sized pattern array */
-int pat_len; /* actual number of pattern bytes */
-unsigned char *madr; /* mmap address */
-size_t filesize;
-int num_matches = 0;
-off_t firstloc = 0;
-
-void usage (void)
-{
- fprintf (stderr, "%s ver. %s\n", progname, VERSION);
- fprintf (stderr, "usage: %s filename pattern_bytes\n",
- progname);
- fprintf (stderr, " [prints location of pattern_bytes in file]\n");
- exit (1);
-}
-
-void get_pattern (int pat_count, char *pats [])
-{
- int ix, err, tmp;
-
-#ifdef DEBUG
- fprintf (stderr,"get_pattern: count = %d\n", pat_count);
- for (ix = 0; ix < pat_count; ix++)
- fprintf (stderr, " pat # %d: [%s]\n", ix, pats[ix]);
-#endif
-
- for (ix = 0; ix < pat_count; ix++) {
- tmp = 0;
- err = sscanf (pats[ix], "%5i", &tmp);
- if (err != 1 || tmp > 0xff) {
- fprintf (stderr, "pattern or value error in pattern # %d [%s]\n",
- ix, pats[ix]);
- usage ();
- }
- patterns [ix] = tmp;
- }
- pat_len = pat_count;
-}
-
-void search_pattern (void)
-{
- for (bix = 0; bix < filesize; bix++) {
- if (madr[bix] == patterns[0]) {
- if (memcmp (&madr[bix], patterns, pat_len) == 0) {
- if (num_matches == 0)
- firstloc = bix;
- num_matches++;
- }
- }
- }
-}
-
-#ifdef NOTDEF
-size_t get_filesize (int fd)
-{
- off_t end_off = lseek (fd, 0, SEEK_END);
- lseek (fd, 0, SEEK_SET);
- return (size_t) end_off;
-}
-#endif
-
-size_t get_filesize (int fd)
-{
- int err;
- struct stat stat;
-
- err = fstat (fd, &stat);
- fprintf (stderr, "filesize: %ld\n", err < 0 ? (long)err : stat.st_size);
- if (err < 0)
- return err;
- return (size_t) stat.st_size;
-}
-
-int main (int argc, char *argv [])
-{
- progname = argv[0];
-
- if (argc < 3)
- usage ();
-
- get_pattern (argc - 2, argv + 2);
-
- inputname = argv[1];
-
- inputfd = open (inputname, O_RDONLY);
- if (inputfd == -1) {
- fprintf (stderr, "%s: cannot open '%s'\n",
- progname, inputname);
- exit (3);
- }
-
- filesize = get_filesize (inputfd);
-
- madr = mmap (0, filesize, PROT_READ, MAP_PRIVATE, inputfd, 0);
- if (madr == MAP_FAILED) {
- fprintf (stderr, "mmap error = %d\n", errno);
- close (inputfd);
- exit (4);
- }
-
- search_pattern ();
-
- if (munmap (madr, filesize))
- fprintf (stderr, "munmap error = %d\n", errno);
-
- if (close (inputfd))
- fprintf (stderr, "%s: error %d closing '%s'\n",
- progname, errno, inputname);
-
- fprintf (stderr, "number of pattern matches = %d\n", num_matches);
- if (num_matches == 0)
- firstloc = ~0;
- printf ("%ld\n", firstloc);
- fprintf (stderr, "%ld\n", firstloc);
-
- exit (num_matches ? 0 : 2);
-}
-
-/* end binoffset.c */
diff --git a/scripts/extract-ikconfig b/scripts/extract-ikconfig
index de233ff43c1c..37f30d36c944 100755
--- a/scripts/extract-ikconfig
+++ b/scripts/extract-ikconfig
@@ -1,92 +1,53 @@
#!/bin/sh
-# extracts .config info from a [b]zImage file
-# uses: binoffset (new), dd, zcat, strings, grep
-# $arg1 is [b]zImage filename
-
-binoffset="./scripts/binoffset"
-test -e $binoffset || cc -o $binoffset ./scripts/binoffset.c || exit 1
-
-IKCFG_ST="0x49 0x4b 0x43 0x46 0x47 0x5f 0x53 0x54"
-IKCFG_ED="0x49 0x4b 0x43 0x46 0x47 0x5f 0x45 0x44"
-dump_config() {
- file="$1"
-
- start=`$binoffset $file $IKCFG_ST 2>/dev/null`
- [ "$?" != "0" ] && start="-1"
- if [ "$start" -eq "-1" ]; then
- return
- fi
- end=`$binoffset $file $IKCFG_ED 2>/dev/null`
- [ "$?" != "0" ] && end="-1"
- if [ "$end" -eq "-1" ]; then
- return
- fi
-
- start=`expr $start + 8`
- size=`expr $end - $start`
-
- dd if="$file" ibs=1 skip="$start" count="$size" 2>/dev/null | zcat
-
- clean_up
- exit 0
-}
-
-
-usage()
-{
- echo " usage: extract-ikconfig [b]zImage_filename"
-}
-
-clean_up()
+# ----------------------------------------------------------------------
+# extract-ikconfig - Extract the .config file from a kernel image
+#
+# This will only work when the kernel was compiled with CONFIG_IKCONFIG.
+#
+# The obscure use of the "tr" filter is to work around older versions of
+# "grep" that report the byte offset of the line instead of the pattern.
+#
+# (c) 2009, Dick Streefland <dick@streefland.net>
+# Licensed under the terms of the GNU General Public License.
+# ----------------------------------------------------------------------
+
+gz1='\037\213\010'
+gz2='01'
+cf1='IKCFG_ST\037\213\010'
+cf2='0123456789'
+
+dump_config()
{
- if [ "$TMPFILE" != "" ]; then
- rm -f $TMPFILE
+ if pos=`tr "$cf1\n$cf2" "\n$cf2=" < "$1" | grep -abo "^$cf2"`
+ then
+ pos=${pos%%:*}
+ tail -c+$(($pos+8)) "$1" | zcat -q
+ exit 0
fi
}
-if [ $# -lt 1 ]
+# Check invocation:
+me=${0##*/}
+img=$1
+if [ $# -ne 1 -o ! -s "$img" ]
then
- usage
- exit 1
+ echo "Usage: $me <kernel-image>" >&2
+ exit 2
fi
-TMPFILE=`mktemp -t ikconfig-XXXXXX` || exit 1
-image="$1"
-
-# vmlinux: Attempt to dump the configuration from the file directly
-dump_config "$image"
-
-GZHDR1="0x1f 0x8b 0x08 0x00"
-GZHDR2="0x1f 0x8b 0x08 0x08"
-
-ELFHDR="0x7f 0x45 0x4c 0x46"
-
-# vmlinux.gz: Check for a compressed images
-off=`$binoffset "$image" $GZHDR1 2>/dev/null`
-[ "$?" != "0" ] && off="-1"
-if [ "$off" -eq "-1" ]; then
- off=`$binoffset "$image" $GZHDR2 2>/dev/null`
- [ "$?" != "0" ] && off="-1"
-fi
-if [ "$off" -eq "0" ]; then
- zcat <"$image" >"$TMPFILE"
- dump_config "$TMPFILE"
-elif [ "$off" -ne "-1" ]; then
- (dd ibs="$off" skip=1 count=0 && dd bs=512k) <"$image" 2>/dev/null | \
- zcat >"$TMPFILE"
- dump_config "$TMPFILE"
-
-# check if this is simply an ELF file
-else
- off=`$binoffset "$image" $ELFHDR 2>/dev/null`
- [ "$?" != "0" ] && off="-1"
- if [ "$off" -eq "0" ]; then
- dump_config "$image"
- fi
-fi
-
-echo "ERROR: Unable to extract kernel configuration information."
-echo " This kernel image may not have the config info."
-
-clean_up
+# Initial attempt for uncompressed images or objects:
+dump_config "$img"
+
+# That didn't work, so decompress and try again:
+tmp=/tmp/ikconfig$$
+trap "rm -f $tmp" 0
+for pos in `tr "$gz1\n$gz2" "\n$gz2=" < "$img" | grep -abo "^$gz2"`
+do
+ pos=${pos%%:*}
+ tail -c+$pos "$img" | zcat 2> /dev/null > $tmp
+ dump_config $tmp
+done
+
+# Bail out:
+echo "$me: Cannot find kernel config." >&2
exit 1
diff --git a/scripts/headers.sh b/scripts/headers.sh
index 0308ecc10d5b..1ddcdd38d97f 100755
--- a/scripts/headers.sh
+++ b/scripts/headers.sh
@@ -8,8 +8,6 @@ do_command()
{
if [ -f ${srctree}/arch/$2/include/asm/Kbuild ]; then
make ARCH=$2 KBUILD_HEADERS=$1 headers_$1
- elif [ -f ${srctree}/include/asm-$2/Kbuild ]; then
- make ARCH=$2 KBUILD_HEADERS=$1 headers_$1
else
printf "Ignoring arch: %s\n" ${arch}
fi
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index b55e72ff2fc6..797a7410f690 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -776,7 +776,7 @@ int conf_write_autoconf(void)
name = getenv("KCONFIG_AUTOHEADER");
if (!name)
- name = "include/linux/autoconf.h";
+ name = "include/generated/autoconf.h";
if (rename(".tmpconfig.h", name))
return 1;
name = conf_get_autoconfig_name();
diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h
index bce3d0fe6fbd..23dbad80cce9 100755
--- a/scripts/mkcompile_h
+++ b/scripts/mkcompile_h
@@ -14,7 +14,7 @@ vecho() { [ "${quiet}" = "silent_" ] || echo "$@" ; }
# So "sudo make install" won't change the "compiled by <user>"
# do "compiled by root"
-if [ -r $TARGET -a ! -O include/linux/autoconf.h ]; then
+if [ -r $TARGET -a ! -O include/generated/autoconf.h ]; then
vecho " SKIPPED $TARGET"
exit 0
fi
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl
index 090d300d7394..bfb8b2cdd92a 100755
--- a/scripts/recordmcount.pl
+++ b/scripts/recordmcount.pl
@@ -119,6 +119,7 @@ my %text_sections = (
".sched.text" => 1,
".spinlock.text" => 1,
".irqentry.text" => 1,
+ ".text.unlikely" => 1,
);
$objdump = "objdump" if ((length $objdump) == 0);
diff --git a/scripts/selinux/Makefile b/scripts/selinux/Makefile
index ca4b1ec01822..e8049da1831f 100644
--- a/scripts/selinux/Makefile
+++ b/scripts/selinux/Makefile
@@ -1,2 +1,2 @@
-subdir-y := mdp
-subdir- += mdp
+subdir-y := mdp genheaders
+subdir- += mdp genheaders
diff --git a/scripts/selinux/genheaders/.gitignore b/scripts/selinux/genheaders/.gitignore
new file mode 100644
index 000000000000..4c0b646ff8d5
--- /dev/null
+++ b/scripts/selinux/genheaders/.gitignore
@@ -0,0 +1 @@
+genheaders
diff --git a/scripts/selinux/genheaders/Makefile b/scripts/selinux/genheaders/Makefile
new file mode 100644
index 000000000000..417b165008ee
--- /dev/null
+++ b/scripts/selinux/genheaders/Makefile
@@ -0,0 +1,5 @@
+hostprogs-y := genheaders
+HOST_EXTRACFLAGS += -Isecurity/selinux/include
+
+always := $(hostprogs-y)
+clean-files := $(hostprogs-y)
diff --git a/scripts/selinux/genheaders/genheaders.c b/scripts/selinux/genheaders/genheaders.c
new file mode 100644
index 000000000000..3b16145dabe3
--- /dev/null
+++ b/scripts/selinux/genheaders/genheaders.c
@@ -0,0 +1,118 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+struct security_class_mapping {
+ const char *name;
+ const char *perms[sizeof(unsigned) * 8 + 1];
+};
+
+#include "classmap.h"
+#include "initial_sid_to_string.h"
+
+#define max(x, y) ((x > y) ? x : y)
+
+const char *progname;
+
+void usage(void)
+{
+ printf("usage: %s flask.h av_permissions.h\n", progname);
+ exit(1);
+}
+
+char *stoupperx(const char *s)
+{
+ char *s2 = strdup(s);
+ char *p;
+
+ if (!s2) {
+ fprintf(stderr, "%s: out of memory\n", progname);
+ exit(3);
+ }
+
+ for (p = s2; *p; p++)
+ *p = toupper(*p);
+ return s2;
+}
+
+int main(int argc, char *argv[])
+{
+ int i, j, k;
+ int isids_len;
+ FILE *fout;
+
+ progname = argv[0];
+
+ if (argc < 3)
+ usage();
+
+ fout = fopen(argv[1], "w");
+ if (!fout) {
+ fprintf(stderr, "Could not open %s for writing: %s\n",
+ argv[1], strerror(errno));
+ exit(2);
+ }
+
+ for (i = 0; secclass_map[i].name; i++) {
+ struct security_class_mapping *map = &secclass_map[i];
+ map->name = stoupperx(map->name);
+ for (j = 0; map->perms[j]; j++)
+ map->perms[j] = stoupperx(map->perms[j]);
+ }
+
+ isids_len = sizeof(initial_sid_to_string) / sizeof (char *);
+ for (i = 1; i < isids_len; i++)
+ initial_sid_to_string[i] = stoupperx(initial_sid_to_string[i]);
+
+ fprintf(fout, "/* This file is automatically generated. Do not edit. */\n");
+ fprintf(fout, "#ifndef _SELINUX_FLASK_H_\n#define _SELINUX_FLASK_H_\n\n");
+
+ for (i = 0; secclass_map[i].name; i++) {
+ struct security_class_mapping *map = &secclass_map[i];
+ fprintf(fout, "#define SECCLASS_%s", map->name);
+ for (j = 0; j < max(1, 40 - strlen(map->name)); j++)
+ fprintf(fout, " ");
+ fprintf(fout, "%2d\n", i+1);
+ }
+
+ fprintf(fout, "\n");
+
+ for (i = 1; i < isids_len; i++) {
+ char *s = initial_sid_to_string[i];
+ fprintf(fout, "#define SECINITSID_%s", s);
+ for (j = 0; j < max(1, 40 - strlen(s)); j++)
+ fprintf(fout, " ");
+ fprintf(fout, "%2d\n", i);
+ }
+ fprintf(fout, "\n#define SECINITSID_NUM %d\n", i-1);
+ fprintf(fout, "\n#endif\n");
+ fclose(fout);
+
+ fout = fopen(argv[2], "w");
+ if (!fout) {
+ fprintf(stderr, "Could not open %s for writing: %s\n",
+ argv[2], strerror(errno));
+ exit(4);
+ }
+
+ fprintf(fout, "/* This file is automatically generated. Do not edit. */\n");
+ fprintf(fout, "#ifndef _SELINUX_AV_PERMISSIONS_H_\n#define _SELINUX_AV_PERMISSIONS_H_\n\n");
+
+ for (i = 0; secclass_map[i].name; i++) {
+ struct security_class_mapping *map = &secclass_map[i];
+ for (j = 0; map->perms[j]; j++) {
+ fprintf(fout, "#define %s__%s", map->name,
+ map->perms[j]);
+ for (k = 0; k < max(1, 40 - strlen(map->name) - strlen(map->perms[j])); k++)
+ fprintf(fout, " ");
+ fprintf(fout, "0x%08xUL\n", (1<<j));
+ }
+ }
+
+ fprintf(fout, "\n#endif\n");
+ fclose(fout);
+ exit(0);
+}
diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c
index b4ced8562587..62b34ce1f50d 100644
--- a/scripts/selinux/mdp/mdp.c
+++ b/scripts/selinux/mdp/mdp.c
@@ -29,86 +29,27 @@
#include <unistd.h>
#include <string.h>
-#include "flask.h"
-
static void usage(char *name)
{
printf("usage: %s [-m] policy_file context_file\n", name);
exit(1);
}
-static void find_common_name(char *cname, char *dest, int len)
-{
- char *start, *end;
-
- start = strchr(cname, '_')+1;
- end = strchr(start, '_');
- if (!start || !end || start-cname > len || end-start > len) {
- printf("Error with commons defines\n");
- exit(1);
- }
- strncpy(dest, start, end-start);
- dest[end-start] = '\0';
-}
-
-#define S_(x) x,
-static char *classlist[] = {
-#include "class_to_string.h"
- NULL
+/* Class/perm mapping support */
+struct security_class_mapping {
+ const char *name;
+ const char *perms[sizeof(unsigned) * 8 + 1];
};
-#undef S_
+#include "classmap.h"
#include "initial_sid_to_string.h"
-#define TB_(x) char *x[] = {
-#define TE_(x) NULL };
-#define S_(x) x,
-#include "common_perm_to_string.h"
-#undef TB_
-#undef TE_
-#undef S_
-
-struct common {
- char *cname;
- char **perms;
-};
-struct common common[] = {
-#define TB_(x) { #x, x },
-#define S_(x)
-#define TE_(x)
-#include "common_perm_to_string.h"
-#undef TB_
-#undef TE_
-#undef S_
-};
-
-#define S_(x, y, z) {x, #y},
-struct av_inherit {
- int class;
- char *common;
-};
-struct av_inherit av_inherit[] = {
-#include "av_inherit.h"
-};
-#undef S_
-
-#include "av_permissions.h"
-#define S_(x, y, z) {x, y, z},
-struct av_perms {
- int class;
- int perm_i;
- char *perm_s;
-};
-struct av_perms av_perms[] = {
-#include "av_perm_to_string.h"
-};
-#undef S_
-
int main(int argc, char *argv[])
{
int i, j, mls = 0;
+ int initial_sid_to_string_len;
char **arg, *polout, *ctxout;
- int classlist_len, initial_sid_to_string_len;
+
FILE *fout;
if (argc < 3)
@@ -127,64 +68,25 @@ int main(int argc, char *argv[])
usage(argv[0]);
}
- classlist_len = sizeof(classlist) / sizeof(char *);
/* print out the classes */
- for (i=1; i < classlist_len; i++) {
- if(classlist[i])
- fprintf(fout, "class %s\n", classlist[i]);
- else
- fprintf(fout, "class user%d\n", i);
- }
+ for (i = 0; secclass_map[i].name; i++)
+ fprintf(fout, "class %s\n", secclass_map[i].name);
fprintf(fout, "\n");
initial_sid_to_string_len = sizeof(initial_sid_to_string) / sizeof (char *);
/* print out the sids */
- for (i=1; i < initial_sid_to_string_len; i++)
+ for (i = 1; i < initial_sid_to_string_len; i++)
fprintf(fout, "sid %s\n", initial_sid_to_string[i]);
fprintf(fout, "\n");
- /* print out the commons */
- for (i=0; i< sizeof(common)/sizeof(struct common); i++) {
- char cname[101];
- find_common_name(common[i].cname, cname, 100);
- cname[100] = '\0';
- fprintf(fout, "common %s\n{\n", cname);
- for (j=0; common[i].perms[j]; j++)
- fprintf(fout, "\t%s\n", common[i].perms[j]);
- fprintf(fout, "}\n\n");
- }
- fprintf(fout, "\n");
-
/* print out the class permissions */
- for (i=1; i < classlist_len; i++) {
- if (classlist[i]) {
- int firstperm = -1, numperms = 0;
-
- fprintf(fout, "class %s\n", classlist[i]);
- /* does it inherit from a common? */
- for (j=0; j < sizeof(av_inherit)/sizeof(struct av_inherit); j++)
- if (av_inherit[j].class == i)
- fprintf(fout, "inherits %s\n", av_inherit[j].common);
-
- for (j=0; j < sizeof(av_perms)/sizeof(struct av_perms); j++) {
- if (av_perms[j].class == i) {
- if (firstperm == -1)
- firstperm = j;
- numperms++;
- }
- }
- if (!numperms) {
- fprintf(fout, "\n");
- continue;
- }
-
- fprintf(fout, "{\n");
- /* print out the av_perms */
- for (j=0; j < numperms; j++) {
- fprintf(fout, "\t%s\n", av_perms[firstperm+j].perm_s);
- }
- fprintf(fout, "}\n\n");
- }
+ for (i = 0; secclass_map[i].name; i++) {
+ struct security_class_mapping *map = &secclass_map[i];
+ fprintf(fout, "class %s\n", map->name);
+ fprintf(fout, "{\n");
+ for (j = 0; map->perms[j]; j++)
+ fprintf(fout, "\t%s\n", map->perms[j]);
+ fprintf(fout, "}\n\n");
}
fprintf(fout, "\n");
@@ -197,31 +99,34 @@ int main(int argc, char *argv[])
/* types, roles, and allows */
fprintf(fout, "type base_t;\n");
fprintf(fout, "role base_r types { base_t };\n");
- for (i=1; i < classlist_len; i++) {
- if (classlist[i])
- fprintf(fout, "allow base_t base_t:%s *;\n", classlist[i]);
- else
- fprintf(fout, "allow base_t base_t:user%d *;\n", i);
- }
+ for (i = 0; secclass_map[i].name; i++)
+ fprintf(fout, "allow base_t base_t:%s *;\n",
+ secclass_map[i].name);
fprintf(fout, "user user_u roles { base_r };\n");
fprintf(fout, "\n");
/* default sids */
- for (i=1; i < initial_sid_to_string_len; i++)
+ for (i = 1; i < initial_sid_to_string_len; i++)
fprintf(fout, "sid %s user_u:base_r:base_t\n", initial_sid_to_string[i]);
fprintf(fout, "\n");
-
fprintf(fout, "fs_use_xattr ext2 user_u:base_r:base_t;\n");
fprintf(fout, "fs_use_xattr ext3 user_u:base_r:base_t;\n");
+ fprintf(fout, "fs_use_xattr ext4 user_u:base_r:base_t;\n");
fprintf(fout, "fs_use_xattr jfs user_u:base_r:base_t;\n");
fprintf(fout, "fs_use_xattr xfs user_u:base_r:base_t;\n");
fprintf(fout, "fs_use_xattr reiserfs user_u:base_r:base_t;\n");
+ fprintf(fout, "fs_use_xattr jffs2 user_u:base_r:base_t;\n");
+ fprintf(fout, "fs_use_xattr gfs2 user_u:base_r:base_t;\n");
+ fprintf(fout, "fs_use_xattr lustre user_u:base_r:base_t;\n");
+ fprintf(fout, "fs_use_task eventpollfs user_u:base_r:base_t;\n");
fprintf(fout, "fs_use_task pipefs user_u:base_r:base_t;\n");
fprintf(fout, "fs_use_task sockfs user_u:base_r:base_t;\n");
+ fprintf(fout, "fs_use_trans mqueue user_u:base_r:base_t;\n");
fprintf(fout, "fs_use_trans devpts user_u:base_r:base_t;\n");
+ fprintf(fout, "fs_use_trans hugetlbfs user_u:base_r:base_t;\n");
fprintf(fout, "fs_use_trans tmpfs user_u:base_r:base_t;\n");
fprintf(fout, "fs_use_trans shm user_u:base_r:base_t;\n");
diff --git a/security/Kconfig b/security/Kconfig
index fb363cd81cf6..aeea8c2bb59c 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -100,19 +100,6 @@ config SECURITY_FILE_CAPABILITIES
If in doubt, answer N.
-config SECURITY_ROOTPLUG
- bool "Root Plug Support"
- depends on USB=y && SECURITY
- help
- This is a sample LSM module that should only be used as such.
- It prevents any programs running with egid == 0 if a specific
- USB device is not present in the system.
-
- See <http://www.linuxjournal.com/article.php?sid=6279> for
- more information about this module.
-
- If you are unsure how to answer this question, answer N.
-
config INTEL_TXT
bool "Enable Intel(R) Trusted Execution Technology (Intel(R) TXT)"
depends on HAVE_INTEL_TXT
diff --git a/security/Makefile b/security/Makefile
index 95ecc06392d7..bb44e350c618 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -18,7 +18,6 @@ obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o
obj-$(CONFIG_AUDIT) += lsm_audit.o
obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o
-obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
# Object integrity file lists
diff --git a/security/capability.c b/security/capability.c
index fce07a7bc825..d30a8e8e2dd8 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -308,6 +308,22 @@ static int cap_path_truncate(struct path *path, loff_t length,
{
return 0;
}
+
+static int cap_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
+ mode_t mode)
+{
+ return 0;
+}
+
+static int cap_path_chown(struct path *path, uid_t uid, gid_t gid)
+{
+ return 0;
+}
+
+static int cap_path_chroot(struct path *root)
+{
+ return 0;
+}
#endif
static int cap_file_permission(struct file *file, int mask)
@@ -450,7 +466,8 @@ static int cap_task_getioprio(struct task_struct *p)
return 0;
}
-static int cap_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
+static int cap_task_setrlimit(struct task_struct *p, unsigned int resource,
+ struct rlimit *new_rlim)
{
return 0;
}
@@ -977,6 +994,9 @@ void security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, path_link);
set_to_cap_if_null(ops, path_rename);
set_to_cap_if_null(ops, path_truncate);
+ set_to_cap_if_null(ops, path_chmod);
+ set_to_cap_if_null(ops, path_chown);
+ set_to_cap_if_null(ops, path_chroot);
#endif
set_to_cap_if_null(ops, file_permission);
set_to_cap_if_null(ops, file_alloc_security);
diff --git a/security/commoncap.c b/security/commoncap.c
index fe30751a6cd9..45b87af4ae5d 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -1,4 +1,4 @@
-/* Common capabilities, needed by capability.o and root_plug.o
+/* Common capabilities, needed by capability.o.
*
* This 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/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index 53d9764e8f09..3d7846de8069 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -3,6 +3,7 @@
config IMA
bool "Integrity Measurement Architecture(IMA)"
depends on ACPI
+ depends on SECURITY
select SECURITYFS
select CRYPTO
select CRYPTO_HMAC
diff --git a/security/lsm_audit.c b/security/lsm_audit.c
index 3bb90b6f1dd3..e04566a2c4e5 100644
--- a/security/lsm_audit.c
+++ b/security/lsm_audit.c
@@ -273,11 +273,11 @@ static void dump_common_audit_data(struct audit_buffer *ab,
case AF_INET: {
struct inet_sock *inet = inet_sk(sk);
- print_ipv4_addr(ab, inet->rcv_saddr,
- inet->sport,
+ print_ipv4_addr(ab, inet->inet_rcv_saddr,
+ inet->inet_sport,
"laddr", "lport");
- print_ipv4_addr(ab, inet->daddr,
- inet->dport,
+ print_ipv4_addr(ab, inet->inet_daddr,
+ inet->inet_dport,
"faddr", "fport");
break;
}
@@ -286,10 +286,10 @@ static void dump_common_audit_data(struct audit_buffer *ab,
struct ipv6_pinfo *inet6 = inet6_sk(sk);
print_ipv6_addr(ab, &inet6->rcv_saddr,
- inet->sport,
+ inet->inet_sport,
"laddr", "lport");
print_ipv6_addr(ab, &inet6->daddr,
- inet->dport,
+ inet->inet_dport,
"faddr", "fport");
break;
}
diff --git a/security/root_plug.c b/security/root_plug.c
deleted file mode 100644
index 2f7ffa67c4d2..000000000000
--- a/security/root_plug.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Root Plug sample LSM module
- *
- * Originally written for a Linux Journal.
- *
- * Copyright (C) 2002 Greg Kroah-Hartman <greg@kroah.com>
- *
- * Prevents any programs running with egid == 0 if a specific USB device
- * is not present in the system. Yes, it can be gotten around, but is a
- * nice starting point for people to play with, and learn the LSM
- * interface.
- *
- * If you want to turn this into something with a semblance of security,
- * you need to hook the task_* functions also.
- *
- * See http://www.linuxjournal.com/article.php?sid=6279 for more information
- * about this code.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2 of the
- * License.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/security.h>
-#include <linux/usb.h>
-#include <linux/moduleparam.h>
-
-/* default is a generic type of usb to serial converter */
-static int vendor_id = 0x0557;
-static int product_id = 0x2008;
-
-module_param(vendor_id, uint, 0400);
-module_param(product_id, uint, 0400);
-
-/* should we print out debug messages */
-static int debug = 0;
-
-module_param(debug, bool, 0600);
-
-#define MY_NAME "root_plug"
-
-#define root_dbg(fmt, arg...) \
- do { \
- if (debug) \
- printk(KERN_DEBUG "%s: %s: " fmt , \
- MY_NAME , __func__ , \
- ## arg); \
- } while (0)
-
-static int rootplug_bprm_check_security (struct linux_binprm *bprm)
-{
- struct usb_device *dev;
-
- root_dbg("file %s, e_uid = %d, e_gid = %d\n",
- bprm->filename, bprm->cred->euid, bprm->cred->egid);
-
- if (bprm->cred->egid == 0) {
- dev = usb_find_device(vendor_id, product_id);
- if (!dev) {
- root_dbg("e_gid = 0, and device not found, "
- "task not allowed to run...\n");
- return -EPERM;
- }
- usb_put_dev(dev);
- }
-
- return 0;
-}
-
-static struct security_operations rootplug_security_ops = {
- .bprm_check_security = rootplug_bprm_check_security,
-};
-
-static int __init rootplug_init (void)
-{
- /* register ourselves with the security framework */
- if (register_security (&rootplug_security_ops)) {
- printk (KERN_INFO
- "Failure registering Root Plug module with the kernel\n");
- return -EINVAL;
- }
- printk (KERN_INFO "Root Plug module initialized, "
- "vendor_id = %4.4x, product id = %4.4x\n", vendor_id, product_id);
- return 0;
-}
-
-security_initcall (rootplug_init);
diff --git a/security/security.c b/security/security.c
index c4c673240c1c..48ec2b4e15d5 100644
--- a/security/security.c
+++ b/security/security.c
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/security.h>
+#include <linux/ima.h>
/* Boot-time LSM user choice */
static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1];
@@ -235,7 +236,12 @@ int security_bprm_set_creds(struct linux_binprm *bprm)
int security_bprm_check(struct linux_binprm *bprm)
{
- return security_ops->bprm_check_security(bprm);
+ int ret;
+
+ ret = security_ops->bprm_check_security(bprm);
+ if (ret)
+ return ret;
+ return ima_bprm_check(bprm);
}
void security_bprm_committing_creds(struct linux_binprm *bprm)
@@ -352,12 +358,21 @@ EXPORT_SYMBOL(security_sb_parse_opts_str);
int security_inode_alloc(struct inode *inode)
{
+ int ret;
+
inode->i_security = NULL;
- return security_ops->inode_alloc_security(inode);
+ ret = security_ops->inode_alloc_security(inode);
+ if (ret)
+ return ret;
+ ret = ima_inode_alloc(inode);
+ if (ret)
+ security_inode_free(inode);
+ return ret;
}
void security_inode_free(struct inode *inode)
{
+ ima_inode_free(inode);
security_ops->inode_free_security(inode);
}
@@ -434,6 +449,26 @@ int security_path_truncate(struct path *path, loff_t length,
return 0;
return security_ops->path_truncate(path, length, time_attrs);
}
+
+int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
+ mode_t mode)
+{
+ if (unlikely(IS_PRIVATE(dentry->d_inode)))
+ return 0;
+ return security_ops->path_chmod(dentry, mnt, mode);
+}
+
+int security_path_chown(struct path *path, uid_t uid, gid_t gid)
+{
+ if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+ return 0;
+ return security_ops->path_chown(path, uid, gid);
+}
+
+int security_path_chroot(struct path *path)
+{
+ return security_ops->path_chroot(path);
+}
#endif
int security_inode_create(struct inode *dir, struct dentry *dentry, int mode)
@@ -628,6 +663,8 @@ int security_file_alloc(struct file *file)
void security_file_free(struct file *file)
{
security_ops->file_free_security(file);
+ if (file->f_dentry)
+ ima_file_free(file);
}
int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -639,7 +676,12 @@ int security_file_mmap(struct file *file, unsigned long reqprot,
unsigned long prot, unsigned long flags,
unsigned long addr, unsigned long addr_only)
{
- return security_ops->file_mmap(file, reqprot, prot, flags, addr, addr_only);
+ int ret;
+
+ ret = security_ops->file_mmap(file, reqprot, prot, flags, addr, addr_only);
+ if (ret)
+ return ret;
+ return ima_file_mmap(file, prot);
}
int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
@@ -781,9 +823,10 @@ int security_task_getioprio(struct task_struct *p)
return security_ops->task_getioprio(p);
}
-int security_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
+int security_task_setrlimit(struct task_struct *p, unsigned int resource,
+ struct rlimit *new_rlim)
{
- return security_ops->task_setrlimit(resource, new_rlim);
+ return security_ops->task_setrlimit(p, resource, new_rlim);
}
int security_task_setscheduler(struct task_struct *p,
diff --git a/security/selinux/.gitignore b/security/selinux/.gitignore
new file mode 100644
index 000000000000..2e5040a3d48b
--- /dev/null
+++ b/security/selinux/.gitignore
@@ -0,0 +1,2 @@
+av_permissions.h
+flask.h
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index d47fc5e545e0..f013982df417 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -18,5 +18,13 @@ selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
selinux-$(CONFIG_NETLABEL) += netlabel.o
-EXTRA_CFLAGS += -Isecurity/selinux/include
+EXTRA_CFLAGS += -Isecurity/selinux -Isecurity/selinux/include
+$(obj)/avc.o: $(obj)/flask.h
+
+quiet_cmd_flask = GEN $(obj)/flask.h $(obj)/av_permissions.h
+ cmd_flask = scripts/selinux/genheaders/genheaders $(obj)/flask.h $(obj)/av_permissions.h
+
+targets += flask.h
+$(obj)/flask.h: $(src)/include/classmap.h FORCE
+ $(call if_changed,flask)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index b4b5da1c0a42..18f4103e02b7 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -31,43 +31,7 @@
#include <net/ipv6.h>
#include "avc.h"
#include "avc_ss.h"
-
-static const struct av_perm_to_string av_perm_to_string[] = {
-#define S_(c, v, s) { c, v, s },
-#include "av_perm_to_string.h"
-#undef S_
-};
-
-static const char *class_to_string[] = {
-#define S_(s) s,
-#include "class_to_string.h"
-#undef S_
-};
-
-#define TB_(s) static const char *s[] = {
-#define TE_(s) };
-#define S_(s) s,
-#include "common_perm_to_string.h"
-#undef TB_
-#undef TE_
-#undef S_
-
-static const struct av_inherit av_inherit[] = {
-#define S_(c, i, b) { .tclass = c,\
- .common_pts = common_##i##_perm_to_string,\
- .common_base = b },
-#include "av_inherit.h"
-#undef S_
-};
-
-const struct selinux_class_perm selinux_class_perm = {
- .av_perm_to_string = av_perm_to_string,
- .av_pts_len = ARRAY_SIZE(av_perm_to_string),
- .class_to_string = class_to_string,
- .cts_len = ARRAY_SIZE(class_to_string),
- .av_inherit = av_inherit,
- .av_inherit_len = ARRAY_SIZE(av_inherit)
-};
+#include "classmap.h"
#define AVC_CACHE_SLOTS 512
#define AVC_DEF_CACHE_THRESHOLD 512
@@ -139,52 +103,28 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
*/
static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
{
- const char **common_pts = NULL;
- u32 common_base = 0;
- int i, i2, perm;
+ const char **perms;
+ int i, perm;
if (av == 0) {
audit_log_format(ab, " null");
return;
}
- for (i = 0; i < ARRAY_SIZE(av_inherit); i++) {
- if (av_inherit[i].tclass == tclass) {
- common_pts = av_inherit[i].common_pts;
- common_base = av_inherit[i].common_base;
- break;
- }
- }
+ perms = secclass_map[tclass-1].perms;
audit_log_format(ab, " {");
i = 0;
perm = 1;
- while (perm < common_base) {
+ while (i < (sizeof(av) * 8)) {
if (perm & av) {
- audit_log_format(ab, " %s", common_pts[i]);
+ audit_log_format(ab, " %s", perms[i]);
av &= ~perm;
}
i++;
perm <<= 1;
}
- while (i < sizeof(av) * 8) {
- if (perm & av) {
- for (i2 = 0; i2 < ARRAY_SIZE(av_perm_to_string); i2++) {
- if ((av_perm_to_string[i2].tclass == tclass) &&
- (av_perm_to_string[i2].value == perm))
- break;
- }
- if (i2 < ARRAY_SIZE(av_perm_to_string)) {
- audit_log_format(ab, " %s",
- av_perm_to_string[i2].name);
- av &= ~perm;
- }
- }
- i++;
- perm <<= 1;
- }
-
if (av)
audit_log_format(ab, " 0x%x", av);
@@ -219,8 +159,8 @@ static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tcla
kfree(scontext);
}
- BUG_ON(tclass >= ARRAY_SIZE(class_to_string) || !class_to_string[tclass]);
- audit_log_format(ab, " tclass=%s", class_to_string[tclass]);
+ BUG_ON(tclass >= ARRAY_SIZE(secclass_map));
+ audit_log_format(ab, " tclass=%s", secclass_map[tclass-1].name);
}
/**
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index bb230d5d7085..0c0c1bffe13a 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -91,7 +91,6 @@
#define NUM_SEL_MNT_OPTS 5
-extern unsigned int policydb_loaded_version;
extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
extern struct security_operations *security_ops;
@@ -2366,7 +2365,8 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
initrlim = init_task.signal->rlim + i;
rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
}
- update_rlimit_cpu(rlim->rlim_cur);
+ update_rlimit_cpu(current,
+ current->signal->rlim[RLIMIT_CPU].rlim_cur);
}
}
@@ -3390,16 +3390,17 @@ static int selinux_task_getioprio(struct task_struct *p)
return current_has_perm(p, PROCESS__GETSCHED);
}
-static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
+static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
+ struct rlimit *new_rlim)
{
- struct rlimit *old_rlim = current->signal->rlim + resource;
+ struct rlimit *old_rlim = p->signal->rlim + resource;
/* Control the ability to change the hard limit (whether
lowering or raising it), so that the hard limit can
later be used as a safe reset point for the soft limit
upon context transitions. See selinux_bprm_committing_creds. */
if (old_rlim->rlim_max != new_rlim->rlim_max)
- return current_has_perm(current, PROCESS__SETRLIMIT);
+ return current_has_perm(p, PROCESS__SETRLIMIT);
return 0;
}
@@ -4714,10 +4715,7 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
if (err)
return err;
- if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
- err = selinux_nlmsg_perm(sk, skb);
-
- return err;
+ return selinux_nlmsg_perm(sk, skb);
}
static int selinux_netlink_recv(struct sk_buff *skb, int capability)
@@ -5830,12 +5828,12 @@ int selinux_disable(void)
selinux_disabled = 1;
selinux_enabled = 0;
- /* Try to destroy the avc node cache */
- avc_disable();
-
/* Reset security_ops to the secondary module, dummy or capability. */
security_ops = secondary_ops;
+ /* Try to destroy the avc node cache */
+ avc_disable();
+
/* Unregister netfilter hooks. */
selinux_nf_ip_exit();
diff --git a/security/selinux/include/av_inherit.h b/security/selinux/include/av_inherit.h
deleted file mode 100644
index abedcd704dae..000000000000
--- a/security/selinux/include/av_inherit.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* This file is automatically generated. Do not edit. */
- S_(SECCLASS_DIR, file, 0x00020000UL)
- S_(SECCLASS_FILE, file, 0x00020000UL)
- S_(SECCLASS_LNK_FILE, file, 0x00020000UL)
- S_(SECCLASS_CHR_FILE, file, 0x00020000UL)
- S_(SECCLASS_BLK_FILE, file, 0x00020000UL)
- S_(SECCLASS_SOCK_FILE, file, 0x00020000UL)
- S_(SECCLASS_FIFO_FILE, file, 0x00020000UL)
- S_(SECCLASS_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_TCP_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_UDP_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_RAWIP_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_NETLINK_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_PACKET_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_KEY_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_UNIX_STREAM_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_UNIX_DGRAM_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_TUN_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_IPC, ipc, 0x00000200UL)
- S_(SECCLASS_SEM, ipc, 0x00000200UL)
- S_(SECCLASS_MSGQ, ipc, 0x00000200UL)
- S_(SECCLASS_SHM, ipc, 0x00000200UL)
- S_(SECCLASS_NETLINK_ROUTE_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_NETLINK_FIREWALL_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_NETLINK_TCPDIAG_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_NETLINK_NFLOG_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_NETLINK_XFRM_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_NETLINK_SELINUX_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_NETLINK_AUDIT_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_NETLINK_IP6FW_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_NETLINK_DNRT_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_APPLETALK_SOCKET, socket, 0x00400000UL)
- S_(SECCLASS_DCCP_SOCKET, socket, 0x00400000UL)
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
deleted file mode 100644
index 2b683ad83d21..000000000000
--- a/security/selinux/include/av_perm_to_string.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/* This file is automatically generated. Do not edit. */
- S_(SECCLASS_FILESYSTEM, FILESYSTEM__MOUNT, "mount")
- S_(SECCLASS_FILESYSTEM, FILESYSTEM__REMOUNT, "remount")
- S_(SECCLASS_FILESYSTEM, FILESYSTEM__UNMOUNT, "unmount")
- S_(SECCLASS_FILESYSTEM, FILESYSTEM__GETATTR, "getattr")
- S_(SECCLASS_FILESYSTEM, FILESYSTEM__RELABELFROM, "relabelfrom")
- S_(SECCLASS_FILESYSTEM, FILESYSTEM__RELABELTO, "relabelto")
- S_(SECCLASS_FILESYSTEM, FILESYSTEM__TRANSITION, "transition")
- S_(SECCLASS_FILESYSTEM, FILESYSTEM__ASSOCIATE, "associate")
- S_(SECCLASS_FILESYSTEM, FILESYSTEM__QUOTAMOD, "quotamod")
- S_(SECCLASS_FILESYSTEM, FILESYSTEM__QUOTAGET, "quotaget")
- S_(SECCLASS_DIR, DIR__ADD_NAME, "add_name")
- S_(SECCLASS_DIR, DIR__REMOVE_NAME, "remove_name")
- S_(SECCLASS_DIR, DIR__REPARENT, "reparent")
- S_(SECCLASS_DIR, DIR__SEARCH, "search")
- S_(SECCLASS_DIR, DIR__RMDIR, "rmdir")
- S_(SECCLASS_DIR, DIR__OPEN, "open")
- S_(SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, "execute_no_trans")
- S_(SECCLASS_FILE, FILE__ENTRYPOINT, "entrypoint")
- S_(SECCLASS_FILE, FILE__EXECMOD, "execmod")
- S_(SECCLASS_FILE, FILE__OPEN, "open")
- S_(SECCLASS_CHR_FILE, CHR_FILE__EXECUTE_NO_TRANS, "execute_no_trans")
- S_(SECCLASS_CHR_FILE, CHR_FILE__ENTRYPOINT, "entrypoint")
- S_(SECCLASS_CHR_FILE, CHR_FILE__EXECMOD, "execmod")
- S_(SECCLASS_CHR_FILE, CHR_FILE__OPEN, "open")
- S_(SECCLASS_BLK_FILE, BLK_FILE__OPEN, "open")
- S_(SECCLASS_SOCK_FILE, SOCK_FILE__OPEN, "open")
- S_(SECCLASS_FIFO_FILE, FIFO_FILE__OPEN, "open")
- S_(SECCLASS_FD, FD__USE, "use")
- S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__CONNECTTO, "connectto")
- S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__NEWCONN, "newconn")
- S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__ACCEPTFROM, "acceptfrom")
- S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__NODE_BIND, "node_bind")
- S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__NAME_CONNECT, "name_connect")
- S_(SECCLASS_UDP_SOCKET, UDP_SOCKET__NODE_BIND, "node_bind")
- S_(SECCLASS_RAWIP_SOCKET, RAWIP_SOCKET__NODE_BIND, "node_bind")
- S_(SECCLASS_NODE, NODE__TCP_RECV, "tcp_recv")
- S_(SECCLASS_NODE, NODE__TCP_SEND, "tcp_send")
- S_(SECCLASS_NODE, NODE__UDP_RECV, "udp_recv")
- S_(SECCLASS_NODE, NODE__UDP_SEND, "udp_send")
- S_(SECCLASS_NODE, NODE__RAWIP_RECV, "rawip_recv")
- S_(SECCLASS_NODE, NODE__RAWIP_SEND, "rawip_send")
- S_(SECCLASS_NODE, NODE__ENFORCE_DEST, "enforce_dest")
- S_(SECCLASS_NODE, NODE__DCCP_RECV, "dccp_recv")
- S_(SECCLASS_NODE, NODE__DCCP_SEND, "dccp_send")
- S_(SECCLASS_NODE, NODE__RECVFROM, "recvfrom")
- S_(SECCLASS_NODE, NODE__SENDTO, "sendto")
- S_(SECCLASS_NETIF, NETIF__TCP_RECV, "tcp_recv")
- S_(SECCLASS_NETIF, NETIF__TCP_SEND, "tcp_send")
- S_(SECCLASS_NETIF, NETIF__UDP_RECV, "udp_recv")
- S_(SECCLASS_NETIF, NETIF__UDP_SEND, "udp_send")
- S_(SECCLASS_NETIF, NETIF__RAWIP_RECV, "rawip_recv")
- S_(SECCLASS_NETIF, NETIF__RAWIP_SEND, "rawip_send")
- S_(SECCLASS_NETIF, NETIF__DCCP_RECV, "dccp_recv")
- S_(SECCLASS_NETIF, NETIF__DCCP_SEND, "dccp_send")
- S_(SECCLASS_NETIF, NETIF__INGRESS, "ingress")
- S_(SECCLASS_NETIF, NETIF__EGRESS, "egress")
- S_(SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__CONNECTTO, "connectto")
- S_(SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__NEWCONN, "newconn")
- S_(SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__ACCEPTFROM, "acceptfrom")
- S_(SECCLASS_PROCESS, PROCESS__FORK, "fork")
- S_(SECCLASS_PROCESS, PROCESS__TRANSITION, "transition")
- S_(SECCLASS_PROCESS, PROCESS__SIGCHLD, "sigchld")
- S_(SECCLASS_PROCESS, PROCESS__SIGKILL, "sigkill")
- S_(SECCLASS_PROCESS, PROCESS__SIGSTOP, "sigstop")
- S_(SECCLASS_PROCESS, PROCESS__SIGNULL, "signull")
- S_(SECCLASS_PROCESS, PROCESS__SIGNAL, "signal")
- S_(SECCLASS_PROCESS, PROCESS__PTRACE, "ptrace")
- S_(SECCLASS_PROCESS, PROCESS__GETSCHED, "getsched")
- S_(SECCLASS_PROCESS, PROCESS__SETSCHED, "setsched")
- S_(SECCLASS_PROCESS, PROCESS__GETSESSION, "getsession")
- S_(SECCLASS_PROCESS, PROCESS__GETPGID, "getpgid")
- S_(SECCLASS_PROCESS, PROCESS__SETPGID, "setpgid")
- S_(SECCLASS_PROCESS, PROCESS__GETCAP, "getcap")
- S_(SECCLASS_PROCESS, PROCESS__SETCAP, "setcap")
- S_(SECCLASS_PROCESS, PROCESS__SHARE, "share")
- S_(SECCLASS_PROCESS, PROCESS__GETATTR, "getattr")
- S_(SECCLASS_PROCESS, PROCESS__SETEXEC, "setexec")
- S_(SECCLASS_PROCESS, PROCESS__SETFSCREATE, "setfscreate")
- S_(SECCLASS_PROCESS, PROCESS__NOATSECURE, "noatsecure")
- S_(SECCLASS_PROCESS, PROCESS__SIGINH, "siginh")
- S_(SECCLASS_PROCESS, PROCESS__SETRLIMIT, "setrlimit")
- S_(SECCLASS_PROCESS, PROCESS__RLIMITINH, "rlimitinh")
- S_(SECCLASS_PROCESS, PROCESS__DYNTRANSITION, "dyntransition")
- S_(SECCLASS_PROCESS, PROCESS__SETCURRENT, "setcurrent")
- S_(SECCLASS_PROCESS, PROCESS__EXECMEM, "execmem")
- S_(SECCLASS_PROCESS, PROCESS__EXECSTACK, "execstack")
- S_(SECCLASS_PROCESS, PROCESS__EXECHEAP, "execheap")
- S_(SECCLASS_PROCESS, PROCESS__SETKEYCREATE, "setkeycreate")
- S_(SECCLASS_PROCESS, PROCESS__SETSOCKCREATE, "setsockcreate")
- S_(SECCLASS_MSGQ, MSGQ__ENQUEUE, "enqueue")
- S_(SECCLASS_MSG, MSG__SEND, "send")
- S_(SECCLASS_MSG, MSG__RECEIVE, "receive")
- S_(SECCLASS_SHM, SHM__LOCK, "lock")
- S_(SECCLASS_SECURITY, SECURITY__COMPUTE_AV, "compute_av")
- S_(SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE, "compute_create")
- S_(SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER, "compute_member")
- S_(SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, "check_context")
- S_(SECCLASS_SECURITY, SECURITY__LOAD_POLICY, "load_policy")
- S_(SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL, "compute_relabel")
- S_(SECCLASS_SECURITY, SECURITY__COMPUTE_USER, "compute_user")
- S_(SECCLASS_SECURITY, SECURITY__SETENFORCE, "setenforce")
- S_(SECCLASS_SECURITY, SECURITY__SETBOOL, "setbool")
- S_(SECCLASS_SECURITY, SECURITY__SETSECPARAM, "setsecparam")
- S_(SECCLASS_SECURITY, SECURITY__SETCHECKREQPROT, "setcheckreqprot")
- S_(SECCLASS_SYSTEM, SYSTEM__IPC_INFO, "ipc_info")
- S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, "syslog_read")
- S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, "syslog_mod")
- S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, "syslog_console")
- S_(SECCLASS_SYSTEM, SYSTEM__MODULE_REQUEST, "module_request")
- S_(SECCLASS_CAPABILITY, CAPABILITY__CHOWN, "chown")
- S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_OVERRIDE, "dac_override")
- S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_READ_SEARCH, "dac_read_search")
- S_(SECCLASS_CAPABILITY, CAPABILITY__FOWNER, "fowner")
- S_(SECCLASS_CAPABILITY, CAPABILITY__FSETID, "fsetid")
- S_(SECCLASS_CAPABILITY, CAPABILITY__KILL, "kill")
- S_(SECCLASS_CAPABILITY, CAPABILITY__SETGID, "setgid")
- S_(SECCLASS_CAPABILITY, CAPABILITY__SETUID, "setuid")
- S_(SECCLASS_CAPABILITY, CAPABILITY__SETPCAP, "setpcap")
- S_(SECCLASS_CAPABILITY, CAPABILITY__LINUX_IMMUTABLE, "linux_immutable")
- S_(SECCLASS_CAPABILITY, CAPABILITY__NET_BIND_SERVICE, "net_bind_service")
- S_(SECCLASS_CAPABILITY, CAPABILITY__NET_BROADCAST, "net_broadcast")
- S_(SECCLASS_CAPABILITY, CAPABILITY__NET_ADMIN, "net_admin")
- S_(SECCLASS_CAPABILITY, CAPABILITY__NET_RAW, "net_raw")
- S_(SECCLASS_CAPABILITY, CAPABILITY__IPC_LOCK, "ipc_lock")
- S_(SECCLASS_CAPABILITY, CAPABILITY__IPC_OWNER, "ipc_owner")
- S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_MODULE, "sys_module")
- S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_RAWIO, "sys_rawio")
- S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_CHROOT, "sys_chroot")
- S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_PTRACE, "sys_ptrace")
- S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_PACCT, "sys_pacct")
- S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_ADMIN, "sys_admin")
- S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_BOOT, "sys_boot")
- S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_NICE, "sys_nice")
- S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_RESOURCE, "sys_resource")
- S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_TIME, "sys_time")
- S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_TTY_CONFIG, "sys_tty_config")
- S_(SECCLASS_CAPABILITY, CAPABILITY__MKNOD, "mknod")
- S_(SECCLASS_CAPABILITY, CAPABILITY__LEASE, "lease")
- S_(SECCLASS_CAPABILITY, CAPABILITY__AUDIT_WRITE, "audit_write")
- S_(SECCLASS_CAPABILITY, CAPABILITY__AUDIT_CONTROL, "audit_control")
- S_(SECCLASS_CAPABILITY, CAPABILITY__SETFCAP, "setfcap")
- S_(SECCLASS_CAPABILITY2, CAPABILITY2__MAC_OVERRIDE, "mac_override")
- S_(SECCLASS_CAPABILITY2, CAPABILITY2__MAC_ADMIN, "mac_admin")
- S_(SECCLASS_NETLINK_ROUTE_SOCKET, NETLINK_ROUTE_SOCKET__NLMSG_READ, "nlmsg_read")
- S_(SECCLASS_NETLINK_ROUTE_SOCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE, "nlmsg_write")
- S_(SECCLASS_NETLINK_FIREWALL_SOCKET, NETLINK_FIREWALL_SOCKET__NLMSG_READ, "nlmsg_read")
- S_(SECCLASS_NETLINK_FIREWALL_SOCKET, NETLINK_FIREWALL_SOCKET__NLMSG_WRITE, "nlmsg_write")
- S_(SECCLASS_NETLINK_TCPDIAG_SOCKET, NETLINK_TCPDIAG_SOCKET__NLMSG_READ, "nlmsg_read")
- S_(SECCLASS_NETLINK_TCPDIAG_SOCKET, NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE, "nlmsg_write")
- S_(SECCLASS_NETLINK_XFRM_SOCKET, NETLINK_XFRM_SOCKET__NLMSG_READ, "nlmsg_read")
- S_(SECCLASS_NETLINK_XFRM_SOCKET, NETLINK_XFRM_SOCKET__NLMSG_WRITE, "nlmsg_write")
- S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_READ, "nlmsg_read")
- S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE, "nlmsg_write")
- S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_RELAY, "nlmsg_relay")
- S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV, "nlmsg_readpriv")
- S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT, "nlmsg_tty_audit")
- S_(SECCLASS_NETLINK_IP6FW_SOCKET, NETLINK_IP6FW_SOCKET__NLMSG_READ, "nlmsg_read")
- S_(SECCLASS_NETLINK_IP6FW_SOCKET, NETLINK_IP6FW_SOCKET__NLMSG_WRITE, "nlmsg_write")
- S_(SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, "sendto")
- S_(SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, "recvfrom")
- S_(SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, "setcontext")
- S_(SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, "polmatch")
- S_(SECCLASS_PACKET, PACKET__SEND, "send")
- S_(SECCLASS_PACKET, PACKET__RECV, "recv")
- S_(SECCLASS_PACKET, PACKET__RELABELTO, "relabelto")
- S_(SECCLASS_PACKET, PACKET__FLOW_IN, "flow_in")
- S_(SECCLASS_PACKET, PACKET__FLOW_OUT, "flow_out")
- S_(SECCLASS_PACKET, PACKET__FORWARD_IN, "forward_in")
- S_(SECCLASS_PACKET, PACKET__FORWARD_OUT, "forward_out")
- S_(SECCLASS_KEY, KEY__VIEW, "view")
- S_(SECCLASS_KEY, KEY__READ, "read")
- S_(SECCLASS_KEY, KEY__WRITE, "write")
- S_(SECCLASS_KEY, KEY__SEARCH, "search")
- S_(SECCLASS_KEY, KEY__LINK, "link")
- S_(SECCLASS_KEY, KEY__SETATTR, "setattr")
- S_(SECCLASS_KEY, KEY__CREATE, "create")
- S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NODE_BIND, "node_bind")
- S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NAME_CONNECT, "name_connect")
- S_(SECCLASS_MEMPROTECT, MEMPROTECT__MMAP_ZERO, "mmap_zero")
- S_(SECCLASS_PEER, PEER__RECV, "recv")
- S_(SECCLASS_KERNEL_SERVICE, KERNEL_SERVICE__USE_AS_OVERRIDE, "use_as_override")
- S_(SECCLASS_KERNEL_SERVICE, KERNEL_SERVICE__CREATE_FILES_AS, "create_files_as")
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
deleted file mode 100644
index 0546d616ccac..000000000000
--- a/security/selinux/include/av_permissions.h
+++ /dev/null
@@ -1,870 +0,0 @@
-/* This file is automatically generated. Do not edit. */
-#define COMMON_FILE__IOCTL 0x00000001UL
-#define COMMON_FILE__READ 0x00000002UL
-#define COMMON_FILE__WRITE 0x00000004UL
-#define COMMON_FILE__CREATE 0x00000008UL
-#define COMMON_FILE__GETATTR 0x00000010UL
-#define COMMON_FILE__SETATTR 0x00000020UL
-#define COMMON_FILE__LOCK 0x00000040UL
-#define COMMON_FILE__RELABELFROM 0x00000080UL
-#define COMMON_FILE__RELABELTO 0x00000100UL
-#define COMMON_FILE__APPEND 0x00000200UL
-#define COMMON_FILE__UNLINK 0x00000400UL
-#define COMMON_FILE__LINK 0x00000800UL
-#define COMMON_FILE__RENAME 0x00001000UL
-#define COMMON_FILE__EXECUTE 0x00002000UL
-#define COMMON_FILE__SWAPON 0x00004000UL
-#define COMMON_FILE__QUOTAON 0x00008000UL
-#define COMMON_FILE__MOUNTON 0x00010000UL
-#define COMMON_SOCKET__IOCTL 0x00000001UL
-#define COMMON_SOCKET__READ 0x00000002UL
-#define COMMON_SOCKET__WRITE 0x00000004UL
-#define COMMON_SOCKET__CREATE 0x00000008UL
-#define COMMON_SOCKET__GETATTR 0x00000010UL
-#define COMMON_SOCKET__SETATTR 0x00000020UL
-#define COMMON_SOCKET__LOCK 0x00000040UL
-#define COMMON_SOCKET__RELABELFROM 0x00000080UL
-#define COMMON_SOCKET__RELABELTO 0x00000100UL
-#define COMMON_SOCKET__APPEND 0x00000200UL
-#define COMMON_SOCKET__BIND 0x00000400UL
-#define COMMON_SOCKET__CONNECT 0x00000800UL
-#define COMMON_SOCKET__LISTEN 0x00001000UL
-#define COMMON_SOCKET__ACCEPT 0x00002000UL
-#define COMMON_SOCKET__GETOPT 0x00004000UL
-#define COMMON_SOCKET__SETOPT 0x00008000UL
-#define COMMON_SOCKET__SHUTDOWN 0x00010000UL
-#define COMMON_SOCKET__RECVFROM 0x00020000UL
-#define COMMON_SOCKET__SENDTO 0x00040000UL
-#define COMMON_SOCKET__RECV_MSG 0x00080000UL
-#define COMMON_SOCKET__SEND_MSG 0x00100000UL
-#define COMMON_SOCKET__NAME_BIND 0x00200000UL
-#define COMMON_IPC__CREATE 0x00000001UL
-#define COMMON_IPC__DESTROY 0x00000002UL
-#define COMMON_IPC__GETATTR 0x00000004UL
-#define COMMON_IPC__SETATTR 0x00000008UL
-#define COMMON_IPC__READ 0x00000010UL
-#define COMMON_IPC__WRITE 0x00000020UL
-#define COMMON_IPC__ASSOCIATE 0x00000040UL
-#define COMMON_IPC__UNIX_READ 0x00000080UL
-#define COMMON_IPC__UNIX_WRITE 0x00000100UL
-#define FILESYSTEM__MOUNT 0x00000001UL
-#define FILESYSTEM__REMOUNT 0x00000002UL
-#define FILESYSTEM__UNMOUNT 0x00000004UL
-#define FILESYSTEM__GETATTR 0x00000008UL
-#define FILESYSTEM__RELABELFROM 0x00000010UL
-#define FILESYSTEM__RELABELTO 0x00000020UL
-#define FILESYSTEM__TRANSITION 0x00000040UL
-#define FILESYSTEM__ASSOCIATE 0x00000080UL
-#define FILESYSTEM__QUOTAMOD 0x00000100UL
-#define FILESYSTEM__QUOTAGET 0x00000200UL
-#define DIR__IOCTL 0x00000001UL
-#define DIR__READ 0x00000002UL
-#define DIR__WRITE 0x00000004UL
-#define DIR__CREATE 0x00000008UL
-#define DIR__GETATTR 0x00000010UL
-#define DIR__SETATTR 0x00000020UL
-#define DIR__LOCK 0x00000040UL
-#define DIR__RELABELFROM 0x00000080UL
-#define DIR__RELABELTO 0x00000100UL
-#define DIR__APPEND 0x00000200UL
-#define DIR__UNLINK 0x00000400UL
-#define DIR__LINK 0x00000800UL
-#define DIR__RENAME 0x00001000UL
-#define DIR__EXECUTE 0x00002000UL
-#define DIR__SWAPON 0x00004000UL
-#define DIR__QUOTAON 0x00008000UL
-#define DIR__MOUNTON 0x00010000UL
-#define DIR__ADD_NAME 0x00020000UL
-#define DIR__REMOVE_NAME 0x00040000UL
-#define DIR__REPARENT 0x00080000UL
-#define DIR__SEARCH 0x00100000UL
-#define DIR__RMDIR 0x00200000UL
-#define DIR__OPEN 0x00400000UL
-#define FILE__IOCTL 0x00000001UL
-#define FILE__READ 0x00000002UL
-#define FILE__WRITE 0x00000004UL
-#define FILE__CREATE 0x00000008UL
-#define FILE__GETATTR 0x00000010UL
-#define FILE__SETATTR 0x00000020UL
-#define FILE__LOCK 0x00000040UL
-#define FILE__RELABELFROM 0x00000080UL
-#define FILE__RELABELTO 0x00000100UL
-#define FILE__APPEND 0x00000200UL
-#define FILE__UNLINK 0x00000400UL
-#define FILE__LINK 0x00000800UL
-#define FILE__RENAME 0x00001000UL
-#define FILE__EXECUTE 0x00002000UL
-#define FILE__SWAPON 0x00004000UL
-#define FILE__QUOTAON 0x00008000UL
-#define FILE__MOUNTON 0x00010000UL
-#define FILE__EXECUTE_NO_TRANS 0x00020000UL
-#define FILE__ENTRYPOINT 0x00040000UL
-#define FILE__EXECMOD 0x00080000UL
-#define FILE__OPEN 0x00100000UL
-#define LNK_FILE__IOCTL 0x00000001UL
-#define LNK_FILE__READ 0x00000002UL
-#define LNK_FILE__WRITE 0x00000004UL
-#define LNK_FILE__CREATE 0x00000008UL
-#define LNK_FILE__GETATTR 0x00000010UL
-#define LNK_FILE__SETATTR 0x00000020UL
-#define LNK_FILE__LOCK 0x00000040UL
-#define LNK_FILE__RELABELFROM 0x00000080UL
-#define LNK_FILE__RELABELTO 0x00000100UL
-#define LNK_FILE__APPEND 0x00000200UL
-#define LNK_FILE__UNLINK 0x00000400UL
-#define LNK_FILE__LINK 0x00000800UL
-#define LNK_FILE__RENAME 0x00001000UL
-#define LNK_FILE__EXECUTE 0x00002000UL
-#define LNK_FILE__SWAPON 0x00004000UL
-#define LNK_FILE__QUOTAON 0x00008000UL
-#define LNK_FILE__MOUNTON 0x00010000UL
-#define CHR_FILE__IOCTL 0x00000001UL
-#define CHR_FILE__READ 0x00000002UL
-#define CHR_FILE__WRITE 0x00000004UL
-#define CHR_FILE__CREATE 0x00000008UL
-#define CHR_FILE__GETATTR 0x00000010UL
-#define CHR_FILE__SETATTR 0x00000020UL
-#define CHR_FILE__LOCK 0x00000040UL
-#define CHR_FILE__RELABELFROM 0x00000080UL
-#define CHR_FILE__RELABELTO 0x00000100UL
-#define CHR_FILE__APPEND 0x00000200UL
-#define CHR_FILE__UNLINK 0x00000400UL
-#define CHR_FILE__LINK 0x00000800UL
-#define CHR_FILE__RENAME 0x00001000UL
-#define CHR_FILE__EXECUTE 0x00002000UL
-#define CHR_FILE__SWAPON 0x00004000UL
-#define CHR_FILE__QUOTAON 0x00008000UL
-#define CHR_FILE__MOUNTON 0x00010000UL
-#define CHR_FILE__EXECUTE_NO_TRANS 0x00020000UL
-#define CHR_FILE__ENTRYPOINT 0x00040000UL
-#define CHR_FILE__EXECMOD 0x00080000UL
-#define CHR_FILE__OPEN 0x00100000UL
-#define BLK_FILE__IOCTL 0x00000001UL
-#define BLK_FILE__READ 0x00000002UL
-#define BLK_FILE__WRITE 0x00000004UL
-#define BLK_FILE__CREATE 0x00000008UL
-#define BLK_FILE__GETATTR 0x00000010UL
-#define BLK_FILE__SETATTR 0x00000020UL
-#define BLK_FILE__LOCK 0x00000040UL
-#define BLK_FILE__RELABELFROM 0x00000080UL
-#define BLK_FILE__RELABELTO 0x00000100UL
-#define BLK_FILE__APPEND 0x00000200UL
-#define BLK_FILE__UNLINK 0x00000400UL
-#define BLK_FILE__LINK 0x00000800UL
-#define BLK_FILE__RENAME 0x00001000UL
-#define BLK_FILE__EXECUTE 0x00002000UL
-#define BLK_FILE__SWAPON 0x00004000UL
-#define BLK_FILE__QUOTAON 0x00008000UL
-#define BLK_FILE__MOUNTON 0x00010000UL
-#define BLK_FILE__OPEN 0x00020000UL
-#define SOCK_FILE__IOCTL 0x00000001UL
-#define SOCK_FILE__READ 0x00000002UL
-#define SOCK_FILE__WRITE 0x00000004UL
-#define SOCK_FILE__CREATE 0x00000008UL
-#define SOCK_FILE__GETATTR 0x00000010UL
-#define SOCK_FILE__SETATTR 0x00000020UL
-#define SOCK_FILE__LOCK 0x00000040UL
-#define SOCK_FILE__RELABELFROM 0x00000080UL
-#define SOCK_FILE__RELABELTO 0x00000100UL
-#define SOCK_FILE__APPEND 0x00000200UL
-#define SOCK_FILE__UNLINK 0x00000400UL
-#define SOCK_FILE__LINK 0x00000800UL
-#define SOCK_FILE__RENAME 0x00001000UL
-#define SOCK_FILE__EXECUTE 0x00002000UL
-#define SOCK_FILE__SWAPON 0x00004000UL
-#define SOCK_FILE__QUOTAON 0x00008000UL
-#define SOCK_FILE__MOUNTON 0x00010000UL
-#define SOCK_FILE__OPEN 0x00020000UL
-#define FIFO_FILE__IOCTL 0x00000001UL
-#define FIFO_FILE__READ 0x00000002UL
-#define FIFO_FILE__WRITE 0x00000004UL
-#define FIFO_FILE__CREATE 0x00000008UL
-#define FIFO_FILE__GETATTR 0x00000010UL
-#define FIFO_FILE__SETATTR 0x00000020UL
-#define FIFO_FILE__LOCK 0x00000040UL
-#define FIFO_FILE__RELABELFROM 0x00000080UL
-#define FIFO_FILE__RELABELTO 0x00000100UL
-#define FIFO_FILE__APPEND 0x00000200UL
-#define FIFO_FILE__UNLINK 0x00000400UL
-#define FIFO_FILE__LINK 0x00000800UL
-#define FIFO_FILE__RENAME 0x00001000UL
-#define FIFO_FILE__EXECUTE 0x00002000UL
-#define FIFO_FILE__SWAPON 0x00004000UL
-#define FIFO_FILE__QUOTAON 0x00008000UL
-#define FIFO_FILE__MOUNTON 0x00010000UL
-#define FIFO_FILE__OPEN 0x00020000UL
-#define FD__USE 0x00000001UL
-#define SOCKET__IOCTL 0x00000001UL
-#define SOCKET__READ 0x00000002UL
-#define SOCKET__WRITE 0x00000004UL
-#define SOCKET__CREATE 0x00000008UL
-#define SOCKET__GETATTR 0x00000010UL
-#define SOCKET__SETATTR 0x00000020UL
-#define SOCKET__LOCK 0x00000040UL
-#define SOCKET__RELABELFROM 0x00000080UL
-#define SOCKET__RELABELTO 0x00000100UL
-#define SOCKET__APPEND 0x00000200UL
-#define SOCKET__BIND 0x00000400UL
-#define SOCKET__CONNECT 0x00000800UL
-#define SOCKET__LISTEN 0x00001000UL
-#define SOCKET__ACCEPT 0x00002000UL
-#define SOCKET__GETOPT 0x00004000UL
-#define SOCKET__SETOPT 0x00008000UL
-#define SOCKET__SHUTDOWN 0x00010000UL
-#define SOCKET__RECVFROM 0x00020000UL
-#define SOCKET__SENDTO 0x00040000UL
-#define SOCKET__RECV_MSG 0x00080000UL
-#define SOCKET__SEND_MSG 0x00100000UL
-#define SOCKET__NAME_BIND 0x00200000UL
-#define TCP_SOCKET__IOCTL 0x00000001UL
-#define TCP_SOCKET__READ 0x00000002UL
-#define TCP_SOCKET__WRITE 0x00000004UL
-#define TCP_SOCKET__CREATE 0x00000008UL
-#define TCP_SOCKET__GETATTR 0x00000010UL
-#define TCP_SOCKET__SETATTR 0x00000020UL
-#define TCP_SOCKET__LOCK 0x00000040UL
-#define TCP_SOCKET__RELABELFROM 0x00000080UL
-#define TCP_SOCKET__RELABELTO 0x00000100UL
-#define TCP_SOCKET__APPEND 0x00000200UL
-#define TCP_SOCKET__BIND 0x00000400UL
-#define TCP_SOCKET__CONNECT 0x00000800UL
-#define TCP_SOCKET__LISTEN 0x00001000UL
-#define TCP_SOCKET__ACCEPT 0x00002000UL
-#define TCP_SOCKET__GETOPT 0x00004000UL
-#define TCP_SOCKET__SETOPT 0x00008000UL
-#define TCP_SOCKET__SHUTDOWN 0x00010000UL
-#define TCP_SOCKET__RECVFROM 0x00020000UL
-#define TCP_SOCKET__SENDTO 0x00040000UL
-#define TCP_SOCKET__RECV_MSG 0x00080000UL
-#define TCP_SOCKET__SEND_MSG 0x00100000UL
-#define TCP_SOCKET__NAME_BIND 0x00200000UL
-#define TCP_SOCKET__CONNECTTO 0x00400000UL
-#define TCP_SOCKET__NEWCONN 0x00800000UL
-#define TCP_SOCKET__ACCEPTFROM 0x01000000UL
-#define TCP_SOCKET__NODE_BIND 0x02000000UL
-#define TCP_SOCKET__NAME_CONNECT 0x04000000UL
-#define UDP_SOCKET__IOCTL 0x00000001UL
-#define UDP_SOCKET__READ 0x00000002UL
-#define UDP_SOCKET__WRITE 0x00000004UL
-#define UDP_SOCKET__CREATE 0x00000008UL
-#define UDP_SOCKET__GETATTR 0x00000010UL
-#define UDP_SOCKET__SETATTR 0x00000020UL
-#define UDP_SOCKET__LOCK 0x00000040UL
-#define UDP_SOCKET__RELABELFROM 0x00000080UL
-#define UDP_SOCKET__RELABELTO 0x00000100UL
-#define UDP_SOCKET__APPEND 0x00000200UL
-#define UDP_SOCKET__BIND 0x00000400UL
-#define UDP_SOCKET__CONNECT 0x00000800UL
-#define UDP_SOCKET__LISTEN 0x00001000UL
-#define UDP_SOCKET__ACCEPT 0x00002000UL
-#define UDP_SOCKET__GETOPT 0x00004000UL
-#define UDP_SOCKET__SETOPT 0x00008000UL
-#define UDP_SOCKET__SHUTDOWN 0x00010000UL
-#define UDP_SOCKET__RECVFROM 0x00020000UL
-#define UDP_SOCKET__SENDTO 0x00040000UL
-#define UDP_SOCKET__RECV_MSG 0x00080000UL
-#define UDP_SOCKET__SEND_MSG 0x00100000UL
-#define UDP_SOCKET__NAME_BIND 0x00200000UL
-#define UDP_SOCKET__NODE_BIND 0x00400000UL
-#define RAWIP_SOCKET__IOCTL 0x00000001UL
-#define RAWIP_SOCKET__READ 0x00000002UL
-#define RAWIP_SOCKET__WRITE 0x00000004UL
-#define RAWIP_SOCKET__CREATE 0x00000008UL
-#define RAWIP_SOCKET__GETATTR 0x00000010UL
-#define RAWIP_SOCKET__SETATTR 0x00000020UL
-#define RAWIP_SOCKET__LOCK 0x00000040UL
-#define RAWIP_SOCKET__RELABELFROM 0x00000080UL
-#define RAWIP_SOCKET__RELABELTO 0x00000100UL
-#define RAWIP_SOCKET__APPEND 0x00000200UL
-#define RAWIP_SOCKET__BIND 0x00000400UL
-#define RAWIP_SOCKET__CONNECT 0x00000800UL
-#define RAWIP_SOCKET__LISTEN 0x00001000UL
-#define RAWIP_SOCKET__ACCEPT 0x00002000UL
-#define RAWIP_SOCKET__GETOPT 0x00004000UL
-#define RAWIP_SOCKET__SETOPT 0x00008000UL
-#define RAWIP_SOCKET__SHUTDOWN 0x00010000UL
-#define RAWIP_SOCKET__RECVFROM 0x00020000UL
-#define RAWIP_SOCKET__SENDTO 0x00040000UL
-#define RAWIP_SOCKET__RECV_MSG 0x00080000UL
-#define RAWIP_SOCKET__SEND_MSG 0x00100000UL
-#define RAWIP_SOCKET__NAME_BIND 0x00200000UL
-#define RAWIP_SOCKET__NODE_BIND 0x00400000UL
-#define NODE__TCP_RECV 0x00000001UL
-#define NODE__TCP_SEND 0x00000002UL
-#define NODE__UDP_RECV 0x00000004UL
-#define NODE__UDP_SEND 0x00000008UL
-#define NODE__RAWIP_RECV 0x00000010UL
-#define NODE__RAWIP_SEND 0x00000020UL
-#define NODE__ENFORCE_DEST 0x00000040UL
-#define NODE__DCCP_RECV 0x00000080UL
-#define NODE__DCCP_SEND 0x00000100UL
-#define NODE__RECVFROM 0x00000200UL
-#define NODE__SENDTO 0x00000400UL
-#define NETIF__TCP_RECV 0x00000001UL
-#define NETIF__TCP_SEND 0x00000002UL
-#define NETIF__UDP_RECV 0x00000004UL
-#define NETIF__UDP_SEND 0x00000008UL
-#define NETIF__RAWIP_RECV 0x00000010UL
-#define NETIF__RAWIP_SEND 0x00000020UL
-#define NETIF__DCCP_RECV 0x00000040UL
-#define NETIF__DCCP_SEND 0x00000080UL
-#define NETIF__INGRESS 0x00000100UL
-#define NETIF__EGRESS 0x00000200UL
-#define NETLINK_SOCKET__IOCTL 0x00000001UL
-#define NETLINK_SOCKET__READ 0x00000002UL
-#define NETLINK_SOCKET__WRITE 0x00000004UL
-#define NETLINK_SOCKET__CREATE 0x00000008UL
-#define NETLINK_SOCKET__GETATTR 0x00000010UL
-#define NETLINK_SOCKET__SETATTR 0x00000020UL
-#define NETLINK_SOCKET__LOCK 0x00000040UL
-#define NETLINK_SOCKET__RELABELFROM 0x00000080UL
-#define NETLINK_SOCKET__RELABELTO 0x00000100UL
-#define NETLINK_SOCKET__APPEND 0x00000200UL
-#define NETLINK_SOCKET__BIND 0x00000400UL
-#define NETLINK_SOCKET__CONNECT 0x00000800UL
-#define NETLINK_SOCKET__LISTEN 0x00001000UL
-#define NETLINK_SOCKET__ACCEPT 0x00002000UL
-#define NETLINK_SOCKET__GETOPT 0x00004000UL
-#define NETLINK_SOCKET__SETOPT 0x00008000UL
-#define NETLINK_SOCKET__SHUTDOWN 0x00010000UL
-#define NETLINK_SOCKET__RECVFROM 0x00020000UL
-#define NETLINK_SOCKET__SENDTO 0x00040000UL
-#define NETLINK_SOCKET__RECV_MSG 0x00080000UL
-#define NETLINK_SOCKET__SEND_MSG 0x00100000UL
-#define NETLINK_SOCKET__NAME_BIND 0x00200000UL
-#define PACKET_SOCKET__IOCTL 0x00000001UL
-#define PACKET_SOCKET__READ 0x00000002UL
-#define PACKET_SOCKET__WRITE 0x00000004UL
-#define PACKET_SOCKET__CREATE 0x00000008UL
-#define PACKET_SOCKET__GETATTR 0x00000010UL
-#define PACKET_SOCKET__SETATTR 0x00000020UL
-#define PACKET_SOCKET__LOCK 0x00000040UL
-#define PACKET_SOCKET__RELABELFROM 0x00000080UL
-#define PACKET_SOCKET__RELABELTO 0x00000100UL
-#define PACKET_SOCKET__APPEND 0x00000200UL
-#define PACKET_SOCKET__BIND 0x00000400UL
-#define PACKET_SOCKET__CONNECT 0x00000800UL
-#define PACKET_SOCKET__LISTEN 0x00001000UL
-#define PACKET_SOCKET__ACCEPT 0x00002000UL
-#define PACKET_SOCKET__GETOPT 0x00004000UL
-#define PACKET_SOCKET__SETOPT 0x00008000UL
-#define PACKET_SOCKET__SHUTDOWN 0x00010000UL
-#define PACKET_SOCKET__RECVFROM 0x00020000UL
-#define PACKET_SOCKET__SENDTO 0x00040000UL
-#define PACKET_SOCKET__RECV_MSG 0x00080000UL
-#define PACKET_SOCKET__SEND_MSG 0x00100000UL
-#define PACKET_SOCKET__NAME_BIND 0x00200000UL
-#define KEY_SOCKET__IOCTL 0x00000001UL
-#define KEY_SOCKET__READ 0x00000002UL
-#define KEY_SOCKET__WRITE 0x00000004UL
-#define KEY_SOCKET__CREATE 0x00000008UL
-#define KEY_SOCKET__GETATTR 0x00000010UL
-#define KEY_SOCKET__SETATTR 0x00000020UL
-#define KEY_SOCKET__LOCK 0x00000040UL
-#define KEY_SOCKET__RELABELFROM 0x00000080UL
-#define KEY_SOCKET__RELABELTO 0x00000100UL
-#define KEY_SOCKET__APPEND 0x00000200UL
-#define KEY_SOCKET__BIND 0x00000400UL
-#define KEY_SOCKET__CONNECT 0x00000800UL
-#define KEY_SOCKET__LISTEN 0x00001000UL
-#define KEY_SOCKET__ACCEPT 0x00002000UL
-#define KEY_SOCKET__GETOPT 0x00004000UL
-#define KEY_SOCKET__SETOPT 0x00008000UL
-#define KEY_SOCKET__SHUTDOWN 0x00010000UL
-#define KEY_SOCKET__RECVFROM 0x00020000UL
-#define KEY_SOCKET__SENDTO 0x00040000UL
-#define KEY_SOCKET__RECV_MSG 0x00080000UL
-#define KEY_SOCKET__SEND_MSG 0x00100000UL
-#define KEY_SOCKET__NAME_BIND 0x00200000UL
-#define UNIX_STREAM_SOCKET__IOCTL 0x00000001UL
-#define UNIX_STREAM_SOCKET__READ 0x00000002UL
-#define UNIX_STREAM_SOCKET__WRITE 0x00000004UL
-#define UNIX_STREAM_SOCKET__CREATE 0x00000008UL
-#define UNIX_STREAM_SOCKET__GETATTR 0x00000010UL
-#define UNIX_STREAM_SOCKET__SETATTR 0x00000020UL
-#define UNIX_STREAM_SOCKET__LOCK 0x00000040UL
-#define UNIX_STREAM_SOCKET__RELABELFROM 0x00000080UL
-#define UNIX_STREAM_SOCKET__RELABELTO 0x00000100UL
-#define UNIX_STREAM_SOCKET__APPEND 0x00000200UL
-#define UNIX_STREAM_SOCKET__BIND 0x00000400UL
-#define UNIX_STREAM_SOCKET__CONNECT 0x00000800UL
-#define UNIX_STREAM_SOCKET__LISTEN 0x00001000UL
-#define UNIX_STREAM_SOCKET__ACCEPT 0x00002000UL
-#define UNIX_STREAM_SOCKET__GETOPT 0x00004000UL
-#define UNIX_STREAM_SOCKET__SETOPT 0x00008000UL
-#define UNIX_STREAM_SOCKET__SHUTDOWN 0x00010000UL
-#define UNIX_STREAM_SOCKET__RECVFROM 0x00020000UL
-#define UNIX_STREAM_SOCKET__SENDTO 0x00040000UL
-#define UNIX_STREAM_SOCKET__RECV_MSG 0x00080000UL
-#define UNIX_STREAM_SOCKET__SEND_MSG 0x00100000UL
-#define UNIX_STREAM_SOCKET__NAME_BIND 0x00200000UL
-#define UNIX_STREAM_SOCKET__CONNECTTO 0x00400000UL
-#define UNIX_STREAM_SOCKET__NEWCONN 0x00800000UL
-#define UNIX_STREAM_SOCKET__ACCEPTFROM 0x01000000UL
-#define UNIX_DGRAM_SOCKET__IOCTL 0x00000001UL
-#define UNIX_DGRAM_SOCKET__READ 0x00000002UL
-#define UNIX_DGRAM_SOCKET__WRITE 0x00000004UL
-#define UNIX_DGRAM_SOCKET__CREATE 0x00000008UL
-#define UNIX_DGRAM_SOCKET__GETATTR 0x00000010UL
-#define UNIX_DGRAM_SOCKET__SETATTR 0x00000020UL
-#define UNIX_DGRAM_SOCKET__LOCK 0x00000040UL
-#define UNIX_DGRAM_SOCKET__RELABELFROM 0x00000080UL
-#define UNIX_DGRAM_SOCKET__RELABELTO 0x00000100UL
-#define UNIX_DGRAM_SOCKET__APPEND 0x00000200UL
-#define UNIX_DGRAM_SOCKET__BIND 0x00000400UL
-#define UNIX_DGRAM_SOCKET__CONNECT 0x00000800UL
-#define UNIX_DGRAM_SOCKET__LISTEN 0x00001000UL
-#define UNIX_DGRAM_SOCKET__ACCEPT 0x00002000UL
-#define UNIX_DGRAM_SOCKET__GETOPT 0x00004000UL
-#define UNIX_DGRAM_SOCKET__SETOPT 0x00008000UL
-#define UNIX_DGRAM_SOCKET__SHUTDOWN 0x00010000UL
-#define UNIX_DGRAM_SOCKET__RECVFROM 0x00020000UL
-#define UNIX_DGRAM_SOCKET__SENDTO 0x00040000UL
-#define UNIX_DGRAM_SOCKET__RECV_MSG 0x00080000UL
-#define UNIX_DGRAM_SOCKET__SEND_MSG 0x00100000UL
-#define UNIX_DGRAM_SOCKET__NAME_BIND 0x00200000UL
-#define TUN_SOCKET__IOCTL 0x00000001UL
-#define TUN_SOCKET__READ 0x00000002UL
-#define TUN_SOCKET__WRITE 0x00000004UL
-#define TUN_SOCKET__CREATE 0x00000008UL
-#define TUN_SOCKET__GETATTR 0x00000010UL
-#define TUN_SOCKET__SETATTR 0x00000020UL
-#define TUN_SOCKET__LOCK 0x00000040UL
-#define TUN_SOCKET__RELABELFROM 0x00000080UL
-#define TUN_SOCKET__RELABELTO 0x00000100UL
-#define TUN_SOCKET__APPEND 0x00000200UL
-#define TUN_SOCKET__BIND 0x00000400UL
-#define TUN_SOCKET__CONNECT 0x00000800UL
-#define TUN_SOCKET__LISTEN 0x00001000UL
-#define TUN_SOCKET__ACCEPT 0x00002000UL
-#define TUN_SOCKET__GETOPT 0x00004000UL
-#define TUN_SOCKET__SETOPT 0x00008000UL
-#define TUN_SOCKET__SHUTDOWN 0x00010000UL
-#define TUN_SOCKET__RECVFROM 0x00020000UL
-#define TUN_SOCKET__SENDTO 0x00040000UL
-#define TUN_SOCKET__RECV_MSG 0x00080000UL
-#define TUN_SOCKET__SEND_MSG 0x00100000UL
-#define TUN_SOCKET__NAME_BIND 0x00200000UL
-#define PROCESS__FORK 0x00000001UL
-#define PROCESS__TRANSITION 0x00000002UL
-#define PROCESS__SIGCHLD 0x00000004UL
-#define PROCESS__SIGKILL 0x00000008UL
-#define PROCESS__SIGSTOP 0x00000010UL
-#define PROCESS__SIGNULL 0x00000020UL
-#define PROCESS__SIGNAL 0x00000040UL
-#define PROCESS__PTRACE 0x00000080UL
-#define PROCESS__GETSCHED 0x00000100UL
-#define PROCESS__SETSCHED 0x00000200UL
-#define PROCESS__GETSESSION 0x00000400UL
-#define PROCESS__GETPGID 0x00000800UL
-#define PROCESS__SETPGID 0x00001000UL
-#define PROCESS__GETCAP 0x00002000UL
-#define PROCESS__SETCAP 0x00004000UL
-#define PROCESS__SHARE 0x00008000UL
-#define PROCESS__GETATTR 0x00010000UL
-#define PROCESS__SETEXEC 0x00020000UL
-#define PROCESS__SETFSCREATE 0x00040000UL
-#define PROCESS__NOATSECURE 0x00080000UL
-#define PROCESS__SIGINH 0x00100000UL
-#define PROCESS__SETRLIMIT 0x00200000UL
-#define PROCESS__RLIMITINH 0x00400000UL
-#define PROCESS__DYNTRANSITION 0x00800000UL
-#define PROCESS__SETCURRENT 0x01000000UL
-#define PROCESS__EXECMEM 0x02000000UL
-#define PROCESS__EXECSTACK 0x04000000UL
-#define PROCESS__EXECHEAP 0x08000000UL
-#define PROCESS__SETKEYCREATE 0x10000000UL
-#define PROCESS__SETSOCKCREATE 0x20000000UL
-#define IPC__CREATE 0x00000001UL
-#define IPC__DESTROY 0x00000002UL
-#define IPC__GETATTR 0x00000004UL
-#define IPC__SETATTR 0x00000008UL
-#define IPC__READ 0x00000010UL
-#define IPC__WRITE 0x00000020UL
-#define IPC__ASSOCIATE 0x00000040UL
-#define IPC__UNIX_READ 0x00000080UL
-#define IPC__UNIX_WRITE 0x00000100UL
-#define SEM__CREATE 0x00000001UL
-#define SEM__DESTROY 0x00000002UL
-#define SEM__GETATTR 0x00000004UL
-#define SEM__SETATTR 0x00000008UL
-#define SEM__READ 0x00000010UL
-#define SEM__WRITE 0x00000020UL
-#define SEM__ASSOCIATE 0x00000040UL
-#define SEM__UNIX_READ 0x00000080UL
-#define SEM__UNIX_WRITE 0x00000100UL
-#define MSGQ__CREATE 0x00000001UL
-#define MSGQ__DESTROY 0x00000002UL
-#define MSGQ__GETATTR 0x00000004UL
-#define MSGQ__SETATTR 0x00000008UL
-#define MSGQ__READ 0x00000010UL
-#define MSGQ__WRITE 0x00000020UL
-#define MSGQ__ASSOCIATE 0x00000040UL
-#define MSGQ__UNIX_READ 0x00000080UL
-#define MSGQ__UNIX_WRITE 0x00000100UL
-#define MSGQ__ENQUEUE 0x00000200UL
-#define MSG__SEND 0x00000001UL
-#define MSG__RECEIVE 0x00000002UL
-#define SHM__CREATE 0x00000001UL
-#define SHM__DESTROY 0x00000002UL
-#define SHM__GETATTR 0x00000004UL
-#define SHM__SETATTR 0x00000008UL
-#define SHM__READ 0x00000010UL
-#define SHM__WRITE 0x00000020UL
-#define SHM__ASSOCIATE 0x00000040UL
-#define SHM__UNIX_READ 0x00000080UL
-#define SHM__UNIX_WRITE 0x00000100UL
-#define SHM__LOCK 0x00000200UL
-#define SECURITY__COMPUTE_AV 0x00000001UL
-#define SECURITY__COMPUTE_CREATE 0x00000002UL
-#define SECURITY__COMPUTE_MEMBER 0x00000004UL
-#define SECURITY__CHECK_CONTEXT 0x00000008UL
-#define SECURITY__LOAD_POLICY 0x00000010UL
-#define SECURITY__COMPUTE_RELABEL 0x00000020UL
-#define SECURITY__COMPUTE_USER 0x00000040UL
-#define SECURITY__SETENFORCE 0x00000080UL
-#define SECURITY__SETBOOL 0x00000100UL
-#define SECURITY__SETSECPARAM 0x00000200UL
-#define SECURITY__SETCHECKREQPROT 0x00000400UL
-#define SYSTEM__IPC_INFO 0x00000001UL
-#define SYSTEM__SYSLOG_READ 0x00000002UL
-#define SYSTEM__SYSLOG_MOD 0x00000004UL
-#define SYSTEM__SYSLOG_CONSOLE 0x00000008UL
-#define SYSTEM__MODULE_REQUEST 0x00000010UL
-#define CAPABILITY__CHOWN 0x00000001UL
-#define CAPABILITY__DAC_OVERRIDE 0x00000002UL
-#define CAPABILITY__DAC_READ_SEARCH 0x00000004UL
-#define CAPABILITY__FOWNER 0x00000008UL
-#define CAPABILITY__FSETID 0x00000010UL
-#define CAPABILITY__KILL 0x00000020UL
-#define CAPABILITY__SETGID 0x00000040UL
-#define CAPABILITY__SETUID 0x00000080UL
-#define CAPABILITY__SETPCAP 0x00000100UL
-#define CAPABILITY__LINUX_IMMUTABLE 0x00000200UL
-#define CAPABILITY__NET_BIND_SERVICE 0x00000400UL
-#define CAPABILITY__NET_BROADCAST 0x00000800UL
-#define CAPABILITY__NET_ADMIN 0x00001000UL
-#define CAPABILITY__NET_RAW 0x00002000UL
-#define CAPABILITY__IPC_LOCK 0x00004000UL
-#define CAPABILITY__IPC_OWNER 0x00008000UL
-#define CAPABILITY__SYS_MODULE 0x00010000UL
-#define CAPABILITY__SYS_RAWIO 0x00020000UL
-#define CAPABILITY__SYS_CHROOT 0x00040000UL
-#define CAPABILITY__SYS_PTRACE 0x00080000UL
-#define CAPABILITY__SYS_PACCT 0x00100000UL
-#define CAPABILITY__SYS_ADMIN 0x00200000UL
-#define CAPABILITY__SYS_BOOT 0x00400000UL
-#define CAPABILITY__SYS_NICE 0x00800000UL
-#define CAPABILITY__SYS_RESOURCE 0x01000000UL
-#define CAPABILITY__SYS_TIME 0x02000000UL
-#define CAPABILITY__SYS_TTY_CONFIG 0x04000000UL
-#define CAPABILITY__MKNOD 0x08000000UL
-#define CAPABILITY__LEASE 0x10000000UL
-#define CAPABILITY__AUDIT_WRITE 0x20000000UL
-#define CAPABILITY__AUDIT_CONTROL 0x40000000UL
-#define CAPABILITY__SETFCAP 0x80000000UL
-#define CAPABILITY2__MAC_OVERRIDE 0x00000001UL
-#define CAPABILITY2__MAC_ADMIN 0x00000002UL
-#define NETLINK_ROUTE_SOCKET__IOCTL 0x00000001UL
-#define NETLINK_ROUTE_SOCKET__READ 0x00000002UL
-#define NETLINK_ROUTE_SOCKET__WRITE 0x00000004UL
-#define NETLINK_ROUTE_SOCKET__CREATE 0x00000008UL
-#define NETLINK_ROUTE_SOCKET__GETATTR 0x00000010UL
-#define NETLINK_ROUTE_SOCKET__SETATTR 0x00000020UL
-#define NETLINK_ROUTE_SOCKET__LOCK 0x00000040UL
-#define NETLINK_ROUTE_SOCKET__RELABELFROM 0x00000080UL
-#define NETLINK_ROUTE_SOCKET__RELABELTO 0x00000100UL
-#define NETLINK_ROUTE_SOCKET__APPEND 0x00000200UL
-#define NETLINK_ROUTE_SOCKET__BIND 0x00000400UL
-#define NETLINK_ROUTE_SOCKET__CONNECT 0x00000800UL
-#define NETLINK_ROUTE_SOCKET__LISTEN 0x00001000UL
-#define NETLINK_ROUTE_SOCKET__ACCEPT 0x00002000UL
-#define NETLINK_ROUTE_SOCKET__GETOPT 0x00004000UL
-#define NETLINK_ROUTE_SOCKET__SETOPT 0x00008000UL
-#define NETLINK_ROUTE_SOCKET__SHUTDOWN 0x00010000UL
-#define NETLINK_ROUTE_SOCKET__RECVFROM 0x00020000UL
-#define NETLINK_ROUTE_SOCKET__SENDTO 0x00040000UL
-#define NETLINK_ROUTE_SOCKET__RECV_MSG 0x00080000UL
-#define NETLINK_ROUTE_SOCKET__SEND_MSG 0x00100000UL
-#define NETLINK_ROUTE_SOCKET__NAME_BIND 0x00200000UL
-#define NETLINK_ROUTE_SOCKET__NLMSG_READ 0x00400000UL
-#define NETLINK_ROUTE_SOCKET__NLMSG_WRITE 0x00800000UL
-#define NETLINK_FIREWALL_SOCKET__IOCTL 0x00000001UL
-#define NETLINK_FIREWALL_SOCKET__READ 0x00000002UL
-#define NETLINK_FIREWALL_SOCKET__WRITE 0x00000004UL
-#define NETLINK_FIREWALL_SOCKET__CREATE 0x00000008UL
-#define NETLINK_FIREWALL_SOCKET__GETATTR 0x00000010UL
-#define NETLINK_FIREWALL_SOCKET__SETATTR 0x00000020UL
-#define NETLINK_FIREWALL_SOCKET__LOCK 0x00000040UL
-#define NETLINK_FIREWALL_SOCKET__RELABELFROM 0x00000080UL
-#define NETLINK_FIREWALL_SOCKET__RELABELTO 0x00000100UL
-#define NETLINK_FIREWALL_SOCKET__APPEND 0x00000200UL
-#define NETLINK_FIREWALL_SOCKET__BIND 0x00000400UL
-#define NETLINK_FIREWALL_SOCKET__CONNECT 0x00000800UL
-#define NETLINK_FIREWALL_SOCKET__LISTEN 0x00001000UL
-#define NETLINK_FIREWALL_SOCKET__ACCEPT 0x00002000UL
-#define NETLINK_FIREWALL_SOCKET__GETOPT 0x00004000UL
-#define NETLINK_FIREWALL_SOCKET__SETOPT 0x00008000UL
-#define NETLINK_FIREWALL_SOCKET__SHUTDOWN 0x00010000UL
-#define NETLINK_FIREWALL_SOCKET__RECVFROM 0x00020000UL
-#define NETLINK_FIREWALL_SOCKET__SENDTO 0x00040000UL
-#define NETLINK_FIREWALL_SOCKET__RECV_MSG 0x00080000UL
-#define NETLINK_FIREWALL_SOCKET__SEND_MSG 0x00100000UL
-#define NETLINK_FIREWALL_SOCKET__NAME_BIND 0x00200000UL
-#define NETLINK_FIREWALL_SOCKET__NLMSG_READ 0x00400000UL
-#define NETLINK_FIREWALL_SOCKET__NLMSG_WRITE 0x00800000UL
-#define NETLINK_TCPDIAG_SOCKET__IOCTL 0x00000001UL
-#define NETLINK_TCPDIAG_SOCKET__READ 0x00000002UL
-#define NETLINK_TCPDIAG_SOCKET__WRITE 0x00000004UL
-#define NETLINK_TCPDIAG_SOCKET__CREATE 0x00000008UL
-#define NETLINK_TCPDIAG_SOCKET__GETATTR 0x00000010UL
-#define NETLINK_TCPDIAG_SOCKET__SETATTR 0x00000020UL
-#define NETLINK_TCPDIAG_SOCKET__LOCK 0x00000040UL
-#define NETLINK_TCPDIAG_SOCKET__RELABELFROM 0x00000080UL
-#define NETLINK_TCPDIAG_SOCKET__RELABELTO 0x00000100UL
-#define NETLINK_TCPDIAG_SOCKET__APPEND 0x00000200UL
-#define NETLINK_TCPDIAG_SOCKET__BIND 0x00000400UL
-#define NETLINK_TCPDIAG_SOCKET__CONNECT 0x00000800UL
-#define NETLINK_TCPDIAG_SOCKET__LISTEN 0x00001000UL
-#define NETLINK_TCPDIAG_SOCKET__ACCEPT 0x00002000UL
-#define NETLINK_TCPDIAG_SOCKET__GETOPT 0x00004000UL
-#define NETLINK_TCPDIAG_SOCKET__SETOPT 0x00008000UL
-#define NETLINK_TCPDIAG_SOCKET__SHUTDOWN 0x00010000UL
-#define NETLINK_TCPDIAG_SOCKET__RECVFROM 0x00020000UL
-#define NETLINK_TCPDIAG_SOCKET__SENDTO 0x00040000UL
-#define NETLINK_TCPDIAG_SOCKET__RECV_MSG 0x00080000UL
-#define NETLINK_TCPDIAG_SOCKET__SEND_MSG 0x00100000UL
-#define NETLINK_TCPDIAG_SOCKET__NAME_BIND 0x00200000UL
-#define NETLINK_TCPDIAG_SOCKET__NLMSG_READ 0x00400000UL
-#define NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE 0x00800000UL
-#define NETLINK_NFLOG_SOCKET__IOCTL 0x00000001UL
-#define NETLINK_NFLOG_SOCKET__READ 0x00000002UL
-#define NETLINK_NFLOG_SOCKET__WRITE 0x00000004UL
-#define NETLINK_NFLOG_SOCKET__CREATE 0x00000008UL
-#define NETLINK_NFLOG_SOCKET__GETATTR 0x00000010UL
-#define NETLINK_NFLOG_SOCKET__SETATTR 0x00000020UL
-#define NETLINK_NFLOG_SOCKET__LOCK 0x00000040UL
-#define NETLINK_NFLOG_SOCKET__RELABELFROM 0x00000080UL
-#define NETLINK_NFLOG_SOCKET__RELABELTO 0x00000100UL
-#define NETLINK_NFLOG_SOCKET__APPEND 0x00000200UL
-#define NETLINK_NFLOG_SOCKET__BIND 0x00000400UL
-#define NETLINK_NFLOG_SOCKET__CONNECT 0x00000800UL
-#define NETLINK_NFLOG_SOCKET__LISTEN 0x00001000UL
-#define NETLINK_NFLOG_SOCKET__ACCEPT 0x00002000UL
-#define NETLINK_NFLOG_SOCKET__GETOPT 0x00004000UL
-#define NETLINK_NFLOG_SOCKET__SETOPT 0x00008000UL
-#define NETLINK_NFLOG_SOCKET__SHUTDOWN 0x00010000UL
-#define NETLINK_NFLOG_SOCKET__RECVFROM 0x00020000UL
-#define NETLINK_NFLOG_SOCKET__SENDTO 0x00040000UL
-#define NETLINK_NFLOG_SOCKET__RECV_MSG 0x00080000UL
-#define NETLINK_NFLOG_SOCKET__SEND_MSG 0x00100000UL
-#define NETLINK_NFLOG_SOCKET__NAME_BIND 0x00200000UL
-#define NETLINK_XFRM_SOCKET__IOCTL 0x00000001UL
-#define NETLINK_XFRM_SOCKET__READ 0x00000002UL
-#define NETLINK_XFRM_SOCKET__WRITE 0x00000004UL
-#define NETLINK_XFRM_SOCKET__CREATE 0x00000008UL
-#define NETLINK_XFRM_SOCKET__GETATTR 0x00000010UL
-#define NETLINK_XFRM_SOCKET__SETATTR 0x00000020UL
-#define NETLINK_XFRM_SOCKET__LOCK 0x00000040UL
-#define NETLINK_XFRM_SOCKET__RELABELFROM 0x00000080UL
-#define NETLINK_XFRM_SOCKET__RELABELTO 0x00000100UL
-#define NETLINK_XFRM_SOCKET__APPEND 0x00000200UL
-#define NETLINK_XFRM_SOCKET__BIND 0x00000400UL
-#define NETLINK_XFRM_SOCKET__CONNECT 0x00000800UL
-#define NETLINK_XFRM_SOCKET__LISTEN 0x00001000UL
-#define NETLINK_XFRM_SOCKET__ACCEPT 0x00002000UL
-#define NETLINK_XFRM_SOCKET__GETOPT 0x00004000UL
-#define NETLINK_XFRM_SOCKET__SETOPT 0x00008000UL
-#define NETLINK_XFRM_SOCKET__SHUTDOWN 0x00010000UL
-#define NETLINK_XFRM_SOCKET__RECVFROM 0x00020000UL
-#define NETLINK_XFRM_SOCKET__SENDTO 0x00040000UL
-#define NETLINK_XFRM_SOCKET__RECV_MSG 0x00080000UL
-#define NETLINK_XFRM_SOCKET__SEND_MSG 0x00100000UL
-#define NETLINK_XFRM_SOCKET__NAME_BIND 0x00200000UL
-#define NETLINK_XFRM_SOCKET__NLMSG_READ 0x00400000UL
-#define NETLINK_XFRM_SOCKET__NLMSG_WRITE 0x00800000UL
-#define NETLINK_SELINUX_SOCKET__IOCTL 0x00000001UL
-#define NETLINK_SELINUX_SOCKET__READ 0x00000002UL
-#define NETLINK_SELINUX_SOCKET__WRITE 0x00000004UL
-#define NETLINK_SELINUX_SOCKET__CREATE 0x00000008UL
-#define NETLINK_SELINUX_SOCKET__GETATTR 0x00000010UL
-#define NETLINK_SELINUX_SOCKET__SETATTR 0x00000020UL
-#define NETLINK_SELINUX_SOCKET__LOCK 0x00000040UL
-#define NETLINK_SELINUX_SOCKET__RELABELFROM 0x00000080UL
-#define NETLINK_SELINUX_SOCKET__RELABELTO 0x00000100UL
-#define NETLINK_SELINUX_SOCKET__APPEND 0x00000200UL
-#define NETLINK_SELINUX_SOCKET__BIND 0x00000400UL
-#define NETLINK_SELINUX_SOCKET__CONNECT 0x00000800UL
-#define NETLINK_SELINUX_SOCKET__LISTEN 0x00001000UL
-#define NETLINK_SELINUX_SOCKET__ACCEPT 0x00002000UL
-#define NETLINK_SELINUX_SOCKET__GETOPT 0x00004000UL
-#define NETLINK_SELINUX_SOCKET__SETOPT 0x00008000UL
-#define NETLINK_SELINUX_SOCKET__SHUTDOWN 0x00010000UL
-#define NETLINK_SELINUX_SOCKET__RECVFROM 0x00020000UL
-#define NETLINK_SELINUX_SOCKET__SENDTO 0x00040000UL
-#define NETLINK_SELINUX_SOCKET__RECV_MSG 0x00080000UL
-#define NETLINK_SELINUX_SOCKET__SEND_MSG 0x00100000UL
-#define NETLINK_SELINUX_SOCKET__NAME_BIND 0x00200000UL
-#define NETLINK_AUDIT_SOCKET__IOCTL 0x00000001UL
-#define NETLINK_AUDIT_SOCKET__READ 0x00000002UL
-#define NETLINK_AUDIT_SOCKET__WRITE 0x00000004UL
-#define NETLINK_AUDIT_SOCKET__CREATE 0x00000008UL
-#define NETLINK_AUDIT_SOCKET__GETATTR 0x00000010UL
-#define NETLINK_AUDIT_SOCKET__SETATTR 0x00000020UL
-#define NETLINK_AUDIT_SOCKET__LOCK 0x00000040UL
-#define NETLINK_AUDIT_SOCKET__RELABELFROM 0x00000080UL
-#define NETLINK_AUDIT_SOCKET__RELABELTO 0x00000100UL
-#define NETLINK_AUDIT_SOCKET__APPEND 0x00000200UL
-#define NETLINK_AUDIT_SOCKET__BIND 0x00000400UL
-#define NETLINK_AUDIT_SOCKET__CONNECT 0x00000800UL
-#define NETLINK_AUDIT_SOCKET__LISTEN 0x00001000UL
-#define NETLINK_AUDIT_SOCKET__ACCEPT 0x00002000UL
-#define NETLINK_AUDIT_SOCKET__GETOPT 0x00004000UL
-#define NETLINK_AUDIT_SOCKET__SETOPT 0x00008000UL
-#define NETLINK_AUDIT_SOCKET__SHUTDOWN 0x00010000UL
-#define NETLINK_AUDIT_SOCKET__RECVFROM 0x00020000UL
-#define NETLINK_AUDIT_SOCKET__SENDTO 0x00040000UL
-#define NETLINK_AUDIT_SOCKET__RECV_MSG 0x00080000UL
-#define NETLINK_AUDIT_SOCKET__SEND_MSG 0x00100000UL
-#define NETLINK_AUDIT_SOCKET__NAME_BIND 0x00200000UL
-#define NETLINK_AUDIT_SOCKET__NLMSG_READ 0x00400000UL
-#define NETLINK_AUDIT_SOCKET__NLMSG_WRITE 0x00800000UL
-#define NETLINK_AUDIT_SOCKET__NLMSG_RELAY 0x01000000UL
-#define NETLINK_AUDIT_SOCKET__NLMSG_READPRIV 0x02000000UL
-#define NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT 0x04000000UL
-#define NETLINK_IP6FW_SOCKET__IOCTL 0x00000001UL
-#define NETLINK_IP6FW_SOCKET__READ 0x00000002UL
-#define NETLINK_IP6FW_SOCKET__WRITE 0x00000004UL
-#define NETLINK_IP6FW_SOCKET__CREATE 0x00000008UL
-#define NETLINK_IP6FW_SOCKET__GETATTR 0x00000010UL
-#define NETLINK_IP6FW_SOCKET__SETATTR 0x00000020UL
-#define NETLINK_IP6FW_SOCKET__LOCK 0x00000040UL
-#define NETLINK_IP6FW_SOCKET__RELABELFROM 0x00000080UL
-#define NETLINK_IP6FW_SOCKET__RELABELTO 0x00000100UL
-#define NETLINK_IP6FW_SOCKET__APPEND 0x00000200UL
-#define NETLINK_IP6FW_SOCKET__BIND 0x00000400UL
-#define NETLINK_IP6FW_SOCKET__CONNECT 0x00000800UL
-#define NETLINK_IP6FW_SOCKET__LISTEN 0x00001000UL
-#define NETLINK_IP6FW_SOCKET__ACCEPT 0x00002000UL
-#define NETLINK_IP6FW_SOCKET__GETOPT 0x00004000UL
-#define NETLINK_IP6FW_SOCKET__SETOPT 0x00008000UL
-#define NETLINK_IP6FW_SOCKET__SHUTDOWN 0x00010000UL
-#define NETLINK_IP6FW_SOCKET__RECVFROM 0x00020000UL
-#define NETLINK_IP6FW_SOCKET__SENDTO 0x00040000UL
-#define NETLINK_IP6FW_SOCKET__RECV_MSG 0x00080000UL
-#define NETLINK_IP6FW_SOCKET__SEND_MSG 0x00100000UL
-#define NETLINK_IP6FW_SOCKET__NAME_BIND 0x00200000UL
-#define NETLINK_IP6FW_SOCKET__NLMSG_READ 0x00400000UL
-#define NETLINK_IP6FW_SOCKET__NLMSG_WRITE 0x00800000UL
-#define NETLINK_DNRT_SOCKET__IOCTL 0x00000001UL
-#define NETLINK_DNRT_SOCKET__READ 0x00000002UL
-#define NETLINK_DNRT_SOCKET__WRITE 0x00000004UL
-#define NETLINK_DNRT_SOCKET__CREATE 0x00000008UL
-#define NETLINK_DNRT_SOCKET__GETATTR 0x00000010UL
-#define NETLINK_DNRT_SOCKET__SETATTR 0x00000020UL
-#define NETLINK_DNRT_SOCKET__LOCK 0x00000040UL
-#define NETLINK_DNRT_SOCKET__RELABELFROM 0x00000080UL
-#define NETLINK_DNRT_SOCKET__RELABELTO 0x00000100UL
-#define NETLINK_DNRT_SOCKET__APPEND 0x00000200UL
-#define NETLINK_DNRT_SOCKET__BIND 0x00000400UL
-#define NETLINK_DNRT_SOCKET__CONNECT 0x00000800UL
-#define NETLINK_DNRT_SOCKET__LISTEN 0x00001000UL
-#define NETLINK_DNRT_SOCKET__ACCEPT 0x00002000UL
-#define NETLINK_DNRT_SOCKET__GETOPT 0x00004000UL
-#define NETLINK_DNRT_SOCKET__SETOPT 0x00008000UL
-#define NETLINK_DNRT_SOCKET__SHUTDOWN 0x00010000UL
-#define NETLINK_DNRT_SOCKET__RECVFROM 0x00020000UL
-#define NETLINK_DNRT_SOCKET__SENDTO 0x00040000UL
-#define NETLINK_DNRT_SOCKET__RECV_MSG 0x00080000UL
-#define NETLINK_DNRT_SOCKET__SEND_MSG 0x00100000UL
-#define NETLINK_DNRT_SOCKET__NAME_BIND 0x00200000UL
-#define ASSOCIATION__SENDTO 0x00000001UL
-#define ASSOCIATION__RECVFROM 0x00000002UL
-#define ASSOCIATION__SETCONTEXT 0x00000004UL
-#define ASSOCIATION__POLMATCH 0x00000008UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__IOCTL 0x00000001UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__READ 0x00000002UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__WRITE 0x00000004UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__CREATE 0x00000008UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__GETATTR 0x00000010UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__SETATTR 0x00000020UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__LOCK 0x00000040UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__RELABELFROM 0x00000080UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__RELABELTO 0x00000100UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__APPEND 0x00000200UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__BIND 0x00000400UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__CONNECT 0x00000800UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__LISTEN 0x00001000UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__ACCEPT 0x00002000UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__GETOPT 0x00004000UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__SETOPT 0x00008000UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__SHUTDOWN 0x00010000UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__RECVFROM 0x00020000UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__SENDTO 0x00040000UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__RECV_MSG 0x00080000UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__SEND_MSG 0x00100000UL
-#define NETLINK_KOBJECT_UEVENT_SOCKET__NAME_BIND 0x00200000UL
-#define APPLETALK_SOCKET__IOCTL 0x00000001UL
-#define APPLETALK_SOCKET__READ 0x00000002UL
-#define APPLETALK_SOCKET__WRITE 0x00000004UL
-#define APPLETALK_SOCKET__CREATE 0x00000008UL
-#define APPLETALK_SOCKET__GETATTR 0x00000010UL
-#define APPLETALK_SOCKET__SETATTR 0x00000020UL
-#define APPLETALK_SOCKET__LOCK 0x00000040UL
-#define APPLETALK_SOCKET__RELABELFROM 0x00000080UL
-#define APPLETALK_SOCKET__RELABELTO 0x00000100UL
-#define APPLETALK_SOCKET__APPEND 0x00000200UL
-#define APPLETALK_SOCKET__BIND 0x00000400UL
-#define APPLETALK_SOCKET__CONNECT 0x00000800UL
-#define APPLETALK_SOCKET__LISTEN 0x00001000UL
-#define APPLETALK_SOCKET__ACCEPT 0x00002000UL
-#define APPLETALK_SOCKET__GETOPT 0x00004000UL
-#define APPLETALK_SOCKET__SETOPT 0x00008000UL
-#define APPLETALK_SOCKET__SHUTDOWN 0x00010000UL
-#define APPLETALK_SOCKET__RECVFROM 0x00020000UL
-#define APPLETALK_SOCKET__SENDTO 0x00040000UL
-#define APPLETALK_SOCKET__RECV_MSG 0x00080000UL
-#define APPLETALK_SOCKET__SEND_MSG 0x00100000UL
-#define APPLETALK_SOCKET__NAME_BIND 0x00200000UL
-#define PACKET__SEND 0x00000001UL
-#define PACKET__RECV 0x00000002UL
-#define PACKET__RELABELTO 0x00000004UL
-#define PACKET__FLOW_IN 0x00000008UL
-#define PACKET__FLOW_OUT 0x00000010UL
-#define PACKET__FORWARD_IN 0x00000020UL
-#define PACKET__FORWARD_OUT 0x00000040UL
-#define KEY__VIEW 0x00000001UL
-#define KEY__READ 0x00000002UL
-#define KEY__WRITE 0x00000004UL
-#define KEY__SEARCH 0x00000008UL
-#define KEY__LINK 0x00000010UL
-#define KEY__SETATTR 0x00000020UL
-#define KEY__CREATE 0x00000040UL
-#define DCCP_SOCKET__IOCTL 0x00000001UL
-#define DCCP_SOCKET__READ 0x00000002UL
-#define DCCP_SOCKET__WRITE 0x00000004UL
-#define DCCP_SOCKET__CREATE 0x00000008UL
-#define DCCP_SOCKET__GETATTR 0x00000010UL
-#define DCCP_SOCKET__SETATTR 0x00000020UL
-#define DCCP_SOCKET__LOCK 0x00000040UL
-#define DCCP_SOCKET__RELABELFROM 0x00000080UL
-#define DCCP_SOCKET__RELABELTO 0x00000100UL
-#define DCCP_SOCKET__APPEND 0x00000200UL
-#define DCCP_SOCKET__BIND 0x00000400UL
-#define DCCP_SOCKET__CONNECT 0x00000800UL
-#define DCCP_SOCKET__LISTEN 0x00001000UL
-#define DCCP_SOCKET__ACCEPT 0x00002000UL
-#define DCCP_SOCKET__GETOPT 0x00004000UL
-#define DCCP_SOCKET__SETOPT 0x00008000UL
-#define DCCP_SOCKET__SHUTDOWN 0x00010000UL
-#define DCCP_SOCKET__RECVFROM 0x00020000UL
-#define DCCP_SOCKET__SENDTO 0x00040000UL
-#define DCCP_SOCKET__RECV_MSG 0x00080000UL
-#define DCCP_SOCKET__SEND_MSG 0x00100000UL
-#define DCCP_SOCKET__NAME_BIND 0x00200000UL
-#define DCCP_SOCKET__NODE_BIND 0x00400000UL
-#define DCCP_SOCKET__NAME_CONNECT 0x00800000UL
-#define MEMPROTECT__MMAP_ZERO 0x00000001UL
-#define PEER__RECV 0x00000001UL
-#define KERNEL_SERVICE__USE_AS_OVERRIDE 0x00000001UL
-#define KERNEL_SERVICE__CREATE_FILES_AS 0x00000002UL
diff --git a/security/selinux/include/avc_ss.h b/security/selinux/include/avc_ss.h
index bb1ec801bdfe..4677aa519b04 100644
--- a/security/selinux/include/avc_ss.h
+++ b/security/selinux/include/avc_ss.h
@@ -10,26 +10,13 @@
int avc_ss_reset(u32 seqno);
-struct av_perm_to_string {
- u16 tclass;
- u32 value;
+/* Class/perm mapping support */
+struct security_class_mapping {
const char *name;
+ const char *perms[sizeof(u32) * 8 + 1];
};
-struct av_inherit {
- const char **common_pts;
- u32 common_base;
- u16 tclass;
-};
-
-struct selinux_class_perm {
- const struct av_perm_to_string *av_perm_to_string;
- u32 av_pts_len;
- u32 cts_len;
- const char **class_to_string;
- const struct av_inherit *av_inherit;
- u32 av_inherit_len;
-};
+extern struct security_class_mapping secclass_map[];
#endif /* _SELINUX_AVC_SS_H_ */
diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h
deleted file mode 100644
index 7ab9299bfb6b..000000000000
--- a/security/selinux/include/class_to_string.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* This file is automatically generated. Do not edit. */
-/*
- * Security object class definitions
- */
- S_(NULL)
- S_("security")
- S_("process")
- S_("system")
- S_("capability")
- S_("filesystem")
- S_("file")
- S_("dir")
- S_("fd")
- S_("lnk_file")
- S_("chr_file")
- S_("blk_file")
- S_("sock_file")
- S_("fifo_file")
- S_("socket")
- S_("tcp_socket")
- S_("udp_socket")
- S_("rawip_socket")
- S_("node")
- S_("netif")
- S_("netlink_socket")
- S_("packet_socket")
- S_("key_socket")
- S_("unix_stream_socket")
- S_("unix_dgram_socket")
- S_("sem")
- S_("msg")
- S_("msgq")
- S_("shm")
- S_("ipc")
- S_(NULL)
- S_(NULL)
- S_(NULL)
- S_(NULL)
- S_(NULL)
- S_(NULL)
- S_(NULL)
- S_(NULL)
- S_(NULL)
- S_(NULL)
- S_(NULL)
- S_(NULL)
- S_(NULL)
- S_("netlink_route_socket")
- S_("netlink_firewall_socket")
- S_("netlink_tcpdiag_socket")
- S_("netlink_nflog_socket")
- S_("netlink_xfrm_socket")
- S_("netlink_selinux_socket")
- S_("netlink_audit_socket")
- S_("netlink_ip6fw_socket")
- S_("netlink_dnrt_socket")
- S_(NULL)
- S_(NULL)
- S_("association")
- S_("netlink_kobject_uevent_socket")
- S_("appletalk_socket")
- S_("packet")
- S_("key")
- S_(NULL)
- S_("dccp_socket")
- S_("memprotect")
- S_(NULL)
- S_(NULL)
- S_(NULL)
- S_(NULL)
- S_(NULL)
- S_(NULL)
- S_("peer")
- S_("capability2")
- S_(NULL)
- S_(NULL)
- S_(NULL)
- S_(NULL)
- S_("kernel_service")
- S_("tun_socket")
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
new file mode 100644
index 000000000000..8b32e959bb2e
--- /dev/null
+++ b/security/selinux/include/classmap.h
@@ -0,0 +1,150 @@
+#define COMMON_FILE_SOCK_PERMS "ioctl", "read", "write", "create", \
+ "getattr", "setattr", "lock", "relabelfrom", "relabelto", "append"
+
+#define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \
+ "rename", "execute", "swapon", "quotaon", "mounton"
+
+#define COMMON_SOCK_PERMS COMMON_FILE_SOCK_PERMS, "bind", "connect", \
+ "listen", "accept", "getopt", "setopt", "shutdown", "recvfrom", \
+ "sendto", "recv_msg", "send_msg", "name_bind"
+
+#define COMMON_IPC_PERMS "create", "destroy", "getattr", "setattr", "read", \
+ "write", "associate", "unix_read", "unix_write"
+
+struct security_class_mapping secclass_map[] = {
+ { "security",
+ { "compute_av", "compute_create", "compute_member",
+ "check_context", "load_policy", "compute_relabel",
+ "compute_user", "setenforce", "setbool", "setsecparam",
+ "setcheckreqprot", NULL } },
+ { "process",
+ { "fork", "transition", "sigchld", "sigkill",
+ "sigstop", "signull", "signal", "ptrace", "getsched", "setsched",
+ "getsession", "getpgid", "setpgid", "getcap", "setcap", "share",
+ "getattr", "setexec", "setfscreate", "noatsecure", "siginh",
+ "setrlimit", "rlimitinh", "dyntransition", "setcurrent",
+ "execmem", "execstack", "execheap", "setkeycreate",
+ "setsockcreate", NULL } },
+ { "system",
+ { "ipc_info", "syslog_read", "syslog_mod",
+ "syslog_console", "module_request", NULL } },
+ { "capability",
+ { "chown", "dac_override", "dac_read_search",
+ "fowner", "fsetid", "kill", "setgid", "setuid", "setpcap",
+ "linux_immutable", "net_bind_service", "net_broadcast",
+ "net_admin", "net_raw", "ipc_lock", "ipc_owner", "sys_module",
+ "sys_rawio", "sys_chroot", "sys_ptrace", "sys_pacct", "sys_admin",
+ "sys_boot", "sys_nice", "sys_resource", "sys_time",
+ "sys_tty_config", "mknod", "lease", "audit_write",
+ "audit_control", "setfcap", NULL } },
+ { "filesystem",
+ { "mount", "remount", "unmount", "getattr",
+ "relabelfrom", "relabelto", "transition", "associate", "quotamod",
+ "quotaget", NULL } },
+ { "file",
+ { COMMON_FILE_PERMS,
+ "execute_no_trans", "entrypoint", "execmod", "open", NULL } },
+ { "dir",
+ { COMMON_FILE_PERMS, "add_name", "remove_name",
+ "reparent", "search", "rmdir", "open", NULL } },
+ { "fd", { "use", NULL } },
+ { "lnk_file",
+ { COMMON_FILE_PERMS, NULL } },
+ { "chr_file",
+ { COMMON_FILE_PERMS,
+ "execute_no_trans", "entrypoint", "execmod", "open", NULL } },
+ { "blk_file",
+ { COMMON_FILE_PERMS, "open", NULL } },
+ { "sock_file",
+ { COMMON_FILE_PERMS, "open", NULL } },
+ { "fifo_file",
+ { COMMON_FILE_PERMS, "open", NULL } },
+ { "socket",
+ { COMMON_SOCK_PERMS, NULL } },
+ { "tcp_socket",
+ { COMMON_SOCK_PERMS,
+ "connectto", "newconn", "acceptfrom", "node_bind", "name_connect",
+ NULL } },
+ { "udp_socket",
+ { COMMON_SOCK_PERMS,
+ "node_bind", NULL } },
+ { "rawip_socket",
+ { COMMON_SOCK_PERMS,
+ "node_bind", NULL } },
+ { "node",
+ { "tcp_recv", "tcp_send", "udp_recv", "udp_send",
+ "rawip_recv", "rawip_send", "enforce_dest",
+ "dccp_recv", "dccp_send", "recvfrom", "sendto", NULL } },
+ { "netif",
+ { "tcp_recv", "tcp_send", "udp_recv", "udp_send",
+ "rawip_recv", "rawip_send", "dccp_recv", "dccp_send",
+ "ingress", "egress", NULL } },
+ { "netlink_socket",
+ { COMMON_SOCK_PERMS, NULL } },
+ { "packet_socket",
+ { COMMON_SOCK_PERMS, NULL } },
+ { "key_socket",
+ { COMMON_SOCK_PERMS, NULL } },
+ { "unix_stream_socket",
+ { COMMON_SOCK_PERMS, "connectto", "newconn", "acceptfrom", NULL
+ } },
+ { "unix_dgram_socket",
+ { COMMON_SOCK_PERMS, NULL
+ } },
+ { "sem",
+ { COMMON_IPC_PERMS, NULL } },
+ { "msg", { "send", "receive", NULL } },
+ { "msgq",
+ { COMMON_IPC_PERMS, "enqueue", NULL } },
+ { "shm",
+ { COMMON_IPC_PERMS, "lock", NULL } },
+ { "ipc",
+ { COMMON_IPC_PERMS, NULL } },
+ { "netlink_route_socket",
+ { COMMON_SOCK_PERMS,
+ "nlmsg_read", "nlmsg_write", NULL } },
+ { "netlink_firewall_socket",
+ { COMMON_SOCK_PERMS,
+ "nlmsg_read", "nlmsg_write", NULL } },
+ { "netlink_tcpdiag_socket",
+ { COMMON_SOCK_PERMS,
+ "nlmsg_read", "nlmsg_write", NULL } },
+ { "netlink_nflog_socket",
+ { COMMON_SOCK_PERMS, NULL } },
+ { "netlink_xfrm_socket",
+ { COMMON_SOCK_PERMS,
+ "nlmsg_read", "nlmsg_write", NULL } },
+ { "netlink_selinux_socket",
+ { COMMON_SOCK_PERMS, NULL } },
+ { "netlink_audit_socket",
+ { COMMON_SOCK_PERMS,
+ "nlmsg_read", "nlmsg_write", "nlmsg_relay", "nlmsg_readpriv",
+ "nlmsg_tty_audit", NULL } },
+ { "netlink_ip6fw_socket",
+ { COMMON_SOCK_PERMS,
+ "nlmsg_read", "nlmsg_write", NULL } },
+ { "netlink_dnrt_socket",
+ { COMMON_SOCK_PERMS, NULL } },
+ { "association",
+ { "sendto", "recvfrom", "setcontext", "polmatch", NULL } },
+ { "netlink_kobject_uevent_socket",
+ { COMMON_SOCK_PERMS, NULL } },
+ { "appletalk_socket",
+ { COMMON_SOCK_PERMS, NULL } },
+ { "packet",
+ { "send", "recv", "relabelto", "flow_in", "flow_out",
+ "forward_in", "forward_out", NULL } },
+ { "key",
+ { "view", "read", "write", "search", "link", "setattr", "create",
+ NULL } },
+ { "dccp_socket",
+ { COMMON_SOCK_PERMS,
+ "node_bind", "name_connect", NULL } },
+ { "memprotect", { "mmap_zero", NULL } },
+ { "peer", { "recv", NULL } },
+ { "capability2", { "mac_override", "mac_admin", NULL } },
+ { "kernel_service", { "use_as_override", "create_files_as", NULL } },
+ { "tun_socket",
+ { COMMON_SOCK_PERMS, NULL } },
+ { NULL }
+ };
diff --git a/security/selinux/include/common_perm_to_string.h b/security/selinux/include/common_perm_to_string.h
deleted file mode 100644
index ce5b6e2fe9dd..000000000000
--- a/security/selinux/include/common_perm_to_string.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* This file is automatically generated. Do not edit. */
-TB_(common_file_perm_to_string)
- S_("ioctl")
- S_("read")
- S_("write")
- S_("create")
- S_("getattr")
- S_("setattr")
- S_("lock")
- S_("relabelfrom")
- S_("relabelto")
- S_("append")
- S_("unlink")
- S_("link")
- S_("rename")
- S_("execute")
- S_("swapon")
- S_("quotaon")
- S_("mounton")
-TE_(common_file_perm_to_string)
-
-TB_(common_socket_perm_to_string)
- S_("ioctl")
- S_("read")
- S_("write")
- S_("create")
- S_("getattr")
- S_("setattr")
- S_("lock")
- S_("relabelfrom")
- S_("relabelto")
- S_("append")
- S_("bind")
- S_("connect")
- S_("listen")
- S_("accept")
- S_("getopt")
- S_("setopt")
- S_("shutdown")
- S_("recvfrom")
- S_("sendto")
- S_("recv_msg")
- S_("send_msg")
- S_("name_bind")
-TE_(common_socket_perm_to_string)
-
-TB_(common_ipc_perm_to_string)
- S_("create")
- S_("destroy")
- S_("getattr")
- S_("setattr")
- S_("read")
- S_("write")
- S_("associate")
- S_("unix_read")
- S_("unix_write")
-TE_(common_ipc_perm_to_string)
-
diff --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h
deleted file mode 100644
index f248500a1e3c..000000000000
--- a/security/selinux/include/flask.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* This file is automatically generated. Do not edit. */
-#ifndef _SELINUX_FLASK_H_
-#define _SELINUX_FLASK_H_
-
-/*
- * Security object class definitions
- */
-#define SECCLASS_SECURITY 1
-#define SECCLASS_PROCESS 2
-#define SECCLASS_SYSTEM 3
-#define SECCLASS_CAPABILITY 4
-#define SECCLASS_FILESYSTEM 5
-#define SECCLASS_FILE 6
-#define SECCLASS_DIR 7
-#define SECCLASS_FD 8
-#define SECCLASS_LNK_FILE 9
-#define SECCLASS_CHR_FILE 10
-#define SECCLASS_BLK_FILE 11
-#define SECCLASS_SOCK_FILE 12
-#define SECCLASS_FIFO_FILE 13
-#define SECCLASS_SOCKET 14
-#define SECCLASS_TCP_SOCKET 15
-#define SECCLASS_UDP_SOCKET 16
-#define SECCLASS_RAWIP_SOCKET 17
-#define SECCLASS_NODE 18
-#define SECCLASS_NETIF 19
-#define SECCLASS_NETLINK_SOCKET 20
-#define SECCLASS_PACKET_SOCKET 21
-#define SECCLASS_KEY_SOCKET 22
-#define SECCLASS_UNIX_STREAM_SOCKET 23
-#define SECCLASS_UNIX_DGRAM_SOCKET 24
-#define SECCLASS_SEM 25
-#define SECCLASS_MSG 26
-#define SECCLASS_MSGQ 27
-#define SECCLASS_SHM 28
-#define SECCLASS_IPC 29
-#define SECCLASS_NETLINK_ROUTE_SOCKET 43
-#define SECCLASS_NETLINK_FIREWALL_SOCKET 44
-#define SECCLASS_NETLINK_TCPDIAG_SOCKET 45
-#define SECCLASS_NETLINK_NFLOG_SOCKET 46
-#define SECCLASS_NETLINK_XFRM_SOCKET 47
-#define SECCLASS_NETLINK_SELINUX_SOCKET 48
-#define SECCLASS_NETLINK_AUDIT_SOCKET 49
-#define SECCLASS_NETLINK_IP6FW_SOCKET 50
-#define SECCLASS_NETLINK_DNRT_SOCKET 51
-#define SECCLASS_ASSOCIATION 54
-#define SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET 55
-#define SECCLASS_APPLETALK_SOCKET 56
-#define SECCLASS_PACKET 57
-#define SECCLASS_KEY 58
-#define SECCLASS_DCCP_SOCKET 60
-#define SECCLASS_MEMPROTECT 61
-#define SECCLASS_PEER 68
-#define SECCLASS_CAPABILITY2 69
-#define SECCLASS_KERNEL_SERVICE 74
-#define SECCLASS_TUN_SOCKET 75
-
-/*
- * Security identifier indices for initial entities
- */
-#define SECINITSID_KERNEL 1
-#define SECINITSID_SECURITY 2
-#define SECINITSID_UNLABELED 3
-#define SECINITSID_FS 4
-#define SECINITSID_FILE 5
-#define SECINITSID_FILE_LABELS 6
-#define SECINITSID_INIT 7
-#define SECINITSID_ANY_SOCKET 8
-#define SECINITSID_PORT 9
-#define SECINITSID_NETIF 10
-#define SECINITSID_NETMSG 11
-#define SECINITSID_NODE 12
-#define SECINITSID_IGMP_PACKET 13
-#define SECINITSID_ICMP_SOCKET 14
-#define SECINITSID_TCP_SOCKET 15
-#define SECINITSID_SYSCTL_MODPROBE 16
-#define SECINITSID_SYSCTL 17
-#define SECINITSID_SYSCTL_FS 18
-#define SECINITSID_SYSCTL_KERNEL 19
-#define SECINITSID_SYSCTL_NET 20
-#define SECINITSID_SYSCTL_NET_UNIX 21
-#define SECINITSID_SYSCTL_VM 22
-#define SECINITSID_SYSCTL_DEV 23
-#define SECINITSID_KMOD 24
-#define SECINITSID_POLICY 25
-#define SECINITSID_SCMP_PACKET 26
-#define SECINITSID_DEVNULL 27
-
-#define SECINITSID_NUM 27
-
-#endif
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index ca835795a8b3..2553266ad793 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -97,11 +97,18 @@ struct av_decision {
#define AVD_FLAGS_PERMISSIVE 0x0001
int security_compute_av(u32 ssid, u32 tsid,
- u16 tclass, u32 requested,
- struct av_decision *avd);
+ u16 tclass, u32 requested,
+ struct av_decision *avd);
+
+int security_compute_av_user(u32 ssid, u32 tsid,
+ u16 tclass, u32 requested,
+ struct av_decision *avd);
int security_transition_sid(u32 ssid, u32 tsid,
- u16 tclass, u32 *out_sid);
+ u16 tclass, u32 *out_sid);
+
+int security_transition_sid_user(u32 ssid, u32 tsid,
+ u16 tclass, u32 *out_sid);
int security_member_sid(u32 ssid, u32 tsid,
u16 tclass, u32 *out_sid);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index b4fc506e7a87..fab36fdf2769 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -522,7 +522,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
if (length < 0)
goto out2;
- length = security_compute_av(ssid, tsid, tclass, req, &avd);
+ length = security_compute_av_user(ssid, tsid, tclass, req, &avd);
if (length < 0)
goto out2;
@@ -571,7 +571,7 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
if (length < 0)
goto out2;
- length = security_transition_sid(ssid, tsid, tclass, &newsid);
+ length = security_transition_sid_user(ssid, tsid, tclass, &newsid);
if (length < 0)
goto out2;
diff --git a/security/selinux/ss/Makefile b/security/selinux/ss/Makefile
index bad78779b9b0..15d4e62917de 100644
--- a/security/selinux/ss/Makefile
+++ b/security/selinux/ss/Makefile
@@ -2,7 +2,7 @@
# Makefile for building the SELinux security server as part of the kernel tree.
#
-EXTRA_CFLAGS += -Isecurity/selinux/include
+EXTRA_CFLAGS += -Isecurity/selinux -Isecurity/selinux/include
obj-y := ss.o
ss-y := ebitmap.o hashtab.o symtab.o sidtab.o avtab.o policydb.o services.o conditional.o mls.o
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index b5407f16c2a4..3f2b2706b5bb 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -532,7 +532,7 @@ int mls_compute_sid(struct context *scontext,
}
/* Fallthrough */
case AVTAB_CHANGE:
- if (tclass == SECCLASS_PROCESS)
+ if (tclass == policydb.process_class)
/* Use the process MLS attributes. */
return mls_context_cpy(newcontext, scontext);
else
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 72e4a54973aa..f03667213ea8 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -713,7 +713,6 @@ void policydb_destroy(struct policydb *p)
ebitmap_destroy(&p->type_attr_map[i]);
}
kfree(p->type_attr_map);
- kfree(p->undefined_perms);
ebitmap_destroy(&p->policycaps);
ebitmap_destroy(&p->permissive_map);
@@ -1640,6 +1639,40 @@ static int policydb_bounds_sanity_check(struct policydb *p)
extern int ss_initialized;
+u16 string_to_security_class(struct policydb *p, const char *name)
+{
+ struct class_datum *cladatum;
+
+ cladatum = hashtab_search(p->p_classes.table, name);
+ if (!cladatum)
+ return 0;
+
+ return cladatum->value;
+}
+
+u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name)
+{
+ struct class_datum *cladatum;
+ struct perm_datum *perdatum = NULL;
+ struct common_datum *comdatum;
+
+ if (!tclass || tclass > p->p_classes.nprim)
+ return 0;
+
+ cladatum = p->class_val_to_struct[tclass-1];
+ comdatum = cladatum->comdatum;
+ if (comdatum)
+ perdatum = hashtab_search(comdatum->permissions.table,
+ name);
+ if (!perdatum)
+ perdatum = hashtab_search(cladatum->permissions.table,
+ name);
+ if (!perdatum)
+ return 0;
+
+ return 1U << (perdatum->value-1);
+}
+
/*
* Read the configuration data from a policy database binary
* representation file into a policy database structure.
@@ -1861,6 +1894,16 @@ int policydb_read(struct policydb *p, void *fp)
if (rc)
goto bad;
+ p->process_class = string_to_security_class(p, "process");
+ if (!p->process_class)
+ goto bad;
+ p->process_trans_perms = string_to_av_perm(p, p->process_class,
+ "transition");
+ p->process_trans_perms |= string_to_av_perm(p, p->process_class,
+ "dyntransition");
+ if (!p->process_trans_perms)
+ goto bad;
+
for (i = 0; i < info->ocon_num; i++) {
rc = next_entry(buf, fp, sizeof(u32));
if (rc < 0)
@@ -2101,7 +2144,7 @@ int policydb_read(struct policydb *p, void *fp)
goto bad;
rt->target_class = le32_to_cpu(buf[0]);
} else
- rt->target_class = SECCLASS_PROCESS;
+ rt->target_class = p->process_class;
if (!policydb_type_isvalid(p, rt->source_type) ||
!policydb_type_isvalid(p, rt->target_type) ||
!policydb_class_isvalid(p, rt->target_class)) {
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index 55152d498b53..cdcc5700946f 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -254,7 +254,9 @@ struct policydb {
unsigned int reject_unknown : 1;
unsigned int allow_unknown : 1;
- u32 *undefined_perms;
+
+ u16 process_class;
+ u32 process_trans_perms;
};
extern void policydb_destroy(struct policydb *p);
@@ -295,5 +297,8 @@ static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes)
return 0;
}
+extern u16 string_to_security_class(struct policydb *p, const char *name);
+extern u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name);
+
#endif /* _SS_POLICYDB_H_ */
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index ff17820d35ec..77f6e54bb43f 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -65,16 +65,10 @@
#include "audit.h"
extern void selnl_notify_policyload(u32 seqno);
-unsigned int policydb_loaded_version;
int selinux_policycap_netpeer;
int selinux_policycap_openperm;
-/*
- * This is declared in avc.c
- */
-extern const struct selinux_class_perm selinux_class_perm;
-
static DEFINE_RWLOCK(policy_rwlock);
static struct sidtab sidtab;
@@ -98,6 +92,158 @@ static int context_struct_compute_av(struct context *scontext,
u16 tclass,
u32 requested,
struct av_decision *avd);
+
+struct selinux_mapping {
+ u16 value; /* policy value */
+ unsigned num_perms;
+ u32 perms[sizeof(u32) * 8];
+};
+
+static struct selinux_mapping *current_mapping;
+static u16 current_mapping_size;
+
+static int selinux_set_mapping(struct policydb *pol,
+ struct security_class_mapping *map,
+ struct selinux_mapping **out_map_p,
+ u16 *out_map_size)
+{
+ struct selinux_mapping *out_map = NULL;
+ size_t size = sizeof(struct selinux_mapping);
+ u16 i, j;
+ unsigned k;
+ bool print_unknown_handle = false;
+
+ /* Find number of classes in the input mapping */
+ if (!map)
+ return -EINVAL;
+ i = 0;
+ while (map[i].name)
+ i++;
+
+ /* Allocate space for the class records, plus one for class zero */
+ out_map = kcalloc(++i, size, GFP_ATOMIC);
+ if (!out_map)
+ return -ENOMEM;
+
+ /* Store the raw class and permission values */
+ j = 0;
+ while (map[j].name) {
+ struct security_class_mapping *p_in = map + (j++);
+ struct selinux_mapping *p_out = out_map + j;
+
+ /* An empty class string skips ahead */
+ if (!strcmp(p_in->name, "")) {
+ p_out->num_perms = 0;
+ continue;
+ }
+
+ p_out->value = string_to_security_class(pol, p_in->name);
+ if (!p_out->value) {
+ printk(KERN_INFO
+ "SELinux: Class %s not defined in policy.\n",
+ p_in->name);
+ if (pol->reject_unknown)
+ goto err;
+ p_out->num_perms = 0;
+ print_unknown_handle = true;
+ continue;
+ }
+
+ k = 0;
+ while (p_in->perms && p_in->perms[k]) {
+ /* An empty permission string skips ahead */
+ if (!*p_in->perms[k]) {
+ k++;
+ continue;
+ }
+ p_out->perms[k] = string_to_av_perm(pol, p_out->value,
+ p_in->perms[k]);
+ if (!p_out->perms[k]) {
+ printk(KERN_INFO
+ "SELinux: Permission %s in class %s not defined in policy.\n",
+ p_in->perms[k], p_in->name);
+ if (pol->reject_unknown)
+ goto err;
+ print_unknown_handle = true;
+ }
+
+ k++;
+ }
+ p_out->num_perms = k;
+ }
+
+ if (print_unknown_handle)
+ printk(KERN_INFO "SELinux: the above unknown classes and permissions will be %s\n",
+ pol->allow_unknown ? "allowed" : "denied");
+
+ *out_map_p = out_map;
+ *out_map_size = i;
+ return 0;
+err:
+ kfree(out_map);
+ return -EINVAL;
+}
+
+/*
+ * Get real, policy values from mapped values
+ */
+
+static u16 unmap_class(u16 tclass)
+{
+ if (tclass < current_mapping_size)
+ return current_mapping[tclass].value;
+
+ return tclass;
+}
+
+static u32 unmap_perm(u16 tclass, u32 tperm)
+{
+ if (tclass < current_mapping_size) {
+ unsigned i;
+ u32 kperm = 0;
+
+ for (i = 0; i < current_mapping[tclass].num_perms; i++)
+ if (tperm & (1<<i)) {
+ kperm |= current_mapping[tclass].perms[i];
+ tperm &= ~(1<<i);
+ }
+ return kperm;
+ }
+
+ return tperm;
+}
+
+static void map_decision(u16 tclass, struct av_decision *avd,
+ int allow_unknown)
+{
+ if (tclass < current_mapping_size) {
+ unsigned i, n = current_mapping[tclass].num_perms;
+ u32 result;
+
+ for (i = 0, result = 0; i < n; i++) {
+ if (avd->allowed & current_mapping[tclass].perms[i])
+ result |= 1<<i;
+ if (allow_unknown && !current_mapping[tclass].perms[i])
+ result |= 1<<i;
+ }
+ avd->allowed = result;
+
+ for (i = 0, result = 0; i < n; i++)
+ if (avd->auditallow & current_mapping[tclass].perms[i])
+ result |= 1<<i;
+ avd->auditallow = result;
+
+ for (i = 0, result = 0; i < n; i++) {
+ if (avd->auditdeny & current_mapping[tclass].perms[i])
+ result |= 1<<i;
+ if (!allow_unknown && !current_mapping[tclass].perms[i])
+ result |= 1<<i;
+ }
+ avd->auditdeny = result;
+ }
+}
+
+
/*
* Return the boolean value of a constraint expression
* when it is applied to the specified source and target
@@ -467,21 +613,9 @@ static int context_struct_compute_av(struct context *scontext,
struct class_datum *tclass_datum;
struct ebitmap *sattr, *tattr;
struct ebitmap_node *snode, *tnode;
- const struct selinux_class_perm *kdefs = &selinux_class_perm;
unsigned int i, j;
/*
- * Remap extended Netlink classes for old policy versions.
- * Do this here rather than socket_type_to_security_class()
- * in case a newer policy version is loaded, allowing sockets
- * to remain in the correct class.
- */
- if (policydb_loaded_version < POLICYDB_VERSION_NLCLASS)
- if (tclass >= SECCLASS_NETLINK_ROUTE_SOCKET &&
- tclass <= SECCLASS_NETLINK_DNRT_SOCKET)
- tclass = SECCLASS_NETLINK_SOCKET;
-
- /*
* Initialize the access vectors to the default values.
*/
avd->allowed = 0;
@@ -490,33 +624,11 @@ static int context_struct_compute_av(struct context *scontext,
avd->seqno = latest_granting;
avd->flags = 0;
- /*
- * Check for all the invalid cases.
- * - tclass 0
- * - tclass > policy and > kernel
- * - tclass > policy but is a userspace class
- * - tclass > policy but we do not allow unknowns
- */
- if (unlikely(!tclass))
- goto inval_class;
- if (unlikely(tclass > policydb.p_classes.nprim))
- if (tclass > kdefs->cts_len ||
- !kdefs->class_to_string[tclass] ||
- !policydb.allow_unknown)
- goto inval_class;
-
- /*
- * Kernel class and we allow unknown so pad the allow decision
- * the pad will be all 1 for unknown classes.
- */
- if (tclass <= kdefs->cts_len && policydb.allow_unknown)
- avd->allowed = policydb.undefined_perms[tclass - 1];
-
- /*
- * Not in policy. Since decision is completed (all 1 or all 0) return.
- */
- if (unlikely(tclass > policydb.p_classes.nprim))
- return 0;
+ if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) {
+ if (printk_ratelimit())
+ printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass);
+ return -EINVAL;
+ }
tclass_datum = policydb.class_val_to_struct[tclass - 1];
@@ -568,8 +680,8 @@ static int context_struct_compute_av(struct context *scontext,
* role is changing, then check the (current_role, new_role)
* pair.
*/
- if (tclass == SECCLASS_PROCESS &&
- (avd->allowed & (PROCESS__TRANSITION | PROCESS__DYNTRANSITION)) &&
+ if (tclass == policydb.process_class &&
+ (avd->allowed & policydb.process_trans_perms) &&
scontext->role != tcontext->role) {
for (ra = policydb.role_allow; ra; ra = ra->next) {
if (scontext->role == ra->role &&
@@ -577,8 +689,7 @@ static int context_struct_compute_av(struct context *scontext,
break;
}
if (!ra)
- avd->allowed &= ~(PROCESS__TRANSITION |
- PROCESS__DYNTRANSITION);
+ avd->allowed &= ~policydb.process_trans_perms;
}
/*
@@ -590,21 +701,6 @@ static int context_struct_compute_av(struct context *scontext,
tclass, requested, avd);
return 0;
-
-inval_class:
- if (!tclass || tclass > kdefs->cts_len ||
- !kdefs->class_to_string[tclass]) {
- if (printk_ratelimit())
- printk(KERN_ERR "SELinux: %s: unrecognized class %d\n",
- __func__, tclass);
- return -EINVAL;
- }
-
- /*
- * Known to the kernel, but not to the policy.
- * Handle as a denial (allowed is 0).
- */
- return 0;
}
static int security_validtrans_handle_fail(struct context *ocontext,
@@ -636,13 +732,14 @@ out:
}
int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
- u16 tclass)
+ u16 orig_tclass)
{
struct context *ocontext;
struct context *ncontext;
struct context *tcontext;
struct class_datum *tclass_datum;
struct constraint_node *constraint;
+ u16 tclass;
int rc = 0;
if (!ss_initialized)
@@ -650,16 +747,7 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
read_lock(&policy_rwlock);
- /*
- * Remap extended Netlink classes for old policy versions.
- * Do this here rather than socket_type_to_security_class()
- * in case a newer policy version is loaded, allowing sockets
- * to remain in the correct class.
- */
- if (policydb_loaded_version < POLICYDB_VERSION_NLCLASS)
- if (tclass >= SECCLASS_NETLINK_ROUTE_SOCKET &&
- tclass <= SECCLASS_NETLINK_DNRT_SOCKET)
- tclass = SECCLASS_NETLINK_SOCKET;
+ tclass = unmap_class(orig_tclass);
if (!tclass || tclass > policydb.p_classes.nprim) {
printk(KERN_ERR "SELinux: %s: unrecognized class %d\n",
@@ -792,6 +880,38 @@ out:
}
+static int security_compute_av_core(u32 ssid,
+ u32 tsid,
+ u16 tclass,
+ u32 requested,
+ struct av_decision *avd)
+{
+ struct context *scontext = NULL, *tcontext = NULL;
+ int rc = 0;
+
+ scontext = sidtab_search(&sidtab, ssid);
+ if (!scontext) {
+ printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
+ __func__, ssid);
+ return -EINVAL;
+ }
+ tcontext = sidtab_search(&sidtab, tsid);
+ if (!tcontext) {
+ printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
+ __func__, tsid);
+ return -EINVAL;
+ }
+
+ rc = context_struct_compute_av(scontext, tcontext, tclass,
+ requested, avd);
+
+ /* permissive domain? */
+ if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
+ avd->flags |= AVD_FLAGS_PERMISSIVE;
+
+ return rc;
+}
+
/**
* security_compute_av - Compute access vector decisions.
* @ssid: source security identifier
@@ -807,12 +927,49 @@ out:
*/
int security_compute_av(u32 ssid,
u32 tsid,
- u16 tclass,
- u32 requested,
+ u16 orig_tclass,
+ u32 orig_requested,
struct av_decision *avd)
{
- struct context *scontext = NULL, *tcontext = NULL;
- int rc = 0;
+ u16 tclass;
+ u32 requested;
+ int rc;
+
+ read_lock(&policy_rwlock);
+
+ if (!ss_initialized)
+ goto allow;
+
+ requested = unmap_perm(orig_tclass, orig_requested);
+ tclass = unmap_class(orig_tclass);
+ if (unlikely(orig_tclass && !tclass)) {
+ if (policydb.allow_unknown)
+ goto allow;
+ rc = -EINVAL;
+ goto out;
+ }
+ rc = security_compute_av_core(ssid, tsid, tclass, requested, avd);
+ map_decision(orig_tclass, avd, policydb.allow_unknown);
+out:
+ read_unlock(&policy_rwlock);
+ return rc;
+allow:
+ avd->allowed = 0xffffffff;
+ avd->auditallow = 0;
+ avd->auditdeny = 0xffffffff;
+ avd->seqno = latest_granting;
+ avd->flags = 0;
+ rc = 0;
+ goto out;
+}
+
+int security_compute_av_user(u32 ssid,
+ u32 tsid,
+ u16 tclass,
+ u32 requested,
+ struct av_decision *avd)
+{
+ int rc;
if (!ss_initialized) {
avd->allowed = 0xffffffff;
@@ -823,29 +980,7 @@ int security_compute_av(u32 ssid,
}
read_lock(&policy_rwlock);
-
- scontext = sidtab_search(&sidtab, ssid);
- if (!scontext) {
- printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
- __func__, ssid);
- rc = -EINVAL;
- goto out;
- }
- tcontext = sidtab_search(&sidtab, tsid);
- if (!tcontext) {
- printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
- __func__, tsid);
- rc = -EINVAL;
- goto out;
- }
-
- rc = context_struct_compute_av(scontext, tcontext, tclass,
- requested, avd);
-
- /* permissive domain? */
- if (ebitmap_get_bit(&policydb.permissive_map, scontext->type))
- avd->flags |= AVD_FLAGS_PERMISSIVE;
-out:
+ rc = security_compute_av_core(ssid, tsid, tclass, requested, avd);
read_unlock(&policy_rwlock);
return rc;
}
@@ -1204,20 +1339,22 @@ out:
static int security_compute_sid(u32 ssid,
u32 tsid,
- u16 tclass,
+ u16 orig_tclass,
u32 specified,
- u32 *out_sid)
+ u32 *out_sid,
+ bool kern)
{
struct context *scontext = NULL, *tcontext = NULL, newcontext;
struct role_trans *roletr = NULL;
struct avtab_key avkey;
struct avtab_datum *avdatum;
struct avtab_node *node;
+ u16 tclass;
int rc = 0;
if (!ss_initialized) {
- switch (tclass) {
- case SECCLASS_PROCESS:
+ switch (orig_tclass) {
+ case SECCLASS_PROCESS: /* kernel value */
*out_sid = ssid;
break;
default:
@@ -1231,6 +1368,11 @@ static int security_compute_sid(u32 ssid,
read_lock(&policy_rwlock);
+ if (kern)
+ tclass = unmap_class(orig_tclass);
+ else
+ tclass = orig_tclass;
+
scontext = sidtab_search(&sidtab, ssid);
if (!scontext) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
@@ -1260,13 +1402,11 @@ static int security_compute_sid(u32 ssid,
}
/* Set the role and type to default values. */
- switch (tclass) {
- case SECCLASS_PROCESS:
+ if (tclass == policydb.process_class) {
/* Use the current role and type of process. */
newcontext.role = scontext->role;
newcontext.type = scontext->type;
- break;
- default:
+ } else {
/* Use the well-defined object role. */
newcontext.role = OBJECT_R_VAL;
/* Use the type of the related object. */
@@ -1297,8 +1437,7 @@ static int security_compute_sid(u32 ssid,
}
/* Check for class-specific changes. */
- switch (tclass) {
- case SECCLASS_PROCESS:
+ if (tclass == policydb.process_class) {
if (specified & AVTAB_TRANSITION) {
/* Look for a role transition rule. */
for (roletr = policydb.role_tr; roletr;
@@ -1311,9 +1450,6 @@ static int security_compute_sid(u32 ssid,
}
}
}
- break;
- default:
- break;
}
/* Set the MLS attributes.
@@ -1358,7 +1494,17 @@ int security_transition_sid(u32 ssid,
u16 tclass,
u32 *out_sid)
{
- return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, out_sid);
+ return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
+ out_sid, true);
+}
+
+int security_transition_sid_user(u32 ssid,
+ u32 tsid,
+ u16 tclass,
+ u32 *out_sid)
+{
+ return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
+ out_sid, false);
}
/**
@@ -1379,7 +1525,8 @@ int security_member_sid(u32 ssid,
u16 tclass,
u32 *out_sid)
{
- return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid);
+ return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid,
+ false);
}
/**
@@ -1400,144 +1547,8 @@ int security_change_sid(u32 ssid,
u16 tclass,
u32 *out_sid)
{
- return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid);
-}
-
-/*
- * Verify that each kernel class that is defined in the
- * policy is correct
- */
-static int validate_classes(struct policydb *p)
-{
- int i, j;
- struct class_datum *cladatum;
- struct perm_datum *perdatum;
- u32 nprim, tmp, common_pts_len, perm_val, pol_val;
- u16 class_val;
- const struct selinux_class_perm *kdefs = &selinux_class_perm;
- const char *def_class, *def_perm, *pol_class;
- struct symtab *perms;
- bool print_unknown_handle = 0;
-
- if (p->allow_unknown) {
- u32 num_classes = kdefs->cts_len;
- p->undefined_perms = kcalloc(num_classes, sizeof(u32), GFP_KERNEL);
- if (!p->undefined_perms)
- return -ENOMEM;
- }
-
- for (i = 1; i < kdefs->cts_len; i++) {
- def_class = kdefs->class_to_string[i];
- if (!def_class)
- continue;
- if (i > p->p_classes.nprim) {
- printk(KERN_INFO
- "SELinux: class %s not defined in policy\n",
- def_class);
- if (p->reject_unknown)
- return -EINVAL;
- if (p->allow_unknown)
- p->undefined_perms[i-1] = ~0U;
- print_unknown_handle = 1;
- continue;
- }
- pol_class = p->p_class_val_to_name[i-1];
- if (strcmp(pol_class, def_class)) {
- printk(KERN_ERR
- "SELinux: class %d is incorrect, found %s but should be %s\n",
- i, pol_class, def_class);
- return -EINVAL;
- }
- }
- for (i = 0; i < kdefs->av_pts_len; i++) {
- class_val = kdefs->av_perm_to_string[i].tclass;
- perm_val = kdefs->av_perm_to_string[i].value;
- def_perm = kdefs->av_perm_to_string[i].name;
- if (class_val > p->p_classes.nprim)
- continue;
- pol_class = p->p_class_val_to_name[class_val-1];
- cladatum = hashtab_search(p->p_classes.table, pol_class);
- BUG_ON(!cladatum);
- perms = &cladatum->permissions;
- nprim = 1 << (perms->nprim - 1);
- if (perm_val > nprim) {
- printk(KERN_INFO
- "SELinux: permission %s in class %s not defined in policy\n",
- def_perm, pol_class);
- if (p->reject_unknown)
- return -EINVAL;
- if (p->allow_unknown)
- p->undefined_perms[class_val-1] |= perm_val;
- print_unknown_handle = 1;
- continue;
- }
- perdatum = hashtab_search(perms->table, def_perm);
- if (perdatum == NULL) {
- printk(KERN_ERR
- "SELinux: permission %s in class %s not found in policy, bad policy\n",
- def_perm, pol_class);
- return -EINVAL;
- }
- pol_val = 1 << (perdatum->value - 1);
- if (pol_val != perm_val) {
- printk(KERN_ERR
- "SELinux: permission %s in class %s has incorrect value\n",
- def_perm, pol_class);
- return -EINVAL;
- }
- }
- for (i = 0; i < kdefs->av_inherit_len; i++) {
- class_val = kdefs->av_inherit[i].tclass;
- if (class_val > p->p_classes.nprim)
- continue;
- pol_class = p->p_class_val_to_name[class_val-1];
- cladatum = hashtab_search(p->p_classes.table, pol_class);
- BUG_ON(!cladatum);
- if (!cladatum->comdatum) {
- printk(KERN_ERR
- "SELinux: class %s should have an inherits clause but does not\n",
- pol_class);
- return -EINVAL;
- }
- tmp = kdefs->av_inherit[i].common_base;
- common_pts_len = 0;
- while (!(tmp & 0x01)) {
- common_pts_len++;
- tmp >>= 1;
- }
- perms = &cladatum->comdatum->permissions;
- for (j = 0; j < common_pts_len; j++) {
- def_perm = kdefs->av_inherit[i].common_pts[j];
- if (j >= perms->nprim) {
- printk(KERN_INFO
- "SELinux: permission %s in class %s not defined in policy\n",
- def_perm, pol_class);
- if (p->reject_unknown)
- return -EINVAL;
- if (p->allow_unknown)
- p->undefined_perms[class_val-1] |= (1 << j);
- print_unknown_handle = 1;
- continue;
- }
- perdatum = hashtab_search(perms->table, def_perm);
- if (perdatum == NULL) {
- printk(KERN_ERR
- "SELinux: permission %s in class %s not found in policy, bad policy\n",
- def_perm, pol_class);
- return -EINVAL;
- }
- if (perdatum->value != j + 1) {
- printk(KERN_ERR
- "SELinux: permission %s in class %s has incorrect value\n",
- def_perm, pol_class);
- return -EINVAL;
- }
- }
- }
- if (print_unknown_handle)
- printk(KERN_INFO "SELinux: the above unknown classes and permissions will be %s\n",
- (security_get_allow_unknown() ? "allowed" : "denied"));
- return 0;
+ return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid,
+ false);
}
/* Clone the SID into the new SID table. */
@@ -1710,8 +1721,10 @@ int security_load_policy(void *data, size_t len)
{
struct policydb oldpolicydb, newpolicydb;
struct sidtab oldsidtab, newsidtab;
+ struct selinux_mapping *oldmap, *map = NULL;
struct convert_context_args args;
u32 seqno;
+ u16 map_size;
int rc = 0;
struct policy_file file = { data, len }, *fp = &file;
@@ -1721,22 +1734,19 @@ int security_load_policy(void *data, size_t len)
avtab_cache_destroy();
return -EINVAL;
}
- if (policydb_load_isids(&policydb, &sidtab)) {
+ if (selinux_set_mapping(&policydb, secclass_map,
+ &current_mapping,
+ &current_mapping_size)) {
policydb_destroy(&policydb);
avtab_cache_destroy();
return -EINVAL;
}
- /* Verify that the kernel defined classes are correct. */
- if (validate_classes(&policydb)) {
- printk(KERN_ERR
- "SELinux: the definition of a class is incorrect\n");
- sidtab_destroy(&sidtab);
+ if (policydb_load_isids(&policydb, &sidtab)) {
policydb_destroy(&policydb);
avtab_cache_destroy();
return -EINVAL;
}
security_load_policycaps();
- policydb_loaded_version = policydb.policyvers;
ss_initialized = 1;
seqno = ++latest_granting;
selinux_complete_init();
@@ -1759,13 +1769,9 @@ int security_load_policy(void *data, size_t len)
return -ENOMEM;
}
- /* Verify that the kernel defined classes are correct. */
- if (validate_classes(&newpolicydb)) {
- printk(KERN_ERR
- "SELinux: the definition of a class is incorrect\n");
- rc = -EINVAL;
+ if (selinux_set_mapping(&newpolicydb, secclass_map,
+ &map, &map_size))
goto err;
- }
rc = security_preserve_bools(&newpolicydb);
if (rc) {
@@ -1799,13 +1805,16 @@ int security_load_policy(void *data, size_t len)
memcpy(&policydb, &newpolicydb, sizeof policydb);
sidtab_set(&sidtab, &newsidtab);
security_load_policycaps();
+ oldmap = current_mapping;
+ current_mapping = map;
+ current_mapping_size = map_size;
seqno = ++latest_granting;
- policydb_loaded_version = policydb.policyvers;
write_unlock_irq(&policy_rwlock);
/* Free the old policydb and SID table. */
policydb_destroy(&oldpolicydb);
sidtab_destroy(&oldsidtab);
+ kfree(oldmap);
avc_ss_reset(seqno);
selnl_notify_policyload(seqno);
@@ -1815,6 +1824,7 @@ int security_load_policy(void *data, size_t len)
return 0;
err:
+ kfree(map);
sidtab_destroy(&newsidtab);
policydb_destroy(&newpolicydb);
return rc;
@@ -2091,7 +2101,7 @@ out_unlock:
}
for (i = 0, j = 0; i < mynel; i++) {
rc = avc_has_perm_noaudit(fromsid, mysids[i],
- SECCLASS_PROCESS,
+ SECCLASS_PROCESS, /* kernel value */
PROCESS__TRANSITION, AVC_STRICT,
NULL);
if (!rc)
@@ -2119,10 +2129,11 @@ out:
*/
int security_genfs_sid(const char *fstype,
char *path,
- u16 sclass,
+ u16 orig_sclass,
u32 *sid)
{
int len;
+ u16 sclass;
struct genfs *genfs;
struct ocontext *c;
int rc = 0, cmp = 0;
@@ -2132,6 +2143,8 @@ int security_genfs_sid(const char *fstype,
read_lock(&policy_rwlock);
+ sclass = unmap_class(orig_sclass);
+
for (genfs = policydb.genfs; genfs; genfs = genfs->next) {
cmp = strcmp(fstype, genfs->fstype);
if (cmp <= 0)
diff --git a/sound/Kconfig b/sound/Kconfig
index 439e15c8faa3..4b5365ad6b46 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -1,6 +1,3 @@
-# sound/Config.in
-#
-
menuconfig SOUND
tristate "Sound card support"
depends on HAS_IOMEM
@@ -136,4 +133,3 @@ config AC97_BUS
sound subsystem and other function drivers completely unrelated to
sound although they're sharing the AC97 bus. Concerned drivers
should "select" this.
-
diff --git a/sound/core/isadma.c b/sound/core/isadma.c
index 79f0f16af339..950e19ba91fc 100644
--- a/sound/core/isadma.c
+++ b/sound/core/isadma.c
@@ -85,16 +85,24 @@ EXPORT_SYMBOL(snd_dma_disable);
unsigned int snd_dma_pointer(unsigned long dma, unsigned int size)
{
unsigned long flags;
- unsigned int result;
+ unsigned int result, result1;
flags = claim_dma_lock();
clear_dma_ff(dma);
if (!isa_dma_bridge_buggy)
disable_dma(dma);
result = get_dma_residue(dma);
+ /*
+ * HACK - read the counter again and choose higher value in order to
+ * avoid reading during counter lower byte roll over if the
+ * isa_dma_bridge_buggy is set.
+ */
+ result1 = get_dma_residue(dma);
if (!isa_dma_bridge_buggy)
enable_dma(dma);
release_dma_lock(flags);
+ if (unlikely(result < result1))
+ result = result1;
#ifdef CONFIG_SND_DEBUG
if (result > size)
snd_printk(KERN_ERR "pointer (0x%x) for DMA #%ld is greater than transfer size (0x%x)\n", result, dma, size);
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index c0adc14c91f0..8b1a70b36abc 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -1258,7 +1258,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,
break;
count -= count1;
}
- if (file->f_flags & O_SYNC) {
+ if (file->f_flags & O_DSYNC) {
spin_lock_irq(&runtime->lock);
while (runtime->avail != runtime->buffer_size) {
wait_queue_t wait;
diff --git a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile
index 703d954238f4..2dad40f3f622 100644
--- a/sound/i2c/other/Makefile
+++ b/sound/i2c/other/Makefile
@@ -5,6 +5,7 @@
snd-ak4114-objs := ak4114.o
snd-ak4117-objs := ak4117.o
+snd-ak4113-objs := ak4113.o
snd-ak4xxx-adda-objs := ak4xxx-adda.o
snd-pt2258-objs := pt2258.o
snd-tea575x-tuner-objs := tea575x-tuner.o
@@ -12,5 +13,5 @@ snd-tea575x-tuner-objs := tea575x-tuner.o
# Module Dependency
obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o
obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o
-obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4xxx-adda.o snd-pt2258.o
+obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4113.o snd-ak4xxx-adda.o snd-pt2258.o
obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o
diff --git a/sound/i2c/other/ak4113.c b/sound/i2c/other/ak4113.c
new file mode 100644
index 000000000000..fff62cc8607c
--- /dev/null
+++ b/sound/i2c/other/ak4113.c
@@ -0,0 +1,639 @@
+/*
+ * Routines for control of the AK4113 via I2C/4-wire serial interface
+ * IEC958 (S/PDIF) receiver by Asahi Kasei
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ * Copyright (c) by Pavel Hofman <pavel.hofman@ivitera.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/slab.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/ak4113.h>
+#include <sound/asoundef.h>
+#include <sound/info.h>
+
+MODULE_AUTHOR("Pavel Hofman <pavel.hofman@ivitera.com>");
+MODULE_DESCRIPTION("AK4113 IEC958 (S/PDIF) receiver by Asahi Kasei");
+MODULE_LICENSE("GPL");
+
+#define AK4113_ADDR 0x00 /* fixed address */
+
+static void ak4113_stats(struct work_struct *work);
+static void ak4113_init_regs(struct ak4113 *chip);
+
+
+static void reg_write(struct ak4113 *ak4113, unsigned char reg,
+ unsigned char val)
+{
+ ak4113->write(ak4113->private_data, reg, val);
+ if (reg < sizeof(ak4113->regmap))
+ ak4113->regmap[reg] = val;
+}
+
+static inline unsigned char reg_read(struct ak4113 *ak4113, unsigned char reg)
+{
+ return ak4113->read(ak4113->private_data, reg);
+}
+
+static void snd_ak4113_free(struct ak4113 *chip)
+{
+ chip->init = 1; /* don't schedule new work */
+ mb();
+ cancel_delayed_work(&chip->work);
+ flush_scheduled_work();
+ kfree(chip);
+}
+
+static int snd_ak4113_dev_free(struct snd_device *device)
+{
+ struct ak4113 *chip = device->device_data;
+ snd_ak4113_free(chip);
+ return 0;
+}
+
+int snd_ak4113_create(struct snd_card *card, ak4113_read_t *read,
+ ak4113_write_t *write, const unsigned char pgm[5],
+ void *private_data, struct ak4113 **r_ak4113)
+{
+ struct ak4113 *chip;
+ int err = 0;
+ unsigned char reg;
+ static struct snd_device_ops ops = {
+ .dev_free = snd_ak4113_dev_free,
+ };
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (chip == NULL)
+ return -ENOMEM;
+ spin_lock_init(&chip->lock);
+ chip->card = card;
+ chip->read = read;
+ chip->write = write;
+ chip->private_data = private_data;
+ INIT_DELAYED_WORK(&chip->work, ak4113_stats);
+
+ for (reg = 0; reg < AK4113_WRITABLE_REGS ; reg++)
+ chip->regmap[reg] = pgm[reg];
+ ak4113_init_regs(chip);
+
+ chip->rcs0 = reg_read(chip, AK4113_REG_RCS0) & ~(AK4113_QINT |
+ AK4113_CINT | AK4113_STC);
+ chip->rcs1 = reg_read(chip, AK4113_REG_RCS1);
+ chip->rcs2 = reg_read(chip, AK4113_REG_RCS2);
+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+ if (err < 0)
+ goto __fail;
+
+ if (r_ak4113)
+ *r_ak4113 = chip;
+ return 0;
+
+__fail:
+ snd_ak4113_free(chip);
+ return err < 0 ? err : -EIO;
+}
+EXPORT_SYMBOL_GPL(snd_ak4113_create);
+
+void snd_ak4113_reg_write(struct ak4113 *chip, unsigned char reg,
+ unsigned char mask, unsigned char val)
+{
+ if (reg >= AK4113_WRITABLE_REGS)
+ return;
+ reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val);
+}
+EXPORT_SYMBOL_GPL(snd_ak4113_reg_write);
+
+static void ak4113_init_regs(struct ak4113 *chip)
+{
+ unsigned char old = chip->regmap[AK4113_REG_PWRDN], reg;
+
+ /* bring the chip to reset state and powerdown state */
+ reg_write(chip, AK4113_REG_PWRDN, old & ~(AK4113_RST|AK4113_PWN));
+ udelay(200);
+ /* release reset, but leave powerdown */
+ reg_write(chip, AK4113_REG_PWRDN, (old | AK4113_RST) & ~AK4113_PWN);
+ udelay(200);
+ for (reg = 1; reg < AK4113_WRITABLE_REGS; reg++)
+ reg_write(chip, reg, chip->regmap[reg]);
+ /* release powerdown, everything is initialized now */
+ reg_write(chip, AK4113_REG_PWRDN, old | AK4113_RST | AK4113_PWN);
+}
+
+void snd_ak4113_reinit(struct ak4113 *chip)
+{
+ chip->init = 1;
+ mb();
+ flush_scheduled_work();
+ ak4113_init_regs(chip);
+ /* bring up statistics / event queing */
+ chip->init = 0;
+ if (chip->kctls[0])
+ schedule_delayed_work(&chip->work, HZ / 10);
+}
+EXPORT_SYMBOL_GPL(snd_ak4113_reinit);
+
+static unsigned int external_rate(unsigned char rcs1)
+{
+ switch (rcs1 & (AK4113_FS0|AK4113_FS1|AK4113_FS2|AK4113_FS3)) {
+ case AK4113_FS_8000HZ:
+ return 8000;
+ case AK4113_FS_11025HZ:
+ return 11025;
+ case AK4113_FS_16000HZ:
+ return 16000;
+ case AK4113_FS_22050HZ:
+ return 22050;
+ case AK4113_FS_24000HZ:
+ return 24000;
+ case AK4113_FS_32000HZ:
+ return 32000;
+ case AK4113_FS_44100HZ:
+ return 44100;
+ case AK4113_FS_48000HZ:
+ return 48000;
+ case AK4113_FS_64000HZ:
+ return 64000;
+ case AK4113_FS_88200HZ:
+ return 88200;
+ case AK4113_FS_96000HZ:
+ return 96000;
+ case AK4113_FS_176400HZ:
+ return 176400;
+ case AK4113_FS_192000HZ:
+ return 192000;
+ default:
+ return 0;
+ }
+}
+
+static int snd_ak4113_in_error_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 = LONG_MAX;
+ return 0;
+}
+
+static int snd_ak4113_in_error_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
+ long *ptr;
+
+ spin_lock_irq(&chip->lock);
+ ptr = (long *)(((char *)chip) + kcontrol->private_value);
+ ucontrol->value.integer.value[0] = *ptr;
+ *ptr = 0;
+ spin_unlock_irq(&chip->lock);
+ return 0;
+}
+
+#define snd_ak4113_in_bit_info snd_ctl_boolean_mono_info
+
+static int snd_ak4113_in_bit_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
+ unsigned char reg = kcontrol->private_value & 0xff;
+ unsigned char bit = (kcontrol->private_value >> 8) & 0xff;
+ unsigned char inv = (kcontrol->private_value >> 31) & 1;
+
+ ucontrol->value.integer.value[0] =
+ ((reg_read(chip, reg) & (1 << bit)) ? 1 : 0) ^ inv;
+ return 0;
+}
+
+static int snd_ak4113_rx_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 = 5;
+ return 0;
+}
+
+static int snd_ak4113_rx_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] =
+ (AK4113_IPS(chip->regmap[AK4113_REG_IO1]));
+ return 0;
+}
+
+static int snd_ak4113_rx_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
+ int change;
+ u8 old_val;
+
+ spin_lock_irq(&chip->lock);
+ old_val = chip->regmap[AK4113_REG_IO1];
+ change = ucontrol->value.integer.value[0] != AK4113_IPS(old_val);
+ if (change)
+ reg_write(chip, AK4113_REG_IO1,
+ (old_val & (~AK4113_IPS(0xff))) |
+ (AK4113_IPS(ucontrol->value.integer.value[0])));
+ spin_unlock_irq(&chip->lock);
+ return change;
+}
+
+static int snd_ak4113_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;
+ return 0;
+}
+
+static int snd_ak4113_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = external_rate(reg_read(chip,
+ AK4113_REG_RCS1));
+ return 0;
+}
+
+static int snd_ak4113_spdif_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
+ return 0;
+}
+
+static int snd_ak4113_spdif_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
+ unsigned i;
+
+ for (i = 0; i < AK4113_REG_RXCSB_SIZE; i++)
+ ucontrol->value.iec958.status[i] = reg_read(chip,
+ AK4113_REG_RXCSB0 + i);
+ return 0;
+}
+
+static int snd_ak4113_spdif_mask_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
+ return 0;
+}
+
+static int snd_ak4113_spdif_mask_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ memset(ucontrol->value.iec958.status, 0xff, AK4113_REG_RXCSB_SIZE);
+ return 0;
+}
+
+static int snd_ak4113_spdif_pinfo(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 0xffff;
+ uinfo->count = 4;
+ return 0;
+}
+
+static int snd_ak4113_spdif_pget(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
+ unsigned short tmp;
+
+ ucontrol->value.integer.value[0] = 0xf8f2;
+ ucontrol->value.integer.value[1] = 0x4e1f;
+ tmp = reg_read(chip, AK4113_REG_Pc0) |
+ (reg_read(chip, AK4113_REG_Pc1) << 8);
+ ucontrol->value.integer.value[2] = tmp;
+ tmp = reg_read(chip, AK4113_REG_Pd0) |
+ (reg_read(chip, AK4113_REG_Pd1) << 8);
+ ucontrol->value.integer.value[3] = tmp;
+ return 0;
+}
+
+static int snd_ak4113_spdif_qinfo(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = AK4113_REG_QSUB_SIZE;
+ return 0;
+}
+
+static int snd_ak4113_spdif_qget(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct ak4113 *chip = snd_kcontrol_chip(kcontrol);
+ unsigned i;
+
+ for (i = 0; i < AK4113_REG_QSUB_SIZE; i++)
+ ucontrol->value.bytes.data[i] = reg_read(chip,
+ AK4113_REG_QSUB_ADDR + i);
+ return 0;
+}
+
+/* Don't forget to change AK4113_CONTROLS define!!! */
+static struct snd_kcontrol_new snd_ak4113_iec958_controls[] = {
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "IEC958 Parity Errors",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = snd_ak4113_in_error_info,
+ .get = snd_ak4113_in_error_get,
+ .private_value = offsetof(struct ak4113, parity_errors),
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "IEC958 V-Bit Errors",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = snd_ak4113_in_error_info,
+ .get = snd_ak4113_in_error_get,
+ .private_value = offsetof(struct ak4113, v_bit_errors),
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "IEC958 C-CRC Errors",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = snd_ak4113_in_error_info,
+ .get = snd_ak4113_in_error_get,
+ .private_value = offsetof(struct ak4113, ccrc_errors),
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "IEC958 Q-CRC Errors",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = snd_ak4113_in_error_info,
+ .get = snd_ak4113_in_error_get,
+ .private_value = offsetof(struct ak4113, qcrc_errors),
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "IEC958 External Rate",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = snd_ak4113_rate_info,
+ .get = snd_ak4113_rate_get,
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK),
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .info = snd_ak4113_spdif_mask_info,
+ .get = snd_ak4113_spdif_mask_get,
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = snd_ak4113_spdif_info,
+ .get = snd_ak4113_spdif_get,
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "IEC958 Preample Capture Default",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = snd_ak4113_spdif_pinfo,
+ .get = snd_ak4113_spdif_pget,
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "IEC958 Q-subcode Capture Default",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = snd_ak4113_spdif_qinfo,
+ .get = snd_ak4113_spdif_qget,
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "IEC958 Audio",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = snd_ak4113_in_bit_info,
+ .get = snd_ak4113_in_bit_get,
+ .private_value = (1<<31) | (1<<8) | AK4113_REG_RCS0,
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "IEC958 Non-PCM Bitstream",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = snd_ak4113_in_bit_info,
+ .get = snd_ak4113_in_bit_get,
+ .private_value = (0<<8) | AK4113_REG_RCS1,
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "IEC958 DTS Bitstream",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = snd_ak4113_in_bit_info,
+ .get = snd_ak4113_in_bit_get,
+ .private_value = (1<<8) | AK4113_REG_RCS1,
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "AK4113 Input Select",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_WRITE,
+ .info = snd_ak4113_rx_info,
+ .get = snd_ak4113_rx_get,
+ .put = snd_ak4113_rx_put,
+}
+};
+
+static void snd_ak4113_proc_regs_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct ak4113 *ak4113 = entry->private_data;
+ int reg, val;
+ /* all ak4113 registers 0x00 - 0x1c */
+ for (reg = 0; reg < 0x1d; reg++) {
+ val = reg_read(ak4113, reg);
+ snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val);
+ }
+}
+
+static void snd_ak4113_proc_init(struct ak4113 *ak4113)
+{
+ struct snd_info_entry *entry;
+ if (!snd_card_proc_new(ak4113->card, "ak4113", &entry))
+ snd_info_set_text_ops(entry, ak4113, snd_ak4113_proc_regs_read);
+}
+
+int snd_ak4113_build(struct ak4113 *ak4113,
+ struct snd_pcm_substream *cap_substream)
+{
+ struct snd_kcontrol *kctl;
+ unsigned int idx;
+ int err;
+
+ if (snd_BUG_ON(!cap_substream))
+ return -EINVAL;
+ ak4113->substream = cap_substream;
+ for (idx = 0; idx < AK4113_CONTROLS; idx++) {
+ kctl = snd_ctl_new1(&snd_ak4113_iec958_controls[idx], ak4113);
+ if (kctl == NULL)
+ return -ENOMEM;
+ kctl->id.device = cap_substream->pcm->device;
+ kctl->id.subdevice = cap_substream->number;
+ err = snd_ctl_add(ak4113->card, kctl);
+ if (err < 0)
+ return err;
+ ak4113->kctls[idx] = kctl;
+ }
+ snd_ak4113_proc_init(ak4113);
+ /* trigger workq */
+ schedule_delayed_work(&ak4113->work, HZ / 10);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_ak4113_build);
+
+int snd_ak4113_external_rate(struct ak4113 *ak4113)
+{
+ unsigned char rcs1;
+
+ rcs1 = reg_read(ak4113, AK4113_REG_RCS1);
+ return external_rate(rcs1);
+}
+EXPORT_SYMBOL_GPL(snd_ak4113_external_rate);
+
+int snd_ak4113_check_rate_and_errors(struct ak4113 *ak4113, unsigned int flags)
+{
+ struct snd_pcm_runtime *runtime =
+ ak4113->substream ? ak4113->substream->runtime : NULL;
+ unsigned long _flags;
+ int res = 0;
+ unsigned char rcs0, rcs1, rcs2;
+ unsigned char c0, c1;
+
+ rcs1 = reg_read(ak4113, AK4113_REG_RCS1);
+ if (flags & AK4113_CHECK_NO_STAT)
+ goto __rate;
+ rcs0 = reg_read(ak4113, AK4113_REG_RCS0);
+ rcs2 = reg_read(ak4113, AK4113_REG_RCS2);
+ spin_lock_irqsave(&ak4113->lock, _flags);
+ if (rcs0 & AK4113_PAR)
+ ak4113->parity_errors++;
+ if (rcs0 & AK4113_V)
+ ak4113->v_bit_errors++;
+ if (rcs2 & AK4113_CCRC)
+ ak4113->ccrc_errors++;
+ if (rcs2 & AK4113_QCRC)
+ ak4113->qcrc_errors++;
+ c0 = (ak4113->rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC |
+ AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK)) ^
+ (rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC |
+ AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK));
+ c1 = (ak4113->rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM |
+ AK4113_DAT | 0xf0)) ^
+ (rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM |
+ AK4113_DAT | 0xf0));
+ ak4113->rcs0 = rcs0 & ~(AK4113_QINT | AK4113_CINT | AK4113_STC);
+ ak4113->rcs1 = rcs1;
+ ak4113->rcs2 = rcs2;
+ spin_unlock_irqrestore(&ak4113->lock, _flags);
+
+ if (rcs0 & AK4113_PAR)
+ snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &ak4113->kctls[0]->id);
+ if (rcs0 & AK4113_V)
+ snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &ak4113->kctls[1]->id);
+ if (rcs2 & AK4113_CCRC)
+ snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &ak4113->kctls[2]->id);
+ if (rcs2 & AK4113_QCRC)
+ snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &ak4113->kctls[3]->id);
+
+ /* rate change */
+ if (c1 & 0xf0)
+ snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &ak4113->kctls[4]->id);
+
+ if ((c1 & AK4113_PEM) | (c0 & AK4113_CINT))
+ snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &ak4113->kctls[6]->id);
+ if (c0 & AK4113_QINT)
+ snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &ak4113->kctls[8]->id);
+
+ if (c0 & AK4113_AUDION)
+ snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &ak4113->kctls[9]->id);
+ if (c1 & AK4113_NPCM)
+ snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &ak4113->kctls[10]->id);
+ if (c1 & AK4113_DTSCD)
+ snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &ak4113->kctls[11]->id);
+
+ if (ak4113->change_callback && (c0 | c1) != 0)
+ ak4113->change_callback(ak4113, c0, c1);
+
+__rate:
+ /* compare rate */
+ res = external_rate(rcs1);
+ if (!(flags & AK4113_CHECK_NO_RATE) && runtime &&
+ (runtime->rate != res)) {
+ snd_pcm_stream_lock_irqsave(ak4113->substream, _flags);
+ if (snd_pcm_running(ak4113->substream)) {
+ /*printk(KERN_DEBUG "rate changed (%i <- %i)\n",
+ * runtime->rate, res); */
+ snd_pcm_stop(ak4113->substream,
+ SNDRV_PCM_STATE_DRAINING);
+ wake_up(&runtime->sleep);
+ res = 1;
+ }
+ snd_pcm_stream_unlock_irqrestore(ak4113->substream, _flags);
+ }
+ return res;
+}
+EXPORT_SYMBOL_GPL(snd_ak4113_check_rate_and_errors);
+
+static void ak4113_stats(struct work_struct *work)
+{
+ struct ak4113 *chip = container_of(work, struct ak4113, work.work);
+
+ if (!chip->init)
+ snd_ak4113_check_rate_and_errors(chip, chip->check_flags);
+
+ schedule_delayed_work(&chip->work, HZ / 10);
+}
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index ee47abab764e..1adb8a3c2b62 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -19,7 +19,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- */
+ */
#include <asm/io.h>
#include <linux/delay.h>
@@ -29,6 +29,7 @@
#include <sound/control.h>
#include <sound/tlv.h>
#include <sound/ak4xxx-adda.h>
+#include <sound/info.h>
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>");
MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters");
@@ -52,26 +53,21 @@ EXPORT_SYMBOL(snd_akm4xxx_write);
static void ak4524_reset(struct snd_akm4xxx *ak, int state)
{
unsigned int chip;
- unsigned char reg, maxreg;
+ unsigned char reg;
- if (ak->type == SND_AK4528)
- maxreg = 0x06;
- else
- maxreg = 0x08;
for (chip = 0; chip < ak->num_dacs/2; chip++) {
snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03);
if (state)
continue;
/* DAC volumes */
- for (reg = 0x04; reg < maxreg; reg++)
+ for (reg = 0x04; reg < ak->total_regs; reg++)
snd_akm4xxx_write(ak, chip, reg,
snd_akm4xxx_get(ak, chip, reg));
}
}
/* reset procedure for AK4355 and AK4358 */
-static void ak435X_reset(struct snd_akm4xxx *ak, int state,
- unsigned char total_regs)
+static void ak435X_reset(struct snd_akm4xxx *ak, int state)
{
unsigned char reg;
@@ -79,7 +75,7 @@ static void ak435X_reset(struct snd_akm4xxx *ak, int state,
snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
return;
}
- for (reg = 0x00; reg < total_regs; reg++)
+ for (reg = 0x00; reg < ak->total_regs; reg++)
if (reg != 0x01)
snd_akm4xxx_write(ak, 0, reg,
snd_akm4xxx_get(ak, 0, reg));
@@ -91,12 +87,11 @@ static void ak4381_reset(struct snd_akm4xxx *ak, int state)
{
unsigned int chip;
unsigned char reg;
-
for (chip = 0; chip < ak->num_dacs/2; chip++) {
snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f);
if (state)
continue;
- for (reg = 0x01; reg < 0x05; reg++)
+ for (reg = 0x01; reg < ak->total_regs; reg++)
snd_akm4xxx_write(ak, chip, reg,
snd_akm4xxx_get(ak, chip, reg));
}
@@ -113,16 +108,17 @@ void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state)
switch (ak->type) {
case SND_AK4524:
case SND_AK4528:
+ case SND_AK4620:
ak4524_reset(ak, state);
break;
case SND_AK4529:
/* FIXME: needed for ak4529? */
break;
case SND_AK4355:
- ak435X_reset(ak, state, 0x0b);
+ ak435X_reset(ak, state);
break;
case SND_AK4358:
- ak435X_reset(ak, state, 0x10);
+ ak435X_reset(ak, state);
break;
case SND_AK4381:
ak4381_reset(ak, state);
@@ -139,7 +135,7 @@ EXPORT_SYMBOL(snd_akm4xxx_reset);
* Volume conversion table for non-linear volumes
* from -63.5dB (mute) to 0dB step 0.5dB
*
- * Used for AK4524 input/ouput attenuation, AK4528, and
+ * Used for AK4524/AK4620 input/ouput attenuation, AK4528, and
* AK5365 input attenuation
*/
static const unsigned char vol_cvt_datt[128] = {
@@ -259,8 +255,22 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
0x00, 0x0f, /* 0: power-up, un-reset */
0xff, 0xff
};
+ static const unsigned char inits_ak4620[] = {
+ 0x00, 0x07, /* 0: normal */
+ 0x01, 0x00, /* 0: reset */
+ 0x01, 0x02, /* 1: RSTAD */
+ 0x01, 0x03, /* 1: RSTDA */
+ 0x01, 0x0f, /* 1: normal */
+ 0x02, 0x60, /* 2: 24bit I2S */
+ 0x03, 0x01, /* 3: deemphasis off */
+ 0x04, 0x00, /* 4: LIN muted */
+ 0x05, 0x00, /* 5: RIN muted */
+ 0x06, 0x00, /* 6: LOUT muted */
+ 0x07, 0x00, /* 7: ROUT muted */
+ 0xff, 0xff
+ };
- int chip, num_chips;
+ int chip;
const unsigned char *ptr, *inits;
unsigned char reg, data;
@@ -270,42 +280,64 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
switch (ak->type) {
case SND_AK4524:
inits = inits_ak4524;
- num_chips = ak->num_dacs / 2;
+ ak->num_chips = ak->num_dacs / 2;
+ ak->name = "ak4524";
+ ak->total_regs = 0x08;
break;
case SND_AK4528:
inits = inits_ak4528;
- num_chips = ak->num_dacs / 2;
+ ak->num_chips = ak->num_dacs / 2;
+ ak->name = "ak4528";
+ ak->total_regs = 0x06;
break;
case SND_AK4529:
inits = inits_ak4529;
- num_chips = 1;
+ ak->num_chips = 1;
+ ak->name = "ak4529";
+ ak->total_regs = 0x0d;
break;
case SND_AK4355:
inits = inits_ak4355;
- num_chips = 1;
+ ak->num_chips = 1;
+ ak->name = "ak4355";
+ ak->total_regs = 0x0b;
break;
case SND_AK4358:
inits = inits_ak4358;
- num_chips = 1;
+ ak->num_chips = 1;
+ ak->name = "ak4358";
+ ak->total_regs = 0x10;
break;
case SND_AK4381:
inits = inits_ak4381;
- num_chips = ak->num_dacs / 2;
+ ak->num_chips = ak->num_dacs / 2;
+ ak->name = "ak4381";
+ ak->total_regs = 0x05;
break;
case SND_AK5365:
/* FIXME: any init sequence? */
+ ak->num_chips = 1;
+ ak->name = "ak5365";
+ ak->total_regs = 0x08;
return;
+ case SND_AK4620:
+ inits = inits_ak4620;
+ ak->num_chips = ak->num_dacs / 2;
+ ak->name = "ak4620";
+ ak->total_regs = 0x08;
+ break;
default:
snd_BUG();
return;
}
- for (chip = 0; chip < num_chips; chip++) {
+ for (chip = 0; chip < ak->num_chips; chip++) {
ptr = inits;
while (*ptr != 0xff) {
reg = *ptr++;
data = *ptr++;
snd_akm4xxx_write(ak, chip, reg, data);
+ udelay(10);
}
}
}
@@ -688,6 +720,12 @@ static int build_dac_controls(struct snd_akm4xxx *ak)
AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
knew.tlv.p = db_scale_linear;
break;
+ case SND_AK4620:
+ /* register 6 & 7 */
+ knew.private_value =
+ AK_COMPOSE(idx/2, (idx%2) + 6, 0, 255);
+ knew.tlv.p = db_scale_linear;
+ break;
default:
return -EINVAL;
}
@@ -704,10 +742,12 @@ static int build_dac_controls(struct snd_akm4xxx *ak)
static int build_adc_controls(struct snd_akm4xxx *ak)
{
- int idx, err, mixer_ch, num_stereo;
+ int idx, err, mixer_ch, num_stereo, max_steps;
struct snd_kcontrol_new knew;
mixer_ch = 0;
+ if (ak->type == SND_AK4528)
+ return 0; /* no controls */
for (idx = 0; idx < ak->num_adcs;) {
memset(&knew, 0, sizeof(knew));
if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) {
@@ -733,13 +773,12 @@ static int build_adc_controls(struct snd_akm4xxx *ak)
}
/* register 4 & 5 */
if (ak->type == SND_AK5365)
- knew.private_value =
- AK_COMPOSE(idx/2, (idx%2) + 4, 0, 151) |
- AK_VOL_CVT | AK_IPGA;
+ max_steps = 152;
else
- knew.private_value =
- AK_COMPOSE(idx/2, (idx%2) + 4, 0, 163) |
- AK_VOL_CVT | AK_IPGA;
+ max_steps = 164;
+ knew.private_value =
+ AK_COMPOSE(idx/2, (idx%2) + 4, 0, max_steps) |
+ AK_VOL_CVT | AK_IPGA;
knew.tlv.p = db_scale_vol_datt;
err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
if (err < 0)
@@ -808,6 +847,7 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
switch (ak->type) {
case SND_AK4524:
case SND_AK4528:
+ case SND_AK4620:
/* register 3 */
knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
break;
@@ -834,6 +874,35 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
return 0;
}
+#ifdef CONFIG_PROC_FS
+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;
+ int reg, val, chip;
+ for (chip = 0; chip < ak->num_chips; chip++) {
+ for (reg = 0; reg < ak->total_regs; reg++) {
+ val = snd_akm4xxx_get(ak, chip, reg);
+ snd_iprintf(buffer, "chip %d: 0x%02x = 0x%02x\n", chip,
+ reg, val);
+ }
+ }
+}
+
+static int proc_init(struct snd_akm4xxx *ak)
+{
+ struct snd_info_entry *entry;
+ int err;
+ err = snd_card_proc_new(ak->card, ak->name, &entry);
+ if (err < 0)
+ return err;
+ snd_info_set_text_ops(entry, ak, proc_regs_read);
+ return 0;
+}
+#else /* !CONFIG_PROC_FS */
+static int proc_init(struct snd_akm4xxx *ak) {}
+#endif
+
int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
{
int err, num_emphs;
@@ -845,18 +914,21 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
err = build_adc_controls(ak);
if (err < 0)
return err;
-
if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
num_emphs = 1;
+ else if (ak->type == SND_AK4620)
+ num_emphs = 0;
else
num_emphs = ak->num_dacs / 2;
err = build_deemphasis(ak, num_emphs);
if (err < 0)
return err;
+ err = proc_init(ak);
+ if (err < 0)
+ return err;
return 0;
}
-
EXPORT_SYMBOL(snd_akm4xxx_build_controls);
static int __init alsa_akm4xxx_module_init(void)
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index 51a7e3777e17..02fe81ca88fd 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -372,15 +372,21 @@ config SND_SGALAXY
config SND_SSCAPE
tristate "Ensoniq SoundScape driver"
- select SND_HWDEP
select SND_MPU401_UART
select SND_WSS_LIB
+ select FW_LOADER
help
Say Y here to include support for Ensoniq SoundScape
- soundcards.
+ and Ensoniq OEM soundcards.
The PCM audio is supported on SoundScape Classic, Elite, PnP
- and VIVO cards. The MIDI support is very experimental.
+ and VIVO cards. The supported OEM cards are SPEA Media FX and
+ Reveal SC-600.
+ The MIDI support is very experimental and requires binary
+ firmware files called "scope.cod" and "sndscape.co?" where the
+ ? is digit 0, 1, 2, 3 or 4. The firmware files can be found
+ in DOS or Windows driver packages. One has to put the firmware
+ files into the /lib/firmware directory.
To compile this driver as a module, choose M here: the module
will be called snd-sscape.
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
index 66187122377c..e2d5d2d3ed96 100644
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -1,5 +1,5 @@
/*
- * Low-level ALSA driver for the ENSONIQ SoundScape PnP
+ * Low-level ALSA driver for the ENSONIQ SoundScape
* Copyright (c) by Chris Rankin
*
* This driver was written in part using information obtained from
@@ -25,31 +25,36 @@
#include <linux/err.h>
#include <linux/isa.h>
#include <linux/delay.h>
+#include <linux/firmware.h>
#include <linux/pnp.h>
#include <linux/spinlock.h>
#include <linux/moduleparam.h>
#include <asm/dma.h>
#include <sound/core.h>
-#include <sound/hwdep.h>
#include <sound/wss.h>
#include <sound/mpu401.h>
#include <sound/initval.h>
-#include <sound/sscape_ioctl.h>
-
MODULE_AUTHOR("Chris Rankin");
-MODULE_DESCRIPTION("ENSONIQ SoundScape PnP driver");
+MODULE_DESCRIPTION("ENSONIQ SoundScape driver");
MODULE_LICENSE("GPL");
-
-static int index[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IDX;
-static char* id[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_STR;
-static long port[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT;
-static long wss_port[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT;
-static int irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ;
-static int mpu_irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ;
-static int dma[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_DMA;
-static int dma2[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_DMA;
+MODULE_FIRMWARE("sndscape.co0");
+MODULE_FIRMWARE("sndscape.co1");
+MODULE_FIRMWARE("sndscape.co2");
+MODULE_FIRMWARE("sndscape.co3");
+MODULE_FIRMWARE("sndscape.co4");
+MODULE_FIRMWARE("scope.cod");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long wss_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 dma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+static bool joystick[SNDRV_CARDS];
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index number for SoundScape soundcard");
@@ -75,6 +80,9 @@ MODULE_PARM_DESC(dma, "DMA # for SoundScape driver.");
module_param_array(dma2, int, NULL, 0444);
MODULE_PARM_DESC(dma2, "DMA2 # for SoundScape driver.");
+module_param_array(joystick, bool, NULL, 0444);
+MODULE_PARM_DESC(joystick, "Enable gameport.");
+
#ifdef CONFIG_PNP
static int isa_registered;
static int pnp_registered;
@@ -101,14 +109,14 @@ MODULE_DEVICE_TABLE(pnp_card, sscape_pnpids);
#define RX_READY 0x01
#define TX_READY 0x02
-#define CMD_ACK 0x80
-#define CMD_SET_MIDI_VOL 0x84
-#define CMD_GET_MIDI_VOL 0x85
-#define CMD_XXX_MIDI_VOL 0x86
-#define CMD_SET_EXTMIDI 0x8a
-#define CMD_GET_EXTMIDI 0x8b
-#define CMD_SET_MT32 0x8c
-#define CMD_GET_MT32 0x8d
+#define CMD_ACK 0x80
+#define CMD_SET_MIDI_VOL 0x84
+#define CMD_GET_MIDI_VOL 0x85
+#define CMD_XXX_MIDI_VOL 0x86
+#define CMD_SET_EXTMIDI 0x8a
+#define CMD_GET_EXTMIDI 0x8b
+#define CMD_SET_MT32 0x8c
+#define CMD_GET_MT32 0x8d
enum GA_REG {
GA_INTSTAT_REG = 0,
@@ -127,7 +135,8 @@ enum GA_REG {
enum card_type {
- SSCAPE,
+ MEDIA_FX, /* Sequoia S-1000 */
+ SSCAPE, /* Sequoia S-2000 */
SSCAPE_PNP,
SSCAPE_VIVO,
};
@@ -140,16 +149,7 @@ struct soundscape {
struct resource *io_res;
struct resource *wss_res;
struct snd_wss *chip;
- struct snd_mpu401 *mpu;
- struct snd_hwdep *hw;
- /*
- * The MIDI device won't work until we've loaded
- * its firmware via a hardware-dependent device IOCTL
- */
- spinlock_t fwlock;
- int hw_in_use;
- unsigned long midi_usage;
unsigned char midi_vol;
};
@@ -161,28 +161,21 @@ static inline struct soundscape *get_card_soundscape(struct snd_card *c)
return (struct soundscape *) (c->private_data);
}
-static inline struct soundscape *get_mpu401_soundscape(struct snd_mpu401 * mpu)
-{
- return (struct soundscape *) (mpu->private_data);
-}
-
-static inline struct soundscape *get_hwdep_soundscape(struct snd_hwdep * hw)
-{
- return (struct soundscape *) (hw->private_data);
-}
-
-
/*
* Allocates some kernel memory that we can use for DMA.
* I think this means that the memory has to map to
* contiguous pages of physical memory.
*/
-static struct snd_dma_buffer *get_dmabuf(struct snd_dma_buffer *buf, unsigned long size)
+static struct snd_dma_buffer *get_dmabuf(struct snd_dma_buffer *buf,
+ unsigned long size)
{
if (buf) {
- if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(),
+ if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV,
+ snd_dma_isa_data(),
size, buf) < 0) {
- snd_printk(KERN_ERR "sscape: Failed to allocate %lu bytes for DMA\n", size);
+ snd_printk(KERN_ERR "sscape: Failed to allocate "
+ "%lu bytes for DMA\n",
+ size);
return NULL;
}
}
@@ -199,13 +192,13 @@ static void free_dmabuf(struct snd_dma_buffer *buf)
snd_dma_free_pages(buf);
}
-
/*
* This function writes to the SoundScape's control registers,
* but doesn't do any locking. It's up to the caller to do that.
* This is why this function is "unsafe" ...
*/
-static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg, unsigned char val)
+static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg,
+ unsigned char val)
{
outb(reg, ODIE_ADDR_IO(io_base));
outb(val, ODIE_DATA_IO(io_base));
@@ -215,7 +208,8 @@ static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg, unsign
* Write to the SoundScape's control registers, and do the
* necessary locking ...
*/
-static void sscape_write(struct soundscape *s, enum GA_REG reg, unsigned char val)
+static void sscape_write(struct soundscape *s, enum GA_REG reg,
+ unsigned char val)
{
unsigned long flags;
@@ -228,7 +222,8 @@ static void sscape_write(struct soundscape *s, enum GA_REG reg, unsigned char va
* Read from the SoundScape's control registers, but leave any
* locking to the caller. This is why the function is "unsafe" ...
*/
-static inline unsigned char sscape_read_unsafe(unsigned io_base, enum GA_REG reg)
+static inline unsigned char sscape_read_unsafe(unsigned io_base,
+ enum GA_REG reg)
{
outb(reg, ODIE_ADDR_IO(io_base));
return inb(ODIE_DATA_IO(io_base));
@@ -257,9 +252,8 @@ static inline void set_midi_mode_unsafe(unsigned io_base)
static inline int host_read_unsafe(unsigned io_base)
{
int data = -1;
- if ((inb(HOST_CTRL_IO(io_base)) & RX_READY) != 0) {
+ if ((inb(HOST_CTRL_IO(io_base)) & RX_READY) != 0)
data = inb(HOST_DATA_IO(io_base));
- }
return data;
}
@@ -301,7 +295,7 @@ static inline int host_write_unsafe(unsigned io_base, unsigned char data)
* Also leaves all locking-issues to the caller ...
*/
static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data,
- unsigned timeout)
+ unsigned timeout)
{
int err;
@@ -320,7 +314,7 @@ static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data,
*
* NOTE: This check is based upon observation, not documentation.
*/
-static inline int verify_mpu401(const struct snd_mpu401 * mpu)
+static inline int verify_mpu401(const struct snd_mpu401 *mpu)
{
return ((inb(MPU401C(mpu)) & 0xc0) == 0x80);
}
@@ -328,7 +322,7 @@ static inline int verify_mpu401(const struct snd_mpu401 * mpu)
/*
* This is apparently the standard way to initailise an MPU-401
*/
-static inline void initialise_mpu401(const struct snd_mpu401 * mpu)
+static inline void initialise_mpu401(const struct snd_mpu401 *mpu)
{
outb(0, MPU401D(mpu));
}
@@ -338,9 +332,10 @@ static inline void initialise_mpu401(const struct snd_mpu401 * mpu)
* The AD1845 detection fails if we *don't* do this, so I
* think that this is a good idea ...
*/
-static inline void activate_ad1845_unsafe(unsigned io_base)
+static void activate_ad1845_unsafe(unsigned io_base)
{
- sscape_write_unsafe(io_base, GA_HMCTL_REG, (sscape_read_unsafe(io_base, GA_HMCTL_REG) & 0xcf) | 0x10);
+ unsigned char val = sscape_read_unsafe(io_base, GA_HMCTL_REG);
+ sscape_write_unsafe(io_base, GA_HMCTL_REG, (val & 0xcf) | 0x10);
sscape_write_unsafe(io_base, GA_CDCFG_REG, 0x80);
}
@@ -359,24 +354,27 @@ static void soundscape_free(struct snd_card *c)
* Tell the SoundScape to begin a DMA tranfer using the given channel.
* All locking issues are left to the caller.
*/
-static inline void sscape_start_dma_unsafe(unsigned io_base, enum GA_REG reg)
+static void sscape_start_dma_unsafe(unsigned io_base, enum GA_REG reg)
{
- sscape_write_unsafe(io_base, reg, sscape_read_unsafe(io_base, reg) | 0x01);
- sscape_write_unsafe(io_base, reg, sscape_read_unsafe(io_base, reg) & 0xfe);
+ sscape_write_unsafe(io_base, reg,
+ sscape_read_unsafe(io_base, reg) | 0x01);
+ sscape_write_unsafe(io_base, reg,
+ sscape_read_unsafe(io_base, reg) & 0xfe);
}
/*
* Wait for a DMA transfer to complete. This is a "limited busy-wait",
* and all locking issues are left to the caller.
*/
-static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg, unsigned timeout)
+static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg,
+ unsigned timeout)
{
while (!(sscape_read_unsafe(io_base, reg) & 0x01) && (timeout != 0)) {
udelay(100);
--timeout;
} /* while */
- return (sscape_read_unsafe(io_base, reg) & 0x01);
+ return sscape_read_unsafe(io_base, reg) & 0x01;
}
/*
@@ -392,12 +390,12 @@ static int obp_startup_ack(struct soundscape *s, unsigned timeout)
do {
unsigned long flags;
- unsigned char x;
+ int x;
spin_lock_irqsave(&s->lock, flags);
- x = inb(HOST_DATA_IO(s->io_base));
+ x = host_read_unsafe(s->io_base);
spin_unlock_irqrestore(&s->lock, flags);
- if ((x & 0xfe) == 0xfe)
+ if (x == 0xfe || x == 0xff)
return 1;
msleep(10);
@@ -419,10 +417,10 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout)
do {
unsigned long flags;
- unsigned char x;
+ int x;
spin_lock_irqsave(&s->lock, flags);
- x = inb(HOST_DATA_IO(s->io_base));
+ x = host_read_unsafe(s->io_base);
spin_unlock_irqrestore(&s->lock, flags);
if (x == 0xfe)
return 1;
@@ -436,15 +434,15 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout)
/*
* Upload a byte-stream into the SoundScape using DMA channel A.
*/
-static int upload_dma_data(struct soundscape *s,
- const unsigned char __user *data,
- size_t size)
+static int upload_dma_data(struct soundscape *s, const unsigned char *data,
+ size_t size)
{
unsigned long flags;
struct snd_dma_buffer dma;
int ret;
+ unsigned char val;
- if (!get_dmabuf(&dma, PAGE_ALIGN(size)))
+ if (!get_dmabuf(&dma, PAGE_ALIGN(32 * 1024)))
return -ENOMEM;
spin_lock_irqsave(&s->lock, flags);
@@ -452,70 +450,57 @@ static int upload_dma_data(struct soundscape *s,
/*
* Reset the board ...
*/
- sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f);
+ val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
+ sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val & 0x3f);
/*
* Enable the DMA channels and configure them ...
*/
- sscape_write_unsafe(s->io_base, GA_DMACFG_REG, 0x50);
- sscape_write_unsafe(s->io_base, GA_DMAA_REG, (s->chip->dma1 << 4) | DMA_8BIT);
+ val = (s->chip->dma1 << 4) | DMA_8BIT;
+ sscape_write_unsafe(s->io_base, GA_DMAA_REG, val);
sscape_write_unsafe(s->io_base, GA_DMAB_REG, 0x20);
/*
* Take the board out of reset ...
*/
- sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x80);
+ val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
+ sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x80);
/*
- * Upload the user's data (firmware?) to the SoundScape
+ * Upload the firmware to the SoundScape
* board through the DMA channel ...
*/
while (size != 0) {
unsigned long len;
- /*
- * Apparently, copying to/from userspace can sleep.
- * We are therefore forbidden from holding any
- * spinlocks while we copy ...
- */
- spin_unlock_irqrestore(&s->lock, flags);
-
- /*
- * Remember that the data that we want to DMA
- * comes from USERSPACE. We have already verified
- * the userspace pointer ...
- */
len = min(size, dma.bytes);
- len -= __copy_from_user(dma.area, data, len);
+ memcpy(dma.area, data, len);
data += len;
size -= len;
- /*
- * Grab that spinlock again, now that we've
- * finished copying!
- */
- spin_lock_irqsave(&s->lock, flags);
-
snd_dma_program(s->chip->dma1, dma.addr, len, DMA_MODE_WRITE);
sscape_start_dma_unsafe(s->io_base, GA_DMAA_REG);
if (!sscape_wait_dma_unsafe(s->io_base, GA_DMAA_REG, 5000)) {
/*
- * Don't forget to release this spinlock we're holding ...
+ * Don't forget to release this spinlock we're holding
*/
spin_unlock_irqrestore(&s->lock, flags);
- snd_printk(KERN_ERR "sscape: DMA upload has timed out\n");
+ snd_printk(KERN_ERR
+ "sscape: DMA upload has timed out\n");
ret = -EAGAIN;
goto _release_dma;
}
} /* while */
set_host_mode_unsafe(s->io_base);
+ outb(0x0, s->io_base);
/*
* Boot the board ... (I think)
*/
- sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x40);
+ val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
+ sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x40);
spin_unlock_irqrestore(&s->lock, flags);
/*
@@ -525,10 +510,12 @@ static int upload_dma_data(struct soundscape *s,
*/
ret = 0;
if (!obp_startup_ack(s, 5000)) {
- snd_printk(KERN_ERR "sscape: No response from on-board processor after upload\n");
+ snd_printk(KERN_ERR "sscape: No response "
+ "from on-board processor after upload\n");
ret = -EAGAIN;
} else if (!host_startup_ack(s, 5000)) {
- snd_printk(KERN_ERR "sscape: SoundScape failed to initialise\n");
+ snd_printk(KERN_ERR
+ "sscape: SoundScape failed to initialise\n");
ret = -EAGAIN;
}
@@ -536,7 +523,7 @@ _release_dma:
/*
* NOTE!!! We are NOT holding any spinlocks at this point !!!
*/
- sscape_write(s, GA_DMAA_REG, (s->ic_type == IC_ODIE ? 0x70 : 0x40));
+ sscape_write(s, GA_DMAA_REG, (s->ic_type == IC_OPUS ? 0x40 : 0x70));
free_dmabuf(&dma);
return ret;
@@ -546,167 +533,76 @@ _release_dma:
* Upload the bootblock(?) into the SoundScape. The only
* purpose of this block of code seems to be to tell
* us which version of the microcode we should be using.
- *
- * NOTE: The boot-block data resides in USER-SPACE!!!
- * However, we have already verified its memory
- * addresses by the time we get here.
*/
-static int sscape_upload_bootblock(struct soundscape *sscape, struct sscape_bootblock __user *bb)
+static int sscape_upload_bootblock(struct snd_card *card)
{
+ struct soundscape *sscape = get_card_soundscape(card);
unsigned long flags;
+ const struct firmware *init_fw = NULL;
int data = 0;
int ret;
- ret = upload_dma_data(sscape, bb->code, sizeof(bb->code));
-
- spin_lock_irqsave(&sscape->lock, flags);
- if (ret == 0) {
- data = host_read_ctrl_unsafe(sscape->io_base, 100);
- }
- set_midi_mode_unsafe(sscape->io_base);
- spin_unlock_irqrestore(&sscape->lock, flags);
-
- if (ret == 0) {
- if (data < 0) {
- snd_printk(KERN_ERR "sscape: timeout reading firmware version\n");
- ret = -EAGAIN;
- }
- else if (__copy_to_user(&bb->version, &data, sizeof(bb->version))) {
- ret = -EFAULT;
- }
+ ret = request_firmware(&init_fw, "scope.cod", card->dev);
+ if (ret < 0) {
+ snd_printk(KERN_ERR "sscape: Error loading scope.cod");
+ return ret;
}
+ ret = upload_dma_data(sscape, init_fw->data, init_fw->size);
- return ret;
-}
-
-/*
- * Upload the microcode into the SoundScape. The
- * microcode is 64K of data, and if we try to copy
- * it into a local variable then we will SMASH THE
- * KERNEL'S STACK! We therefore leave it in USER
- * SPACE, and save ourselves from copying it at all.
- */
-static int sscape_upload_microcode(struct soundscape *sscape,
- const struct sscape_microcode __user *mc)
-{
- unsigned long flags;
- char __user *code;
- int err;
+ release_firmware(init_fw);
- /*
- * We are going to have to copy this data into a special
- * DMA-able buffer before we can upload it. We shall therefore
- * just check that the data pointer is valid for now.
- *
- * NOTE: This buffer is 64K long! That's WAY too big to
- * copy into a stack-temporary anyway.
- */
- if ( get_user(code, &mc->code) ||
- !access_ok(VERIFY_READ, code, SSCAPE_MICROCODE_SIZE) )
- return -EFAULT;
+ spin_lock_irqsave(&sscape->lock, flags);
+ if (ret == 0)
+ data = host_read_ctrl_unsafe(sscape->io_base, 100);
- if ((err = upload_dma_data(sscape, code, SSCAPE_MICROCODE_SIZE)) == 0) {
- snd_printk(KERN_INFO "sscape: MIDI firmware loaded\n");
- }
+ if (data & 0x10)
+ sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2f);
- spin_lock_irqsave(&sscape->lock, flags);
- set_midi_mode_unsafe(sscape->io_base);
spin_unlock_irqrestore(&sscape->lock, flags);
- initialise_mpu401(sscape->mpu);
+ data &= 0xf;
+ if (ret == 0 && data > 7) {
+ snd_printk(KERN_ERR
+ "sscape: timeout reading firmware version\n");
+ ret = -EAGAIN;
+ }
- return err;
+ return (ret == 0) ? data : ret;
}
/*
- * Hardware-specific device functions, to implement special
- * IOCTLs for the SoundScape card. This is how we upload
- * the microcode into the card, for example, and so we
- * must ensure that no two processes can open this device
- * simultaneously, and that we can't open it at all if
- * someone is using the MIDI device.
+ * Upload the microcode into the SoundScape.
*/
-static int sscape_hw_open(struct snd_hwdep * hw, struct file *file)
+static int sscape_upload_microcode(struct snd_card *card, int version)
{
- register struct soundscape *sscape = get_hwdep_soundscape(hw);
- unsigned long flags;
+ struct soundscape *sscape = get_card_soundscape(card);
+ const struct firmware *init_fw = NULL;
+ char name[14];
int err;
- spin_lock_irqsave(&sscape->fwlock, flags);
+ snprintf(name, sizeof(name), "sndscape.co%d", version);
- if ((sscape->midi_usage != 0) || sscape->hw_in_use) {
- err = -EBUSY;
- } else {
- sscape->hw_in_use = 1;
- err = 0;
+ err = request_firmware(&init_fw, name, card->dev);
+ if (err < 0) {
+ snd_printk(KERN_ERR "sscape: Error loading sndscape.co%d",
+ version);
+ return err;
}
+ err = upload_dma_data(sscape, init_fw->data, init_fw->size);
+ if (err == 0)
+ snd_printk(KERN_INFO "sscape: MIDI firmware loaded %d KBs\n",
+ init_fw->size >> 10);
- spin_unlock_irqrestore(&sscape->fwlock, flags);
- return err;
-}
-
-static int sscape_hw_release(struct snd_hwdep * hw, struct file *file)
-{
- register struct soundscape *sscape = get_hwdep_soundscape(hw);
- unsigned long flags;
-
- spin_lock_irqsave(&sscape->fwlock, flags);
- sscape->hw_in_use = 0;
- spin_unlock_irqrestore(&sscape->fwlock, flags);
- return 0;
-}
-
-static int sscape_hw_ioctl(struct snd_hwdep * hw, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct soundscape *sscape = get_hwdep_soundscape(hw);
- int err = -EBUSY;
-
- switch (cmd) {
- case SND_SSCAPE_LOAD_BOOTB:
- {
- register struct sscape_bootblock __user *bb = (struct sscape_bootblock __user *) arg;
-
- /*
- * We are going to have to copy this data into a special
- * DMA-able buffer before we can upload it. We shall therefore
- * just check that the data pointer is valid for now ...
- */
- if ( !access_ok(VERIFY_READ, bb->code, sizeof(bb->code)) )
- return -EFAULT;
-
- /*
- * Now check that we can write the firmware version number too...
- */
- if ( !access_ok(VERIFY_WRITE, &bb->version, sizeof(bb->version)) )
- return -EFAULT;
-
- err = sscape_upload_bootblock(sscape, bb);
- }
- break;
-
- case SND_SSCAPE_LOAD_MCODE:
- {
- register const struct sscape_microcode __user *mc = (const struct sscape_microcode __user *) arg;
-
- err = sscape_upload_microcode(sscape, mc);
- }
- break;
-
- default:
- err = -EINVAL;
- break;
- } /* switch */
+ release_firmware(init_fw);
return err;
}
-
/*
* Mixer control for the SoundScape's MIDI device.
*/
static int sscape_midi_info(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_info *uinfo)
+ struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
@@ -716,7 +612,7 @@ static int sscape_midi_info(struct snd_kcontrol *ctl,
}
static int sscape_midi_get(struct snd_kcontrol *kctl,
- struct snd_ctl_elem_value *uctl)
+ struct snd_ctl_elem_value *uctl)
{
struct snd_wss *chip = snd_kcontrol_chip(kctl);
struct snd_card *card = chip->card;
@@ -730,16 +626,18 @@ static int sscape_midi_get(struct snd_kcontrol *kctl,
}
static int sscape_midi_put(struct snd_kcontrol *kctl,
- struct snd_ctl_elem_value *uctl)
+ struct snd_ctl_elem_value *uctl)
{
struct snd_wss *chip = snd_kcontrol_chip(kctl);
struct snd_card *card = chip->card;
- register struct soundscape *s = get_card_soundscape(card);
+ struct soundscape *s = get_card_soundscape(card);
unsigned long flags;
int change;
+ unsigned char new_val;
spin_lock_irqsave(&s->lock, flags);
+ new_val = uctl->value.integer.value[0] & 127;
/*
* We need to put the board into HOST mode before we
* can send any volume-changing HOST commands ...
@@ -752,15 +650,16 @@ static int sscape_midi_put(struct snd_kcontrol *kctl,
* and then perform another volume-related command. Perhaps the
* first command is an "open" and the second command is a "close"?
*/
- if (s->midi_vol == ((unsigned char) uctl->value.integer. value[0] & 127)) {
+ if (s->midi_vol == new_val) {
change = 0;
goto __skip_change;
}
- change = (host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100)
- && host_write_ctrl_unsafe(s->io_base, ((unsigned char) uctl->value.integer. value[0]) & 127, 100)
- && host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100));
- s->midi_vol = (unsigned char) uctl->value.integer.value[0] & 127;
- __skip_change:
+ change = host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100)
+ && host_write_ctrl_unsafe(s->io_base, new_val, 100)
+ && host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100)
+ && host_write_ctrl_unsafe(s->io_base, new_val, 100);
+ s->midi_vol = new_val;
+__skip_change:
/*
* Take the board out of HOST mode and back into MIDI mode ...
@@ -784,20 +683,25 @@ static struct snd_kcontrol_new midi_mixer_ctl = {
* These IRQs are encoded as bit patterns so that they can be
* written to the control registers.
*/
-static unsigned __devinit get_irq_config(int irq)
+static unsigned __devinit get_irq_config(int sscape_type, int irq)
{
static const int valid_irq[] = { 9, 5, 7, 10 };
+ static const int old_irq[] = { 9, 7, 5, 15 };
unsigned cfg;
- for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg) {
- if (irq == valid_irq[cfg])
- return cfg;
- } /* for */
+ if (sscape_type == MEDIA_FX) {
+ for (cfg = 0; cfg < ARRAY_SIZE(old_irq); ++cfg)
+ if (irq == old_irq[cfg])
+ return cfg;
+ } else {
+ for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg)
+ if (irq == valid_irq[cfg])
+ return cfg;
+ }
return INVALID_IRQ;
}
-
/*
* Perform certain arcane port-checks to see whether there
* is a SoundScape board lurking behind the given ports.
@@ -842,11 +746,38 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io)
if (s->type != SSCAPE_VIVO && (d & 0x9f) != 0x0e)
goto _done;
- d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f;
- sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0);
+ if (s->ic_type == IC_OPUS)
+ activate_ad1845_unsafe(s->io_base);
if (s->type == SSCAPE_VIVO)
wss_io += 4;
+
+ d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
+ sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0);
+
+ /* wait for WSS codec */
+ for (d = 0; d < 500; d++) {
+ if ((inb(wss_io) & 0x80) == 0)
+ break;
+ spin_unlock_irqrestore(&s->lock, flags);
+ msleep(1);
+ spin_lock_irqsave(&s->lock, flags);
+ }
+
+ if ((inb(wss_io) & 0x80) != 0)
+ goto _done;
+
+ if (inb(wss_io + 2) == 0xff)
+ goto _done;
+
+ d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f;
+ sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d);
+
+ if ((inb(wss_io) & 0x80) != 0)
+ s->type = MEDIA_FX;
+
+ d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG);
+ sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0);
/* wait for WSS codec */
for (d = 0; d < 500; d++) {
if ((inb(wss_io) & 0x80) == 0)
@@ -855,14 +786,13 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io)
msleep(1);
spin_lock_irqsave(&s->lock, flags);
}
- snd_printd(KERN_INFO "init delay = %d ms\n", d);
/*
* SoundScape successfully detected!
*/
retval = 1;
- _done:
+_done:
spin_unlock_irqrestore(&s->lock, flags);
return retval;
}
@@ -873,63 +803,35 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io)
* to crash the machine. Also check that someone isn't using the hardware
* IOCTL device.
*/
-static int mpu401_open(struct snd_mpu401 * mpu)
+static int mpu401_open(struct snd_mpu401 *mpu)
{
- int err;
-
if (!verify_mpu401(mpu)) {
- snd_printk(KERN_ERR "sscape: MIDI disabled, please load firmware\n");
- err = -ENODEV;
- } else {
- register struct soundscape *sscape = get_mpu401_soundscape(mpu);
- unsigned long flags;
-
- spin_lock_irqsave(&sscape->fwlock, flags);
-
- if (sscape->hw_in_use || (sscape->midi_usage == ULONG_MAX)) {
- err = -EBUSY;
- } else {
- ++(sscape->midi_usage);
- err = 0;
- }
-
- spin_unlock_irqrestore(&sscape->fwlock, flags);
+ snd_printk(KERN_ERR "sscape: MIDI disabled, "
+ "please load firmware\n");
+ return -ENODEV;
}
- return err;
-}
-
-static void mpu401_close(struct snd_mpu401 * mpu)
-{
- register struct soundscape *sscape = get_mpu401_soundscape(mpu);
- unsigned long flags;
-
- spin_lock_irqsave(&sscape->fwlock, flags);
- --(sscape->midi_usage);
- spin_unlock_irqrestore(&sscape->fwlock, flags);
+ return 0;
}
/*
* Initialse an MPU-401 subdevice for MIDI support on the SoundScape.
*/
-static int __devinit create_mpu401(struct snd_card *card, int devnum, unsigned long port, int irq)
+static int __devinit create_mpu401(struct snd_card *card, int devnum,
+ unsigned long port, int irq)
{
struct soundscape *sscape = get_card_soundscape(card);
struct snd_rawmidi *rawmidi;
int err;
- if ((err = snd_mpu401_uart_new(card, devnum,
- MPU401_HW_MPU401,
- port, MPU401_INFO_INTEGRATED,
- irq, IRQF_DISABLED,
- &rawmidi)) == 0) {
- struct snd_mpu401 *mpu = (struct snd_mpu401 *) rawmidi->private_data;
+ err = snd_mpu401_uart_new(card, devnum, MPU401_HW_MPU401, port,
+ MPU401_INFO_INTEGRATED, irq, IRQF_DISABLED,
+ &rawmidi);
+ if (err == 0) {
+ struct snd_mpu401 *mpu = rawmidi->private_data;
mpu->open_input = mpu401_open;
mpu->open_output = mpu401_open;
- mpu->close_input = mpu401_close;
- mpu->close_output = mpu401_close;
mpu->private_data = sscape;
- sscape->mpu = mpu;
initialise_mpu401(mpu);
}
@@ -950,32 +852,34 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
register struct soundscape *sscape = get_card_soundscape(card);
struct snd_wss *chip;
int err;
+ int codec_type = WSS_HW_DETECT;
- if (sscape->type == SSCAPE_VIVO)
- port += 4;
+ switch (sscape->type) {
+ case MEDIA_FX:
+ case SSCAPE:
+ /*
+ * There are some freak examples of early Soundscape cards
+ * with CS4231 instead of AD1848/CS4248. Unfortunately, the
+ * CS4231 works only in CS4248 compatibility mode on
+ * these cards so force it.
+ */
+ if (sscape->ic_type != IC_OPUS)
+ codec_type = WSS_HW_AD1848;
+ break;
- if (dma1 == dma2)
- dma2 = -1;
+ case SSCAPE_VIVO:
+ port += 4;
+ break;
+ default:
+ break;
+ }
err = snd_wss_create(card, port, -1, irq, dma1, dma2,
- WSS_HW_DETECT, WSS_HWSHARE_DMA1, &chip);
+ codec_type, WSS_HWSHARE_DMA1, &chip);
if (!err) {
unsigned long flags;
struct snd_pcm *pcm;
-/*
- * It turns out that the PLAYBACK_ENABLE bit is set
- * by the lowlevel driver ...
- *
-#define AD1845_IFACE_CONFIG \
- (CS4231_AUTOCALIB | CS4231_RECORD_ENABLE | CS4231_PLAYBACK_ENABLE)
- snd_wss_mce_up(chip);
- spin_lock_irqsave(&chip->reg_lock, flags);
- snd_wss_out(chip, CS4231_IFACE_CTRL, AD1845_IFACE_CONFIG);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
- snd_wss_mce_down(chip);
- */
-
if (sscape->type != SSCAPE_VIVO) {
/*
* The input clock frequency on the SoundScape must
@@ -1022,17 +926,10 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
}
}
- strcpy(card->driver, "SoundScape");
- strcpy(card->shortname, pcm->name);
- snprintf(card->longname, sizeof(card->longname),
- "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n",
- pcm->name, chip->port, chip->irq,
- chip->dma1, chip->dma2);
-
sscape->chip = chip;
}
- _error:
+_error:
return err;
}
@@ -1051,21 +948,8 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
struct resource *wss_res;
unsigned long flags;
int err;
-
- /*
- * Check that the user didn't pass us garbage data ...
- */
- irq_cfg = get_irq_config(irq[dev]);
- if (irq_cfg == INVALID_IRQ) {
- snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]);
- return -ENXIO;
- }
-
- mpu_irq_cfg = get_irq_config(mpu_irq[dev]);
- if (mpu_irq_cfg == INVALID_IRQ) {
- printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]);
- return -ENXIO;
- }
+ int val;
+ const char *name;
/*
* Grab IO ports that we will need to probe so that we
@@ -1098,41 +982,51 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
}
spin_lock_init(&sscape->lock);
- spin_lock_init(&sscape->fwlock);
sscape->io_res = io_res;
sscape->wss_res = wss_res;
sscape->io_base = port[dev];
if (!detect_sscape(sscape, wss_port[dev])) {
- printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", sscape->io_base);
+ printk(KERN_ERR "sscape: hardware not detected at 0x%x\n",
+ sscape->io_base);
err = -ENODEV;
goto _release_dma;
}
- printk(KERN_INFO "sscape: hardware detected at 0x%x, using IRQ %d, DMA %d\n",
- sscape->io_base, irq[dev], dma[dev]);
+ switch (sscape->type) {
+ case MEDIA_FX:
+ name = "MediaFX/SoundFX";
+ break;
+ case SSCAPE:
+ name = "Soundscape";
+ break;
+ case SSCAPE_PNP:
+ name = "Soundscape PnP";
+ break;
+ case SSCAPE_VIVO:
+ name = "Soundscape VIVO";
+ break;
+ default:
+ name = "unknown Soundscape";
+ break;
+ }
- if (sscape->type != SSCAPE_VIVO) {
- /*
- * Now create the hardware-specific device so that we can
- * load the microcode into the on-board processor.
- * We cannot use the MPU-401 MIDI system until this firmware
- * has been loaded into the card.
- */
- err = snd_hwdep_new(card, "MC68EC000", 0, &(sscape->hw));
- if (err < 0) {
- printk(KERN_ERR "sscape: Failed to create "
- "firmware device\n");
- goto _release_dma;
- }
- strlcpy(sscape->hw->name, "SoundScape M68K",
- sizeof(sscape->hw->name));
- sscape->hw->name[sizeof(sscape->hw->name) - 1] = '\0';
- sscape->hw->iface = SNDRV_HWDEP_IFACE_SSCAPE;
- sscape->hw->ops.open = sscape_hw_open;
- sscape->hw->ops.release = sscape_hw_release;
- sscape->hw->ops.ioctl = sscape_hw_ioctl;
- sscape->hw->private_data = sscape;
+ printk(KERN_INFO "sscape: %s card detected at 0x%x, using IRQ %d, DMA %d\n",
+ name, sscape->io_base, irq[dev], dma[dev]);
+
+ /*
+ * Check that the user didn't pass us garbage data ...
+ */
+ irq_cfg = get_irq_config(sscape->type, irq[dev]);
+ if (irq_cfg == INVALID_IRQ) {
+ snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]);
+ return -ENXIO;
+ }
+
+ mpu_irq_cfg = get_irq_config(sscape->type, mpu_irq[dev]);
+ if (mpu_irq_cfg == INVALID_IRQ) {
+ snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]);
+ return -ENXIO;
}
/*
@@ -1141,9 +1035,6 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
*/
spin_lock_irqsave(&sscape->lock, flags);
- activate_ad1845_unsafe(sscape->io_base);
-
- sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x00); /* disable */
sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e);
sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00);
@@ -1151,15 +1042,23 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
* Enable and configure the DMA channels ...
*/
sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50);
- dma_cfg = (sscape->ic_type == IC_ODIE ? 0x70 : 0x40);
+ dma_cfg = (sscape->ic_type == IC_OPUS ? 0x40 : 0x70);
sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg);
sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20);
- sscape_write_unsafe(sscape->io_base,
- GA_INTCFG_REG, 0xf0 | (mpu_irq_cfg << 2) | mpu_irq_cfg);
+ mpu_irq_cfg |= mpu_irq_cfg << 2;
+ val = sscape_read_unsafe(sscape->io_base, GA_HMCTL_REG) & 0xF7;
+ if (joystick[dev])
+ val |= 8;
+ sscape_write_unsafe(sscape->io_base, GA_HMCTL_REG, val | 0x10);
+ sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | mpu_irq_cfg);
sscape_write_unsafe(sscape->io_base,
GA_CDCFG_REG, 0x09 | DMA_8BIT
| (dma[dev] << 4) | (irq_cfg << 1));
+ /*
+ * Enable the master IRQ ...
+ */
+ sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x80);
spin_unlock_irqrestore(&sscape->lock, flags);
@@ -1170,32 +1069,56 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
err = create_ad1845(card, wss_port[dev], irq[dev],
dma[dev], dma2[dev]);
if (err < 0) {
- printk(KERN_ERR "sscape: No AD1845 device at 0x%lx, IRQ %d\n",
- wss_port[dev], irq[dev]);
+ snd_printk(KERN_ERR
+ "sscape: No AD1845 device at 0x%lx, IRQ %d\n",
+ wss_port[dev], irq[dev]);
goto _release_dma;
}
+ strcpy(card->driver, "SoundScape");
+ strcpy(card->shortname, name);
+ snprintf(card->longname, sizeof(card->longname),
+ "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n",
+ name, sscape->chip->port, sscape->chip->irq,
+ sscape->chip->dma1, sscape->chip->dma2);
+
#define MIDI_DEVNUM 0
if (sscape->type != SSCAPE_VIVO) {
- err = create_mpu401(card, MIDI_DEVNUM, port[dev], mpu_irq[dev]);
- if (err < 0) {
- printk(KERN_ERR "sscape: Failed to create "
- "MPU-401 device at 0x%lx\n",
- port[dev]);
- goto _release_dma;
- }
+ err = sscape_upload_bootblock(card);
+ if (err >= 0)
+ err = sscape_upload_microcode(card, err);
- /*
- * Enable the master IRQ ...
- */
- sscape_write(sscape, GA_INTENA_REG, 0x80);
+ if (err == 0) {
+ err = create_mpu401(card, MIDI_DEVNUM, port[dev],
+ mpu_irq[dev]);
+ if (err < 0) {
+ snd_printk(KERN_ERR "sscape: Failed to create "
+ "MPU-401 device at 0x%lx\n",
+ port[dev]);
+ goto _release_dma;
+ }
- /*
- * Initialize mixer
- */
- sscape->midi_vol = 0;
- host_write_ctrl_unsafe(sscape->io_base, CMD_SET_MIDI_VOL, 100);
- host_write_ctrl_unsafe(sscape->io_base, 0, 100);
- host_write_ctrl_unsafe(sscape->io_base, CMD_XXX_MIDI_VOL, 100);
+ /*
+ * Initialize mixer
+ */
+ spin_lock_irqsave(&sscape->lock, flags);
+ sscape->midi_vol = 0;
+ host_write_ctrl_unsafe(sscape->io_base,
+ CMD_SET_MIDI_VOL, 100);
+ host_write_ctrl_unsafe(sscape->io_base,
+ sscape->midi_vol, 100);
+ host_write_ctrl_unsafe(sscape->io_base,
+ CMD_XXX_MIDI_VOL, 100);
+ host_write_ctrl_unsafe(sscape->io_base,
+ sscape->midi_vol, 100);
+ host_write_ctrl_unsafe(sscape->io_base,
+ CMD_SET_EXTMIDI, 100);
+ host_write_ctrl_unsafe(sscape->io_base,
+ 0, 100);
+ host_write_ctrl_unsafe(sscape->io_base, CMD_ACK, 100);
+
+ set_midi_mode_unsafe(sscape->io_base);
+ spin_unlock_irqrestore(&sscape->lock, flags);
+ }
}
/*
@@ -1231,7 +1154,8 @@ static int __devinit snd_sscape_match(struct device *pdev, unsigned int i)
mpu_irq[i] == SNDRV_AUTO_IRQ ||
dma[i] == SNDRV_AUTO_DMA) {
printk(KERN_INFO
- "sscape: insufficient parameters, need IO, IRQ, MPU-IRQ and DMA\n");
+ "sscape: insufficient parameters, "
+ "need IO, IRQ, MPU-IRQ and DMA\n");
return 0;
}
@@ -1253,13 +1177,15 @@ static int __devinit snd_sscape_probe(struct device *pdev, unsigned int dev)
sscape->type = SSCAPE;
dma[dev] &= 0x03;
+ snd_card_set_dev(card, pdev);
+
ret = create_sscape(dev, card);
if (ret < 0)
goto _release_card;
- snd_card_set_dev(card, pdev);
- if ((ret = snd_card_register(card)) < 0) {
- printk(KERN_ERR "sscape: Failed to register sound card\n");
+ ret = snd_card_register(card);
+ if (ret < 0) {
+ snd_printk(KERN_ERR "sscape: Failed to register sound card\n");
goto _release_card;
}
dev_set_drvdata(pdev, card);
@@ -1311,36 +1237,20 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard,
* Allow this function to fail *quietly* if all the ISA PnP
* devices were configured using module parameters instead.
*/
- if ((idx = get_next_autoindex(idx)) >= SNDRV_CARDS)
+ idx = get_next_autoindex(idx);
+ if (idx >= SNDRV_CARDS)
return -ENOSPC;
/*
- * We have found a candidate ISA PnP card. Now we
- * have to check that it has the devices that we
- * expect it to have.
- *
- * We will NOT try and autoconfigure all of the resources
- * needed and then activate the card as we are assuming that
- * has already been done at boot-time using /proc/isapnp.
- * We shall simply try to give each active card the resources
- * that it wants. This is a sensible strategy for a modular
- * system where unused modules are unloaded regularly.
- *
- * This strategy is utterly useless if we compile the driver
- * into the kernel, of course.
- */
- // printk(KERN_INFO "sscape: %s\n", card->name);
-
- /*
* Check that we still have room for another sound card ...
*/
dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL);
- if (! dev)
+ if (!dev)
return -ENODEV;
if (!pnp_is_active(dev)) {
if (pnp_activate_dev(dev) < 0) {
- printk(KERN_INFO "sscape: device is inactive\n");
+ snd_printk(KERN_INFO "sscape: device is inactive\n");
return -EBUSY;
}
}
@@ -1378,14 +1288,15 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard,
wss_port[idx] = pnp_port_start(dev, 1);
dma2[idx] = pnp_dma(dev, 1);
}
+ snd_card_set_dev(card, &pcard->card->dev);
ret = create_sscape(idx, card);
if (ret < 0)
goto _release_card;
- snd_card_set_dev(card, &pcard->card->dev);
- if ((ret = snd_card_register(card)) < 0) {
- printk(KERN_ERR "sscape: Failed to register sound card\n");
+ ret = snd_card_register(card);
+ if (ret < 0) {
+ snd_printk(KERN_ERR "sscape: Failed to register sound card\n");
goto _release_card;
}
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c
index 5d2ba1b749ab..2ba18978b419 100644
--- a/sound/isa/wss/wss_lib.c
+++ b/sound/isa/wss/wss_lib.c
@@ -2198,84 +2198,61 @@ EXPORT_SYMBOL(snd_wss_put_double);
static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
+static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);
-static struct snd_kcontrol_new snd_ad1848_controls[] = {
-WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT,
- 7, 7, 1, 1),
+static struct snd_kcontrol_new snd_wss_controls[] = {
+WSS_DOUBLE("PCM Playback Switch", 0,
+ CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
WSS_DOUBLE_TLV("PCM Playback Volume", 0,
- CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
- db_scale_6bit),
+ CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
+ db_scale_6bit),
WSS_DOUBLE("Aux Playback Switch", 0,
- CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
+ CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
WSS_DOUBLE_TLV("Aux Playback Volume", 0,
- CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
- db_scale_5bit_12db_max),
+ CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
+ db_scale_5bit_12db_max),
WSS_DOUBLE("Aux Playback Switch", 1,
- CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+ CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
WSS_DOUBLE_TLV("Aux Playback Volume", 1,
- CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
- db_scale_5bit_12db_max),
+ CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
+ db_scale_5bit_12db_max),
WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT,
0, 0, 15, 0, db_scale_rec_gain),
{
- .name = "Capture Source",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
.info = snd_wss_info_mux,
.get = snd_wss_get_mux,
.put = snd_wss_put_mux,
},
-WSS_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
-WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 1, 63, 0,
- db_scale_6bit),
-};
-
-static struct snd_kcontrol_new snd_wss_controls[] = {
-WSS_DOUBLE("PCM Playback Switch", 0,
- CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
-WSS_DOUBLE("PCM Playback Volume", 0,
- CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
+WSS_DOUBLE("Mic Boost", 0,
+ CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
+WSS_SINGLE("Loopback Capture Switch", 0,
+ CS4231_LOOPBACK, 0, 1, 0),
+WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1,
+ db_scale_6bit),
WSS_DOUBLE("Line Playback Switch", 0,
CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
-WSS_DOUBLE("Line Playback Volume", 0,
- CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
-WSS_DOUBLE("Aux Playback Switch", 0,
- CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
-WSS_DOUBLE("Aux Playback Volume", 0,
- CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
-WSS_DOUBLE("Aux Playback Switch", 1,
- CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
-WSS_DOUBLE("Aux Playback Volume", 1,
- CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
+WSS_DOUBLE_TLV("Line Playback Volume", 0,
+ CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1,
+ db_scale_5bit_12db_max),
WSS_SINGLE("Mono Playback Switch", 0,
CS4231_MONO_CTRL, 7, 1, 1),
-WSS_SINGLE("Mono Playback Volume", 0,
- CS4231_MONO_CTRL, 0, 15, 1),
+WSS_SINGLE_TLV("Mono Playback Volume", 0,
+ CS4231_MONO_CTRL, 0, 15, 1,
+ db_scale_4bit),
WSS_SINGLE("Mono Output Playback Switch", 0,
CS4231_MONO_CTRL, 6, 1, 1),
WSS_SINGLE("Mono Output Playback Bypass", 0,
CS4231_MONO_CTRL, 5, 1, 0),
-WSS_DOUBLE("Capture Volume", 0,
- CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
-{
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Capture Source",
- .info = snd_wss_info_mux,
- .get = snd_wss_get_mux,
- .put = snd_wss_put_mux,
-},
-WSS_DOUBLE("Mic Boost", 0,
- CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
-WSS_SINGLE("Loopback Capture Switch", 0,
- CS4231_LOOPBACK, 0, 1, 0),
-WSS_SINGLE("Loopback Capture Volume", 0,
- CS4231_LOOPBACK, 2, 63, 1)
};
static struct snd_kcontrol_new snd_opti93x_controls[] = {
WSS_DOUBLE("Master Playback Switch", 0,
OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1),
-WSS_DOUBLE("Master Playback Volume", 0,
- OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1),
+WSS_DOUBLE_TLV("Master Playback Volume", 0,
+ OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1,
+ db_scale_6bit),
WSS_DOUBLE("PCM Playback Switch", 0,
CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
WSS_DOUBLE("PCM Playback Volume", 0,
@@ -2334,22 +2311,21 @@ int snd_wss_mixer(struct snd_wss *chip)
if (err < 0)
return err;
}
- else if (chip->hardware & WSS_HW_AD1848_MASK)
- for (idx = 0; idx < ARRAY_SIZE(snd_ad1848_controls); idx++) {
- err = snd_ctl_add(card,
- snd_ctl_new1(&snd_ad1848_controls[idx],
- chip));
- if (err < 0)
- return err;
- }
- else
- for (idx = 0; idx < ARRAY_SIZE(snd_wss_controls); idx++) {
+ else {
+ int count = ARRAY_SIZE(snd_wss_controls);
+
+ /* Use only the first 11 entries on AD1848 */
+ if (chip->hardware & WSS_HW_AD1848_MASK)
+ count = 11;
+
+ for (idx = 0; idx < count; idx++) {
err = snd_ctl_add(card,
snd_ctl_new1(&snd_wss_controls[idx],
chip));
if (err < 0)
return err;
}
+ }
return 0;
}
EXPORT_SYMBOL(snd_wss_mixer);
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index bcf2a0698d54..ea0b1aeffe66 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -1,5 +1,3 @@
-# drivers/sound/Config.in
-#
# 18 Apr 1998, Michael Elizabeth Chastain, <mailto:mec@shout.net>
# More hacking for modularisation.
#
diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c
index 4191acccbcdb..c1070e33b32f 100644
--- a/sound/oss/au1550_ac97.c
+++ b/sound/oss/au1550_ac97.c
@@ -614,7 +614,8 @@ start_adc(struct au1550_state *s)
/* Put two buffers on the ring to get things started.
*/
for (i=0; i<2; i++) {
- au1xxx_dbdma_put_dest(db->dmanr, db->nextIn, db->dma_fragsize);
+ au1xxx_dbdma_put_dest(db->dmanr, virt_to_phys(db->nextIn),
+ db->dma_fragsize, DDMA_FLAGS_IE);
db->nextIn += db->dma_fragsize;
if (db->nextIn >= db->rawbuf + db->dmasize)
@@ -732,8 +733,9 @@ static void dac_dma_interrupt(int irq, void *dev_id)
db->dma_qcount--;
if (db->count >= db->fragsize) {
- if (au1xxx_dbdma_put_source(db->dmanr, db->nextOut,
- db->fragsize) == 0) {
+ if (au1xxx_dbdma_put_source(db->dmanr,
+ virt_to_phys(db->nextOut), db->fragsize,
+ DDMA_FLAGS_IE) == 0) {
err("qcount < 2 and no ring room!");
}
db->nextOut += db->fragsize;
@@ -777,7 +779,8 @@ static void adc_dma_interrupt(int irq, void *dev_id)
/* Put a new empty buffer on the destination DMA.
*/
- au1xxx_dbdma_put_dest(dp->dmanr, dp->nextIn, dp->dma_fragsize);
+ au1xxx_dbdma_put_dest(dp->dmanr, virt_to_phys(dp->nextIn),
+ dp->dma_fragsize, DDMA_FLAGS_IE);
dp->nextIn += dp->dma_fragsize;
if (dp->nextIn >= dp->rawbuf + dp->dmasize)
@@ -1177,8 +1180,9 @@ au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
* we know the dma has stopped.
*/
while ((db->dma_qcount < 2) && (db->count >= db->fragsize)) {
- if (au1xxx_dbdma_put_source(db->dmanr, db->nextOut,
- db->fragsize) == 0) {
+ if (au1xxx_dbdma_put_source(db->dmanr,
+ virt_to_phys(db->nextOut), db->fragsize,
+ DDMA_FLAGS_IE) == 0) {
err("qcount < 2 and no ring room!");
}
db->nextOut += db->fragsize;
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index fb5ee3cc3968..75c602b5b132 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -259,7 +259,6 @@ config SND_CS5530
config SND_CS5535AUDIO
tristate "CS5535/CS5536 Audio"
- depends on X86 && !X86_64
select SND_PCM
select SND_AC97_CODEC
help
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index c9ad182e1b4b..d0effa3563e2 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -60,7 +60,7 @@ static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
static int probe_only[SNDRV_CARDS];
static int single_cmd;
-static int enable_msi;
+static int enable_msi = -1;
#ifdef CONFIG_SND_HDA_PATCH_LOADER
static char *patch[SNDRV_CARDS];
#endif
@@ -2300,11 +2300,9 @@ static void __devinit check_probe_mask(struct azx *chip, int dev)
}
/*
- * white-list for enable_msi
+ * white/black-list for enable_msi
*/
-static struct snd_pci_quirk msi_white_list[] __devinitdata = {
- SND_PCI_QUIRK(0x103c, 0x30f7, "HP Pavilion dv4t-1300", 1),
- SND_PCI_QUIRK(0x103c, 0x3607, "HP Compa CQ40", 1),
+static struct snd_pci_quirk msi_black_list[] __devinitdata = {
{}
};
@@ -2312,10 +2310,12 @@ static void __devinit check_msi(struct azx *chip)
{
const struct snd_pci_quirk *q;
- chip->msi = enable_msi;
- if (chip->msi)
+ if (enable_msi >= 0) {
+ chip->msi = !!enable_msi;
return;
- q = snd_pci_quirk_lookup(chip->pci, msi_white_list);
+ }
+ chip->msi = 1; /* enable MSI as default */
+ q = snd_pci_quirk_lookup(chip->pci, msi_black_list);
if (q) {
printk(KERN_INFO
"hda_intel: msi for device %04x:%04x set to %d\n",
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 8ba306856d38..7b0446fa6009 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -947,7 +947,7 @@ static void init_input(struct hda_codec *codec)
coef |= 0x0500; /* DMIC2 enable 2 channels, disable GPIO1 */
if (is_active_pin(codec, CS_DMIC1_PIN_NID))
coef |= 0x1800; /* DMIC1 enable 2 channels, disable GPIO0
- * No effect if SPDIF_OUT2 is slected in
+ * No effect if SPDIF_OUT2 is selected in
* IDX_SPDIF_CTL.
*/
cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index c08ca660daba..e01b4b13be97 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -4324,6 +4324,20 @@ static int add_control(struct alc_spec *spec, int type, const char *name,
return 0;
}
+static int add_control_with_pfx(struct alc_spec *spec, int type,
+ const char *pfx, const char *dir,
+ const char *sfx, unsigned long val)
+{
+ char name[32];
+ snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
+ return add_control(spec, type, name, 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 alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
@@ -4377,7 +4391,6 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
const struct auto_pin_cfg *cfg)
{
- char name[32];
static const char *chname[4] = {
"Front", "Surround", NULL /*CLFE*/, "Side"
};
@@ -4390,26 +4403,26 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
if (i == 2) {
/* Center/LFE */
- err = add_control(spec, ALC_CTL_WIDGET_VOL,
- "Center Playback Volume",
+ err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
+ "Center",
HDA_COMPOSE_AMP_VAL(nid, 1, 0,
HDA_OUTPUT));
if (err < 0)
return err;
- err = add_control(spec, ALC_CTL_WIDGET_VOL,
- "LFE Playback Volume",
+ err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
+ "LFE",
HDA_COMPOSE_AMP_VAL(nid, 2, 0,
HDA_OUTPUT));
if (err < 0)
return err;
- err = add_control(spec, ALC_CTL_BIND_MUTE,
- "Center Playback Switch",
+ err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
+ "Center",
HDA_COMPOSE_AMP_VAL(nid, 1, 2,
HDA_INPUT));
if (err < 0)
return err;
- err = add_control(spec, ALC_CTL_BIND_MUTE,
- "LFE Playback Switch",
+ err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
+ "LFE",
HDA_COMPOSE_AMP_VAL(nid, 2, 2,
HDA_INPUT));
if (err < 0)
@@ -4421,14 +4434,12 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
pfx = "Speaker";
else
pfx = chname[i];
- sprintf(name, "%s Playback Volume", pfx);
- err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+ err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
HDA_COMPOSE_AMP_VAL(nid, 3, 0,
HDA_OUTPUT));
if (err < 0)
return err;
- sprintf(name, "%s Playback Switch", pfx);
- err = add_control(spec, ALC_CTL_BIND_MUTE, name,
+ err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
HDA_COMPOSE_AMP_VAL(nid, 3, 2,
HDA_INPUT));
if (err < 0)
@@ -4444,7 +4455,6 @@ static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
{
hda_nid_t nid;
int err;
- char name[32];
if (!pin)
return 0;
@@ -4458,21 +4468,18 @@ static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
spec->multiout.extra_out_nid[0] = nid;
/* control HP volume/switch on the output mixer amp */
nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
- sprintf(name, "%s Playback Volume", pfx);
- err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+ err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
if (err < 0)
return err;
- sprintf(name, "%s Playback Switch", pfx);
- err = add_control(spec, ALC_CTL_BIND_MUTE, name,
+ err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
if (err < 0)
return err;
} else if (alc880_is_multi_pin(pin)) {
/* set manual connection */
/* we have only a switch on HP-out PIN */
- sprintf(name, "%s Playback Switch", pfx);
- err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+ err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
if (err < 0)
return err;
@@ -4485,16 +4492,13 @@ static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
const char *ctlname,
int idx, hda_nid_t mix_nid)
{
- char name[32];
int err;
- sprintf(name, "%s Playback Volume", ctlname);
- err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+ err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
if (err < 0)
return err;
- sprintf(name, "%s Playback Switch", ctlname);
- err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+ err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
if (err < 0)
return err;
@@ -5987,7 +5991,6 @@ static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
{
hda_nid_t nid_vol;
unsigned long vol_val, sw_val;
- char name[32];
int err;
if (nid >= 0x0f && nid < 0x11) {
@@ -6007,14 +6010,12 @@ static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
if (!(*vol_bits & (1 << nid_vol))) {
/* first control for the volume widget */
- snprintf(name, sizeof(name), "%s Playback Volume", pfx);
- err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
+ err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
if (err < 0)
return err;
*vol_bits |= (1 << nid_vol);
}
- snprintf(name, sizeof(name), "%s Playback Switch", pfx);
- err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
+ err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
if (err < 0)
return err;
return 1;
@@ -10953,7 +10954,6 @@ 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)
{
- char name[32];
unsigned long val;
int vbit;
@@ -10963,28 +10963,25 @@ static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
if (*vbits & vbit) /* a volume control for this mixer already there */
return 0;
*vbits |= vbit;
- snprintf(name, sizeof(name), "%s Playback Volume", pfx);
if (vbit == 2)
val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
else
val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
- return add_control(spec, ALC_CTL_WIDGET_VOL, name, val);
+ return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, val);
}
static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
const char *pfx)
{
- char name[32];
unsigned long val;
if (!nid)
return 0;
- snprintf(name, sizeof(name), "%s Playback Switch", pfx);
if (nid == 0x16)
val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
else
val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
- return add_control(spec, ALC_CTL_WIDGET_MUTE, name, val);
+ return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val);
}
/* add playback controls from the parsed DAC table */
@@ -12322,11 +12319,9 @@ static struct snd_kcontrol_new alc268_test_mixer[] = {
static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
const char *ctlname, int idx)
{
- char name[32];
hda_nid_t dac;
int err;
- sprintf(name, "%s Playback Volume", ctlname);
switch (nid) {
case 0x14:
case 0x16:
@@ -12340,7 +12335,7 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
}
if (spec->multiout.dac_nids[0] != dac &&
spec->multiout.dac_nids[1] != dac) {
- err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+ err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
HDA_COMPOSE_AMP_VAL(dac, 3, idx,
HDA_OUTPUT));
if (err < 0)
@@ -12348,12 +12343,11 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
}
- sprintf(name, "%s Playback Switch", ctlname);
if (nid != 0x16)
- err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+ err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
else /* mono */
- err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+ err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
if (err < 0)
return err;
@@ -12383,8 +12377,7 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
nid = cfg->speaker_pins[0];
if (nid == 0x1d) {
- err = add_control(spec, ALC_CTL_WIDGET_VOL,
- "Speaker Playback Volume",
+ err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
if (err < 0)
return err;
@@ -12402,8 +12395,7 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
if (nid == 0x16) {
- err = add_control(spec, ALC_CTL_WIDGET_MUTE,
- "Mono Playback Switch",
+ err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
if (err < 0)
return err;
@@ -14254,9 +14246,7 @@ static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
hda_nid_t nid, unsigned int chs)
{
- char name[32];
- snprintf(name, sizeof(name), "%s Playback Switch", pfx);
- return add_control(codec->spec, ALC_CTL_WIDGET_MUTE, name,
+ return add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx,
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
}
@@ -15380,7 +15370,6 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
const struct auto_pin_cfg *cfg)
{
- char name[32];
static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
hda_nid_t nid_v, nid_s;
int i, err;
@@ -15397,26 +15386,26 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
if (i == 2) {
/* Center/LFE */
- err = add_control(spec, ALC_CTL_WIDGET_VOL,
- "Center Playback Volume",
+ err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
+ "Center",
HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
HDA_OUTPUT));
if (err < 0)
return err;
- err = add_control(spec, ALC_CTL_WIDGET_VOL,
- "LFE Playback Volume",
+ err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
+ "LFE",
HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
HDA_OUTPUT));
if (err < 0)
return err;
- err = add_control(spec, ALC_CTL_BIND_MUTE,
- "Center Playback Switch",
+ err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
+ "Center",
HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
HDA_INPUT));
if (err < 0)
return err;
- err = add_control(spec, ALC_CTL_BIND_MUTE,
- "LFE Playback Switch",
+ err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
+ "LFE",
HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
HDA_INPUT));
if (err < 0)
@@ -15431,8 +15420,7 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
pfx = "PCM";
} else
pfx = chname[i];
- sprintf(name, "%s Playback Volume", pfx);
- err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+ err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
HDA_OUTPUT));
if (err < 0)
@@ -15440,8 +15428,7 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
if (cfg->line_outs == 1 &&
cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
pfx = "Speaker";
- sprintf(name, "%s Playback Switch", pfx);
- err = add_control(spec, ALC_CTL_BIND_MUTE, name,
+ err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
HDA_INPUT));
if (err < 0)
@@ -15459,7 +15446,6 @@ static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
{
hda_nid_t nid_v, nid_s;
int err;
- char name[32];
if (!pin)
return 0;
@@ -15477,21 +15463,18 @@ static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
nid_s = alc861vd_idx_to_mixer_switch(
alc880_fixed_pin_idx(pin));
- sprintf(name, "%s Playback Volume", pfx);
- err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+ err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
if (err < 0)
return err;
- sprintf(name, "%s Playback Switch", pfx);
- err = add_control(spec, ALC_CTL_BIND_MUTE, name,
+ err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
if (err < 0)
return err;
} else if (alc880_is_multi_pin(pin)) {
/* set manual connection */
/* we have only a switch on HP-out PIN */
- sprintf(name, "%s Playback Switch", pfx);
- err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+ err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
if (err < 0)
return err;
@@ -17258,21 +17241,17 @@ static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
return 0;
}
-static int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
+static inline int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
hda_nid_t nid, unsigned int chs)
{
- char name[32];
- sprintf(name, "%s Playback Volume", pfx);
- return add_control(spec, ALC_CTL_WIDGET_VOL, name,
+ return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
}
-static int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
+static inline int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
hda_nid_t nid, unsigned int chs)
{
- char name[32];
- sprintf(name, "%s Playback Switch", pfx);
- return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+ return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
}
@@ -17350,13 +17329,11 @@ static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
return 0;
nid = alc662_look_for_dac(codec, pin);
if (!nid) {
- char name[32];
/* the corresponding DAC is already occupied */
if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
return 0; /* no way */
/* create a switch only */
- sprintf(name, "%s Playback Switch", pfx);
- return add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+ return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
}
@@ -17374,7 +17351,7 @@ static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
/* create playback/capture controls for input pins */
#define alc662_auto_create_input_ctls \
- alc880_auto_create_input_ctls
+ alc882_auto_create_input_ctls
static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
hda_nid_t nid, int pin_type,
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index ee89db90c9b6..89e084d45369 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -1,10 +1,10 @@
/*
* Universal Interface for Intel High Definition Audio Codec
*
- * HD audio interface patch for VIA VT1702/VT1708/VT1709 codec
+ * HD audio interface patch for VIA VT17xx/VT18xx/VT20xx codec
*
- * Copyright (c) 2006-2008 Lydia Wang <lydiawang@viatech.com>
- * Takashi Iwai <tiwai@suse.de>
+ * (C) 2006-2009 VIA Technology, Inc.
+ * (C) 2006-2008 Takashi Iwai <tiwai@suse.de>
*
* 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
@@ -22,21 +22,26 @@
*/
/* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */
-/* */
+/* */
/* 2006-03-03 Lydia Wang Create the basic patch to support VT1708 codec */
-/* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */
-/* 2006-08-02 Lydia Wang Add support to VT1709 codec */
+/* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */
+/* 2006-08-02 Lydia Wang Add support to VT1709 codec */
/* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */
-/* 2007-09-12 Lydia Wang Add EAPD enable during driver initialization */
-/* 2007-09-17 Lydia Wang Add VT1708B codec support */
+/* 2007-09-12 Lydia Wang Add EAPD enable during driver initialization */
+/* 2007-09-17 Lydia Wang Add VT1708B codec support */
/* 2007-11-14 Lydia Wang Add VT1708A codec HP and CD pin connect config */
/* 2008-02-03 Lydia Wang Fix Rear channels and Back channels inverse issue */
-/* 2008-03-06 Lydia Wang Add VT1702 codec and VT1708S codec support */
-/* 2008-04-09 Lydia Wang Add mute front speaker when HP plugin */
-/* 2008-04-09 Lydia Wang Add Independent HP feature */
+/* 2008-03-06 Lydia Wang Add VT1702 codec and VT1708S codec support */
+/* 2008-04-09 Lydia Wang Add mute front speaker when HP plugin */
+/* 2008-04-09 Lydia Wang Add Independent HP feature */
/* 2008-05-28 Lydia Wang Add second S/PDIF Out support for VT1702 */
-/* 2008-09-15 Logan Li Add VT1708S Mic Boost workaround/backdoor */
-/* */
+/* 2008-09-15 Logan Li Add VT1708S Mic Boost workaround/backdoor */
+/* 2009-02-16 Logan Li Add support for VT1718S */
+/* 2009-03-13 Logan Li Add support for VT1716S */
+/* 2009-04-14 Lydai Wang Add support for VT1828S and VT2020 */
+/* 2009-07-08 Lydia Wang Add support for VT2002P */
+/* 2009-07-21 Lydia Wang Add support for VT1812 */
+/* */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@@ -76,14 +81,6 @@
#define VT1702_HP_NID 0x17
#define VT1702_DIGOUT_NID 0x11
-#define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b)
-#define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713)
-#define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717)
-#define IS_VT1708B_8CH_VENDORID(x) ((x) >= 0x1106e720 && (x) <= 0x1106e723)
-#define IS_VT1708B_4CH_VENDORID(x) ((x) >= 0x1106e724 && (x) <= 0x1106e727)
-#define IS_VT1708S_VENDORID(x) ((x) >= 0x11060397 && (x) <= 0x11067397)
-#define IS_VT1702_VENDORID(x) ((x) >= 0x11060398 && (x) <= 0x11067398)
-
enum VIA_HDA_CODEC {
UNKNOWN = -1,
VT1708,
@@ -92,12 +89,76 @@ enum VIA_HDA_CODEC {
VT1708B_8CH,
VT1708B_4CH,
VT1708S,
+ VT1708BCE,
VT1702,
+ VT1718S,
+ VT1716S,
+ VT2002P,
+ VT1812,
CODEC_TYPES,
};
-static enum VIA_HDA_CODEC get_codec_type(u32 vendor_id)
+struct via_spec {
+ /* codec parameterization */
+ struct snd_kcontrol_new *mixers[6];
+ unsigned int num_mixers;
+
+ struct hda_verb *init_verbs[5];
+ unsigned int num_iverbs;
+
+ char *stream_name_analog;
+ struct hda_pcm_stream *stream_analog_playback;
+ struct hda_pcm_stream *stream_analog_capture;
+
+ char *stream_name_digital;
+ struct hda_pcm_stream *stream_digital_playback;
+ struct hda_pcm_stream *stream_digital_capture;
+
+ /* playback */
+ struct hda_multi_out multiout;
+ hda_nid_t slave_dig_outs[2];
+
+ /* capture */
+ unsigned int num_adc_nids;
+ hda_nid_t *adc_nids;
+ hda_nid_t mux_nids[3];
+ hda_nid_t dig_in_nid;
+ hda_nid_t dig_in_pin;
+
+ /* capture source */
+ const struct hda_input_mux *input_mux;
+ unsigned int cur_mux[3];
+
+ /* PCM information */
+ struct hda_pcm pcm_rec[3];
+
+ /* dynamic controls, init_verbs and input_mux */
+ struct auto_pin_cfg autocfg;
+ struct snd_array kctls;
+ struct hda_input_mux private_imux[2];
+ hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
+
+ /* HP mode source */
+ const struct hda_input_mux *hp_mux;
+ unsigned int hp_independent_mode;
+ unsigned int hp_independent_mode_index;
+ unsigned int smart51_enabled;
+ unsigned int dmic_enabled;
+ enum VIA_HDA_CODEC codec_type;
+
+ /* work to check hp jack state */
+ struct hda_codec *codec;
+ struct delayed_work vt1708_hp_work;
+ int vt1708_jack_detectect;
+ int vt1708_hp_present;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+ struct hda_loopback_check loopback;
+#endif
+};
+
+static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
{
+ u32 vendor_id = codec->vendor_id;
u16 ven_id = vendor_id >> 16;
u16 dev_id = vendor_id & 0xffff;
enum VIA_HDA_CODEC codec_type;
@@ -111,9 +172,11 @@ static enum VIA_HDA_CODEC get_codec_type(u32 vendor_id)
codec_type = VT1709_10CH;
else if (dev_id >= 0xe714 && dev_id <= 0xe717)
codec_type = VT1709_6CH;
- else if (dev_id >= 0xe720 && dev_id <= 0xe723)
+ else if (dev_id >= 0xe720 && dev_id <= 0xe723) {
codec_type = VT1708B_8CH;
- else if (dev_id >= 0xe724 && dev_id <= 0xe727)
+ if (snd_hda_param_read(codec, 0x16, AC_PAR_CONNLIST_LEN) == 0x7)
+ codec_type = VT1708BCE;
+ } else if (dev_id >= 0xe724 && dev_id <= 0xe727)
codec_type = VT1708B_4CH;
else if ((dev_id & 0xfff) == 0x397
&& (dev_id >> 12) < 8)
@@ -121,6 +184,17 @@ static enum VIA_HDA_CODEC get_codec_type(u32 vendor_id)
else if ((dev_id & 0xfff) == 0x398
&& (dev_id >> 12) < 8)
codec_type = VT1702;
+ else if ((dev_id & 0xfff) == 0x428
+ && (dev_id >> 12) < 8)
+ codec_type = VT1718S;
+ else if (dev_id == 0x0433 || dev_id == 0xa721)
+ codec_type = VT1716S;
+ else if (dev_id == 0x0441 || dev_id == 0x4441)
+ codec_type = VT1718S;
+ else if (dev_id == 0x0438 || dev_id == 0x4438)
+ codec_type = VT2002P;
+ else if (dev_id == 0x0448)
+ codec_type = VT1812;
else
codec_type = UNKNOWN;
return codec_type;
@@ -128,10 +202,16 @@ static enum VIA_HDA_CODEC get_codec_type(u32 vendor_id)
#define VIA_HP_EVENT 0x01
#define VIA_GPIO_EVENT 0x02
+#define VIA_JACK_EVENT 0x04
+#define VIA_MONO_EVENT 0x08
+#define VIA_SPEAKER_EVENT 0x10
+#define VIA_BIND_HP_EVENT 0x20
enum {
VIA_CTL_WIDGET_VOL,
VIA_CTL_WIDGET_MUTE,
+ VIA_CTL_WIDGET_ANALOG_MUTE,
+ VIA_CTL_WIDGET_BIND_PIN_MUTE,
};
enum {
@@ -141,99 +221,162 @@ enum {
AUTO_SEQ_SIDE
};
-/* Some VT1708S based boards gets the micboost setting wrong, so we have
- * to apply some brute-force and re-write the TLV's by software. */
-static int mic_boost_tlv(struct snd_kcontrol *kcontrol, int op_flag,
- unsigned int size, unsigned int __user *_tlv)
+static void analog_low_current_mode(struct hda_codec *codec, int stream_idle);
+static void set_jack_power_state(struct hda_codec *codec);
+static int is_aa_path_mute(struct hda_codec *codec);
+
+static void vt1708_start_hp_work(struct via_spec *spec)
{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- hda_nid_t nid = get_amp_nid(kcontrol);
+ if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
+ return;
+ snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
+ !spec->vt1708_jack_detectect);
+ if (!delayed_work_pending(&spec->vt1708_hp_work))
+ schedule_delayed_work(&spec->vt1708_hp_work,
+ msecs_to_jiffies(100));
+}
- if (get_codec_type(codec->vendor_id) == VT1708S
- && (nid == 0x1a || nid == 0x1e)) {
- if (size < 4 * sizeof(unsigned int))
- return -ENOMEM;
- if (put_user(1, _tlv)) /* SNDRV_CTL_TLVT_DB_SCALE */
- return -EFAULT;
- if (put_user(2 * sizeof(unsigned int), _tlv + 1))
- return -EFAULT;
- if (put_user(0, _tlv + 2)) /* offset = 0 */
- return -EFAULT;
- if (put_user(1000, _tlv + 3)) /* step size = 10 dB */
- return -EFAULT;
- }
- return 0;
+static void vt1708_stop_hp_work(struct via_spec *spec)
+{
+ if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
+ return;
+ if (snd_hda_get_bool_hint(spec->codec, "analog_loopback_hp_detect") == 1
+ && !is_aa_path_mute(spec->codec))
+ return;
+ snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
+ !spec->vt1708_jack_detectect);
+ cancel_delayed_work(&spec->vt1708_hp_work);
+ flush_scheduled_work();
}
-static int mic_boost_volume_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
+
+static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
+ int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- hda_nid_t nid = get_amp_nid(kcontrol);
- if (get_codec_type(codec->vendor_id) == VT1708S
- && (nid == 0x1a || nid == 0x1e)) {
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 2;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 3;
+ set_jack_power_state(codec);
+ analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1);
+ if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) {
+ if (is_aa_path_mute(codec))
+ vt1708_start_hp_work(codec->spec);
+ else
+ vt1708_stop_hp_work(codec->spec);
}
- return 0;
+ return change;
}
-static struct snd_kcontrol_new vt1708_control_templates[] = {
- HDA_CODEC_VOLUME(NULL, 0, 0, 0),
- HDA_CODEC_MUTE(NULL, 0, 0, 0),
-};
-
-
-struct via_spec {
- /* codec parameterization */
- struct snd_kcontrol_new *mixers[3];
- unsigned int num_mixers;
-
- struct hda_verb *init_verbs[5];
- unsigned int num_iverbs;
-
- char *stream_name_analog;
- struct hda_pcm_stream *stream_analog_playback;
- struct hda_pcm_stream *stream_analog_capture;
-
- char *stream_name_digital;
- struct hda_pcm_stream *stream_digital_playback;
- struct hda_pcm_stream *stream_digital_capture;
+/* modify .put = snd_hda_mixer_amp_switch_put */
+#define ANALOG_INPUT_MUTE \
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = NULL, \
+ .index = 0, \
+ .info = snd_hda_mixer_amp_switch_info, \
+ .get = snd_hda_mixer_amp_switch_get, \
+ .put = analog_input_switch_put, \
+ .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
- /* playback */
- struct hda_multi_out multiout;
- hda_nid_t slave_dig_outs[2];
+static void via_hp_bind_automute(struct hda_codec *codec);
- /* capture */
- unsigned int num_adc_nids;
- hda_nid_t *adc_nids;
- hda_nid_t mux_nids[3];
- hda_nid_t dig_in_nid;
- hda_nid_t dig_in_pin;
+static int bind_pin_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct via_spec *spec = codec->spec;
+ int i;
+ int change = 0;
- /* capture source */
- const struct hda_input_mux *input_mux;
- unsigned int cur_mux[3];
+ long *valp = ucontrol->value.integer.value;
+ int lmute, rmute;
+ if (strstr(kcontrol->id.name, "Switch") == NULL) {
+ snd_printd("Invalid control!\n");
+ return change;
+ }
+ change = snd_hda_mixer_amp_switch_put(kcontrol,
+ ucontrol);
+ /* Get mute value */
+ lmute = *valp ? 0 : HDA_AMP_MUTE;
+ valp++;
+ rmute = *valp ? 0 : HDA_AMP_MUTE;
+
+ /* Set hp pins */
+ if (!spec->hp_independent_mode) {
+ for (i = 0; i < spec->autocfg.hp_outs; i++) {
+ snd_hda_codec_amp_update(
+ codec, spec->autocfg.hp_pins[i],
+ 0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
+ lmute);
+ snd_hda_codec_amp_update(
+ codec, spec->autocfg.hp_pins[i],
+ 1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
+ rmute);
+ }
+ }
- /* PCM information */
- struct hda_pcm pcm_rec[3];
+ if (!lmute && !rmute) {
+ /* Line Outs */
+ for (i = 0; i < spec->autocfg.line_outs; i++)
+ snd_hda_codec_amp_stereo(
+ codec, spec->autocfg.line_out_pins[i],
+ HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
+ /* Speakers */
+ for (i = 0; i < spec->autocfg.speaker_outs; i++)
+ snd_hda_codec_amp_stereo(
+ codec, spec->autocfg.speaker_pins[i],
+ HDA_OUTPUT, 0, HDA_AMP_MUTE, 0);
+ /* unmute */
+ via_hp_bind_automute(codec);
- /* dynamic controls, init_verbs and input_mux */
- struct auto_pin_cfg autocfg;
- struct snd_array kctls;
- struct hda_input_mux private_imux[2];
- hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
+ } else {
+ if (lmute) {
+ /* Mute all left channels */
+ for (i = 1; i < spec->autocfg.line_outs; i++)
+ snd_hda_codec_amp_update(
+ codec,
+ spec->autocfg.line_out_pins[i],
+ 0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
+ lmute);
+ for (i = 0; i < spec->autocfg.speaker_outs; i++)
+ snd_hda_codec_amp_update(
+ codec,
+ spec->autocfg.speaker_pins[i],
+ 0, HDA_OUTPUT, 0, HDA_AMP_MUTE,
+ lmute);
+ }
+ if (rmute) {
+ /* mute all right channels */
+ for (i = 1; i < spec->autocfg.line_outs; i++)
+ snd_hda_codec_amp_update(
+ codec,
+ spec->autocfg.line_out_pins[i],
+ 1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
+ rmute);
+ for (i = 0; i < spec->autocfg.speaker_outs; i++)
+ snd_hda_codec_amp_update(
+ codec,
+ spec->autocfg.speaker_pins[i],
+ 1, HDA_OUTPUT, 0, HDA_AMP_MUTE,
+ rmute);
+ }
+ }
+ return change;
+}
- /* HP mode source */
- const struct hda_input_mux *hp_mux;
- unsigned int hp_independent_mode;
+#define BIND_PIN_MUTE \
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = NULL, \
+ .index = 0, \
+ .info = snd_hda_mixer_amp_switch_info, \
+ .get = snd_hda_mixer_amp_switch_get, \
+ .put = bind_pin_switch_put, \
+ .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) }
-#ifdef CONFIG_SND_HDA_POWER_SAVE
- struct hda_loopback_check loopback;
-#endif
+static struct snd_kcontrol_new via_control_templates[] = {
+ HDA_CODEC_VOLUME(NULL, 0, 0, 0),
+ HDA_CODEC_MUTE(NULL, 0, 0, 0),
+ ANALOG_INPUT_MUTE,
+ BIND_PIN_MUTE,
};
static hda_nid_t vt1708_adc_nids[2] = {
@@ -261,6 +404,27 @@ static hda_nid_t vt1702_adc_nids[3] = {
0x12, 0x20, 0x1F
};
+static hda_nid_t vt1718S_adc_nids[2] = {
+ /* ADC1-2 */
+ 0x10, 0x11
+};
+
+static hda_nid_t vt1716S_adc_nids[2] = {
+ /* ADC1-2 */
+ 0x13, 0x14
+};
+
+static hda_nid_t vt2002P_adc_nids[2] = {
+ /* ADC1-2 */
+ 0x10, 0x11
+};
+
+static hda_nid_t vt1812_adc_nids[2] = {
+ /* ADC1-2 */
+ 0x10, 0x11
+};
+
+
/* add dynamic controls */
static int via_add_control(struct via_spec *spec, int type, const char *name,
unsigned long val)
@@ -271,7 +435,7 @@ static int via_add_control(struct via_spec *spec, int type, const char *name,
knew = snd_array_new(&spec->kctls);
if (!knew)
return -ENOMEM;
- *knew = vt1708_control_templates[type];
+ *knew = via_control_templates[type];
knew->name = kstrdup(name, GFP_KERNEL);
if (!knew->name)
return -ENOMEM;
@@ -293,8 +457,8 @@ 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, hda_nid_t pin,
- const char *ctlname, int idx, int mix_nid)
+static int via_new_analog_input(struct via_spec *spec, const char *ctlname,
+ int idx, int mix_nid)
{
char name[32];
int err;
@@ -305,7 +469,7 @@ static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin,
if (err < 0)
return err;
sprintf(name, "%s Playback Switch", ctlname);
- err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+ err = via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name,
HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
if (err < 0)
return err;
@@ -322,7 +486,7 @@ static void via_auto_set_output_and_unmute(struct hda_codec *codec,
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
AMP_OUT_UNMUTE);
if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
- snd_hda_codec_write(codec, nid, 0,
+ snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_EAPD_BTLENABLE, 0x02);
}
@@ -343,10 +507,13 @@ static void via_auto_init_hp_out(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
hda_nid_t pin;
+ int i;
- pin = spec->autocfg.hp_pins[0];
- if (pin) /* connect to front */
- via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+ for (i = 0; i < spec->autocfg.hp_outs; i++) {
+ pin = spec->autocfg.hp_pins[i];
+ if (pin) /* connect to front */
+ via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+ }
}
static void via_auto_init_analog_input(struct hda_codec *codec)
@@ -364,6 +531,510 @@ static void via_auto_init_analog_input(struct hda_codec *codec)
}
}
+
+static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin);
+
+static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int *affected_parm)
+{
+ unsigned parm;
+ unsigned def_conf = snd_hda_codec_get_pincfg(codec, nid);
+ unsigned no_presence = (def_conf & AC_DEFCFG_MISC)
+ >> AC_DEFCFG_MISC_SHIFT
+ & AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */
+ unsigned present = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_PIN_SENSE, 0) >> 31;
+ struct via_spec *spec = codec->spec;
+ if ((spec->smart51_enabled && is_smart51_pins(spec, nid))
+ || ((no_presence || present)
+ && get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)) {
+ *affected_parm = AC_PWRST_D0; /* if it's connected */
+ parm = AC_PWRST_D0;
+ } else
+ parm = AC_PWRST_D3;
+
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
+}
+
+static void set_jack_power_state(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int imux_is_smixer;
+ unsigned int parm;
+
+ if (spec->codec_type == VT1702) {
+ imux_is_smixer = snd_hda_codec_read(
+ codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
+ /* inputs */
+ /* PW 1/2/5 (14h/15h/18h) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x14, &parm);
+ set_pin_power_state(codec, 0x15, &parm);
+ set_pin_power_state(codec, 0x18, &parm);
+ if (imux_is_smixer)
+ parm = AC_PWRST_D0; /* SW0 = stereo mixer (idx 3) */
+ /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
+ snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+
+ /* outputs */
+ /* PW 3/4 (16h/17h) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x16, &parm);
+ set_pin_power_state(codec, 0x17, &parm);
+ /* MW0 (1ah), AOW 0/1 (10h/1dh) */
+ snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
+ imux_is_smixer ? AC_PWRST_D0 : parm);
+ snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ } else if (spec->codec_type == VT1708B_8CH
+ || spec->codec_type == VT1708B_4CH
+ || spec->codec_type == VT1708S) {
+ /* SW0 (17h) = stereo mixer */
+ int is_8ch = spec->codec_type != VT1708B_4CH;
+ imux_is_smixer = snd_hda_codec_read(
+ codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
+ == ((spec->codec_type == VT1708S) ? 5 : 0);
+ /* inputs */
+ /* PW 1/2/5 (1ah/1bh/1eh) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x1a, &parm);
+ set_pin_power_state(codec, 0x1b, &parm);
+ set_pin_power_state(codec, 0x1e, &parm);
+ if (imux_is_smixer)
+ parm = AC_PWRST_D0;
+ /* SW0 (17h), AIW 0/1 (13h/14h) */
+ snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+
+ /* outputs */
+ /* PW0 (19h), SW1 (18h), AOW1 (11h) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x19, &parm);
+ snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+
+ /* PW6 (22h), SW2 (26h), AOW2 (24h) */
+ if (is_8ch) {
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x22, &parm);
+ snd_hda_codec_write(codec, 0x26, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ snd_hda_codec_write(codec, 0x24, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ }
+
+ /* PW 3/4/7 (1ch/1dh/23h) */
+ parm = AC_PWRST_D3;
+ /* force to D0 for internal Speaker */
+ set_pin_power_state(codec, 0x1c, &parm);
+ set_pin_power_state(codec, 0x1d, &parm);
+ if (is_8ch)
+ set_pin_power_state(codec, 0x23, &parm);
+ /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
+ snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
+ imux_is_smixer ? AC_PWRST_D0 : parm);
+ snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ if (is_8ch) {
+ snd_hda_codec_write(codec, 0x25, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ snd_hda_codec_write(codec, 0x27, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ }
+ } else if (spec->codec_type == VT1718S) {
+ /* MUX6 (1eh) = stereo mixer */
+ imux_is_smixer = snd_hda_codec_read(
+ codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
+ /* inputs */
+ /* PW 5/6/7 (29h/2ah/2bh) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x29, &parm);
+ set_pin_power_state(codec, 0x2a, &parm);
+ set_pin_power_state(codec, 0x2b, &parm);
+ if (imux_is_smixer)
+ parm = AC_PWRST_D0;
+ /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */
+ snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+
+ /* outputs */
+ /* PW3 (27h), MW2 (1ah), AOW3 (bh) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x27, &parm);
+ snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+
+ /* PW2 (26h), AOW2 (ah) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x26, &parm);
+ snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+
+ /* PW0/1 (24h/25h) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x24, &parm);
+ set_pin_power_state(codec, 0x25, &parm);
+ if (!spec->hp_independent_mode) /* check for redirected HP */
+ set_pin_power_state(codec, 0x28, &parm);
+ snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
+ snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE,
+ imux_is_smixer ? AC_PWRST_D0 : parm);
+ if (spec->hp_independent_mode) {
+ /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x28, &parm);
+ snd_hda_codec_write(codec, 0x1b, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ snd_hda_codec_write(codec, 0x34, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ snd_hda_codec_write(codec, 0xc, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ }
+ } else if (spec->codec_type == VT1716S) {
+ unsigned int mono_out, present;
+ /* SW0 (17h) = stereo mixer */
+ imux_is_smixer = snd_hda_codec_read(
+ codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
+ /* inputs */
+ /* PW 1/2/5 (1ah/1bh/1eh) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x1a, &parm);
+ set_pin_power_state(codec, 0x1b, &parm);
+ set_pin_power_state(codec, 0x1e, &parm);
+ if (imux_is_smixer)
+ parm = AC_PWRST_D0;
+ /* SW0 (17h), AIW0(13h) */
+ snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x1e, &parm);
+ /* PW11 (22h) */
+ if (spec->dmic_enabled)
+ set_pin_power_state(codec, 0x22, &parm);
+ else
+ snd_hda_codec_write(
+ codec, 0x22, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+
+ /* SW2(26h), AIW1(14h) */
+ snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+
+ /* outputs */
+ /* PW0 (19h), SW1 (18h), AOW1 (11h) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x19, &parm);
+ /* Smart 5.1 PW2(1bh) */
+ if (spec->smart51_enabled)
+ set_pin_power_state(codec, 0x1b, &parm);
+ snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+
+ /* PW7 (23h), SW3 (27h), AOW3 (25h) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x23, &parm);
+ /* Smart 5.1 PW1(1ah) */
+ if (spec->smart51_enabled)
+ set_pin_power_state(codec, 0x1a, &parm);
+ snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+
+ /* Smart 5.1 PW5(1eh) */
+ if (spec->smart51_enabled)
+ set_pin_power_state(codec, 0x1e, &parm);
+ snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+
+ /* Mono out */
+ /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/
+ present = snd_hda_codec_read(
+ codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ if (present)
+ mono_out = 0;
+ else {
+ present = snd_hda_codec_read(
+ codec, 0x1d, 0, AC_VERB_GET_PIN_SENSE, 0)
+ & 0x80000000;
+ if (!spec->hp_independent_mode && present)
+ mono_out = 0;
+ else
+ mono_out = 1;
+ }
+ parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3;
+ snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+ snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE,
+ parm);
+
+ /* PW 3/4 (1ch/1dh) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x1c, &parm);
+ set_pin_power_state(codec, 0x1d, &parm);
+ /* HP Independent Mode, power on AOW3 */
+ if (spec->hp_independent_mode)
+ snd_hda_codec_write(codec, 0x25, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+
+ /* force to D0 for internal Speaker */
+ /* MW0 (16h), AOW0 (10h) */
+ snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
+ imux_is_smixer ? AC_PWRST_D0 : parm);
+ snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
+ mono_out ? AC_PWRST_D0 : parm);
+ } else if (spec->codec_type == VT2002P) {
+ unsigned int present;
+ /* MUX9 (1eh) = stereo mixer */
+ imux_is_smixer = snd_hda_codec_read(
+ codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
+ /* inputs */
+ /* PW 5/6/7 (29h/2ah/2bh) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x29, &parm);
+ set_pin_power_state(codec, 0x2a, &parm);
+ set_pin_power_state(codec, 0x2b, &parm);
+ if (imux_is_smixer)
+ parm = AC_PWRST_D0;
+ /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */
+ snd_hda_codec_write(codec, 0x1e, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ snd_hda_codec_write(codec, 0x1f, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ snd_hda_codec_write(codec, 0x10, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ snd_hda_codec_write(codec, 0x11, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+
+ /* outputs */
+ /* AOW0 (8h)*/
+ snd_hda_codec_write(codec, 0x8, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+ /* PW4 (26h), MW4 (1ch), MUX4(37h) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x26, &parm);
+ snd_hda_codec_write(codec, 0x1c, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ snd_hda_codec_write(codec, 0x37,
+ 0, AC_VERB_SET_POWER_STATE, parm);
+
+ /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x25, &parm);
+ snd_hda_codec_write(codec, 0x19, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ snd_hda_codec_write(codec, 0x35, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ if (spec->hp_independent_mode) {
+ snd_hda_codec_write(codec, 0x9, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ }
+
+ /* Class-D */
+ /* PW0 (24h), MW0(18h), MUX0(34h) */
+ present = snd_hda_codec_read(
+ codec, 0x25, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x24, &parm);
+ if (present) {
+ snd_hda_codec_write(
+ codec, 0x18, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+ snd_hda_codec_write(
+ codec, 0x34, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+ } else {
+ snd_hda_codec_write(
+ codec, 0x18, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+ snd_hda_codec_write(
+ codec, 0x34, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+ }
+
+ /* Mono Out */
+ /* PW15 (31h), MW8(17h), MUX8(3bh) */
+ present = snd_hda_codec_read(
+ codec, 0x26, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x31, &parm);
+ if (present) {
+ snd_hda_codec_write(
+ codec, 0x17, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+ snd_hda_codec_write(
+ codec, 0x3b, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+ } else {
+ snd_hda_codec_write(
+ codec, 0x17, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+ snd_hda_codec_write(
+ codec, 0x3b, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+ }
+
+ /* MW9 (21h) */
+ if (imux_is_smixer || !is_aa_path_mute(codec))
+ snd_hda_codec_write(
+ codec, 0x21, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+ else
+ snd_hda_codec_write(
+ codec, 0x21, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+ } else if (spec->codec_type == VT1812) {
+ unsigned int present;
+ /* MUX10 (1eh) = stereo mixer */
+ imux_is_smixer = snd_hda_codec_read(
+ codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
+ /* inputs */
+ /* PW 5/6/7 (29h/2ah/2bh) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x29, &parm);
+ set_pin_power_state(codec, 0x2a, &parm);
+ set_pin_power_state(codec, 0x2b, &parm);
+ if (imux_is_smixer)
+ parm = AC_PWRST_D0;
+ /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */
+ snd_hda_codec_write(codec, 0x1e, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ snd_hda_codec_write(codec, 0x1f, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ snd_hda_codec_write(codec, 0x10, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ snd_hda_codec_write(codec, 0x11, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+
+ /* outputs */
+ /* AOW0 (8h)*/
+ snd_hda_codec_write(codec, 0x8, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+ /* PW4 (28h), MW4 (18h), MUX4(38h) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x28, &parm);
+ snd_hda_codec_write(codec, 0x18, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ snd_hda_codec_write(codec, 0x38, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+
+ /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x25, &parm);
+ snd_hda_codec_write(codec, 0x15, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ snd_hda_codec_write(codec, 0x35, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ if (spec->hp_independent_mode) {
+ snd_hda_codec_write(codec, 0x9, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ }
+
+ /* Internal Speaker */
+ /* PW0 (24h), MW0(14h), MUX0(34h) */
+ present = snd_hda_codec_read(
+ codec, 0x25, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x24, &parm);
+ if (present) {
+ snd_hda_codec_write(codec, 0x14, 0,
+ AC_VERB_SET_POWER_STATE,
+ AC_PWRST_D3);
+ snd_hda_codec_write(codec, 0x34, 0,
+ AC_VERB_SET_POWER_STATE,
+ AC_PWRST_D3);
+ } else {
+ snd_hda_codec_write(codec, 0x14, 0,
+ AC_VERB_SET_POWER_STATE,
+ AC_PWRST_D0);
+ snd_hda_codec_write(codec, 0x34, 0,
+ AC_VERB_SET_POWER_STATE,
+ AC_PWRST_D0);
+ }
+ /* Mono Out */
+ /* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */
+ present = snd_hda_codec_read(
+ codec, 0x28, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x31, &parm);
+ if (present) {
+ snd_hda_codec_write(codec, 0x1c, 0,
+ AC_VERB_SET_POWER_STATE,
+ AC_PWRST_D3);
+ snd_hda_codec_write(codec, 0x3c, 0,
+ AC_VERB_SET_POWER_STATE,
+ AC_PWRST_D3);
+ snd_hda_codec_write(codec, 0x3e, 0,
+ AC_VERB_SET_POWER_STATE,
+ AC_PWRST_D3);
+ } else {
+ snd_hda_codec_write(codec, 0x1c, 0,
+ AC_VERB_SET_POWER_STATE,
+ AC_PWRST_D0);
+ snd_hda_codec_write(codec, 0x3c, 0,
+ AC_VERB_SET_POWER_STATE,
+ AC_PWRST_D0);
+ snd_hda_codec_write(codec, 0x3e, 0,
+ AC_VERB_SET_POWER_STATE,
+ AC_PWRST_D0);
+ }
+
+ /* PW15 (33h), MW15 (1dh), MUX15(3dh) */
+ parm = AC_PWRST_D3;
+ set_pin_power_state(codec, 0x33, &parm);
+ snd_hda_codec_write(codec, 0x1d, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+ snd_hda_codec_write(codec, 0x3d, 0,
+ AC_VERB_SET_POWER_STATE, parm);
+
+ /* MW9 (21h) */
+ if (imux_is_smixer || !is_aa_path_mute(codec))
+ snd_hda_codec_write(
+ codec, 0x21, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+ else
+ snd_hda_codec_write(
+ codec, 0x21, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+ }
+}
+
/*
* input MUX handling
*/
@@ -395,6 +1066,14 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
if (!spec->mux_nids[adc_idx])
return -EINVAL;
+ /* switch to D0 beofre change index */
+ if (snd_hda_codec_read(codec, spec->mux_nids[adc_idx], 0,
+ AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0)
+ snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+ /* update jack power state */
+ set_jack_power_state(codec);
+
return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
spec->mux_nids[adc_idx],
&spec->cur_mux[adc_idx]);
@@ -413,16 +1092,74 @@ static int via_independent_hp_get(struct snd_kcontrol *kcontrol,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct via_spec *spec = codec->spec;
- hda_nid_t nid = spec->autocfg.hp_pins[0];
- unsigned int pinsel = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_CONNECT_SEL,
- 0x00);
-
+ hda_nid_t nid;
+ unsigned int pinsel;
+
+ switch (spec->codec_type) {
+ case VT1718S:
+ nid = 0x34;
+ break;
+ case VT2002P:
+ nid = 0x35;
+ break;
+ case VT1812:
+ nid = 0x3d;
+ break;
+ default:
+ nid = spec->autocfg.hp_pins[0];
+ break;
+ }
+ /* use !! to translate conn sel 2 for VT1718S */
+ pinsel = !!snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_CONNECT_SEL,
+ 0x00);
ucontrol->value.enumerated.item[0] = pinsel;
return 0;
}
+static void activate_ctl(struct hda_codec *codec, const char *name, int active)
+{
+ struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name);
+ if (ctl) {
+ ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+ ctl->vd[0].access |= active
+ ? 0 : SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+ snd_ctl_notify(codec->bus->card,
+ SNDRV_CTL_EVENT_MASK_VALUE, &ctl->id);
+ }
+}
+
+static int update_side_mute_status(struct hda_codec *codec)
+{
+ /* mute side channel */
+ struct via_spec *spec = codec->spec;
+ unsigned int parm = spec->hp_independent_mode
+ ? AMP_OUT_MUTE : AMP_OUT_UNMUTE;
+ hda_nid_t sw3;
+
+ switch (spec->codec_type) {
+ case VT1708:
+ sw3 = 0x1b;
+ break;
+ case VT1709_10CH:
+ sw3 = 0x29;
+ break;
+ case VT1708B_8CH:
+ case VT1708S:
+ sw3 = 0x27;
+ break;
+ default:
+ sw3 = 0;
+ break;
+ }
+
+ if (sw3)
+ snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ parm);
+ return 0;
+}
+
static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -430,47 +1167,46 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
struct via_spec *spec = codec->spec;
hda_nid_t nid = spec->autocfg.hp_pins[0];
unsigned int pinsel = ucontrol->value.enumerated.item[0];
- unsigned int con_nid = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
-
- if (con_nid == spec->multiout.hp_nid) {
- if (pinsel == 0) {
- if (!spec->hp_independent_mode) {
- if (spec->multiout.num_dacs > 1)
- spec->multiout.num_dacs -= 1;
- spec->hp_independent_mode = 1;
- }
- } else if (pinsel == 1) {
- if (spec->hp_independent_mode) {
- if (spec->multiout.num_dacs > 1)
- spec->multiout.num_dacs += 1;
- spec->hp_independent_mode = 0;
- }
- }
- } else {
- if (pinsel == 0) {
- if (spec->hp_independent_mode) {
- if (spec->multiout.num_dacs > 1)
- spec->multiout.num_dacs += 1;
- spec->hp_independent_mode = 0;
- }
- } else if (pinsel == 1) {
- if (!spec->hp_independent_mode) {
- if (spec->multiout.num_dacs > 1)
- spec->multiout.num_dacs -= 1;
- spec->hp_independent_mode = 1;
- }
- }
+ /* Get Independent Mode index of headphone pin widget */
+ spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel
+ ? 1 : 0;
+
+ switch (spec->codec_type) {
+ case VT1718S:
+ nid = 0x34;
+ pinsel = pinsel ? 2 : 0; /* indep HP use AOW4 (index 2) */
+ spec->multiout.num_dacs = 4;
+ break;
+ case VT2002P:
+ nid = 0x35;
+ break;
+ case VT1812:
+ nid = 0x3d;
+ break;
+ default:
+ nid = spec->autocfg.hp_pins[0];
+ break;
+ }
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel);
+
+ if (spec->multiout.hp_nid && spec->multiout.hp_nid
+ != spec->multiout.dac_nids[HDA_FRONT])
+ snd_hda_codec_setup_stream(codec, spec->multiout.hp_nid,
+ 0, 0, 0);
+
+ update_side_mute_status(codec);
+ /* update HP volume/swtich active state */
+ if (spec->codec_type == VT1708S
+ || spec->codec_type == VT1702
+ || spec->codec_type == VT1718S
+ || spec->codec_type == VT1716S
+ || spec->codec_type == VT2002P
+ || spec->codec_type == VT1812) {
+ activate_ctl(codec, "Headphone Playback Volume",
+ spec->hp_independent_mode);
+ activate_ctl(codec, "Headphone Playback Switch",
+ spec->hp_independent_mode);
}
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL,
- pinsel);
-
- if (spec->multiout.hp_nid &&
- spec->multiout.hp_nid != spec->multiout.dac_nids[HDA_FRONT])
- snd_hda_codec_setup_stream(codec,
- spec->multiout.hp_nid,
- 0, 0, 0);
-
return 0;
}
@@ -486,6 +1222,175 @@ static struct snd_kcontrol_new via_hp_mixer[] = {
{ } /* end */
};
+static void notify_aa_path_ctls(struct hda_codec *codec)
+{
+ int i;
+ struct snd_ctl_elem_id id;
+ const char *labels[] = {"Mic", "Front Mic", "Line"};
+
+ memset(&id, 0, sizeof(id));
+ id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ for (i = 0; i < ARRAY_SIZE(labels); i++) {
+ sprintf(id.name, "%s Playback Volume", labels[i]);
+ snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &id);
+ }
+}
+
+static void mute_aa_path(struct hda_codec *codec, int mute)
+{
+ struct via_spec *spec = codec->spec;
+ hda_nid_t nid_mixer;
+ int start_idx;
+ int end_idx;
+ int i;
+ /* get nid of MW0 and start & end index */
+ switch (spec->codec_type) {
+ case VT1708:
+ nid_mixer = 0x17;
+ start_idx = 2;
+ end_idx = 4;
+ break;
+ case VT1709_10CH:
+ case VT1709_6CH:
+ nid_mixer = 0x18;
+ start_idx = 2;
+ end_idx = 4;
+ break;
+ case VT1708B_8CH:
+ case VT1708B_4CH:
+ case VT1708S:
+ case VT1716S:
+ nid_mixer = 0x16;
+ start_idx = 2;
+ end_idx = 4;
+ break;
+ default:
+ return;
+ }
+ /* check AA path's mute status */
+ for (i = start_idx; i <= end_idx; i++) {
+ int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE;
+ snd_hda_codec_amp_stereo(codec, nid_mixer, HDA_INPUT, i,
+ HDA_AMP_MUTE, val);
+ }
+}
+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;
+ }
+ }
+ return res;
+}
+
+static int via_smart51_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int via_smart51_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ 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 };
+ 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;
+ }
+ }
+ *ucontrol->value.integer.value = on;
+ return 0;
+}
+
+static int via_smart51_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct via_spec *spec = codec->spec;
+ 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)
+ 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(
+ codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE,
+ HDA_AMP_UNMUTE);
+ }
+ if (i == AUTO_PIN_FRONT_MIC) {
+ if (spec->codec_type == VT1708S
+ || spec->codec_type == VT1716S) {
+ /* input = index 1 (AOW3) */
+ snd_hda_codec_write(
+ codec, nid, 0,
+ AC_VERB_SET_CONNECT_SEL, 1);
+ snd_hda_codec_amp_stereo(
+ codec, nid, HDA_OUTPUT,
+ 0, HDA_AMP_MUTE, HDA_AMP_UNMUTE);
+ }
+ }
+ }
+ spec->smart51_enabled = *ucontrol->value.integer.value;
+ set_jack_power_state(codec);
+ return 1;
+}
+
+static struct snd_kcontrol_new via_smart51_mixer[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Smart 5.1",
+ .count = 1,
+ .info = via_smart51_info,
+ .get = via_smart51_get,
+ .put = via_smart51_put,
+ },
+ {} /* end */
+};
+
/* capture mixer elements */
static struct snd_kcontrol_new vt1708_capture_mixer[] = {
HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT),
@@ -506,6 +1411,112 @@ static struct snd_kcontrol_new vt1708_capture_mixer[] = {
},
{ } /* end */
};
+
+/* check AA path's mute statue */
+static int is_aa_path_mute(struct hda_codec *codec)
+{
+ int mute = 1;
+ hda_nid_t nid_mixer;
+ int start_idx;
+ int end_idx;
+ int i;
+ struct via_spec *spec = codec->spec;
+ /* get nid of MW0 and start & end index */
+ switch (spec->codec_type) {
+ case VT1708B_8CH:
+ case VT1708B_4CH:
+ case VT1708S:
+ case VT1716S:
+ nid_mixer = 0x16;
+ start_idx = 2;
+ end_idx = 4;
+ break;
+ case VT1702:
+ nid_mixer = 0x1a;
+ start_idx = 1;
+ end_idx = 3;
+ break;
+ case VT1718S:
+ nid_mixer = 0x21;
+ start_idx = 1;
+ end_idx = 3;
+ break;
+ case VT2002P:
+ case VT1812:
+ nid_mixer = 0x21;
+ start_idx = 0;
+ end_idx = 2;
+ break;
+ default:
+ return 0;
+ }
+ /* check AA path's mute status */
+ for (i = start_idx; i <= end_idx; i++) {
+ unsigned int con_list = snd_hda_codec_read(
+ codec, nid_mixer, 0, AC_VERB_GET_CONNECT_LIST, i/4*4);
+ int shift = 8 * (i % 4);
+ hda_nid_t nid_pin = (con_list & (0xff << shift)) >> shift;
+ unsigned int defconf = snd_hda_codec_get_pincfg(codec, nid_pin);
+ if (get_defcfg_connect(defconf) == AC_JACK_PORT_COMPLEX) {
+ /* check mute status while the pin is connected */
+ int mute_l = snd_hda_codec_amp_read(codec, nid_mixer, 0,
+ HDA_INPUT, i) >> 7;
+ int mute_r = snd_hda_codec_amp_read(codec, nid_mixer, 1,
+ HDA_INPUT, i) >> 7;
+ if (!mute_l || !mute_r) {
+ mute = 0;
+ break;
+ }
+ }
+ }
+ return mute;
+}
+
+/* enter/exit analog low-current mode */
+static void analog_low_current_mode(struct hda_codec *codec, int stream_idle)
+{
+ struct via_spec *spec = codec->spec;
+ static int saved_stream_idle = 1; /* saved stream idle status */
+ int enable = is_aa_path_mute(codec);
+ unsigned int verb = 0;
+ unsigned int parm = 0;
+
+ if (stream_idle == -1) /* stream status did not change */
+ enable = enable && saved_stream_idle;
+ else {
+ enable = enable && stream_idle;
+ saved_stream_idle = stream_idle;
+ }
+
+ /* decide low current mode's verb & parameter */
+ switch (spec->codec_type) {
+ case VT1708B_8CH:
+ case VT1708B_4CH:
+ verb = 0xf70;
+ parm = enable ? 0x02 : 0x00; /* 0x02: 2/3x, 0x00: 1x */
+ break;
+ case VT1708S:
+ case VT1718S:
+ case VT1716S:
+ verb = 0xf73;
+ parm = enable ? 0x51 : 0xe1; /* 0x51: 4/28x, 0xe1: 1x */
+ break;
+ case VT1702:
+ verb = 0xf73;
+ parm = enable ? 0x01 : 0x1d; /* 0x01: 4/40x, 0x1d: 1x */
+ break;
+ case VT2002P:
+ case VT1812:
+ verb = 0xf93;
+ parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */
+ break;
+ default:
+ return; /* other codecs are not supported */
+ }
+ /* send verb */
+ snd_hda_codec_write(codec, codec->afg, 0, verb, parm);
+}
+
/*
* generic initialization of ADC, input mixers and output mixers
*/
@@ -534,9 +1545,9 @@ static struct hda_verb vt1708_volume_init_verbs[] = {
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-
- /* Setup default input to PW4 */
- {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
+
+ /* Setup default input MW0 to PW4 */
+ {0x20, AC_VERB_SET_CONNECT_SEL, 0},
/* PW9 Output enable */
{0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
{ }
@@ -547,30 +1558,13 @@ static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream)
{
struct via_spec *spec = codec->spec;
+ int idle = substream->pstr->substream_opened == 1
+ && substream->ref_count == 0;
+ analog_low_current_mode(codec, idle);
return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
hinfo);
}
-static int via_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 via_spec *spec = codec->spec;
- return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
- stream_tag, format, substream);
-}
-
-static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- struct via_spec *spec = codec->spec;
- return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
-}
-
-
static void playback_multi_pcm_prep_0(struct hda_codec *codec,
unsigned int stream_tag,
unsigned int format,
@@ -615,8 +1609,8 @@ static void playback_multi_pcm_prep_0(struct hda_codec *codec,
snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag,
0, format);
- if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] &&
- !spec->hp_independent_mode)
+ if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT]
+ && !spec->hp_independent_mode)
/* headphone out will just decode front left/right (stereo) */
snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag,
0, format);
@@ -658,7 +1652,7 @@ static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
snd_hda_codec_setup_stream(codec, mout->hp_nid,
stream_tag, 0, format);
}
-
+ vt1708_start_hp_work(spec);
return 0;
}
@@ -698,7 +1692,7 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
snd_hda_codec_setup_stream(codec, mout->hp_nid,
0, 0, 0);
}
-
+ vt1708_stop_hp_work(spec);
return 0;
}
@@ -779,7 +1773,7 @@ static struct hda_pcm_stream vt1708_pcm_analog_playback = {
};
static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
- .substreams = 1,
+ .substreams = 2,
.channels_min = 2,
.channels_max = 8,
.nid = 0x10, /* NID to query formats and rates */
@@ -790,8 +1784,8 @@ static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = {
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.ops = {
.open = via_playback_pcm_open,
- .prepare = via_playback_pcm_prepare,
- .cleanup = via_playback_pcm_cleanup
+ .prepare = via_playback_multi_pcm_prepare,
+ .cleanup = via_playback_multi_pcm_cleanup
},
};
@@ -853,6 +1847,11 @@ static int via_build_controls(struct hda_codec *codec)
if (err < 0)
return err;
}
+
+ /* init power states */
+ set_jack_power_state(codec);
+ analog_low_current_mode(codec, 1);
+
via_free_kctls(codec); /* no longer needed */
return 0;
}
@@ -866,8 +1865,10 @@ static int via_build_pcms(struct hda_codec *codec)
codec->pcm_info = info;
info->name = spec->stream_name_analog;
- info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
- info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+ *(spec->stream_analog_playback);
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+ spec->multiout.dac_nids[0];
info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
@@ -904,20 +1905,62 @@ static void via_free(struct hda_codec *codec)
return;
via_free_kctls(codec);
+ vt1708_stop_hp_work(spec);
kfree(codec->spec);
}
/* mute internal speaker if HP is plugged */
static void via_hp_automute(struct hda_codec *codec)
{
- unsigned int present;
+ unsigned int present = 0;
struct via_spec *spec = codec->spec;
present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
- snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0],
- HDA_OUTPUT, 0, HDA_AMP_MUTE,
- present ? HDA_AMP_MUTE : 0);
+
+ if (!spec->hp_independent_mode) {
+ struct snd_ctl_elem_id id;
+ /* auto mute */
+ snd_hda_codec_amp_stereo(
+ codec, spec->autocfg.line_out_pins[0], HDA_OUTPUT, 0,
+ HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+ /* notify change */
+ memset(&id, 0, sizeof(id));
+ id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ strcpy(id.name, "Front Playback Switch");
+ snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &id);
+ }
+}
+
+/* mute mono out if HP or Line out is plugged */
+static void via_mono_automute(struct hda_codec *codec)
+{
+ unsigned int hp_present, lineout_present;
+ struct via_spec *spec = codec->spec;
+
+ if (spec->codec_type != VT1716S)
+ return;
+
+ lineout_present = snd_hda_codec_read(
+ codec, spec->autocfg.line_out_pins[0], 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+
+ /* Mute Mono Out if Line Out is plugged */
+ if (lineout_present) {
+ snd_hda_codec_amp_stereo(
+ codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE, HDA_AMP_MUTE);
+ return;
+ }
+
+ hp_present = snd_hda_codec_read(
+ codec, spec->autocfg.hp_pins[0], 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+
+ if (!spec->hp_independent_mode)
+ snd_hda_codec_amp_stereo(
+ codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE,
+ hp_present ? HDA_AMP_MUTE : 0);
}
static void via_gpio_control(struct hda_codec *codec)
@@ -968,15 +2011,83 @@ static void via_gpio_control(struct hda_codec *codec)
}
}
+/* mute Internal-Speaker if HP is plugged */
+static void via_speaker_automute(struct hda_codec *codec)
+{
+ unsigned int hp_present;
+ struct via_spec *spec = codec->spec;
+
+ if (spec->codec_type != VT2002P && spec->codec_type != VT1812)
+ return;
+
+ hp_present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+
+ if (!spec->hp_independent_mode) {
+ struct snd_ctl_elem_id id;
+ snd_hda_codec_amp_stereo(
+ codec, spec->autocfg.speaker_pins[0], HDA_OUTPUT, 0,
+ HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0);
+ /* notify change */
+ memset(&id, 0, sizeof(id));
+ id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ strcpy(id.name, "Speaker Playback Switch");
+ snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &id);
+ }
+}
+
+/* mute line-out and internal speaker if HP is plugged */
+static void via_hp_bind_automute(struct hda_codec *codec)
+{
+ unsigned int hp_present, present = 0;
+ struct via_spec *spec = codec->spec;
+ int i;
+
+ if (!spec->autocfg.hp_pins[0] || !spec->autocfg.line_out_pins[0])
+ return;
+
+ hp_present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+
+ present = snd_hda_codec_read(codec, spec->autocfg.line_out_pins[0], 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+
+ if (!spec->hp_independent_mode) {
+ /* Mute Line-Outs */
+ for (i = 0; i < spec->autocfg.line_outs; i++)
+ snd_hda_codec_amp_stereo(
+ codec, spec->autocfg.line_out_pins[i],
+ HDA_OUTPUT, 0,
+ HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0);
+ if (hp_present)
+ present = hp_present;
+ }
+ /* Speakers */
+ for (i = 0; i < spec->autocfg.speaker_outs; i++)
+ snd_hda_codec_amp_stereo(
+ codec, spec->autocfg.speaker_pins[i], HDA_OUTPUT, 0,
+ HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+}
+
+
/* unsolicited event for jack sensing */
static void via_unsol_event(struct hda_codec *codec,
unsigned int res)
{
res >>= 26;
- if (res == VIA_HP_EVENT)
+ if (res & VIA_HP_EVENT)
via_hp_automute(codec);
- else if (res == VIA_GPIO_EVENT)
+ if (res & VIA_GPIO_EVENT)
via_gpio_control(codec);
+ if (res & VIA_JACK_EVENT)
+ set_jack_power_state(codec);
+ if (res & VIA_MONO_EVENT)
+ via_mono_automute(codec);
+ if (res & VIA_SPEAKER_EVENT)
+ via_speaker_automute(codec);
+ if (res & VIA_BIND_HP_EVENT)
+ via_hp_bind_automute(codec);
}
static int via_init(struct hda_codec *codec)
@@ -986,6 +2097,10 @@ static int via_init(struct hda_codec *codec)
for (i = 0; i < spec->num_iverbs; i++)
snd_hda_sequence_write(codec, spec->init_verbs[i]);
+ spec->codec_type = get_codec_type(codec);
+ if (spec->codec_type == VT1708BCE)
+ spec->codec_type = VT1708S; /* VT1708BCE & VT1708S are almost
+ same */
/* Lydia Add for EAPD enable */
if (!spec->dig_in_nid) { /* No Digital In connection */
if (spec->dig_in_pin) {
@@ -1003,8 +2118,17 @@ static int via_init(struct hda_codec *codec)
if (spec->slave_dig_outs[0])
codec->slave_dig_outs = spec->slave_dig_outs;
- return 0;
+ return 0;
+}
+
+#ifdef SND_HDA_NEEDS_RESUME
+static int via_suspend(struct hda_codec *codec, pm_message_t state)
+{
+ struct via_spec *spec = codec->spec;
+ vt1708_stop_hp_work(spec);
+ return 0;
}
+#endif
#ifdef CONFIG_SND_HDA_POWER_SAVE
static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
@@ -1021,6 +2145,9 @@ static struct hda_codec_ops via_patch_ops = {
.build_pcms = via_build_pcms,
.init = via_init,
.free = via_free,
+#ifdef SND_HDA_NEEDS_RESUME
+ .suspend = via_suspend,
+#endif
#ifdef CONFIG_SND_HDA_POWER_SAVE
.check_power_status = via_check_power_status,
#endif
@@ -1036,8 +2163,8 @@ static int vt1708_auto_fill_dac_nids(struct via_spec *spec,
spec->multiout.num_dacs = cfg->line_outs;
spec->multiout.dac_nids = spec->private_dac_nids;
-
- for(i = 0; i < 4; i++) {
+
+ for (i = 0; i < 4; i++) {
nid = cfg->line_out_pins[i];
if (nid) {
/* config dac list */
@@ -1067,7 +2194,7 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
{
char name[32];
static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
- hda_nid_t nid, nid_vol = 0;
+ hda_nid_t nid, nid_vol, nid_vols[] = {0x17, 0x19, 0x1a, 0x1b};
int i, err;
for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
@@ -1075,9 +2202,8 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
if (!nid)
continue;
-
- if (i != AUTO_SEQ_FRONT)
- nid_vol = 0x18 + i;
+
+ nid_vol = nid_vols[i];
if (i == AUTO_SEQ_CENLFE) {
/* Center/LFE */
@@ -1105,21 +2231,21 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
HDA_OUTPUT));
if (err < 0)
return err;
- } else if (i == AUTO_SEQ_FRONT){
+ } else if (i == AUTO_SEQ_FRONT) {
/* add control to mixer index 0 */
err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
"Master Front Playback Volume",
- HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
HDA_INPUT));
if (err < 0)
return err;
err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
"Master Front Playback Switch",
- HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
HDA_INPUT));
if (err < 0)
return err;
-
+
/* add control to PW3 */
sprintf(name, "%s Playback Volume", chname[i]);
err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
@@ -1178,6 +2304,7 @@ static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
return 0;
spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */
+ spec->hp_independent_mode_index = 1;
err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
"Headphone Playback Volume",
@@ -1218,7 +2345,7 @@ static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
case 0x1d: /* Mic */
idx = 2;
break;
-
+
case 0x1e: /* Line In */
idx = 3;
break;
@@ -1231,8 +2358,7 @@ static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
idx = 1;
break;
}
- err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
- idx, 0x17);
+ err = via_new_analog_input(spec, labels[i], idx, 0x17);
if (err < 0)
return err;
imux->items[imux->num_items].label = labels[i];
@@ -1260,16 +2386,60 @@ static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
def_conf = snd_hda_codec_get_pincfg(codec, nid);
seqassoc = (unsigned char) get_defcfg_association(def_conf);
seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
- if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) {
- if (seqassoc == 0xff) {
- def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
- snd_hda_codec_set_pincfg(codec, nid, def_conf);
- }
+ if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE
+ && (seqassoc == 0xf0 || seqassoc == 0xff)) {
+ def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
+ snd_hda_codec_set_pincfg(codec, nid, def_conf);
}
return;
}
+static int vt1708_jack_detectect_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct via_spec *spec = codec->spec;
+
+ if (spec->codec_type != VT1708)
+ return 0;
+ spec->vt1708_jack_detectect =
+ !((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1);
+ ucontrol->value.integer.value[0] = spec->vt1708_jack_detectect;
+ return 0;
+}
+
+static int vt1708_jack_detectect_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct via_spec *spec = codec->spec;
+ int change;
+
+ if (spec->codec_type != VT1708)
+ return 0;
+ spec->vt1708_jack_detectect = ucontrol->value.integer.value[0];
+ change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8))
+ == !spec->vt1708_jack_detectect;
+ if (spec->vt1708_jack_detectect) {
+ mute_aa_path(codec, 1);
+ notify_aa_path_ctls(codec);
+ }
+ return change;
+}
+
+static struct snd_kcontrol_new vt1708_jack_detectect[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Jack Detect",
+ .count = 1,
+ .info = snd_ctl_boolean_mono_info,
+ .get = vt1708_jack_detectect_get,
+ .put = vt1708_jack_detectect_put,
+ },
+ {} /* end */
+};
+
static int vt1708_parse_auto_config(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
@@ -1297,6 +2467,10 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
if (err < 0)
return err;
+ /* add jack detect on/off control */
+ err = snd_hda_add_new_ctls(codec, vt1708_jack_detectect);
+ if (err < 0)
+ return err;
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
@@ -1316,19 +2490,45 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
if (spec->hp_mux)
spec->mixers[spec->num_mixers++] = via_hp_mixer;
+ spec->mixers[spec->num_mixers++] = via_smart51_mixer;
return 1;
}
/* init callback for auto-configuration model -- overriding the default init */
static int via_auto_init(struct hda_codec *codec)
{
+ struct via_spec *spec = codec->spec;
+
via_init(codec);
via_auto_init_multi_out(codec);
via_auto_init_hp_out(codec);
via_auto_init_analog_input(codec);
+ if (spec->codec_type == VT2002P || spec->codec_type == VT1812) {
+ via_hp_bind_automute(codec);
+ } else {
+ via_hp_automute(codec);
+ via_speaker_automute(codec);
+ }
+
return 0;
}
+static void vt1708_update_hp_jack_state(struct work_struct *work)
+{
+ struct via_spec *spec = container_of(work, struct via_spec,
+ vt1708_hp_work.work);
+ if (spec->codec_type != VT1708)
+ return;
+ /* if jack state toggled */
+ if (spec->vt1708_hp_present
+ != (snd_hda_codec_read(spec->codec, spec->autocfg.hp_pins[0], 0,
+ AC_VERB_GET_PIN_SENSE, 0) >> 31)) {
+ spec->vt1708_hp_present ^= 1;
+ via_hp_automute(spec->codec);
+ }
+ vt1708_start_hp_work(spec);
+}
+
static int get_mux_nids(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
@@ -1378,7 +2578,7 @@ static int patch_vt1708(struct hda_codec *codec)
"from BIOS. Using genenic mode...\n");
}
-
+
spec->stream_name_analog = "VT1708 Analog";
spec->stream_analog_playback = &vt1708_pcm_analog_playback;
/* disable 32bit format on VT1708 */
@@ -1390,7 +2590,7 @@ static int patch_vt1708(struct hda_codec *codec)
spec->stream_digital_playback = &vt1708_pcm_digital_playback;
spec->stream_digital_capture = &vt1708_pcm_digital_capture;
-
+
if (!spec->adc_nids && spec->input_mux) {
spec->adc_nids = vt1708_adc_nids;
spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids);
@@ -1405,7 +2605,8 @@ static int patch_vt1708(struct hda_codec *codec)
#ifdef CONFIG_SND_HDA_POWER_SAVE
spec->loopback.amplist = vt1708_loopbacks;
#endif
-
+ spec->codec = codec;
+ INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state);
return 0;
}
@@ -1433,7 +2634,8 @@ static struct snd_kcontrol_new vt1709_capture_mixer[] = {
};
static struct hda_verb vt1709_uniwill_init_verbs[] = {
- {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
+ {0x20, AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
{ }
};
@@ -1473,8 +2675,8 @@ static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- /* Set input of PW4 as AOW4 */
- {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
+ /* Set input of PW4 as MW0 */
+ {0x20, AC_VERB_SET_CONNECT_SEL, 0},
/* PW9 Output enable */
{0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
{ }
@@ -1487,8 +2689,8 @@ static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = {
.nid = 0x10, /* NID to query formats and rates */
.ops = {
.open = via_playback_pcm_open,
- .prepare = via_playback_pcm_prepare,
- .cleanup = via_playback_pcm_cleanup
+ .prepare = via_playback_multi_pcm_prepare,
+ .cleanup = via_playback_multi_pcm_cleanup,
},
};
@@ -1499,8 +2701,8 @@ static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = {
.nid = 0x10, /* NID to query formats and rates */
.ops = {
.open = via_playback_pcm_open,
- .prepare = via_playback_pcm_prepare,
- .cleanup = via_playback_pcm_cleanup
+ .prepare = via_playback_multi_pcm_prepare,
+ .cleanup = via_playback_multi_pcm_cleanup,
},
};
@@ -1575,11 +2777,11 @@ static int vt1709_auto_fill_dac_nids(struct via_spec *spec,
spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */
} else if (cfg->line_outs == 3) { /* 6 channels */
- for(i = 0; i < cfg->line_outs; i++) {
+ for (i = 0; i < cfg->line_outs; i++) {
nid = cfg->line_out_pins[i];
if (nid) {
/* config dac list */
- switch(i) {
+ switch (i) {
case AUTO_SEQ_FRONT:
/* AOW0 */
spec->multiout.dac_nids[i] = 0x10;
@@ -1608,56 +2810,58 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
{
char name[32];
static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
- hda_nid_t nid = 0;
+ hda_nid_t nid, nid_vol, nid_vols[] = {0x18, 0x1a, 0x1b, 0x29};
int i, err;
for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
nid = cfg->line_out_pins[i];
- if (!nid)
+ if (!nid)
continue;
+ nid_vol = nid_vols[i];
+
if (i == AUTO_SEQ_CENLFE) {
/* Center/LFE */
err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
"Center Playback Volume",
- HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
HDA_OUTPUT));
if (err < 0)
return err;
err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
"LFE Playback Volume",
- HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
HDA_OUTPUT));
if (err < 0)
return err;
err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
"Center Playback Switch",
- HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
HDA_OUTPUT));
if (err < 0)
return err;
err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
"LFE Playback Switch",
- HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
HDA_OUTPUT));
if (err < 0)
return err;
- } else if (i == AUTO_SEQ_FRONT){
- /* add control to mixer index 0 */
+ } else if (i == AUTO_SEQ_FRONT) {
+ /* ADD control to mixer index 0 */
err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
"Master Front Playback Volume",
- HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
HDA_INPUT));
if (err < 0)
return err;
err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
"Master Front Playback Switch",
- HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
HDA_INPUT));
if (err < 0)
return err;
-
+
/* add control to PW3 */
sprintf(name, "%s Playback Volume", chname[i]);
err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
@@ -1674,26 +2878,26 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
} else if (i == AUTO_SEQ_SURROUND) {
sprintf(name, "%s Playback Volume", chname[i]);
err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
HDA_OUTPUT));
if (err < 0)
return err;
sprintf(name, "%s Playback Switch", chname[i]);
err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
- HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
HDA_OUTPUT));
if (err < 0)
return err;
} else if (i == AUTO_SEQ_SIDE) {
sprintf(name, "%s Playback Volume", chname[i]);
err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
- HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
HDA_OUTPUT));
if (err < 0)
return err;
sprintf(name, "%s Playback Switch", chname[i]);
err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
- HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
HDA_OUTPUT));
if (err < 0)
return err;
@@ -1714,6 +2918,7 @@ static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
spec->multiout.hp_nid = VT1709_HP_DAC_NID;
else if (spec->multiout.num_dacs == 3) /* 6 channels */
spec->multiout.hp_nid = 0;
+ spec->hp_independent_mode_index = 1;
err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
"Headphone Playback Volume",
@@ -1752,7 +2957,7 @@ static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
case 0x1d: /* Mic */
idx = 2;
break;
-
+
case 0x1e: /* Line In */
idx = 3;
break;
@@ -1765,8 +2970,7 @@ static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
idx = 1;
break;
}
- err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
- idx, 0x18);
+ err = via_new_analog_input(spec, labels[i], idx, 0x18);
if (err < 0)
return err;
imux->items[imux->num_items].label = labels[i];
@@ -1816,6 +3020,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
if (spec->hp_mux)
spec->mixers[spec->num_mixers++] = via_hp_mixer;
+ spec->mixers[spec->num_mixers++] = via_smart51_mixer;
return 1;
}
@@ -1861,7 +3066,7 @@ static int patch_vt1709_10ch(struct hda_codec *codec)
spec->stream_digital_playback = &vt1709_pcm_digital_playback;
spec->stream_digital_capture = &vt1709_pcm_digital_capture;
-
+
if (!spec->adc_nids && spec->input_mux) {
spec->adc_nids = vt1709_adc_nids;
spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
@@ -1955,7 +3160,7 @@ static int patch_vt1709_6ch(struct hda_codec *codec)
spec->stream_digital_playback = &vt1709_pcm_digital_playback;
spec->stream_digital_capture = &vt1709_pcm_digital_capture;
-
+
if (!spec->adc_nids && spec->input_mux) {
spec->adc_nids = vt1709_adc_nids;
spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids);
@@ -2024,7 +3229,7 @@ static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
{0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
/* Setup default input to PW4 */
- {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1},
+ {0x1d, AC_VERB_SET_CONNECT_SEL, 0},
/* PW9 Output enable */
{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
/* PW10 Input enable */
@@ -2068,10 +3273,29 @@ static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
};
static struct hda_verb vt1708B_uniwill_init_verbs[] = {
- {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
+ {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
+ {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
{ }
};
+static int via_pcm_open_close(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ int idle = substream->pstr->substream_opened == 1
+ && substream->ref_count == 0;
+
+ analog_low_current_mode(codec, idle);
+ return 0;
+}
+
static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
.substreams = 2,
.channels_min = 2,
@@ -2080,7 +3304,8 @@ static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
.ops = {
.open = via_playback_pcm_open,
.prepare = via_playback_multi_pcm_prepare,
- .cleanup = via_playback_multi_pcm_cleanup
+ .cleanup = via_playback_multi_pcm_cleanup,
+ .close = via_pcm_open_close
},
};
@@ -2102,8 +3327,10 @@ static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
.channels_max = 2,
.nid = 0x13, /* NID to query formats and rates */
.ops = {
+ .open = via_pcm_open_close,
.prepare = via_capture_pcm_prepare,
- .cleanup = via_capture_pcm_cleanup
+ .cleanup = via_capture_pcm_cleanup,
+ .close = via_pcm_open_close
},
};
@@ -2260,6 +3487,7 @@ static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
return 0;
spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
+ spec->hp_independent_mode_index = 1;
err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
"Headphone Playback Volume",
@@ -2313,8 +3541,7 @@ static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
idx = 1;
break;
}
- err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
- idx, 0x16);
+ err = via_new_analog_input(spec, labels[i], idx, 0x16);
if (err < 0)
return err;
imux->items[imux->num_items].label = labels[i];
@@ -2364,6 +3591,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
if (spec->hp_mux)
spec->mixers[spec->num_mixers++] = via_hp_mixer;
+ spec->mixers[spec->num_mixers++] = via_smart51_mixer;
return 1;
}
@@ -2376,12 +3604,14 @@ static struct hda_amp_list vt1708B_loopbacks[] = {
{ } /* end */
};
#endif
-
+static int patch_vt1708S(struct hda_codec *codec);
static int patch_vt1708B_8ch(struct hda_codec *codec)
{
struct via_spec *spec;
int err;
+ if (get_codec_type(codec) == VT1708BCE)
+ return patch_vt1708S(codec);
/* create a codec specific record */
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
@@ -2483,29 +3713,15 @@ static int patch_vt1708B_4ch(struct hda_codec *codec)
/* Patch for VT1708S */
-/* VT1708S software backdoor based override for buggy hardware micboost
- * setting */
-#define MIC_BOOST_VOLUME(xname, nid) { \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .index = 0, \
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
- SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
- SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
- .info = mic_boost_volume_info, \
- .get = snd_hda_mixer_amp_volume_get, \
- .put = snd_hda_mixer_amp_volume_put, \
- .tlv = { .c = mic_boost_tlv }, \
- .private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT) }
-
/* capture mixer elements */
static struct snd_kcontrol_new vt1708S_capture_mixer[] = {
HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
- MIC_BOOST_VOLUME("Mic Boost Capture Volume", 0x1A),
- MIC_BOOST_VOLUME("Front Mic Boost Capture Volume", 0x1E),
+ HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0,
+ HDA_INPUT),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
/* The multiple "Capture Source" controls confuse alsamixer
@@ -2542,11 +3758,21 @@ static struct hda_verb vt1708S_volume_init_verbs[] = {
{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
/* Enable Mic Boost Volume backdoor */
{0x1, 0xf98, 0x1},
+ /* don't bybass mixer */
+ {0x1, 0xf88, 0xc0},
{ }
};
static struct hda_verb vt1708S_uniwill_init_verbs[] = {
- {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
+ {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
+ {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
{ }
};
@@ -2557,8 +3783,9 @@ static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
.nid = 0x10, /* NID to query formats and rates */
.ops = {
.open = via_playback_pcm_open,
- .prepare = via_playback_pcm_prepare,
- .cleanup = via_playback_pcm_cleanup
+ .prepare = via_playback_multi_pcm_prepare,
+ .cleanup = via_playback_multi_pcm_cleanup,
+ .close = via_pcm_open_close
},
};
@@ -2568,8 +3795,10 @@ static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
.channels_max = 2,
.nid = 0x13, /* NID to query formats and rates */
.ops = {
+ .open = via_pcm_open_close,
.prepare = via_capture_pcm_prepare,
- .cleanup = via_capture_pcm_cleanup
+ .cleanup = via_capture_pcm_cleanup,
+ .close = via_pcm_open_close
},
};
@@ -2726,6 +3955,7 @@ static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
return 0;
spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */
+ spec->hp_independent_mode_index = 1;
err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
"Headphone Playback Volume",
@@ -2780,8 +4010,7 @@ static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
idx = 1;
break;
}
- err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
- idx, 0x16);
+ err = via_new_analog_input(spec, labels[i], idx, 0x16);
if (err < 0)
return err;
imux->items[imux->num_items].label = labels[i];
@@ -2852,6 +4081,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
if (spec->hp_mux)
spec->mixers[spec->num_mixers++] = via_hp_mixer;
+ spec->mixers[spec->num_mixers++] = via_smart51_mixer;
return 1;
}
@@ -2865,6 +4095,16 @@ static struct hda_amp_list vt1708S_loopbacks[] = {
};
#endif
+static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin,
+ int offset, int num_steps, int step_size)
+{
+ snd_hda_override_amp_caps(codec, pin, HDA_INPUT,
+ (offset << AC_AMPCAP_OFFSET_SHIFT) |
+ (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) |
+ (step_size << AC_AMPCAP_STEP_SIZE_SHIFT) |
+ (0 << AC_AMPCAP_MUTE_SHIFT));
+}
+
static int patch_vt1708S(struct hda_codec *codec)
{
struct via_spec *spec;
@@ -2901,6 +4141,8 @@ static int patch_vt1708S(struct hda_codec *codec)
spec->adc_nids = vt1708S_adc_nids;
spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
get_mux_nids(codec);
+ override_mic_boost(codec, 0x1a, 0, 3, 40);
+ override_mic_boost(codec, 0x1e, 0, 3, 40);
spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
spec->num_mixers++;
}
@@ -2913,6 +4155,16 @@ static int patch_vt1708S(struct hda_codec *codec)
spec->loopback.amplist = vt1708S_loopbacks;
#endif
+ /* correct names for VT1708BCE */
+ if (get_codec_type(codec) == VT1708BCE) {
+ kfree(codec->chip_name);
+ codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL);
+ snprintf(codec->bus->card->mixername,
+ sizeof(codec->bus->card->mixername),
+ "%s %s", codec->vendor_name, codec->chip_name);
+ spec->stream_name_analog = "VT1708BCE Analog";
+ spec->stream_name_digital = "VT1708BCE Digital";
+ }
return 0;
}
@@ -2967,12 +4219,20 @@ static struct hda_verb vt1702_volume_init_verbs[] = {
/* PW6 PW7 Output enable */
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
{0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+ /* mixer enable */
+ {0x1, 0xF88, 0x3},
+ /* GPIO 0~2 */
+ {0x1, 0xF82, 0x3F},
{ }
};
static struct hda_verb vt1702_uniwill_init_verbs[] = {
- {0x01, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_GPIO_EVENT},
- {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT},
+ {0x17, AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
+ {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
{ }
};
@@ -2984,7 +4244,8 @@ static struct hda_pcm_stream vt1702_pcm_analog_playback = {
.ops = {
.open = via_playback_pcm_open,
.prepare = via_playback_multi_pcm_prepare,
- .cleanup = via_playback_multi_pcm_cleanup
+ .cleanup = via_playback_multi_pcm_cleanup,
+ .close = via_pcm_open_close
},
};
@@ -2994,8 +4255,10 @@ static struct hda_pcm_stream vt1702_pcm_analog_capture = {
.channels_max = 2,
.nid = 0x12, /* NID to query formats and rates */
.ops = {
+ .open = via_pcm_open_close,
.prepare = via_capture_pcm_prepare,
- .cleanup = via_capture_pcm_cleanup
+ .cleanup = via_capture_pcm_cleanup,
+ .close = via_pcm_open_close
},
};
@@ -3065,12 +4328,13 @@ static int vt1702_auto_create_line_out_ctls(struct via_spec *spec,
static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
{
- int err;
-
+ int err, i;
+ struct hda_input_mux *imux;
+ static const char *texts[] = { "ON", "OFF", NULL};
if (!pin)
return 0;
-
spec->multiout.hp_nid = 0x1D;
+ spec->hp_independent_mode_index = 0;
err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
"Headphone Playback Volume",
@@ -3084,8 +4348,18 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
if (err < 0)
return err;
- create_hp_imux(spec);
+ 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++;
+ }
+
+ spec->hp_mux = &spec->private_imux[1];
return 0;
}
@@ -3121,8 +4395,7 @@ static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
idx = 3;
break;
}
- err = via_new_analog_input(spec, cfg->input_pins[i],
- labels[i], idx, 0x1A);
+ err = via_new_analog_input(spec, labels[i], idx, 0x1A);
if (err < 0)
return err;
imux->items[imux->num_items].label = labels[i];
@@ -3152,6 +4425,12 @@ static int vt1702_parse_auto_config(struct hda_codec *codec)
err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
if (err < 0)
return err;
+ /* limit AA path volume to 0 dB */
+ snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT,
+ (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
+ (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);
if (err < 0)
return err;
@@ -3185,8 +4464,6 @@ static int patch_vt1702(struct hda_codec *codec)
{
struct via_spec *spec;
int err;
- unsigned int response;
- unsigned char control;
/* create a codec specific record */
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
@@ -3231,17 +4508,1638 @@ static int patch_vt1702(struct hda_codec *codec)
spec->loopback.amplist = vt1702_loopbacks;
#endif
- /* Open backdoor */
- response = snd_hda_codec_read(codec, codec->afg, 0, 0xF8C, 0);
- control = (unsigned char)(response & 0xff);
- control |= 0x3;
- snd_hda_codec_write(codec, codec->afg, 0, 0xF88, control);
+ return 0;
+}
+
+/* Patch for VT1718S */
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt1718S_capture_mixer[] = {
+ HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0,
+ HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* The multiple "Capture Source" controls confuse alsamixer
+ * So call somewhat different..
+ */
+ .name = "Input Source",
+ .count = 2,
+ .info = via_mux_enum_info,
+ .get = via_mux_enum_get,
+ .put = via_mux_enum_put,
+ },
+ { } /* end */
+};
+
+static struct hda_verb vt1718S_volume_init_verbs[] = {
+ /*
+ * Unmute ADC0-1 and set the default input to mic-in
+ */
+ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+ /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+ * mixer widget
+ */
+ /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
+
+ /* Setup default input of Front HP to MW9 */
+ {0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
+ /* PW9 PW10 Output enable */
+ {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
+ {0x2e, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
+ /* PW11 Input enable */
+ {0x2f, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_IN_EN},
+ /* Enable Boost Volume backdoor */
+ {0x1, 0xf88, 0x8},
+ /* MW0/1/2/3/4: un-mute index 0 (AOWx), mute index 1 (MW9) */
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ /* set MUX1 = 2 (AOW4), MUX2 = 1 (AOW3) */
+ {0x34, AC_VERB_SET_CONNECT_SEL, 0x2},
+ {0x35, AC_VERB_SET_CONNECT_SEL, 0x1},
+ /* Unmute MW4's index 0 */
+ {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ { }
+};
+
+
+static struct hda_verb vt1718S_uniwill_init_verbs[] = {
+ {0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
+ {0x24, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x26, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x27, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ { }
+};
+
+static struct hda_pcm_stream vt1718S_pcm_analog_playback = {
+ .substreams = 2,
+ .channels_min = 2,
+ .channels_max = 10,
+ .nid = 0x8, /* NID to query formats and rates */
+ .ops = {
+ .open = via_playback_pcm_open,
+ .prepare = via_playback_multi_pcm_prepare,
+ .cleanup = via_playback_multi_pcm_cleanup,
+ .close = via_pcm_open_close,
+ },
+};
+
+static struct hda_pcm_stream vt1718S_pcm_analog_capture = {
+ .substreams = 2,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0x10, /* NID to query formats and rates */
+ .ops = {
+ .open = via_pcm_open_close,
+ .prepare = via_capture_pcm_prepare,
+ .cleanup = via_capture_pcm_cleanup,
+ .close = via_pcm_open_close,
+ },
+};
+
+static struct hda_pcm_stream vt1718S_pcm_digital_playback = {
+ .substreams = 2,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in via_build_pcms */
+ .ops = {
+ .open = via_dig_playback_pcm_open,
+ .close = via_dig_playback_pcm_close,
+ .prepare = via_dig_playback_pcm_prepare,
+ .cleanup = via_dig_playback_pcm_cleanup
+ },
+};
+
+static struct hda_pcm_stream vt1718S_pcm_digital_capture = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+};
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int vt1718S_auto_fill_dac_nids(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ int i;
+ hda_nid_t nid;
+
+ spec->multiout.num_dacs = cfg->line_outs;
+
+ spec->multiout.dac_nids = spec->private_dac_nids;
+
+ for (i = 0; i < 4; i++) {
+ nid = cfg->line_out_pins[i];
+ if (nid) {
+ /* config dac list */
+ switch (i) {
+ case AUTO_SEQ_FRONT:
+ spec->multiout.dac_nids[i] = 0x8;
+ break;
+ case AUTO_SEQ_CENLFE:
+ spec->multiout.dac_nids[i] = 0xa;
+ break;
+ case AUTO_SEQ_SURROUND:
+ spec->multiout.dac_nids[i] = 0x9;
+ break;
+ case AUTO_SEQ_SIDE:
+ spec->multiout.dac_nids[i] = 0xb;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int vt1718S_auto_create_multi_out_ctls(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ char name[32];
+ static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+ hda_nid_t nid_vols[] = {0x8, 0x9, 0xa, 0xb};
+ hda_nid_t nid_mutes[] = {0x24, 0x25, 0x26, 0x27};
+ hda_nid_t nid, nid_vol, nid_mute = 0;
+ int i, err;
+
+ for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
+ nid = cfg->line_out_pins[i];
+
+ if (!nid)
+ continue;
+ nid_vol = nid_vols[i];
+ nid_mute = nid_mutes[i];
+
+ if (i == AUTO_SEQ_CENLFE) {
+ /* Center/LFE */
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Center Playback Volume",
+ HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
+ HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "LFE Playback Volume",
+ HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
+ HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(
+ spec, VIA_CTL_WIDGET_MUTE,
+ "Center Playback Switch",
+ HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0,
+ HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(
+ spec, VIA_CTL_WIDGET_MUTE,
+ "LFE Playback Switch",
+ HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0,
+ HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ } else if (i == AUTO_SEQ_FRONT) {
+ /* Front */
+ sprintf(name, "%s Playback Volume", chname[i]);
+ err = via_add_control(
+ spec, VIA_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", chname[i]);
+ err = via_add_control(
+ spec, VIA_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
+ HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ } else {
+ sprintf(name, "%s Playback Volume", chname[i]);
+ err = via_add_control(
+ spec, VIA_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", chname[i]);
+ err = via_add_control(
+ spec, VIA_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
+ HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ }
+ }
+ return 0;
+}
+
+static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+ int err;
+
+ if (!pin)
+ return 0;
+
+ spec->multiout.hp_nid = 0xc; /* AOW4 */
+ spec->hp_independent_mode_index = 1;
+
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Headphone Playback Volume",
+ HDA_COMPOSE_AMP_VAL(0xc, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "Headphone Playback Switch",
+ HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+
+ create_hp_imux(spec);
+ return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt1718S_auto_create_analog_input_ctls(struct via_spec *spec,
+ 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 int vt1718S_parse_auto_config(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int err;
+
+ err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+
+ if (err < 0)
+ return err;
+ err = vt1718S_auto_fill_dac_nids(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+ if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+ return 0; /* can't find valid BIOS pin config */
+
+ err = vt1718S_auto_create_multi_out_ctls(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+ 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);
+ if (err < 0)
+ return err;
+
+ spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+ fill_dig_outs(codec);
+
+ if (spec->autocfg.dig_in_pin && codec->vendor_id == 0x11060428)
+ spec->dig_in_nid = 0x13;
+
+ if (spec->kctls.list)
+ spec->mixers[spec->num_mixers++] = spec->kctls.list;
+
+ spec->input_mux = &spec->private_imux[0];
+
+ if (spec->hp_mux)
+ spec->mixers[spec->num_mixers++] = via_hp_mixer;
+
+ spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+
+ return 1;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static struct hda_amp_list vt1718S_loopbacks[] = {
+ { 0x21, HDA_INPUT, 1 },
+ { 0x21, HDA_INPUT, 2 },
+ { 0x21, HDA_INPUT, 3 },
+ { 0x21, HDA_INPUT, 4 },
+ { } /* end */
+};
+#endif
+
+static int patch_vt1718S(struct hda_codec *codec)
+{
+ struct via_spec *spec;
+ int err;
+
+ /* create a codec specific record */
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+
+ /* automatic parse from the BIOS config */
+ err = vt1718S_parse_auto_config(codec);
+ if (err < 0) {
+ via_free(codec);
+ return err;
+ } else if (!err) {
+ printk(KERN_INFO "hda_codec: Cannot set up configuration "
+ "from BIOS. Using genenic mode...\n");
+ }
+
+ spec->init_verbs[spec->num_iverbs++] = vt1718S_volume_init_verbs;
+ spec->init_verbs[spec->num_iverbs++] = vt1718S_uniwill_init_verbs;
+
+ if (codec->vendor_id == 0x11060441)
+ spec->stream_name_analog = "VT2020 Analog";
+ else if (codec->vendor_id == 0x11064441)
+ spec->stream_name_analog = "VT1828S Analog";
+ else
+ spec->stream_name_analog = "VT1718S Analog";
+ spec->stream_analog_playback = &vt1718S_pcm_analog_playback;
+ spec->stream_analog_capture = &vt1718S_pcm_analog_capture;
+
+ if (codec->vendor_id == 0x11060441)
+ spec->stream_name_digital = "VT2020 Digital";
+ else if (codec->vendor_id == 0x11064441)
+ spec->stream_name_digital = "VT1828S Digital";
+ else
+ spec->stream_name_digital = "VT1718S Digital";
+ spec->stream_digital_playback = &vt1718S_pcm_digital_playback;
+ if (codec->vendor_id == 0x11060428 || codec->vendor_id == 0x11060441)
+ spec->stream_digital_capture = &vt1718S_pcm_digital_capture;
+
+ if (!spec->adc_nids && spec->input_mux) {
+ spec->adc_nids = vt1718S_adc_nids;
+ spec->num_adc_nids = ARRAY_SIZE(vt1718S_adc_nids);
+ get_mux_nids(codec);
+ override_mic_boost(codec, 0x2b, 0, 3, 40);
+ override_mic_boost(codec, 0x29, 0, 3, 40);
+ spec->mixers[spec->num_mixers] = vt1718S_capture_mixer;
+ spec->num_mixers++;
+ }
+
+ codec->patch_ops = via_patch_ops;
+
+ codec->patch_ops.init = via_auto_init;
+ codec->patch_ops.unsol_event = via_unsol_event;
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+ spec->loopback.amplist = vt1718S_loopbacks;
+#endif
+
+ return 0;
+}
+
+/* Patch for VT1716S */
+
+static int vt1716s_dmic_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int vt1716s_dmic_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ int index = 0;
+
+ index = snd_hda_codec_read(codec, 0x26, 0,
+ AC_VERB_GET_CONNECT_SEL, 0);
+ if (index != -1)
+ *ucontrol->value.integer.value = index;
+
+ return 0;
+}
+
+static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct via_spec *spec = codec->spec;
+ int index = *ucontrol->value.integer.value;
+
+ snd_hda_codec_write(codec, 0x26, 0,
+ AC_VERB_SET_CONNECT_SEL, index);
+ spec->dmic_enabled = index;
+ set_jack_power_state(codec);
+
+ return 1;
+}
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt1716S_capture_mixer[] = {
+ HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0,
+ HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Input Source",
+ .count = 1,
+ .info = via_mux_enum_info,
+ .get = via_mux_enum_get,
+ .put = via_mux_enum_put,
+ },
+ { } /* end */
+};
+
+static struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
+ HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Digital Mic Capture Switch",
+ .count = 1,
+ .info = vt1716s_dmic_info,
+ .get = vt1716s_dmic_get,
+ .put = vt1716s_dmic_put,
+ },
+ {} /* end */
+};
+
+
+/* mono-out mixer elements */
+static struct snd_kcontrol_new vt1716S_mono_out_mixer[] = {
+ HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT),
+ { } /* end */
+};
+
+static struct hda_verb vt1716S_volume_init_verbs[] = {
+ /*
+ * Unmute ADC0-1 and set the default input to mic-in
+ */
+ {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+ /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+ * mixer widget
+ */
+ /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+ /* MUX Indices: Stereo Mixer = 5 */
+ {0x17, AC_VERB_SET_CONNECT_SEL, 0x5},
+
+ /* Setup default input of PW4 to MW0 */
+ {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
+
+ /* Setup default input of SW1 as MW0 */
+ {0x18, AC_VERB_SET_CONNECT_SEL, 0x1},
+
+ /* Setup default input of SW4 as AOW0 */
+ {0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
+
+ /* PW9 PW10 Output enable */
+ {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+ {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+
+ /* Unmute SW1, PW12 */
+ {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* PW12 Output enable */
+ {0x2a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+ /* Enable Boost Volume backdoor */
+ {0x1, 0xf8a, 0x80},
+ /* don't bybass mixer */
+ {0x1, 0xf88, 0xc0},
+ /* Enable mono output */
+ {0x1, 0xf90, 0x08},
+ { }
+};
+
+
+static struct hda_verb vt1716S_uniwill_init_verbs[] = {
+ {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
+ {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | VIA_MONO_EVENT | VIA_JACK_EVENT},
+ {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ { }
+};
+
+static struct hda_pcm_stream vt1716S_pcm_analog_playback = {
+ .substreams = 2,
+ .channels_min = 2,
+ .channels_max = 6,
+ .nid = 0x10, /* NID to query formats and rates */
+ .ops = {
+ .open = via_playback_pcm_open,
+ .prepare = via_playback_multi_pcm_prepare,
+ .cleanup = via_playback_multi_pcm_cleanup,
+ .close = via_pcm_open_close,
+ },
+};
+
+static struct hda_pcm_stream vt1716S_pcm_analog_capture = {
+ .substreams = 2,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0x13, /* NID to query formats and rates */
+ .ops = {
+ .open = via_pcm_open_close,
+ .prepare = via_capture_pcm_prepare,
+ .cleanup = via_capture_pcm_cleanup,
+ .close = via_pcm_open_close,
+ },
+};
+
+static struct hda_pcm_stream vt1716S_pcm_digital_playback = {
+ .substreams = 2,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in via_build_pcms */
+ .ops = {
+ .open = via_dig_playback_pcm_open,
+ .close = via_dig_playback_pcm_close,
+ .prepare = via_dig_playback_pcm_prepare,
+ .cleanup = via_dig_playback_pcm_cleanup
+ },
+};
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int vt1716S_auto_fill_dac_nids(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{ int i;
+ hda_nid_t nid;
+
+ spec->multiout.num_dacs = cfg->line_outs;
+
+ spec->multiout.dac_nids = spec->private_dac_nids;
+
+ for (i = 0; i < 3; i++) {
+ nid = cfg->line_out_pins[i];
+ if (nid) {
+ /* config dac list */
+ switch (i) {
+ case AUTO_SEQ_FRONT:
+ spec->multiout.dac_nids[i] = 0x10;
+ break;
+ case AUTO_SEQ_CENLFE:
+ spec->multiout.dac_nids[i] = 0x25;
+ break;
+ case AUTO_SEQ_SURROUND:
+ spec->multiout.dac_nids[i] = 0x11;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int vt1716S_auto_create_multi_out_ctls(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ char name[32];
+ static const char *chname[3] = { "Front", "Surround", "C/LFE" };
+ hda_nid_t nid_vols[] = {0x10, 0x11, 0x25};
+ hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x27};
+ hda_nid_t nid, nid_vol, nid_mute;
+ int i, err;
+
+ for (i = 0; i <= AUTO_SEQ_CENLFE; i++) {
+ nid = cfg->line_out_pins[i];
+
+ if (!nid)
+ continue;
+
+ nid_vol = nid_vols[i];
+ nid_mute = nid_mutes[i];
+
+ if (i == AUTO_SEQ_CENLFE) {
+ err = via_add_control(
+ spec, VIA_CTL_WIDGET_VOL,
+ "Center Playback Volume",
+ HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(
+ spec, VIA_CTL_WIDGET_VOL,
+ "LFE Playback Volume",
+ HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(
+ spec, VIA_CTL_WIDGET_MUTE,
+ "Center Playback Switch",
+ HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0,
+ HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(
+ spec, VIA_CTL_WIDGET_MUTE,
+ "LFE Playback Switch",
+ HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0,
+ HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ } else if (i == AUTO_SEQ_FRONT) {
+
+ err = via_add_control(
+ spec, VIA_CTL_WIDGET_VOL,
+ "Master Front Playback Volume",
+ HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(
+ spec, VIA_CTL_WIDGET_MUTE,
+ "Master Front Playback Switch",
+ HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT));
+ if (err < 0)
+ return err;
+
+ sprintf(name, "%s Playback Volume", chname[i]);
+ err = via_add_control(
+ spec, VIA_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", chname[i]);
+ err = via_add_control(
+ spec, VIA_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
+ HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ } else {
+ sprintf(name, "%s Playback Volume", chname[i]);
+ err = via_add_control(
+ spec, VIA_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", chname[i]);
+ err = via_add_control(
+ spec, VIA_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0,
+ HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ }
+ }
+ return 0;
+}
+
+static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+ int err;
+
+ if (!pin)
+ return 0;
+
+ spec->multiout.hp_nid = 0x25; /* AOW3 */
+ spec->hp_independent_mode_index = 1;
+
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Headphone Playback Volume",
+ HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "Headphone Playback Switch",
+ HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+
+ create_hp_imux(spec);
+ return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt1716S_auto_create_analog_input_ctls(struct via_spec *spec,
+ 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 int vt1716S_parse_auto_config(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int err;
+
+ err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+ if (err < 0)
+ return err;
+ err = vt1716S_auto_fill_dac_nids(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+ if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+ return 0; /* can't find valid BIOS pin config */
+
+ err = vt1716S_auto_create_multi_out_ctls(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+ 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);
+ if (err < 0)
+ return err;
+
+ spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+ fill_dig_outs(codec);
+
+ if (spec->kctls.list)
+ spec->mixers[spec->num_mixers++] = spec->kctls.list;
+
+ spec->input_mux = &spec->private_imux[0];
+
+ if (spec->hp_mux)
+ spec->mixers[spec->num_mixers++] = via_hp_mixer;
+
+ spec->mixers[spec->num_mixers++] = via_smart51_mixer;
+
+ return 1;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static struct hda_amp_list vt1716S_loopbacks[] = {
+ { 0x16, HDA_INPUT, 1 },
+ { 0x16, HDA_INPUT, 2 },
+ { 0x16, HDA_INPUT, 3 },
+ { 0x16, HDA_INPUT, 4 },
+ { } /* end */
+};
+#endif
+
+static int patch_vt1716S(struct hda_codec *codec)
+{
+ struct via_spec *spec;
+ int err;
+
+ /* create a codec specific record */
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+
+ /* automatic parse from the BIOS config */
+ err = vt1716S_parse_auto_config(codec);
+ if (err < 0) {
+ via_free(codec);
+ return err;
+ } else if (!err) {
+ printk(KERN_INFO "hda_codec: Cannot set up configuration "
+ "from BIOS. Using genenic mode...\n");
+ }
+
+ spec->init_verbs[spec->num_iverbs++] = vt1716S_volume_init_verbs;
+ spec->init_verbs[spec->num_iverbs++] = vt1716S_uniwill_init_verbs;
+
+ spec->stream_name_analog = "VT1716S Analog";
+ spec->stream_analog_playback = &vt1716S_pcm_analog_playback;
+ spec->stream_analog_capture = &vt1716S_pcm_analog_capture;
+
+ spec->stream_name_digital = "VT1716S Digital";
+ spec->stream_digital_playback = &vt1716S_pcm_digital_playback;
+
+ if (!spec->adc_nids && spec->input_mux) {
+ spec->adc_nids = vt1716S_adc_nids;
+ spec->num_adc_nids = ARRAY_SIZE(vt1716S_adc_nids);
+ get_mux_nids(codec);
+ override_mic_boost(codec, 0x1a, 0, 3, 40);
+ override_mic_boost(codec, 0x1e, 0, 3, 40);
+ spec->mixers[spec->num_mixers] = vt1716S_capture_mixer;
+ spec->num_mixers++;
+ }
+
+ spec->mixers[spec->num_mixers] = vt1716s_dmic_mixer;
+ spec->num_mixers++;
+
+ spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer;
+
+ codec->patch_ops = via_patch_ops;
+
+ codec->patch_ops.init = via_auto_init;
+ codec->patch_ops.unsol_event = via_unsol_event;
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+ spec->loopback.amplist = vt1716S_loopbacks;
+#endif
+
+ return 0;
+}
+
+/* for vt2002P */
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt2002P_capture_mixer[] = {
+ HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0,
+ HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* The multiple "Capture Source" controls confuse alsamixer
+ * So call somewhat different..
+ */
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 2,
+ .info = via_mux_enum_info,
+ .get = via_mux_enum_get,
+ .put = via_mux_enum_put,
+ },
+ { } /* end */
+};
+
+static struct hda_verb vt2002P_volume_init_verbs[] = {
+ /*
+ * Unmute ADC0-1 and set the default input to mic-in
+ */
+ {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+ /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+ * mixer widget
+ */
+ /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+ /* MUX Indices: Mic = 0 */
+ {0x1e, AC_VERB_SET_CONNECT_SEL, 0},
+ {0x1f, AC_VERB_SET_CONNECT_SEL, 0},
+
+ /* PW9 Output enable */
+ {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
+
+ /* Enable Boost Volume backdoor */
+ {0x1, 0xfb9, 0x24},
+
+ /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+ /* set MUX0/1/4/8 = 0 (AOW0) */
+ {0x34, AC_VERB_SET_CONNECT_SEL, 0},
+ {0x35, AC_VERB_SET_CONNECT_SEL, 0},
+ {0x37, AC_VERB_SET_CONNECT_SEL, 0},
+ {0x3b, AC_VERB_SET_CONNECT_SEL, 0},
+
+ /* set PW0 index=0 (MW0) */
+ {0x24, AC_VERB_SET_CONNECT_SEL, 0},
+
+ /* Enable AOW0 to MW9 */
+ {0x1, 0xfb8, 0x88},
+ { }
+};
+
+
+static struct hda_verb vt2002P_uniwill_init_verbs[] = {
+ {0x25, AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
+ {0x26, AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
+ {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ { }
+};
+
+static struct hda_pcm_stream vt2002P_pcm_analog_playback = {
+ .substreams = 2,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0x8, /* NID to query formats and rates */
+ .ops = {
+ .open = via_playback_pcm_open,
+ .prepare = via_playback_multi_pcm_prepare,
+ .cleanup = via_playback_multi_pcm_cleanup,
+ .close = via_pcm_open_close,
+ },
+};
+
+static struct hda_pcm_stream vt2002P_pcm_analog_capture = {
+ .substreams = 2,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0x10, /* NID to query formats and rates */
+ .ops = {
+ .open = via_pcm_open_close,
+ .prepare = via_capture_pcm_prepare,
+ .cleanup = via_capture_pcm_cleanup,
+ .close = via_pcm_open_close,
+ },
+};
+
+static struct hda_pcm_stream vt2002P_pcm_digital_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in via_build_pcms */
+ .ops = {
+ .open = via_dig_playback_pcm_open,
+ .close = via_dig_playback_pcm_close,
+ .prepare = via_dig_playback_pcm_prepare,
+ .cleanup = via_dig_playback_pcm_cleanup
+ },
+};
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int vt2002P_auto_fill_dac_nids(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ spec->multiout.num_dacs = 1;
+ spec->multiout.dac_nids = spec->private_dac_nids;
+ if (cfg->line_out_pins[0])
+ spec->multiout.dac_nids[0] = 0x8;
+ return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ int err;
+
+ if (!cfg->line_out_pins[0])
+ return -1;
+
+
+ /* Line-Out: PortE */
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Master Front Playback Volume",
+ HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
+ "Master Front Playback Switch",
+ HDA_COMPOSE_AMP_VAL(0x26, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int vt2002P_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+ int err;
+
+ if (!pin)
+ return 0;
+
+ spec->multiout.hp_nid = 0x9;
+ spec->hp_independent_mode_index = 1;
+
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Headphone Playback Volume",
+ HDA_COMPOSE_AMP_VAL(
+ spec->multiout.hp_nid, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "Headphone Playback Switch",
+ HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+
+ create_hp_imux(spec);
+ return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt2002P_auto_create_analog_input_ctls(struct via_spec *spec,
+ 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 (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++;
+ }
+
+ /* build volume/mute control of loopback */
+ err = via_new_analog_input(spec, "Stereo Mixer", 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++;
+
+ return 0;
+}
+
+static int vt2002P_parse_auto_config(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int err;
+
+
+ err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+ if (err < 0)
+ return err;
+
+ err = vt2002P_auto_fill_dac_nids(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+
+ if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+ return 0; /* can't find valid BIOS pin config */
+
+ err = vt2002P_auto_create_multi_out_ctls(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+ 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);
+ if (err < 0)
+ return err;
+
+ spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+ fill_dig_outs(codec);
+
+ if (spec->kctls.list)
+ spec->mixers[spec->num_mixers++] = spec->kctls.list;
+
+ spec->input_mux = &spec->private_imux[0];
+
+ if (spec->hp_mux)
+ spec->mixers[spec->num_mixers++] = via_hp_mixer;
+
+ return 1;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static struct hda_amp_list vt2002P_loopbacks[] = {
+ { 0x21, HDA_INPUT, 0 },
+ { 0x21, HDA_INPUT, 1 },
+ { 0x21, HDA_INPUT, 2 },
+ { } /* end */
+};
+#endif
+
+
+/* patch for vt2002P */
+static int patch_vt2002P(struct hda_codec *codec)
+{
+ struct via_spec *spec;
+ int err;
+
+ /* create a codec specific record */
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+
+ /* automatic parse from the BIOS config */
+ err = vt2002P_parse_auto_config(codec);
+ if (err < 0) {
+ via_free(codec);
+ return err;
+ } else if (!err) {
+ printk(KERN_INFO "hda_codec: Cannot set up configuration "
+ "from BIOS. Using genenic mode...\n");
+ }
+
+ spec->init_verbs[spec->num_iverbs++] = vt2002P_volume_init_verbs;
+ spec->init_verbs[spec->num_iverbs++] = vt2002P_uniwill_init_verbs;
+
+ spec->stream_name_analog = "VT2002P Analog";
+ spec->stream_analog_playback = &vt2002P_pcm_analog_playback;
+ spec->stream_analog_capture = &vt2002P_pcm_analog_capture;
+
+ spec->stream_name_digital = "VT2002P Digital";
+ spec->stream_digital_playback = &vt2002P_pcm_digital_playback;
+
+ if (!spec->adc_nids && spec->input_mux) {
+ spec->adc_nids = vt2002P_adc_nids;
+ spec->num_adc_nids = ARRAY_SIZE(vt2002P_adc_nids);
+ get_mux_nids(codec);
+ override_mic_boost(codec, 0x2b, 0, 3, 40);
+ override_mic_boost(codec, 0x29, 0, 3, 40);
+ spec->mixers[spec->num_mixers] = vt2002P_capture_mixer;
+ spec->num_mixers++;
+ }
+
+ codec->patch_ops = via_patch_ops;
+
+ codec->patch_ops.init = via_auto_init;
+ codec->patch_ops.unsol_event = via_unsol_event;
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+ spec->loopback.amplist = vt2002P_loopbacks;
+#endif
+
+ return 0;
+}
+
+/* for vt1812 */
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt1812_capture_mixer[] = {
+ HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Boost Capture Volume", 0x29, 0x0,
+ HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* The multiple "Capture Source" controls confuse alsamixer
+ * So call somewhat different..
+ */
+ .name = "Input Source",
+ .count = 2,
+ .info = via_mux_enum_info,
+ .get = via_mux_enum_get,
+ .put = via_mux_enum_put,
+ },
+ { } /* end */
+};
+
+static struct hda_verb vt1812_volume_init_verbs[] = {
+ /*
+ * Unmute ADC0-1 and set the default input to mic-in
+ */
+ {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+ /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+ * mixer widget
+ */
+ /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+ /* MUX Indices: Mic = 0 */
+ {0x1e, AC_VERB_SET_CONNECT_SEL, 0},
+ {0x1f, AC_VERB_SET_CONNECT_SEL, 0},
+
+ /* PW9 Output enable */
+ {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
+
+ /* Enable Boost Volume backdoor */
+ {0x1, 0xfb9, 0x24},
+
+ /* MW0/1/4/13/15: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+ /* set MUX0/1/4/13/15 = 0 (AOW0) */
+ {0x34, AC_VERB_SET_CONNECT_SEL, 0},
+ {0x35, AC_VERB_SET_CONNECT_SEL, 0},
+ {0x38, AC_VERB_SET_CONNECT_SEL, 0},
+ {0x3c, AC_VERB_SET_CONNECT_SEL, 0},
+ {0x3d, AC_VERB_SET_CONNECT_SEL, 0},
+
+ /* Enable AOW0 to MW9 */
+ {0x1, 0xfb8, 0xa8},
+ { }
+};
+
+
+static struct hda_verb vt1812_uniwill_init_verbs[] = {
+ {0x33, AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
+ {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT },
+ {0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
+ AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
+ {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
+ { }
+};
+
+static struct hda_pcm_stream vt1812_pcm_analog_playback = {
+ .substreams = 2,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0x8, /* NID to query formats and rates */
+ .ops = {
+ .open = via_playback_pcm_open,
+ .prepare = via_playback_multi_pcm_prepare,
+ .cleanup = via_playback_multi_pcm_cleanup,
+ .close = via_pcm_open_close,
+ },
+};
+
+static struct hda_pcm_stream vt1812_pcm_analog_capture = {
+ .substreams = 2,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0x10, /* NID to query formats and rates */
+ .ops = {
+ .open = via_pcm_open_close,
+ .prepare = via_capture_pcm_prepare,
+ .cleanup = via_capture_pcm_cleanup,
+ .close = via_pcm_open_close,
+ },
+};
+
+static struct hda_pcm_stream vt1812_pcm_digital_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in via_build_pcms */
+ .ops = {
+ .open = via_dig_playback_pcm_open,
+ .close = via_dig_playback_pcm_close,
+ .prepare = via_dig_playback_pcm_prepare,
+ .cleanup = via_dig_playback_pcm_cleanup
+ },
+};
+/* fill in the dac_nids table from the parsed pin configuration */
+static int vt1812_auto_fill_dac_nids(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ spec->multiout.num_dacs = 1;
+ spec->multiout.dac_nids = spec->private_dac_nids;
+ if (cfg->line_out_pins[0])
+ spec->multiout.dac_nids[0] = 0x8;
+ return 0;
+}
+
+
+/* add playback controls from the parsed DAC table */
+static int vt1812_auto_create_multi_out_ctls(struct via_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ int err;
+
+ if (!cfg->line_out_pins[0])
+ return -1;
+
+ /* Line-Out: PortE */
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Master Front Playback Volume",
+ HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
+ "Master Front Playback Switch",
+ HDA_COMPOSE_AMP_VAL(0x28, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int vt1812_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+ int err;
+
+ if (!pin)
+ return 0;
+
+ spec->multiout.hp_nid = 0x9;
+ spec->hp_independent_mode_index = 1;
+
+
+ err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+ "Headphone Playback Volume",
+ HDA_COMPOSE_AMP_VAL(
+ spec->multiout.hp_nid, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+
+ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+ "Headphone Playback Switch",
+ HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+
+ create_hp_imux(spec);
+ return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt1812_auto_create_analog_input_ctls(struct via_spec *spec,
+ 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 (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++;
+ }
+ /* build volume/mute control of loopback */
+ err = via_new_analog_input(spec, "Stereo Mixer", 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++;
+
+ return 0;
+}
+
+static int vt1812_parse_auto_config(struct hda_codec *codec)
+{
+ struct via_spec *spec = codec->spec;
+ int err;
+
+
+ err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+ if (err < 0)
+ return err;
+ fill_dig_outs(codec);
+ err = vt1812_auto_fill_dac_nids(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+
+ if (!spec->autocfg.line_outs && !spec->autocfg.hp_outs)
+ return 0; /* can't find valid BIOS pin config */
+
+ err = vt1812_auto_create_multi_out_ctls(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+ 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);
+ if (err < 0)
+ return err;
+
+ spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+ fill_dig_outs(codec);
+
+ if (spec->kctls.list)
+ spec->mixers[spec->num_mixers++] = spec->kctls.list;
+
+ spec->input_mux = &spec->private_imux[0];
+
+ if (spec->hp_mux)
+ spec->mixers[spec->num_mixers++] = via_hp_mixer;
+
+ return 1;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static struct hda_amp_list vt1812_loopbacks[] = {
+ { 0x21, HDA_INPUT, 0 },
+ { 0x21, HDA_INPUT, 1 },
+ { 0x21, HDA_INPUT, 2 },
+ { } /* end */
+};
+#endif
+
+
+/* patch for vt1812 */
+static int patch_vt1812(struct hda_codec *codec)
+{
+ struct via_spec *spec;
+ int err;
+
+ /* create a codec specific record */
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+
+ /* automatic parse from the BIOS config */
+ err = vt1812_parse_auto_config(codec);
+ if (err < 0) {
+ via_free(codec);
+ return err;
+ } else if (!err) {
+ printk(KERN_INFO "hda_codec: Cannot set up configuration "
+ "from BIOS. Using genenic mode...\n");
+ }
+
+
+ spec->init_verbs[spec->num_iverbs++] = vt1812_volume_init_verbs;
+ spec->init_verbs[spec->num_iverbs++] = vt1812_uniwill_init_verbs;
+
+ spec->stream_name_analog = "VT1812 Analog";
+ spec->stream_analog_playback = &vt1812_pcm_analog_playback;
+ spec->stream_analog_capture = &vt1812_pcm_analog_capture;
+
+ spec->stream_name_digital = "VT1812 Digital";
+ spec->stream_digital_playback = &vt1812_pcm_digital_playback;
+
- /* Enable GPIO 0&1 for volume&mute control */
- /* Enable GPIO 2 for DMIC-DATA */
- response = snd_hda_codec_read(codec, codec->afg, 0, 0xF84, 0);
- control = (unsigned char)((response >> 16) & 0x3f);
- snd_hda_codec_write(codec, codec->afg, 0, 0xF82, control);
+ if (!spec->adc_nids && spec->input_mux) {
+ spec->adc_nids = vt1812_adc_nids;
+ spec->num_adc_nids = ARRAY_SIZE(vt1812_adc_nids);
+ get_mux_nids(codec);
+ override_mic_boost(codec, 0x2b, 0, 3, 40);
+ override_mic_boost(codec, 0x29, 0, 3, 40);
+ spec->mixers[spec->num_mixers] = vt1812_capture_mixer;
+ spec->num_mixers++;
+ }
+
+ codec->patch_ops = via_patch_ops;
+
+ codec->patch_ops.init = via_auto_init;
+ codec->patch_ops.unsol_event = via_unsol_event;
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+ spec->loopback.amplist = vt1812_loopbacks;
+#endif
return 0;
}
@@ -3318,6 +6216,21 @@ static struct hda_codec_preset snd_hda_preset_via[] = {
.patch = patch_vt1702},
{ .id = 0x11067398, .name = "VT1702",
.patch = patch_vt1702},
+ { .id = 0x11060428, .name = "VT1718S",
+ .patch = patch_vt1718S},
+ { .id = 0x11064428, .name = "VT1718S",
+ .patch = patch_vt1718S},
+ { .id = 0x11060441, .name = "VT2020",
+ .patch = patch_vt1718S},
+ { .id = 0x11064441, .name = "VT1828S",
+ .patch = patch_vt1718S},
+ { .id = 0x11060433, .name = "VT1716S",
+ .patch = patch_vt1716S},
+ { .id = 0x1106a721, .name = "VT1716S",
+ .patch = patch_vt1716S},
+ { .id = 0x11060438, .name = "VT2002P", .patch = patch_vt2002P},
+ { .id = 0x11064438, .name = "VT2002P", .patch = patch_vt2002P},
+ { .id = 0x11060448, .name = "VT1812", .patch = patch_vt1812},
{} /* terminator */
};
diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile
index 536eae2ccf94..f7ce33f00ea5 100644
--- a/sound/pci/ice1712/Makefile
+++ b/sound/pci/ice1712/Makefile
@@ -5,7 +5,7 @@
snd-ice17xx-ak4xxx-objs := ak4xxx.o
snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o
-snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o maya44.o
+snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o maya44.o quartet.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index d74033a2cfbe..c7cff6f8168a 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -298,6 +298,16 @@ static void snd_ice1712_set_gpio_dir(struct snd_ice1712 *ice, unsigned int data)
inb(ICEREG(ice, DATA)); /* dummy read for pci-posting */
}
+static unsigned int snd_ice1712_get_gpio_dir(struct snd_ice1712 *ice)
+{
+ return snd_ice1712_read(ice, ICE1712_IREG_GPIO_DIRECTION);
+}
+
+static unsigned int snd_ice1712_get_gpio_mask(struct snd_ice1712 *ice)
+{
+ return snd_ice1712_read(ice, ICE1712_IREG_GPIO_WRITE_MASK);
+}
+
static void snd_ice1712_set_gpio_mask(struct snd_ice1712 *ice, unsigned int data)
{
snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, data);
@@ -2557,7 +2567,9 @@ static int __devinit snd_ice1712_create(struct snd_card *card,
mutex_init(&ice->i2c_mutex);
mutex_init(&ice->open_mutex);
ice->gpio.set_mask = snd_ice1712_set_gpio_mask;
+ ice->gpio.get_mask = snd_ice1712_get_gpio_mask;
ice->gpio.set_dir = snd_ice1712_set_gpio_dir;
+ ice->gpio.get_dir = snd_ice1712_get_gpio_dir;
ice->gpio.set_data = snd_ice1712_set_gpio_data;
ice->gpio.get_data = snd_ice1712_get_gpio_data;
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
index 9da2dae64c5b..4615bca39e18 100644
--- a/sound/pci/ice1712/ice1712.h
+++ b/sound/pci/ice1712/ice1712.h
@@ -359,7 +359,9 @@ struct snd_ice1712 {
unsigned int saved[2]; /* for ewx_i2c */
/* operators */
void (*set_mask)(struct snd_ice1712 *ice, unsigned int data);
+ unsigned int (*get_mask)(struct snd_ice1712 *ice);
void (*set_dir)(struct snd_ice1712 *ice, unsigned int data);
+ unsigned int (*get_dir)(struct snd_ice1712 *ice);
void (*set_data)(struct snd_ice1712 *ice, unsigned int data);
unsigned int (*get_data)(struct snd_ice1712 *ice);
/* misc operators - move to another place? */
@@ -377,8 +379,11 @@ struct snd_ice1712 {
unsigned int (*get_rate)(struct snd_ice1712 *ice);
void (*set_rate)(struct snd_ice1712 *ice, unsigned int rate);
unsigned char (*set_mclk)(struct snd_ice1712 *ice, unsigned int rate);
- void (*set_spdif_clock)(struct snd_ice1712 *ice);
-
+ int (*set_spdif_clock)(struct snd_ice1712 *ice, int type);
+ int (*get_spdif_master_type)(struct snd_ice1712 *ice);
+ char **ext_clock_names;
+ int ext_clock_count;
+ void (*pro_open)(struct snd_ice1712 *, struct snd_pcm_substream *);
#ifdef CONFIG_PM
int (*pm_suspend)(struct snd_ice1712 *);
int (*pm_resume)(struct snd_ice1712 *);
@@ -399,6 +404,11 @@ static inline void snd_ice1712_gpio_set_dir(struct snd_ice1712 *ice, unsigned in
ice->gpio.set_dir(ice, bits);
}
+static inline unsigned int snd_ice1712_gpio_get_dir(struct snd_ice1712 *ice)
+{
+ return ice->gpio.get_dir(ice);
+}
+
static inline void snd_ice1712_gpio_set_mask(struct snd_ice1712 *ice, unsigned int bits)
{
ice->gpio.set_mask(ice, bits);
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 10fc92c05574..ae29073eea93 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -53,6 +53,7 @@
#include "phase.h"
#include "wtm.h"
#include "se.h"
+#include "quartet.h"
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)");
@@ -70,6 +71,7 @@ MODULE_SUPPORTED_DEVICE("{"
PHASE_DEVICE_DESC
WTM_DEVICE_DESC
SE_DEVICE_DESC
+ QTET_DEVICE_DESC
"{VIA,VT1720},"
"{VIA,VT1724},"
"{ICEnsemble,Generic ICE1724},"
@@ -104,6 +106,8 @@ static int PRO_RATE_LOCKED;
static int PRO_RATE_RESET = 1;
static unsigned int PRO_RATE_DEFAULT = 44100;
+static char *ext_clock_names[1] = { "IEC958 In" };
+
/*
* Basic I/O
*/
@@ -118,9 +122,12 @@ static inline int stdclock_is_spdif_master(struct snd_ice1712 *ice)
return (inb(ICEMT1724(ice, RATE)) & VT1724_SPDIF_MASTER) ? 1 : 0;
}
+/*
+ * locking rate makes sense only for internal clock mode
+ */
static inline int is_pro_rate_locked(struct snd_ice1712 *ice)
{
- return ice->is_spdif_master(ice) || PRO_RATE_LOCKED;
+ return (!ice->is_spdif_master(ice)) && PRO_RATE_LOCKED;
}
/*
@@ -196,6 +203,12 @@ static void snd_vt1724_set_gpio_dir(struct snd_ice1712 *ice, unsigned int data)
inw(ICEREG1724(ice, GPIO_DIRECTION)); /* dummy read for pci-posting */
}
+/* get gpio direction 0 = read, 1 = write */
+static unsigned int snd_vt1724_get_gpio_dir(struct snd_ice1712 *ice)
+{
+ return inl(ICEREG1724(ice, GPIO_DIRECTION));
+}
+
/* set the gpio mask (0 = writable) */
static void snd_vt1724_set_gpio_mask(struct snd_ice1712 *ice, unsigned int data)
{
@@ -205,6 +218,17 @@ static void snd_vt1724_set_gpio_mask(struct snd_ice1712 *ice, unsigned int data)
inw(ICEREG1724(ice, GPIO_WRITE_MASK)); /* dummy read for pci-posting */
}
+static unsigned int snd_vt1724_get_gpio_mask(struct snd_ice1712 *ice)
+{
+ unsigned int mask;
+ if (!ice->vt1720)
+ mask = (unsigned int)inb(ICEREG1724(ice, GPIO_WRITE_MASK_22));
+ else
+ mask = 0;
+ mask = (mask << 16) | inw(ICEREG1724(ice, GPIO_WRITE_MASK));
+ return mask;
+}
+
static void snd_vt1724_set_gpio_data(struct snd_ice1712 *ice, unsigned int data)
{
outw(data, ICEREG1724(ice, GPIO_DATA));
@@ -651,16 +675,22 @@ static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
return ((rate == ice->cur_rate) && !force) ? 0 : -EBUSY;
}
if (!force && is_pro_rate_locked(ice)) {
+ /* comparing required and current rate - makes sense for
+ * internal clock only */
spin_unlock_irqrestore(&ice->reg_lock, flags);
return (rate == ice->cur_rate) ? 0 : -EBUSY;
}
- old_rate = ice->get_rate(ice);
- if (force || (old_rate != rate))
- ice->set_rate(ice, rate);
- else if (rate == ice->cur_rate) {
- spin_unlock_irqrestore(&ice->reg_lock, flags);
- return 0;
+ if (force || !ice->is_spdif_master(ice)) {
+ /* force means the rate was switched by ucontrol, otherwise
+ * setting clock rate for internal clock mode */
+ old_rate = ice->get_rate(ice);
+ if (force || (old_rate != rate))
+ ice->set_rate(ice, rate);
+ else if (rate == ice->cur_rate) {
+ spin_unlock_irqrestore(&ice->reg_lock, flags);
+ return 0;
+ }
}
ice->cur_rate = rate;
@@ -1016,6 +1046,8 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream)
VT1724_BUFFER_ALIGN);
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
VT1724_BUFFER_ALIGN);
+ if (ice->pro_open)
+ ice->pro_open(ice, substream);
return 0;
}
@@ -1034,6 +1066,8 @@ static int snd_vt1724_capture_pro_open(struct snd_pcm_substream *substream)
VT1724_BUFFER_ALIGN);
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
VT1724_BUFFER_ALIGN);
+ if (ice->pro_open)
+ ice->pro_open(ice, substream);
return 0;
}
@@ -1787,15 +1821,21 @@ static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-
+ int hw_rates_count = ice->hw_rates->count;
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
- uinfo->value.enumerated.items = ice->hw_rates->count + 1;
+
+ uinfo->value.enumerated.items = hw_rates_count + ice->ext_clock_count;
+ /* upper limit - keep at top */
if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- if (uinfo->value.enumerated.item == uinfo->value.enumerated.items - 1)
- strcpy(uinfo->value.enumerated.name, "IEC958 Input");
+ if (uinfo->value.enumerated.item >= hw_rates_count)
+ /* ext_clock items */
+ strcpy(uinfo->value.enumerated.name,
+ ice->ext_clock_names[
+ uinfo->value.enumerated.item - hw_rates_count]);
else
+ /* int clock items */
sprintf(uinfo->value.enumerated.name, "%d",
ice->hw_rates->list[uinfo->value.enumerated.item]);
return 0;
@@ -1809,7 +1849,8 @@ static int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
spin_lock_irq(&ice->reg_lock);
if (ice->is_spdif_master(ice)) {
- ucontrol->value.enumerated.item[0] = ice->hw_rates->count;
+ ucontrol->value.enumerated.item[0] = ice->hw_rates->count +
+ ice->get_spdif_master_type(ice);
} else {
rate = ice->get_rate(ice);
ucontrol->value.enumerated.item[0] = 0;
@@ -1824,8 +1865,14 @@ static int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
return 0;
}
+static int stdclock_get_spdif_master_type(struct snd_ice1712 *ice)
+{
+ /* standard external clock - only single type - SPDIF IN */
+ return 0;
+}
+
/* setting clock to external - SPDIF */
-static void stdclock_set_spdif_clock(struct snd_ice1712 *ice)
+static int stdclock_set_spdif_clock(struct snd_ice1712 *ice, int type)
{
unsigned char oval;
unsigned char i2s_oval;
@@ -1834,27 +1881,30 @@ static void stdclock_set_spdif_clock(struct snd_ice1712 *ice)
/* setting 256fs */
i2s_oval = inb(ICEMT1724(ice, I2S_FORMAT));
outb(i2s_oval & ~VT1724_MT_I2S_MCLK_128X, ICEMT1724(ice, I2S_FORMAT));
+ return 0;
}
+
static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
unsigned int old_rate, new_rate;
unsigned int item = ucontrol->value.enumerated.item[0];
- unsigned int spdif = ice->hw_rates->count;
+ unsigned int first_ext_clock = ice->hw_rates->count;
- if (item > spdif)
+ if (item > first_ext_clock + ice->ext_clock_count - 1)
return -EINVAL;
+ /* if rate = 0 => external clock */
spin_lock_irq(&ice->reg_lock);
if (ice->is_spdif_master(ice))
old_rate = 0;
else
old_rate = ice->get_rate(ice);
- if (item == spdif) {
- /* switching to external clock via SPDIF */
- ice->set_spdif_clock(ice);
+ if (item >= first_ext_clock) {
+ /* switching to external clock */
+ ice->set_spdif_clock(ice, item - first_ext_clock);
new_rate = 0;
} else {
/* internal on-card clock */
@@ -1866,7 +1916,7 @@ static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
}
spin_unlock_irq(&ice->reg_lock);
- /* the first reset to the SPDIF master mode? */
+ /* the first switch to the ext. clock mode? */
if (old_rate != new_rate && !new_rate) {
/* notify akm chips as well */
unsigned int i;
@@ -2136,6 +2186,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
snd_vt1724_phase_cards,
snd_vt1724_wtm_cards,
snd_vt1724_se_cards,
+ snd_vt1724_qtet_cards,
NULL,
};
@@ -2434,7 +2485,9 @@ static int __devinit snd_vt1724_create(struct snd_card *card,
mutex_init(&ice->open_mutex);
mutex_init(&ice->i2c_mutex);
ice->gpio.set_mask = snd_vt1724_set_gpio_mask;
+ ice->gpio.get_mask = snd_vt1724_get_gpio_mask;
ice->gpio.set_dir = snd_vt1724_set_gpio_dir;
+ ice->gpio.get_dir = snd_vt1724_get_gpio_dir;
ice->gpio.set_data = snd_vt1724_set_gpio_data;
ice->gpio.get_data = snd_vt1724_get_gpio_data;
ice->card = card;
@@ -2522,6 +2575,9 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci,
return err;
}
+ /* field init before calling chip_init */
+ ice->ext_clock_count = 0;
+
for (tbl = card_tables; *tbl; tbl++) {
for (c = *tbl; c->subvendor; c++) {
if (c->subvendor == ice->eeprom.subvendor) {
@@ -2560,6 +2616,13 @@ __found:
ice->set_mclk = stdclock_set_mclk;
if (!ice->set_spdif_clock)
ice->set_spdif_clock = stdclock_set_spdif_clock;
+ if (!ice->get_spdif_master_type)
+ ice->get_spdif_master_type = stdclock_get_spdif_master_type;
+ if (!ice->ext_clock_names)
+ ice->ext_clock_names = ext_clock_names;
+ if (!ice->ext_clock_count)
+ ice->ext_clock_count = ARRAY_SIZE(ext_clock_names);
+
if (!ice->hw_rates)
set_std_hw_rates(ice);
@@ -2719,7 +2782,7 @@ static int snd_vt1724_resume(struct pci_dev *pci)
if (ice->pm_saved_is_spdif_master) {
/* switching to external clock via SPDIF */
- ice->set_spdif_clock(ice);
+ ice->set_spdif_clock(ice, 0);
} else {
/* internal on-card clock */
snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1);
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c
index fd948bfd9aef..b82d4ef228d9 100644
--- a/sound/pci/ice1712/juli.c
+++ b/sound/pci/ice1712/juli.c
@@ -380,7 +380,7 @@ static struct snd_kcontrol_new juli_mute_controls[] __devinitdata = {
* inputs) are fed from Xilinx.
*
* I even checked traces on board and coded a support in driver for
- * an alternative possiblity - the unused I2S ICE output channels
+ * an alternative possibility - the unused I2S ICE output channels
* switched to HW-IN/SPDIF-IN and providing the monitoring signal to
* the DAC - to no avail. The I2S outputs seem to be unconnected.
*
@@ -412,25 +412,6 @@ static struct snd_kcontrol_new juli_mute_controls[] __devinitdata = {
},
};
-
-static void ak4358_proc_regs_read(struct snd_info_entry *entry,
- struct snd_info_buffer *buffer)
-{
- struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
- int reg, val;
- for (reg = 0; reg <= 0xf; reg++) {
- val = snd_akm4xxx_get(ice->akm, 0, reg);
- snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val);
- }
-}
-
-static void ak4358_proc_init(struct snd_ice1712 *ice)
-{
- struct snd_info_entry *entry;
- if (!snd_card_proc_new(ice->card, "ak4358_codec", &entry))
- snd_info_set_text_ops(entry, ice, ak4358_proc_regs_read);
-}
-
static char *slave_vols[] __devinitdata = {
PCM_VOLUME,
MONITOR_AN_IN_VOLUME,
@@ -496,8 +477,6 @@ static int __devinit juli_add_controls(struct snd_ice1712 *ice)
/* only capture SPDIF over AK4114 */
err = snd_ak4114_build(spec->ak4114, NULL,
ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
-
- ak4358_proc_init(ice);
if (err < 0)
return err;
return 0;
@@ -550,13 +529,14 @@ static inline unsigned char juli_set_mclk(struct snd_ice1712 *ice,
}
/* setting clock to external - SPDIF */
-static void juli_set_spdif_clock(struct snd_ice1712 *ice)
+static int juli_set_spdif_clock(struct snd_ice1712 *ice, int type)
{
unsigned int old;
old = ice->gpio.get_data(ice);
/* external clock (= 0), multiply 1x, 48kHz */
ice->gpio.set_data(ice, (old & ~GPIO_RATE_MASK) | GPIO_MULTI_1X |
GPIO_FREQ_48KHZ);
+ return 0;
}
/* Called when ak4114 detects change in the input SPDIF stream */
diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c
new file mode 100644
index 000000000000..1948632787e6
--- /dev/null
+++ b/sound/pci/ice1712/quartet.c
@@ -0,0 +1,1130 @@
+/*
+ * ALSA driver for ICEnsemble VT1724 (Envy24HT)
+ *
+ * Lowlevel functions for Infrasonic Quartet
+ *
+ * Copyright (c) 2009 Pavel Hofman <pavel.hofman@ivitera.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 <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/tlv.h>
+#include <sound/info.h>
+
+#include "ice1712.h"
+#include "envy24ht.h"
+#include <sound/ak4113.h>
+#include "quartet.h"
+
+struct qtet_spec {
+ struct ak4113 *ak4113;
+ unsigned int scr; /* system control register */
+ unsigned int mcr; /* monitoring control register */
+ unsigned int cpld; /* cpld register */
+};
+
+struct qtet_kcontrol_private {
+ unsigned int bit;
+ void (*set_register)(struct snd_ice1712 *ice, unsigned int val);
+ unsigned int (*get_register)(struct snd_ice1712 *ice);
+ unsigned char *texts[2];
+};
+
+enum {
+ IN12_SEL = 0,
+ IN34_SEL,
+ AIN34_SEL,
+ COAX_OUT,
+ IN12_MON12,
+ IN12_MON34,
+ IN34_MON12,
+ IN34_MON34,
+ OUT12_MON34,
+ OUT34_MON12,
+};
+
+static char *ext_clock_names[3] = {"IEC958 In", "Word Clock 1xFS",
+ "Word Clock 256xFS"};
+
+/* chip address on I2C bus */
+#define AK4113_ADDR 0x26 /* S/PDIF receiver */
+
+/* chip address on SPI bus */
+#define AK4620_ADDR 0x02 /* ADC/DAC */
+
+
+/*
+ * GPIO pins
+ */
+
+/* GPIO0 - O - DATA0, def. 0 */
+#define GPIO_D0 (1<<0)
+/* GPIO1 - I/O - DATA1, Jack Detect Input0 (0:present, 1:missing), def. 1 */
+#define GPIO_D1_JACKDTC0 (1<<1)
+/* GPIO2 - I/O - DATA2, Jack Detect Input1 (0:present, 1:missing), def. 1 */
+#define GPIO_D2_JACKDTC1 (1<<2)
+/* GPIO3 - I/O - DATA3, def. 1 */
+#define GPIO_D3 (1<<3)
+/* GPIO4 - I/O - DATA4, SPI CDTO, def. 1 */
+#define GPIO_D4_SPI_CDTO (1<<4)
+/* GPIO5 - I/O - DATA5, SPI CCLK, def. 1 */
+#define GPIO_D5_SPI_CCLK (1<<5)
+/* GPIO6 - I/O - DATA6, Cable Detect Input (0:detected, 1:not detected */
+#define GPIO_D6_CD (1<<6)
+/* GPIO7 - I/O - DATA7, Device Detect Input (0:detected, 1:not detected */
+#define GPIO_D7_DD (1<<7)
+/* GPIO8 - O - CPLD Chip Select, def. 1 */
+#define GPIO_CPLD_CSN (1<<8)
+/* GPIO9 - O - CPLD register read/write (0:write, 1:read), def. 0 */
+#define GPIO_CPLD_RW (1<<9)
+/* GPIO10 - O - SPI Chip Select for CODEC#0, def. 1 */
+#define GPIO_SPI_CSN0 (1<<10)
+/* GPIO11 - O - SPI Chip Select for CODEC#1, def. 1 */
+#define GPIO_SPI_CSN1 (1<<11)
+/* GPIO12 - O - Ex. Register Output Enable (0:enable, 1:disable), def. 1,
+ * init 0 */
+#define GPIO_EX_GPIOE (1<<12)
+/* GPIO13 - O - Ex. Register0 Chip Select for System Control Register,
+ * def. 1 */
+#define GPIO_SCR (1<<13)
+/* GPIO14 - O - Ex. Register1 Chip Select for Monitor Control Register,
+ * def. 1 */
+#define GPIO_MCR (1<<14)
+
+#define GPIO_SPI_ALL (GPIO_D4_SPI_CDTO | GPIO_D5_SPI_CCLK |\
+ GPIO_SPI_CSN0 | GPIO_SPI_CSN1)
+
+#define GPIO_DATA_MASK (GPIO_D0 | GPIO_D1_JACKDTC0 | \
+ GPIO_D2_JACKDTC1 | GPIO_D3 | \
+ GPIO_D4_SPI_CDTO | GPIO_D5_SPI_CCLK | \
+ GPIO_D6_CD | GPIO_D7_DD)
+
+/* System Control Register GPIO_SCR data bits */
+/* Mic/Line select relay (0:line, 1:mic) */
+#define SCR_RELAY GPIO_D0
+/* Phantom power drive control (0:5V, 1:48V) */
+#define SCR_PHP_V GPIO_D1_JACKDTC0
+/* H/W mute control (0:Normal, 1:Mute) */
+#define SCR_MUTE GPIO_D2_JACKDTC1
+/* Phantom power control (0:Phantom on, 1:off) */
+#define SCR_PHP GPIO_D3
+/* Analog input 1/2 Source Select */
+#define SCR_AIN12_SEL0 GPIO_D4_SPI_CDTO
+#define SCR_AIN12_SEL1 GPIO_D5_SPI_CCLK
+/* Analog input 3/4 Source Select (0:line, 1:hi-z) */
+#define SCR_AIN34_SEL GPIO_D6_CD
+/* Codec Power Down (0:power down, 1:normal) */
+#define SCR_CODEC_PDN GPIO_D7_DD
+
+#define SCR_AIN12_LINE (0)
+#define SCR_AIN12_MIC (SCR_AIN12_SEL0)
+#define SCR_AIN12_LOWCUT (SCR_AIN12_SEL1 | SCR_AIN12_SEL0)
+
+/* Monitor Control Register GPIO_MCR data bits */
+/* Input 1/2 to Monitor 1/2 (0:off, 1:on) */
+#define MCR_IN12_MON12 GPIO_D0
+/* Input 1/2 to Monitor 3/4 (0:off, 1:on) */
+#define MCR_IN12_MON34 GPIO_D1_JACKDTC0
+/* Input 3/4 to Monitor 1/2 (0:off, 1:on) */
+#define MCR_IN34_MON12 GPIO_D2_JACKDTC1
+/* Input 3/4 to Monitor 3/4 (0:off, 1:on) */
+#define MCR_IN34_MON34 GPIO_D3
+/* Output to Monitor 1/2 (0:off, 1:on) */
+#define MCR_OUT34_MON12 GPIO_D4_SPI_CDTO
+/* Output to Monitor 3/4 (0:off, 1:on) */
+#define MCR_OUT12_MON34 GPIO_D5_SPI_CCLK
+
+/* CPLD Register DATA bits */
+/* Clock Rate Select */
+#define CPLD_CKS0 GPIO_D0
+#define CPLD_CKS1 GPIO_D1_JACKDTC0
+#define CPLD_CKS2 GPIO_D2_JACKDTC1
+/* Sync Source Select (0:Internal, 1:External) */
+#define CPLD_SYNC_SEL GPIO_D3
+/* Word Clock FS Select (0:FS, 1:256FS) */
+#define CPLD_WORD_SEL GPIO_D4_SPI_CDTO
+/* Coaxial Output Source (IS-Link) (0:SPDIF, 1:I2S) */
+#define CPLD_COAX_OUT GPIO_D5_SPI_CCLK
+/* Input 1/2 Source Select (0:Analog12, 1:An34) */
+#define CPLD_IN12_SEL GPIO_D6_CD
+/* Input 3/4 Source Select (0:Analog34, 1:Digital In) */
+#define CPLD_IN34_SEL GPIO_D7_DD
+
+/* internal clock (CPLD_SYNC_SEL = 0) options */
+#define CPLD_CKS_44100HZ (0)
+#define CPLD_CKS_48000HZ (CPLD_CKS0)
+#define CPLD_CKS_88200HZ (CPLD_CKS1)
+#define CPLD_CKS_96000HZ (CPLD_CKS1 | CPLD_CKS0)
+#define CPLD_CKS_176400HZ (CPLD_CKS2)
+#define CPLD_CKS_192000HZ (CPLD_CKS2 | CPLD_CKS0)
+
+#define CPLD_CKS_MASK (CPLD_CKS0 | CPLD_CKS1 | CPLD_CKS2)
+
+/* external clock (CPLD_SYNC_SEL = 1) options */
+/* external clock - SPDIF */
+#define CPLD_EXT_SPDIF (0 | CPLD_SYNC_SEL)
+/* external clock - WordClock 1xfs */
+#define CPLD_EXT_WORDCLOCK_1FS (CPLD_CKS1 | CPLD_SYNC_SEL)
+/* external clock - WordClock 256xfs */
+#define CPLD_EXT_WORDCLOCK_256FS (CPLD_CKS1 | CPLD_WORD_SEL |\
+ CPLD_SYNC_SEL)
+
+#define EXT_SPDIF_TYPE 0
+#define EXT_WORDCLOCK_1FS_TYPE 1
+#define EXT_WORDCLOCK_256FS_TYPE 2
+
+#define AK4620_DFS0 (1<<0)
+#define AK4620_DFS1 (1<<1)
+#define AK4620_CKS0 (1<<2)
+#define AK4620_CKS1 (1<<3)
+/* Clock and Format Control register */
+#define AK4620_DFS_REG 0x02
+
+/* Deem and Volume Control register */
+#define AK4620_DEEMVOL_REG 0x03
+#define AK4620_SMUTE (1<<7)
+
+/*
+ * Conversion from int value to its binary form. Used for debugging.
+ * The output buffer must be allocated prior to calling the function.
+ */
+static char *get_binary(char *buffer, int value)
+{
+ int i, j, pos;
+ pos = 0;
+ for (i = 0; i < 4; ++i) {
+ for (j = 0; j < 8; ++j) {
+ if (value & (1 << (31-(i*8 + j))))
+ buffer[pos] = '1';
+ else
+ buffer[pos] = '0';
+ pos++;
+ }
+ if (i < 3) {
+ buffer[pos] = ' ';
+ pos++;
+ }
+ }
+ buffer[pos] = '\0';
+ return buffer;
+}
+
+/*
+ * Initial setup of the conversion array GPIO <-> rate
+ */
+static unsigned int qtet_rates[] = {
+ 44100, 48000, 88200,
+ 96000, 176400, 192000,
+};
+
+static unsigned int cks_vals[] = {
+ CPLD_CKS_44100HZ, CPLD_CKS_48000HZ, CPLD_CKS_88200HZ,
+ CPLD_CKS_96000HZ, CPLD_CKS_176400HZ, CPLD_CKS_192000HZ,
+};
+
+static struct snd_pcm_hw_constraint_list qtet_rates_info = {
+ .count = ARRAY_SIZE(qtet_rates),
+ .list = qtet_rates,
+ .mask = 0,
+};
+
+static void qtet_ak4113_write(void *private_data, unsigned char reg,
+ unsigned char val)
+{
+ snd_vt1724_write_i2c((struct snd_ice1712 *)private_data, AK4113_ADDR,
+ reg, val);
+}
+
+static unsigned char qtet_ak4113_read(void *private_data, unsigned char reg)
+{
+ return snd_vt1724_read_i2c((struct snd_ice1712 *)private_data,
+ AK4113_ADDR, reg);
+}
+
+
+/*
+ * AK4620 section
+ */
+
+/*
+ * Write data to addr register of ak4620
+ */
+static void qtet_akm_write(struct snd_akm4xxx *ak, int chip,
+ unsigned char addr, unsigned char data)
+{
+ unsigned int tmp, orig_dir;
+ int idx;
+ unsigned int addrdata;
+ struct snd_ice1712 *ice = ak->private_data[0];
+
+ if (snd_BUG_ON(chip < 0 || chip >= 4))
+ return;
+ /*printk(KERN_DEBUG "Writing to AK4620: chip=%d, addr=0x%x,
+ data=0x%x\n", chip, addr, data);*/
+ orig_dir = ice->gpio.get_dir(ice);
+ ice->gpio.set_dir(ice, orig_dir | GPIO_SPI_ALL);
+ /* set mask - only SPI bits */
+ ice->gpio.set_mask(ice, ~GPIO_SPI_ALL);
+
+ tmp = ice->gpio.get_data(ice);
+ /* high all */
+ tmp |= GPIO_SPI_ALL;
+ ice->gpio.set_data(ice, tmp);
+ udelay(100);
+ /* drop chip select */
+ if (chip)
+ /* CODEC 1 */
+ tmp &= ~GPIO_SPI_CSN1;
+ else
+ tmp &= ~GPIO_SPI_CSN0;
+ ice->gpio.set_data(ice, tmp);
+ udelay(100);
+
+ /* build I2C address + data byte */
+ addrdata = (AK4620_ADDR << 6) | 0x20 | (addr & 0x1f);
+ addrdata = (addrdata << 8) | data;
+ for (idx = 15; idx >= 0; idx--) {
+ /* drop clock */
+ tmp &= ~GPIO_D5_SPI_CCLK;
+ ice->gpio.set_data(ice, tmp);
+ udelay(100);
+ /* set data */
+ if (addrdata & (1 << idx))
+ tmp |= GPIO_D4_SPI_CDTO;
+ else
+ tmp &= ~GPIO_D4_SPI_CDTO;
+ ice->gpio.set_data(ice, tmp);
+ udelay(100);
+ /* raise clock */
+ tmp |= GPIO_D5_SPI_CCLK;
+ ice->gpio.set_data(ice, tmp);
+ udelay(100);
+ }
+ /* all back to 1 */
+ tmp |= GPIO_SPI_ALL;
+ ice->gpio.set_data(ice, tmp);
+ udelay(100);
+
+ /* return all gpios to non-writable */
+ ice->gpio.set_mask(ice, 0xffffff);
+ /* restore GPIOs direction */
+ ice->gpio.set_dir(ice, orig_dir);
+}
+
+static void qtet_akm_set_regs(struct snd_akm4xxx *ak, unsigned char addr,
+ unsigned char mask, unsigned char value)
+{
+ unsigned char tmp;
+ int chip;
+ for (chip = 0; chip < ak->num_chips; chip++) {
+ tmp = snd_akm4xxx_get(ak, chip, addr);
+ /* clear the bits */
+ tmp &= ~mask;
+ /* set the new bits */
+ tmp |= value;
+ snd_akm4xxx_write(ak, chip, addr, tmp);
+ }
+}
+
+/*
+ * change the rate of AK4620
+ */
+static void qtet_akm_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
+{
+ unsigned char ak4620_dfs;
+
+ if (rate == 0) /* no hint - S/PDIF input is master or the new spdif
+ input rate undetected, simply return */
+ return;
+
+ /* adjust DFS on codecs - see datasheet */
+ if (rate > 108000)
+ ak4620_dfs = AK4620_DFS1 | AK4620_CKS1;
+ else if (rate > 54000)
+ ak4620_dfs = AK4620_DFS0 | AK4620_CKS0;
+ else
+ ak4620_dfs = 0;
+
+ /* set new value */
+ qtet_akm_set_regs(ak, AK4620_DFS_REG, AK4620_DFS0 | AK4620_DFS1 |
+ AK4620_CKS0 | AK4620_CKS1, ak4620_dfs);
+}
+
+#define AK_CONTROL(xname, xch) { .name = xname, .num_channels = xch }
+
+#define PCM_12_PLAYBACK_VOLUME "PCM 1/2 Playback Volume"
+#define PCM_34_PLAYBACK_VOLUME "PCM 3/4 Playback Volume"
+#define PCM_12_CAPTURE_VOLUME "PCM 1/2 Capture Volume"
+#define PCM_34_CAPTURE_VOLUME "PCM 3/4 Capture Volume"
+
+static const struct snd_akm4xxx_dac_channel qtet_dac[] = {
+ AK_CONTROL(PCM_12_PLAYBACK_VOLUME, 2),
+ AK_CONTROL(PCM_34_PLAYBACK_VOLUME, 2),
+};
+
+static const struct snd_akm4xxx_adc_channel qtet_adc[] = {
+ AK_CONTROL(PCM_12_CAPTURE_VOLUME, 2),
+ AK_CONTROL(PCM_34_CAPTURE_VOLUME, 2),
+};
+
+static struct snd_akm4xxx akm_qtet_dac __devinitdata = {
+ .type = SND_AK4620,
+ .num_dacs = 4, /* DAC1 - Output 12
+ */
+ .num_adcs = 4, /* ADC1 - Input 12
+ */
+ .ops = {
+ .write = qtet_akm_write,
+ .set_rate_val = qtet_akm_set_rate_val,
+ },
+ .dac_info = qtet_dac,
+ .adc_info = qtet_adc,
+};
+
+/* Communication routines with the CPLD */
+
+
+/* Writes data to external register reg, both reg and data are
+ * GPIO representations */
+static void reg_write(struct snd_ice1712 *ice, unsigned int reg,
+ unsigned int data)
+{
+ unsigned int tmp;
+
+ mutex_lock(&ice->gpio_mutex);
+ /* set direction of used GPIOs*/
+ /* all outputs */
+ tmp = 0x00ffff;
+ ice->gpio.set_dir(ice, tmp);
+ /* mask - writable bits */
+ ice->gpio.set_mask(ice, ~(tmp));
+ /* write the data */
+ tmp = ice->gpio.get_data(ice);
+ tmp &= ~GPIO_DATA_MASK;
+ tmp |= data;
+ ice->gpio.set_data(ice, tmp);
+ udelay(100);
+ /* drop output enable */
+ tmp &= ~GPIO_EX_GPIOE;
+ ice->gpio.set_data(ice, tmp);
+ udelay(100);
+ /* drop the register gpio */
+ tmp &= ~reg;
+ ice->gpio.set_data(ice, tmp);
+ udelay(100);
+ /* raise the register GPIO */
+ tmp |= reg;
+ ice->gpio.set_data(ice, tmp);
+ udelay(100);
+
+ /* raise all data gpios */
+ tmp |= GPIO_DATA_MASK;
+ ice->gpio.set_data(ice, tmp);
+ /* mask - immutable bits */
+ ice->gpio.set_mask(ice, 0xffffff);
+ /* outputs only 8-15 */
+ ice->gpio.set_dir(ice, 0x00ff00);
+ mutex_unlock(&ice->gpio_mutex);
+}
+
+static unsigned int get_scr(struct snd_ice1712 *ice)
+{
+ struct qtet_spec *spec = ice->spec;
+ return spec->scr;
+}
+
+static unsigned int get_mcr(struct snd_ice1712 *ice)
+{
+ struct qtet_spec *spec = ice->spec;
+ return spec->mcr;
+}
+
+static unsigned int get_cpld(struct snd_ice1712 *ice)
+{
+ struct qtet_spec *spec = ice->spec;
+ return spec->cpld;
+}
+
+static void set_scr(struct snd_ice1712 *ice, unsigned int val)
+{
+ struct qtet_spec *spec = ice->spec;
+ reg_write(ice, GPIO_SCR, val);
+ spec->scr = val;
+}
+
+static void set_mcr(struct snd_ice1712 *ice, unsigned int val)
+{
+ struct qtet_spec *spec = ice->spec;
+ reg_write(ice, GPIO_MCR, val);
+ spec->mcr = val;
+}
+
+static void set_cpld(struct snd_ice1712 *ice, unsigned int val)
+{
+ struct qtet_spec *spec = ice->spec;
+ reg_write(ice, GPIO_CPLD_CSN, val);
+ spec->cpld = val;
+}
+#ifdef CONFIG_PROC_FS
+static void proc_regs_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct snd_ice1712 *ice = entry->private_data;
+ char bin_buffer[36];
+
+ snd_iprintf(buffer, "SCR: %s\n", get_binary(bin_buffer,
+ get_scr(ice)));
+ snd_iprintf(buffer, "MCR: %s\n", get_binary(bin_buffer,
+ get_mcr(ice)));
+ snd_iprintf(buffer, "CPLD: %s\n", get_binary(bin_buffer,
+ get_cpld(ice)));
+}
+
+static void proc_init(struct snd_ice1712 *ice)
+{
+ struct snd_info_entry *entry;
+ if (!snd_card_proc_new(ice->card, "quartet", &entry))
+ snd_info_set_text_ops(entry, ice, proc_regs_read);
+}
+#else /* !CONFIG_PROC_FS */
+static void proc_init(struct snd_ice1712 *ice) {}
+#endif
+
+static int qtet_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned int val;
+ val = get_scr(ice) & SCR_MUTE;
+ ucontrol->value.integer.value[0] = (val) ? 0 : 1;
+ return 0;
+}
+
+static int qtet_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned int old, new, smute;
+ old = get_scr(ice) & SCR_MUTE;
+ if (ucontrol->value.integer.value[0]) {
+ /* unmute */
+ new = 0;
+ /* un-smuting DAC */
+ smute = 0;
+ } else {
+ /* mute */
+ new = SCR_MUTE;
+ /* smuting DAC */
+ smute = AK4620_SMUTE;
+ }
+ if (old != new) {
+ struct snd_akm4xxx *ak = ice->akm;
+ set_scr(ice, (get_scr(ice) & ~SCR_MUTE) | new);
+ /* set smute */
+ qtet_akm_set_regs(ak, AK4620_DEEMVOL_REG, AK4620_SMUTE, smute);
+ return 1;
+ }
+ /* no change */
+ return 0;
+}
+
+static int qtet_ain12_enum_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[3] = {"Line In 1/2", "Mic", "Mic + Low-cut"};
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = ARRAY_SIZE(texts);
+
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
+
+static int qtet_ain12_sw_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned int val, result;
+ val = get_scr(ice) & (SCR_AIN12_SEL1 | SCR_AIN12_SEL0);
+ switch (val) {
+ case SCR_AIN12_LINE:
+ result = 0;
+ break;
+ case SCR_AIN12_MIC:
+ result = 1;
+ break;
+ case SCR_AIN12_LOWCUT:
+ result = 2;
+ break;
+ default:
+ /* BUG - no other combinations allowed */
+ snd_BUG();
+ result = 0;
+ }
+ ucontrol->value.integer.value[0] = result;
+ return 0;
+}
+
+static int qtet_ain12_sw_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned int old, new, tmp, masked_old;
+ old = new = get_scr(ice);
+ masked_old = old & (SCR_AIN12_SEL1 | SCR_AIN12_SEL0);
+ tmp = ucontrol->value.integer.value[0];
+ if (tmp == 2)
+ tmp = 3; /* binary 10 is not supported */
+ tmp <<= 4; /* shifting to SCR_AIN12_SEL0 */
+ if (tmp != masked_old) {
+ /* change requested */
+ switch (tmp) {
+ case SCR_AIN12_LINE:
+ new = old & ~(SCR_AIN12_SEL1 | SCR_AIN12_SEL0);
+ set_scr(ice, new);
+ /* turn off relay */
+ new &= ~SCR_RELAY;
+ set_scr(ice, new);
+ break;
+ case SCR_AIN12_MIC:
+ /* turn on relay */
+ new = old | SCR_RELAY;
+ set_scr(ice, new);
+ new = (new & ~SCR_AIN12_SEL1) | SCR_AIN12_SEL0;
+ set_scr(ice, new);
+ break;
+ case SCR_AIN12_LOWCUT:
+ /* turn on relay */
+ new = old | SCR_RELAY;
+ set_scr(ice, new);
+ new |= SCR_AIN12_SEL1 | SCR_AIN12_SEL0;
+ set_scr(ice, new);
+ break;
+ default:
+ snd_BUG();
+ }
+ return 1;
+ }
+ /* no change */
+ return 0;
+}
+
+static int qtet_php_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned int val;
+ /* if phantom voltage =48V, phantom on */
+ val = get_scr(ice) & SCR_PHP_V;
+ ucontrol->value.integer.value[0] = val ? 1 : 0;
+ return 0;
+}
+
+static int qtet_php_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned int old, new;
+ old = new = get_scr(ice);
+ if (ucontrol->value.integer.value[0] /* phantom on requested */
+ && (~old & SCR_PHP_V)) /* 0 = voltage 5V */ {
+ /* is off, turn on */
+ /* turn voltage on first, = 1 */
+ new = old | SCR_PHP_V;
+ set_scr(ice, new);
+ /* turn phantom on, = 0 */
+ new &= ~SCR_PHP;
+ set_scr(ice, new);
+ } else if (!ucontrol->value.integer.value[0] && (old & SCR_PHP_V)) {
+ /* phantom off requested and 1 = voltage 48V */
+ /* is on, turn off */
+ /* turn voltage off first, = 0 */
+ new = old & ~SCR_PHP_V;
+ set_scr(ice, new);
+ /* turn phantom off, = 1 */
+ new |= SCR_PHP;
+ set_scr(ice, new);
+ }
+ if (old != new)
+ return 1;
+ /* no change */
+ return 0;
+}
+
+#define PRIV_SW(xid, xbit, xreg) [xid] = {.bit = xbit,\
+ .set_register = set_##xreg,\
+ .get_register = get_##xreg, }
+
+
+#define PRIV_ENUM2(xid, xbit, xreg, xtext1, xtext2) [xid] = {.bit = xbit,\
+ .set_register = set_##xreg,\
+ .get_register = get_##xreg,\
+ .texts = {xtext1, xtext2} }
+
+static struct qtet_kcontrol_private qtet_privates[] = {
+ PRIV_ENUM2(IN12_SEL, CPLD_IN12_SEL, cpld, "An In 1/2", "An In 3/4"),
+ PRIV_ENUM2(IN34_SEL, CPLD_IN34_SEL, cpld, "An In 3/4", "IEC958 In"),
+ PRIV_ENUM2(AIN34_SEL, SCR_AIN34_SEL, scr, "Line In 3/4", "Hi-Z"),
+ PRIV_ENUM2(COAX_OUT, CPLD_COAX_OUT, cpld, "IEC958", "I2S"),
+ PRIV_SW(IN12_MON12, MCR_IN12_MON12, mcr),
+ PRIV_SW(IN12_MON34, MCR_IN12_MON34, mcr),
+ PRIV_SW(IN34_MON12, MCR_IN34_MON12, mcr),
+ PRIV_SW(IN34_MON34, MCR_IN34_MON34, mcr),
+ PRIV_SW(OUT12_MON34, MCR_OUT12_MON34, mcr),
+ PRIV_SW(OUT34_MON12, MCR_OUT34_MON12, mcr),
+};
+
+static int qtet_enum_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct qtet_kcontrol_private private =
+ qtet_privates[kcontrol->private_value];
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = ARRAY_SIZE(private.texts);
+
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name,
+ private.texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
+
+static int qtet_sw_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct qtet_kcontrol_private private =
+ qtet_privates[kcontrol->private_value];
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ ucontrol->value.integer.value[0] =
+ (private.get_register(ice) & private.bit) ? 1 : 0;
+ return 0;
+}
+
+static int qtet_sw_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct qtet_kcontrol_private private =
+ qtet_privates[kcontrol->private_value];
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned int old, new;
+ old = private.get_register(ice);
+ if (ucontrol->value.integer.value[0])
+ new = old | private.bit;
+ else
+ new = old & ~private.bit;
+ if (old != new) {
+ private.set_register(ice, new);
+ return 1;
+ }
+ /* no change */
+ return 0;
+}
+
+#define qtet_sw_info snd_ctl_boolean_mono_info
+
+#define QTET_CONTROL(xname, xtype, xpriv) \
+ {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,\
+ .name = xname,\
+ .info = qtet_##xtype##_info,\
+ .get = qtet_sw_get,\
+ .put = qtet_sw_put,\
+ .private_value = xpriv }
+
+static struct snd_kcontrol_new qtet_controls[] __devinitdata = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Switch",
+ .info = qtet_sw_info,
+ .get = qtet_mute_get,
+ .put = qtet_mute_put,
+ .private_value = 0
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Phantom Power",
+ .info = qtet_sw_info,
+ .get = qtet_php_get,
+ .put = qtet_php_put,
+ .private_value = 0
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog In 1/2 Capture Switch",
+ .info = qtet_ain12_enum_info,
+ .get = qtet_ain12_sw_get,
+ .put = qtet_ain12_sw_put,
+ .private_value = 0
+ },
+ QTET_CONTROL("Analog In 3/4 Capture Switch", enum, AIN34_SEL),
+ QTET_CONTROL("PCM In 1/2 Capture Switch", enum, IN12_SEL),
+ QTET_CONTROL("PCM In 3/4 Capture Switch", enum, IN34_SEL),
+ QTET_CONTROL("Coax Output Source", enum, COAX_OUT),
+ QTET_CONTROL("Analog In 1/2 to Monitor 1/2", sw, IN12_MON12),
+ QTET_CONTROL("Analog In 1/2 to Monitor 3/4", sw, IN12_MON34),
+ QTET_CONTROL("Analog In 3/4 to Monitor 1/2", sw, IN34_MON12),
+ QTET_CONTROL("Analog In 3/4 to Monitor 3/4", sw, IN34_MON34),
+ QTET_CONTROL("Output 1/2 to Monitor 3/4", sw, OUT12_MON34),
+ QTET_CONTROL("Output 3/4 to Monitor 1/2", sw, OUT34_MON12),
+};
+
+static char *slave_vols[] __devinitdata = {
+ PCM_12_PLAYBACK_VOLUME,
+ PCM_34_PLAYBACK_VOLUME,
+ NULL
+};
+
+static __devinitdata
+DECLARE_TLV_DB_SCALE(qtet_master_db_scale, -6350, 50, 1);
+
+static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card,
+ const char *name)
+{
+ struct snd_ctl_elem_id sid;
+ memset(&sid, 0, sizeof(sid));
+ /* FIXME: strcpy is bad. */
+ strcpy(sid.name, name);
+ sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ return snd_ctl_find_id(card, &sid);
+}
+
+static void __devinit add_slaves(struct snd_card *card,
+ struct snd_kcontrol *master, char **list)
+{
+ for (; *list; list++) {
+ struct snd_kcontrol *slave = ctl_find(card, *list);
+ if (slave)
+ snd_ctl_add_slave(master, slave);
+ }
+}
+
+static int __devinit qtet_add_controls(struct snd_ice1712 *ice)
+{
+ struct qtet_spec *spec = ice->spec;
+ int err, i;
+ struct snd_kcontrol *vmaster;
+ err = snd_ice1712_akm4xxx_build_controls(ice);
+ if (err < 0)
+ return err;
+ for (i = 0; i < ARRAY_SIZE(qtet_controls); i++) {
+ err = snd_ctl_add(ice->card,
+ snd_ctl_new1(&qtet_controls[i], ice));
+ if (err < 0)
+ return err;
+ }
+
+ /* Create virtual master control */
+ vmaster = snd_ctl_make_virtual_master("Master Playback Volume",
+ qtet_master_db_scale);
+ if (!vmaster)
+ return -ENOMEM;
+ add_slaves(ice->card, vmaster, slave_vols);
+ err = snd_ctl_add(ice->card, vmaster);
+ if (err < 0)
+ return err;
+ /* only capture SPDIF over AK4113 */
+ err = snd_ak4113_build(spec->ak4113,
+ ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static inline int qtet_is_spdif_master(struct snd_ice1712 *ice)
+{
+ /* CPLD_SYNC_SEL: 0 = internal, 1 = external (i.e. spdif master) */
+ return (get_cpld(ice) & CPLD_SYNC_SEL) ? 1 : 0;
+}
+
+static unsigned int qtet_get_rate(struct snd_ice1712 *ice)
+{
+ int i;
+ unsigned char result;
+
+ result = get_cpld(ice) & CPLD_CKS_MASK;
+ for (i = 0; i < ARRAY_SIZE(cks_vals); i++)
+ if (cks_vals[i] == result)
+ return qtet_rates[i];
+ return 0;
+}
+
+static int get_cks_val(int rate)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(qtet_rates); i++)
+ if (qtet_rates[i] == rate)
+ return cks_vals[i];
+ return 0;
+}
+
+/* setting new rate */
+static void qtet_set_rate(struct snd_ice1712 *ice, unsigned int rate)
+{
+ unsigned int new;
+ unsigned char val;
+ /* switching ice1724 to external clock - supplied by ext. circuits */
+ val = inb(ICEMT1724(ice, RATE));
+ outb(val | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE));
+
+ new = (get_cpld(ice) & ~CPLD_CKS_MASK) | get_cks_val(rate);
+ /* switch to internal clock, drop CPLD_SYNC_SEL */
+ new &= ~CPLD_SYNC_SEL;
+ /* printk(KERN_DEBUG "QT - set_rate: old %x, new %x\n",
+ get_cpld(ice), new); */
+ set_cpld(ice, new);
+}
+
+static inline unsigned char qtet_set_mclk(struct snd_ice1712 *ice,
+ unsigned int rate)
+{
+ /* no change in master clock */
+ return 0;
+}
+
+/* setting clock to external - SPDIF */
+static int qtet_set_spdif_clock(struct snd_ice1712 *ice, int type)
+{
+ unsigned int old, new;
+
+ old = new = get_cpld(ice);
+ new &= ~(CPLD_CKS_MASK | CPLD_WORD_SEL);
+ switch (type) {
+ case EXT_SPDIF_TYPE:
+ new |= CPLD_EXT_SPDIF;
+ break;
+ case EXT_WORDCLOCK_1FS_TYPE:
+ new |= CPLD_EXT_WORDCLOCK_1FS;
+ break;
+ case EXT_WORDCLOCK_256FS_TYPE:
+ new |= CPLD_EXT_WORDCLOCK_256FS;
+ break;
+ default:
+ snd_BUG();
+ }
+ if (old != new) {
+ set_cpld(ice, new);
+ /* changed */
+ return 1;
+ }
+ return 0;
+}
+
+static int qtet_get_spdif_master_type(struct snd_ice1712 *ice)
+{
+ unsigned int val;
+ int result;
+ val = get_cpld(ice);
+ /* checking only rate/clock-related bits */
+ val &= (CPLD_CKS_MASK | CPLD_WORD_SEL | CPLD_SYNC_SEL);
+ if (!(val & CPLD_SYNC_SEL)) {
+ /* switched to internal clock, is not any external type */
+ result = -1;
+ } else {
+ switch (val) {
+ case (CPLD_EXT_SPDIF):
+ result = EXT_SPDIF_TYPE;
+ break;
+ case (CPLD_EXT_WORDCLOCK_1FS):
+ result = EXT_WORDCLOCK_1FS_TYPE;
+ break;
+ case (CPLD_EXT_WORDCLOCK_256FS):
+ result = EXT_WORDCLOCK_256FS_TYPE;
+ break;
+ default:
+ /* undefined combination of external clock setup */
+ snd_BUG();
+ result = 0;
+ }
+ }
+ return result;
+}
+
+/* Called when ak4113 detects change in the input SPDIF stream */
+static void qtet_ak4113_change(struct ak4113 *ak4113, unsigned char c0,
+ unsigned char c1)
+{
+ struct snd_ice1712 *ice = ak4113->change_callback_private;
+ int rate;
+ if ((qtet_get_spdif_master_type(ice) == EXT_SPDIF_TYPE) &&
+ c1) {
+ /* only for SPDIF master mode, rate was changed */
+ rate = snd_ak4113_external_rate(ak4113);
+ /* printk(KERN_DEBUG "ak4113 - input rate changed to %d\n",
+ rate); */
+ qtet_akm_set_rate_val(ice->akm, rate);
+ }
+}
+
+/*
+ * If clock slaved to SPDIF-IN, setting runtime rate
+ * to the detected external rate
+ */
+static void qtet_spdif_in_open(struct snd_ice1712 *ice,
+ struct snd_pcm_substream *substream)
+{
+ struct qtet_spec *spec = ice->spec;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int rate;
+
+ if (qtet_get_spdif_master_type(ice) != EXT_SPDIF_TYPE)
+ /* not external SPDIF, no rate limitation */
+ return;
+ /* only external SPDIF can detect incoming sample rate */
+ rate = snd_ak4113_external_rate(spec->ak4113);
+ if (rate >= runtime->hw.rate_min && rate <= runtime->hw.rate_max) {
+ runtime->hw.rate_min = rate;
+ runtime->hw.rate_max = rate;
+ }
+}
+
+/*
+ * initialize the chip
+ */
+static int __devinit qtet_init(struct snd_ice1712 *ice)
+{
+ static const unsigned char ak4113_init_vals[] = {
+ /* AK4113_REG_PWRDN */ AK4113_RST | AK4113_PWN |
+ AK4113_OCKS0 | AK4113_OCKS1,
+ /* AK4113_REQ_FORMAT */ AK4113_DIF_I24I2S | AK4113_VTX |
+ AK4113_DEM_OFF | AK4113_DEAU,
+ /* AK4113_REG_IO0 */ AK4113_OPS2 | AK4113_TXE |
+ AK4113_XTL_24_576M,
+ /* AK4113_REG_IO1 */ AK4113_EFH_1024LRCLK | AK4113_IPS(0),
+ /* AK4113_REG_INT0_MASK */ 0,
+ /* AK4113_REG_INT1_MASK */ 0,
+ /* AK4113_REG_DATDTS */ 0,
+ };
+ int err;
+ struct qtet_spec *spec;
+ struct snd_akm4xxx *ak;
+ unsigned char val;
+
+ /* switching ice1724 to external clock - supplied by ext. circuits */
+ val = inb(ICEMT1724(ice, RATE));
+ outb(val | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE));
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return -ENOMEM;
+ /* qtet is clocked by Xilinx array */
+ ice->hw_rates = &qtet_rates_info;
+ ice->is_spdif_master = qtet_is_spdif_master;
+ ice->get_rate = qtet_get_rate;
+ ice->set_rate = qtet_set_rate;
+ ice->set_mclk = qtet_set_mclk;
+ ice->set_spdif_clock = qtet_set_spdif_clock;
+ ice->get_spdif_master_type = qtet_get_spdif_master_type;
+ ice->ext_clock_names = ext_clock_names;
+ ice->ext_clock_count = ARRAY_SIZE(ext_clock_names);
+ /* since Qtet can detect correct SPDIF-in rate, all streams can be
+ * limited to this specific rate */
+ ice->spdif.ops.open = ice->pro_open = qtet_spdif_in_open;
+ ice->spec = spec;
+
+ /* Mute Off */
+ /* SCR Initialize*/
+ /* keep codec power down first */
+ set_scr(ice, SCR_PHP);
+ udelay(1);
+ /* codec power up */
+ set_scr(ice, SCR_PHP | SCR_CODEC_PDN);
+
+ /* MCR Initialize */
+ set_mcr(ice, 0);
+
+ /* CPLD Initialize */
+ set_cpld(ice, 0);
+
+
+ ice->num_total_dacs = 2;
+ ice->num_total_adcs = 2;
+
+ ice->akm = kcalloc(2, sizeof(struct snd_akm4xxx), GFP_KERNEL);
+ ak = ice->akm;
+ if (!ak)
+ return -ENOMEM;
+ /* only one codec with two chips */
+ ice->akm_codecs = 1;
+ err = snd_ice1712_akm4xxx_init(ak, &akm_qtet_dac, NULL, ice);
+ if (err < 0)
+ return err;
+ err = snd_ak4113_create(ice->card,
+ qtet_ak4113_read,
+ qtet_ak4113_write,
+ ak4113_init_vals,
+ ice, &spec->ak4113);
+ if (err < 0)
+ return err;
+ /* callback for codecs rate setting */
+ spec->ak4113->change_callback = qtet_ak4113_change;
+ spec->ak4113->change_callback_private = ice;
+ /* AK41143 in Quartet can detect external rate correctly
+ * (i.e. check_flags = 0) */
+ spec->ak4113->check_flags = 0;
+
+ proc_init(ice);
+
+ qtet_set_rate(ice, 44100);
+ return 0;
+}
+
+static unsigned char qtet_eeprom[] __devinitdata = {
+ [ICE_EEP2_SYSCONF] = 0x28, /* clock 256(24MHz), mpu401, 1xADC,
+ 1xDACs, SPDIF in */
+ [ICE_EEP2_ACLINK] = 0x80, /* I2S */
+ [ICE_EEP2_I2S] = 0x78, /* 96k, 24bit, 192k */
+ [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, in, out-ext */
+ [ICE_EEP2_GPIO_DIR] = 0x00, /* 0-7 inputs, switched to output
+ only during output operations */
+ [ICE_EEP2_GPIO_DIR1] = 0xff, /* 8-15 outputs */
+ [ICE_EEP2_GPIO_DIR2] = 0x00,
+ [ICE_EEP2_GPIO_MASK] = 0xff, /* changed only for OUT operations */
+ [ICE_EEP2_GPIO_MASK1] = 0x00,
+ [ICE_EEP2_GPIO_MASK2] = 0xff,
+
+ [ICE_EEP2_GPIO_STATE] = 0x00, /* inputs */
+ [ICE_EEP2_GPIO_STATE1] = 0x7d, /* all 1, but GPIO_CPLD_RW
+ and GPIO15 always zero */
+ [ICE_EEP2_GPIO_STATE2] = 0x00, /* inputs */
+};
+
+/* entry point */
+struct snd_ice1712_card_info snd_vt1724_qtet_cards[] __devinitdata = {
+ {
+ .subvendor = VT1724_SUBDEVICE_QTET,
+ .name = "Infrasonic Quartet",
+ .model = "quartet",
+ .chip_init = qtet_init,
+ .build_controls = qtet_add_controls,
+ .eeprom_size = sizeof(qtet_eeprom),
+ .eeprom_data = qtet_eeprom,
+ },
+ { } /* terminator */
+};
diff --git a/sound/pci/ice1712/quartet.h b/sound/pci/ice1712/quartet.h
new file mode 100644
index 000000000000..80809b72439a
--- /dev/null
+++ b/sound/pci/ice1712/quartet.h
@@ -0,0 +1,10 @@
+#ifndef __SOUND_QTET_H
+#define __SOUND_QTET_H
+
+#define QTET_DEVICE_DESC "{Infrasonic,Quartet},"
+
+#define VT1724_SUBDEVICE_QTET 0x30305349 /* Infrasonic Quartet */
+
+extern struct snd_ice1712_card_info snd_vt1724_qtet_cards[];
+
+#endif /* __SOUND_QTET_H */
diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile
index 4ba07d42fd1d..389941cf6100 100644
--- a/sound/pci/oxygen/Makefile
+++ b/sound/pci/oxygen/Makefile
@@ -1,7 +1,8 @@
snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o
snd-hifier-objs := hifier.o
snd-oxygen-objs := oxygen.o
-snd-virtuoso-objs := virtuoso.o
+snd-virtuoso-objs := virtuoso.o xonar_lib.o \
+ xonar_pcm179x.o xonar_cs43xx.o xonar_hdmi.o
obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o
obj-$(CONFIG_SND_HIFIER) += snd-hifier.o
diff --git a/sound/pci/oxygen/cs2000.h b/sound/pci/oxygen/cs2000.h
new file mode 100644
index 000000000000..c3501bdb5edc
--- /dev/null
+++ b/sound/pci/oxygen/cs2000.h
@@ -0,0 +1,83 @@
+#ifndef CS2000_H_INCLUDED
+#define CS2000_H_INCLUDED
+
+#define CS2000_DEV_ID 0x01
+#define CS2000_DEV_CTRL 0x02
+#define CS2000_DEV_CFG_1 0x03
+#define CS2000_DEV_CFG_2 0x04
+#define CS2000_GLOBAL_CFG 0x05
+#define CS2000_RATIO_0 0x06 /* 32 bits, big endian */
+#define CS2000_RATIO_1 0x0a
+#define CS2000_RATIO_2 0x0e
+#define CS2000_RATIO_3 0x12
+#define CS2000_FUN_CFG_1 0x16
+#define CS2000_FUN_CFG_2 0x17
+#define CS2000_FUN_CFG_3 0x1e
+
+/* DEV_ID */
+#define CS2000_DEVICE_MASK 0xf8
+#define CS2000_REVISION_MASK 0x07
+
+/* DEV_CTRL */
+#define CS2000_UNLOCK 0x80
+#define CS2000_AUX_OUT_DIS 0x02
+#define CS2000_CLK_OUT_DIS 0x01
+
+/* DEV_CFG_1 */
+#define CS2000_R_MOD_SEL_MASK 0xe0
+#define CS2000_R_MOD_SEL_1 0x00
+#define CS2000_R_MOD_SEL_2 0x20
+#define CS2000_R_MOD_SEL_4 0x40
+#define CS2000_R_MOD_SEL_8 0x60
+#define CS2000_R_MOD_SEL_1_2 0x80
+#define CS2000_R_MOD_SEL_1_4 0xa0
+#define CS2000_R_MOD_SEL_1_8 0xc0
+#define CS2000_R_MOD_SEL_1_16 0xe0
+#define CS2000_R_SEL_MASK 0x18
+#define CS2000_R_SEL_SHIFT 3
+#define CS2000_AUX_OUT_SRC_MASK 0x06
+#define CS2000_AUX_OUT_SRC_REF_CLK 0x00
+#define CS2000_AUX_OUT_SRC_CLK_IN 0x02
+#define CS2000_AUX_OUT_SRC_CLK_OUT 0x04
+#define CS2000_AUX_OUT_SRC_PLL_LOCK 0x06
+#define CS2000_EN_DEV_CFG_1 0x01
+
+/* DEV_CFG_2 */
+#define CS2000_LOCK_CLK_MASK 0x06
+#define CS2000_LOCK_CLK_SHIFT 1
+#define CS2000_FRAC_N_SRC_MASK 0x01
+#define CS2000_FRAC_N_SRC_STATIC 0x00
+#define CS2000_FRAC_N_SRC_DYNAMIC 0x01
+
+/* GLOBAL_CFG */
+#define CS2000_FREEZE 0x08
+#define CS2000_EN_DEV_CFG_2 0x01
+
+/* FUN_CFG_1 */
+#define CS2000_CLK_SKIP_EN 0x80
+#define CS2000_AUX_LOCK_CFG_MASK 0x40
+#define CS2000_AUX_LOCK_CFG_PP_HIGH 0x00
+#define CS2000_AUX_LOCK_CFG_OD_LOW 0x40
+#define CS2000_REF_CLK_DIV_MASK 0x18
+#define CS2000_REF_CLK_DIV_4 0x00
+#define CS2000_REF_CLK_DIV_2 0x08
+#define CS2000_REF_CLK_DIV_1 0x10
+
+/* FUN_CFG_2 */
+#define CS2000_CLK_OUT_UNL 0x10
+#define CS2000_L_F_RATIO_CFG_MASK 0x08
+#define CS2000_L_F_RATIO_CFG_20_12 0x00
+#define CS2000_L_F_RATIO_CFG_12_20 0x08
+
+/* FUN_CFG_3 */
+#define CS2000_CLK_IN_BW_MASK 0x70
+#define CS2000_CLK_IN_BW_1 0x00
+#define CS2000_CLK_IN_BW_2 0x10
+#define CS2000_CLK_IN_BW_4 0x20
+#define CS2000_CLK_IN_BW_8 0x30
+#define CS2000_CLK_IN_BW_16 0x40
+#define CS2000_CLK_IN_BW_32 0x50
+#define CS2000_CLK_IN_BW_64 0x60
+#define CS2000_CLK_IN_BW_128 0x70
+
+#endif
diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c
index 84ef13183419..e3c229b63311 100644
--- a/sound/pci/oxygen/hifier.c
+++ b/sound/pci/oxygen/hifier.c
@@ -17,6 +17,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+/*
+ * CMI8788:
+ *
+ * SPI 0 -> AK4396
+ */
+
#include <linux/delay.h>
#include <linux/pci.h>
#include <sound/control.h>
@@ -51,23 +57,28 @@ static struct pci_device_id hifier_ids[] __devinitdata = {
MODULE_DEVICE_TABLE(pci, hifier_ids);
struct hifier_data {
- u8 ak4396_ctl2;
+ u8 ak4396_regs[5];
};
static void ak4396_write(struct oxygen *chip, u8 reg, u8 value)
{
+ struct hifier_data *data = chip->model_data;
+
oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
OXYGEN_SPI_DATA_LENGTH_2 |
OXYGEN_SPI_CLOCK_160 |
(0 << OXYGEN_SPI_CODEC_SHIFT) |
OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
AK4396_WRITE | (reg << 8) | value);
+ data->ak4396_regs[reg] = value;
}
-static void update_ak4396_volume(struct oxygen *chip)
+static void ak4396_write_cached(struct oxygen *chip, u8 reg, u8 value)
{
- ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]);
- ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]);
+ struct hifier_data *data = chip->model_data;
+
+ if (value != data->ak4396_regs[reg])
+ ak4396_write(chip, reg, value);
}
static void hifier_registers_init(struct oxygen *chip)
@@ -75,16 +86,19 @@ static void hifier_registers_init(struct oxygen *chip)
struct hifier_data *data = chip->model_data;
ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
- ak4396_write(chip, AK4396_CONTROL_2, data->ak4396_ctl2);
+ ak4396_write(chip, AK4396_CONTROL_2,
+ data->ak4396_regs[AK4396_CONTROL_2]);
ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM);
- update_ak4396_volume(chip);
+ ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]);
+ ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]);
}
static void hifier_init(struct oxygen *chip)
{
struct hifier_data *data = chip->model_data;
- data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
+ data->ak4396_regs[AK4396_CONTROL_2] =
+ AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
hifier_registers_init(chip);
snd_component_add(chip->card, "AK4396");
@@ -106,20 +120,29 @@ static void set_ak4396_params(struct oxygen *chip,
struct hifier_data *data = chip->model_data;
u8 value;
- value = data->ak4396_ctl2 & ~AK4396_DFS_MASK;
+ value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_DFS_MASK;
if (params_rate(params) <= 54000)
value |= AK4396_DFS_NORMAL;
else if (params_rate(params) <= 108000)
value |= AK4396_DFS_DOUBLE;
else
value |= AK4396_DFS_QUAD;
- data->ak4396_ctl2 = value;
msleep(1); /* wait for the new MCLK to become stable */
- ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB);
- ak4396_write(chip, AK4396_CONTROL_2, value);
- ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
+ if (value != data->ak4396_regs[AK4396_CONTROL_2]) {
+ ak4396_write(chip, AK4396_CONTROL_1,
+ AK4396_DIF_24_MSB);
+ ak4396_write(chip, AK4396_CONTROL_2, value);
+ ak4396_write(chip, AK4396_CONTROL_1,
+ AK4396_DIF_24_MSB | AK4396_RSTN);
+ }
+}
+
+static void update_ak4396_volume(struct oxygen *chip)
+{
+ ak4396_write_cached(chip, AK4396_LCH_ATT, chip->dac_volume[0]);
+ ak4396_write_cached(chip, AK4396_RCH_ATT, chip->dac_volume[1]);
}
static void update_ak4396_mute(struct oxygen *chip)
@@ -127,11 +150,10 @@ static void update_ak4396_mute(struct oxygen *chip)
struct hifier_data *data = chip->model_data;
u8 value;
- value = data->ak4396_ctl2 & ~AK4396_SMUTE;
+ value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_SMUTE;
if (chip->dac_mute)
value |= AK4396_SMUTE;
- data->ak4396_ctl2 = value;
- ak4396_write(chip, AK4396_CONTROL_2, value);
+ ak4396_write_cached(chip, AK4396_CONTROL_2, value);
}
static void set_cs5340_params(struct oxygen *chip,
@@ -141,21 +163,14 @@ static void set_cs5340_params(struct oxygen *chip,
static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
-static int hifier_control_filter(struct snd_kcontrol_new *template)
-{
- if (!strcmp(template->name, "Stereo Upmixing"))
- return 1; /* stereo only - we don't need upmixing */
- return 0;
-}
-
static const struct oxygen_model model_hifier = {
.shortname = "C-Media CMI8787",
.longname = "C-Media Oxygen HD Audio",
.chip = "CMI8788",
.init = hifier_init,
- .control_filter = hifier_control_filter,
.cleanup = hifier_cleanup,
.resume = hifier_resume,
+ .get_i2s_mclk = oxygen_default_i2s_mclk,
.set_dac_params = set_ak4396_params,
.set_adc_params = set_cs5340_params,
.update_dac_volume = update_ak4396_volume,
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index 72db4c39007f..acbedebcffd9 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -18,6 +18,8 @@
*/
/*
+ * CMI8788:
+ *
* SPI 0 -> 1st AK4396 (front)
* SPI 1 -> 2nd AK4396 (surround)
* SPI 2 -> 3rd AK4396 (center/LFE)
@@ -27,6 +29,10 @@
* GPIO 0 -> DFS0 of AK5385
* GPIO 1 -> DFS1 of AK5385
* GPIO 8 -> enable headphone amplifier on HT-Omega models
+ *
+ * CM9780:
+ *
+ * GPO 0 -> route line-in (0) or AC97 output (1) to ADC input
*/
#include <linux/delay.h>
@@ -91,8 +97,8 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids);
#define GPIO_CLARO_HP 0x0100
struct generic_data {
- u8 ak4396_ctl2;
- u16 saved_wm8785_registers[2];
+ u8 ak4396_regs[4][5];
+ u16 wm8785_regs[3];
};
static void ak4396_write(struct oxygen *chip, unsigned int codec,
@@ -102,12 +108,24 @@ static void ak4396_write(struct oxygen *chip, unsigned int codec,
static const u8 codec_spi_map[4] = {
0, 1, 2, 4
};
+ struct generic_data *data = chip->model_data;
+
oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
OXYGEN_SPI_DATA_LENGTH_2 |
OXYGEN_SPI_CLOCK_160 |
(codec_spi_map[codec] << OXYGEN_SPI_CODEC_SHIFT) |
OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
AK4396_WRITE | (reg << 8) | value);
+ data->ak4396_regs[codec][reg] = value;
+}
+
+static void ak4396_write_cached(struct oxygen *chip, unsigned int codec,
+ u8 reg, u8 value)
+{
+ struct generic_data *data = chip->model_data;
+
+ if (value != data->ak4396_regs[codec][reg])
+ ak4396_write(chip, codec, reg, value);
}
static void wm8785_write(struct oxygen *chip, u8 reg, unsigned int value)
@@ -120,20 +138,8 @@ static void wm8785_write(struct oxygen *chip, u8 reg, unsigned int value)
(3 << OXYGEN_SPI_CODEC_SHIFT) |
OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
(reg << 9) | value);
- if (reg < ARRAY_SIZE(data->saved_wm8785_registers))
- data->saved_wm8785_registers[reg] = value;
-}
-
-static void update_ak4396_volume(struct oxygen *chip)
-{
- unsigned int i;
-
- for (i = 0; i < 4; ++i) {
- ak4396_write(chip, i,
- AK4396_LCH_ATT, chip->dac_volume[i * 2]);
- ak4396_write(chip, i,
- AK4396_RCH_ATT, chip->dac_volume[i * 2 + 1]);
- }
+ if (reg < ARRAY_SIZE(data->wm8785_regs))
+ data->wm8785_regs[reg] = value;
}
static void ak4396_registers_init(struct oxygen *chip)
@@ -142,21 +148,25 @@ static void ak4396_registers_init(struct oxygen *chip)
unsigned int i;
for (i = 0; i < 4; ++i) {
- ak4396_write(chip, i,
- AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
- ak4396_write(chip, i,
- AK4396_CONTROL_2, data->ak4396_ctl2);
- ak4396_write(chip, i,
- AK4396_CONTROL_3, AK4396_PCM);
+ ak4396_write(chip, i, AK4396_CONTROL_1,
+ AK4396_DIF_24_MSB | AK4396_RSTN);
+ ak4396_write(chip, i, AK4396_CONTROL_2,
+ data->ak4396_regs[0][AK4396_CONTROL_2]);
+ ak4396_write(chip, i, AK4396_CONTROL_3,
+ AK4396_PCM);
+ ak4396_write(chip, i, AK4396_LCH_ATT,
+ chip->dac_volume[i * 2]);
+ ak4396_write(chip, i, AK4396_RCH_ATT,
+ chip->dac_volume[i * 2 + 1]);
}
- update_ak4396_volume(chip);
}
static void ak4396_init(struct oxygen *chip)
{
struct generic_data *data = chip->model_data;
- data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
+ data->ak4396_regs[0][AK4396_CONTROL_2] =
+ AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
ak4396_registers_init(chip);
snd_component_add(chip->card, "AK4396");
}
@@ -173,17 +183,17 @@ static void wm8785_registers_init(struct oxygen *chip)
struct generic_data *data = chip->model_data;
wm8785_write(chip, WM8785_R7, 0);
- wm8785_write(chip, WM8785_R0, data->saved_wm8785_registers[0]);
- wm8785_write(chip, WM8785_R1, data->saved_wm8785_registers[1]);
+ wm8785_write(chip, WM8785_R0, data->wm8785_regs[0]);
+ wm8785_write(chip, WM8785_R2, data->wm8785_regs[2]);
}
static void wm8785_init(struct oxygen *chip)
{
struct generic_data *data = chip->model_data;
- data->saved_wm8785_registers[0] = WM8785_MCR_SLAVE |
- WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST;
- data->saved_wm8785_registers[1] = WM8785_WL_24;
+ data->wm8785_regs[0] =
+ WM8785_MCR_SLAVE | WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST;
+ data->wm8785_regs[2] = WM8785_HPFR | WM8785_HPFL;
wm8785_registers_init(chip);
snd_component_add(chip->card, "WM8785");
}
@@ -264,24 +274,36 @@ static void set_ak4396_params(struct oxygen *chip,
unsigned int i;
u8 value;
- value = data->ak4396_ctl2 & ~AK4396_DFS_MASK;
+ value = data->ak4396_regs[0][AK4396_CONTROL_2] & ~AK4396_DFS_MASK;
if (params_rate(params) <= 54000)
value |= AK4396_DFS_NORMAL;
else if (params_rate(params) <= 108000)
value |= AK4396_DFS_DOUBLE;
else
value |= AK4396_DFS_QUAD;
- data->ak4396_ctl2 = value;
msleep(1); /* wait for the new MCLK to become stable */
+ if (value != data->ak4396_regs[0][AK4396_CONTROL_2]) {
+ for (i = 0; i < 4; ++i) {
+ ak4396_write(chip, i, AK4396_CONTROL_1,
+ AK4396_DIF_24_MSB);
+ ak4396_write(chip, i, AK4396_CONTROL_2, value);
+ ak4396_write(chip, i, AK4396_CONTROL_1,
+ AK4396_DIF_24_MSB | AK4396_RSTN);
+ }
+ }
+}
+
+static void update_ak4396_volume(struct oxygen *chip)
+{
+ unsigned int i;
+
for (i = 0; i < 4; ++i) {
- ak4396_write(chip, i,
- AK4396_CONTROL_1, AK4396_DIF_24_MSB);
- ak4396_write(chip, i,
- AK4396_CONTROL_2, value);
- ak4396_write(chip, i,
- AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
+ ak4396_write_cached(chip, i, AK4396_LCH_ATT,
+ chip->dac_volume[i * 2]);
+ ak4396_write_cached(chip, i, AK4396_RCH_ATT,
+ chip->dac_volume[i * 2 + 1]);
}
}
@@ -291,21 +313,19 @@ static void update_ak4396_mute(struct oxygen *chip)
unsigned int i;
u8 value;
- value = data->ak4396_ctl2 & ~AK4396_SMUTE;
+ value = data->ak4396_regs[0][AK4396_CONTROL_2] & ~AK4396_SMUTE;
if (chip->dac_mute)
value |= AK4396_SMUTE;
- data->ak4396_ctl2 = value;
for (i = 0; i < 4; ++i)
- ak4396_write(chip, i, AK4396_CONTROL_2, value);
+ ak4396_write_cached(chip, i, AK4396_CONTROL_2, value);
}
static void set_wm8785_params(struct oxygen *chip,
struct snd_pcm_hw_params *params)
{
+ struct generic_data *data = chip->model_data;
unsigned int value;
- wm8785_write(chip, WM8785_R7, 0);
-
value = WM8785_MCR_SLAVE | WM8785_FORMAT_LJUST;
if (params_rate(params) <= 48000)
value |= WM8785_OSR_SINGLE;
@@ -313,13 +333,11 @@ static void set_wm8785_params(struct oxygen *chip,
value |= WM8785_OSR_DOUBLE;
else
value |= WM8785_OSR_QUAD;
- wm8785_write(chip, WM8785_R0, value);
-
- if (snd_pcm_format_width(params_format(params)) <= 16)
- value = WM8785_WL_16;
- else
- value = WM8785_WL_24;
- wm8785_write(chip, WM8785_R1, value);
+ if (value != data->wm8785_regs[0]) {
+ wm8785_write(chip, WM8785_R7, 0);
+ wm8785_write(chip, WM8785_R0, value);
+ wm8785_write(chip, WM8785_R2, data->wm8785_regs[2]);
+ }
}
static void set_ak5385_params(struct oxygen *chip,
@@ -337,6 +355,134 @@ static void set_ak5385_params(struct oxygen *chip,
value, GPIO_AK5385_DFS_MASK);
}
+static int rolloff_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ static const char *const names[2] = {
+ "Sharp Roll-off", "Slow Roll-off"
+ };
+
+ info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ info->count = 1;
+ info->value.enumerated.items = 2;
+ if (info->value.enumerated.item >= 2)
+ info->value.enumerated.item = 1;
+ strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+ return 0;
+}
+
+static int rolloff_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct generic_data *data = chip->model_data;
+
+ value->value.enumerated.item[0] =
+ (data->ak4396_regs[0][AK4396_CONTROL_2] & AK4396_SLOW) != 0;
+ return 0;
+}
+
+static int rolloff_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct generic_data *data = chip->model_data;
+ unsigned int i;
+ int changed;
+ u8 reg;
+
+ mutex_lock(&chip->mutex);
+ reg = data->ak4396_regs[0][AK4396_CONTROL_2];
+ if (value->value.enumerated.item[0])
+ reg |= AK4396_SLOW;
+ else
+ reg &= ~AK4396_SLOW;
+ changed = reg != data->ak4396_regs[0][AK4396_CONTROL_2];
+ if (changed) {
+ for (i = 0; i < 4; ++i)
+ ak4396_write(chip, i, AK4396_CONTROL_2, reg);
+ }
+ mutex_unlock(&chip->mutex);
+ return changed;
+}
+
+static const struct snd_kcontrol_new rolloff_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "DAC Filter Playback Enum",
+ .info = rolloff_info,
+ .get = rolloff_get,
+ .put = rolloff_put,
+};
+
+static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
+{
+ static const char *const names[2] = {
+ "None", "High-pass Filter"
+ };
+
+ info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ info->count = 1;
+ info->value.enumerated.items = 2;
+ if (info->value.enumerated.item >= 2)
+ info->value.enumerated.item = 1;
+ strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+ return 0;
+}
+
+static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct generic_data *data = chip->model_data;
+
+ value->value.enumerated.item[0] =
+ (data->wm8785_regs[WM8785_R2] & WM8785_HPFR) != 0;
+ return 0;
+}
+
+static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct generic_data *data = chip->model_data;
+ unsigned int reg;
+ int changed;
+
+ mutex_lock(&chip->mutex);
+ reg = data->wm8785_regs[WM8785_R2] & ~(WM8785_HPFR | WM8785_HPFL);
+ if (value->value.enumerated.item[0])
+ reg |= WM8785_HPFR | WM8785_HPFL;
+ changed = reg != data->wm8785_regs[WM8785_R2];
+ if (changed)
+ wm8785_write(chip, WM8785_R2, reg);
+ mutex_unlock(&chip->mutex);
+ return changed;
+}
+
+static const struct snd_kcontrol_new hpf_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "ADC Filter Capture Enum",
+ .info = hpf_info,
+ .get = hpf_get,
+ .put = hpf_put,
+};
+
+static int generic_mixer_init(struct oxygen *chip)
+{
+ return snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip));
+}
+
+static int generic_wm8785_mixer_init(struct oxygen *chip)
+{
+ int err;
+
+ err = generic_mixer_init(chip);
+ if (err < 0)
+ return err;
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&hpf_control, chip));
+ if (err < 0)
+ return err;
+ return 0;
+}
+
static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
static const struct oxygen_model model_generic = {
@@ -344,8 +490,10 @@ static const struct oxygen_model model_generic = {
.longname = "C-Media Oxygen HD Audio",
.chip = "CMI8788",
.init = generic_init,
+ .mixer_init = generic_wm8785_mixer_init,
.cleanup = generic_cleanup,
.resume = generic_resume,
+ .get_i2s_mclk = oxygen_default_i2s_mclk,
.set_dac_params = set_ak4396_params,
.set_adc_params = set_wm8785_params,
.update_dac_volume = update_ak4396_volume,
@@ -374,6 +522,7 @@ static int __devinit get_oxygen_model(struct oxygen *chip,
switch (id->driver_data) {
case MODEL_MERIDIAN:
chip->model.init = meridian_init;
+ chip->model.mixer_init = generic_mixer_init;
chip->model.resume = meridian_resume;
chip->model.set_adc_params = set_ak5385_params;
chip->model.device_config = PLAYBACK_0_TO_I2S |
@@ -389,6 +538,7 @@ static int __devinit get_oxygen_model(struct oxygen *chip,
break;
case MODEL_CLARO_HALO:
chip->model.init = claro_halo_init;
+ chip->model.mixer_init = generic_mixer_init;
chip->model.cleanup = claro_cleanup;
chip->model.suspend = claro_suspend;
chip->model.resume = claro_resume;
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index bd615dbffadb..6147216af744 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -78,12 +78,15 @@ struct oxygen_model {
void (*resume)(struct oxygen *chip);
void (*pcm_hardware_filter)(unsigned int channel,
struct snd_pcm_hardware *hardware);
+ unsigned int (*get_i2s_mclk)(struct oxygen *chip, unsigned int channel,
+ struct snd_pcm_hw_params *hw_params);
void (*set_dac_params)(struct oxygen *chip,
struct snd_pcm_hw_params *params);
void (*set_adc_params)(struct oxygen *chip,
struct snd_pcm_hw_params *params);
void (*update_dac_volume)(struct oxygen *chip);
void (*update_dac_mute)(struct oxygen *chip);
+ void (*update_center_lfe_mix)(struct oxygen *chip, bool mixed);
void (*gpio_changed)(struct oxygen *chip);
void (*uart_input)(struct oxygen *chip);
void (*ac97_switch)(struct oxygen *chip,
@@ -162,6 +165,8 @@ void oxygen_update_spdif_source(struct oxygen *chip);
/* oxygen_pcm.c */
int oxygen_pcm_init(struct oxygen *chip);
+unsigned int oxygen_default_i2s_mclk(struct oxygen *chip, unsigned int channel,
+ struct snd_pcm_hw_params *hw_params);
/* oxygen_io.c */
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index 9a8936e20744..9c5e6450eebb 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -278,7 +278,11 @@ oxygen_search_pci_id(struct oxygen *chip, const struct pci_device_id ids[])
static void oxygen_restore_eeprom(struct oxygen *chip,
const struct pci_device_id *id)
{
- if (oxygen_read_eeprom(chip, 0) != OXYGEN_EEPROM_ID) {
+ u16 eeprom_id;
+
+ eeprom_id = oxygen_read_eeprom(chip, 0);
+ if (eeprom_id != OXYGEN_EEPROM_ID &&
+ (eeprom_id != 0xffff || id->subdevice != 0x8788)) {
/*
* This function gets called only when a known card model has
* been detected, i.e., we know there is a valid subsystem
@@ -303,6 +307,28 @@ static void oxygen_restore_eeprom(struct oxygen *chip,
}
}
+static void pci_bridge_magic(void)
+{
+ struct pci_dev *pci = NULL;
+ 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. */
+ }
+}
+
static void oxygen_init(struct oxygen *chip)
{
unsigned int i;
@@ -581,6 +607,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();
oxygen_init(chip);
chip->model.init(chip);
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c
index 5401c547c4e3..f375b8a27862 100644
--- a/sound/pci/oxygen/oxygen_mixer.c
+++ b/sound/pci/oxygen/oxygen_mixer.c
@@ -99,11 +99,15 @@ static int dac_mute_put(struct snd_kcontrol *ctl,
static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
{
- static const char *const names[3] = {
- "Front", "Front+Surround", "Front+Surround+Back"
+ static const char *const names[5] = {
+ "Front",
+ "Front+Surround",
+ "Front+Surround+Back",
+ "Front+Surround+Center/LFE",
+ "Front+Surround+Center/LFE+Back",
};
struct oxygen *chip = ctl->private_data;
- unsigned int count = 2 + (chip->model.dac_channels == 8);
+ unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3;
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
info->count = 1;
@@ -127,7 +131,7 @@ static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
void oxygen_update_dac_routing(struct oxygen *chip)
{
/* DAC 0: front, DAC 1: surround, DAC 2: center/LFE, DAC 3: back */
- static const unsigned int reg_values[3] = {
+ static const unsigned int reg_values[5] = {
/* stereo -> front */
(0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
(1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
@@ -143,6 +147,16 @@ void oxygen_update_dac_routing(struct oxygen *chip)
(0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
(2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
(0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
+ /* stereo -> front+surround+center/LFE */
+ (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+ (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+ (0 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+ (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
+ /* stereo -> front+surround+center/LFE+back */
+ (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+ (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+ (0 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+ (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
};
u8 channels;
unsigned int reg_value;
@@ -167,22 +181,23 @@ void oxygen_update_dac_routing(struct oxygen *chip)
OXYGEN_PLAY_DAC1_SOURCE_MASK |
OXYGEN_PLAY_DAC2_SOURCE_MASK |
OXYGEN_PLAY_DAC3_SOURCE_MASK);
+ if (chip->model.update_center_lfe_mix)
+ chip->model.update_center_lfe_mix(chip, chip->dac_routing > 2);
}
static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
{
struct oxygen *chip = ctl->private_data;
- unsigned int count = 2 + (chip->model.dac_channels == 8);
+ unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3;
int changed;
+ if (value->value.enumerated.item[0] >= count)
+ return -EINVAL;
mutex_lock(&chip->mutex);
changed = value->value.enumerated.item[0] != chip->dac_routing;
if (changed) {
- chip->dac_routing = min(value->value.enumerated.item[0],
- count - 1);
- spin_lock_irq(&chip->reg_lock);
+ chip->dac_routing = value->value.enumerated.item[0];
oxygen_update_dac_routing(chip);
- spin_unlock_irq(&chip->reg_lock);
}
mutex_unlock(&chip->mutex);
return changed;
@@ -790,7 +805,7 @@ static const struct {
.controls = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Analog Input Monitor Switch",
+ .name = "Analog Input Monitor Playback Switch",
.info = snd_ctl_boolean_mono_info,
.get = monitor_get,
.put = monitor_put,
@@ -798,7 +813,7 @@ static const struct {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Analog Input Monitor Volume",
+ .name = "Analog Input Monitor Playback Volume",
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = monitor_volume_info,
@@ -815,7 +830,7 @@ static const struct {
.controls = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Analog Input Monitor Switch",
+ .name = "Analog Input Monitor Playback Switch",
.info = snd_ctl_boolean_mono_info,
.get = monitor_get,
.put = monitor_put,
@@ -823,7 +838,7 @@ static const struct {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Analog Input Monitor Volume",
+ .name = "Analog Input Monitor Playback Volume",
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = monitor_volume_info,
@@ -840,7 +855,7 @@ static const struct {
.controls = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Analog Input Monitor Switch",
+ .name = "Analog Input Monitor Playback Switch",
.index = 1,
.info = snd_ctl_boolean_mono_info,
.get = monitor_get,
@@ -849,7 +864,7 @@ static const struct {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Analog Input Monitor Volume",
+ .name = "Analog Input Monitor Playback Volume",
.index = 1,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ,
@@ -867,7 +882,7 @@ static const struct {
.controls = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Digital Input Monitor Switch",
+ .name = "Digital Input Monitor Playback Switch",
.info = snd_ctl_boolean_mono_info,
.get = monitor_get,
.put = monitor_put,
@@ -875,7 +890,7 @@ static const struct {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Digital Input Monitor Volume",
+ .name = "Digital Input Monitor Playback Volume",
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ,
.info = monitor_volume_info,
@@ -954,6 +969,9 @@ static int add_controls(struct oxygen *chip,
if (err == 1)
continue;
}
+ if (!strcmp(template.name, "Stereo Upmixing") &&
+ chip->model.dac_channels == 2)
+ 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 ef2345d82b86..9dff6954c397 100644
--- a/sound/pci/oxygen/oxygen_pcm.c
+++ b/sound/pci/oxygen/oxygen_pcm.c
@@ -271,13 +271,16 @@ static unsigned int oxygen_rate(struct snd_pcm_hw_params *hw_params)
}
}
-static unsigned int oxygen_i2s_mclk(struct snd_pcm_hw_params *hw_params)
+unsigned int oxygen_default_i2s_mclk(struct oxygen *chip,
+ unsigned int channel,
+ struct snd_pcm_hw_params *hw_params)
{
if (params_rate(hw_params) <= 96000)
return OXYGEN_I2S_MCLK_256;
else
return OXYGEN_I2S_MCLK_128;
}
+EXPORT_SYMBOL(oxygen_default_i2s_mclk);
static unsigned int oxygen_i2s_bits(struct snd_pcm_hw_params *hw_params)
{
@@ -354,7 +357,7 @@ static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream,
OXYGEN_REC_FORMAT_A_MASK);
oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT,
oxygen_rate(hw_params) |
- oxygen_i2s_mclk(hw_params) |
+ chip->model.get_i2s_mclk(chip, PCM_A, hw_params) |
chip->model.adc_i2s_format |
oxygen_i2s_bits(hw_params),
OXYGEN_I2S_RATE_MASK |
@@ -390,7 +393,8 @@ static int oxygen_rec_b_hw_params(struct snd_pcm_substream *substream,
if (!is_ac97)
oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT,
oxygen_rate(hw_params) |
- oxygen_i2s_mclk(hw_params) |
+ chip->model.get_i2s_mclk(chip, PCM_B,
+ hw_params) |
chip->model.adc_i2s_format |
oxygen_i2s_bits(hw_params),
OXYGEN_I2S_RATE_MASK |
@@ -435,6 +439,7 @@ static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream,
if (err < 0)
return err;
+ mutex_lock(&chip->mutex);
spin_lock_irq(&chip->reg_lock);
oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
OXYGEN_SPDIF_OUT_ENABLE);
@@ -446,6 +451,7 @@ static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream,
OXYGEN_SPDIF_OUT_RATE_MASK);
oxygen_update_spdif_source(chip);
spin_unlock_irq(&chip->reg_lock);
+ mutex_unlock(&chip->mutex);
return 0;
}
@@ -459,6 +465,7 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream,
if (err < 0)
return err;
+ mutex_lock(&chip->mutex);
spin_lock_irq(&chip->reg_lock);
oxygen_write8_masked(chip, OXYGEN_PLAY_CHANNELS,
oxygen_play_channels(hw_params),
@@ -469,18 +476,18 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream,
oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT,
oxygen_rate(hw_params) |
chip->model.dac_i2s_format |
- oxygen_i2s_mclk(hw_params) |
+ chip->model.get_i2s_mclk(chip, PCM_MULTICH,
+ hw_params) |
oxygen_i2s_bits(hw_params),
OXYGEN_I2S_RATE_MASK |
OXYGEN_I2S_FORMAT_MASK |
OXYGEN_I2S_MCLK_MASK |
OXYGEN_I2S_BITS_MASK);
- oxygen_update_dac_routing(chip);
oxygen_update_spdif_source(chip);
spin_unlock_irq(&chip->reg_lock);
- mutex_lock(&chip->mutex);
chip->model.set_dac_params(chip, hw_params);
+ oxygen_update_dac_routing(chip);
mutex_unlock(&chip->mutex);
return 0;
}
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
index 6ebcb6bdd712..6accaf9580b2 100644
--- a/sound/pci/oxygen/virtuoso.c
+++ b/sound/pci/oxygen/virtuoso.c
@@ -17,145 +17,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-/*
- * Xonar D2/D2X
- * ------------
- *
- * CMI8788:
- *
- * SPI 0 -> 1st PCM1796 (front)
- * SPI 1 -> 2nd PCM1796 (surround)
- * SPI 2 -> 3rd PCM1796 (center/LFE)
- * SPI 4 -> 4th PCM1796 (back)
- *
- * GPIO 2 -> M0 of CS5381
- * GPIO 3 -> M1 of CS5381
- * GPIO 5 <- external power present (D2X only)
- * GPIO 7 -> ALT
- * GPIO 8 -> enable output to speakers
- */
-
-/*
- * Xonar D1/DX
- * -----------
- *
- * CMI8788:
- *
- * I²C <-> CS4398 (front)
- * <-> CS4362A (surround, center/LFE, back)
- *
- * GPI 0 <- external power present (DX only)
- *
- * GPIO 0 -> enable output to speakers
- * GPIO 1 -> enable front panel I/O
- * GPIO 2 -> M0 of CS5361
- * GPIO 3 -> M1 of CS5361
- * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
- *
- * CS4398:
- *
- * AD0 <- 1
- * AD1 <- 1
- *
- * CS4362A:
- *
- * AD0 <- 0
- */
-
-/*
- * Xonar HDAV1.3 (Deluxe)
- * ----------------------
- *
- * CMI8788:
- *
- * I²C <-> PCM1796 (front)
- *
- * GPI 0 <- external power present
- *
- * GPIO 0 -> enable output to speakers
- * GPIO 2 -> M0 of CS5381
- * GPIO 3 -> M1 of CS5381
- * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
- *
- * TXD -> HDMI controller
- * RXD <- HDMI controller
- *
- * PCM1796 front: AD1,0 <- 0,0
- *
- * no daughterboard
- * ----------------
- *
- * GPIO 4 <- 1
- *
- * H6 daughterboard
- * ----------------
- *
- * GPIO 4 <- 0
- * GPIO 5 <- 0
- *
- * I²C <-> PCM1796 (surround)
- * <-> PCM1796 (center/LFE)
- * <-> PCM1796 (back)
- *
- * PCM1796 surround: AD1,0 <- 0,1
- * PCM1796 center/LFE: AD1,0 <- 1,0
- * PCM1796 back: AD1,0 <- 1,1
- *
- * unknown daughterboard
- * ---------------------
- *
- * GPIO 4 <- 0
- * GPIO 5 <- 1
- *
- * I²C <-> CS4362A (surround, center/LFE, back)
- *
- * CS4362A: AD0 <- 0
- */
-
-/*
- * Xonar Essence ST (Deluxe)/STX
- * -----------------------------
- *
- * CMI8788:
- *
- * I²C <-> PCM1792A
- *
- * GPI 0 <- external power present
- *
- * GPIO 0 -> enable output to speakers
- * GPIO 1 -> route HP to front panel (0) or rear jack (1)
- * GPIO 2 -> M0 of CS5381
- * GPIO 3 -> M1 of CS5381
- * GPIO 7 -> route output to speaker jacks (0) or HP (1)
- * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
- *
- * PCM1792A:
- *
- * AD0 <- 0
- *
- * H6 daughterboard
- * ----------------
- *
- * GPIO 4 <- 0
- * GPIO 5 <- 0
- */
-
#include <linux/pci.h>
#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <sound/ac97_codec.h>
-#include <sound/asoundef.h>
-#include <sound/control.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/tlv.h>
-#include "oxygen.h"
-#include "cm9780.h"
-#include "pcm1796.h"
-#include "cs4398.h"
-#include "cs4362a.h"
+#include "xonar.h"
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_DESCRIPTION("Asus AVx00 driver");
@@ -173,972 +40,28 @@ MODULE_PARM_DESC(id, "ID string");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "enable card");
-enum {
- MODEL_D2,
- MODEL_D2X,
- MODEL_D1,
- MODEL_DX,
- MODEL_HDAV, /* without daughterboard */
- MODEL_HDAV_H6, /* with H6 daughterboard */
- MODEL_ST,
- MODEL_ST_H6,
- MODEL_STX,
-};
-
static struct pci_device_id xonar_ids[] __devinitdata = {
- { OXYGEN_PCI_SUBID(0x1043, 0x8269), .driver_data = MODEL_D2 },
- { OXYGEN_PCI_SUBID(0x1043, 0x8275), .driver_data = MODEL_DX },
- { OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X },
- { OXYGEN_PCI_SUBID(0x1043, 0x8314), .driver_data = MODEL_HDAV },
- { OXYGEN_PCI_SUBID(0x1043, 0x8327), .driver_data = MODEL_DX },
- { OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 },
- { OXYGEN_PCI_SUBID(0x1043, 0x835c), .driver_data = MODEL_STX },
- { OXYGEN_PCI_SUBID(0x1043, 0x835d), .driver_data = MODEL_ST },
+ { OXYGEN_PCI_SUBID(0x1043, 0x8269) },
+ { OXYGEN_PCI_SUBID(0x1043, 0x8275) },
+ { OXYGEN_PCI_SUBID(0x1043, 0x82b7) },
+ { OXYGEN_PCI_SUBID(0x1043, 0x8314) },
+ { OXYGEN_PCI_SUBID(0x1043, 0x8327) },
+ { OXYGEN_PCI_SUBID(0x1043, 0x834f) },
+ { OXYGEN_PCI_SUBID(0x1043, 0x835c) },
+ { OXYGEN_PCI_SUBID(0x1043, 0x835d) },
{ OXYGEN_PCI_SUBID_BROKEN_EEPROM },
{ }
};
MODULE_DEVICE_TABLE(pci, xonar_ids);
-
-#define GPIO_CS53x1_M_MASK 0x000c
-#define GPIO_CS53x1_M_SINGLE 0x0000
-#define GPIO_CS53x1_M_DOUBLE 0x0004
-#define GPIO_CS53x1_M_QUAD 0x0008
-
-#define GPIO_D2X_EXT_POWER 0x0020
-#define GPIO_D2_ALT 0x0080
-#define GPIO_D2_OUTPUT_ENABLE 0x0100
-
-#define GPI_DX_EXT_POWER 0x01
-#define GPIO_DX_OUTPUT_ENABLE 0x0001
-#define GPIO_DX_FRONT_PANEL 0x0002
-#define GPIO_DX_INPUT_ROUTE 0x0100
-
-#define GPIO_DB_MASK 0x0030
-#define GPIO_DB_H6 0x0000
-#define GPIO_DB_XX 0x0020
-
-#define GPIO_ST_HP_REAR 0x0002
-#define GPIO_ST_HP 0x0080
-
-#define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ADx=i, /W=0 */
-#define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */
-#define I2C_DEVICE_CS4362A 0x30 /* 001100, AD0=0, /W=0 */
-
-struct xonar_data {
- unsigned int anti_pop_delay;
- unsigned int dacs;
- u16 output_enable_bit;
- u8 ext_power_reg;
- u8 ext_power_int_reg;
- u8 ext_power_bit;
- u8 has_power;
- u8 pcm1796_oversampling;
- u8 cs4398_fm;
- u8 cs4362a_fm;
- u8 hdmi_params[5];
-};
-
-static void xonar_gpio_changed(struct oxygen *chip);
-
-static inline void pcm1796_write_spi(struct oxygen *chip, unsigned int codec,
- u8 reg, u8 value)
-{
- /* maps ALSA channel pair number to SPI output */
- static const u8 codec_map[4] = {
- 0, 1, 2, 4
- };
- oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
- OXYGEN_SPI_DATA_LENGTH_2 |
- OXYGEN_SPI_CLOCK_160 |
- (codec_map[codec] << OXYGEN_SPI_CODEC_SHIFT) |
- OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
- (reg << 8) | value);
-}
-
-static inline void pcm1796_write_i2c(struct oxygen *chip, unsigned int codec,
- u8 reg, u8 value)
-{
- oxygen_write_i2c(chip, I2C_DEVICE_PCM1796(codec), reg, value);
-}
-
-static void pcm1796_write(struct oxygen *chip, unsigned int codec,
- u8 reg, u8 value)
-{
- if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) ==
- OXYGEN_FUNCTION_SPI)
- pcm1796_write_spi(chip, codec, reg, value);
- else
- pcm1796_write_i2c(chip, codec, reg, value);
-}
-
-static void cs4398_write(struct oxygen *chip, u8 reg, u8 value)
-{
- oxygen_write_i2c(chip, I2C_DEVICE_CS4398, reg, value);
-}
-
-static void cs4362a_write(struct oxygen *chip, u8 reg, u8 value)
-{
- oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value);
-}
-
-static void hdmi_write_command(struct oxygen *chip, u8 command,
- unsigned int count, const u8 *params)
-{
- unsigned int i;
- u8 checksum;
-
- oxygen_write_uart(chip, 0xfb);
- oxygen_write_uart(chip, 0xef);
- oxygen_write_uart(chip, command);
- oxygen_write_uart(chip, count);
- for (i = 0; i < count; ++i)
- oxygen_write_uart(chip, params[i]);
- checksum = 0xfb + 0xef + command + count;
- for (i = 0; i < count; ++i)
- checksum += params[i];
- oxygen_write_uart(chip, checksum);
-}
-
-static void xonar_enable_output(struct oxygen *chip)
-{
- struct xonar_data *data = chip->model_data;
-
- msleep(data->anti_pop_delay);
- oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit);
-}
-
-static void xonar_common_init(struct oxygen *chip)
-{
- struct xonar_data *data = chip->model_data;
-
- if (data->ext_power_reg) {
- oxygen_set_bits8(chip, data->ext_power_int_reg,
- data->ext_power_bit);
- chip->interrupt_mask |= OXYGEN_INT_GPIO;
- chip->model.gpio_changed = xonar_gpio_changed;
- data->has_power = !!(oxygen_read8(chip, data->ext_power_reg)
- & data->ext_power_bit);
- }
- oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
- GPIO_CS53x1_M_MASK | data->output_enable_bit);
- oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
- GPIO_CS53x1_M_SINGLE, GPIO_CS53x1_M_MASK);
- oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC);
- xonar_enable_output(chip);
-}
-
-static void update_pcm1796_volume(struct oxygen *chip)
-{
- struct xonar_data *data = chip->model_data;
- unsigned int i;
-
- for (i = 0; i < data->dacs; ++i) {
- pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]);
- pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]);
- }
-}
-
-static void update_pcm1796_mute(struct oxygen *chip)
-{
- struct xonar_data *data = chip->model_data;
- unsigned int i;
- u8 value;
-
- value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD;
- if (chip->dac_mute)
- value |= PCM1796_MUTE;
- for (i = 0; i < data->dacs; ++i)
- pcm1796_write(chip, i, 18, value);
-}
-
-static void pcm1796_init(struct oxygen *chip)
-{
- struct xonar_data *data = chip->model_data;
- unsigned int i;
-
- for (i = 0; i < data->dacs; ++i) {
- pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1);
- pcm1796_write(chip, i, 20, data->pcm1796_oversampling);
- pcm1796_write(chip, i, 21, 0);
- }
- update_pcm1796_mute(chip); /* set ATLD before ATL/ATR */
- update_pcm1796_volume(chip);
-}
-
-static void xonar_d2_init(struct oxygen *chip)
-{
- struct xonar_data *data = chip->model_data;
-
- data->anti_pop_delay = 300;
- data->dacs = 4;
- data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE;
- data->pcm1796_oversampling = PCM1796_OS_64;
-
- pcm1796_init(chip);
-
- oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2_ALT);
- oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_D2_ALT);
-
- xonar_common_init(chip);
-
- snd_component_add(chip->card, "PCM1796");
- snd_component_add(chip->card, "CS5381");
-}
-
-static void xonar_d2x_init(struct oxygen *chip)
-{
- struct xonar_data *data = chip->model_data;
-
- data->ext_power_reg = OXYGEN_GPIO_DATA;
- data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK;
- data->ext_power_bit = GPIO_D2X_EXT_POWER;
- oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2X_EXT_POWER);
-
- xonar_d2_init(chip);
-}
-
-static void update_cs4362a_volumes(struct oxygen *chip)
-{
- u8 mute;
-
- mute = chip->dac_mute ? CS4362A_MUTE : 0;
- cs4362a_write(chip, 7, (127 - chip->dac_volume[2]) | mute);
- cs4362a_write(chip, 8, (127 - chip->dac_volume[3]) | mute);
- cs4362a_write(chip, 10, (127 - chip->dac_volume[4]) | mute);
- cs4362a_write(chip, 11, (127 - chip->dac_volume[5]) | mute);
- cs4362a_write(chip, 13, (127 - chip->dac_volume[6]) | mute);
- cs4362a_write(chip, 14, (127 - chip->dac_volume[7]) | mute);
-}
-
-static void update_cs43xx_volume(struct oxygen *chip)
-{
- cs4398_write(chip, 5, (127 - chip->dac_volume[0]) * 2);
- cs4398_write(chip, 6, (127 - chip->dac_volume[1]) * 2);
- update_cs4362a_volumes(chip);
-}
-
-static void update_cs43xx_mute(struct oxygen *chip)
-{
- u8 reg;
-
- reg = CS4398_MUTEP_LOW | CS4398_PAMUTE;
- if (chip->dac_mute)
- reg |= CS4398_MUTE_B | CS4398_MUTE_A;
- cs4398_write(chip, 4, reg);
- update_cs4362a_volumes(chip);
-}
-
-static void cs43xx_init(struct oxygen *chip)
-{
- struct xonar_data *data = chip->model_data;
-
- /* set CPEN (control port mode) and power down */
- cs4398_write(chip, 8, CS4398_CPEN | CS4398_PDN);
- cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN);
- /* configure */
- cs4398_write(chip, 2, data->cs4398_fm);
- cs4398_write(chip, 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L);
- cs4398_write(chip, 7, CS4398_RMP_DN | CS4398_RMP_UP |
- CS4398_ZERO_CROSS | CS4398_SOFT_RAMP);
- cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST);
- cs4362a_write(chip, 0x03, CS4362A_MUTEC_6 | CS4362A_AMUTE |
- CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP);
- cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE);
- cs4362a_write(chip, 0x05, 0);
- cs4362a_write(chip, 0x06, data->cs4362a_fm);
- cs4362a_write(chip, 0x09, data->cs4362a_fm);
- cs4362a_write(chip, 0x0c, data->cs4362a_fm);
- update_cs43xx_volume(chip);
- update_cs43xx_mute(chip);
- /* clear power down */
- cs4398_write(chip, 8, CS4398_CPEN);
- cs4362a_write(chip, 0x01, CS4362A_CPEN);
-}
-
-static void xonar_d1_init(struct oxygen *chip)
-{
- struct xonar_data *data = chip->model_data;
-
- data->anti_pop_delay = 800;
- data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE;
- data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST;
- data->cs4362a_fm = CS4362A_FM_SINGLE |
- CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
-
- oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
- OXYGEN_2WIRE_LENGTH_8 |
- OXYGEN_2WIRE_INTERRUPT_MASK |
- OXYGEN_2WIRE_SPEED_FAST);
-
- cs43xx_init(chip);
-
- oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
- GPIO_DX_FRONT_PANEL | GPIO_DX_INPUT_ROUTE);
- oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
- GPIO_DX_FRONT_PANEL | GPIO_DX_INPUT_ROUTE);
-
- xonar_common_init(chip);
-
- snd_component_add(chip->card, "CS4398");
- snd_component_add(chip->card, "CS4362A");
- snd_component_add(chip->card, "CS5361");
-}
-
-static void xonar_dx_init(struct oxygen *chip)
-{
- struct xonar_data *data = chip->model_data;
-
- data->ext_power_reg = OXYGEN_GPI_DATA;
- data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
- data->ext_power_bit = GPI_DX_EXT_POWER;
-
- xonar_d1_init(chip);
-}
-
-static void xonar_hdav_init(struct oxygen *chip)
-{
- struct xonar_data *data = chip->model_data;
- u8 param;
-
- oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
- OXYGEN_2WIRE_LENGTH_8 |
- OXYGEN_2WIRE_INTERRUPT_MASK |
- OXYGEN_2WIRE_SPEED_FAST);
-
- data->anti_pop_delay = 100;
- data->dacs = chip->model.private_data == MODEL_HDAV_H6 ? 4 : 1;
- data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE;
- data->ext_power_reg = OXYGEN_GPI_DATA;
- data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
- data->ext_power_bit = GPI_DX_EXT_POWER;
- data->pcm1796_oversampling = PCM1796_OS_64;
-
- pcm1796_init(chip);
-
- oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DX_INPUT_ROUTE);
- oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DX_INPUT_ROUTE);
-
- oxygen_reset_uart(chip);
- param = 0;
- hdmi_write_command(chip, 0x61, 1, &param);
- param = 1;
- hdmi_write_command(chip, 0x74, 1, &param);
- data->hdmi_params[1] = IEC958_AES3_CON_FS_48000;
- data->hdmi_params[4] = 1;
- hdmi_write_command(chip, 0x54, 5, data->hdmi_params);
-
- xonar_common_init(chip);
-
- snd_component_add(chip->card, "PCM1796");
- snd_component_add(chip->card, "CS5381");
-}
-
-static void xonar_st_init(struct oxygen *chip)
-{
- struct xonar_data *data = chip->model_data;
-
- oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
- OXYGEN_2WIRE_LENGTH_8 |
- OXYGEN_2WIRE_INTERRUPT_MASK |
- OXYGEN_2WIRE_SPEED_FAST);
-
- if (chip->model.private_data == MODEL_ST_H6)
- chip->model.dac_channels = 8;
- data->anti_pop_delay = 100;
- data->dacs = chip->model.private_data == MODEL_ST_H6 ? 4 : 1;
- data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE;
- data->pcm1796_oversampling = PCM1796_OS_64;
-
- pcm1796_init(chip);
-
- oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
- GPIO_DX_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
- oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
- GPIO_DX_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
-
- xonar_common_init(chip);
-
- snd_component_add(chip->card, "PCM1792A");
- snd_component_add(chip->card, "CS5381");
-}
-
-static void xonar_stx_init(struct oxygen *chip)
-{
- struct xonar_data *data = chip->model_data;
-
- data->ext_power_reg = OXYGEN_GPI_DATA;
- data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
- data->ext_power_bit = GPI_DX_EXT_POWER;
-
- xonar_st_init(chip);
-}
-
-static void xonar_disable_output(struct oxygen *chip)
-{
- struct xonar_data *data = chip->model_data;
-
- oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit);
-}
-
-static void xonar_d2_cleanup(struct oxygen *chip)
-{
- xonar_disable_output(chip);
-}
-
-static void xonar_d1_cleanup(struct oxygen *chip)
-{
- xonar_disable_output(chip);
- cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN);
- oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC);
-}
-
-static void xonar_hdav_cleanup(struct oxygen *chip)
-{
- u8 param = 0;
-
- hdmi_write_command(chip, 0x74, 1, &param);
- xonar_disable_output(chip);
-}
-
-static void xonar_st_cleanup(struct oxygen *chip)
-{
- xonar_disable_output(chip);
-}
-
-static void xonar_d2_suspend(struct oxygen *chip)
-{
- xonar_d2_cleanup(chip);
-}
-
-static void xonar_d1_suspend(struct oxygen *chip)
-{
- xonar_d1_cleanup(chip);
-}
-
-static void xonar_hdav_suspend(struct oxygen *chip)
-{
- xonar_hdav_cleanup(chip);
- msleep(2);
-}
-
-static void xonar_st_suspend(struct oxygen *chip)
-{
- xonar_st_cleanup(chip);
-}
-
-static void xonar_d2_resume(struct oxygen *chip)
-{
- pcm1796_init(chip);
- xonar_enable_output(chip);
-}
-
-static void xonar_d1_resume(struct oxygen *chip)
-{
- oxygen_set_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC);
- msleep(1);
- cs43xx_init(chip);
- xonar_enable_output(chip);
-}
-
-static void xonar_hdav_resume(struct oxygen *chip)
-{
- struct xonar_data *data = chip->model_data;
- u8 param;
-
- oxygen_reset_uart(chip);
- param = 0;
- hdmi_write_command(chip, 0x61, 1, &param);
- param = 1;
- hdmi_write_command(chip, 0x74, 1, &param);
- hdmi_write_command(chip, 0x54, 5, data->hdmi_params);
- pcm1796_init(chip);
- xonar_enable_output(chip);
-}
-
-static void xonar_st_resume(struct oxygen *chip)
-{
- pcm1796_init(chip);
- xonar_enable_output(chip);
-}
-
-static void xonar_hdav_pcm_hardware_filter(unsigned int channel,
- struct snd_pcm_hardware *hardware)
-{
- if (channel == PCM_MULTICH) {
- hardware->rates = SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000 |
- SNDRV_PCM_RATE_96000 |
- SNDRV_PCM_RATE_192000;
- hardware->rate_min = 44100;
- }
-}
-
-static void set_pcm1796_params(struct oxygen *chip,
- struct snd_pcm_hw_params *params)
-{
- struct xonar_data *data = chip->model_data;
- unsigned int i;
-
- data->pcm1796_oversampling =
- params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64;
- for (i = 0; i < data->dacs; ++i)
- pcm1796_write(chip, i, 20, data->pcm1796_oversampling);
-}
-
-static void set_cs53x1_params(struct oxygen *chip,
- struct snd_pcm_hw_params *params)
-{
- unsigned int value;
-
- if (params_rate(params) <= 54000)
- value = GPIO_CS53x1_M_SINGLE;
- else if (params_rate(params) <= 108000)
- value = GPIO_CS53x1_M_DOUBLE;
- else
- value = GPIO_CS53x1_M_QUAD;
- oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
- value, GPIO_CS53x1_M_MASK);
-}
-
-static void set_cs43xx_params(struct oxygen *chip,
- struct snd_pcm_hw_params *params)
-{
- struct xonar_data *data = chip->model_data;
-
- data->cs4398_fm = CS4398_DEM_NONE | CS4398_DIF_LJUST;
- data->cs4362a_fm = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
- if (params_rate(params) <= 50000) {
- data->cs4398_fm |= CS4398_FM_SINGLE;
- data->cs4362a_fm |= CS4362A_FM_SINGLE;
- } else if (params_rate(params) <= 100000) {
- data->cs4398_fm |= CS4398_FM_DOUBLE;
- data->cs4362a_fm |= CS4362A_FM_DOUBLE;
- } else {
- data->cs4398_fm |= CS4398_FM_QUAD;
- data->cs4362a_fm |= CS4362A_FM_QUAD;
- }
- cs4398_write(chip, 2, data->cs4398_fm);
- cs4362a_write(chip, 0x06, data->cs4362a_fm);
- cs4362a_write(chip, 0x09, data->cs4362a_fm);
- cs4362a_write(chip, 0x0c, data->cs4362a_fm);
-}
-
-static void set_hdmi_params(struct oxygen *chip,
- struct snd_pcm_hw_params *params)
-{
- struct xonar_data *data = chip->model_data;
-
- data->hdmi_params[0] = 0; /* 1 = non-audio */
- switch (params_rate(params)) {
- case 44100:
- data->hdmi_params[1] = IEC958_AES3_CON_FS_44100;
- break;
- case 48000:
- data->hdmi_params[1] = IEC958_AES3_CON_FS_48000;
- break;
- default: /* 96000 */
- data->hdmi_params[1] = IEC958_AES3_CON_FS_96000;
- break;
- case 192000:
- data->hdmi_params[1] = IEC958_AES3_CON_FS_192000;
- break;
- }
- data->hdmi_params[2] = params_channels(params) / 2 - 1;
- if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE)
- data->hdmi_params[3] = 0;
- else
- data->hdmi_params[3] = 0xc0;
- data->hdmi_params[4] = 1; /* ? */
- hdmi_write_command(chip, 0x54, 5, data->hdmi_params);
-}
-
-static void set_hdav_params(struct oxygen *chip,
- struct snd_pcm_hw_params *params)
-{
- set_pcm1796_params(chip, params);
- set_hdmi_params(chip, params);
-}
-
-static void xonar_gpio_changed(struct oxygen *chip)
-{
- struct xonar_data *data = chip->model_data;
- u8 has_power;
-
- has_power = !!(oxygen_read8(chip, data->ext_power_reg)
- & data->ext_power_bit);
- if (has_power != data->has_power) {
- data->has_power = has_power;
- if (has_power) {
- snd_printk(KERN_NOTICE "power restored\n");
- } else {
- snd_printk(KERN_CRIT
- "Hey! Don't unplug the power cable!\n");
- /* TODO: stop PCMs */
- }
- }
-}
-
-static void xonar_hdav_uart_input(struct oxygen *chip)
-{
- if (chip->uart_input_count >= 2 &&
- chip->uart_input[chip->uart_input_count - 2] == 'O' &&
- chip->uart_input[chip->uart_input_count - 1] == 'K') {
- printk(KERN_DEBUG "message from Xonar HDAV HDMI chip received:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
- chip->uart_input, chip->uart_input_count);
- chip->uart_input_count = 0;
- }
-}
-
-static int gpio_bit_switch_get(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- u16 bit = ctl->private_value;
-
- value->value.integer.value[0] =
- !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit);
- return 0;
-}
-
-static int gpio_bit_switch_put(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- u16 bit = ctl->private_value;
- u16 old_bits, new_bits;
- int changed;
-
- spin_lock_irq(&chip->reg_lock);
- old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
- if (value->value.integer.value[0])
- new_bits = old_bits | bit;
- else
- new_bits = old_bits & ~bit;
- changed = new_bits != old_bits;
- if (changed)
- oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits);
- spin_unlock_irq(&chip->reg_lock);
- return changed;
-}
-
-static const struct snd_kcontrol_new alt_switch = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Analog Loopback Switch",
- .info = snd_ctl_boolean_mono_info,
- .get = gpio_bit_switch_get,
- .put = gpio_bit_switch_put,
- .private_value = GPIO_D2_ALT,
-};
-
-static const struct snd_kcontrol_new front_panel_switch = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Front Panel Switch",
- .info = snd_ctl_boolean_mono_info,
- .get = gpio_bit_switch_get,
- .put = gpio_bit_switch_put,
- .private_value = GPIO_DX_FRONT_PANEL,
-};
-
-static int st_output_switch_info(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_info *info)
-{
- static const char *const names[3] = {
- "Speakers", "Headphones", "FP Headphones"
- };
-
- info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- info->count = 1;
- info->value.enumerated.items = 3;
- if (info->value.enumerated.item >= 3)
- info->value.enumerated.item = 2;
- strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
- return 0;
-}
-
-static int st_output_switch_get(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- u16 gpio;
-
- gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA);
- if (!(gpio & GPIO_ST_HP))
- value->value.enumerated.item[0] = 0;
- else if (gpio & GPIO_ST_HP_REAR)
- value->value.enumerated.item[0] = 1;
- else
- value->value.enumerated.item[0] = 2;
- return 0;
-}
-
-
-static int st_output_switch_put(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- u16 gpio_old, gpio;
-
- mutex_lock(&chip->mutex);
- gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA);
- gpio = gpio_old;
- switch (value->value.enumerated.item[0]) {
- case 0:
- gpio &= ~(GPIO_ST_HP | GPIO_ST_HP_REAR);
- break;
- case 1:
- gpio |= GPIO_ST_HP | GPIO_ST_HP_REAR;
- break;
- case 2:
- gpio = (gpio | GPIO_ST_HP) & ~GPIO_ST_HP_REAR;
- break;
- }
- oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio);
- mutex_unlock(&chip->mutex);
- return gpio != gpio_old;
-}
-
-static const struct snd_kcontrol_new st_output_switch = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Analog Output",
- .info = st_output_switch_info,
- .get = st_output_switch_get,
- .put = st_output_switch_put,
-};
-
-static void xonar_line_mic_ac97_switch(struct oxygen *chip,
- unsigned int reg, unsigned int mute)
-{
- if (reg == AC97_LINE) {
- spin_lock_irq(&chip->reg_lock);
- oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
- mute ? GPIO_DX_INPUT_ROUTE : 0,
- GPIO_DX_INPUT_ROUTE);
- spin_unlock_irq(&chip->reg_lock);
- }
-}
-
-static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -6000, 50, 0);
-static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0);
-
-static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
-{
- if (!strncmp(template->name, "CD Capture ", 11))
- /* CD in is actually connected to the video in pin */
- template->private_value ^= AC97_CD ^ AC97_VIDEO;
- return 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_st_control_filter(struct snd_kcontrol_new *template)
-{
- if (!strncmp(template->name, "CD Capture ", 11))
- return 1; /* no CD input */
- if (!strcmp(template->name, "Stereo Upmixing"))
- return 1; /* stereo only - we don't need upmixing */
- return 0;
-}
-
-static int xonar_d2_mixer_init(struct oxygen *chip)
-{
- return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip));
-}
-
-static int xonar_d1_mixer_init(struct oxygen *chip)
-{
- return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip));
-}
-
-static int xonar_st_mixer_init(struct oxygen *chip)
-{
- return snd_ctl_add(chip->card, snd_ctl_new1(&st_output_switch, chip));
-}
-
-static const struct oxygen_model model_xonar_d2 = {
- .longname = "Asus Virtuoso 200",
- .chip = "AV200",
- .init = xonar_d2_init,
- .control_filter = xonar_d2_control_filter,
- .mixer_init = xonar_d2_mixer_init,
- .cleanup = xonar_d2_cleanup,
- .suspend = xonar_d2_suspend,
- .resume = xonar_d2_resume,
- .set_dac_params = set_pcm1796_params,
- .set_adc_params = set_cs53x1_params,
- .update_dac_volume = update_pcm1796_volume,
- .update_dac_mute = update_pcm1796_mute,
- .dac_tlv = pcm1796_db_scale,
- .model_data_size = sizeof(struct xonar_data),
- .device_config = PLAYBACK_0_TO_I2S |
- PLAYBACK_1_TO_SPDIF |
- CAPTURE_0_FROM_I2S_2 |
- CAPTURE_1_FROM_SPDIF |
- MIDI_OUTPUT |
- MIDI_INPUT,
- .dac_channels = 8,
- .dac_volume_min = 255 - 2*60,
- .dac_volume_max = 255,
- .misc_flags = OXYGEN_MISC_MIDI,
- .function_flags = OXYGEN_FUNCTION_SPI |
- OXYGEN_FUNCTION_ENABLE_SPI_4_5,
- .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
- .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-};
-
-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,
- .resume = xonar_d1_resume,
- .set_dac_params = set_cs43xx_params,
- .set_adc_params = set_cs53x1_params,
- .update_dac_volume = update_cs43xx_volume,
- .update_dac_mute = update_cs43xx_mute,
- .ac97_switch = xonar_line_mic_ac97_switch,
- .dac_tlv = cs4362a_db_scale,
- .model_data_size = sizeof(struct xonar_data),
- .device_config = PLAYBACK_0_TO_I2S |
- PLAYBACK_1_TO_SPDIF |
- CAPTURE_0_FROM_I2S_2,
- .dac_channels = 8,
- .dac_volume_min = 127 - 60,
- .dac_volume_max = 127,
- .function_flags = OXYGEN_FUNCTION_2WIRE,
- .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
- .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-};
-
-static const struct oxygen_model model_xonar_hdav = {
- .longname = "Asus Virtuoso 200",
- .chip = "AV200",
- .init = xonar_hdav_init,
- .cleanup = xonar_hdav_cleanup,
- .suspend = xonar_hdav_suspend,
- .resume = xonar_hdav_resume,
- .pcm_hardware_filter = xonar_hdav_pcm_hardware_filter,
- .set_dac_params = set_hdav_params,
- .set_adc_params = set_cs53x1_params,
- .update_dac_volume = update_pcm1796_volume,
- .update_dac_mute = update_pcm1796_mute,
- .uart_input = xonar_hdav_uart_input,
- .ac97_switch = xonar_line_mic_ac97_switch,
- .dac_tlv = pcm1796_db_scale,
- .model_data_size = sizeof(struct xonar_data),
- .device_config = PLAYBACK_0_TO_I2S |
- PLAYBACK_1_TO_SPDIF |
- CAPTURE_0_FROM_I2S_2 |
- CAPTURE_1_FROM_SPDIF,
- .dac_channels = 8,
- .dac_volume_min = 255 - 2*60,
- .dac_volume_max = 255,
- .misc_flags = OXYGEN_MISC_MIDI,
- .function_flags = OXYGEN_FUNCTION_2WIRE,
- .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
- .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-};
-
-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,
- .resume = xonar_st_resume,
- .set_dac_params = set_pcm1796_params,
- .set_adc_params = set_cs53x1_params,
- .update_dac_volume = update_pcm1796_volume,
- .update_dac_mute = update_pcm1796_mute,
- .ac97_switch = xonar_line_mic_ac97_switch,
- .dac_tlv = pcm1796_db_scale,
- .model_data_size = sizeof(struct xonar_data),
- .device_config = PLAYBACK_0_TO_I2S |
- PLAYBACK_1_TO_SPDIF |
- CAPTURE_0_FROM_I2S_2,
- .dac_channels = 2,
- .dac_volume_min = 255 - 2*60,
- .dac_volume_max = 255,
- .function_flags = OXYGEN_FUNCTION_2WIRE,
- .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
- .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-};
-
static int __devinit get_xonar_model(struct oxygen *chip,
const struct pci_device_id *id)
{
- static const struct oxygen_model *const models[] = {
- [MODEL_D1] = &model_xonar_d1,
- [MODEL_DX] = &model_xonar_d1,
- [MODEL_D2] = &model_xonar_d2,
- [MODEL_D2X] = &model_xonar_d2,
- [MODEL_HDAV] = &model_xonar_hdav,
- [MODEL_ST] = &model_xonar_st,
- [MODEL_STX] = &model_xonar_st,
- };
- static const char *const names[] = {
- [MODEL_D1] = "Xonar D1",
- [MODEL_DX] = "Xonar DX",
- [MODEL_D2] = "Xonar D2",
- [MODEL_D2X] = "Xonar D2X",
- [MODEL_HDAV] = "Xonar HDAV1.3",
- [MODEL_HDAV_H6] = "Xonar HDAV1.3+H6",
- [MODEL_ST] = "Xonar Essence ST",
- [MODEL_ST_H6] = "Xonar Essence ST+H6",
- [MODEL_STX] = "Xonar Essence STX",
- };
- unsigned int model = id->driver_data;
-
- if (model >= ARRAY_SIZE(models) || !models[model])
- return -EINVAL;
- chip->model = *models[model];
-
- switch (model) {
- case MODEL_D2X:
- chip->model.init = xonar_d2x_init;
- break;
- case MODEL_DX:
- chip->model.init = xonar_dx_init;
- break;
- case MODEL_HDAV:
- oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
- switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) {
- case GPIO_DB_H6:
- model = MODEL_HDAV_H6;
- break;
- case GPIO_DB_XX:
- snd_printk(KERN_ERR "unknown daughterboard\n");
- return -ENODEV;
- }
- break;
- case MODEL_ST:
- oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
- switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) {
- case GPIO_DB_H6:
- model = MODEL_ST_H6;
- break;
- }
- break;
- case MODEL_STX:
- chip->model.init = xonar_stx_init;
- oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
- break;
- }
-
- chip->model.shortname = names[model];
- chip->model.private_data = model;
- return 0;
+ if (get_xonar_pcm179x_model(chip, id) >= 0)
+ return 0;
+ if (get_xonar_cs43xx_model(chip, id) >= 0)
+ return 0;
+ return -EINVAL;
}
static int __devinit xonar_probe(struct pci_dev *pci,
diff --git a/sound/pci/oxygen/xonar.h b/sound/pci/oxygen/xonar.h
new file mode 100644
index 000000000000..89b3ed814d64
--- /dev/null
+++ b/sound/pci/oxygen/xonar.h
@@ -0,0 +1,50 @@
+#ifndef XONAR_H_INCLUDED
+#define XONAR_H_INCLUDED
+
+#include "oxygen.h"
+
+struct xonar_generic {
+ unsigned int anti_pop_delay;
+ u16 output_enable_bit;
+ u8 ext_power_reg;
+ u8 ext_power_int_reg;
+ u8 ext_power_bit;
+ u8 has_power;
+};
+
+struct xonar_hdmi {
+ u8 params[5];
+};
+
+/* generic helper functions */
+
+void xonar_enable_output(struct oxygen *chip);
+void xonar_disable_output(struct oxygen *chip);
+void xonar_init_ext_power(struct oxygen *chip);
+void xonar_init_cs53x1(struct oxygen *chip);
+void xonar_set_cs53x1_params(struct oxygen *chip,
+ struct snd_pcm_hw_params *params);
+int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value);
+int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value);
+
+/* model-specific card drivers */
+
+int get_xonar_pcm179x_model(struct oxygen *chip,
+ const struct pci_device_id *id);
+int get_xonar_cs43xx_model(struct oxygen *chip,
+ const struct pci_device_id *id);
+
+/* HDMI helper functions */
+
+void xonar_hdmi_init(struct oxygen *chip, struct xonar_hdmi *data);
+void xonar_hdmi_cleanup(struct oxygen *chip);
+void xonar_hdmi_resume(struct oxygen *chip, struct xonar_hdmi *hdmi);
+void xonar_hdmi_pcm_hardware_filter(unsigned int channel,
+ struct snd_pcm_hardware *hardware);
+void xonar_set_hdmi_params(struct oxygen *chip, struct xonar_hdmi *hdmi,
+ struct snd_pcm_hw_params *params);
+void xonar_hdmi_uart_input(struct oxygen *chip);
+
+#endif
diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c
new file mode 100644
index 000000000000..16c226bfcd2b
--- /dev/null
+++ b/sound/pci/oxygen/xonar_cs43xx.c
@@ -0,0 +1,434 @@
+/*
+ * card driver for models with CS4398/CS4362A DACs (Xonar D1/DX)
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2.
+ *
+ * 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 driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Xonar D1/DX
+ * -----------
+ *
+ * CMI8788:
+ *
+ * I²C <-> CS4398 (front)
+ * <-> CS4362A (surround, center/LFE, back)
+ *
+ * GPI 0 <- external power present (DX only)
+ *
+ * GPIO 0 -> enable output to speakers
+ * GPIO 1 -> enable front panel I/O
+ * GPIO 2 -> M0 of CS5361
+ * GPIO 3 -> M1 of CS5361
+ * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
+ *
+ * CS4398:
+ *
+ * AD0 <- 1
+ * AD1 <- 1
+ *
+ * CS4362A:
+ *
+ * AD0 <- 0
+ *
+ * CM9780:
+ *
+ * GPO 0 -> route line-in (0) or AC97 output (1) to CS5361 input
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <sound/ac97_codec.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include "xonar.h"
+#include "cs4398.h"
+#include "cs4362a.h"
+
+#define GPI_EXT_POWER 0x01
+#define GPIO_D1_OUTPUT_ENABLE 0x0001
+#define GPIO_D1_FRONT_PANEL 0x0002
+#define GPIO_D1_INPUT_ROUTE 0x0100
+
+#define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */
+#define I2C_DEVICE_CS4362A 0x30 /* 001100, AD0=0, /W=0 */
+
+struct xonar_cs43xx {
+ struct xonar_generic generic;
+ u8 cs4398_regs[8];
+ u8 cs4362a_regs[15];
+};
+
+static void cs4398_write(struct oxygen *chip, u8 reg, u8 value)
+{
+ struct xonar_cs43xx *data = chip->model_data;
+
+ oxygen_write_i2c(chip, I2C_DEVICE_CS4398, reg, value);
+ if (reg < ARRAY_SIZE(data->cs4398_regs))
+ data->cs4398_regs[reg] = value;
+}
+
+static void cs4398_write_cached(struct oxygen *chip, u8 reg, u8 value)
+{
+ struct xonar_cs43xx *data = chip->model_data;
+
+ if (value != data->cs4398_regs[reg])
+ cs4398_write(chip, reg, value);
+}
+
+static void cs4362a_write(struct oxygen *chip, u8 reg, u8 value)
+{
+ struct xonar_cs43xx *data = chip->model_data;
+
+ oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value);
+ if (reg < ARRAY_SIZE(data->cs4362a_regs))
+ data->cs4362a_regs[reg] = value;
+}
+
+static void cs4362a_write_cached(struct oxygen *chip, u8 reg, u8 value)
+{
+ struct xonar_cs43xx *data = chip->model_data;
+
+ if (value != data->cs4362a_regs[reg])
+ cs4362a_write(chip, reg, value);
+}
+
+static void cs43xx_registers_init(struct oxygen *chip)
+{
+ struct xonar_cs43xx *data = chip->model_data;
+ unsigned int i;
+
+ /* set CPEN (control port mode) and power down */
+ cs4398_write(chip, 8, CS4398_CPEN | CS4398_PDN);
+ cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN);
+ /* configure */
+ cs4398_write(chip, 2, data->cs4398_regs[2]);
+ cs4398_write(chip, 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L);
+ cs4398_write(chip, 4, data->cs4398_regs[4]);
+ cs4398_write(chip, 5, data->cs4398_regs[5]);
+ cs4398_write(chip, 6, data->cs4398_regs[6]);
+ cs4398_write(chip, 7, data->cs4398_regs[7]);
+ cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST);
+ cs4362a_write(chip, 0x03, CS4362A_MUTEC_6 | CS4362A_AMUTE |
+ CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP);
+ cs4362a_write(chip, 0x04, data->cs4362a_regs[0x04]);
+ cs4362a_write(chip, 0x05, 0);
+ for (i = 6; i <= 14; ++i)
+ cs4362a_write(chip, i, data->cs4362a_regs[i]);
+ /* clear power down */
+ cs4398_write(chip, 8, CS4398_CPEN);
+ cs4362a_write(chip, 0x01, CS4362A_CPEN);
+}
+
+static void xonar_d1_init(struct oxygen *chip)
+{
+ struct xonar_cs43xx *data = chip->model_data;
+
+ data->generic.anti_pop_delay = 800;
+ data->generic.output_enable_bit = GPIO_D1_OUTPUT_ENABLE;
+ data->cs4398_regs[2] =
+ CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST;
+ data->cs4398_regs[4] = CS4398_MUTEP_LOW |
+ CS4398_MUTE_B | CS4398_MUTE_A | CS4398_PAMUTE;
+ data->cs4398_regs[5] = 60 * 2;
+ data->cs4398_regs[6] = 60 * 2;
+ data->cs4398_regs[7] = CS4398_RMP_DN | CS4398_RMP_UP |
+ CS4398_ZERO_CROSS | CS4398_SOFT_RAMP;
+ data->cs4362a_regs[4] = CS4362A_RMP_DN | CS4362A_DEM_NONE;
+ data->cs4362a_regs[6] = CS4362A_FM_SINGLE |
+ CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
+ data->cs4362a_regs[7] = 60 | CS4362A_MUTE;
+ data->cs4362a_regs[8] = 60 | CS4362A_MUTE;
+ data->cs4362a_regs[9] = data->cs4362a_regs[6];
+ data->cs4362a_regs[10] = 60 | CS4362A_MUTE;
+ data->cs4362a_regs[11] = 60 | CS4362A_MUTE;
+ data->cs4362a_regs[12] = data->cs4362a_regs[6];
+ data->cs4362a_regs[13] = 60 | CS4362A_MUTE;
+ data->cs4362a_regs[14] = 60 | CS4362A_MUTE;
+
+ oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
+ OXYGEN_2WIRE_LENGTH_8 |
+ OXYGEN_2WIRE_INTERRUPT_MASK |
+ OXYGEN_2WIRE_SPEED_FAST);
+
+ cs43xx_registers_init(chip);
+
+ oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+ GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE);
+ oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
+ GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE);
+
+ xonar_init_cs53x1(chip);
+ xonar_enable_output(chip);
+
+ snd_component_add(chip->card, "CS4398");
+ snd_component_add(chip->card, "CS4362A");
+ snd_component_add(chip->card, "CS5361");
+}
+
+static void xonar_dx_init(struct oxygen *chip)
+{
+ struct xonar_cs43xx *data = chip->model_data;
+
+ 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;
+ xonar_init_ext_power(chip);
+ xonar_d1_init(chip);
+}
+
+static void xonar_d1_cleanup(struct oxygen *chip)
+{
+ xonar_disable_output(chip);
+ cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN);
+ oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC);
+}
+
+static void xonar_d1_suspend(struct oxygen *chip)
+{
+ xonar_d1_cleanup(chip);
+}
+
+static void xonar_d1_resume(struct oxygen *chip)
+{
+ oxygen_set_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC);
+ msleep(1);
+ cs43xx_registers_init(chip);
+ xonar_enable_output(chip);
+}
+
+static void set_cs43xx_params(struct oxygen *chip,
+ struct snd_pcm_hw_params *params)
+{
+ struct xonar_cs43xx *data = chip->model_data;
+ u8 cs4398_fm, cs4362a_fm;
+
+ if (params_rate(params) <= 50000) {
+ cs4398_fm = CS4398_FM_SINGLE;
+ cs4362a_fm = CS4362A_FM_SINGLE;
+ } else if (params_rate(params) <= 100000) {
+ cs4398_fm = CS4398_FM_DOUBLE;
+ cs4362a_fm = CS4362A_FM_DOUBLE;
+ } else {
+ cs4398_fm = CS4398_FM_QUAD;
+ cs4362a_fm = CS4362A_FM_QUAD;
+ }
+ cs4398_fm |= CS4398_DEM_NONE | CS4398_DIF_LJUST;
+ cs4398_write_cached(chip, 2, cs4398_fm);
+ cs4362a_fm |= data->cs4362a_regs[6] & ~CS4362A_FM_MASK;
+ cs4362a_write_cached(chip, 6, cs4362a_fm);
+ cs4362a_write_cached(chip, 12, cs4362a_fm);
+ cs4362a_fm &= CS4362A_FM_MASK;
+ cs4362a_fm |= data->cs4362a_regs[9] & ~CS4362A_FM_MASK;
+ cs4362a_write_cached(chip, 9, cs4362a_fm);
+}
+
+static void update_cs4362a_volumes(struct oxygen *chip)
+{
+ unsigned int i;
+ u8 mute;
+
+ mute = chip->dac_mute ? CS4362A_MUTE : 0;
+ for (i = 0; i < 6; ++i)
+ cs4362a_write_cached(chip, 7 + i + i / 2,
+ (127 - chip->dac_volume[2 + i]) | mute);
+}
+
+static void update_cs43xx_volume(struct oxygen *chip)
+{
+ cs4398_write_cached(chip, 5, (127 - chip->dac_volume[0]) * 2);
+ cs4398_write_cached(chip, 6, (127 - chip->dac_volume[1]) * 2);
+ update_cs4362a_volumes(chip);
+}
+
+static void update_cs43xx_mute(struct oxygen *chip)
+{
+ u8 reg;
+
+ reg = CS4398_MUTEP_LOW | CS4398_PAMUTE;
+ if (chip->dac_mute)
+ reg |= CS4398_MUTE_B | CS4398_MUTE_A;
+ cs4398_write_cached(chip, 4, reg);
+ update_cs4362a_volumes(chip);
+}
+
+static void update_cs43xx_center_lfe_mix(struct oxygen *chip, bool mixed)
+{
+ struct xonar_cs43xx *data = chip->model_data;
+ u8 reg;
+
+ reg = data->cs4362a_regs[9] & ~CS4362A_ATAPI_MASK;
+ if (mixed)
+ reg |= CS4362A_ATAPI_B_LR | CS4362A_ATAPI_A_LR;
+ else
+ reg |= CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
+ cs4362a_write_cached(chip, 9, reg);
+}
+
+static const struct snd_kcontrol_new front_panel_switch = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Front Panel Switch",
+ .info = snd_ctl_boolean_mono_info,
+ .get = xonar_gpio_bit_switch_get,
+ .put = xonar_gpio_bit_switch_put,
+ .private_value = GPIO_D1_FRONT_PANEL,
+};
+
+static int rolloff_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ static const char *const names[2] = {
+ "Fast Roll-off", "Slow Roll-off"
+ };
+
+ info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ info->count = 1;
+ info->value.enumerated.items = 2;
+ if (info->value.enumerated.item >= 2)
+ info->value.enumerated.item = 1;
+ strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+ return 0;
+}
+
+static int rolloff_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct xonar_cs43xx *data = chip->model_data;
+
+ value->value.enumerated.item[0] =
+ (data->cs4398_regs[7] & CS4398_FILT_SEL) != 0;
+ return 0;
+}
+
+static int rolloff_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct xonar_cs43xx *data = chip->model_data;
+ int changed;
+ u8 reg;
+
+ mutex_lock(&chip->mutex);
+ reg = data->cs4398_regs[7];
+ if (value->value.enumerated.item[0])
+ reg |= CS4398_FILT_SEL;
+ else
+ reg &= ~CS4398_FILT_SEL;
+ changed = reg != data->cs4398_regs[7];
+ if (changed) {
+ cs4398_write(chip, 7, reg);
+ if (reg & CS4398_FILT_SEL)
+ reg = data->cs4362a_regs[0x04] | CS4362A_FILT_SEL;
+ else
+ reg = data->cs4362a_regs[0x04] & ~CS4362A_FILT_SEL;
+ cs4362a_write(chip, 0x04, reg);
+ }
+ mutex_unlock(&chip->mutex);
+ return changed;
+}
+
+static const struct snd_kcontrol_new rolloff_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "DAC Filter Playback Enum",
+ .info = rolloff_info,
+ .get = rolloff_get,
+ .put = rolloff_put,
+};
+
+static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip,
+ unsigned int reg, unsigned int mute)
+{
+ if (reg == AC97_LINE) {
+ spin_lock_irq(&chip->reg_lock);
+ oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+ mute ? GPIO_D1_INPUT_ROUTE : 0,
+ GPIO_D1_INPUT_ROUTE);
+ spin_unlock_irq(&chip->reg_lock);
+ }
+}
+
+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;
+
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip));
+ if (err < 0)
+ return err;
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip));
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+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,
+ .resume = xonar_d1_resume,
+ .get_i2s_mclk = oxygen_default_i2s_mclk,
+ .set_dac_params = set_cs43xx_params,
+ .set_adc_params = xonar_set_cs53x1_params,
+ .update_dac_volume = update_cs43xx_volume,
+ .update_dac_mute = update_cs43xx_mute,
+ .update_center_lfe_mix = update_cs43xx_center_lfe_mix,
+ .ac97_switch = xonar_d1_line_mic_ac97_switch,
+ .dac_tlv = cs4362a_db_scale,
+ .model_data_size = sizeof(struct xonar_cs43xx),
+ .device_config = PLAYBACK_0_TO_I2S |
+ PLAYBACK_1_TO_SPDIF |
+ CAPTURE_0_FROM_I2S_2,
+ .dac_channels = 8,
+ .dac_volume_min = 127 - 60,
+ .dac_volume_max = 127,
+ .function_flags = OXYGEN_FUNCTION_2WIRE,
+ .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+ .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+
+int __devinit get_xonar_cs43xx_model(struct oxygen *chip,
+ const struct pci_device_id *id)
+{
+ switch (id->subdevice) {
+ case 0x834f:
+ chip->model = model_xonar_d1;
+ chip->model.shortname = "Xonar D1";
+ break;
+ case 0x8275:
+ case 0x8327:
+ chip->model = model_xonar_d1;
+ chip->model.shortname = "Xonar DX";
+ chip->model.init = xonar_dx_init;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
diff --git a/sound/pci/oxygen/xonar_hdmi.c b/sound/pci/oxygen/xonar_hdmi.c
new file mode 100644
index 000000000000..b12db1f1cea9
--- /dev/null
+++ b/sound/pci/oxygen/xonar_hdmi.c
@@ -0,0 +1,128 @@
+/*
+ * helper functions for HDMI models (Xonar HDAV1.3)
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2.
+ *
+ * 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 driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <sound/asoundef.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include "xonar.h"
+
+static void hdmi_write_command(struct oxygen *chip, u8 command,
+ unsigned int count, const u8 *params)
+{
+ unsigned int i;
+ u8 checksum;
+
+ oxygen_write_uart(chip, 0xfb);
+ oxygen_write_uart(chip, 0xef);
+ oxygen_write_uart(chip, command);
+ oxygen_write_uart(chip, count);
+ for (i = 0; i < count; ++i)
+ oxygen_write_uart(chip, params[i]);
+ checksum = 0xfb + 0xef + command + count;
+ for (i = 0; i < count; ++i)
+ checksum += params[i];
+ oxygen_write_uart(chip, checksum);
+}
+
+static void xonar_hdmi_init_commands(struct oxygen *chip,
+ struct xonar_hdmi *hdmi)
+{
+ u8 param;
+
+ oxygen_reset_uart(chip);
+ param = 0;
+ hdmi_write_command(chip, 0x61, 1, &param);
+ param = 1;
+ hdmi_write_command(chip, 0x74, 1, &param);
+ hdmi_write_command(chip, 0x54, 5, hdmi->params);
+}
+
+void xonar_hdmi_init(struct oxygen *chip, struct xonar_hdmi *hdmi)
+{
+ hdmi->params[1] = IEC958_AES3_CON_FS_48000;
+ hdmi->params[4] = 1;
+ xonar_hdmi_init_commands(chip, hdmi);
+}
+
+void xonar_hdmi_cleanup(struct oxygen *chip)
+{
+ u8 param = 0;
+
+ hdmi_write_command(chip, 0x74, 1, &param);
+}
+
+void xonar_hdmi_resume(struct oxygen *chip, struct xonar_hdmi *hdmi)
+{
+ xonar_hdmi_init_commands(chip, hdmi);
+}
+
+void xonar_hdmi_pcm_hardware_filter(unsigned int channel,
+ struct snd_pcm_hardware *hardware)
+{
+ if (channel == PCM_MULTICH) {
+ hardware->rates = SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000;
+ hardware->rate_min = 44100;
+ }
+}
+
+void xonar_set_hdmi_params(struct oxygen *chip, struct xonar_hdmi *hdmi,
+ struct snd_pcm_hw_params *params)
+{
+ hdmi->params[0] = 0; /* 1 = non-audio */
+ switch (params_rate(params)) {
+ case 44100:
+ hdmi->params[1] = IEC958_AES3_CON_FS_44100;
+ break;
+ case 48000:
+ hdmi->params[1] = IEC958_AES3_CON_FS_48000;
+ break;
+ default: /* 96000 */
+ hdmi->params[1] = IEC958_AES3_CON_FS_96000;
+ break;
+ case 192000:
+ hdmi->params[1] = IEC958_AES3_CON_FS_192000;
+ break;
+ }
+ hdmi->params[2] = params_channels(params) / 2 - 1;
+ if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE)
+ hdmi->params[3] = 0;
+ else
+ hdmi->params[3] = 0xc0;
+ hdmi->params[4] = 1; /* ? */
+ hdmi_write_command(chip, 0x54, 5, hdmi->params);
+}
+
+void xonar_hdmi_uart_input(struct oxygen *chip)
+{
+ if (chip->uart_input_count >= 2 &&
+ chip->uart_input[chip->uart_input_count - 2] == 'O' &&
+ chip->uart_input[chip->uart_input_count - 1] == 'K') {
+ printk(KERN_DEBUG "message from HDMI chip received:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ chip->uart_input, chip->uart_input_count);
+ chip->uart_input_count = 0;
+ }
+}
diff --git a/sound/pci/oxygen/xonar_lib.c b/sound/pci/oxygen/xonar_lib.c
new file mode 100644
index 000000000000..b3ff71316653
--- /dev/null
+++ b/sound/pci/oxygen/xonar_lib.c
@@ -0,0 +1,132 @@
+/*
+ * helper functions for Asus Xonar cards
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2.
+ *
+ * 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 driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include "xonar.h"
+
+
+#define GPIO_CS53x1_M_MASK 0x000c
+#define GPIO_CS53x1_M_SINGLE 0x0000
+#define GPIO_CS53x1_M_DOUBLE 0x0004
+#define GPIO_CS53x1_M_QUAD 0x0008
+
+
+void xonar_enable_output(struct oxygen *chip)
+{
+ struct xonar_generic *data = chip->model_data;
+
+ oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, data->output_enable_bit);
+ msleep(data->anti_pop_delay);
+ oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit);
+}
+
+void xonar_disable_output(struct oxygen *chip)
+{
+ struct xonar_generic *data = chip->model_data;
+
+ oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit);
+}
+
+static void xonar_ext_power_gpio_changed(struct oxygen *chip)
+{
+ struct xonar_generic *data = chip->model_data;
+ u8 has_power;
+
+ has_power = !!(oxygen_read8(chip, data->ext_power_reg)
+ & data->ext_power_bit);
+ if (has_power != data->has_power) {
+ data->has_power = has_power;
+ if (has_power) {
+ snd_printk(KERN_NOTICE "power restored\n");
+ } else {
+ snd_printk(KERN_CRIT
+ "Hey! Don't unplug the power cable!\n");
+ /* TODO: stop PCMs */
+ }
+ }
+}
+
+void xonar_init_ext_power(struct oxygen *chip)
+{
+ struct xonar_generic *data = chip->model_data;
+
+ oxygen_set_bits8(chip, data->ext_power_int_reg,
+ data->ext_power_bit);
+ chip->interrupt_mask |= OXYGEN_INT_GPIO;
+ chip->model.gpio_changed = xonar_ext_power_gpio_changed;
+ data->has_power = !!(oxygen_read8(chip, data->ext_power_reg)
+ & data->ext_power_bit);
+}
+
+void xonar_init_cs53x1(struct oxygen *chip)
+{
+ oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CS53x1_M_MASK);
+ oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+ GPIO_CS53x1_M_SINGLE, GPIO_CS53x1_M_MASK);
+}
+
+void xonar_set_cs53x1_params(struct oxygen *chip,
+ struct snd_pcm_hw_params *params)
+{
+ unsigned int value;
+
+ if (params_rate(params) <= 54000)
+ value = GPIO_CS53x1_M_SINGLE;
+ else if (params_rate(params) <= 108000)
+ value = GPIO_CS53x1_M_DOUBLE;
+ else
+ value = GPIO_CS53x1_M_QUAD;
+ oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+ value, GPIO_CS53x1_M_MASK);
+}
+
+int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ u16 bit = ctl->private_value;
+
+ value->value.integer.value[0] =
+ !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit);
+ return 0;
+}
+
+int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ u16 bit = ctl->private_value;
+ u16 old_bits, new_bits;
+ int changed;
+
+ spin_lock_irq(&chip->reg_lock);
+ old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+ if (value->value.integer.value[0])
+ new_bits = old_bits | bit;
+ else
+ new_bits = old_bits & ~bit;
+ changed = new_bits != old_bits;
+ if (changed)
+ oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits);
+ spin_unlock_irq(&chip->reg_lock);
+ return changed;
+}
diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c
new file mode 100644
index 000000000000..ba18fb546b4f
--- /dev/null
+++ b/sound/pci/oxygen/xonar_pcm179x.c
@@ -0,0 +1,1115 @@
+/*
+ * card driver for models with PCM1796 DACs (Xonar D2/D2X/HDAV1.3/ST/STX)
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2.
+ *
+ * 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 driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Xonar D2/D2X
+ * ------------
+ *
+ * CMI8788:
+ *
+ * SPI 0 -> 1st PCM1796 (front)
+ * SPI 1 -> 2nd PCM1796 (surround)
+ * SPI 2 -> 3rd PCM1796 (center/LFE)
+ * SPI 4 -> 4th PCM1796 (back)
+ *
+ * GPIO 2 -> M0 of CS5381
+ * GPIO 3 -> M1 of CS5381
+ * GPIO 5 <- external power present (D2X only)
+ * GPIO 7 -> ALT
+ * GPIO 8 -> enable output to speakers
+ *
+ * CM9780:
+ *
+ * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
+ */
+
+/*
+ * Xonar HDAV1.3 (Deluxe)
+ * ----------------------
+ *
+ * CMI8788:
+ *
+ * I²C <-> PCM1796 (front)
+ *
+ * GPI 0 <- external power present
+ *
+ * GPIO 0 -> enable output to speakers
+ * GPIO 2 -> M0 of CS5381
+ * GPIO 3 -> M1 of CS5381
+ * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
+ *
+ * TXD -> HDMI controller
+ * RXD <- HDMI controller
+ *
+ * PCM1796 front: AD1,0 <- 0,0
+ *
+ * CM9780:
+ *
+ * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
+ *
+ * no daughterboard
+ * ----------------
+ *
+ * GPIO 4 <- 1
+ *
+ * H6 daughterboard
+ * ----------------
+ *
+ * GPIO 4 <- 0
+ * GPIO 5 <- 0
+ *
+ * I²C <-> PCM1796 (surround)
+ * <-> PCM1796 (center/LFE)
+ * <-> PCM1796 (back)
+ *
+ * PCM1796 surround: AD1,0 <- 0,1
+ * PCM1796 center/LFE: AD1,0 <- 1,0
+ * PCM1796 back: AD1,0 <- 1,1
+ *
+ * unknown daughterboard
+ * ---------------------
+ *
+ * GPIO 4 <- 0
+ * GPIO 5 <- 1
+ *
+ * I²C <-> CS4362A (surround, center/LFE, back)
+ *
+ * CS4362A: AD0 <- 0
+ */
+
+/*
+ * Xonar Essence ST (Deluxe)/STX
+ * -----------------------------
+ *
+ * CMI8788:
+ *
+ * I²C <-> PCM1792A
+ * <-> CS2000 (ST only)
+ *
+ * ADC1 MCLK -> REF_CLK of CS2000 (ST only)
+ *
+ * GPI 0 <- external power present (STX only)
+ *
+ * GPIO 0 -> enable output to speakers
+ * GPIO 1 -> route HP to front panel (0) or rear jack (1)
+ * GPIO 2 -> M0 of CS5381
+ * GPIO 3 -> M1 of CS5381
+ * GPIO 7 -> route output to speaker jacks (0) or HP (1)
+ * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
+ *
+ * PCM1792A:
+ *
+ * AD1,0 <- 0,0
+ * SCK <- CLK_OUT of CS2000 (ST only)
+ *
+ * CS2000:
+ *
+ * AD0 <- 0
+ *
+ * CM9780:
+ *
+ * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
+ *
+ * H6 daughterboard
+ * ----------------
+ *
+ * GPIO 4 <- 0
+ * GPIO 5 <- 0
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <sound/ac97_codec.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include "xonar.h"
+#include "cm9780.h"
+#include "pcm1796.h"
+#include "cs2000.h"
+
+
+#define GPIO_D2X_EXT_POWER 0x0020
+#define GPIO_D2_ALT 0x0080
+#define GPIO_D2_OUTPUT_ENABLE 0x0100
+
+#define GPI_EXT_POWER 0x01
+#define GPIO_INPUT_ROUTE 0x0100
+
+#define GPIO_HDAV_OUTPUT_ENABLE 0x0001
+
+#define GPIO_DB_MASK 0x0030
+#define GPIO_DB_H6 0x0000
+
+#define GPIO_ST_OUTPUT_ENABLE 0x0001
+#define GPIO_ST_HP_REAR 0x0002
+#define GPIO_ST_HP 0x0080
+
+#define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ii, /W=0 */
+#define I2C_DEVICE_CS2000 0x9c /* 100111, 0, /W=0 */
+
+#define PCM1796_REG_BASE 16
+
+
+struct xonar_pcm179x {
+ struct xonar_generic generic;
+ unsigned int dacs;
+ u8 pcm1796_regs[4][5];
+ unsigned int current_rate;
+ bool os_128;
+ bool hp_active;
+ s8 hp_gain_offset;
+ bool has_cs2000;
+ u8 cs2000_fun_cfg_1;
+};
+
+struct xonar_hdav {
+ struct xonar_pcm179x pcm179x;
+ struct xonar_hdmi hdmi;
+};
+
+
+static inline void pcm1796_write_spi(struct oxygen *chip, unsigned int codec,
+ u8 reg, u8 value)
+{
+ /* maps ALSA channel pair number to SPI output */
+ static const u8 codec_map[4] = {
+ 0, 1, 2, 4
+ };
+ oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
+ OXYGEN_SPI_DATA_LENGTH_2 |
+ OXYGEN_SPI_CLOCK_160 |
+ (codec_map[codec] << OXYGEN_SPI_CODEC_SHIFT) |
+ OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
+ (reg << 8) | value);
+}
+
+static inline void pcm1796_write_i2c(struct oxygen *chip, unsigned int codec,
+ u8 reg, u8 value)
+{
+ oxygen_write_i2c(chip, I2C_DEVICE_PCM1796(codec), reg, value);
+}
+
+static void pcm1796_write(struct oxygen *chip, unsigned int codec,
+ u8 reg, u8 value)
+{
+ struct xonar_pcm179x *data = chip->model_data;
+
+ if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) ==
+ OXYGEN_FUNCTION_SPI)
+ pcm1796_write_spi(chip, codec, reg, value);
+ else
+ pcm1796_write_i2c(chip, codec, reg, value);
+ if ((unsigned int)(reg - PCM1796_REG_BASE)
+ < ARRAY_SIZE(data->pcm1796_regs[codec]))
+ data->pcm1796_regs[codec][reg - PCM1796_REG_BASE] = value;
+}
+
+static void pcm1796_write_cached(struct oxygen *chip, unsigned int codec,
+ u8 reg, u8 value)
+{
+ struct xonar_pcm179x *data = chip->model_data;
+
+ if (value != data->pcm1796_regs[codec][reg - PCM1796_REG_BASE])
+ pcm1796_write(chip, codec, reg, value);
+}
+
+static void cs2000_write(struct oxygen *chip, u8 reg, u8 value)
+{
+ struct xonar_pcm179x *data = chip->model_data;
+
+ oxygen_write_i2c(chip, I2C_DEVICE_CS2000, reg, value);
+ if (reg == CS2000_FUN_CFG_1)
+ data->cs2000_fun_cfg_1 = value;
+}
+
+static void cs2000_write_cached(struct oxygen *chip, u8 reg, u8 value)
+{
+ struct xonar_pcm179x *data = chip->model_data;
+
+ if (reg != CS2000_FUN_CFG_1 ||
+ value != data->cs2000_fun_cfg_1)
+ cs2000_write(chip, reg, value);
+}
+
+static void pcm1796_registers_init(struct oxygen *chip)
+{
+ struct xonar_pcm179x *data = chip->model_data;
+ unsigned int i;
+ s8 gain_offset;
+
+ gain_offset = data->hp_active ? data->hp_gain_offset : 0;
+ for (i = 0; i < data->dacs; ++i) {
+ /* set ATLD before ATL/ATR */
+ pcm1796_write(chip, i, 18,
+ data->pcm1796_regs[0][18 - PCM1796_REG_BASE]);
+ pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]
+ + gain_offset);
+ pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]
+ + gain_offset);
+ pcm1796_write(chip, i, 19,
+ data->pcm1796_regs[0][19 - PCM1796_REG_BASE]);
+ pcm1796_write(chip, i, 20,
+ data->pcm1796_regs[0][20 - PCM1796_REG_BASE]);
+ pcm1796_write(chip, i, 21, 0);
+ }
+}
+
+static void pcm1796_init(struct oxygen *chip)
+{
+ struct xonar_pcm179x *data = chip->model_data;
+
+ data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE |
+ PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD;
+ data->pcm1796_regs[0][19 - PCM1796_REG_BASE] =
+ PCM1796_FLT_SHARP | PCM1796_ATS_1;
+ data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = PCM1796_OS_64;
+ pcm1796_registers_init(chip);
+ data->current_rate = 48000;
+}
+
+static void xonar_d2_init(struct oxygen *chip)
+{
+ struct xonar_pcm179x *data = chip->model_data;
+
+ data->generic.anti_pop_delay = 300;
+ data->generic.output_enable_bit = GPIO_D2_OUTPUT_ENABLE;
+ data->dacs = 4;
+
+ pcm1796_init(chip);
+
+ oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2_ALT);
+ oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_D2_ALT);
+
+ oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC);
+
+ xonar_init_cs53x1(chip);
+ xonar_enable_output(chip);
+
+ snd_component_add(chip->card, "PCM1796");
+ snd_component_add(chip->card, "CS5381");
+}
+
+static void xonar_d2x_init(struct oxygen *chip)
+{
+ struct xonar_pcm179x *data = chip->model_data;
+
+ data->generic.ext_power_reg = OXYGEN_GPIO_DATA;
+ data->generic.ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK;
+ data->generic.ext_power_bit = GPIO_D2X_EXT_POWER;
+ oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2X_EXT_POWER);
+ xonar_init_ext_power(chip);
+ xonar_d2_init(chip);
+}
+
+static void xonar_hdav_init(struct oxygen *chip)
+{
+ struct xonar_hdav *data = chip->model_data;
+
+ oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
+ OXYGEN_2WIRE_LENGTH_8 |
+ OXYGEN_2WIRE_INTERRUPT_MASK |
+ OXYGEN_2WIRE_SPEED_FAST);
+
+ data->pcm179x.generic.anti_pop_delay = 100;
+ data->pcm179x.generic.output_enable_bit = GPIO_HDAV_OUTPUT_ENABLE;
+ data->pcm179x.generic.ext_power_reg = OXYGEN_GPI_DATA;
+ data->pcm179x.generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
+ data->pcm179x.generic.ext_power_bit = GPI_EXT_POWER;
+ data->pcm179x.dacs = chip->model.private_data ? 4 : 1;
+
+ pcm1796_init(chip);
+
+ oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_INPUT_ROUTE);
+ oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_INPUT_ROUTE);
+
+ xonar_init_cs53x1(chip);
+ xonar_init_ext_power(chip);
+ xonar_hdmi_init(chip, &data->hdmi);
+ xonar_enable_output(chip);
+
+ snd_component_add(chip->card, "PCM1796");
+ snd_component_add(chip->card, "CS5381");
+}
+
+static void xonar_st_init_i2c(struct oxygen *chip)
+{
+ oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
+ OXYGEN_2WIRE_LENGTH_8 |
+ OXYGEN_2WIRE_INTERRUPT_MASK |
+ OXYGEN_2WIRE_SPEED_FAST);
+}
+
+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;
+
+ pcm1796_init(chip);
+
+ oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+ GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
+ oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
+ GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
+
+ xonar_init_cs53x1(chip);
+ xonar_enable_output(chip);
+
+ snd_component_add(chip->card, "PCM1792A");
+ snd_component_add(chip->card, "CS5381");
+}
+
+static void cs2000_registers_init(struct oxygen *chip)
+{
+ struct xonar_pcm179x *data = chip->model_data;
+
+ cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_FREEZE);
+ cs2000_write(chip, CS2000_DEV_CTRL, 0);
+ cs2000_write(chip, CS2000_DEV_CFG_1,
+ CS2000_R_MOD_SEL_1 |
+ (0 << CS2000_R_SEL_SHIFT) |
+ CS2000_AUX_OUT_SRC_REF_CLK |
+ CS2000_EN_DEV_CFG_1);
+ cs2000_write(chip, CS2000_DEV_CFG_2,
+ (0 << CS2000_LOCK_CLK_SHIFT) |
+ CS2000_FRAC_N_SRC_STATIC);
+ cs2000_write(chip, CS2000_RATIO_0 + 0, 0x00); /* 1.0 */
+ cs2000_write(chip, CS2000_RATIO_0 + 1, 0x10);
+ cs2000_write(chip, CS2000_RATIO_0 + 2, 0x00);
+ cs2000_write(chip, CS2000_RATIO_0 + 3, 0x00);
+ cs2000_write(chip, CS2000_FUN_CFG_1, data->cs2000_fun_cfg_1);
+ cs2000_write(chip, CS2000_FUN_CFG_2, 0);
+ cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_EN_DEV_CFG_2);
+}
+
+static void xonar_st_init(struct oxygen *chip)
+{
+ struct xonar_pcm179x *data = chip->model_data;
+
+ data->has_cs2000 = 1;
+ data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1;
+
+ oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
+ OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_I2S |
+ OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 |
+ OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+
+ xonar_st_init_i2c(chip);
+ cs2000_registers_init(chip);
+ xonar_st_init_common(chip);
+
+ snd_component_add(chip->card, "CS2000");
+}
+
+static void xonar_stx_init(struct oxygen *chip)
+{
+ struct xonar_pcm179x *data = chip->model_data;
+
+ xonar_st_init_i2c(chip);
+ 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;
+ xonar_init_ext_power(chip);
+ xonar_st_init_common(chip);
+}
+
+static void xonar_d2_cleanup(struct oxygen *chip)
+{
+ xonar_disable_output(chip);
+}
+
+static void xonar_hdav_cleanup(struct oxygen *chip)
+{
+ xonar_hdmi_cleanup(chip);
+ xonar_disable_output(chip);
+ msleep(2);
+}
+
+static void xonar_st_cleanup(struct oxygen *chip)
+{
+ xonar_disable_output(chip);
+}
+
+static void xonar_d2_suspend(struct oxygen *chip)
+{
+ xonar_d2_cleanup(chip);
+}
+
+static void xonar_hdav_suspend(struct oxygen *chip)
+{
+ xonar_hdav_cleanup(chip);
+}
+
+static void xonar_st_suspend(struct oxygen *chip)
+{
+ xonar_st_cleanup(chip);
+}
+
+static void xonar_d2_resume(struct oxygen *chip)
+{
+ pcm1796_registers_init(chip);
+ xonar_enable_output(chip);
+}
+
+static void xonar_hdav_resume(struct oxygen *chip)
+{
+ struct xonar_hdav *data = chip->model_data;
+
+ pcm1796_registers_init(chip);
+ xonar_hdmi_resume(chip, &data->hdmi);
+ xonar_enable_output(chip);
+}
+
+static void xonar_stx_resume(struct oxygen *chip)
+{
+ pcm1796_registers_init(chip);
+ xonar_enable_output(chip);
+}
+
+static void xonar_st_resume(struct oxygen *chip)
+{
+ cs2000_registers_init(chip);
+ xonar_stx_resume(chip);
+}
+
+static unsigned int mclk_from_rate(struct oxygen *chip, unsigned int rate)
+{
+ struct xonar_pcm179x *data = chip->model_data;
+
+ if (rate <= 32000)
+ return OXYGEN_I2S_MCLK_512;
+ else if (rate <= 48000 && data->os_128)
+ return OXYGEN_I2S_MCLK_512;
+ else if (rate <= 96000)
+ return OXYGEN_I2S_MCLK_256;
+ else
+ return OXYGEN_I2S_MCLK_128;
+}
+
+static unsigned int get_pcm1796_i2s_mclk(struct oxygen *chip,
+ unsigned int channel,
+ struct snd_pcm_hw_params *params)
+{
+ if (channel == PCM_MULTICH)
+ return mclk_from_rate(chip, params_rate(params));
+ else
+ return oxygen_default_i2s_mclk(chip, channel, params);
+}
+
+static void update_pcm1796_oversampling(struct oxygen *chip)
+{
+ struct xonar_pcm179x *data = chip->model_data;
+ unsigned int i;
+ u8 reg;
+
+ if (data->current_rate <= 32000)
+ reg = PCM1796_OS_128;
+ else if (data->current_rate <= 48000 && data->os_128)
+ reg = PCM1796_OS_128;
+ else if (data->current_rate <= 96000 || data->os_128)
+ reg = PCM1796_OS_64;
+ else
+ reg = PCM1796_OS_32;
+ for (i = 0; i < data->dacs; ++i)
+ pcm1796_write_cached(chip, i, 20, reg);
+}
+
+static void set_pcm1796_params(struct oxygen *chip,
+ struct snd_pcm_hw_params *params)
+{
+ struct xonar_pcm179x *data = chip->model_data;
+
+ data->current_rate = params_rate(params);
+ update_pcm1796_oversampling(chip);
+}
+
+static void update_pcm1796_volume(struct oxygen *chip)
+{
+ struct xonar_pcm179x *data = chip->model_data;
+ unsigned int i;
+ s8 gain_offset;
+
+ gain_offset = data->hp_active ? data->hp_gain_offset : 0;
+ for (i = 0; i < data->dacs; ++i) {
+ pcm1796_write_cached(chip, i, 16, chip->dac_volume[i * 2]
+ + gain_offset);
+ pcm1796_write_cached(chip, i, 17, chip->dac_volume[i * 2 + 1]
+ + gain_offset);
+ }
+}
+
+static void update_pcm1796_mute(struct oxygen *chip)
+{
+ struct xonar_pcm179x *data = chip->model_data;
+ unsigned int i;
+ u8 value;
+
+ value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD;
+ if (chip->dac_mute)
+ value |= PCM1796_MUTE;
+ for (i = 0; i < data->dacs; ++i)
+ pcm1796_write_cached(chip, i, 18, value);
+}
+
+static void update_cs2000_rate(struct oxygen *chip, unsigned int rate)
+{
+ struct xonar_pcm179x *data = chip->model_data;
+ u8 rate_mclk, reg;
+
+ switch (rate) {
+ /* XXX Why is the I2S A MCLK half the actual I2S MCLK? */
+ case 32000:
+ rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256;
+ break;
+ case 44100:
+ if (data->os_128)
+ rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256;
+ else
+ rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_128;
+ break;
+ default: /* 48000 */
+ if (data->os_128)
+ rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256;
+ else
+ rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_128;
+ break;
+ case 64000:
+ rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256;
+ break;
+ case 88200:
+ rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256;
+ break;
+ case 96000:
+ rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256;
+ break;
+ case 176400:
+ rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256;
+ break;
+ case 192000:
+ rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256;
+ break;
+ }
+ oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk,
+ OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK);
+ if ((rate_mclk & OXYGEN_I2S_MCLK_MASK) <= OXYGEN_I2S_MCLK_128)
+ reg = CS2000_REF_CLK_DIV_1;
+ else
+ reg = CS2000_REF_CLK_DIV_2;
+ cs2000_write_cached(chip, CS2000_FUN_CFG_1, reg);
+}
+
+static void set_st_params(struct oxygen *chip,
+ struct snd_pcm_hw_params *params)
+{
+ update_cs2000_rate(chip, params_rate(params));
+ set_pcm1796_params(chip, params);
+}
+
+static void set_hdav_params(struct oxygen *chip,
+ struct snd_pcm_hw_params *params)
+{
+ struct xonar_hdav *data = chip->model_data;
+
+ set_pcm1796_params(chip, params);
+ xonar_set_hdmi_params(chip, &data->hdmi, params);
+}
+
+static const struct snd_kcontrol_new alt_switch = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog Loopback Switch",
+ .info = snd_ctl_boolean_mono_info,
+ .get = xonar_gpio_bit_switch_get,
+ .put = xonar_gpio_bit_switch_put,
+ .private_value = GPIO_D2_ALT,
+};
+
+static int rolloff_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ static const char *const names[2] = {
+ "Sharp Roll-off", "Slow Roll-off"
+ };
+
+ info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ info->count = 1;
+ info->value.enumerated.items = 2;
+ if (info->value.enumerated.item >= 2)
+ info->value.enumerated.item = 1;
+ strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+ return 0;
+}
+
+static int rolloff_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct xonar_pcm179x *data = chip->model_data;
+
+ value->value.enumerated.item[0] =
+ (data->pcm1796_regs[0][19 - PCM1796_REG_BASE] &
+ PCM1796_FLT_MASK) != PCM1796_FLT_SHARP;
+ return 0;
+}
+
+static int rolloff_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct xonar_pcm179x *data = chip->model_data;
+ unsigned int i;
+ int changed;
+ u8 reg;
+
+ mutex_lock(&chip->mutex);
+ reg = data->pcm1796_regs[0][19 - PCM1796_REG_BASE];
+ reg &= ~PCM1796_FLT_MASK;
+ if (!value->value.enumerated.item[0])
+ reg |= PCM1796_FLT_SHARP;
+ else
+ reg |= PCM1796_FLT_SLOW;
+ changed = reg != data->pcm1796_regs[0][19 - PCM1796_REG_BASE];
+ if (changed) {
+ for (i = 0; i < data->dacs; ++i)
+ pcm1796_write(chip, i, 19, reg);
+ }
+ mutex_unlock(&chip->mutex);
+ return changed;
+}
+
+static const struct snd_kcontrol_new rolloff_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "DAC Filter Playback Enum",
+ .info = rolloff_info,
+ .get = rolloff_get,
+ .put = rolloff_put,
+};
+
+static int os_128_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
+{
+ static const char *const names[2] = { "64x", "128x" };
+
+ info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ info->count = 1;
+ info->value.enumerated.items = 2;
+ if (info->value.enumerated.item >= 2)
+ info->value.enumerated.item = 1;
+ strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+ return 0;
+}
+
+static int os_128_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct xonar_pcm179x *data = chip->model_data;
+
+ value->value.enumerated.item[0] = data->os_128;
+ return 0;
+}
+
+static int os_128_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct xonar_pcm179x *data = chip->model_data;
+ int changed;
+
+ mutex_lock(&chip->mutex);
+ changed = value->value.enumerated.item[0] != data->os_128;
+ if (changed) {
+ data->os_128 = value->value.enumerated.item[0];
+ if (data->has_cs2000)
+ update_cs2000_rate(chip, data->current_rate);
+ oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT,
+ mclk_from_rate(chip, data->current_rate),
+ OXYGEN_I2S_MCLK_MASK);
+ update_pcm1796_oversampling(chip);
+ }
+ mutex_unlock(&chip->mutex);
+ return changed;
+}
+
+static const struct snd_kcontrol_new os_128_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "DAC Oversampling Playback Enum",
+ .info = os_128_info,
+ .get = os_128_get,
+ .put = os_128_put,
+};
+
+static int st_output_switch_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ static const char *const names[3] = {
+ "Speakers", "Headphones", "FP Headphones"
+ };
+
+ info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ info->count = 1;
+ info->value.enumerated.items = 3;
+ if (info->value.enumerated.item >= 3)
+ info->value.enumerated.item = 2;
+ strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+ return 0;
+}
+
+static int st_output_switch_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ u16 gpio;
+
+ gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+ if (!(gpio & GPIO_ST_HP))
+ value->value.enumerated.item[0] = 0;
+ else if (gpio & GPIO_ST_HP_REAR)
+ value->value.enumerated.item[0] = 1;
+ else
+ value->value.enumerated.item[0] = 2;
+ return 0;
+}
+
+
+static int st_output_switch_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct xonar_pcm179x *data = chip->model_data;
+ u16 gpio_old, gpio;
+
+ mutex_lock(&chip->mutex);
+ gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+ gpio = gpio_old;
+ switch (value->value.enumerated.item[0]) {
+ case 0:
+ gpio &= ~(GPIO_ST_HP | GPIO_ST_HP_REAR);
+ break;
+ case 1:
+ gpio |= GPIO_ST_HP | GPIO_ST_HP_REAR;
+ break;
+ case 2:
+ gpio = (gpio | GPIO_ST_HP) & ~GPIO_ST_HP_REAR;
+ break;
+ }
+ oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio);
+ data->hp_active = gpio & GPIO_ST_HP;
+ update_pcm1796_volume(chip);
+ mutex_unlock(&chip->mutex);
+ return gpio != gpio_old;
+}
+
+static int st_hp_volume_offset_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ static const char *const names[3] = {
+ "< 64 ohms", "64-300 ohms", "300-600 ohms"
+ };
+
+ info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ info->count = 1;
+ info->value.enumerated.items = 3;
+ if (info->value.enumerated.item > 2)
+ info->value.enumerated.item = 2;
+ strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+ return 0;
+}
+
+static int st_hp_volume_offset_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct xonar_pcm179x *data = chip->model_data;
+
+ mutex_lock(&chip->mutex);
+ if (data->hp_gain_offset < 2*-6)
+ value->value.enumerated.item[0] = 0;
+ else if (data->hp_gain_offset < 0)
+ value->value.enumerated.item[0] = 1;
+ else
+ value->value.enumerated.item[0] = 2;
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+
+static int st_hp_volume_offset_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ static const s8 offsets[] = { 2*-18, 2*-6, 0 };
+ struct oxygen *chip = ctl->private_data;
+ struct xonar_pcm179x *data = chip->model_data;
+ s8 offset;
+ int changed;
+
+ if (value->value.enumerated.item[0] > 2)
+ return -EINVAL;
+ offset = offsets[value->value.enumerated.item[0]];
+ mutex_lock(&chip->mutex);
+ changed = offset != data->hp_gain_offset;
+ if (changed) {
+ data->hp_gain_offset = offset;
+ update_pcm1796_volume(chip);
+ }
+ mutex_unlock(&chip->mutex);
+ return changed;
+}
+
+static const struct snd_kcontrol_new st_controls[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog Output",
+ .info = st_output_switch_info,
+ .get = st_output_switch_get,
+ .put = st_output_switch_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Headphones Impedance Playback Enum",
+ .info = st_hp_volume_offset_info,
+ .get = st_hp_volume_offset_get,
+ .put = st_hp_volume_offset_put,
+ },
+};
+
+static void xonar_line_mic_ac97_switch(struct oxygen *chip,
+ unsigned int reg, unsigned int mute)
+{
+ if (reg == AC97_LINE) {
+ spin_lock_irq(&chip->reg_lock);
+ oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+ mute ? GPIO_INPUT_ROUTE : 0,
+ GPIO_INPUT_ROUTE);
+ spin_unlock_irq(&chip->reg_lock);
+ }
+}
+
+static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -6000, 50, 0);
+
+static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
+{
+ if (!strncmp(template->name, "CD Capture ", 11))
+ /* CD in is actually connected to the video in pin */
+ template->private_value ^= AC97_CD ^ AC97_VIDEO;
+ 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;
+
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip));
+ if (err < 0)
+ return err;
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip));
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int xonar_d2_mixer_init(struct oxygen *chip)
+{
+ int err;
+
+ err = snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip));
+ if (err < 0)
+ return err;
+ err = add_pcm1796_controls(chip);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int xonar_hdav_mixer_init(struct oxygen *chip)
+{
+ return add_pcm1796_controls(chip);
+}
+
+static int xonar_st_mixer_init(struct oxygen *chip)
+{
+ unsigned int i;
+ int err;
+
+ for (i = 0; i < ARRAY_SIZE(st_controls); ++i) {
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&st_controls[i], chip));
+ if (err < 0)
+ return err;
+ }
+ err = add_pcm1796_controls(chip);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static const struct oxygen_model model_xonar_d2 = {
+ .longname = "Asus Virtuoso 200",
+ .chip = "AV200",
+ .init = xonar_d2_init,
+ .control_filter = xonar_d2_control_filter,
+ .mixer_init = xonar_d2_mixer_init,
+ .cleanup = xonar_d2_cleanup,
+ .suspend = xonar_d2_suspend,
+ .resume = xonar_d2_resume,
+ .get_i2s_mclk = get_pcm1796_i2s_mclk,
+ .set_dac_params = set_pcm1796_params,
+ .set_adc_params = xonar_set_cs53x1_params,
+ .update_dac_volume = update_pcm1796_volume,
+ .update_dac_mute = update_pcm1796_mute,
+ .dac_tlv = pcm1796_db_scale,
+ .model_data_size = sizeof(struct xonar_pcm179x),
+ .device_config = PLAYBACK_0_TO_I2S |
+ PLAYBACK_1_TO_SPDIF |
+ CAPTURE_0_FROM_I2S_2 |
+ CAPTURE_1_FROM_SPDIF |
+ MIDI_OUTPUT |
+ MIDI_INPUT,
+ .dac_channels = 8,
+ .dac_volume_min = 255 - 2*60,
+ .dac_volume_max = 255,
+ .misc_flags = OXYGEN_MISC_MIDI,
+ .function_flags = OXYGEN_FUNCTION_SPI |
+ OXYGEN_FUNCTION_ENABLE_SPI_4_5,
+ .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+ .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+
+static const struct oxygen_model model_xonar_hdav = {
+ .longname = "Asus Virtuoso 200",
+ .chip = "AV200",
+ .init = xonar_hdav_init,
+ .mixer_init = xonar_hdav_mixer_init,
+ .cleanup = xonar_hdav_cleanup,
+ .suspend = xonar_hdav_suspend,
+ .resume = xonar_hdav_resume,
+ .pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter,
+ .get_i2s_mclk = get_pcm1796_i2s_mclk,
+ .set_dac_params = set_hdav_params,
+ .set_adc_params = xonar_set_cs53x1_params,
+ .update_dac_volume = update_pcm1796_volume,
+ .update_dac_mute = update_pcm1796_mute,
+ .uart_input = xonar_hdmi_uart_input,
+ .ac97_switch = xonar_line_mic_ac97_switch,
+ .dac_tlv = pcm1796_db_scale,
+ .model_data_size = sizeof(struct xonar_hdav),
+ .device_config = PLAYBACK_0_TO_I2S |
+ PLAYBACK_1_TO_SPDIF |
+ CAPTURE_0_FROM_I2S_2 |
+ CAPTURE_1_FROM_SPDIF,
+ .dac_channels = 8,
+ .dac_volume_min = 255 - 2*60,
+ .dac_volume_max = 255,
+ .misc_flags = OXYGEN_MISC_MIDI,
+ .function_flags = OXYGEN_FUNCTION_2WIRE,
+ .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+ .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+
+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,
+ .resume = xonar_st_resume,
+ .get_i2s_mclk = get_pcm1796_i2s_mclk,
+ .set_dac_params = set_st_params,
+ .set_adc_params = xonar_set_cs53x1_params,
+ .update_dac_volume = update_pcm1796_volume,
+ .update_dac_mute = update_pcm1796_mute,
+ .ac97_switch = xonar_line_mic_ac97_switch,
+ .dac_tlv = pcm1796_db_scale,
+ .model_data_size = sizeof(struct xonar_pcm179x),
+ .device_config = PLAYBACK_0_TO_I2S |
+ PLAYBACK_1_TO_SPDIF |
+ CAPTURE_0_FROM_I2S_2,
+ .dac_channels = 2,
+ .dac_volume_min = 255 - 2*60,
+ .dac_volume_max = 255,
+ .function_flags = OXYGEN_FUNCTION_2WIRE,
+ .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+ .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+
+int __devinit get_xonar_pcm179x_model(struct oxygen *chip,
+ const struct pci_device_id *id)
+{
+ switch (id->subdevice) {
+ case 0x8269:
+ chip->model = model_xonar_d2;
+ chip->model.shortname = "Xonar D2";
+ break;
+ case 0x82b7:
+ chip->model = model_xonar_d2;
+ chip->model.shortname = "Xonar D2X";
+ chip->model.init = xonar_d2x_init;
+ break;
+ case 0x8314:
+ chip->model = model_xonar_hdav;
+ oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
+ switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) {
+ default:
+ chip->model.shortname = "Xonar HDAV1.3";
+ break;
+ case GPIO_DB_H6:
+ chip->model.shortname = "Xonar HDAV1.3+H6";
+ chip->model.private_data = 1;
+ break;
+ }
+ break;
+ case 0x835d:
+ chip->model = model_xonar_st;
+ oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK);
+ switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) {
+ default:
+ chip->model.shortname = "Xonar ST";
+ break;
+ case GPIO_DB_H6:
+ chip->model.shortname = "Xonar ST+H6";
+ chip->model.dac_channels = 8;
+ chip->model.private_data = 1;
+ break;
+ }
+ break;
+ case 0x835c:
+ chip->model = model_xonar_st;
+ chip->model.shortname = "Xonar STX";
+ chip->model.init = xonar_stx_init;
+ chip->model.resume = xonar_stx_resume;
+ chip->model.set_dac_params = set_pcm1796_params;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
diff --git a/sound/ppc/Kconfig b/sound/ppc/Kconfig
index bd2338ab2ced..0519c60f5be1 100644
--- a/sound/ppc/Kconfig
+++ b/sound/ppc/Kconfig
@@ -2,7 +2,7 @@
menuconfig SND_PPC
bool "PowerPC sound devices"
- depends on PPC64 || PPC32
+ depends on PPC
default y
help
Support for sound devices specific to PowerPC architectures.
diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c
index 9eb610c2ba91..9df4c68ef000 100644
--- a/sound/soc/atmel/playpaq_wm8510.c
+++ b/sound/soc/atmel/playpaq_wm8510.c
@@ -268,7 +268,7 @@ static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream,
#endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */
- ret = snd_soc_dai_set_pll(codec_dai, 0,
+ ret = snd_soc_dai_set_pll(codec_dai, 0, 0,
clk_get_rate(CODEC_CLK), pll_out);
if (ret < 0) {
pr_warning("playpaq_wm8510: Failed to set CODEC DAI PLL (%d)\n",
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
index 885ba012557e..e028744c32ce 100644
--- a/sound/soc/atmel/sam9g20_wm8731.c
+++ b/sound/soc/atmel/sam9g20_wm8731.c
@@ -207,7 +207,7 @@ static int __init at91sam9g20ek_init(void)
struct clk *pllb;
int ret;
- if (!machine_is_at91sam9g20ek())
+ if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc()))
return -ENODEV;
/*
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c
index 594c6c5b7838..72617d7f21c5 100644
--- a/sound/soc/au1x/dbdma2.c
+++ b/sound/soc/au1x/dbdma2.c
@@ -51,8 +51,8 @@ struct au1xpsc_audio_dmadata {
struct snd_pcm_substream *substream;
unsigned long curr_period; /* current segment DDMA is working on */
unsigned long q_period; /* queue period(s) */
- unsigned long dma_area; /* address of queued DMA area */
- unsigned long dma_area_s; /* start address of DMA area */
+ dma_addr_t dma_area; /* address of queued DMA area */
+ dma_addr_t dma_area_s; /* start address of DMA area */
unsigned long pos; /* current byte position being played */
unsigned long periods; /* number of SG segments in total */
unsigned long period_bytes; /* size in bytes of one SG segment */
@@ -94,8 +94,7 @@ static const struct snd_pcm_hardware au1xpsc_pcm_hardware = {
static void au1x_pcm_queue_tx(struct au1xpsc_audio_dmadata *cd)
{
- au1xxx_dbdma_put_source_flags(cd->ddma_chan,
- (void *)phys_to_virt(cd->dma_area),
+ au1xxx_dbdma_put_source(cd->ddma_chan, cd->dma_area,
cd->period_bytes, DDMA_FLAGS_IE);
/* update next-to-queue period */
@@ -109,9 +108,8 @@ static void au1x_pcm_queue_tx(struct au1xpsc_audio_dmadata *cd)
static void au1x_pcm_queue_rx(struct au1xpsc_audio_dmadata *cd)
{
- au1xxx_dbdma_put_dest_flags(cd->ddma_chan,
- (void *)phys_to_virt(cd->dma_area),
- cd->period_bytes, DDMA_FLAGS_IE);
+ au1xxx_dbdma_put_dest(cd->ddma_chan, cd->dma_area,
+ cd->period_bytes, DDMA_FLAGS_IE);
/* update next-to-queue period */
++cd->q_period;
@@ -233,7 +231,7 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
pcd->substream = substream;
pcd->period_bytes = params_period_bytes(params);
pcd->periods = params_periods(params);
- pcd->dma_area_s = pcd->dma_area = (unsigned long)runtime->dma_addr;
+ pcd->dma_area_s = pcd->dma_area = runtime->dma_addr;
pcd->q_period = 0;
pcd->curr_period = 0;
pcd->pos = 0;
diff --git a/sound/soc/blackfin/bf5xx-ad1836.c b/sound/soc/blackfin/bf5xx-ad1836.c
index cd361e304b0f..0f45a3f56be8 100644
--- a/sound/soc/blackfin/bf5xx-ad1836.c
+++ b/sound/soc/blackfin/bf5xx-ad1836.c
@@ -52,6 +52,7 @@ static int bf5xx_ad1836_hw_params(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 *codec_dai = rtd->dai->codec_dai;
+ unsigned int channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7};
int ret = 0;
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
@@ -65,6 +66,12 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
+ /* set cpu DAI channel mapping */
+ ret = snd_soc_dai_set_channel_map(cpu_dai, ARRAY_SIZE(channel_map),
+ channel_map, ARRAY_SIZE(channel_map), channel_map);
+ if (ret < 0)
+ return ret;
+
return 0;
}
diff --git a/sound/soc/blackfin/bf5xx-ad1938.c b/sound/soc/blackfin/bf5xx-ad1938.c
index 08269e91810c..2ef1e5013b8c 100644
--- a/sound/soc/blackfin/bf5xx-ad1938.c
+++ b/sound/soc/blackfin/bf5xx-ad1938.c
@@ -61,6 +61,7 @@ static int bf5xx_ad1938_hw_params(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 *codec_dai = rtd->dai->codec_dai;
+ unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
int ret = 0;
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
@@ -75,7 +76,13 @@ static int bf5xx_ad1938_hw_params(struct snd_pcm_substream *substream,
return ret;
/* set codec DAI slots, 8 channels, all channels are enabled */
- ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 8);
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 0xFF, 8, 32);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI channel mapping */
+ ret = snd_soc_dai_set_channel_map(cpu_dai, ARRAY_SIZE(channel_map),
+ channel_map, ARRAY_SIZE(channel_map), channel_map);
if (ret < 0)
return ret;
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c
index 084b68884ada..3e6ada0dd1c4 100644
--- a/sound/soc/blackfin/bf5xx-i2s.c
+++ b/sound/soc/blackfin/bf5xx-i2s.c
@@ -49,7 +49,6 @@ struct bf5xx_i2s_port {
u16 rcr1;
u16 tcr2;
u16 rcr2;
- int counter;
int configured;
};
@@ -133,16 +132,6 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
return ret;
}
-static int bf5xx_i2s_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- pr_debug("%s enter\n", __func__);
-
- /*this counter is used for counting how many pcm streams are opened*/
- bf5xx_i2s.counter++;
- return 0;
-}
-
static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -201,9 +190,8 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
pr_debug("%s enter\n", __func__);
- bf5xx_i2s.counter--;
/* No active stream, SPORT is allowed to be configured again. */
- if (!bf5xx_i2s.counter)
+ if (!dai->active)
bf5xx_i2s.configured = 0;
}
@@ -284,7 +272,6 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
- .startup = bf5xx_i2s_startup,
.shutdown = bf5xx_i2s_shutdown,
.hw_params = bf5xx_i2s_hw_params,
.set_fmt = bf5xx_i2s_set_dai_fmt,
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c
index ccb5e823bd18..a8c73cbbd685 100644
--- a/sound/soc/blackfin/bf5xx-tdm-pcm.c
+++ b/sound/soc/blackfin/bf5xx-tdm-pcm.c
@@ -43,7 +43,7 @@
#include "bf5xx-tdm.h"
#include "bf5xx-sport.h"
-#define PCM_BUFFER_MAX 0x10000
+#define PCM_BUFFER_MAX 0x8000
#define FRAGMENT_SIZE_MIN (4*1024)
#define FRAGMENTS_MIN 2
#define FRAGMENTS_MAX 32
@@ -177,6 +177,9 @@ out:
static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
snd_pcm_uframes_t pos, void *buf, snd_pcm_uframes_t count)
{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct sport_device *sport = runtime->private_data;
+ struct bf5xx_tdm_port *tdm_port = sport->private_data;
unsigned int *src;
unsigned int *dst;
int i;
@@ -188,7 +191,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
dst += pos * 8;
while (count--) {
for (i = 0; i < substream->runtime->channels; i++)
- *(dst + i) = *src++;
+ *(dst + tdm_port->tx_map[i]) = *src++;
dst += 8;
}
} else {
@@ -198,7 +201,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
src += pos * 8;
while (count--) {
for (i = 0; i < substream->runtime->channels; i++)
- *dst++ = *(src+i);
+ *dst++ = *(src + tdm_port->rx_map[i]);
src += 8;
}
}
diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c
index ff546e91a22e..4b360124083e 100644
--- a/sound/soc/blackfin/bf5xx-tdm.c
+++ b/sound/soc/blackfin/bf5xx-tdm.c
@@ -46,14 +46,6 @@
#include "bf5xx-sport.h"
#include "bf5xx-tdm.h"
-struct bf5xx_tdm_port {
- u16 tcr1;
- u16 rcr1;
- u16 tcr2;
- u16 rcr2;
- int configured;
-};
-
static struct bf5xx_tdm_port bf5xx_tdm;
static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
@@ -181,6 +173,40 @@ static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream,
bf5xx_tdm.configured = 0;
}
+static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
+{
+ int i;
+ unsigned int slot;
+ unsigned int tx_mapped = 0, rx_mapped = 0;
+
+ if ((tx_num > BFIN_TDM_DAI_MAX_SLOTS) ||
+ (rx_num > BFIN_TDM_DAI_MAX_SLOTS))
+ return -EINVAL;
+
+ for (i = 0; i < tx_num; i++) {
+ slot = tx_slot[i];
+ if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
+ (!(tx_mapped & (1 << slot)))) {
+ bf5xx_tdm.tx_map[i] = slot;
+ tx_mapped |= 1 << slot;
+ } else
+ return -EINVAL;
+ }
+ for (i = 0; i < rx_num; i++) {
+ slot = rx_slot[i];
+ if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
+ (!(rx_mapped & (1 << slot)))) {
+ bf5xx_tdm.rx_map[i] = slot;
+ rx_mapped |= 1 << slot;
+ } else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_PM
static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
{
@@ -235,6 +261,7 @@ static struct snd_soc_dai_ops bf5xx_tdm_dai_ops = {
.hw_params = bf5xx_tdm_hw_params,
.set_fmt = bf5xx_tdm_set_dai_fmt,
.shutdown = bf5xx_tdm_shutdown,
+ .set_channel_map = bf5xx_tdm_set_channel_map,
};
struct snd_soc_dai bf5xx_tdm_dai = {
@@ -300,6 +327,8 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev)
pr_err("Failed to register DAI: %d\n", ret);
goto sport_config_err;
}
+
+ sport_handle->private_data = &bf5xx_tdm;
return 0;
sport_config_err:
diff --git a/sound/soc/blackfin/bf5xx-tdm.h b/sound/soc/blackfin/bf5xx-tdm.h
index 618ec3d90cd4..04189a18c1ba 100644
--- a/sound/soc/blackfin/bf5xx-tdm.h
+++ b/sound/soc/blackfin/bf5xx-tdm.h
@@ -9,6 +9,17 @@
#ifndef _BF5XX_TDM_H
#define _BF5XX_TDM_H
+#define BFIN_TDM_DAI_MAX_SLOTS 8
+struct bf5xx_tdm_port {
+ u16 tcr1;
+ u16 rcr1;
+ u16 tcr2;
+ u16 rcr2;
+ unsigned int tx_map[BFIN_TDM_DAI_MAX_SLOTS];
+ unsigned int rx_map[BFIN_TDM_DAI_MAX_SLOTS];
+ int configured;
+};
+
extern struct snd_soc_dai bf5xx_tdm_dai;
#endif
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 0edca93af3b0..d30fce71cfe8 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -19,6 +19,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_AK4104 if SPI_MASTER
select SND_SOC_AK4535 if I2C
select SND_SOC_AK4642 if I2C
+ select SND_SOC_AK4671 if I2C
select SND_SOC_CS4270 if I2C
select SND_SOC_MAX9877 if I2C
select SND_SOC_PCM3008
@@ -28,6 +29,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_TLV320AIC23 if I2C
select SND_SOC_TLV320AIC26 if SPI_MASTER
select SND_SOC_TLV320AIC3X if I2C
+ select SND_SOC_TPA6130A2 if I2C
+ select SND_SOC_TLV320DAC33 if I2C
select SND_SOC_TWL4030 if TWL4030_CORE
select SND_SOC_UDA134X
select SND_SOC_UDA1380 if I2C
@@ -36,6 +39,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8523 if I2C
select SND_SOC_WM8580 if I2C
+ select SND_SOC_WM8711 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
@@ -96,6 +100,9 @@ config SND_SOC_AK4535
config SND_SOC_AK4642
tristate
+config SND_SOC_AK4671
+ tristate
+
# Cirrus Logic CS4270 Codec
config SND_SOC_CS4270
tristate
@@ -136,6 +143,9 @@ config SND_SOC_TLV320AIC26
config SND_SOC_TLV320AIC3X
tristate
+config SND_SOC_TLV320DAC33
+ tristate
+
config SND_SOC_TWL4030
tristate
@@ -160,6 +170,9 @@ config SND_SOC_WM8523
config SND_SOC_WM8580
tristate
+config SND_SOC_WM8711
+ tristate
+
config SND_SOC_WM8728
tristate
@@ -220,3 +233,6 @@ config SND_SOC_WM9713
# Amp
config SND_SOC_MAX9877
tristate
+
+config SND_SOC_TPA6130A2
+ tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index fb4af28486ba..8f519ee9600d 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -6,6 +6,7 @@ snd-soc-ad73311-objs := ad73311.o
snd-soc-ak4104-objs := ak4104.o
snd-soc-ak4535-objs := ak4535.o
snd-soc-ak4642-objs := ak4642.o
+snd-soc-ak4671-objs := ak4671.o
snd-soc-cs4270-objs := cs4270.o
snd-soc-cx20442-objs := cx20442.o
snd-soc-l3-objs := l3.o
@@ -16,6 +17,7 @@ snd-soc-stac9766-objs := stac9766.o
snd-soc-tlv320aic23-objs := tlv320aic23.o
snd-soc-tlv320aic26-objs := tlv320aic26.o
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
+snd-soc-tlv320dac33-objs := tlv320dac33.o
snd-soc-twl4030-objs := twl4030.o
snd-soc-uda134x-objs := uda134x.o
snd-soc-uda1380-objs := uda1380.o
@@ -24,6 +26,7 @@ snd-soc-wm8400-objs := wm8400.o
snd-soc-wm8510-objs := wm8510.o
snd-soc-wm8523-objs := wm8523.o
snd-soc-wm8580-objs := wm8580.o
+snd-soc-wm8711-objs := wm8711.o
snd-soc-wm8728-objs := wm8728.o
snd-soc-wm8731-objs := wm8731.o
snd-soc-wm8750-objs := wm8750.o
@@ -47,6 +50,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o
# Amp
snd-soc-max9877-objs := max9877.o
+snd-soc-tpa6130a2-objs := tpa6130a2.o
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o
@@ -56,6 +60,7 @@ obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o
+obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
@@ -66,6 +71,7 @@ obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
+obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o
obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
@@ -74,6 +80,7 @@ obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o
obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o
obj-$(CONFIG_SND_SOC_WM8523) += snd-soc-wm8523.o
obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o
+obj-$(CONFIG_SND_SOC_WM8711) += snd-soc-wm8711.o
obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o
obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o
obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o
@@ -97,3 +104,4 @@ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
# Amp
obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
+obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
new file mode 100644
index 000000000000..b61214d1c5de
--- /dev/null
+++ b/sound/soc/codecs/ak4671.c
@@ -0,0 +1,825 @@
+/*
+ * ak4671.c -- audio driver for AK4671
+ *
+ * Copyright (C) 2009 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@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/init.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "ak4671.h"
+
+static struct snd_soc_codec *ak4671_codec;
+
+/* codec private data */
+struct ak4671_priv {
+ struct snd_soc_codec codec;
+ u8 reg_cache[AK4671_CACHEREGNUM];
+};
+
+/* ak4671 register cache & default register settings */
+static const u8 ak4671_reg[AK4671_CACHEREGNUM] = {
+ 0x00, /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) */
+ 0xf6, /* AK4671_PLL_MODE_SELECT0 (0x01) */
+ 0x00, /* AK4671_PLL_MODE_SELECT1 (0x02) */
+ 0x02, /* AK4671_FORMAT_SELECT (0x03) */
+ 0x00, /* AK4671_MIC_SIGNAL_SELECT (0x04) */
+ 0x55, /* AK4671_MIC_AMP_GAIN (0x05) */
+ 0x00, /* AK4671_MIXING_POWER_MANAGEMENT0 (0x06) */
+ 0x00, /* AK4671_MIXING_POWER_MANAGEMENT1 (0x07) */
+ 0xb5, /* AK4671_OUTPUT_VOLUME_CONTROL (0x08) */
+ 0x00, /* AK4671_LOUT1_SIGNAL_SELECT (0x09) */
+ 0x00, /* AK4671_ROUT1_SIGNAL_SELECT (0x0a) */
+ 0x00, /* AK4671_LOUT2_SIGNAL_SELECT (0x0b) */
+ 0x00, /* AK4671_ROUT2_SIGNAL_SELECT (0x0c) */
+ 0x00, /* AK4671_LOUT3_SIGNAL_SELECT (0x0d) */
+ 0x00, /* AK4671_ROUT3_SIGNAL_SELECT (0x0e) */
+ 0x00, /* AK4671_LOUT1_POWER_MANAGERMENT (0x0f) */
+ 0x00, /* AK4671_LOUT2_POWER_MANAGERMENT (0x10) */
+ 0x80, /* AK4671_LOUT3_POWER_MANAGERMENT (0x11) */
+ 0x91, /* AK4671_LCH_INPUT_VOLUME_CONTROL (0x12) */
+ 0x91, /* AK4671_RCH_INPUT_VOLUME_CONTROL (0x13) */
+ 0xe1, /* AK4671_ALC_REFERENCE_SELECT (0x14) */
+ 0x00, /* AK4671_DIGITAL_MIXING_CONTROL (0x15) */
+ 0x00, /* AK4671_ALC_TIMER_SELECT (0x16) */
+ 0x00, /* AK4671_ALC_MODE_CONTROL (0x17) */
+ 0x02, /* AK4671_MODE_CONTROL1 (0x18) */
+ 0x01, /* AK4671_MODE_CONTROL2 (0x19) */
+ 0x18, /* AK4671_LCH_OUTPUT_VOLUME_CONTROL (0x1a) */
+ 0x18, /* AK4671_RCH_OUTPUT_VOLUME_CONTROL (0x1b) */
+ 0x00, /* AK4671_SIDETONE_A_CONTROL (0x1c) */
+ 0x02, /* AK4671_DIGITAL_FILTER_SELECT (0x1d) */
+ 0x00, /* AK4671_FIL3_COEFFICIENT0 (0x1e) */
+ 0x00, /* AK4671_FIL3_COEFFICIENT1 (0x1f) */
+ 0x00, /* AK4671_FIL3_COEFFICIENT2 (0x20) */
+ 0x00, /* AK4671_FIL3_COEFFICIENT3 (0x21) */
+ 0x00, /* AK4671_EQ_COEFFICIENT0 (0x22) */
+ 0x00, /* AK4671_EQ_COEFFICIENT1 (0x23) */
+ 0x00, /* AK4671_EQ_COEFFICIENT2 (0x24) */
+ 0x00, /* AK4671_EQ_COEFFICIENT3 (0x25) */
+ 0x00, /* AK4671_EQ_COEFFICIENT4 (0x26) */
+ 0x00, /* AK4671_EQ_COEFFICIENT5 (0x27) */
+ 0xa9, /* AK4671_FIL1_COEFFICIENT0 (0x28) */
+ 0x1f, /* AK4671_FIL1_COEFFICIENT1 (0x29) */
+ 0xad, /* AK4671_FIL1_COEFFICIENT2 (0x2a) */
+ 0x20, /* AK4671_FIL1_COEFFICIENT3 (0x2b) */
+ 0x00, /* AK4671_FIL2_COEFFICIENT0 (0x2c) */
+ 0x00, /* AK4671_FIL2_COEFFICIENT1 (0x2d) */
+ 0x00, /* AK4671_FIL2_COEFFICIENT2 (0x2e) */
+ 0x00, /* AK4671_FIL2_COEFFICIENT3 (0x2f) */
+ 0x00, /* AK4671_DIGITAL_FILTER_SELECT2 (0x30) */
+ 0x00, /* this register not used */
+ 0x00, /* AK4671_E1_COEFFICIENT0 (0x32) */
+ 0x00, /* AK4671_E1_COEFFICIENT1 (0x33) */
+ 0x00, /* AK4671_E1_COEFFICIENT2 (0x34) */
+ 0x00, /* AK4671_E1_COEFFICIENT3 (0x35) */
+ 0x00, /* AK4671_E1_COEFFICIENT4 (0x36) */
+ 0x00, /* AK4671_E1_COEFFICIENT5 (0x37) */
+ 0x00, /* AK4671_E2_COEFFICIENT0 (0x38) */
+ 0x00, /* AK4671_E2_COEFFICIENT1 (0x39) */
+ 0x00, /* AK4671_E2_COEFFICIENT2 (0x3a) */
+ 0x00, /* AK4671_E2_COEFFICIENT3 (0x3b) */
+ 0x00, /* AK4671_E2_COEFFICIENT4 (0x3c) */
+ 0x00, /* AK4671_E2_COEFFICIENT5 (0x3d) */
+ 0x00, /* AK4671_E3_COEFFICIENT0 (0x3e) */
+ 0x00, /* AK4671_E3_COEFFICIENT1 (0x3f) */
+ 0x00, /* AK4671_E3_COEFFICIENT2 (0x40) */
+ 0x00, /* AK4671_E3_COEFFICIENT3 (0x41) */
+ 0x00, /* AK4671_E3_COEFFICIENT4 (0x42) */
+ 0x00, /* AK4671_E3_COEFFICIENT5 (0x43) */
+ 0x00, /* AK4671_E4_COEFFICIENT0 (0x44) */
+ 0x00, /* AK4671_E4_COEFFICIENT1 (0x45) */
+ 0x00, /* AK4671_E4_COEFFICIENT2 (0x46) */
+ 0x00, /* AK4671_E4_COEFFICIENT3 (0x47) */
+ 0x00, /* AK4671_E4_COEFFICIENT4 (0x48) */
+ 0x00, /* AK4671_E4_COEFFICIENT5 (0x49) */
+ 0x00, /* AK4671_E5_COEFFICIENT0 (0x4a) */
+ 0x00, /* AK4671_E5_COEFFICIENT1 (0x4b) */
+ 0x00, /* AK4671_E5_COEFFICIENT2 (0x4c) */
+ 0x00, /* AK4671_E5_COEFFICIENT3 (0x4d) */
+ 0x00, /* AK4671_E5_COEFFICIENT4 (0x4e) */
+ 0x00, /* AK4671_E5_COEFFICIENT5 (0x4f) */
+ 0x88, /* AK4671_EQ_CONTROL_250HZ_100HZ (0x50) */
+ 0x88, /* AK4671_EQ_CONTROL_3500HZ_1KHZ (0x51) */
+ 0x08, /* AK4671_EQ_CONTRO_10KHZ (0x52) */
+ 0x00, /* AK4671_PCM_IF_CONTROL0 (0x53) */
+ 0x00, /* AK4671_PCM_IF_CONTROL1 (0x54) */
+ 0x00, /* AK4671_PCM_IF_CONTROL2 (0x55) */
+ 0x18, /* AK4671_DIGITAL_VOLUME_B_CONTROL (0x56) */
+ 0x18, /* AK4671_DIGITAL_VOLUME_C_CONTROL (0x57) */
+ 0x00, /* AK4671_SIDETONE_VOLUME_CONTROL (0x58) */
+ 0x00, /* AK4671_DIGITAL_MIXING_CONTROL2 (0x59) */
+ 0x00, /* AK4671_SAR_ADC_CONTROL (0x5a) */
+};
+
+/*
+ * LOUT1/ROUT1 output volume control:
+ * from -24 to 6 dB in 6 dB steps (mute instead of -30 dB)
+ */
+static DECLARE_TLV_DB_SCALE(out1_tlv, -3000, 600, 1);
+
+/*
+ * LOUT2/ROUT2 output volume control:
+ * from -33 to 6 dB in 3 dB steps (mute instead of -33 dB)
+ */
+static DECLARE_TLV_DB_SCALE(out2_tlv, -3300, 300, 1);
+
+/*
+ * LOUT3/ROUT3 output volume control:
+ * from -6 to 3 dB in 3 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(out3_tlv, -600, 300, 0);
+
+/*
+ * Mic amp gain control:
+ * from -15 to 30 dB in 3 dB steps
+ * REVISIT: The actual min value(0x01) is -12 dB and the reg value 0x00 is not
+ * available
+ */
+static DECLARE_TLV_DB_SCALE(mic_amp_tlv, -1500, 300, 0);
+
+static const struct snd_kcontrol_new ak4671_snd_controls[] = {
+ /* Common playback gain controls */
+ SOC_SINGLE_TLV("Line Output1 Playback Volume",
+ AK4671_OUTPUT_VOLUME_CONTROL, 0, 0x6, 0, out1_tlv),
+ SOC_SINGLE_TLV("Headphone Output2 Playback Volume",
+ AK4671_OUTPUT_VOLUME_CONTROL, 4, 0xd, 0, out2_tlv),
+ SOC_SINGLE_TLV("Line Output3 Playback Volume",
+ AK4671_LOUT3_POWER_MANAGERMENT, 6, 0x3, 0, out3_tlv),
+
+ /* Common capture gain controls */
+ SOC_DOUBLE_TLV("Mic Amp Capture Volume",
+ AK4671_MIC_AMP_GAIN, 0, 4, 0xf, 0, mic_amp_tlv),
+};
+
+/* event handlers */
+static int ak4671_out2_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ u8 reg;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ reg = snd_soc_read(codec, AK4671_LOUT2_POWER_MANAGERMENT);
+ reg |= AK4671_MUTEN;
+ snd_soc_write(codec, AK4671_LOUT2_POWER_MANAGERMENT, reg);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ reg = snd_soc_read(codec, AK4671_LOUT2_POWER_MANAGERMENT);
+ reg &= ~AK4671_MUTEN;
+ snd_soc_write(codec, AK4671_LOUT2_POWER_MANAGERMENT, reg);
+ break;
+ }
+
+ return 0;
+}
+
+/* Output Mixers */
+static const struct snd_kcontrol_new ak4671_lout1_mixer_controls[] = {
+ SOC_DAPM_SINGLE("DACL", AK4671_LOUT1_SIGNAL_SELECT, 0, 1, 0),
+ SOC_DAPM_SINGLE("LINL1", AK4671_LOUT1_SIGNAL_SELECT, 1, 1, 0),
+ SOC_DAPM_SINGLE("LINL2", AK4671_LOUT1_SIGNAL_SELECT, 2, 1, 0),
+ SOC_DAPM_SINGLE("LINL3", AK4671_LOUT1_SIGNAL_SELECT, 3, 1, 0),
+ SOC_DAPM_SINGLE("LINL4", AK4671_LOUT1_SIGNAL_SELECT, 4, 1, 0),
+ SOC_DAPM_SINGLE("LOOPL", AK4671_LOUT1_SIGNAL_SELECT, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new ak4671_rout1_mixer_controls[] = {
+ SOC_DAPM_SINGLE("DACR", AK4671_ROUT1_SIGNAL_SELECT, 0, 1, 0),
+ SOC_DAPM_SINGLE("RINR1", AK4671_ROUT1_SIGNAL_SELECT, 1, 1, 0),
+ SOC_DAPM_SINGLE("RINR2", AK4671_ROUT1_SIGNAL_SELECT, 2, 1, 0),
+ SOC_DAPM_SINGLE("RINR3", AK4671_ROUT1_SIGNAL_SELECT, 3, 1, 0),
+ SOC_DAPM_SINGLE("RINR4", AK4671_ROUT1_SIGNAL_SELECT, 4, 1, 0),
+ SOC_DAPM_SINGLE("LOOPR", AK4671_ROUT1_SIGNAL_SELECT, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new ak4671_lout2_mixer_controls[] = {
+ SOC_DAPM_SINGLE("DACHL", AK4671_LOUT2_SIGNAL_SELECT, 0, 1, 0),
+ SOC_DAPM_SINGLE("LINH1", AK4671_LOUT2_SIGNAL_SELECT, 1, 1, 0),
+ SOC_DAPM_SINGLE("LINH2", AK4671_LOUT2_SIGNAL_SELECT, 2, 1, 0),
+ SOC_DAPM_SINGLE("LINH3", AK4671_LOUT2_SIGNAL_SELECT, 3, 1, 0),
+ SOC_DAPM_SINGLE("LINH4", AK4671_LOUT2_SIGNAL_SELECT, 4, 1, 0),
+ SOC_DAPM_SINGLE("LOOPHL", AK4671_LOUT2_SIGNAL_SELECT, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new ak4671_rout2_mixer_controls[] = {
+ SOC_DAPM_SINGLE("DACHR", AK4671_ROUT2_SIGNAL_SELECT, 0, 1, 0),
+ SOC_DAPM_SINGLE("RINH1", AK4671_ROUT2_SIGNAL_SELECT, 1, 1, 0),
+ SOC_DAPM_SINGLE("RINH2", AK4671_ROUT2_SIGNAL_SELECT, 2, 1, 0),
+ SOC_DAPM_SINGLE("RINH3", AK4671_ROUT2_SIGNAL_SELECT, 3, 1, 0),
+ SOC_DAPM_SINGLE("RINH4", AK4671_ROUT2_SIGNAL_SELECT, 4, 1, 0),
+ SOC_DAPM_SINGLE("LOOPHR", AK4671_ROUT2_SIGNAL_SELECT, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new ak4671_lout3_mixer_controls[] = {
+ SOC_DAPM_SINGLE("DACSL", AK4671_LOUT3_SIGNAL_SELECT, 0, 1, 0),
+ SOC_DAPM_SINGLE("LINS1", AK4671_LOUT3_SIGNAL_SELECT, 1, 1, 0),
+ SOC_DAPM_SINGLE("LINS2", AK4671_LOUT3_SIGNAL_SELECT, 2, 1, 0),
+ SOC_DAPM_SINGLE("LINS3", AK4671_LOUT3_SIGNAL_SELECT, 3, 1, 0),
+ SOC_DAPM_SINGLE("LINS4", AK4671_LOUT3_SIGNAL_SELECT, 4, 1, 0),
+ SOC_DAPM_SINGLE("LOOPSL", AK4671_LOUT3_SIGNAL_SELECT, 5, 1, 0),
+};
+
+static const struct snd_kcontrol_new ak4671_rout3_mixer_controls[] = {
+ SOC_DAPM_SINGLE("DACSR", AK4671_ROUT3_SIGNAL_SELECT, 0, 1, 0),
+ SOC_DAPM_SINGLE("RINS1", AK4671_ROUT3_SIGNAL_SELECT, 1, 1, 0),
+ SOC_DAPM_SINGLE("RINS2", AK4671_ROUT3_SIGNAL_SELECT, 2, 1, 0),
+ SOC_DAPM_SINGLE("RINS3", AK4671_ROUT3_SIGNAL_SELECT, 3, 1, 0),
+ SOC_DAPM_SINGLE("RINS4", AK4671_ROUT3_SIGNAL_SELECT, 4, 1, 0),
+ SOC_DAPM_SINGLE("LOOPSR", AK4671_ROUT3_SIGNAL_SELECT, 5, 1, 0),
+};
+
+/* Input MUXs */
+static const char *ak4671_lin_mux_texts[] =
+ {"LIN1", "LIN2", "LIN3", "LIN4"};
+static const struct soc_enum ak4671_lin_mux_enum =
+ SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 0,
+ ARRAY_SIZE(ak4671_lin_mux_texts),
+ ak4671_lin_mux_texts);
+static const struct snd_kcontrol_new ak4671_lin_mux_control =
+ SOC_DAPM_ENUM("Route", ak4671_lin_mux_enum);
+
+static const char *ak4671_rin_mux_texts[] =
+ {"RIN1", "RIN2", "RIN3", "RIN4"};
+static const struct soc_enum ak4671_rin_mux_enum =
+ SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 2,
+ ARRAY_SIZE(ak4671_rin_mux_texts),
+ ak4671_rin_mux_texts);
+static const struct snd_kcontrol_new ak4671_rin_mux_control =
+ SOC_DAPM_ENUM("Route", ak4671_rin_mux_enum);
+
+static const struct snd_soc_dapm_widget ak4671_dapm_widgets[] = {
+ /* Inputs */
+ SND_SOC_DAPM_INPUT("LIN1"),
+ SND_SOC_DAPM_INPUT("RIN1"),
+ SND_SOC_DAPM_INPUT("LIN2"),
+ SND_SOC_DAPM_INPUT("RIN2"),
+ SND_SOC_DAPM_INPUT("LIN3"),
+ SND_SOC_DAPM_INPUT("RIN3"),
+ SND_SOC_DAPM_INPUT("LIN4"),
+ SND_SOC_DAPM_INPUT("RIN4"),
+
+ /* Outputs */
+ SND_SOC_DAPM_OUTPUT("LOUT1"),
+ SND_SOC_DAPM_OUTPUT("ROUT1"),
+ SND_SOC_DAPM_OUTPUT("LOUT2"),
+ SND_SOC_DAPM_OUTPUT("ROUT2"),
+ SND_SOC_DAPM_OUTPUT("LOUT3"),
+ SND_SOC_DAPM_OUTPUT("ROUT3"),
+
+ /* DAC */
+ SND_SOC_DAPM_DAC("DAC Left", "Left HiFi Playback",
+ AK4671_AD_DA_POWER_MANAGEMENT, 6, 0),
+ SND_SOC_DAPM_DAC("DAC Right", "Right HiFi Playback",
+ AK4671_AD_DA_POWER_MANAGEMENT, 7, 0),
+
+ /* ADC */
+ SND_SOC_DAPM_ADC("ADC Left", "Left HiFi Capture",
+ AK4671_AD_DA_POWER_MANAGEMENT, 4, 0),
+ SND_SOC_DAPM_ADC("ADC Right", "Right HiFi Capture",
+ AK4671_AD_DA_POWER_MANAGEMENT, 5, 0),
+
+ /* PGA */
+ SND_SOC_DAPM_PGA("LOUT2 Mix Amp",
+ AK4671_LOUT2_POWER_MANAGERMENT, 5, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ROUT2 Mix Amp",
+ AK4671_LOUT2_POWER_MANAGERMENT, 6, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("LIN1 Mixing Circuit",
+ AK4671_MIXING_POWER_MANAGEMENT1, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("RIN1 Mixing Circuit",
+ AK4671_MIXING_POWER_MANAGEMENT1, 1, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("LIN2 Mixing Circuit",
+ AK4671_MIXING_POWER_MANAGEMENT1, 2, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("RIN2 Mixing Circuit",
+ AK4671_MIXING_POWER_MANAGEMENT1, 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("LIN3 Mixing Circuit",
+ AK4671_MIXING_POWER_MANAGEMENT1, 4, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("RIN3 Mixing Circuit",
+ AK4671_MIXING_POWER_MANAGEMENT1, 5, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("LIN4 Mixing Circuit",
+ AK4671_MIXING_POWER_MANAGEMENT1, 6, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("RIN4 Mixing Circuit",
+ AK4671_MIXING_POWER_MANAGEMENT1, 7, 0, NULL, 0),
+
+ /* Output Mixers */
+ SND_SOC_DAPM_MIXER("LOUT1 Mixer", AK4671_LOUT1_POWER_MANAGERMENT, 0, 0,
+ &ak4671_lout1_mixer_controls[0],
+ ARRAY_SIZE(ak4671_lout1_mixer_controls)),
+ SND_SOC_DAPM_MIXER("ROUT1 Mixer", AK4671_LOUT1_POWER_MANAGERMENT, 1, 0,
+ &ak4671_rout1_mixer_controls[0],
+ ARRAY_SIZE(ak4671_rout1_mixer_controls)),
+ SND_SOC_DAPM_MIXER_E("LOUT2 Mixer", AK4671_LOUT2_POWER_MANAGERMENT,
+ 0, 0, &ak4671_lout2_mixer_controls[0],
+ ARRAY_SIZE(ak4671_lout2_mixer_controls),
+ ak4671_out2_event,
+ SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_MIXER_E("ROUT2 Mixer", AK4671_LOUT2_POWER_MANAGERMENT,
+ 1, 0, &ak4671_rout2_mixer_controls[0],
+ ARRAY_SIZE(ak4671_rout2_mixer_controls),
+ ak4671_out2_event,
+ SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_MIXER("LOUT3 Mixer", AK4671_LOUT3_POWER_MANAGERMENT, 0, 0,
+ &ak4671_lout3_mixer_controls[0],
+ ARRAY_SIZE(ak4671_lout3_mixer_controls)),
+ SND_SOC_DAPM_MIXER("ROUT3 Mixer", AK4671_LOUT3_POWER_MANAGERMENT, 1, 0,
+ &ak4671_rout3_mixer_controls[0],
+ ARRAY_SIZE(ak4671_rout3_mixer_controls)),
+
+ /* Input MUXs */
+ SND_SOC_DAPM_MUX("LIN MUX", AK4671_AD_DA_POWER_MANAGEMENT, 2, 0,
+ &ak4671_lin_mux_control),
+ SND_SOC_DAPM_MUX("RIN MUX", AK4671_AD_DA_POWER_MANAGEMENT, 3, 0,
+ &ak4671_rin_mux_control),
+
+ /* Mic Power */
+ SND_SOC_DAPM_MICBIAS("Mic Bias", AK4671_AD_DA_POWER_MANAGEMENT, 1, 0),
+
+ /* Supply */
+ SND_SOC_DAPM_SUPPLY("PMPLL", AK4671_PLL_MODE_SELECT1, 0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+ {"DAC Left", "NULL", "PMPLL"},
+ {"DAC Right", "NULL", "PMPLL"},
+ {"ADC Left", "NULL", "PMPLL"},
+ {"ADC Right", "NULL", "PMPLL"},
+
+ /* Outputs */
+ {"LOUT1", "NULL", "LOUT1 Mixer"},
+ {"ROUT1", "NULL", "ROUT1 Mixer"},
+ {"LOUT2", "NULL", "LOUT2 Mix Amp"},
+ {"ROUT2", "NULL", "ROUT2 Mix Amp"},
+ {"LOUT3", "NULL", "LOUT3 Mixer"},
+ {"ROUT3", "NULL", "ROUT3 Mixer"},
+
+ {"LOUT1 Mixer", "DACL", "DAC Left"},
+ {"ROUT1 Mixer", "DACR", "DAC Right"},
+ {"LOUT2 Mixer", "DACHL", "DAC Left"},
+ {"ROUT2 Mixer", "DACHR", "DAC Right"},
+ {"LOUT2 Mix Amp", "NULL", "LOUT2 Mixer"},
+ {"ROUT2 Mix Amp", "NULL", "ROUT2 Mixer"},
+ {"LOUT3 Mixer", "DACSL", "DAC Left"},
+ {"ROUT3 Mixer", "DACSR", "DAC Right"},
+
+ /* Inputs */
+ {"LIN MUX", "LIN1", "LIN1"},
+ {"LIN MUX", "LIN2", "LIN2"},
+ {"LIN MUX", "LIN3", "LIN3"},
+ {"LIN MUX", "LIN4", "LIN4"},
+
+ {"RIN MUX", "RIN1", "RIN1"},
+ {"RIN MUX", "RIN2", "RIN2"},
+ {"RIN MUX", "RIN3", "RIN3"},
+ {"RIN MUX", "RIN4", "RIN4"},
+
+ {"LIN1", NULL, "Mic Bias"},
+ {"RIN1", NULL, "Mic Bias"},
+ {"LIN2", NULL, "Mic Bias"},
+ {"RIN2", NULL, "Mic Bias"},
+
+ {"ADC Left", "NULL", "LIN MUX"},
+ {"ADC Right", "NULL", "RIN MUX"},
+
+ /* Analog Loops */
+ {"LIN1 Mixing Circuit", "NULL", "LIN1"},
+ {"RIN1 Mixing Circuit", "NULL", "RIN1"},
+ {"LIN2 Mixing Circuit", "NULL", "LIN2"},
+ {"RIN2 Mixing Circuit", "NULL", "RIN2"},
+ {"LIN3 Mixing Circuit", "NULL", "LIN3"},
+ {"RIN3 Mixing Circuit", "NULL", "RIN3"},
+ {"LIN4 Mixing Circuit", "NULL", "LIN4"},
+ {"RIN4 Mixing Circuit", "NULL", "RIN4"},
+
+ {"LOUT1 Mixer", "LINL1", "LIN1 Mixing Circuit"},
+ {"ROUT1 Mixer", "RINR1", "RIN1 Mixing Circuit"},
+ {"LOUT2 Mixer", "LINH1", "LIN1 Mixing Circuit"},
+ {"ROUT2 Mixer", "RINH1", "RIN1 Mixing Circuit"},
+ {"LOUT3 Mixer", "LINS1", "LIN1 Mixing Circuit"},
+ {"ROUT3 Mixer", "RINS1", "RIN1 Mixing Circuit"},
+
+ {"LOUT1 Mixer", "LINL2", "LIN2 Mixing Circuit"},
+ {"ROUT1 Mixer", "RINR2", "RIN2 Mixing Circuit"},
+ {"LOUT2 Mixer", "LINH2", "LIN2 Mixing Circuit"},
+ {"ROUT2 Mixer", "RINH2", "RIN2 Mixing Circuit"},
+ {"LOUT3 Mixer", "LINS2", "LIN2 Mixing Circuit"},
+ {"ROUT3 Mixer", "RINS2", "RIN2 Mixing Circuit"},
+
+ {"LOUT1 Mixer", "LINL3", "LIN3 Mixing Circuit"},
+ {"ROUT1 Mixer", "RINR3", "RIN3 Mixing Circuit"},
+ {"LOUT2 Mixer", "LINH3", "LIN3 Mixing Circuit"},
+ {"ROUT2 Mixer", "RINH3", "RIN3 Mixing Circuit"},
+ {"LOUT3 Mixer", "LINS3", "LIN3 Mixing Circuit"},
+ {"ROUT3 Mixer", "RINS3", "RIN3 Mixing Circuit"},
+
+ {"LOUT1 Mixer", "LINL4", "LIN4 Mixing Circuit"},
+ {"ROUT1 Mixer", "RINR4", "RIN4 Mixing Circuit"},
+ {"LOUT2 Mixer", "LINH4", "LIN4 Mixing Circuit"},
+ {"ROUT2 Mixer", "RINH4", "RIN4 Mixing Circuit"},
+ {"LOUT3 Mixer", "LINS4", "LIN4 Mixing Circuit"},
+ {"ROUT3 Mixer", "RINS4", "RIN4 Mixing Circuit"},
+};
+
+static int ak4671_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, ak4671_dapm_widgets,
+ ARRAY_SIZE(ak4671_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+ snd_soc_dapm_new_widgets(codec);
+ return 0;
+}
+
+static int ak4671_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;
+ u8 fs;
+
+ fs = snd_soc_read(codec, AK4671_PLL_MODE_SELECT0);
+ fs &= ~AK4671_FS;
+
+ switch (params_rate(params)) {
+ case 8000:
+ fs |= AK4671_FS_8KHZ;
+ break;
+ case 12000:
+ fs |= AK4671_FS_12KHZ;
+ break;
+ case 16000:
+ fs |= AK4671_FS_16KHZ;
+ break;
+ case 24000:
+ fs |= AK4671_FS_24KHZ;
+ break;
+ case 11025:
+ fs |= AK4671_FS_11_025KHZ;
+ break;
+ case 22050:
+ fs |= AK4671_FS_22_05KHZ;
+ break;
+ case 32000:
+ fs |= AK4671_FS_32KHZ;
+ break;
+ case 44100:
+ fs |= AK4671_FS_44_1KHZ;
+ break;
+ case 48000:
+ fs |= AK4671_FS_48KHZ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_write(codec, AK4671_PLL_MODE_SELECT0, fs);
+
+ return 0;
+}
+
+static int ak4671_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u8 pll;
+
+ pll = snd_soc_read(codec, AK4671_PLL_MODE_SELECT0);
+ pll &= ~AK4671_PLL;
+
+ switch (freq) {
+ case 11289600:
+ pll |= AK4671_PLL_11_2896MHZ;
+ break;
+ case 12000000:
+ pll |= AK4671_PLL_12MHZ;
+ break;
+ case 12288000:
+ pll |= AK4671_PLL_12_288MHZ;
+ break;
+ case 13000000:
+ pll |= AK4671_PLL_13MHZ;
+ break;
+ case 13500000:
+ pll |= AK4671_PLL_13_5MHZ;
+ break;
+ case 19200000:
+ pll |= AK4671_PLL_19_2MHZ;
+ break;
+ case 24000000:
+ pll |= AK4671_PLL_24MHZ;
+ break;
+ case 26000000:
+ pll |= AK4671_PLL_26MHZ;
+ break;
+ case 27000000:
+ pll |= AK4671_PLL_27MHZ;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_write(codec, AK4671_PLL_MODE_SELECT0, pll);
+
+ return 0;
+}
+
+static int ak4671_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u8 mode;
+ u8 format;
+
+ /* set master/slave audio interface */
+ mode = snd_soc_read(codec, AK4671_PLL_MODE_SELECT1);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ mode |= AK4671_M_S;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ mode &= ~(AK4671_M_S);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* interface format */
+ format = snd_soc_read(codec, AK4671_FORMAT_SELECT);
+ format &= ~AK4671_DIF;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ format |= AK4671_DIF_I2S_MODE;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ format |= AK4671_DIF_MSB_MODE;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ format |= AK4671_DIF_DSP_MODE;
+ format |= AK4671_BCKP;
+ format |= AK4671_MSBS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* set mode and format */
+ snd_soc_write(codec, AK4671_PLL_MODE_SELECT1, mode);
+ snd_soc_write(codec, AK4671_FORMAT_SELECT, format);
+
+ return 0;
+}
+
+static int ak4671_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ u8 reg;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ case SND_SOC_BIAS_PREPARE:
+ case SND_SOC_BIAS_STANDBY:
+ reg = snd_soc_read(codec, AK4671_AD_DA_POWER_MANAGEMENT);
+ snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT,
+ reg | AK4671_PMVCM);
+ break;
+ case SND_SOC_BIAS_OFF:
+ snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, 0x00);
+ break;
+ }
+ codec->bias_level = level;
+ return 0;
+}
+
+#define AK4671_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+ SNDRV_PCM_RATE_48000)
+
+#define AK4671_FORMATS SNDRV_PCM_FMTBIT_S16_LE
+
+static struct snd_soc_dai_ops ak4671_dai_ops = {
+ .hw_params = ak4671_hw_params,
+ .set_sysclk = ak4671_set_dai_sysclk,
+ .set_fmt = ak4671_set_dai_fmt,
+};
+
+struct snd_soc_dai ak4671_dai = {
+ .name = "AK4671",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AK4671_RATES,
+ .formats = AK4671_FORMATS,},
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AK4671_RATES,
+ .formats = AK4671_FORMATS,},
+ .ops = &ak4671_dai_ops,
+};
+EXPORT_SYMBOL_GPL(ak4671_dai);
+
+static int ak4671_probe(struct platform_device *pdev)
+{
+ 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;
+ }
+
+ socdev->card->codec = ak4671_codec;
+ codec = ak4671_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, ak4671_snd_controls,
+ ARRAY_SIZE(ak4671_snd_controls));
+ ak4671_add_widgets(codec);
+
+ ret = snd_soc_init_card(socdev);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to register card: %d\n", ret);
+ goto card_err;
+ }
+
+ ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return ret;
+
+card_err:
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+pcm_err:
+ return ret;
+}
+
+static int ak4671_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_ak4671 = {
+ .probe = ak4671_probe,
+ .remove = ak4671_remove,
+};
+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);
+
+ codec->private_data = 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;
+
+ 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;
+
+ return ak4671_register(ak4671, SND_SOC_I2C);
+}
+
+static __devexit int ak4671_i2c_remove(struct i2c_client *client)
+{
+ struct ak4671_priv *ak4671 = i2c_get_clientdata(client);
+
+ ak4671_unregister(ak4671);
+
+ return 0;
+}
+
+static const struct i2c_device_id ak4671_i2c_id[] = {
+ { "ak4671", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ak4671_i2c_id);
+
+static struct i2c_driver ak4671_i2c_driver = {
+ .driver = {
+ .name = "ak4671",
+ .owner = THIS_MODULE,
+ },
+ .probe = ak4671_i2c_probe,
+ .remove = __devexit_p(ak4671_i2c_remove),
+ .id_table = ak4671_i2c_id,
+};
+
+static int __init ak4671_modinit(void)
+{
+ return i2c_add_driver(&ak4671_i2c_driver);
+}
+module_init(ak4671_modinit);
+
+static void __exit ak4671_exit(void)
+{
+ i2c_del_driver(&ak4671_i2c_driver);
+}
+module_exit(ak4671_exit);
+
+MODULE_DESCRIPTION("ASoC AK4671 codec driver");
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ak4671.h b/sound/soc/codecs/ak4671.h
new file mode 100644
index 000000000000..e2fad964e88b
--- /dev/null
+++ b/sound/soc/codecs/ak4671.h
@@ -0,0 +1,156 @@
+/*
+ * ak4671.h -- audio driver for AK4671
+ *
+ * Copyright (C) 2009 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@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.
+ *
+ */
+
+#ifndef _AK4671_H
+#define _AK4671_H
+
+#define AK4671_AD_DA_POWER_MANAGEMENT 0x00
+#define AK4671_PLL_MODE_SELECT0 0x01
+#define AK4671_PLL_MODE_SELECT1 0x02
+#define AK4671_FORMAT_SELECT 0x03
+#define AK4671_MIC_SIGNAL_SELECT 0x04
+#define AK4671_MIC_AMP_GAIN 0x05
+#define AK4671_MIXING_POWER_MANAGEMENT0 0x06
+#define AK4671_MIXING_POWER_MANAGEMENT1 0x07
+#define AK4671_OUTPUT_VOLUME_CONTROL 0x08
+#define AK4671_LOUT1_SIGNAL_SELECT 0x09
+#define AK4671_ROUT1_SIGNAL_SELECT 0x0a
+#define AK4671_LOUT2_SIGNAL_SELECT 0x0b
+#define AK4671_ROUT2_SIGNAL_SELECT 0x0c
+#define AK4671_LOUT3_SIGNAL_SELECT 0x0d
+#define AK4671_ROUT3_SIGNAL_SELECT 0x0e
+#define AK4671_LOUT1_POWER_MANAGERMENT 0x0f
+#define AK4671_LOUT2_POWER_MANAGERMENT 0x10
+#define AK4671_LOUT3_POWER_MANAGERMENT 0x11
+#define AK4671_LCH_INPUT_VOLUME_CONTROL 0x12
+#define AK4671_RCH_INPUT_VOLUME_CONTROL 0x13
+#define AK4671_ALC_REFERENCE_SELECT 0x14
+#define AK4671_DIGITAL_MIXING_CONTROL 0x15
+#define AK4671_ALC_TIMER_SELECT 0x16
+#define AK4671_ALC_MODE_CONTROL 0x17
+#define AK4671_MODE_CONTROL1 0x18
+#define AK4671_MODE_CONTROL2 0x19
+#define AK4671_LCH_OUTPUT_VOLUME_CONTROL 0x1a
+#define AK4671_RCH_OUTPUT_VOLUME_CONTROL 0x1b
+#define AK4671_SIDETONE_A_CONTROL 0x1c
+#define AK4671_DIGITAL_FILTER_SELECT 0x1d
+#define AK4671_FIL3_COEFFICIENT0 0x1e
+#define AK4671_FIL3_COEFFICIENT1 0x1f
+#define AK4671_FIL3_COEFFICIENT2 0x20
+#define AK4671_FIL3_COEFFICIENT3 0x21
+#define AK4671_EQ_COEFFICIENT0 0x22
+#define AK4671_EQ_COEFFICIENT1 0x23
+#define AK4671_EQ_COEFFICIENT2 0x24
+#define AK4671_EQ_COEFFICIENT3 0x25
+#define AK4671_EQ_COEFFICIENT4 0x26
+#define AK4671_EQ_COEFFICIENT5 0x27
+#define AK4671_FIL1_COEFFICIENT0 0x28
+#define AK4671_FIL1_COEFFICIENT1 0x29
+#define AK4671_FIL1_COEFFICIENT2 0x2a
+#define AK4671_FIL1_COEFFICIENT3 0x2b
+#define AK4671_FIL2_COEFFICIENT0 0x2c
+#define AK4671_FIL2_COEFFICIENT1 0x2d
+#define AK4671_FIL2_COEFFICIENT2 0x2e
+#define AK4671_FIL2_COEFFICIENT3 0x2f
+#define AK4671_DIGITAL_FILTER_SELECT2 0x30
+#define AK4671_E1_COEFFICIENT0 0x32
+#define AK4671_E1_COEFFICIENT1 0x33
+#define AK4671_E1_COEFFICIENT2 0x34
+#define AK4671_E1_COEFFICIENT3 0x35
+#define AK4671_E1_COEFFICIENT4 0x36
+#define AK4671_E1_COEFFICIENT5 0x37
+#define AK4671_E2_COEFFICIENT0 0x38
+#define AK4671_E2_COEFFICIENT1 0x39
+#define AK4671_E2_COEFFICIENT2 0x3a
+#define AK4671_E2_COEFFICIENT3 0x3b
+#define AK4671_E2_COEFFICIENT4 0x3c
+#define AK4671_E2_COEFFICIENT5 0x3d
+#define AK4671_E3_COEFFICIENT0 0x3e
+#define AK4671_E3_COEFFICIENT1 0x3f
+#define AK4671_E3_COEFFICIENT2 0x40
+#define AK4671_E3_COEFFICIENT3 0x41
+#define AK4671_E3_COEFFICIENT4 0x42
+#define AK4671_E3_COEFFICIENT5 0x43
+#define AK4671_E4_COEFFICIENT0 0x44
+#define AK4671_E4_COEFFICIENT1 0x45
+#define AK4671_E4_COEFFICIENT2 0x46
+#define AK4671_E4_COEFFICIENT3 0x47
+#define AK4671_E4_COEFFICIENT4 0x48
+#define AK4671_E4_COEFFICIENT5 0x49
+#define AK4671_E5_COEFFICIENT0 0x4a
+#define AK4671_E5_COEFFICIENT1 0x4b
+#define AK4671_E5_COEFFICIENT2 0x4c
+#define AK4671_E5_COEFFICIENT3 0x4d
+#define AK4671_E5_COEFFICIENT4 0x4e
+#define AK4671_E5_COEFFICIENT5 0x4f
+#define AK4671_EQ_CONTROL_250HZ_100HZ 0x50
+#define AK4671_EQ_CONTROL_3500HZ_1KHZ 0x51
+#define AK4671_EQ_CONTRO_10KHZ 0x52
+#define AK4671_PCM_IF_CONTROL0 0x53
+#define AK4671_PCM_IF_CONTROL1 0x54
+#define AK4671_PCM_IF_CONTROL2 0x55
+#define AK4671_DIGITAL_VOLUME_B_CONTROL 0x56
+#define AK4671_DIGITAL_VOLUME_C_CONTROL 0x57
+#define AK4671_SIDETONE_VOLUME_CONTROL 0x58
+#define AK4671_DIGITAL_MIXING_CONTROL2 0x59
+#define AK4671_SAR_ADC_CONTROL 0x5a
+
+#define AK4671_CACHEREGNUM (AK4671_SAR_ADC_CONTROL + 1)
+
+/* Bitfield Definitions */
+
+/* AK4671_AD_DA_POWER_MANAGEMENT (0x00) Fields */
+#define AK4671_PMVCM 0x01
+
+/* AK4671_PLL_MODE_SELECT0 (0x01) Fields */
+#define AK4671_PLL 0x0f
+#define AK4671_PLL_11_2896MHZ (4 << 0)
+#define AK4671_PLL_12_288MHZ (5 << 0)
+#define AK4671_PLL_12MHZ (6 << 0)
+#define AK4671_PLL_24MHZ (7 << 0)
+#define AK4671_PLL_19_2MHZ (8 << 0)
+#define AK4671_PLL_13_5MHZ (12 << 0)
+#define AK4671_PLL_27MHZ (13 << 0)
+#define AK4671_PLL_13MHZ (14 << 0)
+#define AK4671_PLL_26MHZ (15 << 0)
+#define AK4671_FS 0xf0
+#define AK4671_FS_8KHZ (0 << 4)
+#define AK4671_FS_12KHZ (1 << 4)
+#define AK4671_FS_16KHZ (2 << 4)
+#define AK4671_FS_24KHZ (3 << 4)
+#define AK4671_FS_11_025KHZ (5 << 4)
+#define AK4671_FS_22_05KHZ (7 << 4)
+#define AK4671_FS_32KHZ (10 << 4)
+#define AK4671_FS_48KHZ (11 << 4)
+#define AK4671_FS_44_1KHZ (15 << 4)
+
+/* AK4671_PLL_MODE_SELECT1 (0x02) Fields */
+#define AK4671_PMPLL 0x01
+#define AK4671_M_S 0x02
+
+/* AK4671_FORMAT_SELECT (0x03) Fields */
+#define AK4671_DIF 0x03
+#define AK4671_DIF_DSP_MODE (0 << 0)
+#define AK4671_DIF_MSB_MODE (2 << 0)
+#define AK4671_DIF_I2S_MODE (3 << 0)
+#define AK4671_BCKP 0x04
+#define AK4671_MSBS 0x08
+#define AK4671_SDOD 0x10
+
+/* 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/cs4270.c b/sound/soc/codecs/cs4270.c
index ca1e24a8f12a..59bb16d033d6 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -802,22 +802,6 @@ MODULE_DEVICE_TABLE(i2c, cs4270_id);
* and all registers are written back to the hardware when resuming.
*/
-static int cs4270_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
-{
- struct cs4270_private *cs4270 = i2c_get_clientdata(client);
- struct snd_soc_codec *codec = &cs4270->codec;
-
- return snd_soc_suspend_device(codec->dev);
-}
-
-static int cs4270_i2c_resume(struct i2c_client *client)
-{
- struct cs4270_private *cs4270 = i2c_get_clientdata(client);
- struct snd_soc_codec *codec = &cs4270->codec;
-
- return snd_soc_resume_device(codec->dev);
-}
-
static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg)
{
struct snd_soc_codec *codec = cs4270_codec;
@@ -853,8 +837,6 @@ static int cs4270_soc_resume(struct platform_device *pdev)
return snd_soc_write(codec, CS4270_PWRCTL, reg);
}
#else
-#define cs4270_i2c_suspend NULL
-#define cs4270_i2c_resume NULL
#define cs4270_soc_suspend NULL
#define cs4270_soc_resume NULL
#endif /* CONFIG_PM */
@@ -873,8 +855,6 @@ static struct i2c_driver cs4270_i2c_driver = {
.id_table = cs4270_id,
.probe = cs4270_i2c_probe,
.remove = cs4270_i2c_remove,
- .suspend = cs4270_i2c_suspend,
- .resume = cs4270_i2c_resume,
};
/*
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
new file mode 100644
index 000000000000..3ca8934fc26c
--- /dev/null
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -0,0 +1,1237 @@
+/*
+ * ALSA SoC Texas Instruments TLV320DAC33 codec driver
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *
+ * Copyright: (C) 2009 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.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 <sound/tlv320dac33-plat.h>
+#include "tlv320dac33.h"
+
+#define DAC33_BUFFER_SIZE_BYTES 24576 /* bytes, 12288 16 bit words,
+ * 6144 stereo */
+#define DAC33_BUFFER_SIZE_SAMPLES 6144
+
+#define NSAMPLE_MAX 5700
+
+#define LATENCY_TIME_MS 20
+
+static struct snd_soc_codec *tlv320dac33_codec;
+
+enum dac33_state {
+ DAC33_IDLE = 0,
+ DAC33_PREFILL,
+ DAC33_PLAYBACK,
+ DAC33_FLUSH,
+};
+
+struct tlv320dac33_priv {
+ struct mutex mutex;
+ struct workqueue_struct *dac33_wq;
+ struct work_struct work;
+ struct snd_soc_codec codec;
+ int power_gpio;
+ int chip_power;
+ int irq;
+ unsigned int refclk;
+
+ unsigned int alarm_threshold; /* set to be half of LATENCY_TIME_MS */
+ unsigned int nsample_min; /* nsample should not be lower than
+ * this */
+ unsigned int nsample_max; /* nsample should not be higher than
+ * this */
+ unsigned int nsample_switch; /* Use FIFO or bypass FIFO switch */
+ unsigned int nsample; /* burst read amount from host */
+
+ enum dac33_state state;
+};
+
+static const u8 dac33_reg[DAC33_CACHEREGNUM] = {
+0x00, 0x00, 0x00, 0x00, /* 0x00 - 0x03 */
+0x00, 0x00, 0x00, 0x00, /* 0x04 - 0x07 */
+0x00, 0x00, 0x00, 0x00, /* 0x08 - 0x0b */
+0x00, 0x00, 0x00, 0x00, /* 0x0c - 0x0f */
+0x00, 0x00, 0x00, 0x00, /* 0x10 - 0x13 */
+0x00, 0x00, 0x00, 0x00, /* 0x14 - 0x17 */
+0x00, 0x00, 0x00, 0x00, /* 0x18 - 0x1b */
+0x00, 0x00, 0x00, 0x00, /* 0x1c - 0x1f */
+0x00, 0x00, 0x00, 0x00, /* 0x20 - 0x23 */
+0x00, 0x00, 0x00, 0x00, /* 0x24 - 0x27 */
+0x00, 0x00, 0x00, 0x00, /* 0x28 - 0x2b */
+0x00, 0x00, 0x00, 0x80, /* 0x2c - 0x2f */
+0x80, 0x00, 0x00, 0x00, /* 0x30 - 0x33 */
+0x00, 0x00, 0x00, 0x00, /* 0x34 - 0x37 */
+0x00, 0x00, /* 0x38 - 0x39 */
+/* Registers 0x3a - 0x3f are reserved */
+ 0x00, 0x00, /* 0x3a - 0x3b */
+0x00, 0x00, 0x00, 0x00, /* 0x3c - 0x3f */
+
+0x00, 0x00, 0x00, 0x00, /* 0x40 - 0x43 */
+0x00, 0x80, /* 0x44 - 0x45 */
+/* Registers 0x46 - 0x47 are reserved */
+ 0x80, 0x80, /* 0x46 - 0x47 */
+
+0x80, 0x00, 0x00, /* 0x48 - 0x4a */
+/* Registers 0x4b - 0x7c are reserved */
+ 0x00, /* 0x4b */
+0x00, 0x00, 0x00, 0x00, /* 0x4c - 0x4f */
+0x00, 0x00, 0x00, 0x00, /* 0x50 - 0x53 */
+0x00, 0x00, 0x00, 0x00, /* 0x54 - 0x57 */
+0x00, 0x00, 0x00, 0x00, /* 0x58 - 0x5b */
+0x00, 0x00, 0x00, 0x00, /* 0x5c - 0x5f */
+0x00, 0x00, 0x00, 0x00, /* 0x60 - 0x63 */
+0x00, 0x00, 0x00, 0x00, /* 0x64 - 0x67 */
+0x00, 0x00, 0x00, 0x00, /* 0x68 - 0x6b */
+0x00, 0x00, 0x00, 0x00, /* 0x6c - 0x6f */
+0x00, 0x00, 0x00, 0x00, /* 0x70 - 0x73 */
+0x00, 0x00, 0x00, 0x00, /* 0x74 - 0x77 */
+0x00, 0x00, 0x00, 0x00, /* 0x78 - 0x7b */
+0x00, /* 0x7c */
+
+ 0xda, 0x33, 0x03, /* 0x7d - 0x7f */
+};
+
+/* Register read and write */
+static inline unsigned int dac33_read_reg_cache(struct snd_soc_codec *codec,
+ unsigned reg)
+{
+ u8 *cache = codec->reg_cache;
+ if (reg >= DAC33_CACHEREGNUM)
+ return 0;
+
+ return cache[reg];
+}
+
+static inline void dac33_write_reg_cache(struct snd_soc_codec *codec,
+ u8 reg, u8 value)
+{
+ u8 *cache = codec->reg_cache;
+ if (reg >= DAC33_CACHEREGNUM)
+ return;
+
+ cache[reg] = value;
+}
+
+static int dac33_read(struct snd_soc_codec *codec, unsigned int reg,
+ u8 *value)
+{
+ struct tlv320dac33_priv *dac33 = codec->private_data;
+ int val;
+
+ *value = reg & 0xff;
+
+ /* If powered off, return the cached value */
+ if (dac33->chip_power) {
+ val = i2c_smbus_read_byte_data(codec->control_data, value[0]);
+ if (val < 0) {
+ dev_err(codec->dev, "Read failed (%d)\n", val);
+ value[0] = dac33_read_reg_cache(codec, reg);
+ } else {
+ value[0] = val;
+ dac33_write_reg_cache(codec, reg, val);
+ }
+ } else {
+ value[0] = dac33_read_reg_cache(codec, reg);
+ }
+
+ return 0;
+}
+
+static int dac33_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ struct tlv320dac33_priv *dac33 = codec->private_data;
+ u8 data[2];
+ int ret = 0;
+
+ /*
+ * data is
+ * D15..D8 dac33 register offset
+ * D7...D0 register data
+ */
+ data[0] = reg & 0xff;
+ data[1] = value & 0xff;
+
+ dac33_write_reg_cache(codec, data[0], data[1]);
+ if (dac33->chip_power) {
+ ret = codec->hw_write(codec->control_data, data, 2);
+ if (ret != 2)
+ dev_err(codec->dev, "Write failed (%d)\n", ret);
+ else
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int dac33_write_locked(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ struct tlv320dac33_priv *dac33 = codec->private_data;
+ int ret;
+
+ mutex_lock(&dac33->mutex);
+ ret = dac33_write(codec, reg, value);
+ mutex_unlock(&dac33->mutex);
+
+ return ret;
+}
+
+#define DAC33_I2C_ADDR_AUTOINC 0x80
+static int dac33_write16(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ struct tlv320dac33_priv *dac33 = codec->private_data;
+ u8 data[3];
+ int ret = 0;
+
+ /*
+ * data is
+ * D23..D16 dac33 register offset
+ * D15..D8 register data MSB
+ * D7...D0 register data LSB
+ */
+ data[0] = reg & 0xff;
+ data[1] = (value >> 8) & 0xff;
+ data[2] = value & 0xff;
+
+ dac33_write_reg_cache(codec, data[0], data[1]);
+ dac33_write_reg_cache(codec, data[0] + 1, data[2]);
+
+ if (dac33->chip_power) {
+ /* We need to set autoincrement mode for 16 bit writes */
+ data[0] |= DAC33_I2C_ADDR_AUTOINC;
+ ret = codec->hw_write(codec->control_data, data, 3);
+ if (ret != 3)
+ dev_err(codec->dev, "Write failed (%d)\n", ret);
+ else
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static void dac33_restore_regs(struct snd_soc_codec *codec)
+{
+ struct tlv320dac33_priv *dac33 = codec->private_data;
+ u8 *cache = codec->reg_cache;
+ u8 data[2];
+ int i, ret;
+
+ if (!dac33->chip_power)
+ return;
+
+ for (i = DAC33_PWR_CTRL; i <= DAC33_INTP_CTRL_B; i++) {
+ data[0] = i;
+ data[1] = cache[i];
+ /* Skip the read only registers */
+ if ((i >= DAC33_INT_OSC_STATUS &&
+ i <= DAC33_INT_OSC_FREQ_RAT_READ_B) ||
+ (i >= DAC33_FIFO_WPTR_MSB && i <= DAC33_FIFO_IRQ_FLAG) ||
+ i == DAC33_DAC_STATUS_FLAGS ||
+ i == DAC33_SRC_EST_REF_CLK_RATIO_A ||
+ i == DAC33_SRC_EST_REF_CLK_RATIO_B)
+ continue;
+ ret = codec->hw_write(codec->control_data, data, 2);
+ if (ret != 2)
+ dev_err(codec->dev, "Write failed (%d)\n", ret);
+ }
+ for (i = DAC33_LDAC_PWR_CTRL; i <= DAC33_LINEL_TO_LLO_VOL; i++) {
+ data[0] = i;
+ data[1] = cache[i];
+ ret = codec->hw_write(codec->control_data, data, 2);
+ if (ret != 2)
+ dev_err(codec->dev, "Write failed (%d)\n", ret);
+ }
+ for (i = DAC33_LINER_TO_RLO_VOL; i <= DAC33_OSC_TRIM; i++) {
+ data[0] = i;
+ data[1] = cache[i];
+ ret = codec->hw_write(codec->control_data, data, 2);
+ if (ret != 2)
+ dev_err(codec->dev, "Write failed (%d)\n", ret);
+ }
+}
+
+static inline void dac33_soft_power(struct snd_soc_codec *codec, int power)
+{
+ u8 reg;
+
+ reg = dac33_read_reg_cache(codec, DAC33_PWR_CTRL);
+ if (power)
+ reg |= DAC33_PDNALLB;
+ else
+ reg &= ~DAC33_PDNALLB;
+ dac33_write(codec, DAC33_PWR_CTRL, reg);
+}
+
+static void dac33_hard_power(struct snd_soc_codec *codec, int power)
+{
+ struct tlv320dac33_priv *dac33 = codec->private_data;
+
+ mutex_lock(&dac33->mutex);
+ if (power) {
+ if (dac33->power_gpio >= 0) {
+ gpio_set_value(dac33->power_gpio, 1);
+ dac33->chip_power = 1;
+ /* Restore registers */
+ dac33_restore_regs(codec);
+ }
+ dac33_soft_power(codec, 1);
+ } else {
+ dac33_soft_power(codec, 0);
+ if (dac33->power_gpio >= 0) {
+ gpio_set_value(dac33->power_gpio, 0);
+ dac33->chip_power = 0;
+ }
+ }
+ mutex_unlock(&dac33->mutex);
+
+}
+
+static int dac33_get_nsample(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct tlv320dac33_priv *dac33 = codec->private_data;
+
+ ucontrol->value.integer.value[0] = dac33->nsample;
+
+ return 0;
+}
+
+static int dac33_set_nsample(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct tlv320dac33_priv *dac33 = codec->private_data;
+ int ret = 0;
+
+ if (dac33->nsample == ucontrol->value.integer.value[0])
+ return 0;
+
+ if (ucontrol->value.integer.value[0] < dac33->nsample_min ||
+ ucontrol->value.integer.value[0] > dac33->nsample_max)
+ ret = -EINVAL;
+ else
+ dac33->nsample = ucontrol->value.integer.value[0];
+
+ return ret;
+}
+
+static int dac33_get_nsample_switch(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct tlv320dac33_priv *dac33 = codec->private_data;
+
+ ucontrol->value.integer.value[0] = dac33->nsample_switch;
+
+ return 0;
+}
+
+static int dac33_set_nsample_switch(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct tlv320dac33_priv *dac33 = codec->private_data;
+ int ret = 0;
+
+ if (dac33->nsample_switch == 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] > 1)
+ ret = -EINVAL;
+ else
+ dac33->nsample_switch = ucontrol->value.integer.value[0];
+
+ return ret;
+}
+
+/*
+ * DACL/R digital volume control:
+ * from 0 dB to -63.5 in 0.5 dB steps
+ * Need to be inverted later on:
+ * 0x00 == 0 dB
+ * 0x7f == -63.5 dB
+ */
+static DECLARE_TLV_DB_SCALE(dac_digivol_tlv, -6350, 50, 0);
+
+static const struct snd_kcontrol_new dac33_snd_controls[] = {
+ SOC_DOUBLE_R_TLV("DAC Digital Playback Volume",
+ DAC33_LDAC_DIG_VOL_CTRL, DAC33_RDAC_DIG_VOL_CTRL,
+ 0, 0x7f, 1, dac_digivol_tlv),
+ SOC_DOUBLE_R("DAC Digital Playback Switch",
+ 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),
+};
+
+static const struct snd_kcontrol_new dac33_nsample_snd_controls[] = {
+ SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0,
+ dac33_get_nsample, dac33_set_nsample),
+ SOC_SINGLE_EXT("nSample Switch", 0, 0, 1, 0,
+ dac33_get_nsample_switch, dac33_set_nsample_switch),
+};
+
+/* Analog bypass */
+static const struct snd_kcontrol_new dac33_dapm_abypassl_control =
+ SOC_DAPM_SINGLE("Switch", DAC33_LINEL_TO_LLO_VOL, 7, 1, 1);
+
+static const struct snd_kcontrol_new dac33_dapm_abypassr_control =
+ SOC_DAPM_SINGLE("Switch", DAC33_LINER_TO_RLO_VOL, 7, 1, 1);
+
+static const struct snd_soc_dapm_widget dac33_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("LEFT_LO"),
+ SND_SOC_DAPM_OUTPUT("RIGHT_LO"),
+
+ SND_SOC_DAPM_INPUT("LINEL"),
+ SND_SOC_DAPM_INPUT("LINER"),
+
+ SND_SOC_DAPM_DAC("DACL", "Left Playback", DAC33_LDAC_PWR_CTRL, 2, 0),
+ SND_SOC_DAPM_DAC("DACR", "Right Playback", DAC33_RDAC_PWR_CTRL, 2, 0),
+
+ /* Analog bypass */
+ SND_SOC_DAPM_SWITCH("Analog Left Bypass", SND_SOC_NOPM, 0, 0,
+ &dac33_dapm_abypassl_control),
+ SND_SOC_DAPM_SWITCH("Analog Right Bypass", SND_SOC_NOPM, 0, 0,
+ &dac33_dapm_abypassr_control),
+
+ SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Left Amp Power",
+ DAC33_OUT_AMP_PWR_CTRL, 6, 3, 3, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Right Amp Power",
+ DAC33_OUT_AMP_PWR_CTRL, 4, 3, 3, 0),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* Analog bypass */
+ {"Analog Left Bypass", "Switch", "LINEL"},
+ {"Analog Right Bypass", "Switch", "LINER"},
+
+ {"Output Left Amp Power", NULL, "DACL"},
+ {"Output Right Amp Power", NULL, "DACR"},
+
+ {"Output Left Amp Power", NULL, "Analog Left Bypass"},
+ {"Output Right Amp Power", NULL, "Analog Right Bypass"},
+
+ /* output */
+ {"LEFT_LO", NULL, "Output Left Amp Power"},
+ {"RIGHT_LO", NULL, "Output Right Amp Power"},
+};
+
+static int dac33_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, dac33_dapm_widgets,
+ ARRAY_SIZE(dac33_dapm_widgets));
+
+ /* set up audio path interconnects */
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+ snd_soc_dapm_new_widgets(codec);
+
+ return 0;
+}
+
+static int dac33_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ dac33_soft_power(codec, 1);
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->bias_level == SND_SOC_BIAS_OFF)
+ dac33_hard_power(codec, 1);
+ dac33_soft_power(codec, 0);
+ break;
+ case SND_SOC_BIAS_OFF:
+ dac33_hard_power(codec, 0);
+ break;
+ }
+ codec->bias_level = level;
+
+ return 0;
+}
+
+static void dac33_work(struct work_struct *work)
+{
+ struct snd_soc_codec *codec;
+ struct tlv320dac33_priv *dac33;
+ u8 reg;
+
+ dac33 = container_of(work, struct tlv320dac33_priv, work);
+ codec = &dac33->codec;
+
+ mutex_lock(&dac33->mutex);
+ switch (dac33->state) {
+ case DAC33_PREFILL:
+ dac33->state = DAC33_PLAYBACK;
+ dac33_write16(codec, DAC33_NSAMPLE_MSB,
+ DAC33_THRREG(dac33->nsample));
+ dac33_write16(codec, DAC33_PREFILL_MSB,
+ DAC33_THRREG(dac33->alarm_threshold));
+ break;
+ case DAC33_PLAYBACK:
+ dac33_write16(codec, DAC33_NSAMPLE_MSB,
+ DAC33_THRREG(dac33->nsample));
+ break;
+ case DAC33_IDLE:
+ break;
+ case DAC33_FLUSH:
+ dac33->state = DAC33_IDLE;
+ /* Mask all interrupts from dac33 */
+ dac33_write(codec, DAC33_FIFO_IRQ_MASK, 0);
+
+ /* flush fifo */
+ reg = dac33_read_reg_cache(codec, DAC33_FIFO_CTRL_A);
+ reg |= DAC33_FIFOFLUSH;
+ dac33_write(codec, DAC33_FIFO_CTRL_A, reg);
+ break;
+ }
+ mutex_unlock(&dac33->mutex);
+}
+
+static irqreturn_t dac33_interrupt_handler(int irq, void *dev)
+{
+ struct snd_soc_codec *codec = dev;
+ struct tlv320dac33_priv *dac33 = codec->private_data;
+
+ queue_work(dac33->dac33_wq, &dac33->work);
+
+ return IRQ_HANDLED;
+}
+
+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 tlv320dac33_priv *dac33 = codec->private_data;
+ unsigned int pwr_ctrl;
+
+ /* Stop pending workqueue */
+ if (dac33->nsample_switch)
+ cancel_work_sync(&dac33->work);
+
+ mutex_lock(&dac33->mutex);
+ pwr_ctrl = dac33_read_reg_cache(codec, DAC33_PWR_CTRL);
+ pwr_ctrl &= ~(DAC33_OSCPDNB | DAC33_DACRPDNB | DAC33_DACLPDNB);
+ dac33_write(codec, DAC33_PWR_CTRL, pwr_ctrl);
+ mutex_unlock(&dac33->mutex);
+}
+
+static void dac33_oscwait(struct snd_soc_codec *codec)
+{
+ int timeout = 20;
+ u8 reg;
+
+ do {
+ msleep(1);
+ dac33_read(codec, DAC33_INT_OSC_STATUS, &reg);
+ } while (((reg & 0x03) != DAC33_OSCSTATUS_NORMAL) && timeout--);
+ if ((reg & 0x03) != DAC33_OSCSTATUS_NORMAL)
+ dev_err(codec->dev,
+ "internal oscillator calibration failed\n");
+}
+
+static int dac33_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;
+
+ /* Check parameters for validity */
+ switch (params_rate(params)) {
+ case 44100:
+ case 48000:
+ break;
+ default:
+ dev_err(codec->dev, "unsupported rate %d\n",
+ params_rate(params));
+ return -EINVAL;
+ }
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ default:
+ dev_err(codec->dev, "unsupported format %d\n",
+ params_format(params));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#define CALC_OSCSET(rate, refclk) ( \
+ ((((rate * 10000) / refclk) * 4096) + 5000) / 10000)
+#define CALC_RATIOSET(rate, refclk) ( \
+ ((((refclk * 100000) / rate) * 16384) + 50000) / 100000)
+
+/*
+ * tlv320dac33 is strict on the sequence of the register writes, if the register
+ * writes happens in different order, than dac33 might end up in unknown state.
+ * Use the known, working sequence of register writes to initialize the dac33.
+ */
+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 tlv320dac33_priv *dac33 = codec->private_data;
+ unsigned int oscset, ratioset, pwr_ctrl, reg_tmp;
+ u8 aictrl_a, fifoctrl_a;
+
+ switch (substream->runtime->rate) {
+ case 44100:
+ case 48000:
+ oscset = CALC_OSCSET(substream->runtime->rate, dac33->refclk);
+ ratioset = CALC_RATIOSET(substream->runtime->rate,
+ dac33->refclk);
+ break;
+ default:
+ dev_err(codec->dev, "unsupported rate %d\n",
+ substream->runtime->rate);
+ return -EINVAL;
+ }
+
+
+ aictrl_a = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A);
+ aictrl_a &= ~(DAC33_NCYCL_MASK | DAC33_WLEN_MASK);
+ fifoctrl_a = dac33_read_reg_cache(codec, DAC33_FIFO_CTRL_A);
+ fifoctrl_a &= ~DAC33_WIDTH;
+ switch (substream->runtime->format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ aictrl_a |= (DAC33_NCYCL_16 | DAC33_WLEN_16);
+ fifoctrl_a |= DAC33_WIDTH;
+ break;
+ default:
+ dev_err(codec->dev, "unsupported format %d\n",
+ substream->runtime->format);
+ return -EINVAL;
+ }
+
+ mutex_lock(&dac33->mutex);
+ dac33_soft_power(codec, 1);
+
+ reg_tmp = dac33_read_reg_cache(codec, DAC33_INT_OSC_CTRL);
+ dac33_write(codec, DAC33_INT_OSC_CTRL, reg_tmp);
+
+ /* Write registers 0x08 and 0x09 (MSB, LSB) */
+ dac33_write16(codec, DAC33_INT_OSC_FREQ_RAT_A, oscset);
+
+ /* calib time: 128 is a nice number ;) */
+ dac33_write(codec, DAC33_CALIB_TIME, 128);
+
+ /* adjustment treshold & step */
+ dac33_write(codec, DAC33_INT_OSC_CTRL_B, DAC33_ADJTHRSHLD(2) |
+ DAC33_ADJSTEP(1));
+
+ /* div=4 / gain=1 / div */
+ dac33_write(codec, DAC33_INT_OSC_CTRL_C, DAC33_REFDIV(4));
+
+ pwr_ctrl = dac33_read_reg_cache(codec, DAC33_PWR_CTRL);
+ pwr_ctrl |= DAC33_OSCPDNB | DAC33_DACRPDNB | DAC33_DACLPDNB;
+ dac33_write(codec, DAC33_PWR_CTRL, pwr_ctrl);
+
+ dac33_oscwait(codec);
+
+ if (dac33->nsample_switch) {
+ /* 50-51 : ASRC Control registers */
+ dac33_write(codec, DAC33_ASRC_CTRL_A, (1 << 4)); /* div=2 */
+ dac33_write(codec, DAC33_ASRC_CTRL_B, 1); /* ??? */
+
+ /* Write registers 0x34 and 0x35 (MSB, LSB) */
+ dac33_write16(codec, DAC33_SRC_REF_CLK_RATIO_A, ratioset);
+
+ /* Set interrupts to high active */
+ dac33_write(codec, DAC33_INTP_CTRL_A, DAC33_INTPM_AHIGH);
+
+ dac33_write(codec, DAC33_FIFO_IRQ_MODE_B,
+ DAC33_ATM(DAC33_FIFO_IRQ_MODE_LEVEL));
+ dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
+ } else {
+ /* 50-51 : ASRC Control registers */
+ dac33_write(codec, DAC33_ASRC_CTRL_A, DAC33_SRCBYP);
+ dac33_write(codec, DAC33_ASRC_CTRL_B, 0); /* ??? */
+ }
+
+ if (dac33->nsample_switch)
+ fifoctrl_a &= ~DAC33_FBYPAS;
+ else
+ fifoctrl_a |= DAC33_FBYPAS;
+ dac33_write(codec, DAC33_FIFO_CTRL_A, fifoctrl_a);
+
+ dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a);
+ reg_tmp = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B);
+ if (dac33->nsample_switch)
+ reg_tmp &= ~DAC33_BCLKON;
+ else
+ reg_tmp |= DAC33_BCLKON;
+ dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_B, reg_tmp);
+
+ if (dac33->nsample_switch) {
+ /* 20: BCLK divide ratio */
+ dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 3);
+
+ dac33_write16(codec, DAC33_ATHR_MSB,
+ DAC33_THRREG(dac33->alarm_threshold));
+ } else {
+ dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 32);
+ }
+
+ mutex_unlock(&dac33->mutex);
+
+ return 0;
+}
+
+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 tlv320dac33_priv *dac33 = codec->private_data;
+ unsigned int nsample_limit;
+
+ /* Number of samples (16bit, stereo) in one period */
+ dac33->nsample_min = snd_pcm_lib_period_bytes(substream) / 4;
+
+ /* Number of samples (16bit, stereo) in ALSA buffer */
+ dac33->nsample_max = snd_pcm_lib_buffer_bytes(substream) / 4;
+ /* Subtract one period from the total */
+ dac33->nsample_max -= dac33->nsample_min;
+
+ /* Number of samples for LATENCY_TIME_MS / 2 */
+ dac33->alarm_threshold = substream->runtime->rate /
+ (1000 / (LATENCY_TIME_MS / 2));
+
+ /* Find and fix up the lowest nsmaple limit */
+ nsample_limit = substream->runtime->rate / (1000 / LATENCY_TIME_MS);
+
+ if (dac33->nsample_min < nsample_limit)
+ dac33->nsample_min = nsample_limit;
+
+ if (dac33->nsample < dac33->nsample_min)
+ dac33->nsample = dac33->nsample_min;
+
+ /*
+ * Find and fix up the highest nsmaple limit
+ * In order to not overflow the DAC33 buffer substract the
+ * alarm_threshold value from the size of the DAC33 buffer
+ */
+ nsample_limit = DAC33_BUFFER_SIZE_SAMPLES - dac33->alarm_threshold;
+
+ if (dac33->nsample_max > nsample_limit)
+ dac33->nsample_max = nsample_limit;
+
+ if (dac33->nsample > dac33->nsample_max)
+ dac33->nsample = dac33->nsample_max;
+}
+
+static int dac33_pcm_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ dac33_calculate_times(substream);
+ dac33_prepare_chip(substream);
+
+ return 0;
+}
+
+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 tlv320dac33_priv *dac33 = codec->private_data;
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (dac33->nsample_switch) {
+ dac33->state = DAC33_PREFILL;
+ queue_work(dac33->dac33_wq, &dac33->work);
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (dac33->nsample_switch) {
+ dac33->state = DAC33_FLUSH;
+ queue_work(dac33->dac33_wq, &dac33->work);
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int dac33_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 tlv320dac33_priv *dac33 = codec->private_data;
+ u8 ioc_reg, asrcb_reg;
+
+ ioc_reg = dac33_read_reg_cache(codec, DAC33_INT_OSC_CTRL);
+ asrcb_reg = dac33_read_reg_cache(codec, DAC33_ASRC_CTRL_B);
+ switch (clk_id) {
+ case TLV320DAC33_MCLK:
+ ioc_reg |= DAC33_REFSEL;
+ asrcb_reg |= DAC33_SRCREFSEL;
+ break;
+ case TLV320DAC33_SLEEPCLK:
+ ioc_reg &= ~DAC33_REFSEL;
+ asrcb_reg &= ~DAC33_SRCREFSEL;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid clock ID (%d)\n", clk_id);
+ break;
+ }
+ dac33->refclk = freq;
+
+ dac33_write_reg_cache(codec, DAC33_INT_OSC_CTRL, ioc_reg);
+ dac33_write_reg_cache(codec, DAC33_ASRC_CTRL_B, asrcb_reg);
+
+ return 0;
+}
+
+static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u8 aictrl_a, aictrl_b;
+
+ aictrl_a = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A);
+ aictrl_b = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B);
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* Codec Master */
+ aictrl_a |= (DAC33_MSBCLK | DAC33_MSWCLK);
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* Codec Slave */
+ aictrl_a &= ~(DAC33_MSBCLK | DAC33_MSWCLK);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ aictrl_a &= ~DAC33_AFMT_MASK;
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ aictrl_a |= DAC33_AFMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ aictrl_a |= DAC33_AFMT_DSP;
+ aictrl_b &= ~DAC33_DATA_DELAY_MASK;
+ aictrl_b |= DAC33_DATA_DELAY(1); /* 1 bit delay */
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ aictrl_a |= DAC33_AFMT_DSP;
+ aictrl_b &= ~DAC33_DATA_DELAY_MASK; /* No delay */
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ aictrl_a |= DAC33_AFMT_RIGHT_J;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ aictrl_a |= DAC33_AFMT_LEFT_J;
+ break;
+ default:
+ dev_err(codec->dev, "Unsupported format (%u)\n",
+ fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+ return -EINVAL;
+ }
+
+ dac33_write_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a);
+ dac33_write_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B, aictrl_b);
+
+ return 0;
+}
+
+static void dac33_init_chip(struct snd_soc_codec *codec)
+{
+ /* 44-46: DAC Control Registers */
+ /* A : DAC sample rate Fsref/1.5 */
+ dac33_write(codec, DAC33_DAC_CTRL_A, DAC33_DACRATE(1));
+ /* B : DAC src=normal, not muted */
+ dac33_write(codec, DAC33_DAC_CTRL_B, DAC33_DACSRCR_RIGHT |
+ DAC33_DACSRCL_LEFT);
+ /* C : (defaults) */
+ dac33_write(codec, DAC33_DAC_CTRL_C, 0x00);
+
+ /* 64-65 : L&R DAC power control
+ Line In -> OUT 1V/V Gain, DAC -> OUT 4V/V Gain*/
+ dac33_write(codec, DAC33_LDAC_PWR_CTRL, DAC33_LROUT_GAIN(2));
+ dac33_write(codec, DAC33_RDAC_PWR_CTRL, DAC33_LROUT_GAIN(2));
+
+ /* 73 : volume soft stepping control,
+ clock source = internal osc (?) */
+ dac33_write(codec, DAC33_ANA_VOL_SOFT_STEP_CTRL, DAC33_VOLCLKEN);
+
+ /* 66 : LOP/LOM Modes */
+ dac33_write(codec, DAC33_OUT_AMP_CM_CTRL, 0xff);
+
+ /* 68 : LOM inverted from LOP */
+ dac33_write(codec, DAC33_OUT_AMP_CTRL, (3<<2));
+
+ dac33_write(codec, DAC33_PWR_CTRL, DAC33_PDNALLB);
+}
+
+static int dac33_soc_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ struct tlv320dac33_priv *dac33;
+ int ret = 0;
+
+ BUG_ON(!tlv320dac33_codec);
+
+ codec = tlv320dac33_codec;
+ socdev->card->codec = codec;
+ dac33 = codec->private_data;
+
+ /* Power up the codec */
+ dac33_hard_power(codec, 1);
+ /* Set default configuration */
+ dac33_init_chip(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");
+ goto pcm_err;
+ }
+
+ snd_soc_add_controls(codec, dac33_snd_controls,
+ ARRAY_SIZE(dac33_snd_controls));
+ /* Only add the nSample controls, if we have valid IRQ number */
+ if (dac33->irq >= 0)
+ snd_soc_add_controls(codec, dac33_nsample_snd_controls,
+ ARRAY_SIZE(dac33_nsample_snd_controls));
+
+ dac33_add_widgets(codec);
+
+ /* power on device */
+ dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ ret = snd_soc_init_card(socdev);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to register card\n");
+ goto card_err;
+ }
+
+ return 0;
+card_err:
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+pcm_err:
+ dac33_hard_power(codec, 0);
+ return ret;
+}
+
+static int dac33_soc_remove(struct platform_device *pdev)
+{
+ 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);
+
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+
+ return 0;
+}
+
+static int dac33_soc_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;
+
+ dac33_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static int dac33_soc_resume(struct platform_device *pdev)
+{
+ 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);
+ dac33_set_bias_level(codec, codec->suspend_bias_level);
+
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_tlv320dac33 = {
+ .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)
+#define DAC33_FORMATS SNDRV_PCM_FMTBIT_S16_LE
+
+static struct snd_soc_dai_ops dac33_dai_ops = {
+ .shutdown = dac33_shutdown,
+ .hw_params = dac33_hw_params,
+ .prepare = dac33_pcm_prepare,
+ .trigger = dac33_pcm_trigger,
+ .set_sysclk = dac33_set_dai_sysclk,
+ .set_fmt = dac33_set_dai_fmt,
+};
+
+struct snd_soc_dai dac33_dai = {
+ .name = "tlv320dac33",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = DAC33_RATES,
+ .formats = DAC33_FORMATS,},
+ .ops = &dac33_dai_ops,
+};
+EXPORT_SYMBOL_GPL(dac33_dai);
+
+static int 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 = 0;
+
+ if (client->dev.platform_data == NULL) {
+ dev_err(&client->dev, "Platform data not set\n");
+ return -ENODEV;
+ }
+ pdata = client->dev.platform_data;
+
+ dac33 = kzalloc(sizeof(struct tlv320dac33_priv), GFP_KERNEL);
+ if (dac33 == NULL)
+ return -ENOMEM;
+
+ codec = &dac33->codec;
+ codec->private_data = dac33;
+ codec->control_data = client;
+
+ mutex_init(&codec->mutex);
+ mutex_init(&dac33->mutex);
+ 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->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);
+
+ dac33->power_gpio = pdata->power_gpio;
+ dac33->irq = client->irq;
+ dac33->nsample = NSAMPLE_MAX;
+ /* Disable FIFO use by default */
+ dac33->nsample_switch = 0;
+
+ 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,
+ "Failed to request reset GPIO (%d)\n",
+ dac33->power_gpio);
+ snd_soc_unregister_dai(&dac33_dai);
+ snd_soc_unregister_codec(codec);
+ goto error_gpio;
+ }
+ gpio_direction_output(dac33->power_gpio, 0);
+ } else {
+ dac33->chip_power = 1;
+ }
+
+ /* 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_rt_workqueue("tlv320dac33");
+ if (dac33->dac33_wq == NULL) {
+ free_irq(dac33->irq, &dac33->codec);
+ ret = -ENOMEM;
+ goto error_wq;
+ }
+
+ INIT_WORK(&dac33->work, dac33_work);
+ }
+ }
+
+ 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;
+ }
+
+ /* Shut down the codec for now */
+ dac33_hard_power(codec, 0);
+
+ return ret;
+
+error_codec:
+ 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;
+ kfree(dac33);
+
+ return ret;
+}
+
+static int dac33_i2c_remove(struct i2c_client *client)
+{
+ struct tlv320dac33_priv *dac33;
+
+ dac33 = i2c_get_clientdata(client);
+ 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);
+
+ destroy_workqueue(dac33->dac33_wq);
+ snd_soc_unregister_dai(&dac33_dai);
+ snd_soc_unregister_codec(&dac33->codec);
+ kfree(dac33->codec.reg_cache);
+ kfree(dac33);
+ tlv320dac33_codec = NULL;
+
+ return 0;
+}
+
+static const struct i2c_device_id tlv320dac33_i2c_id[] = {
+ {
+ .name = "tlv320dac33",
+ .driver_data = 0,
+ },
+ { },
+};
+
+static struct i2c_driver tlv320dac33_i2c_driver = {
+ .driver = {
+ .name = "tlv320dac33",
+ .owner = THIS_MODULE,
+ },
+ .probe = dac33_i2c_probe,
+ .remove = __devexit_p(dac33_i2c_remove),
+ .id_table = tlv320dac33_i2c_id,
+};
+
+static int __init dac33_module_init(void)
+{
+ int r;
+ r = i2c_add_driver(&tlv320dac33_i2c_driver);
+ if (r < 0) {
+ printk(KERN_ERR "DAC33: driver registration failed\n");
+ return r;
+ }
+ return 0;
+}
+module_init(dac33_module_init);
+
+static void __exit dac33_module_exit(void)
+{
+ i2c_del_driver(&tlv320dac33_i2c_driver);
+}
+module_exit(dac33_module_exit);
+
+
+MODULE_DESCRIPTION("ASoC TLV320DAC33 codec driver");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@nokia.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320dac33.h b/sound/soc/codecs/tlv320dac33.h
new file mode 100644
index 000000000000..0fedd709028e
--- /dev/null
+++ b/sound/soc/codecs/tlv320dac33.h
@@ -0,0 +1,267 @@
+/*
+ * ALSA SoC Texas Instruments TLV320DAC33 codec driver
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *
+ * Copyright: (C) 2009 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
+ *
+ */
+
+#ifndef __TLV320DAC33_H
+#define __TLV320DAC33_H
+
+#define DAC33_PAGE_SELECT 0x00
+#define DAC33_PWR_CTRL 0x01
+#define DAC33_PLL_CTRL_A 0x02
+#define DAC33_PLL_CTRL_B 0x03
+#define DAC33_PLL_CTRL_C 0x04
+#define DAC33_PLL_CTRL_D 0x05
+#define DAC33_PLL_CTRL_E 0x06
+#define DAC33_INT_OSC_CTRL 0x07
+#define DAC33_INT_OSC_FREQ_RAT_A 0x08
+#define DAC33_INT_OSC_FREQ_RAT_B 0x09
+#define DAC33_INT_OSC_DAC_RATIO_SET 0x0A
+#define DAC33_CALIB_TIME 0x0B
+#define DAC33_INT_OSC_CTRL_B 0x0C
+#define DAC33_INT_OSC_CTRL_C 0x0D
+#define DAC33_INT_OSC_STATUS 0x0E
+#define DAC33_INT_OSC_DAC_RATIO_READ 0x0F
+#define DAC33_INT_OSC_FREQ_RAT_READ_A 0x10
+#define DAC33_INT_OSC_FREQ_RAT_READ_B 0x11
+#define DAC33_SER_AUDIOIF_CTRL_A 0x12
+#define DAC33_SER_AUDIOIF_CTRL_B 0x13
+#define DAC33_SER_AUDIOIF_CTRL_C 0x14
+#define DAC33_FIFO_CTRL_A 0x15
+#define DAC33_UTHR_MSB 0x16
+#define DAC33_UTHR_LSB 0x17
+#define DAC33_ATHR_MSB 0x18
+#define DAC33_ATHR_LSB 0x19
+#define DAC33_LTHR_MSB 0x1A
+#define DAC33_LTHR_LSB 0x1B
+#define DAC33_PREFILL_MSB 0x1C
+#define DAC33_PREFILL_LSB 0x1D
+#define DAC33_NSAMPLE_MSB 0x1E
+#define DAC33_NSAMPLE_LSB 0x1F
+#define DAC33_FIFO_WPTR_MSB 0x20
+#define DAC33_FIFO_WPTR_LSB 0x21
+#define DAC33_FIFO_RPTR_MSB 0x22
+#define DAC33_FIFO_RPTR_LSB 0x23
+#define DAC33_FIFO_DEPTH_MSB 0x24
+#define DAC33_FIFO_DEPTH_LSB 0x25
+#define DAC33_SAMPLES_REMAINING_MSB 0x26
+#define DAC33_SAMPLES_REMAINING_LSB 0x27
+#define DAC33_FIFO_IRQ_FLAG 0x28
+#define DAC33_FIFO_IRQ_MASK 0x29
+#define DAC33_FIFO_IRQ_MODE_A 0x2A
+#define DAC33_FIFO_IRQ_MODE_B 0x2B
+#define DAC33_DAC_CTRL_A 0x2C
+#define DAC33_DAC_CTRL_B 0x2D
+#define DAC33_DAC_CTRL_C 0x2E
+#define DAC33_LDAC_DIG_VOL_CTRL 0x2F
+#define DAC33_RDAC_DIG_VOL_CTRL 0x30
+#define DAC33_DAC_STATUS_FLAGS 0x31
+#define DAC33_ASRC_CTRL_A 0x32
+#define DAC33_ASRC_CTRL_B 0x33
+#define DAC33_SRC_REF_CLK_RATIO_A 0x34
+#define DAC33_SRC_REF_CLK_RATIO_B 0x35
+#define DAC33_SRC_EST_REF_CLK_RATIO_A 0x36
+#define DAC33_SRC_EST_REF_CLK_RATIO_B 0x37
+#define DAC33_INTP_CTRL_A 0x38
+#define DAC33_INTP_CTRL_B 0x39
+/* Registers 0x3A - 0x3F Reserved */
+#define DAC33_LDAC_PWR_CTRL 0x40
+#define DAC33_RDAC_PWR_CTRL 0x41
+#define DAC33_OUT_AMP_CM_CTRL 0x42
+#define DAC33_OUT_AMP_PWR_CTRL 0x43
+#define DAC33_OUT_AMP_CTRL 0x44
+#define DAC33_LINEL_TO_LLO_VOL 0x45
+/* Registers 0x45 - 0x47 Reserved */
+#define DAC33_LINER_TO_RLO_VOL 0x48
+#define DAC33_ANA_VOL_SOFT_STEP_CTRL 0x49
+#define DAC33_OSC_TRIM 0x4A
+/* Registers 0x4B - 0x7C Reserved */
+#define DAC33_DEVICE_ID_MSB 0x7D
+#define DAC33_DEVICE_ID_LSB 0x7E
+#define DAC33_DEVICE_REV_ID 0x7F
+
+#define DAC33_CACHEREGNUM 128
+
+/* Bit definitions */
+
+/* DAC33_PWR_CTRL (0x01) */
+#define DAC33_DACRPDNB (0x01 << 0)
+#define DAC33_DACLPDNB (0x01 << 1)
+#define DAC33_OSCPDNB (0x01 << 2)
+#define DAC33_PLLPDNB (0x01 << 3)
+#define DAC33_PDNALLB (0x01 << 4)
+#define DAC33_SOFT_RESET (0x01 << 7)
+
+/* DAC33_INT_OSC_CTRL (0x07) */
+#define DAC33_REFSEL (0x01 << 1)
+
+/* DAC33_INT_OSC_CTRL_B (0x0C) */
+#define DAC33_ADJSTEP(x) (x << 0)
+#define DAC33_ADJTHRSHLD(x) (x << 4)
+
+/* DAC33_INT_OSC_CTRL_C (0x0D) */
+#define DAC33_REFDIV(x) (x << 4)
+
+/* DAC33_INT_OSC_STATUS (0x0E) */
+#define DAC33_OSCSTATUS_IDLE_CALIB (0x00)
+#define DAC33_OSCSTATUS_NORMAL (0x01)
+#define DAC33_OSCSTATUS_ADJUSTMENT (0x03)
+#define DAC33_OSCSTATUS_NOT_USED (0x02)
+
+/* DAC33_SER_AUDIOIF_CTRL_A (0x12) */
+#define DAC33_MSWCLK (0x01 << 0)
+#define DAC33_MSBCLK (0x01 << 1)
+#define DAC33_AFMT_MASK (0x03 << 2)
+#define DAC33_AFMT_I2S (0x00 << 2)
+#define DAC33_AFMT_DSP (0x01 << 2)
+#define DAC33_AFMT_RIGHT_J (0x02 << 2)
+#define DAC33_AFMT_LEFT_J (0x03 << 2)
+#define DAC33_WLEN_MASK (0x03 << 4)
+#define DAC33_WLEN_16 (0x00 << 4)
+#define DAC33_WLEN_20 (0x01 << 4)
+#define DAC33_WLEN_24 (0x02 << 4)
+#define DAC33_WLEN_32 (0x03 << 4)
+#define DAC33_NCYCL_MASK (0x03 << 6)
+#define DAC33_NCYCL_16 (0x00 << 6)
+#define DAC33_NCYCL_20 (0x01 << 6)
+#define DAC33_NCYCL_24 (0x02 << 6)
+#define DAC33_NCYCL_32 (0x03 << 6)
+
+/* DAC33_SER_AUDIOIF_CTRL_B (0x13) */
+#define DAC33_DATA_DELAY_MASK (0x03 << 2)
+#define DAC33_DATA_DELAY(x) (x << 2)
+#define DAC33_BCLKON (0x01 << 5)
+
+/* DAC33_FIFO_CTRL_A (0x15) */
+#define DAC33_WIDTH (0x01 << 0)
+#define DAC33_FBYPAS (0x01 << 1)
+#define DAC33_FAUTO (0x01 << 2)
+#define DAC33_FIFOFLUSH (0x01 << 3)
+
+/*
+ * UTHR, ATHR, LTHR, PREFILL, NSAMPLE (0x16 - 0x1F)
+ * 13-bit values
+*/
+#define DAC33_THRREG(x) (((x) & 0x1FFF) << 3)
+
+/* DAC33_FIFO_IRQ_MASK (0x29) */
+#define DAC33_MNS (0x01 << 0)
+#define DAC33_MPS (0x01 << 1)
+#define DAC33_MAT (0x01 << 2)
+#define DAC33_MLT (0x01 << 3)
+#define DAC33_MUT (0x01 << 4)
+#define DAC33_MUF (0x01 << 5)
+#define DAC33_MOF (0x01 << 6)
+
+#define DAC33_FIFO_IRQ_MODE_MASK (0x03)
+#define DAC33_FIFO_IRQ_MODE_RISING (0x00)
+#define DAC33_FIFO_IRQ_MODE_FALLING (0x01)
+#define DAC33_FIFO_IRQ_MODE_LEVEL (0x02)
+#define DAC33_FIFO_IRQ_MODE_EDGE (0x03)
+
+/* DAC33_FIFO_IRQ_MODE_A (0x2A) */
+#define DAC33_UTM(x) (x << 0)
+#define DAC33_UFM(x) (x << 2)
+#define DAC33_OFM(x) (x << 4)
+
+/* DAC33_FIFO_IRQ_MODE_B (0x2B) */
+#define DAC33_NSM(x) (x << 0)
+#define DAC33_PSM(x) (x << 2)
+#define DAC33_ATM(x) (x << 4)
+#define DAC33_LTM(x) (x << 4)
+
+/* DAC33_DAC_CTRL_A (0x2C) */
+#define DAC33_DACRATE(x) (x << 0)
+#define DAC33_DACDUAL (0x01 << 4)
+#define DAC33_DACLKSEL_MASK (0x03 << 5)
+#define DAC33_DACLKSEL_INTSOC (0x00 << 5)
+#define DAC33_DACLKSEL_PLL (0x01 << 5)
+#define DAC33_DACLKSEL_MCLK (0x02 << 5)
+#define DAC33_DACLKSEL_BCLK (0x03 << 5)
+
+/* DAC33_DAC_CTRL_B (0x2D) */
+#define DAC33_DACSRCR_MASK (0x03 << 0)
+#define DAC33_DACSRCR_MUTE (0x00 << 0)
+#define DAC33_DACSRCR_RIGHT (0x01 << 0)
+#define DAC33_DACSRCR_LEFT (0x02 << 0)
+#define DAC33_DACSRCR_MONOMIX (0x03 << 0)
+#define DAC33_DACSRCL_MASK (0x03 << 2)
+#define DAC33_DACSRCL_MUTE (0x00 << 2)
+#define DAC33_DACSRCL_LEFT (0x01 << 2)
+#define DAC33_DACSRCL_RIGHT (0x02 << 2)
+#define DAC33_DACSRCL_MONOMIX (0x03 << 2)
+#define DAC33_DVOLSTEP_MASK (0x03 << 4)
+#define DAC33_DVOLSTEP_SS_PERFS (0x00 << 4)
+#define DAC33_DVOLSTEP_SS_PER2FS (0x01 << 4)
+#define DAC33_DVOLSTEP_SS_DISABLED (0x02 << 4)
+#define DAC33_DVOLCTRL_MASK (0x03 << 6)
+#define DAC33_DVOLCTRL_LR_INDEPENDENT1 (0x00 << 6)
+#define DAC33_DVOLCTRL_LR_RIGHT_CONTROL (0x01 << 6)
+#define DAC33_DVOLCTRL_LR_LEFT_CONTROL (0x02 << 6)
+#define DAC33_DVOLCTRL_LR_INDEPENDENT2 (0x03 << 6)
+
+/* DAC33_DAC_CTRL_C (0x2E) */
+#define DAC33_DEEMENR (0x01 << 0)
+#define DAC33_EFFENR (0x01 << 1)
+#define DAC33_DEEMENL (0x01 << 2)
+#define DAC33_EFFENL (0x01 << 3)
+#define DAC33_EN3D (0x01 << 4)
+#define DAC33_RESYNMUTE (0x01 << 5)
+#define DAC33_RESYNEN (0x01 << 6)
+
+/* DAC33_ASRC_CTRL_A (0x32) */
+#define DAC33_SRCBYP (0x01 << 0)
+#define DAC33_SRCLKSEL_MASK (0x03 << 1)
+#define DAC33_SRCLKSEL_INTSOC (0x00 << 1)
+#define DAC33_SRCLKSEL_PLL (0x01 << 1)
+#define DAC33_SRCLKSEL_MCLK (0x02 << 1)
+#define DAC33_SRCLKSEL_BCLK (0x03 << 1)
+#define DAC33_SRCLKDIV(x) (x << 3)
+
+/* DAC33_ASRC_CTRL_B (0x33) */
+#define DAC33_SRCSETUP(x) (x << 0)
+#define DAC33_SRCREFSEL (0x01 << 4)
+#define DAC33_SRCREFDIV(x) (x << 5)
+
+/* DAC33_INTP_CTRL_A (0x38) */
+#define DAC33_INTPSEL (0x01 << 0)
+#define DAC33_INTPM_MASK (0x03 << 1)
+#define DAC33_INTPM_ALOW_OPENDRAIN (0x00 << 1)
+#define DAC33_INTPM_ALOW (0x01 << 1)
+#define DAC33_INTPM_AHIGH (0x02 << 1)
+
+/* DAC33_LDAC_PWR_CTRL (0x40) */
+/* DAC33_RDAC_PWR_CTRL (0x41) */
+#define DAC33_DACLRNUM (0x01 << 2)
+#define DAC33_LROUT_GAIN(x) (x << 0)
+
+/* DAC33_ANA_VOL_SOFT_STEP_CTRL (0x49) */
+#define DAC33_VOLCLKSEL (0x01 << 0)
+#define DAC33_VOLCLKEN (0x01 << 1)
+#define DAC33_VOLBYPASS (0x01 << 2)
+
+#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
new file mode 100644
index 000000000000..6b650c1aa3d1
--- /dev/null
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -0,0 +1,463 @@
+/*
+ * ALSA SoC Texas Instruments TPA6130A2 headset stereo amplifier driver
+ *
+ * Copyright (C) Nokia Corporation
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@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/module.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <sound/tpa6130a2-plat.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+#include "tpa6130a2.h"
+
+static struct i2c_client *tpa6130a2_client;
+
+/* This struct is used to save the context */
+struct tpa6130a2_data {
+ struct mutex mutex;
+ unsigned char regs[TPA6130A2_CACHEREGNUM];
+ int power_gpio;
+ unsigned char power_state;
+};
+
+static int tpa6130a2_i2c_read(int reg)
+{
+ struct tpa6130a2_data *data;
+ int val;
+
+ BUG_ON(tpa6130a2_client == NULL);
+ data = i2c_get_clientdata(tpa6130a2_client);
+
+ /* If powered off, return the cached value */
+ if (data->power_state) {
+ val = i2c_smbus_read_byte_data(tpa6130a2_client, reg);
+ if (val < 0)
+ dev_err(&tpa6130a2_client->dev, "Read failed\n");
+ else
+ data->regs[reg] = val;
+ } else {
+ val = data->regs[reg];
+ }
+
+ return val;
+}
+
+static int tpa6130a2_i2c_write(int reg, u8 value)
+{
+ struct tpa6130a2_data *data;
+ int val = 0;
+
+ BUG_ON(tpa6130a2_client == NULL);
+ data = i2c_get_clientdata(tpa6130a2_client);
+
+ if (data->power_state) {
+ val = i2c_smbus_write_byte_data(tpa6130a2_client, reg, value);
+ if (val < 0)
+ dev_err(&tpa6130a2_client->dev, "Write failed\n");
+ }
+
+ /* Either powered on or off, we save the context */
+ data->regs[reg] = value;
+
+ return val;
+}
+
+static u8 tpa6130a2_read(int reg)
+{
+ struct tpa6130a2_data *data;
+
+ BUG_ON(tpa6130a2_client == NULL);
+ data = i2c_get_clientdata(tpa6130a2_client);
+
+ return data->regs[reg];
+}
+
+static void tpa6130a2_initialize(void)
+{
+ struct tpa6130a2_data *data;
+ int i;
+
+ 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]);
+}
+
+static void tpa6130a2_power(int power)
+{
+ struct tpa6130a2_data *data;
+ u8 val;
+
+ BUG_ON(tpa6130a2_client == NULL);
+ data = i2c_get_clientdata(tpa6130a2_client);
+
+ mutex_lock(&data->mutex);
+ if (power) {
+ /* Power on */
+ if (data->power_gpio >= 0) {
+ gpio_set_value(data->power_gpio, 1);
+ data->power_state = 1;
+ tpa6130a2_initialize();
+ }
+ /* Clear SWS */
+ val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
+ val &= ~TPA6130A2_SWS;
+ tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
+ } else {
+ /* set SWS */
+ val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
+ val |= TPA6130A2_SWS;
+ tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
+ /* Power off */
+ if (data->power_gpio >= 0) {
+ gpio_set_value(data->power_gpio, 0);
+ data->power_state = 0;
+ }
+ }
+ mutex_unlock(&data->mutex);
+}
+
+static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct tpa6130a2_data *data;
+ unsigned int reg = mc->reg;
+ unsigned int shift = mc->shift;
+ unsigned int mask = mc->max;
+ unsigned int invert = mc->invert;
+
+ BUG_ON(tpa6130a2_client == NULL);
+ data = i2c_get_clientdata(tpa6130a2_client);
+
+ mutex_lock(&data->mutex);
+
+ ucontrol->value.integer.value[0] =
+ (tpa6130a2_read(reg) >> shift) & mask;
+
+ if (invert)
+ ucontrol->value.integer.value[0] =
+ mask - ucontrol->value.integer.value[0];
+
+ mutex_unlock(&data->mutex);
+ return 0;
+}
+
+static int tpa6130a2_set_reg(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct tpa6130a2_data *data;
+ unsigned int reg = mc->reg;
+ unsigned int shift = mc->shift;
+ unsigned int mask = mc->max;
+ unsigned int invert = mc->invert;
+ unsigned int val = (ucontrol->value.integer.value[0] & mask);
+ unsigned int val_reg;
+
+ BUG_ON(tpa6130a2_client == NULL);
+ data = i2c_get_clientdata(tpa6130a2_client);
+
+ if (invert)
+ val = mask - val;
+
+ mutex_lock(&data->mutex);
+
+ val_reg = tpa6130a2_read(reg);
+ if (((val_reg >> shift) & mask) == val) {
+ mutex_unlock(&data->mutex);
+ return 0;
+ }
+
+ val_reg &= ~(mask << shift);
+ val_reg |= val << shift;
+ tpa6130a2_i2c_write(reg, val_reg);
+
+ mutex_unlock(&data->mutex);
+
+ return 1;
+}
+
+/*
+ * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going
+ * down in gain.
+ */
+static const unsigned int tpa6130_tlv[] = {
+ TLV_DB_RANGE_HEAD(10),
+ 0, 1, TLV_DB_SCALE_ITEM(-5950, 600, 0),
+ 2, 3, TLV_DB_SCALE_ITEM(-5000, 250, 0),
+ 4, 5, TLV_DB_SCALE_ITEM(-4550, 160, 0),
+ 6, 7, TLV_DB_SCALE_ITEM(-4140, 190, 0),
+ 8, 9, TLV_DB_SCALE_ITEM(-3650, 120, 0),
+ 10, 11, TLV_DB_SCALE_ITEM(-3330, 160, 0),
+ 12, 13, TLV_DB_SCALE_ITEM(-3040, 180, 0),
+ 14, 20, TLV_DB_SCALE_ITEM(-2710, 110, 0),
+ 21, 37, TLV_DB_SCALE_ITEM(-1960, 74, 0),
+ 38, 63, TLV_DB_SCALE_ITEM(-720, 45, 0),
+};
+
+static const struct snd_kcontrol_new tpa6130a2_controls[] = {
+ SOC_SINGLE_EXT_TLV("TPA6130A2 Headphone Playback Volume",
+ TPA6130A2_REG_VOL_MUTE, 0, 0x3f, 0,
+ tpa6130a2_get_reg, tpa6130a2_set_reg,
+ tpa6130_tlv),
+};
+
+/*
+ * Enable or disable channel (left or right)
+ * The bit number for mute and amplifier are the same per channel:
+ * bit 6: Right channel
+ * bit 7: Left channel
+ * in both registers.
+ */
+static void tpa6130a2_channel_enable(u8 channel, int enable)
+{
+ struct tpa6130a2_data *data;
+ u8 val;
+
+ BUG_ON(tpa6130a2_client == NULL);
+ data = i2c_get_clientdata(tpa6130a2_client);
+
+ if (enable) {
+ /* Enable channel */
+ /* Enable amplifier */
+ val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
+ val |= channel;
+ tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
+
+ /* Unmute channel */
+ val = tpa6130a2_read(TPA6130A2_REG_VOL_MUTE);
+ val &= ~channel;
+ tpa6130a2_i2c_write(TPA6130A2_REG_VOL_MUTE, val);
+ } else {
+ /* Disable channel */
+ /* Mute channel */
+ val = tpa6130a2_read(TPA6130A2_REG_VOL_MUTE);
+ val |= channel;
+ tpa6130a2_i2c_write(TPA6130A2_REG_VOL_MUTE, val);
+
+ /* Disable amplifier */
+ val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
+ val &= ~channel;
+ tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
+ }
+}
+
+static int tpa6130a2_left_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ tpa6130a2_channel_enable(TPA6130A2_HP_EN_L, 1);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ tpa6130a2_channel_enable(TPA6130A2_HP_EN_L, 0);
+ break;
+ }
+ return 0;
+}
+
+static int tpa6130a2_right_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ tpa6130a2_channel_enable(TPA6130A2_HP_EN_R, 1);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ tpa6130a2_channel_enable(TPA6130A2_HP_EN_R, 0);
+ break;
+ }
+ return 0;
+}
+
+static int tpa6130a2_supply_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ tpa6130a2_power(1);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ tpa6130a2_power(0);
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = {
+ SND_SOC_DAPM_PGA_E("TPA6130A2 Left", SND_SOC_NOPM,
+ 0, 0, NULL, 0, tpa6130a2_left_event,
+ SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("TPA6130A2 Right", SND_SOC_NOPM,
+ 0, 0, NULL, 0, tpa6130a2_right_event,
+ SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("TPA6130A2 Enable", SND_SOC_NOPM,
+ 0, 0, tpa6130a2_supply_event,
+ SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+ /* Outputs */
+ SND_SOC_DAPM_HP("TPA6130A2 Headphone Left", NULL),
+ SND_SOC_DAPM_HP("TPA6130A2 Headphone Right", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ {"TPA6130A2 Headphone Left", NULL, "TPA6130A2 Left"},
+ {"TPA6130A2 Headphone Right", NULL, "TPA6130A2 Right"},
+
+ {"TPA6130A2 Headphone Left", NULL, "TPA6130A2 Enable"},
+ {"TPA6130A2 Headphone Right", NULL, "TPA6130A2 Enable"},
+};
+
+int tpa6130a2_add_controls(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, tpa6130a2_dapm_widgets,
+ ARRAY_SIZE(tpa6130a2_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ return snd_soc_add_controls(codec, tpa6130a2_controls,
+ ARRAY_SIZE(tpa6130a2_controls));
+
+}
+EXPORT_SYMBOL_GPL(tpa6130a2_add_controls);
+
+static int tpa6130a2_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev;
+ struct tpa6130a2_data *data;
+ struct tpa6130a2_platform_data *pdata;
+ int ret;
+
+ dev = &client->dev;
+
+ if (client->dev.platform_data == NULL) {
+ dev_err(dev, "Platform data not set\n");
+ dump_stack();
+ return -ENODEV;
+ }
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (data == NULL) {
+ dev_err(dev, "Can not allocate memory\n");
+ return -ENOMEM;
+ }
+
+ tpa6130a2_client = client;
+
+ i2c_set_clientdata(tpa6130a2_client, data);
+
+ pdata = client->dev.platform_data;
+ data->power_gpio = pdata->power_gpio;
+
+ mutex_init(&data->mutex);
+
+ /* Set default register values */
+ data->regs[TPA6130A2_REG_CONTROL] = TPA6130A2_SWS;
+ data->regs[TPA6130A2_REG_VOL_MUTE] = TPA6130A2_MUTE_R |
+ TPA6130A2_MUTE_L;
+
+ if (data->power_gpio >= 0) {
+ ret = gpio_request(data->power_gpio, "tpa6130a2 enable");
+ if (ret < 0) {
+ dev_err(dev, "Failed to request power GPIO (%d)\n",
+ data->power_gpio);
+ goto fail;
+ }
+ gpio_direction_output(data->power_gpio, 0);
+ } else {
+ data->power_state = 1;
+ tpa6130a2_initialize();
+ }
+
+ tpa6130a2_power(1);
+
+ /* Read version */
+ ret = tpa6130a2_i2c_read(TPA6130A2_REG_VERSION) &
+ TPA6130A2_VERSION_MASK;
+ if ((ret != 1) && (ret != 2))
+ dev_warn(dev, "UNTESTED version detected (%d)\n", ret);
+
+ /* Disable the chip */
+ tpa6130a2_power(0);
+
+ return 0;
+fail:
+ kfree(data);
+ i2c_set_clientdata(tpa6130a2_client, NULL);
+ tpa6130a2_client = NULL;
+
+ return ret;
+}
+
+static int tpa6130a2_remove(struct i2c_client *client)
+{
+ struct tpa6130a2_data *data = i2c_get_clientdata(client);
+
+ tpa6130a2_power(0);
+
+ if (data->power_gpio >= 0)
+ gpio_free(data->power_gpio);
+ kfree(data);
+ tpa6130a2_client = NULL;
+
+ return 0;
+}
+
+static const struct i2c_device_id tpa6130a2_id[] = {
+ { "tpa6130a2", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tpa6130a2_id);
+
+static struct i2c_driver tpa6130a2_i2c_driver = {
+ .driver = {
+ .name = "tpa6130a2",
+ .owner = THIS_MODULE,
+ },
+ .probe = tpa6130a2_probe,
+ .remove = __devexit_p(tpa6130a2_remove),
+ .id_table = tpa6130a2_id,
+};
+
+static int __init tpa6130a2_init(void)
+{
+ return i2c_add_driver(&tpa6130a2_i2c_driver);
+}
+
+static void __exit tpa6130a2_exit(void)
+{
+ i2c_del_driver(&tpa6130a2_i2c_driver);
+}
+
+MODULE_AUTHOR("Peter Ujfalusi");
+MODULE_DESCRIPTION("TPA6130A2 Headphone amplifier driver");
+MODULE_LICENSE("GPL");
+
+module_init(tpa6130a2_init);
+module_exit(tpa6130a2_exit);
diff --git a/sound/soc/codecs/tpa6130a2.h b/sound/soc/codecs/tpa6130a2.h
new file mode 100644
index 000000000000..57e867fd86d1
--- /dev/null
+++ b/sound/soc/codecs/tpa6130a2.h
@@ -0,0 +1,61 @@
+/*
+ * ALSA SoC TPA6130A2 amplifier driver
+ *
+ * Copyright (C) Nokia Corporation
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@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 __TPA6130A2_H__
+#define __TPA6130A2_H__
+
+/* Register addresses */
+#define TPA6130A2_REG_CONTROL 0x01
+#define TPA6130A2_REG_VOL_MUTE 0x02
+#define TPA6130A2_REG_OUT_IMPEDANCE 0x03
+#define TPA6130A2_REG_VERSION 0x04
+
+#define TPA6130A2_CACHEREGNUM (TPA6130A2_REG_VERSION + 1)
+
+/* Register bits */
+/* TPA6130A2_REG_CONTROL (0x01) */
+#define TPA6130A2_SWS (0x01 << 0)
+#define TPA6130A2_TERMAL (0x01 << 1)
+#define TPA6130A2_MODE(x) (x << 4)
+#define TPA6130A2_MODE_STEREO (0x00)
+#define TPA6130A2_MODE_DUAL_MONO (0x01)
+#define TPA6130A2_MODE_BRIDGE (0x02)
+#define TPA6130A2_MODE_MASK (0x03)
+#define TPA6130A2_HP_EN_R (0x01 << 6)
+#define TPA6130A2_HP_EN_L (0x01 << 7)
+
+/* TPA6130A2_REG_VOL_MUTE (0x02) */
+#define TPA6130A2_VOLUME(x) ((x & 0x3f) << 0)
+#define TPA6130A2_MUTE_R (0x01 << 6)
+#define TPA6130A2_MUTE_L (0x01 << 7)
+
+/* TPA6130A2_REG_OUT_IMPEDANCE (0x03) */
+#define TPA6130A2_HIZ_R (0x01 << 0)
+#define TPA6130A2_HIZ_L (0x01 << 1)
+
+/* TPA6130A2_REG_VERSION (0x04) */
+#define TPA6130A2_VERSION_MASK (0x0f)
+
+extern int tpa6130a2_add_controls(struct snd_soc_codec *codec);
+
+#endif /* __TPA6130A2_H__ */
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index 593d5b9c9f03..714114b50d18 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -1101,7 +1101,7 @@ static inline int fll_factors(struct _fll_div *fll_div, unsigned int input,
}
static int wm8350_set_fll(struct snd_soc_dai *codec_dai,
- int pll_id, unsigned int freq_in,
+ int pll_id, int source, unsigned int freq_in,
unsigned int freq_out)
{
struct snd_soc_codec *codec = codec_dai->codec;
@@ -1680,21 +1680,6 @@ static int __devexit wm8350_codec_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8350_codec_suspend(struct platform_device *pdev, pm_message_t m)
-{
- return snd_soc_suspend_device(&pdev->dev);
-}
-
-static int wm8350_codec_resume(struct platform_device *pdev)
-{
- return snd_soc_resume_device(&pdev->dev);
-}
-#else
-#define wm8350_codec_suspend NULL
-#define wm8350_codec_resume NULL
-#endif
-
static struct platform_driver wm8350_codec_driver = {
.driver = {
.name = "wm8350-codec",
@@ -1702,8 +1687,6 @@ static struct platform_driver wm8350_codec_driver = {
},
.probe = wm8350_codec_probe,
.remove = __devexit_p(wm8350_codec_remove),
- .suspend = wm8350_codec_suspend,
- .resume = wm8350_codec_resume,
};
static __init int wm8350_init(void)
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index b9ef4d915221..bd7eecba20fe 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -1011,7 +1011,8 @@ static int fll_factors(struct wm8400_priv *wm8400, struct fll_factors *factors,
}
static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
- unsigned int freq_in, unsigned int freq_out)
+ int source, unsigned int freq_in,
+ unsigned int freq_out)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct wm8400_priv *wm8400 = codec->private_data;
@@ -1558,21 +1559,6 @@ static int __exit wm8400_codec_remove(struct platform_device *dev)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8400_pdev_suspend(struct platform_device *pdev, pm_message_t msg)
-{
- return snd_soc_suspend_device(&pdev->dev);
-}
-
-static int wm8400_pdev_resume(struct platform_device *pdev)
-{
- return snd_soc_resume_device(&pdev->dev);
-}
-#else
-#define wm8400_pdev_suspend NULL
-#define wm8400_pdev_resume NULL
-#endif
-
static struct platform_driver wm8400_codec_driver = {
.driver = {
.name = "wm8400-codec",
@@ -1580,8 +1566,6 @@ static struct platform_driver wm8400_codec_driver = {
},
.probe = wm8400_codec_probe,
.remove = __exit_p(wm8400_codec_remove),
- .suspend = wm8400_pdev_suspend,
- .resume = wm8400_pdev_resume,
};
static int __init wm8400_codec_init(void)
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 060d5d06ba95..5702435af81b 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -271,8 +271,8 @@ static void pll_factors(unsigned int target, unsigned int source)
pll_div.k = K;
}
-static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai,
- int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+ int source, unsigned int freq_in, unsigned int freq_out)
{
struct snd_soc_codec *codec = codec_dai->codec;
u16 reg;
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 25870a4652fb..268cab21c2cc 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -638,21 +638,6 @@ static __devexit int wm8523_i2c_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8523_i2c_suspend(struct i2c_client *i2c, pm_message_t msg)
-{
- return snd_soc_suspend_device(&i2c->dev);
-}
-
-static int wm8523_i2c_resume(struct i2c_client *i2c)
-{
- return snd_soc_resume_device(&i2c->dev);
-}
-#else
-#define wm8523_i2c_suspend NULL
-#define wm8523_i2c_resume NULL
-#endif
-
static const struct i2c_device_id wm8523_i2c_id[] = {
{ "wm8523", 0 },
{ }
@@ -666,8 +651,6 @@ static struct i2c_driver wm8523_i2c_driver = {
},
.probe = wm8523_i2c_probe,
.remove = __devexit_p(wm8523_i2c_remove),
- .suspend = wm8523_i2c_suspend,
- .resume = wm8523_i2c_resume,
.id_table = wm8523_i2c_id,
};
#endif
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 6bded8c78150..a09b23e03664 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -407,8 +407,8 @@ static int pll_factors(struct _pll_div *pll_div, unsigned int target,
return 0;
}
-static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai,
- int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+ int source, unsigned int freq_in, unsigned int freq_out)
{
int offset;
struct snd_soc_codec *codec = codec_dai->codec;
@@ -961,21 +961,6 @@ static int wm8580_i2c_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8580_i2c_suspend(struct i2c_client *client, pm_message_t msg)
-{
- return snd_soc_suspend_device(&client->dev);
-}
-
-static int wm8580_i2c_resume(struct i2c_client *client)
-{
- return snd_soc_resume_device(&client->dev);
-}
-#else
-#define wm8580_i2c_suspend NULL
-#define wm8580_i2c_resume NULL
-#endif
-
static const struct i2c_device_id wm8580_i2c_id[] = {
{ "wm8580", 0 },
{ }
@@ -989,8 +974,6 @@ static struct i2c_driver wm8580_i2c_driver = {
},
.probe = wm8580_i2c_probe,
.remove = wm8580_i2c_remove,
- .suspend = wm8580_i2c_suspend,
- .resume = wm8580_i2c_resume,
.id_table = wm8580_i2c_id,
};
#endif
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
new file mode 100644
index 000000000000..54189fbf9e93
--- /dev/null
+++ b/sound/soc/codecs/wm8711.c
@@ -0,0 +1,642 @@
+/*
+ * wm8711.c -- WM8711 ALSA SoC Audio driver
+ *
+ * Copyright 2006 Wolfson Microelectronics
+ *
+ * Author: Mike Arthur <linux@wolfsonmicro.com>
+ *
+ * Based on wm8731.c by Richard Purdie
+ *
+ * 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/platform_device.h>
+#include <linux/spi/spi.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 "wm8711.h"
+
+static struct snd_soc_codec *wm8711_codec;
+
+/* codec private data */
+struct wm8711_priv {
+ struct snd_soc_codec codec;
+ u16 reg_cache[WM8711_CACHEREGNUM];
+ unsigned int sysclk;
+};
+
+/*
+ * wm8711 register cache
+ * We can't read the WM8711 register space when we are
+ * using 2 wire for device control, so we cache them instead.
+ * There is no point in caching the reset register
+ */
+static const u16 wm8711_reg[WM8711_CACHEREGNUM] = {
+ 0x0079, 0x0079, 0x000a, 0x0008,
+ 0x009f, 0x000a, 0x0000, 0x0000
+};
+
+#define wm8711_reset(c) snd_soc_write(c, WM8711_RESET, 0)
+
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+
+static const struct snd_kcontrol_new wm8711_snd_controls[] = {
+
+SOC_DOUBLE_R_TLV("Master Playback Volume", WM8711_LOUT1V, WM8711_ROUT1V,
+ 0, 127, 0, out_tlv),
+SOC_DOUBLE_R("Master Playback ZC Switch", WM8711_LOUT1V, WM8711_ROUT1V,
+ 7, 1, 0),
+
+};
+
+/* Output Mixer */
+static const struct snd_kcontrol_new wm8711_output_mixer_controls[] = {
+SOC_DAPM_SINGLE("Line Bypass Switch", WM8711_APANA, 3, 1, 0),
+SOC_DAPM_SINGLE("HiFi Playback Switch", WM8711_APANA, 4, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8711_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Output Mixer", WM8711_PWR, 4, 1,
+ &wm8711_output_mixer_controls[0],
+ ARRAY_SIZE(wm8711_output_mixer_controls)),
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8711_PWR, 3, 1),
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("LHPOUT"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_OUTPUT("RHPOUT"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+ /* output mixer */
+ {"Output Mixer", "Line Bypass Switch", "Line Input"},
+ {"Output Mixer", "HiFi Playback Switch", "DAC"},
+
+ /* outputs */
+ {"RHPOUT", NULL, "Output Mixer"},
+ {"ROUT", NULL, "Output Mixer"},
+ {"LHPOUT", NULL, "Output Mixer"},
+ {"LOUT", NULL, "Output Mixer"},
+};
+
+static int wm8711_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, wm8711_dapm_widgets,
+ ARRAY_SIZE(wm8711_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+ snd_soc_dapm_new_widgets(codec);
+ return 0;
+}
+
+struct _coeff_div {
+ u32 mclk;
+ u32 rate;
+ u16 fs;
+ u8 sr:4;
+ u8 bosr:1;
+ u8 usb:1;
+};
+
+/* codec mclk clock divider coefficients */
+static const struct _coeff_div coeff_div[] = {
+ /* 48k */
+ {12288000, 48000, 256, 0x0, 0x0, 0x0},
+ {18432000, 48000, 384, 0x0, 0x1, 0x0},
+ {12000000, 48000, 250, 0x0, 0x0, 0x1},
+
+ /* 32k */
+ {12288000, 32000, 384, 0x6, 0x0, 0x0},
+ {18432000, 32000, 576, 0x6, 0x1, 0x0},
+ {12000000, 32000, 375, 0x6, 0x0, 0x1},
+
+ /* 8k */
+ {12288000, 8000, 1536, 0x3, 0x0, 0x0},
+ {18432000, 8000, 2304, 0x3, 0x1, 0x0},
+ {11289600, 8000, 1408, 0xb, 0x0, 0x0},
+ {16934400, 8000, 2112, 0xb, 0x1, 0x0},
+ {12000000, 8000, 1500, 0x3, 0x0, 0x1},
+
+ /* 96k */
+ {12288000, 96000, 128, 0x7, 0x0, 0x0},
+ {18432000, 96000, 192, 0x7, 0x1, 0x0},
+ {12000000, 96000, 125, 0x7, 0x0, 0x1},
+
+ /* 44.1k */
+ {11289600, 44100, 256, 0x8, 0x0, 0x0},
+ {16934400, 44100, 384, 0x8, 0x1, 0x0},
+ {12000000, 44100, 272, 0x8, 0x1, 0x1},
+
+ /* 88.2k */
+ {11289600, 88200, 128, 0xf, 0x0, 0x0},
+ {16934400, 88200, 192, 0xf, 0x1, 0x0},
+ {12000000, 88200, 136, 0xf, 0x1, 0x1},
+};
+
+static inline int get_coeff(int mclk, int rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+ if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+ return i;
+ }
+ return 0;
+}
+
+static int wm8711_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 wm8711_priv *wm8711 = codec->private_data;
+ 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) |
+ (coeff_div[i].bosr << 1) | coeff_div[i].usb;
+
+ snd_soc_write(codec, WM8711_SRATE, srate);
+
+ /* bit size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ iface |= 0x0004;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ iface |= 0x0008;
+ break;
+ }
+
+ snd_soc_write(codec, WM8711_IFACE, iface);
+ return 0;
+}
+
+static int wm8711_pcm_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+
+ /* set active */
+ snd_soc_write(codec, WM8711_ACTIVE, 0x0001);
+
+ return 0;
+}
+
+static void wm8711_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+
+ /* deactivate */
+ if (!codec->active) {
+ udelay(50);
+ snd_soc_write(codec, WM8711_ACTIVE, 0x0);
+ }
+}
+
+static int wm8711_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u16 mute_reg = snd_soc_read(codec, WM8711_APDIGI) & 0xfff7;
+
+ if (mute)
+ snd_soc_write(codec, WM8711_APDIGI, mute_reg | 0x8);
+ else
+ snd_soc_write(codec, WM8711_APDIGI, mute_reg);
+
+ return 0;
+}
+
+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 = codec->private_data;
+
+ switch (freq) {
+ case 11289600:
+ case 12000000:
+ case 12288000:
+ case 16934400:
+ case 18432000:
+ wm8711->sysclk = freq;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u16 iface = 0;
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ iface |= 0x0040;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ iface |= 0x0002;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ iface |= 0x0001;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ iface |= 0x0003;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ iface |= 0x0013;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ iface |= 0x0090;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ iface |= 0x0080;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ iface |= 0x0010;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* set iface */
+ snd_soc_write(codec, WM8711_IFACE, iface);
+ return 0;
+}
+
+
+static int wm8711_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ u16 reg = snd_soc_read(codec, WM8711_PWR) & 0xff7f;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ snd_soc_write(codec, WM8711_PWR, reg);
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ snd_soc_write(codec, WM8711_PWR, reg | 0x0040);
+ break;
+ case SND_SOC_BIAS_OFF:
+ snd_soc_write(codec, WM8711_ACTIVE, 0x0);
+ snd_soc_write(codec, WM8711_PWR, 0xffff);
+ break;
+ }
+ codec->bias_level = level;
+ return 0;
+}
+
+#define WM8711_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8711_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops wm8711_ops = {
+ .prepare = wm8711_pcm_prepare,
+ .hw_params = wm8711_hw_params,
+ .shutdown = wm8711_shutdown,
+ .digital_mute = wm8711_mute,
+ .set_sysclk = wm8711_set_dai_sysclk,
+ .set_fmt = wm8711_set_dai_fmt,
+};
+
+struct snd_soc_dai wm8711_dai = {
+ .name = "WM8711",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM8711_RATES,
+ .formats = WM8711_FORMATS,
+ },
+ .ops = &wm8711_ops,
+};
+EXPORT_SYMBOL_GPL(wm8711_dai);
+
+static int wm8711_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;
+
+ 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)
+{
+ 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(wm8711_reg); i++) {
+ data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
+ data[1] = cache[i] & 0x00ff;
+ codec->hw_write(codec->control_data, data, 2);
+ }
+ wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ wm8711_set_bias_level(codec, codec->suspend_bias_level);
+ return 0;
+}
+
+static int wm8711_probe(struct platform_device *pdev)
+{
+ 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);
+ ret = snd_soc_init_card(socdev);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to register card: %d\n", ret);
+ goto card_err;
+ }
+
+ return ret;
+
+card_err:
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+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");
+ return -EINVAL;
+ }
+
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ codec->private_data = 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));
+
+ 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;
+ }
+
+ ret = wm8711_reset(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to issue reset\n");
+ goto err;
+ }
+
+ wm8711_dai.dev = codec->dev;
+
+ wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ /* Latch the update bits */
+ reg = snd_soc_read(codec, WM8711_LOUT1V);
+ snd_soc_write(codec, WM8711_LOUT1V, reg | 0x0100);
+ 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;
+
+err_codec:
+ snd_soc_unregister_codec(codec);
+err:
+ kfree(wm8711);
+ return ret;
+}
+
+static void wm8711_unregister(struct wm8711_priv *wm8711)
+{
+ 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;
+}
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8711_spi_probe(struct spi_device *spi)
+{
+ struct snd_soc_codec *codec;
+ struct wm8711_priv *wm8711;
+
+ wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL);
+ if (wm8711 == NULL)
+ return -ENOMEM;
+
+ codec = &wm8711->codec;
+ codec->control_data = spi;
+ codec->dev = &spi->dev;
+
+ dev_set_drvdata(&spi->dev, wm8711);
+
+ return wm8711_register(wm8711, SND_SOC_SPI);
+}
+
+static int __devexit wm8711_spi_remove(struct spi_device *spi)
+{
+ struct wm8711_priv *wm8711 = dev_get_drvdata(&spi->dev);
+
+ wm8711_unregister(wm8711);
+
+ return 0;
+}
+
+static struct spi_driver wm8711_spi_driver = {
+ .driver = {
+ .name = "wm8711",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8711_spi_probe,
+ .remove = __devexit_p(wm8711_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8711_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8711_priv *wm8711;
+ struct snd_soc_codec *codec;
+
+ 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;
+
+ codec->dev = &i2c->dev;
+
+ return wm8711_register(wm8711, SND_SOC_I2C);
+}
+
+static __devexit int wm8711_i2c_remove(struct i2c_client *client)
+{
+ struct wm8711_priv *wm8711 = i2c_get_clientdata(client);
+ wm8711_unregister(wm8711);
+ return 0;
+}
+
+static const struct i2c_device_id wm8711_i2c_id[] = {
+ { "wm8711", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8711_i2c_id);
+
+static struct i2c_driver wm8711_i2c_driver = {
+ .driver = {
+ .name = "WM8711 I2C Codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8711_i2c_probe,
+ .remove = __devexit_p(wm8711_i2c_remove),
+ .id_table = wm8711_i2c_id,
+};
+#endif
+
+static int __init wm8711_modinit(void)
+{
+ int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8711_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8711 I2C driver: %d\n",
+ ret);
+ }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ ret = spi_register_driver(&wm8711_spi_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8711 SPI driver: %d\n",
+ ret);
+ }
+#endif
+ return 0;
+}
+module_init(wm8711_modinit);
+
+static void __exit wm8711_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8711_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ spi_unregister_driver(&wm8711_spi_driver);
+#endif
+}
+module_exit(wm8711_exit);
+
+MODULE_DESCRIPTION("ASoC WM8711 driver");
+MODULE_AUTHOR("Mike Arthur");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8711.h b/sound/soc/codecs/wm8711.h
new file mode 100644
index 000000000000..381e84a43816
--- /dev/null
+++ b/sound/soc/codecs/wm8711.h
@@ -0,0 +1,42 @@
+/*
+ * wm8711.h -- WM8711 Soc Audio driver
+ *
+ * Copyright 2006 Wolfson Microelectronics
+ *
+ * Author: Mike Arthur <linux@wolfsonmicro.com>
+ *
+ * Based on wm8731.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 _WM8711_H
+#define _WM8711_H
+
+/* WM8711 register space */
+
+#define WM8711_LOUT1V 0x02
+#define WM8711_ROUT1V 0x03
+#define WM8711_APANA 0x04
+#define WM8711_APDIGI 0x05
+#define WM8711_PWR 0x06
+#define WM8711_IFACE 0x07
+#define WM8711_SRATE 0x08
+#define WM8711_ACTIVE 0x09
+#define WM8711_RESET 0x0f
+
+#define WM8711_CACHEREGNUM 8
+
+#define WM8711_SYSCLK 0
+#define WM8711_DAI 0
+
+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/wm8731.c b/sound/soc/codecs/wm8731.c
index d3fd4f28d96e..0e59219a59f4 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -623,21 +623,6 @@ static int __devexit wm8731_spi_remove(struct spi_device *spi)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8731_spi_suspend(struct spi_device *spi, pm_message_t msg)
-{
- return snd_soc_suspend_device(&spi->dev);
-}
-
-static int wm8731_spi_resume(struct spi_device *spi)
-{
- return snd_soc_resume_device(&spi->dev);
-}
-#else
-#define wm8731_spi_suspend NULL
-#define wm8731_spi_resume NULL
-#endif
-
static struct spi_driver wm8731_spi_driver = {
.driver = {
.name = "wm8731",
@@ -645,8 +630,6 @@ static struct spi_driver wm8731_spi_driver = {
.owner = THIS_MODULE,
},
.probe = wm8731_spi_probe,
- .suspend = wm8731_spi_suspend,
- .resume = wm8731_spi_resume,
.remove = __devexit_p(wm8731_spi_remove),
};
#endif /* CONFIG_SPI_MASTER */
@@ -679,21 +662,6 @@ static __devexit int wm8731_i2c_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8731_i2c_suspend(struct i2c_client *i2c, pm_message_t msg)
-{
- return snd_soc_suspend_device(&i2c->dev);
-}
-
-static int wm8731_i2c_resume(struct i2c_client *i2c)
-{
- return snd_soc_resume_device(&i2c->dev);
-}
-#else
-#define wm8731_i2c_suspend NULL
-#define wm8731_i2c_resume NULL
-#endif
-
static const struct i2c_device_id wm8731_i2c_id[] = {
{ "wm8731", 0 },
{ }
@@ -707,8 +675,6 @@ static struct i2c_driver wm8731_i2c_driver = {
},
.probe = wm8731_i2c_probe,
.remove = __devexit_p(wm8731_i2c_remove),
- .suspend = wm8731_i2c_suspend,
- .resume = wm8731_i2c_resume,
.id_table = wm8731_i2c_id,
};
#endif
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index 5ad677ce80da..8f7305257d29 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -724,8 +724,8 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target,
pll_div->k = K;
}
-static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai,
- int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+ int source, unsigned int freq_in, unsigned int freq_out)
{
u16 reg, enable;
int offset;
@@ -1767,21 +1767,6 @@ static int wm8753_i2c_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8753_i2c_suspend(struct i2c_client *client, pm_message_t msg)
-{
- return snd_soc_suspend_device(&client->dev);
-}
-
-static int wm8753_i2c_resume(struct i2c_client *client)
-{
- return snd_soc_resume_device(&client->dev);
-}
-#else
-#define wm8753_i2c_suspend NULL
-#define wm8753_i2c_resume NULL
-#endif
-
static const struct i2c_device_id wm8753_i2c_id[] = {
{ "wm8753", 0 },
{ }
@@ -1795,8 +1780,6 @@ static struct i2c_driver wm8753_i2c_driver = {
},
.probe = wm8753_i2c_probe,
.remove = wm8753_i2c_remove,
- .suspend = wm8753_i2c_suspend,
- .resume = wm8753_i2c_resume,
.id_table = wm8753_i2c_id,
};
#endif
@@ -1852,22 +1835,6 @@ static int __devexit wm8753_spi_remove(struct spi_device *spi)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8753_spi_suspend(struct spi_device *spi, pm_message_t msg)
-{
- return snd_soc_suspend_device(&spi->dev);
-}
-
-static int wm8753_spi_resume(struct spi_device *spi)
-{
- return snd_soc_resume_device(&spi->dev);
-}
-
-#else
-#define wm8753_spi_suspend NULL
-#define wm8753_spi_resume NULL
-#endif
-
static struct spi_driver wm8753_spi_driver = {
.driver = {
.name = "wm8753",
@@ -1876,8 +1843,6 @@ static struct spi_driver wm8753_spi_driver = {
},
.probe = wm8753_spi_probe,
.remove = __devexit_p(wm8753_spi_remove),
- .suspend = wm8753_spi_suspend,
- .resume = wm8753_spi_resume,
};
#endif
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index a9829aa26e53..a0bbb28eed75 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -616,21 +616,6 @@ static int __devexit wm8776_spi_remove(struct spi_device *spi)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8776_spi_suspend(struct spi_device *spi, pm_message_t msg)
-{
- return snd_soc_suspend_device(&spi->dev);
-}
-
-static int wm8776_spi_resume(struct spi_device *spi)
-{
- return snd_soc_resume_device(&spi->dev);
-}
-#else
-#define wm8776_spi_suspend NULL
-#define wm8776_spi_resume NULL
-#endif
-
static struct spi_driver wm8776_spi_driver = {
.driver = {
.name = "wm8776",
@@ -638,8 +623,6 @@ static struct spi_driver wm8776_spi_driver = {
.owner = THIS_MODULE,
},
.probe = wm8776_spi_probe,
- .suspend = wm8776_spi_suspend,
- .resume = wm8776_spi_resume,
.remove = __devexit_p(wm8776_spi_remove),
};
#endif /* CONFIG_SPI_MASTER */
@@ -673,21 +656,6 @@ static __devexit int wm8776_i2c_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8776_i2c_suspend(struct i2c_client *i2c, pm_message_t msg)
-{
- return snd_soc_suspend_device(&i2c->dev);
-}
-
-static int wm8776_i2c_resume(struct i2c_client *i2c)
-{
- return snd_soc_resume_device(&i2c->dev);
-}
-#else
-#define wm8776_i2c_suspend NULL
-#define wm8776_i2c_resume NULL
-#endif
-
static const struct i2c_device_id wm8776_i2c_id[] = {
{ "wm8776", 0 },
{ }
@@ -701,8 +669,6 @@ static struct i2c_driver wm8776_i2c_driver = {
},
.probe = wm8776_i2c_probe,
.remove = __devexit_p(wm8776_i2c_remove),
- .suspend = wm8776_i2c_suspend,
- .resume = wm8776_i2c_resume,
.id_table = wm8776_i2c_id,
};
#endif
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index 5e9c855c0036..b48804b5cacd 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -814,8 +814,8 @@ reenable:
return 0;
}
-static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai,
- int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+ int source, unsigned int freq_in, unsigned int freq_out)
{
return wm8900_set_fll(codec_dai->codec, pll_id, freq_in, freq_out);
}
@@ -1312,21 +1312,6 @@ static __devexit int wm8900_i2c_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8900_i2c_suspend(struct i2c_client *client, pm_message_t msg)
-{
- return snd_soc_suspend_device(&client->dev);
-}
-
-static int wm8900_i2c_resume(struct i2c_client *client)
-{
- return snd_soc_resume_device(&client->dev);
-}
-#else
-#define wm8900_i2c_suspend NULL
-#define wm8900_i2c_resume NULL
-#endif
-
static const struct i2c_device_id wm8900_i2c_id[] = {
{ "wm8900", 0 },
{ }
@@ -1340,8 +1325,6 @@ static struct i2c_driver wm8900_i2c_driver = {
},
.probe = wm8900_i2c_probe,
.remove = __devexit_p(wm8900_i2c_remove),
- .suspend = wm8900_i2c_suspend,
- .resume = wm8900_i2c_resume,
.id_table = wm8900_i2c_id,
};
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index fe1307b500cf..94cdb8130415 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -1655,21 +1655,6 @@ static __devexit int wm8903_i2c_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8903_i2c_suspend(struct i2c_client *client, pm_message_t msg)
-{
- return snd_soc_suspend_device(&client->dev);
-}
-
-static int wm8903_i2c_resume(struct i2c_client *client)
-{
- return snd_soc_resume_device(&client->dev);
-}
-#else
-#define wm8903_i2c_suspend NULL
-#define wm8903_i2c_resume NULL
-#endif
-
/* i2c codec control layer */
static const struct i2c_device_id wm8903_i2c_id[] = {
{ "wm8903", 0 },
@@ -1684,8 +1669,6 @@ static struct i2c_driver wm8903_i2c_driver = {
},
.probe = wm8903_i2c_probe,
.remove = __devexit_p(wm8903_i2c_remove),
- .suspend = wm8903_i2c_suspend,
- .resume = wm8903_i2c_resume,
.id_table = wm8903_i2c_id,
};
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index 1ef2454c5205..8d4fd3c08c09 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -536,8 +536,8 @@ static void pll_factors(unsigned int target, unsigned int source)
}
/* Untested at the moment */
-static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai,
- int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+ int source, unsigned int freq_in, unsigned int freq_out)
{
struct snd_soc_codec *codec = codec_dai->codec;
u16 reg;
@@ -877,21 +877,6 @@ static int __devexit wm8940_i2c_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8940_i2c_suspend(struct i2c_client *client, pm_message_t msg)
-{
- return snd_soc_suspend_device(&client->dev);
-}
-
-static int wm8940_i2c_resume(struct i2c_client *client)
-{
- return snd_soc_resume_device(&client->dev);
-}
-#else
-#define wm8940_i2c_suspend NULL
-#define wm8940_i2c_resume NULL
-#endif
-
static const struct i2c_device_id wm8940_i2c_id[] = {
{ "wm8940", 0 },
{ }
@@ -905,8 +890,6 @@ static struct i2c_driver wm8940_i2c_driver = {
},
.probe = wm8940_i2c_probe,
.remove = __devexit_p(wm8940_i2c_remove),
- .suspend = wm8940_i2c_suspend,
- .resume = wm8940_i2c_resume,
.id_table = wm8940_i2c_id,
};
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index f59703be61c8..b9b096a85396 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -540,8 +540,8 @@ static int pll_factors(unsigned int source, unsigned int target,
return 0;
}
-static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai,
- int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+ int source, unsigned int freq_in, unsigned int freq_out)
{
struct snd_soc_codec *codec = codec_dai->codec;
u16 reg;
@@ -883,21 +883,6 @@ static __devexit int wm8960_i2c_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8960_i2c_suspend(struct i2c_client *client, pm_message_t msg)
-{
- return snd_soc_suspend_device(&client->dev);
-}
-
-static int wm8960_i2c_resume(struct i2c_client *client)
-{
- return snd_soc_resume_device(&client->dev);
-}
-#else
-#define wm8960_i2c_suspend NULL
-#define wm8960_i2c_resume NULL
-#endif
-
static const struct i2c_device_id wm8960_i2c_id[] = {
{ "wm8960", 0 },
{ }
@@ -911,8 +896,6 @@ static struct i2c_driver wm8960_i2c_driver = {
},
.probe = wm8960_i2c_probe,
.remove = __devexit_p(wm8960_i2c_remove),
- .suspend = wm8960_i2c_suspend,
- .resume = wm8960_i2c_resume,
.id_table = wm8960_i2c_id,
};
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index 503032085899..b5c6f2cd5ae2 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -1206,21 +1206,6 @@ static __devexit int wm8961_i2c_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8961_i2c_suspend(struct i2c_client *client, pm_message_t state)
-{
- return snd_soc_suspend_device(&client->dev);
-}
-
-static int wm8961_i2c_resume(struct i2c_client *client)
-{
- return snd_soc_resume_device(&client->dev);
-}
-#else
-#define wm8961_i2c_suspend NULL
-#define wm8961_i2c_resume NULL
-#endif
-
static const struct i2c_device_id wm8961_i2c_id[] = {
{ "wm8961", 0 },
{ }
@@ -1234,8 +1219,6 @@ static struct i2c_driver wm8961_i2c_driver = {
},
.probe = wm8961_i2c_probe,
.remove = __devexit_p(wm8961_i2c_remove),
- .suspend = wm8961_i2c_suspend,
- .resume = wm8961_i2c_resume,
.id_table = wm8961_i2c_id,
};
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index 98d663afc97d..eff29331235b 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -281,36 +281,38 @@ static int wm8974_add_widgets(struct snd_soc_codec *codec)
}
struct pll_ {
- unsigned int pre_div:4; /* prescale - 1 */
+ unsigned int pre_div:1;
unsigned int n:4;
unsigned int k;
};
-static struct pll_ pll_div;
-
/* The size in bits of the pll divide multiplied by 10
* to allow rounding later */
#define FIXED_PLL_SIZE ((1 << 24) * 10)
-static void pll_factors(unsigned int target, unsigned int source)
+static void pll_factors(struct pll_ *pll_div,
+ unsigned int target, unsigned int source)
{
unsigned long long Kpart;
unsigned int K, Ndiv, Nmod;
+ /* There is a fixed divide by 4 in the output path */
+ target *= 4;
+
Ndiv = target / source;
if (Ndiv < 6) {
- source >>= 1;
- pll_div.pre_div = 1;
+ source /= 2;
+ pll_div->pre_div = 1;
Ndiv = target / source;
} else
- pll_div.pre_div = 0;
+ pll_div->pre_div = 0;
if ((Ndiv < 6) || (Ndiv > 12))
printk(KERN_WARNING
"WM8974 N value %u outwith recommended range!\n",
Ndiv);
- pll_div.n = Ndiv;
+ pll_div->n = Ndiv;
Nmod = target % source;
Kpart = FIXED_PLL_SIZE * (long long)Nmod;
@@ -325,13 +327,14 @@ static void pll_factors(unsigned int target, unsigned int source)
/* Move down to proper range now rounding is done */
K /= 10;
- pll_div.k = K;
+ pll_div->k = K;
}
-static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai,
- int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+ int source, unsigned int freq_in, unsigned int freq_out)
{
struct snd_soc_codec *codec = codec_dai->codec;
+ struct pll_ pll_div;
u16 reg;
if (freq_in == 0 || freq_out == 0) {
@@ -345,7 +348,7 @@ static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai,
return 0;
}
- pll_factors(freq_out*4, freq_in);
+ pll_factors(&pll_div, freq_out, freq_in);
snd_soc_write(codec, WM8974_PLLN, (pll_div.pre_div << 4) | pll_div.n);
snd_soc_write(codec, WM8974_PLLK1, pll_div.k >> 18);
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index 3f530f8a972a..d8d8f68b81ea 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -944,21 +944,6 @@ static int wm8988_i2c_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8988_i2c_suspend(struct i2c_client *client, pm_message_t msg)
-{
- return snd_soc_suspend_device(&client->dev);
-}
-
-static int wm8988_i2c_resume(struct i2c_client *client)
-{
- return snd_soc_resume_device(&client->dev);
-}
-#else
-#define wm8988_i2c_suspend NULL
-#define wm8988_i2c_resume NULL
-#endif
-
static const struct i2c_device_id wm8988_i2c_id[] = {
{ "wm8988", 0 },
{ }
@@ -972,8 +957,6 @@ static struct i2c_driver wm8988_i2c_driver = {
},
.probe = wm8988_i2c_probe,
.remove = wm8988_i2c_remove,
- .suspend = wm8988_i2c_suspend,
- .resume = wm8988_i2c_resume,
.id_table = wm8988_i2c_id,
};
#endif
@@ -1006,21 +989,6 @@ static int __devexit wm8988_spi_remove(struct spi_device *spi)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8988_spi_suspend(struct spi_device *spi, pm_message_t msg)
-{
- return snd_soc_suspend_device(&spi->dev);
-}
-
-static int wm8988_spi_resume(struct spi_device *spi)
-{
- return snd_soc_resume_device(&spi->dev);
-}
-#else
-#define wm8988_spi_suspend NULL
-#define wm8988_spi_resume NULL
-#endif
-
static struct spi_driver wm8988_spi_driver = {
.driver = {
.name = "wm8988",
@@ -1029,8 +997,6 @@ static struct spi_driver wm8988_spi_driver = {
},
.probe = wm8988_spi_probe,
.remove = __devexit_p(wm8988_spi_remove),
- .suspend = wm8988_spi_suspend,
- .resume = wm8988_spi_resume,
};
#endif
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 2d702db4131d..f657e9a5fe26 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -972,8 +972,8 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target,
pll_div->k = K;
}
-static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai,
- int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+ int source, unsigned int freq_in, unsigned int freq_out)
{
u16 reg;
struct snd_soc_codec *codec = codec_dai->codec;
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index d9987999e92c..dac397712147 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -422,7 +422,7 @@ 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,
+static int wm8993_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;
@@ -1572,33 +1572,15 @@ static int wm8993_i2c_probe(struct i2c_client *i2c,
/* Use automatic clock configuration */
snd_soc_update_bits(codec, WM8993_CLOCKING_4, WM8993_SR_MODE, 0);
- if (!wm8993->pdata.lineout1_diff)
- snd_soc_update_bits(codec, WM8993_LINE_MIXER1,
- WM8993_LINEOUT1_MODE,
- WM8993_LINEOUT1_MODE);
- if (!wm8993->pdata.lineout2_diff)
- snd_soc_update_bits(codec, WM8993_LINE_MIXER2,
- WM8993_LINEOUT2_MODE,
- WM8993_LINEOUT2_MODE);
-
- if (wm8993->pdata.lineout1fb)
- snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
- WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB);
-
- if (wm8993->pdata.lineout2fb)
- snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
- WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB);
-
- /* Apply the microphone bias/detection configuration - the
- * platform data is directly applicable to the register. */
- snd_soc_update_bits(codec, WM8993_MICBIAS,
- WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK |
- WM8993_MICB1_LVL | WM8993_MICB2_LVL,
- wm8993->pdata.jd_scthr << WM8993_JD_SCTHR_SHIFT |
- wm8993->pdata.jd_thr << WM8993_JD_THR_SHIFT |
- wm8993->pdata.micbias1_lvl |
- wm8993->pdata.micbias1_lvl << 1);
-
+ 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;
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 686e5aa97206..4cb6b104b729 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -1452,21 +1452,6 @@ static __devexit int wm9081_i2c_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
-static int wm9081_i2c_suspend(struct i2c_client *client, pm_message_t msg)
-{
- return snd_soc_suspend_device(&client->dev);
-}
-
-static int wm9081_i2c_resume(struct i2c_client *client)
-{
- return snd_soc_resume_device(&client->dev);
-}
-#else
-#define wm9081_i2c_suspend NULL
-#define wm9081_i2c_resume NULL
-#endif
-
static const struct i2c_device_id wm9081_i2c_id[] = {
{ "wm9081", 0 },
{ }
@@ -1480,8 +1465,6 @@ static struct i2c_driver wm9081_i2c_driver = {
},
.probe = wm9081_i2c_probe,
.remove = __devexit_p(wm9081_i2c_remove),
- .suspend = wm9081_i2c_suspend,
- .resume = wm9081_i2c_resume,
.id_table = wm9081_i2c_id,
};
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index abed37acf787..ca3d449ed89e 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -800,8 +800,8 @@ static int wm9713_set_pll(struct snd_soc_codec *codec,
return 0;
}
-static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai,
- int pll_id, unsigned int freq_in, unsigned int freq_out)
+static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+ int source, unsigned int freq_in, unsigned int freq_out)
{
struct snd_soc_codec *codec = codec_dai->codec;
return wm9713_set_pll(codec, pll_id, freq_in, freq_out);
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index e542027eea89..810a563d0ebf 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -738,6 +738,41 @@ int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec,
}
EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_routes);
+int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec,
+ int lineout1_diff, int lineout2_diff,
+ int lineout1fb, int lineout2fb,
+ int jd_scthr, int jd_thr, int micbias1_lvl,
+ int micbias2_lvl)
+{
+ if (!lineout1_diff)
+ snd_soc_update_bits(codec, WM8993_LINE_MIXER1,
+ WM8993_LINEOUT1_MODE,
+ WM8993_LINEOUT1_MODE);
+ if (!lineout2_diff)
+ snd_soc_update_bits(codec, WM8993_LINE_MIXER2,
+ WM8993_LINEOUT2_MODE,
+ WM8993_LINEOUT2_MODE);
+
+ if (lineout1fb)
+ snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
+ WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB);
+
+ if (lineout2fb)
+ snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
+ WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB);
+
+ snd_soc_update_bits(codec, WM8993_MICBIAS,
+ WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK |
+ WM8993_MICB1_LVL | WM8993_MICB2_LVL,
+ jd_scthr << WM8993_JD_SCTHR_SHIFT |
+ jd_thr << WM8993_JD_THR_SHIFT |
+ micbias1_lvl |
+ micbias2_lvl << WM8993_MICB2_LVL_SHIFT);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata);
+
MODULE_DESCRIPTION("Shared support for Wolfson hubs products");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h
index ec09cb6a2939..36d3fba1de8b 100644
--- a/sound/soc/codecs/wm_hubs.h
+++ b/sound/soc/codecs/wm_hubs.h
@@ -20,5 +20,10 @@ extern const unsigned int wm_hubs_spkmix_tlv[];
extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *);
extern int wm_hubs_add_analogue_routes(struct snd_soc_codec *, int, int);
+extern int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *,
+ int lineout1_diff, int lineout2_diff,
+ int lineout1fb, int lineout2fb,
+ int jd_scthr, int jd_thr,
+ int micbias1_lvl, int micbias2_lvl);
#endif
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index 4dfd4ad9d90e..047ee39418c0 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -13,9 +13,9 @@ config SND_DAVINCI_SOC_MCASP
tristate
config SND_DAVINCI_SOC_EVM
- tristate "SoC Audio support for DaVinci DM6446 or DM355 EVM"
+ tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
depends on SND_DAVINCI_SOC
- depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM
+ depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM
select SND_DAVINCI_SOC_I2S
select SND_SOC_TLV320AIC3X
help
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 67414f659405..7ccbe6684fc2 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -45,7 +45,8 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
unsigned sysclk;
/* ASP1 on DM355 EVM is clocked by an external oscillator */
- if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm())
+ if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm() ||
+ machine_is_davinci_dm365_evm())
sysclk = 27000000;
/* ASP0 in DM6446 EVM is clocked by U55, as configured by
@@ -176,7 +177,7 @@ static struct snd_soc_dai_link da8xx_evm_dai = {
.ops = &evm_ops,
};
-/* davinci-evm audio machine driver */
+/* davinci dm6446, dm355 or dm365 evm audio machine driver */
static struct snd_soc_card snd_soc_card_evm = {
.name = "DaVinci EVM",
.platform = &davinci_soc_platform,
@@ -243,7 +244,7 @@ static int __init evm_init(void)
int index;
int ret;
- if (machine_is_davinci_evm()) {
+ if (machine_is_davinci_evm() || machine_is_davinci_dm365_evm()) {
evm_snd_dev_data = &evm_snd_devdata;
index = 0;
} else if (machine_is_davinci_dm355_evm()) {
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index 4ae707048021..2ab809359c08 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -397,6 +397,8 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
}
dma_params->acnt = dma_params->data_type;
+ dma_params->fifo_level = 0;
+
rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(1);
xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(1);
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 5d1f98a4c978..50ad0519a8fa 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -714,16 +714,13 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
struct davinci_pcm_dma_params *dma_params =
&dev->dma_params[substream->stream];
int word_length;
- u8 numevt;
+ u8 fifo_level;
davinci_hw_common_param(dev, substream->stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- numevt = dev->txnumevt;
+ fifo_level = dev->txnumevt;
else
- numevt = dev->rxnumevt;
-
- if (!numevt)
- numevt = 1;
+ fifo_level = dev->rxnumevt;
if (dev->op_mode == DAVINCI_MCASP_DIT_MODE)
davinci_hw_dit_param(dev);
@@ -751,12 +748,12 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- if (dev->version == MCASP_VERSION_2) {
- dma_params->data_type *= numevt;
- dma_params->acnt = 4 * numevt;
- } else
+ if (dev->version == MCASP_VERSION_2 && !fifo_level)
+ dma_params->acnt = 4;
+ else
dma_params->acnt = dma_params->data_type;
+ dma_params->fifo_level = fifo_level;
davinci_config_channel_size(dev, word_length);
return 0;
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index c73a915f233f..fb10f1d63fdb 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -66,38 +66,53 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
dma_addr_t dma_pos;
dma_addr_t src, dst;
unsigned short src_bidx, dst_bidx;
+ unsigned short src_cidx, dst_cidx;
unsigned int data_type;
unsigned short acnt;
unsigned int count;
+ unsigned int fifo_level;
period_size = snd_pcm_lib_period_bytes(substream);
dma_offset = prtd->period * period_size;
dma_pos = runtime->dma_addr + dma_offset;
+ fifo_level = prtd->params->fifo_level;
pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d "
"dma_ptr = %x period_size=%x\n", lch, dma_pos, period_size);
data_type = prtd->params->data_type;
count = period_size / data_type;
+ if (fifo_level)
+ count /= fifo_level;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
src = dma_pos;
dst = prtd->params->dma_addr;
src_bidx = data_type;
dst_bidx = 0;
+ src_cidx = data_type * fifo_level;
+ dst_cidx = 0;
} else {
src = prtd->params->dma_addr;
dst = dma_pos;
src_bidx = 0;
dst_bidx = data_type;
+ src_cidx = 0;
+ dst_cidx = data_type * fifo_level;
}
acnt = prtd->params->acnt;
edma_set_src(lch, src, INCR, W8BIT);
edma_set_dest(lch, dst, INCR, W8BIT);
- edma_set_src_index(lch, src_bidx, 0);
- edma_set_dest_index(lch, dst_bidx, 0);
- edma_set_transfer_params(lch, acnt, count, 1, 0, ASYNC);
+
+ edma_set_src_index(lch, src_bidx, src_cidx);
+ edma_set_dest_index(lch, dst_bidx, dst_cidx);
+
+ if (!fifo_level)
+ edma_set_transfer_params(lch, acnt, count, 1, 0, ASYNC);
+ else
+ edma_set_transfer_params(lch, acnt, fifo_level, count,
+ fifo_level, ABSYNC);
prtd->period++;
if (unlikely(prtd->period >= runtime->periods))
diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h
index 8746606efc89..c8b0d2baf05a 100644
--- a/sound/soc/davinci/davinci-pcm.h
+++ b/sound/soc/davinci/davinci-pcm.h
@@ -23,6 +23,7 @@ struct davinci_pcm_dma_params {
enum dma_event_q eventq_no; /* event queue number */
unsigned char data_type; /* xfer data type */
unsigned char convert_mono_stereo;
+ unsigned int fifo_level;
};
diff --git a/sound/soc/imx/mx27vis_wm8974.c b/sound/soc/imx/mx27vis_wm8974.c
index e4dcb539108a..0267d2d91685 100644
--- a/sound/soc/imx/mx27vis_wm8974.c
+++ b/sound/soc/imx/mx27vis_wm8974.c
@@ -157,7 +157,7 @@ static int mx27vis_hifi_hw_params(struct snd_pcm_substream *substream,
/* codec PLL input is 25 MHz */
- ret = codec_dai->ops->set_pll(codec_dai, IGNORED_ARG,
+ ret = codec_dai->ops->set_pll(codec_dai, IGNORED_ARG, IGNORED_ARG,
25000000, pll_out);
if (ret < 0) {
printk(KERN_ERR "Error when setting PLL input\n");
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index 5a5166ac7279..3f1a6c1a0355 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -31,8 +31,8 @@
#include <asm/mach-types.h>
-#include <mach/board-ams-delta.h>
-#include <mach/mcbsp.h>
+#include <plat/board-ams-delta.h>
+#include <plat/mcbsp.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 0a505938e42b..08e09d72790f 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -32,7 +32,7 @@
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <linux/gpio.h>
-#include <mach/mcbsp.h>
+#include <plat/mcbsp.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 3341f49402ca..e8e63ba40877 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -31,9 +31,9 @@
#include <sound/initval.h>
#include <sound/soc.h>
-#include <mach/control.h>
-#include <mach/dma.h>
-#include <mach/mcbsp.h>
+#include <plat/control.h>
+#include <plat/dma.h>
+#include <plat/mcbsp.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 5735945788bf..1169d2ec2e24 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -28,7 +28,7 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
-#include <mach/dma.h>
+#include <plat/dma.h>
#include "omap-pcm.h"
static const struct snd_pcm_hardware omap_pcm_hardware = {
diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c
index 027e1a40f8a1..c7adea38274c 100644
--- a/sound/soc/omap/omap2evm.c
+++ b/sound/soc/omap/omap2evm.c
@@ -31,7 +31,7 @@
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
-#include <mach/mcbsp.h>
+#include <plat/mcbsp.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c
index b0cff9f33b7e..d88ad5ca526c 100644
--- a/sound/soc/omap/omap3beagle.c
+++ b/sound/soc/omap/omap3beagle.c
@@ -29,7 +29,7 @@
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
-#include <mach/mcbsp.h>
+#include <plat/mcbsp.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c
index 9114c263077b..41a91b5cf12b 100644
--- a/sound/soc/omap/omap3evm.c
+++ b/sound/soc/omap/omap3evm.c
@@ -27,7 +27,7 @@
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
-#include <mach/mcbsp.h>
+#include <plat/mcbsp.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
index a4e149b7f0eb..498ca2e03519 100644
--- a/sound/soc/omap/osk5912.c
+++ b/sound/soc/omap/osk5912.c
@@ -31,7 +31,7 @@
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <linux/gpio.h>
-#include <mach/mcbsp.h>
+#include <plat/mcbsp.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c
index ec4f8fd8b3a2..624f40ecc472 100644
--- a/sound/soc/omap/overo.c
+++ b/sound/soc/omap/overo.c
@@ -29,7 +29,7 @@
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
-#include <mach/mcbsp.h>
+#include <plat/mcbsp.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index 4a3f62d1f295..c071f9603a38 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -34,7 +34,7 @@
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
-#include <mach/mcbsp.h>
+#include <plat/mcbsp.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c
index f90b45f56220..f90a2ac888cf 100644
--- a/sound/soc/omap/zoom2.c
+++ b/sound/soc/omap/zoom2.c
@@ -29,7 +29,7 @@
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
-#include <mach/mcbsp.h>
+#include <plat/mcbsp.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index dcb3181bb340..d4f4031afa33 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -90,7 +90,8 @@ config SND_PXA2XX_SOC_E800
config SND_PXA2XX_SOC_EM_X270
tristate "SoC Audio support for CompuLab EM-x270, eXeda and CM-X300"
- depends on SND_PXA2XX_SOC && MACH_EM_X270
+ depends on SND_PXA2XX_SOC && (MACH_EM_X270 || MACH_EXEDA || \
+ MACH_CM_X300)
select SND_PXA2XX_SOC_AC97
select SND_SOC_WM9712
help
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c
index 9f7c61e23daf..4c8d99a8d386 100644
--- a/sound/soc/pxa/magician.c
+++ b/sound/soc/pxa/magician.c
@@ -213,7 +213,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
return ret;
/* set SSP audio pll clock */
- ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, acps);
+ ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, acps);
if (ret < 0)
return ret;
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index d11a6d7e384a..3bd7712f029b 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -305,8 +305,8 @@ static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
/*
* Configure the PLL frequency pxa27x and (afaik - pxa320 only)
*/
-static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai,
- int pll_id, unsigned int freq_in, unsigned int freq_out)
+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_device *ssp = priv->dev.ssp;
@@ -760,13 +760,13 @@ struct snd_soc_dai pxa_ssp_dai[] = {
.resume = pxa_ssp_resume,
.playback = {
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
.rates = PXA_SSP_RATES,
.formats = PXA_SSP_FORMATS,
},
.capture = {
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
.rates = PXA_SSP_RATES,
.formats = PXA_SSP_FORMATS,
},
@@ -780,13 +780,13 @@ struct snd_soc_dai pxa_ssp_dai[] = {
.resume = pxa_ssp_resume,
.playback = {
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
.rates = PXA_SSP_RATES,
.formats = PXA_SSP_FORMATS,
},
.capture = {
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
.rates = PXA_SSP_RATES,
.formats = PXA_SSP_FORMATS,
},
@@ -801,13 +801,13 @@ struct snd_soc_dai pxa_ssp_dai[] = {
.resume = pxa_ssp_resume,
.playback = {
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
.rates = PXA_SSP_RATES,
.formats = PXA_SSP_FORMATS,
},
.capture = {
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
.rates = PXA_SSP_RATES,
.formats = PXA_SSP_FORMATS,
},
@@ -822,13 +822,13 @@ struct snd_soc_dai pxa_ssp_dai[] = {
.resume = pxa_ssp_resume,
.playback = {
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
.rates = PXA_SSP_RATES,
.formats = PXA_SSP_FORMATS,
},
.capture = {
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
.rates = PXA_SSP_RATES,
.formats = PXA_SSP_FORMATS,
},
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c
index 9a386b4c4ed1..dd678ae24398 100644
--- a/sound/soc/pxa/zylonite.c
+++ b/sound/soc/pxa/zylonite.c
@@ -74,7 +74,8 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int zylonite_wm9713_init(struct snd_soc_codec *codec)
{
if (clk_pout)
- snd_soc_dai_set_pll(&codec->dai[0], 0, clk_get_rate(pout), 0);
+ snd_soc_dai_set_pll(&codec->dai[0], 0, 0,
+ clk_get_rate(pout), 0);
snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets,
ARRAY_SIZE(zylonite_dapm_widgets));
@@ -128,7 +129,7 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, pll_out);
+ ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, pll_out);
if (ret < 0)
return ret;
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 923428fc1adb..d7912f1e4627 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -56,6 +56,15 @@ config SND_S3C24XX_SOC_JIVE_WM8750
help
Sat Y if you want to add support for SoC audio on the Jive.
+config SND_S3C64XX_SOC_WM8580
+ tristate "SoC I2S Audio support for WM8580 on SMDK64XX"
+ depends on SND_S3C24XX_SOC && (MACH_SMDK6400 || MACH_SMDK6410)
+ depends on BROKEN
+ select SND_SOC_WM8580
+ select SND_S3C64XX_SOC_I2S
+ help
+ Sat Y if you want to add support for SoC audio on the SMDK64XX.
+
config SND_S3C24XX_SOC_SMDK2443_WM9710
tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
depends on SND_S3C24XX_SOC && MACH_SMDK2443
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 99f5a7dd3fc6..7790406f90b7 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -23,6 +23,7 @@ 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-smdk64xx-wm8580-objs := smdk64xx_wm8580.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
@@ -33,4 +34,5 @@ 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_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o
diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
index 0c52e36ddd87..26409a9cef9e 100644
--- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
@@ -119,7 +119,7 @@ static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream,
return ret;
/* codec PLL input is PCLK/4 */
- ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1,
+ ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
iis_clkrate / 4, pll_out);
if (ret < 0)
return ret;
@@ -133,7 +133,7 @@ static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream)
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
/* disable the PLL */
- return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0);
+ return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
}
/*
@@ -183,7 +183,7 @@ static int neo1973_gta02_voice_hw_params(
return ret;
/* configue and enable PLL for 12.288MHz output */
- ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2,
+ ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
iis_clkrate / 4, 12288000);
if (ret < 0)
return ret;
@@ -197,7 +197,7 @@ static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream)
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
/* disable the PLL */
- return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0);
+ return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
}
static struct snd_soc_ops neo1973_gta02_voice_ops = {
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index 906709e6dd5f..77de6c5127d2 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -29,7 +29,6 @@
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
-#include <plat/audio.h>
#include <linux/io.h>
#include <mach/spi-gpio.h>
@@ -137,7 +136,7 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
return ret;
/* codec PLL input is PCLK/4 */
- ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1,
+ ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
iis_clkrate / 4, pll_out);
if (ret < 0)
return ret;
@@ -153,7 +152,7 @@ static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
pr_debug("Entered %s\n", __func__);
/* disable the PLL */
- return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0);
+ return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
}
/*
@@ -203,7 +202,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
return ret;
/* configue and enable PLL for 12.288MHz output */
- ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2,
+ ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
iis_clkrate / 4, 12288000);
if (ret < 0)
return ret;
@@ -219,7 +218,7 @@ static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
pr_debug("Entered %s\n", __func__);
/* disable the PLL */
- return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0);
+ return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
}
static struct snd_soc_ops neo1973_voice_ops = {
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c
index 9bc4aa35caab..28b0ab255096 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.c
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.c
@@ -32,7 +32,6 @@
#include <plat/regs-s3c2412-iis.h>
-#include <plat/audio.h>
#include <mach/dma.h>
#include "s3c-i2s-v2.h"
@@ -312,12 +311,15 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_RIGHT_J:
+ iismod |= S3C2412_IISMOD_LR_RLOW;
iismod |= S3C2412_IISMOD_SDF_MSB;
break;
case SND_SOC_DAIFMT_LEFT_J:
+ iismod |= S3C2412_IISMOD_LR_RLOW;
iismod |= S3C2412_IISMOD_SDF_LSB;
break;
case SND_SOC_DAIFMT_I2S:
+ iismod &= ~S3C2412_IISMOD_LR_RLOW;
iismod |= S3C2412_IISMOD_SDF_IIS;
break;
default:
@@ -467,6 +469,31 @@ static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
switch (div_id) {
case S3C_I2SV2_DIV_BCLK:
+ if (div > 3) {
+ /* convert value to bit field */
+
+ switch (div) {
+ case 16:
+ div = S3C2412_IISMOD_BCLK_16FS;
+ break;
+
+ case 32:
+ div = S3C2412_IISMOD_BCLK_32FS;
+ break;
+
+ case 24:
+ div = S3C2412_IISMOD_BCLK_24FS;
+ break;
+
+ case 48:
+ div = S3C2412_IISMOD_BCLK_48FS;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ }
+
reg = readl(i2s->regs + S3C2412_IISMOD);
reg &= ~S3C2412_IISMOD_BCLK_MASK;
writel(reg | div, i2s->regs + S3C2412_IISMOD);
@@ -626,7 +653,7 @@ int s3c_i2sv2_probe(struct platform_device *pdev,
}
i2s->iis_pclk = clk_get(dev, "iis");
- if (i2s->iis_pclk == NULL) {
+ if (IS_ERR(i2s->iis_pclk)) {
dev_err(dev, "failed to get iis_clock\n");
iounmap(i2s->regs);
return -ENOENT;
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c
index a587ec40b449..ac5e47b082fb 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.c
+++ b/sound/soc/s3c24xx/s3c2412-i2s.c
@@ -34,7 +34,6 @@
#include <plat/regs-s3c2412-iis.h>
-#include <plat/audio.h>
#include <mach/regs-gpio.h>
#include <mach/dma.h>
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c
index fc1beb0930b9..b25e9f968df9 100644
--- a/sound/soc/s3c24xx/s3c2443-ac97.c
+++ b/sound/soc/s3c24xx/s3c2443-ac97.c
@@ -32,7 +32,6 @@
#include <plat/regs-ac97.h>
#include <mach/regs-gpio.h>
#include <mach/regs-clock.h>
-#include <plat/audio.h>
#include <asm/dma.h>
#include <mach/dma.h>
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c
index 40e2c4790f0d..c76b8bb214bc 100644
--- a/sound/soc/s3c24xx/s3c24xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c24xx-i2s.c
@@ -32,7 +32,7 @@
#include <mach/hardware.h>
#include <mach/regs-gpio.h>
#include <mach/regs-clock.h>
-#include <plat/audio.h>
+
#include <asm/dma.h>
#include <mach/dma.h>
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c
index 5cbbdc80fde3..27cf097c2b1d 100644
--- a/sound/soc/s3c24xx/s3c24xx-pcm.c
+++ b/sound/soc/s3c24xx/s3c24xx-pcm.c
@@ -29,7 +29,6 @@
#include <asm/dma.h>
#include <mach/hardware.h>
#include <mach/dma.h>
-#include <plat/audio.h>
#include "s3c24xx-pcm.h"
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c
index 3c06c401d0fb..b67eed59666a 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.c
@@ -31,7 +31,6 @@
#include <plat/gpio-bank-d.h>
#include <plat/gpio-bank-e.h>
#include <plat/gpio-cfg.h>
-#include <plat/audio.h>
#include <mach/map.h>
#include <mach/dma.h>
@@ -99,6 +98,19 @@ static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
iismod |= S3C64XX_IISMOD_IMS_SYSMUX;
break;
+ case S3C64XX_CLKSRC_CDCLK:
+ switch (dir) {
+ case SND_SOC_CLOCK_IN:
+ iismod |= S3C64XX_IISMOD_CDCLKCON;
+ break;
+ case SND_SOC_CLOCK_OUT:
+ iismod &= ~S3C64XX_IISMOD_CDCLKCON;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
default:
return -EINVAL;
}
@@ -111,8 +123,12 @@ static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai)
{
struct s3c_i2sv2_info *i2s = to_info(dai);
+ u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
- return i2s->iis_cclk;
+ if (iismod & S3C64XX_IISMOD_IMS_SYSMUX)
+ return i2s->iis_cclk;
+ else
+ return i2s->iis_pclk;
}
EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock);
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h
index 02148cee2613..abe7253b55fc 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.h
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.h
@@ -25,6 +25,7 @@ struct clk;
#define S3C64XX_CLKSRC_PCLK (0)
#define S3C64XX_CLKSRC_MUX (1)
+#define S3C64XX_CLKSRC_CDCLK (2)
extern struct snd_soc_dai s3c64xx_i2s_dai[];
diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c
new file mode 100644
index 000000000000..482aaf10eff6
--- /dev/null
+++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c
@@ -0,0 +1,273 @@
+/*
+ * smdk64xx_wm8580.c
+ *
+ * Copyright (c) 2009 Samsung Electronics Co. Ltd
+ * Author: Jaswinder Singh <jassi.brar@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/platform_device.h>
+#include <linux/clk.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "../codecs/wm8580.h"
+#include "s3c24xx-pcm.h"
+#include "s3c64xx-i2s.h"
+
+#define S3C64XX_I2S_V4 2
+
+/* SMDK64XX has a 12MHZ crystal attached to WM8580 */
+#define SMDK64XX_WM8580_FREQ 12000000
+
+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;
+ unsigned int pll_out;
+ int bfs, rfs, ret;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_U8:
+ case SNDRV_PCM_FORMAT_S8:
+ bfs = 16;
+ break;
+ case SNDRV_PCM_FORMAT_U16_LE:
+ case SNDRV_PCM_FORMAT_S16_LE:
+ bfs = 32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* The Fvco for WM8580 PLLs must fall within [90,100]MHz.
+ * This criterion can't be met if we request PLL output
+ * as {8000x256, 64000x256, 11025x256}Hz.
+ * As a wayout, we rather change rfs to a minimum value that
+ * results in (params_rate(params) * rfs), and itself, acceptable
+ * to both - the CODEC and the CPU.
+ */
+ switch (params_rate(params)) {
+ case 16000:
+ case 22050:
+ case 32000:
+ case 44100:
+ case 48000:
+ case 88200:
+ case 96000:
+ rfs = 256;
+ break;
+ case 64000:
+ rfs = 384;
+ break;
+ case 8000:
+ case 11025:
+ rfs = 512;
+ break;
+ default:
+ return -EINVAL;
+ }
+ pll_out = params_rate(params) * rfs;
+
+ /* Set the 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 AP 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;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_CDCLK,
+ 0, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* We use PCLK for basic ops in SoC-Slave mode */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK,
+ 0, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* Set WM8580 to drive MCLK from it's PLLA */
+ ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
+ WM8580_CLKSRC_PLLA);
+ 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);
+ if (ret < 0)
+ return ret;
+
+ /* Assuming the CODEC driver evaluates it's rfs too from this call */
+ ret = snd_soc_dai_set_pll(codec_dai, 0, WM8580_PLLA,
+ SMDK64XX_WM8580_FREQ, pll_out);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_BCLK, bfs);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_RCLK, rfs);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/*
+ * SMDK64XX WM8580 DAI operations.
+ */
+static struct snd_soc_ops smdk64xx_ops = {
+ .hw_params = smdk64xx_hw_params,
+};
+
+/* 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),
+};
+
+/* SMDK64xx Capture widgets */
+static const struct snd_soc_dapm_widget wm8580_dapm_widgets_cpt[] = {
+ SND_SOC_DAPM_MIC("MicIn", NULL),
+ SND_SOC_DAPM_LINE("LineIn", NULL),
+};
+
+/* SMDK-PAIFTX connections */
+static const struct snd_soc_dapm_route audio_map_tx[] = {
+ /* MicIn feeds AINL */
+ {"AINL", NULL, "MicIn"},
+
+ /* LineIn feeds AINL/R */
+ {"AINL", NULL, "LineIn"},
+ {"AINR", NULL, "LineIn"},
+};
+
+/* 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"},
+
+ /* Center/Sub are fed VOUT2L/R */
+ {"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"},
+};
+
+static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec)
+{
+ /* Add smdk64xx specific Capture widgets */
+ snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_cpt,
+ ARRAY_SIZE(wm8580_dapm_widgets_cpt));
+
+ /* Set up PAIFTX audio path */
+ snd_soc_dapm_add_routes(codec, audio_map_tx, ARRAY_SIZE(audio_map_tx));
+
+ /* All enabled by default */
+ snd_soc_dapm_enable_pin(codec, "MicIn");
+ snd_soc_dapm_enable_pin(codec, "LineIn");
+
+ /* signal a DAPM event */
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+static int smdk64xx_wm8580_init_paifrx(struct snd_soc_codec *codec)
+{
+ /* Add smdk64xx specific Playback widgets */
+ snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_pbk,
+ ARRAY_SIZE(wm8580_dapm_widgets_pbk));
+
+ /* Set up PAIFRX audio path */
+ snd_soc_dapm_add_routes(codec, audio_map_rx, ARRAY_SIZE(audio_map_rx));
+
+ /* All enabled by default */
+ snd_soc_dapm_enable_pin(codec, "Front-L/R");
+ snd_soc_dapm_enable_pin(codec, "Center/Sub");
+ snd_soc_dapm_enable_pin(codec, "Rear-L/R");
+
+ /* signal a DAPM event */
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+static struct snd_soc_dai_link smdk64xx_dai[] = {
+{ /* Primary Playback i/f */
+ .name = "WM8580 PAIF RX",
+ .stream_name = "Playback",
+ .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4],
+ .codec_dai = &wm8580_dai[WM8580_DAI_PAIFRX],
+ .init = smdk64xx_wm8580_init_paifrx,
+ .ops = &smdk64xx_ops,
+},
+{ /* Primary Capture i/f */
+ .name = "WM8580 PAIF TX",
+ .stream_name = "Capture",
+ .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4],
+ .codec_dai = &wm8580_dai[WM8580_DAI_PAIFTX],
+ .init = smdk64xx_wm8580_init_paiftx,
+ .ops = &smdk64xx_ops,
+},
+};
+
+static struct snd_soc_card smdk64xx = {
+ .name = "smdk64xx",
+ .platform = &s3c24xx_soc_platform,
+ .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)
+{
+ int ret;
+
+ smdk64xx_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!smdk64xx_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(smdk64xx_snd_device, &smdk64xx_snd_devdata);
+ smdk64xx_snd_devdata.dev = &smdk64xx_snd_device->dev;
+ ret = platform_device_add(smdk64xx_snd_device);
+
+ if (ret)
+ platform_device_put(smdk64xx_snd_device);
+
+ return ret;
+}
+module_init(smdk64xx_audio_init);
+
+MODULE_AUTHOR("Jaswinder Singh, jassi.brar@samsung.com");
+MODULE_DESCRIPTION("ALSA SoC SMDK64XX WM8580");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index c8ceddc2a26c..d2505e8b06c9 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -77,6 +77,35 @@ static int snd_soc_7_9_spi_write(void *control_data, const char *data,
#define snd_soc_7_9_spi_write NULL
#endif
+static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ u8 *cache = codec->reg_cache;
+ u8 data[2];
+
+ BUG_ON(codec->volatile_register);
+
+ data[0] = reg & 0xff;
+ data[1] = value & 0xff;
+
+ if (reg < codec->reg_cache_size)
+ cache[reg] = value;
+
+ if (codec->hw_write(codec->control_data, data, 2) == 2)
+ return 0;
+ else
+ return -EIO;
+}
+
+static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ u8 *cache = codec->reg_cache;
+ if (reg >= codec->reg_cache_size)
+ return -1;
+ return cache[reg];
+}
+
static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
@@ -150,9 +179,20 @@ static struct {
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
} io_types[] = {
- { 7, 9, snd_soc_7_9_write, snd_soc_7_9_spi_write, snd_soc_7_9_read },
- { 8, 16, snd_soc_8_16_write, NULL, snd_soc_8_16_read,
- snd_soc_8_16_read_i2c },
+ {
+ .addr_bits = 7, .data_bits = 9,
+ .write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
+ .spi_write = snd_soc_7_9_spi_write
+ },
+ {
+ .addr_bits = 8, .data_bits = 8,
+ .write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
+ },
+ {
+ .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,
+ },
};
/**
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 7ff04ad2a97e..fa0da3cac705 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -790,45 +790,6 @@ static int soc_resume(struct device *dev)
return 0;
}
-
-/**
- * snd_soc_suspend_device: Notify core of device suspend
- *
- * @dev: Device being suspended.
- *
- * In order to ensure that the entire audio subsystem is suspended in a
- * coordinated fashion ASoC devices should suspend themselves when
- * called by ASoC. When the standard kernel suspend process asks the
- * device to suspend it should call this function to initiate a suspend
- * of the entire ASoC card.
- *
- * \note Currently this function is stubbed out.
- */
-int snd_soc_suspend_device(struct device *dev)
-{
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_suspend_device);
-
-/**
- * snd_soc_resume_device: Notify core of device resume
- *
- * @dev: Device being resumed.
- *
- * In order to ensure that the entire audio subsystem is resumed in a
- * coordinated fashion ASoC devices should resume themselves when called
- * by ASoC. When the standard kernel resume process asks the device
- * to resume it should call this function. Once all the components of
- * the card have notified that they are ready to be resumed the card
- * will be resumed.
- *
- * \note Currently this function is stubbed out.
- */
-int snd_soc_resume_device(struct device *dev)
-{
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_resume_device);
#else
#define soc_suspend NULL
#define soc_resume NULL
@@ -1254,21 +1215,39 @@ 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,
+ debugfs_root);
+ if (!codec->debugfs_codec_root) {
+ printk(KERN_WARNING
+ "ASoC: Failed to create codec debugfs directory\n");
+ return;
+ }
+
codec->debugfs_reg = debugfs_create_file("codec_reg", 0644,
- debugfs_root, codec,
- &codec_reg_fops);
+ codec->debugfs_codec_root,
+ codec, &codec_reg_fops);
if (!codec->debugfs_reg)
printk(KERN_WARNING
"ASoC: Failed to create codec register debugfs file\n");
codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0744,
- debugfs_root,
+ codec->debugfs_codec_root,
&codec->pop_time);
if (!codec->debugfs_pop_time)
printk(KERN_WARNING
"Failed to create pop time debugfs file\n");
- codec->debugfs_dapm = debugfs_create_dir("dapm", debugfs_root);
+ codec->debugfs_dapm = debugfs_create_dir("dapm",
+ codec->debugfs_codec_root);
if (!codec->debugfs_dapm)
printk(KERN_WARNING
"Failed to create DAPM debugfs directory\n");
@@ -1278,9 +1257,7 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
{
- debugfs_remove_recursive(codec->debugfs_dapm);
- debugfs_remove(codec->debugfs_pop_time);
- debugfs_remove(codec->debugfs_reg);
+ debugfs_remove_recursive(codec->debugfs_codec_root);
}
#else
@@ -2197,16 +2174,18 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
* snd_soc_dai_set_pll - configure DAI PLL.
* @dai: DAI
* @pll_id: DAI specific PLL ID
+ * @source: DAI specific source for the PLL
* @freq_in: PLL input clock frequency in Hz
* @freq_out: requested PLL output clock frequency in Hz
*
* Configures and enables PLL to generate output clock based on input clock.
*/
-int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
- int pll_id, unsigned int freq_in, unsigned int freq_out)
+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, freq_in, freq_out);
+ return dai->ops->set_pll(dai, pll_id, source,
+ freq_in, freq_out);
else
return -EINVAL;
}
@@ -2251,6 +2230,30 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
/**
+ * snd_soc_dai_set_channel_map - configure DAI audio channel map
+ * @dai: DAI
+ * @tx_num: how many TX channels
+ * @tx_slot: pointer to an array which imply the TX slot number channel
+ * 0~num-1 uses
+ * @rx_num: how many RX channels
+ * @rx_slot: pointer to an array which imply the RX slot number channel
+ * 0~num-1 uses
+ *
+ * configure the relationship between channel number and TDM slot number.
+ */
+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,
+ rx_num, rx_slot);
+ else
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
+
+/**
* snd_soc_dai_set_tristate - configure DAI system or master clock.
* @dai: DAI
* @tristate: tristate enable
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 8de6f9dec4a2..eaadb4b742f4 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -719,6 +719,10 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
/* Check if one of our outputs is connected */
list_for_each_entry(path, &w->sinks, list_source) {
+ if (path->connected &&
+ !path->connected(path->source, path->sink))
+ continue;
+
if (path->sink && path->sink->power_check &&
path->sink->power_check(path->sink)) {
power = 1;
@@ -1138,6 +1142,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
w->active ? "active" : "inactive");
list_for_each_entry(p, &w->sources, list_sink) {
+ if (p->connected && !p->connected(w, p->sink))
+ continue;
+
if (p->connect)
ret += snprintf(buf + ret, PAGE_SIZE - ret,
" in %s %s\n",
@@ -1145,6 +1152,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
p->source->name);
}
list_for_each_entry(p, &w->sinks, list_source) {
+ if (p->connected && !p->connected(w, p->sink))
+ continue;
+
if (p->connect)
ret += snprintf(buf + ret, PAGE_SIZE - ret,
" out %s %s\n",
@@ -1192,8 +1202,8 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec)
/* test and update the power status of a mux widget */
static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
- struct snd_kcontrol *kcontrol, int mask,
- int mux, int val, struct soc_enum *e)
+ struct snd_kcontrol *kcontrol, int change,
+ int mux, struct soc_enum *e)
{
struct snd_soc_dapm_path *path;
int found = 0;
@@ -1202,7 +1212,7 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
widget->id != snd_soc_dapm_value_mux)
return -ENODEV;
- if (!snd_soc_test_bits(widget->codec, e->reg, mask, val))
+ if (!change)
return 0;
/* find dapm widget path assoc with kcontrol */
@@ -1387,10 +1397,13 @@ int snd_soc_dapm_sync(struct snd_soc_codec *codec)
EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
- const char *sink, const char *control, const char *source)
+ const struct snd_soc_dapm_route *route)
{
struct snd_soc_dapm_path *path;
struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
+ const char *sink = route->sink;
+ const char *control = route->control;
+ const char *source = route->source;
int ret = 0;
/* find src and dest widgets */
@@ -1414,6 +1427,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
path->source = wsource;
path->sink = wsink;
+ path->connected = route->connected;
INIT_LIST_HEAD(&path->list);
INIT_LIST_HEAD(&path->list_source);
INIT_LIST_HEAD(&path->list_sink);
@@ -1514,8 +1528,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
int i, ret;
for (i = 0; i < num; i++) {
- ret = snd_soc_dapm_add_route(codec, route->sink,
- route->control, route->source);
+ ret = snd_soc_dapm_add_route(codec, route);
if (ret < 0) {
printk(KERN_ERR "Failed to add route %s->%s\n",
route->source,
@@ -1752,7 +1765,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
{
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned int val, mux;
+ unsigned int val, mux, change;
unsigned int mask, bitmask;
int ret = 0;
@@ -1772,20 +1785,21 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
mutex_lock(&widget->codec->mutex);
widget->value = val;
- dapm_mux_update_power(widget, kcontrol, mask, mux, val, e);
- if (widget->event) {
- if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
- ret = widget->event(widget,
- kcontrol, SND_SOC_DAPM_PRE_REG);
- if (ret < 0)
- goto out;
- }
- ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
- if (widget->event_flags & SND_SOC_DAPM_POST_REG)
- ret = widget->event(widget,
- kcontrol, SND_SOC_DAPM_POST_REG);
- } else
- ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
+ change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
+ dapm_mux_update_power(widget, kcontrol, change, mux, e);
+
+ if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
+ ret = widget->event(widget,
+ kcontrol, SND_SOC_DAPM_PRE_REG);
+ if (ret < 0)
+ goto out;
+ }
+
+ ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
+
+ if (widget->event_flags & SND_SOC_DAPM_POST_REG)
+ ret = widget->event(widget,
+ kcontrol, SND_SOC_DAPM_POST_REG);
out:
mutex_unlock(&widget->codec->mutex);
@@ -1794,6 +1808,54 @@ out:
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
/**
+ * snd_soc_dapm_get_enum_virt - Get virtual DAPM mux
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = widget->value;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);
+
+/**
+ * snd_soc_dapm_put_enum_virt - Set virtual DAPM mux
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+ struct soc_enum *e =
+ (struct soc_enum *)kcontrol->private_value;
+ int change;
+ int ret = 0;
+
+ if (ucontrol->value.enumerated.item[0] >= e->max)
+ return -EINVAL;
+
+ mutex_lock(&widget->codec->mutex);
+
+ change = widget->value != ucontrol->value.enumerated.item[0];
+ widget->value = ucontrol->value.enumerated.item[0];
+ dapm_mux_update_power(widget, kcontrol, change, widget->value, e);
+
+ mutex_unlock(&widget->codec->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
+
+/**
* snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get
* callback
* @kcontrol: mixer control
@@ -1851,7 +1913,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
{
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned int val, mux;
+ unsigned int val, mux, change;
unsigned int mask;
int ret = 0;
@@ -1869,20 +1931,21 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
mutex_lock(&widget->codec->mutex);
widget->value = val;
- dapm_mux_update_power(widget, kcontrol, mask, mux, val, e);
- if (widget->event) {
- if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
- ret = widget->event(widget,
- kcontrol, SND_SOC_DAPM_PRE_REG);
- if (ret < 0)
- goto out;
- }
- ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
- if (widget->event_flags & SND_SOC_DAPM_POST_REG)
- ret = widget->event(widget,
- kcontrol, SND_SOC_DAPM_POST_REG);
- } else
- ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
+ change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
+ dapm_mux_update_power(widget, kcontrol, change, mux, e);
+
+ if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
+ ret = widget->event(widget,
+ kcontrol, SND_SOC_DAPM_PRE_REG);
+ if (ret < 0)
+ goto out;
+ }
+
+ ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
+
+ if (widget->event_flags & SND_SOC_DAPM_POST_REG)
+ ret = widget->event(widget,
+ kcontrol, SND_SOC_DAPM_POST_REG);
out:
mutex_unlock(&widget->codec->mutex);
@@ -2072,9 +2135,9 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
}
}
}
- mutex_unlock(&codec->mutex);
dapm_power_widgets(codec, event);
+ mutex_unlock(&codec->mutex);
dump_dapm(codec, __func__);
return 0;
}
diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c
index 99f33766cd51..00cd54c236b4 100644
--- a/sound/usb/usx2y/us122l.c
+++ b/sound/usb/usx2y/us122l.c
@@ -66,6 +66,28 @@ static int us122l_create_usbmidi(struct snd_card *card)
iface, &quirk);
}
+static int us144_create_usbmidi(struct snd_card *card)
+{
+ static struct snd_usb_midi_endpoint_info quirk_data = {
+ .out_ep = 4,
+ .in_ep = 3,
+ .out_cables = 0x001,
+ .in_cables = 0x001
+ };
+ static struct snd_usb_audio_quirk quirk = {
+ .vendor_name = "US144",
+ .product_name = NAME_ALLCAPS,
+ .ifnum = 0,
+ .type = QUIRK_MIDI_US122L,
+ .data = &quirk_data
+ };
+ struct usb_device *dev = US122L(card)->chip.dev;
+ struct usb_interface *iface = usb_ifnum_to_if(dev, 0);
+
+ return snd_usb_create_midi_interface(&US122L(card)->chip,
+ iface, &quirk);
+}
+
/*
* Wrapper for usb_control_msg().
* Allocates a temp buffer to prevent dmaing from/to the stack.
@@ -171,6 +193,11 @@ static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file)
if (!us122l->first)
us122l->first = file;
+
+ if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) {
+ iface = usb_ifnum_to_if(us122l->chip.dev, 0);
+ usb_autopm_get_interface(iface);
+ }
iface = usb_ifnum_to_if(us122l->chip.dev, 1);
usb_autopm_get_interface(iface);
return 0;
@@ -179,8 +206,14 @@ static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file)
static int usb_stream_hwdep_release(struct snd_hwdep *hw, struct file *file)
{
struct us122l *us122l = hw->private_data;
- struct usb_interface *iface = usb_ifnum_to_if(us122l->chip.dev, 1);
+ struct usb_interface *iface;
snd_printdd(KERN_DEBUG "%p %p\n", hw, file);
+
+ if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) {
+ iface = usb_ifnum_to_if(us122l->chip.dev, 0);
+ usb_autopm_put_interface(iface);
+ }
+ iface = usb_ifnum_to_if(us122l->chip.dev, 1);
usb_autopm_put_interface(iface);
if (us122l->first == file)
us122l->first = NULL;
@@ -443,6 +476,13 @@ static bool us122l_create_card(struct snd_card *card)
int err;
struct us122l *us122l = US122L(card);
+ if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) {
+ err = usb_set_interface(us122l->chip.dev, 0, 1);
+ if (err) {
+ snd_printk(KERN_ERR "usb_set_interface error \n");
+ return false;
+ }
+ }
err = usb_set_interface(us122l->chip.dev, 1, 1);
if (err) {
snd_printk(KERN_ERR "usb_set_interface error \n");
@@ -455,7 +495,10 @@ static bool us122l_create_card(struct snd_card *card)
if (!us122l_start(us122l, 44100, 256))
return false;
- err = us122l_create_usbmidi(card);
+ if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144)
+ err = us144_create_usbmidi(card);
+ else
+ err = us122l_create_usbmidi(card);
if (err < 0) {
snd_printk(KERN_ERR "us122l_create_usbmidi error %i \n", err);
us122l_stop(us122l);
@@ -542,6 +585,7 @@ static int us122l_usb_probe(struct usb_interface *intf,
return err;
}
+ usb_get_intf(usb_ifnum_to_if(device, 0));
usb_get_dev(device);
*cardp = card;
return 0;
@@ -550,9 +594,16 @@ static int us122l_usb_probe(struct usb_interface *intf,
static int snd_us122l_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
+ struct usb_device *device = interface_to_usbdev(intf);
struct snd_card *card;
int err;
+ if (device->descriptor.idProduct == USB_ID_US144
+ && device->speed == USB_SPEED_HIGH) {
+ snd_printk(KERN_ERR "disable ehci-hcd to run US-144 \n");
+ return -ENODEV;
+ }
+
snd_printdd(KERN_DEBUG"%p:%i\n",
intf, intf->cur_altsetting->desc.bInterfaceNumber);
if (intf->cur_altsetting->desc.bInterfaceNumber != 1)
@@ -591,7 +642,8 @@ static void snd_us122l_disconnect(struct usb_interface *intf)
snd_usbmidi_disconnect(p);
}
- usb_put_intf(intf);
+ usb_put_intf(usb_ifnum_to_if(us122l->chip.dev, 0));
+ usb_put_intf(usb_ifnum_to_if(us122l->chip.dev, 1));
usb_put_dev(us122l->chip.dev);
while (atomic_read(&us122l->mmap_count))
@@ -642,6 +694,13 @@ static int snd_us122l_resume(struct usb_interface *intf)
mutex_lock(&us122l->mutex);
/* needed, doesn't restart without: */
+ if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) {
+ err = usb_set_interface(us122l->chip.dev, 0, 1);
+ if (err) {
+ snd_printk(KERN_ERR "usb_set_interface error \n");
+ goto unlock;
+ }
+ }
err = usb_set_interface(us122l->chip.dev, 1, 1);
if (err) {
snd_printk(KERN_ERR "usb_set_interface error \n");
@@ -675,11 +734,11 @@ static struct usb_device_id snd_us122l_usb_id_table[] = {
.idVendor = 0x0644,
.idProduct = USB_ID_US122L
},
-/* { */ /* US-144 maybe works when @USB1.1. Untested. */
-/* .match_flags = USB_DEVICE_ID_MATCH_DEVICE, */
-/* .idVendor = 0x0644, */
-/* .idProduct = USB_ID_US144 */
-/* }, */
+ { /* US-144 only works at USB1.1! Disable module ehci-hcd. */
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+ .idVendor = 0x0644,
+ .idProduct = USB_ID_US144
+ },
{ /* terminator */ }
};
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
new file mode 100644
index 000000000000..6b6c6aecdf1d
--- /dev/null
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -0,0 +1,48 @@
+perf-probe(1)
+=============
+
+NAME
+----
+perf-probe - Define new dynamic tracepoints
+
+SYNOPSIS
+--------
+[verse]
+'perf probe' [-k <file>] -P 'PROBE' [-P 'PROBE' ...]
+
+
+DESCRIPTION
+-----------
+This command defines dynamic tracepoint events, by symbol and registers
+without debuginfo, or by C expressions (C line numbers, C function names,
+and C local variables) with debuginfo.
+
+
+OPTIONS
+-------
+-k::
+--vmlinux::
+ Specify vmlinux path which has debuginfo (Dwarf binary).
+
+-v::
+--verbose::
+ Be more verbose (show parsed arguments, etc).
+
+-P::
+--probe::
+ Define a probe point (see PROBE SYNTAX for detail)
+
+PROBE SYNTAX
+------------
+Probe points are defined by following syntax.
+
+ "TYPE:[GRP/]NAME FUNC[+OFFS][@SRC]|@SRC:LINE [ARG ...]"
+
+'TYPE' specifies the type of probe point, you can use either "p" (kprobe) or "r" (kretprobe) for 'TYPE'. 'GRP' specifies the group name of this probe, and 'NAME' specifies the event name. If 'GRP' is omitted, "kprobes" is used for its group name.
+'FUNC' and 'OFFS' specifies function and offset (in byte) where probe will be put. In addition, 'SRC' specifies a source file which has that function (this is mainly for inline functions).
+You can specify a probe point by the source line number by using '@SRC:LINE' syntax, where 'SRC' is the source file path and 'LINE' is the line number.
+'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc).
+
+SEE ALSO
+--------
+linkperf:perf-trace[1], linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index a7910099d6fd..4b1788355eca 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -31,9 +31,12 @@ OPTIONS
-w::
--width=::
Select the width of the SVG file (default: 1000)
--p::
+-P::
--power-only::
Only output the CPU power section of the diagram
+-p::
+--process::
+ Select the processes to display, by name or PID
SEE ALSO
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 742a32eee8fc..800783db10e1 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -177,8 +177,7 @@ endif
# Include saner warnings here, which can catch bugs:
#
-EXTRA_WARNINGS := -Wcast-align
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat
+EXTRA_WARNINGS := -Wformat
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-security
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-y2k
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow
@@ -201,7 +200,14 @@ EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement
-CFLAGS = $(MBITS) -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -fstack-protector-all -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS)
+ifeq ("$(origin DEBUG)", "command line")
+ PERF_DEBUG = $(DEBUG)
+endif
+ifndef PERF_DEBUG
+ CFLAGS_OPTIMIZE = -O6
+endif
+
+CFLAGS = $(MBITS) -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -fstack-protector-all -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS)
LDFLAGS = -lpthread -lrt -lelf -lm
ALL_CFLAGS = $(CFLAGS)
ALL_LDFLAGS = $(LDFLAGS)
@@ -328,8 +334,27 @@ LIB_FILE=libperf.a
LIB_H += ../../include/linux/perf_event.h
LIB_H += ../../include/linux/rbtree.h
LIB_H += ../../include/linux/list.h
+LIB_H += ../../include/linux/stringify.h
+LIB_H += util/include/linux/bitmap.h
+LIB_H += util/include/linux/bitops.h
+LIB_H += util/include/linux/compiler.h
+LIB_H += util/include/linux/ctype.h
+LIB_H += util/include/linux/kernel.h
LIB_H += util/include/linux/list.h
+LIB_H += util/include/linux/module.h
+LIB_H += util/include/linux/poison.h
+LIB_H += util/include/linux/prefetch.h
+LIB_H += util/include/linux/rbtree.h
+LIB_H += util/include/linux/string.h
+LIB_H += util/include/linux/types.h
+LIB_H += util/include/asm/asm-offsets.h
+LIB_H += util/include/asm/bitops.h
+LIB_H += util/include/asm/byteorder.h
+LIB_H += util/include/asm/swab.h
+LIB_H += util/include/asm/system.h
+LIB_H += util/include/asm/uaccess.h
LIB_H += perf.h
+LIB_H += util/event.h
LIB_H += util/types.h
LIB_H += util/levenshtein.h
LIB_H += util/parse-options.h
@@ -343,15 +368,19 @@ LIB_H += util/strlist.h
LIB_H += util/run-command.h
LIB_H += util/sigchain.h
LIB_H += util/symbol.h
-LIB_H += util/module.h
LIB_H += util/color.h
LIB_H += util/values.h
+LIB_H += util/sort.h
+LIB_H += util/hist.h
+LIB_H += util/thread.h
+LIB_H += util/data_map.h
LIB_OBJS += util/abspath.o
LIB_OBJS += util/alias.o
LIB_OBJS += util/config.o
LIB_OBJS += util/ctype.o
LIB_OBJS += util/environment.o
+LIB_OBJS += util/event.o
LIB_OBJS += util/exec_cmd.o
LIB_OBJS += util/help.o
LIB_OBJS += util/levenshtein.o
@@ -359,6 +388,9 @@ LIB_OBJS += util/parse-options.o
LIB_OBJS += util/parse-events.o
LIB_OBJS += util/path.o
LIB_OBJS += util/rbtree.o
+LIB_OBJS += util/bitmap.o
+LIB_OBJS += util/hweight.o
+LIB_OBJS += util/find_next_bit.o
LIB_OBJS += util/run-command.o
LIB_OBJS += util/quote.o
LIB_OBJS += util/strbuf.o
@@ -368,7 +400,6 @@ LIB_OBJS += util/usage.o
LIB_OBJS += util/wrapper.o
LIB_OBJS += util/sigchain.o
LIB_OBJS += util/symbol.o
-LIB_OBJS += util/module.o
LIB_OBJS += util/color.o
LIB_OBJS += util/pager.o
LIB_OBJS += util/header.o
@@ -381,6 +412,9 @@ LIB_OBJS += util/trace-event-parse.o
LIB_OBJS += util/trace-event-read.o
LIB_OBJS += util/trace-event-info.o
LIB_OBJS += util/svghelper.o
+LIB_OBJS += util/sort.o
+LIB_OBJS += util/hist.o
+LIB_OBJS += util/data_map.o
BUILTIN_OBJS += builtin-annotate.o
BUILTIN_OBJS += builtin-help.o
@@ -392,6 +426,7 @@ BUILTIN_OBJS += builtin-stat.o
BUILTIN_OBJS += builtin-timechart.o
BUILTIN_OBJS += builtin-top.o
BUILTIN_OBJS += builtin-trace.o
+BUILTIN_OBJS += builtin-probe.o
PERFLIBS = $(LIB_FILE)
@@ -422,8 +457,25 @@ ifeq ($(uname_S),Darwin)
PTHREAD_LIBS =
endif
-ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y)
- msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
+ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y)
+ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y)
+ msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]);
+endif
+
+ ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y)
+ BASIC_CFLAGS += -DLIBELF_NO_MMAP
+ endif
+else
+ msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel);
+endif
+
+ifneq ($(shell sh -c "(echo '\#include <libdwarf/dwarf.h>'; echo '\#include <libdwarf/libdwarf.h>'; echo 'int main(void) { Dwarf_Debug dbg; Dwarf_Error err; Dwarf_Ranges *rng; dwarf_init(0, DW_DLC_READ, 0, 0, &dbg, &err); dwarf_get_ranges(dbg, 0, &rng, 0, 0, &err); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -ldwarf -lelf -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y)
+ msg := $(warning No libdwarf.h found or old libdwarf.h found, disables dwarf support. Please install libdwarf-dev/libdwarf-devel >= 20081231);
+ BASIC_CFLAGS += -DNO_LIBDWARF
+else
+ EXTLIBS += -lelf -ldwarf
+ LIB_H += util/probe-finder.h
+ LIB_OBJS += util/probe-finder.o
endif
ifdef NO_DEMANGLE
@@ -784,6 +836,19 @@ util/config.o: util/config.c PERF-CFLAGS
util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS
$(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
+# some perf warning policies can't fit to lib/bitmap.c, eg: it warns about variable shadowing
+# from <string.h> that comes from kernel headers wrapping.
+KBITMAP_FLAGS=`echo $(ALL_CFLAGS) | sed s/-Wshadow// | sed s/-Wswitch-default// | sed s/-Wextra//`
+
+util/bitmap.o: ../../lib/bitmap.c PERF-CFLAGS
+ $(QUIET_CC)$(CC) -o util/bitmap.o -c $(KBITMAP_FLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
+
+util/hweight.o: ../../lib/hweight.c PERF-CFLAGS
+ $(QUIET_CC)$(CC) -o util/hweight.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
+
+util/find_next_bit.o: ../../lib/find_next_bit.c PERF-CFLAGS
+ $(QUIET_CC)$(CC) -o util/find_next_bit.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
+
perf-%$X: %.o $(PERFLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 1ec741615814..6d63c2eea2c7 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -22,15 +22,13 @@
#include "util/parse-options.h"
#include "util/parse-events.h"
#include "util/thread.h"
+#include "util/sort.h"
+#include "util/hist.h"
static char const *input_name = "perf.data";
-static char default_sort_order[] = "comm,symbol";
-static char *sort_order = default_sort_order;
-
static int force;
static int input;
-static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
static int full_paths;
@@ -39,9 +37,10 @@ static int print_line;
static unsigned long page_size;
static unsigned long mmap_window = 32;
-static struct rb_root threads;
-static struct thread *last_match;
-
+struct sym_hist {
+ u64 sum;
+ u64 ip[0];
+};
struct sym_ext {
struct rb_node node;
@@ -49,247 +48,33 @@ struct sym_ext {
char *path;
};
-/*
- * histogram, sorted on item, collects counts
- */
-
-static struct rb_root hist;
-
-struct hist_entry {
- struct rb_node rb_node;
-
- struct thread *thread;
- struct map *map;
- struct dso *dso;
- struct symbol *sym;
- u64 ip;
- char level;
-
- uint32_t count;
-};
-
-/*
- * configurable sorting bits
- */
-
-struct sort_entry {
- struct list_head list;
-
- const char *header;
-
- int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
- int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
- size_t (*print)(FILE *fp, struct hist_entry *);
-};
-
-/* --sort pid */
-
-static int64_t
-sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
-{
- return right->thread->pid - left->thread->pid;
-}
-
-static size_t
-sort__thread_print(FILE *fp, struct hist_entry *self)
-{
- return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid);
-}
-
-static struct sort_entry sort_thread = {
- .header = " Command: Pid",
- .cmp = sort__thread_cmp,
- .print = sort__thread_print,
-};
-
-/* --sort comm */
-
-static int64_t
-sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
-{
- return right->thread->pid - left->thread->pid;
-}
-
-static int64_t
-sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
-{
- char *comm_l = left->thread->comm;
- char *comm_r = right->thread->comm;
-
- if (!comm_l || !comm_r) {
- if (!comm_l && !comm_r)
- return 0;
- else if (!comm_l)
- return -1;
- else
- return 1;
- }
-
- return strcmp(comm_l, comm_r);
-}
-
-static size_t
-sort__comm_print(FILE *fp, struct hist_entry *self)
-{
- return fprintf(fp, "%16s", self->thread->comm);
-}
-
-static struct sort_entry sort_comm = {
- .header = " Command",
- .cmp = sort__comm_cmp,
- .collapse = sort__comm_collapse,
- .print = sort__comm_print,
-};
-
-/* --sort dso */
-
-static int64_t
-sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
-{
- struct dso *dso_l = left->dso;
- struct dso *dso_r = right->dso;
-
- if (!dso_l || !dso_r) {
- if (!dso_l && !dso_r)
- return 0;
- else if (!dso_l)
- return -1;
- else
- return 1;
- }
-
- return strcmp(dso_l->name, dso_r->name);
-}
-
-static size_t
-sort__dso_print(FILE *fp, struct hist_entry *self)
-{
- if (self->dso)
- return fprintf(fp, "%-25s", self->dso->name);
-
- return fprintf(fp, "%016llx ", (u64)self->ip);
-}
-
-static struct sort_entry sort_dso = {
- .header = "Shared Object ",
- .cmp = sort__dso_cmp,
- .print = sort__dso_print,
-};
-
-/* --sort symbol */
-
-static int64_t
-sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
-{
- u64 ip_l, ip_r;
-
- if (left->sym == right->sym)
- return 0;
-
- ip_l = left->sym ? left->sym->start : left->ip;
- ip_r = right->sym ? right->sym->start : right->ip;
-
- return (int64_t)(ip_r - ip_l);
-}
-
-static size_t
-sort__sym_print(FILE *fp, struct hist_entry *self)
-{
- size_t ret = 0;
-
- if (verbose)
- ret += fprintf(fp, "%#018llx ", (u64)self->ip);
-
- if (self->sym) {
- ret += fprintf(fp, "[%c] %s",
- self->dso == kernel_dso ? 'k' : '.', self->sym->name);
- } else {
- ret += fprintf(fp, "%#016llx", (u64)self->ip);
- }
-
- return ret;
-}
-
-static struct sort_entry sort_sym = {
- .header = "Symbol",
- .cmp = sort__sym_cmp,
- .print = sort__sym_print,
-};
-
-static int sort__need_collapse = 0;
-
-struct sort_dimension {
- const char *name;
- struct sort_entry *entry;
- int taken;
-};
-
-static struct sort_dimension sort_dimensions[] = {
- { .name = "pid", .entry = &sort_thread, },
- { .name = "comm", .entry = &sort_comm, },
- { .name = "dso", .entry = &sort_dso, },
- { .name = "symbol", .entry = &sort_sym, },
+struct sym_priv {
+ struct sym_hist *hist;
+ struct sym_ext *ext;
};
-static LIST_HEAD(hist_entry__sort_list);
+static const char *sym_hist_filter;
-static int sort_dimension__add(char *tok)
+static int symbol_filter(struct map *map, struct symbol *sym)
{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
- struct sort_dimension *sd = &sort_dimensions[i];
-
- if (sd->taken)
- continue;
-
- if (strncasecmp(tok, sd->name, strlen(tok)))
- continue;
-
- if (sd->entry->collapse)
- sort__need_collapse = 1;
-
- list_add_tail(&sd->entry->list, &hist_entry__sort_list);
- sd->taken = 1;
+ if (sym_hist_filter == NULL ||
+ strcmp(sym->name, sym_hist_filter) == 0) {
+ struct sym_priv *priv = dso__sym_priv(map->dso, sym);
+ const int size = (sizeof(*priv->hist) +
+ (sym->end - sym->start) * sizeof(u64));
+ priv->hist = malloc(size);
+ if (priv->hist)
+ memset(priv->hist, 0, size);
return 0;
}
-
- return -ESRCH;
-}
-
-static int64_t
-hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
-{
- struct sort_entry *se;
- int64_t cmp = 0;
-
- list_for_each_entry(se, &hist_entry__sort_list, list) {
- cmp = se->cmp(left, right);
- if (cmp)
- break;
- }
-
- return cmp;
-}
-
-static int64_t
-hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
-{
- struct sort_entry *se;
- int64_t cmp = 0;
-
- list_for_each_entry(se, &hist_entry__sort_list, list) {
- int64_t (*f)(struct hist_entry *, struct hist_entry *);
-
- f = se->collapse ?: se->cmp;
-
- cmp = f(left, right);
- if (cmp)
- break;
- }
-
- return cmp;
+ /*
+ * FIXME: We should really filter it out, as we don't want to go thru symbols
+ * we're not interested, and if a DSO ends up with no symbols, delete it too,
+ * but right now the kernel loading routines in symbol.c bail out if no symbols
+ * are found, fix it later.
+ */
+ return 0;
}
/*
@@ -299,196 +84,60 @@ static void hist_hit(struct hist_entry *he, u64 ip)
{
unsigned int sym_size, offset;
struct symbol *sym = he->sym;
+ struct sym_priv *priv;
+ struct sym_hist *h;
he->count++;
- if (!sym || !sym->hist)
+ if (!sym || !he->map)
+ return;
+
+ priv = dso__sym_priv(he->map->dso, sym);
+ if (!priv->hist)
return;
sym_size = sym->end - sym->start;
offset = ip - sym->start;
+ if (verbose)
+ fprintf(stderr, "%s: ip=%Lx\n", __func__,
+ he->map->unmap_ip(he->map, ip));
+
if (offset >= sym_size)
return;
- sym->hist_sum++;
- sym->hist[offset]++;
+ h = priv->hist;
+ h->sum++;
+ h->ip[offset]++;
if (verbose >= 3)
printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n",
(void *)(unsigned long)he->sym->start,
he->sym->name,
(void *)(unsigned long)ip, ip - he->sym->start,
- sym->hist[offset]);
+ h->ip[offset]);
}
-static int
-hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
- struct symbol *sym, u64 ip, char level)
+static int hist_entry__add(struct thread *thread, struct map *map,
+ struct symbol *sym, u64 ip, u64 count, char level)
{
- struct rb_node **p = &hist.rb_node;
- struct rb_node *parent = NULL;
- struct hist_entry *he;
- struct hist_entry entry = {
- .thread = thread,
- .map = map,
- .dso = dso,
- .sym = sym,
- .ip = ip,
- .level = level,
- .count = 1,
- };
- int cmp;
-
- while (*p != NULL) {
- parent = *p;
- he = rb_entry(parent, struct hist_entry, rb_node);
-
- cmp = hist_entry__cmp(&entry, he);
-
- if (!cmp) {
- hist_hit(he, ip);
-
- return 0;
- }
-
- if (cmp < 0)
- p = &(*p)->rb_left;
- else
- p = &(*p)->rb_right;
- }
-
- he = malloc(sizeof(*he));
- if (!he)
+ bool hit;
+ struct hist_entry *he = __hist_entry__add(thread, map, sym, NULL, ip,
+ count, level, &hit);
+ if (he == NULL)
return -ENOMEM;
- *he = entry;
- rb_link_node(&he->rb_node, parent, p);
- rb_insert_color(&he->rb_node, &hist);
-
+ hist_hit(he, ip);
return 0;
}
-static void hist_entry__free(struct hist_entry *he)
-{
- free(he);
-}
-
-/*
- * collapse the histogram
- */
-
-static struct rb_root collapse_hists;
-
-static void collapse__insert_entry(struct hist_entry *he)
-{
- struct rb_node **p = &collapse_hists.rb_node;
- struct rb_node *parent = NULL;
- struct hist_entry *iter;
- int64_t cmp;
-
- while (*p != NULL) {
- parent = *p;
- iter = rb_entry(parent, struct hist_entry, rb_node);
-
- cmp = hist_entry__collapse(iter, he);
-
- if (!cmp) {
- iter->count += he->count;
- hist_entry__free(he);
- return;
- }
-
- if (cmp < 0)
- p = &(*p)->rb_left;
- else
- p = &(*p)->rb_right;
- }
-
- rb_link_node(&he->rb_node, parent, p);
- rb_insert_color(&he->rb_node, &collapse_hists);
-}
-
-static void collapse__resort(void)
-{
- struct rb_node *next;
- struct hist_entry *n;
-
- if (!sort__need_collapse)
- return;
-
- next = rb_first(&hist);
- while (next) {
- n = rb_entry(next, struct hist_entry, rb_node);
- next = rb_next(&n->rb_node);
-
- rb_erase(&n->rb_node, &hist);
- collapse__insert_entry(n);
- }
-}
-
-/*
- * reverse the map, sort on count.
- */
-
-static struct rb_root output_hists;
-
-static void output__insert_entry(struct hist_entry *he)
-{
- struct rb_node **p = &output_hists.rb_node;
- struct rb_node *parent = NULL;
- struct hist_entry *iter;
-
- while (*p != NULL) {
- parent = *p;
- iter = rb_entry(parent, struct hist_entry, rb_node);
-
- if (he->count > iter->count)
- p = &(*p)->rb_left;
- else
- p = &(*p)->rb_right;
- }
-
- rb_link_node(&he->rb_node, parent, p);
- rb_insert_color(&he->rb_node, &output_hists);
-}
-
-static void output__resort(void)
-{
- struct rb_node *next;
- struct hist_entry *n;
- struct rb_root *tree = &hist;
-
- if (sort__need_collapse)
- tree = &collapse_hists;
-
- next = rb_first(tree);
-
- while (next) {
- n = rb_entry(next, struct hist_entry, rb_node);
- next = rb_next(&n->rb_node);
-
- rb_erase(&n->rb_node, tree);
- output__insert_entry(n);
- }
-}
-
-static unsigned long total = 0,
- total_mmap = 0,
- total_comm = 0,
- total_fork = 0,
- total_unknown = 0;
-
static int
process_sample_event(event_t *event, unsigned long offset, unsigned long head)
{
char level;
- int show = 0;
- struct dso *dso = NULL;
- struct thread *thread;
u64 ip = event->ip.ip;
struct map *map = NULL;
-
- thread = threads__findnew(event->ip.pid, &threads, &last_match);
+ struct symbol *sym = NULL;
+ struct thread *thread = threads__findnew(event->ip.pid);
dump_printf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
(void *)(offset + head),
@@ -497,60 +146,53 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
event->ip.pid,
(void *)(long)ip);
- dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
-
if (thread == NULL) {
fprintf(stderr, "problem processing %d event, skipping it.\n",
event->header.type);
return -1;
}
+ dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
+
if (event->header.misc & PERF_RECORD_MISC_KERNEL) {
- show = SHOW_KERNEL;
level = 'k';
-
- dso = kernel_dso;
-
- dump_printf(" ...... dso: %s\n", dso->name);
-
+ sym = kernel_maps__find_symbol(ip, &map);
+ dump_printf(" ...... dso: %s\n",
+ map ? map->dso->long_name : "<not found>");
} else if (event->header.misc & PERF_RECORD_MISC_USER) {
-
- show = SHOW_USER;
level = '.';
-
map = thread__find_map(thread, ip);
if (map != NULL) {
+got_map:
ip = map->map_ip(map, ip);
- dso = map->dso;
+ sym = map->dso->find_symbol(map->dso, ip);
} else {
/*
* If this is outside of all known maps,
* and is a negative address, try to look it
* up in the kernel dso, as it might be a
- * vsyscall (which executes in user-mode):
+ * vsyscall or vdso (which executes in user-mode).
+ *
+ * XXX This is nasty, we should have a symbol list in
+ * the "[vdso]" dso, but for now lets use the old
+ * trick of looking in the whole kernel symbol list.
*/
- if ((long long)ip < 0)
- dso = kernel_dso;
+ if ((long long)ip < 0) {
+ map = kernel_map;
+ goto got_map;
+ }
}
- dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
-
+ dump_printf(" ...... dso: %s\n",
+ map ? map->dso->long_name : "<not found>");
} else {
- show = SHOW_HV;
level = 'H';
dump_printf(" ...... dso: [hypervisor]\n");
}
- if (show & show_mask) {
- struct symbol *sym = NULL;
-
- if (dso)
- sym = dso->find_symbol(dso, ip);
-
- if (hist_entry__add(thread, map, dso, sym, ip, level)) {
- fprintf(stderr,
- "problem incrementing symbol count, skipping event\n");
- return -1;
- }
+ if (hist_entry__add(thread, map, sym, ip, 1, level)) {
+ fprintf(stderr, "problem incrementing symbol count, "
+ "skipping event\n");
+ return -1;
}
total++;
@@ -560,10 +202,9 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
static int
process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
{
- struct thread *thread;
- struct map *map = map__new(&event->mmap, NULL, 0);
-
- thread = threads__findnew(event->mmap.pid, &threads, &last_match);
+ struct map *map = map__new(&event->mmap, NULL, 0,
+ sizeof(struct sym_priv), symbol_filter);
+ struct thread *thread = threads__findnew(event->mmap.pid);
dump_printf("%p [%p]: PERF_RECORD_MMAP %d: [%p(%p) @ %p]: %s\n",
(void *)(offset + head),
@@ -588,9 +229,8 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
static int
process_comm_event(event_t *event, unsigned long offset, unsigned long head)
{
- struct thread *thread;
+ struct thread *thread = threads__findnew(event->comm.pid);
- thread = threads__findnew(event->comm.pid, &threads, &last_match);
dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
(void *)(offset + head),
(void *)(long)(event->header.size),
@@ -609,11 +249,9 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
static int
process_fork_event(event_t *event, unsigned long offset, unsigned long head)
{
- struct thread *thread;
- struct thread *parent;
+ struct thread *thread = threads__findnew(event->fork.pid);
+ struct thread *parent = threads__findnew(event->fork.ppid);
- thread = threads__findnew(event->fork.pid, &threads, &last_match);
- parent = threads__findnew(event->fork.ppid, &threads, &last_match);
dump_printf("%p [%p]: PERF_RECORD_FORK: %d:%d\n",
(void *)(offset + head),
(void *)(long)(event->header.size),
@@ -665,14 +303,15 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
return 0;
}
-static int
-parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
+static int parse_line(FILE *file, struct hist_entry *he, u64 len)
{
+ struct symbol *sym = he->sym;
char *line = NULL, *tmp, *tmp2;
static const char *prev_line;
static const char *prev_color;
unsigned int offset;
size_t line_len;
+ u64 start;
s64 line_ip;
int ret;
char *c;
@@ -709,22 +348,26 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
line_ip = -1;
}
+ start = he->map->unmap_ip(he->map, sym->start);
+
if (line_ip != -1) {
const char *path = NULL;
unsigned int hits = 0;
double percent = 0.0;
const char *color;
- struct sym_ext *sym_ext = sym->priv;
+ struct sym_priv *priv = dso__sym_priv(he->map->dso, sym);
+ struct sym_ext *sym_ext = priv->ext;
+ struct sym_hist *h = priv->hist;
offset = line_ip - start;
if (offset < len)
- hits = sym->hist[offset];
+ hits = h->ip[offset];
if (offset < len && sym_ext) {
path = sym_ext[offset].path;
percent = sym_ext[offset].percent;
- } else if (sym->hist_sum)
- percent = 100.0 * hits / sym->hist_sum;
+ } else if (h->sum)
+ percent = 100.0 * hits / h->sum;
color = get_percent_color(percent);
@@ -777,9 +420,10 @@ static void insert_source_line(struct sym_ext *sym_ext)
rb_insert_color(&sym_ext->node, &root_sym_ext);
}
-static void free_source_line(struct symbol *sym, int len)
+static void free_source_line(struct hist_entry *he, int len)
{
- struct sym_ext *sym_ext = sym->priv;
+ struct sym_priv *priv = dso__sym_priv(he->map->dso, he->sym);
+ struct sym_ext *sym_ext = priv->ext;
int i;
if (!sym_ext)
@@ -789,26 +433,30 @@ static void free_source_line(struct symbol *sym, int len)
free(sym_ext[i].path);
free(sym_ext);
- sym->priv = NULL;
+ priv->ext = NULL;
root_sym_ext = RB_ROOT;
}
/* Get the filename:line for the colored entries */
static void
-get_source_line(struct symbol *sym, u64 start, int len, const char *filename)
+get_source_line(struct hist_entry *he, int len, const char *filename)
{
+ struct symbol *sym = he->sym;
+ u64 start;
int i;
char cmd[PATH_MAX * 2];
struct sym_ext *sym_ext;
+ struct sym_priv *priv = dso__sym_priv(he->map->dso, sym);
+ struct sym_hist *h = priv->hist;
- if (!sym->hist_sum)
+ if (!h->sum)
return;
- sym->priv = calloc(len, sizeof(struct sym_ext));
- if (!sym->priv)
+ sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext));
+ if (!priv->ext)
return;
- sym_ext = sym->priv;
+ start = he->map->unmap_ip(he->map, sym->start);
for (i = 0; i < len; i++) {
char *path = NULL;
@@ -816,7 +464,7 @@ get_source_line(struct symbol *sym, u64 start, int len, const char *filename)
u64 offset;
FILE *fp;
- sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum;
+ sym_ext[i].percent = 100.0 * h->ip[i] / h->sum;
if (sym_ext[i].percent <= 0.5)
continue;
@@ -870,33 +518,34 @@ static void print_summary(const char *filename)
}
}
-static void annotate_sym(struct dso *dso, struct symbol *sym)
+static void annotate_sym(struct hist_entry *he)
{
- const char *filename = dso->name, *d_filename;
- u64 start, end, len;
+ struct map *map = he->map;
+ struct dso *dso = map->dso;
+ struct symbol *sym = he->sym;
+ const char *filename = dso->long_name, *d_filename;
+ u64 len;
char command[PATH_MAX*2];
FILE *file;
if (!filename)
return;
- if (sym->module)
- filename = sym->module->path;
- else if (dso == kernel_dso)
- filename = vmlinux_name;
-
- start = sym->obj_start;
- if (!start)
- start = sym->start;
+
+ if (verbose)
+ fprintf(stderr, "%s: filename=%s, sym=%s, start=%Lx, end=%Lx\n",
+ __func__, filename, sym->name,
+ map->unmap_ip(map, sym->start),
+ map->unmap_ip(map, sym->end));
+
if (full_paths)
d_filename = filename;
else
d_filename = basename(filename);
- end = start + sym->end - sym->start + 1;
len = sym->end - sym->start;
if (print_line) {
- get_source_line(sym, start, len, filename);
+ get_source_line(he, len, filename);
print_summary(filename);
}
@@ -905,10 +554,12 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
printf("------------------------------------------------\n");
if (verbose >= 2)
- printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);
+ printf("annotating [%p] %30s : [%p] %30s\n",
+ dso, dso->long_name, sym, sym->name);
sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
- (u64)start, (u64)end, filename, filename);
+ map->unmap_ip(map, sym->start), map->unmap_ip(map, sym->end),
+ filename, filename);
if (verbose >= 3)
printf("doing: %s\n", command);
@@ -918,35 +569,38 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
return;
while (!feof(file)) {
- if (parse_line(file, sym, start, len) < 0)
+ if (parse_line(file, he, len) < 0)
break;
}
pclose(file);
if (print_line)
- free_source_line(sym, len);
+ free_source_line(he, len);
}
static void find_annotations(void)
{
struct rb_node *nd;
- struct dso *dso;
- int count = 0;
- list_for_each_entry(dso, &dsos, node) {
+ for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
+ struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
+ struct sym_priv *priv;
- for (nd = rb_first(&dso->syms); nd; nd = rb_next(nd)) {
- struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
+ if (he->sym == NULL)
+ continue;
- if (sym->hist) {
- annotate_sym(dso, sym);
- count++;
- }
- }
- }
+ priv = dso__sym_priv(he->map->dso, he->sym);
+ if (priv->hist == NULL)
+ continue;
- if (!count)
- printf(" Error: symbol '%s' not present amongst the samples.\n", sym_hist_filter);
+ annotate_sym(he);
+ /*
+ * Since we have a hist_entry per IP for the same symbol, free
+ * he->sym->hist to signal we already processed this symbol.
+ */
+ free(priv->hist);
+ priv->hist = NULL;
+ }
}
static int __cmd_annotate(void)
@@ -959,7 +613,7 @@ static int __cmd_annotate(void)
uint32_t size;
char *buf;
- register_idle_thread(&threads, &last_match);
+ register_idle_thread();
input = open(input_name, O_RDONLY);
if (input < 0) {
@@ -983,7 +637,7 @@ static int __cmd_annotate(void)
exit(0);
}
- if (load_kernel() < 0) {
+ if (load_kernel(sizeof(struct sym_priv), symbol_filter) < 0) {
perror("failed to load kernel symbols");
return EXIT_FAILURE;
}
@@ -1059,14 +713,14 @@ more:
if (dump_trace)
return 0;
- if (verbose >= 3)
- threads__fprintf(stdout, &threads);
+ if (verbose > 3)
+ threads__fprintf(stdout);
- if (verbose >= 2)
+ if (verbose > 2)
dsos__fprintf(stdout);
collapse__resort();
- output__resort();
+ output__resort(total);
find_annotations();
@@ -1134,10 +788,13 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
sym_hist_filter = argv[0];
}
- if (!sym_hist_filter)
- usage_with_options(annotate_usage, options);
-
setup_pager();
+ if (field_sep && *field_sep == '.') {
+ fputs("'.' is the only non valid --field-separator argument\n",
+ stderr);
+ exit(129);
+ }
+
return __cmd_annotate();
}
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
new file mode 100644
index 000000000000..dcb406c7f82d
--- /dev/null
+++ b/tools/perf/builtin-probe.c
@@ -0,0 +1,372 @@
+/*
+ * builtin-probe.c
+ *
+ * Builtin probe command: Set up probe events by C expression
+ *
+ * Written by Masami Hiramatsu <mhiramat@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+#define _GNU_SOURCE
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#undef _GNU_SOURCE
+#include "perf.h"
+#include "builtin.h"
+#include "util/util.h"
+#include "util/event.h"
+#include "util/debug.h"
+#include "util/parse-options.h"
+#include "util/parse-events.h" /* For debugfs_path */
+#include "util/probe-finder.h"
+
+/* Default vmlinux search paths */
+#define NR_SEARCH_PATH 3
+const char *default_search_path[NR_SEARCH_PATH] = {
+"/lib/modules/%s/build/vmlinux", /* Custom build kernel */
+"/usr/lib/debug/lib/modules/%s/vmlinux", /* Red Hat debuginfo */
+"/boot/vmlinux-debug-%s", /* Ubuntu */
+};
+
+#define MAX_PATH_LEN 256
+#define MAX_PROBES 128
+#define MAX_PROBE_ARGS 128
+
+/* Session management structure */
+static struct {
+ char *vmlinux;
+ char *release;
+ int need_dwarf;
+ int nr_probe;
+ struct probe_point probes[MAX_PROBES];
+ char *events[MAX_PROBES];
+} session;
+
+#define semantic_error(msg ...) die("Semantic error :" msg)
+
+static int parse_probepoint(const struct option *opt __used,
+ const char *str, int unset __used)
+{
+ char *argv[MAX_PROBE_ARGS + 2]; /* Event + probe + args */
+ int argc, i;
+ char *arg, *ptr;
+ struct probe_point *pp = &session.probes[session.nr_probe];
+ char **event = &session.events[session.nr_probe];
+ int retp = 0;
+
+ if (!str) /* The end of probe points */
+ return 0;
+
+ pr_debug("probe-definition(%d): %s\n", session.nr_probe, str);
+ if (++session.nr_probe == MAX_PROBES)
+ semantic_error("Too many probes");
+
+ /* Separate arguments, similar to argv_split */
+ argc = 0;
+ do {
+ /* Skip separators */
+ while (isspace(*str))
+ str++;
+
+ /* Add an argument */
+ if (*str != '\0') {
+ const char *s = str;
+
+ /* Skip the argument */
+ while (!isspace(*str) && *str != '\0')
+ str++;
+
+ /* Duplicate the argument */
+ argv[argc] = strndup(s, str - s);
+ if (argv[argc] == NULL)
+ die("strndup");
+ if (++argc == MAX_PROBE_ARGS)
+ semantic_error("Too many arguments");
+ pr_debug("argv[%d]=%s\n", argc, argv[argc - 1]);
+ }
+ } while (*str != '\0');
+ if (argc < 2)
+ semantic_error("Need event-name and probe-point at least.");
+
+ /* Parse the event name */
+ if (argv[0][0] == 'r')
+ retp = 1;
+ else if (argv[0][0] != 'p')
+ semantic_error("You must specify 'p'(kprobe) or"
+ " 'r'(kretprobe) first.");
+ /* TODO: check event name */
+ *event = argv[0];
+
+ /* Parse probe point */
+ arg = argv[1];
+ if (arg[0] == '@') {
+ /* Source Line */
+ arg++;
+ ptr = strchr(arg, ':');
+ if (!ptr || !isdigit(ptr[1]))
+ semantic_error("Line number is required.");
+ *ptr++ = '\0';
+ if (strlen(arg) == 0)
+ semantic_error("No file name.");
+ pp->file = strdup(arg);
+ pp->line = atoi(ptr);
+ if (!pp->file || !pp->line)
+ semantic_error("Failed to parse line.");
+ pr_debug("file:%s line:%d\n", pp->file, pp->line);
+ } else {
+ /* Function name */
+ ptr = strchr(arg, '+');
+ if (ptr) {
+ if (!isdigit(ptr[1]))
+ semantic_error("Offset is required.");
+ *ptr++ = '\0';
+ pp->offset = atoi(ptr);
+ } else
+ ptr = arg;
+ ptr = strchr(ptr, '@');
+ if (ptr) {
+ *ptr++ = '\0';
+ pp->file = strdup(ptr);
+ }
+ pp->function = strdup(arg);
+ pr_debug("symbol:%s file:%s offset:%d\n",
+ pp->function, pp->file, pp->offset);
+ }
+ free(argv[1]);
+ if (pp->file)
+ session.need_dwarf = 1;
+
+ /* Copy arguments */
+ pp->nr_args = argc - 2;
+ if (pp->nr_args > 0) {
+ pp->args = (char **)malloc(sizeof(char *) * pp->nr_args);
+ if (!pp->args)
+ die("malloc");
+ memcpy(pp->args, &argv[2], sizeof(char *) * pp->nr_args);
+ }
+
+ /* Ensure return probe has no C argument */
+ for (i = 0; i < pp->nr_args; i++)
+ if (is_c_varname(pp->args[i])) {
+ if (retp)
+ semantic_error("You can't specify local"
+ " variable for kretprobe");
+ session.need_dwarf = 1;
+ }
+
+ pr_debug("%d arguments\n", pp->nr_args);
+ return 0;
+}
+
+#ifndef NO_LIBDWARF
+static int open_default_vmlinux(void)
+{
+ struct utsname uts;
+ char fname[MAX_PATH_LEN];
+ int fd, ret, i;
+
+ ret = uname(&uts);
+ if (ret) {
+ pr_debug("uname() failed.\n");
+ return -errno;
+ }
+ session.release = uts.release;
+ for (i = 0; i < NR_SEARCH_PATH; i++) {
+ ret = snprintf(fname, MAX_PATH_LEN,
+ default_search_path[i], session.release);
+ if (ret >= MAX_PATH_LEN || ret < 0) {
+ pr_debug("Filename(%d,%s) is too long.\n", i,
+ uts.release);
+ errno = E2BIG;
+ return -E2BIG;
+ }
+ pr_debug("try to open %s\n", fname);
+ fd = open(fname, O_RDONLY);
+ if (fd >= 0)
+ break;
+ }
+ return fd;
+}
+#endif
+
+static const char * const probe_usage[] = {
+ "perf probe [<options>] -P 'PROBEDEF' [-P 'PROBEDEF' ...]",
+ NULL
+};
+
+static const struct option options[] = {
+ OPT_BOOLEAN('v', "verbose", &verbose,
+ "be more verbose (show parsed arguments, etc)"),
+#ifndef NO_LIBDWARF
+ OPT_STRING('k', "vmlinux", &session.vmlinux, "file",
+ "vmlinux/module pathname"),
+#endif
+ OPT_CALLBACK('P', "probe", NULL,
+#ifdef NO_LIBDWARF
+ "p|r:[GRP/]NAME FUNC[+OFFS] [ARG ...]",
+#else
+ "p|r:[GRP/]NAME FUNC[+OFFS][@SRC]|@SRC:LINE [ARG ...]",
+#endif
+ "probe point definition, where\n"
+ "\t\tp:\tkprobe probe\n"
+ "\t\tr:\tkretprobe probe\n"
+ "\t\tGRP:\tGroup name (optional)\n"
+ "\t\tNAME:\tEvent name\n"
+ "\t\tFUNC:\tFunction name\n"
+ "\t\tOFFS:\tOffset from function entry (in byte)\n"
+#ifdef NO_LIBDWARF
+ "\t\tARG:\tProbe argument (only \n"
+#else
+ "\t\tSRC:\tSource code path\n"
+ "\t\tLINE:\tLine number\n"
+ "\t\tARG:\tProbe argument (local variable name or\n"
+#endif
+ "\t\t\tkprobe-tracer argument format is supported.)\n",
+ parse_probepoint),
+ OPT_END()
+};
+
+static int write_new_event(int fd, const char *buf)
+{
+ int ret;
+
+ printf("Adding new event: %s\n", buf);
+ ret = write(fd, buf, strlen(buf));
+ if (ret <= 0)
+ die("failed to create event.");
+
+ return ret;
+}
+
+#define MAX_CMDLEN 256
+
+static int synthesize_probepoint(struct probe_point *pp)
+{
+ char *buf;
+ int i, len, ret;
+ pp->probes[0] = buf = (char *)calloc(MAX_CMDLEN, sizeof(char));
+ if (!buf)
+ die("calloc");
+ ret = snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
+ if (ret <= 0 || ret >= MAX_CMDLEN)
+ goto error;
+ len = ret;
+
+ for (i = 0; i < pp->nr_args; i++) {
+ ret = snprintf(&buf[len], MAX_CMDLEN - len, " %s",
+ pp->args[i]);
+ if (ret <= 0 || ret >= MAX_CMDLEN - len)
+ goto error;
+ len += ret;
+ }
+ pp->found = 1;
+ return pp->found;
+error:
+ free(pp->probes[0]);
+ if (ret > 0)
+ ret = -E2BIG;
+ return ret;
+}
+
+int cmd_probe(int argc, const char **argv, const char *prefix __used)
+{
+ int i, j, fd, ret;
+ struct probe_point *pp;
+ char buf[MAX_CMDLEN];
+
+ argc = parse_options(argc, argv, options, probe_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+ if (argc || session.nr_probe == 0)
+ usage_with_options(probe_usage, options);
+
+#ifdef NO_LIBDWARF
+ if (session.need_dwarf)
+ semantic_error("Dwarf-analysis is not supported");
+#endif
+
+ /* Synthesize probes without dwarf */
+ for (j = 0; j < session.nr_probe; j++) {
+#ifndef NO_LIBDWARF
+ if (session.events[j][0] != 'r') {
+ session.need_dwarf = 1;
+ continue;
+ }
+#endif
+ ret = synthesize_probepoint(&session.probes[j]);
+ if (ret == -E2BIG)
+ semantic_error("probe point is too long.");
+ else if (ret < 0)
+ die("snprintf");
+ }
+
+#ifndef NO_LIBDWARF
+ if (!session.need_dwarf)
+ goto setup_probes;
+
+ if (session.vmlinux)
+ fd = open(session.vmlinux, O_RDONLY);
+ else
+ fd = open_default_vmlinux();
+ if (fd < 0)
+ die("vmlinux/module file open");
+
+ /* Searching probe points */
+ for (j = 0; j < session.nr_probe; j++) {
+ pp = &session.probes[j];
+ if (pp->found)
+ continue;
+
+ lseek(fd, SEEK_SET, 0);
+ ret = find_probepoint(fd, pp);
+ if (ret <= 0)
+ die("No probe point found.\n");
+ pr_debug("probe event %s found\n", session.events[j]);
+ }
+ close(fd);
+
+setup_probes:
+#endif /* !NO_LIBDWARF */
+
+ /* Settng up probe points */
+ snprintf(buf, MAX_CMDLEN, "%s/../kprobe_events", debugfs_path);
+ fd = open(buf, O_WRONLY, O_APPEND);
+ if (fd < 0)
+ die("kprobe_events open");
+ for (j = 0; j < session.nr_probe; j++) {
+ pp = &session.probes[j];
+ if (pp->found == 1) {
+ snprintf(buf, MAX_CMDLEN, "%s %s\n",
+ session.events[j], pp->probes[0]);
+ write_new_event(fd, buf);
+ } else
+ for (i = 0; i < pp->found; i++) {
+ snprintf(buf, MAX_CMDLEN, "%s%d %s\n",
+ session.events[j], i, pp->probes[i]);
+ write_new_event(fd, buf);
+ }
+ }
+ close(fd);
+ return 0;
+}
+
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 3eeef339c787..4a73d89ce5d1 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -17,55 +17,51 @@
#include "util/header.h"
#include "util/event.h"
#include "util/debug.h"
-#include "util/trace-event.h"
#include <unistd.h>
#include <sched.h>
-#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
-#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
-
static int fd[MAX_NR_CPUS][MAX_COUNTERS];
-static long default_interval = 100000;
+static long default_interval = 0;
-static int nr_cpus = 0;
+static int nr_cpus = 0;
static unsigned int page_size;
-static unsigned int mmap_pages = 128;
-static int freq = 0;
+static unsigned int mmap_pages = 128;
+static int freq = 1000;
static int output;
static const char *output_name = "perf.data";
-static int group = 0;
-static unsigned int realtime_prio = 0;
-static int raw_samples = 0;
-static int system_wide = 0;
-static int profile_cpu = -1;
-static pid_t target_pid = -1;
-static pid_t child_pid = -1;
-static int inherit = 1;
-static int force = 0;
-static int append_file = 0;
-static int call_graph = 0;
-static int inherit_stat = 0;
-static int no_samples = 0;
-static int sample_address = 0;
-static int multiplex = 0;
-static int multiplex_fd = -1;
-
-static long samples;
+static int group = 0;
+static unsigned int realtime_prio = 0;
+static int raw_samples = 0;
+static int system_wide = 0;
+static int profile_cpu = -1;
+static pid_t target_pid = -1;
+static pid_t child_pid = -1;
+static int inherit = 1;
+static int force = 0;
+static int append_file = 0;
+static int call_graph = 0;
+static int inherit_stat = 0;
+static int no_samples = 0;
+static int sample_address = 0;
+static int multiplex = 0;
+static int multiplex_fd = -1;
+
+static long samples = 0;
static struct timeval last_read;
static struct timeval this_read;
-static u64 bytes_written;
+static u64 bytes_written = 0;
static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
-static int nr_poll;
-static int nr_cpu;
+static int nr_poll = 0;
+static int nr_cpu = 0;
-static int file_new = 1;
+static int file_new = 1;
-struct perf_header *header;
+struct perf_header *header = NULL;
struct mmap_data {
int counter;
@@ -113,6 +109,12 @@ static void write_output(void *buf, size_t size)
}
}
+static int process_synthesized_event(event_t *event)
+{
+ write_output(event, event->header.size);
+ return 0;
+}
+
static void mmap_read(struct mmap_data *md)
{
unsigned int head = mmap_read_head(md);
@@ -195,168 +197,6 @@ static void sig_atexit(void)
kill(getpid(), signr);
}
-static pid_t pid_synthesize_comm_event(pid_t pid, int full)
-{
- struct comm_event comm_ev;
- char filename[PATH_MAX];
- char bf[BUFSIZ];
- FILE *fp;
- size_t size = 0;
- DIR *tasks;
- struct dirent dirent, *next;
- pid_t tgid = 0;
-
- snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
-
- fp = fopen(filename, "r");
- if (fp == NULL) {
- /*
- * We raced with a task exiting - just return:
- */
- if (verbose)
- fprintf(stderr, "couldn't open %s\n", filename);
- return 0;
- }
-
- memset(&comm_ev, 0, sizeof(comm_ev));
- while (!comm_ev.comm[0] || !comm_ev.pid) {
- if (fgets(bf, sizeof(bf), fp) == NULL)
- goto out_failure;
-
- if (memcmp(bf, "Name:", 5) == 0) {
- char *name = bf + 5;
- while (*name && isspace(*name))
- ++name;
- size = strlen(name) - 1;
- memcpy(comm_ev.comm, name, size++);
- } else if (memcmp(bf, "Tgid:", 5) == 0) {
- char *tgids = bf + 5;
- while (*tgids && isspace(*tgids))
- ++tgids;
- tgid = comm_ev.pid = atoi(tgids);
- }
- }
-
- comm_ev.header.type = PERF_RECORD_COMM;
- size = ALIGN(size, sizeof(u64));
- comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size);
-
- if (!full) {
- comm_ev.tid = pid;
-
- write_output(&comm_ev, comm_ev.header.size);
- goto out_fclose;
- }
-
- snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
-
- tasks = opendir(filename);
- while (!readdir_r(tasks, &dirent, &next) && next) {
- char *end;
- pid = strtol(dirent.d_name, &end, 10);
- if (*end)
- continue;
-
- comm_ev.tid = pid;
-
- write_output(&comm_ev, comm_ev.header.size);
- }
- closedir(tasks);
-
-out_fclose:
- fclose(fp);
- return tgid;
-
-out_failure:
- fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n",
- filename);
- exit(EXIT_FAILURE);
-}
-
-static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid)
-{
- char filename[PATH_MAX];
- FILE *fp;
-
- snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
-
- fp = fopen(filename, "r");
- if (fp == NULL) {
- /*
- * We raced with a task exiting - just return:
- */
- if (verbose)
- fprintf(stderr, "couldn't open %s\n", filename);
- return;
- }
- while (1) {
- char bf[BUFSIZ], *pbf = bf;
- struct mmap_event mmap_ev = {
- .header = { .type = PERF_RECORD_MMAP },
- };
- int n;
- size_t size;
- if (fgets(bf, sizeof(bf), fp) == NULL)
- break;
-
- /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
- n = hex2u64(pbf, &mmap_ev.start);
- if (n < 0)
- continue;
- pbf += n + 1;
- n = hex2u64(pbf, &mmap_ev.len);
- if (n < 0)
- continue;
- pbf += n + 3;
- if (*pbf == 'x') { /* vm_exec */
- char *execname = strchr(bf, '/');
-
- /* Catch VDSO */
- if (execname == NULL)
- execname = strstr(bf, "[vdso]");
-
- if (execname == NULL)
- continue;
-
- size = strlen(execname);
- execname[size - 1] = '\0'; /* Remove \n */
- memcpy(mmap_ev.filename, execname, size);
- size = ALIGN(size, sizeof(u64));
- mmap_ev.len -= mmap_ev.start;
- mmap_ev.header.size = (sizeof(mmap_ev) -
- (sizeof(mmap_ev.filename) - size));
- mmap_ev.pid = tgid;
- mmap_ev.tid = pid;
-
- write_output(&mmap_ev, mmap_ev.header.size);
- }
- }
-
- fclose(fp);
-}
-
-static void synthesize_all(void)
-{
- DIR *proc;
- struct dirent dirent, *next;
-
- proc = opendir("/proc");
-
- while (!readdir_r(proc, &dirent, &next) && next) {
- char *end;
- pid_t pid, tgid;
-
- pid = strtol(dirent.d_name, &end, 10);
- if (*end) /* only interested in proper numerical dirents */
- continue;
-
- tgid = pid_synthesize_comm_event(pid, 1);
- pid_synthesize_mmap_samples(pid, tgid);
- }
-
- closedir(proc);
-}
-
static int group_fd;
static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
@@ -375,9 +215,11 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
static void create_counter(int counter, int cpu, pid_t pid)
{
+ char *filter = filters[counter];
struct perf_event_attr *attr = attrs + counter;
struct perf_header_attr *h_attr;
int track = !counter; /* only the first counter needs these */
+ int ret;
struct {
u64 count;
u64 time_enabled;
@@ -480,7 +322,6 @@ try_again:
multiplex_fd = fd[nr_cpu][counter];
if (multiplex && fd[nr_cpu][counter] != multiplex_fd) {
- int ret;
ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd);
assert(ret != -1);
@@ -500,6 +341,16 @@ try_again:
}
}
+ if (filter != NULL) {
+ ret = ioctl(fd[nr_cpu][counter],
+ PERF_EVENT_IOC_SET_FILTER, filter);
+ if (ret) {
+ error("failed to set filter with %d (%s)\n", errno,
+ strerror(errno));
+ exit(-1);
+ }
+ }
+
ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE);
}
@@ -566,17 +417,17 @@ static int __cmd_record(int argc, const char **argv)
else
header = perf_header__new();
-
if (raw_samples) {
- read_tracing_data(attrs, nr_counters);
+ perf_header__feat_trace_info(header);
} else {
for (i = 0; i < nr_counters; i++) {
if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
- read_tracing_data(attrs, nr_counters);
+ perf_header__feat_trace_info(header);
break;
}
}
}
+
atexit(atexit_header);
if (!system_wide) {
@@ -597,11 +448,10 @@ static int __cmd_record(int argc, const char **argv)
if (file_new)
perf_header__write(header, output);
- if (!system_wide) {
- pid_t tgid = pid_synthesize_comm_event(pid, 0);
- pid_synthesize_mmap_samples(pid, tgid);
- } else
- synthesize_all();
+ if (!system_wide)
+ event__synthesize_thread(pid, process_synthesized_event);
+ else
+ event__synthesize_threads(process_synthesized_event);
if (target_pid == -1 && argc) {
pid = fork();
@@ -623,7 +473,7 @@ static int __cmd_record(int argc, const char **argv)
param.sched_priority = realtime_prio;
if (sched_setscheduler(0, SCHED_FIFO, &param)) {
- printf("Could not set realtime priority.\n");
+ pr_err("Could not set realtime priority.\n");
exit(-1);
}
}
@@ -677,6 +527,8 @@ static const struct option options[] = {
OPT_CALLBACK('e', "event", NULL, "event",
"event selector. use 'perf list' to list available events",
parse_events),
+ OPT_CALLBACK(0, "filter", NULL, "filter",
+ "event filter", parse_filter),
OPT_INTEGER('p', "pid", &target_pid,
"record events on existing pid"),
OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -731,6 +583,18 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
attrs[0].config = PERF_COUNT_HW_CPU_CYCLES;
}
+ /*
+ * User specified count overrides default frequency.
+ */
+ if (default_interval)
+ freq = 0;
+ else if (freq) {
+ default_interval = freq;
+ } else {
+ fprintf(stderr, "frequency and count are zero, aborting\n");
+ exit(EXIT_FAILURE);
+ }
+
for (counter = 0; counter < nr_counters; counter++) {
if (attrs[counter].sample_period)
continue;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 19669c20088e..b3d814b54555 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -26,20 +26,18 @@
#include "util/parse-options.h"
#include "util/parse-events.h"
+#include "util/data_map.h"
#include "util/thread.h"
+#include "util/sort.h"
+#include "util/hist.h"
static char const *input_name = "perf.data";
-static char default_sort_order[] = "comm,dso,symbol";
-static char *sort_order = default_sort_order;
static char *dso_list_str, *comm_list_str, *sym_list_str,
*col_width_list_str;
static struct strlist *dso_list, *comm_list, *sym_list;
-static char *field_sep;
static int force;
-static int input;
-static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
static int full_paths;
static int show_nr_samples;
@@ -50,374 +48,39 @@ static struct perf_read_values show_threads_values;
static char default_pretty_printing_style[] = "normal";
static char *pretty_printing_style = default_pretty_printing_style;
-static unsigned long page_size;
-static unsigned long mmap_window = 32;
-
-static char default_parent_pattern[] = "^sys_|^do_page_fault";
-static char *parent_pattern = default_parent_pattern;
-static regex_t parent_regex;
-
static int exclude_other = 1;
static char callchain_default_opt[] = "fractal,0.5";
-static int callchain;
-
-static char __cwd[PATH_MAX];
-static char *cwd = __cwd;
+static char *cwd;
static int cwdlen;
-static struct rb_root threads;
-static struct thread *last_match;
-
static struct perf_header *header;
-static
-struct callchain_param callchain_param = {
- .mode = CHAIN_GRAPH_REL,
- .min_percent = 0.5
-};
-
static u64 sample_type;
-static int repsep_fprintf(FILE *fp, const char *fmt, ...)
-{
- int n;
- va_list ap;
-
- va_start(ap, fmt);
- if (!field_sep)
- n = vfprintf(fp, fmt, ap);
- else {
- char *bf = NULL;
- n = vasprintf(&bf, fmt, ap);
- if (n > 0) {
- char *sep = bf;
-
- while (1) {
- sep = strchr(sep, *field_sep);
- if (sep == NULL)
- break;
- *sep = '.';
- }
- }
- fputs(bf, fp);
- free(bf);
- }
- va_end(ap);
- return n;
-}
-
-static unsigned int dsos__col_width,
- comms__col_width,
- threads__col_width;
-
-/*
- * histogram, sorted on item, collects counts
- */
-
-static struct rb_root hist;
-
-struct hist_entry {
- struct rb_node rb_node;
-
- struct thread *thread;
- struct map *map;
- struct dso *dso;
- struct symbol *sym;
- struct symbol *parent;
- u64 ip;
- char level;
- struct callchain_node callchain;
- struct rb_root sorted_chain;
-
- u64 count;
-};
-
-/*
- * configurable sorting bits
- */
-
-struct sort_entry {
- struct list_head list;
-
- const char *header;
-
- int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
- int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
- size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
- unsigned int *width;
- bool elide;
-};
-
-static int64_t cmp_null(void *l, void *r)
-{
- if (!l && !r)
- return 0;
- else if (!l)
- return -1;
- else
- return 1;
-}
-
-/* --sort pid */
-
-static int64_t
-sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
-{
- return right->thread->pid - left->thread->pid;
-}
-
-static size_t
-sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
-{
- return repsep_fprintf(fp, "%*s:%5d", width - 6,
- self->thread->comm ?: "", self->thread->pid);
-}
-
-static struct sort_entry sort_thread = {
- .header = "Command: Pid",
- .cmp = sort__thread_cmp,
- .print = sort__thread_print,
- .width = &threads__col_width,
-};
-
-/* --sort comm */
-
-static int64_t
-sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
-{
- return right->thread->pid - left->thread->pid;
-}
-
-static int64_t
-sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
-{
- char *comm_l = left->thread->comm;
- char *comm_r = right->thread->comm;
-
- if (!comm_l || !comm_r)
- return cmp_null(comm_l, comm_r);
-
- return strcmp(comm_l, comm_r);
-}
-
-static size_t
-sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
-{
- return repsep_fprintf(fp, "%*s", width, self->thread->comm);
-}
-
-static struct sort_entry sort_comm = {
- .header = "Command",
- .cmp = sort__comm_cmp,
- .collapse = sort__comm_collapse,
- .print = sort__comm_print,
- .width = &comms__col_width,
-};
-
-/* --sort dso */
-
-static int64_t
-sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
-{
- struct dso *dso_l = left->dso;
- struct dso *dso_r = right->dso;
-
- if (!dso_l || !dso_r)
- return cmp_null(dso_l, dso_r);
-
- return strcmp(dso_l->name, dso_r->name);
-}
-
-static size_t
-sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
-{
- if (self->dso)
- return repsep_fprintf(fp, "%-*s", width, self->dso->name);
-
- return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
-}
-
-static struct sort_entry sort_dso = {
- .header = "Shared Object",
- .cmp = sort__dso_cmp,
- .print = sort__dso_print,
- .width = &dsos__col_width,
-};
-
-/* --sort symbol */
-
-static int64_t
-sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
-{
- u64 ip_l, ip_r;
-
- if (left->sym == right->sym)
- return 0;
-
- ip_l = left->sym ? left->sym->start : left->ip;
- ip_r = right->sym ? right->sym->start : right->ip;
-
- return (int64_t)(ip_r - ip_l);
-}
static size_t
-sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
+callchain__fprintf_left_margin(FILE *fp, int left_margin)
{
- size_t ret = 0;
+ int i;
+ int ret;
- if (verbose)
- ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
- dso__symtab_origin(self->dso));
+ ret = fprintf(fp, " ");
- ret += repsep_fprintf(fp, "[%c] ", self->level);
- if (self->sym) {
- ret += repsep_fprintf(fp, "%s", self->sym->name);
-
- if (self->sym->module)
- ret += repsep_fprintf(fp, "\t[%s]",
- self->sym->module->name);
- } else {
- ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
- }
+ for (i = 0; i < left_margin; i++)
+ ret += fprintf(fp, " ");
return ret;
}
-static struct sort_entry sort_sym = {
- .header = "Symbol",
- .cmp = sort__sym_cmp,
- .print = sort__sym_print,
-};
-
-/* --sort parent */
-
-static int64_t
-sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
-{
- struct symbol *sym_l = left->parent;
- struct symbol *sym_r = right->parent;
-
- if (!sym_l || !sym_r)
- return cmp_null(sym_l, sym_r);
-
- return strcmp(sym_l->name, sym_r->name);
-}
-
-static size_t
-sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
-{
- return repsep_fprintf(fp, "%-*s", width,
- self->parent ? self->parent->name : "[other]");
-}
-
-static unsigned int parent_symbol__col_width;
-
-static struct sort_entry sort_parent = {
- .header = "Parent symbol",
- .cmp = sort__parent_cmp,
- .print = sort__parent_print,
- .width = &parent_symbol__col_width,
-};
-
-static int sort__need_collapse = 0;
-static int sort__has_parent = 0;
-
-struct sort_dimension {
- const char *name;
- struct sort_entry *entry;
- int taken;
-};
-
-static struct sort_dimension sort_dimensions[] = {
- { .name = "pid", .entry = &sort_thread, },
- { .name = "comm", .entry = &sort_comm, },
- { .name = "dso", .entry = &sort_dso, },
- { .name = "symbol", .entry = &sort_sym, },
- { .name = "parent", .entry = &sort_parent, },
-};
-
-static LIST_HEAD(hist_entry__sort_list);
-
-static int sort_dimension__add(const char *tok)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
- struct sort_dimension *sd = &sort_dimensions[i];
-
- if (sd->taken)
- continue;
-
- if (strncasecmp(tok, sd->name, strlen(tok)))
- continue;
-
- if (sd->entry->collapse)
- sort__need_collapse = 1;
-
- if (sd->entry == &sort_parent) {
- int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
- if (ret) {
- char err[BUFSIZ];
-
- regerror(ret, &parent_regex, err, sizeof(err));
- fprintf(stderr, "Invalid regex: %s\n%s",
- parent_pattern, err);
- exit(-1);
- }
- sort__has_parent = 1;
- }
-
- list_add_tail(&sd->entry->list, &hist_entry__sort_list);
- sd->taken = 1;
-
- return 0;
- }
-
- return -ESRCH;
-}
-
-static int64_t
-hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
-{
- struct sort_entry *se;
- int64_t cmp = 0;
-
- list_for_each_entry(se, &hist_entry__sort_list, list) {
- cmp = se->cmp(left, right);
- if (cmp)
- break;
- }
-
- return cmp;
-}
-
-static int64_t
-hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
-{
- struct sort_entry *se;
- int64_t cmp = 0;
-
- list_for_each_entry(se, &hist_entry__sort_list, list) {
- int64_t (*f)(struct hist_entry *, struct hist_entry *);
-
- f = se->collapse ?: se->cmp;
-
- cmp = f(left, right);
- if (cmp)
- break;
- }
-
- return cmp;
-}
-
-static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
+static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
+ int left_margin)
{
int i;
size_t ret = 0;
- ret += fprintf(fp, "%s", " ");
+ ret += callchain__fprintf_left_margin(fp, left_margin);
for (i = 0; i < depth; i++)
if (depth_mask & (1 << i))
@@ -432,12 +95,12 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
static size_t
ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
int depth_mask, int count, u64 total_samples,
- int hits)
+ int hits, int left_margin)
{
int i;
size_t ret = 0;
- ret += fprintf(fp, "%s", " ");
+ ret += callchain__fprintf_left_margin(fp, left_margin);
for (i = 0; i < depth; i++) {
if (depth_mask & (1 << i))
ret += fprintf(fp, "|");
@@ -475,8 +138,9 @@ static void init_rem_hits(void)
}
static size_t
-callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
- u64 total_samples, int depth, int depth_mask)
+__callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
+ u64 total_samples, int depth, int depth_mask,
+ int left_margin)
{
struct rb_node *node, *next;
struct callchain_node *child;
@@ -517,7 +181,8 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
* But we keep the older depth mask for the line seperator
* to keep the level link until we reach the last child
*/
- ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
+ ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
+ left_margin);
i = 0;
list_for_each_entry(chain, &child->val, list) {
if (chain->ip >= PERF_CONTEXT_MAX)
@@ -525,11 +190,13 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
ret += ipchain__fprintf_graph(fp, chain, depth,
new_depth_mask, i++,
new_total,
- cumul);
+ cumul,
+ left_margin);
}
- ret += callchain__fprintf_graph(fp, child, new_total,
- depth + 1,
- new_depth_mask | (1 << depth));
+ ret += __callchain__fprintf_graph(fp, child, new_total,
+ depth + 1,
+ new_depth_mask | (1 << depth),
+ left_margin);
node = next;
}
@@ -543,12 +210,51 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
new_depth_mask, 0, new_total,
- remaining);
+ remaining, left_margin);
}
return ret;
}
+
+static size_t
+callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
+ u64 total_samples, int left_margin)
+{
+ struct callchain_list *chain;
+ bool printed = false;
+ int i = 0;
+ int ret = 0;
+
+ list_for_each_entry(chain, &self->val, list) {
+ if (chain->ip >= PERF_CONTEXT_MAX)
+ continue;
+
+ if (!i++ && sort__first_dimension == SORT_SYM)
+ continue;
+
+ if (!printed) {
+ ret += callchain__fprintf_left_margin(fp, left_margin);
+ ret += fprintf(fp, "|\n");
+ ret += callchain__fprintf_left_margin(fp, left_margin);
+ ret += fprintf(fp, "---");
+
+ left_margin += 3;
+ printed = true;
+ } else
+ ret += callchain__fprintf_left_margin(fp, left_margin);
+
+ if (chain->sym)
+ ret += fprintf(fp, " %s\n", chain->sym->name);
+ else
+ ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
+ }
+
+ ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
+
+ return ret;
+}
+
static size_t
callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
u64 total_samples)
@@ -577,7 +283,7 @@ callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
static size_t
hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
- u64 total_samples)
+ u64 total_samples, int left_margin)
{
struct rb_node *rb_node;
struct callchain_node *chain;
@@ -597,8 +303,8 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
break;
case CHAIN_GRAPH_ABS: /* Falldown */
case CHAIN_GRAPH_REL:
- ret += callchain__fprintf_graph(fp, chain,
- total_samples, 1, 1);
+ ret += callchain__fprintf_graph(fp, chain, total_samples,
+ left_margin);
case CHAIN_NONE:
default:
break;
@@ -610,7 +316,6 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
return ret;
}
-
static size_t
hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
{
@@ -644,8 +349,19 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
ret += fprintf(fp, "\n");
- if (callchain)
- hist_entry_callchain__fprintf(fp, self, total_samples);
+ if (callchain) {
+ int left_margin = 0;
+
+ if (sort__first_dimension == SORT_COMM) {
+ se = list_first_entry(&hist_entry__sort_list, typeof(*se),
+ list);
+ left_margin = se->width ? *se->width : 0;
+ left_margin -= thread__comm_len(self->thread);
+ }
+
+ hist_entry_callchain__fprintf(fp, self, total_samples,
+ left_margin);
+ }
return ret;
}
@@ -695,22 +411,17 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm)
static struct symbol *
-resolve_symbol(struct thread *thread, struct map **mapp,
- struct dso **dsop, u64 *ipp)
+resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp)
{
- struct dso *dso = dsop ? *dsop : NULL;
struct map *map = mapp ? *mapp : NULL;
u64 ip = *ipp;
- if (!thread)
- return NULL;
-
- if (dso)
- goto got_dso;
-
if (map)
goto got_map;
+ if (!thread)
+ return NULL;
+
map = thread__find_map(thread, ip);
if (map != NULL) {
/*
@@ -725,29 +436,26 @@ resolve_symbol(struct thread *thread, struct map **mapp,
*mapp = map;
got_map:
ip = map->map_ip(map, ip);
-
- dso = map->dso;
} else {
/*
* If this is outside of all known maps,
* and is a negative address, try to look it
* up in the kernel dso, as it might be a
- * vsyscall (which executes in user-mode):
+ * vsyscall or vdso (which executes in user-mode).
+ *
+ * XXX This is nasty, we should have a symbol list in
+ * the "[vdso]" dso, but for now lets use the old
+ * trick of looking in the whole kernel symbol list.
*/
if ((long long)ip < 0)
- dso = kernel_dso;
+ return kernel_maps__find_symbol(ip, mapp);
}
- dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
+ dump_printf(" ...... dso: %s\n",
+ map ? map->dso->long_name : "<not found>");
dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
*ipp = ip;
- if (dsop)
- *dsop = dso;
-
- if (!dso)
- return NULL;
-got_dso:
- return dso->find_symbol(dso, ip);
+ return map ? map->dso->find_symbol(map->dso, ip) : NULL;
}
static int call__match(struct symbol *sym)
@@ -758,9 +466,9 @@ static int call__match(struct symbol *sym)
return 0;
}
-static struct symbol **
-resolve_callchain(struct thread *thread, struct map *map __used,
- struct ip_callchain *chain, struct hist_entry *entry)
+static struct symbol **resolve_callchain(struct thread *thread, struct map *map,
+ struct ip_callchain *chain,
+ struct symbol **parent)
{
u64 context = PERF_CONTEXT_MAX;
struct symbol **syms = NULL;
@@ -776,8 +484,7 @@ resolve_callchain(struct thread *thread, struct map *map __used,
for (i = 0; i < chain->nr; i++) {
u64 ip = chain->ips[i];
- struct dso *dso = NULL;
- struct symbol *sym;
+ struct symbol *sym = NULL;
if (ip >= PERF_CONTEXT_MAX) {
context = ip;
@@ -786,21 +493,18 @@ resolve_callchain(struct thread *thread, struct map *map __used,
switch (context) {
case PERF_CONTEXT_HV:
- dso = hypervisor_dso;
break;
case PERF_CONTEXT_KERNEL:
- dso = kernel_dso;
+ sym = kernel_maps__find_symbol(ip, &map);
break;
default:
+ sym = resolve_symbol(thread, &map, &ip);
break;
}
- sym = resolve_symbol(thread, NULL, &dso, &ip);
-
if (sym) {
- if (sort__has_parent && call__match(sym) &&
- !entry->parent)
- entry->parent = sym;
+ if (sort__has_parent && !*parent && call__match(sym))
+ *parent = sym;
if (!callchain)
break;
syms[i] = sym;
@@ -815,177 +519,35 @@ resolve_callchain(struct thread *thread, struct map *map __used,
*/
static int
-hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
+hist_entry__add(struct thread *thread, struct map *map,
struct symbol *sym, u64 ip, struct ip_callchain *chain,
char level, u64 count)
{
- struct rb_node **p = &hist.rb_node;
- struct rb_node *parent = NULL;
+ struct symbol **syms = NULL, *parent = NULL;
+ bool hit;
struct hist_entry *he;
- struct symbol **syms = NULL;
- struct hist_entry entry = {
- .thread = thread,
- .map = map,
- .dso = dso,
- .sym = sym,
- .ip = ip,
- .level = level,
- .count = count,
- .parent = NULL,
- .sorted_chain = RB_ROOT
- };
- int cmp;
if ((sort__has_parent || callchain) && chain)
- syms = resolve_callchain(thread, map, chain, &entry);
-
- while (*p != NULL) {
- parent = *p;
- he = rb_entry(parent, struct hist_entry, rb_node);
-
- cmp = hist_entry__cmp(&entry, he);
+ syms = resolve_callchain(thread, map, chain, &parent);
- if (!cmp) {
- he->count += count;
- if (callchain) {
- append_chain(&he->callchain, chain, syms);
- free(syms);
- }
- return 0;
- }
+ he = __hist_entry__add(thread, map, sym, parent,
+ ip, count, level, &hit);
+ if (he == NULL)
+ return -ENOMEM;
- if (cmp < 0)
- p = &(*p)->rb_left;
- else
- p = &(*p)->rb_right;
- }
+ if (hit)
+ he->count += count;
- he = malloc(sizeof(*he));
- if (!he)
- return -ENOMEM;
- *he = entry;
if (callchain) {
- callchain_init(&he->callchain);
+ if (!hit)
+ callchain_init(&he->callchain);
append_chain(&he->callchain, chain, syms);
free(syms);
}
- rb_link_node(&he->rb_node, parent, p);
- rb_insert_color(&he->rb_node, &hist);
return 0;
}
-static void hist_entry__free(struct hist_entry *he)
-{
- free(he);
-}
-
-/*
- * collapse the histogram
- */
-
-static struct rb_root collapse_hists;
-
-static void collapse__insert_entry(struct hist_entry *he)
-{
- struct rb_node **p = &collapse_hists.rb_node;
- struct rb_node *parent = NULL;
- struct hist_entry *iter;
- int64_t cmp;
-
- while (*p != NULL) {
- parent = *p;
- iter = rb_entry(parent, struct hist_entry, rb_node);
-
- cmp = hist_entry__collapse(iter, he);
-
- if (!cmp) {
- iter->count += he->count;
- hist_entry__free(he);
- return;
- }
-
- if (cmp < 0)
- p = &(*p)->rb_left;
- else
- p = &(*p)->rb_right;
- }
-
- rb_link_node(&he->rb_node, parent, p);
- rb_insert_color(&he->rb_node, &collapse_hists);
-}
-
-static void collapse__resort(void)
-{
- struct rb_node *next;
- struct hist_entry *n;
-
- if (!sort__need_collapse)
- return;
-
- next = rb_first(&hist);
- while (next) {
- n = rb_entry(next, struct hist_entry, rb_node);
- next = rb_next(&n->rb_node);
-
- rb_erase(&n->rb_node, &hist);
- collapse__insert_entry(n);
- }
-}
-
-/*
- * reverse the map, sort on count.
- */
-
-static struct rb_root output_hists;
-
-static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
-{
- struct rb_node **p = &output_hists.rb_node;
- struct rb_node *parent = NULL;
- struct hist_entry *iter;
-
- if (callchain)
- callchain_param.sort(&he->sorted_chain, &he->callchain,
- min_callchain_hits, &callchain_param);
-
- while (*p != NULL) {
- parent = *p;
- iter = rb_entry(parent, struct hist_entry, rb_node);
-
- if (he->count > iter->count)
- p = &(*p)->rb_left;
- else
- p = &(*p)->rb_right;
- }
-
- rb_link_node(&he->rb_node, parent, p);
- rb_insert_color(&he->rb_node, &output_hists);
-}
-
-static void output__resort(u64 total_samples)
-{
- struct rb_node *next;
- struct hist_entry *n;
- struct rb_root *tree = &hist;
- u64 min_callchain_hits;
-
- min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
-
- if (sort__need_collapse)
- tree = &collapse_hists;
-
- next = rb_first(tree);
-
- while (next) {
- n = rb_entry(next, struct hist_entry, rb_node);
- next = rb_next(&n->rb_node);
-
- rb_erase(&n->rb_node, tree);
- output__insert_entry(n, min_callchain_hits);
- }
-}
-
static size_t output__fprintf(FILE *fp, u64 total_samples)
{
struct hist_entry *pos;
@@ -1080,13 +642,6 @@ print_entries:
return ret;
}
-static unsigned long total = 0,
- total_mmap = 0,
- total_comm = 0,
- total_fork = 0,
- total_unknown = 0,
- total_lost = 0;
-
static int validate_chain(struct ip_callchain *chain, event_t *event)
{
unsigned int chain_size;
@@ -1104,17 +659,14 @@ static int
process_sample_event(event_t *event, unsigned long offset, unsigned long head)
{
char level;
- int show = 0;
- struct dso *dso = NULL;
- struct thread *thread;
+ struct symbol *sym = NULL;
u64 ip = event->ip.ip;
u64 period = 1;
struct map *map = NULL;
void *more_data = event->ip.__more_data;
struct ip_callchain *chain = NULL;
int cpumode;
-
- thread = threads__findnew(event->ip.pid, &threads, &last_match);
+ struct thread *thread = threads__findnew(event->ip.pid);
if (sample_type & PERF_SAMPLE_PERIOD) {
period = *(u64 *)more_data;
@@ -1137,7 +689,8 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
dump_printf("... chain: nr:%Lu\n", chain->nr);
if (validate_chain(chain, event) < 0) {
- eprintf("call-chain problem with event, skipping it.\n");
+ pr_debug("call-chain problem with event, "
+ "skipping it.\n");
return 0;
}
@@ -1147,56 +700,49 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
}
}
- dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
-
if (thread == NULL) {
- eprintf("problem processing %d event, skipping it.\n",
+ pr_debug("problem processing %d event, skipping it.\n",
event->header.type);
return -1;
}
+ dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
+
if (comm_list && !strlist__has_entry(comm_list, thread->comm))
return 0;
cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
if (cpumode == PERF_RECORD_MISC_KERNEL) {
- show = SHOW_KERNEL;
level = 'k';
-
- dso = kernel_dso;
-
- dump_printf(" ...... dso: %s\n", dso->name);
-
+ sym = kernel_maps__find_symbol(ip, &map);
+ dump_printf(" ...... dso: %s\n",
+ map ? map->dso->long_name : "<not found>");
} else if (cpumode == PERF_RECORD_MISC_USER) {
-
- show = SHOW_USER;
level = '.';
+ sym = resolve_symbol(thread, &map, &ip);
} else {
- show = SHOW_HV;
level = 'H';
-
- dso = hypervisor_dso;
-
dump_printf(" ...... dso: [hypervisor]\n");
}
- if (show & show_mask) {
- struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
-
- if (dso_list && (!dso || !dso->name ||
- !strlist__has_entry(dso_list, dso->name)))
- return 0;
+ if (dso_list &&
+ (!map || !map->dso ||
+ !(strlist__has_entry(dso_list, map->dso->short_name) ||
+ (map->dso->short_name != map->dso->long_name &&
+ strlist__has_entry(dso_list, map->dso->long_name)))))
+ return 0;
- if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name)))
- return 0;
+ if (sym_list && sym && !strlist__has_entry(sym_list, sym->name))
+ return 0;
- if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
- eprintf("problem incrementing symbol count, skipping event\n");
- return -1;
- }
+ if (hist_entry__add(thread, map, sym, ip,
+ chain, level, period)) {
+ pr_debug("problem incrementing symbol count, skipping event\n");
+ return -1;
}
+
total += period;
return 0;
@@ -1205,10 +751,8 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
static int
process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
{
- struct thread *thread;
- struct map *map = map__new(&event->mmap, cwd, cwdlen);
-
- thread = threads__findnew(event->mmap.pid, &threads, &last_match);
+ struct map *map = map__new(&event->mmap, cwd, cwdlen, 0, NULL);
+ struct thread *thread = threads__findnew(event->mmap.pid);
dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
(void *)(offset + head),
@@ -1234,9 +778,7 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
static int
process_comm_event(event_t *event, unsigned long offset, unsigned long head)
{
- struct thread *thread;
-
- thread = threads__findnew(event->comm.pid, &threads, &last_match);
+ struct thread *thread = threads__findnew(event->comm.pid);
dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
(void *)(offset + head),
@@ -1256,11 +798,8 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
static int
process_task_event(event_t *event, unsigned long offset, unsigned long head)
{
- struct thread *thread;
- struct thread *parent;
-
- thread = threads__findnew(event->fork.pid, &threads, &last_match);
- parent = threads__findnew(event->fork.ppid, &threads, &last_match);
+ struct thread *thread = threads__findnew(event->fork.pid);
+ struct thread *parent = threads__findnew(event->fork.ppid);
dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n",
(void *)(offset + head),
@@ -1331,216 +870,79 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head)
return 0;
}
-static int
-process_event(event_t *event, unsigned long offset, unsigned long head)
-{
- trace_event(event);
-
- switch (event->header.type) {
- case PERF_RECORD_SAMPLE:
- return process_sample_event(event, offset, head);
-
- case PERF_RECORD_MMAP:
- return process_mmap_event(event, offset, head);
-
- case PERF_RECORD_COMM:
- return process_comm_event(event, offset, head);
-
- case PERF_RECORD_FORK:
- case PERF_RECORD_EXIT:
- return process_task_event(event, offset, head);
-
- case PERF_RECORD_LOST:
- return process_lost_event(event, offset, head);
-
- case PERF_RECORD_READ:
- return process_read_event(event, offset, head);
-
- /*
- * We dont process them right now but they are fine:
- */
-
- case PERF_RECORD_THROTTLE:
- case PERF_RECORD_UNTHROTTLE:
- return 0;
-
- default:
- return -1;
- }
-
- return 0;
-}
-
-static int __cmd_report(void)
+static int sample_type_check(u64 type)
{
- int ret, rc = EXIT_FAILURE;
- unsigned long offset = 0;
- unsigned long head, shift;
- struct stat input_stat;
- struct thread *idle;
- event_t *event;
- uint32_t size;
- char *buf;
-
- idle = register_idle_thread(&threads, &last_match);
- thread__comm_adjust(idle);
-
- if (show_threads)
- perf_read_values_init(&show_threads_values);
-
- input = open(input_name, O_RDONLY);
- if (input < 0) {
- fprintf(stderr, " failed to open file: %s", input_name);
- if (!strcmp(input_name, "perf.data"))
- fprintf(stderr, " (try 'perf record' first)");
- fprintf(stderr, "\n");
- exit(-1);
- }
-
- ret = fstat(input, &input_stat);
- if (ret < 0) {
- perror("failed to stat file");
- exit(-1);
- }
-
- if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
- fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
- exit(-1);
- }
-
- if (!input_stat.st_size) {
- fprintf(stderr, "zero-sized file, nothing to do!\n");
- exit(0);
- }
-
- header = perf_header__read(input);
- head = header->data_offset;
-
- sample_type = perf_header__sample_type(header);
+ sample_type = type;
if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
if (sort__has_parent) {
fprintf(stderr, "selected --sort parent, but no"
" callchain data. Did you call"
" perf record without -g?\n");
- exit(-1);
+ return -1;
}
if (callchain) {
fprintf(stderr, "selected -g but no callchain data."
" Did you call perf record without"
" -g?\n");
- exit(-1);
+ return -1;
}
} else if (callchain_param.mode != CHAIN_NONE && !callchain) {
callchain = 1;
if (register_callchain_param(&callchain_param) < 0) {
fprintf(stderr, "Can't register callchain"
" params\n");
- exit(-1);
+ return -1;
}
}
- if (load_kernel() < 0) {
- perror("failed to load kernel symbols");
- return EXIT_FAILURE;
- }
-
- if (!full_paths) {
- if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
- perror("failed to get the current directory");
- return EXIT_FAILURE;
- }
- cwdlen = strlen(cwd);
- } else {
- cwd = NULL;
- cwdlen = 0;
- }
-
- shift = page_size * (head / page_size);
- offset += shift;
- head -= shift;
-
-remap:
- buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
- MAP_SHARED, input, offset);
- if (buf == MAP_FAILED) {
- perror("failed to mmap file");
- exit(-1);
- }
-
-more:
- event = (event_t *)(buf + head);
-
- size = event->header.size;
- if (!size)
- size = 8;
-
- if (head + event->header.size >= page_size * mmap_window) {
- int munmap_ret;
-
- shift = page_size * (head / page_size);
-
- munmap_ret = munmap(buf, page_size * mmap_window);
- assert(munmap_ret == 0);
-
- offset += shift;
- head -= shift;
- goto remap;
- }
-
- size = event->header.size;
-
- dump_printf("\n%p [%p]: event: %d\n",
- (void *)(offset + head),
- (void *)(long)event->header.size,
- event->header.type);
-
- if (!size || process_event(event, offset, head) < 0) {
-
- dump_printf("%p [%p]: skipping unknown header type: %d\n",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
- event->header.type);
-
- total_unknown++;
+ return 0;
+}
- /*
- * assume we lost track of the stream, check alignment, and
- * increment a single u64 in the hope to catch on again 'soon'.
- */
+static struct perf_file_handler file_handler = {
+ .process_sample_event = process_sample_event,
+ .process_mmap_event = process_mmap_event,
+ .process_comm_event = process_comm_event,
+ .process_exit_event = process_task_event,
+ .process_fork_event = process_task_event,
+ .process_lost_event = process_lost_event,
+ .process_read_event = process_read_event,
+ .sample_type_check = sample_type_check,
+};
- if (unlikely(head & 7))
- head &= ~7ULL;
- size = 8;
- }
+static int __cmd_report(void)
+{
+ struct thread *idle;
+ int ret;
- head += size;
+ idle = register_idle_thread();
+ thread__comm_adjust(idle);
- if (offset + head >= header->data_offset + header->data_size)
- goto done;
+ if (show_threads)
+ perf_read_values_init(&show_threads_values);
- if (offset + head < (unsigned long)input_stat.st_size)
- goto more;
+ register_perf_file_handler(&file_handler);
-done:
- rc = EXIT_SUCCESS;
- close(input);
+ ret = mmap_dispatch_perf_file(&header, input_name, force, full_paths,
+ &cwdlen, &cwd);
+ if (ret)
+ return ret;
dump_printf(" IP events: %10ld\n", total);
dump_printf(" mmap events: %10ld\n", total_mmap);
dump_printf(" comm events: %10ld\n", total_comm);
dump_printf(" fork events: %10ld\n", total_fork);
dump_printf(" lost events: %10ld\n", total_lost);
- dump_printf(" unknown events: %10ld\n", total_unknown);
+ dump_printf(" unknown events: %10ld\n", file_handler.total_unknown);
if (dump_trace)
return 0;
- if (verbose >= 3)
- threads__fprintf(stdout, &threads);
+ if (verbose > 3)
+ threads__fprintf(stdout);
- if (verbose >= 2)
+ if (verbose > 2)
dsos__fprintf(stdout);
collapse__resort();
@@ -1550,7 +952,7 @@ done:
if (show_threads)
perf_read_values_destroy(&show_threads_values);
- return rc;
+ return ret;
}
static int
@@ -1606,7 +1008,8 @@ setup:
return 0;
}
-static const char * const report_usage[] = {
+//static const char * const report_usage[] = {
+const char * const report_usage[] = {
"perf report [<options>] <command>",
NULL
};
@@ -1692,8 +1095,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
{
symbol__init();
- page_size = getpagesize();
-
argc = parse_options(argc, argv, options, report_usage, 0);
setup_sorting();
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index ce2d5be4f30e..9a48d9626be4 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -11,6 +11,7 @@
#include "util/trace-event.h"
#include "util/debug.h"
+#include "util/data_map.h"
#include <sys/types.h>
#include <sys/prctl.h>
@@ -20,26 +21,23 @@
#include <math.h>
static char const *input_name = "perf.data";
-static int input;
-static unsigned long page_size;
-static unsigned long mmap_window = 32;
static unsigned long total_comm = 0;
-static struct rb_root threads;
-static struct thread *last_match;
-
static struct perf_header *header;
static u64 sample_type;
static char default_sort_order[] = "avg, max, switch, runtime";
static char *sort_order = default_sort_order;
+static int profile_cpu = -1;
+
+static char *cwd;
+static int cwdlen;
+
#define PR_SET_NAME 15 /* Set process name */
#define MAX_CPUS 4096
-#define BUG_ON(x) assert(!(x))
-
static u64 run_measurement_overhead;
static u64 sleep_measurement_overhead;
@@ -74,6 +72,7 @@ enum sched_event_type {
SCHED_EVENT_RUN,
SCHED_EVENT_SLEEP,
SCHED_EVENT_WAKEUP,
+ SCHED_EVENT_MIGRATION,
};
struct sched_atom {
@@ -398,6 +397,8 @@ process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom)
ret = sem_post(atom->wait_sem);
BUG_ON(ret);
break;
+ case SCHED_EVENT_MIGRATION:
+ break;
default:
BUG_ON(1);
}
@@ -635,9 +636,7 @@ static void test_calibrations(void)
static int
process_comm_event(event_t *event, unsigned long offset, unsigned long head)
{
- struct thread *thread;
-
- thread = threads__findnew(event->comm.pid, &threads, &last_match);
+ struct thread *thread = threads__findnew(event->comm.tid);
dump_printf("%p [%p]: perf_event_comm: %s:%d\n",
(void *)(offset + head),
@@ -745,6 +744,22 @@ struct trace_fork_event {
u32 child_pid;
};
+struct trace_migrate_task_event {
+ u32 size;
+
+ u16 common_type;
+ u8 common_flags;
+ u8 common_preempt_count;
+ u32 common_pid;
+ u32 common_tgid;
+
+ char comm[16];
+ u32 pid;
+
+ u32 prio;
+ u32 cpu;
+};
+
struct trace_sched_handler {
void (*switch_event)(struct trace_switch_event *,
struct event *,
@@ -769,6 +784,12 @@ struct trace_sched_handler {
int cpu,
u64 timestamp,
struct thread *thread);
+
+ void (*migrate_task_event)(struct trace_migrate_task_event *,
+ struct event *,
+ int cpu,
+ u64 timestamp,
+ struct thread *thread);
};
@@ -1058,8 +1079,8 @@ latency_switch_event(struct trace_switch_event *switch_event,
die("hm, delta: %Ld < 0 ?\n", delta);
- sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match);
- sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match);
+ sched_out = threads__findnew(switch_event->prev_pid);
+ sched_in = threads__findnew(switch_event->next_pid);
out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
if (!out_events) {
@@ -1092,13 +1113,10 @@ latency_runtime_event(struct trace_runtime_event *runtime_event,
u64 timestamp,
struct thread *this_thread __used)
{
- struct work_atoms *atoms;
- struct thread *thread;
+ struct thread *thread = threads__findnew(runtime_event->pid);
+ struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
BUG_ON(cpu >= MAX_CPUS || cpu < 0);
-
- thread = threads__findnew(runtime_event->pid, &threads, &last_match);
- atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
if (!atoms) {
thread_atoms_insert(thread);
atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
@@ -1125,7 +1143,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
if (!wakeup_event->success)
return;
- wakee = threads__findnew(wakeup_event->pid, &threads, &last_match);
+ wakee = threads__findnew(wakeup_event->pid);
atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
if (!atoms) {
thread_atoms_insert(wakee);
@@ -1139,7 +1157,12 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
atom = list_entry(atoms->work_list.prev, struct work_atom, list);
- if (atom->state != THREAD_SLEEPING)
+ /*
+ * You WILL be missing events if you've recorded only
+ * one CPU, or are only looking at only one, so don't
+ * make useless noise.
+ */
+ if (profile_cpu == -1 && atom->state != THREAD_SLEEPING)
nr_state_machine_bugs++;
nr_timestamps++;
@@ -1152,11 +1175,51 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
atom->wake_up_time = timestamp;
}
+static void
+latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
+ struct event *__event __used,
+ int cpu __used,
+ u64 timestamp,
+ struct thread *thread __used)
+{
+ struct work_atoms *atoms;
+ struct work_atom *atom;
+ struct thread *migrant;
+
+ /*
+ * Only need to worry about migration when profiling one CPU.
+ */
+ if (profile_cpu == -1)
+ return;
+
+ migrant = threads__findnew(migrate_task_event->pid);
+ atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
+ if (!atoms) {
+ thread_atoms_insert(migrant);
+ register_pid(migrant->pid, migrant->comm);
+ atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
+ if (!atoms)
+ die("migration-event: Internal tree error");
+ add_sched_out_event(atoms, 'R', timestamp);
+ }
+
+ BUG_ON(list_empty(&atoms->work_list));
+
+ atom = list_entry(atoms->work_list.prev, struct work_atom, list);
+ atom->sched_in_time = atom->sched_out_time = atom->wake_up_time = timestamp;
+
+ nr_timestamps++;
+
+ if (atom->sched_out_time > timestamp)
+ nr_unordered_timestamps++;
+}
+
static struct trace_sched_handler lat_ops = {
.wakeup_event = latency_wakeup_event,
.switch_event = latency_switch_event,
.runtime_event = latency_runtime_event,
.fork_event = latency_fork_event,
+ .migrate_task_event = latency_migrate_task_event,
};
static void output_lat_thread(struct work_atoms *work_list)
@@ -1385,8 +1448,8 @@ map_switch_event(struct trace_switch_event *switch_event,
die("hm, delta: %Ld < 0 ?\n", delta);
- sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match);
- sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match);
+ sched_out = threads__findnew(switch_event->prev_pid);
+ sched_in = threads__findnew(switch_event->next_pid);
curr_thread[this_cpu] = sched_in;
@@ -1517,6 +1580,26 @@ process_sched_exit_event(struct event *event,
}
static void
+process_sched_migrate_task_event(struct raw_event_sample *raw,
+ struct event *event,
+ int cpu __used,
+ u64 timestamp __used,
+ struct thread *thread __used)
+{
+ struct trace_migrate_task_event migrate_task_event;
+
+ FILL_COMMON_FIELDS(migrate_task_event, event, raw->data);
+
+ FILL_ARRAY(migrate_task_event, comm, event, raw->data);
+ FILL_FIELD(migrate_task_event, pid, event, raw->data);
+ FILL_FIELD(migrate_task_event, prio, event, raw->data);
+ FILL_FIELD(migrate_task_event, cpu, event, raw->data);
+
+ if (trace_handler->migrate_task_event)
+ trace_handler->migrate_task_event(&migrate_task_event, event, cpu, timestamp, thread);
+}
+
+static void
process_raw_event(event_t *raw_event __used, void *more_data,
int cpu, u64 timestamp, struct thread *thread)
{
@@ -1539,23 +1622,24 @@ process_raw_event(event_t *raw_event __used, void *more_data,
process_sched_fork_event(raw, event, cpu, timestamp, thread);
if (!strcmp(event->name, "sched_process_exit"))
process_sched_exit_event(event, cpu, timestamp, thread);
+ if (!strcmp(event->name, "sched_migrate_task"))
+ process_sched_migrate_task_event(raw, event, cpu, timestamp, thread);
}
static int
process_sample_event(event_t *event, unsigned long offset, unsigned long head)
{
- char level;
- int show = 0;
- struct dso *dso = NULL;
struct thread *thread;
u64 ip = event->ip.ip;
u64 timestamp = -1;
u32 cpu = -1;
u64 period = 1;
void *more_data = event->ip.__more_data;
- int cpumode;
- thread = threads__findnew(event->ip.pid, &threads, &last_match);
+ if (!(sample_type & PERF_SAMPLE_RAW))
+ return 0;
+
+ thread = threads__findnew(event->ip.pid);
if (sample_type & PERF_SAMPLE_TIME) {
timestamp = *(u64 *)more_data;
@@ -1581,169 +1665,60 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
(void *)(long)ip,
(long long)period);
- dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
-
if (thread == NULL) {
- eprintf("problem processing %d event, skipping it.\n",
- event->header.type);
+ pr_debug("problem processing %d event, skipping it.\n",
+ event->header.type);
return -1;
}
- cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
-
- if (cpumode == PERF_RECORD_MISC_KERNEL) {
- show = SHOW_KERNEL;
- level = 'k';
-
- dso = kernel_dso;
-
- dump_printf(" ...... dso: %s\n", dso->name);
-
- } else if (cpumode == PERF_RECORD_MISC_USER) {
-
- show = SHOW_USER;
- level = '.';
-
- } else {
- show = SHOW_HV;
- level = 'H';
-
- dso = hypervisor_dso;
+ dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
- dump_printf(" ...... dso: [hypervisor]\n");
- }
+ if (profile_cpu != -1 && profile_cpu != (int) cpu)
+ return 0;
- if (sample_type & PERF_SAMPLE_RAW)
- process_raw_event(event, more_data, cpu, timestamp, thread);
+ process_raw_event(event, more_data, cpu, timestamp, thread);
return 0;
}
static int
-process_event(event_t *event, unsigned long offset, unsigned long head)
+process_lost_event(event_t *event __used,
+ unsigned long offset __used,
+ unsigned long head __used)
{
- trace_event(event);
+ nr_lost_chunks++;
+ nr_lost_events += event->lost.lost;
- nr_events++;
- switch (event->header.type) {
- case PERF_RECORD_MMAP:
- return 0;
- case PERF_RECORD_LOST:
- nr_lost_chunks++;
- nr_lost_events += event->lost.lost;
- return 0;
-
- case PERF_RECORD_COMM:
- return process_comm_event(event, offset, head);
-
- case PERF_RECORD_EXIT ... PERF_RECORD_READ:
- return 0;
+ return 0;
+}
- case PERF_RECORD_SAMPLE:
- return process_sample_event(event, offset, head);
+static int sample_type_check(u64 type)
+{
+ sample_type = type;
- case PERF_RECORD_MAX:
- default:
+ if (!(sample_type & PERF_SAMPLE_RAW)) {
+ fprintf(stderr,
+ "No trace sample to read. Did you call perf record "
+ "without -R?");
return -1;
}
return 0;
}
+static struct perf_file_handler file_handler = {
+ .process_sample_event = process_sample_event,
+ .process_comm_event = process_comm_event,
+ .process_lost_event = process_lost_event,
+ .sample_type_check = sample_type_check,
+};
+
static int read_events(void)
{
- int ret, rc = EXIT_FAILURE;
- unsigned long offset = 0;
- unsigned long head = 0;
- struct stat perf_stat;
- event_t *event;
- uint32_t size;
- char *buf;
-
- trace_report();
- register_idle_thread(&threads, &last_match);
-
- input = open(input_name, O_RDONLY);
- if (input < 0) {
- perror("failed to open file");
- exit(-1);
- }
-
- ret = fstat(input, &perf_stat);
- if (ret < 0) {
- perror("failed to stat file");
- exit(-1);
- }
-
- if (!perf_stat.st_size) {
- fprintf(stderr, "zero-sized file, nothing to do!\n");
- exit(0);
- }
- header = perf_header__read(input);
- head = header->data_offset;
- sample_type = perf_header__sample_type(header);
-
- if (!(sample_type & PERF_SAMPLE_RAW))
- die("No trace sample to read. Did you call perf record "
- "without -R?");
-
- if (load_kernel() < 0) {
- perror("failed to load kernel symbols");
- return EXIT_FAILURE;
- }
-
-remap:
- buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
- MAP_SHARED, input, offset);
- if (buf == MAP_FAILED) {
- perror("failed to mmap file");
- exit(-1);
- }
-
-more:
- event = (event_t *)(buf + head);
-
- size = event->header.size;
- if (!size)
- size = 8;
-
- if (head + event->header.size >= page_size * mmap_window) {
- unsigned long shift = page_size * (head / page_size);
- int res;
-
- res = munmap(buf, page_size * mmap_window);
- assert(res == 0);
-
- offset += shift;
- head -= shift;
- goto remap;
- }
-
- size = event->header.size;
-
-
- if (!size || process_event(event, offset, head) < 0) {
-
- /*
- * assume we lost track of the stream, check alignment, and
- * increment a single u64 in the hope to catch on again 'soon'.
- */
-
- if (unlikely(head & 7))
- head &= ~7ULL;
-
- size = 8;
- }
-
- head += size;
-
- if (offset + head < (unsigned long)perf_stat.st_size)
- goto more;
-
- rc = EXIT_SUCCESS;
- close(input);
+ register_idle_thread();
+ register_perf_file_handler(&file_handler);
- return rc;
+ return mmap_dispatch_perf_file(&header, input_name, 0, 0, &cwdlen, &cwd);
}
static void print_bad_events(void)
@@ -1883,6 +1858,8 @@ static const struct option latency_options[] = {
"sort by key(s): runtime, switch, avg, max"),
OPT_BOOLEAN('v', "verbose", &verbose,
"be more verbose (show symbol address, etc)"),
+ OPT_INTEGER('C', "CPU", &profile_cpu,
+ "CPU to profile on"),
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
"dump raw trace in ASCII"),
OPT_END()
@@ -1961,7 +1938,6 @@ static int __cmd_record(int argc, const char **argv)
int cmd_sched(int argc, const char **argv, const char *prefix __used)
{
symbol__init();
- page_size = getpagesize();
argc = parse_options(argc, argv, sched_options, sched_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 3db31e7bf173..c6df3770b87e 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -50,15 +50,17 @@
static struct perf_event_attr default_attrs[] = {
- { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
- { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES},
- { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS },
- { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
-
- { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES },
- { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS },
- { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES},
- { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES },
+ { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
+ { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES },
+ { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS },
+ { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
+
+ { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES },
+ { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS },
+ { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
+ { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES },
+ { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES },
+ { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES },
};
@@ -125,6 +127,7 @@ struct stats event_res_stats[MAX_COUNTERS][3];
struct stats runtime_nsecs_stats;
struct stats walltime_nsecs_stats;
struct stats runtime_cycles_stats;
+struct stats runtime_branches_stats;
#define MATCH_EVENT(t, c, counter) \
(attrs[counter].type == PERF_TYPE_##t && \
@@ -235,6 +238,8 @@ static void read_counter(int counter)
update_stats(&runtime_nsecs_stats, count[0]);
if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter))
update_stats(&runtime_cycles_stats, count[0]);
+ if (MATCH_EVENT(HARDWARE, HW_BRANCH_INSTRUCTIONS, counter))
+ update_stats(&runtime_branches_stats, count[0]);
}
static int run_perf_stat(int argc __used, const char **argv)
@@ -352,6 +357,14 @@ static void abs_printout(int counter, double avg)
ratio = avg / total;
fprintf(stderr, " # %10.3f IPC ", ratio);
+ } else if (MATCH_EVENT(HARDWARE, HW_BRANCH_MISSES, counter)) {
+ total = avg_stats(&runtime_branches_stats);
+
+ if (total)
+ ratio = avg * 100 / total;
+
+ fprintf(stderr, " # %10.3f %% ", ratio);
+
} else {
total = avg_stats(&runtime_nsecs_stats);
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 702d8fe58fbc..0a2f22261c3a 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -153,6 +153,17 @@ static struct wake_event *wake_events;
struct sample_wrapper *all_samples;
+
+struct process_filter;
+struct process_filter {
+ char *name;
+ int pid;
+ struct process_filter *next;
+};
+
+static struct process_filter *process_filter;
+
+
static struct per_pid *find_create_pid(int pid)
{
struct per_pid *cursor = all_data;
@@ -763,21 +774,42 @@ static void draw_wakeups(void)
c = p->all;
while (c) {
if (c->Y && c->start_time <= we->time && c->end_time >= we->time) {
- if (p->pid == we->waker) {
+ if (p->pid == we->waker && !from) {
from = c->Y;
- task_from = c->comm;
+ task_from = strdup(c->comm);
}
- if (p->pid == we->wakee) {
+ if (p->pid == we->wakee && !to) {
to = c->Y;
- task_to = c->comm;
+ task_to = strdup(c->comm);
}
}
c = c->next;
}
+ c = p->all;
+ while (c) {
+ if (p->pid == we->waker && !from) {
+ from = c->Y;
+ task_from = strdup(c->comm);
+ }
+ if (p->pid == we->wakee && !to) {
+ to = c->Y;
+ task_to = strdup(c->comm);
+ }
+ c = c->next;
+ }
}
p = p->next;
}
+ if (!task_from) {
+ task_from = malloc(40);
+ sprintf(task_from, "[%i]", we->waker);
+ }
+ if (!task_to) {
+ task_to = malloc(40);
+ sprintf(task_to, "[%i]", we->wakee);
+ }
+
if (we->waker == -1)
svg_interrupt(we->time, to);
else if (from && to && abs(from - to) == 1)
@@ -785,6 +817,9 @@ static void draw_wakeups(void)
else
svg_partial_wakeline(we->time, from, task_from, to, task_to);
we = we->next;
+
+ free(task_from);
+ free(task_to);
}
}
@@ -858,12 +893,89 @@ static void draw_process_bars(void)
}
}
+static void add_process_filter(const char *string)
+{
+ struct process_filter *filt;
+ int pid;
+
+ pid = strtoull(string, NULL, 10);
+ filt = malloc(sizeof(struct process_filter));
+ if (!filt)
+ return;
+
+ filt->name = strdup(string);
+ filt->pid = pid;
+ filt->next = process_filter;
+
+ process_filter = filt;
+}
+
+static int passes_filter(struct per_pid *p, struct per_pidcomm *c)
+{
+ struct process_filter *filt;
+ if (!process_filter)
+ return 1;
+
+ filt = process_filter;
+ while (filt) {
+ if (filt->pid && p->pid == filt->pid)
+ return 1;
+ if (strcmp(filt->name, c->comm) == 0)
+ return 1;
+ filt = filt->next;
+ }
+ return 0;
+}
+
+static int determine_display_tasks_filtered(void)
+{
+ struct per_pid *p;
+ struct per_pidcomm *c;
+ int count = 0;
+
+ p = all_data;
+ while (p) {
+ p->display = 0;
+ if (p->start_time == 1)
+ p->start_time = first_time;
+
+ /* no exit marker, task kept running to the end */
+ if (p->end_time == 0)
+ p->end_time = last_time;
+
+ c = p->all;
+
+ while (c) {
+ c->display = 0;
+
+ if (c->start_time == 1)
+ c->start_time = first_time;
+
+ if (passes_filter(p, c)) {
+ c->display = 1;
+ p->display = 1;
+ count++;
+ }
+
+ if (c->end_time == 0)
+ c->end_time = last_time;
+
+ c = c->next;
+ }
+ p = p->next;
+ }
+ return count;
+}
+
static int determine_display_tasks(u64 threshold)
{
struct per_pid *p;
struct per_pidcomm *c;
int count = 0;
+ if (process_filter)
+ return determine_display_tasks_filtered();
+
p = all_data;
while (p) {
p->display = 0;
@@ -1050,12 +1162,10 @@ more:
size = event->header.size;
if (!size || process_event(event) < 0) {
-
- printf("%p [%p]: skipping unknown header type: %d\n",
- (void *)(offset + head),
- (void *)(long)(event->header.size),
- event->header.type);
-
+ pr_warning("%p [%p]: skipping unknown header type: %d\n",
+ (void *)(offset + head),
+ (void *)(long)(event->header.size),
+ event->header.type);
/*
* assume we lost track of the stream, check alignment, and
* increment a single u64 in the hope to catch on again 'soon'.
@@ -1088,7 +1198,8 @@ done:
write_svg_file(output_name);
- printf("Written %2.1f seconds of trace to %s.\n", (last_time - first_time) / 1000000000.0, output_name);
+ pr_info("Written %2.1f seconds of trace to %s.\n",
+ (last_time - first_time) / 1000000000.0, output_name);
return rc;
}
@@ -1129,6 +1240,14 @@ static int __cmd_record(int argc, const char **argv)
return cmd_record(i, rec_argv, NULL);
}
+static int
+parse_process(const struct option *opt __used, const char *arg, int __used unset)
+{
+ if (arg)
+ add_process_filter(arg);
+ return 0;
+}
+
static const struct option options[] = {
OPT_STRING('i', "input", &input_name, "file",
"input file name"),
@@ -1136,8 +1255,11 @@ static const struct option options[] = {
"output file name"),
OPT_INTEGER('w', "width", &svg_page_width,
"page width"),
- OPT_BOOLEAN('p', "power-only", &power_only,
+ OPT_BOOLEAN('P', "power-only", &power_only,
"output power data only"),
+ OPT_CALLBACK('p', "process", NULL, "process",
+ "process selector. Pass a pid or process name.",
+ parse_process),
OPT_END()
};
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 37512e936235..a02fc4146017 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -22,6 +22,7 @@
#include "util/symbol.h"
#include "util/color.h"
+#include "util/thread.h"
#include "util/util.h"
#include <linux/rbtree.h>
#include "util/parse-options.h"
@@ -54,26 +55,26 @@
static int fd[MAX_NR_CPUS][MAX_COUNTERS];
-static int system_wide = 0;
+static int system_wide = 0;
-static int default_interval = 100000;
+static int default_interval = 0;
-static int count_filter = 5;
-static int print_entries = 15;
+static int count_filter = 5;
+static int print_entries = 15;
-static int target_pid = -1;
-static int inherit = 0;
-static int profile_cpu = -1;
-static int nr_cpus = 0;
-static unsigned int realtime_prio = 0;
-static int group = 0;
+static int target_pid = -1;
+static int inherit = 0;
+static int profile_cpu = -1;
+static int nr_cpus = 0;
+static unsigned int realtime_prio = 0;
+static int group = 0;
static unsigned int page_size;
-static unsigned int mmap_pages = 16;
-static int freq = 0;
+static unsigned int mmap_pages = 16;
+static int freq = 1000; /* 1 KHz */
-static int delay_secs = 2;
-static int zero;
-static int dump_symtab;
+static int delay_secs = 2;
+static int zero = 0;
+static int dump_symtab = 0;
/*
* Source
@@ -86,19 +87,16 @@ struct source_line {
struct source_line *next;
};
-static char *sym_filter = NULL;
-struct sym_entry *sym_filter_entry = NULL;
-static int sym_pcnt_filter = 5;
-static int sym_counter = 0;
-static int display_weighted = -1;
+static char *sym_filter = NULL;
+struct sym_entry *sym_filter_entry = NULL;
+static int sym_pcnt_filter = 5;
+static int sym_counter = 0;
+static int display_weighted = -1;
/*
* Symbols
*/
-static u64 min_ip;
-static u64 max_ip = -1ll;
-
struct sym_entry {
struct rb_node rb_node;
struct list_head node;
@@ -106,6 +104,7 @@ struct sym_entry {
unsigned long snap_count;
double weight;
int skip;
+ struct map *map;
struct source_line *source;
struct source_line *lines;
struct source_line **lines_tail;
@@ -119,12 +118,11 @@ struct sym_entry {
static void parse_source(struct sym_entry *syme)
{
struct symbol *sym;
- struct module *module;
- struct section *section = NULL;
+ struct map *map;
FILE *file;
char command[PATH_MAX*2];
- const char *path = vmlinux_name;
- u64 start, end, len;
+ const char *path;
+ u64 len;
if (!syme)
return;
@@ -135,27 +133,16 @@ static void parse_source(struct sym_entry *syme)
}
sym = (struct symbol *)(syme + 1);
- module = sym->module;
-
- if (module)
- path = module->path;
- if (!path)
- return;
-
- start = sym->obj_start;
- if (!start)
- start = sym->start;
+ map = syme->map;
+ path = map->dso->long_name;
- if (module) {
- section = module->sections->find_section(module->sections, ".text");
- if (section)
- start -= section->vma;
- }
-
- end = start + sym->end - sym->start + 1;
len = sym->end - sym->start;
- sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", start, end, path);
+ sprintf(command,
+ "objdump --start-address=0x%016Lx "
+ "--stop-address=0x%016Lx -dS %s",
+ map->unmap_ip(map, sym->start),
+ map->unmap_ip(map, sym->end), path);
file = popen(command, "r");
if (!file)
@@ -187,13 +174,11 @@ static void parse_source(struct sym_entry *syme)
if (strlen(src->line)>8 && src->line[8] == ':') {
src->eip = strtoull(src->line, NULL, 16);
- if (section)
- src->eip += section->vma;
+ src->eip = map->unmap_ip(map, src->eip);
}
if (strlen(src->line)>8 && src->line[16] == ':') {
src->eip = strtoull(src->line, NULL, 16);
- if (section)
- src->eip += section->vma;
+ src->eip = map->unmap_ip(map, src->eip);
}
}
pclose(file);
@@ -245,16 +230,9 @@ static void lookup_sym_source(struct sym_entry *syme)
struct symbol *symbol = (struct symbol *)(syme + 1);
struct source_line *line;
char pattern[PATH_MAX];
- char *idx;
sprintf(pattern, "<%s>:", symbol->name);
- if (symbol->module) {
- idx = strstr(pattern, "\t");
- if (idx)
- *idx = 0;
- }
-
pthread_mutex_lock(&syme->source_lock);
for (line = syme->lines; line; line = line->next) {
if (strstr(line->line, pattern)) {
@@ -340,7 +318,7 @@ static void show_details(struct sym_entry *syme)
}
/*
- * Symbols will be added here in record_ip and will get out
+ * Symbols will be added here in event__process_sample and will get out
* after decayed.
*/
static LIST_HEAD(active_symbols);
@@ -481,18 +459,18 @@ static void print_sym_table(void)
}
if (nr_counters == 1)
- printf(" samples pcnt");
+ printf(" samples pcnt");
else
- printf(" weight samples pcnt");
+ printf(" weight samples pcnt");
if (verbose)
printf(" RIP ");
- printf(" kernel function\n");
- printf(" %s _______ _____",
+ printf(" function DSO\n");
+ printf(" %s _______ _____",
nr_counters == 1 ? " " : "______");
if (verbose)
- printf(" ________________");
- printf(" _______________\n\n");
+ printf(" ________________");
+ printf(" ________________________________ ________________\n\n");
for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
struct symbol *sym;
@@ -508,16 +486,15 @@ static void print_sym_table(void)
sum_ksamples));
if (nr_counters == 1 || !display_weighted)
- printf("%20.2f - ", syme->weight);
+ printf("%20.2f ", syme->weight);
else
- printf("%9.1f %10ld - ", syme->weight, syme->snap_count);
+ printf("%9.1f %10ld ", syme->weight, syme->snap_count);
percent_color_fprintf(stdout, "%4.1f%%", pcnt);
if (verbose)
- printf(" - %016llx", sym->start);
- printf(" : %s", sym->name);
- if (sym->module)
- printf("\t[%s]", sym->module->name);
+ printf(" %016llx", sym->start);
+ printf(" %-32s", sym->name);
+ printf(" %s", syme->map->dso->short_name);
printf("\n");
}
}
@@ -686,6 +663,8 @@ static void handle_keypress(int c)
switch (c) {
case 'd':
prompt_integer(&delay_secs, "Enter display delay");
+ if (delay_secs < 1)
+ delay_secs = 1;
break;
case 'e':
prompt_integer(&print_entries, "Enter display entries (lines)");
@@ -788,7 +767,7 @@ static const char *skip_symbols[] = {
NULL
};
-static int symbol_filter(struct dso *self, struct symbol *sym)
+static int symbol_filter(struct map *map, struct symbol *sym)
{
struct sym_entry *syme;
const char *name = sym->name;
@@ -810,7 +789,8 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
strstr(name, "_text_end"))
return 1;
- syme = dso__sym_priv(self, sym);
+ syme = dso__sym_priv(map->dso, sym);
+ syme->map = map;
pthread_mutex_init(&syme->source_lock, NULL);
if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter))
sym_filter_entry = syme;
@@ -827,70 +807,107 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
static int parse_symbols(void)
{
- struct rb_node *node;
- struct symbol *sym;
- int use_modules = vmlinux_name ? 1 : 0;
-
- kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
- if (kernel_dso == NULL)
+ if (dsos__load_kernel(vmlinux_name, sizeof(struct sym_entry),
+ symbol_filter, 1) <= 0)
return -1;
- if (dso__load_kernel(kernel_dso, vmlinux_name, symbol_filter, verbose, use_modules) <= 0)
- goto out_delete_dso;
-
- node = rb_first(&kernel_dso->syms);
- sym = rb_entry(node, struct symbol, rb_node);
- min_ip = sym->start;
-
- node = rb_last(&kernel_dso->syms);
- sym = rb_entry(node, struct symbol, rb_node);
- max_ip = sym->end;
-
if (dump_symtab)
- dso__fprintf(kernel_dso, stderr);
+ dsos__fprintf(stderr);
return 0;
-
-out_delete_dso:
- dso__delete(kernel_dso);
- kernel_dso = NULL;
- return -1;
}
-/*
- * Binary search in the histogram table and record the hit:
- */
-static void record_ip(u64 ip, int counter)
+static void event__process_sample(const event_t *self, int counter)
{
- struct symbol *sym = dso__find_symbol(kernel_dso, ip);
-
- if (sym != NULL) {
- struct sym_entry *syme = dso__sym_priv(kernel_dso, sym);
-
- if (!syme->skip) {
- syme->count[counter]++;
- record_precise_ip(syme, counter, ip);
- pthread_mutex_lock(&active_symbols_lock);
- if (list_empty(&syme->node) || !syme->node.next)
- __list_insert_active_sym(syme);
- pthread_mutex_unlock(&active_symbols_lock);
+ u64 ip = self->ip.ip;
+ struct map *map;
+ struct sym_entry *syme;
+ struct symbol *sym;
+
+ switch (self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK) {
+ case PERF_RECORD_MISC_USER: {
+ struct thread *thread = threads__findnew(self->ip.pid);
+
+ if (thread == NULL)
return;
+
+ map = thread__find_map(thread, ip);
+ if (map != NULL) {
+ ip = map->map_ip(map, ip);
+ sym = map->dso->find_symbol(map->dso, ip);
+ if (sym == NULL)
+ return;
+ userspace_samples++;
+ break;
}
}
+ /*
+ * If this is outside of all known maps,
+ * and is a negative address, try to look it
+ * up in the kernel dso, as it might be a
+ * vsyscall or vdso (which executes in user-mode).
+ */
+ if ((long long)ip >= 0)
+ return;
+ /* Fall thru */
+ case PERF_RECORD_MISC_KERNEL:
+ sym = kernel_maps__find_symbol(ip, &map);
+ if (sym == NULL)
+ return;
+ break;
+ default:
+ return;
+ }
+
+ syme = dso__sym_priv(map->dso, sym);
+
+ if (!syme->skip) {
+ syme->count[counter]++;
+ record_precise_ip(syme, counter, ip);
+ pthread_mutex_lock(&active_symbols_lock);
+ if (list_empty(&syme->node) || !syme->node.next)
+ __list_insert_active_sym(syme);
+ pthread_mutex_unlock(&active_symbols_lock);
+ ++samples;
+ return;
+ }
+}
- samples--;
+static void event__process_mmap(event_t *self)
+{
+ struct thread *thread = threads__findnew(self->mmap.pid);
+
+ if (thread != NULL) {
+ struct map *map = map__new(&self->mmap, NULL, 0,
+ sizeof(struct sym_entry),
+ symbol_filter);
+ if (map != NULL)
+ thread__insert_map(thread, map);
+ }
}
-static void process_event(u64 ip, int counter, int user)
+static void event__process_comm(event_t *self)
{
- samples++;
+ struct thread *thread = threads__findnew(self->comm.pid);
- if (user) {
- userspace_samples++;
- return;
+ if (thread != NULL)
+ thread__set_comm(thread, self->comm.comm);
+}
+
+static int event__process(event_t *event)
+{
+ switch (event->header.type) {
+ case PERF_RECORD_COMM:
+ event__process_comm(event);
+ break;
+ case PERF_RECORD_MMAP:
+ event__process_mmap(event);
+ break;
+ default:
+ break;
}
- record_ip(ip, counter);
+ return 0;
}
struct mmap_data {
@@ -911,8 +928,6 @@ static unsigned int mmap_read_head(struct mmap_data *md)
return head;
}
-struct timeval last_read, this_read;
-
static void mmap_read_counter(struct mmap_data *md)
{
unsigned int head = mmap_read_head(md);
@@ -920,8 +935,6 @@ static void mmap_read_counter(struct mmap_data *md)
unsigned char *data = md->base + page_size;
int diff;
- gettimeofday(&this_read, NULL);
-
/*
* If we're further behind than half the buffer, there's a chance
* the writer will bite our tail and mess up the samples under us.
@@ -932,14 +945,7 @@ static void mmap_read_counter(struct mmap_data *md)
*/
diff = head - old;
if (diff > md->mask / 2 || diff < 0) {
- struct timeval iv;
- unsigned long msecs;
-
- timersub(&this_read, &last_read, &iv);
- msecs = iv.tv_sec*1000 + iv.tv_usec/1000;
-
- fprintf(stderr, "WARNING: failed to keep up with mmap data."
- " Last read %lu msecs ago.\n", msecs);
+ fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
/*
* head points to a known good entry, start there.
@@ -947,8 +953,6 @@ static void mmap_read_counter(struct mmap_data *md)
old = head;
}
- last_read = this_read;
-
for (; old != head;) {
event_t *event = (event_t *)&data[old & md->mask];
@@ -976,13 +980,11 @@ static void mmap_read_counter(struct mmap_data *md)
event = &event_copy;
}
+ if (event->header.type == PERF_RECORD_SAMPLE)
+ event__process_sample(event, md->counter);
+ else
+ event__process(event);
old += size;
-
- if (event->header.type == PERF_RECORD_SAMPLE) {
- int user =
- (event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK) == PERF_RECORD_MISC_USER;
- process_event(event->ip.ip, md->counter, user);
- }
}
md->prev = old;
@@ -1016,8 +1018,15 @@ static void start_counter(int i, int counter)
attr = attrs + counter;
attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
- attr->freq = freq;
+
+ if (freq) {
+ attr->sample_type |= PERF_SAMPLE_PERIOD;
+ attr->freq = 1;
+ attr->sample_freq = freq;
+ }
+
attr->inherit = (cpu < 0) && inherit;
+ attr->mmap = 1;
try_again:
fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0);
@@ -1076,6 +1085,11 @@ static int __cmd_top(void)
int i, counter;
int ret;
+ if (target_pid != -1)
+ event__synthesize_thread(target_pid, event__process);
+ else
+ event__synthesize_threads(event__process);
+
for (i = 0; i < nr_cpus; i++) {
group_fd = -1;
for (counter = 0; counter < nr_counters; counter++)
@@ -1171,11 +1185,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
if (argc)
usage_with_options(top_usage, options);
- if (freq) {
- default_interval = freq;
- freq = 1;
- }
-
/* CPU and PID are mutually exclusive */
if (target_pid != -1 && profile_cpu != -1) {
printf("WARNING: PID switch overriding CPU\n");
@@ -1192,6 +1201,19 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
parse_symbols();
parse_source(sym_filter_entry);
+
+ /*
+ * User specified count overrides default frequency.
+ */
+ if (default_interval)
+ freq = 0;
+ else if (freq) {
+ default_interval = freq;
+ } else {
+ fprintf(stderr, "frequency and count are zero, aborting\n");
+ exit(EXIT_FAILURE);
+ }
+
/*
* Fill in the ones not specifically initialized via -c:
*/
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 0c5e4f72f2ba..e566bbe3f22d 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -12,28 +12,24 @@
#include "util/debug.h"
#include "util/trace-event.h"
+#include "util/data_map.h"
static char const *input_name = "perf.data";
-static int input;
-static unsigned long page_size;
-static unsigned long mmap_window = 32;
static unsigned long total = 0;
static unsigned long total_comm = 0;
-static struct rb_root threads;
-static struct thread *last_match;
-
static struct perf_header *header;
static u64 sample_type;
+static char *cwd;
+static int cwdlen;
+
static int
process_comm_event(event_t *event, unsigned long offset, unsigned long head)
{
- struct thread *thread;
-
- thread = threads__findnew(event->comm.pid, &threads, &last_match);
+ struct thread *thread = threads__findnew(event->comm.pid);
dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
(void *)(offset + head),
@@ -53,18 +49,12 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
static int
process_sample_event(event_t *event, unsigned long offset, unsigned long head)
{
- char level;
- int show = 0;
- struct dso *dso = NULL;
- struct thread *thread;
u64 ip = event->ip.ip;
u64 timestamp = -1;
u32 cpu = -1;
u64 period = 1;
void *more_data = event->ip.__more_data;
- int cpumode;
-
- thread = threads__findnew(event->ip.pid, &threads, &last_match);
+ struct thread *thread = threads__findnew(event->ip.pid);
if (sample_type & PERF_SAMPLE_TIME) {
timestamp = *(u64 *)more_data;
@@ -90,37 +80,13 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
(void *)(long)ip,
(long long)period);
- dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
-
if (thread == NULL) {
- eprintf("problem processing %d event, skipping it.\n",
- event->header.type);
+ pr_debug("problem processing %d event, skipping it.\n",
+ event->header.type);
return -1;
}
- cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
-
- if (cpumode == PERF_RECORD_MISC_KERNEL) {
- show = SHOW_KERNEL;
- level = 'k';
-
- dso = kernel_dso;
-
- dump_printf(" ...... dso: %s\n", dso->name);
-
- } else if (cpumode == PERF_RECORD_MISC_USER) {
-
- show = SHOW_USER;
- level = '.';
-
- } else {
- show = SHOW_HV;
- level = 'H';
-
- dso = hypervisor_dso;
-
- dump_printf(" ...... dso: [hypervisor]\n");
- }
+ dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
if (sample_type & PERF_SAMPLE_RAW) {
struct {
@@ -140,121 +106,32 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
return 0;
}
-static int
-process_event(event_t *event, unsigned long offset, unsigned long head)
+static int sample_type_check(u64 type)
{
- trace_event(event);
-
- switch (event->header.type) {
- case PERF_RECORD_MMAP ... PERF_RECORD_LOST:
- return 0;
-
- case PERF_RECORD_COMM:
- return process_comm_event(event, offset, head);
+ sample_type = type;
- case PERF_RECORD_EXIT ... PERF_RECORD_READ:
- return 0;
-
- case PERF_RECORD_SAMPLE:
- return process_sample_event(event, offset, head);
-
- case PERF_RECORD_MAX:
- default:
+ if (!(sample_type & PERF_SAMPLE_RAW)) {
+ fprintf(stderr,
+ "No trace sample to read. Did you call perf record "
+ "without -R?");
return -1;
}
return 0;
}
+static struct perf_file_handler file_handler = {
+ .process_sample_event = process_sample_event,
+ .process_comm_event = process_comm_event,
+ .sample_type_check = sample_type_check,
+};
+
static int __cmd_trace(void)
{
- int ret, rc = EXIT_FAILURE;
- unsigned long offset = 0;
- unsigned long head = 0;
- struct stat perf_stat;
- event_t *event;
- uint32_t size;
- char *buf;
-
- trace_report();
- register_idle_thread(&threads, &last_match);
-
- input = open(input_name, O_RDONLY);
- if (input < 0) {
- perror("failed to open file");
- exit(-1);
- }
-
- ret = fstat(input, &perf_stat);
- if (ret < 0) {
- perror("failed to stat file");
- exit(-1);
- }
-
- if (!perf_stat.st_size) {
- fprintf(stderr, "zero-sized file, nothing to do!\n");
- exit(0);
- }
- header = perf_header__read(input);
- head = header->data_offset;
- sample_type = perf_header__sample_type(header);
-
- if (!(sample_type & PERF_SAMPLE_RAW))
- die("No trace sample to read. Did you call perf record "
- "without -R?");
-
- if (load_kernel() < 0) {
- perror("failed to load kernel symbols");
- return EXIT_FAILURE;
- }
-
-remap:
- buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
- MAP_SHARED, input, offset);
- if (buf == MAP_FAILED) {
- perror("failed to mmap file");
- exit(-1);
- }
-
-more:
- event = (event_t *)(buf + head);
-
- if (head + event->header.size >= page_size * mmap_window) {
- unsigned long shift = page_size * (head / page_size);
- int res;
-
- res = munmap(buf, page_size * mmap_window);
- assert(res == 0);
-
- offset += shift;
- head -= shift;
- goto remap;
- }
-
- size = event->header.size;
-
- if (!size || process_event(event, offset, head) < 0) {
-
- /*
- * assume we lost track of the stream, check alignment, and
- * increment a single u64 in the hope to catch on again 'soon'.
- */
-
- if (unlikely(head & 7))
- head &= ~7ULL;
-
- size = 8;
- }
-
- head += size;
-
- if (offset + head < (unsigned long)perf_stat.st_size)
- goto more;
-
- rc = EXIT_SUCCESS;
- close(input);
+ register_idle_thread();
+ register_perf_file_handler(&file_handler);
- return rc;
+ return mmap_dispatch_perf_file(&header, input_name, 0, 0, &cwdlen, &cwd);
}
static const char * const annotate_usage[] = {
@@ -267,13 +144,14 @@ static const struct option options[] = {
"dump raw trace in ASCII"),
OPT_BOOLEAN('v', "verbose", &verbose,
"be more verbose (show symbol address, etc)"),
+ OPT_BOOLEAN('l', "latency", &latency_format,
+ "show latency attributes (irqs/preemption disabled, etc)"),
OPT_END()
};
int cmd_trace(int argc, const char **argv, const char *prefix __used)
{
symbol__init();
- page_size = getpagesize();
argc = parse_options(argc, argv, options, annotate_usage, 0);
if (argc) {
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index e11d8d231c3b..ad5f0f4c49ee 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -25,5 +25,6 @@ extern int cmd_timechart(int argc, const char **argv, const char *prefix);
extern int cmd_top(int argc, const char **argv, const char *prefix);
extern int cmd_trace(int argc, const char **argv, const char *prefix);
extern int cmd_version(int argc, const char **argv, const char *prefix);
+extern int cmd_probe(int argc, const char **argv, const char *prefix);
#endif
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 00326e230d87..6475db4f194c 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -11,3 +11,4 @@ perf-stat mainporcelain common
perf-timechart mainporcelain common
perf-top mainporcelain common
perf-trace mainporcelain common
+perf-probe mainporcelain common
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 19fc7feb9d59..9cafe5463266 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -89,8 +89,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
/*
* Check remaining flags.
*/
- if (!prefixcmp(cmd, "--exec-path")) {
- cmd += 11;
+ if (!prefixcmp(cmd, CMD_EXEC_PATH)) {
+ cmd += strlen(CMD_EXEC_PATH);
if (*cmd == '=')
perf_set_argv_exec_path(cmd + 1);
else {
@@ -117,8 +117,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
(*argv)++;
(*argc)--;
handled++;
- } else if (!prefixcmp(cmd, "--perf-dir=")) {
- setenv(PERF_DIR_ENVIRONMENT, cmd + 10, 1);
+ } else if (!prefixcmp(cmd, CMD_PERF_DIR)) {
+ setenv(PERF_DIR_ENVIRONMENT, cmd + strlen(CMD_PERF_DIR), 1);
if (envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--work-tree")) {
@@ -131,8 +131,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
*envchanged = 1;
(*argv)++;
(*argc)--;
- } else if (!prefixcmp(cmd, "--work-tree=")) {
- setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
+ } else if (!prefixcmp(cmd, CMD_WORK_TREE)) {
+ setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + strlen(CMD_WORK_TREE), 1);
if (envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--debugfs-dir")) {
@@ -146,8 +146,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
*envchanged = 1;
(*argv)++;
(*argc)--;
- } else if (!prefixcmp(cmd, "--debugfs-dir=")) {
- strncpy(debugfs_mntpt, cmd + 14, MAXPATHLEN);
+ } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) {
+ strncpy(debugfs_mntpt, cmd + strlen(CMD_DEBUGFS_DIR), MAXPATHLEN);
debugfs_mntpt[MAXPATHLEN - 1] = '\0';
if (envchanged)
*envchanged = 1;
@@ -295,6 +295,7 @@ static void handle_internal_command(int argc, const char **argv)
{ "version", cmd_version, 0 },
{ "trace", cmd_trace, 0 },
{ "sched", cmd_sched, 0 },
+ { "probe", cmd_probe, 0 },
};
unsigned int i;
static const char ext[] = STRIP_EXTENSION;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 8cc4623afd6f..216bdb223f63 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -47,6 +47,12 @@
#define cpu_relax() asm volatile("":::"memory")
#endif
+#ifdef __alpha__
+#include "../../arch/alpha/include/asm/unistd.h"
+#define rmb() asm volatile("mb" ::: "memory")
+#define cpu_relax() asm volatile("" ::: "memory")
+#endif
+
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index c561d1538c03..54552a00a117 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=PERF-VERSION-FILE
-DEF_VER=v0.0.1.PERF
+DEF_VER=v0.0.2.PERF
LF='
'
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 6f8ea9d210b6..918eb376abe3 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -1,10 +1,15 @@
-#ifndef CACHE_H
-#define CACHE_H
+#ifndef __PERF_CACHE_H
+#define __PERF_CACHE_H
#include "util.h"
#include "strbuf.h"
#include "../perf.h"
+#define CMD_EXEC_PATH "--exec-path"
+#define CMD_PERF_DIR "--perf-dir="
+#define CMD_WORK_TREE "--work-tree="
+#define CMD_DEBUGFS_DIR "--debugfs-dir="
+
#define PERF_DIR_ENVIRONMENT "PERF_DIR"
#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
@@ -117,4 +122,4 @@ extern char *perf_pathdup(const char *fmt, ...)
extern size_t strlcpy(char *dest, const char *src, size_t size);
-#endif /* CACHE_H */
+#endif /* __PERF_CACHE_H */
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 3b8380f1b478..b3b71258272a 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -206,7 +206,7 @@ fill_node(struct callchain_node *node, struct ip_callchain *chain,
}
node->val_nr = chain->nr - start;
if (!node->val_nr)
- printf("Warning: empty node in callchain tree\n");
+ pr_warning("Warning: empty node in callchain tree\n");
}
static void
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 43cf3ea9e088..ad4626de4c2b 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -58,4 +58,4 @@ static inline u64 cumul_hits(struct callchain_node *node)
int register_callchain_param(struct callchain_param *param);
void append_chain(struct callchain_node *root, struct ip_callchain *chain,
struct symbol **syms);
-#endif
+#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index 58d597564b99..24e8809210bb 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -1,5 +1,5 @@
-#ifndef COLOR_H
-#define COLOR_H
+#ifndef __PERF_COLOR_H
+#define __PERF_COLOR_H
/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
#define COLOR_MAXLEN 24
@@ -39,4 +39,4 @@ int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *bu
int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
const char *get_percent_color(double percent);
-#endif /* COLOR_H */
+#endif /* __PERF_COLOR_H */
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
new file mode 100644
index 000000000000..18accb8fee4d
--- /dev/null
+++ b/tools/perf/util/data_map.c
@@ -0,0 +1,222 @@
+#include "data_map.h"
+#include "symbol.h"
+#include "util.h"
+#include "debug.h"
+
+
+static struct perf_file_handler *curr_handler;
+static unsigned long mmap_window = 32;
+static char __cwd[PATH_MAX];
+
+static int
+process_event_stub(event_t *event __used,
+ unsigned long offset __used,
+ unsigned long head __used)
+{
+ return 0;
+}
+
+void register_perf_file_handler(struct perf_file_handler *handler)
+{
+ if (!handler->process_sample_event)
+ handler->process_sample_event = process_event_stub;
+ if (!handler->process_mmap_event)
+ handler->process_mmap_event = process_event_stub;
+ if (!handler->process_comm_event)
+ handler->process_comm_event = process_event_stub;
+ if (!handler->process_fork_event)
+ handler->process_fork_event = process_event_stub;
+ if (!handler->process_exit_event)
+ handler->process_exit_event = process_event_stub;
+ if (!handler->process_lost_event)
+ handler->process_lost_event = process_event_stub;
+ if (!handler->process_read_event)
+ handler->process_read_event = process_event_stub;
+ if (!handler->process_throttle_event)
+ handler->process_throttle_event = process_event_stub;
+ if (!handler->process_unthrottle_event)
+ handler->process_unthrottle_event = process_event_stub;
+
+ curr_handler = handler;
+}
+
+static int
+process_event(event_t *event, unsigned long offset, unsigned long head)
+{
+ trace_event(event);
+
+ switch (event->header.type) {
+ case PERF_RECORD_SAMPLE:
+ return curr_handler->process_sample_event(event, offset, head);
+ case PERF_RECORD_MMAP:
+ return curr_handler->process_mmap_event(event, offset, head);
+ case PERF_RECORD_COMM:
+ return curr_handler->process_comm_event(event, offset, head);
+ case PERF_RECORD_FORK:
+ return curr_handler->process_fork_event(event, offset, head);
+ case PERF_RECORD_EXIT:
+ return curr_handler->process_exit_event(event, offset, head);
+ case PERF_RECORD_LOST:
+ return curr_handler->process_lost_event(event, offset, head);
+ case PERF_RECORD_READ:
+ return curr_handler->process_read_event(event, offset, head);
+ case PERF_RECORD_THROTTLE:
+ return curr_handler->process_throttle_event(event, offset, head);
+ case PERF_RECORD_UNTHROTTLE:
+ return curr_handler->process_unthrottle_event(event, offset, head);
+ default:
+ curr_handler->total_unknown++;
+ return -1;
+ }
+}
+
+int mmap_dispatch_perf_file(struct perf_header **pheader,
+ const char *input_name,
+ int force,
+ int full_paths,
+ int *cwdlen,
+ char **cwd)
+{
+ int ret, rc = EXIT_FAILURE;
+ struct perf_header *header;
+ unsigned long head, shift;
+ unsigned long offset = 0;
+ struct stat input_stat;
+ size_t page_size;
+ u64 sample_type;
+ event_t *event;
+ uint32_t size;
+ int input;
+ char *buf;
+
+ if (!curr_handler)
+ die("Forgot to register perf file handler");
+
+ page_size = getpagesize();
+
+ input = open(input_name, O_RDONLY);
+ if (input < 0) {
+ fprintf(stderr, " failed to open file: %s", input_name);
+ if (!strcmp(input_name, "perf.data"))
+ fprintf(stderr, " (try 'perf record' first)");
+ fprintf(stderr, "\n");
+ exit(-1);
+ }
+
+ ret = fstat(input, &input_stat);
+ if (ret < 0) {
+ perror("failed to stat file");
+ exit(-1);
+ }
+
+ if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
+ fprintf(stderr, "file: %s not owned by current user or root\n",
+ input_name);
+ exit(-1);
+ }
+
+ if (!input_stat.st_size) {
+ fprintf(stderr, "zero-sized file, nothing to do!\n");
+ exit(0);
+ }
+
+ *pheader = perf_header__read(input);
+ header = *pheader;
+ head = header->data_offset;
+
+ sample_type = perf_header__sample_type(header);
+
+ if (curr_handler->sample_type_check)
+ if (curr_handler->sample_type_check(sample_type) < 0)
+ exit(-1);
+
+ if (load_kernel(0, NULL) < 0) {
+ perror("failed to load kernel symbols");
+ return EXIT_FAILURE;
+ }
+
+ if (!full_paths) {
+ if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
+ perror("failed to get the current directory");
+ return EXIT_FAILURE;
+ }
+ *cwd = __cwd;
+ *cwdlen = strlen(*cwd);
+ } else {
+ *cwd = NULL;
+ *cwdlen = 0;
+ }
+
+ shift = page_size * (head / page_size);
+ offset += shift;
+ head -= shift;
+
+remap:
+ buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
+ MAP_SHARED, input, offset);
+ if (buf == MAP_FAILED) {
+ perror("failed to mmap file");
+ exit(-1);
+ }
+
+more:
+ event = (event_t *)(buf + head);
+
+ size = event->header.size;
+ if (!size)
+ size = 8;
+
+ if (head + event->header.size >= page_size * mmap_window) {
+ int munmap_ret;
+
+ shift = page_size * (head / page_size);
+
+ munmap_ret = munmap(buf, page_size * mmap_window);
+ assert(munmap_ret == 0);
+
+ offset += shift;
+ head -= shift;
+ goto remap;
+ }
+
+ size = event->header.size;
+
+ dump_printf("\n%p [%p]: event: %d\n",
+ (void *)(offset + head),
+ (void *)(long)event->header.size,
+ event->header.type);
+
+ if (!size || process_event(event, offset, head) < 0) {
+
+ dump_printf("%p [%p]: skipping unknown header type: %d\n",
+ (void *)(offset + head),
+ (void *)(long)(event->header.size),
+ event->header.type);
+
+ /*
+ * assume we lost track of the stream, check alignment, and
+ * increment a single u64 in the hope to catch on again 'soon'.
+ */
+
+ if (unlikely(head & 7))
+ head &= ~7ULL;
+
+ size = 8;
+ }
+
+ head += size;
+
+ if (offset + head >= header->data_offset + header->data_size)
+ goto done;
+
+ if (offset + head < (unsigned long)input_stat.st_size)
+ goto more;
+
+done:
+ rc = EXIT_SUCCESS;
+ close(input);
+
+ return rc;
+}
+
+
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h
new file mode 100644
index 000000000000..716d1053b074
--- /dev/null
+++ b/tools/perf/util/data_map.h
@@ -0,0 +1,31 @@
+#ifndef __PERF_DATAMAP_H
+#define __PERF_DATAMAP_H
+
+#include "event.h"
+#include "header.h"
+
+typedef int (*event_type_handler_t)(event_t *, unsigned long, unsigned long);
+
+struct perf_file_handler {
+ event_type_handler_t process_sample_event;
+ event_type_handler_t process_mmap_event;
+ event_type_handler_t process_comm_event;
+ event_type_handler_t process_fork_event;
+ event_type_handler_t process_exit_event;
+ event_type_handler_t process_lost_event;
+ event_type_handler_t process_read_event;
+ event_type_handler_t process_throttle_event;
+ event_type_handler_t process_unthrottle_event;
+ int (*sample_type_check)(u64 sample_type);
+ unsigned long total_unknown;
+};
+
+void register_perf_file_handler(struct perf_file_handler *handler);
+int mmap_dispatch_perf_file(struct perf_header **pheader,
+ const char *input_name,
+ int force,
+ int full_paths,
+ int *cwdlen,
+ char **cwd);
+
+#endif
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index e8ca98fe0bd4..28d520d5a1fb 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -13,12 +13,12 @@
int verbose = 0;
int dump_trace = 0;
-int eprintf(const char *fmt, ...)
+int eprintf(int level, const char *fmt, ...)
{
va_list args;
int ret = 0;
- if (verbose) {
+ if (verbose >= level) {
va_start(args, fmt);
ret = vfprintf(stderr, fmt, args);
va_end(args);
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 437eea58ce40..e8b18a1f87a4 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -1,8 +1,13 @@
/* For debugging general purposes */
+#ifndef __PERF_DEBUG_H
+#define __PERF_DEBUG_H
extern int verbose;
extern int dump_trace;
-int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
+int eprintf(int level,
+ const char *fmt, ...) __attribute__((format(printf, 2, 3)));
int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
void trace_event(event_t *event);
+
+#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
new file mode 100644
index 000000000000..1dae7e3b400d
--- /dev/null
+++ b/tools/perf/util/event.c
@@ -0,0 +1,177 @@
+#include <linux/types.h>
+#include "event.h"
+#include "debug.h"
+#include "string.h"
+
+static pid_t event__synthesize_comm(pid_t pid, int full,
+ int (*process)(event_t *event))
+{
+ event_t ev;
+ char filename[PATH_MAX];
+ char bf[BUFSIZ];
+ FILE *fp;
+ size_t size = 0;
+ DIR *tasks;
+ struct dirent dirent, *next;
+ pid_t tgid = 0;
+
+ snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
+
+ fp = fopen(filename, "r");
+ if (fp == NULL) {
+out_race:
+ /*
+ * We raced with a task exiting - just return:
+ */
+ pr_debug("couldn't open %s\n", filename);
+ return 0;
+ }
+
+ memset(&ev.comm, 0, sizeof(ev.comm));
+ while (!ev.comm.comm[0] || !ev.comm.pid) {
+ if (fgets(bf, sizeof(bf), fp) == NULL)
+ goto out_failure;
+
+ if (memcmp(bf, "Name:", 5) == 0) {
+ char *name = bf + 5;
+ while (*name && isspace(*name))
+ ++name;
+ size = strlen(name) - 1;
+ memcpy(ev.comm.comm, name, size++);
+ } else if (memcmp(bf, "Tgid:", 5) == 0) {
+ char *tgids = bf + 5;
+ while (*tgids && isspace(*tgids))
+ ++tgids;
+ tgid = ev.comm.pid = atoi(tgids);
+ }
+ }
+
+ ev.comm.header.type = PERF_RECORD_COMM;
+ size = ALIGN(size, sizeof(u64));
+ ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size);
+
+ if (!full) {
+ ev.comm.tid = pid;
+
+ process(&ev);
+ goto out_fclose;
+ }
+
+ snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
+
+ tasks = opendir(filename);
+ if (tasks == NULL)
+ goto out_race;
+
+ while (!readdir_r(tasks, &dirent, &next) && next) {
+ char *end;
+ pid = strtol(dirent.d_name, &end, 10);
+ if (*end)
+ continue;
+
+ ev.comm.tid = pid;
+
+ process(&ev);
+ }
+ closedir(tasks);
+
+out_fclose:
+ fclose(fp);
+ return tgid;
+
+out_failure:
+ pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
+ return -1;
+}
+
+static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
+ int (*process)(event_t *event))
+{
+ char filename[PATH_MAX];
+ FILE *fp;
+
+ snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
+
+ fp = fopen(filename, "r");
+ if (fp == NULL) {
+ /*
+ * We raced with a task exiting - just return:
+ */
+ pr_debug("couldn't open %s\n", filename);
+ return -1;
+ }
+
+ while (1) {
+ char bf[BUFSIZ], *pbf = bf;
+ event_t ev = {
+ .header = { .type = PERF_RECORD_MMAP },
+ };
+ int n;
+ size_t size;
+ if (fgets(bf, sizeof(bf), fp) == NULL)
+ break;
+
+ /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
+ n = hex2u64(pbf, &ev.mmap.start);
+ if (n < 0)
+ continue;
+ pbf += n + 1;
+ n = hex2u64(pbf, &ev.mmap.len);
+ if (n < 0)
+ continue;
+ pbf += n + 3;
+ if (*pbf == 'x') { /* vm_exec */
+ char *execname = strchr(bf, '/');
+
+ /* Catch VDSO */
+ if (execname == NULL)
+ execname = strstr(bf, "[vdso]");
+
+ if (execname == NULL)
+ continue;
+
+ size = strlen(execname);
+ execname[size - 1] = '\0'; /* Remove \n */
+ memcpy(ev.mmap.filename, execname, size);
+ size = ALIGN(size, sizeof(u64));
+ ev.mmap.len -= ev.mmap.start;
+ ev.mmap.header.size = (sizeof(ev.mmap) -
+ (sizeof(ev.mmap.filename) - size));
+ ev.mmap.pid = tgid;
+ ev.mmap.tid = pid;
+
+ process(&ev);
+ }
+ }
+
+ fclose(fp);
+ return 0;
+}
+
+int event__synthesize_thread(pid_t pid, int (*process)(event_t *event))
+{
+ pid_t tgid = event__synthesize_comm(pid, 1, process);
+ if (tgid == -1)
+ return -1;
+ return event__synthesize_mmap_events(pid, tgid, process);
+}
+
+void event__synthesize_threads(int (*process)(event_t *event))
+{
+ DIR *proc;
+ struct dirent dirent, *next;
+
+ proc = opendir("/proc");
+
+ while (!readdir_r(proc, &dirent, &next) && next) {
+ char *end;
+ pid_t pid = strtol(dirent.d_name, &end, 10);
+
+ if (*end) /* only interested in proper numerical dirents */
+ continue;
+
+ event__synthesize_thread(pid, process);
+ }
+
+ closedir(proc);
+}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 2c9c26d6ded0..2ae1177be40b 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -1,14 +1,10 @@
#ifndef __PERF_RECORD_H
#define __PERF_RECORD_H
+
#include "../perf.h"
#include "util.h"
#include <linux/list.h>
-
-enum {
- SHOW_KERNEL = 1,
- SHOW_USER = 2,
- SHOW_HV = 4,
-};
+#include <linux/rbtree.h>
/*
* PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
@@ -78,11 +74,15 @@ typedef union event_union {
} event_t;
struct map {
- struct list_head node;
+ union {
+ struct rb_node rb_node;
+ struct list_head node;
+ };
u64 start;
u64 end;
u64 pgoff;
u64 (*map_ip)(struct map *, u64);
+ u64 (*unmap_ip)(struct map *, u64);
struct dso *dso;
};
@@ -91,14 +91,27 @@ static inline u64 map__map_ip(struct map *map, u64 ip)
return ip - map->start + map->pgoff;
}
-static inline u64 vdso__map_ip(struct map *map __used, u64 ip)
+static inline u64 map__unmap_ip(struct map *map, u64 ip)
+{
+ return ip + map->start - map->pgoff;
+}
+
+static inline u64 identity__map_ip(struct map *map __used, u64 ip)
{
return ip;
}
-struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen);
+struct symbol;
+
+typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
+
+struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen,
+ unsigned int sym_priv_size, symbol_filter_t filter);
struct map *map__clone(struct map *self);
int map__overlap(struct map *l, struct map *r);
size_t map__fprintf(struct map *self, FILE *fp);
-#endif
+int event__synthesize_thread(pid_t pid, int (*process)(event_t *event));
+void event__synthesize_threads(int (*process)(event_t *event));
+
+#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/exec_cmd.h b/tools/perf/util/exec_cmd.h
index effe25eb1545..31647ac92ed1 100644
--- a/tools/perf/util/exec_cmd.h
+++ b/tools/perf/util/exec_cmd.h
@@ -1,5 +1,5 @@
-#ifndef PERF_EXEC_CMD_H
-#define PERF_EXEC_CMD_H
+#ifndef __PERF_EXEC_CMD_H
+#define __PERF_EXEC_CMD_H
extern void perf_set_argv_exec_path(const char *exec_path);
extern const char *perf_extract_argv0_path(const char *path);
@@ -10,4 +10,4 @@ extern int execv_perf_cmd(const char **argv); /* NULL terminated */
extern int execl_perf_cmd(const char *cmd, ...);
extern const char *system_path(const char *path);
-#endif /* PERF_EXEC_CMD_H */
+#endif /* __PERF_EXEC_CMD_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index e306857b2c2b..7d26659b806c 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -5,6 +5,8 @@
#include "util.h"
#include "header.h"
+#include "../perf.h"
+#include "trace-event.h"
/*
* Create new perf.data header attribute:
@@ -46,23 +48,17 @@ void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
*/
struct perf_header *perf_header__new(void)
{
- struct perf_header *self = malloc(sizeof(*self));
+ struct perf_header *self = calloc(sizeof(*self), 1);
if (!self)
die("nomem");
- self->frozen = 0;
-
- self->attrs = 0;
self->size = 1;
self->attr = malloc(sizeof(void *));
if (!self->attr)
die("nomem");
- self->data_offset = 0;
- self->data_size = 0;
-
return self;
}
@@ -97,7 +93,7 @@ static struct perf_trace_event_type *events;
void perf_header__push_event(u64 id, const char *name)
{
if (strlen(name) > MAX_EVENT_NAME)
- printf("Event %s will be truncated\n", name);
+ pr_warning("Event %s will be truncated\n", name);
if (!events) {
events = malloc(sizeof(struct perf_trace_event_type));
@@ -145,8 +141,14 @@ struct perf_file_header {
struct perf_file_section attrs;
struct perf_file_section data;
struct perf_file_section event_types;
+ DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
};
+void perf_header__feat_trace_info(struct perf_header *header)
+{
+ set_bit(HEADER_TRACE_INFO, header->adds_features);
+}
+
static void do_write(int fd, void *buf, size_t size)
{
while (size) {
@@ -160,6 +162,32 @@ static void do_write(int fd, void *buf, size_t size)
}
}
+static void perf_header__adds_write(struct perf_header *self, int fd)
+{
+ struct perf_file_section trace_sec;
+ u64 cur_offset = lseek(fd, 0, SEEK_CUR);
+ unsigned long *feat_mask = self->adds_features;
+
+ if (test_bit(HEADER_TRACE_INFO, feat_mask)) {
+ /* Write trace info */
+ trace_sec.offset = lseek(fd, sizeof(trace_sec), SEEK_CUR);
+ read_tracing_data(fd, attrs, nr_counters);
+ trace_sec.size = lseek(fd, 0, SEEK_CUR) - trace_sec.offset;
+
+ /* Write trace info headers */
+ lseek(fd, cur_offset, SEEK_SET);
+ do_write(fd, &trace_sec, sizeof(trace_sec));
+
+ /*
+ * Update cur_offset. So that other (future)
+ * features can set their own infos in this place. But if we are
+ * the only feature, at least that seeks to the place the data
+ * should begin.
+ */
+ cur_offset = lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET);
+ }
+};
+
void perf_header__write(struct perf_header *self, int fd)
{
struct perf_file_header f_header;
@@ -198,6 +226,7 @@ void perf_header__write(struct perf_header *self, int fd)
if (events)
do_write(fd, events, self->event_size);
+ perf_header__adds_write(self, fd);
self->data_offset = lseek(fd, 0, SEEK_CUR);
@@ -219,6 +248,8 @@ void perf_header__write(struct perf_header *self, int fd)
},
};
+ memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
+
lseek(fd, 0, SEEK_SET);
do_write(fd, &f_header, sizeof(f_header));
lseek(fd, self->data_offset + self->data_size, SEEK_SET);
@@ -241,6 +272,20 @@ static void do_read(int fd, void *buf, size_t size)
}
}
+static void perf_header__adds_read(struct perf_header *self, int fd)
+{
+ const unsigned long *feat_mask = self->adds_features;
+
+ if (test_bit(HEADER_TRACE_INFO, feat_mask)) {
+ struct perf_file_section trace_sec;
+
+ do_read(fd, &trace_sec, sizeof(trace_sec));
+ lseek(fd, trace_sec.offset, SEEK_SET);
+ trace_report(fd);
+ lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET);
+ }
+};
+
struct perf_header *perf_header__read(int fd)
{
struct perf_header *self = perf_header__new();
@@ -254,10 +299,16 @@ struct perf_header *perf_header__read(int fd)
do_read(fd, &f_header, sizeof(f_header));
if (f_header.magic != PERF_MAGIC ||
- f_header.size != sizeof(f_header) ||
f_header.attr_size != sizeof(f_attr))
die("incompatible file format");
+ if (f_header.size != sizeof(f_header)) {
+ /* Support the previous format */
+ if (f_header.size == offsetof(typeof(f_header), adds_features))
+ bitmap_zero(f_header.adds_features, HEADER_FEAT_BITS);
+ else
+ die("incompatible file format");
+ }
nr_attrs = f_header.attrs.size / sizeof(f_attr);
lseek(fd, f_header.attrs.offset, SEEK_SET);
@@ -290,6 +341,11 @@ struct perf_header *perf_header__read(int fd)
do_read(fd, events, f_header.event_types.size);
event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
}
+
+ memcpy(&self->adds_features, &f_header.adds_features, sizeof(f_header.adds_features));
+
+ perf_header__adds_read(self, fd);
+
self->event_offset = f_header.event_types.offset;
self->event_size = f_header.event_types.size;
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index a0761bc7863c..2ea9dfb1236a 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -1,10 +1,12 @@
-#ifndef _PERF_HEADER_H
-#define _PERF_HEADER_H
+#ifndef __PERF_HEADER_H
+#define __PERF_HEADER_H
#include "../../../include/linux/perf_event.h"
#include <sys/types.h>
#include "types.h"
+#include <linux/bitmap.h>
+
struct perf_header_attr {
struct perf_event_attr attr;
int ids, size;
@@ -12,15 +14,20 @@ struct perf_header_attr {
off_t id_offset;
};
+#define HEADER_TRACE_INFO 1
+
+#define HEADER_FEAT_BITS 256
+
struct perf_header {
- int frozen;
- int attrs, size;
+ int frozen;
+ int attrs, size;
struct perf_header_attr **attr;
- s64 attr_offset;
- u64 data_offset;
- u64 data_size;
- u64 event_offset;
- u64 event_size;
+ s64 attr_offset;
+ u64 data_offset;
+ u64 data_size;
+ u64 event_offset;
+ u64 event_size;
+ DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
};
struct perf_header *perf_header__read(int fd);
@@ -40,8 +47,8 @@ void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
u64 perf_header__sample_type(struct perf_header *header);
struct perf_event_attr *
perf_header__find_attr(u64 id, struct perf_header *header);
-
+void perf_header__feat_trace_info(struct perf_header *header);
struct perf_header *perf_header__new(void);
-#endif /* _PERF_HEADER_H */
+#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/help.h b/tools/perf/util/help.h
index 7128783637b4..7f5c6dedd714 100644
--- a/tools/perf/util/help.h
+++ b/tools/perf/util/help.h
@@ -1,5 +1,5 @@
-#ifndef HELP_H
-#define HELP_H
+#ifndef __PERF_HELP_H
+#define __PERF_HELP_H
struct cmdnames {
size_t alloc;
@@ -26,4 +26,4 @@ int is_in_cmdlist(struct cmdnames *c, const char *s);
void list_commands(const char *title, struct cmdnames *main_cmds,
struct cmdnames *other_cmds);
-#endif /* HELP_H */
+#endif /* __PERF_HELP_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
new file mode 100644
index 000000000000..7393a02fd8d4
--- /dev/null
+++ b/tools/perf/util/hist.c
@@ -0,0 +1,210 @@
+#include "hist.h"
+
+struct rb_root hist;
+struct rb_root collapse_hists;
+struct rb_root output_hists;
+int callchain;
+
+struct callchain_param callchain_param = {
+ .mode = CHAIN_GRAPH_REL,
+ .min_percent = 0.5
+};
+
+unsigned long total;
+unsigned long total_mmap;
+unsigned long total_comm;
+unsigned long total_fork;
+unsigned long total_unknown;
+unsigned long total_lost;
+
+/*
+ * histogram, sorted on item, collects counts
+ */
+
+struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map,
+ struct symbol *sym,
+ struct symbol *sym_parent,
+ u64 ip, u64 count, char level, bool *hit)
+{
+ struct rb_node **p = &hist.rb_node;
+ struct rb_node *parent = NULL;
+ struct hist_entry *he;
+ struct hist_entry entry = {
+ .thread = thread,
+ .map = map,
+ .sym = sym,
+ .ip = ip,
+ .level = level,
+ .count = count,
+ .parent = sym_parent,
+ };
+ int cmp;
+
+ while (*p != NULL) {
+ parent = *p;
+ he = rb_entry(parent, struct hist_entry, rb_node);
+
+ cmp = hist_entry__cmp(&entry, he);
+
+ if (!cmp) {
+ *hit = true;
+ return he;
+ }
+
+ if (cmp < 0)
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ }
+
+ he = malloc(sizeof(*he));
+ if (!he)
+ return NULL;
+ *he = entry;
+ rb_link_node(&he->rb_node, parent, p);
+ rb_insert_color(&he->rb_node, &hist);
+ *hit = false;
+ return he;
+}
+
+int64_t
+hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ struct sort_entry *se;
+ int64_t cmp = 0;
+
+ list_for_each_entry(se, &hist_entry__sort_list, list) {
+ cmp = se->cmp(left, right);
+ if (cmp)
+ break;
+ }
+
+ return cmp;
+}
+
+int64_t
+hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
+{
+ struct sort_entry *se;
+ int64_t cmp = 0;
+
+ list_for_each_entry(se, &hist_entry__sort_list, list) {
+ int64_t (*f)(struct hist_entry *, struct hist_entry *);
+
+ f = se->collapse ?: se->cmp;
+
+ cmp = f(left, right);
+ if (cmp)
+ break;
+ }
+
+ return cmp;
+}
+
+void hist_entry__free(struct hist_entry *he)
+{
+ free(he);
+}
+
+/*
+ * collapse the histogram
+ */
+
+void collapse__insert_entry(struct hist_entry *he)
+{
+ struct rb_node **p = &collapse_hists.rb_node;
+ struct rb_node *parent = NULL;
+ struct hist_entry *iter;
+ int64_t cmp;
+
+ while (*p != NULL) {
+ parent = *p;
+ iter = rb_entry(parent, struct hist_entry, rb_node);
+
+ cmp = hist_entry__collapse(iter, he);
+
+ if (!cmp) {
+ iter->count += he->count;
+ hist_entry__free(he);
+ return;
+ }
+
+ if (cmp < 0)
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ }
+
+ rb_link_node(&he->rb_node, parent, p);
+ rb_insert_color(&he->rb_node, &collapse_hists);
+}
+
+void collapse__resort(void)
+{
+ struct rb_node *next;
+ struct hist_entry *n;
+
+ if (!sort__need_collapse)
+ return;
+
+ next = rb_first(&hist);
+ while (next) {
+ n = rb_entry(next, struct hist_entry, rb_node);
+ next = rb_next(&n->rb_node);
+
+ rb_erase(&n->rb_node, &hist);
+ collapse__insert_entry(n);
+ }
+}
+
+/*
+ * reverse the map, sort on count.
+ */
+
+void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
+{
+ struct rb_node **p = &output_hists.rb_node;
+ struct rb_node *parent = NULL;
+ struct hist_entry *iter;
+
+ if (callchain)
+ callchain_param.sort(&he->sorted_chain, &he->callchain,
+ min_callchain_hits, &callchain_param);
+
+ while (*p != NULL) {
+ parent = *p;
+ iter = rb_entry(parent, struct hist_entry, rb_node);
+
+ if (he->count > iter->count)
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ }
+
+ rb_link_node(&he->rb_node, parent, p);
+ rb_insert_color(&he->rb_node, &output_hists);
+}
+
+void output__resort(u64 total_samples)
+{
+ struct rb_node *next;
+ struct hist_entry *n;
+ struct rb_root *tree = &hist;
+ u64 min_callchain_hits;
+
+ min_callchain_hits =
+ total_samples * (callchain_param.min_percent / 100);
+
+ if (sort__need_collapse)
+ tree = &collapse_hists;
+
+ next = rb_first(tree);
+
+ while (next) {
+ n = rb_entry(next, struct hist_entry, rb_node);
+ next = rb_next(&n->rb_node);
+
+ rb_erase(&n->rb_node, tree);
+ output__insert_entry(n, min_callchain_hits);
+ }
+}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
new file mode 100644
index 000000000000..ac2149c559b0
--- /dev/null
+++ b/tools/perf/util/hist.h
@@ -0,0 +1,50 @@
+#ifndef __PERF_HIST_H
+#define __PERF_HIST_H
+#include "../builtin.h"
+
+#include "util.h"
+
+#include "color.h"
+#include <linux/list.h>
+#include "cache.h"
+#include <linux/rbtree.h>
+#include "symbol.h"
+#include "string.h"
+#include "callchain.h"
+#include "strlist.h"
+#include "values.h"
+
+#include "../perf.h"
+#include "debug.h"
+#include "header.h"
+
+#include "parse-options.h"
+#include "parse-events.h"
+
+#include "thread.h"
+#include "sort.h"
+
+extern struct rb_root hist;
+extern struct rb_root collapse_hists;
+extern struct rb_root output_hists;
+extern int callchain;
+extern struct callchain_param callchain_param;
+extern unsigned long total;
+extern unsigned long total_mmap;
+extern unsigned long total_comm;
+extern unsigned long total_fork;
+extern unsigned long total_unknown;
+extern unsigned long total_lost;
+
+struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map,
+ struct symbol *sym, struct symbol *parent,
+ u64 ip, u64 count, char level, bool *hit);
+extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
+extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
+extern void hist_entry__free(struct hist_entry *);
+extern void collapse__insert_entry(struct hist_entry *);
+extern void collapse__resort(void);
+extern void output__insert_entry(struct hist_entry *, u64);
+extern void output__resort(u64);
+
+#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/asm/asm-offsets.h b/tools/perf/util/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..ed538942523d
--- /dev/null
+++ b/tools/perf/util/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+/* stub */
diff --git a/tools/perf/util/include/asm/bitops.h b/tools/perf/util/include/asm/bitops.h
new file mode 100644
index 000000000000..58e9817ffae0
--- /dev/null
+++ b/tools/perf/util/include/asm/bitops.h
@@ -0,0 +1,18 @@
+#ifndef _PERF_ASM_BITOPS_H_
+#define _PERF_ASM_BITOPS_H_
+
+#include <sys/types.h>
+#include "../../types.h"
+#include <linux/compiler.h>
+
+/* CHECKME: Not sure both always match */
+#define BITS_PER_LONG __WORDSIZE
+
+#include "../../../../include/asm-generic/bitops/__fls.h"
+#include "../../../../include/asm-generic/bitops/fls.h"
+#include "../../../../include/asm-generic/bitops/fls64.h"
+#include "../../../../include/asm-generic/bitops/__ffs.h"
+#include "../../../../include/asm-generic/bitops/ffz.h"
+#include "../../../../include/asm-generic/bitops/hweight.h"
+
+#endif
diff --git a/tools/perf/util/include/asm/byteorder.h b/tools/perf/util/include/asm/byteorder.h
new file mode 100644
index 000000000000..b722abe3a626
--- /dev/null
+++ b/tools/perf/util/include/asm/byteorder.h
@@ -0,0 +1,2 @@
+#include <asm/types.h>
+#include "../../../../include/linux/swab.h"
diff --git a/tools/perf/util/include/asm/swab.h b/tools/perf/util/include/asm/swab.h
new file mode 100644
index 000000000000..ed538942523d
--- /dev/null
+++ b/tools/perf/util/include/asm/swab.h
@@ -0,0 +1 @@
+/* stub */
diff --git a/tools/perf/util/include/asm/uaccess.h b/tools/perf/util/include/asm/uaccess.h
new file mode 100644
index 000000000000..d0f72b8fcc35
--- /dev/null
+++ b/tools/perf/util/include/asm/uaccess.h
@@ -0,0 +1,14 @@
+#ifndef _PERF_ASM_UACCESS_H_
+#define _PERF_ASM_UACCESS_H_
+
+#define __get_user(src, dest) \
+({ \
+ (src) = *dest; \
+ 0; \
+})
+
+#define get_user __get_user
+
+#define access_ok(type, addr, size) 1
+
+#endif
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
new file mode 100644
index 000000000000..821c1033bccf
--- /dev/null
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -0,0 +1,2 @@
+#include "../../../../include/linux/bitmap.h"
+#include "../../../../include/asm-generic/bitops/find.h"
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
new file mode 100644
index 000000000000..ace57c36d1d0
--- /dev/null
+++ b/tools/perf/util/include/linux/bitops.h
@@ -0,0 +1,27 @@
+#ifndef _PERF_LINUX_BITOPS_H_
+#define _PERF_LINUX_BITOPS_H_
+
+#define __KERNEL__
+
+#define CONFIG_GENERIC_FIND_NEXT_BIT
+#define CONFIG_GENERIC_FIND_FIRST_BIT
+#include "../../../../include/linux/bitops.h"
+
+static inline void set_bit(int nr, unsigned long *addr)
+{
+ addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
+}
+
+static __always_inline int test_bit(unsigned int nr, const unsigned long *addr)
+{
+ return ((1UL << (nr % BITS_PER_LONG)) &
+ (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
+}
+
+unsigned long generic_find_next_zero_le_bit(const unsigned long *addr, unsigned
+ long size, unsigned long offset);
+
+unsigned long generic_find_next_le_bit(const unsigned long *addr, unsigned
+ long size, unsigned long offset);
+
+#endif
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h
new file mode 100644
index 000000000000..dfb0713ed47f
--- /dev/null
+++ b/tools/perf/util/include/linux/compiler.h
@@ -0,0 +1,10 @@
+#ifndef _PERF_LINUX_COMPILER_H_
+#define _PERF_LINUX_COMPILER_H_
+
+#ifndef __always_inline
+#define __always_inline inline
+#endif
+#define __user
+#define __attribute_const__
+
+#endif
diff --git a/tools/perf/util/include/linux/ctype.h b/tools/perf/util/include/linux/ctype.h
new file mode 100644
index 000000000000..bae5783282ef
--- /dev/null
+++ b/tools/perf/util/include/linux/ctype.h
@@ -0,0 +1 @@
+#include "../../../../include/linux/ctype.h"
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
index a6b87390cb52..21c0274c02fa 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -1,6 +1,16 @@
#ifndef PERF_LINUX_KERNEL_H_
#define PERF_LINUX_KERNEL_H_
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+
+#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
+#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
+
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
@@ -26,4 +36,70 @@
_max1 > _max2 ? _max1 : _max2; })
#endif
+#ifndef min
+#define min(x, y) ({ \
+ typeof(x) _min1 = (x); \
+ typeof(y) _min2 = (y); \
+ (void) (&_min1 == &_min2); \
+ _min1 < _min2 ? _min1 : _min2; })
+#endif
+
+#ifndef BUG_ON
+#define BUG_ON(cond) assert(!(cond))
+#endif
+
+/*
+ * Both need more care to handle endianness
+ * (Don't use bitmap_copy_le() for now)
+ */
+#define cpu_to_le64(x) (x)
+#define cpu_to_le32(x) (x)
+
+static inline int
+vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+ int i;
+ ssize_t ssize = size;
+
+ i = vsnprintf(buf, size, fmt, args);
+
+ return (i >= ssize) ? (ssize - 1) : i;
+}
+
+static inline int scnprintf(char * buf, size_t size, const char * fmt, ...)
+{
+ va_list args;
+ ssize_t ssize = size;
+ int i;
+
+ va_start(args, fmt);
+ i = vsnprintf(buf, size, fmt, args);
+ va_end(args);
+
+ return (i >= ssize) ? (ssize - 1) : i;
+}
+
+static inline unsigned long
+simple_strtoul(const char *nptr, char **endptr, int base)
+{
+ return strtoul(nptr, endptr, base);
+}
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) fmt
+#endif
+
+#define pr_err(fmt, ...) \
+ do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
+#define pr_warning(fmt, ...) \
+ do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
+#define pr_info(fmt, ...) \
+ do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
+#define pr_debug(fmt, ...) \
+ eprintf(1, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_debugN(n, fmt, ...) \
+ eprintf(n, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
+
#endif
diff --git a/tools/perf/util/include/linux/string.h b/tools/perf/util/include/linux/string.h
new file mode 100644
index 000000000000..3b2f5900276f
--- /dev/null
+++ b/tools/perf/util/include/linux/string.h
@@ -0,0 +1 @@
+#include <string.h>
diff --git a/tools/perf/util/include/linux/types.h b/tools/perf/util/include/linux/types.h
new file mode 100644
index 000000000000..196862a81a21
--- /dev/null
+++ b/tools/perf/util/include/linux/types.h
@@ -0,0 +1,9 @@
+#ifndef _PERF_LINUX_TYPES_H_
+#define _PERF_LINUX_TYPES_H_
+
+#include <asm/types.h>
+
+#define DECLARE_BITMAP(name,bits) \
+ unsigned long name[BITS_TO_LONGS(bits)]
+
+#endif
diff --git a/tools/perf/util/levenshtein.h b/tools/perf/util/levenshtein.h
index 0173abeef52c..b0fcb6d8a881 100644
--- a/tools/perf/util/levenshtein.h
+++ b/tools/perf/util/levenshtein.h
@@ -1,8 +1,8 @@
-#ifndef LEVENSHTEIN_H
-#define LEVENSHTEIN_H
+#ifndef __PERF_LEVENSHTEIN_H
+#define __PERF_LEVENSHTEIN_H
int levenshtein(const char *string1, const char *string2,
int swap_penalty, int substition_penalty,
int insertion_penalty, int deletion_penalty);
-#endif
+#endif /* __PERF_LEVENSHTEIN_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 804e02382739..c1c556825343 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -3,6 +3,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
+#include "debug.h"
static inline int is_anon_memory(const char *filename)
{
@@ -19,7 +20,8 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
return n;
}
- struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen)
+struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen,
+ unsigned int sym_priv_size, symbol_filter_t filter)
{
struct map *self = malloc(sizeof(*self));
@@ -27,6 +29,7 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
const char *filename = event->filename;
char newfilename[PATH_MAX];
int anon;
+ bool new_dso;
if (cwd) {
int n = strcommon(filename, cwd, cwdlen);
@@ -49,14 +52,29 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
self->end = event->start + event->len;
self->pgoff = event->pgoff;
- self->dso = dsos__findnew(filename);
+ self->dso = dsos__findnew(filename, sym_priv_size, &new_dso);
if (self->dso == NULL)
goto out_delete;
+ if (new_dso) {
+ int nr = dso__load(self->dso, self, filter);
+
+ if (nr < 0)
+ pr_warning("Failed to open %s, continuing "
+ "without symbols\n",
+ self->dso->long_name);
+ else if (nr == 0)
+ pr_warning("No symbols found in %s, maybe "
+ "install a debug package?\n",
+ self->dso->long_name);
+ }
+
if (self->dso == vdso || anon)
- self->map_ip = vdso__map_ip;
- else
+ self->map_ip = self->unmap_ip = identity__map_ip;
+ else {
self->map_ip = map__map_ip;
+ self->unmap_ip = map__unmap_ip;
+ }
}
return self;
out_delete:
diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c
deleted file mode 100644
index 0d8c85defcd2..000000000000
--- a/tools/perf/util/module.c
+++ /dev/null
@@ -1,545 +0,0 @@
-#include "util.h"
-#include "../perf.h"
-#include "string.h"
-#include "module.h"
-
-#include <libelf.h>
-#include <libgen.h>
-#include <gelf.h>
-#include <elf.h>
-#include <dirent.h>
-#include <sys/utsname.h>
-
-static unsigned int crc32(const char *p, unsigned int len)
-{
- int i;
- unsigned int crc = 0;
-
- while (len--) {
- crc ^= *p++;
- for (i = 0; i < 8; i++)
- crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
- }
- return crc;
-}
-
-/* module section methods */
-
-struct sec_dso *sec_dso__new_dso(const char *name)
-{
- struct sec_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
-
- if (self != NULL) {
- strcpy(self->name, name);
- self->secs = RB_ROOT;
- self->find_section = sec_dso__find_section;
- }
-
- return self;
-}
-
-static void sec_dso__delete_section(struct section *self)
-{
- free(((void *)self));
-}
-
-void sec_dso__delete_sections(struct sec_dso *self)
-{
- struct section *pos;
- struct rb_node *next = rb_first(&self->secs);
-
- while (next) {
- pos = rb_entry(next, struct section, rb_node);
- next = rb_next(&pos->rb_node);
- rb_erase(&pos->rb_node, &self->secs);
- sec_dso__delete_section(pos);
- }
-}
-
-void sec_dso__delete_self(struct sec_dso *self)
-{
- sec_dso__delete_sections(self);
- free(self);
-}
-
-static void sec_dso__insert_section(struct sec_dso *self, struct section *sec)
-{
- struct rb_node **p = &self->secs.rb_node;
- struct rb_node *parent = NULL;
- const u64 hash = sec->hash;
- struct section *s;
-
- while (*p != NULL) {
- parent = *p;
- s = rb_entry(parent, struct section, rb_node);
- if (hash < s->hash)
- p = &(*p)->rb_left;
- else
- p = &(*p)->rb_right;
- }
- rb_link_node(&sec->rb_node, parent, p);
- rb_insert_color(&sec->rb_node, &self->secs);
-}
-
-struct section *sec_dso__find_section(struct sec_dso *self, const char *name)
-{
- struct rb_node *n;
- u64 hash;
- int len;
-
- if (self == NULL)
- return NULL;
-
- len = strlen(name);
- hash = crc32(name, len);
-
- n = self->secs.rb_node;
-
- while (n) {
- struct section *s = rb_entry(n, struct section, rb_node);
-
- if (hash < s->hash)
- n = n->rb_left;
- else if (hash > s->hash)
- n = n->rb_right;
- else {
- if (!strcmp(name, s->name))
- return s;
- else
- n = rb_next(&s->rb_node);
- }
- }
-
- return NULL;
-}
-
-static size_t sec_dso__fprintf_section(struct section *self, FILE *fp)
-{
- return fprintf(fp, "name:%s vma:%llx path:%s\n",
- self->name, self->vma, self->path);
-}
-
-size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp)
-{
- size_t ret = fprintf(fp, "dso: %s\n", self->name);
-
- struct rb_node *nd;
- for (nd = rb_first(&self->secs); nd; nd = rb_next(nd)) {
- struct section *pos = rb_entry(nd, struct section, rb_node);
- ret += sec_dso__fprintf_section(pos, fp);
- }
-
- return ret;
-}
-
-static struct section *section__new(const char *name, const char *path)
-{
- struct section *self = calloc(1, sizeof(*self));
-
- if (!self)
- goto out_failure;
-
- self->name = calloc(1, strlen(name) + 1);
- if (!self->name)
- goto out_failure;
-
- self->path = calloc(1, strlen(path) + 1);
- if (!self->path)
- goto out_failure;
-
- strcpy(self->name, name);
- strcpy(self->path, path);
- self->hash = crc32(self->name, strlen(name));
-
- return self;
-
-out_failure:
- if (self) {
- if (self->name)
- free(self->name);
- if (self->path)
- free(self->path);
- free(self);
- }
-
- return NULL;
-}
-
-/* module methods */
-
-struct mod_dso *mod_dso__new_dso(const char *name)
-{
- struct mod_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
-
- if (self != NULL) {
- strcpy(self->name, name);
- self->mods = RB_ROOT;
- self->find_module = mod_dso__find_module;
- }
-
- return self;
-}
-
-static void mod_dso__delete_module(struct module *self)
-{
- free(((void *)self));
-}
-
-void mod_dso__delete_modules(struct mod_dso *self)
-{
- struct module *pos;
- struct rb_node *next = rb_first(&self->mods);
-
- while (next) {
- pos = rb_entry(next, struct module, rb_node);
- next = rb_next(&pos->rb_node);
- rb_erase(&pos->rb_node, &self->mods);
- mod_dso__delete_module(pos);
- }
-}
-
-void mod_dso__delete_self(struct mod_dso *self)
-{
- mod_dso__delete_modules(self);
- free(self);
-}
-
-static void mod_dso__insert_module(struct mod_dso *self, struct module *mod)
-{
- struct rb_node **p = &self->mods.rb_node;
- struct rb_node *parent = NULL;
- const u64 hash = mod->hash;
- struct module *m;
-
- while (*p != NULL) {
- parent = *p;
- m = rb_entry(parent, struct module, rb_node);
- if (hash < m->hash)
- p = &(*p)->rb_left;
- else
- p = &(*p)->rb_right;
- }
- rb_link_node(&mod->rb_node, parent, p);
- rb_insert_color(&mod->rb_node, &self->mods);
-}
-
-struct module *mod_dso__find_module(struct mod_dso *self, const char *name)
-{
- struct rb_node *n;
- u64 hash;
- int len;
-
- if (self == NULL)
- return NULL;
-
- len = strlen(name);
- hash = crc32(name, len);
-
- n = self->mods.rb_node;
-
- while (n) {
- struct module *m = rb_entry(n, struct module, rb_node);
-
- if (hash < m->hash)
- n = n->rb_left;
- else if (hash > m->hash)
- n = n->rb_right;
- else {
- if (!strcmp(name, m->name))
- return m;
- else
- n = rb_next(&m->rb_node);
- }
- }
-
- return NULL;
-}
-
-static size_t mod_dso__fprintf_module(struct module *self, FILE *fp)
-{
- return fprintf(fp, "name:%s path:%s\n", self->name, self->path);
-}
-
-size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp)
-{
- struct rb_node *nd;
- size_t ret;
-
- ret = fprintf(fp, "dso: %s\n", self->name);
-
- for (nd = rb_first(&self->mods); nd; nd = rb_next(nd)) {
- struct module *pos = rb_entry(nd, struct module, rb_node);
-
- ret += mod_dso__fprintf_module(pos, fp);
- }
-
- return ret;
-}
-
-static struct module *module__new(const char *name, const char *path)
-{
- struct module *self = calloc(1, sizeof(*self));
-
- if (!self)
- goto out_failure;
-
- self->name = calloc(1, strlen(name) + 1);
- if (!self->name)
- goto out_failure;
-
- self->path = calloc(1, strlen(path) + 1);
- if (!self->path)
- goto out_failure;
-
- strcpy(self->name, name);
- strcpy(self->path, path);
- self->hash = crc32(self->name, strlen(name));
-
- return self;
-
-out_failure:
- if (self) {
- if (self->name)
- free(self->name);
- if (self->path)
- free(self->path);
- free(self);
- }
-
- return NULL;
-}
-
-static int mod_dso__load_sections(struct module *mod)
-{
- int count = 0, path_len;
- struct dirent *entry;
- char *line = NULL;
- char *dir_path;
- DIR *dir;
- size_t n;
-
- path_len = strlen("/sys/module/");
- path_len += strlen(mod->name);
- path_len += strlen("/sections/");
-
- dir_path = calloc(1, path_len + 1);
- if (dir_path == NULL)
- goto out_failure;
-
- strcat(dir_path, "/sys/module/");
- strcat(dir_path, mod->name);
- strcat(dir_path, "/sections/");
-
- dir = opendir(dir_path);
- if (dir == NULL)
- goto out_free;
-
- while ((entry = readdir(dir))) {
- struct section *section;
- char *path, *vma;
- int line_len;
- FILE *file;
-
- if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name))
- continue;
-
- path = calloc(1, path_len + strlen(entry->d_name) + 1);
- if (path == NULL)
- break;
- strcat(path, dir_path);
- strcat(path, entry->d_name);
-
- file = fopen(path, "r");
- if (file == NULL) {
- free(path);
- break;
- }
-
- line_len = getline(&line, &n, file);
- if (line_len < 0) {
- free(path);
- fclose(file);
- break;
- }
-
- if (!line) {
- free(path);
- fclose(file);
- break;
- }
-
- line[--line_len] = '\0'; /* \n */
-
- vma = strstr(line, "0x");
- if (!vma) {
- free(path);
- fclose(file);
- break;
- }
- vma += 2;
-
- section = section__new(entry->d_name, path);
- if (!section) {
- fprintf(stderr, "load_sections: allocation error\n");
- free(path);
- fclose(file);
- break;
- }
-
- hex2u64(vma, &section->vma);
- sec_dso__insert_section(mod->sections, section);
-
- free(path);
- fclose(file);
- count++;
- }
-
- closedir(dir);
- free(line);
- free(dir_path);
-
- return count;
-
-out_free:
- free(dir_path);
-
-out_failure:
- return count;
-}
-
-static int mod_dso__load_module_paths(struct mod_dso *self)
-{
- struct utsname uts;
- int count = 0, len, err = -1;
- char *line = NULL;
- FILE *file;
- char *dpath, *dir;
- size_t n;
-
- if (uname(&uts) < 0)
- return err;
-
- len = strlen("/lib/modules/");
- len += strlen(uts.release);
- len += strlen("/modules.dep");
-
- dpath = calloc(1, len + 1);
- if (dpath == NULL)
- return err;
-
- strcat(dpath, "/lib/modules/");
- strcat(dpath, uts.release);
- strcat(dpath, "/modules.dep");
-
- file = fopen(dpath, "r");
- if (file == NULL)
- goto out_failure;
-
- dir = dirname(dpath);
- if (!dir)
- goto out_failure;
- strcat(dir, "/");
-
- while (!feof(file)) {
- struct module *module;
- char *name, *path, *tmp;
- FILE *modfile;
- int line_len;
-
- line_len = getline(&line, &n, file);
- if (line_len < 0)
- break;
-
- if (!line)
- break;
-
- line[--line_len] = '\0'; /* \n */
-
- path = strchr(line, ':');
- if (!path)
- break;
- *path = '\0';
-
- path = strdup(line);
- if (!path)
- break;
-
- if (!strstr(path, dir)) {
- if (strncmp(path, "kernel/", 7))
- break;
-
- free(path);
- path = calloc(1, strlen(dir) + strlen(line) + 1);
- if (!path)
- break;
- strcat(path, dir);
- strcat(path, line);
- }
-
- modfile = fopen(path, "r");
- if (modfile == NULL)
- break;
- fclose(modfile);
-
- name = strdup(path);
- if (!name)
- break;
-
- name = strtok(name, "/");
- tmp = name;
-
- while (tmp) {
- tmp = strtok(NULL, "/");
- if (tmp)
- name = tmp;
- }
-
- name = strsep(&name, ".");
- if (!name)
- break;
-
- /* Quirk: replace '-' with '_' in all modules */
- for (len = strlen(name); len; len--) {
- if (*(name+len) == '-')
- *(name+len) = '_';
- }
-
- module = module__new(name, path);
- if (!module)
- break;
- mod_dso__insert_module(self, module);
-
- module->sections = sec_dso__new_dso("sections");
- if (!module->sections)
- break;
-
- module->active = mod_dso__load_sections(module);
-
- if (module->active > 0)
- count++;
- }
-
- if (feof(file))
- err = count;
- else
- fprintf(stderr, "load_module_paths: modules.dep parsing failure!\n");
-
-out_failure:
- if (dpath)
- free(dpath);
- if (file)
- fclose(file);
- if (line)
- free(line);
-
- return err;
-}
-
-int mod_dso__load_modules(struct mod_dso *dso)
-{
- int err;
-
- err = mod_dso__load_module_paths(dso);
-
- return err;
-}
diff --git a/tools/perf/util/module.h b/tools/perf/util/module.h
deleted file mode 100644
index 8a592ef641ca..000000000000
--- a/tools/perf/util/module.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef _PERF_MODULE_
-#define _PERF_MODULE_ 1
-
-#include <linux/types.h>
-#include "../types.h"
-#include <linux/list.h>
-#include <linux/rbtree.h>
-
-struct section {
- struct rb_node rb_node;
- u64 hash;
- u64 vma;
- char *name;
- char *path;
-};
-
-struct sec_dso {
- struct list_head node;
- struct rb_root secs;
- struct section *(*find_section)(struct sec_dso *, const char *name);
- char name[0];
-};
-
-struct module {
- struct rb_node rb_node;
- u64 hash;
- char *name;
- char *path;
- struct sec_dso *sections;
- int active;
-};
-
-struct mod_dso {
- struct list_head node;
- struct rb_root mods;
- struct module *(*find_module)(struct mod_dso *, const char *name);
- char name[0];
-};
-
-struct sec_dso *sec_dso__new_dso(const char *name);
-void sec_dso__delete_sections(struct sec_dso *self);
-void sec_dso__delete_self(struct sec_dso *self);
-size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp);
-struct section *sec_dso__find_section(struct sec_dso *self, const char *name);
-
-struct mod_dso *mod_dso__new_dso(const char *name);
-void mod_dso__delete_modules(struct mod_dso *self);
-void mod_dso__delete_self(struct mod_dso *self);
-size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp);
-struct module *mod_dso__find_module(struct mod_dso *self, const char *name);
-int mod_dso__load_modules(struct mod_dso *dso);
-
-#endif /* _PERF_MODULE_ */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 8cfb48cbbea0..31baa5a60365 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -8,9 +8,10 @@
#include "cache.h"
#include "header.h"
-int nr_counters;
+int nr_counters;
struct perf_event_attr attrs[MAX_COUNTERS];
+char *filters[MAX_COUNTERS];
struct event_symbol {
u8 type;
@@ -677,6 +678,8 @@ parse_event_symbols(const char **str, struct perf_event_attr *attr)
if (ret != EVT_FAILED)
goto modifier;
+ fprintf(stderr, "invalid or unsupported event: '%s'\n", *str);
+ fprintf(stderr, "Run 'perf list' for a list of valid events\n");
return EVT_FAILED;
modifier:
@@ -708,7 +711,6 @@ static void store_event_type(const char *orgname)
perf_header__push_event(id, orgname);
}
-
int parse_events(const struct option *opt __used, const char *str, int unset __used)
{
struct perf_event_attr attr;
@@ -745,6 +747,28 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
return 0;
}
+int parse_filter(const struct option *opt __used, const char *str,
+ int unset __used)
+{
+ int i = nr_counters - 1;
+ int len = strlen(str);
+
+ if (i < 0 || attrs[i].type != PERF_TYPE_TRACEPOINT) {
+ fprintf(stderr,
+ "-F option should follow a -e tracepoint option\n");
+ return -1;
+ }
+
+ filters[i] = malloc(len + 1);
+ if (!filters[i]) {
+ fprintf(stderr, "not enough memory to hold filter string\n");
+ return -1;
+ }
+ strcpy(filters[i], str);
+
+ return 0;
+}
+
static const char * const event_type_descriptors[] = {
"",
"Hardware event",
@@ -782,7 +806,7 @@ static void print_tracepoint_events(void)
for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
snprintf(evt_path, MAXPATHLEN, "%s:%s",
sys_dirent.d_name, evt_dirent.d_name);
- fprintf(stderr, " %-42s [%s]\n", evt_path,
+ printf(" %-42s [%s]\n", evt_path,
event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
}
closedir(evt_dir);
@@ -799,8 +823,8 @@ void print_events(void)
unsigned int i, type, op, prev_type = -1;
char name[40];
- fprintf(stderr, "\n");
- fprintf(stderr, "List of pre-defined events (to be used in -e):\n");
+ printf("\n");
+ printf("List of pre-defined events (to be used in -e):\n");
for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
type = syms->type + 1;
@@ -808,19 +832,19 @@ void print_events(void)
type = 0;
if (type != prev_type)
- fprintf(stderr, "\n");
+ printf("\n");
if (strlen(syms->alias))
sprintf(name, "%s OR %s", syms->symbol, syms->alias);
else
strcpy(name, syms->symbol);
- fprintf(stderr, " %-42s [%s]\n", name,
+ printf(" %-42s [%s]\n", name,
event_type_descriptors[type]);
prev_type = type;
}
- fprintf(stderr, "\n");
+ printf("\n");
for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
/* skip invalid cache type */
@@ -828,17 +852,17 @@ void print_events(void)
continue;
for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
- fprintf(stderr, " %-42s [%s]\n",
+ printf(" %-42s [%s]\n",
event_cache_name(type, op, i),
event_type_descriptors[4]);
}
}
}
- fprintf(stderr, "\n");
- fprintf(stderr, " %-42s [raw hardware event descriptor]\n",
+ printf("\n");
+ printf(" %-42s [raw hardware event descriptor]\n",
"rNNN");
- fprintf(stderr, "\n");
+ printf("\n");
print_tracepoint_events();
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 30c608112845..b8c1f64bc935 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -1,5 +1,5 @@
-#ifndef _PARSE_EVENTS_H
-#define _PARSE_EVENTS_H
+#ifndef __PERF_PARSE_EVENTS_H
+#define __PERF_PARSE_EVENTS_H
/*
* Parse symbolic events/counts passed in as options:
*/
@@ -17,11 +17,13 @@ extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
extern int nr_counters;
extern struct perf_event_attr attrs[MAX_COUNTERS];
+extern char *filters[MAX_COUNTERS];
extern const char *event_name(int ctr);
extern const char *__event_name(int type, u64 config);
extern int parse_events(const struct option *opt, const char *str, int unset);
+extern int parse_filter(const struct option *opt, const char *str, int unset);
#define EVENTS_HELP_MAX (128*1024)
@@ -31,4 +33,4 @@ extern char debugfs_path[];
extern int valid_debugfs_mount(const char *debugfs);
-#endif /* _PARSE_EVENTS_H */
+#endif /* __PERF_PARSE_EVENTS_H */
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index 2ee248ff27e5..948805af43c2 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -1,5 +1,5 @@
-#ifndef PARSE_OPTIONS_H
-#define PARSE_OPTIONS_H
+#ifndef __PERF_PARSE_OPTIONS_H
+#define __PERF_PARSE_OPTIONS_H
enum parse_opt_type {
/* special types */
@@ -174,4 +174,4 @@ extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
extern const char *parse_options_fix_filename(const char *prefix, const char *file);
-#endif
+#endif /* __PERF_PARSE_OPTIONS_H */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
new file mode 100644
index 000000000000..54e707185308
--- /dev/null
+++ b/tools/perf/util/probe-finder.c
@@ -0,0 +1,677 @@
+/*
+ * probe-finder.c : C expression to kprobe event converter
+ *
+ * Written by Masami Hiramatsu <mhiramat@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#include "event.h"
+#include "debug.h"
+#include "util.h"
+#include "probe-finder.h"
+
+
+/* Dwarf_Die Linkage to parent Die */
+struct die_link {
+ struct die_link *parent; /* Parent die */
+ Dwarf_Die die; /* Current die */
+};
+
+static Dwarf_Debug __dw_debug;
+static Dwarf_Error __dw_error;
+
+/*
+ * Generic dwarf analysis helpers
+ */
+
+#define X86_32_MAX_REGS 8
+const char *x86_32_regs_table[X86_32_MAX_REGS] = {
+ "%ax",
+ "%cx",
+ "%dx",
+ "%bx",
+ "$stack", /* Stack address instead of %sp */
+ "%bp",
+ "%si",
+ "%di",
+};
+
+#define X86_64_MAX_REGS 16
+const char *x86_64_regs_table[X86_64_MAX_REGS] = {
+ "%ax",
+ "%dx",
+ "%cx",
+ "%bx",
+ "%si",
+ "%di",
+ "%bp",
+ "%sp",
+ "%r8",
+ "%r9",
+ "%r10",
+ "%r11",
+ "%r12",
+ "%r13",
+ "%r14",
+ "%r15",
+};
+
+/* TODO: switching by dwarf address size */
+#ifdef __x86_64__
+#define ARCH_MAX_REGS X86_64_MAX_REGS
+#define arch_regs_table x86_64_regs_table
+#else
+#define ARCH_MAX_REGS X86_32_MAX_REGS
+#define arch_regs_table x86_32_regs_table
+#endif
+
+/* Return architecture dependent register string (for kprobe-tracer) */
+static const char *get_arch_regstr(unsigned int n)
+{
+ return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL;
+}
+
+/*
+ * Compare the tail of two strings.
+ * Return 0 if whole of either string is same as another's tail part.
+ */
+static int strtailcmp(const char *s1, const char *s2)
+{
+ int i1 = strlen(s1);
+ int i2 = strlen(s2);
+ while (--i1 > 0 && --i2 > 0) {
+ if (s1[i1] != s2[i2])
+ return s1[i1] - s2[i2];
+ }
+ return 0;
+}
+
+/* Find the fileno of the target file. */
+static Dwarf_Unsigned die_get_fileno(Dwarf_Die cu_die, const char *fname)
+{
+ Dwarf_Signed cnt, i;
+ Dwarf_Unsigned found = 0;
+ char **srcs;
+ int ret;
+
+ if (!fname)
+ return 0;
+
+ ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error);
+ if (ret == DW_DLV_OK) {
+ for (i = 0; i < cnt && !found; i++) {
+ if (strtailcmp(srcs[i], fname) == 0)
+ found = i + 1;
+ dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
+ }
+ for (; i < cnt; i++)
+ dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
+ dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST);
+ }
+ if (found)
+ pr_debug("found fno: %d\n", (int)found);
+ return found;
+}
+
+/* Compare diename and tname */
+static int die_compare_name(Dwarf_Die dw_die, const char *tname)
+{
+ char *name;
+ int ret;
+ ret = dwarf_diename(dw_die, &name, &__dw_error);
+ DIE_IF(ret == DW_DLV_ERROR);
+ if (ret == DW_DLV_OK) {
+ ret = strcmp(tname, name);
+ dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
+ } else
+ ret = -1;
+ return ret;
+}
+
+/* Check the address is in the subprogram(function). */
+static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr,
+ Dwarf_Signed *offs)
+{
+ Dwarf_Addr lopc, hipc;
+ int ret;
+
+ /* TODO: check ranges */
+ ret = dwarf_lowpc(sp_die, &lopc, &__dw_error);
+ DIE_IF(ret == DW_DLV_ERROR);
+ if (ret == DW_DLV_NO_ENTRY)
+ return 0;
+ ret = dwarf_highpc(sp_die, &hipc, &__dw_error);
+ DIE_IF(ret != DW_DLV_OK);
+ if (lopc <= addr && addr < hipc) {
+ *offs = addr - lopc;
+ return 1;
+ } else
+ return 0;
+}
+
+/* Check the die is inlined function */
+static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die)
+{
+ /* TODO: check strictly */
+ Dwarf_Bool inl;
+ int ret;
+
+ ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error);
+ DIE_IF(ret == DW_DLV_ERROR);
+ return inl;
+}
+
+/* Get the offset of abstruct_origin */
+static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die)
+{
+ Dwarf_Attribute attr;
+ Dwarf_Off cu_offs;
+ int ret;
+
+ ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error);
+ DIE_IF(ret != DW_DLV_OK);
+ ret = dwarf_formref(attr, &cu_offs, &__dw_error);
+ DIE_IF(ret != DW_DLV_OK);
+ dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
+ return cu_offs;
+}
+
+/* Get entry pc(or low pc, 1st entry of ranges) of the die */
+static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die)
+{
+ Dwarf_Attribute attr;
+ Dwarf_Addr addr;
+ Dwarf_Off offs;
+ Dwarf_Ranges *ranges;
+ Dwarf_Signed cnt;
+ int ret;
+
+ /* Try to get entry pc */
+ ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error);
+ DIE_IF(ret == DW_DLV_ERROR);
+ if (ret == DW_DLV_OK) {
+ ret = dwarf_formaddr(attr, &addr, &__dw_error);
+ DIE_IF(ret != DW_DLV_OK);
+ dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
+ return addr;
+ }
+
+ /* Try to get low pc */
+ ret = dwarf_lowpc(dw_die, &addr, &__dw_error);
+ DIE_IF(ret == DW_DLV_ERROR);
+ if (ret == DW_DLV_OK)
+ return addr;
+
+ /* Try to get ranges */
+ ret = dwarf_attr(dw_die, DW_AT_ranges, &attr, &__dw_error);
+ DIE_IF(ret != DW_DLV_OK);
+ ret = dwarf_formref(attr, &offs, &__dw_error);
+ DIE_IF(ret != DW_DLV_OK);
+ ret = dwarf_get_ranges(__dw_debug, offs, &ranges, &cnt, NULL,
+ &__dw_error);
+ DIE_IF(ret != DW_DLV_OK);
+ addr = ranges[0].dwr_addr1;
+ dwarf_ranges_dealloc(__dw_debug, ranges, cnt);
+ return addr;
+}
+
+/*
+ * Search a Die from Die tree.
+ * Note: cur_link->die should be deallocated in this function.
+ */
+static int __search_die_tree(struct die_link *cur_link,
+ int (*die_cb)(struct die_link *, void *),
+ void *data)
+{
+ Dwarf_Die new_die;
+ struct die_link new_link;
+ int ret;
+
+ if (!die_cb)
+ return 0;
+
+ /* Check current die */
+ while (!(ret = die_cb(cur_link, data))) {
+ /* Check child die */
+ ret = dwarf_child(cur_link->die, &new_die, &__dw_error);
+ DIE_IF(ret == DW_DLV_ERROR);
+ if (ret == DW_DLV_OK) {
+ new_link.parent = cur_link;
+ new_link.die = new_die;
+ ret = __search_die_tree(&new_link, die_cb, data);
+ if (ret)
+ break;
+ }
+
+ /* Move to next sibling */
+ ret = dwarf_siblingof(__dw_debug, cur_link->die, &new_die,
+ &__dw_error);
+ DIE_IF(ret == DW_DLV_ERROR);
+ dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
+ cur_link->die = new_die;
+ if (ret == DW_DLV_NO_ENTRY)
+ return 0;
+ }
+ dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
+ return ret;
+}
+
+/* Search a die in its children's die tree */
+static int search_die_from_children(Dwarf_Die parent_die,
+ int (*die_cb)(struct die_link *, void *),
+ void *data)
+{
+ struct die_link new_link;
+ int ret;
+
+ new_link.parent = NULL;
+ ret = dwarf_child(parent_die, &new_link.die, &__dw_error);
+ DIE_IF(ret == DW_DLV_ERROR);
+ if (ret == DW_DLV_OK)
+ return __search_die_tree(&new_link, die_cb, data);
+ else
+ return 0;
+}
+
+/* Find a locdesc corresponding to the address */
+static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc,
+ Dwarf_Addr addr)
+{
+ Dwarf_Signed lcnt;
+ Dwarf_Locdesc **llbuf;
+ int ret, i;
+
+ ret = dwarf_loclist_n(attr, &llbuf, &lcnt, &__dw_error);
+ DIE_IF(ret != DW_DLV_OK);
+ ret = DW_DLV_NO_ENTRY;
+ for (i = 0; i < lcnt; ++i) {
+ if (llbuf[i]->ld_lopc <= addr &&
+ llbuf[i]->ld_hipc > addr) {
+ memcpy(desc, llbuf[i], sizeof(Dwarf_Locdesc));
+ desc->ld_s =
+ malloc(sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
+ DIE_IF(desc->ld_s == NULL);
+ memcpy(desc->ld_s, llbuf[i]->ld_s,
+ sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
+ ret = DW_DLV_OK;
+ break;
+ }
+ dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
+ dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
+ }
+ /* Releasing loop */
+ for (; i < lcnt; ++i) {
+ dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
+ dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
+ }
+ dwarf_dealloc(__dw_debug, llbuf, DW_DLA_LIST);
+ return ret;
+}
+
+/*
+ * Probe finder related functions
+ */
+
+/* Show a location */
+static void show_location(Dwarf_Loc *loc, struct probe_finder *pf)
+{
+ Dwarf_Small op;
+ Dwarf_Unsigned regn;
+ Dwarf_Signed offs;
+ int deref = 0, ret;
+ const char *regs;
+
+ op = loc->lr_atom;
+
+ /* If this is based on frame buffer, set the offset */
+ if (op == DW_OP_fbreg) {
+ deref = 1;
+ offs = (Dwarf_Signed)loc->lr_number;
+ op = pf->fbloc.ld_s[0].lr_atom;
+ loc = &pf->fbloc.ld_s[0];
+ } else
+ offs = 0;
+
+ if (op >= DW_OP_breg0 && op <= DW_OP_breg31) {
+ regn = op - DW_OP_breg0;
+ offs += (Dwarf_Signed)loc->lr_number;
+ deref = 1;
+ } else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) {
+ regn = op - DW_OP_reg0;
+ } else if (op == DW_OP_bregx) {
+ regn = loc->lr_number;
+ offs += (Dwarf_Signed)loc->lr_number2;
+ deref = 1;
+ } else if (op == DW_OP_regx) {
+ regn = loc->lr_number;
+ } else
+ die("Dwarf_OP %d is not supported.\n", op);
+
+ regs = get_arch_regstr(regn);
+ if (!regs)
+ die("%lld exceeds max register number.\n", regn);
+
+ if (deref)
+ ret = snprintf(pf->buf, pf->len,
+ " %s=%+lld(%s)", pf->var, offs, regs);
+ else
+ ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
+ DIE_IF(ret < 0);
+ DIE_IF(ret >= pf->len);
+}
+
+/* Show a variables in kprobe event format */
+static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf)
+{
+ Dwarf_Attribute attr;
+ Dwarf_Locdesc ld;
+ int ret;
+
+ ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error);
+ if (ret != DW_DLV_OK)
+ goto error;
+ ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base));
+ if (ret != DW_DLV_OK)
+ goto error;
+ /* TODO? */
+ DIE_IF(ld.ld_cents != 1);
+ show_location(&ld.ld_s[0], pf);
+ free(ld.ld_s);
+ dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
+ return ;
+error:
+ die("Failed to find the location of %s at this address.\n"
+ " Perhaps, it has been optimized out.\n", pf->var);
+}
+
+static int variable_callback(struct die_link *dlink, void *data)
+{
+ struct probe_finder *pf = (struct probe_finder *)data;
+ Dwarf_Half tag;
+ int ret;
+
+ ret = dwarf_tag(dlink->die, &tag, &__dw_error);
+ DIE_IF(ret == DW_DLV_ERROR);
+ if ((tag == DW_TAG_formal_parameter ||
+ tag == DW_TAG_variable) &&
+ (die_compare_name(dlink->die, pf->var) == 0)) {
+ show_variable(dlink->die, pf);
+ return 1;
+ }
+ /* TODO: Support struct members and arrays */
+ return 0;
+}
+
+/* Find a variable in a subprogram die */
+static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf)
+{
+ int ret;
+
+ if (!is_c_varname(pf->var)) {
+ /* Output raw parameters */
+ ret = snprintf(pf->buf, pf->len, " %s", pf->var);
+ DIE_IF(ret < 0);
+ DIE_IF(ret >= pf->len);
+ return ;
+ }
+
+ pr_debug("Searching '%s' variable in context.\n", pf->var);
+ /* Search child die for local variables and parameters. */
+ ret = search_die_from_children(sp_die, variable_callback, pf);
+ if (!ret)
+ die("Failed to find '%s' in this function.\n", pf->var);
+}
+
+/* Get a frame base on the address */
+static void get_current_frame_base(Dwarf_Die sp_die, struct probe_finder *pf)
+{
+ Dwarf_Attribute attr;
+ int ret;
+
+ ret = dwarf_attr(sp_die, DW_AT_frame_base, &attr, &__dw_error);
+ DIE_IF(ret != DW_DLV_OK);
+ ret = attr_get_locdesc(attr, &pf->fbloc, (pf->addr - pf->cu_base));
+ DIE_IF(ret != DW_DLV_OK);
+ dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
+}
+
+static void free_current_frame_base(struct probe_finder *pf)
+{
+ free(pf->fbloc.ld_s);
+ memset(&pf->fbloc, 0, sizeof(Dwarf_Locdesc));
+}
+
+/* Show a probe point to output buffer */
+static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
+ struct probe_finder *pf)
+{
+ struct probe_point *pp = pf->pp;
+ char *name;
+ char tmp[MAX_PROBE_BUFFER];
+ int ret, i, len;
+
+ /* Output name of probe point */
+ ret = dwarf_diename(sp_die, &name, &__dw_error);
+ DIE_IF(ret == DW_DLV_ERROR);
+ if (ret == DW_DLV_OK) {
+ ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name,
+ (unsigned int)offs);
+ dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
+ } else {
+ /* This function has no name. */
+ ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr);
+ }
+ DIE_IF(ret < 0);
+ DIE_IF(ret >= MAX_PROBE_BUFFER);
+ len = ret;
+
+ /* Find each argument */
+ get_current_frame_base(sp_die, pf);
+ for (i = 0; i < pp->nr_args; i++) {
+ pf->var = pp->args[i];
+ pf->buf = &tmp[len];
+ pf->len = MAX_PROBE_BUFFER - len;
+ find_variable(sp_die, pf);
+ len += strlen(pf->buf);
+ }
+ free_current_frame_base(pf);
+
+ pp->probes[pp->found] = strdup(tmp);
+ pp->found++;
+}
+
+static int probeaddr_callback(struct die_link *dlink, void *data)
+{
+ struct probe_finder *pf = (struct probe_finder *)data;
+ Dwarf_Half tag;
+ Dwarf_Signed offs;
+ int ret;
+
+ ret = dwarf_tag(dlink->die, &tag, &__dw_error);
+ DIE_IF(ret == DW_DLV_ERROR);
+ /* Check the address is in this subprogram */
+ if (tag == DW_TAG_subprogram &&
+ die_within_subprogram(dlink->die, pf->addr, &offs)) {
+ show_probepoint(dlink->die, offs, pf);
+ return 1;
+ }
+ return 0;
+}
+
+/* Find probe point from its line number */
+static void find_by_line(Dwarf_Die cu_die, struct probe_finder *pf)
+{
+ struct probe_point *pp = pf->pp;
+ Dwarf_Signed cnt, i;
+ Dwarf_Line *lines;
+ Dwarf_Unsigned lineno = 0;
+ Dwarf_Addr addr;
+ Dwarf_Unsigned fno;
+ int ret;
+
+ ret = dwarf_srclines(cu_die, &lines, &cnt, &__dw_error);
+ DIE_IF(ret != DW_DLV_OK);
+
+ for (i = 0; i < cnt; i++) {
+ ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error);
+ DIE_IF(ret != DW_DLV_OK);
+ if (fno != pf->fno)
+ continue;
+
+ ret = dwarf_lineno(lines[i], &lineno, &__dw_error);
+ DIE_IF(ret != DW_DLV_OK);
+ if (lineno != (Dwarf_Unsigned)pp->line)
+ continue;
+
+ ret = dwarf_lineaddr(lines[i], &addr, &__dw_error);
+ DIE_IF(ret != DW_DLV_OK);
+ pr_debug("Probe point found: 0x%llx\n", addr);
+ pf->addr = addr;
+ /* Search a real subprogram including this line, */
+ ret = search_die_from_children(cu_die, probeaddr_callback, pf);
+ if (ret == 0)
+ die("Probe point is not found in subprograms.\n");
+ /* Continuing, because target line might be inlined. */
+ }
+ dwarf_srclines_dealloc(__dw_debug, lines, cnt);
+}
+
+/* Search function from function name */
+static int probefunc_callback(struct die_link *dlink, void *data)
+{
+ struct probe_finder *pf = (struct probe_finder *)data;
+ struct probe_point *pp = pf->pp;
+ struct die_link *lk;
+ Dwarf_Signed offs;
+ Dwarf_Half tag;
+ int ret;
+
+ ret = dwarf_tag(dlink->die, &tag, &__dw_error);
+ DIE_IF(ret == DW_DLV_ERROR);
+ if (tag == DW_TAG_subprogram) {
+ if (die_compare_name(dlink->die, pp->function) == 0) {
+ if (die_inlined_subprogram(dlink->die)) {
+ /* Inlined function, save it. */
+ ret = dwarf_die_CU_offset(dlink->die,
+ &pf->inl_offs,
+ &__dw_error);
+ DIE_IF(ret != DW_DLV_OK);
+ pr_debug("inline definition offset %lld\n",
+ pf->inl_offs);
+ return 0;
+ }
+ /* Get probe address */
+ pf->addr = die_get_entrypc(dlink->die);
+ pf->addr += pp->offset;
+ /* TODO: Check the address in this function */
+ show_probepoint(dlink->die, pp->offset, pf);
+ /* Continue to search */
+ }
+ } else if (tag == DW_TAG_inlined_subroutine && pf->inl_offs) {
+ if (die_get_abstract_origin(dlink->die) == pf->inl_offs) {
+ /* Get probe address */
+ pf->addr = die_get_entrypc(dlink->die);
+ pf->addr += pp->offset;
+ pr_debug("found inline addr: 0x%llx\n", pf->addr);
+ /* Inlined function. Get a real subprogram */
+ for (lk = dlink->parent; lk != NULL; lk = lk->parent) {
+ tag = 0;
+ dwarf_tag(lk->die, &tag, &__dw_error);
+ DIE_IF(ret == DW_DLV_ERROR);
+ if (tag == DW_TAG_subprogram &&
+ !die_inlined_subprogram(lk->die))
+ goto found;
+ }
+ die("Failed to find real subprogram.\n");
+found:
+ /* Get offset from subprogram */
+ ret = die_within_subprogram(lk->die, pf->addr, &offs);
+ DIE_IF(!ret);
+ show_probepoint(lk->die, offs, pf);
+ /* Continue to search */
+ }
+ }
+ return 0;
+}
+
+static void find_by_func(Dwarf_Die cu_die, struct probe_finder *pf)
+{
+ search_die_from_children(cu_die, probefunc_callback, pf);
+}
+
+/* Find a probe point */
+int find_probepoint(int fd, struct probe_point *pp)
+{
+ Dwarf_Half addr_size = 0;
+ Dwarf_Unsigned next_cuh = 0;
+ Dwarf_Die cu_die = 0;
+ int cu_number = 0, ret;
+ struct probe_finder pf = {.pp = pp};
+
+ ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error);
+ if (ret != DW_DLV_OK)
+ die("Failed to call dwarf_init(). Maybe, not a dwarf file.\n");
+
+ pp->found = 0;
+ while (++cu_number) {
+ /* Search CU (Compilation Unit) */
+ ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL,
+ &addr_size, &next_cuh, &__dw_error);
+ DIE_IF(ret == DW_DLV_ERROR);
+ if (ret == DW_DLV_NO_ENTRY)
+ break;
+
+ /* Get the DIE(Debugging Information Entry) of this CU */
+ ret = dwarf_siblingof(__dw_debug, 0, &cu_die, &__dw_error);
+ DIE_IF(ret != DW_DLV_OK);
+
+ /* Check if target file is included. */
+ if (pp->file)
+ pf.fno = die_get_fileno(cu_die, pp->file);
+
+ if (!pp->file || pf.fno) {
+ /* Save CU base address (for frame_base) */
+ ret = dwarf_lowpc(cu_die, &pf.cu_base, &__dw_error);
+ DIE_IF(ret == DW_DLV_ERROR);
+ if (ret == DW_DLV_NO_ENTRY)
+ pf.cu_base = 0;
+ if (pp->line)
+ find_by_line(cu_die, &pf);
+ if (pp->function)
+ find_by_func(cu_die, &pf);
+ }
+ dwarf_dealloc(__dw_debug, cu_die, DW_DLA_DIE);
+ }
+ ret = dwarf_finish(__dw_debug, &__dw_error);
+ DIE_IF(ret != DW_DLV_OK);
+
+ return pp->found;
+}
+
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
new file mode 100644
index 000000000000..d17fafc21351
--- /dev/null
+++ b/tools/perf/util/probe-finder.h
@@ -0,0 +1,53 @@
+#ifndef _PROBE_FINDER_H
+#define _PROBE_FINDER_H
+
+#define MAX_PATH_LEN 256
+#define MAX_PROBE_BUFFER 1024
+#define MAX_PROBES 128
+
+static inline int is_c_varname(const char *name)
+{
+ /* TODO */
+ return isalpha(name[0]) || name[0] == '_';
+}
+
+struct probe_point {
+ /* Inputs */
+ char *file; /* File name */
+ int line; /* Line number */
+
+ char *function; /* Function name */
+ int offset; /* Offset bytes */
+
+ int nr_args; /* Number of arguments */
+ char **args; /* Arguments */
+
+ /* Output */
+ int found; /* Number of found probe points */
+ char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/
+};
+
+#ifndef NO_LIBDWARF
+extern int find_probepoint(int fd, struct probe_point *pp);
+
+#include <libdwarf/dwarf.h>
+#include <libdwarf/libdwarf.h>
+
+struct probe_finder {
+ struct probe_point *pp; /* Target probe point */
+
+ /* For function searching */
+ Dwarf_Addr addr; /* Address */
+ Dwarf_Unsigned fno; /* File number */
+ Dwarf_Off inl_offs; /* Inline offset */
+
+ /* For variable searching */
+ Dwarf_Addr cu_base; /* Current CU base address */
+ Dwarf_Locdesc fbloc; /* Location of Current Frame Base */
+ const char *var; /* Current variable name */
+ char *buf; /* Current output buffer */
+ int len; /* Length of output buffer */
+};
+#endif /* NO_LIBDWARF */
+
+#endif /*_PROBE_FINDER_H */
diff --git a/tools/perf/util/quote.h b/tools/perf/util/quote.h
index a5454a1d1c13..b6a019733919 100644
--- a/tools/perf/util/quote.h
+++ b/tools/perf/util/quote.h
@@ -1,5 +1,5 @@
-#ifndef QUOTE_H
-#define QUOTE_H
+#ifndef __PERF_QUOTE_H
+#define __PERF_QUOTE_H
#include <stddef.h>
#include <stdio.h>
@@ -65,4 +65,4 @@ extern void perl_quote_print(FILE *stream, const char *src);
extern void python_quote_print(FILE *stream, const char *src);
extern void tcl_quote_print(FILE *stream, const char *src);
-#endif
+#endif /* __PERF_QUOTE_H */
diff --git a/tools/perf/util/run-command.h b/tools/perf/util/run-command.h
index cc1837deba88..d79028727ce2 100644
--- a/tools/perf/util/run-command.h
+++ b/tools/perf/util/run-command.h
@@ -1,5 +1,5 @@
-#ifndef RUN_COMMAND_H
-#define RUN_COMMAND_H
+#ifndef __PERF_RUN_COMMAND_H
+#define __PERF_RUN_COMMAND_H
enum {
ERR_RUN_COMMAND_FORK = 10000,
@@ -85,4 +85,4 @@ struct async {
int start_async(struct async *async);
int finish_async(struct async *async);
-#endif
+#endif /* __PERF_RUN_COMMAND_H */
diff --git a/tools/perf/util/sigchain.h b/tools/perf/util/sigchain.h
index 618083bce0c6..1a53c11265fd 100644
--- a/tools/perf/util/sigchain.h
+++ b/tools/perf/util/sigchain.h
@@ -1,5 +1,5 @@
-#ifndef SIGCHAIN_H
-#define SIGCHAIN_H
+#ifndef __PERF_SIGCHAIN_H
+#define __PERF_SIGCHAIN_H
typedef void (*sigchain_fun)(int);
@@ -8,4 +8,4 @@ int sigchain_pop(int sig);
void sigchain_push_common(sigchain_fun f);
-#endif /* SIGCHAIN_H */
+#endif /* __PERF_SIGCHAIN_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
new file mode 100644
index 000000000000..b490354d1b23
--- /dev/null
+++ b/tools/perf/util/sort.c
@@ -0,0 +1,290 @@
+#include "sort.h"
+
+regex_t parent_regex;
+char default_parent_pattern[] = "^sys_|^do_page_fault";
+char *parent_pattern = default_parent_pattern;
+char default_sort_order[] = "comm,dso,symbol";
+char *sort_order = default_sort_order;
+int sort__need_collapse = 0;
+int sort__has_parent = 0;
+
+enum sort_type sort__first_dimension;
+
+unsigned int dsos__col_width;
+unsigned int comms__col_width;
+unsigned int threads__col_width;
+static unsigned int parent_symbol__col_width;
+char * field_sep;
+
+LIST_HEAD(hist_entry__sort_list);
+
+struct sort_entry sort_thread = {
+ .header = "Command: Pid",
+ .cmp = sort__thread_cmp,
+ .print = sort__thread_print,
+ .width = &threads__col_width,
+};
+
+struct sort_entry sort_comm = {
+ .header = "Command",
+ .cmp = sort__comm_cmp,
+ .collapse = sort__comm_collapse,
+ .print = sort__comm_print,
+ .width = &comms__col_width,
+};
+
+struct sort_entry sort_dso = {
+ .header = "Shared Object",
+ .cmp = sort__dso_cmp,
+ .print = sort__dso_print,
+ .width = &dsos__col_width,
+};
+
+struct sort_entry sort_sym = {
+ .header = "Symbol",
+ .cmp = sort__sym_cmp,
+ .print = sort__sym_print,
+};
+
+struct sort_entry sort_parent = {
+ .header = "Parent symbol",
+ .cmp = sort__parent_cmp,
+ .print = sort__parent_print,
+ .width = &parent_symbol__col_width,
+};
+
+struct sort_dimension {
+ const char *name;
+ struct sort_entry *entry;
+ int taken;
+};
+
+static struct sort_dimension sort_dimensions[] = {
+ { .name = "pid", .entry = &sort_thread, },
+ { .name = "comm", .entry = &sort_comm, },
+ { .name = "dso", .entry = &sort_dso, },
+ { .name = "symbol", .entry = &sort_sym, },
+ { .name = "parent", .entry = &sort_parent, },
+};
+
+int64_t cmp_null(void *l, void *r)
+{
+ if (!l && !r)
+ return 0;
+ else if (!l)
+ return -1;
+ else
+ return 1;
+}
+
+/* --sort pid */
+
+int64_t
+sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ return right->thread->pid - left->thread->pid;
+}
+
+int repsep_fprintf(FILE *fp, const char *fmt, ...)
+{
+ int n;
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (!field_sep)
+ n = vfprintf(fp, fmt, ap);
+ else {
+ char *bf = NULL;
+ n = vasprintf(&bf, fmt, ap);
+ if (n > 0) {
+ char *sep = bf;
+
+ while (1) {
+ sep = strchr(sep, *field_sep);
+ if (sep == NULL)
+ break;
+ *sep = '.';
+ }
+ }
+ fputs(bf, fp);
+ free(bf);
+ }
+ va_end(ap);
+ return n;
+}
+
+size_t
+sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
+{
+ return repsep_fprintf(fp, "%*s:%5d", width - 6,
+ self->thread->comm ?: "", self->thread->pid);
+}
+
+size_t
+sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
+{
+ return repsep_fprintf(fp, "%*s", width, self->thread->comm);
+}
+
+/* --sort dso */
+
+int64_t
+sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ struct dso *dso_l = left->map ? left->map->dso : NULL;
+ struct dso *dso_r = right->map ? right->map->dso : NULL;
+ const char *dso_name_l, *dso_name_r;
+
+ if (!dso_l || !dso_r)
+ return cmp_null(dso_l, dso_r);
+
+ if (verbose) {
+ dso_name_l = dso_l->long_name;
+ dso_name_r = dso_r->long_name;
+ } else {
+ dso_name_l = dso_l->short_name;
+ dso_name_r = dso_r->short_name;
+ }
+
+ return strcmp(dso_name_l, dso_name_r);
+}
+
+size_t
+sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
+{
+ if (self->map && self->map->dso) {
+ const char *dso_name = !verbose ? self->map->dso->short_name :
+ self->map->dso->long_name;
+ return repsep_fprintf(fp, "%-*s", width, dso_name);
+ }
+
+ return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
+}
+
+/* --sort symbol */
+
+int64_t
+sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ u64 ip_l, ip_r;
+
+ if (left->sym == right->sym)
+ return 0;
+
+ ip_l = left->sym ? left->sym->start : left->ip;
+ ip_r = right->sym ? right->sym->start : right->ip;
+
+ return (int64_t)(ip_r - ip_l);
+}
+
+
+size_t
+sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
+{
+ size_t ret = 0;
+
+ if (verbose) {
+ char o = self->map ? dso__symtab_origin(self->map->dso) : '!';
+ ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o);
+ }
+
+ ret += repsep_fprintf(fp, "[%c] ", self->level);
+ if (self->sym)
+ ret += repsep_fprintf(fp, "%s", self->sym->name);
+ else
+ ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
+
+ return ret;
+}
+
+/* --sort comm */
+
+int64_t
+sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ return right->thread->pid - left->thread->pid;
+}
+
+int64_t
+sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
+{
+ char *comm_l = left->thread->comm;
+ char *comm_r = right->thread->comm;
+
+ if (!comm_l || !comm_r)
+ return cmp_null(comm_l, comm_r);
+
+ return strcmp(comm_l, comm_r);
+}
+
+/* --sort parent */
+
+int64_t
+sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ struct symbol *sym_l = left->parent;
+ struct symbol *sym_r = right->parent;
+
+ if (!sym_l || !sym_r)
+ return cmp_null(sym_l, sym_r);
+
+ return strcmp(sym_l->name, sym_r->name);
+}
+
+size_t
+sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
+{
+ return repsep_fprintf(fp, "%-*s", width,
+ self->parent ? self->parent->name : "[other]");
+}
+
+int sort_dimension__add(const char *tok)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
+ struct sort_dimension *sd = &sort_dimensions[i];
+
+ if (sd->taken)
+ continue;
+
+ if (strncasecmp(tok, sd->name, strlen(tok)))
+ continue;
+
+ if (sd->entry->collapse)
+ sort__need_collapse = 1;
+
+ if (sd->entry == &sort_parent) {
+ int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
+ if (ret) {
+ char err[BUFSIZ];
+
+ regerror(ret, &parent_regex, err, sizeof(err));
+ fprintf(stderr, "Invalid regex: %s\n%s",
+ parent_pattern, err);
+ exit(-1);
+ }
+ sort__has_parent = 1;
+ }
+
+ if (list_empty(&hist_entry__sort_list)) {
+ if (!strcmp(sd->name, "pid"))
+ sort__first_dimension = SORT_PID;
+ else if (!strcmp(sd->name, "comm"))
+ sort__first_dimension = SORT_COMM;
+ else if (!strcmp(sd->name, "dso"))
+ sort__first_dimension = SORT_DSO;
+ else if (!strcmp(sd->name, "symbol"))
+ sort__first_dimension = SORT_SYM;
+ else if (!strcmp(sd->name, "parent"))
+ sort__first_dimension = SORT_PARENT;
+ }
+
+ list_add_tail(&sd->entry->list, &hist_entry__sort_list);
+ sd->taken = 1;
+
+ return 0;
+ }
+
+ return -ESRCH;
+}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
new file mode 100644
index 000000000000..333e664ff45f
--- /dev/null
+++ b/tools/perf/util/sort.h
@@ -0,0 +1,99 @@
+#ifndef __PERF_SORT_H
+#define __PERF_SORT_H
+#include "../builtin.h"
+
+#include "util.h"
+
+#include "color.h"
+#include <linux/list.h>
+#include "cache.h"
+#include <linux/rbtree.h>
+#include "symbol.h"
+#include "string.h"
+#include "callchain.h"
+#include "strlist.h"
+#include "values.h"
+
+#include "../perf.h"
+#include "debug.h"
+#include "header.h"
+
+#include "parse-options.h"
+#include "parse-events.h"
+
+#include "thread.h"
+#include "sort.h"
+
+extern regex_t parent_regex;
+extern char *sort_order;
+extern char default_parent_pattern[];
+extern char *parent_pattern;
+extern char default_sort_order[];
+extern int sort__need_collapse;
+extern int sort__has_parent;
+extern char *field_sep;
+extern struct sort_entry sort_comm;
+extern struct sort_entry sort_dso;
+extern struct sort_entry sort_sym;
+extern struct sort_entry sort_parent;
+extern unsigned int dsos__col_width;
+extern unsigned int comms__col_width;
+extern unsigned int threads__col_width;
+extern enum sort_type sort__first_dimension;
+
+struct hist_entry {
+ struct rb_node rb_node;
+ u64 count;
+ struct thread *thread;
+ struct map *map;
+ struct symbol *sym;
+ u64 ip;
+ char level;
+ struct symbol *parent;
+ struct callchain_node callchain;
+ struct rb_root sorted_chain;
+};
+
+enum sort_type {
+ SORT_PID,
+ SORT_COMM,
+ SORT_DSO,
+ SORT_SYM,
+ SORT_PARENT
+};
+
+/*
+ * configurable sorting bits
+ */
+
+struct sort_entry {
+ struct list_head list;
+
+ const char *header;
+
+ int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
+ int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
+ size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
+ unsigned int *width;
+ bool elide;
+};
+
+extern struct sort_entry sort_thread;
+extern struct list_head hist_entry__sort_list;
+
+extern int repsep_fprintf(FILE *fp, const char *fmt, ...);
+extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
+extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
+extern size_t sort__dso_print(FILE *, struct hist_entry *, unsigned int);
+extern size_t sort__sym_print(FILE *, struct hist_entry *, unsigned int __used);
+extern int64_t cmp_null(void *, void *);
+extern int64_t sort__thread_cmp(struct hist_entry *, struct hist_entry *);
+extern int64_t sort__comm_cmp(struct hist_entry *, struct hist_entry *);
+extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *);
+extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *);
+extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
+extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
+extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
+extern int sort_dimension__add(const char *);
+
+#endif /* __PERF_SORT_H */
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h
index d2aa86c014c1..a3d121d6c83e 100644
--- a/tools/perf/util/strbuf.h
+++ b/tools/perf/util/strbuf.h
@@ -1,5 +1,5 @@
-#ifndef STRBUF_H
-#define STRBUF_H
+#ifndef __PERF_STRBUF_H
+#define __PERF_STRBUF_H
/*
* Strbuf's can be use in many ways: as a byte array, or to store arbitrary
@@ -134,4 +134,4 @@ extern int launch_editor(const char *path, struct strbuf *buffer, const char *co
extern int strbuf_branchname(struct strbuf *sb, const char *name);
extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
-#endif /* STRBUF_H */
+#endif /* __PERF_STRBUF_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index c93eca9a7be3..04743d3e9039 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -1,3 +1,4 @@
+#include <string.h>
#include "string.h"
static int hex(char ch)
@@ -32,3 +33,13 @@ int hex2u64(const char *ptr, u64 *long_val)
return p - ptr;
}
+
+char *strxfrchar(char *s, char from, char to)
+{
+ char *p = s;
+
+ while ((p = strchr(p, from)) != NULL)
+ *p++ = to;
+
+ return s;
+}
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index bf39dfadfd24..2c84bf65ba0f 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -1,11 +1,12 @@
-#ifndef _PERF_STRING_H_
-#define _PERF_STRING_H_
+#ifndef __PERF_STRING_H_
+#define __PERF_STRING_H_
#include "types.h"
int hex2u64(const char *ptr, u64 *val);
+char *strxfrchar(char *s, char from, char to);
#define _STR(x) #x
#define STR(x) _STR(x)
-#endif
+#endif /* __PERF_STRING_H */
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index 921818e44a54..cb4659306d7b 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -1,5 +1,5 @@
-#ifndef STRLIST_H_
-#define STRLIST_H_
+#ifndef __PERF_STRLIST_H
+#define __PERF_STRLIST_H
#include <linux/rbtree.h>
#include <stdbool.h>
@@ -36,4 +36,4 @@ static inline unsigned int strlist__nr_entries(const struct strlist *self)
}
int strlist__parse_list(struct strlist *self, const char *s);
-#endif /* STRLIST_H_ */
+#endif /* __PERF_STRLIST_H */
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
index 856655d8b0b8..b3637db025a2 100644
--- a/tools/perf/util/svghelper.c
+++ b/tools/perf/util/svghelper.c
@@ -103,7 +103,7 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
- fprintf(svgfile, " rect.waiting { fill:rgb(214,214, 0); fill-opacity:0.3; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
+ fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
fprintf(svgfile, " rect.cpu { fill:rgb(192,192,192); fill-opacity:0.2; stroke-width:0.5; stroke:rgb(128,128,128); } \n");
fprintf(svgfile, " rect.pstate { fill:rgb(128,128,128); fill-opacity:0.8; stroke-width:0; } \n");
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
index cd93195aedb3..e0781989cc31 100644
--- a/tools/perf/util/svghelper.h
+++ b/tools/perf/util/svghelper.h
@@ -1,5 +1,5 @@
-#ifndef _INCLUDE_GUARD_SVG_HELPER_
-#define _INCLUDE_GUARD_SVG_HELPER_
+#ifndef __PERF_SVGHELPER_H
+#define __PERF_SVGHELPER_H
#include "types.h"
@@ -25,4 +25,4 @@ extern void svg_close(void);
extern int svg_page_width;
-#endif
+#endif /* __PERF_SVGHELPER_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 47ea0609a760..2e6a0137fa73 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -2,14 +2,14 @@
#include "../perf.h"
#include "string.h"
#include "symbol.h"
+#include "thread.h"
#include "debug.h"
#include <libelf.h>
#include <gelf.h>
#include <elf.h>
-
-const char *sym_hist_filter;
+#include <sys/utsname.h>
enum dso_origin {
DSO__ORIG_KERNEL = 0,
@@ -18,12 +18,65 @@ enum dso_origin {
DSO__ORIG_UBUNTU,
DSO__ORIG_BUILDID,
DSO__ORIG_DSO,
+ DSO__ORIG_KMODULE,
DSO__ORIG_NOT_FOUND,
};
-static struct symbol *symbol__new(u64 start, u64 len,
- const char *name, unsigned int priv_size,
- u64 obj_start, int v)
+static void dsos__add(struct dso *dso);
+static struct dso *dsos__find(const char *name);
+static struct map *map__new2(u64 start, struct dso *dso);
+static void kernel_maps__insert(struct map *map);
+
+static struct rb_root kernel_maps;
+
+static void dso__fixup_sym_end(struct dso *self)
+{
+ struct rb_node *nd, *prevnd = rb_first(&self->syms);
+ struct symbol *curr, *prev;
+
+ if (prevnd == NULL)
+ return;
+
+ curr = rb_entry(prevnd, struct symbol, rb_node);
+
+ for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
+ prev = curr;
+ curr = rb_entry(nd, struct symbol, rb_node);
+
+ if (prev->end == prev->start)
+ prev->end = curr->start - 1;
+ }
+
+ /* Last entry */
+ if (curr->end == curr->start)
+ curr->end = roundup(curr->start, 4096);
+}
+
+static void kernel_maps__fixup_end(void)
+{
+ struct map *prev, *curr;
+ struct rb_node *nd, *prevnd = rb_first(&kernel_maps);
+
+ if (prevnd == NULL)
+ return;
+
+ curr = rb_entry(prevnd, struct map, rb_node);
+
+ for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
+ prev = curr;
+ curr = rb_entry(nd, struct map, rb_node);
+ prev->end = curr->start - 1;
+ }
+
+ nd = rb_last(&curr->dso->syms);
+ if (nd) {
+ struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
+ curr->end = sym->end;
+ }
+}
+
+static struct symbol *symbol__new(u64 start, u64 len, const char *name,
+ unsigned int priv_size)
{
size_t namelen = strlen(name) + 1;
struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
@@ -31,23 +84,15 @@ static struct symbol *symbol__new(u64 start, u64 len,
if (!self)
return NULL;
- if (v >= 2)
- printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n",
- (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start);
-
- self->obj_start= obj_start;
- self->hist = NULL;
- self->hist_sum = 0;
-
- if (sym_hist_filter && !strcmp(name, sym_hist_filter))
- self->hist = calloc(sizeof(u64), len);
-
if (priv_size) {
memset(self, 0, priv_size);
self = ((void *)self) + priv_size;
}
self->start = start;
self->end = len ? start + len - 1 : start;
+
+ pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
+
memcpy(self->name, name, namelen);
return self;
@@ -60,12 +105,8 @@ static void symbol__delete(struct symbol *self, unsigned int priv_size)
static size_t symbol__fprintf(struct symbol *self, FILE *fp)
{
- if (!self->module)
- return fprintf(fp, " %llx-%llx %s\n",
+ return fprintf(fp, " %llx-%llx %s\n",
self->start, self->end, self->name);
- else
- return fprintf(fp, " %llx-%llx %s \t[%s]\n",
- self->start, self->end, self->name, self->module->name);
}
struct dso *dso__new(const char *name, unsigned int sym_priv_size)
@@ -74,6 +115,8 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)
if (self != NULL) {
strcpy(self->name, name);
+ self->long_name = self->name;
+ self->short_name = self->name;
self->syms = RB_ROOT;
self->sym_priv_size = sym_priv_size;
self->find_symbol = dso__find_symbol;
@@ -100,6 +143,8 @@ static void dso__delete_symbols(struct dso *self)
void dso__delete(struct dso *self)
{
dso__delete_symbols(self);
+ if (self->long_name != self->name)
+ free(self->long_name);
free(self);
}
@@ -147,7 +192,7 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip)
size_t dso__fprintf(struct dso *self, FILE *fp)
{
- size_t ret = fprintf(fp, "dso: %s\n", self->name);
+ size_t ret = fprintf(fp, "dso: %s\n", self->short_name);
struct rb_node *nd;
for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
@@ -158,13 +203,16 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
return ret;
}
-static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
+/*
+ * Loads the function entries in /proc/kallsyms into kernel_map->dso,
+ * so that we can in the next step set the symbol ->end address and then
+ * call kernel_maps__split_kallsyms.
+ */
+static int kernel_maps__load_all_kallsyms(void)
{
- struct rb_node *nd, *prevnd;
char *line = NULL;
size_t n;
FILE *file = fopen("/proc/kallsyms", "r");
- int count = 0;
if (file == NULL)
goto out_failure;
@@ -174,6 +222,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
struct symbol *sym;
int line_len, len;
char symbol_type;
+ char *symbol_name;
line_len = getline(&line, &n, file);
if (line_len < 0)
@@ -196,44 +245,24 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
*/
if (symbol_type != 'T' && symbol_type != 'W')
continue;
+
+ symbol_name = line + len + 2;
/*
- * Well fix up the end later, when we have all sorted.
+ * Will fix up the end later, when we have all symbols sorted.
*/
- sym = symbol__new(start, 0xdead, line + len + 2,
- self->sym_priv_size, 0, v);
+ sym = symbol__new(start, 0, symbol_name,
+ kernel_map->dso->sym_priv_size);
if (sym == NULL)
goto out_delete_line;
- if (filter && filter(self, sym))
- symbol__delete(sym, self->sym_priv_size);
- else {
- dso__insert_symbol(self, sym);
- count++;
- }
- }
-
- /*
- * Now that we have all sorted out, just set the ->end of all
- * symbols
- */
- prevnd = rb_first(&self->syms);
-
- if (prevnd == NULL)
- goto out_delete_line;
-
- for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
- struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
- *curr = rb_entry(nd, struct symbol, rb_node);
-
- prev->end = curr->start - 1;
- prevnd = nd;
+ dso__insert_symbol(kernel_map->dso, sym);
}
free(line);
fclose(file);
- return count;
+ return 0;
out_delete_line:
free(line);
@@ -241,14 +270,124 @@ out_failure:
return -1;
}
-static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
+/*
+ * Split the symbols into maps, making sure there are no overlaps, i.e. the
+ * kernel range is broken in several maps, named [kernel].N, as we don't have
+ * the original ELF section names vmlinux have.
+ */
+static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules)
+{
+ struct map *map = kernel_map;
+ struct symbol *pos;
+ int count = 0;
+ struct rb_node *next = rb_first(&kernel_map->dso->syms);
+ int kernel_range = 0;
+
+ while (next) {
+ char *module;
+
+ pos = rb_entry(next, struct symbol, rb_node);
+ next = rb_next(&pos->rb_node);
+
+ module = strchr(pos->name, '\t');
+ if (module) {
+ if (!use_modules)
+ goto delete_symbol;
+
+ *module++ = '\0';
+
+ if (strcmp(map->dso->name, module)) {
+ map = kernel_maps__find_by_dso_name(module);
+ if (!map) {
+ pr_err("/proc/{kallsyms,modules} "
+ "inconsistency!\n");
+ return -1;
+ }
+ }
+ /*
+ * So that we look just like we get from .ko files,
+ * i.e. not prelinked, relative to map->start.
+ */
+ pos->start = map->map_ip(map, pos->start);
+ pos->end = map->map_ip(map, pos->end);
+ } else if (map != kernel_map) {
+ char dso_name[PATH_MAX];
+ struct dso *dso;
+
+ snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
+ kernel_range++);
+
+ dso = dso__new(dso_name,
+ kernel_map->dso->sym_priv_size);
+ if (dso == NULL)
+ return -1;
+
+ map = map__new2(pos->start, dso);
+ if (map == NULL) {
+ dso__delete(dso);
+ return -1;
+ }
+
+ map->map_ip = map->unmap_ip = identity__map_ip;
+ kernel_maps__insert(map);
+ ++kernel_range;
+ }
+
+ if (filter && filter(map, pos)) {
+delete_symbol:
+ rb_erase(&pos->rb_node, &kernel_map->dso->syms);
+ symbol__delete(pos, kernel_map->dso->sym_priv_size);
+ } else {
+ if (map != kernel_map) {
+ rb_erase(&pos->rb_node, &kernel_map->dso->syms);
+ dso__insert_symbol(map->dso, pos);
+ }
+ count++;
+ }
+ }
+
+ return count;
+}
+
+
+static int kernel_maps__load_kallsyms(symbol_filter_t filter, int use_modules)
+{
+ if (kernel_maps__load_all_kallsyms())
+ return -1;
+
+ dso__fixup_sym_end(kernel_map->dso);
+
+ return kernel_maps__split_kallsyms(filter, use_modules);
+}
+
+static size_t kernel_maps__fprintf(FILE *fp)
+{
+ size_t printed = fprintf(fp, "Kernel maps:\n");
+ struct rb_node *nd;
+
+ for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
+ struct map *pos = rb_entry(nd, struct map, rb_node);
+
+ printed += fprintf(fp, "Map:");
+ printed += map__fprintf(pos, fp);
+ if (verbose > 1) {
+ printed += dso__fprintf(pos->dso, fp);
+ printed += fprintf(fp, "--\n");
+ }
+ }
+
+ return printed + fprintf(fp, "END kernel maps\n");
+}
+
+static int dso__load_perf_map(struct dso *self, struct map *map,
+ symbol_filter_t filter)
{
char *line = NULL;
size_t n;
FILE *file;
int nr_syms = 0;
- file = fopen(self->name, "r");
+ file = fopen(self->long_name, "r");
if (file == NULL)
goto out_failure;
@@ -279,12 +418,12 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
continue;
sym = symbol__new(start, size, line + len,
- self->sym_priv_size, start, v);
+ self->sym_priv_size);
if (sym == NULL)
goto out_delete_line;
- if (filter && filter(self, sym))
+ if (filter && filter(map, sym))
symbol__delete(sym, self->sym_priv_size);
else {
dso__insert_symbol(self, sym);
@@ -393,7 +532,7 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
* And always look at the original dso, not at debuginfo packages, that
* have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
*/
-static int dso__synthesize_plt_symbols(struct dso *self, int v)
+static int dso__synthesize_plt_symbols(struct dso *self)
{
uint32_t nr_rel_entries, idx;
GElf_Sym sym;
@@ -409,11 +548,11 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
Elf *elf;
int nr = 0, symidx, fd, err = 0;
- fd = open(self->name, O_RDONLY);
+ fd = open(self->long_name, O_RDONLY);
if (fd < 0)
goto out;
- elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
+ elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
if (elf == NULL)
goto out_close;
@@ -477,7 +616,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
"%s@plt", elf_sym__name(&sym, symstrs));
f = symbol__new(plt_offset, shdr_plt.sh_entsize,
- sympltname, self->sym_priv_size, 0, v);
+ sympltname, self->sym_priv_size);
if (!f)
goto out_elf_end;
@@ -495,7 +634,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
"%s@plt", elf_sym__name(&sym, symstrs));
f = symbol__new(plt_offset, shdr_plt.sh_entsize,
- sympltname, self->sym_priv_size, 0, v);
+ sympltname, self->sym_priv_size);
if (!f)
goto out_elf_end;
@@ -513,14 +652,18 @@ out_close:
if (err == 0)
return nr;
out:
- fprintf(stderr, "%s: problems reading %s PLT info.\n",
- __func__, self->name);
+ pr_warning("%s: problems reading %s PLT info.\n",
+ __func__, self->long_name);
return 0;
}
-static int dso__load_sym(struct dso *self, int fd, const char *name,
- symbol_filter_t filter, int v, struct module *mod)
+static int dso__load_sym(struct dso *self, struct map *map, const char *name,
+ int fd, symbol_filter_t filter, int kernel,
+ int kmodule)
{
+ struct map *curr_map = map;
+ struct dso *curr_dso = self;
+ size_t dso_name_len = strlen(self->short_name);
Elf_Data *symstrs, *secstrs;
uint32_t nr_syms;
int err = -1;
@@ -531,19 +674,16 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
GElf_Sym sym;
Elf_Scn *sec, *sec_strndx;
Elf *elf;
- int nr = 0, kernel = !strcmp("[kernel]", self->name);
+ int nr = 0;
- elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
+ elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
if (elf == NULL) {
- if (v)
- fprintf(stderr, "%s: cannot read %s ELF file.\n",
- __func__, name);
+ pr_err("%s: cannot read %s ELF file.\n", __func__, name);
goto out_close;
}
if (gelf_getehdr(elf, &ehdr) == NULL) {
- if (v)
- fprintf(stderr, "%s: cannot get elf header.\n", __func__);
+ pr_err("%s: cannot get elf header.\n", __func__);
goto out_elf_end;
}
@@ -587,9 +727,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
struct symbol *f;
const char *elf_name;
- char *demangled;
- u64 obj_start;
- struct section *section = NULL;
+ char *demangled = NULL;
int is_label = elf_sym__is_label(&sym);
const char *section_name;
@@ -605,52 +743,85 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
if (is_label && !elf_sec__is_text(&shdr, secstrs))
continue;
+ elf_name = elf_sym__name(&sym, symstrs);
section_name = elf_sec__name(&shdr, secstrs);
- obj_start = sym.st_value;
- if (self->adjust_symbols) {
- if (v >= 2)
- printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
- (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
+ if (kernel || kmodule) {
+ char dso_name[PATH_MAX];
- sym.st_value -= shdr.sh_addr - shdr.sh_offset;
- }
+ if (strcmp(section_name,
+ curr_dso->short_name + dso_name_len) == 0)
+ goto new_symbol;
- if (mod) {
- section = mod->sections->find_section(mod->sections, section_name);
- if (section)
- sym.st_value += section->vma;
- else {
- fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
- mod->name, section_name);
- goto out_elf_end;
+ if (strcmp(section_name, ".text") == 0) {
+ curr_map = map;
+ curr_dso = self;
+ goto new_symbol;
}
+
+ snprintf(dso_name, sizeof(dso_name),
+ "%s%s", self->short_name, section_name);
+
+ curr_map = kernel_maps__find_by_dso_name(dso_name);
+ if (curr_map == NULL) {
+ u64 start = sym.st_value;
+
+ if (kmodule)
+ start += map->start + shdr.sh_offset;
+
+ curr_dso = dso__new(dso_name, self->sym_priv_size);
+ if (curr_dso == NULL)
+ goto out_elf_end;
+ curr_map = map__new2(start, curr_dso);
+ if (curr_map == NULL) {
+ dso__delete(curr_dso);
+ goto out_elf_end;
+ }
+ curr_map->map_ip = identity__map_ip;
+ curr_map->unmap_ip = identity__map_ip;
+ curr_dso->origin = DSO__ORIG_KERNEL;
+ kernel_maps__insert(curr_map);
+ dsos__add(curr_dso);
+ } else
+ curr_dso = curr_map->dso;
+
+ goto new_symbol;
+ }
+
+ if (curr_dso->adjust_symbols) {
+ pr_debug2("adjusting symbol: st_value: %Lx sh_addr: "
+ "%Lx sh_offset: %Lx\n", (u64)sym.st_value,
+ (u64)shdr.sh_addr, (u64)shdr.sh_offset);
+ sym.st_value -= shdr.sh_addr - shdr.sh_offset;
}
/*
* We need to figure out if the object was created from C++ sources
* DWARF DW_compile_unit has this, but we don't always have access
* to it...
*/
- elf_name = elf_sym__name(&sym, symstrs);
demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
if (demangled != NULL)
elf_name = demangled;
-
+new_symbol:
f = symbol__new(sym.st_value, sym.st_size, elf_name,
- self->sym_priv_size, obj_start, v);
+ curr_dso->sym_priv_size);
free(demangled);
if (!f)
goto out_elf_end;
- if (filter && filter(self, f))
- symbol__delete(f, self->sym_priv_size);
+ if (filter && filter(curr_map, f))
+ symbol__delete(f, curr_dso->sym_priv_size);
else {
- f->module = mod;
- dso__insert_symbol(self, f);
+ dso__insert_symbol(curr_dso, f);
nr++;
}
}
+ /*
+ * For misannotated, zeroed, ASM function sizes.
+ */
+ if (nr > 0)
+ dso__fixup_sym_end(self);
err = nr;
out_elf_end:
elf_end(elf);
@@ -660,7 +831,7 @@ out_close:
#define BUILD_ID_SIZE 128
-static char *dso__read_build_id(struct dso *self, int v)
+static char *dso__read_build_id(struct dso *self)
{
int i;
GElf_Ehdr ehdr;
@@ -670,22 +841,20 @@ static char *dso__read_build_id(struct dso *self, int v)
char *build_id = NULL, *bid;
unsigned char *raw;
Elf *elf;
- int fd = open(self->name, O_RDONLY);
+ int fd = open(self->long_name, O_RDONLY);
if (fd < 0)
goto out;
- elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
+ elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
if (elf == NULL) {
- if (v)
- fprintf(stderr, "%s: cannot read %s ELF file.\n",
- __func__, self->name);
+ pr_err("%s: cannot read %s ELF file.\n", __func__,
+ self->long_name);
goto out_close;
}
if (gelf_getehdr(elf, &ehdr) == NULL) {
- if (v)
- fprintf(stderr, "%s: cannot get elf header.\n", __func__);
+ pr_err("%s: cannot get elf header.\n", __func__);
goto out_elf_end;
}
@@ -707,8 +876,7 @@ static char *dso__read_build_id(struct dso *self, int v)
++raw;
bid += 2;
}
- if (v >= 2)
- printf("%s(%s): %s\n", __func__, self->name, build_id);
+ pr_debug2("%s(%s): %s\n", __func__, self->long_name, build_id);
out_elf_end:
elf_end(elf);
out_close:
@@ -726,6 +894,7 @@ char dso__symtab_origin(const struct dso *self)
[DSO__ORIG_UBUNTU] = 'u',
[DSO__ORIG_BUILDID] = 'b',
[DSO__ORIG_DSO] = 'd',
+ [DSO__ORIG_KMODULE] = 'K',
};
if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
@@ -733,7 +902,7 @@ char dso__symtab_origin(const struct dso *self)
return origin[self->origin];
}
-int dso__load(struct dso *self, symbol_filter_t filter, int v)
+int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
{
int size = PATH_MAX;
char *name = malloc(size), *build_id = NULL;
@@ -746,7 +915,7 @@ int dso__load(struct dso *self, symbol_filter_t filter, int v)
self->adjust_symbols = 0;
if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
- ret = dso__load_perf_map(self, filter, v);
+ ret = dso__load_perf_map(self, map, filter);
self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
DSO__ORIG_NOT_FOUND;
return ret;
@@ -759,13 +928,15 @@ more:
self->origin++;
switch (self->origin) {
case DSO__ORIG_FEDORA:
- snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
+ snprintf(name, size, "/usr/lib/debug%s.debug",
+ self->long_name);
break;
case DSO__ORIG_UBUNTU:
- snprintf(name, size, "/usr/lib/debug%s", self->name);
+ snprintf(name, size, "/usr/lib/debug%s",
+ self->long_name);
break;
case DSO__ORIG_BUILDID:
- build_id = dso__read_build_id(self, v);
+ build_id = dso__read_build_id(self);
if (build_id != NULL) {
snprintf(name, size,
"/usr/lib/debug/.build-id/%.2s/%s.debug",
@@ -776,7 +947,7 @@ more:
self->origin++;
/* Fall thru */
case DSO__ORIG_DSO:
- snprintf(name, size, "%s", self->name);
+ snprintf(name, size, "%s", self->long_name);
break;
default:
@@ -786,7 +957,7 @@ more:
fd = open(name, O_RDONLY);
} while (fd < 0);
- ret = dso__load_sym(self, fd, name, filter, v, NULL);
+ ret = dso__load_sym(self, map, name, fd, filter, 0, 0);
close(fd);
/*
@@ -796,7 +967,7 @@ more:
goto more;
if (ret > 0) {
- int nr_plt = dso__synthesize_plt_symbols(self, v);
+ int nr_plt = dso__synthesize_plt_symbols(self);
if (nr_plt > 0)
ret += nr_plt;
}
@@ -807,137 +978,321 @@ out:
return ret;
}
-static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
- symbol_filter_t filter, int v)
+struct map *kernel_map;
+
+static void kernel_maps__insert(struct map *map)
{
- struct module *mod = mod_dso__find_module(mods, name);
- int err = 0, fd;
+ maps__insert(&kernel_maps, map);
+}
- if (mod == NULL || !mod->active)
- return err;
+struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp)
+{
+ struct map *map = maps__find(&kernel_maps, ip);
- fd = open(mod->path, O_RDONLY);
+ if (mapp)
+ *mapp = map;
- if (fd < 0)
+ if (map) {
+ ip = map->map_ip(map, ip);
+ return map->dso->find_symbol(map->dso, ip);
+ }
+
+ return NULL;
+}
+
+struct map *kernel_maps__find_by_dso_name(const char *name)
+{
+ struct rb_node *nd;
+
+ for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
+ struct map *map = rb_entry(nd, struct map, rb_node);
+
+ if (map->dso && strcmp(map->dso->name, name) == 0)
+ return map;
+ }
+
+ return NULL;
+}
+
+static int dso__load_module_sym(struct dso *self, struct map *map,
+ symbol_filter_t filter)
+{
+ int err = 0, fd = open(self->long_name, O_RDONLY);
+
+ if (fd < 0) {
+ pr_err("%s: cannot open %s\n", __func__, self->long_name);
return err;
+ }
- err = dso__load_sym(self, fd, name, filter, v, mod);
+ err = dso__load_sym(self, map, self->long_name, fd, filter, 0, 1);
close(fd);
return err;
}
-int dso__load_modules(struct dso *self, symbol_filter_t filter, int v)
+static int dsos__load_modules_sym_dir(char *dirname, symbol_filter_t filter)
{
- struct mod_dso *mods = mod_dso__new_dso("modules");
- struct module *pos;
- struct rb_node *next;
- int err, count = 0;
+ struct dirent *dent;
+ int nr_symbols = 0, err;
+ DIR *dir = opendir(dirname);
- err = mod_dso__load_modules(mods);
+ if (!dir) {
+ pr_err("%s: cannot open %s dir\n", __func__, dirname);
+ return -1;
+ }
- if (err <= 0)
- return err;
+ while ((dent = readdir(dir)) != NULL) {
+ char path[PATH_MAX];
+
+ if (dent->d_type == DT_DIR) {
+ if (!strcmp(dent->d_name, ".") ||
+ !strcmp(dent->d_name, ".."))
+ continue;
+
+ snprintf(path, sizeof(path), "%s/%s",
+ dirname, dent->d_name);
+ err = dsos__load_modules_sym_dir(path, filter);
+ if (err < 0)
+ goto failure;
+ } else {
+ char *dot = strrchr(dent->d_name, '.'),
+ dso_name[PATH_MAX];
+ struct map *map;
+ struct rb_node *last;
+
+ if (dot == NULL || strcmp(dot, ".ko"))
+ continue;
+ snprintf(dso_name, sizeof(dso_name), "[%.*s]",
+ (int)(dot - dent->d_name), dent->d_name);
+
+ strxfrchar(dso_name, '-', '_');
+ map = kernel_maps__find_by_dso_name(dso_name);
+ if (map == NULL)
+ continue;
+
+ snprintf(path, sizeof(path), "%s/%s",
+ dirname, dent->d_name);
+
+ map->dso->long_name = strdup(path);
+ if (map->dso->long_name == NULL)
+ goto failure;
+
+ err = dso__load_module_sym(map->dso, map, filter);
+ if (err < 0)
+ goto failure;
+ last = rb_last(&map->dso->syms);
+ if (last) {
+ struct symbol *sym;
+ /*
+ * We do this here as well, even having the
+ * symbol size found in the symtab because
+ * misannotated ASM symbols may have the size
+ * set to zero.
+ */
+ dso__fixup_sym_end(map->dso);
+
+ sym = rb_entry(last, struct symbol, rb_node);
+ map->end = map->start + sym->end;
+ }
+ }
+ nr_symbols += err;
+ }
- /*
- * Iterate over modules, and load active symbols.
- */
- next = rb_first(&mods->mods);
- while (next) {
- pos = rb_entry(next, struct module, rb_node);
- err = dso__load_module(self, mods, pos->name, filter, v);
+ return nr_symbols;
+failure:
+ closedir(dir);
+ return -1;
+}
- if (err < 0)
- break;
+static int dsos__load_modules_sym(symbol_filter_t filter)
+{
+ struct utsname uts;
+ char modules_path[PATH_MAX];
- next = rb_next(&pos->rb_node);
- count += err;
- }
+ if (uname(&uts) < 0)
+ return -1;
- if (err < 0) {
- mod_dso__delete_modules(mods);
- mod_dso__delete_self(mods);
- return err;
- }
+ snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
+ uts.release);
- return count;
+ return dsos__load_modules_sym_dir(modules_path, filter);
}
-static inline void dso__fill_symbol_holes(struct dso *self)
+/*
+ * Constructor variant for modules (where we know from /proc/modules where
+ * they are loaded) and for vmlinux, where only after we load all the
+ * symbols we'll know where it starts and ends.
+ */
+static struct map *map__new2(u64 start, struct dso *dso)
{
- struct symbol *prev = NULL;
- struct rb_node *nd;
+ struct map *self = malloc(sizeof(*self));
- for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
- struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
+ if (self != NULL) {
+ self->start = start;
+ /*
+ * Will be filled after we load all the symbols
+ */
+ self->end = 0;
- if (prev) {
- u64 hole = 0;
- int alias = pos->start == prev->start;
+ self->pgoff = 0;
+ self->dso = dso;
+ self->map_ip = map__map_ip;
+ self->unmap_ip = map__unmap_ip;
+ RB_CLEAR_NODE(&self->rb_node);
+ }
+ return self;
+}
- if (!alias)
- hole = prev->start - pos->end - 1;
+static int dsos__load_modules(unsigned int sym_priv_size)
+{
+ char *line = NULL;
+ size_t n;
+ FILE *file = fopen("/proc/modules", "r");
+ struct map *map;
- if (hole || alias) {
- if (alias)
- pos->end = prev->end;
- else if (hole)
- pos->end = prev->start - 1;
- }
+ if (file == NULL)
+ return -1;
+
+ while (!feof(file)) {
+ char name[PATH_MAX];
+ u64 start;
+ struct dso *dso;
+ char *sep;
+ int line_len;
+
+ line_len = getline(&line, &n, file);
+ if (line_len < 0)
+ break;
+
+ if (!line)
+ goto out_failure;
+
+ line[--line_len] = '\0'; /* \n */
+
+ sep = strrchr(line, 'x');
+ if (sep == NULL)
+ continue;
+
+ hex2u64(sep + 1, &start);
+
+ sep = strchr(line, ' ');
+ if (sep == NULL)
+ continue;
+
+ *sep = '\0';
+
+ snprintf(name, sizeof(name), "[%s]", line);
+ dso = dso__new(name, sym_priv_size);
+
+ if (dso == NULL)
+ goto out_delete_line;
+
+ map = map__new2(start, dso);
+ if (map == NULL) {
+ dso__delete(dso);
+ goto out_delete_line;
}
- prev = pos;
+
+ dso->origin = DSO__ORIG_KMODULE;
+ kernel_maps__insert(map);
+ dsos__add(dso);
}
+
+ free(line);
+ fclose(file);
+
+ return 0;
+
+out_delete_line:
+ free(line);
+out_failure:
+ return -1;
}
-static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
- symbol_filter_t filter, int v)
+static int dso__load_vmlinux(struct dso *self, struct map *map,
+ const char *vmlinux, symbol_filter_t filter)
{
int err, fd = open(vmlinux, O_RDONLY);
if (fd < 0)
return -1;
- err = dso__load_sym(self, fd, vmlinux, filter, v, NULL);
-
- if (err > 0)
- dso__fill_symbol_holes(self);
+ err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0);
close(fd);
return err;
}
-int dso__load_kernel(struct dso *self, const char *vmlinux,
- symbol_filter_t filter, int v, int use_modules)
+int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
+ symbol_filter_t filter, int use_modules)
{
int err = -1;
+ struct dso *dso = dso__new(vmlinux, sym_priv_size);
+
+ if (dso == NULL)
+ return -1;
+
+ dso->short_name = "[kernel]";
+ kernel_map = map__new2(0, dso);
+ if (kernel_map == NULL)
+ goto out_delete_dso;
+
+ kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip;
+
+ if (use_modules && dsos__load_modules(sym_priv_size) < 0) {
+ pr_warning("Failed to load list of modules in use! "
+ "Continuing...\n");
+ use_modules = 0;
+ }
if (vmlinux) {
- err = dso__load_vmlinux(self, vmlinux, filter, v);
+ err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter);
if (err > 0 && use_modules) {
- int syms = dso__load_modules(self, filter, v);
+ int syms = dsos__load_modules_sym(filter);
- if (syms < 0) {
- fprintf(stderr, "dso__load_modules failed!\n");
- return syms;
- }
- err += syms;
+ if (syms < 0)
+ pr_warning("Failed to read module symbols!"
+ " Continuing...\n");
+ else
+ err += syms;
}
}
if (err <= 0)
- err = dso__load_kallsyms(self, filter, v);
+ err = kernel_maps__load_kallsyms(filter, use_modules);
+
+ if (err > 0) {
+ struct rb_node *node = rb_first(&dso->syms);
+ struct symbol *sym = rb_entry(node, struct symbol, rb_node);
+
+ kernel_map->start = sym->start;
+ node = rb_last(&dso->syms);
+ sym = rb_entry(node, struct symbol, rb_node);
+ kernel_map->end = sym->end;
+
+ dso->origin = DSO__ORIG_KERNEL;
+ kernel_maps__insert(kernel_map);
+ /*
+ * Now that we have all sorted out, just set the ->end of all
+ * maps:
+ */
+ kernel_maps__fixup_end();
+ dsos__add(dso);
- if (err > 0)
- self->origin = DSO__ORIG_KERNEL;
+ if (verbose)
+ kernel_maps__fprintf(stderr);
+ }
return err;
+
+out_delete_dso:
+ dso__delete(dso);
+ return -1;
}
LIST_HEAD(dsos);
-struct dso *kernel_dso;
struct dso *vdso;
-struct dso *hypervisor_dso;
const char *vmlinux_name = "vmlinux";
int modules;
@@ -957,33 +1312,21 @@ static struct dso *dsos__find(const char *name)
return NULL;
}
-struct dso *dsos__findnew(const char *name)
+struct dso *dsos__findnew(const char *name, unsigned int sym_priv_size,
+ bool *is_new)
{
struct dso *dso = dsos__find(name);
- int nr;
- if (dso)
- return dso;
-
- dso = dso__new(name, 0);
- if (!dso)
- goto out_delete_dso;
-
- nr = dso__load(dso, NULL, verbose);
- if (nr < 0) {
- eprintf("Failed to open: %s\n", name);
- goto out_delete_dso;
- }
- if (!nr)
- eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
-
- dsos__add(dso);
+ if (!dso) {
+ dso = dso__new(name, sym_priv_size);
+ if (dso) {
+ dsos__add(dso);
+ *is_new = true;
+ }
+ } else
+ *is_new = false;
return dso;
-
-out_delete_dso:
- dso__delete(dso);
- return NULL;
}
void dsos__fprintf(FILE *fp)
@@ -994,43 +1337,21 @@ void dsos__fprintf(FILE *fp)
dso__fprintf(pos, fp);
}
-static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
-{
- return dso__find_symbol(dso, ip);
-}
-
-int load_kernel(void)
+int load_kernel(unsigned int sym_priv_size, symbol_filter_t filter)
{
- int err;
-
- kernel_dso = dso__new("[kernel]", 0);
- if (!kernel_dso)
+ if (dsos__load_kernel(vmlinux_name, sym_priv_size, filter,
+ modules) <= 0)
return -1;
- err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules);
- if (err <= 0) {
- dso__delete(kernel_dso);
- kernel_dso = NULL;
- } else
- dsos__add(kernel_dso);
-
vdso = dso__new("[vdso]", 0);
if (!vdso)
return -1;
- vdso->find_symbol = vdso__find_symbol;
-
dsos__add(vdso);
- hypervisor_dso = dso__new("[hypervisor]", 0);
- if (!hypervisor_dso)
- return -1;
- dsos__add(hypervisor_dso);
-
- return err;
+ return 0;
}
-
void symbol__init(void)
{
elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 6e8490716408..5ae673025121 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -1,11 +1,11 @@
-#ifndef _PERF_SYMBOL_
-#define _PERF_SYMBOL_ 1
+#ifndef __PERF_SYMBOL
+#define __PERF_SYMBOL 1
#include <linux/types.h>
+#include <stdbool.h>
#include "types.h"
#include <linux/list.h>
#include <linux/rbtree.h>
-#include "module.h"
#include "event.h"
#ifdef HAVE_CPLUS_DEMANGLE
@@ -27,6 +27,16 @@ static inline char *bfd_demangle(void __used *v, const char __used *c,
#endif
#endif
+/*
+ * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP;
+ * for newer versions we can use mmap to reduce memory usage:
+ */
+#ifdef LIBELF_NO_MMAP
+# define PERF_ELF_C_READ_MMAP ELF_C_READ
+#else
+# define PERF_ELF_C_READ_MMAP ELF_C_READ_MMAP
+#endif
+
#ifndef DMGL_PARAMS
#define DMGL_PARAMS (1 << 0) /* Include function args */
#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
@@ -36,11 +46,6 @@ struct symbol {
struct rb_node rb_node;
u64 start;
u64 end;
- u64 obj_start;
- u64 hist_sum;
- u64 *hist;
- struct module *module;
- void *priv;
char name[0];
};
@@ -52,13 +57,11 @@ struct dso {
unsigned char adjust_symbols;
unsigned char slen_calculated;
unsigned char origin;
+ const char *short_name;
+ char *long_name;
char name[0];
};
-extern const char *sym_hist_filter;
-
-typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym);
-
struct dso *dso__new(const char *name, unsigned int sym_priv_size);
void dso__delete(struct dso *self);
@@ -69,24 +72,23 @@ static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
struct symbol *dso__find_symbol(struct dso *self, u64 ip);
-int dso__load_kernel(struct dso *self, const char *vmlinux,
- symbol_filter_t filter, int verbose, int modules);
-int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
-int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
-struct dso *dsos__findnew(const char *name);
+int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
+ symbol_filter_t filter, int modules);
+struct dso *dsos__findnew(const char *name, unsigned int sym_priv_size,
+ bool *is_new);
+int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
void dsos__fprintf(FILE *fp);
size_t dso__fprintf(struct dso *self, FILE *fp);
char dso__symtab_origin(const struct dso *self);
-int load_kernel(void);
+int load_kernel(unsigned int sym_priv_size, symbol_filter_t filter);
void symbol__init(void);
extern struct list_head dsos;
-extern struct dso *kernel_dso;
+extern struct map *kernel_map;
extern struct dso *vdso;
-extern struct dso *hypervisor_dso;
extern const char *vmlinux_name;
extern int modules;
-#endif /* _PERF_SYMBOL_ */
+#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 45efb5db0d19..0f6d78c9863a 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -6,6 +6,9 @@
#include "util.h"
#include "debug.h"
+static struct rb_root threads;
+static struct thread *last_match;
+
static struct thread *thread__new(pid_t pid)
{
struct thread *self = calloc(1, sizeof(*self));
@@ -15,7 +18,8 @@ static struct thread *thread__new(pid_t pid)
self->comm = malloc(32);
if (self->comm)
snprintf(self->comm, 32, ":%d", self->pid);
- INIT_LIST_HEAD(&self->maps);
+ self->maps = RB_ROOT;
+ INIT_LIST_HEAD(&self->removed_maps);
}
return self;
@@ -29,21 +33,40 @@ int thread__set_comm(struct thread *self, const char *comm)
return self->comm ? 0 : -ENOMEM;
}
+int thread__comm_len(struct thread *self)
+{
+ if (!self->comm_len) {
+ if (!self->comm)
+ return 0;
+ self->comm_len = strlen(self->comm);
+ }
+
+ return self->comm_len;
+}
+
static size_t thread__fprintf(struct thread *self, FILE *fp)
{
+ struct rb_node *nd;
struct map *pos;
- size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
+ size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n",
+ self->pid, self->comm);
- list_for_each_entry(pos, &self->maps, node)
+ for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) {
+ pos = rb_entry(nd, struct map, rb_node);
+ ret += map__fprintf(pos, fp);
+ }
+
+ ret = fprintf(fp, "Removed maps:\n");
+
+ list_for_each_entry(pos, &self->removed_maps, node)
ret += map__fprintf(pos, fp);
return ret;
}
-struct thread *
-threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
+struct thread *threads__findnew(pid_t pid)
{
- struct rb_node **p = &threads->rb_node;
+ struct rb_node **p = &threads.rb_node;
struct rb_node *parent = NULL;
struct thread *th;
@@ -52,15 +75,15 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
* so most of the time we dont have to look up
* the full rbtree:
*/
- if (*last_match && (*last_match)->pid == pid)
- return *last_match;
+ if (last_match && last_match->pid == pid)
+ return last_match;
while (*p != NULL) {
parent = *p;
th = rb_entry(parent, struct thread, rb_node);
if (th->pid == pid) {
- *last_match = th;
+ last_match = th;
return th;
}
@@ -73,17 +96,16 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
th = thread__new(pid);
if (th != NULL) {
rb_link_node(&th->rb_node, parent, p);
- rb_insert_color(&th->rb_node, threads);
- *last_match = th;
+ rb_insert_color(&th->rb_node, &threads);
+ last_match = th;
}
return th;
}
-struct thread *
-register_idle_thread(struct rb_root *threads, struct thread **last_match)
+struct thread *register_idle_thread(void)
{
- struct thread *thread = threads__findnew(0, threads, last_match);
+ struct thread *thread = threads__findnew(0);
if (!thread || thread__set_comm(thread, "swapper")) {
fprintf(stderr, "problem inserting idle task.\n");
@@ -93,42 +115,82 @@ register_idle_thread(struct rb_root *threads, struct thread **last_match)
return thread;
}
-void thread__insert_map(struct thread *self, struct map *map)
+static void thread__remove_overlappings(struct thread *self, struct map *map)
{
- struct map *pos, *tmp;
-
- list_for_each_entry_safe(pos, tmp, &self->maps, node) {
- if (map__overlap(pos, map)) {
- if (verbose >= 2) {
- printf("overlapping maps:\n");
- map__fprintf(map, stdout);
- map__fprintf(pos, stdout);
- }
-
- if (map->start <= pos->start && map->end > pos->start)
- pos->start = map->end;
-
- if (map->end >= pos->end && map->start < pos->end)
- pos->end = map->start;
-
- if (verbose >= 2) {
- printf("after collision:\n");
- map__fprintf(pos, stdout);
- }
-
- if (pos->start >= pos->end) {
- list_del_init(&pos->node);
- free(pos);
- }
+ struct rb_node *next = rb_first(&self->maps);
+
+ while (next) {
+ struct map *pos = rb_entry(next, struct map, rb_node);
+ next = rb_next(&pos->rb_node);
+
+ if (!map__overlap(pos, map))
+ continue;
+
+ if (verbose >= 2) {
+ fputs("overlapping maps:\n", stderr);
+ map__fprintf(map, stderr);
+ map__fprintf(pos, stderr);
}
+
+ rb_erase(&pos->rb_node, &self->maps);
+ /*
+ * We may have references to this map, for instance in some
+ * hist_entry instances, so just move them to a separate
+ * list.
+ */
+ list_add_tail(&pos->node, &self->removed_maps);
+ }
+}
+
+void maps__insert(struct rb_root *maps, struct map *map)
+{
+ struct rb_node **p = &maps->rb_node;
+ struct rb_node *parent = NULL;
+ const u64 ip = map->start;
+ struct map *m;
+
+ while (*p != NULL) {
+ parent = *p;
+ m = rb_entry(parent, struct map, rb_node);
+ if (ip < m->start)
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
}
- list_add_tail(&map->node, &self->maps);
+ rb_link_node(&map->rb_node, parent, p);
+ rb_insert_color(&map->rb_node, maps);
+}
+
+struct map *maps__find(struct rb_root *maps, u64 ip)
+{
+ struct rb_node **p = &maps->rb_node;
+ struct rb_node *parent = NULL;
+ struct map *m;
+
+ while (*p != NULL) {
+ parent = *p;
+ m = rb_entry(parent, struct map, rb_node);
+ if (ip < m->start)
+ p = &(*p)->rb_left;
+ else if (ip > m->end)
+ p = &(*p)->rb_right;
+ else
+ return m;
+ }
+
+ return NULL;
+}
+
+void thread__insert_map(struct thread *self, struct map *map)
+{
+ thread__remove_overlappings(self, map);
+ maps__insert(&self->maps, map);
}
int thread__fork(struct thread *self, struct thread *parent)
{
- struct map *map;
+ struct rb_node *nd;
if (self->comm)
free(self->comm);
@@ -136,7 +198,8 @@ int thread__fork(struct thread *self, struct thread *parent)
if (!self->comm)
return -ENOMEM;
- list_for_each_entry(map, &parent->maps, node) {
+ for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) {
+ struct map *map = rb_entry(nd, struct map, rb_node);
struct map *new = map__clone(map);
if (!new)
return -ENOMEM;
@@ -146,26 +209,12 @@ int thread__fork(struct thread *self, struct thread *parent)
return 0;
}
-struct map *thread__find_map(struct thread *self, u64 ip)
-{
- struct map *pos;
-
- if (self == NULL)
- return NULL;
-
- list_for_each_entry(pos, &self->maps, node)
- if (ip >= pos->start && ip <= pos->end)
- return pos;
-
- return NULL;
-}
-
-size_t threads__fprintf(FILE *fp, struct rb_root *threads)
+size_t threads__fprintf(FILE *fp)
{
size_t ret = 0;
struct rb_node *nd;
- for (nd = rb_first(threads); nd; nd = rb_next(nd)) {
+ for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
struct thread *pos = rb_entry(nd, struct thread, rb_node);
ret += thread__fprintf(pos, fp);
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 32aea3c1c2ad..53addd77ce8f 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -1,22 +1,37 @@
+#ifndef __PERF_THREAD_H
+#define __PERF_THREAD_H
+
#include <linux/rbtree.h>
-#include <linux/list.h>
#include <unistd.h>
#include "symbol.h"
struct thread {
struct rb_node rb_node;
- struct list_head maps;
+ struct rb_root maps;
+ struct list_head removed_maps;
pid_t pid;
char shortname[3];
char *comm;
+ int comm_len;
};
int thread__set_comm(struct thread *self, const char *comm);
-struct thread *
-threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match);
-struct thread *
-register_idle_thread(struct rb_root *threads, struct thread **last_match);
+int thread__comm_len(struct thread *self);
+struct thread *threads__findnew(pid_t pid);
+struct thread *register_idle_thread(void);
void thread__insert_map(struct thread *self, struct map *map);
int thread__fork(struct thread *self, struct thread *parent);
-struct map *thread__find_map(struct thread *self, u64 ip);
-size_t threads__fprintf(FILE *fp, struct rb_root *threads);
+size_t threads__fprintf(FILE *fp);
+
+void maps__insert(struct rb_root *maps, struct map *map);
+struct map *maps__find(struct rb_root *maps, u64 ip);
+
+struct symbol *kernel_maps__find_symbol(const u64 ip, struct map **mapp);
+struct map *kernel_maps__find_by_dso_name(const char *name);
+
+static inline struct map *thread__find_map(struct thread *self, u64 ip)
+{
+ return self ? maps__find(&self->maps, ip) : NULL;
+}
+
+#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index af4b0573b37f..831052d4b4fb 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -496,14 +496,12 @@ get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events)
return path.next;
}
-void read_tracing_data(struct perf_event_attr *pattrs, int nb_events)
+void read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
{
char buf[BUFSIZ];
struct tracepoint_path *tps;
- output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
- if (output_fd < 0)
- die("creating file '%s'", output_file);
+ output_fd = fd;
buf[0] = 23;
buf[1] = 8;
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 55c9659a56e2..eae560503086 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -40,6 +40,8 @@ int header_page_size_size;
int header_page_data_offset;
int header_page_data_size;
+int latency_format;
+
static char *input_buf;
static unsigned long long input_buf_ptr;
static unsigned long long input_buf_siz;
@@ -284,18 +286,19 @@ void parse_ftrace_printk(char *file, unsigned int size __unused)
char *line;
char *next = NULL;
char *addr_str;
- int ret;
int i;
line = strtok_r(file, "\n", &next);
while (line) {
+ addr_str = strsep(&line, ":");
+ if (!line) {
+ warning("error parsing print strings");
+ break;
+ }
item = malloc_or_die(sizeof(*item));
- ret = sscanf(line, "%as : %as",
- (float *)(void *)&addr_str, /* workaround gcc warning */
- (float *)(void *)&item->printk);
item->addr = strtoull(addr_str, NULL, 16);
- free(addr_str);
-
+ /* fmt still has a space, skip it */
+ item->printk = strdup(line+1);
item->next = list;
list = item;
line = strtok_r(NULL, "\n", &next);
@@ -522,7 +525,10 @@ static enum event_type __read_token(char **tok)
last_ch = ch;
ch = __read_char();
buf[i++] = ch;
- } while (ch != quote_ch && last_ch != '\\');
+ /* the '\' '\' will cancel itself */
+ if (ch == '\\' && last_ch == '\\')
+ last_ch = 0;
+ } while (ch != quote_ch || last_ch == '\\');
/* remove the last quote */
i--;
goto out;
@@ -610,7 +616,7 @@ static enum event_type read_token_item(char **tok)
static int test_type(enum event_type type, enum event_type expect)
{
if (type != expect) {
- die("Error: expected type %d but read %d",
+ warning("Error: expected type %d but read %d",
expect, type);
return -1;
}
@@ -621,13 +627,13 @@ static int test_type_token(enum event_type type, char *token,
enum event_type expect, const char *expect_tok)
{
if (type != expect) {
- die("Error: expected type %d but read %d",
+ warning("Error: expected type %d but read %d",
expect, type);
return -1;
}
if (strcmp(token, expect_tok) != 0) {
- die("Error: expected '%s' but read '%s'",
+ warning("Error: expected '%s' but read '%s'",
expect_tok, token);
return -1;
}
@@ -665,7 +671,7 @@ static int __read_expected(enum event_type expect, const char *str, int newline_
free_token(token);
- return 0;
+ return ret;
}
static int read_expected(enum event_type expect, const char *str)
@@ -682,10 +688,10 @@ static char *event_read_name(void)
{
char *token;
- if (read_expected(EVENT_ITEM, (char *)"name") < 0)
+ if (read_expected(EVENT_ITEM, "name") < 0)
return NULL;
- if (read_expected(EVENT_OP, (char *)":") < 0)
+ if (read_expected(EVENT_OP, ":") < 0)
return NULL;
if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -703,10 +709,10 @@ static int event_read_id(void)
char *token;
int id;
- if (read_expected_item(EVENT_ITEM, (char *)"ID") < 0)
+ if (read_expected_item(EVENT_ITEM, "ID") < 0)
return -1;
- if (read_expected(EVENT_OP, (char *)":") < 0)
+ if (read_expected(EVENT_OP, ":") < 0)
return -1;
if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -721,6 +727,24 @@ static int event_read_id(void)
return -1;
}
+static int field_is_string(struct format_field *field)
+{
+ if ((field->flags & FIELD_IS_ARRAY) &&
+ (!strstr(field->type, "char") || !strstr(field->type, "u8") ||
+ !strstr(field->type, "s8")))
+ return 1;
+
+ return 0;
+}
+
+static int field_is_dynamic(struct format_field *field)
+{
+ if (!strcmp(field->type, "__data_loc"))
+ return 1;
+
+ return 0;
+}
+
static int event_read_fields(struct event *event, struct format_field **fields)
{
struct format_field *field = NULL;
@@ -738,7 +762,7 @@ static int event_read_fields(struct event *event, struct format_field **fields)
count++;
- if (test_type_token(type, token, EVENT_ITEM, (char *)"field"))
+ if (test_type_token(type, token, EVENT_ITEM, "field"))
goto fail;
free_token(token);
@@ -753,7 +777,7 @@ static int event_read_fields(struct event *event, struct format_field **fields)
type = read_token(&token);
}
- if (test_type_token(type, token, EVENT_OP, (char *)":") < 0)
+ if (test_type_token(type, token, EVENT_OP, ":") < 0)
return -1;
if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -865,14 +889,20 @@ static int event_read_fields(struct event *event, struct format_field **fields)
free(brackets);
}
- if (test_type_token(type, token, EVENT_OP, (char *)";"))
+ if (field_is_string(field)) {
+ field->flags |= FIELD_IS_STRING;
+ if (field_is_dynamic(field))
+ field->flags |= FIELD_IS_DYNAMIC;
+ }
+
+ if (test_type_token(type, token, EVENT_OP, ";"))
goto fail;
free_token(token);
- if (read_expected(EVENT_ITEM, (char *)"offset") < 0)
+ if (read_expected(EVENT_ITEM, "offset") < 0)
goto fail_expect;
- if (read_expected(EVENT_OP, (char *)":") < 0)
+ if (read_expected(EVENT_OP, ":") < 0)
goto fail_expect;
if (read_expect_type(EVENT_ITEM, &token))
@@ -880,13 +910,13 @@ static int event_read_fields(struct event *event, struct format_field **fields)
field->offset = strtoul(token, NULL, 0);
free_token(token);
- if (read_expected(EVENT_OP, (char *)";") < 0)
+ if (read_expected(EVENT_OP, ";") < 0)
goto fail_expect;
- if (read_expected(EVENT_ITEM, (char *)"size") < 0)
+ if (read_expected(EVENT_ITEM, "size") < 0)
goto fail_expect;
- if (read_expected(EVENT_OP, (char *)":") < 0)
+ if (read_expected(EVENT_OP, ":") < 0)
goto fail_expect;
if (read_expect_type(EVENT_ITEM, &token))
@@ -894,11 +924,33 @@ static int event_read_fields(struct event *event, struct format_field **fields)
field->size = strtoul(token, NULL, 0);
free_token(token);
- if (read_expected(EVENT_OP, (char *)";") < 0)
+ if (read_expected(EVENT_OP, ";") < 0)
goto fail_expect;
- if (read_expect_type(EVENT_NEWLINE, &token) < 0)
- goto fail;
+ type = read_token(&token);
+ if (type != EVENT_NEWLINE) {
+ /* newer versions of the kernel have a "signed" type */
+ if (test_type_token(type, token, EVENT_ITEM, "signed"))
+ goto fail;
+
+ free_token(token);
+
+ if (read_expected(EVENT_OP, ":") < 0)
+ goto fail_expect;
+
+ if (read_expect_type(EVENT_ITEM, &token))
+ goto fail;
+
+ /* add signed type */
+
+ free_token(token);
+ if (read_expected(EVENT_OP, ";") < 0)
+ goto fail_expect;
+
+ if (read_expect_type(EVENT_NEWLINE, &token))
+ goto fail;
+ }
+
free_token(token);
*fields = field;
@@ -921,10 +973,10 @@ static int event_read_format(struct event *event)
char *token;
int ret;
- if (read_expected_item(EVENT_ITEM, (char *)"format") < 0)
+ if (read_expected_item(EVENT_ITEM, "format") < 0)
return -1;
- if (read_expected(EVENT_OP, (char *)":") < 0)
+ if (read_expected(EVENT_OP, ":") < 0)
return -1;
if (read_expect_type(EVENT_NEWLINE, &token))
@@ -984,7 +1036,7 @@ process_cond(struct event *event, struct print_arg *top, char **tok)
*tok = NULL;
type = process_arg(event, left, &token);
- if (test_type_token(type, token, EVENT_OP, (char *)":"))
+ if (test_type_token(type, token, EVENT_OP, ":"))
goto out_free;
arg->op.op = token;
@@ -1004,6 +1056,35 @@ out_free:
return EVENT_ERROR;
}
+static enum event_type
+process_array(struct event *event, struct print_arg *top, char **tok)
+{
+ struct print_arg *arg;
+ enum event_type type;
+ char *token = NULL;
+
+ arg = malloc_or_die(sizeof(*arg));
+ memset(arg, 0, sizeof(*arg));
+
+ *tok = NULL;
+ type = process_arg(event, arg, &token);
+ if (test_type_token(type, token, EVENT_OP, "]"))
+ goto out_free;
+
+ top->op.right = arg;
+
+ free_token(token);
+ type = read_token_item(&token);
+ *tok = token;
+
+ return type;
+
+out_free:
+ free_token(*tok);
+ free_arg(arg);
+ return EVENT_ERROR;
+}
+
static int get_op_prio(char *op)
{
if (!op[1]) {
@@ -1128,6 +1209,8 @@ process_op(struct event *event, struct print_arg *arg, char **tok)
strcmp(token, "*") == 0 ||
strcmp(token, "^") == 0 ||
strcmp(token, "/") == 0 ||
+ strcmp(token, "<") == 0 ||
+ strcmp(token, ">") == 0 ||
strcmp(token, "==") == 0 ||
strcmp(token, "!=") == 0) {
@@ -1144,17 +1227,46 @@ process_op(struct event *event, struct print_arg *arg, char **tok)
right = malloc_or_die(sizeof(*right));
- type = process_arg(event, right, tok);
+ type = read_token_item(&token);
+ *tok = token;
+
+ /* could just be a type pointer */
+ if ((strcmp(arg->op.op, "*") == 0) &&
+ type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
+ if (left->type != PRINT_ATOM)
+ die("bad pointer type");
+ left->atom.atom = realloc(left->atom.atom,
+ sizeof(left->atom.atom) + 3);
+ strcat(left->atom.atom, " *");
+ *arg = *left;
+ free(arg);
+
+ return type;
+ }
+
+ type = process_arg_token(event, right, tok, type);
arg->op.right = right;
+ } else if (strcmp(token, "[") == 0) {
+
+ left = malloc_or_die(sizeof(*left));
+ *left = *arg;
+
+ arg->type = PRINT_OP;
+ arg->op.op = token;
+ arg->op.left = left;
+
+ arg->op.prio = 0;
+ type = process_array(event, arg, tok);
+
} else {
- die("unknown op '%s'", token);
+ warning("unknown op '%s'", token);
+ event->flags |= EVENT_FL_FAILED;
/* the arg is now the left side */
return EVENT_NONE;
}
-
if (type == EVENT_OP) {
int prio;
@@ -1178,7 +1290,7 @@ process_entry(struct event *event __unused, struct print_arg *arg,
char *field;
char *token;
- if (read_expected(EVENT_OP, (char *)"->") < 0)
+ if (read_expected(EVENT_OP, "->") < 0)
return EVENT_ERROR;
if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -1338,14 +1450,14 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
do {
free_token(token);
type = read_token_item(&token);
- if (test_type_token(type, token, EVENT_OP, (char *)"{"))
+ if (test_type_token(type, token, EVENT_OP, "{"))
break;
arg = malloc_or_die(sizeof(*arg));
free_token(token);
type = process_arg(event, arg, &token);
- if (test_type_token(type, token, EVENT_DELIM, (char *)","))
+ if (test_type_token(type, token, EVENT_DELIM, ","))
goto out_free;
field = malloc_or_die(sizeof(*field));
@@ -1356,7 +1468,7 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
free_token(token);
type = process_arg(event, arg, &token);
- if (test_type_token(type, token, EVENT_OP, (char *)"}"))
+ if (test_type_token(type, token, EVENT_OP, "}"))
goto out_free;
value = arg_eval(arg);
@@ -1391,13 +1503,13 @@ process_flags(struct event *event, struct print_arg *arg, char **tok)
memset(arg, 0, sizeof(*arg));
arg->type = PRINT_FLAGS;
- if (read_expected_item(EVENT_DELIM, (char *)"(") < 0)
+ if (read_expected_item(EVENT_DELIM, "(") < 0)
return EVENT_ERROR;
field = malloc_or_die(sizeof(*field));
type = process_arg(event, field, &token);
- if (test_type_token(type, token, EVENT_DELIM, (char *)","))
+ if (test_type_token(type, token, EVENT_DELIM, ","))
goto out_free;
arg->flags.field = field;
@@ -1408,11 +1520,11 @@ process_flags(struct event *event, struct print_arg *arg, char **tok)
type = read_token_item(&token);
}
- if (test_type_token(type, token, EVENT_DELIM, (char *)","))
+ if (test_type_token(type, token, EVENT_DELIM, ","))
goto out_free;
type = process_fields(event, &arg->flags.flags, &token);
- if (test_type_token(type, token, EVENT_DELIM, (char *)")"))
+ if (test_type_token(type, token, EVENT_DELIM, ")"))
goto out_free;
free_token(token);
@@ -1434,19 +1546,19 @@ process_symbols(struct event *event, struct print_arg *arg, char **tok)
memset(arg, 0, sizeof(*arg));
arg->type = PRINT_SYMBOL;
- if (read_expected_item(EVENT_DELIM, (char *)"(") < 0)
+ if (read_expected_item(EVENT_DELIM, "(") < 0)
return EVENT_ERROR;
field = malloc_or_die(sizeof(*field));
type = process_arg(event, field, &token);
- if (test_type_token(type, token, EVENT_DELIM, (char *)","))
+ if (test_type_token(type, token, EVENT_DELIM, ","))
goto out_free;
arg->symbol.field = field;
type = process_fields(event, &arg->symbol.symbols, &token);
- if (test_type_token(type, token, EVENT_DELIM, (char *)")"))
+ if (test_type_token(type, token, EVENT_DELIM, ")"))
goto out_free;
free_token(token);
@@ -1463,7 +1575,6 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
{
struct print_arg *item_arg;
enum event_type type;
- int ptr_cast = 0;
char *token;
type = process_arg(event, arg, &token);
@@ -1471,28 +1582,13 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
if (type == EVENT_ERROR)
return EVENT_ERROR;
- if (type == EVENT_OP) {
- /* handle the ptr casts */
- if (!strcmp(token, "*")) {
- /*
- * FIXME: should we zapp whitespaces before ')' ?
- * (may require a peek_token_item())
- */
- if (__peek_char() == ')') {
- ptr_cast = 1;
- free_token(token);
- type = read_token_item(&token);
- }
- }
- if (!ptr_cast) {
- type = process_op(event, arg, &token);
+ if (type == EVENT_OP)
+ type = process_op(event, arg, &token);
- if (type == EVENT_ERROR)
- return EVENT_ERROR;
- }
- }
+ if (type == EVENT_ERROR)
+ return EVENT_ERROR;
- if (test_type_token(type, token, EVENT_DELIM, (char *)")")) {
+ if (test_type_token(type, token, EVENT_DELIM, ")")) {
free_token(token);
return EVENT_ERROR;
}
@@ -1516,13 +1612,6 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
item_arg = malloc_or_die(sizeof(*item_arg));
arg->type = PRINT_TYPE;
- if (ptr_cast) {
- char *old = arg->atom.atom;
-
- arg->atom.atom = malloc_or_die(strlen(old + 3));
- sprintf(arg->atom.atom, "%s *", old);
- free(old);
- }
arg->typecast.type = arg->atom.atom;
arg->typecast.item = item_arg;
type = process_arg_token(event, item_arg, &token, type);
@@ -1540,7 +1629,7 @@ process_str(struct event *event __unused, struct print_arg *arg, char **tok)
enum event_type type;
char *token;
- if (read_expected(EVENT_DELIM, (char *)"(") < 0)
+ if (read_expected(EVENT_DELIM, "(") < 0)
return EVENT_ERROR;
if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -1550,7 +1639,7 @@ process_str(struct event *event __unused, struct print_arg *arg, char **tok)
arg->string.string = token;
arg->string.offset = -1;
- if (read_expected(EVENT_DELIM, (char *)")") < 0)
+ if (read_expected(EVENT_DELIM, ")") < 0)
return EVENT_ERROR;
type = read_token(&token);
@@ -1637,12 +1726,18 @@ process_arg_token(struct event *event, struct print_arg *arg,
static int event_read_print_args(struct event *event, struct print_arg **list)
{
- enum event_type type;
+ enum event_type type = EVENT_ERROR;
struct print_arg *arg;
char *token;
int args = 0;
do {
+ if (type == EVENT_NEWLINE) {
+ free_token(token);
+ type = read_token_item(&token);
+ continue;
+ }
+
arg = malloc_or_die(sizeof(*arg));
memset(arg, 0, sizeof(*arg));
@@ -1683,18 +1778,19 @@ static int event_read_print(struct event *event)
char *token;
int ret;
- if (read_expected_item(EVENT_ITEM, (char *)"print") < 0)
+ if (read_expected_item(EVENT_ITEM, "print") < 0)
return -1;
- if (read_expected(EVENT_ITEM, (char *)"fmt") < 0)
+ if (read_expected(EVENT_ITEM, "fmt") < 0)
return -1;
- if (read_expected(EVENT_OP, (char *)":") < 0)
+ if (read_expected(EVENT_OP, ":") < 0)
return -1;
if (read_expect_type(EVENT_DQUOTE, &token) < 0)
goto fail;
+ concat:
event->print_fmt.format = token;
event->print_fmt.args = NULL;
@@ -1704,7 +1800,22 @@ static int event_read_print(struct event *event)
if (type == EVENT_NONE)
return 0;
- if (test_type_token(type, token, EVENT_DELIM, (char *)","))
+ /* Handle concatination of print lines */
+ if (type == EVENT_DQUOTE) {
+ char *cat;
+
+ cat = malloc_or_die(strlen(event->print_fmt.format) +
+ strlen(token) + 1);
+ strcpy(cat, event->print_fmt.format);
+ strcat(cat, token);
+ free_token(token);
+ free_token(event->print_fmt.format);
+ event->print_fmt.format = NULL;
+ token = cat;
+ goto concat;
+ }
+
+ if (test_type_token(type, token, EVENT_DELIM, ","))
goto fail;
free_token(token);
@@ -1713,7 +1824,7 @@ static int event_read_print(struct event *event)
if (ret < 0)
return -1;
- return 0;
+ return ret;
fail:
free_token(token);
@@ -1822,37 +1933,67 @@ static int get_common_info(const char *type, int *offset, int *size)
return 0;
}
-int trace_parse_common_type(void *data)
+static int __parse_common(void *data, int *size, int *offset,
+ const char *name)
{
- static int type_offset;
- static int type_size;
int ret;
- if (!type_size) {
- ret = get_common_info("common_type",
- &type_offset,
- &type_size);
+ if (!*size) {
+ ret = get_common_info(name, offset, size);
if (ret < 0)
return ret;
}
- return read_size(data + type_offset, type_size);
+ return read_size(data + *offset, *size);
+}
+
+int trace_parse_common_type(void *data)
+{
+ static int type_offset;
+ static int type_size;
+
+ return __parse_common(data, &type_size, &type_offset,
+ "common_type");
}
static int parse_common_pid(void *data)
{
static int pid_offset;
static int pid_size;
+
+ return __parse_common(data, &pid_size, &pid_offset,
+ "common_pid");
+}
+
+static int parse_common_pc(void *data)
+{
+ static int pc_offset;
+ static int pc_size;
+
+ return __parse_common(data, &pc_size, &pc_offset,
+ "common_preempt_count");
+}
+
+static int parse_common_flags(void *data)
+{
+ static int flags_offset;
+ static int flags_size;
+
+ return __parse_common(data, &flags_size, &flags_offset,
+ "common_flags");
+}
+
+static int parse_common_lock_depth(void *data)
+{
+ static int ld_offset;
+ static int ld_size;
int ret;
- if (!pid_size) {
- ret = get_common_info("common_pid",
- &pid_offset,
- &pid_size);
- if (ret < 0)
- return ret;
- }
+ ret = __parse_common(data, &ld_size, &ld_offset,
+ "common_lock_depth");
+ if (ret < 0)
+ return -1;
- return read_size(data + pid_offset, pid_size);
+ return ret;
}
struct event *trace_find_event(int id)
@@ -1871,6 +2012,7 @@ static unsigned long long eval_num_arg(void *data, int size,
{
unsigned long long val = 0;
unsigned long long left, right;
+ struct print_arg *larg;
switch (arg->type) {
case PRINT_NULL:
@@ -1897,6 +2039,26 @@ static unsigned long long eval_num_arg(void *data, int size,
return 0;
break;
case PRINT_OP:
+ if (strcmp(arg->op.op, "[") == 0) {
+ /*
+ * Arrays are special, since we don't want
+ * to read the arg as is.
+ */
+ if (arg->op.left->type != PRINT_FIELD)
+ goto default_op; /* oops, all bets off */
+ larg = arg->op.left;
+ if (!larg->field.field) {
+ larg->field.field =
+ find_any_field(event, larg->field.name);
+ if (!larg->field.field)
+ die("field %s not found", larg->field.name);
+ }
+ right = eval_num_arg(data, size, event, arg->op.right);
+ val = read_size(data + larg->field.field->offset +
+ right * long_size, long_size);
+ break;
+ }
+ default_op:
left = eval_num_arg(data, size, event, arg->op.left);
right = eval_num_arg(data, size, event, arg->op.right);
switch (arg->op.op[0]) {
@@ -1947,6 +2109,12 @@ static unsigned long long eval_num_arg(void *data, int size,
die("unknown op '%s'", arg->op.op);
val = left == right;
break;
+ case '-':
+ val = left - right;
+ break;
+ case '+':
+ val = left + right;
+ break;
default:
die("unknown op '%s'", arg->op.op);
}
@@ -2145,8 +2313,9 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
case 'u':
case 'x':
case 'i':
- bptr = (void *)(((unsigned long)bptr + (long_size - 1)) &
- ~(long_size - 1));
+ /* the pointers are always 4 bytes aligned */
+ bptr = (void *)(((unsigned long)bptr + 3) &
+ ~3);
switch (ls) {
case 0:
case 1:
@@ -2270,7 +2439,27 @@ static void pretty_print(void *data, int size, struct event *event)
for (; *ptr; ptr++) {
ls = 0;
- if (*ptr == '%') {
+ if (*ptr == '\\') {
+ ptr++;
+ switch (*ptr) {
+ case 'n':
+ printf("\n");
+ break;
+ case 't':
+ printf("\t");
+ break;
+ case 'r':
+ printf("\r");
+ break;
+ case '\\':
+ printf("\\");
+ break;
+ default:
+ printf("%c", *ptr);
+ break;
+ }
+
+ } else if (*ptr == '%') {
saveptr = ptr;
show_func = 0;
cont_process:
@@ -2377,6 +2566,41 @@ static inline int log10_cpu(int nb)
return 1;
}
+static void print_lat_fmt(void *data, int size __unused)
+{
+ unsigned int lat_flags;
+ unsigned int pc;
+ int lock_depth;
+ int hardirq;
+ int softirq;
+
+ lat_flags = parse_common_flags(data);
+ pc = parse_common_pc(data);
+ lock_depth = parse_common_lock_depth(data);
+
+ hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
+ softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
+
+ printf("%c%c%c",
+ (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
+ (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
+ 'X' : '.',
+ (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
+ 'N' : '.',
+ (hardirq && softirq) ? 'H' :
+ hardirq ? 'h' : softirq ? 's' : '.');
+
+ if (pc)
+ printf("%x", pc);
+ else
+ printf(".");
+
+ if (lock_depth < 0)
+ printf(".");
+ else
+ printf("%d", lock_depth);
+}
+
/* taken from Linux, written by Frederic Weisbecker */
static void print_graph_cpu(int cpu)
{
@@ -2620,6 +2844,11 @@ pretty_print_func_ent(void *data, int size, struct event *event,
printf(" | ");
+ if (latency_format) {
+ print_lat_fmt(data, size);
+ printf(" | ");
+ }
+
field = find_field(event, "func");
if (!field)
die("function entry does not have func field");
@@ -2663,6 +2892,11 @@ pretty_print_func_ret(void *data, int size __unused, struct event *event,
printf(" | ");
+ if (latency_format) {
+ print_lat_fmt(data, size);
+ printf(" | ");
+ }
+
field = find_field(event, "rettime");
if (!field)
die("can't find rettime in return graph");
@@ -2724,7 +2958,7 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
event = trace_find_event(type);
if (!event) {
- printf("ug! no event found for type %d\n", type);
+ warning("ug! no event found for type %d", type);
return;
}
@@ -2734,9 +2968,20 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
return pretty_print_func_graph(data, size, event, cpu,
pid, comm, secs, usecs);
- printf("%16s-%-5d [%03d] %5lu.%09Lu: %s: ",
- comm, pid, cpu,
- secs, nsecs, event->name);
+ if (latency_format) {
+ printf("%8.8s-%-5d %3d",
+ comm, pid, cpu);
+ print_lat_fmt(data, size);
+ } else
+ printf("%16s-%-5d [%03d]", comm, pid, cpu);
+
+ printf(" %5lu.%06lu: %s: ", secs, usecs, event->name);
+
+ if (event->flags & EVENT_FL_FAILED) {
+ printf("EVENT '%s' FAILED TO PARSE\n",
+ event->name);
+ return;
+ }
pretty_print(data, size, event);
printf("\n");
@@ -2807,46 +3052,71 @@ static void print_args(struct print_arg *args)
}
}
-static void parse_header_field(char *type,
+static void parse_header_field(const char *field,
int *offset, int *size)
{
char *token;
+ int type;
- if (read_expected(EVENT_ITEM, (char *)"field") < 0)
+ if (read_expected(EVENT_ITEM, "field") < 0)
return;
- if (read_expected(EVENT_OP, (char *)":") < 0)
+ if (read_expected(EVENT_OP, ":") < 0)
return;
+
/* type */
if (read_expect_type(EVENT_ITEM, &token) < 0)
- return;
+ goto fail;
free_token(token);
- if (read_expected(EVENT_ITEM, type) < 0)
+ if (read_expected(EVENT_ITEM, field) < 0)
return;
- if (read_expected(EVENT_OP, (char *)";") < 0)
+ if (read_expected(EVENT_OP, ";") < 0)
return;
- if (read_expected(EVENT_ITEM, (char *)"offset") < 0)
+ if (read_expected(EVENT_ITEM, "offset") < 0)
return;
- if (read_expected(EVENT_OP, (char *)":") < 0)
+ if (read_expected(EVENT_OP, ":") < 0)
return;
if (read_expect_type(EVENT_ITEM, &token) < 0)
- return;
+ goto fail;
*offset = atoi(token);
free_token(token);
- if (read_expected(EVENT_OP, (char *)";") < 0)
+ if (read_expected(EVENT_OP, ";") < 0)
return;
- if (read_expected(EVENT_ITEM, (char *)"size") < 0)
+ if (read_expected(EVENT_ITEM, "size") < 0)
return;
- if (read_expected(EVENT_OP, (char *)":") < 0)
+ if (read_expected(EVENT_OP, ":") < 0)
return;
if (read_expect_type(EVENT_ITEM, &token) < 0)
- return;
+ goto fail;
*size = atoi(token);
free_token(token);
- if (read_expected(EVENT_OP, (char *)";") < 0)
- return;
- if (read_expect_type(EVENT_NEWLINE, &token) < 0)
+ if (read_expected(EVENT_OP, ";") < 0)
return;
+ type = read_token(&token);
+ if (type != EVENT_NEWLINE) {
+ /* newer versions of the kernel have a "signed" type */
+ if (type != EVENT_ITEM)
+ goto fail;
+
+ if (strcmp(token, "signed") != 0)
+ goto fail;
+
+ free_token(token);
+
+ if (read_expected(EVENT_OP, ":") < 0)
+ return;
+
+ if (read_expect_type(EVENT_ITEM, &token))
+ goto fail;
+
+ free_token(token);
+ if (read_expected(EVENT_OP, ";") < 0)
+ return;
+
+ if (read_expect_type(EVENT_NEWLINE, &token))
+ goto fail;
+ }
+ fail:
free_token(token);
}
@@ -2854,11 +3124,11 @@ int parse_header_page(char *buf, unsigned long size)
{
init_input_buf(buf, size);
- parse_header_field((char *)"timestamp", &header_page_ts_offset,
+ parse_header_field("timestamp", &header_page_ts_offset,
&header_page_ts_size);
- parse_header_field((char *)"commit", &header_page_size_offset,
+ parse_header_field("commit", &header_page_size_offset,
&header_page_size_size);
- parse_header_field((char *)"data", &header_page_data_offset,
+ parse_header_field("data", &header_page_data_offset,
&header_page_data_size);
return 0;
@@ -2909,6 +3179,9 @@ int parse_ftrace_file(char *buf, unsigned long size)
if (ret < 0)
die("failed to read ftrace event print fmt");
+ /* New ftrace handles args */
+ if (ret > 0)
+ return 0;
/*
* The arguments for ftrace files are parsed by the fields.
* Set up the fields as their arguments.
@@ -2926,7 +3199,7 @@ int parse_ftrace_file(char *buf, unsigned long size)
return 0;
}
-int parse_event_file(char *buf, unsigned long size, char *system__unused __unused)
+int parse_event_file(char *buf, unsigned long size, char *sys)
{
struct event *event;
int ret;
@@ -2946,12 +3219,18 @@ int parse_event_file(char *buf, unsigned long size, char *system__unused __unuse
die("failed to read event id");
ret = event_read_format(event);
- if (ret < 0)
- die("failed to read event format");
+ if (ret < 0) {
+ warning("failed to read event format for %s", event->name);
+ goto event_failed;
+ }
ret = event_read_print(event);
- if (ret < 0)
- die("failed to read event print fmt");
+ if (ret < 0) {
+ warning("failed to read event print fmt for %s", event->name);
+ goto event_failed;
+ }
+
+ event->system = strdup(sys);
#define PRINT_ARGS 0
if (PRINT_ARGS && event->print_fmt.args)
@@ -2959,6 +3238,12 @@ int parse_event_file(char *buf, unsigned long size, char *system__unused __unuse
add_event(event);
return 0;
+
+ event_failed:
+ event->flags |= EVENT_FL_FAILED;
+ /* still add it even if it failed */
+ add_event(event);
+ return -1;
}
void parse_set_info(int nr_cpus, int long_sz)
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 1b5c847d2c22..44292e06cca4 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -458,9 +458,8 @@ struct record *trace_read_data(int cpu)
return data;
}
-void trace_report(void)
+void trace_report(int fd)
{
- const char *input_file = "trace.info";
char buf[BUFSIZ];
char test[] = { 23, 8, 68 };
char *version;
@@ -468,9 +467,7 @@ void trace_report(void)
int show_funcs = 0;
int show_printk = 0;
- input_fd = open(input_file, O_RDONLY);
- if (input_fd < 0)
- die("opening '%s'\n", input_file);
+ input_fd = fd;
read_or_die(buf, 3);
if (memcmp(buf, test, 3) != 0)
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 693f815c9429..f6637c2fa1fe 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -1,5 +1,5 @@
-#ifndef _TRACE_EVENTS_H
-#define _TRACE_EVENTS_H
+#ifndef __PERF_TRACE_EVENTS_H
+#define __PERF_TRACE_EVENTS_H
#include "parse-events.h"
@@ -26,6 +26,9 @@ enum {
enum format_flags {
FIELD_IS_ARRAY = 1,
FIELD_IS_POINTER = 2,
+ FIELD_IS_SIGNED = 4,
+ FIELD_IS_STRING = 8,
+ FIELD_IS_DYNAMIC = 16,
};
struct format_field {
@@ -132,15 +135,18 @@ struct event {
int flags;
struct format format;
struct print_fmt print_fmt;
+ char *system;
};
enum {
- EVENT_FL_ISFTRACE = 1,
- EVENT_FL_ISPRINT = 2,
- EVENT_FL_ISBPRINT = 4,
- EVENT_FL_ISFUNC = 8,
- EVENT_FL_ISFUNCENT = 16,
- EVENT_FL_ISFUNCRET = 32,
+ EVENT_FL_ISFTRACE = 0x01,
+ EVENT_FL_ISPRINT = 0x02,
+ EVENT_FL_ISBPRINT = 0x04,
+ EVENT_FL_ISFUNC = 0x08,
+ EVENT_FL_ISFUNCENT = 0x10,
+ EVENT_FL_ISFUNCRET = 0x20,
+
+ EVENT_FL_FAILED = 0x80000000
};
struct record {
@@ -154,7 +160,7 @@ struct record *trace_read_data(int cpu);
void parse_set_info(int nr_cpus, int long_sz);
-void trace_report(void);
+void trace_report(int fd);
void *malloc_or_die(unsigned int size);
@@ -166,7 +172,7 @@ void print_funcs(void);
void print_printk(void);
int parse_ftrace_file(char *buf, unsigned long size);
-int parse_event_file(char *buf, unsigned long size, char *system);
+int parse_event_file(char *buf, unsigned long size, char *sys);
void print_event(int cpu, void *data, int size, unsigned long long nsecs,
char *comm);
@@ -233,6 +239,8 @@ extern int header_page_size_size;
extern int header_page_data_offset;
extern int header_page_data_size;
+extern int latency_format;
+
int parse_header_page(char *buf, unsigned long size);
int trace_parse_common_type(void *data);
struct event *trace_find_event(int id);
@@ -240,6 +248,15 @@ unsigned long long
raw_field_value(struct event *event, const char *name, void *data);
void *raw_field_ptr(struct event *event, const char *name, void *data);
-void read_tracing_data(struct perf_event_attr *pattrs, int nb_events);
+void read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events);
+
+/* taken from kernel/trace/trace.h */
+enum trace_flag_type {
+ TRACE_FLAG_IRQS_OFF = 0x01,
+ TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
+ TRACE_FLAG_NEED_RESCHED = 0x04,
+ TRACE_FLAG_HARDIRQ = 0x08,
+ TRACE_FLAG_SOFTIRQ = 0x10,
+};
-#endif /* _TRACE_EVENTS_H */
+#endif /* __PERF_TRACE_EVENTS_H */
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
index 5e75f9005940..7d6b8331f898 100644
--- a/tools/perf/util/types.h
+++ b/tools/perf/util/types.h
@@ -1,5 +1,5 @@
-#ifndef _PERF_TYPES_H
-#define _PERF_TYPES_H
+#ifndef __PERF_TYPES_H
+#define __PERF_TYPES_H
/*
* We define u64 as unsigned long long for every architecture
@@ -14,4 +14,4 @@ typedef signed short s16;
typedef unsigned char u8;
typedef signed char s8;
-#endif /* _PERF_TYPES_H */
+#endif /* __PERF_TYPES_H */
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 9de2329dd44d..0daa341734f9 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -134,6 +134,15 @@ extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1,
extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
+#include "../../../include/linux/stringify.h"
+
+#define DIE_IF(cnd) \
+ do { if (cnd) \
+ die(" at (" __FILE__ ":" __stringify(__LINE__) "): " \
+ __stringify(cnd) "\n"); \
+ } while (0)
+
+
extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
extern int prefixcmp(const char *str, const char *prefix);
diff --git a/tools/perf/util/values.h b/tools/perf/util/values.h
index cadf8cf2a590..2fa967e1a88a 100644
--- a/tools/perf/util/values.h
+++ b/tools/perf/util/values.h
@@ -1,5 +1,5 @@
-#ifndef _PERF_VALUES_H
-#define _PERF_VALUES_H
+#ifndef __PERF_VALUES_H
+#define __PERF_VALUES_H
#include "types.h"
@@ -24,4 +24,4 @@ void perf_read_values_add_value(struct perf_read_values *values,
void perf_read_values_display(FILE *fp, struct perf_read_values *values,
int raw);
-#endif /* _PERF_VALUES_H */
+#endif /* __PERF_VALUES_H */
diff --git a/virt/kvm/assigned-dev.c b/virt/kvm/assigned-dev.c
new file mode 100644
index 000000000000..fd9c097b760a
--- /dev/null
+++ b/virt/kvm/assigned-dev.c
@@ -0,0 +1,818 @@
+/*
+ * Kernel-based Virtual Machine - device assignment support
+ *
+ * Copyright (C) 2006-9 Red Hat, Inc
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <linux/kvm_host.h>
+#include <linux/kvm.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include "irq.h"
+
+static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *head,
+ int assigned_dev_id)
+{
+ struct list_head *ptr;
+ struct kvm_assigned_dev_kernel *match;
+
+ list_for_each(ptr, head) {
+ match = list_entry(ptr, struct kvm_assigned_dev_kernel, list);
+ if (match->assigned_dev_id == assigned_dev_id)
+ return match;
+ }
+ return NULL;
+}
+
+static int find_index_from_host_irq(struct kvm_assigned_dev_kernel
+ *assigned_dev, int irq)
+{
+ int i, index;
+ struct msix_entry *host_msix_entries;
+
+ host_msix_entries = assigned_dev->host_msix_entries;
+
+ index = -1;
+ for (i = 0; i < assigned_dev->entries_nr; i++)
+ if (irq == host_msix_entries[i].vector) {
+ index = i;
+ break;
+ }
+ if (index < 0) {
+ printk(KERN_WARNING "Fail to find correlated MSI-X entry!\n");
+ return 0;
+ }
+
+ return index;
+}
+
+static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
+{
+ struct kvm_assigned_dev_kernel *assigned_dev;
+ struct kvm *kvm;
+ int i;
+
+ assigned_dev = container_of(work, struct kvm_assigned_dev_kernel,
+ interrupt_work);
+ kvm = assigned_dev->kvm;
+
+ spin_lock_irq(&assigned_dev->assigned_dev_lock);
+ if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
+ struct kvm_guest_msix_entry *guest_entries =
+ assigned_dev->guest_msix_entries;
+ for (i = 0; i < assigned_dev->entries_nr; i++) {
+ if (!(guest_entries[i].flags &
+ KVM_ASSIGNED_MSIX_PENDING))
+ continue;
+ guest_entries[i].flags &= ~KVM_ASSIGNED_MSIX_PENDING;
+ kvm_set_irq(assigned_dev->kvm,
+ assigned_dev->irq_source_id,
+ guest_entries[i].vector, 1);
+ }
+ } else
+ kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
+ assigned_dev->guest_irq, 1);
+
+ spin_unlock_irq(&assigned_dev->assigned_dev_lock);
+}
+
+static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id)
+{
+ unsigned long flags;
+ struct kvm_assigned_dev_kernel *assigned_dev =
+ (struct kvm_assigned_dev_kernel *) dev_id;
+
+ spin_lock_irqsave(&assigned_dev->assigned_dev_lock, flags);
+ if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
+ int index = find_index_from_host_irq(assigned_dev, irq);
+ if (index < 0)
+ goto out;
+ assigned_dev->guest_msix_entries[index].flags |=
+ KVM_ASSIGNED_MSIX_PENDING;
+ }
+
+ schedule_work(&assigned_dev->interrupt_work);
+
+ if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_GUEST_INTX) {
+ disable_irq_nosync(irq);
+ assigned_dev->host_irq_disabled = true;
+ }
+
+out:
+ spin_unlock_irqrestore(&assigned_dev->assigned_dev_lock, flags);
+ return IRQ_HANDLED;
+}
+
+/* Ack the irq line for an assigned device */
+static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian)
+{
+ struct kvm_assigned_dev_kernel *dev;
+ unsigned long flags;
+
+ if (kian->gsi == -1)
+ return;
+
+ dev = container_of(kian, struct kvm_assigned_dev_kernel,
+ ack_notifier);
+
+ kvm_set_irq(dev->kvm, dev->irq_source_id, dev->guest_irq, 0);
+
+ /* The guest irq may be shared so this ack may be
+ * from another device.
+ */
+ spin_lock_irqsave(&dev->assigned_dev_lock, flags);
+ if (dev->host_irq_disabled) {
+ enable_irq(dev->host_irq);
+ dev->host_irq_disabled = false;
+ }
+ spin_unlock_irqrestore(&dev->assigned_dev_lock, flags);
+}
+
+static void deassign_guest_irq(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *assigned_dev)
+{
+ kvm_unregister_irq_ack_notifier(kvm, &assigned_dev->ack_notifier);
+ assigned_dev->ack_notifier.gsi = -1;
+
+ if (assigned_dev->irq_source_id != -1)
+ kvm_free_irq_source_id(kvm, assigned_dev->irq_source_id);
+ assigned_dev->irq_source_id = -1;
+ assigned_dev->irq_requested_type &= ~(KVM_DEV_IRQ_GUEST_MASK);
+}
+
+/* The function implicit hold kvm->lock mutex due to cancel_work_sync() */
+static void deassign_host_irq(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *assigned_dev)
+{
+ /*
+ * In kvm_free_device_irq, cancel_work_sync return true if:
+ * 1. work is scheduled, and then cancelled.
+ * 2. work callback is executed.
+ *
+ * The first one ensured that the irq is disabled and no more events
+ * would happen. But for the second one, the irq may be enabled (e.g.
+ * for MSI). So we disable irq here to prevent further events.
+ *
+ * Notice this maybe result in nested disable if the interrupt type is
+ * INTx, but it's OK for we are going to free it.
+ *
+ * If this function is a part of VM destroy, please ensure that till
+ * now, the kvm state is still legal for probably we also have to wait
+ * interrupt_work done.
+ */
+ if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
+ int i;
+ for (i = 0; i < assigned_dev->entries_nr; i++)
+ disable_irq_nosync(assigned_dev->
+ host_msix_entries[i].vector);
+
+ cancel_work_sync(&assigned_dev->interrupt_work);
+
+ for (i = 0; i < assigned_dev->entries_nr; i++)
+ free_irq(assigned_dev->host_msix_entries[i].vector,
+ (void *)assigned_dev);
+
+ assigned_dev->entries_nr = 0;
+ kfree(assigned_dev->host_msix_entries);
+ kfree(assigned_dev->guest_msix_entries);
+ pci_disable_msix(assigned_dev->dev);
+ } else {
+ /* Deal with MSI and INTx */
+ disable_irq_nosync(assigned_dev->host_irq);
+ cancel_work_sync(&assigned_dev->interrupt_work);
+
+ free_irq(assigned_dev->host_irq, (void *)assigned_dev);
+
+ if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSI)
+ pci_disable_msi(assigned_dev->dev);
+ }
+
+ assigned_dev->irq_requested_type &= ~(KVM_DEV_IRQ_HOST_MASK);
+}
+
+static int kvm_deassign_irq(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *assigned_dev,
+ unsigned long irq_requested_type)
+{
+ unsigned long guest_irq_type, host_irq_type;
+
+ if (!irqchip_in_kernel(kvm))
+ return -EINVAL;
+ /* no irq assignment to deassign */
+ if (!assigned_dev->irq_requested_type)
+ return -ENXIO;
+
+ host_irq_type = irq_requested_type & KVM_DEV_IRQ_HOST_MASK;
+ guest_irq_type = irq_requested_type & KVM_DEV_IRQ_GUEST_MASK;
+
+ if (host_irq_type)
+ deassign_host_irq(kvm, assigned_dev);
+ if (guest_irq_type)
+ deassign_guest_irq(kvm, assigned_dev);
+
+ return 0;
+}
+
+static void kvm_free_assigned_irq(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *assigned_dev)
+{
+ kvm_deassign_irq(kvm, assigned_dev, assigned_dev->irq_requested_type);
+}
+
+static void kvm_free_assigned_device(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel
+ *assigned_dev)
+{
+ kvm_free_assigned_irq(kvm, assigned_dev);
+
+ pci_reset_function(assigned_dev->dev);
+
+ pci_release_regions(assigned_dev->dev);
+ pci_disable_device(assigned_dev->dev);
+ pci_dev_put(assigned_dev->dev);
+
+ list_del(&assigned_dev->list);
+ kfree(assigned_dev);
+}
+
+void kvm_free_all_assigned_devices(struct kvm *kvm)
+{
+ struct list_head *ptr, *ptr2;
+ struct kvm_assigned_dev_kernel *assigned_dev;
+
+ list_for_each_safe(ptr, ptr2, &kvm->arch.assigned_dev_head) {
+ assigned_dev = list_entry(ptr,
+ struct kvm_assigned_dev_kernel,
+ list);
+
+ kvm_free_assigned_device(kvm, assigned_dev);
+ }
+}
+
+static int assigned_device_enable_host_intx(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *dev)
+{
+ dev->host_irq = dev->dev->irq;
+ /* Even though this is PCI, we don't want to use shared
+ * interrupts. Sharing host devices with guest-assigned devices
+ * on the same interrupt line is not a happy situation: there
+ * are going to be long delays in accepting, acking, etc.
+ */
+ if (request_irq(dev->host_irq, kvm_assigned_dev_intr,
+ 0, "kvm_assigned_intx_device", (void *)dev))
+ return -EIO;
+ return 0;
+}
+
+#ifdef __KVM_HAVE_MSI
+static int assigned_device_enable_host_msi(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *dev)
+{
+ int r;
+
+ if (!dev->dev->msi_enabled) {
+ r = pci_enable_msi(dev->dev);
+ if (r)
+ return r;
+ }
+
+ dev->host_irq = dev->dev->irq;
+ if (request_irq(dev->host_irq, kvm_assigned_dev_intr, 0,
+ "kvm_assigned_msi_device", (void *)dev)) {
+ pci_disable_msi(dev->dev);
+ return -EIO;
+ }
+
+ return 0;
+}
+#endif
+
+#ifdef __KVM_HAVE_MSIX
+static int assigned_device_enable_host_msix(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *dev)
+{
+ int i, r = -EINVAL;
+
+ /* host_msix_entries and guest_msix_entries should have been
+ * initialized */
+ if (dev->entries_nr == 0)
+ return r;
+
+ r = pci_enable_msix(dev->dev, dev->host_msix_entries, dev->entries_nr);
+ if (r)
+ return r;
+
+ for (i = 0; i < dev->entries_nr; i++) {
+ r = request_irq(dev->host_msix_entries[i].vector,
+ kvm_assigned_dev_intr, 0,
+ "kvm_assigned_msix_device",
+ (void *)dev);
+ /* FIXME: free requested_irq's on failure */
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
+#endif
+
+static int assigned_device_enable_guest_intx(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *dev,
+ struct kvm_assigned_irq *irq)
+{
+ dev->guest_irq = irq->guest_irq;
+ dev->ack_notifier.gsi = irq->guest_irq;
+ return 0;
+}
+
+#ifdef __KVM_HAVE_MSI
+static int assigned_device_enable_guest_msi(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *dev,
+ struct kvm_assigned_irq *irq)
+{
+ dev->guest_irq = irq->guest_irq;
+ dev->ack_notifier.gsi = -1;
+ dev->host_irq_disabled = false;
+ return 0;
+}
+#endif
+
+#ifdef __KVM_HAVE_MSIX
+static int assigned_device_enable_guest_msix(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *dev,
+ struct kvm_assigned_irq *irq)
+{
+ dev->guest_irq = irq->guest_irq;
+ dev->ack_notifier.gsi = -1;
+ dev->host_irq_disabled = false;
+ return 0;
+}
+#endif
+
+static int assign_host_irq(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *dev,
+ __u32 host_irq_type)
+{
+ int r = -EEXIST;
+
+ if (dev->irq_requested_type & KVM_DEV_IRQ_HOST_MASK)
+ return r;
+
+ switch (host_irq_type) {
+ case KVM_DEV_IRQ_HOST_INTX:
+ r = assigned_device_enable_host_intx(kvm, dev);
+ break;
+#ifdef __KVM_HAVE_MSI
+ case KVM_DEV_IRQ_HOST_MSI:
+ r = assigned_device_enable_host_msi(kvm, dev);
+ break;
+#endif
+#ifdef __KVM_HAVE_MSIX
+ case KVM_DEV_IRQ_HOST_MSIX:
+ r = assigned_device_enable_host_msix(kvm, dev);
+ break;
+#endif
+ default:
+ r = -EINVAL;
+ }
+
+ if (!r)
+ dev->irq_requested_type |= host_irq_type;
+
+ return r;
+}
+
+static int assign_guest_irq(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *dev,
+ struct kvm_assigned_irq *irq,
+ unsigned long guest_irq_type)
+{
+ int id;
+ int r = -EEXIST;
+
+ if (dev->irq_requested_type & KVM_DEV_IRQ_GUEST_MASK)
+ return r;
+
+ id = kvm_request_irq_source_id(kvm);
+ if (id < 0)
+ return id;
+
+ dev->irq_source_id = id;
+
+ switch (guest_irq_type) {
+ case KVM_DEV_IRQ_GUEST_INTX:
+ r = assigned_device_enable_guest_intx(kvm, dev, irq);
+ break;
+#ifdef __KVM_HAVE_MSI
+ case KVM_DEV_IRQ_GUEST_MSI:
+ r = assigned_device_enable_guest_msi(kvm, dev, irq);
+ break;
+#endif
+#ifdef __KVM_HAVE_MSIX
+ case KVM_DEV_IRQ_GUEST_MSIX:
+ r = assigned_device_enable_guest_msix(kvm, dev, irq);
+ break;
+#endif
+ default:
+ r = -EINVAL;
+ }
+
+ if (!r) {
+ dev->irq_requested_type |= guest_irq_type;
+ kvm_register_irq_ack_notifier(kvm, &dev->ack_notifier);
+ } else
+ kvm_free_irq_source_id(kvm, dev->irq_source_id);
+
+ return r;
+}
+
+/* TODO Deal with KVM_DEV_IRQ_ASSIGNED_MASK_MSIX */
+static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
+ struct kvm_assigned_irq *assigned_irq)
+{
+ int r = -EINVAL;
+ struct kvm_assigned_dev_kernel *match;
+ unsigned long host_irq_type, guest_irq_type;
+
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ if (!irqchip_in_kernel(kvm))
+ return r;
+
+ mutex_lock(&kvm->lock);
+ r = -ENODEV;
+ match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+ assigned_irq->assigned_dev_id);
+ if (!match)
+ goto out;
+
+ host_irq_type = (assigned_irq->flags & KVM_DEV_IRQ_HOST_MASK);
+ guest_irq_type = (assigned_irq->flags & KVM_DEV_IRQ_GUEST_MASK);
+
+ r = -EINVAL;
+ /* can only assign one type at a time */
+ if (hweight_long(host_irq_type) > 1)
+ goto out;
+ if (hweight_long(guest_irq_type) > 1)
+ goto out;
+ if (host_irq_type == 0 && guest_irq_type == 0)
+ goto out;
+
+ r = 0;
+ if (host_irq_type)
+ r = assign_host_irq(kvm, match, host_irq_type);
+ if (r)
+ goto out;
+
+ if (guest_irq_type)
+ r = assign_guest_irq(kvm, match, assigned_irq, guest_irq_type);
+out:
+ mutex_unlock(&kvm->lock);
+ return r;
+}
+
+static int kvm_vm_ioctl_deassign_dev_irq(struct kvm *kvm,
+ struct kvm_assigned_irq
+ *assigned_irq)
+{
+ int r = -ENODEV;
+ struct kvm_assigned_dev_kernel *match;
+
+ mutex_lock(&kvm->lock);
+
+ match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+ assigned_irq->assigned_dev_id);
+ if (!match)
+ goto out;
+
+ r = kvm_deassign_irq(kvm, match, assigned_irq->flags);
+out:
+ mutex_unlock(&kvm->lock);
+ return r;
+}
+
+static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
+ struct kvm_assigned_pci_dev *assigned_dev)
+{
+ int r = 0;
+ struct kvm_assigned_dev_kernel *match;
+ struct pci_dev *dev;
+
+ down_read(&kvm->slots_lock);
+ mutex_lock(&kvm->lock);
+
+ match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+ assigned_dev->assigned_dev_id);
+ if (match) {
+ /* device already assigned */
+ r = -EEXIST;
+ goto out;
+ }
+
+ match = kzalloc(sizeof(struct kvm_assigned_dev_kernel), GFP_KERNEL);
+ if (match == NULL) {
+ printk(KERN_INFO "%s: Couldn't allocate memory\n",
+ __func__);
+ r = -ENOMEM;
+ goto out;
+ }
+ dev = pci_get_bus_and_slot(assigned_dev->busnr,
+ assigned_dev->devfn);
+ if (!dev) {
+ printk(KERN_INFO "%s: host device not found\n", __func__);
+ r = -EINVAL;
+ goto out_free;
+ }
+ if (pci_enable_device(dev)) {
+ printk(KERN_INFO "%s: Could not enable PCI device\n", __func__);
+ r = -EBUSY;
+ goto out_put;
+ }
+ r = pci_request_regions(dev, "kvm_assigned_device");
+ if (r) {
+ printk(KERN_INFO "%s: Could not get access to device regions\n",
+ __func__);
+ goto out_disable;
+ }
+
+ pci_reset_function(dev);
+
+ match->assigned_dev_id = assigned_dev->assigned_dev_id;
+ match->host_busnr = assigned_dev->busnr;
+ match->host_devfn = assigned_dev->devfn;
+ match->flags = assigned_dev->flags;
+ match->dev = dev;
+ spin_lock_init(&match->assigned_dev_lock);
+ match->irq_source_id = -1;
+ match->kvm = kvm;
+ match->ack_notifier.irq_acked = kvm_assigned_dev_ack_irq;
+ INIT_WORK(&match->interrupt_work,
+ kvm_assigned_dev_interrupt_work_handler);
+
+ list_add(&match->list, &kvm->arch.assigned_dev_head);
+
+ if (assigned_dev->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU) {
+ if (!kvm->arch.iommu_domain) {
+ r = kvm_iommu_map_guest(kvm);
+ if (r)
+ goto out_list_del;
+ }
+ r = kvm_assign_device(kvm, match);
+ if (r)
+ goto out_list_del;
+ }
+
+out:
+ mutex_unlock(&kvm->lock);
+ up_read(&kvm->slots_lock);
+ return r;
+out_list_del:
+ list_del(&match->list);
+ pci_release_regions(dev);
+out_disable:
+ pci_disable_device(dev);
+out_put:
+ pci_dev_put(dev);
+out_free:
+ kfree(match);
+ mutex_unlock(&kvm->lock);
+ up_read(&kvm->slots_lock);
+ return r;
+}
+
+static int kvm_vm_ioctl_deassign_device(struct kvm *kvm,
+ struct kvm_assigned_pci_dev *assigned_dev)
+{
+ int r = 0;
+ struct kvm_assigned_dev_kernel *match;
+
+ mutex_lock(&kvm->lock);
+
+ match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+ assigned_dev->assigned_dev_id);
+ if (!match) {
+ printk(KERN_INFO "%s: device hasn't been assigned before, "
+ "so cannot be deassigned\n", __func__);
+ r = -EINVAL;
+ goto out;
+ }
+
+ if (match->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU)
+ kvm_deassign_device(kvm, match);
+
+ kvm_free_assigned_device(kvm, match);
+
+out:
+ mutex_unlock(&kvm->lock);
+ return r;
+}
+
+
+#ifdef __KVM_HAVE_MSIX
+static int kvm_vm_ioctl_set_msix_nr(struct kvm *kvm,
+ struct kvm_assigned_msix_nr *entry_nr)
+{
+ int r = 0;
+ struct kvm_assigned_dev_kernel *adev;
+
+ mutex_lock(&kvm->lock);
+
+ adev = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+ entry_nr->assigned_dev_id);
+ if (!adev) {
+ r = -EINVAL;
+ goto msix_nr_out;
+ }
+
+ if (adev->entries_nr == 0) {
+ adev->entries_nr = entry_nr->entry_nr;
+ if (adev->entries_nr == 0 ||
+ adev->entries_nr >= KVM_MAX_MSIX_PER_DEV) {
+ r = -EINVAL;
+ goto msix_nr_out;
+ }
+
+ adev->host_msix_entries = kzalloc(sizeof(struct msix_entry) *
+ entry_nr->entry_nr,
+ GFP_KERNEL);
+ if (!adev->host_msix_entries) {
+ r = -ENOMEM;
+ goto msix_nr_out;
+ }
+ adev->guest_msix_entries = kzalloc(
+ sizeof(struct kvm_guest_msix_entry) *
+ entry_nr->entry_nr, GFP_KERNEL);
+ if (!adev->guest_msix_entries) {
+ kfree(adev->host_msix_entries);
+ r = -ENOMEM;
+ goto msix_nr_out;
+ }
+ } else /* Not allowed set MSI-X number twice */
+ r = -EINVAL;
+msix_nr_out:
+ mutex_unlock(&kvm->lock);
+ return r;
+}
+
+static int kvm_vm_ioctl_set_msix_entry(struct kvm *kvm,
+ struct kvm_assigned_msix_entry *entry)
+{
+ int r = 0, i;
+ struct kvm_assigned_dev_kernel *adev;
+
+ mutex_lock(&kvm->lock);
+
+ adev = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+ entry->assigned_dev_id);
+
+ if (!adev) {
+ r = -EINVAL;
+ goto msix_entry_out;
+ }
+
+ for (i = 0; i < adev->entries_nr; i++)
+ if (adev->guest_msix_entries[i].vector == 0 ||
+ adev->guest_msix_entries[i].entry == entry->entry) {
+ adev->guest_msix_entries[i].entry = entry->entry;
+ adev->guest_msix_entries[i].vector = entry->gsi;
+ adev->host_msix_entries[i].entry = entry->entry;
+ break;
+ }
+ if (i == adev->entries_nr) {
+ r = -ENOSPC;
+ goto msix_entry_out;
+ }
+
+msix_entry_out:
+ mutex_unlock(&kvm->lock);
+
+ return r;
+}
+#endif
+
+long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int r = -ENOTTY;
+
+ switch (ioctl) {
+ case KVM_ASSIGN_PCI_DEVICE: {
+ struct kvm_assigned_pci_dev assigned_dev;
+
+ r = -EFAULT;
+ if (copy_from_user(&assigned_dev, argp, sizeof assigned_dev))
+ goto out;
+ r = kvm_vm_ioctl_assign_device(kvm, &assigned_dev);
+ if (r)
+ goto out;
+ break;
+ }
+ case KVM_ASSIGN_IRQ: {
+ r = -EOPNOTSUPP;
+ break;
+ }
+#ifdef KVM_CAP_ASSIGN_DEV_IRQ
+ case KVM_ASSIGN_DEV_IRQ: {
+ struct kvm_assigned_irq assigned_irq;
+
+ r = -EFAULT;
+ if (copy_from_user(&assigned_irq, argp, sizeof assigned_irq))
+ goto out;
+ r = kvm_vm_ioctl_assign_irq(kvm, &assigned_irq);
+ if (r)
+ goto out;
+ break;
+ }
+ case KVM_DEASSIGN_DEV_IRQ: {
+ struct kvm_assigned_irq assigned_irq;
+
+ r = -EFAULT;
+ if (copy_from_user(&assigned_irq, argp, sizeof assigned_irq))
+ goto out;
+ r = kvm_vm_ioctl_deassign_dev_irq(kvm, &assigned_irq);
+ if (r)
+ goto out;
+ break;
+ }
+#endif
+#ifdef KVM_CAP_DEVICE_DEASSIGNMENT
+ case KVM_DEASSIGN_PCI_DEVICE: {
+ struct kvm_assigned_pci_dev assigned_dev;
+
+ r = -EFAULT;
+ if (copy_from_user(&assigned_dev, argp, sizeof assigned_dev))
+ goto out;
+ r = kvm_vm_ioctl_deassign_device(kvm, &assigned_dev);
+ if (r)
+ goto out;
+ break;
+ }
+#endif
+#ifdef KVM_CAP_IRQ_ROUTING
+ case KVM_SET_GSI_ROUTING: {
+ struct kvm_irq_routing routing;
+ struct kvm_irq_routing __user *urouting;
+ struct kvm_irq_routing_entry *entries;
+
+ r = -EFAULT;
+ if (copy_from_user(&routing, argp, sizeof(routing)))
+ goto out;
+ r = -EINVAL;
+ if (routing.nr >= KVM_MAX_IRQ_ROUTES)
+ goto out;
+ if (routing.flags)
+ goto out;
+ r = -ENOMEM;
+ entries = vmalloc(routing.nr * sizeof(*entries));
+ if (!entries)
+ goto out;
+ r = -EFAULT;
+ urouting = argp;
+ if (copy_from_user(entries, urouting->entries,
+ routing.nr * sizeof(*entries)))
+ goto out_free_irq_routing;
+ r = kvm_set_irq_routing(kvm, entries, routing.nr,
+ routing.flags);
+ out_free_irq_routing:
+ vfree(entries);
+ break;
+ }
+#endif /* KVM_CAP_IRQ_ROUTING */
+#ifdef __KVM_HAVE_MSIX
+ case KVM_ASSIGN_SET_MSIX_NR: {
+ struct kvm_assigned_msix_nr entry_nr;
+ r = -EFAULT;
+ if (copy_from_user(&entry_nr, argp, sizeof entry_nr))
+ goto out;
+ r = kvm_vm_ioctl_set_msix_nr(kvm, &entry_nr);
+ if (r)
+ goto out;
+ break;
+ }
+ case KVM_ASSIGN_SET_MSIX_ENTRY: {
+ struct kvm_assigned_msix_entry entry;
+ r = -EFAULT;
+ if (copy_from_user(&entry, argp, sizeof entry))
+ goto out;
+ r = kvm_vm_ioctl_set_msix_entry(kvm, &entry);
+ if (r)
+ goto out;
+ break;
+ }
+#endif
+ }
+out:
+ return r;
+}
+
diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c
index bb4ebd89b9ff..30f70fd511c4 100644
--- a/virt/kvm/eventfd.c
+++ b/virt/kvm/eventfd.c
@@ -61,10 +61,8 @@ irqfd_inject(struct work_struct *work)
struct _irqfd *irqfd = container_of(work, struct _irqfd, inject);
struct kvm *kvm = irqfd->kvm;
- mutex_lock(&kvm->irq_lock);
kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 1);
kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 0);
- mutex_unlock(&kvm->irq_lock);
}
/*
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index 9fe140bb38ec..38a2d20b89de 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -182,6 +182,7 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
union kvm_ioapic_redirect_entry entry;
int ret = 1;
+ mutex_lock(&ioapic->lock);
if (irq >= 0 && irq < IOAPIC_NUM_PINS) {
entry = ioapic->redirtbl[irq];
level ^= entry.fields.polarity;
@@ -198,34 +199,51 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
}
trace_kvm_ioapic_set_irq(entry.bits, irq, ret == 0);
}
+ mutex_unlock(&ioapic->lock);
+
return ret;
}
-static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int pin,
- int trigger_mode)
+static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int vector,
+ int trigger_mode)
{
- union kvm_ioapic_redirect_entry *ent;
+ int i;
+
+ for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+ union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i];
- ent = &ioapic->redirtbl[pin];
+ if (ent->fields.vector != vector)
+ continue;
- kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, pin);
+ /*
+ * We are dropping lock while calling ack notifiers because ack
+ * notifier callbacks for assigned devices call into IOAPIC
+ * recursively. Since remote_irr is cleared only after call
+ * to notifiers if the same vector will be delivered while lock
+ * is dropped it will be put into irr and will be delivered
+ * after ack notifier returns.
+ */
+ mutex_unlock(&ioapic->lock);
+ kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, i);
+ mutex_lock(&ioapic->lock);
+
+ if (trigger_mode != IOAPIC_LEVEL_TRIG)
+ continue;
- if (trigger_mode == IOAPIC_LEVEL_TRIG) {
ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
ent->fields.remote_irr = 0;
- if (!ent->fields.mask && (ioapic->irr & (1 << pin)))
- ioapic_service(ioapic, pin);
+ if (!ent->fields.mask && (ioapic->irr & (1 << i)))
+ ioapic_service(ioapic, i);
}
}
void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode)
{
struct kvm_ioapic *ioapic = kvm->arch.vioapic;
- int i;
- for (i = 0; i < IOAPIC_NUM_PINS; i++)
- if (ioapic->redirtbl[i].fields.vector == vector)
- __kvm_ioapic_update_eoi(ioapic, i, trigger_mode);
+ mutex_lock(&ioapic->lock);
+ __kvm_ioapic_update_eoi(ioapic, vector, trigger_mode);
+ mutex_unlock(&ioapic->lock);
}
static inline struct kvm_ioapic *to_ioapic(struct kvm_io_device *dev)
@@ -250,8 +268,8 @@ static int ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len,
ioapic_debug("addr %lx\n", (unsigned long)addr);
ASSERT(!(addr & 0xf)); /* check alignment */
- mutex_lock(&ioapic->kvm->irq_lock);
addr &= 0xff;
+ mutex_lock(&ioapic->lock);
switch (addr) {
case IOAPIC_REG_SELECT:
result = ioapic->ioregsel;
@@ -265,6 +283,8 @@ static int ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len,
result = 0;
break;
}
+ mutex_unlock(&ioapic->lock);
+
switch (len) {
case 8:
*(u64 *) val = result;
@@ -277,7 +297,6 @@ static int ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len,
default:
printk(KERN_WARNING "ioapic: wrong length %d\n", len);
}
- mutex_unlock(&ioapic->kvm->irq_lock);
return 0;
}
@@ -293,15 +312,15 @@ static int ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len,
(void*)addr, len, val);
ASSERT(!(addr & 0xf)); /* check alignment */
- mutex_lock(&ioapic->kvm->irq_lock);
if (len == 4 || len == 8)
data = *(u32 *) val;
else {
printk(KERN_WARNING "ioapic: Unsupported size %d\n", len);
- goto unlock;
+ return 0;
}
addr &= 0xff;
+ mutex_lock(&ioapic->lock);
switch (addr) {
case IOAPIC_REG_SELECT:
ioapic->ioregsel = data;
@@ -312,15 +331,14 @@ static int ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len,
break;
#ifdef CONFIG_IA64
case IOAPIC_REG_EOI:
- kvm_ioapic_update_eoi(ioapic->kvm, data, IOAPIC_LEVEL_TRIG);
+ __kvm_ioapic_update_eoi(ioapic, data, IOAPIC_LEVEL_TRIG);
break;
#endif
default:
break;
}
-unlock:
- mutex_unlock(&ioapic->kvm->irq_lock);
+ mutex_unlock(&ioapic->lock);
return 0;
}
@@ -349,6 +367,7 @@ int kvm_ioapic_init(struct kvm *kvm)
ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL);
if (!ioapic)
return -ENOMEM;
+ mutex_init(&ioapic->lock);
kvm->arch.vioapic = ioapic;
kvm_ioapic_reset(ioapic);
kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops);
@@ -360,3 +379,26 @@ int kvm_ioapic_init(struct kvm *kvm)
return ret;
}
+int kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)
+{
+ struct kvm_ioapic *ioapic = ioapic_irqchip(kvm);
+ if (!ioapic)
+ return -EINVAL;
+
+ mutex_lock(&ioapic->lock);
+ memcpy(state, ioapic, sizeof(struct kvm_ioapic_state));
+ mutex_unlock(&ioapic->lock);
+ return 0;
+}
+
+int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)
+{
+ struct kvm_ioapic *ioapic = ioapic_irqchip(kvm);
+ if (!ioapic)
+ return -EINVAL;
+
+ mutex_lock(&ioapic->lock);
+ memcpy(ioapic, state, sizeof(struct kvm_ioapic_state));
+ mutex_unlock(&ioapic->lock);
+ return 0;
+}
diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h
index 7080b713c160..419c43b667ab 100644
--- a/virt/kvm/ioapic.h
+++ b/virt/kvm/ioapic.h
@@ -41,9 +41,11 @@ struct kvm_ioapic {
u32 irr;
u32 pad;
union kvm_ioapic_redirect_entry redirtbl[IOAPIC_NUM_PINS];
+ unsigned long irq_states[IOAPIC_NUM_PINS];
struct kvm_io_device dev;
struct kvm *kvm;
void (*ack_notifier)(void *opaque, int irq);
+ struct mutex lock;
};
#ifdef DEBUG
@@ -73,4 +75,7 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
void kvm_ioapic_reset(struct kvm_ioapic *ioapic);
int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
struct kvm_lapic_irq *irq);
+int kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state);
+int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state);
+
#endif
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index 001663ff401a..00c68d298579 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -31,20 +31,39 @@
#include "ioapic.h"
+static inline int kvm_irq_line_state(unsigned long *irq_state,
+ int irq_source_id, int level)
+{
+ /* Logical OR for level trig interrupt */
+ if (level)
+ set_bit(irq_source_id, irq_state);
+ else
+ clear_bit(irq_source_id, irq_state);
+
+ return !!(*irq_state);
+}
+
static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e,
- struct kvm *kvm, int level)
+ struct kvm *kvm, int irq_source_id, int level)
{
#ifdef CONFIG_X86
- return kvm_pic_set_irq(pic_irqchip(kvm), e->irqchip.pin, level);
+ struct kvm_pic *pic = pic_irqchip(kvm);
+ level = kvm_irq_line_state(&pic->irq_states[e->irqchip.pin],
+ irq_source_id, level);
+ return kvm_pic_set_irq(pic, e->irqchip.pin, level);
#else
return -1;
#endif
}
static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
- struct kvm *kvm, int level)
+ struct kvm *kvm, int irq_source_id, int level)
{
- return kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level);
+ struct kvm_ioapic *ioapic = kvm->arch.vioapic;
+ level = kvm_irq_line_state(&ioapic->irq_states[e->irqchip.pin],
+ irq_source_id, level);
+
+ return kvm_ioapic_set_irq(ioapic, e->irqchip.pin, level);
}
inline static bool kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq)
@@ -63,8 +82,6 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
int i, r = -1;
struct kvm_vcpu *vcpu, *lowest = NULL;
- WARN_ON(!mutex_is_locked(&kvm->irq_lock));
-
if (irq->dest_mode == 0 && irq->dest_id == 0xff &&
kvm_is_dm_lowest_prio(irq))
printk(KERN_INFO "kvm: apic: phys broadcast and lowest prio\n");
@@ -96,10 +113,13 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
}
static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
- struct kvm *kvm, int level)
+ struct kvm *kvm, int irq_source_id, int level)
{
struct kvm_lapic_irq irq;
+ if (!level)
+ return -1;
+
trace_kvm_msi_set_irq(e->msi.address_lo, e->msi.data);
irq.dest_id = (e->msi.address_lo &
@@ -116,78 +136,67 @@ static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
return kvm_irq_delivery_to_apic(kvm, NULL, &irq);
}
-/* This should be called with the kvm->irq_lock mutex held
+/*
* Return value:
* < 0 Interrupt was ignored (masked or not delivered for other reasons)
* = 0 Interrupt was coalesced (previous irq is still pending)
* > 0 Number of CPUs interrupt was delivered to
*/
-int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level)
+int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level)
{
- struct kvm_kernel_irq_routing_entry *e;
- unsigned long *irq_state, sig_level;
- int ret = -1;
+ struct kvm_kernel_irq_routing_entry *e, irq_set[KVM_NR_IRQCHIPS];
+ int ret = -1, i = 0;
+ struct kvm_irq_routing_table *irq_rt;
+ struct hlist_node *n;
trace_kvm_set_irq(irq, level, irq_source_id);
- WARN_ON(!mutex_is_locked(&kvm->irq_lock));
-
- if (irq < KVM_IOAPIC_NUM_PINS) {
- irq_state = (unsigned long *)&kvm->arch.irq_states[irq];
-
- /* Logical OR for level trig interrupt */
- if (level)
- set_bit(irq_source_id, irq_state);
- else
- clear_bit(irq_source_id, irq_state);
- sig_level = !!(*irq_state);
- } else if (!level)
- return ret;
- else /* Deal with MSI/MSI-X */
- sig_level = 1;
-
/* Not possible to detect if the guest uses the PIC or the
* IOAPIC. So set the bit in both. The guest will ignore
* writes to the unused one.
*/
- list_for_each_entry(e, &kvm->irq_routing, link)
- if (e->gsi == irq) {
- int r = e->set(e, kvm, sig_level);
- if (r < 0)
- continue;
+ rcu_read_lock();
+ irq_rt = rcu_dereference(kvm->irq_routing);
+ if (irq < irq_rt->nr_rt_entries)
+ hlist_for_each_entry(e, n, &irq_rt->map[irq], link)
+ irq_set[i++] = *e;
+ rcu_read_unlock();
+
+ while(i--) {
+ int r;
+ r = irq_set[i].set(&irq_set[i], kvm, irq_source_id, level);
+ if (r < 0)
+ continue;
+
+ ret = r + ((ret < 0) ? 0 : ret);
+ }
- ret = r + ((ret < 0) ? 0 : ret);
- }
return ret;
}
void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin)
{
- struct kvm_kernel_irq_routing_entry *e;
struct kvm_irq_ack_notifier *kian;
struct hlist_node *n;
- unsigned gsi = pin;
+ int gsi;
trace_kvm_ack_irq(irqchip, pin);
- list_for_each_entry(e, &kvm->irq_routing, link)
- if (e->type == KVM_IRQ_ROUTING_IRQCHIP &&
- e->irqchip.irqchip == irqchip &&
- e->irqchip.pin == pin) {
- gsi = e->gsi;
- break;
- }
-
- hlist_for_each_entry(kian, n, &kvm->arch.irq_ack_notifier_list, link)
- if (kian->gsi == gsi)
- kian->irq_acked(kian);
+ rcu_read_lock();
+ gsi = rcu_dereference(kvm->irq_routing)->chip[irqchip][pin];
+ if (gsi != -1)
+ hlist_for_each_entry_rcu(kian, n, &kvm->irq_ack_notifier_list,
+ link)
+ if (kian->gsi == gsi)
+ kian->irq_acked(kian);
+ rcu_read_unlock();
}
void kvm_register_irq_ack_notifier(struct kvm *kvm,
struct kvm_irq_ack_notifier *kian)
{
mutex_lock(&kvm->irq_lock);
- hlist_add_head(&kian->link, &kvm->arch.irq_ack_notifier_list);
+ hlist_add_head_rcu(&kian->link, &kvm->irq_ack_notifier_list);
mutex_unlock(&kvm->irq_lock);
}
@@ -195,8 +204,9 @@ void kvm_unregister_irq_ack_notifier(struct kvm *kvm,
struct kvm_irq_ack_notifier *kian)
{
mutex_lock(&kvm->irq_lock);
- hlist_del_init(&kian->link);
+ hlist_del_init_rcu(&kian->link);
mutex_unlock(&kvm->irq_lock);
+ synchronize_rcu();
}
int kvm_request_irq_source_id(struct kvm *kvm)
@@ -210,11 +220,13 @@ int kvm_request_irq_source_id(struct kvm *kvm)
if (irq_source_id >= sizeof(kvm->arch.irq_sources_bitmap)) {
printk(KERN_WARNING "kvm: exhaust allocatable IRQ sources!\n");
- return -EFAULT;
+ irq_source_id = -EFAULT;
+ goto unlock;
}
ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID);
set_bit(irq_source_id, bitmap);
+unlock:
mutex_unlock(&kvm->irq_lock);
return irq_source_id;
@@ -230,11 +242,18 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id)
if (irq_source_id < 0 ||
irq_source_id >= sizeof(kvm->arch.irq_sources_bitmap)) {
printk(KERN_ERR "kvm: IRQ source ID out of range!\n");
- return;
+ goto unlock;
+ }
+ for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++) {
+ clear_bit(irq_source_id, &kvm->arch.vioapic->irq_states[i]);
+ if (i >= 16)
+ continue;
+#ifdef CONFIG_X86
+ clear_bit(irq_source_id, &pic_irqchip(kvm)->irq_states[i]);
+#endif
}
- for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++)
- clear_bit(irq_source_id, &kvm->arch.irq_states[i]);
clear_bit(irq_source_id, &kvm->arch.irq_sources_bitmap);
+unlock:
mutex_unlock(&kvm->irq_lock);
}
@@ -243,7 +262,7 @@ void kvm_register_irq_mask_notifier(struct kvm *kvm, int irq,
{
mutex_lock(&kvm->irq_lock);
kimn->irq = irq;
- hlist_add_head(&kimn->link, &kvm->mask_notifier_list);
+ hlist_add_head_rcu(&kimn->link, &kvm->mask_notifier_list);
mutex_unlock(&kvm->irq_lock);
}
@@ -251,8 +270,9 @@ void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq,
struct kvm_irq_mask_notifier *kimn)
{
mutex_lock(&kvm->irq_lock);
- hlist_del(&kimn->link);
+ hlist_del_rcu(&kimn->link);
mutex_unlock(&kvm->irq_lock);
+ synchronize_rcu();
}
void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask)
@@ -260,33 +280,37 @@ void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask)
struct kvm_irq_mask_notifier *kimn;
struct hlist_node *n;
- WARN_ON(!mutex_is_locked(&kvm->irq_lock));
-
- hlist_for_each_entry(kimn, n, &kvm->mask_notifier_list, link)
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(kimn, n, &kvm->mask_notifier_list, link)
if (kimn->irq == irq)
kimn->func(kimn, mask);
-}
-
-static void __kvm_free_irq_routing(struct list_head *irq_routing)
-{
- struct kvm_kernel_irq_routing_entry *e, *n;
-
- list_for_each_entry_safe(e, n, irq_routing, link)
- kfree(e);
+ rcu_read_unlock();
}
void kvm_free_irq_routing(struct kvm *kvm)
{
- mutex_lock(&kvm->irq_lock);
- __kvm_free_irq_routing(&kvm->irq_routing);
- mutex_unlock(&kvm->irq_lock);
+ /* Called only during vm destruction. Nobody can use the pointer
+ at this stage */
+ kfree(kvm->irq_routing);
}
-static int setup_routing_entry(struct kvm_kernel_irq_routing_entry *e,
+static int setup_routing_entry(struct kvm_irq_routing_table *rt,
+ struct kvm_kernel_irq_routing_entry *e,
const struct kvm_irq_routing_entry *ue)
{
int r = -EINVAL;
int delta;
+ struct kvm_kernel_irq_routing_entry *ei;
+ struct hlist_node *n;
+
+ /*
+ * Do not allow GSI to be mapped to the same irqchip more than once.
+ * Allow only one to one mapping between GSI and MSI.
+ */
+ hlist_for_each_entry(ei, n, &rt->map[ue->gsi], link)
+ if (ei->type == KVM_IRQ_ROUTING_MSI ||
+ ue->u.irqchip.irqchip == ei->irqchip.irqchip)
+ return r;
e->gsi = ue->gsi;
e->type = ue->type;
@@ -309,6 +333,9 @@ static int setup_routing_entry(struct kvm_kernel_irq_routing_entry *e,
}
e->irqchip.irqchip = ue->u.irqchip.irqchip;
e->irqchip.pin = ue->u.irqchip.pin + delta;
+ if (e->irqchip.pin >= KVM_IOAPIC_NUM_PINS)
+ goto out;
+ rt->chip[ue->u.irqchip.irqchip][e->irqchip.pin] = ue->gsi;
break;
case KVM_IRQ_ROUTING_MSI:
e->set = kvm_set_msi;
@@ -319,6 +346,8 @@ static int setup_routing_entry(struct kvm_kernel_irq_routing_entry *e,
default:
goto out;
}
+
+ hlist_add_head(&e->link, &rt->map[e->gsi]);
r = 0;
out:
return r;
@@ -330,43 +359,53 @@ int kvm_set_irq_routing(struct kvm *kvm,
unsigned nr,
unsigned flags)
{
- struct list_head irq_list = LIST_HEAD_INIT(irq_list);
- struct list_head tmp = LIST_HEAD_INIT(tmp);
- struct kvm_kernel_irq_routing_entry *e = NULL;
- unsigned i;
+ struct kvm_irq_routing_table *new, *old;
+ u32 i, j, nr_rt_entries = 0;
int r;
for (i = 0; i < nr; ++i) {
+ if (ue[i].gsi >= KVM_MAX_IRQ_ROUTES)
+ return -EINVAL;
+ nr_rt_entries = max(nr_rt_entries, ue[i].gsi);
+ }
+
+ nr_rt_entries += 1;
+
+ new = kzalloc(sizeof(*new) + (nr_rt_entries * sizeof(struct hlist_head))
+ + (nr * sizeof(struct kvm_kernel_irq_routing_entry)),
+ GFP_KERNEL);
+
+ if (!new)
+ return -ENOMEM;
+
+ new->rt_entries = (void *)&new->map[nr_rt_entries];
+
+ new->nr_rt_entries = nr_rt_entries;
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < KVM_IOAPIC_NUM_PINS; j++)
+ new->chip[i][j] = -1;
+
+ for (i = 0; i < nr; ++i) {
r = -EINVAL;
- if (ue->gsi >= KVM_MAX_IRQ_ROUTES)
- goto out;
if (ue->flags)
goto out;
- r = -ENOMEM;
- e = kzalloc(sizeof(*e), GFP_KERNEL);
- if (!e)
- goto out;
- r = setup_routing_entry(e, ue);
+ r = setup_routing_entry(new, &new->rt_entries[i], ue);
if (r)
goto out;
++ue;
- list_add(&e->link, &irq_list);
- e = NULL;
}
mutex_lock(&kvm->irq_lock);
- list_splice(&kvm->irq_routing, &tmp);
- INIT_LIST_HEAD(&kvm->irq_routing);
- list_splice(&irq_list, &kvm->irq_routing);
- INIT_LIST_HEAD(&irq_list);
- list_splice(&tmp, &irq_list);
+ old = kvm->irq_routing;
+ rcu_assign_pointer(kvm->irq_routing, new);
mutex_unlock(&kvm->irq_lock);
+ synchronize_rcu();
+ new = old;
r = 0;
out:
- kfree(e);
- __kvm_free_irq_routing(&irq_list);
+ kfree(new);
return r;
}
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index b7c78a403dc2..70c8cbea0a99 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -53,12 +53,6 @@
#include "coalesced_mmio.h"
#endif
-#ifdef KVM_CAP_DEVICE_ASSIGNMENT
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include "irq.h"
-#endif
-
#define CREATE_TRACE_POINTS
#include <trace/events/kvm.h>
@@ -75,6 +69,8 @@ DEFINE_SPINLOCK(kvm_lock);
LIST_HEAD(vm_list);
static cpumask_var_t cpus_hardware_enabled;
+static int kvm_usage_count = 0;
+static atomic_t hardware_enable_failed;
struct kmem_cache *kvm_vcpu_cache;
EXPORT_SYMBOL_GPL(kvm_vcpu_cache);
@@ -85,615 +81,13 @@ struct dentry *kvm_debugfs_dir;
static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl,
unsigned long arg);
+static int hardware_enable_all(void);
+static void hardware_disable_all(void);
static bool kvm_rebooting;
static bool largepages_enabled = true;
-#ifdef KVM_CAP_DEVICE_ASSIGNMENT
-static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *head,
- int assigned_dev_id)
-{
- struct list_head *ptr;
- struct kvm_assigned_dev_kernel *match;
-
- list_for_each(ptr, head) {
- match = list_entry(ptr, struct kvm_assigned_dev_kernel, list);
- if (match->assigned_dev_id == assigned_dev_id)
- return match;
- }
- return NULL;
-}
-
-static int find_index_from_host_irq(struct kvm_assigned_dev_kernel
- *assigned_dev, int irq)
-{
- int i, index;
- struct msix_entry *host_msix_entries;
-
- host_msix_entries = assigned_dev->host_msix_entries;
-
- index = -1;
- for (i = 0; i < assigned_dev->entries_nr; i++)
- if (irq == host_msix_entries[i].vector) {
- index = i;
- break;
- }
- if (index < 0) {
- printk(KERN_WARNING "Fail to find correlated MSI-X entry!\n");
- return 0;
- }
-
- return index;
-}
-
-static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
-{
- struct kvm_assigned_dev_kernel *assigned_dev;
- struct kvm *kvm;
- int i;
-
- assigned_dev = container_of(work, struct kvm_assigned_dev_kernel,
- interrupt_work);
- kvm = assigned_dev->kvm;
-
- mutex_lock(&kvm->irq_lock);
- spin_lock_irq(&assigned_dev->assigned_dev_lock);
- if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
- struct kvm_guest_msix_entry *guest_entries =
- assigned_dev->guest_msix_entries;
- for (i = 0; i < assigned_dev->entries_nr; i++) {
- if (!(guest_entries[i].flags &
- KVM_ASSIGNED_MSIX_PENDING))
- continue;
- guest_entries[i].flags &= ~KVM_ASSIGNED_MSIX_PENDING;
- kvm_set_irq(assigned_dev->kvm,
- assigned_dev->irq_source_id,
- guest_entries[i].vector, 1);
- }
- } else
- kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
- assigned_dev->guest_irq, 1);
-
- spin_unlock_irq(&assigned_dev->assigned_dev_lock);
- mutex_unlock(&assigned_dev->kvm->irq_lock);
-}
-
-static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id)
-{
- unsigned long flags;
- struct kvm_assigned_dev_kernel *assigned_dev =
- (struct kvm_assigned_dev_kernel *) dev_id;
-
- spin_lock_irqsave(&assigned_dev->assigned_dev_lock, flags);
- if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
- int index = find_index_from_host_irq(assigned_dev, irq);
- if (index < 0)
- goto out;
- assigned_dev->guest_msix_entries[index].flags |=
- KVM_ASSIGNED_MSIX_PENDING;
- }
-
- schedule_work(&assigned_dev->interrupt_work);
-
- if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_GUEST_INTX) {
- disable_irq_nosync(irq);
- assigned_dev->host_irq_disabled = true;
- }
-
-out:
- spin_unlock_irqrestore(&assigned_dev->assigned_dev_lock, flags);
- return IRQ_HANDLED;
-}
-
-/* Ack the irq line for an assigned device */
-static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian)
-{
- struct kvm_assigned_dev_kernel *dev;
- unsigned long flags;
-
- if (kian->gsi == -1)
- return;
-
- dev = container_of(kian, struct kvm_assigned_dev_kernel,
- ack_notifier);
-
- kvm_set_irq(dev->kvm, dev->irq_source_id, dev->guest_irq, 0);
-
- /* The guest irq may be shared so this ack may be
- * from another device.
- */
- spin_lock_irqsave(&dev->assigned_dev_lock, flags);
- if (dev->host_irq_disabled) {
- enable_irq(dev->host_irq);
- dev->host_irq_disabled = false;
- }
- spin_unlock_irqrestore(&dev->assigned_dev_lock, flags);
-}
-
-static void deassign_guest_irq(struct kvm *kvm,
- struct kvm_assigned_dev_kernel *assigned_dev)
-{
- kvm_unregister_irq_ack_notifier(kvm, &assigned_dev->ack_notifier);
- assigned_dev->ack_notifier.gsi = -1;
-
- if (assigned_dev->irq_source_id != -1)
- kvm_free_irq_source_id(kvm, assigned_dev->irq_source_id);
- assigned_dev->irq_source_id = -1;
- assigned_dev->irq_requested_type &= ~(KVM_DEV_IRQ_GUEST_MASK);
-}
-
-/* The function implicit hold kvm->lock mutex due to cancel_work_sync() */
-static void deassign_host_irq(struct kvm *kvm,
- struct kvm_assigned_dev_kernel *assigned_dev)
-{
- /*
- * In kvm_free_device_irq, cancel_work_sync return true if:
- * 1. work is scheduled, and then cancelled.
- * 2. work callback is executed.
- *
- * The first one ensured that the irq is disabled and no more events
- * would happen. But for the second one, the irq may be enabled (e.g.
- * for MSI). So we disable irq here to prevent further events.
- *
- * Notice this maybe result in nested disable if the interrupt type is
- * INTx, but it's OK for we are going to free it.
- *
- * If this function is a part of VM destroy, please ensure that till
- * now, the kvm state is still legal for probably we also have to wait
- * interrupt_work done.
- */
- if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
- int i;
- for (i = 0; i < assigned_dev->entries_nr; i++)
- disable_irq_nosync(assigned_dev->
- host_msix_entries[i].vector);
-
- cancel_work_sync(&assigned_dev->interrupt_work);
-
- for (i = 0; i < assigned_dev->entries_nr; i++)
- free_irq(assigned_dev->host_msix_entries[i].vector,
- (void *)assigned_dev);
-
- assigned_dev->entries_nr = 0;
- kfree(assigned_dev->host_msix_entries);
- kfree(assigned_dev->guest_msix_entries);
- pci_disable_msix(assigned_dev->dev);
- } else {
- /* Deal with MSI and INTx */
- disable_irq_nosync(assigned_dev->host_irq);
- cancel_work_sync(&assigned_dev->interrupt_work);
-
- free_irq(assigned_dev->host_irq, (void *)assigned_dev);
-
- if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSI)
- pci_disable_msi(assigned_dev->dev);
- }
-
- assigned_dev->irq_requested_type &= ~(KVM_DEV_IRQ_HOST_MASK);
-}
-
-static int kvm_deassign_irq(struct kvm *kvm,
- struct kvm_assigned_dev_kernel *assigned_dev,
- unsigned long irq_requested_type)
-{
- unsigned long guest_irq_type, host_irq_type;
-
- if (!irqchip_in_kernel(kvm))
- return -EINVAL;
- /* no irq assignment to deassign */
- if (!assigned_dev->irq_requested_type)
- return -ENXIO;
-
- host_irq_type = irq_requested_type & KVM_DEV_IRQ_HOST_MASK;
- guest_irq_type = irq_requested_type & KVM_DEV_IRQ_GUEST_MASK;
-
- if (host_irq_type)
- deassign_host_irq(kvm, assigned_dev);
- if (guest_irq_type)
- deassign_guest_irq(kvm, assigned_dev);
-
- return 0;
-}
-
-static void kvm_free_assigned_irq(struct kvm *kvm,
- struct kvm_assigned_dev_kernel *assigned_dev)
-{
- kvm_deassign_irq(kvm, assigned_dev, assigned_dev->irq_requested_type);
-}
-
-static void kvm_free_assigned_device(struct kvm *kvm,
- struct kvm_assigned_dev_kernel
- *assigned_dev)
-{
- kvm_free_assigned_irq(kvm, assigned_dev);
-
- pci_reset_function(assigned_dev->dev);
-
- pci_release_regions(assigned_dev->dev);
- pci_disable_device(assigned_dev->dev);
- pci_dev_put(assigned_dev->dev);
-
- list_del(&assigned_dev->list);
- kfree(assigned_dev);
-}
-
-void kvm_free_all_assigned_devices(struct kvm *kvm)
-{
- struct list_head *ptr, *ptr2;
- struct kvm_assigned_dev_kernel *assigned_dev;
-
- list_for_each_safe(ptr, ptr2, &kvm->arch.assigned_dev_head) {
- assigned_dev = list_entry(ptr,
- struct kvm_assigned_dev_kernel,
- list);
-
- kvm_free_assigned_device(kvm, assigned_dev);
- }
-}
-
-static int assigned_device_enable_host_intx(struct kvm *kvm,
- struct kvm_assigned_dev_kernel *dev)
-{
- dev->host_irq = dev->dev->irq;
- /* Even though this is PCI, we don't want to use shared
- * interrupts. Sharing host devices with guest-assigned devices
- * on the same interrupt line is not a happy situation: there
- * are going to be long delays in accepting, acking, etc.
- */
- if (request_irq(dev->host_irq, kvm_assigned_dev_intr,
- 0, "kvm_assigned_intx_device", (void *)dev))
- return -EIO;
- return 0;
-}
-
-#ifdef __KVM_HAVE_MSI
-static int assigned_device_enable_host_msi(struct kvm *kvm,
- struct kvm_assigned_dev_kernel *dev)
-{
- int r;
-
- if (!dev->dev->msi_enabled) {
- r = pci_enable_msi(dev->dev);
- if (r)
- return r;
- }
-
- dev->host_irq = dev->dev->irq;
- if (request_irq(dev->host_irq, kvm_assigned_dev_intr, 0,
- "kvm_assigned_msi_device", (void *)dev)) {
- pci_disable_msi(dev->dev);
- return -EIO;
- }
-
- return 0;
-}
-#endif
-
-#ifdef __KVM_HAVE_MSIX
-static int assigned_device_enable_host_msix(struct kvm *kvm,
- struct kvm_assigned_dev_kernel *dev)
-{
- int i, r = -EINVAL;
-
- /* host_msix_entries and guest_msix_entries should have been
- * initialized */
- if (dev->entries_nr == 0)
- return r;
-
- r = pci_enable_msix(dev->dev, dev->host_msix_entries, dev->entries_nr);
- if (r)
- return r;
-
- for (i = 0; i < dev->entries_nr; i++) {
- r = request_irq(dev->host_msix_entries[i].vector,
- kvm_assigned_dev_intr, 0,
- "kvm_assigned_msix_device",
- (void *)dev);
- /* FIXME: free requested_irq's on failure */
- if (r)
- return r;
- }
-
- return 0;
-}
-
-#endif
-
-static int assigned_device_enable_guest_intx(struct kvm *kvm,
- struct kvm_assigned_dev_kernel *dev,
- struct kvm_assigned_irq *irq)
-{
- dev->guest_irq = irq->guest_irq;
- dev->ack_notifier.gsi = irq->guest_irq;
- return 0;
-}
-
-#ifdef __KVM_HAVE_MSI
-static int assigned_device_enable_guest_msi(struct kvm *kvm,
- struct kvm_assigned_dev_kernel *dev,
- struct kvm_assigned_irq *irq)
-{
- dev->guest_irq = irq->guest_irq;
- dev->ack_notifier.gsi = -1;
- dev->host_irq_disabled = false;
- return 0;
-}
-#endif
-#ifdef __KVM_HAVE_MSIX
-static int assigned_device_enable_guest_msix(struct kvm *kvm,
- struct kvm_assigned_dev_kernel *dev,
- struct kvm_assigned_irq *irq)
-{
- dev->guest_irq = irq->guest_irq;
- dev->ack_notifier.gsi = -1;
- dev->host_irq_disabled = false;
- return 0;
-}
-#endif
-
-static int assign_host_irq(struct kvm *kvm,
- struct kvm_assigned_dev_kernel *dev,
- __u32 host_irq_type)
-{
- int r = -EEXIST;
-
- if (dev->irq_requested_type & KVM_DEV_IRQ_HOST_MASK)
- return r;
-
- switch (host_irq_type) {
- case KVM_DEV_IRQ_HOST_INTX:
- r = assigned_device_enable_host_intx(kvm, dev);
- break;
-#ifdef __KVM_HAVE_MSI
- case KVM_DEV_IRQ_HOST_MSI:
- r = assigned_device_enable_host_msi(kvm, dev);
- break;
-#endif
-#ifdef __KVM_HAVE_MSIX
- case KVM_DEV_IRQ_HOST_MSIX:
- r = assigned_device_enable_host_msix(kvm, dev);
- break;
-#endif
- default:
- r = -EINVAL;
- }
-
- if (!r)
- dev->irq_requested_type |= host_irq_type;
-
- return r;
-}
-
-static int assign_guest_irq(struct kvm *kvm,
- struct kvm_assigned_dev_kernel *dev,
- struct kvm_assigned_irq *irq,
- unsigned long guest_irq_type)
-{
- int id;
- int r = -EEXIST;
-
- if (dev->irq_requested_type & KVM_DEV_IRQ_GUEST_MASK)
- return r;
-
- id = kvm_request_irq_source_id(kvm);
- if (id < 0)
- return id;
-
- dev->irq_source_id = id;
-
- switch (guest_irq_type) {
- case KVM_DEV_IRQ_GUEST_INTX:
- r = assigned_device_enable_guest_intx(kvm, dev, irq);
- break;
-#ifdef __KVM_HAVE_MSI
- case KVM_DEV_IRQ_GUEST_MSI:
- r = assigned_device_enable_guest_msi(kvm, dev, irq);
- break;
-#endif
-#ifdef __KVM_HAVE_MSIX
- case KVM_DEV_IRQ_GUEST_MSIX:
- r = assigned_device_enable_guest_msix(kvm, dev, irq);
- break;
-#endif
- default:
- r = -EINVAL;
- }
-
- if (!r) {
- dev->irq_requested_type |= guest_irq_type;
- kvm_register_irq_ack_notifier(kvm, &dev->ack_notifier);
- } else
- kvm_free_irq_source_id(kvm, dev->irq_source_id);
-
- return r;
-}
-
-/* TODO Deal with KVM_DEV_IRQ_ASSIGNED_MASK_MSIX */
-static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
- struct kvm_assigned_irq *assigned_irq)
-{
- int r = -EINVAL;
- struct kvm_assigned_dev_kernel *match;
- unsigned long host_irq_type, guest_irq_type;
-
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
-
- if (!irqchip_in_kernel(kvm))
- return r;
-
- mutex_lock(&kvm->lock);
- r = -ENODEV;
- match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
- assigned_irq->assigned_dev_id);
- if (!match)
- goto out;
-
- host_irq_type = (assigned_irq->flags & KVM_DEV_IRQ_HOST_MASK);
- guest_irq_type = (assigned_irq->flags & KVM_DEV_IRQ_GUEST_MASK);
-
- r = -EINVAL;
- /* can only assign one type at a time */
- if (hweight_long(host_irq_type) > 1)
- goto out;
- if (hweight_long(guest_irq_type) > 1)
- goto out;
- if (host_irq_type == 0 && guest_irq_type == 0)
- goto out;
-
- r = 0;
- if (host_irq_type)
- r = assign_host_irq(kvm, match, host_irq_type);
- if (r)
- goto out;
-
- if (guest_irq_type)
- r = assign_guest_irq(kvm, match, assigned_irq, guest_irq_type);
-out:
- mutex_unlock(&kvm->lock);
- return r;
-}
-
-static int kvm_vm_ioctl_deassign_dev_irq(struct kvm *kvm,
- struct kvm_assigned_irq
- *assigned_irq)
-{
- int r = -ENODEV;
- struct kvm_assigned_dev_kernel *match;
-
- mutex_lock(&kvm->lock);
-
- match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
- assigned_irq->assigned_dev_id);
- if (!match)
- goto out;
-
- r = kvm_deassign_irq(kvm, match, assigned_irq->flags);
-out:
- mutex_unlock(&kvm->lock);
- return r;
-}
-
-static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
- struct kvm_assigned_pci_dev *assigned_dev)
-{
- int r = 0;
- struct kvm_assigned_dev_kernel *match;
- struct pci_dev *dev;
-
- down_read(&kvm->slots_lock);
- mutex_lock(&kvm->lock);
-
- match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
- assigned_dev->assigned_dev_id);
- if (match) {
- /* device already assigned */
- r = -EEXIST;
- goto out;
- }
-
- match = kzalloc(sizeof(struct kvm_assigned_dev_kernel), GFP_KERNEL);
- if (match == NULL) {
- printk(KERN_INFO "%s: Couldn't allocate memory\n",
- __func__);
- r = -ENOMEM;
- goto out;
- }
- dev = pci_get_bus_and_slot(assigned_dev->busnr,
- assigned_dev->devfn);
- if (!dev) {
- printk(KERN_INFO "%s: host device not found\n", __func__);
- r = -EINVAL;
- goto out_free;
- }
- if (pci_enable_device(dev)) {
- printk(KERN_INFO "%s: Could not enable PCI device\n", __func__);
- r = -EBUSY;
- goto out_put;
- }
- r = pci_request_regions(dev, "kvm_assigned_device");
- if (r) {
- printk(KERN_INFO "%s: Could not get access to device regions\n",
- __func__);
- goto out_disable;
- }
-
- pci_reset_function(dev);
-
- match->assigned_dev_id = assigned_dev->assigned_dev_id;
- match->host_busnr = assigned_dev->busnr;
- match->host_devfn = assigned_dev->devfn;
- match->flags = assigned_dev->flags;
- match->dev = dev;
- spin_lock_init(&match->assigned_dev_lock);
- match->irq_source_id = -1;
- match->kvm = kvm;
- match->ack_notifier.irq_acked = kvm_assigned_dev_ack_irq;
- INIT_WORK(&match->interrupt_work,
- kvm_assigned_dev_interrupt_work_handler);
-
- list_add(&match->list, &kvm->arch.assigned_dev_head);
-
- if (assigned_dev->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU) {
- if (!kvm->arch.iommu_domain) {
- r = kvm_iommu_map_guest(kvm);
- if (r)
- goto out_list_del;
- }
- r = kvm_assign_device(kvm, match);
- if (r)
- goto out_list_del;
- }
-
-out:
- mutex_unlock(&kvm->lock);
- up_read(&kvm->slots_lock);
- return r;
-out_list_del:
- list_del(&match->list);
- pci_release_regions(dev);
-out_disable:
- pci_disable_device(dev);
-out_put:
- pci_dev_put(dev);
-out_free:
- kfree(match);
- mutex_unlock(&kvm->lock);
- up_read(&kvm->slots_lock);
- return r;
-}
-#endif
-
-#ifdef KVM_CAP_DEVICE_DEASSIGNMENT
-static int kvm_vm_ioctl_deassign_device(struct kvm *kvm,
- struct kvm_assigned_pci_dev *assigned_dev)
-{
- int r = 0;
- struct kvm_assigned_dev_kernel *match;
-
- mutex_lock(&kvm->lock);
-
- match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
- assigned_dev->assigned_dev_id);
- if (!match) {
- printk(KERN_INFO "%s: device hasn't been assigned before, "
- "so cannot be deassigned\n", __func__);
- r = -EINVAL;
- goto out;
- }
-
- if (match->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU)
- kvm_deassign_device(kvm, match);
-
- kvm_free_assigned_device(kvm, match);
-
-out:
- mutex_unlock(&kvm->lock);
- return r;
-}
-#endif
-
inline int kvm_is_mmio_pfn(pfn_t pfn)
{
if (pfn_valid(pfn)) {
@@ -949,6 +343,7 @@ static const struct mmu_notifier_ops kvm_mmu_notifier_ops = {
static struct kvm *kvm_create_vm(void)
{
+ int r = 0;
struct kvm *kvm = kvm_arch_create_vm();
#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
struct page *page;
@@ -956,16 +351,21 @@ static struct kvm *kvm_create_vm(void)
if (IS_ERR(kvm))
goto out;
+
+ r = hardware_enable_all();
+ if (r)
+ goto out_err_nodisable;
+
#ifdef CONFIG_HAVE_KVM_IRQCHIP
- INIT_LIST_HEAD(&kvm->irq_routing);
INIT_HLIST_HEAD(&kvm->mask_notifier_list);
+ INIT_HLIST_HEAD(&kvm->irq_ack_notifier_list);
#endif
#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
page = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (!page) {
- kfree(kvm);
- return ERR_PTR(-ENOMEM);
+ r = -ENOMEM;
+ goto out_err;
}
kvm->coalesced_mmio_ring =
(struct kvm_coalesced_mmio_ring *)page_address(page);
@@ -973,15 +373,13 @@ static struct kvm *kvm_create_vm(void)
#if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
{
- int err;
kvm->mmu_notifier.ops = &kvm_mmu_notifier_ops;
- err = mmu_notifier_register(&kvm->mmu_notifier, current->mm);
- if (err) {
+ r = mmu_notifier_register(&kvm->mmu_notifier, current->mm);
+ if (r) {
#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
put_page(page);
#endif
- kfree(kvm);
- return ERR_PTR(err);
+ goto out_err;
}
}
#endif
@@ -1005,6 +403,12 @@ static struct kvm *kvm_create_vm(void)
#endif
out:
return kvm;
+
+out_err:
+ hardware_disable_all();
+out_err_nodisable:
+ kfree(kvm);
+ return ERR_PTR(r);
}
/*
@@ -1063,6 +467,7 @@ static void kvm_destroy_vm(struct kvm *kvm)
kvm_arch_flush_shadow(kvm);
#endif
kvm_arch_destroy_vm(kvm);
+ hardware_disable_all();
mmdrop(mm);
}
@@ -1689,9 +1094,7 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu)
if (signal_pending(current))
break;
- vcpu_put(vcpu);
schedule();
- vcpu_load(vcpu);
}
finish_wait(&vcpu->wq, &wait);
@@ -1828,88 +1231,6 @@ static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset)
return 0;
}
-#ifdef __KVM_HAVE_MSIX
-static int kvm_vm_ioctl_set_msix_nr(struct kvm *kvm,
- struct kvm_assigned_msix_nr *entry_nr)
-{
- int r = 0;
- struct kvm_assigned_dev_kernel *adev;
-
- mutex_lock(&kvm->lock);
-
- adev = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
- entry_nr->assigned_dev_id);
- if (!adev) {
- r = -EINVAL;
- goto msix_nr_out;
- }
-
- if (adev->entries_nr == 0) {
- adev->entries_nr = entry_nr->entry_nr;
- if (adev->entries_nr == 0 ||
- adev->entries_nr >= KVM_MAX_MSIX_PER_DEV) {
- r = -EINVAL;
- goto msix_nr_out;
- }
-
- adev->host_msix_entries = kzalloc(sizeof(struct msix_entry) *
- entry_nr->entry_nr,
- GFP_KERNEL);
- if (!adev->host_msix_entries) {
- r = -ENOMEM;
- goto msix_nr_out;
- }
- adev->guest_msix_entries = kzalloc(
- sizeof(struct kvm_guest_msix_entry) *
- entry_nr->entry_nr, GFP_KERNEL);
- if (!adev->guest_msix_entries) {
- kfree(adev->host_msix_entries);
- r = -ENOMEM;
- goto msix_nr_out;
- }
- } else /* Not allowed set MSI-X number twice */
- r = -EINVAL;
-msix_nr_out:
- mutex_unlock(&kvm->lock);
- return r;
-}
-
-static int kvm_vm_ioctl_set_msix_entry(struct kvm *kvm,
- struct kvm_assigned_msix_entry *entry)
-{
- int r = 0, i;
- struct kvm_assigned_dev_kernel *adev;
-
- mutex_lock(&kvm->lock);
-
- adev = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
- entry->assigned_dev_id);
-
- if (!adev) {
- r = -EINVAL;
- goto msix_entry_out;
- }
-
- for (i = 0; i < adev->entries_nr; i++)
- if (adev->guest_msix_entries[i].vector == 0 ||
- adev->guest_msix_entries[i].entry == entry->entry) {
- adev->guest_msix_entries[i].entry = entry->entry;
- adev->guest_msix_entries[i].vector = entry->gsi;
- adev->host_msix_entries[i].entry = entry->entry;
- break;
- }
- if (i == adev->entries_nr) {
- r = -ENOSPC;
- goto msix_entry_out;
- }
-
-msix_entry_out:
- mutex_unlock(&kvm->lock);
-
- return r;
-}
-#endif
-
static long kvm_vcpu_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
@@ -2168,112 +1489,6 @@ static long kvm_vm_ioctl(struct file *filp,
break;
}
#endif
-#ifdef KVM_CAP_DEVICE_ASSIGNMENT
- case KVM_ASSIGN_PCI_DEVICE: {
- struct kvm_assigned_pci_dev assigned_dev;
-
- r = -EFAULT;
- if (copy_from_user(&assigned_dev, argp, sizeof assigned_dev))
- goto out;
- r = kvm_vm_ioctl_assign_device(kvm, &assigned_dev);
- if (r)
- goto out;
- break;
- }
- case KVM_ASSIGN_IRQ: {
- r = -EOPNOTSUPP;
- break;
- }
-#ifdef KVM_CAP_ASSIGN_DEV_IRQ
- case KVM_ASSIGN_DEV_IRQ: {
- struct kvm_assigned_irq assigned_irq;
-
- r = -EFAULT;
- if (copy_from_user(&assigned_irq, argp, sizeof assigned_irq))
- goto out;
- r = kvm_vm_ioctl_assign_irq(kvm, &assigned_irq);
- if (r)
- goto out;
- break;
- }
- case KVM_DEASSIGN_DEV_IRQ: {
- struct kvm_assigned_irq assigned_irq;
-
- r = -EFAULT;
- if (copy_from_user(&assigned_irq, argp, sizeof assigned_irq))
- goto out;
- r = kvm_vm_ioctl_deassign_dev_irq(kvm, &assigned_irq);
- if (r)
- goto out;
- break;
- }
-#endif
-#endif
-#ifdef KVM_CAP_DEVICE_DEASSIGNMENT
- case KVM_DEASSIGN_PCI_DEVICE: {
- struct kvm_assigned_pci_dev assigned_dev;
-
- r = -EFAULT;
- if (copy_from_user(&assigned_dev, argp, sizeof assigned_dev))
- goto out;
- r = kvm_vm_ioctl_deassign_device(kvm, &assigned_dev);
- if (r)
- goto out;
- break;
- }
-#endif
-#ifdef KVM_CAP_IRQ_ROUTING
- case KVM_SET_GSI_ROUTING: {
- struct kvm_irq_routing routing;
- struct kvm_irq_routing __user *urouting;
- struct kvm_irq_routing_entry *entries;
-
- r = -EFAULT;
- if (copy_from_user(&routing, argp, sizeof(routing)))
- goto out;
- r = -EINVAL;
- if (routing.nr >= KVM_MAX_IRQ_ROUTES)
- goto out;
- if (routing.flags)
- goto out;
- r = -ENOMEM;
- entries = vmalloc(routing.nr * sizeof(*entries));
- if (!entries)
- goto out;
- r = -EFAULT;
- urouting = argp;
- if (copy_from_user(entries, urouting->entries,
- routing.nr * sizeof(*entries)))
- goto out_free_irq_routing;
- r = kvm_set_irq_routing(kvm, entries, routing.nr,
- routing.flags);
- out_free_irq_routing:
- vfree(entries);
- break;
- }
-#endif /* KVM_CAP_IRQ_ROUTING */
-#ifdef __KVM_HAVE_MSIX
- case KVM_ASSIGN_SET_MSIX_NR: {
- struct kvm_assigned_msix_nr entry_nr;
- r = -EFAULT;
- if (copy_from_user(&entry_nr, argp, sizeof entry_nr))
- goto out;
- r = kvm_vm_ioctl_set_msix_nr(kvm, &entry_nr);
- if (r)
- goto out;
- break;
- }
- case KVM_ASSIGN_SET_MSIX_ENTRY: {
- struct kvm_assigned_msix_entry entry;
- r = -EFAULT;
- if (copy_from_user(&entry, argp, sizeof entry))
- goto out;
- r = kvm_vm_ioctl_set_msix_entry(kvm, &entry);
- if (r)
- goto out;
- break;
- }
-#endif
case KVM_IRQFD: {
struct kvm_irqfd data;
@@ -2305,6 +1520,8 @@ static long kvm_vm_ioctl(struct file *filp,
#endif
default:
r = kvm_arch_vm_ioctl(filp, ioctl, arg);
+ if (r == -ENOTTY)
+ r = kvm_vm_ioctl_assigned_device(kvm, ioctl, arg);
}
out:
return r;
@@ -2442,11 +1659,21 @@ static struct miscdevice kvm_dev = {
static void hardware_enable(void *junk)
{
int cpu = raw_smp_processor_id();
+ int r;
if (cpumask_test_cpu(cpu, cpus_hardware_enabled))
return;
+
cpumask_set_cpu(cpu, cpus_hardware_enabled);
- kvm_arch_hardware_enable(NULL);
+
+ r = kvm_arch_hardware_enable(NULL);
+
+ if (r) {
+ cpumask_clear_cpu(cpu, cpus_hardware_enabled);
+ atomic_inc(&hardware_enable_failed);
+ printk(KERN_INFO "kvm: enabling virtualization on "
+ "CPU%d failed\n", cpu);
+ }
}
static void hardware_disable(void *junk)
@@ -2459,11 +1686,52 @@ static void hardware_disable(void *junk)
kvm_arch_hardware_disable(NULL);
}
+static void hardware_disable_all_nolock(void)
+{
+ BUG_ON(!kvm_usage_count);
+
+ kvm_usage_count--;
+ if (!kvm_usage_count)
+ on_each_cpu(hardware_disable, NULL, 1);
+}
+
+static void hardware_disable_all(void)
+{
+ spin_lock(&kvm_lock);
+ hardware_disable_all_nolock();
+ spin_unlock(&kvm_lock);
+}
+
+static int hardware_enable_all(void)
+{
+ int r = 0;
+
+ spin_lock(&kvm_lock);
+
+ kvm_usage_count++;
+ if (kvm_usage_count == 1) {
+ atomic_set(&hardware_enable_failed, 0);
+ on_each_cpu(hardware_enable, NULL, 1);
+
+ if (atomic_read(&hardware_enable_failed)) {
+ hardware_disable_all_nolock();
+ r = -EBUSY;
+ }
+ }
+
+ spin_unlock(&kvm_lock);
+
+ return r;
+}
+
static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
void *v)
{
int cpu = (long)v;
+ if (!kvm_usage_count)
+ return NOTIFY_OK;
+
val &= ~CPU_TASKS_FROZEN;
switch (val) {
case CPU_DYING:
@@ -2666,13 +1934,15 @@ static void kvm_exit_debug(void)
static int kvm_suspend(struct sys_device *dev, pm_message_t state)
{
- hardware_disable(NULL);
+ if (kvm_usage_count)
+ hardware_disable(NULL);
return 0;
}
static int kvm_resume(struct sys_device *dev)
{
- hardware_enable(NULL);
+ if (kvm_usage_count)
+ hardware_enable(NULL);
return 0;
}
@@ -2717,8 +1987,6 @@ int kvm_init(void *opaque, unsigned int vcpu_size,
int r;
int cpu;
- kvm_init_debug();
-
r = kvm_arch_init(opaque);
if (r)
goto out_fail;
@@ -2749,7 +2017,6 @@ int kvm_init(void *opaque, unsigned int vcpu_size,
goto out_free_1;
}
- on_each_cpu(hardware_enable, NULL, 1);
r = register_cpu_notifier(&kvm_cpu_notifier);
if (r)
goto out_free_2;
@@ -2785,6 +2052,8 @@ int kvm_init(void *opaque, unsigned int vcpu_size,
kvm_preempt_ops.sched_in = kvm_sched_in;
kvm_preempt_ops.sched_out = kvm_sched_out;
+ kvm_init_debug();
+
return 0;
out_free:
@@ -2797,7 +2066,6 @@ out_free_3:
unregister_reboot_notifier(&kvm_reboot_notifier);
unregister_cpu_notifier(&kvm_cpu_notifier);
out_free_2:
- on_each_cpu(hardware_disable, NULL, 1);
out_free_1:
kvm_arch_hardware_unsetup();
out_free_0a:
@@ -2807,7 +2075,6 @@ out_free_0:
out:
kvm_arch_exit();
out_fail:
- kvm_exit_debug();
return r;
}
EXPORT_SYMBOL_GPL(kvm_init);
@@ -2815,6 +2082,7 @@ EXPORT_SYMBOL_GPL(kvm_init);
void kvm_exit(void)
{
tracepoint_synchronize_unregister();
+ kvm_exit_debug();
misc_deregister(&kvm_dev);
kmem_cache_destroy(kvm_vcpu_cache);
sysdev_unregister(&kvm_sysdev);
@@ -2824,7 +2092,6 @@ void kvm_exit(void)
on_each_cpu(hardware_disable, NULL, 1);
kvm_arch_hardware_unsetup();
kvm_arch_exit();
- kvm_exit_debug();
free_cpumask_var(cpus_hardware_enabled);
__free_page(bad_page);
}